summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format2
-rw-r--r--.gitattributes2
-rw-r--r--.github/actions/godot-deps/action.yml2
-rw-r--r--.github/actions/upload-artifact/action.yml2
-rw-r--r--.github/workflows/android_builds.yml13
-rw-r--r--.github/workflows/ios_builds.yml4
-rw-r--r--.github/workflows/linux_builds.yml47
-rw-r--r--.github/workflows/macos_builds.yml6
-rw-r--r--.github/workflows/static_checks.yml22
-rw-r--r--.github/workflows/web_builds.yml (renamed from .github/workflows/javascript_builds.yml)20
-rw-r--r--.github/workflows/windows_builds.yml6
-rw-r--r--CONTRIBUTING.md8
-rw-r--r--README.md3
-rw-r--r--SConstruct57
-rw-r--r--core/config/engine.cpp84
-rw-r--r--core/config/engine.h17
-rw-r--r--core/config/project_settings.cpp66
-rw-r--r--core/config/project_settings.h5
-rw-r--r--core/core_bind.cpp219
-rw-r--r--core/core_bind.h49
-rw-r--r--core/core_constants.cpp2
-rw-r--r--core/core_globals.cpp35
-rw-r--r--core/core_globals.h (renamed from modules/visual_script/register_types.h)19
-rw-r--r--core/extension/extension_api_dump.cpp16
-rw-r--r--core/extension/gdnative_interface.h10
-rw-r--r--core/extension/native_extension.cpp13
-rw-r--r--core/input/gamecontrollerdb.txt89
-rw-r--r--core/input/godotcontrollerdb.txt50
-rw-r--r--core/input/input.cpp13
-rw-r--r--core/input/input.h20
-rw-r--r--core/input/input_builders.py2
-rw-r--r--core/input/input_event.cpp16
-rw-r--r--core/input/input_event.h2
-rw-r--r--core/input/input_map.cpp9
-rw-r--r--core/input/input_map.h7
-rw-r--r--core/io/dir_access.cpp14
-rw-r--r--core/io/dir_access.h2
-rw-r--r--core/io/file_access.cpp8
-rw-r--r--core/io/file_access.h3
-rw-r--r--core/io/file_access_compressed.h32
-rw-r--r--core/io/file_access_encrypted.h38
-rw-r--r--core/io/file_access_memory.h34
-rw-r--r--core/io/file_access_network.h32
-rw-r--r--core/io/file_access_pack.cpp2
-rw-r--r--core/io/file_access_pack.h74
-rw-r--r--core/io/file_access_zip.h32
-rw-r--r--core/io/http_client_tcp.cpp4
-rw-r--r--core/io/image.cpp4
-rw-r--r--core/io/image.h2
-rw-r--r--core/io/image_loader.cpp6
-rw-r--r--core/io/image_loader.h9
-rw-r--r--core/io/ip.cpp17
-rw-r--r--core/io/ip.h9
-rw-r--r--core/io/json.cpp23
-rw-r--r--core/io/json.h3
-rw-r--r--core/io/logger.cpp3
-rw-r--r--core/io/packed_data_container.cpp2
-rw-r--r--core/io/resource.cpp40
-rw-r--r--core/io/resource.h1
-rw-r--r--core/io/resource_format_binary.cpp6
-rw-r--r--core/io/resource_importer.cpp2
-rw-r--r--core/io/resource_loader.cpp14
-rw-r--r--core/io/resource_saver.cpp2
-rw-r--r--core/io/resource_uid.cpp2
-rw-r--r--core/math/a_star.cpp6
-rw-r--r--core/math/a_star.h4
-rw-r--r--core/math/audio_frame.h2
-rw-r--r--core/math/basis.cpp61
-rw-r--r--core/math/basis.h3
-rw-r--r--core/math/math_funcs.h99
-rw-r--r--core/math/projection.cpp8
-rw-r--r--core/math/projection.h2
-rw-r--r--core/math/quaternion.cpp56
-rw-r--r--core/math/quaternion.h1
-rw-r--r--core/math/transform_2d.cpp34
-rw-r--r--core/math/transform_2d.h5
-rw-r--r--core/math/transform_3d.cpp30
-rw-r--r--core/math/transform_3d.h3
-rw-r--r--core/math/vector2.h8
-rw-r--r--core/math/vector3.cpp16
-rw-r--r--core/math/vector3.h22
-rw-r--r--core/math/vector4.cpp107
-rw-r--r--core/math/vector4.h27
-rw-r--r--core/math/vector4i.cpp2
-rw-r--r--core/object/class_db.cpp30
-rw-r--r--core/object/class_db.h2
-rw-r--r--core/object/method_bind.cpp2
-rw-r--r--core/object/object.cpp90
-rw-r--r--core/object/object.h75
-rw-r--r--core/object/ref_counted.cpp3
-rw-r--r--core/object/script_language.cpp38
-rw-r--r--core/object/script_language.h15
-rw-r--r--core/object/script_language_extension.cpp1
-rw-r--r--core/object/script_language_extension.h21
-rw-r--r--core/os/keyboard.h44
-rw-r--r--core/os/memory.h9
-rw-r--r--core/os/os.cpp53
-rw-r--r--core/os/os.h12
-rw-r--r--core/register_core_types.cpp1
-rw-r--r--core/string/char_range.inc1456
-rw-r--r--core/string/char_utils.h20
-rw-r--r--core/string/print_string.cpp9
-rw-r--r--core/string/print_string.h2
-rw-r--r--core/string/translation.cpp10
-rw-r--r--core/string/translation.h2
-rw-r--r--core/string/ustring.cpp118
-rw-r--r--core/string/ustring.h4
-rw-r--r--core/templates/cowdata.h13
-rw-r--r--core/templates/local_vector.h11
-rw-r--r--core/templates/paged_allocator.h10
-rw-r--r--core/templates/paged_array.h12
-rw-r--r--core/templates/rid_owner.h20
-rw-r--r--core/templates/vector.h1
-rw-r--r--core/variant/variant.cpp67
-rw-r--r--core/variant/variant.h25
-rw-r--r--core/variant/variant_call.cpp39
-rw-r--r--core/variant/variant_construct.cpp1
-rw-r--r--core/variant/variant_internal.h17
-rw-r--r--core/variant/variant_op.cpp2
-rw-r--r--core/variant/variant_utility.cpp219
-rw-r--r--doc/Makefile2
-rw-r--r--doc/class.xsd10
-rw-r--r--doc/classes/@GlobalScope.xml577
-rw-r--r--doc/classes/AABB.xml50
-rw-r--r--doc/classes/AESContext.xml14
-rw-r--r--doc/classes/AStar2D.xml106
-rw-r--r--doc/classes/AStar3D.xml106
-rw-r--r--doc/classes/AcceptDialog.xml22
-rw-r--r--doc/classes/AnimatedSprite2D.xml6
-rw-r--r--doc/classes/AnimatedSprite3D.xml4
-rw-r--r--doc/classes/AnimatedTexture.xml12
-rw-r--r--doc/classes/Animation.xml369
-rw-r--r--doc/classes/AnimationLibrary.xml34
-rw-r--r--doc/classes/AnimationNode.xml90
-rw-r--r--doc/classes/AnimationNodeBlendSpace1D.xml32
-rw-r--r--doc/classes/AnimationNodeBlendSpace2D.xml52
-rw-r--r--doc/classes/AnimationNodeBlendTree.xml42
-rw-r--r--doc/classes/AnimationNodeStateMachine.xml54
-rw-r--r--doc/classes/AnimationNodeStateMachinePlayback.xml4
-rw-r--r--doc/classes/AnimationNodeStateMachineTransition.xml5
-rw-r--r--doc/classes/AnimationNodeTransition.xml16
-rw-r--r--doc/classes/AnimationPlayer.xml130
-rw-r--r--doc/classes/AnimationTree.xml6
-rw-r--r--doc/classes/Area2D.xml90
-rw-r--r--doc/classes/Area3D.xml88
-rw-r--r--doc/classes/Array.xml144
-rw-r--r--doc/classes/ArrayMesh.xml60
-rw-r--r--doc/classes/ArrayOccluder3D.xml4
-rw-r--r--doc/classes/AudioEffectCapture.xml10
-rw-r--r--doc/classes/AudioEffectChorus.xml38
-rw-r--r--doc/classes/AudioEffectDelay.xml24
-rw-r--r--doc/classes/AudioEffectEQ.xml6
-rw-r--r--doc/classes/AudioEffectInstance.xml6
-rw-r--r--doc/classes/AudioEffectRecord.xml2
-rw-r--r--doc/classes/AudioEffectSpectrumAnalyzerInstance.xml6
-rw-r--r--doc/classes/AudioServer.xml154
-rw-r--r--doc/classes/AudioStreamGeneratorPlayback.xml8
-rw-r--r--doc/classes/AudioStreamPlayback.xml10
-rw-r--r--doc/classes/AudioStreamPlaybackResampled.xml4
-rw-r--r--doc/classes/AudioStreamPlayer.xml6
-rw-r--r--doc/classes/AudioStreamPlayer2D.xml9
-rw-r--r--doc/classes/AudioStreamPlayer3D.xml8
-rw-r--r--doc/classes/AudioStreamRandomizer.xml20
-rw-r--r--doc/classes/AudioStreamWAV.xml6
-rw-r--r--doc/classes/BaseButton.xml8
-rw-r--r--doc/classes/BaseMaterial3D.xml50
-rw-r--r--doc/classes/Basis.xml74
-rw-r--r--doc/classes/BitMap.xml38
-rw-r--r--doc/classes/Bone2D.xml8
-rw-r--r--doc/classes/BoneAttachment3D.xml10
-rw-r--r--doc/classes/BoneMap.xml14
-rw-r--r--doc/classes/BoxContainer.xml4
-rw-r--r--doc/classes/Button.xml2
-rw-r--r--doc/classes/ButtonGroup.xml4
-rw-r--r--doc/classes/CPUParticles2D.xml32
-rw-r--r--doc/classes/CPUParticles3D.xml38
-rw-r--r--doc/classes/Callable.xml16
-rw-r--r--doc/classes/CallbackTweener.xml2
-rw-r--r--doc/classes/Camera2D.xml12
-rw-r--r--doc/classes/Camera3D.xml65
-rw-r--r--doc/classes/CameraServer.xml18
-rw-r--r--doc/classes/CanvasItem.xml379
-rw-r--r--doc/classes/CanvasItemMaterial.xml2
-rw-r--r--doc/classes/CanvasLayer.xml4
-rw-r--r--doc/classes/CharacterBody2D.xml36
-rw-r--r--doc/classes/CharacterBody3D.xml36
-rw-r--r--doc/classes/CheckBox.xml2
-rw-r--r--doc/classes/CheckButton.xml2
-rw-r--r--doc/classes/ClassDB.xml136
-rw-r--r--doc/classes/CodeEdit.xml170
-rw-r--r--doc/classes/CodeHighlighter.xml32
-rw-r--r--doc/classes/CollisionObject2D.xml131
-rw-r--r--doc/classes/CollisionObject3D.xml101
-rw-r--r--doc/classes/CollisionShape2D.xml3
-rw-r--r--doc/classes/CollisionShape3D.xml5
-rw-r--r--doc/classes/Color.xml124
-rw-r--r--doc/classes/ColorPicker.xml10
-rw-r--r--doc/classes/ColorPickerButton.xml2
-rw-r--r--doc/classes/CompressedTexture2D.xml2
-rw-r--r--doc/classes/CompressedTexture3D.xml2
-rw-r--r--doc/classes/CompressedTextureLayered.xml2
-rw-r--r--doc/classes/ConcavePolygonShape2D.xml3
-rw-r--r--doc/classes/ConcavePolygonShape3D.xml5
-rw-r--r--doc/classes/ConeTwistJoint3D.xml10
-rw-r--r--doc/classes/ConfigFile.xml58
-rw-r--r--doc/classes/Container.xml4
-rw-r--r--doc/classes/Control.xml365
-rw-r--r--doc/classes/ConvexPolygonShape2D.xml2
-rw-r--r--doc/classes/Crypto.xml58
-rw-r--r--doc/classes/CryptoKey.xml26
-rw-r--r--doc/classes/Curve.xml77
-rw-r--r--doc/classes/Curve2D.xml86
-rw-r--r--doc/classes/Curve3D.xml104
-rw-r--r--doc/classes/DTLSServer.xml12
-rw-r--r--doc/classes/Decal.xml6
-rw-r--r--doc/classes/Dictionary.xml28
-rw-r--r--doc/classes/Directory.xml30
-rw-r--r--doc/classes/DisplayServer.xml782
-rw-r--r--doc/classes/EditorCommandPalette.xml20
-rw-r--r--doc/classes/EditorDebuggerPlugin.xml18
-rw-r--r--doc/classes/EditorExportPlugin.xml56
-rw-r--r--doc/classes/EditorFeatureProfile.xml52
-rw-r--r--doc/classes/EditorFileDialog.xml16
-rw-r--r--doc/classes/EditorFileSystem.xml16
-rw-r--r--doc/classes/EditorFileSystemDirectory.xml36
-rw-r--r--doc/classes/EditorImportPlugin.xml26
-rw-r--r--doc/classes/EditorInspector.xml22
-rw-r--r--doc/classes/EditorInspectorPlugin.xml56
-rw-r--r--doc/classes/EditorInterface.xml63
-rw-r--r--doc/classes/EditorNode3DGizmo.xml128
-rw-r--r--doc/classes/EditorNode3DGizmoPlugin.xml136
-rw-r--r--doc/classes/EditorPlugin.xml150
-rw-r--r--doc/classes/EditorProperty.xml64
-rw-r--r--doc/classes/EditorResourceConversionPlugin.xml4
-rw-r--r--doc/classes/EditorResourcePicker.xml16
-rw-r--r--doc/classes/EditorResourcePreview.xml34
-rw-r--r--doc/classes/EditorResourcePreviewGenerator.xml12
-rw-r--r--doc/classes/EditorSceneFormatImporter.xml16
-rw-r--r--doc/classes/EditorScenePostImport.xml2
-rw-r--r--doc/classes/EditorScenePostImportPlugin.xml50
-rw-r--r--doc/classes/EditorScript.xml4
-rw-r--r--doc/classes/EditorSelection.xml6
-rw-r--r--doc/classes/EditorSettings.xml363
-rw-r--r--doc/classes/EditorSyntaxHighlighter.xml2
-rw-r--r--doc/classes/EditorTranslationParserPlugin.xml6
-rw-r--r--doc/classes/EditorUndoRedoManager.xml118
-rw-r--r--doc/classes/EditorVCSInterface.xml12
-rw-r--r--doc/classes/Engine.xml34
-rw-r--r--doc/classes/EngineDebugger.xml46
-rw-r--r--doc/classes/EngineProfiler.xml16
-rw-r--r--doc/classes/Environment.xml19
-rw-r--r--doc/classes/Expression.xml14
-rw-r--r--doc/classes/File.xml99
-rw-r--r--doc/classes/FileDialog.xml18
-rw-r--r--doc/classes/FileSystemDock.xml18
-rw-r--r--doc/classes/Font.xml196
-rw-r--r--doc/classes/FontFile.xml298
-rw-r--r--doc/classes/FontVariation.xml6
-rw-r--r--doc/classes/GPUParticles2D.xml20
-rw-r--r--doc/classes/GPUParticles3D.xml30
-rw-r--r--doc/classes/GPUParticlesAttractor3D.xml2
-rw-r--r--doc/classes/GPUParticlesCollision3D.xml6
-rw-r--r--doc/classes/GPUParticlesCollisionBox3D.xml2
-rw-r--r--doc/classes/GPUParticlesCollisionHeightField3D.xml2
-rw-r--r--doc/classes/GPUParticlesCollisionSDF3D.xml22
-rw-r--r--doc/classes/GPUParticlesCollisionSphere3D.xml2
-rw-r--r--doc/classes/Generic6DOFJoint3D.xml48
-rw-r--r--doc/classes/Geometry2D.xml176
-rw-r--r--doc/classes/Geometry3D.xml116
-rw-r--r--doc/classes/GeometryInstance3D.xml12
-rw-r--r--doc/classes/Gradient.xml33
-rw-r--r--doc/classes/GraphEdit.xml157
-rw-r--r--doc/classes/GraphNode.xml155
-rw-r--r--doc/classes/HMACContext.xml8
-rw-r--r--doc/classes/HTTPClient.xml49
-rw-r--r--doc/classes/HTTPRequest.xml44
-rw-r--r--doc/classes/HashingContext.xml8
-rw-r--r--doc/classes/HingeJoint3D.xml16
-rw-r--r--doc/classes/IP.xml42
-rw-r--r--doc/classes/Image.xml212
-rw-r--r--doc/classes/ImageTexture.xml14
-rw-r--r--doc/classes/ImageTexture3D.xml14
-rw-r--r--doc/classes/ImageTextureLayered.xml6
-rw-r--r--doc/classes/ImmediateMesh.xml18
-rw-r--r--doc/classes/ImporterMesh.xml72
-rw-r--r--doc/classes/Input.xml124
-rw-r--r--doc/classes/InputEvent.xml44
-rw-r--r--doc/classes/InputEventWithModifiers.xml6
-rw-r--r--doc/classes/InputMap.xml44
-rw-r--r--doc/classes/InstancePlaceholder.xml11
-rw-r--r--doc/classes/ItemList.xml150
-rw-r--r--doc/classes/JSON.xml33
-rw-r--r--doc/classes/JSONRPC.xml52
-rw-r--r--doc/classes/JavaClassWrapper.xml2
-rw-r--r--doc/classes/JavaScript.xml32
-rw-r--r--doc/classes/JavaScriptObject.xml2
-rw-r--r--doc/classes/Joint3D.xml8
-rw-r--r--doc/classes/KinematicCollision2D.xml10
-rw-r--r--doc/classes/KinematicCollision3D.xml30
-rw-r--r--doc/classes/Label.xml26
-rw-r--r--doc/classes/Label3D.xml19
-rw-r--r--doc/classes/LabelSettings.xml8
-rw-r--r--doc/classes/Light2D.xml2
-rw-r--r--doc/classes/Light3D.xml24
-rw-r--r--doc/classes/LightmapGIData.xml16
-rw-r--r--doc/classes/Line2D.xml24
-rw-r--r--doc/classes/LineEdit.xml62
-rw-r--r--doc/classes/MainLoop.xml10
-rw-r--r--doc/classes/Marker2D.xml (renamed from doc/classes/Position2D.xml)2
-rw-r--r--doc/classes/Marker3D.xml (renamed from doc/classes/Position3D.xml)2
-rw-r--r--doc/classes/Marshalls.xml26
-rw-r--r--doc/classes/MenuBar.xml172
-rw-r--r--doc/classes/MenuButton.xml4
-rw-r--r--doc/classes/Mesh.xml52
-rw-r--r--doc/classes/MeshDataTool.xml94
-rw-r--r--doc/classes/MeshInstance3D.xml24
-rw-r--r--doc/classes/MeshLibrary.xml48
-rw-r--r--doc/classes/MethodTweener.xml6
-rw-r--r--doc/classes/MovieWriter.xml20
-rw-r--r--doc/classes/MultiMesh.xml26
-rw-r--r--doc/classes/MultiMeshInstance3D.xml2
-rw-r--r--doc/classes/MultiplayerAPI.xml28
-rw-r--r--doc/classes/MultiplayerAPIExtension.xml18
-rw-r--r--doc/classes/MultiplayerPeer.xml8
-rw-r--r--doc/classes/MultiplayerPeerExtension.xml22
-rw-r--r--doc/classes/NativeExtension.xml6
-rw-r--r--doc/classes/NativeExtensionManager.xml10
-rw-r--r--doc/classes/NavigationAgent2D.xml22
-rw-r--r--doc/classes/NavigationAgent3D.xml22
-rw-r--r--doc/classes/NavigationMesh.xml19
-rw-r--r--doc/classes/NavigationMeshGenerator.xml12
-rw-r--r--doc/classes/NavigationPolygon.xml20
-rw-r--r--doc/classes/NavigationRegion2D.xml10
-rw-r--r--doc/classes/NavigationRegion3D.xml14
-rw-r--r--doc/classes/NavigationServer2D.xml182
-rw-r--r--doc/classes/NavigationServer3D.xml208
-rw-r--r--doc/classes/NinePatchRect.xml8
-rw-r--r--doc/classes/Node.xml210
-rw-r--r--doc/classes/Node2D.xml40
-rw-r--r--doc/classes/Node3D.xml90
-rw-r--r--doc/classes/NodePath.xml16
-rw-r--r--doc/classes/OS.xml202
-rw-r--r--doc/classes/Object.xml184
-rw-r--r--doc/classes/OccluderInstance3D.xml12
-rw-r--r--doc/classes/OptimizedTranslation.xml2
-rw-r--r--doc/classes/OptionButton.xml104
-rw-r--r--doc/classes/PCKPacker.xml22
-rw-r--r--doc/classes/PackedByteArray.xml198
-rw-r--r--doc/classes/PackedColorArray.xml73
-rw-r--r--doc/classes/PackedDataContainer.xml2
-rw-r--r--doc/classes/PackedFloat32Array.xml75
-rw-r--r--doc/classes/PackedFloat64Array.xml74
-rw-r--r--doc/classes/PackedInt32Array.xml73
-rw-r--r--doc/classes/PackedInt64Array.xml72
-rw-r--r--doc/classes/PackedScene.xml10
-rw-r--r--doc/classes/PackedStringArray.xml73
-rw-r--r--doc/classes/PackedVector2Array.xml76
-rw-r--r--doc/classes/PackedVector3Array.xml76
-rw-r--r--doc/classes/PacketPeer.xml12
-rw-r--r--doc/classes/PacketPeerDTLS.xml10
-rw-r--r--doc/classes/PacketPeerExtension.xml8
-rw-r--r--doc/classes/PacketPeerUDP.xml38
-rw-r--r--doc/classes/ParticleProcessMaterial.xml (renamed from doc/classes/ParticlesMaterial.xml)111
-rw-r--r--doc/classes/PathFollow2D.xml12
-rw-r--r--doc/classes/PathFollow3D.xml12
-rw-r--r--doc/classes/Performance.xml28
-rw-r--r--doc/classes/PhysicalBone2D.xml4
-rw-r--r--doc/classes/PhysicalBone3D.xml8
-rw-r--r--doc/classes/PhysicsBody2D.xml32
-rw-r--r--doc/classes/PhysicsBody3D.xml50
-rw-r--r--doc/classes/PhysicsDirectBodyState2D.xml58
-rw-r--r--doc/classes/PhysicsDirectBodyState3D.xml60
-rw-r--r--doc/classes/PhysicsDirectBodyState3DExtension.xml58
-rw-r--r--doc/classes/PhysicsDirectSpaceState2D.xml30
-rw-r--r--doc/classes/PhysicsDirectSpaceState3D.xml30
-rw-r--r--doc/classes/PhysicsDirectSpaceState3DExtension.xml106
-rw-r--r--doc/classes/PhysicsRayQueryParameters2D.xml16
-rw-r--r--doc/classes/PhysicsRayQueryParameters3D.xml16
-rw-r--r--doc/classes/PhysicsServer2D.xml425
-rw-r--r--doc/classes/PhysicsServer3D.xml519
-rw-r--r--doc/classes/PhysicsServer3DExtension.xml505
-rw-r--r--doc/classes/PhysicsServer3DRenderingServerHandler.xml10
-rw-r--r--doc/classes/PhysicsTestMotionResult3D.xml18
-rw-r--r--doc/classes/PinJoint3D.xml6
-rw-r--r--doc/classes/Plane.xml79
-rw-r--r--doc/classes/PlaneMesh.xml16
-rw-r--r--doc/classes/Polygon2D.xml26
-rw-r--r--doc/classes/PolygonPathFinder.xml22
-rw-r--r--doc/classes/PopupMenu.xml386
-rw-r--r--doc/classes/PopupPanel.xml1
-rw-r--r--doc/classes/PortableCompressedTexture2D.xml10
-rw-r--r--doc/classes/PrimitiveMesh.xml2
-rw-r--r--doc/classes/ProjectSettings.xml146
-rw-r--r--doc/classes/Projection.xml130
-rw-r--r--doc/classes/PropertyTweener.xml8
-rw-r--r--doc/classes/ProxyTexture.xml13
-rw-r--r--doc/classes/QuadMesh.xml21
-rw-r--r--doc/classes/Quaternion.xml92
-rw-r--r--doc/classes/RDShaderFile.xml6
-rw-r--r--doc/classes/RDShaderSPIRV.xml12
-rw-r--r--doc/classes/RDShaderSource.xml6
-rw-r--r--doc/classes/RDTextureFormat.xml4
-rw-r--r--doc/classes/RDUniform.xml4
-rw-r--r--doc/classes/RID.xml14
-rw-r--r--doc/classes/RandomNumberGenerator.xml18
-rw-r--r--doc/classes/Range.xml8
-rw-r--r--doc/classes/RayCast2D.xml24
-rw-r--r--doc/classes/RayCast3D.xml24
-rw-r--r--doc/classes/Rect2.xml64
-rw-r--r--doc/classes/Rect2i.xml52
-rw-r--r--doc/classes/ReflectionProbe.xml2
-rw-r--r--doc/classes/RenderingDevice.xml406
-rw-r--r--doc/classes/RenderingServer.xml2046
-rw-r--r--doc/classes/Resource.xml8
-rw-r--r--doc/classes/ResourceFormatLoader.xml34
-rw-r--r--doc/classes/ResourceFormatSaver.xml12
-rw-r--r--doc/classes/ResourceLoader.xml62
-rw-r--r--doc/classes/ResourcePreloader.xml24
-rw-r--r--doc/classes/ResourceSaver.xml18
-rw-r--r--doc/classes/ResourceUID.xml37
-rw-r--r--doc/classes/RichTextEffect.xml4
-rw-r--r--doc/classes/RichTextLabel.xml150
-rw-r--r--doc/classes/RigidBody2D.xml (renamed from doc/classes/RigidDynamicBody2D.xml)118
-rw-r--r--doc/classes/RigidBody3D.xml (renamed from doc/classes/RigidDynamicBody3D.xml)124
-rw-r--r--doc/classes/RootMotionView.xml12
-rw-r--r--doc/classes/SceneState.xml84
-rw-r--r--doc/classes/SceneTree.xml103
-rw-r--r--doc/classes/Script.xml16
-rw-r--r--doc/classes/ScriptCreateDialog.xml10
-rw-r--r--doc/classes/ScriptEditor.xml20
-rw-r--r--doc/classes/ScriptEditorBase.xml14
-rw-r--r--doc/classes/ScriptExtension.xml30
-rw-r--r--doc/classes/ScriptLanguageExtension.xml126
-rw-r--r--doc/classes/ScrollContainer.xml4
-rw-r--r--doc/classes/Shader.xml24
-rw-r--r--doc/classes/ShaderMaterial.xml26
-rw-r--r--doc/classes/Shape2D.xml54
-rw-r--r--doc/classes/ShapeCast2D.xml34
-rw-r--r--doc/classes/ShapeCast3D.xml36
-rw-r--r--doc/classes/Shortcut.xml4
-rw-r--r--doc/classes/Signal.xml20
-rw-r--r--doc/classes/Skeleton2D.xml28
-rw-r--r--doc/classes/Skeleton3D.xml191
-rw-r--r--doc/classes/SkeletonIK3D.xml2
-rw-r--r--doc/classes/SkeletonModification2D.xml18
-rw-r--r--doc/classes/SkeletonModification2DCCDIK.xml72
-rw-r--r--doc/classes/SkeletonModification2DFABRIK.xml40
-rw-r--r--doc/classes/SkeletonModification2DJiggle.xml84
-rw-r--r--doc/classes/SkeletonModification2DLookAt.xml10
-rw-r--r--doc/classes/SkeletonModification2DPhysicalBones.xml16
-rw-r--r--doc/classes/SkeletonModification2DStackHolder.xml2
-rw-r--r--doc/classes/SkeletonModification2DTwoBoneIK.xml8
-rw-r--r--doc/classes/SkeletonModification3D.xml16
-rw-r--r--doc/classes/SkeletonModification3DCCDIK.xml72
-rw-r--r--doc/classes/SkeletonModification3DFABRIK.xml82
-rw-r--r--doc/classes/SkeletonModification3DJiggle.xml90
-rw-r--r--doc/classes/SkeletonModification3DLookAt.xml6
-rw-r--r--doc/classes/SkeletonModification3DStackHolder.xml2
-rw-r--r--doc/classes/SkeletonModification3DTwoBoneIK.xml34
-rw-r--r--doc/classes/SkeletonModificationStack2D.xml24
-rw-r--r--doc/classes/SkeletonModificationStack3D.xml26
-rw-r--r--doc/classes/SkeletonProfile.xml94
-rw-r--r--doc/classes/Skin.xml28
-rw-r--r--doc/classes/Slider.xml4
-rw-r--r--doc/classes/SliderJoint3D.xml10
-rw-r--r--doc/classes/SoftBody3D.xml (renamed from doc/classes/SoftDynamicBody3D.xml)56
-rw-r--r--doc/classes/SpinBox.xml3
-rw-r--r--doc/classes/SplitContainer.xml2
-rw-r--r--doc/classes/SpringArm3D.xml4
-rw-r--r--doc/classes/Sprite2D.xml2
-rw-r--r--doc/classes/Sprite3D.xml2
-rw-r--r--doc/classes/SpriteBase3D.xml6
-rw-r--r--doc/classes/SpriteFrames.xml48
-rw-r--r--doc/classes/StaticBody2D.xml2
-rw-r--r--doc/classes/StaticBody3D.xml2
-rw-r--r--doc/classes/StreamPeer.xml56
-rw-r--r--doc/classes/StreamPeerBuffer.xml6
-rw-r--r--doc/classes/StreamPeerExtension.xml24
-rw-r--r--doc/classes/StreamPeerSSL.xml22
-rw-r--r--doc/classes/StreamPeerTCP.xml14
-rw-r--r--doc/classes/String.xml273
-rw-r--r--doc/classes/StringName.xml20
-rw-r--r--doc/classes/StyleBox.xml30
-rw-r--r--doc/classes/StyleBoxFlat.xml58
-rw-r--r--doc/classes/StyleBoxTexture.xml30
-rw-r--r--doc/classes/SubViewport.xml2
-rw-r--r--doc/classes/SurfaceTool.xml92
-rw-r--r--doc/classes/SyntaxHighlighter.xml4
-rw-r--r--doc/classes/SystemFont.xml7
-rw-r--r--doc/classes/TCPServer.xml12
-rw-r--r--doc/classes/TabBar.xml100
-rw-r--r--doc/classes/TabContainer.xml70
-rw-r--r--doc/classes/TextEdit.xml324
-rw-r--r--doc/classes/TextLine.xml52
-rw-r--r--doc/classes/TextMesh.xml12
-rw-r--r--doc/classes/TextParagraph.xml126
-rw-r--r--doc/classes/TextServer.xml904
-rw-r--r--doc/classes/TextServerExtension.xml850
-rw-r--r--doc/classes/TextServerManager.xml16
-rw-r--r--doc/classes/Texture2D.xml66
-rw-r--r--doc/classes/TextureLayered.xml6
-rw-r--r--doc/classes/TextureProgressBar.xml6
-rw-r--r--doc/classes/Theme.xml341
-rw-r--r--doc/classes/ThemeDB.xml54
-rw-r--r--doc/classes/Thread.xml8
-rw-r--r--doc/classes/TileData.xml122
-rw-r--r--doc/classes/TileMap.xml212
-rw-r--r--doc/classes/TileMapPattern.xml30
-rw-r--r--doc/classes/TileSet.xml268
-rw-r--r--doc/classes/TileSetAtlasSource.xml154
-rw-r--r--doc/classes/TileSetScenesCollectionSource.xml42
-rw-r--r--doc/classes/TileSetSource.xml24
-rw-r--r--doc/classes/Time.xml60
-rw-r--r--doc/classes/Timer.xml4
-rw-r--r--doc/classes/TorusMesh.xml25
-rw-r--r--doc/classes/Transform2D.xml112
-rw-r--r--doc/classes/Transform3D.xml118
-rw-r--r--doc/classes/Translation.xml42
-rw-r--r--doc/classes/TranslationServer.xml56
-rw-r--r--doc/classes/Tree.xml123
-rw-r--r--doc/classes/TreeItem.xml326
-rw-r--r--doc/classes/Tween.xml76
-rw-r--r--doc/classes/UDPServer.xml6
-rw-r--r--doc/classes/UndoRedo.xml48
-rw-r--r--doc/classes/Variant.xml1
-rw-r--r--doc/classes/Vector2.xml170
-rw-r--r--doc/classes/Vector2i.xml60
-rw-r--r--doc/classes/Vector3.xml184
-rw-r--r--doc/classes/Vector3i.xml60
-rw-r--r--doc/classes/Vector4.xml141
-rw-r--r--doc/classes/Vector4i.xml50
-rw-r--r--doc/classes/VehicleBody3D.xml8
-rw-r--r--doc/classes/VehicleWheel3D.xml6
-rw-r--r--doc/classes/VelocityTracker3D.xml32
-rw-r--r--doc/classes/VideoStreamPlayer.xml2
-rw-r--r--doc/classes/Viewport.xml30
-rw-r--r--doc/classes/VisibleOnScreenEnabler3D.xml2
-rw-r--r--doc/classes/VisualInstance3D.xml10
-rw-r--r--doc/classes/VisualShader.xml120
-rw-r--r--doc/classes/VisualShaderNode.xml18
-rw-r--r--doc/classes/VisualShaderNodeCustom.xml40
-rw-r--r--doc/classes/VisualShaderNodeDistanceFade.xml9
-rw-r--r--doc/classes/VisualShaderNodeExpression.xml2
-rw-r--r--doc/classes/VisualShaderNodeGroupBase.xml48
-rw-r--r--doc/classes/VisualShaderNodeLinearSceneDepth.xml9
-rw-r--r--doc/classes/VisualShaderNodeProximityFade.xml9
-rw-r--r--doc/classes/VisualShaderNodeRandomRange.xml9
-rw-r--r--doc/classes/VisualShaderNodeRemap.xml9
-rw-r--r--doc/classes/VisualShaderNodeTextureUniform.xml9
-rw-r--r--doc/classes/VisualShaderNodeUVFunc.xml2
-rw-r--r--doc/classes/VisualShaderNodeUVPolarCoord.xml9
-rw-r--r--doc/classes/VisualShaderNodeVectorRefract.xml4
-rw-r--r--doc/classes/VoxelGI.xml4
-rw-r--r--doc/classes/VoxelGIData.xml14
-rw-r--r--doc/classes/WeakRef.xml2
-rw-r--r--doc/classes/Window.xml131
-rw-r--r--doc/classes/WorkerThreadPool.xml26
-rw-r--r--doc/classes/X509Certificate.xml8
-rw-r--r--doc/classes/XMLParser.xml30
-rw-r--r--doc/classes/XRController3D.xml24
-rw-r--r--doc/classes/XRInterface.xml22
-rw-r--r--doc/classes/XRInterfaceExtension.xml64
-rw-r--r--doc/classes/XRNode3D.xml12
-rw-r--r--doc/classes/XRPositionalTracker.xml42
-rw-r--r--doc/classes/XRServer.xml50
-rw-r--r--doc/classes/bool.xml14
-rw-r--r--doc/classes/float.xml66
-rw-r--r--doc/classes/int.xml82
-rwxr-xr-xdoc/tools/doc_status.py69
-rwxr-xr-xdoc/tools/make_rst.py1366
-rw-r--r--doc/translations/fr.po2949
-rw-r--r--doc/translations/it.po7
-rw-r--r--doc/translations/pt_BR.po14
-rw-r--r--doc/translations/ru.po37
-rw-r--r--doc/translations/zh_CN.po234
-rw-r--r--drivers/alsa/audio_driver_alsa.cpp31
-rw-r--r--drivers/alsa/audio_driver_alsa.h8
-rw-r--r--drivers/alsamidi/midi_driver_alsamidi.cpp8
-rw-r--r--drivers/alsamidi/midi_driver_alsamidi.h3
-rw-r--r--drivers/coreaudio/audio_driver_coreaudio.cpp10
-rw-r--r--drivers/coreaudio/audio_driver_coreaudio.h6
-rw-r--r--drivers/gles3/effects/copy_effects.cpp1
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp159
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.h3
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp2
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp41
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h2
-rw-r--r--drivers/gles3/shader_gles3.cpp4
-rw-r--r--drivers/gles3/shaders/canvas.glsl8
-rw-r--r--drivers/gles3/shaders/canvas_uniforms_inc.glsl1
-rw-r--r--drivers/gles3/shaders/cubemap_filter.glsl8
-rw-r--r--drivers/gles3/shaders/scene.glsl36
-rw-r--r--drivers/gles3/storage/config.cpp7
-rw-r--r--drivers/gles3/storage/light_storage.cpp3
-rw-r--r--drivers/gles3/storage/material_storage.cpp91
-rw-r--r--drivers/gles3/storage/material_storage.h15
-rw-r--r--drivers/gles3/storage/mesh_storage.cpp44
-rw-r--r--drivers/gles3/storage/mesh_storage.h8
-rw-r--r--drivers/gles3/storage/texture_storage.cpp11
-rw-r--r--drivers/gles3/storage/texture_storage.h1
-rw-r--r--drivers/png/SCsub4
-rw-r--r--drivers/png/image_loader_png.cpp4
-rw-r--r--drivers/png/image_loader_png.h2
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.cpp35
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.h14
-rw-r--r--drivers/unix/dir_access_unix.cpp28
-rw-r--r--drivers/unix/dir_access_unix.h46
-rw-r--r--drivers/unix/file_access_unix.h38
-rw-r--r--drivers/unix/ip_unix.cpp4
-rw-r--r--drivers/unix/net_socket_posix.cpp2
-rw-r--r--drivers/unix/os_unix.cpp16
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp944
-rw-r--r--drivers/vulkan/rendering_device_vulkan.h101
-rw-r--r--drivers/vulkan/vulkan_context.cpp108
-rw-r--r--drivers/vulkan/vulkan_context.h12
-rw-r--r--drivers/wasapi/audio_driver_wasapi.cpp43
-rw-r--r--drivers/wasapi/audio_driver_wasapi.h12
-rw-r--r--drivers/windows/dir_access_windows.cpp14
-rw-r--r--drivers/windows/dir_access_windows.h38
-rw-r--r--drivers/windows/file_access_windows.h38
-rw-r--r--drivers/xaudio2/audio_driver_xaudio2.cpp17
-rw-r--r--drivers/xaudio2/audio_driver_xaudio2.h6
-rw-r--r--editor/action_map_editor.cpp11
-rw-r--r--editor/animation_bezier_editor.cpp574
-rw-r--r--editor/animation_bezier_editor.h46
-rw-r--r--editor/animation_track_editor.cpp973
-rw-r--r--editor/animation_track_editor.h58
-rw-r--r--editor/animation_track_editor_plugins.cpp1
-rw-r--r--editor/array_property_edit.cpp7
-rw-r--r--editor/code_editor.cpp17
-rw-r--r--editor/connections_dialog.cpp15
-rw-r--r--editor/connections_dialog.h11
-rw-r--r--editor/create_dialog.cpp18
-rw-r--r--editor/create_dialog.h2
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_parser.cpp2
-rw-r--r--editor/debugger/editor_debugger_inspector.cpp1
-rw-r--r--editor/debugger/editor_debugger_inspector.h1
-rw-r--r--editor/debugger/editor_debugger_node.cpp8
-rw-r--r--editor/debugger/editor_debugger_node.h2
-rw-r--r--editor/debugger/editor_profiler.cpp2
-rw-r--r--editor/debugger/script_editor_debugger.cpp23
-rw-r--r--editor/dependency_editor.cpp40
-rw-r--r--editor/dependency_editor.h1
-rw-r--r--editor/dictionary_property_edit.cpp5
-rw-r--r--editor/doc_tools.cpp520
-rw-r--r--editor/editor_about.cpp2
-rw-r--r--editor/editor_audio_buses.cpp61
-rw-r--r--editor/editor_autoload_settings.cpp13
-rw-r--r--editor/editor_build_profile.cpp130
-rw-r--r--editor/editor_build_profile.h20
-rw-r--r--editor/editor_data.cpp82
-rw-r--r--editor/editor_data.h22
-rw-r--r--editor/editor_dir_dialog.cpp2
-rw-r--r--editor/editor_feature_profile.cpp21
-rw-r--r--editor/editor_file_dialog.cpp42
-rw-r--r--editor/editor_file_system.cpp35
-rw-r--r--editor/editor_folding.cpp10
-rw-r--r--editor/editor_fonts.cpp82
-rw-r--r--editor/editor_help.cpp60
-rw-r--r--editor/editor_help.h1
-rw-r--r--editor/editor_help_search.cpp4
-rw-r--r--editor/editor_inspector.cpp519
-rw-r--r--editor/editor_inspector.h41
-rw-r--r--editor/editor_locale_dialog.cpp9
-rw-r--r--editor/editor_locale_dialog.h4
-rw-r--r--editor/editor_log.cpp35
-rw-r--r--editor/editor_log.h15
-rw-r--r--editor/editor_node.cpp671
-rw-r--r--editor/editor_node.h33
-rw-r--r--editor/editor_path.cpp13
-rw-r--r--editor/editor_paths.cpp28
-rw-r--r--editor/editor_plugin.cpp29
-rw-r--r--editor/editor_plugin.h14
-rw-r--r--editor/editor_plugin_settings.cpp4
-rw-r--r--editor/editor_properties.cpp320
-rw-r--r--editor/editor_properties.h30
-rw-r--r--editor/editor_properties_array_dict.cpp4
-rw-r--r--editor/editor_property_name_processor.cpp8
-rw-r--r--editor/editor_resource_picker.cpp133
-rw-r--r--editor/editor_resource_picker.h3
-rw-r--r--editor/editor_resource_preview.cpp2
-rw-r--r--editor/editor_run.cpp9
-rw-r--r--editor/editor_run_native.cpp4
-rw-r--r--editor/editor_sectioned_inspector.cpp8
-rw-r--r--editor/editor_settings.cpp68
-rw-r--r--editor/editor_settings.h6
-rw-r--r--editor/editor_settings_dialog.cpp10
-rw-r--r--editor/editor_settings_dialog.h4
-rw-r--r--editor/editor_spin_slider.cpp8
-rw-r--r--editor/editor_spin_slider.h2
-rw-r--r--editor/editor_themes.cpp360
-rw-r--r--editor/editor_themes.h16
-rw-r--r--editor/editor_title_bar.cpp (renamed from modules/mono/glue/arguments_vector.h)77
-rw-r--r--editor/editor_title_bar.h (renamed from modules/mono/utils/mono_reg_utils.h)37
-rw-r--r--editor/editor_toaster.cpp10
-rw-r--r--editor/editor_undo_redo_manager.cpp442
-rw-r--r--editor/editor_undo_redo_manager.h134
-rw-r--r--editor/editor_vcs_interface.cpp12
-rw-r--r--editor/editor_vcs_interface.h4
-rw-r--r--editor/export/editor_export.cpp2
-rw-r--r--editor/export/editor_export_platform.cpp63
-rw-r--r--editor/export/editor_export_platform.h25
-rw-r--r--editor/export/editor_export_platform_pc.cpp10
-rw-r--r--editor/export/editor_export_platform_pc.h3
-rw-r--r--editor/export/editor_export_plugin.cpp2
-rw-r--r--editor/export/editor_export_preset.cpp5
-rw-r--r--editor/export/editor_export_preset.h1
-rw-r--r--editor/export/export_template_manager.cpp44
-rw-r--r--editor/export/project_export.cpp14
-rw-r--r--editor/filesystem_dock.cpp45
-rw-r--r--editor/find_in_files.cpp6
-rw-r--r--editor/groups_editor.cpp9
-rw-r--r--editor/groups_editor.h11
-rw-r--r--editor/icons/AudioStream.svg1
-rw-r--r--editor/icons/AudioStreamGenerator.svg1
-rw-r--r--editor/icons/AudioStreamMicrophone.svg1
-rw-r--r--editor/icons/AudioStreamRandomizer.svg1
-rw-r--r--editor/icons/BezierHandlesBalanced.svg2
-rw-r--r--editor/icons/BezierHandlesFree.svg2
-rw-r--r--editor/icons/BezierHandlesLinear.svg1
-rw-r--r--editor/icons/BezierHandlesMirror.svg2
-rw-r--r--editor/icons/ContainerLayout.svg1
-rw-r--r--editor/icons/ControlLayout.svg2
-rw-r--r--editor/icons/CurveIn.svg2
-rw-r--r--editor/icons/CurveInOut.svg2
-rw-r--r--editor/icons/CurveLinear.svg2
-rw-r--r--editor/icons/CurveOut.svg2
-rw-r--r--editor/icons/CurveOutIn.svg2
-rw-r--r--editor/icons/DefaultProjectIcon.svg2
-rw-r--r--editor/icons/InterpCubicAngle.svg1
-rw-r--r--editor/icons/InterpLinearAngle.svg1
-rw-r--r--editor/icons/Marker2D.svg (renamed from editor/icons/Position2D.svg)0
-rw-r--r--editor/icons/Marker3D.svg (renamed from editor/icons/Position3D.svg)0
-rw-r--r--editor/icons/MenuBar.svg1
-rw-r--r--editor/icons/NodeInfo.svg1
-rw-r--r--editor/icons/NodeWarnings2.svg1
-rw-r--r--editor/icons/NodeWarnings3.svg1
-rw-r--r--editor/icons/NodeWarnings4Plus.svg1
-rw-r--r--editor/icons/ParticleProcessMaterial.svg (renamed from editor/icons/ParticlesMaterial.svg)0
-rw-r--r--editor/icons/RigidBody2D.svg (renamed from editor/icons/RigidDynamicBody2D.svg)0
-rw-r--r--editor/icons/RigidBody3D.svg (renamed from editor/icons/RigidDynamicBody3D.svg)0
-rw-r--r--editor/icons/SoftBody3D.svg (renamed from editor/icons/SoftDynamicBody3D.svg)0
-rw-r--r--editor/icons/TorusMesh.svg1
-rw-r--r--editor/import/audio_stream_import_settings.cpp10
-rw-r--r--editor/import/collada.cpp6
-rw-r--r--editor/import/dynamic_font_import_settings.cpp18
-rw-r--r--editor/import/editor_import_plugin.cpp2
-rw-r--r--editor/import/editor_import_plugin.h3
-rw-r--r--editor/import/post_import_plugin_skeleton_rest_fixer.cpp272
-rw-r--r--editor/import/resource_importer_dynamic_font.cpp6
-rw-r--r--editor/import/resource_importer_imagefont.cpp2
-rw-r--r--editor/import/resource_importer_layered_texture.cpp15
-rw-r--r--editor/import/resource_importer_layered_texture.h2
-rw-r--r--editor/import/resource_importer_obj.cpp10
-rw-r--r--editor/import/resource_importer_scene.cpp20
-rw-r--r--editor/import/resource_importer_scene.h2
-rw-r--r--editor/import/resource_importer_shader_file.cpp2
-rw-r--r--editor/import/resource_importer_texture.cpp31
-rw-r--r--editor/import/resource_importer_texture_atlas.cpp1
-rw-r--r--editor/import/resource_importer_wav.cpp2
-rw-r--r--editor/import/scene_import_settings.cpp6
-rw-r--r--editor/import_dock.cpp7
-rw-r--r--editor/inspector_dock.cpp76
-rw-r--r--editor/inspector_dock.h9
-rw-r--r--editor/localization_editor.cpp104
-rw-r--r--editor/localization_editor.h7
-rw-r--r--editor/multi_node_edit.cpp3
-rw-r--r--editor/node_dock.cpp2
-rw-r--r--editor/plugin_config_dialog.cpp18
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp15
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.h3
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp171
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.h5
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp178
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.h5
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp86
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.h8
-rw-r--r--editor/plugins/animation_library_editor.cpp162
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp160
-rw-r--r--editor/plugins/animation_player_editor_plugin.h5
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp94
-rw-r--r--editor/plugins/animation_state_machine_editor.h5
-rw-r--r--editor/plugins/animation_tree_editor_plugin.cpp8
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp10
-rw-r--r--editor/plugins/audio_stream_randomizer_editor_plugin.cpp5
-rw-r--r--editor/plugins/bone_map_editor_plugin.cpp931
-rw-r--r--editor/plugins/bone_map_editor_plugin.h65
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp252
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h7
-rw-r--r--editor/plugins/cast_2d_editor_plugin.cpp (renamed from editor/plugins/ray_cast_2d_editor_plugin.cpp)57
-rw-r--r--editor/plugins/cast_2d_editor_plugin.h (renamed from editor/plugins/ray_cast_2d_editor_plugin.h)37
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.cpp1
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.h3
-rw-r--r--editor/plugins/control_editor_plugin.cpp855
-rw-r--r--editor/plugins/control_editor_plugin.h172
-rw-r--r--editor/plugins/cpu_particles_2d_editor_plugin.cpp3
-rw-r--r--editor/plugins/cpu_particles_2d_editor_plugin.h3
-rw-r--r--editor/plugins/curve_editor_plugin.cpp54
-rw-r--r--editor/plugins/debugger_editor_plugin.cpp73
-rw-r--r--editor/plugins/debugger_editor_plugin.h4
-rw-r--r--editor/plugins/editor_preview_plugins.cpp2
-rw-r--r--editor/plugins/font_config_plugin.cpp20
-rw-r--r--editor/plugins/font_config_plugin.h6
-rw-r--r--editor/plugins/gpu_particles_2d_editor_plugin.cpp13
-rw-r--r--editor/plugins/gpu_particles_2d_editor_plugin.h3
-rw-r--r--editor/plugins/gpu_particles_3d_editor_plugin.cpp17
-rw-r--r--editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp4
-rw-r--r--editor/plugins/gradient_editor_plugin.cpp5
-rw-r--r--editor/plugins/gradient_texture_2d_editor_plugin.cpp9
-rw-r--r--editor/plugins/gradient_texture_2d_editor_plugin.h6
-rw-r--r--editor/plugins/material_editor_plugin.cpp59
-rw-r--r--editor/plugins/material_editor_plugin.h4
-rw-r--r--editor/plugins/mesh_editor_plugin.cpp4
-rw-r--r--editor/plugins/mesh_instance_3d_editor_plugin.cpp15
-rw-r--r--editor/plugins/node_3d_editor_gizmos.cpp194
-rw-r--r--editor/plugins/node_3d_editor_gizmos.h12
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp180
-rw-r--r--editor/plugins/node_3d_editor_plugin.h9
-rw-r--r--editor/plugins/packed_scene_translation_parser_plugin.cpp2
-rw-r--r--editor/plugins/path_2d_editor_plugin.cpp11
-rw-r--r--editor/plugins/path_2d_editor_plugin.h3
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp21
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp28
-rw-r--r--editor/plugins/polygon_3d_editor_plugin.cpp1
-rw-r--r--editor/plugins/polygon_3d_editor_plugin.h3
-rw-r--r--editor/plugins/resource_preloader_editor_plugin.cpp8
-rw-r--r--editor/plugins/resource_preloader_editor_plugin.h5
-rw-r--r--editor/plugins/root_motion_editor_plugin.cpp2
-rw-r--r--editor/plugins/script_editor_plugin.cpp46
-rw-r--r--editor/plugins/script_editor_plugin.h10
-rw-r--r--editor/plugins/script_text_editor.cpp14
-rw-r--r--editor/plugins/script_text_editor.h2
-rw-r--r--editor/plugins/shader_editor_plugin.cpp254
-rw-r--r--editor/plugins/shader_editor_plugin.h29
-rw-r--r--editor/plugins/skeleton_2d_editor_plugin.cpp5
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp86
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.h10
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.cpp14
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp41
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.h5
-rw-r--r--editor/plugins/text_editor.cpp6
-rw-r--r--editor/plugins/text_editor.h2
-rw-r--r--editor/plugins/texture_3d_editor_plugin.cpp4
-rw-r--r--editor/plugins/texture_editor_plugin.cpp2
-rw-r--r--editor/plugins/texture_layered_editor_plugin.cpp14
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp7
-rw-r--r--editor/plugins/texture_region_editor_plugin.h3
-rw-r--r--editor/plugins/theme_editor_plugin.cpp171
-rw-r--r--editor/plugins/theme_editor_preview.cpp7
-rw-r--r--editor/plugins/tiles/atlas_merging_dialog.cpp1
-rw-r--r--editor/plugins/tiles/atlas_merging_dialog.h3
-rw-r--r--editor/plugins/tiles/tile_atlas_view.cpp40
-rw-r--r--editor/plugins/tiles/tile_atlas_view.h2
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp46
-rw-r--r--editor/plugins/tiles/tile_data_editors.h14
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp25
-rw-r--r--editor/plugins/tiles/tile_map_editor.h8
-rw-r--r--editor/plugins/tiles/tile_proxies_manager_dialog.cpp1
-rw-r--r--editor/plugins/tiles/tile_proxies_manager_dialog.h2
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp62
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.h2
-rw-r--r--editor/plugins/tiles/tile_set_editor.cpp11
-rw-r--r--editor/plugins/tiles/tile_set_editor.h4
-rw-r--r--editor/plugins/tiles/tile_set_scenes_collection_source_editor.h2
-rw-r--r--editor/plugins/version_control_editor_plugin.cpp8
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp180
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h55
-rw-r--r--editor/plugins/voxel_gi_editor_plugin.cpp2
-rw-r--r--editor/project_converter_3_to_4.cpp2993
-rw-r--r--editor/project_converter_3_to_4.h52
-rw-r--r--editor/project_manager.cpp328
-rw-r--r--editor/project_manager.h2
-rw-r--r--editor/project_settings_editor.cpp9
-rw-r--r--editor/project_settings_editor.h7
-rw-r--r--editor/property_editor.cpp1866
-rw-r--r--editor/property_editor.h168
-rw-r--r--editor/property_selector.cpp4
-rw-r--r--editor/property_selector.h8
-rw-r--r--editor/rename_dialog.cpp31
-rw-r--r--editor/rename_dialog.h7
-rw-r--r--editor/scene_create_dialog.cpp2
-rw-r--r--editor/scene_tree_dock.cpp470
-rw-r--r--editor/scene_tree_editor.cpp51
-rw-r--r--editor/scene_tree_editor.h7
-rw-r--r--editor/script_create_dialog.cpp5
-rw-r--r--editor/shader_create_dialog.cpp7
-rw-r--r--editor/shader_create_dialog.h7
-rw-r--r--editor/shader_globals_editor.cpp7
-rw-r--r--editor/shader_globals_editor.h1
-rw-r--r--editor/translations/af.po29
-rw-r--r--editor/translations/ar.po26
-rw-r--r--editor/translations/az.po138
-rw-r--r--editor/translations/bg.po29
-rw-r--r--editor/translations/bn.po26
-rw-r--r--editor/translations/br.po23
-rw-r--r--editor/translations/ca.po27
-rw-r--r--editor/translations/cs.po26
-rw-r--r--editor/translations/da.po29
-rw-r--r--editor/translations/de.po43
-rw-r--r--editor/translations/editor.pot20
-rw-r--r--editor/translations/el.po26
-rw-r--r--editor/translations/en_Shaw.po23
-rw-r--r--editor/translations/eo.po29
-rw-r--r--editor/translations/es.po742
-rw-r--r--editor/translations/es_AR.po26
-rw-r--r--editor/translations/et.po26
-rw-r--r--editor/translations/eu.po29
-rw-r--r--editor/translations/fa.po26
-rw-r--r--editor/translations/fi.po26
-rw-r--r--editor/translations/fil.po23
-rw-r--r--editor/translations/fr.po2684
-rw-r--r--editor/translations/ga.po23
-rw-r--r--editor/translations/gl.po26
-rw-r--r--editor/translations/he.po26
-rw-r--r--editor/translations/hi.po29
-rw-r--r--editor/translations/hr.po29
-rw-r--r--editor/translations/hu.po26
-rw-r--r--editor/translations/id.po85
-rw-r--r--editor/translations/is.po23
-rw-r--r--editor/translations/it.po45
-rw-r--r--editor/translations/ja.po26
-rw-r--r--editor/translations/ka.po29
-rw-r--r--editor/translations/km.po23
-rw-r--r--editor/translations/ko.po26
-rw-r--r--editor/translations/lt.po29
-rw-r--r--editor/translations/lv.po26
-rw-r--r--editor/translations/mk.po20
-rw-r--r--editor/translations/ml.po23
-rw-r--r--editor/translations/mr.po23
-rw-r--r--editor/translations/ms.po29
-rw-r--r--editor/translations/nb.po26
-rw-r--r--editor/translations/nl.po26
-rw-r--r--editor/translations/pl.po85
-rw-r--r--editor/translations/pr.po26
-rw-r--r--editor/translations/pt.po27
-rw-r--r--editor/translations/pt_BR.po35
-rw-r--r--editor/translations/ro.po29
-rw-r--r--editor/translations/ru.po27
-rw-r--r--editor/translations/si.po23
-rw-r--r--editor/translations/sk.po29
-rw-r--r--editor/translations/sl.po29
-rw-r--r--editor/translations/sq.po29
-rw-r--r--editor/translations/sr_Cyrl.po26
-rw-r--r--editor/translations/sr_Latn.po23
-rw-r--r--editor/translations/sv.po26
-rw-r--r--editor/translations/te.po23
-rw-r--r--editor/translations/th.po26
-rw-r--r--editor/translations/tl.po23
-rw-r--r--editor/translations/tr.po118
-rw-r--r--editor/translations/uk.po27
-rw-r--r--editor/translations/ur_PK.po23
-rw-r--r--editor/translations/vi.po26
-rw-r--r--editor/translations/zh_CN.po32
-rw-r--r--editor/translations/zh_HK.po26
-rw-r--r--editor/translations/zh_TW.po379
-rw-r--r--gles3_builders.py8
-rw-r--r--glsl_builders.py126
-rw-r--r--main/main.cpp191
-rw-r--r--main/main.h11
-rw-r--r--main/performance.cpp7
-rw-r--r--main/performance.h6
-rw-r--r--methods.py80
-rw-r--r--misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj7
-rw-r--r--misc/dist/ios_xcode/godot_ios/dummy.h31
-rw-r--r--misc/dist/ios_xcode/godot_ios/dummy.swift31
-rwxr-xr-xmisc/scripts/clang_format.sh3
-rwxr-xr-xmisc/scripts/dotnet_format.sh28
-rwxr-xr-xmisc/scripts/file_format.sh2
-rwxr-xr-xmisc/scripts/pytest_builders.sh5
-rw-r--r--modules/bmp/SCsub2
-rw-r--r--modules/bmp/image_loader_bmp.cpp2
-rw-r--r--modules/bmp/image_loader_bmp.h2
-rw-r--r--modules/csg/SCsub3
-rw-r--r--modules/csg/csg.cpp2
-rw-r--r--modules/csg/csg_shape.cpp48
-rw-r--r--modules/csg/csg_shape.h8
-rw-r--r--modules/csg/doc_classes/CSGShape3D.xml14
-rw-r--r--modules/csg/editor/csg_gizmos.cpp10
-rw-r--r--modules/denoise/config.py11
-rw-r--r--modules/enet/doc_classes/ENetConnection.xml60
-rw-r--r--modules/enet/doc_classes/ENetMultiplayerPeer.xml34
-rw-r--r--modules/enet/doc_classes/ENetPacketPeer.xml40
-rw-r--r--modules/enet/enet_connection.cpp5
-rw-r--r--modules/enet/enet_connection.h5
-rw-r--r--modules/enet/enet_packet_peer.cpp2
-rw-r--r--modules/freetype/SCsub35
-rw-r--r--modules/freetype/config.py8
-rw-r--r--modules/gdscript/config.py1
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml267
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp180
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.h6
-rw-r--r--modules/gdscript/editor/gdscript_translation_parser_plugin.cpp8
-rw-r--r--modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd2
-rw-r--r--modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd2
-rw-r--r--modules/gdscript/gdscript.cpp91
-rw-r--r--modules/gdscript/gdscript.h5
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp6
-rw-r--r--modules/gdscript/gdscript_editor.cpp80
-rw-r--r--modules/gdscript/gdscript_parser.cpp2
-rw-r--r--modules/gdscript/gdscript_utility_functions.cpp13
-rw-r--r--modules/gdscript/gdscript_utility_functions.h3
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.cpp4
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.cpp8
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.cpp11
-rw-r--r--modules/gdscript/tests/gdscript_test_runner_suite.h34
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/preload_constant_types_are_inferred.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/preload_constant_types_are_inferred.out2
-rw-r--r--modules/gltf/SCsub2
-rw-r--r--modules/gltf/doc_classes/GLTFCamera.xml41
-rw-r--r--modules/gltf/doc_classes/GLTFDocument.xml38
-rw-r--r--modules/gltf/doc_classes/GLTFDocumentExtension.xml28
-rw-r--r--modules/gltf/doc_classes/GLTFLight.xml31
-rw-r--r--modules/gltf/doc_classes/GLTFSkeleton.xml8
-rw-r--r--modules/gltf/doc_classes/GLTFSkin.xml8
-rw-r--r--modules/gltf/doc_classes/GLTFSpecGloss.xml8
-rw-r--r--modules/gltf/doc_classes/GLTFState.xml70
-rw-r--r--modules/gltf/editor/editor_scene_importer_blend.cpp16
-rw-r--r--modules/gltf/editor/editor_scene_importer_fbx.cpp2
-rw-r--r--modules/gltf/editor/editor_scene_importer_gltf.cpp3
-rw-r--r--modules/gltf/extensions/gltf_light.cpp119
-rw-r--r--modules/gltf/extensions/gltf_light.h8
-rw-r--r--modules/gltf/extensions/gltf_spec_gloss.h5
-rw-r--r--modules/gltf/gltf_document.cpp209
-rw-r--r--modules/gltf/gltf_state.cpp79
-rw-r--r--modules/gltf/gltf_state.h68
-rw-r--r--modules/gltf/gltf_template_convert.h6
-rw-r--r--modules/gltf/register_types.cpp25
-rw-r--r--modules/gltf/structures/gltf_camera.cpp96
-rw-r--r--modules/gltf/structures/gltf_camera.h33
-rw-r--r--modules/gltf/structures/gltf_skeleton.cpp4
-rw-r--r--modules/gltf/structures/gltf_skeleton.h4
-rw-r--r--modules/gltf/structures/gltf_skin.cpp5
-rw-r--r--modules/gltf/structures/gltf_skin.h7
-rw-r--r--modules/gridmap/SCsub2
-rw-r--r--modules/gridmap/doc_classes/GridMap.xml71
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.cpp67
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.h3
-rw-r--r--modules/gridmap/grid_map.cpp90
-rw-r--r--modules/gridmap/grid_map.h7
-rw-r--r--modules/hdr/SCsub2
-rw-r--r--modules/hdr/image_loader_hdr.cpp4
-rw-r--r--modules/hdr/image_loader_hdr.h2
-rw-r--r--modules/jpg/image_loader_jpegd.cpp2
-rw-r--r--modules/jpg/image_loader_jpegd.h2
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp4
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.h2
-rw-r--r--modules/minimp3/SCsub2
-rw-r--r--modules/mono/.editorconfig29
-rw-r--r--modules/mono/Directory.Build.props5
-rw-r--r--modules/mono/Directory.Build.targets22
-rw-r--r--modules/mono/README.md45
-rw-r--r--modules/mono/SCsub35
-rw-r--r--modules/mono/SdkPackageVersions.props5
-rw-r--r--modules/mono/build_scripts/api_solution_build.py80
-rwxr-xr-xmodules/mono/build_scripts/build_assemblies.py329
-rw-r--r--modules/mono/build_scripts/gen_cs_glue_version.py20
-rw-r--r--modules/mono/build_scripts/godot_net_sdk_build.py55
-rw-r--r--modules/mono/build_scripts/godot_tools_build.py38
-rw-r--r--modules/mono/build_scripts/make_android_mono_config.py55
-rw-r--r--modules/mono/build_scripts/mono_android_config.xml28
-rw-r--r--modules/mono/build_scripts/mono_configure.py701
-rw-r--r--modules/mono/build_scripts/mono_reg_utils.py112
-rw-r--r--modules/mono/build_scripts/solution_builder.py145
-rw-r--r--modules/mono/config.py66
-rw-r--r--modules/mono/csharp_script.cpp2160
-rw-r--r--modules/mono/csharp_script.h188
-rw-r--r--modules/mono/doc_classes/GodotSharp.xml47
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln2
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj10
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props20
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets6
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/EventSignals.cs7
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs113
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs113
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic.cs5
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj4
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Methods.cs31
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ScriptBoilerplate.cs36
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs337
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs236
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj14
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.props3
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs9
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs148
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs84
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs63
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs73
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs678
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MethodInfo.cs24
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs100
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/PropertyInfo.cs23
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs408
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs36
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs658
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs298
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptRegistrarGenerator.cs19
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs284
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs428
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj4
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs4
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs10
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotIdeMetadata.cs5
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Peer.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.IdeMessaging/ResponseAwaiter.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Utils/NotifyAwaiter.cs6
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj26
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/MSBuild.exe0
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs10
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs13
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets4
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj4
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.sln14
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs61
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs228
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs36
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs209
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildTool.cs10
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/DotNetFinder.cs99
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs14
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs233
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs16
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs66
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs390
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/XcodeHelper.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs134
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj20
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs6
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs12
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs16
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs9
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs25
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs63
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs214
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs173
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Utils/FsPathUtils.cs8
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs265
-rw-r--r--modules/mono/editor/bindings_generator.cpp1886
-rw-r--r--modules/mono/editor/bindings_generator.h205
-rw-r--r--modules/mono/editor/code_completion.cpp17
-rw-r--r--modules/mono/editor/editor_internal_calls.cpp333
-rw-r--r--modules/mono/editor/editor_internal_calls.h6
-rw-r--r--modules/mono/editor/godotsharp_export.cpp144
-rw-r--r--modules/mono/editor/godotsharp_export.h48
-rw-r--r--modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs4
-rw-r--r--modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs6
-rw-r--r--modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs2
-rw-r--r--modules/mono/glue/GodotSharp/.editorconfig8
-rw-r--r--modules/mono/glue/GodotSharp/ExternalAnnotations/System.Runtime.InteropServices.xml5
-rw-r--r--modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/CallbacksInfo.cs24
-rw-r--r--modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Common.cs65
-rw-r--r--modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/ExtensionMethods.cs119
-rw-r--r--modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/GeneratorClasses.cs6
-rw-r--r--modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Godot.SourceGenerators.Internal.csproj11
-rw-r--r--modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/UnmanagedCallbacksGenerator.cs463
-rw-r--r--modules/mono/glue/GodotSharp/GodotPlugins/GodotPlugins.csproj17
-rw-r--r--modules/mono/glue/GodotSharp/GodotPlugins/Main.cs270
-rw-r--r--modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs64
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp.sln12
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp.sln.DotSettings8
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs15
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs666
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs17
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportCategoryAttribute.cs22
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportGroupAttribute.cs25
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportSubgroupAttribute.cs25
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs24
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/MustBeVariantAttribute.cs11
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs136
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/AlcReloadCfg.cs18
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs253
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GCHandleBridge.cs22
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GodotSerializationInfo.cs87
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs89
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/MethodInfo.cs25
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs24
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs1028
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.types.cs92
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs70
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs19
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs292
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/CustomGCHandle.cs98
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs111
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs245
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs677
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs20
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DisposablesTracker.cs95
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DynamicObject.cs220
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs29
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs17
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs21
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs224
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTraceListener.cs5
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GodotUnhandledExceptionEvent.cs30
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs154
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs114
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs5
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/CustomUnsafe.cs313
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs139
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/GodotDllImportResolver.cs59
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs1091
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs96
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs1092
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs522
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs99
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeVariantPtrArgs.cs20
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs976
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs33
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs611
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs146
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs164
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Object.exceptions.cs142
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs12
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs120
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs303
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs85
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs12
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/ReflectionUtils.cs16
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs73
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs92
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs120
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs106
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs354
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/UnhandledExceptionArgs.cs20
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs62
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs46
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs81
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs49
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs169
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs52
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GlobalUsings.cs5
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj73
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj.DotSettings5
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Variant.cs841
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj17
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj.DotSettings4
-rw-r--r--modules/mono/glue/base_object_glue.cpp257
-rw-r--r--modules/mono/glue/collections_glue.cpp374
-rw-r--r--modules/mono/glue/gd_glue.cpp348
-rw-r--r--modules/mono/glue/glue_header.h91
-rw-r--r--modules/mono/glue/nodepath_glue.cpp102
-rw-r--r--modules/mono/glue/runtime_interop.cpp1513
-rw-r--r--modules/mono/glue/runtime_interop.h40
-rw-r--r--modules/mono/glue/scene_tree_glue.cpp86
-rw-r--r--modules/mono/glue/string_glue.cpp85
-rw-r--r--modules/mono/glue/string_name_glue.cpp62
-rw-r--r--modules/mono/godotsharp_defs.h4
-rw-r--r--modules/mono/godotsharp_dirs.cpp134
-rw-r--r--modules/mono/godotsharp_dirs.h9
-rw-r--r--modules/mono/interop_types.h208
-rw-r--r--modules/mono/managed_callable.cpp60
-rw-r--r--modules/mono/managed_callable.h14
-rw-r--r--modules/mono/mono_gc_handle.cpp32
-rw-r--r--modules/mono/mono_gc_handle.h56
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp1471
-rw-r--r--modules/mono/mono_gd/gd_mono.h246
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp482
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.h138
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.cpp350
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.h258
-rw-r--r--modules/mono/mono_gd/gd_mono_class.cpp576
-rw-r--r--modules/mono/mono_gd/gd_mono_class.h160
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp556
-rw-r--r--modules/mono/mono_gd/gd_mono_field.h78
-rw-r--r--modules/mono/mono_gd/gd_mono_header.h52
-rw-r--r--modules/mono/mono_gd/gd_mono_internals.cpp145
-rw-r--r--modules/mono/mono_gd/gd_mono_internals.h52
-rw-r--r--modules/mono/mono_gd/gd_mono_log.cpp209
-rw-r--r--modules/mono/mono_gd/gd_mono_log.h71
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp1824
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h605
-rw-r--r--modules/mono/mono_gd/gd_mono_method.cpp296
-rw-r--r--modules/mono/mono_gd/gd_mono_method.h97
-rw-r--r--modules/mono/mono_gd/gd_mono_method_thunk.h320
-rw-r--r--modules/mono/mono_gd/gd_mono_property.cpp202
-rw-r--r--modules/mono/mono_gd/gd_mono_property.h80
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp677
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h205
-rw-r--r--modules/mono/mono_gd/gd_mono_wasm_m2n.h263
-rw-r--r--modules/mono/mono_gd/i_mono_class_member.h70
-rw-r--r--modules/mono/mono_gd/managed_type.cpp58
-rw-r--r--modules/mono/mono_gd/managed_type.h55
-rw-r--r--modules/mono/mono_gd/support/android_support.cpp2
-rw-r--r--modules/mono/signal_awaiter_utils.cpp82
-rw-r--r--modules/mono/signal_awaiter_utils.h21
-rw-r--r--modules/mono/utils/mono_reg_utils.cpp242
-rw-r--r--modules/mono/utils/path_utils.cpp33
-rw-r--r--modules/mono/utils/path_utils.h2
-rw-r--r--modules/mono/utils/string_utils.cpp29
-rw-r--r--modules/mono/utils/string_utils.h3
-rw-r--r--modules/msdfgen/config.py3
-rw-r--r--modules/multiplayer/doc_classes/MultiplayerSpawner.xml12
-rw-r--r--modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml14
-rw-r--r--modules/multiplayer/doc_classes/SceneMultiplayer.xml12
-rw-r--r--modules/multiplayer/doc_classes/SceneReplicationConfig.xml22
-rw-r--r--modules/multiplayer/editor/replication_editor_plugin.cpp122
-rw-r--r--modules/multiplayer/editor/replication_editor_plugin.h20
-rw-r--r--modules/navigation/editor/navigation_mesh_editor_plugin.cpp2
-rw-r--r--modules/navigation/godot_navigation_server.cpp16
-rw-r--r--modules/navigation/godot_navigation_server.h8
-rw-r--r--modules/navigation/navigation_mesh_generator.cpp89
-rw-r--r--modules/noise/config.py2
-rw-r--r--modules/noise/doc_classes/Noise.xml34
-rw-r--r--modules/noise/doc_classes/NoiseTexture2D.xml (renamed from modules/noise/doc_classes/NoiseTexture.xml)6
-rw-r--r--modules/noise/editor/noise_editor_plugin.cpp6
-rw-r--r--modules/noise/fastnoise_lite.cpp18
-rw-r--r--modules/noise/fastnoise_lite.h2
-rw-r--r--modules/noise/noise_texture_2d.cpp (renamed from modules/noise/noise_texture.cpp)138
-rw-r--r--modules/noise/noise_texture_2d.h (renamed from modules/noise/noise_texture.h)18
-rw-r--r--modules/noise/register_types.cpp5
-rw-r--r--modules/openxr/doc_classes/OpenXRAction.xml2
-rw-r--r--modules/openxr/doc_classes/OpenXRActionMap.xml16
-rw-r--r--modules/openxr/doc_classes/OpenXRActionSet.xml4
-rw-r--r--modules/openxr/doc_classes/OpenXRIPBinding.xml6
-rw-r--r--modules/openxr/doc_classes/OpenXRInteractionProfile.xml2
-rw-r--r--modules/openxr/editor/openxr_action_editor.cpp2
-rw-r--r--modules/openxr/editor/openxr_action_map_editor.cpp8
-rw-r--r--modules/openxr/editor/openxr_action_set_editor.cpp4
-rw-r--r--modules/raycast/SCsub4
-rw-r--r--modules/raycast/config.py17
-rw-r--r--modules/regex/doc_classes/RegEx.xml35
-rw-r--r--modules/regex/doc_classes/RegExMatch.xml6
-rw-r--r--modules/regex/regex.cpp17
-rw-r--r--modules/regex/regex.h7
-rw-r--r--modules/regex/tests/test_regex.h2
-rw-r--r--modules/svg/image_loader_svg.cpp26
-rw-r--r--modules/svg/image_loader_svg.h9
-rw-r--r--modules/text_server_adv/SCsub29
-rw-r--r--modules/text_server_adv/config.py8
-rw-r--r--modules/text_server_adv/text_server_adv.cpp583
-rw-r--r--modules/text_server_adv/text_server_adv.h24
-rw-r--r--modules/text_server_fb/SCsub5
-rw-r--r--modules/text_server_fb/text_server_fb.cpp298
-rw-r--r--modules/text_server_fb/text_server_fb.h18
-rw-r--r--modules/tga/SCsub2
-rw-r--r--modules/tga/image_loader_tga.cpp2
-rw-r--r--modules/tga/image_loader_tga.h2
-rw-r--r--modules/theora/config.py3
-rw-r--r--modules/theora/doc_classes/VideoStreamTheora.xml2
-rw-r--r--modules/tinyexr/image_loader_tinyexr.cpp6
-rw-r--r--modules/tinyexr/image_loader_tinyexr.h2
-rw-r--r--modules/upnp/doc_classes/UPNP.xml59
-rw-r--r--modules/upnp/doc_classes/UPNPDevice.xml18
-rw-r--r--modules/upnp/upnp.cpp2
-rw-r--r--modules/visual_script/SCsub11
-rw-r--r--modules/visual_script/config.py63
-rw-r--r--modules/visual_script/doc_classes/VisualScript.xml357
-rw-r--r--modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml19
-rw-r--r--modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml221
-rw-r--r--modules/visual_script/doc_classes/VisualScriptClassConstant.xml23
-rw-r--r--modules/visual_script/doc_classes/VisualScriptComment.xml23
-rw-r--r--modules/visual_script/doc_classes/VisualScriptComposeArray.xml11
-rw-r--r--modules/visual_script/doc_classes/VisualScriptCondition.xml18
-rw-r--r--modules/visual_script/doc_classes/VisualScriptConstant.xml23
-rw-r--r--modules/visual_script/doc_classes/VisualScriptConstructor.xml35
-rw-r--r--modules/visual_script/doc_classes/VisualScriptCustomNode.xml166
-rw-r--r--modules/visual_script/doc_classes/VisualScriptCustomNodes.xml37
-rw-r--r--modules/visual_script/doc_classes/VisualScriptDeconstruct.xml16
-rw-r--r--modules/visual_script/doc_classes/VisualScriptEmitSignal.xml20
-rw-r--r--modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml16
-rw-r--r--modules/visual_script/doc_classes/VisualScriptExpression.xml11
-rw-r--r--modules/visual_script/doc_classes/VisualScriptFunction.xml11
-rw-r--r--modules/visual_script/doc_classes/VisualScriptFunctionCall.xml75
-rw-r--r--modules/visual_script/doc_classes/VisualScriptFunctionState.xml35
-rw-r--r--modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml16
-rw-r--r--modules/visual_script/doc_classes/VisualScriptIndexGet.xml11
-rw-r--r--modules/visual_script/doc_classes/VisualScriptIndexSet.xml11
-rw-r--r--modules/visual_script/doc_classes/VisualScriptInputAction.xml33
-rw-r--r--modules/visual_script/doc_classes/VisualScriptIterator.xml18
-rw-r--r--modules/visual_script/doc_classes/VisualScriptLists.xml77
-rw-r--r--modules/visual_script/doc_classes/VisualScriptLocalVar.xml23
-rw-r--r--modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml25
-rw-r--r--modules/visual_script/doc_classes/VisualScriptMathConstant.xml49
-rw-r--r--modules/visual_script/doc_classes/VisualScriptNode.xml47
-rw-r--r--modules/visual_script/doc_classes/VisualScriptOperator.xml23
-rw-r--r--modules/visual_script/doc_classes/VisualScriptPreload.xml20
-rw-r--r--modules/visual_script/doc_classes/VisualScriptPropertyGet.xml48
-rw-r--r--modules/visual_script/doc_classes/VisualScriptPropertySet.xml84
-rw-r--r--modules/visual_script/doc_classes/VisualScriptResourcePath.xml13
-rw-r--r--modules/visual_script/doc_classes/VisualScriptReturn.xml24
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSceneNode.xml20
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSceneTree.xml11
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSelect.xml22
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSelf.xml15
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSequence.xml22
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSubCall.xml11
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSwitch.xml20
-rw-r--r--modules/visual_script/doc_classes/VisualScriptTypeCast.xml19
-rw-r--r--modules/visual_script/doc_classes/VisualScriptVariableGet.xml20
-rw-r--r--modules/visual_script/doc_classes/VisualScriptVariableSet.xml21
-rw-r--r--modules/visual_script/doc_classes/VisualScriptWhile.xml17
-rw-r--r--modules/visual_script/doc_classes/VisualScriptYield.xml30
-rw-r--r--modules/visual_script/doc_classes/VisualScriptYieldSignal.xml36
-rw-r--r--modules/visual_script/editor/visual_script_editor.cpp4936
-rw-r--r--modules/visual_script/editor/visual_script_editor.h377
-rw-r--r--modules/visual_script/editor/visual_script_property_selector.cpp1277
-rw-r--r--modules/visual_script/editor/visual_script_property_selector.h229
-rw-r--r--modules/visual_script/icons/VisualScript.svg1
-rw-r--r--modules/visual_script/icons/VisualScriptInternal.svg1
-rw-r--r--modules/visual_script/register_types.cpp150
-rw-r--r--modules/visual_script/visual_script.cpp2502
-rw-r--r--modules/visual_script/visual_script.h627
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.cpp1380
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.h153
-rw-r--r--modules/visual_script/visual_script_expression.cpp1570
-rw-r--r--modules/visual_script/visual_script_expression.h284
-rw-r--r--modules/visual_script/visual_script_flow_control.cpp880
-rw-r--r--modules/visual_script/visual_script_flow_control.h268
-rw-r--r--modules/visual_script/visual_script_func_nodes.cpp2444
-rw-r--r--modules/visual_script/visual_script_func_nodes.h363
-rw-r--r--modules/visual_script/visual_script_nodes.cpp4072
-rw-r--r--modules/visual_script/visual_script_nodes.h1092
-rw-r--r--modules/visual_script/visual_script_yield_nodes.cpp598
-rw-r--r--modules/visual_script/visual_script_yield_nodes.h147
-rw-r--r--modules/vorbis/config.py3
-rw-r--r--modules/webp/SCsub238
-rw-r--r--modules/webp/image_loader_webp.cpp2
-rw-r--r--modules/webp/image_loader_webp.h2
-rw-r--r--modules/webrtc/SCsub2
-rw-r--r--modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml10
-rw-r--r--modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml18
-rw-r--r--modules/webrtc/doc_classes/WebRTCPeerConnection.xml34
-rw-r--r--modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml20
-rw-r--r--modules/webrtc/webrtc_data_channel_js.cpp2
-rw-r--r--modules/webrtc/webrtc_data_channel_js.h4
-rw-r--r--modules/webrtc/webrtc_peer_connection.cpp4
-rw-r--r--modules/webrtc/webrtc_peer_connection_js.cpp2
-rw-r--r--modules/webrtc/webrtc_peer_connection_js.h2
-rw-r--r--modules/websocket/SCsub2
-rw-r--r--modules/websocket/doc_classes/WebSocketClient.xml26
-rw-r--r--modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml14
-rw-r--r--modules/websocket/doc_classes/WebSocketPeer.xml18
-rw-r--r--modules/websocket/doc_classes/WebSocketServer.xml40
-rw-r--r--modules/websocket/emws_client.cpp12
-rw-r--r--modules/websocket/emws_client.h4
-rw-r--r--modules/websocket/emws_peer.cpp10
-rw-r--r--modules/websocket/emws_peer.h4
-rw-r--r--modules/websocket/register_types.cpp9
-rw-r--r--modules/websocket/remote_debugger_peer_websocket.cpp4
-rw-r--r--modules/websocket/remote_debugger_peer_websocket.h2
-rw-r--r--modules/websocket/wsl_client.cpp4
-rw-r--r--modules/websocket/wsl_client.h4
-rw-r--r--modules/websocket/wsl_peer.cpp4
-rw-r--r--modules/websocket/wsl_peer.h4
-rw-r--r--modules/websocket/wsl_server.cpp4
-rw-r--r--modules/websocket/wsl_server.h4
-rw-r--r--modules/webxr/SCsub2
-rw-r--r--modules/webxr/doc_classes/WebXRInterface.xml26
-rw-r--r--modules/webxr/register_types.cpp6
-rw-r--r--modules/webxr/webxr_interface_js.cpp4
-rw-r--r--modules/webxr/webxr_interface_js.h4
-rw-r--r--platform/android/README.md7
-rw-r--r--platform/android/SCsub8
-rw-r--r--platform/android/android_input_handler.cpp53
-rw-r--r--platform/android/android_input_handler.h2
-rw-r--r--platform/android/android_keys_utils.cpp47
-rw-r--r--platform/android/android_keys_utils.h251
-rw-r--r--platform/android/detect.py44
-rw-r--r--platform/android/dir_access_jandroid.cpp16
-rw-r--r--platform/android/dir_access_jandroid.h1
-rw-r--r--platform/android/display_server_android.cpp8
-rw-r--r--platform/android/display_server_android.h6
-rw-r--r--platform/android/export/export_plugin.cpp61
-rw-r--r--platform/android/export/export_plugin.h5
-rw-r--r--platform/android/export/godot_plugin_config.cpp2
-rw-r--r--platform/android/file_access_android.h36
-rw-r--r--platform/android/file_access_filesystem_jandroid.cpp19
-rw-r--r--platform/android/file_access_filesystem_jandroid.h2
-rw-r--r--platform/android/java/build.gradle4
-rw-r--r--platform/android/java/lib/build.gradle2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotIO.java7
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotLib.java2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java49
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java19
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java22
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt8
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt5
-rw-r--r--platform/android/java_godot_io_wrapper.cpp10
-rw-r--r--platform/android/java_godot_io_wrapper.h6
-rw-r--r--platform/android/java_godot_lib_jni.cpp5
-rw-r--r--platform/android/java_godot_lib_jni.h2
-rw-r--r--platform/android/os_android.cpp8
-rw-r--r--platform/ios/README.md14
-rw-r--r--platform/ios/detect.py15
-rw-r--r--platform/ios/display_server_ios.h4
-rw-r--r--platform/ios/display_server_ios.mm42
-rw-r--r--platform/ios/export/export_plugin.cpp222
-rw-r--r--platform/ios/export/export_plugin.h16
-rw-r--r--platform/ios/export/godot_plugin_config.cpp15
-rw-r--r--platform/ios/export/godot_plugin_config.h3
-rw-r--r--platform/ios/keyboard_input_view.h2
-rw-r--r--platform/ios/keyboard_input_view.mm2
-rw-r--r--platform/ios/platform_config.h2
-rw-r--r--platform/javascript/README.md15
-rw-r--r--platform/linuxbsd/README.md14
-rw-r--r--platform/linuxbsd/detect.py46
-rw-r--r--platform/linuxbsd/detect_prime_x11.cpp5
-rw-r--r--platform/linuxbsd/display_server_x11.cpp32
-rw-r--r--platform/linuxbsd/display_server_x11.h3
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp22
-rw-r--r--platform/linuxbsd/os_linuxbsd.h2
-rw-r--r--platform/macos/README.md19
-rw-r--r--platform/macos/detect.py29
-rw-r--r--platform/macos/dir_access_macos.h8
-rw-r--r--platform/macos/dir_access_macos.mm2
-rw-r--r--platform/macos/display_server_macos.h35
-rw-r--r--platform/macos/display_server_macos.mm494
-rw-r--r--platform/macos/export/codesign.cpp82
-rw-r--r--platform/macos/export/export.cpp8
-rw-r--r--platform/macos/export/export_plugin.cpp780
-rw-r--r--platform/macos/export/export_plugin.h5
-rw-r--r--platform/macos/godot_menu_item.h1
-rw-r--r--platform/macos/os_macos.h2
-rw-r--r--platform/macos/os_macos.mm17
-rw-r--r--platform/uwp/README.md20
-rw-r--r--platform/uwp/detect.py39
-rw-r--r--platform/uwp/export/app_packager.cpp4
-rw-r--r--platform/uwp/export/export_plugin.cpp23
-rw-r--r--platform/uwp/export/export_plugin.h5
-rw-r--r--platform/uwp/os_uwp.cpp7
-rw-r--r--platform/uwp/os_uwp.h3
-rw-r--r--platform/web/.eslintrc.engine.js (renamed from platform/javascript/.eslintrc.engine.js)0
-rw-r--r--platform/web/.eslintrc.js (renamed from platform/javascript/.eslintrc.js)0
-rw-r--r--platform/web/.eslintrc.libs.js (renamed from platform/javascript/.eslintrc.libs.js)0
-rw-r--r--platform/web/README.md22
-rw-r--r--platform/web/SCsub (renamed from platform/javascript/SCsub)22
-rw-r--r--platform/web/api/api.cpp (renamed from platform/javascript/api/api.cpp)20
-rw-r--r--platform/web/api/api.h (renamed from platform/javascript/api/api.h)10
-rw-r--r--platform/web/api/javascript_singleton.h (renamed from platform/javascript/api/javascript_singleton.h)0
-rw-r--r--platform/web/api/web_tools_editor_plugin.cpp (renamed from platform/javascript/api/javascript_tools_editor_plugin.cpp)30
-rw-r--r--platform/web/api/web_tools_editor_plugin.h (renamed from platform/javascript/api/javascript_tools_editor_plugin.h)18
-rw-r--r--platform/web/audio_driver_web.cpp (renamed from platform/javascript/audio_driver_javascript.cpp)38
-rw-r--r--platform/web/audio_driver_web.h (renamed from platform/javascript/audio_driver_javascript.h)20
-rw-r--r--platform/web/detect.py (renamed from platform/javascript/detect.py)16
-rw-r--r--platform/web/display_server_web.cpp (renamed from platform/javascript/display_server_javascript.cpp)244
-rw-r--r--platform/web/display_server_web.h (renamed from platform/javascript/display_server_javascript.h)22
-rw-r--r--platform/web/dom_keys.inc (renamed from platform/javascript/dom_keys.inc)0
-rw-r--r--platform/web/emscripten_helpers.py (renamed from platform/javascript/emscripten_helpers.py)4
-rw-r--r--platform/web/export/editor_http_server.h (renamed from platform/javascript/export/export_server.h)16
-rw-r--r--platform/web/export/export.cpp (renamed from platform/javascript/export/export.cpp)4
-rw-r--r--platform/web/export/export.h (renamed from platform/javascript/export/export.h)8
-rw-r--r--platform/web/export/export_plugin.cpp (renamed from platform/javascript/export/export_plugin.cpp)98
-rw-r--r--platform/web/export/export_plugin.h (renamed from platform/javascript/export/export_plugin.h)23
-rw-r--r--platform/web/godot_audio.h (renamed from platform/javascript/godot_audio.h)0
-rw-r--r--platform/web/godot_js.h (renamed from platform/javascript/godot_js.h)2
-rw-r--r--platform/web/godot_webgl2.h (renamed from platform/javascript/godot_webgl2.h)0
-rw-r--r--platform/web/http_client_web.cpp (renamed from platform/javascript/http_client_javascript.cpp)66
-rw-r--r--platform/web/http_client_web.h (renamed from platform/javascript/http_client_javascript.h)14
-rw-r--r--platform/web/javascript_singleton.cpp (renamed from platform/javascript/javascript_singleton.cpp)6
-rw-r--r--platform/web/js/engine/config.js (renamed from platform/javascript/js/engine/config.js)0
-rw-r--r--platform/web/js/engine/engine.externs.js (renamed from platform/javascript/js/engine/engine.externs.js)0
-rw-r--r--platform/web/js/engine/engine.js (renamed from platform/javascript/js/engine/engine.js)2
-rw-r--r--platform/web/js/engine/preloader.js (renamed from platform/javascript/js/engine/preloader.js)0
-rw-r--r--platform/web/js/jsdoc2rst/publish.js (renamed from platform/javascript/js/jsdoc2rst/publish.js)0
-rw-r--r--platform/web/js/libs/audio.worklet.js (renamed from platform/javascript/js/libs/audio.worklet.js)0
-rw-r--r--platform/web/js/libs/library_godot_audio.js (renamed from platform/javascript/js/libs/library_godot_audio.js)0
-rw-r--r--platform/web/js/libs/library_godot_display.js (renamed from platform/javascript/js/libs/library_godot_display.js)77
-rw-r--r--platform/web/js/libs/library_godot_fetch.js (renamed from platform/javascript/js/libs/library_godot_fetch.js)0
-rw-r--r--platform/web/js/libs/library_godot_input.js (renamed from platform/javascript/js/libs/library_godot_input.js)0
-rw-r--r--platform/web/js/libs/library_godot_javascript_singleton.js (renamed from platform/javascript/js/libs/library_godot_javascript_singleton.js)0
-rw-r--r--platform/web/js/libs/library_godot_os.js (renamed from platform/javascript/js/libs/library_godot_os.js)0
-rw-r--r--platform/web/js/libs/library_godot_runtime.js (renamed from platform/javascript/js/libs/library_godot_runtime.js)0
-rw-r--r--platform/web/logo.png (renamed from platform/javascript/logo.png)bin1234 -> 1234 bytes
-rw-r--r--platform/web/os_web.cpp (renamed from platform/javascript/os_javascript.cpp)98
-rw-r--r--platform/web/os_web.h (renamed from platform/javascript/os_javascript.h)21
-rw-r--r--platform/web/package-lock.json (renamed from platform/javascript/package-lock.json)0
-rw-r--r--platform/web/package.json (renamed from platform/javascript/package.json)2
-rw-r--r--platform/web/platform_config.h (renamed from platform/javascript/platform_config.h)2
-rw-r--r--platform/web/run_icon.png (renamed from platform/javascript/run_icon.png)bin290 -> 290 bytes
-rw-r--r--platform/web/serve.json (renamed from platform/javascript/serve.json)0
-rw-r--r--platform/web/web_main.cpp (renamed from platform/javascript/javascript_main.cpp)16
-rw-r--r--platform/web/web_runtime.cpp (renamed from platform/javascript/javascript_runtime.cpp)6
-rw-r--r--platform/windows/README.md15
-rw-r--r--platform/windows/crash_handler_windows.cpp10
-rw-r--r--platform/windows/detect.py413
-rw-r--r--platform/windows/display_server_windows.cpp45
-rw-r--r--platform/windows/display_server_windows.h4
-rw-r--r--platform/windows/export/export_plugin.cpp31
-rw-r--r--platform/windows/export/export_plugin.h5
-rw-r--r--platform/windows/os_windows.cpp12
-rw-r--r--platform/windows/os_windows.h1
-rw-r--r--platform/windows/platform_windows_builders.py2
-rw-r--r--platform_methods.py36
-rw-r--r--scene/2d/animated_sprite_2d.cpp35
-rw-r--r--scene/2d/animated_sprite_2d.h2
-rw-r--r--scene/2d/area_2d.cpp26
-rw-r--r--scene/2d/area_2d.h2
-rw-r--r--scene/2d/audio_stream_player_2d.cpp8
-rw-r--r--scene/2d/audio_stream_player_2d.h2
-rw-r--r--scene/2d/camera_2d.cpp6
-rw-r--r--scene/2d/camera_2d.h2
-rw-r--r--scene/2d/collision_object_2d.cpp22
-rw-r--r--scene/2d/collision_object_2d.h10
-rw-r--r--scene/2d/collision_polygon_2d.cpp2
-rw-r--r--scene/2d/collision_shape_2d.cpp2
-rw-r--r--scene/2d/cpu_particles_2d.cpp64
-rw-r--r--scene/2d/cpu_particles_2d.h2
-rw-r--r--scene/2d/gpu_particles_2d.cpp20
-rw-r--r--scene/2d/gpu_particles_2d.h2
-rw-r--r--scene/2d/light_2d.cpp6
-rw-r--r--scene/2d/light_2d.h2
-rw-r--r--scene/2d/line_2d.cpp8
-rw-r--r--scene/2d/marker_2d.cpp (renamed from scene/2d/position_2d.cpp)26
-rw-r--r--scene/2d/marker_2d.h (renamed from scene/2d/position_2d.h)14
-rw-r--r--scene/2d/navigation_agent_2d.cpp14
-rw-r--r--scene/2d/navigation_agent_2d.h8
-rw-r--r--scene/2d/navigation_obstacle_2d.cpp4
-rw-r--r--scene/2d/navigation_obstacle_2d.h2
-rw-r--r--scene/2d/navigation_region_2d.cpp4
-rw-r--r--scene/2d/path_2d.cpp50
-rw-r--r--scene/2d/path_2d.h12
-rw-r--r--scene/2d/physical_bone_2d.cpp6
-rw-r--r--scene/2d/physical_bone_2d.h4
-rw-r--r--scene/2d/physics_body_2d.cpp384
-rw-r--r--scene/2d/physics_body_2d.h56
-rw-r--r--scene/2d/polygon_2d.cpp12
-rw-r--r--scene/2d/polygon_2d.h2
-rw-r--r--scene/2d/ray_cast_2d.cpp7
-rw-r--r--scene/2d/ray_cast_2d.h2
-rw-r--r--scene/2d/shape_cast_2d.cpp31
-rw-r--r--scene/2d/skeleton_2d.cpp4
-rw-r--r--scene/2d/sprite_2d.cpp18
-rw-r--r--scene/2d/sprite_2d.h2
-rw-r--r--scene/2d/tile_map.cpp41
-rw-r--r--scene/2d/tile_map.h2
-rw-r--r--scene/3d/area_3d.cpp28
-rw-r--r--scene/3d/area_3d.h2
-rw-r--r--scene/3d/audio_stream_player_3d.cpp20
-rw-r--r--scene/3d/audio_stream_player_3d.h2
-rw-r--r--scene/3d/bone_attachment_3d.cpp14
-rw-r--r--scene/3d/bone_attachment_3d.h2
-rw-r--r--scene/3d/camera_3d.cpp11
-rw-r--r--scene/3d/camera_3d.h3
-rw-r--r--scene/3d/collision_object_3d.cpp20
-rw-r--r--scene/3d/collision_object_3d.h8
-rw-r--r--scene/3d/collision_polygon_3d.cpp2
-rw-r--r--scene/3d/collision_shape_3d.cpp6
-rw-r--r--scene/3d/cpu_particles_3d.cpp72
-rw-r--r--scene/3d/cpu_particles_3d.h4
-rw-r--r--scene/3d/decal.cpp7
-rw-r--r--scene/3d/decal.h2
-rw-r--r--scene/3d/fog_volume.cpp7
-rw-r--r--scene/3d/fog_volume.h2
-rw-r--r--scene/3d/gpu_particles_3d.cpp22
-rw-r--r--scene/3d/gpu_particles_3d.h2
-rw-r--r--scene/3d/gpu_particles_collision_3d.cpp47
-rw-r--r--scene/3d/gpu_particles_collision_3d.h9
-rw-r--r--scene/3d/joint_3d.cpp168
-rw-r--r--scene/3d/joint_3d.h36
-rw-r--r--scene/3d/label_3d.cpp52
-rw-r--r--scene/3d/label_3d.h8
-rw-r--r--scene/3d/light_3d.cpp41
-rw-r--r--scene/3d/light_3d.h5
-rw-r--r--scene/3d/lightmap_gi.cpp15
-rw-r--r--scene/3d/lightmap_gi.h2
-rw-r--r--scene/3d/marker_3d.cpp (renamed from scene/3d/position_3d.cpp)6
-rw-r--r--scene/3d/marker_3d.h (renamed from scene/3d/position_3d.h)14
-rw-r--r--scene/3d/navigation_agent_3d.cpp14
-rw-r--r--scene/3d/navigation_agent_3d.h8
-rw-r--r--scene/3d/navigation_obstacle_3d.cpp4
-rw-r--r--scene/3d/navigation_obstacle_3d.h2
-rw-r--r--scene/3d/navigation_region_3d.cpp13
-rw-r--r--scene/3d/node_3d.cpp60
-rw-r--r--scene/3d/node_3d.h8
-rw-r--r--scene/3d/path_3d.cpp65
-rw-r--r--scene/3d/path_3d.h12
-rw-r--r--scene/3d/physics_body_3d.cpp429
-rw-r--r--scene/3d/physics_body_3d.h56
-rw-r--r--scene/3d/ray_cast_3d.cpp7
-rw-r--r--scene/3d/ray_cast_3d.h2
-rw-r--r--scene/3d/reflection_probe.cpp7
-rw-r--r--scene/3d/reflection_probe.h2
-rw-r--r--scene/3d/skeleton_3d.cpp78
-rw-r--r--scene/3d/skeleton_3d.h5
-rw-r--r--scene/3d/skeleton_ik_3d.cpp14
-rw-r--r--scene/3d/skeleton_ik_3d.h2
-rw-r--r--scene/3d/soft_body_3d.cpp (renamed from scene/3d/soft_dynamic_body_3d.cpp)243
-rw-r--r--scene/3d/soft_body_3d.h (renamed from scene/3d/soft_dynamic_body_3d.h)31
-rw-r--r--scene/3d/sprite_3d.cpp86
-rw-r--r--scene/3d/sprite_3d.h4
-rw-r--r--scene/3d/vehicle_body_3d.cpp2
-rw-r--r--scene/3d/vehicle_body_3d.h4
-rw-r--r--scene/3d/velocity_tracker_3d.h2
-rw-r--r--scene/3d/visual_instance_3d.cpp32
-rw-r--r--scene/3d/visual_instance_3d.h4
-rw-r--r--scene/3d/voxelizer.cpp10
-rw-r--r--scene/3d/xr_nodes.cpp12
-rw-r--r--scene/3d/xr_nodes.h2
-rw-r--r--scene/SCsub1
-rw-r--r--scene/animation/animation_blend_space_1d.cpp9
-rw-r--r--scene/animation/animation_blend_space_1d.h2
-rw-r--r--scene/animation/animation_blend_space_2d.cpp13
-rw-r--r--scene/animation/animation_blend_space_2d.h2
-rw-r--r--scene/animation/animation_blend_tree.cpp53
-rw-r--r--scene/animation/animation_blend_tree.h14
-rw-r--r--scene/animation/animation_node_state_machine.cpp51
-rw-r--r--scene/animation/animation_node_state_machine.h9
-rw-r--r--scene/animation/animation_player.cpp25
-rw-r--r--scene/animation/animation_player.h2
-rw-r--r--scene/animation/animation_tree.cpp38
-rw-r--r--scene/animation/animation_tree.h3
-rw-r--r--scene/animation/tween.cpp8
-rw-r--r--scene/audio/audio_stream_player.cpp10
-rw-r--r--scene/audio/audio_stream_player.h2
-rw-r--r--scene/gui/aspect_ratio_container.cpp12
-rw-r--r--scene/gui/base_button.cpp11
-rw-r--r--scene/gui/base_button.h4
-rw-r--r--scene/gui/box_container.cpp3
-rw-r--r--scene/gui/button.cpp94
-rw-r--r--scene/gui/button.h4
-rw-r--r--scene/gui/check_box.cpp2
-rw-r--r--scene/gui/check_button.cpp2
-rw-r--r--scene/gui/code_edit.cpp14
-rw-r--r--scene/gui/code_edit.h8
-rw-r--r--scene/gui/color_mode.cpp4
-rw-r--r--scene/gui/color_picker.cpp103
-rw-r--r--scene/gui/color_picker.h3
-rw-r--r--scene/gui/color_rect.cpp3
-rw-r--r--scene/gui/control.cpp588
-rw-r--r--scene/gui/control.h31
-rw-r--r--scene/gui/dialogs.cpp5
-rw-r--r--scene/gui/file_dialog.cpp40
-rw-r--r--scene/gui/graph_edit.cpp126
-rw-r--r--scene/gui/graph_edit.h7
-rw-r--r--scene/gui/graph_node.cpp84
-rw-r--r--scene/gui/graph_node.h10
-rw-r--r--scene/gui/grid_container.cpp5
-rw-r--r--scene/gui/item_list.cpp87
-rw-r--r--scene/gui/label.cpp100
-rw-r--r--scene/gui/label.h11
-rw-r--r--scene/gui/line_edit.cpp114
-rw-r--r--scene/gui/line_edit.h31
-rw-r--r--scene/gui/link_button.cpp4
-rw-r--r--scene/gui/menu_bar.cpp874
-rw-r--r--scene/gui/menu_bar.h156
-rw-r--r--scene/gui/menu_button.cpp26
-rw-r--r--scene/gui/nine_patch_rect.cpp17
-rw-r--r--scene/gui/option_button.cpp100
-rw-r--r--scene/gui/option_button.h9
-rw-r--r--scene/gui/popup_menu.cpp339
-rw-r--r--scene/gui/popup_menu.h11
-rw-r--r--scene/gui/range.cpp20
-rw-r--r--scene/gui/reference_rect.cpp15
-rw-r--r--scene/gui/rich_text_label.cpp137
-rw-r--r--scene/gui/rich_text_label.h10
-rw-r--r--scene/gui/scroll_container.cpp87
-rw-r--r--scene/gui/scroll_container.h4
-rw-r--r--scene/gui/slider.cpp12
-rw-r--r--scene/gui/spin_box.cpp58
-rw-r--r--scene/gui/spin_box.h4
-rw-r--r--scene/gui/split_container.cpp6
-rw-r--r--scene/gui/subviewport_container.cpp4
-rw-r--r--scene/gui/tab_bar.cpp40
-rw-r--r--scene/gui/tab_container.cpp30
-rw-r--r--scene/gui/text_edit.cpp119
-rw-r--r--scene/gui/text_edit.h3
-rw-r--r--scene/gui/texture_button.cpp35
-rw-r--r--scene/gui/texture_progress_bar.cpp59
-rw-r--r--scene/gui/texture_rect.cpp16
-rw-r--r--scene/gui/tree.cpp224
-rw-r--r--scene/gui/tree.h9
-rw-r--r--scene/gui/video_stream_player.cpp12
-rw-r--r--scene/gui/video_stream_player.h2
-rw-r--r--scene/main/canvas_item.cpp11
-rw-r--r--scene/main/canvas_item.h1
-rw-r--r--scene/main/canvas_layer.cpp8
-rw-r--r--scene/main/canvas_layer.h2
-rw-r--r--scene/main/multiplayer_api.cpp22
-rw-r--r--scene/main/node.cpp49
-rw-r--r--scene/main/node.h21
-rw-r--r--scene/main/resource_preloader.cpp2
-rw-r--r--scene/main/scene_tree.cpp12
-rw-r--r--scene/main/scene_tree.h4
-rw-r--r--scene/main/viewport.cpp59
-rw-r--r--scene/main/viewport.h4
-rw-r--r--scene/main/window.cpp177
-rw-r--r--scene/main/window.h6
-rw-r--r--scene/register_scene_types.cpp131
-rw-r--r--scene/register_scene_types.h3
-rw-r--r--scene/resources/animation.cpp915
-rw-r--r--scene/resources/animation.h63
-rw-r--r--scene/resources/animation_library.cpp2
-rw-r--r--scene/resources/bit_map.cpp7
-rw-r--r--scene/resources/bit_map.h5
-rw-r--r--scene/resources/bone_map.cpp10
-rw-r--r--scene/resources/bone_map.h6
-rw-r--r--scene/resources/camera_effects.cpp10
-rw-r--r--scene/resources/camera_effects.h2
-rw-r--r--scene/resources/canvas_item_material.cpp6
-rw-r--r--scene/resources/canvas_item_material.h2
-rw-r--r--scene/resources/capsule_shape_3d.cpp4
-rw-r--r--scene/resources/curve.cpp12
-rw-r--r--scene/resources/cylinder_shape_3d.cpp4
-rw-r--r--scene/resources/default_theme/default_theme.cpp59
-rw-r--r--scene/resources/default_theme/default_theme.h3
-rw-r--r--scene/resources/environment.cpp56
-rw-r--r--scene/resources/environment.h10
-rw-r--r--scene/resources/font.cpp139
-rw-r--r--scene/resources/font.h22
-rw-r--r--scene/resources/immediate_mesh.cpp4
-rw-r--r--scene/resources/immediate_mesh.h2
-rw-r--r--scene/resources/importer_mesh.cpp6
-rw-r--r--scene/resources/label_settings.h8
-rw-r--r--scene/resources/material.cpp273
-rw-r--r--scene/resources/material.h12
-rw-r--r--scene/resources/mesh.cpp169
-rw-r--r--scene/resources/mesh.h14
-rw-r--r--scene/resources/mesh_library.h2
-rw-r--r--scene/resources/multimesh.cpp8
-rw-r--r--scene/resources/navigation_mesh.cpp12
-rw-r--r--scene/resources/navigation_mesh.h4
-rw-r--r--scene/resources/packed_scene.cpp49
-rw-r--r--scene/resources/particle_process_material.cpp (renamed from scene/resources/particles_material.cpp)665
-rw-r--r--scene/resources/particle_process_material.h (renamed from scene/resources/particles_material.h)87
-rw-r--r--scene/resources/polygon_path_finder.cpp2
-rw-r--r--scene/resources/primitive_meshes.cpp785
-rw-r--r--scene/resources/primitive_meshes.h98
-rw-r--r--scene/resources/resource_format_text.cpp6
-rw-r--r--scene/resources/shader.cpp12
-rw-r--r--scene/resources/shader.h14
-rw-r--r--scene/resources/shader_include.cpp2
-rw-r--r--scene/resources/shape_2d.cpp20
-rw-r--r--scene/resources/shape_2d.h4
-rw-r--r--scene/resources/skeleton_modification_2d_ccdik.cpp8
-rw-r--r--scene/resources/skeleton_modification_2d_lookat.cpp12
-rw-r--r--scene/resources/skeleton_modification_3d_ccdik.cpp8
-rw-r--r--scene/resources/skeleton_modification_3d_ccdik.h6
-rw-r--r--scene/resources/skeleton_modification_3d_fabrik.cpp4
-rw-r--r--scene/resources/skeleton_modification_3d_fabrik.h6
-rw-r--r--scene/resources/skeleton_modification_3d_jiggle.cpp4
-rw-r--r--scene/resources/skeleton_modification_3d_jiggle.h6
-rw-r--r--scene/resources/skeleton_modification_3d_lookat.cpp12
-rw-r--r--scene/resources/skeleton_modification_3d_lookat.h6
-rw-r--r--scene/resources/skeleton_modification_3d_stackholder.h6
-rw-r--r--scene/resources/skeleton_modification_3d_twoboneik.cpp8
-rw-r--r--scene/resources/skeleton_modification_3d_twoboneik.h6
-rw-r--r--scene/resources/skeleton_profile.cpp16
-rw-r--r--scene/resources/skeleton_profile.h2
-rw-r--r--scene/resources/sky_material.cpp2
-rw-r--r--scene/resources/sphere_shape_3d.cpp4
-rw-r--r--scene/resources/sprite_frames.cpp2
-rw-r--r--scene/resources/style_box.cpp6
-rw-r--r--scene/resources/style_box.h2
-rw-r--r--scene/resources/texture.cpp21
-rw-r--r--scene/resources/texture.h10
-rw-r--r--scene/resources/theme.cpp79
-rw-r--r--scene/resources/theme.h29
-rw-r--r--scene/resources/tile_set.cpp10
-rw-r--r--scene/resources/tile_set.h2
-rw-r--r--scene/resources/visual_shader.cpp112
-rw-r--r--scene/resources/visual_shader.h8
-rw-r--r--scene/resources/visual_shader_nodes.cpp474
-rw-r--r--scene/resources/visual_shader_nodes.h134
-rw-r--r--scene/theme/SCsub5
-rw-r--r--scene/theme/theme_db.cpp237
-rw-r--r--scene/theme/theme_db.h (renamed from modules/websocket/emws_server.h)87
-rw-r--r--servers/audio/audio_driver_dummy.cpp19
-rw-r--r--servers/audio/audio_driver_dummy.h6
-rw-r--r--servers/audio/audio_stream.cpp2
-rw-r--r--servers/audio/effects/audio_effect_amplify.cpp4
-rw-r--r--servers/audio/effects/audio_effect_chorus.cpp10
-rw-r--r--servers/audio/effects/audio_effect_chorus.h2
-rw-r--r--servers/audio/effects/audio_effect_compressor.cpp14
-rw-r--r--servers/audio/effects/audio_effect_compressor.h2
-rw-r--r--servers/audio/effects/audio_effect_delay.cpp57
-rw-r--r--servers/audio/effects/audio_effect_delay.h29
-rw-r--r--servers/audio/effects/audio_effect_distortion.cpp4
-rw-r--r--servers/audio/effects/audio_effect_eq.cpp2
-rw-r--r--servers/audio/effects/audio_effect_filter.h18
-rw-r--r--servers/audio/effects/audio_effect_limiter.cpp14
-rw-r--r--servers/audio_server.cpp18
-rw-r--r--servers/audio_server.h8
-rw-r--r--servers/camera_server.cpp5
-rw-r--r--servers/camera_server.h4
-rw-r--r--servers/display_server.cpp68
-rw-r--r--servers/display_server.h46
-rw-r--r--servers/extensions/physics_server_3d_extension.cpp3
-rw-r--r--servers/extensions/physics_server_3d_extension.h3
-rw-r--r--servers/movie_writer/movie_writer.cpp2
-rw-r--r--servers/navigation_server_2d.cpp53
-rw-r--r--servers/navigation_server_2d.h25
-rw-r--r--servers/navigation_server_3d.cpp10
-rw-r--r--servers/navigation_server_3d.h8
-rw-r--r--servers/physics_2d/godot_area_2d.cpp8
-rw-r--r--servers/physics_2d/godot_body_2d.cpp18
-rw-r--r--servers/physics_2d/godot_body_2d.h2
-rw-r--r--servers/physics_2d/godot_collision_object_2d.h8
-rw-r--r--servers/physics_2d/godot_physics_server_2d.cpp14
-rw-r--r--servers/physics_2d/godot_physics_server_2d.h3
-rw-r--r--servers/physics_2d/godot_space_2d.cpp20
-rw-r--r--servers/physics_2d/godot_step_2d.cpp2
-rw-r--r--servers/physics_3d/godot_area_3d.cpp8
-rw-r--r--servers/physics_3d/godot_body_3d.cpp20
-rw-r--r--servers/physics_3d/godot_body_3d.h2
-rw-r--r--servers/physics_3d/godot_collision_object_3d.h8
-rw-r--r--servers/physics_3d/godot_collision_solver_3d.cpp18
-rw-r--r--servers/physics_3d/godot_collision_solver_3d.h2
-rw-r--r--servers/physics_3d/godot_physics_server_3d.cpp14
-rw-r--r--servers/physics_3d/godot_physics_server_3d.h3
-rw-r--r--servers/physics_3d/godot_space_3d.cpp18
-rw-r--r--servers/physics_3d/godot_step_3d.cpp2
-rw-r--r--servers/physics_server_2d.cpp50
-rw-r--r--servers/physics_server_2d.h18
-rw-r--r--servers/physics_server_2d_wrap_mt.h3
-rw-r--r--servers/physics_server_3d.cpp52
-rw-r--r--servers/physics_server_3d.h19
-rw-r--r--servers/physics_server_3d_wrap_mt.h3
-rw-r--r--servers/rendering/dummy/storage/material_storage.h4
-rw-r--r--servers/rendering/dummy/storage/mesh_storage.h48
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp52
-rw-r--r--servers/rendering/renderer_canvas_cull.h1
-rw-r--r--servers/rendering/renderer_canvas_render.h3
-rw-r--r--servers/rendering/renderer_geometry_instance.cpp4
-rw-r--r--servers/rendering/renderer_geometry_instance.h6
-rw-r--r--servers/rendering/renderer_rd/cluster_builder_rd.h4
-rw-r--r--servers/rendering/renderer_rd/effects/ss_effects.cpp2
-rw-r--r--servers/rendering/renderer_rd/effects/vrs.cpp15
-rw-r--r--servers/rendering/renderer_rd/environment/fog.cpp40
-rw-r--r--servers/rendering/renderer_rd/environment/fog.h14
-rw-r--r--servers/rendering/renderer_rd/environment/gi.cpp127
-rw-r--r--servers/rendering/renderer_rd/environment/gi.h16
-rw-r--r--servers/rendering/renderer_rd/environment/sky.cpp76
-rw-r--r--servers/rendering/renderer_rd/environment/sky.h14
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp92
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp33
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h15
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp56
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp31
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h14
-rw-r--r--servers/rendering/renderer_rd/framebuffer_cache_rd.cpp (renamed from modules/mono/glue/rid_glue.cpp)48
-rw-r--r--servers/rendering/renderer_rd/framebuffer_cache_rd.h310
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp133
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h17
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.cpp4
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.h2
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp88
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h4
-rw-r--r--servers/rendering/renderer_rd/shader_rd.cpp4
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl8
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl1
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl13
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/sdfgi_debug.glsl24
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/light_data_inc.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/particles.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl54
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl19
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl50
-rw-r--r--servers/rendering/renderer_rd/shaders/skeleton.glsl64
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.cpp32
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.h141
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.cpp81
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.h288
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp55
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.h408
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.cpp55
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.h387
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.cpp56
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.h461
-rw-r--r--servers/rendering/renderer_rd/storage_rd/utilities.cpp43
-rw-r--r--servers/rendering/renderer_rd/uniform_set_cache_rd.h4
-rw-r--r--servers/rendering/renderer_scene.h8
-rw-r--r--servers/rendering/renderer_scene_cull.cpp68
-rw-r--r--servers/rendering/renderer_scene_cull.h16
-rw-r--r--servers/rendering/renderer_viewport.cpp58
-rw-r--r--servers/rendering/renderer_viewport.h15
-rw-r--r--servers/rendering/rendering_device.cpp2
-rw-r--r--servers/rendering/rendering_device.h12
-rw-r--r--servers/rendering/rendering_device_binds.h6
-rw-r--r--servers/rendering/rendering_server_default.h11
-rw-r--r--servers/rendering/shader_compiler.cpp46
-rw-r--r--servers/rendering/shader_compiler.h1
-rw-r--r--servers/rendering/shader_language.cpp110
-rw-r--r--servers/rendering/shader_language.h8
-rw-r--r--servers/rendering/shader_preprocessor.cpp377
-rw-r--r--servers/rendering/shader_preprocessor.h52
-rw-r--r--servers/rendering/shader_types.cpp10
-rw-r--r--servers/rendering/storage/environment_storage.h8
-rw-r--r--servers/rendering/storage/material_storage.h4
-rw-r--r--servers/rendering_server.cpp123
-rw-r--r--servers/rendering_server.h39
-rw-r--r--servers/text/text_server_extension.cpp68
-rw-r--r--servers/text/text_server_extension.h33
-rw-r--r--servers/text_server.cpp63
-rw-r--r--servers/text_server.h47
-rw-r--r--servers/xr_server.cpp2
-rw-r--r--servers/xr_server.h2
-rw-r--r--tests/core/input/test_input_event_key.h294
-rw-r--r--tests/core/input/test_shortcut.h235
-rw-r--r--tests/core/io/test_config_file.h2
-rw-r--r--tests/core/io/test_file_access.h23
-rw-r--r--tests/core/io/test_image.h4
-rw-r--r--tests/core/io/test_marshalls.h2
-rw-r--r--tests/core/io/test_pck_packer.h16
-rw-r--r--tests/core/io/test_resource.h4
-rw-r--r--tests/core/math/test_aabb.h20
-rw-r--r--tests/core/math/test_quaternion.h389
-rw-r--r--tests/core/math/test_transform_2d.h (renamed from modules/mono/glue/callable_glue.cpp)77
-rw-r--r--tests/core/math/test_transform_3d.h (renamed from modules/mono/mono_gd/gd_mono_wasm_m2n.cpp)76
-rw-r--r--tests/core/math/test_vector4.h315
-rw-r--r--tests/core/math/test_vector4i.h148
-rw-r--r--tests/core/object/test_class_db.h86
-rw-r--r--tests/core/object/test_method_bind.h1
-rw-r--r--tests/core/object/test_object.h6
-rw-r--r--tests/core/string/test_string.h138
-rw-r--r--tests/core/templates/test_hash_set.h2
-rw-r--r--tests/core/templates/test_rid.h (renamed from modules/websocket/emws_server.cpp)89
-rw-r--r--tests/core/templates/test_vector.h4
-rw-r--r--tests/core/variant/test_variant.h62
-rw-r--r--tests/create_test.py132
-rw-r--r--tests/data/line_endings_cr.test.txt1
-rw-r--r--tests/data/line_endings_crlf.test.txt4
-rw-r--r--tests/data/line_endings_lf.test.txt4
-rw-r--r--tests/python_build/conftest.py26
-rw-r--r--tests/python_build/fixtures/gles3/_included.glsl1
-rw-r--r--tests/python_build/fixtures/gles3/vertex_fragment.glsl34
-rw-r--r--tests/python_build/fixtures/gles3/vertex_fragment_expected_full.glsl50
-rw-r--r--tests/python_build/fixtures/gles3/vertex_fragment_expected_parts.json52
-rw-r--r--tests/python_build/fixtures/glsl/_included.glsl1
-rw-r--r--tests/python_build/fixtures/glsl/compute.glsl12
-rw-r--r--tests/python_build/fixtures/glsl/compute_expected_full.glsl8
-rw-r--r--tests/python_build/fixtures/glsl/compute_expected_parts.json3
-rw-r--r--tests/python_build/fixtures/glsl/vertex_fragment.glsl32
-rw-r--r--tests/python_build/fixtures/glsl/vertex_fragment_expected_full.glsl8
-rw-r--r--tests/python_build/fixtures/glsl/vertex_fragment_expected_parts.json3
-rw-r--r--tests/python_build/fixtures/rd_glsl/_included.glsl1
-rw-r--r--tests/python_build/fixtures/rd_glsl/compute.glsl13
-rw-r--r--tests/python_build/fixtures/rd_glsl/compute_expected_full.glsl20
-rw-r--r--tests/python_build/fixtures/rd_glsl/compute_expected_parts.json28
-rw-r--r--tests/python_build/fixtures/rd_glsl/vertex_fragment.glsl25
-rw-r--r--tests/python_build/fixtures/rd_glsl/vertex_fragment_expected_full.glsl23
-rw-r--r--tests/python_build/fixtures/rd_glsl/vertex_fragment_expected_parts.json40
-rw-r--r--tests/python_build/test_gles3_builder.py31
-rw-r--r--tests/python_build/test_glsl_builder.py37
-rw-r--r--tests/scene/test_audio_stream_wav.h243
-rw-r--r--tests/scene/test_code_edit.h6
-rw-r--r--tests/scene/test_path_follow_2d.h94
-rw-r--r--tests/scene/test_path_follow_3d.h94
-rw-r--r--tests/scene/test_sprite_frames.h247
-rw-r--r--tests/scene/test_theme.h18
-rw-r--r--tests/servers/test_text_server.h219
-rw-r--r--tests/test_macros.h13
-rw-r--r--tests/test_main.cpp37
-rw-r--r--tests/test_utils.cpp2
-rw-r--r--tests/test_validate_testing.h5
-rw-r--r--thirdparty/README.md19
-rw-r--r--thirdparty/certs/ca-certificates.crt231
-rw-r--r--thirdparty/glslang/glslang/OSDependent/Unix/ossource.cpp37
-rw-r--r--thirdparty/glslang/glslang/OSDependent/osinclude.h2
-rw-r--r--thirdparty/glslang/patches/unused_cleanup.diff61
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh14
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh23
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh13
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh16
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/PairValueRecord.hh2
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh22
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh14
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh15
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh50
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh16
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh61
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh27
-rw-r--r--thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh15
-rw-r--r--thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh12
-rw-r--r--thirdparty/harfbuzz/src/graph/coverage-graph.hh80
-rw-r--r--thirdparty/harfbuzz/src/graph/graph.hh140
-rw-r--r--thirdparty/harfbuzz/src/graph/gsubgpos-context.cc71
-rw-r--r--thirdparty/harfbuzz/src/graph/gsubgpos-context.hh67
-rw-r--r--thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh351
-rw-r--r--thirdparty/harfbuzz/src/graph/pairpos-graph.hh299
-rw-r--r--thirdparty/harfbuzz/src/hb-blob.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-blob.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer.cc43
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer.h25
-rw-r--r--thirdparty/harfbuzz/src/hb-buffer.hh18
-rw-r--r--thirdparty/harfbuzz/src/hb-cplusplus.hh23
-rw-r--r--thirdparty/harfbuzz/src/hb-debug.hh5
-rw-r--r--thirdparty/harfbuzz/src/hb-face.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-face.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-font.cc6
-rw-r--r--thirdparty/harfbuzz/src/hb-font.h6
-rw-r--r--thirdparty/harfbuzz/src/hb-ft.cc3
-rw-r--r--thirdparty/harfbuzz/src/hb-map.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-map.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-number-parser.hh8
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-common.hh6
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh24
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shape.cc29
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-arabic.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh498
-rw-r--r--thirdparty/harfbuzz/src/hb-repacker.hh161
-rw-r--r--thirdparty/harfbuzz/src/hb-set.cc2
-rw-r--r--thirdparty/harfbuzz/src/hb-set.h2
-rw-r--r--thirdparty/harfbuzz/src/hb-shape-plan.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-shape-plan.h4
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-repacker.cc13
-rw-r--r--thirdparty/harfbuzz/src/hb-subset-repacker.h3
-rw-r--r--thirdparty/harfbuzz/src/hb-ucd-table.hh5283
-rw-r--r--thirdparty/harfbuzz/src/hb-unicode-emoji-table.hh59
-rw-r--r--thirdparty/harfbuzz/src/hb-unicode.cc4
-rw-r--r--thirdparty/harfbuzz/src/hb-unicode.h4
-rw-r--r--thirdparty/harfbuzz/src/hb-version.h6
-rw-r--r--thirdparty/icu4c/godot_data.json3
-rw-r--r--thirdparty/icu4c/i18n/scriptset.cpp313
-rw-r--r--thirdparty/icu4c/i18n/scriptset.h86
-rw-r--r--thirdparty/icu4c/i18n/ucln_in.cpp65
-rw-r--r--thirdparty/icu4c/i18n/ucln_in.h74
-rw-r--r--thirdparty/icu4c/i18n/unicode/uspoof.h1577
-rw-r--r--thirdparty/icu4c/i18n/uspoof.cpp839
-rw-r--r--thirdparty/icu4c/i18n/uspoof_impl.cpp959
-rw-r--r--thirdparty/icu4c/i18n/uspoof_impl.h343
-rw-r--r--thirdparty/icu4c/icudt71l.datbin4226000 -> 4271680 bytes
-rw-r--r--thirdparty/libwebp/AUTHORS4
-rw-r--r--thirdparty/libwebp/sharpyuv/sharpyuv.c498
-rw-r--r--thirdparty/libwebp/sharpyuv/sharpyuv.h81
-rw-r--r--thirdparty/libwebp/sharpyuv/sharpyuv_csp.c110
-rw-r--r--thirdparty/libwebp/sharpyuv/sharpyuv_csp.h59
-rw-r--r--thirdparty/libwebp/sharpyuv/sharpyuv_dsp.c102
-rw-r--r--thirdparty/libwebp/sharpyuv/sharpyuv_dsp.h29
-rw-r--r--thirdparty/libwebp/sharpyuv/sharpyuv_gamma.c114
-rw-r--r--thirdparty/libwebp/sharpyuv/sharpyuv_gamma.h35
-rw-r--r--thirdparty/libwebp/sharpyuv/sharpyuv_neon.c182
-rw-r--r--thirdparty/libwebp/sharpyuv/sharpyuv_sse2.c204
-rw-r--r--thirdparty/libwebp/src/dec/vp8i_dec.h2
-rw-r--r--thirdparty/libwebp/src/dec/vp8l_dec.c6
-rw-r--r--thirdparty/libwebp/src/demux/demux.c5
-rw-r--r--thirdparty/libwebp/src/dsp/alpha_processing_neon.c6
-rw-r--r--thirdparty/libwebp/src/dsp/cpu.c2
-rw-r--r--thirdparty/libwebp/src/dsp/cpu.h254
-rw-r--r--thirdparty/libwebp/src/dsp/dsp.h229
-rw-r--r--thirdparty/libwebp/src/dsp/lossless.h8
-rw-r--r--thirdparty/libwebp/src/dsp/lossless_enc.c12
-rw-r--r--thirdparty/libwebp/src/dsp/lossless_enc_mips32.c22
-rw-r--r--thirdparty/libwebp/src/dsp/lossless_enc_sse2.c4
-rw-r--r--thirdparty/libwebp/src/dsp/yuv.c64
-rw-r--r--thirdparty/libwebp/src/dsp/yuv_neon.c108
-rw-r--r--thirdparty/libwebp/src/dsp/yuv_sse2.c119
-rw-r--r--thirdparty/libwebp/src/enc/alpha_enc.c2
-rw-r--r--thirdparty/libwebp/src/enc/backward_references_cost_enc.c75
-rw-r--r--thirdparty/libwebp/src/enc/backward_references_enc.c86
-rw-r--r--thirdparty/libwebp/src/enc/backward_references_enc.h12
-rw-r--r--thirdparty/libwebp/src/enc/histogram_enc.c208
-rw-r--r--thirdparty/libwebp/src/enc/histogram_enc.h24
-rw-r--r--thirdparty/libwebp/src/enc/picture_csp_enc.c492
-rw-r--r--thirdparty/libwebp/src/enc/picture_enc.c44
-rw-r--r--thirdparty/libwebp/src/enc/picture_rescale_enc.c72
-rw-r--r--thirdparty/libwebp/src/enc/picture_tools_enc.c45
-rw-r--r--thirdparty/libwebp/src/enc/predictor_enc.c50
-rw-r--r--thirdparty/libwebp/src/enc/quant_enc.c62
-rw-r--r--thirdparty/libwebp/src/enc/vp8i_enc.h24
-rw-r--r--thirdparty/libwebp/src/enc/vp8l_enc.c527
-rw-r--r--thirdparty/libwebp/src/enc/vp8li_enc.h26
-rw-r--r--thirdparty/libwebp/src/enc/webp_enc.c4
-rw-r--r--thirdparty/libwebp/src/mux/muxedit.c1
-rw-r--r--thirdparty/libwebp/src/mux/muxi.h2
-rw-r--r--thirdparty/libwebp/src/mux/muxinternal.c9
-rw-r--r--thirdparty/libwebp/src/webp/encode.h6
-rw-r--r--thirdparty/mbedtls/library/timing.c4
-rw-r--r--thirdparty/minimp3/minimp3.h23
-rw-r--r--thirdparty/spirv-reflect/include/spirv/unified1/spirv.h46
-rw-r--r--thirdparty/spirv-reflect/patches/specialization-constants.patch34
-rw-r--r--thirdparty/spirv-reflect/patches/zero-calloc.patch28
-rw-r--r--thirdparty/spirv-reflect/spirv_reflect.c83
-rw-r--r--thirdparty/spirv-reflect/spirv_reflect.h11
2180 files changed, 89557 insertions, 87402 deletions
diff --git a/.clang-format b/.clang-format
index f7527b8927..1df6c35bfb 100644
--- a/.clang-format
+++ b/.clang-format
@@ -19,7 +19,7 @@ AllowAllParametersOfDeclarationOnNextLine: false
# AllowShortEnumsOnASingleLine: true
# AllowShortBlocksOnASingleLine: Never
# AllowShortCaseLabelsOnASingleLine: false
-AllowShortFunctionsOnASingleLine: Inline
+# AllowShortFunctionsOnASingleLine: All
# AllowShortLambdasOnASingleLine: All
# AllowShortIfStatementsOnASingleLine: Never
# AllowShortLoopsOnASingleLine: false
diff --git a/.gitattributes b/.gitattributes
index 45ea6c25e8..8d2fb108ba 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -7,6 +7,8 @@ thirdparty/* linguist-vendored
* text=auto eol=lf
# Except for bat files, which are Windows only files
*.bat eol=crlf
+# And some test files where the EOL matters
+*.test.txt -text
# The above only works properly for Git 2.10+, so for older versions
# we need to manually list the binary files we don't want modified.
diff --git a/.github/actions/godot-deps/action.yml b/.github/actions/godot-deps/action.yml
index ee4d7d3751..e99167ff2b 100644
--- a/.github/actions/godot-deps/action.yml
+++ b/.github/actions/godot-deps/action.yml
@@ -12,7 +12,7 @@ runs:
steps:
# Use python 3.x release (works cross platform)
- name: Set up Python 3.x
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
# Semantic version range syntax or exact version of a Python version
python-version: ${{ inputs.python-version }}
diff --git a/.github/actions/upload-artifact/action.yml b/.github/actions/upload-artifact/action.yml
index bc1871b914..ae0e634cbf 100644
--- a/.github/actions/upload-artifact/action.yml
+++ b/.github/actions/upload-artifact/action.yml
@@ -12,7 +12,7 @@ runs:
using: "composite"
steps:
- name: Upload Godot Artifact
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
name: ${{ inputs.name }}
path: ${{ inputs.path }}
diff --git a/.github/workflows/android_builds.yml b/.github/workflows/android_builds.yml
index a9a580247b..4f54f6629e 100644
--- a/.github/workflows/android_builds.yml
+++ b/.github/workflows/android_builds.yml
@@ -17,7 +17,7 @@ jobs:
name: Template (target=release, tools=no)
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
# Azure repositories are not reliable, we need to prevent azure giving us packages.
- name: Make apt sources.list use the default Ubuntu repositories
@@ -27,8 +27,9 @@ jobs:
sudo apt-get update
- name: Set up Java 11
- uses: actions/setup-java@v1
+ uses: actions/setup-java@v3
with:
+ distribution: temurin
java-version: 11
- name: Setup Godot build cache
@@ -38,19 +39,19 @@ jobs:
- name: Setup python and scons
uses: ./.github/actions/godot-deps
- - name: Compilation (armv7)
+ - name: Compilation (arm32)
uses: ./.github/actions/godot-build
with:
- sconsflags: ${{ env.SCONSFLAGS }} android_arch=armv7
+ sconsflags: ${{ env.SCONSFLAGS }} arch=arm32
platform: android
target: release
tools: false
tests: false
- - name: Compilation (arm64v8)
+ - name: Compilation (arm64)
uses: ./.github/actions/godot-build
with:
- sconsflags: ${{ env.SCONSFLAGS }} android_arch=arm64v8
+ sconsflags: ${{ env.SCONSFLAGS }} arch=arm64
platform: android
target: release
tools: false
diff --git a/.github/workflows/ios_builds.yml b/.github/workflows/ios_builds.yml
index 03277edc1d..bc00fad569 100644
--- a/.github/workflows/ios_builds.yml
+++ b/.github/workflows/ios_builds.yml
@@ -17,7 +17,7 @@ jobs:
name: Template (target=release, tools=no)
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Setup Godot build cache
uses: ./.github/actions/godot-cache
@@ -26,7 +26,7 @@ jobs:
- name: Setup python and scons
uses: ./.github/actions/godot-deps
- - name: Compilation (arm64v8)
+ - name: Compilation (arm64)
uses: ./.github/actions/godot-build
with:
sconsflags: ${{ env.SCONSFLAGS }}
diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml
index 8c716242e4..2e8bd101e5 100644
--- a/.github/workflows/linux_builds.yml
+++ b/.github/workflows/linux_builds.yml
@@ -4,8 +4,10 @@ on: [push, pull_request]
# Global Settings
env:
# Only used for the cache key. Increment version to force clean build.
- GODOT_BASE_BRANCH: master-v2
+ GODOT_BASE_BRANCH: master
SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes
+ DOTNET_NOLOGO: true
+ DOTNET_CLI_TELEMETRY_OPTOUT: false
concurrency:
group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-linux
@@ -24,9 +26,9 @@ jobs:
target: release_debug
tools: true
tests: false # Disabled due freeze caused by mix Mono build and CI
- sconsflags: module_mono_enabled=yes mono_static=yes mono_glue=no
+ sconsflags: module_mono_enabled=yes
doc-test: true
- bin: "./bin/godot.linuxbsd.opt.tools.64.mono"
+ bin: "./bin/godot.linuxbsd.opt.tools.x86_64.mono"
build-mono: true
proj-conv: true
artifact: true
@@ -41,7 +43,7 @@ jobs:
# Can be turned off for PRs that intentionally break compat with godot-cpp,
# until both the upstream PR and the matching godot-cpp changes are merged.
godot-cpp-test: true
- bin: "./bin/godot.linuxbsd.double.tools.64.san"
+ bin: "./bin/godot.linuxbsd.double.tools.x86_64.san"
build-mono: false
# Skip 2GiB artifact speeding up action.
artifact: false
@@ -52,7 +54,7 @@ jobs:
tools: true
tests: true
sconsflags: use_asan=yes use_ubsan=yes use_llvm=yes linker=lld
- bin: "./bin/godot.linuxbsd.tools.64.llvm.san"
+ bin: "./bin/godot.linuxbsd.tools.x86_64.llvm.san"
build-mono: false
# Skip 2GiB artifact speeding up action.
artifact: false
@@ -62,7 +64,7 @@ jobs:
target: release
tools: false
tests: false
- sconsflags: module_mono_enabled=yes mono_static=yes mono_glue=no debug_symbols=no
+ sconsflags: module_mono_enabled=yes debug_symbols=no
build-mono: false
artifact: true
@@ -75,7 +77,7 @@ jobs:
artifact: true
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Linux dependencies
shell: bash
@@ -99,6 +101,12 @@ jobs:
- name: Setup python and scons
uses: ./.github/actions/godot-deps
+ - name: Set up .NET Sdk
+ uses: actions/setup-dotnet@v2
+ if: ${{ matrix.build-mono }}
+ with:
+ dotnet-version: '6.0.x'
+
- name: Compilation
uses: ./.github/actions/godot-build
with:
@@ -108,20 +116,15 @@ jobs:
tools: ${{ matrix.tools }}
tests: ${{ matrix.tests }}
- - name: Generate Mono glue
+ - name: Generate C# glue
if: ${{ matrix.build-mono }}
run: |
- ${{ matrix.bin }} --headless --generate-mono-glue modules/mono/glue || true
+ ${{ matrix.bin }} --headless --generate-mono-glue ./modules/mono/glue || true
- # Rebuild with mono
- - name: Compilation (mono_glue=yes)
- uses: ./.github/actions/godot-build
+ - name: Build .NET solutions
if: ${{ matrix.build-mono }}
- with:
- sconsflags: ${{ env.SCONSFLAGS }} ${{ matrix.sconsflags }} mono_glue=yes
- platform: linuxbsd
- target: ${{ matrix.target }}
- tools: ${{ matrix.tools }}
+ run: |
+ ./modules/mono/build_scripts/build_assemblies.py --godot-output-dir=./bin --godot-platform=linuxbsd
# Execute unit tests for the editor
- name: Unit tests
@@ -170,12 +173,18 @@ jobs:
mv "regression-test-project-4.0" "test_project"
# Editor is quite complicated piece of software, so it is easy to introduce bug here
- - name: Open and close editor
+ - name: Open and close editor (Vulkan)
if: ${{ matrix.proj-test }}
run: |
VK_ICD_FILENAMES=$(pwd)/vk_swiftshader_icd.json DRI_PRIME=0 xvfb-run ${{ matrix.bin }} --audio-driver Dummy --editor --quit --path test_project 2>&1 | tee sanitizers_log.txt || true
misc/scripts/check_ci_log.py sanitizers_log.txt
+ - name: Open and close editor (GLES3)
+ if: ${{ matrix.proj-test }}
+ run: |
+ DRI_PRIME=0 xvfb-run ${{ matrix.bin }} --audio-driver Dummy --rendering-driver opengl3 --editor --quit --path test_project 2>&1 | tee sanitizers_log.txt || true
+ misc/scripts/check_ci_log.py sanitizers_log.txt
+
# Run test project
- name: Run project
if: ${{ matrix.proj-test }}
@@ -186,7 +195,7 @@ jobs:
# Checkout godot-cpp
- name: Checkout godot-cpp
if: ${{ matrix.godot-cpp-test }}
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
with:
repository: godotengine/godot-cpp
submodules: 'recursive'
diff --git a/.github/workflows/macos_builds.yml b/.github/workflows/macos_builds.yml
index 0ad0995bb7..be1fb8de85 100644
--- a/.github/workflows/macos_builds.yml
+++ b/.github/workflows/macos_builds.yml
@@ -4,7 +4,7 @@ on: [push, pull_request]
# Global Settings
env:
# Only used for the cache key. Increment version to force clean build.
- GODOT_BASE_BRANCH: master-v3
+ GODOT_BASE_BRANCH: master
SCONSFLAGS: verbose=yes warnings=extra werror=yes module_text_server_fb_enabled=yes
concurrency:
@@ -24,7 +24,7 @@ jobs:
target: release_debug
tools: true
tests: true
- bin: "./bin/godot.macos.opt.tools.64"
+ bin: "./bin/godot.macos.opt.tools.x86_64"
- name: Template (target=release, tools=no)
cache-name: macos-template
@@ -34,7 +34,7 @@ jobs:
sconsflags: debug_symbols=no
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Setup Godot build cache
uses: ./.github/actions/godot-cache
diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml
index 81c7042663..3e84702d7f 100644
--- a/.github/workflows/static_checks.yml
+++ b/.github/workflows/static_checks.yml
@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-20.04
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
# Azure repositories are not reliable, we need to prevent Azure giving us packages.
- name: Make apt sources.list use the default Ubuntu repositories
@@ -27,16 +27,12 @@ jobs:
sudo apt-get install -qq dos2unix recode clang-format-13 libxml2-utils
sudo update-alternatives --remove-all clang-format
sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-13 100
- sudo pip3 install black==22.3.0 pygments
+ sudo pip3 install black==22.3.0 pygments pytest
- name: File formatting checks (file_format.sh)
run: |
bash ./misc/scripts/file_format.sh
- - name: Style checks via clang-format (clang_format.sh)
- run: |
- bash ./misc/scripts/clang_format.sh
-
- name: Header guards formatting checks (header_guards.sh)
run: |
bash ./misc/scripts/header_guards.sh
@@ -45,9 +41,13 @@ jobs:
run: |
bash ./misc/scripts/black_format.sh
+ - name: Python builders checks via pytest (pytest_builders.sh)
+ run: |
+ bash ./misc/scripts/pytest_builders.sh
+
- name: JavaScript style and documentation checks via ESLint and JSDoc
run: |
- cd platform/javascript
+ cd platform/web
npm ci
npm run lint
npm run docs -- -d dry-run
@@ -59,3 +59,11 @@ jobs:
- name: Documentation checks
run: |
doc/tools/make_rst.py --dry-run --color doc/classes modules
+
+ - name: Style checks via clang-format (clang_format.sh)
+ run: |
+ bash ./misc/scripts/clang_format.sh
+
+ - name: Style checks via dotnet format (dotnet_format.sh)
+ run: |
+ bash ./misc/scripts/dotnet_format.sh
diff --git a/.github/workflows/javascript_builds.yml b/.github/workflows/web_builds.yml
index 00c79e8ba0..8c5b14e314 100644
--- a/.github/workflows/javascript_builds.yml
+++ b/.github/workflows/web_builds.yml
@@ -1,4 +1,4 @@
-name: 🌠JavaScript Builds
+name: 🌠Web Builds
on: [push, pull_request]
# Global Settings
@@ -10,27 +10,19 @@ env:
EM_CACHE_FOLDER: "emsdk-cache"
concurrency:
- group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-javascript
+ group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-web
cancel-in-progress: true
jobs:
- javascript-template:
+ web-template:
runs-on: "ubuntu-20.04"
name: Template (target=release, tools=no)
steps:
- - uses: actions/checkout@v2
-
- # Additional cache for Emscripten generated system libraries
- - name: Load Emscripten cache
- id: javascript-template-emscripten-cache
- uses: actions/cache@v2
- with:
- path: ${{env.EM_CACHE_FOLDER}}
- key: ${{env.EM_VERSION}}-${{github.job}}
+ - uses: actions/checkout@v3
- name: Set up Emscripten latest
- uses: mymindstorm/setup-emsdk@v10
+ uses: mymindstorm/setup-emsdk@v11
with:
version: ${{env.EM_VERSION}}
actions-cache-folder: ${{env.EM_CACHE_FOLDER}}
@@ -50,7 +42,7 @@ jobs:
uses: ./.github/actions/godot-build
with:
sconsflags: ${{ env.SCONSFLAGS }}
- platform: javascript
+ platform: web
target: release
tools: false
tests: false
diff --git a/.github/workflows/windows_builds.yml b/.github/workflows/windows_builds.yml
index e04d49adde..9033e1ab1d 100644
--- a/.github/workflows/windows_builds.yml
+++ b/.github/workflows/windows_builds.yml
@@ -5,7 +5,7 @@ on: [push, pull_request]
# SCONS_CACHE for windows must be set in the build environment
env:
# Only used for the cache key. Increment version to force clean build.
- GODOT_BASE_BRANCH: master-v2
+ GODOT_BASE_BRANCH: master
SCONSFLAGS: verbose=yes warnings=all werror=yes module_text_server_fb_enabled=yes
SCONS_CACHE_MSVC_CONFIG: true
@@ -29,7 +29,7 @@ jobs:
tests: true
# Skip debug symbols, they're way too big with MSVC.
sconsflags: debug_symbols=no
- bin: "./bin/godot.windows.opt.tools.64.exe"
+ bin: "./bin/godot.windows.opt.tools.x86_64.exe"
- name: Template (target=release, tools=no)
cache-name: windows-template
@@ -39,7 +39,7 @@ jobs:
sconsflags: debug_symbols=no
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Setup Godot build cache
uses: ./.github/actions/godot-cache
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 49355d2782..a1e8d3a59d 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -37,7 +37,7 @@ Godot runs on a large variety of platforms and operating systems and devices.
For bugs that are likely OS-specific and/or graphics-related, please also specify:
-- Device (CPU model including architecture, e.g. x86, x86_64, ARM, etc.)
+- Device (CPU model including architecture, e.g. x86_64, arm64, etc.)
- GPU model (and the driver version in use if you know it)
**Bug reports not including the required information may be closed at the
@@ -74,10 +74,10 @@ if your ZIP file isn't accepted by GitHub because it's too large.
We recommend always attaching a minimal reproduction project, even if the issue
may seem simple to reproduce manually.
-**Note for C# users:** If your issue is not Mono-specific, please upload a
-minimal reproduction project written in GDScript or VisualScript.
+**Note for C# users:** If your issue is not .NET-specific, please upload a
+minimal reproduction project written in GDScript.
This will make it easier for contributors to reproduce the issue
-locally as not everyone has a Mono setup available.
+locally as not everyone has a .NET setup available.
**If you've been asked by a maintainer to upload a minimal reproduction project,
you *must* do so within 7 days.** Otherwise, your bug report will be closed as
diff --git a/README.md b/README.md
index a7e67f8946..82dbdcfed1 100644
--- a/README.md
+++ b/README.md
@@ -14,8 +14,7 @@ comprehensive set of [common tools](https://godotengine.org/features), so that u
without having to reinvent the wheel. Games can be exported with one click to a
number of platforms, including the major desktop platforms (Linux, macOS,
Windows), mobile platforms (Android, iOS), as well as Web-based platforms
-(HTML5) and
-[consoles](https://docs.godotengine.org/en/latest/tutorials/platform/consoles.html).
+and [consoles](https://docs.godotengine.org/en/latest/tutorials/platform/consoles.html).
## Free, open source and community-driven
diff --git a/SConstruct b/SConstruct
index 0fd9326e1c..4972b21421 100644
--- a/SConstruct
+++ b/SConstruct
@@ -55,6 +55,7 @@ _helper_module("modules.modules_builders", "modules/modules_builders.py")
import methods
import glsl_builders
import gles3_builders
+from platform_methods import architectures, architecture_aliases
if methods.get_cmdline_bool("tools", True):
_helper_module("editor.editor_builders", "editor/editor_builders.py")
@@ -105,7 +106,7 @@ platform_arg = ARGUMENTS.get("platform", ARGUMENTS.get("p", False))
if platform_arg == "android":
custom_tools = ["clang", "clang++", "as", "ar", "link"]
-elif platform_arg == "javascript":
+elif platform_arg == "web":
# Use generic POSIX build toolchain for Emscripten.
custom_tools = ["cc", "c++", "ar", "link", "textfile", "zip"]
elif os.name == "nt" and methods.get_cmdline_bool("use_mingw", False):
@@ -138,6 +139,7 @@ env_base.__class__.CommandNoCache = methods.CommandNoCache
env_base.__class__.Run = methods.Run
env_base.__class__.disable_warnings = methods.disable_warnings
env_base.__class__.force_optimization_on_debug = methods.force_optimization_on_debug
+env_base.__class__.module_add_dependencies = methods.module_add_dependencies
env_base.__class__.module_check_dependencies = methods.module_check_dependencies
env_base["x86_libtheora_opt_gcc"] = False
@@ -160,12 +162,11 @@ if profile:
opts = Variables(customs, ARGUMENTS)
# Target build options
-opts.Add("p", "Platform (alias for 'platform')", "")
opts.Add("platform", "Target platform (%s)" % ("|".join(platform_list),), "")
+opts.Add("p", "Platform (alias for 'platform')", "")
opts.Add(BoolVariable("tools", "Build the tools (a.k.a. the Godot editor)", True))
opts.Add(EnumVariable("target", "Compilation target", "debug", ("debug", "release_debug", "release")))
-opts.Add("arch", "Platform-dependent architecture (arm/arm64/x86/x64/mips/...)", "")
-opts.Add(EnumVariable("bits", "Target platform bits", "default", ("default", "32", "64")))
+opts.Add(EnumVariable("arch", "CPU architecture", "auto", ["auto"] + architectures, architecture_aliases))
opts.Add(EnumVariable("float", "Floating-point precision", "default", ("default", "32", "64")))
opts.Add(EnumVariable("optimize", "Optimization type", "speed", ("speed", "size", "none")))
opts.Add(BoolVariable("production", "Set defaults to build Godot for use in production", False))
@@ -337,21 +338,27 @@ for path in module_search_paths:
# Add module options.
for name, path in modules_detected.items():
+ sys.path.insert(0, path)
+ import config
+
if env_base["modules_enabled_by_default"]:
enabled = True
-
- sys.path.insert(0, path)
- import config
-
try:
enabled = config.is_enabled()
except AttributeError:
pass
- sys.path.remove(path)
- sys.modules.pop("config")
else:
enabled = False
+ # Add module-specific options.
+ try:
+ for opt in config.get_opts(selected_platform):
+ opts.Add(opt)
+ except AttributeError:
+ pass
+
+ sys.path.remove(path)
+ sys.modules.pop("config")
opts.Add(BoolVariable("module_" + name + "_enabled", "Enable module '%s'" % (name,), enabled))
methods.write_modules(modules_detected)
@@ -495,12 +502,17 @@ if selected_platform in platform_list:
# Platform specific flags
flag_list = platform_flags[selected_platform]
for f in flag_list:
- if not (f[0] in ARGUMENTS): # allow command line to override platform flags
+ if not (f[0] in ARGUMENTS) or ARGUMENTS[f[0]] == "auto": # Allow command line to override platform flags
env[f[0]] = f[1]
# Must happen after the flags' definition, so that they can be used by platform detect
detect.configure(env)
+ print(
+ 'Building for platform "%s", architecture "%s", %s, target "%s".'
+ % (selected_platform, env["arch"], "editor" if env["tools"] else "template", env["target"])
+ )
+
# Set our C and C++ standard requirements.
# C++17 is required as we need guaranteed copy elision as per GH-36436.
# Prepending to make it possible to override.
@@ -686,19 +698,14 @@ if selected_platform in platform_list:
)
suffix += ".debug"
- if env["arch"] != "":
- suffix += "." + env["arch"]
- elif env["bits"] == "32":
- suffix += ".32"
- elif env["bits"] == "64":
- suffix += ".64"
-
+ suffix += "." + env["arch"]
suffix += env.extra_suffix
sys.path.remove(tmppath)
sys.modules.pop("detect")
modules_enabled = OrderedDict()
+ env.module_dependencies = {}
env.module_icons_paths = []
env.doc_class_path = {}
@@ -710,6 +717,10 @@ if selected_platform in platform_list:
import config
if config.can_build(env, selected_platform):
+ # Disable it if a required dependency is missing.
+ if not env.module_check_dependencies(name):
+ continue
+
config.configure(env)
# Get doc classes paths (if present)
try:
@@ -732,6 +743,7 @@ if selected_platform in platform_list:
sys.modules.pop("config")
env.module_list = modules_enabled
+ methods.sort_module_list(env)
methods.update_version(env.module_version_string)
@@ -794,15 +806,6 @@ if selected_platform in platform_list:
if env["minizip"]:
env.Append(CPPDEFINES=["MINIZIP_ENABLED"])
- editor_module_list = []
- if env["tools"] and not env.module_check_dependencies("tools", editor_module_list):
- print(
- "Build option 'module_"
- + x
- + "_enabled=no' cannot be used with 'tools=yes' (editor), only with 'tools=no' (export template)."
- )
- Exit(255)
-
if not env["verbose"]:
methods.no_verbose(sys, env)
diff --git a/core/config/engine.cpp b/core/config/engine.cpp
index 44ad4961d9..94db3612b4 100644
--- a/core/config/engine.cpp
+++ b/core/config/engine.cpp
@@ -33,7 +33,10 @@
#include "core/authors.gen.h"
#include "core/config/project_settings.h"
#include "core/donors.gen.h"
+#include "core/io/json.h"
#include "core/license.gen.h"
+#include "core/os/os.h"
+#include "core/variant/typed_array.h"
#include "core/version.h"
void Engine::set_physics_ticks_per_second(int p_ips) {
@@ -134,8 +137,8 @@ Dictionary Engine::get_author_info() const {
return dict;
}
-Array Engine::get_copyright_info() const {
- Array components;
+TypedArray<Dictionary> Engine::get_copyright_info() const {
+ TypedArray<Dictionary> components;
for (int component_index = 0; component_index < COPYRIGHT_INFO_COUNT; component_index++) {
const ComponentCopyright &cp_info = COPYRIGHT_INFO[component_index];
Dictionary component_dict;
@@ -181,6 +184,42 @@ String Engine::get_license_text() const {
return String(GODOT_LICENSE_TEXT);
}
+String Engine::get_architecture_name() const {
+#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(_M_X64)
+ return "x86_64";
+
+#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
+ return "x86_32";
+
+#elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
+ return "arm64";
+
+#elif defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7S__) || defined(_M_ARM)
+ return "arm32";
+
+#elif defined(__riscv)
+#if __riscv_xlen == 8
+ return "rv64";
+#else
+ return "riscv";
+#endif
+
+#elif defined(__powerpc__)
+#if defined(__powerpc64__)
+ return "ppc64";
+#else
+ return "ppc";
+#endif
+
+#elif defined(__wasm__)
+#if defined(__wasm64__)
+ return "wasm64";
+#elif defined(__wasm32__)
+ return "wasm32";
+#endif
+#endif
+}
+
bool Engine::is_abort_on_gpu_errors_enabled() const {
return abort_on_gpu_errors;
}
@@ -194,11 +233,11 @@ bool Engine::is_validation_layers_enabled() const {
}
void Engine::set_print_error_messages(bool p_enabled) {
- _print_error_enabled = p_enabled;
+ CoreGlobals::print_error_enabled = p_enabled;
}
bool Engine::is_printing_error_messages() const {
- return _print_error_enabled;
+ return CoreGlobals::print_error_enabled;
}
void Engine::add_singleton(const Singleton &p_singleton) {
@@ -271,6 +310,43 @@ Engine::Engine() {
singleton = this;
}
+void Engine::startup_begin() {
+ startup_benchmark_total_from = OS::get_singleton()->get_ticks_usec();
+}
+
+void Engine::startup_benchmark_begin_measure(const String &p_what) {
+ startup_benchmark_section = p_what;
+ startup_benchmark_from = OS::get_singleton()->get_ticks_usec();
+}
+void Engine::startup_benchmark_end_measure() {
+ uint64_t total = OS::get_singleton()->get_ticks_usec() - startup_benchmark_from;
+ double total_f = double(total) / double(1000000);
+
+ startup_benchmark_json[startup_benchmark_section] = total_f;
+}
+
+void Engine::startup_dump(const String &p_to_file) {
+ uint64_t total = OS::get_singleton()->get_ticks_usec() - startup_benchmark_total_from;
+ double total_f = double(total) / double(1000000);
+ startup_benchmark_json["total_time"] = total_f;
+
+ if (!p_to_file.is_empty()) {
+ Ref<FileAccess> f = FileAccess::open(p_to_file, FileAccess::WRITE);
+ if (f.is_valid()) {
+ Ref<JSON> json;
+ json.instantiate();
+ f->store_string(json->stringify(startup_benchmark_json, "\t", false, true));
+ }
+ } else {
+ List<Variant> keys;
+ startup_benchmark_json.get_key_list(&keys);
+ print_line("STARTUP BENCHMARK:");
+ for (const Variant &K : keys) {
+ print_line("\t-", K, ": ", startup_benchmark_json[K], +" sec.");
+ }
+ }
+}
+
Engine::Singleton::Singleton(const StringName &p_name, Object *p_ptr, const StringName &p_class_name) :
name(p_name),
ptr(p_ptr),
diff --git a/core/config/engine.h b/core/config/engine.h
index 68562643e7..121fd4d541 100644
--- a/core/config/engine.h
+++ b/core/config/engine.h
@@ -36,6 +36,9 @@
#include "core/templates/list.h"
#include "core/templates/vector.h"
+template <typename T>
+class TypedArray;
+
class Engine {
public:
struct Singleton {
@@ -79,6 +82,11 @@ private:
String write_movie_path;
String shader_cache_path;
+ Dictionary startup_benchmark_json;
+ String startup_benchmark_section;
+ uint64_t startup_benchmark_from = 0;
+ uint64_t startup_benchmark_total_from = 0;
+
public:
static Engine *get_singleton();
@@ -134,7 +142,7 @@ public:
Dictionary get_version_info() const;
Dictionary get_author_info() const;
- Array get_copyright_info() const;
+ TypedArray<Dictionary> get_copyright_info() const;
Dictionary get_donor_info() const;
Dictionary get_license_info() const;
String get_license_text() const;
@@ -142,6 +150,8 @@ public:
void set_write_movie_path(const String &p_path);
String get_write_movie_path() const;
+ String get_architecture_name() const;
+
void set_shader_cache_path(const String &p_path);
String get_shader_cache_path() const;
@@ -149,6 +159,11 @@ public:
bool is_validation_layers_enabled() const;
int32_t get_gpu_index() const;
+ void startup_begin();
+ void startup_benchmark_begin_measure(const String &p_what);
+ void startup_benchmark_end_measure();
+ void startup_dump(const String &p_to_file);
+
Engine();
virtual ~Engine() {}
};
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 38db7f9190..74c06123e1 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -72,7 +72,7 @@ String ProjectSettings::get_safe_project_name() const {
}
String ProjectSettings::get_imported_files_path() const {
- return get_project_data_path().plus_file("imported");
+ return get_project_data_path().path_join("imported");
}
// Returns the features that a project must have when opened with this build of Godot.
@@ -157,12 +157,12 @@ String ProjectSettings::localize_path(const String &p_path) const {
// in an absolute path that just happens to contain this string but points to a
// different folder (e.g. "/my/project" as resource_path would be contained in
// "/my/project_data", even though the latter is not part of res://.
- // `plus_file("")` is an easy way to ensure we have a trailing '/'.
- const String res_path = resource_path.plus_file("");
+ // `path_join("")` is an easy way to ensure we have a trailing '/'.
+ const String res_path = resource_path.path_join("");
// DirAccess::get_current_dir() is not guaranteed to return a path that with a trailing '/',
// so we must make sure we have it as well in order to compare with 'res_path'.
- cwd = cwd.plus_file("");
+ cwd = cwd.path_join("");
if (!cwd.begins_with(res_path)) {
return p_path;
@@ -442,6 +442,15 @@ void ProjectSettings::_convert_to_last_version(int p_from_version) {
* If nothing was found, error out.
*/
Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, bool p_upwards, bool p_ignore_override) {
+ if (!OS::get_singleton()->get_resource_dir().is_empty()) {
+ // OS will call ProjectSettings->get_resource_path which will be empty if not overridden!
+ // If the OS would rather use a specific location, then it will not be empty.
+ resource_path = OS::get_singleton()->get_resource_dir().replace("\\", "/");
+ if (!resource_path.is_empty() && resource_path[resource_path.length() - 1] == '/') {
+ resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end.
+ }
+ }
+
// If looking for files in a network client, use it directly
if (FileAccessNetworkClient::get_singleton()) {
@@ -463,7 +472,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
if (err == OK && !p_ignore_override) {
// Load override from location of the main pack
// Optional, we don't mind if it fails
- _load_settings_text(p_main_pack.get_base_dir().plus_file("override.cfg"));
+ _load_settings_text(p_main_pack.get_base_dir().path_join("override.cfg"));
}
return err;
}
@@ -491,14 +500,14 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
#ifdef MACOS_ENABLED
if (!found) {
// Attempt to load PCK from macOS .app bundle resources.
- found = _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().plus_file(exec_basename + ".pck")) || _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().plus_file(exec_filename + ".pck"));
+ found = _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().path_join(exec_basename + ".pck")) || _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().path_join(exec_filename + ".pck"));
}
#endif
if (!found) {
// Try to load data pack at the location of the executable.
// As mentioned above, we have two potential names to attempt.
- found = _load_resource_pack(exec_dir.plus_file(exec_basename + ".pck")) || _load_resource_pack(exec_dir.plus_file(exec_filename + ".pck"));
+ found = _load_resource_pack(exec_dir.path_join(exec_basename + ".pck")) || _load_resource_pack(exec_dir.path_join(exec_filename + ".pck"));
}
if (!found) {
@@ -514,7 +523,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
// Load overrides from the PCK and the executable location.
// Optional, we don't mind if either fails.
_load_settings_text("res://override.cfg");
- _load_settings_text(exec_path.get_base_dir().plus_file("override.cfg"));
+ _load_settings_text(exec_path.get_base_dir().path_join("override.cfg"));
}
return err;
}
@@ -524,13 +533,6 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
// (Only Android -when reading from pck- and iOS use this.)
if (!OS::get_singleton()->get_resource_dir().is_empty()) {
- // OS will call ProjectSettings->get_resource_path which will be empty if not overridden!
- // If the OS would rather use a specific location, then it will not be empty.
- resource_path = OS::get_singleton()->get_resource_dir().replace("\\", "/");
- if (!resource_path.is_empty() && resource_path[resource_path.length() - 1] == '/') {
- resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end.
- }
-
Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary");
if (err == OK && !p_ignore_override) {
// Optional, we don't mind if it fails.
@@ -554,10 +556,10 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
// Set the resource path early so things can be resolved when loading.
resource_path = current_dir;
resource_path = resource_path.replace("\\", "/"); // Windows path to Unix path just in case.
- err = _load_settings_text_or_binary(current_dir.plus_file("project.godot"), current_dir.plus_file("project.binary"));
+ err = _load_settings_text_or_binary(current_dir.path_join("project.godot"), current_dir.path_join("project.binary"));
if (err == OK && !p_ignore_override) {
// Optional, we don't mind if it fails.
- _load_settings_text(current_dir.plus_file("override.cfg"));
+ _load_settings_text(current_dir.path_join("override.cfg"));
found = true;
break;
}
@@ -683,7 +685,7 @@ Error ProjectSettings::_load_settings_text(const String &p_path) {
// If we're loading a project.godot from source code, we can operate some
// ProjectSettings conversions if need be.
_convert_to_last_version(config_version);
- last_save_time = FileAccess::get_modified_time(get_resource_path().plus_file("project.godot"));
+ last_save_time = FileAccess::get_modified_time(get_resource_path().path_join("project.godot"));
return OK;
}
ERR_FAIL_COND_V_MSG(err != OK, err, "Error parsing " + p_path + " at line " + itos(lines) + ": " + error_text + " File might be corrupted.");
@@ -762,9 +764,9 @@ void ProjectSettings::clear(const String &p_name) {
}
Error ProjectSettings::save() {
- Error error = save_custom(get_resource_path().plus_file("project.godot"));
+ Error error = save_custom(get_resource_path().path_join("project.godot"));
if (error == OK) {
- last_save_time = FileAccess::get_modified_time(get_resource_path().plus_file("project.godot"));
+ last_save_time = FileAccess::get_modified_time(get_resource_path().path_join("project.godot"));
}
return error;
}
@@ -909,7 +911,7 @@ Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_cust
}
}
// Check for the existence of a csproj file.
- if (FileAccess::exists(get_resource_path().plus_file(get_safe_project_name() + ".csproj"))) {
+ if (FileAccess::exists(get_resource_path().path_join(get_safe_project_name() + ".csproj"))) {
// If there is a csproj file, add the C# feature if it doesn't already exist.
if (!project_features.has("C#")) {
project_features.append("C#");
@@ -1070,7 +1072,7 @@ bool ProjectSettings::is_using_datapack() const {
return using_datapack;
}
-bool ProjectSettings::property_can_revert(const String &p_name) {
+bool ProjectSettings::_property_can_revert(const StringName &p_name) const {
if (!props.has(p_name)) {
return false;
}
@@ -1078,12 +1080,13 @@ bool ProjectSettings::property_can_revert(const String &p_name) {
return props[p_name].initial != props[p_name].variant;
}
-Variant ProjectSettings::property_get_revert(const String &p_name) {
+bool ProjectSettings::_property_get_revert(const StringName &p_name, Variant &r_property) const {
if (!props.has(p_name)) {
- return Variant();
+ return false;
}
- return props[p_name].initial;
+ r_property = props[p_name].initial;
+ return true;
}
void ProjectSettings::set_setting(const String &p_setting, const Variant &p_value) {
@@ -1134,8 +1137,6 @@ void ProjectSettings::_bind_methods() {
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", "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);
ClassDB::bind_method(D_METHOD("save_custom", "file"), &ProjectSettings::_save_custom_bnd);
}
@@ -1183,10 +1184,14 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("application/config/custom_user_dir_name", "");
GLOBAL_DEF("application/config/project_settings_override", "");
- GLOBAL_DEF_BASIC("display/window/size/viewport_width", 1024);
+ // The default window size is tuned to:
+ // - Have a 16:9 aspect ratio,
+ // - Have both dimensions divisible by 8 to better play along with video recording,
+ // - Be displayable correctly in windowed mode on a 1366×768 display (tested on Windows 10 with default settings).
+ GLOBAL_DEF_BASIC("display/window/size/viewport_width", 1152);
custom_prop_info["display/window/size/viewport_width"] = PropertyInfo(Variant::INT, "display/window/size/viewport_width", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"); // 8K resolution
- GLOBAL_DEF_BASIC("display/window/size/viewport_height", 600);
+ GLOBAL_DEF_BASIC("display/window/size/viewport_height", 648);
custom_prop_info["display/window/size/viewport_height"] = PropertyInfo(Variant::INT, "display/window/size/viewport_height", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"); // 8K resolution
GLOBAL_DEF_BASIC("display/window/size/resizable", true);
@@ -1198,6 +1203,9 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("display/window/size/window_height_override", 0);
custom_prop_info["display/window/size/window_height_override"] = PropertyInfo(Variant::INT, "display/window/size/window_height_override", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"); // 8K resolution
+ GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true);
+ GLOBAL_DEF("display/window/energy_saving/keep_screen_on.editor", false);
+
GLOBAL_DEF_BASIC("audio/buses/default_bus_layout", "res://default_bus_layout.tres");
custom_prop_info["audio/buses/default_bus_layout"] = PropertyInfo(Variant::STRING, "audio/buses/default_bus_layout", PROPERTY_HINT_FILE, "*.tres");
GLOBAL_DEF_RST("audio/general/2d_panning_strength", 1.0f);
diff --git a/core/config/project_settings.h b/core/config/project_settings.h
index c3992a4db2..c845120a26 100644
--- a/core/config/project_settings.h
+++ b/core/config/project_settings.h
@@ -102,6 +102,8 @@ protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ bool _property_can_revert(const StringName &p_name) const;
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
static ProjectSettings *singleton;
@@ -147,9 +149,6 @@ public:
void set_ignore_value_in_docs(const String &p_name, bool p_ignore);
bool get_ignore_value_in_docs(const String &p_name) const;
- bool property_can_revert(const String &p_name);
- Variant property_get_revert(const String &p_name);
-
String get_project_data_dir_name() const;
String get_project_data_path() const;
String get_resource_path() const;
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 3f94ff8329..9daf58cb71 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -39,6 +39,7 @@
#include "core/math/geometry_2d.h"
#include "core/math/geometry_3d.h"
#include "core/os/keyboard.h"
+#include "core/variant/typed_array.h"
namespace core_bind {
@@ -331,6 +332,39 @@ Vector<String> OS::get_cmdline_args() {
return cmdlinev;
}
+Vector<String> OS::get_cmdline_user_args() {
+ List<String> cmdline = ::OS::get_singleton()->get_cmdline_user_args();
+ Vector<String> cmdlinev;
+ for (const String &E : cmdline) {
+ cmdlinev.push_back(E);
+ }
+
+ return cmdlinev;
+}
+
+void OS::set_restart_on_exit(bool p_restart, const Vector<String> &p_restart_arguments) {
+ List<String> args_list;
+ for (const String &restart_argument : p_restart_arguments) {
+ args_list.push_back(restart_argument);
+ }
+
+ ::OS::get_singleton()->set_restart_on_exit(p_restart, args_list);
+}
+
+bool OS::is_restart_on_exit_set() const {
+ return ::OS::get_singleton()->is_restart_on_exit_set();
+}
+
+Vector<String> OS::get_restart_on_exit_arguments() const {
+ List<String> args = ::OS::get_singleton()->get_restart_on_exit_arguments();
+ Vector<String> args_vector;
+ for (List<String>::Element *E = args.front(); E; E = E->next()) {
+ args_vector.push_back(E->get());
+ }
+
+ return args_vector;
+}
+
String OS::get_locale() const {
return ::OS::get_singleton()->get_locale();
}
@@ -403,118 +437,6 @@ bool OS::is_stdout_verbose() const {
return ::OS::get_singleton()->is_stdout_verbose();
}
-void OS::dump_memory_to_file(const String &p_file) {
- ::OS::get_singleton()->dump_memory_to_file(p_file.utf8().get_data());
-}
-
-struct OSCoreBindImg {
- String path;
- Size2 size;
- int fmt = 0;
- ObjectID id;
- int vram = 0;
- bool operator<(const OSCoreBindImg &p_img) const { return vram == p_img.vram ? id < p_img.id : vram > p_img.vram; }
-};
-
-void OS::print_all_textures_by_size() {
- List<OSCoreBindImg> imgs;
- uint64_t total = 0;
- {
- List<Ref<Resource>> rsrc;
- ResourceCache::get_cached_resources(&rsrc);
-
- for (Ref<Resource> &res : rsrc) {
- if (!res->is_class("Texture")) {
- continue;
- }
-
- Size2 size = res->call("get_size");
- int fmt = res->call("get_format");
-
- OSCoreBindImg img;
- img.size = size;
- img.fmt = fmt;
- img.path = res->get_path();
- img.vram = Image::get_image_data_size(img.size.width, img.size.height, Image::Format(img.fmt));
- img.id = res->get_instance_id();
- total += img.vram;
- imgs.push_back(img);
- }
- }
-
- imgs.sort();
-
- if (imgs.size() == 0) {
- print_line("No textures seem used in this project.");
- } else {
- print_line("Textures currently in use, sorted by VRAM usage:\n"
- "Path - VRAM usage (Dimensions)");
- }
-
- for (const OSCoreBindImg &img : imgs) {
- print_line(vformat("%s - %s %s",
- img.path,
- String::humanize_size(img.vram),
- img.size));
- }
-
- print_line(vformat("Total VRAM usage: %s.", String::humanize_size(total)));
-}
-
-void OS::print_resources_by_type(const Vector<String> &p_types) {
- ERR_FAIL_COND_MSG(p_types.size() == 0,
- "At least one type should be provided to print resources by type.");
-
- print_line(vformat("Resources currently in use for the following types: %s", p_types));
-
- RBMap<String, int> type_count;
- List<Ref<Resource>> resources;
- ResourceCache::get_cached_resources(&resources);
-
- for (const Ref<Resource> &r : resources) {
- bool found = false;
-
- for (int i = 0; i < p_types.size(); i++) {
- if (r->is_class(p_types[i])) {
- found = true;
- }
- }
- if (!found) {
- continue;
- }
-
- if (!type_count.has(r->get_class())) {
- type_count[r->get_class()] = 0;
- }
-
- type_count[r->get_class()]++;
-
- print_line(vformat("%s: %s", r->get_class(), r->get_path()));
-
- List<StringName> metas;
- r->get_meta_list(&metas);
- for (const StringName &meta : metas) {
- print_line(vformat(" %s: %s", meta, r->get_meta(meta)));
- }
- }
-
- for (const KeyValue<String, int> &E : type_count) {
- print_line(vformat("%s count: %d", E.key, E.value));
- }
-}
-
-void OS::print_all_resources(const String &p_to_file) {
- ::OS::get_singleton()->print_all_resources(p_to_file);
-}
-
-void OS::print_resources_in_use(bool p_short) {
- ::OS::get_singleton()->print_resources_in_use(p_short);
-}
-
-void OS::dump_resources_to_file(const String &p_file) {
- ::OS::get_singleton()->dump_resources_to_file(p_file.utf8().get_data());
-}
-
Error OS::move_to_trash(const String &p_path) const {
return ::OS::get_singleton()->move_to_trash(p_path);
}
@@ -614,6 +536,11 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_name"), &OS::get_name);
ClassDB::bind_method(D_METHOD("get_cmdline_args"), &OS::get_cmdline_args);
+ ClassDB::bind_method(D_METHOD("get_cmdline_user_args"), &OS::get_cmdline_user_args);
+
+ ClassDB::bind_method(D_METHOD("set_restart_on_exit", "restart", "arguments"), &OS::set_restart_on_exit, DEFVAL(Vector<String>()));
+ ClassDB::bind_method(D_METHOD("is_restart_on_exit_set"), &OS::is_restart_on_exit_set);
+ ClassDB::bind_method(D_METHOD("get_restart_on_exit_arguments"), &OS::get_restart_on_exit_arguments);
ClassDB::bind_method(D_METHOD("delay_usec", "usec"), &OS::delay_usec);
ClassDB::bind_method(D_METHOD("delay_msec", "msec"), &OS::delay_msec);
@@ -628,11 +555,6 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_debug_build"), &OS::is_debug_build);
- ClassDB::bind_method(D_METHOD("dump_memory_to_file", "file"), &OS::dump_memory_to_file);
- ClassDB::bind_method(D_METHOD("dump_resources_to_file", "file"), &OS::dump_resources_to_file);
- ClassDB::bind_method(D_METHOD("print_resources_in_use", "short"), &OS::print_resources_in_use, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("print_all_resources", "tofile"), &OS::print_all_resources, DEFVAL(""));
-
ClassDB::bind_method(D_METHOD("get_static_memory_usage"), &OS::get_static_memory_usage);
ClassDB::bind_method(D_METHOD("get_static_memory_peak_usage"), &OS::get_static_memory_peak_usage);
@@ -644,9 +566,6 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_cache_dir"), &OS::get_cache_dir);
ClassDB::bind_method(D_METHOD("get_unique_id"), &OS::get_unique_id);
- ClassDB::bind_method(D_METHOD("print_all_textures_by_size"), &OS::print_all_textures_by_size);
- ClassDB::bind_method(D_METHOD("print_resources_by_type", "types"), &OS::print_resources_by_type);
-
ClassDB::bind_method(D_METHOD("get_keycode_string", "code"), &OS::get_keycode_string);
ClassDB::bind_method(D_METHOD("is_keycode_unicode", "code"), &OS::is_keycode_unicode);
ClassDB::bind_method(D_METHOD("find_keycode_from_string", "string"), &OS::find_keycode_from_string);
@@ -780,7 +699,7 @@ Vector<Point2> Geometry2D::convex_hull(const Vector<Point2> &p_points) {
return ::Geometry2D::convex_hull(p_points);
}
-Array Geometry2D::merge_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
+TypedArray<PackedVector2Array> Geometry2D::merge_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
Vector<Vector<Point2>> polys = ::Geometry2D::merge_polygons(p_polygon_a, p_polygon_b);
Array ret;
@@ -791,10 +710,10 @@ Array Geometry2D::merge_polygons(const Vector<Vector2> &p_polygon_a, const Vecto
return ret;
}
-Array Geometry2D::clip_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
+TypedArray<PackedVector2Array> Geometry2D::clip_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
Vector<Vector<Point2>> polys = ::Geometry2D::clip_polygons(p_polygon_a, p_polygon_b);
- Array ret;
+ TypedArray<PackedVector2Array> ret;
for (int i = 0; i < polys.size(); ++i) {
ret.push_back(polys[i]);
@@ -802,7 +721,7 @@ Array Geometry2D::clip_polygons(const Vector<Vector2> &p_polygon_a, const Vector
return ret;
}
-Array Geometry2D::intersect_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
+TypedArray<PackedVector2Array> Geometry2D::intersect_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
Vector<Vector<Point2>> polys = ::Geometry2D::intersect_polygons(p_polygon_a, p_polygon_b);
Array ret;
@@ -813,7 +732,7 @@ Array Geometry2D::intersect_polygons(const Vector<Vector2> &p_polygon_a, const V
return ret;
}
-Array Geometry2D::exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
+TypedArray<PackedVector2Array> Geometry2D::exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b) {
Vector<Vector<Point2>> polys = ::Geometry2D::exclude_polygons(p_polygon_a, p_polygon_b);
Array ret;
@@ -824,7 +743,7 @@ Array Geometry2D::exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vec
return ret;
}
-Array Geometry2D::clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
+TypedArray<PackedVector2Array> Geometry2D::clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
Vector<Vector<Point2>> polys = ::Geometry2D::clip_polyline_with_polygon(p_polyline, p_polygon);
Array ret;
@@ -835,7 +754,7 @@ Array Geometry2D::clip_polyline_with_polygon(const Vector<Vector2> &p_polyline,
return ret;
}
-Array Geometry2D::intersect_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
+TypedArray<PackedVector2Array> Geometry2D::intersect_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon) {
Vector<Vector<Point2>> polys = ::Geometry2D::intersect_polyline_with_polygon(p_polyline, p_polygon);
Array ret;
@@ -846,7 +765,7 @@ Array Geometry2D::intersect_polyline_with_polygon(const Vector<Vector2> &p_polyl
return ret;
}
-Array Geometry2D::offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type) {
+TypedArray<PackedVector2Array> Geometry2D::offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type) {
Vector<Vector<Point2>> polys = ::Geometry2D::offset_polygon(p_polygon, p_delta, ::Geometry2D::PolyJoinType(p_join_type));
Array ret;
@@ -857,7 +776,7 @@ Array Geometry2D::offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delt
return ret;
}
-Array Geometry2D::offset_polyline(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) {
+TypedArray<PackedVector2Array> Geometry2D::offset_polyline(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type) {
Vector<Vector<Point2>> polys = ::Geometry2D::offset_polyline(p_polygon, p_delta, ::Geometry2D::PolyJoinType(p_join_type), ::Geometry2D::PolyEndType(p_end_type));
Array ret;
@@ -895,6 +814,7 @@ Dictionary Geometry2D::make_atlas(const Vector<Size2> &p_rects) {
void Geometry2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_point_in_circle", "point", "circle_position", "circle_radius"), &Geometry2D::is_point_in_circle);
+ ClassDB::bind_method(D_METHOD("segment_intersects_circle", "segment_from", "segment_to", "circle_position", "circle_radius"), &Geometry2D::segment_intersects_circle);
ClassDB::bind_method(D_METHOD("segment_intersects_segment", "from_a", "to_a", "from_b", "to_b"), &Geometry2D::segment_intersects_segment);
ClassDB::bind_method(D_METHOD("line_intersects_line", "from_a", "dir_a", "from_b", "dir_b"), &Geometry2D::line_intersects_line);
@@ -949,16 +869,19 @@ Geometry3D *Geometry3D::get_singleton() {
return singleton;
}
-Vector<Plane> Geometry3D::build_box_planes(const Vector3 &p_extents) {
- return ::Geometry3D::build_box_planes(p_extents);
+TypedArray<Plane> Geometry3D::build_box_planes(const Vector3 &p_extents) {
+ Variant ret = ::Geometry3D::build_box_planes(p_extents);
+ return ret;
}
-Vector<Plane> Geometry3D::build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis) {
- return ::Geometry3D::build_cylinder_planes(p_radius, p_height, p_sides, p_axis);
+TypedArray<Plane> Geometry3D::build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis) {
+ Variant ret = ::Geometry3D::build_cylinder_planes(p_radius, p_height, p_sides, p_axis);
+ return ret;
}
-Vector<Plane> Geometry3D::build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis) {
- return ::Geometry3D::build_capsule_planes(p_radius, p_height, p_sides, p_lats, p_axis);
+TypedArray<Plane> Geometry3D::build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis) {
+ Variant ret = ::Geometry3D::build_capsule_planes(p_radius, p_height, p_sides, p_lats, p_axis);
+ return ret;
}
Vector<Vector3> Geometry3D::get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2) {
@@ -1227,13 +1150,13 @@ Vector<uint8_t> File::get_buffer(int64_t p_length) const {
return data;
}
-String File::get_as_text() const {
+String File::get_as_text(bool p_skip_cr) const {
ERR_FAIL_COND_V_MSG(f.is_null(), String(), "File must be opened before use, or is lacking read-write permission.");
uint64_t original_pos = f->get_position();
const_cast<FileAccess *>(*f)->seek(0);
- String text = f->get_as_utf8_string();
+ String text = f->get_as_utf8_string(p_skip_cr);
const_cast<FileAccess *>(*f)->seek(original_pos);
@@ -1430,7 +1353,7 @@ void File::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_buffer", "length"), &File::get_buffer);
ClassDB::bind_method(D_METHOD("get_line"), &File::get_line);
ClassDB::bind_method(D_METHOD("get_csv_line", "delim"), &File::get_csv_line, DEFVAL(","));
- ClassDB::bind_method(D_METHOD("get_as_text"), &File::get_as_text);
+ ClassDB::bind_method(D_METHOD("get_as_text", "skip_cr"), &File::get_as_text, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_md5", "path"), &File::get_md5);
ClassDB::bind_method(D_METHOD("get_sha256", "path"), &File::get_sha256);
ClassDB::bind_method(D_METHOD("is_big_endian"), &File::is_big_endian);
@@ -1983,10 +1906,10 @@ Dictionary ClassDB::get_signal(StringName p_class, StringName p_signal) const {
}
}
-Array ClassDB::get_signal_list(StringName p_class, bool p_no_inheritance) const {
+TypedArray<Dictionary> ClassDB::get_signal_list(StringName p_class, bool p_no_inheritance) const {
List<MethodInfo> signals;
::ClassDB::get_signal_list(p_class, &signals, p_no_inheritance);
- Array ret;
+ TypedArray<Dictionary> ret;
for (const MethodInfo &E : signals) {
ret.push_back(E.operator Dictionary());
@@ -1995,10 +1918,10 @@ Array ClassDB::get_signal_list(StringName p_class, bool p_no_inheritance) const
return ret;
}
-Array ClassDB::get_property_list(StringName p_class, bool p_no_inheritance) const {
+TypedArray<Dictionary> ClassDB::get_property_list(StringName p_class, bool p_no_inheritance) const {
List<PropertyInfo> plist;
::ClassDB::get_property_list(p_class, &plist, p_no_inheritance);
- Array ret;
+ TypedArray<Dictionary> ret;
for (const PropertyInfo &E : plist) {
ret.push_back(E.operator Dictionary());
}
@@ -2027,10 +1950,10 @@ bool ClassDB::has_method(StringName p_class, StringName p_method, bool p_no_inhe
return ::ClassDB::has_method(p_class, p_method, p_no_inheritance);
}
-Array ClassDB::get_method_list(StringName p_class, bool p_no_inheritance) const {
+TypedArray<Dictionary> ClassDB::get_method_list(StringName p_class, bool p_no_inheritance) const {
List<MethodInfo> methods;
::ClassDB::get_method_list(p_class, &methods, p_no_inheritance);
- Array ret;
+ TypedArray<Dictionary> ret;
for (const MethodInfo &E : methods) {
#ifdef DEBUG_METHODS_ENABLED
@@ -2215,7 +2138,7 @@ Dictionary Engine::get_author_info() const {
return ::Engine::get_singleton()->get_author_info();
}
-Array Engine::get_copyright_info() const {
+TypedArray<Dictionary> Engine::get_copyright_info() const {
return ::Engine::get_singleton()->get_copyright_info();
}
@@ -2231,6 +2154,10 @@ String Engine::get_license_text() const {
return ::Engine::get_singleton()->get_license_text();
}
+String Engine::get_architecture_name() const {
+ return ::Engine::get_singleton()->get_architecture_name();
+}
+
bool Engine::is_in_physics_frame() const {
return ::Engine::get_singleton()->is_in_physics_frame();
}
@@ -2328,6 +2255,8 @@ void Engine::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_license_info"), &Engine::get_license_info);
ClassDB::bind_method(D_METHOD("get_license_text"), &Engine::get_license_text);
+ ClassDB::bind_method(D_METHOD("get_architecture_name"), &Engine::get_architecture_name);
+
ClassDB::bind_method(D_METHOD("is_in_physics_frame"), &Engine::is_in_physics_frame);
ClassDB::bind_method(D_METHOD("has_singleton", "name"), &Engine::has_singleton);
diff --git a/core/core_bind.h b/core/core_bind.h
index 3a4faa3422..cd382d2915 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -45,6 +45,8 @@
#include "core/templates/safe_refcount.h"
class MainLoop;
+template <typename T>
+class TypedArray;
namespace core_bind {
@@ -182,26 +184,23 @@ public:
bool is_process_running(int p_pid) const;
int get_process_id() const;
+ void set_restart_on_exit(bool p_restart, const Vector<String> &p_restart_arguments = Vector<String>());
+ bool is_restart_on_exit_set() const;
+ Vector<String> get_restart_on_exit_arguments() const;
+
bool has_environment(const String &p_var) const;
String get_environment(const String &p_var) const;
bool set_environment(const String &p_var, const String &p_value) const;
String get_name() const;
Vector<String> get_cmdline_args();
+ Vector<String> get_cmdline_user_args();
String get_locale() const;
String get_locale_language() const;
String get_model_name() const;
- void dump_memory_to_file(const String &p_file);
- void dump_resources_to_file(const String &p_file);
-
- void print_resources_in_use(bool p_short = false);
- void print_all_resources(const String &p_to_file);
- void print_all_textures_by_size();
- void print_resources_by_type(const Vector<String> &p_types);
-
bool is_debug_build() const;
String get_unique_id() const;
@@ -296,14 +295,14 @@ public:
OPERATION_XOR
};
// 2D polygon boolean operations.
- Array merge_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Union (add).
- Array clip_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Difference (subtract).
- Array intersect_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Common area (multiply).
- Array exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // All but common area (xor).
+ TypedArray<PackedVector2Array> merge_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Union (add).
+ TypedArray<PackedVector2Array> clip_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Difference (subtract).
+ TypedArray<PackedVector2Array> intersect_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // Common area (multiply).
+ TypedArray<PackedVector2Array> exclude_polygons(const Vector<Vector2> &p_polygon_a, const Vector<Vector2> &p_polygon_b); // All but common area (xor).
// 2D polyline vs polygon operations.
- Array clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Cut.
- Array intersect_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Chop.
+ TypedArray<PackedVector2Array> clip_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Cut.
+ TypedArray<PackedVector2Array> intersect_polyline_with_polygon(const Vector<Vector2> &p_polyline, const Vector<Vector2> &p_polygon); // Chop.
// 2D offset polygons/polylines.
enum PolyJoinType {
@@ -318,8 +317,8 @@ public:
END_SQUARE,
END_ROUND
};
- Array offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE);
- Array offset_polyline(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE, PolyEndType p_end_type = END_SQUARE);
+ TypedArray<PackedVector2Array> offset_polygon(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE);
+ TypedArray<PackedVector2Array> offset_polyline(const Vector<Vector2> &p_polygon, real_t p_delta, PolyJoinType p_join_type = JOIN_SQUARE, PolyEndType p_end_type = END_SQUARE);
Dictionary make_atlas(const Vector<Size2> &p_rects);
@@ -336,9 +335,9 @@ protected:
public:
static Geometry3D *get_singleton();
- Vector<Plane> build_box_planes(const Vector3 &p_extents);
- Vector<Plane> build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis = Vector3::AXIS_Z);
- Vector<Plane> build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis = Vector3::AXIS_Z);
+ TypedArray<Plane> build_box_planes(const Vector3 &p_extents);
+ TypedArray<Plane> build_cylinder_planes(float p_radius, float p_height, int p_sides, Vector3::Axis p_axis = Vector3::AXIS_Z);
+ TypedArray<Plane> build_capsule_planes(float p_radius, float p_height, int p_sides, int p_lats, Vector3::Axis p_axis = Vector3::AXIS_Z);
Vector<Vector3> get_closest_points_between_segments(const Vector3 &p1, const Vector3 &p2, const Vector3 &q1, const Vector3 &q2);
Vector3 get_closest_point_to_segment(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b);
Vector3 get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b);
@@ -411,7 +410,7 @@ public:
Vector<uint8_t> get_buffer(int64_t p_length) const; // Get an array of bytes.
String get_line() const;
Vector<String> get_csv_line(const String &p_delim = ",") const;
- String get_as_text() const;
+ String get_as_text(bool p_skip_cr = false) const;
String get_md5(const String &p_path) const;
String get_sha256(const String &p_path) const;
@@ -597,15 +596,15 @@ public:
bool has_signal(StringName p_class, StringName p_signal) const;
Dictionary get_signal(StringName p_class, StringName p_signal) const;
- Array get_signal_list(StringName p_class, bool p_no_inheritance = false) const;
+ TypedArray<Dictionary> get_signal_list(StringName p_class, bool p_no_inheritance = false) const;
- Array get_property_list(StringName p_class, bool p_no_inheritance = false) const;
+ TypedArray<Dictionary> get_property_list(StringName p_class, bool p_no_inheritance = false) const;
Variant get_property(Object *p_object, const StringName &p_property) const;
Error set_property(Object *p_object, const StringName &p_property, const Variant &p_value) const;
bool has_method(StringName p_class, StringName p_method, bool p_no_inheritance = false) const;
- Array get_method_list(StringName p_class, bool p_no_inheritance = false) const;
+ TypedArray<Dictionary> get_method_list(StringName p_class, bool p_no_inheritance = false) const;
PackedStringArray get_integer_constant_list(const StringName &p_class, bool p_no_inheritance = false) const;
bool has_integer_constant(const StringName &p_class, const StringName &p_name) const;
@@ -656,11 +655,13 @@ public:
Dictionary get_version_info() const;
Dictionary get_author_info() const;
- Array get_copyright_info() const;
+ TypedArray<Dictionary> get_copyright_info() const;
Dictionary get_donor_info() const;
Dictionary get_license_info() const;
String get_license_text() const;
+ String get_architecture_name() const;
+
bool is_in_physics_frame() const;
bool has_singleton(const StringName &p_name) const;
diff --git a/core/core_constants.cpp b/core/core_constants.cpp
index dc0ab72a86..c4d83d4765 100644
--- a/core/core_constants.cpp
+++ b/core/core_constants.cpp
@@ -612,6 +612,8 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALE_ID);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LOCALIZABLE_STRING);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NODE_TYPE);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_HIDE_QUATERNION_EDIT);
+ BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_PASSWORD);
BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_MAX);
BIND_CORE_ENUM_CONSTANT(PROPERTY_USAGE_NONE);
diff --git a/core/core_globals.cpp b/core/core_globals.cpp
new file mode 100644
index 0000000000..45297b459f
--- /dev/null
+++ b/core/core_globals.cpp
@@ -0,0 +1,35 @@
+/*************************************************************************/
+/* core_globals.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "core_globals.h"
+
+bool CoreGlobals::leak_reporting_enabled = true;
+bool CoreGlobals::print_line_enabled = true;
+bool CoreGlobals::print_error_enabled = true;
diff --git a/modules/visual_script/register_types.h b/core/core_globals.h
index 90f84de11c..c5e614dc0a 100644
--- a/modules/visual_script/register_types.h
+++ b/core/core_globals.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* register_types.h */
+/* core_globals.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,12 +28,17 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef VISUAL_SCRIPT_REGISTER_TYPES_H
-#define VISUAL_SCRIPT_REGISTER_TYPES_H
+#ifndef CORE_GLOBALS_H
+#define CORE_GLOBALS_H
-#include "modules/register_module_types.h"
+// Home for state needed from global functions
+// that cannot be stored in Engine or OS due to e.g. circular includes
-void initialize_visual_script_module(ModuleInitializationLevel p_level);
-void uninitialize_visual_script_module(ModuleInitializationLevel p_level);
+class CoreGlobals {
+public:
+ static bool leak_reporting_enabled;
+ static bool print_line_enabled;
+ static bool print_error_enabled;
+};
-#endif // VISUAL_SCRIPT_REGISTER_TYPES_H
+#endif // CORE_GLOBALS_H
diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp
index 867b1fc637..5cf951a93c 100644
--- a/core/extension/extension_api_dump.cpp
+++ b/core/extension/extension_api_dump.cpp
@@ -52,6 +52,9 @@ static String get_type_name(const PropertyInfo &p_info) {
if (p_info.type == Variant::INT && (p_info.usage & (PROPERTY_USAGE_CLASS_IS_BITFIELD))) {
return String("bitfield::") + String(p_info.class_name);
}
+ if (p_info.type == Variant::INT && (p_info.usage & PROPERTY_USAGE_ARRAY)) {
+ return "int";
+ }
if (p_info.class_name != StringName()) {
return p_info.class_name;
}
@@ -88,6 +91,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
}
const uint32_t vec3_elems = 3;
+ const uint32_t vec4_elems = 4;
const uint32_t ptrsize_32 = 4;
const uint32_t ptrsize_64 = 8;
static const char *build_config_name[4] = { "float_32", "float_64", "double_32", "double_64" };
@@ -138,7 +142,7 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
{ Variant::AABB, (vec3_elems * 2) * sizeof(float), (vec3_elems * 2) * sizeof(float), (vec3_elems * 2) * sizeof(double), (vec3_elems * 2) * sizeof(double) },
{ Variant::BASIS, (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(double), (vec3_elems * 3) * sizeof(double) },
{ Variant::TRANSFORM3D, (vec3_elems * 4) * sizeof(float), (vec3_elems * 4) * sizeof(float), (vec3_elems * 4) * sizeof(double), (vec3_elems * 4) * sizeof(double) },
- { Variant::PROJECTION, 4 * 4 * sizeof(float), 4 * 4 * sizeof(float), 4 * 4 * sizeof(double), 4 * 4 * sizeof(double) },
+ { Variant::PROJECTION, (vec4_elems * 4) * sizeof(float), (vec4_elems * 4) * sizeof(float), (vec4_elems * 4) * sizeof(double), (vec4_elems * 4) * sizeof(double) },
{ Variant::COLOR, 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(float) },
{ Variant::STRING_NAME, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
{ Variant::NODE_PATH, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 },
@@ -284,6 +288,10 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
{ Variant::BASIS, "z", vec3_elems * 2 * sizeof(float), vec3_elems * 2 * sizeof(float), vec3_elems * 2 * sizeof(double), vec3_elems * 2 * sizeof(double) },
{ Variant::TRANSFORM3D, "basis", 0, 0, 0, 0 },
{ Variant::TRANSFORM3D, "origin", (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(double), (vec3_elems * 3) * sizeof(double) },
+ { Variant::PROJECTION, "x", 0, 0, 0, 0 },
+ { Variant::PROJECTION, "y", vec4_elems * sizeof(float), vec4_elems * sizeof(float), vec4_elems * sizeof(double), vec4_elems * sizeof(double) },
+ { Variant::PROJECTION, "z", vec4_elems * 2 * sizeof(float), vec4_elems * 2 * sizeof(float), vec4_elems * 2 * sizeof(double), vec4_elems * 2 * sizeof(double) },
+ { Variant::PROJECTION, "w", vec4_elems * 3 * sizeof(float), vec4_elems * 3 * sizeof(float), vec4_elems * 3 * sizeof(double), vec4_elems * 3 * sizeof(double) },
{ Variant::COLOR, "r", 0, 0, 0, 0 },
{ Variant::COLOR, "g", sizeof(float), sizeof(float), sizeof(float), sizeof(float) },
{ Variant::COLOR, "b", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(float) },
@@ -840,12 +848,16 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() {
List<PropertyInfo> property_list;
ClassDB::get_property_list(class_name, &property_list, true);
for (const PropertyInfo &F : property_list) {
- if (F.usage & PROPERTY_USAGE_CATEGORY || F.usage & PROPERTY_USAGE_GROUP || F.usage & PROPERTY_USAGE_SUBGROUP) {
+ if (F.usage & PROPERTY_USAGE_CATEGORY || F.usage & PROPERTY_USAGE_GROUP || F.usage & PROPERTY_USAGE_SUBGROUP || (F.type == Variant::NIL && F.usage & PROPERTY_USAGE_ARRAY)) {
continue; //not real properties
}
if (F.name.begins_with("_")) {
continue; //hidden property
}
+ if (F.name.find("/") >= 0) {
+ // Ignore properties with '/' (slash) in the name. These are only meant for use in the inspector.
+ continue;
+ }
StringName property_name = F.name;
Dictionary d2;
d2["type"] = get_type_name(F);
diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h
index 041a6e5112..cb2adcb562 100644
--- a/core/extension/gdnative_interface.h
+++ b/core/extension/gdnative_interface.h
@@ -222,6 +222,8 @@ typedef struct {
typedef const GDNativePropertyInfo *(*GDNativeExtensionClassGetPropertyList)(GDExtensionClassInstancePtr p_instance, uint32_t *r_count);
typedef void (*GDNativeExtensionClassFreePropertyList)(GDExtensionClassInstancePtr p_instance, const GDNativePropertyInfo *p_list);
+typedef GDNativeBool (*GDNativeExtensionClassPropertyCanRevert)(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name);
+typedef GDNativeBool (*GDNativeExtensionClassPropertyGetRevert)(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret);
typedef void (*GDNativeExtensionClassNotification)(GDExtensionClassInstancePtr p_instance, int32_t p_what);
typedef void (*GDNativeExtensionClassToString)(GDExtensionClassInstancePtr p_instance, GDNativeStringPtr p_out);
typedef void (*GDNativeExtensionClassReference)(GDExtensionClassInstancePtr p_instance);
@@ -237,6 +239,8 @@ typedef struct {
GDNativeExtensionClassGet get_func;
GDNativeExtensionClassGetPropertyList get_property_list_func;
GDNativeExtensionClassFreePropertyList free_property_list_func;
+ GDNativeExtensionClassPropertyCanRevert property_can_revert_func;
+ GDNativeExtensionClassPropertyGetRevert property_get_revert_func;
GDNativeExtensionClassNotification notification_func;
GDNativeExtensionClassToString to_string_func;
GDNativeExtensionClassReference reference_func;
@@ -309,6 +313,9 @@ typedef const GDNativePropertyInfo *(*GDNativeExtensionScriptInstanceGetProperty
typedef void (*GDNativeExtensionScriptInstanceFreePropertyList)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativePropertyInfo *p_list);
typedef GDNativeVariantType (*GDNativeExtensionScriptInstanceGetPropertyType)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name, GDNativeBool *r_is_valid);
+typedef GDNativeBool (*GDNativeExtensionScriptInstancePropertyCanRevert)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name);
+typedef GDNativeBool (*GDNativeExtensionScriptInstancePropertyGetRevert)(GDNativeExtensionScriptInstanceDataPtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret);
+
typedef GDNativeObjectPtr (*GDNativeExtensionScriptInstanceGetOwner)(GDNativeExtensionScriptInstanceDataPtr p_instance);
typedef void (*GDNativeExtensionScriptInstancePropertyStateAdd)(const GDNativeStringNamePtr p_name, const GDNativeVariantPtr p_value, void *p_userdata);
typedef void (*GDNativeExtensionScriptInstanceGetPropertyState)(GDNativeExtensionScriptInstanceDataPtr p_instance, GDNativeExtensionScriptInstancePropertyStateAdd p_add_func, void *p_userdata);
@@ -343,6 +350,9 @@ typedef struct {
GDNativeExtensionScriptInstanceFreePropertyList free_property_list_func;
GDNativeExtensionScriptInstanceGetPropertyType get_property_type_func;
+ GDNativeExtensionScriptInstancePropertyCanRevert property_can_revert_func;
+ GDNativeExtensionScriptInstancePropertyGetRevert property_get_revert_func;
+
GDNativeExtensionScriptInstanceGetOwner get_owner_func;
GDNativeExtensionScriptInstanceGetPropertyState get_property_state_func;
diff --git a/core/extension/native_extension.cpp b/core/extension/native_extension.cpp
index b69859b441..6418da2235 100644
--- a/core/extension/native_extension.cpp
+++ b/core/extension/native_extension.cpp
@@ -36,7 +36,7 @@
#include "core/os/os.h"
String NativeExtension::get_extension_list_config_file() {
- return ProjectSettings::get_singleton()->get_project_data_path().plus_file("extension_list.cfg");
+ return ProjectSettings::get_singleton()->get_project_data_path().path_join("extension_list.cfg");
}
class NativeExtensionMethodBind : public MethodBind {
@@ -156,6 +156,8 @@ void NativeExtension::_register_extension_class(const GDNativeExtensionClassLibr
extension->native_extension.get = p_extension_funcs->get_func;
extension->native_extension.get_property_list = p_extension_funcs->get_property_list_func;
extension->native_extension.free_property_list = p_extension_funcs->free_property_list_func;
+ extension->native_extension.property_can_revert = p_extension_funcs->property_can_revert_func;
+ extension->native_extension.property_get_revert = p_extension_funcs->property_get_revert_func;
extension->native_extension.notification = p_extension_funcs->notification_func;
extension->native_extension.to_string = p_extension_funcs->to_string_func;
extension->native_extension.reference = p_extension_funcs->reference_func;
@@ -372,7 +374,7 @@ Ref<Resource> NativeExtensionResourceLoader::load(const String &p_path, const St
}
if (err != OK) {
- ERR_PRINT("Error loading GDExtension config file: " + p_path);
+ ERR_PRINT("Error loading GDExtension configuration file: " + p_path);
return Ref<Resource>();
}
@@ -380,7 +382,7 @@ Ref<Resource> NativeExtensionResourceLoader::load(const String &p_path, const St
if (r_error) {
*r_error = ERR_INVALID_DATA;
}
- ERR_PRINT("GDExtension config file must contain 'configuration.entry_symbol' key: " + p_path);
+ ERR_PRINT("GDExtension configuration file must contain a \"configuration/entry_symbol\" key: " + p_path);
return Ref<Resource>();
}
@@ -413,12 +415,13 @@ Ref<Resource> NativeExtensionResourceLoader::load(const String &p_path, const St
if (r_error) {
*r_error = ERR_FILE_NOT_FOUND;
}
- ERR_PRINT("No GDExtension library found for current architecture; in config file " + p_path);
+ const String os_arch = OS::get_singleton()->get_name().to_lower() + "." + Engine::get_singleton()->get_architecture_name();
+ ERR_PRINT(vformat("No GDExtension library found for current OS and architecture (%s) in configuration file: %s", os_arch, p_path));
return Ref<Resource>();
}
if (!library_path.is_resource_file() && !library_path.is_absolute_path()) {
- library_path = p_path.get_base_dir().plus_file(library_path);
+ library_path = p_path.get_base_dir().path_join(library_path);
}
Ref<NativeExtension> lib;
diff --git a/core/input/gamecontrollerdb.txt b/core/input/gamecontrollerdb.txt
index d751f6c9b8..f5874a3dec 100644
--- a/core/input/gamecontrollerdb.txt
+++ b/core/input/gamecontrollerdb.txt
@@ -11,7 +11,7 @@
03000000d0160000600a000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows,
03000000c82d00000031000000000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000531000000000000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
-03000000c82d00000951000000000000,8BitDo Dogbone Modkit,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Windows,
+03000000c82d00000951000000000000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightx:a3,righty:a5,start:b11,platform:Windows,
03000000008000000210000000000000,8BitDo F30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
030000003512000011ab000000000000,8BitDo F30 Arcade Joystick,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,
03000000c82d00001028000000000000,8BitDo F30 Arcade Joystick,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
@@ -19,14 +19,15 @@
03000000801000000900000000000000,8BitDo F30 Arcade Stick,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00001038000000000000,8BitDo F30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00001151000000000000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
+03000000c82d00000151000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000650000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00005106000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,guide:b2,leftshoulder:b8,lefttrigger:b9,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,
-03000000c82d00000151000000000000,8BitDo M30 Modkit,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,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,
+03000000c82d00000451000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightx:a3,righty:a5,start:b11,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,
03000000c82d0000e002000000000000,8BitDo N30,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b6,platform:Windows,
-03000000c82d00000451000000000000,8BitDo N30 Modkit,a:b1,b:b0,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,start:b11,platform:Windows,
03000000c82d00000190000000000000,8BitDo N30 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,
03000000c82d00001590000000000000,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:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00006528000000000000,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:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
@@ -37,7 +38,8 @@
03000000022000000090000000000000,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:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000203800000900000000000000,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:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00002038000000000000,8BitDo NES30 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,
-03000000c82d00000751000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00000751000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00000851000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000360000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000361000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000660000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
@@ -45,7 +47,7 @@
03000000c82d00000231000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000331000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000431000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,
-03000000c82d00002867000000000000,8BitDo S30 Modkit,a:b0,b:b1,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b8,lefttrigger:b9,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows,
+03000000c82d00002867000000000000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a2,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b10,x:b3,y:b4,platform:Windows,
03000000c82d00000130000000000000,8BitDo SF30,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,
03000000c82d00000060000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000061000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
@@ -54,11 +56,11 @@
03000000c82d00003028000000000000,8BitDo SFC30,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:Windows,
030000003512000020ab000000000000,8BitDo SN30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000030000000000000,8BitDo SN30,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:Windows,
+03000000c82d00000351000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a2,rightshoulder:b7,rightx:a3,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00001290000000000000,8BitDo SN30,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:Windows,
03000000c82d000020ab000000000000,8BitDo SN30,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,
03000000c82d00004028000000000000,8BitDo SN30,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,
03000000c82d00006228000000000000,8BitDo SN30,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:Windows,
-03000000c82d00000351000000000000,8BitDo SN30 Modkit,a:b1,b:b0,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
03000000c82d00000021000000000000,8BitDo SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
03000000c82d00000160000000000000,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,
03000000c82d00000161000000000000,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,
@@ -120,6 +122,7 @@
030000006b1400000103000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
03000000120c0000200e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000210e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+03000000120c0000f10e000000000000,Brook PS2 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000310c000000000000,Brook Super Converter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
03000000d81d00000b00000000000000,Buffalo BSGP1601 Series,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows,
030000005b1c00002400000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows,
@@ -234,14 +237,14 @@
030000000d0f00005100000000000000,Hori Fighting Commander PS3,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,
030000000d0f00008600000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000000d0f0000ba00000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
+030000000d0f00008800000000000000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,
+030000000d0f00008700000000000000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00001000000000000000,Hori Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00003200000000000000,Hori Fightstick 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f0000c000000000000000,Hori Fightstick 4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
030000000d0f00000d00000000000000,Hori Fightstick EX2,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
030000000d0f00003701000000000000,Hori Fightstick Mini,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Windows,
030000000d0f00004000000000000000,Hori Fightstick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,
-030000000d0f00008700000000000000,Hori Fightstick Mini 4,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,
-030000000d0f00008800000000000000,Hori Fightstick Mini 4,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows,
030000000d0f00002100000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f00002700000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
030000000d0f0000a000000000000000,Hori Grip TAC4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b13,x:b0,y:b3,platform:Windows,
@@ -439,7 +442,7 @@
03000000d9040000160f000000000000,PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows,
030000004c0500003713000000000000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
-0300000062060000d570000000000000,PowerA PS3 Contoller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
+0300000062060000d570000000000000,PowerA PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000d620000013a7000000000000,PowerA Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
030000006d04000084ca000000000000,Precision,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
03000000d62000009557000000000000,Pro Elite 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,
@@ -482,7 +485,6 @@
03000000120c00001e0e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000a957000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000aa57000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
-03000000120c0000f10e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000f21c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000f31c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000120c0000f41c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
@@ -538,7 +540,6 @@
03000000321500000910000000000000,Razer Raiju UE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
03000000321500000011000000000000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
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,
-03000000632500008005000000010000,Redgear,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,guide:b12,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:Mac OS X,
03000000921200004547000000000000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b6,x:b3,y:b4,platform:Windows,
03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
03000000830500006020000000000000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
@@ -741,11 +742,17 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000008f0e00000300000009010000,2 In 1 Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000c82d00000031000001000000,8BitDo Adapter,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:Mac OS X,
03000000c82d00000531000000020000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Mac OS X,
03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00001151000000020000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000a30c00002400000006020000,8BitDo M30,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,guide:b9,leftshoulder:b6,lefttrigger:b5,rightshoulder:b4,righttrigger:b7,start:b8,x:b3,y:b0,platform:Mac OS X,
+03000000c82d00000151000000010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform: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,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b2,leftshoulder:b6,lefttrigger:a5,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000451000000010000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform: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,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,
@@ -754,13 +761,17 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
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,
+03000000c82d00000751000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
+03000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
03000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000660000000020000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000131000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000231000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000331000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
03000000c82d00000431000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00002867000000010000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b3,y:b4,platform:Mac OS X,
03000000102800000900000000000000,8BitDo SFC30 Joystick,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
+03000000c82d00000351000000010000,8BitDo SN30,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:Mac OS X,
03000000c82d00001290000001000000,8BitDo SN30,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,
03000000c82d00004028000000010000,8BitDo SN30,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,
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,
@@ -786,6 +797,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
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 V3 Rumble Pad PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+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,
03000000791d00000103000009010000,Dual Box Wii Classic Adapter,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,
+030000006e0500000720000010020000,Elecom JC-W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Mac OS X,
030000006f0e00008401000003010000,Faceoff Premiere Wired Pro Controller for Nintendo 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:b13,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
03000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b4,paddle2:b5,paddle3:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,platform:Mac OS X,
@@ -804,6 +816,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000d0f00005e00000000010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00008400000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00008500000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00008800000000010000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
+030000000d0f00008700000000010000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00004d00000000000000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
030000000d0f00003801000008010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Mac OS X,
030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -883,6 +897,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
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,
+03000000632500008005000000010000,Redgear,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:Mac OS X,
030000000d0f0000c100000072050000,Retro Bit Sega Genesis 6B Controller,a:b2,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b8,rightshoulder:b6,righttrigger:b7,start:b9,x:b3,y:b0,platform:Mac OS X,
03000000921200004547000000020000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b2,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,lefttrigger:b14,rightshoulder:b10,righttrigger:b4,start:b12,x:b6,y:b8,platform:Mac OS X,
03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Mac OS X,
@@ -954,11 +969,16 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
# Linux
030000005e0400008e02000020010000,8BitDo Adapter,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,
03000000c82d00000031000011010000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Linux,
03000000021000000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00001151000011010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00000151000000010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00000650000011010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b3,y:b4,platform:Linux,
05000000c82d00005106000000010000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Linux,
+03000000c82d00000451000000010000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Linux,
03000000c82d00001590000011010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000008000000210000011010000,8BitDo NES30,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
@@ -968,12 +988,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d00000190000011010000,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:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000203800000900000000010000,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:Linux,
05000000c82d00002038000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00000751000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+05000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000c82d00000660000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000131000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000231000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000331000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000431000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
+03000000c82d00002867000000010000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b3,y:b4,platform:Linux,
05000000c82d00000060000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00000061000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
030000003512000012ab000010010000,8BitDo SFC30,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux,
@@ -981,6 +1004,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
03000000c82d000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
05000000102800000900000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
05000000c82d00003028000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
+05000000c82d00000351000000010000,8BitDo SN30,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,
03000000c82d00000160000000000000,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:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,
03000000c82d00000160000011010000,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,
03000000c82d00000161000000000000,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:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,
@@ -1075,9 +1099,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000d0f00005001000009040000,Hori Fighting Commander OCTA Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
030000000d0f00008500000010010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00008600000002010000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
+030000000d0f00008800000011010000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00008700000011010000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,rightstick:b11,righttrigger:a4,start:b9,x:b0,y:b3,platform:Linux,
030000000d0f00001000000011010000,Hori Fightstick 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
03000000ad1b000003f5000033050000,Hori Fightstick VX,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b8,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
-030000000d0f00004d00000011010000,HORI Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
+030000000d0f00004d00000011010000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
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,
030000000d0f00003801000011010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Linux,
030000000d0f00009200000011010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
@@ -1092,7 +1118,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000000d0f0000ee00000011010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
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,
030000000d0f0000c100000011010000,Horipad S,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
-050000000d0f0000f600000001000000,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,
+050000000d0f0000f600000001000000,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,
03000000341a000005f7000010010000,HuiJia GameCube Controller Adapter,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,
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,
@@ -1203,8 +1229,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000007e0500000620000001800000,Nintendo Switch Left Joy-Con,a:b16,b:b15,back:b4,leftshoulder:b6,leftstick:b12,leftx:a1,lefty:a0~,rightshoulder:b8,start:b9,x:b14,y:b17,platform:Linux,
03000000d620000013a7000011010000,Nintendo Switch PowerA 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,
03000000d620000011a7000011010000,Nintendo Switch PowerA Core Plus 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,
-030000007e0500000920000011810000,Nintendo Switch Pro Controller,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,
-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,
+030000007e0500000920000011810000,Nintendo Switch Pro Controller,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,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,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,misc1:b4,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
050000007e0500000920000001800000,Nintendo Switch Pro Controller,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,
050000007e0500000720000001800000,Nintendo Switch Right Joy-Con,a:b1,b:b2,back:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0,rightshoulder:b6,start:b8,x:b0,y:b3,platform:Linux,
05000000010000000100000003000000,Nintendo Wii Remote,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,
@@ -1243,14 +1269,14 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000004c0500003713000011010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
-03000000d62000000140000001010000,PowerA Fusion Pro 2 Controller,a:b0,b:b1,x:b2,y:b3,back:b6,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,
+03000000d62000000140000001010000,PowerA Fusion Pro 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
03000000c62400001a53000000010000,PowerA Mini Pro Ex,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,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,
03000000d62000000220000001010000,PowerA Xbox One Controller,a:b0,b:b1,back:b7,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:b6,x:b2,y:b3,platform:Linux,
03000000d62000000228000001010000,PowerA 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,
03000000c62400001a54000001010000,PowerA Xbox One Mini Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
-03000000d62000000240000001010000,PowerA Xbox One Spectra Infinity,a:b0,b:b1,x:b2,y:b3,back:b6,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,
+03000000d62000000240000001010000,PowerA Xbox One Spectra Infinity,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
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,
@@ -1434,6 +1460,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
060000005e040000120b00000b050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
050000005e040000130b000011050000,Xbox Series X Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
+030000005e040000120b000007050000,Xbox Series X 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,misc1:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
050000005e040000130b000007050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
03000000450c00002043000010010000,XEOX SL6556 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,
05000000172700004431000029010000,XiaoMi 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,
@@ -1449,18 +1476,30 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
61393962646434393836356631636132,8BitDo Arcade Stick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android,
64323139346131306233636562663738,8BitDo Arcade Stick,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
64643565386136613265663236636564,8BitDo Arcade Stick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android,
+33313433353539306634656436353432,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38426974446f20446f67626f6e65204d,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android,
34343439373236623466343934376233,8BitDo FC30 Pro,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b28,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b29,righttrigger:b7,start:b5,x:b30,y:b2,platform:Android,
+38393936616436383062666232653338,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f2038426974446f204c69,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+39356430616562366466646636643435,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
05000000c82d000006500000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b17,leftshoulder:b9,lefttrigger:a5,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,platform:Android,
05000000c82d000051060000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b17,leftshoulder:b9,lefttrigger:a4,rightshoulder:b10,righttrigger:a5,start:b6,x:b3,y:b2,platform:Android,
+32323161363037623637326438643634,8BitDo M30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
33656266353630643966653238646264,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,start:b10,x:b19,y:b2,platform:Android,
+38426974446f204d3330204d6f646b69,8BitDo M30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
39366630663062373237616566353437,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,start:b6,x:b2,y:b3,platform:Android,
64653533313537373934323436343563,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,start:b6,x:b2,y:b3,platform:Android,
66356438346136366337386437653934,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,start:b18,x:b19,y:b2,platform:Android,
66393064393162303732356665666366,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b2,y:b3,platform:Android,
+33663431326134333366393233616633,8BitDo N30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android,
+38426974446f204e3330204d6f646b69,8BitDo N30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android,
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,
+38313433643131656262306631373166,8BitDo P30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38326536643339353865323063616339,8BitDo P30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+38426974446f2050333020636c617373,8BitDo P30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
35376664343164386333616535333434,8BitDo Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,start:b10,x:b19,y:b2,platform:Android,
38426974446f2038426974446f205072,8BitDo Pro 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
38426974446f2050726f203200000000,8BitDo Pro 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
@@ -1468,12 +1507,17 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
38386464613034326435626130396565,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
38426974446f2038426974446f205265,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
66303230343038613365623964393766,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f20533330204d6f646b69,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
+66316462353561376330346462316137,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
05000000c82d000000600000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
05000000c82d000000610000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
38426974646f20534633302050726f00,8BitDo SF30 Pro,a:b1,b:b0,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b17,platform:Android,
61623334636338643233383735326439,8BitDo SFC30,a:b0,b:b1,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b31,start:b5,x:b30,y:b2,platform:Android,
05000000c82d000012900000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
05000000c82d000062280000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android,
+38316230613931613964356666353839,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+38426974446f20534e3330204d6f646b,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
+65323563303231646531383162646335,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android,
35383531346263653330306238353131,8BitDo SN30 PP,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
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,
36653638656632326235346264663661,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
@@ -1497,6 +1541,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
417374726f2063697479206d696e6920,Astro City Mini,a:b23,b:b22,back:b29,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,platform:Android,
32303165626138343962363666346165,Brook Mars PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
38383337343564366131323064613561,Brook Mars PS4 Controller,a:b1,b:b19,back:b17,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
+34313430343161653665353737323365,Elecom JC-W01U,a:b23,b:b24,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android,
+4875694a6961204a432d573031550000,Elecom JC-W01U,a:b23,b:b24,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android,
30363230653635633863366338623265,Evo VR,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,x:b2,y:b3,platform:Android,
05000000b404000011240000dfff3f00,Flydigi Vader 2,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
@@ -1535,6 +1581,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
6d6179666c617368206c696d69746564,Mayflash GameCube Adapter,a:b22,b:b21,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a5,righty:a2,start:b30,x:b23,y:b24,platform:Android,
436f6e74726f6c6c6572000000000000,Mayflash N64 Adapter,a:b1,b:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android,
65666330633838383061313633326461,Mayflash N64 Adapter,a:b1,b:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android,
+535a4d792d706f776572204c54442043,Mayflash Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b31,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android,
+30653962643666303631376438373532,Mayflash Wii DolphinBar,a:b23,b:b24,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b0,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android,
+484a5a204d6179666c61736820576969,Mayflash Wii DolphinBar,a:b23,b:b24,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b0,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android,
31323564663862633234646330373138,Mega Drive,a:b23,b:b22,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,platform:Android,
37333564393261653735306132613061,Mega Drive,a:b21,b:b22,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android,
64363363336633363736393038313464,Mega Drive,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Android,
@@ -1589,10 +1638,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
65366465656364636137653363376531,PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android,
66613532303965383534396638613230,PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
050000004c050000e60c0000fffe3f00,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android,
+32346465346533616263386539323932,PS5 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
32633532643734376632656664383733,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
37363764353731323963323639666565,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
61303162353165316365336436343139,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android,
-32346465346533616263386539323932,PS5 Controller,a:b0,b:b1,x:b2,y:b3,leftshoulder:b9,rightshoulder:b10,lefttrigger:a4,righttrigger:a5,guide:b5,start:b6,leftstick:b7,rightstick:b8,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,back:b15,platform:Android,
64336263393933626535303339616332,Qanba 4RAF,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android,
36626666353861663864336130363137,Razer Junglecat,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android,
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,
@@ -1669,6 +1718,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
05000000ac050000020000004f066d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,platform:iOS,
4d466947616d65706164010000000000,MFi Extended Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:iOS,
4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:iOS,
+050000007e050000062000004f060000,Nintendo Switch Joy-Con (L),+leftx:h0.1,+lefty:h0.2,-leftx:h0.4,-lefty:h0.8,dpdown:b2,dpleft:b0,dpright:b3,dpup:b1,leftshoulder:b4,misc1:b6,rightshoulder:b5,platform:iOS,
+050000007e0500000e200000df070000,Nintendo Switch Joy-Con (L/R),a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:iOS,
+050000007e050000072000004f060000,Nintendo Switch Joy-Con (R),+rightx:h0.4,+righty:h0.8,-rightx:h0.1,-righty:h0.2,a:b1,b:b0,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b3,y:b2,platform:iOS,
+050000007e05000009200000ff870000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
050000004c050000cc090000df070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
050000004c050000cc090000df870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS,
050000004c050000cc090000ff070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS,
diff --git a/core/input/godotcontrollerdb.txt b/core/input/godotcontrollerdb.txt
index 7f3570729a..b2a6160c6c 100644
--- a/core/input/godotcontrollerdb.txt
+++ b/core/input/godotcontrollerdb.txt
@@ -7,31 +7,31 @@ __XINPUT_DEVICE__,XInput Gamepad,a:b12,b:b13,x:b14,y:b15,start:b4,back:b5,leftst
# Android
Default Android Gamepad,Default Controller,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b8,rightshoulder:b10,rightx:a2,start:b6,righty:a3,dpleft:h0.8,lefttrigger:a4,x:b2,dpup:h0.1,back:b4,leftstick:b7,leftshoulder:b9,y:b3,a:b0,dpright:h0.2,righttrigger:a5,b:b1,platform:Android,
-# Javascript
-standard,Standard Gamepad Mapping,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a6,righttrigger:a7,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,leftstick:b10,rightstick:b11,dpup:b12,dpdown:b13,dpleft:b14,dpright:b15,guide:b16,leftstick:b10,rightstick:b11,platform:Javascript,
-Linux24c6581a,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:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript,
-Linux0e6f0301,Logic 3 Controller (xbox compatible),a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript,
-Linux045e028e,Microsoft X-Box 360 pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript,
-Linux045e02d1,Microsoft X-Box One pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript,
-Linux045e02ea,Microsoft X-Box One S pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript,
-Linux045e0b12,Microsoft X-Box Series X pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript,
-Linux044fb315,Thrustmaster dual analog 3.2,a:b0,b:b2,y:b3,x:b1,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Javascript,
-Linux0e8f0003,PS3 Controller,a:b2,b:b1,back:b8,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,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:Javascript,
-MacOSX24c6581a,PowerA Xbox One Cabled,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Javascript
-MacOSX045e028e,Xbox 360 Wired Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Javascript
-MacOSX045e02d1,Xbox One Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Javascript
-MacOSX045e02ea,Xbox One S Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Javascript
-MacOSX045e0b12,Xbox Series X Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Javascript
-Linux15320a14,Razer Wolverine Ultimate,a:b0,b:b1,y:b3,x:b2,start:b7,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript
-Linux05832060,iBuffalo BSGP801,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Javascript
-MacOSX05832060,iBuffalo BSGP801,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Javascript
-Linux0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Javascript
-Windows0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Javascript
-MacOSX0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a4,dpleft:-a3,dpdown:+a4,dpright:+a3,platform:Javascript
-Linux046dc216,046d-c216-Logitech Logitech Dual Action,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Javascript
-Linux20d6a713,Bensussen Deutsch & Associates Inc.(BDA) NSW Wired controller,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Javascript
-Linux054c05c4,Sony Computer Entertainment Wireless Controller,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Javascript
-Linux18d19400,18d1-9400-Google LLC Stadia Controller rev. A,a:b0,b:b1,y:b3,x:b2,start:b7,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Javascript
+# Web
+standard,Standard Gamepad Mapping,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a6,righttrigger:a7,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b8,start:b9,leftstick:b10,rightstick:b11,dpup:b12,dpdown:b13,dpleft:b14,dpright:b15,guide:b16,leftstick:b10,rightstick:b11,platform:Web,
+Linux24c6581a,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:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
+Linux0e6f0301,Logic 3 Controller (xbox compatible),a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
+Linux045e028e,Microsoft X-Box 360 pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
+Linux045e02d1,Microsoft X-Box One pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
+Linux045e02ea,Microsoft X-Box One S pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
+Linux045e0b12,Microsoft X-Box Series X pad,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web,
+Linux044fb315,Thrustmaster dual analog 3.2,a:b0,b:b2,y:b3,x:b1,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Web,
+Linux0e8f0003,PS3 Controller,a:b2,b:b1,back:b8,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,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:Web,
+MacOSX24c6581a,PowerA Xbox One Cabled,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
+MacOSX045e028e,Xbox 360 Wired Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
+MacOSX045e02d1,Xbox One Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
+MacOSX045e02ea,Xbox One S Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
+MacOSX045e0b12,Xbox Series X Controller,a:b11,b:b12,y:b14,x:b13,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpleft:b2,dpdown:b1,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Web
+Linux15320a14,Razer Wolverine Ultimate,a:b0,b:b1,y:b3,x:b2,start:b7,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web
+Linux05832060,iBuffalo BSGP801,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Web
+MacOSX05832060,iBuffalo BSGP801,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Web
+Linux0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Web
+Windows0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a1,dpleft:-a0,dpdown:+a1,dpright:+a0,platform:Web
+MacOSX0e8f3013,HuiJia USB GamePad,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftshoulder:b6,rightshoulder:b7,dpup:-a4,dpleft:-a3,dpdown:+a4,dpright:+a3,platform:Web
+Linux046dc216,046d-c216-Logitech Logitech Dual Action,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Web
+Linux20d6a713,Bensussen Deutsch & Associates Inc.(BDA) NSW Wired controller,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:-a5,dpleft:-a4,dpdown:+a5,dpright:+a4,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Web
+Linux054c05c4,Sony Computer Entertainment Wireless Controller,a:b0,b:b1,y:b2,x:b3,start:b9,back:b8,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Web
+Linux18d19400,18d1-9400-Google LLC Stadia Controller rev. A,a:b0,b:b1,y:b3,x:b2,start:b7,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:-a7,dpleft:-a6,dpdown:+a7,dpright:+a6,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,platform:Web
# UWP
__UWP_GAMEPAD__,Xbox Controller,a:b2,b:b3,x:b4,y:b5,start:b0,back:b1,leftstick:b12,rightstick:b13,leftshoulder:b10,rightshoulder:b11,dpup:b6,dpdown:b7,dpleft:b8,dpright:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:UWP,
diff --git a/core/input/input.cpp b/core/input/input.cpp
index da0c6cb62a..4e538a85ae 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -767,9 +767,6 @@ Point2i Input::warp_mouse_motion(const Ref<InputEventMouseMotion> &p_motion, con
return rel_warped;
}
-void Input::iteration(float p_step) {
-}
-
void Input::action_press(const StringName &p_action, float p_strength) {
Action action;
@@ -974,11 +971,9 @@ void Input::joy_axis(int p_device, JoyAxis p_axis, float p_value) {
if (map.type == TYPE_BUTTON) {
bool pressed = map.value > 0.5;
- if (pressed == joy_buttons_pressed.has(_combine_device((JoyButton)map.index, p_device))) {
- // Button already pressed or released; so ignore.
- return;
+ if (pressed != joy_buttons_pressed.has(_combine_device((JoyButton)map.index, p_device))) {
+ _button_event(p_device, (JoyButton)map.index, pressed);
}
- _button_event(p_device, (JoyButton)map.index, pressed);
// Ensure opposite D-Pad button is also released.
switch ((JoyButton)map.index) {
@@ -1129,7 +1124,7 @@ Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, J
value = -value;
}
if (binding.input.axis.range == FULL_AXIS ||
- (binding.input.axis.range == POSITIVE_HALF_AXIS && value > 0) ||
+ (binding.input.axis.range == POSITIVE_HALF_AXIS && value >= 0) ||
(binding.input.axis.range == NEGATIVE_HALF_AXIS && value < 0)) {
event.type = binding.outputType;
float shifted_positive_value = 0;
@@ -1187,7 +1182,7 @@ Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, J
return event;
}
-void Input::_get_mapped_hat_events(const JoyDeviceMapping &mapping, HatDir p_hat, JoyEvent r_events[]) {
+void Input::_get_mapped_hat_events(const JoyDeviceMapping &mapping, HatDir p_hat, JoyEvent r_events[(size_t)HatDir::MAX]) {
for (int i = 0; i < mapping.bindings.size(); i++) {
const JoyBinding binding = mapping.bindings[i];
if (binding.inputType == TYPE_HAT && binding.input.hat.hat == p_hat) {
diff --git a/core/input/input.h b/core/input/input.h
index 3ad8c91ddf..a07174b887 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -114,6 +114,15 @@ private:
int mouse_from_touch_index = -1;
+ struct VibrationInfo {
+ float weak_magnitude;
+ float strong_magnitude;
+ float duration; // Duration in seconds
+ uint64_t timestamp;
+ };
+
+ HashMap<int, VibrationInfo> joy_vibration;
+
struct VelocityTrack {
uint64_t last_tick = 0;
Vector2 velocity;
@@ -226,15 +235,6 @@ private:
EventDispatchFunc event_dispatch_function = nullptr;
protected:
- struct VibrationInfo {
- float weak_magnitude;
- float strong_magnitude;
- float duration; // Duration in seconds
- uint64_t timestamp;
- };
-
- HashMap<int, VibrationInfo> joy_vibration;
-
static void _bind_methods();
public:
@@ -295,8 +295,6 @@ public:
void action_press(const StringName &p_action, float p_strength = 1.f);
void action_release(const StringName &p_action);
- void iteration(float p_step);
-
void set_emulate_touch_from_mouse(bool p_emulate);
bool is_emulating_touch_from_mouse() const;
void ensure_touch_mouse_raised();
diff --git a/core/input/input_builders.py b/core/input/input_builders.py
index c0dac26f02..16f125ff38 100644
--- a/core/input/input_builders.py
+++ b/core/input/input_builders.py
@@ -50,7 +50,7 @@ def make_default_controller_mappings(target, source, env):
"Mac OS X": "#ifdef MACOS_ENABLED",
"Android": "#if defined(__ANDROID__)",
"iOS": "#ifdef IOS_ENABLED",
- "Javascript": "#ifdef JAVASCRIPT_ENABLED",
+ "Web": "#ifdef WEB_ENABLED",
"UWP": "#ifdef UWP_ENABLED",
}
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index 3c104c2c86..3f02d80c26 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -274,24 +274,24 @@ void InputEventWithModifiers::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "command_pressed"), "set_command_pressed", "is_command_pressed");
}
-void InputEventWithModifiers::_validate_property(PropertyInfo &property) const {
+void InputEventWithModifiers::_validate_property(PropertyInfo &p_property) const {
if (store_command) {
// If we only want to Store "Command".
#ifdef APPLE_STYLE_KEYS
// Don't store "Meta" on Mac.
- if (property.name == "meta_pressed") {
- property.usage ^= PROPERTY_USAGE_STORAGE;
+ if (p_property.name == "meta_pressed") {
+ p_property.usage ^= PROPERTY_USAGE_STORAGE;
}
#else
// Don't store "Ctrl".
- if (property.name == "ctrl_pressed") {
- property.usage ^= PROPERTY_USAGE_STORAGE;
+ if (p_property.name == "ctrl_pressed") {
+ p_property.usage ^= PROPERTY_USAGE_STORAGE;
}
#endif
} else {
// We don't want to store command, only ctrl or meta (on mac).
- if (property.name == "command_pressed") {
- property.usage ^= PROPERTY_USAGE_STORAGE;
+ if (p_property.name == "command_pressed") {
+ p_property.usage ^= PROPERTY_USAGE_STORAGE;
}
}
}
@@ -816,7 +816,7 @@ String InputEventMouseMotion::to_string() {
// Work around the fact vformat can only take 5 substitutions but 7 need to be passed.
String mask_and_position_and_relative = vformat("button_mask=%s, position=(%s), relative=(%s)", button_mask_string, String(get_position()), String(get_relative()));
- return vformat("InputEventMouseMotion: %s, velocity=(%s), pressure=%.2f, tilt=(%s), pen_inverted=(%d)", mask_and_position_and_relative, String(get_velocity()), get_pressure(), String(get_tilt()), get_pen_inverted());
+ return vformat("InputEventMouseMotion: %s, velocity=(%s), pressure=%.2f, tilt=(%s), pen_inverted=(%s)", mask_and_position_and_relative, String(get_velocity()), get_pressure(), String(get_tilt()), get_pen_inverted());
}
bool InputEventMouseMotion::accumulate(const Ref<InputEvent> &p_event) {
diff --git a/core/input/input_event.h b/core/input/input_event.h
index 59a2df497c..6cfc031c8a 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -128,7 +128,7 @@ class InputEventWithModifiers : public InputEventFromWindow {
protected:
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_store_command(bool p_enabled);
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index 942c5248df..702e257fb4 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -34,6 +34,7 @@
#include "core/input/input.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
+#include "core/variant/typed_array.h"
InputMap *InputMap::singleton = nullptr;
@@ -99,8 +100,8 @@ void InputMap::erase_action(const StringName &p_action) {
input_map.erase(p_action);
}
-Array InputMap::_get_actions() {
- Array ret;
+TypedArray<StringName> InputMap::_get_actions() {
+ TypedArray<StringName> ret;
List<StringName> actions = get_actions();
if (actions.is_empty()) {
return ret;
@@ -190,8 +191,8 @@ void InputMap::action_erase_events(const StringName &p_action) {
input_map[p_action].inputs.clear();
}
-Array InputMap::_action_get_events(const StringName &p_action) {
- Array ret;
+TypedArray<InputEvent> InputMap::_action_get_events(const StringName &p_action) {
+ TypedArray<InputEvent> ret;
const List<Ref<InputEvent>> *al = action_get_events(p_action);
if (al) {
for (const List<Ref<InputEvent>>::Element *E = al->front(); E; E = E->next()) {
diff --git a/core/input/input_map.h b/core/input/input_map.h
index 2400a4a3f7..414a06b2f1 100644
--- a/core/input/input_map.h
+++ b/core/input/input_map.h
@@ -36,6 +36,9 @@
#include "core/object/object.h"
#include "core/templates/hash_map.h"
+template <typename T>
+class TypedArray;
+
class InputMap : public Object {
GDCLASS(InputMap, Object);
@@ -60,8 +63,8 @@ private:
List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match = false, bool *r_pressed = nullptr, float *r_strength = nullptr, float *r_raw_strength = nullptr) const;
- Array _action_get_events(const StringName &p_action);
- Array _get_actions();
+ TypedArray<InputEvent> _action_get_events(const StringName &p_action);
+ TypedArray<StringName> _get_actions();
protected:
static void _bind_methods();
diff --git a/core/io/dir_access.cpp b/core/io/dir_access.cpp
index f82d6f077f..bed41b8d89 100644
--- a/core/io/dir_access.cpp
+++ b/core/io/dir_access.cpp
@@ -106,7 +106,7 @@ static Error _erase_recursive(DirAccess *da) {
if (err) {
return err;
}
- err = da->remove(da->get_current_dir().plus_file(E));
+ err = da->remove(da->get_current_dir().path_join(E));
if (err) {
return err;
}
@@ -116,7 +116,7 @@ static Error _erase_recursive(DirAccess *da) {
}
for (const String &E : files) {
- Error err = da->remove(da->get_current_dir().plus_file(E));
+ Error err = da->remove(da->get_current_dir().path_join(E));
if (err) {
return err;
}
@@ -138,7 +138,7 @@ Error DirAccess::make_dir_recursive(String p_dir) {
if (p_dir.is_relative_path()) {
//append current
- full_dir = get_current_dir().plus_file(p_dir);
+ full_dir = get_current_dir().path_join(p_dir);
} else {
full_dir = p_dir;
@@ -172,7 +172,7 @@ Error DirAccess::make_dir_recursive(String p_dir) {
String curpath = base;
for (int i = 0; i < subdirs.size(); i++) {
- curpath = curpath.plus_file(subdirs[i]);
+ curpath = curpath.path_join(subdirs[i]);
Error err = make_dir(curpath);
if (err != OK && err != ERR_ALREADY_EXISTS) {
ERR_FAIL_V_MSG(err, "Could not create directory: " + curpath);
@@ -354,8 +354,8 @@ Error DirAccess::_copy_dir(Ref<DirAccess> &p_target_da, String p_to, int p_chmod
String n = get_next();
while (!n.is_empty()) {
if (n != "." && n != "..") {
- if (p_copy_links && is_link(get_current_dir().plus_file(n))) {
- create_link(read_link(get_current_dir().plus_file(n)), p_to + n);
+ if (p_copy_links && is_link(get_current_dir().path_join(n))) {
+ create_link(read_link(get_current_dir().path_join(n)), p_to + n);
} else if (current_is_dir()) {
dirs.push_back(n);
} else {
@@ -364,7 +364,7 @@ Error DirAccess::_copy_dir(Ref<DirAccess> &p_target_da, String p_to, int p_chmod
list_dir_end();
return ERR_BUG;
}
- Error err = copy(get_current_dir().plus_file(n), p_to + rel_path, p_chmod_flags);
+ Error err = copy(get_current_dir().path_join(n), p_to + rel_path, p_chmod_flags);
if (err) {
list_dir_end();
return err;
diff --git a/core/io/dir_access.h b/core/io/dir_access.h
index 22017efaa3..d5318dfb45 100644
--- a/core/io/dir_access.h
+++ b/core/io/dir_access.h
@@ -108,6 +108,8 @@ public:
if (da->remove(p_path) != OK) {
ERR_FAIL_MSG("Cannot remove file or directory: " + p_path);
}
+ } else {
+ ERR_FAIL_MSG("Cannot remove non-existent file or directory: " + p_path);
}
}
diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp
index da25f23917..72c00bd678 100644
--- a/core/io/file_access.cpp
+++ b/core/io/file_access.cpp
@@ -115,6 +115,10 @@ FileAccess::CreateFunc FileAccess::get_create_func(AccessType p_access) {
return create_func[p_access];
}
+FileAccess::AccessType FileAccess::get_access_type() const {
+ return _access_type;
+}
+
String FileAccess::fix_path(const String &p_path) const {
//helper used by file accesses that use a single filesystem
@@ -377,7 +381,7 @@ uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
return i;
}
-String FileAccess::get_as_utf8_string() const {
+String FileAccess::get_as_utf8_string(bool p_skip_cr) const {
Vector<uint8_t> sourcef;
uint64_t len = get_length();
sourcef.resize(len + 1);
@@ -388,7 +392,7 @@ String FileAccess::get_as_utf8_string() const {
w[len] = 0;
String s;
- s.parse_utf8((const char *)w);
+ s.parse_utf8((const char *)w, -1, p_skip_cr);
return s;
}
diff --git a/core/io/file_access.h b/core/io/file_access.h
index e2c11142d7..fc0eb95d44 100644
--- a/core/io/file_access.h
+++ b/core/io/file_access.h
@@ -60,6 +60,7 @@ public:
virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) = 0;
protected:
+ AccessType get_access_type() const;
String fix_path(const String &p_path) const;
virtual Error _open(const String &p_path, int p_mode_flags) = 0; ///< open a file
virtual uint64_t _get_modified_time(const String &p_file) = 0;
@@ -113,7 +114,7 @@ public:
virtual String get_line() const;
virtual String get_token() const;
virtual Vector<String> get_csv_line(const String &p_delim = ",") const;
- virtual String get_as_utf8_string() const;
+ virtual String get_as_utf8_string(bool p_skip_cr = false) const;
/**
* Use this for files WRITTEN in _big_ endian machines (ie, amiga/mac)
diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h
index b8382e61d9..e41491a92c 100644
--- a/core/io/file_access_compressed.h
+++ b/core/io/file_access_compressed.h
@@ -70,29 +70,29 @@ public:
Error open_after_magic(Ref<FileAccess> p_base);
- virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual bool is_open() const; ///< true when file is open
+ virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual bool is_open() const override; ///< true when file is open
- virtual void seek(uint64_t p_position); ///< seek to a given position
- virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual uint64_t get_position() const; ///< get position in the file
- virtual uint64_t get_length() const; ///< get size of the file
+ virtual void seek(uint64_t p_position) override; ///< seek to a given position
+ virtual void seek_end(int64_t p_position = 0) override; ///< seek from the end of file
+ virtual uint64_t get_position() const override; ///< get position in the file
+ virtual uint64_t get_length() const override; ///< get size of the file
- virtual bool eof_reached() const; ///< reading passed EOF
+ virtual bool eof_reached() const override; ///< reading passed EOF
- virtual uint8_t get_8() const; ///< get a byte
- virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
+ virtual uint8_t get_8() const override; ///< get a byte
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
- virtual Error get_error() const; ///< get last error
+ virtual Error get_error() const override; ///< get last error
- virtual void flush();
- virtual void store_8(uint8_t p_dest); ///< store a byte
+ virtual void flush() override;
+ virtual void store_8(uint8_t p_dest) override; ///< store a byte
- virtual bool file_exists(const String &p_name); ///< return true if a file exists
+ virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
- virtual uint64_t _get_modified_time(const String &p_file);
- virtual uint32_t _get_unix_permissions(const String &p_file);
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions);
+ virtual uint64_t _get_modified_time(const String &p_file) override;
+ virtual uint32_t _get_unix_permissions(const String &p_file) override;
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override;
FileAccessCompressed() {}
virtual ~FileAccessCompressed();
diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h
index 0d1ee6a4d8..6200f87a7a 100644
--- a/core/io/file_access_encrypted.h
+++ b/core/io/file_access_encrypted.h
@@ -60,33 +60,33 @@ public:
Error open_and_parse(Ref<FileAccess> p_base, const Vector<uint8_t> &p_key, Mode p_mode, bool p_with_magic = true);
Error open_and_parse_password(Ref<FileAccess> p_base, const String &p_key, Mode p_mode);
- virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual bool is_open() const; ///< true when file is open
+ virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual bool is_open() const override; ///< true when file is open
- virtual String get_path() const; /// returns the path for the current open file
- virtual String get_path_absolute() const; /// returns the absolute path for the current open file
+ virtual String get_path() const override; /// returns the path for the current open file
+ virtual String get_path_absolute() const override; /// returns the absolute path for the current open file
- virtual void seek(uint64_t p_position); ///< seek to a given position
- virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual uint64_t get_position() const; ///< get position in the file
- virtual uint64_t get_length() const; ///< get size of the file
+ virtual void seek(uint64_t p_position) override; ///< seek to a given position
+ virtual void seek_end(int64_t p_position = 0) override; ///< seek from the end of file
+ virtual uint64_t get_position() const override; ///< get position in the file
+ virtual uint64_t get_length() const override; ///< get size of the file
- virtual bool eof_reached() const; ///< reading passed EOF
+ virtual bool eof_reached() const override; ///< reading passed EOF
- virtual uint8_t get_8() const; ///< get a byte
- virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
+ virtual uint8_t get_8() const override; ///< get a byte
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
- virtual Error get_error() const; ///< get last error
+ virtual Error get_error() const override; ///< get last error
- virtual void flush();
- virtual void store_8(uint8_t p_dest); ///< store a byte
- virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
+ virtual void flush() override;
+ virtual void store_8(uint8_t p_dest) override; ///< store a byte
+ virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
- virtual bool file_exists(const String &p_name); ///< return true if a file exists
+ virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
- virtual uint64_t _get_modified_time(const String &p_file);
- virtual uint32_t _get_unix_permissions(const String &p_file);
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions);
+ virtual uint64_t _get_modified_time(const String &p_file) override;
+ virtual uint32_t _get_unix_permissions(const String &p_file) override;
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override;
FileAccessEncrypted() {}
~FileAccessEncrypted();
diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h
index 868b8ed481..f2bd2aa832 100644
--- a/core/io/file_access_memory.h
+++ b/core/io/file_access_memory.h
@@ -45,31 +45,31 @@ public:
static void cleanup();
virtual Error open_custom(const uint8_t *p_data, uint64_t p_len); ///< open a file
- virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual bool is_open() const; ///< true when file is open
+ virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual bool is_open() const override; ///< true when file is open
- virtual void seek(uint64_t p_position); ///< seek to a given position
- virtual void seek_end(int64_t p_position); ///< seek from the end of file
- virtual uint64_t get_position() const; ///< get position in the file
- virtual uint64_t get_length() const; ///< get size of the file
+ virtual void seek(uint64_t p_position) override; ///< seek to a given position
+ virtual void seek_end(int64_t p_position) override; ///< seek from the end of file
+ virtual uint64_t get_position() const override; ///< get position in the file
+ virtual uint64_t get_length() const override; ///< get size of the file
- virtual bool eof_reached() const; ///< reading passed EOF
+ virtual bool eof_reached() const override; ///< reading passed EOF
- virtual uint8_t get_8() const; ///< get a byte
+ virtual uint8_t get_8() const override; ///< get a byte
- virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; ///< get an array of bytes
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override; ///< get an array of bytes
- virtual Error get_error() const; ///< get last error
+ virtual Error get_error() const override; ///< get last error
- virtual void flush();
- virtual void store_8(uint8_t p_byte); ///< store a byte
- virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
+ virtual void flush() override;
+ virtual void store_8(uint8_t p_byte) override; ///< store a byte
+ virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
- virtual bool file_exists(const String &p_name); ///< return true if a file exists
+ virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
- virtual uint64_t _get_modified_time(const String &p_file) { return 0; }
- virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; }
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; }
+ virtual uint64_t _get_modified_time(const String &p_file) override { return 0; }
+ virtual uint32_t _get_unix_permissions(const String &p_file) override { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override { return FAILED; }
FileAccessMemory() {}
};
diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h
index c7431752c0..ceadc715a1 100644
--- a/core/io/file_access_network.h
+++ b/core/io/file_access_network.h
@@ -132,29 +132,29 @@ public:
RESPONSE_GET_MODTIME,
};
- virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual bool is_open() const; ///< true when file is open
+ virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual bool is_open() const override; ///< true when file is open
- virtual void seek(uint64_t p_position); ///< seek to a given position
- virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual uint64_t get_position() const; ///< get position in the file
- virtual uint64_t get_length() const; ///< get size of the file
+ virtual void seek(uint64_t p_position) override; ///< seek to a given position
+ virtual void seek_end(int64_t p_position = 0) override; ///< seek from the end of file
+ virtual uint64_t get_position() const override; ///< get position in the file
+ virtual uint64_t get_length() const override; ///< get size of the file
- virtual bool eof_reached() const; ///< reading passed EOF
+ virtual bool eof_reached() const override; ///< reading passed EOF
- virtual uint8_t get_8() const; ///< get a byte
- virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
+ virtual uint8_t get_8() const override; ///< get a byte
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
- virtual Error get_error() const; ///< get last error
+ virtual Error get_error() const override; ///< get last error
- virtual void flush();
- virtual void store_8(uint8_t p_dest); ///< store a byte
+ virtual void flush() override;
+ virtual void store_8(uint8_t p_dest) override; ///< store a byte
- virtual bool file_exists(const String &p_path); ///< return true if a file exists
+ virtual bool file_exists(const String &p_path) override; ///< return true if a file exists
- virtual uint64_t _get_modified_time(const String &p_file);
- virtual uint32_t _get_unix_permissions(const String &p_file);
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions);
+ virtual uint64_t _get_modified_time(const String &p_file) override;
+ virtual uint32_t _get_unix_permissions(const String &p_file) override;
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override;
static void configure();
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index 595a6e9873..adae0db0f4 100644
--- a/core/io/file_access_pack.cpp
+++ b/core/io/file_access_pack.cpp
@@ -520,7 +520,7 @@ String DirAccessPack::get_current_dir(bool p_include_drive) const {
while (pd->parent) {
pd = pd->parent;
- p = pd->name.plus_file(p);
+ p = pd->name.path_join(p);
}
return "res://" + p;
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index e656f6b885..023758ac0f 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -148,35 +148,35 @@ class FileAccessPack : public FileAccess {
uint64_t off;
Ref<FileAccess> f;
- virtual Error _open(const String &p_path, int p_mode_flags);
- virtual uint64_t _get_modified_time(const String &p_file) { return 0; }
- virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; }
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; }
+ virtual Error _open(const String &p_path, int p_mode_flags) override;
+ virtual uint64_t _get_modified_time(const String &p_file) override { return 0; }
+ virtual uint32_t _get_unix_permissions(const String &p_file) override { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override { return FAILED; }
public:
- virtual bool is_open() const;
+ virtual bool is_open() const override;
- virtual void seek(uint64_t p_position);
- virtual void seek_end(int64_t p_position = 0);
- virtual uint64_t get_position() const;
- virtual uint64_t get_length() const;
+ virtual void seek(uint64_t p_position) override;
+ virtual void seek_end(int64_t p_position = 0) override;
+ virtual uint64_t get_position() const override;
+ virtual uint64_t get_length() const override;
- virtual bool eof_reached() const;
+ virtual bool eof_reached() const override;
- virtual uint8_t get_8() const;
+ virtual uint8_t get_8() const override;
- virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
- virtual void set_big_endian(bool p_big_endian);
+ virtual void set_big_endian(bool p_big_endian) override;
- virtual Error get_error() const;
+ virtual Error get_error() const override;
- virtual void flush();
- virtual void store_8(uint8_t p_dest);
+ virtual void flush() override;
+ virtual void store_8(uint8_t p_dest) override;
- virtual void store_buffer(const uint8_t *p_src, uint64_t p_length);
+ virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override;
- virtual bool file_exists(const String &p_name);
+ virtual bool file_exists(const String &p_name) override;
FileAccessPack(const String &p_path, const PackedData::PackedFile &p_file);
};
@@ -217,33 +217,33 @@ class DirAccessPack : public DirAccess {
PackedData::PackedDir *_find_dir(String p_dir);
public:
- virtual Error list_dir_begin();
- virtual String get_next();
- virtual bool current_is_dir() const;
- virtual bool current_is_hidden() const;
- virtual void list_dir_end();
+ virtual Error list_dir_begin() override;
+ virtual String get_next() override;
+ virtual bool current_is_dir() const override;
+ virtual bool current_is_hidden() const override;
+ virtual void list_dir_end() override;
- virtual int get_drive_count();
- virtual String get_drive(int p_drive);
+ virtual int get_drive_count() override;
+ virtual String get_drive(int p_drive) override;
- virtual Error change_dir(String p_dir);
- virtual String get_current_dir(bool p_include_drive = true) const;
+ virtual Error change_dir(String p_dir) override;
+ virtual String get_current_dir(bool p_include_drive = true) const override;
- virtual bool file_exists(String p_file);
- virtual bool dir_exists(String p_dir);
+ virtual bool file_exists(String p_file) override;
+ virtual bool dir_exists(String p_dir) override;
- virtual Error make_dir(String p_dir);
+ virtual Error make_dir(String p_dir) override;
- virtual Error rename(String p_from, String p_to);
- virtual Error remove(String p_name);
+ virtual Error rename(String p_from, String p_to) override;
+ virtual Error remove(String p_name) override;
- uint64_t get_space_left();
+ uint64_t get_space_left() override;
- virtual bool is_link(String p_file) { return false; }
- virtual String read_link(String p_file) { return p_file; }
- virtual Error create_link(String p_source, String p_target) { return FAILED; }
+ virtual bool is_link(String p_file) override { return false; }
+ virtual String read_link(String p_file) override { return p_file; }
+ virtual Error create_link(String p_source, String p_target) override { return FAILED; }
- virtual String get_filesystem_type() const;
+ virtual String get_filesystem_type() const override;
DirAccessPack();
};
diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h
index 6ea603546a..74a48192f3 100644
--- a/core/io/file_access_zip.h
+++ b/core/io/file_access_zip.h
@@ -85,29 +85,29 @@ class FileAccessZip : public FileAccess {
void _close();
public:
- virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual bool is_open() const; ///< true when file is open
+ virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual bool is_open() const override; ///< true when file is open
- virtual void seek(uint64_t p_position); ///< seek to a given position
- virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual uint64_t get_position() const; ///< get position in the file
- virtual uint64_t get_length() const; ///< get size of the file
+ virtual void seek(uint64_t p_position) override; ///< seek to a given position
+ virtual void seek_end(int64_t p_position = 0) override; ///< seek from the end of file
+ virtual uint64_t get_position() const override; ///< get position in the file
+ virtual uint64_t get_length() const override; ///< get size of the file
- virtual bool eof_reached() const; ///< reading passed EOF
+ virtual bool eof_reached() const override; ///< reading passed EOF
- virtual uint8_t get_8() const; ///< get a byte
- virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
+ virtual uint8_t get_8() const override; ///< get a byte
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
- virtual Error get_error() const; ///< get last error
+ virtual Error get_error() const override; ///< get last error
- virtual void flush();
- virtual void store_8(uint8_t p_dest); ///< store a byte
+ virtual void flush() override;
+ virtual void store_8(uint8_t p_dest) override; ///< store a byte
- virtual bool file_exists(const String &p_name); ///< return true if a file exists
+ virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
- virtual uint64_t _get_modified_time(const String &p_file) { return 0; } // todo
- virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; }
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; }
+ virtual uint64_t _get_modified_time(const String &p_file) override { return 0; } // todo
+ virtual uint32_t _get_unix_permissions(const String &p_file) override { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override { return FAILED; }
FileAccessZip(const String &p_path, const PackedData::PackedFile &p_file);
~FileAccessZip();
diff --git a/core/io/http_client_tcp.cpp b/core/io/http_client_tcp.cpp
index d983d86b99..9499a6f8e3 100644
--- a/core/io/http_client_tcp.cpp
+++ b/core/io/http_client_tcp.cpp
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef JAVASCRIPT_ENABLED
+#ifndef WEB_ENABLED
#include "http_client_tcp.h"
@@ -788,4 +788,4 @@ HTTPClientTCP::HTTPClientTCP() {
HTTPClient *(*HTTPClient::_create)() = HTTPClientTCP::_create_func;
-#endif // #ifndef JAVASCRIPT_ENABLED
+#endif // WEB_ENABLED
diff --git a/core/io/image.cpp b/core/io/image.cpp
index 0f20aabd7e..2d87523ca4 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -416,8 +416,8 @@ int Image::get_height() const {
return height;
}
-Vector2 Image::get_size() const {
- return Vector2(width, height);
+Vector2i Image::get_size() const {
+ return Vector2i(width, height);
}
bool Image::has_mipmaps() const {
diff --git a/core/io/image.h b/core/io/image.h
index 46820a4c08..9d415423be 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -209,7 +209,7 @@ private:
public:
int get_width() const; ///< Get image width
int get_height() const; ///< Get image height
- Vector2 get_size() const;
+ Vector2i get_size() const;
bool has_mipmaps() const;
int get_mipmap_count() const;
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
index 9cf7c9caba..d09697b951 100644
--- a/core/io/image_loader.cpp
+++ b/core/io/image_loader.cpp
@@ -44,7 +44,7 @@ bool ImageFormatLoader::recognize(const String &p_extension) const {
return false;
}
-Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom, bool p_force_linear, float p_scale) {
+Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom, uint32_t p_flags, float p_scale) {
ERR_FAIL_COND_V_MSG(p_image.is_null(), ERR_INVALID_PARAMETER, "It's not a reference to a valid Image object.");
Ref<FileAccess> f = p_custom;
@@ -60,7 +60,7 @@ Error ImageLoader::load_image(String p_file, Ref<Image> p_image, Ref<FileAccess>
if (!loader[i]->recognize(extension)) {
continue;
}
- Error err = loader[i]->load_image(p_image, f, p_force_linear, p_scale);
+ Error err = loader[i]->load_image(p_image, f, p_flags, p_scale);
if (err != OK) {
ERR_PRINT("Error loading image: " + p_file);
}
@@ -152,7 +152,7 @@ Ref<Resource> ResourceFormatLoaderImage::load(const String &p_path, const String
Ref<Image> image;
image.instantiate();
- Error err = ImageLoader::loader[idx]->load_image(image, f, false, 1.0);
+ Error err = ImageLoader::loader[idx]->load_image(image, f);
if (err != OK) {
if (r_error) {
diff --git a/core/io/image_loader.h b/core/io/image_loader.h
index c91d382c25..cb64d2310e 100644
--- a/core/io/image_loader.h
+++ b/core/io/image_loader.h
@@ -44,11 +44,16 @@ class ImageFormatLoader {
friend class ResourceFormatLoaderImage;
protected:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, bool p_force_linear, float p_scale) = 0;
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, uint32_t p_flags = (uint32_t)FLAG_NONE, float p_scale = 1.0) = 0;
virtual void get_recognized_extensions(List<String> *p_extensions) const = 0;
bool recognize(const String &p_extension) const;
public:
+ enum LoaderFlags {
+ FLAG_NONE = 0,
+ FLAG_FORCE_LINEAR = 1,
+ };
+
virtual ~ImageFormatLoader() {}
};
@@ -58,7 +63,7 @@ class ImageLoader {
protected:
public:
- static Error load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom = Ref<FileAccess>(), bool p_force_linear = false, float p_scale = 1.0);
+ static Error load_image(String p_file, Ref<Image> p_image, Ref<FileAccess> p_custom = Ref<FileAccess>(), uint32_t p_flags = (uint32_t)ImageFormatLoader::FLAG_NONE, float p_scale = 1.0);
static void get_recognized_extensions(List<String> *p_extensions);
static ImageFormatLoader *recognize(const String &p_extension);
diff --git a/core/io/ip.cpp b/core/io/ip.cpp
index 25e3bef5fc..a4d8dc3d5b 100644
--- a/core/io/ip.cpp
+++ b/core/io/ip.cpp
@@ -33,6 +33,7 @@
#include "core/os/semaphore.h"
#include "core/os/thread.h"
#include "core/templates/hash_map.h"
+#include "core/variant/typed_array.h"
VARIANT_ENUM_CAST(IP::ResolverStatus);
@@ -124,11 +125,11 @@ struct _IP_ResolverPrivate {
};
IPAddress IP::resolve_hostname(const String &p_hostname, IP::Type p_type) {
- const Array addresses = resolve_hostname_addresses(p_hostname, p_type);
- return addresses.size() ? addresses[0].operator IPAddress() : IPAddress();
+ const PackedStringArray addresses = resolve_hostname_addresses(p_hostname, p_type);
+ return addresses.size() ? (IPAddress)addresses[0] : IPAddress();
}
-Array IP::resolve_hostname_addresses(const String &p_hostname, Type p_type) {
+PackedStringArray IP::resolve_hostname_addresses(const String &p_hostname, Type p_type) {
List<IPAddress> res;
String key = _IP_ResolverPrivate::get_cache_key(p_hostname, p_type);
@@ -148,7 +149,7 @@ Array IP::resolve_hostname_addresses(const String &p_hostname, Type p_type) {
}
resolver->mutex.unlock();
- Array result;
+ PackedStringArray result;
for (int i = 0; i < res.size(); ++i) {
result.push_back(String(res[i]));
}
@@ -254,8 +255,8 @@ void IP::clear_cache(const String &p_hostname) {
}
}
-Array IP::_get_local_addresses() const {
- Array addresses;
+PackedStringArray IP::_get_local_addresses() const {
+ PackedStringArray addresses;
List<IPAddress> ip_addresses;
get_local_addresses(&ip_addresses);
for (const IPAddress &E : ip_addresses) {
@@ -265,8 +266,8 @@ Array IP::_get_local_addresses() const {
return addresses;
}
-Array IP::_get_local_interfaces() const {
- Array results;
+TypedArray<Dictionary> IP::_get_local_interfaces() const {
+ TypedArray<Dictionary> results;
HashMap<String, Interface_Info> interfaces;
get_local_interfaces(&interfaces);
for (KeyValue<String, Interface_Info> &E : interfaces) {
diff --git a/core/io/ip.h b/core/io/ip.h
index 4d83515e2b..f2d93a454d 100644
--- a/core/io/ip.h
+++ b/core/io/ip.h
@@ -34,6 +34,9 @@
#include "core/io/ip_address.h"
#include "core/os/os.h"
+template <typename T>
+class TypedArray;
+
struct _IP_ResolverPrivate;
class IP : public Object {
@@ -68,8 +71,8 @@ protected:
static IP *singleton;
static void _bind_methods();
- Array _get_local_addresses() const;
- Array _get_local_interfaces() const;
+ PackedStringArray _get_local_addresses() const;
+ TypedArray<Dictionary> _get_local_interfaces() const;
static IP *(*_create)();
@@ -82,7 +85,7 @@ public:
};
IPAddress resolve_hostname(const String &p_hostname, Type p_type = TYPE_ANY);
- Array resolve_hostname_addresses(const String &p_hostname, Type p_type = TYPE_ANY);
+ PackedStringArray resolve_hostname_addresses(const String &p_hostname, Type p_type = TYPE_ANY);
// async resolver hostname
ResolverID resolve_hostname_queue_item(const String &p_hostname, Type p_type = TYPE_ANY);
ResolverStatus get_resolve_item_status(ResolverID p_id) const;
diff --git a/core/io/json.cpp b/core/io/json.cpp
index 4c4d91f851..91500ff3d5 100644
--- a/core/io/json.cpp
+++ b/core/io/json.cpp
@@ -528,11 +528,6 @@ Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_st
return err;
}
-String JSON::stringify(const Variant &p_var, const String &p_indent, bool p_sort_keys, bool p_full_precision) {
- HashSet<const void *> markers;
- return _stringify(p_var, p_indent, 0, p_sort_keys, markers, p_full_precision);
-}
-
Error JSON::parse(const String &p_json_string) {
Error err = _parse_string(p_json_string, data, err_str, err_line);
if (err == Error::OK) {
@@ -541,8 +536,24 @@ Error JSON::parse(const String &p_json_string) {
return err;
}
+String JSON::stringify(const Variant &p_var, const String &p_indent, bool p_sort_keys, bool p_full_precision) {
+ Ref<JSON> jason;
+ jason.instantiate();
+ HashSet<const void *> markers;
+ return jason->_stringify(p_var, p_indent, 0, p_sort_keys, markers, p_full_precision);
+}
+
+Variant JSON::parse_string(const String &p_json_string) {
+ Ref<JSON> jason;
+ jason.instantiate();
+ Error error = jason->parse(p_json_string);
+ ERR_FAIL_COND_V_MSG(error != Error::OK, Variant(), vformat("Parse JSON failed. Error at line %d: %s", jason->get_error_line(), jason->get_error_message()));
+ return jason->get_data();
+}
+
void JSON::_bind_methods() {
- ClassDB::bind_method(D_METHOD("stringify", "data", "indent", "sort_keys", "full_precision"), &JSON::stringify, DEFVAL(""), DEFVAL(true), DEFVAL(false));
+ ClassDB::bind_static_method("JSON", D_METHOD("stringify", "data", "indent", "sort_keys", "full_precision"), &JSON::stringify, DEFVAL(""), DEFVAL(true), DEFVAL(false));
+ ClassDB::bind_static_method("JSON", D_METHOD("parse_string", "json_string"), &JSON::parse_string);
ClassDB::bind_method(D_METHOD("parse", "json_string"), &JSON::parse);
ClassDB::bind_method(D_METHOD("get_data"), &JSON::get_data);
diff --git a/core/io/json.h b/core/io/json.h
index 6ba0a8c76b..840b1cc08a 100644
--- a/core/io/json.h
+++ b/core/io/json.h
@@ -81,8 +81,9 @@ protected:
static void _bind_methods();
public:
- String stringify(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true, bool p_full_precision = false);
Error parse(const String &p_json_string);
+ static String stringify(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true, bool p_full_precision = false);
+ static Variant parse_string(const String &p_json_string);
inline Variant get_data() const { return data; }
inline int get_error_line() const { return err_line; }
diff --git a/core/io/logger.cpp b/core/io/logger.cpp
index 5820ec0c09..b0f74f8db5 100644
--- a/core/io/logger.cpp
+++ b/core/io/logger.cpp
@@ -31,6 +31,7 @@
#include "logger.h"
#include "core/config/project_settings.h"
+#include "core/core_globals.h"
#include "core/io/dir_access.h"
#include "core/os/os.h"
#include "core/os/time.h"
@@ -41,7 +42,7 @@
#endif
bool Logger::should_log(bool p_err) {
- return (!p_err || _print_error_enabled) && (p_err || _print_line_enabled);
+ return (!p_err || CoreGlobals::print_error_enabled) && (p_err || CoreGlobals::print_line_enabled);
}
bool Logger::_flush_stdout_on_print = true;
diff --git a/core/io/packed_data_container.cpp b/core/io/packed_data_container.cpp
index a456318148..2dcb86cbc6 100644
--- a/core/io/packed_data_container.cpp
+++ b/core/io/packed_data_container.cpp
@@ -353,7 +353,7 @@ Variant PackedDataContainer::_iter_get(const Variant &p_iter) {
}
void PackedDataContainer::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_set_data"), &PackedDataContainer::_set_data);
+ ClassDB::bind_method(D_METHOD("_set_data", "data"), &PackedDataContainer::_set_data);
ClassDB::bind_method(D_METHOD("_get_data"), &PackedDataContainer::_get_data);
ClassDB::bind_method(D_METHOD("_iter_init"), &PackedDataContainer::_iter_init);
ClassDB::bind_method(D_METHOD("_iter_get"), &PackedDataContainer::_iter_get);
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index fec5ca5c7b..d117f86f39 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -543,43 +543,3 @@ int ResourceCache::get_cached_resource_count() {
return rc;
}
-
-void ResourceCache::dump(const char *p_file, bool p_short) {
-#ifdef DEBUG_ENABLED
- lock.lock();
-
- HashMap<String, int> type_count;
-
- Ref<FileAccess> f;
- if (p_file) {
- f = FileAccess::open(String::utf8(p_file), FileAccess::WRITE);
- ERR_FAIL_COND_MSG(f.is_null(), "Cannot create file at path '" + String::utf8(p_file) + "'.");
- }
-
- for (KeyValue<String, Resource *> &E : resources) {
- Resource *r = E.value;
-
- if (!type_count.has(r->get_class())) {
- type_count[r->get_class()] = 0;
- }
-
- type_count[r->get_class()]++;
-
- if (!p_short) {
- if (f.is_valid()) {
- f->store_line(r->get_class() + ": " + r->get_path());
- }
- }
- }
-
- for (const KeyValue<String, int> &E : type_count) {
- if (f.is_valid()) {
- f->store_line(E.key + " count: " + itos(E.value));
- }
- }
-
- lock.unlock();
-#else
- WARN_PRINT("ResourceCache::dump only with in debug builds.");
-#endif
-}
diff --git a/core/io/resource.h b/core/io/resource.h
index a2cde87990..a76a3920be 100644
--- a/core/io/resource.h
+++ b/core/io/resource.h
@@ -167,7 +167,6 @@ public:
static void reload_externals();
static bool has(const String &p_path);
static Ref<Resource> get_ref(const String &p_path);
- static void dump(const char *p_file = nullptr, bool p_short = false);
static void get_cached_resources(List<Ref<Resource>> *p_resources);
static int get_cached_resource_count();
};
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index b731608b4f..4f1204fc48 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -421,7 +421,7 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
if (!path.contains("://") && path.is_relative_path()) {
// path is relative to file being loaded, so convert to a resource path
- path = ProjectSettings::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path));
+ path = ProjectSettings::get_singleton()->localize_path(res_path.get_base_dir().path_join(path));
}
if (remaps.find(path)) {
@@ -683,7 +683,7 @@ Error ResourceLoaderBinary::load() {
if (!path.contains("://") && path.is_relative_path()) {
// path is relative to file being loaded, so convert to a resource path
- path = ProjectSettings::get_singleton()->localize_path(path.get_base_dir().plus_file(external_resources[i].path));
+ path = ProjectSettings::get_singleton()->localize_path(path.get_base_dir().path_join(external_resources[i].path));
}
external_resources.write[i].path = path; //remap happens here, not on load because on load it can actually be used for filesystem dock resource remap
@@ -1329,7 +1329,7 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
bool relative = false;
if (!path.begins_with("res://")) {
- path = local_path.plus_file(path).simplify_path();
+ path = local_path.path_join(path).simplify_path();
relative = true;
}
diff --git a/core/io/resource_importer.cpp b/core/io/resource_importer.cpp
index e059fc842b..aa7f96a047 100644
--- a/core/io/resource_importer.cpp
+++ b/core/io/resource_importer.cpp
@@ -421,7 +421,7 @@ Ref<ResourceImporter> ResourceFormatImporter::get_importer_by_extension(const St
}
String ResourceFormatImporter::get_import_base_path(const String &p_for_file) const {
- return ProjectSettings::get_singleton()->get_imported_files_path().plus_file(p_for_file.get_file() + "-" + p_for_file.md5_text());
+ return ProjectSettings::get_singleton()->get_imported_files_path().path_join(p_for_file.get_file() + "-" + p_for_file.md5_text());
}
bool ResourceFormatImporter::are_import_settings_valid(const String &p_path) const {
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index fc4177004b..eccb397e2e 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -794,6 +794,8 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem
// To find the path of the remapped resource, we extract the locale name after
// the last ':' to match the project locale.
+ // An extra remap may still be necessary afterwards due to the text -> binary converter on export.
+
String locale = TranslationServer::get_singleton()->get_locale();
ERR_FAIL_COND_V_MSG(locale.length() < 2, p_path, "Could not remap path '" + p_path + "' for translation as configured locale '" + locale + "' is invalid.");
@@ -819,16 +821,20 @@ String ResourceLoader::_path_remap(const String &p_path, bool *r_translation_rem
if (r_translation_remapped) {
*r_translation_remapped = true;
}
+
+ // Fallback to p_path if new_path does not exist.
+ if (!FileAccess::exists(new_path)) {
+ WARN_PRINT(vformat("Translation remap '%s' does not exist. Falling back to '%s'.", new_path, p_path));
+ new_path = p_path;
+ }
}
if (path_remaps.has(new_path)) {
new_path = path_remaps[new_path];
- }
-
- if (new_path == p_path) { // Did not remap.
+ } else {
// Try file remap.
Error err;
- Ref<FileAccess> f = FileAccess::open(p_path + ".remap", FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(new_path + ".remap", FileAccess::READ, &err);
if (f.is_valid()) {
VariantParser::StreamFile stream;
stream.f = f;
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
index 274316f058..386ccb78e9 100644
--- a/core/io/resource_saver.cpp
+++ b/core/io/resource_saver.cpp
@@ -70,7 +70,7 @@ void ResourceFormatSaver::get_recognized_extensions(const Ref<Resource> &p_resou
}
void ResourceFormatSaver::_bind_methods() {
- GDVIRTUAL_BIND(_save, "path", "resource", "flags");
+ GDVIRTUAL_BIND(_save, "resource", "path", "flags");
GDVIRTUAL_BIND(_recognize, "resource");
GDVIRTUAL_BIND(_get_recognized_extensions, "resource");
}
diff --git a/core/io/resource_uid.cpp b/core/io/resource_uid.cpp
index fc324a26da..5324c5dd84 100644
--- a/core/io/resource_uid.cpp
+++ b/core/io/resource_uid.cpp
@@ -39,7 +39,7 @@ static constexpr uint32_t char_count = ('z' - 'a');
static constexpr uint32_t base = char_count + ('9' - '0');
String ResourceUID::get_cache_file() {
- return ProjectSettings::get_singleton()->get_project_data_path().plus_file("uid_cache.bin");
+ return ProjectSettings::get_singleton()->get_project_data_path().path_join("uid_cache.bin");
}
String ResourceUID::id_to_text(ID p_id) const {
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp
index 41a0848d01..b4281820e2 100644
--- a/core/math/a_star.cpp
+++ b/core/math/a_star.cpp
@@ -209,8 +209,8 @@ bool AStar3D::has_point(int64_t p_id) const {
return points.has(p_id);
}
-Array AStar3D::get_point_ids() {
- Array point_list;
+PackedInt64Array AStar3D::get_point_ids() {
+ PackedInt64Array point_list;
for (OAHashMap<int64_t, Point *>::Iterator it = points.iter(); it.valid; it = points.next_iter(it)) {
point_list.push_back(*(it.key));
@@ -605,7 +605,7 @@ Vector<int64_t> AStar2D::get_point_connections(int64_t p_id) {
return astar.get_point_connections(p_id);
}
-Array AStar2D::get_point_ids() {
+PackedInt64Array AStar2D::get_point_ids() {
return astar.get_point_ids();
}
diff --git a/core/math/a_star.h b/core/math/a_star.h
index c1497d133f..a9e2a62bb2 100644
--- a/core/math/a_star.h
+++ b/core/math/a_star.h
@@ -133,7 +133,7 @@ public:
void remove_point(int64_t p_id);
bool has_point(int64_t p_id) const;
Vector<int64_t> get_point_connections(int64_t p_id);
- Array get_point_ids();
+ PackedInt64Array get_point_ids();
void set_point_disabled(int64_t p_id, bool p_disabled = true);
bool is_point_disabled(int64_t p_id) const;
@@ -183,7 +183,7 @@ public:
void remove_point(int64_t p_id);
bool has_point(int64_t p_id) const;
Vector<int64_t> get_point_connections(int64_t p_id);
- Array get_point_ids();
+ PackedInt64Array get_point_ids();
void set_point_disabled(int64_t p_id, bool p_disabled = true);
bool is_point_disabled(int64_t p_id) const;
diff --git a/core/math/audio_frame.h b/core/math/audio_frame.h
index b3d63c0094..1a80faaa12 100644
--- a/core/math/audio_frame.h
+++ b/core/math/audio_frame.h
@@ -48,7 +48,7 @@ static inline float undenormalise(volatile float f) {
}
static const float AUDIO_PEAK_OFFSET = 0.0000000001f;
-static const float AUDIO_MIN_PEAK_DB = -200.0f; // linear2db(AUDIO_PEAK_OFFSET)
+static const float AUDIO_MIN_PEAK_DB = -200.0f; // linear_to_db(AUDIO_PEAK_OFFSET)
struct AudioFrame {
//left and right samples
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index f8e7c47107..bc50d0e64c 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -749,67 +749,6 @@ Quaternion Basis::get_quaternion() const {
return Quaternion(temp[0], temp[1], temp[2], temp[3]);
}
-static const Basis _ortho_bases[24] = {
- Basis(1, 0, 0, 0, 1, 0, 0, 0, 1),
- Basis(0, -1, 0, 1, 0, 0, 0, 0, 1),
- Basis(-1, 0, 0, 0, -1, 0, 0, 0, 1),
- Basis(0, 1, 0, -1, 0, 0, 0, 0, 1),
- Basis(1, 0, 0, 0, 0, -1, 0, 1, 0),
- Basis(0, 0, 1, 1, 0, 0, 0, 1, 0),
- Basis(-1, 0, 0, 0, 0, 1, 0, 1, 0),
- Basis(0, 0, -1, -1, 0, 0, 0, 1, 0),
- Basis(1, 0, 0, 0, -1, 0, 0, 0, -1),
- Basis(0, 1, 0, 1, 0, 0, 0, 0, -1),
- Basis(-1, 0, 0, 0, 1, 0, 0, 0, -1),
- Basis(0, -1, 0, -1, 0, 0, 0, 0, -1),
- Basis(1, 0, 0, 0, 0, 1, 0, -1, 0),
- Basis(0, 0, -1, 1, 0, 0, 0, -1, 0),
- Basis(-1, 0, 0, 0, 0, -1, 0, -1, 0),
- Basis(0, 0, 1, -1, 0, 0, 0, -1, 0),
- Basis(0, 0, 1, 0, 1, 0, -1, 0, 0),
- Basis(0, -1, 0, 0, 0, 1, -1, 0, 0),
- Basis(0, 0, -1, 0, -1, 0, -1, 0, 0),
- Basis(0, 1, 0, 0, 0, -1, -1, 0, 0),
- Basis(0, 0, 1, 0, -1, 0, 1, 0, 0),
- Basis(0, 1, 0, 0, 0, 1, 1, 0, 0),
- Basis(0, 0, -1, 0, 1, 0, 1, 0, 0),
- Basis(0, -1, 0, 0, 0, -1, 1, 0, 0)
-};
-
-int Basis::get_orthogonal_index() const {
- //could be sped up if i come up with a way
- Basis orth = *this;
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- real_t v = orth[i][j];
- if (v > 0.5f) {
- v = 1.0f;
- } else if (v < -0.5f) {
- v = -1.0f;
- } else {
- v = 0;
- }
-
- orth[i][j] = v;
- }
- }
-
- for (int i = 0; i < 24; i++) {
- if (_ortho_bases[i] == orth) {
- return i;
- }
- }
-
- return 0;
-}
-
-void Basis::set_orthogonal_index(int p_index) {
- //there only exist 24 orthogonal bases in r3
- ERR_FAIL_INDEX(p_index, 24);
-
- *this = _ortho_bases[p_index];
-}
-
void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
/* checking this is a bad idea, because obtaining from scaled transform is a valid use case
#ifdef MATH_CHECKS
diff --git a/core/math/basis.h b/core/math/basis.h
index 4be325cdd2..2853947ba7 100644
--- a/core/math/basis.h
+++ b/core/math/basis.h
@@ -149,9 +149,6 @@ struct _NO_DISCARD_ Basis {
_FORCE_INLINE_ void operator*=(const real_t p_val);
_FORCE_INLINE_ Basis operator*(const real_t p_val) const;
- int get_orthogonal_index() const;
- void set_orthogonal_index(int p_index);
-
bool is_orthogonal() const;
bool is_diagonal() const;
bool is_rotation() const;
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 53deb9bd42..cae76b182a 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -229,11 +229,11 @@ public:
return value;
}
- static _ALWAYS_INLINE_ double deg2rad(double p_y) { return p_y * (Math_PI / 180.0); }
- static _ALWAYS_INLINE_ float deg2rad(float p_y) { return p_y * (float)(Math_PI / 180.0); }
+ static _ALWAYS_INLINE_ double deg_to_rad(double p_y) { return p_y * (Math_PI / 180.0); }
+ static _ALWAYS_INLINE_ float deg_to_rad(float p_y) { return p_y * (float)(Math_PI / 180.0); }
- static _ALWAYS_INLINE_ double rad2deg(double p_y) { return p_y * (180.0 / Math_PI); }
- static _ALWAYS_INLINE_ float rad2deg(float p_y) { return p_y * (float)(180.0 / Math_PI); }
+ static _ALWAYS_INLINE_ double rad_to_deg(double p_y) { return p_y * (180.0 / Math_PI); }
+ static _ALWAYS_INLINE_ float rad_to_deg(float p_y) { return p_y * (float)(180.0 / Math_PI); }
static _ALWAYS_INLINE_ double lerp(double p_from, double p_to, double p_weight) { return p_from + (p_to - p_from) * p_weight; }
static _ALWAYS_INLINE_ float lerp(float p_from, float p_to, float p_weight) { return p_from + (p_to - p_from) * p_weight; }
@@ -253,6 +253,89 @@ public:
(-p_pre + 3.0f * p_from - 3.0f * p_to + p_post) * (p_weight * p_weight * p_weight));
}
+ static _ALWAYS_INLINE_ double cubic_interpolate_angle(double p_from, double p_to, double p_pre, double p_post, double p_weight) {
+ double from_rot = fmod(p_from, Math_TAU);
+
+ double pre_diff = fmod(p_pre - from_rot, Math_TAU);
+ double pre_rot = from_rot + fmod(2.0 * pre_diff, Math_TAU) - pre_diff;
+
+ double to_diff = fmod(p_to - from_rot, Math_TAU);
+ double to_rot = from_rot + fmod(2.0 * to_diff, Math_TAU) - to_diff;
+
+ double post_diff = fmod(p_post - to_rot, Math_TAU);
+ double post_rot = to_rot + fmod(2.0 * post_diff, Math_TAU) - post_diff;
+
+ return cubic_interpolate(from_rot, to_rot, pre_rot, post_rot, p_weight);
+ }
+ static _ALWAYS_INLINE_ float cubic_interpolate_angle(float p_from, float p_to, float p_pre, float p_post, float p_weight) {
+ float from_rot = fmod(p_from, (float)Math_TAU);
+
+ float pre_diff = fmod(p_pre - from_rot, (float)Math_TAU);
+ float pre_rot = from_rot + fmod(2.0f * pre_diff, (float)Math_TAU) - pre_diff;
+
+ float to_diff = fmod(p_to - from_rot, (float)Math_TAU);
+ float to_rot = from_rot + fmod(2.0f * to_diff, (float)Math_TAU) - to_diff;
+
+ float post_diff = fmod(p_post - to_rot, (float)Math_TAU);
+ float post_rot = to_rot + fmod(2.0f * post_diff, (float)Math_TAU) - post_diff;
+
+ return cubic_interpolate(from_rot, to_rot, pre_rot, post_rot, p_weight);
+ }
+
+ static _ALWAYS_INLINE_ double cubic_interpolate_in_time(double p_from, double p_to, double p_pre, double p_post, double p_weight,
+ double p_to_t, double p_pre_t, double p_post_t) {
+ /* Barry-Goldman method */
+ double t = Math::lerp(0.0, p_to_t, p_weight);
+ double a1 = Math::lerp(p_pre, p_from, p_pre_t == 0 ? 0.0 : (t - p_pre_t) / -p_pre_t);
+ double a2 = Math::lerp(p_from, p_to, p_to_t == 0 ? 0.5 : t / p_to_t);
+ double a3 = Math::lerp(p_to, p_post, p_post_t - p_to_t == 0 ? 1.0 : (t - p_to_t) / (p_post_t - p_to_t));
+ double b1 = Math::lerp(a1, a2, p_to_t - p_pre_t == 0 ? 0.0 : (t - p_pre_t) / (p_to_t - p_pre_t));
+ double b2 = Math::lerp(a2, a3, p_post_t == 0 ? 1.0 : t / p_post_t);
+ return Math::lerp(b1, b2, p_to_t == 0 ? 0.5 : t / p_to_t);
+ }
+ static _ALWAYS_INLINE_ float cubic_interpolate_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight,
+ float p_to_t, float p_pre_t, float p_post_t) {
+ /* Barry-Goldman method */
+ float t = Math::lerp(0.0f, p_to_t, p_weight);
+ float a1 = Math::lerp(p_pre, p_from, p_pre_t == 0 ? 0.0f : (t - p_pre_t) / -p_pre_t);
+ float a2 = Math::lerp(p_from, p_to, p_to_t == 0 ? 0.5f : t / p_to_t);
+ float a3 = Math::lerp(p_to, p_post, p_post_t - p_to_t == 0 ? 1.0f : (t - p_to_t) / (p_post_t - p_to_t));
+ float b1 = Math::lerp(a1, a2, p_to_t - p_pre_t == 0 ? 0.0f : (t - p_pre_t) / (p_to_t - p_pre_t));
+ float b2 = Math::lerp(a2, a3, p_post_t == 0 ? 1.0f : t / p_post_t);
+ return Math::lerp(b1, b2, p_to_t == 0 ? 0.5f : t / p_to_t);
+ }
+
+ static _ALWAYS_INLINE_ double cubic_interpolate_angle_in_time(double p_from, double p_to, double p_pre, double p_post, double p_weight,
+ double p_to_t, double p_pre_t, double p_post_t) {
+ double from_rot = fmod(p_from, Math_TAU);
+
+ double pre_diff = fmod(p_pre - from_rot, Math_TAU);
+ double pre_rot = from_rot + fmod(2.0 * pre_diff, Math_TAU) - pre_diff;
+
+ double to_diff = fmod(p_to - from_rot, Math_TAU);
+ double to_rot = from_rot + fmod(2.0 * to_diff, Math_TAU) - to_diff;
+
+ double post_diff = fmod(p_post - to_rot, Math_TAU);
+ double post_rot = to_rot + fmod(2.0 * post_diff, Math_TAU) - post_diff;
+
+ return cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t);
+ }
+ static _ALWAYS_INLINE_ float cubic_interpolate_angle_in_time(float p_from, float p_to, float p_pre, float p_post, float p_weight,
+ float p_to_t, float p_pre_t, float p_post_t) {
+ float from_rot = fmod(p_from, (float)Math_TAU);
+
+ float pre_diff = fmod(p_pre - from_rot, (float)Math_TAU);
+ float pre_rot = from_rot + fmod(2.0f * pre_diff, (float)Math_TAU) - pre_diff;
+
+ float to_diff = fmod(p_to - from_rot, (float)Math_TAU);
+ float to_rot = from_rot + fmod(2.0f * to_diff, (float)Math_TAU) - to_diff;
+
+ float post_diff = fmod(p_post - to_rot, (float)Math_TAU);
+ float post_rot = to_rot + fmod(2.0f * post_diff, (float)Math_TAU) - post_diff;
+
+ return cubic_interpolate_in_time(from_rot, to_rot, pre_rot, post_rot, p_weight, p_to_t, p_pre_t, p_post_t);
+ }
+
static _ALWAYS_INLINE_ double bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) {
/* Formula from Wikipedia article on Bezier curves. */
double omt = (1.0 - p_t);
@@ -308,11 +391,11 @@ public:
static _ALWAYS_INLINE_ double move_toward(double p_from, double p_to, double p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; }
static _ALWAYS_INLINE_ float move_toward(float p_from, float p_to, float p_delta) { return abs(p_to - p_from) <= p_delta ? p_to : p_from + SIGN(p_to - p_from) * p_delta; }
- static _ALWAYS_INLINE_ double linear2db(double p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; }
- static _ALWAYS_INLINE_ float linear2db(float p_linear) { return Math::log(p_linear) * (float)8.6858896380650365530225783783321; }
+ static _ALWAYS_INLINE_ double linear_to_db(double p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; }
+ static _ALWAYS_INLINE_ float linear_to_db(float p_linear) { return Math::log(p_linear) * (float)8.6858896380650365530225783783321; }
- static _ALWAYS_INLINE_ double db2linear(double p_db) { return Math::exp(p_db * 0.11512925464970228420089957273422); }
- static _ALWAYS_INLINE_ float db2linear(float p_db) { return Math::exp(p_db * (float)0.11512925464970228420089957273422); }
+ static _ALWAYS_INLINE_ double db_to_linear(double p_db) { return Math::exp(p_db * 0.11512925464970228420089957273422); }
+ static _ALWAYS_INLINE_ float db_to_linear(float p_db) { return Math::exp(p_db * (float)0.11512925464970228420089957273422); }
static _ALWAYS_INLINE_ double round(double p_val) { return ::round(p_val); }
static _ALWAYS_INLINE_ float round(float p_val) { return ::roundf(p_val); }
diff --git a/core/math/projection.cpp b/core/math/projection.cpp
index edf8bf36cd..863fe6ee79 100644
--- a/core/math/projection.cpp
+++ b/core/math/projection.cpp
@@ -255,7 +255,7 @@ void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t
}
real_t sine, cotangent, deltaZ;
- real_t radians = Math::deg2rad(p_fovy_degrees / 2.0);
+ real_t radians = Math::deg_to_rad(p_fovy_degrees / 2.0);
deltaZ = p_z_far - p_z_near;
sine = Math::sin(radians);
@@ -282,7 +282,7 @@ void Projection::set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t
real_t left, right, modeltranslation, ymax, xmax, frustumshift;
- ymax = p_z_near * tan(Math::deg2rad(p_fovy_degrees / 2.0));
+ ymax = p_z_near * tan(Math::deg_to_rad(p_fovy_degrees / 2.0));
xmax = ymax * p_aspect;
frustumshift = (p_intraocular_dist / 2.0) * p_z_near / p_convergence_dist;
@@ -816,7 +816,7 @@ real_t Projection::get_fov() const {
right_plane.normalize();
if ((matrix[8] == 0) && (matrix[9] == 0)) {
- return Math::rad2deg(Math::acos(Math::abs(right_plane.normal.x))) * 2.0;
+ return Math::rad_to_deg(Math::acos(Math::abs(right_plane.normal.x))) * 2.0;
} else {
// our frustum is asymmetrical need to calculate the left planes angle separately..
Plane left_plane = Plane(matrix[3] + matrix[0],
@@ -825,7 +825,7 @@ real_t Projection::get_fov() const {
matrix[15] + matrix[12]);
left_plane.normalize();
- return Math::rad2deg(Math::acos(Math::abs(left_plane.normal.x))) + Math::rad2deg(Math::acos(Math::abs(right_plane.normal.x)));
+ return Math::rad_to_deg(Math::acos(Math::abs(left_plane.normal.x))) + Math::rad_to_deg(Math::acos(Math::abs(right_plane.normal.x)));
}
}
diff --git a/core/math/projection.h b/core/math/projection.h
index a3d2d7720b..f149d307b3 100644
--- a/core/math/projection.h
+++ b/core/math/projection.h
@@ -96,7 +96,7 @@ struct Projection {
Projection jitter_offseted(const Vector2 &p_offset) const;
static real_t get_fovy(real_t p_fovx, real_t p_aspect) {
- return Math::rad2deg(Math::atan(p_aspect * Math::tan(Math::deg2rad(p_fovx) * 0.5)) * 2.0);
+ return Math::rad_to_deg(Math::atan(p_aspect * Math::tan(Math::deg_to_rad(p_fovx) * 0.5)) * 2.0);
}
real_t get_z_far() const;
diff --git a/core/math/quaternion.cpp b/core/math/quaternion.cpp
index c681c60694..c836a82e37 100644
--- a/core/math/quaternion.cpp
+++ b/core/math/quaternion.cpp
@@ -112,10 +112,11 @@ Quaternion Quaternion::exp() const {
Quaternion src = *this;
Vector3 src_v = Vector3(src.x, src.y, src.z);
real_t theta = src_v.length();
- if (theta < CMP_EPSILON) {
+ src_v = src_v.normalized();
+ if (theta < CMP_EPSILON || !src_v.is_normalized()) {
return Quaternion(0, 0, 0, 1);
}
- return Quaternion(src_v.normalized(), theta);
+ return Quaternion(src_v, theta);
}
Quaternion Quaternion::slerp(const Quaternion &p_to, const real_t &p_weight) const {
@@ -233,6 +234,57 @@ Quaternion Quaternion::spherical_cubic_interpolate(const Quaternion &p_b, const
return q1.slerp(q2, p_weight);
}
+Quaternion Quaternion::spherical_cubic_interpolate_in_time(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight,
+ const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const {
+#ifdef MATH_CHECKS
+ ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized.");
+ ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quaternion(), "The end quaternion must be normalized.");
+#endif
+ Quaternion from_q = *this;
+ Quaternion pre_q = p_pre_a;
+ Quaternion to_q = p_b;
+ Quaternion post_q = p_post_b;
+
+ // Align flip phases.
+ from_q = Basis(from_q).get_rotation_quaternion();
+ pre_q = Basis(pre_q).get_rotation_quaternion();
+ to_q = Basis(to_q).get_rotation_quaternion();
+ post_q = Basis(post_q).get_rotation_quaternion();
+
+ // Flip quaternions to shortest path if necessary.
+ bool flip1 = signbit(from_q.dot(pre_q));
+ pre_q = flip1 ? -pre_q : pre_q;
+ bool flip2 = signbit(from_q.dot(to_q));
+ to_q = flip2 ? -to_q : to_q;
+ bool flip3 = flip2 ? to_q.dot(post_q) <= 0 : signbit(to_q.dot(post_q));
+ post_q = flip3 ? -post_q : post_q;
+
+ // Calc by Expmap in from_q space.
+ Quaternion ln_from = Quaternion(0, 0, 0, 0);
+ Quaternion ln_to = (from_q.inverse() * to_q).log();
+ Quaternion ln_pre = (from_q.inverse() * pre_q).log();
+ Quaternion ln_post = (from_q.inverse() * post_q).log();
+ Quaternion ln = Quaternion(0, 0, 0, 0);
+ ln.x = Math::cubic_interpolate_in_time(ln_from.x, ln_to.x, ln_pre.x, ln_post.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ ln.y = Math::cubic_interpolate_in_time(ln_from.y, ln_to.y, ln_pre.y, ln_post.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ ln.z = Math::cubic_interpolate_in_time(ln_from.z, ln_to.z, ln_pre.z, ln_post.z, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ Quaternion q1 = from_q * ln.exp();
+
+ // Calc by Expmap in to_q space.
+ ln_from = (to_q.inverse() * from_q).log();
+ ln_to = Quaternion(0, 0, 0, 0);
+ ln_pre = (to_q.inverse() * pre_q).log();
+ ln_post = (to_q.inverse() * post_q).log();
+ ln = Quaternion(0, 0, 0, 0);
+ ln.x = Math::cubic_interpolate_in_time(ln_from.x, ln_to.x, ln_pre.x, ln_post.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ ln.y = Math::cubic_interpolate_in_time(ln_from.y, ln_to.y, ln_pre.y, ln_post.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ ln.z = Math::cubic_interpolate_in_time(ln_from.z, ln_to.z, ln_pre.z, ln_post.z, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ Quaternion q2 = to_q * ln.exp();
+
+ // To cancel error made by Expmap ambiguity, do blends.
+ return q1.slerp(q2, p_weight);
+}
+
Quaternion::operator String() const {
return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ", " + String::num_real(w, false) + ")";
}
diff --git a/core/math/quaternion.h b/core/math/quaternion.h
index cb54a6f540..43d7bffcfc 100644
--- a/core/math/quaternion.h
+++ b/core/math/quaternion.h
@@ -72,6 +72,7 @@ struct _NO_DISCARD_ Quaternion {
Quaternion slerp(const Quaternion &p_to, const real_t &p_weight) const;
Quaternion slerpni(const Quaternion &p_to, const real_t &p_weight) const;
Quaternion spherical_cubic_interpolate(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const;
+ Quaternion spherical_cubic_interpolate_in_time(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const;
Vector3 get_axis() const;
real_t get_angle() const;
diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp
index bb8bf9f569..226076029b 100644
--- a/core/math/transform_2d.cpp
+++ b/core/math/transform_2d.cpp
@@ -217,34 +217,48 @@ Transform2D Transform2D::operator*(const Transform2D &p_transform) const {
return t;
}
-Transform2D Transform2D::scaled(const Size2 &p_scale) const {
+Transform2D Transform2D::basis_scaled(const Size2 &p_scale) const {
Transform2D copy = *this;
- copy.scale(p_scale);
+ copy.scale_basis(p_scale);
return copy;
}
-Transform2D Transform2D::basis_scaled(const Size2 &p_scale) const {
+Transform2D Transform2D::scaled(const Size2 &p_scale) const {
+ // Equivalent to left multiplication
Transform2D copy = *this;
- copy.scale_basis(p_scale);
+ copy.scale(p_scale);
return copy;
}
+Transform2D Transform2D::scaled_local(const Size2 &p_scale) const {
+ // Equivalent to right multiplication
+ return Transform2D(columns[0] * p_scale.x, columns[1] * p_scale.y, columns[2]);
+}
+
Transform2D Transform2D::untranslated() const {
Transform2D copy = *this;
copy.columns[2] = Vector2();
return copy;
}
+Transform2D Transform2D::translated(const Vector2 &p_offset) const {
+ // Equivalent to left multiplication
+ return Transform2D(columns[0], columns[1], columns[2] + p_offset);
+}
+
Transform2D Transform2D::translated_local(const Vector2 &p_offset) const {
- Transform2D copy = *this;
- copy.translate_local(p_offset);
- return copy;
+ // Equivalent to right multiplication
+ return Transform2D(columns[0], columns[1], columns[2] + basis_xform(p_offset));
}
Transform2D Transform2D::rotated(const real_t p_angle) const {
- Transform2D copy = *this;
- copy.rotate(p_angle);
- return copy;
+ // Equivalent to left multiplication
+ return Transform2D(p_angle, Vector2()) * (*this);
+}
+
+Transform2D Transform2D::rotated_local(const real_t p_angle) const {
+ // Equivalent to right multiplication
+ return (*this) * Transform2D(p_angle, Vector2()); // Could be optimized, because origin transform can be skipped.
}
real_t Transform2D::basis_determinant() const {
diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h
index e64d050f0c..f23f32867a 100644
--- a/core/math/transform_2d.h
+++ b/core/math/transform_2d.h
@@ -85,10 +85,13 @@ struct _NO_DISCARD_ Transform2D {
_FORCE_INLINE_ const Vector2 &get_origin() const { return columns[2]; }
_FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { columns[2] = p_origin; }
- Transform2D scaled(const Size2 &p_scale) const;
Transform2D basis_scaled(const Size2 &p_scale) const;
+ Transform2D scaled(const Size2 &p_scale) const;
+ Transform2D scaled_local(const Size2 &p_scale) const;
+ Transform2D translated(const Vector2 &p_offset) const;
Transform2D translated_local(const Vector2 &p_offset) const;
Transform2D rotated(const real_t p_angle) const;
+ Transform2D rotated_local(const real_t p_angle) const;
Transform2D untranslated() const;
diff --git a/core/math/transform_3d.cpp b/core/math/transform_3d.cpp
index c497a276f3..a634faca9a 100644
--- a/core/math/transform_3d.cpp
+++ b/core/math/transform_3d.cpp
@@ -62,7 +62,15 @@ void Transform3D::rotate(const Vector3 &p_axis, real_t p_angle) {
}
Transform3D Transform3D::rotated(const Vector3 &p_axis, real_t p_angle) const {
- return Transform3D(Basis(p_axis, p_angle), Vector3()) * (*this);
+ // Equivalent to left multiplication
+ Basis p_basis(p_axis, p_angle);
+ return Transform3D(p_basis * basis, p_basis.xform(origin));
+}
+
+Transform3D Transform3D::rotated_local(const Vector3 &p_axis, real_t p_angle) const {
+ // Equivalent to right multiplication
+ Basis p_basis(p_axis, p_angle);
+ return Transform3D(basis * p_basis, origin);
}
void Transform3D::rotate_basis(const Vector3 &p_axis, real_t p_angle) {
@@ -120,9 +128,13 @@ void Transform3D::scale(const Vector3 &p_scale) {
}
Transform3D Transform3D::scaled(const Vector3 &p_scale) const {
- Transform3D t = *this;
- t.scale(p_scale);
- return t;
+ // Equivalent to left multiplication
+ return Transform3D(basis.scaled(p_scale), origin * p_scale);
+}
+
+Transform3D Transform3D::scaled_local(const Vector3 &p_scale) const {
+ // Equivalent to right multiplication
+ return Transform3D(basis.scaled_local(p_scale), origin);
}
void Transform3D::scale_basis(const Vector3 &p_scale) {
@@ -139,10 +151,14 @@ void Transform3D::translate_local(const Vector3 &p_translation) {
}
}
+Transform3D Transform3D::translated(const Vector3 &p_translation) const {
+ // Equivalent to left multiplication
+ return Transform3D(basis, origin + p_translation);
+}
+
Transform3D Transform3D::translated_local(const Vector3 &p_translation) const {
- Transform3D t = *this;
- t.translate_local(p_translation);
- return t;
+ // Equivalent to right multiplication
+ return Transform3D(basis, origin + basis.xform(p_translation));
}
void Transform3D::orthonormalize() {
diff --git a/core/math/transform_3d.h b/core/math/transform_3d.h
index 1f8026043f..b572e90859 100644
--- a/core/math/transform_3d.h
+++ b/core/math/transform_3d.h
@@ -46,6 +46,7 @@ struct _NO_DISCARD_ Transform3D {
Transform3D affine_inverse() const;
Transform3D rotated(const Vector3 &p_axis, real_t p_angle) const;
+ Transform3D rotated_local(const Vector3 &p_axis, real_t p_angle) const;
void rotate(const Vector3 &p_axis, real_t p_angle);
void rotate_basis(const Vector3 &p_axis, real_t p_angle);
@@ -55,9 +56,11 @@ struct _NO_DISCARD_ Transform3D {
void scale(const Vector3 &p_scale);
Transform3D scaled(const Vector3 &p_scale) const;
+ Transform3D scaled_local(const Vector3 &p_scale) const;
void scale_basis(const Vector3 &p_scale);
void translate_local(real_t p_tx, real_t p_ty, real_t p_tz);
void translate_local(const Vector3 &p_translation);
+ Transform3D translated(const Vector3 &p_translation) const;
Transform3D translated_local(const Vector3 &p_translation) const;
const Basis &get_basis() const { return basis; }
diff --git a/core/math/vector2.h b/core/math/vector2.h
index 91d3d3a56b..caa6b226e7 100644
--- a/core/math/vector2.h
+++ b/core/math/vector2.h
@@ -114,6 +114,7 @@ struct _NO_DISCARD_ Vector2 {
_FORCE_INLINE_ Vector2 lerp(const Vector2 &p_to, const real_t p_weight) const;
_FORCE_INLINE_ Vector2 slerp(const Vector2 &p_to, const real_t p_weight) const;
_FORCE_INLINE_ Vector2 cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight) const;
+ _FORCE_INLINE_ Vector2 cubic_interpolate_in_time(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const;
_FORCE_INLINE_ Vector2 bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const;
Vector2 move_toward(const Vector2 &p_to, const real_t p_delta) const;
@@ -270,6 +271,13 @@ Vector2 Vector2::cubic_interpolate(const Vector2 &p_b, const Vector2 &p_pre_a, c
return res;
}
+Vector2 Vector2::cubic_interpolate_in_time(const Vector2 &p_b, const Vector2 &p_pre_a, const Vector2 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const {
+ Vector2 res = *this;
+ res.x = Math::cubic_interpolate_in_time(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ res.y = Math::cubic_interpolate_in_time(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ return res;
+}
+
Vector2 Vector2::bezier_interpolate(const Vector2 &p_control_1, const Vector2 &p_control_2, const Vector2 &p_end, const real_t p_t) const {
Vector2 res = *this;
diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp
index d71d365053..fdbbb8cb5c 100644
--- a/core/math/vector3.cpp
+++ b/core/math/vector3.cpp
@@ -117,6 +117,22 @@ Vector3 Vector3::octahedron_decode(const Vector2 &p_oct) {
return n.normalized();
}
+Vector2 Vector3::octahedron_tangent_encode(const float sign) const {
+ Vector2 res = this->octahedron_encode();
+ res.y = res.y * 0.5f + 0.5f;
+ res.y = sign >= 0.0f ? res.y : 1 - res.y;
+ return res;
+}
+
+Vector3 Vector3::octahedron_tangent_decode(const Vector2 &p_oct, float *sign) {
+ Vector2 oct_compressed = p_oct;
+ oct_compressed.y = oct_compressed.y * 2 - 1;
+ *sign = oct_compressed.y >= 0.0f ? 1.0f : -1.0f;
+ oct_compressed.y = Math::abs(oct_compressed.y);
+ Vector3 res = Vector3::octahedron_decode(oct_compressed);
+ return res;
+}
+
Basis Vector3::outer(const Vector3 &p_with) const {
Vector3 row0(x * p_with.x, x * p_with.y, x * p_with.z);
Vector3 row1(y * p_with.x, y * p_with.y, y * p_with.z);
diff --git a/core/math/vector3.h b/core/math/vector3.h
index 970416234d..7cae6e2481 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -105,12 +105,15 @@ struct _NO_DISCARD_ Vector3 {
_FORCE_INLINE_ Vector3 lerp(const Vector3 &p_to, const real_t p_weight) const;
_FORCE_INLINE_ Vector3 slerp(const Vector3 &p_to, const real_t p_weight) const;
_FORCE_INLINE_ Vector3 cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const;
+ _FORCE_INLINE_ Vector3 cubic_interpolate_in_time(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const;
_FORCE_INLINE_ Vector3 bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const;
Vector3 move_toward(const Vector3 &p_to, const real_t p_delta) const;
Vector2 octahedron_encode() const;
static Vector3 octahedron_decode(const Vector2 &p_oct);
+ Vector2 octahedron_tangent_encode(const float sign) const;
+ static Vector3 octahedron_tangent_decode(const Vector2 &p_oct, float *sign);
_FORCE_INLINE_ Vector3 cross(const Vector3 &p_with) const;
_FORCE_INLINE_ real_t dot(const Vector3 &p_with) const;
@@ -217,16 +220,25 @@ Vector3 Vector3::lerp(const Vector3 &p_to, const real_t p_weight) const {
}
Vector3 Vector3::slerp(const Vector3 &p_to, const real_t p_weight) const {
+ // This method seems more complicated than it really is, since we write out
+ // the internals of some methods for efficiency (mainly, checking length).
real_t start_length_sq = length_squared();
real_t end_length_sq = p_to.length_squared();
if (unlikely(start_length_sq == 0.0f || end_length_sq == 0.0f)) {
// Zero length vectors have no angle, so the best we can do is either lerp or throw an error.
return lerp(p_to, p_weight);
}
+ Vector3 axis = cross(p_to);
+ real_t axis_length_sq = axis.length_squared();
+ if (unlikely(axis_length_sq == 0.0f)) {
+ // Colinear vectors have no rotation axis or angle between them, so the best we can do is lerp.
+ return lerp(p_to, p_weight);
+ }
+ axis /= Math::sqrt(axis_length_sq);
real_t start_length = Math::sqrt(start_length_sq);
real_t result_length = Math::lerp(start_length, Math::sqrt(end_length_sq), p_weight);
real_t angle = angle_to(p_to);
- return rotated(cross(p_to).normalized(), angle * p_weight) * (result_length / start_length);
+ return rotated(axis, angle * p_weight) * (result_length / start_length);
}
Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight) const {
@@ -237,6 +249,14 @@ Vector3 Vector3::cubic_interpolate(const Vector3 &p_b, const Vector3 &p_pre_a, c
return res;
}
+Vector3 Vector3::cubic_interpolate_in_time(const Vector3 &p_b, const Vector3 &p_pre_a, const Vector3 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const {
+ Vector3 res = *this;
+ res.x = Math::cubic_interpolate_in_time(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ res.y = Math::cubic_interpolate_in_time(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ res.z = Math::cubic_interpolate_in_time(res.z, p_b.z, p_pre_a.z, p_post_b.z, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ return res;
+}
+
Vector3 Vector3::bezier_interpolate(const Vector3 &p_control_1, const Vector3 &p_control_2, const Vector3 &p_end, const real_t p_t) const {
Vector3 res = *this;
diff --git a/core/math/vector4.cpp b/core/math/vector4.cpp
index ed42d8bfb9..273a111891 100644
--- a/core/math/vector4.cpp
+++ b/core/math/vector4.cpp
@@ -33,6 +33,40 @@
#include "core/math/basis.h"
#include "core/string/print_string.h"
+void Vector4::set_axis(const int p_axis, const real_t p_value) {
+ ERR_FAIL_INDEX(p_axis, 4);
+ components[p_axis] = p_value;
+}
+
+real_t Vector4::get_axis(const int p_axis) const {
+ ERR_FAIL_INDEX_V(p_axis, 4, 0);
+ return operator[](p_axis);
+}
+
+Vector4::Axis Vector4::min_axis_index() const {
+ uint32_t min_index = 0;
+ real_t min_value = x;
+ for (uint32_t i = 1; i < 4; i++) {
+ if (operator[](i) <= min_value) {
+ min_index = i;
+ min_value = operator[](i);
+ }
+ }
+ return Vector4::Axis(min_index);
+}
+
+Vector4::Axis Vector4::max_axis_index() const {
+ uint32_t max_index = 0;
+ real_t max_value = x;
+ for (uint32_t i = 1; i < 4; i++) {
+ if (operator[](i) > max_value) {
+ max_index = i;
+ max_value = operator[](i);
+ }
+ }
+ return Vector4::Axis(max_index);
+}
+
bool Vector4::is_equal_approx(const Vector4 &p_vec4) const {
return Math::is_equal_approx(x, p_vec4.x) && Math::is_equal_approx(y, p_vec4.y) && Math::is_equal_approx(z, p_vec4.z) && Math::is_equal_approx(w, p_vec4.w);
}
@@ -53,6 +87,20 @@ bool Vector4::is_normalized() const {
return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON); // Use less epsilon.
}
+real_t Vector4::distance_to(const Vector4 &p_to) const {
+ return (p_to - *this).length();
+}
+
+real_t Vector4::distance_squared_to(const Vector4 &p_to) const {
+ return (p_to - *this).length_squared();
+}
+
+Vector4 Vector4::direction_to(const Vector4 &p_to) const {
+ Vector4 ret(p_to.x - x, p_to.y - y, p_to.z - z, p_to.w - w);
+ ret.normalize();
+ return ret;
+}
+
Vector4 Vector4::abs() const {
return Vector4(Math::abs(x), Math::abs(y), Math::abs(z), Math::abs(w));
}
@@ -81,32 +129,47 @@ Vector4 Vector4::lerp(const Vector4 &p_to, const real_t p_weight) const {
w + (p_weight * (p_to.w - w)));
}
-Vector4 Vector4::inverse() const {
- return Vector4(1.0f / x, 1.0f / y, 1.0f / z, 1.0f / w);
+Vector4 Vector4::cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight) const {
+ Vector4 res = *this;
+ res.x = Math::cubic_interpolate(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight);
+ res.y = Math::cubic_interpolate(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight);
+ res.z = Math::cubic_interpolate(res.z, p_b.z, p_pre_a.z, p_post_b.z, p_weight);
+ res.w = Math::cubic_interpolate(res.w, p_b.w, p_pre_a.w, p_post_b.w, p_weight);
+ return res;
}
-Vector4::Axis Vector4::min_axis_index() const {
- uint32_t min_index = 0;
- real_t min_value = x;
- for (uint32_t i = 1; i < 4; i++) {
- if (operator[](i) < min_value) {
- min_index = i;
- min_value = operator[](i);
- }
- }
- return Vector4::Axis(min_index);
+Vector4 Vector4::cubic_interpolate_in_time(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const {
+ Vector4 res = *this;
+ res.x = Math::cubic_interpolate_in_time(res.x, p_b.x, p_pre_a.x, p_post_b.x, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ res.y = Math::cubic_interpolate_in_time(res.y, p_b.y, p_pre_a.y, p_post_b.y, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ res.z = Math::cubic_interpolate_in_time(res.z, p_b.z, p_pre_a.z, p_post_b.z, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ res.w = Math::cubic_interpolate_in_time(res.w, p_b.w, p_pre_a.w, p_post_b.w, p_weight, p_b_t, p_pre_a_t, p_post_b_t);
+ return res;
}
-Vector4::Axis Vector4::max_axis_index() const {
- uint32_t max_index = 0;
- real_t max_value = x;
- for (uint32_t i = 1; i < 4; i++) {
- if (operator[](i) > max_value) {
- max_index = i;
- max_value = operator[](i);
- }
- }
- return Vector4::Axis(max_index);
+Vector4 Vector4::posmod(const real_t p_mod) const {
+ return Vector4(Math::fposmod(x, p_mod), Math::fposmod(y, p_mod), Math::fposmod(z, p_mod), Math::fposmod(w, p_mod));
+}
+
+Vector4 Vector4::posmodv(const Vector4 &p_modv) const {
+ return Vector4(Math::fposmod(x, p_modv.x), Math::fposmod(y, p_modv.y), Math::fposmod(z, p_modv.z), Math::fposmod(w, p_modv.w));
+}
+
+void Vector4::snap(const Vector4 &p_step) {
+ x = Math::snapped(x, p_step.x);
+ y = Math::snapped(y, p_step.y);
+ z = Math::snapped(z, p_step.z);
+ w = Math::snapped(w, p_step.w);
+}
+
+Vector4 Vector4::snapped(const Vector4 &p_step) const {
+ Vector4 v = *this;
+ v.snap(p_step);
+ return v;
+}
+
+Vector4 Vector4::inverse() const {
+ return Vector4(1.0f / x, 1.0f / y, 1.0f / z, 1.0f / w);
}
Vector4 Vector4::clamp(const Vector4 &p_min, const Vector4 &p_max) const {
diff --git a/core/math/vector4.h b/core/math/vector4.h
index 37ddb509d6..17d0de18e1 100644
--- a/core/math/vector4.h
+++ b/core/math/vector4.h
@@ -62,6 +62,15 @@ struct _NO_DISCARD_ Vector4 {
DEV_ASSERT((unsigned int)p_axis < 4);
return components[p_axis];
}
+
+ _FORCE_INLINE_ void set_all(const real_t p_value);
+
+ void set_axis(const int p_axis, const real_t p_value);
+ real_t get_axis(const int p_axis) const;
+
+ Vector4::Axis min_axis_index() const;
+ Vector4::Axis max_axis_index() const;
+
_FORCE_INLINE_ real_t length_squared() const;
bool is_equal_approx(const Vector4 &p_vec4) const;
real_t length() const;
@@ -69,15 +78,23 @@ struct _NO_DISCARD_ Vector4 {
Vector4 normalized() const;
bool is_normalized() const;
+ real_t distance_to(const Vector4 &p_to) const;
+ real_t distance_squared_to(const Vector4 &p_to) const;
+ Vector4 direction_to(const Vector4 &p_to) const;
+
Vector4 abs() const;
Vector4 sign() const;
Vector4 floor() const;
Vector4 ceil() const;
Vector4 round() const;
Vector4 lerp(const Vector4 &p_to, const real_t p_weight) const;
+ Vector4 cubic_interpolate(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight) const;
+ Vector4 cubic_interpolate_in_time(const Vector4 &p_b, const Vector4 &p_pre_a, const Vector4 &p_post_b, const real_t p_weight, const real_t &p_b_t, const real_t &p_pre_a_t, const real_t &p_post_b_t) const;
- Vector4::Axis min_axis_index() const;
- Vector4::Axis max_axis_index() const;
+ Vector4 posmod(const real_t p_mod) const;
+ Vector4 posmodv(const Vector4 &p_modv) const;
+ void snap(const Vector4 &p_step);
+ Vector4 snapped(const Vector4 &p_step) const;
Vector4 clamp(const Vector4 &p_min, const Vector4 &p_max) const;
Vector4 inverse() const;
@@ -130,6 +147,10 @@ struct _NO_DISCARD_ Vector4 {
}
};
+void Vector4::set_all(const real_t p_value) {
+ x = y = z = p_value;
+}
+
real_t Vector4::dot(const Vector4 &p_vec4) const {
return x * p_vec4.x + y * p_vec4.y + z * p_vec4.z + w * p_vec4.w;
}
@@ -193,7 +214,7 @@ Vector4 Vector4::operator/(const Vector4 &p_vec4) const {
}
Vector4 Vector4::operator-() const {
- return Vector4(x, y, z, w);
+ return Vector4(-x, -y, -z, -w);
}
Vector4 Vector4::operator*(const real_t &s) const {
diff --git a/core/math/vector4i.cpp b/core/math/vector4i.cpp
index 8c571b02e3..2dc5b74202 100644
--- a/core/math/vector4i.cpp
+++ b/core/math/vector4i.cpp
@@ -47,7 +47,7 @@ Vector4i::Axis Vector4i::min_axis_index() const {
uint32_t min_index = 0;
int32_t min_value = x;
for (uint32_t i = 1; i < 4; i++) {
- if (operator[](i) < min_value) {
+ if (operator[](i) <= min_value) {
min_index = i;
min_value = operator[](i);
}
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index d67315f20d..99b20560da 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -963,8 +963,11 @@ void ClassDB::add_linked_property(const StringName &p_class, const String &p_pro
ERR_FAIL_COND(!type->property_map.has(p_property));
ERR_FAIL_COND(!type->property_map.has(p_linked_property));
- PropertyInfo &pinfo = type->property_map[p_property];
- pinfo.linked_properties.push_back(p_linked_property);
+ if (!type->linked_properties.has(p_property)) {
+ type->linked_properties.insert(p_property, List<StringName>());
+ }
+ type->linked_properties[p_property].push_back(p_linked_property);
+
#endif
}
@@ -978,7 +981,7 @@ void ClassDB::get_property_list(const StringName &p_class, List<PropertyInfo> *p
if (p_validator) {
// Making a copy as we may modify it.
PropertyInfo pi_mut = pi;
- p_validator->_validate_property(pi_mut);
+ p_validator->validate_property(pi_mut);
p_list->push_back(pi_mut);
} else {
p_list->push_back(pi);
@@ -992,6 +995,25 @@ void ClassDB::get_property_list(const StringName &p_class, List<PropertyInfo> *p
}
}
+void ClassDB::get_linked_properties_info(const StringName &p_class, const StringName &p_property, List<StringName> *r_properties, bool p_no_inheritance) {
+#ifdef TOOLS_ENABLED
+ ClassInfo *check = classes.getptr(p_class);
+ while (check) {
+ if (!check->linked_properties.has(p_property)) {
+ return;
+ }
+ for (const StringName &E : check->linked_properties[p_property]) {
+ r_properties->push_back(E);
+ }
+
+ if (p_no_inheritance) {
+ break;
+ }
+ check = check->inherits_ptr;
+ }
+#endif
+}
+
bool ClassDB::get_property_info(const StringName &p_class, const StringName &p_property, PropertyInfo *r_info, bool p_no_inheritance, const Object *p_validator) {
OBJTYPE_RLOCK;
@@ -1000,7 +1022,7 @@ bool ClassDB::get_property_info(const StringName &p_class, const StringName &p_p
if (check->property_map.has(p_property)) {
PropertyInfo pinfo = check->property_map[p_property];
if (p_validator) {
- p_validator->_validate_property(pinfo);
+ p_validator->validate_property(pinfo);
}
if (r_info) {
*r_info = pinfo;
diff --git a/core/object/class_db.h b/core/object/class_db.h
index 8b6a260d86..5fba52e23e 100644
--- a/core/object/class_db.h
+++ b/core/object/class_db.h
@@ -120,6 +120,7 @@ public:
List<MethodInfo> virtual_methods;
HashMap<StringName, MethodInfo> virtual_methods_map;
HashMap<StringName, Vector<Error>> method_error_values;
+ HashMap<StringName, List<StringName>> linked_properties;
#endif
HashMap<StringName, PropertySetGet> property_setget;
@@ -312,6 +313,7 @@ public:
static void add_linked_property(const StringName &p_class, const String &p_property, const String &p_linked_property);
static void get_property_list(const StringName &p_class, List<PropertyInfo> *p_list, bool p_no_inheritance = false, const Object *p_validator = nullptr);
static bool get_property_info(const StringName &p_class, const StringName &p_property, PropertyInfo *r_info, bool p_no_inheritance = false, const Object *p_validator = nullptr);
+ static void get_linked_properties_info(const StringName &p_class, const StringName &p_property, List<StringName> *r_properties, bool p_no_inheritance = false);
static bool set_property(Object *p_object, const StringName &p_property, const Variant &p_value, bool *r_valid = nullptr);
static bool get_property(Object *p_object, const StringName &p_property, Variant &r_value);
static bool has_property(const StringName &p_class, const StringName &p_property, bool p_no_inheritance = false);
diff --git a/core/object/method_bind.cpp b/core/object/method_bind.cpp
index a4474ea53b..0edc7a90c2 100644
--- a/core/object/method_bind.cpp
+++ b/core/object/method_bind.cpp
@@ -63,7 +63,7 @@ PropertyInfo MethodBind::get_argument_info(int p_argument) const {
PropertyInfo info = _gen_argument_type_info(p_argument);
#ifdef DEBUG_METHODS_ENABLED
- info.name = p_argument < arg_names.size() ? String(arg_names[p_argument]) : String("arg" + itos(p_argument));
+ info.name = p_argument < arg_names.size() ? String(arg_names[p_argument]) : String("_unnamed_arg" + itos(p_argument));
#endif
return info;
}
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 75dbe8872f..4f7f55c8b6 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -38,6 +38,7 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
#include "core/string/translation.h"
+#include "core/variant/typed_array.h"
#ifdef DEBUG_ENABLED
@@ -102,8 +103,8 @@ PropertyInfo PropertyInfo::from_dict(const Dictionary &p_dict) {
return pi;
}
-Array convert_property_list(const List<PropertyInfo> *p_list) {
- Array va;
+TypedArray<Dictionary> convert_property_list(const List<PropertyInfo> *p_list) {
+ TypedArray<Dictionary> va;
for (const List<PropertyInfo>::Element *E = p_list->front(); E; E = E->next()) {
va.push_back(Dictionary(E->get()));
}
@@ -472,7 +473,6 @@ Variant Object::get_indexed(const Vector<StringName> &p_names, bool *r_valid) co
void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) const {
if (script_instance && p_reversed) {
- p_list->push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
script_instance->get_property_list(p_list);
}
@@ -503,7 +503,6 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
}
if (script_instance && !p_reversed) {
- p_list->push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY));
script_instance->get_property_list(p_list);
}
@@ -517,7 +516,61 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
}
}
-void Object::_validate_property(PropertyInfo &property) const {
+void Object::validate_property(PropertyInfo &p_property) const {
+ _validate_propertyv(p_property);
+}
+
+bool Object::property_can_revert(const StringName &p_name) const {
+ if (script_instance) {
+ if (script_instance->property_can_revert(p_name)) {
+ return true;
+ }
+ }
+
+// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it.
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wignored-qualifiers"
+#endif
+ if (_extension && _extension->property_can_revert) {
+ if (_extension->property_can_revert(_extension_instance, (const GDNativeStringNamePtr)&p_name)) {
+ return true;
+ }
+ }
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+ return _property_can_revertv(p_name);
+}
+
+Variant Object::property_get_revert(const StringName &p_name) const {
+ Variant ret;
+
+ if (script_instance) {
+ if (script_instance->property_get_revert(p_name, ret)) {
+ return ret;
+ }
+ }
+
+// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it.
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wignored-qualifiers"
+#endif
+ if (_extension && _extension->property_get_revert) {
+ if (_extension->property_get_revert(_extension_instance, (const GDNativeStringNamePtr)&p_name, (GDNativeVariantPtr)&ret)) {
+ return ret;
+ }
+ }
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+ if (_property_get_revertv(p_name, ret)) {
+ return ret;
+ }
+ return Variant();
}
void Object::get_method_list(List<MethodInfo> *p_list) const {
@@ -860,16 +913,16 @@ void Object::remove_meta(const StringName &p_name) {
set_meta(p_name, Variant());
}
-Array Object::_get_property_list_bind() const {
+TypedArray<Dictionary> Object::_get_property_list_bind() const {
List<PropertyInfo> lpi;
get_property_list(&lpi);
return convert_property_list(&lpi);
}
-Array Object::_get_method_list_bind() const {
+TypedArray<Dictionary> Object::_get_method_list_bind() const {
List<MethodInfo> ml;
get_method_list(&ml);
- Array ret;
+ TypedArray<Dictionary> ret;
for (List<MethodInfo>::Element *E = ml.front(); E; E = E->next()) {
Dictionary d = E->get();
@@ -1057,11 +1110,11 @@ void Object::_add_user_signal(const String &p_name, const Array &p_args) {
add_user_signal(mi);
}
-Array Object::_get_signal_list() const {
+TypedArray<Dictionary> Object::_get_signal_list() const {
List<MethodInfo> signal_list;
get_signal_list(&signal_list);
- Array ret;
+ TypedArray<Dictionary> ret;
for (const MethodInfo &E : signal_list) {
ret.push_back(Dictionary(E));
}
@@ -1069,11 +1122,11 @@ Array Object::_get_signal_list() const {
return ret;
}
-Array Object::_get_signal_connection_list(const StringName &p_signal) const {
+TypedArray<Dictionary> Object::_get_signal_connection_list(const StringName &p_signal) const {
List<Connection> conns;
get_all_signal_connections(&conns);
- Array ret;
+ TypedArray<Dictionary> ret;
for (const Connection &c : conns) {
if (c.signal.get_name() == p_signal) {
@@ -1084,8 +1137,8 @@ Array Object::_get_signal_connection_list(const StringName &p_signal) const {
return ret;
}
-Array Object::_get_incoming_connections() const {
- Array ret;
+TypedArray<Dictionary> Object::_get_incoming_connections() const {
+ TypedArray<Dictionary> ret;
int connections_amount = connections.size();
for (int idx_conn = 0; idx_conn < connections_amount; idx_conn++) {
ret.push_back(connections[idx_conn]);
@@ -1502,10 +1555,17 @@ void Object::_bind_methods() {
BIND_OBJ_CORE_METHOD(miget);
MethodInfo plget("_get_property_list");
-
plget.return_val.type = Variant::ARRAY;
+ plget.return_val.hint = PROPERTY_HINT_ARRAY_TYPE;
+ plget.return_val.hint_string = "Dictionary";
BIND_OBJ_CORE_METHOD(plget);
+ BIND_OBJ_CORE_METHOD(MethodInfo(Variant::BOOL, "_property_can_revert", PropertyInfo(Variant::STRING_NAME, "property")));
+ MethodInfo mipgr("_property_get_revert", PropertyInfo(Variant::STRING_NAME, "property"));
+ mipgr.return_val.name = "Variant";
+ mipgr.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ BIND_OBJ_CORE_METHOD(mipgr);
+
#endif
BIND_OBJ_CORE_METHOD(MethodInfo("_init"));
BIND_OBJ_CORE_METHOD(MethodInfo(Variant::STRING, "_to_string"));
diff --git a/core/object/object.h b/core/object/object.h
index f3f89982d9..1784c1fe70 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -45,12 +45,15 @@
#include "core/variant/callable_bind.h"
#include "core/variant/variant.h"
+template <typename T>
+class TypedArray;
+
enum PropertyHint {
PROPERTY_HINT_NONE, ///< no hint provided.
PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_lesser][,no_slider][,radians][,degrees][,exp][,suffix:<keyword>] range.
PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc"
PROPERTY_HINT_ENUM_SUGGESTION, ///< hint_text= "val1,val2,val3,etc"
- PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "full" to also include in/out. (ie: "attenuation,inout")
+ PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "positive_only" to exclude in-out and out-in. (ie: "attenuation,positive_only")
PROPERTY_HINT_LINK,
PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags)
PROPERTY_HINT_LAYERS_2D_RENDER,
@@ -91,6 +94,8 @@ enum PropertyHint {
PROPERTY_HINT_LOCALE_ID,
PROPERTY_HINT_LOCALIZABLE_STRING,
PROPERTY_HINT_NODE_TYPE, ///< a node object type
+ PROPERTY_HINT_HIDE_QUATERNION_EDIT, /// Only Node3D::transform should hide the quaternion editor.
+ PROPERTY_HINT_PASSWORD,
PROPERTY_HINT_MAX,
// When updating PropertyHint, also sync the hardcoded list in VisualScriptEditorVariableEdit
};
@@ -154,9 +159,7 @@ struct PropertyInfo {
String hint_string;
uint32_t usage = PROPERTY_USAGE_DEFAULT;
-#ifdef TOOLS_ENABLED
- Vector<String> linked_properties;
-#endif
+ // If you are thinking about adding another member to this class, ask the maintainer (Juan) first.
_FORCE_INLINE_ PropertyInfo added_usage(uint32_t p_fl) const {
PropertyInfo pi = *this;
@@ -209,7 +212,7 @@ struct PropertyInfo {
}
};
-Array convert_property_list(const List<PropertyInfo> *p_list);
+TypedArray<Dictionary> convert_property_list(const List<PropertyInfo> *p_list);
enum MethodFlags {
METHOD_FLAG_NORMAL = 1,
@@ -296,6 +299,8 @@ struct ObjectNativeExtension {
GDNativeExtensionClassGet get;
GDNativeExtensionClassGetPropertyList get_property_list;
GDNativeExtensionClassFreePropertyList free_property_list;
+ GDNativeExtensionClassPropertyCanRevert property_can_revert;
+ GDNativeExtensionClassPropertyGetRevert property_get_revert;
GDNativeExtensionClassNotification notification;
GDNativeExtensionClassToString to_string;
GDNativeExtensionClassReference reference;
@@ -471,6 +476,37 @@ protected:
m_inherits::_get_property_listv(p_list, p_reversed); \
} \
} \
+ _FORCE_INLINE_ void (Object::*_get_validate_property() const)(PropertyInfo & p_property) const { \
+ return (void(Object::*)(PropertyInfo &) const) & m_class::_validate_property; \
+ } \
+ virtual void _validate_propertyv(PropertyInfo &p_property) const override { \
+ m_inherits::_validate_propertyv(p_property); \
+ if (m_class::_get_validate_property() != m_inherits::_get_validate_property()) { \
+ _validate_property(p_property); \
+ } \
+ } \
+ _FORCE_INLINE_ bool (Object::*_get_property_can_revert() const)(const StringName &p_name) const { \
+ return (bool(Object::*)(const StringName &) const) & m_class::_property_can_revert; \
+ } \
+ virtual bool _property_can_revertv(const StringName &p_name) const override { \
+ if (m_class::_get_property_can_revert() != m_inherits::_get_property_can_revert()) { \
+ if (_property_can_revert(p_name)) { \
+ return true; \
+ } \
+ } \
+ return m_inherits::_property_can_revertv(p_name); \
+ } \
+ _FORCE_INLINE_ bool (Object::*_get_property_get_revert() const)(const StringName &p_name, Variant &) const { \
+ return (bool(Object::*)(const StringName &, Variant &) const) & m_class::_property_get_revert; \
+ } \
+ virtual bool _property_get_revertv(const StringName &p_name, Variant &r_ret) const override { \
+ if (m_class::_get_property_get_revert() != m_inherits::_get_property_get_revert()) { \
+ if (_property_get_revert(p_name, r_ret)) { \
+ return true; \
+ } \
+ } \
+ return m_inherits::_property_get_revertv(p_name, r_ret); \
+ } \
_FORCE_INLINE_ void (Object::*_get_notification() const)(int) { \
return (void(Object::*)(int)) & m_class::_notification; \
} \
@@ -566,9 +602,9 @@ private:
void _add_user_signal(const String &p_name, const Array &p_args = Array());
bool _has_user_signal(const StringName &p_name) const;
Error _emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- Array _get_signal_list() const;
- Array _get_signal_connection_list(const StringName &p_signal) const;
- Array _get_incoming_connections() const;
+ TypedArray<Dictionary> _get_signal_list() const;
+ TypedArray<Dictionary> _get_signal_connection_list(const StringName &p_signal) const;
+ TypedArray<Dictionary> _get_incoming_connections() const;
void _set_bind(const StringName &p_set, const Variant &p_value);
Variant _get_bind(const StringName &p_name) const;
void _set_indexed_bind(const NodePath &p_name, const Variant &p_value);
@@ -615,12 +651,18 @@ protected:
virtual bool _setv(const StringName &p_name, const Variant &p_property) { return false; };
virtual bool _getv(const StringName &p_name, Variant &r_property) const { return false; };
virtual void _get_property_listv(List<PropertyInfo> *p_list, bool p_reversed) const {};
+ virtual void _validate_propertyv(PropertyInfo &p_property) const {};
+ virtual bool _property_can_revertv(const StringName &p_name) const { return false; };
+ virtual bool _property_get_revertv(const StringName &p_name, Variant &r_property) const { return false; };
virtual void _notificationv(int p_notification, bool p_reversed) {}
static void _bind_methods();
bool _set(const StringName &p_name, const Variant &p_property) { return false; };
bool _get(const StringName &p_name, Variant &r_property) const { return false; };
void _get_property_list(List<PropertyInfo> *p_list) const {};
+ void _validate_property(PropertyInfo &p_property) const {};
+ bool _property_can_revert(const StringName &p_name) const { return false; };
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return false; };
void _notification(int p_notification) {}
_FORCE_INLINE_ static void (*_get_bind_methods())() {
@@ -635,6 +677,15 @@ protected:
_FORCE_INLINE_ void (Object::*_get_get_property_list() const)(List<PropertyInfo> *p_list) const {
return &Object::_get_property_list;
}
+ _FORCE_INLINE_ void (Object::*_get_validate_property() const)(PropertyInfo &p_property) const {
+ return &Object::_validate_property;
+ }
+ _FORCE_INLINE_ bool (Object::*_get_property_can_revert() const)(const StringName &p_name) const {
+ return &Object::_property_can_revert;
+ }
+ _FORCE_INLINE_ bool (Object::*_get_property_get_revert() const)(const StringName &p_name, Variant &) const {
+ return &Object::_property_get_revert;
+ }
_FORCE_INLINE_ void (Object::*_get_notification() const)(int) {
return &Object::_notification;
}
@@ -652,13 +703,12 @@ protected:
}
Vector<StringName> _get_meta_list_bind() const;
- Array _get_property_list_bind() const;
- Array _get_method_list_bind() const;
+ TypedArray<Dictionary> _get_property_list_bind() const;
+ TypedArray<Dictionary> _get_method_list_bind() const;
void _clear_internal_resource_paths(const Variant &p_var);
friend class ClassDB;
- virtual void _validate_property(PropertyInfo &property) const;
void _disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force = false);
@@ -759,6 +809,9 @@ public:
Variant get_indexed(const Vector<StringName> &p_names, bool *r_valid = nullptr) const;
void get_property_list(List<PropertyInfo> *p_list, bool p_reversed = false) const;
+ void validate_property(PropertyInfo &p_property) const;
+ bool property_can_revert(const StringName &p_name) const;
+ Variant property_get_revert(const StringName &p_name) const;
bool has_method(const StringName &p_method) const;
void get_method_list(List<MethodInfo> *p_list) const;
diff --git a/core/object/ref_counted.cpp b/core/object/ref_counted.cpp
index 726e2c012c..cac2400744 100644
--- a/core/object/ref_counted.cpp
+++ b/core/object/ref_counted.cpp
@@ -85,7 +85,8 @@ bool RefCounted::unreference() {
_get_extension()->unreference(_get_extension_instance());
}
- die = die && _instance_binding_reference(false);
+ bool binding_ret = _instance_binding_reference(false);
+ die = die && binding_ret;
}
return die;
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index 226fd8b791..e56d2e80b9 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -34,6 +34,7 @@
#include "core/core_string_names.h"
#include "core/debugger/engine_debugger.h"
#include "core/debugger/script_debugger.h"
+#include "core/variant/typed_array.h"
#include <stdint.h>
@@ -61,8 +62,8 @@ Variant Script::_get_property_default_value(const StringName &p_property) {
return ret;
}
-Array Script::_get_script_property_list() {
- Array ret;
+TypedArray<Dictionary> Script::_get_script_property_list() {
+ TypedArray<Dictionary> ret;
List<PropertyInfo> list;
get_script_property_list(&list);
for (const PropertyInfo &E : list) {
@@ -71,8 +72,8 @@ Array Script::_get_script_property_list() {
return ret;
}
-Array Script::_get_script_method_list() {
- Array ret;
+TypedArray<Dictionary> Script::_get_script_method_list() {
+ TypedArray<Dictionary> ret;
List<MethodInfo> list;
get_script_method_list(&list);
for (const MethodInfo &E : list) {
@@ -81,8 +82,8 @@ Array Script::_get_script_method_list() {
return ret;
}
-Array Script::_get_script_signal_list() {
- Array ret;
+TypedArray<Dictionary> Script::_get_script_signal_list() {
+ TypedArray<Dictionary> ret;
List<MethodInfo> list;
get_script_signal_list(&list);
for (const MethodInfo &E : list) {
@@ -101,6 +102,31 @@ Dictionary Script::_get_script_constant_map() {
return ret;
}
+#ifdef TOOLS_ENABLED
+
+PropertyInfo Script::get_class_category() const {
+ String path = get_path();
+ String name;
+
+ if (is_built_in()) {
+ if (get_name().is_empty()) {
+ name = TTR("Built-in script");
+ } else {
+ name = vformat("%s (%s)", get_name(), TTR("Built-in"));
+ }
+ } else {
+ if (get_name().is_empty()) {
+ name = path.get_file();
+ } else {
+ name = get_name();
+ }
+ }
+
+ return PropertyInfo(Variant::NIL, name, PROPERTY_HINT_NONE, path, PROPERTY_USAGE_CATEGORY);
+}
+
+#endif // TOOLS_ENABLED
+
void Script::_bind_methods() {
ClassDB::bind_method(D_METHOD("can_instantiate"), &Script::can_instantiate);
//ClassDB::bind_method(D_METHOD("instance_create","base_object"),&Script::instance_create);
diff --git a/core/object/script_language.h b/core/object/script_language.h
index c9f8a4f828..12a21150bc 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -37,6 +37,8 @@
#include "core/templates/rb_map.h"
class ScriptLanguage;
+template <typename T>
+class TypedArray;
typedef void (*ScriptEditRequestFunction)(const String &p_path);
@@ -108,9 +110,9 @@ protected:
virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {}
Variant _get_property_default_value(const StringName &p_property);
- Array _get_script_property_list();
- Array _get_script_method_list();
- Array _get_script_signal_list();
+ TypedArray<Dictionary> _get_script_property_list();
+ TypedArray<Dictionary> _get_script_method_list();
+ TypedArray<Dictionary> _get_script_signal_list();
Dictionary _get_script_constant_map();
public:
@@ -132,6 +134,7 @@ public:
#ifdef TOOLS_ENABLED
virtual Vector<DocData::ClassDoc> get_documentation() const = 0;
+ virtual PropertyInfo get_class_category() const;
#endif // TOOLS_ENABLED
virtual bool has_method(const StringName &p_method) const = 0;
@@ -170,6 +173,9 @@ public:
virtual void get_property_list(List<PropertyInfo> *p_properties) const = 0;
virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const = 0;
+ virtual bool property_can_revert(const StringName &p_name) const = 0;
+ virtual bool property_get_revert(const StringName &p_name, Variant &r_ret) const = 0;
+
virtual Object *get_owner() { return nullptr; }
virtual void get_property_state(List<Pair<StringName, Variant>> &state);
@@ -446,6 +452,9 @@ public:
virtual void get_property_list(List<PropertyInfo> *p_properties) const override;
virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const override;
+ virtual bool property_can_revert(const StringName &p_name) const override { return false; };
+ virtual bool property_get_revert(const StringName &p_name, Variant &r_ret) const override { return false; };
+
virtual void get_method_list(List<MethodInfo> *p_list) const override;
virtual bool has_method(const StringName &p_method) const override;
diff --git a/core/object/script_language_extension.cpp b/core/object/script_language_extension.cpp
index 9de784ea7f..78e9038b66 100644
--- a/core/object/script_language_extension.cpp
+++ b/core/object/script_language_extension.cpp
@@ -62,6 +62,7 @@ void ScriptExtension::_bind_methods() {
GDVIRTUAL_BIND(_has_script_signal, "signal");
GDVIRTUAL_BIND(_get_script_signal_list);
+ GDVIRTUAL_BIND(_has_property_default_value, "property");
GDVIRTUAL_BIND(_get_property_default_value, "property");
GDVIRTUAL_BIND(_update_exports);
diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h
index 10eacfd9f7..7e74f6a2be 100644
--- a/core/object/script_language_extension.h
+++ b/core/object/script_language_extension.h
@@ -663,6 +663,14 @@ public:
if (native_info->get_property_list_func) {
uint32_t pcount;
const GDNativePropertyInfo *pinfo = native_info->get_property_list_func(instance, &pcount);
+
+#ifdef TOOLS_ENABLED
+ Ref<Script> script = get_script();
+ if (script->is_valid() && pcount > 0) {
+ p_list->push_back(script->get_class_category());
+ }
+#endif // TOOLS_ENABLED
+
for (uint32_t i = 0; i < pcount; i++) {
p_list->push_back(PropertyInfo(pinfo[i]));
}
@@ -684,6 +692,19 @@ public:
return Variant::NIL;
}
+ virtual bool property_can_revert(const StringName &p_name) const override {
+ if (native_info->property_can_revert_func) {
+ return native_info->property_can_revert_func(instance, (const GDNativeStringNamePtr)&p_name);
+ }
+ return false;
+ }
+ virtual bool property_get_revert(const StringName &p_name, Variant &r_ret) const override {
+ if (native_info->property_get_revert_func) {
+ return native_info->property_get_revert_func(instance, (const GDNativeStringNamePtr)&p_name, (GDNativeVariantPtr)&r_ret);
+ }
+ return false;
+ }
+
virtual Object *get_owner() override {
if (native_info->get_owner_func) {
return (Object *)native_info->get_owner_func(instance);
diff --git a/core/os/keyboard.h b/core/os/keyboard.h
index 517a53e505..29418049cb 100644
--- a/core/os/keyboard.h
+++ b/core/os/keyboard.h
@@ -329,67 +329,71 @@ enum class KeyModifierMask {
// To avoid having unnecessary operators, only define the ones that are needed.
-inline Key operator-(uint32_t a, Key b) {
+constexpr Key operator-(uint32_t a, Key b) {
return (Key)(a - (uint32_t)b);
}
-inline Key &operator-=(Key &a, int b) {
- return (Key &)((int &)a -= b);
+constexpr Key &operator-=(Key &a, int b) {
+ a = static_cast<Key>(static_cast<int>(a) - static_cast<int>(b));
+ return a;
}
-inline Key operator+(Key a, int b) {
+constexpr Key operator+(Key a, int b) {
return (Key)((int)a + (int)b);
}
-inline Key operator+(Key a, Key b) {
+constexpr Key operator+(Key a, Key b) {
return (Key)((int)a + (int)b);
}
-inline Key operator-(Key a, Key b) {
+constexpr Key operator-(Key a, Key b) {
return (Key)((int)a - (int)b);
}
-inline Key operator&(Key a, Key b) {
+constexpr Key operator&(Key a, Key b) {
return (Key)((int)a & (int)b);
}
-inline Key operator|(Key a, Key b) {
+constexpr Key operator|(Key a, Key b) {
return (Key)((int)a | (int)b);
}
-inline Key &operator|=(Key &a, Key b) {
- return (Key &)((int &)a |= (int)b);
+constexpr Key &operator|=(Key &a, Key b) {
+ a = static_cast<Key>(static_cast<int>(a) | static_cast<int>(b));
+ return a;
}
-inline Key &operator|=(Key &a, KeyModifierMask b) {
- return (Key &)((int &)a |= (int)b);
+constexpr Key &operator|=(Key &a, KeyModifierMask b) {
+ a = static_cast<Key>(static_cast<int>(a) | static_cast<int>(b));
+ return a;
}
-inline Key &operator&=(Key &a, KeyModifierMask b) {
- return (Key &)((int &)a &= (int)b);
+constexpr Key &operator&=(Key &a, KeyModifierMask b) {
+ a = static_cast<Key>(static_cast<int>(a) & static_cast<int>(b));
+ return a;
}
-inline Key operator|(Key a, KeyModifierMask b) {
+constexpr Key operator|(Key a, KeyModifierMask b) {
return (Key)((int)a | (int)b);
}
-inline Key operator&(Key a, KeyModifierMask b) {
+constexpr Key operator&(Key a, KeyModifierMask b) {
return (Key)((int)a & (int)b);
}
-inline Key operator+(KeyModifierMask a, Key b) {
+constexpr Key operator+(KeyModifierMask a, Key b) {
return (Key)((int)a + (int)b);
}
-inline Key operator|(KeyModifierMask a, Key b) {
+constexpr Key operator|(KeyModifierMask a, Key b) {
return (Key)((int)a | (int)b);
}
-inline KeyModifierMask operator+(KeyModifierMask a, KeyModifierMask b) {
+constexpr KeyModifierMask operator+(KeyModifierMask a, KeyModifierMask b) {
return (KeyModifierMask)((int)a + (int)b);
}
-inline KeyModifierMask operator|(KeyModifierMask a, KeyModifierMask b) {
+constexpr KeyModifierMask operator|(KeyModifierMask a, KeyModifierMask b) {
return (KeyModifierMask)((int)a | (int)b);
}
diff --git a/core/os/memory.h b/core/os/memory.h
index 42ba9634e2..0e1afe027e 100644
--- a/core/os/memory.h
+++ b/core/os/memory.h
@@ -36,6 +36,7 @@
#include <stddef.h>
#include <new>
+#include <type_traits>
#ifndef PAD_ALIGN
#define PAD_ALIGN 16 //must always be greater than this at much
@@ -104,7 +105,7 @@ void memdelete(T *p_class) {
if (!predelete_handler(p_class)) {
return; // doesn't want to be deleted
}
- if (!__has_trivial_destructor(T)) {
+ if (!std::is_trivially_destructible<T>::value) {
p_class->~T();
}
@@ -116,7 +117,7 @@ void memdelete_allocator(T *p_class) {
if (!predelete_handler(p_class)) {
return; // doesn't want to be deleted
}
- if (!__has_trivial_destructor(T)) {
+ if (!std::is_trivially_destructible<T>::value) {
p_class->~T();
}
@@ -146,7 +147,7 @@ T *memnew_arr_template(size_t p_elements) {
ERR_FAIL_COND_V(!mem, failptr);
*(mem - 1) = p_elements;
- if (!__has_trivial_constructor(T)) {
+ if (!std::is_trivially_constructible<T>::value) {
T *elems = (T *)mem;
/* call operator new */
@@ -173,7 +174,7 @@ template <typename T>
void memdelete_arr(T *p_class) {
uint64_t *ptr = (uint64_t *)p_class;
- if (!__has_trivial_destructor(T)) {
+ if (!std::is_trivially_destructible<T>::value) {
uint64_t elem_count = *(ptr - 1);
for (uint64_t i = 0; i < elem_count; i++) {
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 619e3eb06f..526b31ae7e 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -159,17 +159,13 @@ int OS::get_process_id() const {
}
void OS::vibrate_handheld(int p_duration_ms) {
- WARN_PRINT("vibrate_handheld() only works with Android, iOS and HTML5");
+ WARN_PRINT("vibrate_handheld() only works with Android, iOS and Web");
}
bool OS::is_stdout_verbose() const {
return _verbose_stdout;
}
-bool OS::is_single_window() const {
- return _single_window;
-}
-
bool OS::is_stdout_debug_enabled() const {
return _debug_stdout;
}
@@ -190,50 +186,6 @@ void OS::set_stderr_enabled(bool p_enabled) {
_stderr_enabled = p_enabled;
}
-void OS::dump_memory_to_file(const char *p_file) {
- //Memory::dump_static_mem_to_file(p_file);
-}
-
-static Ref<FileAccess> _OSPRF;
-
-static void _OS_printres(Object *p_obj) {
- Resource *res = Object::cast_to<Resource>(p_obj);
- if (!res) {
- return;
- }
-
- String str = vformat("%s - %s - %s", res->to_string(), res->get_name(), res->get_path());
- if (_OSPRF.is_valid()) {
- _OSPRF->store_line(str);
- } else {
- print_line(str);
- }
-}
-
-void OS::print_all_resources(String p_to_file) {
- ERR_FAIL_COND(!p_to_file.is_empty() && _OSPRF.is_valid());
- if (!p_to_file.is_empty()) {
- Error err;
- _OSPRF = FileAccess::open(p_to_file, FileAccess::WRITE, &err);
- if (err != OK) {
- _OSPRF.unref();
- ERR_FAIL_MSG("Can't print all resources to file: " + String(p_to_file) + ".");
- }
- }
-
- ObjectDB::debug_objects(_OS_printres);
-
- _OSPRF.unref();
-}
-
-void OS::print_resources_in_use(bool p_short) {
- ResourceCache::dump(nullptr, p_short);
-}
-
-void OS::dump_resources_to_file(const char *p_file) {
- ResourceCache::dump(p_file);
-}
-
int OS::get_exit_code() const {
return _exit_code;
}
@@ -362,9 +314,10 @@ String OS::get_model_name() const {
return "GenericDevice";
}
-void OS::set_cmdline(const char *p_execpath, const List<String> &p_args) {
+void OS::set_cmdline(const char *p_execpath, const List<String> &p_args, const List<String> &p_user_args) {
_execpath = String::utf8(p_execpath);
_cmdline = p_args;
+ _user_args = p_user_args;
}
String OS::get_unique_id() const {
diff --git a/core/os/os.h b/core/os/os.h
index b9f7328929..0e8a2d0398 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -46,12 +46,12 @@ class OS {
static uint64_t target_ticks;
String _execpath;
List<String> _cmdline;
+ List<String> _user_args;
bool _keep_screen_on = true; // set default value to true, because this had been true before godot 2.0.
bool low_processor_usage_mode = false;
int low_processor_usage_mode_sleep_usec = 10000;
bool _verbose_stdout = false;
bool _debug_stdout = false;
- bool _single_window = false;
String _local_clipboard;
int _exit_code = EXIT_FAILURE; // unexpected exit is marked as failure
bool _allow_hidpi = false;
@@ -106,7 +106,7 @@ protected:
virtual void finalize() = 0;
virtual void finalize_core() = 0;
- virtual void set_cmdline(const char *p_execpath, const List<String> &p_args);
+ virtual void set_cmdline(const char *p_execpath, const List<String> &p_args, const List<String> &p_user_args);
virtual bool _check_internal_feature_support(const String &p_feature) = 0;
@@ -162,6 +162,7 @@ public:
virtual String get_name() const = 0;
virtual List<String> get_cmdline_args() const { return _cmdline; }
+ virtual List<String> get_cmdline_user_args() const { return _user_args; }
virtual List<String> get_cmdline_platform_args() const { return List<String>(); }
virtual String get_model_name() const;
@@ -241,17 +242,10 @@ public:
void set_stdout_enabled(bool p_enabled);
void set_stderr_enabled(bool p_enabled);
- virtual bool is_single_window() const;
-
virtual void disable_crash_handler() {}
virtual bool is_disable_crash_handler() const { return false; }
virtual void initialize_debugging() {}
- virtual void dump_memory_to_file(const char *p_file);
- virtual void dump_resources_to_file(const char *p_file);
- virtual void print_resources_in_use(bool p_short = false);
- virtual void print_all_resources(String p_to_file = "");
-
virtual uint64_t get_static_memory_usage() const;
virtual uint64_t get_static_memory_peak_usage() const;
virtual uint64_t get_free_static_memory() const;
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 1ae5d1c83f..9ad6b0ca68 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -269,6 +269,7 @@ void register_core_types() {
_marshalls = memnew(core_bind::Marshalls);
_engine_debugger = memnew(core_bind::EngineDebugger);
+ GDREGISTER_NATIVE_STRUCT(ObjectID, "uint64_t id = 0");
GDREGISTER_NATIVE_STRUCT(AudioFrame, "float left;float right");
GDREGISTER_NATIVE_STRUCT(ScriptLanguageExtensionProfilingInfo, "StringName signature;uint64_t call_count;uint64_t total_time;uint64_t self_time");
diff --git a/core/string/char_range.inc b/core/string/char_range.inc
new file mode 100644
index 0000000000..c0be9016ad
--- /dev/null
+++ b/core/string/char_range.inc
@@ -0,0 +1,1456 @@
+/*************************************************************************/
+/* char_range.inc */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef CHAR_RANGE_INC
+#define CHAR_RANGE_INC
+
+#include "core/typedefs.h"
+
+struct CharRange {
+ char32_t start;
+ char32_t end;
+};
+
+static CharRange xid_start[] = {
+ { 0x41, 0x5a },
+ { 0x5f, 0x5f },
+ { 0x61, 0x7a },
+ { 0xaa, 0xaa },
+ { 0xb5, 0xb5 },
+ { 0xba, 0xba },
+ { 0xc0, 0xd6 },
+ { 0xd8, 0xf6 },
+ { 0xf8, 0x2c1 },
+ { 0x2c6, 0x2d1 },
+ { 0x2e0, 0x2e4 },
+ { 0x2ec, 0x2ec },
+ { 0x2ee, 0x2ee },
+ { 0x370, 0x374 },
+ { 0x376, 0x377 },
+ { 0x37a, 0x37d },
+ { 0x37f, 0x37f },
+ { 0x386, 0x386 },
+ { 0x388, 0x38a },
+ { 0x38c, 0x38c },
+ { 0x38e, 0x3a1 },
+ { 0x3a3, 0x3f5 },
+ { 0x3f7, 0x481 },
+ { 0x48a, 0x52f },
+ { 0x531, 0x556 },
+ { 0x559, 0x559 },
+ { 0x560, 0x588 },
+ { 0x5d0, 0x5ea },
+ { 0x5ef, 0x5f2 },
+ { 0x620, 0x64a },
+ { 0x66e, 0x66f },
+ { 0x671, 0x6d3 },
+ { 0x6d5, 0x6d5 },
+ { 0x6e5, 0x6e6 },
+ { 0x6ee, 0x6ef },
+ { 0x6fa, 0x6fc },
+ { 0x6ff, 0x6ff },
+ { 0x710, 0x710 },
+ { 0x712, 0x72f },
+ { 0x74d, 0x7a5 },
+ { 0x7b1, 0x7b1 },
+ { 0x7ca, 0x7ea },
+ { 0x7f4, 0x7f5 },
+ { 0x7fa, 0x7fa },
+ { 0x800, 0x815 },
+ { 0x81a, 0x81a },
+ { 0x824, 0x824 },
+ { 0x828, 0x828 },
+ { 0x840, 0x858 },
+ { 0x860, 0x86a },
+ { 0x870, 0x887 },
+ { 0x889, 0x88e },
+ { 0x8a0, 0x8c9 },
+ { 0x904, 0x939 },
+ { 0x93d, 0x93d },
+ { 0x950, 0x950 },
+ { 0x958, 0x961 },
+ { 0x971, 0x980 },
+ { 0x985, 0x98c },
+ { 0x98f, 0x990 },
+ { 0x993, 0x9a8 },
+ { 0x9aa, 0x9b0 },
+ { 0x9b2, 0x9b2 },
+ { 0x9b6, 0x9b9 },
+ { 0x9bd, 0x9bd },
+ { 0x9ce, 0x9ce },
+ { 0x9dc, 0x9dd },
+ { 0x9df, 0x9e1 },
+ { 0x9f0, 0x9f1 },
+ { 0x9fc, 0x9fc },
+ { 0xa05, 0xa0a },
+ { 0xa0f, 0xa10 },
+ { 0xa13, 0xa28 },
+ { 0xa2a, 0xa30 },
+ { 0xa32, 0xa33 },
+ { 0xa35, 0xa36 },
+ { 0xa38, 0xa39 },
+ { 0xa59, 0xa5c },
+ { 0xa5e, 0xa5e },
+ { 0xa72, 0xa74 },
+ { 0xa85, 0xa8d },
+ { 0xa8f, 0xa91 },
+ { 0xa93, 0xaa8 },
+ { 0xaaa, 0xab0 },
+ { 0xab2, 0xab3 },
+ { 0xab5, 0xab9 },
+ { 0xabd, 0xabd },
+ { 0xad0, 0xad0 },
+ { 0xae0, 0xae1 },
+ { 0xaf9, 0xaf9 },
+ { 0xb05, 0xb0c },
+ { 0xb0f, 0xb10 },
+ { 0xb13, 0xb28 },
+ { 0xb2a, 0xb30 },
+ { 0xb32, 0xb33 },
+ { 0xb35, 0xb39 },
+ { 0xb3d, 0xb3d },
+ { 0xb5c, 0xb5d },
+ { 0xb5f, 0xb61 },
+ { 0xb71, 0xb71 },
+ { 0xb83, 0xb83 },
+ { 0xb85, 0xb8a },
+ { 0xb8e, 0xb90 },
+ { 0xb92, 0xb95 },
+ { 0xb99, 0xb9a },
+ { 0xb9c, 0xb9c },
+ { 0xb9e, 0xb9f },
+ { 0xba3, 0xba4 },
+ { 0xba8, 0xbaa },
+ { 0xbae, 0xbb9 },
+ { 0xbd0, 0xbd0 },
+ { 0xc05, 0xc0c },
+ { 0xc0e, 0xc10 },
+ { 0xc12, 0xc28 },
+ { 0xc2a, 0xc39 },
+ { 0xc3d, 0xc3d },
+ { 0xc58, 0xc5a },
+ { 0xc5d, 0xc5d },
+ { 0xc60, 0xc61 },
+ { 0xc80, 0xc80 },
+ { 0xc85, 0xc8c },
+ { 0xc8e, 0xc90 },
+ { 0xc92, 0xca8 },
+ { 0xcaa, 0xcb3 },
+ { 0xcb5, 0xcb9 },
+ { 0xcbd, 0xcbd },
+ { 0xcdd, 0xcde },
+ { 0xce0, 0xce1 },
+ { 0xcf1, 0xcf2 },
+ { 0xd04, 0xd0c },
+ { 0xd0e, 0xd10 },
+ { 0xd12, 0xd3a },
+ { 0xd3d, 0xd3d },
+ { 0xd4e, 0xd4e },
+ { 0xd54, 0xd56 },
+ { 0xd5f, 0xd61 },
+ { 0xd7a, 0xd7f },
+ { 0xd85, 0xd96 },
+ { 0xd9a, 0xdb1 },
+ { 0xdb3, 0xdbb },
+ { 0xdbd, 0xdbd },
+ { 0xdc0, 0xdc6 },
+ { 0xe01, 0xe30 },
+ { 0xe32, 0xe33 },
+ { 0xe40, 0xe46 },
+ { 0xe81, 0xe82 },
+ { 0xe84, 0xe84 },
+ { 0xe86, 0xe8a },
+ { 0xe8c, 0xea3 },
+ { 0xea5, 0xea5 },
+ { 0xea7, 0xeb0 },
+ { 0xeb2, 0xeb3 },
+ { 0xebd, 0xebd },
+ { 0xec0, 0xec4 },
+ { 0xec6, 0xec6 },
+ { 0xedc, 0xedf },
+ { 0xf00, 0xf00 },
+ { 0xf40, 0xf47 },
+ { 0xf49, 0xf6c },
+ { 0xf88, 0xf8c },
+ { 0x1000, 0x102a },
+ { 0x103f, 0x103f },
+ { 0x1050, 0x1055 },
+ { 0x105a, 0x105d },
+ { 0x1061, 0x1061 },
+ { 0x1065, 0x1066 },
+ { 0x106e, 0x1070 },
+ { 0x1075, 0x1081 },
+ { 0x108e, 0x108e },
+ { 0x10a0, 0x10c5 },
+ { 0x10c7, 0x10c7 },
+ { 0x10cd, 0x10cd },
+ { 0x10d0, 0x10fa },
+ { 0x10fc, 0x1248 },
+ { 0x124a, 0x124d },
+ { 0x1250, 0x1256 },
+ { 0x1258, 0x1258 },
+ { 0x125a, 0x125d },
+ { 0x1260, 0x1288 },
+ { 0x128a, 0x128d },
+ { 0x1290, 0x12b0 },
+ { 0x12b2, 0x12b5 },
+ { 0x12b8, 0x12be },
+ { 0x12c0, 0x12c0 },
+ { 0x12c2, 0x12c5 },
+ { 0x12c8, 0x12d6 },
+ { 0x12d8, 0x1310 },
+ { 0x1312, 0x1315 },
+ { 0x1318, 0x135a },
+ { 0x1380, 0x138f },
+ { 0x13a0, 0x13f5 },
+ { 0x13f8, 0x13fd },
+ { 0x1401, 0x166c },
+ { 0x166f, 0x167f },
+ { 0x1681, 0x169a },
+ { 0x16a0, 0x16ea },
+ { 0x16ee, 0x16f8 },
+ { 0x1700, 0x1711 },
+ { 0x171f, 0x1731 },
+ { 0x1740, 0x1751 },
+ { 0x1760, 0x176c },
+ { 0x176e, 0x1770 },
+ { 0x1780, 0x17b3 },
+ { 0x17d7, 0x17d7 },
+ { 0x17dc, 0x17dc },
+ { 0x1820, 0x1878 },
+ { 0x1880, 0x1884 },
+ { 0x1887, 0x18a8 },
+ { 0x18aa, 0x18aa },
+ { 0x18b0, 0x18f5 },
+ { 0x1900, 0x191e },
+ { 0x1950, 0x196d },
+ { 0x1970, 0x1974 },
+ { 0x1980, 0x19ab },
+ { 0x19b0, 0x19c9 },
+ { 0x1a00, 0x1a16 },
+ { 0x1a20, 0x1a54 },
+ { 0x1aa7, 0x1aa7 },
+ { 0x1b05, 0x1b33 },
+ { 0x1b45, 0x1b4c },
+ { 0x1b83, 0x1ba0 },
+ { 0x1bae, 0x1baf },
+ { 0x1bba, 0x1be5 },
+ { 0x1c00, 0x1c23 },
+ { 0x1c4d, 0x1c4f },
+ { 0x1c5a, 0x1c7d },
+ { 0x1c80, 0x1c88 },
+ { 0x1c90, 0x1cba },
+ { 0x1cbd, 0x1cbf },
+ { 0x1ce9, 0x1cec },
+ { 0x1cee, 0x1cf3 },
+ { 0x1cf5, 0x1cf6 },
+ { 0x1cfa, 0x1cfa },
+ { 0x1d00, 0x1dbf },
+ { 0x1e00, 0x1f15 },
+ { 0x1f18, 0x1f1d },
+ { 0x1f20, 0x1f45 },
+ { 0x1f48, 0x1f4d },
+ { 0x1f50, 0x1f57 },
+ { 0x1f59, 0x1f59 },
+ { 0x1f5b, 0x1f5b },
+ { 0x1f5d, 0x1f5d },
+ { 0x1f5f, 0x1f7d },
+ { 0x1f80, 0x1fb4 },
+ { 0x1fb6, 0x1fbc },
+ { 0x1fbe, 0x1fbe },
+ { 0x1fc2, 0x1fc4 },
+ { 0x1fc6, 0x1fcc },
+ { 0x1fd0, 0x1fd3 },
+ { 0x1fd6, 0x1fdb },
+ { 0x1fe0, 0x1fec },
+ { 0x1ff2, 0x1ff4 },
+ { 0x1ff6, 0x1ffc },
+ { 0x2071, 0x2071 },
+ { 0x207f, 0x207f },
+ { 0x2090, 0x209c },
+ { 0x2102, 0x2102 },
+ { 0x2107, 0x2107 },
+ { 0x210a, 0x2113 },
+ { 0x2115, 0x2115 },
+ { 0x2118, 0x211d },
+ { 0x2124, 0x2124 },
+ { 0x2126, 0x2126 },
+ { 0x2128, 0x2128 },
+ { 0x212a, 0x2139 },
+ { 0x213c, 0x213f },
+ { 0x2145, 0x2149 },
+ { 0x214e, 0x214e },
+ { 0x2160, 0x2188 },
+ { 0x2c00, 0x2ce4 },
+ { 0x2ceb, 0x2cee },
+ { 0x2cf2, 0x2cf3 },
+ { 0x2d00, 0x2d25 },
+ { 0x2d27, 0x2d27 },
+ { 0x2d2d, 0x2d2d },
+ { 0x2d30, 0x2d67 },
+ { 0x2d6f, 0x2d6f },
+ { 0x2d80, 0x2d96 },
+ { 0x2da0, 0x2da6 },
+ { 0x2da8, 0x2dae },
+ { 0x2db0, 0x2db6 },
+ { 0x2db8, 0x2dbe },
+ { 0x2dc0, 0x2dc6 },
+ { 0x2dc8, 0x2dce },
+ { 0x2dd0, 0x2dd6 },
+ { 0x2dd8, 0x2dde },
+ { 0x3005, 0x3007 },
+ { 0x3021, 0x3029 },
+ { 0x3031, 0x3035 },
+ { 0x3038, 0x303c },
+ { 0x3041, 0x3096 },
+ { 0x309b, 0x309f },
+ { 0x30a1, 0x30fa },
+ { 0x30fc, 0x30ff },
+ { 0x3105, 0x312f },
+ { 0x3131, 0x318e },
+ { 0x31a0, 0x31bf },
+ { 0x31f0, 0x31ff },
+ { 0x3400, 0x4dbf },
+ { 0x4e00, 0xa48c },
+ { 0xa4d0, 0xa4fd },
+ { 0xa500, 0xa60c },
+ { 0xa610, 0xa61f },
+ { 0xa62a, 0xa62b },
+ { 0xa640, 0xa66e },
+ { 0xa67f, 0xa69d },
+ { 0xa6a0, 0xa6ef },
+ { 0xa717, 0xa71f },
+ { 0xa722, 0xa788 },
+ { 0xa78b, 0xa7ca },
+ { 0xa7d0, 0xa7d1 },
+ { 0xa7d3, 0xa7d3 },
+ { 0xa7d5, 0xa7d9 },
+ { 0xa7f2, 0xa801 },
+ { 0xa803, 0xa805 },
+ { 0xa807, 0xa80a },
+ { 0xa80c, 0xa822 },
+ { 0xa840, 0xa873 },
+ { 0xa882, 0xa8b3 },
+ { 0xa8f2, 0xa8f7 },
+ { 0xa8fb, 0xa8fb },
+ { 0xa8fd, 0xa8fe },
+ { 0xa90a, 0xa925 },
+ { 0xa930, 0xa946 },
+ { 0xa960, 0xa97c },
+ { 0xa984, 0xa9b2 },
+ { 0xa9cf, 0xa9cf },
+ { 0xa9e0, 0xa9e4 },
+ { 0xa9e6, 0xa9ef },
+ { 0xa9fa, 0xa9fe },
+ { 0xaa00, 0xaa28 },
+ { 0xaa40, 0xaa42 },
+ { 0xaa44, 0xaa4b },
+ { 0xaa60, 0xaa76 },
+ { 0xaa7a, 0xaa7a },
+ { 0xaa7e, 0xaaaf },
+ { 0xaab1, 0xaab1 },
+ { 0xaab5, 0xaab6 },
+ { 0xaab9, 0xaabd },
+ { 0xaac0, 0xaac0 },
+ { 0xaac2, 0xaac2 },
+ { 0xaadb, 0xaadd },
+ { 0xaae0, 0xaaea },
+ { 0xaaf2, 0xaaf4 },
+ { 0xab01, 0xab06 },
+ { 0xab09, 0xab0e },
+ { 0xab11, 0xab16 },
+ { 0xab20, 0xab26 },
+ { 0xab28, 0xab2e },
+ { 0xab30, 0xab5a },
+ { 0xab5c, 0xab69 },
+ { 0xab70, 0xabe2 },
+ { 0xac00, 0xd7a3 },
+ { 0xd7b0, 0xd7c6 },
+ { 0xd7cb, 0xd7fb },
+ { 0xf900, 0xfa6d },
+ { 0xfa70, 0xfad9 },
+ { 0xfb00, 0xfb06 },
+ { 0xfb13, 0xfb17 },
+ { 0xfb1d, 0xfb1d },
+ { 0xfb1f, 0xfb28 },
+ { 0xfb2a, 0xfb36 },
+ { 0xfb38, 0xfb3c },
+ { 0xfb3e, 0xfb3e },
+ { 0xfb40, 0xfb41 },
+ { 0xfb43, 0xfb44 },
+ { 0xfb46, 0xfbb1 },
+ { 0xfbd3, 0xfd3d },
+ { 0xfd50, 0xfd8f },
+ { 0xfd92, 0xfdc7 },
+ { 0xfdf0, 0xfdfb },
+ { 0xfe70, 0xfe74 },
+ { 0xfe76, 0xfefc },
+ { 0xff21, 0xff3a },
+ { 0xff41, 0xff5a },
+ { 0xff66, 0xffbe },
+ { 0xffc2, 0xffc7 },
+ { 0xffca, 0xffcf },
+ { 0xffd2, 0xffd7 },
+ { 0xffda, 0xffdc },
+ { 0x10000, 0x1000b },
+ { 0x1000d, 0x10026 },
+ { 0x10028, 0x1003a },
+ { 0x1003c, 0x1003d },
+ { 0x1003f, 0x1004d },
+ { 0x10050, 0x1005d },
+ { 0x10080, 0x100fa },
+ { 0x10140, 0x10174 },
+ { 0x10280, 0x1029c },
+ { 0x102a0, 0x102d0 },
+ { 0x10300, 0x1031f },
+ { 0x1032d, 0x1034a },
+ { 0x10350, 0x10375 },
+ { 0x10380, 0x1039d },
+ { 0x103a0, 0x103c3 },
+ { 0x103c8, 0x103cf },
+ { 0x103d1, 0x103d5 },
+ { 0x10400, 0x1049d },
+ { 0x104b0, 0x104d3 },
+ { 0x104d8, 0x104fb },
+ { 0x10500, 0x10527 },
+ { 0x10530, 0x10563 },
+ { 0x10570, 0x1057a },
+ { 0x1057c, 0x1058a },
+ { 0x1058c, 0x10592 },
+ { 0x10594, 0x10595 },
+ { 0x10597, 0x105a1 },
+ { 0x105a3, 0x105b1 },
+ { 0x105b3, 0x105b9 },
+ { 0x105bb, 0x105bc },
+ { 0x10600, 0x10736 },
+ { 0x10740, 0x10755 },
+ { 0x10760, 0x10767 },
+ { 0x10780, 0x10785 },
+ { 0x10787, 0x107b0 },
+ { 0x107b2, 0x107ba },
+ { 0x10800, 0x10805 },
+ { 0x10808, 0x10808 },
+ { 0x1080a, 0x10835 },
+ { 0x10837, 0x10838 },
+ { 0x1083c, 0x1083c },
+ { 0x1083f, 0x10855 },
+ { 0x10860, 0x10876 },
+ { 0x10880, 0x1089e },
+ { 0x108e0, 0x108f2 },
+ { 0x108f4, 0x108f5 },
+ { 0x10900, 0x10915 },
+ { 0x10920, 0x10939 },
+ { 0x10980, 0x109b7 },
+ { 0x109be, 0x109bf },
+ { 0x10a00, 0x10a00 },
+ { 0x10a10, 0x10a13 },
+ { 0x10a15, 0x10a17 },
+ { 0x10a19, 0x10a35 },
+ { 0x10a60, 0x10a7c },
+ { 0x10a80, 0x10a9c },
+ { 0x10ac0, 0x10ac7 },
+ { 0x10ac9, 0x10ae4 },
+ { 0x10b00, 0x10b35 },
+ { 0x10b40, 0x10b55 },
+ { 0x10b60, 0x10b72 },
+ { 0x10b80, 0x10b91 },
+ { 0x10c00, 0x10c48 },
+ { 0x10c80, 0x10cb2 },
+ { 0x10cc0, 0x10cf2 },
+ { 0x10d00, 0x10d23 },
+ { 0x10e80, 0x10ea9 },
+ { 0x10eb0, 0x10eb1 },
+ { 0x10f00, 0x10f1c },
+ { 0x10f27, 0x10f27 },
+ { 0x10f30, 0x10f45 },
+ { 0x10f70, 0x10f81 },
+ { 0x10fb0, 0x10fc4 },
+ { 0x10fe0, 0x10ff6 },
+ { 0x11003, 0x11037 },
+ { 0x11071, 0x11072 },
+ { 0x11075, 0x11075 },
+ { 0x11083, 0x110af },
+ { 0x110d0, 0x110e8 },
+ { 0x11103, 0x11126 },
+ { 0x11144, 0x11144 },
+ { 0x11147, 0x11147 },
+ { 0x11150, 0x11172 },
+ { 0x11176, 0x11176 },
+ { 0x11183, 0x111b2 },
+ { 0x111c1, 0x111c4 },
+ { 0x111da, 0x111da },
+ { 0x111dc, 0x111dc },
+ { 0x11200, 0x11211 },
+ { 0x11213, 0x1122b },
+ { 0x11280, 0x11286 },
+ { 0x11288, 0x11288 },
+ { 0x1128a, 0x1128d },
+ { 0x1128f, 0x1129d },
+ { 0x1129f, 0x112a8 },
+ { 0x112b0, 0x112de },
+ { 0x11305, 0x1130c },
+ { 0x1130f, 0x11310 },
+ { 0x11313, 0x11328 },
+ { 0x1132a, 0x11330 },
+ { 0x11332, 0x11333 },
+ { 0x11335, 0x11339 },
+ { 0x1133d, 0x1133d },
+ { 0x11350, 0x11350 },
+ { 0x1135d, 0x11361 },
+ { 0x11400, 0x11434 },
+ { 0x11447, 0x1144a },
+ { 0x1145f, 0x11461 },
+ { 0x11480, 0x114af },
+ { 0x114c4, 0x114c5 },
+ { 0x114c7, 0x114c7 },
+ { 0x11580, 0x115ae },
+ { 0x115d8, 0x115db },
+ { 0x11600, 0x1162f },
+ { 0x11644, 0x11644 },
+ { 0x11680, 0x116aa },
+ { 0x116b8, 0x116b8 },
+ { 0x11700, 0x1171a },
+ { 0x11740, 0x11746 },
+ { 0x11800, 0x1182b },
+ { 0x118a0, 0x118df },
+ { 0x118ff, 0x11906 },
+ { 0x11909, 0x11909 },
+ { 0x1190c, 0x11913 },
+ { 0x11915, 0x11916 },
+ { 0x11918, 0x1192f },
+ { 0x1193f, 0x1193f },
+ { 0x11941, 0x11941 },
+ { 0x119a0, 0x119a7 },
+ { 0x119aa, 0x119d0 },
+ { 0x119e1, 0x119e1 },
+ { 0x119e3, 0x119e3 },
+ { 0x11a00, 0x11a00 },
+ { 0x11a0b, 0x11a32 },
+ { 0x11a3a, 0x11a3a },
+ { 0x11a50, 0x11a50 },
+ { 0x11a5c, 0x11a89 },
+ { 0x11a9d, 0x11a9d },
+ { 0x11ab0, 0x11af8 },
+ { 0x11c00, 0x11c08 },
+ { 0x11c0a, 0x11c2e },
+ { 0x11c40, 0x11c40 },
+ { 0x11c72, 0x11c8f },
+ { 0x11d00, 0x11d06 },
+ { 0x11d08, 0x11d09 },
+ { 0x11d0b, 0x11d30 },
+ { 0x11d46, 0x11d46 },
+ { 0x11d60, 0x11d65 },
+ { 0x11d67, 0x11d68 },
+ { 0x11d6a, 0x11d89 },
+ { 0x11d98, 0x11d98 },
+ { 0x11ee0, 0x11ef2 },
+ { 0x11fb0, 0x11fb0 },
+ { 0x12000, 0x12399 },
+ { 0x12400, 0x1246e },
+ { 0x12480, 0x12543 },
+ { 0x12f90, 0x12ff0 },
+ { 0x13000, 0x1342e },
+ { 0x14400, 0x14646 },
+ { 0x16800, 0x16a38 },
+ { 0x16a40, 0x16a5e },
+ { 0x16a70, 0x16abe },
+ { 0x16ad0, 0x16aed },
+ { 0x16b00, 0x16b2f },
+ { 0x16b40, 0x16b43 },
+ { 0x16b63, 0x16b77 },
+ { 0x16b7d, 0x16b8f },
+ { 0x16e40, 0x16e7f },
+ { 0x16f00, 0x16f4a },
+ { 0x16f50, 0x16f50 },
+ { 0x16f93, 0x16f9f },
+ { 0x16fe0, 0x16fe1 },
+ { 0x16fe3, 0x16fe3 },
+ { 0x17000, 0x187f7 },
+ { 0x18800, 0x18cd5 },
+ { 0x18d00, 0x18d08 },
+ { 0x1aff0, 0x1aff3 },
+ { 0x1aff5, 0x1affb },
+ { 0x1affd, 0x1affe },
+ { 0x1b000, 0x1b122 },
+ { 0x1b150, 0x1b152 },
+ { 0x1b164, 0x1b167 },
+ { 0x1b170, 0x1b2fb },
+ { 0x1bc00, 0x1bc6a },
+ { 0x1bc70, 0x1bc7c },
+ { 0x1bc80, 0x1bc88 },
+ { 0x1bc90, 0x1bc99 },
+ { 0x1d400, 0x1d454 },
+ { 0x1d456, 0x1d49c },
+ { 0x1d49e, 0x1d49f },
+ { 0x1d4a2, 0x1d4a2 },
+ { 0x1d4a5, 0x1d4a6 },
+ { 0x1d4a9, 0x1d4ac },
+ { 0x1d4ae, 0x1d4b9 },
+ { 0x1d4bb, 0x1d4bb },
+ { 0x1d4bd, 0x1d4c3 },
+ { 0x1d4c5, 0x1d505 },
+ { 0x1d507, 0x1d50a },
+ { 0x1d50d, 0x1d514 },
+ { 0x1d516, 0x1d51c },
+ { 0x1d51e, 0x1d539 },
+ { 0x1d53b, 0x1d53e },
+ { 0x1d540, 0x1d544 },
+ { 0x1d546, 0x1d546 },
+ { 0x1d54a, 0x1d550 },
+ { 0x1d552, 0x1d6a5 },
+ { 0x1d6a8, 0x1d6c0 },
+ { 0x1d6c2, 0x1d6da },
+ { 0x1d6dc, 0x1d6fa },
+ { 0x1d6fc, 0x1d714 },
+ { 0x1d716, 0x1d734 },
+ { 0x1d736, 0x1d74e },
+ { 0x1d750, 0x1d76e },
+ { 0x1d770, 0x1d788 },
+ { 0x1d78a, 0x1d7a8 },
+ { 0x1d7aa, 0x1d7c2 },
+ { 0x1d7c4, 0x1d7cb },
+ { 0x1df00, 0x1df1e },
+ { 0x1e100, 0x1e12c },
+ { 0x1e137, 0x1e13d },
+ { 0x1e14e, 0x1e14e },
+ { 0x1e290, 0x1e2ad },
+ { 0x1e2c0, 0x1e2eb },
+ { 0x1e7e0, 0x1e7e6 },
+ { 0x1e7e8, 0x1e7eb },
+ { 0x1e7ed, 0x1e7ee },
+ { 0x1e7f0, 0x1e7fe },
+ { 0x1e800, 0x1e8c4 },
+ { 0x1e900, 0x1e943 },
+ { 0x1e94b, 0x1e94b },
+ { 0x1ee00, 0x1ee03 },
+ { 0x1ee05, 0x1ee1f },
+ { 0x1ee21, 0x1ee22 },
+ { 0x1ee24, 0x1ee24 },
+ { 0x1ee27, 0x1ee27 },
+ { 0x1ee29, 0x1ee32 },
+ { 0x1ee34, 0x1ee37 },
+ { 0x1ee39, 0x1ee39 },
+ { 0x1ee3b, 0x1ee3b },
+ { 0x1ee42, 0x1ee42 },
+ { 0x1ee47, 0x1ee47 },
+ { 0x1ee49, 0x1ee49 },
+ { 0x1ee4b, 0x1ee4b },
+ { 0x1ee4d, 0x1ee4f },
+ { 0x1ee51, 0x1ee52 },
+ { 0x1ee54, 0x1ee54 },
+ { 0x1ee57, 0x1ee57 },
+ { 0x1ee59, 0x1ee59 },
+ { 0x1ee5b, 0x1ee5b },
+ { 0x1ee5d, 0x1ee5d },
+ { 0x1ee5f, 0x1ee5f },
+ { 0x1ee61, 0x1ee62 },
+ { 0x1ee64, 0x1ee64 },
+ { 0x1ee67, 0x1ee6a },
+ { 0x1ee6c, 0x1ee72 },
+ { 0x1ee74, 0x1ee77 },
+ { 0x1ee79, 0x1ee7c },
+ { 0x1ee7e, 0x1ee7e },
+ { 0x1ee80, 0x1ee89 },
+ { 0x1ee8b, 0x1ee9b },
+ { 0x1eea1, 0x1eea3 },
+ { 0x1eea5, 0x1eea9 },
+ { 0x1eeab, 0x1eebb },
+ { 0x20000, 0x2a6df },
+ { 0x2a700, 0x2b738 },
+ { 0x2b740, 0x2b81d },
+ { 0x2b820, 0x2cea1 },
+ { 0x2ceb0, 0x2ebe0 },
+ { 0x2f800, 0x2fa1d },
+ { 0x30000, 0x3134a },
+ { 0x0, 0x0 },
+};
+
+static CharRange xid_continue[] = {
+ { 0x30, 0x39 },
+ { 0x41, 0x5a },
+ { 0x5f, 0x5f },
+ { 0x61, 0x7a },
+ { 0xaa, 0xaa },
+ { 0xb5, 0xb5 },
+ { 0xb7, 0xb7 },
+ { 0xba, 0xba },
+ { 0xc0, 0xd6 },
+ { 0xd8, 0xf6 },
+ { 0xf8, 0x2c1 },
+ { 0x2c6, 0x2d1 },
+ { 0x2e0, 0x2e4 },
+ { 0x2ec, 0x2ec },
+ { 0x2ee, 0x2ee },
+ { 0x300, 0x374 },
+ { 0x376, 0x377 },
+ { 0x37a, 0x37d },
+ { 0x37f, 0x37f },
+ { 0x386, 0x38a },
+ { 0x38c, 0x38c },
+ { 0x38e, 0x3a1 },
+ { 0x3a3, 0x3f5 },
+ { 0x3f7, 0x481 },
+ { 0x483, 0x487 },
+ { 0x48a, 0x52f },
+ { 0x531, 0x556 },
+ { 0x559, 0x559 },
+ { 0x560, 0x588 },
+ { 0x591, 0x5bd },
+ { 0x5bf, 0x5bf },
+ { 0x5c1, 0x5c2 },
+ { 0x5c4, 0x5c5 },
+ { 0x5c7, 0x5c7 },
+ { 0x5d0, 0x5ea },
+ { 0x5ef, 0x5f2 },
+ { 0x610, 0x61a },
+ { 0x620, 0x669 },
+ { 0x66e, 0x6d3 },
+ { 0x6d5, 0x6dc },
+ { 0x6df, 0x6e8 },
+ { 0x6ea, 0x6fc },
+ { 0x6ff, 0x6ff },
+ { 0x710, 0x74a },
+ { 0x74d, 0x7b1 },
+ { 0x7c0, 0x7f5 },
+ { 0x7fa, 0x7fa },
+ { 0x7fd, 0x7fd },
+ { 0x800, 0x82d },
+ { 0x840, 0x85b },
+ { 0x860, 0x86a },
+ { 0x870, 0x887 },
+ { 0x889, 0x88e },
+ { 0x898, 0x8e1 },
+ { 0x8e3, 0x963 },
+ { 0x966, 0x96f },
+ { 0x971, 0x983 },
+ { 0x985, 0x98c },
+ { 0x98f, 0x990 },
+ { 0x993, 0x9a8 },
+ { 0x9aa, 0x9b0 },
+ { 0x9b2, 0x9b2 },
+ { 0x9b6, 0x9b9 },
+ { 0x9bc, 0x9c4 },
+ { 0x9c7, 0x9c8 },
+ { 0x9cb, 0x9ce },
+ { 0x9d7, 0x9d7 },
+ { 0x9dc, 0x9dd },
+ { 0x9df, 0x9e3 },
+ { 0x9e6, 0x9f1 },
+ { 0x9fc, 0x9fc },
+ { 0x9fe, 0x9fe },
+ { 0xa01, 0xa03 },
+ { 0xa05, 0xa0a },
+ { 0xa0f, 0xa10 },
+ { 0xa13, 0xa28 },
+ { 0xa2a, 0xa30 },
+ { 0xa32, 0xa33 },
+ { 0xa35, 0xa36 },
+ { 0xa38, 0xa39 },
+ { 0xa3c, 0xa3c },
+ { 0xa3e, 0xa42 },
+ { 0xa47, 0xa48 },
+ { 0xa4b, 0xa4d },
+ { 0xa51, 0xa51 },
+ { 0xa59, 0xa5c },
+ { 0xa5e, 0xa5e },
+ { 0xa66, 0xa75 },
+ { 0xa81, 0xa83 },
+ { 0xa85, 0xa8d },
+ { 0xa8f, 0xa91 },
+ { 0xa93, 0xaa8 },
+ { 0xaaa, 0xab0 },
+ { 0xab2, 0xab3 },
+ { 0xab5, 0xab9 },
+ { 0xabc, 0xac5 },
+ { 0xac7, 0xac9 },
+ { 0xacb, 0xacd },
+ { 0xad0, 0xad0 },
+ { 0xae0, 0xae3 },
+ { 0xae6, 0xaef },
+ { 0xaf9, 0xaff },
+ { 0xb01, 0xb03 },
+ { 0xb05, 0xb0c },
+ { 0xb0f, 0xb10 },
+ { 0xb13, 0xb28 },
+ { 0xb2a, 0xb30 },
+ { 0xb32, 0xb33 },
+ { 0xb35, 0xb39 },
+ { 0xb3c, 0xb44 },
+ { 0xb47, 0xb48 },
+ { 0xb4b, 0xb4d },
+ { 0xb55, 0xb57 },
+ { 0xb5c, 0xb5d },
+ { 0xb5f, 0xb63 },
+ { 0xb66, 0xb6f },
+ { 0xb71, 0xb71 },
+ { 0xb82, 0xb83 },
+ { 0xb85, 0xb8a },
+ { 0xb8e, 0xb90 },
+ { 0xb92, 0xb95 },
+ { 0xb99, 0xb9a },
+ { 0xb9c, 0xb9c },
+ { 0xb9e, 0xb9f },
+ { 0xba3, 0xba4 },
+ { 0xba8, 0xbaa },
+ { 0xbae, 0xbb9 },
+ { 0xbbe, 0xbc2 },
+ { 0xbc6, 0xbc8 },
+ { 0xbca, 0xbcd },
+ { 0xbd0, 0xbd0 },
+ { 0xbd7, 0xbd7 },
+ { 0xbe6, 0xbef },
+ { 0xc00, 0xc0c },
+ { 0xc0e, 0xc10 },
+ { 0xc12, 0xc28 },
+ { 0xc2a, 0xc39 },
+ { 0xc3c, 0xc44 },
+ { 0xc46, 0xc48 },
+ { 0xc4a, 0xc4d },
+ { 0xc55, 0xc56 },
+ { 0xc58, 0xc5a },
+ { 0xc5d, 0xc5d },
+ { 0xc60, 0xc63 },
+ { 0xc66, 0xc6f },
+ { 0xc80, 0xc83 },
+ { 0xc85, 0xc8c },
+ { 0xc8e, 0xc90 },
+ { 0xc92, 0xca8 },
+ { 0xcaa, 0xcb3 },
+ { 0xcb5, 0xcb9 },
+ { 0xcbc, 0xcc4 },
+ { 0xcc6, 0xcc8 },
+ { 0xcca, 0xccd },
+ { 0xcd5, 0xcd6 },
+ { 0xcdd, 0xcde },
+ { 0xce0, 0xce3 },
+ { 0xce6, 0xcef },
+ { 0xcf1, 0xcf2 },
+ { 0xd00, 0xd0c },
+ { 0xd0e, 0xd10 },
+ { 0xd12, 0xd44 },
+ { 0xd46, 0xd48 },
+ { 0xd4a, 0xd4e },
+ { 0xd54, 0xd57 },
+ { 0xd5f, 0xd63 },
+ { 0xd66, 0xd6f },
+ { 0xd7a, 0xd7f },
+ { 0xd81, 0xd83 },
+ { 0xd85, 0xd96 },
+ { 0xd9a, 0xdb1 },
+ { 0xdb3, 0xdbb },
+ { 0xdbd, 0xdbd },
+ { 0xdc0, 0xdc6 },
+ { 0xdca, 0xdca },
+ { 0xdcf, 0xdd4 },
+ { 0xdd6, 0xdd6 },
+ { 0xdd8, 0xddf },
+ { 0xde6, 0xdef },
+ { 0xdf2, 0xdf3 },
+ { 0xe01, 0xe3a },
+ { 0xe40, 0xe4e },
+ { 0xe50, 0xe59 },
+ { 0xe81, 0xe82 },
+ { 0xe84, 0xe84 },
+ { 0xe86, 0xe8a },
+ { 0xe8c, 0xea3 },
+ { 0xea5, 0xea5 },
+ { 0xea7, 0xebd },
+ { 0xec0, 0xec4 },
+ { 0xec6, 0xec6 },
+ { 0xec8, 0xecd },
+ { 0xed0, 0xed9 },
+ { 0xedc, 0xedf },
+ { 0xf00, 0xf00 },
+ { 0xf18, 0xf19 },
+ { 0xf20, 0xf29 },
+ { 0xf35, 0xf35 },
+ { 0xf37, 0xf37 },
+ { 0xf39, 0xf39 },
+ { 0xf3e, 0xf47 },
+ { 0xf49, 0xf6c },
+ { 0xf71, 0xf84 },
+ { 0xf86, 0xf97 },
+ { 0xf99, 0xfbc },
+ { 0xfc6, 0xfc6 },
+ { 0x1000, 0x1049 },
+ { 0x1050, 0x109d },
+ { 0x10a0, 0x10c5 },
+ { 0x10c7, 0x10c7 },
+ { 0x10cd, 0x10cd },
+ { 0x10d0, 0x10fa },
+ { 0x10fc, 0x1248 },
+ { 0x124a, 0x124d },
+ { 0x1250, 0x1256 },
+ { 0x1258, 0x1258 },
+ { 0x125a, 0x125d },
+ { 0x1260, 0x1288 },
+ { 0x128a, 0x128d },
+ { 0x1290, 0x12b0 },
+ { 0x12b2, 0x12b5 },
+ { 0x12b8, 0x12be },
+ { 0x12c0, 0x12c0 },
+ { 0x12c2, 0x12c5 },
+ { 0x12c8, 0x12d6 },
+ { 0x12d8, 0x1310 },
+ { 0x1312, 0x1315 },
+ { 0x1318, 0x135a },
+ { 0x135d, 0x135f },
+ { 0x1369, 0x1369 },
+ { 0x1371, 0x1371 },
+ { 0x1380, 0x138f },
+ { 0x13a0, 0x13f5 },
+ { 0x13f8, 0x13fd },
+ { 0x1401, 0x166c },
+ { 0x166f, 0x167f },
+ { 0x1681, 0x169a },
+ { 0x16a0, 0x16ea },
+ { 0x16ee, 0x16f8 },
+ { 0x1700, 0x1715 },
+ { 0x171f, 0x1734 },
+ { 0x1740, 0x1753 },
+ { 0x1760, 0x176c },
+ { 0x176e, 0x1770 },
+ { 0x1772, 0x1773 },
+ { 0x1780, 0x17d3 },
+ { 0x17d7, 0x17d7 },
+ { 0x17dc, 0x17dd },
+ { 0x17e0, 0x17e9 },
+ { 0x180b, 0x180d },
+ { 0x180f, 0x1819 },
+ { 0x1820, 0x1878 },
+ { 0x1880, 0x18aa },
+ { 0x18b0, 0x18f5 },
+ { 0x1900, 0x191e },
+ { 0x1920, 0x192b },
+ { 0x1930, 0x193b },
+ { 0x1946, 0x196d },
+ { 0x1970, 0x1974 },
+ { 0x1980, 0x19ab },
+ { 0x19b0, 0x19c9 },
+ { 0x19d0, 0x19da },
+ { 0x1a00, 0x1a1b },
+ { 0x1a20, 0x1a5e },
+ { 0x1a60, 0x1a7c },
+ { 0x1a7f, 0x1a89 },
+ { 0x1a90, 0x1a99 },
+ { 0x1aa7, 0x1aa7 },
+ { 0x1ab0, 0x1abd },
+ { 0x1abf, 0x1ace },
+ { 0x1b00, 0x1b4c },
+ { 0x1b50, 0x1b59 },
+ { 0x1b6b, 0x1b73 },
+ { 0x1b80, 0x1bf3 },
+ { 0x1c00, 0x1c37 },
+ { 0x1c40, 0x1c49 },
+ { 0x1c4d, 0x1c7d },
+ { 0x1c80, 0x1c88 },
+ { 0x1c90, 0x1cba },
+ { 0x1cbd, 0x1cbf },
+ { 0x1cd0, 0x1cd2 },
+ { 0x1cd4, 0x1cfa },
+ { 0x1d00, 0x1f15 },
+ { 0x1f18, 0x1f1d },
+ { 0x1f20, 0x1f45 },
+ { 0x1f48, 0x1f4d },
+ { 0x1f50, 0x1f57 },
+ { 0x1f59, 0x1f59 },
+ { 0x1f5b, 0x1f5b },
+ { 0x1f5d, 0x1f5d },
+ { 0x1f5f, 0x1f7d },
+ { 0x1f80, 0x1fb4 },
+ { 0x1fb6, 0x1fbc },
+ { 0x1fbe, 0x1fbe },
+ { 0x1fc2, 0x1fc4 },
+ { 0x1fc6, 0x1fcc },
+ { 0x1fd0, 0x1fd3 },
+ { 0x1fd6, 0x1fdb },
+ { 0x1fe0, 0x1fec },
+ { 0x1ff2, 0x1ff4 },
+ { 0x1ff6, 0x1ffc },
+ { 0x203f, 0x2040 },
+ { 0x2054, 0x2054 },
+ { 0x2071, 0x2071 },
+ { 0x207f, 0x207f },
+ { 0x2090, 0x209c },
+ { 0x20d0, 0x20dc },
+ { 0x20e1, 0x20e1 },
+ { 0x20e5, 0x20f0 },
+ { 0x2102, 0x2102 },
+ { 0x2107, 0x2107 },
+ { 0x210a, 0x2113 },
+ { 0x2115, 0x2115 },
+ { 0x2118, 0x211d },
+ { 0x2124, 0x2124 },
+ { 0x2126, 0x2126 },
+ { 0x2128, 0x2128 },
+ { 0x212a, 0x2139 },
+ { 0x213c, 0x213f },
+ { 0x2145, 0x2149 },
+ { 0x214e, 0x214e },
+ { 0x2160, 0x2188 },
+ { 0x2c00, 0x2ce4 },
+ { 0x2ceb, 0x2cf3 },
+ { 0x2d00, 0x2d25 },
+ { 0x2d27, 0x2d27 },
+ { 0x2d2d, 0x2d2d },
+ { 0x2d30, 0x2d67 },
+ { 0x2d6f, 0x2d6f },
+ { 0x2d7f, 0x2d96 },
+ { 0x2da0, 0x2da6 },
+ { 0x2da8, 0x2dae },
+ { 0x2db0, 0x2db6 },
+ { 0x2db8, 0x2dbe },
+ { 0x2dc0, 0x2dc6 },
+ { 0x2dc8, 0x2dce },
+ { 0x2dd0, 0x2dd6 },
+ { 0x2dd8, 0x2dde },
+ { 0x2de0, 0x2dff },
+ { 0x3005, 0x3007 },
+ { 0x3021, 0x302f },
+ { 0x3031, 0x3035 },
+ { 0x3038, 0x303c },
+ { 0x3041, 0x3096 },
+ { 0x3099, 0x309f },
+ { 0x30a1, 0x30fa },
+ { 0x30fc, 0x30ff },
+ { 0x3105, 0x312f },
+ { 0x3131, 0x318e },
+ { 0x31a0, 0x31bf },
+ { 0x31f0, 0x31ff },
+ { 0x3400, 0x4dbf },
+ { 0x4e00, 0xa48c },
+ { 0xa4d0, 0xa4fd },
+ { 0xa500, 0xa60c },
+ { 0xa610, 0xa62b },
+ { 0xa640, 0xa66f },
+ { 0xa674, 0xa67d },
+ { 0xa67f, 0xa6f1 },
+ { 0xa717, 0xa71f },
+ { 0xa722, 0xa788 },
+ { 0xa78b, 0xa7ca },
+ { 0xa7d0, 0xa7d1 },
+ { 0xa7d3, 0xa7d3 },
+ { 0xa7d5, 0xa7d9 },
+ { 0xa7f2, 0xa827 },
+ { 0xa82c, 0xa82c },
+ { 0xa840, 0xa873 },
+ { 0xa880, 0xa8c5 },
+ { 0xa8d0, 0xa8d9 },
+ { 0xa8e0, 0xa8f7 },
+ { 0xa8fb, 0xa8fb },
+ { 0xa8fd, 0xa92d },
+ { 0xa930, 0xa953 },
+ { 0xa960, 0xa97c },
+ { 0xa980, 0xa9c0 },
+ { 0xa9cf, 0xa9d9 },
+ { 0xa9e0, 0xa9fe },
+ { 0xaa00, 0xaa36 },
+ { 0xaa40, 0xaa4d },
+ { 0xaa50, 0xaa59 },
+ { 0xaa60, 0xaa76 },
+ { 0xaa7a, 0xaac2 },
+ { 0xaadb, 0xaadd },
+ { 0xaae0, 0xaaef },
+ { 0xaaf2, 0xaaf6 },
+ { 0xab01, 0xab06 },
+ { 0xab09, 0xab0e },
+ { 0xab11, 0xab16 },
+ { 0xab20, 0xab26 },
+ { 0xab28, 0xab2e },
+ { 0xab30, 0xab5a },
+ { 0xab5c, 0xab69 },
+ { 0xab70, 0xabea },
+ { 0xabec, 0xabed },
+ { 0xabf0, 0xabf9 },
+ { 0xac00, 0xd7a3 },
+ { 0xd7b0, 0xd7c6 },
+ { 0xd7cb, 0xd7fb },
+ { 0xf900, 0xfa6d },
+ { 0xfa70, 0xfad9 },
+ { 0xfb00, 0xfb06 },
+ { 0xfb13, 0xfb17 },
+ { 0xfb1d, 0xfb28 },
+ { 0xfb2a, 0xfb36 },
+ { 0xfb38, 0xfb3c },
+ { 0xfb3e, 0xfb3e },
+ { 0xfb40, 0xfb41 },
+ { 0xfb43, 0xfb44 },
+ { 0xfb46, 0xfbb1 },
+ { 0xfbd3, 0xfd3d },
+ { 0xfd50, 0xfd8f },
+ { 0xfd92, 0xfdc7 },
+ { 0xfdf0, 0xfdfb },
+ { 0xfe00, 0xfe0f },
+ { 0xfe20, 0xfe2f },
+ { 0xfe33, 0xfe34 },
+ { 0xfe4d, 0xfe4f },
+ { 0xfe70, 0xfe74 },
+ { 0xfe76, 0xfefc },
+ { 0xff10, 0xff19 },
+ { 0xff21, 0xff3a },
+ { 0xff3f, 0xff3f },
+ { 0xff41, 0xff5a },
+ { 0xff66, 0xffbe },
+ { 0xffc2, 0xffc7 },
+ { 0xffca, 0xffcf },
+ { 0xffd2, 0xffd7 },
+ { 0xffda, 0xffdc },
+ { 0x10000, 0x1000b },
+ { 0x1000d, 0x10026 },
+ { 0x10028, 0x1003a },
+ { 0x1003c, 0x1003d },
+ { 0x1003f, 0x1004d },
+ { 0x10050, 0x1005d },
+ { 0x10080, 0x100fa },
+ { 0x10140, 0x10174 },
+ { 0x101fd, 0x101fd },
+ { 0x10280, 0x1029c },
+ { 0x102a0, 0x102d0 },
+ { 0x102e0, 0x102e0 },
+ { 0x10300, 0x1031f },
+ { 0x1032d, 0x1034a },
+ { 0x10350, 0x1037a },
+ { 0x10380, 0x1039d },
+ { 0x103a0, 0x103c3 },
+ { 0x103c8, 0x103cf },
+ { 0x103d1, 0x103d5 },
+ { 0x10400, 0x1049d },
+ { 0x104a0, 0x104a9 },
+ { 0x104b0, 0x104d3 },
+ { 0x104d8, 0x104fb },
+ { 0x10500, 0x10527 },
+ { 0x10530, 0x10563 },
+ { 0x10570, 0x1057a },
+ { 0x1057c, 0x1058a },
+ { 0x1058c, 0x10592 },
+ { 0x10594, 0x10595 },
+ { 0x10597, 0x105a1 },
+ { 0x105a3, 0x105b1 },
+ { 0x105b3, 0x105b9 },
+ { 0x105bb, 0x105bc },
+ { 0x10600, 0x10736 },
+ { 0x10740, 0x10755 },
+ { 0x10760, 0x10767 },
+ { 0x10780, 0x10785 },
+ { 0x10787, 0x107b0 },
+ { 0x107b2, 0x107ba },
+ { 0x10800, 0x10805 },
+ { 0x10808, 0x10808 },
+ { 0x1080a, 0x10835 },
+ { 0x10837, 0x10838 },
+ { 0x1083c, 0x1083c },
+ { 0x1083f, 0x10855 },
+ { 0x10860, 0x10876 },
+ { 0x10880, 0x1089e },
+ { 0x108e0, 0x108f2 },
+ { 0x108f4, 0x108f5 },
+ { 0x10900, 0x10915 },
+ { 0x10920, 0x10939 },
+ { 0x10980, 0x109b7 },
+ { 0x109be, 0x109bf },
+ { 0x10a00, 0x10a03 },
+ { 0x10a05, 0x10a06 },
+ { 0x10a0c, 0x10a13 },
+ { 0x10a15, 0x10a17 },
+ { 0x10a19, 0x10a35 },
+ { 0x10a38, 0x10a3a },
+ { 0x10a3f, 0x10a3f },
+ { 0x10a60, 0x10a7c },
+ { 0x10a80, 0x10a9c },
+ { 0x10ac0, 0x10ac7 },
+ { 0x10ac9, 0x10ae6 },
+ { 0x10b00, 0x10b35 },
+ { 0x10b40, 0x10b55 },
+ { 0x10b60, 0x10b72 },
+ { 0x10b80, 0x10b91 },
+ { 0x10c00, 0x10c48 },
+ { 0x10c80, 0x10cb2 },
+ { 0x10cc0, 0x10cf2 },
+ { 0x10d00, 0x10d27 },
+ { 0x10d30, 0x10d39 },
+ { 0x10e80, 0x10ea9 },
+ { 0x10eab, 0x10eac },
+ { 0x10eb0, 0x10eb1 },
+ { 0x10f00, 0x10f1c },
+ { 0x10f27, 0x10f27 },
+ { 0x10f30, 0x10f50 },
+ { 0x10f70, 0x10f85 },
+ { 0x10fb0, 0x10fc4 },
+ { 0x10fe0, 0x10ff6 },
+ { 0x11000, 0x11046 },
+ { 0x11066, 0x11075 },
+ { 0x1107f, 0x110ba },
+ { 0x110c2, 0x110c2 },
+ { 0x110d0, 0x110e8 },
+ { 0x110f0, 0x110f9 },
+ { 0x11100, 0x11134 },
+ { 0x11136, 0x1113f },
+ { 0x11144, 0x11147 },
+ { 0x11150, 0x11173 },
+ { 0x11176, 0x11176 },
+ { 0x11180, 0x111c4 },
+ { 0x111c9, 0x111cc },
+ { 0x111ce, 0x111da },
+ { 0x111dc, 0x111dc },
+ { 0x11200, 0x11211 },
+ { 0x11213, 0x11237 },
+ { 0x1123e, 0x1123e },
+ { 0x11280, 0x11286 },
+ { 0x11288, 0x11288 },
+ { 0x1128a, 0x1128d },
+ { 0x1128f, 0x1129d },
+ { 0x1129f, 0x112a8 },
+ { 0x112b0, 0x112ea },
+ { 0x112f0, 0x112f9 },
+ { 0x11300, 0x11303 },
+ { 0x11305, 0x1130c },
+ { 0x1130f, 0x11310 },
+ { 0x11313, 0x11328 },
+ { 0x1132a, 0x11330 },
+ { 0x11332, 0x11333 },
+ { 0x11335, 0x11339 },
+ { 0x1133b, 0x11344 },
+ { 0x11347, 0x11348 },
+ { 0x1134b, 0x1134d },
+ { 0x11350, 0x11350 },
+ { 0x11357, 0x11357 },
+ { 0x1135d, 0x11363 },
+ { 0x11366, 0x1136c },
+ { 0x11370, 0x11374 },
+ { 0x11400, 0x1144a },
+ { 0x11450, 0x11459 },
+ { 0x1145e, 0x11461 },
+ { 0x11480, 0x114c5 },
+ { 0x114c7, 0x114c7 },
+ { 0x114d0, 0x114d9 },
+ { 0x11580, 0x115b5 },
+ { 0x115b8, 0x115c0 },
+ { 0x115d8, 0x115dd },
+ { 0x11600, 0x11640 },
+ { 0x11644, 0x11644 },
+ { 0x11650, 0x11659 },
+ { 0x11680, 0x116b8 },
+ { 0x116c0, 0x116c9 },
+ { 0x11700, 0x1171a },
+ { 0x1171d, 0x1172b },
+ { 0x11730, 0x11739 },
+ { 0x11740, 0x11746 },
+ { 0x11800, 0x1183a },
+ { 0x118a0, 0x118e9 },
+ { 0x118ff, 0x11906 },
+ { 0x11909, 0x11909 },
+ { 0x1190c, 0x11913 },
+ { 0x11915, 0x11916 },
+ { 0x11918, 0x11935 },
+ { 0x11937, 0x11938 },
+ { 0x1193b, 0x11943 },
+ { 0x11950, 0x11959 },
+ { 0x119a0, 0x119a7 },
+ { 0x119aa, 0x119d7 },
+ { 0x119da, 0x119e1 },
+ { 0x119e3, 0x119e4 },
+ { 0x11a00, 0x11a3e },
+ { 0x11a47, 0x11a47 },
+ { 0x11a50, 0x11a99 },
+ { 0x11a9d, 0x11a9d },
+ { 0x11ab0, 0x11af8 },
+ { 0x11c00, 0x11c08 },
+ { 0x11c0a, 0x11c36 },
+ { 0x11c38, 0x11c40 },
+ { 0x11c50, 0x11c59 },
+ { 0x11c72, 0x11c8f },
+ { 0x11c92, 0x11ca7 },
+ { 0x11ca9, 0x11cb6 },
+ { 0x11d00, 0x11d06 },
+ { 0x11d08, 0x11d09 },
+ { 0x11d0b, 0x11d36 },
+ { 0x11d3a, 0x11d3a },
+ { 0x11d3c, 0x11d3d },
+ { 0x11d3f, 0x11d47 },
+ { 0x11d50, 0x11d59 },
+ { 0x11d60, 0x11d65 },
+ { 0x11d67, 0x11d68 },
+ { 0x11d6a, 0x11d8e },
+ { 0x11d90, 0x11d91 },
+ { 0x11d93, 0x11d98 },
+ { 0x11da0, 0x11da9 },
+ { 0x11ee0, 0x11ef6 },
+ { 0x11fb0, 0x11fb0 },
+ { 0x12000, 0x12399 },
+ { 0x12400, 0x1246e },
+ { 0x12480, 0x12543 },
+ { 0x12f90, 0x12ff0 },
+ { 0x13000, 0x1342e },
+ { 0x14400, 0x14646 },
+ { 0x16800, 0x16a38 },
+ { 0x16a40, 0x16a5e },
+ { 0x16a60, 0x16a69 },
+ { 0x16a70, 0x16abe },
+ { 0x16ac0, 0x16ac9 },
+ { 0x16ad0, 0x16aed },
+ { 0x16af0, 0x16af4 },
+ { 0x16b00, 0x16b36 },
+ { 0x16b40, 0x16b43 },
+ { 0x16b50, 0x16b59 },
+ { 0x16b63, 0x16b77 },
+ { 0x16b7d, 0x16b8f },
+ { 0x16e40, 0x16e7f },
+ { 0x16f00, 0x16f4a },
+ { 0x16f4f, 0x16f87 },
+ { 0x16f8f, 0x16f9f },
+ { 0x16fe0, 0x16fe1 },
+ { 0x16fe3, 0x16fe4 },
+ { 0x16ff0, 0x16ff1 },
+ { 0x17000, 0x187f7 },
+ { 0x18800, 0x18cd5 },
+ { 0x18d00, 0x18d08 },
+ { 0x1aff0, 0x1aff3 },
+ { 0x1aff5, 0x1affb },
+ { 0x1affd, 0x1affe },
+ { 0x1b000, 0x1b122 },
+ { 0x1b150, 0x1b152 },
+ { 0x1b164, 0x1b167 },
+ { 0x1b170, 0x1b2fb },
+ { 0x1bc00, 0x1bc6a },
+ { 0x1bc70, 0x1bc7c },
+ { 0x1bc80, 0x1bc88 },
+ { 0x1bc90, 0x1bc99 },
+ { 0x1bc9d, 0x1bc9e },
+ { 0x1cf00, 0x1cf2d },
+ { 0x1cf30, 0x1cf46 },
+ { 0x1d165, 0x1d169 },
+ { 0x1d16d, 0x1d172 },
+ { 0x1d17b, 0x1d182 },
+ { 0x1d185, 0x1d18b },
+ { 0x1d1aa, 0x1d1ad },
+ { 0x1d242, 0x1d244 },
+ { 0x1d400, 0x1d454 },
+ { 0x1d456, 0x1d49c },
+ { 0x1d49e, 0x1d49f },
+ { 0x1d4a2, 0x1d4a2 },
+ { 0x1d4a5, 0x1d4a6 },
+ { 0x1d4a9, 0x1d4ac },
+ { 0x1d4ae, 0x1d4b9 },
+ { 0x1d4bb, 0x1d4bb },
+ { 0x1d4bd, 0x1d4c3 },
+ { 0x1d4c5, 0x1d505 },
+ { 0x1d507, 0x1d50a },
+ { 0x1d50d, 0x1d514 },
+ { 0x1d516, 0x1d51c },
+ { 0x1d51e, 0x1d539 },
+ { 0x1d53b, 0x1d53e },
+ { 0x1d540, 0x1d544 },
+ { 0x1d546, 0x1d546 },
+ { 0x1d54a, 0x1d550 },
+ { 0x1d552, 0x1d6a5 },
+ { 0x1d6a8, 0x1d6c0 },
+ { 0x1d6c2, 0x1d6da },
+ { 0x1d6dc, 0x1d6fa },
+ { 0x1d6fc, 0x1d714 },
+ { 0x1d716, 0x1d734 },
+ { 0x1d736, 0x1d74e },
+ { 0x1d750, 0x1d76e },
+ { 0x1d770, 0x1d788 },
+ { 0x1d78a, 0x1d7a8 },
+ { 0x1d7aa, 0x1d7c2 },
+ { 0x1d7c4, 0x1d7cb },
+ { 0x1d7ce, 0x1d7ff },
+ { 0x1da00, 0x1da36 },
+ { 0x1da3b, 0x1da6c },
+ { 0x1da75, 0x1da75 },
+ { 0x1da84, 0x1da84 },
+ { 0x1da9b, 0x1da9f },
+ { 0x1daa1, 0x1daaf },
+ { 0x1df00, 0x1df1e },
+ { 0x1e000, 0x1e006 },
+ { 0x1e008, 0x1e018 },
+ { 0x1e01b, 0x1e021 },
+ { 0x1e023, 0x1e024 },
+ { 0x1e026, 0x1e02a },
+ { 0x1e100, 0x1e12c },
+ { 0x1e130, 0x1e13d },
+ { 0x1e140, 0x1e149 },
+ { 0x1e14e, 0x1e14e },
+ { 0x1e290, 0x1e2ae },
+ { 0x1e2c0, 0x1e2f9 },
+ { 0x1e7e0, 0x1e7e6 },
+ { 0x1e7e8, 0x1e7eb },
+ { 0x1e7ed, 0x1e7ee },
+ { 0x1e7f0, 0x1e7fe },
+ { 0x1e800, 0x1e8c4 },
+ { 0x1e8d0, 0x1e8d6 },
+ { 0x1e900, 0x1e94b },
+ { 0x1e950, 0x1e959 },
+ { 0x1ee00, 0x1ee03 },
+ { 0x1ee05, 0x1ee1f },
+ { 0x1ee21, 0x1ee22 },
+ { 0x1ee24, 0x1ee24 },
+ { 0x1ee27, 0x1ee27 },
+ { 0x1ee29, 0x1ee32 },
+ { 0x1ee34, 0x1ee37 },
+ { 0x1ee39, 0x1ee39 },
+ { 0x1ee3b, 0x1ee3b },
+ { 0x1ee42, 0x1ee42 },
+ { 0x1ee47, 0x1ee47 },
+ { 0x1ee49, 0x1ee49 },
+ { 0x1ee4b, 0x1ee4b },
+ { 0x1ee4d, 0x1ee4f },
+ { 0x1ee51, 0x1ee52 },
+ { 0x1ee54, 0x1ee54 },
+ { 0x1ee57, 0x1ee57 },
+ { 0x1ee59, 0x1ee59 },
+ { 0x1ee5b, 0x1ee5b },
+ { 0x1ee5d, 0x1ee5d },
+ { 0x1ee5f, 0x1ee5f },
+ { 0x1ee61, 0x1ee62 },
+ { 0x1ee64, 0x1ee64 },
+ { 0x1ee67, 0x1ee6a },
+ { 0x1ee6c, 0x1ee72 },
+ { 0x1ee74, 0x1ee77 },
+ { 0x1ee79, 0x1ee7c },
+ { 0x1ee7e, 0x1ee7e },
+ { 0x1ee80, 0x1ee89 },
+ { 0x1ee8b, 0x1ee9b },
+ { 0x1eea1, 0x1eea3 },
+ { 0x1eea5, 0x1eea9 },
+ { 0x1eeab, 0x1eebb },
+ { 0x1fbf0, 0x1fbf9 },
+ { 0x20000, 0x2a6df },
+ { 0x2a700, 0x2b738 },
+ { 0x2b740, 0x2b81d },
+ { 0x2b820, 0x2cea1 },
+ { 0x2ceb0, 0x2ebe0 },
+ { 0x2f800, 0x2fa1d },
+ { 0x30000, 0x3134a },
+ { 0xe0100, 0xe01ef },
+ { 0x0, 0x0 },
+};
+
+#endif // CHAR_RANGE_INC
diff --git a/core/string/char_utils.h b/core/string/char_utils.h
index 0afd058f01..67147a4327 100644
--- a/core/string/char_utils.h
+++ b/core/string/char_utils.h
@@ -33,6 +33,26 @@
#include "core/typedefs.h"
+#include "char_range.inc"
+
+static _FORCE_INLINE_ bool is_unicode_identifier_start(char32_t c) {
+ for (int i = 0; xid_start[i].start != 0; i++) {
+ if (c >= xid_start[i].start && c <= xid_start[i].end) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static _FORCE_INLINE_ bool is_unicode_identifier_continue(char32_t c) {
+ for (int i = 0; xid_continue[i].start != 0; i++) {
+ if (c >= xid_continue[i].start && c <= xid_continue[i].end) {
+ return true;
+ }
+ }
+ return false;
+}
+
static _FORCE_INLINE_ bool is_ascii_upper_case(char32_t c) {
return (c >= 'A' && c <= 'Z');
}
diff --git a/core/string/print_string.cpp b/core/string/print_string.cpp
index f58486e0a5..592da58fe7 100644
--- a/core/string/print_string.cpp
+++ b/core/string/print_string.cpp
@@ -30,13 +30,12 @@
#include "print_string.h"
+#include "core/core_globals.h"
#include "core/os/os.h"
#include <stdio.h>
static PrintHandlerList *print_handler_list = nullptr;
-bool _print_line_enabled = true;
-bool _print_error_enabled = true;
void add_print_handler(PrintHandlerList *p_handler) {
_global_lock();
@@ -70,7 +69,7 @@ void remove_print_handler(const PrintHandlerList *p_handler) {
}
void __print_line(String p_string) {
- if (!_print_line_enabled) {
+ if (!CoreGlobals::print_line_enabled) {
return;
}
@@ -87,7 +86,7 @@ void __print_line(String p_string) {
}
void __print_line_rich(String p_string) {
- if (!_print_line_enabled) {
+ if (!CoreGlobals::print_line_enabled) {
return;
}
@@ -178,7 +177,7 @@ void __print_line_rich(String p_string) {
}
void print_error(String p_string) {
- if (!_print_error_enabled) {
+ if (!CoreGlobals::print_error_enabled) {
return;
}
diff --git a/core/string/print_string.h b/core/string/print_string.h
index 823e2c29e8..ca930a3a0f 100644
--- a/core/string/print_string.h
+++ b/core/string/print_string.h
@@ -56,8 +56,6 @@ String stringify_variants(Variant p_var, Args... p_args) {
void add_print_handler(PrintHandlerList *p_handler);
void remove_print_handler(const PrintHandlerList *p_handler);
-extern bool _print_line_enabled;
-extern bool _print_error_enabled;
extern void __print_line(String p_string);
extern void __print_line_rich(String p_string);
extern void print_error(String p_string);
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index cba2f09022..4748f1a0cb 100644
--- a/core/string/translation.cpp
+++ b/core/string/translation.cpp
@@ -70,7 +70,7 @@ void Translation::_set_messages(const Dictionary &p_messages) {
void Translation::set_locale(const String &p_locale) {
locale = TranslationServer::get_singleton()->standardize_locale(p_locale);
- if (OS::get_singleton()->get_main_loop() && TranslationServer::get_singleton()->get_loaded_locales().has(this)) {
+ if (OS::get_singleton()->get_main_loop() && TranslationServer::get_singleton()->get_loaded_locales().has(get_locale())) {
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TRANSLATION_CHANGED);
}
}
@@ -141,7 +141,7 @@ void Translation::_bind_methods() {
ClassDB::bind_method(D_METHOD("erase_message", "src_message", "context"), &Translation::erase_message, DEFVAL(""));
ClassDB::bind_method(D_METHOD("get_message_list"), &Translation::_get_message_list);
ClassDB::bind_method(D_METHOD("get_message_count"), &Translation::get_message_count);
- ClassDB::bind_method(D_METHOD("_set_messages"), &Translation::_set_messages);
+ ClassDB::bind_method(D_METHOD("_set_messages", "messages"), &Translation::_set_messages);
ClassDB::bind_method(D_METHOD("_get_messages"), &Translation::_get_messages);
GDVIRTUAL_BIND(_get_plural_message, "src_message", "src_plural_message", "n", "context");
@@ -505,11 +505,11 @@ String TranslationServer::get_locale() const {
return locale;
}
-Array TranslationServer::get_loaded_locales() const {
- Array locales;
+PackedStringArray TranslationServer::get_loaded_locales() const {
+ PackedStringArray locales;
for (const Ref<Translation> &E : translations) {
const Ref<Translation> &t = E;
- ERR_FAIL_COND_V(t.is_null(), Array());
+ ERR_FAIL_COND_V(t.is_null(), PackedStringArray());
String l = t->get_locale();
locales.push_back(l);
diff --git a/core/string/translation.h b/core/string/translation.h
index 20c6ebd5a5..3f97a8d4fc 100644
--- a/core/string/translation.h
+++ b/core/string/translation.h
@@ -145,7 +145,7 @@ public:
String get_locale_name(const String &p_locale) const;
- Array get_loaded_locales() const;
+ PackedStringArray get_loaded_locales() const;
void add_translation(const Ref<Translation> &p_translation);
void remove_translation(const Ref<Translation> &p_translation);
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index beefe54faf..ed3d4b0b54 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -531,10 +531,12 @@ String &String::operator+=(const String &p_str) {
resize(lhs_len + rhs_len + 1);
- const char32_t *src = p_str.get_data();
+ const char32_t *src = p_str.ptr();
char32_t *dst = ptrw() + lhs_len;
- memcpy(dst, src, (rhs_len + 1) * sizeof(char32_t));
+ // Don't copy the terminating null with `memcpy` to avoid undefined behavior when string is being added to itself (it would overlap the destination).
+ memcpy(dst, src, rhs_len * sizeof(char32_t));
+ *(dst + rhs_len) = _null;
return *this;
}
@@ -1656,7 +1658,7 @@ String String::utf8(const char *p_utf8, int p_len) {
return ret;
}
-Error String::parse_utf8(const char *p_utf8, int p_len) {
+Error String::parse_utf8(const char *p_utf8, int p_len, bool p_skip_cr) {
if (!p_utf8) {
return ERR_INVALID_DATA;
}
@@ -1689,6 +1691,10 @@ Error String::parse_utf8(const char *p_utf8, int p_len) {
uint8_t c = *ptrtmp >= 0 ? *ptrtmp : uint8_t(256 + *ptrtmp);
if (skip == 0) {
+ if (p_skip_cr && c == '\r') {
+ ptrtmp++;
+ continue;
+ }
/* Determine the number of characters in sequence */
if ((c & 0x80) == 0) {
skip = 0;
@@ -1753,6 +1759,10 @@ Error String::parse_utf8(const char *p_utf8, int p_len) {
uint8_t c = *p_utf8 >= 0 ? *p_utf8 : uint8_t(256 + *p_utf8);
if (skip == 0) {
+ if (p_skip_cr && c == '\r') {
+ p_utf8++;
+ continue;
+ }
/* Determine the number of characters in sequence */
if ((c & 0x80) == 0) {
*(dst++) = c;
@@ -3441,18 +3451,19 @@ String String::replacen(const String &p_key, const String &p_with) const {
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 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++) {
- new_string[i * length() + j] = src[j];
- }
- }
-
+ int len = length();
+ String new_string = *this;
+ new_string.resize(p_count * len + 1);
+
+ char32_t *dst = new_string.ptrw();
+ int offset = 1;
+ int stride = 1;
+ while (offset < p_count) {
+ memcpy(dst + offset * len, dst, stride * len * sizeof(char32_t));
+ offset += stride;
+ stride = MIN(stride * 2, p_count - offset);
+ }
+ dst[p_count * len] = _null;
return new_string;
}
@@ -4440,7 +4451,7 @@ String String::get_extension() const {
return substr(pos + 1, length());
}
-String String::plus_file(const String &p_file) const {
+String String::path_join(const String &p_file) const {
if (is_empty()) {
return p_file;
}
@@ -4656,6 +4667,71 @@ String String::sprintf(const Array &values, bool *error) const {
in_format = false;
break;
}
+ case 'v': { // Vector2/3/4/2i/3i/4i
+ if (value_index >= values.size()) {
+ return "not enough arguments for format string";
+ }
+
+ int count;
+ switch (values[value_index].get_type()) {
+ case Variant::VECTOR2:
+ case Variant::VECTOR2I: {
+ count = 2;
+ } break;
+ case Variant::VECTOR3:
+ case Variant::VECTOR3I: {
+ count = 3;
+ } break;
+ case Variant::VECTOR4:
+ case Variant::VECTOR4I: {
+ count = 4;
+ } break;
+ default: {
+ return "%v requires a vector type (Vector2/3/4/2i/3i/4i)";
+ }
+ }
+
+ Vector4 vec = values[value_index];
+ String str = "(";
+ for (int i = 0; i < count; i++) {
+ double val = vec[i];
+ // Pad decimals out.
+ String number_str = String::num(ABS(val), min_decimals).pad_decimals(min_decimals);
+
+ int initial_len = number_str.length();
+
+ // Padding. Leave room for sign later if required.
+ int pad_chars_count = val < 0 ? min_chars - 1 : min_chars;
+ String pad_char = pad_with_zeros ? String("0") : String(" ");
+ if (left_justified) {
+ number_str = number_str.rpad(pad_chars_count, pad_char);
+ } else {
+ number_str = number_str.lpad(pad_chars_count, pad_char);
+ }
+
+ // Add sign if needed.
+ if (val < 0) {
+ if (left_justified) {
+ number_str = number_str.insert(0, "-");
+ } else {
+ number_str = number_str.insert(pad_with_zeros ? 0 : number_str.length() - initial_len, "-");
+ }
+ }
+
+ // Add number to combined string
+ str += number_str;
+
+ if (i < count - 1) {
+ str += ", ";
+ }
+ }
+ str += ")";
+
+ formatted += str;
+ ++value_index;
+ in_format = false;
+ break;
+ }
case 's': { // String
if (value_index >= values.size()) {
return "not enough arguments for format string";
@@ -4748,7 +4824,7 @@ String String::sprintf(const Array &values, bool *error) const {
}
break;
}
- case '.': { // Float separator.
+ case '.': { // Float/Vector separator.
if (in_decimals) {
return "too many decimal points in format";
}
@@ -4762,8 +4838,12 @@ String String::sprintf(const Array &values, bool *error) const {
return "not enough arguments for format string";
}
- if (!values[value_index].is_num()) {
- return "* wants number";
+ Variant::Type value_type = values[value_index].get_type();
+ if (!values[value_index].is_num() &&
+ value_type != Variant::VECTOR2 && value_type != Variant::VECTOR2I &&
+ value_type != Variant::VECTOR3 && value_type != Variant::VECTOR3I &&
+ value_type != Variant::VECTOR4 && value_type != Variant::VECTOR4I) {
+ return "* wants number or vector";
}
int size = values[value_index];
diff --git a/core/string/ustring.h b/core/string/ustring.h
index 7672663964..2463fc35f7 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -370,14 +370,14 @@ public:
String rstrip(const String &p_chars) const;
String get_extension() const;
String get_basename() const;
- String plus_file(const String &p_file) const;
+ String path_join(const String &p_file) const;
char32_t unicode_at(int p_idx) const;
void erase(int p_pos, int p_chars);
CharString ascii(bool p_allow_extended = false) const;
CharString utf8() const;
- Error parse_utf8(const char *p_utf8, int p_len = -1);
+ Error parse_utf8(const char *p_utf8, int p_len = -1, bool p_skip_cr = false);
static String utf8(const char *p_utf8, int p_len = -1);
Char16String utf16() const;
diff --git a/core/templates/cowdata.h b/core/templates/cowdata.h
index e760fc2176..f98b2308c9 100644
--- a/core/templates/cowdata.h
+++ b/core/templates/cowdata.h
@@ -36,6 +36,7 @@
#include "core/templates/safe_refcount.h"
#include <string.h>
+#include <type_traits>
template <class T>
class Vector;
@@ -158,6 +159,7 @@ public:
return _ptr[p_index];
}
+ template <bool p_ensure_zero = false>
Error resize(int p_size);
_FORCE_INLINE_ void remove_at(int p_index) {
@@ -204,7 +206,7 @@ void CowData<T>::_unref(void *p_data) {
}
// clean up
- if (!__has_trivial_destructor(T)) {
+ if (!std::is_trivially_destructible<T>::value) {
uint32_t *count = _get_size();
T *data = (T *)(count + 1);
@@ -239,7 +241,7 @@ uint32_t CowData<T>::_copy_on_write() {
T *_data = (T *)(mem_new);
// initialize new elements
- if (__has_trivial_copy(T)) {
+ if (std::is_trivially_copyable<T>::value) {
memcpy(mem_new, _ptr, current_size * sizeof(T));
} else {
@@ -257,6 +259,7 @@ uint32_t CowData<T>::_copy_on_write() {
}
template <class T>
+template <bool p_ensure_zero>
Error CowData<T>::resize(int p_size) {
ERR_FAIL_COND_V(p_size < 0, ERR_INVALID_PARAMETER);
@@ -302,16 +305,18 @@ Error CowData<T>::resize(int p_size) {
// construct the newly created elements
- if (!__has_trivial_constructor(T)) {
+ if (!std::is_trivially_constructible<T>::value) {
for (int i = *_get_size(); i < p_size; i++) {
memnew_placement(&_ptr[i], T);
}
+ } else if (p_ensure_zero) {
+ memset((void *)(_ptr + current_size), 0, (p_size - current_size) * sizeof(T));
}
*_get_size() = p_size;
} else if (p_size < current_size) {
- if (!__has_trivial_destructor(T)) {
+ if (!std::is_trivially_destructible<T>::value) {
// deinitialize no longer needed elements
for (uint32_t i = p_size; i < *_get_size(); i++) {
T *t = &_ptr[i];
diff --git a/core/templates/local_vector.h b/core/templates/local_vector.h
index 8d687effcf..49690f2373 100644
--- a/core/templates/local_vector.h
+++ b/core/templates/local_vector.h
@@ -37,6 +37,7 @@
#include "core/templates/vector.h"
#include <initializer_list>
+#include <type_traits>
// If tight, it grows strictly as much as needed.
// Otherwise, it grows exponentially (the default and what you want in most cases).
@@ -67,7 +68,7 @@ public:
CRASH_COND_MSG(!data, "Out of memory");
}
- if (!__has_trivial_constructor(T) && !force_trivial) {
+ if (!std::is_trivially_constructible<T>::value && !force_trivial) {
memnew_placement(&data[count++], T(p_elem));
} else {
data[count++] = p_elem;
@@ -80,7 +81,7 @@ public:
for (U i = p_index; i < count; i++) {
data[i] = data[i + 1];
}
- if (!__has_trivial_destructor(T) && !force_trivial) {
+ if (!std::is_trivially_destructible<T>::value && !force_trivial) {
data[count].~T();
}
}
@@ -93,7 +94,7 @@ public:
if (count > p_index) {
data[p_index] = data[count];
}
- if (!__has_trivial_destructor(T) && !force_trivial) {
+ if (!std::is_trivially_destructible<T>::value && !force_trivial) {
data[count].~T();
}
}
@@ -134,7 +135,7 @@ public:
_FORCE_INLINE_ U size() const { return count; }
void resize(U p_size) {
if (p_size < count) {
- if (!__has_trivial_destructor(T) && !force_trivial) {
+ if (!std::is_trivially_destructible<T>::value && !force_trivial) {
for (U i = p_size; i < count; i++) {
data[i].~T();
}
@@ -151,7 +152,7 @@ public:
data = (T *)memrealloc(data, capacity * sizeof(T));
CRASH_COND_MSG(!data, "Out of memory");
}
- if (!__has_trivial_constructor(T) && !force_trivial) {
+ if (!std::is_trivially_constructible<T>::value && !force_trivial) {
for (U i = count; i < p_size; i++) {
memnew_placement(&data[i], T);
}
diff --git a/core/templates/paged_allocator.h b/core/templates/paged_allocator.h
index cf5911a847..43aab052fd 100644
--- a/core/templates/paged_allocator.h
+++ b/core/templates/paged_allocator.h
@@ -31,11 +31,14 @@
#ifndef PAGED_ALLOCATOR_H
#define PAGED_ALLOCATOR_H
+#include "core/core_globals.h"
#include "core/os/memory.h"
#include "core/os/spin_lock.h"
+#include "core/string/ustring.h"
#include "core/typedefs.h"
#include <type_traits>
+#include <typeinfo>
template <class T, bool thread_safe = false>
class PagedAllocator {
@@ -132,7 +135,12 @@ public:
}
~PagedAllocator() {
- ERR_FAIL_COND_MSG(allocs_available < pages_allocated * page_size, "Pages in use exist at exit in PagedAllocator");
+ if (allocs_available < pages_allocated * page_size) {
+ if (CoreGlobals::leak_reporting_enabled) {
+ ERR_FAIL_COND_MSG(allocs_available < pages_allocated * page_size, String("Pages in use exist at exit in PagedAllocator: ") + String(typeid(T).name()));
+ }
+ return;
+ }
reset();
}
};
diff --git a/core/templates/paged_array.h b/core/templates/paged_array.h
index 33d2757bec..f1ede556e6 100644
--- a/core/templates/paged_array.h
+++ b/core/templates/paged_array.h
@@ -35,6 +35,8 @@
#include "core/os/spin_lock.h"
#include "core/typedefs.h"
+#include <type_traits>
+
// PagedArray is used mainly for filling a very large array from multiple threads efficiently and without causing major fragmentation
// PageArrayPool manages central page allocation in a thread safe matter
@@ -197,7 +199,7 @@ public:
uint32_t page = count >> page_size_shift;
uint32_t offset = count & page_size_mask;
- if (!__has_trivial_constructor(T)) {
+ if (!std::is_trivially_constructible<T>::value) {
memnew_placement(&page_data[page][offset], T(p_value));
} else {
page_data[page][offset] = p_value;
@@ -209,7 +211,7 @@ public:
_FORCE_INLINE_ void pop_back() {
ERR_FAIL_COND(count == 0);
- if (!__has_trivial_destructor(T)) {
+ if (!std::is_trivially_destructible<T>::value) {
uint32_t page = (count - 1) >> page_size_shift;
uint32_t offset = (count - 1) & page_size_mask;
page_data[page][offset].~T();
@@ -226,7 +228,7 @@ public:
void clear() {
//destruct if needed
- if (!__has_trivial_destructor(T)) {
+ if (!std::is_trivially_destructible<T>::value) {
for (uint64_t i = 0; i < count; i++) {
uint32_t page = i >> page_size_shift;
uint32_t offset = i & page_size_mask;
@@ -309,13 +311,13 @@ public:
uint32_t to_copy = MIN(page_size - new_remainder, remainder);
for (uint32_t i = 0; i < to_copy; i++) {
- if (!__has_trivial_constructor(T)) {
+ if (!std::is_trivially_constructible<T>::value) {
memnew_placement(&dst_page[i + new_remainder], T(remainder_page[i + remainder - to_copy]));
} else {
dst_page[i + new_remainder] = remainder_page[i + remainder - to_copy];
}
- if (!__has_trivial_destructor(T)) {
+ if (!std::is_trivially_destructible<T>::value) {
remainder_page[i + remainder - to_copy].~T();
}
}
diff --git a/core/templates/rid_owner.h b/core/templates/rid_owner.h
index 9c74b41818..320faebe98 100644
--- a/core/templates/rid_owner.h
+++ b/core/templates/rid_owner.h
@@ -79,7 +79,7 @@ class RID_Alloc : public RID_AllocBase {
const char *description = nullptr;
- SpinLock spin_lock;
+ mutable SpinLock spin_lock;
_FORCE_INLINE_ RID _allocate_rid() {
if (THREAD_SAFE) {
@@ -220,7 +220,7 @@ public:
memnew_placement(mem, T(p_value));
}
- _FORCE_INLINE_ bool owns(const RID &p_rid) {
+ _FORCE_INLINE_ bool owns(const RID &p_rid) const {
if (THREAD_SAFE) {
spin_lock.lock();
}
@@ -292,7 +292,7 @@ public:
_FORCE_INLINE_ uint32_t get_rid_count() const {
return alloc_count;
}
- void get_owned_list(List<RID> *p_owned) {
+ void get_owned_list(List<RID> *p_owned) const {
if (THREAD_SAFE) {
spin_lock.lock();
}
@@ -308,7 +308,7 @@ public:
}
//used for fast iteration in the elements or RIDs
- void fill_owned_buffer(RID *p_rid_buffer) {
+ void fill_owned_buffer(RID *p_rid_buffer) const {
if (THREAD_SAFE) {
spin_lock.lock();
}
@@ -402,7 +402,7 @@ public:
*ptr = p_new_ptr;
}
- _FORCE_INLINE_ bool owns(const RID &p_rid) {
+ _FORCE_INLINE_ bool owns(const RID &p_rid) const {
return alloc.owns(p_rid);
}
@@ -414,11 +414,11 @@ public:
return alloc.get_rid_count();
}
- _FORCE_INLINE_ void get_owned_list(List<RID> *p_owned) {
+ _FORCE_INLINE_ void get_owned_list(List<RID> *p_owned) const {
return alloc.get_owned_list(p_owned);
}
- void fill_owned_buffer(RID *p_rid_buffer) {
+ void fill_owned_buffer(RID *p_rid_buffer) const {
alloc.fill_owned_buffer(p_rid_buffer);
}
@@ -458,7 +458,7 @@ public:
return alloc.get_or_null(p_rid);
}
- _FORCE_INLINE_ bool owns(const RID &p_rid) {
+ _FORCE_INLINE_ bool owns(const RID &p_rid) const {
return alloc.owns(p_rid);
}
@@ -470,10 +470,10 @@ public:
return alloc.get_rid_count();
}
- _FORCE_INLINE_ void get_owned_list(List<RID> *p_owned) {
+ _FORCE_INLINE_ void get_owned_list(List<RID> *p_owned) const {
return alloc.get_owned_list(p_owned);
}
- void fill_owned_buffer(RID *p_rid_buffer) {
+ void fill_owned_buffer(RID *p_rid_buffer) const {
alloc.fill_owned_buffer(p_rid_buffer);
}
diff --git a/core/templates/vector.h b/core/templates/vector.h
index f3f5ed76a7..51595a75f5 100644
--- a/core/templates/vector.h
+++ b/core/templates/vector.h
@@ -89,6 +89,7 @@ public:
_FORCE_INLINE_ void set(int p_index, const 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); }
+ Error resize_zeroed(int p_size) { return _cowdata.template resize<true>(p_size); }
_FORCE_INLINE_ const T &operator[](int p_index) const { return _cowdata.get(p_index); }
Error insert(int p_pos, T p_val) { return _cowdata.insert(p_pos, p_val); }
int find(const T &p_val, int p_from = 0) const { return _cowdata.find(p_val, p_from); }
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index 6763dd66b0..a5bc6c229d 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -39,6 +39,10 @@
#include "core/string/print_string.h"
#include "core/variant/variant_parser.h"
+PagedAllocator<Variant::Pools::BucketSmall, true> Variant::Pools::_bucket_small;
+PagedAllocator<Variant::Pools::BucketMedium, true> Variant::Pools::_bucket_medium;
+PagedAllocator<Variant::Pools::BucketLarge, true> Variant::Pools::_bucket_large;
+
String Variant::get_type_name(Variant::Type p_type) {
switch (p_type) {
case NIL: {
@@ -1162,7 +1166,8 @@ void Variant::reference(const Variant &p_variant) {
memnew_placement(_data._mem, Rect2i(*reinterpret_cast<const Rect2i *>(p_variant._data._mem)));
} break;
case TRANSFORM2D: {
- _data._transform2d = memnew(Transform2D(*p_variant._data._transform2d));
+ _data._transform2d = (Transform2D *)Pools::_bucket_small.alloc();
+ memnew_placement(_data._transform2d, Transform2D(*p_variant._data._transform2d));
} break;
case VECTOR3: {
memnew_placement(_data._mem, Vector3(*reinterpret_cast<const Vector3 *>(p_variant._data._mem)));
@@ -1179,23 +1184,24 @@ void Variant::reference(const Variant &p_variant) {
case PLANE: {
memnew_placement(_data._mem, Plane(*reinterpret_cast<const Plane *>(p_variant._data._mem)));
} break;
-
case AABB: {
- _data._aabb = memnew(::AABB(*p_variant._data._aabb));
+ _data._aabb = (::AABB *)Pools::_bucket_small.alloc();
+ memnew_placement(_data._aabb, ::AABB(*p_variant._data._aabb));
} break;
case QUATERNION: {
memnew_placement(_data._mem, Quaternion(*reinterpret_cast<const Quaternion *>(p_variant._data._mem)));
-
} break;
case BASIS: {
- _data._basis = memnew(Basis(*p_variant._data._basis));
-
+ _data._basis = (Basis *)Pools::_bucket_medium.alloc();
+ memnew_placement(_data._basis, Basis(*p_variant._data._basis));
} break;
case TRANSFORM3D: {
- _data._transform3d = memnew(Transform3D(*p_variant._data._transform3d));
+ _data._transform3d = (Transform3D *)Pools::_bucket_medium.alloc();
+ memnew_placement(_data._transform3d, Transform3D(*p_variant._data._transform3d));
} break;
case PROJECTION: {
- _data._projection = memnew(Projection(*p_variant._data._projection));
+ _data._projection = (Projection *)Pools::_bucket_large.alloc();
+ memnew_placement(_data._projection, Projection(*p_variant._data._projection));
} break;
// misc types
@@ -1381,19 +1387,39 @@ void Variant::_clear_internal() {
RECT2
*/
case TRANSFORM2D: {
- memdelete(_data._transform2d);
+ if (_data._transform2d) {
+ _data._transform2d->~Transform2D();
+ Pools::_bucket_small.free((Pools::BucketSmall *)_data._transform2d);
+ _data._transform2d = nullptr;
+ }
} break;
case AABB: {
- memdelete(_data._aabb);
+ if (_data._aabb) {
+ _data._aabb->~AABB();
+ Pools::_bucket_small.free((Pools::BucketSmall *)_data._aabb);
+ _data._aabb = nullptr;
+ }
} break;
case BASIS: {
- memdelete(_data._basis);
+ if (_data._basis) {
+ _data._basis->~Basis();
+ Pools::_bucket_medium.free((Pools::BucketMedium *)_data._basis);
+ _data._basis = nullptr;
+ }
} break;
case TRANSFORM3D: {
- memdelete(_data._transform3d);
+ if (_data._transform3d) {
+ _data._transform3d->~Transform3D();
+ Pools::_bucket_medium.free((Pools::BucketMedium *)_data._transform3d);
+ _data._transform3d = nullptr;
+ }
} break;
case PROJECTION: {
- memdelete(_data._projection);
+ if (_data._projection) {
+ _data._projection->~Projection();
+ Pools::_bucket_large.free((Pools::BucketLarge *)_data._projection);
+ _data._projection = nullptr;
+ }
} break;
// misc types
case STRING_NAME: {
@@ -2609,12 +2635,14 @@ Variant::Variant(const Plane &p_plane) {
Variant::Variant(const ::AABB &p_aabb) {
type = AABB;
- _data._aabb = memnew(::AABB(p_aabb));
+ _data._aabb = (::AABB *)Pools::_bucket_small.alloc();
+ memnew_placement(_data._aabb, ::AABB(p_aabb));
}
Variant::Variant(const Basis &p_matrix) {
type = BASIS;
- _data._basis = memnew(Basis(p_matrix));
+ _data._basis = (Basis *)Pools::_bucket_medium.alloc();
+ memnew_placement(_data._basis, Basis(p_matrix));
}
Variant::Variant(const Quaternion &p_quaternion) {
@@ -2624,17 +2652,20 @@ Variant::Variant(const Quaternion &p_quaternion) {
Variant::Variant(const Transform3D &p_transform) {
type = TRANSFORM3D;
- _data._transform3d = memnew(Transform3D(p_transform));
+ _data._transform3d = (Transform3D *)Pools::_bucket_medium.alloc();
+ memnew_placement(_data._transform3d, Transform3D(p_transform));
}
Variant::Variant(const Projection &pp_projection) {
type = PROJECTION;
- _data._projection = memnew(Projection(pp_projection));
+ _data._projection = (Projection *)Pools::_bucket_large.alloc();
+ memnew_placement(_data._projection, Projection(pp_projection));
}
Variant::Variant(const Transform2D &p_transform) {
type = TRANSFORM2D;
- _data._transform2d = memnew(Transform2D(p_transform));
+ _data._transform2d = (Transform2D *)Pools::_bucket_small.alloc();
+ memnew_placement(_data._transform2d, Transform2D(p_transform));
}
Variant::Variant(const Color &p_color) {
diff --git a/core/variant/variant.h b/core/variant/variant.h
index bfa110842a..212f94a9a8 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -54,6 +54,7 @@
#include "core/os/keyboard.h"
#include "core/string/node_path.h"
#include "core/string/ustring.h"
+#include "core/templates/paged_allocator.h"
#include "core/templates/rid.h"
#include "core/variant/array.h"
#include "core/variant/callable.h"
@@ -134,6 +135,30 @@ public:
};
private:
+ struct Pools {
+ union BucketSmall {
+ BucketSmall() {}
+ ~BucketSmall() {}
+ Transform2D _transform2d;
+ ::AABB _aabb;
+ };
+ union BucketMedium {
+ BucketMedium() {}
+ ~BucketMedium() {}
+ Basis _basis;
+ Transform3D _transform3d;
+ };
+ union BucketLarge {
+ BucketLarge() {}
+ ~BucketLarge() {}
+ Projection _projection;
+ };
+
+ static PagedAllocator<BucketSmall, true> _bucket_small;
+ static PagedAllocator<BucketMedium, true> _bucket_medium;
+ static PagedAllocator<BucketLarge, true> _bucket_large;
+ };
+
friend struct _VariantCall;
friend class VariantInternal;
// Variant takes 20 bytes when real_t is float, and 36 if double
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index b933a90a48..8e73c8dfc0 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1523,7 +1523,7 @@ static void _register_variant_builtin_methods() {
bind_method(String, rstrip, sarray("chars"), varray());
bind_method(String, get_extension, sarray(), varray());
bind_method(String, get_basename, sarray(), varray());
- bind_method(String, plus_file, sarray("file"), varray());
+ bind_method(String, path_join, sarray("file"), varray());
bind_method(String, unicode_at, sarray("at"), varray());
bind_method(String, indent, sarray("prefix"), varray());
bind_method(String, dedent, sarray(), varray());
@@ -1608,6 +1608,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector2, lerp, sarray("to", "weight"), varray());
bind_method(Vector2, slerp, sarray("to", "weight"), varray());
bind_method(Vector2, cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray());
+ bind_method(Vector2, cubic_interpolate_in_time, sarray("b", "pre_a", "post_b", "weight", "b_t", "pre_a_t", "post_b_t"), varray());
bind_method(Vector2, bezier_interpolate, sarray("control_1", "control_2", "end", "t"), varray());
bind_method(Vector2, max_axis_index, sarray(), varray());
bind_method(Vector2, min_axis_index, sarray(), varray());
@@ -1696,6 +1697,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector3, lerp, sarray("to", "weight"), varray());
bind_method(Vector3, slerp, sarray("to", "weight"), varray());
bind_method(Vector3, cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray());
+ bind_method(Vector3, cubic_interpolate_in_time, sarray("b", "pre_a", "post_b", "weight", "b_t", "pre_a_t", "post_b_t"), varray());
bind_method(Vector3, bezier_interpolate, sarray("control_1", "control_2", "end", "t"), varray());
bind_method(Vector3, move_toward, sarray("to", "delta"), varray());
bind_method(Vector3, dot, sarray("with"), varray());
@@ -1737,9 +1739,17 @@ static void _register_variant_builtin_methods() {
bind_method(Vector4, ceil, sarray(), varray());
bind_method(Vector4, round, sarray(), varray());
bind_method(Vector4, lerp, sarray("to", "weight"), varray());
+ bind_method(Vector4, cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray());
+ bind_method(Vector4, cubic_interpolate_in_time, sarray("b", "pre_a", "post_b", "weight", "b_t", "pre_a_t", "post_b_t"), varray());
+ bind_method(Vector4, posmod, sarray("mod"), varray());
+ bind_method(Vector4, posmodv, sarray("modv"), varray());
+ bind_method(Vector4, snapped, sarray("step"), varray());
bind_method(Vector4, clamp, sarray("min", "max"), varray());
bind_method(Vector4, normalized, sarray(), varray());
bind_method(Vector4, is_normalized, sarray(), varray());
+ bind_method(Vector4, direction_to, sarray("to"), varray());
+ bind_method(Vector4, distance_to, sarray("to"), varray());
+ bind_method(Vector4, distance_squared_to, sarray("to"), varray());
bind_method(Vector4, dot, sarray("with"), varray());
bind_method(Vector4, inverse, sarray(), varray());
bind_method(Vector4, is_equal_approx, sarray("with"), varray());
@@ -1782,6 +1792,7 @@ static void _register_variant_builtin_methods() {
bind_method(Quaternion, slerp, sarray("to", "weight"), varray());
bind_method(Quaternion, slerpni, sarray("to", "weight"), varray());
bind_method(Quaternion, spherical_cubic_interpolate, sarray("b", "pre_a", "post_b", "weight"), varray());
+ bind_method(Quaternion, spherical_cubic_interpolate_in_time, sarray("b", "pre_a", "post_b", "weight", "b_t", "pre_a_t", "post_b_t"), varray());
bind_method(Quaternion, get_euler, sarray(), varray());
bind_method(Quaternion, get_axis, sarray(), varray());
bind_method(Quaternion, get_angle, sarray(), varray());
@@ -1882,7 +1893,10 @@ static void _register_variant_builtin_methods() {
bind_method(Transform2D, get_skew, sarray(), varray());
bind_method(Transform2D, orthonormalized, sarray(), varray());
bind_method(Transform2D, rotated, sarray("angle"), varray());
+ bind_method(Transform2D, rotated_local, sarray("angle"), varray());
bind_method(Transform2D, scaled, sarray("scale"), varray());
+ bind_method(Transform2D, scaled_local, sarray("scale"), varray());
+ bind_method(Transform2D, translated, sarray("offset"), varray());
bind_method(Transform2D, translated_local, sarray("offset"), varray());
bind_method(Transform2D, basis_xform, sarray("v"), varray());
bind_method(Transform2D, basis_xform_inv, sarray("v"), varray());
@@ -1906,7 +1920,6 @@ static void _register_variant_builtin_methods() {
bind_method(Basis, tdotx, sarray("with"), varray());
bind_method(Basis, tdoty, sarray("with"), varray());
bind_method(Basis, tdotz, sarray("with"), varray());
- bind_method(Basis, get_orthogonal_index, sarray(), varray());
bind_method(Basis, slerp, sarray("to", "weight"), varray());
bind_method(Basis, is_equal_approx, sarray("b"), varray());
bind_method(Basis, get_rotation_quaternion, sarray(), varray());
@@ -1947,7 +1960,10 @@ static void _register_variant_builtin_methods() {
bind_method(Transform3D, affine_inverse, sarray(), varray());
bind_method(Transform3D, orthonormalized, sarray(), varray());
bind_method(Transform3D, rotated, sarray("axis", "angle"), varray());
+ bind_method(Transform3D, rotated_local, sarray("axis", "angle"), varray());
bind_method(Transform3D, scaled, sarray("scale"), varray());
+ bind_method(Transform3D, scaled_local, sarray("scale"), varray());
+ bind_method(Transform3D, translated, sarray("offset"), varray());
bind_method(Transform3D, translated_local, sarray("offset"), varray());
bind_method(Transform3D, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0)));
bind_method(Transform3D, spherical_interpolate_with, sarray("xform", "weight"), varray());
@@ -2054,7 +2070,8 @@ static void _register_variant_builtin_methods() {
bind_method(PackedByteArray, remove_at, sarray("index"), varray());
bind_method(PackedByteArray, insert, sarray("at_index", "value"), varray());
bind_method(PackedByteArray, fill, sarray("value"), varray());
- bind_method(PackedByteArray, resize, sarray("new_size"), varray());
+ bind_methodv(PackedByteArray, resize, &PackedByteArray::resize_zeroed, sarray("new_size"), varray());
+ bind_method(PackedByteArray, clear, sarray(), varray());
bind_method(PackedByteArray, has, sarray("value"), varray());
bind_method(PackedByteArray, reverse, sarray(), varray());
bind_method(PackedByteArray, slice, sarray("begin", "end"), varray(INT_MAX));
@@ -2118,7 +2135,8 @@ static void _register_variant_builtin_methods() {
bind_method(PackedInt32Array, remove_at, sarray("index"), varray());
bind_method(PackedInt32Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedInt32Array, fill, sarray("value"), varray());
- bind_method(PackedInt32Array, resize, sarray("new_size"), varray());
+ bind_methodv(PackedInt32Array, resize, &PackedInt32Array::resize_zeroed, sarray("new_size"), varray());
+ bind_method(PackedInt32Array, clear, sarray(), varray());
bind_method(PackedInt32Array, has, sarray("value"), varray());
bind_method(PackedInt32Array, reverse, sarray(), varray());
bind_method(PackedInt32Array, slice, sarray("begin", "end"), varray(INT_MAX));
@@ -2141,7 +2159,8 @@ static void _register_variant_builtin_methods() {
bind_method(PackedInt64Array, remove_at, sarray("index"), varray());
bind_method(PackedInt64Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedInt64Array, fill, sarray("value"), varray());
- bind_method(PackedInt64Array, resize, sarray("new_size"), varray());
+ bind_methodv(PackedInt64Array, resize, &PackedInt64Array::resize_zeroed, sarray("new_size"), varray());
+ bind_method(PackedInt64Array, clear, sarray(), varray());
bind_method(PackedInt64Array, has, sarray("value"), varray());
bind_method(PackedInt64Array, reverse, sarray(), varray());
bind_method(PackedInt64Array, slice, sarray("begin", "end"), varray(INT_MAX));
@@ -2164,7 +2183,8 @@ static void _register_variant_builtin_methods() {
bind_method(PackedFloat32Array, remove_at, sarray("index"), varray());
bind_method(PackedFloat32Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedFloat32Array, fill, sarray("value"), varray());
- bind_method(PackedFloat32Array, resize, sarray("new_size"), varray());
+ bind_methodv(PackedFloat32Array, resize, &PackedFloat32Array::resize_zeroed, sarray("new_size"), varray());
+ bind_method(PackedFloat32Array, clear, sarray(), varray());
bind_method(PackedFloat32Array, has, sarray("value"), varray());
bind_method(PackedFloat32Array, reverse, sarray(), varray());
bind_method(PackedFloat32Array, slice, sarray("begin", "end"), varray(INT_MAX));
@@ -2187,7 +2207,8 @@ static void _register_variant_builtin_methods() {
bind_method(PackedFloat64Array, remove_at, sarray("index"), varray());
bind_method(PackedFloat64Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedFloat64Array, fill, sarray("value"), varray());
- bind_method(PackedFloat64Array, resize, sarray("new_size"), varray());
+ bind_methodv(PackedFloat64Array, resize, &PackedFloat64Array::resize_zeroed, sarray("new_size"), varray());
+ bind_method(PackedFloat64Array, clear, sarray(), varray());
bind_method(PackedFloat64Array, has, sarray("value"), varray());
bind_method(PackedFloat64Array, reverse, sarray(), varray());
bind_method(PackedFloat64Array, slice, sarray("begin", "end"), varray(INT_MAX));
@@ -2211,6 +2232,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedStringArray, insert, sarray("at_index", "value"), varray());
bind_method(PackedStringArray, fill, sarray("value"), varray());
bind_method(PackedStringArray, resize, sarray("new_size"), varray());
+ bind_method(PackedStringArray, clear, sarray(), varray());
bind_method(PackedStringArray, has, sarray("value"), varray());
bind_method(PackedStringArray, reverse, sarray(), varray());
bind_method(PackedStringArray, slice, sarray("begin", "end"), varray(INT_MAX));
@@ -2234,6 +2256,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedVector2Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedVector2Array, fill, sarray("value"), varray());
bind_method(PackedVector2Array, resize, sarray("new_size"), varray());
+ bind_method(PackedVector2Array, clear, sarray(), varray());
bind_method(PackedVector2Array, has, sarray("value"), varray());
bind_method(PackedVector2Array, reverse, sarray(), varray());
bind_method(PackedVector2Array, slice, sarray("begin", "end"), varray(INT_MAX));
@@ -2257,6 +2280,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedVector3Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedVector3Array, fill, sarray("value"), varray());
bind_method(PackedVector3Array, resize, sarray("new_size"), varray());
+ bind_method(PackedVector3Array, clear, sarray(), varray());
bind_method(PackedVector3Array, has, sarray("value"), varray());
bind_method(PackedVector3Array, reverse, sarray(), varray());
bind_method(PackedVector3Array, slice, sarray("begin", "end"), varray(INT_MAX));
@@ -2280,6 +2304,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedColorArray, insert, sarray("at_index", "value"), varray());
bind_method(PackedColorArray, fill, sarray("value"), varray());
bind_method(PackedColorArray, resize, sarray("new_size"), varray());
+ bind_method(PackedColorArray, clear, sarray(), varray());
bind_method(PackedColorArray, has, sarray("value"), varray());
bind_method(PackedColorArray, reverse, sarray(), varray());
bind_method(PackedColorArray, slice, sarray("begin", "end"), varray(INT_MAX));
diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp
index 3a0b6c1bb9..d048f45737 100644
--- a/core/variant/variant_construct.cpp
+++ b/core/variant/variant_construct.cpp
@@ -162,6 +162,7 @@ void Variant::_register_variant_constructors() {
add_constructor<VariantConstructNoArgs<Projection>>(sarray());
add_constructor<VariantConstructor<Projection, Projection>>(sarray("from"));
add_constructor<VariantConstructor<Projection, Transform3D>>(sarray("from"));
+ add_constructor<VariantConstructor<Projection, Vector4, Vector4, Vector4, Vector4>>(sarray("x_axis", "y_axis", "z_axis", "w_axis"));
add_constructor<VariantConstructNoArgs<Color>>(sarray());
add_constructor<VariantConstructor<Color, Color>>(sarray("from"));
diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h
index 961c0f3a51..874a183d29 100644
--- a/core/variant/variant_internal.h
+++ b/core/variant/variant_internal.h
@@ -36,6 +36,8 @@
// 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 {
+ friend class Variant;
+
public:
// Set type.
_FORCE_INLINE_ static void initialize(Variant *v, Variant::Type p_type) {
@@ -215,23 +217,28 @@ public:
}
_FORCE_INLINE_ static void init_transform2d(Variant *v) {
- v->_data._transform2d = memnew(Transform2D);
+ v->_data._transform2d = (Transform2D *)Variant::Pools::_bucket_small.alloc();
+ memnew_placement(v->_data._transform2d, Transform2D);
v->type = Variant::TRANSFORM2D;
}
_FORCE_INLINE_ static void init_aabb(Variant *v) {
- v->_data._aabb = memnew(AABB);
+ v->_data._aabb = (AABB *)Variant::Pools::_bucket_small.alloc();
+ memnew_placement(v->_data._aabb, AABB);
v->type = Variant::AABB;
}
_FORCE_INLINE_ static void init_basis(Variant *v) {
- v->_data._basis = memnew(Basis);
+ v->_data._basis = (Basis *)Variant::Pools::_bucket_medium.alloc();
+ memnew_placement(v->_data._basis, Basis);
v->type = Variant::BASIS;
}
_FORCE_INLINE_ static void init_transform(Variant *v) {
- v->_data._transform3d = memnew(Transform3D);
+ v->_data._transform3d = (Transform3D *)Variant::Pools::_bucket_medium.alloc();
+ memnew_placement(v->_data._transform3d, Transform3D);
v->type = Variant::TRANSFORM3D;
}
_FORCE_INLINE_ static void init_projection(Variant *v) {
- v->_data._projection = memnew(Projection);
+ v->_data._projection = (Projection *)Variant::Pools::_bucket_large.alloc();
+ memnew_placement(v->_data._projection, Projection);
v->type = Variant::PROJECTION;
}
_FORCE_INLINE_ static void init_string_name(Variant *v) {
diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp
index 669e18b5f7..6cca7955ae 100644
--- a/core/variant/variant_op.cpp
+++ b/core/variant/variant_op.cpp
@@ -341,6 +341,8 @@ void Variant::_register_variant_operators() {
register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Transform3D>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::TRANSFORM3D);
register_op<OperatorEvaluatorXForm<::AABB, Transform3D, ::AABB>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::AABB);
register_op<OperatorEvaluatorXFormInv<::AABB, ::AABB, Transform3D>>(Variant::OP_MULTIPLY, Variant::AABB, Variant::TRANSFORM3D);
+ register_op<OperatorEvaluatorXForm<Plane, Transform3D, Plane>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::PLANE);
+ register_op<OperatorEvaluatorXFormInv<Plane, Plane, Transform3D>>(Variant::OP_MULTIPLY, Variant::PLANE, Variant::TRANSFORM3D);
register_op<OperatorEvaluatorXForm<Vector<Vector3>, Transform3D, Vector<Vector3>>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::PACKED_VECTOR3_ARRAY);
register_op<OperatorEvaluatorXFormInv<Vector<Vector3>, Vector<Vector3>, Transform3D>>(Variant::OP_MULTIPLY, Variant::PACKED_VECTOR3_ARRAY, Variant::TRANSFORM3D);
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index c1a0ad73b0..1be17405c7 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -99,18 +99,105 @@ struct VariantUtilityFunctions {
return Math::posmod(b, r);
}
- static inline double floor(double x) {
+ static inline Variant floor(Variant x, Callable::CallError &r_error) {
+ r_error.error = Callable::CallError::CALL_OK;
+ switch (x.get_type()) {
+ case Variant::INT: {
+ return VariantInternalAccessor<int64_t>::get(&x);
+ } break;
+ case Variant::FLOAT: {
+ return Math::floor(VariantInternalAccessor<double>::get(&x));
+ } break;
+ case Variant::VECTOR2: {
+ return VariantInternalAccessor<Vector2>::get(&x).floor();
+ } break;
+ case Variant::VECTOR3: {
+ return VariantInternalAccessor<Vector3>::get(&x).floor();
+ } break;
+ case Variant::VECTOR4: {
+ return VariantInternalAccessor<Vector4>::get(&x).floor();
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
+ }
+ }
+ }
+
+ static inline double floorf(double x) {
return Math::floor(x);
}
- static inline double ceil(double x) {
+ static inline int floori(double x) {
+ return int(x);
+ }
+
+ static inline Variant ceil(Variant x, Callable::CallError &r_error) {
+ r_error.error = Callable::CallError::CALL_OK;
+ switch (x.get_type()) {
+ case Variant::INT: {
+ return VariantInternalAccessor<int64_t>::get(&x);
+ } break;
+ case Variant::FLOAT: {
+ return Math::ceil(VariantInternalAccessor<double>::get(&x));
+ } break;
+ case Variant::VECTOR2: {
+ return VariantInternalAccessor<Vector2>::get(&x).ceil();
+ } break;
+ case Variant::VECTOR3: {
+ return VariantInternalAccessor<Vector3>::get(&x).ceil();
+ } break;
+ case Variant::VECTOR4: {
+ return VariantInternalAccessor<Vector4>::get(&x).ceil();
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
+ }
+ }
+ }
+
+ static inline double ceilf(double x) {
return Math::ceil(x);
}
- static inline double round(double x) {
+ static inline int ceili(double x) {
+ return int(Math::ceil(x));
+ }
+
+ static inline Variant round(Variant x, Callable::CallError &r_error) {
+ r_error.error = Callable::CallError::CALL_OK;
+ switch (x.get_type()) {
+ case Variant::INT: {
+ return VariantInternalAccessor<int64_t>::get(&x);
+ } break;
+ case Variant::FLOAT: {
+ return Math::round(VariantInternalAccessor<double>::get(&x));
+ } break;
+ case Variant::VECTOR2: {
+ return VariantInternalAccessor<Vector2>::get(&x).round();
+ } break;
+ case Variant::VECTOR3: {
+ return VariantInternalAccessor<Vector3>::get(&x).round();
+ } break;
+ case Variant::VECTOR4: {
+ return VariantInternalAccessor<Vector4>::get(&x).round();
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
+ }
+ }
+ }
+
+ static inline double roundf(double x) {
return Math::round(x);
}
+ static inline int roundi(double x) {
+ return int(Math::round(x));
+ }
+
static inline Variant abs(const Variant &x, Callable::CallError &r_error) {
r_error.error = Callable::CallError::CALL_OK;
switch (x.get_type()) {
@@ -235,7 +322,44 @@ struct VariantUtilityFunctions {
return Math::snapped(value, step);
}
- static inline double lerp(double from, double to, double weight) {
+ static inline Variant lerp(const Variant &from, const Variant &to, double weight, Callable::CallError &r_error) {
+ r_error.error = Callable::CallError::CALL_OK;
+ if (from.get_type() != to.get_type()) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 1;
+ return Variant();
+ }
+
+ switch (from.get_type()) {
+ case Variant::FLOAT: {
+ return lerpf(VariantInternalAccessor<double>::get(&from), to, weight);
+ } break;
+ case Variant::VECTOR2: {
+ return VariantInternalAccessor<Vector2>::get(&from).lerp(VariantInternalAccessor<Vector2>::get(&to), weight);
+ } break;
+ case Variant::VECTOR3: {
+ return VariantInternalAccessor<Vector3>::get(&from).lerp(VariantInternalAccessor<Vector3>::get(&to), weight);
+ } break;
+ case Variant::VECTOR4: {
+ return VariantInternalAccessor<Vector4>::get(&from).lerp(VariantInternalAccessor<Vector4>::get(&to), weight);
+ } break;
+ case Variant::QUATERNION: {
+ return VariantInternalAccessor<Quaternion>::get(&from).slerp(VariantInternalAccessor<Quaternion>::get(&to), weight);
+ } break;
+ case Variant::BASIS: {
+ return VariantInternalAccessor<Basis>::get(&from).slerp(VariantInternalAccessor<Basis>::get(&to), weight);
+ } break;
+ case Variant::COLOR: {
+ return VariantInternalAccessor<Color>::get(&from).lerp(VariantInternalAccessor<Color>::get(&to), weight);
+ } break;
+ default: {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
+ }
+ }
+ }
+
+ static inline double lerpf(double from, double to, double weight) {
return Math::lerp(from, to, weight);
}
@@ -243,6 +367,20 @@ struct VariantUtilityFunctions {
return Math::cubic_interpolate(from, to, pre, post, weight);
}
+ static inline double cubic_interpolate_angle(double from, double to, double pre, double post, double weight) {
+ return Math::cubic_interpolate_angle(from, to, pre, post, weight);
+ }
+
+ static inline double cubic_interpolate_in_time(double from, double to, double pre, double post, double weight,
+ double to_t, double pre_t, double post_t) {
+ return Math::cubic_interpolate_in_time(from, to, pre, post, weight, to_t, pre_t, post_t);
+ }
+
+ static inline double cubic_interpolate_angle_in_time(double from, double to, double pre, double post, double weight,
+ double to_t, double pre_t, double post_t) {
+ return Math::cubic_interpolate_angle_in_time(from, to, pre, post, weight, to_t, pre_t, post_t);
+ }
+
static inline double bezier_interpolate(double p_start, double p_control_1, double p_control_2, double p_end, double p_t) {
return Math::bezier_interpolate(p_start, p_control_1, p_control_2, p_end, p_t);
}
@@ -267,20 +405,20 @@ struct VariantUtilityFunctions {
return Math::move_toward(from, to, delta);
}
- static inline double deg2rad(double angle_deg) {
- return Math::deg2rad(angle_deg);
+ static inline double deg_to_rad(double angle_deg) {
+ return Math::deg_to_rad(angle_deg);
}
- static inline double rad2deg(double angle_rad) {
- return Math::rad2deg(angle_rad);
+ static inline double rad_to_deg(double angle_rad) {
+ return Math::rad_to_deg(angle_rad);
}
- static inline double linear2db(double linear) {
- return Math::linear2db(linear);
+ static inline double linear_to_db(double linear) {
+ return Math::linear_to_db(linear);
}
- static inline double db2linear(double db) {
- return Math::db2linear(db);
+ static inline double db_to_linear(double db) {
+ return Math::db_to_linear(db);
}
static inline Variant wrap(const Variant &p_x, const Variant &p_min, const Variant &p_max, Callable::CallError &r_error) {
@@ -708,13 +846,13 @@ struct VariantUtilityFunctions {
r_error.error = Callable::CallError::CALL_OK;
}
- static inline String var2str(const Variant &p_var) {
+ static inline String var_to_str(const Variant &p_var) {
String vars;
VariantWriter::write_to_string(p_var, vars);
return vars;
}
- static inline Variant str2var(const String &p_var) {
+ static inline Variant str_to_var(const String &p_var) {
VariantParser::StreamString ss;
ss.s = p_var;
@@ -726,7 +864,7 @@ struct VariantUtilityFunctions {
return ret;
}
- static inline PackedByteArray var2bytes(const Variant &p_var) {
+ static inline PackedByteArray var_to_bytes(const Variant &p_var) {
int len;
Error err = encode_variant(p_var, nullptr, len, false);
if (err != OK) {
@@ -746,7 +884,7 @@ struct VariantUtilityFunctions {
return barr;
}
- static inline PackedByteArray var2bytes_with_objects(const Variant &p_var) {
+ static inline PackedByteArray var_to_bytes_with_objects(const Variant &p_var) {
int len;
Error err = encode_variant(p_var, nullptr, len, true);
if (err != OK) {
@@ -766,7 +904,7 @@ struct VariantUtilityFunctions {
return barr;
}
- static inline Variant bytes2var(const PackedByteArray &p_arr) {
+ static inline Variant bytes_to_var(const PackedByteArray &p_arr) {
Variant ret;
{
const uint8_t *r = p_arr.ptr();
@@ -778,7 +916,7 @@ struct VariantUtilityFunctions {
return ret;
}
- static inline Variant bytes2var_with_objects(const PackedByteArray &p_arr) {
+ static inline Variant bytes_to_var_with_objects(const PackedByteArray &p_arr) {
Variant ret;
{
const uint8_t *r = p_arr.ptr();
@@ -1252,17 +1390,24 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(fmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(fposmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(posmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(floor, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(ceil, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(round, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDVR(abs, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDVR(floor, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(floorf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(floori, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDVR(ceil, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(ceilf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(ceili, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDVR(round, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(roundf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(roundi, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
+
+ FUNCBINDVR(abs, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(absf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(absi, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDVR(sign, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
-
FUNCBINDR(signf, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(signi, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
@@ -1280,8 +1425,12 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(step_decimals, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(snapped, sarray("x", "step"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDVR3(lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(lerpf, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(cubic_interpolate, sarray("from", "to", "pre", "post", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(cubic_interpolate_angle, sarray("from", "to", "pre", "post", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(cubic_interpolate_in_time, sarray("from", "to", "pre", "post", "weight", "to_t", "pre_t", "post_t"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(cubic_interpolate_angle_in_time, sarray("from", "to", "pre", "post", "weight", "to_t", "pre_t", "post_t"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(bezier_interpolate, sarray("start", "control_1", "control_2", "end", "t"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(lerp_angle, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(inverse_lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
@@ -1290,22 +1439,20 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(smoothstep, sarray("from", "to", "x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(move_toward, sarray("from", "to", "delta"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(deg2rad, sarray("deg"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(rad2deg, sarray("rad"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(linear2db, sarray("lin"), Variant::UTILITY_FUNC_TYPE_MATH);
- FUNCBINDR(db2linear, sarray("db"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(deg_to_rad, sarray("deg"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(rad_to_deg, sarray("rad"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(linear_to_db, sarray("lin"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(db_to_linear, sarray("db"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDVR3(wrap, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(wrapi, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(wrapf, sarray("value", "min", "max"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDVARARG(max, sarray(), Variant::UTILITY_FUNC_TYPE_MATH);
-
FUNCBINDR(maxi, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(maxf, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDVARARG(min, sarray(), Variant::UTILITY_FUNC_TYPE_MATH);
-
FUNCBINDR(mini, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(minf, sarray("a", "b"), Variant::UTILITY_FUNC_TYPE_MATH);
@@ -1343,14 +1490,14 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDVARARGV(push_error, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
FUNCBINDVARARGV(push_warning, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
- FUNCBINDR(var2str, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL);
- FUNCBINDR(str2var, sarray("string"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(var_to_str, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(str_to_var, sarray("string"), Variant::UTILITY_FUNC_TYPE_GENERAL);
- FUNCBINDR(var2bytes, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL);
- FUNCBINDR(bytes2var, sarray("bytes"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(var_to_bytes, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(bytes_to_var, sarray("bytes"), Variant::UTILITY_FUNC_TYPE_GENERAL);
- FUNCBINDR(var2bytes_with_objects, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL);
- FUNCBINDR(bytes2var_with_objects, sarray("bytes"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(var_to_bytes_with_objects, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(bytes_to_var_with_objects, sarray("bytes"), Variant::UTILITY_FUNC_TYPE_GENERAL);
FUNCBINDR(hash, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL);
diff --git a/doc/Makefile b/doc/Makefile
index c29843f303..ecc5e51dd6 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -2,7 +2,7 @@ BASEDIR = $(CURDIR)
CLASSES = $(BASEDIR)/classes/ $(BASEDIR)/../modules/
OUTPUTDIR = $(BASEDIR)/_build
TOOLSDIR = $(BASEDIR)/tools
-JSDIR = $(BASEDIR)/../platform/javascript
+JSDIR = $(BASEDIR)/../platform/web
LANGARG ?= en
LANGCMD = -l $(LANGARG)
diff --git a/doc/class.xsd b/doc/class.xsd
index 70c0323464..7681ddad3d 100644
--- a/doc/class.xsd
+++ b/doc/class.xsd
@@ -35,7 +35,7 @@
<xs:attribute type="xs:string" name="enum" use="optional" />
</xs:complexType>
</xs:element>
- <xs:element name="argument" maxOccurs="unbounded" minOccurs="0">
+ <xs:element name="param" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:sequence />
@@ -79,7 +79,7 @@
<xs:attribute type="xs:byte" name="number" />
</xs:complexType>
</xs:element>
- <xs:element name="argument" maxOccurs="unbounded" minOccurs="0">
+ <xs:element name="param" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:sequence />
@@ -127,7 +127,7 @@
<xs:element name="signal" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
- <xs:element name="argument" maxOccurs="unbounded" minOccurs="0">
+ <xs:element name="param" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:sequence />
@@ -178,7 +178,7 @@
<xs:attribute type="xs:string" name="enum" use="optional" />
</xs:complexType>
</xs:element>
- <xs:element name="argument" maxOccurs="unbounded" minOccurs="0">
+ <xs:element name="param" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:sequence />
@@ -232,7 +232,7 @@
<xs:attribute type="xs:string" name="enum" use="optional" />
</xs:complexType>
</xs:element>
- <xs:element name="argument" maxOccurs="unbounded" minOccurs="0">
+ <xs:element name="param" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:sequence />
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 709863b70f..71b0901b3d 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -14,9 +14,9 @@
<methods>
<method name="abs">
<return type="Variant" />
- <argument index="0" name="x" type="Variant" />
+ <param index="0" name="x" type="Variant" />
<description>
- Returns the absolute value of a [Variant] parameter [code]x[/code] (i.e. non-negative value). Variant types [int], [float] (real), [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
+ Returns the absolute value of a [Variant] parameter [param x] (i.e. non-negative value). Variant types [int], [float] (real), [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
[codeblock]
var a = abs(-1)
# a is 1
@@ -40,9 +40,9 @@
</method>
<method name="absf">
<return type="float" />
- <argument index="0" name="x" type="float" />
+ <param index="0" name="x" type="float" />
<description>
- Returns the absolute value of float parameter [code]x[/code] (i.e. positive value).
+ Returns the absolute value of float parameter [param x] (i.e. positive value).
[codeblock]
# a is 1.2
var a = absf(-1.2)
@@ -51,9 +51,9 @@
</method>
<method name="absi">
<return type="int" />
- <argument index="0" name="x" type="int" />
+ <param index="0" name="x" type="int" />
<description>
- Returns the absolute value of int parameter [code]x[/code] (i.e. positive value).
+ Returns the absolute value of int parameter [param x] (i.e. positive value).
[codeblock]
# a is 1
var a = absi(-1)
@@ -62,42 +62,42 @@
</method>
<method name="acos">
<return type="float" />
- <argument index="0" name="x" type="float" />
+ <param index="0" name="x" type="float" />
<description>
- Returns the arc cosine of [code]x[/code] in radians. Use to get the angle of cosine [code]x[/code]. [code]x[/code] must be between [code]-1.0[/code] and [code]1.0[/code] (inclusive), otherwise, [method acos] will return [constant @GDScript.NAN].
+ Returns the arc cosine of [param x] in radians. Use to get the angle of cosine [param x]. [param x] must be between [code]-1.0[/code] and [code]1.0[/code] (inclusive), otherwise, [method acos] will return [constant @GDScript.NAN].
[codeblock]
- # c is 0.523599 or 30 degrees if converted with rad2deg(c)
+ # c is 0.523599 or 30 degrees if converted with rad_to_deg(c)
var c = acos(0.866025)
[/codeblock]
</description>
</method>
<method name="asin">
<return type="float" />
- <argument index="0" name="x" type="float" />
+ <param index="0" name="x" type="float" />
<description>
- Returns the arc sine of [code]x[/code] in radians. Use to get the angle of sine [code]x[/code]. [code]x[/code] must be between [code]-1.0[/code] and [code]1.0[/code] (inclusive), otherwise, [method asin] will return [constant @GDScript.NAN].
+ Returns the arc sine of [param x] in radians. Use to get the angle of sine [param x]. [param x] must be between [code]-1.0[/code] and [code]1.0[/code] (inclusive), otherwise, [method asin] will return [constant @GDScript.NAN].
[codeblock]
- # s is 0.523599 or 30 degrees if converted with rad2deg(s)
+ # s is 0.523599 or 30 degrees if converted with rad_to_deg(s)
var s = asin(0.5)
[/codeblock]
</description>
</method>
<method name="atan">
<return type="float" />
- <argument index="0" name="x" type="float" />
+ <param index="0" name="x" type="float" />
<description>
- Returns the arc tangent of [code]x[/code] in radians. Use it to get the angle from an angle's tangent in trigonometry.
+ Returns the arc tangent of [param x] in radians. Use it to get the angle from an angle's tangent in trigonometry.
The method cannot know in which quadrant the angle should fall. See [method atan2] if you have both [code]y[/code] and [code]x[/code].
[codeblock]
var a = atan(0.5) # a is 0.463648
[/codeblock]
- If [code]x[/code] is between [code]-PI / 2[/code] and [code]PI / 2[/code] (inclusive), [code]atan(tan(x))[/code] is equal to [code]x[/code].
+ If [param x] is between [code]-PI / 2[/code] and [code]PI / 2[/code] (inclusive), [code]atan(tan(x))[/code] is equal to [param x].
</description>
</method>
<method name="atan2">
<return type="float" />
- <argument index="0" name="y" type="float" />
- <argument index="1" name="x" type="float" />
+ <param index="0" name="y" type="float" />
+ <param index="1" name="x" type="float" />
<description>
Returns the arc tangent of [code]y/x[/code] in radians. Use to get the angle of tangent [code]y/x[/code]. To compute the value, the method takes into account the sign of both arguments in order to determine the quadrant.
Important note: The Y coordinate comes first, by convention.
@@ -108,50 +108,67 @@
</method>
<method name="bezier_interpolate">
<return type="float" />
- <argument index="0" name="start" type="float" />
- <argument index="1" name="control_1" type="float" />
- <argument index="2" name="control_2" type="float" />
- <argument index="3" name="end" type="float" />
- <argument index="4" name="t" type="float" />
+ <param index="0" name="start" type="float" />
+ <param index="1" name="control_1" type="float" />
+ <param index="2" name="control_2" type="float" />
+ <param index="3" name="end" type="float" />
+ <param index="4" name="t" type="float" />
<description>
- Returns the point at the given [code]t[/code] on a one-dimnesional [url=https://en.wikipedia.org/wiki/B%C3%A9zier_curve]Bezier curve[/url] defined by the given [code]control_1[/code], [code]control_2[/code], and [code]end[/code] points.
+ Returns the point at the given [param t] on a one-dimnesional [url=https://en.wikipedia.org/wiki/B%C3%A9zier_curve]Bezier curve[/url] defined by the given [param control_1], [param control_2], and [param end] points.
</description>
</method>
- <method name="bytes2var">
+ <method name="bytes_to_var">
<return type="Variant" />
- <argument index="0" name="bytes" type="PackedByteArray" />
+ <param index="0" name="bytes" type="PackedByteArray" />
<description>
Decodes a byte array back to a [Variant] value, without decoding objects.
- [b]Note:[/b] If you need object deserialization, see [method bytes2var_with_objects].
+ [b]Note:[/b] If you need object deserialization, see [method bytes_to_var_with_objects].
</description>
</method>
- <method name="bytes2var_with_objects">
+ <method name="bytes_to_var_with_objects">
<return type="Variant" />
- <argument index="0" name="bytes" type="PackedByteArray" />
+ <param index="0" name="bytes" type="PackedByteArray" />
<description>
Decodes a byte array back to a [Variant] value. Decoding objects is allowed.
[b]Warning:[/b] Deserialized object can contain code which gets executed. Do not use this option if the serialized object comes from untrusted sources to avoid potential security threats (remote code execution).
</description>
</method>
<method name="ceil">
- <return type="float" />
- <argument index="0" name="x" type="float" />
+ <return type="Variant" />
+ <param index="0" name="x" type="Variant" />
<description>
- Rounds [code]x[/code] upward (towards positive infinity), returning the smallest whole number that is not less than [code]x[/code].
+ Rounds [param x] upward (towards positive infinity), returning the smallest whole number that is not less than [param x]. Supported types: [int], [float], [Vector2], [Vector3], [Vector4].
[codeblock]
var i = ceil(1.45) # i is 2.0
i = ceil(1.001) # i is 2.0
[/codeblock]
See also [method floor], [method round], and [method snapped].
+ [b]Note:[/b] For better type safety, you can use [method ceilf], [method ceili], [method Vector2.ceil], [method Vector3.ceil] or [method Vector4.ceil] instead.
+ </description>
+ </method>
+ <method name="ceilf">
+ <return type="float" />
+ <param index="0" name="x" type="float" />
+ <description>
+ Rounds [param x] upward (towards positive infinity), returning the smallest whole number that is not less than [param x].
+ A type-safe version of [method ceil], specialzied in floats.
+ </description>
+ </method>
+ <method name="ceili">
+ <return type="int" />
+ <param index="0" name="x" type="float" />
+ <description>
+ Rounds [param x] upward (towards positive infinity), returning the smallest whole number that is not less than [param x].
+ A type-safe version of [method ceil] that returns integer.
</description>
</method>
<method name="clamp">
<return type="Variant" />
- <argument index="0" name="value" type="Variant" />
- <argument index="1" name="min" type="Variant" />
- <argument index="2" name="max" type="Variant" />
+ <param index="0" name="value" type="Variant" />
+ <param index="1" name="min" type="Variant" />
+ <param index="2" name="max" type="Variant" />
<description>
- Clamps the [Variant] [code]value[/code] and returns a value not less than [code]min[/code] and not more than [code]max[/code]. Variant types [int], [float] (real), [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
+ Clamps the [Variant] [param value] and returns a value not less than [param min] and not more than [param max]. Variant types [int], [float] (real), [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
[codeblock]
var a = clamp(-10, -1, 5)
# a is -1
@@ -175,11 +192,11 @@
</method>
<method name="clampf">
<return type="float" />
- <argument index="0" name="value" type="float" />
- <argument index="1" name="min" type="float" />
- <argument index="2" name="max" type="float" />
+ <param index="0" name="value" type="float" />
+ <param index="1" name="min" type="float" />
+ <param index="2" name="max" type="float" />
<description>
- Clamps the float [code]value[/code] and returns a value not less than [code]min[/code] and not more than [code]max[/code].
+ Clamps the float [param value] and returns a value not less than [param min] and not more than [param max].
[codeblock]
var speed = 42.1
# a is 20.0
@@ -193,11 +210,11 @@
</method>
<method name="clampi">
<return type="int" />
- <argument index="0" name="value" type="int" />
- <argument index="1" name="min" type="int" />
- <argument index="2" name="max" type="int" />
+ <param index="0" name="value" type="int" />
+ <param index="1" name="min" type="int" />
+ <param index="2" name="max" type="int" />
<description>
- Clamps the integer [code]value[/code] and returns a value not less than [code]min[/code] and not more than [code]max[/code].
+ Clamps the integer [param value] and returns a value not less than [param min] and not more than [param max].
[codeblock]
var speed = 42
# a is 20
@@ -211,21 +228,21 @@
</method>
<method name="cos">
<return type="float" />
- <argument index="0" name="angle_rad" type="float" />
+ <param index="0" name="angle_rad" type="float" />
<description>
- Returns the cosine of angle [code]angle_rad[/code] in radians.
+ Returns the cosine of angle [param angle_rad] in radians.
[codeblock]
- cos(PI * 2) # Returns 1.0
- cos(PI) # Returns -1.0
- cos(deg2rad(90)) # Returns 0.0
+ cos(PI * 2) # Returns 1.0
+ cos(PI) # Returns -1.0
+ cos(deg_to_rad(90)) # Returns 0.0
[/codeblock]
</description>
</method>
<method name="cosh">
<return type="float" />
- <argument index="0" name="x" type="float" />
+ <param index="0" name="x" type="float" />
<description>
- Returns the hyperbolic cosine of [code]x[/code] in radians.
+ Returns the hyperbolic cosine of [param x] in radians.
[codeblock]
# Prints 1.543081
print(cosh(1))
@@ -234,39 +251,80 @@
</method>
<method name="cubic_interpolate">
<return type="float" />
- <argument index="0" name="from" type="float" />
- <argument index="1" name="to" type="float" />
- <argument index="2" name="pre" type="float" />
- <argument index="3" name="post" type="float" />
- <argument index="4" name="weight" type="float" />
+ <param index="0" name="from" type="float" />
+ <param index="1" name="to" type="float" />
+ <param index="2" name="pre" type="float" />
+ <param index="3" name="post" type="float" />
+ <param index="4" name="weight" type="float" />
<description>
- Cubic interpolates between two values by the factor defined in [code]weight[/code] with pre and post values.
+ Cubic interpolates between two values by the factor defined in [param weight] with pre and post values.
</description>
</method>
- <method name="db2linear">
+ <method name="cubic_interpolate_angle">
<return type="float" />
- <argument index="0" name="db" type="float" />
+ <param index="0" name="from" type="float" />
+ <param index="1" name="to" type="float" />
+ <param index="2" name="pre" type="float" />
+ <param index="3" name="post" type="float" />
+ <param index="4" name="weight" type="float" />
+ <description>
+ Cubic interpolates between two rotation values with shortest path by the factor defined in [param weight] with pre and post values. See also [method lerp_angle].
+ </description>
+ </method>
+ <method name="cubic_interpolate_angle_in_time">
+ <return type="float" />
+ <param index="0" name="from" type="float" />
+ <param index="1" name="to" type="float" />
+ <param index="2" name="pre" type="float" />
+ <param index="3" name="post" type="float" />
+ <param index="4" name="weight" type="float" />
+ <param index="5" name="to_t" type="float" />
+ <param index="6" name="pre_t" type="float" />
+ <param index="7" name="post_t" type="float" />
+ <description>
+ Cubic interpolates between two rotation values with shortest path by the factor defined in [param weight] with pre and post values. See also [method lerp_angle].
+ It can perform smoother interpolation than [code]cubic_interpolate()[/code] by the time values.
+ </description>
+ </method>
+ <method name="cubic_interpolate_in_time">
+ <return type="float" />
+ <param index="0" name="from" type="float" />
+ <param index="1" name="to" type="float" />
+ <param index="2" name="pre" type="float" />
+ <param index="3" name="post" type="float" />
+ <param index="4" name="weight" type="float" />
+ <param index="5" name="to_t" type="float" />
+ <param index="6" name="pre_t" type="float" />
+ <param index="7" name="post_t" type="float" />
+ <description>
+ Cubic interpolates between two values by the factor defined in [param weight] with pre and post values.
+ It can perform smoother interpolation than [code]cubic_interpolate()[/code] by the time values.
+ </description>
+ </method>
+ <method name="db_to_linear">
+ <return type="float" />
+ <param index="0" name="db" type="float" />
<description>
Converts from decibels to linear energy (audio).
</description>
</method>
- <method name="deg2rad">
+ <method name="deg_to_rad">
<return type="float" />
- <argument index="0" name="deg" type="float" />
+ <param index="0" name="deg" type="float" />
<description>
Converts an angle expressed in degrees to radians.
[codeblock]
# r is 3.141593
- var r = deg2rad(180)
+ var r = deg_to_rad(180)
[/codeblock]
</description>
</method>
<method name="ease">
<return type="float" />
- <argument index="0" name="x" type="float" />
- <argument index="1" name="curve" type="float" />
+ <param index="0" name="x" type="float" />
+ <param index="1" name="curve" type="float" />
<description>
- Returns an "eased" value of [code]x[/code] based on an easing function defined with [code]curve[/code]. This easing function is based on an exponent. The [code]curve[/code] can be any floating-point number, with specific values leading to the following behaviors:
+ Returns an "eased" value of [param x] based on an easing function defined with [param curve]. This easing function is based on an exponent. The [param curve] can be any floating-point number, with specific values leading to the following behaviors:
[codeblock]
- Lower than -1.0 (exclusive): Ease in-out
- 1.0: Linear
@@ -282,16 +340,16 @@
</method>
<method name="error_string">
<return type="String" />
- <argument index="0" name="error" type="int" />
+ <param index="0" name="error" type="int" />
<description>
Returns a human-readable name for the given error code.
</description>
</method>
<method name="exp">
<return type="float" />
- <argument index="0" name="x" type="float" />
+ <param index="0" name="x" type="float" />
<description>
- The natural exponential function. It raises the mathematical constant [b]e[/b] to the power of [code]x[/code] and returns it.
+ The natural exponential function. It raises the mathematical constant [b]e[/b] to the power of [param x] and returns it.
[b]e[/b] has an approximate value of 2.71828, and can be obtained with [code]exp(1)[/code].
For exponents to other bases use the method [method pow].
[codeblock]
@@ -300,10 +358,10 @@
</description>
</method>
<method name="floor">
- <return type="float" />
- <argument index="0" name="x" type="float" />
+ <return type="Variant" />
+ <param index="0" name="x" type="Variant" />
<description>
- Rounds [code]x[/code] downward (towards negative infinity), returning the largest whole number that is not more than [code]x[/code].
+ Rounds [param x] downward (towards negative infinity), returning the largest whole number that is not more than [param x]. Supported types: [int], [float], [Vector2], [Vector3], [Vector4].
[codeblock]
# a is 2.0
var a = floor(2.99)
@@ -311,15 +369,31 @@
a = floor(-2.99)
[/codeblock]
See also [method ceil], [method round], and [method snapped].
- [b]Note:[/b] This method returns a float. If you need an integer, you can use [code]int(x)[/code] directly.
+ [b]Note:[/b] For better type safety, you can use [method floorf], [method floori], [method Vector2.floor], [method Vector3.floor] or [method Vector4.floor] instead.
+ </description>
+ </method>
+ <method name="floorf">
+ <return type="float" />
+ <param index="0" name="x" type="float" />
+ <description>
+ Rounds [param x] downward (towards negative infinity), returning the largest whole number that is not more than [param x].
+ A type-safe version of [method floor], specialzied in floats.
+ </description>
+ </method>
+ <method name="floori">
+ <return type="int" />
+ <param index="0" name="x" type="float" />
+ <description>
+ Rounds [param x] downward (towards negative infinity), returning the largest whole number that is not more than [param x].
+ Equivalent of doing [code]int(x)[/code].
</description>
</method>
<method name="fmod">
<return type="float" />
- <argument index="0" name="x" type="float" />
- <argument index="1" name="y" type="float" />
+ <param index="0" name="x" type="float" />
+ <param index="1" name="y" type="float" />
<description>
- Returns the floating-point remainder of [code]x/y[/code], keeping the sign of [code]x[/code].
+ Returns the floating-point remainder of [code]x/y[/code], keeping the sign of [param x].
[codeblock]
# Remainder is 1.5
var remainder = fmod(7, 5.5)
@@ -329,8 +403,8 @@
</method>
<method name="fposmod">
<return type="float" />
- <argument index="0" name="x" type="float" />
- <argument index="1" name="y" type="float" />
+ <param index="0" name="x" type="float" />
+ <param index="1" name="y" type="float" />
<description>
Returns the floating-point modulus of [code]x/y[/code] that wraps equally in positive and negative.
[codeblock]
@@ -352,7 +426,7 @@
</method>
<method name="hash">
<return type="int" />
- <argument index="0" name="variable" type="Variant" />
+ <param index="0" name="variable" type="Variant" />
<description>
Returns the integer hash of the variable passed.
[codeblock]
@@ -362,9 +436,9 @@
</method>
<method name="instance_from_id">
<return type="Object" />
- <argument index="0" name="instance_id" type="int" />
+ <param index="0" name="instance_id" type="int" />
<description>
- Returns the Object that corresponds to [code]instance_id[/code]. All Objects have a unique instance ID.
+ Returns the Object that corresponds to [param instance_id]. All Objects have a unique instance ID.
[codeblock]
var foo = "bar"
func _ready():
@@ -376,11 +450,11 @@
</method>
<method name="inverse_lerp">
<return type="float" />
- <argument index="0" name="from" type="float" />
- <argument index="1" name="to" type="float" />
- <argument index="2" name="weight" type="float" />
+ <param index="0" name="from" type="float" />
+ <param index="1" name="to" type="float" />
+ <param index="2" name="weight" type="float" />
<description>
- Returns an interpolation or extrapolation factor considering the range specified in [code]from[/code] and [code]to[/code], and the interpolated value specified in [code]weight[/code]. The returned value will be between [code]0.0[/code] and [code]1.0[/code] if [code]weight[/code] is between [code]from[/code] and [code]to[/code] (inclusive). If [code]weight[/code] is located outside this range, then an extrapolation factor will be returned (return value lower than [code]0.0[/code] or greater than [code]1.0[/code]).
+ Returns an interpolation or extrapolation factor considering the range specified in [param from] and [param to], and the interpolated value specified in [param weight]. The returned value will be between [code]0.0[/code] and [code]1.0[/code] if [param weight] is between [param from] and [param to] (inclusive). If [param weight] is located outside this range, then an extrapolation factor will be returned (return value lower than [code]0.0[/code] or greater than [code]1.0[/code]). Use [method clamp] on the result of [method inverse_lerp] if this is not desired.
[codeblock]
# The interpolation ratio in the `lerp()` call below is 0.75.
var middle = lerp(20, 30, 0.75)
@@ -389,73 +463,75 @@
var ratio = inverse_lerp(20, 30, 27.5)
# `ratio` is now 0.75.
[/codeblock]
- See also [method lerp] which performs the reverse of this operation.
+ See also [method lerp] which performs the reverse of this operation, and [method range_lerp] to map a continuous series of values to another.
</description>
</method>
<method name="is_equal_approx">
<return type="bool" />
- <argument index="0" name="a" type="float" />
- <argument index="1" name="b" type="float" />
+ <param index="0" name="a" type="float" />
+ <param index="1" name="b" type="float" />
<description>
- Returns [code]true[/code] if [code]a[/code] and [code]b[/code] are approximately equal to each other.
- Here, approximately equal means that [code]a[/code] and [code]b[/code] are within a small internal epsilon of each other, which scales with the magnitude of the numbers.
+ Returns [code]true[/code] if [param a] and [param b] are approximately equal to each other.
+ Here, approximately equal means that [param a] and [param b] are within a small internal epsilon of each other, which scales with the magnitude of the numbers.
Infinity values of the same sign are considered equal.
</description>
</method>
<method name="is_inf">
<return type="bool" />
- <argument index="0" name="x" type="float" />
+ <param index="0" name="x" type="float" />
<description>
- Returns whether [code]x[/code] is an infinity value (either positive infinity or negative infinity).
+ Returns whether [param x] is an infinity value (either positive infinity or negative infinity).
</description>
</method>
<method name="is_instance_id_valid">
<return type="bool" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
- Returns [code]true[/code] if the Object that corresponds to [code]instance_id[/code] is a valid object (e.g. has not been deleted from memory). All Objects have a unique instance ID.
+ Returns [code]true[/code] if the Object that corresponds to [param id] is a valid object (e.g. has not been deleted from memory). All Objects have a unique instance ID.
</description>
</method>
<method name="is_instance_valid">
<return type="bool" />
- <argument index="0" name="instance" type="Variant" />
+ <param index="0" name="instance" type="Variant" />
<description>
- Returns whether [code]instance[/code] is a valid object (e.g. has not been deleted from memory).
+ Returns whether [param instance] is a valid object (e.g. has not been deleted from memory).
</description>
</method>
<method name="is_nan">
<return type="bool" />
- <argument index="0" name="x" type="float" />
+ <param index="0" name="x" type="float" />
<description>
- Returns whether [code]x[/code] is a NaN ("Not a Number" or invalid) value.
+ Returns whether [param x] is a NaN ("Not a Number" or invalid) value.
</description>
</method>
<method name="is_zero_approx">
<return type="bool" />
- <argument index="0" name="x" type="float" />
+ <param index="0" name="x" type="float" />
<description>
- Returns [code]true[/code] if [code]x[/code] is zero or almost zero.
+ Returns [code]true[/code] if [param x] is zero or almost zero.
This method is faster than using [method is_equal_approx] with one value as zero.
</description>
</method>
<method name="lerp">
- <return type="float" />
- <argument index="0" name="from" type="float" />
- <argument index="1" name="to" type="float" />
- <argument index="2" name="weight" type="float" />
+ <return type="Variant" />
+ <param index="0" name="from" type="Variant" />
+ <param index="1" name="to" type="Variant" />
+ <param index="2" name="weight" type="Variant" />
<description>
- Linearly interpolates between two values by the factor defined in [code]weight[/code]. To perform interpolation, [code]weight[/code] should be between [code]0.0[/code] and [code]1.0[/code] (inclusive). However, values outside this range are allowed and can be used to perform [i]extrapolation[/i].
+ Linearly interpolates between two values by the factor defined in [param weight]. To perform interpolation, [param weight] should be between [code]0.0[/code] and [code]1.0[/code] (inclusive). However, values outside this range are allowed and can be used to perform [i]extrapolation[/i]. Use [method clamp] on the result of [method lerp] if this is not desired.
+ Both [param from] and [param to] must have matching types. Supported types: [float], [Vector2], [Vector3], [Vector4], [Color], [Quaternion], [Basis].
[codeblock]
lerp(0, 4, 0.75) # Returns 3.0
[/codeblock]
- See also [method inverse_lerp] which performs the reverse of this operation. To perform eased interpolation with [method lerp], combine it with [method ease] or [method smoothstep].
+ See also [method inverse_lerp] which performs the reverse of this operation. To perform eased interpolation with [method lerp], combine it with [method ease] or [method smoothstep]. See also [method range_lerp] to map a continuous series of values to another.
+ [b]Note:[/b] For better type safety, you can use [method lerpf], [method Vector2.lerp], [method Vector3.lerp], [method Vector4.lerp], [method Color.lerp], [method Quaternion.slerp] or [method Basis.slerp] instead.
</description>
</method>
<method name="lerp_angle">
<return type="float" />
- <argument index="0" name="from" type="float" />
- <argument index="1" name="to" type="float" />
- <argument index="2" name="weight" type="float" />
+ <param index="0" name="from" type="float" />
+ <param index="1" name="to" type="float" />
+ <param index="2" name="weight" type="float" />
<description>
Linearly interpolates between two angles (in radians) by a normalized value.
Similar to [method lerp], but interpolates correctly when the angles wrap around [constant @GDScript.TAU]. To perform eased interpolation with [method lerp_angle], combine it with [method ease] or [method smoothstep].
@@ -463,30 +539,43 @@
extends Sprite
var elapsed = 0.0
func _process(delta):
- var min_angle = deg2rad(0.0)
- var max_angle = deg2rad(90.0)
+ var min_angle = deg_to_rad(0.0)
+ var max_angle = deg_to_rad(90.0)
rotation = lerp_angle(min_angle, max_angle, elapsed)
elapsed += delta
[/codeblock]
- [b]Note:[/b] This method lerps through the shortest path between [code]from[/code] and [code]to[/code]. However, when these two angles are approximately [code]PI + k * TAU[/code] apart for any integer [code]k[/code], it's not obvious which way they lerp due to floating-point precision errors. For example, [code]lerp_angle(0, PI, weight)[/code] lerps counter-clockwise, while [code]lerp_angle(0, PI + 5 * TAU, weight)[/code] lerps clockwise.
+ [b]Note:[/b] This method lerps through the shortest path between [param from] and [param to]. However, when these two angles are approximately [code]PI + k * TAU[/code] apart for any integer [code]k[/code], it's not obvious which way they lerp due to floating-point precision errors. For example, [code]lerp_angle(0, PI, weight)[/code] lerps counter-clockwise, while [code]lerp_angle(0, PI + 5 * TAU, weight)[/code] lerps clockwise.
+ </description>
+ </method>
+ <method name="lerpf">
+ <return type="float" />
+ <param index="0" name="from" type="float" />
+ <param index="1" name="to" type="float" />
+ <param index="2" name="weight" type="float" />
+ <description>
+ Linearly interpolates between two values by the factor defined in [param weight]. To perform interpolation, [param weight] should be between [code]0.0[/code] and [code]1.0[/code] (inclusive). However, values outside this range are allowed and can be used to perform [i]extrapolation[/i].
+ [codeblock]
+ lerp(0, 4, 0.75) # Returns 3.0
+ [/codeblock]
+ See also [method inverse_lerp] which performs the reverse of this operation. To perform eased interpolation with [method lerp], combine it with [method ease] or [method smoothstep].
</description>
</method>
- <method name="linear2db">
+ <method name="linear_to_db">
<return type="float" />
- <argument index="0" name="lin" type="float" />
+ <param index="0" name="lin" type="float" />
<description>
Converts from linear energy to decibels (audio). This can be used to implement volume sliders that behave as expected (since volume isn't linear). Example:
[codeblock]
# "Slider" refers to a node that inherits Range such as HSlider or VSlider.
# Its range must be configured to go from 0 to 1.
# Change the bus name if you'd like to change the volume of a specific bus only.
- AudioServer.set_bus_volume_db(AudioServer.get_bus_index("Master"), linear2db($Slider.value))
+ AudioServer.set_bus_volume_db(AudioServer.get_bus_index("Master"), linear_to_db($Slider.value))
[/codeblock]
</description>
</method>
<method name="log">
<return type="float" />
- <argument index="0" name="x" type="float" />
+ <param index="0" name="x" type="float" />
<description>
Natural logarithm. The amount of time needed to reach a certain level of continuous growth.
[b]Note:[/b] This is not the same as the "log" function on most calculators, which uses a base 10 logarithm.
@@ -507,8 +596,8 @@
</method>
<method name="maxf">
<return type="float" />
- <argument index="0" name="a" type="float" />
- <argument index="1" name="b" type="float" />
+ <param index="0" name="a" type="float" />
+ <param index="1" name="b" type="float" />
<description>
Returns the maximum of two float values.
[codeblock]
@@ -519,8 +608,8 @@
</method>
<method name="maxi">
<return type="int" />
- <argument index="0" name="a" type="int" />
- <argument index="1" name="b" type="int" />
+ <param index="0" name="a" type="int" />
+ <param index="1" name="b" type="int" />
<description>
Returns the maximum of two int values.
[codeblock]
@@ -540,8 +629,8 @@
</method>
<method name="minf">
<return type="float" />
- <argument index="0" name="a" type="float" />
- <argument index="1" name="b" type="float" />
+ <param index="0" name="a" type="float" />
+ <param index="1" name="b" type="float" />
<description>
Returns the minimum of two float values.
[codeblock]
@@ -552,8 +641,8 @@
</method>
<method name="mini">
<return type="int" />
- <argument index="0" name="a" type="int" />
- <argument index="1" name="b" type="int" />
+ <param index="0" name="a" type="int" />
+ <param index="1" name="b" type="int" />
<description>
Returns the minimum of two int values.
[codeblock]
@@ -564,12 +653,12 @@
</method>
<method name="move_toward">
<return type="float" />
- <argument index="0" name="from" type="float" />
- <argument index="1" name="to" type="float" />
- <argument index="2" name="delta" type="float" />
+ <param index="0" name="from" type="float" />
+ <param index="1" name="to" type="float" />
+ <param index="2" name="delta" type="float" />
<description>
- Moves [code]from[/code] toward [code]to[/code] by the [code]delta[/code] value.
- Use a negative [code]delta[/code] value to move away.
+ Moves [param from] toward [param to] by the [param delta] value.
+ Use a negative [param delta] value to move away.
[codeblock]
move_toward(5, 10, 4) # Returns 9
move_toward(10, 5, 4) # Returns 6
@@ -579,9 +668,9 @@
</method>
<method name="nearest_po2">
<return type="int" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
- Returns the nearest equal or larger power of 2 for integer [code]value[/code].
+ Returns the nearest equal or larger power of 2 for integer [param value].
In other words, returns the smallest value [code]a[/code] where [code]a = pow(2, n)[/code] such that [code]value &lt;= a[/code] for some non-negative integer [code]n[/code].
[codeblock]
nearest_po2(3) # Returns 4
@@ -591,15 +680,15 @@
nearest_po2(0) # Returns 0 (this may not be what you expect)
nearest_po2(-1) # Returns 0 (this may not be what you expect)
[/codeblock]
- [b]Warning:[/b] Due to the way it is implemented, this function returns [code]0[/code] rather than [code]1[/code] for non-positive values of [code]value[/code] (in reality, 1 is the smallest integer power of 2).
+ [b]Warning:[/b] Due to the way it is implemented, this function returns [code]0[/code] rather than [code]1[/code] for non-positive values of [param value] (in reality, 1 is the smallest integer power of 2).
</description>
</method>
<method name="pingpong">
<return type="float" />
- <argument index="0" name="value" type="float" />
- <argument index="1" name="length" type="float" />
+ <param index="0" name="value" type="float" />
+ <param index="1" name="length" type="float" />
<description>
- Returns the [code]value[/code] wrapped between [code]0[/code] and the [code]length[/code]. If the limit is reached, the next value the function returned is decreased to the [code]0[/code] side or increased to the [code]length[/code] side (like a triangle wave). If [code]length[/code] is less than zero, it becomes positive.
+ Returns the [param value] wrapped between [code]0[/code] and the [param length]. If the limit is reached, the next value the function returned is decreased to the [code]0[/code] side or increased to the [param length] side (like a triangle wave). If [param length] is less than zero, it becomes positive.
[codeblock]
pingpong(-3.0, 3.0) # Returns 3
pingpong(-2.0, 3.0) # Returns 2
@@ -616,8 +705,8 @@
</method>
<method name="posmod">
<return type="int" />
- <argument index="0" name="x" type="int" />
- <argument index="1" name="y" type="int" />
+ <param index="0" name="x" type="int" />
+ <param index="1" name="y" type="int" />
<description>
Returns the integer modulus of [code]x/y[/code] that wraps equally in positive and negative.
[codeblock]
@@ -638,10 +727,10 @@
</method>
<method name="pow">
<return type="float" />
- <argument index="0" name="base" type="float" />
- <argument index="1" name="exp" type="float" />
+ <param index="0" name="base" type="float" />
+ <param index="1" name="exp" type="float" />
<description>
- Returns the result of [code]base[/code] raised to the power of [code]exp[/code].
+ Returns the result of [param base] raised to the power of [param exp].
[codeblock]
pow(2, 5) # Returns 32
[/codeblock]
@@ -724,21 +813,21 @@
[/codeblock]
</description>
</method>
- <method name="rad2deg">
+ <method name="rad_to_deg">
<return type="float" />
- <argument index="0" name="rad" type="float" />
+ <param index="0" name="rad" type="float" />
<description>
Converts an angle expressed in radians to degrees.
[codeblock]
- rad2deg(0.523599) # Returns 30
+ rad_to_deg(0.523599) # Returns 30
[/codeblock]
</description>
</method>
<method name="rand_from_seed">
<return type="PackedInt64Array" />
- <argument index="0" name="seed" type="int" />
+ <param index="0" name="seed" type="int" />
<description>
- Random from seed: pass a [code]seed[/code], and an array with both number and new seed is returned. "Seed" here refers to the internal state of the pseudo random number generator. The internal state of the current implementation is 64 bits.
+ Random from seed: pass a [param seed], and an array with both number and new seed is returned. "Seed" here refers to the internal state of the pseudo random number generator. The internal state of the current implementation is 64 bits.
</description>
</method>
<method name="randf">
@@ -752,10 +841,10 @@
</method>
<method name="randf_range">
<return type="float" />
- <argument index="0" name="from" type="float" />
- <argument index="1" name="to" type="float" />
+ <param index="0" name="from" type="float" />
+ <param index="1" name="to" type="float" />
<description>
- Returns a random floating point value on the interval between [code]from[/code] and [code]to[/code] (inclusive).
+ Returns a random floating point value on the interval between [param from] and [param to] (inclusive).
[codeblock]
prints(randf_range(-10, 10), randf_range(-10, 10)) # Prints e.g. -3.844535 7.45315
[/codeblock]
@@ -763,10 +852,10 @@
</method>
<method name="randfn">
<return type="float" />
- <argument index="0" name="mean" type="float" />
- <argument index="1" name="deviation" type="float" />
+ <param index="0" name="mean" type="float" />
+ <param index="1" name="deviation" type="float" />
<description>
- Returns a normally-distributed pseudo-random floating point value using Box-Muller transform with the specified [code]mean[/code] and a standard [code]deviation[/code]. This is also called Gaussian distribution.
+ Returns a normally-distributed pseudo-random floating point value using Box-Muller transform with the specified [param mean] and a standard [param deviation]. This is also called Gaussian distribution.
</description>
</method>
<method name="randi">
@@ -783,10 +872,10 @@
</method>
<method name="randi_range">
<return type="int" />
- <argument index="0" name="from" type="int" />
- <argument index="1" name="to" type="int" />
+ <param index="0" name="from" type="int" />
+ <param index="1" name="to" type="int" />
<description>
- Returns a random signed 32-bit integer between [code]from[/code] and [code]to[/code] (inclusive). If [code]to[/code] is lesser than [code]from[/code], they are swapped.
+ Returns a random signed 32-bit integer between [param from] and [param to] (inclusive). If [param to] is lesser than [param from], they are swapped.
[codeblock]
print(randi_range(0, 1)) # Prints 0 or 1
print(randi_range(-10, 1000)) # Prints any number from -10 to 1000
@@ -801,16 +890,17 @@
</method>
<method name="range_lerp">
<return type="float" />
- <argument index="0" name="value" type="float" />
- <argument index="1" name="istart" type="float" />
- <argument index="2" name="istop" type="float" />
- <argument index="3" name="ostart" type="float" />
- <argument index="4" name="ostop" type="float" />
+ <param index="0" name="value" type="float" />
+ <param index="1" name="istart" type="float" />
+ <param index="2" name="istop" type="float" />
+ <param index="3" name="ostart" type="float" />
+ <param index="4" name="ostop" type="float" />
<description>
- Maps a [code]value[/code] from range [code][istart, istop][/code] to [code][ostart, ostop][/code].
+ Maps a [param value] from range [code][istart, istop][/code] to [code][ostart, ostop][/code]. See also [method lerp] and [method inverse_lerp]. If [param value] is outside [code][istart, istop][/code], then the resulting value will also be outside [code][ostart, ostop][/code]. Use [method clamp] on the result of [method range_lerp] if this is not desired.
[codeblock]
range_lerp(75, 0, 100, -1, 1) # Returns 0.5
[/codeblock]
+ For complex use cases where you need multiple ranges, consider using [Curve] or [Gradient] instead.
</description>
</method>
<method name="rid_allocate_id">
@@ -821,24 +911,43 @@
</method>
<method name="rid_from_int64">
<return type="RID" />
- <argument index="0" name="base" type="int" />
+ <param index="0" name="base" type="int" />
<description>
Create a RID from an int64. This is used mainly from native extensions to build servers.
</description>
</method>
<method name="round">
- <return type="float" />
- <argument index="0" name="x" type="float" />
+ <return type="Variant" />
+ <param index="0" name="x" type="Variant" />
<description>
- Rounds [code]x[/code] to the nearest whole number, with halfway cases rounded away from zero.
+ Rounds [param x] to the nearest whole number, with halfway cases rounded away from zero. Supported types: [int], [float], [Vector2], [Vector3], [Vector4].
[codeblock]
+ round(2.4) # Returns 2
+ round(2.5) # Returns 3
round(2.6) # Returns 3
[/codeblock]
See also [method floor], [method ceil], and [method snapped].
+ [b]Note:[/b] For better type safety, you can use [method roundf], [method roundi], [method Vector2.round], [method Vector3.round] or [method Vector4.round] instead.
+ </description>
+ </method>
+ <method name="roundf">
+ <return type="float" />
+ <param index="0" name="x" type="float" />
+ <description>
+ Rounds [param x] to the nearest whole number, with halfway cases rounded away from zero.
+ A type-safe version of [method round], specialzied in floats.
+ </description>
+ </method>
+ <method name="roundi">
+ <return type="int" />
+ <param index="0" name="x" type="float" />
+ <description>
+ Rounds [param x] to the nearest whole number, with halfway cases rounded away from zero.
+ A type-safe version of [method round] that returns integer.
</description>
</method>
<method name="seed">
- <argument index="0" name="base" type="int" />
+ <param index="0" name="base" type="int" />
<description>
Sets seed for the random number generator.
[codeblock]
@@ -849,9 +958,9 @@
</method>
<method name="sign">
<return type="Variant" />
- <argument index="0" name="x" type="Variant" />
+ <param index="0" name="x" type="Variant" />
<description>
- Returns the sign of [code]x[/code] as same type of [Variant] as [code]x[/code] with each component being -1, 0 and 1 for each negative, zero and positive values respectivelu. Variant types [int], [float] (real), [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
+ Returns the sign of [param x] as same type of [Variant] as [param x] with each component being -1, 0 and 1 for each negative, zero and positive values respectivelu. Variant types [int], [float] (real), [Vector2], [Vector2i], [Vector3] and [Vector3i] are supported.
[codeblock]
sign(-6.0) # Returns -1
sign(0.0) # Returns 0
@@ -863,9 +972,9 @@
</method>
<method name="signf">
<return type="float" />
- <argument index="0" name="x" type="float" />
+ <param index="0" name="x" type="float" />
<description>
- Returns the sign of [code]x[/code] as a float: -1.0 or 1.0. Returns 0.0 if [code]x[/code] is 0.
+ Returns the sign of [param x] as a float: -1.0 or 1.0. Returns 0.0 if [param x] is 0.
[codeblock]
sign(-6.0) # Returns -1.0
sign(0.0) # Returns 0.0
@@ -875,9 +984,9 @@
</method>
<method name="signi">
<return type="int" />
- <argument index="0" name="x" type="int" />
+ <param index="0" name="x" type="int" />
<description>
- Returns the sign of [code]x[/code] as an integer: -1 or 1. Returns 0 if [code]x[/code] is 0.
+ Returns the sign of [param x] as an integer: -1 or 1. Returns 0 if [param x] is 0.
[codeblock]
sign(-6) # Returns -1
sign(0) # Returns 0
@@ -887,20 +996,20 @@
</method>
<method name="sin">
<return type="float" />
- <argument index="0" name="angle_rad" type="float" />
+ <param index="0" name="angle_rad" type="float" />
<description>
- Returns the sine of angle [code]angle_rad[/code] in radians.
+ Returns the sine of angle [param angle_rad] in radians.
[codeblock]
- sin(0.523599) # Returns 0.5
- sin(deg2rad(90)) # Returns 1.0
+ sin(0.523599) # Returns 0.5
+ sin(deg_to_rad(90)) # Returns 1.0
[/codeblock]
</description>
</method>
<method name="sinh">
<return type="float" />
- <argument index="0" name="x" type="float" />
+ <param index="0" name="x" type="float" />
<description>
- Returns the hyperbolic sine of [code]x[/code].
+ Returns the hyperbolic sine of [param x].
[codeblock]
var a = log(2.0) # Returns 0.693147
sinh(a) # Returns 0.75
@@ -909,12 +1018,12 @@
</method>
<method name="smoothstep">
<return type="float" />
- <argument index="0" name="from" type="float" />
- <argument index="1" name="to" type="float" />
- <argument index="2" name="x" type="float" />
+ <param index="0" name="from" type="float" />
+ <param index="1" name="to" type="float" />
+ <param index="2" name="x" type="float" />
<description>
- Returns the result of smoothly interpolating the value of [code]x[/code] between [code]0[/code] and [code]1[/code], based on the where [code]x[/code] lies with respect to the edges [code]from[/code] and [code]to[/code].
- The return value is [code]0[/code] if [code]x &lt;= from[/code], and [code]1[/code] if [code]x &gt;= to[/code]. If [code]x[/code] lies between [code]from[/code] and [code]to[/code], the returned value follows an S-shaped curve that maps [code]x[/code] between [code]0[/code] and [code]1[/code].
+ Returns the result of smoothly interpolating the value of [param x] between [code]0[/code] and [code]1[/code], based on the where [param x] lies with respect to the edges [param from] and [param to].
+ The return value is [code]0[/code] if [code]x &lt;= from[/code], and [code]1[/code] if [code]x &gt;= to[/code]. If [param x] lies between [param from] and [param to], the returned value follows an S-shaped curve that maps [param x] between [code]0[/code] and [code]1[/code].
This S-shaped curve is the cubic Hermite interpolator, given by [code]f(y) = 3*y^2 - 2*y^3[/code] where [code]y = (x-from) / (to-from)[/code].
[codeblock]
smoothstep(0, 2, -5.0) # Returns 0.0
@@ -928,10 +1037,10 @@
</method>
<method name="snapped">
<return type="float" />
- <argument index="0" name="x" type="float" />
- <argument index="1" name="step" type="float" />
+ <param index="0" name="x" type="float" />
+ <param index="1" name="step" type="float" />
<description>
- Snaps float value [code]x[/code] to a given [code]step[/code]. This can also be used to round a floating point number to an arbitrary number of decimals.
+ Snaps float value [param x] to a given [param step]. This can also be used to round a floating point number to an arbitrary number of decimals.
[codeblock]
snapped(100, 32) # Returns 96
snapped(3.14159, 0.01) # Returns 3.14
@@ -941,18 +1050,18 @@
</method>
<method name="sqrt">
<return type="float" />
- <argument index="0" name="x" type="float" />
+ <param index="0" name="x" type="float" />
<description>
- Returns the square root of [code]x[/code], where [code]x[/code] is a non-negative number.
+ Returns the square root of [param x], where [param x] is a non-negative number.
[codeblock]
sqrt(9) # Returns 3
[/codeblock]
- [b]Note:[/b] Negative values of [code]x[/code] return NaN. If you need negative inputs, use [code]System.Numerics.Complex[/code] in C#.
+ [b]Note:[/b] Negative values of [param x] return NaN. If you need negative inputs, use [code]System.Numerics.Complex[/code] in C#.
</description>
</method>
<method name="step_decimals">
<return type="int" />
- <argument index="0" name="x" type="float" />
+ <param index="0" name="x" type="float" />
<description>
Returns the position of the first non-zero digit, after the decimal point. Note that the maximum return value is 10, which is a design decision in the implementation.
[codeblock]
@@ -971,33 +1080,33 @@
Converts one or more arguments of any type to string in the best way possible.
</description>
</method>
- <method name="str2var">
+ <method name="str_to_var">
<return type="Variant" />
- <argument index="0" name="string" type="String" />
+ <param index="0" name="string" type="String" />
<description>
- Converts a formatted string that was returned by [method var2str] to the original value.
+ Converts a formatted [param string] that was returned by [method var_to_str] to the original value.
[codeblock]
var a = '{ "a": 1, "b": 2 }'
- var b = str2var(a)
+ var b = str_to_var(a)
print(b["a"]) # Prints 1
[/codeblock]
</description>
</method>
<method name="tan">
<return type="float" />
- <argument index="0" name="angle_rad" type="float" />
+ <param index="0" name="angle_rad" type="float" />
<description>
- Returns the tangent of angle [code]angle_rad[/code] in radians.
+ Returns the tangent of angle [param angle_rad] in radians.
[codeblock]
- tan(deg2rad(45)) # Returns 1
+ tan(deg_to_rad(45)) # Returns 1
[/codeblock]
</description>
</method>
<method name="tanh">
<return type="float" />
- <argument index="0" name="x" type="float" />
+ <param index="0" name="x" type="float" />
<description>
- Returns the hyperbolic tangent of [code]x[/code].
+ Returns the hyperbolic tangent of [param x].
[codeblock]
var a = log(2.0) # Returns 0.693147
tanh(a) # Returns 0.6
@@ -1006,7 +1115,7 @@
</method>
<method name="typeof">
<return type="int" />
- <argument index="0" name="variable" type="Variant" />
+ <param index="0" name="variable" type="Variant" />
<description>
Returns the internal type of the given Variant object, using the [enum Variant.Type] values.
[codeblock]
@@ -1020,29 +1129,29 @@
[/codeblock]
</description>
</method>
- <method name="var2bytes">
+ <method name="var_to_bytes">
<return type="PackedByteArray" />
- <argument index="0" name="variable" type="Variant" />
+ <param index="0" name="variable" type="Variant" />
<description>
- Encodes a [Variant] value to a byte array, without encoding objects. Deserialization can be done with [method bytes2var].
- [b]Note:[/b] If you need object serialization, see [method var2bytes_with_objects].
+ Encodes a [Variant] value to a byte array, without encoding objects. Deserialization can be done with [method bytes_to_var].
+ [b]Note:[/b] If you need object serialization, see [method var_to_bytes_with_objects].
</description>
</method>
- <method name="var2bytes_with_objects">
+ <method name="var_to_bytes_with_objects">
<return type="PackedByteArray" />
- <argument index="0" name="variable" type="Variant" />
+ <param index="0" name="variable" type="Variant" />
<description>
- Encodes a [Variant] value to a byte array. Encoding objects is allowed (and can potentially include code). Deserialization can be done with [method bytes2var_with_objects].
+ Encodes a [Variant] value to a byte array. Encoding objects is allowed (and can potentially include code). Deserialization can be done with [method bytes_to_var_with_objects].
</description>
</method>
- <method name="var2str">
+ <method name="var_to_str">
<return type="String" />
- <argument index="0" name="variable" type="Variant" />
+ <param index="0" name="variable" type="Variant" />
<description>
- Converts a Variant [code]variable[/code] to a formatted string that can later be parsed using [method str2var].
+ Converts a Variant [param variable] to a formatted string that can later be parsed using [method str_to_var].
[codeblock]
a = { "a": 1, "b": 2 }
- print(var2str(a))
+ print(var_to_str(a))
[/codeblock]
prints
[codeblock]
@@ -1055,19 +1164,19 @@
</method>
<method name="weakref">
<return type="Variant" />
- <argument index="0" name="obj" type="Variant" />
+ <param index="0" name="obj" type="Variant" />
<description>
- Returns a weak reference to an object, or [code]null[/code] is the argument is invalid.
+ Returns a weak reference to an object, or [code]null[/code] if the argument is invalid.
A weak reference to an object is not enough to keep the object alive: when the only remaining references to a referent are weak references, garbage collection is free to destroy the referent and reuse its memory for something else. However, until the object is actually destroyed the weak reference may return the object even if there are no strong references to it.
</description>
</method>
<method name="wrap">
<return type="Variant" />
- <argument index="0" name="value" type="Variant" />
- <argument index="1" name="min" type="Variant" />
- <argument index="2" name="max" type="Variant" />
+ <param index="0" name="value" type="Variant" />
+ <param index="1" name="min" type="Variant" />
+ <param index="2" name="max" type="Variant" />
<description>
- Wraps the [Variant] [code]value[/code] between [code]min[/code] and [code]max[/code].
+ Wraps the [Variant] [param value] between [param min] and [param max].
Usable for creating loop-alike behavior or infinite surfaces.
Variant types [int] and [float] (real) are supported. If any of the argument is [float] the result will be [float], otherwise it is [int].
[codeblock]
@@ -1084,11 +1193,11 @@
</method>
<method name="wrapf">
<return type="float" />
- <argument index="0" name="value" type="float" />
- <argument index="1" name="min" type="float" />
- <argument index="2" name="max" type="float" />
+ <param index="0" name="value" type="float" />
+ <param index="1" name="min" type="float" />
+ <param index="2" name="max" type="float" />
<description>
- Wraps float [code]value[/code] between [code]min[/code] and [code]max[/code].
+ Wraps float [param value] between [param min] and [param max].
Usable for creating loop-alike behavior or infinite surfaces.
[codeblock]
# Infinite loop between 5.0 and 9.9
@@ -1102,17 +1211,17 @@
# Infinite rotation (in radians)
angle = wrapf(angle + 0.1, -PI, PI)
[/codeblock]
- [b]Note:[/b] If [code]min[/code] is [code]0[/code], this is equivalent to [method fposmod], so prefer using that instead.
+ [b]Note:[/b] If [param min] is [code]0[/code], this is equivalent to [method fposmod], so prefer using that instead.
[code]wrapf[/code] is more flexible than using the [method fposmod] approach by giving the user control over the minimum value.
</description>
</method>
<method name="wrapi">
<return type="int" />
- <argument index="0" name="value" type="int" />
- <argument index="1" name="min" type="int" />
- <argument index="2" name="max" type="int" />
+ <param index="0" name="value" type="int" />
+ <param index="1" name="min" type="int" />
+ <param index="2" name="max" type="int" />
<description>
- Wraps integer [code]value[/code] between [code]min[/code] and [code]max[/code].
+ Wraps integer [param value] between [param min] and [param max].
Usable for creating loop-alike behavior or infinite surfaces.
[codeblock]
# Infinite loop between 5 and 9
@@ -1168,7 +1277,7 @@
</member>
<member name="JavaScript" type="JavaScript" setter="" getter="">
The [JavaScript] singleton.
- [b]Note:[/b] Only implemented on HTML5.
+ [b]Note:[/b] Only implemented on the Web platform.
</member>
<member name="Marshalls" type="Marshalls" setter="" getter="">
The [Marshalls] singleton.
@@ -1209,20 +1318,22 @@
The [ResourceSaver] singleton.
</member>
<member name="ResourceUID" type="ResourceUID" setter="" getter="">
+ The [ResourceUID] singleton.
</member>
<member name="TextServerManager" type="TextServerManager" setter="" getter="">
The [TextServerManager] singleton.
</member>
+ <member name="ThemeDB" type="ThemeDB" setter="" getter="">
+ The [ThemeDB] singleton.
+ </member>
<member name="Time" type="Time" setter="" getter="">
The [Time] singleton.
</member>
<member name="TranslationServer" type="TranslationServer" setter="" getter="">
The [TranslationServer] singleton.
</member>
- <member name="VisualScriptCustomNodes" type="VisualScriptCustomNodes" setter="" getter="">
- The [VisualScriptCustomNodes] singleton.
- </member>
<member name="WorkerThreadPool" type="WorkerThreadPool" setter="" getter="">
+ The [WorkerThreadPool] singleton.
</member>
<member name="XRServer" type="XRServer" setter="" getter="">
The [XRServer] singleton.
@@ -2504,7 +2615,7 @@
</constant>
<constant name="PROPERTY_HINT_RANGE" value="1" enum="PropertyHint">
Hints that an integer or float property should be within a range specified via the hint string [code]"min,max"[/code] or [code]"min,max,step"[/code]. The hint string can optionally include [code]"or_greater"[/code] and/or [code]"or_lesser"[/code] to allow manual input going respectively above the max or below the min values. Example: [code]"-360,360,1,or_greater,or_lesser"[/code].
- Additionally, other keywords can be included: "exp" for exponential range editing, "radians" for editing radian angles in degrees, "degrees" to hint at an angle and "no_slider" to hide the slider.
+ Additionally, other keywords can be included: [code]"exp"[/code] for exponential range editing, [code]"radians"[/code] for editing radian angles in degrees, [code]"degrees"[/code] to hint at an angle and [code]"no_slider"[/code] to hide the slider.
</constant>
<constant name="PROPERTY_HINT_ENUM" value="2" enum="PropertyHint">
Hints that an integer, float or string property is an enumerated value to pick in a list specified via a hint string.
@@ -2515,7 +2626,7 @@
Unlike [constant PROPERTY_HINT_ENUM] a property with this hint still accepts arbitrary values and can be empty. The list of values serves to suggest possible values.
</constant>
<constant name="PROPERTY_HINT_EXP_EASING" value="4" enum="PropertyHint">
- Hints that a float property should be edited via an exponential easing function. The hint string can include [code]"attenuation"[/code] to flip the curve horizontally and/or [code]"inout"[/code] to also include in/out easing.
+ Hints that a float property should be edited via an exponential easing function. The hint string can include [code]"attenuation"[/code] to flip the curve horizontally and/or [code]"positive_only"[/code] to exclude in/out easing and limit values to be greater than or equal to zero.
</constant>
<constant name="PROPERTY_HINT_LINK" value="5" enum="PropertyHint">
Hints that a vector property should allow linking values (e.g. to edit both [code]x[/code] and [code]y[/code] together).
@@ -2626,7 +2737,13 @@
</constant>
<constant name="PROPERTY_HINT_NODE_TYPE" value="44" enum="PropertyHint">
</constant>
- <constant name="PROPERTY_HINT_MAX" value="45" enum="PropertyHint">
+ <constant name="PROPERTY_HINT_HIDE_QUATERNION_EDIT" value="45" enum="PropertyHint">
+ Hints that a quaternion property should disable the temporary euler editor.
+ </constant>
+ <constant name="PROPERTY_HINT_PASSWORD" value="46" enum="PropertyHint">
+ Hints that a string property is a password, and every character is replaced with the secret character.
+ </constant>
+ <constant name="PROPERTY_HINT_MAX" value="47" enum="PropertyHint">
</constant>
<constant name="PROPERTY_USAGE_NONE" value="0" enum="PropertyUsageFlags">
</constant>
diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml
index db880efaf2..e2e4e7c61d 100644
--- a/doc/classes/AABB.xml
+++ b/doc/classes/AABB.xml
@@ -23,15 +23,15 @@
</constructor>
<constructor name="AABB">
<return type="AABB" />
- <argument index="0" name="from" type="AABB" />
+ <param index="0" name="from" type="AABB" />
<description>
Constructs an [AABB] as a copy of the given [AABB].
</description>
</constructor>
<constructor name="AABB">
<return type="AABB" />
- <argument index="0" name="position" type="Vector3" />
- <argument index="1" name="size" type="Vector3" />
+ <param index="0" name="position" type="Vector3" />
+ <param index="1" name="size" type="Vector3" />
<description>
Constructs an [AABB] from a position and size.
</description>
@@ -46,14 +46,14 @@
</method>
<method name="encloses" qualifiers="const">
<return type="bool" />
- <argument index="0" name="with" type="AABB" />
+ <param index="0" name="with" type="AABB" />
<description>
Returns [code]true[/code] if this [AABB] completely encloses another one.
</description>
</method>
<method name="expand" qualifiers="const">
<return type="AABB" />
- <argument index="0" name="to_point" type="Vector3" />
+ <param index="0" name="to_point" type="Vector3" />
<description>
Returns a copy of this [AABB] expanded to include a given point.
[b]Example:[/b]
@@ -81,7 +81,7 @@
</method>
<method name="get_endpoint" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Gets the position of the 8 endpoints of the [AABB] in space.
</description>
@@ -124,7 +124,7 @@
</method>
<method name="get_support" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="dir" type="Vector3" />
+ <param index="0" name="dir" type="Vector3" />
<description>
Returns the support point in a given direction. This is useful for collision detection algorithms.
</description>
@@ -137,9 +137,9 @@
</method>
<method name="grow" qualifiers="const">
<return type="AABB" />
- <argument index="0" name="by" type="float" />
+ <param index="0" name="by" type="float" />
<description>
- Returns a copy of the [AABB] grown a given amount of units towards all the sides.
+ Returns a copy of the [AABB] grown a given number of units towards all the sides.
</description>
</method>
<method name="has_no_surface" qualifiers="const">
@@ -156,7 +156,7 @@
</method>
<method name="has_point" qualifiers="const">
<return type="bool" />
- <argument index="0" name="point" type="Vector3" />
+ <param index="0" name="point" type="Vector3" />
<description>
Returns [code]true[/code] if the [AABB] contains a point. Points on the faces of the AABB are considered included, though float-point precision errors may impact the accuracy of such checks.
[b]Note:[/b] This method is not reliable for [AABB] with a [i]negative size[/i]. Use [method abs] to get a positive sized equivalent [AABB] to check for contained points.
@@ -164,52 +164,52 @@
</method>
<method name="intersection" qualifiers="const">
<return type="AABB" />
- <argument index="0" name="with" type="AABB" />
+ <param index="0" name="with" type="AABB" />
<description>
Returns the intersection between two [AABB]. An empty AABB (size [code](0, 0, 0)[/code]) is returned on failure.
</description>
</method>
<method name="intersects" qualifiers="const">
<return type="bool" />
- <argument index="0" name="with" type="AABB" />
+ <param index="0" name="with" type="AABB" />
<description>
Returns [code]true[/code] if the [AABB] overlaps with another.
</description>
</method>
<method name="intersects_plane" qualifiers="const">
<return type="bool" />
- <argument index="0" name="plane" type="Plane" />
+ <param index="0" name="plane" type="Plane" />
<description>
Returns [code]true[/code] if the [AABB] is on both sides of a plane.
</description>
</method>
<method name="intersects_ray" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="from" type="Vector3" />
- <argument index="1" name="dir" type="Vector3" />
+ <param index="0" name="from" type="Vector3" />
+ <param index="1" name="dir" type="Vector3" />
<description>
</description>
</method>
<method name="intersects_segment" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="from" type="Vector3" />
- <argument index="1" name="to" type="Vector3" />
+ <param index="0" name="from" type="Vector3" />
+ <param index="1" name="to" type="Vector3" />
<description>
- Returns [code]true[/code] if the [AABB] intersects the line segment between [code]from[/code] and [code]to[/code].
+ Returns [code]true[/code] if the [AABB] intersects the line segment between [param from] and [param to].
</description>
</method>
<method name="is_equal_approx" qualifiers="const">
<return type="bool" />
- <argument index="0" name="aabb" type="AABB" />
+ <param index="0" name="aabb" type="AABB" />
<description>
- Returns [code]true[/code] if this [AABB] and [code]aabb[/code] are approximately equal, by calling [method @GlobalScope.is_equal_approx] on each component.
+ Returns [code]true[/code] if this [AABB] and [param aabb] are approximately equal, by calling [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
<method name="merge" qualifiers="const">
<return type="AABB" />
- <argument index="0" name="with" type="AABB" />
+ <param index="0" name="with" type="AABB" />
<description>
- Returns a larger [AABB] that contains both this [AABB] and [code]with[/code].
+ Returns a larger [AABB] that contains both this [AABB] and [param with].
</description>
</method>
</methods>
@@ -228,7 +228,7 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="AABB" />
+ <param index="0" name="right" type="AABB" />
<description>
Returns [code]true[/code] if the vectors are not equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
@@ -236,14 +236,14 @@
</operator>
<operator name="operator *">
<return type="AABB" />
- <argument index="0" name="right" type="Transform3D" />
+ <param index="0" name="right" type="Transform3D" />
<description>
Inversely transforms (multiplies) the [AABB] by the given [Transform3D] transformation matrix.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="AABB" />
+ <param index="0" name="right" type="AABB" />
<description>
Returns [code]true[/code] if the AABBs are exactly equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
diff --git a/doc/classes/AESContext.xml b/doc/classes/AESContext.xml
index 82634f8859..69cd54a79b 100644
--- a/doc/classes/AESContext.xml
+++ b/doc/classes/AESContext.xml
@@ -94,19 +94,19 @@
</method>
<method name="start">
<return type="int" enum="Error" />
- <argument index="0" name="mode" type="int" enum="AESContext.Mode" />
- <argument index="1" name="key" type="PackedByteArray" />
- <argument index="2" name="iv" type="PackedByteArray" default="PackedByteArray()" />
+ <param index="0" name="mode" type="int" enum="AESContext.Mode" />
+ <param index="1" name="key" type="PackedByteArray" />
+ <param index="2" name="iv" type="PackedByteArray" default="PackedByteArray()" />
<description>
- Start the AES context in the given [code]mode[/code]. A [code]key[/code] of either 16 or 32 bytes must always be provided, while an [code]iv[/code] (initialization vector) of exactly 16 bytes, is only needed when [code]mode[/code] is either [constant MODE_CBC_ENCRYPT] or [constant MODE_CBC_DECRYPT].
+ Start the AES context in the given [param mode]. A [param key] of either 16 or 32 bytes must always be provided, while an [param iv] (initialization vector) of exactly 16 bytes, is only needed when [param mode] is either [constant MODE_CBC_ENCRYPT] or [constant MODE_CBC_DECRYPT].
</description>
</method>
<method name="update">
<return type="PackedByteArray" />
- <argument index="0" name="src" type="PackedByteArray" />
+ <param index="0" name="src" type="PackedByteArray" />
<description>
- Run the desired operation for this AES context. Will return a [PackedByteArray] containing the result of encrypting (or decrypting) the given [code]src[/code]. See [method start] for mode of operation.
- [b]Note:[/b] The size of [code]src[/code] must be a multiple of 16. Apply some padding if needed.
+ Run the desired operation for this AES context. Will return a [PackedByteArray] containing the result of encrypting (or decrypting) the given [param src]. See [method start] for mode of operation.
+ [b]Note:[/b] The size of [param src] must be a multiple of 16. Apply some padding if needed.
</description>
</method>
</methods>
diff --git a/doc/classes/AStar2D.xml b/doc/classes/AStar2D.xml
index c05fb885b9..6e76df647e 100644
--- a/doc/classes/AStar2D.xml
+++ b/doc/classes/AStar2D.xml
@@ -11,8 +11,8 @@
<methods>
<method name="_compute_cost" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="from_id" type="int" />
- <argument index="1" name="to_id" type="int" />
+ <param index="0" name="from_id" type="int" />
+ <param index="1" name="to_id" type="int" />
<description>
Called when computing the cost between two connected points.
Note that this function is hidden in the default [code]AStar2D[/code] class.
@@ -20,8 +20,8 @@
</method>
<method name="_estimate_cost" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="from_id" type="int" />
- <argument index="1" name="to_id" type="int" />
+ <param index="0" name="from_id" type="int" />
+ <param index="1" name="to_id" type="int" />
<description>
Called when estimating the cost between a point and the path's ending point.
Note that this function is hidden in the default [code]AStar2D[/code] class.
@@ -29,12 +29,12 @@
</method>
<method name="add_point">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="position" type="Vector2" />
- <argument index="2" name="weight_scale" type="float" default="1.0" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="position" type="Vector2" />
+ <param index="2" name="weight_scale" type="float" default="1.0" />
<description>
- Adds a new point at the given position with the given identifier. The [code]id[/code] must be 0 or larger, and the [code]weight_scale[/code] must be 0.0 or greater.
- The [code]weight_scale[/code] is multiplied by the result of [method _compute_cost] when determining the overall cost of traveling across a segment from a neighboring point to this point. Thus, all else being equal, the algorithm prefers points with lower [code]weight_scale[/code]s to form a path.
+ Adds a new point at the given position with the given identifier. The [param id] must be 0 or larger, and the [param weight_scale] must be 0.0 or greater.
+ The [param weight_scale] is multiplied by the result of [method _compute_cost] when determining the overall cost of traveling across a segment from a neighboring point to this point. Thus, all else being equal, the algorithm prefers points with lower [param weight_scale]s to form a path.
[codeblocks]
[gdscript]
var astar = AStar2D.new()
@@ -45,16 +45,16 @@
astar.AddPoint(1, new Vector2(1, 0), 4); // Adds the point (1, 0) with weight_scale 4 and id 1
[/csharp]
[/codeblocks]
- If there already exists a point for the given [code]id[/code], its position and weight scale are updated to the given values.
+ If there already exists a point for the given [param id], its position and weight scale are updated to the given values.
</description>
</method>
<method name="are_points_connected" qualifiers="const">
<return type="bool" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="to_id" type="int" />
- <argument index="2" name="bidirectional" type="bool" default="true" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="to_id" type="int" />
+ <param index="2" name="bidirectional" type="bool" default="true" />
<description>
- Returns whether there is a connection/segment between the given points. If [code]bidirectional[/code] is [code]false[/code], returns whether movement from [code]id[/code] to [code]to_id[/code] is possible through this segment.
+ Returns whether there is a connection/segment between the given points. If [param bidirectional] is [code]false[/code], returns whether movement from [param id] to [param to_id] is possible through this segment.
</description>
</method>
<method name="clear">
@@ -65,11 +65,11 @@
</method>
<method name="connect_points">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="to_id" type="int" />
- <argument index="2" name="bidirectional" type="bool" default="true" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="to_id" type="int" />
+ <param index="2" name="bidirectional" type="bool" default="true" />
<description>
- Creates a segment between the given points. If [code]bidirectional[/code] is [code]false[/code], only movement from [code]id[/code] to [code]to_id[/code] is allowed, not the reverse direction.
+ Creates a segment between the given points. If [param bidirectional] is [code]false[/code], only movement from [param id] to [param to_id] is allowed, not the reverse direction.
[codeblocks]
[gdscript]
var astar = AStar2D.new()
@@ -88,11 +88,11 @@
</method>
<method name="disconnect_points">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="to_id" type="int" />
- <argument index="2" name="bidirectional" type="bool" default="true" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="to_id" type="int" />
+ <param index="2" name="bidirectional" type="bool" default="true" />
<description>
- Deletes the segment between the given points. If [code]bidirectional[/code] is [code]false[/code], only movement from [code]id[/code] to [code]to_id[/code] is prevented, and a unidirectional segment possibly remains.
+ Deletes the segment between the given points. If [param bidirectional] is [code]false[/code], only movement from [param id] to [param to_id] is prevented, and a unidirectional segment possibly remains.
</description>
</method>
<method name="get_available_point_id" qualifiers="const">
@@ -103,18 +103,18 @@
</method>
<method name="get_closest_point" qualifiers="const">
<return type="int" />
- <argument index="0" name="to_position" type="Vector2" />
- <argument index="1" name="include_disabled" type="bool" default="false" />
+ <param index="0" name="to_position" type="Vector2" />
+ <param index="1" name="include_disabled" type="bool" default="false" />
<description>
- Returns the ID of the closest point to [code]to_position[/code], optionally taking disabled points into account. Returns [code]-1[/code] if there are no points in the points pool.
- [b]Note:[/b] If several points are the closest to [code]to_position[/code], the one with the smallest ID will be returned, ensuring a deterministic result.
+ Returns the ID of the closest point to [param to_position], optionally taking disabled points into account. Returns [code]-1[/code] if there are no points in the points pool.
+ [b]Note:[/b] If several points are the closest to [param to_position], the one with the smallest ID will be returned, ensuring a deterministic result.
</description>
</method>
<method name="get_closest_position_in_segment" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="to_position" type="Vector2" />
+ <param index="0" name="to_position" type="Vector2" />
<description>
- Returns the closest position to [code]to_position[/code] that resides inside a segment between two connected points.
+ Returns the closest position to [param to_position] that resides inside a segment between two connected points.
[codeblocks]
[gdscript]
var astar = AStar2D.new()
@@ -136,8 +136,8 @@
</method>
<method name="get_id_path">
<return type="PackedInt64Array" />
- <argument index="0" name="from_id" type="int" />
- <argument index="1" name="to_id" type="int" />
+ <param index="0" name="from_id" type="int" />
+ <param index="1" name="to_id" type="int" />
<description>
Returns an array with the IDs of the points that form the path found by AStar2D between the given points. The array is ordered from the starting point to the ending point of the path.
[codeblocks]
@@ -180,7 +180,7 @@
</method>
<method name="get_point_connections">
<return type="PackedInt64Array" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Returns an array with the IDs of the points that form the connection with the given point.
[codeblocks]
@@ -218,15 +218,15 @@
</description>
</method>
<method name="get_point_ids">
- <return type="Array" />
+ <return type="PackedInt64Array" />
<description>
Returns an array of all point IDs.
</description>
</method>
<method name="get_point_path">
<return type="PackedVector2Array" />
- <argument index="0" name="from_id" type="int" />
- <argument index="1" name="to_id" type="int" />
+ <param index="0" name="from_id" type="int" />
+ <param index="1" name="to_id" type="int" />
<description>
Returns an array with the points that are in the path found by AStar2D between the given points. The array is ordered from the starting point to the ending point of the path.
[b]Note:[/b] This method is not thread-safe. If called from a [Thread], it will return an empty [PackedVector2Array] and will print an error message.
@@ -234,68 +234,68 @@
</method>
<method name="get_point_position" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
- Returns the position of the point associated with the given [code]id[/code].
+ Returns the position of the point associated with the given [param id].
</description>
</method>
<method name="get_point_weight_scale" qualifiers="const">
<return type="float" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
- Returns the weight scale of the point associated with the given [code]id[/code].
+ Returns the weight scale of the point associated with the given [param id].
</description>
</method>
<method name="has_point" qualifiers="const">
<return type="bool" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
- Returns whether a point associated with the given [code]id[/code] exists.
+ Returns whether a point associated with the given [param id] exists.
</description>
</method>
<method name="is_point_disabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Returns whether a point is disabled or not for pathfinding. By default, all points are enabled.
</description>
</method>
<method name="remove_point">
<return type="void" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
- Removes the point associated with the given [code]id[/code] from the points pool.
+ Removes the point associated with the given [param id] from the points pool.
</description>
</method>
<method name="reserve_space">
<return type="void" />
- <argument index="0" name="num_nodes" type="int" />
+ <param index="0" name="num_nodes" type="int" />
<description>
- Reserves space internally for [code]num_nodes[/code] points, useful if you're adding a known large number of points at once, for a grid for instance. New capacity must be greater or equals to old capacity.
+ Reserves space internally for [param num_nodes] points, useful if you're adding a known large number of points at once, for a grid for instance. New capacity must be greater or equals to old capacity.
</description>
</method>
<method name="set_point_disabled">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="disabled" type="bool" default="true" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="disabled" type="bool" default="true" />
<description>
Disables or enables the specified point for pathfinding. Useful for making a temporary obstacle.
</description>
</method>
<method name="set_point_position">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="position" type="Vector2" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="position" type="Vector2" />
<description>
- Sets the [code]position[/code] for the point with the given [code]id[/code].
+ Sets the [param position] for the point with the given [param id].
</description>
</method>
<method name="set_point_weight_scale">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="weight_scale" type="float" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="weight_scale" type="float" />
<description>
- Sets the [code]weight_scale[/code] for the point with the given [code]id[/code]. The [code]weight_scale[/code] is multiplied by the result of [method _compute_cost] when determining the overall cost of traveling across a segment from a neighboring point to this point.
+ Sets the [param weight_scale] for the point with the given [param id]. The [param weight_scale] is multiplied by the result of [method _compute_cost] when determining the overall cost of traveling across a segment from a neighboring point to this point.
</description>
</method>
</methods>
diff --git a/doc/classes/AStar3D.xml b/doc/classes/AStar3D.xml
index ea4e49c173..45b1019bab 100644
--- a/doc/classes/AStar3D.xml
+++ b/doc/classes/AStar3D.xml
@@ -40,8 +40,8 @@
<methods>
<method name="_compute_cost" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="from_id" type="int" />
- <argument index="1" name="to_id" type="int" />
+ <param index="0" name="from_id" type="int" />
+ <param index="1" name="to_id" type="int" />
<description>
Called when computing the cost between two connected points.
Note that this function is hidden in the default [code]AStar3D[/code] class.
@@ -49,8 +49,8 @@
</method>
<method name="_estimate_cost" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="from_id" type="int" />
- <argument index="1" name="to_id" type="int" />
+ <param index="0" name="from_id" type="int" />
+ <param index="1" name="to_id" type="int" />
<description>
Called when estimating the cost between a point and the path's ending point.
Note that this function is hidden in the default [code]AStar3D[/code] class.
@@ -58,12 +58,12 @@
</method>
<method name="add_point">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="position" type="Vector3" />
- <argument index="2" name="weight_scale" type="float" default="1.0" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="position" type="Vector3" />
+ <param index="2" name="weight_scale" type="float" default="1.0" />
<description>
- Adds a new point at the given position with the given identifier. The [code]id[/code] must be 0 or larger, and the [code]weight_scale[/code] must be 0.0 or greater.
- The [code]weight_scale[/code] is multiplied by the result of [method _compute_cost] when determining the overall cost of traveling across a segment from a neighboring point to this point. Thus, all else being equal, the algorithm prefers points with lower [code]weight_scale[/code]s to form a path.
+ Adds a new point at the given position with the given identifier. The [param id] must be 0 or larger, and the [param weight_scale] must be 0.0 or greater.
+ The [param weight_scale] is multiplied by the result of [method _compute_cost] when determining the overall cost of traveling across a segment from a neighboring point to this point. Thus, all else being equal, the algorithm prefers points with lower [param weight_scale]s to form a path.
[codeblocks]
[gdscript]
var astar = AStar3D.new()
@@ -74,16 +74,16 @@
astar.AddPoint(1, new Vector3(1, 0, 0), 4); // Adds the point (1, 0, 0) with weight_scale 4 and id 1
[/csharp]
[/codeblocks]
- If there already exists a point for the given [code]id[/code], its position and weight scale are updated to the given values.
+ If there already exists a point for the given [param id], its position and weight scale are updated to the given values.
</description>
</method>
<method name="are_points_connected" qualifiers="const">
<return type="bool" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="to_id" type="int" />
- <argument index="2" name="bidirectional" type="bool" default="true" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="to_id" type="int" />
+ <param index="2" name="bidirectional" type="bool" default="true" />
<description>
- Returns whether the two given points are directly connected by a segment. If [code]bidirectional[/code] is [code]false[/code], returns whether movement from [code]id[/code] to [code]to_id[/code] is possible through this segment.
+ Returns whether the two given points are directly connected by a segment. If [param bidirectional] is [code]false[/code], returns whether movement from [param id] to [param to_id] is possible through this segment.
</description>
</method>
<method name="clear">
@@ -94,11 +94,11 @@
</method>
<method name="connect_points">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="to_id" type="int" />
- <argument index="2" name="bidirectional" type="bool" default="true" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="to_id" type="int" />
+ <param index="2" name="bidirectional" type="bool" default="true" />
<description>
- Creates a segment between the given points. If [code]bidirectional[/code] is [code]false[/code], only movement from [code]id[/code] to [code]to_id[/code] is allowed, not the reverse direction.
+ Creates a segment between the given points. If [param bidirectional] is [code]false[/code], only movement from [param id] to [param to_id] is allowed, not the reverse direction.
[codeblocks]
[gdscript]
var astar = AStar3D.new()
@@ -117,11 +117,11 @@
</method>
<method name="disconnect_points">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="to_id" type="int" />
- <argument index="2" name="bidirectional" type="bool" default="true" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="to_id" type="int" />
+ <param index="2" name="bidirectional" type="bool" default="true" />
<description>
- Deletes the segment between the given points. If [code]bidirectional[/code] is [code]false[/code], only movement from [code]id[/code] to [code]to_id[/code] is prevented, and a unidirectional segment possibly remains.
+ Deletes the segment between the given points. If [param bidirectional] is [code]false[/code], only movement from [param id] to [param to_id] is prevented, and a unidirectional segment possibly remains.
</description>
</method>
<method name="get_available_point_id" qualifiers="const">
@@ -132,18 +132,18 @@
</method>
<method name="get_closest_point" qualifiers="const">
<return type="int" />
- <argument index="0" name="to_position" type="Vector3" />
- <argument index="1" name="include_disabled" type="bool" default="false" />
+ <param index="0" name="to_position" type="Vector3" />
+ <param index="1" name="include_disabled" type="bool" default="false" />
<description>
- Returns the ID of the closest point to [code]to_position[/code], optionally taking disabled points into account. Returns [code]-1[/code] if there are no points in the points pool.
- [b]Note:[/b] If several points are the closest to [code]to_position[/code], the one with the smallest ID will be returned, ensuring a deterministic result.
+ Returns the ID of the closest point to [param to_position], optionally taking disabled points into account. Returns [code]-1[/code] if there are no points in the points pool.
+ [b]Note:[/b] If several points are the closest to [param to_position], the one with the smallest ID will be returned, ensuring a deterministic result.
</description>
</method>
<method name="get_closest_position_in_segment" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="to_position" type="Vector3" />
+ <param index="0" name="to_position" type="Vector3" />
<description>
- Returns the closest position to [code]to_position[/code] that resides inside a segment between two connected points.
+ Returns the closest position to [param to_position] that resides inside a segment between two connected points.
[codeblocks]
[gdscript]
var astar = AStar3D.new()
@@ -165,8 +165,8 @@
</method>
<method name="get_id_path">
<return type="PackedInt64Array" />
- <argument index="0" name="from_id" type="int" />
- <argument index="1" name="to_id" type="int" />
+ <param index="0" name="from_id" type="int" />
+ <param index="1" name="to_id" type="int" />
<description>
Returns an array with the IDs of the points that form the path found by AStar3D between the given points. The array is ordered from the starting point to the ending point of the path.
[codeblocks]
@@ -208,7 +208,7 @@
</method>
<method name="get_point_connections">
<return type="PackedInt64Array" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Returns an array with the IDs of the points that form the connection with the given point.
[codeblocks]
@@ -245,15 +245,15 @@
</description>
</method>
<method name="get_point_ids">
- <return type="Array" />
+ <return type="PackedInt64Array" />
<description>
Returns an array of all point IDs.
</description>
</method>
<method name="get_point_path">
<return type="PackedVector3Array" />
- <argument index="0" name="from_id" type="int" />
- <argument index="1" name="to_id" type="int" />
+ <param index="0" name="from_id" type="int" />
+ <param index="1" name="to_id" type="int" />
<description>
Returns an array with the points that are in the path found by AStar3D between the given points. The array is ordered from the starting point to the ending point of the path.
[b]Note:[/b] This method is not thread-safe. If called from a [Thread], it will return an empty [PackedVector3Array] and will print an error message.
@@ -261,68 +261,68 @@
</method>
<method name="get_point_position" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
- Returns the position of the point associated with the given [code]id[/code].
+ Returns the position of the point associated with the given [param id].
</description>
</method>
<method name="get_point_weight_scale" qualifiers="const">
<return type="float" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
- Returns the weight scale of the point associated with the given [code]id[/code].
+ Returns the weight scale of the point associated with the given [param id].
</description>
</method>
<method name="has_point" qualifiers="const">
<return type="bool" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
- Returns whether a point associated with the given [code]id[/code] exists.
+ Returns whether a point associated with the given [param id] exists.
</description>
</method>
<method name="is_point_disabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Returns whether a point is disabled or not for pathfinding. By default, all points are enabled.
</description>
</method>
<method name="remove_point">
<return type="void" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
- Removes the point associated with the given [code]id[/code] from the points pool.
+ Removes the point associated with the given [param id] from the points pool.
</description>
</method>
<method name="reserve_space">
<return type="void" />
- <argument index="0" name="num_nodes" type="int" />
+ <param index="0" name="num_nodes" type="int" />
<description>
- Reserves space internally for [code]num_nodes[/code] points, useful if you're adding a known large number of points at once, for a grid for instance. New capacity must be greater or equals to old capacity.
+ Reserves space internally for [param num_nodes] points, useful if you're adding a known large number of points at once, for a grid for instance. New capacity must be greater or equals to old capacity.
</description>
</method>
<method name="set_point_disabled">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="disabled" type="bool" default="true" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="disabled" type="bool" default="true" />
<description>
Disables or enables the specified point for pathfinding. Useful for making a temporary obstacle.
</description>
</method>
<method name="set_point_position">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="position" type="Vector3" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="position" type="Vector3" />
<description>
- Sets the [code]position[/code] for the point with the given [code]id[/code].
+ Sets the [param position] for the point with the given [param id].
</description>
</method>
<method name="set_point_weight_scale">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="weight_scale" type="float" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="weight_scale" type="float" />
<description>
- Sets the [code]weight_scale[/code] for the point with the given [code]id[/code]. The [code]weight_scale[/code] is multiplied by the result of [method _compute_cost] when determining the overall cost of traveling across a segment from a neighboring point to this point.
+ Sets the [param weight_scale] for the point with the given [param id]. The [param weight_scale] is multiplied by the result of [method _compute_cost] when determining the overall cost of traveling across a segment from a neighboring point to this point.
</description>
</method>
</methods>
diff --git a/doc/classes/AcceptDialog.xml b/doc/classes/AcceptDialog.xml
index 0009c82548..c83ea8c60a 100644
--- a/doc/classes/AcceptDialog.xml
+++ b/doc/classes/AcceptDialog.xml
@@ -11,20 +11,20 @@
<methods>
<method name="add_button">
<return type="Button" />
- <argument index="0" name="text" type="String" />
- <argument index="1" name="right" type="bool" default="false" />
- <argument index="2" name="action" type="String" default="&quot;&quot;" />
+ <param index="0" name="text" type="String" />
+ <param index="1" name="right" type="bool" default="false" />
+ <param index="2" name="action" type="String" default="&quot;&quot;" />
<description>
- Adds a button with label [code]text[/code] and a custom [code]action[/code] to the dialog and returns the created button. [code]action[/code] will be passed to the [signal custom_action] signal when pressed.
- If [code]true[/code], [code]right[/code] will place the button to the right of any sibling buttons.
+ Adds a button with label [param text] and a custom [param action] to the dialog and returns the created button. [param action] will be passed to the [signal custom_action] signal when pressed.
+ If [code]true[/code], [param right] will place the button to the right of any sibling buttons.
You can use [method remove_button] method to remove a button created with this method from the dialog.
</description>
</method>
<method name="add_cancel_button">
<return type="Button" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
- Adds a button with label [code]name[/code] and a cancel action to the dialog and returns the created button.
+ Adds a button with label [param name] and a cancel action to the dialog and returns the created button.
You can use [method remove_button] method to remove a button created with this method from the dialog.
</description>
</method>
@@ -44,16 +44,16 @@
</method>
<method name="register_text_enter">
<return type="void" />
- <argument index="0" name="line_edit" type="Control" />
+ <param index="0" name="line_edit" type="Control" />
<description>
Registers a [LineEdit] in the dialog. When the enter key is pressed, the dialog will be accepted.
</description>
</method>
<method name="remove_button">
<return type="void" />
- <argument index="0" name="button" type="Control" />
+ <param index="0" name="button" type="Control" />
<description>
- Removes the [code]button[/code] from the dialog. Does NOT free the [code]button[/code]. The [code]button[/code] must be a [Button] added with [method add_button] or [method add_cancel_button] method. After removal, pressing the [code]button[/code] will no longer emit this dialog's [signal custom_action] or [signal cancelled] signals.
+ Removes the [param button] from the dialog. Does NOT free the [param button]. The [param button] must be a [Button] added with [method add_button] or [method add_cancel_button] method. After removal, pressing the [param button] will no longer emit this dialog's [signal custom_action] or [signal cancelled] signals.
</description>
</method>
</methods>
@@ -92,7 +92,7 @@
</description>
</signal>
<signal name="custom_action">
- <argument index="0" name="action" type="StringName" />
+ <param index="0" name="action" type="StringName" />
<description>
Emitted when a custom button is pressed. See [method add_button].
</description>
diff --git a/doc/classes/AnimatedSprite2D.xml b/doc/classes/AnimatedSprite2D.xml
index 638d142791..b207eda27f 100644
--- a/doc/classes/AnimatedSprite2D.xml
+++ b/doc/classes/AnimatedSprite2D.xml
@@ -14,10 +14,10 @@
<methods>
<method name="play">
<return type="void" />
- <argument index="0" name="anim" type="StringName" default="&amp;&quot;&quot;" />
- <argument index="1" name="backwards" type="bool" default="false" />
+ <param index="0" name="anim" type="StringName" default="&amp;&quot;&quot;" />
+ <param index="1" name="backwards" type="bool" default="false" />
<description>
- Plays the animation named [code]anim[/code]. If no [code]anim[/code] is provided, the current animation is played. If [code]backwards[/code] is [code]true[/code], the animation will be played in reverse.
+ Plays the animation named [param anim]. If no [param anim] is provided, the current animation is played. If [code]backwards[/code] is [code]true[/code], the animation will be played in reverse.
</description>
</method>
<method name="stop">
diff --git a/doc/classes/AnimatedSprite3D.xml b/doc/classes/AnimatedSprite3D.xml
index 30ea2249a3..68354f092c 100644
--- a/doc/classes/AnimatedSprite3D.xml
+++ b/doc/classes/AnimatedSprite3D.xml
@@ -18,9 +18,9 @@
</method>
<method name="play">
<return type="void" />
- <argument index="0" name="anim" type="StringName" default="&amp;&quot;&quot;" />
+ <param index="0" name="anim" type="StringName" default="&amp;&quot;&quot;" />
<description>
- Plays the animation named [code]anim[/code]. If no [code]anim[/code] is provided, the current animation is played.
+ Plays the animation named [param anim]. If no [param anim] is provided, the current animation is played.
</description>
</method>
<method name="stop">
diff --git a/doc/classes/AnimatedTexture.xml b/doc/classes/AnimatedTexture.xml
index c322db9c37..5ad4c4e10a 100644
--- a/doc/classes/AnimatedTexture.xml
+++ b/doc/classes/AnimatedTexture.xml
@@ -14,22 +14,22 @@
<methods>
<method name="get_frame_delay" qualifiers="const">
<return type="float" />
- <argument index="0" name="frame" type="int" />
+ <param index="0" name="frame" type="int" />
<description>
Returns the given frame's delay value.
</description>
</method>
<method name="get_frame_texture" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="frame" type="int" />
+ <param index="0" name="frame" type="int" />
<description>
Returns the given frame's [Texture2D].
</description>
</method>
<method name="set_frame_delay">
<return type="void" />
- <argument index="0" name="frame" type="int" />
- <argument index="1" name="delay" type="float" />
+ <param index="0" name="frame" type="int" />
+ <param index="1" name="delay" type="float" />
<description>
Sets an additional delay (in seconds) between this frame and the next one, that will be added to the time interval defined by [member fps]. By default, frames have no delay defined. If a delay value is defined, the final time interval between this frame and the next will be [code]1.0 / fps + delay[/code].
For example, for an animation with 3 frames, 2 FPS and a frame delay on the second frame of 1.2, the resulting playback will be:
@@ -43,8 +43,8 @@
</method>
<method name="set_frame_texture">
<return type="void" />
- <argument index="0" name="frame" type="int" />
- <argument index="1" name="texture" type="Texture2D" />
+ <param index="0" name="frame" type="int" />
+ <param index="1" name="texture" type="Texture2D" />
<description>
Assigns a [Texture2D] to the given frame. Frame IDs start at 0, so the first frame has ID 0, and the last frame of the animation has ID [member frames] - 1.
You can define any number of textures up to [constant MAX_FRAMES], but keep in mind that only frames from 0 to [member frames] - 1 will be part of the animation.
diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml
index f40f11944d..df0fb11ac7 100644
--- a/doc/classes/Animation.xml
+++ b/doc/classes/Animation.xml
@@ -33,200 +33,181 @@
<methods>
<method name="add_track">
<return type="int" />
- <argument index="0" name="type" type="int" enum="Animation.TrackType" />
- <argument index="1" name="at_position" type="int" default="-1" />
+ <param index="0" name="type" type="int" enum="Animation.TrackType" />
+ <param index="1" name="at_position" type="int" default="-1" />
<description>
Adds a track to the Animation.
</description>
</method>
<method name="animation_track_get_key_animation" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
<description>
- Returns the animation name at the key identified by [code]key_idx[/code]. The [code]track_idx[/code] must be the index of an Animation Track.
+ Returns the animation name at the key identified by [param key_idx]. The [param track_idx] must be the index of an Animation Track.
</description>
</method>
<method name="animation_track_insert_key">
<return type="int" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="time" type="float" />
- <argument index="2" name="animation" type="StringName" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="time" type="float" />
+ <param index="2" name="animation" type="StringName" />
<description>
- Inserts a key with value [code]animation[/code] at the given [code]time[/code] (in seconds). The [code]track_idx[/code] must be the index of an Animation Track.
+ Inserts a key with value [param animation] at the given [param time] (in seconds). The [param track_idx] must be the index of an Animation Track.
</description>
</method>
<method name="animation_track_set_key_animation">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
- <argument index="2" name="animation" type="StringName" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
+ <param index="2" name="animation" type="StringName" />
<description>
- Sets the key identified by [code]key_idx[/code] to value [code]animation[/code]. The [code]track_idx[/code] must be the index of an Animation Track.
+ Sets the key identified by [param key_idx] to value [param animation]. The [param track_idx] must be the index of an Animation Track.
</description>
</method>
<method name="audio_track_get_key_end_offset" qualifiers="const">
<return type="float" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
<description>
- Returns the end offset of the key identified by [code]key_idx[/code]. The [code]track_idx[/code] must be the index of an Audio Track.
+ Returns the end offset of the key identified by [param key_idx]. The [param track_idx] must be the index of an Audio Track.
End offset is the number of seconds cut off at the ending of the audio stream.
</description>
</method>
<method name="audio_track_get_key_start_offset" qualifiers="const">
<return type="float" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
<description>
- Returns the start offset of the key identified by [code]key_idx[/code]. The [code]track_idx[/code] must be the index of an Audio Track.
+ Returns the start offset of the key identified by [param key_idx]. The [param track_idx] must be the index of an Audio Track.
Start offset is the number of seconds cut off at the beginning of the audio stream.
</description>
</method>
<method name="audio_track_get_key_stream" qualifiers="const">
<return type="Resource" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
<description>
- Returns the audio stream of the key identified by [code]key_idx[/code]. The [code]track_idx[/code] must be the index of an Audio Track.
+ Returns the audio stream of the key identified by [param key_idx]. The [param track_idx] must be the index of an Audio Track.
</description>
</method>
<method name="audio_track_insert_key">
<return type="int" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="time" type="float" />
- <argument index="2" name="stream" type="Resource" />
- <argument index="3" name="start_offset" type="float" default="0" />
- <argument index="4" name="end_offset" type="float" default="0" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="time" type="float" />
+ <param index="2" name="stream" type="Resource" />
+ <param index="3" name="start_offset" type="float" default="0" />
+ <param index="4" name="end_offset" type="float" default="0" />
<description>
- Inserts an Audio Track key at the given [code]time[/code] in seconds. The [code]track_idx[/code] must be the index of an Audio Track.
- [code]stream[/code] is the [AudioStream] resource to play. [code]start_offset[/code] is the number of seconds cut off at the beginning of the audio stream, while [code]end_offset[/code] is at the ending.
+ Inserts an Audio Track key at the given [param time] in seconds. The [param track_idx] must be the index of an Audio Track.
+ [param stream] is the [AudioStream] resource to play. [param start_offset] is the number of seconds cut off at the beginning of the audio stream, while [param end_offset] is at the ending.
</description>
</method>
<method name="audio_track_set_key_end_offset">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
- <argument index="2" name="offset" type="float" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
+ <param index="2" name="offset" type="float" />
<description>
- Sets the end offset of the key identified by [code]key_idx[/code] to value [code]offset[/code]. The [code]track_idx[/code] must be the index of an Audio Track.
+ Sets the end offset of the key identified by [param key_idx] to value [param offset]. The [param track_idx] must be the index of an Audio Track.
</description>
</method>
<method name="audio_track_set_key_start_offset">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
- <argument index="2" name="offset" type="float" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
+ <param index="2" name="offset" type="float" />
<description>
- Sets the start offset of the key identified by [code]key_idx[/code] to value [code]offset[/code]. The [code]track_idx[/code] must be the index of an Audio Track.
+ Sets the start offset of the key identified by [param key_idx] to value [param offset]. The [param track_idx] must be the index of an Audio Track.
</description>
</method>
<method name="audio_track_set_key_stream">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
- <argument index="2" name="stream" type="Resource" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
+ <param index="2" name="stream" type="Resource" />
<description>
- Sets the stream of the key identified by [code]key_idx[/code] to value [code]stream[/code]. The [code]track_idx[/code] must be the index of an Audio Track.
- </description>
- </method>
- <method name="bezier_track_get_key_handle_mode" qualifiers="const">
- <return type="int" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
- <description>
- Returns the handle mode of the key identified by [code]index[/code]. See [enum HandleMode] for possible values. The [code]track_idx[/code] must be the index of a Bezier Track.
+ Sets the stream of the key identified by [param key_idx] to value [param stream]. The [param track_idx] must be the index of an Audio Track.
</description>
</method>
<method name="bezier_track_get_key_in_handle" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
<description>
- Returns the in handle of the key identified by [code]key_idx[/code]. The [code]track_idx[/code] must be the index of a Bezier Track.
+ Returns the in handle of the key identified by [param key_idx]. The [param track_idx] must be the index of a Bezier Track.
</description>
</method>
<method name="bezier_track_get_key_out_handle" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
<description>
- Returns the out handle of the key identified by [code]key_idx[/code]. The [code]track_idx[/code] must be the index of a Bezier Track.
+ Returns the out handle of the key identified by [param key_idx]. The [param track_idx] must be the index of a Bezier Track.
</description>
</method>
<method name="bezier_track_get_key_value" qualifiers="const">
<return type="float" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
<description>
- Returns the value of the key identified by [code]key_idx[/code]. The [code]track_idx[/code] must be the index of a Bezier Track.
+ Returns the value of the key identified by [param key_idx]. The [param track_idx] must be the index of a Bezier Track.
</description>
</method>
<method name="bezier_track_insert_key">
<return type="int" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="time" type="float" />
- <argument index="2" name="value" type="float" />
- <argument index="3" name="in_handle" type="Vector2" default="Vector2(0, 0)" />
- <argument index="4" name="out_handle" type="Vector2" default="Vector2(0, 0)" />
- <argument index="5" name="handle_mode" type="int" enum="Animation.HandleMode" default="1" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="time" type="float" />
+ <param index="2" name="value" type="float" />
+ <param index="3" name="in_handle" type="Vector2" default="Vector2(0, 0)" />
+ <param index="4" name="out_handle" type="Vector2" default="Vector2(0, 0)" />
<description>
- Inserts a Bezier Track key at the given [code]time[/code] in seconds. The [code]track_idx[/code] must be the index of a Bezier Track.
- [code]in_handle[/code] is the left-side weight of the added Bezier curve point, [code]out_handle[/code] is the right-side one, while [code]value[/code] is the actual value at this point.
+ Inserts a Bezier Track key at the given [param time] in seconds. The [param track_idx] must be the index of a Bezier Track.
+ [param in_handle] is the left-side weight of the added Bezier curve point, [param out_handle] is the right-side one, while [param value] is the actual value at this point.
</description>
</method>
<method name="bezier_track_interpolate" qualifiers="const">
<return type="float" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="time" type="float" />
- <description>
- Returns the interpolated value at the given [code]time[/code] (in seconds). The [code]track_idx[/code] must be the index of a Bezier Track.
- </description>
- </method>
- <method name="bezier_track_set_key_handle_mode">
- <return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
- <argument index="2" name="key_handle_mode" type="int" enum="Animation.HandleMode" />
- <argument index="3" name="balanced_value_time_ratio" type="float" default="1.0" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="time" type="float" />
<description>
- Changes the handle mode of the keyframe at the given [code]index[/code]. See [enum HandleMode] for possible values. The [code]track_idx[/code] must be the index of a Bezier Track.
+ Returns the interpolated value at the given [param time] (in seconds). The [param track_idx] must be the index of a Bezier Track.
</description>
</method>
<method name="bezier_track_set_key_in_handle">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
- <argument index="2" name="in_handle" type="Vector2" />
- <argument index="3" name="balanced_value_time_ratio" type="float" default="1.0" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
+ <param index="2" name="in_handle" type="Vector2" />
+ <param index="3" name="balanced_value_time_ratio" type="float" default="1.0" />
<description>
- Sets the in handle of the key identified by [code]key_idx[/code] to value [code]in_handle[/code]. The [code]track_idx[/code] must be the index of a Bezier Track.
+ Sets the in handle of the key identified by [param key_idx] to value [param in_handle]. The [param track_idx] must be the index of a Bezier Track.
</description>
</method>
<method name="bezier_track_set_key_out_handle">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
- <argument index="2" name="out_handle" type="Vector2" />
- <argument index="3" name="balanced_value_time_ratio" type="float" default="1.0" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
+ <param index="2" name="out_handle" type="Vector2" />
+ <param index="3" name="balanced_value_time_ratio" type="float" default="1.0" />
<description>
- Sets the out handle of the key identified by [code]key_idx[/code] to value [code]out_handle[/code]. The [code]track_idx[/code] must be the index of a Bezier Track.
+ Sets the out handle of the key identified by [param key_idx] to value [param out_handle]. The [param track_idx] must be the index of a Bezier Track.
</description>
</method>
<method name="bezier_track_set_key_value">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
- <argument index="2" name="value" type="float" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
+ <param index="2" name="value" type="float" />
<description>
- Sets the value of the key identified by [code]key_idx[/code] to the given value. The [code]track_idx[/code] must be the index of a Bezier Track.
+ Sets the value of the key identified by [param key_idx] to the given value. The [param track_idx] must be the index of a Bezier Track.
</description>
</method>
<method name="blend_shape_track_insert_key">
<return type="int" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="time" type="float" />
- <argument index="2" name="amount" type="float" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="time" type="float" />
+ <param index="2" name="amount" type="float" />
<description>
</description>
</method>
@@ -238,24 +219,24 @@
</method>
<method name="compress">
<return type="void" />
- <argument index="0" name="page_size" type="int" default="8192" />
- <argument index="1" name="fps" type="int" default="120" />
- <argument index="2" name="split_tolerance" type="float" default="4.0" />
+ <param index="0" name="page_size" type="int" default="8192" />
+ <param index="1" name="fps" type="int" default="120" />
+ <param index="2" name="split_tolerance" type="float" default="4.0" />
<description>
</description>
</method>
<method name="copy_track">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="to_animation" type="Animation" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="to_animation" type="Animation" />
<description>
- Adds a new track that is a copy of the given track from [code]to_animation[/code].
+ Adds a new track that is a copy of the given track from [param to_animation].
</description>
</method>
<method name="find_track" qualifiers="const">
<return type="int" />
- <argument index="0" name="path" type="NodePath" />
- <argument index="1" name="type" type="int" enum="Animation.TrackType" />
+ <param index="0" name="path" type="NodePath" />
+ <param index="1" name="type" type="int" enum="Animation.TrackType" />
<description>
Returns the index of the specified track. If the track is not found, return -1.
</description>
@@ -268,259 +249,259 @@
</method>
<method name="method_track_get_key_indices" qualifiers="const">
<return type="PackedInt32Array" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="time_sec" type="float" />
- <argument index="2" name="delta" type="float" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="time_sec" type="float" />
+ <param index="2" name="delta" type="float" />
<description>
Returns all the key indices of a method track, given a position and delta time.
</description>
</method>
<method name="method_track_get_name" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
<description>
Returns the method name of a method track.
</description>
</method>
<method name="method_track_get_params" qualifiers="const">
<return type="Array" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
<description>
Returns the arguments values to be called on a method track for a given key in a given track.
</description>
</method>
<method name="position_track_insert_key">
<return type="int" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="time" type="float" />
- <argument index="2" name="position" type="Vector3" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="time" type="float" />
+ <param index="2" name="position" type="Vector3" />
<description>
</description>
</method>
<method name="remove_track">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
<description>
Removes a track by specifying the track index.
</description>
</method>
<method name="rotation_track_insert_key">
<return type="int" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="time" type="float" />
- <argument index="2" name="rotation" type="Quaternion" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="time" type="float" />
+ <param index="2" name="rotation" type="Quaternion" />
<description>
</description>
</method>
<method name="scale_track_insert_key">
<return type="int" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="time" type="float" />
- <argument index="2" name="scale" type="Vector3" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="time" type="float" />
+ <param index="2" name="scale" type="Vector3" />
<description>
</description>
</method>
<method name="track_find_key" qualifiers="const">
<return type="int" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="time" type="float" />
- <argument index="2" name="exact" type="bool" default="false" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="time" type="float" />
+ <param index="2" name="exact" type="bool" default="false" />
<description>
Finds the key index by time in a given track. Optionally, only find it if the exact time is given.
</description>
</method>
<method name="track_get_interpolation_loop_wrap" qualifiers="const">
<return type="bool" />
- <argument index="0" name="track_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
<description>
- Returns [code]true[/code] if the track at [code]idx[/code] wraps the interpolation loop. New tracks wrap the interpolation loop by default.
+ Returns [code]true[/code] if the track at [param track_idx] wraps the interpolation loop. New tracks wrap the interpolation loop by default.
</description>
</method>
<method name="track_get_interpolation_type" qualifiers="const">
<return type="int" enum="Animation.InterpolationType" />
- <argument index="0" name="track_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
<description>
Returns the interpolation type of a given track.
</description>
</method>
<method name="track_get_key_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="track_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
<description>
- Returns the amount of keys in a given track.
+ Returns the number of keys in a given track.
</description>
</method>
<method name="track_get_key_time" qualifiers="const">
<return type="float" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
<description>
Returns the time at which the key is located.
</description>
</method>
<method name="track_get_key_transition" qualifiers="const">
<return type="float" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
<description>
Returns the transition curve (easing) for a specific key (see the built-in math function [method @GlobalScope.ease]).
</description>
</method>
<method name="track_get_key_value" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
<description>
Returns the value of a given key in a given track.
</description>
</method>
<method name="track_get_path" qualifiers="const">
<return type="NodePath" />
- <argument index="0" name="track_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
<description>
Gets the path of a track. For more information on the path format, see [method track_set_path].
</description>
</method>
<method name="track_get_type" qualifiers="const">
<return type="int" enum="Animation.TrackType" />
- <argument index="0" name="track_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
<description>
Gets the type of a track.
</description>
</method>
<method name="track_insert_key">
<return type="int" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="time" type="float" />
- <argument index="2" name="key" type="Variant" />
- <argument index="3" name="transition" type="float" default="1" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="time" type="float" />
+ <param index="2" name="key" type="Variant" />
+ <param index="3" name="transition" type="float" default="1" />
<description>
Inserts a generic key in a given track. Returns the key index.
</description>
</method>
<method name="track_is_compressed" qualifiers="const">
<return type="bool" />
- <argument index="0" name="track_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
<description>
</description>
</method>
<method name="track_is_enabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="track_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
<description>
- Returns [code]true[/code] if the track at index [code]idx[/code] is enabled.
+ Returns [code]true[/code] if the track at index [param track_idx] is enabled.
</description>
</method>
<method name="track_is_imported" qualifiers="const">
<return type="bool" />
- <argument index="0" name="track_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
<description>
Returns [code]true[/code] if the given track is imported. Else, return [code]false[/code].
</description>
</method>
<method name="track_move_down">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
<description>
Moves a track down.
</description>
</method>
<method name="track_move_to">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="to_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="to_idx" type="int" />
<description>
- Changes the index position of track [code]idx[/code] to the one defined in [code]to_idx[/code].
+ Changes the index position of track [param track_idx] to the one defined in [param to_idx].
</description>
</method>
<method name="track_move_up">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
<description>
Moves a track up.
</description>
</method>
<method name="track_remove_key">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
<description>
Removes a key by index in a given track.
</description>
</method>
<method name="track_remove_key_at_time">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="time" type="float" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="time" type="float" />
<description>
- Removes a key at [code]time[/code] in a given track.
+ Removes a key at [param time] in a given track.
</description>
</method>
<method name="track_set_enabled">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="enabled" type="bool" />
<description>
Enables/disables the given track. Tracks are enabled by default.
</description>
</method>
<method name="track_set_imported">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="imported" type="bool" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="imported" type="bool" />
<description>
Sets the given track as imported or not.
</description>
</method>
<method name="track_set_interpolation_loop_wrap">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="interpolation" type="bool" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="interpolation" type="bool" />
<description>
- If [code]true[/code], the track at [code]idx[/code] wraps the interpolation loop.
+ If [code]true[/code], the track at [param track_idx] wraps the interpolation loop.
</description>
</method>
<method name="track_set_interpolation_type">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="interpolation" type="int" enum="Animation.InterpolationType" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="interpolation" type="int" enum="Animation.InterpolationType" />
<description>
Sets the interpolation type of a given track.
</description>
</method>
<method name="track_set_key_time">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
- <argument index="2" name="time" type="float" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
+ <param index="2" name="time" type="float" />
<description>
Sets the time of an existing key.
</description>
</method>
<method name="track_set_key_transition">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key_idx" type="int" />
- <argument index="2" name="transition" type="float" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key_idx" type="int" />
+ <param index="2" name="transition" type="float" />
<description>
Sets the transition curve (easing) for a specific key (see the built-in math function [method @GlobalScope.ease]).
</description>
</method>
<method name="track_set_key_value">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="key" type="int" />
- <argument index="2" name="value" type="Variant" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="key" type="int" />
+ <param index="2" name="value" type="Variant" />
<description>
Sets the value of an existing key.
</description>
</method>
<method name="track_set_path">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="path" type="NodePath" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="path" type="NodePath" />
<description>
Sets the path of a track. Paths must be valid scene-tree paths to a node and must be specified starting from the parent node of the node that will reproduce the animation. Tracks that control properties or bones must append their name after the path, separated by [code]":"[/code].
For example, [code]"character/skeleton:ankle"[/code] or [code]"character/mesh:transform/local"[/code].
@@ -528,40 +509,40 @@
</method>
<method name="track_swap">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="with_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="with_idx" type="int" />
<description>
- Swaps the track [code]idx[/code]'s index position with the track [code]with_idx[/code].
+ Swaps the track [param track_idx]'s index position with the track [param with_idx].
</description>
</method>
<method name="value_track_get_key_indices" qualifiers="const">
<return type="PackedInt32Array" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="time_sec" type="float" />
- <argument index="2" name="delta" type="float" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="time_sec" type="float" />
+ <param index="2" name="delta" type="float" />
<description>
Returns all the key indices of a value track, given a position and delta time.
</description>
</method>
<method name="value_track_get_update_mode" qualifiers="const">
<return type="int" enum="Animation.UpdateMode" />
- <argument index="0" name="track_idx" type="int" />
+ <param index="0" name="track_idx" type="int" />
<description>
Returns the update mode of a value track.
</description>
</method>
<method name="value_track_interpolate" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="time_sec" type="float" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="time_sec" type="float" />
<description>
- Returns the interpolated value at the given time (in seconds). The [code]track_idx[/code] must be the index of a value track.
+ Returns the interpolated value at the given time (in seconds). The [param track_idx] must be the index of a value track.
</description>
</method>
<method name="value_track_set_update_mode">
<return type="void" />
- <argument index="0" name="track_idx" type="int" />
- <argument index="1" name="mode" type="int" enum="Animation.UpdateMode" />
+ <param index="0" name="track_idx" type="int" />
+ <param index="1" name="mode" type="int" enum="Animation.UpdateMode" />
<description>
Sets the update mode (see [enum UpdateMode]) of a value track.
</description>
@@ -619,6 +600,14 @@
<constant name="INTERPOLATION_CUBIC" value="2" enum="InterpolationType">
Cubic interpolation.
</constant>
+ <constant name="INTERPOLATION_LINEAR_ANGLE" value="3" enum="InterpolationType">
+ Linear interpolation with shortest path rotation.
+ [b]Note:[/b] The result value is always normalized and may not match the key value.
+ </constant>
+ <constant name="INTERPOLATION_CUBIC_ANGLE" value="4" enum="InterpolationType">
+ Cubic interpolation with shortest path rotation.
+ [b]Note:[/b] The result value is always normalized and may not match the key value.
+ </constant>
<constant name="UPDATE_CONTINUOUS" value="0" enum="UpdateMode">
Update between keyframes.
</constant>
@@ -640,11 +629,5 @@
<constant name="LOOP_PINGPONG" value="2" enum="LoopMode">
Repeats playback and reverse playback at both ends of the animation.
</constant>
- <constant name="HANDLE_MODE_FREE" value="0" enum="HandleMode">
- Assigning the free handle mode to a Bezier Track's keyframe allows you to edit the keyframe's left and right handles independently from one another.
- </constant>
- <constant name="HANDLE_MODE_BALANCED" value="1" enum="HandleMode">
- Assigning the balanced handle mode to a Bezier Track's keyframe makes it so the two handles of the keyframe always stay aligned when changing either the keyframe's left or right handle.
- </constant>
</constants>
</class>
diff --git a/doc/classes/AnimationLibrary.xml b/doc/classes/AnimationLibrary.xml
index d856c65dfc..75fe393dbb 100644
--- a/doc/classes/AnimationLibrary.xml
+++ b/doc/classes/AnimationLibrary.xml
@@ -1,47 +1,56 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AnimationLibrary" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Container for [Animation] resources.
</brief_description>
<description>
+ An animation library stores a set of animations accessible through [StringName] keys, for use with [AnimationPlayer] nodes.
</description>
<tutorials>
+ <link title="Animation tutorial index">$DOCS_URL/tutorials/animation/index.html</link>
</tutorials>
<methods>
<method name="add_animation">
<return type="int" enum="Error" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="animation" type="Animation" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="animation" type="Animation" />
<description>
+ Adds the [param animation] to the library, accesible by the key [param name].
</description>
</method>
<method name="get_animation" qualifiers="const">
<return type="Animation" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
+ Returns the [Animation] with the key [param name]. If the animation does not exist, [code]null[/code] is returned and an error is logged.
</description>
</method>
<method name="get_animation_list" qualifiers="const">
<return type="StringName[]" />
<description>
+ Returns the keys for the [Animation]s stored in the library.
</description>
</method>
<method name="has_animation" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
+ Returns [code]true[/code] if the library stores an [Animation] with [param name] as the key.
</description>
</method>
<method name="remove_animation">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
+ Removes the [Animation] with the key [param name].
</description>
</method>
<method name="rename_animation">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="newname" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="newname" type="StringName" />
<description>
+ Changes the key of the [Animation] associated with the key [param name] to [param newname].
</description>
</method>
</methods>
@@ -51,19 +60,22 @@
</members>
<signals>
<signal name="animation_added">
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
+ Emitted when an [Animation] is added, under the key [param name].
</description>
</signal>
<signal name="animation_removed">
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
+ Emitted when an [Animation] stored with the key [param name] is removed.
</description>
</signal>
<signal name="animation_renamed">
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="to_name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="to_name" type="StringName" />
<description>
+ Emitted when the key for an [Animation] is changed, from [param name] to [param to_name].
</description>
</signal>
</signals>
diff --git a/doc/classes/AnimationNode.xml b/doc/classes/AnimationNode.xml
index 189e30b5f2..b856b5f208 100644
--- a/doc/classes/AnimationNode.xml
+++ b/doc/classes/AnimationNode.xml
@@ -14,95 +14,95 @@
<method name="_get_caption" qualifiers="virtual const">
<return type="String" />
<description>
- Gets the text caption for this node (used by some editors).
+ When inheriting from [AnimationRootNode], implement this virtual method to override the text caption for this node.
</description>
</method>
<method name="_get_child_by_name" qualifiers="virtual const">
<return type="AnimationNode" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Gets a child node by index (used by editors inheriting from [AnimationRootNode]).
+ When inheriting from [AnimationRootNode], implement this virtual method to return a child node by its [param name].
</description>
</method>
<method name="_get_child_nodes" qualifiers="virtual const">
<return type="Dictionary" />
<description>
- Gets all children nodes in order as a [code]name: node[/code] dictionary. Only useful when inheriting [AnimationRootNode].
+ When inheriting from [AnimationRootNode], implement this virtual method to return all children nodes in order as a [code]name: node[/code] dictionary.
</description>
</method>
<method name="_get_parameter_default_value" qualifiers="virtual const">
<return type="Variant" />
- <argument index="0" name="parameter" type="StringName" />
+ <param index="0" name="parameter" type="StringName" />
<description>
- Gets the default value of a parameter. Parameters are custom local memory used for your nodes, given a resource can be reused in multiple trees.
+ When inheriting from [AnimationRootNode], implement this virtual method to return the default value of a [param parameter]. Parameters are custom local memory used for your nodes, given a resource can be reused in multiple trees.
</description>
</method>
<method name="_get_parameter_list" qualifiers="virtual const">
<return type="Array" />
<description>
- Gets the property information for parameter. Parameters are custom local memory used for your nodes, given a resource can be reused in multiple trees. Format is similar to [method Object.get_property_list].
+ When inheriting from [AnimationRootNode], implement this virtual method to return a list of the properties on this node. Parameters are custom local memory used for your nodes, given a resource can be reused in multiple trees. Format is similar to [method Object.get_property_list].
</description>
</method>
<method name="_has_filter" qualifiers="virtual const">
<return type="bool" />
<description>
- Returns whether you want the blend tree editor to display filter editing on this node.
+ When inheriting from [AnimationRootNode], implement this virtual method to return whether the blend tree editor should display filter editing on this node.
</description>
</method>
<method name="_process" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="time" type="float" />
- <argument index="1" name="seek" type="bool" />
- <argument index="2" name="seek_root" type="bool" />
+ <param index="0" name="time" type="float" />
+ <param index="1" name="seek" type="bool" />
+ <param index="2" name="seek_root" type="bool" />
<description>
- User-defined callback called when a custom node is processed. The [code]time[/code] parameter is a relative delta, unless [code]seek[/code] is [code]true[/code], in which case it is absolute.
+ When inheriting from [AnimationRootNode], implement this virtual method to run some code when this node is processed. The [param time] parameter is a relative delta, unless [param seek] is [code]true[/code], in which case it is absolute.
Here, call the [method blend_input], [method blend_node] or [method blend_animation] functions. You can also use [method get_parameter] and [method set_parameter] to modify local memory.
This function should return the time left for the current animation to finish (if unsure, pass the value from the main blend being called).
</description>
</method>
<method name="add_input">
<return type="void" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
Adds an input to the node. This is only useful for nodes created for use in an [AnimationNodeBlendTree].
</description>
</method>
<method name="blend_animation">
<return type="void" />
- <argument index="0" name="animation" type="StringName" />
- <argument index="1" name="time" type="float" />
- <argument index="2" name="delta" type="float" />
- <argument index="3" name="seeked" type="bool" />
- <argument index="4" name="seek_root" type="bool" />
- <argument index="5" name="blend" type="float" />
- <argument index="6" name="pingponged" type="int" default="0" />
+ <param index="0" name="animation" type="StringName" />
+ <param index="1" name="time" type="float" />
+ <param index="2" name="delta" type="float" />
+ <param index="3" name="seeked" type="bool" />
+ <param index="4" name="seek_root" type="bool" />
+ <param index="5" name="blend" type="float" />
+ <param index="6" name="pingponged" type="int" default="0" />
<description>
- Blend an animation by [code]blend[/code] amount (name must be valid in the linked [AnimationPlayer]). A [code]time[/code] and [code]delta[/code] may be passed, as well as whether [code]seek[/code] happened.
+ Blend an animation by [param blend] amount (name must be valid in the linked [AnimationPlayer]). A [param time] and [param delta] may be passed, as well as whether [param seeked] happened.
</description>
</method>
<method name="blend_input">
<return type="float" />
- <argument index="0" name="input_index" type="int" />
- <argument index="1" name="time" type="float" />
- <argument index="2" name="seek" type="bool" />
- <argument index="3" name="seek_root" type="bool" />
- <argument index="4" name="blend" type="float" />
- <argument index="5" name="filter" type="int" enum="AnimationNode.FilterAction" default="0" />
- <argument index="6" name="sync" type="bool" default="true" />
+ <param index="0" name="input_index" type="int" />
+ <param index="1" name="time" type="float" />
+ <param index="2" name="seek" type="bool" />
+ <param index="3" name="seek_root" type="bool" />
+ <param index="4" name="blend" type="float" />
+ <param index="5" name="filter" type="int" enum="AnimationNode.FilterAction" default="0" />
+ <param index="6" name="sync" type="bool" default="true" />
<description>
- Blend an input. This is only useful for nodes created for an [AnimationNodeBlendTree]. The [code]time[/code] parameter is a relative delta, unless [code]seek[/code] is [code]true[/code], in which case it is absolute. A filter mode may be optionally passed (see [enum FilterAction] for options).
+ Blend an input. This is only useful for nodes created for an [AnimationNodeBlendTree]. The [param time] parameter is a relative delta, unless [param seek] is [code]true[/code], in which case it is absolute. A filter mode may be optionally passed (see [enum FilterAction] for options).
</description>
</method>
<method name="blend_node">
<return type="float" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="node" type="AnimationNode" />
- <argument index="2" name="time" type="float" />
- <argument index="3" name="seek" type="bool" />
- <argument index="4" name="seek_root" type="bool" />
- <argument index="5" name="blend" type="float" />
- <argument index="6" name="filter" type="int" enum="AnimationNode.FilterAction" default="0" />
- <argument index="7" name="sync" type="bool" default="true" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="node" type="AnimationNode" />
+ <param index="2" name="time" type="float" />
+ <param index="3" name="seek" type="bool" />
+ <param index="4" name="seek_root" type="bool" />
+ <param index="5" name="blend" type="float" />
+ <param index="6" name="filter" type="int" enum="AnimationNode.FilterAction" default="0" />
+ <param index="7" name="sync" type="bool" default="true" />
<description>
Blend another animation node (in case this node contains children animation nodes). This function is only useful if you inherit from [AnimationRootNode] instead, else editors will not display your node for addition.
</description>
@@ -115,44 +115,44 @@
</method>
<method name="get_input_name">
<return type="String" />
- <argument index="0" name="input" type="int" />
+ <param index="0" name="input" type="int" />
<description>
Gets the name of an input by index.
</description>
</method>
<method name="get_parameter" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
Gets the value of a parameter. Parameters are custom local memory used for your nodes, given a resource can be reused in multiple trees.
</description>
</method>
<method name="is_path_filtered" qualifiers="const">
<return type="bool" />
- <argument index="0" name="path" type="NodePath" />
+ <param index="0" name="path" type="NodePath" />
<description>
Returns whether the given path is filtered.
</description>
</method>
<method name="remove_input">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Removes an input, call this only when inactive.
</description>
</method>
<method name="set_filter_path">
<return type="void" />
- <argument index="0" name="path" type="NodePath" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="path" type="NodePath" />
+ <param index="1" name="enable" type="bool" />
<description>
Adds or removes a path for the filter.
</description>
</method>
<method name="set_parameter">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="value" type="Variant" />
<description>
Sets a custom parameter. These are used as local memory, because resources can be reused across the tree or scenes.
</description>
diff --git a/doc/classes/AnimationNodeBlendSpace1D.xml b/doc/classes/AnimationNodeBlendSpace1D.xml
index 7bb136308d..0f1ce127cd 100644
--- a/doc/classes/AnimationNodeBlendSpace1D.xml
+++ b/doc/classes/AnimationNodeBlendSpace1D.xml
@@ -15,11 +15,11 @@
<methods>
<method name="add_blend_point">
<return type="void" />
- <argument index="0" name="node" type="AnimationRootNode" />
- <argument index="1" name="pos" type="float" />
- <argument index="2" name="at_index" type="int" default="-1" />
+ <param index="0" name="node" type="AnimationRootNode" />
+ <param index="1" name="pos" type="float" />
+ <param index="2" name="at_index" type="int" default="-1" />
<description>
- Adds a new point that represents a [code]node[/code] on the virtual axis at a given position set by [code]pos[/code]. You can insert it at a specific index using the [code]at_index[/code] argument. If you use the default value for [code]at_index[/code], the point is inserted at the end of the blend points array.
+ Adds a new point that represents a [param node] on the virtual axis at a given position set by [param pos]. You can insert it at a specific index using the [param at_index] argument. If you use the default value for [param at_index], the point is inserted at the end of the blend points array.
</description>
</method>
<method name="get_blend_point_count" qualifiers="const">
@@ -30,39 +30,39 @@
</method>
<method name="get_blend_point_node" qualifiers="const">
<return type="AnimationRootNode" />
- <argument index="0" name="point" type="int" />
+ <param index="0" name="point" type="int" />
<description>
- Returns the [AnimationNode] referenced by the point at index [code]point[/code].
+ Returns the [AnimationNode] referenced by the point at index [param point].
</description>
</method>
<method name="get_blend_point_position" qualifiers="const">
<return type="float" />
- <argument index="0" name="point" type="int" />
+ <param index="0" name="point" type="int" />
<description>
- Returns the position of the point at index [code]point[/code].
+ Returns the position of the point at index [param point].
</description>
</method>
<method name="remove_blend_point">
<return type="void" />
- <argument index="0" name="point" type="int" />
+ <param index="0" name="point" type="int" />
<description>
- Removes the point at index [code]point[/code] from the blend axis.
+ Removes the point at index [param point] from the blend axis.
</description>
</method>
<method name="set_blend_point_node">
<return type="void" />
- <argument index="0" name="point" type="int" />
- <argument index="1" name="node" type="AnimationRootNode" />
+ <param index="0" name="point" type="int" />
+ <param index="1" name="node" type="AnimationRootNode" />
<description>
- Changes the [AnimationNode] referenced by the point at index [code]point[/code].
+ Changes the [AnimationNode] referenced by the point at index [param point].
</description>
</method>
<method name="set_blend_point_position">
<return type="void" />
- <argument index="0" name="point" type="int" />
- <argument index="1" name="pos" type="float" />
+ <param index="0" name="point" type="int" />
+ <param index="1" name="pos" type="float" />
<description>
- Updates the position of the point at index [code]point[/code] on the blend axis.
+ Updates the position of the point at index [param point] on the blend axis.
</description>
</method>
</methods>
diff --git a/doc/classes/AnimationNodeBlendSpace2D.xml b/doc/classes/AnimationNodeBlendSpace2D.xml
index eb2249d2d2..8d5e153b03 100644
--- a/doc/classes/AnimationNodeBlendSpace2D.xml
+++ b/doc/classes/AnimationNodeBlendSpace2D.xml
@@ -15,21 +15,21 @@
<methods>
<method name="add_blend_point">
<return type="void" />
- <argument index="0" name="node" type="AnimationRootNode" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="at_index" type="int" default="-1" />
+ <param index="0" name="node" type="AnimationRootNode" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="at_index" type="int" default="-1" />
<description>
- Adds a new point that represents a [code]node[/code] at the position set by [code]pos[/code]. You can insert it at a specific index using the [code]at_index[/code] argument. If you use the default value for [code]at_index[/code], the point is inserted at the end of the blend points array.
+ Adds a new point that represents a [param node] at the position set by [param pos]. You can insert it at a specific index using the [param at_index] argument. If you use the default value for [param at_index], the point is inserted at the end of the blend points array.
</description>
</method>
<method name="add_triangle">
<return type="void" />
- <argument index="0" name="x" type="int" />
- <argument index="1" name="y" type="int" />
- <argument index="2" name="z" type="int" />
- <argument index="3" name="at_index" type="int" default="-1" />
+ <param index="0" name="x" type="int" />
+ <param index="1" name="y" type="int" />
+ <param index="2" name="z" type="int" />
+ <param index="3" name="at_index" type="int" default="-1" />
<description>
- Creates a new triangle using three points [code]x[/code], [code]y[/code], and [code]z[/code]. Triangles can overlap. You can insert the triangle at a specific index using the [code]at_index[/code] argument. If you use the default value for [code]at_index[/code], the point is inserted at the end of the blend points array.
+ Creates a new triangle using three points [param x], [param y], and [param z]. Triangles can overlap. You can insert the triangle at a specific index using the [param at_index] argument. If you use the default value for [param at_index], the point is inserted at the end of the blend points array.
</description>
</method>
<method name="get_blend_point_count" qualifiers="const">
@@ -40,16 +40,16 @@
</method>
<method name="get_blend_point_node" qualifiers="const">
<return type="AnimationRootNode" />
- <argument index="0" name="point" type="int" />
+ <param index="0" name="point" type="int" />
<description>
- Returns the [AnimationRootNode] referenced by the point at index [code]point[/code].
+ Returns the [AnimationRootNode] referenced by the point at index [param point].
</description>
</method>
<method name="get_blend_point_position" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="point" type="int" />
+ <param index="0" name="point" type="int" />
<description>
- Returns the position of the point at index [code]point[/code].
+ Returns the position of the point at index [param point].
</description>
</method>
<method name="get_triangle_count" qualifiers="const">
@@ -60,40 +60,40 @@
</method>
<method name="get_triangle_point">
<return type="int" />
- <argument index="0" name="triangle" type="int" />
- <argument index="1" name="point" type="int" />
+ <param index="0" name="triangle" type="int" />
+ <param index="1" name="point" type="int" />
<description>
- Returns the position of the point at index [code]point[/code] in the triangle of index [code]triangle[/code].
+ Returns the position of the point at index [param point] in the triangle of index [param triangle].
</description>
</method>
<method name="remove_blend_point">
<return type="void" />
- <argument index="0" name="point" type="int" />
+ <param index="0" name="point" type="int" />
<description>
- Removes the point at index [code]point[/code] from the blend space.
+ Removes the point at index [param point] from the blend space.
</description>
</method>
<method name="remove_triangle">
<return type="void" />
- <argument index="0" name="triangle" type="int" />
+ <param index="0" name="triangle" type="int" />
<description>
- Removes the triangle at index [code]triangle[/code] from the blend space.
+ Removes the triangle at index [param triangle] from the blend space.
</description>
</method>
<method name="set_blend_point_node">
<return type="void" />
- <argument index="0" name="point" type="int" />
- <argument index="1" name="node" type="AnimationRootNode" />
+ <param index="0" name="point" type="int" />
+ <param index="1" name="node" type="AnimationRootNode" />
<description>
- Changes the [AnimationNode] referenced by the point at index [code]point[/code].
+ Changes the [AnimationNode] referenced by the point at index [param point].
</description>
</method>
<method name="set_blend_point_position">
<return type="void" />
- <argument index="0" name="point" type="int" />
- <argument index="1" name="pos" type="Vector2" />
+ <param index="0" name="point" type="int" />
+ <param index="1" name="pos" type="Vector2" />
<description>
- Updates the position of the point at index [code]point[/code] on the blend axis.
+ Updates the position of the point at index [param point] on the blend axis.
</description>
</method>
</methods>
diff --git a/doc/classes/AnimationNodeBlendTree.xml b/doc/classes/AnimationNodeBlendTree.xml
index fcdd09f144..4c7943ece3 100644
--- a/doc/classes/AnimationNodeBlendTree.xml
+++ b/doc/classes/AnimationNodeBlendTree.xml
@@ -13,70 +13,70 @@
<methods>
<method name="add_node">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="node" type="AnimationNode" />
- <argument index="2" name="position" type="Vector2" default="Vector2(0, 0)" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="node" type="AnimationNode" />
+ <param index="2" name="position" type="Vector2" default="Vector2(0, 0)" />
<description>
- Adds an [AnimationNode] at the given [code]position[/code]. The [code]name[/code] is used to identify the created sub-node later.
+ Adds an [AnimationNode] at the given [param position]. The [param name] is used to identify the created sub-node later.
</description>
</method>
<method name="connect_node">
<return type="void" />
- <argument index="0" name="input_node" type="StringName" />
- <argument index="1" name="input_index" type="int" />
- <argument index="2" name="output_node" type="StringName" />
+ <param index="0" name="input_node" type="StringName" />
+ <param index="1" name="input_index" type="int" />
+ <param index="2" name="output_node" type="StringName" />
<description>
- Connects the output of an [AnimationNode] as input for another [AnimationNode], at the input port specified by [code]input_index[/code].
+ Connects the output of an [AnimationNode] as input for another [AnimationNode], at the input port specified by [param input_index].
</description>
</method>
<method name="disconnect_node">
<return type="void" />
- <argument index="0" name="input_node" type="StringName" />
- <argument index="1" name="input_index" type="int" />
+ <param index="0" name="input_node" type="StringName" />
+ <param index="1" name="input_index" type="int" />
<description>
Disconnects the node connected to the specified input.
</description>
</method>
<method name="get_node" qualifiers="const">
<return type="AnimationNode" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Returns the sub-node with the specified [code]name[/code].
+ Returns the sub-node with the specified [param name].
</description>
</method>
<method name="get_node_position" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Returns the position of the sub-node with the specified [code]name[/code].
+ Returns the position of the sub-node with the specified [param name].
</description>
</method>
<method name="has_node" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Returns [code]true[/code] if a sub-node with specified [code]name[/code] exists.
+ Returns [code]true[/code] if a sub-node with specified [param name] exists.
</description>
</method>
<method name="remove_node">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
Removes a sub-node.
</description>
</method>
<method name="rename_node">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="new_name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="new_name" type="StringName" />
<description>
Changes the name of a sub-node.
</description>
</method>
<method name="set_node_position">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="position" type="Vector2" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="position" type="Vector2" />
<description>
Modifies the position of a sub-node.
</description>
diff --git a/doc/classes/AnimationNodeStateMachine.xml b/doc/classes/AnimationNodeStateMachine.xml
index 6140dd799f..0fb789875f 100644
--- a/doc/classes/AnimationNodeStateMachine.xml
+++ b/doc/classes/AnimationNodeStateMachine.xml
@@ -23,18 +23,18 @@
<methods>
<method name="add_node">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="node" type="AnimationNode" />
- <argument index="2" name="position" type="Vector2" default="Vector2(0, 0)" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="node" type="AnimationNode" />
+ <param index="2" name="position" type="Vector2" default="Vector2(0, 0)" />
<description>
- Adds a new node to the graph. The [code]position[/code] is used for display in the editor.
+ Adds a new node to the graph. The [param position] is used for display in the editor.
</description>
</method>
<method name="add_transition">
<return type="void" />
- <argument index="0" name="from" type="StringName" />
- <argument index="1" name="to" type="StringName" />
- <argument index="2" name="transition" type="AnimationNodeStateMachineTransition" />
+ <param index="0" name="from" type="StringName" />
+ <param index="1" name="to" type="StringName" />
+ <param index="2" name="transition" type="AnimationNodeStateMachineTransition" />
<description>
Adds a transition between the given nodes.
</description>
@@ -47,28 +47,28 @@
</method>
<method name="get_node" qualifiers="const">
<return type="AnimationNode" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
Returns the animation node with the given name.
</description>
</method>
<method name="get_node_name" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="node" type="AnimationNode" />
+ <param index="0" name="node" type="AnimationNode" />
<description>
Returns the given animation node's name.
</description>
</method>
<method name="get_node_position" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
Returns the given node's coordinates. Used for display in the editor.
</description>
</method>
<method name="get_transition" qualifiers="const">
<return type="AnimationNodeStateMachineTransition" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns the given transition.
</description>
@@ -81,81 +81,81 @@
</method>
<method name="get_transition_from" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns the given transition's start node.
</description>
</method>
<method name="get_transition_to" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns the given transition's end node.
</description>
</method>
<method name="has_node" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
Returns [code]true[/code] if the graph contains the given node.
</description>
</method>
<method name="has_transition" qualifiers="const">
<return type="bool" />
- <argument index="0" name="from" type="StringName" />
- <argument index="1" name="to" type="StringName" />
+ <param index="0" name="from" type="StringName" />
+ <param index="1" name="to" type="StringName" />
<description>
Returns [code]true[/code] if there is a transition between the given nodes.
</description>
</method>
<method name="remove_node">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
Deletes the given node from the graph.
</description>
</method>
<method name="remove_transition">
<return type="void" />
- <argument index="0" name="from" type="StringName" />
- <argument index="1" name="to" type="StringName" />
+ <param index="0" name="from" type="StringName" />
+ <param index="1" name="to" type="StringName" />
<description>
Deletes the transition between the two specified nodes.
</description>
</method>
<method name="remove_transition_by_index">
<return type="void" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Deletes the given transition by index.
</description>
</method>
<method name="rename_node">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="new_name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="new_name" type="StringName" />
<description>
Renames the given node.
</description>
</method>
<method name="replace_node">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="node" type="AnimationNode" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="node" type="AnimationNode" />
<description>
</description>
</method>
<method name="set_graph_offset">
<return type="void" />
- <argument index="0" name="offset" type="Vector2" />
+ <param index="0" name="offset" type="Vector2" />
<description>
Sets the draw offset of the graph. Used for display in the editor.
</description>
</method>
<method name="set_node_position">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="position" type="Vector2" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="position" type="Vector2" />
<description>
Sets the node's coordinates. Used for display in the editor.
</description>
diff --git a/doc/classes/AnimationNodeStateMachinePlayback.xml b/doc/classes/AnimationNodeStateMachinePlayback.xml
index 901ab569c8..8f53ef0dcf 100644
--- a/doc/classes/AnimationNodeStateMachinePlayback.xml
+++ b/doc/classes/AnimationNodeStateMachinePlayback.xml
@@ -52,7 +52,7 @@
</method>
<method name="start">
<return type="void" />
- <argument index="0" name="node" type="StringName" />
+ <param index="0" name="node" type="StringName" />
<description>
Starts playing the given animation.
</description>
@@ -65,7 +65,7 @@
</method>
<method name="travel">
<return type="void" />
- <argument index="0" name="to_node" type="StringName" />
+ <param index="0" name="to_node" type="StringName" />
<description>
Transitions from the current state to another one, following the shortest path.
</description>
diff --git a/doc/classes/AnimationNodeStateMachineTransition.xml b/doc/classes/AnimationNodeStateMachineTransition.xml
index 0badb831de..1b5a795b3c 100644
--- a/doc/classes/AnimationNodeStateMachineTransition.xml
+++ b/doc/classes/AnimationNodeStateMachineTransition.xml
@@ -9,7 +9,7 @@
</tutorials>
<members>
<member name="advance_condition" type="StringName" setter="set_advance_condition" getter="get_advance_condition" default="&amp;&quot;&quot;">
- Turn on auto advance when this condition is set. The provided name will become a boolean parameter on the [AnimationTree] that can be controlled from code (see [url=$DOCS_URL/tutorials/animation/animation_tree.html#controlling-from-code][/url]). For example, if [member AnimationTree.tree_root] is an [AnimationNodeStateMachine] and [member advance_condition] is set to [code]"idle"[/code]:
+ Turn on auto advance when this condition is set. The provided name will become a boolean parameter on the [AnimationTree] that can be controlled from code (see [url=$DOCS_URL/tutorials/animation/animation_tree.html#controlling-from-code]Using AnimationTree[/url]). For example, if [member AnimationTree.tree_root] is an [AnimationNodeStateMachine] and [member advance_condition] is set to [code]"idle"[/code]:
[codeblocks]
[gdscript]
$animation_tree.set("parameters/conditions/idle", is_on_floor and (linear_velocity.x == 0))
@@ -37,6 +37,9 @@
<member name="switch_mode" type="int" setter="set_switch_mode" getter="get_switch_mode" enum="AnimationNodeStateMachineTransition.SwitchMode" default="0">
The transition type.
</member>
+ <member name="xfade_curve" type="Curve" setter="set_xfade_curve" getter="get_xfade_curve">
+ Ease curve for better control over cross-fade between this state and the next.
+ </member>
<member name="xfade_time" type="float" setter="set_xfade_time" getter="get_xfade_time" default="0.0">
The time to cross-fade between this state and the next.
</member>
diff --git a/doc/classes/AnimationNodeTransition.xml b/doc/classes/AnimationNodeTransition.xml
index 7e757d4640..d574bc044d 100644
--- a/doc/classes/AnimationNodeTransition.xml
+++ b/doc/classes/AnimationNodeTransition.xml
@@ -14,27 +14,27 @@
<methods>
<method name="get_input_caption" qualifiers="const">
<return type="String" />
- <argument index="0" name="input" type="int" />
+ <param index="0" name="input" type="int" />
<description>
</description>
</method>
<method name="is_input_set_as_auto_advance" qualifiers="const">
<return type="bool" />
- <argument index="0" name="input" type="int" />
+ <param index="0" name="input" type="int" />
<description>
</description>
</method>
<method name="set_input_as_auto_advance">
<return type="void" />
- <argument index="0" name="input" type="int" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="input" type="int" />
+ <param index="1" name="enable" type="bool" />
<description>
</description>
</method>
<method name="set_input_caption">
<return type="void" />
- <argument index="0" name="input" type="int" />
- <argument index="1" name="caption" type="String" />
+ <param index="0" name="input" type="int" />
+ <param index="1" name="caption" type="String" />
<description>
</description>
</method>
@@ -46,7 +46,9 @@
<member name="input_count" type="int" setter="set_enabled_inputs" getter="get_enabled_inputs" default="0">
The number of available input ports for this node.
</member>
- <member name="xfade_time" type="float" setter="set_cross_fade_time" getter="get_cross_fade_time" default="0.0">
+ <member name="xfade_curve" type="Curve" setter="set_xfade_curve" getter="get_xfade_curve">
+ </member>
+ <member name="xfade_time" type="float" setter="set_xfade_time" getter="get_xfade_time" default="0.0">
Cross-fading time (in seconds) between each animation connected to the inputs.
</member>
</members>
diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml
index b24c439432..710dc55a4b 100644
--- a/doc/classes/AnimationPlayer.xml
+++ b/doc/classes/AnimationPlayer.xml
@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AnimationPlayer" inherits="Node" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- Container and player of [Animation] resources.
+ Player of [Animation] resources.
</brief_description>
<description>
- An animation player is used for general-purpose playback of [Animation] resources. It contains a dictionary of animations (referenced by name) and custom blend times between their transitions. Additionally, animations can be played and blended in different channels.
- [AnimationPlayer] is more suited than [Tween] for animations where you know the final values in advance. For example, fading a screen in and out is more easily done with an [AnimationPlayer] node thanks to the animation tools provided by the editor. That particular example can also be implemented with a [Tween] node, but it requires doing everything by code.
+ An animation player is used for general-purpose playback of [Animation] resources. It contains a dictionary of [AnimationLibrary] resources and custom blend times between animation transitions.
+ Some methods and properties use a single key to refence an animation directly. These keys are formatted as the key for the library, followed by a forward slash, then the key for the animation whithin the library, for example [code]"movement/run"[/code]. If the library's key is an empty string (known as the default library), the forward slash is omitted, being the same key used by the library.
+ [AnimationPlayer] is more suited than [Tween] for animations where you know the final values in advance. For example, fading a screen in and out is more easily done with an [AnimationPlayer] node thanks to the animation tools provided by the editor. That particular example can also be implemented with a [Tween], but it requires doing everything by code.
Updating the target properties of animations occurs at process time.
</description>
<tutorials>
@@ -16,31 +17,32 @@
<methods>
<method name="add_animation_library">
<return type="int" enum="Error" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="library" type="AnimationLibrary" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="library" type="AnimationLibrary" />
<description>
+ Adds [param library] to the animation player, under the key [param name].
</description>
</method>
<method name="advance">
<return type="void" />
- <argument index="0" name="delta" type="float" />
+ <param index="0" name="delta" type="float" />
<description>
- Shifts position in the animation timeline and immediately updates the animation. [code]delta[/code] is the time in seconds to shift. Events between the current frame and [code]delta[/code] are handled.
+ Shifts position in the animation timeline and immediately updates the animation. [param delta] is the time in seconds to shift. Events between the current frame and [param delta] are handled.
</description>
</method>
<method name="animation_get_next" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="anim_from" type="StringName" />
+ <param index="0" name="anim_from" type="StringName" />
<description>
- Returns the name of the next animation in the queue.
+ Returns the key of the animation which is queued to play after the [param anim_from] animation.
</description>
</method>
<method name="animation_set_next">
<return type="void" />
- <argument index="0" name="anim_from" type="StringName" />
- <argument index="1" name="anim_to" type="StringName" />
+ <param index="0" name="anim_from" type="StringName" />
+ <param index="1" name="anim_to" type="StringName" />
<description>
- Triggers the [code]anim_to[/code] animation when the [code]anim_from[/code] animation completes.
+ Triggers the [param anim_to] animation when the [param anim_from] animation completes.
</description>
</method>
<method name="clear_caches">
@@ -57,47 +59,50 @@
</method>
<method name="find_animation" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="animation" type="Animation" />
+ <param index="0" name="animation" type="Animation" />
<description>
- Returns the name of [code]animation[/code] or an empty string if not found.
+ Returns the key of [param animation] or an empty [StringName] if not found.
</description>
</method>
<method name="find_animation_library" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="animation" type="Animation" />
+ <param index="0" name="animation" type="Animation" />
<description>
+ Returns the key for the [AnimationLibrary] that contains [param animation] or an empty [StringName] if not found.
</description>
</method>
<method name="get_animation" qualifiers="const">
<return type="Animation" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Returns the [Animation] with key [code]name[/code] or [code]null[/code] if not found.
+ Returns the [Animation] with the key [param name]. If the animation does not exist, [code]null[/code] is returned and an error is logged.
</description>
</method>
<method name="get_animation_library" qualifiers="const">
<return type="AnimationLibrary" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
+ Returns the first [AnimationLibrary] with key [param name] or [code]null[/code] if not found.
</description>
</method>
<method name="get_animation_library_list" qualifiers="const">
<return type="StringName[]" />
<description>
+ Returns the list of stored library keys.
</description>
</method>
<method name="get_animation_list" qualifiers="const">
<return type="PackedStringArray" />
<description>
- Returns the list of stored animation names.
+ Returns the list of stored animation keys.
</description>
</method>
<method name="get_blend_time" qualifiers="const">
<return type="float" />
- <argument index="0" name="anim_from" type="StringName" />
- <argument index="1" name="anim_to" type="StringName" />
+ <param index="0" name="anim_from" type="StringName" />
+ <param index="1" name="anim_to" type="StringName" />
<description>
- Gets the blend time (in seconds) between two animations, referenced by their names.
+ Gets the blend time (in seconds) between two animations, referenced by their keys.
</description>
</method>
<method name="get_playing_speed" qualifiers="const">
@@ -109,20 +114,21 @@
<method name="get_queue">
<return type="PackedStringArray" />
<description>
- Returns a list of the animation names that are currently queued to play.
+ Returns a list of the animation keys that are currently queued to play.
</description>
</method>
<method name="has_animation" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Returns [code]true[/code] if the [AnimationPlayer] stores an [Animation] with key [code]name[/code].
+ Returns [code]true[/code] if the [AnimationPlayer] stores an [Animation] with key [param name].
</description>
</method>
<method name="has_animation_library" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
+ Returns [code]true[/code] if the [AnimationPlayer] stores an [AnimationLibrary] with key [param name].
</description>
</method>
<method name="is_playing" qualifiers="const">
@@ -133,28 +139,28 @@
</method>
<method name="play">
<return type="void" />
- <argument index="0" name="name" type="StringName" default="&quot;&quot;" />
- <argument index="1" name="custom_blend" type="float" default="-1" />
- <argument index="2" name="custom_speed" type="float" default="1.0" />
- <argument index="3" name="from_end" type="bool" default="false" />
+ <param index="0" name="name" type="StringName" default="&quot;&quot;" />
+ <param index="1" name="custom_blend" type="float" default="-1" />
+ <param index="2" name="custom_speed" type="float" default="1.0" />
+ <param index="3" name="from_end" type="bool" default="false" />
<description>
- Plays the animation with key [code]name[/code]. Custom blend times and speed can be set. If [code]custom_speed[/code] is negative and [code]from_end[/code] is [code]true[/code], the animation will play backwards (which is equivalent to calling [method play_backwards]).
- The [AnimationPlayer] keeps track of its current or last played animation with [member assigned_animation]. If this method is called with that same animation [code]name[/code], or with no [code]name[/code] parameter, the assigned animation will resume playing if it was paused, or restart if it was stopped (see [method stop] for both pause and stop). If the animation was already playing, it will keep playing.
+ Plays the animation with key [param name]. Custom blend times and speed can be set. If [param custom_speed] is negative and [param from_end] is [code]true[/code], the animation will play backwards (which is equivalent to calling [method play_backwards]).
+ The [AnimationPlayer] keeps track of its current or last played animation with [member assigned_animation]. If this method is called with that same animation [param name], or with no [param name] parameter, the assigned animation will resume playing if it was paused, or restart if it was stopped (see [method stop] for both pause and stop). If the animation was already playing, it will keep playing.
[b]Note:[/b] The animation will be updated the next time the [AnimationPlayer] is processed. If other variables are updated at the same time this is called, they may be updated too early. To perform the update immediately, call [code]advance(0)[/code].
</description>
</method>
<method name="play_backwards">
<return type="void" />
- <argument index="0" name="name" type="StringName" default="&quot;&quot;" />
- <argument index="1" name="custom_blend" type="float" default="-1" />
+ <param index="0" name="name" type="StringName" default="&quot;&quot;" />
+ <param index="1" name="custom_blend" type="float" default="-1" />
<description>
- Plays the animation with key [code]name[/code] in reverse.
+ Plays the animation with key [param name] in reverse.
This method is a shorthand for [method play] with [code]custom_speed = -1.0[/code] and [code]from_end = true[/code], so see its description for more information.
</description>
</method>
<method name="queue">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
Queues an animation for playback once the current one is done.
[b]Note:[/b] If a looped animation is currently playing, the queued animation will never play unless the looped animation is stopped somehow.
@@ -162,57 +168,59 @@
</method>
<method name="remove_animation_library">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
+ Removes the [AnimationLibrary] assosiated with the key [param name].
</description>
</method>
<method name="rename_animation_library">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="newname" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="newname" type="StringName" />
<description>
+ Moves the [AnimationLibrary] associated with the key [param name] to the key [param newname].
</description>
</method>
<method name="seek">
<return type="void" />
- <argument index="0" name="seconds" type="float" />
- <argument index="1" name="update" type="bool" default="false" />
+ <param index="0" name="seconds" type="float" />
+ <param index="1" name="update" type="bool" default="false" />
<description>
- Seeks the animation to the [code]seconds[/code] point in time (in seconds). If [code]update[/code] is [code]true[/code], the animation updates too, otherwise it updates at process time. Events between the current frame and [code]seconds[/code] are skipped.
+ Seeks the animation to the [param seconds] point in time (in seconds). If [param update] is [code]true[/code], the animation updates too, otherwise it updates at process time. Events between the current frame and [param seconds] are skipped.
[b]Note:[/b] Seeking to the end of the animation doesn't emit [signal animation_finished]. If you want to skip animation and emit the signal, use [method advance].
</description>
</method>
<method name="set_blend_time">
<return type="void" />
- <argument index="0" name="anim_from" type="StringName" />
- <argument index="1" name="anim_to" type="StringName" />
- <argument index="2" name="sec" type="float" />
+ <param index="0" name="anim_from" type="StringName" />
+ <param index="1" name="anim_to" type="StringName" />
+ <param index="2" name="sec" type="float" />
<description>
- Specifies a blend time (in seconds) between two animations, referenced by their names.
+ Specifies a blend time (in seconds) between two animations, referenced by their keys.
</description>
</method>
<method name="stop">
<return type="void" />
- <argument index="0" name="reset" type="bool" default="true" />
+ <param index="0" name="reset" type="bool" default="true" />
<description>
- Stops or pauses the currently playing animation. If [code]reset[/code] is [code]true[/code], the animation position is reset to [code]0[/code] and the playback speed is reset to [code]1.0[/code].
- If [code]reset[/code] is [code]false[/code], the [member current_animation_position] will be kept and calling [method play] or [method play_backwards] without arguments or with the same animation name as [member assigned_animation] will resume the animation.
+ Stops or pauses the currently playing animation. If [param reset] is [code]true[/code], the animation position is reset to [code]0[/code] and the playback speed is reset to [code]1.0[/code].
+ If [param reset] is [code]false[/code], the [member current_animation_position] will be kept and calling [method play] or [method play_backwards] without arguments or with the same animation name as [member assigned_animation] will resume the animation.
</description>
</method>
</methods>
<members>
<member name="assigned_animation" type="String" setter="set_assigned_animation" getter="get_assigned_animation">
- If playing, the current animation; otherwise, the animation last played. When set, would change the animation, but would not play it unless currently playing. See also [member current_animation].
+ If playing, the the current animation's key, otherwise, the animation last played. When set, this changes the animation, but will not play it unless already playing. See also [member current_animation].
</member>
<member name="autoplay" type="String" setter="set_autoplay" getter="get_autoplay" default="&quot;&quot;">
- The name of the animation to play when the scene loads.
+ The key 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 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.
+ The key 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.
+ The length (in seconds) of the currently playing animation.
</member>
<member name="current_animation_position" type="float" setter="" getter="get_current_animation_position">
The position (in seconds) of the currently playing animation.
@@ -237,8 +245,8 @@
The speed scaling ratio. For instance, if this value is 1, then the animation plays at normal speed. If it's 0.5, then it plays at half speed. If it's 2, then it plays at double speed.
</member>
<member name="reset_on_save" type="bool" setter="set_reset_on_save_enabled" getter="is_reset_on_save_enabled" default="true">
- This is used by the editor. If set to [code]true[/code], the scene will be saved with the effects of the reset animation applied (as if it had been seeked to time 0), then reverted after saving.
- In other words, the saved scene file will contain the "default pose", as defined by the reset animation, if any, with the editor keeping the values that the nodes had before saving.
+ This is used by the editor. If set to [code]true[/code], the scene will be saved with the effects of the reset animation (the animation with the key [code]"RESET"[/code]) applied as if it had been seeked to time 0, with the editor keeping the values that the scene had before saving.
+ This makes it more convenient to preview and edit animations in the editor, as changes to the scene will not be saved as long as they are set in the reset animation.
</member>
<member name="root_node" type="NodePath" setter="set_root" getter="get_root" default="NodePath(&quot;..&quot;)">
The node from which node path references will travel.
@@ -246,22 +254,22 @@
</members>
<signals>
<signal name="animation_changed">
- <argument index="0" name="old_name" type="StringName" />
- <argument index="1" name="new_name" type="StringName" />
+ <param index="0" name="old_name" type="StringName" />
+ <param index="1" name="new_name" type="StringName" />
<description>
- Emitted when a queued animation plays after the previous animation was finished. See [method queue].
- [b]Note:[/b] The signal is not emitted when the animation is changed via [method play] or from [AnimationTree].
+ Emitted when a queued animation plays after the previous animation finished. See [method queue].
+ [b]Note:[/b] The signal is not emitted when the animation is changed via [method play] or by an [AnimationTree].
</description>
</signal>
<signal name="animation_finished">
- <argument index="0" name="anim_name" type="StringName" />
+ <param index="0" name="anim_name" type="StringName" />
<description>
Notifies when an animation finished playing.
[b]Note:[/b] This signal is not emitted if an animation is looping.
</description>
</signal>
<signal name="animation_started">
- <argument index="0" name="anim_name" type="StringName" />
+ <param index="0" name="anim_name" type="StringName" />
<description>
Notifies when an animation starts playing.
</description>
diff --git a/doc/classes/AnimationTree.xml b/doc/classes/AnimationTree.xml
index 45d9152564..f2bf74f495 100644
--- a/doc/classes/AnimationTree.xml
+++ b/doc/classes/AnimationTree.xml
@@ -14,7 +14,7 @@
<methods>
<method name="advance">
<return type="void" />
- <argument index="0" name="delta" type="float" />
+ <param index="0" name="delta" type="float" />
<description>
Manually advance the animations by the specified time (in seconds).
</description>
@@ -27,8 +27,8 @@
</method>
<method name="rename_parameter">
<return type="void" />
- <argument index="0" name="old_name" type="String" />
- <argument index="1" name="new_name" type="String" />
+ <param index="0" name="old_name" type="String" />
+ <param index="1" name="new_name" type="String" />
<description>
</description>
</method>
diff --git a/doc/classes/Area2D.xml b/doc/classes/Area2D.xml
index 1eb74768f5..f1e40d4979 100644
--- a/doc/classes/Area2D.xml
+++ b/doc/classes/Area2D.xml
@@ -4,7 +4,9 @@
2D area for detection and physics and audio influence.
</brief_description>
<description>
- 2D area that detects [CollisionObject2D] nodes overlapping, entering, or exiting. Can also alter or override local physics parameters (gravity, damping) and route audio to a custom audio bus.
+ 2D area that detects [CollisionObject2D] nodes overlapping, entering, or exiting. Can also alter or override local physics parameters (gravity, damping) and route audio to custom audio buses.
+ To give the area its shape, add a [CollisionShape2D] or a [CollisionPolygon2D] node as a [i]direct[/i] child (or add multiple such nodes as direct children) of the area.
+ [b]Warning:[/b] See [ConcavePolygonShape2D] for a warning about possibly unexpected behavior when using that shape for an area.
</description>
<tutorials>
<link title="Using Area2D">$DOCS_URL/tutorials/physics/using_area_2d.html</link>
@@ -29,7 +31,7 @@
</method>
<method name="overlaps_area" qualifiers="const">
<return type="bool" />
- <argument index="0" name="area" type="Node" />
+ <param index="0" name="area" type="Node" />
<description>
Returns [code]true[/code] if the given [Area2D] intersects or overlaps this [Area2D], [code]false[/code] otherwise.
[b]Note:[/b] The result of this test is not immediate after moving objects. For performance, the list of overlaps is updated once per frame and before the physics step. Consider using signals instead.
@@ -37,11 +39,11 @@
</method>
<method name="overlaps_body" qualifiers="const">
<return type="bool" />
- <argument index="0" name="body" type="Node" />
+ <param index="0" name="body" type="Node" />
<description>
Returns [code]true[/code] if the given physics body intersects or overlaps this [Area2D], [code]false[/code] otherwise.
[b]Note:[/b] The result of this test is not immediate after moving objects. For performance, list of overlaps is updated once per frame and before the physics step. Consider using signals instead.
- The [code]body[/code] argument can either be a [PhysicsBody2D] or a [TileMap] instance. While TileMaps are not physics bodies themselves, they register their tiles with collision shapes as a virtual physics body.
+ The [param body] argument can either be a [PhysicsBody2D] or a [TileMap] instance. While TileMaps are not physics bodies themselves, they register their tiles with collision shapes as a virtual physics body.
</description>
</method>
</methods>
@@ -96,83 +98,83 @@
</members>
<signals>
<signal name="area_entered">
- <argument index="0" name="area" type="Area2D" />
+ <param index="0" name="area" type="Area2D" />
<description>
Emitted when another Area2D enters this Area2D. Requires [member monitoring] to be set to [code]true[/code].
- [code]area[/code] the other Area2D.
+ [param area] the other Area2D.
</description>
</signal>
<signal name="area_exited">
- <argument index="0" name="area" type="Area2D" />
+ <param index="0" name="area" type="Area2D" />
<description>
Emitted when another Area2D exits this Area2D. Requires [member monitoring] to be set to [code]true[/code].
- [code]area[/code] the other Area2D.
+ [param area] the other Area2D.
</description>
</signal>
<signal name="area_shape_entered">
- <argument index="0" name="area_rid" type="RID" />
- <argument index="1" name="area" type="Area2D" />
- <argument index="2" name="area_shape_index" type="int" />
- <argument index="3" name="local_shape_index" type="int" />
+ <param index="0" name="area_rid" type="RID" />
+ <param index="1" name="area" type="Area2D" />
+ <param index="2" name="area_shape_index" type="int" />
+ <param index="3" name="local_shape_index" type="int" />
<description>
Emitted when one of another Area2D's [Shape2D]s enters one of this Area2D's [Shape2D]s. Requires [member monitoring] to be set to [code]true[/code].
- [code]area_rid[/code] the [RID] of the other Area2D's [CollisionObject2D] used by the [PhysicsServer2D].
- [code]area[/code] the other Area2D.
- [code]area_shape_index[/code] the index of the [Shape2D] of the other Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]area.shape_owner_get_owner(area.shape_find_owner(area_shape_index))[/code].
- [code]local_shape_index[/code] the index of the [Shape2D] of this Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
+ [param area_rid] the [RID] of the other Area2D's [CollisionObject2D] used by the [PhysicsServer2D].
+ [param area] the other Area2D.
+ [param area_shape_index] the index of the [Shape2D] of the other Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]area.shape_owner_get_owner(area.shape_find_owner(area_shape_index))[/code].
+ [param local_shape_index] the index of the [Shape2D] of this Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
</description>
</signal>
<signal name="area_shape_exited">
- <argument index="0" name="area_rid" type="RID" />
- <argument index="1" name="area" type="Area2D" />
- <argument index="2" name="area_shape_index" type="int" />
- <argument index="3" name="local_shape_index" type="int" />
+ <param index="0" name="area_rid" type="RID" />
+ <param index="1" name="area" type="Area2D" />
+ <param index="2" name="area_shape_index" type="int" />
+ <param index="3" name="local_shape_index" type="int" />
<description>
Emitted when one of another Area2D's [Shape2D]s exits one of this Area2D's [Shape2D]s. Requires [member monitoring] to be set to [code]true[/code].
- [code]area_rid[/code] the [RID] of the other Area2D's [CollisionObject2D] used by the [PhysicsServer2D].
- [code]area[/code] the other Area2D.
- [code]area_shape_index[/code] the index of the [Shape2D] of the other Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]area.shape_owner_get_owner(area.shape_find_owner(area_shape_index))[/code].
- [code]local_shape_index[/code] the index of the [Shape2D] of this Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
+ [param area_rid] the [RID] of the other Area2D's [CollisionObject2D] used by the [PhysicsServer2D].
+ [param area] the other Area2D.
+ [param area_shape_index] the index of the [Shape2D] of the other Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]area.shape_owner_get_owner(area.shape_find_owner(area_shape_index))[/code].
+ [param local_shape_index] the index of the [Shape2D] of this Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
</description>
</signal>
<signal name="body_entered">
- <argument index="0" name="body" type="Node2D" />
+ <param index="0" name="body" type="Node2D" />
<description>
Emitted when a [PhysicsBody2D] or [TileMap] enters this Area2D. Requires [member monitoring] to be set to [code]true[/code]. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s.
- [code]body[/code] the [Node], if it exists in the tree, of the other [PhysicsBody2D] or [TileMap].
+ [param body] the [Node], if it exists in the tree, of the other [PhysicsBody2D] or [TileMap].
</description>
</signal>
<signal name="body_exited">
- <argument index="0" name="body" type="Node2D" />
+ <param index="0" name="body" type="Node2D" />
<description>
Emitted when a [PhysicsBody2D] or [TileMap] exits this Area2D. Requires [member monitoring] to be set to [code]true[/code]. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s.
- [code]body[/code] the [Node], if it exists in the tree, of the other [PhysicsBody2D] or [TileMap].
+ [param body] the [Node], if it exists in the tree, of the other [PhysicsBody2D] or [TileMap].
</description>
</signal>
<signal name="body_shape_entered">
- <argument index="0" name="body_rid" type="RID" />
- <argument index="1" name="body" type="Node2D" />
- <argument index="2" name="body_shape_index" type="int" />
- <argument index="3" name="local_shape_index" type="int" />
+ <param index="0" name="body_rid" type="RID" />
+ <param index="1" name="body" type="Node2D" />
+ <param index="2" name="body_shape_index" type="int" />
+ <param index="3" name="local_shape_index" type="int" />
<description>
Emitted when one of a [PhysicsBody2D] or [TileMap]'s [Shape2D]s enters one of this Area2D's [Shape2D]s. Requires [member monitoring] to be set to [code]true[/code]. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s.
- [code]body_rid[/code] the [RID] of the [PhysicsBody2D] or [TileSet]'s [CollisionObject2D] used by the [PhysicsServer2D].
- [code]body[/code] the [Node], if it exists in the tree, of the [PhysicsBody2D] or [TileMap].
- [code]body_shape_index[/code] the index of the [Shape2D] of the [PhysicsBody2D] or [TileMap] used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code].
- [code]local_shape_index[/code] the index of the [Shape2D] of this Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
+ [param body_rid] the [RID] of the [PhysicsBody2D] or [TileSet]'s [CollisionObject2D] used by the [PhysicsServer2D].
+ [param body] the [Node], if it exists in the tree, of the [PhysicsBody2D] or [TileMap].
+ [param body_shape_index] the index of the [Shape2D] of the [PhysicsBody2D] or [TileMap] used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code].
+ [param local_shape_index] the index of the [Shape2D] of this Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
</description>
</signal>
<signal name="body_shape_exited">
- <argument index="0" name="body_rid" type="RID" />
- <argument index="1" name="body" type="Node2D" />
- <argument index="2" name="body_shape_index" type="int" />
- <argument index="3" name="local_shape_index" type="int" />
+ <param index="0" name="body_rid" type="RID" />
+ <param index="1" name="body" type="Node2D" />
+ <param index="2" name="body_shape_index" type="int" />
+ <param index="3" name="local_shape_index" type="int" />
<description>
Emitted when one of a [PhysicsBody2D] or [TileMap]'s [Shape2D]s exits one of this Area2D's [Shape2D]s. Requires [member monitoring] to be set to [code]true[/code]. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s.
- [code]body_rid[/code] the [RID] of the [PhysicsBody2D] or [TileSet]'s [CollisionObject2D] used by the [PhysicsServer2D].
- [code]body[/code] the [Node], if it exists in the tree, of the [PhysicsBody2D] or [TileMap].
- [code]body_shape_index[/code] the index of the [Shape2D] of the [PhysicsBody2D] or [TileMap] used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code].
- [code]local_shape_index[/code] the index of the [Shape2D] of this Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
+ [param body_rid] the [RID] of the [PhysicsBody2D] or [TileSet]'s [CollisionObject2D] used by the [PhysicsServer2D].
+ [param body] the [Node], if it exists in the tree, of the [PhysicsBody2D] or [TileMap].
+ [param body_shape_index] the index of the [Shape2D] of the [PhysicsBody2D] or [TileMap] used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code].
+ [param local_shape_index] the index of the [Shape2D] of this Area2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
</description>
</signal>
</signals>
diff --git a/doc/classes/Area3D.xml b/doc/classes/Area3D.xml
index 7d14fd825b..14081918cf 100644
--- a/doc/classes/Area3D.xml
+++ b/doc/classes/Area3D.xml
@@ -5,6 +5,8 @@
</brief_description>
<description>
3D area that detects [CollisionObject3D] nodes overlapping, entering, or exiting. Can also alter or override local physics parameters (gravity, damping) and route audio to custom audio buses.
+ To give the area its shape, add a [CollisionShape3D] or a [CollisionPolygon3D] node as a [i]direct[/i] child (or add multiple such nodes as direct children) of the area.
+ [b]Warning:[/b] See [ConcavePolygonShape3D] (also called "trimesh") for a warning about possibly unexpected behavior when using that shape for an area.
</description>
<tutorials>
<link title="3D Platformer Demo">https://godotengine.org/asset-library/asset/125</link>
@@ -27,7 +29,7 @@
</method>
<method name="overlaps_area" qualifiers="const">
<return type="bool" />
- <argument index="0" name="area" type="Node" />
+ <param index="0" name="area" type="Node" />
<description>
Returns [code]true[/code] if the given [Area3D] intersects or overlaps this [Area3D], [code]false[/code] otherwise.
[b]Note:[/b] The result of this test is not immediate after moving objects. For performance, list of overlaps is updated once per frame and before the physics step. Consider using signals instead.
@@ -35,11 +37,11 @@
</method>
<method name="overlaps_body" qualifiers="const">
<return type="bool" />
- <argument index="0" name="body" type="Node" />
+ <param index="0" name="body" type="Node" />
<description>
Returns [code]true[/code] if the given physics body intersects or overlaps this [Area3D], [code]false[/code] otherwise.
[b]Note:[/b] The result of this test is not immediate after moving objects. For performance, list of overlaps is updated once per frame and before the physics step. Consider using signals instead.
- The [code]body[/code] argument can either be a [PhysicsBody3D] or a [GridMap] instance. While GridMaps are not physics body themselves, they register their tiles with collision shapes as a virtual physics body.
+ The [param body] argument can either be a [PhysicsBody3D] or a [GridMap] instance. While GridMaps are not physics body themselves, they register their tiles with collision shapes as a virtual physics body.
</description>
</method>
</methods>
@@ -115,83 +117,83 @@
</members>
<signals>
<signal name="area_entered">
- <argument index="0" name="area" type="Area3D" />
+ <param index="0" name="area" type="Area3D" />
<description>
Emitted when another Area3D enters this Area3D. Requires [member monitoring] to be set to [code]true[/code].
- [code]area[/code] the other Area3D.
+ [param area] the other Area3D.
</description>
</signal>
<signal name="area_exited">
- <argument index="0" name="area" type="Area3D" />
+ <param index="0" name="area" type="Area3D" />
<description>
Emitted when another Area3D exits this Area3D. Requires [member monitoring] to be set to [code]true[/code].
- [code]area[/code] the other Area3D.
+ [param area] the other Area3D.
</description>
</signal>
<signal name="area_shape_entered">
- <argument index="0" name="area_rid" type="RID" />
- <argument index="1" name="area" type="Area3D" />
- <argument index="2" name="area_shape_index" type="int" />
- <argument index="3" name="local_shape_index" type="int" />
+ <param index="0" name="area_rid" type="RID" />
+ <param index="1" name="area" type="Area3D" />
+ <param index="2" name="area_shape_index" type="int" />
+ <param index="3" name="local_shape_index" type="int" />
<description>
Emitted when one of another Area3D's [Shape3D]s enters one of this Area3D's [Shape3D]s. Requires [member monitoring] to be set to [code]true[/code].
- [code]area_rid[/code] the [RID] of the other Area3D's [CollisionObject3D] used by the [PhysicsServer3D].
- [code]area[/code] the other Area3D.
- [code]area_shape_index[/code] the index of the [Shape3D] of the other Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]area.shape_owner_get_owner(area.shape_find_owner(area_shape_index))[/code].
- [code]local_shape_index[/code] the index of the [Shape3D] of this Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
+ [param area_rid] the [RID] of the other Area3D's [CollisionObject3D] used by the [PhysicsServer3D].
+ [param area] the other Area3D.
+ [param area_shape_index] the index of the [Shape3D] of the other Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]area.shape_owner_get_owner(area.shape_find_owner(area_shape_index))[/code].
+ [param local_shape_index] the index of the [Shape3D] of this Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
</description>
</signal>
<signal name="area_shape_exited">
- <argument index="0" name="area_rid" type="RID" />
- <argument index="1" name="area" type="Area3D" />
- <argument index="2" name="area_shape_index" type="int" />
- <argument index="3" name="local_shape_index" type="int" />
+ <param index="0" name="area_rid" type="RID" />
+ <param index="1" name="area" type="Area3D" />
+ <param index="2" name="area_shape_index" type="int" />
+ <param index="3" name="local_shape_index" type="int" />
<description>
Emitted when one of another Area3D's [Shape3D]s exits one of this Area3D's [Shape3D]s. Requires [member monitoring] to be set to [code]true[/code].
- [code]area_rid[/code] the [RID] of the other Area3D's [CollisionObject3D] used by the [PhysicsServer3D].
- [code]area[/code] the other Area3D.
- [code]area_shape_index[/code] the index of the [Shape3D] of the other Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]area.shape_owner_get_owner(area.shape_find_owner(area_shape_index))[/code].
- [code]local_shape_index[/code] the index of the [Shape3D] of this Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
+ [param area_rid] the [RID] of the other Area3D's [CollisionObject3D] used by the [PhysicsServer3D].
+ [param area] the other Area3D.
+ [param area_shape_index] the index of the [Shape3D] of the other Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]area.shape_owner_get_owner(area.shape_find_owner(area_shape_index))[/code].
+ [param local_shape_index] the index of the [Shape3D] of this Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
</description>
</signal>
<signal name="body_entered">
- <argument index="0" name="body" type="Node3D" />
+ <param index="0" name="body" type="Node3D" />
<description>
Emitted when a [PhysicsBody3D] or [GridMap] enters this Area3D. Requires [member monitoring] to be set to [code]true[/code]. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s.
- [code]body[/code] the [Node], if it exists in the tree, of the other [PhysicsBody3D] or [GridMap].
+ [param body] the [Node], if it exists in the tree, of the other [PhysicsBody3D] or [GridMap].
</description>
</signal>
<signal name="body_exited">
- <argument index="0" name="body" type="Node3D" />
+ <param index="0" name="body" type="Node3D" />
<description>
Emitted when a [PhysicsBody3D] or [GridMap] exits this Area3D. Requires [member monitoring] to be set to [code]true[/code]. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s.
- [code]body[/code] the [Node], if it exists in the tree, of the other [PhysicsBody3D] or [GridMap].
+ [param body] the [Node], if it exists in the tree, of the other [PhysicsBody3D] or [GridMap].
</description>
</signal>
<signal name="body_shape_entered">
- <argument index="0" name="body_rid" type="RID" />
- <argument index="1" name="body" type="Node3D" />
- <argument index="2" name="body_shape_index" type="int" />
- <argument index="3" name="local_shape_index" type="int" />
+ <param index="0" name="body_rid" type="RID" />
+ <param index="1" name="body" type="Node3D" />
+ <param index="2" name="body_shape_index" type="int" />
+ <param index="3" name="local_shape_index" type="int" />
<description>
Emitted when one of a [PhysicsBody3D] or [GridMap]'s [Shape3D]s enters one of this Area3D's [Shape3D]s. Requires [member monitoring] to be set to [code]true[/code]. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s.
- [code]body_rid[/code] the [RID] of the [PhysicsBody3D] or [MeshLibrary]'s [CollisionObject3D] used by the [PhysicsServer3D].
- [code]body[/code] the [Node], if it exists in the tree, of the [PhysicsBody3D] or [GridMap].
- [code]body_shape_index[/code] the index of the [Shape3D] of the [PhysicsBody3D] or [GridMap] used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code].
- [code]local_shape_index[/code] the index of the [Shape3D] of this Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
+ [param body_rid] the [RID] of the [PhysicsBody3D] or [MeshLibrary]'s [CollisionObject3D] used by the [PhysicsServer3D].
+ [param body] the [Node], if it exists in the tree, of the [PhysicsBody3D] or [GridMap].
+ [param body_shape_index] the index of the [Shape3D] of the [PhysicsBody3D] or [GridMap] used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code].
+ [param local_shape_index] the index of the [Shape3D] of this Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
</description>
</signal>
<signal name="body_shape_exited">
- <argument index="0" name="body_rid" type="RID" />
- <argument index="1" name="body" type="Node3D" />
- <argument index="2" name="body_shape_index" type="int" />
- <argument index="3" name="local_shape_index" type="int" />
+ <param index="0" name="body_rid" type="RID" />
+ <param index="1" name="body" type="Node3D" />
+ <param index="2" name="body_shape_index" type="int" />
+ <param index="3" name="local_shape_index" type="int" />
<description>
Emitted when one of a [PhysicsBody3D] or [GridMap]'s [Shape3D]s enters one of this Area3D's [Shape3D]s. Requires [member monitoring] to be set to [code]true[/code]. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s.
- [code]body_rid[/code] the [RID] of the [PhysicsBody3D] or [MeshLibrary]'s [CollisionObject3D] used by the [PhysicsServer3D].
- [code]body[/code] the [Node], if it exists in the tree, of the [PhysicsBody3D] or [GridMap].
- [code]body_shape_index[/code] the index of the [Shape3D] of the [PhysicsBody3D] or [GridMap] used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code].
- [code]local_shape_index[/code] the index of the [Shape3D] of this Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
+ [param body_rid] the [RID] of the [PhysicsBody3D] or [MeshLibrary]'s [CollisionObject3D] used by the [PhysicsServer3D].
+ [param body] the [Node], if it exists in the tree, of the [PhysicsBody3D] or [GridMap].
+ [param body_shape_index] the index of the [Shape3D] of the [PhysicsBody3D] or [GridMap] used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code].
+ [param local_shape_index] the index of the [Shape3D] of this Area3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
</description>
</signal>
</signals>
diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml
index c149cdc0e4..f6d926031d 100644
--- a/doc/classes/Array.xml
+++ b/doc/classes/Array.xml
@@ -53,70 +53,70 @@
</constructor>
<constructor name="Array">
<return type="Array" />
- <argument index="0" name="from" type="Array" />
+ <param index="0" name="from" type="Array" />
<description>
Constructs an [Array] as a copy of the given [Array].
</description>
</constructor>
<constructor name="Array">
<return type="Array" />
- <argument index="0" name="from" type="PackedByteArray" />
+ <param index="0" name="from" type="PackedByteArray" />
<description>
Constructs an array from a [PackedByteArray].
</description>
</constructor>
<constructor name="Array">
<return type="Array" />
- <argument index="0" name="from" type="PackedColorArray" />
+ <param index="0" name="from" type="PackedColorArray" />
<description>
Constructs an array from a [PackedColorArray].
</description>
</constructor>
<constructor name="Array">
<return type="Array" />
- <argument index="0" name="from" type="PackedFloat32Array" />
+ <param index="0" name="from" type="PackedFloat32Array" />
<description>
Constructs an array from a [PackedFloat32Array].
</description>
</constructor>
<constructor name="Array">
<return type="Array" />
- <argument index="0" name="from" type="PackedFloat64Array" />
+ <param index="0" name="from" type="PackedFloat64Array" />
<description>
Constructs an array from a [PackedFloat64Array].
</description>
</constructor>
<constructor name="Array">
<return type="Array" />
- <argument index="0" name="from" type="PackedInt32Array" />
+ <param index="0" name="from" type="PackedInt32Array" />
<description>
Constructs an array from a [PackedInt32Array].
</description>
</constructor>
<constructor name="Array">
<return type="Array" />
- <argument index="0" name="from" type="PackedInt64Array" />
+ <param index="0" name="from" type="PackedInt64Array" />
<description>
Constructs an array from a [PackedInt64Array].
</description>
</constructor>
<constructor name="Array">
<return type="Array" />
- <argument index="0" name="from" type="PackedStringArray" />
+ <param index="0" name="from" type="PackedStringArray" />
<description>
Constructs an array from a [PackedStringArray].
</description>
</constructor>
<constructor name="Array">
<return type="Array" />
- <argument index="0" name="from" type="PackedVector2Array" />
+ <param index="0" name="from" type="PackedVector2Array" />
<description>
Constructs an array from a [PackedVector2Array].
</description>
</constructor>
<constructor name="Array">
<return type="Array" />
- <argument index="0" name="from" type="PackedVector3Array" />
+ <param index="0" name="from" type="PackedVector3Array" />
<description>
Constructs an array from a [PackedVector3Array].
</description>
@@ -125,7 +125,7 @@
<methods>
<method name="all" qualifiers="const">
<return type="bool" />
- <argument index="0" name="method" type="Callable" />
+ <param index="0" name="method" type="Callable" />
<description>
Calls the provided [Callable] on each element in the array and returns [code]true[/code] if the [Callable] returns [code]true[/code] for [i]all[/i] elements in the array. If the [Callable] returns [code]false[/code] for one array element or more, this method returns [code]false[/code].
The callable's method should take one [Variant] parameter (the current array element) and return a boolean value.
@@ -148,7 +148,7 @@
</method>
<method name="any" qualifiers="const">
<return type="bool" />
- <argument index="0" name="method" type="Callable" />
+ <param index="0" name="method" type="Callable" />
<description>
Calls the provided [Callable] on each element in the array and returns [code]true[/code] if the [Callable] returns [code]true[/code] for [i]one or more[/i] elements in the array. If the [Callable] returns [code]false[/code] for all elements in the array, this method returns [code]false[/code].
The callable's method should take one [Variant] parameter (the current array element) and return a boolean value.
@@ -171,14 +171,14 @@
</method>
<method name="append">
<return type="void" />
- <argument index="0" name="value" type="Variant" />
+ <param index="0" name="value" type="Variant" />
<description>
Appends an element at the end of the array (alias of [method push_back]).
</description>
</method>
<method name="append_array">
<return type="void" />
- <argument index="0" name="array" type="Array" />
+ <param index="0" name="array" type="Array" />
<description>
Appends another array at the end of this array.
[codeblock]
@@ -198,20 +198,20 @@
</method>
<method name="bsearch">
<return type="int" />
- <argument index="0" name="value" type="Variant" />
- <argument index="1" name="before" type="bool" default="true" />
+ <param index="0" name="value" type="Variant" />
+ <param index="1" name="before" type="bool" default="true" />
<description>
- Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search. Optionally, a [code]before[/code] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array.
+ Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search. Optionally, a [param before] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array.
[b]Note:[/b] Calling [method bsearch] on an unsorted array results in unexpected behavior.
</description>
</method>
<method name="bsearch_custom">
<return type="int" />
- <argument index="0" name="value" type="Variant" />
- <argument index="1" name="func" type="Callable" />
- <argument index="2" name="before" type="bool" default="true" />
+ <param index="0" name="value" type="Variant" />
+ <param index="1" name="func" type="Callable" />
+ <param index="2" name="before" type="bool" default="true" />
<description>
- Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search and a custom comparison method. Optionally, a [code]before[/code] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array. The custom method receives two arguments (an element from the array and the value searched for) and must return [code]true[/code] if the first argument is less than the second, and return [code]false[/code] otherwise.
+ Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search and a custom comparison method. Optionally, a [param before] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array. The custom method receives two arguments (an element from the array and the value searched for) and must return [code]true[/code] if the first argument is less than the second, and return [code]false[/code] otherwise.
[b]Note:[/b] Calling [method bsearch_custom] on an unsorted array results in unexpected behavior.
</description>
</method>
@@ -223,22 +223,22 @@
</method>
<method name="count" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="Variant" />
+ <param index="0" name="value" type="Variant" />
<description>
Returns the number of times an element is in the array.
</description>
</method>
<method name="duplicate" qualifiers="const">
<return type="Array" />
- <argument index="0" name="deep" type="bool" default="false" />
+ <param index="0" name="deep" type="bool" default="false" />
<description>
Returns a copy of the array.
- If [code]deep[/code] is [code]true[/code], a deep copy is performed: all nested arrays and dictionaries are duplicated and will not be shared with the original array. If [code]false[/code], a shallow copy is made and references to the original nested arrays and dictionaries are kept, so that modifying a sub-array or dictionary in the copy will also impact those referenced in the source array.
+ If [param deep] is [code]true[/code], a deep copy is performed: all nested arrays and dictionaries are duplicated and will not be shared with the original array. If [code]false[/code], a shallow copy is made and references to the original nested arrays and dictionaries are kept, so that modifying a sub-array or dictionary in the copy will also impact those referenced in the source array.
</description>
</method>
<method name="erase">
<return type="void" />
- <argument index="0" name="value" type="Variant" />
+ <param index="0" name="value" type="Variant" />
<description>
Removes the first occurrence of a value from the array. If the value does not exist in the array, nothing happens. To remove an element by index, use [method remove_at] instead.
[b]Note:[/b] This method acts in-place and doesn't return a value.
@@ -247,7 +247,7 @@
</method>
<method name="fill">
<return type="void" />
- <argument index="0" name="value" type="Variant" />
+ <param index="0" name="value" type="Variant" />
<description>
Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements:
[codeblocks]
@@ -266,7 +266,7 @@
</method>
<method name="filter" qualifiers="const">
<return type="Array" />
- <argument index="0" name="method" type="Callable" />
+ <param index="0" name="method" type="Callable" />
<description>
Calls the provided [Callable] on each element in the array and returns a new array with the elements for which the method returned [code]true[/code].
The callable's method should take one [Variant] parameter (the current array element) and return a boolean value.
@@ -283,15 +283,15 @@
</method>
<method name="find" qualifiers="const">
<return type="int" />
- <argument index="0" name="what" type="Variant" />
- <argument index="1" name="from" type="int" default="0" />
+ <param index="0" name="what" type="Variant" />
+ <param index="1" name="from" type="int" default="0" />
<description>
Searches the array for a value and returns its index or [code]-1[/code] if not found. Optionally, the initial search index can be passed.
</description>
</method>
<method name="find_last" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="Variant" />
+ <param index="0" name="value" type="Variant" />
<description>
Searches the array in reverse order for a value and returns its index or [code]-1[/code] if not found.
</description>
@@ -305,7 +305,7 @@
</method>
<method name="has" qualifiers="const">
<return type="bool" />
- <argument index="0" name="value" type="Variant" />
+ <param index="0" name="value" type="Variant" />
<description>
Returns [code]true[/code] if the array contains the given value.
[codeblocks]
@@ -352,8 +352,8 @@
</method>
<method name="insert">
<return type="int" />
- <argument index="0" name="position" type="int" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="position" type="int" />
+ <param index="1" name="value" type="Variant" />
<description>
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]pos == size()[/code]).
[b]Note:[/b] This method acts in-place and doesn't return a value.
@@ -368,7 +368,7 @@
</method>
<method name="map" qualifiers="const">
<return type="Array" />
- <argument index="0" name="method" type="Callable" />
+ <param index="0" name="method" type="Callable" />
<description>
Calls the provided [Callable] for each element in the array and returns a new array filled with values returned by the method.
The callable's method should take one [Variant] parameter (the current array element) and can return any [Variant].
@@ -397,9 +397,9 @@
</method>
<method name="pop_at">
<return type="Variant" />
- <argument index="0" name="position" type="int" />
+ <param index="0" name="position" type="int" />
<description>
- Removes and returns the element of the array at index [code]position[/code]. If negative, [code]position[/code] is considered relative to the end of the array. Leaves the array untouched and returns [code]null[/code] if the array is empty or if it's accessed out of bounds. An error message is printed when the array is accessed out of bounds, but not when the array is empty.
+ Removes and returns the element of the array at index [param position]. If negative, [param position] is considered relative to the end of the array. Leaves the array untouched and returns [code]null[/code] if the array is empty or if it's accessed out of bounds. An error message is printed when the array is accessed out of bounds, but not when the array is empty.
[b]Note:[/b] On large arrays, this method can be slower than [method pop_back] as it will reindex the array's elements that are located after the removed element. The larger the array and the lower the index of the removed element, the slower [method pop_at] will be.
</description>
</method>
@@ -418,14 +418,14 @@
</method>
<method name="push_back">
<return type="void" />
- <argument index="0" name="value" type="Variant" />
+ <param index="0" name="value" type="Variant" />
<description>
Appends an element at the end of the array. See also [method push_front].
</description>
</method>
<method name="push_front">
<return type="void" />
- <argument index="0" name="value" type="Variant" />
+ <param index="0" name="value" type="Variant" />
<description>
Adds an element at the beginning of the array. See also [method push_back].
[b]Note:[/b] On large arrays, this method is much slower than [method push_back] as it will reindex all the array's elements every time it's called. The larger the array, the slower [method push_front] will be.
@@ -433,11 +433,11 @@
</method>
<method name="reduce" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="method" type="Callable" />
- <argument index="1" name="accum" type="Variant" default="null" />
+ <param index="0" name="method" type="Callable" />
+ <param index="1" name="accum" type="Variant" default="null" />
<description>
- Calls the provided [Callable] for each element in array and accumulates the result in [code]accum[/code].
- The callable's method takes two arguments: the current value of [code]accum[/code] and the current array element. If [code]accum[/code] is [code]null[/code] (default value), the iteration will start from the second element, with the first one used as initial value of [code]accum[/code].
+ Calls the provided [Callable] for each element in array and accumulates the result in [param accum].
+ The callable's method takes two arguments: the current value of [param accum] and the current array element. If [param accum] is [code]null[/code] (default value), the iteration will start from the second element, with the first one used as initial value of [param accum].
[codeblock]
func _ready():
print([1, 2, 3].reduce(sum, 10)) # Prints 16.
@@ -451,7 +451,7 @@
</method>
<method name="remove_at">
<return type="void" />
- <argument index="0" name="position" type="int" />
+ <param index="0" name="position" type="int" />
<description>
Removes an element from the array by index. If the index does not exist in the array, nothing happens. To remove an element by searching for its value, use [method erase] instead.
[b]Note:[/b] This method acts in-place and doesn't return a value.
@@ -460,7 +460,7 @@
</method>
<method name="resize">
<return type="int" />
- <argument index="0" name="size" type="int" />
+ <param index="0" name="size" type="int" />
<description>
Resizes the array to contain a different number of elements. If the array size is smaller, elements are cleared, if bigger, new elements are [code]null[/code].
</description>
@@ -473,8 +473,8 @@
</method>
<method name="rfind" qualifiers="const">
<return type="int" />
- <argument index="0" name="what" type="Variant" />
- <argument index="1" name="from" type="int" default="-1" />
+ <param index="0" name="what" type="Variant" />
+ <param index="1" name="from" type="int" default="-1" />
<description>
Searches the array in reverse order. Optionally, a start search index can be passed. If negative, the start index is considered relative to the end of the array.
</description>
@@ -493,16 +493,16 @@
</method>
<method name="slice" qualifiers="const">
<return type="Array" />
- <argument index="0" name="begin" type="int" />
- <argument index="1" name="end" type="int" default="2147483647" />
- <argument index="2" name="step" type="int" default="1" />
- <argument index="3" name="deep" type="bool" default="false" />
+ <param index="0" name="begin" type="int" />
+ <param index="1" name="end" type="int" default="2147483647" />
+ <param index="2" name="step" type="int" default="1" />
+ <param index="3" name="deep" type="bool" default="false" />
<description>
- Returns the slice of the [Array], from [code]begin[/code] (inclusive) to [code]end[/code] (exclusive), as a new [Array].
- The absolute value of [code]begin[/code] and [code]end[/code] will be clamped to the array size, so the default value for [code]end[/code] makes it slice to the size of the array by default (i.e. [code]arr.slice(1)[/code] is a shorthand for [code]arr.slice(1, arr.size())[/code]).
- If either [code]begin[/code] or [code]end[/code] are negative, they will be relative to the end of the array (i.e. [code]arr.slice(0, -2)[/code] is a shorthand for [code]arr.slice(0, arr.size() - 2)[/code]).
- If specified, [code]step[/code] is the relative index between source elements. It can be negative, then [code]begin[/code] must be higher than [code]end[/code]. For example, [code][0, 1, 2, 3, 4, 5].slice(5, 1, -2)[/code] returns [code][5, 3][/code]).
- If [code]deep[/code] is true, each element will be copied by value rather than by reference.
+ Returns the slice of the [Array], from [param begin] (inclusive) to [param end] (exclusive), as a new [Array].
+ The absolute value of [param begin] and [param end] will be clamped to the array size, so the default value for [param end] makes it slice to the size of the array by default (i.e. [code]arr.slice(1)[/code] is a shorthand for [code]arr.slice(1, arr.size())[/code]).
+ If either [param begin] or [param end] are negative, they will be relative to the end of the array (i.e. [code]arr.slice(0, -2)[/code] is a shorthand for [code]arr.slice(0, arr.size() - 2)[/code]).
+ If specified, [param step] is the relative index between source elements. It can be negative, then [param begin] must be higher than [param end]. For example, [code][0, 1, 2, 3, 4, 5].slice(5, 1, -2)[/code] returns [code][5, 3][/code]).
+ If [param deep] is true, each element will be copied by value rather than by reference.
</description>
</method>
<method name="sort">
@@ -530,7 +530,7 @@
</method>
<method name="sort_custom">
<return type="void" />
- <argument index="0" name="func" type="Callable" />
+ <param index="0" name="func" type="Callable" />
<description>
Sorts the array using a custom method. The custom method receives two arguments (a pair of elements from the array) and must return either [code]true[/code] or [code]false[/code]. For two elements [code]a[/code] and [code]b[/code], if the given method returns [code]true[/code], element [code]b[/code] will be after element [code]a[/code] in the array.
[b]Note:[/b] You cannot randomize the return value as the heapsort algorithm expects a deterministic result. Doing so will result in unexpected behavior.
@@ -560,58 +560,58 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="Array" />
+ <param index="0" name="right" type="Array" />
<description>
- Compares the left operand [Array] against the [code]right[/code] [Array]. Returns [code]true[/code] if the sizes or contents of the arrays are [i]not[/i] equal, [code]false[/code] otherwise.
+ Compares the left operand [Array] against the [param right] [Array]. Returns [code]true[/code] if the sizes or contents of the arrays are [i]not[/i] equal, [code]false[/code] otherwise.
</description>
</operator>
<operator name="operator +">
<return type="Array" />
- <argument index="0" name="right" type="Array" />
+ <param index="0" name="right" type="Array" />
<description>
- Concatenates two [Array]s together, with the [code]right[/code] [Array] being added to the end of the [Array] specified in the left operand. For example, [code][1, 2] + [3, 4][/code] results in [code][1, 2, 3, 4][/code].
+ Concatenates two [Array]s together, with the [param right] [Array] being added to the end of the [Array] specified in the left operand. For example, [code][1, 2] + [3, 4][/code] results in [code][1, 2, 3, 4][/code].
</description>
</operator>
<operator name="operator &lt;">
<return type="bool" />
- <argument index="0" name="right" type="Array" />
+ <param index="0" name="right" type="Array" />
<description>
- Performs a comparison for each index between the left operand [Array] and the [code]right[/code] [Array], considering the highest common index of both arrays for this comparison: Returns [code]true[/code] on the first occurrence of an element that is less, or [code]false[/code] if the element is greater. Note that depending on the type of data stored, this function may be recursive. If all elements are equal, it compares the length of both arrays and returns [code]false[/code] if the left operand [Array] has less elements, otherwise it returns [code]true[/code].
+ Performs a comparison for each index between the left operand [Array] and the [param right] [Array], considering the highest common index of both arrays for this comparison: Returns [code]true[/code] on the first occurrence of an element that is less, or [code]false[/code] if the element is greater. Note that depending on the type of data stored, this function may be recursive. If all elements are equal, it compares the length of both arrays and returns [code]false[/code] if the left operand [Array] has fewer elements, otherwise it returns [code]true[/code].
</description>
</operator>
<operator name="operator &lt;=">
<return type="bool" />
- <argument index="0" name="right" type="Array" />
+ <param index="0" name="right" type="Array" />
<description>
- Performs a comparison for each index between the left operand [Array] and the [code]right[/code] [Array], considering the highest common index of both arrays for this comparison: Returns [code]true[/code] on the first occurrence of an element that is less, or [code]false[/code] if the element is greater. Note that depending on the type of data stored, this function may be recursive. If all elements are equal, it compares the length of both arrays and returns [code]true[/code] if the left operand [Array] has less or the same number of elements, otherwise it returns [code]false[/code].
+ Performs a comparison for each index between the left operand [Array] and the [param right] [Array], considering the highest common index of both arrays for this comparison: Returns [code]true[/code] on the first occurrence of an element that is less, or [code]false[/code] if the element is greater. Note that depending on the type of data stored, this function may be recursive. If all elements are equal, it compares the length of both arrays and returns [code]true[/code] if the left operand [Array] has the same number of elements or fewer, otherwise it returns [code]false[/code].
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="Array" />
+ <param index="0" name="right" type="Array" />
<description>
- Compares the left operand [Array] against the [code]right[/code] [Array]. Returns [code]true[/code] if the sizes and contents of the arrays are equal, [code]false[/code] otherwise.
+ Compares the left operand [Array] against the [param right] [Array]. Returns [code]true[/code] if the sizes and contents of the arrays are equal, [code]false[/code] otherwise.
</description>
</operator>
<operator name="operator &gt;">
<return type="bool" />
- <argument index="0" name="right" type="Array" />
+ <param index="0" name="right" type="Array" />
<description>
- Performs a comparison for each index between the left operand [Array] and the [code]right[/code] [Array], considering the highest common index of both arrays for this comparison: Returns [code]true[/code] on the first occurrence of an element that is greater, or [code]false[/code] if the element is less. Note that depending on the type of data stored, this function may be recursive. If all elements are equal, it compares the length of both arrays and returns [code]true[/code] if the [code]right[/code] [Array] has more elements, otherwise it returns [code]false[/code].
+ Performs a comparison for each index between the left operand [Array] and the [param right] [Array], considering the highest common index of both arrays for this comparison: Returns [code]true[/code] on the first occurrence of an element that is greater, or [code]false[/code] if the element is less. Note that depending on the type of data stored, this function may be recursive. If all elements are equal, it compares the length of both arrays and returns [code]true[/code] if the [param right] [Array] has more elements, otherwise it returns [code]false[/code].
</description>
</operator>
<operator name="operator &gt;=">
<return type="bool" />
- <argument index="0" name="right" type="Array" />
+ <param index="0" name="right" type="Array" />
<description>
- Performs a comparison for each index between the left operand [Array] and the [code]right[/code] [Array], considering the highest common index of both arrays for this comparison: Returns [code]true[/code] on the first occurrence of an element that is greater, or [code]false[/code] if the element is less. Note that depending on the type of data stored, this function may be recursive. If all elements are equal, it compares the length of both arrays and returns [code]true[/code] if the [code]right[/code] [Array] has more or the same number of elements, otherwise it returns [code]false[/code].
+ Performs a comparison for each index between the left operand [Array] and the [param right] [Array], considering the highest common index of both arrays for this comparison: Returns [code]true[/code] on the first occurrence of an element that is greater, or [code]false[/code] if the element is less. Note that depending on the type of data stored, this function may be recursive. If all elements are equal, it compares the length of both arrays and returns [code]true[/code] if the [param right] [Array] has more or the same number of elements, otherwise it returns [code]false[/code].
</description>
</operator>
<operator name="operator []">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns a reference to the element of type [Variant] at the specified location. Arrays start at index 0. [code]index[/code] can be a zero or positive value to start from the beginning, or a negative value to start from the end. Out-of-bounds array access causes a run-time error, which will result in an error being printed and the project execution pausing if run from the editor.
+ Returns a reference to the element of type [Variant] at the specified location. Arrays start at index 0. [param index] can be a zero or positive value to start from the beginning, or a negative value to start from the end. Out-of-bounds array access causes a run-time error, which will result in an error being printed and the project execution pausing if run from the editor.
</description>
</operator>
</operators>
diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml
index f5c799d4de..c766becce2 100644
--- a/doc/classes/ArrayMesh.xml
+++ b/doc/classes/ArrayMesh.xml
@@ -52,22 +52,22 @@
<methods>
<method name="add_blend_shape">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
Adds name for a blend shape that will be added with [method add_surface_from_arrays]. Must be called before surface is added.
</description>
</method>
<method name="add_surface_from_arrays">
<return type="void" />
- <argument index="0" name="primitive" type="int" enum="Mesh.PrimitiveType" />
- <argument index="1" name="arrays" type="Array" />
- <argument index="2" name="blend_shapes" type="Array" default="[]" />
- <argument index="3" name="lods" type="Dictionary" default="{}" />
- <argument index="4" name="compress_flags" type="int" default="0" />
+ <param index="0" name="primitive" type="int" enum="Mesh.PrimitiveType" />
+ <param index="1" name="arrays" type="Array" />
+ <param index="2" name="blend_shapes" type="Array" default="[]" />
+ <param index="3" name="lods" type="Dictionary" default="{}" />
+ <param index="4" name="compress_flags" type="int" default="0" />
<description>
Creates a new surface.
- Surfaces are created to be rendered using a [code]primitive[/code], which may be any of the types defined in [enum Mesh.PrimitiveType]. (As a note, when using indices, it is recommended to only use points, lines, or triangles.) [method Mesh.get_surface_count] will become the [code]surf_idx[/code] for this new surface.
- The [code]arrays[/code] argument is an array of arrays. See [enum Mesh.ArrayType] for the values used in this array. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this function into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array (or be an exact multiple of the vertex array's length, when multiple elements of a sub-array correspond to a single vertex) or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used.
+ Surfaces are created to be rendered using a [param primitive], which may be any of the types defined in [enum Mesh.PrimitiveType]. (As a note, when using indices, it is recommended to only use points, lines, or triangles.) [method Mesh.get_surface_count] will become the [code]surf_idx[/code] for this new surface.
+ The [param arrays] argument is an array of arrays. See [enum Mesh.ArrayType] for the values used in this array. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this function into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array (or be an exact multiple of the vertex array's length, when multiple elements of a sub-array correspond to a single vertex) or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used.
</description>
</method>
<method name="clear_blend_shapes">
@@ -90,15 +90,15 @@
</method>
<method name="get_blend_shape_name" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Returns the name of the blend shape at this index.
</description>
</method>
<method name="lightmap_unwrap">
<return type="int" enum="Error" />
- <argument index="0" name="transform" type="Transform3D" />
- <argument index="1" name="texel_size" type="float" />
+ <param index="0" name="transform" type="Transform3D" />
+ <param index="1" name="texel_size" type="float" />
<description>
Will perform a UV unwrap on the [ArrayMesh] to prepare the mesh for lightmapping.
</description>
@@ -111,83 +111,83 @@
</method>
<method name="set_blend_shape_name">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="name" type="StringName" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="name" type="StringName" />
<description>
Sets the name of the blend shape at this index.
</description>
</method>
<method name="surface_find_by_name" qualifiers="const">
<return type="int" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
Returns the index of the first surface with this name held within this [ArrayMesh]. If none are found, -1 is returned.
</description>
</method>
<method name="surface_get_array_index_len" qualifiers="const">
<return type="int" />
- <argument index="0" name="surf_idx" type="int" />
+ <param index="0" name="surf_idx" type="int" />
<description>
Returns the length in indices of the index array in the requested surface (see [method add_surface_from_arrays]).
</description>
</method>
<method name="surface_get_array_len" qualifiers="const">
<return type="int" />
- <argument index="0" name="surf_idx" type="int" />
+ <param index="0" name="surf_idx" type="int" />
<description>
Returns the length in vertices of the vertex array in the requested surface (see [method add_surface_from_arrays]).
</description>
</method>
<method name="surface_get_format" qualifiers="const">
<return type="int" />
- <argument index="0" name="surf_idx" type="int" />
+ <param index="0" name="surf_idx" type="int" />
<description>
Returns the format mask of the requested surface (see [method add_surface_from_arrays]).
</description>
</method>
<method name="surface_get_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="surf_idx" type="int" />
+ <param index="0" name="surf_idx" type="int" />
<description>
Gets the name assigned to this surface.
</description>
</method>
<method name="surface_get_primitive_type" qualifiers="const">
<return type="int" enum="Mesh.PrimitiveType" />
- <argument index="0" name="surf_idx" type="int" />
+ <param index="0" name="surf_idx" type="int" />
<description>
Returns the primitive type of the requested surface (see [method add_surface_from_arrays]).
</description>
</method>
<method name="surface_set_name">
<return type="void" />
- <argument index="0" name="surf_idx" type="int" />
- <argument index="1" name="name" type="String" />
+ <param index="0" name="surf_idx" type="int" />
+ <param index="1" name="name" type="String" />
<description>
Sets a name for a given surface.
</description>
</method>
<method name="surface_update_attribute_region">
<return type="void" />
- <argument index="0" name="surf_idx" type="int" />
- <argument index="1" name="offset" type="int" />
- <argument index="2" name="data" type="PackedByteArray" />
+ <param index="0" name="surf_idx" type="int" />
+ <param index="1" name="offset" type="int" />
+ <param index="2" name="data" type="PackedByteArray" />
<description>
</description>
</method>
<method name="surface_update_skin_region">
<return type="void" />
- <argument index="0" name="surf_idx" type="int" />
- <argument index="1" name="offset" type="int" />
- <argument index="2" name="data" type="PackedByteArray" />
+ <param index="0" name="surf_idx" type="int" />
+ <param index="1" name="offset" type="int" />
+ <param index="2" name="data" type="PackedByteArray" />
<description>
</description>
</method>
<method name="surface_update_vertex_region">
<return type="void" />
- <argument index="0" name="surf_idx" type="int" />
- <argument index="1" name="offset" type="int" />
- <argument index="2" name="data" type="PackedByteArray" />
+ <param index="0" name="surf_idx" type="int" />
+ <param index="1" name="offset" type="int" />
+ <param index="2" name="data" type="PackedByteArray" />
<description>
</description>
</method>
diff --git a/doc/classes/ArrayOccluder3D.xml b/doc/classes/ArrayOccluder3D.xml
index 7f6bf93c8f..866427beeb 100644
--- a/doc/classes/ArrayOccluder3D.xml
+++ b/doc/classes/ArrayOccluder3D.xml
@@ -12,8 +12,8 @@
<methods>
<method name="set_arrays">
<return type="void" />
- <argument index="0" name="vertices" type="PackedVector3Array" />
- <argument index="1" name="indices" type="PackedInt32Array" />
+ <param index="0" name="vertices" type="PackedVector3Array" />
+ <param index="1" name="indices" type="PackedInt32Array" />
<description>
</description>
</method>
diff --git a/doc/classes/AudioEffectCapture.xml b/doc/classes/AudioEffectCapture.xml
index 8e02056456..c2a5ec3b45 100644
--- a/doc/classes/AudioEffectCapture.xml
+++ b/doc/classes/AudioEffectCapture.xml
@@ -13,9 +13,9 @@
<methods>
<method name="can_get_buffer" qualifiers="const">
<return type="bool" />
- <argument index="0" name="frames" type="int" />
+ <param index="0" name="frames" type="int" />
<description>
- Returns [code]true[/code] if at least [code]frames[/code] audio frames are available to read in the internal ring buffer.
+ Returns [code]true[/code] if at least [param frames] audio frames are available to read in the internal ring buffer.
</description>
</method>
<method name="clear_buffer">
@@ -26,10 +26,10 @@
</method>
<method name="get_buffer">
<return type="PackedVector2Array" />
- <argument index="0" name="frames" type="int" />
+ <param index="0" name="frames" type="int" />
<description>
- Gets the next [code]frames[/code] audio samples from the internal ring buffer.
- Returns a [PackedVector2Array] containing exactly [code]frames[/code] audio samples if available, or an empty [PackedVector2Array] if insufficient data was available.
+ Gets the next [param frames] audio samples from the internal ring buffer.
+ Returns a [PackedVector2Array] containing exactly [param frames] audio samples if available, or an empty [PackedVector2Array] if insufficient data was available.
</description>
</method>
<method name="get_buffer_length_frames" qualifiers="const">
diff --git a/doc/classes/AudioEffectChorus.xml b/doc/classes/AudioEffectChorus.xml
index 5efba17e6a..de168cdfb0 100644
--- a/doc/classes/AudioEffectChorus.xml
+++ b/doc/classes/AudioEffectChorus.xml
@@ -12,79 +12,79 @@
<methods>
<method name="get_voice_cutoff_hz" qualifiers="const">
<return type="float" />
- <argument index="0" name="voice_idx" type="int" />
+ <param index="0" name="voice_idx" type="int" />
<description>
</description>
</method>
<method name="get_voice_delay_ms" qualifiers="const">
<return type="float" />
- <argument index="0" name="voice_idx" type="int" />
+ <param index="0" name="voice_idx" type="int" />
<description>
</description>
</method>
<method name="get_voice_depth_ms" qualifiers="const">
<return type="float" />
- <argument index="0" name="voice_idx" type="int" />
+ <param index="0" name="voice_idx" type="int" />
<description>
</description>
</method>
<method name="get_voice_level_db" qualifiers="const">
<return type="float" />
- <argument index="0" name="voice_idx" type="int" />
+ <param index="0" name="voice_idx" type="int" />
<description>
</description>
</method>
<method name="get_voice_pan" qualifiers="const">
<return type="float" />
- <argument index="0" name="voice_idx" type="int" />
+ <param index="0" name="voice_idx" type="int" />
<description>
</description>
</method>
<method name="get_voice_rate_hz" qualifiers="const">
<return type="float" />
- <argument index="0" name="voice_idx" type="int" />
+ <param index="0" name="voice_idx" type="int" />
<description>
</description>
</method>
<method name="set_voice_cutoff_hz">
<return type="void" />
- <argument index="0" name="voice_idx" type="int" />
- <argument index="1" name="cutoff_hz" type="float" />
+ <param index="0" name="voice_idx" type="int" />
+ <param index="1" name="cutoff_hz" type="float" />
<description>
</description>
</method>
<method name="set_voice_delay_ms">
<return type="void" />
- <argument index="0" name="voice_idx" type="int" />
- <argument index="1" name="delay_ms" type="float" />
+ <param index="0" name="voice_idx" type="int" />
+ <param index="1" name="delay_ms" type="float" />
<description>
</description>
</method>
<method name="set_voice_depth_ms">
<return type="void" />
- <argument index="0" name="voice_idx" type="int" />
- <argument index="1" name="depth_ms" type="float" />
+ <param index="0" name="voice_idx" type="int" />
+ <param index="1" name="depth_ms" type="float" />
<description>
</description>
</method>
<method name="set_voice_level_db">
<return type="void" />
- <argument index="0" name="voice_idx" type="int" />
- <argument index="1" name="level_db" type="float" />
+ <param index="0" name="voice_idx" type="int" />
+ <param index="1" name="level_db" type="float" />
<description>
</description>
</method>
<method name="set_voice_pan">
<return type="void" />
- <argument index="0" name="voice_idx" type="int" />
- <argument index="1" name="pan" type="float" />
+ <param index="0" name="voice_idx" type="int" />
+ <param index="1" name="pan" type="float" />
<description>
</description>
</method>
<method name="set_voice_rate_hz">
<return type="void" />
- <argument index="0" name="voice_idx" type="int" />
- <argument index="1" name="rate_hz" type="float" />
+ <param index="0" name="voice_idx" type="int" />
+ <param index="1" name="rate_hz" type="float" />
<description>
</description>
</method>
@@ -166,7 +166,7 @@
The voice's filter rate.
</member>
<member name="voice_count" type="int" setter="set_voice_count" getter="get_voice_count" default="2">
- The amount of voices in the effect.
+ The number of voices in the effect.
</member>
<member name="wet" type="float" setter="set_wet" getter="get_wet" default="0.5">
The effect's processed signal.
diff --git a/doc/classes/AudioEffectDelay.xml b/doc/classes/AudioEffectDelay.xml
index 8223ccd6bd..b9ae12204e 100644
--- a/doc/classes/AudioEffectDelay.xml
+++ b/doc/classes/AudioEffectDelay.xml
@@ -14,40 +14,40 @@
<member name="dry" type="float" setter="set_dry" getter="get_dry" default="1.0">
Output percent of original sound. At 0, only delayed sounds are output. Value can range from 0 to 1.
</member>
- <member name="feedback/active" type="bool" setter="set_feedback_active" getter="is_feedback_active" default="false">
+ <member name="feedback_active" type="bool" setter="set_feedback_active" getter="is_feedback_active" default="false">
If [code]true[/code], feedback is enabled.
</member>
- <member name="feedback/delay_ms" type="float" setter="set_feedback_delay_ms" getter="get_feedback_delay_ms" default="340.0">
+ <member name="feedback_delay_ms" type="float" setter="set_feedback_delay_ms" getter="get_feedback_delay_ms" default="340.0">
Feedback delay time in milliseconds.
</member>
- <member name="feedback/level_db" type="float" setter="set_feedback_level_db" getter="get_feedback_level_db" default="-6.0">
+ <member name="feedback_level_db" type="float" setter="set_feedback_level_db" getter="get_feedback_level_db" default="-6.0">
Sound level for [code]tap1[/code].
</member>
- <member name="feedback/lowpass" type="float" setter="set_feedback_lowpass" getter="get_feedback_lowpass" default="16000.0">
+ <member name="feedback_lowpass" type="float" setter="set_feedback_lowpass" getter="get_feedback_lowpass" default="16000.0">
Low-pass filter for feedback, in Hz. Frequencies below this value are filtered out of the source signal.
</member>
- <member name="tap1/active" type="bool" setter="set_tap1_active" getter="is_tap1_active" default="true">
+ <member name="tap1_active" type="bool" setter="set_tap1_active" getter="is_tap1_active" default="true">
If [code]true[/code], [code]tap1[/code] will be enabled.
</member>
- <member name="tap1/delay_ms" type="float" setter="set_tap1_delay_ms" getter="get_tap1_delay_ms" default="250.0">
+ <member name="tap1_delay_ms" type="float" setter="set_tap1_delay_ms" getter="get_tap1_delay_ms" default="250.0">
[code]tap1[/code] delay time in milliseconds.
</member>
- <member name="tap1/level_db" type="float" setter="set_tap1_level_db" getter="get_tap1_level_db" default="-6.0">
+ <member name="tap1_level_db" type="float" setter="set_tap1_level_db" getter="get_tap1_level_db" default="-6.0">
Sound level for [code]tap1[/code].
</member>
- <member name="tap1/pan" type="float" setter="set_tap1_pan" getter="get_tap1_pan" default="0.2">
+ <member name="tap1_pan" type="float" setter="set_tap1_pan" getter="get_tap1_pan" default="0.2">
Pan position for [code]tap1[/code]. Value can range from -1 (fully left) to 1 (fully right).
</member>
- <member name="tap2/active" type="bool" setter="set_tap2_active" getter="is_tap2_active" default="true">
+ <member name="tap2_active" type="bool" setter="set_tap2_active" getter="is_tap2_active" default="true">
If [code]true[/code], [code]tap2[/code] will be enabled.
</member>
- <member name="tap2/delay_ms" type="float" setter="set_tap2_delay_ms" getter="get_tap2_delay_ms" default="500.0">
+ <member name="tap2_delay_ms" type="float" setter="set_tap2_delay_ms" getter="get_tap2_delay_ms" default="500.0">
[b]Tap2[/b] delay time in milliseconds.
</member>
- <member name="tap2/level_db" type="float" setter="set_tap2_level_db" getter="get_tap2_level_db" default="-12.0">
+ <member name="tap2_level_db" type="float" setter="set_tap2_level_db" getter="get_tap2_level_db" default="-12.0">
Sound level for [code]tap2[/code].
</member>
- <member name="tap2/pan" type="float" setter="set_tap2_pan" getter="get_tap2_pan" default="-0.4">
+ <member name="tap2_pan" type="float" setter="set_tap2_pan" getter="get_tap2_pan" default="-0.4">
Pan position for [code]tap2[/code]. Value can range from -1 (fully left) to 1 (fully right).
</member>
</members>
diff --git a/doc/classes/AudioEffectEQ.xml b/doc/classes/AudioEffectEQ.xml
index ce5b6de3be..6e4040c16e 100644
--- a/doc/classes/AudioEffectEQ.xml
+++ b/doc/classes/AudioEffectEQ.xml
@@ -19,15 +19,15 @@
</method>
<method name="get_band_gain_db" qualifiers="const">
<return type="float" />
- <argument index="0" name="band_idx" type="int" />
+ <param index="0" name="band_idx" type="int" />
<description>
Returns the band's gain at the specified index, in dB.
</description>
</method>
<method name="set_band_gain_db">
<return type="void" />
- <argument index="0" name="band_idx" type="int" />
- <argument index="1" name="volume_db" type="float" />
+ <param index="0" name="band_idx" type="int" />
+ <param index="1" name="volume_db" type="float" />
<description>
Sets band's gain at the specified index, in dB.
</description>
diff --git a/doc/classes/AudioEffectInstance.xml b/doc/classes/AudioEffectInstance.xml
index f50246d6ca..bc3d579f36 100644
--- a/doc/classes/AudioEffectInstance.xml
+++ b/doc/classes/AudioEffectInstance.xml
@@ -9,9 +9,9 @@
<methods>
<method name="_process" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="src_buffer" type="const void*" />
- <argument index="1" name="dst_buffer" type="AudioFrame*" />
- <argument index="2" name="frame_count" type="int" />
+ <param index="0" name="src_buffer" type="const void*" />
+ <param index="1" name="dst_buffer" type="AudioFrame*" />
+ <param index="2" name="frame_count" type="int" />
<description>
</description>
</method>
diff --git a/doc/classes/AudioEffectRecord.xml b/doc/classes/AudioEffectRecord.xml
index 32a6aea340..ff034389fc 100644
--- a/doc/classes/AudioEffectRecord.xml
+++ b/doc/classes/AudioEffectRecord.xml
@@ -27,7 +27,7 @@
</method>
<method name="set_recording_active">
<return type="void" />
- <argument index="0" name="record" type="bool" />
+ <param index="0" name="record" type="bool" />
<description>
If [code]true[/code], the sound will be recorded. Note that restarting the recording will remove the previously recorded sample.
</description>
diff --git a/doc/classes/AudioEffectSpectrumAnalyzerInstance.xml b/doc/classes/AudioEffectSpectrumAnalyzerInstance.xml
index 08dd5a5d69..55ac78f197 100644
--- a/doc/classes/AudioEffectSpectrumAnalyzerInstance.xml
+++ b/doc/classes/AudioEffectSpectrumAnalyzerInstance.xml
@@ -9,9 +9,9 @@
<methods>
<method name="get_magnitude_for_frequency_range" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="from_hz" type="float" />
- <argument index="1" name="to_hz" type="float" />
- <argument index="2" name="mode" type="int" enum="AudioEffectSpectrumAnalyzerInstance.MagnitudeMode" default="1" />
+ <param index="0" name="from_hz" type="float" />
+ <param index="1" name="to_hz" type="float" />
+ <param index="2" name="mode" type="int" enum="AudioEffectSpectrumAnalyzerInstance.MagnitudeMode" default="1" />
<description>
</description>
</method>
diff --git a/doc/classes/AudioServer.xml b/doc/classes/AudioServer.xml
index 28dcd2794e..8dc80e3bdc 100644
--- a/doc/classes/AudioServer.xml
+++ b/doc/classes/AudioServer.xml
@@ -15,22 +15,22 @@
<methods>
<method name="add_bus">
<return type="void" />
- <argument index="0" name="at_position" type="int" default="-1" />
+ <param index="0" name="at_position" type="int" default="-1" />
<description>
- Adds a bus at [code]at_position[/code].
+ Adds a bus at [param at_position].
</description>
</method>
<method name="add_bus_effect">
<return type="void" />
- <argument index="0" name="bus_idx" type="int" />
- <argument index="1" name="effect" type="AudioEffect" />
- <argument index="2" name="at_position" type="int" default="-1" />
+ <param index="0" name="bus_idx" type="int" />
+ <param index="1" name="effect" type="AudioEffect" />
+ <param index="2" name="at_position" type="int" default="-1" />
<description>
- Adds an [AudioEffect] effect to the bus [code]bus_idx[/code] at [code]at_position[/code].
+ Adds an [AudioEffect] effect to the bus [param bus_idx] at [param at_position].
</description>
</method>
<method name="capture_get_device_list">
- <return type="Array" />
+ <return type="PackedStringArray" />
<description>
Returns the names of all audio input devices detected on the system.
</description>
@@ -43,81 +43,81 @@
</method>
<method name="get_bus_channels" qualifiers="const">
<return type="int" />
- <argument index="0" name="bus_idx" type="int" />
+ <param index="0" name="bus_idx" type="int" />
<description>
- Returns the amount of channels of the bus at index [code]bus_idx[/code].
+ Returns the number of channels of the bus at index [param bus_idx].
</description>
</method>
<method name="get_bus_effect">
<return type="AudioEffect" />
- <argument index="0" name="bus_idx" type="int" />
- <argument index="1" name="effect_idx" type="int" />
+ <param index="0" name="bus_idx" type="int" />
+ <param index="1" name="effect_idx" type="int" />
<description>
- Returns the [AudioEffect] at position [code]effect_idx[/code] in bus [code]bus_idx[/code].
+ Returns the [AudioEffect] at position [param effect_idx] in bus [param bus_idx].
</description>
</method>
<method name="get_bus_effect_count">
<return type="int" />
- <argument index="0" name="bus_idx" type="int" />
+ <param index="0" name="bus_idx" type="int" />
<description>
- Returns the number of effects on the bus at [code]bus_idx[/code].
+ Returns the number of effects on the bus at [param bus_idx].
</description>
</method>
<method name="get_bus_effect_instance">
<return type="AudioEffectInstance" />
- <argument index="0" name="bus_idx" type="int" />
- <argument index="1" name="effect_idx" type="int" />
- <argument index="2" name="channel" type="int" default="0" />
+ <param index="0" name="bus_idx" type="int" />
+ <param index="1" name="effect_idx" type="int" />
+ <param index="2" name="channel" type="int" default="0" />
<description>
Returns the [AudioEffectInstance] assigned to the given bus and effect indices (and optionally channel).
</description>
</method>
<method name="get_bus_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="bus_name" type="StringName" />
+ <param index="0" name="bus_name" type="StringName" />
<description>
- Returns the index of the bus with the name [code]bus_name[/code].
+ Returns the index of the bus with the name [param bus_name].
</description>
</method>
<method name="get_bus_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="bus_idx" type="int" />
+ <param index="0" name="bus_idx" type="int" />
<description>
- Returns the name of the bus with the index [code]bus_idx[/code].
+ Returns the name of the bus with the index [param bus_idx].
</description>
</method>
<method name="get_bus_peak_volume_left_db" qualifiers="const">
<return type="float" />
- <argument index="0" name="bus_idx" type="int" />
- <argument index="1" name="channel" type="int" />
+ <param index="0" name="bus_idx" type="int" />
+ <param index="1" name="channel" type="int" />
<description>
- Returns the peak volume of the left speaker at bus index [code]bus_idx[/code] and channel index [code]channel[/code].
+ Returns the peak volume of the left speaker at bus index [param bus_idx] and channel index [param channel].
</description>
</method>
<method name="get_bus_peak_volume_right_db" qualifiers="const">
<return type="float" />
- <argument index="0" name="bus_idx" type="int" />
- <argument index="1" name="channel" type="int" />
+ <param index="0" name="bus_idx" type="int" />
+ <param index="1" name="channel" type="int" />
<description>
- Returns the peak volume of the right speaker at bus index [code]bus_idx[/code] and channel index [code]channel[/code].
+ Returns the peak volume of the right speaker at bus index [param bus_idx] and channel index [param channel].
</description>
</method>
<method name="get_bus_send" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="bus_idx" type="int" />
+ <param index="0" name="bus_idx" type="int" />
<description>
- Returns the name of the bus that the bus at index [code]bus_idx[/code] sends to.
+ Returns the name of the bus that the bus at index [param bus_idx] sends to.
</description>
</method>
<method name="get_bus_volume_db" qualifiers="const">
<return type="float" />
- <argument index="0" name="bus_idx" type="int" />
+ <param index="0" name="bus_idx" type="int" />
<description>
- Returns the volume of the bus at index [code]bus_idx[/code] in dB.
+ Returns the volume of the bus at index [param bus_idx] in dB.
</description>
</method>
<method name="get_device_list">
- <return type="Array" />
+ <return type="PackedStringArray" />
<description>
Returns the names of all audio devices detected on the system.
</description>
@@ -154,31 +154,31 @@
</method>
<method name="is_bus_bypassing_effects" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bus_idx" type="int" />
+ <param index="0" name="bus_idx" type="int" />
<description>
- If [code]true[/code], the bus at index [code]bus_idx[/code] is bypassing effects.
+ If [code]true[/code], the bus at index [param bus_idx] is bypassing effects.
</description>
</method>
<method name="is_bus_effect_enabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bus_idx" type="int" />
- <argument index="1" name="effect_idx" type="int" />
+ <param index="0" name="bus_idx" type="int" />
+ <param index="1" name="effect_idx" type="int" />
<description>
- If [code]true[/code], the effect at index [code]effect_idx[/code] on the bus at index [code]bus_idx[/code] is enabled.
+ If [code]true[/code], the effect at index [param effect_idx] on the bus at index [param bus_idx] is enabled.
</description>
</method>
<method name="is_bus_mute" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bus_idx" type="int" />
+ <param index="0" name="bus_idx" type="int" />
<description>
- If [code]true[/code], the bus at index [code]bus_idx[/code] is muted.
+ If [code]true[/code], the bus at index [param bus_idx] is muted.
</description>
</method>
<method name="is_bus_solo" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bus_idx" type="int" />
+ <param index="0" name="bus_idx" type="int" />
<description>
- If [code]true[/code], the bus at index [code]bus_idx[/code] is in solo mode.
+ If [code]true[/code], the bus at index [param bus_idx] is in solo mode.
</description>
</method>
<method name="lock">
@@ -190,104 +190,104 @@
</method>
<method name="move_bus">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="to_index" type="int" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="to_index" type="int" />
<description>
- Moves the bus from index [code]index[/code] to index [code]to_index[/code].
+ Moves the bus from index [param index] to index [param to_index].
</description>
</method>
<method name="remove_bus">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Removes the bus at index [code]index[/code].
+ Removes the bus at index [param index].
</description>
</method>
<method name="remove_bus_effect">
<return type="void" />
- <argument index="0" name="bus_idx" type="int" />
- <argument index="1" name="effect_idx" type="int" />
+ <param index="0" name="bus_idx" type="int" />
+ <param index="1" name="effect_idx" type="int" />
<description>
- Removes the effect at index [code]effect_idx[/code] from the bus at index [code]bus_idx[/code].
+ Removes the effect at index [param effect_idx] from the bus at index [param bus_idx].
</description>
</method>
<method name="set_bus_bypass_effects">
<return type="void" />
- <argument index="0" name="bus_idx" type="int" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="bus_idx" type="int" />
+ <param index="1" name="enable" type="bool" />
<description>
- If [code]true[/code], the bus at index [code]bus_idx[/code] is bypassing effects.
+ If [code]true[/code], the bus at index [param bus_idx] is bypassing effects.
</description>
</method>
<method name="set_bus_effect_enabled">
<return type="void" />
- <argument index="0" name="bus_idx" type="int" />
- <argument index="1" name="effect_idx" type="int" />
- <argument index="2" name="enabled" type="bool" />
+ <param index="0" name="bus_idx" type="int" />
+ <param index="1" name="effect_idx" type="int" />
+ <param index="2" name="enabled" type="bool" />
<description>
- If [code]true[/code], the effect at index [code]effect_idx[/code] on the bus at index [code]bus_idx[/code] is enabled.
+ If [code]true[/code], the effect at index [param effect_idx] on the bus at index [param bus_idx] is enabled.
</description>
</method>
<method name="set_bus_layout">
<return type="void" />
- <argument index="0" name="bus_layout" type="AudioBusLayout" />
+ <param index="0" name="bus_layout" type="AudioBusLayout" />
<description>
Overwrites the currently used [AudioBusLayout].
</description>
</method>
<method name="set_bus_mute">
<return type="void" />
- <argument index="0" name="bus_idx" type="int" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="bus_idx" type="int" />
+ <param index="1" name="enable" type="bool" />
<description>
- If [code]true[/code], the bus at index [code]bus_idx[/code] is muted.
+ If [code]true[/code], the bus at index [param bus_idx] is muted.
</description>
</method>
<method name="set_bus_name">
<return type="void" />
- <argument index="0" name="bus_idx" type="int" />
- <argument index="1" name="name" type="String" />
+ <param index="0" name="bus_idx" type="int" />
+ <param index="1" name="name" type="String" />
<description>
- Sets the name of the bus at index [code]bus_idx[/code] to [code]name[/code].
+ Sets the name of the bus at index [param bus_idx] to [param name].
</description>
</method>
<method name="set_bus_send">
<return type="void" />
- <argument index="0" name="bus_idx" type="int" />
- <argument index="1" name="send" type="StringName" />
+ <param index="0" name="bus_idx" type="int" />
+ <param index="1" name="send" type="StringName" />
<description>
- Connects the output of the bus at [code]bus_idx[/code] to the bus named [code]send[/code].
+ Connects the output of the bus at [param bus_idx] to the bus named [param send].
</description>
</method>
<method name="set_bus_solo">
<return type="void" />
- <argument index="0" name="bus_idx" type="int" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="bus_idx" type="int" />
+ <param index="1" name="enable" type="bool" />
<description>
- If [code]true[/code], the bus at index [code]bus_idx[/code] is in solo mode.
+ If [code]true[/code], the bus at index [param bus_idx] is in solo mode.
</description>
</method>
<method name="set_bus_volume_db">
<return type="void" />
- <argument index="0" name="bus_idx" type="int" />
- <argument index="1" name="volume_db" type="float" />
+ <param index="0" name="bus_idx" type="int" />
+ <param index="1" name="volume_db" type="float" />
<description>
- Sets the volume of the bus at index [code]bus_idx[/code] to [code]volume_db[/code].
+ Sets the volume of the bus at index [param bus_idx] to [param volume_db].
</description>
</method>
<method name="set_enable_tagging_used_audio_streams">
<return type="void" />
- <argument index="0" name="enable" type="bool" />
+ <param index="0" name="enable" type="bool" />
<description>
</description>
</method>
<method name="swap_bus_effects">
<return type="void" />
- <argument index="0" name="bus_idx" type="int" />
- <argument index="1" name="effect_idx" type="int" />
- <argument index="2" name="by_effect_idx" type="int" />
+ <param index="0" name="bus_idx" type="int" />
+ <param index="1" name="effect_idx" type="int" />
+ <param index="2" name="by_effect_idx" type="int" />
<description>
- Swaps the position of two effects in bus [code]bus_idx[/code].
+ Swaps the position of two effects in bus [param bus_idx].
</description>
</method>
<method name="unlock">
diff --git a/doc/classes/AudioStreamGeneratorPlayback.xml b/doc/classes/AudioStreamGeneratorPlayback.xml
index 06c285bff7..1c02dbd3ce 100644
--- a/doc/classes/AudioStreamGeneratorPlayback.xml
+++ b/doc/classes/AudioStreamGeneratorPlayback.xml
@@ -13,9 +13,9 @@
<methods>
<method name="can_push_buffer" qualifiers="const">
<return type="bool" />
- <argument index="0" name="amount" type="int" />
+ <param index="0" name="amount" type="int" />
<description>
- Returns [code]true[/code] if a buffer of the size [code]amount[/code] can be pushed to the audio sample data buffer without overflowing it, [code]false[/code] otherwise.
+ Returns [code]true[/code] if a buffer of the size [param amount] can be pushed to the audio sample data buffer without overflowing it, [code]false[/code] otherwise.
</description>
</method>
<method name="clear_buffer">
@@ -37,14 +37,14 @@
</method>
<method name="push_buffer">
<return type="bool" />
- <argument index="0" name="frames" type="PackedVector2Array" />
+ <param index="0" name="frames" type="PackedVector2Array" />
<description>
Pushes several audio data frames to the buffer. This is usually more efficient than [method push_frame] in C# and compiled languages via GDExtension, but [method push_buffer] may be [i]less[/i] efficient in GDScript.
</description>
</method>
<method name="push_frame">
<return type="bool" />
- <argument index="0" name="frame" type="Vector2" />
+ <param index="0" name="frame" type="Vector2" />
<description>
Pushes a single audio data frame to the buffer. This is usually less efficient than [method push_buffer] in C# and compiled languages via GDExtension, but [method push_frame] may be [i]more[/i] efficient in GDScript.
</description>
diff --git a/doc/classes/AudioStreamPlayback.xml b/doc/classes/AudioStreamPlayback.xml
index f1a1c18c1c..e80c112f16 100644
--- a/doc/classes/AudioStreamPlayback.xml
+++ b/doc/classes/AudioStreamPlayback.xml
@@ -27,21 +27,21 @@
</method>
<method name="_mix" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="buffer" type="AudioFrame*" />
- <argument index="1" name="rate_scale" type="float" />
- <argument index="2" name="frames" type="int" />
+ <param index="0" name="buffer" type="AudioFrame*" />
+ <param index="1" name="rate_scale" type="float" />
+ <param index="2" name="frames" type="int" />
<description>
</description>
</method>
<method name="_seek" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="position" type="float" />
+ <param index="0" name="position" type="float" />
<description>
</description>
</method>
<method name="_start" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="from_pos" type="float" />
+ <param index="0" name="from_pos" type="float" />
<description>
</description>
</method>
diff --git a/doc/classes/AudioStreamPlaybackResampled.xml b/doc/classes/AudioStreamPlaybackResampled.xml
index eb41e4256e..cc2268f145 100644
--- a/doc/classes/AudioStreamPlaybackResampled.xml
+++ b/doc/classes/AudioStreamPlaybackResampled.xml
@@ -14,8 +14,8 @@
</method>
<method name="_mix_resampled" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="dst_buffer" type="AudioFrame*" />
- <argument index="1" name="frame_count" type="int" />
+ <param index="0" name="dst_buffer" type="AudioFrame*" />
+ <param index="1" name="frame_count" type="int" />
<description>
</description>
</method>
diff --git a/doc/classes/AudioStreamPlayer.xml b/doc/classes/AudioStreamPlayer.xml
index e0bc98e208..06e183f4e2 100644
--- a/doc/classes/AudioStreamPlayer.xml
+++ b/doc/classes/AudioStreamPlayer.xml
@@ -30,14 +30,14 @@
</method>
<method name="play">
<return type="void" />
- <argument index="0" name="from_position" type="float" default="0.0" />
+ <param index="0" name="from_position" type="float" default="0.0" />
<description>
- Plays the audio from the given [code]from_position[/code], in seconds.
+ Plays the audio from the given [param from_position], in seconds.
</description>
</method>
<method name="seek">
<return type="void" />
- <argument index="0" name="to_position" type="float" />
+ <param index="0" name="to_position" type="float" />
<description>
Sets the position from which audio will be played, in seconds.
</description>
diff --git a/doc/classes/AudioStreamPlayer2D.xml b/doc/classes/AudioStreamPlayer2D.xml
index f04f95bd72..ae86fd0e66 100644
--- a/doc/classes/AudioStreamPlayer2D.xml
+++ b/doc/classes/AudioStreamPlayer2D.xml
@@ -4,7 +4,8 @@
Plays positional sound in 2D space.
</brief_description>
<description>
- Plays audio that dampens with distance from screen center.
+ Plays audio that dampens with distance from a given position.
+ By default, audio is heard from the screen center. This can be changed by adding an [AudioListener2D] node to the scene and enabling it by calling [method AudioListener2D.make_current] on it.
See also [AudioStreamPlayer] to play a sound non-positionally.
[b]Note:[/b] Hiding an [AudioStreamPlayer2D] node does not disable its audio output. To temporarily disable an [AudioStreamPlayer2D]'s audio output, set [member volume_db] to a very low value like [code]-100[/code] (which isn't audible to human hearing).
</description>
@@ -26,14 +27,14 @@
</method>
<method name="play">
<return type="void" />
- <argument index="0" name="from_position" type="float" default="0.0" />
+ <param index="0" name="from_position" type="float" default="0.0" />
<description>
- Plays the audio from the given position [code]from_position[/code], in seconds.
+ Plays the audio from the given position [param from_position], in seconds.
</description>
</method>
<method name="seek">
<return type="void" />
- <argument index="0" name="to_position" type="float" />
+ <param index="0" name="to_position" type="float" />
<description>
Sets the position from which audio will be played, in seconds.
</description>
diff --git a/doc/classes/AudioStreamPlayer3D.xml b/doc/classes/AudioStreamPlayer3D.xml
index 72febf7006..02192a9b7c 100644
--- a/doc/classes/AudioStreamPlayer3D.xml
+++ b/doc/classes/AudioStreamPlayer3D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Plays a sound effect with directed sound effects, dampens with distance if needed, generates effect of hearable position in space. For greater realism, a low-pass filter is automatically applied to distant sounds. This can be disabled by setting [member attenuation_filter_cutoff_hz] to [code]20500[/code].
- By default, audio is heard from the camera position. This can be changed by adding a [AudioListener3D] node to the scene and enabling it by calling [method AudioListener3D.make_current] on it.
+ By default, audio is heard from the camera position. This can be changed by adding an [AudioListener3D] node to the scene and enabling it by calling [method AudioListener3D.make_current] on it.
See also [AudioStreamPlayer] to play a sound non-positionally.
[b]Note:[/b] Hiding an [AudioStreamPlayer3D] node does not disable its audio output. To temporarily disable an [AudioStreamPlayer3D]'s audio output, set [member unit_db] to a very low value like [code]-100[/code] (which isn't audible to human hearing).
</description>
@@ -27,14 +27,14 @@
</method>
<method name="play">
<return type="void" />
- <argument index="0" name="from_position" type="float" default="0.0" />
+ <param index="0" name="from_position" type="float" default="0.0" />
<description>
- Plays the audio from the given position [code]from_position[/code], in seconds.
+ Plays the audio from the given position [param from_position], in seconds.
</description>
</method>
<method name="seek">
<return type="void" />
- <argument index="0" name="to_position" type="float" />
+ <param index="0" name="to_position" type="float" />
<description>
Sets the position from which audio will be played, in seconds.
</description>
diff --git a/doc/classes/AudioStreamRandomizer.xml b/doc/classes/AudioStreamRandomizer.xml
index 0eb733582a..5490770b7d 100644
--- a/doc/classes/AudioStreamRandomizer.xml
+++ b/doc/classes/AudioStreamRandomizer.xml
@@ -11,52 +11,52 @@
<methods>
<method name="add_stream">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Insert a stream at the specified index.
</description>
</method>
<method name="get_stream" qualifiers="const">
<return type="AudioStream" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Returns the stream at the specified index.
</description>
</method>
<method name="get_stream_probability_weight" qualifiers="const">
<return type="float" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Returns the probability weight associated with the stream at the given index.
</description>
</method>
<method name="move_stream">
<return type="void" />
- <argument index="0" name="index_from" type="int" />
- <argument index="1" name="index_to" type="int" />
+ <param index="0" name="index_from" type="int" />
+ <param index="1" name="index_to" type="int" />
<description>
Move a stream from one index to another.
</description>
</method>
<method name="remove_stream">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Remove the stream at the specified index.
</description>
</method>
<method name="set_stream">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="stream" type="AudioStream" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="stream" type="AudioStream" />
<description>
Set the AudioStream at the specified index.
</description>
</method>
<method name="set_stream_probability_weight">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="weight" type="float" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="weight" type="float" />
<description>
Set the probability weight of the stream at the specified index. The higher this value, the more likely that the randomizer will choose this stream during random playback modes.
</description>
diff --git a/doc/classes/AudioStreamWAV.xml b/doc/classes/AudioStreamWAV.xml
index 17595aec2f..9f057dfa45 100644
--- a/doc/classes/AudioStreamWAV.xml
+++ b/doc/classes/AudioStreamWAV.xml
@@ -12,10 +12,10 @@
<methods>
<method name="save_to_wav">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
- Saves the AudioStreamWAV as a WAV file to [code]path[/code]. Samples with IMA ADPCM format can't be saved.
- [b]Note:[/b] A [code].wav[/code] extension is automatically appended to [code]path[/code] if it is missing.
+ Saves the AudioStreamWAV as a WAV file to [param path]. Samples with IMA ADPCM format can't be saved.
+ [b]Note:[/b] A [code].wav[/code] extension is automatically appended to [param path] if it is missing.
</description>
</method>
</methods>
diff --git a/doc/classes/BaseButton.xml b/doc/classes/BaseButton.xml
index 13fe75a3e3..629675132a 100644
--- a/doc/classes/BaseButton.xml
+++ b/doc/classes/BaseButton.xml
@@ -17,7 +17,7 @@
</method>
<method name="_toggled" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="button_pressed" type="bool" />
+ <param index="0" name="button_pressed" type="bool" />
<description>
Called when the button is toggled (only if [member toggle_mode] is active).
</description>
@@ -36,7 +36,7 @@
</method>
<method name="set_pressed_no_signal">
<return type="void" />
- <argument index="0" name="pressed" type="bool" />
+ <param index="0" name="pressed" type="bool" />
<description>
Changes the [member button_pressed] state of the button, without emitting [signal toggled]. Use when you just want to change the state of the button without sending the pressed event (e.g. when initializing scene). Only works if [member toggle_mode] is [code]true[/code].
[b]Note:[/b] This method doesn't unpress other buttons in [member button_group].
@@ -96,9 +96,9 @@
</description>
</signal>
<signal name="toggled">
- <argument index="0" name="button_pressed" type="bool" />
+ <param index="0" name="button_pressed" type="bool" />
<description>
- Emitted when the button was just toggled between pressed and normal states (only if [member toggle_mode] is active). The new state is contained in the [code]button_pressed[/code] argument.
+ Emitted when the button was just toggled between pressed and normal states (only if [member toggle_mode] is active). The new state is contained in the [param button_pressed] argument.
</description>
</signal>
</signals>
diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml
index b3cea7217e..2262c4fe47 100644
--- a/doc/classes/BaseMaterial3D.xml
+++ b/doc/classes/BaseMaterial3D.xml
@@ -12,47 +12,47 @@
<methods>
<method name="get_feature" qualifiers="const">
<return type="bool" />
- <argument index="0" name="feature" type="int" enum="BaseMaterial3D.Feature" />
+ <param index="0" name="feature" type="int" enum="BaseMaterial3D.Feature" />
<description>
Returns [code]true[/code], if the specified [enum Feature] is enabled.
</description>
</method>
<method name="get_flag" qualifiers="const">
<return type="bool" />
- <argument index="0" name="flag" type="int" enum="BaseMaterial3D.Flags" />
+ <param index="0" name="flag" type="int" enum="BaseMaterial3D.Flags" />
<description>
Returns [code]true[/code], if the specified flag is enabled. See [enum Flags] enumerator for options.
</description>
</method>
<method name="get_texture" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="param" type="int" enum="BaseMaterial3D.TextureParam" />
+ <param index="0" name="param" type="int" enum="BaseMaterial3D.TextureParam" />
<description>
Returns the [Texture] associated with the specified [enum TextureParam].
</description>
</method>
<method name="set_feature">
<return type="void" />
- <argument index="0" name="feature" type="int" enum="BaseMaterial3D.Feature" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="feature" type="int" enum="BaseMaterial3D.Feature" />
+ <param index="1" name="enable" type="bool" />
<description>
If [code]true[/code], enables the specified [enum Feature]. Many features that are available in [BaseMaterial3D]s need to be enabled before use. This way the cost for using the feature is only incurred when specified. Features can also be enabled by setting the corresponding member to [code]true[/code].
</description>
</method>
<method name="set_flag">
<return type="void" />
- <argument index="0" name="flag" type="int" enum="BaseMaterial3D.Flags" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="flag" type="int" enum="BaseMaterial3D.Flags" />
+ <param index="1" name="enable" type="bool" />
<description>
If [code]true[/code], enables the specified flag. Flags are optional behavior that can be turned on and off. Only one flag can be enabled at a time with this function, the flag enumerators cannot be bit-masked together to enable or disable multiple flags at once. Flags can also be enabled by setting the corresponding member to [code]true[/code]. See [enum Flags] enumerator for options.
</description>
</method>
<method name="set_texture">
<return type="void" />
- <argument index="0" name="param" type="int" enum="BaseMaterial3D.TextureParam" />
- <argument index="1" name="texture" type="Texture2D" />
+ <param index="0" name="param" type="int" enum="BaseMaterial3D.TextureParam" />
+ <param index="1" name="texture" type="Texture2D" />
<description>
- Sets the texture for the slot specified by [code]param[/code]. See [enum TextureParam] for available slots.
+ Sets the texture for the slot specified by [param param]. See [enum TextureParam] for available slots.
</description>
</method>
</methods>
@@ -82,7 +82,7 @@
The hashing scale for Alpha Hash. Recommended values between [code]0[/code] and [code]2[/code].
</member>
<member name="alpha_scissor_threshold" type="float" setter="set_alpha_scissor_threshold" getter="get_alpha_scissor_threshold">
- Threshold at which the alpha scissor will discard values.
+ Threshold at which the alpha scissor will discard values. Higher values will result in more pixels being discarded. If the material becomes too opaque at a distance, try increasing [member alpha_scissor_threshold]. If the material disappears at a distance, try decreasing [member alpha_scissor_threshold].
</member>
<member name="anisotropy" type="float" setter="set_anisotropy" getter="get_anisotropy" default="0.0">
The strength of the anisotropy effect. This is multiplied by [member anisotropy_flowmap]'s alpha channel if a texture is defined there and the texture contains an alpha channel.
@@ -218,30 +218,44 @@
Grows object vertices in the direction of their normals.
</member>
<member name="heightmap_deep_parallax" type="bool" setter="set_heightmap_deep_parallax" getter="is_heightmap_deep_parallax_enabled" default="false">
+ If [code]true[/code], uses parallax occlusion mapping to represent depth in the material instead of simple offset mapping (see [member heightmap_enabled]). This results in a more convincing depth effect, but is much more expensive on the GPU. Only enable this on materials where it makes a significant visual difference.
</member>
<member name="heightmap_enabled" type="bool" setter="set_feature" getter="get_feature" default="false">
- If [code]true[/code], height mapping is enabled (also called "parallax mapping" or "depth mapping"). See also [member normal_enabled].
+ If [code]true[/code], height mapping is enabled (also called "parallax mapping" or "depth mapping"). See also [member normal_enabled]. Height mapping is a demanding feature on the GPU, so it should only be used on materials where it makes a significant visual difference.
[b]Note:[/b] Height mapping is not supported if triplanar mapping is used on the same material. The value of [member heightmap_enabled] will be ignored if [member uv1_triplanar] is enabled.
</member>
<member name="heightmap_flip_binormal" type="bool" setter="set_heightmap_deep_parallax_flip_binormal" getter="get_heightmap_deep_parallax_flip_binormal" default="false">
+ If [code]true[/code], flips the mesh's binormal vectors when interpreting the height map. If the heightmap effect looks strange when the camera moves (even with a reasonable [member heightmap_scale]), try setting this to [code]true[/code].
</member>
<member name="heightmap_flip_tangent" type="bool" setter="set_heightmap_deep_parallax_flip_tangent" getter="get_heightmap_deep_parallax_flip_tangent" default="false">
+ If [code]true[/code], flips the mesh's tangent vectors when interpreting the height map. If the heightmap effect looks strange when the camera moves (even with a reasonable [member heightmap_scale]), try setting this to [code]true[/code].
</member>
<member name="heightmap_flip_texture" type="bool" setter="set_flag" getter="get_flag" default="false">
+ If [code]true[/code], interprets the height map texture as a depth map, with brighter values appearing to be "lower" in altitude compared to darker values.
+ This can be enabled for compatibility with some materials authored for Godot 3.x. This is not necessary if the Invert import option was used to invert the depth map in Godot 3.x, in which case [member heightmap_flip_texture] should remain [code]false[/code].
</member>
<member name="heightmap_max_layers" type="int" setter="set_heightmap_deep_parallax_max_layers" getter="get_heightmap_deep_parallax_max_layers">
+ The number of layers to use for parallax occlusion mapping when the camera is up close to the material. Higher values result in a more convincing depth effect, especially in materials that have steep height changes. Higher values have a significant cost on the GPU, so it should only be increased on materials where it makes a significant visual difference.
+ [b]Note:[/b] Only effective if [member heightmap_deep_parallax] is [code]true[/code].
</member>
<member name="heightmap_min_layers" type="int" setter="set_heightmap_deep_parallax_min_layers" getter="get_heightmap_deep_parallax_min_layers">
+ The number of layers to use for parallax occlusion mapping when the camera is far away from the material. Higher values result in a more convincing depth effect, especially in materials that have steep height changes. Higher values have a significant cost on the GPU, so it should only be increased on materials where it makes a significant visual difference.
+ [b]Note:[/b] Only effective if [member heightmap_deep_parallax] is [code]true[/code].
</member>
- <member name="heightmap_scale" type="float" setter="set_heightmap_scale" getter="get_heightmap_scale" default="0.05">
+ <member name="heightmap_scale" type="float" setter="set_heightmap_scale" getter="get_heightmap_scale" default="5.0">
+ The heightmap scale to use for the parallax effect (see [member heightmap_enabled]). The default value is tuned so that the highest point (value = 255) appears to be 5 cm higher than the lowest point (value = 0). Higher values result in a deeper appearance, but may result in artifacts appearing when looking at the material from oblique angles, especially when the camera moves. Negative values can be used to invert the parallax effect, but this is different from inverting the texture using [member heightmap_flip_texture] as the material will also appear to be "closer" to the camera. In most cases, [member heightmap_scale] should be kept to a positive value.
+ [b]Note:[/b] If the height map effect looks strange regardless of this value, try adjusting [member heightmap_flip_binormal] and [member heightmap_flip_tangent]. See also [member heightmap_texture] for recommendations on authoring heightmap textures, as the way the heightmap texture is authored affects how [member heightmap_scale] behaves.
</member>
<member name="heightmap_texture" type="Texture2D" setter="set_texture" getter="get_texture">
+ The texture to use as a height map. See also [member heightmap_enabled].
+ For best results, the texture should be normalized (with [member heightmap_scale] reduced to compensate). In [url=https://gimp.org]GIMP[/url], this can be done using [b]Colors &gt; Auto &gt; Equalize[/b]. If the texture only uses a small part of its available range, the parallax effect may look strange, especially when the camera moves.
+ [b]Note:[/b] To reduce memory usage and improve loading times, you may be able to use a lower-resolution heightmap texture as most heightmaps are only comprised of low-frequency data.
</member>
<member name="metallic" type="float" setter="set_metallic" getter="get_metallic" default="0.0">
A high value makes the material appear more like a metal. Non-metals use their albedo as the diffuse color and add diffuse to the specular reflection. With non-metals, the reflection appears on top of the albedo color. Metals use their albedo as a multiplier to the specular reflection and set the diffuse color to black resulting in a tinted reflection. Materials work better when fully metal or fully non-metal, values between [code]0[/code] and [code]1[/code] should only be used for blending between metal and non-metal sections. To alter the amount of reflection use [member roughness].
</member>
<member name="metallic_specular" type="float" setter="set_specular" getter="get_specular" default="0.5">
- Sets the size of the specular lobe. The specular lobe is the bright spot that is reflected from light sources.
+ Adjusts the strength of specular reflections. Specular reflections are composed of scene reflections and the specular lobe which is the bright spot that is reflected from light sources. When set to [code]0.0[/code], no specular reflections will be visible. This differs from the [constant SPECULAR_DISABLED] [enum SpecularMode] as [constant SPECULAR_DISABLED] only applies to the specular lobe from the light source.
[b]Note:[/b] Unlike [member metallic], this is not energy-conserving, so it should be left at [code]0.5[/code] in most cases. See also [member roughness].
</member>
<member name="metallic_texture" type="Texture2D" setter="set_texture" getter="get_texture">
@@ -384,6 +398,7 @@
</member>
<member name="uv1_triplanar_sharpness" type="float" setter="set_uv1_triplanar_blend_sharpness" getter="get_uv1_triplanar_blend_sharpness" default="1.0">
A lower number blends the texture more softly while a higher number blends the texture more sharply.
+ [b]Note:[/b] [member uv1_triplanar_sharpness] is clamped between [code]0.0[/code] and [code]150.0[/code] (inclusive) as values outside that range can look broken depending on the mesh.
</member>
<member name="uv1_world_triplanar" type="bool" setter="set_flag" getter="get_flag" default="false">
If [code]true[/code], triplanar mapping for [code]UV[/code] is calculated in world space rather than object local space. See also [member uv1_triplanar].
@@ -399,6 +414,7 @@
</member>
<member name="uv2_triplanar_sharpness" type="float" setter="set_uv2_triplanar_blend_sharpness" getter="get_uv2_triplanar_blend_sharpness" default="1.0">
A lower number blends the texture more softly while a higher number blends the texture more sharply.
+ [b]Note:[/b] [member uv2_triplanar_sharpness] is clamped between [code]0.0[/code] and [code]150.0[/code] (inclusive) as values outside that range can look broken depending on the mesh.
</member>
<member name="uv2_world_triplanar" type="bool" setter="set_flag" getter="get_flag" default="false">
If [code]true[/code], triplanar mapping for [code]UV2[/code] is calculated in world space rather than object local space. See also [member uv2_triplanar].
@@ -482,10 +498,10 @@
The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps. Use this for most cases as mipmaps are important to smooth out pixels that are far from the camera.
</constant>
<constant name="TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC" value="4" enum="TextureFilter">
- The texture filter reads from the nearest pixel, but selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera.
+ The texture filter reads from the nearest pixel, but selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
</constant>
<constant name="TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC" value="5" enum="TextureFilter">
- The texture filter blends between the nearest 4 pixels and selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. This is the slowest of the filtering options, but results in the highest quality texturing.
+ The texture filter blends between the nearest 4 pixels and selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. This is the slowest of the filtering options, but results in the highest quality texturing. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
</constant>
<constant name="TEXTURE_FILTER_MAX" value="6" enum="TextureFilter">
Represents the size of the [enum TextureFilter] enum.
@@ -702,7 +718,7 @@
</constant>
<constant name="BILLBOARD_PARTICLES" value="3" enum="BillboardMode">
Used for particle systems when assigned to [GPUParticles3D] and [CPUParticles3D] nodes. Enables [code]particles_anim_*[/code] properties.
- The [member ParticlesMaterial.anim_speed_min] or [member CPUParticles3D.anim_speed_min] should also be set to a value bigger than zero for the animation to play.
+ The [member ParticleProcessMaterial.anim_speed_min] or [member CPUParticles3D.anim_speed_min] should also be set to a value bigger than zero for the animation to play.
</constant>
<constant name="TEXTURE_CHANNEL_RED" value="0" enum="TextureChannel">
Used to read from the red channel of a texture.
diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml
index 0af482d654..d62f704528 100644
--- a/doc/classes/Basis.xml
+++ b/doc/classes/Basis.xml
@@ -27,31 +27,31 @@
</constructor>
<constructor name="Basis">
<return type="Basis" />
- <argument index="0" name="from" type="Basis" />
+ <param index="0" name="from" type="Basis" />
<description>
Constructs a [Basis] as a copy of the given [Basis].
</description>
</constructor>
<constructor name="Basis">
<return type="Basis" />
- <argument index="0" name="axis" type="Vector3" />
- <argument index="1" name="angle" type="float" />
+ <param index="0" name="axis" type="Vector3" />
+ <param index="1" name="angle" type="float" />
<description>
- Constructs a pure rotation basis matrix, rotated around the given [code]axis[/code] by [code]angle[/code] (in radians). The axis must be a normalized vector.
+ Constructs a pure rotation basis matrix, rotated around the given [param axis] by [param angle] (in radians). The axis must be a normalized vector.
</description>
</constructor>
<constructor name="Basis">
<return type="Basis" />
- <argument index="0" name="from" type="Quaternion" />
+ <param index="0" name="from" type="Quaternion" />
<description>
Constructs a pure rotation basis matrix from the given quaternion.
</description>
</constructor>
<constructor name="Basis">
<return type="Basis" />
- <argument index="0" name="x_axis" type="Vector3" />
- <argument index="1" name="y_axis" type="Vector3" />
- <argument index="2" name="z_axis" type="Vector3" />
+ <param index="0" name="x_axis" type="Vector3" />
+ <param index="1" name="y_axis" type="Vector3" />
+ <param index="2" name="z_axis" type="Vector3" />
<description>
Constructs a basis matrix from 3 axis vectors (matrix columns).
</description>
@@ -67,32 +67,26 @@
</method>
<method name="from_euler" qualifiers="static">
<return type="Basis" />
- <argument index="0" name="euler" type="Vector3" />
- <argument index="1" name="order" type="int" default="2" />
+ <param index="0" name="euler" type="Vector3" />
+ <param index="1" name="order" type="int" default="2" />
<description>
</description>
</method>
<method name="from_scale" qualifiers="static">
<return type="Basis" />
- <argument index="0" name="scale" type="Vector3" />
+ <param index="0" name="scale" type="Vector3" />
<description>
Constructs a pure scale basis matrix with no rotation or shearing. The scale values are set as the diagonal of the matrix, and the other parts of the matrix are zero.
</description>
</method>
<method name="get_euler" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="order" type="int" default="2" />
+ <param index="0" name="order" type="int" default="2" />
<description>
Returns the basis's rotation in the form of Euler angles (in the YXZ convention: when decomposing, first Z, then X, and Y last). The returned vector contains the rotation angles in the format (X angle, Y angle, Z angle).
Consider using the [method get_rotation_quaternion] method instead, which returns a [Quaternion] quaternion instead of Euler angles.
</description>
</method>
- <method name="get_orthogonal_index" qualifiers="const">
- <return type="int" />
- <description>
- This function considers a discretization of rotations into 24 points on unit sphere, lying along the vectors (x,y,z) with each component being either -1, 0, or 1, and returns the index of the point best representing the orientation of the object. It is mainly used by the [GridMap] editor. For further details, refer to the Godot source code.
- </description>
- </method>
<method name="get_rotation_quaternion" qualifiers="const">
<return type="Quaternion" />
<description>
@@ -113,18 +107,18 @@
</method>
<method name="is_equal_approx" qualifiers="const">
<return type="bool" />
- <argument index="0" name="b" type="Basis" />
+ <param index="0" name="b" type="Basis" />
<description>
- Returns [code]true[/code] if this basis and [code]b[/code] are approximately equal, by calling [code]is_equal_approx[/code] on each component.
+ Returns [code]true[/code] if this basis and [param b] are approximately equal, by calling [code]is_equal_approx[/code] on each component.
</description>
</method>
<method name="looking_at" qualifiers="static">
<return type="Basis" />
- <argument index="0" name="target" type="Vector3" />
- <argument index="1" name="up" type="Vector3" default="Vector3(0, 1, 0)" />
+ <param index="0" name="target" type="Vector3" />
+ <param index="1" name="up" type="Vector3" default="Vector3(0, 1, 0)" />
<description>
- Creates a Basis with a rotation such that the forward axis (-Z) points towards the [code]target[/code] position.
- The up axis (+Y) points as close to the [code]up[/code] vector as possible while staying perpendicular to the forward axis. The resulting Basis is orthonormalized. The [code]target[/code] and [code]up[/code] vectors cannot be zero, and cannot be parallel to each other.
+ Creates a Basis with a rotation such that the forward axis (-Z) points towards the [param target] position.
+ The up axis (+Y) points as close to the [param up] vector as possible while staying perpendicular to the forward axis. The resulting Basis is orthonormalized. The [param target] and [param up] vectors cannot be zero, and cannot be parallel to each other.
</description>
</method>
<method name="orthonormalized" qualifiers="const">
@@ -135,44 +129,44 @@
</method>
<method name="rotated" qualifiers="const">
<return type="Basis" />
- <argument index="0" name="axis" type="Vector3" />
- <argument index="1" name="angle" type="float" />
+ <param index="0" name="axis" type="Vector3" />
+ <param index="1" name="angle" type="float" />
<description>
- Introduce an additional rotation around the given axis by [code]angle[/code] (in radians). The axis must be a normalized vector.
+ Introduce an additional rotation around the given axis by [param angle] (in radians). The axis must be a normalized vector.
</description>
</method>
<method name="scaled" qualifiers="const">
<return type="Basis" />
- <argument index="0" name="scale" type="Vector3" />
+ <param index="0" name="scale" type="Vector3" />
<description>
Introduce an additional scaling specified by the given 3D scaling factor.
</description>
</method>
<method name="slerp" qualifiers="const">
<return type="Basis" />
- <argument index="0" name="to" type="Basis" />
- <argument index="1" name="weight" type="float" />
+ <param index="0" name="to" type="Basis" />
+ <param index="1" name="weight" type="float" />
<description>
Assuming that the matrix is a proper rotation matrix, slerp performs a spherical-linear interpolation with another rotation matrix.
</description>
</method>
<method name="tdotx" qualifiers="const">
<return type="float" />
- <argument index="0" name="with" type="Vector3" />
+ <param index="0" name="with" type="Vector3" />
<description>
Transposed dot product with the X axis of the matrix.
</description>
</method>
<method name="tdoty" qualifiers="const">
<return type="float" />
- <argument index="0" name="with" type="Vector3" />
+ <param index="0" name="with" type="Vector3" />
<description>
Transposed dot product with the Y axis of the matrix.
</description>
</method>
<method name="tdotz" qualifiers="const">
<return type="float" />
- <argument index="0" name="with" type="Vector3" />
+ <param index="0" name="with" type="Vector3" />
<description>
Transposed dot product with the Z axis of the matrix.
</description>
@@ -225,7 +219,7 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="Basis" />
+ <param index="0" name="right" type="Basis" />
<description>
Returns [code]true[/code] if the [Basis] matrices are not equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
@@ -233,35 +227,35 @@
</operator>
<operator name="operator *">
<return type="Basis" />
- <argument index="0" name="right" type="Basis" />
+ <param index="0" name="right" type="Basis" />
<description>
Composes these two basis matrices by multiplying them together. This has the effect of transforming the second basis (the child) by the first basis (the parent).
</description>
</operator>
<operator name="operator *">
<return type="Vector3" />
- <argument index="0" name="right" type="Vector3" />
+ <param index="0" name="right" type="Vector3" />
<description>
Transforms (multiplies) the [Vector3] by the given [Basis] matrix.
</description>
</operator>
<operator name="operator *">
<return type="Basis" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
This operator multiplies all components of the [Basis], which scales it uniformly.
</description>
</operator>
<operator name="operator *">
<return type="Basis" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
This operator multiplies all components of the [Basis], which scales it uniformly.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="Basis" />
+ <param index="0" name="right" type="Basis" />
<description>
Returns [code]true[/code] if the [Basis] matrices are exactly equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
@@ -269,7 +263,7 @@
</operator>
<operator name="operator []">
<return type="Vector3" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Access basis components using their index. [code]b[0][/code] is equivalent to [code]b.x[/code], [code]b[1][/code] is equivalent to [code]b.y[/code], and [code]b[2][/code] is equivalent to [code]b.z[/code].
</description>
diff --git a/doc/classes/BitMap.xml b/doc/classes/BitMap.xml
index f248bec15f..9323642274 100644
--- a/doc/classes/BitMap.xml
+++ b/doc/classes/BitMap.xml
@@ -17,22 +17,22 @@
</method>
<method name="create">
<return type="void" />
- <argument index="0" name="size" type="Vector2" />
+ <param index="0" name="size" type="Vector2" />
<description>
Creates a bitmap with the specified size, filled with [code]false[/code].
</description>
</method>
<method name="create_from_image_alpha">
<return type="void" />
- <argument index="0" name="image" type="Image" />
- <argument index="1" name="threshold" type="float" default="0.1" />
+ <param index="0" name="image" type="Image" />
+ <param index="1" name="threshold" type="float" default="0.1" />
<description>
- Creates a bitmap that matches the given image dimensions, every element of the bitmap is set to [code]false[/code] if the alpha value of the image at that position is equal to [code]threshold[/code] or less, and [code]true[/code] in other case.
+ Creates a bitmap that matches the given image dimensions, every element of the bitmap is set to [code]false[/code] if the alpha value of the image at that position is equal to [param threshold] or less, and [code]true[/code] in other case.
</description>
</method>
<method name="get_bit" qualifiers="const">
<return type="bool" />
- <argument index="0" name="position" type="Vector2" />
+ <param index="0" name="position" type="Vector2" />
<description>
Returns bitmap's value at the specified position.
</description>
@@ -46,49 +46,49 @@
<method name="get_true_bit_count" qualifiers="const">
<return type="int" />
<description>
- Returns the amount of bitmap elements that are set to [code]true[/code].
+ Returns the number of bitmap elements that are set to [code]true[/code].
</description>
</method>
<method name="grow_mask">
<return type="void" />
- <argument index="0" name="pixels" type="int" />
- <argument index="1" name="rect" type="Rect2" />
+ <param index="0" name="pixels" type="int" />
+ <param index="1" name="rect" type="Rect2" />
<description>
- Applies morphological dilation or erosion to the bitmap. If [code]pixels[/code] is positive, dilation is applied to the bitmap. If [code]pixels[/code] is negative, erosion is applied to the bitmap. [code]rect[/code] defines the area where the morphological operation is applied. Pixels located outside the [code]rect[/code] are unaffected by [method grow_mask].
+ Applies morphological dilation or erosion to the bitmap. If [param pixels] is positive, dilation is applied to the bitmap. If [param pixels] is negative, erosion is applied to the bitmap. [param rect] defines the area where the morphological operation is applied. Pixels located outside the [param rect] are unaffected by [method grow_mask].
</description>
</method>
<method name="opaque_to_polygons" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="rect" type="Rect2" />
- <argument index="1" name="epsilon" type="float" default="2.0" />
+ <return type="PackedVector2Array[]" />
+ <param index="0" name="rect" type="Rect2" />
+ <param index="1" name="epsilon" type="float" default="2.0" />
<description>
Creates an [Array] of polygons covering a rectangular portion of the bitmap. It uses a marching squares algorithm, followed by Ramer-Douglas-Peucker (RDP) reduction of the number of vertices. Each polygon is described as a [PackedVector2Array] of its vertices.
To get polygons covering the whole bitmap, pass:
[codeblock]
Rect2(Vector2(), get_size())
[/codeblock]
- [code]epsilon[/code] is passed to RDP to control how accurately the polygons cover the bitmap: a lower [code]epsilon[/code] corresponds to more points in the polygons.
+ [param epsilon] is passed to RDP to control how accurately the polygons cover the bitmap: a lower [param epsilon] corresponds to more points in the polygons.
</description>
</method>
<method name="resize">
<return type="void" />
- <argument index="0" name="new_size" type="Vector2" />
+ <param index="0" name="new_size" type="Vector2" />
<description>
- Resizes the image to [code]new_size[/code].
+ Resizes the image to [param new_size].
</description>
</method>
<method name="set_bit">
<return type="void" />
- <argument index="0" name="position" type="Vector2" />
- <argument index="1" name="bit" type="bool" />
+ <param index="0" name="position" type="Vector2" />
+ <param index="1" name="bit" type="bool" />
<description>
Sets the bitmap's element at the specified position, to the specified value.
</description>
</method>
<method name="set_bit_rect">
<return type="void" />
- <argument index="0" name="rect" type="Rect2" />
- <argument index="1" name="bit" type="bool" />
+ <param index="0" name="rect" type="Rect2" />
+ <param index="1" name="bit" type="bool" />
<description>
Sets a rectangular portion of the bitmap to the specified value.
</description>
diff --git a/doc/classes/Bone2D.xml b/doc/classes/Bone2D.xml
index 1e09e90d4a..d452edd1aa 100644
--- a/doc/classes/Bone2D.xml
+++ b/doc/classes/Bone2D.xml
@@ -57,14 +57,14 @@
</method>
<method name="set_autocalculate_length_and_angle">
<return type="void" />
- <argument index="0" name="auto_calculate" type="bool" />
+ <param index="0" name="auto_calculate" type="bool" />
<description>
When set to [code]true[/code], the [code]Bone2D[/code] node will attempt to automatically calculate the bone angle and length using the first child [code]Bone2D[/code] node, if one exists. If none exist, the [code]Bone2D[/code] cannot automatically calculate these values and will print a warning.
</description>
</method>
<method name="set_bone_angle">
<return type="void" />
- <argument index="0" name="angle" type="float" />
+ <param index="0" name="angle" type="float" />
<description>
Sets the bone angle for the [code]Bone2D[/code] node. This is typically set to the rotation from the [code]Bone2D[/code] node to a child [code]Bone2D[/code] node.
[b]Note:[/b] This is different from the [code]Bone2D[/code]'s rotation. The bone angle is the rotation of the bone shown by the [code]Bone2D[/code] gizmo, and because [code]Bone2D[/code] bones are based on positions, this can vary from the actual rotation of the [code]Bone2D[/code] node.
@@ -72,14 +72,14 @@
</method>
<method name="set_default_length">
<return type="void" />
- <argument index="0" name="default_length" type="float" />
+ <param index="0" name="default_length" type="float" />
<description>
Deprecated. Please use [code]set_length[/code] instead.
</description>
</method>
<method name="set_length">
<return type="void" />
- <argument index="0" name="length" type="float" />
+ <param index="0" name="length" type="float" />
<description>
Sets the length of the bone in the [code]Bone2D[/code] node.
</description>
diff --git a/doc/classes/BoneAttachment3D.xml b/doc/classes/BoneAttachment3D.xml
index bb4b45cd48..dc3d448621 100644
--- a/doc/classes/BoneAttachment3D.xml
+++ b/doc/classes/BoneAttachment3D.xml
@@ -36,35 +36,35 @@
</method>
<method name="on_bone_pose_update">
<return type="void" />
- <argument index="0" name="bone_index" type="int" />
+ <param index="0" name="bone_index" type="int" />
<description>
A function that is called automatically when the [Skeleton3D] the BoneAttachment3D node is using has a bone that has changed its pose. This function is where the BoneAttachment3D node updates its position so it is correctly bound when it is [i]not[/i] set to override the bone pose.
</description>
</method>
<method name="set_external_skeleton">
<return type="void" />
- <argument index="0" name="external_skeleton" type="NodePath" />
+ <param index="0" name="external_skeleton" type="NodePath" />
<description>
Sets the [NodePath] to the external skeleton that the BoneAttachment3D node should use. The external [Skeleton3D] node is only used when [code]use_external_skeleton[/code] is set to [code]true[/code].
</description>
</method>
<method name="set_override_mode">
<return type="void" />
- <argument index="0" name="override_mode" type="int" />
+ <param index="0" name="override_mode" type="int" />
<description>
Sets the override mode for the BoneAttachment3D node. The override mode defines which of the bone poses the BoneAttachment3D node will override.
</description>
</method>
<method name="set_override_pose">
<return type="void" />
- <argument index="0" name="override_pose" type="bool" />
+ <param index="0" name="override_pose" type="bool" />
<description>
Sets whether the BoneAttachment3D node will override the bone pose of the bone it is attached to. When set to [code]true[/code], the BoneAttachment3D node can change the pose of the bone.
</description>
</method>
<method name="set_use_external_skeleton">
<return type="void" />
- <argument index="0" name="use_external_skeleton" type="bool" />
+ <param index="0" name="use_external_skeleton" type="bool" />
<description>
Sets whether the BoneAttachment3D node will use an extenral [Skeleton3D] node rather than attenpting to use its parent node as the [Skeleton3D]. When set to [code]true[/code], the BoneAttachment3D node will use the external [Skeleton3D] node set in [code]set_external_skeleton[/code].
</description>
diff --git a/doc/classes/BoneMap.xml b/doc/classes/BoneMap.xml
index 371cb4fa93..f7a4845b7d 100644
--- a/doc/classes/BoneMap.xml
+++ b/doc/classes/BoneMap.xml
@@ -12,26 +12,26 @@
<methods>
<method name="find_profile_bone_name" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="skeleton_bone_name" type="StringName" />
+ <param index="0" name="skeleton_bone_name" type="StringName" />
<description>
- Returns a profile bone name having [code]skeleton_bone_name[/code]. If not found, an empty [StringName] will be returned.
+ Returns a profile bone name having [param skeleton_bone_name]. If not found, an empty [StringName] will be returned.
In the retargeting process, the returned bone name is the bone name of the target skeleton.
</description>
</method>
<method name="get_skeleton_bone_name" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="profile_bone_name" type="StringName" />
+ <param index="0" name="profile_bone_name" type="StringName" />
<description>
- Returns a skeleton bone name is mapped to [code]profile_bone_name[/code].
+ Returns a skeleton bone name is mapped to [param profile_bone_name].
In the retargeting process, the returned bone name is the bone name of the source skeleton.
</description>
</method>
<method name="set_skeleton_bone_name">
<return type="void" />
- <argument index="0" name="profile_bone_name" type="StringName" />
- <argument index="1" name="skeleton_bone_name" type="StringName" />
+ <param index="0" name="profile_bone_name" type="StringName" />
+ <param index="1" name="skeleton_bone_name" type="StringName" />
<description>
- Maps a skeleton bone name to [code]profile_bone_name[/code].
+ Maps a skeleton bone name to [param profile_bone_name].
In the retargeting process, the setting bone name is the bone name of the source skeleton.
</description>
</method>
diff --git a/doc/classes/BoxContainer.xml b/doc/classes/BoxContainer.xml
index c76a178368..65ceab3e30 100644
--- a/doc/classes/BoxContainer.xml
+++ b/doc/classes/BoxContainer.xml
@@ -12,9 +12,9 @@
<methods>
<method name="add_spacer">
<return type="Control" />
- <argument index="0" name="begin" type="bool" />
+ <param index="0" name="begin" type="bool" />
<description>
- Adds a [Control] node to the box as a spacer. If [code]begin[/code] is [code]true[/code], it will insert the [Control] node in front of all other children.
+ Adds a [Control] node to the box as a spacer. If [param begin] is [code]true[/code], it will insert the [Control] node in front of all other children.
</description>
</method>
</methods>
diff --git a/doc/classes/Button.xml b/doc/classes/Button.xml
index 1cd9ca0afb..e78cdfc951 100644
--- a/doc/classes/Button.xml
+++ b/doc/classes/Button.xml
@@ -114,7 +114,7 @@
Icon modulate [Color] used when the [Button] is being pressed.
</theme_item>
<theme_item name="h_separation" data_type="constant" type="int" default="2">
- The horizontal space between [Button]'s icon and text.
+ The horizontal space between [Button]'s icon and text. Negative values will be treated as [code]0[/code] when used.
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline.
diff --git a/doc/classes/ButtonGroup.xml b/doc/classes/ButtonGroup.xml
index a887404932..277bda2836 100644
--- a/doc/classes/ButtonGroup.xml
+++ b/doc/classes/ButtonGroup.xml
@@ -11,7 +11,7 @@
</tutorials>
<methods>
<method name="get_buttons">
- <return type="Array" />
+ <return type="BaseButton[]" />
<description>
Returns an [Array] of [Button]s who have this as their [ButtonGroup] (see [member BaseButton.button_group]).
</description>
@@ -28,7 +28,7 @@
</members>
<signals>
<signal name="pressed">
- <argument index="0" name="button" type="BaseButton" />
+ <param index="0" name="button" type="BaseButton" />
<description>
Emitted when one of the buttons of the group is pressed.
</description>
diff --git a/doc/classes/CPUParticles2D.xml b/doc/classes/CPUParticles2D.xml
index dacdca1cee..906789d09f 100644
--- a/doc/classes/CPUParticles2D.xml
+++ b/doc/classes/CPUParticles2D.xml
@@ -13,33 +13,33 @@
<methods>
<method name="convert_from_particles">
<return type="void" />
- <argument index="0" name="particles" type="Node" />
+ <param index="0" name="particles" type="Node" />
<description>
- Sets this node's properties to match a given [GPUParticles2D] node with an assigned [ParticlesMaterial].
+ Sets this node's properties to match a given [GPUParticles2D] node with an assigned [ParticleProcessMaterial].
</description>
</method>
<method name="get_param_curve" qualifiers="const">
<return type="Curve" />
- <argument index="0" name="param" type="int" enum="CPUParticles2D.Parameter" />
+ <param index="0" name="param" type="int" enum="CPUParticles2D.Parameter" />
<description>
Returns the [Curve] of the parameter specified by [enum Parameter].
</description>
</method>
<method name="get_param_max" qualifiers="const">
<return type="float" />
- <argument index="0" name="param" type="int" enum="CPUParticles2D.Parameter" />
+ <param index="0" name="param" type="int" enum="CPUParticles2D.Parameter" />
<description>
</description>
</method>
<method name="get_param_min" qualifiers="const">
<return type="float" />
- <argument index="0" name="param" type="int" enum="CPUParticles2D.Parameter" />
+ <param index="0" name="param" type="int" enum="CPUParticles2D.Parameter" />
<description>
</description>
</method>
<method name="get_particle_flag" qualifiers="const">
<return type="bool" />
- <argument index="0" name="particle_flag" type="int" enum="CPUParticles2D.ParticleFlags" />
+ <param index="0" name="particle_flag" type="int" enum="CPUParticles2D.ParticleFlags" />
<description>
Returns the enabled state of the given flag (see [enum ParticleFlags] for options).
</description>
@@ -52,30 +52,30 @@
</method>
<method name="set_param_curve">
<return type="void" />
- <argument index="0" name="param" type="int" enum="CPUParticles2D.Parameter" />
- <argument index="1" name="curve" type="Curve" />
+ <param index="0" name="param" type="int" enum="CPUParticles2D.Parameter" />
+ <param index="1" name="curve" type="Curve" />
<description>
Sets the [Curve] of the parameter specified by [enum Parameter].
</description>
</method>
<method name="set_param_max">
<return type="void" />
- <argument index="0" name="param" type="int" enum="CPUParticles2D.Parameter" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="param" type="int" enum="CPUParticles2D.Parameter" />
+ <param index="1" name="value" type="float" />
<description>
</description>
</method>
<method name="set_param_min">
<return type="void" />
- <argument index="0" name="param" type="int" enum="CPUParticles2D.Parameter" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="param" type="int" enum="CPUParticles2D.Parameter" />
+ <param index="1" name="value" type="float" />
<description>
</description>
</method>
<method name="set_particle_flag">
<return type="void" />
- <argument index="0" name="particle_flag" type="int" enum="CPUParticles2D.ParticleFlags" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="particle_flag" type="int" enum="CPUParticles2D.ParticleFlags" />
+ <param index="1" name="enable" type="bool" />
<description>
Enables or disables the given flag (see [enum ParticleFlags] for options).
</description>
@@ -192,8 +192,8 @@
</member>
<member name="linear_accel_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
</member>
- <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="true">
- If [code]true[/code], particles use the parent node's coordinate space. If [code]false[/code], they use global coordinates.
+ <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="false">
+ If [code]true[/code], particles use the parent node's coordinate space (known as local coordinates). This will cause particles to move and rotate along the [CPUParticles2D] node (and its parents) when it is moved or rotated. If [code]false[/code], particles use global coordinates; they will not move or rotate along the [CPUParticles2D] node (and its parents) when it is moved or rotated.
</member>
<member name="one_shot" type="bool" setter="set_one_shot" getter="get_one_shot" default="false">
If [code]true[/code], only one emission cycle occurs. If set [code]true[/code] during a cycle, emission will stop at the cycle's end.
diff --git a/doc/classes/CPUParticles3D.xml b/doc/classes/CPUParticles3D.xml
index f2a0040ed4..6b39c08b3f 100644
--- a/doc/classes/CPUParticles3D.xml
+++ b/doc/classes/CPUParticles3D.xml
@@ -12,33 +12,33 @@
<methods>
<method name="convert_from_particles">
<return type="void" />
- <argument index="0" name="particles" type="Node" />
+ <param index="0" name="particles" type="Node" />
<description>
- Sets this node's properties to match a given [GPUParticles3D] node with an assigned [ParticlesMaterial].
+ Sets this node's properties to match a given [GPUParticles3D] node with an assigned [ParticleProcessMaterial].
</description>
</method>
<method name="get_param_curve" qualifiers="const">
<return type="Curve" />
- <argument index="0" name="param" type="int" enum="CPUParticles3D.Parameter" />
+ <param index="0" name="param" type="int" enum="CPUParticles3D.Parameter" />
<description>
Returns the [Curve] of the parameter specified by [enum Parameter].
</description>
</method>
<method name="get_param_max" qualifiers="const">
<return type="float" />
- <argument index="0" name="param" type="int" enum="CPUParticles3D.Parameter" />
+ <param index="0" name="param" type="int" enum="CPUParticles3D.Parameter" />
<description>
</description>
</method>
<method name="get_param_min" qualifiers="const">
<return type="float" />
- <argument index="0" name="param" type="int" enum="CPUParticles3D.Parameter" />
+ <param index="0" name="param" type="int" enum="CPUParticles3D.Parameter" />
<description>
</description>
</method>
<method name="get_particle_flag" qualifiers="const">
<return type="bool" />
- <argument index="0" name="particle_flag" type="int" enum="CPUParticles3D.ParticleFlags" />
+ <param index="0" name="particle_flag" type="int" enum="CPUParticles3D.ParticleFlags" />
<description>
Returns the enabled state of the given particle flag (see [enum ParticleFlags] for options).
</description>
@@ -51,32 +51,32 @@
</method>
<method name="set_param_curve">
<return type="void" />
- <argument index="0" name="param" type="int" enum="CPUParticles3D.Parameter" />
- <argument index="1" name="curve" type="Curve" />
+ <param index="0" name="param" type="int" enum="CPUParticles3D.Parameter" />
+ <param index="1" name="curve" type="Curve" />
<description>
Sets the [Curve] of the parameter specified by [enum Parameter].
</description>
</method>
<method name="set_param_max">
<return type="void" />
- <argument index="0" name="param" type="int" enum="CPUParticles3D.Parameter" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="param" type="int" enum="CPUParticles3D.Parameter" />
+ <param index="1" name="value" type="float" />
<description>
Sets the maximum value for the given parameter
</description>
</method>
<method name="set_param_min">
<return type="void" />
- <argument index="0" name="param" type="int" enum="CPUParticles3D.Parameter" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="param" type="int" enum="CPUParticles3D.Parameter" />
+ <param index="1" name="value" type="float" />
<description>
Sets the minimum value for the given parameter
</description>
</method>
<method name="set_particle_flag">
<return type="void" />
- <argument index="0" name="particle_flag" type="int" enum="CPUParticles3D.ParticleFlags" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="particle_flag" type="int" enum="CPUParticles3D.ParticleFlags" />
+ <param index="1" name="enable" type="bool" />
<description>
Enables or disables the given particle flag (see [enum ParticleFlags] for options).
</description>
@@ -123,13 +123,16 @@
Minimum particle animation speed.
</member>
<member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)">
- Each particle's initial color. To have particle display color in a [BaseMaterial3D] make sure to set [member BaseMaterial3D.vertex_color_use_as_albedo] to [code]true[/code].
+ Each particle's initial color.
+ [b]Note:[/b] [member color] multiplies the particle mesh's vertex colors. To have a visible effect on a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] [i]must[/i] be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/code] must be inserted in the shader's [code]fragment()[/code] function. Otherwise, [member color] will have no visible effect.
</member>
<member name="color_initial_ramp" type="Gradient" setter="set_color_initial_ramp" getter="get_color_initial_ramp">
Each particle's initial color will vary along this [GradientTexture1D] (multiplied with [member color]).
+ [b]Note:[/b] [member color_initial_ramp] multiplies the particle mesh's vertex colors. To have a visible effect on a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] [i]must[/i] be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/code] must be inserted in the shader's [code]fragment()[/code] function. Otherwise, [member color_initial_ramp] will have no visible effect.
</member>
<member name="color_ramp" type="Gradient" setter="set_color_ramp" getter="get_color_ramp">
Each particle's color will vary along this [GradientTexture1D] over its lifetime (multiplied with [member color]).
+ [b]Note:[/b] [member color_ramp] multiplies the particle mesh's vertex colors. To have a visible effect on a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] [i]must[/i] be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/code] must be inserted in the shader's [code]fragment()[/code] function. Otherwise, [member color_ramp] will have no visible effect.
</member>
<member name="damping_curve" type="Curve" setter="set_param_curve" getter="get_param_curve">
Damping will vary along this [Curve].
@@ -151,6 +154,7 @@
</member>
<member name="emission_colors" type="PackedColorArray" setter="set_emission_colors" getter="get_emission_colors" default="PackedColorArray()">
Sets the [Color]s to modulate particles by when using [constant EMISSION_SHAPE_POINTS] or [constant EMISSION_SHAPE_DIRECTED_POINTS].
+ [b]Note:[/b] [member emission_colors] multiplies the particle mesh's vertex colors. To have a visible effect on a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] [i]must[/i] be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/code] must be inserted in the shader's [code]fragment()[/code] function. Otherwise, [member emission_colors] will have no visible effect.
</member>
<member name="emission_normals" type="PackedVector3Array" setter="set_emission_normals" getter="get_emission_normals">
Sets the direction the particles will be emitted in when using [constant EMISSION_SHAPE_DIRECTED_POINTS].
@@ -224,8 +228,8 @@
<member name="linear_accel_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
Minimum linear acceleration.
</member>
- <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="true">
- If [code]true[/code], particles use the parent node's coordinate space. If [code]false[/code], they use global coordinates.
+ <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="false">
+ If [code]true[/code], particles use the parent node's coordinate space (known as local coordinates). This will cause particles to move and rotate along the [CPUParticles3D] node (and its parents) when it is moved or rotated. If [code]false[/code], particles use global coordinates; they will not move or rotate along the [CPUParticles3D] node (and its parents) when it is moved or rotated.
</member>
<member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh">
The [Mesh] used for each particle. If [code]null[/code], particles will be spheres.
diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml
index efe3e3d091..6838bdeb70 100644
--- a/doc/classes/Callable.xml
+++ b/doc/classes/Callable.xml
@@ -44,17 +44,17 @@
</constructor>
<constructor name="Callable">
<return type="Callable" />
- <argument index="0" name="from" type="Callable" />
+ <param index="0" name="from" type="Callable" />
<description>
Constructs a [Callable] as a copy of the given [Callable].
</description>
</constructor>
<constructor name="Callable">
<return type="Callable" />
- <argument index="0" name="object" type="Object" />
- <argument index="1" name="method" type="StringName" />
+ <param index="0" name="object" type="Object" />
+ <param index="1" name="method" type="StringName" />
<description>
- Creates a new [Callable] for the method called [code]method[/code] in the specified [code]object[/code].
+ Creates a new [Callable] for the method called [param method] in the specified [param object].
</description>
</constructor>
</constructors>
@@ -134,14 +134,14 @@
</method>
<method name="rpc_id" qualifiers="vararg const">
<return type="void" />
- <argument index="0" name="peer_id" type="int" />
+ <param index="0" name="peer_id" type="int" />
<description>
Perform an RPC (Remote Procedure Call) on a specific peer ID (see multiplayer documentation for reference). This is used for multiplayer and is normally not available unless the function being called has been marked as [i]RPC[/i]. Calling it on unsupported functions will result in an error.
</description>
</method>
<method name="unbind" qualifiers="const">
<return type="Callable" />
- <argument index="0" name="argcount" type="int" />
+ <param index="0" name="argcount" type="int" />
<description>
Returns a copy of this [Callable] with the arguments unbound. Calling the returned [Callable] will call the method without the extra arguments that are supplied in the [Callable] on which you are calling this method.
</description>
@@ -150,14 +150,14 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="Callable" />
+ <param index="0" name="right" type="Callable" />
<description>
Returns [code]true[/code] if both [Callable]s invoke different targets.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="Callable" />
+ <param index="0" name="right" type="Callable" />
<description>
Returns [code]true[/code] if both [Callable]s invoke the same custom target.
</description>
diff --git a/doc/classes/CallbackTweener.xml b/doc/classes/CallbackTweener.xml
index 3d80d8f3ab..6e4ee0380e 100644
--- a/doc/classes/CallbackTweener.xml
+++ b/doc/classes/CallbackTweener.xml
@@ -12,7 +12,7 @@
<methods>
<method name="set_delay">
<return type="CallbackTweener" />
- <argument index="0" name="delay" type="float" />
+ <param index="0" name="delay" type="float" />
<description>
Makes the callback call delayed by given time in seconds. Example:
[codeblock]
diff --git a/doc/classes/Camera2D.xml b/doc/classes/Camera2D.xml
index b9373676e2..edb5235b75 100644
--- a/doc/classes/Camera2D.xml
+++ b/doc/classes/Camera2D.xml
@@ -43,14 +43,14 @@
</method>
<method name="get_drag_margin" qualifiers="const">
<return type="float" />
- <argument index="0" name="margin" type="int" enum="Side" />
+ <param index="0" name="margin" type="int" enum="Side" />
<description>
Returns the specified [enum Side]'s margin. See also [member drag_bottom_margin], [member drag_top_margin], [member drag_left_margin], and [member drag_right_margin].
</description>
</method>
<method name="get_limit" qualifiers="const">
<return type="int" />
- <argument index="0" name="margin" type="int" enum="Side" />
+ <param index="0" name="margin" type="int" enum="Side" />
<description>
Returns the camera limit for the specified [enum Side]. See also [member limit_bottom], [member limit_top], [member limit_left], and [member limit_right].
</description>
@@ -64,16 +64,16 @@
</method>
<method name="set_drag_margin">
<return type="void" />
- <argument index="0" name="margin" type="int" enum="Side" />
- <argument index="1" name="drag_margin" type="float" />
+ <param index="0" name="margin" type="int" enum="Side" />
+ <param index="1" name="drag_margin" type="float" />
<description>
Sets the specified [enum Side]'s margin. See also [member drag_bottom_margin], [member drag_top_margin], [member drag_left_margin], and [member drag_right_margin].
</description>
</method>
<method name="set_limit">
<return type="void" />
- <argument index="0" name="margin" type="int" enum="Side" />
- <argument index="1" name="limit" type="int" />
+ <param index="0" name="margin" type="int" enum="Side" />
+ <param index="1" name="limit" type="int" />
<description>
Sets the camera limit for the specified [enum Side]. See also [member limit_bottom], [member limit_top], [member limit_left], and [member limit_right].
</description>
diff --git a/doc/classes/Camera3D.xml b/doc/classes/Camera3D.xml
index 3aedbbd1e6..65fdecc3c6 100644
--- a/doc/classes/Camera3D.xml
+++ b/doc/classes/Camera3D.xml
@@ -12,9 +12,9 @@
<methods>
<method name="clear_current">
<return type="void" />
- <argument index="0" name="enable_next" type="bool" default="true" />
+ <param index="0" name="enable_next" type="bool" default="true" />
<description>
- If this is the current camera, remove it from being current. If [code]enable_next[/code] is [code]true[/code], request to make the next camera current, if any.
+ If this is the current camera, remove it from being current. If [param enable_next] is [code]true[/code], request to make the next camera current, if any.
</description>
</method>
<method name="get_camera_rid" qualifiers="const">
@@ -31,13 +31,13 @@
</method>
<method name="get_cull_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
- Returns whether or not the specified layer of the [member cull_mask] is enabled, given a [code]layer_number[/code] between 1 and 20.
+ Returns whether or not the specified layer of the [member cull_mask] is enabled, given a [param layer_number] between 1 and 20.
</description>
</method>
<method name="get_frustum" qualifiers="const">
- <return type="Array" />
+ <return type="Plane[]" />
<description>
Returns the camera's frustum planes in world space units as an array of [Plane]s in the following order: near, far, left, top, right, bottom. Not to be confused with [member frustum_offset].
</description>
@@ -50,7 +50,7 @@
</method>
<method name="is_position_behind" qualifiers="const">
<return type="bool" />
- <argument index="0" name="world_point" type="Vector3" />
+ <param index="0" name="world_point" type="Vector3" />
<description>
Returns [code]true[/code] if the given position is behind the camera (the blue part of the linked diagram). [url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/camera3d_position_frustum.png]See this diagram[/url] for an overview of position query methods.
[b]Note:[/b] A position which returns [code]false[/code] may still be outside the camera's field of view.
@@ -58,7 +58,7 @@
</method>
<method name="is_position_in_frustum" qualifiers="const">
<return type="bool" />
- <argument index="0" name="world_point" type="Vector3" />
+ <param index="0" name="world_point" type="Vector3" />
<description>
Returns [code]true[/code] if the given position is inside the camera's frustum (the green part of the linked diagram). [url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/camera3d_position_frustum.png]See this diagram[/url] for an overview of position query methods.
</description>
@@ -71,72 +71,72 @@
</method>
<method name="project_local_ray_normal" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="screen_point" type="Vector2" />
+ <param index="0" name="screen_point" type="Vector2" />
<description>
Returns a normal vector from the screen point location directed along the camera. Orthogonal cameras are normalized. Perspective cameras account for perspective, screen width/height, etc.
</description>
</method>
<method name="project_position" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="screen_point" type="Vector2" />
- <argument index="1" name="z_depth" type="float" />
+ <param index="0" name="screen_point" type="Vector2" />
+ <param index="1" name="z_depth" type="float" />
<description>
- Returns the 3D point in world space that maps to the given 2D coordinate in the [Viewport] rectangle on a plane that is the given [code]z_depth[/code] distance into the scene away from the camera.
+ Returns the 3D point in world space that maps to the given 2D coordinate in the [Viewport] rectangle on a plane that is the given [param z_depth] distance into the scene away from the camera.
</description>
</method>
<method name="project_ray_normal" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="screen_point" type="Vector2" />
+ <param index="0" name="screen_point" type="Vector2" />
<description>
Returns a normal vector in world space, that is the result of projecting a point on the [Viewport] rectangle by the inverse camera projection. This is useful for casting rays in the form of (origin, normal) for object intersection or picking.
</description>
</method>
<method name="project_ray_origin" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="screen_point" type="Vector2" />
+ <param index="0" name="screen_point" type="Vector2" />
<description>
Returns a 3D position in world space, that is the result of projecting a point on the [Viewport] rectangle by the inverse camera projection. This is useful for casting rays in the form of (origin, normal) for object intersection or picking.
</description>
</method>
<method name="set_cull_mask_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
- Based on [code]value[/code], enables or disables the specified layer in the [member cull_mask], given a [code]layer_number[/code] between 1 and 20.
+ Based on [param value], enables or disables the specified layer in the [member cull_mask], given a [param layer_number] between 1 and 20.
</description>
</method>
<method name="set_frustum">
<return type="void" />
- <argument index="0" name="size" type="float" />
- <argument index="1" name="offset" type="Vector2" />
- <argument index="2" name="z_near" type="float" />
- <argument index="3" name="z_far" type="float" />
+ <param index="0" name="size" type="float" />
+ <param index="1" name="offset" type="Vector2" />
+ <param index="2" name="z_near" type="float" />
+ <param index="3" name="z_far" type="float" />
<description>
- Sets the camera projection to frustum mode (see [constant PROJECTION_FRUSTUM]), by specifying a [code]size[/code], an [code]offset[/code], and the [code]z_near[/code] and [code]z_far[/code] clip planes in world space units.
+ Sets the camera projection to frustum mode (see [constant PROJECTION_FRUSTUM]), by specifying a [param size], an [param offset], and the [param z_near] and [param z_far] clip planes in world space units. See also [member frustum_offset].
</description>
</method>
<method name="set_orthogonal">
<return type="void" />
- <argument index="0" name="size" type="float" />
- <argument index="1" name="z_near" type="float" />
- <argument index="2" name="z_far" type="float" />
+ <param index="0" name="size" type="float" />
+ <param index="1" name="z_near" type="float" />
+ <param index="2" name="z_far" type="float" />
<description>
- Sets the camera projection to orthogonal mode (see [constant PROJECTION_ORTHOGONAL]), by specifying a [code]size[/code], and the [code]z_near[/code] and [code]z_far[/code] clip planes in world space units. (As a hint, 2D games often use this projection, with values specified in pixels.)
+ Sets the camera projection to orthogonal mode (see [constant PROJECTION_ORTHOGONAL]), by specifying a [param size], and the [param z_near] and [param z_far] clip planes in world space units. (As a hint, 2D games often use this projection, with values specified in pixels.)
</description>
</method>
<method name="set_perspective">
<return type="void" />
- <argument index="0" name="fov" type="float" />
- <argument index="1" name="z_near" type="float" />
- <argument index="2" name="z_far" type="float" />
+ <param index="0" name="fov" type="float" />
+ <param index="1" name="z_near" type="float" />
+ <param index="2" name="z_far" type="float" />
<description>
- Sets the camera projection to perspective mode (see [constant PROJECTION_PERSPECTIVE]), by specifying a [code]fov[/code] (field of view) angle in degrees, and the [code]z_near[/code] and [code]z_far[/code] clip planes in world space units.
+ Sets the camera projection to perspective mode (see [constant PROJECTION_PERSPECTIVE]), by specifying a [param fov] (field of view) angle in degrees, and the [param z_near] and [param z_far] clip planes in world space units.
</description>
</method>
<method name="unproject_position" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="world_point" type="Vector3" />
+ <param index="0" name="world_point" type="Vector3" />
<description>
Returns the 2D coordinate in the [Viewport] rectangle that maps to the given 3D point in world space.
[b]Note:[/b] When using this to position GUI elements over a 3D viewport, use [method is_position_behind] to prevent them from appearing if the 3D point is behind the camera:
@@ -144,7 +144,7 @@
# This code block is part of a script that inherits from Node3D.
# `control` is a reference to a node inheriting from Control.
control.visible = not get_viewport().get_camera_3d().is_position_behind(global_transform.origin)
- control.rect_position = get_viewport().get_camera_3d().unproject_position(global_transform.origin)
+ control.position = get_viewport().get_camera_3d().unproject_position(global_transform.origin)
[/codeblock]
</description>
</method>
@@ -179,6 +179,7 @@
</member>
<member name="frustum_offset" type="Vector2" setter="set_frustum_offset" getter="get_frustum_offset" default="Vector2(0, 0)">
The camera's frustum offset. This can be changed from the default to create "tilted frustum" effects such as [url=https://zdoom.org/wiki/Y-shearing]Y-shearing[/url].
+ [b]Note:[/b] Only effective if [member projection] is [constant PROJECTION_FRUSTUM].
</member>
<member name="h_offset" type="float" setter="set_h_offset" getter="get_h_offset" default="0.0">
The horizontal (X) offset of the camera viewport.
@@ -193,7 +194,7 @@
The camera's projection mode. In [constant PROJECTION_PERSPECTIVE] mode, objects' Z distance from the camera's local space scales their perceived size.
</member>
<member name="size" type="float" setter="set_size" getter="get_size" default="1.0">
- The camera's size measured as 1/2 the width or height. Only applicable in orthogonal and frustum modes. Since [member keep_aspect] locks on axis, [code]size[/code] sets the other axis' size length.
+ The camera's size in meters measured as the diameter of the width or height, depending on [member keep_aspect]. Only applicable in orthogonal and frustum modes.
</member>
<member name="v_offset" type="float" setter="set_v_offset" getter="get_v_offset" default="0.0">
The vertical (Y) offset of the camera viewport.
diff --git a/doc/classes/CameraServer.xml b/doc/classes/CameraServer.xml
index 1ccdee58f7..d346fbde4f 100644
--- a/doc/classes/CameraServer.xml
+++ b/doc/classes/CameraServer.xml
@@ -13,22 +13,22 @@
<methods>
<method name="add_feed">
<return type="void" />
- <argument index="0" name="feed" type="CameraFeed" />
+ <param index="0" name="feed" type="CameraFeed" />
<description>
- Adds the camera [code]feed[/code] to the camera server.
+ Adds the camera [param feed] to the camera server.
</description>
</method>
<method name="feeds">
- <return type="Array" />
+ <return type="CameraFeed[]" />
<description>
Returns an array of [CameraFeed]s.
</description>
</method>
<method name="get_feed">
<return type="CameraFeed" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the [CameraFeed] corresponding to the camera with the given [code]index[/code].
+ Returns the [CameraFeed] corresponding to the camera with the given [param index].
</description>
</method>
<method name="get_feed_count">
@@ -39,21 +39,21 @@
</method>
<method name="remove_feed">
<return type="void" />
- <argument index="0" name="feed" type="CameraFeed" />
+ <param index="0" name="feed" type="CameraFeed" />
<description>
- Removes the specified camera [code]feed[/code].
+ Removes the specified camera [param feed].
</description>
</method>
</methods>
<signals>
<signal name="camera_feed_added">
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Emitted when a [CameraFeed] is added (e.g. a webcam is plugged in).
</description>
</signal>
<signal name="camera_feed_removed">
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Emitted when a [CameraFeed] is removed (e.g. a webcam is unplugged).
</description>
diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index 2d68ae6902..d1fdca5814 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -5,11 +5,11 @@
</brief_description>
<description>
Base class of anything 2D. Canvas items are laid out in a tree; children inherit and extend their parent's transform. [CanvasItem] is extended by [Control] for anything GUI-related, and by [Node2D] for anything related to the 2D engine.
- Any [CanvasItem] can draw. For this, [method update] must be called, then [constant NOTIFICATION_DRAW] will be received on idle time to request redraw. Because of this, canvas items don't need to be redrawn on every frame, improving the performance significantly. Several functions for drawing on the [CanvasItem] are provided (see [code]draw_*[/code] functions). However, they can only be used inside the [method Object._notification], signal or [method _draw] virtual functions.
+ Any [CanvasItem] can draw. For this, [method update] is called by the engine, then [constant NOTIFICATION_DRAW] will be received on idle time to request redraw. Because of this, canvas items don't need to be redrawn on every frame, improving the performance significantly. Several functions for drawing on the [CanvasItem] are provided (see [code]draw_*[/code] functions). However, they can only be used inside [method _draw], its corresponding [method Object._notification] or methods connected to the [signal draw] signal.
Canvas items are drawn in tree order. By default, children are on top of their parents so a root [CanvasItem] will be drawn behind everything. This behavior can be changed on a per-item basis.
A [CanvasItem] can also be hidden, which will also hide its children. It provides many ways to change parameters such as modulation (for itself and its children) and self modulation (only for itself), as well as its blend mode.
Ultimately, a transform notification can be requested, which will notify the node that its global position changed in case the parent tree changed.
- [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 @GlobalScope.deg2rad].
+ [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 @GlobalScope.deg_to_rad].
</description>
<tutorials>
<link title="Viewport and canvas transforms">$DOCS_URL/tutorials/2d/2d_transforms.html</link>
@@ -20,82 +20,83 @@
<method name="_draw" qualifiers="virtual">
<return type="void" />
<description>
- Overridable function called by the engine (if defined) to draw the canvas item.
+ Called when [CanvasItem] has been requested to redraw (when [method update] is called, either manually or by the engine).
+ Corresponds to the [constant NOTIFICATION_DRAW] notification in [method Object._notification].
</description>
</method>
<method name="draw_animation_slice">
<return type="void" />
- <argument index="0" name="animation_length" type="float" />
- <argument index="1" name="slice_begin" type="float" />
- <argument index="2" name="slice_end" type="float" />
- <argument index="3" name="offset" type="float" default="0.0" />
+ <param index="0" name="animation_length" type="float" />
+ <param index="1" name="slice_begin" type="float" />
+ <param index="2" name="slice_end" type="float" />
+ <param index="3" name="offset" type="float" default="0.0" />
<description>
Subsequent drawing commands will be ignored unless they fall within the specified animation slice. This is a faster way to implement animations that loop on background rather than redrawing constantly.
</description>
</method>
<method name="draw_arc">
<return type="void" />
- <argument index="0" name="center" type="Vector2" />
- <argument index="1" name="radius" type="float" />
- <argument index="2" name="start_angle" type="float" />
- <argument index="3" name="end_angle" type="float" />
- <argument index="4" name="point_count" type="int" />
- <argument index="5" name="color" type="Color" />
- <argument index="6" name="width" type="float" default="1.0" />
- <argument index="7" name="antialiased" type="bool" default="false" />
+ <param index="0" name="center" type="Vector2" />
+ <param index="1" name="radius" type="float" />
+ <param index="2" name="start_angle" type="float" />
+ <param index="3" name="end_angle" type="float" />
+ <param index="4" name="point_count" type="int" />
+ <param index="5" name="color" type="Color" />
+ <param index="6" name="width" type="float" default="1.0" />
+ <param index="7" name="antialiased" type="bool" default="false" />
<description>
- Draws a unfilled arc between the given angles. The larger the value of [code]point_count[/code], the smoother the curve. See also [method draw_circle].
+ Draws a unfilled arc between the given angles. The larger the value of [param point_count], the smoother the curve. See also [method draw_circle].
</description>
</method>
<method name="draw_char" qualifiers="const">
<return type="void" />
- <argument index="0" name="font" type="Font" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="char" type="String" />
- <argument index="3" name="font_size" type="int" default="16" />
- <argument index="4" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="0" name="font" type="Font" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="char" type="String" />
+ <param index="3" name="font_size" type="int" default="16" />
+ <param index="4" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
<description>
Draws a string first character using a custom font.
</description>
</method>
<method name="draw_char_outline" qualifiers="const">
<return type="void" />
- <argument index="0" name="font" type="Font" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="char" type="String" />
- <argument index="3" name="font_size" type="int" default="16" />
- <argument index="4" name="size" type="int" default="-1" />
- <argument index="5" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="0" name="font" type="Font" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="char" type="String" />
+ <param index="3" name="font_size" type="int" default="16" />
+ <param index="4" name="size" type="int" default="-1" />
+ <param index="5" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
<description>
Draws a string first character outline using a custom font.
</description>
</method>
<method name="draw_circle">
<return type="void" />
- <argument index="0" name="position" type="Vector2" />
- <argument index="1" name="radius" type="float" />
- <argument index="2" name="color" type="Color" />
+ <param index="0" name="position" type="Vector2" />
+ <param index="1" name="radius" type="float" />
+ <param index="2" name="color" type="Color" />
<description>
Draws a colored, filled circle. See also [method draw_arc], [method draw_polyline] and [method draw_polygon].
</description>
</method>
<method name="draw_colored_polygon">
<return type="void" />
- <argument index="0" name="points" type="PackedVector2Array" />
- <argument index="1" name="color" type="Color" />
- <argument index="2" name="uvs" type="PackedVector2Array" default="PackedVector2Array()" />
- <argument index="3" name="texture" type="Texture2D" default="null" />
+ <param index="0" name="points" type="PackedVector2Array" />
+ <param index="1" name="color" type="Color" />
+ <param index="2" name="uvs" type="PackedVector2Array" default="PackedVector2Array()" />
+ <param index="3" name="texture" type="Texture2D" default="null" />
<description>
- Draws a colored polygon of any amount of points, convex or concave. Unlike [method draw_polygon], a single color must be specified for the whole polygon.
+ Draws a colored polygon of any number of points, convex or concave. Unlike [method draw_polygon], a single color must be specified for the whole polygon.
</description>
</method>
<method name="draw_dashed_line">
<return type="void" />
- <argument index="0" name="from" type="Vector2" />
- <argument index="1" name="to" type="Vector2" />
- <argument index="2" name="color" type="Color" />
- <argument index="3" name="width" type="float" default="1.0" />
- <argument index="4" name="dash" type="float" default="2.0" />
+ <param index="0" name="from" type="Vector2" />
+ <param index="1" name="to" type="Vector2" />
+ <param index="2" name="color" type="Color" />
+ <param index="3" name="width" type="float" default="1.0" />
+ <param index="4" name="dash" type="float" default="2.0" />
<description>
Draws a dashed line from a 2D point to another, with a given color and width. See also [method draw_multiline] and [method draw_polyline].
</description>
@@ -106,186 +107,203 @@
After submitting all animations slices via [method draw_animation_slice], this function can be used to revert drawing to its default state (all subsequent drawing commands will be visible). If you don't care about this particular use case, usage of this function after submitting the slices is not required.
</description>
</method>
+ <method name="draw_lcd_texture_rect_region">
+ <return type="void" />
+ <param index="0" name="texture" type="Texture2D" />
+ <param index="1" name="rect" type="Rect2" />
+ <param index="2" name="src_rect" type="Rect2" />
+ <param index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <description>
+ Draws a textured rectangle region of the font texture with LCD sub-pixel anti-aliasing at a given position, optionally modulated by a color.
+ Texture is drawn using the following blend operation, blend mode of the [CanvasItemMaterial] is ignored:
+ [codeblock]
+ dst.r = texture.r * modulate.r * modulate.a + dst.r * (1.0 - texture.r * modulate.a);
+ dst.g = texture.g * modulate.g * modulate.a + dst.g * (1.0 - texture.g * modulate.a);
+ dst.b = texture.b * modulate.b * modulate.a + dst.b * (1.0 - texture.b * modulate.a);
+ dst.a = modulate.a + dst.a * (1.0 - modulate.a);
+ [/codeblock]
+ </description>
+ </method>
<method name="draw_line">
<return type="void" />
- <argument index="0" name="from" type="Vector2" />
- <argument index="1" name="to" type="Vector2" />
- <argument index="2" name="color" type="Color" />
- <argument index="3" name="width" type="float" default="1.0" />
- <argument index="4" name="antialiased" type="bool" default="false" />
+ <param index="0" name="from" type="Vector2" />
+ <param index="1" name="to" type="Vector2" />
+ <param index="2" name="color" type="Color" />
+ <param index="3" name="width" type="float" default="1.0" />
+ <param index="4" name="antialiased" type="bool" default="false" />
<description>
Draws a line from a 2D point to another, with a given color and width. It can be optionally antialiased. See also [method draw_multiline] and [method draw_polyline].
</description>
</method>
<method name="draw_mesh">
<return type="void" />
- <argument index="0" name="mesh" type="Mesh" />
- <argument index="1" name="texture" type="Texture2D" />
- <argument index="2" name="transform" type="Transform2D" default="Transform2D(1, 0, 0, 1, 0, 0)" />
- <argument index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="0" name="mesh" type="Mesh" />
+ <param index="1" name="texture" type="Texture2D" />
+ <param index="2" name="transform" type="Transform2D" default="Transform2D(1, 0, 0, 1, 0, 0)" />
+ <param index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
<description>
Draws a [Mesh] in 2D, using the provided texture. See [MeshInstance2D] for related documentation.
</description>
</method>
<method name="draw_msdf_texture_rect_region">
<return type="void" />
- <argument index="0" name="texture" type="Texture2D" />
- <argument index="1" name="rect" type="Rect2" />
- <argument index="2" name="src_rect" type="Rect2" />
- <argument index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="4" name="outline" type="float" default="0.0" />
- <argument index="5" name="pixel_range" type="float" default="4.0" />
+ <param index="0" name="texture" type="Texture2D" />
+ <param index="1" name="rect" type="Rect2" />
+ <param index="2" name="src_rect" type="Rect2" />
+ <param index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="4" name="outline" type="float" default="0.0" />
+ <param index="5" name="pixel_range" type="float" default="4.0" />
<description>
Draws a textured rectangle region of the multi-channel signed distance field texture at a given position, optionally modulated by a color. See [member FontFile.multichannel_signed_distance_field] for more information and caveats about MSDF font rendering.
- If [code]outline[/code] is positive, each alpha channel value of pixel in region is set to maximum value of true distance in the [code]outline[/code] radius.
- Value of the [code]pixel_range[/code] should the same that was used during distance field texture generation.
+ If [param outline] is positive, each alpha channel value of pixel in region is set to maximum value of true distance in the [param outline] radius.
+ Value of the [param pixel_range] should the same that was used during distance field texture generation.
</description>
</method>
<method name="draw_multiline">
<return type="void" />
- <argument index="0" name="points" type="PackedVector2Array" />
- <argument index="1" name="color" type="Color" />
- <argument index="2" name="width" type="float" default="1.0" />
+ <param index="0" name="points" type="PackedVector2Array" />
+ <param index="1" name="color" type="Color" />
+ <param index="2" name="width" type="float" default="1.0" />
<description>
- Draws multiple disconnected lines with a uniform [code]color[/code]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw interconnected lines, use [method draw_polyline] instead.
+ Draws multiple disconnected lines with a uniform [param color]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw interconnected lines, use [method draw_polyline] instead.
</description>
</method>
<method name="draw_multiline_colors">
<return type="void" />
- <argument index="0" name="points" type="PackedVector2Array" />
- <argument index="1" name="colors" type="PackedColorArray" />
- <argument index="2" name="width" type="float" default="1.0" />
+ <param index="0" name="points" type="PackedVector2Array" />
+ <param index="1" name="colors" type="PackedColorArray" />
+ <param index="2" name="width" type="float" default="1.0" />
<description>
- Draws multiple disconnected lines with a uniform [code]width[/code] and segment-by-segment coloring. Colors assigned to line segments match by index between [code]points[/code] and [code]colors[/code]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw interconnected lines, use [method draw_polyline_colors] instead.
+ Draws multiple disconnected lines with a uniform [param width] and segment-by-segment coloring. Colors assigned to line segments match by index between [param points] and [param colors]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw interconnected lines, use [method draw_polyline_colors] instead.
</description>
</method>
<method name="draw_multiline_string" qualifiers="const">
<return type="void" />
- <argument index="0" name="font" type="Font" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="text" type="String" />
- <argument index="3" name="alignment" type="int" enum="HorizontalAlignment" default="0" />
- <argument index="4" name="width" type="float" default="-1" />
- <argument index="5" name="font_size" type="int" default="16" />
- <argument index="6" name="max_lines" type="int" default="-1" />
- <argument index="7" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="8" name="brk_flags" type="int" enum="TextServer.LineBreakFlag" default="3" />
- <argument index="9" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
- <argument index="10" name="direction" type="int" enum="TextServer.Direction" default="0" />
- <argument index="11" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
+ <param index="0" name="font" type="Font" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="text" type="String" />
+ <param index="3" name="alignment" type="int" enum="HorizontalAlignment" default="0" />
+ <param index="4" name="width" type="float" default="-1" />
+ <param index="5" name="font_size" type="int" default="16" />
+ <param index="6" name="max_lines" type="int" default="-1" />
+ <param index="7" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="8" name="brk_flags" type="int" enum="TextServer.LineBreakFlag" default="3" />
+ <param index="9" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="10" name="direction" type="int" enum="TextServer.Direction" default="0" />
+ <param index="11" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
- Breaks [code]text[/code] to the lines and draws it using the specified [code]font[/code] at the [code]position[/code] (top-left corner). The text will have its color multiplied by [code]modulate[/code]. If [code]clip_w[/code] is greater than or equal to 0, the text will be clipped if it exceeds the specified width.
+ Breaks [param text] into lines and draws it using the specified [param font] at the [param pos] (top-left corner). The text will have its color multiplied by [param modulate]. If [param width] is greater than or equal to 0, the text will be clipped if it exceeds the specified width.
</description>
</method>
<method name="draw_multiline_string_outline" qualifiers="const">
<return type="void" />
- <argument index="0" name="font" type="Font" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="text" type="String" />
- <argument index="3" name="alignment" type="int" enum="HorizontalAlignment" default="0" />
- <argument index="4" name="width" type="float" default="-1" />
- <argument index="5" name="font_size" type="int" default="16" />
- <argument index="6" name="max_lines" type="int" default="-1" />
- <argument index="7" name="size" type="int" default="1" />
- <argument index="8" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="9" name="brk_flags" type="int" enum="TextServer.LineBreakFlag" default="3" />
- <argument index="10" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
- <argument index="11" name="direction" type="int" enum="TextServer.Direction" default="0" />
- <argument index="12" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
+ <param index="0" name="font" type="Font" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="text" type="String" />
+ <param index="3" name="alignment" type="int" enum="HorizontalAlignment" default="0" />
+ <param index="4" name="width" type="float" default="-1" />
+ <param index="5" name="font_size" type="int" default="16" />
+ <param index="6" name="max_lines" type="int" default="-1" />
+ <param index="7" name="size" type="int" default="1" />
+ <param index="8" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="9" name="brk_flags" type="int" enum="TextServer.LineBreakFlag" default="3" />
+ <param index="10" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="11" name="direction" type="int" enum="TextServer.Direction" default="0" />
+ <param index="12" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
- Breaks [code]text[/code] to the lines and draws text outline using the specified [code]font[/code] at the [code]position[/code] (top-left corner). The text will have its color multiplied by [code]modulate[/code]. If [code]clip_w[/code] is greater than or equal to 0, the text will be clipped if it exceeds the specified width.
+ Breaks [param text] to the lines and draws text outline using the specified [param font] at the [param pos] (top-left corner). The text will have its color multiplied by [param modulate]. If [param width] is greater than or equal to 0, the text will be clipped if it exceeds the specified width.
</description>
</method>
<method name="draw_multimesh">
<return type="void" />
- <argument index="0" name="multimesh" type="MultiMesh" />
- <argument index="1" name="texture" type="Texture2D" />
+ <param index="0" name="multimesh" type="MultiMesh" />
+ <param index="1" name="texture" type="Texture2D" />
<description>
Draws a [MultiMesh] in 2D with the provided texture. See [MultiMeshInstance2D] for related documentation.
</description>
</method>
<method name="draw_polygon">
<return type="void" />
- <argument index="0" name="points" type="PackedVector2Array" />
- <argument index="1" name="colors" type="PackedColorArray" />
- <argument index="2" name="uvs" type="PackedVector2Array" default="PackedVector2Array()" />
- <argument index="3" name="texture" type="Texture2D" default="null" />
+ <param index="0" name="points" type="PackedVector2Array" />
+ <param index="1" name="colors" type="PackedColorArray" />
+ <param index="2" name="uvs" type="PackedVector2Array" default="PackedVector2Array()" />
+ <param index="3" name="texture" type="Texture2D" default="null" />
<description>
- Draws a solid polygon of any amount of points, convex or concave. Unlike [method draw_colored_polygon], each point's color can be changed individually. See also [method draw_polyline] and [method draw_polyline_colors].
+ Draws a solid polygon of any number of points, convex or concave. Unlike [method draw_colored_polygon], each point's color can be changed individually. See also [method draw_polyline] and [method draw_polyline_colors].
</description>
</method>
<method name="draw_polyline">
<return type="void" />
- <argument index="0" name="points" type="PackedVector2Array" />
- <argument index="1" name="color" type="Color" />
- <argument index="2" name="width" type="float" default="1.0" />
- <argument index="3" name="antialiased" type="bool" default="false" />
+ <param index="0" name="points" type="PackedVector2Array" />
+ <param index="1" name="color" type="Color" />
+ <param index="2" name="width" type="float" default="1.0" />
+ <param index="3" name="antialiased" type="bool" default="false" />
<description>
- Draws interconnected line segments with a uniform [code]color[/code] and [code]width[/code] and optional antialiasing. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw disconnected lines, use [method draw_multiline] instead. See also [method draw_polygon].
+ Draws interconnected line segments with a uniform [param color] and [param width] and optional antialiasing. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw disconnected lines, use [method draw_multiline] instead. See also [method draw_polygon].
</description>
</method>
<method name="draw_polyline_colors">
<return type="void" />
- <argument index="0" name="points" type="PackedVector2Array" />
- <argument index="1" name="colors" type="PackedColorArray" />
- <argument index="2" name="width" type="float" default="1.0" />
- <argument index="3" name="antialiased" type="bool" default="false" />
+ <param index="0" name="points" type="PackedVector2Array" />
+ <param index="1" name="colors" type="PackedColorArray" />
+ <param index="2" name="width" type="float" default="1.0" />
+ <param index="3" name="antialiased" type="bool" default="false" />
<description>
- Draws interconnected line segments with a uniform [code]width[/code] and segment-by-segment coloring, and optional antialiasing. Colors assigned to line segments match by index between [code]points[/code] and [code]colors[/code]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw disconnected lines, use [method draw_multiline_colors] instead. See also [method draw_polygon].
+ Draws interconnected line segments with a uniform [param width] and segment-by-segment coloring, and optional antialiasing. Colors assigned to line segments match by index between [param points] and [param colors]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw disconnected lines, use [method draw_multiline_colors] instead. See also [method draw_polygon].
</description>
</method>
<method name="draw_primitive">
<return type="void" />
- <argument index="0" name="points" type="PackedVector2Array" />
- <argument index="1" name="colors" type="PackedColorArray" />
- <argument index="2" name="uvs" type="PackedVector2Array" />
- <argument index="3" name="texture" type="Texture2D" default="null" />
- <argument index="4" name="width" type="float" default="1.0" />
+ <param index="0" name="points" type="PackedVector2Array" />
+ <param index="1" name="colors" type="PackedColorArray" />
+ <param index="2" name="uvs" type="PackedVector2Array" />
+ <param index="3" name="texture" type="Texture2D" default="null" />
+ <param index="4" name="width" type="float" default="1.0" />
<description>
Draws a custom primitive. 1 point for a point, 2 points for a line, 3 points for a triangle, and 4 points for a quad. If 0 points or more than 4 points are specified, nothing will be drawn and an error message will be printed. See also [method draw_line], [method draw_polyline], [method draw_polygon], and [method draw_rect].
</description>
</method>
<method name="draw_rect">
<return type="void" />
- <argument index="0" name="rect" type="Rect2" />
- <argument index="1" name="color" type="Color" />
- <argument index="2" name="filled" type="bool" default="true" />
- <argument index="3" name="width" type="float" default="1.0" />
+ <param index="0" name="rect" type="Rect2" />
+ <param index="1" name="color" type="Color" />
+ <param index="2" name="filled" type="bool" default="true" />
+ <param index="3" name="width" type="float" default="1.0" />
<description>
- Draws a rectangle. If [code]filled[/code] is [code]true[/code], the rectangle will be filled with the [code]color[/code] specified. If [code]filled[/code] is [code]false[/code], the rectangle will be drawn as a stroke with the [code]color[/code] and [code]width[/code] specified.
- [b]Note:[/b] [code]width[/code] is only effective if [code]filled[/code] is [code]false[/code].
+ Draws a rectangle. If [param filled] is [code]true[/code], the rectangle will be filled with the [param color] specified. If [param filled] is [code]false[/code], the rectangle will be drawn as a stroke with the [param color] and [param width] specified.
+ [b]Note:[/b] [param width] is only effective if [param filled] is [code]false[/code].
</description>
</method>
<method name="draw_set_transform">
<return type="void" />
- <argument index="0" name="position" type="Vector2" />
- <argument index="1" name="rotation" type="float" default="0.0" />
- <argument index="2" name="scale" type="Vector2" default="Vector2(1, 1)" />
+ <param index="0" name="position" type="Vector2" />
+ <param index="1" name="rotation" type="float" default="0.0" />
+ <param index="2" name="scale" type="Vector2" default="Vector2(1, 1)" />
<description>
Sets a custom transform for drawing via components. Anything drawn afterwards will be transformed by this.
</description>
</method>
<method name="draw_set_transform_matrix">
<return type="void" />
- <argument index="0" name="xform" type="Transform2D" />
+ <param index="0" name="xform" type="Transform2D" />
<description>
Sets a custom transform for drawing via matrix. Anything drawn afterwards will be transformed by this.
</description>
</method>
<method name="draw_string" qualifiers="const">
<return type="void" />
- <argument index="0" name="font" type="Font" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="text" type="String" />
- <argument index="3" name="alignment" type="int" enum="HorizontalAlignment" default="0" />
- <argument index="4" name="width" type="float" default="-1" />
- <argument index="5" name="font_size" type="int" default="16" />
- <argument index="6" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="7" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
- <argument index="8" name="direction" type="int" enum="TextServer.Direction" default="0" />
- <argument index="9" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
- <description>
- Draws [code]text[/code] using the specified [code]font[/code] at the [code]position[/code] (bottom-left corner using the baseline of the font). The text will have its color multiplied by [code]modulate[/code]. If [code]clip_w[/code] is greater than or equal to 0, the text will be clipped if it exceeds the specified width.
+ <param index="0" name="font" type="Font" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="text" type="String" />
+ <param index="3" name="alignment" type="int" enum="HorizontalAlignment" default="0" />
+ <param index="4" name="width" type="float" default="-1" />
+ <param index="5" name="font_size" type="int" default="16" />
+ <param index="6" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="7" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="8" name="direction" type="int" enum="TextServer.Direction" default="0" />
+ <param index="9" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
+ <description>
+ Draws [param text] using the specified [param font] at the [param pos] (bottom-left corner using the baseline of the font). The text will have its color multiplied by [param modulate]. If [param width] is greater than or equal to 0, the text will be clipped if it exceeds the specified width.
[b]Example using the default project font:[/b]
[codeblocks]
[gdscript]
@@ -310,59 +328,59 @@
</method>
<method name="draw_string_outline" qualifiers="const">
<return type="void" />
- <argument index="0" name="font" type="Font" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="text" type="String" />
- <argument index="3" name="alignment" type="int" enum="HorizontalAlignment" default="0" />
- <argument index="4" name="width" type="float" default="-1" />
- <argument index="5" name="font_size" type="int" default="16" />
- <argument index="6" name="size" type="int" default="1" />
- <argument index="7" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="8" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
- <argument index="9" name="direction" type="int" enum="TextServer.Direction" default="0" />
- <argument index="10" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
+ <param index="0" name="font" type="Font" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="text" type="String" />
+ <param index="3" name="alignment" type="int" enum="HorizontalAlignment" default="0" />
+ <param index="4" name="width" type="float" default="-1" />
+ <param index="5" name="font_size" type="int" default="16" />
+ <param index="6" name="size" type="int" default="1" />
+ <param index="7" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="8" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="9" name="direction" type="int" enum="TextServer.Direction" default="0" />
+ <param index="10" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
- Draws [code]text[/code] outline using the specified [code]font[/code] at the [code]position[/code] (bottom-left corner using the baseline of the font). The text will have its color multiplied by [code]modulate[/code]. If [code]clip_w[/code] is greater than or equal to 0, the text will be clipped if it exceeds the specified width.
+ Draws [param text] outline using the specified [param font] at the [param pos] (bottom-left corner using the baseline of the font). The text will have its color multiplied by [param modulate]. If [param width] is greater than or equal to 0, the text will be clipped if it exceeds the specified width.
</description>
</method>
<method name="draw_style_box">
<return type="void" />
- <argument index="0" name="style_box" type="StyleBox" />
- <argument index="1" name="rect" type="Rect2" />
+ <param index="0" name="style_box" type="StyleBox" />
+ <param index="1" name="rect" type="Rect2" />
<description>
Draws a styled rectangle.
</description>
</method>
<method name="draw_texture">
<return type="void" />
- <argument index="0" name="texture" type="Texture2D" />
- <argument index="1" name="position" type="Vector2" />
- <argument index="2" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="0" name="texture" type="Texture2D" />
+ <param index="1" name="position" type="Vector2" />
+ <param index="2" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
<description>
Draws a texture at a given position.
</description>
</method>
<method name="draw_texture_rect">
<return type="void" />
- <argument index="0" name="texture" type="Texture2D" />
- <argument index="1" name="rect" type="Rect2" />
- <argument index="2" name="tile" type="bool" />
- <argument index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="4" name="transpose" type="bool" default="false" />
+ <param index="0" name="texture" type="Texture2D" />
+ <param index="1" name="rect" type="Rect2" />
+ <param index="2" name="tile" type="bool" />
+ <param index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="4" name="transpose" type="bool" default="false" />
<description>
- Draws a textured rectangle at a given position, optionally modulated by a color. If [code]transpose[/code] is [code]true[/code], the texture will have its X and Y coordinates swapped.
+ Draws a textured rectangle at a given position, optionally modulated by a color. If [param transpose] is [code]true[/code], the texture will have its X and Y coordinates swapped.
</description>
</method>
<method name="draw_texture_rect_region">
<return type="void" />
- <argument index="0" name="texture" type="Texture2D" />
- <argument index="1" name="rect" type="Rect2" />
- <argument index="2" name="src_rect" type="Rect2" />
- <argument index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="4" name="transpose" type="bool" default="false" />
- <argument index="5" name="clip_uv" type="bool" default="true" />
+ <param index="0" name="texture" type="Texture2D" />
+ <param index="1" name="rect" type="Rect2" />
+ <param index="2" name="src_rect" type="Rect2" />
+ <param index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="4" name="transpose" type="bool" default="false" />
+ <param index="5" name="clip_uv" type="bool" default="true" />
<description>
- Draws a textured rectangle region at a given position, optionally modulated by a color. If [code]transpose[/code] is [code]true[/code], the texture will have its X and Y coordinates swapped.
+ Draws a textured rectangle region at a given position, optionally modulated by a color. If [param transpose] is [code]true[/code], the texture will have its X and Y coordinates swapped.
</description>
</method>
<method name="force_update_transform">
@@ -465,35 +483,35 @@
<method name="is_visible_in_tree" qualifiers="const">
<return type="bool" />
<description>
- Returns [code]true[/code] if the node is present in the [SceneTree], its [member visible] property is [code]true[/code] and all its antecedents are also visible. If any antecedent is hidden, this node will not be visible in the scene tree.
+ Returns [code]true[/code] if the node is present in the [SceneTree], its [member visible] property is [code]true[/code] and all its antecedents are also visible. If any antecedent is hidden, this node will not be visible in the scene tree, and is consequently not drawn (see [method _draw]).
</description>
</method>
<method name="make_canvas_position_local" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="screen_point" type="Vector2" />
+ <param index="0" name="screen_point" type="Vector2" />
<description>
- Assigns [code]screen_point[/code] as this node's new local transform.
+ Assigns [param screen_point] as this node's new local transform.
</description>
</method>
<method name="make_input_local" qualifiers="const">
<return type="InputEvent" />
- <argument index="0" name="event" type="InputEvent" />
+ <param index="0" name="event" type="InputEvent" />
<description>
- Transformations issued by [code]event[/code]'s inputs are applied in local space instead of global space.
+ Transformations issued by [param event]'s inputs are applied in local space instead of global space.
</description>
</method>
<method name="set_notify_local_transform">
<return type="void" />
- <argument index="0" name="enable" type="bool" />
+ <param index="0" name="enable" type="bool" />
<description>
- If [code]enable[/code] is [code]true[/code], this node will receive [constant NOTIFICATION_LOCAL_TRANSFORM_CHANGED] when its local transform changes.
+ If [param enable] is [code]true[/code], this node will receive [constant NOTIFICATION_LOCAL_TRANSFORM_CHANGED] when its local transform changes.
</description>
</method>
<method name="set_notify_transform">
<return type="void" />
- <argument index="0" name="enable" type="bool" />
+ <param index="0" name="enable" type="bool" />
<description>
- If [code]enable[/code] is [code]true[/code], this node will receive [constant NOTIFICATION_TRANSFORM_CHANGED] when its global transform changes.
+ If [param enable] is [code]true[/code], this node will receive [constant NOTIFICATION_TRANSFORM_CHANGED] when its global transform changes.
</description>
</method>
<method name="show">
@@ -505,7 +523,7 @@
<method name="update">
<return type="void" />
<description>
- Queue the [CanvasItem] for update. [constant NOTIFICATION_DRAW] will be called on idle time to request redraw.
+ Queues the [CanvasItem] to redraw. During idle time, if [CanvasItem] is visible, [constant NOTIFICATION_DRAW] is sent and [method _draw] is called. This only occurs [b]once[/b] per frame, even if this method has been called multiple times.
</description>
</method>
</methods>
@@ -547,7 +565,8 @@
<signals>
<signal name="draw">
<description>
- Emitted when the [CanvasItem] must redraw. This can only be connected realtime, as deferred will not allow drawing.
+ Emitted when the [CanvasItem] must redraw, [i]after[/i] the related [constant NOTIFICATION_DRAW] notification, and [i]before[/i] [method _draw] is called.
+ [b]Note:[/b] Deferred connections do not allow drawing through the [code]draw_*[/code] methods.
</description>
</signal>
<signal name="hidden">
@@ -574,7 +593,7 @@
The [CanvasItem]'s local transform has changed. This notification is only received if enabled by [method set_notify_local_transform].
</constant>
<constant name="NOTIFICATION_DRAW" value="30">
- The [CanvasItem] is requested to draw.
+ The [CanvasItem] is requested to draw (see [method _draw]).
</constant>
<constant name="NOTIFICATION_VISIBILITY_CHANGED" value="31">
The [CanvasItem]'s visibility has changed.
@@ -601,11 +620,11 @@
The texture filter blends between the nearest 4 pixels and between the nearest 2 mipmaps. Use this for non-pixel art textures that may be viewed at a low scale (e.g. due to [Camera2D] zoom), as mipmaps are important to smooth out pixels that are smaller than on-screen pixels.
</constant>
<constant name="TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC" value="5" enum="TextureFilter">
- The texture filter reads from the nearest pixel, but selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera.
+ The texture filter reads from the nearest pixel, but selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
[b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant TEXTURE_FILTER_NEAREST_WITH_MIPMAPS] is usually more appropriate.
</constant>
<constant name="TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC" value="6" enum="TextureFilter">
- The texture filter blends between the nearest 4 pixels and selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. This is the slowest of the filtering options, but results in the highest quality texturing.
+ The texture filter blends between the nearest 4 pixels and selects a mipmap based on the angle between the surface and the camera view. This reduces artifacts on surfaces that are almost in line with the camera. This is the slowest of the filtering options, but results in the highest quality texturing. The anisotropic filtering level can be changed by adjusting [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
[b]Note:[/b] This texture filter is rarely useful in 2D projects. [constant TEXTURE_FILTER_LINEAR_WITH_MIPMAPS] is usually more appropriate.
</constant>
<constant name="TEXTURE_FILTER_MAX" value="7" enum="TextureFilter">
diff --git a/doc/classes/CanvasItemMaterial.xml b/doc/classes/CanvasItemMaterial.xml
index 22daf79074..59226840bc 100644
--- a/doc/classes/CanvasItemMaterial.xml
+++ b/doc/classes/CanvasItemMaterial.xml
@@ -28,7 +28,7 @@
[b]Note:[/b] This property is only used and visible in the editor if [member particles_animation] is [code]true[/code].
</member>
<member name="particles_animation" type="bool" setter="set_particles_animation" getter="get_particles_animation" default="false">
- If [code]true[/code], enable spritesheet-based animation features when assigned to [GPUParticles2D] and [CPUParticles2D] nodes. The [member ParticlesMaterial.anim_speed_max] or [member CPUParticles2D.anim_speed_max] should also be set to a positive value for the animation to play.
+ If [code]true[/code], enable spritesheet-based animation features when assigned to [GPUParticles2D] and [CPUParticles2D] nodes. The [member ParticleProcessMaterial.anim_speed_max] or [member CPUParticles2D.anim_speed_max] should also be set to a positive value for the animation to play.
This property (and other [code]particles_anim_*[/code] properties that depend on it) has no effect on other types of nodes.
</member>
</members>
diff --git a/doc/classes/CanvasLayer.xml b/doc/classes/CanvasLayer.xml
index ff2c3a8855..555137ac45 100644
--- a/doc/classes/CanvasLayer.xml
+++ b/doc/classes/CanvasLayer.xml
@@ -35,11 +35,11 @@
<member name="custom_viewport" type="Node" setter="set_custom_viewport" getter="get_custom_viewport">
The custom [Viewport] node assigned to the [CanvasLayer]. If [code]null[/code], uses the default viewport instead.
</member>
- <member name="follow_viewport_enable" type="bool" setter="set_follow_viewport" getter="is_following_viewport" default="false">
+ <member name="follow_viewport_enabled" type="bool" setter="set_follow_viewport" getter="is_following_viewport" default="false">
Sets the layer to follow the viewport in order to simulate a pseudo 3D effect.
</member>
<member name="follow_viewport_scale" type="float" setter="set_follow_viewport_scale" getter="get_follow_viewport_scale" default="1.0">
- Scales the layer when using [member follow_viewport_enable]. Layers moving into the foreground should have increasing scales, while layers moving into the background should have decreasing scales.
+ Scales the layer when using [member follow_viewport_enabled]. Layers moving into the foreground should have increasing scales, while layers moving into the background should have decreasing scales.
</member>
<member name="layer" type="int" setter="set_layer" getter="get_layer" default="1">
Layer index for draw order. Lower values are drawn first.
diff --git a/doc/classes/CharacterBody2D.xml b/doc/classes/CharacterBody2D.xml
index 63d493248f..2f8e1a7bb8 100644
--- a/doc/classes/CharacterBody2D.xml
+++ b/doc/classes/CharacterBody2D.xml
@@ -17,9 +17,9 @@
<methods>
<method name="get_floor_angle" qualifiers="const">
<return type="float" />
- <argument index="0" name="up_direction" type="Vector2" default="Vector2(0, -1)" />
+ <param index="0" name="up_direction" type="Vector2" default="Vector2(0, -1)" />
<description>
- Returns the floor's collision angle at the last collision point according to [code]up_direction[/code], which is [code]Vector2.UP[/code] by default. This value is always positive and only valid after calling [method move_and_slide] and when [method is_on_floor] returns [code]true[/code].
+ Returns the floor's collision angle at the last collision point according to [param up_direction], which is [code]Vector2.UP[/code] by default. This value is always positive and only valid after calling [method move_and_slide] and when [method is_on_floor] returns [code]true[/code].
</description>
</method>
<method name="get_floor_normal" qualifiers="const">
@@ -60,7 +60,7 @@
</method>
<method name="get_slide_collision">
<return type="KinematicCollision2D" />
- <argument index="0" name="slide_idx" type="int" />
+ <param index="0" name="slide_idx" type="int" />
<description>
Returns a [KinematicCollision2D], which contains information about a collision that occurred during the last call to [method move_and_slide]. Since the body can collide several times in a single call to [method move_and_slide], you must specify the index of the collision in the range 0 to ([method get_slide_collision_count] - 1).
[b]Example usage:[/b]
@@ -131,7 +131,7 @@
<method name="move_and_slide">
<return type="bool" />
<description>
- Moves the body based on [member velocity]. If the body collides with another, it will slide along the other body (by default only on floor) rather than stop immediately. If the other body is a [CharacterBody2D] or [RigidDynamicBody2D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes.
+ Moves the body based on [member velocity]. If the body collides with another, it will slide along the other body (by default only on floor) rather than stop immediately. If the other body is a [CharacterBody2D] or [RigidBody2D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes.
Modifies [member velocity] if a slide collision occurred. To get the latest collision call [method get_last_slide_collision], for detailed information about collisions that occurred, use [method get_slide_collision].
When the body touches a moving platform, the platform's velocity is automatically added to the body motion. If a collision occurs due to the platform's motion, it will always be first in the slide collisions.
The general behavior and available properties change according to the [member motion_mode].
@@ -140,12 +140,6 @@
</method>
</methods>
<members>
- <member name="collision/safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.08">
- Extra margin used for collision recovery when calling [method move_and_slide].
- If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion.
- A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors.
- A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of character bodies.
- </member>
<member name="floor_block_on_wall" type="bool" setter="set_floor_block_on_wall_enabled" getter="is_floor_block_on_wall_enabled" default="true">
If [code]true[/code], the body will be able to move on the floor only. This option avoids to be able to walk on walls, it will however allow to slide down along them.
</member>
@@ -170,15 +164,21 @@
<member name="motion_mode" type="int" setter="set_motion_mode" getter="get_motion_mode" enum="CharacterBody2D.MotionMode" default="0">
Sets the motion mode which defines the behavior of [method move_and_slide]. See [enum MotionMode] constants for available modes.
</member>
- <member name="moving_platform_apply_velocity_on_leave" type="int" setter="set_moving_platform_apply_velocity_on_leave" getter="get_moving_platform_apply_velocity_on_leave" enum="CharacterBody2D.MovingPlatformApplyVelocityOnLeave" default="0">
- Sets the behavior to apply when you leave a moving platform. By default, to be physically accurate, when you leave the last platform velocity is applied. See [enum MovingPlatformApplyVelocityOnLeave] constants for available behavior.
- </member>
- <member name="moving_platform_floor_layers" type="int" setter="set_moving_platform_floor_layers" getter="get_moving_platform_floor_layers" default="4294967295">
+ <member name="platform_floor_layers" type="int" setter="set_platform_floor_layers" getter="get_platform_floor_layers" default="4294967295">
Collision layers that will be included for detecting floor bodies that will act as moving platforms to be followed by the [CharacterBody2D]. By default, all floor bodies are detected and propagate their velocity.
</member>
- <member name="moving_platform_wall_layers" type="int" setter="set_moving_platform_wall_layers" getter="get_moving_platform_wall_layers" default="0">
+ <member name="platform_on_leave" type="int" setter="set_platform_on_leave" getter="get_platform_on_leave" enum="CharacterBody2D.PlatformOnLeave" default="0">
+ Sets the behavior to apply when you leave a moving platform. By default, to be physically accurate, when you leave the last platform velocity is applied. See [enum PlatformOnLeave] constants for available behavior.
+ </member>
+ <member name="platform_wall_layers" type="int" setter="set_platform_wall_layers" getter="get_platform_wall_layers" default="0">
Collision layers that will be included for detecting wall bodies that will act as moving platforms to be followed by the [CharacterBody2D]. By default, all wall bodies are ignored.
</member>
+ <member name="safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.08">
+ Extra margin used for collision recovery when calling [method move_and_slide].
+ If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion.
+ A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors.
+ A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of character bodies.
+ </member>
<member name="slide_on_ceiling" type="bool" setter="set_slide_on_ceiling_enabled" getter="is_slide_on_ceiling_enabled" default="true">
If [code]true[/code], during a jump against the ceiling, the body will slide, if [code]false[/code] it will be stopped and will fall vertically.
</member>
@@ -199,13 +199,13 @@
<constant name="MOTION_MODE_FLOATING" value="1" enum="MotionMode">
Apply when there is no notion of floor or ceiling. All collisions will be reported as [code]on_wall[/code]. In this mode, when you slide, the speed will always be constant. This mode is suitable for top-down games.
</constant>
- <constant name="PLATFORM_VEL_ON_LEAVE_ALWAYS" value="0" enum="MovingPlatformApplyVelocityOnLeave">
+ <constant name="PLATFORM_ON_LEAVE_ADD_VELOCITY" value="0" enum="PlatformOnLeave">
Add the last platform velocity to the [member velocity] when you leave a moving platform.
</constant>
- <constant name="PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY" value="1" enum="MovingPlatformApplyVelocityOnLeave">
+ <constant name="PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY" value="1" enum="PlatformOnLeave">
Add the last platform velocity to the [member velocity] when you leave a moving platform, but any downward motion is ignored. It's useful to keep full jump height even when the platform is moving down.
</constant>
- <constant name="PLATFORM_VEL_ON_LEAVE_NEVER" value="2" enum="MovingPlatformApplyVelocityOnLeave">
+ <constant name="PLATFORM_ON_LEAVE_DO_NOTHING" value="2" enum="PlatformOnLeave">
Do nothing when leaving a platform.
</constant>
</constants>
diff --git a/doc/classes/CharacterBody3D.xml b/doc/classes/CharacterBody3D.xml
index 795bd7a429..6a1975d40f 100644
--- a/doc/classes/CharacterBody3D.xml
+++ b/doc/classes/CharacterBody3D.xml
@@ -18,9 +18,9 @@
<methods>
<method name="get_floor_angle" qualifiers="const">
<return type="float" />
- <argument index="0" name="up_direction" type="Vector3" default="Vector3(0, 1, 0)" />
+ <param index="0" name="up_direction" type="Vector3" default="Vector3(0, 1, 0)" />
<description>
- Returns the floor's collision angle at the last collision point according to [code]up_direction[/code], which is [code]Vector3.UP[/code] by default. This value is always positive and only valid after calling [method move_and_slide] and when [method is_on_floor] returns [code]true[/code].
+ Returns the floor's collision angle at the last collision point according to [param up_direction], which is [code]Vector3.UP[/code] by default. This value is always positive and only valid after calling [method move_and_slide] and when [method is_on_floor] returns [code]true[/code].
</description>
</method>
<method name="get_floor_normal" qualifiers="const">
@@ -61,7 +61,7 @@
</method>
<method name="get_slide_collision">
<return type="KinematicCollision3D" />
- <argument index="0" name="slide_idx" type="int" />
+ <param index="0" name="slide_idx" type="int" />
<description>
Returns a [KinematicCollision3D], which contains information about a collision that occurred during the last call to [method move_and_slide]. Since the body can collide several times in a single call to [method move_and_slide], you must specify the index of the collision in the range 0 to ([method get_slide_collision_count] - 1).
</description>
@@ -117,7 +117,7 @@
<method name="move_and_slide">
<return type="bool" />
<description>
- Moves the body based on [member velocity]. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [CharacterBody3D] or [RigidDynamicBody3D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes.
+ Moves the body based on [member velocity]. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [CharacterBody3D] or [RigidBody3D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes.
Modifies [member velocity] if a slide collision occurred. To get the latest collision call [method get_last_slide_collision], for more detailed information about collisions that occurred, use [method get_slide_collision].
When the body touches a moving platform, the platform's velocity is automatically added to the body motion. If a collision occurs due to the platform's motion, it will always be first in the slide collisions.
Returns [code]true[/code] if the body collided, otherwise, returns [code]false[/code].
@@ -125,12 +125,6 @@
</method>
</methods>
<members>
- <member name="collision/safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.001">
- Extra margin used for collision recovery when calling [method move_and_slide].
- If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion.
- A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors.
- A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of character bodies.
- </member>
<member name="floor_block_on_wall" type="bool" setter="set_floor_block_on_wall_enabled" getter="is_floor_block_on_wall_enabled" default="true">
If [code]true[/code], the body will be able to move on the floor only. This option avoids to be able to walk on walls, it will however allow to slide down along them.
</member>
@@ -155,15 +149,21 @@
<member name="motion_mode" type="int" setter="set_motion_mode" getter="get_motion_mode" enum="CharacterBody3D.MotionMode" default="0">
Sets the motion mode which defines the behavior of [method move_and_slide]. See [enum MotionMode] constants for available modes.
</member>
- <member name="moving_platform_apply_velocity_on_leave" type="int" setter="set_moving_platform_apply_velocity_on_leave" getter="get_moving_platform_apply_velocity_on_leave" enum="CharacterBody3D.MovingPlatformApplyVelocityOnLeave" default="0">
- Sets the behavior to apply when you leave a moving platform. By default, to be physically accurate, when you leave the last platform velocity is applied. See [enum MovingPlatformApplyVelocityOnLeave] constants for available behavior.
- </member>
- <member name="moving_platform_floor_layers" type="int" setter="set_moving_platform_floor_layers" getter="get_moving_platform_floor_layers" default="4294967295">
+ <member name="platform_floor_layers" type="int" setter="set_platform_floor_layers" getter="get_platform_floor_layers" default="4294967295">
Collision layers that will be included for detecting floor bodies that will act as moving platforms to be followed by the [CharacterBody3D]. By default, all floor bodies are detected and propagate their velocity.
</member>
- <member name="moving_platform_wall_layers" type="int" setter="set_moving_platform_wall_layers" getter="get_moving_platform_wall_layers" default="0">
+ <member name="platform_on_leave" type="int" setter="set_platform_on_leave" getter="get_platform_on_leave" enum="CharacterBody3D.PlatformOnLeave" default="0">
+ Sets the behavior to apply when you leave a moving platform. By default, to be physically accurate, when you leave the last platform velocity is applied. See [enum PlatformOnLeave] constants for available behavior.
+ </member>
+ <member name="platform_wall_layers" type="int" setter="set_platform_wall_layers" getter="get_platform_wall_layers" default="0">
Collision layers that will be included for detecting wall bodies that will act as moving platforms to be followed by the [CharacterBody3D]. By default, all wall bodies are ignored.
</member>
+ <member name="safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.001">
+ Extra margin used for collision recovery when calling [method move_and_slide].
+ If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion.
+ A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors.
+ A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of character bodies.
+ </member>
<member name="slide_on_ceiling" type="bool" setter="set_slide_on_ceiling_enabled" getter="is_slide_on_ceiling_enabled" default="true">
If [code]true[/code], during a jump against the ceiling, the body will slide, if [code]false[/code] it will be stopped and will fall vertically.
</member>
@@ -184,13 +184,13 @@
<constant name="MOTION_MODE_FLOATING" value="1" enum="MotionMode">
Apply when there is no notion of floor or ceiling. All collisions will be reported as [code]on_wall[/code]. In this mode, when you slide, the speed will always be constant. This mode is suitable for games without ground like space games.
</constant>
- <constant name="PLATFORM_VEL_ON_LEAVE_ALWAYS" value="0" enum="MovingPlatformApplyVelocityOnLeave">
+ <constant name="PLATFORM_ON_LEAVE_ADD_VELOCITY" value="0" enum="PlatformOnLeave">
Add the last platform velocity to the [member velocity] when you leave a moving platform.
</constant>
- <constant name="PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY" value="1" enum="MovingPlatformApplyVelocityOnLeave">
+ <constant name="PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY" value="1" enum="PlatformOnLeave">
Add the last platform velocity to the [member velocity] when you leave a moving platform, but any downward motion is ignored. It's useful to keep full jump height even when the platform is moving down.
</constant>
- <constant name="PLATFORM_VEL_ON_LEAVE_NEVER" value="2" enum="MovingPlatformApplyVelocityOnLeave">
+ <constant name="PLATFORM_ON_LEAVE_DO_NOTHING" value="2" enum="PlatformOnLeave">
Do nothing when leaving a platform.
</constant>
</constants>
diff --git a/doc/classes/CheckBox.xml b/doc/classes/CheckBox.xml
index 6483faf763..d39b75ae52 100644
--- a/doc/classes/CheckBox.xml
+++ b/doc/classes/CheckBox.xml
@@ -39,7 +39,7 @@
The vertical offset used when rendering the check icons (in pixels).
</theme_item>
<theme_item name="h_separation" data_type="constant" type="int" default="4">
- The separation between the check icon and the text (in pixels).
+ The separation between the check icon and the text (in pixels). Negative values will be treated as [code]0[/code] when used.
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline.
diff --git a/doc/classes/CheckButton.xml b/doc/classes/CheckButton.xml
index 51b0411f4e..f49da69926 100644
--- a/doc/classes/CheckButton.xml
+++ b/doc/classes/CheckButton.xml
@@ -39,7 +39,7 @@
The vertical offset used when rendering the toggle icons (in pixels).
</theme_item>
<theme_item name="h_separation" data_type="constant" type="int" default="4">
- The separation between the toggle icon and the text (in pixels).
+ The separation between the toggle icon and the text (in pixels). Negative values will be treated as [code]0[/code] when used.
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline.
diff --git a/doc/classes/ClassDB.xml b/doc/classes/ClassDB.xml
index 43210de686..58a536406f 100644
--- a/doc/classes/ClassDB.xml
+++ b/doc/classes/ClassDB.xml
@@ -11,142 +11,142 @@
<methods>
<method name="can_instantiate" qualifiers="const">
<return type="bool" />
- <argument index="0" name="class" type="StringName" />
+ <param index="0" name="class" type="StringName" />
<description>
- Returns [code]true[/code] if you can instance objects from the specified [code]class[/code], [code]false[/code] in other case.
+ Returns [code]true[/code] if you can instance objects from the specified [param class], [code]false[/code] in other case.
</description>
</method>
<method name="class_exists" qualifiers="const">
<return type="bool" />
- <argument index="0" name="class" type="StringName" />
+ <param index="0" name="class" type="StringName" />
<description>
- Returns whether the specified [code]class[/code] is available or not.
+ Returns whether the specified [param class] is available or not.
</description>
</method>
<method name="class_get_enum_constants" qualifiers="const">
<return type="PackedStringArray" />
- <argument index="0" name="class" type="StringName" />
- <argument index="1" name="enum" type="StringName" />
- <argument index="2" name="no_inheritance" type="bool" default="false" />
+ <param index="0" name="class" type="StringName" />
+ <param index="1" name="enum" type="StringName" />
+ <param index="2" name="no_inheritance" type="bool" default="false" />
<description>
- Returns an array with all the keys in [code]enum[/code] of [code]class[/code] or its ancestry.
+ Returns an array with all the keys in [param enum] of [param class] or its ancestry.
</description>
</method>
<method name="class_get_enum_list" qualifiers="const">
<return type="PackedStringArray" />
- <argument index="0" name="class" type="StringName" />
- <argument index="1" name="no_inheritance" type="bool" default="false" />
+ <param index="0" name="class" type="StringName" />
+ <param index="1" name="no_inheritance" type="bool" default="false" />
<description>
- Returns an array with all the enums of [code]class[/code] or its ancestry.
+ Returns an array with all the enums of [param class] or its ancestry.
</description>
</method>
<method name="class_get_integer_constant" qualifiers="const">
<return type="int" />
- <argument index="0" name="class" type="StringName" />
- <argument index="1" name="name" type="StringName" />
+ <param index="0" name="class" type="StringName" />
+ <param index="1" name="name" type="StringName" />
<description>
- Returns the value of the integer constant [code]name[/code] of [code]class[/code] or its ancestry. Always returns 0 when the constant could not be found.
+ Returns the value of the integer constant [param name] of [param class] or its ancestry. Always returns 0 when the constant could not be found.
</description>
</method>
<method name="class_get_integer_constant_enum" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="class" type="StringName" />
- <argument index="1" name="name" type="StringName" />
- <argument index="2" name="no_inheritance" type="bool" default="false" />
+ <param index="0" name="class" type="StringName" />
+ <param index="1" name="name" type="StringName" />
+ <param index="2" name="no_inheritance" type="bool" default="false" />
<description>
- Returns which enum the integer constant [code]name[/code] of [code]class[/code] or its ancestry belongs to.
+ Returns which enum the integer constant [param name] of [param class] or its ancestry belongs to.
</description>
</method>
<method name="class_get_integer_constant_list" qualifiers="const">
<return type="PackedStringArray" />
- <argument index="0" name="class" type="StringName" />
- <argument index="1" name="no_inheritance" type="bool" default="false" />
+ <param index="0" name="class" type="StringName" />
+ <param index="1" name="no_inheritance" type="bool" default="false" />
<description>
- Returns an array with the names all the integer constants of [code]class[/code] or its ancestry.
+ Returns an array with the names all the integer constants of [param class] or its ancestry.
</description>
</method>
<method name="class_get_method_list" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="class" type="StringName" />
- <argument index="1" name="no_inheritance" type="bool" default="false" />
+ <return type="Dictionary[]" />
+ <param index="0" name="class" type="StringName" />
+ <param index="1" name="no_inheritance" type="bool" default="false" />
<description>
- Returns an array with all the methods of [code]class[/code] or its ancestry if [code]no_inheritance[/code] is [code]false[/code]. Every element of the array is a [Dictionary] with the following keys: [code]args[/code], [code]default_args[/code], [code]flags[/code], [code]id[/code], [code]name[/code], [code]return: (class_name, hint, hint_string, name, type, usage)[/code].
+ Returns an array with all the methods of [param class] or its ancestry if [param no_inheritance] is [code]false[/code]. Every element of the array is a [Dictionary] with the following keys: [code]args[/code], [code]default_args[/code], [code]flags[/code], [code]id[/code], [code]name[/code], [code]return: (class_name, hint, hint_string, name, type, usage)[/code].
[b]Note:[/b] In exported release builds the debug info is not available, so the returned dictionaries will contain only method names.
</description>
</method>
<method name="class_get_property" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="object" type="Object" />
- <argument index="1" name="property" type="StringName" />
+ <param index="0" name="object" type="Object" />
+ <param index="1" name="property" type="StringName" />
<description>
- Returns the value of [code]property[/code] of [code]class[/code] or its ancestry.
+ Returns the value of [param property] of [param object] or its ancestry.
</description>
</method>
<method name="class_get_property_list" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="class" type="StringName" />
- <argument index="1" name="no_inheritance" type="bool" default="false" />
+ <return type="Dictionary[]" />
+ <param index="0" name="class" type="StringName" />
+ <param index="1" name="no_inheritance" type="bool" default="false" />
<description>
- Returns an array with all the properties of [code]class[/code] or its ancestry if [code]no_inheritance[/code] is [code]false[/code].
+ Returns an array with all the properties of [param class] or its ancestry if [param no_inheritance] is [code]false[/code].
</description>
</method>
<method name="class_get_signal" qualifiers="const">
<return type="Dictionary" />
- <argument index="0" name="class" type="StringName" />
- <argument index="1" name="signal" type="StringName" />
+ <param index="0" name="class" type="StringName" />
+ <param index="1" name="signal" type="StringName" />
<description>
- Returns the [code]signal[/code] data of [code]class[/code] or its ancestry. The returned value is a [Dictionary] with the following keys: [code]args[/code], [code]default_args[/code], [code]flags[/code], [code]id[/code], [code]name[/code], [code]return: (class_name, hint, hint_string, name, type, usage)[/code].
+ Returns the [param signal] data of [param class] or its ancestry. The returned value is a [Dictionary] with the following keys: [code]args[/code], [code]default_args[/code], [code]flags[/code], [code]id[/code], [code]name[/code], [code]return: (class_name, hint, hint_string, name, type, usage)[/code].
</description>
</method>
<method name="class_get_signal_list" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="class" type="StringName" />
- <argument index="1" name="no_inheritance" type="bool" default="false" />
+ <return type="Dictionary[]" />
+ <param index="0" name="class" type="StringName" />
+ <param index="1" name="no_inheritance" type="bool" default="false" />
<description>
- Returns an array with all the signals of [code]class[/code] or its ancestry if [code]no_inheritance[/code] is [code]false[/code]. Every element of the array is a [Dictionary] as described in [method class_get_signal].
+ Returns an array with all the signals of [param class] or its ancestry if [param no_inheritance] is [code]false[/code]. Every element of the array is a [Dictionary] as described in [method class_get_signal].
</description>
</method>
<method name="class_has_enum" qualifiers="const">
<return type="bool" />
- <argument index="0" name="class" type="StringName" />
- <argument index="1" name="name" type="StringName" />
- <argument index="2" name="no_inheritance" type="bool" default="false" />
+ <param index="0" name="class" type="StringName" />
+ <param index="1" name="name" type="StringName" />
+ <param index="2" name="no_inheritance" type="bool" default="false" />
<description>
- Returns whether [code]class[/code] or its ancestry has an enum called [code]name[/code] or not.
+ Returns whether [param class] or its ancestry has an enum called [param name] or not.
</description>
</method>
<method name="class_has_integer_constant" qualifiers="const">
<return type="bool" />
- <argument index="0" name="class" type="StringName" />
- <argument index="1" name="name" type="StringName" />
+ <param index="0" name="class" type="StringName" />
+ <param index="1" name="name" type="StringName" />
<description>
- Returns whether [code]class[/code] or its ancestry has an integer constant called [code]name[/code] or not.
+ Returns whether [param class] or its ancestry has an integer constant called [param name] or not.
</description>
</method>
<method name="class_has_method" qualifiers="const">
<return type="bool" />
- <argument index="0" name="class" type="StringName" />
- <argument index="1" name="method" type="StringName" />
- <argument index="2" name="no_inheritance" type="bool" default="false" />
+ <param index="0" name="class" type="StringName" />
+ <param index="1" name="method" type="StringName" />
+ <param index="2" name="no_inheritance" type="bool" default="false" />
<description>
- Returns whether [code]class[/code] (or its ancestry if [code]no_inheritance[/code] is [code]false[/code]) has a method called [code]method[/code] or not.
+ Returns whether [param class] (or its ancestry if [param no_inheritance] is [code]false[/code]) has a method called [param method] or not.
</description>
</method>
<method name="class_has_signal" qualifiers="const">
<return type="bool" />
- <argument index="0" name="class" type="StringName" />
- <argument index="1" name="signal" type="StringName" />
+ <param index="0" name="class" type="StringName" />
+ <param index="1" name="signal" type="StringName" />
<description>
- Returns whether [code]class[/code] or its ancestry has a signal called [code]signal[/code] or not.
+ Returns whether [param class] or its ancestry has a signal called [param signal] or not.
</description>
</method>
<method name="class_set_property" qualifiers="const">
<return type="int" enum="Error" />
- <argument index="0" name="object" type="Object" />
- <argument index="1" name="property" type="StringName" />
- <argument index="2" name="value" type="Variant" />
+ <param index="0" name="object" type="Object" />
+ <param index="1" name="property" type="StringName" />
+ <param index="2" name="value" type="Variant" />
<description>
- Sets [code]property[/code] value of [code]class[/code] to [code]value[/code].
+ Sets [param property] value of [param object] to [param value].
</description>
</method>
<method name="get_class_list" qualifiers="const">
@@ -157,38 +157,38 @@
</method>
<method name="get_inheriters_from_class" qualifiers="const">
<return type="PackedStringArray" />
- <argument index="0" name="class" type="StringName" />
+ <param index="0" name="class" type="StringName" />
<description>
- Returns the names of all the classes that directly or indirectly inherit from [code]class[/code].
+ Returns the names of all the classes that directly or indirectly inherit from [param class].
</description>
</method>
<method name="get_parent_class" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="class" type="StringName" />
+ <param index="0" name="class" type="StringName" />
<description>
- Returns the parent class of [code]class[/code].
+ Returns the parent class of [param class].
</description>
</method>
<method name="instantiate" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="class" type="StringName" />
+ <param index="0" name="class" type="StringName" />
<description>
- Creates an instance of [code]class[/code].
+ Creates an instance of [param class].
</description>
</method>
<method name="is_class_enabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="class" type="StringName" />
+ <param index="0" name="class" type="StringName" />
<description>
- Returns whether this [code]class[/code] is enabled or not.
+ Returns whether this [param class] is enabled or not.
</description>
</method>
<method name="is_parent_class" qualifiers="const">
<return type="bool" />
- <argument index="0" name="class" type="StringName" />
- <argument index="1" name="inherits" type="StringName" />
+ <param index="0" name="class" type="StringName" />
+ <param index="1" name="inherits" type="StringName" />
<description>
- Returns whether [code]inherits[/code] is an ancestor of [code]class[/code] or not.
+ Returns whether [param inherits] is an ancestor of [param class] or not.
</description>
</method>
</methods>
diff --git a/doc/classes/CodeEdit.xml b/doc/classes/CodeEdit.xml
index 4994ef352e..ca482a39e0 100644
--- a/doc/classes/CodeEdit.xml
+++ b/doc/classes/CodeEdit.xml
@@ -12,30 +12,30 @@
<methods>
<method name="_confirm_code_completion" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="replace" type="bool" />
+ <param index="0" name="replace" type="bool" />
<description>
- Override this method to define how the selected entry should be inserted. If [code]replace[/code] is true, any existing text should be replaced.
+ Override this method to define how the selected entry should be inserted. If [param replace] is true, any existing text should be replaced.
</description>
</method>
<method name="_filter_code_completion_candidates" qualifiers="virtual const">
- <return type="Array" />
- <argument index="0" name="candidates" type="Dictionary[]" />
+ <return type="Dictionary[]" />
+ <param index="0" name="candidates" type="Dictionary[]" />
<description>
- Override this method to define what items in [code]candidates[/code] should be displayed.
- Both [code]candidates[/code] and the return is a [Array] of [Dictionary], see [method get_code_completion_option] for [Dictionary] content.
+ Override this method to define what items in [param candidates] should be displayed.
+ Both [param candidates] and the return is a [Array] of [Dictionary], see [method get_code_completion_option] for [Dictionary] content.
</description>
</method>
<method name="_request_code_completion" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="force" type="bool" />
+ <param index="0" name="force" type="bool" />
<description>
- Override this method to define what happens when the user requests code completion. If [code]force[/code] is true, any checks should be bypassed.
+ Override this method to define what happens when the user requests code completion. If [param force] is true, any checks should be bypassed.
</description>
</method>
<method name="add_auto_brace_completion_pair">
<return type="void" />
- <argument index="0" name="start_key" type="String" />
- <argument index="1" name="end_key" type="String" />
+ <param index="0" name="start_key" type="String" />
+ <param index="1" name="end_key" type="String" />
<description>
Adds a brace pair.
Both the start and end keys must be symbols. Only the start key has to be unique.
@@ -43,12 +43,12 @@
</method>
<method name="add_code_completion_option">
<return type="void" />
- <argument index="0" name="type" type="int" enum="CodeEdit.CodeCompletionKind" />
- <argument index="1" name="display_text" type="String" />
- <argument index="2" name="insert_text" type="String" />
- <argument index="3" name="text_color" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="4" name="icon" type="Resource" default="null" />
- <argument index="5" name="value" type="Variant" default="0" />
+ <param index="0" name="type" type="int" enum="CodeEdit.CodeCompletionKind" />
+ <param index="1" name="display_text" type="String" />
+ <param index="2" name="insert_text" type="String" />
+ <param index="3" name="text_color" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="4" name="icon" type="Resource" default="null" />
+ <param index="5" name="value" type="Variant" default="0" />
<description>
Submits an item to the queue of potential candidates for the autocomplete menu. Call [method update_code_completion_options] to update the list.
[b]Note:[/b] This list will replace all current candidates.
@@ -56,9 +56,9 @@
</method>
<method name="add_comment_delimiter">
<return type="void" />
- <argument index="0" name="start_key" type="String" />
- <argument index="1" name="end_key" type="String" />
- <argument index="2" name="line_only" type="bool" default="false" />
+ <param index="0" name="start_key" type="String" />
+ <param index="1" name="end_key" type="String" />
+ <param index="2" name="line_only" type="bool" default="false" />
<description>
Adds a comment delimiter.
Both the start and end keys must be symbols. Only the start key has to be unique.
@@ -67,9 +67,9 @@
</method>
<method name="add_string_delimiter">
<return type="void" />
- <argument index="0" name="start_key" type="String" />
- <argument index="1" name="end_key" type="String" />
- <argument index="2" name="line_only" type="bool" default="false" />
+ <param index="0" name="start_key" type="String" />
+ <param index="1" name="end_key" type="String" />
+ <param index="2" name="line_only" type="bool" default="false" />
<description>
Adds a string delimiter.
Both the start and end keys must be symbols. Only the start key has to be unique.
@@ -78,7 +78,7 @@
</method>
<method name="can_fold_line" qualifiers="const">
<return type="bool" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns if the given line is foldable, that is, it has indented lines right below it or a comment / string block.
</description>
@@ -121,9 +121,9 @@
</method>
<method name="confirm_code_completion">
<return type="void" />
- <argument index="0" name="replace" type="bool" default="false" />
+ <param index="0" name="replace" type="bool" default="false" />
<description>
- Inserts the selected entry into the text. If [code]replace[/code] is true, any existing text is replaced rather then merged.
+ Inserts the selected entry into the text. If [param replace] is true, any existing text is replaced rather then merged.
</description>
</method>
<method name="do_indent">
@@ -146,35 +146,35 @@
</method>
<method name="fold_line">
<return type="void" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Folds the given line, if possible (see [method can_fold_line]).
</description>
</method>
<method name="get_auto_brace_completion_close_key" qualifiers="const">
<return type="String" />
- <argument index="0" name="open_key" type="String" />
+ <param index="0" name="open_key" type="String" />
<description>
- Gets the matching auto brace close key for [code]open_key[/code].
+ Gets the matching auto brace close key for [param open_key].
</description>
</method>
<method name="get_bookmarked_lines" qualifiers="const">
- <return type="Array" />
+ <return type="PackedInt32Array" />
<description>
Gets all bookmarked lines.
</description>
</method>
<method name="get_breakpointed_lines" qualifiers="const">
- <return type="Array" />
+ <return type="PackedInt32Array" />
<description>
Gets all breakpointed lines.
</description>
</method>
<method name="get_code_completion_option" qualifiers="const">
<return type="Dictionary" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Gets the completion option at [code]index[/code]. The return [Dictionary] has the following key-values:
+ Gets the completion option at [param index]. The return [Dictionary] has the following key-values:
[code]kind[/code]: [enum CodeCompletionKind]
[code]display_text[/code]: Text that is shown on the autocomplete menu.
[code]insert_text[/code]: Text that is to be inserted when this item is selected.
@@ -197,36 +197,36 @@
</method>
<method name="get_delimiter_end_key" qualifiers="const">
<return type="String" />
- <argument index="0" name="delimiter_index" type="int" />
+ <param index="0" name="delimiter_index" type="int" />
<description>
Gets the end key for a string or comment region index.
</description>
</method>
<method name="get_delimiter_end_position" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="column" type="int" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="column" type="int" />
<description>
- If [code]line[/code] [code]column[/code] is in a string or comment, returns the end position of the region. If not or no end could be found, both [Vector2] values will be [code]-1[/code].
+ If [param line] [param column] is in a string or comment, returns the end position of the region. If not or no end could be found, both [Vector2] values will be [code]-1[/code].
</description>
</method>
<method name="get_delimiter_start_key" qualifiers="const">
<return type="String" />
- <argument index="0" name="delimiter_index" type="int" />
+ <param index="0" name="delimiter_index" type="int" />
<description>
Gets the start key for a string or comment region index.
</description>
</method>
<method name="get_delimiter_start_position" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="column" type="int" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="column" type="int" />
<description>
- If [code]line[/code] [code]column[/code] is in a string or comment, returns the start position of the region. If not or no start could be found, both [Vector2] values will be [code]-1[/code].
+ If [param line] [param column] is in a string or comment, returns the start position of the region. If not or no start could be found, both [Vector2] values will be [code]-1[/code].
</description>
</method>
<method name="get_executing_lines" qualifiers="const">
- <return type="Array" />
+ <return type="PackedInt32Array" />
<description>
Gets all executing lines.
</description>
@@ -251,30 +251,30 @@
</method>
<method name="has_auto_brace_completion_close_key" qualifiers="const">
<return type="bool" />
- <argument index="0" name="close_key" type="String" />
+ <param index="0" name="close_key" type="String" />
<description>
- Returns [code]true[/code] if close key [code]close_key[/code] exists.
+ Returns [code]true[/code] if close key [param close_key] exists.
</description>
</method>
<method name="has_auto_brace_completion_open_key" qualifiers="const">
<return type="bool" />
- <argument index="0" name="open_key" type="String" />
+ <param index="0" name="open_key" type="String" />
<description>
- Returns [code]true[/code] if open key [code]open_key[/code] exists.
+ Returns [code]true[/code] if open key [param open_key] exists.
</description>
</method>
<method name="has_comment_delimiter" qualifiers="const">
<return type="bool" />
- <argument index="0" name="start_key" type="String" />
+ <param index="0" name="start_key" type="String" />
<description>
- Returns [code]true[/code] if comment [code]start_key[/code] exists.
+ Returns [code]true[/code] if comment [param start_key] exists.
</description>
</method>
<method name="has_string_delimiter" qualifiers="const">
<return type="bool" />
- <argument index="0" name="start_key" type="String" />
+ <param index="0" name="start_key" type="String" />
<description>
- Returns [code]true[/code] if string [code]start_key[/code] exists.
+ Returns [code]true[/code] if string [param start_key] exists.
</description>
</method>
<method name="indent_lines">
@@ -285,124 +285,124 @@
</method>
<method name="is_in_comment" qualifiers="const">
<return type="int" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="column" type="int" default="-1" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="column" type="int" default="-1" />
<description>
- Returns delimiter index if [code]line[/code] [code]column[/code] is in a comment. If [code]column[/code] is not provided, will return delimiter index if the entire [code]line[/code] is a comment. Otherwise [code]-1[/code].
+ Returns delimiter index if [param line] [param column] is in a comment. If [param column] is not provided, will return delimiter index if the entire [param line] is a comment. Otherwise [code]-1[/code].
</description>
</method>
<method name="is_in_string" qualifiers="const">
<return type="int" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="column" type="int" default="-1" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="column" type="int" default="-1" />
<description>
- Returns the delimiter index if [code]line[/code] [code]column[/code] is in a string. If [code]column[/code] is not provided, will return the delimiter index if the entire [code]line[/code] is a string. Otherwise [code]-1[/code].
+ Returns the delimiter index if [param line] [param column] is in a string. If [param column] is not provided, will return the delimiter index if the entire [param line] is a string. Otherwise [code]-1[/code].
</description>
</method>
<method name="is_line_bookmarked" qualifiers="const">
<return type="bool" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns whether the line at the specified index is bookmarked or not.
</description>
</method>
<method name="is_line_breakpointed" qualifiers="const">
<return type="bool" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns whether the line at the specified index is breakpointed or not.
</description>
</method>
<method name="is_line_executing" qualifiers="const">
<return type="bool" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns whether the line at the specified index is marked as executing or not.
</description>
</method>
<method name="is_line_folded" qualifiers="const">
<return type="bool" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns whether the line at the specified index is folded or not.
</description>
</method>
<method name="remove_comment_delimiter">
<return type="void" />
- <argument index="0" name="start_key" type="String" />
+ <param index="0" name="start_key" type="String" />
<description>
- Removes the comment delimiter with [code]start_key[/code].
+ Removes the comment delimiter with [param start_key].
</description>
</method>
<method name="remove_string_delimiter">
<return type="void" />
- <argument index="0" name="start_key" type="String" />
+ <param index="0" name="start_key" type="String" />
<description>
- Removes the string delimiter with [code]start_key[/code].
+ Removes the string delimiter with [param start_key].
</description>
</method>
<method name="request_code_completion">
<return type="void" />
- <argument index="0" name="force" type="bool" default="false" />
+ <param index="0" name="force" type="bool" default="false" />
<description>
- Emits [signal code_completion_requested], if [code]force[/code] is true will bypass all checks. Otherwise will check that the caret is in a word or in front of a prefix. Will ignore the request if all current options are of type file path, node path or signal.
+ Emits [signal code_completion_requested], if [param force] is true will bypass all checks. Otherwise will check that the caret is in a word or in front of a prefix. Will ignore the request if all current options are of type file path, node path or signal.
</description>
</method>
<method name="set_code_completion_selected_index">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Sets the current selected completion option.
</description>
</method>
<method name="set_code_hint">
<return type="void" />
- <argument index="0" name="code_hint" type="String" />
+ <param index="0" name="code_hint" type="String" />
<description>
Sets the code hint text. Pass an empty string to clear.
</description>
</method>
<method name="set_code_hint_draw_below">
<return type="void" />
- <argument index="0" name="draw_below" type="bool" />
+ <param index="0" name="draw_below" type="bool" />
<description>
Sets if the code hint should draw below the text.
</description>
</method>
<method name="set_line_as_bookmarked">
<return type="void" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="bookmarked" type="bool" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="bookmarked" type="bool" />
<description>
Sets the line as bookmarked.
</description>
</method>
<method name="set_line_as_breakpoint">
<return type="void" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="breakpointed" type="bool" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="breakpointed" type="bool" />
<description>
Sets the line as breakpointed.
</description>
</method>
<method name="set_line_as_executing">
<return type="void" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="executing" type="bool" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="executing" type="bool" />
<description>
Sets the line as executing.
</description>
</method>
<method name="set_symbol_lookup_word_as_valid">
<return type="void" />
- <argument index="0" name="valid" type="bool" />
+ <param index="0" name="valid" type="bool" />
<description>
Sets the symbol emitted by [signal symbol_validate] as a valid lookup.
</description>
</method>
<method name="toggle_foldable_line">
<return type="void" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Toggle the folding of the code block at the given line.
</description>
@@ -415,7 +415,7 @@
</method>
<method name="unfold_line">
<return type="void" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Unfolds all lines that were previously folded.
</description>
@@ -428,9 +428,9 @@
</method>
<method name="update_code_completion_options">
<return type="void" />
- <argument index="0" name="force" type="bool" />
+ <param index="0" name="force" type="bool" />
<description>
- Submits all completion options added with [method add_code_completion_option]. Will try to force the autoccomplete menu to popup, if [code]force[/code] is [code]true[/code].
+ Submits all completion options added with [method add_code_completion_option]. Will try to force the autoccomplete menu to popup, if [param force] is [code]true[/code].
[b]Note:[/b] This will replace all current candidates.
</description>
</method>
@@ -482,7 +482,7 @@
Prefixes to trigger an automatic indent.
</member>
<member name="indent_size" type="int" setter="set_indent_size" getter="get_indent_size" default="4">
- Size of tabs, if [code]indent_use_spaces[/code] is enabled the amount of spaces to use.
+ Size of tabs, if [code]indent_use_spaces[/code] is enabled the number of spaces to use.
</member>
<member name="indent_use_spaces" type="bool" setter="set_indent_using_spaces" getter="is_indent_using_spaces" default="false">
Use spaces instead of tabs for indentation.
@@ -501,7 +501,7 @@
</members>
<signals>
<signal name="breakpoint_toggled">
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Emitted when a breakpoint is added or removed from a line. If the line is moved via backspace a removed is emitted at the old line.
</description>
@@ -512,15 +512,15 @@
</description>
</signal>
<signal name="symbol_lookup">
- <argument index="0" name="symbol" type="String" />
- <argument index="1" name="line" type="int" />
- <argument index="2" name="column" type="int" />
+ <param index="0" name="symbol" type="String" />
+ <param index="1" name="line" type="int" />
+ <param index="2" name="column" type="int" />
<description>
Emitted when the user has clicked on a valid symbol.
</description>
</signal>
<signal name="symbol_validate">
- <argument index="0" name="symbol" type="String" />
+ <param index="0" name="symbol" type="String" />
<description>
Emitted when the user hovers over a symbol. The symbol should be validated and responded to, by calling [method set_symbol_lookup_word_as_valid].
</description>
diff --git a/doc/classes/CodeHighlighter.xml b/doc/classes/CodeHighlighter.xml
index b4bde1d00b..fd1f595fc6 100644
--- a/doc/classes/CodeHighlighter.xml
+++ b/doc/classes/CodeHighlighter.xml
@@ -11,10 +11,10 @@
<methods>
<method name="add_color_region">
<return type="void" />
- <argument index="0" name="start_key" type="String" />
- <argument index="1" name="end_key" type="String" />
- <argument index="2" name="color" type="Color" />
- <argument index="3" name="line_only" type="bool" default="false" />
+ <param index="0" name="start_key" type="String" />
+ <param index="1" name="end_key" type="String" />
+ <param index="2" name="color" type="Color" />
+ <param index="3" name="line_only" type="bool" default="false" />
<description>
Adds a color region such as comments or strings.
Both the start and end keys must be symbols. Only the start key has to be unique.
@@ -23,8 +23,8 @@
</method>
<method name="add_keyword_color">
<return type="void" />
- <argument index="0" name="keyword" type="String" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="keyword" type="String" />
+ <param index="1" name="color" type="Color" />
<description>
Sets the color for a keyword.
The keyword cannot contain any symbols except '_'.
@@ -32,8 +32,8 @@
</method>
<method name="add_member_keyword_color">
<return type="void" />
- <argument index="0" name="member_keyword" type="String" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="member_keyword" type="String" />
+ <param index="1" name="color" type="Color" />
<description>
Sets the color for a member keyword.
The member keyword cannot contain any symbols except '_'.
@@ -60,56 +60,56 @@
</method>
<method name="get_keyword_color" qualifiers="const">
<return type="Color" />
- <argument index="0" name="keyword" type="String" />
+ <param index="0" name="keyword" type="String" />
<description>
Returns the color for a keyword.
</description>
</method>
<method name="get_member_keyword_color" qualifiers="const">
<return type="Color" />
- <argument index="0" name="member_keyword" type="String" />
+ <param index="0" name="member_keyword" type="String" />
<description>
Returns the color for a member keyword.
</description>
</method>
<method name="has_color_region" qualifiers="const">
<return type="bool" />
- <argument index="0" name="start_key" type="String" />
+ <param index="0" name="start_key" type="String" />
<description>
Returns [code]true[/code] if the start key exists, else [code]false[/code].
</description>
</method>
<method name="has_keyword_color" qualifiers="const">
<return type="bool" />
- <argument index="0" name="keyword" type="String" />
+ <param index="0" name="keyword" type="String" />
<description>
Returns [code]true[/code] if the keyword exists, else [code]false[/code].
</description>
</method>
<method name="has_member_keyword_color" qualifiers="const">
<return type="bool" />
- <argument index="0" name="member_keyword" type="String" />
+ <param index="0" name="member_keyword" type="String" />
<description>
Returns [code]true[/code] if the member keyword exists, else [code]false[/code].
</description>
</method>
<method name="remove_color_region">
<return type="void" />
- <argument index="0" name="start_key" type="String" />
+ <param index="0" name="start_key" type="String" />
<description>
Removes the color region that uses that start key.
</description>
</method>
<method name="remove_keyword_color">
<return type="void" />
- <argument index="0" name="keyword" type="String" />
+ <param index="0" name="keyword" type="String" />
<description>
Removes the keyword.
</description>
</method>
<method name="remove_member_keyword_color">
<return type="void" />
- <argument index="0" name="member_keyword" type="String" />
+ <param index="0" name="member_keyword" type="String" />
<description>
Removes the member keyword.
</description>
diff --git a/doc/classes/CollisionObject2D.xml b/doc/classes/CollisionObject2D.xml
index 95d99855f6..ee69015ae1 100644
--- a/doc/classes/CollisionObject2D.xml
+++ b/doc/classes/CollisionObject2D.xml
@@ -12,33 +12,59 @@
<methods>
<method name="_input_event" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="viewport" type="Viewport" />
- <argument index="1" name="event" type="InputEvent" />
- <argument index="2" name="shape_idx" type="int" />
+ <param index="0" name="viewport" type="Viewport" />
+ <param index="1" name="event" type="InputEvent" />
+ <param index="2" name="shape_idx" type="int" />
<description>
- Accepts unhandled [InputEvent]s. [code]shape_idx[/code] is the child index of the clicked [Shape2D]. Connect to the [code]input_event[/code] signal to easily pick up these events.
+ Accepts unhandled [InputEvent]s. [param shape_idx] is the child index of the clicked [Shape2D]. Connect to the [code]input_event[/code] signal to easily pick up these events.
[b]Note:[/b] [method _input_event] requires [member input_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set.
</description>
</method>
+ <method name="_mouse_enter" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Called when the mouse pointer enters any of this object's shapes. Requires [member input_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set. Note that moving between different shapes within a single [CollisionObject2D] won't cause this function to be called.
+ </description>
+ </method>
+ <method name="_mouse_exit" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Called when the mouse pointer exits all this object's shapes. Requires [member input_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set. Note that moving between different shapes within a single [CollisionObject2D] won't cause this function to be called.
+ </description>
+ </method>
+ <method name="_mouse_shape_enter" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="shape_idx" type="int" />
+ <description>
+ Called when the mouse pointer enters any of this object's shapes or moves from one shape to another. [param shape_idx] is the child index of the newly entered [Shape2D]. Requires [member input_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be called.
+ </description>
+ </method>
+ <method name="_mouse_shape_exit" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="shape_idx" type="int" />
+ <description>
+ Called when the mouse pointer exits any of this object's shapes. [param shape_idx] is the child index of the exited [Shape2D]. Requires [member input_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be called.
+ </description>
+ </method>
<method name="create_shape_owner">
<return type="int" />
- <argument index="0" name="owner" type="Object" />
+ <param index="0" name="owner" type="Object" />
<description>
Creates a new shape owner for the given object. Returns [code]owner_id[/code] of the new owner for future reference.
</description>
</method>
<method name="get_collision_layer_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
- Returns whether or not the specified layer of the [member collision_layer] is enabled, given a [code]layer_number[/code] between 1 and 32.
+ Returns whether or not the specified layer of the [member collision_layer] is enabled, given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
- Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
+ Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="get_rid" qualifiers="const">
@@ -49,149 +75,149 @@
</method>
<method name="get_shape_owner_one_way_collision_margin" qualifiers="const">
<return type="float" />
- <argument index="0" name="owner_id" type="int" />
+ <param index="0" name="owner_id" type="int" />
<description>
- Returns the [code]one_way_collision_margin[/code] of the shape owner identified by given [code]owner_id[/code].
+ Returns the [code]one_way_collision_margin[/code] of the shape owner identified by given [param owner_id].
</description>
</method>
<method name="get_shape_owners">
- <return type="Array" />
+ <return type="PackedInt32Array" />
<description>
Returns an [Array] of [code]owner_id[/code] identifiers. You can use these ids in other methods that take [code]owner_id[/code] as an argument.
</description>
</method>
<method name="is_shape_owner_disabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="owner_id" type="int" />
+ <param index="0" name="owner_id" type="int" />
<description>
If [code]true[/code], the shape owner and its shapes are disabled.
</description>
</method>
<method name="is_shape_owner_one_way_collision_enabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="owner_id" type="int" />
+ <param index="0" name="owner_id" type="int" />
<description>
Returns [code]true[/code] if collisions for the shape owner originating from this [CollisionObject2D] will not be reported to collided with [CollisionObject2D]s.
</description>
</method>
<method name="remove_shape_owner">
<return type="void" />
- <argument index="0" name="owner_id" type="int" />
+ <param index="0" name="owner_id" type="int" />
<description>
Removes the given shape owner.
</description>
</method>
<method name="set_collision_layer_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
- Based on [code]value[/code], enables or disables the specified layer in the [member collision_layer], given a [code]layer_number[/code] between 1 and 32.
+ Based on [param value], enables or disables the specified layer in the [member collision_layer], given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="set_collision_mask_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
- Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
+ Based on [param value], enables or disables the specified layer in the [member collision_mask], given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="shape_find_owner" qualifiers="const">
<return type="int" />
- <argument index="0" name="shape_index" type="int" />
+ <param index="0" name="shape_index" type="int" />
<description>
Returns the [code]owner_id[/code] of the given shape.
</description>
</method>
<method name="shape_owner_add_shape">
<return type="void" />
- <argument index="0" name="owner_id" type="int" />
- <argument index="1" name="shape" type="Shape2D" />
+ <param index="0" name="owner_id" type="int" />
+ <param index="1" name="shape" type="Shape2D" />
<description>
Adds a [Shape2D] to the shape owner.
</description>
</method>
<method name="shape_owner_clear_shapes">
<return type="void" />
- <argument index="0" name="owner_id" type="int" />
+ <param index="0" name="owner_id" type="int" />
<description>
Removes all shapes from the shape owner.
</description>
</method>
<method name="shape_owner_get_owner" qualifiers="const">
<return type="Object" />
- <argument index="0" name="owner_id" type="int" />
+ <param index="0" name="owner_id" type="int" />
<description>
Returns the parent object of the given shape owner.
</description>
</method>
<method name="shape_owner_get_shape" qualifiers="const">
<return type="Shape2D" />
- <argument index="0" name="owner_id" type="int" />
- <argument index="1" name="shape_id" type="int" />
+ <param index="0" name="owner_id" type="int" />
+ <param index="1" name="shape_id" type="int" />
<description>
Returns the [Shape2D] with the given id from the given shape owner.
</description>
</method>
<method name="shape_owner_get_shape_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="owner_id" type="int" />
+ <param index="0" name="owner_id" type="int" />
<description>
Returns the number of shapes the given shape owner contains.
</description>
</method>
<method name="shape_owner_get_shape_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="owner_id" type="int" />
- <argument index="1" name="shape_id" type="int" />
+ <param index="0" name="owner_id" type="int" />
+ <param index="1" name="shape_id" type="int" />
<description>
Returns the child index of the [Shape2D] with the given id from the given shape owner.
</description>
</method>
<method name="shape_owner_get_transform" qualifiers="const">
<return type="Transform2D" />
- <argument index="0" name="owner_id" type="int" />
+ <param index="0" name="owner_id" type="int" />
<description>
Returns the shape owner's [Transform2D].
</description>
</method>
<method name="shape_owner_remove_shape">
<return type="void" />
- <argument index="0" name="owner_id" type="int" />
- <argument index="1" name="shape_id" type="int" />
+ <param index="0" name="owner_id" type="int" />
+ <param index="1" name="shape_id" type="int" />
<description>
Removes a shape from the given shape owner.
</description>
</method>
<method name="shape_owner_set_disabled">
<return type="void" />
- <argument index="0" name="owner_id" type="int" />
- <argument index="1" name="disabled" type="bool" />
+ <param index="0" name="owner_id" type="int" />
+ <param index="1" name="disabled" type="bool" />
<description>
If [code]true[/code], disables the given shape owner.
</description>
</method>
<method name="shape_owner_set_one_way_collision">
<return type="void" />
- <argument index="0" name="owner_id" type="int" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="owner_id" type="int" />
+ <param index="1" name="enable" type="bool" />
<description>
- If [code]enable[/code] is [code]true[/code], collisions for the shape owner originating from this [CollisionObject2D] will not be reported to collided with [CollisionObject2D]s.
+ If [param enable] is [code]true[/code], collisions for the shape owner originating from this [CollisionObject2D] will not be reported to collided with [CollisionObject2D]s.
</description>
</method>
<method name="shape_owner_set_one_way_collision_margin">
<return type="void" />
- <argument index="0" name="owner_id" type="int" />
- <argument index="1" name="margin" type="float" />
+ <param index="0" name="owner_id" type="int" />
+ <param index="1" name="margin" type="float" />
<description>
- Sets the [code]one_way_collision_margin[/code] of the shape owner identified by given [code]owner_id[/code] to [code]margin[/code] pixels.
+ Sets the [code]one_way_collision_margin[/code] of the shape owner identified by given [param owner_id] to [param margin] pixels.
</description>
</method>
<method name="shape_owner_set_transform">
<return type="void" />
- <argument index="0" name="owner_id" type="int" />
- <argument index="1" name="transform" type="Transform2D" />
+ <param index="0" name="owner_id" type="int" />
+ <param index="1" name="transform" type="Transform2D" />
<description>
Sets the [Transform2D] of the given shape owner.
</description>
@@ -206,6 +232,9 @@
The physics layers this CollisionObject2D scans. Collision objects can scan one or more of 32 different layers. See also [member collision_layer].
[b]Note:[/b] Object A can detect a contact with object B only if object B is in any of the layers that object A scans. See [url=$DOCS_URL/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
+ <member name="collision_priority" type="float" setter="set_collision_priority" getter="get_collision_priority" default="1.0">
+ The priority used to solve colliding when occurring penetration. The higher the priority is, the lower the penetration into the object will be. This can for example be used to prevent the player from breaking through the boundaries of a level.
+ </member>
<member name="disable_mode" type="int" setter="set_disable_mode" getter="get_disable_mode" enum="CollisionObject2D.DisableMode" default="0">
Defines the behavior in physics when [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED]. See [enum DisableMode] for more details about the different modes.
</member>
@@ -215,9 +244,9 @@
</members>
<signals>
<signal name="input_event">
- <argument index="0" name="viewport" type="Node" />
- <argument index="1" name="event" type="InputEvent" />
- <argument index="2" name="shape_idx" type="int" />
+ <param index="0" name="viewport" type="Node" />
+ <param index="1" name="event" type="InputEvent" />
+ <param index="2" name="shape_idx" type="int" />
<description>
Emitted when an input event occurs. Requires [member input_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set. See [method _input_event] for details.
</description>
@@ -235,15 +264,15 @@
</description>
</signal>
<signal name="mouse_shape_entered">
- <argument index="0" name="shape_idx" type="int" />
+ <param index="0" name="shape_idx" type="int" />
<description>
- Emitted when the mouse pointer enters any of this object's shapes or moves from one shape to another. [code]shape_idx[/code] is the child index of the newly entered [Shape2D]. Requires [member input_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set.
+ Emitted when the mouse pointer enters any of this object's shapes or moves from one shape to another. [param shape_idx] is the child index of the newly entered [Shape2D]. Requires [member input_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set.
</description>
</signal>
<signal name="mouse_shape_exited">
- <argument index="0" name="shape_idx" type="int" />
+ <param index="0" name="shape_idx" type="int" />
<description>
- Emitted when the mouse pointer exits any of this object's shapes. [code]shape_idx[/code] is the child index of the exited [Shape2D]. Requires [member input_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set.
+ Emitted when the mouse pointer exits any of this object's shapes. [param shape_idx] is the child index of the exited [Shape2D]. Requires [member input_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set.
</description>
</signal>
</signals>
diff --git a/doc/classes/CollisionObject3D.xml b/doc/classes/CollisionObject3D.xml
index 7284a7e341..f10136521a 100644
--- a/doc/classes/CollisionObject3D.xml
+++ b/doc/classes/CollisionObject3D.xml
@@ -11,35 +11,47 @@
<methods>
<method name="_input_event" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="camera" type="Camera3D" />
- <argument index="1" name="event" type="InputEvent" />
- <argument index="2" name="position" type="Vector3" />
- <argument index="3" name="normal" type="Vector3" />
- <argument index="4" name="shape_idx" type="int" />
+ <param index="0" name="camera" type="Camera3D" />
+ <param index="1" name="event" type="InputEvent" />
+ <param index="2" name="position" type="Vector3" />
+ <param index="3" name="normal" type="Vector3" />
+ <param index="4" name="shape_idx" type="int" />
<description>
- Receives unhandled [InputEvent]s. [code]position[/code] is the location in world space of the mouse pointer on the surface of the shape with index [code]shape_idx[/code] and [code]normal[/code] is the normal vector of the surface at that point. Connect to the [signal input_event] signal to easily pick up these events.
+ Receives unhandled [InputEvent]s. [param position] is the location in world space of the mouse pointer on the surface of the shape with index [param shape_idx] and [param normal] is the normal vector of the surface at that point. Connect to the [signal input_event] signal to easily pick up these events.
[b]Note:[/b] [method _input_event] requires [member input_ray_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set.
</description>
</method>
+ <method name="_mouse_enter" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Called when the mouse pointer enters any of this object's shapes. Requires [member input_ray_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set. Note that moving between different shapes within a single [CollisionObject3D] won't cause this function to be called.
+ </description>
+ </method>
+ <method name="_mouse_exit" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Called when the mouse pointer exits all this object's shapes. Requires [member input_ray_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set. Note that moving between different shapes within a single [CollisionObject3D] won't cause this function to be called.
+ </description>
+ </method>
<method name="create_shape_owner">
<return type="int" />
- <argument index="0" name="owner" type="Object" />
+ <param index="0" name="owner" type="Object" />
<description>
Creates a new shape owner for the given object. Returns [code]owner_id[/code] of the new owner for future reference.
</description>
</method>
<method name="get_collision_layer_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
- Returns whether or not the specified layer of the [member collision_layer] is enabled, given a [code]layer_number[/code] between 1 and 32.
+ Returns whether or not the specified layer of the [member collision_layer] is enabled, given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
- Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
+ Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="get_rid" qualifiers="const">
@@ -49,120 +61,120 @@
</description>
</method>
<method name="get_shape_owners">
- <return type="Array" />
+ <return type="PackedInt32Array" />
<description>
Returns an [Array] of [code]owner_id[/code] identifiers. You can use these ids in other methods that take [code]owner_id[/code] as an argument.
</description>
</method>
<method name="is_shape_owner_disabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="owner_id" type="int" />
+ <param index="0" name="owner_id" type="int" />
<description>
If [code]true[/code], the shape owner and its shapes are disabled.
</description>
</method>
<method name="remove_shape_owner">
<return type="void" />
- <argument index="0" name="owner_id" type="int" />
+ <param index="0" name="owner_id" type="int" />
<description>
Removes the given shape owner.
</description>
</method>
<method name="set_collision_layer_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
- Based on [code]value[/code], enables or disables the specified layer in the [member collision_layer], given a [code]layer_number[/code] between 1 and 32.
+ Based on [param value], enables or disables the specified layer in the [member collision_layer], given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="set_collision_mask_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
- Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
+ Based on [param value], enables or disables the specified layer in the [member collision_mask], given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="shape_find_owner" qualifiers="const">
<return type="int" />
- <argument index="0" name="shape_index" type="int" />
+ <param index="0" name="shape_index" type="int" />
<description>
Returns the [code]owner_id[/code] of the given shape.
</description>
</method>
<method name="shape_owner_add_shape">
<return type="void" />
- <argument index="0" name="owner_id" type="int" />
- <argument index="1" name="shape" type="Shape3D" />
+ <param index="0" name="owner_id" type="int" />
+ <param index="1" name="shape" type="Shape3D" />
<description>
Adds a [Shape3D] to the shape owner.
</description>
</method>
<method name="shape_owner_clear_shapes">
<return type="void" />
- <argument index="0" name="owner_id" type="int" />
+ <param index="0" name="owner_id" type="int" />
<description>
Removes all shapes from the shape owner.
</description>
</method>
<method name="shape_owner_get_owner" qualifiers="const">
<return type="Object" />
- <argument index="0" name="owner_id" type="int" />
+ <param index="0" name="owner_id" type="int" />
<description>
Returns the parent object of the given shape owner.
</description>
</method>
<method name="shape_owner_get_shape" qualifiers="const">
<return type="Shape3D" />
- <argument index="0" name="owner_id" type="int" />
- <argument index="1" name="shape_id" type="int" />
+ <param index="0" name="owner_id" type="int" />
+ <param index="1" name="shape_id" type="int" />
<description>
Returns the [Shape3D] with the given id from the given shape owner.
</description>
</method>
<method name="shape_owner_get_shape_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="owner_id" type="int" />
+ <param index="0" name="owner_id" type="int" />
<description>
Returns the number of shapes the given shape owner contains.
</description>
</method>
<method name="shape_owner_get_shape_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="owner_id" type="int" />
- <argument index="1" name="shape_id" type="int" />
+ <param index="0" name="owner_id" type="int" />
+ <param index="1" name="shape_id" type="int" />
<description>
Returns the child index of the [Shape3D] with the given id from the given shape owner.
</description>
</method>
<method name="shape_owner_get_transform" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="owner_id" type="int" />
+ <param index="0" name="owner_id" type="int" />
<description>
Returns the shape owner's [Transform3D].
</description>
</method>
<method name="shape_owner_remove_shape">
<return type="void" />
- <argument index="0" name="owner_id" type="int" />
- <argument index="1" name="shape_id" type="int" />
+ <param index="0" name="owner_id" type="int" />
+ <param index="1" name="shape_id" type="int" />
<description>
Removes a shape from the given shape owner.
</description>
</method>
<method name="shape_owner_set_disabled">
<return type="void" />
- <argument index="0" name="owner_id" type="int" />
- <argument index="1" name="disabled" type="bool" />
+ <param index="0" name="owner_id" type="int" />
+ <param index="1" name="disabled" type="bool" />
<description>
If [code]true[/code], disables the given shape owner.
</description>
</method>
<method name="shape_owner_set_transform">
<return type="void" />
- <argument index="0" name="owner_id" type="int" />
- <argument index="1" name="transform" type="Transform3D" />
+ <param index="0" name="owner_id" type="int" />
+ <param index="1" name="transform" type="Transform3D" />
<description>
Sets the [Transform3D] of the given shape owner.
</description>
@@ -177,6 +189,9 @@
The physics layers this CollisionObject3D [b]scans[/b]. Collision objects can scan one or more of 32 different layers. See also [member collision_layer].
[b]Note:[/b] Object A can detect a contact with object B only if object B is in any of the layers that object A scans. See [url=$DOCS_URL/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
+ <member name="collision_priority" type="float" setter="set_collision_priority" getter="get_collision_priority" default="1.0">
+ The priority used to solve colliding when occurring penetration. The higher the priority is, the lower the penetration into the object will be. This can for example be used to prevent the player from breaking through the boundaries of a level.
+ </member>
<member name="disable_mode" type="int" setter="set_disable_mode" getter="get_disable_mode" enum="CollisionObject3D.DisableMode" default="0">
Defines the behavior in physics when [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED]. See [enum DisableMode] for more details about the different modes.
</member>
@@ -189,13 +204,13 @@
</members>
<signals>
<signal name="input_event">
- <argument index="0" name="camera" type="Node" />
- <argument index="1" name="event" type="InputEvent" />
- <argument index="2" name="position" type="Vector3" />
- <argument index="3" name="normal" type="Vector3" />
- <argument index="4" name="shape_idx" type="int" />
+ <param index="0" name="camera" type="Node" />
+ <param index="1" name="event" type="InputEvent" />
+ <param index="2" name="position" type="Vector3" />
+ <param index="3" name="normal" type="Vector3" />
+ <param index="4" name="shape_idx" type="int" />
<description>
- Emitted when the object receives an unhandled [InputEvent]. [code]position[/code] is the location in world space of the mouse pointer on the surface of the shape with index [code]shape_idx[/code] and [code]normal[/code] is the normal vector of the surface at that point.
+ Emitted when the object receives an unhandled [InputEvent]. [param position] is the location in world space of the mouse pointer on the surface of the shape with index [param shape_idx] and [param normal] is the normal vector of the surface at that point.
</description>
</signal>
<signal name="mouse_entered">
diff --git a/doc/classes/CollisionShape2D.xml b/doc/classes/CollisionShape2D.xml
index 246e0e8663..fa8fbd0d3e 100644
--- a/doc/classes/CollisionShape2D.xml
+++ b/doc/classes/CollisionShape2D.xml
@@ -4,7 +4,8 @@
Node that represents collision shape data in 2D space.
</brief_description>
<description>
- 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.
+ Editor facility for creating and editing collision shapes in 2D space. Set the [member shape] property to configure the shape. [b]IMPORTANT[/b]: this is an Editor-only helper to create shapes, use [method CollisionObject2D.shape_owner_get_shape] to get the actual shape.
+ 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.
</description>
<tutorials>
<link title="Physics introduction">$DOCS_URL/tutorials/physics/physics_introduction.html</link>
diff --git a/doc/classes/CollisionShape3D.xml b/doc/classes/CollisionShape3D.xml
index 521a11effd..304b46ba27 100644
--- a/doc/classes/CollisionShape3D.xml
+++ b/doc/classes/CollisionShape3D.xml
@@ -4,7 +4,8 @@
Node that represents collision shape data in 3D space.
</brief_description>
<description>
- 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.
+ Editor facility for creating and editing collision shapes in 3D space. Set the [member shape] property to configure the shape. [b]IMPORTANT[/b]: this is an Editor-only helper to create shapes, use [method CollisionObject3D.shape_owner_get_shape] to get the actual shape.
+ 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.
</description>
<tutorials>
<link title="Physics introduction">$DOCS_URL/tutorials/physics/physics_introduction.html</link>
@@ -21,7 +22,7 @@
</method>
<method name="resource_changed">
<return type="void" />
- <argument index="0" name="resource" type="Resource" />
+ <param index="0" name="resource" type="Resource" />
<description>
If this method exists within a script it will be called whenever the shape resource has been modified.
</description>
diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml
index 59ad104ad1..3a3803c1da 100644
--- a/doc/classes/Color.xml
+++ b/doc/classes/Color.xml
@@ -24,8 +24,8 @@
</constructor>
<constructor name="Color">
<return type="Color" />
- <argument index="0" name="from" type="Color" />
- <argument index="1" name="alpha" type="float" />
+ <param index="0" name="from" type="Color" />
+ <param index="1" name="alpha" type="float" />
<description>
Constructs a [Color] from an existing color, but with a custom alpha value.
[codeblocks]
@@ -40,31 +40,31 @@
</constructor>
<constructor name="Color">
<return type="Color" />
- <argument index="0" name="from" type="Color" />
+ <param index="0" name="from" type="Color" />
<description>
Constructs a [Color] as a copy of the given [Color].
</description>
</constructor>
<constructor name="Color">
<return type="Color" />
- <argument index="0" name="code" type="String" />
+ <param index="0" name="code" type="String" />
<description>
Constructs a [Color] either from an HTML color code or from a standardized color name. Supported color names are the same as the constants.
</description>
</constructor>
<constructor name="Color">
<return type="Color" />
- <argument index="0" name="code" type="String" />
- <argument index="1" name="alpha" type="float" />
+ <param index="0" name="code" type="String" />
+ <param index="1" name="alpha" type="float" />
<description>
- Constructs a [Color] either from an HTML color code or from a standardized color name, with [code]alpha[/code] on the range of 0 to 1. Supported color names are the same as the constants.
+ Constructs a [Color] either from an HTML color code or from a standardized color name, with [param alpha] on the range of 0 to 1. Supported color names are the same as the constants.
</description>
</constructor>
<constructor name="Color">
<return type="Color" />
- <argument index="0" name="r" type="float" />
- <argument index="1" name="g" type="float" />
- <argument index="2" name="b" type="float" />
+ <param index="0" name="r" type="float" />
+ <param index="1" name="g" type="float" />
+ <param index="2" name="b" type="float" />
<description>
Constructs a [Color] from RGB values, typically between 0 and 1. Alpha will be 1.
[codeblocks]
@@ -79,10 +79,10 @@
</constructor>
<constructor name="Color">
<return type="Color" />
- <argument index="0" name="r" type="float" />
- <argument index="1" name="g" type="float" />
- <argument index="2" name="b" type="float" />
- <argument index="3" name="a" type="float" />
+ <param index="0" name="r" type="float" />
+ <param index="1" name="g" type="float" />
+ <param index="2" name="b" type="float" />
+ <param index="3" name="a" type="float" />
<description>
Constructs a [Color] from RGBA values, typically between 0 and 1.
[codeblocks]
@@ -99,7 +99,7 @@
<methods>
<method name="blend" qualifiers="const">
<return type="Color" />
- <argument index="0" name="over" type="Color" />
+ <param index="0" name="over" type="Color" />
<description>
Returns a new color resulting from blending this color over another. If the color is opaque, the result is also opaque. The second color may have a range of alpha values.
[codeblocks]
@@ -118,15 +118,15 @@
</method>
<method name="clamp" qualifiers="const">
<return type="Color" />
- <argument index="0" name="min" type="Color" default="Color(0, 0, 0, 0)" />
- <argument index="1" name="max" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="0" name="min" type="Color" default="Color(0, 0, 0, 0)" />
+ <param index="1" name="max" type="Color" default="Color(1, 1, 1, 1)" />
<description>
- Returns a new color with all components clamped between the components of [code]min[/code] and [code]max[/code], by running [method @GlobalScope.clamp] on each component.
+ Returns a new color with all components clamped between the components of [param min] and [param max], by running [method @GlobalScope.clamp] on each component.
</description>
</method>
<method name="darkened" qualifiers="const">
<return type="Color" />
- <argument index="0" name="amount" type="float" />
+ <param index="0" name="amount" type="float" />
<description>
Returns a new color resulting from making this color darker by the specified percentage (ratio from 0 to 1).
[codeblocks]
@@ -143,18 +143,18 @@
</method>
<method name="find_named_color" qualifiers="static">
<return type="int" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
</description>
</method>
<method name="from_hsv" qualifiers="static">
<return type="Color" />
- <argument index="0" name="h" type="float" />
- <argument index="1" name="s" type="float" />
- <argument index="2" name="v" type="float" />
- <argument index="3" name="alpha" type="float" default="1.0" />
+ <param index="0" name="h" type="float" />
+ <param index="1" name="s" type="float" />
+ <param index="2" name="v" type="float" />
+ <param index="3" name="alpha" type="float" default="1.0" />
<description>
- Constructs a color from an [url=https://en.wikipedia.org/wiki/HSL_and_HSV]HSV profile[/url]. [code]h[/code] (hue), [code]s[/code] (saturation), and [code]v[/code] (value) are typically between 0 and 1.
+ Constructs a color from an [url=https://en.wikipedia.org/wiki/HSL_and_HSV]HSV profile[/url]. [param h] (hue), [param s] (saturation), and [param v] (value) are typically between 0 and 1.
[codeblocks]
[gdscript]
var color = Color.from_hsv(0.58, 0.5, 0.79, 0.8)
@@ -167,12 +167,12 @@
</method>
<method name="from_ok_hsl" qualifiers="static">
<return type="Color" />
- <argument index="0" name="h" type="float" />
- <argument index="1" name="s" type="float" />
- <argument index="2" name="l" type="float" />
- <argument index="3" name="alpha" type="float" default="1.0" />
+ <param index="0" name="h" type="float" />
+ <param index="1" name="s" type="float" />
+ <param index="2" name="l" type="float" />
+ <param index="3" name="alpha" type="float" default="1.0" />
<description>
- Constructs a color from an [url=https://bottosson.github.io/posts/colorpicker/]OK HSL profile[/url]. [code]h[/code] (hue), [code]s[/code] (saturation), and [code]v[/code] (value) are typically between 0 and 1.
+ Constructs a color from an [url=https://bottosson.github.io/posts/colorpicker/]OK HSL profile[/url]. [param h] (hue), [param s] (saturation), and [param l] (lightness) are typically between 0 and 1.
[codeblocks]
[gdscript]
var color = Color.from_ok_hsl(0.58, 0.5, 0.79, 0.8)
@@ -185,14 +185,14 @@
</method>
<method name="from_rgbe9995" qualifiers="static">
<return type="Color" />
- <argument index="0" name="rgbe" type="int" />
+ <param index="0" name="rgbe" type="int" />
<description>
</description>
</method>
<method name="from_string" qualifiers="static">
<return type="Color" />
- <argument index="0" name="str" type="String" />
- <argument index="1" name="default" type="Color" />
+ <param index="0" name="str" type="String" />
+ <param index="1" name="default" type="Color" />
<description>
</description>
</method>
@@ -206,7 +206,7 @@
</method>
<method name="get_named_color" qualifiers="static">
<return type="Color" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
</description>
</method>
@@ -217,29 +217,29 @@
</method>
<method name="get_named_color_name" qualifiers="static">
<return type="String" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
</description>
</method>
<method name="hex" qualifiers="static">
<return type="Color" />
- <argument index="0" name="hex" type="int" />
+ <param index="0" name="hex" type="int" />
<description>
</description>
</method>
<method name="hex64" qualifiers="static">
<return type="Color" />
- <argument index="0" name="hex" type="int" />
+ <param index="0" name="hex" type="int" />
<description>
</description>
</method>
<method name="html" qualifiers="static">
<return type="Color" />
- <argument index="0" name="rgba" type="String" />
+ <param index="0" name="rgba" type="String" />
<description>
- Returns a new color from [code]rgba[/code], an HTML hexadecimal color string. [code]rgba[/code] is not case sensitive, and may be prefixed with a '#' character.
- [code]rgba[/code] must be a valid three-digit or six-digit hexadecimal color string, and may contain an alpha channel value. If [code]rgba[/code] does not contain an alpha channel value, an alpha channel value of 1.0 is applied.
- If [code]rgba[/code] is invalid a Color(0.0, 0.0, 0.0, 1.0) is returned.
+ Returns a new color from [param rgba], an HTML hexadecimal color string. [param rgba] is not case sensitive, and may be prefixed with a '#' character.
+ [param rgba] must be a valid three-digit or six-digit hexadecimal color string, and may contain an alpha channel value. If [param rgba] does not contain an alpha channel value, an alpha channel value of 1.0 is applied.
+ If [param rgba] is invalid a Color(0.0, 0.0, 0.0, 1.0) is returned.
[b]Note:[/b] This method is not implemented in C#, but the same functionality is provided in the class constructor.
[codeblocks]
[gdscript]
@@ -255,9 +255,9 @@
</method>
<method name="html_is_valid" qualifiers="static">
<return type="bool" />
- <argument index="0" name="color" type="String" />
+ <param index="0" name="color" type="String" />
<description>
- Returns [code]true[/code] if [code]color[/code] is a valid HTML hexadecimal color string. [code]color[/code] is not case sensitive, and may be prefixed with a '#' character.
+ Returns [code]true[/code] if [param color] is a valid HTML hexadecimal color string. [param color] is not case sensitive, and may be prefixed with a '#' character.
For a string to be valid it must be three-digit or six-digit hexadecimal, and may contain an alpha channel value.
[codeblocks]
[gdscript]
@@ -297,17 +297,17 @@
</method>
<method name="is_equal_approx" qualifiers="const">
<return type="bool" />
- <argument index="0" name="to" type="Color" />
+ <param index="0" name="to" type="Color" />
<description>
- Returns [code]true[/code] if this color and [code]color[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
+ Returns [code]true[/code] if this color and [param to] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
<method name="lerp" qualifiers="const">
<return type="Color" />
- <argument index="0" name="to" type="Color" />
- <argument index="1" name="weight" type="float" />
+ <param index="0" name="to" type="Color" />
+ <param index="1" name="weight" type="float" />
<description>
- Returns the linear interpolation with another color. The interpolation factor [code]weight[/code] is between 0 and 1.
+ Returns the linear interpolation with another color. The interpolation factor [param weight] is between 0 and 1.
[codeblocks]
[gdscript]
var c1 = Color(1.0, 0.0, 0.0)
@@ -324,7 +324,7 @@
</method>
<method name="lightened" qualifiers="const">
<return type="Color" />
- <argument index="0" name="amount" type="float" />
+ <param index="0" name="amount" type="float" />
<description>
Returns a new color resulting from making this color lighter by the specified percentage (ratio from 0 to 1).
[codeblocks]
@@ -417,10 +417,10 @@
</method>
<method name="to_html" qualifiers="const">
<return type="String" />
- <argument index="0" name="with_alpha" type="bool" default="true" />
+ <param index="0" name="with_alpha" type="bool" default="true" />
<description>
Returns the color converted to an 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).
+ Setting [param with_alpha] to [code]false[/code] excludes alpha from the hexadecimal string (and uses RGB instead of RGBA format).
[codeblocks]
[gdscript]
var color = Color(1, 1, 1, 0.5)
@@ -946,7 +946,7 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="Color" />
+ <param index="0" name="right" type="Color" />
<description>
Returns [code]true[/code] if the colors are not equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
@@ -954,63 +954,63 @@
</operator>
<operator name="operator *">
<return type="Color" />
- <argument index="0" name="right" type="Color" />
+ <param index="0" name="right" type="Color" />
<description>
Multiplies each component of the [Color] by the components of the given [Color].
</description>
</operator>
<operator name="operator *">
<return type="Color" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Multiplies each component of the [Color] by the given [float].
</description>
</operator>
<operator name="operator *">
<return type="Color" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Multiplies each component of the [Color] by the given [int].
</description>
</operator>
<operator name="operator +">
<return type="Color" />
- <argument index="0" name="right" type="Color" />
+ <param index="0" name="right" type="Color" />
<description>
Adds each component of the [Color] with the components of the given [Color].
</description>
</operator>
<operator name="operator -">
<return type="Color" />
- <argument index="0" name="right" type="Color" />
+ <param index="0" name="right" type="Color" />
<description>
Subtracts each component of the [Color] by the components of the given [Color].
</description>
</operator>
<operator name="operator /">
<return type="Color" />
- <argument index="0" name="right" type="Color" />
+ <param index="0" name="right" type="Color" />
<description>
Divides each component of the [Color] by the components of the given [Color].
</description>
</operator>
<operator name="operator /">
<return type="Color" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Divides each component of the [Color] by the given [float].
</description>
</operator>
<operator name="operator /">
<return type="Color" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Divides each component of the [Color] by the given [int].
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="Color" />
+ <param index="0" name="right" type="Color" />
<description>
Returns [code]true[/code] if the colors are exactly equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
@@ -1018,7 +1018,7 @@
</operator>
<operator name="operator []">
<return type="float" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Access color components using their index. [code]c[0][/code] is equivalent to [code]c.r[/code], [code]c[1][/code] is equivalent to [code]c.g[/code], [code]c[2][/code] is equivalent to [code]c.b[/code], and [code]c[3][/code] is equivalent to [code]c.a[/code].
</description>
diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml
index cc9c5877c5..705d2282c1 100644
--- a/doc/classes/ColorPicker.xml
+++ b/doc/classes/ColorPicker.xml
@@ -13,7 +13,7 @@
<methods>
<method name="add_preset">
<return type="void" />
- <argument index="0" name="color" type="Color" />
+ <param index="0" name="color" type="Color" />
<description>
Adds the given color to a list of color presets. The presets are displayed in the color picker and the user will be able to select them.
[b]Note:[/b] The presets list is only for [i]this[/i] color picker.
@@ -21,7 +21,7 @@
</method>
<method name="erase_preset">
<return type="void" />
- <argument index="0" name="color" type="Color" />
+ <param index="0" name="color" type="Color" />
<description>
Removes the given color from the list of color presets of this color picker.
</description>
@@ -58,19 +58,19 @@
</members>
<signals>
<signal name="color_changed">
- <argument index="0" name="color" type="Color" />
+ <param index="0" name="color" type="Color" />
<description>
Emitted when the color is changed.
</description>
</signal>
<signal name="preset_added">
- <argument index="0" name="color" type="Color" />
+ <param index="0" name="color" type="Color" />
<description>
Emitted when a preset is added.
</description>
</signal>
<signal name="preset_removed">
- <argument index="0" name="color" type="Color" />
+ <param index="0" name="color" type="Color" />
<description>
Emitted when a preset is removed.
</description>
diff --git a/doc/classes/ColorPickerButton.xml b/doc/classes/ColorPickerButton.xml
index 75a715789c..b7a0bdfb0c 100644
--- a/doc/classes/ColorPickerButton.xml
+++ b/doc/classes/ColorPickerButton.xml
@@ -39,7 +39,7 @@
</members>
<signals>
<signal name="color_changed">
- <argument index="0" name="color" type="Color" />
+ <param index="0" name="color" type="Color" />
<description>
Emitted when the color changes.
</description>
diff --git a/doc/classes/CompressedTexture2D.xml b/doc/classes/CompressedTexture2D.xml
index 5f73b55f69..f74265b8d5 100644
--- a/doc/classes/CompressedTexture2D.xml
+++ b/doc/classes/CompressedTexture2D.xml
@@ -11,7 +11,7 @@
<methods>
<method name="load">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Loads the texture from the given path.
</description>
diff --git a/doc/classes/CompressedTexture3D.xml b/doc/classes/CompressedTexture3D.xml
index de7a93d788..50bd025861 100644
--- a/doc/classes/CompressedTexture3D.xml
+++ b/doc/classes/CompressedTexture3D.xml
@@ -9,7 +9,7 @@
<methods>
<method name="load">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
</description>
</method>
diff --git a/doc/classes/CompressedTextureLayered.xml b/doc/classes/CompressedTextureLayered.xml
index 03bea84ba4..547679c0f0 100644
--- a/doc/classes/CompressedTextureLayered.xml
+++ b/doc/classes/CompressedTextureLayered.xml
@@ -9,7 +9,7 @@
<methods>
<method name="load">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
</description>
</method>
diff --git a/doc/classes/ConcavePolygonShape2D.xml b/doc/classes/ConcavePolygonShape2D.xml
index f3c245c229..ee3e4f6de4 100644
--- a/doc/classes/ConcavePolygonShape2D.xml
+++ b/doc/classes/ConcavePolygonShape2D.xml
@@ -4,9 +4,10 @@
Concave polygon shape resource for 2D physics.
</brief_description>
<description>
- 2D concave polygon shape to be added as a [i]direct[/i] child of a [PhysicsBody2D] or [Area2D] using a [CollisionShape2D] node. It is made out of segments and is optimal for complex polygonal concave collisions. However, it is not advised to use for [RigidDynamicBody2D] nodes. A CollisionPolygon2D in convex decomposition mode (solids) or several convex objects are advised for that instead. Otherwise, a concave polygon 2D shape is better for static collisions.
+ 2D concave polygon shape to be added as a [i]direct[/i] child of a [PhysicsBody2D] or [Area2D] using a [CollisionShape2D] node. It is made out of segments and is optimal for complex polygonal concave collisions. However, it is not advised to use for [RigidBody2D] nodes. A CollisionPolygon2D in convex decomposition mode (solids) or several convex objects are advised for that instead. Otherwise, a concave polygon 2D shape is better for static collisions.
The main difference between a [ConvexPolygonShape2D] and a [ConcavePolygonShape2D] is that a concave polygon assumes it is concave and uses a more complex method of collision detection, and a convex one forces itself to be convex to speed up collision detection.
[b]Performance:[/b] Due to its complexity, [ConcavePolygonShape2D] is the slowest collision shape to check collisions against. Its use should generally be limited to level geometry. For convex geometry, using [ConvexPolygonShape2D] will perform better. For dynamic physics bodies that need concave collision, several [ConvexPolygonShape2D]s can be used to represent its collision by using convex decomposition; see [ConvexPolygonShape2D]'s documentation for instructions. However, consider using primitive collision shapes such as [CircleShape2D] or [RectangleShape2D] first.
+ [b]Warning:[/b] Using this shape for an [Area2D] (via a [CollisionShape2D] node) may give unexpected results: the area will only detect collisions with the segments in the [ConcavePolygonShape2D] (and not with any "inside" of the shape, for example).
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/ConcavePolygonShape3D.xml b/doc/classes/ConcavePolygonShape3D.xml
index 60d7e32492..f01ca8efaf 100644
--- a/doc/classes/ConcavePolygonShape3D.xml
+++ b/doc/classes/ConcavePolygonShape3D.xml
@@ -5,8 +5,9 @@
</brief_description>
<description>
3D concave polygon shape resource (also called "trimesh") to be added as a [i]direct[/i] child of a [PhysicsBody3D] or [Area3D] using a [CollisionShape3D] node. This shape is created by feeding a list of triangles. Despite its name, [ConcavePolygonShape3D] can also store convex polygon shapes. However, unlike [ConvexPolygonShape3D], [ConcavePolygonShape3D] is [i]not[/i] limited to storing convex shapes exclusively.
- [b]Note:[/b] When used for collision, [ConcavePolygonShape3D] is intended to work with static [PhysicsBody3D] nodes like [StaticBody3D] and will not work with [CharacterBody3D] or [RigidDynamicBody3D] with a mode other than Static.
+ [b]Note:[/b] When used for collision, [ConcavePolygonShape3D] is intended to work with static [PhysicsBody3D] nodes like [StaticBody3D] and will not work with [CharacterBody3D] or [RigidBody3D] with a mode other than Static.
[b]Performance:[/b] Due to its complexity, [ConcavePolygonShape3D] is the slowest collision shape to check collisions against. Its use should generally be limited to level geometry. For convex geometry, using [ConvexPolygonShape3D] will perform better. For dynamic physics bodies that need concave collision, several [ConvexPolygonShape3D]s can be used to represent its collision by using convex decomposition; see [ConvexPolygonShape3D]'s documentation for instructions. However, consider using primitive collision shapes such as [SphereShape3D] or [BoxShape3D] first.
+ [b]Warning:[/b] Using this shape for an [Area3D] (via a [CollisionShape3D] node, created e.g. by using the [i]Create Trimesh Collision Sibling[/i] option in the [i]Mesh[/i] menu that appears when selecting a [MeshInstance3D] node) may give unexpected results: the area will only detect collisions with the triangle faces in the [ConcavePolygonShape3D] (and not with any "inside" of the shape, for example); moreover it will only detect all such collisions if [member backface_collision] is [code]true[/code].
</description>
<tutorials>
<link title="3D Physics Tests Demo">https://godotengine.org/asset-library/asset/675</link>
@@ -20,7 +21,7 @@
</method>
<method name="set_faces">
<return type="void" />
- <argument index="0" name="faces" type="PackedVector3Array" />
+ <param index="0" name="faces" type="PackedVector3Array" />
<description>
Sets the faces (an array of triangles).
</description>
diff --git a/doc/classes/ConeTwistJoint3D.xml b/doc/classes/ConeTwistJoint3D.xml
index f78a5b5332..1cfe9d197d 100644
--- a/doc/classes/ConeTwistJoint3D.xml
+++ b/doc/classes/ConeTwistJoint3D.xml
@@ -13,14 +13,14 @@
<methods>
<method name="get_param" qualifiers="const">
<return type="float" />
- <argument index="0" name="param" type="int" enum="ConeTwistJoint3D.Param" />
+ <param index="0" name="param" type="int" enum="ConeTwistJoint3D.Param" />
<description>
</description>
</method>
<method name="set_param">
<return type="void" />
- <argument index="0" name="param" type="int" enum="ConeTwistJoint3D.Param" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="param" type="int" enum="ConeTwistJoint3D.Param" />
+ <param index="1" name="value" type="float" />
<description>
</description>
</method>
@@ -36,13 +36,13 @@
<member name="softness" type="float" setter="set_param" getter="get_param" default="0.8">
The ease with which the joint starts to twist. If it's too low, it takes more force to start twisting the joint.
</member>
- <member name="swing_span" type="float" setter="_set_swing_span" getter="_get_swing_span" default="45.0">
+ <member name="swing_span" type="float" setter="set_param" getter="get_param" default="0.785398">
Swing is rotation from side to side, around the axis perpendicular to the twist axis.
The swing span defines, how much rotation will not get corrected along the swing axis.
Could be defined as looseness in the [ConeTwistJoint3D].
If below 0.05, this behavior is locked.
</member>
- <member name="twist_span" type="float" setter="_set_twist_span" getter="_get_twist_span" default="180.0">
+ <member name="twist_span" type="float" setter="set_param" getter="get_param" default="3.14159">
Twist is the rotation around the twist axis, this value defined how far the joint can twist.
Twist is locked if below 0.05.
</member>
diff --git a/doc/classes/ConfigFile.xml b/doc/classes/ConfigFile.xml
index b766981f1e..d3ad4e6e4b 100644
--- a/doc/classes/ConfigFile.xml
+++ b/doc/classes/ConfigFile.xml
@@ -100,22 +100,22 @@
</method>
<method name="erase_section">
<return type="void" />
- <argument index="0" name="section" type="String" />
+ <param index="0" name="section" type="String" />
<description>
Deletes the specified section along with all the key-value pairs inside. Raises an error if the section does not exist.
</description>
</method>
<method name="erase_section_key">
<return type="void" />
- <argument index="0" name="section" type="String" />
- <argument index="1" name="key" type="String" />
+ <param index="0" name="section" type="String" />
+ <param index="1" name="key" type="String" />
<description>
Deletes the specified key in a section. Raises an error if either the section or the key do not exist.
</description>
</method>
<method name="get_section_keys" qualifiers="const">
<return type="PackedStringArray" />
- <argument index="0" name="section" type="String" />
+ <param index="0" name="section" type="String" />
<description>
Returns an array of all defined key identifiers in the specified section. Raises an error and returns an empty array if the section does not exist.
</description>
@@ -128,24 +128,24 @@
</method>
<method name="get_value" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="section" type="String" />
- <argument index="1" name="key" type="String" />
- <argument index="2" name="default" type="Variant" default="null" />
+ <param index="0" name="section" type="String" />
+ <param index="1" name="key" type="String" />
+ <param index="2" name="default" type="Variant" default="null" />
<description>
- Returns the current value for the specified section and key. If either the section or the key do not exist, the method returns the fallback [code]default[/code] value. If [code]default[/code] is not specified or set to [code]null[/code], an error is also raised.
+ Returns the current value for the specified section and key. If either the section or the key do not exist, the method returns the fallback [param default] value. If [param default] is not specified or set to [code]null[/code], an error is also raised.
</description>
</method>
<method name="has_section" qualifiers="const">
<return type="bool" />
- <argument index="0" name="section" type="String" />
+ <param index="0" name="section" type="String" />
<description>
Returns [code]true[/code] if the specified section exists.
</description>
</method>
<method name="has_section_key" qualifiers="const">
<return type="bool" />
- <argument index="0" name="section" type="String" />
- <argument index="1" name="key" type="String" />
+ <param index="0" name="section" type="String" />
+ <param index="1" name="key" type="String" />
<description>
Returns [code]true[/code] if the specified section-key pair exists.
</description>
@@ -154,7 +154,7 @@
<return type="int" enum="Error" />
<returns_error number="0"/>
<returns_error number="12"/>
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Loads the config file specified as a parameter. The file's contents are parsed and loaded in the [ConfigFile] object which the method was called on.
Returns one of the [enum Error] code constants ([code]OK[/code] on success).
@@ -162,25 +162,25 @@
</method>
<method name="load_encrypted">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="key" type="PackedByteArray" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="key" type="PackedByteArray" />
<description>
- Loads the encrypted config file specified as a parameter, using the provided [code]key[/code] to decrypt it. The file's contents are parsed and loaded in the [ConfigFile] object which the method was called on.
+ Loads the encrypted config file specified as a parameter, using the provided [param key] to decrypt it. The file's contents are parsed and loaded in the [ConfigFile] object which the method was called on.
Returns one of the [enum Error] code constants ([code]OK[/code] on success).
</description>
</method>
<method name="load_encrypted_pass">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="password" type="String" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="password" type="String" />
<description>
- Loads the encrypted config file specified as a parameter, using the provided [code]password[/code] to decrypt it. The file's contents are parsed and loaded in the [ConfigFile] object which the method was called on.
+ Loads the encrypted config file specified as a parameter, using the provided [param password] to decrypt it. The file's contents are parsed and loaded in the [ConfigFile] object which the method was called on.
Returns one of the [enum Error] code constants ([code]OK[/code] on success).
</description>
</method>
<method name="parse">
<return type="int" enum="Error" />
- <argument index="0" name="data" type="String" />
+ <param index="0" name="data" type="String" />
<description>
Parses the passed string as the contents of a config file. The string is parsed and loaded in the ConfigFile object which the method was called on.
Returns one of the [enum Error] code constants ([code]OK[/code] on success).
@@ -188,7 +188,7 @@
</method>
<method name="save">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Saves the contents of the [ConfigFile] object to the file specified as a parameter. The output file uses an INI-style structure.
Returns one of the [enum Error] code constants ([code]OK[/code] on success).
@@ -196,27 +196,27 @@
</method>
<method name="save_encrypted">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="key" type="PackedByteArray" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="key" type="PackedByteArray" />
<description>
- Saves the contents of the [ConfigFile] object to the AES-256 encrypted file specified as a parameter, using the provided [code]key[/code] to encrypt it. The output file uses an INI-style structure.
+ Saves the contents of the [ConfigFile] object to the AES-256 encrypted file specified as a parameter, using the provided [param key] to encrypt it. The output file uses an INI-style structure.
Returns one of the [enum Error] code constants ([code]OK[/code] on success).
</description>
</method>
<method name="save_encrypted_pass">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="password" type="String" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="password" type="String" />
<description>
- Saves the contents of the [ConfigFile] object to the AES-256 encrypted file specified as a parameter, using the provided [code]password[/code] to encrypt it. The output file uses an INI-style structure.
+ Saves the contents of the [ConfigFile] object to the AES-256 encrypted file specified as a parameter, using the provided [param password] to encrypt it. The output file uses an INI-style structure.
Returns one of the [enum Error] code constants ([code]OK[/code] on success).
</description>
</method>
<method name="set_value">
<return type="void" />
- <argument index="0" name="section" type="String" />
- <argument index="1" name="key" type="String" />
- <argument index="2" name="value" type="Variant" />
+ <param index="0" name="section" type="String" />
+ <param index="1" name="key" type="String" />
+ <param index="2" name="value" type="Variant" />
<description>
Assigns a value to the specified key of the specified section. If either the section or the key do not exist, they are created. Passing a [code]null[/code] value deletes the specified key if it exists, and deletes the section if it ends up empty once the key has been removed.
</description>
diff --git a/doc/classes/Container.xml b/doc/classes/Container.xml
index 900997d119..a13e1598b2 100644
--- a/doc/classes/Container.xml
+++ b/doc/classes/Container.xml
@@ -27,8 +27,8 @@
</method>
<method name="fit_child_in_rect">
<return type="void" />
- <argument index="0" name="child" type="Control" />
- <argument index="1" name="rect" type="Rect2" />
+ <param index="0" name="child" type="Control" />
+ <param index="1" name="rect" type="Rect2" />
<description>
Fit a child control in a given rect. This is mainly a helper for creating custom container classes.
</description>
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index 9fc80e1aab..0e71dbd0b1 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -24,10 +24,10 @@
<methods>
<method name="_can_drop_data" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="at_position" type="Vector2" />
- <argument index="1" name="data" type="Variant" />
+ <param index="0" name="at_position" type="Vector2" />
+ <param index="1" name="data" type="Variant" />
<description>
- Godot calls this method to test if [code]data[/code] from a control's [method _get_drag_data] can be dropped at [code]position[/code]. [code]position[/code] is local to this control.
+ Godot calls this method to test if [param data] from a control's [method _get_drag_data] can be dropped at [param at_position]. [param at_position] is local to this control.
This method should only be used to test the data. Process the data in [method _drop_data].
[codeblocks]
[gdscript]
@@ -49,10 +49,10 @@
</method>
<method name="_drop_data" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="at_position" type="Vector2" />
- <argument index="1" name="data" type="Variant" />
+ <param index="0" name="at_position" type="Vector2" />
+ <param index="1" name="data" type="Variant" />
<description>
- Godot calls this method to pass you the [code]data[/code] from a control's [method _get_drag_data] result. Godot first calls [method _can_drop_data] to test if [code]data[/code] is allowed to drop at [code]position[/code] where [code]position[/code] is local to this control.
+ Godot calls this method to pass you the [param data] from a control's [method _get_drag_data] result. Godot first calls [method _can_drop_data] to test if [param data] is allowed to drop at [param at_position] where [param at_position] is local to this control.
[codeblocks]
[gdscript]
func _can_drop_data(position, data):
@@ -75,9 +75,9 @@
</method>
<method name="_get_drag_data" qualifiers="virtual const">
<return type="Variant" />
- <argument index="0" name="at_position" type="Vector2" />
+ <param index="0" name="at_position" type="Vector2" />
<description>
- Godot calls this method to get data that can be dragged and dropped onto controls that expect drop data. Returns [code]null[/code] if there is no data to drag. Controls that want to receive drop data should implement [method _can_drop_data] and [method _drop_data]. [code]position[/code] is local to this control. Drag may be forced with [method force_drag].
+ Godot calls this method to get data that can be dragged and dropped onto controls that expect drop data. Returns [code]null[/code] if there is no data to drag. Controls that want to receive drop data should implement [method _can_drop_data] and [method _drop_data]. [param at_position] is local to this control. Drag may be forced with [method force_drag].
A preview that will follow the mouse that should represent the data can be set with [method set_drag_preview]. A good time to set the preview is in this method.
[codeblocks]
[gdscript]
@@ -107,7 +107,7 @@
</method>
<method name="_gui_input" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="event" type="InputEvent" />
+ <param index="0" name="event" type="InputEvent" />
<description>
Virtual method to be implemented by the user. Use this method to process and accept inputs on UI elements. See [method accept_event].
Example: clicking a control.
@@ -143,20 +143,20 @@
</method>
<method name="_has_point" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="position" type="Vector2" />
+ <param index="0" name="position" type="Vector2" />
<description>
- Virtual method to be implemented by the user. Returns whether the given [code]point[/code] is inside this control.
+ Virtual method to be implemented by the user. Returns whether the given [param position] is inside this control.
If not overridden, default behavior is checking if the point is within control's Rect.
[b]Note:[/b] If you want to check if a point is inside the control, you can use [code]get_rect().has_point(point)[/code].
</description>
</method>
<method name="_make_custom_tooltip" qualifiers="virtual const">
<return type="Object" />
- <argument index="0" name="for_text" type="String" />
+ <param index="0" name="for_text" type="String" />
<description>
- Virtual method to be implemented by the user. Returns a [Control] node that should be used as a tooltip instead of the default one. The [code]for_text[/code] includes the contents of the [member hint_tooltip] property.
+ Virtual method to be implemented by the user. Returns a [Control] node that should be used as a tooltip instead of the default one. The [param for_text] includes the contents of the [member tooltip_text] property.
The returned node must be of type [Control] or Control-derived. It can have child nodes of any type. It is freed when the tooltip disappears, so make sure you always provide a new instance (if you want to use a pre-existing node from your scene tree, you can duplicate it and pass the duplicated instance). When [code]null[/code] or a non-Control node is returned, the default tooltip will be used instead.
- The returned node will be added as child to a [PopupPanel], so you should only provide the contents of that panel. That [PopupPanel] can be themed using [method Theme.set_stylebox] for the type [code]"TooltipPanel"[/code] (see [member hint_tooltip] for an example).
+ The returned node will be added as child to a [PopupPanel], so you should only provide the contents of that panel. That [PopupPanel] can be themed using [method Theme.set_stylebox] for the type [code]"TooltipPanel"[/code] (see [member tooltip_text] for an example).
[b]Note:[/b] The tooltip is shrunk to minimal size. If you want to ensure it's fully visible, you might want to set its [member custom_minimum_size] to some non-zero value.
[b]Note:[/b] The node (and any relevant children) should be [member CanvasItem.visible] when returned, otherwise, the viewport that instantiates it will not be able to calculate its minimum size reliably.
Example of usage with a custom-constructed node:
@@ -196,12 +196,12 @@
</description>
</method>
<method name="_structured_text_parser" qualifiers="virtual const">
- <return type="Array" />
- <argument index="0" name="args" type="Array" />
- <argument index="1" name="text" type="String" />
+ <return type="Vector2i[]" />
+ <param index="0" name="args" type="Array" />
+ <param index="1" name="text" type="String" />
<description>
User defined BiDi algorithm override function.
- Returns [code]Array[/code] of [code]Vector2i[/code] text ranges, in the left-to-right order. Ranges should cover full source [code]text[/code] without overlaps. BiDi algorithm will be used on each range separately.
+ Returns [code]Array[/code] of [code]Vector2i[/code] text ranges, in the left-to-right order. Ranges should cover full source [param text] without overlaps. BiDi algorithm will be used on each range separately.
</description>
</method>
<method name="accept_event">
@@ -212,10 +212,10 @@
</method>
<method name="add_theme_color_override">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="color" type="Color" />
<description>
- Creates a local override for a theme [Color] with the specified [code]name[/code]. Local overrides always take precedence when fetching theme items for the control. An override can be removed with [method remove_theme_color_override].
+ Creates a local override for a theme [Color] with the specified [param name]. Local overrides always take precedence when fetching theme items for the control. An override can be removed with [method remove_theme_color_override].
See also [method get_theme_color].
[b]Example of overriding a label's color and resetting it later:[/b]
[codeblocks]
@@ -240,46 +240,46 @@
</method>
<method name="add_theme_constant_override">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="constant" type="int" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="constant" type="int" />
<description>
- Creates a local override for a theme constant with the specified [code]name[/code]. Local overrides always take precedence when fetching theme items for the control. An override can be removed with [method remove_theme_constant_override].
+ Creates a local override for a theme constant with the specified [param name]. Local overrides always take precedence when fetching theme items for the control. An override can be removed with [method remove_theme_constant_override].
See also [method get_theme_constant].
</description>
</method>
<method name="add_theme_font_override">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="font" type="Font" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="font" type="Font" />
<description>
- Creates a local override for a theme [Font] with the specified [code]name[/code]. Local overrides always take precedence when fetching theme items for the control. An override can be removed with [method remove_theme_font_override].
+ Creates a local override for a theme [Font] with the specified [param name]. Local overrides always take precedence when fetching theme items for the control. An override can be removed with [method remove_theme_font_override].
See also [method get_theme_font].
</description>
</method>
<method name="add_theme_font_size_override">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="font_size" type="int" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="font_size" type="int" />
<description>
- Creates a local override for a theme font size with the specified [code]name[/code]. Local overrides always take precedence when fetching theme items for the control. An override can be removed with [method remove_theme_font_size_override].
+ Creates a local override for a theme font size with the specified [param name]. Local overrides always take precedence when fetching theme items for the control. An override can be removed with [method remove_theme_font_size_override].
See also [method get_theme_font_size].
</description>
</method>
<method name="add_theme_icon_override">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="texture" type="Texture2D" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="texture" type="Texture2D" />
<description>
- Creates a local override for a theme icon with the specified [code]name[/code]. Local overrides always take precedence when fetching theme items for the control. An override can be removed with [method remove_theme_icon_override].
+ Creates a local override for a theme icon with the specified [param name]. Local overrides always take precedence when fetching theme items for the control. An override can be removed with [method remove_theme_icon_override].
See also [method get_theme_icon].
</description>
</method>
<method name="add_theme_stylebox_override">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="stylebox" type="StyleBox" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="stylebox" type="StyleBox" />
<description>
- Creates a local override for a theme [StyleBox] with the specified [code]name[/code]. Local overrides always take precedence when fetching theme items for the control. An override can be removed with [method remove_theme_stylebox_override].
+ Creates a local override for a theme [StyleBox] with the specified [param name]. Local overrides always take precedence when fetching theme items for the control. An override can be removed with [method remove_theme_stylebox_override].
See also [method get_theme_stylebox].
[b]Example of modifying a property in a StyleBox by duplicating it:[/b]
[codeblocks]
@@ -334,16 +334,16 @@
</method>
<method name="force_drag">
<return type="void" />
- <argument index="0" name="data" type="Variant" />
- <argument index="1" name="preview" type="Control" />
+ <param index="0" name="data" type="Variant" />
+ <param index="1" name="preview" type="Control" />
<description>
- Forces drag and bypasses [method _get_drag_data] and [method set_drag_preview] by passing [code]data[/code] and [code]preview[/code]. Drag will start even if the mouse is neither over nor pressed on this control.
+ Forces drag and bypasses [method _get_drag_data] and [method set_drag_preview] by passing [param data] and [param preview]. Drag will start even if the mouse is neither over nor pressed on this control.
The methods [method _can_drop_data] and [method _drop_data] must be implemented on controls that want to receive drop data.
</description>
</method>
<method name="get_anchor" qualifiers="const">
<return type="float" />
- <argument index="0" name="side" type="int" enum="Side" />
+ <param index="0" name="side" type="int" enum="Side" />
<description>
Returns the anchor for the specified [enum Side]. A getter method for [member anchor_bottom], [member anchor_left], [member anchor_right] and [member anchor_top].
</description>
@@ -362,7 +362,7 @@
</method>
<method name="get_cursor_shape" qualifiers="const">
<return type="int" enum="Control.CursorShape" />
- <argument index="0" name="position" type="Vector2" default="Vector2(0, 0)" />
+ <param index="0" name="position" type="Vector2" default="Vector2(0, 0)" />
<description>
Returns the mouse cursor shape the control displays on mouse hover. See [enum CursorShape].
</description>
@@ -375,7 +375,7 @@
</method>
<method name="get_focus_neighbor" qualifiers="const">
<return type="NodePath" />
- <argument index="0" name="side" type="int" enum="Side" />
+ <param index="0" name="side" type="int" enum="Side" />
<description>
Returns the focus neighbor for the specified [enum Side]. A getter method for [member focus_neighbor_bottom], [member focus_neighbor_left], [member focus_neighbor_right] and [member focus_neighbor_top].
</description>
@@ -394,7 +394,7 @@
</method>
<method name="get_offset" qualifiers="const">
<return type="float" />
- <argument index="0" name="offset" type="int" enum="Side" />
+ <param index="0" name="offset" type="int" enum="Side" />
<description>
Returns the anchor for the specified [enum Side]. A getter method for [member offset_bottom], [member offset_left], [member offset_right] and [member offset_top].
</description>
@@ -432,11 +432,11 @@
</method>
<method name="get_theme_color" qualifiers="const">
<return type="Color" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns a [Color] from the first matching [Theme] in the tree if that [Theme] has a color item with the specified [code]name[/code] and [code]theme_type[/code]. If [code]theme_type[/code] is omitted the class name of the current control is used as the type, or [member theme_type_variation] if it is defined. If the type is a class name its parent classes are also checked, in order of inheritance. If the type is a variation its base types are checked, in order of dependency, then the control's class name and its parent classes are checked.
- For the current control its local overrides are considered first (see [method add_theme_color_override]), then its assigned [member theme]. After the current control, each parent control and its assigned [member theme] are considered; controls without a [member theme] assigned are skipped. If no matching [Theme] is found in the tree, a custom project [Theme] (see [member ProjectSettings.gui/theme/custom]) and the default [Theme] are used.
+ Returns a [Color] from the first matching [Theme] in the tree if that [Theme] has a color item with the specified [param name] and [param theme_type]. If [param theme_type] is omitted the class name of the current control is used as the type, or [member theme_type_variation] if it is defined. If the type is a class name its parent classes are also checked, in order of inheritance. If the type is a variation its base types are checked, in order of dependency, then the control's class name and its parent classes are checked.
+ For the current control its local overrides are considered first (see [method add_theme_color_override]), then its assigned [member theme]. After the current control, each parent control and its assigned [member theme] are considered; controls without a [member theme] assigned are skipped. If no matching [Theme] is found in the tree, the custom project [Theme] (see [member ProjectSettings.gui/theme/custom]) and the default [Theme] are used (see [ThemeDB]).
[codeblocks]
[gdscript]
func _ready():
@@ -459,10 +459,10 @@
</method>
<method name="get_theme_constant" qualifiers="const">
<return type="int" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns a constant from the first matching [Theme] in the tree if that [Theme] has a constant item with the specified [code]name[/code] and [code]theme_type[/code].
+ Returns a constant from the first matching [Theme] in the tree if that [Theme] has a constant item with the specified [param name] and [param theme_type].
See [method get_theme_color] for details.
</description>
</method>
@@ -489,45 +489,46 @@
</method>
<method name="get_theme_font" qualifiers="const">
<return type="Font" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns a [Font] from the first matching [Theme] in the tree if that [Theme] has a font item with the specified [code]name[/code] and [code]theme_type[/code].
+ Returns a [Font] from the first matching [Theme] in the tree if that [Theme] has a font item with the specified [param name] and [param theme_type].
See [method get_theme_color] for details.
</description>
</method>
<method name="get_theme_font_size" qualifiers="const">
<return type="int" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns a font size from the first matching [Theme] in the tree if that [Theme] has a font size item with the specified [code]name[/code] and [code]theme_type[/code].
+ Returns a font size from the first matching [Theme] in the tree if that [Theme] has a font size item with the specified [param name] and [param theme_type].
See [method get_theme_color] for details.
</description>
</method>
<method name="get_theme_icon" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns an icon from the first matching [Theme] in the tree if that [Theme] has an icon item with the specified [code]name[/code] and [code]theme_type[/code].
+ Returns an icon from the first matching [Theme] in the tree if that [Theme] has an icon item with the specified [param name] and [param theme_type].
See [method get_theme_color] for details.
</description>
</method>
<method name="get_theme_stylebox" qualifiers="const">
<return type="StyleBox" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns a [StyleBox] from the first matching [Theme] in the tree if that [Theme] has a stylebox item with the specified [code]name[/code] and [code]theme_type[/code].
+ Returns a [StyleBox] from the first matching [Theme] in the tree if that [Theme] has a stylebox item with the specified [param name] and [param theme_type].
See [method get_theme_color] for details.
</description>
</method>
<method name="get_tooltip" qualifiers="const">
<return type="String" />
- <argument index="0" name="at_position" type="Vector2" default="Vector2(0, 0)" />
+ <param index="0" name="at_position" type="Vector2" default="Vector2(0, 0)" />
<description>
- Returns the tooltip, which will appear when the cursor is resting over this control. See [member hint_tooltip].
+ Returns the tooltip text [param at_position] in local coordinates, which will typically appear when the cursor is resting over this control. By default, it returns [member tooltip_text].
+ [b]Note:[/b] This method can be overriden to customise its behaviour. If this method returns an empty [String], no tooltip is displayed.
</description>
</method>
<method name="grab_click_focus">
@@ -562,103 +563,103 @@
</method>
<method name="has_theme_color" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns [code]true[/code] if there is a matching [Theme] in the tree that has a color item with the specified [code]name[/code] and [code]theme_type[/code].
+ Returns [code]true[/code] if there is a matching [Theme] in the tree that has a color item with the specified [param name] and [param theme_type].
See [method get_theme_color] for details.
</description>
</method>
<method name="has_theme_color_override" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Returns [code]true[/code] if there is a local override for a theme [Color] with the specified [code]name[/code] in this [Control] node.
+ Returns [code]true[/code] if there is a local override for a theme [Color] with the specified [param name] in this [Control] node.
See [method add_theme_color_override].
</description>
</method>
<method name="has_theme_constant" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns [code]true[/code] if there is a matching [Theme] in the tree that has a constant item with the specified [code]name[/code] and [code]theme_type[/code].
+ Returns [code]true[/code] if there is a matching [Theme] in the tree that has a constant item with the specified [param name] and [param theme_type].
See [method get_theme_color] for details.
</description>
</method>
<method name="has_theme_constant_override" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Returns [code]true[/code] if there is a local override for a theme constant with the specified [code]name[/code] in this [Control] node.
+ Returns [code]true[/code] if there is a local override for a theme constant with the specified [param name] in this [Control] node.
See [method add_theme_constant_override].
</description>
</method>
<method name="has_theme_font" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns [code]true[/code] if there is a matching [Theme] in the tree that has a font item with the specified [code]name[/code] and [code]theme_type[/code].
+ Returns [code]true[/code] if there is a matching [Theme] in the tree that has a font item with the specified [param name] and [param theme_type].
See [method get_theme_color] for details.
</description>
</method>
<method name="has_theme_font_override" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Returns [code]true[/code] if there is a local override for a theme [Font] with the specified [code]name[/code] in this [Control] node.
+ Returns [code]true[/code] if there is a local override for a theme [Font] with the specified [param name] in this [Control] node.
See [method add_theme_font_override].
</description>
</method>
<method name="has_theme_font_size" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns [code]true[/code] if there is a matching [Theme] in the tree that has a font size item with the specified [code]name[/code] and [code]theme_type[/code].
+ Returns [code]true[/code] if there is a matching [Theme] in the tree that has a font size item with the specified [param name] and [param theme_type].
See [method get_theme_color] for details.
</description>
</method>
<method name="has_theme_font_size_override" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Returns [code]true[/code] if there is a local override for a theme font size with the specified [code]name[/code] in this [Control] node.
+ Returns [code]true[/code] if there is a local override for a theme font size with the specified [param name] in this [Control] node.
See [method add_theme_font_size_override].
</description>
</method>
<method name="has_theme_icon" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns [code]true[/code] if there is a matching [Theme] in the tree that has an icon item with the specified [code]name[/code] and [code]theme_type[/code].
+ Returns [code]true[/code] if there is a matching [Theme] in the tree that has an icon item with the specified [param name] and [param theme_type].
See [method get_theme_color] for details.
</description>
</method>
<method name="has_theme_icon_override" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Returns [code]true[/code] if there is a local override for a theme icon with the specified [code]name[/code] in this [Control] node.
+ Returns [code]true[/code] if there is a local override for a theme icon with the specified [param name] in this [Control] node.
See [method add_theme_icon_override].
</description>
</method>
<method name="has_theme_stylebox" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns [code]true[/code] if there is a matching [Theme] in the tree that has a stylebox item with the specified [code]name[/code] and [code]theme_type[/code].
+ Returns [code]true[/code] if there is a matching [Theme] in the tree that has a stylebox item with the specified [param name] and [param theme_type].
See [method get_theme_color] for details.
</description>
</method>
<method name="has_theme_stylebox_override" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Returns [code]true[/code] if there is a local override for a theme [StyleBox] with the specified [code]name[/code] in this [Control] node.
+ Returns [code]true[/code] if there is a local override for a theme [StyleBox] with the specified [param name] in this [Control] node.
See [method add_theme_stylebox_override].
</description>
</method>
@@ -683,44 +684,44 @@
</method>
<method name="remove_theme_color_override">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Removes a local override for a theme [Color] with the specified [code]name[/code] previously added by [method add_theme_color_override] or via the Inspector dock.
+ Removes a local override for a theme [Color] with the specified [param name] previously added by [method add_theme_color_override] or via the Inspector dock.
</description>
</method>
<method name="remove_theme_constant_override">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Removes a local override for a theme constant with the specified [code]name[/code] previously added by [method add_theme_constant_override] or via the Inspector dock.
+ Removes a local override for a theme constant with the specified [param name] previously added by [method add_theme_constant_override] or via the Inspector dock.
</description>
</method>
<method name="remove_theme_font_override">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Removes a local override for a theme [Font] with the specified [code]name[/code] previously added by [method add_theme_font_override] or via the Inspector dock.
+ Removes a local override for a theme [Font] with the specified [param name] previously added by [method add_theme_font_override] or via the Inspector dock.
</description>
</method>
<method name="remove_theme_font_size_override">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Removes a local override for a theme font size with the specified [code]name[/code] previously added by [method add_theme_font_size_override] or via the Inspector dock.
+ Removes a local override for a theme font size with the specified [param name] previously added by [method add_theme_font_size_override] or via the Inspector dock.
</description>
</method>
<method name="remove_theme_icon_override">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Removes a local override for a theme icon with the specified [code]name[/code] previously added by [method add_theme_icon_override] or via the Inspector dock.
+ Removes a local override for a theme icon with the specified [param name] previously added by [method add_theme_icon_override] or via the Inspector dock.
</description>
</method>
<method name="remove_theme_stylebox_override">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Removes a local override for a theme [StyleBox] with the specified [code]name[/code] previously added by [method add_theme_stylebox_override] or via the Inspector dock.
+ Removes a local override for a theme [StyleBox] with the specified [param name] previously added by [method add_theme_stylebox_override] or via the Inspector dock.
</description>
</method>
<method name="reset_size">
@@ -731,56 +732,56 @@
</method>
<method name="set_anchor">
<return type="void" />
- <argument index="0" name="side" type="int" enum="Side" />
- <argument index="1" name="anchor" type="float" />
- <argument index="2" name="keep_offset" type="bool" default="false" />
- <argument index="3" name="push_opposite_anchor" type="bool" default="true" />
+ <param index="0" name="side" type="int" enum="Side" />
+ <param index="1" name="anchor" type="float" />
+ <param index="2" name="keep_offset" type="bool" default="false" />
+ <param index="3" name="push_opposite_anchor" type="bool" default="true" />
<description>
- Sets the anchor for the specified [enum Side] to [code]anchor[/code]. A setter method for [member anchor_bottom], [member anchor_left], [member anchor_right] and [member anchor_top].
- If [code]keep_offset[/code] is [code]true[/code], offsets aren't updated after this operation.
- If [code]push_opposite_anchor[/code] is [code]true[/code] and the opposite anchor overlaps this anchor, the opposite one will have its value overridden. For example, when setting left anchor to 1 and the right anchor has value of 0.5, the right anchor will also get value of 1. If [code]push_opposite_anchor[/code] was [code]false[/code], the left anchor would get value 0.5.
+ Sets the anchor for the specified [enum Side] to [param anchor]. A setter method for [member anchor_bottom], [member anchor_left], [member anchor_right] and [member anchor_top].
+ If [param keep_offset] is [code]true[/code], offsets aren't updated after this operation.
+ If [param push_opposite_anchor] is [code]true[/code] and the opposite anchor overlaps this anchor, the opposite one will have its value overridden. For example, when setting left anchor to 1 and the right anchor has value of 0.5, the right anchor will also get value of 1. If [param push_opposite_anchor] was [code]false[/code], the left anchor would get value 0.5.
</description>
</method>
<method name="set_anchor_and_offset">
<return type="void" />
- <argument index="0" name="side" type="int" enum="Side" />
- <argument index="1" name="anchor" type="float" />
- <argument index="2" name="offset" type="float" />
- <argument index="3" name="push_opposite_anchor" type="bool" default="false" />
+ <param index="0" name="side" type="int" enum="Side" />
+ <param index="1" name="anchor" type="float" />
+ <param index="2" name="offset" type="float" />
+ <param index="3" name="push_opposite_anchor" type="bool" default="false" />
<description>
Works the same as [method set_anchor], but instead of [code]keep_offset[/code] argument and automatic update of offset, it allows to set the offset yourself (see [method set_offset]).
</description>
</method>
<method name="set_anchors_and_offsets_preset">
<return type="void" />
- <argument index="0" name="preset" type="int" enum="Control.LayoutPreset" />
- <argument index="1" name="resize_mode" type="int" enum="Control.LayoutPresetMode" default="0" />
- <argument index="2" name="margin" type="int" default="0" />
+ <param index="0" name="preset" type="int" enum="Control.LayoutPreset" />
+ <param index="1" name="resize_mode" type="int" enum="Control.LayoutPresetMode" default="0" />
+ <param index="2" name="margin" type="int" default="0" />
<description>
Sets both anchor preset and offset preset. See [method set_anchors_preset] and [method set_offsets_preset].
</description>
</method>
<method name="set_anchors_preset">
<return type="void" />
- <argument index="0" name="preset" type="int" enum="Control.LayoutPreset" />
- <argument index="1" name="keep_offsets" type="bool" default="false" />
+ <param index="0" name="preset" type="int" enum="Control.LayoutPreset" />
+ <param index="1" name="keep_offsets" type="bool" default="false" />
<description>
- Sets the anchors to a [code]preset[/code] from [enum Control.LayoutPreset] enum. This is the code equivalent to using the Layout menu in the 2D editor.
- If [code]keep_offsets[/code] is [code]true[/code], control's position will also be updated.
+ Sets the anchors to a [param preset] from [enum Control.LayoutPreset] enum. This is the code equivalent to using the Layout menu in the 2D editor.
+ If [param keep_offsets] is [code]true[/code], control's position will also be updated.
</description>
</method>
<method name="set_begin">
<return type="void" />
- <argument index="0" name="position" type="Vector2" />
+ <param index="0" name="position" type="Vector2" />
<description>
Sets [member offset_left] and [member offset_top] at the same time. Equivalent of changing [member position].
</description>
</method>
<method name="set_drag_forwarding">
<return type="void" />
- <argument index="0" name="target" type="Object" />
+ <param index="0" name="target" type="Object" />
<description>
- Forwards the handling of this control's drag and drop to [code]target[/code] object.
+ Forwards the handling of this control's drag and drop to [param target] object.
Forwarding can be implemented in the target object similar to the methods [method _get_drag_data], [method _can_drop_data], and [method _drop_data] but with two differences:
1. The function name must be suffixed with [b]_fw[/b]
2. The function must take an extra argument that is the control doing the forwarding
@@ -843,7 +844,7 @@
</method>
<method name="set_drag_preview">
<return type="void" />
- <argument index="0" name="control" type="Control" />
+ <param index="0" name="control" type="Control" />
<description>
Shows the given control at the mouse pointer. A good time to call this method is in [method _get_drag_data]. The control must not be in the scene tree. You should not free the control, and you should not keep a reference to the control beyond the duration of the drag. It will be deleted automatically after the drag has ended.
[codeblocks]
@@ -877,63 +878,63 @@
</method>
<method name="set_end">
<return type="void" />
- <argument index="0" name="position" type="Vector2" />
+ <param index="0" name="position" type="Vector2" />
<description>
Sets [member offset_right] and [member offset_bottom] at the same time.
</description>
</method>
<method name="set_focus_neighbor">
<return type="void" />
- <argument index="0" name="side" type="int" enum="Side" />
- <argument index="1" name="neighbor" type="NodePath" />
+ <param index="0" name="side" type="int" enum="Side" />
+ <param index="1" name="neighbor" type="NodePath" />
<description>
- Sets the anchor for the specified [enum Side] to the [Control] at [code]neighbor[/code] node path. A setter method for [member focus_neighbor_bottom], [member focus_neighbor_left], [member focus_neighbor_right] and [member focus_neighbor_top].
+ Sets the anchor for the specified [enum Side] to the [Control] at [param neighbor] node path. A setter method for [member focus_neighbor_bottom], [member focus_neighbor_left], [member focus_neighbor_right] and [member focus_neighbor_top].
</description>
</method>
<method name="set_global_position">
<return type="void" />
- <argument index="0" name="position" type="Vector2" />
- <argument index="1" name="keep_offsets" type="bool" default="false" />
+ <param index="0" name="position" type="Vector2" />
+ <param index="1" name="keep_offsets" type="bool" default="false" />
<description>
- Sets the [member global_position] to given [code]position[/code].
- If [code]keep_offsets[/code] is [code]true[/code], control's anchors will be updated instead of offsets.
+ Sets the [member global_position] to given [param position].
+ If [param keep_offsets] is [code]true[/code], control's anchors will be updated instead of offsets.
</description>
</method>
<method name="set_offset">
<return type="void" />
- <argument index="0" name="side" type="int" enum="Side" />
- <argument index="1" name="offset" type="float" />
+ <param index="0" name="side" type="int" enum="Side" />
+ <param index="1" name="offset" type="float" />
<description>
- Sets the offset for the specified [enum Side] to [code]offset[/code]. A setter method for [member offset_bottom], [member offset_left], [member offset_right] and [member offset_top].
+ Sets the offset for the specified [enum Side] to [param offset]. A setter method for [member offset_bottom], [member offset_left], [member offset_right] and [member offset_top].
</description>
</method>
<method name="set_offsets_preset">
<return type="void" />
- <argument index="0" name="preset" type="int" enum="Control.LayoutPreset" />
- <argument index="1" name="resize_mode" type="int" enum="Control.LayoutPresetMode" default="0" />
- <argument index="2" name="margin" type="int" default="0" />
+ <param index="0" name="preset" type="int" enum="Control.LayoutPreset" />
+ <param index="1" name="resize_mode" type="int" enum="Control.LayoutPresetMode" default="0" />
+ <param index="2" name="margin" type="int" default="0" />
<description>
- Sets the offsets to a [code]preset[/code] from [enum Control.LayoutPreset] enum. This is the code equivalent to using the Layout menu in the 2D editor.
- Use parameter [code]resize_mode[/code] with constants from [enum Control.LayoutPresetMode] to better determine the resulting size of the [Control]. Constant size will be ignored if used with presets that change size, e.g. [code]PRESET_LEFT_WIDE[/code].
- Use parameter [code]margin[/code] to determine the gap between the [Control] and the edges.
+ Sets the offsets to a [param preset] from [enum Control.LayoutPreset] enum. This is the code equivalent to using the Layout menu in the 2D editor.
+ Use parameter [param resize_mode] with constants from [enum Control.LayoutPresetMode] to better determine the resulting size of the [Control]. Constant size will be ignored if used with presets that change size, e.g. [code]PRESET_LEFT_WIDE[/code].
+ Use parameter [param margin] to determine the gap between the [Control] and the edges.
</description>
</method>
<method name="set_position">
<return type="void" />
- <argument index="0" name="position" type="Vector2" />
- <argument index="1" name="keep_offsets" type="bool" default="false" />
+ <param index="0" name="position" type="Vector2" />
+ <param index="1" name="keep_offsets" type="bool" default="false" />
<description>
- Sets the [member position] to given [code]position[/code].
- If [code]keep_offsets[/code] is [code]true[/code], control's anchors will be updated instead of offsets.
+ Sets the [member position] to given [param position].
+ If [param keep_offsets] is [code]true[/code], control's anchors will be updated instead of offsets.
</description>
</method>
<method name="set_size">
<return type="void" />
- <argument index="0" name="size" type="Vector2" />
- <argument index="1" name="keep_offsets" type="bool" default="false" />
+ <param index="0" name="size" type="Vector2" />
+ <param index="1" name="keep_offsets" type="bool" default="false" />
<description>
Sets the size (see [member size]).
- If [code]keep_offsets[/code] is [code]true[/code], control's anchors will be updated instead of offsets.
+ If [param keep_offsets] is [code]true[/code], control's anchors will be updated instead of offsets.
</description>
</method>
<method name="update_minimum_size">
@@ -944,9 +945,9 @@
</method>
<method name="warp_mouse">
<return type="void" />
- <argument index="0" name="position" type="Vector2" />
+ <param index="0" name="position" type="Vector2" />
<description>
- Moves the mouse cursor to [code]position[/code], relative to [member position] of this [Control].
+ Moves the mouse cursor to [param position], relative to [member position] of this [Control].
</description>
</method>
</methods>
@@ -1005,28 +1006,6 @@
<member name="grow_vertical" type="int" setter="set_v_grow_direction" getter="get_v_grow_direction" enum="Control.GrowDirection" default="1">
Controls the direction on the vertical axis in which the control should grow if its vertical minimum size is changed to be greater than its current size, as the control always has to be at least the minimum size.
</member>
- <member name="hint_tooltip" type="String" setter="set_tooltip" getter="_get_tooltip" default="&quot;&quot;">
- Changes the tooltip text. The tooltip appears when the user's mouse cursor stays idle over this control for a few moments, provided that the [member mouse_filter] property is not [constant MOUSE_FILTER_IGNORE]. You can change the time required for the tooltip to appear with [code]gui/timers/tooltip_delay_sec[/code] option in Project Settings.
- The tooltip popup will use either a default implementation, or a custom one that you can provide by overriding [method _make_custom_tooltip]. The default tooltip includes a [PopupPanel] and [Label] whose theme properties can be customized using [Theme] methods with the [code]"TooltipPanel"[/code] and [code]"TooltipLabel"[/code] respectively. For example:
- [codeblocks]
- [gdscript]
- var style_box = StyleBoxFlat.new()
- style_box.set_bg_color(Color(1, 1, 0))
- style_box.set_border_width_all(2)
- # We assume here that the `theme` property has been assigned a custom Theme beforehand.
- theme.set_stylebox("panel", "TooltipPanel", style_box)
- theme.set_color("font_color", "TooltipLabel", Color(0, 1, 1))
- [/gdscript]
- [csharp]
- var styleBox = new StyleBoxFlat();
- styleBox.SetBgColor(new Color(1, 1, 0));
- styleBox.SetBorderWidthAll(2);
- // We assume here that the `Theme` property has been assigned a custom Theme beforehand.
- Theme.SetStyleBox("panel", "TooltipPanel", styleBox);
- Theme.SetColor("font_color", "TooltipLabel", new Color(0, 1, 1));
- [/csharp]
- [/codeblocks]
- </member>
<member name="layout_direction" type="int" setter="set_layout_direction" getter="get_layout_direction" enum="Control.LayoutDirection" default="0">
Controls layout direction and text writing direction. Right-to-left layouts are necessary for certain languages (e.g. Arabic and Hebrew).
</member>
@@ -1067,7 +1046,7 @@
The node's rotation around its pivot, in radians. See [member pivot_offset] to change the pivot's position.
</member>
<member name="scale" type="Vector2" setter="set_scale" getter="get_scale" default="Vector2(1, 1)">
- The node's scale, relative to its [member size]. Change this property to scale the node around its [member pivot_offset]. The Control's [member hint_tooltip] will also scale according to this value.
+ The node's scale, relative to its [member size]. Change this property to scale the node around its [member pivot_offset]. The Control's [member tooltip_text] will also scale according to this value.
[b]Note:[/b] This property is mainly intended to be used for animation purposes. Text inside the Control will look pixelated or blurry when the Control is scaled. To support multiple resolutions in your project, use an appropriate viewport stretch mode as described in the [url=$DOCS_URL/tutorials/viewports/multiple_resolutions.html]documentation[/url] instead of scaling Controls individually.
[b]Note:[/b] If the Control node is a child of a [Container] node, the scale will be reset to [code]Vector2(1, 1)[/code] when the scene is instantiated. To set the Control's scale when it's instantiated, wait for one frame using [code]await get_tree().process_frame[/code] then set its [member scale] property.
</member>
@@ -1092,6 +1071,28 @@
[b]Note:[/b] To look up [Control]'s own items use various [code]get_theme_*[/code] methods without specifying [code]theme_type[/code].
[b]Note:[/b] Theme items are looked for in the tree order, from branch to root, where each [Control] node is checked for its [member theme] property. The earliest match against any type/class name is returned. The project-level Theme and the default Theme are checked last.
</member>
+ <member name="tooltip_text" type="String" setter="set_tooltip_text" getter="get_tooltip_text" default="&quot;&quot;">
+ The default tooltip text. The tooltip appears when the user's mouse cursor stays idle over this control for a few moments, provided that the [member mouse_filter] property is not [constant MOUSE_FILTER_IGNORE]. The time required for the tooltip to appear can be changed with the [code]gui/timers/tooltip_delay_sec[/code] option in Project Settings. See also [method get_tooltip].
+ The tooltip popup will use either a default implementation, or a custom one that you can provide by overriding [method _make_custom_tooltip]. The default tooltip includes a [PopupPanel] and [Label] whose theme properties can be customized using [Theme] methods with the [code]"TooltipPanel"[/code] and [code]"TooltipLabel"[/code] respectively. For example:
+ [codeblocks]
+ [gdscript]
+ var style_box = StyleBoxFlat.new()
+ style_box.set_bg_color(Color(1, 1, 0))
+ style_box.set_border_width_all(2)
+ # We assume here that the `theme` property has been assigned a custom Theme beforehand.
+ theme.set_stylebox("panel", "TooltipPanel", style_box)
+ theme.set_color("font_color", "TooltipLabel", Color(0, 1, 1))
+ [/gdscript]
+ [csharp]
+ var styleBox = new StyleBoxFlat();
+ styleBox.SetBgColor(new Color(1, 1, 0));
+ styleBox.SetBorderWidthAll(2);
+ // We assume here that the `Theme` property has been assigned a custom Theme beforehand.
+ Theme.SetStyleBox("panel", "TooltipPanel", styleBox);
+ Theme.SetColor("font_color", "TooltipLabel", new Color(0, 1, 1));
+ [/csharp]
+ [/codeblocks]
+ </member>
</members>
<signals>
<signal name="focus_entered">
@@ -1105,7 +1106,7 @@
</description>
</signal>
<signal name="gui_input">
- <argument index="0" name="event" type="InputEvent" />
+ <param index="0" name="event" type="InputEvent" />
<description>
Emitted when the node receives an [InputEvent].
</description>
@@ -1145,6 +1146,7 @@
</signal>
<signal name="theme_changed">
<description>
+ Emitted when the [constant NOTIFICATION_THEME_CHANGED] notification is sent.
</description>
</signal>
</signals>
@@ -1174,7 +1176,12 @@
Sent when the node loses focus.
</constant>
<constant name="NOTIFICATION_THEME_CHANGED" value="45">
- Sent when the node's [member theme] changes, right before Godot redraws the control. Happens when you call one of the [code]add_theme_*_override[/code] methods.
+ Sent when the node needs to refresh its theme items. This happens in one of the following cases:
+ - The [member theme] property is changed on this node or any of its ancestors.
+ - The [member theme_type_variation] property is changed on this node.
+ - One of the node's theme property overrides is changed.
+ - The node enters the scene tree.
+ [b]Note:[/b] As an optimization, this notification won't be sent from changes that occur while this node is outside of the scene tree. Instead, all of the theme item updates can be applied at once when the node enters the scene tree.
</constant>
<constant name="NOTIFICATION_SCROLL_BEGIN" value="47">
Sent when this node is inside a [ScrollContainer] which has begun being scrolled.
diff --git a/doc/classes/ConvexPolygonShape2D.xml b/doc/classes/ConvexPolygonShape2D.xml
index df96b50fc1..862626d9b6 100644
--- a/doc/classes/ConvexPolygonShape2D.xml
+++ b/doc/classes/ConvexPolygonShape2D.xml
@@ -13,7 +13,7 @@
<methods>
<method name="set_point_cloud">
<return type="void" />
- <argument index="0" name="point_cloud" type="PackedVector2Array" />
+ <param index="0" name="point_cloud" type="PackedVector2Array" />
<description>
Based on the set of points provided, this creates and assigns the [member points] property using the convex hull algorithm. Removing all unneeded points. See [method Geometry2D.convex_hull] for details.
</description>
diff --git a/doc/classes/Crypto.xml b/doc/classes/Crypto.xml
index 4936fc1d85..dab2a77584 100644
--- a/doc/classes/Crypto.xml
+++ b/doc/classes/Crypto.xml
@@ -74,8 +74,8 @@
<methods>
<method name="constant_time_compare">
<return type="bool" />
- <argument index="0" name="trusted" type="PackedByteArray" />
- <argument index="1" name="received" type="PackedByteArray" />
+ <param index="0" name="trusted" type="PackedByteArray" />
+ <param index="1" name="received" type="PackedByteArray" />
<description>
Compares two [PackedByteArray]s for equality without leaking timing information in order to prevent timing attacks.
See [url=https://paragonie.com/blog/2015/11/preventing-timing-attacks-on-string-comparison-with-double-hmac-strategy]this blog post[/url] for more information.
@@ -83,44 +83,44 @@
</method>
<method name="decrypt">
<return type="PackedByteArray" />
- <argument index="0" name="key" type="CryptoKey" />
- <argument index="1" name="ciphertext" type="PackedByteArray" />
+ <param index="0" name="key" type="CryptoKey" />
+ <param index="1" name="ciphertext" type="PackedByteArray" />
<description>
- Decrypt the given [code]ciphertext[/code] with the provided private [code]key[/code].
+ Decrypt the given [param ciphertext] with the provided private [param key].
[b]Note:[/b] The maximum size of accepted ciphertext is limited by the key size.
</description>
</method>
<method name="encrypt">
<return type="PackedByteArray" />
- <argument index="0" name="key" type="CryptoKey" />
- <argument index="1" name="plaintext" type="PackedByteArray" />
+ <param index="0" name="key" type="CryptoKey" />
+ <param index="1" name="plaintext" type="PackedByteArray" />
<description>
- Encrypt the given [code]plaintext[/code] with the provided public [code]key[/code].
+ Encrypt the given [param plaintext] with the provided public [param key].
[b]Note:[/b] The maximum size of accepted plaintext is limited by the key size.
</description>
</method>
<method name="generate_random_bytes">
<return type="PackedByteArray" />
- <argument index="0" name="size" type="int" />
+ <param index="0" name="size" type="int" />
<description>
- Generates a [PackedByteArray] of cryptographically secure random bytes with given [code]size[/code].
+ Generates a [PackedByteArray] of cryptographically secure random bytes with given [param size].
</description>
</method>
<method name="generate_rsa">
<return type="CryptoKey" />
- <argument index="0" name="size" type="int" />
+ <param index="0" name="size" type="int" />
<description>
Generates an RSA [CryptoKey] that can be used for creating self-signed certificates and passed to [method StreamPeerSSL.accept_stream].
</description>
</method>
<method name="generate_self_signed_certificate">
<return type="X509Certificate" />
- <argument index="0" name="key" type="CryptoKey" />
- <argument index="1" name="issuer_name" type="String" default="&quot;CN=myserver,O=myorganisation,C=IT&quot;" />
- <argument index="2" name="not_before" type="String" default="&quot;20140101000000&quot;" />
- <argument index="3" name="not_after" type="String" default="&quot;20340101000000&quot;" />
+ <param index="0" name="key" type="CryptoKey" />
+ <param index="1" name="issuer_name" type="String" default="&quot;CN=myserver,O=myorganisation,C=IT&quot;" />
+ <param index="2" name="not_before" type="String" default="&quot;20140101000000&quot;" />
+ <param index="3" name="not_after" type="String" default="&quot;20340101000000&quot;" />
<description>
- Generates a self-signed [X509Certificate] from the given [CryptoKey] and [code]issuer_name[/code]. The certificate validity will be defined by [code]not_before[/code] and [code]not_after[/code] (first valid date and last valid date). The [code]issuer_name[/code] must contain at least "CN=" (common name, i.e. the domain name), "O=" (organization, i.e. your company name), "C=" (country, i.e. 2 lettered ISO-3166 code of the country the organization is based in).
+ Generates a self-signed [X509Certificate] from the given [CryptoKey] and [param issuer_name]. The certificate validity will be defined by [param not_before] and [param not_after] (first valid date and last valid date). The [param issuer_name] must contain at least "CN=" (common name, i.e. the domain name), "O=" (organization, i.e. your company name), "C=" (country, i.e. 2 lettered ISO-3166 code of the country the organization is based in).
A small example to generate an RSA key and a X509 self-signed certificate.
[codeblocks]
[gdscript]
@@ -142,31 +142,31 @@
</method>
<method name="hmac_digest">
<return type="PackedByteArray" />
- <argument index="0" name="hash_type" type="int" enum="HashingContext.HashType" />
- <argument index="1" name="key" type="PackedByteArray" />
- <argument index="2" name="msg" type="PackedByteArray" />
+ <param index="0" name="hash_type" type="int" enum="HashingContext.HashType" />
+ <param index="1" name="key" type="PackedByteArray" />
+ <param index="2" name="msg" type="PackedByteArray" />
<description>
- Generates an [url=https://en.wikipedia.org/wiki/HMAC]HMAC[/url] digest of [code]msg[/code] using [code]key[/code]. The [code]hash_type[/code] parameter is the hashing algorithm that is used for the inner and outer hashes.
+ Generates an [url=https://en.wikipedia.org/wiki/HMAC]HMAC[/url] digest of [param msg] using [param key]. The [param hash_type] parameter is the hashing algorithm that is used for the inner and outer hashes.
Currently, only [constant HashingContext.HASH_SHA256] and [constant HashingContext.HASH_SHA1] are supported.
</description>
</method>
<method name="sign">
<return type="PackedByteArray" />
- <argument index="0" name="hash_type" type="int" enum="HashingContext.HashType" />
- <argument index="1" name="hash" type="PackedByteArray" />
- <argument index="2" name="key" type="CryptoKey" />
+ <param index="0" name="hash_type" type="int" enum="HashingContext.HashType" />
+ <param index="1" name="hash" type="PackedByteArray" />
+ <param index="2" name="key" type="CryptoKey" />
<description>
- Sign a given [code]hash[/code] of type [code]hash_type[/code] with the provided private [code]key[/code].
+ Sign a given [param hash] of type [param hash_type] with the provided private [param key].
</description>
</method>
<method name="verify">
<return type="bool" />
- <argument index="0" name="hash_type" type="int" enum="HashingContext.HashType" />
- <argument index="1" name="hash" type="PackedByteArray" />
- <argument index="2" name="signature" type="PackedByteArray" />
- <argument index="3" name="key" type="CryptoKey" />
+ <param index="0" name="hash_type" type="int" enum="HashingContext.HashType" />
+ <param index="1" name="hash" type="PackedByteArray" />
+ <param index="2" name="signature" type="PackedByteArray" />
+ <param index="3" name="key" type="CryptoKey" />
<description>
- Verify that a given [code]signature[/code] for [code]hash[/code] of type [code]hash_type[/code] against the provided public [code]key[/code].
+ Verify that a given [param signature] for [param hash] of type [param hash_type] against the provided public [param key].
</description>
</method>
</methods>
diff --git a/doc/classes/CryptoKey.xml b/doc/classes/CryptoKey.xml
index 8496c6dec1..1f502846b4 100644
--- a/doc/classes/CryptoKey.xml
+++ b/doc/classes/CryptoKey.xml
@@ -18,35 +18,35 @@
</method>
<method name="load">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="public_only" type="bool" default="false" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="public_only" type="bool" default="false" />
<description>
- Loads a key from [code]path[/code]. If [code]public_only[/code] is [code]true[/code], only the public key will be loaded.
- [b]Note:[/b] [code]path[/code] should be a "*.pub" file if [code]public_only[/code] is [code]true[/code], a "*.key" file otherwise.
+ Loads a key from [param path]. If [param public_only] is [code]true[/code], only the public key will be loaded.
+ [b]Note:[/b] [param path] should be a "*.pub" file if [param public_only] is [code]true[/code], a "*.key" file otherwise.
</description>
</method>
<method name="load_from_string">
<return type="int" enum="Error" />
- <argument index="0" name="string_key" type="String" />
- <argument index="1" name="public_only" type="bool" default="false" />
+ <param index="0" name="string_key" type="String" />
+ <param index="1" name="public_only" type="bool" default="false" />
<description>
- Loads a key from the given [code]string[/code]. If [code]public_only[/code] is [code]true[/code], only the public key will be loaded.
+ Loads a key from the given [param string_key]. If [param public_only] is [code]true[/code], only the public key will be loaded.
</description>
</method>
<method name="save">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="public_only" type="bool" default="false" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="public_only" type="bool" default="false" />
<description>
- Saves a key to the given [code]path[/code]. If [code]public_only[/code] is [code]true[/code], only the public key will be saved.
- [b]Note:[/b] [code]path[/code] should be a "*.pub" file if [code]public_only[/code] is [code]true[/code], a "*.key" file otherwise.
+ Saves a key to the given [param path]. If [param public_only] is [code]true[/code], only the public key will be saved.
+ [b]Note:[/b] [param path] should be a "*.pub" file if [param public_only] is [code]true[/code], a "*.key" file otherwise.
</description>
</method>
<method name="save_to_string">
<return type="String" />
- <argument index="0" name="public_only" type="bool" default="false" />
+ <param index="0" name="public_only" type="bool" default="false" />
<description>
- Returns a string containing the key in PEM format. If [code]public_only[/code] is [code]true[/code], only the public key will be included.
+ Returns a string containing the key in PEM format. If [param public_only] is [code]true[/code], only the public key will be included.
</description>
</method>
</methods>
diff --git a/doc/classes/Curve.xml b/doc/classes/Curve.xml
index 383d33532b..ae9add995b 100644
--- a/doc/classes/Curve.xml
+++ b/doc/classes/Curve.xml
@@ -5,17 +5,18 @@
</brief_description>
<description>
A curve that can be saved and re-used for other objects. By default, it ranges between [code]0[/code] and [code]1[/code] on the Y axis and positions points relative to the [code]0.5[/code] Y position.
+ See also [Gradient] which is designed for color interpolation. See also [Curve2D] and [Curve3D].
</description>
<tutorials>
</tutorials>
<methods>
<method name="add_point">
<return type="int" />
- <argument index="0" name="position" type="Vector2" />
- <argument index="1" name="left_tangent" type="float" default="0" />
- <argument index="2" name="right_tangent" type="float" default="0" />
- <argument index="3" name="left_mode" type="int" enum="Curve.TangentMode" default="0" />
- <argument index="4" name="right_mode" type="int" enum="Curve.TangentMode" default="0" />
+ <param index="0" name="position" type="Vector2" />
+ <param index="1" name="left_tangent" type="float" default="0" />
+ <param index="2" name="right_tangent" type="float" default="0" />
+ <param index="3" name="left_mode" type="int" enum="Curve.TangentMode" default="0" />
+ <param index="4" name="right_mode" type="int" enum="Curve.TangentMode" default="0" />
<description>
Adds a point to the curve. For each side, if the [code]*_mode[/code] is [constant TANGENT_LINEAR], the [code]*_tangent[/code] angle (in degrees) uses the slope of the curve halfway to the adjacent point. Allows custom assignments to the [code]*_tangent[/code] angle if [code]*_mode[/code] is set to [constant TANGENT_FREE].
</description>
@@ -40,106 +41,106 @@
</method>
<method name="get_point_left_mode" qualifiers="const">
<return type="int" enum="Curve.TangentMode" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the left [enum TangentMode] for the point at [code]index[/code].
+ Returns the left [enum TangentMode] for the point at [param index].
</description>
</method>
<method name="get_point_left_tangent" qualifiers="const">
<return type="float" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the left tangent angle (in degrees) for the point at [code]index[/code].
+ Returns the left tangent angle (in degrees) for the point at [param index].
</description>
</method>
<method name="get_point_position" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the curve coordinates for the point at [code]index[/code].
+ Returns the curve coordinates for the point at [param index].
</description>
</method>
<method name="get_point_right_mode" qualifiers="const">
<return type="int" enum="Curve.TangentMode" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the right [enum TangentMode] for the point at [code]index[/code].
+ Returns the right [enum TangentMode] for the point at [param index].
</description>
</method>
<method name="get_point_right_tangent" qualifiers="const">
<return type="float" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the right tangent angle (in degrees) for the point at [code]index[/code].
+ Returns the right tangent angle (in degrees) for the point at [param index].
</description>
</method>
<method name="interpolate" qualifiers="const">
<return type="float" />
- <argument index="0" name="offset" type="float" />
+ <param index="0" name="offset" type="float" />
<description>
- Returns the Y value for the point that would exist at the X position [code]offset[/code] along the curve.
+ Returns the Y value for the point that would exist at the X position [param offset] along the curve.
</description>
</method>
<method name="interpolate_baked" qualifiers="const">
<return type="float" />
- <argument index="0" name="offset" type="float" />
+ <param index="0" name="offset" type="float" />
<description>
- Returns the Y value for the point that would exist at the X position [code]offset[/code] along the curve using the baked cache. Bakes the curve's points if not already baked.
+ Returns the Y value for the point that would exist at the X position [param offset] along the curve using the baked cache. Bakes the curve's points if not already baked.
</description>
</method>
<method name="remove_point">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Removes the point at [code]index[/code] from the curve.
+ Removes the point at [param index] from the curve.
</description>
</method>
<method name="set_point_left_mode">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="mode" type="int" enum="Curve.TangentMode" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="mode" type="int" enum="Curve.TangentMode" />
<description>
- Sets the left [enum TangentMode] for the point at [code]index[/code] to [code]mode[/code].
+ Sets the left [enum TangentMode] for the point at [param index] to [param mode].
</description>
</method>
<method name="set_point_left_tangent">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="tangent" type="float" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="tangent" type="float" />
<description>
- Sets the left tangent angle for the point at [code]index[/code] to [code]tangent[/code].
+ Sets the left tangent angle for the point at [param index] to [param tangent].
</description>
</method>
<method name="set_point_offset">
<return type="int" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="offset" type="float" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="offset" type="float" />
<description>
Sets the offset from [code]0.5[/code].
</description>
</method>
<method name="set_point_right_mode">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="mode" type="int" enum="Curve.TangentMode" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="mode" type="int" enum="Curve.TangentMode" />
<description>
- Sets the right [enum TangentMode] for the point at [code]index[/code] to [code]mode[/code].
+ Sets the right [enum TangentMode] for the point at [param index] to [param mode].
</description>
</method>
<method name="set_point_right_tangent">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="tangent" type="float" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="tangent" type="float" />
<description>
- Sets the right tangent angle for the point at [code]index[/code] to [code]tangent[/code].
+ Sets the right tangent angle for the point at [param index] to [param tangent].
</description>
</method>
<method name="set_point_value">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="y" type="float" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="y" type="float" />
<description>
- Assigns the vertical position [code]y[/code] to the point at [code]index[/code].
+ Assigns the vertical position [param y] to the point at [param index].
</description>
</method>
</methods>
diff --git a/doc/classes/Curve2D.xml b/doc/classes/Curve2D.xml
index 3bba825aaa..f15c0d74ca 100644
--- a/doc/classes/Curve2D.xml
+++ b/doc/classes/Curve2D.xml
@@ -12,13 +12,13 @@
<methods>
<method name="add_point">
<return type="void" />
- <argument index="0" name="position" type="Vector2" />
- <argument index="1" name="in" type="Vector2" default="Vector2(0, 0)" />
- <argument index="2" name="out" type="Vector2" default="Vector2(0, 0)" />
- <argument index="3" name="at_position" type="int" default="-1" />
+ <param index="0" name="position" type="Vector2" />
+ <param index="1" name="in" type="Vector2" default="Vector2(0, 0)" />
+ <param index="2" name="out" type="Vector2" default="Vector2(0, 0)" />
+ <param index="3" name="index" type="int" default="-1" />
<description>
- Adds a point to a curve at [code]position[/code] relative to the [Curve2D]'s position, with control points [code]in[/code] and [code]out[/code].
- If [code]at_position[/code] is given, the point is inserted before the point number [code]at_position[/code], moving that point (and every point after) after the inserted point. If [code]at_position[/code] is not given, or is an illegal value ([code]at_position &lt;0[/code] or [code]at_position &gt;= [method get_point_count][/code]), the point will be appended at the end of the point list.
+ Adds a point with the specified [param position] relative to the curve's own position, with control points [param in] and [param out]. Appends the new point at the end of the point list.
+ If [param index] is given, the new point is inserted before the existing point identified by index [param index]. Every existing point starting from [param index] is shifted further down the list of points. The index must be greater than or equal to [code]0[/code] and must not exceed the number of existing points in the line. See [member point_count].
</description>
</method>
<method name="clear_points">
@@ -41,107 +41,107 @@
</method>
<method name="get_closest_offset" qualifiers="const">
<return type="float" />
- <argument index="0" name="to_point" type="Vector2" />
+ <param index="0" name="to_point" type="Vector2" />
<description>
- Returns the closest offset to [code]to_point[/code]. This offset is meant to be used in [method interpolate_baked].
- [code]to_point[/code] must be in this curve's local space.
+ Returns the closest offset to [param to_point]. This offset is meant to be used in [method interpolate_baked].
+ [param to_point] must be in this curve's local space.
</description>
</method>
<method name="get_closest_point" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="to_point" type="Vector2" />
+ <param index="0" name="to_point" type="Vector2" />
<description>
- Returns the closest baked point (in curve's local space) to [code]to_point[/code].
- [code]to_point[/code] must be in this curve's local space.
+ Returns the closest baked point (in curve's local space) to [param to_point].
+ [param to_point] must be in this curve's local space.
</description>
</method>
<method name="get_point_in" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the position of the control point leading to the vertex [code]idx[/code]. The returned position is relative to the vertex [code]idx[/code]. If the index is out of bounds, the function sends an error to the console, and returns [code](0, 0)[/code].
+ Returns the position of the control point leading to the vertex [param idx]. The returned position is relative to the vertex [param idx]. If the index is out of bounds, the function sends an error to the console, and returns [code](0, 0)[/code].
</description>
</method>
<method name="get_point_out" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the position of the control point leading out of the vertex [code]idx[/code]. The returned position is relative to the vertex [code]idx[/code]. If the index is out of bounds, the function sends an error to the console, and returns [code](0, 0)[/code].
+ Returns the position of the control point leading out of the vertex [param idx]. The returned position is relative to the vertex [param idx]. If the index is out of bounds, the function sends an error to the console, and returns [code](0, 0)[/code].
</description>
</method>
<method name="get_point_position" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the position of the vertex [code]idx[/code]. If the index is out of bounds, the function sends an error to the console, and returns [code](0, 0)[/code].
+ Returns the position of the vertex [param idx]. If the index is out of bounds, the function sends an error to the console, and returns [code](0, 0)[/code].
</description>
</method>
<method name="interpolate" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="t" type="float" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="t" type="float" />
<description>
- Returns the position between the vertex [code]idx[/code] and the vertex [code]idx + 1[/code], where [code]t[/code] controls if the point is the first vertex ([code]t = 0.0[/code]), the last vertex ([code]t = 1.0[/code]), or in between. Values of [code]t[/code] outside the range ([code]0.0 &gt;= t &lt;=1[/code]) give strange, but predictable results.
- If [code]idx[/code] is out of bounds it is truncated to the first or last vertex, and [code]t[/code] is ignored. If the curve has no points, the function sends an error to the console, and returns [code](0, 0)[/code].
+ Returns the position between the vertex [param idx] and the vertex [code]idx + 1[/code], where [param t] controls if the point is the first vertex ([code]t = 0.0[/code]), the last vertex ([code]t = 1.0[/code]), or in between. Values of [param t] outside the range ([code]0.0 &gt;= t &lt;=1[/code]) give strange, but predictable results.
+ If [param idx] is out of bounds it is truncated to the first or last vertex, and [param t] is ignored. If the curve has no points, the function sends an error to the console, and returns [code](0, 0)[/code].
</description>
</method>
<method name="interpolate_baked" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="offset" type="float" />
- <argument index="1" name="cubic" type="bool" default="false" />
+ <param index="0" name="offset" type="float" />
+ <param index="1" name="cubic" type="bool" default="false" />
<description>
- Returns a point within the curve at position [code]offset[/code], where [code]offset[/code] is measured as a pixel distance along the curve.
- To do that, it finds the two cached points where the [code]offset[/code] lies between, then interpolates the values. This interpolation is cubic if [code]cubic[/code] is set to [code]true[/code], or linear if set to [code]false[/code].
+ Returns a point within the curve at position [param offset], where [param offset] is measured as a pixel distance along the curve.
+ To do that, it finds the two cached points where the [param offset] lies between, then interpolates the values. This interpolation is cubic if [param cubic] is set to [code]true[/code], or linear if set to [code]false[/code].
Cubic interpolation tends to follow the curves better, but linear is faster (and often, precise enough).
</description>
</method>
<method name="interpolatef" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="fofs" type="float" />
+ <param index="0" name="fofs" type="float" />
<description>
- Returns the position at the vertex [code]fofs[/code]. It calls [method interpolate] using the integer part of [code]fofs[/code] as [code]idx[/code], and its fractional part as [code]t[/code].
+ Returns the position at the vertex [param fofs]. It calls [method interpolate] using the integer part of [param fofs] as [code]idx[/code], and its fractional part as [code]t[/code].
</description>
</method>
<method name="remove_point">
<return type="void" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Deletes the point [code]idx[/code] from the curve. Sends an error to the console if [code]idx[/code] is out of bounds.
+ Deletes the point [param idx] from the curve. Sends an error to the console if [param idx] is out of bounds.
</description>
</method>
<method name="set_point_in">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="position" type="Vector2" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="position" type="Vector2" />
<description>
- Sets the position of the control point leading to the vertex [code]idx[/code]. If the index is out of bounds, the function sends an error to the console. The position is relative to the vertex.
+ Sets the position of the control point leading to the vertex [param idx]. If the index is out of bounds, the function sends an error to the console. The position is relative to the vertex.
</description>
</method>
<method name="set_point_out">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="position" type="Vector2" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="position" type="Vector2" />
<description>
- Sets the position of the control point leading out of the vertex [code]idx[/code]. If the index is out of bounds, the function sends an error to the console. The position is relative to the vertex.
+ Sets the position of the control point leading out of the vertex [param idx]. If the index is out of bounds, the function sends an error to the console. The position is relative to the vertex.
</description>
</method>
<method name="set_point_position">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="position" type="Vector2" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="position" type="Vector2" />
<description>
- Sets the position for the vertex [code]idx[/code]. If the index is out of bounds, the function sends an error to the console.
+ Sets the position for the vertex [param idx]. If the index is out of bounds, the function sends an error to the console.
</description>
</method>
<method name="tessellate" qualifiers="const">
<return type="PackedVector2Array" />
- <argument index="0" name="max_stages" type="int" default="5" />
- <argument index="1" name="tolerance_degrees" type="float" default="4" />
+ <param index="0" name="max_stages" type="int" default="5" />
+ <param index="1" name="tolerance_degrees" type="float" default="4" />
<description>
Returns a list of points along the curve, with a curvature controlled point density. That is, the curvier parts will have more points than the straighter parts.
This approximation makes straight segments between each point, then subdivides those segments until the resulting shape is similar enough.
- [code]max_stages[/code] controls how many subdivisions a curve segment may face before it is considered approximate enough. Each subdivision splits the segment in half, so the default 5 stages may mean up to 32 subdivisions per curve segment. Increase with care!
- [code]tolerance_degrees[/code] controls how many degrees the midpoint of a segment may deviate from the real curve, before the segment has to be subdivided.
+ [param max_stages] controls how many subdivisions a curve segment may face before it is considered approximate enough. Each subdivision splits the segment in half, so the default 5 stages may mean up to 32 subdivisions per curve segment. Increase with care!
+ [param tolerance_degrees] controls how many degrees the midpoint of a segment may deviate from the real curve, before the segment has to be subdivided.
</description>
</method>
</methods>
diff --git a/doc/classes/Curve3D.xml b/doc/classes/Curve3D.xml
index 6457d9681e..0843453820 100644
--- a/doc/classes/Curve3D.xml
+++ b/doc/classes/Curve3D.xml
@@ -12,13 +12,13 @@
<methods>
<method name="add_point">
<return type="void" />
- <argument index="0" name="position" type="Vector3" />
- <argument index="1" name="in" type="Vector3" default="Vector3(0, 0, 0)" />
- <argument index="2" name="out" type="Vector3" default="Vector3(0, 0, 0)" />
- <argument index="3" name="at_position" type="int" default="-1" />
+ <param index="0" name="position" type="Vector3" />
+ <param index="1" name="in" type="Vector3" default="Vector3(0, 0, 0)" />
+ <param index="2" name="out" type="Vector3" default="Vector3(0, 0, 0)" />
+ <param index="3" name="index" type="int" default="-1" />
<description>
- Adds a point to a curve at [code]position[/code] relative to the [Curve3D]'s position, with control points [code]in[/code] and [code]out[/code].
- If [code]at_position[/code] is given, the point is inserted before the point number [code]at_position[/code], moving that point (and every point after) after the inserted point. If [code]at_position[/code] is not given, or is an illegal value ([code]at_position &lt;0[/code] or [code]at_position &gt;= [method get_point_count][/code]), the point will be appended at the end of the point list.
+ Adds a point with the specified [param position] relative to the curve's own position, with control points [param in] and [param out]. Appends the new point at the end of the point list.
+ If [param index] is given, the new point is inserted before the existing point identified by index [param index]. Every existing point starting from [param index] is shifted further down the list of points. The index must be greater than or equal to [code]0[/code] and must not exceed the number of existing points in the line. See [member point_count].
</description>
</method>
<method name="clear_points">
@@ -54,133 +54,133 @@
</method>
<method name="get_closest_offset" qualifiers="const">
<return type="float" />
- <argument index="0" name="to_point" type="Vector3" />
+ <param index="0" name="to_point" type="Vector3" />
<description>
- Returns the closest offset to [code]to_point[/code]. This offset is meant to be used in [method interpolate_baked] or [method interpolate_baked_up_vector].
- [code]to_point[/code] must be in this curve's local space.
+ Returns the closest offset to [param to_point]. This offset is meant to be used in [method interpolate_baked] or [method interpolate_baked_up_vector].
+ [param to_point] must be in this curve's local space.
</description>
</method>
<method name="get_closest_point" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="to_point" type="Vector3" />
+ <param index="0" name="to_point" type="Vector3" />
<description>
- Returns the closest baked point (in curve's local space) to [code]to_point[/code].
- [code]to_point[/code] must be in this curve's local space.
+ Returns the closest baked point (in curve's local space) to [param to_point].
+ [param to_point] must be in this curve's local space.
</description>
</method>
<method name="get_point_in" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the position of the control point leading to the vertex [code]idx[/code]. The returned position is relative to the vertex [code]idx[/code]. If the index is out of bounds, the function sends an error to the console, and returns [code](0, 0, 0)[/code].
+ Returns the position of the control point leading to the vertex [param idx]. The returned position is relative to the vertex [param idx]. If the index is out of bounds, the function sends an error to the console, and returns [code](0, 0, 0)[/code].
</description>
</method>
<method name="get_point_out" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the position of the control point leading out of the vertex [code]idx[/code]. The returned position is relative to the vertex [code]idx[/code]. If the index is out of bounds, the function sends an error to the console, and returns [code](0, 0, 0)[/code].
+ Returns the position of the control point leading out of the vertex [param idx]. The returned position is relative to the vertex [param idx]. If the index is out of bounds, the function sends an error to the console, and returns [code](0, 0, 0)[/code].
</description>
</method>
<method name="get_point_position" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the position of the vertex [code]idx[/code]. If the index is out of bounds, the function sends an error to the console, and returns [code](0, 0, 0)[/code].
+ Returns the position of the vertex [param idx]. If the index is out of bounds, the function sends an error to the console, and returns [code](0, 0, 0)[/code].
</description>
</method>
<method name="get_point_tilt" qualifiers="const">
<return type="float" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the tilt angle in radians for the point [code]idx[/code]. If the index is out of bounds, the function sends an error to the console, and returns [code]0[/code].
+ Returns the tilt angle in radians for the point [param idx]. If the index is out of bounds, the function sends an error to the console, and returns [code]0[/code].
</description>
</method>
<method name="interpolate" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="t" type="float" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="t" type="float" />
<description>
- Returns the position between the vertex [code]idx[/code] and the vertex [code]idx + 1[/code], where [code]t[/code] controls if the point is the first vertex ([code]t = 0.0[/code]), the last vertex ([code]t = 1.0[/code]), or in between. Values of [code]t[/code] outside the range ([code]0.0 &gt;= t &lt;=1[/code]) give strange, but predictable results.
- If [code]idx[/code] is out of bounds it is truncated to the first or last vertex, and [code]t[/code] is ignored. If the curve has no points, the function sends an error to the console, and returns [code](0, 0, 0)[/code].
+ Returns the position between the vertex [param idx] and the vertex [code]idx + 1[/code], where [param t] controls if the point is the first vertex ([code]t = 0.0[/code]), the last vertex ([code]t = 1.0[/code]), or in between. Values of [param t] outside the range ([code]0.0 &gt;= t &lt;=1[/code]) give strange, but predictable results.
+ If [param idx] is out of bounds it is truncated to the first or last vertex, and [param t] is ignored. If the curve has no points, the function sends an error to the console, and returns [code](0, 0, 0)[/code].
</description>
</method>
<method name="interpolate_baked" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="offset" type="float" />
- <argument index="1" name="cubic" type="bool" default="false" />
+ <param index="0" name="offset" type="float" />
+ <param index="1" name="cubic" type="bool" default="false" />
<description>
- Returns a point within the curve at position [code]offset[/code], where [code]offset[/code] is measured as a distance in 3D units along the curve.
- To do that, it finds the two cached points where the [code]offset[/code] lies between, then interpolates the values. This interpolation is cubic if [code]cubic[/code] is set to [code]true[/code], or linear if set to [code]false[/code].
+ Returns a point within the curve at position [param offset], where [param offset] is measured as a distance in 3D units along the curve.
+ To do that, it finds the two cached points where the [param offset] lies between, then interpolates the values. This interpolation is cubic if [param cubic] is set to [code]true[/code], or linear if set to [code]false[/code].
Cubic interpolation tends to follow the curves better, but linear is faster (and often, precise enough).
</description>
</method>
<method name="interpolate_baked_up_vector" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="offset" type="float" />
- <argument index="1" name="apply_tilt" type="bool" default="false" />
+ <param index="0" name="offset" type="float" />
+ <param index="1" name="apply_tilt" type="bool" default="false" />
<description>
- Returns an up vector within the curve at position [code]offset[/code], where [code]offset[/code] is measured as a distance in 3D units along the curve.
- To do that, it finds the two cached up vectors where the [code]offset[/code] lies between, then interpolates the values. If [code]apply_tilt[/code] is [code]true[/code], an interpolated tilt is applied to the interpolated up vector.
+ Returns an up vector within the curve at position [param offset], where [param offset] is measured as a distance in 3D units along the curve.
+ To do that, it finds the two cached up vectors where the [param offset] lies between, then interpolates the values. If [param apply_tilt] is [code]true[/code], an interpolated tilt is applied to the interpolated up vector.
If the curve has no up vectors, the function sends an error to the console, and returns [code](0, 1, 0)[/code].
</description>
</method>
<method name="interpolatef" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="fofs" type="float" />
+ <param index="0" name="fofs" type="float" />
<description>
- Returns the position at the vertex [code]fofs[/code]. It calls [method interpolate] using the integer part of [code]fofs[/code] as [code]idx[/code], and its fractional part as [code]t[/code].
+ Returns the position at the vertex [param fofs]. It calls [method interpolate] using the integer part of [param fofs] as [code]idx[/code], and its fractional part as [code]t[/code].
</description>
</method>
<method name="remove_point">
<return type="void" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Deletes the point [code]idx[/code] from the curve. Sends an error to the console if [code]idx[/code] is out of bounds.
+ Deletes the point [param idx] from the curve. Sends an error to the console if [param idx] is out of bounds.
</description>
</method>
<method name="set_point_in">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="position" type="Vector3" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="position" type="Vector3" />
<description>
- Sets the position of the control point leading to the vertex [code]idx[/code]. If the index is out of bounds, the function sends an error to the console. The position is relative to the vertex.
+ Sets the position of the control point leading to the vertex [param idx]. If the index is out of bounds, the function sends an error to the console. The position is relative to the vertex.
</description>
</method>
<method name="set_point_out">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="position" type="Vector3" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="position" type="Vector3" />
<description>
- Sets the position of the control point leading out of the vertex [code]idx[/code]. If the index is out of bounds, the function sends an error to the console. The position is relative to the vertex.
+ Sets the position of the control point leading out of the vertex [param idx]. If the index is out of bounds, the function sends an error to the console. The position is relative to the vertex.
</description>
</method>
<method name="set_point_position">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="position" type="Vector3" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="position" type="Vector3" />
<description>
- Sets the position for the vertex [code]idx[/code]. If the index is out of bounds, the function sends an error to the console.
+ Sets the position for the vertex [param idx]. If the index is out of bounds, the function sends an error to the console.
</description>
</method>
<method name="set_point_tilt">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="tilt" type="float" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="tilt" type="float" />
<description>
- Sets the tilt angle in radians for the point [code]idx[/code]. If the index is out of bounds, the function sends an error to the console.
+ Sets the tilt angle in radians for the point [param idx]. If the index is out of bounds, the function sends an error to the console.
The tilt controls the rotation along the look-at axis an object traveling the path would have. In the case of a curve controlling a [PathFollow3D], this tilt is an offset over the natural tilt the [PathFollow3D] calculates.
</description>
</method>
<method name="tessellate" qualifiers="const">
<return type="PackedVector3Array" />
- <argument index="0" name="max_stages" type="int" default="5" />
- <argument index="1" name="tolerance_degrees" type="float" default="4" />
+ <param index="0" name="max_stages" type="int" default="5" />
+ <param index="1" name="tolerance_degrees" type="float" default="4" />
<description>
Returns a list of points along the curve, with a curvature controlled point density. That is, the curvier parts will have more points than the straighter parts.
This approximation makes straight segments between each point, then subdivides those segments until the resulting shape is similar enough.
- [code]max_stages[/code] controls how many subdivisions a curve segment may face before it is considered approximate enough. Each subdivision splits the segment in half, so the default 5 stages may mean up to 32 subdivisions per curve segment. Increase with care!
- [code]tolerance_degrees[/code] controls how many degrees the midpoint of a segment may deviate from the real curve, before the segment has to be subdivided.
+ [param max_stages] controls how many subdivisions a curve segment may face before it is considered approximate enough. Each subdivision splits the segment in half, so the default 5 stages may mean up to 32 subdivisions per curve segment. Increase with care!
+ [param tolerance_degrees] controls how many degrees the midpoint of a segment may deviate from the real curve, before the segment has to be subdivided.
</description>
</method>
</methods>
diff --git a/doc/classes/DTLSServer.xml b/doc/classes/DTLSServer.xml
index 5d8a2bc16d..9af8be99ef 100644
--- a/doc/classes/DTLSServer.xml
+++ b/doc/classes/DTLSServer.xml
@@ -148,18 +148,18 @@
<methods>
<method name="setup">
<return type="int" enum="Error" />
- <argument index="0" name="key" type="CryptoKey" />
- <argument index="1" name="certificate" type="X509Certificate" />
- <argument index="2" name="chain" type="X509Certificate" default="null" />
+ <param index="0" name="key" type="CryptoKey" />
+ <param index="1" name="certificate" type="X509Certificate" />
+ <param index="2" name="chain" type="X509Certificate" default="null" />
<description>
- Setup the DTLS server to use the given [code]private_key[/code] and provide the given [code]certificate[/code] to clients. You can pass the optional [code]chain[/code] parameter to provide additional CA chain information along with the certificate.
+ Setup the DTLS server to use the given [param key] and provide the given [param certificate] to clients. You can pass the optional [param chain] parameter to provide additional CA chain information along with the certificate.
</description>
</method>
<method name="take_connection">
<return type="PacketPeerDTLS" />
- <argument index="0" name="udp_peer" type="PacketPeerUDP" />
+ <param index="0" name="udp_peer" type="PacketPeerUDP" />
<description>
- Try to initiate the DTLS handshake with the given [code]udp_peer[/code] which must be already connected (see [method PacketPeerUDP.connect_to_host]).
+ Try to initiate the DTLS handshake with the given [param udp_peer] which must be already connected (see [method PacketPeerUDP.connect_to_host]).
[b]Note:[/b] You must check that the state of the return PacketPeerUDP is [constant PacketPeerDTLS.STATUS_HANDSHAKING], as it is normal that 50% of the new connections will be invalid due to cookie exchange.
</description>
</method>
diff --git a/doc/classes/Decal.xml b/doc/classes/Decal.xml
index 3322ab4c66..b9d3f1d81e 100644
--- a/doc/classes/Decal.xml
+++ b/doc/classes/Decal.xml
@@ -14,7 +14,7 @@
<methods>
<method name="get_texture" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="type" type="int" enum="Decal.DecalTexture" />
+ <param index="0" name="type" type="int" enum="Decal.DecalTexture" />
<description>
Returns the [Texture2D] associated with the specified [enum DecalTexture]. This is a convenience method, in most cases you should access the texture directly.
For example, instead of [code]albedo_tex = $Decal.get_texture(Decal.TEXTURE_ALBEDO)[/code], use [code]albedo_tex = $Decal.texture_albedo[/code].
@@ -35,8 +35,8 @@
</method>
<method name="set_texture">
<return type="void" />
- <argument index="0" name="type" type="int" enum="Decal.DecalTexture" />
- <argument index="1" name="texture" type="Texture2D" />
+ <param index="0" name="type" type="int" enum="Decal.DecalTexture" />
+ <param index="1" name="texture" type="Texture2D" />
<description>
Sets the [Texture2D] associated with the specified [enum DecalTexture]. This is a convenience method, in most cases you should access the texture directly.
For example, instead of [code]$Decal.set_texture(Decal.TEXTURE_ALBEDO, albedo_tex)[/code], use [code]$Decal.texture_albedo = albedo_tex[/code].
diff --git a/doc/classes/Dictionary.xml b/doc/classes/Dictionary.xml
index 6f2ad5205c..40b5e88fff 100644
--- a/doc/classes/Dictionary.xml
+++ b/doc/classes/Dictionary.xml
@@ -190,7 +190,7 @@
</constructor>
<constructor name="Dictionary">
<return type="Dictionary" />
- <argument index="0" name="from" type="Dictionary" />
+ <param index="0" name="from" type="Dictionary" />
<description>
Constructs a [Dictionary] as a copy of the given [Dictionary].
</description>
@@ -205,14 +205,14 @@
</method>
<method name="duplicate" qualifiers="const">
<return type="Dictionary" />
- <argument index="0" name="deep" type="bool" default="false" />
+ <param index="0" name="deep" type="bool" default="false" />
<description>
- Creates a copy of the dictionary, and returns it. The [code]deep[/code] parameter causes inner dictionaries and arrays to be copied recursively, but does not apply to objects.
+ Creates a copy of the dictionary, and returns it. The [param deep] parameter causes inner dictionaries and arrays to be copied recursively, but does not apply to objects.
</description>
</method>
<method name="erase">
<return type="bool" />
- <argument index="0" name="key" type="Variant" />
+ <param index="0" name="key" type="Variant" />
<description>
Erase a dictionary key/value pair by key. Returns [code]true[/code] if the given key was present in the dictionary, [code]false[/code] otherwise.
[b]Note:[/b] Don't erase elements while iterating over the dictionary. You can iterate over the [method keys] array instead.
@@ -220,15 +220,15 @@
</method>
<method name="get" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="key" type="Variant" />
- <argument index="1" name="default" type="Variant" default="null" />
+ <param index="0" name="key" type="Variant" />
+ <param index="1" name="default" type="Variant" default="null" />
<description>
Returns the current value for the specified key in the [Dictionary]. If the key does not exist, the method returns the value of the optional default argument, or [code]null[/code] if it is omitted.
</description>
</method>
<method name="has" qualifiers="const">
<return type="bool" />
- <argument index="0" name="key" type="Variant" />
+ <param index="0" name="key" type="Variant" />
<description>
Returns [code]true[/code] if the dictionary has a given key.
[b]Note:[/b] This is equivalent to using the [code]in[/code] operator as follows:
@@ -251,7 +251,7 @@
</method>
<method name="has_all" qualifiers="const">
<return type="bool" />
- <argument index="0" name="keys" type="Array" />
+ <param index="0" name="keys" type="Array" />
<description>
Returns [code]true[/code] if the dictionary has all the keys in the given array.
</description>
@@ -293,10 +293,10 @@
</method>
<method name="merge">
<return type="void" />
- <argument index="0" name="dictionary" type="Dictionary" />
- <argument index="1" name="overwrite" type="bool" default="false" />
+ <param index="0" name="dictionary" type="Dictionary" />
+ <param index="1" name="overwrite" type="bool" default="false" />
<description>
- Adds elements from [code]dictionary[/code] to this [Dictionary]. By default, duplicate keys will not be copied over, unless [code]overwrite[/code] is [code]true[/code].
+ Adds elements from [param dictionary] to this [Dictionary]. By default, duplicate keys will not be copied over, unless [param overwrite] is [code]true[/code].
</description>
</method>
<method name="size" qualifiers="const">
@@ -315,19 +315,19 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="Dictionary" />
+ <param index="0" name="right" type="Dictionary" />
<description>
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="Dictionary" />
+ <param index="0" name="right" type="Dictionary" />
<description>
</description>
</operator>
<operator name="operator []">
<return type="Variant" />
- <argument index="0" name="key" type="Variant" />
+ <param index="0" name="key" type="Variant" />
<description>
</description>
</operator>
diff --git a/doc/classes/Directory.xml b/doc/classes/Directory.xml
index bd16fd3936..c9a9f346a5 100644
--- a/doc/classes/Directory.xml
+++ b/doc/classes/Directory.xml
@@ -59,7 +59,7 @@
<methods>
<method name="change_dir">
<return type="int" enum="Error" />
- <argument index="0" name="todir" type="String" />
+ <param index="0" name="todir" type="String" />
<description>
Changes the currently opened directory to the one passed as an argument. The argument can be relative to the current directory (e.g. [code]newdir[/code] or [code]../newdir[/code]), or an absolute path (e.g. [code]/tmp/newdir[/code] or [code]res://somedir/newdir[/code]).
Returns one of the [enum Error] code constants ([code]OK[/code] on success).
@@ -67,10 +67,10 @@
</method>
<method name="copy">
<return type="int" enum="Error" />
- <argument index="0" name="from" type="String" />
- <argument index="1" name="to" type="String" />
+ <param index="0" name="from" type="String" />
+ <param index="1" name="to" type="String" />
<description>
- Copies the [code]from[/code] file to the [code]to[/code] destination. Both arguments should be paths to files, either relative or absolute. If the destination file exists and is not access-protected, it will be overwritten.
+ Copies the [param from] file to the [param to] destination. Both arguments should be paths to files, either relative or absolute. If the destination file exists and is not access-protected, it will be overwritten.
Returns one of the [enum Error] code constants ([code]OK[/code] on success).
</description>
</method>
@@ -82,7 +82,7 @@
</method>
<method name="dir_exists">
<return type="bool" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Returns whether the target directory exists. The argument can be relative to the current directory, or an absolute path.
If the [Directory] is not open, the path is relative to [code]res://[/code].
@@ -90,7 +90,7 @@
</method>
<method name="file_exists">
<return type="bool" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Returns whether the target file exists. The argument can be relative to the current directory, or an absolute path.
If the [Directory] is not open, the path is relative to [code]res://[/code].
@@ -117,7 +117,7 @@
</method>
<method name="get_drive">
<return type="String" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
On Windows, returns the name of the drive (partition) passed as an argument (e.g. [code]C:[/code]).
On macOS, returns the path to the mounted volume passed as an argument.
@@ -170,7 +170,7 @@
</method>
<method name="make_dir">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Creates a directory. The argument can be relative to the current directory, or an absolute path. The target directory should be placed in an already existing directory (to create the full path recursively, see [method make_dir_recursive]).
Returns one of the [enum Error] code constants ([code]OK[/code] on success).
@@ -178,7 +178,7 @@
</method>
<method name="make_dir_recursive">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Creates a target directory and all necessary intermediate directories in its path, by calling [method make_dir] recursively. The argument can be relative to the current directory, or an absolute path.
Returns one of the [enum Error] code constants ([code]OK[/code] on success).
@@ -186,15 +186,15 @@
</method>
<method name="open">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
- Opens an existing directory of the filesystem. The [code]path[/code] argument can be within the project tree ([code]res://folder[/code]), the user directory ([code]user://folder[/code]) or an absolute path of the user filesystem (e.g. [code]/tmp/folder[/code] or [code]C:\tmp\folder[/code]).
+ Opens an existing directory of the filesystem. The [param path] argument can be within the project tree ([code]res://folder[/code]), the user directory ([code]user://folder[/code]) or an absolute path of the user filesystem (e.g. [code]/tmp/folder[/code] or [code]C:\tmp\folder[/code]).
Returns one of the [enum Error] code constants ([code]OK[/code] on success).
</description>
</method>
<method name="remove">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Permanently deletes the target file or an empty directory. The argument can be relative to the current directory, or an absolute path. If the target directory is not empty, the operation will fail.
If you don't want to delete the file/directory permanently, use [method OS.move_to_trash] instead.
@@ -203,10 +203,10 @@
</method>
<method name="rename">
<return type="int" enum="Error" />
- <argument index="0" name="from" type="String" />
- <argument index="1" name="to" type="String" />
+ <param index="0" name="from" type="String" />
+ <param index="1" name="to" type="String" />
<description>
- Renames (move) the [code]from[/code] file or directory to the [code]to[/code] destination. Both arguments should be paths to files or directories, either relative or absolute. If the destination file or directory exists and is not access-protected, it will be overwritten.
+ Renames (move) the [param from] file or directory to the [param to] destination. Both arguments should be paths to files or directories, either relative or absolute. If the destination file or directory exists and is not access-protected, it will be overwritten.
Returns one of the [enum Error] code constants ([code]OK[/code] on success).
</description>
</method>
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index cec504584c..35a2861c54 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -28,14 +28,14 @@
</method>
<method name="clipboard_set">
<return type="void" />
- <argument index="0" name="clipboard" type="String" />
+ <param index="0" name="clipboard" type="String" />
<description>
Sets the user's clipboard content to the given string.
</description>
</method>
<method name="clipboard_set_primary">
<return type="void" />
- <argument index="0" name="clipboard_primary" type="String" />
+ <param index="0" name="clipboard_primary" type="String" />
<description>
Sets the user's primary clipboard content to the given string.
[b]Note:[/b] This method is only implemented on Linux.
@@ -43,10 +43,10 @@
</method>
<method name="create_sub_window">
<return type="int" />
- <argument index="0" name="mode" type="int" enum="DisplayServer.WindowMode" />
- <argument index="1" name="vsync_mode" type="int" enum="DisplayServer.VSyncMode" />
- <argument index="2" name="flags" type="int" />
- <argument index="3" name="rect" type="Rect2i" default="Rect2i(0, 0, 0, 0)" />
+ <param index="0" name="mode" type="int" enum="DisplayServer.WindowMode" />
+ <param index="1" name="vsync_mode" type="int" enum="DisplayServer.VSyncMode" />
+ <param index="2" name="flags" type="int" />
+ <param index="3" name="rect" type="Rect2i" default="Rect2i(0, 0, 0, 0)" />
<description>
</description>
</method>
@@ -57,45 +57,45 @@
</method>
<method name="cursor_set_custom_image">
<return type="void" />
- <argument index="0" name="cursor" type="Resource" />
- <argument index="1" name="shape" type="int" enum="DisplayServer.CursorShape" default="0" />
- <argument index="2" name="hotspot" type="Vector2" default="Vector2(0, 0)" />
+ <param index="0" name="cursor" type="Resource" />
+ <param index="1" name="shape" type="int" enum="DisplayServer.CursorShape" default="0" />
+ <param index="2" name="hotspot" type="Vector2" default="Vector2(0, 0)" />
<description>
</description>
</method>
<method name="cursor_set_shape">
<return type="void" />
- <argument index="0" name="shape" type="int" enum="DisplayServer.CursorShape" />
+ <param index="0" name="shape" type="int" enum="DisplayServer.CursorShape" />
<description>
</description>
</method>
<method name="delete_sub_window">
<return type="void" />
- <argument index="0" name="window_id" type="int" />
+ <param index="0" name="window_id" type="int" />
<description>
</description>
</method>
<method name="dialog_input_text">
<return type="int" enum="Error" />
- <argument index="0" name="title" type="String" />
- <argument index="1" name="description" type="String" />
- <argument index="2" name="existing_text" type="String" />
- <argument index="3" name="callback" type="Callable" />
+ <param index="0" name="title" type="String" />
+ <param index="1" name="description" type="String" />
+ <param index="2" name="existing_text" type="String" />
+ <param index="3" name="callback" type="Callable" />
<description>
</description>
</method>
<method name="dialog_show">
<return type="int" enum="Error" />
- <argument index="0" name="title" type="String" />
- <argument index="1" name="description" type="String" />
- <argument index="2" name="buttons" type="PackedStringArray" />
- <argument index="3" name="callback" type="Callable" />
+ <param index="0" name="title" type="String" />
+ <param index="1" name="description" type="String" />
+ <param index="2" name="buttons" type="PackedStringArray" />
+ <param index="3" name="callback" type="Callable" />
<description>
</description>
</method>
<method name="enable_for_stealing_focus">
<return type="void" />
- <argument index="0" name="process_id" type="int" />
+ <param index="0" name="process_id" type="int" />
<description>
</description>
</method>
@@ -105,7 +105,7 @@
</description>
</method>
<method name="get_display_cutouts" qualifiers="const">
- <return type="Array" />
+ <return type="Rect2[]" />
<description>
Returns an [Array] of [Rect2], each of which is the bounding rectangle for a display cutout or notch. These are non-functional areas on edge-to-edge screens used by cameras and sensors. Returns an empty array if the device does not have cutouts. See also [method get_display_safe_area].
[b]Note:[/b] Currently only implemented on Android. Other platforms will return an empty array even if they do have display cutouts or notches.
@@ -134,7 +134,7 @@
</method>
<method name="get_window_at_screen_position" qualifiers="const">
<return type="int" />
- <argument index="0" name="position" type="Vector2i" />
+ <param index="0" name="position" type="Vector2i" />
<description>
</description>
</method>
@@ -144,231 +144,250 @@
</description>
</method>
<method name="global_menu_add_check_item">
- <return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="label" type="String" />
- <argument index="2" name="callback" type="Callable" />
- <argument index="3" name="tag" type="Variant" default="null" />
- <argument index="4" name="accelerator" type="int" enum="Key" default="0" />
- <argument index="5" name="index" type="int" default="-1" />
- <description>
- Adds a new checkable item with text [code]label[/code] to the global menu with ID [code]menu_root[/code].
+ <return type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="label" type="String" />
+ <param index="2" name="callback" type="Callable" />
+ <param index="3" name="tag" type="Variant" default="null" />
+ <param index="4" name="accelerator" type="int" enum="Key" default="0" />
+ <param index="5" name="index" type="int" default="-1" />
+ <description>
+ Adds a new checkable item with text [param label] to the global menu with ID [param menu_root].
+ Returns index of the inserted item, it's not guaranteed to be the same as [param index] value.
[b]Note:[/b] This method is implemented on macOS.
[b]Supported system menu IDs:[/b]
[codeblock]
- "" - Main menu (macOS).
+ "_main" - Main menu (macOS).
"_dock" - Dock popup menu (macOS).
[/codeblock]
</description>
</method>
<method name="global_menu_add_icon_check_item">
- <return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="icon" type="Texture2D" />
- <argument index="2" name="label" type="String" />
- <argument index="3" name="callback" type="Callable" />
- <argument index="4" name="tag" type="Variant" default="null" />
- <argument index="5" name="accelerator" type="int" enum="Key" default="0" />
- <argument index="6" name="index" type="int" default="-1" />
- <description>
- Adds a new checkable item with text [code]label[/code] and icon [code]icon[/code] to the global menu with ID [code]menu_root[/code].
+ <return type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="icon" type="Texture2D" />
+ <param index="2" name="label" type="String" />
+ <param index="3" name="callback" type="Callable" />
+ <param index="4" name="tag" type="Variant" default="null" />
+ <param index="5" name="accelerator" type="int" enum="Key" default="0" />
+ <param index="6" name="index" type="int" default="-1" />
+ <description>
+ Adds a new checkable item with text [param label] and icon [param icon] to the global menu with ID [param menu_root].
+ Returns index of the inserted item, it's not guaranteed to be the same as [param index] value.
[b]Note:[/b] This method is implemented on macOS.
[b]Supported system menu IDs:[/b]
[codeblock]
- "" - Main menu (macOS).
+ "_main" - Main menu (macOS).
"_dock" - Dock popup menu (macOS).
[/codeblock]
</description>
</method>
<method name="global_menu_add_icon_item">
- <return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="icon" type="Texture2D" />
- <argument index="2" name="label" type="String" />
- <argument index="3" name="callback" type="Callable" />
- <argument index="4" name="tag" type="Variant" default="null" />
- <argument index="5" name="accelerator" type="int" enum="Key" default="0" />
- <argument index="6" name="index" type="int" default="-1" />
- <description>
- Adds a new item with text [code]label[/code] and icon [code]icon[/code] to the global menu with ID [code]menu_root[/code].
+ <return type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="icon" type="Texture2D" />
+ <param index="2" name="label" type="String" />
+ <param index="3" name="callback" type="Callable" />
+ <param index="4" name="tag" type="Variant" default="null" />
+ <param index="5" name="accelerator" type="int" enum="Key" default="0" />
+ <param index="6" name="index" type="int" default="-1" />
+ <description>
+ Adds a new item with text [param label] and icon [param icon] to the global menu with ID [param menu_root].
+ Returns index of the inserted item, it's not guaranteed to be the same as [param index] value.
[b]Note:[/b] This method is implemented on macOS.
[b]Supported system menu IDs:[/b]
[codeblock]
- "" - Main menu (macOS).
+ "_main" - Main menu (macOS).
"_dock" - Dock popup menu (macOS).
[/codeblock]
</description>
</method>
<method name="global_menu_add_icon_radio_check_item">
- <return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="icon" type="Texture2D" />
- <argument index="2" name="label" type="String" />
- <argument index="3" name="callback" type="Callable" />
- <argument index="4" name="tag" type="Variant" default="null" />
- <argument index="5" name="accelerator" type="int" enum="Key" default="0" />
- <argument index="6" name="index" type="int" default="-1" />
- <description>
- Adds a new radio-checkable item with text [code]label[/code] and icon [code]icon[/code] to the global menu with ID [code]menu_root[/code].
+ <return type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="icon" type="Texture2D" />
+ <param index="2" name="label" type="String" />
+ <param index="3" name="callback" type="Callable" />
+ <param index="4" name="tag" type="Variant" default="null" />
+ <param index="5" name="accelerator" type="int" enum="Key" default="0" />
+ <param index="6" name="index" type="int" default="-1" />
+ <description>
+ Adds a new radio-checkable item with text [param label] and icon [param icon] to the global menu with ID [param menu_root].
+ Returns index of the inserted item, it's not guaranteed to be the same as [param index] value.
[b]Note:[/b] Radio-checkable items just display a checkmark, but don't have any built-in checking behavior and must be checked/unchecked manually. See [method global_menu_set_item_checked] for more info on how to control it.
[b]Note:[/b] This method is implemented on macOS.
[b]Supported system menu IDs:[/b]
[codeblock]
- "" - Main menu (macOS).
+ "_main" - Main menu (macOS).
"_dock" - Dock popup menu (macOS).
[/codeblock]
</description>
</method>
<method name="global_menu_add_item">
- <return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="label" type="String" />
- <argument index="2" name="callback" type="Callable" />
- <argument index="3" name="tag" type="Variant" default="null" />
- <argument index="4" name="accelerator" type="int" enum="Key" default="0" />
- <argument index="5" name="index" type="int" default="-1" />
- <description>
- Adds a new item with text [code]label[/code] to the global menu with ID [code]menu_root[/code].
+ <return type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="label" type="String" />
+ <param index="2" name="callback" type="Callable" />
+ <param index="3" name="tag" type="Variant" default="null" />
+ <param index="4" name="accelerator" type="int" enum="Key" default="0" />
+ <param index="5" name="index" type="int" default="-1" />
+ <description>
+ Adds a new item with text [param label] to the global menu with ID [param menu_root].
+ Returns index of the inserted item, it's not guaranteed to be the same as [param index] value.
[b]Note:[/b] This method is implemented on macOS.
[b]Supported system menu IDs:[/b]
[codeblock]
- "" - Main menu (macOS).
+ "_main" - Main menu (macOS).
"_dock" - Dock popup menu (macOS).
[/codeblock]
</description>
</method>
<method name="global_menu_add_multistate_item">
- <return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="labe" type="String" />
- <argument index="2" name="max_states" type="int" />
- <argument index="3" name="default_state" type="int" />
- <argument index="4" name="callback" type="Callable" />
- <argument index="5" name="tag" type="Variant" default="null" />
- <argument index="6" name="accelerator" type="int" enum="Key" default="0" />
- <argument index="7" name="index" type="int" default="-1" />
- <description>
- Adds a new item with text [code]label[/code] to the global menu with ID [code]menu_root[/code].
- Contrarily to normal binary items, multistate items can have more than two states, as defined by [code]max_states[/code]. Each press or activate of the item will increase the state by one. The default value is defined by [code]default_state[/code].
+ <return type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="labe" type="String" />
+ <param index="2" name="max_states" type="int" />
+ <param index="3" name="default_state" type="int" />
+ <param index="4" name="callback" type="Callable" />
+ <param index="5" name="tag" type="Variant" default="null" />
+ <param index="6" name="accelerator" type="int" enum="Key" default="0" />
+ <param index="7" name="index" type="int" default="-1" />
+ <description>
+ Adds a new item with text [param labe] to the global menu with ID [param menu_root].
+ Contrarily to normal binary items, multistate items can have more than two states, as defined by [param max_states]. Each press or activate of the item will increase the state by one. The default value is defined by [param default_state].
+ Returns index of the inserted item, it's not guaranteed to be the same as [param index] value.
+ [b]Note:[/b] By default, there's no indication of the current item state, it should be changed manually.
[b]Note:[/b] This method is implemented on macOS.
[b]Supported system menu IDs:[/b]
[codeblock]
- "" - Main menu (macOS).
+ "_main" - Main menu (macOS).
"_dock" - Dock popup menu (macOS).
[/codeblock]
</description>
</method>
<method name="global_menu_add_radio_check_item">
- <return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="label" type="String" />
- <argument index="2" name="callback" type="Callable" />
- <argument index="3" name="tag" type="Variant" default="null" />
- <argument index="4" name="accelerator" type="int" enum="Key" default="0" />
- <argument index="5" name="index" type="int" default="-1" />
- <description>
- Adds a new radio-checkable item with text [code]label[/code] to the global menu with ID [code]menu_root[/code].
+ <return type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="label" type="String" />
+ <param index="2" name="callback" type="Callable" />
+ <param index="3" name="tag" type="Variant" default="null" />
+ <param index="4" name="accelerator" type="int" enum="Key" default="0" />
+ <param index="5" name="index" type="int" default="-1" />
+ <description>
+ Adds a new radio-checkable item with text [param label] to the global menu with ID [param menu_root].
+ Returns index of the inserted item, it's not guaranteed to be the same as [param index] value.
[b]Note:[/b] Radio-checkable items just display a checkmark, but don't have any built-in checking behavior and must be checked/unchecked manually. See [method global_menu_set_item_checked] for more info on how to control it.
[b]Note:[/b] This method is implemented on macOS.
[b]Supported system menu IDs:[/b]
[codeblock]
- "" - Main menu (macOS).
+ "_main" - Main menu (macOS).
"_dock" - Dock popup menu (macOS).
[/codeblock]
</description>
</method>
<method name="global_menu_add_separator">
- <return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="index" type="int" default="-1" />
+ <return type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="index" type="int" default="-1" />
<description>
- Adds a separator between items to the global menu with ID [code]menu_root[/code]. Separators also occupy an index.
+ Adds a separator between items to the global menu with ID [param menu_root]. Separators also occupy an index.
+ Returns index of the inserted item, it's not guaranteed to be the same as [param index] value.
[b]Note:[/b] This method is implemented on macOS.
[b]Supported system menu IDs:[/b]
[codeblock]
- "" - Main menu (macOS).
+ "_main" - Main menu (macOS).
"_dock" - Dock popup menu (macOS).
[/codeblock]
</description>
</method>
<method name="global_menu_add_submenu_item">
- <return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="label" type="String" />
- <argument index="2" name="submenu" type="String" />
- <argument index="3" name="index" type="int" default="-1" />
+ <return type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="label" type="String" />
+ <param index="2" name="submenu" type="String" />
+ <param index="3" name="index" type="int" default="-1" />
<description>
- Adds an item that will act as a submenu of the global menu [code]menu_root[/code]. The [code]submenu[/code] argument is the ID of the global menu root that will be shown when the item is clicked.
+ Adds an item that will act as a submenu of the global menu [param menu_root]. The [param submenu] argument is the ID of the global menu root that will be shown when the item is clicked.
+ Returns index of the inserted item, it's not guaranteed to be the same as [param index] value.
[b]Note:[/b] This method is implemented on macOS.
[b]Supported system menu IDs:[/b]
[codeblock]
- "" - Main menu (macOS).
+ "_main" - Main menu (macOS).
"_dock" - Dock popup menu (macOS).
[/codeblock]
</description>
</method>
<method name="global_menu_clear">
<return type="void" />
- <argument index="0" name="menu_root" type="String" />
+ <param index="0" name="menu_root" type="String" />
<description>
- Removes all items from the global menu with ID [code]menu_root[/code].
+ Removes all items from the global menu with ID [param menu_root].
[b]Note:[/b] This method is implemented on macOS.
[b]Supported system menu IDs:[/b]
[codeblock]
- "" - Main menu (macOS).
+ "_main" - Main menu (macOS).
"_dock" - Dock popup menu (macOS).
[/codeblock]
</description>
</method>
<method name="global_menu_get_item_accelerator" qualifiers="const">
<return type="int" enum="Key" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
<description>
- Returns the accelerator of the item at index [code]idx[/code]. Accelerators are special combinations of keys that activate the item, no matter which control is focused.
+ Returns the accelerator of the item at index [param idx]. Accelerators are special combinations of keys that activate the item, no matter which control is focused.
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="global_menu_get_item_callback" qualifiers="const">
<return type="Callable" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
<description>
- Returns the callback of the item at index [code]idx[/code].
+ Returns the callback of the item at index [param idx].
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="global_menu_get_item_icon" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
<description>
- Returns the icon of the item at index [code]idx[/code].
+ Returns the icon of the item at index [param idx].
+ [b]Note:[/b] This method is implemented on macOS.
+ </description>
+ </method>
+ <method name="global_menu_get_item_indentation_level" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
+ <description>
+ Returns the horizontal offset of the item at the given [param idx].
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="global_menu_get_item_index_from_tag" qualifiers="const">
<return type="int" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="tag" type="Variant" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="tag" type="Variant" />
<description>
- Returns the index of the item with the specified [code]tag[/code]. Index is automatically assigned to each item by the engine. Index can not be set manually.
+ Returns the index of the item with the specified [param tag]. Index is automatically assigned to each item by the engine. Index can not be set manually.
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="global_menu_get_item_index_from_text" qualifiers="const">
<return type="int" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="text" type="String" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="text" type="String" />
<description>
- Returns the index of the item with the specified [code]text[/code]. Index is automatically assigned to each item by the engine. Index can not be set manually.
+ Returns the index of the item with the specified [param text]. Index is automatically assigned to each item by the engine. Index can not be set manually.
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="global_menu_get_item_max_states" qualifiers="const">
<return type="int" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
<description>
Returns number of states of an multistate item. See [method global_menu_add_multistate_item] for details.
[b]Note:[/b] This method is implemented on macOS.
@@ -376,8 +395,8 @@
</method>
<method name="global_menu_get_item_state" qualifiers="const">
<return type="int" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
<description>
Returns the state of an multistate item. See [method global_menu_add_multistate_item] for details.
[b]Note:[/b] This method is implemented on macOS.
@@ -385,17 +404,17 @@
</method>
<method name="global_menu_get_item_submenu" qualifiers="const">
<return type="String" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
<description>
- Returns the submenu ID of the item at index [code]idx[/code]. See [method global_menu_add_submenu_item] for more info on how to add a submenu.
+ Returns the submenu ID of the item at index [param idx]. See [method global_menu_add_submenu_item] for more info on how to add a submenu.
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="global_menu_get_item_tag" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
<description>
Returns the metadata of the specified item, which might be of any type. You can set it with [method global_menu_set_item_tag], which provides a simple way of assigning context data to items.
[b]Note:[/b] This method is implemented on macOS.
@@ -403,136 +422,146 @@
</method>
<method name="global_menu_get_item_text" qualifiers="const">
<return type="String" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
<description>
- Returns the text of the item at index [code]idx[/code].
+ Returns the text of the item at index [param idx].
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="global_menu_get_item_tooltip" qualifiers="const">
<return type="String" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
<description>
- Returns the tooltip associated with the specified index index [code]idx[/code].
+ Returns the tooltip associated with the specified index index [param idx].
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="global_menu_is_item_checkable" qualifiers="const">
<return type="bool" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
<description>
- Returns [code]true[/code] if the item at index [code]idx[/code] is checkable in some way, i.e. if it has a checkbox or radio button.
+ Returns [code]true[/code] if the item at index [param idx] is checkable in some way, i.e. if it has a checkbox or radio button.
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="global_menu_is_item_checked" qualifiers="const">
<return type="bool" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
<description>
- Returns [code]true[/code] if the item at index [code]idx[/code] is checked.
+ Returns [code]true[/code] if the item at index [param idx] is checked.
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="global_menu_is_item_disabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
<description>
- Returns [code]true[/code] if the item at index [code]idx[/code] is disabled. When it is disabled it can't be selected, or its action invoked.
+ Returns [code]true[/code] if the item at index [param idx] is disabled. When it is disabled it can't be selected, or its action invoked.
See [method global_menu_set_item_disabled] for more info on how to disable an item.
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="global_menu_is_item_radio_checkable" qualifiers="const">
<return type="bool" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
<description>
- Returns [code]true[/code] if the item at index [code]idx[/code] has radio button-style checkability.
+ Returns [code]true[/code] if the item at index [param idx] has radio button-style checkability.
[b]Note:[/b] This is purely cosmetic; you must add the logic for checking/unchecking items in radio groups.
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="global_menu_remove_item">
<return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
<description>
- Removes the item at index [code]idx[/code] from the global menu [code]menu_root[/code].
+ Removes the item at index [param idx] from the global menu [param menu_root].
[b]Note:[/b] The indices of items after the removed item will be shifted by one.
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="global_menu_set_item_accelerator">
<return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
- <argument index="2" name="keycode" type="int" enum="Key" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
+ <param index="2" name="keycode" type="int" enum="Key" />
<description>
- Sets the accelerator of the item at index [code]idx[/code].
+ Sets the accelerator of the item at index [param idx].
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="global_menu_set_item_callback">
<return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
- <argument index="2" name="callback" type="Callable" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
+ <param index="2" name="callback" type="Callable" />
<description>
- Sets the callback of the item at index [code]idx[/code]. Callback is emitted when an item is pressed or its accelerator is activated.
+ Sets the callback of the item at index [param idx]. Callback is emitted when an item is pressed or its accelerator is activated.
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="global_menu_set_item_checkable">
<return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
- <argument index="2" name="checkable" type="bool" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
+ <param index="2" name="checkable" type="bool" />
<description>
- Sets whether the item at index [code]idx[/code] has a checkbox. If [code]false[/code], sets the type of the item to plain text.
+ Sets whether the item at index [param idx] has a checkbox. If [code]false[/code], sets the type of the item to plain text.
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="global_menu_set_item_checked">
<return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
- <argument index="2" name="checked" type="bool" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
+ <param index="2" name="checked" type="bool" />
<description>
- Sets the checkstate status of the item at index [code]idx[/code].
+ Sets the checkstate status of the item at index [param idx].
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="global_menu_set_item_disabled">
<return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
- <argument index="2" name="disabled" type="bool" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
+ <param index="2" name="disabled" type="bool" />
<description>
- Enables/disables the item at index [code]idx[/code]. When it is disabled, it can't be selected and its action can't be invoked.
+ Enables/disables the item at index [param idx]. When it is disabled, it can't be selected and its action can't be invoked.
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="global_menu_set_item_icon">
<return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
- <argument index="2" name="icon" type="Texture2D" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
+ <param index="2" name="icon" type="Texture2D" />
<description>
- Replaces the [Texture2D] icon of the specified [code]idx[/code].
+ Replaces the [Texture2D] icon of the specified [param idx].
[b]Note:[/b] This method is implemented on macOS.
[b]Note:[/b] This method is not supported by macOS "_dock" menu items.
</description>
</method>
+ <method name="global_menu_set_item_indentation_level">
+ <return type="void" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
+ <param index="2" name="level" type="int" />
+ <description>
+ Sets the horizontal offset of the item at the given [param idx].
+ [b]Note:[/b] This method is implemented on macOS.
+ </description>
+ </method>
<method name="global_menu_set_item_max_states">
<return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
- <argument index="2" name="max_states" type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
+ <param index="2" name="max_states" type="int" />
<description>
Sets number of state of an multistate item. See [method global_menu_add_multistate_item] for details.
[b]Note:[/b] This method is implemented on macOS.
@@ -540,20 +569,20 @@
</method>
<method name="global_menu_set_item_radio_checkable">
<return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
- <argument index="2" name="checkable" type="bool" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
+ <param index="2" name="checkable" type="bool" />
<description>
- Sets the type of the item at the specified index [code]idx[/code] to radio button. If [code]false[/code], sets the type of the item to plain text
+ Sets the type of the item at the specified index [param idx] to radio button. If [code]false[/code], sets the type of the item to plain text
[b]Note:[/b] This is purely cosmetic; you must add the logic for checking/unchecking items in radio groups.
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="global_menu_set_item_state">
<return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
- <argument index="2" name="state" type="int" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
+ <param index="2" name="state" type="int" />
<description>
Sets the state of an multistate item. See [method global_menu_add_multistate_item] for details.
[b]Note:[/b] This method is implemented on macOS.
@@ -561,19 +590,19 @@
</method>
<method name="global_menu_set_item_submenu">
<return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
- <argument index="2" name="submenu" type="String" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
+ <param index="2" name="submenu" type="String" />
<description>
- Sets the submenu of the item at index [code]idx[/code]. The submenu is the ID of a global menu root that would be shown when the item is clicked.
+ Sets the submenu of the item at index [param idx]. The submenu is the ID of a global menu root that would be shown when the item is clicked.
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="global_menu_set_item_tag">
<return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
- <argument index="2" name="tag" type="Variant" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
+ <param index="2" name="tag" type="Variant" />
<description>
Sets the metadata of an item, which may be of any type. You can later get it with [method global_menu_get_item_tag], which provides a simple way of assigning context data to items.
[b]Note:[/b] This method is implemented on macOS.
@@ -581,27 +610,27 @@
</method>
<method name="global_menu_set_item_text">
<return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
- <argument index="2" name="text" type="String" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
+ <param index="2" name="text" type="String" />
<description>
- Sets the text of the item at index [code]idx[/code].
+ Sets the text of the item at index [param idx].
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="global_menu_set_item_tooltip">
<return type="void" />
- <argument index="0" name="menu_root" type="String" />
- <argument index="1" name="idx" type="int" />
- <argument index="2" name="tooltip" type="String" />
+ <param index="0" name="menu_root" type="String" />
+ <param index="1" name="idx" type="int" />
+ <param index="2" name="tooltip" type="String" />
<description>
- Sets the [String] tooltip of the item at the specified index [code]idx[/code].
+ Sets the [String] tooltip of the item at the specified index [param idx].
[b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="has_feature" qualifiers="const">
<return type="bool" />
- <argument index="0" name="feature" type="int" enum="DisplayServer.Feature" />
+ <param index="0" name="feature" type="int" enum="DisplayServer.Feature" />
<description>
</description>
</method>
@@ -624,9 +653,9 @@
</method>
<method name="keyboard_get_keycode_from_physical" qualifiers="const">
<return type="int" enum="Key" />
- <argument index="0" name="keycode" type="int" enum="Key" />
+ <param index="0" name="keycode" type="int" enum="Key" />
<description>
- Converts a physical (US QWERTY) [code]keycode[/code] to one in the active keyboard layout.
+ Converts a physical (US QWERTY) [param keycode] to one in the active keyboard layout.
[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
</description>
</method>
@@ -639,23 +668,23 @@
</method>
<method name="keyboard_get_layout_language" qualifiers="const">
<return type="String" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the ISO-639/BCP-47 language code of the keyboard layout at position [code]index[/code].
+ Returns the ISO-639/BCP-47 language code of the keyboard layout at position [param index].
[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
</description>
</method>
<method name="keyboard_get_layout_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the localized name of the keyboard layout at position [code]index[/code].
+ Returns the localized name of the keyboard layout at position [param index].
[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
</description>
</method>
<method name="keyboard_set_current_layout">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Sets active keyboard layout.
[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
@@ -679,7 +708,7 @@
</method>
<method name="mouse_set_mode">
<return type="void" />
- <argument index="0" name="mouse_mode" type="int" enum="DisplayServer.MouseMode" />
+ <param index="0" name="mouse_mode" type="int" enum="DisplayServer.MouseMode" />
<description>
</description>
</method>
@@ -690,9 +719,9 @@
</method>
<method name="screen_get_dpi" qualifiers="const">
<return type="int" />
- <argument index="0" name="screen" type="int" default="-1" />
+ <param index="0" name="screen" type="int" default="-1" />
<description>
- Returns the dots per inch density of the specified screen. If [code]screen[/code] is [/code]SCREEN_OF_MAIN_WINDOW[/code] (the default value), a screen with the main window will be used.
+ Returns the dots per inch density of the specified screen. If [param screen] is [constant SCREEN_OF_MAIN_WINDOW] (the default value), a screen with the main window will be used.
[b]Note:[/b] On macOS, returned value is inaccurate if fractional display scaling mode is used.
[b]Note:[/b] On Android devices, the actual screen densities are grouped into six generalized densities:
[codeblock]
@@ -716,22 +745,22 @@
</method>
<method name="screen_get_orientation" qualifiers="const">
<return type="int" enum="DisplayServer.ScreenOrientation" />
- <argument index="0" name="screen" type="int" default="-1" />
+ <param index="0" name="screen" type="int" default="-1" />
<description>
</description>
</method>
<method name="screen_get_position" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="screen" type="int" default="-1" />
+ <param index="0" name="screen" type="int" default="-1" />
<description>
</description>
</method>
<method name="screen_get_refresh_rate" qualifiers="const">
<return type="float" />
- <argument index="0" name="screen" type="int" default="-1" />
+ <param index="0" name="screen" type="int" default="-1" />
<description>
- Returns the current refresh rate of the specified screen. If [code]screen[/code] is [constant SCREEN_OF_MAIN_WINDOW] (the default value), a screen with the main window will be used.
- [b]Note:[/b] Returns [code]-1.0[/code] if the DisplayServer fails to find the refresh rate for the specified screen. On HTML5, [method screen_get_refresh_rate] will always return [code]-1.0[/code] as there is no way to retrieve the refresh rate on that platform.
+ Returns the current refresh rate of the specified screen. If [param screen] is [constant SCREEN_OF_MAIN_WINDOW] (the default value), a screen with the main window will be used.
+ [b]Note:[/b] Returns [code]-1.0[/code] if the DisplayServer fails to find the refresh rate for the specified screen. On Web, [method screen_get_refresh_rate] will always return [code]-1.0[/code] as there is no way to retrieve the refresh rate on that platform.
To fallback to a default refresh rate if the method fails, try:
[codeblock]
var refresh_rate = DisplayServer.screen_get_refresh_rate()
@@ -742,7 +771,7 @@
</method>
<method name="screen_get_scale" qualifiers="const">
<return type="float" />
- <argument index="0" name="screen" type="int" default="-1" />
+ <param index="0" name="screen" type="int" default="-1" />
<description>
Returns the scale factor of the specified screen by index.
[b]Note:[/b] On macOS returned value is [code]2.0[/code] for hiDPI (Retina) screen, and [code]1.0[/code] for all other cases.
@@ -751,13 +780,13 @@
</method>
<method name="screen_get_size" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="screen" type="int" default="-1" />
+ <param index="0" name="screen" type="int" default="-1" />
<description>
</description>
</method>
<method name="screen_get_usable_rect" qualifiers="const">
<return type="Rect2i" />
- <argument index="0" name="screen" type="int" default="-1" />
+ <param index="0" name="screen" type="int" default="-1" />
<description>
</description>
</method>
@@ -768,32 +797,32 @@
</method>
<method name="screen_is_touchscreen" qualifiers="const">
<return type="bool" />
- <argument index="0" name="screen" type="int" default="-1" />
+ <param index="0" name="screen" type="int" default="-1" />
<description>
</description>
</method>
<method name="screen_set_keep_on">
<return type="void" />
- <argument index="0" name="enable" type="bool" />
+ <param index="0" name="enable" type="bool" />
<description>
</description>
</method>
<method name="screen_set_orientation">
<return type="void" />
- <argument index="0" name="orientation" type="int" enum="DisplayServer.ScreenOrientation" />
- <argument index="1" name="screen" type="int" default="-1" />
+ <param index="0" name="orientation" type="int" enum="DisplayServer.ScreenOrientation" />
+ <param index="1" name="screen" type="int" default="-1" />
<description>
</description>
</method>
<method name="set_icon">
<return type="void" />
- <argument index="0" name="image" type="Image" />
+ <param index="0" name="image" type="Image" />
<description>
</description>
</method>
<method name="set_native_icon">
<return type="void" />
- <argument index="0" name="filename" type="String" />
+ <param index="0" name="filename" type="String" />
<description>
</description>
</method>
@@ -813,7 +842,7 @@
</method>
<method name="tablet_get_driver_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns the tablet driver name for the given index.
[b]Note:[/b] This method is implemented on Windows.
@@ -821,97 +850,97 @@
</method>
<method name="tablet_set_current_driver">
<return type="void" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
Set active tablet driver name.
[b]Note:[/b] This method is implemented on Windows.
</description>
</method>
<method name="tts_get_voices" qualifiers="const">
- <return type="Array" />
+ <return type="Dictionary[]" />
<description>
Returns an [Array] of voice information dictionaries.
Each [Dictionary] contains two [String] entries:
- [code]name[/code] is voice name.
- [code]id[/code] is voice identifier.
- [code]language[/code] is language code in [code]lang_Variant[/code] format. [code]lang[/code] part is a 2 or 3-letter code based on the ISO-639 standard, in lowercase. And [code]Variant[/code] part is an engine dependent string describing country, region or/and dialect.
- [b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS, and Windows.
+ [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS, and Windows.
</description>
</method>
<method name="tts_get_voices_for_language" qualifiers="const">
<return type="PackedStringArray" />
- <argument index="0" name="language" type="String" />
+ <param index="0" name="language" type="String" />
<description>
- Returns an [PackedStringArray] of voice identifiers for the [code]language[/code].
- [b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS, and Windows.
+ Returns an [PackedStringArray] of voice identifiers for the [param language].
+ [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS, and Windows.
</description>
</method>
<method name="tts_is_paused" qualifiers="const">
<return type="bool" />
<description>
Returns [code]true[/code] if the synthesizer is in a paused state.
- [b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS, and Windows.
+ [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS, and Windows.
</description>
</method>
<method name="tts_is_speaking" qualifiers="const">
<return type="bool" />
<description>
Returns [code]true[/code] if the synthesizer is generating speech, or have utterance waiting in the queue.
- [b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS, and Windows.
+ [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS, and Windows.
</description>
</method>
<method name="tts_pause">
<return type="void" />
<description>
Puts the synthesizer into a paused state.
- [b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS, and Windows.
+ [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS, and Windows.
</description>
</method>
<method name="tts_resume">
<return type="void" />
<description>
Resumes the synthesizer if it was paused.
- [b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS, and Windows.
+ [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS, and Windows.
</description>
</method>
<method name="tts_set_utterance_callback">
<return type="void" />
- <argument index="0" name="event" type="int" enum="DisplayServer.TTSUtteranceEvent" />
- <argument index="1" name="callable" type="Callable" />
+ <param index="0" name="event" type="int" enum="DisplayServer.TTSUtteranceEvent" />
+ <param index="1" name="callable" type="Callable" />
<description>
Adds a callback, which is called when the utterance has started, finished, canceled or reached a text boundary.
- [code]TTS_UTTERANCE_STARTED[/code], [code]TTS_UTTERANCE_ENDED[/code], and [code]TTS_UTTERANCE_CANCELED[/code] callable's method should take one [int] parameter, the utterance id.
- [code]TTS_UTTERANCE_BOUNDARY[/code] callable's method should take two [int] parameters, the index of the character and the utterance id.
[b]Note:[/b] The granularity of the boundary callbacks is engine dependent.
- [b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS, and Windows.
+ [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS, and Windows.
</description>
</method>
<method name="tts_speak">
<return type="void" />
- <argument index="0" name="text" type="String" />
- <argument index="1" name="voice" type="String" />
- <argument index="2" name="volume" type="int" default="50" />
- <argument index="3" name="pitch" type="float" default="1.0" />
- <argument index="4" name="rate" type="float" default="1.0" />
- <argument index="5" name="utterance_id" type="int" default="0" />
- <argument index="6" name="interrupt" type="bool" default="false" />
- <description>
- Adds an utterance to the queue. If [code]interrupt[/code] is [code]true[/code], the queue is cleared first.
- - [code]voice[/code] identifier is one of the [code]"id"[/code] values returned by [method tts_get_voices] or one of the values returned by [method tts_get_voices_for_language].
- - [code]volume[/code] ranges from [code]0[/code] (lowest) to [code]100[/code] (highest).
- - [code]pitch[/code] ranges from [code]0.0[/code] (lowest) to [code]2.0[/code] (highest), [code]1.0[/code] is default pitch for the current voice.
- - [code]rate[/code] ranges from [code]0.1[/code] (lowest) to [code]10.0[/code] (highest), [code]1.0[/code] is a normal speaking rate. Other values act as a percentage relative.
- - [code]utterance_id[/code] is passed as a parameter to the callback functions.
- [b]Note:[/b] On Windows and Linux, utterance [code]text[/code] can use SSML markup. SSML support is engine and voice dependent. If the engine does not support SSML, you should strip out all XML markup before calling [method tts_speak].
+ <param index="0" name="text" type="String" />
+ <param index="1" name="voice" type="String" />
+ <param index="2" name="volume" type="int" default="50" />
+ <param index="3" name="pitch" type="float" default="1.0" />
+ <param index="4" name="rate" type="float" default="1.0" />
+ <param index="5" name="utterance_id" type="int" default="0" />
+ <param index="6" name="interrupt" type="bool" default="false" />
+ <description>
+ Adds an utterance to the queue. If [param interrupt] is [code]true[/code], the queue is cleared first.
+ - [param voice] identifier is one of the [code]"id"[/code] values returned by [method tts_get_voices] or one of the values returned by [method tts_get_voices_for_language].
+ - [param volume] ranges from [code]0[/code] (lowest) to [code]100[/code] (highest).
+ - [param pitch] ranges from [code]0.0[/code] (lowest) to [code]2.0[/code] (highest), [code]1.0[/code] is default pitch for the current voice.
+ - [param rate] ranges from [code]0.1[/code] (lowest) to [code]10.0[/code] (highest), [code]1.0[/code] is a normal speaking rate. Other values act as a percentage relative.
+ - [param utterance_id] is passed as a parameter to the callback functions.
+ [b]Note:[/b] On Windows and Linux, utterance [param text] can use SSML markup. SSML support is engine and voice dependent. If the engine does not support SSML, you should strip out all XML markup before calling [method tts_speak].
[b]Note:[/b] The granularity of pitch, rate, and volume is engine and voice dependent. Values may be truncated.
- [b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS, and Windows.
+ [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS, and Windows.
</description>
</method>
<method name="tts_stop">
<return type="void" />
<description>
Stops synthesis in progress and removes all utterances from the queue.
- [b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS, and Windows.
+ [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS, and Windows.
</description>
</method>
<method name="virtual_keyboard_get_height" qualifiers="const">
@@ -928,40 +957,40 @@
</method>
<method name="virtual_keyboard_show">
<return type="void" />
- <argument index="0" name="existing_text" type="String" />
- <argument index="1" name="position" type="Rect2" default="Rect2(0, 0, 0, 0)" />
- <argument index="2" name="multiline" type="bool" default="false" />
- <argument index="3" name="max_length" type="int" default="-1" />
- <argument index="4" name="cursor_start" type="int" default="-1" />
- <argument index="5" name="cursor_end" type="int" default="-1" />
+ <param index="0" name="existing_text" type="String" />
+ <param index="1" name="position" type="Rect2" default="Rect2(0, 0, 0, 0)" />
+ <param index="2" name="type" type="int" enum="DisplayServer.VirtualKeyboardType" default="0" />
+ <param index="3" name="max_length" type="int" default="-1" />
+ <param index="4" name="cursor_start" type="int" default="-1" />
+ <param index="5" name="cursor_end" type="int" default="-1" />
<description>
Shows the virtual keyboard if the platform has one.
- [code]existing_text[/code] parameter is useful for implementing your own [LineEdit] or [TextEdit], as it tells the virtual keyboard what text has already been typed (the virtual keyboard uses it for auto-correct and predictions).
- [code]position[/code] parameter is the screen space [Rect2] of the edited text.
- [code]multiline[/code] parameter needs to be set to [code]true[/code] to be able to enter multiple lines of text, as in [TextEdit].
- [code]max_length[/code] limits the number of characters that can be entered if different from [code]-1[/code].
- [code]cursor_start[/code] can optionally define the current text cursor position if [code]cursor_end[/code] is not set.
- [code]cursor_start[/code] and [code]cursor_end[/code] can optionally define the current text selection.
- [b]Note:[/b] This method is implemented on Android, iOS and UWP.
+ [param existing_text] parameter is useful for implementing your own [LineEdit] or [TextEdit], as it tells the virtual keyboard what text has already been typed (the virtual keyboard uses it for auto-correct and predictions).
+ [param position] parameter is the screen space [Rect2] of the edited text.
+ [param type] parameter allows configuring which type of virtual keyboard to show.
+ [param max_length] limits the number of characters that can be entered if different from [code]-1[/code].
+ [param cursor_start] can optionally define the current text cursor position if [param cursor_end] is not set.
+ [param cursor_start] and [param cursor_end] can optionally define the current text selection.
+ [b]Note:[/b] This method is implemented on Android, iOS and Web.
</description>
</method>
<method name="warp_mouse">
<return type="void" />
- <argument index="0" name="position" type="Vector2i" />
+ <param index="0" name="position" type="Vector2i" />
<description>
- Sets the mouse cursor position to the given [code]position[/code] relative to an origin at the upper left corner of the currently focused game Window Manager window.
+ Sets the mouse cursor position to the given [param position] relative to an origin at the upper left corner of the currently focused game Window Manager window.
</description>
</method>
<method name="window_attach_instance_id">
<return type="void" />
- <argument index="0" name="instance_id" type="int" />
- <argument index="1" name="window_id" type="int" default="0" />
+ <param index="0" name="instance_id" type="int" />
+ <param index="1" name="window_id" type="int" default="0" />
<description>
</description>
</method>
<method name="window_can_draw" qualifiers="const">
<return type="bool" />
- <argument index="0" name="window_id" type="int" default="0" />
+ <param index="0" name="window_id" type="int" default="0" />
<description>
</description>
</method>
@@ -973,47 +1002,47 @@
</method>
<method name="window_get_attached_instance_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="window_id" type="int" default="0" />
+ <param index="0" name="window_id" type="int" default="0" />
<description>
</description>
</method>
<method name="window_get_current_screen" qualifiers="const">
<return type="int" />
- <argument index="0" name="window_id" type="int" default="0" />
+ <param index="0" name="window_id" type="int" default="0" />
<description>
</description>
</method>
<method name="window_get_flag" qualifiers="const">
<return type="bool" />
- <argument index="0" name="flag" type="int" enum="DisplayServer.WindowFlags" />
- <argument index="1" name="window_id" type="int" default="0" />
+ <param index="0" name="flag" type="int" enum="DisplayServer.WindowFlags" />
+ <param index="1" name="window_id" type="int" default="0" />
<description>
- Returns the current value of the given window's [code]flag[/code].
+ Returns the current value of the given window's [param flag].
</description>
</method>
<method name="window_get_max_size" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="window_id" type="int" default="0" />
+ <param index="0" name="window_id" type="int" default="0" />
<description>
</description>
</method>
<method name="window_get_min_size" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="window_id" type="int" default="0" />
+ <param index="0" name="window_id" type="int" default="0" />
<description>
</description>
</method>
<method name="window_get_mode" qualifiers="const">
<return type="int" enum="DisplayServer.WindowMode" />
- <argument index="0" name="window_id" type="int" default="0" />
+ <param index="0" name="window_id" type="int" default="0" />
<description>
Returns the mode of the given window.
</description>
</method>
<method name="window_get_native_handle" qualifiers="const">
<return type="int" />
- <argument index="0" name="handle_type" type="int" enum="DisplayServer.HandleType" />
- <argument index="1" name="window_id" type="int" default="0" />
+ <param index="0" name="handle_type" type="int" enum="DisplayServer.HandleType" />
+ <param index="1" name="window_id" type="int" default="0" />
<description>
Returns internal structure pointers for use in plugins.
[b]Note:[/b] This method is implemented on Android, Linux, macOS and Windows.
@@ -1021,67 +1050,88 @@
</method>
<method name="window_get_popup_safe_rect" qualifiers="const">
<return type="Rect2i" />
- <argument index="0" name="window" type="int" />
+ <param index="0" name="window" type="int" />
<description>
Returns the bounding box of control, or menu item that was used to open the popup window, in the screen coordinate system.
</description>
</method>
<method name="window_get_position" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="window_id" type="int" default="0" />
+ <param index="0" name="window_id" type="int" default="0" />
<description>
Returns the position of the given window to on the screen.
</description>
</method>
<method name="window_get_real_size" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="window_id" type="int" default="0" />
+ <param index="0" name="window_id" type="int" default="0" />
<description>
</description>
</method>
+ <method name="window_get_safe_title_margins" qualifiers="const">
+ <return type="Vector2i" />
+ <param index="0" name="window_id" type="int" default="0" />
+ <description>
+ Returns left and right margins of the title that are safe to use (contains no buttons or other elements) when [constant WINDOW_FLAG_EXTEND_TO_TITLE] flag is set.
+ </description>
+ </method>
<method name="window_get_size" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="window_id" type="int" default="0" />
+ <param index="0" name="window_id" type="int" default="0" />
<description>
</description>
</method>
<method name="window_get_vsync_mode" qualifiers="const">
<return type="int" enum="DisplayServer.VSyncMode" />
- <argument index="0" name="window_id" type="int" default="0" />
+ <param index="0" name="window_id" type="int" default="0" />
+ <description>
+ Returns the V-Sync mode of the given window.
+ </description>
+ </method>
+ <method name="window_maximize_on_title_dbl_click" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code], if double-click on a window title should maximize it.
+ [b]Note:[/b] This method is implemented on macOS.
+ </description>
+ </method>
+ <method name="window_minimize_on_title_dbl_click" qualifiers="const">
+ <return type="bool" />
<description>
- Returns the VSync mode of the given window.
+ Returns [code]true[/code], if double-click on a window title should minimize it.
+ [b]Note:[/b] This method is implemented on macOS.
</description>
</method>
<method name="window_move_to_foreground">
<return type="void" />
- <argument index="0" name="window_id" type="int" default="0" />
+ <param index="0" name="window_id" type="int" default="0" />
<description>
</description>
</method>
<method name="window_request_attention">
<return type="void" />
- <argument index="0" name="window_id" type="int" default="0" />
+ <param index="0" name="window_id" type="int" default="0" />
<description>
</description>
</method>
<method name="window_set_current_screen">
<return type="void" />
- <argument index="0" name="screen" type="int" />
- <argument index="1" name="window_id" type="int" default="0" />
+ <param index="0" name="screen" type="int" />
+ <param index="1" name="window_id" type="int" default="0" />
<description>
</description>
</method>
<method name="window_set_drop_files_callback">
<return type="void" />
- <argument index="0" name="callback" type="Callable" />
- <argument index="1" name="window_id" type="int" default="0" />
+ <param index="0" name="callback" type="Callable" />
+ <param index="1" name="window_id" type="int" default="0" />
<description>
</description>
</method>
<method name="window_set_exclusive">
<return type="void" />
- <argument index="0" name="window_id" type="int" />
- <argument index="1" name="exclusive" type="bool" />
+ <param index="0" name="window_id" type="int" />
+ <param index="1" name="exclusive" type="bool" />
<description>
If set to [code]true[/code], this window will always stay on top of its parent window, parent window will ignore input while this window is opened.
[b]Note:[/b] On macOS, exclusive windows are confined to the same space (virtual desktop or screen) as the parent window.
@@ -1090,70 +1140,70 @@
</method>
<method name="window_set_flag">
<return type="void" />
- <argument index="0" name="flag" type="int" enum="DisplayServer.WindowFlags" />
- <argument index="1" name="enabled" type="bool" />
- <argument index="2" name="window_id" type="int" default="0" />
+ <param index="0" name="flag" type="int" enum="DisplayServer.WindowFlags" />
+ <param index="1" name="enabled" type="bool" />
+ <param index="2" name="window_id" type="int" default="0" />
<description>
- Enables or disables the given window's given [code]flag[/code]. See [enum WindowFlags] for possible values and their behavior.
+ Enables or disables the given window's given [param flag]. See [enum WindowFlags] for possible values and their behavior.
</description>
</method>
<method name="window_set_ime_active">
<return type="void" />
- <argument index="0" name="active" type="bool" />
- <argument index="1" name="window_id" type="int" default="0" />
+ <param index="0" name="active" type="bool" />
+ <param index="1" name="window_id" type="int" default="0" />
<description>
</description>
</method>
<method name="window_set_ime_position">
<return type="void" />
- <argument index="0" name="position" type="Vector2i" />
- <argument index="1" name="window_id" type="int" default="0" />
+ <param index="0" name="position" type="Vector2i" />
+ <param index="1" name="window_id" type="int" default="0" />
<description>
</description>
</method>
<method name="window_set_input_event_callback">
<return type="void" />
- <argument index="0" name="callback" type="Callable" />
- <argument index="1" name="window_id" type="int" default="0" />
+ <param index="0" name="callback" type="Callable" />
+ <param index="1" name="window_id" type="int" default="0" />
<description>
</description>
</method>
<method name="window_set_input_text_callback">
<return type="void" />
- <argument index="0" name="callback" type="Callable" />
- <argument index="1" name="window_id" type="int" default="0" />
+ <param index="0" name="callback" type="Callable" />
+ <param index="1" name="window_id" type="int" default="0" />
<description>
</description>
</method>
<method name="window_set_max_size">
<return type="void" />
- <argument index="0" name="max_size" type="Vector2i" />
- <argument index="1" name="window_id" type="int" default="0" />
+ <param index="0" name="max_size" type="Vector2i" />
+ <param index="1" name="window_id" type="int" default="0" />
<description>
</description>
</method>
<method name="window_set_min_size">
<return type="void" />
- <argument index="0" name="min_size" type="Vector2i" />
- <argument index="1" name="window_id" type="int" default="0" />
+ <param index="0" name="min_size" type="Vector2i" />
+ <param index="1" name="window_id" type="int" default="0" />
<description>
- Sets the minimum size for the given window to [code]min_size[/code] (in pixels).
+ Sets the minimum size for the given window to [param min_size] (in pixels).
[b]Note:[/b] By default, the main window has a minimum size of [code]Vector2i(64, 64)[/code]. This prevents issues that can arise when the window is resized to a near-zero size.
</description>
</method>
<method name="window_set_mode">
<return type="void" />
- <argument index="0" name="mode" type="int" enum="DisplayServer.WindowMode" />
- <argument index="1" name="window_id" type="int" default="0" />
+ <param index="0" name="mode" type="int" enum="DisplayServer.WindowMode" />
+ <param index="1" name="window_id" type="int" default="0" />
<description>
- Sets window mode for the given window to [code]mode[/code]. See [enum WindowMode] for possible values and how each mode behaves.
+ Sets window mode for the given window to [param mode]. See [enum WindowMode] for possible values and how each mode behaves.
[b]Note:[/b] Setting the window to fullscreen forcibly sets the borderless flag to [code]true[/code], so make sure to set it back to [code]false[/code] when not wanted.
</description>
</method>
<method name="window_set_mouse_passthrough">
<return type="void" />
- <argument index="0" name="region" type="PackedVector2Array" />
- <argument index="1" name="window_id" type="int" default="0" />
+ <param index="0" name="region" type="PackedVector2Array" />
+ <param index="1" name="window_id" type="int" default="0" />
<description>
Sets a polygonal region of the window which accepts mouse events. Mouse events outside the region will be passed through.
Passing an empty array will disable passthrough support (all mouse events will be intercepted by the window, which is the default behavior).
@@ -1185,64 +1235,64 @@
</method>
<method name="window_set_popup_safe_rect">
<return type="void" />
- <argument index="0" name="window" type="int" />
- <argument index="1" name="rect" type="Rect2i" />
+ <param index="0" name="window" type="int" />
+ <param index="1" name="rect" type="Rect2i" />
<description>
Sets the bounding box of control, or menu item that was used to open the popup window, in the screen coordinate system. Clicking this area will not auto-close this popup.
</description>
</method>
<method name="window_set_position">
<return type="void" />
- <argument index="0" name="position" type="Vector2i" />
- <argument index="1" name="window_id" type="int" default="0" />
+ <param index="0" name="position" type="Vector2i" />
+ <param index="1" name="window_id" type="int" default="0" />
<description>
- Sets the position of the given window to [code]position[/code].
+ Sets the position of the given window to [param position].
</description>
</method>
<method name="window_set_rect_changed_callback">
<return type="void" />
- <argument index="0" name="callback" type="Callable" />
- <argument index="1" name="window_id" type="int" default="0" />
+ <param index="0" name="callback" type="Callable" />
+ <param index="1" name="window_id" type="int" default="0" />
<description>
</description>
</method>
<method name="window_set_size">
<return type="void" />
- <argument index="0" name="size" type="Vector2i" />
- <argument index="1" name="window_id" type="int" default="0" />
+ <param index="0" name="size" type="Vector2i" />
+ <param index="1" name="window_id" type="int" default="0" />
<description>
- Sets the size of the given window to [code]size[/code].
+ Sets the size of the given window to [param size].
</description>
</method>
<method name="window_set_title">
<return type="void" />
- <argument index="0" name="title" type="String" />
- <argument index="1" name="window_id" type="int" default="0" />
+ <param index="0" name="title" type="String" />
+ <param index="1" name="window_id" type="int" default="0" />
<description>
- Sets the title of the given window to [code]title[/code].
+ Sets the title of the given window to [param title].
</description>
</method>
<method name="window_set_transient">
<return type="void" />
- <argument index="0" name="window_id" type="int" />
- <argument index="1" name="parent_window_id" type="int" />
+ <param index="0" name="window_id" type="int" />
+ <param index="1" name="parent_window_id" type="int" />
<description>
</description>
</method>
<method name="window_set_vsync_mode">
<return type="void" />
- <argument index="0" name="vsync_mode" type="int" enum="DisplayServer.VSyncMode" />
- <argument index="1" name="window_id" type="int" default="0" />
+ <param index="0" name="vsync_mode" type="int" enum="DisplayServer.VSyncMode" />
+ <param index="1" name="window_id" type="int" default="0" />
<description>
- Sets the VSync mode of the given window.
+ Sets the V-Sync mode of the given window.
See [enum DisplayServer.VSyncMode] for possible values and how they affect the behavior of your application.
Depending on the platform and used renderer, the engine will fall back to [constant VSYNC_ENABLED], if the desired mode is not supported.
</description>
</method>
<method name="window_set_window_event_callback">
<return type="void" />
- <argument index="0" name="callback" type="Callable" />
- <argument index="1" name="window_id" type="int" default="0" />
+ <param index="0" name="callback" type="Callable" />
+ <param index="1" name="window_id" type="int" default="0" />
<description>
</description>
</method>
@@ -1287,6 +1337,9 @@
<constant name="FEATURE_TEXT_TO_SPEECH" value="19" enum="Feature">
Display server supports text-to-speech. See [code]tts_*[/code] methods.
</constant>
+ <constant name="FEATURE_EXTEND_TO_TITLE" value="20" enum="Feature">
+ Display server supports expanding window content to the title. See [constant WINDOW_FLAG_EXTEND_TO_TITLE].
+ </constant>
<constant name="MOUSE_MODE_VISIBLE" value="0" enum="MouseMode">
Makes the mouse cursor visible if it is hidden.
</constant>
@@ -1323,6 +1376,31 @@
</constant>
<constant name="SCREEN_SENSOR" value="6" enum="ScreenOrientation">
</constant>
+ <constant name="KEYBOARD_TYPE_DEFAULT" value="0" enum="VirtualKeyboardType">
+ Default text virtual keyboard.
+ </constant>
+ <constant name="KEYBOARD_TYPE_MULTILINE" value="1" enum="VirtualKeyboardType">
+ Multiline virtual keyboard.
+ </constant>
+ <constant name="KEYBOARD_TYPE_NUMBER" value="2" enum="VirtualKeyboardType">
+ Virtual number keypad, useful for PIN entry.
+ </constant>
+ <constant name="KEYBOARD_TYPE_NUMBER_DECIMAL" value="3" enum="VirtualKeyboardType">
+ Virtual number keypad, useful for entering fractional numbers.
+ </constant>
+ <constant name="KEYBOARD_TYPE_PHONE" value="4" enum="VirtualKeyboardType">
+ Virtual phone number keypad.
+ </constant>
+ <constant name="KEYBOARD_TYPE_EMAIL_ADDRESS" value="5" enum="VirtualKeyboardType">
+ Virtual keyboard with additional keys to assist with typing email addresses.
+ </constant>
+ <constant name="KEYBOARD_TYPE_PASSWORD" value="6" enum="VirtualKeyboardType">
+ Virtual keyboard for entering a password. On most platforms, this should disable autocomplete and autocapitalization.
+ [b]Note:[/b] This is not supported on Web. Instead, this behaves identically to [constant KEYBOARD_TYPE_DEFAULT].
+ </constant>
+ <constant name="KEYBOARD_TYPE_URL" value="7" enum="VirtualKeyboardType">
+ Virtual keyboard with additional keys to assist with typing URLs.
+ </constant>
<constant name="CURSOR_ARROW" value="0" enum="CursorShape">
</constant>
<constant name="CURSOR_IBEAM" value="1" enum="CursorShape">
@@ -1392,7 +1470,11 @@
<constant name="WINDOW_FLAG_POPUP" value="5" enum="WindowFlags">
Window is part of menu or [OptionButton] dropdown. This flag can't be changed when window is visible. An active popup window will exclusively receive all input, without stealing focus from its parent. Popup windows are automatically closed when uses click outside it, or when an application is switched. Popup window must have [constant WINDOW_FLAG_TRANSPARENT] set.
</constant>
- <constant name="WINDOW_FLAG_MAX" value="6" enum="WindowFlags">
+ <constant name="WINDOW_FLAG_EXTEND_TO_TITLE" value="6" enum="WindowFlags">
+ Window content is expanded to the full size of the window. Unlike borderless window, the frame is left intact and can be used to resize the window, title bar is transparent, but have minimize/maximize/close buttons.
+ [b]Note:[/b] This flag is implemented on macOS.
+ </constant>
+ <constant name="WINDOW_FLAG_MAX" value="7" enum="WindowFlags">
</constant>
<constant name="WINDOW_EVENT_MOUSE_ENTER" value="0" enum="WindowEvent">
</constant>
@@ -1429,13 +1511,13 @@
Window handle:
- Windows: [code]HWND[/code] for the window.
- Linux: [code]X11::Window*[/code] for the window.
- - MacOS: [code]NSWindow*[/code] for the window.
+ - macOS: [code]NSWindow*[/code] for the window.
- iOS: [code]UIViewController*[/code] for the view controller.
- Android: [code]jObject[/code] for the activity.
</constant>
<constant name="WINDOW_VIEW" value="2" enum="HandleType">
Window view:
- - MacOS: [code]NSView*[/code] for the window main view.
+ - macOS: [code]NSView*[/code] for the window main view.
- iOS: [code]UIView*[/code] for the window main view.
</constant>
<constant name="TTS_UTTERANCE_STARTED" value="0" enum="TTSUtteranceEvent">
diff --git a/doc/classes/EditorCommandPalette.xml b/doc/classes/EditorCommandPalette.xml
index 2cc07c7f1b..53a3fe5d19 100644
--- a/doc/classes/EditorCommandPalette.xml
+++ b/doc/classes/EditorCommandPalette.xml
@@ -27,24 +27,24 @@
<methods>
<method name="add_command">
<return type="void" />
- <argument index="0" name="command_name" type="String" />
- <argument index="1" name="key_name" type="String" />
- <argument index="2" name="binded_callable" type="Callable" />
- <argument index="3" name="shortcut_text" type="String" default="&quot;None&quot;" />
+ <param index="0" name="command_name" type="String" />
+ <param index="1" name="key_name" type="String" />
+ <param index="2" name="binded_callable" type="Callable" />
+ <param index="3" name="shortcut_text" type="String" default="&quot;None&quot;" />
<description>
Adds a custom command to EditorCommandPalette.
- - [code]command_name[/code]: [String] (Name of the [b]Command[/b]. This is displayed to the user.)
- - [code]key_name[/code]: [String] (Name of the key for a particular [b]Command[/b]. This is used to uniquely identify the [b]Command[/b].)
- - [code]binded_callable[/code]: [Callable] (Callable of the [b]Command[/b]. This will be executed when the [b]Command[/b] is selected.)
- - [code]shortcut_text[/code]: [String] (Shortcut text of the [b]Command[/b] if available.)
+ - [param command_name]: [String] (Name of the [b]Command[/b]. This is displayed to the user.)
+ - [param key_name]: [String] (Name of the key for a particular [b]Command[/b]. This is used to uniquely identify the [b]Command[/b].)
+ - [param binded_callable]: [Callable] (Callable of the [b]Command[/b]. This will be executed when the [b]Command[/b] is selected.)
+ - [param shortcut_text]: [String] (Shortcut text of the [b]Command[/b] if available.)
</description>
</method>
<method name="remove_command">
<return type="void" />
- <argument index="0" name="key_name" type="String" />
+ <param index="0" name="key_name" type="String" />
<description>
Removes the custom command from EditorCommandPalette.
- - [code]key_name[/code]: [String] (Name of the key for a particular [b]Command[/b].)
+ - [param key_name]: [String] (Name of the key for a particular [b]Command[/b].)
</description>
</method>
</methods>
diff --git a/doc/classes/EditorDebuggerPlugin.xml b/doc/classes/EditorDebuggerPlugin.xml
index ba0a479fa7..c3e0a995c6 100644
--- a/doc/classes/EditorDebuggerPlugin.xml
+++ b/doc/classes/EditorDebuggerPlugin.xml
@@ -14,7 +14,7 @@
<methods>
<method name="has_capture">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
Returns [code]true[/code] if a message capture with given name is present otherwise [code]false[/code].
</description>
@@ -39,24 +39,24 @@
</method>
<method name="register_message_capture">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="callable" type="Callable" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="callable" type="Callable" />
<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.
+ Registers a message capture with given [param name]. If [param name] 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" />
- <argument index="0" name="message" type="String" />
- <argument index="1" name="data" type="Array" />
+ <param index="0" name="message" type="String" />
+ <param index="1" name="data" type="Array" />
<description>
- Sends a message with given [code]message[/code] and [code]data[/code] array.
+ Sends a message with given [param message] and [param data] array.
</description>
</method>
<method name="unregister_message_capture">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
Unregisters the message capture with given name.
</description>
@@ -64,7 +64,7 @@
</methods>
<signals>
<signal name="breaked">
- <argument index="0" name="can_debug" type="bool" />
+ <param index="0" name="can_debug" type="bool" />
<description>
Emitted when the game enters a break state.
</description>
diff --git a/doc/classes/EditorExportPlugin.xml b/doc/classes/EditorExportPlugin.xml
index f217fbaf48..091bac7d8e 100644
--- a/doc/classes/EditorExportPlugin.xml
+++ b/doc/classes/EditorExportPlugin.xml
@@ -12,12 +12,12 @@
<methods>
<method name="_export_begin" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="features" type="PackedStringArray" />
- <argument index="1" name="is_debug" type="bool" />
- <argument index="2" name="path" type="String" />
- <argument index="3" name="flags" type="int" />
+ <param index="0" name="features" type="PackedStringArray" />
+ <param index="1" name="is_debug" type="bool" />
+ <param index="2" name="path" type="String" />
+ <param index="3" name="flags" type="int" />
<description>
- Virtual method to be overridden by the user. It is called when the export starts and provides all information about the export. [code]features[/code] is the list of features for the export, [code]is_debug[/code] is [code]true[/code] for debug builds, [code]path[/code] is the target path for the exported project. [code]flags[/code] is only used when running a runnable profile, e.g. when using native run on Android.
+ Virtual method to be overridden by the user. It is called when the export starts and provides all information about the export. [param features] is the list of features for the export, [param is_debug] is [code]true[/code] for debug builds, [param path] is the target path for the exported project. [param flags] is only used when running a runnable profile, e.g. when using native run on Android.
</description>
</method>
<method name="_export_end" qualifiers="virtual">
@@ -28,40 +28,40 @@
</method>
<method name="_export_file" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="type" type="String" />
- <argument index="2" name="features" type="PackedStringArray" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="type" type="String" />
+ <param index="2" name="features" type="PackedStringArray" />
<description>
- Virtual method to be overridden by the user. Called for each exported file, providing arguments that can be used to identify the file. [code]path[/code] is the path of the file, [code]type[/code] is the [Resource] represented by the file (e.g. [PackedScene]) and [code]features[/code] is the list of features for the export.
+ Virtual method to be overridden by the user. Called for each exported file, providing arguments that can be used to identify the file. [param path] is the path of the file, [param type] is the [Resource] represented by the file (e.g. [PackedScene]) and [param features] is the list of features for the export.
Calling [method skip] inside this callback will make the file not included in the export.
</description>
</method>
<method name="add_file">
<return type="void" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="file" type="PackedByteArray" />
- <argument index="2" name="remap" type="bool" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="file" type="PackedByteArray" />
+ <param index="2" name="remap" type="bool" />
<description>
- Adds a custom file to be exported. [code]path[/code] is the virtual path that can be used to load the file, [code]file[/code] is the binary data of the file. If [code]remap[/code] is [code]true[/code], file will not be exported, but instead remapped to the given [code]path[/code].
+ Adds a custom file to be exported. [param path] is the virtual path that can be used to load the file, [param file] is the binary data of the file. If [param remap] is [code]true[/code], file will not be exported, but instead remapped to the given [param path].
</description>
</method>
<method name="add_ios_bundle_file">
<return type="void" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
- Adds an iOS bundle file from the given [code]path[/code] to the exported project.
+ Adds an iOS bundle file from the given [param path] to the exported project.
</description>
</method>
<method name="add_ios_cpp_code">
<return type="void" />
- <argument index="0" name="code" type="String" />
+ <param index="0" name="code" type="String" />
<description>
Adds a C++ code to the iOS export. The final code is created from the code appended by each active export plugin.
</description>
</method>
<method name="add_ios_embedded_framework">
<return type="void" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<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].
@@ -70,47 +70,47 @@
</method>
<method name="add_ios_framework">
<return type="void" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
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">
<return type="void" />
- <argument index="0" name="flags" type="String" />
+ <param index="0" name="flags" type="String" />
<description>
Adds linker flags for the iOS export.
</description>
</method>
<method name="add_ios_plist_content">
<return type="void" />
- <argument index="0" name="plist_content" type="String" />
+ <param index="0" name="plist_content" type="String" />
<description>
Adds content for iOS Property List files.
</description>
</method>
<method name="add_ios_project_static_lib">
<return type="void" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
- Adds a static lib from the given [code]path[/code] to the iOS project.
+ Adds a static lib from the given [param path] to the iOS project.
</description>
</method>
<method name="add_macos_plugin_file">
<return type="void" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
- Adds file or directory matching [code]path[/code] to [code]PlugIns[/code] directory of macOS app bundle.
+ Adds file or directory matching [param path] to [code]PlugIns[/code] directory of macOS app bundle.
[b]Note:[/b] This is useful only for macOS exports.
</description>
</method>
<method name="add_shared_object">
<return type="void" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="tags" type="PackedStringArray" />
- <argument index="2" name="target" type="String" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="tags" type="PackedStringArray" />
+ <param index="2" name="target" type="String" />
<description>
- Adds a shared object or a directory containing only shared objects with the given [code]tags[/code] and destination [code]path[/code].
+ Adds a shared object or a directory containing only shared objects with the given [param tags] and destination [param path].
[b]Note:[/b] In case of macOS exports, those shared objects will be added to [code]Frameworks[/code] directory of app bundle.
In case of a directory code-sign will error if you place non code object in directory.
</description>
diff --git a/doc/classes/EditorFeatureProfile.xml b/doc/classes/EditorFeatureProfile.xml
index a6bdc294ac..e216059364 100644
--- a/doc/classes/EditorFeatureProfile.xml
+++ b/doc/classes/EditorFeatureProfile.xml
@@ -12,85 +12,85 @@
<methods>
<method name="get_feature_name">
<return type="String" />
- <argument index="0" name="feature" type="int" enum="EditorFeatureProfile.Feature" />
+ <param index="0" name="feature" type="int" enum="EditorFeatureProfile.Feature" />
<description>
- Returns the specified [code]feature[/code]'s human-readable name.
+ Returns the specified [param feature]'s human-readable name.
</description>
</method>
<method name="is_class_disabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="class_name" type="StringName" />
+ <param index="0" name="class_name" type="StringName" />
<description>
- Returns [code]true[/code] if the class specified by [code]class_name[/code] is disabled. When disabled, the class won't appear in the Create New Node dialog.
+ Returns [code]true[/code] if the class specified by [param class_name] is disabled. When disabled, the class won't appear in the Create New Node dialog.
</description>
</method>
<method name="is_class_editor_disabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="class_name" type="StringName" />
+ <param index="0" name="class_name" type="StringName" />
<description>
- Returns [code]true[/code] if editing for the class specified by [code]class_name[/code] is disabled. When disabled, the class will still appear in the Create New Node dialog but the inspector will be read-only when selecting a node that extends the class.
+ Returns [code]true[/code] if editing for the class specified by [param class_name] is disabled. When disabled, the class will still appear in the Create New Node dialog but the inspector will be read-only when selecting a node that extends the class.
</description>
</method>
<method name="is_class_property_disabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="class_name" type="StringName" />
- <argument index="1" name="property" type="StringName" />
+ <param index="0" name="class_name" type="StringName" />
+ <param index="1" name="property" type="StringName" />
<description>
- Returns [code]true[/code] if [code]property[/code] is disabled in the class specified by [code]class_name[/code]. When a property is disabled, it won't appear in the inspector when selecting a node that extends the class specified by [code]class_name[/code].
+ Returns [code]true[/code] if [param property] is disabled in the class specified by [param class_name]. When a property is disabled, it won't appear in the inspector when selecting a node that extends the class specified by [param class_name].
</description>
</method>
<method name="is_feature_disabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="feature" type="int" enum="EditorFeatureProfile.Feature" />
+ <param index="0" name="feature" type="int" enum="EditorFeatureProfile.Feature" />
<description>
- Returns [code]true[/code] if the [code]feature[/code] is disabled. When a feature is disabled, it will disappear from the editor entirely.
+ Returns [code]true[/code] if the [param feature] is disabled. When a feature is disabled, it will disappear from the editor entirely.
</description>
</method>
<method name="load_from_file">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Loads an editor feature profile from a file. The file must follow the JSON format obtained by using the feature profile manager's [b]Export[/b] button or the [method save_to_file] method.
</description>
</method>
<method name="save_to_file">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Saves the editor feature profile to a file in JSON format. It can then be imported using the feature profile manager's [b]Import[/b] button or the [method load_from_file] method.
</description>
</method>
<method name="set_disable_class">
<return type="void" />
- <argument index="0" name="class_name" type="StringName" />
- <argument index="1" name="disable" type="bool" />
+ <param index="0" name="class_name" type="StringName" />
+ <param index="1" name="disable" type="bool" />
<description>
- If [code]disable[/code] is [code]true[/code], disables the class specified by [code]class_name[/code]. When disabled, the class won't appear in the Create New Node dialog.
+ If [param disable] is [code]true[/code], disables the class specified by [param class_name]. When disabled, the class won't appear in the Create New Node dialog.
</description>
</method>
<method name="set_disable_class_editor">
<return type="void" />
- <argument index="0" name="class_name" type="StringName" />
- <argument index="1" name="disable" type="bool" />
+ <param index="0" name="class_name" type="StringName" />
+ <param index="1" name="disable" type="bool" />
<description>
- If [code]disable[/code] is [code]true[/code], disables editing for the class specified by [code]class_name[/code]. When disabled, the class will still appear in the Create New Node dialog but the inspector will be read-only when selecting a node that extends the class.
+ If [param disable] is [code]true[/code], disables editing for the class specified by [param class_name]. When disabled, the class will still appear in the Create New Node dialog but the inspector will be read-only when selecting a node that extends the class.
</description>
</method>
<method name="set_disable_class_property">
<return type="void" />
- <argument index="0" name="class_name" type="StringName" />
- <argument index="1" name="property" type="StringName" />
- <argument index="2" name="disable" type="bool" />
+ <param index="0" name="class_name" type="StringName" />
+ <param index="1" name="property" type="StringName" />
+ <param index="2" name="disable" type="bool" />
<description>
- If [code]disable[/code] is [code]true[/code], disables editing for [code]property[/code] in the class specified by [code]class_name[/code]. When a property is disabled, it won't appear in the inspector when selecting a node that extends the class specified by [code]class_name[/code].
+ If [param disable] is [code]true[/code], disables editing for [param property] in the class specified by [param class_name]. When a property is disabled, it won't appear in the inspector when selecting a node that extends the class specified by [param class_name].
</description>
</method>
<method name="set_disable_feature">
<return type="void" />
- <argument index="0" name="feature" type="int" enum="EditorFeatureProfile.Feature" />
- <argument index="1" name="disable" type="bool" />
+ <param index="0" name="feature" type="int" enum="EditorFeatureProfile.Feature" />
+ <param index="1" name="disable" type="bool" />
<description>
- If [code]disable[/code] is [code]true[/code], disables the editor feature specified in [code]feature[/code]. When a feature is disabled, it will disappear from the editor entirely.
+ If [param disable] is [code]true[/code], disables the editor feature specified in [param feature]. When a feature is disabled, it will disappear from the editor entirely.
</description>
</method>
</methods>
diff --git a/doc/classes/EditorFileDialog.xml b/doc/classes/EditorFileDialog.xml
index 6fd5abe369..891c8d7d92 100644
--- a/doc/classes/EditorFileDialog.xml
+++ b/doc/classes/EditorFileDialog.xml
@@ -10,12 +10,12 @@
<methods>
<method name="add_filter">
<return type="void" />
- <argument index="0" name="filter" type="String" />
- <argument index="1" name="description" type="String" default="&quot;&quot;" />
+ <param index="0" name="filter" type="String" />
+ <param index="1" name="description" type="String" default="&quot;&quot;" />
<description>
- Adds a comma-delimited file name [code]filter[/code] option to the [EditorFileDialog] with an optional [code]description[/code], which restricts what files can be picked.
- A [code]filter[/code] should be of the form [code]"filename.extension"[/code], where filename and extension can be [code]*[/code] to match any string. Filters starting with [code].[/code] (i.e. empty filenames) are not allowed.
- For example, a [code]filter[/code] of [code]"*.tscn, *.scn"[/code] and a [code]description[/code] of [code]"Scenes"[/code] results in filter text "Scenes (*.tscn, *.scn)".
+ Adds a comma-delimited file name [param filter] option to the [EditorFileDialog] with an optional [param description], which restricts what files can be picked.
+ A [param filter] should be of the form [code]"filename.extension"[/code], where filename and extension can be [code]*[/code] to match any string. Filters starting with [code].[/code] (i.e. empty filenames) are not allowed.
+ For example, a [param filter] of [code]"*.tscn, *.scn"[/code] and a [param description] of [code]"Scenes"[/code] results in filter text "Scenes (*.tscn, *.scn)".
</description>
</method>
<method name="clear_filters">
@@ -68,19 +68,19 @@
</members>
<signals>
<signal name="dir_selected">
- <argument index="0" name="dir" type="String" />
+ <param index="0" name="dir" type="String" />
<description>
Emitted when a directory is selected.
</description>
</signal>
<signal name="file_selected">
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Emitted when a file is selected.
</description>
</signal>
<signal name="files_selected">
- <argument index="0" name="paths" type="PackedStringArray" />
+ <param index="0" name="paths" type="PackedStringArray" />
<description>
Emitted when multiple files are selected.
</description>
diff --git a/doc/classes/EditorFileSystem.xml b/doc/classes/EditorFileSystem.xml
index 402efba34a..e8df6ae7fe 100644
--- a/doc/classes/EditorFileSystem.xml
+++ b/doc/classes/EditorFileSystem.xml
@@ -12,7 +12,7 @@
<methods>
<method name="get_file_type" qualifiers="const">
<return type="String" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Returns the resource type of the file, given the full path. This returns a string such as [code]"Resource"[/code] or [code]"GDScript"[/code], [i]not[/i] a file extension such as [code]".gd"[/code].
</description>
@@ -25,9 +25,9 @@
</method>
<method name="get_filesystem_path">
<return type="EditorFileSystemDirectory" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
- Returns a view into the filesystem at [code]path[/code].
+ Returns a view into the filesystem at [param path].
</description>
</method>
<method name="get_scanning_progress" qualifiers="const">
@@ -44,7 +44,7 @@
</method>
<method name="reimport_files">
<return type="void" />
- <argument index="0" name="files" type="PackedStringArray" />
+ <param index="0" name="files" type="PackedStringArray" />
<description>
Reimports a set of files. Call this if these files or their [code].import[/code] files were directly edited by script or an external program.
If the file type changed or the file was newly created, use [method update_file] or [method scan].
@@ -65,7 +65,7 @@
</method>
<method name="update_file">
<return type="void" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Add a file in an existing directory, or schedule file information to be updated on editor restart. Can be used to update text files saved by an external program.
This will not import the file. To reimport, call [method reimport_files] or [method scan] methods.
@@ -85,19 +85,19 @@
</description>
</signal>
<signal name="resources_reimported">
- <argument index="0" name="resources" type="PackedStringArray" />
+ <param index="0" name="resources" type="PackedStringArray" />
<description>
Emitted if a resource is reimported.
</description>
</signal>
<signal name="resources_reload">
- <argument index="0" name="resources" type="PackedStringArray" />
+ <param index="0" name="resources" type="PackedStringArray" />
<description>
Emitted if at least one resource is reloaded when the filesystem is scanned.
</description>
</signal>
<signal name="sources_changed">
- <argument index="0" name="exist" type="bool" />
+ <param index="0" name="exist" type="bool" />
<description>
Emitted if the source of any imported file changed.
</description>
diff --git a/doc/classes/EditorFileSystemDirectory.xml b/doc/classes/EditorFileSystemDirectory.xml
index 98fea40a50..e9a0e3310c 100644
--- a/doc/classes/EditorFileSystemDirectory.xml
+++ b/doc/classes/EditorFileSystemDirectory.xml
@@ -11,23 +11,23 @@
<methods>
<method name="find_dir_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
- Returns the index of the directory with name [code]name[/code] or [code]-1[/code] if not found.
+ Returns the index of the directory with name [param name] or [code]-1[/code] if not found.
</description>
</method>
<method name="find_file_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
- Returns the index of the file with name [code]name[/code] or [code]-1[/code] if not found.
+ Returns the index of the file with name [param name] or [code]-1[/code] if not found.
</description>
</method>
<method name="get_file" qualifiers="const">
<return type="String" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the name of the file at index [code]idx[/code].
+ Returns the name of the file at index [param idx].
</description>
</method>
<method name="get_file_count" qualifiers="const">
@@ -38,37 +38,37 @@
</method>
<method name="get_file_import_is_valid" qualifiers="const">
<return type="bool" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns [code]true[/code] if the file at index [code]idx[/code] imported properly.
+ Returns [code]true[/code] if the file at index [param idx] imported properly.
</description>
</method>
<method name="get_file_path" qualifiers="const">
<return type="String" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the path to the file at index [code]idx[/code].
+ Returns the path to the file at index [param idx].
</description>
</method>
<method name="get_file_script_class_extends" qualifiers="const">
<return type="String" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the base class of the script class defined in the file at index [code]idx[/code]. If the file doesn't define a script class using the [code]class_name[/code] syntax, this will return an empty string.
+ Returns the base class of the script class defined in the file at index [param idx]. If the file doesn't define a script class using the [code]class_name[/code] syntax, this will return an empty string.
</description>
</method>
<method name="get_file_script_class_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the name of the script class defined in the file at index [code]idx[/code]. If the file doesn't define a script class using the [code]class_name[/code] syntax, this will return an empty string.
+ Returns the name of the script class defined in the file at index [param idx]. If the file doesn't define a script class using the [code]class_name[/code] syntax, this will return an empty string.
</description>
</method>
<method name="get_file_type" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the resource type of the file at index [code]idx[/code]. This returns a string such as [code]"Resource"[/code] or [code]"GDScript"[/code], [i]not[/i] a file extension such as [code]".gd"[/code].
+ Returns the resource type of the file at index [param idx]. This returns a string such as [code]"Resource"[/code] or [code]"GDScript"[/code], [i]not[/i] a file extension such as [code]".gd"[/code].
</description>
</method>
<method name="get_name">
@@ -91,9 +91,9 @@
</method>
<method name="get_subdir">
<return type="EditorFileSystemDirectory" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the subdirectory at index [code]idx[/code].
+ Returns the subdirectory at index [param idx].
</description>
</method>
<method name="get_subdir_count" qualifiers="const">
diff --git a/doc/classes/EditorImportPlugin.xml b/doc/classes/EditorImportPlugin.xml
index 2e84d3094f..f7f1d456d0 100644
--- a/doc/classes/EditorImportPlugin.xml
+++ b/doc/classes/EditorImportPlugin.xml
@@ -115,9 +115,9 @@
</tutorials>
<methods>
<method name="_get_import_options" qualifiers="virtual const">
- <return type="Array" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="preset_index" type="int" />
+ <return type="Dictionary[]" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="preset_index" type="int" />
<description>
Gets the options and default values for the preset at this index. Returns an Array of Dictionaries with the following keys: [code]name[/code], [code]default_value[/code], [code]property_hint[/code] (optional), [code]hint_string[/code] (optional), [code]usage[/code] (optional).
</description>
@@ -136,9 +136,9 @@
</method>
<method name="_get_option_visibility" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="option_name" type="StringName" />
- <argument index="2" name="options" type="Dictionary" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="option_name" type="StringName" />
+ <param index="2" name="options" type="Dictionary" />
<description>
This method can be overridden to hide specific import options if conditions are met. This is mainly useful for hiding options that depend on others if one of them is disabled. For example:
[codeblocks]
@@ -174,7 +174,7 @@
</method>
<method name="_get_preset_name" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="preset_index" type="int" />
+ <param index="0" name="preset_index" type="int" />
<description>
Gets the name of the options preset at this index.
</description>
@@ -211,13 +211,13 @@
</method>
<method name="_import" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="source_file" type="String" />
- <argument index="1" name="save_path" type="String" />
- <argument index="2" name="options" type="Dictionary" />
- <argument index="3" name="platform_variants" type="Array" />
- <argument index="4" name="gen_files" type="Array" />
+ <param index="0" name="source_file" type="String" />
+ <param index="1" name="save_path" type="String" />
+ <param index="2" name="options" type="Dictionary" />
+ <param index="3" name="platform_variants" type="Array" />
+ <param index="4" name="gen_files" type="Array" />
<description>
- Imports [code]source_file[/code] into [code]save_path[/code] with the import [code]options[/code] specified. The [code]platform_variants[/code] and [code]gen_files[/code] arrays will be modified by this function.
+ Imports [param source_file] into [param save_path] with the import [param options] specified. The [param platform_variants] and [param gen_files] arrays will be modified by this function.
This method must be overridden to do the actual importing work. See this class' description for an example of overriding this method.
</description>
</method>
diff --git a/doc/classes/EditorInspector.xml b/doc/classes/EditorInspector.xml
index 365e1f13a9..280a7bf34a 100644
--- a/doc/classes/EditorInspector.xml
+++ b/doc/classes/EditorInspector.xml
@@ -23,48 +23,48 @@
</description>
</signal>
<signal name="object_id_selected">
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Emitted when the Edit button of an [Object] has been pressed in the inspector. This is mainly used in the remote scene tree inspector.
</description>
</signal>
<signal name="property_deleted">
- <argument index="0" name="property" type="String" />
+ <param index="0" name="property" type="String" />
<description>
Emitted when a property is removed from the inspector.
</description>
</signal>
<signal name="property_edited">
- <argument index="0" name="property" type="String" />
+ <param index="0" name="property" type="String" />
<description>
Emitted when a property is edited in the inspector.
</description>
</signal>
<signal name="property_keyed">
- <argument index="0" name="property" type="String" />
- <argument index="1" name="value" type="Variant" />
- <argument index="2" name="advance" type="bool" />
+ <param index="0" name="property" type="String" />
+ <param index="1" name="value" type="Variant" />
+ <param index="2" name="advance" type="bool" />
<description>
Emitted when a property is keyed in the inspector. Properties can be keyed by clicking the "key" icon next to a property when the Animation panel is toggled.
</description>
</signal>
<signal name="property_selected">
- <argument index="0" name="property" type="String" />
+ <param index="0" name="property" type="String" />
<description>
Emitted when a property is selected in the inspector.
</description>
</signal>
<signal name="property_toggled">
- <argument index="0" name="property" type="String" />
- <argument index="1" name="checked" type="bool" />
+ <param index="0" name="property" type="String" />
+ <param index="1" name="checked" type="bool" />
<description>
Emitted when a boolean property is toggled in the inspector.
[b]Note:[/b] This signal is never emitted if the internal [code]autoclear[/code] property enabled. Since this property is always enabled in the editor inspector, this signal is never emitted by the editor itself.
</description>
</signal>
<signal name="resource_selected">
- <argument index="0" name="resource" type="Resource" />
- <argument index="1" name="path" type="String" />
+ <param index="0" name="resource" type="Resource" />
+ <param index="1" name="path" type="String" />
<description>
Emitted when a resource is selected in the inspector.
</description>
diff --git a/doc/classes/EditorInspectorPlugin.xml b/doc/classes/EditorInspectorPlugin.xml
index 572d5d9d84..c8a499260e 100644
--- a/doc/classes/EditorInspectorPlugin.xml
+++ b/doc/classes/EditorInspectorPlugin.xml
@@ -18,77 +18,77 @@
<methods>
<method name="_can_handle" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="object" type="Variant" />
+ <param index="0" name="object" type="Variant" />
<description>
Returns [code]true[/code] if this object can be handled by this plugin.
</description>
</method>
<method name="_parse_begin" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="object" type="Object" />
+ <param index="0" name="object" type="Object" />
<description>
- Called to allow adding controls at the beginning of the property list for [code]object[/code].
+ Called to allow adding controls at the beginning of the property list for [param object].
</description>
</method>
<method name="_parse_category" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="object" type="Object" />
- <argument index="1" name="category" type="String" />
+ <param index="0" name="object" type="Object" />
+ <param index="1" name="category" type="String" />
<description>
- Called to allow adding controls at the beginning of a category in the property list for [code]object[/code].
+ Called to allow adding controls at the beginning of a category in the property list for [param object].
</description>
</method>
<method name="_parse_end" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="object" type="Object" />
+ <param index="0" name="object" type="Object" />
<description>
- Called to allow adding controls at the end of the property list for [code]object[/code].
+ Called to allow adding controls at the end of the property list for [param object].
</description>
</method>
<method name="_parse_group" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="object" type="Object" />
- <argument index="1" name="group" type="String" />
+ <param index="0" name="object" type="Object" />
+ <param index="1" name="group" type="String" />
<description>
- Called to allow adding controls at the beginning of a group or a sub-group in the property list for [code]object[/code].
+ Called to allow adding controls at the beginning of a group or a sub-group in the property list for [param object].
</description>
</method>
<method name="_parse_property" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="object" type="Object" />
- <argument index="1" name="type" type="int" />
- <argument index="2" name="name" type="String" />
- <argument index="3" name="hint_type" type="int" />
- <argument index="4" name="hint_string" type="String" />
- <argument index="5" name="usage_flags" type="int" />
- <argument index="6" name="wide" type="bool" />
+ <param index="0" name="object" type="Object" />
+ <param index="1" name="type" type="int" />
+ <param index="2" name="name" type="String" />
+ <param index="3" name="hint_type" type="int" />
+ <param index="4" name="hint_string" type="String" />
+ <param index="5" name="usage_flags" type="int" />
+ <param index="6" name="wide" type="bool" />
<description>
- Called to allow adding property-specific editors to the property list for [code]object[/code]. The added editor control must extend [EditorProperty]. Returning [code]true[/code] removes the built-in editor for this property, otherwise allows to insert a custom editor before the built-in one.
+ Called to allow adding property-specific editors to the property list for [param object]. The added editor control must extend [EditorProperty]. Returning [code]true[/code] removes the built-in editor for this property, otherwise allows to insert a custom editor before the built-in one.
</description>
</method>
<method name="add_custom_control">
<return type="void" />
- <argument index="0" name="control" type="Control" />
+ <param index="0" name="control" type="Control" />
<description>
Adds a custom control, which is not necessarily a property editor.
</description>
</method>
<method name="add_property_editor">
<return type="void" />
- <argument index="0" name="property" type="String" />
- <argument index="1" name="editor" type="Control" />
- <argument index="2" name="add_to_end" type="bool" default="false" />
+ <param index="0" name="property" type="String" />
+ <param index="1" name="editor" type="Control" />
+ <param index="2" name="add_to_end" type="bool" default="false" />
<description>
- Adds a property editor for an individual property. The [code]editor[/code] control must extend [EditorProperty].
+ Adds a property editor for an individual property. The [param editor] control must extend [EditorProperty].
</description>
</method>
<method name="add_property_editor_for_multiple_properties">
<return type="void" />
- <argument index="0" name="label" type="String" />
- <argument index="1" name="properties" type="PackedStringArray" />
- <argument index="2" name="editor" type="Control" />
+ <param index="0" name="label" type="String" />
+ <param index="1" name="properties" type="PackedStringArray" />
+ <param index="2" name="editor" type="Control" />
<description>
- Adds an editor that allows modifying multiple properties. The [code]editor[/code] control must extend [EditorProperty].
+ Adds an editor that allows modifying multiple properties. The [param editor] control must extend [EditorProperty].
</description>
</method>
</methods>
diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml
index cc2f33ce89..49cd715f5e 100644
--- a/doc/classes/EditorInterface.xml
+++ b/doc/classes/EditorInterface.xml
@@ -12,24 +12,24 @@
<methods>
<method name="edit_node">
<return type="void" />
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
Edits the given [Node]. The node will be also selected if it's inside the scene tree.
</description>
</method>
<method name="edit_resource">
<return type="void" />
- <argument index="0" name="resource" type="Resource" />
+ <param index="0" name="resource" type="Resource" />
<description>
Edits the given [Resource]. If the resource is a [Script] you can also edit it with [method edit_script] to specify the line and column position.
</description>
</method>
<method name="edit_script">
<return type="void" />
- <argument index="0" name="script" type="Script" />
- <argument index="1" name="line" type="int" default="-1" />
- <argument index="2" name="column" type="int" default="0" />
- <argument index="3" name="grab_focus" type="bool" default="true" />
+ <param index="0" name="script" type="Script" />
+ <param index="1" name="line" type="int" default="-1" />
+ <param index="2" name="column" type="int" default="0" />
+ <param index="3" name="grab_focus" type="bool" default="true" />
<description>
Edits the given [Script]. The line and column on which to open the script can also be specified. The script will be open with the user-configured editor for the script's language which may be an external editor.
</description>
@@ -101,7 +101,7 @@
</description>
</method>
<method name="get_open_scenes" qualifiers="const">
- <return type="Array" />
+ <return type="PackedStringArray" />
<description>
Returns an [Array] with the file paths of the currently opened scenes.
</description>
@@ -145,11 +145,11 @@
</method>
<method name="inspect_object">
<return type="void" />
- <argument index="0" name="object" type="Object" />
- <argument index="1" name="for_property" type="String" default="&quot;&quot;" />
- <argument index="2" name="inspector_only" type="bool" default="false" />
+ <param index="0" name="object" type="Object" />
+ <param index="1" name="for_property" type="String" default="&quot;&quot;" />
+ <param index="2" name="inspector_only" type="bool" default="false" />
<description>
- Shows the given property on the given [code]object[/code] in the editor's Inspector dock. If [code]inspector_only[/code] is [code]true[/code], plugins will not attempt to edit [code]object[/code].
+ Shows the given property on the given [param object] in the editor's Inspector dock. If [param inspector_only] is [code]true[/code], plugins will not attempt to edit [param object].
</description>
</method>
<method name="is_playing_scene" qualifiers="const">
@@ -160,22 +160,22 @@
</method>
<method name="is_plugin_enabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="plugin" type="String" />
+ <param index="0" name="plugin" type="String" />
<description>
- Returns [code]true[/code] if the specified [code]plugin[/code] is enabled. The plugin name is the same as its directory name.
+ Returns [code]true[/code] if the specified [param plugin] is enabled. The plugin name is the same as its directory name.
</description>
</method>
<method name="make_mesh_previews">
- <return type="Array" />
- <argument index="0" name="meshes" type="Array" />
- <argument index="1" name="preview_size" type="int" />
+ <return type="Texture2D[]" />
+ <param index="0" name="meshes" type="Array" />
+ <param index="1" name="preview_size" type="int" />
<description>
Returns mesh previews rendered at the given size as an [Array] of [Texture2D]s.
</description>
</method>
<method name="open_scene_from_path">
<return type="void" />
- <argument index="0" name="scene_filepath" type="String" />
+ <param index="0" name="scene_filepath" type="String" />
<description>
Opens the scene at the given path.
</description>
@@ -188,7 +188,7 @@
</method>
<method name="play_custom_scene">
<return type="void" />
- <argument index="0" name="scene_filepath" type="String" />
+ <param index="0" name="scene_filepath" type="String" />
<description>
Plays the scene specified by its filepath.
</description>
@@ -201,11 +201,18 @@
</method>
<method name="reload_scene_from_path">
<return type="void" />
- <argument index="0" name="scene_filepath" type="String" />
+ <param index="0" name="scene_filepath" type="String" />
<description>
Reloads the scene at the given path.
</description>
</method>
+ <method name="restart_editor">
+ <return type="void" />
+ <param index="0" name="save" type="bool" default="true" />
+ <description>
+ Restarts the editor. This closes the editor and then opens the same project. If [param save] is [code]true[/code], the project will be saved before restarting.
+ </description>
+ </method>
<method name="save_scene">
<return type="int" enum="Error" />
<description>
@@ -214,30 +221,30 @@
</method>
<method name="save_scene_as">
<return type="void" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="with_preview" type="bool" default="true" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="with_preview" type="bool" default="true" />
<description>
- Saves the scene as a file at [code]path[/code].
+ Saves the scene as a file at [param path].
</description>
</method>
<method name="select_file">
<return type="void" />
- <argument index="0" name="file" type="String" />
+ <param index="0" name="file" type="String" />
<description>
- Selects the file, with the path provided by [code]file[/code], in the FileSystem dock.
+ Selects the file, with the path provided by [param file], in the FileSystem dock.
</description>
</method>
<method name="set_main_screen_editor">
<return type="void" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
- Sets the editor's current main screen to the one specified in [code]name[/code]. [code]name[/code] must match the text of the tab in question exactly ([code]2D[/code], [code]3D[/code], [code]Script[/code], [code]AssetLib[/code]).
+ Sets the editor's current main screen to the one specified in [param name]. [param name] must match the text of the tab in question exactly ([code]2D[/code], [code]3D[/code], [code]Script[/code], [code]AssetLib[/code]).
</description>
</method>
<method name="set_plugin_enabled">
<return type="void" />
- <argument index="0" name="plugin" type="String" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="plugin" type="String" />
+ <param index="1" name="enabled" type="bool" />
<description>
Sets the enabled status of a plugin. The plugin name is the same as its directory name.
</description>
diff --git a/doc/classes/EditorNode3DGizmo.xml b/doc/classes/EditorNode3DGizmo.xml
index 2eec5310dc..9ee21fd63b 100644
--- a/doc/classes/EditorNode3DGizmo.xml
+++ b/doc/classes/EditorNode3DGizmo.xml
@@ -11,58 +11,58 @@
<methods>
<method name="_commit_handle" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="secondary" type="bool" />
- <argument index="2" name="restore" type="Variant" />
- <argument index="3" name="cancel" type="bool" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="secondary" type="bool" />
+ <param index="2" name="restore" type="Variant" />
+ <param index="3" name="cancel" type="bool" />
<description>
- Override this method to commit a handle being edited (handles must have been previously added by [method add_handles]). This usually means creating an [UndoRedo] action for the change, using the current handle value as "do" and the [code]restore[/code] argument as "undo".
- If the [code]cancel[/code] argument is [code]true[/code], the [code]restore[/code] value should be directly set, without any [UndoRedo] action.
- The [code]secondary[/code] argument is [code]true[/code] when the committed handle is secondary (see [method add_handles] for more information).
+ Override this method to commit a handle being edited (handles must have been previously added by [method add_handles]). This usually means creating an [UndoRedo] action for the change, using the current handle value as "do" and the [param restore] argument as "undo".
+ If the [param cancel] argument is [code]true[/code], the [param restore] value should be directly set, without any [UndoRedo] action.
+ The [param secondary] argument is [code]true[/code] when the committed handle is secondary (see [method add_handles] for more information).
</description>
</method>
<method name="_commit_subgizmos" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="ids" type="PackedInt32Array" />
- <argument index="1" name="restores" type="Transform3D[]" />
- <argument index="2" name="cancel" type="bool" />
+ <param index="0" name="ids" type="PackedInt32Array" />
+ <param index="1" name="restores" type="Transform3D[]" />
+ <param index="2" name="cancel" type="bool" />
<description>
- Override this method to commit a group of subgizmos being edited (see [method _subgizmos_intersect_ray] and [method _subgizmos_intersect_frustum]). This usually means creating an [UndoRedo] action for the change, using the current transforms as "do" and the [code]restore[/code] transforms as "undo".
- If the [code]cancel[/code] argument is [code]true[/code], the [code]restore[/code] transforms should be directly set, without any [UndoRedo] action.
+ Override this method to commit a group of subgizmos being edited (see [method _subgizmos_intersect_ray] and [method _subgizmos_intersect_frustum]). This usually means creating an [UndoRedo] action for the change, using the current transforms as "do" and the [param restores] transforms as "undo".
+ If the [param cancel] argument is [code]true[/code], the [param restores] transforms should be directly set, without any [UndoRedo] action.
</description>
</method>
<method name="_get_handle_name" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="secondary" type="bool" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="secondary" type="bool" />
<description>
Override this method to return the name of an edited handle (handles must have been previously added by [method add_handles]). Handles can be named for reference to the user when editing.
- The [code]secondary[/code] argument is [code]true[/code] when the requested handle is secondary (see [method add_handles] for more information).
+ The [param secondary] argument is [code]true[/code] when the requested handle is secondary (see [method add_handles] for more information).
</description>
</method>
<method name="_get_handle_value" qualifiers="virtual const">
<return type="Variant" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="secondary" type="bool" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="secondary" type="bool" />
<description>
Override this method to return the current value of a handle. This value will be requested at the start of an edit and used as the [code]restore[/code] argument in [method _commit_handle].
- The [code]secondary[/code] argument is [code]true[/code] when the requested handle is secondary (see [method add_handles] for more information).
+ The [param secondary] argument is [code]true[/code] when the requested handle is secondary (see [method add_handles] for more information).
</description>
</method>
<method name="_get_subgizmo_transform" qualifiers="virtual const">
<return type="Transform3D" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Override this method to return the current transform of a subgizmo. This transform will be requested at the start of an edit and used as the [code]restore[/code] argument in [method _commit_subgizmos].
</description>
</method>
<method name="_is_handle_highlighted" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="secondary" type="bool" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="secondary" type="bool" />
<description>
Override this method to return [code]true[/code] whenever the given handle should be highlighted in the editor.
- The [code]secondary[/code] argument is [code]true[/code] when the requested handle is secondary (see [method add_handles] for more information).
+ The [param secondary] argument is [code]true[/code] when the requested handle is secondary (see [method add_handles] for more information).
</description>
</method>
<method name="_redraw" qualifiers="virtual">
@@ -73,91 +73,91 @@
</method>
<method name="_set_handle" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="secondary" type="bool" />
- <argument index="2" name="camera" type="Camera3D" />
- <argument index="3" name="point" type="Vector2" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="secondary" type="bool" />
+ <param index="2" name="camera" type="Camera3D" />
+ <param index="3" name="point" type="Vector2" />
<description>
- Override this method to update the node properties when the user drags a gizmo handle (previously added with [method add_handles]). The provided [code]point[/code] is the mouse position in screen coordinates and the [code]camera[/code] can be used to convert it to raycasts.
- The [code]secondary[/code] argument is [code]true[/code] when the edited handle is secondary (see [method add_handles] for more information).
+ Override this method to update the node properties when the user drags a gizmo handle (previously added with [method add_handles]). The provided [param point] is the mouse position in screen coordinates and the [param camera] can be used to convert it to raycasts.
+ The [param secondary] argument is [code]true[/code] when the edited handle is secondary (see [method add_handles] for more information).
</description>
</method>
<method name="_set_subgizmo_transform" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="transform" type="Transform3D" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="transform" type="Transform3D" />
<description>
- Override this method to update the node properties during subgizmo editing (see [method _subgizmos_intersect_ray] and [method _subgizmos_intersect_frustum]). The [code]transform[/code] is given in the Node3D's local coordinate system.
+ Override this method to update the node properties during subgizmo editing (see [method _subgizmos_intersect_ray] and [method _subgizmos_intersect_frustum]). The [param transform] is given in the Node3D's local coordinate system.
</description>
</method>
<method name="_subgizmos_intersect_frustum" qualifiers="virtual const">
<return type="PackedInt32Array" />
- <argument index="0" name="camera" type="Camera3D" />
- <argument index="1" name="frustum" type="Plane[]" />
+ <param index="0" name="camera" type="Camera3D" />
+ <param index="1" name="frustum" type="Plane[]" />
<description>
- Override this method to allow selecting subgizmos using mouse drag box selection. Given a [code]camera[/code] and a [code]frustum[/code], this method should return which subgizmos are contained within the frustum. The [code]frustum[/code] argument consists of an [code]Array[/code] with all the [code]Plane[/code]s that make up the selection frustum. The returned value should contain a list of unique subgizmo identifiers, which can have any non-negative value and will be used in other virtual methods like [method _get_subgizmo_transform] or [method _commit_subgizmos].
+ Override this method to allow selecting subgizmos using mouse drag box selection. Given a [param camera] and a [param frustum], this method should return which subgizmos are contained within the frustum. The [param frustum] argument consists of an [code]Array[/code] with all the [code]Plane[/code]s that make up the selection frustum. The returned value should contain a list of unique subgizmo identifiers, which can have any non-negative value and will be used in other virtual methods like [method _get_subgizmo_transform] or [method _commit_subgizmos].
</description>
</method>
<method name="_subgizmos_intersect_ray" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="camera" type="Camera3D" />
- <argument index="1" name="point" type="Vector2" />
+ <param index="0" name="camera" type="Camera3D" />
+ <param index="1" name="point" type="Vector2" />
<description>
- Override this method to allow selecting subgizmos using mouse clicks. Given a [code]camera[/code] and a [code]point[/code] in screen coordinates, this method should return which subgizmo should be selected. The returned value should be a unique subgizmo identifier, which can have any non-negative value and will be used in other virtual methods like [method _get_subgizmo_transform] or [method _commit_subgizmos].
+ Override this method to allow selecting subgizmos using mouse clicks. Given a [param camera] and a [param point] in screen coordinates, this method should return which subgizmo should be selected. The returned value should be a unique subgizmo identifier, which can have any non-negative value and will be used in other virtual methods like [method _get_subgizmo_transform] or [method _commit_subgizmos].
</description>
</method>
<method name="add_collision_segments">
<return type="void" />
- <argument index="0" name="segments" type="PackedVector3Array" />
+ <param index="0" name="segments" type="PackedVector3Array" />
<description>
- Adds the specified [code]segments[/code] to the gizmo's collision shape for picking. Call this method during [method _redraw].
+ Adds the specified [param segments] to the gizmo's collision shape for picking. Call this method during [method _redraw].
</description>
</method>
<method name="add_collision_triangles">
<return type="void" />
- <argument index="0" name="triangles" type="TriangleMesh" />
+ <param index="0" name="triangles" type="TriangleMesh" />
<description>
Adds collision triangles to the gizmo for picking. A [TriangleMesh] can be generated from a regular [Mesh] too. Call this method during [method _redraw].
</description>
</method>
<method name="add_handles">
<return type="void" />
- <argument index="0" name="handles" type="PackedVector3Array" />
- <argument index="1" name="material" type="Material" />
- <argument index="2" name="ids" type="PackedInt32Array" />
- <argument index="3" name="billboard" type="bool" default="false" />
- <argument index="4" name="secondary" type="bool" default="false" />
- <description>
- Adds a list of handles (points) which can be used to edit the properties of the gizmo's Node3D. The [code]ids[/code] argument can be used to specify a custom identifier for each handle, if an empty [code]Array[/code] is passed, the ids will be assigned automatically from the [code]handles[/code] argument order.
- The [code]secondary[/code] argument marks the added handles as secondary, meaning they will normally have less selection priority than regular handles. When the user is holding the shift key secondary handles will switch to have higher priority than regular handles. This change in priority can be used to place multiple handles at the same point while still giving the user control on their selection.
+ <param index="0" name="handles" type="PackedVector3Array" />
+ <param index="1" name="material" type="Material" />
+ <param index="2" name="ids" type="PackedInt32Array" />
+ <param index="3" name="billboard" type="bool" default="false" />
+ <param index="4" name="secondary" type="bool" default="false" />
+ <description>
+ Adds a list of handles (points) which can be used to edit the properties of the gizmo's Node3D. The [param ids] argument can be used to specify a custom identifier for each handle, if an empty [code]Array[/code] is passed, the ids will be assigned automatically from the [param handles] argument order.
+ The [param secondary] argument marks the added handles as secondary, meaning they will normally have lower selection priority than regular handles. When the user is holding the shift key secondary handles will switch to have higher priority than regular handles. This change in priority can be used to place multiple handles at the same point while still giving the user control on their selection.
There are virtual methods which will be called upon editing of these handles. Call this method during [method _redraw].
</description>
</method>
<method name="add_lines">
<return type="void" />
- <argument index="0" name="lines" type="PackedVector3Array" />
- <argument index="1" name="material" type="Material" />
- <argument index="2" name="billboard" type="bool" default="false" />
- <argument index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="0" name="lines" type="PackedVector3Array" />
+ <param index="1" name="material" type="Material" />
+ <param index="2" name="billboard" type="bool" default="false" />
+ <param index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
<description>
Adds lines to the gizmo (as sets of 2 points), with a given material. The lines are used for visualizing the gizmo. Call this method during [method _redraw].
</description>
</method>
<method name="add_mesh">
<return type="void" />
- <argument index="0" name="mesh" type="Mesh" />
- <argument index="1" name="material" type="Material" default="null" />
- <argument index="2" name="transform" type="Transform3D" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)" />
- <argument index="3" name="skeleton" type="SkinReference" default="null" />
+ <param index="0" name="mesh" type="Mesh" />
+ <param index="1" name="material" type="Material" default="null" />
+ <param index="2" name="transform" type="Transform3D" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)" />
+ <param index="3" name="skeleton" type="SkinReference" default="null" />
<description>
- Adds a mesh to the gizmo with the specified [code]material[/code], local [code]transform[/code] and [code]skeleton[/code]. Call this method during [method _redraw].
+ Adds a mesh to the gizmo with the specified [param material], local [param transform] and [param skeleton]. Call this method during [method _redraw].
</description>
</method>
<method name="add_unscaled_billboard">
<return type="void" />
- <argument index="0" name="material" type="Material" />
- <argument index="1" name="default_scale" type="float" default="1" />
- <argument index="2" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="0" name="material" type="Material" />
+ <param index="1" name="default_scale" type="float" default="1" />
+ <param index="2" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
<description>
Adds an unscaled billboard for visualization and selection. Call this method during [method _redraw].
</description>
@@ -188,23 +188,23 @@
</method>
<method name="is_subgizmo_selected" qualifiers="const">
<return type="bool" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Returns [code]true[/code] if the given subgizmo is currently selected. Can be used to highlight selected elements during [method _redraw].
</description>
</method>
<method name="set_hidden">
<return type="void" />
- <argument index="0" name="hidden" type="bool" />
+ <param index="0" name="hidden" type="bool" />
<description>
Sets the gizmo's hidden state. If [code]true[/code], the gizmo will be hidden. If [code]false[/code], it will be shown.
</description>
</method>
<method name="set_spatial_node">
<return type="void" />
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
- Sets the reference [Node3D] node for the gizmo. [code]node[/code] must inherit from [Node3D].
+ Sets the reference [Node3D] node for the gizmo. [param node] must inherit from [Node3D].
</description>
</method>
</methods>
diff --git a/doc/classes/EditorNode3DGizmoPlugin.xml b/doc/classes/EditorNode3DGizmoPlugin.xml
index d194786131..8a97dda9ae 100644
--- a/doc/classes/EditorNode3DGizmoPlugin.xml
+++ b/doc/classes/EditorNode3DGizmoPlugin.xml
@@ -19,32 +19,32 @@
</method>
<method name="_commit_handle" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="gizmo" type="EditorNode3DGizmo" />
- <argument index="1" name="handle_id" type="int" />
- <argument index="2" name="secondary" type="bool" />
- <argument index="3" name="restore" type="Variant" />
- <argument index="4" name="cancel" type="bool" />
- <description>
- Override this method to commit a handle being edited (handles must have been previously added by [method EditorNode3DGizmo.add_handles] during [method _redraw]). This usually means creating an [UndoRedo] action for the change, using the current handle value as "do" and the [code]restore[/code] argument as "undo".
- If the [code]cancel[/code] argument is [code]true[/code], the [code]restore[/code] value should be directly set, without any [UndoRedo] action.
- The [code]secondary[/code] argument is [code]true[/code] when the committed handle is secondary (see [method EditorNode3DGizmo.add_handles] for more information).
+ <param index="0" name="gizmo" type="EditorNode3DGizmo" />
+ <param index="1" name="handle_id" type="int" />
+ <param index="2" name="secondary" type="bool" />
+ <param index="3" name="restore" type="Variant" />
+ <param index="4" name="cancel" type="bool" />
+ <description>
+ Override this method to commit a handle being edited (handles must have been previously added by [method EditorNode3DGizmo.add_handles] during [method _redraw]). This usually means creating an [UndoRedo] action for the change, using the current handle value as "do" and the [param restore] argument as "undo".
+ If the [param cancel] argument is [code]true[/code], the [param restore] value should be directly set, without any [UndoRedo] action.
+ The [param secondary] argument is [code]true[/code] when the committed handle is secondary (see [method EditorNode3DGizmo.add_handles] for more information).
Called for this plugin's active gizmos.
</description>
</method>
<method name="_commit_subgizmos" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="gizmo" type="EditorNode3DGizmo" />
- <argument index="1" name="ids" type="PackedInt32Array" />
- <argument index="2" name="restores" type="Transform3D[]" />
- <argument index="3" name="cancel" type="bool" />
+ <param index="0" name="gizmo" type="EditorNode3DGizmo" />
+ <param index="1" name="ids" type="PackedInt32Array" />
+ <param index="2" name="restores" type="Transform3D[]" />
+ <param index="3" name="cancel" type="bool" />
<description>
- Override this method to commit a group of subgizmos being edited (see [method _subgizmos_intersect_ray] and [method _subgizmos_intersect_frustum]). This usually means creating an [UndoRedo] action for the change, using the current transforms as "do" and the [code]restore[/code] transforms as "undo".
- If the [code]cancel[/code] argument is [code]true[/code], the [code]restore[/code] transforms should be directly set, without any [UndoRedo] action. As with all subgizmo methods, transforms are given in local space respect to the gizmo's Node3D. Called for this plugin's active gizmos.
+ Override this method to commit a group of subgizmos being edited (see [method _subgizmos_intersect_ray] and [method _subgizmos_intersect_frustum]). This usually means creating an [UndoRedo] action for the change, using the current transforms as "do" and the [param restores] transforms as "undo".
+ If the [param cancel] argument is [code]true[/code], the [param restores] transforms should be directly set, without any [UndoRedo] action. As with all subgizmo methods, transforms are given in local space respect to the gizmo's Node3D. Called for this plugin's active gizmos.
</description>
</method>
<method name="_create_gizmo" qualifiers="virtual const">
<return type="EditorNode3DGizmo" />
- <argument index="0" name="for_node_3d" type="Node3D" />
+ <param index="0" name="for_node_3d" type="Node3D" />
<description>
Override this method to return a custom [EditorNode3DGizmo] for the spatial nodes of your choice, return [code]null[/code] for the rest of nodes. See also [method _has_gizmo].
</description>
@@ -57,21 +57,21 @@
</method>
<method name="_get_handle_name" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="gizmo" type="EditorNode3DGizmo" />
- <argument index="1" name="handle_id" type="int" />
- <argument index="2" name="secondary" type="bool" />
+ <param index="0" name="gizmo" type="EditorNode3DGizmo" />
+ <param index="1" name="handle_id" type="int" />
+ <param index="2" name="secondary" type="bool" />
<description>
- Override this method to provide gizmo's handle names. The [code]secondary[/code] argument is [code]true[/code] when the requested handle is secondary (see [method EditorNode3DGizmo.add_handles] for more information). Called for this plugin's active gizmos.
+ Override this method to provide gizmo's handle names. The [param secondary] argument is [code]true[/code] when the requested handle is secondary (see [method EditorNode3DGizmo.add_handles] for more information). Called for this plugin's active gizmos.
</description>
</method>
<method name="_get_handle_value" qualifiers="virtual const">
<return type="Variant" />
- <argument index="0" name="gizmo" type="EditorNode3DGizmo" />
- <argument index="1" name="handle_id" type="int" />
- <argument index="2" name="secondary" type="bool" />
+ <param index="0" name="gizmo" type="EditorNode3DGizmo" />
+ <param index="1" name="handle_id" type="int" />
+ <param index="2" name="secondary" type="bool" />
<description>
Override this method to return the current value of a handle. This value will be requested at the start of an edit and used as the [code]restore[/code] argument in [method _commit_handle].
- The [code]secondary[/code] argument is [code]true[/code] when the requested handle is secondary (see [method EditorNode3DGizmo.add_handles] for more information).
+ The [param secondary] argument is [code]true[/code] when the requested handle is secondary (see [method EditorNode3DGizmo.add_handles] for more information).
Called for this plugin's active gizmos.
</description>
</method>
@@ -84,26 +84,26 @@
</method>
<method name="_get_subgizmo_transform" qualifiers="virtual const">
<return type="Transform3D" />
- <argument index="0" name="gizmo" type="EditorNode3DGizmo" />
- <argument index="1" name="subgizmo_id" type="int" />
+ <param index="0" name="gizmo" type="EditorNode3DGizmo" />
+ <param index="1" name="subgizmo_id" type="int" />
<description>
Override this method to return the current transform of a subgizmo. As with all subgizmo methods, the transform should be in local space respect to the gizmo's Node3D. This transform will be requested at the start of an edit and used in the [code]restore[/code] argument in [method _commit_subgizmos]. Called for this plugin's active gizmos.
</description>
</method>
<method name="_has_gizmo" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="for_node_3d" type="Node3D" />
+ <param index="0" name="for_node_3d" type="Node3D" />
<description>
Override this method to define which Node3D nodes have a gizmo from this plugin. Whenever a [Node3D] node is added to a scene this method is called, if it returns [code]true[/code] the node gets a generic [EditorNode3DGizmo] assigned and is added to this plugin's list of active gizmos.
</description>
</method>
<method name="_is_handle_highlighted" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="gizmo" type="EditorNode3DGizmo" />
- <argument index="1" name="handle_id" type="int" />
- <argument index="2" name="secondary" type="bool" />
+ <param index="0" name="gizmo" type="EditorNode3DGizmo" />
+ <param index="1" name="handle_id" type="int" />
+ <param index="2" name="secondary" type="bool" />
<description>
- Override this method to return [code]true[/code] whenever to given handle should be highlighted in the editor. The [code]secondary[/code] argument is [code]true[/code] when the requested handle is secondary (see [method EditorNode3DGizmo.add_handles] for more information). Called for this plugin's active gizmos.
+ Override this method to return [code]true[/code] whenever to given handle should be highlighted in the editor. The [param secondary] argument is [code]true[/code] when the requested handle is secondary (see [method EditorNode3DGizmo.add_handles] for more information). Called for this plugin's active gizmos.
</description>
</method>
<method name="_is_selectable_when_hidden" qualifiers="virtual const">
@@ -114,64 +114,64 @@
</method>
<method name="_redraw" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="gizmo" type="EditorNode3DGizmo" />
+ <param index="0" name="gizmo" type="EditorNode3DGizmo" />
<description>
Override this method to add all the gizmo elements whenever a gizmo update is requested. It's common to call [method EditorNode3DGizmo.clear] at the beginning of this method and then add visual elements depending on the node's properties.
</description>
</method>
<method name="_set_handle" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="gizmo" type="EditorNode3DGizmo" />
- <argument index="1" name="handle_id" type="int" />
- <argument index="2" name="secondary" type="bool" />
- <argument index="3" name="camera" type="Camera3D" />
- <argument index="4" name="screen_pos" type="Vector2" />
- <description>
- Override this method to update the node's properties when the user drags a gizmo handle (previously added with [method EditorNode3DGizmo.add_handles]). The provided [code]point[/code] is the mouse position in screen coordinates and the [code]camera[/code] can be used to convert it to raycasts.
- The [code]secondary[/code] argument is [code]true[/code] when the edited handle is secondary (see [method EditorNode3DGizmo.add_handles] for more information).
+ <param index="0" name="gizmo" type="EditorNode3DGizmo" />
+ <param index="1" name="handle_id" type="int" />
+ <param index="2" name="secondary" type="bool" />
+ <param index="3" name="camera" type="Camera3D" />
+ <param index="4" name="screen_pos" type="Vector2" />
+ <description>
+ Override this method to update the node's properties when the user drags a gizmo handle (previously added with [method EditorNode3DGizmo.add_handles]). The provided [param screen_pos] is the mouse position in screen coordinates and the [param camera] can be used to convert it to raycasts.
+ The [param secondary] argument is [code]true[/code] when the edited handle is secondary (see [method EditorNode3DGizmo.add_handles] for more information).
Called for this plugin's active gizmos.
</description>
</method>
<method name="_set_subgizmo_transform" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="gizmo" type="EditorNode3DGizmo" />
- <argument index="1" name="subgizmo_id" type="int" />
- <argument index="2" name="transform" type="Transform3D" />
+ <param index="0" name="gizmo" type="EditorNode3DGizmo" />
+ <param index="1" name="subgizmo_id" type="int" />
+ <param index="2" name="transform" type="Transform3D" />
<description>
- Override this method to update the node properties during subgizmo editing (see [method _subgizmos_intersect_ray] and [method _subgizmos_intersect_frustum]). The [code]transform[/code] is given in the Node3D's local coordinate system. Called for this plugin's active gizmos.
+ Override this method to update the node properties during subgizmo editing (see [method _subgizmos_intersect_ray] and [method _subgizmos_intersect_frustum]). The [param transform] is given in the Node3D's local coordinate system. Called for this plugin's active gizmos.
</description>
</method>
<method name="_subgizmos_intersect_frustum" qualifiers="virtual const">
<return type="PackedInt32Array" />
- <argument index="0" name="gizmo" type="EditorNode3DGizmo" />
- <argument index="1" name="camera" type="Camera3D" />
- <argument index="2" name="frustum_planes" type="Plane[]" />
+ <param index="0" name="gizmo" type="EditorNode3DGizmo" />
+ <param index="1" name="camera" type="Camera3D" />
+ <param index="2" name="frustum_planes" type="Plane[]" />
<description>
- Override this method to allow selecting subgizmos using mouse drag box selection. Given a [code]camera[/code] and a [code]frustum[/code], this method should return which subgizmos are contained within the frustum. The [code]frustum[/code] argument consists of an [code]Array[/code] with all the [code]Plane[/code]s that make up the selection frustum. The returned value should contain a list of unique subgizmo identifiers, these identifiers can have any non-negative value and will be used in other virtual methods like [method _get_subgizmo_transform] or [method _commit_subgizmos]. Called for this plugin's active gizmos.
+ Override this method to allow selecting subgizmos using mouse drag box selection. Given a [param camera] and [param frustum_planes], this method should return which subgizmos are contained within the frustums. The [param frustum_planes] argument consists of an [code]Array[/code] with all the [code]Plane[/code]s that make up the selection frustum. The returned value should contain a list of unique subgizmo identifiers, these identifiers can have any non-negative value and will be used in other virtual methods like [method _get_subgizmo_transform] or [method _commit_subgizmos]. Called for this plugin's active gizmos.
</description>
</method>
<method name="_subgizmos_intersect_ray" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="gizmo" type="EditorNode3DGizmo" />
- <argument index="1" name="camera" type="Camera3D" />
- <argument index="2" name="screen_pos" type="Vector2" />
+ <param index="0" name="gizmo" type="EditorNode3DGizmo" />
+ <param index="1" name="camera" type="Camera3D" />
+ <param index="2" name="screen_pos" type="Vector2" />
<description>
- Override this method to allow selecting subgizmos using mouse clicks. Given a [code]camera[/code] and a [code]point[/code] in screen coordinates, this method should return which subgizmo should be selected. The returned value should be a unique subgizmo identifier, which can have any non-negative value and will be used in other virtual methods like [method _get_subgizmo_transform] or [method _commit_subgizmos]. Called for this plugin's active gizmos.
+ Override this method to allow selecting subgizmos using mouse clicks. Given a [param camera] and a [param screen_pos] in screen coordinates, this method should return which subgizmo should be selected. The returned value should be a unique subgizmo identifier, which can have any non-negative value and will be used in other virtual methods like [method _get_subgizmo_transform] or [method _commit_subgizmos]. Called for this plugin's active gizmos.
</description>
</method>
<method name="add_material">
<return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="material" type="StandardMaterial3D" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="material" type="StandardMaterial3D" />
<description>
Adds a new material to the internal material list for the plugin. It can then be accessed with [method get_material]. Should not be overridden.
</description>
</method>
<method name="create_handle_material">
<return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="billboard" type="bool" default="false" />
- <argument index="2" name="texture" type="Texture2D" default="null" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="billboard" type="bool" default="false" />
+ <param index="2" name="texture" type="Texture2D" default="null" />
<description>
Creates a handle material with its variants (selected and/or editable) and adds them to the internal material list. They can then be accessed with [method get_material] and used in [method EditorNode3DGizmo.add_handles]. Should not be overridden.
You can optionally provide a texture to use instead of the default icon.
@@ -179,29 +179,29 @@
</method>
<method name="create_icon_material">
<return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="texture" type="Texture2D" />
- <argument index="2" name="on_top" type="bool" default="false" />
- <argument index="3" name="color" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="texture" type="Texture2D" />
+ <param index="2" name="on_top" type="bool" default="false" />
+ <param index="3" name="color" type="Color" default="Color(1, 1, 1, 1)" />
<description>
Creates an icon material with its variants (selected and/or editable) and adds them to the internal material list. They can then be accessed with [method get_material] and used in [method EditorNode3DGizmo.add_unscaled_billboard]. Should not be overridden.
</description>
</method>
<method name="create_material">
<return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="color" type="Color" />
- <argument index="2" name="billboard" type="bool" default="false" />
- <argument index="3" name="on_top" type="bool" default="false" />
- <argument index="4" name="use_vertex_color" type="bool" default="false" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="color" type="Color" />
+ <param index="2" name="billboard" type="bool" default="false" />
+ <param index="3" name="on_top" type="bool" default="false" />
+ <param index="4" name="use_vertex_color" type="bool" default="false" />
<description>
Creates an unshaded material with its variants (selected and/or editable) and adds them to the internal material list. They can then be accessed with [method get_material] and used in [method EditorNode3DGizmo.add_mesh] and [method EditorNode3DGizmo.add_lines]. Should not be overridden.
</description>
</method>
<method name="get_material">
<return type="StandardMaterial3D" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="gizmo" type="EditorNode3DGizmo" default="null" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="gizmo" type="EditorNode3DGizmo" default="null" />
<description>
Gets material from the internal list of materials. If an [EditorNode3DGizmo] is provided, it will try to get the corresponding variant (selected and/or editable).
</description>
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index 2930c2ec22..fdd3807b69 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -38,7 +38,7 @@
</method>
<method name="_edit" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="object" type="Variant" />
+ <param index="0" name="object" type="Variant" />
<description>
This function is used for plugins that edit specific object types (nodes or resources). It requests the editor to edit the given object.
</description>
@@ -51,7 +51,7 @@
</method>
<method name="_forward_3d_draw_over_viewport" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="viewport_control" type="Control" />
+ <param index="0" name="viewport_control" type="Control" />
<description>
Called by the engine when the 3D editor's viewport is updated. Use the [code]overlay[/code] [Control] for drawing. You can update the viewport manually by calling [method update_overlays].
[codeblocks]
@@ -89,7 +89,7 @@
</method>
<method name="_forward_3d_force_draw_over_viewport" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="viewport_control" type="Control" />
+ <param index="0" name="viewport_control" type="Control" />
<description>
This method is the same as [method _forward_3d_draw_over_viewport], except it draws on top of everything. Useful when you need an extra layer that shows over anything else.
You need to enable calling of this method by using [method set_force_draw_over_forwarding_enabled].
@@ -97,10 +97,10 @@
</method>
<method name="_forward_3d_gui_input" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="viewport_camera" type="Camera3D" />
- <argument index="1" name="event" type="InputEvent" />
+ <param index="0" name="viewport_camera" type="Camera3D" />
+ <param index="1" name="event" type="InputEvent" />
<description>
- Called when there is a root node in the current edited scene, [method _handles] is implemented and an [InputEvent] happens in the 3D viewport. Intercepts the [InputEvent], if [code]return true[/code] [EditorPlugin] consumes the [code]event[/code], otherwise forwards [code]event[/code] to other Editor classes. Example:
+ Called when there is a root node in the current edited scene, [method _handles] is implemented and an [InputEvent] happens in the 3D viewport. Intercepts the [InputEvent], if [code]return true[/code] [EditorPlugin] consumes the [param event], otherwise forwards [param event] to other Editor classes. Example:
[codeblocks]
[gdscript]
# Prevents the InputEvent to reach other Editor classes.
@@ -134,7 +134,7 @@
</method>
<method name="_forward_canvas_draw_over_viewport" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="viewport_control" type="Control" />
+ <param index="0" name="viewport_control" type="Control" />
<description>
Called by the engine when the 2D editor's viewport is updated. Use the [code]overlay[/code] [Control] for drawing. You can update the viewport manually by calling [method update_overlays].
[codeblocks]
@@ -172,7 +172,7 @@
</method>
<method name="_forward_canvas_force_draw_over_viewport" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="viewport_control" type="Control" />
+ <param index="0" name="viewport_control" type="Control" />
<description>
This method is the same as [method _forward_canvas_draw_over_viewport], except it draws on top of everything. Useful when you need an extra layer that shows over anything else.
You need to enable calling of this method by using [method set_force_draw_over_forwarding_enabled].
@@ -180,9 +180,9 @@
</method>
<method name="_forward_canvas_gui_input" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="event" type="InputEvent" />
+ <param index="0" name="event" type="InputEvent" />
<description>
- Called when there is a root node in the current edited scene, [method _handles] is implemented and an [InputEvent] happens in the 2D viewport. Intercepts the [InputEvent], if [code]return true[/code] [EditorPlugin] consumes the [code]event[/code], otherwise forwards [code]event[/code] to other Editor classes. Example:
+ Called when there is a root node in the current edited scene, [method _handles] is implemented and an [InputEvent] happens in the 2D viewport. Intercepts the [InputEvent], if [code]return true[/code] [EditorPlugin] consumes the [param event], otherwise forwards [param event] to other Editor classes. Example:
[codeblocks]
[gdscript]
# Prevents the InputEvent to reach other Editor classes.
@@ -274,7 +274,7 @@
</method>
<method name="_get_window_layout" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="configuration" type="ConfigFile" />
+ <param index="0" name="configuration" type="ConfigFile" />
<description>
Override this method to provide the GUI layout of the plugin or any other data you want to be stored. This is used to save the project's editor layout when [method queue_save_layout] is called or the editor layout was changed (for example changing the position of a dock). The data is stored in the [code]editor_layout.cfg[/code] file in the editor metadata directory.
Use [method _set_window_layout] to restore your saved layout.
@@ -287,7 +287,7 @@
</method>
<method name="_handles" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="object" type="Variant" />
+ <param index="0" name="object" type="Variant" />
<description>
Implement this function if your plugin edits a specific type of object (Resource or Node). If you return [code]true[/code], then you will get the functions [method _edit] and [method _make_visible] called when the editor requests them. If you have declared the methods [method _forward_canvas_gui_input] and [method _forward_3d_gui_input] these will be called too.
</description>
@@ -322,7 +322,7 @@
</method>
<method name="_make_visible" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="visible" type="bool" />
+ <param index="0" name="visible" type="bool" />
<description>
This function will be called when the editor is requested to become visible. It is used for plugins that edit a specific object type.
Remember that you have to manage the visibility of all your editor controls manually.
@@ -336,7 +336,7 @@
</method>
<method name="_set_state" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="state" type="Dictionary" />
+ <param index="0" name="state" type="Dictionary" />
<description>
Restore the state saved by [method _get_state]. This method is called when the current scene tab is changed in the editor.
[b]Note:[/b] Your plugin must implement [method _get_plugin_name], otherwise it will not be recognized and this method will not be called.
@@ -349,9 +349,9 @@
</method>
<method name="_set_window_layout" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="configuration" type="ConfigFile" />
+ <param index="0" name="configuration" type="ConfigFile" />
<description>
- Restore the plugin GUI layout and data saved by [method _get_window_layout]. This method is called for every plugin on editor startup. Use the provided [code]configuration[/code] file to read your saved data.
+ Restore the plugin GUI layout and data saved by [method _get_window_layout]. This method is called for every plugin on editor startup. Use the provided [param configuration] file to read your saved data.
[codeblock]
func _set_window_layout(configuration):
$Window.position = configuration.get_value("MyPlugin", "window_position", Vector2())
@@ -361,24 +361,24 @@
</method>
<method name="add_autoload_singleton">
<return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="path" type="String" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="path" type="String" />
<description>
- Adds a script at [code]path[/code] to the Autoload list as [code]name[/code].
+ Adds a script at [param path] to the Autoload list as [param name].
</description>
</method>
<method name="add_control_to_bottom_panel">
<return type="Button" />
- <argument index="0" name="control" type="Control" />
- <argument index="1" name="title" type="String" />
+ <param index="0" name="control" type="Control" />
+ <param index="1" name="title" type="String" />
<description>
Adds a control to the bottom panel (together with Output, Debug, Animation, etc). Returns a reference to the button added. It's up to you to hide/show the button when needed. When your plugin is deactivated, make sure to remove your custom control with [method remove_control_from_bottom_panel] and free it with [method Node.queue_free].
</description>
</method>
<method name="add_control_to_container">
<return type="void" />
- <argument index="0" name="container" type="int" enum="EditorPlugin.CustomControlContainer" />
- <argument index="1" name="control" type="Control" />
+ <param index="0" name="container" type="int" enum="EditorPlugin.CustomControlContainer" />
+ <param index="1" name="control" type="Control" />
<description>
Adds a custom control to a container (see [enum CustomControlContainer]). There are many locations where custom controls can be added in the editor UI.
Please remember that you have to manage the visibility of your custom controls yourself (and likely hide it after adding it).
@@ -387,8 +387,8 @@
</method>
<method name="add_control_to_dock">
<return type="void" />
- <argument index="0" name="slot" type="int" enum="EditorPlugin.DockSlot" />
- <argument index="1" name="control" type="Control" />
+ <param index="0" name="slot" type="int" enum="EditorPlugin.DockSlot" />
+ <param index="1" name="control" type="Control" />
<description>
Adds the control to a specific dock slot (see [enum DockSlot] for options).
If the dock is repositioned and as long as the plugin is active, the editor will save the dock position on further sessions.
@@ -397,10 +397,10 @@
</method>
<method name="add_custom_type">
<return type="void" />
- <argument index="0" name="type" type="String" />
- <argument index="1" name="base" type="String" />
- <argument index="2" name="script" type="Script" />
- <argument index="3" name="icon" type="Texture2D" />
+ <param index="0" name="type" type="String" />
+ <param index="1" name="base" type="String" />
+ <param index="2" name="script" type="Script" />
+ <param index="3" name="icon" type="Texture2D" />
<description>
Adds a custom type, which will appear in the list of nodes or resources. An icon can be optionally passed.
When a given node or resource is selected, the base type will be instantiated (e.g. "Node3D", "Control", "Resource"), then the script will be loaded and set to this object.
@@ -410,14 +410,14 @@
</method>
<method name="add_debugger_plugin">
<return type="void" />
- <argument index="0" name="script" type="Script" />
+ <param index="0" name="script" type="Script" />
<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" />
- <argument index="0" name="plugin" type="EditorExportPlugin" />
+ <param index="0" name="plugin" type="EditorExportPlugin" />
<description>
Registers a new [EditorExportPlugin]. Export plugins are used to perform tasks when the project is being exported.
See [method add_inspector_plugin] for an example of how to register a plugin.
@@ -425,18 +425,18 @@
</method>
<method name="add_import_plugin">
<return type="void" />
- <argument index="0" name="importer" type="EditorImportPlugin" />
- <argument index="1" name="first_priority" type="bool" default="false" />
+ <param index="0" name="importer" type="EditorImportPlugin" />
+ <param index="1" name="first_priority" type="bool" default="false" />
<description>
Registers a new [EditorImportPlugin]. Import plugins are used to import custom and unsupported assets as a custom [Resource] type.
- If [code]first_priority[/code] is [code]true[/code], the new import plugin is inserted first in the list and takes precedence over pre-existing plugins.
+ If [param first_priority] is [code]true[/code], the new import plugin is inserted first in the list and takes precedence over pre-existing plugins.
[b]Note:[/b] If you want to import custom 3D asset formats use [method add_scene_format_importer_plugin] instead.
See [method add_inspector_plugin] for an example of how to register a plugin.
</description>
</method>
<method name="add_inspector_plugin">
<return type="void" />
- <argument index="0" name="plugin" type="EditorInspectorPlugin" />
+ <param index="0" name="plugin" type="EditorInspectorPlugin" />
<description>
Registers a new [EditorInspectorPlugin]. Inspector plugins are used to extend [EditorInspector] and provide custom configuration tools for your object's properties.
[b]Note:[/b] Always use [method remove_inspector_plugin] to remove the registered [EditorInspectorPlugin] when your [EditorPlugin] is disabled to prevent leaks and an unexpected behavior.
@@ -456,25 +456,25 @@
</method>
<method name="add_scene_format_importer_plugin">
<return type="void" />
- <argument index="0" name="scene_format_importer" type="EditorSceneFormatImporter" />
- <argument index="1" name="first_priority" type="bool" default="false" />
+ <param index="0" name="scene_format_importer" type="EditorSceneFormatImporter" />
+ <param index="1" name="first_priority" type="bool" default="false" />
<description>
Registers a new [EditorSceneFormatImporter]. Scene importers are used to import custom 3D asset formats as scenes.
- If [code]first_priority[/code] is [code]true[/code], the new import plugin is inserted first in the list and takes precedence over pre-existing plugins.
+ If [param first_priority] is [code]true[/code], the new import plugin is inserted first in the list and takes precedence over pre-existing plugins.
</description>
</method>
<method name="add_scene_post_import_plugin">
<return type="void" />
- <argument index="0" name="scene_import_plugin" type="EditorScenePostImportPlugin" />
- <argument index="1" name="first_priority" type="bool" default="false" />
+ <param index="0" name="scene_import_plugin" type="EditorScenePostImportPlugin" />
+ <param index="1" name="first_priority" type="bool" default="false" />
<description>
Add a [EditorScenePostImportPlugin]. These plugins allow customizing the import process of 3D assets by adding new options to the import dialogs.
- If [code]first_priority[/code] is [code]true[/code], the new import plugin is inserted first in the list and takes precedence over pre-existing plugins.
+ If [param first_priority] is [code]true[/code], the new import plugin is inserted first in the list and takes precedence over pre-existing plugins.
</description>
</method>
<method name="add_spatial_gizmo_plugin">
<return type="void" />
- <argument index="0" name="plugin" type="EditorNode3DGizmoPlugin" />
+ <param index="0" name="plugin" type="EditorNode3DGizmoPlugin" />
<description>
Registers a new [EditorNode3DGizmoPlugin]. Gizmo plugins are used to add custom gizmos to the 3D preview viewport for a [Node3D].
See [method add_inspector_plugin] for an example of how to register a plugin.
@@ -482,30 +482,30 @@
</method>
<method name="add_tool_menu_item">
<return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="callable" type="Callable" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="callable" type="Callable" />
<description>
- Adds a custom menu item to [b]Project &gt; Tools[/b] named [code]name[/code]. When clicked, the provided [code]callable[/code] will be called.
+ Adds a custom menu item to [b]Project &gt; Tools[/b] named [param name]. When clicked, the provided [param callable] will be called.
</description>
</method>
<method name="add_tool_submenu_item">
<return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="submenu" type="PopupMenu" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="submenu" type="PopupMenu" />
<description>
- Adds a custom [PopupMenu] submenu under [b]Project &gt; Tools &gt;[/b] [code]name[/code]. Use [code]remove_tool_menu_item(name)[/code] on plugin clean up to remove the menu.
+ Adds a custom [PopupMenu] submenu under [b]Project &gt; Tools &gt;[/b] [param name]. Use [code]remove_tool_menu_item(name)[/code] on plugin clean up to remove the menu.
</description>
</method>
<method name="add_translation_parser_plugin">
<return type="void" />
- <argument index="0" name="parser" type="EditorTranslationParserPlugin" />
+ <param index="0" name="parser" type="EditorTranslationParserPlugin" />
<description>
Registers a custom translation parser plugin for extracting translatable strings from custom files.
</description>
</method>
<method name="add_undo_redo_inspector_hook_callback">
<return type="void" />
- <argument index="0" name="callable" type="Callable" />
+ <param index="0" name="callable" type="Callable" />
<description>
Hooks a callback into the undo/redo action creation when a property is modified in the inspector. This allows, for example, to save other properties that may be lost when a given property is modified.
The callback should have 4 arguments: [Object] [code]undo_redo[/code], [Object] [code]modified_object[/code], [String] [code]property[/code] and [Variant] [code]new_value[/code]. They are, respectively, the [UndoRedo] object used by the inspector, the currently modified object, the name of the modified property and the new value the property is about to take.
@@ -532,7 +532,7 @@
</description>
</method>
<method name="get_undo_redo">
- <return type="UndoRedo" />
+ <return type="EditorUndoRedoManager" />
<description>
Gets the undo/redo object. Most actions in the editor can be undoable, so use this object to make sure this happens when it's worth it.
</description>
@@ -545,7 +545,7 @@
</method>
<method name="make_bottom_panel_item_visible">
<return type="void" />
- <argument index="0" name="item" type="Control" />
+ <param index="0" name="item" type="Control" />
<description>
Makes a specific item in the bottom panel visible.
</description>
@@ -558,106 +558,106 @@
</method>
<method name="remove_autoload_singleton">
<return type="void" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
- Removes an Autoload [code]name[/code] from the list.
+ Removes an Autoload [param name] from the list.
</description>
</method>
<method name="remove_control_from_bottom_panel">
<return type="void" />
- <argument index="0" name="control" type="Control" />
+ <param index="0" name="control" type="Control" />
<description>
Removes the control from the bottom panel. You have to manually [method Node.queue_free] the control.
</description>
</method>
<method name="remove_control_from_container">
<return type="void" />
- <argument index="0" name="container" type="int" enum="EditorPlugin.CustomControlContainer" />
- <argument index="1" name="control" type="Control" />
+ <param index="0" name="container" type="int" enum="EditorPlugin.CustomControlContainer" />
+ <param index="1" name="control" type="Control" />
<description>
Removes the control from the specified container. You have to manually [method Node.queue_free] the control.
</description>
</method>
<method name="remove_control_from_docks">
<return type="void" />
- <argument index="0" name="control" type="Control" />
+ <param index="0" name="control" type="Control" />
<description>
Removes the control from the dock. You have to manually [method Node.queue_free] the control.
</description>
</method>
<method name="remove_custom_type">
<return type="void" />
- <argument index="0" name="type" type="String" />
+ <param index="0" name="type" type="String" />
<description>
Removes a custom type added by [method add_custom_type].
</description>
</method>
<method name="remove_debugger_plugin">
<return type="void" />
- <argument index="0" name="script" type="Script" />
+ <param index="0" name="script" type="Script" />
<description>
Removes the debugger plugin with given script from the Debugger.
</description>
</method>
<method name="remove_export_plugin">
<return type="void" />
- <argument index="0" name="plugin" type="EditorExportPlugin" />
+ <param index="0" name="plugin" type="EditorExportPlugin" />
<description>
Removes an export plugin registered by [method add_export_plugin].
</description>
</method>
<method name="remove_import_plugin">
<return type="void" />
- <argument index="0" name="importer" type="EditorImportPlugin" />
+ <param index="0" name="importer" type="EditorImportPlugin" />
<description>
Removes an import plugin registered by [method add_import_plugin].
</description>
</method>
<method name="remove_inspector_plugin">
<return type="void" />
- <argument index="0" name="plugin" type="EditorInspectorPlugin" />
+ <param index="0" name="plugin" type="EditorInspectorPlugin" />
<description>
Removes an inspector plugin registered by [method add_import_plugin]
</description>
</method>
<method name="remove_scene_format_importer_plugin">
<return type="void" />
- <argument index="0" name="scene_format_importer" type="EditorSceneFormatImporter" />
+ <param index="0" name="scene_format_importer" type="EditorSceneFormatImporter" />
<description>
Removes a scene format importer registered by [method add_scene_format_importer_plugin].
</description>
</method>
<method name="remove_scene_post_import_plugin">
<return type="void" />
- <argument index="0" name="scene_import_plugin" type="EditorScenePostImportPlugin" />
+ <param index="0" name="scene_import_plugin" type="EditorScenePostImportPlugin" />
<description>
Remove the [EditorScenePostImportPlugin], added with [method add_scene_post_import_plugin].
</description>
</method>
<method name="remove_spatial_gizmo_plugin">
<return type="void" />
- <argument index="0" name="plugin" type="EditorNode3DGizmoPlugin" />
+ <param index="0" name="plugin" type="EditorNode3DGizmoPlugin" />
<description>
Removes a gizmo plugin registered by [method add_spatial_gizmo_plugin].
</description>
</method>
<method name="remove_tool_menu_item">
<return type="void" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
- Removes a menu [code]name[/code] from [b]Project &gt; Tools[/b].
+ Removes a menu [param name] from [b]Project &gt; Tools[/b].
</description>
</method>
<method name="remove_translation_parser_plugin">
<return type="void" />
- <argument index="0" name="parser" type="EditorTranslationParserPlugin" />
+ <param index="0" name="parser" type="EditorTranslationParserPlugin" />
<description>
Removes a custom translation parser plugin registered by [method add_translation_parser_plugin].
</description>
</method>
<method name="remove_undo_redo_inspector_hook_callback">
<return type="void" />
- <argument index="0" name="callable" type="Callable" />
+ <param index="0" name="callable" type="Callable" />
<description>
Removes a callback previsously added by [method add_undo_redo_inspector_hook_callback].
</description>
@@ -683,7 +683,7 @@
</methods>
<signals>
<signal name="main_screen_changed">
- <argument index="0" name="screen_name" type="String" />
+ <param index="0" name="screen_name" type="String" />
<description>
Emitted when user changes the workspace ([b]2D[/b], [b]3D[/b], [b]Script[/b], [b]AssetLib[/b]). Also works with custom screens defined by plugins.
</description>
@@ -693,18 +693,18 @@
</description>
</signal>
<signal name="resource_saved">
- <argument index="0" name="resource" type="Resource" />
+ <param index="0" name="resource" type="Resource" />
<description>
</description>
</signal>
<signal name="scene_changed">
- <argument index="0" name="scene_root" type="Node" />
+ <param index="0" name="scene_root" type="Node" />
<description>
Emitted when the scene is changed in the editor. The argument will return the root node of the scene that has just become active. If this scene is new and empty, the argument will be [code]null[/code].
</description>
</signal>
<signal name="scene_closed">
- <argument index="0" name="filepath" type="String" />
+ <param index="0" name="filepath" type="String" />
<description>
Emitted when user closes a scene. The argument is file path to a closed scene.
</description>
@@ -729,7 +729,7 @@
</constant>
<constant name="CONTAINER_CANVAS_EDITOR_BOTTOM" value="8" enum="CustomControlContainer">
</constant>
- <constant name="CONTAINER_PROPERTY_EDITOR_BOTTOM" value="9" enum="CustomControlContainer">
+ <constant name="CONTAINER_INSPECTOR_BOTTOM" value="9" enum="CustomControlContainer">
</constant>
<constant name="CONTAINER_PROJECT_SETTING_TAB_LEFT" value="10" enum="CustomControlContainer">
</constant>
diff --git a/doc/classes/EditorProperty.xml b/doc/classes/EditorProperty.xml
index 586458bd28..7bac4bf7ac 100644
--- a/doc/classes/EditorProperty.xml
+++ b/doc/classes/EditorProperty.xml
@@ -17,19 +17,19 @@
</method>
<method name="add_focusable">
<return type="void" />
- <argument index="0" name="control" type="Control" />
+ <param index="0" name="control" type="Control" />
<description>
If any of the controls added can gain keyboard focus, add it here. This ensures that focus will be restored if the inspector is refreshed.
</description>
</method>
<method name="emit_changed">
<return type="void" />
- <argument index="0" name="property" type="StringName" />
- <argument index="1" name="value" type="Variant" />
- <argument index="2" name="field" type="StringName" default="&amp;&quot;&quot;" />
- <argument index="3" name="changing" type="bool" default="false" />
+ <param index="0" name="property" type="StringName" />
+ <param index="1" name="value" type="Variant" />
+ <param index="2" name="field" type="StringName" default="&amp;&quot;&quot;" />
+ <param index="3" name="changing" type="bool" default="false" />
<description>
- If one or several properties have changed, this must be called. [code]field[/code] is used in case your editor can modify fields separately (as an example, Vector3.x). The [code]changing[/code] argument avoids the editor requesting this property to be refreshed (leave as [code]false[/code] if unsure).
+ If one or several properties have changed, this must be called. [param field] is used in case your editor can modify fields separately (as an example, Vector3.x). The [param changing] argument avoids the editor requesting this property to be refreshed (leave as [code]false[/code] if unsure).
</description>
</method>
<method name="get_edited_object">
@@ -44,17 +44,11 @@
Gets the edited property. If your editor is for a single property (added via [method EditorInspectorPlugin._parse_property]), then this will return the property.
</description>
</method>
- <method name="get_tooltip_text" qualifiers="const">
- <return type="String" />
- <description>
- Must be implemented to provide a custom tooltip to the property editor.
- </description>
- </method>
<method name="set_bottom_editor">
<return type="void" />
- <argument index="0" name="editor" type="Control" />
+ <param index="0" name="editor" type="Control" />
<description>
- Puts the [code]editor[/code] control below the property label. The control must be previously added using [method Node.add_child].
+ Puts the [param editor] control below the property label. The control must be previously added using [method Node.add_child].
</description>
</method>
<method name="update_property">
@@ -88,77 +82,79 @@
</members>
<signals>
<signal name="multiple_properties_changed">
- <argument index="0" name="properties" type="PackedStringArray" />
- <argument index="1" name="value" type="Array" />
+ <param index="0" name="properties" type="PackedStringArray" />
+ <param index="1" name="value" type="Array" />
<description>
Emit it if you want multiple properties modified at the same time. Do not use if added via [method EditorInspectorPlugin._parse_property].
</description>
</signal>
<signal name="object_id_selected">
- <argument index="0" name="property" type="StringName" />
- <argument index="1" name="id" type="int" />
+ <param index="0" name="property" type="StringName" />
+ <param index="1" name="id" type="int" />
<description>
Used by sub-inspectors. Emit it if what was selected was an Object ID.
</description>
</signal>
<signal name="property_can_revert_changed">
- <argument index="0" name="property" type="StringName" />
- <argument index="1" name="can_revert" type="bool" />
+ <param index="0" name="property" type="StringName" />
+ <param index="1" name="can_revert" type="bool" />
<description>
Emitted when the revertability (i.e., whether it has a non-default value and thus is displayed with a revert icon) of a property has changed.
</description>
</signal>
<signal name="property_changed">
- <argument index="0" name="property" type="StringName" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="property" type="StringName" />
+ <param index="1" name="value" type="Variant" />
+ <param index="2" name="field" type="StringName" />
+ <param index="3" name="changing" type="bool" />
<description>
Do not emit this manually, use the [method emit_changed] method instead.
</description>
</signal>
<signal name="property_checked">
- <argument index="0" name="property" type="StringName" />
- <argument index="1" name="checked" type="bool" />
+ <param index="0" name="property" type="StringName" />
+ <param index="1" name="checked" type="bool" />
<description>
Emitted when a property was checked. Used internally.
</description>
</signal>
<signal name="property_deleted">
- <argument index="0" name="property" type="StringName" />
+ <param index="0" name="property" type="StringName" />
<description>
Emitted when a property was deleted. Used internally.
</description>
</signal>
<signal name="property_keyed">
- <argument index="0" name="property" type="StringName" />
+ <param index="0" name="property" type="StringName" />
<description>
Emit it if you want to add this value as an animation key (check for keying being enabled first).
</description>
</signal>
<signal name="property_keyed_with_value">
- <argument index="0" name="property" type="StringName" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="property" type="StringName" />
+ <param index="1" name="value" type="Variant" />
<description>
Emit it if you want to key a property with a single value.
</description>
</signal>
<signal name="property_pinned">
- <argument index="0" name="property" type="StringName" />
- <argument index="1" name="pinned" type="bool" />
+ <param index="0" name="property" type="StringName" />
+ <param index="1" name="pinned" type="bool" />
<description>
Emit it if you want to mark (or unmark) the value of a property for being saved regardless of being equal to the default value.
The default value is the one the property will get when the node is just instantiated and can come from an ancestor scene in the inheritance/instancing chain, a script or a builtin class.
</description>
</signal>
<signal name="resource_selected">
- <argument index="0" name="path" type="String" />
- <argument index="1" name="resource" type="Resource" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="resource" type="Resource" />
<description>
If you want a sub-resource to be edited, emit this signal with the resource.
</description>
</signal>
<signal name="selected">
- <argument index="0" name="path" type="String" />
- <argument index="1" name="focusable_idx" type="int" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="focusable_idx" type="int" />
<description>
Emitted when selected. Used internally.
</description>
diff --git a/doc/classes/EditorResourceConversionPlugin.xml b/doc/classes/EditorResourceConversionPlugin.xml
index 8a4aee0eef..c40bb1d91e 100644
--- a/doc/classes/EditorResourceConversionPlugin.xml
+++ b/doc/classes/EditorResourceConversionPlugin.xml
@@ -9,7 +9,7 @@
<methods>
<method name="_convert" qualifiers="virtual const">
<return type="Resource" />
- <argument index="0" name="resource" type="Resource" />
+ <param index="0" name="resource" type="Resource" />
<description>
</description>
</method>
@@ -20,7 +20,7 @@
</method>
<method name="_handles" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="resource" type="Resource" />
+ <param index="0" name="resource" type="Resource" />
<description>
</description>
</method>
diff --git a/doc/classes/EditorResourcePicker.xml b/doc/classes/EditorResourcePicker.xml
index aa8f75d764..4182ab3c16 100644
--- a/doc/classes/EditorResourcePicker.xml
+++ b/doc/classes/EditorResourcePicker.xml
@@ -12,16 +12,16 @@
<methods>
<method name="_handle_menu_selected" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
This virtual method can be implemented to handle context menu items not handled by default. See [method _set_create_options].
</description>
</method>
<method name="_set_create_options" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="menu_node" type="Object" />
+ <param index="0" name="menu_node" type="Object" />
<description>
- This virtual method is called when updating the context menu of [EditorResourcePicker]. Implement this method to override the "New ..." items with your own options. [code]menu_node[/code] is a reference to the [PopupMenu] node.
+ This virtual method is called when updating the context menu of [EditorResourcePicker]. Implement this method to override the "New ..." items with your own options. [param menu_node] is a reference to the [PopupMenu] node.
[b]Note:[/b] Implement [method _handle_menu_selected] to handle these custom items.
</description>
</method>
@@ -33,7 +33,7 @@
</method>
<method name="set_toggle_pressed">
<return type="void" />
- <argument index="0" name="pressed" type="bool" />
+ <param index="0" name="pressed" type="bool" />
<description>
Sets the toggle mode state for the main button. Works only if [member toggle_mode] is set to [code]true[/code].
</description>
@@ -55,16 +55,16 @@
</members>
<signals>
<signal name="resource_changed">
- <argument index="0" name="resource" type="Resource" />
+ <param index="0" name="resource" type="Resource" />
<description>
Emitted when the value of the edited resource was changed.
</description>
</signal>
<signal name="resource_selected">
- <argument index="0" name="resource" type="Resource" />
- <argument index="1" name="edit" type="bool" />
+ <param index="0" name="resource" type="Resource" />
+ <param index="1" name="inspect" type="bool" />
<description>
- Emitted when the resource value was set and user clicked to edit it. When [code]edit[/code] is [code]true[/code], the signal was caused by the context menu "Edit" option.
+ Emitted when the resource value was set and user clicked to edit it. When [param inspect] is [code]true[/code], the signal was caused by the context menu "Edit" or "Inspect" option.
</description>
</signal>
</signals>
diff --git a/doc/classes/EditorResourcePreview.xml b/doc/classes/EditorResourcePreview.xml
index 5df797f516..68ead12c03 100644
--- a/doc/classes/EditorResourcePreview.xml
+++ b/doc/classes/EditorResourcePreview.xml
@@ -12,43 +12,43 @@
<methods>
<method name="add_preview_generator">
<return type="void" />
- <argument index="0" name="generator" type="EditorResourcePreviewGenerator" />
+ <param index="0" name="generator" type="EditorResourcePreviewGenerator" />
<description>
Create an own, custom preview generator.
</description>
</method>
<method name="check_for_invalidation">
<return type="void" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Check if the resource changed, if so, it will be invalidated and the corresponding signal emitted.
</description>
</method>
<method name="queue_edited_resource_preview">
<return type="void" />
- <argument index="0" name="resource" type="Resource" />
- <argument index="1" name="receiver" type="Object" />
- <argument index="2" name="receiver_func" type="StringName" />
- <argument index="3" name="userdata" type="Variant" />
+ <param index="0" name="resource" type="Resource" />
+ <param index="1" name="receiver" type="Object" />
+ <param index="2" name="receiver_func" type="StringName" />
+ <param index="3" name="userdata" type="Variant" />
<description>
- Queue the [code]resource[/code] being edited for preview. Once the preview is ready, the [code]receiver[/code]'s [code]receiver_func[/code] will be called. The [code]receiver_func[/code] must take the following four arguments: [String] path, [Texture2D] preview, [Texture2D] thumbnail_preview, [Variant] userdata. [code]userdata[/code] can be anything, and will be returned when [code]receiver_func[/code] is called.
- [b]Note:[/b] If it was not possible to create the preview the [code]receiver_func[/code] will still be called, but the preview will be null.
+ Queue the [param resource] being edited for preview. Once the preview is ready, the [param receiver]'s [param receiver_func] will be called. The [param receiver_func] must take the following four arguments: [String] path, [Texture2D] preview, [Texture2D] thumbnail_preview, [Variant] userdata. [param userdata] can be anything, and will be returned when [param receiver_func] is called.
+ [b]Note:[/b] If it was not possible to create the preview the [param receiver_func] will still be called, but the preview will be null.
</description>
</method>
<method name="queue_resource_preview">
<return type="void" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="receiver" type="Object" />
- <argument index="2" name="receiver_func" type="StringName" />
- <argument index="3" name="userdata" type="Variant" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="receiver" type="Object" />
+ <param index="2" name="receiver_func" type="StringName" />
+ <param index="3" name="userdata" type="Variant" />
<description>
- Queue a resource file located at [code]path[/code] for preview. Once the preview is ready, the [code]receiver[/code]'s [code]receiver_func[/code] will be called. The [code]receiver_func[/code] must take the following four arguments: [String] path, [Texture2D] preview, [Texture2D] thumbnail_preview, [Variant] userdata. [code]userdata[/code] can be anything, and will be returned when [code]receiver_func[/code] is called.
- [b]Note:[/b] If it was not possible to create the preview the [code]receiver_func[/code] will still be called, but the preview will be null.
+ Queue a resource file located at [param path] for preview. Once the preview is ready, the [param receiver]'s [param receiver_func] will be called. The [param receiver_func] must take the following four arguments: [String] path, [Texture2D] preview, [Texture2D] thumbnail_preview, [Variant] userdata. [param userdata] can be anything, and will be returned when [param receiver_func] is called.
+ [b]Note:[/b] If it was not possible to create the preview the [param receiver_func] will still be called, but the preview will be null.
</description>
</method>
<method name="remove_preview_generator">
<return type="void" />
- <argument index="0" name="generator" type="EditorResourcePreviewGenerator" />
+ <param index="0" name="generator" type="EditorResourcePreviewGenerator" />
<description>
Removes a custom preview generator.
</description>
@@ -56,9 +56,9 @@
</methods>
<signals>
<signal name="preview_invalidated">
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
- Emitted if a preview was invalidated (changed). [code]path[/code] corresponds to the path of the preview.
+ Emitted if a preview was invalidated (changed). [param path] corresponds to the path of the preview.
</description>
</signal>
</signals>
diff --git a/doc/classes/EditorResourcePreviewGenerator.xml b/doc/classes/EditorResourcePreviewGenerator.xml
index d8b4a86a97..75628beae9 100644
--- a/doc/classes/EditorResourcePreviewGenerator.xml
+++ b/doc/classes/EditorResourcePreviewGenerator.xml
@@ -18,8 +18,8 @@
</method>
<method name="_generate" qualifiers="virtual const">
<return type="Texture2D" />
- <argument index="0" name="resource" type="Resource" />
- <argument index="1" name="size" type="Vector2i" />
+ <param index="0" name="resource" type="Resource" />
+ <param index="1" name="size" type="Vector2i" />
<description>
Generate a preview from a given resource with the specified size. This must always be implemented.
Returning an empty texture is an OK way to fail and let another generator take care.
@@ -28,8 +28,8 @@
</method>
<method name="_generate_from_path" qualifiers="virtual const">
<return type="Texture2D" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="size" type="Vector2i" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="size" type="Vector2i" />
<description>
Generate a preview directly from a path with the specified size. Implementing this is optional, as default code will load and call [method _generate].
Returning an empty texture is an OK way to fail and let another generator take care.
@@ -45,9 +45,9 @@
</method>
<method name="_handles" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="type" type="String" />
+ <param index="0" name="type" type="String" />
<description>
- Returns [code]true[/code] if your generator supports the resource of type [code]type[/code].
+ Returns [code]true[/code] if your generator supports the resource of type [param type].
</description>
</method>
</methods>
diff --git a/doc/classes/EditorSceneFormatImporter.xml b/doc/classes/EditorSceneFormatImporter.xml
index 0290d7207d..6de9c2c5dc 100644
--- a/doc/classes/EditorSceneFormatImporter.xml
+++ b/doc/classes/EditorSceneFormatImporter.xml
@@ -22,24 +22,24 @@
</method>
<method name="_get_import_options" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
</description>
</method>
<method name="_get_option_visibility" qualifiers="virtual const">
<return type="Variant" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="for_animation" type="bool" />
- <argument index="2" name="option" type="String" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="for_animation" type="bool" />
+ <param index="2" name="option" type="String" />
<description>
</description>
</method>
<method name="_import_scene" qualifiers="virtual">
<return type="Object" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="flags" type="int" />
- <argument index="2" name="options" type="Dictionary" />
- <argument index="3" name="bake_fps" type="int" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="flags" type="int" />
+ <param index="2" name="options" type="Dictionary" />
+ <param index="3" name="bake_fps" type="int" />
<description>
</description>
</method>
diff --git a/doc/classes/EditorScenePostImport.xml b/doc/classes/EditorScenePostImport.xml
index 3adf814947..395b094bf2 100644
--- a/doc/classes/EditorScenePostImport.xml
+++ b/doc/classes/EditorScenePostImport.xml
@@ -57,7 +57,7 @@
<methods>
<method name="_post_import" qualifiers="virtual">
<return type="Object" />
- <argument index="0" name="scene" type="Node" />
+ <param index="0" name="scene" type="Node" />
<description>
Called after the scene was imported. This method must return the modified version of the scene.
</description>
diff --git a/doc/classes/EditorScenePostImportPlugin.xml b/doc/classes/EditorScenePostImportPlugin.xml
index 44d644411d..3ea0e53c01 100644
--- a/doc/classes/EditorScenePostImportPlugin.xml
+++ b/doc/classes/EditorScenePostImportPlugin.xml
@@ -11,91 +11,91 @@
<methods>
<method name="_get_import_options" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Override to add general import options. These will appear in the main import dock on the editor. Add options via [method add_import_option] and [method add_import_option_advanced].
</description>
</method>
<method name="_get_internal_import_options" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="category" type="int" />
+ <param index="0" name="category" type="int" />
<description>
Override to add internal import options. These will appear in the 3D scene import dialog. Add options via [method add_import_option] and [method add_import_option_advanced].
</description>
</method>
<method name="_get_internal_option_update_view_required" qualifiers="virtual const">
<return type="Variant" />
- <argument index="0" name="category" type="int" />
- <argument index="1" name="option" type="String" />
+ <param index="0" name="category" type="int" />
+ <param index="1" name="option" type="String" />
<description>
Return true whether updating the 3D view of the import dialog needs to be updated if an option has changed.
</description>
</method>
<method name="_get_internal_option_visibility" qualifiers="virtual const">
<return type="Variant" />
- <argument index="0" name="category" type="int" />
- <argument index="1" name="for_animation" type="bool" />
- <argument index="2" name="option" type="String" />
+ <param index="0" name="category" type="int" />
+ <param index="1" name="for_animation" type="bool" />
+ <param index="2" name="option" type="String" />
<description>
Return true or false whether a given option should be visible. Return null to ignore.
</description>
</method>
<method name="_get_option_visibility" qualifiers="virtual const">
<return type="Variant" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="for_animation" type="bool" />
- <argument index="2" name="option" type="String" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="for_animation" type="bool" />
+ <param index="2" name="option" type="String" />
<description>
Return true or false whether a given option should be visible. Return null to ignore.
</description>
</method>
<method name="_internal_process" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="category" type="int" />
- <argument index="1" name="base_node" type="Node" />
- <argument index="2" name="node" type="Node" />
- <argument index="3" name="resource" type="Resource" />
+ <param index="0" name="category" type="int" />
+ <param index="1" name="base_node" type="Node" />
+ <param index="2" name="node" type="Node" />
+ <param index="3" name="resource" type="Resource" />
<description>
Process a specific node or resource for a given category.
</description>
</method>
<method name="_post_process" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="scene" type="Node" />
+ <param index="0" name="scene" type="Node" />
<description>
Post process the scene. This function is called after the final scene has been configured.
</description>
</method>
<method name="_pre_process" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="scene" type="Node" />
+ <param index="0" name="scene" type="Node" />
<description>
Pre Process the scene. This function is called right after the scene format loader loaded the scene and no changes have been made.
</description>
</method>
<method name="add_import_option">
<return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="value" type="Variant" />
<description>
Add a specific import option (name and default value only). This function can only be called from [method _get_import_options] and [method _get_internal_import_options].
</description>
</method>
<method name="add_import_option_advanced">
<return type="void" />
- <argument index="0" name="type" type="int" enum="Variant.Type" />
- <argument index="1" name="name" type="String" />
- <argument index="2" name="default_value" type="Variant" />
- <argument index="3" name="hint" type="int" enum="PropertyHint" default="0" />
- <argument index="4" name="hint_string" type="String" default="&quot;&quot;" />
- <argument index="5" name="usage_flags" type="int" default="6" />
+ <param index="0" name="type" type="int" enum="Variant.Type" />
+ <param index="1" name="name" type="String" />
+ <param index="2" name="default_value" type="Variant" />
+ <param index="3" name="hint" type="int" enum="PropertyHint" default="0" />
+ <param index="4" name="hint_string" type="String" default="&quot;&quot;" />
+ <param index="5" name="usage_flags" type="int" default="6" />
<description>
Add a specific import option. This function can only be called from [method _get_import_options] and [method _get_internal_import_options].
</description>
</method>
<method name="get_option_value" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
Query the value of an option. This function can only be called from those querying visibility, or processing.
</description>
diff --git a/doc/classes/EditorScript.xml b/doc/classes/EditorScript.xml
index 68ee939370..2ff8a7ba2a 100644
--- a/doc/classes/EditorScript.xml
+++ b/doc/classes/EditorScript.xml
@@ -42,9 +42,9 @@
</method>
<method name="add_root_node">
<return type="void" />
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
- Adds [code]node[/code] as a child of the root node in the editor context.
+ Adds [param node] as a child of the root node in the editor context.
[b]Warning:[/b] The implementation of this method is currently disabled.
</description>
</method>
diff --git a/doc/classes/EditorSelection.xml b/doc/classes/EditorSelection.xml
index ff6f5f9206..54029c2ccf 100644
--- a/doc/classes/EditorSelection.xml
+++ b/doc/classes/EditorSelection.xml
@@ -12,7 +12,7 @@
<methods>
<method name="add_node">
<return type="void" />
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
Adds a node to the selection.
[b]Note:[/b] The newly selected node will not be automatically edited in the inspector. If you want to edit a node, use [method EditorInterface.edit_node].
@@ -31,14 +31,14 @@
</description>
</method>
<method name="get_transformable_selected_nodes">
- <return type="Array" />
+ <return type="Node[]" />
<description>
Gets the list of selected nodes, optimized for transform operations (i.e. moving them, rotating, etc). This list avoids situations where a node is selected and also child/grandchild.
</description>
</method>
<method name="remove_node">
<return type="void" />
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
Removes a node from the selection.
</description>
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index 687c3d70ca..56c1f6e55a 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -32,7 +32,7 @@
<methods>
<method name="add_property_info">
<return type="void" />
- <argument index="0" name="info" type="Dictionary" />
+ <param index="0" name="info" type="Dictionary" />
<description>
Adds a custom property info to a property. The dictionary must contain:
- [code]name[/code]: [String] (the name of the property)
@@ -72,20 +72,20 @@
</method>
<method name="check_changed_settings_in_group" qualifiers="const">
<return type="bool" />
- <argument index="0" name="setting_prefix" type="String" />
+ <param index="0" name="setting_prefix" type="String" />
<description>
- Checks if any settings with the prefix [code]setting_prefix[/code] exist in the set of changed settings. See also [method get_changed_settings].
+ Checks if any settings with the prefix [param setting_prefix] exist in the set of changed settings. See also [method get_changed_settings].
</description>
</method>
<method name="erase">
<return type="void" />
- <argument index="0" name="property" type="String" />
+ <param index="0" name="property" type="String" />
<description>
- Erases the setting whose name is specified by [code]property[/code].
+ Erases the setting whose name is specified by [param property].
</description>
</method>
<method name="get_changed_settings" qualifiers="const">
- <return type="Array" />
+ <return type="PackedStringArray" />
<description>
Gets an array of the settings which have been changed since the last save. Note that internally [code]changed_settings[/code] is cleared after a successful save, so generally the most appropriate place to use this method is when processing [constant NOTIFICATION_EDITOR_SETTINGS_CHANGED]
</description>
@@ -98,11 +98,11 @@
</method>
<method name="get_project_metadata" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="section" type="String" />
- <argument index="1" name="key" type="String" />
- <argument index="2" name="default" type="Variant" default="null" />
+ <param index="0" name="section" type="String" />
+ <param index="1" name="key" type="String" />
+ <param index="2" name="default" type="Variant" default="null" />
<description>
- Returns project-specific metadata for the [code]section[/code] and [code]key[/code] specified. If the metadata doesn't exist, [code]default[/code] will be returned instead. See also [method set_project_metadata].
+ Returns project-specific metadata for the [param section] and [param key] specified. If the metadata doesn't exist, [param default] will be returned instead. See also [method set_project_metadata].
</description>
</method>
<method name="get_recent_dirs" qualifiers="const">
@@ -113,533 +113,804 @@
</method>
<method name="get_setting" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
- Returns the value of the setting specified by [code]name[/code]. This is equivalent to using [method Object.get] on the EditorSettings instance.
+ Returns the value of the setting specified by [param name]. This is equivalent to using [method Object.get] on the EditorSettings instance.
</description>
</method>
<method name="has_setting" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
- Returns [code]true[/code] if the setting specified by [code]name[/code] exists, [code]false[/code] otherwise.
+ Returns [code]true[/code] if the setting specified by [param name] exists, [code]false[/code] otherwise.
</description>
</method>
<method name="mark_setting_changed">
<return type="void" />
- <argument index="0" name="setting" type="String" />
+ <param index="0" name="setting" type="String" />
<description>
Marks the passed editor setting as being changed, see [method get_changed_settings]. Only settings which exist (see [method has_setting]) will be accepted.
</description>
</method>
- <method name="property_can_revert">
- <return type="bool" />
- <argument index="0" name="name" type="String" />
- <description>
- Returns [code]true[/code] if the setting specified by [code]name[/code] can have its value reverted to the default value, [code]false[/code] otherwise. When this method returns [code]true[/code], a Revert button will display next to the setting in the Editor Settings.
- </description>
- </method>
- <method name="property_get_revert">
- <return type="Variant" />
- <argument index="0" name="name" type="String" />
- <description>
- Returns the default value of the setting specified by [code]name[/code]. This is the value that would be applied when clicking the Revert button in the Editor Settings.
- </description>
- </method>
<method name="set_builtin_action_override">
<return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="actions_list" type="Array" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="actions_list" type="Array" />
<description>
+ Overrides the built-in editor action [param name] with the input actions defined in [param actions_list].
</description>
</method>
<method name="set_favorites">
<return type="void" />
- <argument index="0" name="dirs" type="PackedStringArray" />
+ <param index="0" name="dirs" type="PackedStringArray" />
<description>
Sets the list of favorite files and directories for this project.
</description>
</method>
<method name="set_initial_value">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="value" type="Variant" />
- <argument index="2" name="update_current" type="bool" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="value" type="Variant" />
+ <param index="2" name="update_current" type="bool" />
<description>
- Sets the initial value of the setting specified by [code]name[/code] to [code]value[/code]. This is used to provide a value for the Revert button in the Editor Settings. If [code]update_current[/code] is true, the current value of the setting will be set to [code]value[/code] as well.
+ Sets the initial value of the setting specified by [param name] to [param value]. This is used to provide a value for the Revert button in the Editor Settings. If [param update_current] is true, the current value of the setting will be set to [param value] as well.
</description>
</method>
<method name="set_project_metadata">
<return type="void" />
- <argument index="0" name="section" type="String" />
- <argument index="1" name="key" type="String" />
- <argument index="2" name="data" type="Variant" />
+ <param index="0" name="section" type="String" />
+ <param index="1" name="key" type="String" />
+ <param index="2" name="data" type="Variant" />
<description>
- Sets project-specific metadata with the [code]section[/code], [code]key[/code] and [code]data[/code] specified. This metadata is stored outside the project folder and therefore won't be checked into version control. See also [method get_project_metadata].
+ Sets project-specific metadata with the [param section], [param key] and [param data] specified. This metadata is stored outside the project folder and therefore won't be checked into version control. See also [method get_project_metadata].
</description>
</method>
<method name="set_recent_dirs">
<return type="void" />
- <argument index="0" name="dirs" type="PackedStringArray" />
+ <param index="0" name="dirs" type="PackedStringArray" />
<description>
Sets the list of recently visited folders in the file dialog for this project.
</description>
</method>
<method name="set_setting">
<return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="value" type="Variant" />
<description>
- Sets the [code]value[/code] of the setting specified by [code]name[/code]. This is equivalent to using [method Object.set] on the EditorSettings instance.
+ Sets the [param value] of the setting specified by [param name]. This is equivalent to using [method Object.set] on the EditorSettings instance.
</description>
</method>
</methods>
<members>
<member name="debugger/profiler_frame_history_size" type="int" setter="" getter="">
+ The size of the profiler's frame history. The default value (3600) allows seeing up to 60 seconds of profiling if the project renders at a constant 60 FPS. Higher values allow viewing longer periods of profiling in the graphs, especially when the project is running at high framerates.
</member>
<member name="docks/filesystem/always_show_folders" type="bool" setter="" getter="">
+ If [code]true[/code], displays folders in the FileSystem dock's bottom pane when split mode is enabled. If [code]false[/code], only files will be displayed in the bottom pane. Split mode can be toggled by pressing the icon next to the [code]res://[/code] folder path.
+ [b]Note:[/b] This setting has no effect when split mode is disabled (which is the default).
</member>
<member name="docks/filesystem/textfile_extensions" type="String" setter="" getter="">
+ List of file extensions to consider as editable text files in the FileSystem dock (by double-clicking on the files).
</member>
<member name="docks/filesystem/thumbnail_size" type="int" setter="" getter="">
+ The thumbnail size to use in the FileSystem dock (in pixels). See also [member filesystem/file_dialog/thumbnail_size].
</member>
<member name="docks/property_editor/auto_refresh_interval" type="float" setter="" getter="">
+ The refresh interval to use for the inspector dock's properties. The effect of this setting is mainly noticeable when adjusting gizmos in the 2D/3D editor and looking at the inspector at the same time. Lower values make the inspector more often, but take up more CPU time.
</member>
<member name="docks/property_editor/subresource_hue_tint" type="float" setter="" getter="">
+ The tint intensity to use for the subresources background in the inspector dock. The tint is used to distinguish between different subresources in the inspector. Higher values result in a more noticeable background color difference.
</member>
<member name="docks/scene_tree/auto_expand_to_selected" type="bool" setter="" getter="">
+ If [code]true[/code], the scene tree dock will automatically unfold nodes when a node that has folded parents is selected.
</member>
<member name="docks/scene_tree/start_create_dialog_fully_expanded" type="bool" setter="" getter="">
+ If [code]true[/code], the Create dialog (Create New Node/Create New Resource) will start with all its sections expanded. Otherwise, sections will be collapsed until the user starts searching (which will automatically expand sections as needed).
</member>
<member name="editors/2d/bone_color1" type="Color" setter="" getter="">
+ The "start" stop of the color gradient to use for bones in the 2D skeleton editor.
</member>
<member name="editors/2d/bone_color2" type="Color" setter="" getter="">
+ The "end" stop of the color gradient to use for bones in the 2D skeleton editor.
</member>
<member name="editors/2d/bone_ik_color" type="Color" setter="" getter="">
+ The color to use for inverse kinematics-enabled bones in the 2D skeleton editor.
</member>
<member name="editors/2d/bone_outline_color" type="Color" setter="" getter="">
+ The outline color to use for non-selected bones in the 2D skeleton editor. See also [member editors/2d/bone_selected_color].
</member>
<member name="editors/2d/bone_outline_size" type="int" setter="" getter="">
+ The outline size in the 2D skeleton editor (in pixels). See also [member editors/2d/bone_width].
</member>
<member name="editors/2d/bone_selected_color" type="Color" setter="" getter="">
+ The color to use for selected bones in the 2D skeleton editor. See also [member editors/2d/bone_outline_color].
</member>
<member name="editors/2d/bone_width" type="int" setter="" getter="">
+ The bone width in the 2D skeleton editor (in pixels). See also [member editors/2d/bone_outline_size].
</member>
<member name="editors/2d/constrain_editor_view" type="bool" setter="" getter="">
+ If [code]true[/code], prevents the 2D editor viewport from leaving the scene. Limits are calculated dynamically based on nodes present in the current scene. If [code]false[/code], the 2D editor viewport will be able to move freely, but you risk getting lost when zooming out too far. You can refocus on the scene by selecting a node then pressing [kbd]F[/kbd].
</member>
<member name="editors/2d/grid_color" type="Color" setter="" getter="">
+ The grid color to use in the 2D editor.
</member>
<member name="editors/2d/guides_color" type="Color" setter="" getter="">
+ The guides color to use in the 2D editor. Guides can be created by dragging the mouse cursor from the rulers.
</member>
<member name="editors/2d/smart_snapping_line_color" type="Color" setter="" getter="">
+ The color to use when drawing smart snapping lines in the 2D editor. The smart snapping lines will automatically display when moving 2D nodes if smart snapping is enabled in the Snapping Options menu at the top of the 2D editor viewport.
</member>
<member name="editors/2d/viewport_border_color" type="Color" setter="" getter="">
+ The color of the viewport border in the 2D editor. This border represents the viewport's size at the base resolution defined in the Project Settings. Objects placed outside this border will not be visible unless a [Camera2D] node is used, or unless the window is resized and the stretch mode is set to [code]disabled[/code].
</member>
<member name="editors/3d/default_fov" type="float" setter="" getter="">
+ The default camera field of view to use in the 3D editor (in degrees). The camera field of view can be adjusted on a per-scene basis using the [b]View[/b] menu at the top of the 3D editor. If a scene had its camera field of view adjusted using the [b]View[/b] menu, this setting is ignored in the scene in question. This setting is also ignored while a Camera3D node is being previewed in the editor.
</member>
<member name="editors/3d/default_z_far" type="float" setter="" getter="">
+ The default camera far clip distance to use in the 3D editor (in degrees). Higher values make it possible to view objects placed further away from the camera, at the cost of lower precision in the depth buffer (which can result in visible Z-fighting in the distance). The camera far clip distance can be adjusted on a per-scene basis using the [b]View[/b] menu at the top of the 3D editor. If a scene had its camera far clip distance adjusted using the [b]View[/b] menu, this setting is ignored in the scene in question. This setting is also ignored while a Camera3D node is being previewed in the editor.
</member>
<member name="editors/3d/default_z_near" type="float" setter="" getter="">
+ The default camera near clip distance to use in the 3D editor (in degrees). Lower values make it possible to view objects placed closer to the camera, at the cost of lower precision in the depth buffer (which can result in visible Z-fighting in the distance). The camera near clip distance can be adjusted on a per-scene basis using the [b]View[/b] menu at the top of the 3D editor. If a scene had its camera near clip distance adjusted using the [b]View[/b] menu, this setting is ignored in the scene in question. This setting is also ignored while a Camera3D node is being previewed in the editor.
</member>
<member name="editors/3d/freelook/freelook_activation_modifier" type="int" setter="" getter="">
+ The modifier key to use to enable freelook in the 3D editor (on top of pressing the right mouse button).
+ [b]Note:[/b] Regardless of this setting, the freelook toggle keyboard shortcut ([kbd]Shift + F[/kbd] by default) is always available.
+ [b]Note:[/b] On certain window managers on Linux, the [kbd]Alt[/kbd] key will be intercepted by the window manager when clicking a mouse button at the same time. This means Godot will not see the modifier key as being pressed.
</member>
<member name="editors/3d/freelook/freelook_base_speed" type="float" setter="" getter="">
+ The base 3D freelook speed in units per second. This can be adjusted by using the mouse wheel while in freelook mode, or by holding down the "fast" or "slow" modifier keys ([kbd]Shift[/kbd] and [kbd]Alt[/kbd] by default, respectively).
</member>
<member name="editors/3d/freelook/freelook_inertia" type="float" setter="" getter="">
+ The inertia of the 3D freelook camera. Higher values make the camera start and stop slower, which looks smoother but adds latency.
</member>
<member name="editors/3d/freelook/freelook_navigation_scheme" type="int" setter="" getter="">
+ The navigation scheme to use when freelook is enabled in the 3D editor. Some of the navigation schemes below may be more convenient when designing specific levels in the 3D editor.
+ - [b]Default:[/b] The "Freelook Forward", "Freelook Backward", "Freelook Up" and "Freelook Down" keys will move relative to the camera, taking its pitch angle into account for the movement.
+ - [b]Partially Axis-Locked:[/b] The "Freelook Forward" and "Freelook Backward" keys will move relative to the camera, taking its pitch angle into account for the movement. The "Freelook Up" and "Freelook Down" keys will move in an "absolute" manner, [i]not[/i] taking the camera's pitch angle into account for the movement.
+ - [b]Fully Axis-Locked:[/b] The "Freelook Forward", "Freelook Backward", "Freelook Up" and "Freelook Down" keys will move in an "absolute" manner, [i]not[/i] taking the camera's pitch angle into account for the movement.
+ See also [member editors/3d/navigation/navigation_scheme].
</member>
<member name="editors/3d/freelook/freelook_sensitivity" type="float" setter="" getter="">
+ The mouse sensitivity to use while freelook mode is active in the 3D editor. See also [member editors/3d/navigation_feel/orbit_sensitivity].
</member>
<member name="editors/3d/freelook/freelook_speed_zoom_link" type="bool" setter="" getter="">
+ If [code]true[/code], freelook speed is linked to the zoom value used in the camera orbit mode in the 3D editor.
</member>
<member name="editors/3d/grid_division_level_bias" type="float" setter="" getter="">
+ The grid division bias to use in the 3D editor. Negative values will cause small grid divisions to appear earlier, whereas positive values will cause small grid divisions to appear later.
</member>
<member name="editors/3d/grid_division_level_max" type="int" setter="" getter="">
+ The smallest grid division to use in the 3D editor, specified as a power of 2. The grid will not be able to get larger than [code]1 ^ grid_division_level_max[/code] units. By default, this means grid divisions cannot get smaller than 100 units each, no matter how far away the camera is from the grid.
</member>
<member name="editors/3d/grid_division_level_min" type="int" setter="" getter="">
+ The smallest grid division to use in the 3D editor, specified as a power of 2. The grid will not be able to get smaller than [code]1 ^ grid_division_level_min[/code] units. By default, this means grid divisions cannot get smaller than 1 unit each, no matter how close the camera is from the grid.
</member>
<member name="editors/3d/grid_size" type="int" setter="" getter="">
+ The grid size in units. Higher values prevent the grid from appearing "cut off" at certain angles, but make the grid more demanding to render. Depending on the camera's position, the grid may not be fully visible since a shader is used to fade it progressively.
</member>
<member name="editors/3d/grid_xy_plane" type="bool" setter="" getter="">
+ If [code]true[/code], render the grid on an XY plane. This can be useful for 3D side-scrolling games.
</member>
<member name="editors/3d/grid_xz_plane" type="bool" setter="" getter="">
+ If [code]true[/code], render the grid on an XZ plane.
</member>
<member name="editors/3d/grid_yz_plane" type="bool" setter="" getter="">
+ If [code]true[/code], render the grid on an YZ plane. This can be useful for 3D side-scrolling games.
</member>
<member name="editors/3d/navigation/emulate_3_button_mouse" type="bool" setter="" getter="">
+ If [code]true[/code], enables 3-button mouse emulation mode. This is useful on laptops when using a trackpad.
+ When 3-button mouse emulation mode is enabled, the pan, zoom and orbit modifiers can always be used in the 3D editor viewport, even when not holding down any mouse button.
+ [b]Note:[/b] No matter the orbit modifier configured in [member editors/3d/navigation/orbit_modifier], [kbd]Alt[/kbd] will always remain usable for orbiting in this mode to improve usability with graphics tablets.
</member>
<member name="editors/3d/navigation/emulate_numpad" type="bool" setter="" getter="">
+ If [code]true[/code], allows using the top row [kbd]0[/kbd]-[kbd]9[/kbd] keys to function as their equivalent numpad keys for 3D editor navigation. This should be enabled on keyboards that have no numeric keypad available.
</member>
<member name="editors/3d/navigation/invert_x_axis" type="bool" setter="" getter="">
+ If [code]true[/code], invert the horizontal mouse axis when panning or orbiting in the 3D editor. This setting does [i]not[/i] apply to freelook mode.
</member>
<member name="editors/3d/navigation/invert_y_axis" type="bool" setter="" getter="">
+ If [code]true[/code], invert the vertical mouse axis when panning, orbiting, or using freelook mode in the 3D editor.
</member>
<member name="editors/3d/navigation/navigation_scheme" type="int" setter="" getter="">
+ The navigation scheme to use in the 3D editor. Changing this setting will affect the mouse buttons that must be held down to perform certain operations in the 3D editor viewport.
+ - [b]Godot[/b] Middle mouse button to orbit, [kbd]Shift + Middle mouse button[/kbd] to pan. [kbd]Mouse wheel[/kbd] to zoom.
+ - [b]Maya:[/b] [kbd]Alt + Left mouse buttton[/kbd] to orbit. [kbd]Middle mouse button[/kbd] to pan, [kbd]Shift + Middle mouse button[/kbd] to pan 10 times faster. [kbd]Mouse wheel[/kbd] to zoom.
+ - [b]Modo:[/b] [kbd]Alt + Left mouse buttton[/kbd] to orbit. [kbd]Alt + Shift + Left mouse button[/kbd] to pan. [kbd]Ctrl + Alt + Left mouse button[/kbd] to zoom.
+ See also [member editors/3d/freelook/freelook_navigation_scheme].
+ [b]Note:[/b] On certain window managers on Linux, the [kbd]Alt[/kbd] key will be intercepted by the window manager when clicking a mouse button at the same time. This means Godot will not see the modifier key as being pressed.
</member>
<member name="editors/3d/navigation/orbit_modifier" type="int" setter="" getter="">
+ The modifier key that must be held to orbit in the 3D editor.
+ [b]Note:[/b] If [member editors/3d/navigation/emulate_3_button_mouse] is [code]true[/code], [kbd]Alt[/kbd] will always remain usable for orbiting to improve usability with graphics tablets.
+ [b]Note:[/b] On certain window managers on Linux, the [kbd]Alt[/kbd] key will be intercepted by the window manager when clicking a mouse button at the same time. This means Godot will not see the modifier key as being pressed.
</member>
<member name="editors/3d/navigation/pan_modifier" type="int" setter="" getter="">
+ The modifier key that must be held to pan in the 3D editor.
+ [b]Note:[/b] On certain window managers on Linux, the [kbd]Alt[/kbd] key will be intercepted by the window manager when clicking a mouse button at the same time. This means Godot will not see the modifier key as being pressed.
</member>
<member name="editors/3d/navigation/warped_mouse_panning" type="bool" setter="" getter="">
+ If [code]true[/code], warps the mouse around the 3D viewport while panning in the 3D editor. This makes it possible to pan over a large area without having to exit panning then mouse the mouse back constantly.
</member>
<member name="editors/3d/navigation/zoom_modifier" type="int" setter="" getter="">
+ The modifier key that must be held to zoom in the 3D editor.
+ [b]Note:[/b] On certain window managers on Linux, the [kbd]Alt[/kbd] key will be intercepted by the window manager when clicking a mouse button at the same time. This means Godot will not see the modifier key as being pressed.
</member>
<member name="editors/3d/navigation/zoom_style" type="int" setter="" getter="">
+ The mouse cursor movement direction to use when zooming by moving the mouse. This does not affect zooming with the mouse wheel.
</member>
<member name="editors/3d/navigation_feel/orbit_inertia" type="float" setter="" getter="">
+ The inertia to use when orbiting in the 3D editor. Higher values make the camera start and stop slower, which looks smoother but adds latency.
</member>
<member name="editors/3d/navigation_feel/orbit_sensitivity" type="float" setter="" getter="">
+ The mouse sensitivity to use when orbiting in the 3D editor. See also [member editors/3d/freelook/freelook_sensitivity].
</member>
<member name="editors/3d/navigation_feel/translation_inertia" type="float" setter="" getter="">
+ The inertia to use when panning in the 3D editor. Higher values make the camera start and stop slower, which looks smoother but adds latency.
</member>
<member name="editors/3d/navigation_feel/zoom_inertia" type="float" setter="" getter="">
+ The inertia to use when zooming in the 3D editor. Higher values make the camera start and stop slower, which looks smoother but adds latency.
</member>
<member name="editors/3d/primary_grid_color" type="Color" setter="" getter="">
+ The color to use for the primary 3D grid. The color's alpha channel affects the grid's opacity.
</member>
<member name="editors/3d/primary_grid_steps" type="int" setter="" getter="">
+ If set above 0, where a primary grid line should be drawn. By default, primary lines are configured to be more visible than secondary lines. This helps with measurements in the 3D editor. See also [member editors/3d/primary_grid_color] and [member editors/3d/secondary_grid_color].
</member>
<member name="editors/3d/secondary_grid_color" type="Color" setter="" getter="">
+ The color to use for the secondary 3D grid. This is generally a less visible color than [member editors/3d/primary_grid_color]. The color's alpha channel affects the grid's opacity.
</member>
<member name="editors/3d/selection_box_color" type="Color" setter="" getter="">
+ The color to use for the selection box that surrounds selected nodes in the 3D editor viewport. The color's alpha channel influences the selection box's opacity.
</member>
<member name="editors/3d_gizmos/gizmo_colors/instantiated" type="Color" setter="" getter="">
+ The color override to use for 3D editor gizmos if the [Node3D] in question is part of an instanced scene file (from the perspective of the current scene).
</member>
<member name="editors/3d_gizmos/gizmo_colors/joint" type="Color" setter="" getter="">
+ The 3D editor gizmo color for [Joint3D]s and [PhysicalBone3D]s.
</member>
<member name="editors/3d_gizmos/gizmo_colors/shape" type="Color" setter="" getter="">
+ The 3D editor gizmo color for [CollisionShape3D]s, [VehicleWheel3D]s, [RayCast3D]s and [SpringArm3D]s.
</member>
<member name="editors/animation/autorename_animation_tracks" type="bool" setter="" getter="">
+ If [code]true[/code], automatically updates animation tracks' target paths when renaming or reparenting nodes in the Scene tree dock.
</member>
<member name="editors/animation/confirm_insert_track" type="bool" setter="" getter="">
+ If [code]true[/code], display a confirmation dialog when adding a new track to an animation by pressing the "key" icon next to a property.
</member>
<member name="editors/animation/default_create_bezier_tracks" type="bool" setter="" getter="">
+ If [code]true[/code], create a Bezier track instead of a standard track when pressing the "key" icon next to a property. Bezier tracks provide more control over animation curves, but are more difficult to adjust quickly.
</member>
<member name="editors/animation/default_create_reset_tracks" type="bool" setter="" getter="">
+ If [code]true[/code], create a [code]RESET[/code] track when creating a new animation track. This track can be used to restore the animation to a "default" state.
</member>
<member name="editors/animation/onion_layers_future_color" type="Color" setter="" getter="">
+ The modulate color to use for "future" frames displayed in the animation editor's onion skinning feature.
</member>
<member name="editors/animation/onion_layers_past_color" type="Color" setter="" getter="">
+ The modulate color to use for "past" frames displayed in the animation editor's onion skinning feature.
</member>
<member name="editors/grid_map/pick_distance" type="float" setter="" getter="">
+ The maximum distance at which tiles can be placed on a GridMap, relative to the camera position (in 3D units).
</member>
<member name="editors/panning/2d_editor_pan_speed" type="int" setter="" getter="">
+ The panning speed when using the mouse wheel or touchscreen events in the 2D editor. This setting does not apply to panning by holding down the middle or right mouse buttons.
</member>
<member name="editors/panning/2d_editor_panning_scheme" type="int" setter="" getter="">
+ Controls whether the mouse wheel scroll zooms or pans in the 2D editor. See also [member editors/panning/sub_editors_panning_scheme] and [member editors/panning/animation_editors_panning_scheme].
</member>
<member name="editors/panning/animation_editors_panning_scheme" type="int" setter="" getter="">
+ Controls whether the mouse wheel scroll zooms or pans in the animation track and Bezier editors. See also [member editors/panning/2d_editor_panning_scheme] and [member editors/panning/sub_editors_panning_scheme] (which controls the animation blend tree editor's pan behavior).
</member>
<member name="editors/panning/simple_panning" type="bool" setter="" getter="">
+ If [code]true[/code], allows panning by holding down [kbd]Space[/kbd] in the 2D editor viewport (in addition to panning with the middle or right mouse buttons). If [code]false[/code], the left mouse button must be held down while holding down [kbd]Space[/kbd] to pan in the 2D editor viewport.
</member>
<member name="editors/panning/sub_editors_panning_scheme" type="int" setter="" getter="">
+ Controls whether the mouse wheel scroll zooms or pans in subeditors. The list of affected subeditors is: animation blend tree editor, [Polygon2D] editor, tileset editor, texture region editor, visual shader editor and visual script editor. See also [member editors/panning/2d_editor_panning_scheme] and [member editors/panning/animation_editors_panning_scheme].
</member>
<member name="editors/panning/warped_mouse_panning" type="bool" setter="" getter="">
+ If [code]true[/code], warps the mouse around the 2D viewport while panning in the 2D editor. This makes it possible to pan over a large area without having to exit panning then mouse the mouse back constantly.
</member>
<member name="editors/polygon_editor/point_grab_radius" type="int" setter="" getter="">
+ The radius in which points can be selected in the [Polygon2D] and [CollisionPolygon2D] editors (in pixels). Higher values make it easier to select points quickly, but can make it more difficult to select the expected point when several points are located close to each other.
</member>
<member name="editors/polygon_editor/show_previous_outline" type="bool" setter="" getter="">
+ If [code]true[/code], displays the polygon's previous shape in the 2D polygon editors with an opaque gray outline. This outline is displayed while dragging a point until the left mouse button is released.
</member>
<member name="editors/tiles_editor/display_grid" type="bool" setter="" getter="">
+ If [code]true[/code], displays a grid while the TileMap editor is active. See also [member editors/tiles_editor/grid_color].
</member>
<member name="editors/tiles_editor/grid_color" type="Color" setter="" getter="">
+ The color to use for the TileMap editor's grid.
+ [b]Note:[/b] Only effective if [member editors/tiles_editor/display_grid] is [code]true[/code].
</member>
<member name="editors/visual_editors/lines_curvature" type="float" setter="" getter="">
+ The curvature to use for connection lines in the visual script and visual shader editors. Higher values will make connection lines appear more curved, with values above [code]0.5[/code] resulting in more "angular" turns in the middle of connection lines.
</member>
<member name="editors/visual_editors/minimap_opacity" type="float" setter="" getter="">
+ The opacity of the minimap displayed in the bottom-right corner of the visual script and visual shader editors.
</member>
- <member name="editors/visual_editors/visualshader/port_preview_size" type="int" setter="" getter="">
+ <member name="editors/visual_editors/visual_shader/port_preview_size" type="int" setter="" getter="">
+ The size to use for port previews in the visual shader uniforms (toggled by clicking the "eye" icon next to an output). The value is defined in pixels at 100% zoom, and will scale with zoom automatically.
</member>
<member name="filesystem/directories/autoscan_project_path" type="String" setter="" getter="">
+ The folder where projects should be scanned for (recursively), in a way similar to the project manager's [b]Scan[/b]button. This can be set to the same value as [member filesystem/directories/default_project_path] for convenience.
+ [b]Note:[/b] Setting this path to a folder with very large amounts of files/folders can slow down the project manager startup significantly. To keep the project manager quick to start up, it is recommended to set this value to a folder as "specific" as possible.
</member>
<member name="filesystem/directories/default_project_path" type="String" setter="" getter="">
+ The folder where new projects should be created by default when clicking the project manager's [b]New Project[/b] button. This can be set to the same value as [member filesystem/directories/autoscan_project_path] for convenience.
</member>
<member name="filesystem/file_dialog/display_mode" type="int" setter="" getter="">
+ The display mode to use in the editor's file dialogs.
+ - [b]Thumbnails[/b] takes more space, but displays dynamic resource thumbnails, making resources easier to preview without having to open them.
+ - [b]List[/b] is more compact but doesn't display dynamic resource thumbnails. Instead, it displays static icons based on the file extension.
</member>
<member name="filesystem/file_dialog/show_hidden_files" type="bool" setter="" getter="">
+ If [code]true[/code], display hidden files in the editor's file dialogs. Files that have names starting with [code].[/code] are considered hidden (e.g. [code].hidden_file[/code]).
</member>
<member name="filesystem/file_dialog/thumbnail_size" type="int" setter="" getter="">
+ The thumbnail size to use in the editor's file dialogs (in pixels). See also [member docks/filesystem/thumbnail_size].
</member>
<member name="filesystem/on_save/compress_binary_resources" type="bool" setter="" getter="">
+ If [code]true[/code], uses lossless compression for binary resources.
</member>
<member name="filesystem/on_save/safe_save_on_backup_then_rename" type="bool" setter="" getter="">
+ If [code]true[/code], when saving a file, the editor will rename the old file to a different name, save a new file, then only remove the old file once the new file has been saved. This makes loss of data less likely to happen if the editor or operating system exits unexpectedly while saving (e.g. due to a crash or power outage).
+ [b]Note:[/b] On Windows, this feature can interact negatively with certain antivirus programs. In this case, you may have to set this to [code]false[/code] to prevent file locking issues.
</member>
<member name="interface/editor/automatically_open_screenshots" type="bool" setter="" getter="">
+ If [code]true[/code], automatically opens screenshots with the default program associated to [code].png[/code] files after a screenshot is taken using the [b]Editor &gt; Take Screenshot[/b] action.
</member>
<member name="interface/editor/code_font" type="String" setter="" getter="">
+ The font to use for the script editor. Must be a resource of a [Font] type such as a [code].ttf[/code] or [code].otf[/code] font file.
</member>
<member name="interface/editor/code_font_contextual_ligatures" type="int" setter="" getter="">
+ The font ligatures to enable for the currently configured code font. Not all fonts include support for ligatures.
+ [b]Note:[/b] The default editor code font ([url=https://www.jetbrains.com/lp/mono/]JetBrains Mono[/url]) has contextual ligatures in its font file.
</member>
<member name="interface/editor/code_font_custom_opentype_features" type="String" setter="" getter="">
+ List of custom OpenType features to use, if supported by the currently configured code font. Not all fonts include support for custom OpenType features. The string should follow the OpenType specification.
+ [b]Note:[/b] The default editor code font ([url=https://www.jetbrains.com/lp/mono/]JetBrains Mono[/url]) has custom OpenType features in its font file, but there is no documented list yet.
</member>
<member name="interface/editor/code_font_custom_variations" type="String" setter="" getter="">
+ List of alternative characters to use, if supported by the currently configured code font. Not all fonts include support for custom variations. The string should follow the OpenType specification.
+ [b]Note:[/b] The default editor code font ([url=https://www.jetbrains.com/lp/mono/]JetBrains Mono[/url]) has alternate characters in its font file, but there is no documented list yet.
</member>
<member name="interface/editor/code_font_size" type="int" setter="" getter="">
+ The size of the font in the script editor. This setting does not impact the font size of the Output panel (see [member run/output/font_size]).
</member>
<member name="interface/editor/custom_display_scale" type="float" setter="" getter="">
+ The custom editor scale factor to use. This can be used for displays with very high DPI where a scale factor of 200% is not sufficient.
+ [b]Note:[/b] Only effective if [member interface/editor/display_scale] is set to [b]Custom[/b].
</member>
<member name="interface/editor/debug/enable_pseudolocalization" type="bool" setter="" getter="">
+ If [code]true[/code], lengthens the editor's localizable strings and replaces their characters with accented variants. This allows spotting non-localizable strings easily, while also ensuring the UI layout doesn't break when strings are made longer (as many languages require strings to be longer).
+ This is a debugging feature and should only be enabled when working on the editor itself.
</member>
<member name="interface/editor/display_scale" type="int" setter="" getter="">
+ The display scale factor to use for the editor interface. Higher values are more suited to hiDPI/Retina displays.
+ If set to [b]Auto[/b], the editor scale is automatically determined based on the screen resolution and reported display DPI. This heuristic is not always ideal, which means you can get better results by setting the editor scale manually.
+ If set to [b]Custom[/b], the scaling value in [member interface/editor/custom_display_scale] will be used.
</member>
<member name="interface/editor/editor_language" type="String" setter="" getter="">
+ The language to use for the editor interface.
+ Translations are provided by the community. If you spot a mistake, [url=https://docs.godotengine.org/en/latest/community/contributing/editor_and_docs_localization.html]contribute to editor translations on Weblate![/url]
</member>
- <member name="interface/editor/font_antialiased" type="bool" setter="" getter="">
+ <member name="interface/editor/expand_to_title" type="bool" setter="" getter="">
+ Expanding main editor window content to the title, if supported by [DisplayServer]. See [constant DisplayServer.WINDOW_FLAG_EXTEND_TO_TITLE].
+ Specific to the macOS platform.
+ </member>
+ <member name="interface/editor/font_antialiasing" type="int" setter="" getter="">
+ FreeType's font anti-aliasing mode used to render the editor fonts. Most fonts are not designed to look good with anti-aliasing disabled, so it's recommended to leave this enabled unless you're using a pixel art font.
</member>
<member name="interface/editor/font_hinting" type="int" setter="" getter="">
+ The font hinting mode to use for the editor fonts. FreeType supports the following font hinting modes:
+ - [b]None:[/b] Don't use font hinting when rasterizing the font. This results in a smooth font, but it can look blurry.
+ - [b]Light:[/b] Use hinting on the X axis only. This is a compromise between font sharpness and smoothness.
+ - [b]Normal:[/b] Use hinting on both X and Y axes. This results in a sharp font, but it doesn't look very smooth.
+ If set to [b]Auto[/b], the font hinting mode will be set to match the current operating system in use. This means the [b]Light[/b] hinting mode will be used on Windows and Linux, and the [b]None[/b] hinting mode will be used on macOS.
</member>
<member name="interface/editor/font_subpixel_positioning" type="int" setter="" getter="">
+ The subpixel positioning mode to use when rendering editor font glyphs. This affects both the main and code fonts. [b]Disabled[/b] is the fastest to render and uses the least memory. [b]Auto[/b] only uses subpixel positioning for small font sizes (where the benefit is the most noticeable). [b]One half of a pixel[/b] and [b]One quarter of a pixel[/b] force the same subpixel positioning mode for all editor fonts, regardless of their size (with [b]One quarter of a pixel[/b] being the highest-quality option).
</member>
<member name="interface/editor/low_processor_mode_sleep_usec" type="float" setter="" getter="">
+ The amount of sleeping between frames when the low-processor usage mode is enabled (in microseconds). Higher values will result in lower CPU/GPU usage, which can improve battery life on laptops. However, higher values will result in a less responsive editor. The default value is set to allow for maximum smoothness on monitors up to 144 Hz. See also [member interface/editor/unfocused_low_processor_mode_sleep_usec].
</member>
<member name="interface/editor/main_font" type="String" setter="" getter="">
+ The font to use for the editor interface. Must be a resource of a [Font] type such as a [code].ttf[/code] or [code].otf[/code] font file.
</member>
<member name="interface/editor/main_font_bold" type="String" setter="" getter="">
+ The font to use for bold text in the editor interface. Must be a resource of a [Font] type such as a [code].ttf[/code] or [code].otf[/code] font file.
</member>
<member name="interface/editor/main_font_size" type="int" setter="" getter="">
+ The size of the font in the editor interface.
</member>
<member name="interface/editor/mouse_extra_buttons_navigate_history" type="bool" setter="" getter="">
+ If [code]true[/code], the mouse's additional side buttons will be usable to navigate in the script editor's file history. Set this to [code]false[/code] if you're using the side buttons for other purposes (such as a push-to-talk button in a VoIP program).
</member>
<member name="interface/editor/save_each_scene_on_quit" type="bool" setter="" getter="">
+ If [code]true[/code], the editor will save all scenes when confirming the [b]Save[/b] action when quitting the editor or quitting to the project list. If [code]false[/code], the editor will ask to save each scene individually.
</member>
<member name="interface/editor/separate_distraction_mode" type="bool" setter="" getter="">
+ If [code]true[/code], the editor's Script tab will have a separate distraction mode setting from the 2D/3D/AssetLib tabs. If [code]false[/code], the distraction-free mode toggle is shared between all tabs.
</member>
<member name="interface/editor/show_internal_errors_in_toast_notifications" type="int" setter="" getter="">
+ If enabled, displays internal engine errors in toast notifications (toggleable by clicking the "bell" icon at the bottom of the editor). No matter the value of this setting, non-internal engine errors will always be visible in toast notifications.
+ The default [b]Auto[/b] value will only enable this if the editor was compiled with the [code]dev=yes[/code] option (the default is [code]dev=no[/code]).
</member>
<member name="interface/editor/single_window_mode" type="bool" setter="" getter="">
+ If [code]true[/code], embed modal windows such as docks inside the main editor window. When single-window mode is enabled, tooltips will also be embedded inside the main editor window, which means they can't be displayed outside of the editor window.
</member>
<member name="interface/editor/unfocused_low_processor_mode_sleep_usec" type="float" setter="" getter="">
+ When the editor window is unfocused, the amount of sleeping between frames when the low-processor usage mode is enabled (in microseconds). Higher values will result in lower CPU/GPU usage, which can improve battery life on laptops (in addition to improving the running project's performance if the editor has to redraw continuously). However, higher values will result in a less responsive editor. The default value is set to limit the editor to 20 FPS when the editor window is unfocused. See also [member interface/editor/low_processor_mode_sleep_usec].
+ </member>
+ <member name="interface/editor/use_embedded_menu" type="bool" setter="" getter="">
+ If [code]true[/code], editor main menu is using embedded [MenuBar] instead of system global menu.
+ Specific to the macOS platform.
</member>
<member name="interface/inspector/max_array_dictionary_items_per_page" type="int" setter="" getter="">
+ The number of [Array] or [Dictionary] items to display on each "page" in the inspector. Higher values allow viewing more values per page, but take more time to load. This increased load time is noticeable when selecting nodes that have array or dictionary properties in the editor.
</member>
<member name="interface/inspector/show_low_level_opentype_features" type="bool" setter="" getter="">
+ If [code]true[/code], display OpenType features marked as [code]hidden[/code] by the font file in the [Font] editor.
</member>
<member name="interface/scene_tabs/display_close_button" type="int" setter="" getter="">
+ Controls when the Close (X) button is displayed on scene tabs at the top of the editor.
</member>
<member name="interface/scene_tabs/maximum_width" type="int" setter="" getter="">
+ The maximum width of each scene tab at the top editor (in pixels).
</member>
<member name="interface/scene_tabs/show_script_button" type="bool" setter="" getter="">
+ If [code]true[/code], show a button next to each scene tab that opens the scene's "dominant" script when clicked. The "dominant" script is the one that is at the highest level in the scene's hierarchy.
</member>
<member name="interface/scene_tabs/show_thumbnail_on_hover" type="bool" setter="" getter="">
+ If [code]true[/code], display an automatically-generated thumbnail when hovering scene tabs with the mouse. Scene thumbnails are generated when saving the scene.
</member>
<member name="interface/theme/accent_color" type="Color" setter="" getter="">
+ The color to use for "highlighted" user interface elements in the editor (pressed and hovered items).
</member>
<member name="interface/theme/additional_spacing" type="float" setter="" getter="">
+ The spacing to add for buttons and list items in the editor (in pixels). Increasing this value is useful to improve usability on touch screens, at the cost of reducing the amount of usable screen real estate.
</member>
<member name="interface/theme/base_color" type="Color" setter="" getter="">
+ The base color to use for user interface elements in the editor. Secondary colors (such as darker/lighter variants) are derived from this color.
</member>
<member name="interface/theme/border_size" type="int" setter="" getter="">
+ The border size to use for interface elements (in pixels).
</member>
<member name="interface/theme/contrast" type="float" setter="" getter="">
+ The contrast factor to use when deriving the editor theme's base color (see [member interface/theme/base_color]). When using a positive values, the derived colors will be [i]darker[/i] than the base color. This contrast factor can be set to a negative value, which will make the derived colors [i]brighter[/i] than the base color. Negative contrast rates often look better for light themes.
</member>
<member name="interface/theme/corner_radius" type="int" setter="" getter="">
+ The corner radius to use for interface elements (in pixels). [code]0[/code] is square.
</member>
<member name="interface/theme/custom_theme" type="String" setter="" getter="">
+ The custom theme resource to use for the editor. Must be a Godot theme resource in [code].tres[/code] or [code].res[/code] format.
</member>
<member name="interface/theme/icon_and_font_color" type="int" setter="" getter="">
+ The icon and font color scheme to use in the editor.
+ - [b]Auto[/b] determines the color scheme to use automatically based on [member interface/theme/base_color].
+ - [b]Dark[/b] makes fonts and icons light (suitable for dark themes).
+ - [b]Light[/b] makes fonts and icons dark (suitable for light themes). Icon colors are automatically converted by the editor following [url=https://github.com/godotengine/godot/blob/master/editor/editor_themes.cpp#L135]this set of rules[/url].
</member>
<member name="interface/theme/icon_saturation" type="float" setter="" getter="">
+ The saturation to use for editor icons. Higher values result in more vibrant colors.
+ [b]Note:[/b] The default editor icon saturation was increased by 30% in Godot 4.0 and later. To get Godot 3.x's icon saturation back, set [member interface/theme/icon_saturation] to [code]0.77[/code].
</member>
<member name="interface/theme/preset" type="String" setter="" getter="">
+ The editor theme preset to use.
</member>
<member name="interface/theme/relationship_line_opacity" type="float" setter="" getter="">
+ The opacity to use when drawing relationship lines in the editor's [Tree]-based GUIs (such as the Scene tree dock).
</member>
<member name="network/debug/remote_host" type="String" setter="" getter="">
+ The address to listen to when starting the remote debugger. This can be set to [code]0.0.0.0[/code] to allow external clients to connect to the remote debugger (instead of restricting the remote debugger to connections from [code]localhost[/code]).
</member>
<member name="network/debug/remote_port" type="int" setter="" getter="">
+ The port to listen to when starting the remote debugger. Godot will try to use port numbers above the configured number if the configured number is already taken by another application.
</member>
<member name="network/http_proxy/host" type="String" setter="" getter="">
+ The host to use to contact the HTTP and HTTPS proxy in the editor (for the asset library and export template downloads). See also [member network/http_proxy/port].
+ [b]Note:[/b] Godot currently doesn't automatically use system proxy settings, so you have to enter them manually here if needed.
</member>
<member name="network/http_proxy/port" type="int" setter="" getter="">
+ The port number to use to contact the HTTP and HTTPS proxy in the editor (for the asset library and export template downloads). See also [member network/http_proxy/host].
+ [b]Note:[/b] Godot currently doesn't automatically use system proxy settings, so you have to enter them manually here if needed.
</member>
<member name="network/ssl/editor_ssl_certificates" type="String" setter="" getter="">
+ The SSL certificate bundle to use for HTTP requests made within the editor (e.g. from the AssetLib tab). If left empty, the [url=https://github.com/godotengine/godot/blob/master/thirdparty/certs/ca-certificates.crt]included Mozilla certificate bundle[/url] will be used.
</member>
<member name="project_manager/sorting_order" type="int" setter="" getter="">
+ The sorting order to use in the project manager. When changing the sorting order in the project manager, this setting is set permanently in the editor settings.
</member>
<member name="run/auto_save/save_before_running" type="bool" setter="" getter="">
+ If [code]true[/code], saves all scenes and scripts automatically before running the project. Setting this to [code]false[/code] prevents the editor from saving if there are no changes which can speed up the project startup slightly, but it makes it possible to run a project that has unsaved changes. (Unsaved changes will not be visible in the running project.)
</member>
<member name="run/output/always_clear_output_on_play" type="bool" setter="" getter="">
+ If [code]true[/code], the editor will clear the Output panel when running the project.
</member>
<member name="run/output/always_close_output_on_stop" type="bool" setter="" getter="">
+ If [code]true[/code], the editor will collapse the Output panel when stopping the project.
</member>
<member name="run/output/always_open_output_on_play" type="bool" setter="" getter="">
+ If [code]true[/code], the editor will expand the Output panel when running the project.
</member>
<member name="run/output/font_size" type="int" setter="" getter="">
+ The size of the font in the [b]Output[/b] panel at the bottom of the editor. This setting does not impact the font size of the script editor (see [member interface/editor/code_font_size]).
</member>
<member name="run/window_placement/rect" type="int" setter="" getter="">
+ The window mode to use to display the project when starting the project from the editor.
</member>
<member name="run/window_placement/rect_custom_position" type="Vector2" setter="" getter="">
+ The custom position to use when starting the project from the editor (in pixels from the top-left corner). Only effective if [member run/window_placement/rect] is set to [b]Custom Position[/b].
</member>
<member name="run/window_placement/screen" type="int" setter="" getter="">
+ The monitor to display the project on when starting the project from the editor.
</member>
<member name="text_editor/appearance/caret/caret_blink" type="bool" setter="" getter="">
+ If [code]true[/code], makes the caret blink according to [member text_editor/appearance/caret/caret_blink_speed]. Disabling this setting can improve battery life on laptops if you spend long amounts of time in the script editor, since it will reduce the frequency at which the editor needs to be redrawn.
</member>
<member name="text_editor/appearance/caret/caret_blink_speed" type="float" setter="" getter="">
+ The interval at which to blink the caret (in seconds). See also [member text_editor/appearance/caret/caret_blink].
</member>
<member name="text_editor/appearance/caret/highlight_all_occurrences" type="bool" setter="" getter="">
+ If [code]true[/code], highlights all occurrences of the currently selected text in the script editor. See also [member text_editor/theme/highlighting/word_highlighted_color].
</member>
<member name="text_editor/appearance/caret/highlight_current_line" type="bool" setter="" getter="">
+ If [code]true[/code], colors the background of the line the caret is currently on with [member text_editor/theme/highlighting/current_line_color].
</member>
<member name="text_editor/appearance/caret/type" type="int" setter="" getter="">
+ The shape of the caret to use in the script editor. [b]Line[/b] displays a vertical line to the left of the current character, whereas [b]Block[/b] displays a outline over the current character.
</member>
<member name="text_editor/appearance/guidelines/line_length_guideline_hard_column" type="int" setter="" getter="">
+ The column at which to display a subtle line as a line length guideline for scripts. This should generally be greater than [member text_editor/appearance/guidelines/line_length_guideline_soft_column].
</member>
<member name="text_editor/appearance/guidelines/line_length_guideline_soft_column" type="int" setter="" getter="">
+ The column at which to display a [i]very[/i] subtle line as a line length guideline for scripts. This should generally be lower than [member text_editor/appearance/guidelines/line_length_guideline_hard_column].
</member>
<member name="text_editor/appearance/guidelines/show_line_length_guidelines" type="bool" setter="" getter="">
+ If [code]true[/code], displays line length guidelines to help you keep line lengths in check. See also [member text_editor/appearance/guidelines/line_length_guideline_soft_column] and [member text_editor/appearance/guidelines/line_length_guideline_hard_column].
</member>
<member name="text_editor/appearance/gutters/highlight_type_safe_lines" type="bool" setter="" getter="">
+ If [code]true[/code], highlights type-safe lines by displaying their line number color with [member text_editor/theme/highlighting/safe_line_number_color] instead of [member text_editor/theme/highlighting/line_number_color]. Type-safe lines are lines of code where the type of all variables is known at compile-time. These type-safe lines will run faster in Godot 4.0 and later thanks to typed instructions.
</member>
<member name="text_editor/appearance/gutters/line_numbers_zero_padded" type="bool" setter="" getter="">
+ If [code]true[/code], displays line numbers with zero padding (e.g. [code]007[/code] instead of [code]7[/code]).
</member>
<member name="text_editor/appearance/gutters/show_bookmark_gutter" type="bool" setter="" getter="">
+ If [code]true[/code], displays a gutter at the left containing icons for bookmarks.
</member>
<member name="text_editor/appearance/gutters/show_info_gutter" type="bool" setter="" getter="">
+ If [code]true[/code], displays a gutter at the left containing icons for methods with signal connections.
</member>
<member name="text_editor/appearance/gutters/show_line_numbers" type="bool" setter="" getter="">
+ If [code]true[/code], displays line numbers in the gutter at the left.
</member>
<member name="text_editor/appearance/lines/code_folding" type="bool" setter="" getter="">
+ If [code]true[/code], displays the folding arrows next to indented code sections and allows code folding. If [code]false[/code], hides the folding arrows next to indented code sections and disallows code folding.
</member>
<member name="text_editor/appearance/lines/word_wrap" type="int" setter="" getter="">
+ If [code]true[/code], wraps long lines over multiple lines to avoid horizontal scrolling. This is a display-only feature; it does not actually insert line breaks in your scripts.
</member>
<member name="text_editor/appearance/minimap/minimap_width" type="int" setter="" getter="">
+ The width of the minimap in the script editor (in pixels).
</member>
<member name="text_editor/appearance/minimap/show_minimap" type="bool" setter="" getter="">
+ If [code]true[/code], draws an overview of the script near the scroll bar. The minimap can be left-clicked to scroll directly to a location in an "absolute" manner.
</member>
<member name="text_editor/appearance/whitespace/draw_spaces" type="bool" setter="" getter="">
+ If [code]true[/code], draws space characters as centered points.
</member>
<member name="text_editor/appearance/whitespace/draw_tabs" type="bool" setter="" getter="">
+ If [code]true[/code], draws tab characters as chevrons.
</member>
<member name="text_editor/appearance/whitespace/line_spacing" type="int" setter="" getter="">
+ The space to add between lines (in pixels). Greater line spacing can help improve readability at the cost of displaying fewer lines on screen.
</member>
<member name="text_editor/behavior/files/auto_reload_scripts_on_external_change" type="bool" setter="" getter="">
+ If [code]true[/code], automatically reloads scripts in the editor when they have been modified and saved by external editors.
</member>
<member name="text_editor/behavior/files/autosave_interval_secs" type="int" setter="" getter="">
+ If set to a value greater than [code]0[/code], automatically saves the current script following the specified interval (in seconds). This can be used to prevent data loss if the editor crashes.
</member>
<member name="text_editor/behavior/files/convert_indent_on_save" type="bool" setter="" getter="">
+ If [code]true[/code], converts indentation to match the script editor's indentation settings when saving a script. See also [member text_editor/behavior/indent/type].
</member>
<member name="text_editor/behavior/files/restore_scripts_on_load" type="bool" setter="" getter="">
+ If [code]true[/code], reopens scripts that were opened in the last session when the editor is reopened on a given project.
</member>
<member name="text_editor/behavior/files/trim_trailing_whitespace_on_save" type="bool" setter="" getter="">
+ If [code]true[/code], trims trailing whitespace when saving a script. Trailing whitespace refers to tab and space characters placed at the end of lines. Since these serve no practical purpose, they can and should be removed to make version control diffs less noisy.
</member>
<member name="text_editor/behavior/indent/auto_indent" type="bool" setter="" getter="">
+ If [code]true[/code], automatically indents code when pressing the [kbd]Enter[/kbd] key based on blocks above the new line.
</member>
<member name="text_editor/behavior/indent/size" type="int" setter="" getter="">
+ When using tab indentation, determines the length of each tab. When using space indentation, determines how many spaces are inserted when pressing [kbd]Tab[/kbd] and when automatic indentation is performed.
</member>
<member name="text_editor/behavior/indent/type" type="int" setter="" getter="">
+ The indentation style to use (tabs or spaces).
+ [b]Note:[/b] The [url=https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/gdscript_styleguide.html]GDScript style guide[/url] recommends using tabs for indentation. It is advised to change this setting only if you need to work on a project that currently uses spaces for indentation.
</member>
<member name="text_editor/behavior/navigation/drag_and_drop_selection" type="bool" setter="" getter="">
+ If [code]true[/code], allows drag-and-dropping text in the script editor to move text. Disable this if you find yourself accidentally drag-and-dropping text in the script editor.
</member>
<member name="text_editor/behavior/navigation/move_caret_on_right_click" type="bool" setter="" getter="">
+ If [code]true[/code], the caret will be moved when right-clicking somewhere in the script editor (like when left-clicking or middle-clicking). If [code]false[/code], the caret will only be moved when left-clicking or middle-clicking somewhere.
</member>
<member name="text_editor/behavior/navigation/scroll_past_end_of_file" type="bool" setter="" getter="">
+ If [code]true[/code], allows scrolling past the end of the file.
</member>
<member name="text_editor/behavior/navigation/smooth_scrolling" type="bool" setter="" getter="">
+ If [code]true[/code], allows scrolling in sub-line intervals and enables a smooth scrolling animation when using the mouse wheel to scroll.
+ [b]Note:[/b] [member text_editor/behavior/navigation/smooth_scrolling] currently behaves poorly in projects where [member ProjectSettings.physics/common/physics_ticks_per_second] has been increased significantly from its default value ([code]60[/code]). In this case, it is recommended to disable this setting.
</member>
<member name="text_editor/behavior/navigation/stay_in_script_editor_on_node_selected" type="bool" setter="" getter="">
+ If [code]true[/code], prevents automatically switching between the Script and 2D/3D screens when selecting a node in the Scene tree dock.
</member>
<member name="text_editor/behavior/navigation/v_scroll_speed" type="int" setter="" getter="">
+ The number of pixels to scroll with every mouse wheel increment. Higher values make the script scroll by faster when using the mouse wheel.
+ [b]Note:[/b] You can hold down [kbd]Alt[/kbd] while using the mouse wheel to temporarily scroll 5 times faster.
</member>
<member name="text_editor/completion/add_type_hints" type="bool" setter="" getter="">
+ If [code]true[/code], adds static typing hints such as [code]-&gt; void[/code] and [code]: int[/code] when performing method definition autocompletion.
</member>
<member name="text_editor/completion/auto_brace_complete" type="bool" setter="" getter="">
+ If [code]true[/code], automatically completes braces when making use of code completion.
</member>
<member name="text_editor/completion/code_complete_delay" type="float" setter="" getter="">
+ The delay in seconds after which autocompletion suggestions should be displayed when the user stops typing.
</member>
<member name="text_editor/completion/complete_file_paths" type="bool" setter="" getter="">
+ If [code]true[/code], provides autocompletion suggestions for file paths in methods such as [code]load()[/code] and [code]preload()[/code].
</member>
<member name="text_editor/completion/idle_parse_delay" type="float" setter="" getter="">
+ The delay in seconds after which the script editor should check for errors when the user stops typing.
</member>
<member name="text_editor/completion/put_callhint_tooltip_below_current_line" type="bool" setter="" getter="">
+ If [code]true[/code], the code completion tooltip will appear below the current line unless there is no space on screen below the current line. If [code]false[/code], the code completion tooltip will appear above the current line.
</member>
<member name="text_editor/completion/use_single_quotes" type="bool" setter="" getter="">
+ If [code]true[/code], performs string autocompletion with single quotes. If [code]false[/code], performs string autocompletion with double quotes (which matches the [url=https://docs.godotengine.org/en/latest/tutorials/scripting/gdscript/gdscript_styleguide.html]GDScript style guide[/url]).
</member>
<member name="text_editor/help/class_reference_examples" type="int" setter="" getter="">
+ Controls which multi-line code blocks should be displayed in the editor help. This setting does not affect single-line code literals in the editor help.
</member>
<member name="text_editor/help/help_font_size" type="int" setter="" getter="">
+ The font size to use for the editor help (built-in class reference).
</member>
<member name="text_editor/help/help_source_font_size" type="int" setter="" getter="">
+ The font size to use for code samples in the editor help (built-in class reference).
</member>
<member name="text_editor/help/help_title_font_size" type="int" setter="" getter="">
+ The font size to use for headings in the editor help (built-in class reference).
</member>
<member name="text_editor/help/show_help_index" type="bool" setter="" getter="">
+ If [code]true[/code], displays a table of contents at the left of the editor help (at the location where the members overview would appear when editing a script).
</member>
<member name="text_editor/script_list/show_members_overview" type="bool" setter="" getter="">
+ If [code]true[/code], displays an overview of the current script's member variables and functions at the left of the script editor. See also [member text_editor/script_list/sort_members_outline_alphabetically].
</member>
<member name="text_editor/script_list/sort_members_outline_alphabetically" type="bool" setter="" getter="">
+ If [code]true[/code], sorts the members outline (located at the left of the script editor) using alphabetical order. If [code]false[/code], sorts the members outline depending on the order in which members are found in the script.
+ [b]Note:[/b] Only effective if [member text_editor/script_list/show_members_overview] is [code]true[/code].
</member>
<member name="text_editor/theme/color_theme" type="String" setter="" getter="">
+ The syntax theme to use in the script editor.
+ You can save your own syntax theme from your current settings by using [b]File &gt; Theme &gt; Save As...[/b] at the top of the script editor. The syntax theme will then be available locally in the list of color themes.
+ You can find additional syntax themes to install in the [url=https://github.com/godotengine/godot-syntax-themes]godot-syntax-themes[/url] repository.
</member>
<member name="text_editor/theme/highlighting/background_color" type="Color" setter="" getter="">
+ The script editor's background color. If set to a translucent color, the editor theme's base color will be visible behind.
</member>
<member name="text_editor/theme/highlighting/base_type_color" type="Color" setter="" getter="">
+ The script editor's base type color (used for types like [Vector2], [Vector3], ...).
</member>
<member name="text_editor/theme/highlighting/bookmark_color" type="Color" setter="" getter="">
+ The script editor's bookmark icon color (displayed in the gutter).
</member>
<member name="text_editor/theme/highlighting/brace_mismatch_color" type="Color" setter="" getter="">
+ The script editor's brace mismatch color. Used when the caret is currently on a mismatched brace, parenthesis or bracket character.
</member>
<member name="text_editor/theme/highlighting/breakpoint_color" type="Color" setter="" getter="">
+ The script editor's breakpoint icon color (displayed in the gutter).
</member>
<member name="text_editor/theme/highlighting/caret_background_color" type="Color" setter="" getter="">
+ The script editor's caret background color.
+ [b]Note:[/b] This setting has no effect as it's currently unused.
</member>
<member name="text_editor/theme/highlighting/caret_color" type="Color" setter="" getter="">
+ The script editor's caret color.
</member>
<member name="text_editor/theme/highlighting/code_folding_color" type="Color" setter="" getter="">
+ The script editor's color for the code folding icon (displayed in the gutter).
</member>
<member name="text_editor/theme/highlighting/comment_color" type="Color" setter="" getter="">
+ The script editor's comment color.
+ [b]Note:[/b] In GDScript, unlike Python, multiline strings are not considered to be comments, and will use the string highlighting color instead.
</member>
<member name="text_editor/theme/highlighting/completion_background_color" type="Color" setter="" getter="">
+ The script editor's autocompletion box background color.
</member>
<member name="text_editor/theme/highlighting/completion_existing_color" type="Color" setter="" getter="">
+ The script editor's autocompletion box background color to highlight existing characters in the completion results. This should be a translucent color so that [member text_editor/theme/highlighting/completion_selected_color] can be seen behind.
</member>
<member name="text_editor/theme/highlighting/completion_font_color" type="Color" setter="" getter="">
+ The script editor's autocompletion box text color.
</member>
<member name="text_editor/theme/highlighting/completion_scroll_color" type="Color" setter="" getter="">
+ The script editor's autocompletion box scroll bar color.
</member>
<member name="text_editor/theme/highlighting/completion_scroll_hovered_color" type="Color" setter="" getter="">
+ The script editor's autocompletion box scroll bar color when hovered or pressed with the mouse.
</member>
<member name="text_editor/theme/highlighting/completion_selected_color" type="Color" setter="" getter="">
+ The script editor's autocompletion box background color for the currently selected line.
</member>
<member name="text_editor/theme/highlighting/control_flow_keyword_color" type="Color" setter="" getter="">
+ The script editor's control flow keyword color (used for keywords like [code]if[/code], [code]for[/code], [code]return[/code], ...).
</member>
<member name="text_editor/theme/highlighting/current_line_color" type="Color" setter="" getter="">
+ The script editor's background color for the line the caret is currently on. This should be set to a translucent color so that it can display on top of other line color modifiers such as [member text_editor/theme/highlighting/mark_color].
</member>
<member name="text_editor/theme/highlighting/engine_type_color" type="Color" setter="" getter="">
+ The script editor's engine type color ([Vector2], [Vector3], [Color], ...).
</member>
<member name="text_editor/theme/highlighting/executing_line_color" type="Color" setter="" getter="">
+ The script editor's color for the debugger's executing line icon (displayed in the gutter).
</member>
<member name="text_editor/theme/highlighting/function_color" type="Color" setter="" getter="">
+ The script editor's function call color.
+ [b]Note:[/b] When using the GDScript syntax highlighter, this is replaced by the function definition color configured in the syntax theme for function definitions (e.g. [code]func _ready():[/code]).
</member>
<member name="text_editor/theme/highlighting/keyword_color" type="Color" setter="" getter="">
+ The script editor's non-control flow keyword color (used for keywords like [code]var[/code], [code]func[/code], some built-in methods, ...).
</member>
<member name="text_editor/theme/highlighting/line_length_guideline_color" type="Color" setter="" getter="">
+ The script editor's color for the line length guideline. The "hard" line length guideline will be drawn with this color, whereas the "soft" line length guideline will be drawn with an opacity twice as low.
</member>
<member name="text_editor/theme/highlighting/line_number_color" type="Color" setter="" getter="">
+ The script editor's color for line numbers. See also [member text_editor/theme/highlighting/safe_line_number_color].
</member>
<member name="text_editor/theme/highlighting/mark_color" type="Color" setter="" getter="">
+ The script editor's background color for lines with errors. This should be set to a translucent color so that it can display on top of other line color modifiers such as [member text_editor/theme/highlighting/current_line_color].
</member>
<member name="text_editor/theme/highlighting/member_variable_color" type="Color" setter="" getter="">
+ The script editor's color for member variables on objects (e.g. [code]self.some_property[/code]).
+ [b]Note:[/b] This color is not used for local variable declaration and access.
</member>
<member name="text_editor/theme/highlighting/number_color" type="Color" setter="" getter="">
+ The script editor's color for numbers (integer and floating-point).
</member>
<member name="text_editor/theme/highlighting/safe_line_number_color" type="Color" setter="" getter="">
+ The script editor's color for type-safe line numbers. See also [member text_editor/theme/highlighting/line_number_color].
+ [b]Note:[/b] Only displayed if [member text_editor/appearance/gutters/highlight_type_safe_lines] is [code]true[/code].
</member>
<member name="text_editor/theme/highlighting/search_result_border_color" type="Color" setter="" getter="">
+ The script editor's color for the border of search results. This border helps bring further attention to the search result. Set this color's opacity to 0 to disable the border.
</member>
<member name="text_editor/theme/highlighting/search_result_color" type="Color" setter="" getter="">
+ The script editor's background color for search results.
</member>
<member name="text_editor/theme/highlighting/selection_color" type="Color" setter="" getter="">
+ The script editor's background color for the currently selected text.
</member>
<member name="text_editor/theme/highlighting/string_color" type="Color" setter="" getter="">
+ The script editor's color for strings (single-line and multi-line).
</member>
<member name="text_editor/theme/highlighting/symbol_color" type="Color" setter="" getter="">
+ The script editor's color for operators ([code]( ) [ ] { } + - * /[/code], ...).
</member>
<member name="text_editor/theme/highlighting/text_color" type="Color" setter="" getter="">
+ The script editor's color for text not highlighted by any syntax highlighting rule.
</member>
<member name="text_editor/theme/highlighting/text_selected_color" type="Color" setter="" getter="">
+ The script editor's background color for text. This should be set to a translucent color so that it can display on top of other line color modifiers such as [member text_editor/theme/highlighting/current_line_color].
</member>
<member name="text_editor/theme/highlighting/user_type_color" type="Color" setter="" getter="">
+ The script editor's color for user-defined types (using [code]@class_name[/code]).
</member>
<member name="text_editor/theme/highlighting/word_highlighted_color" type="Color" setter="" getter="">
+ The script editor's color for words highlighted by selecting them. Only visible if [member text_editor/appearance/caret/highlight_all_occurrences] is [code]true[/code].
</member>
</members>
<signals>
diff --git a/doc/classes/EditorSyntaxHighlighter.xml b/doc/classes/EditorSyntaxHighlighter.xml
index 15b730acb4..51f4474fe7 100644
--- a/doc/classes/EditorSyntaxHighlighter.xml
+++ b/doc/classes/EditorSyntaxHighlighter.xml
@@ -17,7 +17,7 @@
</description>
</method>
<method name="_get_supported_languages" qualifiers="virtual const">
- <return type="Array" />
+ <return type="PackedStringArray" />
<description>
Virtual method which can be overridden to return the supported language names.
</description>
diff --git a/doc/classes/EditorTranslationParserPlugin.xml b/doc/classes/EditorTranslationParserPlugin.xml
index 84a671a93c..bbae06899c 100644
--- a/doc/classes/EditorTranslationParserPlugin.xml
+++ b/doc/classes/EditorTranslationParserPlugin.xml
@@ -111,9 +111,9 @@
</method>
<method name="_parse_file" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="msgids" type="Array" />
- <argument index="2" name="msgids_context_plural" type="Array" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="msgids" type="Array" />
+ <param index="2" name="msgids_context_plural" type="Array" />
<description>
Override this method to define a custom parsing logic to extract the translatable strings.
</description>
diff --git a/doc/classes/EditorUndoRedoManager.xml b/doc/classes/EditorUndoRedoManager.xml
new file mode 100644
index 0000000000..1350e4487c
--- /dev/null
+++ b/doc/classes/EditorUndoRedoManager.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="EditorUndoRedoManager" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Manages undo history of scenes opened in the editor.
+ </brief_description>
+ <description>
+ [EditorUndoRedoManager] is a manager for [UndoRedo] objects associated with edited scenes. Each scene has its own undo history and [EditorUndoRedoManager] ensures that each action performed in the editor gets associated with a proper scene. For actions not related to scenes ([ProjectSettings] edits, external resources, etc.), a separate global history is used.
+ The usage is mostly the same as [UndoRedo]. You create and commit actions and the manager automatically decides under-the-hood what scenes it belongs to. The scene is deduced based on the first operation in an action, using the object from the operation. The rules are as follows:
+ - If the object is a [Node], use the currently edited scene;
+ - If the object is a built-in resource, use the scene from its path;
+ - If the object is external resource or anything else, use global history.
+ This guessing can sometimes yield false results, so you can provide a custom context object when creating an action.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="add_do_method" qualifiers="vararg">
+ <return type="void" />
+ <param index="0" name="object" type="Object" />
+ <param index="1" name="method" type="StringName" />
+ <description>
+ Register a method that will be called when the action is committed (i.e. the "do" action).
+ If this is the first operation, the [param object] will be used to deduce target undo history.
+ </description>
+ </method>
+ <method name="add_do_property">
+ <return type="void" />
+ <param index="0" name="object" type="Object" />
+ <param index="1" name="property" type="StringName" />
+ <param index="2" name="value" type="Variant" />
+ <description>
+ Register a property value change for "do".
+ If this is the first operation, the [param object] will be used to deduce target undo history.
+ </description>
+ </method>
+ <method name="add_do_reference">
+ <return type="void" />
+ <param index="0" name="object" type="Object" />
+ <description>
+ Register a reference for "do" that will be erased if the "do" history is lost. This is useful mostly for new nodes created for the "do" call. Do not use for resources.
+ </description>
+ </method>
+ <method name="add_undo_method" qualifiers="vararg">
+ <return type="void" />
+ <param index="0" name="object" type="Object" />
+ <param index="1" name="method" type="StringName" />
+ <description>
+ Register a method that will be called when the action is undone (i.e. the "undo" action).
+ If this is the first operation, the [param object] will be used to deduce target undo history.
+ </description>
+ </method>
+ <method name="add_undo_property">
+ <return type="void" />
+ <param index="0" name="object" type="Object" />
+ <param index="1" name="property" type="StringName" />
+ <param index="2" name="value" type="Variant" />
+ <description>
+ Register a property value change for "undo".
+ If this is the first operation, the [param object] will be used to deduce target undo history.
+ </description>
+ </method>
+ <method name="add_undo_reference">
+ <return type="void" />
+ <param index="0" name="object" type="Object" />
+ <description>
+ Register a reference for "undo" that will be erased if the "undo" history is lost. This is useful mostly for nodes removed with the "do" call (not the "undo" call!).
+ </description>
+ </method>
+ <method name="commit_action">
+ <return type="void" />
+ <param index="0" name="execute" type="bool" default="true" />
+ <description>
+ Commit the action. If [param execute] is true (default), all "do" methods/properties are called/set when this function is called.
+ </description>
+ </method>
+ <method name="create_action">
+ <return type="void" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="merge_mode" type="int" enum="UndoRedo.MergeMode" default="0" />
+ <param index="2" name="custom_context" type="Object" default="null" />
+ <description>
+ Create a new action. After this is called, do all your calls to [method add_do_method], [method add_undo_method], [method add_do_property], and [method add_undo_property], then commit the action with [method commit_action].
+ The way actions are merged is dictated by the [param merge_mode] argument. See [enum UndoRedo.MergeMode] for details.
+ If [param custom_context] object is provided, it will be used for deducing target history (instead of using the first operation).
+ </description>
+ </method>
+ <method name="get_history_undo_redo" qualifiers="const">
+ <return type="UndoRedo" />
+ <param index="0" name="id" type="int" />
+ <description>
+ Returns the [UndoRedo] object associated with the given history [param id].
+ [param id] above [code]0[/code] are mapped to the opened scene tabs (but it doesn't match their order). [param id] of [code]0[/code] or lower have special meaning (see [enum SpecialHistory]).
+ Best used with [method get_object_history_id]. This method is only provided in case you need some more advanced methods of [UndoRedo] (but keep in mind that directly operating on the [UndoRedo] object might affect editor's stability).
+ </description>
+ </method>
+ <method name="get_object_history_id" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="object" type="Object" />
+ <description>
+ Returns the history ID deduced from the given [param object]. It can be used with [method get_history_undo_redo].
+ </description>
+ </method>
+ <method name="is_committing_action" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if the [EditorUndoRedoManager] is currently committing the action, i.e. running its "do" method or property change (see [method commit_action]).
+ </description>
+ </method>
+ </methods>
+ <constants>
+ <constant name="GLOBAL_HISTORY" value="0" enum="SpecialHistory">
+ Global history not associated with any scene, but with external resources etc.
+ </constant>
+ <constant name="INVALID_HISTORY" value="-99" enum="SpecialHistory">
+ Invalid "null" history. It's a special value, not associated with any object.
+ </constant>
+ </constants>
+</class>
diff --git a/doc/classes/EditorVCSInterface.xml b/doc/classes/EditorVCSInterface.xml
index 0215d81a4e..89ba79f7d9 100644
--- a/doc/classes/EditorVCSInterface.xml
+++ b/doc/classes/EditorVCSInterface.xml
@@ -11,14 +11,14 @@
<methods>
<method name="commit">
<return type="void" />
- <argument index="0" name="msg" type="String" />
+ <param index="0" name="msg" type="String" />
<description>
Creates a version commit if the addon is initialized, else returns without doing anything. Uses the files which have been staged previously, with the commit message set to a value as provided as in the argument.
</description>
</method>
<method name="get_file_diff">
- <return type="Array" />
- <argument index="0" name="file_path" type="String" />
+ <return type="Dictionary[]" />
+ <param index="0" name="file_path" type="String" />
<description>
Returns an [Array] of [Dictionary] objects containing the diff output from the VCS in use, if a VCS addon is initialized, else returns an empty [Array] object. The diff contents also consist of some contextual lines which provide context to the observed line change in the file.
Each [Dictionary] object has the line diff contents under the keys:
@@ -56,7 +56,7 @@
</method>
<method name="initialize">
<return type="bool" />
- <argument index="0" name="project_root_path" type="String" />
+ <param index="0" name="project_root_path" type="String" />
<description>
Initializes the VCS addon if not already. Uses the argument value as the path to the working directory of the project. Creates the initial commit if required. Returns [code]true[/code] if no failure occurs, else returns [code]false[/code].
</description>
@@ -81,14 +81,14 @@
</method>
<method name="stage_file">
<return type="void" />
- <argument index="0" name="file_path" type="String" />
+ <param index="0" name="file_path" type="String" />
<description>
Stages the file which should be committed when [method EditorVCSInterface.commit] is called. Argument should contain the absolute path.
</description>
</method>
<method name="unstage_file">
<return type="void" />
- <argument index="0" name="file_path" type="String" />
+ <param index="0" name="file_path" type="String" />
<description>
Unstages the file which was staged previously to be committed, so that it is no longer committed when [method EditorVCSInterface.commit] is called. Argument should contain the absolute path.
</description>
diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml
index 36dfee833b..301a3e55fb 100644
--- a/doc/classes/Engine.xml
+++ b/doc/classes/Engine.xml
@@ -9,6 +9,20 @@
<tutorials>
</tutorials>
<methods>
+ <method name="get_architecture_name" qualifiers="const">
+ <return type="String" />
+ <description>
+ Returns the name of the CPU architecture the Godot binary was built for. Possible return values are [code]x86_64[/code], [code]x86_32[/code], [code]arm64[/code], [code]armv7[/code], [code]rv64[/code], [code]riscv[/code], [code]ppc64[/code], [code]ppc[/code], [code]wasm64[/code] and [code]wasm32[/code].
+ To detect whether the current CPU architecture is 64-bit, you can use the fact that all 64-bit architecture names have [code]64[/code] in their name:
+ [codeblock]
+ if "64" in Engine.get_architecture_name():
+ print("Running on 64-bit CPU.")
+ else:
+ print("Running on 32-bit CPU.")
+ [/codeblock]
+ [b]Note:[/b] [method get_architecture_name] does [i]not[/i] return the name of the host CPU architecture. For example, if running an x86_32 Godot binary on a x86_64 system, the returned value will be [code]x86_32[/code].
+ </description>
+ </method>
<method name="get_author_info" qualifiers="const">
<return type="Dictionary" />
<description>
@@ -20,7 +34,7 @@
</description>
</method>
<method name="get_copyright_info" qualifiers="const">
- <return type="Array" />
+ <return type="Dictionary[]" />
<description>
Returns an Array of copyright information Dictionaries.
[code]name[/code] - String, component name
@@ -96,7 +110,7 @@
</method>
<method name="get_script_language" qualifiers="const">
<return type="ScriptLanguage" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
</description>
</method>
@@ -107,9 +121,9 @@
</method>
<method name="get_singleton" qualifiers="const">
<return type="Object" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Returns a global singleton with given [code]name[/code]. Often used for plugins, e.g. GodotPayments.
+ Returns a global singleton with given [param name]. Often used for plugins, e.g. GodotPayments.
</description>
</method>
<method name="get_singleton_list" qualifiers="const">
@@ -159,9 +173,9 @@
</method>
<method name="has_singleton" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Returns [code]true[/code] if a singleton with given [code]name[/code] exists in global scope.
+ Returns [code]true[/code] if a singleton with given [param name] exists in global scope.
</description>
</method>
<method name="is_editor_hint" qualifiers="const">
@@ -186,20 +200,20 @@
</method>
<method name="register_script_language">
<return type="void" />
- <argument index="0" name="language" type="ScriptLanguage" />
+ <param index="0" name="language" type="ScriptLanguage" />
<description>
</description>
</method>
<method name="register_singleton">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="instance" type="Object" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="instance" type="Object" />
<description>
</description>
</method>
<method name="unregister_singleton">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
</description>
</method>
diff --git a/doc/classes/EngineDebugger.xml b/doc/classes/EngineDebugger.xml
index cd502dce81..176bc1f135 100644
--- a/doc/classes/EngineDebugger.xml
+++ b/doc/classes/EngineDebugger.xml
@@ -11,14 +11,14 @@
<methods>
<method name="has_capture">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<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" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
Returns [code]true[/code] if a profiler with the given name is present otherwise [code]false[/code].
</description>
@@ -31,65 +31,65 @@
</method>
<method name="is_profiling">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<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" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="data" type="Array" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="data" type="Array" />
<description>
- Calls the [code]add[/code] callable of the profiler with given [code]name[/code] and [code]data[/code].
+ Calls the [code]add[/code] callable of the profiler with given [param name] and [param data].
</description>
</method>
<method name="profiler_enable">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="enable" type="bool" />
- <argument index="2" name="arguments" type="Array" default="[]" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="enable" type="bool" />
+ <param index="2" name="arguments" type="Array" default="[]" />
<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.
+ Calls the [code]toggle[/code] callable of the profiler with given [param name] and [param arguments]. Enables/Disables the same profiler depending on [code]enable[/code] argument.
</description>
</method>
<method name="register_message_capture">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="callable" type="Callable" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="callable" type="Callable" />
<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.
+ Registers a message capture with given [param name]. If [param name] 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" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="profiler" type="EngineProfiler" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="profiler" type="EngineProfiler" />
<description>
- Registers a profiler with the given [code]name[/code]. See [EngineProfiler] for more information.
+ Registers a profiler with the given [param name]. See [EngineProfiler] for more information.
</description>
</method>
<method name="send_message">
<return type="void" />
- <argument index="0" name="message" type="String" />
- <argument index="1" name="data" type="Array" />
+ <param index="0" name="message" type="String" />
+ <param index="1" name="data" type="Array" />
<description>
- Sends a message with given [code]message[/code] and [code]data[/code] array.
+ Sends a message with given [param message] and [param data] array.
</description>
</method>
<method name="unregister_message_capture">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Unregisters the message capture with given [code]name[/code].
+ Unregisters the message capture with given [param name].
</description>
</method>
<method name="unregister_profiler">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Unregisters a profiler with given [code]name[/code].
+ Unregisters a profiler with given [param name].
</description>
</method>
</methods>
diff --git a/doc/classes/EngineProfiler.xml b/doc/classes/EngineProfiler.xml
index 752ecda867..a7a66c4564 100644
--- a/doc/classes/EngineProfiler.xml
+++ b/doc/classes/EngineProfiler.xml
@@ -12,27 +12,27 @@
<methods>
<method name="_add_frame" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="data" type="Array" />
+ <param index="0" name="data" type="Array" />
<description>
Called when data is added to profiler using [method EngineDebugger.profiler_add_frame_data].
</description>
</method>
<method name="_tick" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="frame_time" type="float" />
- <argument index="1" name="process_time" type="float" />
- <argument index="2" name="physics_time" type="float" />
- <argument index="3" name="physics_frame_time" type="float" />
+ <param index="0" name="frame_time" type="float" />
+ <param index="1" name="process_time" type="float" />
+ <param index="2" name="physics_time" type="float" />
+ <param index="3" name="physics_frame_time" type="float" />
<description>
Called once every engine iteration when the profiler is active with information about the current frame. All time values are in seconds. Lower values represent faster processing times and are therefore considered better.
</description>
</method>
<method name="_toggle" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="enable" type="bool" />
- <argument index="1" name="options" type="Array" />
+ <param index="0" name="enable" type="bool" />
+ <param index="1" name="options" type="Array" />
<description>
- Called when the profiler is enabled/disabled, along with a set of [code]options[/code].
+ Called when the profiler is enabled/disabled, along with a set of [param options].
</description>
</method>
</methods>
diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml
index 9da360915b..864dbd423a 100644
--- a/doc/classes/Environment.xml
+++ b/doc/classes/Environment.xml
@@ -20,17 +20,17 @@
<methods>
<method name="get_glow_level" qualifiers="const">
<return type="float" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the intensity of the glow level [code]idx[/code].
+ Returns the intensity of the glow level [param idx].
</description>
</method>
<method name="set_glow_level">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="intensity" type="float" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="intensity" type="float" />
<description>
- Sets the intensity of the glow level [code]idx[/code]. A value above [code]0.0[/code] enables the level. Each level relies on the previous level. This means that enabling higher glow levels will slow down the glow effect rendering, even if previous levels aren't enabled.
+ Sets the intensity of the glow level [param idx]. A value above [code]0.0[/code] enables the level. Each level relies on the previous level. This means that enabling higher glow levels will slow down the glow effect rendering, even if previous levels aren't enabled.
</description>
</method>
</methods>
@@ -97,7 +97,7 @@
Blend factor between the fog's color and the color of the background [Sky]. Must have [member background_mode] set to [constant BG_SKY].
This is useful to simulate [url=https://en.wikipedia.org/wiki/Aerial_perspective]aerial perspective[/url] in large scenes with low density fog. However, it is not very useful for high-density fog, as the sky will shine through. When set to [code]1.0[/code], the fog color comes completely from the [Sky]. If set to [code]0.0[/code], aerial perspective is disabled.
</member>
- <member name="fog_density" type="float" setter="set_fog_density" getter="get_fog_density" default="0.001">
+ <member name="fog_density" type="float" setter="set_fog_density" getter="get_fog_density" default="0.01">
The exponential fog density to use. Higher values result in a more dense fog.
</member>
<member name="fog_enabled" type="bool" setter="set_fog_enabled" getter="is_fog_enabled" default="false">
@@ -109,7 +109,7 @@
<member name="fog_height_density" type="float" setter="set_fog_height_density" getter="get_fog_height_density" default="0.0">
The density used to increase fog as height decreases. To make fog increase as height increases, use a negative value.
</member>
- <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 name="fog_light_color" type="Color" setter="set_fog_light_color" getter="get_fog_light_color" default="Color(0.518, 0.553, 0.608, 1)">
The fog's color.
</member>
<member name="fog_light_energy" type="float" setter="set_fog_light_energy" getter="get_fog_light_energy" default="1.0">
@@ -320,8 +320,9 @@
<member name="volumetric_fog_enabled" type="bool" setter="set_volumetric_fog_enabled" getter="is_volumetric_fog_enabled" default="false">
Enables the volumetric fog effect. Volumetric fog uses a screen-aligned froxel buffer to calculate accurate volumetric scattering in the short to medium range. Volumetric fog interacts with [FogVolume]s and lights to calculate localized and global fog. Volumetric fog uses a PBR single-scattering model based on extinction, scattering, and emission which it exposes to users as density, albedo, and emission.
</member>
- <member name="volumetric_fog_gi_inject" type="float" setter="set_volumetric_fog_gi_inject" getter="get_volumetric_fog_gi_inject" default="0.0">
- Scales the strength of Global Illumination used in the volumetric fog. A value of [code]0[/code] means that Global Illumination will not impact the volumetric fog.
+ <member name="volumetric_fog_gi_inject" type="float" setter="set_volumetric_fog_gi_inject" getter="get_volumetric_fog_gi_inject" default="1.0">
+ Scales the strength of Global Illumination used in the volumetric fog. A value of [code]0.0[/code] means that Global Illumination will not impact the volumetric fog.
+ [b]Note:[/b] Only [VoxelGI] and SDFGI ([member Environment.sdfgi_enabled]) are taken into account when using [member volumetric_fog_gi_inject]. Global illumination from [LightmapGI], [ReflectionProbe] and SSIL (see [member ssil_enabled]) will be ignored by volumetric fog.
</member>
<member name="volumetric_fog_length" type="float" setter="set_volumetric_fog_length" getter="get_volumetric_fog_length" default="64.0">
The distance over which the volumetric fog is computed. Increase to compute fog over a greater range, decrease to add more detail when a long range is not needed. For best quality fog, keep this as low as possible.
diff --git a/doc/classes/Expression.xml b/doc/classes/Expression.xml
index 50979c9b68..3a397f56a9 100644
--- a/doc/classes/Expression.xml
+++ b/doc/classes/Expression.xml
@@ -53,10 +53,10 @@
<methods>
<method name="execute">
<return type="Variant" />
- <argument index="0" name="inputs" type="Array" default="[]" />
- <argument index="1" name="base_instance" type="Object" default="null" />
- <argument index="2" name="show_error" type="bool" default="true" />
- <argument index="3" name="const_calls_only" type="bool" default="false" />
+ <param index="0" name="inputs" type="Array" default="[]" />
+ <param index="1" name="base_instance" type="Object" default="null" />
+ <param index="2" name="show_error" type="bool" default="true" />
+ <param index="3" name="const_calls_only" type="bool" default="false" />
<description>
Executes the expression that was previously parsed by [method parse] and returns the result. Before you use the returned object, you should check if the method failed by calling [method has_execute_failed].
If you defined input variables in [method parse], you can specify their values in the inputs array, in the same order.
@@ -76,11 +76,11 @@
</method>
<method name="parse">
<return type="int" enum="Error" />
- <argument index="0" name="expression" type="String" />
- <argument index="1" name="input_names" type="PackedStringArray" default="PackedStringArray()" />
+ <param index="0" name="expression" type="String" />
+ <param index="1" name="input_names" type="PackedStringArray" default="PackedStringArray()" />
<description>
Parses the expression and returns an [enum Error] code.
- You can optionally specify names of variables that may appear in the expression with [code]input_names[/code], so that you can bind them when it gets executed.
+ You can optionally specify names of variables that may appear in the expression with [param input_names], so that you can bind them when it gets executed.
</description>
</method>
</methods>
diff --git a/doc/classes/File.xml b/doc/classes/File.xml
index 0b4a8fa46e..76c6a4871c 100644
--- a/doc/classes/File.xml
+++ b/doc/classes/File.xml
@@ -76,7 +76,7 @@
</method>
<method name="file_exists" qualifiers="static">
<return type="bool" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Returns [code]true[/code] if the file exists in the given path.
[b]Note:[/b] Many resources types are imported (e.g. textures or sound files), and their source asset will not be included in the exported game, as only the imported version is used. See [method ResourceLoader.exists] for an alternative approach that takes resource remapping into account.
@@ -115,23 +115,24 @@
</method>
<method name="get_as_text" qualifiers="const">
<return type="String" />
+ <param index="0" name="skip_cr" type="bool" default="false" />
<description>
- Returns the whole file as a [String].
- Text is interpreted as being UTF-8 encoded.
+ Returns the whole file as a [String]. Text is interpreted as being UTF-8 encoded.
+ If [param skip_cr] is [code]true[/code], carriage return characters ([code]\r[/code], CR) will be ignored when parsing the UTF-8, so that only line feed characters ([code]\n[/code], LF) represent a new line (Unix convention).
</description>
</method>
<method name="get_buffer" qualifiers="const">
<return type="PackedByteArray" />
- <argument index="0" name="length" type="int" />
+ <param index="0" name="length" type="int" />
<description>
- Returns next [code]length[/code] bytes of the file as a [PackedByteArray].
+ Returns next [param length] bytes of the file as a [PackedByteArray].
</description>
</method>
<method name="get_csv_line" qualifiers="const">
<return type="PackedStringArray" />
- <argument index="0" name="delim" type="String" default="&quot;,&quot;" />
+ <param index="0" name="delim" type="String" default="&quot;,&quot;" />
<description>
- Returns the next value of the file in CSV (Comma-Separated Values) format. You can pass a different delimiter [code]delim[/code] to use other than the default [code]","[/code] (comma). This delimiter must be one-character long, and cannot be a double quotation mark.
+ Returns the next value of the file in CSV (Comma-Separated Values) format. You can pass a different delimiter [param delim] to use other than the default [code]","[/code] (comma). This delimiter must be one-character long, and cannot be a double quotation mark.
Text is interpreted as being UTF-8 encoded. Text values must be enclosed in double quotes if they include the delimiter character. Double quotes within a text value can be escaped by doubling their occurrence.
For example, the following CSV lines are valid and will be properly parsed as two strings each:
[codeblock]
@@ -175,16 +176,16 @@
</method>
<method name="get_md5" qualifiers="const">
<return type="String" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Returns an MD5 String representing the file at the given path or an empty [String] on failure.
</description>
</method>
<method name="get_modified_time" qualifiers="const">
<return type="int" />
- <argument index="0" name="file" type="String" />
+ <param index="0" name="file" type="String" />
<description>
- Returns the last time the [code]file[/code] was modified in Unix timestamp format or returns a [String] "ERROR IN [code]file[/code]". This Unix timestamp can be converted to another format using the [Time] singleton.
+ Returns the last time the [param file] was modified in Unix timestamp format or returns a [String] "ERROR IN [code]file[/code]". This Unix timestamp can be converted to another format using the [Time] singleton.
</description>
</method>
<method name="get_pascal_string">
@@ -220,16 +221,16 @@
</method>
<method name="get_sha256" qualifiers="const">
<return type="String" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Returns a SHA-256 [String] representing the file at the given path or an empty [String] on failure.
</description>
</method>
<method name="get_var" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="allow_objects" type="bool" default="false" />
+ <param index="0" name="allow_objects" type="bool" default="false" />
<description>
- Returns the next [Variant] value from the file. If [code]allow_objects[/code] is [code]true[/code], decoding objects is allowed.
+ Returns the next [Variant] value from the file. If [param allow_objects] is [code]true[/code], decoding objects is allowed.
[b]Warning:[/b] Deserialized objects can contain code which gets executed. Do not use this option if the serialized object comes from untrusted sources to avoid potential security threats such as remote code execution.
</description>
</method>
@@ -241,17 +242,17 @@
</method>
<method name="open">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="flags" type="int" enum="File.ModeFlags" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="flags" type="int" enum="File.ModeFlags" />
<description>
Opens the file for writing or reading, depending on the flags.
</description>
</method>
<method name="open_compressed">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="mode_flags" type="int" enum="File.ModeFlags" />
- <argument index="2" name="compression_mode" type="int" enum="File.CompressionMode" default="0" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="mode_flags" type="int" enum="File.ModeFlags" />
+ <param index="2" name="compression_mode" type="int" enum="File.CompressionMode" default="0" />
<description>
Opens a compressed file for reading or writing.
[b]Note:[/b] [method open_compressed] can only read files that were saved by Godot, not third-party compression formats. See [url=https://github.com/godotengine/godot/issues/28999]GitHub issue #28999[/url] for a workaround.
@@ -259,9 +260,9 @@
</method>
<method name="open_encrypted">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="mode_flags" type="int" enum="File.ModeFlags" />
- <argument index="2" name="key" type="PackedByteArray" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="mode_flags" type="int" enum="File.ModeFlags" />
+ <param index="2" name="key" type="PackedByteArray" />
<description>
Opens an encrypted file in write or read mode. You need to pass a binary key to encrypt/decrypt it.
[b]Note:[/b] The provided key must be 32 bytes long.
@@ -269,23 +270,23 @@
</method>
<method name="open_encrypted_with_pass">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="mode_flags" type="int" enum="File.ModeFlags" />
- <argument index="2" name="pass" type="String" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="mode_flags" type="int" enum="File.ModeFlags" />
+ <param index="2" name="pass" type="String" />
<description>
Opens an encrypted file in write or read mode. You need to pass a password to encrypt/decrypt it.
</description>
</method>
<method name="seek">
<return type="void" />
- <argument index="0" name="position" type="int" />
+ <param index="0" name="position" type="int" />
<description>
Changes the file reading/writing cursor to the specified position (in bytes from the beginning of the file).
</description>
</method>
<method name="seek_end">
<return type="void" />
- <argument index="0" name="position" type="int" default="0" />
+ <param index="0" name="position" type="int" default="0" />
<description>
Changes the file reading/writing cursor to the specified position (in bytes from the end of the file).
[b]Note:[/b] This is an offset, so you should use negative numbers or the cursor will be at the end of the file.
@@ -293,10 +294,10 @@
</method>
<method name="store_16">
<return type="void" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Stores an integer as 16 bits in the file.
- [b]Note:[/b] The [code]value[/code] should lie in the interval [code][0, 2^16 - 1][/code]. Any other value will overflow and wrap around.
+ [b]Note:[/b] The [param value] should lie in the interval [code][0, 2^16 - 1][/code]. Any other value will overflow and wrap around.
To store a signed integer, use [method store_64] or store a signed integer from the interval [code][-2^15, 2^15 - 1][/code] (i.e. keeping one bit for the signedness) and compute its sign manually when reading. For example:
[codeblocks]
[gdscript]
@@ -336,70 +337,70 @@
</method>
<method name="store_32">
<return type="void" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Stores an integer as 32 bits in the file.
- [b]Note:[/b] The [code]value[/code] should lie in the interval [code][0, 2^32 - 1][/code]. Any other value will overflow and wrap around.
+ [b]Note:[/b] The [param value] should lie in the interval [code][0, 2^32 - 1][/code]. Any other value will overflow and wrap around.
To store a signed integer, use [method store_64], or convert it manually (see [method store_16] for an example).
</description>
</method>
<method name="store_64">
<return type="void" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Stores an integer as 64 bits in the file.
- [b]Note:[/b] The [code]value[/code] must lie in the interval [code][-2^63, 2^63 - 1][/code] (i.e. be a valid [int] value).
+ [b]Note:[/b] The [param value] must lie in the interval [code][-2^63, 2^63 - 1][/code] (i.e. be a valid [int] value).
</description>
</method>
<method name="store_8">
<return type="void" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Stores an integer as 8 bits in the file.
- [b]Note:[/b] The [code]value[/code] should lie in the interval [code][0, 255][/code]. Any other value will overflow and wrap around.
+ [b]Note:[/b] The [param value] should lie in the interval [code][0, 255][/code]. Any other value will overflow and wrap around.
To store a signed integer, use [method store_64], or convert it manually (see [method store_16] for an example).
</description>
</method>
<method name="store_buffer">
<return type="void" />
- <argument index="0" name="buffer" type="PackedByteArray" />
+ <param index="0" name="buffer" type="PackedByteArray" />
<description>
Stores the given array of bytes in the file.
</description>
</method>
<method name="store_csv_line">
<return type="void" />
- <argument index="0" name="values" type="PackedStringArray" />
- <argument index="1" name="delim" type="String" default="&quot;,&quot;" />
+ <param index="0" name="values" type="PackedStringArray" />
+ <param index="1" name="delim" type="String" default="&quot;,&quot;" />
<description>
- Store the given [PackedStringArray] in the file as a line formatted in the CSV (Comma-Separated Values) format. You can pass a different delimiter [code]delim[/code] to use other than the default [code]","[/code] (comma). This delimiter must be one-character long.
+ Store the given [PackedStringArray] in the file as a line formatted in the CSV (Comma-Separated Values) format. You can pass a different delimiter [param delim] to use other than the default [code]","[/code] (comma). This delimiter must be one-character long.
Text will be encoded as UTF-8.
</description>
</method>
<method name="store_double">
<return type="void" />
- <argument index="0" name="value" type="float" />
+ <param index="0" name="value" type="float" />
<description>
Stores a floating-point number as 64 bits in the file.
</description>
</method>
<method name="store_float">
<return type="void" />
- <argument index="0" name="value" type="float" />
+ <param index="0" name="value" type="float" />
<description>
Stores a floating-point number as 32 bits in the file.
</description>
</method>
<method name="store_line">
<return type="void" />
- <argument index="0" name="line" type="String" />
+ <param index="0" name="line" type="String" />
<description>
- Appends [code]line[/code] to the file followed by a line return character ([code]\n[/code]), encoding the text as UTF-8.
+ Appends [param line] to the file followed by a line return character ([code]\n[/code]), encoding the text as UTF-8.
</description>
</method>
<method name="store_pascal_string">
<return type="void" />
- <argument index="0" name="string" type="String" />
+ <param index="0" name="string" type="String" />
<description>
Stores the given [String] as a line in the file in Pascal format (i.e. also store the length of the string).
Text will be encoded as UTF-8.
@@ -407,25 +408,25 @@
</method>
<method name="store_real">
<return type="void" />
- <argument index="0" name="value" type="float" />
+ <param index="0" name="value" type="float" />
<description>
Stores a floating-point number in the file.
</description>
</method>
<method name="store_string">
<return type="void" />
- <argument index="0" name="string" type="String" />
+ <param index="0" name="string" type="String" />
<description>
- Appends [code]string[/code] to the file without a line return, encoding the text as UTF-8.
+ Appends [param string] to the file without a line return, encoding the text as UTF-8.
[b]Note:[/b] This method is intended to be used to write text files. The string is stored as a UTF-8 encoded buffer without string length or terminating zero, which means that it can't be loaded back easily. If you want to store a retrievable string in a binary file, consider using [method store_pascal_string] instead. For retrieving strings from a text file, you can use [code]get_buffer(length).get_string_from_utf8()[/code] (if you know the length) or [method get_as_text].
</description>
</method>
<method name="store_var">
<return type="void" />
- <argument index="0" name="value" type="Variant" />
- <argument index="1" name="full_objects" type="bool" default="false" />
+ <param index="0" name="value" type="Variant" />
+ <param index="1" name="full_objects" type="bool" default="false" />
<description>
- Stores any Variant value in the file. If [code]full_objects[/code] is [code]true[/code], encoding objects is allowed (and can potentially include code).
+ Stores any Variant value in the file. If [param full_objects] is [code]true[/code], encoding objects is allowed (and can potentially include code).
[b]Note:[/b] Not all properties are included. Only properties that are configured with the [constant PROPERTY_USAGE_STORAGE] flag set will be serialized. You can add a new usage flag to a property by overriding the [method Object._get_property_list] method in your class. You can also check how property usage is configured by calling [method Object._get_property_list]. See [enum PropertyUsageFlags] for the possible usage flags.
</description>
</method>
diff --git a/doc/classes/FileDialog.xml b/doc/classes/FileDialog.xml
index f45031cea8..43a941c8c8 100644
--- a/doc/classes/FileDialog.xml
+++ b/doc/classes/FileDialog.xml
@@ -11,12 +11,12 @@
<methods>
<method name="add_filter">
<return type="void" />
- <argument index="0" name="filter" type="String" />
- <argument index="1" name="description" type="String" default="&quot;&quot;" />
+ <param index="0" name="filter" type="String" />
+ <param index="1" name="description" type="String" default="&quot;&quot;" />
<description>
- Adds a comma-delimited file name [code]filter[/code] option to the [FileDialog] with an optional [code]description[/code], which restricts what files can be picked.
- A [code]filter[/code] should be of the form [code]"filename.extension"[/code], where filename and extension can be [code]*[/code] to match any string. Filters starting with [code].[/code] (i.e. empty filenames) are not allowed.
- For example, a [code]filter[/code] of [code]"*.png, *.jpg"[/code] and a [code]description[/code] of [code]"Images"[/code] results in filter text "Images (*.png, *.jpg)".
+ Adds a comma-delimited file name [param filter] option to the [FileDialog] with an optional [param description], which restricts what files can be picked.
+ A [param filter] should be of the form [code]"filename.extension"[/code], where filename and extension can be [code]*[/code] to match any string. Filters starting with [code].[/code] (i.e. empty filenames) are not allowed.
+ For example, a [param filter] of [code]"*.png, *.jpg"[/code] and a [param description] of [code]"Images"[/code] results in filter text "Images (*.png, *.jpg)".
</description>
</method>
<method name="clear_filters">
@@ -55,7 +55,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].
+ [b]Warning:[/b] Currently, in sandboxed environments such as Web 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">
The current working directory of the file dialog.
@@ -86,19 +86,19 @@
</members>
<signals>
<signal name="dir_selected">
- <argument index="0" name="dir" type="String" />
+ <param index="0" name="dir" type="String" />
<description>
Emitted when the user selects a directory.
</description>
</signal>
<signal name="file_selected">
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Emitted when the user selects a file by double-clicking it or pressing the [b]OK[/b] button.
</description>
</signal>
<signal name="files_selected">
- <argument index="0" name="paths" type="PackedStringArray" />
+ <param index="0" name="paths" type="PackedStringArray" />
<description>
Emitted when the user selects multiple files.
</description>
diff --git a/doc/classes/FileSystemDock.xml b/doc/classes/FileSystemDock.xml
index 31299deb7d..22048c6761 100644
--- a/doc/classes/FileSystemDock.xml
+++ b/doc/classes/FileSystemDock.xml
@@ -9,7 +9,7 @@
<methods>
<method name="navigate_to_path">
<return type="void" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
</description>
</method>
@@ -20,34 +20,34 @@
</description>
</signal>
<signal name="file_removed">
- <argument index="0" name="file" type="String" />
+ <param index="0" name="file" type="String" />
<description>
</description>
</signal>
<signal name="files_moved">
- <argument index="0" name="old_file" type="String" />
- <argument index="1" name="new_file" type="String" />
+ <param index="0" name="old_file" type="String" />
+ <param index="1" name="new_file" type="String" />
<description>
</description>
</signal>
<signal name="folder_moved">
- <argument index="0" name="old_folder" type="String" />
- <argument index="1" name="new_file" type="String" />
+ <param index="0" name="old_folder" type="String" />
+ <param index="1" name="new_file" type="String" />
<description>
</description>
</signal>
<signal name="folder_removed">
- <argument index="0" name="folder" type="String" />
+ <param index="0" name="folder" type="String" />
<description>
</description>
</signal>
<signal name="inherit">
- <argument index="0" name="file" type="String" />
+ <param index="0" name="file" type="String" />
<description>
</description>
</signal>
<signal name="instance">
- <argument index="0" name="files" type="PackedStringArray" />
+ <param index="0" name="files" type="PackedStringArray" />
<description>
</description>
</signal>
diff --git a/doc/classes/Font.xml b/doc/classes/Font.xml
index ec2776f636..ad3a16afbb 100644
--- a/doc/classes/Font.xml
+++ b/doc/classes/Font.xml
@@ -11,116 +11,116 @@
<methods>
<method name="draw_char" qualifiers="const">
<return type="float" />
- <argument index="0" name="canvas_item" type="RID" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="char" type="int" />
- <argument index="3" name="font_size" type="int" />
- <argument index="4" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="0" name="canvas_item" type="RID" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="char" type="int" />
+ <param index="3" name="font_size" type="int" />
+ <param index="4" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
<description>
- Draw a single Unicode character [code]char[/code] into a canvas item using the font, at a given position, with [code]modulate[/code] color. [code]position[/code] specifies the baseline, not the top. To draw from the top, [i]ascent[/i] must be added to the Y axis.
+ Draw a single Unicode character [param char] into a canvas item using the font, at a given position, with [param modulate] color. [param pos] specifies the baseline, not the top. To draw from the top, [i]ascent[/i] must be added to the Y axis.
[b]Note:[/b] Do not use this function to draw strings character by character, use [method draw_string] or [TextLine] instead.
</description>
</method>
<method name="draw_char_outline" qualifiers="const">
<return type="float" />
- <argument index="0" name="canvas_item" type="RID" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="char" type="int" />
- <argument index="3" name="font_size" type="int" />
- <argument index="4" name="size" type="int" default="-1" />
- <argument index="5" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="0" name="canvas_item" type="RID" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="char" type="int" />
+ <param index="3" name="font_size" type="int" />
+ <param index="4" name="size" type="int" default="-1" />
+ <param index="5" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
<description>
- Draw a single Unicode character [code]char[/code] outline into a canvas item using the font, at a given position, with [code]modulate[/code] color and [code]size[/code] outline size. [code]position[/code] specifies the baseline, not the top. To draw from the top, [i]ascent[/i] must be added to the Y axis.
+ Draw a single Unicode character [param char] outline into a canvas item using the font, at a given position, with [param modulate] color and [param size] outline size. [param pos] specifies the baseline, not the top. To draw from the top, [i]ascent[/i] must be added to the Y axis.
[b]Note:[/b] Do not use this function to draw strings character by character, use [method draw_string] or [TextLine] instead.
</description>
</method>
<method name="draw_multiline_string" qualifiers="const">
<return type="void" />
- <argument index="0" name="canvas_item" type="RID" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="text" type="String" />
- <argument index="3" name="alignment" type="int" enum="HorizontalAlignment" default="0" />
- <argument index="4" name="width" type="float" default="-1" />
- <argument index="5" name="font_size" type="int" default="16" />
- <argument index="6" name="max_lines" type="int" default="-1" />
- <argument index="7" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="8" name="brk_flags" type="int" enum="TextServer.LineBreakFlag" default="3" />
- <argument index="9" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
- <argument index="10" name="direction" type="int" enum="TextServer.Direction" default="0" />
- <argument index="11" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
+ <param index="0" name="canvas_item" type="RID" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="text" type="String" />
+ <param index="3" name="alignment" type="int" enum="HorizontalAlignment" default="0" />
+ <param index="4" name="width" type="float" default="-1" />
+ <param index="5" name="font_size" type="int" default="16" />
+ <param index="6" name="max_lines" type="int" default="-1" />
+ <param index="7" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="8" name="brk_flags" type="int" enum="TextServer.LineBreakFlag" default="3" />
+ <param index="9" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="10" name="direction" type="int" enum="TextServer.Direction" default="0" />
+ <param index="11" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
- Breaks [code]text[/code] to the lines using rules specified by [code]flags[/code] and draws it into a canvas item using the font, at a given position, with [code]modulate[/code] color, optionally clipping the width and aligning horizontally. [code]position[/code] specifies the baseline of the first line, not the top. To draw from the top, [i]ascent[/i] must be added to the Y axis.
+ Breaks [param text] into lines using rules specified by [param brk_flags] and draws it into a canvas item using the font, at a given position, with [param modulate] color, optionally clipping the width and aligning horizontally. [param pos] specifies the baseline of the first line, not the top. To draw from the top, [i]ascent[/i] must be added to the Y axis.
See also [method CanvasItem.draw_multiline_string].
</description>
</method>
<method name="draw_multiline_string_outline" qualifiers="const">
<return type="void" />
- <argument index="0" name="canvas_item" type="RID" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="text" type="String" />
- <argument index="3" name="alignment" type="int" enum="HorizontalAlignment" default="0" />
- <argument index="4" name="width" type="float" default="-1" />
- <argument index="5" name="font_size" type="int" default="16" />
- <argument index="6" name="max_lines" type="int" default="-1" />
- <argument index="7" name="size" type="int" default="1" />
- <argument index="8" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="9" name="brk_flags" type="int" enum="TextServer.LineBreakFlag" default="3" />
- <argument index="10" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
- <argument index="11" name="direction" type="int" enum="TextServer.Direction" default="0" />
- <argument index="12" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
+ <param index="0" name="canvas_item" type="RID" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="text" type="String" />
+ <param index="3" name="alignment" type="int" enum="HorizontalAlignment" default="0" />
+ <param index="4" name="width" type="float" default="-1" />
+ <param index="5" name="font_size" type="int" default="16" />
+ <param index="6" name="max_lines" type="int" default="-1" />
+ <param index="7" name="size" type="int" default="1" />
+ <param index="8" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="9" name="brk_flags" type="int" enum="TextServer.LineBreakFlag" default="3" />
+ <param index="10" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="11" name="direction" type="int" enum="TextServer.Direction" default="0" />
+ <param index="12" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
- Breaks [code]text[/code] to the lines using rules specified by [code]flags[/code] and draws text outline into a canvas item using the font, at a given position, with [code]modulate[/code] color and [code]size[/code] outline size, optionally clipping the width and aligning horizontally. [code]position[/code] specifies the baseline of the first line, not the top. To draw from the top, [i]ascent[/i] must be added to the Y axis.
+ Breaks [param text] to the lines using rules specified by [param brk_flags] and draws text outline into a canvas item using the font, at a given position, with [param modulate] color and [param size] outline size, optionally clipping the width and aligning horizontally. [param pos] specifies the baseline of the first line, not the top. To draw from the top, [i]ascent[/i] must be added to the Y axis.
See also [method CanvasItem.draw_multiline_string_outline].
</description>
</method>
<method name="draw_string" qualifiers="const">
<return type="void" />
- <argument index="0" name="canvas_item" type="RID" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="text" type="String" />
- <argument index="3" name="alignment" type="int" enum="HorizontalAlignment" default="0" />
- <argument index="4" name="width" type="float" default="-1" />
- <argument index="5" name="font_size" type="int" default="16" />
- <argument index="6" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="7" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
- <argument index="8" name="direction" type="int" enum="TextServer.Direction" default="0" />
- <argument index="9" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
+ <param index="0" name="canvas_item" type="RID" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="text" type="String" />
+ <param index="3" name="alignment" type="int" enum="HorizontalAlignment" default="0" />
+ <param index="4" name="width" type="float" default="-1" />
+ <param index="5" name="font_size" type="int" default="16" />
+ <param index="6" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="7" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="8" name="direction" type="int" enum="TextServer.Direction" default="0" />
+ <param index="9" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
- Draw [code]text[/code] into a canvas item using the font, at a given position, with [code]modulate[/code] color, optionally clipping the width and aligning horizontally. [code]position[/code] specifies the baseline, not the top. To draw from the top, [i]ascent[/i] must be added to the Y axis.
+ Draw [param text] into a canvas item using the font, at a given position, with [param modulate] color, optionally clipping the width and aligning horizontally. [param pos] specifies the baseline, not the top. To draw from the top, [i]ascent[/i] must be added to the Y axis.
See also [method CanvasItem.draw_string].
</description>
</method>
<method name="draw_string_outline" qualifiers="const">
<return type="void" />
- <argument index="0" name="canvas_item" type="RID" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="text" type="String" />
- <argument index="3" name="alignment" type="int" enum="HorizontalAlignment" default="0" />
- <argument index="4" name="width" type="float" default="-1" />
- <argument index="5" name="font_size" type="int" default="16" />
- <argument index="6" name="size" type="int" default="1" />
- <argument index="7" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="8" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
- <argument index="9" name="direction" type="int" enum="TextServer.Direction" default="0" />
- <argument index="10" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
+ <param index="0" name="canvas_item" type="RID" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="text" type="String" />
+ <param index="3" name="alignment" type="int" enum="HorizontalAlignment" default="0" />
+ <param index="4" name="width" type="float" default="-1" />
+ <param index="5" name="font_size" type="int" default="16" />
+ <param index="6" name="size" type="int" default="1" />
+ <param index="7" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="8" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="9" name="direction" type="int" enum="TextServer.Direction" default="0" />
+ <param index="10" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
- Draw [code]text[/code] outline into a canvas item using the font, at a given position, with [code]modulate[/code] color and [code]size[/code] outline size, optionally clipping the width and aligning horizontally. [code]position[/code] specifies the baseline, not the top. To draw from the top, [i]ascent[/i] must be added to the Y axis.
+ Draw [param text] outline into a canvas item using the font, at a given position, with [param modulate] color and [param size] outline size, optionally clipping the width and aligning horizontally. [param pos] specifies the baseline, not the top. To draw from the top, [i]ascent[/i] must be added to the Y axis.
See also [method CanvasItem.draw_string_outline].
</description>
</method>
<method name="find_variation" qualifiers="const">
<return type="RID" />
- <argument index="0" name="variation_coordinates" type="Dictionary" />
- <argument index="1" name="face_index" type="int" default="0" />
- <argument index="2" name="strength" type="float" default="0.0" />
- <argument index="3" name="transform" type="Transform2D" default="Transform2D(1, 0, 0, 1, 0, 0)" />
+ <param index="0" name="variation_coordinates" type="Dictionary" />
+ <param index="1" name="face_index" type="int" default="0" />
+ <param index="2" name="strength" type="float" default="0.0" />
+ <param index="3" name="transform" type="Transform2D" default="Transform2D(1, 0, 0, 1, 0, 0)" />
<description>
Returns [TextServer] RID of the font cache for specific variation.
</description>
</method>
<method name="get_ascent" qualifiers="const">
<return type="float" />
- <argument index="0" name="font_size" type="int" default="16" />
+ <param index="0" name="font_size" type="int" default="16" />
<description>
Returns the average font ascent (number of pixels above the baseline).
[b]Note:[/b] Real ascent of the string is context-dependent and can be significantly different from the value returned by this function. Use it only as rough estimate (e.g. as the ascent of empty line).
@@ -128,8 +128,8 @@
</method>
<method name="get_char_size" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="char" type="int" />
- <argument index="1" name="font_size" type="int" />
+ <param index="0" name="char" type="int" />
+ <param index="1" name="font_size" type="int" />
<description>
Returns the size of a character, optionally taking kerning into account if the next character is provided.
[b]Note:[/b] Do not use this function to calculate width of the string character by character, use [method get_string_size] or [TextLine] instead. The height returned is the font height (see also [method get_height]) and has no relation to the glyph height.
@@ -137,7 +137,7 @@
</method>
<method name="get_descent" qualifiers="const">
<return type="float" />
- <argument index="0" name="font_size" type="int" default="16" />
+ <param index="0" name="font_size" type="int" default="16" />
<description>
Returns the average font descent (number of pixels below the baseline).
[b]Note:[/b] Real descent of the string is context-dependent and can be significantly different from the value returned by this function. Use it only as rough estimate (e.g. as the descent of empty line).
@@ -175,7 +175,7 @@
</method>
<method name="get_height" qualifiers="const">
<return type="float" />
- <argument index="0" name="font_size" type="int" default="16" />
+ <param index="0" name="font_size" type="int" default="16" />
<description>
Returns the total average font height (ascent plus descent) in pixels.
[b]Note:[/b] Real height of the string is context-dependent and can be significantly different from the value returned by this function. Use it only as rough estimate (e.g. as the height of empty line).
@@ -183,15 +183,15 @@
</method>
<method name="get_multiline_string_size" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="text" type="String" />
- <argument index="1" name="alignment" type="int" enum="HorizontalAlignment" default="0" />
- <argument index="2" name="width" type="float" default="-1" />
- <argument index="3" name="font_size" type="int" default="16" />
- <argument index="4" name="max_lines" type="int" default="-1" />
- <argument index="5" name="brk_flags" type="int" enum="TextServer.LineBreakFlag" default="3" />
- <argument index="6" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
- <argument index="7" name="direction" type="int" enum="TextServer.Direction" default="0" />
- <argument index="8" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
+ <param index="0" name="text" type="String" />
+ <param index="1" name="alignment" type="int" enum="HorizontalAlignment" default="0" />
+ <param index="2" name="width" type="float" default="-1" />
+ <param index="3" name="font_size" type="int" default="16" />
+ <param index="4" name="max_lines" type="int" default="-1" />
+ <param index="5" name="brk_flags" type="int" enum="TextServer.LineBreakFlag" default="3" />
+ <param index="6" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="7" name="direction" type="int" enum="TextServer.Direction" default="0" />
+ <param index="8" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
Returns the size of a bounding box of a string broken into the lines, taking kerning and advance into account.
See also [method draw_multiline_string].
@@ -211,20 +211,20 @@
</method>
<method name="get_spacing" qualifiers="const">
<return type="int" />
- <argument index="0" name="spacing" type="int" enum="TextServer.SpacingType" />
+ <param index="0" name="spacing" type="int" enum="TextServer.SpacingType" />
<description>
Returns the spacing for the given [code]type[/code] (see [enum TextServer.SpacingType]).
</description>
</method>
<method name="get_string_size" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="text" type="String" />
- <argument index="1" name="alignment" type="int" enum="HorizontalAlignment" default="0" />
- <argument index="2" name="width" type="float" default="-1" />
- <argument index="3" name="font_size" type="int" default="16" />
- <argument index="4" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
- <argument index="5" name="direction" type="int" enum="TextServer.Direction" default="0" />
- <argument index="6" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
+ <param index="0" name="text" type="String" />
+ <param index="1" name="alignment" type="int" enum="HorizontalAlignment" default="0" />
+ <param index="2" name="width" type="float" default="-1" />
+ <param index="3" name="font_size" type="int" default="16" />
+ <param index="4" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="5" name="direction" type="int" enum="TextServer.Direction" default="0" />
+ <param index="6" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
Returns the size of a bounding box of a single-line string, taking kerning and advance into account. See also [method get_multiline_string_size] and [method draw_string].
For example, to get the string size as displayed by a single-line Label, use:
@@ -256,7 +256,7 @@
</method>
<method name="get_underline_position" qualifiers="const">
<return type="float" />
- <argument index="0" name="font_size" type="int" default="16" />
+ <param index="0" name="font_size" type="int" default="16" />
<description>
Returns average pixel offset of the underline below the baseline.
[b]Note:[/b] Real underline position of the string is context-dependent and can be significantly different from the value returned by this function. Use it only as rough estimate.
@@ -264,7 +264,7 @@
</method>
<method name="get_underline_thickness" qualifiers="const">
<return type="float" />
- <argument index="0" name="font_size" type="int" default="16" />
+ <param index="0" name="font_size" type="int" default="16" />
<description>
Returns average thickness of the underline.
[b]Note:[/b] Real underline thickness of the string is context-dependent and can be significantly different from the value returned by this function. Use it only as rough estimate.
@@ -272,36 +272,36 @@
</method>
<method name="has_char" qualifiers="const">
<return type="bool" />
- <argument index="0" name="char" type="int" />
+ <param index="0" name="char" type="int" />
<description>
- Returns [code]true[/code] if a Unicode [code]char[/code] is available in the font.
+ Returns [code]true[/code] if a Unicode [param char] is available in the font.
</description>
</method>
<method name="is_language_supported" qualifiers="const">
<return type="bool" />
- <argument index="0" name="language" type="String" />
+ <param index="0" name="language" type="String" />
<description>
Returns [code]true[/code], if font supports given language ([url=https://en.wikipedia.org/wiki/ISO_639-1]ISO 639[/url] code).
</description>
</method>
<method name="is_script_supported" qualifiers="const">
<return type="bool" />
- <argument index="0" name="script" type="String" />
+ <param index="0" name="script" type="String" />
<description>
Returns [code]true[/code], if font supports given script ([url=https://en.wikipedia.org/wiki/ISO_15924]ISO 15924[/url] code).
</description>
</method>
<method name="set_cache_capacity">
<return type="void" />
- <argument index="0" name="single_line" type="int" />
- <argument index="1" name="multi_line" type="int" />
+ <param index="0" name="single_line" type="int" />
+ <param index="1" name="multi_line" type="int" />
<description>
Sets LRU cache capacity for [code]draw_*[/code] methods.
</description>
</method>
<method name="set_fallbacks">
<return type="void" />
- <argument index="0" name="fallbacks" type="Font[]" />
+ <param index="0" name="fallbacks" type="Font[]" />
<description>
Sets array of fallback [Font]s.
</description>
diff --git a/doc/classes/FontFile.xml b/doc/classes/FontFile.xml
index dc2cbdde63..df378d9d2f 100644
--- a/doc/classes/FontFile.xml
+++ b/doc/classes/FontFile.xml
@@ -39,8 +39,8 @@
</method>
<method name="clear_glyphs">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="Vector2i" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="Vector2i" />
<description>
Removes all rendered glyphs information from the cache entry.
[b]Note:[/b] This function will not remove textures associated with the glyphs, use [method remove_texture] to remove them manually.
@@ -48,23 +48,23 @@
</method>
<method name="clear_kerning_map">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="int" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="int" />
<description>
Removes all kerning overrides.
</description>
</method>
<method name="clear_size_cache">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
+ <param index="0" name="cache_index" type="int" />
<description>
Removes all font sizes from the cache entry
</description>
</method>
<method name="clear_textures">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="Vector2i" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="Vector2i" />
<description>
Removes all textures from font cache entry.
[b]Note:[/b] This function will not remove glyphs associated with the texture, use [method remove_glyph] to remove them manually.
@@ -72,8 +72,8 @@
</method>
<method name="get_cache_ascent" qualifiers="const">
<return type="float" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="int" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="int" />
<description>
Returns the font ascent (number of pixels above the baseline).
</description>
@@ -86,51 +86,51 @@
</method>
<method name="get_cache_descent" qualifiers="const">
<return type="float" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="int" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="int" />
<description>
</description>
</method>
<method name="get_cache_scale" qualifiers="const">
<return type="float" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="int" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="int" />
<description>
</description>
</method>
<method name="get_cache_underline_position" qualifiers="const">
<return type="float" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="int" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="int" />
<description>
</description>
</method>
<method name="get_cache_underline_thickness" qualifiers="const">
<return type="float" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="int" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="int" />
<description>
</description>
</method>
<method name="get_embolden" qualifiers="const">
<return type="float" />
- <argument index="0" name="cache_index" type="int" />
+ <param index="0" name="cache_index" type="int" />
<description>
Returns embolden strength, if is not equal to zero, emboldens the font outlines. Negative values reduce the outline thickness.
</description>
</method>
<method name="get_face_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="cache_index" type="int" />
+ <param index="0" name="cache_index" type="int" />
<description>
Recturns an active face index in the TrueType / OpenType collection.
</description>
</method>
<method name="get_glyph_advance" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="glyph" type="int" />
<description>
Returns glyph advance (offset of the next glyph).
[b]Note:[/b] Advance for glyphs outlines is the same as the base glyph advance and is not saved.
@@ -138,79 +138,79 @@
</method>
<method name="get_glyph_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="size" type="int" />
- <argument index="1" name="char" type="int" />
- <argument index="2" name="variation_selector" type="int" />
+ <param index="0" name="size" type="int" />
+ <param index="1" name="char" type="int" />
+ <param index="2" name="variation_selector" type="int" />
<description>
- Returns the glyph index of a [code]char[/code], optionally modified by the [code]variation_selector[/code].
+ Returns the glyph index of a [param char], optionally modified by the [param variation_selector].
</description>
</method>
<method name="get_glyph_list" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="Vector2i" />
+ <return type="PackedInt32Array" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="Vector2i" />
<description>
Returns list of rendered glyphs in the cache entry.
</description>
</method>
<method name="get_glyph_offset" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
<description>
Returns glyph offset from the baseline.
</description>
</method>
<method name="get_glyph_size" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
<description>
Returns glyph size.
</description>
</method>
<method name="get_glyph_texture_idx" qualifiers="const">
<return type="int" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
<description>
Returns index of the cache texture containing the glyph.
</description>
</method>
<method name="get_glyph_uv_rect" qualifiers="const">
<return type="Rect2" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
<description>
Returns rectangle in the cache texture containing the glyph.
</description>
</method>
<method name="get_kerning" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="glyph_pair" type="Vector2i" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="glyph_pair" type="Vector2i" />
<description>
Returns kerning for the pair of glyphs.
</description>
</method>
<method name="get_kerning_list" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="int" />
+ <return type="Vector2i[]" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="int" />
<description>
Returns list of the kerning overrides.
</description>
</method>
<method name="get_language_support_override" qualifiers="const">
<return type="bool" />
- <argument index="0" name="language" type="String" />
+ <param index="0" name="language" type="String" />
<description>
- Returns [code]true[/code] if support override is enabled for the [code]language[/code].
+ Returns [code]true[/code] if support override is enabled for the [param language].
</description>
</method>
<method name="get_language_support_overrides" qualifiers="const">
@@ -221,9 +221,9 @@
</method>
<method name="get_script_support_override" qualifiers="const">
<return type="bool" />
- <argument index="0" name="script" type="String" />
+ <param index="0" name="script" type="String" />
<description>
- Returns [code]true[/code] if support override is enabled for the [code]script[/code].
+ Returns [code]true[/code] if support override is enabled for the [param script].
</description>
</method>
<method name="get_script_support_overrides" qualifiers="const">
@@ -233,80 +233,80 @@
</description>
</method>
<method name="get_size_cache_list" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="cache_index" type="int" />
+ <return type="Vector2i[]" />
+ <param index="0" name="cache_index" type="int" />
<description>
Returns list of the font sizes in the cache. Each size is [code]Vector2i[/code] with font size and outline size.
</description>
</method>
<method name="get_texture_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="Vector2i" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="Vector2i" />
<description>
Returns number of textures used by font cache entry.
</description>
</method>
<method name="get_texture_image" qualifiers="const">
<return type="Image" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="texture_index" type="int" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="texture_index" type="int" />
<description>
Returns a copy of the font cache texture image.
</description>
</method>
<method name="get_texture_offsets" qualifiers="const">
<return type="PackedInt32Array" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="texture_index" type="int" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="texture_index" type="int" />
<description>
Returns a copy of the array containing the first free pixel in the each column of texture. Should be the same size as texture width or empty.
</description>
</method>
<method name="get_transform" qualifiers="const">
<return type="Transform2D" />
- <argument index="0" name="cache_index" type="int" />
+ <param index="0" name="cache_index" type="int" />
<description>
Returns 2D transform, applied to the font outlines, can be used for slanting, flipping and rotating glyphs.
</description>
</method>
<method name="get_variation_coordinates" qualifiers="const">
<return type="Dictionary" />
- <argument index="0" name="cache_index" type="int" />
+ <param index="0" name="cache_index" type="int" />
<description>
Returns variation coordinates for the specified font cache entry. See [method Font.get_supported_variation_list] for more info.
</description>
</method>
<method name="load_bitmap_font">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
- Loads an AngelCode BMFont (.fnt, .font) bitmap font from file [code]path[/code].
+ Loads an AngelCode BMFont (.fnt, .font) bitmap font from file [param path].
[b]Warning:[/b] This method should only be used in the editor or in cases when you need to load external fonts at run-time, such as fonts located at the [code]user://[/code] directory.
</description>
</method>
<method name="load_dynamic_font">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
- Loads a TrueType (.ttf), OpenType (.otf), WOFF (.woff), WOFF2 (.woff2) or Type 1 (.pfb, .pfm) dynamic font from file [code]path[/code].
+ Loads a TrueType (.ttf), OpenType (.otf), WOFF (.woff), WOFF2 (.woff2) or Type 1 (.pfb, .pfm) dynamic font from file [param path].
[b]Warning:[/b] This method should only be used in the editor or in cases when you need to load external fonts at run-time, such as fonts located at the [code]user://[/code] directory.
</description>
</method>
<method name="remove_cache">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
+ <param index="0" name="cache_index" type="int" />
<description>
Removes specified font cache entry.
</description>
</method>
<method name="remove_glyph">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
<description>
Removes specified rendered glyph information from the cache entry.
[b]Note:[/b] This function will not remove textures associated with the glyphs, use [method remove_texture] to remove them manually.
@@ -314,40 +314,40 @@
</method>
<method name="remove_kerning">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="glyph_pair" type="Vector2i" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="glyph_pair" type="Vector2i" />
<description>
Removes kerning override for the pair of glyphs.
</description>
</method>
<method name="remove_language_support_override">
<return type="void" />
- <argument index="0" name="language" type="String" />
+ <param index="0" name="language" type="String" />
<description>
Remove language support override.
</description>
</method>
<method name="remove_script_support_override">
<return type="void" />
- <argument index="0" name="script" type="String" />
+ <param index="0" name="script" type="String" />
<description>
Removes script support override.
</description>
</method>
<method name="remove_size_cache">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="Vector2i" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="Vector2i" />
<description>
Removes specified font size from the cache entry.
</description>
</method>
<method name="remove_texture">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="texture_index" type="int" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="texture_index" type="int" />
<description>
Removes specified texture from the cache entry.
[b]Note:[/b] This function will not remove glyphs associated with the texture. Remove them manually using [method remove_glyph].
@@ -355,85 +355,85 @@
</method>
<method name="render_glyph">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="index" type="int" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="index" type="int" />
<description>
Renders specified glyph to the font cache texture.
</description>
</method>
<method name="render_range">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="start" type="int" />
- <argument index="3" name="end" type="int" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="start" type="int" />
+ <param index="3" name="end" type="int" />
<description>
Renders the range of characters to the font cache texture.
</description>
</method>
<method name="set_cache_ascent">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="ascent" type="float" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="ascent" type="float" />
<description>
</description>
</method>
<method name="set_cache_descent">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="descent" type="float" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="descent" type="float" />
<description>
</description>
</method>
<method name="set_cache_scale">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="scale" type="float" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="scale" type="float" />
<description>
</description>
</method>
<method name="set_cache_underline_position">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="underline_position" type="float" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="underline_position" type="float" />
<description>
</description>
</method>
<method name="set_cache_underline_thickness">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="underline_thickness" type="float" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="underline_thickness" type="float" />
<description>
</description>
</method>
<method name="set_embolden">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="strength" type="float" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="strength" type="float" />
<description>
Sets embolden strength, if is not equal to zero, emboldens the font outlines. Negative values reduce the outline thickness.
</description>
</method>
<method name="set_face_index">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="face_index" type="int" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="face_index" type="int" />
<description>
Sets an active face index in the TrueType / OpenType collection.
</description>
</method>
<method name="set_glyph_advance">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="glyph" type="int" />
- <argument index="3" name="advance" type="Vector2" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="glyph" type="int" />
+ <param index="3" name="advance" type="Vector2" />
<description>
Sets glyph advance (offset of the next glyph).
[b]Note:[/b] Advance for glyphs outlines is the same as the base glyph advance and is not saved.
@@ -441,110 +441,110 @@
</method>
<method name="set_glyph_offset">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
- <argument index="3" name="offset" type="Vector2" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
+ <param index="3" name="offset" type="Vector2" />
<description>
Sets glyph offset from the baseline.
</description>
</method>
<method name="set_glyph_size">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
- <argument index="3" name="gl_size" type="Vector2" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
+ <param index="3" name="gl_size" type="Vector2" />
<description>
Sets glyph size.
</description>
</method>
<method name="set_glyph_texture_idx">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
- <argument index="3" name="texture_idx" type="int" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
+ <param index="3" name="texture_idx" type="int" />
<description>
Sets index of the cache texture containing the glyph.
</description>
</method>
<method name="set_glyph_uv_rect">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
- <argument index="3" name="uv_rect" type="Rect2" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
+ <param index="3" name="uv_rect" type="Rect2" />
<description>
Sets rectangle in the cache texture containing the glyph.
</description>
</method>
<method name="set_kerning">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="glyph_pair" type="Vector2i" />
- <argument index="3" name="kerning" type="Vector2" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="glyph_pair" type="Vector2i" />
+ <param index="3" name="kerning" type="Vector2" />
<description>
Sets kerning for the pair of glyphs.
</description>
</method>
<method name="set_language_support_override">
<return type="void" />
- <argument index="0" name="language" type="String" />
- <argument index="1" name="supported" type="bool" />
+ <param index="0" name="language" type="String" />
+ <param index="1" name="supported" type="bool" />
<description>
Adds override for [method Font.is_language_supported].
</description>
</method>
<method name="set_script_support_override">
<return type="void" />
- <argument index="0" name="script" type="String" />
- <argument index="1" name="supported" type="bool" />
+ <param index="0" name="script" type="String" />
+ <param index="1" name="supported" type="bool" />
<description>
Adds override for [method Font.is_script_supported].
</description>
</method>
<method name="set_texture_image">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="texture_index" type="int" />
- <argument index="3" name="image" type="Image" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="texture_index" type="int" />
+ <param index="3" name="image" type="Image" />
<description>
Sets font cache texture image.
</description>
</method>
<method name="set_texture_offsets">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="texture_index" type="int" />
- <argument index="3" name="offset" type="PackedInt32Array" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="texture_index" type="int" />
+ <param index="3" name="offset" type="PackedInt32Array" />
<description>
Sets array containing the first free pixel in the each column of texture. Should be the same size as texture width or empty (for the fonts without dynamic glyph generation support).
</description>
</method>
<method name="set_transform">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="transform" type="Transform2D" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="transform" type="Transform2D" />
<description>
Sets 2D transform, applied to the font outlines, can be used for slanting, flipping and rotating glyphs.
</description>
</method>
<method name="set_variation_coordinates">
<return type="void" />
- <argument index="0" name="cache_index" type="int" />
- <argument index="1" name="variation_coordinates" type="Dictionary" />
+ <param index="0" name="cache_index" type="int" />
+ <param index="1" name="variation_coordinates" type="Dictionary" />
<description>
Sets variation coordinates for the specified font cache entry. See [method Font.get_supported_variation_list] for more info.
</description>
</method>
</methods>
<members>
- <member name="antialiased" type="bool" setter="set_antialiased" getter="is_antialiased" default="true">
- If set to [code]true[/code], font 8-bit anitialiased glyph rendering is supported and enabled.
+ <member name="antialiasing" type="int" setter="set_antialiasing" getter="get_antialiasing" enum="TextServer.FontAntialiasing" default="1">
+ Font anti-aliasing mode.
</member>
<member name="data" type="PackedByteArray" setter="set_data" getter="get_data" default="PackedByteArray()">
Contents of the dynamic font source file.
diff --git a/doc/classes/FontVariation.xml b/doc/classes/FontVariation.xml
index a1b96fb137..6aa381c2de 100644
--- a/doc/classes/FontVariation.xml
+++ b/doc/classes/FontVariation.xml
@@ -29,10 +29,10 @@
<methods>
<method name="set_spacing">
<return type="void" />
- <argument index="0" name="spacing" type="int" enum="TextServer.SpacingType" />
- <argument index="1" name="value" type="int" />
+ <param index="0" name="spacing" type="int" enum="TextServer.SpacingType" />
+ <param index="1" name="value" type="int" />
<description>
- Sets the spacing for [code]type[/code] (see [enum TextServer.SpacingType]) to [code]value[/code] in pixels (not relative to the font size).
+ Sets the spacing for [code]type[/code] (see [enum TextServer.SpacingType]) to [param value] in pixels (not relative to the font size).
</description>
</method>
</methods>
diff --git a/doc/classes/GPUParticles2D.xml b/doc/classes/GPUParticles2D.xml
index 53894bad87..f41e34c43a 100644
--- a/doc/classes/GPUParticles2D.xml
+++ b/doc/classes/GPUParticles2D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
2D particle node used to create a variety of particle systems and effects. [GPUParticles2D] features an emitter that generates some number of particles at a given rate.
- 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.
+ Use the [code]process_material[/code] property to add a [ParticleProcessMaterial] to configure particle appearance and behavior. Alternatively, you can add a [ShaderMaterial] which will be applied to all particles.
</description>
<tutorials>
<link title="Particle systems (2D)">$DOCS_URL/tutorials/2d/particle_systems_2d.html</link>
@@ -20,13 +20,13 @@
</method>
<method name="emit_particle">
<return type="void" />
- <argument index="0" name="xform" type="Transform2D" />
- <argument index="1" name="velocity" type="Vector2" />
- <argument index="2" name="color" type="Color" />
- <argument index="3" name="custom" type="Color" />
- <argument index="4" name="flags" type="int" />
+ <param index="0" name="xform" type="Transform2D" />
+ <param index="1" name="velocity" type="Vector2" />
+ <param index="2" name="color" type="Color" />
+ <param index="3" name="custom" type="Color" />
+ <param index="4" name="flags" type="int" />
<description>
- Emits a single particle. Whether [code]xform[/code], [code]velocity[/code], [code]color[/code] and [code]custom[/code] are applied depends on the value of [code]flags[/code]. See [enum EmitFlags].
+ Emits a single particle. Whether [param xform], [param velocity], [param color] and [param custom] are applied depends on the value of [param flags]. See [enum EmitFlags].
</description>
</method>
<method name="restart">
@@ -63,8 +63,8 @@
<member name="lifetime" type="float" setter="set_lifetime" getter="get_lifetime" default="1.0">
Amount of time each particle will exist.
</member>
- <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="true">
- If [code]true[/code], particles use the parent node's coordinate space. If [code]false[/code], they use global coordinates.
+ <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="false">
+ If [code]true[/code], particles use the parent node's coordinate space (known as local coordinates). This will cause particles to move and rotate along the [GPUParticles2D] node (and its parents) when it is moved or rotated. If [code]false[/code], particles use global coordinates; they will not move or rotate along the [GPUParticles2D] node (and its parents) when it is moved or rotated.
</member>
<member name="one_shot" type="bool" setter="set_one_shot" getter="get_one_shot" default="false">
If [code]true[/code], only one emission cycle occurs. If set [code]true[/code] during a cycle, emission will stop at the cycle's end.
@@ -73,7 +73,7 @@
Particle system starts as if it had already run for this many seconds.
</member>
<member name="process_material" type="Material" setter="set_process_material" getter="get_process_material">
- [Material] for processing particles. Can be a [ParticlesMaterial] or a [ShaderMaterial].
+ [Material] for processing particles. Can be a [ParticleProcessMaterial] or a [ShaderMaterial].
</member>
<member name="randomness" type="float" setter="set_randomness_ratio" getter="get_randomness_ratio" default="0.0">
Emission lifetime randomness ratio.
diff --git a/doc/classes/GPUParticles3D.xml b/doc/classes/GPUParticles3D.xml
index c4bd18db69..e7b436010e 100644
--- a/doc/classes/GPUParticles3D.xml
+++ b/doc/classes/GPUParticles3D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
3D particle node used to create a variety of particle systems and effects. [GPUParticles3D] features an emitter that generates some number of particles at a given rate.
- 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.
+ Use the [code]process_material[/code] property to add a [ParticleProcessMaterial] to configure particle appearance and behavior. Alternatively, you can add a [ShaderMaterial] which will be applied to all particles.
</description>
<tutorials>
<link title="Controlling thousands of fish with Particles">$DOCS_URL/tutorials/performance/vertex_animation/controlling_thousands_of_fish.html</link>
@@ -20,20 +20,20 @@
</method>
<method name="emit_particle">
<return type="void" />
- <argument index="0" name="xform" type="Transform3D" />
- <argument index="1" name="velocity" type="Vector3" />
- <argument index="2" name="color" type="Color" />
- <argument index="3" name="custom" type="Color" />
- <argument index="4" name="flags" type="int" />
+ <param index="0" name="xform" type="Transform3D" />
+ <param index="1" name="velocity" type="Vector3" />
+ <param index="2" name="color" type="Color" />
+ <param index="3" name="custom" type="Color" />
+ <param index="4" name="flags" type="int" />
<description>
- Emits a single particle. Whether [code]xform[/code], [code]velocity[/code], [code]color[/code] and [code]custom[/code] are applied depends on the value of [code]flags[/code]. See [enum EmitFlags].
+ Emits a single particle. Whether [param xform], [param velocity], [param color] and [param custom] are applied depends on the value of [param flags]. See [enum EmitFlags].
</description>
</method>
<method name="get_draw_pass_mesh" qualifiers="const">
<return type="Mesh" />
- <argument index="0" name="pass" type="int" />
+ <param index="0" name="pass" type="int" />
<description>
- Returns the [Mesh] that is drawn at index [code]pass[/code].
+ Returns the [Mesh] that is drawn at index [param pass].
</description>
</method>
<method name="restart">
@@ -44,10 +44,10 @@
</method>
<method name="set_draw_pass_mesh">
<return type="void" />
- <argument index="0" name="pass" type="int" />
- <argument index="1" name="mesh" type="Mesh" />
+ <param index="0" name="pass" type="int" />
+ <param index="1" name="mesh" type="Mesh" />
<description>
- Sets the [Mesh] that is drawn at index [code]pass[/code].
+ Sets the [Mesh] that is drawn at index [param pass].
</description>
</method>
</methods>
@@ -95,8 +95,8 @@
<member name="lifetime" type="float" setter="set_lifetime" getter="get_lifetime" default="1.0">
Amount of time each particle will exist.
</member>
- <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="true">
- If [code]true[/code], particles use the parent node's coordinate space. If [code]false[/code], they use global coordinates.
+ <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="false">
+ If [code]true[/code], particles use the parent node's coordinate space (known as local coordinates). This will cause particles to move and rotate along the [GPUParticles3D] node (and its parents) when it is moved or rotated. If [code]false[/code], particles use global coordinates; they will not move or rotate along the [GPUParticles3D] node (and its parents) when it is moved or rotated.
</member>
<member name="one_shot" type="bool" setter="set_one_shot" getter="get_one_shot" default="false">
If [code]true[/code], only [code]amount[/code] particles will be emitted.
@@ -105,7 +105,7 @@
Amount of time to preprocess the particles before animation starts. Lets you start the animation some time after particles have started emitting.
</member>
<member name="process_material" type="Material" setter="set_process_material" getter="get_process_material">
- [Material] for processing particles. Can be a [ParticlesMaterial] or a [ShaderMaterial].
+ [Material] for processing particles. Can be a [ParticleProcessMaterial] or a [ShaderMaterial].
</member>
<member name="randomness" type="float" setter="set_randomness_ratio" getter="get_randomness_ratio" default="0.0">
Emission randomness ratio.
diff --git a/doc/classes/GPUParticlesAttractor3D.xml b/doc/classes/GPUParticlesAttractor3D.xml
index e69255cc31..a1c49afcca 100644
--- a/doc/classes/GPUParticlesAttractor3D.xml
+++ b/doc/classes/GPUParticlesAttractor3D.xml
@@ -18,7 +18,7 @@
<member name="cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask" default="4294967295">
The particle rendering layers ([member VisualInstance3D.layers]) that will be affected by the attractor. By default, all particles are affected by an attractor.
After configuring particle nodes accordingly, specific layers can be unchecked to prevent certain particles from being affected by attractors. For example, this can be used if you're using an attractor as part of a spell effect but don't want the attractor to affect unrelated weather particles at the same position.
- Particle attraction can also be disabled on a per-process material basis by setting [member ParticlesMaterial.attractor_interaction_enabled] on the [GPUParticles3D] node.
+ Particle attraction can also be disabled on a per-process material basis by setting [member ParticleProcessMaterial.attractor_interaction_enabled] on the [GPUParticles3D] node.
</member>
<member name="directionality" type="float" setter="set_directionality" getter="get_directionality" default="0.0">
Adjusts how directional the attractor is. At [code]0.0[/code], the attractor is not directional at all: it will attract particles towards its center. At [code]1.0[/code], the attractor is fully directional: particles will always be pushed towards local -Z (or +Z if [member strength] is negative).
diff --git a/doc/classes/GPUParticlesCollision3D.xml b/doc/classes/GPUParticlesCollision3D.xml
index 435f9781f0..1b744f7ed6 100644
--- a/doc/classes/GPUParticlesCollision3D.xml
+++ b/doc/classes/GPUParticlesCollision3D.xml
@@ -7,7 +7,7 @@
Particle collision shapes can be used to make particles stop or bounce against them.
Particle collision shapes in real-time and can be moved, rotated and scaled during gameplay. Unlike attractors, non-uniform scaling of collision shapes is [i]not[/i] supported.
Particle collision shapes can be temporarily disabled by hiding them.
- [b]Note:[/b] [member ParticlesMaterial.collision_enabled] must be [code]true[/code] on the [GPUParticles3D]'s process material for collision to work.
+ [b]Note:[/b] [member ParticleProcessMaterial.collision_mode] must be [constant ParticleProcessMaterial.COLLISION_RIGID] or [constant ParticleProcessMaterial.COLLISION_HIDE_ON_CONTACT] on the [GPUParticles3D]'s process material for collision to work.
[b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D].
[b]Note:[/b] Particles pushed by a collider that is being moved will not be interpolated, which can result in visible stuttering. This can be alleviated by setting [member GPUParticles3D.fixed_fps] to [code]0[/code] or a value that matches or exceeds the target framerate.
</description>
@@ -15,9 +15,9 @@
</tutorials>
<members>
<member name="cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask" default="4294967295">
- The particle rendering layers ([member VisualInstance3D.layers]) that will be affected by the collision shape. By default, all particles that have [member ParticlesMaterial.collision_enabled] set to [code]true[/code] will be affected by a collision shape.
+ The particle rendering layers ([member VisualInstance3D.layers]) that will be affected by the collision shape. By default, all particles that have [member ParticleProcessMaterial.collision_mode] set to [constant ParticleProcessMaterial.COLLISION_RIGID] or [constant ParticleProcessMaterial.COLLISION_HIDE_ON_CONTACT] will be affected by a collision shape.
After configuring particle nodes accordingly, specific layers can be unchecked to prevent certain particles from being affected by attractors. For example, this can be used if you're using an attractor as part of a spell effect but don't want the attractor to affect unrelated weather particles at the same position.
- Particle attraction can also be disabled on a per-process material basis by setting [member ParticlesMaterial.attractor_interaction_enabled] on the [GPUParticles3D] node.
+ Particle attraction can also be disabled on a per-process material basis by setting [member ParticleProcessMaterial.attractor_interaction_enabled] on the [GPUParticles3D] node.
</member>
</members>
</class>
diff --git a/doc/classes/GPUParticlesCollisionBox3D.xml b/doc/classes/GPUParticlesCollisionBox3D.xml
index 60d66ca682..103be18bfd 100644
--- a/doc/classes/GPUParticlesCollisionBox3D.xml
+++ b/doc/classes/GPUParticlesCollisionBox3D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Box-shaped 3D particle collision shape affecting [GPUParticles3D] nodes.
- [b]Note:[/b] [member ParticlesMaterial.collision_enabled] must be [code]true[/code] on the [GPUParticles3D]'s process material for collision to work.
+ [b]Note:[/b] [member ParticleProcessMaterial.collision_mode] must be [constant ParticleProcessMaterial.COLLISION_RIGID] or [constant ParticleProcessMaterial.COLLISION_HIDE_ON_CONTACT] on the [GPUParticles3D]'s process material for collision to work.
[b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D].
</description>
<tutorials>
diff --git a/doc/classes/GPUParticlesCollisionHeightField3D.xml b/doc/classes/GPUParticlesCollisionHeightField3D.xml
index 3fcad43efb..6e996d5fbd 100644
--- a/doc/classes/GPUParticlesCollisionHeightField3D.xml
+++ b/doc/classes/GPUParticlesCollisionHeightField3D.xml
@@ -7,7 +7,7 @@
Real-time heightmap-shaped 3D particle attractor affecting [GPUParticles3D] nodes.
Heightmap shapes allow for efficiently representing collisions for convex and concave objects with a single "floor" (such as terrain). This is less flexible than [GPUParticlesCollisionSDF3D], but it doesn't require a baking step.
[GPUParticlesCollisionHeightField3D] can also be regenerated in real-time when it is moved, when the camera moves, or even continuously. This makes [GPUParticlesCollisionHeightField3D] a good choice for weather effects such as rain and snow and games with highly dynamic geometry. However, since heightmaps cannot represent overhangs, [GPUParticlesCollisionHeightField3D] is not suited for indoor particle collision.
- [b]Note:[/b] [member ParticlesMaterial.collision_enabled] must be [code]true[/code] on the [GPUParticles3D]'s process material for collision to work.
+ [b]Note:[/b] [member ParticleProcessMaterial.collision_mode] must be [code]true[/code] on the [GPUParticles3D]'s process material for collision to work.
[b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D].
</description>
<tutorials>
diff --git a/doc/classes/GPUParticlesCollisionSDF3D.xml b/doc/classes/GPUParticlesCollisionSDF3D.xml
index c9af07288e..8467cfdda1 100644
--- a/doc/classes/GPUParticlesCollisionSDF3D.xml
+++ b/doc/classes/GPUParticlesCollisionSDF3D.xml
@@ -8,12 +8,32 @@
Signed distance fields (SDF) allow for efficiently representing approximate collision shapes for convex and concave objects of any shape. This is more flexible than [GPUParticlesCollisionHeightField3D], but it requires a baking step.
[b]Baking:[/b] The signed distance field texture can be baked by selecting the [GPUParticlesCollisionSDF3D] node in the editor, then clicking [b]Bake SDF[/b] at the top of the 3D viewport. Any [i]visible[/i] [MeshInstance3D]s touching the [member extents] will be taken into account for baking, regardless of their [member GeometryInstance3D.gi_mode].
[b]Note:[/b] Baking a [GPUParticlesCollisionSDF3D]'s [member texture] is only possible within the editor, as there is no bake method exposed for use in exported projects. However, it's still possible to load pre-baked [Texture3D]s into its [member texture] property in an exported project.
- [b]Note:[/b] [member ParticlesMaterial.collision_enabled] must be [code]true[/code] on the [GPUParticles3D]'s process material for collision to work.
+ [b]Note:[/b] [member ParticleProcessMaterial.collision_mode] must be [constant ParticleProcessMaterial.COLLISION_RIGID] or [constant ParticleProcessMaterial.COLLISION_HIDE_ON_CONTACT] on the [GPUParticles3D]'s process material for collision to work.
[b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D].
</description>
<tutorials>
</tutorials>
+ <methods>
+ <method name="get_bake_mask_value" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <description>
+ Returns whether or not the specified layer of the [member bake_mask] is enabled, given a [param layer_number] between 1 and 32.
+ </description>
+ </method>
+ <method name="set_bake_mask_value">
+ <return type="void" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
+ <description>
+ Based on [param value], enables or disables the specified layer in the [member bake_mask], given a [param layer_number] between 1 and 32.
+ </description>
+ </method>
+ </methods>
<members>
+ <member name="bake_mask" type="int" setter="set_bake_mask" getter="get_bake_mask" default="4294967295">
+ The visual layers to account for when baking the particle collision SDF. Only [MeshInstance3D]s whose [member VisualInstance3D.layers] match with this [member bake_mask] will be included in the generated particle collision SDF. By default, all objects are taken into account for the particle collision SDF baking.
+ </member>
<member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3(1, 1, 1)">
The collision SDF's extents in 3D units. To improve SDF quality, the [member extents] should be set as small as possible while covering the parts of the scene you need.
</member>
diff --git a/doc/classes/GPUParticlesCollisionSphere3D.xml b/doc/classes/GPUParticlesCollisionSphere3D.xml
index 6651a732da..ee582108dd 100644
--- a/doc/classes/GPUParticlesCollisionSphere3D.xml
+++ b/doc/classes/GPUParticlesCollisionSphere3D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Sphere-shaped 3D particle collision shape affecting [GPUParticles3D] nodes.
- [b]Note:[/b] [member ParticlesMaterial.collision_enabled] must be [code]true[/code] on the [GPUParticles3D]'s process material for collision to work.
+ [b]Note:[/b] [member ParticleProcessMaterial.collision_mode] must be [constant ParticleProcessMaterial.COLLISION_RIGID] or [constant ParticleProcessMaterial.COLLISION_HIDE_ON_CONTACT] on the [GPUParticles3D]'s process material for collision to work.
[b]Note:[/b] Particle collision only affects [GPUParticles3D], not [CPUParticles3D].
</description>
<tutorials>
diff --git a/doc/classes/Generic6DOFJoint3D.xml b/doc/classes/Generic6DOFJoint3D.xml
index b1bc411a21..e6058b1bf9 100644
--- a/doc/classes/Generic6DOFJoint3D.xml
+++ b/doc/classes/Generic6DOFJoint3D.xml
@@ -11,79 +11,79 @@
<methods>
<method name="get_flag_x" qualifiers="const">
<return type="bool" />
- <argument index="0" name="flag" type="int" enum="Generic6DOFJoint3D.Flag" />
+ <param index="0" name="flag" type="int" enum="Generic6DOFJoint3D.Flag" />
<description>
</description>
</method>
<method name="get_flag_y" qualifiers="const">
<return type="bool" />
- <argument index="0" name="flag" type="int" enum="Generic6DOFJoint3D.Flag" />
+ <param index="0" name="flag" type="int" enum="Generic6DOFJoint3D.Flag" />
<description>
</description>
</method>
<method name="get_flag_z" qualifiers="const">
<return type="bool" />
- <argument index="0" name="flag" type="int" enum="Generic6DOFJoint3D.Flag" />
+ <param index="0" name="flag" type="int" enum="Generic6DOFJoint3D.Flag" />
<description>
</description>
</method>
<method name="get_param_x" qualifiers="const">
<return type="float" />
- <argument index="0" name="param" type="int" enum="Generic6DOFJoint3D.Param" />
+ <param index="0" name="param" type="int" enum="Generic6DOFJoint3D.Param" />
<description>
</description>
</method>
<method name="get_param_y" qualifiers="const">
<return type="float" />
- <argument index="0" name="param" type="int" enum="Generic6DOFJoint3D.Param" />
+ <param index="0" name="param" type="int" enum="Generic6DOFJoint3D.Param" />
<description>
</description>
</method>
<method name="get_param_z" qualifiers="const">
<return type="float" />
- <argument index="0" name="param" type="int" enum="Generic6DOFJoint3D.Param" />
+ <param index="0" name="param" type="int" enum="Generic6DOFJoint3D.Param" />
<description>
</description>
</method>
<method name="set_flag_x">
<return type="void" />
- <argument index="0" name="flag" type="int" enum="Generic6DOFJoint3D.Flag" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="flag" type="int" enum="Generic6DOFJoint3D.Flag" />
+ <param index="1" name="value" type="bool" />
<description>
</description>
</method>
<method name="set_flag_y">
<return type="void" />
- <argument index="0" name="flag" type="int" enum="Generic6DOFJoint3D.Flag" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="flag" type="int" enum="Generic6DOFJoint3D.Flag" />
+ <param index="1" name="value" type="bool" />
<description>
</description>
</method>
<method name="set_flag_z">
<return type="void" />
- <argument index="0" name="flag" type="int" enum="Generic6DOFJoint3D.Flag" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="flag" type="int" enum="Generic6DOFJoint3D.Flag" />
+ <param index="1" name="value" type="bool" />
<description>
</description>
</method>
<method name="set_param_x">
<return type="void" />
- <argument index="0" name="param" type="int" enum="Generic6DOFJoint3D.Param" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="param" type="int" enum="Generic6DOFJoint3D.Param" />
+ <param index="1" name="value" type="float" />
<description>
</description>
</method>
<method name="set_param_y">
<return type="void" />
- <argument index="0" name="param" type="int" enum="Generic6DOFJoint3D.Param" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="param" type="int" enum="Generic6DOFJoint3D.Param" />
+ <param index="1" name="value" type="float" />
<description>
</description>
</method>
<method name="set_param_z">
<return type="void" />
- <argument index="0" name="param" type="int" enum="Generic6DOFJoint3D.Param" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="param" type="int" enum="Generic6DOFJoint3D.Param" />
+ <param index="1" name="value" type="float" />
<description>
</description>
</method>
@@ -102,7 +102,7 @@
<member name="angular_limit_x/force_limit" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
The maximum amount of force that can occur, when rotating around the X axis.
</member>
- <member name="angular_limit_x/lower_angle" type="float" setter="_set_angular_lo_limit_x" getter="_get_angular_lo_limit_x" default="0.0">
+ <member name="angular_limit_x/lower_angle" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
The minimum rotation in negative direction to break loose and rotate around the X axis.
</member>
<member name="angular_limit_x/restitution" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
@@ -111,7 +111,7 @@
<member name="angular_limit_x/softness" type="float" setter="set_param_x" getter="get_param_x" default="0.5">
The speed of all rotations across the X axis.
</member>
- <member name="angular_limit_x/upper_angle" type="float" setter="_set_angular_hi_limit_x" getter="_get_angular_hi_limit_x" default="0.0">
+ <member name="angular_limit_x/upper_angle" type="float" setter="set_param_x" getter="get_param_x" default="0.0">
The minimum rotation in positive direction to break loose and rotate around the X axis.
</member>
<member name="angular_limit_y/damping" type="float" setter="set_param_y" getter="get_param_y" default="1.0">
@@ -126,7 +126,7 @@
<member name="angular_limit_y/force_limit" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
The maximum amount of force that can occur, when rotating around the Y axis.
</member>
- <member name="angular_limit_y/lower_angle" type="float" setter="_set_angular_lo_limit_y" getter="_get_angular_lo_limit_y" default="0.0">
+ <member name="angular_limit_y/lower_angle" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
The minimum rotation in negative direction to break loose and rotate around the Y axis.
</member>
<member name="angular_limit_y/restitution" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
@@ -135,7 +135,7 @@
<member name="angular_limit_y/softness" type="float" setter="set_param_y" getter="get_param_y" default="0.5">
The speed of all rotations across the Y axis.
</member>
- <member name="angular_limit_y/upper_angle" type="float" setter="_set_angular_hi_limit_y" getter="_get_angular_hi_limit_y" default="0.0">
+ <member name="angular_limit_y/upper_angle" type="float" setter="set_param_y" getter="get_param_y" default="0.0">
The minimum rotation in positive direction to break loose and rotate around the Y axis.
</member>
<member name="angular_limit_z/damping" type="float" setter="set_param_z" getter="get_param_z" default="1.0">
@@ -150,7 +150,7 @@
<member name="angular_limit_z/force_limit" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
The maximum amount of force that can occur, when rotating around the Z axis.
</member>
- <member name="angular_limit_z/lower_angle" type="float" setter="_set_angular_lo_limit_z" getter="_get_angular_lo_limit_z" default="0.0">
+ <member name="angular_limit_z/lower_angle" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
The minimum rotation in negative direction to break loose and rotate around the Z axis.
</member>
<member name="angular_limit_z/restitution" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
@@ -159,7 +159,7 @@
<member name="angular_limit_z/softness" type="float" setter="set_param_z" getter="get_param_z" default="0.5">
The speed of all rotations across the Z axis.
</member>
- <member name="angular_limit_z/upper_angle" type="float" setter="_set_angular_hi_limit_z" getter="_get_angular_hi_limit_z" default="0.0">
+ <member name="angular_limit_z/upper_angle" type="float" setter="set_param_z" getter="get_param_z" default="0.0">
The minimum rotation in positive direction to break loose and rotate around the Z axis.
</member>
<member name="angular_motor_x/enabled" type="bool" setter="set_flag_x" getter="get_flag_x" default="false">
diff --git a/doc/classes/Geometry2D.xml b/doc/classes/Geometry2D.xml
index 195c481187..392ca2cabb 100644
--- a/doc/classes/Geometry2D.xml
+++ b/doc/classes/Geometry2D.xml
@@ -10,142 +10,142 @@
</tutorials>
<methods>
<method name="clip_polygons">
- <return type="Array" />
- <argument index="0" name="polygon_a" type="PackedVector2Array" />
- <argument index="1" name="polygon_b" type="PackedVector2Array" />
+ <return type="PackedVector2Array[]" />
+ <param index="0" name="polygon_a" type="PackedVector2Array" />
+ <param index="1" name="polygon_b" type="PackedVector2Array" />
<description>
- Clips [code]polygon_a[/code] against [code]polygon_b[/code] and returns an array of clipped polygons. This performs [constant OPERATION_DIFFERENCE] between polygons. Returns an empty array if [code]polygon_b[/code] completely overlaps [code]polygon_a[/code].
- If [code]polygon_b[/code] is enclosed by [code]polygon_a[/code], returns an outer polygon (boundary) and inner polygon (hole) which could be distinguished by calling [method is_polygon_clockwise].
+ Clips [param polygon_a] against [param polygon_b] and returns an array of clipped polygons. This performs [constant OPERATION_DIFFERENCE] between polygons. Returns an empty array if [param polygon_b] completely overlaps [param polygon_a].
+ If [param polygon_b] is enclosed by [param polygon_a], returns an outer polygon (boundary) and inner polygon (hole) which could be distinguished by calling [method is_polygon_clockwise].
</description>
</method>
<method name="clip_polyline_with_polygon">
- <return type="Array" />
- <argument index="0" name="polyline" type="PackedVector2Array" />
- <argument index="1" name="polygon" type="PackedVector2Array" />
+ <return type="PackedVector2Array[]" />
+ <param index="0" name="polyline" type="PackedVector2Array" />
+ <param index="1" name="polygon" type="PackedVector2Array" />
<description>
- Clips [code]polyline[/code] against [code]polygon[/code] and returns an array of clipped polylines. This performs [constant OPERATION_DIFFERENCE] between the polyline and the polygon. This operation can be thought of as cutting a line with a closed shape.
+ Clips [param polyline] against [param polygon] and returns an array of clipped polylines. This performs [constant OPERATION_DIFFERENCE] between the polyline and the polygon. This operation can be thought of as cutting a line with a closed shape.
</description>
</method>
<method name="convex_hull">
<return type="PackedVector2Array" />
- <argument index="0" name="points" type="PackedVector2Array" />
+ <param index="0" name="points" type="PackedVector2Array" />
<description>
Given an array of [Vector2]s, returns the convex hull as a list of points in counterclockwise order. The last point is the same as the first one.
</description>
</method>
<method name="exclude_polygons">
- <return type="Array" />
- <argument index="0" name="polygon_a" type="PackedVector2Array" />
- <argument index="1" name="polygon_b" type="PackedVector2Array" />
+ <return type="PackedVector2Array[]" />
+ <param index="0" name="polygon_a" type="PackedVector2Array" />
+ <param index="1" name="polygon_b" type="PackedVector2Array" />
<description>
- Mutually excludes common area defined by intersection of [code]polygon_a[/code] and [code]polygon_b[/code] (see [method intersect_polygons]) and returns an array of excluded polygons. This performs [constant OPERATION_XOR] between polygons. In other words, returns all but common area between polygons.
+ Mutually excludes common area defined by intersection of [param polygon_a] and [param polygon_b] (see [method intersect_polygons]) and returns an array of excluded polygons. This performs [constant OPERATION_XOR] between polygons. In other words, returns all but common area between polygons.
The operation may result in an outer polygon (boundary) and inner polygon (hole) produced which could be distinguished by calling [method is_polygon_clockwise].
</description>
</method>
<method name="get_closest_point_to_segment">
<return type="Vector2" />
- <argument index="0" name="point" type="Vector2" />
- <argument index="1" name="s1" type="Vector2" />
- <argument index="2" name="s2" type="Vector2" />
+ <param index="0" name="point" type="Vector2" />
+ <param index="1" name="s1" type="Vector2" />
+ <param index="2" name="s2" type="Vector2" />
<description>
- Returns the 2D point on the 2D segment ([code]s1[/code], [code]s2[/code]) that is closest to [code]point[/code]. The returned point will always be inside the specified segment.
+ Returns the 2D point on the 2D segment ([param s1], [param s2]) that is closest to [param point]. The returned point will always be inside the specified segment.
</description>
</method>
<method name="get_closest_point_to_segment_uncapped">
<return type="Vector2" />
- <argument index="0" name="point" type="Vector2" />
- <argument index="1" name="s1" type="Vector2" />
- <argument index="2" name="s2" type="Vector2" />
+ <param index="0" name="point" type="Vector2" />
+ <param index="1" name="s1" type="Vector2" />
+ <param index="2" name="s2" type="Vector2" />
<description>
- Returns the 2D point on the 2D line defined by ([code]s1[/code], [code]s2[/code]) that is closest to [code]point[/code]. The returned point can be inside the segment ([code]s1[/code], [code]s2[/code]) or outside of it, i.e. somewhere on the line extending from the segment.
+ Returns the 2D point on the 2D line defined by ([param s1], [param s2]) that is closest to [param point]. The returned point can be inside the segment ([param s1], [param s2]) or outside of it, i.e. somewhere on the line extending from the segment.
</description>
</method>
<method name="get_closest_points_between_segments">
<return type="PackedVector2Array" />
- <argument index="0" name="p1" type="Vector2" />
- <argument index="1" name="q1" type="Vector2" />
- <argument index="2" name="p2" type="Vector2" />
- <argument index="3" name="q2" type="Vector2" />
+ <param index="0" name="p1" type="Vector2" />
+ <param index="1" name="q1" type="Vector2" />
+ <param index="2" name="p2" type="Vector2" />
+ <param index="3" name="q2" type="Vector2" />
<description>
- Given the two 2D segments ([code]p1[/code], [code]q1[/code]) and ([code]p2[/code], [code]q2[/code]), finds those two points on the two segments that are closest to each other. Returns a [PackedVector2Array] that contains this point on ([code]p1[/code], [code]q1[/code]) as well the accompanying point on ([code]p2[/code], [code]q2[/code]).
+ Given the two 2D segments ([param p1], [param q1]) and ([param p2], [param q2]), finds those two points on the two segments that are closest to each other. Returns a [PackedVector2Array] that contains this point on ([param p1], [param q1]) as well the accompanying point on ([param p2], [param q2]).
</description>
</method>
<method name="intersect_polygons">
- <return type="Array" />
- <argument index="0" name="polygon_a" type="PackedVector2Array" />
- <argument index="1" name="polygon_b" type="PackedVector2Array" />
+ <return type="PackedVector2Array[]" />
+ <param index="0" name="polygon_a" type="PackedVector2Array" />
+ <param index="1" name="polygon_b" type="PackedVector2Array" />
<description>
- Intersects [code]polygon_a[/code] with [code]polygon_b[/code] and returns an array of intersected polygons. This performs [constant OPERATION_INTERSECTION] between polygons. In other words, returns common area shared by polygons. Returns an empty array if no intersection occurs.
+ Intersects [param polygon_a] with [param polygon_b] and returns an array of intersected polygons. This performs [constant OPERATION_INTERSECTION] between polygons. In other words, returns common area shared by polygons. Returns an empty array if no intersection occurs.
The operation may result in an outer polygon (boundary) and inner polygon (hole) produced which could be distinguished by calling [method is_polygon_clockwise].
</description>
</method>
<method name="intersect_polyline_with_polygon">
- <return type="Array" />
- <argument index="0" name="polyline" type="PackedVector2Array" />
- <argument index="1" name="polygon" type="PackedVector2Array" />
+ <return type="PackedVector2Array[]" />
+ <param index="0" name="polyline" type="PackedVector2Array" />
+ <param index="1" name="polygon" type="PackedVector2Array" />
<description>
- Intersects [code]polyline[/code] with [code]polygon[/code] and returns an array of intersected polylines. This performs [constant OPERATION_INTERSECTION] between the polyline and the polygon. This operation can be thought of as chopping a line with a closed shape.
+ Intersects [param polyline] with [param polygon] and returns an array of intersected polylines. This performs [constant OPERATION_INTERSECTION] between the polyline and the polygon. This operation can be thought of as chopping a line with a closed shape.
</description>
</method>
<method name="is_point_in_circle">
<return type="bool" />
- <argument index="0" name="point" type="Vector2" />
- <argument index="1" name="circle_position" type="Vector2" />
- <argument index="2" name="circle_radius" type="float" />
+ <param index="0" name="point" type="Vector2" />
+ <param index="1" name="circle_position" type="Vector2" />
+ <param index="2" name="circle_radius" type="float" />
<description>
- Returns [code]true[/code] if [code]point[/code] is inside the circle or if it's located exactly [i]on[/i] the circle's boundary, otherwise returns [code]false[/code].
+ Returns [code]true[/code] if [param point] is inside the circle or if it's located exactly [i]on[/i] the circle's boundary, otherwise returns [code]false[/code].
</description>
</method>
<method name="is_point_in_polygon">
<return type="bool" />
- <argument index="0" name="point" type="Vector2" />
- <argument index="1" name="polygon" type="PackedVector2Array" />
+ <param index="0" name="point" type="Vector2" />
+ <param index="1" name="polygon" type="PackedVector2Array" />
<description>
- Returns [code]true[/code] if [code]point[/code] is inside [code]polygon[/code] or if it's located exactly [i]on[/i] polygon's boundary, otherwise returns [code]false[/code].
+ Returns [code]true[/code] if [param point] is inside [param polygon] or if it's located exactly [i]on[/i] polygon's boundary, otherwise returns [code]false[/code].
</description>
</method>
<method name="is_polygon_clockwise">
<return type="bool" />
- <argument index="0" name="polygon" type="PackedVector2Array" />
+ <param index="0" name="polygon" type="PackedVector2Array" />
<description>
- Returns [code]true[/code] if [code]polygon[/code]'s vertices are ordered in clockwise order, otherwise returns [code]false[/code].
+ Returns [code]true[/code] if [param polygon]'s vertices are ordered in clockwise order, otherwise returns [code]false[/code].
</description>
</method>
<method name="line_intersects_line">
<return type="Variant" />
- <argument index="0" name="from_a" type="Vector2" />
- <argument index="1" name="dir_a" type="Vector2" />
- <argument index="2" name="from_b" type="Vector2" />
- <argument index="3" name="dir_b" type="Vector2" />
+ <param index="0" name="from_a" type="Vector2" />
+ <param index="1" name="dir_a" type="Vector2" />
+ <param index="2" name="from_b" type="Vector2" />
+ <param index="3" name="dir_b" type="Vector2" />
<description>
- Checks if the two lines ([code]from_a[/code], [code]dir_a[/code]) and ([code]from_b[/code], [code]dir_b[/code]) intersect. If yes, return the point of intersection as [Vector2]. If no intersection takes place, returns [code]null[/code].
+ Checks if the two lines ([param from_a], [param dir_a]) and ([param from_b], [param dir_b]) intersect. If yes, return the point of intersection as [Vector2]. If no intersection takes place, returns [code]null[/code].
[b]Note:[/b] The lines are specified using direction vectors, not end points.
</description>
</method>
<method name="make_atlas">
<return type="Dictionary" />
- <argument index="0" name="sizes" type="PackedVector2Array" />
+ <param index="0" name="sizes" type="PackedVector2Array" />
<description>
Given an array of [Vector2]s representing tiles, builds an atlas. The returned dictionary has two keys: [code]points[/code] is an array of [Vector2] that specifies the positions of each tile, [code]size[/code] contains the overall size of the whole atlas as [Vector2].
</description>
</method>
<method name="merge_polygons">
- <return type="Array" />
- <argument index="0" name="polygon_a" type="PackedVector2Array" />
- <argument index="1" name="polygon_b" type="PackedVector2Array" />
+ <return type="PackedVector2Array[]" />
+ <param index="0" name="polygon_a" type="PackedVector2Array" />
+ <param index="1" name="polygon_b" type="PackedVector2Array" />
<description>
- Merges (combines) [code]polygon_a[/code] and [code]polygon_b[/code] and returns an array of merged polygons. This performs [constant OPERATION_UNION] between polygons.
+ Merges (combines) [param polygon_a] and [param polygon_b] and returns an array of merged polygons. This performs [constant OPERATION_UNION] between polygons.
The operation may result in an outer polygon (boundary) and multiple inner polygons (holes) produced which could be distinguished by calling [method is_polygon_clockwise].
</description>
</method>
<method name="offset_polygon">
- <return type="Array" />
- <argument index="0" name="polygon" type="PackedVector2Array" />
- <argument index="1" name="delta" type="float" />
- <argument index="2" name="join_type" type="int" enum="Geometry2D.PolyJoinType" default="0" />
+ <return type="PackedVector2Array[]" />
+ <param index="0" name="polygon" type="PackedVector2Array" />
+ <param index="1" name="delta" type="float" />
+ <param index="2" name="join_type" type="int" enum="Geometry2D.PolyJoinType" default="0" />
<description>
- Inflates or deflates [code]polygon[/code] by [code]delta[/code] units (pixels). If [code]delta[/code] is positive, makes the polygon grow outward. If [code]delta[/code] is negative, shrinks the polygon inward. Returns an array of polygons because inflating/deflating may result in multiple discrete polygons. Returns an empty array if [code]delta[/code] is negative and the absolute value of it approximately exceeds the minimum bounding rectangle dimensions of the polygon.
- Each polygon's vertices will be rounded as determined by [code]join_type[/code], see [enum PolyJoinType].
+ Inflates or deflates [param polygon] by [param delta] units (pixels). If [param delta] is positive, makes the polygon grow outward. If [param delta] is negative, shrinks the polygon inward. Returns an array of polygons because inflating/deflating may result in multiple discrete polygons. Returns an empty array if [param delta] is negative and the absolute value of it approximately exceeds the minimum bounding rectangle dimensions of the polygon.
+ Each polygon's vertices will be rounded as determined by [param join_type], see [enum PolyJoinType].
The operation may result in an outer polygon (boundary) and inner polygon (hole) produced which could be distinguished by calling [method is_polygon_clockwise].
[b]Note:[/b] To translate the polygon's vertices specifically, multiply them to a [Transform2D]:
[codeblocks]
@@ -166,50 +166,60 @@
</description>
</method>
<method name="offset_polyline">
- <return type="Array" />
- <argument index="0" name="polyline" type="PackedVector2Array" />
- <argument index="1" name="delta" type="float" />
- <argument index="2" name="join_type" type="int" enum="Geometry2D.PolyJoinType" default="0" />
- <argument index="3" name="end_type" type="int" enum="Geometry2D.PolyEndType" default="3" />
- <description>
- Inflates or deflates [code]polyline[/code] by [code]delta[/code] units (pixels), producing polygons. If [code]delta[/code] is positive, makes the polyline grow outward. Returns an array of polygons because inflating/deflating may result in multiple discrete polygons. If [code]delta[/code] is negative, returns an empty array.
- Each polygon's vertices will be rounded as determined by [code]join_type[/code], see [enum PolyJoinType].
- Each polygon's endpoints will be rounded as determined by [code]end_type[/code], see [enum PolyEndType].
+ <return type="PackedVector2Array[]" />
+ <param index="0" name="polyline" type="PackedVector2Array" />
+ <param index="1" name="delta" type="float" />
+ <param index="2" name="join_type" type="int" enum="Geometry2D.PolyJoinType" default="0" />
+ <param index="3" name="end_type" type="int" enum="Geometry2D.PolyEndType" default="3" />
+ <description>
+ Inflates or deflates [param polyline] by [param delta] units (pixels), producing polygons. If [param delta] is positive, makes the polyline grow outward. Returns an array of polygons because inflating/deflating may result in multiple discrete polygons. If [param delta] is negative, returns an empty array.
+ Each polygon's vertices will be rounded as determined by [param join_type], see [enum PolyJoinType].
+ Each polygon's endpoints will be rounded as determined by [param end_type], see [enum PolyEndType].
The operation may result in an outer polygon (boundary) and inner polygon (hole) produced which could be distinguished by calling [method is_polygon_clockwise].
</description>
</method>
<method name="point_is_inside_triangle" qualifiers="const">
<return type="bool" />
- <argument index="0" name="point" type="Vector2" />
- <argument index="1" name="a" type="Vector2" />
- <argument index="2" name="b" type="Vector2" />
- <argument index="3" name="c" type="Vector2" />
+ <param index="0" name="point" type="Vector2" />
+ <param index="1" name="a" type="Vector2" />
+ <param index="2" name="b" type="Vector2" />
+ <param index="3" name="c" type="Vector2" />
+ <description>
+ Returns if [param point] is inside the triangle specified by [param a], [param b] and [param c].
+ </description>
+ </method>
+ <method name="segment_intersects_circle">
+ <return type="float" />
+ <param index="0" name="segment_from" type="Vector2" />
+ <param index="1" name="segment_to" type="Vector2" />
+ <param index="2" name="circle_position" type="Vector2" />
+ <param index="3" name="circle_radius" type="float" />
<description>
- Returns if [code]point[/code] is inside the triangle specified by [code]a[/code], [code]b[/code] and [code]c[/code].
+ Given the 2D segment ([param segment_from], [param segment_to]), returns the position on the segment (as a number between 0 and 1) at which the segment hits the circle that is located at position [param circle_position] and has radius [param circle_radius]. If the segment does not intersect the circle, -1 is returned (this is also the case if the line extending the segment would intersect the circle, but the segment does not).
</description>
</method>
<method name="segment_intersects_segment">
<return type="Variant" />
- <argument index="0" name="from_a" type="Vector2" />
- <argument index="1" name="to_a" type="Vector2" />
- <argument index="2" name="from_b" type="Vector2" />
- <argument index="3" name="to_b" type="Vector2" />
+ <param index="0" name="from_a" type="Vector2" />
+ <param index="1" name="to_a" type="Vector2" />
+ <param index="2" name="from_b" type="Vector2" />
+ <param index="3" name="to_b" type="Vector2" />
<description>
- Checks if the two segments ([code]from_a[/code], [code]to_a[/code]) and ([code]from_b[/code], [code]to_b[/code]) intersect. If yes, return the point of intersection as [Vector2]. If no intersection takes place, returns [code]null[/code].
+ Checks if the two segments ([param from_a], [param to_a]) and ([param from_b], [param to_b]) intersect. If yes, return the point of intersection as [Vector2]. If no intersection takes place, returns [code]null[/code].
</description>
</method>
<method name="triangulate_delaunay">
<return type="PackedInt32Array" />
- <argument index="0" name="points" type="PackedVector2Array" />
+ <param index="0" name="points" type="PackedVector2Array" />
<description>
- Triangulates the area specified by discrete set of [code]points[/code] such that no point is inside the circumcircle of any resulting triangle. Returns a [PackedInt32Array] where each triangle consists of three consecutive point indices into [code]points[/code] (i.e. the returned array will have [code]n * 3[/code] elements, with [code]n[/code] being the number of found triangles). If the triangulation did not succeed, an empty [PackedInt32Array] is returned.
+ Triangulates the area specified by discrete set of [param points] such that no point is inside the circumcircle of any resulting triangle. Returns a [PackedInt32Array] where each triangle consists of three consecutive point indices into [param points] (i.e. the returned array will have [code]n * 3[/code] elements, with [code]n[/code] being the number of found triangles). If the triangulation did not succeed, an empty [PackedInt32Array] is returned.
</description>
</method>
<method name="triangulate_polygon">
<return type="PackedInt32Array" />
- <argument index="0" name="polygon" type="PackedVector2Array" />
+ <param index="0" name="polygon" type="PackedVector2Array" />
<description>
- Triangulates the polygon specified by the points in [code]polygon[/code]. Returns a [PackedInt32Array] where each triangle consists of three consecutive point indices into [code]polygon[/code] (i.e. the returned array will have [code]n * 3[/code] elements, with [code]n[/code] being the number of found triangles). Output triangles will always be counter clockwise, and the contour will be flipped if it's clockwise. If the triangulation did not succeed, an empty [PackedInt32Array] is returned.
+ Triangulates the polygon specified by the points in [param polygon]. Returns a [PackedInt32Array] where each triangle consists of three consecutive point indices into [param polygon] (i.e. the returned array will have [code]n * 3[/code] elements, with [code]n[/code] being the number of found triangles). Output triangles will always be counter clockwise, and the contour will be flipped if it's clockwise. If the triangulation did not succeed, an empty [PackedInt32Array] is returned.
</description>
</method>
</methods>
diff --git a/doc/classes/Geometry3D.xml b/doc/classes/Geometry3D.xml
index c05d7df53f..d37b0b7b81 100644
--- a/doc/classes/Geometry3D.xml
+++ b/doc/classes/Geometry3D.xml
@@ -10,118 +10,118 @@
</tutorials>
<methods>
<method name="build_box_planes">
- <return type="Array" />
- <argument index="0" name="extents" type="Vector3" />
+ <return type="Plane[]" />
+ <param index="0" name="extents" type="Vector3" />
<description>
- Returns an array with 6 [Plane]s that describe the sides of a box centered at the origin. The box size is defined by [code]extents[/code], which represents one (positive) corner of the box (i.e. half its actual size).
+ Returns an array with 6 [Plane]s that describe the sides of a box centered at the origin. The box size is defined by [param extents], which represents one (positive) corner of the box (i.e. half its actual size).
</description>
</method>
<method name="build_capsule_planes">
- <return type="Array" />
- <argument index="0" name="radius" type="float" />
- <argument index="1" name="height" type="float" />
- <argument index="2" name="sides" type="int" />
- <argument index="3" name="lats" type="int" />
- <argument index="4" name="axis" type="int" enum="Vector3.Axis" default="2" />
+ <return type="Plane[]" />
+ <param index="0" name="radius" type="float" />
+ <param index="1" name="height" type="float" />
+ <param index="2" name="sides" type="int" />
+ <param index="3" name="lats" type="int" />
+ <param index="4" name="axis" type="int" enum="Vector3.Axis" default="2" />
<description>
- Returns an array of [Plane]s closely bounding a faceted capsule centered at the origin with radius [code]radius[/code] and height [code]height[/code]. The parameter [code]sides[/code] defines how many planes will be generated for the side part of the capsule, whereas [code]lats[/code] gives the number of latitudinal steps at the bottom and top of the capsule. The parameter [code]axis[/code] describes the axis along which the capsule is oriented (0 for X, 1 for Y, 2 for Z).
+ Returns an array of [Plane]s closely bounding a faceted capsule centered at the origin with radius [param radius] and height [param height]. The parameter [param sides] defines how many planes will be generated for the side part of the capsule, whereas [param lats] gives the number of latitudinal steps at the bottom and top of the capsule. The parameter [param axis] describes the axis along which the capsule is oriented (0 for X, 1 for Y, 2 for Z).
</description>
</method>
<method name="build_cylinder_planes">
- <return type="Array" />
- <argument index="0" name="radius" type="float" />
- <argument index="1" name="height" type="float" />
- <argument index="2" name="sides" type="int" />
- <argument index="3" name="axis" type="int" enum="Vector3.Axis" default="2" />
+ <return type="Plane[]" />
+ <param index="0" name="radius" type="float" />
+ <param index="1" name="height" type="float" />
+ <param index="2" name="sides" type="int" />
+ <param index="3" name="axis" type="int" enum="Vector3.Axis" default="2" />
<description>
- Returns an array of [Plane]s closely bounding a faceted cylinder centered at the origin with radius [code]radius[/code] and height [code]height[/code]. The parameter [code]sides[/code] defines how many planes will be generated for the round part of the cylinder. The parameter [code]axis[/code] describes the axis along which the cylinder is oriented (0 for X, 1 for Y, 2 for Z).
+ Returns an array of [Plane]s closely bounding a faceted cylinder centered at the origin with radius [param radius] and height [param height]. The parameter [param sides] defines how many planes will be generated for the round part of the cylinder. The parameter [param axis] describes the axis along which the cylinder is oriented (0 for X, 1 for Y, 2 for Z).
</description>
</method>
<method name="clip_polygon">
<return type="PackedVector3Array" />
- <argument index="0" name="points" type="PackedVector3Array" />
- <argument index="1" name="plane" type="Plane" />
+ <param index="0" name="points" type="PackedVector3Array" />
+ <param index="1" name="plane" type="Plane" />
<description>
- Clips the polygon defined by the points in [code]points[/code] against the [code]plane[/code] and returns the points of the clipped polygon.
+ Clips the polygon defined by the points in [param points] against the [param plane] and returns the points of the clipped polygon.
</description>
</method>
<method name="get_closest_point_to_segment">
<return type="Vector3" />
- <argument index="0" name="point" type="Vector3" />
- <argument index="1" name="s1" type="Vector3" />
- <argument index="2" name="s2" type="Vector3" />
+ <param index="0" name="point" type="Vector3" />
+ <param index="1" name="s1" type="Vector3" />
+ <param index="2" name="s2" type="Vector3" />
<description>
- Returns the 3D point on the 3D segment ([code]s1[/code], [code]s2[/code]) that is closest to [code]point[/code]. The returned point will always be inside the specified segment.
+ Returns the 3D point on the 3D segment ([param s1], [param s2]) that is closest to [param point]. The returned point will always be inside the specified segment.
</description>
</method>
<method name="get_closest_point_to_segment_uncapped">
<return type="Vector3" />
- <argument index="0" name="point" type="Vector3" />
- <argument index="1" name="s1" type="Vector3" />
- <argument index="2" name="s2" type="Vector3" />
+ <param index="0" name="point" type="Vector3" />
+ <param index="1" name="s1" type="Vector3" />
+ <param index="2" name="s2" type="Vector3" />
<description>
- Returns the 3D point on the 3D line defined by ([code]s1[/code], [code]s2[/code]) that is closest to [code]point[/code]. The returned point can be inside the segment ([code]s1[/code], [code]s2[/code]) or outside of it, i.e. somewhere on the line extending from the segment.
+ Returns the 3D point on the 3D line defined by ([param s1], [param s2]) that is closest to [param point]. The returned point can be inside the segment ([param s1], [param s2]) or outside of it, i.e. somewhere on the line extending from the segment.
</description>
</method>
<method name="get_closest_points_between_segments">
<return type="PackedVector3Array" />
- <argument index="0" name="p1" type="Vector3" />
- <argument index="1" name="p2" type="Vector3" />
- <argument index="2" name="q1" type="Vector3" />
- <argument index="3" name="q2" type="Vector3" />
+ <param index="0" name="p1" type="Vector3" />
+ <param index="1" name="p2" type="Vector3" />
+ <param index="2" name="q1" type="Vector3" />
+ <param index="3" name="q2" type="Vector3" />
<description>
- Given the two 3D segments ([code]p1[/code], [code]p2[/code]) and ([code]q1[/code], [code]q2[/code]), finds those two points on the two segments that are closest to each other. Returns a [PackedVector3Array] that contains this point on ([code]p1[/code], [code]p2[/code]) as well the accompanying point on ([code]q1[/code], [code]q2[/code]).
+ Given the two 3D segments ([param p1], [param p2]) and ([param q1], [param q2]), finds those two points on the two segments that are closest to each other. Returns a [PackedVector3Array] that contains this point on ([param p1], [param p2]) as well the accompanying point on ([param q1], [param q2]).
</description>
</method>
<method name="ray_intersects_triangle">
<return type="Variant" />
- <argument index="0" name="from" type="Vector3" />
- <argument index="1" name="dir" type="Vector3" />
- <argument index="2" name="a" type="Vector3" />
- <argument index="3" name="b" type="Vector3" />
- <argument index="4" name="c" type="Vector3" />
+ <param index="0" name="from" type="Vector3" />
+ <param index="1" name="dir" type="Vector3" />
+ <param index="2" name="a" type="Vector3" />
+ <param index="3" name="b" type="Vector3" />
+ <param index="4" name="c" type="Vector3" />
<description>
- Tests if the 3D ray starting at [code]from[/code] with the direction of [code]dir[/code] intersects the triangle specified by [code]a[/code], [code]b[/code] and [code]c[/code]. If yes, returns the point of intersection as [Vector3]. If no intersection takes place, returns [code]null[/code].
+ Tests if the 3D ray starting at [param from] with the direction of [param dir] intersects the triangle specified by [param a], [param b] and [param c]. If yes, returns the point of intersection as [Vector3]. If no intersection takes place, returns [code]null[/code].
</description>
</method>
<method name="segment_intersects_convex">
<return type="PackedVector3Array" />
- <argument index="0" name="from" type="Vector3" />
- <argument index="1" name="to" type="Vector3" />
- <argument index="2" name="planes" type="Array" />
+ <param index="0" name="from" type="Vector3" />
+ <param index="1" name="to" type="Vector3" />
+ <param index="2" name="planes" type="Array" />
<description>
- Given a convex hull defined though the [Plane]s in the array [code]planes[/code], tests if the segment ([code]from[/code], [code]to[/code]) intersects with that hull. If an intersection is found, returns a [PackedVector3Array] containing the point the intersection and the hull's normal. Otherwise, returns an empty array.
+ Given a convex hull defined though the [Plane]s in the array [param planes], tests if the segment ([param from], [param to]) intersects with that hull. If an intersection is found, returns a [PackedVector3Array] containing the point the intersection and the hull's normal. Otherwise, returns an empty array.
</description>
</method>
<method name="segment_intersects_cylinder">
<return type="PackedVector3Array" />
- <argument index="0" name="from" type="Vector3" />
- <argument index="1" name="to" type="Vector3" />
- <argument index="2" name="height" type="float" />
- <argument index="3" name="radius" type="float" />
+ <param index="0" name="from" type="Vector3" />
+ <param index="1" name="to" type="Vector3" />
+ <param index="2" name="height" type="float" />
+ <param index="3" name="radius" type="float" />
<description>
- Checks if the segment ([code]from[/code], [code]to[/code]) intersects the cylinder with height [code]height[/code] that is centered at the origin and has radius [code]radius[/code]. If no, returns an empty [PackedVector3Array]. If an intersection takes place, the returned array contains the point of intersection and the cylinder's normal at the point of intersection.
+ Checks if the segment ([param from], [param to]) intersects the cylinder with height [param height] that is centered at the origin and has radius [param radius]. If no, returns an empty [PackedVector3Array]. If an intersection takes place, the returned array contains the point of intersection and the cylinder's normal at the point of intersection.
</description>
</method>
<method name="segment_intersects_sphere">
<return type="PackedVector3Array" />
- <argument index="0" name="from" type="Vector3" />
- <argument index="1" name="to" type="Vector3" />
- <argument index="2" name="sphere_position" type="Vector3" />
- <argument index="3" name="sphere_radius" type="float" />
+ <param index="0" name="from" type="Vector3" />
+ <param index="1" name="to" type="Vector3" />
+ <param index="2" name="sphere_position" type="Vector3" />
+ <param index="3" name="sphere_radius" type="float" />
<description>
- Checks if the segment ([code]from[/code], [code]to[/code]) intersects the sphere that is located at [code]sphere_position[/code] and has radius [code]sphere_radius[/code]. If no, returns an empty [PackedVector3Array]. If yes, returns a [PackedVector3Array] containing the point of intersection and the sphere's normal at the point of intersection.
+ Checks if the segment ([param from], [param to]) intersects the sphere that is located at [param sphere_position] and has radius [param sphere_radius]. If no, returns an empty [PackedVector3Array]. If yes, returns a [PackedVector3Array] containing the point of intersection and the sphere's normal at the point of intersection.
</description>
</method>
<method name="segment_intersects_triangle">
<return type="Variant" />
- <argument index="0" name="from" type="Vector3" />
- <argument index="1" name="to" type="Vector3" />
- <argument index="2" name="a" type="Vector3" />
- <argument index="3" name="b" type="Vector3" />
- <argument index="4" name="c" type="Vector3" />
+ <param index="0" name="from" type="Vector3" />
+ <param index="1" name="to" type="Vector3" />
+ <param index="2" name="a" type="Vector3" />
+ <param index="3" name="b" type="Vector3" />
+ <param index="4" name="c" type="Vector3" />
<description>
- Tests if the segment ([code]from[/code], [code]to[/code]) intersects the triangle [code]a[/code], [code]b[/code], [code]c[/code]. If yes, returns the point of intersection as [Vector3]. If no intersection takes place, returns [code]null[/code].
+ Tests if the segment ([param from], [param to]) intersects the triangle [param a], [param b], [param c]. If yes, returns the point of intersection as [Vector3]. If no intersection takes place, returns [code]null[/code].
</description>
</method>
</methods>
diff --git a/doc/classes/GeometryInstance3D.xml b/doc/classes/GeometryInstance3D.xml
index c803f43fb0..79a60a9e62 100644
--- a/doc/classes/GeometryInstance3D.xml
+++ b/doc/classes/GeometryInstance3D.xml
@@ -9,23 +9,23 @@
<tutorials>
</tutorials>
<methods>
- <method name="get_shader_instance_uniform" qualifiers="const">
+ <method name="get_instance_shader_uniform" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="uniform" type="StringName" />
+ <param index="0" name="uniform" type="StringName" />
<description>
</description>
</method>
<method name="set_custom_aabb">
<return type="void" />
- <argument index="0" name="aabb" type="AABB" />
+ <param index="0" name="aabb" type="AABB" />
<description>
Overrides the bounding box of this node with a custom one. To remove it, set an [AABB] with all fields set to zero.
</description>
</method>
- <method name="set_shader_instance_uniform">
+ <method name="set_instance_shader_uniform">
<return type="void" />
- <argument index="0" name="uniform" type="StringName" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="uniform" type="StringName" />
+ <param index="1" name="value" type="Variant" />
<description>
</description>
</method>
diff --git a/doc/classes/Gradient.xml b/doc/classes/Gradient.xml
index 89c968cc9e..f081174b67 100644
--- a/doc/classes/Gradient.xml
+++ b/doc/classes/Gradient.xml
@@ -5,30 +5,31 @@
</brief_description>
<description>
Given a set of colors, this resource will interpolate them in order. This means that if you have color 1, color 2 and color 3, the gradient will interpolate from color 1 to color 2 and from color 2 to color 3. The gradient will initially have 2 colors (black and white), one (black) at gradient lower offset 0 and the other (white) at the gradient higher offset 1.
+ See also [Curve] which supports more complex easing methods, but does not support colors.
</description>
<tutorials>
</tutorials>
<methods>
<method name="add_point">
<return type="void" />
- <argument index="0" name="offset" type="float" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="offset" type="float" />
+ <param index="1" name="color" type="Color" />
<description>
Adds the specified color to the end of the gradient, with the specified offset.
</description>
</method>
<method name="get_color">
<return type="Color" />
- <argument index="0" name="point" type="int" />
+ <param index="0" name="point" type="int" />
<description>
- Returns the color of the gradient color at index [code]point[/code].
+ Returns the color of the gradient color at index [param point].
</description>
</method>
<method name="get_offset">
<return type="float" />
- <argument index="0" name="point" type="int" />
+ <param index="0" name="point" type="int" />
<description>
- Returns the offset of the gradient color at index [code]point[/code].
+ Returns the offset of the gradient color at index [param point].
</description>
</method>
<method name="get_point_count" qualifiers="const">
@@ -39,16 +40,16 @@
</method>
<method name="interpolate">
<return type="Color" />
- <argument index="0" name="offset" type="float" />
+ <param index="0" name="offset" type="float" />
<description>
- Returns the interpolated color specified by [code]offset[/code].
+ Returns the interpolated color specified by [param offset].
</description>
</method>
<method name="remove_point">
<return type="void" />
- <argument index="0" name="point" type="int" />
+ <param index="0" name="point" type="int" />
<description>
- Removes the color at the index [code]point[/code].
+ Removes the color at the index [param point].
</description>
</method>
<method name="reverse">
@@ -59,18 +60,18 @@
</method>
<method name="set_color">
<return type="void" />
- <argument index="0" name="point" type="int" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="point" type="int" />
+ <param index="1" name="color" type="Color" />
<description>
- Sets the color of the gradient color at index [code]point[/code].
+ Sets the color of the gradient color at index [param point].
</description>
</method>
<method name="set_offset">
<return type="void" />
- <argument index="0" name="point" type="int" />
- <argument index="1" name="offset" type="float" />
+ <param index="0" name="point" type="int" />
+ <param index="1" name="offset" type="float" />
<description>
- Sets the offset for the gradient color at index [code]point[/code].
+ Sets the offset for the gradient color at index [param point].
</description>
</method>
</methods>
diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml
index 33145dccd0..dc093acdcd 100644
--- a/doc/classes/GraphEdit.xml
+++ b/doc/classes/GraphEdit.xml
@@ -12,20 +12,20 @@
<methods>
<method name="_get_connection_line" qualifiers="virtual const">
<return type="PackedVector2Array" />
- <argument index="0" name="from" type="Vector2" />
- <argument index="1" name="to" type="Vector2" />
+ <param index="0" name="from" type="Vector2" />
+ <param index="1" name="to" type="Vector2" />
<description>
Virtual method which can be overridden to customize how connections are drawn.
</description>
</method>
<method name="_is_in_input_hotzone" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="graph_node" type="Object" />
- <argument index="1" name="slot_index" type="int" />
- <argument index="2" name="mouse_position" type="Vector2" />
+ <param index="0" name="graph_node" type="Object" />
+ <param index="1" name="slot_index" type="int" />
+ <param index="2" name="mouse_position" type="Vector2" />
<description>
- Returns whether the [code]mouse_position[/code] is in the input hot zone.
- By default, a hot zone is a [Rect2] positioned such that its center is at [code]graph_node[/code].[method GraphNode.get_connection_input_position]([code]slot_index[/code]) (For output's case, call [method GraphNode.get_connection_output_position] instead). The hot zone's width is twice the Theme Property [code]port_grab_distance_horizontal[/code], and its height is twice the [code]port_grab_distance_vertical[/code].
+ Returns whether the [param mouse_position] is in the input hot zone.
+ By default, a hot zone is a [Rect2] positioned such that its center is at [param graph_node].[method GraphNode.get_connection_input_position]([param slot_index]) (For output's case, call [method GraphNode.get_connection_output_position] instead). The hot zone's width is twice the Theme Property [code]port_grab_distance_horizontal[/code], and its height is twice the [code]port_grab_distance_vertical[/code].
Below is a sample code to help get started:
[codeblock]
func _is_in_input_hotzone(graph_node, slot_index, mouse_position):
@@ -39,11 +39,11 @@
</method>
<method name="_is_in_output_hotzone" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="graph_node" type="Object" />
- <argument index="1" name="slot_index" type="int" />
- <argument index="2" name="mouse_position" type="Vector2" />
+ <param index="0" name="graph_node" type="Object" />
+ <param index="1" name="slot_index" type="int" />
+ <param index="2" name="mouse_position" type="Vector2" />
<description>
- Returns whether the [code]mouse_position[/code] is in the output hot zone. For more information on hot zones, see [method _is_in_input_hotzone].
+ Returns whether the [param mouse_position] is in the output hot zone. For more information on hot zones, see [method _is_in_input_hotzone].
Below is a sample code to help get started:
[codeblock]
func _is_in_output_hotzone(graph_node, slot_index, mouse_position):
@@ -57,10 +57,10 @@
</method>
<method name="_is_node_hover_valid" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="from" type="StringName" />
- <argument index="1" name="from_slot" type="int" />
- <argument index="2" name="to" type="StringName" />
- <argument index="3" name="to_slot" type="int" />
+ <param index="0" name="from" type="StringName" />
+ <param index="1" name="from_slot" type="int" />
+ <param index="2" name="to" type="StringName" />
+ <param index="3" name="to_slot" type="int" />
<description>
This virtual method can be used to insert additional error detection while the user is dragging a connection over a valid port.
Return [code]true[/code] if the connection is indeed valid or return [code]false[/code] if the connection is impossible. If the connection is impossible, no snapping to the port and thus no connection request to that port will happen.
@@ -80,22 +80,22 @@
</method>
<method name="add_valid_connection_type">
<return type="void" />
- <argument index="0" name="from_type" type="int" />
- <argument index="1" name="to_type" type="int" />
+ <param index="0" name="from_type" type="int" />
+ <param index="1" name="to_type" type="int" />
<description>
Makes possible the connection between two different slot types. The type is defined with the [method GraphNode.set_slot] method.
</description>
</method>
<method name="add_valid_left_disconnect_type">
<return type="void" />
- <argument index="0" name="type" type="int" />
+ <param index="0" name="type" type="int" />
<description>
Makes possible to disconnect nodes when dragging from the slot at the left if it has the specified type.
</description>
</method>
<method name="add_valid_right_disconnect_type">
<return type="void" />
- <argument index="0" name="type" type="int" />
+ <param index="0" name="type" type="int" />
<description>
Makes possible to disconnect nodes when dragging from the slot at the right if it has the specified type.
</description>
@@ -114,22 +114,22 @@
</method>
<method name="connect_node">
<return type="int" enum="Error" />
- <argument index="0" name="from" type="StringName" />
- <argument index="1" name="from_port" type="int" />
- <argument index="2" name="to" type="StringName" />
- <argument index="3" name="to_port" type="int" />
+ <param index="0" name="from" type="StringName" />
+ <param index="1" name="from_port" type="int" />
+ <param index="2" name="to" type="StringName" />
+ <param index="3" name="to_port" type="int" />
<description>
- Create a connection between the [code]from_port[/code] slot of the [code]from[/code] GraphNode and the [code]to_port[/code] slot of the [code]to[/code] GraphNode. If the connection already exists, no connection is created.
+ Create a connection between the [param from_port] slot of the [param from] GraphNode and the [param to_port] slot of the [param to] GraphNode. If the connection already exists, no connection is created.
</description>
</method>
<method name="disconnect_node">
<return type="void" />
- <argument index="0" name="from" type="StringName" />
- <argument index="1" name="from_port" type="int" />
- <argument index="2" name="to" type="StringName" />
- <argument index="3" name="to_port" type="int" />
+ <param index="0" name="from" type="StringName" />
+ <param index="1" name="from_port" type="int" />
+ <param index="2" name="to" type="StringName" />
+ <param index="3" name="to_port" type="int" />
<description>
- Removes the connection between the [code]from_port[/code] slot of the [code]from[/code] GraphNode and the [code]to_port[/code] slot of the [code]to[/code] GraphNode. If the connection does not exist, no connection is removed.
+ Removes the connection between the [param from_port] slot of the [param from] GraphNode and the [param to_port] slot of the [param to] GraphNode. If the connection does not exist, no connection is removed.
</description>
</method>
<method name="force_connection_drag_end">
@@ -142,14 +142,14 @@
</method>
<method name="get_connection_line">
<return type="PackedVector2Array" />
- <argument index="0" name="from" type="Vector2" />
- <argument index="1" name="to" type="Vector2" />
+ <param index="0" name="from" type="Vector2" />
+ <param index="1" name="to" type="Vector2" />
<description>
- Returns the points which would make up a connection between [code]from[/code] and [code]to[/code].
+ Returns the points which would make up a connection between [param from] and [param to].
</description>
</method>
<method name="get_connection_list" qualifiers="const">
- <return type="Array" />
+ <return type="Dictionary[]" />
<description>
Returns an Array containing the list of connections. A connection consists in a structure of the form [code]{ from_port: 0, from: "GraphNode name 0", to_port: 1, to: "GraphNode name 1" }[/code].
</description>
@@ -163,64 +163,67 @@
</method>
<method name="is_node_connected">
<return type="bool" />
- <argument index="0" name="from" type="StringName" />
- <argument index="1" name="from_port" type="int" />
- <argument index="2" name="to" type="StringName" />
- <argument index="3" name="to_port" type="int" />
+ <param index="0" name="from" type="StringName" />
+ <param index="1" name="from_port" type="int" />
+ <param index="2" name="to" type="StringName" />
+ <param index="3" name="to_port" type="int" />
<description>
- Returns [code]true[/code] if the [code]from_port[/code] slot of the [code]from[/code] GraphNode is connected to the [code]to_port[/code] slot of the [code]to[/code] GraphNode.
+ Returns [code]true[/code] if the [param from_port] slot of the [param from] GraphNode is connected to the [param to_port] slot of the [param to] GraphNode.
</description>
</method>
<method name="is_valid_connection_type" qualifiers="const">
<return type="bool" />
- <argument index="0" name="from_type" type="int" />
- <argument index="1" name="to_type" type="int" />
+ <param index="0" name="from_type" type="int" />
+ <param index="1" name="to_type" type="int" />
<description>
Returns whether it's possible to connect slots of the specified types.
</description>
</method>
<method name="remove_valid_connection_type">
<return type="void" />
- <argument index="0" name="from_type" type="int" />
- <argument index="1" name="to_type" type="int" />
+ <param index="0" name="from_type" type="int" />
+ <param index="1" name="to_type" type="int" />
<description>
Makes it not possible to connect between two different slot types. The type is defined with the [method GraphNode.set_slot] method.
</description>
</method>
<method name="remove_valid_left_disconnect_type">
<return type="void" />
- <argument index="0" name="type" type="int" />
+ <param index="0" name="type" type="int" />
<description>
Removes the possibility to disconnect nodes when dragging from the slot at the left if it has the specified type.
</description>
</method>
<method name="remove_valid_right_disconnect_type">
<return type="void" />
- <argument index="0" name="type" type="int" />
+ <param index="0" name="type" type="int" />
<description>
Removes the possibility to disconnect nodes when dragging from the slot at the right if it has the specified type.
</description>
</method>
<method name="set_connection_activity">
<return type="void" />
- <argument index="0" name="from" type="StringName" />
- <argument index="1" name="from_port" type="int" />
- <argument index="2" name="to" type="StringName" />
- <argument index="3" name="to_port" type="int" />
- <argument index="4" name="amount" type="float" />
+ <param index="0" name="from" type="StringName" />
+ <param index="1" name="from_port" type="int" />
+ <param index="2" name="to" type="StringName" />
+ <param index="3" name="to_port" type="int" />
+ <param index="4" name="amount" type="float" />
<description>
- Sets the coloration of the connection between [code]from[/code]'s [code]from_port[/code] and [code]to[/code]'s [code]to_port[/code] with the color provided in the [theme_item activity] theme property.
+ Sets the coloration of the connection between [param from]'s [param from_port] and [param to]'s [param to_port] with the color provided in the [theme_item activity] theme property.
</description>
</method>
<method name="set_selected">
<return type="void" />
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
- Sets the specified [code]node[/code] as the one selected.
+ Sets the specified [param node] as the one selected.
</description>
</method>
</methods>
<members>
+ <member name="arrange_nodes_button_hidden" type="bool" setter="set_arrange_nodes_button_hidden" getter="is_arrange_nodes_button_hidden" default="false">
+ If [code]true[/code], the Arrange Nodes button is hidden.
+ </member>
<member name="clip_contents" type="bool" setter="set_clip_contents" getter="is_clipping_contents" overrides="Control" default="true" />
<member name="connection_lines_antialiased" type="bool" setter="set_connection_lines_antialiased" getter="is_connection_lines_antialiased" default="true">
If [code]true[/code], the lines between nodes will use antialiasing.
@@ -284,34 +287,34 @@
</description>
</signal>
<signal name="connection_drag_started">
- <argument index="0" name="from" type="String" />
- <argument index="1" name="slot" type="String" />
- <argument index="2" name="is_output" type="bool" />
+ <param index="0" name="from" type="String" />
+ <param index="1" name="slot" type="int" />
+ <param index="2" name="is_output" type="bool" />
<description>
Emitted at the beginning of a connection drag.
</description>
</signal>
<signal name="connection_from_empty">
- <argument index="0" name="to" type="StringName" />
- <argument index="1" name="to_slot" type="int" />
- <argument index="2" name="release_position" type="Vector2" />
+ <param index="0" name="to" type="StringName" />
+ <param index="1" name="to_slot" type="int" />
+ <param index="2" name="release_position" type="Vector2" />
<description>
Emitted when user dragging connection from input port into empty space of the graph.
</description>
</signal>
<signal name="connection_request">
- <argument index="0" name="from" type="StringName" />
- <argument index="1" name="from_slot" type="int" />
- <argument index="2" name="to" type="StringName" />
- <argument index="3" name="to_slot" type="int" />
+ <param index="0" name="from" type="StringName" />
+ <param index="1" name="from_slot" type="int" />
+ <param index="2" name="to" type="StringName" />
+ <param index="3" name="to_slot" type="int" />
<description>
- Emitted to the GraphEdit when the connection between the [code]from_slot[/code] slot of the [code]from[/code] GraphNode and the [code]to_slot[/code] slot of the [code]to[/code] GraphNode is attempted to be created.
+ Emitted to the GraphEdit when the connection between the [param from_slot] slot of the [param from] GraphNode and the [param to_slot] slot of the [param to] GraphNode is attempted to be created.
</description>
</signal>
<signal name="connection_to_empty">
- <argument index="0" name="from" type="StringName" />
- <argument index="1" name="from_slot" type="int" />
- <argument index="2" name="release_position" type="Vector2" />
+ <param index="0" name="from" type="StringName" />
+ <param index="1" name="from_slot" type="int" />
+ <param index="2" name="release_position" type="Vector2" />
<description>
Emitted when user dragging connection from output port into empty space of the graph.
</description>
@@ -322,18 +325,18 @@
</description>
</signal>
<signal name="delete_nodes_request">
- <argument index="0" name="nodes" type="StringName[]" />
+ <param index="0" name="nodes" type="StringName[]" />
<description>
Emitted when a GraphNode is attempted to be removed from the GraphEdit. Provides a list of node names to be removed (all selected nodes, excluding nodes without closing button).
</description>
</signal>
<signal name="disconnection_request">
- <argument index="0" name="from" type="StringName" />
- <argument index="1" name="from_slot" type="int" />
- <argument index="2" name="to" type="StringName" />
- <argument index="3" name="to_slot" type="int" />
+ <param index="0" name="from" type="StringName" />
+ <param index="1" name="from_slot" type="int" />
+ <param index="2" name="to" type="StringName" />
+ <param index="3" name="to_slot" type="int" />
<description>
- Emitted to the GraphEdit when the connection between [code]from_slot[/code] slot of [code]from[/code] GraphNode and [code]to_slot[/code] slot of [code]to[/code] GraphNode is attempted to be removed.
+ Emitted to the GraphEdit when the connection between [param from_slot] slot of [param from] GraphNode and [param to_slot] slot of [param to] GraphNode is attempted to be removed.
</description>
</signal>
<signal name="duplicate_nodes_request">
@@ -347,12 +350,12 @@
</description>
</signal>
<signal name="node_deselected">
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
</description>
</signal>
<signal name="node_selected">
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
Emitted when a GraphNode is selected.
</description>
@@ -363,13 +366,13 @@
</description>
</signal>
<signal name="popup_request">
- <argument index="0" name="position" type="Vector2" />
+ <param index="0" name="position" type="Vector2" />
<description>
- Emitted when a popup is requested. Happens on right-clicking in the GraphEdit. [code]position[/code] is the position of the mouse pointer when the signal is sent.
+ Emitted when a popup is requested. Happens on right-clicking in the GraphEdit. [param position] is the position of the mouse pointer when the signal is sent.
</description>
</signal>
<signal name="scroll_offset_changed">
- <argument index="0" name="offset" type="Vector2" />
+ <param index="0" name="offset" type="Vector2" />
<description>
Emitted when the scroll offset is changed by the user. It will not be emitted when changed in code.
</description>
diff --git a/doc/classes/GraphNode.xml b/doc/classes/GraphNode.xml
index 36dbae1d74..ebd4525b19 100644
--- a/doc/classes/GraphNode.xml
+++ b/doc/classes/GraphNode.xml
@@ -19,16 +19,16 @@
</method>
<method name="clear_slot">
<return type="void" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Disables input and output slot whose index is [code]idx[/code].
+ Disables input and output slot whose index is [param idx].
</description>
</method>
<method name="get_connection_input_color">
<return type="Color" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the [Color] of the input connection [code]idx[/code].
+ Returns the [Color] of the input connection [param idx].
</description>
</method>
<method name="get_connection_input_count">
@@ -39,30 +39,30 @@
</method>
<method name="get_connection_input_height">
<return type="int" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the height of the input connection [code]idx[/code].
+ Returns the height of the input connection [param idx].
</description>
</method>
<method name="get_connection_input_position">
<return type="Vector2" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the position of the input connection [code]idx[/code].
+ Returns the position of the input connection [param idx].
</description>
</method>
<method name="get_connection_input_type">
<return type="int" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the type of the input connection [code]idx[/code].
+ Returns the type of the input connection [param idx].
</description>
</method>
<method name="get_connection_output_color">
<return type="Color" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the [Color] of the output connection [code]idx[/code].
+ Returns the [Color] of the output connection [param idx].
</description>
</method>
<method name="get_connection_output_count">
@@ -73,150 +73,150 @@
</method>
<method name="get_connection_output_height">
<return type="int" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the height of the output connection [code]idx[/code].
+ Returns the height of the output connection [param idx].
</description>
</method>
<method name="get_connection_output_position">
<return type="Vector2" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the position of the output connection [code]idx[/code].
+ Returns the position of the output connection [param idx].
</description>
</method>
<method name="get_connection_output_type">
<return type="int" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the type of the output connection [code]idx[/code].
+ Returns the type of the output connection [param idx].
</description>
</method>
<method name="get_slot_color_left" qualifiers="const">
<return type="Color" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the left (input) [Color] of the slot [code]idx[/code].
+ Returns the left (input) [Color] of the slot [param idx].
</description>
</method>
<method name="get_slot_color_right" qualifiers="const">
<return type="Color" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the right (output) [Color] of the slot [code]idx[/code].
+ Returns the right (output) [Color] of the slot [param idx].
</description>
</method>
<method name="get_slot_type_left" qualifiers="const">
<return type="int" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the left (input) type of the slot [code]idx[/code].
+ Returns the left (input) type of the slot [param idx].
</description>
</method>
<method name="get_slot_type_right" qualifiers="const">
<return type="int" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the right (output) type of the slot [code]idx[/code].
+ Returns the right (output) type of the slot [param idx].
</description>
</method>
<method name="is_slot_draw_stylebox" qualifiers="const">
<return type="bool" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns true if the background [StyleBox] of the slot [code]idx[/code] is drawn.
+ Returns true if the background [StyleBox] of the slot [param idx] is drawn.
</description>
</method>
<method name="is_slot_enabled_left" qualifiers="const">
<return type="bool" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns [code]true[/code] if left (input) side of the slot [code]idx[/code] is enabled.
+ Returns [code]true[/code] if left (input) side of the slot [param idx] is enabled.
</description>
</method>
<method name="is_slot_enabled_right" qualifiers="const">
<return type="bool" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns [code]true[/code] if right (output) side of the slot [code]idx[/code] is enabled.
+ Returns [code]true[/code] if right (output) side of the slot [param idx] is enabled.
</description>
</method>
<method name="set_slot">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="enable_left" type="bool" />
- <argument index="2" name="type_left" type="int" />
- <argument index="3" name="color_left" type="Color" />
- <argument index="4" name="enable_right" type="bool" />
- <argument index="5" name="type_right" type="int" />
- <argument index="6" name="color_right" type="Color" />
- <argument index="7" name="custom_left" type="Texture2D" default="null" />
- <argument index="8" name="custom_right" type="Texture2D" default="null" />
- <argument index="9" name="enable" type="bool" default="true" />
- <description>
- Sets properties of the slot with ID [code]idx[/code].
- If [code]enable_left[/code]/[code]right[/code], a port will appear and the slot will be able to be connected from this side.
- [code]type_left[/code]/[code]right[/code] is an arbitrary type of the port. Only ports with the same type values can be connected.
- [code]color_left[/code]/[code]right[/code] is the tint of the port's icon on this side.
- [code]custom_left[/code]/[code]right[/code] is a custom texture for this side's port.
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="enable_left" type="bool" />
+ <param index="2" name="type_left" type="int" />
+ <param index="3" name="color_left" type="Color" />
+ <param index="4" name="enable_right" type="bool" />
+ <param index="5" name="type_right" type="int" />
+ <param index="6" name="color_right" type="Color" />
+ <param index="7" name="custom_left" type="Texture2D" default="null" />
+ <param index="8" name="custom_right" type="Texture2D" default="null" />
+ <param index="9" name="enable" type="bool" default="true" />
+ <description>
+ Sets properties of the slot with ID [param idx].
+ If [param enable_left]/[param enable_right], a port will appear and the slot will be able to be connected from this side.
+ [param type_left]/[param type_right] is an arbitrary type of the port. Only ports with the same type values can be connected and negative values will disallow all connections to be made via user inputs.
+ [param color_left]/[param color_right] is the tint of the port's icon on this side.
+ [param custom_left]/[param custom_right] is a custom texture for this side's port.
[b]Note:[/b] This method only sets properties of the slot. To create the slot, add a [Control]-derived child to the GraphNode.
Individual properties can be set using one of the [code]set_slot_*[/code] methods. You must enable at least one side of the slot to do so.
</description>
</method>
<method name="set_slot_color_left">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="color_left" type="Color" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="color_left" type="Color" />
<description>
- Sets the [Color] of the left (input) side of the slot [code]idx[/code] to [code]color_left[/code].
+ Sets the [Color] of the left (input) side of the slot [param idx] to [param color_left].
</description>
</method>
<method name="set_slot_color_right">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="color_right" type="Color" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="color_right" type="Color" />
<description>
- Sets the [Color] of the right (output) side of the slot [code]idx[/code] to [code]color_right[/code].
+ Sets the [Color] of the right (output) side of the slot [param idx] to [param color_right].
</description>
</method>
<method name="set_slot_draw_stylebox">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="draw_stylebox" type="bool" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="draw_stylebox" type="bool" />
<description>
- Toggles the background [StyleBox] of the slot [code]idx[/code].
+ Toggles the background [StyleBox] of the slot [param idx].
</description>
</method>
<method name="set_slot_enabled_left">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="enable_left" type="bool" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="enable_left" type="bool" />
<description>
- Toggles the left (input) side of the slot [code]idx[/code]. If [code]enable_left[/code] is [code]true[/code], a port will appear on the left side and the slot will be able to be connected from this side.
+ Toggles the left (input) side of the slot [param idx]. If [param enable_left] is [code]true[/code], a port will appear on the left side and the slot will be able to be connected from this side.
</description>
</method>
<method name="set_slot_enabled_right">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="enable_right" type="bool" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="enable_right" type="bool" />
<description>
- Toggles the right (output) side of the slot [code]idx[/code]. If [code]enable_right[/code] is [code]true[/code], a port will appear on the right side and the slot will be able to be connected from this side.
+ Toggles the right (output) side of the slot [param idx]. If [param enable_right] is [code]true[/code], a port will appear on the right side and the slot will be able to be connected from this side.
</description>
</method>
<method name="set_slot_type_left">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="type_left" type="int" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="type_left" type="int" />
<description>
- Sets the left (input) type of the slot [code]idx[/code] to [code]type_left[/code].
+ Sets the left (input) type of the slot [param idx] to [param type_left]. If the value is negative, all connections will be disallowed to be created via user inputs.
</description>
</method>
<method name="set_slot_type_right">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="type_right" type="int" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="type_right" type="int" />
<description>
- Sets the right (output) type of the slot [code]idx[/code] to [code]type_right[/code].
+ Sets the right (output) type of the slot [param idx] to [param type_right]. If the value is negative, all connections will be disallowed to be created via user inputs.
</description>
</method>
</methods>
@@ -224,6 +224,9 @@
<member name="comment" type="bool" setter="set_comment" getter="is_comment" default="false">
If [code]true[/code], the GraphNode is a comment node.
</member>
+ <member name="draggable" type="bool" setter="set_draggable" getter="is_draggable" default="true">
+ If [code]true[/code], the user can drag the GraphNode.
+ </member>
<member name="language" type="String" setter="set_language" getter="get_language" default="&quot;&quot;">
Language code used for line-breaking and text shaping algorithms, if left empty current locale is used instead.
</member>
@@ -239,6 +242,9 @@
If [code]true[/code], the user can resize the GraphNode.
[b]Note:[/b] Dragging the handle will only emit the [signal resize_request] signal, the GraphNode needs to be resized manually.
</member>
+ <member name="selectable" type="bool" setter="set_selectable" getter="is_selectable" default="true">
+ If [code]true[/code], the user can select the GraphNode.
+ </member>
<member name="selected" type="bool" setter="set_selected" getter="is_selected" default="false">
If [code]true[/code], the GraphNode is selected.
</member>
@@ -260,8 +266,8 @@
</description>
</signal>
<signal name="dragged">
- <argument index="0" name="from" type="Vector2" />
- <argument index="1" name="to" type="Vector2" />
+ <param index="0" name="from" type="Vector2" />
+ <param index="1" name="to" type="Vector2" />
<description>
Emitted when the GraphNode is dragged.
</description>
@@ -277,13 +283,13 @@
</description>
</signal>
<signal name="resize_request">
- <argument index="0" name="new_minsize" type="Vector2" />
+ <param index="0" name="new_minsize" type="Vector2" />
<description>
Emitted when the GraphNode is requested to be resized. Happens on dragging the resizer handle (see [member resizable]).
</description>
</signal>
<signal name="slot_updated">
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Emitted when any GraphNode's slot is updated.
</description>
@@ -321,6 +327,9 @@
<theme_item name="separation" data_type="constant" type="int" default="2">
The vertical distance between ports.
</theme_item>
+ <theme_item name="title_h_offset" data_type="constant" type="int" default="0">
+ Horizontal offset of the title text.
+ </theme_item>
<theme_item name="title_offset" data_type="constant" type="int" default="26">
Vertical offset of the title text.
</theme_item>
diff --git a/doc/classes/HMACContext.xml b/doc/classes/HMACContext.xml
index f2b946cab7..52d4fce28f 100644
--- a/doc/classes/HMACContext.xml
+++ b/doc/classes/HMACContext.xml
@@ -62,17 +62,17 @@
</method>
<method name="start">
<return type="int" enum="Error" />
- <argument index="0" name="hash_type" type="int" enum="HashingContext.HashType" />
- <argument index="1" name="key" type="PackedByteArray" />
+ <param index="0" name="hash_type" type="int" enum="HashingContext.HashType" />
+ <param index="1" name="key" type="PackedByteArray" />
<description>
Initializes the HMACContext. This method cannot be called again on the same HMACContext until [method finish] has been called.
</description>
</method>
<method name="update">
<return type="int" enum="Error" />
- <argument index="0" name="data" type="PackedByteArray" />
+ <param index="0" name="data" type="PackedByteArray" />
<description>
- Updates the message to be HMACed. This can be called multiple times before [method finish] is called to append [code]data[/code] to the message, but cannot be called until [method start] has been called.
+ Updates the message to be HMACed. This can be called multiple times before [method finish] is called to append [param data] to the message, but cannot be called until [method start] has been called.
</description>
</method>
</methods>
diff --git a/doc/classes/HTTPClient.xml b/doc/classes/HTTPClient.xml
index 5a9d12d01b..332ce9d8f4 100644
--- a/doc/classes/HTTPClient.xml
+++ b/doc/classes/HTTPClient.xml
@@ -4,13 +4,14 @@
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. [b]See the [HTTPRequest] node for a higher-level alternative.[/b]
+ 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 the [HTTPRequest] node for a higher-level alternative.
[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 exporting to Android, make sure to enable the [code]INTERNET[/code] permission in the Android export preset before exporting the project or using one-click deploy. Otherwise, network communication of any kind will be blocked by Android.
[b]Note:[/b] It's recommended to use transport encryption (SSL/TLS) and to avoid sending sensitive information (such as login credentials) in HTTP GET URL parameters. Consider using HTTP POST requests or HTTP headers for such information instead.
- [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.
+ [b]Note:[/b] When performing HTTP requests from a project exported to Web, 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.
[b]Note:[/b] SSL/TLS support is currently limited to TLS 1.0, TLS 1.1, and TLS 1.2. Attempting to connect to a TLS 1.3-only server will return an error.
[b]Warning:[/b] SSL/TLS certificate revocation and certificate pinning are currently not supported. Revoked certificates are accepted as long as they are otherwise valid. If this is a concern, you may want to use automatically managed certificates with a short validity period.
</description>
@@ -27,15 +28,15 @@
</method>
<method name="connect_to_host">
<return type="int" enum="Error" />
- <argument index="0" name="host" type="String" />
- <argument index="1" name="port" type="int" default="-1" />
- <argument index="2" name="use_ssl" type="bool" default="false" />
- <argument index="3" name="verify_host" type="bool" default="true" />
+ <param index="0" name="host" type="String" />
+ <param index="1" name="port" type="int" default="-1" />
+ <param index="2" name="use_ssl" type="bool" default="false" />
+ <param index="3" name="verify_host" type="bool" default="true" />
<description>
Connects to a host. This needs to be done before any requests are sent.
The host should not have http:// prepended but will strip the protocol identifier if provided.
- If no [code]port[/code] is specified (or [code]-1[/code] is used), it is automatically set to 80 for HTTP and 443 for HTTPS (if [code]use_ssl[/code] is enabled).
- [code]verify_host[/code] will check the SSL identity of the host if set to [code]true[/code].
+ If no [param port] is specified (or [code]-1[/code] is used), it is automatically set to 80 for HTTP and 443 for HTTPS (if [param use_ssl] is enabled).
+ [param verify_host] will check the SSL identity of the host if set to [code]true[/code].
</description>
</method>
<method name="get_response_body_length" qualifiers="const">
@@ -96,7 +97,7 @@
</method>
<method name="query_string_from_dict">
<return type="String" />
- <argument index="0" name="fields" type="Dictionary" />
+ <param index="0" name="fields" type="Dictionary" />
<description>
Generates a GET/POST application/x-www-form-urlencoded style query string from a provided dictionary, e.g.:
[codeblocks]
@@ -134,10 +135,10 @@
</method>
<method name="request">
<return type="int" enum="Error" />
- <argument index="0" name="method" type="int" enum="HTTPClient.Method" />
- <argument index="1" name="url" type="String" />
- <argument index="2" name="headers" type="PackedStringArray" />
- <argument index="3" name="body" type="String" default="&quot;&quot;" />
+ <param index="0" name="method" type="int" enum="HTTPClient.Method" />
+ <param index="1" name="url" type="String" />
+ <param index="2" name="headers" type="PackedStringArray" />
+ <param index="3" name="body" type="String" default="&quot;&quot;" />
<description>
Sends a request to the connected host.
The URL parameter is usually just the part after the host, so for [code]https://somehost.com/index.php[/code], it is [code]/index.php[/code]. When sending requests to an HTTP proxy server, it should be an absolute URL. For [constant HTTPClient.METHOD_OPTIONS] requests, [code]*[/code] is also allowed. For [constant HTTPClient.METHOD_CONNECT] requests, it should be the authority component ([code]host:port[/code]).
@@ -157,15 +158,15 @@
var result = new HTTPClient().Request(HTTPClient.Method.Post, "index.php", headers, queryString);
[/csharp]
[/codeblocks]
- [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.uri_encode] for an example.
+ [b]Note:[/b] The [param body] parameter is ignored if [param method] 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.uri_encode] for an example.
</description>
</method>
<method name="request_raw">
<return type="int" enum="Error" />
- <argument index="0" name="method" type="int" enum="HTTPClient.Method" />
- <argument index="1" name="url" type="String" />
- <argument index="2" name="headers" type="PackedStringArray" />
- <argument index="3" name="body" type="PackedByteArray" />
+ <param index="0" name="method" type="int" enum="HTTPClient.Method" />
+ <param index="1" name="url" type="String" />
+ <param index="2" name="headers" type="PackedStringArray" />
+ <param index="3" name="body" type="PackedByteArray" />
<description>
Sends a raw request to the connected host.
The URL parameter is usually just the part after the host, so for [code]https://somehost.com/index.php[/code], it is [code]/index.php[/code]. When sending requests to an HTTP proxy server, it should be an absolute URL. For [constant HTTPClient.METHOD_OPTIONS] requests, [code]*[/code] is also allowed. For [constant HTTPClient.METHOD_CONNECT] requests, it should be the authority component ([code]host:port[/code]).
@@ -175,20 +176,20 @@
</method>
<method name="set_http_proxy">
<return type="void" />
- <argument index="0" name="host" type="String" />
- <argument index="1" name="port" type="int" />
+ <param index="0" name="host" type="String" />
+ <param index="1" name="port" type="int" />
<description>
Sets the proxy server for HTTP requests.
- The proxy server is unset if [code]host[/code] is empty or [code]port[/code] is -1.
+ The proxy server is unset if [param host] is empty or [param port] is -1.
</description>
</method>
<method name="set_https_proxy">
<return type="void" />
- <argument index="0" name="host" type="String" />
- <argument index="1" name="port" type="int" />
+ <param index="0" name="host" type="String" />
+ <param index="1" name="port" type="int" />
<description>
Sets the proxy server for HTTPS requests.
- The proxy server is unset if [code]host[/code] is empty or [code]port[/code] is -1.
+ The proxy server is unset if [param host] is empty or [param port] is -1.
</description>
</method>
</methods>
diff --git a/doc/classes/HTTPRequest.xml b/doc/classes/HTTPRequest.xml
index 3d2e9449e2..4b098bf585 100644
--- a/doc/classes/HTTPRequest.xml
+++ b/doc/classes/HTTPRequest.xml
@@ -176,7 +176,7 @@
<method name="get_downloaded_bytes" qualifiers="const">
<return type="int" />
<description>
- Returns the amount of bytes this HTTPRequest downloaded.
+ Returns the number of bytes this HTTPRequest downloaded.
</description>
</method>
<method name="get_http_client_status" qualifiers="const">
@@ -187,25 +187,25 @@
</method>
<method name="request">
<return type="int" enum="Error" />
- <argument index="0" name="url" type="String" />
- <argument index="1" name="custom_headers" type="PackedStringArray" default="PackedStringArray()" />
- <argument index="2" name="ssl_validate_domain" type="bool" default="true" />
- <argument index="3" name="method" type="int" enum="HTTPClient.Method" default="0" />
- <argument index="4" name="request_data" type="String" default="&quot;&quot;" />
+ <param index="0" name="url" type="String" />
+ <param index="1" name="custom_headers" type="PackedStringArray" default="PackedStringArray()" />
+ <param index="2" name="ssl_validate_domain" type="bool" default="true" />
+ <param index="3" name="method" type="int" enum="HTTPClient.Method" default="0" />
+ <param index="4" name="request_data" type="String" default="&quot;&quot;" />
<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] When [code]method[/code] is [constant HTTPClient.METHOD_GET], the payload sent via [code]request_data[/code] might be ignored by the server or even cause the server to reject the request (check [url=https://datatracker.ietf.org/doc/html/rfc7231#section-4.3.1]RFC 7231 section 4.3.1[/url] for more details). As a workaround, you can send data as a query string in the URL (see [method String.uri_encode] for an example).
+ [b]Note:[/b] When [param method] is [constant HTTPClient.METHOD_GET], the payload sent via [param request_data] might be ignored by the server or even cause the server to reject the request (check [url=https://datatracker.ietf.org/doc/html/rfc7231#section-4.3.1]RFC 7231 section 4.3.1[/url] for more details). As a workaround, you can send data as a query string in the URL (see [method String.uri_encode] for an example).
[b]Note:[/b] It's recommended to use transport encryption (SSL/TLS) and to avoid sending sensitive information (such as login credentials) in HTTP GET URL parameters. Consider using HTTP POST requests or HTTP headers for such information instead.
</description>
</method>
<method name="request_raw">
<return type="int" enum="Error" />
- <argument index="0" name="url" type="String" />
- <argument index="1" name="custom_headers" type="PackedStringArray" default="PackedStringArray()" />
- <argument index="2" name="ssl_validate_domain" type="bool" default="true" />
- <argument index="3" name="method" type="int" enum="HTTPClient.Method" default="0" />
- <argument index="4" name="request_data_raw" type="PackedByteArray" default="PackedByteArray()" />
+ <param index="0" name="url" type="String" />
+ <param index="1" name="custom_headers" type="PackedStringArray" default="PackedStringArray()" />
+ <param index="2" name="ssl_validate_domain" type="bool" default="true" />
+ <param index="3" name="method" type="int" enum="HTTPClient.Method" default="0" />
+ <param index="4" name="request_data_raw" type="PackedByteArray" default="PackedByteArray()" />
<description>
Creates request on the underlying [HTTPClient] using a raw array of bytes for the request body. 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.
@@ -213,20 +213,20 @@
</method>
<method name="set_http_proxy">
<return type="void" />
- <argument index="0" name="host" type="String" />
- <argument index="1" name="port" type="int" />
+ <param index="0" name="host" type="String" />
+ <param index="1" name="port" type="int" />
<description>
Sets the proxy server for HTTP requests.
- The proxy server is unset if [code]host[/code] is empty or [code]port[/code] is -1.
+ The proxy server is unset if [param host] is empty or [param port] is -1.
</description>
</method>
<method name="set_https_proxy">
<return type="void" />
- <argument index="0" name="host" type="String" />
- <argument index="1" name="port" type="int" />
+ <param index="0" name="host" type="String" />
+ <param index="1" name="port" type="int" />
<description>
Sets the proxy server for HTTPS requests.
- The proxy server is unset if [code]host[/code] is empty or [code]port[/code] is -1.
+ The proxy server is unset if [param host] is empty or [param port] is -1.
</description>
</method>
</methods>
@@ -259,10 +259,10 @@
</members>
<signals>
<signal name="request_completed">
- <argument index="0" name="result" type="int" />
- <argument index="1" name="response_code" type="int" />
- <argument index="2" name="headers" type="PackedStringArray" />
- <argument index="3" name="body" type="PackedByteArray" />
+ <param index="0" name="result" type="int" />
+ <param index="1" name="response_code" type="int" />
+ <param index="2" name="headers" type="PackedStringArray" />
+ <param index="3" name="body" type="PackedByteArray" />
<description>
Emitted when a request is completed.
</description>
diff --git a/doc/classes/HashingContext.xml b/doc/classes/HashingContext.xml
index c126efcfbb..6e3092e618 100644
--- a/doc/classes/HashingContext.xml
+++ b/doc/classes/HashingContext.xml
@@ -69,16 +69,16 @@
</method>
<method name="start">
<return type="int" enum="Error" />
- <argument index="0" name="type" type="int" enum="HashingContext.HashType" />
+ <param index="0" name="type" type="int" enum="HashingContext.HashType" />
<description>
- Starts a new hash computation of the given [code]type[/code] (e.g. [constant HASH_SHA256] to start computation of a SHA-256).
+ Starts a new hash computation of the given [param type] (e.g. [constant HASH_SHA256] to start computation of a SHA-256).
</description>
</method>
<method name="update">
<return type="int" enum="Error" />
- <argument index="0" name="chunk" type="PackedByteArray" />
+ <param index="0" name="chunk" type="PackedByteArray" />
<description>
- Updates the computation with the given [code]chunk[/code] of data.
+ Updates the computation with the given [param chunk] of data.
</description>
</method>
</methods>
diff --git a/doc/classes/HingeJoint3D.xml b/doc/classes/HingeJoint3D.xml
index eb1d1d5eca..99524795f9 100644
--- a/doc/classes/HingeJoint3D.xml
+++ b/doc/classes/HingeJoint3D.xml
@@ -11,30 +11,30 @@
<methods>
<method name="get_flag" qualifiers="const">
<return type="bool" />
- <argument index="0" name="flag" type="int" enum="HingeJoint3D.Flag" />
+ <param index="0" name="flag" type="int" enum="HingeJoint3D.Flag" />
<description>
Returns the value of the specified flag.
</description>
</method>
<method name="get_param" qualifiers="const">
<return type="float" />
- <argument index="0" name="param" type="int" enum="HingeJoint3D.Param" />
+ <param index="0" name="param" type="int" enum="HingeJoint3D.Param" />
<description>
Returns the value of the specified parameter.
</description>
</method>
<method name="set_flag">
<return type="void" />
- <argument index="0" name="flag" type="int" enum="HingeJoint3D.Flag" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="flag" type="int" enum="HingeJoint3D.Flag" />
+ <param index="1" name="enabled" type="bool" />
<description>
If [code]true[/code], enables the specified flag.
</description>
</method>
<method name="set_param">
<return type="void" />
- <argument index="0" name="param" type="int" enum="HingeJoint3D.Param" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="param" type="int" enum="HingeJoint3D.Param" />
+ <param index="1" name="value" type="float" />
<description>
Sets the value of the specified parameter.
</description>
@@ -47,7 +47,7 @@
<member name="angular_limit/enable" type="bool" setter="set_flag" getter="get_flag" default="false">
If [code]true[/code], the hinges maximum and minimum rotation, defined by [member angular_limit/lower] and [member angular_limit/upper] has effects.
</member>
- <member name="angular_limit/lower" type="float" setter="_set_lower_limit" getter="_get_lower_limit" default="-90.0">
+ <member name="angular_limit/lower" type="float" setter="set_param" getter="get_param" default="-1.5708">
The minimum rotation. Only active if [member angular_limit/enable] is [code]true[/code].
</member>
<member name="angular_limit/relaxation" type="float" setter="set_param" getter="get_param" default="1.0">
@@ -55,7 +55,7 @@
</member>
<member name="angular_limit/softness" type="float" setter="set_param" getter="get_param" default="0.9">
</member>
- <member name="angular_limit/upper" type="float" setter="_set_upper_limit" getter="_get_upper_limit" default="90.0">
+ <member name="angular_limit/upper" type="float" setter="set_param" getter="get_param" default="1.5708">
The maximum rotation. Only active if [member angular_limit/enable] is [code]true[/code].
</member>
<member name="motor/enable" type="bool" setter="set_flag" getter="get_flag" default="false">
diff --git a/doc/classes/IP.xml b/doc/classes/IP.xml
index 569f7fe570..1e5e6da513 100644
--- a/doc/classes/IP.xml
+++ b/doc/classes/IP.xml
@@ -11,26 +11,26 @@
<methods>
<method name="clear_cache">
<return type="void" />
- <argument index="0" name="hostname" type="String" default="&quot;&quot;" />
+ <param index="0" name="hostname" type="String" default="&quot;&quot;" />
<description>
- Removes all of a [code]hostname[/code]'s cached references. If no [code]hostname[/code] is given, all cached IP addresses are removed.
+ Removes all of a [param hostname]'s cached references. If no [param hostname] is given, all cached IP addresses are removed.
</description>
</method>
<method name="erase_resolve_item">
<return type="void" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
- Removes a given item [code]id[/code] from the queue. This should be used to free a queue after it has completed to enable more queries to happen.
+ Removes a given item [param id] from the queue. This should be used to free a queue after it has completed to enable more queries to happen.
</description>
</method>
<method name="get_local_addresses" qualifiers="const">
- <return type="Array" />
+ <return type="PackedStringArray" />
<description>
Returns all the user's current IPv4 and IPv6 addresses as an array.
</description>
</method>
<method name="get_local_interfaces" qualifiers="const">
- <return type="Array" />
+ <return type="Dictionary[]" />
<description>
Returns all network adapters as an array.
Each adapter is a dictionary of the form:
@@ -46,47 +46,47 @@
</method>
<method name="get_resolve_item_address" qualifiers="const">
<return type="String" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
- Returns a queued hostname's IP address, given its queue [code]id[/code]. Returns an empty string on error or if resolution hasn't happened yet (see [method get_resolve_item_status]).
+ Returns a queued hostname's IP address, given its queue [param id]. Returns an empty string on error or if resolution hasn't happened yet (see [method get_resolve_item_status]).
</description>
</method>
<method name="get_resolve_item_addresses" qualifiers="const">
<return type="Array" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Returns resolved addresses, or an empty array if an error happened or resolution didn't happen yet (see [method get_resolve_item_status]).
</description>
</method>
<method name="get_resolve_item_status" qualifiers="const">
<return type="int" enum="IP.ResolverStatus" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
- Returns a queued hostname's status as a [enum ResolverStatus] constant, given its queue [code]id[/code].
+ Returns a queued hostname's status as a [enum ResolverStatus] constant, given its queue [param id].
</description>
</method>
<method name="resolve_hostname">
<return type="String" />
- <argument index="0" name="host" type="String" />
- <argument index="1" name="ip_type" type="int" enum="IP.Type" default="3" />
+ <param index="0" name="host" type="String" />
+ <param index="1" name="ip_type" type="int" enum="IP.Type" default="3" />
<description>
- Returns a given hostname's IPv4 or IPv6 address when resolved (blocking-type method). The address type returned depends on the [enum Type] constant given as [code]ip_type[/code].
+ Returns a given hostname's IPv4 or IPv6 address when resolved (blocking-type method). The address type returned depends on the [enum Type] constant given as [param ip_type].
</description>
</method>
<method name="resolve_hostname_addresses">
- <return type="Array" />
- <argument index="0" name="host" type="String" />
- <argument index="1" name="ip_type" type="int" enum="IP.Type" default="3" />
+ <return type="PackedStringArray" />
+ <param index="0" name="host" type="String" />
+ <param index="1" name="ip_type" type="int" enum="IP.Type" default="3" />
<description>
- Resolves a given hostname in a blocking way. Addresses are returned as an [Array] of IPv4 or IPv6 addresses depending on [code]ip_type[/code].
+ Resolves a given hostname in a blocking way. Addresses are returned as an [Array] of IPv4 or IPv6 addresses depending on [param ip_type].
</description>
</method>
<method name="resolve_hostname_queue_item">
<return type="int" />
- <argument index="0" name="host" type="String" />
- <argument index="1" name="ip_type" type="int" enum="IP.Type" default="3" />
+ <param index="0" name="host" type="String" />
+ <param index="1" name="ip_type" type="int" enum="IP.Type" default="3" />
<description>
- Creates a queue item to resolve a hostname to an IPv4 or IPv6 address depending on the [enum Type] constant given as [code]ip_type[/code]. Returns the queue ID if successful, or [constant RESOLVER_INVALID_ID] on error.
+ Creates a queue item to resolve a hostname to an IPv4 or IPv6 address depending on the [enum Type] constant given as [param ip_type]. Returns the queue ID if successful, or [constant RESOLVER_INVALID_ID] on error.
</description>
</method>
</methods>
diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml
index a927345e79..b138a55ea3 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -14,53 +14,53 @@
<methods>
<method name="adjust_bcs">
<return type="void" />
- <argument index="0" name="brightness" type="float" />
- <argument index="1" name="contrast" type="float" />
- <argument index="2" name="saturation" type="float" />
+ <param index="0" name="brightness" type="float" />
+ <param index="1" name="contrast" type="float" />
+ <param index="2" name="saturation" type="float" />
<description>
</description>
</method>
<method name="blend_rect">
<return type="void" />
- <argument index="0" name="src" type="Image" />
- <argument index="1" name="src_rect" type="Rect2i" />
- <argument index="2" name="dst" type="Vector2i" />
+ <param index="0" name="src" type="Image" />
+ <param index="1" name="src_rect" type="Rect2i" />
+ <param index="2" name="dst" type="Vector2i" />
<description>
- Alpha-blends [code]src_rect[/code] from [code]src[/code] image to this image at coordinates [code]dest[/code], clipped accordingly to both image bounds. This image and [code]src[/code] image [b]must[/b] have the same format. [code]src_rect[/code] with not positive size is treated as empty.
+ Alpha-blends [param src_rect] from [param src] image to this image at coordinates [param dst], clipped accordingly to both image bounds. This image and [param src] image [b]must[/b] have the same format. [param src_rect] with not positive size is treated as empty.
</description>
</method>
<method name="blend_rect_mask">
<return type="void" />
- <argument index="0" name="src" type="Image" />
- <argument index="1" name="mask" type="Image" />
- <argument index="2" name="src_rect" type="Rect2i" />
- <argument index="3" name="dst" type="Vector2i" />
+ <param index="0" name="src" type="Image" />
+ <param index="1" name="mask" type="Image" />
+ <param index="2" name="src_rect" type="Rect2i" />
+ <param index="3" name="dst" type="Vector2i" />
<description>
- Alpha-blends [code]src_rect[/code] from [code]src[/code] image to this image using [code]mask[/code] image at coordinates [code]dst[/code], clipped accordingly to both image bounds. Alpha channels are required for both [code]src[/code] and [code]mask[/code]. [code]dst[/code] pixels and [code]src[/code] pixels will blend if the corresponding mask pixel's alpha value is not 0. This image and [code]src[/code] image [b]must[/b] have the same format. [code]src[/code] image and [code]mask[/code] image [b]must[/b] have the same size (width and height) but they can have different formats. [code]src_rect[/code] with not positive size is treated as empty.
+ Alpha-blends [param src_rect] from [param src] image to this image using [param mask] image at coordinates [param dst], clipped accordingly to both image bounds. Alpha channels are required for both [param src] and [param mask]. [param dst] pixels and [param src] pixels will blend if the corresponding mask pixel's alpha value is not 0. This image and [param src] image [b]must[/b] have the same format. [param src] image and [param mask] image [b]must[/b] have the same size (width and height) but they can have different formats. [param src_rect] with not positive size is treated as empty.
</description>
</method>
<method name="blit_rect">
<return type="void" />
- <argument index="0" name="src" type="Image" />
- <argument index="1" name="src_rect" type="Rect2i" />
- <argument index="2" name="dst" type="Vector2i" />
+ <param index="0" name="src" type="Image" />
+ <param index="1" name="src_rect" type="Rect2i" />
+ <param index="2" name="dst" type="Vector2i" />
<description>
- Copies [code]src_rect[/code] from [code]src[/code] image to this image at coordinates [code]dst[/code], clipped accordingly to both image bounds. This image and [code]src[/code] image [b]must[/b] have the same format. [code]src_rect[/code] with not positive size is treated as empty.
+ Copies [param src_rect] from [param src] image to this image at coordinates [param dst], clipped accordingly to both image bounds. This image and [param src] image [b]must[/b] have the same format. [param src_rect] with not positive size is treated as empty.
</description>
</method>
<method name="blit_rect_mask">
<return type="void" />
- <argument index="0" name="src" type="Image" />
- <argument index="1" name="mask" type="Image" />
- <argument index="2" name="src_rect" type="Rect2i" />
- <argument index="3" name="dst" type="Vector2i" />
+ <param index="0" name="src" type="Image" />
+ <param index="1" name="mask" type="Image" />
+ <param index="2" name="src_rect" type="Rect2i" />
+ <param index="3" name="dst" type="Vector2i" />
<description>
- Blits [code]src_rect[/code] area from [code]src[/code] image to this image at the coordinates given by [code]dst[/code], clipped accordingly to both image bounds. [code]src[/code] pixel is copied onto [code]dst[/code] if the corresponding [code]mask[/code] pixel's alpha value is not 0. This image and [code]src[/code] image [b]must[/b] have the same format. [code]src[/code] image and [code]mask[/code] image [b]must[/b] have the same size (width and height) but they can have different formats. [code]src_rect[/code] with not positive size is treated as empty.
+ Blits [param src_rect] area from [param src] image to this image at the coordinates given by [param dst], clipped accordingly to both image bounds. [param src] pixel is copied onto [param dst] if the corresponding [param mask] pixel's alpha value is not 0. This image and [param src] image [b]must[/b] have the same format. [param src] image and [param mask] image [b]must[/b] have the same size (width and height) but they can have different formats. [param src_rect] with not positive size is treated as empty.
</description>
</method>
<method name="bump_map_to_normal_map">
<return type="void" />
- <argument index="0" name="bump_scale" type="float" default="1.0" />
+ <param index="0" name="bump_scale" type="float" default="1.0" />
<description>
Converts a bump map to a normal map. A bump map provides a height offset per-pixel, while a normal map provides a normal direction per pixel.
</description>
@@ -73,25 +73,25 @@
</method>
<method name="compress">
<return type="int" enum="Error" />
- <argument index="0" name="mode" type="int" enum="Image.CompressMode" />
- <argument index="1" name="source" type="int" enum="Image.CompressSource" default="0" />
- <argument index="2" name="lossy_quality" type="float" default="0.7" />
+ <param index="0" name="mode" type="int" enum="Image.CompressMode" />
+ <param index="1" name="source" type="int" enum="Image.CompressSource" default="0" />
+ <param index="2" name="lossy_quality" type="float" default="0.7" />
<description>
Compresses the image to use less memory. Can not directly access pixel data while the image is compressed. Returns error if the chosen compression mode is not available. See [enum CompressMode] and [enum CompressSource] constants.
</description>
</method>
<method name="compress_from_channels">
<return type="int" enum="Error" />
- <argument index="0" name="mode" type="int" enum="Image.CompressMode" />
- <argument index="1" name="channels" type="int" enum="Image.UsedChannels" />
- <argument index="2" name="lossy_quality" type="float" default="0.7" />
+ <param index="0" name="mode" type="int" enum="Image.CompressMode" />
+ <param index="1" name="channels" type="int" enum="Image.UsedChannels" />
+ <param index="2" name="lossy_quality" type="float" default="0.7" />
<description>
</description>
</method>
<method name="compute_image_metrics">
<return type="Dictionary" />
- <argument index="0" name="compared_image" type="Image" />
- <argument index="1" name="use_luma" type="bool" />
+ <param index="0" name="compared_image" type="Image" />
+ <param index="1" name="use_luma" type="bool" />
<description>
Compute image metrics on the current image and the compared image.
The dictionary contains [code]max[/code], [code]mean[/code], [code]mean_squared[/code], [code]root_mean_squared[/code] and [code]peak_snr[/code].
@@ -99,45 +99,45 @@
</method>
<method name="convert">
<return type="void" />
- <argument index="0" name="format" type="int" enum="Image.Format" />
+ <param index="0" name="format" type="int" enum="Image.Format" />
<description>
Converts the image's format. See [enum Format] constants.
</description>
</method>
<method name="copy_from">
<return type="void" />
- <argument index="0" name="src" type="Image" />
+ <param index="0" name="src" type="Image" />
<description>
- Copies [code]src[/code] image to this image.
+ Copies [param src] image to this image.
</description>
</method>
<method name="create">
<return type="void" />
- <argument index="0" name="width" type="int" />
- <argument index="1" name="height" type="int" />
- <argument index="2" name="use_mipmaps" type="bool" />
- <argument index="3" name="format" type="int" enum="Image.Format" />
+ <param index="0" name="width" type="int" />
+ <param index="1" name="height" type="int" />
+ <param index="2" name="use_mipmaps" type="bool" />
+ <param index="3" name="format" type="int" enum="Image.Format" />
<description>
- Creates an empty image of given size and format. See [enum Format] constants. If [code]use_mipmaps[/code] is [code]true[/code] then generate mipmaps for this image. See the [method generate_mipmaps].
+ Creates an empty image of given size and format. See [enum Format] constants. If [param use_mipmaps] is [code]true[/code] then generate mipmaps for this image. See the [method generate_mipmaps].
</description>
</method>
<method name="create_from_data">
<return type="void" />
- <argument index="0" name="width" type="int" />
- <argument index="1" name="height" type="int" />
- <argument index="2" name="use_mipmaps" type="bool" />
- <argument index="3" name="format" type="int" enum="Image.Format" />
- <argument index="4" name="data" type="PackedByteArray" />
+ <param index="0" name="width" type="int" />
+ <param index="1" name="height" type="int" />
+ <param index="2" name="use_mipmaps" type="bool" />
+ <param index="3" name="format" type="int" enum="Image.Format" />
+ <param index="4" name="data" type="PackedByteArray" />
<description>
- Creates a new image of given size and format. See [enum Format] constants. Fills the image with the given raw data. If [code]use_mipmaps[/code] is [code]true[/code] then loads mipmaps for this image from [code]data[/code]. See [method generate_mipmaps].
+ Creates a new image of given size and format. See [enum Format] constants. Fills the image with the given raw data. If [param use_mipmaps] is [code]true[/code] then loads mipmaps for this image from [param data]. See [method generate_mipmaps].
</description>
</method>
<method name="crop">
<return type="void" />
- <argument index="0" name="width" type="int" />
- <argument index="1" name="height" type="int" />
+ <param index="0" name="width" type="int" />
+ <param index="1" name="height" type="int" />
<description>
- Crops the image to the given [code]width[/code] and [code]height[/code]. If the specified size is larger than the current size, the extra area is filled with black pixels.
+ Crops the image to the given [param width] and [param height]. If the specified size is larger than the current size, the extra area is filled with black pixels.
</description>
</method>
<method name="decompress">
@@ -155,23 +155,23 @@
</method>
<method name="detect_used_channels" qualifiers="const">
<return type="int" enum="Image.UsedChannels" />
- <argument index="0" name="source" type="int" enum="Image.CompressSource" default="0" />
+ <param index="0" name="source" type="int" enum="Image.CompressSource" default="0" />
<description>
</description>
</method>
<method name="fill">
<return type="void" />
- <argument index="0" name="color" type="Color" />
+ <param index="0" name="color" type="Color" />
<description>
- Fills the image with [code]color[/code].
+ Fills the image with [param color].
</description>
</method>
<method name="fill_rect">
<return type="void" />
- <argument index="0" name="rect" type="Rect2i" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="rect" type="Rect2i" />
+ <param index="1" name="color" type="Color" />
<description>
- Fills [code]rect[/code] with [code]color[/code].
+ Fills [param rect] with [param color].
</description>
</method>
<method name="fix_alpha_edges">
@@ -194,7 +194,7 @@
</method>
<method name="generate_mipmaps">
<return type="int" enum="Error" />
- <argument index="0" name="renormalize" type="bool" default="false" />
+ <param index="0" name="renormalize" type="bool" default="false" />
<description>
Generates mipmaps for the image. Mipmaps are precalculated lower-resolution copies of the image that are automatically used if the image needs to be scaled down when rendered. They help improve image quality and performance when rendering. This method returns an error if the image is compressed, in a custom format, or if the image's width/height is [code]0[/code].
[b]Note:[/b] Mipmap generation is done on the CPU, is single-threaded and is [i]always[/i] done on the main thread. This means generating mipmaps will result in noticeable stuttering during gameplay, even if [method generate_mipmaps] is called from a [Thread].
@@ -220,15 +220,15 @@
</method>
<method name="get_mipmap_offset" qualifiers="const">
<return type="int" />
- <argument index="0" name="mipmap" type="int" />
+ <param index="0" name="mipmap" type="int" />
<description>
- Returns the offset where the image's mipmap with index [code]mipmap[/code] is stored in the [code]data[/code] dictionary.
+ Returns the offset where the image's mipmap with index [param mipmap] is stored in the [code]data[/code] dictionary.
</description>
</method>
<method name="get_pixel" qualifiers="const">
<return type="Color" />
- <argument index="0" name="x" type="int" />
- <argument index="1" name="y" type="int" />
+ <param index="0" name="x" type="int" />
+ <param index="1" name="y" type="int" />
<description>
Returns the color of the pixel at [code](x, y)[/code].
This is the same as [method get_pixelv], but with two integer arguments instead of a [Vector2i] argument.
@@ -236,21 +236,21 @@
</method>
<method name="get_pixelv" qualifiers="const">
<return type="Color" />
- <argument index="0" name="point" type="Vector2i" />
+ <param index="0" name="point" type="Vector2i" />
<description>
- Returns the color of the pixel at [code]point[/code].
+ Returns the color of the pixel at [param point].
This is the same as [method get_pixel], but with a [Vector2i] argument instead of two integer arguments.
</description>
</method>
<method name="get_rect" qualifiers="const">
<return type="Image" />
- <argument index="0" name="rect" type="Rect2i" />
+ <param index="0" name="rect" type="Rect2i" />
<description>
- Returns a new image that is a copy of the image's area specified with [code]rect[/code].
+ Returns a new image that is a copy of the image's area specified with [param rect].
</description>
</method>
<method name="get_size" qualifiers="const">
- <return type="Vector2" />
+ <return type="Vector2i" />
<description>
Returns the image's size (width and height).
</description>
@@ -293,16 +293,16 @@
</method>
<method name="load">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
- Loads an image from file [code]path[/code]. See [url=$DOCS_URL/tutorials/assets_pipeline/importing_images.html#supported-image-formats]Supported image formats[/url] for a list of supported image formats and limitations.
+ Loads an image from file [param path]. See [url=$DOCS_URL/tutorials/assets_pipeline/importing_images.html#supported-image-formats]Supported image formats[/url] for a list of supported image formats and limitations.
[b]Warning:[/b] This method should only be used in the editor or in cases when you need to load external images at run-time, such as images located at the [code]user://[/code] directory, and may not work in exported projects.
See also [ImageTexture] description for usage examples.
</description>
</method>
<method name="load_bmp_from_buffer">
<return type="int" enum="Error" />
- <argument index="0" name="buffer" type="PackedByteArray" />
+ <param index="0" name="buffer" type="PackedByteArray" />
<description>
Loads an image from the binary contents of a BMP file.
[b]Note:[/b] Godot's BMP module doesn't support 16-bit per pixel images. Only 1-bit, 4-bit, 8-bit, 24-bit, and 32-bit per pixel images are supported.
@@ -310,35 +310,35 @@
</method>
<method name="load_from_file" qualifiers="static">
<return type="Image" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Creates a new [Image] and loads data from the specified file.
</description>
</method>
<method name="load_jpg_from_buffer">
<return type="int" enum="Error" />
- <argument index="0" name="buffer" type="PackedByteArray" />
+ <param index="0" name="buffer" type="PackedByteArray" />
<description>
Loads an image from the binary contents of a JPEG file.
</description>
</method>
<method name="load_png_from_buffer">
<return type="int" enum="Error" />
- <argument index="0" name="buffer" type="PackedByteArray" />
+ <param index="0" name="buffer" type="PackedByteArray" />
<description>
Loads an image from the binary contents of a PNG file.
</description>
</method>
<method name="load_tga_from_buffer">
<return type="int" enum="Error" />
- <argument index="0" name="buffer" type="PackedByteArray" />
+ <param index="0" name="buffer" type="PackedByteArray" />
<description>
Loads an image from the binary contents of a TGA file.
</description>
</method>
<method name="load_webp_from_buffer">
<return type="int" enum="Error" />
- <argument index="0" name="buffer" type="PackedByteArray" />
+ <param index="0" name="buffer" type="PackedByteArray" />
<description>
Loads an image from the binary contents of a WebP file.
</description>
@@ -357,19 +357,19 @@
</method>
<method name="resize">
<return type="void" />
- <argument index="0" name="width" type="int" />
- <argument index="1" name="height" type="int" />
- <argument index="2" name="interpolation" type="int" enum="Image.Interpolation" default="1" />
+ <param index="0" name="width" type="int" />
+ <param index="1" name="height" type="int" />
+ <param index="2" name="interpolation" type="int" enum="Image.Interpolation" default="1" />
<description>
- Resizes the image to the given [code]width[/code] and [code]height[/code]. New pixels are calculated using the [code]interpolation[/code] mode defined via [enum Interpolation] constants.
+ Resizes the image to the given [param width] and [param height]. New pixels are calculated using the [param interpolation] mode defined via [enum Interpolation] constants.
</description>
</method>
<method name="resize_to_po2">
<return type="void" />
- <argument index="0" name="square" type="bool" default="false" />
- <argument index="1" name="interpolation" type="int" enum="Image.Interpolation" default="1" />
+ <param index="0" name="square" type="bool" default="false" />
+ <param index="1" name="interpolation" type="int" enum="Image.Interpolation" default="1" />
<description>
- Resizes the image to the nearest power of 2 for the width and height. If [code]square[/code] is [code]true[/code] then set width and height to be the same. New pixels are calculated using the [code]interpolation[/code] mode defined via [enum Interpolation] constants.
+ Resizes the image to the nearest power of 2 for the width and height. If [param square] is [code]true[/code] then set width and height to be the same. New pixels are calculated using the [param interpolation] mode defined via [enum Interpolation] constants.
</description>
</method>
<method name="rgbe_to_srgb">
@@ -386,50 +386,50 @@
</method>
<method name="rotate_90">
<return type="void" />
- <argument index="0" name="direction" type="int" enum="ClockDirection" />
+ <param index="0" name="direction" type="int" enum="ClockDirection" />
<description>
- Rotates the image in the specified [code]direction[/code] by [code]90[/code] degrees. The width and height of the image must be greater than [code]1[/code]. If the width and height are not equal, the image will be resized.
+ Rotates the image in the specified [param direction] by [code]90[/code] degrees. The width and height of the image must be greater than [code]1[/code]. If the width and height are not equal, the image will be resized.
</description>
</method>
<method name="save_exr" qualifiers="const">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="grayscale" type="bool" default="false" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="grayscale" type="bool" default="false" />
<description>
- Saves the image as an EXR file to [code]path[/code]. If [code]grayscale[/code] is [code]true[/code] and the image has only one channel, it will be saved explicitly as monochrome rather than one red channel. This function will return [constant ERR_UNAVAILABLE] if Godot was compiled without the TinyEXR module.
+ Saves the image as an EXR file to [param path]. If [param grayscale] is [code]true[/code] and the image has only one channel, it will be saved explicitly as monochrome rather than one red channel. This function will return [constant ERR_UNAVAILABLE] if Godot was compiled without the TinyEXR module.
[b]Note:[/b] The TinyEXR module is disabled in non-editor builds, which means [method save_exr] will return [constant ERR_UNAVAILABLE] when it is called from an exported project.
</description>
</method>
<method name="save_exr_to_buffer" qualifiers="const">
<return type="PackedByteArray" />
- <argument index="0" name="grayscale" type="bool" default="false" />
+ <param index="0" name="grayscale" type="bool" default="false" />
<description>
- Saves the image as an EXR file to a byte array. If [code]grayscale[/code] is [code]true[/code] and the image has only one channel, it will be saved explicitly as monochrome rather than one red channel. This function will return an empty byte array if Godot was compiled without the TinyEXR module.
+ Saves the image as an EXR file to a byte array. If [param grayscale] is [code]true[/code] and the image has only one channel, it will be saved explicitly as monochrome rather than one red channel. This function will return an empty byte array if Godot was compiled without the TinyEXR module.
[b]Note:[/b] The TinyEXR module is disabled in non-editor builds, which means [method save_exr] will return an empty byte array when it is called from an exported project.
</description>
</method>
<method name="save_jpg" qualifiers="const">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="quality" type="float" default="0.75" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="quality" type="float" default="0.75" />
<description>
- Saves the image as a JPEG file to [code]path[/code] with the specified [code]quality[/code] between [code]0.01[/code] and [code]1.0[/code] (inclusive). Higher [code]quality[/code] values result in better-looking output at the cost of larger file sizes. Recommended [code]quality[/code] values are between [code]0.75[/code] and [code]0.90[/code]. Even at quality [code]1.00[/code], JPEG compression remains lossy.
+ Saves the image as a JPEG file to [param path] with the specified [param quality] between [code]0.01[/code] and [code]1.0[/code] (inclusive). Higher [param quality] values result in better-looking output at the cost of larger file sizes. Recommended [param quality] values are between [code]0.75[/code] and [code]0.90[/code]. Even at quality [code]1.00[/code], JPEG compression remains lossy.
[b]Note:[/b] JPEG does not save an alpha channel. If the [Image] contains an alpha channel, the image will still be saved, but the resulting JPEG file won't contain the alpha channel.
</description>
</method>
<method name="save_jpg_to_buffer" qualifiers="const">
<return type="PackedByteArray" />
- <argument index="0" name="quality" type="float" default="0.75" />
+ <param index="0" name="quality" type="float" default="0.75" />
<description>
- Saves the image as a JPEG file to a byte array with the specified [code]quality[/code] between [code]0.01[/code] and [code]1.0[/code] (inclusive). Higher [code]quality[/code] values result in better-looking output at the cost of larger byte array sizes (and therefore memory usage). Recommended [code]quality[/code] values are between [code]0.75[/code] and [code]0.90[/code]. Even at quality [code]1.00[/code], JPEG compression remains lossy.
+ Saves the image as a JPEG file to a byte array with the specified [param quality] between [code]0.01[/code] and [code]1.0[/code] (inclusive). Higher [param quality] values result in better-looking output at the cost of larger byte array sizes (and therefore memory usage). Recommended [param quality] values are between [code]0.75[/code] and [code]0.90[/code]. Even at quality [code]1.00[/code], JPEG compression remains lossy.
[b]Note:[/b] JPEG does not save an alpha channel. If the [Image] contains an alpha channel, the image will still be saved, but the resulting byte array won't contain the alpha channel.
</description>
</method>
<method name="save_png" qualifiers="const">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
- Saves the image as a PNG file to the file at [code]path[/code].
+ Saves the image as a PNG file to the file at [param path].
</description>
</method>
<method name="save_png_to_buffer" qualifiers="const">
@@ -440,28 +440,28 @@
</method>
<method name="save_webp" qualifiers="const">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="lossy" type="bool" default="false" />
- <argument index="2" name="quality" type="float" default="0.75" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="lossy" type="bool" default="false" />
+ <param index="2" name="quality" type="float" default="0.75" />
<description>
- Saves the image as a WebP (Web Picture) file to the file at [code]path[/code]. By default it will save lossless. If [code]lossy[/code] is true, the image will be saved lossy, using the [code]quality[/code] setting between 0.0 and 1.0 (inclusive).
+ Saves the image as a WebP (Web Picture) file to the file at [param path]. By default it will save lossless. If [param lossy] is true, the image will be saved lossy, using the [param quality] setting between 0.0 and 1.0 (inclusive).
</description>
</method>
<method name="save_webp_to_buffer" qualifiers="const">
<return type="PackedByteArray" />
- <argument index="0" name="lossy" type="bool" default="false" />
- <argument index="1" name="quality" type="float" default="0.75" />
+ <param index="0" name="lossy" type="bool" default="false" />
+ <param index="1" name="quality" type="float" default="0.75" />
<description>
- Saves the image as a WebP (Web Picture) file to a byte array. By default it will save lossless. If [code]lossy[/code] is true, the image will be saved lossy, using the [code]quality[/code] setting between 0.0 and 1.0 (inclusive).
+ Saves the image as a WebP (Web Picture) file to a byte array. By default it will save lossless. If [param lossy] is true, the image will be saved lossy, using the [param quality] setting between 0.0 and 1.0 (inclusive).
</description>
</method>
<method name="set_pixel">
<return type="void" />
- <argument index="0" name="x" type="int" />
- <argument index="1" name="y" type="int" />
- <argument index="2" name="color" type="Color" />
+ <param index="0" name="x" type="int" />
+ <param index="1" name="y" type="int" />
+ <param index="2" name="color" type="Color" />
<description>
- Sets the [Color] of the pixel at [code](x, y)[/code] to [code]color[/code]. Example:
+ Sets the [Color] of the pixel at [code](x, y)[/code] to [param color]. Example:
[codeblocks]
[gdscript]
var img_width = 10
@@ -485,10 +485,10 @@
</method>
<method name="set_pixelv">
<return type="void" />
- <argument index="0" name="point" type="Vector2i" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="point" type="Vector2i" />
+ <param index="1" name="color" type="Color" />
<description>
- Sets the [Color] of the pixel at [code]point[/code] to [code]color[/code]. Example:
+ Sets the [Color] of the pixel at [param point] to [param color]. Example:
[codeblocks]
[gdscript]
var img_width = 10
diff --git a/doc/classes/ImageTexture.xml b/doc/classes/ImageTexture.xml
index 084bf7e809..45cbd7ac87 100644
--- a/doc/classes/ImageTexture.xml
+++ b/doc/classes/ImageTexture.xml
@@ -6,20 +6,20 @@
<description>
A [Texture2D] based on an [Image]. For an image to be displayed, an [ImageTexture] has to be created from it using the [method create_from_image] method:
[codeblock]
- var image = Image.load_from_file("res://icon.png")
+ var image = Image.load_from_file("res://icon.svg")
var texture = ImageTexture.create_from_image(image)
$Sprite2D.texture = texture
[/codeblock]
This way, textures can be created at run-time by loading images both from within the editor and externally.
[b]Warning:[/b] Prefer to load imported textures with [method @GDScript.load] over loading them from within the filesystem dynamically with [method Image.load], as it may not work in exported projects:
[codeblock]
- var texture = load("res://icon.png")
+ var texture = load("res://icon.svg")
$Sprite2D.texture = texture
[/codeblock]
This is because images have to be imported as a [CompressedTexture2D] first to be loaded with [method @GDScript.load]. If you'd still like to load an image file just like any other [Resource], import it as an [Image] resource instead, and then load it normally using the [method @GDScript.load] method.
[b]Note:[/b] The image can be retrieved from an imported texture using the [method Texture2D.get_image] method, which returns a copy of the image:
[codeblock]
- var texture = load("res://icon.png")
+ var texture = load("res://icon.svg")
var image : Image = texture.get_image()
[/codeblock]
An [ImageTexture] is not meant to be operated from within the editor interface directly, and is mostly useful for rendering images on screen dynamically via code. If you need to generate images procedurally from within the editor, consider saving and importing images as custom texture resources implementing a new [EditorImportPlugin].
@@ -31,7 +31,7 @@
<methods>
<method name="create_from_image" qualifiers="static">
<return type="ImageTexture" />
- <argument index="0" name="image" type="Image" />
+ <param index="0" name="image" type="Image" />
<description>
Creates a new [ImageTexture] and initializes it by allocating and setting the data from an [Image].
</description>
@@ -44,7 +44,7 @@
</method>
<method name="set_image">
<return type="void" />
- <argument index="0" name="image" type="Image" />
+ <param index="0" name="image" type="Image" />
<description>
Replaces the texture's data with a new [Image]. This will re-allocate new memory for the texture.
If you want to update the image, but don't need to change its parameters (format, size), use [method update] instead for better performance.
@@ -52,14 +52,14 @@
</method>
<method name="set_size_override">
<return type="void" />
- <argument index="0" name="size" type="Vector2i" />
+ <param index="0" name="size" type="Vector2i" />
<description>
Resizes the texture to the specified dimensions.
</description>
</method>
<method name="update">
<return type="void" />
- <argument index="0" name="image" type="Image" />
+ <param index="0" name="image" type="Image" />
<description>
Replaces the texture's data with a new [Image].
[b]Note:[/b] The texture has to be created using [method create_from_image] or initialized first with the [method set_image] method before it can be updated. The new image dimensions, format, and mipmaps configuration should match the existing texture's image configuration.
diff --git a/doc/classes/ImageTexture3D.xml b/doc/classes/ImageTexture3D.xml
index b2068504eb..958c5f90f1 100644
--- a/doc/classes/ImageTexture3D.xml
+++ b/doc/classes/ImageTexture3D.xml
@@ -9,18 +9,18 @@
<methods>
<method name="create">
<return type="int" enum="Error" />
- <argument index="0" name="format" type="int" enum="Image.Format" />
- <argument index="1" name="width" type="int" />
- <argument index="2" name="height" type="int" />
- <argument index="3" name="depth" type="int" />
- <argument index="4" name="use_mipmaps" type="bool" />
- <argument index="5" name="data" type="Image[]" />
+ <param index="0" name="format" type="int" enum="Image.Format" />
+ <param index="1" name="width" type="int" />
+ <param index="2" name="height" type="int" />
+ <param index="3" name="depth" type="int" />
+ <param index="4" name="use_mipmaps" type="bool" />
+ <param index="5" name="data" type="Image[]" />
<description>
</description>
</method>
<method name="update">
<return type="void" />
- <argument index="0" name="data" type="Image[]" />
+ <param index="0" name="data" type="Image[]" />
<description>
</description>
</method>
diff --git a/doc/classes/ImageTextureLayered.xml b/doc/classes/ImageTextureLayered.xml
index c574e5c9c1..c0ad19ddd7 100644
--- a/doc/classes/ImageTextureLayered.xml
+++ b/doc/classes/ImageTextureLayered.xml
@@ -9,14 +9,14 @@
<methods>
<method name="create_from_images">
<return type="int" enum="Error" />
- <argument index="0" name="images" type="Array" />
+ <param index="0" name="images" type="Array" />
<description>
</description>
</method>
<method name="update_layer">
<return type="void" />
- <argument index="0" name="image" type="Image" />
- <argument index="1" name="layer" type="int" />
+ <param index="0" name="image" type="Image" />
+ <param index="1" name="layer" type="int" />
<description>
</description>
</method>
diff --git a/doc/classes/ImmediateMesh.xml b/doc/classes/ImmediateMesh.xml
index d12d5de184..a6d2e3e249 100644
--- a/doc/classes/ImmediateMesh.xml
+++ b/doc/classes/ImmediateMesh.xml
@@ -17,22 +17,22 @@
</method>
<method name="surface_add_vertex">
<return type="void" />
- <argument index="0" name="vertex" type="Vector3" />
+ <param index="0" name="vertex" type="Vector3" />
<description>
Add a 3D vertex using the current attributes previously set.
</description>
</method>
<method name="surface_add_vertex_2d">
<return type="void" />
- <argument index="0" name="vertex" type="Vector2" />
+ <param index="0" name="vertex" type="Vector2" />
<description>
Add a 2D vertex using the current attributes previously set.
</description>
</method>
<method name="surface_begin">
<return type="void" />
- <argument index="0" name="primitive" type="int" enum="Mesh.PrimitiveType" />
- <argument index="1" name="material" type="Material" default="null" />
+ <param index="0" name="primitive" type="int" enum="Mesh.PrimitiveType" />
+ <param index="1" name="material" type="Material" default="null" />
<description>
Begin a new surface.
</description>
@@ -45,35 +45,35 @@
</method>
<method name="surface_set_color">
<return type="void" />
- <argument index="0" name="color" type="Color" />
+ <param index="0" name="color" type="Color" />
<description>
Set the color attribute that will be pushed with the next vertex.
</description>
</method>
<method name="surface_set_normal">
<return type="void" />
- <argument index="0" name="normal" type="Vector3" />
+ <param index="0" name="normal" type="Vector3" />
<description>
Set the normal attribute that will be pushed with the next vertex.
</description>
</method>
<method name="surface_set_tangent">
<return type="void" />
- <argument index="0" name="tangent" type="Plane" />
+ <param index="0" name="tangent" type="Plane" />
<description>
Set the tangent attribute that will be pushed with the next vertex.
</description>
</method>
<method name="surface_set_uv">
<return type="void" />
- <argument index="0" name="uv" type="Vector2" />
+ <param index="0" name="uv" type="Vector2" />
<description>
Set the UV attribute that will be pushed with the next vertex.
</description>
</method>
<method name="surface_set_uv2">
<return type="void" />
- <argument index="0" name="uv2" type="Vector2" />
+ <param index="0" name="uv2" type="Vector2" />
<description>
Set the UV2 attribute that will be pushed with the next vertex.
</description>
diff --git a/doc/classes/ImporterMesh.xml b/doc/classes/ImporterMesh.xml
index 201c0ddd38..e15cfcd2c0 100644
--- a/doc/classes/ImporterMesh.xml
+++ b/doc/classes/ImporterMesh.xml
@@ -13,24 +13,24 @@
<methods>
<method name="add_blend_shape">
<return type="void" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
Adds name for a blend shape that will be added with [method add_surface]. Must be called before surface is added.
</description>
</method>
<method name="add_surface">
<return type="void" />
- <argument index="0" name="primitive" type="int" enum="Mesh.PrimitiveType" />
- <argument index="1" name="arrays" type="Array" />
- <argument index="2" name="blend_shapes" type="Array" default="[]" />
- <argument index="3" name="lods" type="Dictionary" default="{}" />
- <argument index="4" name="material" type="Material" default="null" />
- <argument index="5" name="name" type="String" default="&quot;&quot;" />
- <argument index="6" name="flags" type="int" default="0" />
+ <param index="0" name="primitive" type="int" enum="Mesh.PrimitiveType" />
+ <param index="1" name="arrays" type="Array" />
+ <param index="2" name="blend_shapes" type="Array" default="[]" />
+ <param index="3" name="lods" type="Dictionary" default="{}" />
+ <param index="4" name="material" type="Material" default="null" />
+ <param index="5" name="name" type="String" default="&quot;&quot;" />
+ <param index="6" name="flags" type="int" default="0" />
<description>
Creates a new surface, analogous to [method ArrayMesh.add_surface_from_arrays].
- Surfaces are created to be rendered using a [code]primitive[/code], which may be any of the types defined in [enum Mesh.PrimitiveType]. (As a note, when using indices, it is recommended to only use points, lines, or triangles.) [method Mesh.get_surface_count] will become the [code]surf_idx[/code] for this new surface.
- The [code]arrays[/code] argument is an array of arrays. See [enum Mesh.ArrayType] for the values used in this array. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this function into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array (or be an exact multiple of the vertex array's length, when multiple elements of a sub-array correspond to a single vertex) or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used.
+ Surfaces are created to be rendered using a [param primitive], which may be any of the types defined in [enum Mesh.PrimitiveType]. (As a note, when using indices, it is recommended to only use points, lines, or triangles.) [method Mesh.get_surface_count] will become the [code]surf_idx[/code] for this new surface.
+ The [param arrays] argument is an array of arrays. See [enum Mesh.ArrayType] for the values used in this array. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this function into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array (or be an exact multiple of the vertex array's length, when multiple elements of a sub-array correspond to a single vertex) or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used.
</description>
</method>
<method name="clear">
@@ -41,11 +41,11 @@
</method>
<method name="generate_lods">
<return type="void" />
- <argument index="0" name="normal_merge_angle" type="float" />
- <argument index="1" name="normal_split_angle" type="float" />
+ <param index="0" name="normal_merge_angle" type="float" />
+ <param index="1" name="normal_split_angle" type="float" />
<description>
Generates all lods for this ImporterMesh.
- [code]normal_merge_angle[/code] and [code]normal_split_angle[/code] are in degrees and used in the same way as the importer settings in [code]lods[/code]. As a good default, use 25 and 60 respectively.
+ [param normal_merge_angle] and [param normal_split_angle] are in degrees and used in the same way as the importer settings in [code]lods[/code]. As a good default, use 25 and 60 respectively.
The number of generated lods can be accessed using [method get_surface_lod_count], and each LOD is available in [method get_surface_lod_size] and [method get_surface_lod_indices].
</description>
</method>
@@ -63,7 +63,7 @@
</method>
<method name="get_blend_shape_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="blend_shape_idx" type="int" />
+ <param index="0" name="blend_shape_idx" type="int" />
<description>
Returns the name of the blend shape at this index.
</description>
@@ -76,24 +76,24 @@
</method>
<method name="get_mesh">
<return type="ArrayMesh" />
- <argument index="0" name="base_mesh" type="ArrayMesh" default="null" />
+ <param index="0" name="base_mesh" type="ArrayMesh" default="null" />
<description>
Returns the mesh data represented by this [ImporterMesh] as a usable [ArrayMesh].
This method caches the returned mesh, and subsequent calls will return the cached data until [method clear] is called.
- If not yet cached and [code]base_mesh[/code] is provided, [code]base_mesh[/code] will be used and mutated.
+ If not yet cached and [param base_mesh] is provided, [param base_mesh] will be used and mutated.
</description>
</method>
<method name="get_surface_arrays" qualifiers="const">
<return type="Array" />
- <argument index="0" name="surface_idx" type="int" />
+ <param index="0" name="surface_idx" type="int" />
<description>
Returns the arrays for the vertices, normals, uvs, etc. that make up the requested surface. See [method add_surface].
</description>
</method>
<method name="get_surface_blend_shape_arrays" qualifiers="const">
<return type="Array" />
- <argument index="0" name="surface_idx" type="int" />
- <argument index="1" name="blend_shape_idx" type="int" />
+ <param index="0" name="surface_idx" type="int" />
+ <param index="1" name="blend_shape_idx" type="int" />
<description>
Returns a single set of blend shape arrays for the requested blend shape index for a surface.
</description>
@@ -101,86 +101,86 @@
<method name="get_surface_count" qualifiers="const">
<return type="int" />
<description>
- Returns the amount of surfaces that the mesh holds.
+ Returns the number of surfaces that the mesh holds.
</description>
</method>
<method name="get_surface_format" qualifiers="const">
<return type="int" />
- <argument index="0" name="surface_idx" type="int" />
+ <param index="0" name="surface_idx" type="int" />
<description>
Returns the format of the surface that the mesh holds.
</description>
</method>
<method name="get_surface_lod_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="surface_idx" type="int" />
+ <param index="0" name="surface_idx" type="int" />
<description>
- Returns the amount of lods that the mesh holds on a given surface.
+ Returns the number of lods that the mesh holds on a given surface.
</description>
</method>
<method name="get_surface_lod_indices" qualifiers="const">
<return type="PackedInt32Array" />
- <argument index="0" name="surface_idx" type="int" />
- <argument index="1" name="lod_idx" type="int" />
+ <param index="0" name="surface_idx" type="int" />
+ <param index="1" name="lod_idx" type="int" />
<description>
Returns the index buffer of a lod for a surface.
</description>
</method>
<method name="get_surface_lod_size" qualifiers="const">
<return type="float" />
- <argument index="0" name="surface_idx" type="int" />
- <argument index="1" name="lod_idx" type="int" />
+ <param index="0" name="surface_idx" type="int" />
+ <param index="1" name="lod_idx" type="int" />
<description>
Returns the screen ratio which activates a lod for a surface.
</description>
</method>
<method name="get_surface_material" qualifiers="const">
<return type="Material" />
- <argument index="0" name="surface_idx" type="int" />
+ <param index="0" name="surface_idx" type="int" />
<description>
Returns a [Material] in a given surface. Surface is rendered using this material.
</description>
</method>
<method name="get_surface_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="surface_idx" type="int" />
+ <param index="0" name="surface_idx" type="int" />
<description>
Gets the name assigned to this surface.
</description>
</method>
<method name="get_surface_primitive_type">
<return type="int" enum="Mesh.PrimitiveType" />
- <argument index="0" name="surface_idx" type="int" />
+ <param index="0" name="surface_idx" type="int" />
<description>
Returns the primitive type of the requested surface (see [method add_surface]).
</description>
</method>
<method name="set_blend_shape_mode">
<return type="void" />
- <argument index="0" name="mode" type="int" enum="Mesh.BlendShapeMode" />
+ <param index="0" name="mode" type="int" enum="Mesh.BlendShapeMode" />
<description>
Sets the blend shape mode to one of [enum Mesh.BlendShapeMode].
</description>
</method>
<method name="set_lightmap_size_hint">
<return type="void" />
- <argument index="0" name="size" type="Vector2i" />
+ <param index="0" name="size" type="Vector2i" />
<description>
Sets the size hint of this mesh for lightmap-unwrapping in UV-space.
</description>
</method>
<method name="set_surface_material">
<return type="void" />
- <argument index="0" name="surface_idx" type="int" />
- <argument index="1" name="material" type="Material" />
+ <param index="0" name="surface_idx" type="int" />
+ <param index="1" name="material" type="Material" />
<description>
Sets a [Material] for a given surface. Surface will be rendered using this material.
</description>
</method>
<method name="set_surface_name">
<return type="void" />
- <argument index="0" name="surface_idx" type="int" />
- <argument index="1" name="name" type="String" />
+ <param index="0" name="surface_idx" type="int" />
+ <param index="1" name="name" type="String" />
<description>
Sets a name for a given surface.
</description>
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
index 796a80873f..56b95fc755 100644
--- a/doc/classes/Input.xml
+++ b/doc/classes/Input.xml
@@ -14,8 +14,8 @@
<methods>
<method name="action_press">
<return type="void" />
- <argument index="0" name="action" type="StringName" />
- <argument index="1" name="strength" type="float" default="1.0" />
+ <param index="0" name="action" type="StringName" />
+ <param index="1" name="strength" type="float" default="1.0" />
<description>
This will simulate pressing the specified action.
The strength can be used for non-boolean actions, it's ranged between 0 and 1 representing the intensity of the given action.
@@ -24,15 +24,15 @@
</method>
<method name="action_release">
<return type="void" />
- <argument index="0" name="action" type="StringName" />
+ <param index="0" name="action" type="StringName" />
<description>
If the specified action is already pressed, this will release it.
</description>
</method>
<method name="add_joy_mapping">
<return type="void" />
- <argument index="0" name="mapping" type="String" />
- <argument index="1" name="update_existing" type="bool" default="false" />
+ <param index="0" name="mapping" type="String" />
+ <param index="1" name="update_existing" type="bool" default="false" />
<description>
Adds a new mapping entry (in SDL2 format) to the mapping database. Optionally update already connected devices.
</description>
@@ -54,26 +54,26 @@
</method>
<method name="get_action_raw_strength" qualifiers="const">
<return type="float" />
- <argument index="0" name="action" type="StringName" />
- <argument index="1" name="exact_match" type="bool" default="false" />
+ <param index="0" name="action" type="StringName" />
+ <param index="1" name="exact_match" type="bool" default="false" />
<description>
Returns a value between 0 and 1 representing the raw intensity of the given action, ignoring the action's deadzone. In most cases, you should use [method get_action_strength] instead.
- If [code]exact_match[/code] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
+ If [param exact_match] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
</description>
</method>
<method name="get_action_strength" qualifiers="const">
<return type="float" />
- <argument index="0" name="action" type="StringName" />
- <argument index="1" name="exact_match" type="bool" default="false" />
+ <param index="0" name="action" type="StringName" />
+ <param index="1" name="exact_match" type="bool" default="false" />
<description>
Returns a value between 0 and 1 representing the intensity of the given action. In a joypad, for example, the further away the axis (analog sticks or L2, R2 triggers) is from the dead zone, the closer the value will be to 1. If the action is mapped to a control that has no axis as the keyboard, the value returned will be 0 or 1.
- If [code]exact_match[/code] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
+ If [param exact_match] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
</description>
</method>
<method name="get_axis" qualifiers="const">
<return type="float" />
- <argument index="0" name="negative_action" type="StringName" />
- <argument index="1" name="positive_action" type="StringName" />
+ <param index="0" name="negative_action" type="StringName" />
+ <param index="1" name="positive_action" type="StringName" />
<description>
Get axis input by specifying two actions, one negative and one positive.
This is a shorthand for writing [code]Input.get_action_strength("positive_action") - Input.get_action_strength("negative_action")[/code].
@@ -107,36 +107,36 @@
</method>
<method name="get_joy_axis" qualifiers="const">
<return type="float" />
- <argument index="0" name="device" type="int" />
- <argument index="1" name="axis" type="int" enum="JoyAxis" />
+ <param index="0" name="device" type="int" />
+ <param index="1" name="axis" type="int" enum="JoyAxis" />
<description>
Returns the current value of the joypad axis at given index (see [enum JoyAxis]).
</description>
</method>
<method name="get_joy_guid" qualifiers="const">
<return type="String" />
- <argument index="0" name="device" type="int" />
+ <param index="0" name="device" type="int" />
<description>
Returns a SDL2-compatible device GUID on platforms that use gamepad remapping. Returns [code]"Default Gamepad"[/code] otherwise.
</description>
</method>
<method name="get_joy_name">
<return type="String" />
- <argument index="0" name="device" type="int" />
+ <param index="0" name="device" type="int" />
<description>
Returns the name of the joypad at the specified device index.
</description>
</method>
<method name="get_joy_vibration_duration">
<return type="float" />
- <argument index="0" name="device" type="int" />
+ <param index="0" name="device" type="int" />
<description>
Returns the duration of the current vibration effect in seconds.
</description>
</method>
<method name="get_joy_vibration_strength">
<return type="Vector2" />
- <argument index="0" name="device" type="int" />
+ <param index="0" name="device" type="int" />
<description>
Returns the strength of the joypad vibration: x is the strength of the weak motor, and y is the strength of the strong motor.
</description>
@@ -162,11 +162,11 @@
</method>
<method name="get_vector" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="negative_x" type="StringName" />
- <argument index="1" name="positive_x" type="StringName" />
- <argument index="2" name="negative_y" type="StringName" />
- <argument index="3" name="positive_y" type="StringName" />
- <argument index="4" name="deadzone" type="float" default="-1.0" />
+ <param index="0" name="negative_x" type="StringName" />
+ <param index="1" name="positive_x" type="StringName" />
+ <param index="2" name="negative_y" type="StringName" />
+ <param index="3" name="positive_y" type="StringName" />
+ <param index="4" name="deadzone" type="float" default="-1.0" />
<description>
Gets an input vector by specifying four actions for the positive and negative X and Y axes.
This method is useful when getting vector input, such as from a joystick, directional pad, arrows, or WASD. The vector has its length limited to 1 and has a circular deadzone, which is useful for using vector input as movement.
@@ -175,31 +175,31 @@
</method>
<method name="is_action_just_pressed" qualifiers="const">
<return type="bool" />
- <argument index="0" name="action" type="StringName" />
- <argument index="1" name="exact_match" type="bool" default="false" />
+ <param index="0" name="action" type="StringName" />
+ <param index="1" name="exact_match" type="bool" default="false" />
<description>
Returns [code]true[/code] when the user starts pressing the action event, meaning it's [code]true[/code] only on the frame that the user pressed down the button.
This is useful for code that needs to run only once when an action is pressed, instead of every frame while it's pressed.
- If [code]exact_match[/code] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
+ If [param exact_match] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
[b]Note:[/b] Due to keyboard ghosting, [method is_action_just_pressed] may return [code]false[/code] even if one of the action's keys is pressed. See [url=$DOCS_URL/tutorials/inputs/input_examples.html#keyboard-events]Input examples[/url] in the documentation for more information.
</description>
</method>
<method name="is_action_just_released" qualifiers="const">
<return type="bool" />
- <argument index="0" name="action" type="StringName" />
- <argument index="1" name="exact_match" type="bool" default="false" />
+ <param index="0" name="action" type="StringName" />
+ <param index="1" name="exact_match" type="bool" default="false" />
<description>
Returns [code]true[/code] when the user stops pressing the action event, meaning it's [code]true[/code] only on the frame that the user released the button.
- If [code]exact_match[/code] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
+ If [param exact_match] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
</description>
</method>
<method name="is_action_pressed" qualifiers="const">
<return type="bool" />
- <argument index="0" name="action" type="StringName" />
- <argument index="1" name="exact_match" type="bool" default="false" />
+ <param index="0" name="action" type="StringName" />
+ <param index="1" name="exact_match" type="bool" default="false" />
<description>
Returns [code]true[/code] if you are pressing the action event. Note that if an action has multiple buttons assigned and more than one of them is pressed, releasing one button will release the action, even if some other button assigned to this action is still pressed.
- If [code]exact_match[/code] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
+ If [param exact_match] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
[b]Note:[/b] Due to keyboard ghosting, [method is_action_pressed] may return [code]false[/code] even if one of the action's keys is pressed. See [url=$DOCS_URL/tutorials/inputs/input_examples.html#keyboard-events]Input examples[/url] in the documentation for more information.
</description>
</method>
@@ -211,22 +211,22 @@
</method>
<method name="is_joy_button_pressed" qualifiers="const">
<return type="bool" />
- <argument index="0" name="device" type="int" />
- <argument index="1" name="button" type="int" enum="JoyButton" />
+ <param index="0" name="device" type="int" />
+ <param index="1" name="button" type="int" enum="JoyButton" />
<description>
Returns [code]true[/code] if you are pressing the joypad button (see [enum JoyButton]).
</description>
</method>
<method name="is_joy_known">
<return type="bool" />
- <argument index="0" name="device" type="int" />
+ <param index="0" name="device" type="int" />
<description>
Returns [code]true[/code] if the system knows the specified device. This means that it sets all button and axis indices. Unknown joypads are not expected to match these constants, but you can still retrieve events from them.
</description>
</method>
<method name="is_key_pressed" qualifiers="const">
<return type="bool" />
- <argument index="0" name="keycode" type="int" enum="Key" />
+ <param index="0" name="keycode" type="int" enum="Key" />
<description>
Returns [code]true[/code] if you are pressing the key in the current keyboard layout. You can pass a [enum Key] constant.
[method is_key_pressed] is only recommended over [method is_physical_key_pressed] in non-game applications. This ensures that shortcut keys behave as expected depending on the user's keyboard layout, as keyboard shortcuts are generally dependent on the keyboard layout in non-game applications. If in doubt, use [method is_physical_key_pressed].
@@ -235,14 +235,14 @@
</method>
<method name="is_mouse_button_pressed" qualifiers="const">
<return type="bool" />
- <argument index="0" name="button" type="int" enum="MouseButton" />
+ <param index="0" name="button" type="int" enum="MouseButton" />
<description>
Returns [code]true[/code] if you are pressing the mouse button specified with [enum MouseButton].
</description>
</method>
<method name="is_physical_key_pressed" qualifiers="const">
<return type="bool" />
- <argument index="0" name="keycode" type="int" enum="Key" />
+ <param index="0" name="keycode" type="int" enum="Key" />
<description>
Returns [code]true[/code] if you are pressing the key in the physical location on the 101/102-key US QWERTY keyboard. You can pass a [enum Key] constant.
[method is_physical_key_pressed] is recommended over [method is_key_pressed] for in-game actions, as it will make [kbd]W[/kbd]/[kbd]A[/kbd]/[kbd]S[/kbd]/[kbd]D[/kbd] layouts work regardless of the user's keyboard layout. [method is_physical_key_pressed] will also ensure that the top row number keys work on any keyboard layout. If in doubt, use [method is_physical_key_pressed].
@@ -251,7 +251,7 @@
</method>
<method name="parse_input_event">
<return type="void" />
- <argument index="0" name="event" type="InputEvent" />
+ <param index="0" name="event" type="InputEvent" />
<description>
Feeds an [InputEvent] to the game. Can be used to artificially trigger input events from code. Also generates [method Node._input] calls.
Example:
@@ -273,14 +273,14 @@
</method>
<method name="remove_joy_mapping">
<return type="void" />
- <argument index="0" name="guid" type="String" />
+ <param index="0" name="guid" type="String" />
<description>
Removes all mappings from the internal database that match the given GUID.
</description>
</method>
<method name="set_accelerometer">
<return type="void" />
- <argument index="0" name="value" type="Vector3" />
+ <param index="0" name="value" type="Vector3" />
<description>
Sets the acceleration value of the accelerometer sensor. Can be used for debugging on devices without a hardware sensor, for example in an editor on a PC.
[b]Note:[/b] This value can be immediately overwritten by the hardware sensor value on Android and iOS.
@@ -288,20 +288,20 @@
</method>
<method name="set_custom_mouse_cursor">
<return type="void" />
- <argument index="0" name="image" type="Resource" />
- <argument index="1" name="shape" type="int" enum="Input.CursorShape" default="0" />
- <argument index="2" name="hotspot" type="Vector2" default="Vector2(0, 0)" />
+ <param index="0" name="image" type="Resource" />
+ <param index="1" name="shape" type="int" enum="Input.CursorShape" default="0" />
+ <param index="2" name="hotspot" type="Vector2" default="Vector2(0, 0)" />
<description>
Sets a custom mouse cursor image, which is only visible inside the game window. The hotspot can also be specified. Passing [code]null[/code] to the image parameter resets to the system cursor. See [enum CursorShape] for the list of shapes.
- [code]image[/code]'s size must be lower than 256×256.
- [code]hotspot[/code] must be within [code]image[/code]'s size.
+ [param image]'s size must be lower than 256×256.
+ [param hotspot] must be within [param image]'s size.
[b]Note:[/b] [AnimatedTexture]s aren't supported as custom mouse cursors. If using an [AnimatedTexture], only the first frame will be displayed.
[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or [b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] compression mode can't be used for custom cursors.
</description>
</method>
<method name="set_default_cursor_shape">
<return type="void" />
- <argument index="0" name="shape" type="int" enum="Input.CursorShape" default="0" />
+ <param index="0" name="shape" type="int" enum="Input.CursorShape" default="0" />
<description>
Sets the default cursor shape to be used in the viewport instead of [constant CURSOR_ARROW].
[b]Note:[/b] If you want to change the default cursor shape for [Control]'s nodes, use [member Control.mouse_default_cursor_shape] instead.
@@ -310,7 +310,7 @@
</method>
<method name="set_gravity">
<return type="void" />
- <argument index="0" name="value" type="Vector3" />
+ <param index="0" name="value" type="Vector3" />
<description>
Sets the gravity value of the accelerometer sensor. Can be used for debugging on devices without a hardware sensor, for example in an editor on a PC.
[b]Note:[/b] This value can be immediately overwritten by the hardware sensor value on Android and iOS.
@@ -318,7 +318,7 @@
</method>
<method name="set_gyroscope">
<return type="void" />
- <argument index="0" name="value" type="Vector3" />
+ <param index="0" name="value" type="Vector3" />
<description>
Sets the value of the rotation rate of the gyroscope sensor. Can be used for debugging on devices without a hardware sensor, for example in an editor on a PC.
[b]Note:[/b] This value can be immediately overwritten by the hardware sensor value on Android and iOS.
@@ -326,7 +326,7 @@
</method>
<method name="set_magnetometer">
<return type="void" />
- <argument index="0" name="value" type="Vector3" />
+ <param index="0" name="value" type="Vector3" />
<description>
Sets the value of the magnetic field of the magnetometer sensor. Can be used for debugging on devices without a hardware sensor, for example in an editor on a PC.
[b]Note:[/b] This value can be immediately overwritten by the hardware sensor value on Android and iOS.
@@ -334,28 +334,28 @@
</method>
<method name="start_joy_vibration">
<return type="void" />
- <argument index="0" name="device" type="int" />
- <argument index="1" name="weak_magnitude" type="float" />
- <argument index="2" name="strong_magnitude" type="float" />
- <argument index="3" name="duration" type="float" default="0" />
+ <param index="0" name="device" type="int" />
+ <param index="1" name="weak_magnitude" type="float" />
+ <param index="2" name="strong_magnitude" type="float" />
+ <param index="3" name="duration" type="float" default="0" />
<description>
- Starts to vibrate the joypad. Joypads usually come with two rumble motors, a strong and a weak one. [code]weak_magnitude[/code] is the strength of the weak motor (between 0 and 1) and [code]strong_magnitude[/code] is the strength of the strong motor (between 0 and 1). [code]duration[/code] is the duration of the effect in seconds (a duration of 0 will try to play the vibration indefinitely).
+ Starts to vibrate the joypad. Joypads usually come with two rumble motors, a strong and a weak one. [param weak_magnitude] is the strength of the weak motor (between 0 and 1) and [param strong_magnitude] is the strength of the strong motor (between 0 and 1). [param duration] is the duration of the effect in seconds (a duration of 0 will try to play the vibration indefinitely).
[b]Note:[/b] Not every hardware is compatible with long effect durations; it is recommended to restart an effect if it has to be played for more than a few seconds.
</description>
</method>
<method name="stop_joy_vibration">
<return type="void" />
- <argument index="0" name="device" type="int" />
+ <param index="0" name="device" type="int" />
<description>
Stops the vibration of the joypad.
</description>
</method>
<method name="vibrate_handheld">
<return type="void" />
- <argument index="0" name="duration_ms" type="int" default="500" />
+ <param index="0" name="duration_ms" type="int" default="500" />
<description>
Vibrate handheld devices.
- [b]Note:[/b] This method is implemented on Android, iOS, and HTML5.
+ [b]Note:[/b] This method is implemented on Android, iOS, and Web.
[b]Note:[/b] For Android, it requires enabling the [code]VIBRATE[/code] permission in the export preset.
[b]Note:[/b] For iOS, specifying the duration is supported in iOS 13 and later.
[b]Note:[/b] Some web browsers such as Safari and Firefox for Android do not support this method.
@@ -363,7 +363,7 @@
</method>
<method name="warp_mouse">
<return type="void" />
- <argument index="0" name="position" type="Vector2" />
+ <param index="0" name="position" type="Vector2" />
<description>
Sets the mouse position to the specified vector, provided in pixels and relative to an origin at the upper left corner of the currently focused Window Manager game window.
Mouse position is clipped to the limits of the screen resolution, or to the limits of the game window if [enum MouseMode] is set to [code]MOUSE_MODE_CONFINED[/code] or [code]MOUSE_MODE_CONFINED_HIDDEN[/code].
@@ -382,8 +382,8 @@
</members>
<signals>
<signal name="joy_connection_changed">
- <argument index="0" name="device" type="int" />
- <argument index="1" name="connected" type="bool" />
+ <param index="0" name="device" type="int" />
+ <param index="1" name="connected" type="bool" />
<description>
Emitted when a joypad device has been connected or disconnected.
</description>
diff --git a/doc/classes/InputEvent.xml b/doc/classes/InputEvent.xml
index 230ad04b33..043ccdca36 100644
--- a/doc/classes/InputEvent.xml
+++ b/doc/classes/InputEvent.xml
@@ -15,7 +15,7 @@
<methods>
<method name="accumulate">
<return type="bool" />
- <argument index="0" name="with_event" type="InputEvent" />
+ <param index="0" name="with_event" type="InputEvent" />
<description>
Returns [code]true[/code] if the given input event and this input event can be added together (only for events of type [InputEventMouseMotion]).
The given input event's position, global position and speed will be copied. The resulting [code]relative[/code] is a sum of both events. Both events' modifiers have to be identical.
@@ -29,40 +29,40 @@
</method>
<method name="get_action_strength" qualifiers="const">
<return type="float" />
- <argument index="0" name="action" type="StringName" />
- <argument index="1" name="exact_match" type="bool" default="false" />
+ <param index="0" name="action" type="StringName" />
+ <param index="1" name="exact_match" type="bool" default="false" />
<description>
Returns a value between 0.0 and 1.0 depending on the given actions' state. Useful for getting the value of events of type [InputEventJoypadMotion].
- If [code]exact_match[/code] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
+ If [param exact_match] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
</description>
</method>
<method name="is_action" qualifiers="const">
<return type="bool" />
- <argument index="0" name="action" type="StringName" />
- <argument index="1" name="exact_match" type="bool" default="false" />
+ <param index="0" name="action" type="StringName" />
+ <param index="1" name="exact_match" type="bool" default="false" />
<description>
Returns [code]true[/code] if this input event matches a pre-defined action of any type.
- If [code]exact_match[/code] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
+ If [param exact_match] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
</description>
</method>
<method name="is_action_pressed" qualifiers="const">
<return type="bool" />
- <argument index="0" name="action" type="StringName" />
- <argument index="1" name="allow_echo" type="bool" default="false" />
- <argument index="2" name="exact_match" type="bool" default="false" />
+ <param index="0" name="action" type="StringName" />
+ <param index="1" name="allow_echo" type="bool" default="false" />
+ <param index="2" name="exact_match" type="bool" default="false" />
<description>
- Returns [code]true[/code] if the given action is being pressed (and is not an echo event for [InputEventKey] events, unless [code]allow_echo[/code] is [code]true[/code]). Not relevant for events of type [InputEventMouseMotion] or [InputEventScreenDrag].
- If [code]exact_match[/code] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
+ Returns [code]true[/code] if the given action is being pressed (and is not an echo event for [InputEventKey] events, unless [param allow_echo] is [code]true[/code]). Not relevant for events of type [InputEventMouseMotion] or [InputEventScreenDrag].
+ If [param exact_match] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
[b]Note:[/b] Due to keyboard ghosting, [method is_action_pressed] may return [code]false[/code] even if one of the action's keys is pressed. See [url=$DOCS_URL/tutorials/inputs/input_examples.html#keyboard-events]Input examples[/url] in the documentation for more information.
</description>
</method>
<method name="is_action_released" qualifiers="const">
<return type="bool" />
- <argument index="0" name="action" type="StringName" />
- <argument index="1" name="exact_match" type="bool" default="false" />
+ <param index="0" name="action" type="StringName" />
+ <param index="1" name="exact_match" type="bool" default="false" />
<description>
Returns [code]true[/code] if the given action is released (i.e. not pressed). Not relevant for events of type [InputEventMouseMotion] or [InputEventScreenDrag].
- If [code]exact_match[/code] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
+ If [param exact_match] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
</description>
</method>
<method name="is_action_type" qualifiers="const">
@@ -79,11 +79,11 @@
</method>
<method name="is_match" qualifiers="const">
<return type="bool" />
- <argument index="0" name="event" type="InputEvent" />
- <argument index="1" name="exact_match" type="bool" default="true" />
+ <param index="0" name="event" type="InputEvent" />
+ <param index="1" name="exact_match" type="bool" default="true" />
<description>
- Returns [code]true[/code] if the specified [code]event[/code] matches this event. Only valid for action events i.e key ([InputEventKey]), button ([InputEventMouseButton] or [InputEventJoypadButton]), axis [InputEventJoypadMotion] or action ([InputEventAction]) events.
- If [code]exact_match[/code] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
+ Returns [code]true[/code] if the specified [param event] matches this event. Only valid for action events i.e key ([InputEventKey]), button ([InputEventMouseButton] or [InputEventJoypadButton]), axis [InputEventJoypadMotion] or action ([InputEventAction]) events.
+ If [param exact_match] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
</description>
</method>
<method name="is_pressed" qualifiers="const">
@@ -95,10 +95,10 @@
</method>
<method name="xformed_by" qualifiers="const">
<return type="InputEvent" />
- <argument index="0" name="xform" type="Transform2D" />
- <argument index="1" name="local_ofs" type="Vector2" default="Vector2(0, 0)" />
+ <param index="0" name="xform" type="Transform2D" />
+ <param index="1" name="local_ofs" type="Vector2" default="Vector2(0, 0)" />
<description>
- Returns a copy of the given input event which has been offset by [code]local_ofs[/code] and transformed by [code]xform[/code]. Relevant for events of type [InputEventMouseButton], [InputEventMouseMotion], [InputEventScreenTouch], [InputEventScreenDrag], [InputEventMagnifyGesture] and [InputEventPanGesture].
+ Returns a copy of the given input event which has been offset by [param local_ofs] and transformed by [param xform]. Relevant for events of type [InputEventMouseButton], [InputEventMouseMotion], [InputEventScreenTouch], [InputEventScreenDrag], [InputEventMagnifyGesture] and [InputEventPanGesture].
</description>
</method>
</methods>
diff --git a/doc/classes/InputEventWithModifiers.xml b/doc/classes/InputEventWithModifiers.xml
index ff2e6409c9..b4a276f6ac 100644
--- a/doc/classes/InputEventWithModifiers.xml
+++ b/doc/classes/InputEventWithModifiers.xml
@@ -14,13 +14,15 @@
State of the [kbd]Alt[/kbd] modifier.
</member>
<member name="command_pressed" type="bool" setter="set_command_pressed" getter="is_command_pressed" default="false">
- State of the [kbd]Cmd[/kbd] modifier.
+ State of the [kbd]Cmd[/kbd] modifier. On macOS, this is equivalent to [member meta_pressed]. On other platforms, this is equivalent to [member ctrl_pressed].
+ This modifier should be preferred to [member ctrl_pressed] or [member meta_pressed] for system shortcuts, as it maintains better cross-platform compatibility.
</member>
<member name="ctrl_pressed" type="bool" setter="set_ctrl_pressed" getter="is_ctrl_pressed" default="false">
State of the [kbd]Ctrl[/kbd] modifier.
</member>
<member name="meta_pressed" type="bool" setter="set_meta_pressed" getter="is_meta_pressed" default="false">
- State of the [kbd]Meta[/kbd] modifier.
+ State of the [kbd]Meta[/kbd] modifier. On Windows and Linux, this represents the Windows key (sometimes called "meta" or "super" on Linux). On macOS, this represents the Command key, and is equivalent to [member command_pressed].
+ For better cross-system compatibility, use [member command_pressed] instead.
</member>
<member name="shift_pressed" type="bool" setter="set_shift_pressed" getter="is_shift_pressed" default="false">
State of the [kbd]Shift[/kbd] modifier.
diff --git a/doc/classes/InputMap.xml b/doc/classes/InputMap.xml
index eb708432b4..1d7d54f681 100644
--- a/doc/classes/InputMap.xml
+++ b/doc/classes/InputMap.xml
@@ -12,37 +12,37 @@
<methods>
<method name="action_add_event">
<return type="void" />
- <argument index="0" name="action" type="StringName" />
- <argument index="1" name="event" type="InputEvent" />
+ <param index="0" name="action" type="StringName" />
+ <param index="1" name="event" type="InputEvent" />
<description>
Adds an [InputEvent] to an action. This [InputEvent] will trigger the action.
</description>
</method>
<method name="action_erase_event">
<return type="void" />
- <argument index="0" name="action" type="StringName" />
- <argument index="1" name="event" type="InputEvent" />
+ <param index="0" name="action" type="StringName" />
+ <param index="1" name="event" type="InputEvent" />
<description>
Removes an [InputEvent] from an action.
</description>
</method>
<method name="action_erase_events">
<return type="void" />
- <argument index="0" name="action" type="StringName" />
+ <param index="0" name="action" type="StringName" />
<description>
Removes all events from an action.
</description>
</method>
<method name="action_get_deadzone">
<return type="float" />
- <argument index="0" name="action" type="StringName" />
+ <param index="0" name="action" type="StringName" />
<description>
Returns a deadzone value for the action.
</description>
</method>
<method name="action_get_events">
- <return type="Array" />
- <argument index="0" name="action" type="StringName" />
+ <return type="InputEvent[]" />
+ <param index="0" name="action" type="StringName" />
<description>
Returns an array of [InputEvent]s associated with a given action.
[b]Note:[/b] When used in the editor (e.g. a tool script or [EditorPlugin]), this method will return events for the editor action. If you want to access your project's input binds from the editor, read the [code]input/*[/code] settings from [ProjectSettings].
@@ -50,55 +50,55 @@
</method>
<method name="action_has_event">
<return type="bool" />
- <argument index="0" name="action" type="StringName" />
- <argument index="1" name="event" type="InputEvent" />
+ <param index="0" name="action" type="StringName" />
+ <param index="1" name="event" type="InputEvent" />
<description>
Returns [code]true[/code] if the action has the given [InputEvent] associated with it.
</description>
</method>
<method name="action_set_deadzone">
<return type="void" />
- <argument index="0" name="action" type="StringName" />
- <argument index="1" name="deadzone" type="float" />
+ <param index="0" name="action" type="StringName" />
+ <param index="1" name="deadzone" type="float" />
<description>
Sets a deadzone value for the action.
</description>
</method>
<method name="add_action">
<return type="void" />
- <argument index="0" name="action" type="StringName" />
- <argument index="1" name="deadzone" type="float" default="0.5" />
+ <param index="0" name="action" type="StringName" />
+ <param index="1" name="deadzone" type="float" default="0.5" />
<description>
- Adds an empty action to the [InputMap] with a configurable [code]deadzone[/code].
+ Adds an empty action to the [InputMap] with a configurable [param deadzone].
An [InputEvent] can then be added to this action with [method action_add_event].
</description>
</method>
<method name="erase_action">
<return type="void" />
- <argument index="0" name="action" type="StringName" />
+ <param index="0" name="action" type="StringName" />
<description>
Removes an action from the [InputMap].
</description>
</method>
<method name="event_is_action" qualifiers="const">
<return type="bool" />
- <argument index="0" name="event" type="InputEvent" />
- <argument index="1" name="action" type="StringName" />
- <argument index="2" name="exact_match" type="bool" default="false" />
+ <param index="0" name="event" type="InputEvent" />
+ <param index="1" name="action" type="StringName" />
+ <param index="2" name="exact_match" type="bool" default="false" />
<description>
Returns [code]true[/code] if the given event is part of an existing action. This method ignores keyboard modifiers if the given [InputEvent] is not pressed (for proper release detection). See [method action_has_event] if you don't want this behavior.
- If [code]exact_match[/code] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
+ If [param exact_match] is [code]false[/code], it ignores additional input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events.
</description>
</method>
<method name="get_actions">
- <return type="Array" />
+ <return type="StringName[]" />
<description>
Returns an array of all actions in the [InputMap].
</description>
</method>
<method name="has_action" qualifiers="const">
<return type="bool" />
- <argument index="0" name="action" type="StringName" />
+ <param index="0" name="action" type="StringName" />
<description>
Returns [code]true[/code] if the [InputMap] has a registered action with the given name.
</description>
diff --git a/doc/classes/InstancePlaceholder.xml b/doc/classes/InstancePlaceholder.xml
index d22028d478..c62d786d8f 100644
--- a/doc/classes/InstancePlaceholder.xml
+++ b/doc/classes/InstancePlaceholder.xml
@@ -12,10 +12,11 @@
<methods>
<method name="create_instance">
<return type="Node" />
- <argument index="0" name="replace" type="bool" default="false" />
- <argument index="1" name="custom_scene" type="PackedScene" default="null" />
+ <param index="0" name="replace" type="bool" default="false" />
+ <param index="1" name="custom_scene" type="PackedScene" default="null" />
<description>
- Not thread-safe. Use [method Object.call_deferred] if calling from a thread.
+ Call this method to actually load in the node. The created node will be placed as a sibling [i]above[/i] the [InstancePlaceholder] in the scene tree. The [Node]'s reference is also returned for convenience.
+ [b]Note:[/b] [method create_instance] is not thread-safe. Use [method Object.call_deferred] if calling from a thread.
</description>
</method>
<method name="get_instance_path" qualifiers="const">
@@ -26,8 +27,10 @@
</method>
<method name="get_stored_values">
<return type="Dictionary" />
- <argument index="0" name="with_order" type="bool" default="false" />
+ <param index="0" name="with_order" type="bool" default="false" />
<description>
+ Returns the list of properties that will be applied to the node when [method create_instance] is called.
+ If [param with_order] is [code]true[/code], a key named [code].order[/code] (note the leading period) is added to the dictionary. This [code].order[/code] key is an [Array] of [String] property names specifying the order in which properties will be applied (with index 0 being the first).
</description>
</method>
</methods>
diff --git a/doc/classes/ItemList.xml b/doc/classes/ItemList.xml
index 15c97b0838..75a0e1cef7 100644
--- a/doc/classes/ItemList.xml
+++ b/doc/classes/ItemList.xml
@@ -15,20 +15,20 @@
<methods>
<method name="add_icon_item">
<return type="int" />
- <argument index="0" name="icon" type="Texture2D" />
- <argument index="1" name="selectable" type="bool" default="true" />
+ <param index="0" name="icon" type="Texture2D" />
+ <param index="1" name="selectable" type="bool" default="true" />
<description>
Adds an item to the item list with no text, only an icon. Returns the index of an added item.
</description>
</method>
<method name="add_item">
<return type="int" />
- <argument index="0" name="text" type="String" />
- <argument index="1" name="icon" type="Texture2D" default="null" />
- <argument index="2" name="selectable" type="bool" default="true" />
+ <param index="0" name="text" type="String" />
+ <param index="1" name="icon" type="Texture2D" default="null" />
+ <param index="2" name="selectable" type="bool" default="true" />
<description>
Adds an item to the item list with specified text. Returns the index of an added item.
- Specify an [code]icon[/code], or use [code]null[/code] as the [code]icon[/code] for a list item with no icon.
+ Specify an [param icon], or use [code]null[/code] as the [param icon] for a list item with no icon.
If selectable is [code]true[/code], the list item will be selectable.
</description>
</method>
@@ -40,7 +40,7 @@
</method>
<method name="deselect">
<return type="void" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Ensures the item associated with the specified index is not selected.
</description>
@@ -59,79 +59,79 @@
</method>
<method name="get_item_at_position" qualifiers="const">
<return type="int" />
- <argument index="0" name="position" type="Vector2" />
- <argument index="1" name="exact" type="bool" default="false" />
+ <param index="0" name="position" type="Vector2" />
+ <param index="1" name="exact" type="bool" default="false" />
<description>
- Returns the item index at the given [code]position[/code].
- When there is no item at that point, -1 will be returned if [code]exact[/code] is [code]true[/code], and the closest item index will be returned otherwise.
+ Returns the item index at the given [param position].
+ When there is no item at that point, -1 will be returned if [param exact] is [code]true[/code], and the closest item index will be returned otherwise.
</description>
</method>
<method name="get_item_custom_bg_color" qualifiers="const">
<return type="Color" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the custom background color of the item specified by [code]idx[/code] index.
+ Returns the custom background color of the item specified by [param idx] index.
</description>
</method>
<method name="get_item_custom_fg_color" qualifiers="const">
<return type="Color" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the custom foreground color of the item specified by [code]idx[/code] index.
+ Returns the custom foreground color of the item specified by [param idx] index.
</description>
</method>
<method name="get_item_icon" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns the icon associated with the specified index.
</description>
</method>
<method name="get_item_icon_modulate" qualifiers="const">
<return type="Color" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns a [Color] modulating item's icon at the specified index.
</description>
</method>
<method name="get_item_icon_region" qualifiers="const">
<return type="Rect2" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns the region of item's icon used. The whole icon will be used if the region has no area.
</description>
</method>
<method name="get_item_language" qualifiers="const">
<return type="String" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns item's text language code.
</description>
</method>
<method name="get_item_metadata" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns the metadata value of the specified index.
</description>
</method>
<method name="get_item_text" qualifiers="const">
<return type="String" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns the text associated with the specified index.
</description>
</method>
<method name="get_item_text_direction" qualifiers="const">
<return type="int" enum="Control.TextDirection" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns item's text base writing direction.
</description>
</method>
<method name="get_item_tooltip" qualifiers="const">
<return type="String" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns the tooltip hint associated with the specified index.
</description>
@@ -157,58 +157,58 @@
</method>
<method name="is_item_disabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns [code]true[/code] if the item at the specified index is disabled.
</description>
</method>
<method name="is_item_icon_transposed" qualifiers="const">
<return type="bool" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns [code]true[/code] if the item icon will be drawn transposed, i.e. the X and Y axes are swapped.
</description>
</method>
<method name="is_item_selectable" qualifiers="const">
<return type="bool" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns [code]true[/code] if the item at the specified index is selectable.
</description>
</method>
<method name="is_item_tooltip_enabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns [code]true[/code] if the tooltip is enabled for specified item index.
</description>
</method>
<method name="is_selected" qualifiers="const">
<return type="bool" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns [code]true[/code] if the item at the specified index is currently selected.
</description>
</method>
<method name="move_item">
<return type="void" />
- <argument index="0" name="from_idx" type="int" />
- <argument index="1" name="to_idx" type="int" />
+ <param index="0" name="from_idx" type="int" />
+ <param index="1" name="to_idx" type="int" />
<description>
- Moves item from index [code]from_idx[/code] to [code]to_idx[/code].
+ Moves item from index [param from_idx] to [param to_idx].
</description>
</method>
<method name="remove_item">
<return type="void" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Removes the item specified by [code]idx[/code] index from the list.
+ Removes the item specified by [param idx] index from the list.
</description>
</method>
<method name="select">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="single" type="bool" default="true" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="single" type="bool" default="true" />
<description>
Select the item at the specified index.
[b]Note:[/b] This method does not trigger the item selection signal.
@@ -216,24 +216,24 @@
</method>
<method name="set_item_custom_bg_color">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="custom_bg_color" type="Color" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="custom_bg_color" type="Color" />
<description>
- Sets the background color of the item specified by [code]idx[/code] index to the specified [Color].
+ Sets the background color of the item specified by [param idx] index to the specified [Color].
</description>
</method>
<method name="set_item_custom_fg_color">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="custom_fg_color" type="Color" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="custom_fg_color" type="Color" />
<description>
- Sets the foreground color of the item specified by [code]idx[/code] index to the specified [Color].
+ Sets the foreground color of the item specified by [param idx] index to the specified [Color].
</description>
</method>
<method name="set_item_disabled">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="disabled" type="bool" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="disabled" type="bool" />
<description>
Disables (or enables) the item at the specified index.
Disabled items cannot be selected and do not trigger activation signals (when double-clicking or pressing [kbd]Enter[/kbd]).
@@ -241,88 +241,88 @@
</method>
<method name="set_item_icon">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="icon" type="Texture2D" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="icon" type="Texture2D" />
<description>
Sets (or replaces) the icon's [Texture2D] associated with the specified index.
</description>
</method>
<method name="set_item_icon_modulate">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="modulate" type="Color" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="modulate" type="Color" />
<description>
Sets a modulating [Color] of the item associated with the specified index.
</description>
</method>
<method name="set_item_icon_region">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="rect" type="Rect2" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="rect" type="Rect2" />
<description>
Sets the region of item's icon used. The whole icon will be used if the region has no area.
</description>
</method>
<method name="set_item_icon_transposed">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="transposed" type="bool" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="transposed" type="bool" />
<description>
Sets whether the item icon will be drawn transposed.
</description>
</method>
<method name="set_item_language">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="language" type="String" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="language" type="String" />
<description>
Sets language code of item's text used for line-breaking and text shaping algorithms, if left empty current locale is used instead.
</description>
</method>
<method name="set_item_metadata">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="metadata" type="Variant" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="metadata" type="Variant" />
<description>
Sets a value (of any type) to be stored with the item associated with the specified index.
</description>
</method>
<method name="set_item_selectable">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="selectable" type="bool" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="selectable" type="bool" />
<description>
Allows or disallows selection of the item associated with the specified index.
</description>
</method>
<method name="set_item_text">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="text" type="String" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="text" type="String" />
<description>
Sets text of the item associated with the specified index.
</description>
</method>
<method name="set_item_text_direction">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="direction" type="int" enum="Control.TextDirection" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="direction" type="int" enum="Control.TextDirection" />
<description>
Sets item's text base writing direction.
</description>
</method>
<method name="set_item_tooltip">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="tooltip" type="String" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="tooltip" type="String" />
<description>
Sets the tooltip hint for the item associated with the specified index.
</description>
</method>
<method name="set_item_tooltip_enabled">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="enable" type="bool" />
<description>
Sets whether the tooltip hint is enabled for specified item index.
</description>
@@ -385,37 +385,37 @@
</members>
<signals>
<signal name="empty_clicked">
- <argument index="0" name="at_position" type="Vector2" />
- <argument index="1" name="mouse_button_index" type="int" />
+ <param index="0" name="at_position" type="Vector2" />
+ <param index="1" name="mouse_button_index" type="int" />
<description>
Triggered when any mouse click is issued within the rect of the list but on empty space.
</description>
</signal>
<signal name="item_activated">
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Triggered when specified list item is activated via double-clicking or by pressing [kbd]Enter[/kbd].
</description>
</signal>
<signal name="item_clicked">
- <argument index="0" name="index" type="int" />
- <argument index="1" name="at_position" type="Vector2" />
- <argument index="2" name="mouse_button_index" type="int" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="at_position" type="Vector2" />
+ <param index="2" name="mouse_button_index" type="int" />
<description>
Triggered when specified list item has been clicked with any mouse button.
The click position is also provided to allow appropriate popup of context menus at the correct location.
</description>
</signal>
<signal name="item_selected">
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Triggered when specified item has been selected.
[member allow_reselect] must be enabled to reselect an item.
</description>
</signal>
<signal name="multi_selected">
- <argument index="0" name="index" type="int" />
- <argument index="1" name="selected" type="bool" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="selected" type="bool" />
<description>
Triggered when a multiple selection is altered on a list allowing multiple selection.
</description>
@@ -445,7 +445,7 @@
<theme_item name="font_selected_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
Text [Color] used when the item is selected.
</theme_item>
- <theme_item name="guide_color" data_type="color" type="Color" default="Color(0, 0, 0, 0.1)">
+ <theme_item name="guide_color" data_type="color" type="Color" default="Color(0.7, 0.7, 0.7, 0.25)">
[Color] of the guideline. The guideline is a line drawn between each row of items.
</theme_item>
<theme_item name="h_separation" data_type="constant" type="int" default="4">
diff --git a/doc/classes/JSON.xml b/doc/classes/JSON.xml
index 9650701c49..46e46cc164 100644
--- a/doc/classes/JSON.xml
+++ b/doc/classes/JSON.xml
@@ -10,8 +10,7 @@
[b]Example[/b]
[codeblock]
var data_to_send = ["a", "b", "c"]
- var json = JSON.new()
- var json_string = json.stringify(data_to_send)
+ var json_string = JSON.stringify(data_to_send)
# Save data
# ...
# Retrieve data
@@ -25,6 +24,10 @@
else:
print("JSON Parse Error: ", json.get_error_message(), " in ", json_string, " at line ", json.get_error_line())
[/codeblock]
+ Alternatively, you can parse string using the static [method parse_string] method, but it doesn't allow to handle errors.
+ [codeblock]
+ var data = JSON.parse_string(json_string) # Returns null if parsing failed.
+ [/codeblock]
</description>
<tutorials>
</tutorials>
@@ -50,23 +53,31 @@
</method>
<method name="parse">
<return type="int" enum="Error" />
- <argument index="0" name="json_string" type="String" />
+ <param index="0" name="json_string" type="String" />
<description>
- Attempts to parse the [code]json_string[/code] provided.
+ Attempts to parse the [param json_string] provided.
Returns an [enum Error]. If the parse was successful, it returns [code]OK[/code] and the result can be retrieved using [method get_data]. If unsuccessful, use [method get_error_line] and [method get_error_message] for identifying the source of the failure.
+ Non-static variant of [method parse_string], if you want custom error handling.
+ </description>
+ </method>
+ <method name="parse_string" qualifiers="static">
+ <return type="Variant" />
+ <param index="0" name="json_string" type="String" />
+ <description>
+ Attempts to parse the [param json_string] provided and returns the parsed data. Returns [code]null[/code] if parse failed.
</description>
</method>
- <method name="stringify">
+ <method name="stringify" qualifiers="static">
<return type="String" />
- <argument index="0" name="data" type="Variant" />
- <argument index="1" name="indent" type="String" default="&quot;&quot;" />
- <argument index="2" name="sort_keys" type="bool" default="true" />
- <argument index="3" name="full_precision" type="bool" default="false" />
+ <param index="0" name="data" type="Variant" />
+ <param index="1" name="indent" type="String" default="&quot;&quot;" />
+ <param index="2" name="sort_keys" type="bool" default="true" />
+ <param index="3" name="full_precision" type="bool" default="false" />
<description>
Converts a [Variant] var to JSON text and returns the result. Useful for serializing data to store or send over the network.
[b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, converting a Variant to JSON text will convert all numerical values to [float] types.
- [b]Note:[/b] If [code]full_precision[/code] is true, when stringifying floats, the unreliable digits are stringified in addition to the reliable digits to guarantee exact decoding.
- The [code]indent[/code] parameter controls if and how something is indented, the string used for this parameter will be used where there should be an indent in the output, even spaces like [code]" "[/code] will work. [code]\t[/code] and [code]\n[/code] can also be used for a tab indent, or to make a newline for each indent respectively.
+ [b]Note:[/b] If [param full_precision] is [code]true[/code], when stringifying floats, the unreliable digits are stringified in addition to the reliable digits to guarantee exact decoding.
+ The [param indent] parameter controls if and how something is indented, the string used for this parameter will be used where there should be an indent in the output, even spaces like [code]" "[/code] will work. [code]\t[/code] and [code]\n[/code] can also be used for a tab indent, or to make a newline for each indent respectively.
[b]Example output:[/b]
[codeblock]
## JSON.stringify(my_dictionary)
diff --git a/doc/classes/JSONRPC.xml b/doc/classes/JSONRPC.xml
index cfe39d38a7..8af4ed1f26 100644
--- a/doc/classes/JSONRPC.xml
+++ b/doc/classes/JSONRPC.xml
@@ -11,68 +11,68 @@
<methods>
<method name="make_notification">
<return type="Dictionary" />
- <argument index="0" name="method" type="String" />
- <argument index="1" name="params" type="Variant" />
+ <param index="0" name="method" type="String" />
+ <param index="1" name="params" type="Variant" />
<description>
Returns a dictionary in the form of a JSON-RPC notification. Notifications are one-shot messages which do not expect a response.
- - [code]method[/code]: Name of the method being called.
- - [code]params[/code]: An array or dictionary of parameters being passed to the method.
+ - [param method]: Name of the method being called.
+ - [param params]: An array or dictionary of parameters being passed to the method.
</description>
</method>
<method name="make_request">
<return type="Dictionary" />
- <argument index="0" name="method" type="String" />
- <argument index="1" name="params" type="Variant" />
- <argument index="2" name="id" type="Variant" />
+ <param index="0" name="method" type="String" />
+ <param index="1" name="params" type="Variant" />
+ <param index="2" name="id" type="Variant" />
<description>
Returns a dictionary in the form of a JSON-RPC request. Requests are sent to a server with the expectation of a response. The ID field is used for the server to specify which exact request it is responding to.
- - [code]method[/code]: Name of the method being called.
- - [code]params[/code]: An array or dictionary of parameters being passed to the method.
- - [code]id[/code]: Uniquely identifies this request. The server is expected to send a response with the same ID.
+ - [param method]: Name of the method being called.
+ - [param params]: An array or dictionary of parameters being passed to the method.
+ - [param id]: Uniquely identifies this request. The server is expected to send a response with the same ID.
</description>
</method>
<method name="make_response">
<return type="Dictionary" />
- <argument index="0" name="result" type="Variant" />
- <argument index="1" name="id" type="Variant" />
+ <param index="0" name="result" type="Variant" />
+ <param index="1" name="id" type="Variant" />
<description>
When a server has received and processed a request, it is expected to send a response. If you did not want a response then you need to have sent a Notification instead.
- - [code]result[/code]: The return value of the function which was called.
- - [code]id[/code]: The ID of the request this response is targeted to.
+ - [param result]: The return value of the function which was called.
+ - [param id]: The ID of the request this response is targeted to.
</description>
</method>
<method name="make_response_error" qualifiers="const">
<return type="Dictionary" />
- <argument index="0" name="code" type="int" />
- <argument index="1" name="message" type="String" />
- <argument index="2" name="id" type="Variant" default="null" />
+ <param index="0" name="code" type="int" />
+ <param index="1" name="message" type="String" />
+ <param index="2" name="id" type="Variant" default="null" />
<description>
Creates a response which indicates a previous reply has failed in some way.
- - [code]code[/code]: The error code corresponding to what kind of error this is. See the [enum ErrorCode] constants.
- - [code]message[/code]: A custom message about this error.
- - [code]id[/code]: The request this error is a response to.
+ - [param code]: The error code corresponding to what kind of error this is. See the [enum ErrorCode] constants.
+ - [param message]: A custom message about this error.
+ - [param id]: The request this error is a response to.
</description>
</method>
<method name="process_action">
<return type="Variant" />
- <argument index="0" name="action" type="Variant" />
- <argument index="1" name="recurse" type="bool" default="false" />
+ <param index="0" name="action" type="Variant" />
+ <param index="1" name="recurse" type="bool" default="false" />
<description>
Given a Dictionary which takes the form of a JSON-RPC request: unpack the request and run it. Methods are resolved by looking at the field called "method" and looking for an equivalently named function in the JSONRPC object. If one is found that method is called.
To add new supported methods extend the JSONRPC class and call [method process_action] on your subclass.
- [code]action[/code]: The action to be run, as a Dictionary in the form of a JSON-RPC request or notification.
+ [param action]: The action to be run, as a Dictionary in the form of a JSON-RPC request or notification.
</description>
</method>
<method name="process_string">
<return type="String" />
- <argument index="0" name="action" type="String" />
+ <param index="0" name="action" type="String" />
<description>
</description>
</method>
<method name="set_scope">
<return type="void" />
- <argument index="0" name="scope" type="String" />
- <argument index="1" name="target" type="Object" />
+ <param index="0" name="scope" type="String" />
+ <param index="1" name="target" type="Object" />
<description>
</description>
</method>
diff --git a/doc/classes/JavaClassWrapper.xml b/doc/classes/JavaClassWrapper.xml
index fdfac2748b..d44a63938c 100644
--- a/doc/classes/JavaClassWrapper.xml
+++ b/doc/classes/JavaClassWrapper.xml
@@ -9,7 +9,7 @@
<methods>
<method name="wrap">
<return type="JavaClass" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
</description>
</method>
diff --git a/doc/classes/JavaScript.xml b/doc/classes/JavaScript.xml
index 864028f3a6..c838422e85 100644
--- a/doc/classes/JavaScript.xml
+++ b/doc/classes/JavaScript.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="JavaScript" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- Singleton that connects the engine with the browser's JavaScript context in HTML5 export.
+ Singleton that connects the engine with the browser's JavaScript context in Web export.
</brief_description>
<description>
- 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.
+ The JavaScript singleton is implemented only in the Web export. It's used to access the browser's JavaScript context. This allows interaction with embedding pages or calling third-party JavaScript APIs.
[b]Note:[/b] This singleton can be disabled at build-time to improve security. By default, the JavaScript singleton is enabled. Official export templates also have the JavaScript singleton enabled. See [url=$DOCS_URL/development/compiling/compiling_for_web.html]Compiling for the Web[/url] in the documentation for more information.
</description>
<tutorials>
@@ -13,44 +13,44 @@
<methods>
<method name="create_callback">
<return type="JavaScriptObject" />
- <argument index="0" name="callable" type="Callable" />
+ <param index="0" name="callable" type="Callable" />
<description>
Creates a reference to a [Callable] that can be used as a callback by JavaScript. The reference must be kept until the callback happens, or it won't be called at all. See [JavaScriptObject] for usage.
</description>
</method>
<method name="create_object" qualifiers="vararg">
<return type="Variant" />
- <argument index="0" name="object" type="String" />
+ <param index="0" name="object" type="String" />
<description>
- Creates a new JavaScript object using the [code]new[/code] constructor. The [code]object[/code] must a valid property of the JavaScript [code]window[/code]. See [JavaScriptObject] for usage.
+ Creates a new JavaScript object using the [code]new[/code] constructor. The [param object] must a valid property of the JavaScript [code]window[/code]. See [JavaScriptObject] for usage.
</description>
</method>
<method name="download_buffer">
<return type="void" />
- <argument index="0" name="buffer" type="PackedByteArray" />
- <argument index="1" name="name" type="String" />
- <argument index="2" name="mime" type="String" default="&quot;application/octet-stream&quot;" />
+ <param index="0" name="buffer" type="PackedByteArray" />
+ <param index="1" name="name" type="String" />
+ <param index="2" name="mime" type="String" default="&quot;application/octet-stream&quot;" />
<description>
- Prompts the user to download a file containing the specified [code]buffer[/code]. The file will have the given [code]name[/code] and [code]mime[/code] type.
- [b]Note:[/b] The browser may override the [url=https://en.wikipedia.org/wiki/Media_type]MIME type[/url] provided based on the file [code]name[/code]'s extension.
+ Prompts the user to download a file containing the specified [param buffer]. The file will have the given [param name] and [param mime] type.
+ [b]Note:[/b] The browser may override the [url=https://en.wikipedia.org/wiki/Media_type]MIME type[/url] provided based on the file [param name]'s extension.
[b]Note:[/b] Browsers might block the download if [method download_buffer] is not being called from a user interaction (e.g. button click).
[b]Note:[/b] Browsers might ask the user for permission or block the download if multiple download requests are made in a quick succession.
</description>
</method>
<method name="eval">
<return type="Variant" />
- <argument index="0" name="code" type="String" />
- <argument index="1" name="use_global_execution_context" type="bool" default="false" />
+ <param index="0" name="code" type="String" />
+ <param index="1" name="use_global_execution_context" type="bool" default="false" />
<description>
- Execute the string [code]code[/code] as JavaScript code within the browser window. This is a call to the actual global JavaScript function [code]eval()[/code].
- If [code]use_global_execution_context[/code] is [code]true[/code], the code will be evaluated in the global execution context. Otherwise, it is evaluated in the execution context of a function within the engine's runtime environment.
+ Execute the string [param code] as JavaScript code within the browser window. This is a call to the actual global JavaScript function [code]eval()[/code].
+ If [param use_global_execution_context] is [code]true[/code], the code will be evaluated in the global execution context. Otherwise, it is evaluated in the execution context of a function within the engine's runtime environment.
</description>
</method>
<method name="get_interface">
<return type="JavaScriptObject" />
- <argument index="0" name="interface" type="String" />
+ <param index="0" name="interface" type="String" />
<description>
- Returns an interface to a JavaScript object that can be used by scripts. The [code]interface[/code] must be a valid property of the JavaScript [code]window[/code]. The callback must accept a single [Array] argument, which will contain the JavaScript [code]arguments[/code]. See [JavaScriptObject] for usage.
+ Returns an interface to a JavaScript object that can be used by scripts. The [param interface] must be a valid property of the JavaScript [code]window[/code]. The callback must accept a single [Array] argument, which will contain the JavaScript [code]arguments[/code]. See [JavaScriptObject] for usage.
</description>
</method>
<method name="pwa_needs_update" qualifiers="const">
diff --git a/doc/classes/JavaScriptObject.xml b/doc/classes/JavaScriptObject.xml
index 5c1a37266b..e279acf5a4 100644
--- a/doc/classes/JavaScriptObject.xml
+++ b/doc/classes/JavaScriptObject.xml
@@ -31,7 +31,7 @@
# [0, 9, [JavaScriptObject:1180]]
print(args)
[/codeblock]
- [b]Note:[/b] Only available in the HTML5 platform.
+ [b]Note:[/b] Only available in the Web platform.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/Joint3D.xml b/doc/classes/Joint3D.xml
index fef8fdf965..a9ca86d269 100644
--- a/doc/classes/Joint3D.xml
+++ b/doc/classes/Joint3D.xml
@@ -10,16 +10,16 @@
<link title="3D Truck Town Demo">https://godotengine.org/asset-library/asset/524</link>
</tutorials>
<members>
- <member name="collision/exclude_nodes" type="bool" setter="set_exclude_nodes_from_collision" getter="get_exclude_nodes_from_collision" default="true">
+ <member name="exclude_nodes_from_collision" type="bool" setter="set_exclude_nodes_from_collision" getter="get_exclude_nodes_from_collision" default="true">
If [code]true[/code], the two bodies of the nodes are not able to collide with each other.
</member>
- <member name="nodes/node_a" type="NodePath" setter="set_node_a" getter="get_node_a" default="NodePath(&quot;&quot;)">
+ <member name="node_a" type="NodePath" setter="set_node_a" getter="get_node_a" default="NodePath(&quot;&quot;)">
The node attached to the first side (A) of the joint.
</member>
- <member name="nodes/node_b" type="NodePath" setter="set_node_b" getter="get_node_b" default="NodePath(&quot;&quot;)">
+ <member name="node_b" type="NodePath" setter="set_node_b" getter="get_node_b" default="NodePath(&quot;&quot;)">
The node attached to the second side (B) of the joint.
</member>
- <member name="solver/priority" type="int" setter="set_solver_priority" getter="get_solver_priority" default="1">
+ <member name="solver_priority" type="int" setter="set_solver_priority" getter="get_solver_priority" default="1">
The priority used to define which solver is executed first for multiple joints. The lower the value, the higher the priority.
</member>
</members>
diff --git a/doc/classes/KinematicCollision2D.xml b/doc/classes/KinematicCollision2D.xml
index 1f3f0dbb6d..e991856de5 100644
--- a/doc/classes/KinematicCollision2D.xml
+++ b/doc/classes/KinematicCollision2D.xml
@@ -12,9 +12,9 @@
<methods>
<method name="get_angle" qualifiers="const">
<return type="float" />
- <argument index="0" name="up_direction" type="Vector2" default="Vector2(0, -1)" />
+ <param index="0" name="up_direction" type="Vector2" default="Vector2(0, -1)" />
<description>
- Returns the collision angle according to [code]up_direction[/code], which is [code]Vector2.UP[/code] by default. This value is always positive.
+ Returns the collision angle according to [param up_direction], which is [constant Vector2.UP] by default. This value is always positive.
</description>
</method>
<method name="get_collider" qualifiers="const">
@@ -53,6 +53,12 @@
Returns the colliding body's velocity.
</description>
</method>
+ <method name="get_depth" qualifiers="const">
+ <return type="float" />
+ <description>
+ Returns the colliding body's length of overlap along the collision normal.
+ </description>
+ </method>
<method name="get_local_shape" qualifiers="const">
<return type="Object" />
<description>
diff --git a/doc/classes/KinematicCollision3D.xml b/doc/classes/KinematicCollision3D.xml
index 6327d48d38..6b0a806e5c 100644
--- a/doc/classes/KinematicCollision3D.xml
+++ b/doc/classes/KinematicCollision3D.xml
@@ -12,50 +12,50 @@
<methods>
<method name="get_angle" qualifiers="const">
<return type="float" />
- <argument index="0" name="collision_index" type="int" default="0" />
- <argument index="1" name="up_direction" type="Vector3" default="Vector3(0, 1, 0)" />
+ <param index="0" name="collision_index" type="int" default="0" />
+ <param index="1" name="up_direction" type="Vector3" default="Vector3(0, 1, 0)" />
<description>
- Returns the collision angle according to [code]up_direction[/code], which is [code]Vector3.UP[/code] by default. This value is always positive.
+ Returns the collision angle according to [param up_direction], which is [constant Vector3.UP] by default. This value is always positive.
</description>
</method>
<method name="get_collider" qualifiers="const">
<return type="Object" />
- <argument index="0" name="collision_index" type="int" default="0" />
+ <param index="0" name="collision_index" type="int" default="0" />
<description>
Returns the colliding body's attached [Object] given a collision index (the deepest collision by default).
</description>
</method>
<method name="get_collider_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="collision_index" type="int" default="0" />
+ <param index="0" name="collision_index" type="int" default="0" />
<description>
Returns the unique instance ID of the colliding body's attached [Object] given a collision index (the deepest collision by default). See [method Object.get_instance_id].
</description>
</method>
<method name="get_collider_rid" qualifiers="const">
<return type="RID" />
- <argument index="0" name="collision_index" type="int" default="0" />
+ <param index="0" name="collision_index" type="int" default="0" />
<description>
Returns the colliding body's [RID] used by the [PhysicsServer3D] given a collision index (the deepest collision by default).
</description>
</method>
<method name="get_collider_shape" qualifiers="const">
<return type="Object" />
- <argument index="0" name="collision_index" type="int" default="0" />
+ <param index="0" name="collision_index" type="int" default="0" />
<description>
Returns the colliding body's shape given a collision index (the deepest collision by default).
</description>
</method>
<method name="get_collider_shape_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="collision_index" type="int" default="0" />
+ <param index="0" name="collision_index" type="int" default="0" />
<description>
Returns the colliding body's shape index given a collision index (the deepest collision by default). See [CollisionObject3D].
</description>
</method>
<method name="get_collider_velocity" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="collision_index" type="int" default="0" />
+ <param index="0" name="collision_index" type="int" default="0" />
<description>
Returns the colliding body's velocity given a collision index (the deepest collision by default).
</description>
@@ -66,23 +66,29 @@
Returns the number of detected collisions.
</description>
</method>
+ <method name="get_depth" qualifiers="const">
+ <return type="float" />
+ <description>
+ Returns the colliding body's length of overlap along the collision normal.
+ </description>
+ </method>
<method name="get_local_shape" qualifiers="const">
<return type="Object" />
- <argument index="0" name="collision_index" type="int" default="0" />
+ <param index="0" name="collision_index" type="int" default="0" />
<description>
Returns the moving object's colliding shape given a collision index (the deepest collision by default).
</description>
</method>
<method name="get_normal" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="collision_index" type="int" default="0" />
+ <param index="0" name="collision_index" type="int" default="0" />
<description>
Returns the colliding body's shape's normal at the point of collision given a collision index (the deepest collision by default).
</description>
</method>
<method name="get_position" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="collision_index" type="int" default="0" />
+ <param index="0" name="collision_index" type="int" default="0" />
<description>
Returns the point of collision in global coordinates given a collision index (the deepest collision by default).
</description>
diff --git a/doc/classes/Label.xml b/doc/classes/Label.xml
index 1ebf770f7e..615aceac53 100644
--- a/doc/classes/Label.xml
+++ b/doc/classes/Label.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Label displays plain text on the screen. It gives you control over the horizontal and vertical alignment and can wrap the text inside the node's bounding rectangle. It doesn't support bold, italics, or other formatting. For that, use [RichTextLabel] instead.
- [b]Note:[/b] Contrarily to most other [Control]s, Label's [member Control.mouse_filter] defaults to [constant Control.MOUSE_FILTER_IGNORE] (i.e. it doesn't react to mouse input events). This implies that a label won't display any configured [member Control.hint_tooltip], unless you change its mouse filter.
+ [b]Note:[/b] Contrarily to most other [Control]s, Label's [member Control.mouse_filter] defaults to [constant Control.MOUSE_FILTER_IGNORE] (i.e. it doesn't react to mouse input events). This implies that a label won't display any configured [member Control.tooltip_text], unless you change its mouse filter.
</description>
<tutorials>
<link title="2D Dodge The Creeps Demo">https://godotengine.org/asset-library/asset/515</link>
@@ -14,16 +14,16 @@
<method name="get_line_count" qualifiers="const">
<return type="int" />
<description>
- Returns the amount of lines of text the Label has.
+ Returns the number of lines of text the Label has.
</description>
</method>
<method name="get_line_height" qualifiers="const">
<return type="int" />
- <argument index="0" name="line" type="int" default="-1" />
+ <param index="0" name="line" type="int" default="-1" />
<description>
- Returns the height of the line [code]line[/code].
- If [code]line[/code] is set to [code]-1[/code], returns the biggest line height.
- If there're no lines returns font size in pixels.
+ Returns the height of the line [param line].
+ If [param line] is set to [code]-1[/code], returns the biggest line height.
+ If there are no lines, returns font size in pixels.
</description>
</method>
<method name="get_total_character_count" qualifiers="const">
@@ -61,10 +61,6 @@
Limits the lines of text the node shows on screen.
</member>
<member name="mouse_filter" type="int" setter="set_mouse_filter" getter="get_mouse_filter" overrides="Control" enum="Control.MouseFilter" default="2" />
- <member name="percent_visible" type="float" setter="set_percent_visible" getter="get_percent_visible" default="1.0">
- Limits the amount of visible characters. If you set [code]percent_visible[/code] to 0.5, only up to half of the text's characters will display on screen. Useful to animate the text in a dialog box.
- [b]Note:[/b] Setting this property updates [member visible_characters] based on current [method get_total_character_count].
- </member>
<member name="size_flags_vertical" type="int" setter="set_v_size_flags" getter="get_v_size_flags" overrides="Control" default="4" />
<member name="structured_text_bidi_override" type="int" setter="set_structured_text_bidi_override" getter="get_structured_text_bidi_override" enum="TextServer.StructuredTextParser" default="0">
Set BiDi algorithm override for the structured text.
@@ -88,11 +84,15 @@
Controls the text's vertical alignment. Supports top, center, bottom, and fill. Set it to one of the [enum VerticalAlignment] constants.
</member>
<member name="visible_characters" type="int" setter="set_visible_characters" getter="get_visible_characters" default="-1">
- Restricts the number of characters to display. Set to -1 to disable.
- [b]Note:[/b] Setting this property updates [member percent_visible] based on current [method get_total_character_count].
+ The number of characters to display. If set to [code]-1[/code], all characters are displayed. This can be useful when animating the text appearing in a dialog box.
+ [b]Note:[/b] Setting this property updates [member visible_ratio] accordingly.
</member>
<member name="visible_characters_behavior" type="int" setter="set_visible_characters_behavior" getter="get_visible_characters_behavior" enum="TextServer.VisibleCharactersBehavior" default="0">
- Sets the clipping behavior when [member visible_characters] or [member percent_visible] is set. See [enum TextServer.VisibleCharactersBehavior] for more info.
+ Sets the clipping behavior when [member visible_characters] or [member visible_ratio] is set. See [enum TextServer.VisibleCharactersBehavior] for more info.
+ </member>
+ <member name="visible_ratio" type="float" setter="set_visible_ratio" getter="get_visible_ratio" default="1.0">
+ The fraction of characters to display, relative to the total number of characters (see [method get_total_character_count]). If set to [code]1.0[/code], all characters are displayed. If set to [code]0.5[/code], only half of the characters will be displayed. This can be useful when animating the text appearing in a dialog box.
+ [b]Note:[/b] Setting this property updates [member visible_characters] accordingly.
</member>
</members>
<theme_items>
diff --git a/doc/classes/Label3D.xml b/doc/classes/Label3D.xml
index 5ba0a2d79a..b741dc6e64 100644
--- a/doc/classes/Label3D.xml
+++ b/doc/classes/Label3D.xml
@@ -17,15 +17,15 @@
</method>
<method name="get_draw_flag" qualifiers="const">
<return type="bool" />
- <argument index="0" name="flag" type="int" enum="Label3D.DrawFlags" />
+ <param index="0" name="flag" type="int" enum="Label3D.DrawFlags" />
<description>
Returns the value of the specified flag.
</description>
</method>
<method name="set_draw_flag">
<return type="void" />
- <argument index="0" name="flag" type="int" enum="Label3D.DrawFlags" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="flag" type="int" enum="Label3D.DrawFlags" />
+ <param index="1" name="enabled" type="bool" />
<description>
If [code]true[/code], the specified flag will be enabled. See [enum Label3D.DrawFlags] for a list of flags.
</description>
@@ -53,8 +53,9 @@
<member name="font" type="Font" setter="set_font" getter="get_font">
Font configuration used to display text.
</member>
- <member name="font_size" type="int" setter="set_font_size" getter="get_font_size" default="16">
- Font size of the [Label3D]'s text.
+ <member name="font_size" type="int" setter="set_font_size" getter="get_font_size" default="32">
+ Font size of the [Label3D]'s text. To make the font look more detailed when up close, increase [member font_size] while decreasing [member pixel_size] at the same time.
+ Higher font sizes require more time to render new characters, which can cause stuttering during gameplay.
</member>
<member name="horizontal_alignment" type="int" setter="set_horizontal_alignment" getter="get_horizontal_alignment" enum="HorizontalAlignment" default="1">
Controls the text's horizontal alignment. Supports left, center, right, and fill, or justify. Set it to one of the [enum HorizontalAlignment] constants.
@@ -82,11 +83,11 @@
[b]Note:[/b] This only applies if [member alpha_cut] is set to [constant ALPHA_CUT_DISABLED] (default value).
[b]Note:[/b] This only applies to sorting of transparent objects. This will not impact how transparent objects are sorted relative to opaque objects. This is because opaque objects are not sorted, while transparent objects are sorted from back to front (subject to priority).
</member>
- <member name="outline_size" type="int" setter="set_outline_size" getter="get_outline_size" default="0">
+ <member name="outline_size" type="int" setter="set_outline_size" getter="get_outline_size" default="12">
Text outline size.
</member>
- <member name="pixel_size" type="float" setter="set_pixel_size" getter="get_pixel_size" default="0.01">
- The size of one pixel's width on the label to scale it in 3D.
+ <member name="pixel_size" type="float" setter="set_pixel_size" getter="get_pixel_size" default="0.005">
+ The size of one pixel's width on the label to scale it in 3D. To make the font look more detailed when up close, increase [member font_size] while decreasing [member pixel_size] at the same time.
</member>
<member name="render_priority" type="int" setter="set_render_priority" getter="get_render_priority" default="0">
Sets the render priority for the text. Higher priority objects will be sorted in front of lower priority objects.
@@ -138,7 +139,7 @@
Represents the size of the [enum DrawFlags] enum.
</constant>
<constant name="ALPHA_CUT_DISABLED" value="0" enum="AlphaCutMode">
- This mode performs standard alpha blending. It can display translucent areas, but transparency sorting issues may be visible when multiple transparent materials are overlapping.
+ This mode performs standard alpha blending. It can display translucent areas, but transparency sorting issues may be visible when multiple transparent materials are overlapping. [member GeometryInstance3D.cast_shadow] has no effect when this transparency mode is used; the [Label3D] will never cast shadows.
</constant>
<constant name="ALPHA_CUT_DISCARD" value="1" enum="AlphaCutMode">
This mode only allows fully transparent or fully opaque pixels. Harsh edges will be visible unless some form of screen-space antialiasing is enabled (see [member ProjectSettings.rendering/anti_aliasing/quality/screen_space_aa]). This mode is also known as [i]alpha testing[/i] or [i]1-bit transparency[/i].
diff --git a/doc/classes/LabelSettings.xml b/doc/classes/LabelSettings.xml
index 227313d3b3..aa972f2cf3 100644
--- a/doc/classes/LabelSettings.xml
+++ b/doc/classes/LabelSettings.xml
@@ -9,21 +9,21 @@
<members>
<member name="font" type="Font" setter="set_font" getter="get_font">
</member>
- <member name="font_color" type="Color" setter="set_font_color" getter="get_font_color" default="Color(0.875, 0.875, 0.875, 1)">
+ <member name="font_color" type="Color" setter="set_font_color" getter="get_font_color" default="Color(1, 1, 1, 1)">
</member>
<member name="font_size" type="int" setter="set_font_size" getter="get_font_size" default="16">
</member>
- <member name="line_spacing" type="float" setter="set_line_spacing" getter="get_line_spacing" default="0.0">
+ <member name="line_spacing" type="float" setter="set_line_spacing" getter="get_line_spacing" default="3.0">
</member>
<member name="outline_color" type="Color" setter="set_outline_color" getter="get_outline_color" default="Color(1, 1, 1, 1)">
</member>
<member name="outline_size" type="int" setter="set_outline_size" getter="get_outline_size" default="0">
</member>
- <member name="shadow_color" type="Color" setter="set_shadow_color" getter="get_shadow_color" default="Color(1, 1, 1, 1)">
+ <member name="shadow_color" type="Color" setter="set_shadow_color" getter="get_shadow_color" default="Color(0, 0, 0, 0)">
</member>
<member name="shadow_offset" type="Vector2" setter="set_shadow_offset" getter="get_shadow_offset" default="Vector2(1, 1)">
</member>
- <member name="shadow_size" type="int" setter="set_shadow_size" getter="get_shadow_size" default="0">
+ <member name="shadow_size" type="int" setter="set_shadow_size" getter="get_shadow_size" default="1">
</member>
</members>
</class>
diff --git a/doc/classes/Light2D.xml b/doc/classes/Light2D.xml
index 32bf6a67a9..00815758a1 100644
--- a/doc/classes/Light2D.xml
+++ b/doc/classes/Light2D.xml
@@ -18,7 +18,7 @@
</method>
<method name="set_height">
<return type="void" />
- <argument index="0" name="height" type="float" />
+ <param index="0" name="height" type="float" />
<description>
</description>
</method>
diff --git a/doc/classes/Light3D.xml b/doc/classes/Light3D.xml
index 0ebd83c882..80ff83ec46 100644
--- a/doc/classes/Light3D.xml
+++ b/doc/classes/Light3D.xml
@@ -13,15 +13,15 @@
<methods>
<method name="get_param" qualifiers="const">
<return type="float" />
- <argument index="0" name="param" type="int" enum="Light3D.Param" />
+ <param index="0" name="param" type="int" enum="Light3D.Param" />
<description>
Returns the value of the specified [enum Light3D.Param] parameter.
</description>
</method>
<method name="set_param">
<return type="void" />
- <argument index="0" name="param" type="int" enum="Light3D.Param" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="param" type="int" enum="Light3D.Param" />
+ <param index="1" name="value" type="float" />
<description>
Sets the value of the specified [enum Light3D.Param] parameter.
</description>
@@ -37,13 +37,12 @@
[b]Note:[/b] Only effective for [OmniLight3D] and [SpotLight3D].
</member>
<member name="distance_fade_length" type="float" setter="set_distance_fade_length" getter="get_distance_fade_length" default="10.0">
- Distance over which the light fades. The light's energy is progressively reduced over this distance and is completely invisible at the end.
+ Distance over which the light and its shadow fades. The light's energy and shadow's opacity is progressively reduced over this distance and is completely invisible at the end.
[b]Note:[/b] Only effective for [OmniLight3D] and [SpotLight3D].
</member>
<member name="distance_fade_shadow" type="float" setter="set_distance_fade_shadow" getter="get_distance_fade_shadow" default="50.0">
The distance from the camera at which the light's shadow cuts off (in 3D units). Set this to a value lower than [member distance_fade_begin] + [member distance_fade_length] to further improve performance, as shadow rendering is often more expensive than light rendering itself.
[b]Note:[/b] Only effective for [OmniLight3D] and [SpotLight3D], and only when [member shadow_enabled] is [code]true[/code].
- [b]Note:[/b] Due to a rendering engine limitation, shadows will be disabled instantly instead of fading smoothly according to [member distance_fade_length]. This may result in visible pop-in depending on the scene topography.
</member>
<member name="editor_only" type="bool" setter="set_editor_only" getter="is_editor_only" default="false">
If [code]true[/code], the light only appears in the editor and will not be visible at runtime.
@@ -95,6 +94,9 @@
<member name="shadow_normal_bias" type="float" setter="set_param" getter="get_param" default="1.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>
+ <member name="shadow_opacity" type="float" setter="set_param" getter="get_param" default="1.0">
+ The opacity to use when rendering the light's shadow map. Values lower than [code]1.0[/code] make the light appear through shadows. This can be used to fake global illumination at a low performance cost.
+ </member>
<member name="shadow_reverse_cull_face" type="bool" setter="set_shadow_reverse_cull_face" getter="get_shadow_reverse_cull_face" default="false">
If [code]true[/code], reverses the backface culling of the mesh. This can be useful when you have a flat mesh that has a light behind it. If you need to cast a shadow on both sides of the mesh, set the mesh to use double-sided shadows with [constant GeometryInstance3D.SHADOW_CASTING_SETTING_DOUBLE_SIDED].
</member>
@@ -150,15 +152,19 @@
<constant name="PARAM_SHADOW_PANCAKE_SIZE" value="15" enum="Param">
Constant for accessing [member DirectionalLight3D.directional_shadow_pancake_size].
</constant>
- <constant name="PARAM_SHADOW_BLUR" value="16" enum="Param">
+ <constant name="PARAM_SHADOW_OPACITY" value="16" enum="Param">
+ Constant for accessing [member shadow_opacity].
+ </constant>
+ <constant name="PARAM_SHADOW_BLUR" value="17" enum="Param">
Constant for accessing [member shadow_blur].
</constant>
- <constant name="PARAM_SHADOW_VOLUMETRIC_FOG_FADE" value="17" enum="Param">
+ <constant name="PARAM_SHADOW_VOLUMETRIC_FOG_FADE" value="18" enum="Param">
+ Constant for accessing [member shadow_fog_fade].
</constant>
- <constant name="PARAM_TRANSMITTANCE_BIAS" value="18" enum="Param">
+ <constant name="PARAM_TRANSMITTANCE_BIAS" value="19" enum="Param">
Constant for accessing [member shadow_transmittance_bias].
</constant>
- <constant name="PARAM_MAX" value="19" enum="Param">
+ <constant name="PARAM_MAX" value="20" enum="Param">
Represents the size of the [enum Param] enum.
</constant>
<constant name="BAKE_DISABLED" value="0" enum="BakeMode">
diff --git a/doc/classes/LightmapGIData.xml b/doc/classes/LightmapGIData.xml
index 13f44150d7..d24b2c6871 100644
--- a/doc/classes/LightmapGIData.xml
+++ b/doc/classes/LightmapGIData.xml
@@ -11,10 +11,10 @@
<methods>
<method name="add_user">
<return type="void" />
- <argument index="0" name="path" type="NodePath" />
- <argument index="1" name="uv_scale" type="Rect2" />
- <argument index="2" name="slice_index" type="int" />
- <argument index="3" name="sub_instance" type="int" />
+ <param index="0" name="path" type="NodePath" />
+ <param index="1" name="uv_scale" type="Rect2" />
+ <param index="2" name="slice_index" type="int" />
+ <param index="3" name="sub_instance" type="int" />
<description>
Adds an object that is considered baked within this [LightmapGIData].
</description>
@@ -33,9 +33,9 @@
</method>
<method name="get_user_path" qualifiers="const">
<return type="NodePath" />
- <argument index="0" name="user_idx" type="int" />
+ <param index="0" name="user_idx" type="int" />
<description>
- Returns the [NodePath] of the baked object at index [code]user_idx[/code].
+ Returns the [NodePath] of the baked object at index [param user_idx].
</description>
</method>
<method name="is_using_spherical_harmonics" qualifiers="const">
@@ -46,9 +46,9 @@
</method>
<method name="set_uses_spherical_harmonics">
<return type="void" />
- <argument index="0" name="uses_spherical_harmonics" type="bool" />
+ <param index="0" name="uses_spherical_harmonics" type="bool" />
<description>
- If [code]uses_spherical_harmonics[/code] is [code]true[/code], tells the engine to treat the lightmap data as if it was baked with directional information.
+ If [param uses_spherical_harmonics] is [code]true[/code], tells the engine to treat the lightmap data as if it was baked with directional information.
[b]Note:[/b] Changing this value on already baked lightmaps will not cause them to be baked again. This means the material appearance will look incorrect until lightmaps are baked again, in which case the value set here is discarded as the entire [LightmapGIData] resource is replaced by the lightmapper.
</description>
</method>
diff --git a/doc/classes/Line2D.xml b/doc/classes/Line2D.xml
index e2cc43bb75..4547c3589f 100644
--- a/doc/classes/Line2D.xml
+++ b/doc/classes/Line2D.xml
@@ -13,11 +13,11 @@
<methods>
<method name="add_point">
<return type="void" />
- <argument index="0" name="position" type="Vector2" />
- <argument index="1" name="at_position" type="int" default="-1" />
+ <param index="0" name="position" type="Vector2" />
+ <param index="1" name="index" type="int" default="-1" />
<description>
- Adds a point at the [code]position[/code]. Appends the point at the end of the line.
- If [code]at_position[/code] is given, the point is inserted before the point number [code]at_position[/code], moving that point (and every point after) after the inserted point. If [code]at_position[/code] is not given, or is an illegal value ([code]at_position &lt; 0[/code] or [code]at_position &gt;= [method get_point_count][/code]), the point will be appended at the end of the point list.
+ Adds a point with the specified [param position] relative to the line's own position. Appends the new point at the end of the point list.
+ If [param index] is given, the new point is inserted before the existing point identified by index [param index]. Every existing point starting from [param index] is shifted further down the list of points. The index must be greater than or equal to [code]0[/code] and must not exceed the number of existing points in the line. See [method get_point_count].
</description>
</method>
<method name="clear_points">
@@ -29,29 +29,29 @@
<method name="get_point_count" qualifiers="const">
<return type="int" />
<description>
- Returns the Line2D's amount of points.
+ Returns the number of points in the line.
</description>
</method>
<method name="get_point_position" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="i" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns point [code]i[/code]'s position.
+ Returns the position of the point at index [param index].
</description>
</method>
<method name="remove_point">
<return type="void" />
- <argument index="0" name="i" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Removes the point at index [code]i[/code] from the line.
+ Removes the point at index [param index] from the line.
</description>
</method>
<method name="set_point_position">
<return type="void" />
- <argument index="0" name="i" type="int" />
- <argument index="1" name="position" type="Vector2" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="position" type="Vector2" />
<description>
- Overwrites the position in point [code]i[/code] with the supplied [code]position[/code].
+ Overwrites the position of the point at index [param index] with the supplied [param position].
</description>
</method>
</methods>
diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml
index 84471bafc0..f8f2375a71 100644
--- a/doc/classes/LineEdit.xml
+++ b/doc/classes/LineEdit.xml
@@ -45,10 +45,10 @@
</method>
<method name="delete_text">
<return type="void" />
- <argument index="0" name="from_column" type="int" />
- <argument index="1" name="to_column" type="int" />
+ <param index="0" name="from_column" type="int" />
+ <param index="1" name="to_column" type="int" />
<description>
- Deletes a section of the [member text] going from position [code]from_column[/code] to [code]to_column[/code]. Both parameters should be within the text's length.
+ Deletes a section of the [member text] going from position [param from_column] to [param to_column]. Both parameters should be within the text's length.
</description>
</method>
<method name="deselect">
@@ -65,7 +65,7 @@
</description>
</method>
<method name="get_scroll_offset" qualifiers="const">
- <return type="int" />
+ <return type="float" />
<description>
Returns the scroll offset due to [member caret_column], as a number of characters.
</description>
@@ -90,9 +90,9 @@
</method>
<method name="insert_text_at_caret">
<return type="void" />
- <argument index="0" name="text" type="String" />
+ <param index="0" name="text" type="String" />
<description>
- Inserts [code]text[/code] at the caret. If the resulting value is longer than [member max_length], nothing happens.
+ Inserts [param text] at the caret. If the resulting value is longer than [member max_length], nothing happens.
</description>
</method>
<method name="is_menu_visible" qualifiers="const">
@@ -103,17 +103,17 @@
</method>
<method name="menu_option">
<return type="void" />
- <argument index="0" name="option" type="int" />
+ <param index="0" name="option" type="int" />
<description>
Executes a given action as defined in the [enum MenuItems] enum.
</description>
</method>
<method name="select">
<return type="void" />
- <argument index="0" name="from" type="int" default="0" />
- <argument index="1" name="to" type="int" default="-1" />
+ <param index="0" name="from" type="int" default="0" />
+ <param index="1" name="to" type="int" default="-1" />
<description>
- Selects characters inside [LineEdit] between [code]from[/code] and [code]to[/code]. By default, [code]from[/code] is at the beginning and [code]to[/code] at the end.
+ Selects characters inside [LineEdit] between [param from] and [param to]. By default, [param from] is at the beginning and [param to] at the end.
[codeblocks]
[gdscript]
text = "Welcome"
@@ -183,7 +183,7 @@
Language code used for line-breaking and text shaping algorithms, if left empty current locale is used instead.
</member>
<member name="max_length" type="int" setter="set_max_length" getter="get_max_length" default="0">
- Maximum amount of characters that can be entered inside the [LineEdit]. If [code]0[/code], there is no limit.
+ Maximum number of characters that can be entered inside the [LineEdit]. If [code]0[/code], there is no limit.
When a limit is defined, characters that would exceed [member max_length] are truncated. This happens both for existing [member text] contents when setting the max length, or for new text inserted in the [LineEdit], including pasting. If any input text is truncated, the [signal text_change_rejected] signal is emitted with the truncated substring as parameter.
[b]Example:[/b]
[codeblocks]
@@ -221,8 +221,8 @@
<member name="secret" type="bool" setter="set_secret" getter="is_secret" default="false">
If [code]true[/code], every character is replaced with the secret character (see [member secret_character]).
</member>
- <member name="secret_character" type="String" setter="set_secret_character" getter="get_secret_character" default="&quot;*&quot;">
- The character to use to mask secret input (defaults to "*"). Only a single character can be used as the secret character.
+ <member name="secret_character" type="String" setter="set_secret_character" getter="get_secret_character" default="&quot;•&quot;">
+ The character to use to mask secret input (defaults to "•"). Only a single character can be used as the secret character.
</member>
<member name="selecting_enabled" type="bool" setter="set_selecting_enabled" getter="is_selecting_enabled" default="true">
If [code]false[/code], it's impossible to select the text using mouse nor keyboard.
@@ -246,22 +246,25 @@
<member name="virtual_keyboard_enabled" type="bool" setter="set_virtual_keyboard_enabled" getter="is_virtual_keyboard_enabled" default="true">
If [code]true[/code], the native virtual keyboard is shown when focused on platforms that support it.
</member>
+ <member name="virtual_keyboard_type" type="int" setter="set_virtual_keyboard_type" getter="get_virtual_keyboard_type" enum="LineEdit.VirtualKeyboardType" default="0">
+ Specifies the type of virtual keyboard to show.
+ </member>
</members>
<signals>
<signal name="text_change_rejected">
- <argument index="0" name="rejected_substring" type="String" />
+ <param index="0" name="rejected_substring" type="String" />
<description>
Emitted when appending text that overflows the [member max_length]. The appended text is truncated to fit [member max_length], and the part that couldn't fit is passed as the [code]rejected_substring[/code] argument.
</description>
</signal>
<signal name="text_changed">
- <argument index="0" name="new_text" type="String" />
+ <param index="0" name="new_text" type="String" />
<description>
Emitted when the text changes.
</description>
</signal>
<signal name="text_submitted">
- <argument index="0" name="new_text" type="String" />
+ <param index="0" name="new_text" type="String" />
<description>
Emitted when the user presses [constant KEY_ENTER] on the [LineEdit].
</description>
@@ -356,6 +359,31 @@
<constant name="MENU_MAX" value="28" enum="MenuItems">
Represents the size of the [enum MenuItems] enum.
</constant>
+ <constant name="KEYBOARD_TYPE_DEFAULT" value="0" enum="VirtualKeyboardType">
+ Default text virtual keyboard.
+ </constant>
+ <constant name="KEYBOARD_TYPE_MULTILINE" value="1" enum="VirtualKeyboardType">
+ Multiline virtual keyboard.
+ </constant>
+ <constant name="KEYBOARD_TYPE_NUMBER" value="2" enum="VirtualKeyboardType">
+ Virtual number keypad, useful for PIN entry.
+ </constant>
+ <constant name="KEYBOARD_TYPE_NUMBER_DECIMAL" value="3" enum="VirtualKeyboardType">
+ Virtual number keypad, useful for entering fractional numbers.
+ </constant>
+ <constant name="KEYBOARD_TYPE_PHONE" value="4" enum="VirtualKeyboardType">
+ Virtual phone number keypad.
+ </constant>
+ <constant name="KEYBOARD_TYPE_EMAIL_ADDRESS" value="5" enum="VirtualKeyboardType">
+ Virtual keyboard with additional keys to assist with typing email addresses.
+ </constant>
+ <constant name="KEYBOARD_TYPE_PASSWORD" value="6" enum="VirtualKeyboardType">
+ Virtual keyboard for entering a password. On most platforms, this should disable autocomplete and autocapitalization.
+ [b]Note:[/b] This is not supported on Web. Instead, this behaves identically to [constant KEYBOARD_TYPE_DEFAULT].
+ </constant>
+ <constant name="KEYBOARD_TYPE_URL" value="7" enum="VirtualKeyboardType">
+ Virtual keyboard with additional keys to assist with typing URLs.
+ </constant>
</constants>
<theme_items>
<theme_item name="caret_color" data_type="color" type="Color" default="Color(0.95, 0.95, 0.95, 1)">
@@ -389,7 +417,7 @@
The caret's width in pixels. Greater values can be used to improve accessibility by ensuring the caret is easily visible, or to ensure consistency with a large font size.
</theme_item>
<theme_item name="minimum_character_width" data_type="constant" type="int" default="4">
- Minimum horizontal space for the text (not counting the clear button and content margins). This value is measured in count of 'M' characters (i.e. this amount of 'M' characters can be displayed without scrolling).
+ Minimum horizontal space for the text (not counting the clear button and content margins). This value is measured in count of 'M' characters (i.e. this number of 'M' characters can be displayed without scrolling).
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline.
diff --git a/doc/classes/MainLoop.xml b/doc/classes/MainLoop.xml
index 2cf41b750a..674adb1772 100644
--- a/doc/classes/MainLoop.xml
+++ b/doc/classes/MainLoop.xml
@@ -74,15 +74,15 @@
</method>
<method name="_physics_process" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="delta" type="float" />
+ <param index="0" name="delta" type="float" />
<description>
- Called each physics frame with the time since the last physics frame as argument ([code]delta[/code], in seconds). Equivalent to [method Node._physics_process].
+ Called each physics frame with the time since the last physics frame as argument ([param delta], in seconds). Equivalent to [method Node._physics_process].
If implemented, the method must return a boolean value. [code]true[/code] ends the main loop, while [code]false[/code] lets it proceed to the next frame.
</description>
</method>
<method name="_process" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="delta" type="float" />
+ <param index="0" name="delta" type="float" />
<description>
Called each process (idle) frame with the time since the last process frame as argument (in seconds). Equivalent to [method Node._process].
If implemented, the method must return a boolean value. [code]true[/code] ends the main loop, while [code]false[/code] lets it proceed to the next frame.
@@ -91,8 +91,8 @@
</methods>
<signals>
<signal name="on_request_permissions_result">
- <argument index="0" name="permission" type="String" />
- <argument index="1" name="granted" type="bool" />
+ <param index="0" name="permission" type="String" />
+ <param index="1" name="granted" type="bool" />
<description>
Emitted when a user responds to a permission request.
</description>
diff --git a/doc/classes/Position2D.xml b/doc/classes/Marker2D.xml
index 754fd1fdf1..bf90438bf0 100644
--- a/doc/classes/Position2D.xml
+++ b/doc/classes/Marker2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Position2D" inherits="Node2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Marker2D" inherits="Node2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Generic 2D position hint for editing.
</brief_description>
diff --git a/doc/classes/Position3D.xml b/doc/classes/Marker3D.xml
index d91e0fbfdf..5ad1cdf513 100644
--- a/doc/classes/Position3D.xml
+++ b/doc/classes/Marker3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="Position3D" inherits="Node3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="Marker3D" inherits="Node3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Generic 3D position hint for editing.
</brief_description>
diff --git a/doc/classes/Marshalls.xml b/doc/classes/Marshalls.xml
index b66a1b9190..102e4b75ed 100644
--- a/doc/classes/Marshalls.xml
+++ b/doc/classes/Marshalls.xml
@@ -11,47 +11,47 @@
<methods>
<method name="base64_to_raw">
<return type="PackedByteArray" />
- <argument index="0" name="base64_str" type="String" />
+ <param index="0" name="base64_str" type="String" />
<description>
- Returns a decoded [PackedByteArray] corresponding to the Base64-encoded string [code]base64_str[/code].
+ Returns a decoded [PackedByteArray] corresponding to the Base64-encoded string [param base64_str].
</description>
</method>
<method name="base64_to_utf8">
<return type="String" />
- <argument index="0" name="base64_str" type="String" />
+ <param index="0" name="base64_str" type="String" />
<description>
- Returns a decoded string corresponding to the Base64-encoded string [code]base64_str[/code].
+ Returns a decoded string corresponding to the Base64-encoded string [param base64_str].
</description>
</method>
<method name="base64_to_variant">
<return type="Variant" />
- <argument index="0" name="base64_str" type="String" />
- <argument index="1" name="allow_objects" type="bool" default="false" />
+ <param index="0" name="base64_str" type="String" />
+ <param index="1" name="allow_objects" type="bool" default="false" />
<description>
- Returns a decoded [Variant] corresponding to the Base64-encoded string [code]base64_str[/code]. If [code]allow_objects[/code] is [code]true[/code], decoding objects is allowed.
+ Returns a decoded [Variant] corresponding to the Base64-encoded string [param base64_str]. If [param allow_objects] is [code]true[/code], decoding objects is allowed.
[b]Warning:[/b] Deserialized objects can contain code which gets executed. Do not use this option if the serialized object comes from untrusted sources to avoid potential security threats such as remote code execution.
</description>
</method>
<method name="raw_to_base64">
<return type="String" />
- <argument index="0" name="array" type="PackedByteArray" />
+ <param index="0" name="array" type="PackedByteArray" />
<description>
Returns a Base64-encoded string of a given [PackedByteArray].
</description>
</method>
<method name="utf8_to_base64">
<return type="String" />
- <argument index="0" name="utf8_str" type="String" />
+ <param index="0" name="utf8_str" type="String" />
<description>
- Returns a Base64-encoded string of the UTF-8 string [code]utf8_str[/code].
+ Returns a Base64-encoded string of the UTF-8 string [param utf8_str].
</description>
</method>
<method name="variant_to_base64">
<return type="String" />
- <argument index="0" name="variant" type="Variant" />
- <argument index="1" name="full_objects" type="bool" default="false" />
+ <param index="0" name="variant" type="Variant" />
+ <param index="1" name="full_objects" type="bool" default="false" />
<description>
- Returns a Base64-encoded string of the [Variant] [code]variant[/code]. If [code]full_objects[/code] is [code]true[/code], encoding objects is allowed (and can potentially include code).
+ Returns a Base64-encoded string of the [Variant] [param variant]. If [param full_objects] is [code]true[/code], encoding objects is allowed (and can potentially include code).
</description>
</method>
</methods>
diff --git a/doc/classes/MenuBar.xml b/doc/classes/MenuBar.xml
new file mode 100644
index 0000000000..3ef0572e9f
--- /dev/null
+++ b/doc/classes/MenuBar.xml
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="MenuBar" inherits="Control" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ A horizontal menu bar, which displays [PopupMenu]s or system global menu.
+ </brief_description>
+ <description>
+ New items can be created by adding [PopupMenu] nodes to his node.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_menu_count" qualifiers="const">
+ <return type="int" />
+ <description>
+ Returns number of menu items.
+ </description>
+ </method>
+ <method name="get_menu_popup" qualifiers="const">
+ <return type="PopupMenu" />
+ <param index="0" name="menu" type="int" />
+ <description>
+ Returns [PopupMenu] associated with menu item.
+ </description>
+ </method>
+ <method name="get_menu_title" qualifiers="const">
+ <return type="String" />
+ <param index="0" name="menu" type="int" />
+ <description>
+ Returns menu item title.
+ </description>
+ </method>
+ <method name="get_menu_tooltip" qualifiers="const">
+ <return type="String" />
+ <param index="0" name="menu" type="int" />
+ <description>
+ Returns menu item tooltip.
+ </description>
+ </method>
+ <method name="is_menu_disabled" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="menu" type="int" />
+ <description>
+ Returns [code]true[/code], if menu item is disabled.
+ </description>
+ </method>
+ <method name="is_menu_hidden" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="menu" type="int" />
+ <description>
+ Returns [code]true[/code], if menu item is hidden.
+ </description>
+ </method>
+ <method name="is_native_menu" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code], if system global menu is supported and used by this [MenuBar].
+ </description>
+ </method>
+ <method name="set_disable_shortcuts">
+ <return type="void" />
+ <param index="0" name="disabled" type="bool" />
+ <description>
+ If [code]true[/code], shortcuts are disabled and cannot be used to trigger the button.
+ </description>
+ </method>
+ <method name="set_menu_disabled">
+ <return type="void" />
+ <param index="0" name="menu" type="int" />
+ <param index="1" name="disabled" type="bool" />
+ <description>
+ If [code]true[/code], menu item is disabled.
+ </description>
+ </method>
+ <method name="set_menu_hidden">
+ <return type="void" />
+ <param index="0" name="menu" type="int" />
+ <param index="1" name="hidden" type="bool" />
+ <description>
+ If [code]true[/code], menu item is hidden.
+ </description>
+ </method>
+ <method name="set_menu_title">
+ <return type="void" />
+ <param index="0" name="menu" type="int" />
+ <param index="1" name="title" type="String" />
+ <description>
+ Sets menu item title.
+ </description>
+ </method>
+ <method name="set_menu_tooltip">
+ <return type="void" />
+ <param index="0" name="menu" type="int" />
+ <param index="1" name="tooltip" type="String" />
+ <description>
+ Sets menu item tooltip.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="flat" type="bool" setter="set_flat" getter="is_flat" default="false">
+ Flat [MenuBar] don't display item decoration.
+ </member>
+ <member name="language" type="String" setter="set_language" getter="get_language" default="&quot;&quot;">
+ Language code used for line-breaking and text shaping algorithms, if left empty current locale is used instead.
+ </member>
+ <member name="prefer_global_menu" type="bool" setter="set_prefer_global_menu" getter="is_prefer_global_menu" default="true">
+ If [code]true[/code], [MenuBar] will use system global menu when supported.
+ </member>
+ <member name="shortcut_context" type="Node" setter="set_shortcut_context" getter="get_shortcut_context">
+ The [Node] which must be a parent of the focused GUI [Control] for the shortcut to be activated. If [code]null[/code], the shortcut can be activated when any control is focused (a global shortcut). This allows shortcuts to be accepted only when the user has a certain area of the GUI focused.
+ </member>
+ <member name="start_index" type="int" setter="set_start_index" getter="get_start_index" default="-1">
+ Position in the global menu to insert first [MenuBar] item at.
+ </member>
+ <member name="switch_on_hover" type="bool" setter="set_switch_on_hover" getter="is_switch_on_hover" default="true">
+ If [code]true[/code], when the cursor hovers above menu item, it will close the current [PopupMenu] and open the other one.
+ </member>
+ <member name="text_direction" type="int" setter="set_text_direction" getter="get_text_direction" enum="Control.TextDirection" default="0">
+ Base text writing direction.
+ </member>
+ </members>
+ <theme_items>
+ <theme_item name="font_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 1)">
+ Default text [Color] of the menu item.
+ </theme_item>
+ <theme_item name="font_disabled_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 0.5)">
+ Text [Color] used when the menu item is disabled.
+ </theme_item>
+ <theme_item name="font_focus_color" data_type="color" type="Color" default="Color(0.95, 0.95, 0.95, 1)">
+ Text [Color] used when the menu item is focused. Only replaces the normal text color of the menu item. Disabled, hovered, and pressed states take precedence over this color.
+ </theme_item>
+ <theme_item name="font_hover_color" data_type="color" type="Color" default="Color(0.95, 0.95, 0.95, 1)">
+ Text [Color] used when the menu item is being hovered.
+ </theme_item>
+ <theme_item name="font_hover_pressed_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
+ Text [Color] used when the menu item is being hovered and pressed.
+ </theme_item>
+ <theme_item name="font_outline_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
+ The tint of text outline of the menu item.
+ </theme_item>
+ <theme_item name="font_pressed_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
+ Text [Color] used when the menu item is being pressed.
+ </theme_item>
+ <theme_item name="h_separation" data_type="constant" type="int" default="4">
+ The horizontal space between menu items.
+ </theme_item>
+ <theme_item name="outline_size" data_type="constant" type="int" default="0">
+ The size of the text outline.
+ </theme_item>
+ <theme_item name="font" data_type="font" type="Font">
+ [Font] of the menu item's text.
+ </theme_item>
+ <theme_item name="font_size" data_type="font_size" type="int">
+ Font size of the menu item's text.
+ </theme_item>
+ <theme_item name="disabled" data_type="style" type="StyleBox">
+ [StyleBox] used when the menu item is disabled.
+ </theme_item>
+ <theme_item name="focus" data_type="style" type="StyleBox">
+ [StyleBox] used when the menu item is focused. The [code]focus[/code] [StyleBox] is displayed [i]over[/i] the base [StyleBox], so a partially transparent [StyleBox] should be used to ensure the base [StyleBox] remains visible. A [StyleBox] that represents an outline or an underline works well for this purpose. To disable the focus visual effect, assign a [StyleBoxEmpty] resource. Note that disabling the focus visual effect will harm keyboard/controller navigation usability, so this is not recommended for accessibility reasons.
+ </theme_item>
+ <theme_item name="hover" data_type="style" type="StyleBox">
+ [StyleBox] used when the menu item is being hovered.
+ </theme_item>
+ <theme_item name="normal" data_type="style" type="StyleBox">
+ Default [StyleBox] for the menu item.
+ </theme_item>
+ <theme_item name="pressed" data_type="style" type="StyleBox">
+ [StyleBox] used when the menu item is being pressed.
+ </theme_item>
+ </theme_items>
+</class>
diff --git a/doc/classes/MenuButton.xml b/doc/classes/MenuButton.xml
index bec567b3ef..1f38510e83 100644
--- a/doc/classes/MenuButton.xml
+++ b/doc/classes/MenuButton.xml
@@ -20,7 +20,7 @@
</method>
<method name="set_disable_shortcuts">
<return type="void" />
- <argument index="0" name="disabled" type="bool" />
+ <param index="0" name="disabled" type="bool" />
<description>
If [code]true[/code], shortcuts are disabled and cannot be used to trigger the button.
</description>
@@ -65,7 +65,7 @@
Text [Color] used when the [MenuButton] is being pressed.
</theme_item>
<theme_item name="h_separation" data_type="constant" type="int" default="3">
- The horizontal space between [MenuButton]'s icon and text.
+ The horizontal space between [MenuButton]'s icon and text. Negative values will be treated as [code]0[/code] when used.
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline.
diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml
index 48fa2754d5..d3d5a7bfaa 100644
--- a/doc/classes/Mesh.xml
+++ b/doc/classes/Mesh.xml
@@ -25,7 +25,7 @@
</method>
<method name="_get_blend_shape_name" qualifiers="virtual const">
<return type="StringName" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
</description>
</method>
@@ -36,79 +36,79 @@
</method>
<method name="_set_blend_shape_name" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="name" type="StringName" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="name" type="StringName" />
<description>
</description>
</method>
<method name="_surface_get_array_index_len" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
</description>
</method>
<method name="_surface_get_array_len" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
</description>
</method>
<method name="_surface_get_arrays" qualifiers="virtual const">
<return type="Array" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
</description>
</method>
<method name="_surface_get_blend_shape_arrays" qualifiers="virtual const">
- <return type="Array" />
- <argument index="0" name="index" type="int" />
+ <return type="Array[]" />
+ <param index="0" name="index" type="int" />
<description>
</description>
</method>
<method name="_surface_get_format" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
</description>
</method>
<method name="_surface_get_lods" qualifiers="virtual const">
<return type="Dictionary" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
</description>
</method>
<method name="_surface_get_material" qualifiers="virtual const">
<return type="Material" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
</description>
</method>
<method name="_surface_get_primitive_type" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
</description>
</method>
<method name="_surface_set_material" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="material" type="Material" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="material" type="Material" />
<description>
</description>
</method>
<method name="create_convex_shape" qualifiers="const">
<return type="Shape3D" />
- <argument index="0" name="clean" type="bool" default="true" />
- <argument index="1" name="simplify" type="bool" default="false" />
+ <param index="0" name="clean" type="bool" default="true" />
+ <param index="1" name="simplify" type="bool" default="false" />
<description>
Calculate a [ConvexPolygonShape3D] from the mesh.
- If [code]clean[/code] is [code]true[/code] (default), duplicate and interior vertices are removed automatically. You can set it to [code]false[/code] to make the process faster if not needed.
- If [code]simplify[/code] is [code]true[/code], the geometry can be further simplified to reduce the amount of vertices. Disabled by default.
+ If [param clean] is [code]true[/code] (default), duplicate and interior vertices are removed automatically. You can set it to [code]false[/code] to make the process faster if not needed.
+ If [param simplify] is [code]true[/code], the geometry can be further simplified to reduce the number of vertices. Disabled by default.
</description>
</method>
<method name="create_outline" qualifiers="const">
<return type="Mesh" />
- <argument index="0" name="margin" type="float" />
+ <param index="0" name="margin" type="float" />
<description>
Calculate an outline mesh at a defined offset (margin) from the original mesh.
[b]Note:[/b] This method typically returns the vertices in reverse order (e.g. clockwise to counterclockwise).
@@ -142,34 +142,34 @@
<method name="get_surface_count" qualifiers="const">
<return type="int" />
<description>
- Returns the amount of surfaces that the [Mesh] holds.
+ Returns the number of surfaces that the [Mesh] holds.
</description>
</method>
<method name="surface_get_arrays" qualifiers="const">
<return type="Array" />
- <argument index="0" name="surf_idx" type="int" />
+ <param index="0" name="surf_idx" type="int" />
<description>
Returns the arrays for the vertices, normals, uvs, etc. that make up the requested surface (see [method ArrayMesh.add_surface_from_arrays]).
</description>
</method>
<method name="surface_get_blend_shape_arrays" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="surf_idx" type="int" />
+ <return type="Array[]" />
+ <param index="0" name="surf_idx" type="int" />
<description>
Returns the blend shape arrays for the requested surface.
</description>
</method>
<method name="surface_get_material" qualifiers="const">
<return type="Material" />
- <argument index="0" name="surf_idx" type="int" />
+ <param index="0" name="surf_idx" type="int" />
<description>
Returns a [Material] in a given surface. Surface is rendered using this material.
</description>
</method>
<method name="surface_set_material">
<return type="void" />
- <argument index="0" name="surf_idx" type="int" />
- <argument index="1" name="material" type="Material" />
+ <param index="0" name="surf_idx" type="int" />
+ <param index="1" name="material" type="Material" />
<description>
Sets a [Material] for a given surface. Surface will be rendered using this material.
</description>
diff --git a/doc/classes/MeshDataTool.xml b/doc/classes/MeshDataTool.xml
index 0042bb20d8..b46f080a10 100644
--- a/doc/classes/MeshDataTool.xml
+++ b/doc/classes/MeshDataTool.xml
@@ -59,15 +59,15 @@
</method>
<method name="commit_to_surface">
<return type="int" enum="Error" />
- <argument index="0" name="mesh" type="ArrayMesh" />
+ <param index="0" name="mesh" type="ArrayMesh" />
<description>
Adds a new surface to specified [Mesh] with edited data.
</description>
</method>
<method name="create_from_surface">
<return type="int" enum="Error" />
- <argument index="0" name="mesh" type="ArrayMesh" />
- <argument index="1" name="surface" type="int" />
+ <param index="0" name="mesh" type="ArrayMesh" />
+ <param index="1" name="surface" type="int" />
<description>
Uses specified surface of given [Mesh] to populate data for MeshDataTool.
Requires [Mesh] with primitive type [constant Mesh.PRIMITIVE_TRIANGLES].
@@ -81,22 +81,22 @@
</method>
<method name="get_edge_faces" qualifiers="const">
<return type="PackedInt32Array" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns array of faces that touch given edge.
</description>
</method>
<method name="get_edge_meta" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns meta information assigned to given edge.
</description>
</method>
<method name="get_edge_vertex" qualifiers="const">
<return type="int" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="vertex" type="int" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="vertex" type="int" />
<description>
Returns index of specified vertex connected to given edge.
Vertex argument can only be 0 or 1 because edges are comprised of two vertices.
@@ -110,8 +110,8 @@
</method>
<method name="get_face_edge" qualifiers="const">
<return type="int" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="edge" type="int" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="edge" type="int" />
<description>
Returns specified edge associated with given face.
Edge argument must be either 0, 1, or 2 because a face only has three edges.
@@ -119,22 +119,22 @@
</method>
<method name="get_face_meta" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns the metadata associated with the given face.
</description>
</method>
<method name="get_face_normal" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Calculates and returns the face normal of the given face.
</description>
</method>
<method name="get_face_vertex" qualifiers="const">
<return type="int" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="vertex" type="int" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="vertex" type="int" />
<description>
Returns the specified vertex of the given face.
Vertex argument must be either 0, 1, or 2 because faces contain three vertices.
@@ -155,21 +155,21 @@
</method>
<method name="get_vertex" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns the vertex at given index.
</description>
</method>
<method name="get_vertex_bones" qualifiers="const">
<return type="PackedInt32Array" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns the bones of the given vertex.
</description>
</method>
<method name="get_vertex_color" qualifiers="const">
<return type="Color" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns the color of the given vertex.
</description>
@@ -182,151 +182,151 @@
</method>
<method name="get_vertex_edges" qualifiers="const">
<return type="PackedInt32Array" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns an array of edges that share the given vertex.
</description>
</method>
<method name="get_vertex_faces" qualifiers="const">
<return type="PackedInt32Array" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns an array of faces that share the given vertex.
</description>
</method>
<method name="get_vertex_meta" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns the metadata associated with the given vertex.
</description>
</method>
<method name="get_vertex_normal" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns the normal of the given vertex.
</description>
</method>
<method name="get_vertex_tangent" qualifiers="const">
<return type="Plane" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns the tangent of the given vertex.
</description>
</method>
<method name="get_vertex_uv" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns the UV of the given vertex.
</description>
</method>
<method name="get_vertex_uv2" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns the UV2 of the given vertex.
</description>
</method>
<method name="get_vertex_weights" qualifiers="const">
<return type="PackedFloat32Array" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns bone weights of the given vertex.
</description>
</method>
<method name="set_edge_meta">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="meta" type="Variant" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="meta" type="Variant" />
<description>
Sets the metadata of the given edge.
</description>
</method>
<method name="set_face_meta">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="meta" type="Variant" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="meta" type="Variant" />
<description>
Sets the metadata of the given face.
</description>
</method>
<method name="set_material">
<return type="void" />
- <argument index="0" name="material" type="Material" />
+ <param index="0" name="material" type="Material" />
<description>
Sets the material to be used by newly-constructed [Mesh].
</description>
</method>
<method name="set_vertex">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="vertex" type="Vector3" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="vertex" type="Vector3" />
<description>
Sets the position of the given vertex.
</description>
</method>
<method name="set_vertex_bones">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="bones" type="PackedInt32Array" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="bones" type="PackedInt32Array" />
<description>
Sets the bones of the given vertex.
</description>
</method>
<method name="set_vertex_color">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="color" type="Color" />
<description>
Sets the color of the given vertex.
</description>
</method>
<method name="set_vertex_meta">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="meta" type="Variant" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="meta" type="Variant" />
<description>
Sets the metadata associated with the given vertex.
</description>
</method>
<method name="set_vertex_normal">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="normal" type="Vector3" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="normal" type="Vector3" />
<description>
Sets the normal of the given vertex.
</description>
</method>
<method name="set_vertex_tangent">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="tangent" type="Plane" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="tangent" type="Plane" />
<description>
Sets the tangent of the given vertex.
</description>
</method>
<method name="set_vertex_uv">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="uv" type="Vector2" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="uv" type="Vector2" />
<description>
Sets the UV of the given vertex.
</description>
</method>
<method name="set_vertex_uv2">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="uv2" type="Vector2" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="uv2" type="Vector2" />
<description>
Sets the UV2 of the given vertex.
</description>
</method>
<method name="set_vertex_weights">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="weights" type="PackedFloat32Array" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="weights" type="PackedFloat32Array" />
<description>
Sets the bone weights of the given vertex.
</description>
diff --git a/doc/classes/MeshInstance3D.xml b/doc/classes/MeshInstance3D.xml
index 24f1f9918b..618503c8df 100644
--- a/doc/classes/MeshInstance3D.xml
+++ b/doc/classes/MeshInstance3D.xml
@@ -15,12 +15,12 @@
<methods>
<method name="create_convex_collision">
<return type="void" />
- <argument index="0" name="clean" type="bool" default="true" />
- <argument index="1" name="simplify" type="bool" default="false" />
+ <param index="0" name="clean" type="bool" default="true" />
+ <param index="1" name="simplify" type="bool" default="false" />
<description>
This helper creates a [StaticBody3D] child node with a [ConvexPolygonShape3D] collision shape calculated from the mesh geometry. It's mainly used for testing.
- If [code]clean[/code] is [code]true[/code] (default), duplicate and interior vertices are removed automatically. You can set it to [code]false[/code] to make the process faster if not needed.
- If [code]simplify[/code] is [code]true[/code], the geometry can be further simplified to reduce the amount of vertices. Disabled by default.
+ If [param clean] is [code]true[/code] (default), duplicate and interior vertices are removed automatically. You can set it to [code]false[/code] to make the process faster if not needed.
+ If [param simplify] is [code]true[/code], the geometry can be further simplified to reduce the number of vertices. Disabled by default.
</description>
</method>
<method name="create_debug_tangents">
@@ -43,13 +43,13 @@
</method>
<method name="find_blend_shape_by_name">
<return type="int" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
</description>
</method>
<method name="get_active_material" qualifiers="const">
<return type="Material" />
- <argument index="0" name="surface" type="int" />
+ <param index="0" name="surface" type="int" />
<description>
Returns the [Material] that will be used by the [Mesh] when drawing. This can return the [member GeometryInstance3D.material_override], the surface override [Material] defined in this [MeshInstance3D], or the surface [Material] defined in the [Mesh]. For example, if [member GeometryInstance3D.material_override] is used, all surfaces will return the override material.
</description>
@@ -61,13 +61,13 @@
</method>
<method name="get_blend_shape_value" qualifiers="const">
<return type="float" />
- <argument index="0" name="blend_shape_idx" type="int" />
+ <param index="0" name="blend_shape_idx" type="int" />
<description>
</description>
</method>
<method name="get_surface_override_material" qualifiers="const">
<return type="Material" />
- <argument index="0" name="surface" type="int" />
+ <param index="0" name="surface" type="int" />
<description>
Returns the override [Material] for the specified surface of the [Mesh] resource.
</description>
@@ -80,15 +80,15 @@
</method>
<method name="set_blend_shape_value">
<return type="void" />
- <argument index="0" name="blend_shape_idx" type="int" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="blend_shape_idx" type="int" />
+ <param index="1" name="value" type="float" />
<description>
</description>
</method>
<method name="set_surface_override_material">
<return type="void" />
- <argument index="0" name="surface" type="int" />
- <argument index="1" name="material" type="Material" />
+ <param index="0" name="surface" type="int" />
+ <param index="1" name="material" type="Material" />
<description>
Sets the override [Material] for the specified surface of the [Mesh] resource. This material is associated with this [MeshInstance3D] rather than with the [Mesh] resource.
</description>
diff --git a/doc/classes/MeshLibrary.xml b/doc/classes/MeshLibrary.xml
index 6b25441a16..85e57dd0f3 100644
--- a/doc/classes/MeshLibrary.xml
+++ b/doc/classes/MeshLibrary.xml
@@ -19,7 +19,7 @@
</method>
<method name="create_item">
<return type="void" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Creates a new item in the library with the given ID.
You can get an unused ID from [method get_last_unused_item_id].
@@ -27,7 +27,7 @@
</method>
<method name="find_item_by_name" qualifiers="const">
<return type="int" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
Returns the first item with the given name.
</description>
@@ -40,49 +40,49 @@
</method>
<method name="get_item_mesh" qualifiers="const">
<return type="Mesh" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Returns the item's mesh.
</description>
</method>
<method name="get_item_mesh_transform" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Returns the transform applied to the item's mesh.
</description>
</method>
<method name="get_item_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Returns the item's name.
</description>
</method>
<method name="get_item_navmesh" qualifiers="const">
<return type="NavigationMesh" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Returns the item's navigation mesh.
</description>
</method>
<method name="get_item_navmesh_transform" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Returns the transform applied to the item's navigation mesh.
</description>
</method>
<method name="get_item_preview" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
When running in the editor, returns a generated item preview (a 3D rendering in isometric perspective). When used in a running project, returns the manually-defined item preview which can be set using [method set_item_preview]. Returns an empty [Texture2D] if no preview was manually set in a running project.
</description>
</method>
<method name="get_item_shapes" qualifiers="const">
<return type="Array" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Returns an item's collision shapes.
The array consists of each [Shape3D] followed by its [Transform3D].
@@ -96,31 +96,31 @@
</method>
<method name="remove_item">
<return type="void" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Removes the item.
</description>
</method>
<method name="set_item_mesh">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="mesh" type="Mesh" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="mesh" type="Mesh" />
<description>
Sets the item's mesh.
</description>
</method>
<method name="set_item_mesh_transform">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="mesh_transform" type="Transform3D" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="mesh_transform" type="Transform3D" />
<description>
Sets the transform to apply to the item's mesh.
</description>
</method>
<method name="set_item_name">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="name" type="String" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="name" type="String" />
<description>
Sets the item's name.
This name is shown in the editor. It can also be used to look up the item later using [method find_item_by_name].
@@ -128,32 +128,32 @@
</method>
<method name="set_item_navmesh">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="navmesh" type="NavigationMesh" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="navmesh" type="NavigationMesh" />
<description>
Sets the item's navigation mesh.
</description>
</method>
<method name="set_item_navmesh_transform">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="navmesh" type="Transform3D" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="navmesh" type="Transform3D" />
<description>
Sets the transform to apply to the item's navigation mesh.
</description>
</method>
<method name="set_item_preview">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="texture" type="Texture2D" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="texture" type="Texture2D" />
<description>
Sets a texture to use as the item's preview icon in the editor.
</description>
</method>
<method name="set_item_shapes">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="shapes" type="Array" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="shapes" type="Array" />
<description>
Sets an item's collision shapes.
The array should consist of [Shape3D] objects, each followed by a [Transform3D] that will be applied to it. For shapes that should not have a transform, use [constant Transform3D.IDENTITY].
diff --git a/doc/classes/MethodTweener.xml b/doc/classes/MethodTweener.xml
index b22341e0a1..7e042b5eb6 100644
--- a/doc/classes/MethodTweener.xml
+++ b/doc/classes/MethodTweener.xml
@@ -12,21 +12,21 @@
<methods>
<method name="set_delay">
<return type="MethodTweener" />
- <argument index="0" name="delay" type="float" />
+ <param index="0" name="delay" type="float" />
<description>
Sets the time in seconds after which the [MethodTweener] will start interpolating. By default there's no delay.
</description>
</method>
<method name="set_ease">
<return type="MethodTweener" />
- <argument index="0" name="ease" type="int" enum="Tween.EaseType" />
+ <param index="0" name="ease" type="int" enum="Tween.EaseType" />
<description>
Sets the type of used easing from [enum Tween.EaseType]. If not set, the default easing is used from the [Tween] that contains this Tweener.
</description>
</method>
<method name="set_trans">
<return type="MethodTweener" />
- <argument index="0" name="trans" type="int" enum="Tween.TransitionType" />
+ <param index="0" name="trans" type="int" enum="Tween.TransitionType" />
<description>
Sets the type of used transition from [enum Tween.TransitionType]. If not set, the default transition is used from the [Tween] that contains this Tweener.
</description>
diff --git a/doc/classes/MovieWriter.xml b/doc/classes/MovieWriter.xml
index d47e52d7c0..f2509ad2b2 100644
--- a/doc/classes/MovieWriter.xml
+++ b/doc/classes/MovieWriter.xml
@@ -29,9 +29,9 @@
</method>
<method name="_handles_file" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
- Called when the engine determines whether this [MovieWriter] is able to handle the file at [code]path[/code]. Must return [code]true[/code] if this [MovieWriter] is able to handle the given file path, [code]false[/code] otherwise. Typically, [method _handles_file] is overridden as follows to allow the user to record a file at any path with a given file extension:
+ Called when the engine determines whether this [MovieWriter] is able to handle the file at [param path]. Must return [code]true[/code] if this [MovieWriter] is able to handle the given file path, [code]false[/code] otherwise. Typically, [method _handles_file] is overridden as follows to allow the user to record a file at any path with a given file extension:
[codeblock]
func _handles_file(path):
# Allows specifying an output file with a `.mkv` file extension (case-insensitive),
@@ -42,11 +42,11 @@
</method>
<method name="_write_begin" qualifiers="virtual">
<return type="int" enum="Error" />
- <argument index="0" name="movie_size" type="Vector2i" />
- <argument index="1" name="fps" type="int" />
- <argument index="2" name="base_path" type="String" />
+ <param index="0" name="movie_size" type="Vector2i" />
+ <param index="1" name="fps" type="int" />
+ <param index="2" name="base_path" type="String" />
<description>
- Called once before the engine starts writing video and audio data. [code]movie_size[/code] is the width and height of the video to save. [code]fps[/code] is the number of frames per second specified in the project settings or using the [code]--fixed-fps &lt;fps&gt;[/code] command line argument.
+ Called once before the engine starts writing video and audio data. [param movie_size] is the width and height of the video to save. [param fps] is the number of frames per second specified in the project settings or using the [code]--fixed-fps &lt;fps&gt;[/code] command line argument.
</description>
</method>
<method name="_write_end" qualifiers="virtual">
@@ -58,15 +58,15 @@
</method>
<method name="_write_frame" qualifiers="virtual">
<return type="int" enum="Error" />
- <argument index="0" name="frame_image" type="Image" />
- <argument index="1" name="audio_frame_block" type="const void*" />
+ <param index="0" name="frame_image" type="Image" />
+ <param index="1" name="audio_frame_block" type="const void*" />
<description>
- Called at the end of every rendered frame. The [code]frame_image[/code] and [code]audio_frame_block[/code] function arguments should be written to.
+ Called at the end of every rendered frame. The [param frame_image] and [param audio_frame_block] function arguments should be written to.
</description>
</method>
<method name="add_writer" qualifiers="static">
<return type="void" />
- <argument index="0" name="writer" type="MovieWriter" />
+ <param index="0" name="writer" type="MovieWriter" />
<description>
Adds a writer to be usable by the engine. The supported file extensions can be set by overriding [method _handles_file].
[b]Note:[/b] [method add_writer] must be called early enough in the engine initialization to work, as movie writing is designed to start at the same time as the rest of the engine.
diff --git a/doc/classes/MultiMesh.xml b/doc/classes/MultiMesh.xml
index 9d8f1e1e5d..bae2335cfb 100644
--- a/doc/classes/MultiMesh.xml
+++ b/doc/classes/MultiMesh.xml
@@ -22,45 +22,45 @@
</method>
<method name="get_instance_color" qualifiers="const">
<return type="Color" />
- <argument index="0" name="instance" type="int" />
+ <param index="0" name="instance" type="int" />
<description>
Gets a specific instance's color.
</description>
</method>
<method name="get_instance_custom_data" qualifiers="const">
<return type="Color" />
- <argument index="0" name="instance" type="int" />
+ <param index="0" name="instance" type="int" />
<description>
Returns the custom data that has been set for a specific instance.
</description>
</method>
<method name="get_instance_transform" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="instance" type="int" />
+ <param index="0" name="instance" type="int" />
<description>
Returns the [Transform3D] of a specific instance.
</description>
</method>
<method name="get_instance_transform_2d" qualifiers="const">
<return type="Transform2D" />
- <argument index="0" name="instance" type="int" />
+ <param index="0" name="instance" type="int" />
<description>
Returns the [Transform2D] of a specific instance.
</description>
</method>
<method name="set_instance_color">
<return type="void" />
- <argument index="0" name="instance" type="int" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="instance" type="int" />
+ <param index="1" name="color" type="Color" />
<description>
Sets the color of a specific instance by [i]multiplying[/i] the mesh's existing vertex colors.
- For the color to take effect, ensure that [member use_colors] is [code]true[/code] on the [MultiMesh] and [member BaseMaterial3D.vertex_color_use_as_albedo] is [code]true[/code] on the material.
+ For the color to take effect, ensure that [member use_colors] is [code]true[/code] on the [MultiMesh] and [member BaseMaterial3D.vertex_color_use_as_albedo] is [code]true[/code] on the material. If the color doesn't look as expected, make sure the material's albedo color is set to pure white ([code]Color(1, 1, 1)[/code]).
</description>
</method>
<method name="set_instance_custom_data">
<return type="void" />
- <argument index="0" name="instance" type="int" />
- <argument index="1" name="custom_data" type="Color" />
+ <param index="0" name="instance" type="int" />
+ <param index="1" name="custom_data" type="Color" />
<description>
Sets custom data for a specific instance. Although [Color] is used, it is just a container for 4 floating point numbers.
For the custom data to be used, ensure that [member use_custom_data] is [code]true[/code].
@@ -68,16 +68,16 @@
</method>
<method name="set_instance_transform">
<return type="void" />
- <argument index="0" name="instance" type="int" />
- <argument index="1" name="transform" type="Transform3D" />
+ <param index="0" name="instance" type="int" />
+ <param index="1" name="transform" type="Transform3D" />
<description>
Sets the [Transform3D] for a specific instance.
</description>
</method>
<method name="set_instance_transform_2d">
<return type="void" />
- <argument index="0" name="instance" type="int" />
- <argument index="1" name="transform" type="Transform2D" />
+ <param index="0" name="instance" type="int" />
+ <param index="1" name="transform" type="Transform2D" />
<description>
Sets the [Transform2D] for a specific instance.
</description>
diff --git a/doc/classes/MultiMeshInstance3D.xml b/doc/classes/MultiMeshInstance3D.xml
index 52cc9cb65f..70fbf235e2 100644
--- a/doc/classes/MultiMeshInstance3D.xml
+++ b/doc/classes/MultiMeshInstance3D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
[MultiMeshInstance3D] is a specialized node to instance [GeometryInstance3D]s based on a [MultiMesh] resource.
- 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).
+ This is useful to optimize the rendering of a high number of instances of a given mesh (for example trees in a forest or grass strands).
</description>
<tutorials>
<link title="Animating thousands of fish with MultiMeshInstance">$DOCS_URL/tutorials/performance/vertex_animation/animating_thousands_of_fish.html</link>
diff --git a/doc/classes/MultiplayerAPI.xml b/doc/classes/MultiplayerAPI.xml
index 06658bf004..3ce6ce41b4 100644
--- a/doc/classes/MultiplayerAPI.xml
+++ b/doc/classes/MultiplayerAPI.xml
@@ -57,19 +57,19 @@
</method>
<method name="object_configuration_add">
<return type="int" enum="Error" />
- <argument index="0" name="object" type="Object" />
- <argument index="1" name="configuration" type="Variant" />
+ <param index="0" name="object" type="Object" />
+ <param index="1" name="configuration" type="Variant" />
<description>
- Notifies the MultiplayerAPI of a new [code]configuration[/code] for the given [code]object[/code]. This method is used internally by [SceneTree] to configure the root path for this MultiplayerAPI (passing [code]null[/code] and a valid [NodePath] as [code]configuration[/code]). This method can be further used by MultiplayerAPI implementations to provide additional features, refer to specific implementation (e.g. [SceneMultiplayer]) for details on how they use it.
+ Notifies the MultiplayerAPI of a new [param configuration] for the given [param object]. This method is used internally by [SceneTree] to configure the root path for this MultiplayerAPI (passing [code]null[/code] and a valid [NodePath] as [param configuration]). This method can be further used by MultiplayerAPI implementations to provide additional features, refer to specific implementation (e.g. [SceneMultiplayer]) for details on how they use it.
[b]Note:[/b] This method is mostly relevant when extending or overriding the MultiplayerAPI behavior via [MultiplayerAPIExtension].
</description>
</method>
<method name="object_configuration_remove">
<return type="int" enum="Error" />
- <argument index="0" name="object" type="Object" />
- <argument index="1" name="configuration" type="Variant" />
+ <param index="0" name="object" type="Object" />
+ <param index="1" name="configuration" type="Variant" />
<description>
- Notifies the MultiplayerAPI to remove a [code]configuration[/code] for the given [code]object[/code]. This method is used internally by [SceneTree] to configure the root path for this MultiplayerAPI (passing [code]null[/code] and an empty [NodePath] as [code]configuration[/code]). This method can be further used by MultiplayerAPI implementations to provide additional features, refer to specific implementation (e.g. [SceneMultiplayer]) for details on how they use it.
+ Notifies the MultiplayerAPI to remove a [param configuration] for the given [param object]. This method is used internally by [SceneTree] to configure the root path for this MultiplayerAPI (passing [code]null[/code] and an empty [NodePath] as [param configuration]). This method can be further used by MultiplayerAPI implementations to provide additional features, refer to specific implementation (e.g. [SceneMultiplayer]) for details on how they use it.
[b]Note:[/b] This method is mostly relevant when extending or overriding the MultiplayerAPI behavior via [MultiplayerAPIExtension].
</description>
</method>
@@ -82,18 +82,18 @@
</method>
<method name="rpc">
<return type="int" enum="Error" />
- <argument index="0" name="peer" type="int" />
- <argument index="1" name="object" type="Object" />
- <argument index="2" name="method" type="StringName" />
- <argument index="3" name="arguments" type="Array" default="[]" />
+ <param index="0" name="peer" type="int" />
+ <param index="1" name="object" type="Object" />
+ <param index="2" name="method" type="StringName" />
+ <param index="3" name="arguments" type="Array" default="[]" />
<description>
- Sends an RPC to the target [code]peer[/code]. The given [code]method[/code] will be called on the remote [code]object[/code] with the provided [code]arguments[/code]. The RPC may also be called locally depending on the implementation and RPC configuration. See [method Node.rpc] and [method Node.rpc_config].
+ Sends an RPC to the target [param peer]. The given [param method] will be called on the remote [param object] with the provided [param arguments]. The RPC may also be called locally depending on the implementation and RPC configuration. See [method Node.rpc] and [method Node.rpc_config].
[b]Note:[/b] Prefer using [method Node.rpc], [method Node.rpc_id], or [code]my_method.rpc(peer, arg1, arg2, ...)[/code] (in GDScript), since they are faster. This method is mostly useful in conjunction with [MultiplayerAPIExtension] when augmenting or replacing the multiplayer capabilities.
</description>
</method>
<method name="set_default_interface" qualifiers="static">
<return type="void" />
- <argument index="0" name="interface_name" type="StringName" />
+ <param index="0" name="interface_name" type="StringName" />
<description>
Sets the default MultiplayerAPI implementation class. This method can be used by modules and extensions to configure which implementation will be used by [SceneTree] when the engine starts.
</description>
@@ -116,13 +116,13 @@
</description>
</signal>
<signal name="peer_connected">
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Emitted when this MultiplayerAPI's [member multiplayer_peer] connects with a new peer. ID is the peer ID of the new peer. Clients get notified when other clients connect to the same server. Upon connecting to a server, a client also receives this signal for the server (with ID being 1).
</description>
</signal>
<signal name="peer_disconnected">
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Emitted when this MultiplayerAPI's [member multiplayer_peer] disconnects from a peer. Clients get notified when other clients disconnect from the same server.
</description>
diff --git a/doc/classes/MultiplayerAPIExtension.xml b/doc/classes/MultiplayerAPIExtension.xml
index c369977d57..e67970cc89 100644
--- a/doc/classes/MultiplayerAPIExtension.xml
+++ b/doc/classes/MultiplayerAPIExtension.xml
@@ -100,16 +100,16 @@
</method>
<method name="_object_configuration_add" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="object" type="Object" />
- <argument index="1" name="configuration" type="Variant" />
+ <param index="0" name="object" type="Object" />
+ <param index="1" name="configuration" type="Variant" />
<description>
Callback for [method MultiplayerAPI.object_configuration_add].
</description>
</method>
<method name="_object_configuration_remove" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="object" type="Object" />
- <argument index="1" name="configuration" type="Variant" />
+ <param index="0" name="object" type="Object" />
+ <param index="1" name="configuration" type="Variant" />
<description>
Callback for [method MultiplayerAPI.object_configuration_remove].
</description>
@@ -122,17 +122,17 @@
</method>
<method name="_rpc" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="peer" type="int" />
- <argument index="1" name="object" type="Object" />
- <argument index="2" name="method" type="StringName" />
- <argument index="3" name="args" type="Array" />
+ <param index="0" name="peer" type="int" />
+ <param index="1" name="object" type="Object" />
+ <param index="2" name="method" type="StringName" />
+ <param index="3" name="args" type="Array" />
<description>
Callback for [method MultiplayerAPI.rpc].
</description>
</method>
<method name="_set_multiplayer_peer" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="multiplayer_peer" type="MultiplayerPeer" />
+ <param index="0" name="multiplayer_peer" type="MultiplayerPeer" />
<description>
Called when the [member MultiplayerAPI.multiplayer_peer] is set.
</description>
diff --git a/doc/classes/MultiplayerPeer.xml b/doc/classes/MultiplayerPeer.xml
index 6dde40f018..0f57ff9e55 100644
--- a/doc/classes/MultiplayerPeer.xml
+++ b/doc/classes/MultiplayerPeer.xml
@@ -45,10 +45,10 @@
</method>
<method name="set_target_peer">
<return type="void" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Sets the peer to which packets will be sent.
- The [code]id[/code] can be one of: [constant TARGET_PEER_BROADCAST] to send to all connected peers, [constant TARGET_PEER_SERVER] to send to the peer acting as server, a valid peer ID to send to that specific peer, a negative peer ID to send to all peers except that one. By default, the target peer is [constant TARGET_PEER_BROADCAST].
+ The [param id] can be one of: [constant TARGET_PEER_BROADCAST] to send to all connected peers, [constant TARGET_PEER_SERVER] to send to the peer acting as server, a valid peer ID to send to that specific peer, a negative peer ID to send to all peers except that one. By default, the target peer is [constant TARGET_PEER_BROADCAST].
</description>
</method>
</methods>
@@ -76,13 +76,13 @@
</description>
</signal>
<signal name="peer_connected">
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Emitted by the server when a client connects.
</description>
</signal>
<signal name="peer_disconnected">
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Emitted by the server when a client disconnects.
</description>
diff --git a/doc/classes/MultiplayerPeerExtension.xml b/doc/classes/MultiplayerPeerExtension.xml
index f837171e2f..3a193abd7d 100644
--- a/doc/classes/MultiplayerPeerExtension.xml
+++ b/doc/classes/MultiplayerPeerExtension.xml
@@ -29,10 +29,10 @@
</method>
<method name="_get_packet" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="r_buffer" type="const uint8_t **" />
- <argument index="1" name="r_buffer_size" type="int32_t*" />
+ <param index="0" name="r_buffer" type="const uint8_t **" />
+ <param index="1" name="r_buffer_size" type="int32_t*" />
<description>
- Called when a packet needs to be received by the [MultiplayerAPI], with [code]p_buffer_size[/code] being the size of the binary [code]p_buffer[/code] in bytes.
+ Called when a packet needs to be received by the [MultiplayerAPI], with [param r_buffer_size] being the size of the binary [param r_buffer] in bytes.
</description>
</method>
<method name="_get_packet_peer" qualifiers="virtual const">
@@ -85,43 +85,43 @@
</method>
<method name="_put_packet" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="p_buffer" type="const uint8_t*" />
- <argument index="1" name="p_buffer_size" type="int" />
+ <param index="0" name="p_buffer" type="const uint8_t*" />
+ <param index="1" name="p_buffer_size" type="int" />
<description>
- Called when a packet needs to be sent by the [MultiplayerAPI], with [code]p_buffer_size[/code] being the size of the binary [code]p_buffer[/code] in bytes.
+ Called when a packet needs to be sent by the [MultiplayerAPI], with [param p_buffer_size] being the size of the binary [param p_buffer] in bytes.
</description>
</method>
<method name="_put_packet_script" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="p_buffer" type="PackedByteArray" />
+ <param index="0" name="p_buffer" type="PackedByteArray" />
<description>
Called when a packet needs to be sent by the [MultiplayerAPI], if [method _put_packet] isn't implemented. Use this when extending this class via GDScript.
</description>
</method>
<method name="_set_refuse_new_connections" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="p_enable" type="bool" />
+ <param index="0" name="p_enable" type="bool" />
<description>
Called when the "refuse new connections" status is set on this [MultiplayerPeer] (see [member MultiplayerPeer.refuse_new_connections]).
</description>
</method>
<method name="_set_target_peer" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="p_peer" type="int" />
+ <param index="0" name="p_peer" type="int" />
<description>
Called when the target peer to use is set for this [MultiplayerPeer] (see [method MultiplayerPeer.set_target_peer]).
</description>
</method>
<method name="_set_transfer_channel" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="p_channel" type="int" />
+ <param index="0" name="p_channel" type="int" />
<description>
Called when the channel to use is set for this [MultiplayerPeer] (see [member MultiplayerPeer.transfer_channel]).
</description>
</method>
<method name="_set_transfer_mode" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="p_mode" type="int" />
+ <param index="0" name="p_mode" type="int" />
<description>
Called when the transfer mode is set on this [MultiplayerPeer] (see [member MultiplayerPeer.transfer_mode]).
</description>
diff --git a/doc/classes/NativeExtension.xml b/doc/classes/NativeExtension.xml
index e5e11c1c95..50f976ca6f 100644
--- a/doc/classes/NativeExtension.xml
+++ b/doc/classes/NativeExtension.xml
@@ -19,7 +19,7 @@
</method>
<method name="initialize_library">
<return type="void" />
- <argument index="0" name="level" type="int" enum="NativeExtension.InitializationLevel" />
+ <param index="0" name="level" type="int" enum="NativeExtension.InitializationLevel" />
<description>
</description>
</method>
@@ -30,8 +30,8 @@
</method>
<method name="open_library">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="entry_symbol" type="String" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="entry_symbol" type="String" />
<description>
</description>
</method>
diff --git a/doc/classes/NativeExtensionManager.xml b/doc/classes/NativeExtensionManager.xml
index 10c9e32cf2..7d6eefa94f 100644
--- a/doc/classes/NativeExtensionManager.xml
+++ b/doc/classes/NativeExtensionManager.xml
@@ -9,7 +9,7 @@
<methods>
<method name="get_extension">
<return type="NativeExtension" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
</description>
</method>
@@ -20,25 +20,25 @@
</method>
<method name="is_extension_loaded" qualifiers="const">
<return type="bool" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
</description>
</method>
<method name="load_extension">
<return type="int" enum="NativeExtensionManager.LoadStatus" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
</description>
</method>
<method name="reload_extension">
<return type="int" enum="NativeExtensionManager.LoadStatus" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
</description>
</method>
<method name="unload_extension">
<return type="int" enum="NativeExtensionManager.LoadStatus" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
</description>
</method>
diff --git a/doc/classes/NavigationAgent2D.xml b/doc/classes/NavigationAgent2D.xml
index 058f1032cb..bf3aff2c58 100644
--- a/doc/classes/NavigationAgent2D.xml
+++ b/doc/classes/NavigationAgent2D.xml
@@ -36,9 +36,9 @@
</method>
<method name="get_navigation_layer_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
- Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [code]layer_number[/code] between 1 and 32.
+ Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="get_navigation_map" qualifiers="const">
@@ -85,29 +85,29 @@
</method>
<method name="set_navigation_layer_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
- Based on [code]value[/code], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [code]layer_number[/code] between 1 and 32.
+ Based on [param value], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="set_navigation_map">
<return type="void" />
- <argument index="0" name="navigation_map" type="RID" />
+ <param index="0" name="navigation_map" type="RID" />
<description>
Sets the [RID] of the navigation map this NavigationAgent node should use and also updates the [code]agent[/code] on the NavigationServer.
</description>
</method>
<method name="set_target_location">
<return type="void" />
- <argument index="0" name="location" type="Vector2" />
+ <param index="0" name="location" type="Vector2" />
<description>
Sets the user desired final location. This will clear the current navigation path.
</description>
</method>
<method name="set_velocity">
<return type="void" />
- <argument index="0" name="velocity" type="Vector2" />
+ <param index="0" name="velocity" type="Vector2" />
<description>
Sends the passed in velocity to the collision avoidance algorithm. It will adjust the velocity to avoid collisions. Once the adjustment to the velocity is complete, it will emit the [signal velocity_computed] signal.
</description>
@@ -126,7 +126,7 @@
<member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1">
A bitfield determining what navigation layers of navigation regions this agent will use to calculate path. Changing it runtime will clear current navigation path and generate new one, according to new navigation layers.
</member>
- <member name="neighbor_dist" type="float" setter="set_neighbor_dist" getter="get_neighbor_dist" default="500.0">
+ <member name="neighbor_distance" type="float" setter="set_neighbor_distance" getter="get_neighbor_distance" default="500.0">
The distance to search for other agents.
</member>
<member name="path_desired_distance" type="float" setter="set_path_desired_distance" getter="get_path_desired_distance" default="1.0">
@@ -136,7 +136,7 @@
The maximum distance the agent is allowed away from the ideal path to the final location. This can happen due to trying to avoid collisions. When the maximum distance is exceeded, it recalculates the ideal path.
</member>
<member name="radius" type="float" setter="set_radius" getter="get_radius" default="10.0">
- The radius of the avoidance agent. This is the "body" of the avoidance agent and not the avoidance maneuver starting radius (which is controlled by [member neighbor_dist]).
+ The radius of the avoidance agent. This is the "body" of the avoidance agent and not the avoidance maneuver starting radius (which is controlled by [member neighbor_distance]).
Does not affect normal pathfinding. To change an actor's pathfinding radius bake [NavigationMesh] resources with a different [member NavigationMesh.agent_radius] property and use different navigation maps for each actor size.
</member>
<member name="target_desired_distance" type="float" setter="set_target_desired_distance" getter="get_target_desired_distance" default="1.0">
@@ -163,7 +163,7 @@
</description>
</signal>
<signal name="velocity_computed">
- <argument index="0" name="safe_velocity" type="Vector3" />
+ <param index="0" name="safe_velocity" type="Vector3" />
<description>
Notifies when the collision avoidance velocity is calculated. Emitted by [method set_velocity].
</description>
diff --git a/doc/classes/NavigationAgent3D.xml b/doc/classes/NavigationAgent3D.xml
index c689ddc345..7c48f0b52b 100644
--- a/doc/classes/NavigationAgent3D.xml
+++ b/doc/classes/NavigationAgent3D.xml
@@ -36,9 +36,9 @@
</method>
<method name="get_navigation_layer_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
- Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [code]layer_number[/code] between 1 and 32.
+ Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="get_navigation_map" qualifiers="const">
@@ -85,29 +85,29 @@
</method>
<method name="set_navigation_layer_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
- Based on [code]value[/code], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [code]layer_number[/code] between 1 and 32.
+ Based on [param value], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="set_navigation_map">
<return type="void" />
- <argument index="0" name="navigation_map" type="RID" />
+ <param index="0" name="navigation_map" type="RID" />
<description>
Sets the [RID] of the navigation map this NavigationAgent node should use and also updates the [code]agent[/code] on the NavigationServer.
</description>
</method>
<method name="set_target_location">
<return type="void" />
- <argument index="0" name="location" type="Vector3" />
+ <param index="0" name="location" type="Vector3" />
<description>
Sets the user desired final location. This will clear the current navigation path.
</description>
</method>
<method name="set_velocity">
<return type="void" />
- <argument index="0" name="velocity" type="Vector3" />
+ <param index="0" name="velocity" type="Vector3" />
<description>
Sends the passed in velocity to the collision avoidance algorithm. It will adjust the velocity to avoid collisions. Once the adjustment to the velocity is complete, it will emit the [signal velocity_computed] signal.
</description>
@@ -132,7 +132,7 @@
<member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1">
A bitfield determining what navigation layers of navigation regions this NavigationAgent will use to calculate path. Changing it runtime will clear current navigation path and generate new one, according to new navigation layers.
</member>
- <member name="neighbor_dist" type="float" setter="set_neighbor_dist" getter="get_neighbor_dist" default="50.0">
+ <member name="neighbor_distance" type="float" setter="set_neighbor_distance" getter="get_neighbor_distance" default="50.0">
The distance to search for other agents.
</member>
<member name="path_desired_distance" type="float" setter="set_path_desired_distance" getter="get_path_desired_distance" default="1.0">
@@ -142,7 +142,7 @@
The maximum distance the agent is allowed away from the ideal path to the final location. This can happen due to trying to avoid collisions. When the maximum distance is exceeded, it recalculates the ideal path.
</member>
<member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
- The radius of the avoidance agent. This is the "body" of the avoidance agent and not the avoidance maneuver starting radius (which is controlled by [member neighbor_dist]).
+ The radius of the avoidance agent. This is the "body" of the avoidance agent and not the avoidance maneuver starting radius (which is controlled by [member neighbor_distance]).
Does not affect normal pathfinding. To change an actor's pathfinding radius bake [NavigationMesh] resources with a different [member NavigationMesh.agent_radius] property and use different navigation maps for each actor size.
</member>
<member name="target_desired_distance" type="float" setter="set_target_desired_distance" getter="get_target_desired_distance" default="1.0">
@@ -169,7 +169,7 @@
</description>
</signal>
<signal name="velocity_computed">
- <argument index="0" name="safe_velocity" type="Vector3" />
+ <param index="0" name="safe_velocity" type="Vector3" />
<description>
Notifies when the collision avoidance velocity is calculated. Emitted by [method set_velocity].
</description>
diff --git a/doc/classes/NavigationMesh.xml b/doc/classes/NavigationMesh.xml
index 966f964b12..c86bc47e04 100644
--- a/doc/classes/NavigationMesh.xml
+++ b/doc/classes/NavigationMesh.xml
@@ -12,7 +12,7 @@
<methods>
<method name="add_polygon">
<return type="void" />
- <argument index="0" name="polygon" type="PackedInt32Array" />
+ <param index="0" name="polygon" type="PackedInt32Array" />
<description>
Adds a polygon using the indices of the vertices you get when calling [method get_vertices].
</description>
@@ -25,21 +25,22 @@
</method>
<method name="create_from_mesh">
<return type="void" />
- <argument index="0" name="mesh" type="Mesh" />
+ <param index="0" name="mesh" type="Mesh" />
<description>
Initializes the navigation mesh by setting the vertices and indices according to a [Mesh].
+ [b]Note:[/b] The given [param mesh] must be of type [constant Mesh.PRIMITIVE_TRIANGLES] and have an index array.
</description>
</method>
<method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
- Returns whether or not the specified layer of the [member geometry_collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
+ Returns whether or not the specified layer of the [member geometry_collision_mask] is enabled, given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="get_polygon">
<return type="PackedInt32Array" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns a [PackedInt32Array] containing the indices of the vertices of a created polygon.
</description>
@@ -58,15 +59,15 @@
</method>
<method name="set_collision_mask_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
- Based on [code]value[/code], enables or disables the specified layer in the [member geometry_collision_mask], given a [code]layer_number[/code] between 1 and 32.
+ Based on [param value], enables or disables the specified layer in the [member geometry_collision_mask], given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="set_vertices">
<return type="void" />
- <argument index="0" name="vertices" type="PackedVector3Array" />
+ <param index="0" name="vertices" type="PackedVector3Array" />
<description>
Sets the vertices that can be then indexed to create polygons with the [method add_polygon] method.
</description>
diff --git a/doc/classes/NavigationMeshGenerator.xml b/doc/classes/NavigationMeshGenerator.xml
index 612ce54d34..4c337db90f 100644
--- a/doc/classes/NavigationMeshGenerator.xml
+++ b/doc/classes/NavigationMeshGenerator.xml
@@ -6,7 +6,7 @@
<description>
This class is responsible for creating and clearing 3D navigation meshes used as [NavigationMesh] resources inside [NavigationRegion3D]. The [NavigationMeshGenerator] has very limited to no use for 2D as the navigation mesh baking process expects 3D node types and 3D source geometry to parse.
The entire navigation mesh baking is best done in a separate thread as the voxelization, collision tests and mesh optimization steps involved are very performance and time hungry operations.
- Navigation mesh baking happens in multiple steps and the result depends on 3D source geometry and properties of the [NavigationMesh] resource. In the first step, starting from a root node and depending on [NavigationMesh] properties all valid 3D source geometry nodes are collected from the [SceneTree]. Second, all collected nodes are parsed for their relevant 3D geometry data and a combined 3D mesh is build. Due to the many different types of parsable objects, from normal [MeshInstance3D]s to [CSGShape3D]s or various [CollisionObject3D]s, some operations to collect geometry data can trigger [RenderingServer] and [PhysicsServer3D] synchronizations. Server synchronization can have a negative effect on baking time or framerate as it often involves [Mutex] locking for thread security. Many parsable objects and the continuous synchronization with other threaded Servers can increase the baking time significantly. On the other hand only a few but very large and complex objects will take some time to prepare for the Servers which can noticeably stall the next frame render. As a general rule the total amount of parsable objects and their individual size and complexity should be balanced to avoid framerate issues or very long baking times. The combined mesh is then passed to the Recast Navigation Object to test the source geometry for walkable terrain suitable to [NavigationMesh] agent properties by creating a voxel world around the meshes bounding area.
+ Navigation mesh baking happens in multiple steps and the result depends on 3D source geometry and properties of the [NavigationMesh] resource. In the first step, starting from a root node and depending on [NavigationMesh] properties all valid 3D source geometry nodes are collected from the [SceneTree]. Second, all collected nodes are parsed for their relevant 3D geometry data and a combined 3D mesh is build. Due to the many different types of parsable objects, from normal [MeshInstance3D]s to [CSGShape3D]s or various [CollisionObject3D]s, some operations to collect geometry data can trigger [RenderingServer] and [PhysicsServer3D] synchronizations. Server synchronization can have a negative effect on baking time or framerate as it often involves [Mutex] locking for thread security. Many parsable objects and the continuous synchronization with other threaded Servers can increase the baking time significantly. On the other hand only a few but very large and complex objects will take some time to prepare for the Servers which can noticeably stall the next frame render. As a general rule the total number of parsable objects and their individual size and complexity should be balanced to avoid framerate issues or very long baking times. The combined mesh is then passed to the Recast Navigation Object to test the source geometry for walkable terrain suitable to [NavigationMesh] agent properties by creating a voxel world around the meshes bounding area.
The finalized navigation mesh is then returned and stored inside the [NavigationMesh] for use as a resource inside [NavigationRegion3D] nodes.
[b]Note:[/b] Using meshes to not only define walkable surfaces but also obstruct navigation baking does not always work. The navigation baking has no concept of what is a geometry "inside" when dealing with mesh source geometry and this is intentional. Depending on current baking parameters, as soon as the obstructing mesh is large enough to fit a navigation mesh area inside, the baking will generate navigation mesh areas that are inside the obstructing source geometry mesh.
</description>
@@ -15,17 +15,17 @@
<methods>
<method name="bake">
<return type="void" />
- <argument index="0" name="nav_mesh" type="NavigationMesh" />
- <argument index="1" name="root_node" type="Node" />
+ <param index="0" name="nav_mesh" type="NavigationMesh" />
+ <param index="1" name="root_node" type="Node" />
<description>
- Bakes navigation data to the provided [code]nav_mesh[/code] by parsing child nodes under the provided [code]root_node[/code] or a specific group of nodes for potential source geometry. The parse behavior can be controlled with the [member NavigationMesh.geometry_parsed_geometry_type] and [member NavigationMesh.geometry_source_geometry_mode] properties on the [NavigationMesh] resource.
+ Bakes navigation data to the provided [param nav_mesh] by parsing child nodes under the provided [param root_node] or a specific group of nodes for potential source geometry. The parse behavior can be controlled with the [member NavigationMesh.geometry_parsed_geometry_type] and [member NavigationMesh.geometry_source_geometry_mode] properties on the [NavigationMesh] resource.
</description>
</method>
<method name="clear">
<return type="void" />
- <argument index="0" name="nav_mesh" type="NavigationMesh" />
+ <param index="0" name="nav_mesh" type="NavigationMesh" />
<description>
- Removes all polygons and vertices from the provided [code]nav_mesh[/code] resource.
+ Removes all polygons and vertices from the provided [param nav_mesh] resource.
</description>
</method>
</methods>
diff --git a/doc/classes/NavigationPolygon.xml b/doc/classes/NavigationPolygon.xml
index 0a2ceeedc5..19466c171f 100644
--- a/doc/classes/NavigationPolygon.xml
+++ b/doc/classes/NavigationPolygon.xml
@@ -48,22 +48,22 @@
<methods>
<method name="add_outline">
<return type="void" />
- <argument index="0" name="outline" type="PackedVector2Array" />
+ <param index="0" name="outline" type="PackedVector2Array" />
<description>
Appends a [PackedVector2Array] that contains the vertices of an outline to the internal array that contains all the outlines. You have to call [method make_polygons_from_outlines] in order for this array to be converted to polygons that the engine will use.
</description>
</method>
<method name="add_outline_at_index">
<return type="void" />
- <argument index="0" name="outline" type="PackedVector2Array" />
- <argument index="1" name="index" type="int" />
+ <param index="0" name="outline" type="PackedVector2Array" />
+ <param index="1" name="index" type="int" />
<description>
Adds a [PackedVector2Array] that contains the vertices of an outline to the internal array that contains all the outlines at a fixed position. You have to call [method make_polygons_from_outlines] in order for this array to be converted to polygons that the engine will use.
</description>
</method>
<method name="add_polygon">
<return type="void" />
- <argument index="0" name="polygon" type="PackedInt32Array" />
+ <param index="0" name="polygon" type="PackedInt32Array" />
<description>
Adds a polygon using the indices of the vertices you get when calling [method get_vertices].
</description>
@@ -88,7 +88,7 @@
</method>
<method name="get_outline" qualifiers="const">
<return type="PackedVector2Array" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns a [PackedVector2Array] containing the vertices of an outline that was created in the editor or by script.
</description>
@@ -101,7 +101,7 @@
</method>
<method name="get_polygon">
<return type="PackedInt32Array" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns a [PackedInt32Array] containing the indices of the vertices of a created polygon.
</description>
@@ -126,22 +126,22 @@
</method>
<method name="remove_outline">
<return type="void" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Removes an outline created in the editor or by script. You have to call [method make_polygons_from_outlines] for the polygons to update.
</description>
</method>
<method name="set_outline">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="outline" type="PackedVector2Array" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="outline" type="PackedVector2Array" />
<description>
Changes an outline created in the editor or by script. You have to call [method make_polygons_from_outlines] for the polygons to update.
</description>
</method>
<method name="set_vertices">
<return type="void" />
- <argument index="0" name="vertices" type="PackedVector2Array" />
+ <param index="0" name="vertices" type="PackedVector2Array" />
<description>
Sets the vertices that can be then indexed to create polygons with the [method add_polygon] method.
</description>
diff --git a/doc/classes/NavigationRegion2D.xml b/doc/classes/NavigationRegion2D.xml
index 75b6544827..89f7dcb4af 100644
--- a/doc/classes/NavigationRegion2D.xml
+++ b/doc/classes/NavigationRegion2D.xml
@@ -16,9 +16,9 @@
<methods>
<method name="get_navigation_layer_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
- Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [code]layer_number[/code] between 1 and 32.
+ Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="get_region_rid" qualifiers="const">
@@ -29,10 +29,10 @@
</method>
<method name="set_navigation_layer_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
- Based on [code]value[/code], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [code]layer_number[/code] between 1 and 32.
+ Based on [param value], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [param layer_number] between 1 and 32.
</description>
</method>
</methods>
diff --git a/doc/classes/NavigationRegion3D.xml b/doc/classes/NavigationRegion3D.xml
index f5824a24fd..87e82e7b2e 100644
--- a/doc/classes/NavigationRegion3D.xml
+++ b/doc/classes/NavigationRegion3D.xml
@@ -16,16 +16,16 @@
<methods>
<method name="bake_navigation_mesh">
<return type="void" />
- <argument index="0" name="on_thread" type="bool" default="true" />
+ <param index="0" name="on_thread" type="bool" default="true" />
<description>
- Bakes the [NavigationMesh]. If [code]on_thread[/code] is set to [code]true[/code] (default), the baking is done on a separate thread. Baking on separate thread is useful because navigation baking is not a cheap operation. When it is completed, it automatically sets the new [NavigationMesh]. Please note that baking on separate thread may be very slow if geometry is parsed from meshes as async access to each mesh involves heavy synchronization. Also, please note that baking on a separate thread is automatically disabled on operating systems that cannot use threads (such as HTML5 with threads disabled).
+ Bakes the [NavigationMesh]. If [param on_thread] is set to [code]true[/code] (default), the baking is done on a separate thread. Baking on separate thread is useful because navigation baking is not a cheap operation. When it is completed, it automatically sets the new [NavigationMesh]. Please note that baking on separate thread may be very slow if geometry is parsed from meshes as async access to each mesh involves heavy synchronization. Also, please note that baking on a separate thread is automatically disabled on operating systems that cannot use threads (such as Web with threads disabled).
</description>
</method>
<method name="get_navigation_layer_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
- Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [code]layer_number[/code] between 1 and 32.
+ Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="get_region_rid" qualifiers="const">
@@ -36,10 +36,10 @@
</method>
<method name="set_navigation_layer_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
- Based on [code]value[/code], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [code]layer_number[/code] between 1 and 32.
+ Based on [param value], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [param layer_number] between 1 and 32.
</description>
</method>
</methods>
diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml
index 36379d2531..b85c1c6649 100644
--- a/doc/classes/NavigationServer2D.xml
+++ b/doc/classes/NavigationServer2D.xml
@@ -25,110 +25,110 @@
</method>
<method name="agent_get_map" qualifiers="const">
<return type="RID" />
- <argument index="0" name="agent" type="RID" />
+ <param index="0" name="agent" type="RID" />
<description>
- Returns the navigation map [RID] the requested [code]agent[/code] is currently assigned to.
+ Returns the navigation map [RID] the requested [param agent] is currently assigned to.
</description>
</method>
<method name="agent_is_map_changed" qualifiers="const">
<return type="bool" />
- <argument index="0" name="agent" type="RID" />
+ <param index="0" name="agent" type="RID" />
<description>
Returns true if the map got changed the previous frame.
</description>
</method>
<method name="agent_set_callback" qualifiers="const">
<return type="void" />
- <argument index="0" name="agent" type="RID" />
- <argument index="1" name="receiver" type="Object" />
- <argument index="2" name="method" type="StringName" />
- <argument index="3" name="userdata" type="Variant" default="null" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="receiver" type="Object" />
+ <param index="2" name="method" type="StringName" />
+ <param index="3" name="userdata" type="Variant" default="null" />
<description>
- Callback called at the end of the RVO process. If a callback is created manually and the agent is placed on a navigation map it will calculate avoidance for the agent and dispatch the calculated [code]safe_velocity[/code] to the [code]receiver[/code] object with a signal to the chosen [code]method[/code] name.
- [b]Note:[/b] Created callbacks are always processed independently of the SceneTree state as long as the agent is on a navigation map and not freed. To disable the dispatch of a callback from an agent use [method agent_set_callback] again with a [code]null[/code] object as the [code]receiver[/code].
+ Callback called at the end of the RVO process. If a callback is created manually and the agent is placed on a navigation map it will calculate avoidance for the agent and dispatch the calculated [code]safe_velocity[/code] to the [param receiver] object with a signal to the chosen [param method] name.
+ [b]Note:[/b] Created callbacks are always processed independently of the SceneTree state as long as the agent is on a navigation map and not freed. To disable the dispatch of a callback from an agent use [method agent_set_callback] again with a [code]null[/code] object as the [param receiver].
</description>
</method>
<method name="agent_set_map" qualifiers="const">
<return type="void" />
- <argument index="0" name="agent" type="RID" />
- <argument index="1" name="map" type="RID" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="map" type="RID" />
<description>
Puts the agent in the map.
</description>
</method>
<method name="agent_set_max_neighbors" qualifiers="const">
<return type="void" />
- <argument index="0" name="agent" type="RID" />
- <argument index="1" name="count" type="int" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="count" type="int" />
<description>
Sets the maximum number of other agents the agent takes into account in the navigation. The larger this number, the longer the running time of the simulation. If the number is too low, the simulation will not be safe.
</description>
</method>
<method name="agent_set_max_speed" qualifiers="const">
<return type="void" />
- <argument index="0" name="agent" type="RID" />
- <argument index="1" name="max_speed" type="float" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="max_speed" type="float" />
<description>
Sets the maximum speed of the agent. Must be positive.
</description>
</method>
- <method name="agent_set_neighbor_dist" qualifiers="const">
+ <method name="agent_set_neighbor_distance" qualifiers="const">
<return type="void" />
- <argument index="0" name="agent" type="RID" />
- <argument index="1" name="dist" type="float" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="distance" type="float" />
<description>
Sets the maximum distance to other agents this agent takes into account in the navigation. The larger this number, the longer the running time of the simulation. If the number is too low, the simulation will not be safe.
</description>
</method>
<method name="agent_set_position" qualifiers="const">
<return type="void" />
- <argument index="0" name="agent" type="RID" />
- <argument index="1" name="position" type="Vector2" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="position" type="Vector2" />
<description>
Sets the position of the agent in world space.
</description>
</method>
<method name="agent_set_radius" qualifiers="const">
<return type="void" />
- <argument index="0" name="agent" type="RID" />
- <argument index="1" name="radius" type="float" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="radius" type="float" />
<description>
Sets the radius of the agent.
</description>
</method>
<method name="agent_set_target_velocity" qualifiers="const">
<return type="void" />
- <argument index="0" name="agent" type="RID" />
- <argument index="1" name="target_velocity" type="Vector2" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="target_velocity" type="Vector2" />
<description>
Sets the new target velocity.
</description>
</method>
<method name="agent_set_time_horizon" qualifiers="const">
<return type="void" />
- <argument index="0" name="agent" type="RID" />
- <argument index="1" name="time" type="float" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="time" type="float" />
<description>
The minimal amount of time for which the agent's velocities that are computed by the simulation are safe with respect to other agents. The larger this number, the sooner this agent will respond to the presence of other agents, but the less freedom this agent has in choosing its velocities. Must be positive.
</description>
</method>
<method name="agent_set_velocity" qualifiers="const">
<return type="void" />
- <argument index="0" name="agent" type="RID" />
- <argument index="1" name="velocity" type="Vector2" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="velocity" type="Vector2" />
<description>
Sets the current velocity of the agent.
</description>
</method>
<method name="free_rid" qualifiers="const">
<return type="void" />
- <argument index="0" name="rid" type="RID" />
+ <param index="0" name="rid" type="RID" />
<description>
Destroys the given RID.
</description>
</method>
<method name="get_maps" qualifiers="const">
- <return type="Array" />
+ <return type="RID[]" />
<description>
Returns all created navigation map [RID]s on the NavigationServer. This returns both 2D and 3D created navigation maps as there is technically no distinction between them.
</description>
@@ -141,96 +141,96 @@
</method>
<method name="map_force_update">
<return type="void" />
- <argument index="0" name="map" type="RID" />
+ <param index="0" name="map" type="RID" />
<description>
- This function immediately forces synchronization of the specified navigation [code]map[/code] [RID]. By default navigation maps are only synchronized at the end of each physics frame. This function can be used to immediately (re)calculate all the navigation meshes and region connections of the navigation map. This makes it possible to query a navigation path for a changed map immediately and in the same frame (multiple times if needed).
+ This function immediately forces synchronization of the specified navigation [param map] [RID]. By default navigation maps are only synchronized at the end of each physics frame. This function can be used to immediately (re)calculate all the navigation meshes and region connections of the navigation map. This makes it possible to query a navigation path for a changed map immediately and in the same frame (multiple times if needed).
Due to technical restrictions the current NavigationServer command queue will be flushed. This means all already queued update commands for this physics frame will be executed, even those intended for other maps, regions and agents not part of the specified map. The expensive computation of the navigation meshes and region connections of a map will only be done for the specified map. Other maps will receive the normal synchronization at the end of the physics frame. Should the specified map receive changes after the forced update it will update again as well when the other maps receive their update.
Avoidance processing and dispatch of the [code]safe_velocity[/code] signals is untouched by this function and continues to happen for all maps and agents at the end of the physics frame.
[b]Note:[/b] With great power comes great responsibility. This function should only be used by users that really know what they are doing and have a good reason for it. Forcing an immediate update of a navigation map requires locking the NavigationServer and flushing the entire NavigationServer command queue. Not only can this severely impact the performance of a game but it can also introduce bugs if used inappropriately without much foresight.
</description>
</method>
<method name="map_get_agents" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="map" type="RID" />
+ <return type="RID[]" />
+ <param index="0" name="map" type="RID" />
<description>
- Returns all navigation agents [RID]s that are currently assigned to the requested navigation [code]map[/code].
+ Returns all navigation agents [RID]s that are currently assigned to the requested navigation [param map].
</description>
</method>
<method name="map_get_cell_size" qualifiers="const">
<return type="float" />
- <argument index="0" name="map" type="RID" />
+ <param index="0" name="map" type="RID" />
<description>
Returns the map cell size.
</description>
</method>
<method name="map_get_closest_point" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="map" type="RID" />
- <argument index="1" name="to_point" type="Vector2" />
+ <param index="0" name="map" type="RID" />
+ <param index="1" name="to_point" type="Vector2" />
<description>
- Returns the point closest to the provided [code]to_point[/code] on the navigation mesh surface.
+ Returns the point closest to the provided [param to_point] on the navigation mesh surface.
</description>
</method>
<method name="map_get_closest_point_owner" qualifiers="const">
<return type="RID" />
- <argument index="0" name="map" type="RID" />
- <argument index="1" name="to_point" type="Vector2" />
+ <param index="0" name="map" type="RID" />
+ <param index="1" name="to_point" type="Vector2" />
<description>
Returns the owner region RID for the point returned by [method map_get_closest_point].
</description>
</method>
<method name="map_get_edge_connection_margin" qualifiers="const">
<return type="float" />
- <argument index="0" name="map" type="RID" />
+ <param index="0" name="map" type="RID" />
<description>
Returns the edge connection margin of the map. The edge connection margin is a distance used to connect two regions.
</description>
</method>
<method name="map_get_path" qualifiers="const">
<return type="PackedVector2Array" />
- <argument index="0" name="map" type="RID" />
- <argument index="1" name="origin" type="Vector2" />
- <argument index="2" name="destination" type="Vector2" />
- <argument index="3" name="optimize" type="bool" />
- <argument index="4" name="navigation_layers" type="int" default="1" />
+ <param index="0" name="map" type="RID" />
+ <param index="1" name="origin" type="Vector2" />
+ <param index="2" name="destination" type="Vector2" />
+ <param index="3" name="optimize" type="bool" />
+ <param index="4" name="navigation_layers" type="int" default="1" />
<description>
- Returns the navigation path to reach the destination from the origin. [code]navigation_layers[/code] is a bitmask of all region navigation layers that are allowed to be in the path.
+ Returns the navigation path to reach the destination from the origin. [param navigation_layers] is a bitmask of all region navigation layers that are allowed to be in the path.
</description>
</method>
<method name="map_get_regions" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="map" type="RID" />
+ <return type="RID[]" />
+ <param index="0" name="map" type="RID" />
<description>
- Returns all navigation regions [RID]s that are currently assigned to the requested navigation [code]map[/code].
+ Returns all navigation regions [RID]s that are currently assigned to the requested navigation [param map].
</description>
</method>
<method name="map_is_active" qualifiers="const">
<return type="bool" />
- <argument index="0" name="nap" type="RID" />
+ <param index="0" name="map" type="RID" />
<description>
Returns true if the map is active.
</description>
</method>
<method name="map_set_active" qualifiers="const">
<return type="void" />
- <argument index="0" name="map" type="RID" />
- <argument index="1" name="active" type="bool" />
+ <param index="0" name="map" type="RID" />
+ <param index="1" name="active" type="bool" />
<description>
Sets the map active.
</description>
</method>
<method name="map_set_cell_size" qualifiers="const">
<return type="void" />
- <argument index="0" name="map" type="RID" />
- <argument index="1" name="cell_size" type="float" />
+ <param index="0" name="map" type="RID" />
+ <param index="1" name="cell_size" type="float" />
<description>
Set the map cell size used to weld the navigation mesh polygons.
</description>
</method>
<method name="map_set_edge_connection_margin" qualifiers="const">
<return type="void" />
- <argument index="0" name="map" type="RID" />
- <argument index="1" name="margin" type="float" />
+ <param index="0" name="map" type="RID" />
+ <param index="1" name="margin" type="float" />
<description>
Set the map edge connection margin used to weld the compatible region edges.
</description>
@@ -243,117 +243,117 @@
</method>
<method name="region_get_connection_pathway_end" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="region" type="RID" />
- <argument index="1" name="connection" type="int" />
+ <param index="0" name="region" type="RID" />
+ <param index="1" name="connection" type="int" />
<description>
- Returns the ending point of a connection door. [code]connection[/code] is an index between 0 and the return value of [method region_get_connections_count].
+ Returns the ending point of a connection door. [param connection] is an index between 0 and the return value of [method region_get_connections_count].
</description>
</method>
<method name="region_get_connection_pathway_start" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="region" type="RID" />
- <argument index="1" name="connection" type="int" />
+ <param index="0" name="region" type="RID" />
+ <param index="1" name="connection" type="int" />
<description>
- Returns the starting point of a connection door. [code]connection[/code] is an index between 0 and the return value of [method region_get_connections_count].
+ Returns the starting point of a connection door. [param connection] is an index between 0 and the return value of [method region_get_connections_count].
</description>
</method>
<method name="region_get_connections_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="region" type="RID" />
+ <param index="0" name="region" type="RID" />
<description>
- Returns how many connections this [code]region[/code] has with other regions in the map.
+ Returns how many connections this [param region] has with other regions in the map.
</description>
</method>
<method name="region_get_enter_cost" qualifiers="const">
<return type="float" />
- <argument index="0" name="region" type="RID" />
+ <param index="0" name="region" type="RID" />
<description>
- Returns the [code]enter_cost[/code] of this [code]region[/code].
+ Returns the [code]enter_cost[/code] of this [param region].
</description>
</method>
<method name="region_get_map" qualifiers="const">
<return type="RID" />
- <argument index="0" name="region" type="RID" />
+ <param index="0" name="region" type="RID" />
<description>
- Returns the navigation map [RID] the requested [code]region[/code] is currently assigned to.
+ Returns the navigation map [RID] the requested [param region] is currently assigned to.
</description>
</method>
<method name="region_get_navigation_layers" qualifiers="const">
<return type="int" />
- <argument index="0" name="region" type="RID" />
+ <param index="0" name="region" type="RID" />
<description>
Returns the region's navigation layers.
</description>
</method>
<method name="region_get_travel_cost" qualifiers="const">
<return type="float" />
- <argument index="0" name="region" type="RID" />
+ <param index="0" name="region" type="RID" />
<description>
- Returns the [code]travel_cost[/code] of this [code]region[/code].
+ Returns the [code]travel_cost[/code] of this [param region].
</description>
</method>
<method name="region_owns_point" qualifiers="const">
<return type="bool" />
- <argument index="0" name="region" type="RID" />
- <argument index="1" name="point" type="Vector2" />
+ <param index="0" name="region" type="RID" />
+ <param index="1" name="point" type="Vector2" />
<description>
- Returns [code]true[/code] if the provided [code]point[/code] in world space is currently owned by the provided navigation [code]region[/code]. Owned in this context means that one of the region's navigation mesh polygon faces has a possible position at the closest distance to this point compared to all other navigation meshes from other navigation regions that are also registered on the navigation map of the provided region.
+ Returns [code]true[/code] if the provided [param point] in world space is currently owned by the provided navigation [param region]. Owned in this context means that one of the region's navigation mesh polygon faces has a possible position at the closest distance to this point compared to all other navigation meshes from other navigation regions that are also registered on the navigation map of the provided region.
If multiple navigation meshes have positions at equal distance the navigation region whose polygons are processed first wins the ownership. Polygons are processed in the same order that navigation regions were registered on the NavigationServer.
[b]Note:[/b] If navigation meshes from different navigation regions overlap (which should be avoided in general) the result might not be what is expected.
</description>
</method>
<method name="region_set_enter_cost" qualifiers="const">
<return type="void" />
- <argument index="0" name="region" type="RID" />
- <argument index="1" name="enter_cost" type="float" />
+ <param index="0" name="region" type="RID" />
+ <param index="1" name="enter_cost" type="float" />
<description>
- Sets the [code]enter_cost[/code] for this [code]region[/code].
+ Sets the [param enter_cost] for this [param region].
</description>
</method>
<method name="region_set_map" qualifiers="const">
<return type="void" />
- <argument index="0" name="region" type="RID" />
- <argument index="1" name="map" type="RID" />
+ <param index="0" name="region" type="RID" />
+ <param index="1" name="map" type="RID" />
<description>
Sets the map for the region.
</description>
</method>
<method name="region_set_navigation_layers" qualifiers="const">
<return type="void" />
- <argument index="0" name="region" type="RID" />
- <argument index="1" name="navigation_layers" type="int" />
+ <param index="0" name="region" type="RID" />
+ <param index="1" name="navigation_layers" type="int" />
<description>
Set the region's navigation layers. This allows selecting regions from a path request (when using [method NavigationServer2D.map_get_path]).
</description>
</method>
<method name="region_set_navpoly" qualifiers="const">
<return type="void" />
- <argument index="0" name="region" type="RID" />
- <argument index="1" name="nav_poly" type="NavigationPolygon" />
+ <param index="0" name="region" type="RID" />
+ <param index="1" name="nav_poly" type="NavigationPolygon" />
<description>
Sets the navigation mesh for the region.
</description>
</method>
<method name="region_set_transform" qualifiers="const">
<return type="void" />
- <argument index="0" name="region" type="RID" />
- <argument index="1" name="transform" type="Transform2D" />
+ <param index="0" name="region" type="RID" />
+ <param index="1" name="transform" type="Transform2D" />
<description>
Sets the global transformation for the region.
</description>
</method>
<method name="region_set_travel_cost" qualifiers="const">
<return type="void" />
- <argument index="0" name="region" type="RID" />
- <argument index="1" name="travel_cost" type="float" />
+ <param index="0" name="region" type="RID" />
+ <param index="1" name="travel_cost" type="float" />
<description>
- Sets the [code]travel_cost[/code] for this [code]region[/code].
+ Sets the [param travel_cost] for this [param region].
</description>
</method>
</methods>
<signals>
<signal name="map_changed">
- <argument index="0" name="map" type="RID" />
+ <param index="0" name="map" type="RID" />
<description>
Emitted when a navigation map is updated, when a region moves or is modified.
</description>
diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml
index 8600c2643a..5b2a8fc08b 100644
--- a/doc/classes/NavigationServer3D.xml
+++ b/doc/classes/NavigationServer3D.xml
@@ -25,110 +25,110 @@
</method>
<method name="agent_get_map" qualifiers="const">
<return type="RID" />
- <argument index="0" name="agent" type="RID" />
+ <param index="0" name="agent" type="RID" />
<description>
- Returns the navigation map [RID] the requested [code]agent[/code] is currently assigned to.
+ Returns the navigation map [RID] the requested [param agent] is currently assigned to.
</description>
</method>
<method name="agent_is_map_changed" qualifiers="const">
<return type="bool" />
- <argument index="0" name="agent" type="RID" />
+ <param index="0" name="agent" type="RID" />
<description>
Returns true if the map got changed the previous frame.
</description>
</method>
<method name="agent_set_callback" qualifiers="const">
<return type="void" />
- <argument index="0" name="agent" type="RID" />
- <argument index="1" name="receiver" type="Object" />
- <argument index="2" name="method" type="StringName" />
- <argument index="3" name="userdata" type="Variant" default="null" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="receiver" type="Object" />
+ <param index="2" name="method" type="StringName" />
+ <param index="3" name="userdata" type="Variant" default="null" />
<description>
- Callback called at the end of the RVO process. If a callback is created manually and the agent is placed on a navigation map it will calculate avoidance for the agent and dispatch the calculated [code]safe_velocity[/code] to the [code]receiver[/code] object with a signal to the chosen [code]method[/code] name.
- [b]Note:[/b] Created callbacks are always processed independently of the SceneTree state as long as the agent is on a navigation map and not freed. To disable the dispatch of a callback from an agent use [method agent_set_callback] again with a [code]null[/code] object as the [code]receiver[/code].
+ Callback called at the end of the RVO process. If a callback is created manually and the agent is placed on a navigation map it will calculate avoidance for the agent and dispatch the calculated [code]safe_velocity[/code] to the [param receiver] object with a signal to the chosen [param method] name.
+ [b]Note:[/b] Created callbacks are always processed independently of the SceneTree state as long as the agent is on a navigation map and not freed. To disable the dispatch of a callback from an agent use [method agent_set_callback] again with a [code]null[/code] object as the [param receiver].
</description>
</method>
<method name="agent_set_map" qualifiers="const">
<return type="void" />
- <argument index="0" name="agent" type="RID" />
- <argument index="1" name="map" type="RID" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="map" type="RID" />
<description>
Puts the agent in the map.
</description>
</method>
<method name="agent_set_max_neighbors" qualifiers="const">
<return type="void" />
- <argument index="0" name="agent" type="RID" />
- <argument index="1" name="count" type="int" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="count" type="int" />
<description>
Sets the maximum number of other agents the agent takes into account in the navigation. The larger this number, the longer the running time of the simulation. If the number is too low, the simulation will not be safe.
</description>
</method>
<method name="agent_set_max_speed" qualifiers="const">
<return type="void" />
- <argument index="0" name="agent" type="RID" />
- <argument index="1" name="max_speed" type="float" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="max_speed" type="float" />
<description>
Sets the maximum speed of the agent. Must be positive.
</description>
</method>
- <method name="agent_set_neighbor_dist" qualifiers="const">
+ <method name="agent_set_neighbor_distance" qualifiers="const">
<return type="void" />
- <argument index="0" name="agent" type="RID" />
- <argument index="1" name="dist" type="float" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="distance" type="float" />
<description>
Sets the maximum distance to other agents this agent takes into account in the navigation. The larger this number, the longer the running time of the simulation. If the number is too low, the simulation will not be safe.
</description>
</method>
<method name="agent_set_position" qualifiers="const">
<return type="void" />
- <argument index="0" name="agent" type="RID" />
- <argument index="1" name="position" type="Vector3" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="position" type="Vector3" />
<description>
Sets the position of the agent in world space.
</description>
</method>
<method name="agent_set_radius" qualifiers="const">
<return type="void" />
- <argument index="0" name="agent" type="RID" />
- <argument index="1" name="radius" type="float" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="radius" type="float" />
<description>
Sets the radius of the agent.
</description>
</method>
<method name="agent_set_target_velocity" qualifiers="const">
<return type="void" />
- <argument index="0" name="agent" type="RID" />
- <argument index="1" name="target_velocity" type="Vector3" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="target_velocity" type="Vector3" />
<description>
Sets the new target velocity.
</description>
</method>
<method name="agent_set_time_horizon" qualifiers="const">
<return type="void" />
- <argument index="0" name="agent" type="RID" />
- <argument index="1" name="time" type="float" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="time" type="float" />
<description>
The minimal amount of time for which the agent's velocities that are computed by the simulation are safe with respect to other agents. The larger this number, the sooner this agent will respond to the presence of other agents, but the less freedom this agent has in choosing its velocities. Must be positive.
</description>
</method>
<method name="agent_set_velocity" qualifiers="const">
<return type="void" />
- <argument index="0" name="agent" type="RID" />
- <argument index="1" name="velocity" type="Vector3" />
+ <param index="0" name="agent" type="RID" />
+ <param index="1" name="velocity" type="Vector3" />
<description>
Sets the current velocity of the agent.
</description>
</method>
<method name="free_rid" qualifiers="const">
<return type="void" />
- <argument index="0" name="rid" type="RID" />
+ <param index="0" name="rid" type="RID" />
<description>
Destroys the given RID.
</description>
</method>
<method name="get_maps" qualifiers="const">
- <return type="Array" />
+ <return type="RID[]" />
<description>
Returns all created navigation map [RID]s on the NavigationServer. This returns both 2D and 3D created navigation maps as there is technically no distinction between them.
</description>
@@ -141,136 +141,136 @@
</method>
<method name="map_force_update">
<return type="void" />
- <argument index="0" name="map" type="RID" />
+ <param index="0" name="map" type="RID" />
<description>
- This function immediately forces synchronization of the specified navigation [code]map[/code] [RID]. By default navigation maps are only synchronized at the end of each physics frame. This function can be used to immediately (re)calculate all the navigation meshes and region connections of the navigation map. This makes it possible to query a navigation path for a changed map immediately and in the same frame (multiple times if needed).
+ This function immediately forces synchronization of the specified navigation [param map] [RID]. By default navigation maps are only synchronized at the end of each physics frame. This function can be used to immediately (re)calculate all the navigation meshes and region connections of the navigation map. This makes it possible to query a navigation path for a changed map immediately and in the same frame (multiple times if needed).
Due to technical restrictions the current NavigationServer command queue will be flushed. This means all already queued update commands for this physics frame will be executed, even those intended for other maps, regions and agents not part of the specified map. The expensive computation of the navigation meshes and region connections of a map will only be done for the specified map. Other maps will receive the normal synchronization at the end of the physics frame. Should the specified map receive changes after the forced update it will update again as well when the other maps receive their update.
Avoidance processing and dispatch of the [code]safe_velocity[/code] signals is untouched by this function and continues to happen for all maps and agents at the end of the physics frame.
[b]Note:[/b] With great power comes great responsibility. This function should only be used by users that really know what they are doing and have a good reason for it. Forcing an immediate update of a navigation map requires locking the NavigationServer and flushing the entire NavigationServer command queue. Not only can this severely impact the performance of a game but it can also introduce bugs if used inappropriately without much foresight.
</description>
</method>
<method name="map_get_agents" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="map" type="RID" />
+ <return type="RID[]" />
+ <param index="0" name="map" type="RID" />
<description>
- Returns all navigation agents [RID]s that are currently assigned to the requested navigation [code]map[/code].
+ Returns all navigation agents [RID]s that are currently assigned to the requested navigation [param map].
</description>
</method>
<method name="map_get_cell_size" qualifiers="const">
<return type="float" />
- <argument index="0" name="map" type="RID" />
+ <param index="0" name="map" type="RID" />
<description>
Returns the map cell size.
</description>
</method>
<method name="map_get_closest_point" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="map" type="RID" />
- <argument index="1" name="to_point" type="Vector3" />
+ <param index="0" name="map" type="RID" />
+ <param index="1" name="to_point" type="Vector3" />
<description>
- Returns the point closest to the provided [code]point[/code] on the navigation mesh surface.
+ Returns the point closest to the provided [param to_point] on the navigation mesh surface.
</description>
</method>
<method name="map_get_closest_point_normal" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="map" type="RID" />
- <argument index="1" name="to_point" type="Vector3" />
+ <param index="0" name="map" type="RID" />
+ <param index="1" name="to_point" type="Vector3" />
<description>
Returns the normal for the point returned by [method map_get_closest_point].
</description>
</method>
<method name="map_get_closest_point_owner" qualifiers="const">
<return type="RID" />
- <argument index="0" name="map" type="RID" />
- <argument index="1" name="to_point" type="Vector3" />
+ <param index="0" name="map" type="RID" />
+ <param index="1" name="to_point" type="Vector3" />
<description>
Returns the owner region RID for the point returned by [method map_get_closest_point].
</description>
</method>
<method name="map_get_closest_point_to_segment" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="map" type="RID" />
- <argument index="1" name="start" type="Vector3" />
- <argument index="2" name="end" type="Vector3" />
- <argument index="3" name="use_collision" type="bool" default="false" />
+ <param index="0" name="map" type="RID" />
+ <param index="1" name="start" type="Vector3" />
+ <param index="2" name="end" type="Vector3" />
+ <param index="3" name="use_collision" type="bool" default="false" />
<description>
Returns the closest point between the navigation surface and the segment.
</description>
</method>
<method name="map_get_edge_connection_margin" qualifiers="const">
<return type="float" />
- <argument index="0" name="map" type="RID" />
+ <param index="0" name="map" type="RID" />
<description>
Returns the edge connection margin of the map. This distance is the minimum vertex distance needed to connect two edges from different regions.
</description>
</method>
<method name="map_get_path" qualifiers="const">
<return type="PackedVector3Array" />
- <argument index="0" name="map" type="RID" />
- <argument index="1" name="origin" type="Vector3" />
- <argument index="2" name="destination" type="Vector3" />
- <argument index="3" name="optimize" type="bool" />
- <argument index="4" name="navigation_layers" type="int" default="1" />
+ <param index="0" name="map" type="RID" />
+ <param index="1" name="origin" type="Vector3" />
+ <param index="2" name="destination" type="Vector3" />
+ <param index="3" name="optimize" type="bool" />
+ <param index="4" name="navigation_layers" type="int" default="1" />
<description>
- Returns the navigation path to reach the destination from the origin. [code]navigation_layers[/code] is a bitmask of all region navigation layers that are allowed to be in the path.
+ Returns the navigation path to reach the destination from the origin. [param navigation_layers] is a bitmask of all region navigation layers that are allowed to be in the path.
</description>
</method>
<method name="map_get_regions" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="map" type="RID" />
+ <return type="RID[]" />
+ <param index="0" name="map" type="RID" />
<description>
- Returns all navigation regions [RID]s that are currently assigned to the requested navigation [code]map[/code].
+ Returns all navigation regions [RID]s that are currently assigned to the requested navigation [param map].
</description>
</method>
<method name="map_get_up" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="map" type="RID" />
+ <param index="0" name="map" type="RID" />
<description>
Returns the map's up direction.
</description>
</method>
<method name="map_is_active" qualifiers="const">
<return type="bool" />
- <argument index="0" name="nap" type="RID" />
+ <param index="0" name="map" type="RID" />
<description>
Returns true if the map is active.
</description>
</method>
<method name="map_set_active" qualifiers="const">
<return type="void" />
- <argument index="0" name="map" type="RID" />
- <argument index="1" name="active" type="bool" />
+ <param index="0" name="map" type="RID" />
+ <param index="1" name="active" type="bool" />
<description>
Sets the map active.
</description>
</method>
<method name="map_set_cell_size" qualifiers="const">
<return type="void" />
- <argument index="0" name="map" type="RID" />
- <argument index="1" name="cell_size" type="float" />
+ <param index="0" name="map" type="RID" />
+ <param index="1" name="cell_size" type="float" />
<description>
Set the map cell size used to weld the navigation mesh polygons.
</description>
</method>
<method name="map_set_edge_connection_margin" qualifiers="const">
<return type="void" />
- <argument index="0" name="map" type="RID" />
- <argument index="1" name="margin" type="float" />
+ <param index="0" name="map" type="RID" />
+ <param index="1" name="margin" type="float" />
<description>
Set the map edge connection margin used to weld the compatible region edges.
</description>
</method>
<method name="map_set_up" qualifiers="const">
<return type="void" />
- <argument index="0" name="map" type="RID" />
- <argument index="1" name="up" type="Vector3" />
+ <param index="0" name="map" type="RID" />
+ <param index="1" name="up" type="Vector3" />
<description>
Sets the map up direction.
</description>
</method>
<method name="process">
<return type="void" />
- <argument index="0" name="delta_time" type="float" />
+ <param index="0" name="delta_time" type="float" />
<description>
Process the collision avoidance agents.
The result of this process is needed by the physics server, so this must be called in the main thread.
@@ -279,8 +279,8 @@
</method>
<method name="region_bake_navmesh" qualifiers="const">
<return type="void" />
- <argument index="0" name="mesh" type="NavigationMesh" />
- <argument index="1" name="node" type="Node" />
+ <param index="0" name="mesh" type="NavigationMesh" />
+ <param index="1" name="node" type="Node" />
<description>
Bakes the navigation mesh.
</description>
@@ -293,116 +293,116 @@
</method>
<method name="region_get_connection_pathway_end" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="region" type="RID" />
- <argument index="1" name="connection" type="int" />
+ <param index="0" name="region" type="RID" />
+ <param index="1" name="connection" type="int" />
<description>
- Returns the ending point of a connection door. [code]connection[/code] is an index between 0 and the return value of [method region_get_connections_count].
+ Returns the ending point of a connection door. [param connection] is an index between 0 and the return value of [method region_get_connections_count].
</description>
</method>
<method name="region_get_connection_pathway_start" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="region" type="RID" />
- <argument index="1" name="connection" type="int" />
+ <param index="0" name="region" type="RID" />
+ <param index="1" name="connection" type="int" />
<description>
- Returns the starting point of a connection door. [code]connection[/code] is an index between 0 and the return value of [method region_get_connections_count].
+ Returns the starting point of a connection door. [param connection] is an index between 0 and the return value of [method region_get_connections_count].
</description>
</method>
<method name="region_get_connections_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="region" type="RID" />
+ <param index="0" name="region" type="RID" />
<description>
- Returns how many connections this [code]region[/code] has with other regions in the map.
+ Returns how many connections this [param region] has with other regions in the map.
</description>
</method>
<method name="region_get_enter_cost" qualifiers="const">
<return type="float" />
- <argument index="0" name="region" type="RID" />
+ <param index="0" name="region" type="RID" />
<description>
- Returns the [code]enter_cost[/code] of this [code]region[/code].
+ Returns the [code]enter_cost[/code] of this [param region].
</description>
</method>
<method name="region_get_map" qualifiers="const">
<return type="RID" />
- <argument index="0" name="region" type="RID" />
+ <param index="0" name="region" type="RID" />
<description>
- Returns the navigation map [RID] the requested [code]region[/code] is currently assigned to.
+ Returns the navigation map [RID] the requested [param region] is currently assigned to.
</description>
</method>
<method name="region_get_navigation_layers" qualifiers="const">
<return type="int" />
- <argument index="0" name="region" type="RID" />
+ <param index="0" name="region" type="RID" />
<description>
Returns the region's navigation layers.
</description>
</method>
<method name="region_get_travel_cost" qualifiers="const">
<return type="float" />
- <argument index="0" name="region" type="RID" />
+ <param index="0" name="region" type="RID" />
<description>
- Returns the [code]travel_cost[/code] of this [code]region[/code].
+ Returns the [code]travel_cost[/code] of this [param region].
</description>
</method>
<method name="region_owns_point" qualifiers="const">
<return type="bool" />
- <argument index="0" name="region" type="RID" />
- <argument index="1" name="point" type="Vector3" />
+ <param index="0" name="region" type="RID" />
+ <param index="1" name="point" type="Vector3" />
<description>
- Returns [code]true[/code] if the provided [code]point[/code] in world space is currently owned by the provided navigation [code]region[/code]. Owned in this context means that one of the region's navigation mesh polygon faces has a possible position at the closest distance to this point compared to all other navigation meshes from other navigation regions that are also registered on the navigation map of the provided region.
+ Returns [code]true[/code] if the provided [param point] in world space is currently owned by the provided navigation [param region]. Owned in this context means that one of the region's navigation mesh polygon faces has a possible position at the closest distance to this point compared to all other navigation meshes from other navigation regions that are also registered on the navigation map of the provided region.
If multiple navigation meshes have positions at equal distance the navigation region whose polygons are processed first wins the ownership. Polygons are processed in the same order that navigation regions were registered on the NavigationServer.
[b]Note:[/b] If navigation meshes from different navigation regions overlap (which should be avoided in general) the result might not be what is expected.
</description>
</method>
<method name="region_set_enter_cost" qualifiers="const">
<return type="void" />
- <argument index="0" name="region" type="RID" />
- <argument index="1" name="enter_cost" type="float" />
+ <param index="0" name="region" type="RID" />
+ <param index="1" name="enter_cost" type="float" />
<description>
- Sets the [code]enter_cost[/code] for this [code]region[/code].
+ Sets the [param enter_cost] for this [param region].
</description>
</method>
<method name="region_set_map" qualifiers="const">
<return type="void" />
- <argument index="0" name="region" type="RID" />
- <argument index="1" name="map" type="RID" />
+ <param index="0" name="region" type="RID" />
+ <param index="1" name="map" type="RID" />
<description>
Sets the map for the region.
</description>
</method>
<method name="region_set_navigation_layers" qualifiers="const">
<return type="void" />
- <argument index="0" name="region" type="RID" />
- <argument index="1" name="navigation_layers" type="int" />
+ <param index="0" name="region" type="RID" />
+ <param index="1" name="navigation_layers" type="int" />
<description>
Set the region's navigation layers. This allows selecting regions from a path request (when using [method NavigationServer3D.map_get_path]).
</description>
</method>
<method name="region_set_navmesh" qualifiers="const">
<return type="void" />
- <argument index="0" name="region" type="RID" />
- <argument index="1" name="nav_mesh" type="NavigationMesh" />
+ <param index="0" name="region" type="RID" />
+ <param index="1" name="nav_mesh" type="NavigationMesh" />
<description>
Sets the navigation mesh for the region.
</description>
</method>
<method name="region_set_transform" qualifiers="const">
<return type="void" />
- <argument index="0" name="region" type="RID" />
- <argument index="1" name="transform" type="Transform3D" />
+ <param index="0" name="region" type="RID" />
+ <param index="1" name="transform" type="Transform3D" />
<description>
Sets the global transformation for the region.
</description>
</method>
<method name="region_set_travel_cost" qualifiers="const">
<return type="void" />
- <argument index="0" name="region" type="RID" />
- <argument index="1" name="travel_cost" type="float" />
+ <param index="0" name="region" type="RID" />
+ <param index="1" name="travel_cost" type="float" />
<description>
- Sets the [code]travel_cost[/code] for this [code]region[/code].
+ Sets the [param travel_cost] for this [param region].
</description>
</method>
<method name="set_active" qualifiers="const">
<return type="void" />
- <argument index="0" name="active" type="bool" />
+ <param index="0" name="active" type="bool" />
<description>
Control activation of this server.
</description>
@@ -410,7 +410,7 @@
</methods>
<signals>
<signal name="map_changed">
- <argument index="0" name="map" type="RID" />
+ <param index="0" name="map" type="RID" />
<description>
Emitted when a navigation map is updated, when a region moves or is modified.
</description>
diff --git a/doc/classes/NinePatchRect.xml b/doc/classes/NinePatchRect.xml
index 863686926a..1592718c4b 100644
--- a/doc/classes/NinePatchRect.xml
+++ b/doc/classes/NinePatchRect.xml
@@ -11,17 +11,17 @@
<methods>
<method name="get_patch_margin" qualifiers="const">
<return type="int" />
- <argument index="0" name="margin" type="int" enum="Side" />
+ <param index="0" name="margin" type="int" enum="Side" />
<description>
Returns the size of the margin on the specified [enum Side].
</description>
</method>
<method name="set_patch_margin">
<return type="void" />
- <argument index="0" name="margin" type="int" enum="Side" />
- <argument index="1" name="value" type="int" />
+ <param index="0" name="margin" type="int" enum="Side" />
+ <param index="1" name="value" type="int" />
<description>
- Sets the size of the margin on the specified [enum Side] to [code]value[/code] pixels.
+ Sets the size of the margin on the specified [enum Side] to [param value] pixels.
</description>
</method>
</methods>
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index 38a497b562..87edc7de0a 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -46,7 +46,7 @@
</method>
<method name="_input" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="event" type="InputEvent" />
+ <param index="0" name="event" type="InputEvent" />
<description>
Called when there is an input event. The input event propagates up through the node tree until a node consumes it.
It is only called if input processing is enabled, which is done automatically if this method is overridden, and can be toggled with [method set_process_input].
@@ -57,9 +57,9 @@
</method>
<method name="_physics_process" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="delta" type="float" />
+ <param index="0" name="delta" type="float" />
<description>
- Called during the physics processing step of the main loop. Physics processing means that the frame rate is synced to the physics, i.e. the [code]delta[/code] variable should be constant. [code]delta[/code] is in seconds.
+ Called during the physics processing step of the main loop. Physics processing means that the frame rate is synced to the physics, i.e. the [param delta] variable should be constant. [param delta] is in seconds.
It is only called if physics processing is enabled, which is done automatically if this method is overridden, and can be toggled with [method set_physics_process].
Corresponds to the [constant NOTIFICATION_PHYSICS_PROCESS] notification in [method Object._notification].
[b]Note:[/b] This method is only called if the node is present in the scene tree (i.e. if it's not an orphan).
@@ -67,9 +67,9 @@
</method>
<method name="_process" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="delta" type="float" />
+ <param index="0" name="delta" type="float" />
<description>
- Called during the processing step of the main loop. Processing happens at every frame and as fast as possible, so the [code]delta[/code] time since the previous frame is not constant. [code]delta[/code] is in seconds.
+ Called during the processing step of the main loop. Processing happens at every frame and as fast as possible, so the [param delta] time since the previous frame is not constant. [param delta] is in seconds.
It is only called if processing is enabled, which is done automatically if this method is overridden, and can be toggled with [method set_process].
Corresponds to the [constant NOTIFICATION_PROCESS] notification in [method Object._notification].
[b]Note:[/b] This method is only called if the node is present in the scene tree (i.e. if it's not an orphan).
@@ -86,7 +86,7 @@
</method>
<method name="_shortcut_input" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="event" type="InputEvent" />
+ <param index="0" name="event" type="InputEvent" />
<description>
Called when an [InputEventKey] or [InputEventShortcut] hasn't been consumed by [method _input] or any GUI [Control] item. The input event propagates up through the node tree until a node consumes it.
It is only called if shortcut processing is enabled, which is done automatically if this method is overridden, and can be toggled with [method set_process_shortcut_input].
@@ -97,7 +97,7 @@
</method>
<method name="_unhandled_input" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="event" type="InputEvent" />
+ <param index="0" name="event" type="InputEvent" />
<description>
Called when an [InputEvent] hasn't been consumed by [method _input] or any GUI [Control] item. The input event propagates up through the node tree until a node consumes it.
It is only called if unhandled input processing is enabled, which is done automatically if this method is overridden, and can be toggled with [method set_process_unhandled_input].
@@ -108,7 +108,7 @@
</method>
<method name="_unhandled_key_input" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="event" type="InputEvent" />
+ <param index="0" name="event" type="InputEvent" />
<description>
Called when an [InputEventKey] or [InputEventShortcut] hasn't been consumed by [method _input] or any GUI [Control] item. The input event propagates up through the node tree until a node consumes it.
It is only called if unhandled key input processing is enabled, which is done automatically if this method is overridden, and can be toggled with [method set_process_unhandled_key_input].
@@ -120,13 +120,13 @@
</method>
<method name="add_child">
<return type="void" />
- <argument index="0" name="node" type="Node" />
- <argument index="1" name="legible_unique_name" type="bool" default="false" />
- <argument index="2" name="internal" type="int" enum="Node.InternalMode" default="0" />
+ <param index="0" name="node" type="Node" />
+ <param index="1" name="legible_unique_name" type="bool" default="false" />
+ <param index="2" name="internal" type="int" enum="Node.InternalMode" default="0" />
<description>
Adds a child node. Nodes can have any number of children, but every child must have a unique name. Child nodes are automatically deleted when the parent node is deleted, so an entire scene can be removed by deleting its topmost node.
- If [code]legible_unique_name[/code] is [code]true[/code], the child node will have a human-readable name based on the name of the node being instantiated instead of its type.
- If [code]internal[/code] is different than [constant INTERNAL_MODE_DISABLED], the child will be added as internal node. Such nodes are ignored by methods like [method get_children], unless their parameter [code]include_internal[/code] is [code]true[/code].The intended usage is to hide the internal nodes from the user, so the user won't accidentally delete or modify them. Used by some GUI nodes, e.g. [ColorPicker]. See [enum InternalMode] for available modes.
+ If [param legible_unique_name] is [code]true[/code], the child node will have a human-readable name based on the name of the node being instantiated instead of its type.
+ If [param internal] is different than [constant INTERNAL_MODE_DISABLED], the child will be added as internal node. Such nodes are ignored by methods like [method get_children], unless their parameter [code]include_internal[/code] is [code]true[/code].The intended usage is to hide the internal nodes from the user, so the user won't accidentally delete or modify them. Used by some GUI nodes, e.g. [ColorPicker]. See [enum InternalMode] for available modes.
[b]Note:[/b] If the child node already has a parent, the function will fail. Use [method remove_child] first to remove the node from its current parent. For example:
[codeblocks]
[gdscript]
@@ -150,22 +150,22 @@
</method>
<method name="add_sibling">
<return type="void" />
- <argument index="0" name="sibling" type="Node" />
- <argument index="1" name="legible_unique_name" type="bool" default="false" />
+ <param index="0" name="sibling" type="Node" />
+ <param index="1" name="legible_unique_name" type="bool" default="false" />
<description>
- Adds a [code]sibling[/code] node to current's node parent, at the same level as that node, right below it.
- If [code]legible_unique_name[/code] is [code]true[/code], the child node will have a human-readable name based on the name of the node being instantiated instead of its type.
+ Adds a [param sibling] node to current's node parent, at the same level as that node, right below it.
+ If [param legible_unique_name] is [code]true[/code], the child node will have a human-readable name based on the name of the node being instantiated instead of its type.
Use [method add_child] instead of this method if you don't need the child node to be added below a specific node in the list of children.
[b]Note:[/b] If this node is internal, the new sibling will be internal too (see [code]internal[/code] parameter in [method add_child]).
</description>
</method>
<method name="add_to_group">
<return type="void" />
- <argument index="0" name="group" type="StringName" />
- <argument index="1" name="persistent" type="bool" default="false" />
+ <param index="0" name="group" type="StringName" />
+ <param index="1" name="persistent" type="bool" default="false" />
<description>
Adds the node to a group. Groups are helpers to name and organize a subset of nodes, for example "enemies" or "collectables". A node can be in any number of groups. Nodes can be assigned a group at any time, but will not be added until they are inside the scene tree (see [method is_inside_tree]). See notes in the description, and the group methods in [SceneTree].
- The [code]persistent[/code] option is used when packing node to [PackedScene] and saving to file. Non-persistent groups aren't stored.
+ The [param persistent] option is used when packing node to [PackedScene] and saving to file. Non-persistent groups aren't stored.
[b]Note:[/b] For performance reasons, the order of node groups is [i]not[/i] guaranteed. The order of node groups should not be relied upon as it can vary across project runs.
</description>
</method>
@@ -186,23 +186,23 @@
</method>
<method name="duplicate" qualifiers="const">
<return type="Node" />
- <argument index="0" name="flags" type="int" default="15" />
+ <param index="0" name="flags" type="int" default="15" />
<description>
Duplicates the node, returning a new node.
- You can fine-tune the behavior using the [code]flags[/code] (see [enum DuplicateFlags]).
+ You can fine-tune the behavior using the [param flags] (see [enum DuplicateFlags]).
[b]Note:[/b] It will not work properly if the node contains a script with constructor arguments (i.e. needs to supply arguments to [method Object._init] method). In that case, the node will be duplicated without a script.
</description>
</method>
<method name="find_child" qualifiers="const">
<return type="Node" />
- <argument index="0" name="pattern" type="String" />
- <argument index="1" name="recursive" type="bool" default="true" />
- <argument index="2" name="owned" type="bool" default="true" />
- <description>
- Finds the first descendant of this node whose name matches [code]pattern[/code] as in [method String.match].
- [code]pattern[/code] does not match against the full path, just against individual node names. It is case-sensitive, with [code]"*"[/code] matching zero or more characters and [code]"?"[/code] matching any single character except [code]"."[/code]).
- If [code]recursive[/code] is [code]true[/code], all child nodes are included, even if deeply nested. Nodes are checked in tree order, so this node's first direct child is checked first, then its own direct children, etc., before moving to the second direct child, and so on. If [code]recursive[/code] is [code]false[/code], only this node's direct children are matched.
- If [code]owned[/code] is [code]true[/code], this method only finds nodes who have an assigned [member Node.owner]. This is especially important for scenes instantiated through a script, because those scenes don't have an owner.
+ <param index="0" name="pattern" type="String" />
+ <param index="1" name="recursive" type="bool" default="true" />
+ <param index="2" name="owned" type="bool" default="true" />
+ <description>
+ Finds the first descendant of this node whose name matches [param pattern] as in [method String.match].
+ [param pattern] does not match against the full path, just against individual node names. It is case-sensitive, with [code]"*"[/code] matching zero or more characters and [code]"?"[/code] matching any single character except [code]"."[/code]).
+ If [param recursive] is [code]true[/code], all child nodes are included, even if deeply nested. Nodes are checked in tree order, so this node's first direct child is checked first, then its own direct children, etc., before moving to the second direct child, and so on. If [param recursive] is [code]false[/code], only this node's direct children are matched.
+ If [param owned] is [code]true[/code], this method only finds nodes who have an assigned [member Node.owner]. This is especially important for scenes instantiated through a script, because those scenes don't have an owner.
Returns [code]null[/code] if no matching [Node] is found.
[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] with unique names instead (see [member unique_name_in_owner]), or caching the node references into variable.
[b]Note:[/b] To find all descendant nodes matching a pattern or a class type, see [method find_children].
@@ -210,16 +210,16 @@
</method>
<method name="find_children" qualifiers="const">
<return type="Node[]" />
- <argument index="0" name="pattern" type="String" />
- <argument index="1" name="type" type="String" default="&quot;&quot;" />
- <argument index="2" name="recursive" type="bool" default="true" />
- <argument index="3" name="owned" type="bool" default="true" />
- <description>
- Finds descendants of this node whose name matches [code]pattern[/code] as in [method String.match], and/or type matches [code]type[/code] as in [method Object.is_class].
- [code]pattern[/code] does not match against the full path, just against individual node names. It is case-sensitive, with [code]"*"[/code] matching zero or more characters and [code]"?"[/code] matching any single character except [code]"."[/code]).
- [code]type[/code] will check equality or inheritance, and is case-sensitive. [code]"Object"[/code] will match a node whose type is [code]"Node"[/code] but not the other way around.
- If [code]recursive[/code] is [code]true[/code], all child nodes are included, even if deeply nested. Nodes are checked in tree order, so this node's first direct child is checked first, then its own direct children, etc., before moving to the second direct child, and so on. If [code]recursive[/code] is [code]false[/code], only this node's direct children are matched.
- If [code]owned[/code] is [code]true[/code], this method only finds nodes who have an assigned [member Node.owner]. This is especially important for scenes instantiated through a script, because those scenes don't have an owner.
+ <param index="0" name="pattern" type="String" />
+ <param index="1" name="type" type="String" default="&quot;&quot;" />
+ <param index="2" name="recursive" type="bool" default="true" />
+ <param index="3" name="owned" type="bool" default="true" />
+ <description>
+ Finds descendants of this node whose name matches [param pattern] as in [method String.match], and/or type matches [param type] as in [method Object.is_class].
+ [param pattern] does not match against the full path, just against individual node names. It is case-sensitive, with [code]"*"[/code] matching zero or more characters and [code]"?"[/code] matching any single character except [code]"."[/code]).
+ [param type] will check equality or inheritance, and is case-sensitive. [code]"Object"[/code] will match a node whose type is [code]"Node"[/code] but not the other way around.
+ If [param recursive] is [code]true[/code], all child nodes are included, even if deeply nested. Nodes are checked in tree order, so this node's first direct child is checked first, then its own direct children, etc., before moving to the second direct child, and so on. If [param recursive] is [code]false[/code], only this node's direct children are matched.
+ If [param owned] is [code]true[/code], this method only finds nodes who have an assigned [member Node.owner]. This is especially important for scenes instantiated through a script, because those scenes don't have an owner.
Returns an empty array if no matching nodes are found.
[b]Note:[/b] As this method walks through all the descendants of the node, it is the slowest way to get references to other nodes. Whenever possible, consider caching the node references into variables.
[b]Note:[/b] If you only want to find the first descendant node that matches a pattern, see [method find_child].
@@ -227,42 +227,42 @@
</method>
<method name="find_parent" qualifiers="const">
<return type="Node" />
- <argument index="0" name="pattern" type="String" />
+ <param index="0" name="pattern" type="String" />
<description>
- Finds the first parent of the current node whose name matches [code]pattern[/code] as in [method String.match].
- [code]pattern[/code] does not match against the full path, just against individual node names. It is case-sensitive, with [code]"*"[/code] matching zero or more characters and [code]"?"[/code] matching any single character except [code]"."[/code]).
+ Finds the first parent of the current node whose name matches [param pattern] as in [method String.match].
+ [param pattern] does not match against the full path, just against individual node names. It is case-sensitive, with [code]"*"[/code] matching zero or more characters and [code]"?"[/code] matching any single character except [code]"."[/code]).
[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] with unique names instead (see [member unique_name_in_owner]), or caching the node references into variable.
</description>
</method>
<method name="get_child" qualifiers="const">
<return type="Node" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="include_internal" type="bool" default="false" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="include_internal" type="bool" default="false" />
<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.
- If [code]include_internal[/code] is [code]true[/code], internal children are skipped (see [code]internal[/code] parameter in [method add_child]).
+ If [param include_internal] is [code]false[/code], internal children are skipped (see [code]internal[/code] parameter in [method add_child]).
To access a child node via its name, use [method get_node].
</description>
</method>
<method name="get_child_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="include_internal" type="bool" default="false" />
+ <param index="0" name="include_internal" type="bool" default="false" />
<description>
Returns the number of child nodes.
- If [code]include_internal[/code] is [code]false[/code], internal children aren't counted (see [code]internal[/code] parameter in [method add_child]).
+ If [param include_internal] is [code]false[/code], internal children aren't counted (see [code]internal[/code] parameter in [method add_child]).
</description>
</method>
<method name="get_children" qualifiers="const">
<return type="Node[]" />
- <argument index="0" name="include_internal" type="bool" default="false" />
+ <param index="0" name="include_internal" type="bool" default="false" />
<description>
Returns an array of references to node's children.
- If [code]include_internal[/code] is [code]false[/code], the returned array won't include internal children (see [code]internal[/code] parameter in [method add_child]).
+ If [param include_internal] is [code]false[/code], the returned array won't include internal children (see [code]internal[/code] parameter in [method add_child]).
</description>
</method>
<method name="get_groups" qualifiers="const">
- <return type="Array" />
+ <return type="StringName[]" />
<description>
Returns an array listing the groups that the node is a member of.
[b]Note:[/b] For performance reasons, the order of node groups is [i]not[/i] guaranteed. The order of node groups should not be relied upon as it can vary across project runs.
@@ -278,10 +278,10 @@
</method>
<method name="get_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="include_internal" type="bool" default="false" />
+ <param index="0" name="include_internal" type="bool" default="false" />
<description>
Returns the node's order in the scene tree branch. For example, if called on the first child node the position is [code]0[/code].
- If [code]include_internal[/code] is [code]false[/code], the index won't take internal children into account, i.e. first non-internal child will have index of 0 (see [code]internal[/code] parameter in [method add_child]).
+ If [param include_internal] is [code]false[/code], the index won't take internal children into account, i.e. first non-internal child will have index of 0 (see [code]internal[/code] parameter in [method add_child]).
</description>
</method>
<method name="get_multiplayer_authority" qualifiers="const">
@@ -292,7 +292,7 @@
</method>
<method name="get_node" qualifiers="const">
<return type="Node" />
- <argument index="0" name="path" type="NodePath" />
+ <param index="0" name="path" type="NodePath" />
<description>
Fetches a node. The [NodePath] can be either a relative path (from the current node) or an absolute path (in the scene tree) to a node. If the path does not exist, [code]null[/code] is returned and an error is logged. Attempts to access methods on the return value will result in an "Attempt to call &lt;method&gt; on a null instance." error.
[b]Note:[/b] Fetching absolute paths only works when the node is inside the scene tree (see [method is_inside_tree]).
@@ -326,7 +326,7 @@
</method>
<method name="get_node_and_resource">
<return type="Array" />
- <argument index="0" name="path" type="NodePath" />
+ <param index="0" name="path" type="NodePath" />
<description>
Fetches a node and one of its resources as specified by the [NodePath]'s subname (e.g. [code]Area2D/CollisionShape2D:shape[/code]). If several nested resources are specified in the [NodePath], the last one will be fetched.
The return value is an array of size 3: the first index points to the [Node] (or [code]null[/code] if not found), the second index points to the [Resource] (or [code]null[/code] if not found), and the third index is the remaining [NodePath], if any.
@@ -347,9 +347,9 @@
</method>
<method name="get_node_or_null" qualifiers="const">
<return type="Node" />
- <argument index="0" name="path" type="NodePath" />
+ <param index="0" name="path" type="NodePath" />
<description>
- Similar to [method get_node], but does not log an error if [code]path[/code] does not point to a valid [Node].
+ Similar to [method get_node], but does not log an error if [param path] does not point to a valid [Node].
</description>
</method>
<method name="get_parent" qualifiers="const">
@@ -366,9 +366,9 @@
</method>
<method name="get_path_to" qualifiers="const">
<return type="NodePath" />
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
- Returns the relative [NodePath] from this node to the specified [code]node[/code]. Both nodes must be in the same scene or the function will fail.
+ Returns the relative [NodePath] from this node to the specified [param node]. Both nodes must be in the same scene or the function will fail.
</description>
</method>
<method name="get_physics_process_delta_time" qualifiers="const">
@@ -403,21 +403,21 @@
</method>
<method name="has_node" qualifiers="const">
<return type="bool" />
- <argument index="0" name="path" type="NodePath" />
+ <param index="0" name="path" type="NodePath" />
<description>
Returns [code]true[/code] if the node that the [NodePath] points to exists.
</description>
</method>
<method name="has_node_and_resource" qualifiers="const">
<return type="bool" />
- <argument index="0" name="path" type="NodePath" />
+ <param index="0" name="path" type="NodePath" />
<description>
Returns [code]true[/code] if the [NodePath] points to a valid node and its subname points to a valid resource, e.g. [code]Area2D/CollisionShape2D:shape[/code]. Properties with a non-[Resource] type (e.g. nodes or primitive math types) are not considered resources.
</description>
</method>
<method name="is_ancestor_of" qualifiers="const">
<return type="bool" />
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
Returns [code]true[/code] if the given node is a direct or indirect child of the current node.
</description>
@@ -430,21 +430,21 @@
</method>
<method name="is_editable_instance" qualifiers="const">
<return type="bool" />
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
- Returns [code]true[/code] if [code]node[/code] has editable children enabled relative to this node. This method is only intended for use with editor tooling.
+ Returns [code]true[/code] if [param node] has editable children enabled relative to this node. This method is only intended for use with editor tooling.
</description>
</method>
<method name="is_greater_than" qualifiers="const">
<return type="bool" />
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
Returns [code]true[/code] if the given node occurs later in the scene hierarchy than the current node.
</description>
</method>
<method name="is_in_group" qualifiers="const">
<return type="bool" />
- <argument index="0" name="group" type="StringName" />
+ <param index="0" name="group" type="StringName" />
<description>
Returns [code]true[/code] if this node is in the specified group. See notes in the description, and the group methods in [SceneTree].
</description>
@@ -511,8 +511,8 @@
</method>
<method name="move_child">
<return type="void" />
- <argument index="0" name="child_node" type="Node" />
- <argument index="1" name="to_position" type="int" />
+ <param index="0" name="child_node" type="Node" />
+ <param index="1" name="to_position" type="int" />
<description>
Moves a child node to a different position (order) among the other children. Since calls, signals, etc are performed by tree order, changing the order of children nodes may be useful.
[b]Note:[/b] Internal children can only be moved within their expected "internal range" (see [code]internal[/code] parameter in [method add_child]).
@@ -557,16 +557,16 @@
</method>
<method name="propagate_call">
<return type="void" />
- <argument index="0" name="method" type="StringName" />
- <argument index="1" name="args" type="Array" default="[]" />
- <argument index="2" name="parent_first" type="bool" default="false" />
+ <param index="0" name="method" type="StringName" />
+ <param index="1" name="args" type="Array" default="[]" />
+ <param index="2" name="parent_first" type="bool" default="false" />
<description>
- Calls the given method (if present) with the arguments given in [code]args[/code] on this node and recursively on all its children. If the [code]parent_first[/code] argument is [code]true[/code], the method will be called on the current node first, then on all its children. If [code]parent_first[/code] is [code]false[/code], the children will be called first.
+ Calls the given method (if present) with the arguments given in [param args] on this node and recursively on all its children. If the [param parent_first] argument is [code]true[/code], the method will be called on the current node first, then on all its children. If [param parent_first] is [code]false[/code], the children will be called first.
</description>
</method>
<method name="propagate_notification">
<return type="void" />
- <argument index="0" name="what" type="int" />
+ <param index="0" name="what" type="int" />
<description>
Notifies the current node and all its children recursively by calling [method Object.notification] on all of them.
</description>
@@ -591,7 +591,7 @@
</method>
<method name="remove_child">
<return type="void" />
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
Removes a child node. The node is NOT deleted and must be deleted manually.
[b]Note:[/b] This function may set the [member owner] of the removed Node (or its descendants) to be [code]null[/code], if that [member owner] is no longer a parent or ancestor.
@@ -599,18 +599,18 @@
</method>
<method name="remove_from_group">
<return type="void" />
- <argument index="0" name="group" type="StringName" />
+ <param index="0" name="group" type="StringName" />
<description>
Removes a node from a group. See notes in the description, and the group methods in [SceneTree].
</description>
</method>
<method name="replace_by">
<return type="void" />
- <argument index="0" name="node" type="Node" />
- <argument index="1" name="keep_groups" type="bool" default="false" />
+ <param index="0" name="node" type="Node" />
+ <param index="1" name="keep_groups" type="bool" default="false" />
<description>
Replaces a node in a scene by the given one. Subscriptions that pass through this node will be lost.
- If [code]keep_groups[/code] is [code]true[/code], the [code]node[/code] is added to the same groups that the replaced node is in.
+ If [param keep_groups] is [code]true[/code], the [param node] is added to the same groups that the replaced node is in.
[b]Note:[/b] The given node will become the new parent of any child nodes that the replaced node had.
[b]Note:[/b] The replaced node is not automatically freed, so you either need to keep it in a variable for later use or free it using [method Object.free].
</description>
@@ -623,18 +623,18 @@
</method>
<method name="rpc" qualifiers="vararg">
<return type="int" enum="Error" />
- <argument index="0" name="method" type="StringName" />
+ <param index="0" name="method" type="StringName" />
<description>
- Sends a remote procedure call request for the given [code]method[/code] to peers on the network (and locally), optionally sending all additional arguments as arguments to the method called by the RPC. The call request will only be received by nodes with the same [NodePath], including the exact same node name. Behaviour depends on the RPC configuration for the given method, see [method rpc_config]. Methods are not exposed to RPCs by default. Returns [code]null[/code].
+ Sends a remote procedure call request for the given [param method] to peers on the network (and locally), optionally sending all additional arguments as arguments to the method called by the RPC. The call request will only be received by nodes with the same [NodePath], including the exact same node name. Behaviour depends on the RPC configuration for the given method, see [method rpc_config]. Methods are not exposed to RPCs by default. Returns [code]null[/code].
[b]Note:[/b] You can only safely use RPCs on clients after you received the [code]connected_to_server[/code] signal from the [MultiplayerAPI]. You also need to keep track of the connection state, either by the [MultiplayerAPI] signals like [code]server_disconnected[/code] or by checking [code]get_multiplayer().peer.get_connection_status() == CONNECTION_CONNECTED[/code].
</description>
</method>
<method name="rpc_config">
<return type="void" />
- <argument index="0" name="method" type="StringName" />
- <argument index="1" name="config" type="Variant" />
+ <param index="0" name="method" type="StringName" />
+ <param index="1" name="config" type="Variant" />
<description>
- Changes the RPC mode for the given [code]method[/code] with the given [code]config[/code] which should be [code]null[/code] (to disable) or a [Dictionary] in the form:
+ Changes the RPC mode for the given [param method] with the given [param config] which should be [code]null[/code] (to disable) or a [Dictionary] in the form:
[codeblock]
{
rpc_mode = MultiplayerAPI.RPCMode,
@@ -648,45 +648,45 @@
</method>
<method name="rpc_id" qualifiers="vararg">
<return type="int" enum="Error" />
- <argument index="0" name="peer_id" type="int" />
- <argument index="1" name="method" type="StringName" />
+ <param index="0" name="peer_id" type="int" />
+ <param index="1" name="method" type="StringName" />
<description>
- Sends a [method rpc] to a specific peer identified by [code]peer_id[/code] (see [method MultiplayerPeer.set_target_peer]). Returns [code]null[/code].
+ Sends a [method rpc] to a specific peer identified by [param peer_id] (see [method MultiplayerPeer.set_target_peer]). Returns [code]null[/code].
</description>
</method>
<method name="set_display_folded">
<return type="void" />
- <argument index="0" name="fold" type="bool" />
+ <param index="0" name="fold" type="bool" />
<description>
Sets the folded state of the node in the Scene dock. This method is only intended for use with editor tooling.
</description>
</method>
<method name="set_editable_instance">
<return type="void" />
- <argument index="0" name="node" type="Node" />
- <argument index="1" name="is_editable" type="bool" />
+ <param index="0" name="node" type="Node" />
+ <param index="1" name="is_editable" type="bool" />
<description>
- Sets the editable children state of [code]node[/code] relative to this node. This method is only intended for use with editor tooling.
+ Sets the editable children state of [param node] relative to this node. This method is only intended for use with editor tooling.
</description>
</method>
<method name="set_multiplayer_authority">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="recursive" type="bool" default="true" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="recursive" type="bool" default="true" />
<description>
- Sets the node's multiplayer authority to the peer with the given peer ID. The multiplayer authority is the peer that has authority over the node on the network. Useful in conjunction with [method rpc_config] and the [MultiplayerAPI]. Inherited from the parent node by default, which ultimately defaults to peer ID 1 (the server). If [code]recursive[/code], the given peer is recursively set as the authority for all children of this node.
+ Sets the node's multiplayer authority to the peer with the given peer ID. The multiplayer authority is the peer that has authority over the node on the network. Useful in conjunction with [method rpc_config] and the [MultiplayerAPI]. Inherited from the parent node by default, which ultimately defaults to peer ID 1 (the server). If [param recursive], the given peer is recursively set as the authority for all children of this node.
</description>
</method>
<method name="set_physics_process">
<return type="void" />
- <argument index="0" name="enable" type="bool" />
+ <param index="0" name="enable" type="bool" />
<description>
Enables or disables physics (i.e. fixed framerate) processing. When a node is being processed, it will receive a [constant NOTIFICATION_PHYSICS_PROCESS] at a fixed (usually 60 FPS, see [member Engine.physics_ticks_per_second] to change) interval (and the [method _physics_process] callback will be called if exists). Enabled automatically if [method _physics_process] is overridden. Any calls to this before [method _ready] will be ignored.
</description>
</method>
<method name="set_physics_process_internal">
<return type="void" />
- <argument index="0" name="enable" type="bool" />
+ <param index="0" name="enable" type="bool" />
<description>
Enables or disables internal physics for this node. Internal physics processing happens in isolation from the normal [method _physics_process] calls and is used by some nodes internally to guarantee proper functioning even if the node is paused or physics processing is disabled for scripting ([method set_physics_process]). Only useful for advanced uses to manipulate built-in nodes' behavior.
[b]Warning:[/b] Built-in Nodes rely on the internal processing for their own logic, so changing this value from your code may lead to unexpected behavior. Script access to this internal logic is provided for specific advanced uses, but is unsafe and not supported.
@@ -694,21 +694,21 @@
</method>
<method name="set_process">
<return type="void" />
- <argument index="0" name="enable" type="bool" />
+ <param index="0" name="enable" type="bool" />
<description>
Enables or disables processing. When a node is being processed, it will receive a [constant NOTIFICATION_PROCESS] on every drawn frame (and the [method _process] callback will be called if exists). Enabled automatically if [method _process] is overridden. Any calls to this before [method _ready] will be ignored.
</description>
</method>
<method name="set_process_input">
<return type="void" />
- <argument index="0" name="enable" type="bool" />
+ <param index="0" name="enable" type="bool" />
<description>
Enables or disables input processing. This is not required for GUI controls! Enabled automatically if [method _input] is overridden. Any calls to this before [method _ready] will be ignored.
</description>
</method>
<method name="set_process_internal">
<return type="void" />
- <argument index="0" name="enable" type="bool" />
+ <param index="0" name="enable" type="bool" />
<description>
Enables or disabled internal processing for this node. Internal processing happens in isolation from the normal [method _process] calls and is used by some nodes internally to guarantee proper functioning even if the node is paused or processing is disabled for scripting ([method set_process]). Only useful for advanced uses to manipulate built-in nodes' behavior.
[b]Warning:[/b] Built-in Nodes rely on the internal processing for their own logic, so changing this value from your code may lead to unexpected behavior. Script access to this internal logic is provided for specific advanced uses, but is unsafe and not supported.
@@ -716,28 +716,28 @@
</method>
<method name="set_process_shortcut_input">
<return type="void" />
- <argument index="0" name="enable" type="bool" />
+ <param index="0" name="enable" type="bool" />
<description>
Enables shortcut processing. Enabled automatically if [method _shortcut_input] is overridden. Any calls to this before [method _ready] will be ignored.
</description>
</method>
<method name="set_process_unhandled_input">
<return type="void" />
- <argument index="0" name="enable" type="bool" />
+ <param index="0" name="enable" type="bool" />
<description>
Enables unhandled input processing. This is not required for GUI controls! It enables the node to receive all input that was not previously handled (usually by a [Control]). Enabled automatically if [method _unhandled_input] is overridden. Any calls to this before [method _ready] will be ignored.
</description>
</method>
<method name="set_process_unhandled_key_input">
<return type="void" />
- <argument index="0" name="enable" type="bool" />
+ <param index="0" name="enable" type="bool" />
<description>
Enables unhandled key input processing. Enabled automatically if [method _unhandled_key_input] is overridden. Any calls to this before [method _ready] will be ignored.
</description>
</method>
<method name="set_scene_instance_load_placeholder">
<return type="void" />
- <argument index="0" name="load_placeholder" type="bool" />
+ <param index="0" name="load_placeholder" type="bool" />
<description>
Sets whether this is an instance load placeholder. See [InstancePlaceholder].
</description>
@@ -781,17 +781,17 @@
</members>
<signals>
<signal name="child_entered_tree">
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
Emitted when a child node enters the scene tree, either because it entered on its own or because this node entered with it.
This signal is emitted [i]after[/i] the child node's own [constant NOTIFICATION_ENTER_TREE] and [signal tree_entered].
</description>
</signal>
<signal name="child_exiting_tree">
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
Emitted when a child node is about to exit the scene tree, either because it is being removed or freed directly, or because this node is exiting the tree.
- When this signal is received, the child [code]node[/code] is still in the tree and valid. This signal is emitted [i]after[/i] the child node's own [signal tree_exiting] and [constant NOTIFICATION_EXIT_TREE].
+ When this signal is received, the child [param node] is still in the tree and valid. This signal is emitted [i]after[/i] the child node's own [signal tree_exiting] and [constant NOTIFICATION_EXIT_TREE].
</description>
</signal>
<signal name="ready">
diff --git a/doc/classes/Node2D.xml b/doc/classes/Node2D.xml
index 2238be4ece..a587811260 100644
--- a/doc/classes/Node2D.xml
+++ b/doc/classes/Node2D.xml
@@ -13,82 +13,82 @@
<methods>
<method name="apply_scale">
<return type="void" />
- <argument index="0" name="ratio" type="Vector2" />
+ <param index="0" name="ratio" type="Vector2" />
<description>
- Multiplies the current scale by the [code]ratio[/code] vector.
+ Multiplies the current scale by the [param ratio] vector.
</description>
</method>
<method name="get_angle_to" qualifiers="const">
<return type="float" />
- <argument index="0" name="point" type="Vector2" />
+ <param index="0" name="point" type="Vector2" />
<description>
- Returns the angle between the node and the [code]point[/code] in radians.
+ Returns the angle between the node and the [param point] in radians.
[url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/node2d_get_angle_to.png]Illustration of the returned angle.[/url]
</description>
</method>
<method name="get_relative_transform_to_parent" qualifiers="const">
<return type="Transform2D" />
- <argument index="0" name="parent" type="Node" />
+ <param index="0" name="parent" type="Node" />
<description>
Returns the [Transform2D] relative to this node's parent.
</description>
</method>
<method name="global_translate">
<return type="void" />
- <argument index="0" name="offset" type="Vector2" />
+ <param index="0" name="offset" type="Vector2" />
<description>
- Adds the [code]offset[/code] vector to the node's global position.
+ Adds the [param offset] vector to the node's global position.
</description>
</method>
<method name="look_at">
<return type="void" />
- <argument index="0" name="point" type="Vector2" />
+ <param index="0" name="point" type="Vector2" />
<description>
- Rotates the node so it points towards the [code]point[/code], which is expected to use global coordinates.
+ Rotates the node so it points towards the [param point], which is expected to use global coordinates.
</description>
</method>
<method name="move_local_x">
<return type="void" />
- <argument index="0" name="delta" type="float" />
- <argument index="1" name="scaled" type="bool" default="false" />
+ <param index="0" name="delta" type="float" />
+ <param index="1" name="scaled" type="bool" default="false" />
<description>
- Applies a local translation on the node's X axis based on the [method Node._process]'s [code]delta[/code]. If [code]scaled[/code] is [code]false[/code], normalizes the movement.
+ Applies a local translation on the node's X axis based on the [method Node._process]'s [param delta]. If [param scaled] is [code]false[/code], normalizes the movement.
</description>
</method>
<method name="move_local_y">
<return type="void" />
- <argument index="0" name="delta" type="float" />
- <argument index="1" name="scaled" type="bool" default="false" />
+ <param index="0" name="delta" type="float" />
+ <param index="1" name="scaled" type="bool" default="false" />
<description>
- Applies a local translation on the node's Y axis based on the [method Node._process]'s [code]delta[/code]. If [code]scaled[/code] is [code]false[/code], normalizes the movement.
+ Applies a local translation on the node's Y axis based on the [method Node._process]'s [param delta]. If [param scaled] is [code]false[/code], normalizes the movement.
</description>
</method>
<method name="rotate">
<return type="void" />
- <argument index="0" name="radians" type="float" />
+ <param index="0" name="radians" type="float" />
<description>
Applies a rotation to the node, in radians, starting from its current rotation.
</description>
</method>
<method name="to_global" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="local_point" type="Vector2" />
+ <param index="0" name="local_point" type="Vector2" />
<description>
Transforms the provided local position into a position in global coordinate space. The input is expected to be local relative to the [Node2D] it is called on. e.g. Applying this method to the positions of child nodes will correctly transform their positions into the global coordinate space, but applying it to a node's own position will give an incorrect result, as it will incorporate the node's own transformation into its global position.
</description>
</method>
<method name="to_local" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="global_point" type="Vector2" />
+ <param index="0" name="global_point" type="Vector2" />
<description>
Transforms the provided global position into a position in local coordinate space. The output will be local relative to the [Node2D] it is called on. e.g. It is appropriate for determining the positions of child nodes, but it is not appropriate for determining its own position relative to its parent.
</description>
</method>
<method name="translate">
<return type="void" />
- <argument index="0" name="offset" type="Vector2" />
+ <param index="0" name="offset" type="Vector2" />
<description>
- Translates the node by the given [code]offset[/code] in local coordinates.
+ Translates the node by the given [param offset] in local coordinates.
</description>
</method>
</methods>
diff --git a/doc/classes/Node3D.xml b/doc/classes/Node3D.xml
index ff2afd595a..c8e2f1ac68 100644
--- a/doc/classes/Node3D.xml
+++ b/doc/classes/Node3D.xml
@@ -6,7 +6,7 @@
<description>
Most basic 3D game object, with a 3D [Transform3D] and visibility settings. All other 3D game objects inherit from Node3D. Use [Node3D] as a parent node to move, scale, rotate and show/hide children in a 3D project.
Affine operations (rotate, scale, translate) happen in parent's local coordinate system, unless the [Node3D] object is set as top-level. Affine operations in this coordinate system correspond to direct affine operations on the [Node3D]'s transform. The word local below refers to this coordinate system. The coordinate system that is attached to the [Node3D] object itself is referred to as object-local coordinate system.
- [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 @GlobalScope.deg2rad].
+ [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 @GlobalScope.deg_to_rad].
</description>
<tutorials>
<link title="Introduction to 3D">$DOCS_URL/tutorials/3d/introduction_to_3d.html</link>
@@ -15,7 +15,7 @@
<methods>
<method name="add_gizmo">
<return type="void" />
- <argument index="0" name="gizmo" type="Node3DGizmo" />
+ <param index="0" name="gizmo" type="Node3DGizmo" />
<description>
Attach a gizmo to this [code]Node3D[/code].
</description>
@@ -39,7 +39,7 @@
</description>
</method>
<method name="get_gizmos" qualifiers="const">
- <return type="Array" />
+ <return type="Node3DGizmo[]" />
<description>
Returns all the gizmos attached to this [code]Node3D[/code].
</description>
@@ -58,22 +58,22 @@
</method>
<method name="global_rotate">
<return type="void" />
- <argument index="0" name="axis" type="Vector3" />
- <argument index="1" name="angle" type="float" />
+ <param index="0" name="axis" type="Vector3" />
+ <param index="1" name="angle" type="float" />
<description>
Rotates the global (world) transformation around axis, a unit [Vector3], by specified angle in radians. The rotation axis is in global coordinate system.
</description>
</method>
<method name="global_scale">
<return type="void" />
- <argument index="0" name="scale" type="Vector3" />
+ <param index="0" name="scale" type="Vector3" />
<description>
Scales the global (world) transformation by the given [Vector3] scale factors.
</description>
</method>
<method name="global_translate">
<return type="void" />
- <argument index="0" name="offset" type="Vector3" />
+ <param index="0" name="offset" type="Vector3" />
<description>
Moves the global (world) transformation by [Vector3] offset. The offset is in global coordinate system.
</description>
@@ -110,22 +110,22 @@
</method>
<method name="look_at">
<return type="void" />
- <argument index="0" name="target" type="Vector3" />
- <argument index="1" name="up" type="Vector3" default="Vector3(0, 1, 0)" />
+ <param index="0" name="target" type="Vector3" />
+ <param index="1" name="up" type="Vector3" default="Vector3(0, 1, 0)" />
<description>
- Rotates the node so that the local forward axis (-Z) points toward the [code]target[/code] position.
- The local up axis (+Y) points as close to the [code]up[/code] vector as possible while staying perpendicular to the local forward axis. The resulting transform is orthogonal, and the scale is preserved. Non-uniform scaling may not work correctly.
- The [code]target[/code] position cannot be the same as the node's position, the [code]up[/code] vector cannot be zero, and the direction from the node's position to the [code]target[/code] vector cannot be parallel to the [code]up[/code] vector.
+ Rotates the node so that the local forward axis (-Z) points toward the [param target] position.
+ The local up axis (+Y) points as close to the [param up] vector as possible while staying perpendicular to the local forward axis. The resulting transform is orthogonal, and the scale is preserved. Non-uniform scaling may not work correctly.
+ The [param target] position cannot be the same as the node's position, the [param up] vector cannot be zero, and the direction from the node's position to the [param target] vector cannot be parallel to the [param up] vector.
Operations take place in global space.
</description>
</method>
<method name="look_at_from_position">
<return type="void" />
- <argument index="0" name="position" type="Vector3" />
- <argument index="1" name="target" type="Vector3" />
- <argument index="2" name="up" type="Vector3" default="Vector3(0, 1, 0)" />
+ <param index="0" name="position" type="Vector3" />
+ <param index="1" name="target" type="Vector3" />
+ <param index="2" name="up" type="Vector3" default="Vector3(0, 1, 0)" />
<description>
- Moves the node to the specified [code]position[/code], and then rotates the node to point toward the [code]target[/code] as per [method look_at]. Operations take place in global space.
+ Moves the node to the specified [param position], and then rotates the node to point toward the [param target] as per [method look_at]. Operations take place in global space.
</description>
</method>
<method name="orthonormalize">
@@ -134,67 +134,53 @@
Resets this node's transformations (like scale, skew and taper) preserving its rotation and translation by performing Gram-Schmidt orthonormalization on this node's [Transform3D].
</description>
</method>
- <method name="property_can_revert">
- <return type="bool" />
- <argument index="0" name="name" type="String" />
- <description>
- Returns [code]true[/code] if the property identified by [code]name[/code] can be reverted to a default value.
- </description>
- </method>
- <method name="property_get_revert">
- <return type="Variant" />
- <argument index="0" name="name" type="String" />
- <description>
- Returns the default value of the Node3D property with given [code]name[/code].
- </description>
- </method>
<method name="rotate">
<return type="void" />
- <argument index="0" name="axis" type="Vector3" />
- <argument index="1" name="angle" type="float" />
+ <param index="0" name="axis" type="Vector3" />
+ <param index="1" name="angle" type="float" />
<description>
Rotates the local transformation around axis, a unit [Vector3], by specified angle in radians.
</description>
</method>
<method name="rotate_object_local">
<return type="void" />
- <argument index="0" name="axis" type="Vector3" />
- <argument index="1" name="angle" type="float" />
+ <param index="0" name="axis" type="Vector3" />
+ <param index="1" name="angle" type="float" />
<description>
Rotates the local transformation around axis, a unit [Vector3], by specified angle in radians. The rotation axis is in object-local coordinate system.
</description>
</method>
<method name="rotate_x">
<return type="void" />
- <argument index="0" name="angle" type="float" />
+ <param index="0" name="angle" type="float" />
<description>
Rotates the local transformation around the X axis by angle in radians.
</description>
</method>
<method name="rotate_y">
<return type="void" />
- <argument index="0" name="angle" type="float" />
+ <param index="0" name="angle" type="float" />
<description>
Rotates the local transformation around the Y axis by angle in radians.
</description>
</method>
<method name="rotate_z">
<return type="void" />
- <argument index="0" name="angle" type="float" />
+ <param index="0" name="angle" type="float" />
<description>
Rotates the local transformation around the Z axis by angle in radians.
</description>
</method>
<method name="scale_object_local">
<return type="void" />
- <argument index="0" name="scale" type="Vector3" />
+ <param index="0" name="scale" type="Vector3" />
<description>
Scales the local transformation by given 3D scale factors in object-local coordinate system.
</description>
</method>
<method name="set_disable_scale">
<return type="void" />
- <argument index="0" name="disable" type="bool" />
+ <param index="0" name="disable" type="bool" />
<description>
Sets whether the node uses a scale of [code](1, 1, 1)[/code] or its local transformation scale. Changes to the local transformation scale are preserved.
</description>
@@ -207,30 +193,30 @@
</method>
<method name="set_ignore_transform_notification">
<return type="void" />
- <argument index="0" name="enabled" type="bool" />
+ <param index="0" name="enabled" type="bool" />
<description>
Sets whether the node ignores notification that its transformation (global or local) changed.
</description>
</method>
<method name="set_notify_local_transform">
<return type="void" />
- <argument index="0" name="enable" type="bool" />
+ <param index="0" name="enable" type="bool" />
<description>
Sets whether the node notifies about its local transformation changes. [Node3D] will not propagate this by default.
</description>
</method>
<method name="set_notify_transform">
<return type="void" />
- <argument index="0" name="enable" type="bool" />
+ <param index="0" name="enable" type="bool" />
<description>
Sets whether the node notifies about its global and local transformation changes. [Node3D] will not propagate this by default, unless it is in the editor context and it has a valid gizmo.
</description>
</method>
<method name="set_subgizmo_selection">
<return type="void" />
- <argument index="0" name="gizmo" type="Node3DGizmo" />
- <argument index="1" name="id" type="int" />
- <argument index="2" name="transform" type="Transform3D" />
+ <param index="0" name="gizmo" type="Node3DGizmo" />
+ <param index="1" name="id" type="int" />
+ <param index="2" name="transform" type="Transform3D" />
<description>
Set subgizmo selection for this node in the editor.
</description>
@@ -243,29 +229,29 @@
</method>
<method name="to_global" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="local_point" type="Vector3" />
+ <param index="0" name="local_point" type="Vector3" />
<description>
- Transforms [code]local_point[/code] from this node's local space to world space.
+ Transforms [param local_point] from this node's local space to world space.
</description>
</method>
<method name="to_local" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="global_point" type="Vector3" />
+ <param index="0" name="global_point" type="Vector3" />
<description>
- Transforms [code]global_point[/code] from world space to this node's local space.
+ Transforms [param global_point] from world space to this node's local space.
</description>
</method>
<method name="translate">
<return type="void" />
- <argument index="0" name="offset" type="Vector3" />
+ <param index="0" name="offset" type="Vector3" />
<description>
Changes the node's position by the given offset [Vector3].
- Note that the translation [code]offset[/code] is affected by the node's scale, so if scaled by e.g. [code](10, 1, 1)[/code], a translation by an offset of [code](2, 0, 0)[/code] would actually add 20 ([code]2 * 10[/code]) to the X coordinate.
+ Note that the translation [param offset] is affected by the node's scale, so if scaled by e.g. [code](10, 1, 1)[/code], a translation by an offset of [code](2, 0, 0)[/code] would actually add 20 ([code]2 * 10[/code]) to the X coordinate.
</description>
</method>
<method name="translate_object_local">
<return type="void" />
- <argument index="0" name="offset" type="Vector3" />
+ <param index="0" name="offset" type="Vector3" />
<description>
Changes the node's position by the given offset [Vector3] in local space.
</description>
diff --git a/doc/classes/NodePath.xml b/doc/classes/NodePath.xml
index d9e0680a38..9db100c9f8 100644
--- a/doc/classes/NodePath.xml
+++ b/doc/classes/NodePath.xml
@@ -35,14 +35,14 @@
</constructor>
<constructor name="NodePath">
<return type="NodePath" />
- <argument index="0" name="from" type="NodePath" />
+ <param index="0" name="from" type="NodePath" />
<description>
Constructs a [NodePath] as a copy of the given [NodePath]. [code]NodePath("example")[/code] is equivalent to [code]^"example"[/code].
</description>
</constructor>
<constructor name="NodePath">
<return type="NodePath" />
- <argument index="0" name="from" type="String" />
+ <param index="0" name="from" type="String" />
<description>
Creates a NodePath from a string, e.g. [code]"Path2D/PathFollow2D/Sprite2D:texture:size"[/code]. A path is absolute if it starts with a slash. Absolute paths are only valid in the global scene tree, not within individual scenes. In a relative path, [code]"."[/code] and [code]".."[/code] indicate the current node and its parent.
The "subnames" optionally included after the path to the target node can point to resources or properties, and can also be nested.
@@ -111,9 +111,9 @@
</method>
<method name="get_name" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Gets the node name indicated by [code]idx[/code] (0 to [method get_name_count] - 1).
+ Gets the node name indicated by [param idx] (0 to [method get_name_count] - 1).
[codeblocks]
[gdscript]
var node_path = NodePath("Path2D/PathFollow2D/Sprite2D")
@@ -139,9 +139,9 @@
</method>
<method name="get_subname" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Gets the resource or property name indicated by [code]idx[/code] (0 to [method get_subname_count]).
+ Gets the resource or property name indicated by [param idx] (0 to [method get_subname_count]).
[codeblocks]
[gdscript]
var node_path = NodePath("Path2D/PathFollow2D/Sprite2D:texture:load_path")
@@ -185,13 +185,13 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="NodePath" />
+ <param index="0" name="right" type="NodePath" />
<description>
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="NodePath" />
+ <param index="0" name="right" type="NodePath" />
<description>
</description>
</operator>
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index 5473347cb1..059766656f 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -12,8 +12,8 @@
<methods>
<method name="alert">
<return type="void" />
- <argument index="0" name="text" type="String" />
- <argument index="1" name="title" type="String" default="&quot;Alert!&quot;" />
+ <param index="0" name="text" type="String" />
+ <param index="1" name="title" type="String" default="&quot;Alert!&quot;" />
<description>
Displays a modal dialog box using the host OS' facilities. Execution is blocked until the dialog is closed.
</description>
@@ -33,28 +33,28 @@
</method>
<method name="crash">
<return type="void" />
- <argument index="0" name="message" type="String" />
+ <param index="0" name="message" type="String" />
<description>
Crashes the engine (or the editor if called within a [code]@tool[/code] script). This should [i]only[/i] be used for testing the system's crash handler, not for any other purpose. For general error reporting, use (in order of preference) [method @GDScript.assert], [method @GlobalScope.push_error] or [method alert]. See also [method kill].
</description>
</method>
<method name="create_instance">
<return type="int" />
- <argument index="0" name="arguments" type="PackedStringArray" />
+ <param index="0" name="arguments" type="PackedStringArray" />
<description>
- Creates a new instance of Godot that runs independently. The [code]arguments[/code] are used in the given order and separated by a space.
+ Creates a new instance of Godot that runs independently. The [param arguments] are used in the given order and separated by a space.
If the process creation succeeds, the method will return the new process ID, which you can use to monitor the process (and potentially terminate it with [method kill]). If the process creation fails, the method will return [code]-1[/code].
[b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows.
</description>
</method>
<method name="create_process">
<return type="int" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="arguments" type="PackedStringArray" />
- <argument index="2" name="open_console" type="bool" default="false" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="arguments" type="PackedStringArray" />
+ <param index="2" name="open_console" type="bool" default="false" />
<description>
- Creates a new process that runs independently of Godot. It will not terminate if Godot terminates. The path specified in [code]path[/code] must exist and be executable file or macOS .app bundle. Platform path resolution will be used. The [code]arguments[/code] are used in the given order and separated by a space.
- On Windows, if [code]open_console[/code] is [code]true[/code] and the process is a console app, a new terminal window will be opened. This is ignored on other platforms.
+ Creates a new process that runs independently of Godot. It will not terminate if Godot terminates. The path specified in [param path] must exist and be executable file or macOS .app bundle. Platform path resolution will be used. The [param arguments] are used in the given order and separated by a space.
+ On Windows, if [param open_console] is [code]true[/code] and the process is a console app, a new terminal window will be opened. This is ignored on other platforms.
If the process creation succeeds, the method will return the new process ID, which you can use to monitor the process (and potentially terminate it with [method kill]). If the process creation fails, the method will return [code]-1[/code].
For example, running another instance of the project:
[codeblocks]
@@ -72,49 +72,32 @@
</method>
<method name="delay_msec" qualifiers="const">
<return type="void" />
- <argument index="0" name="msec" type="int" />
+ <param index="0" name="msec" type="int" />
<description>
- Delays execution of the current thread by [code]msec[/code] milliseconds. [code]msec[/code] must be greater than or equal to [code]0[/code]. Otherwise, [method delay_msec] will do nothing and will print an error message.
+ Delays execution of the current thread by [param msec] milliseconds. [param msec] must be greater than or equal to [code]0[/code]. Otherwise, [method delay_msec] will do nothing and will print an error message.
[b]Note:[/b] [method delay_msec] is a [i]blocking[/i] way to delay code execution. To delay code execution in a non-blocking way, see [method SceneTree.create_timer]. Awaiting with [method SceneTree.create_timer] will delay the execution of code placed below the [code]await[/code] without affecting the rest of the project (or editor, for [EditorPlugin]s and [EditorScript]s).
[b]Note:[/b] When [method delay_msec] is called on the main thread, it will freeze the project and will prevent it from redrawing and registering input until the delay has passed. When using [method delay_msec] as part of an [EditorPlugin] or [EditorScript], it will freeze the editor but won't freeze the project if it is currently running (since the project is an independent child process).
</description>
</method>
<method name="delay_usec" qualifiers="const">
<return type="void" />
- <argument index="0" name="usec" type="int" />
+ <param index="0" name="usec" type="int" />
<description>
- Delays execution of the current thread by [code]usec[/code] microseconds. [code]usec[/code] must be greater than or equal to [code]0[/code]. Otherwise, [method delay_usec] will do nothing and will print an error message.
+ Delays execution of the current thread by [param usec] microseconds. [param usec] must be greater than or equal to [code]0[/code]. Otherwise, [method delay_usec] will do nothing and will print an error message.
[b]Note:[/b] [method delay_usec] is a [i]blocking[/i] way to delay code execution. To delay code execution in a non-blocking way, see [method SceneTree.create_timer]. Awaiting with [method SceneTree.create_timer] will delay the execution of code placed below the [code]await[/code] without affecting the rest of the project (or editor, for [EditorPlugin]s and [EditorScript]s).
[b]Note:[/b] When [method delay_usec] is called on the main thread, it will freeze the project and will prevent it from redrawing and registering input until the delay has passed. When using [method delay_usec] as part of an [EditorPlugin] or [EditorScript], it will freeze the editor but won't freeze the project if it is currently running (since the project is an independent child process).
</description>
</method>
- <method name="dump_memory_to_file">
- <return type="void" />
- <argument index="0" name="file" type="String" />
- <description>
- Dumps the memory allocation ringlist to a file (only works in debug).
- Entry format per line: "Address - Size - Description".
- </description>
- </method>
- <method name="dump_resources_to_file">
- <return type="void" />
- <argument index="0" name="file" type="String" />
- <description>
- Dumps all used resources to file (only works in debug).
- Entry format per line: "Resource Type : Resource Location".
- At the end of the file is a statistic of all used Resource Types.
- </description>
- </method>
<method name="execute">
<return type="int" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="arguments" type="PackedStringArray" />
- <argument index="2" name="output" type="Array" default="[]" />
- <argument index="3" name="read_stderr" type="bool" default="false" />
- <argument index="4" name="open_console" type="bool" default="false" />
- <description>
- Executes a command. The file specified in [code]path[/code] must exist and be executable. Platform path resolution will be used. The [code]arguments[/code] are used in the given order and separated by a space. If an [code]output[/code] [Array] is provided, the complete shell output of the process will be appended as a single [String] element in [code]output[/code]. If [code]read_stderr[/code] is [code]true[/code], the output to the standard error stream will be included too.
- On Windows, if [code]open_console[/code] is [code]true[/code] and the process is a console app, a new terminal window will be opened. This is ignored on other platforms.
+ <param index="0" name="path" type="String" />
+ <param index="1" name="arguments" type="PackedStringArray" />
+ <param index="2" name="output" type="Array" default="[]" />
+ <param index="3" name="read_stderr" type="bool" default="false" />
+ <param index="4" name="open_console" type="bool" default="false" />
+ <description>
+ Executes a command. The file specified in [param path] must exist and be executable. Platform path resolution will be used. The [param arguments] are used in the given order and separated by a space. If an [param output] [Array] is provided, the complete shell output of the process will be appended as a single [String] element in [param output]. If [param read_stderr] is [code]true[/code], the output to the standard error stream will be included too.
+ On Windows, if [param open_console] is [code]true[/code] and the process is a console app, a new terminal window will be opened. This is ignored on other platforms.
If the command is successfully executed, the method will return the exit code of the command, or [code]-1[/code] if it fails.
[b]Note:[/b] The Godot thread will pause its execution until the executed command terminates. Use [Thread] to create a separate thread that will not pause the Godot thread, or use [method create_process] to create a completely independent process.
For example, to retrieve a list of the working directory's contents:
@@ -140,15 +123,15 @@
[/csharp]
[/codeblocks]
[b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows.
- [b]Note:[/b] To execute a Windows command interpreter built-in command, specify [code]cmd.exe[/code] in [code]path[/code], [code]/c[/code] as the first argument, and the desired command as the second argument.
- [b]Note:[/b] To execute a PowerShell built-in command, specify [code]powershell.exe[/code] in [code]path[/code], [code]-Command[/code] as the first argument, and the desired command as the second argument.
- [b]Note:[/b] To execute a Unix shell built-in command, specify shell executable name in [code]path[/code], [code]-c[/code] as the first argument, and the desired command as the second argument.
+ [b]Note:[/b] To execute a Windows command interpreter built-in command, specify [code]cmd.exe[/code] in [param path], [code]/c[/code] as the first argument, and the desired command as the second argument.
+ [b]Note:[/b] To execute a PowerShell built-in command, specify [code]powershell.exe[/code] in [param path], [code]-Command[/code] as the first argument, and the desired command as the second argument.
+ [b]Note:[/b] To execute a Unix shell built-in command, specify shell executable name in [param path], [code]-c[/code] as the first argument, and the desired command as the second argument.
[b]Note:[/b] On macOS, sandboxed applications are limited to run only embedded helper executables, specified during export.
</description>
</method>
<method name="find_keycode_from_string" qualifiers="const">
<return type="int" enum="Key" />
- <argument index="0" name="string" type="String" />
+ <param index="0" name="string" type="String" />
<description>
Returns the keycode of the given string (e.g. "Escape").
</description>
@@ -198,6 +181,17 @@
}
[/csharp]
[/codeblocks]
+ [b]Note:[/b] Passing custom user arguments directly is not recommended, as the engine may discard or modify them. Instead, the best way is to use the standard UNIX double dash ([code]--[/code]) and then pass custom arguments, which the engine itself will ignore. These can be read via [method get_cmdline_user_args].
+ </description>
+ </method>
+ <method name="get_cmdline_user_args">
+ <return type="PackedStringArray" />
+ <description>
+ Similar to [method get_cmdline_args], but this returns the user arguments (any argument passed after the double dash [code]--[/code] argument). These are left untouched by Godot for the user.
+ For example, in the command line below, [code]--fullscreen[/code] will not be returned in [method get_cmdline_user_args] and [code]--level 1[/code] will only be returned in [method get_cmdline_user_args]:
+ [codeblock]
+ godot --fullscreen -- --level 1
+ [/codeblock]
</description>
</method>
<method name="get_config_dir" qualifiers="const">
@@ -224,10 +218,10 @@
</method>
<method name="get_environment" qualifiers="const">
<return type="String" />
- <argument index="0" name="variable" type="String" />
+ <param index="0" name="variable" type="String" />
<description>
Returns the value of an environment variable. Returns an empty string if the environment variable doesn't exist.
- [b]Note:[/b] Double-check the casing of [code]variable[/code]. Environment variable names are case-sensitive on all platforms except Windows.
+ [b]Note:[/b] Double-check the casing of [param variable]. Environment variable names are case-sensitive on all platforms except Windows.
</description>
</method>
<method name="get_executable_path" qualifiers="const">
@@ -246,7 +240,7 @@
</method>
<method name="get_keycode_string" qualifiers="const">
<return type="String" />
- <argument index="0" name="code" type="int" enum="Key" />
+ <param index="0" name="code" type="int" enum="Key" />
<description>
Returns the given keycode as a string (e.g. Return values: [code]"Escape"[/code], [code]"Shift+Escape"[/code]).
See also [member InputEventKey.keycode] and [method InputEventKey.get_keycode_with_modifiers].
@@ -294,7 +288,7 @@
On BSD-based operating systems, this is [code]"FreeBSD"[/code], [code]"NetBSD"[/code], [code]"OpenBSD"[/code], or [code]"BSD"[/code] as a fallback.
On Android, this is [code]"Android"[/code].
On iOS, this is [code]"iOS"[/code].
- On the web, this is [code]"HTML5"[/code].
+ On the web, this is [code]"Web"[/code].
[b]Note:[/b] Custom builds of the engine may support additional platforms, such as consoles, yielding other return values.
[codeblocks]
[gdscript]
@@ -309,7 +303,7 @@
print("Android")
"iOS":
print("iOS")
- "HTML5":
+ "Web":
print("Web")
[/gdscript]
[csharp]
@@ -335,7 +329,7 @@
case "iOS":
GD.Print("iOS");
break;
- case "HTML5":
+ case "Web":
GD.Print("Web");
break;
}
@@ -360,7 +354,13 @@
<return type="String" />
<description>
Returns the name of the CPU model on the host machine (e.g. "Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz").
- [b]Note:[/b] This method is only implemented on Windows, macOS, Linux and iOS. On Android, HTML5 and UWP, [method get_processor_name] returns an empty string.
+ [b]Note:[/b] This method is only implemented on Windows, macOS, Linux and iOS. On Android, Web and UWP, [method get_processor_name] returns an empty string.
+ </description>
+ </method>
+ <method name="get_restart_on_exit_arguments" qualifiers="const">
+ <return type="PackedStringArray" />
+ <description>
+ Returns the list of command line arguments that will be used when the project automatically restarts using [method set_restart_on_exit]. See also [method is_restart_on_exit_set].
</description>
</method>
<method name="get_static_memory_peak_usage" qualifiers="const">
@@ -377,8 +377,8 @@
</method>
<method name="get_system_dir" qualifiers="const">
<return type="String" />
- <argument index="0" name="dir" type="int" enum="OS.SystemDir" />
- <argument index="1" name="shared_storage" type="bool" default="true" />
+ <param index="0" name="dir" type="int" enum="OS.SystemDir" />
+ <param index="1" name="shared_storage" type="bool" default="true" />
<description>
Returns the actual path to commonly used folders across different platforms. Available locations are specified in [enum SystemDir].
[b]Note:[/b] This method is implemented on Android, Linux, macOS and Windows.
@@ -387,11 +387,11 @@
</method>
<method name="get_system_font_path" qualifiers="const">
<return type="String" />
- <argument index="0" name="font_name" type="String" />
- <argument index="1" name="bold" type="bool" default="false" />
- <argument index="2" name="italic" type="bool" default="false" />
+ <param index="0" name="font_name" type="String" />
+ <param index="1" name="bold" type="bool" default="false" />
+ <param index="2" name="italic" type="bool" default="false" />
<description>
- Returns path to the system font file with [code]font_name[/code] and style. Return empty string if no matching fonts found.
+ Returns path to the system font file with [param font_name] and style. Return empty string if no matching fonts found.
[b]Note:[/b] This method is implemented on iOS, Linux, macOS and Windows.
</description>
</method>
@@ -414,7 +414,7 @@
<description>
Returns a string that is unique to the device.
[b]Note:[/b] This string may change without notice if the user reinstalls/upgrades their operating system or changes their hardware. This means it should generally not be used to encrypt persistent data as the data saved before an unexpected ID change would become inaccessible. The returned string may also be falsified using external programs, so do not rely on the string returned by [method get_unique_id] for security purposes.
- [b]Note:[/b] Returns an empty string on HTML5 and UWP, as this method isn't implemented on those platforms yet.
+ [b]Note:[/b] Returns an empty string on Web and UWP, as this method isn't implemented on those platforms yet.
</description>
</method>
<method name="get_user_data_dir" qualifiers="const">
@@ -432,15 +432,15 @@
</method>
<method name="has_environment" qualifiers="const">
<return type="bool" />
- <argument index="0" name="variable" type="String" />
+ <param index="0" name="variable" type="String" />
<description>
- Returns [code]true[/code] if the environment variable with the name [code]variable[/code] exists.
- [b]Note:[/b] Double-check the casing of [code]variable[/code]. Environment variable names are case-sensitive on all platforms except Windows.
+ Returns [code]true[/code] if the environment variable with the name [param variable] exists.
+ [b]Note:[/b] Double-check the casing of [param variable]. Environment variable names are case-sensitive on all platforms except Windows.
</description>
</method>
<method name="has_feature" qualifiers="const">
<return type="bool" />
- <argument index="0" name="tag_name" type="String" />
+ <param index="0" name="tag_name" type="String" />
<description>
Returns [code]true[/code] if the feature for the given feature tag is supported in the currently running instance, depending on the platform, build, etc. Can be used to check whether you're currently running a debug build, on a certain platform or arch, etc. Refer to the [url=$DOCS_URL/getting_started/workflow/export/feature_tags.html]Feature Tags[/url] documentation for more details.
[b]Note:[/b] Tag names are case-sensitive.
@@ -456,20 +456,26 @@
</method>
<method name="is_keycode_unicode" qualifiers="const">
<return type="bool" />
- <argument index="0" name="code" type="int" />
+ <param index="0" name="code" type="int" />
<description>
Returns [code]true[/code] if the input keycode corresponds to a Unicode character.
</description>
</method>
<method name="is_process_running" qualifiers="const">
<return type="bool" />
- <argument index="0" name="pid" type="int" />
+ <param index="0" name="pid" type="int" />
<description>
- Returns [code]true[/code] if the child process ID ([code]pid[/code]) is still running or [code]false[/code] if it has terminated.
+ Returns [code]true[/code] if the child process ID ([param pid]) is still running or [code]false[/code] if it has terminated.
Must be a valid ID generated from [method create_process].
[b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows.
</description>
</method>
+ <method name="is_restart_on_exit_set" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if the project will automatically restart when it exits for any reason, [code]false[/code] otherwise. See also [method set_restart_on_exit] and [method get_restart_on_exit_arguments].
+ </description>
+ </method>
<method name="is_stdout_verbose" qualifiers="const">
<return type="bool" />
<description>
@@ -479,21 +485,21 @@
<method name="is_userfs_persistent" qualifiers="const">
<return type="bool" />
<description>
- If [code]true[/code], the [code]user://[/code] file system is persistent, so that its state is the same after a player quits and starts the game again. Relevant to the HTML5 platform, where this persistence may be unavailable.
+ If [code]true[/code], the [code]user://[/code] file system is persistent, so that its state is the same after a player quits and starts the game again. Relevant to the Web platform, where this persistence may be unavailable.
</description>
</method>
<method name="kill">
<return type="int" enum="Error" />
- <argument index="0" name="pid" type="int" />
+ <param index="0" name="pid" type="int" />
<description>
- Kill (terminate) the process identified by the given process ID ([code]pid[/code]), e.g. the one returned by [method execute] in non-blocking mode. See also [method crash].
+ Kill (terminate) the process identified by the given process ID ([param pid]), e.g. the one returned by [method execute] in non-blocking mode. See also [method crash].
[b]Note:[/b] This method can also be used to kill processes that were not spawned by the game.
[b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows.
</description>
</method>
<method name="move_to_trash" qualifiers="const">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Moves the file or directory to the system's recycle bin. See also [method Directory.remove].
The method takes only global paths, so you may need to use [method ProjectSettings.globalize_path]. Do not use it for files in [code]res://[/code] as it will not work in exported project.
@@ -511,36 +517,9 @@
[b]Note:[/b] This method is implemented on Linux, macOS and Windows.
</description>
</method>
- <method name="print_all_resources">
- <return type="void" />
- <argument index="0" name="tofile" type="String" default="&quot;&quot;" />
- <description>
- Shows all resources in the game. Optionally, the list can be written to a file by specifying a file path in [code]tofile[/code].
- </description>
- </method>
- <method name="print_all_textures_by_size">
- <return type="void" />
- <description>
- Shows the list of loaded textures sorted by size in memory.
- </description>
- </method>
- <method name="print_resources_by_type">
- <return type="void" />
- <argument index="0" name="types" type="PackedStringArray" />
- <description>
- Shows the number of resources loaded by the game of the given types.
- </description>
- </method>
- <method name="print_resources_in_use">
- <return type="void" />
- <argument index="0" name="short" type="bool" default="false" />
- <description>
- Shows all resources currently used by the game.
- </description>
- </method>
<method name="request_permission">
<return type="bool" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
At the moment this function is only used by [code]AudioDriverOpenSL[/code] to request permission for [code]RECORD_AUDIO[/code] on Android.
</description>
@@ -554,37 +533,48 @@
</method>
<method name="set_environment" qualifiers="const">
<return type="bool" />
- <argument index="0" name="variable" type="String" />
- <argument index="1" name="value" type="String" />
+ <param index="0" name="variable" type="String" />
+ <param index="1" name="value" type="String" />
+ <description>
+ Sets the value of the environment variable [param variable] to [param value]. The environment variable will be set for the Godot process and any process executed with [method execute] after running [method set_environment]. The environment variable will [i]not[/i] persist to processes run after the Godot process was terminated.
+ [b]Note:[/b] Double-check the casing of [param variable]. Environment variable names are case-sensitive on all platforms except Windows.
+ </description>
+ </method>
+ <method name="set_restart_on_exit">
+ <return type="void" />
+ <param index="0" name="restart" type="bool" />
+ <param index="1" name="arguments" type="PackedStringArray" default="PackedStringArray()" />
<description>
- Sets the value of the environment variable [code]variable[/code] to [code]value[/code]. The environment variable will be set for the Godot process and any process executed with [method execute] after running [method set_environment]. The environment variable will [i]not[/i] persist to processes run after the Godot process was terminated.
- [b]Note:[/b] Double-check the casing of [code]variable[/code]. Environment variable names are case-sensitive on all platforms except Windows.
+ If [param restart] is [code]true[/code], restarts the project automatically when it is exited with [method SceneTree.quit] or [constant Node.NOTIFICATION_WM_CLOSE_REQUEST]. Command line [param arguments] can be supplied. To restart the project with the same command line arguments as originally used to run the project, pass [method get_cmdline_args] as the value for [param arguments].
+ [method set_restart_on_exit] can be used to apply setting changes that require a restart. See also [method is_restart_on_exit_set] and [method get_restart_on_exit_arguments].
+ [b]Note:[/b] This method is only effective on desktop platforms, and only when the project isn't started from the editor. It will have no effect on mobile and Web platforms, or when the project is started from the editor.
+ [b]Note:[/b] If the project process crashes or is [i]killed[/i] by the user (by sending [code]SIGKILL[/code] instead of the usual [code]SIGTERM[/code]), the project won't restart automatically.
</description>
</method>
<method name="set_thread_name">
<return type="int" enum="Error" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
Sets the name of the current thread.
</description>
</method>
<method name="set_use_file_access_save_and_swap">
<return type="void" />
- <argument index="0" name="enabled" type="bool" />
+ <param index="0" name="enabled" type="bool" />
<description>
- Enables backup saves if [code]enabled[/code] is [code]true[/code].
+ Enables backup saves if [param enabled] is [code]true[/code].
</description>
</method>
<method name="shell_open">
<return type="int" enum="Error" />
- <argument index="0" name="uri" type="String" />
+ <param index="0" name="uri" type="String" />
<description>
Requests the OS to open a resource with the most appropriate program. For example:
- [code]OS.shell_open("C:\\Users\name\Downloads")[/code] on Windows opens the file explorer at the user's Downloads folder.
- [code]OS.shell_open("https://godotengine.org")[/code] opens the default web browser on the official Godot website.
- [code]OS.shell_open("mailto:example@example.com")[/code] opens the default email client with the "To" field set to [code]example@example.com[/code]. See [url=https://datatracker.ietf.org/doc/html/rfc2368]RFC 2368 - The [code]mailto[/code] URL scheme[/url] for a list of fields that can be added.
Use [method ProjectSettings.globalize_path] to convert a [code]res://[/code] or [code]user://[/code] path into a system path for use with this method.
- [b]Note:[/b] This method is implemented on Android, iOS, HTML5, Linux, macOS and Windows.
+ [b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS and Windows.
</description>
</method>
</methods>
@@ -601,7 +591,7 @@
The Vulkan rendering backend. It requires Vulkan 1.0 support and automatically uses features from Vulkan 1.1 and 1.2 if available.
</constant>
<constant name="VIDEO_DRIVER_OPENGL_3" value="1" enum="VideoDriver">
- The OpenGL 3 rendering backend. It uses OpenGL 3.3 Core Profile on desktop platforms, OpenGL ES 3.0 on mobile devices, and WebGL 2.0 on HTML5.
+ The OpenGL 3 rendering backend. It uses OpenGL 3.3 Core Profile on desktop platforms, OpenGL ES 3.0 on mobile devices, and WebGL 2.0 on Web.
</constant>
<constant name="DAY_SUNDAY" value="0" enum="Weekday">
Sunday.
diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml
index 061b32bfdf..3c71a02a21 100644
--- a/doc/classes/Object.xml
+++ b/doc/classes/Object.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Every class which is not a built-in type inherits from this class.
- You can construct Objects from scripting languages, using [code]Object.new()[/code] in GDScript, [code]new Object[/code] in C#, or the "Construct Object" node in VisualScript.
+ You can construct Objects from scripting languages, using [code]Object.new()[/code] in GDScript, or [code]new Object[/code] in C#.
Objects do not manage memory. If a class inherits from Object, you will have to delete instances of it manually. To do so, call the [method free] method from your script or delete the instance from C++.
Some classes that extend Object add memory management. This is the case of [RefCounted], which counts references and deletes itself automatically when no longer referenced. [Node], another fundamental type, deletes all its children when freed from memory.
Objects export properties, which are mainly useful for storage and editing, but not really so much in programming. Properties are exported in [method _get_property_list] and handled in [method _get] and [method _set]. However, scripting languages and C++ have simpler means to export them.
@@ -36,14 +36,14 @@
<methods>
<method name="_get" qualifiers="virtual">
<return type="Variant" />
- <argument index="0" name="property" type="StringName" />
+ <param index="0" name="property" type="StringName" />
<description>
Virtual method which can be overridden to customize the return value of [method get].
- Returns the given property. Returns [code]null[/code] if the [code]property[/code] does not exist.
+ Returns the given property. Returns [code]null[/code] if the [param property] does not exist.
</description>
</method>
<method name="_get_property_list" qualifiers="virtual">
- <return type="Array" />
+ <return type="Dictionary[]" />
<description>
Virtual method which can be overridden to customize the return value of [method get_property_list].
Returns the object's property list as an [Array] of dictionaries.
@@ -59,18 +59,34 @@
</method>
<method name="_notification" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="what" type="int" />
+ <param index="0" name="what" type="int" />
<description>
- Called whenever the object receives a notification, which is identified in [code]what[/code] by a constant. The base [Object] has two constants [constant NOTIFICATION_POSTINITIALIZE] and [constant NOTIFICATION_PREDELETE], but subclasses such as [Node] define a lot more notifications which are also received by this method.
+ Called whenever the object receives a notification, which is identified in [param what] by a constant. The base [Object] has two constants [constant NOTIFICATION_POSTINITIALIZE] and [constant NOTIFICATION_PREDELETE], but subclasses such as [Node] define a lot more notifications which are also received by this method.
+ </description>
+ </method>
+ <method name="_property_can_revert" qualifiers="virtual">
+ <return type="bool" />
+ <param index="0" name="property" type="StringName" />
+ <description>
+ Virtual methods that can be overridden to customize the property revert behavior in the editor.
+ Returns [code]true[/code] if the property identified by [code]name[/code] can be reverted to a default value. Override [method _property_get_revert] to return the actual value.
+ </description>
+ </method>
+ <method name="_property_get_revert" qualifiers="virtual">
+ <return type="Variant" />
+ <param index="0" name="property" type="StringName" />
+ <description>
+ Virtual methods that can be overridden to customize the property revert behavior in the editor.
+ Returns the default value of the property identified by [code]name[/code]. [method _property_can_revert] must be overridden as well for this method to be called.
</description>
</method>
<method name="_set" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="property" type="StringName" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="property" type="StringName" />
+ <param index="1" name="value" type="Variant" />
<description>
Virtual method which can be overridden to customize the return value of [method set].
- Sets a property. Returns [code]true[/code] if the [code]property[/code] exists.
+ Sets a property. Returns [code]true[/code] if the [param property] exists.
</description>
</method>
<method name="_to_string" qualifiers="virtual">
@@ -82,17 +98,17 @@
</method>
<method name="add_user_signal">
<return type="void" />
- <argument index="0" name="signal" type="String" />
- <argument index="1" name="arguments" type="Array" default="[]" />
+ <param index="0" name="signal" type="String" />
+ <param index="1" name="arguments" type="Array" default="[]" />
<description>
- Adds a user-defined [code]signal[/code]. Arguments are optional, but can be added as an [Array] of dictionaries, each containing [code]name: String[/code] and [code]type: int[/code] (see [enum Variant.Type]) entries.
+ Adds a user-defined [param signal]. Arguments are optional, but can be added as an [Array] of dictionaries, each containing [code]name: String[/code] and [code]type: int[/code] (see [enum Variant.Type]) entries.
</description>
</method>
<method name="call" qualifiers="vararg">
<return type="Variant" />
- <argument index="0" name="method" type="StringName" />
+ <param index="0" name="method" type="StringName" />
<description>
- Calls the [code]method[/code] on the object and returns the result. This method supports a variable number of arguments, so parameters are passed as a comma separated list. Example:
+ Calls the [param method] on the object and returns the result. This method supports a variable number of arguments, so parameters are passed as a comma separated list. Example:
[codeblocks]
[gdscript]
var node = Node3D.new()
@@ -108,9 +124,9 @@
</method>
<method name="call_deferred" qualifiers="vararg">
<return type="Variant" />
- <argument index="0" name="method" type="StringName" />
+ <param index="0" name="method" type="StringName" />
<description>
- Calls the [code]method[/code] on the object during idle time. This method supports a variable number of arguments, so parameters are passed as a comma separated list. Example:
+ Calls the [param method] on the object during idle time. This method supports a variable number of arguments, so parameters are passed as a comma separated list. Example:
[codeblocks]
[gdscript]
var node = Node3D.new()
@@ -126,10 +142,10 @@
</method>
<method name="callv">
<return type="Variant" />
- <argument index="0" name="method" type="StringName" />
- <argument index="1" name="arg_array" type="Array" />
+ <param index="0" name="method" type="StringName" />
+ <param index="1" name="arg_array" type="Array" />
<description>
- Calls the [code]method[/code] on the object and returns the result. Contrarily to [method call], this method does not support a variable number of arguments but expects all parameters to be via a single [Array].
+ Calls the [param method] on the object and returns the result. Contrarily to [method call], this method does not support a variable number of arguments but expects all parameters to be via a single [Array].
[codeblocks]
[gdscript]
var node = Node3D.new()
@@ -150,11 +166,11 @@
</method>
<method name="connect">
<return type="int" enum="Error" />
- <argument index="0" name="signal" type="StringName" />
- <argument index="1" name="callable" type="Callable" />
- <argument index="2" name="flags" type="int" default="0" />
+ <param index="0" name="signal" type="StringName" />
+ <param index="1" name="callable" type="Callable" />
+ <param index="2" name="flags" type="int" default="0" />
<description>
- Connects a [code]signal[/code] to a [code]callable[/code]. Use [code]flags[/code] to set deferred or one-shot connections. See [enum ConnectFlags] constants.
+ Connects a [param signal] to a [param callable]. Use [param flags] to set deferred or one-shot connections. See [enum ConnectFlags] constants.
A signal can only be connected once to a [Callable]. It will print an error if already connected, unless the signal was connected with [constant CONNECT_REFERENCE_COUNTED]. To avoid this, first, use [method is_connected] to check for existing connections.
If the callable's target is destroyed in the game's lifecycle, the connection will be lost.
[b]Examples with recommended syntax:[/b]
@@ -291,18 +307,18 @@
</method>
<method name="disconnect">
<return type="void" />
- <argument index="0" name="signal" type="StringName" />
- <argument index="1" name="callable" type="Callable" />
+ <param index="0" name="signal" type="StringName" />
+ <param index="1" name="callable" type="Callable" />
<description>
- Disconnects a [code]signal[/code] from a given [code]callable[/code].
+ Disconnects a [param signal] from a given [param callable].
If you try to disconnect a connection that does not exist, the method will print an error. Use [method is_connected] to ensure that the connection exists.
</description>
</method>
<method name="emit_signal" qualifiers="vararg">
<return type="int" enum="Error" />
- <argument index="0" name="signal" type="StringName" />
+ <param index="0" name="signal" type="StringName" />
<description>
- Emits the given [code]signal[/code]. The signal must exist, so it should be a built-in signal of this class or one of its parent classes, or a user-defined signal. This method supports a variable number of arguments, so parameters are passed as a comma separated list. Example:
+ Emits the given [param signal]. The signal must exist, so it should be a built-in signal of this class or one of its parent classes, or a user-defined signal. This method supports a variable number of arguments, so parameters are passed as a comma separated list. Example:
[codeblocks]
[gdscript]
emit_signal("hit", "sword", 100)
@@ -323,9 +339,9 @@
</method>
<method name="get" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="property" type="StringName" />
+ <param index="0" name="property" type="StringName" />
<description>
- Returns the [Variant] value of the given [code]property[/code]. If the [code]property[/code] doesn't exist, this will return [code]null[/code].
+ Returns the [Variant] value of the given [param property]. If the [param property] doesn't exist, this will return [code]null[/code].
[b]Note:[/b] In C#, the property name must be specified as snake_case if it is defined by a built-in Godot node. This doesn't apply to user-defined properties where you should use the same convention as in the C# source (typically PascalCase).
</description>
</method>
@@ -337,7 +353,7 @@
</description>
</method>
<method name="get_incoming_connections" qualifiers="const">
- <return type="Array" />
+ <return type="Dictionary[]" />
<description>
Returns an [Array] of dictionaries with information about signals that are connected to the object.
Each [Dictionary] contains three String entries:
@@ -348,7 +364,7 @@
</method>
<method name="get_indexed" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="property" type="NodePath" />
+ <param index="0" name="property" type="NodePath" />
<description>
Gets the object's property indexed by the given [NodePath]. The node path should be relative to the current object and can use the colon character ([code]:[/code]) to access nested properties. Examples: [code]"position:x"[/code] or [code]"material:next_pass:blend_mode"[/code].
[b]Note:[/b] Even though the method takes [NodePath] argument, it doesn't support actual paths to [Node]s in the scene tree, only colon-separated sub-property paths. For the purpose of nodes, use [method Node.get_node_and_resource] instead.
@@ -363,11 +379,12 @@
</method>
<method name="get_meta" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="default" type="Variant" default="null" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="default" type="Variant" default="null" />
<description>
- Returns the object's metadata entry for the given [code]name[/code].
- Throws error if the entry does not exist, unless [code]default[/code] is not [code]null[/code] (in which case the default value will be returned).
+ Returns the object's metadata entry for the given [param name].
+ Throws error if the entry does not exist, unless [param default] is not [code]null[/code] (in which case the default value will be returned). See also [method has_meta], [method set_meta] and [method remove_meta].
+ [b]Note:[/b] Metadata that has a [param name] starting with an underscore ([code]_[/code]) is considered editor-only. Editor-only metadata is not displayed in the inspector and should not be edited.
</description>
</method>
<method name="get_meta_list" qualifiers="const">
@@ -377,13 +394,13 @@
</description>
</method>
<method name="get_method_list" qualifiers="const">
- <return type="Array" />
+ <return type="Dictionary[]" />
<description>
Returns the object's methods and their signatures as an [Array].
</description>
</method>
<method name="get_property_list" qualifiers="const">
- <return type="Array" />
+ <return type="Dictionary[]" />
<description>
Returns the object's property list as an [Array] of dictionaries.
Each property's [Dictionary] contain at least [code]name: String[/code] and [code]type: int[/code] (see [enum Variant.Type]) entries. Optionally, it can also include [code]hint: int[/code] (see [enum PropertyHint]), [code]hint_string: String[/code], and [code]usage: int[/code] (see [enum PropertyUsageFlags]).
@@ -396,44 +413,45 @@
</description>
</method>
<method name="get_signal_connection_list" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="signal" type="StringName" />
+ <return type="Dictionary[]" />
+ <param index="0" name="signal" type="StringName" />
<description>
- Returns an [Array] of connections for the given [code]signal[/code].
+ Returns an [Array] of connections for the given [param signal].
</description>
</method>
<method name="get_signal_list" qualifiers="const">
- <return type="Array" />
+ <return type="Dictionary[]" />
<description>
Returns the list of signals as an [Array] of dictionaries.
</description>
</method>
<method name="has_meta" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Returns [code]true[/code] if a metadata entry is found with the given [code]name[/code].
+ Returns [code]true[/code] if a metadata entry is found with the given [param name]. See also [method get_meta], [method set_meta] and [method remove_meta].
+ [b]Note:[/b] Metadata that has a [param name] starting with an underscore ([code]_[/code]) is considered editor-only. Editor-only metadata is not displayed in the inspector and should not be edited.
</description>
</method>
<method name="has_method" qualifiers="const">
<return type="bool" />
- <argument index="0" name="method" type="StringName" />
+ <param index="0" name="method" type="StringName" />
<description>
- Returns [code]true[/code] if the object contains the given [code]method[/code].
+ Returns [code]true[/code] if the object contains the given [param method].
</description>
</method>
<method name="has_signal" qualifiers="const">
<return type="bool" />
- <argument index="0" name="signal" type="StringName" />
+ <param index="0" name="signal" type="StringName" />
<description>
- Returns [code]true[/code] if the given [code]signal[/code] exists.
+ Returns [code]true[/code] if the given [param signal] exists.
</description>
</method>
<method name="has_user_signal" qualifiers="const">
<return type="bool" />
- <argument index="0" name="signal" type="StringName" />
+ <param index="0" name="signal" type="StringName" />
<description>
- Returns [code]true[/code] if the given user-defined [code]signal[/code] exists. Only signals added using [method add_user_signal] are taken into account.
+ Returns [code]true[/code] if the given user-defined [param signal] exists. Only signals added using [method add_user_signal] are taken into account.
</description>
</method>
<method name="is_blocking_signals" qualifiers="const">
@@ -444,18 +462,18 @@
</method>
<method name="is_class" qualifiers="const">
<return type="bool" />
- <argument index="0" name="class" type="String" />
+ <param index="0" name="class" type="String" />
<description>
- Returns [code]true[/code] if the object inherits from the given [code]class[/code]. See also [method get_class].
+ Returns [code]true[/code] if the object inherits from the given [param class]. See also [method get_class].
[b]Note:[/b] [method is_class] does not take [code]class_name[/code] declarations into account. If the object has a [code]class_name[/code] defined, [method is_class] will return [code]false[/code] for that name.
</description>
</method>
<method name="is_connected" qualifiers="const">
<return type="bool" />
- <argument index="0" name="signal" type="StringName" />
- <argument index="1" name="callable" type="Callable" />
+ <param index="0" name="signal" type="StringName" />
+ <param index="1" name="callable" type="Callable" />
<description>
- Returns [code]true[/code] if a connection exists for a given [code]signal[/code] and [code]callable[/code].
+ Returns [code]true[/code] if a connection exists for a given [param signal] and [param callable].
</description>
</method>
<method name="is_queued_for_deletion" qualifiers="const">
@@ -466,11 +484,11 @@
</method>
<method name="notification">
<return type="void" />
- <argument index="0" name="what" type="int" />
- <argument index="1" name="reversed" type="bool" default="false" />
+ <param index="0" name="what" type="int" />
+ <param index="1" name="reversed" type="bool" default="false" />
<description>
Send a given notification to the object, which will also trigger a call to the [method _notification] method of all classes that the object inherits from.
- If [code]reversed[/code] is [code]true[/code], [method _notification] is called first on the object's own class, and then up to its successive parent classes. If [code]reversed[/code] is [code]false[/code], [method _notification] is called first on the highest ancestor ([Object] itself), and then down to its successive inheriting classes.
+ If [param reversed] is [code]true[/code], [method _notification] is called first on the object's own class, and then up to its successive parent classes. If [param reversed] is [code]false[/code], [method _notification] is called first on the highest ancestor ([Object] itself), and then down to its successive inheriting classes.
</description>
</method>
<method name="notify_property_list_changed">
@@ -481,31 +499,32 @@
</method>
<method name="remove_meta">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Removes a given entry from the object's metadata. See also [method set_meta].
+ Removes a given entry from the object's metadata. See also [method has_meta], [method get_meta] and [method set_meta].
+ [b]Note:[/b] Metadata that has a [param name] starting with an underscore ([code]_[/code]) is considered editor-only. Editor-only metadata is not displayed in the inspector and should not be edited.
</description>
</method>
<method name="set">
<return type="void" />
- <argument index="0" name="property" type="StringName" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="property" type="StringName" />
+ <param index="1" name="value" type="Variant" />
<description>
- Assigns a new value to the given property. If the [code]property[/code] does not exist or the given value's type doesn't match, nothing will happen.
+ Assigns a new value to the given property. If the [param property] does not exist or the given value's type doesn't match, nothing will happen.
[b]Note:[/b] In C#, the property name must be specified as snake_case if it is defined by a built-in Godot node. This doesn't apply to user-defined properties where you should use the same convention as in the C# source (typically PascalCase).
</description>
</method>
<method name="set_block_signals">
<return type="void" />
- <argument index="0" name="enable" type="bool" />
+ <param index="0" name="enable" type="bool" />
<description>
If set to [code]true[/code], signal emission is blocked.
</description>
</method>
<method name="set_deferred">
<return type="void" />
- <argument index="0" name="property" type="StringName" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="property" type="StringName" />
+ <param index="1" name="value" type="Variant" />
<description>
Assigns a new value to the given property, after the current frame's physics step. This is equivalent to calling [method set] via [method call_deferred], i.e. [code]call_deferred("set", property, value)[/code].
[b]Note:[/b] In C#, the property name must be specified as snake_case if it is defined by a built-in Godot node. This doesn't apply to user-defined properties where you should use the same convention as in the C# source (typically PascalCase).
@@ -513,8 +532,8 @@
</method>
<method name="set_indexed">
<return type="void" />
- <argument index="0" name="property" type="NodePath" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="property" type="NodePath" />
+ <param index="1" name="value" type="Variant" />
<description>
Assigns a new value to the property identified by the [NodePath]. The node path should be relative to the current object and can use the colon character ([code]:[/code]) to access nested properties. Example:
[codeblocks]
@@ -535,23 +554,24 @@
</method>
<method name="set_message_translation">
<return type="void" />
- <argument index="0" name="enable" type="bool" />
+ <param index="0" name="enable" type="bool" />
<description>
Defines whether the object can translate strings (with calls to [method tr]). Enabled by default.
</description>
</method>
<method name="set_meta">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="value" type="Variant" />
<description>
Adds, changes or removes a given entry in the object's metadata. Metadata are serialized and can take any [Variant] value.
- To remove a given entry from the object's metadata, use [method remove_meta]. Metadata is also removed if its value is set to [code]null[/code]. This means you can also use [code]set_meta("name", null)[/code] to remove metadata for [code]"name"[/code].
+ To remove a given entry from the object's metadata, use [method remove_meta]. Metadata is also removed if its value is set to [code]null[/code]. This means you can also use [code]set_meta("name", null)[/code] to remove metadata for [code]"name"[/code]. See also [method has_meta] and [method get_meta].
+ [b]Note:[/b] Metadata that has a [param name] starting with an underscore ([code]_[/code]) is considered editor-only. Editor-only metadata is not displayed in the inspector and should not be edited.
</description>
</method>
<method name="set_script">
<return type="void" />
- <argument index="0" name="script" type="Variant" />
+ <param index="0" name="script" type="Variant" />
<description>
Assigns a script to the object. Each object can have a single script assigned to it, which are used to extend its functionality.
If the object already had a script, the previous script instance will be freed and its variables and state will be lost. The new script's [method _init] method will be called.
@@ -566,24 +586,24 @@
</method>
<method name="tr" qualifiers="const">
<return type="String" />
- <argument index="0" name="message" type="StringName" />
- <argument index="1" name="context" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="message" type="StringName" />
+ <param index="1" name="context" type="StringName" default="&quot;&quot;" />
<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].
+ Only works if message translation is enabled (which it is by default), otherwise it returns the [param message] unchanged. See [method set_message_translation].
See [url=$DOCS_URL/tutorials/i18n/internationalizing_games.html]Internationalizing games[/url] for examples of the usage of this method.
</description>
</method>
<method name="tr_n" qualifiers="const">
<return type="String" />
- <argument index="0" name="message" type="StringName" />
- <argument index="1" name="plural_message" type="StringName" />
- <argument index="2" name="n" type="int" />
- <argument index="3" name="context" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="message" type="StringName" />
+ <param index="1" name="plural_message" type="StringName" />
+ <param index="2" name="n" type="int" />
+ <param index="3" name="context" type="StringName" default="&quot;&quot;" />
<description>
Translates a message involving plurals 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] 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.
+ Only works if message translation is enabled (which it is by default), otherwise it returns the [param message] or [param plural_message] unchanged. See [method set_message_translation].
+ The number [param n] 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 [url=$DOCS_URL/tutorials/i18n/localization_using_gettext.html]Localization using gettext[/url] for examples of the usage of this method.
</description>
diff --git a/doc/classes/OccluderInstance3D.xml b/doc/classes/OccluderInstance3D.xml
index abd99dd3aa..0bebc7ea43 100644
--- a/doc/classes/OccluderInstance3D.xml
+++ b/doc/classes/OccluderInstance3D.xml
@@ -15,23 +15,23 @@
<methods>
<method name="get_bake_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
- Returns whether or not the specified layer of the [member bake_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
+ Returns whether or not the specified layer of the [member bake_mask] is enabled, given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="set_bake_mask_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
- Based on [code]value[/code], enables or disables the specified layer in the [member bake_mask], given a [code]layer_number[/code] between 1 and 32.
+ Based on [param value], enables or disables the specified layer in the [member bake_mask], given a [param layer_number] between 1 and 32.
</description>
</method>
</methods>
<members>
<member name="bake_mask" type="int" setter="set_bake_mask" getter="get_bake_mask" default="4294967295">
- The visual layers to account for when baking for occluders. Only [MeshInstance3D]s whose [member VisualInstance3D.layers] match with this [member bake_mask] will be included in the generated occluder mesh. By default, all objects are taken into account for the occluder baking.
+ The visual layers to account for when baking for occluders. Only [MeshInstance3D]s whose [member VisualInstance3D.layers] match with this [member bake_mask] will be included in the generated occluder mesh. By default, all objects with [i]opaque[/i] materials are taken into account for the occluder baking.
To improve performance and avoid artifacts, it is recommended to exclude dynamic objects, small objects and fixtures from the baking process by moving them to a separate visual layer and excluding this layer in [member bake_mask].
</member>
<member name="bake_simplification_distance" type="float" setter="set_bake_simplification_distance" getter="get_bake_simplification_distance" default="0.1">
diff --git a/doc/classes/OptimizedTranslation.xml b/doc/classes/OptimizedTranslation.xml
index 68765f9862..54ebfd3146 100644
--- a/doc/classes/OptimizedTranslation.xml
+++ b/doc/classes/OptimizedTranslation.xml
@@ -11,7 +11,7 @@
<methods>
<method name="generate">
<return type="void" />
- <argument index="0" name="from" type="Translation" />
+ <param index="0" name="from" type="Translation" />
<description>
Generates and sets an optimized translation from the given [Translation] resource.
</description>
diff --git a/doc/classes/OptionButton.xml b/doc/classes/OptionButton.xml
index a7b1f0ea33..f10c096c1b 100644
--- a/doc/classes/OptionButton.xml
+++ b/doc/classes/OptionButton.xml
@@ -13,26 +13,26 @@
<methods>
<method name="add_icon_item">
<return type="void" />
- <argument index="0" name="texture" type="Texture2D" />
- <argument index="1" name="label" type="String" />
- <argument index="2" name="id" type="int" default="-1" />
+ <param index="0" name="texture" type="Texture2D" />
+ <param index="1" name="label" type="String" />
+ <param index="2" name="id" type="int" default="-1" />
<description>
- Adds an item, with a [code]texture[/code] icon, text [code]label[/code] and (optionally) [code]id[/code]. If no [code]id[/code] is passed, the item index will be used as the item's ID. New items are appended at the end.
+ Adds an item, with a [param texture] icon, text [param label] and (optionally) [param id]. If no [param id] is passed, the item index will be used as the item's ID. New items are appended at the end.
</description>
</method>
<method name="add_item">
<return type="void" />
- <argument index="0" name="label" type="String" />
- <argument index="1" name="id" type="int" default="-1" />
+ <param index="0" name="label" type="String" />
+ <param index="1" name="id" type="int" default="-1" />
<description>
- Adds an item, with text [code]label[/code] and (optionally) [code]id[/code]. If no [code]id[/code] is passed, the item index will be used as the item's ID. New items are appended at the end.
+ Adds an item, with text [param label] and (optionally) [param id]. If no [param id] is passed, the item index will be used as the item's ID. New items are appended at the end.
</description>
</method>
<method name="add_separator">
<return type="void" />
- <argument index="0" name="text" type="String" default="&quot;&quot;" />
+ <param index="0" name="text" type="String" default="&quot;&quot;" />
<description>
- Adds a separator to the list of items. Separators help to group items, and can optionally be given a [code]text[/code] header. A separator also gets an index assigned, and is appended at the end of the item list.
+ Adds a separator to the list of items. Separators help to group items, and can optionally be given a [param text] header. A separator also gets an index assigned, and is appended at the end of the item list.
</description>
</method>
<method name="clear">
@@ -43,44 +43,44 @@
</method>
<method name="get_item_icon" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the icon of the item at index [code]idx[/code].
+ Returns the icon of the item at index [param idx].
</description>
</method>
<method name="get_item_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the ID of the item at index [code]idx[/code].
+ Returns the ID of the item at index [param idx].
</description>
</method>
<method name="get_item_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
- Returns the index of the item with the given [code]id[/code].
+ Returns the index of the item with the given [param id].
</description>
</method>
<method name="get_item_metadata" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Retrieves the metadata of an item. Metadata may be any type and can be used to store extra information about an item, such as an external string ID.
</description>
</method>
<method name="get_item_text" qualifiers="const">
<return type="String" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the text of the item at index [code]idx[/code].
+ Returns the text of the item at index [param idx].
</description>
</method>
<method name="get_item_tooltip" qualifiers="const">
<return type="String" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the tooltip of the item at index [code]idx[/code].
+ Returns the tooltip of the item at index [param idx].
</description>
</method>
<method name="get_popup" qualifiers="const">
@@ -92,7 +92,7 @@
</method>
<method name="get_selectable_item" qualifiers="const">
<return type="int" />
- <argument index="0" name="from_last" type="bool" default="false" />
+ <param index="0" name="from_last" type="bool" default="false" />
<description>
</description>
</method>
@@ -115,27 +115,27 @@
</method>
<method name="is_item_disabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns [code]true[/code] if the item at index [code]idx[/code] is disabled.
+ Returns [code]true[/code] if the item at index [param idx] is disabled.
</description>
</method>
<method name="is_item_separator" qualifiers="const">
<return type="bool" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
</description>
</method>
<method name="remove_item">
<return type="void" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Removes the item at index [code]idx[/code].
+ Removes the item at index [param idx].
</description>
</method>
<method name="select">
<return type="void" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Selects an item by index and makes it the current item. This will work even if the item is disabled.
Passing [code]-1[/code] as the index deselects any currently selected item.
@@ -143,57 +143,61 @@
</method>
<method name="set_item_disabled">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="disabled" type="bool" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="disabled" type="bool" />
<description>
- Sets whether the item at index [code]idx[/code] is disabled.
+ Sets whether the item at index [param idx] is disabled.
Disabled items are drawn differently in the dropdown and are not selectable by the user. If the current selected item is set as disabled, it will remain selected.
</description>
</method>
<method name="set_item_icon">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="texture" type="Texture2D" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="texture" type="Texture2D" />
<description>
- Sets the icon of the item at index [code]idx[/code].
+ Sets the icon of the item at index [param idx].
</description>
</method>
<method name="set_item_id">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="id" type="int" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="id" type="int" />
<description>
- Sets the ID of the item at index [code]idx[/code].
+ Sets the ID of the item at index [param idx].
</description>
</method>
<method name="set_item_metadata">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="metadata" type="Variant" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="metadata" type="Variant" />
<description>
Sets the metadata of an item. Metadata may be of any type and can be used to store extra information about an item, such as an external string ID.
</description>
</method>
<method name="set_item_text">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="text" type="String" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="text" type="String" />
<description>
- Sets the text of the item at index [code]idx[/code].
+ Sets the text of the item at index [param idx].
</description>
</method>
<method name="set_item_tooltip">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="tooltip" type="String" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="tooltip" type="String" />
<description>
- Sets the tooltip of the item at index [code]idx[/code].
+ Sets the tooltip of the item at index [param idx].
</description>
</method>
</methods>
<members>
<member name="action_mode" type="int" setter="set_action_mode" getter="get_action_mode" overrides="BaseButton" enum="BaseButton.ActionMode" default="0" />
<member name="alignment" type="int" setter="set_text_alignment" getter="get_text_alignment" overrides="Button" enum="HorizontalAlignment" default="0" />
+ <member name="fit_to_longest_item" type="bool" setter="set_fit_to_longest_item" getter="is_fit_to_longest_item" default="true">
+ If [code]true[/code], minimum size will be determined by the longest item's text, instead of the currently selected one's.
+ [b]Note:[/b] For performance reasons, the minimum size doesn't update immediately when adding, removing or modifying items.
+ </member>
<member name="item_count" type="int" setter="set_item_count" getter="get_item_count" default="0">
The number of items to select from.
</member>
@@ -204,13 +208,13 @@
</members>
<signals>
<signal name="item_focused">
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
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">
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Emitted when the current item has been changed by the user. The index of the item selected is passed as argument.
</description>
@@ -229,6 +233,9 @@
<theme_item name="font_hover_color" data_type="color" type="Color" default="Color(0.95, 0.95, 0.95, 1)">
Text [Color] used when the [OptionButton] is being hovered.
</theme_item>
+ <theme_item name="font_hover_pressed_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
+ Text [Color] used when the [OptionButton] is being hovered and pressed.
+ </theme_item>
<theme_item name="font_outline_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
The tint of text outline of the [OptionButton].
</theme_item>
@@ -239,7 +246,10 @@
The horizontal space between the arrow icon and the right edge of the button.
</theme_item>
<theme_item name="h_separation" data_type="constant" type="int" default="2">
- The horizontal space between [OptionButton]'s icon and text.
+ The horizontal space between [OptionButton]'s icon and text. Negative values will be treated as [code]0[/code] when used.
+ </theme_item>
+ <theme_item name="modulate_arrow" data_type="constant" type="int" default="0">
+ If different than [code]0[/code], the arrow icon will be modulated to the font color.
</theme_item>
<theme_item name="outline_size" data_type="constant" type="int" default="0">
The size of the text outline.
diff --git a/doc/classes/PCKPacker.xml b/doc/classes/PCKPacker.xml
index 3b84128123..cb00b45fed 100644
--- a/doc/classes/PCKPacker.xml
+++ b/doc/classes/PCKPacker.xml
@@ -26,28 +26,28 @@
<methods>
<method name="add_file">
<return type="int" enum="Error" />
- <argument index="0" name="pck_path" type="String" />
- <argument index="1" name="source_path" type="String" />
- <argument index="2" name="encrypt" type="bool" default="false" />
+ <param index="0" name="pck_path" type="String" />
+ <param index="1" name="source_path" type="String" />
+ <param index="2" name="encrypt" type="bool" default="false" />
<description>
- Adds the [code]source_path[/code] file to the current PCK package at the [code]pck_path[/code] internal path (should start with [code]res://[/code]).
+ Adds the [param source_path] file to the current PCK package at the [param pck_path] internal path (should start with [code]res://[/code]).
</description>
</method>
<method name="flush">
<return type="int" enum="Error" />
- <argument index="0" name="verbose" type="bool" default="false" />
+ <param index="0" name="verbose" type="bool" default="false" />
<description>
- Writes the files specified using all [method add_file] calls since the last flush. If [code]verbose[/code] is [code]true[/code], a list of files added will be printed to the console for easier debugging.
+ Writes the files specified using all [method add_file] calls since the last flush. If [param verbose] is [code]true[/code], a list of files added will be printed to the console for easier debugging.
</description>
</method>
<method name="pck_start">
<return type="int" enum="Error" />
- <argument index="0" name="pck_name" type="String" />
- <argument index="1" name="alignment" type="int" default="32" />
- <argument index="2" name="key" type="String" default="&quot;0000000000000000000000000000000000000000000000000000000000000000&quot;" />
- <argument index="3" name="encrypt_directory" type="bool" default="false" />
+ <param index="0" name="pck_name" type="String" />
+ <param index="1" name="alignment" type="int" default="32" />
+ <param index="2" name="key" type="String" default="&quot;0000000000000000000000000000000000000000000000000000000000000000&quot;" />
+ <param index="3" name="encrypt_directory" type="bool" default="false" />
<description>
- Creates a new PCK file with the name [code]pck_name[/code]. The [code].pck[/code] file extension isn't added automatically, so it should be part of [code]pck_name[/code] (even though it's not required).
+ Creates a new PCK file with the name [param pck_name]. The [code].pck[/code] file extension isn't added automatically, so it should be part of [param pck_name] (even though it's not required).
</description>
</method>
</methods>
diff --git a/doc/classes/PackedByteArray.xml b/doc/classes/PackedByteArray.xml
index 3af3bb8697..efb559522a 100644
--- a/doc/classes/PackedByteArray.xml
+++ b/doc/classes/PackedByteArray.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
An array specifically designed to hold bytes. Packs data tightly, so it saves memory for large array sizes.
+ [PackedByteArray] also provides methods to encode/decode various types to/from bytes. The way values are encoded is an implementation detail and shouldn't be relied upon when interacting with external apps.
</description>
<tutorials>
</tutorials>
@@ -17,14 +18,14 @@
</constructor>
<constructor name="PackedByteArray">
<return type="PackedByteArray" />
- <argument index="0" name="from" type="PackedByteArray" />
+ <param index="0" name="from" type="PackedByteArray" />
<description>
Constructs a [PackedByteArray] as a copy of the given [PackedByteArray].
</description>
</constructor>
<constructor name="PackedByteArray">
<return type="PackedByteArray" />
- <argument index="0" name="from" type="Array" />
+ <param index="0" name="from" type="Array" />
<description>
Constructs a new [PackedByteArray]. Optionally, you can pass in a generic [Array] that will be converted.
</description>
@@ -33,137 +34,156 @@
<methods>
<method name="append">
<return type="bool" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Appends an element at the end of the array (alias of [method push_back]).
</description>
</method>
<method name="append_array">
<return type="void" />
- <argument index="0" name="array" type="PackedByteArray" />
+ <param index="0" name="array" type="PackedByteArray" />
<description>
Appends a [PackedByteArray] at the end of this array.
</description>
</method>
<method name="bsearch">
<return type="int" />
- <argument index="0" name="value" type="int" />
- <argument index="1" name="before" type="bool" default="true" />
+ <param index="0" name="value" type="int" />
+ <param index="1" name="before" type="bool" default="true" />
<description>
- Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search. Optionally, a [code]before[/code] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array.
+ Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search. Optionally, a [param before] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array.
[b]Note:[/b] Calling [method bsearch] on an unsorted array results in unexpected behavior.
</description>
</method>
+ <method name="clear">
+ <return type="void" />
+ <description>
+ Clears the array. This is equivalent to using [method resize] with a size of [code]0[/code].
+ </description>
+ </method>
<method name="compress" qualifiers="const">
<return type="PackedByteArray" />
- <argument index="0" name="compression_mode" type="int" default="0" />
+ <param index="0" name="compression_mode" type="int" default="0" />
<description>
Returns a new [PackedByteArray] with the data compressed. Set the compression mode using one of [enum File.CompressionMode]'s constants.
</description>
</method>
<method name="count" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Returns the number of times an element is in the array.
</description>
</method>
<method name="decode_double" qualifiers="const">
<return type="float" />
- <argument index="0" name="byte_offset" type="int" />
+ <param index="0" name="byte_offset" type="int" />
<description>
+ Decodes a 64-bit floating point number from the bytes starting at [param byte_offset]. Fails if the byte count is insufficient. Returns [code]0.0[/code] if a valid number can't be decoded.
</description>
</method>
<method name="decode_float" qualifiers="const">
<return type="float" />
- <argument index="0" name="byte_offset" type="int" />
+ <param index="0" name="byte_offset" type="int" />
<description>
+ Decodes a 32-bit floating point number from the bytes starting at [param byte_offset]. Fails if the byte count is insufficient. Returns [code]0.0[/code] if a valid number can't be decoded.
</description>
</method>
<method name="decode_half" qualifiers="const">
<return type="float" />
- <argument index="0" name="byte_offset" type="int" />
+ <param index="0" name="byte_offset" type="int" />
<description>
+ Decodes a 16-bit floating point number from the bytes starting at [param byte_offset]. Fails if the byte count is insufficient. Returns [code]0.0[/code] if a valid number can't be decoded.
</description>
</method>
<method name="decode_s16" qualifiers="const">
<return type="int" />
- <argument index="0" name="byte_offset" type="int" />
+ <param index="0" name="byte_offset" type="int" />
<description>
+ Decodes a 16-bit signed integer number from the bytes starting at [param byte_offset]. Fails if the byte count is insufficient. Returns [code]0[/code] if a valid number can't be decoded.
</description>
</method>
<method name="decode_s32" qualifiers="const">
<return type="int" />
- <argument index="0" name="byte_offset" type="int" />
+ <param index="0" name="byte_offset" type="int" />
<description>
+ Decodes a 32-bit signed integer number from the bytes starting at [param byte_offset]. Fails if the byte count is insufficient. Returns [code]0[/code] if a valid number can't be decoded.
</description>
</method>
<method name="decode_s64" qualifiers="const">
<return type="int" />
- <argument index="0" name="byte_offset" type="int" />
+ <param index="0" name="byte_offset" type="int" />
<description>
+ Decodes a 64-bit signed integer number from the bytes starting at [param byte_offset]. Fails if the byte count is insufficient. Returns [code]0[/code] if a valid number can't be decoded.
</description>
</method>
<method name="decode_s8" qualifiers="const">
<return type="int" />
- <argument index="0" name="byte_offset" type="int" />
+ <param index="0" name="byte_offset" type="int" />
<description>
+ Decodes a 8-bit signed integer number from the bytes starting at [param byte_offset]. Fails if the byte count is insufficient. Returns [code]0[/code] if a valid number can't be decoded.
</description>
</method>
<method name="decode_u16" qualifiers="const">
<return type="int" />
- <argument index="0" name="byte_offset" type="int" />
+ <param index="0" name="byte_offset" type="int" />
<description>
+ Decodes a 16-bit unsigned integer number from the bytes starting at [param byte_offset]. Fails if the byte count is insufficient. Returns [code]0[/code] if a valid number can't be decoded.
</description>
</method>
<method name="decode_u32" qualifiers="const">
<return type="int" />
- <argument index="0" name="byte_offset" type="int" />
+ <param index="0" name="byte_offset" type="int" />
<description>
+ Decodes a 32-bit unsigned integer number from the bytes starting at [param byte_offset]. Fails if the byte count is insufficient. Returns [code]0[/code] if a valid number can't be decoded.
</description>
</method>
<method name="decode_u64" qualifiers="const">
<return type="int" />
- <argument index="0" name="byte_offset" type="int" />
+ <param index="0" name="byte_offset" type="int" />
<description>
+ Decodes a 64-bit unsigned integer number from the bytes starting at [param byte_offset]. Fails if the byte count is insufficient. Returns [code]0[/code] if a valid number can't be decoded.
</description>
</method>
<method name="decode_u8" qualifiers="const">
<return type="int" />
- <argument index="0" name="byte_offset" type="int" />
+ <param index="0" name="byte_offset" type="int" />
<description>
+ Decodes a 8-bit unsigned integer number from the bytes starting at [param byte_offset]. Fails if the byte count is insufficient. Returns [code]0[/code] if a valid number can't be decoded.
</description>
</method>
<method name="decode_var" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="byte_offset" type="int" />
- <argument index="1" name="allow_objects" type="bool" default="false" />
+ <param index="0" name="byte_offset" type="int" />
+ <param index="1" name="allow_objects" type="bool" default="false" />
<description>
+ Decodes a [Variant] from the bytes starting at [param byte_offset]. Returns [code]null[/code] if a valid variant can't be decoded or the value is [Object]-derived and [param allow_objects] is [code]false[/code].
</description>
</method>
<method name="decode_var_size" qualifiers="const">
<return type="int" />
- <argument index="0" name="byte_offset" type="int" />
- <argument index="1" name="allow_objects" type="bool" default="false" />
+ <param index="0" name="byte_offset" type="int" />
+ <param index="1" name="allow_objects" type="bool" default="false" />
<description>
+ Decodes a size of a [Variant] from the bytes starting at [param byte_offset]. Requires at least 4 bytes of data starting at the offset, otherwise fails.
</description>
</method>
<method name="decompress" qualifiers="const">
<return type="PackedByteArray" />
- <argument index="0" name="buffer_size" type="int" />
- <argument index="1" name="compression_mode" type="int" default="0" />
+ <param index="0" name="buffer_size" type="int" />
+ <param index="1" name="compression_mode" type="int" default="0" />
<description>
- Returns a new [PackedByteArray] with the data decompressed. Set [code]buffer_size[/code] to the size of the uncompressed data. Set the compression mode using one of [enum File.CompressionMode]'s constants.
+ Returns a new [PackedByteArray] with the data decompressed. Set [param buffer_size] to the size of the uncompressed data. Set the compression mode using one of [enum File.CompressionMode]'s constants.
</description>
</method>
<method name="decompress_dynamic" qualifiers="const">
<return type="PackedByteArray" />
- <argument index="0" name="max_output_size" type="int" />
- <argument index="1" name="compression_mode" type="int" default="0" />
+ <param index="0" name="max_output_size" type="int" />
+ <param index="1" name="compression_mode" type="int" default="0" />
<description>
Returns a new [PackedByteArray] with the data decompressed. Set the compression mode using one of [enum File.CompressionMode]'s constants. [b]This method only accepts gzip and deflate compression modes.[/b]
This method is potentially slower than [code]decompress[/code], as it may have to re-allocate its output buffer multiple times while decompressing, whereas [code]decompress[/code] knows it's output buffer size from the beginning.
- GZIP has a maximal compression ratio of 1032:1, meaning it's very possible for a small compressed payload to decompress to a potentially very large output. To guard against this, you may provide a maximum size this function is allowed to allocate in bytes via [code]max_output_size[/code]. Passing -1 will allow for unbounded output. If any positive value is passed, and the decompression exceeds that amount in bytes, then an error will be returned.
+ GZIP has a maximal compression ratio of 1032:1, meaning it's very possible for a small compressed payload to decompress to a potentially very large output. To guard against this, you may provide a maximum size this function is allowed to allocate in bytes via [param max_output_size]. Passing -1 will allow for unbounded output. If any positive value is passed, and the decompression exceeds that amount in bytes, then an error will be returned.
</description>
</method>
<method name="duplicate">
@@ -174,100 +194,112 @@
</method>
<method name="encode_double">
<return type="void" />
- <argument index="0" name="byte_offset" type="int" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="byte_offset" type="int" />
+ <param index="1" name="value" type="float" />
<description>
+ Encodes a 64-bit floating point number as bytes at the index of [param byte_offset] bytes. The array must have at least 8 bytes of allocated space, starting at the offset.
</description>
</method>
<method name="encode_float">
<return type="void" />
- <argument index="0" name="byte_offset" type="int" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="byte_offset" type="int" />
+ <param index="1" name="value" type="float" />
<description>
+ Encodes a 32-bit floating point number as bytes at the index of [param byte_offset] bytes. The array must have at least 4 bytes of space, starting at the offset.
</description>
</method>
<method name="encode_half">
<return type="void" />
- <argument index="0" name="byte_offset" type="int" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="byte_offset" type="int" />
+ <param index="1" name="value" type="float" />
<description>
+ Encodes a 16-bit floating point number as bytes at the index of [param byte_offset] bytes. The array must have at least 2 bytes of space, starting at the offset.
</description>
</method>
<method name="encode_s16">
<return type="void" />
- <argument index="0" name="byte_offset" type="int" />
- <argument index="1" name="value" type="int" />
+ <param index="0" name="byte_offset" type="int" />
+ <param index="1" name="value" type="int" />
<description>
+ Encodes a 16-bit signed integer number as bytes at the index of [param byte_offset] bytes. The array must have at least 2 bytes of space, starting at the offset.
</description>
</method>
<method name="encode_s32">
<return type="void" />
- <argument index="0" name="byte_offset" type="int" />
- <argument index="1" name="value" type="int" />
+ <param index="0" name="byte_offset" type="int" />
+ <param index="1" name="value" type="int" />
<description>
+ Encodes a 32-bit signed integer number as bytes at the index of [param byte_offset] bytes. The array must have at least 2 bytes of space, starting at the offset.
</description>
</method>
<method name="encode_s64">
<return type="void" />
- <argument index="0" name="byte_offset" type="int" />
- <argument index="1" name="value" type="int" />
+ <param index="0" name="byte_offset" type="int" />
+ <param index="1" name="value" type="int" />
<description>
+ Encodes a 64-bit signed integer number as bytes at the index of [param byte_offset] bytes. The array must have at least 2 bytes of space, starting at the offset.
</description>
</method>
<method name="encode_s8">
<return type="void" />
- <argument index="0" name="byte_offset" type="int" />
- <argument index="1" name="value" type="int" />
+ <param index="0" name="byte_offset" type="int" />
+ <param index="1" name="value" type="int" />
<description>
+ Encodes a 8-bit signed integer number (signed byte) at the index of [param byte_offset] bytes. The array must have at least 1 byte of space, starting at the offset.
</description>
</method>
<method name="encode_u16">
<return type="void" />
- <argument index="0" name="byte_offset" type="int" />
- <argument index="1" name="value" type="int" />
+ <param index="0" name="byte_offset" type="int" />
+ <param index="1" name="value" type="int" />
<description>
+ Encodes a 16-bit unsigned integer number as bytes at the index of [param byte_offset] bytes. The array must have at least 2 bytes of space, starting at the offset.
</description>
</method>
<method name="encode_u32">
<return type="void" />
- <argument index="0" name="byte_offset" type="int" />
- <argument index="1" name="value" type="int" />
+ <param index="0" name="byte_offset" type="int" />
+ <param index="1" name="value" type="int" />
<description>
+ Encodes a 32-bit unsigned integer number as bytes at the index of [param byte_offset] bytes. The array must have at least 4 bytes of space, starting at the offset.
</description>
</method>
<method name="encode_u64">
<return type="void" />
- <argument index="0" name="byte_offset" type="int" />
- <argument index="1" name="value" type="int" />
+ <param index="0" name="byte_offset" type="int" />
+ <param index="1" name="value" type="int" />
<description>
+ Encodes a 64-bit unsigned integer number as bytes at the index of [param byte_offset] bytes. The array must have at least 8 bytes of space, starting at the offset.
</description>
</method>
<method name="encode_u8">
<return type="void" />
- <argument index="0" name="byte_offset" type="int" />
- <argument index="1" name="value" type="int" />
+ <param index="0" name="byte_offset" type="int" />
+ <param index="1" name="value" type="int" />
<description>
+ Encodes a 8-bit unsigned integer number (byte) at the index of [param byte_offset] bytes. The array must have at least 1 byte of space, starting at the offset.
</description>
</method>
<method name="encode_var">
<return type="int" />
- <argument index="0" name="byte_offset" type="int" />
- <argument index="1" name="value" type="Variant" />
- <argument index="2" name="allow_objects" type="bool" default="false" />
+ <param index="0" name="byte_offset" type="int" />
+ <param index="1" name="value" type="Variant" />
+ <param index="2" name="allow_objects" type="bool" default="false" />
<description>
+ Encodes a [Variant] at the index of [param byte_offset] bytes. A sufficient space must be allocated, depending on the encoded variant's size. If [param allow_objects] is [code]false[/code], [Object]-derived values are not permitted and will instead be serialized as ID-only.
</description>
</method>
<method name="fill">
<return type="void" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
</description>
</method>
<method name="find" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="int" />
- <argument index="1" name="from" type="int" default="0" />
+ <param index="0" name="value" type="int" />
+ <param index="1" name="from" type="int" default="0" />
<description>
Searches the array for a value and returns its index or [code]-1[/code] if not found. Optionally, the initial search index can be passed.
</description>
@@ -298,16 +330,17 @@
</method>
<method name="has" qualifiers="const">
<return type="bool" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
- Returns [code]true[/code] if the array contains [code]value[/code].
+ Returns [code]true[/code] if the array contains [param value].
</description>
</method>
<method name="has_encoded_var" qualifiers="const">
<return type="bool" />
- <argument index="0" name="byte_offset" type="int" />
- <argument index="1" name="allow_objects" type="bool" default="false" />
+ <param index="0" name="byte_offset" type="int" />
+ <param index="1" name="allow_objects" type="bool" default="false" />
<description>
+ Returns [code]true[/code] if a valid [Variant] value can be decoded at the [param byte_offset]. Returns [code]false[/code] othewrise or when the value is [Object]-derived and [param allow_objects] is [code]false[/code].
</description>
</method>
<method name="hex_encode" qualifiers="const">
@@ -328,8 +361,8 @@
</method>
<method name="insert">
<return type="int" />
- <argument index="0" name="at_index" type="int" />
- <argument index="1" name="value" type="int" />
+ <param index="0" name="at_index" type="int" />
+ <param index="1" name="value" type="int" />
<description>
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
@@ -342,21 +375,21 @@
</method>
<method name="push_back">
<return type="bool" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Appends an element at the end of the array.
</description>
</method>
<method name="remove_at">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Removes an element from the array by index.
</description>
</method>
<method name="resize">
<return type="int" />
- <argument index="0" name="new_size" type="int" />
+ <param index="0" name="new_size" type="int" />
<description>
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
@@ -369,16 +402,16 @@
</method>
<method name="rfind" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="int" />
- <argument index="1" name="from" type="int" default="-1" />
+ <param index="0" name="value" type="int" />
+ <param index="1" name="from" type="int" default="-1" />
<description>
Searches the array in reverse order. Optionally, a start search index can be passed. If negative, the start index is considered relative to the end of the array.
</description>
</method>
<method name="set">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="value" type="int" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="value" type="int" />
<description>
Changes the byte at the given index.
</description>
@@ -391,12 +424,12 @@
</method>
<method name="slice" qualifiers="const">
<return type="PackedByteArray" />
- <argument index="0" name="begin" type="int" />
- <argument index="1" name="end" type="int" default="2147483647" />
+ <param index="0" name="begin" type="int" />
+ <param index="1" name="end" type="int" default="2147483647" />
<description>
- Returns the slice of the [PackedByteArray], from [code]begin[/code] (inclusive) to [code]end[/code] (exclusive), as a new [PackedByteArray].
- The absolute value of [code]begin[/code] and [code]end[/code] will be clamped to the array size, so the default value for [code]end[/code] makes it slice to the size of the array by default (i.e. [code]arr.slice(1)[/code] is a shorthand for [code]arr.slice(1, arr.size())[/code]).
- If either [code]begin[/code] or [code]end[/code] are negative, they will be relative to the end of the array (i.e. [code]arr.slice(0, -2)[/code] is a shorthand for [code]arr.slice(0, arr.size() - 2)[/code]).
+ Returns the slice of the [PackedByteArray], from [param begin] (inclusive) to [param end] (exclusive), as a new [PackedByteArray].
+ The absolute value of [param begin] and [param end] will be clamped to the array size, so the default value for [param end] makes it slice to the size of the array by default (i.e. [code]arr.slice(1)[/code] is a shorthand for [code]arr.slice(1, arr.size())[/code]).
+ If either [param begin] or [param end] are negative, they will be relative to the end of the array (i.e. [code]arr.slice(0, -2)[/code] is a shorthand for [code]arr.slice(0, arr.size() - 2)[/code]).
</description>
</method>
<method name="sort">
@@ -441,26 +474,31 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="PackedByteArray" />
+ <param index="0" name="right" type="PackedByteArray" />
<description>
+ Returns [code]true[/code] if contents of the arrays differ.
</description>
</operator>
<operator name="operator +">
<return type="PackedByteArray" />
- <argument index="0" name="right" type="PackedByteArray" />
+ <param index="0" name="right" type="PackedByteArray" />
<description>
+ Returns a new [PackedByteArray] with contents of [param right] added at the end of this array. For better performance, consider using [method append_array] instead.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="PackedByteArray" />
+ <param index="0" name="right" type="PackedByteArray" />
<description>
+ Returns [code]true[/code] if contents of both arrays are the same, i.e. they have all equal bytes at the corresponding indices.
</description>
</operator>
<operator name="operator []">
<return type="int" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
+ Returns the byte at index [param index]. Negative indices can be used to access the elements starting from the end. Using index out of array's bounds will result in an error.
+ Note that the byte is returned as a 64-bit [int].
</description>
</operator>
</operators>
diff --git a/doc/classes/PackedColorArray.xml b/doc/classes/PackedColorArray.xml
index 12a553af49..a2dc8e8f1d 100644
--- a/doc/classes/PackedColorArray.xml
+++ b/doc/classes/PackedColorArray.xml
@@ -17,14 +17,14 @@
</constructor>
<constructor name="PackedColorArray">
<return type="PackedColorArray" />
- <argument index="0" name="from" type="PackedColorArray" />
+ <param index="0" name="from" type="PackedColorArray" />
<description>
Constructs a [PackedColorArray] as a copy of the given [PackedColorArray].
</description>
</constructor>
<constructor name="PackedColorArray">
<return type="PackedColorArray" />
- <argument index="0" name="from" type="Array" />
+ <param index="0" name="from" type="Array" />
<description>
Constructs a new [PackedColorArray]. Optionally, you can pass in a generic [Array] that will be converted.
</description>
@@ -33,30 +33,36 @@
<methods>
<method name="append">
<return type="bool" />
- <argument index="0" name="value" type="Color" />
+ <param index="0" name="value" type="Color" />
<description>
Appends an element at the end of the array (alias of [method push_back]).
</description>
</method>
<method name="append_array">
<return type="void" />
- <argument index="0" name="array" type="PackedColorArray" />
+ <param index="0" name="array" type="PackedColorArray" />
<description>
Appends a [PackedColorArray] at the end of this array.
</description>
</method>
<method name="bsearch">
<return type="int" />
- <argument index="0" name="value" type="Color" />
- <argument index="1" name="before" type="bool" default="true" />
+ <param index="0" name="value" type="Color" />
+ <param index="1" name="before" type="bool" default="true" />
<description>
- Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search. Optionally, a [code]before[/code] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array.
+ Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search. Optionally, a [param before] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array.
[b]Note:[/b] Calling [method bsearch] on an unsorted array results in unexpected behavior.
</description>
</method>
+ <method name="clear">
+ <return type="void" />
+ <description>
+ Clears the array. This is equivalent to using [method resize] with a size of [code]0[/code].
+ </description>
+ </method>
<method name="count" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="Color" />
+ <param index="0" name="value" type="Color" />
<description>
Returns the number of times an element is in the array.
</description>
@@ -69,30 +75,30 @@
</method>
<method name="fill">
<return type="void" />
- <argument index="0" name="value" type="Color" />
+ <param index="0" name="value" type="Color" />
<description>
Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
</description>
</method>
<method name="find" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="Color" />
- <argument index="1" name="from" type="int" default="0" />
+ <param index="0" name="value" type="Color" />
+ <param index="1" name="from" type="int" default="0" />
<description>
Searches the array for a value and returns its index or [code]-1[/code] if not found. Optionally, the initial search index can be passed.
</description>
</method>
<method name="has" qualifiers="const">
<return type="bool" />
- <argument index="0" name="value" type="Color" />
+ <param index="0" name="value" type="Color" />
<description>
- Returns [code]true[/code] if the array contains [code]value[/code].
+ Returns [code]true[/code] if the array contains [param value].
</description>
</method>
<method name="insert">
<return type="int" />
- <argument index="0" name="at_index" type="int" />
- <argument index="1" name="value" type="Color" />
+ <param index="0" name="at_index" type="int" />
+ <param index="1" name="value" type="Color" />
<description>
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
@@ -105,21 +111,21 @@
</method>
<method name="push_back">
<return type="bool" />
- <argument index="0" name="value" type="Color" />
+ <param index="0" name="value" type="Color" />
<description>
Appends a value to the array.
</description>
</method>
<method name="remove_at">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Removes an element from the array by index.
</description>
</method>
<method name="resize">
<return type="int" />
- <argument index="0" name="new_size" type="int" />
+ <param index="0" name="new_size" type="int" />
<description>
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
@@ -132,16 +138,16 @@
</method>
<method name="rfind" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="Color" />
- <argument index="1" name="from" type="int" default="-1" />
+ <param index="0" name="value" type="Color" />
+ <param index="1" name="from" type="int" default="-1" />
<description>
Searches the array in reverse order. Optionally, a start search index can be passed. If negative, the start index is considered relative to the end of the array.
</description>
</method>
<method name="set">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="value" type="Color" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="value" type="Color" />
<description>
Changes the [Color] at the given index.
</description>
@@ -154,12 +160,12 @@
</method>
<method name="slice" qualifiers="const">
<return type="PackedColorArray" />
- <argument index="0" name="begin" type="int" />
- <argument index="1" name="end" type="int" default="2147483647" />
+ <param index="0" name="begin" type="int" />
+ <param index="1" name="end" type="int" default="2147483647" />
<description>
- Returns the slice of the [PackedColorArray], from [code]begin[/code] (inclusive) to [code]end[/code] (exclusive), as a new [PackedColorArray].
- The absolute value of [code]begin[/code] and [code]end[/code] will be clamped to the array size, so the default value for [code]end[/code] makes it slice to the size of the array by default (i.e. [code]arr.slice(1)[/code] is a shorthand for [code]arr.slice(1, arr.size())[/code]).
- If either [code]begin[/code] or [code]end[/code] are negative, they will be relative to the end of the array (i.e. [code]arr.slice(0, -2)[/code] is a shorthand for [code]arr.slice(0, arr.size() - 2)[/code]).
+ Returns the slice of the [PackedColorArray], from [param begin] (inclusive) to [param end] (exclusive), as a new [PackedColorArray].
+ The absolute value of [param begin] and [param end] will be clamped to the array size, so the default value for [param end] makes it slice to the size of the array by default (i.e. [code]arr.slice(1)[/code] is a shorthand for [code]arr.slice(1, arr.size())[/code]).
+ If either [param begin] or [param end] are negative, they will be relative to the end of the array (i.e. [code]arr.slice(0, -2)[/code] is a shorthand for [code]arr.slice(0, arr.size() - 2)[/code]).
</description>
</method>
<method name="sort">
@@ -171,32 +177,37 @@
<method name="to_byte_array" qualifiers="const">
<return type="PackedByteArray" />
<description>
+ Returns a [PackedByteArray] with each color encoded as bytes.
</description>
</method>
</methods>
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="PackedColorArray" />
+ <param index="0" name="right" type="PackedColorArray" />
<description>
+ Returns [code]true[/code] if contents of the arrays differ.
</description>
</operator>
<operator name="operator +">
<return type="PackedColorArray" />
- <argument index="0" name="right" type="PackedColorArray" />
+ <param index="0" name="right" type="PackedColorArray" />
<description>
+ Returns a new [PackedColorArray] with contents of [param right] added at the end of this array. For better performance, consider using [method append_array] instead.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="PackedColorArray" />
+ <param index="0" name="right" type="PackedColorArray" />
<description>
+ Returns [code]true[/code] if contents of both arrays are the same, i.e. they have all equal [Color]s at the corresponding indices.
</description>
</operator>
<operator name="operator []">
<return type="Color" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
+ Returns the [Color] at index [param index]. Negative indices can be used to access the elements starting from the end. Using index out of array's bounds will result in an error.
</description>
</operator>
</operators>
diff --git a/doc/classes/PackedDataContainer.xml b/doc/classes/PackedDataContainer.xml
index cba7269ccf..5035c8dee4 100644
--- a/doc/classes/PackedDataContainer.xml
+++ b/doc/classes/PackedDataContainer.xml
@@ -9,7 +9,7 @@
<methods>
<method name="pack">
<return type="int" enum="Error" />
- <argument index="0" name="value" type="Variant" />
+ <param index="0" name="value" type="Variant" />
<description>
</description>
</method>
diff --git a/doc/classes/PackedFloat32Array.xml b/doc/classes/PackedFloat32Array.xml
index 0a114e6c06..d350d64f38 100644
--- a/doc/classes/PackedFloat32Array.xml
+++ b/doc/classes/PackedFloat32Array.xml
@@ -4,7 +4,7 @@
A packed array of 32-bit floating-point values.
</brief_description>
<description>
- An array specifically designed to hold 32-bit floating-point values. Packs data tightly, so it saves memory for large array sizes.
+ An array specifically designed to hold 32-bit floating-point values (float). Packs data tightly, so it saves memory for large array sizes.
If you need to pack 64-bit floats tightly, see [PackedFloat64Array].
</description>
<tutorials>
@@ -18,14 +18,14 @@
</constructor>
<constructor name="PackedFloat32Array">
<return type="PackedFloat32Array" />
- <argument index="0" name="from" type="PackedFloat32Array" />
+ <param index="0" name="from" type="PackedFloat32Array" />
<description>
Constructs a [PackedFloat32Array] as a copy of the given [PackedFloat32Array].
</description>
</constructor>
<constructor name="PackedFloat32Array">
<return type="PackedFloat32Array" />
- <argument index="0" name="from" type="Array" />
+ <param index="0" name="from" type="Array" />
<description>
Constructs a new [PackedFloat32Array]. Optionally, you can pass in a generic [Array] that will be converted.
</description>
@@ -34,30 +34,36 @@
<methods>
<method name="append">
<return type="bool" />
- <argument index="0" name="value" type="float" />
+ <param index="0" name="value" type="float" />
<description>
Appends an element at the end of the array (alias of [method push_back]).
</description>
</method>
<method name="append_array">
<return type="void" />
- <argument index="0" name="array" type="PackedFloat32Array" />
+ <param index="0" name="array" type="PackedFloat32Array" />
<description>
Appends a [PackedFloat32Array] at the end of this array.
</description>
</method>
<method name="bsearch">
<return type="int" />
- <argument index="0" name="value" type="float" />
- <argument index="1" name="before" type="bool" default="true" />
+ <param index="0" name="value" type="float" />
+ <param index="1" name="before" type="bool" default="true" />
<description>
- Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search. Optionally, a [code]before[/code] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array.
+ Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search. Optionally, a [param before] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array.
[b]Note:[/b] Calling [method bsearch] on an unsorted array results in unexpected behavior.
</description>
</method>
+ <method name="clear">
+ <return type="void" />
+ <description>
+ Clears the array. This is equivalent to using [method resize] with a size of [code]0[/code].
+ </description>
+ </method>
<method name="count" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="float" />
+ <param index="0" name="value" type="float" />
<description>
Returns the number of times an element is in the array.
</description>
@@ -70,30 +76,30 @@
</method>
<method name="fill">
<return type="void" />
- <argument index="0" name="value" type="float" />
+ <param index="0" name="value" type="float" />
<description>
Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
</description>
</method>
<method name="find" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="float" />
- <argument index="1" name="from" type="int" default="0" />
+ <param index="0" name="value" type="float" />
+ <param index="1" name="from" type="int" default="0" />
<description>
Searches the array for a value and returns its index or [code]-1[/code] if not found. Optionally, the initial search index can be passed.
</description>
</method>
<method name="has" qualifiers="const">
<return type="bool" />
- <argument index="0" name="value" type="float" />
+ <param index="0" name="value" type="float" />
<description>
- Returns [code]true[/code] if the array contains [code]value[/code].
+ Returns [code]true[/code] if the array contains [param value].
</description>
</method>
<method name="insert">
<return type="int" />
- <argument index="0" name="at_index" type="int" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="at_index" type="int" />
+ <param index="1" name="value" type="float" />
<description>
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
@@ -106,21 +112,21 @@
</method>
<method name="push_back">
<return type="bool" />
- <argument index="0" name="value" type="float" />
+ <param index="0" name="value" type="float" />
<description>
Appends an element at the end of the array.
</description>
</method>
<method name="remove_at">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Removes an element from the array by index.
</description>
</method>
<method name="resize">
<return type="int" />
- <argument index="0" name="new_size" type="int" />
+ <param index="0" name="new_size" type="int" />
<description>
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
@@ -133,16 +139,16 @@
</method>
<method name="rfind" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="float" />
- <argument index="1" name="from" type="int" default="-1" />
+ <param index="0" name="value" type="float" />
+ <param index="1" name="from" type="int" default="-1" />
<description>
Searches the array in reverse order. Optionally, a start search index can be passed. If negative, the start index is considered relative to the end of the array.
</description>
</method>
<method name="set">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="value" type="float" />
<description>
Changes the float at the given index.
</description>
@@ -155,12 +161,12 @@
</method>
<method name="slice" qualifiers="const">
<return type="PackedFloat32Array" />
- <argument index="0" name="begin" type="int" />
- <argument index="1" name="end" type="int" default="2147483647" />
+ <param index="0" name="begin" type="int" />
+ <param index="1" name="end" type="int" default="2147483647" />
<description>
- Returns the slice of the [PackedFloat32Array], from [code]begin[/code] (inclusive) to [code]end[/code] (exclusive), as a new [PackedFloat32Array].
- The absolute value of [code]begin[/code] and [code]end[/code] will be clamped to the array size, so the default value for [code]end[/code] makes it slice to the size of the array by default (i.e. [code]arr.slice(1)[/code] is a shorthand for [code]arr.slice(1, arr.size())[/code]).
- If either [code]begin[/code] or [code]end[/code] are negative, they will be relative to the end of the array (i.e. [code]arr.slice(0, -2)[/code] is a shorthand for [code]arr.slice(0, arr.size() - 2)[/code]).
+ Returns the slice of the [PackedFloat32Array], from [param begin] (inclusive) to [param end] (exclusive), as a new [PackedFloat32Array].
+ The absolute value of [param begin] and [param end] will be clamped to the array size, so the default value for [param end] makes it slice to the size of the array by default (i.e. [code]arr.slice(1)[/code] is a shorthand for [code]arr.slice(1, arr.size())[/code]).
+ If either [param begin] or [param end] are negative, they will be relative to the end of the array (i.e. [code]arr.slice(0, -2)[/code] is a shorthand for [code]arr.slice(0, arr.size() - 2)[/code]).
</description>
</method>
<method name="sort">
@@ -180,26 +186,31 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="PackedFloat32Array" />
+ <param index="0" name="right" type="PackedFloat32Array" />
<description>
+ Returns [code]true[/code] if contents of the arrays differ.
</description>
</operator>
<operator name="operator +">
<return type="PackedFloat32Array" />
- <argument index="0" name="right" type="PackedFloat32Array" />
+ <param index="0" name="right" type="PackedFloat32Array" />
<description>
+ Returns a new [PackedFloat32Array] with contents of [param right] added at the end of this array. For better performance, consider using [method append_array] instead.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="PackedFloat32Array" />
+ <param index="0" name="right" type="PackedFloat32Array" />
<description>
+ Returns [code]true[/code] if contents of both arrays are the same, i.e. they have all equal floats at the corresponding indices.
</description>
</operator>
<operator name="operator []">
<return type="float" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
+ Returns the [float] at index [param index]. Negative indices can be used to access the elements starting from the end. Using index out of array's bounds will result in an error.
+ Note that [float] type is 64-bit, unlike the values stored in the array.
</description>
</operator>
</operators>
diff --git a/doc/classes/PackedFloat64Array.xml b/doc/classes/PackedFloat64Array.xml
index 0327559f5b..690cb15fa7 100644
--- a/doc/classes/PackedFloat64Array.xml
+++ b/doc/classes/PackedFloat64Array.xml
@@ -4,7 +4,7 @@
A packed array of 64-bit floating-point values.
</brief_description>
<description>
- An array specifically designed to hold 64-bit floating-point values. Packs data tightly, so it saves memory for large array sizes.
+ An array specifically designed to hold 64-bit floating-point values (double). Packs data tightly, so it saves memory for large array sizes.
If you only need to pack 32-bit floats tightly, see [PackedFloat32Array] for a more memory-friendly alternative.
</description>
<tutorials>
@@ -18,14 +18,14 @@
</constructor>
<constructor name="PackedFloat64Array">
<return type="PackedFloat64Array" />
- <argument index="0" name="from" type="PackedFloat64Array" />
+ <param index="0" name="from" type="PackedFloat64Array" />
<description>
Constructs a [PackedFloat64Array] as a copy of the given [PackedFloat64Array].
</description>
</constructor>
<constructor name="PackedFloat64Array">
<return type="PackedFloat64Array" />
- <argument index="0" name="from" type="Array" />
+ <param index="0" name="from" type="Array" />
<description>
Constructs a new [PackedFloat64Array]. Optionally, you can pass in a generic [Array] that will be converted.
</description>
@@ -34,30 +34,36 @@
<methods>
<method name="append">
<return type="bool" />
- <argument index="0" name="value" type="float" />
+ <param index="0" name="value" type="float" />
<description>
Appends an element at the end of the array (alias of [method push_back]).
</description>
</method>
<method name="append_array">
<return type="void" />
- <argument index="0" name="array" type="PackedFloat64Array" />
+ <param index="0" name="array" type="PackedFloat64Array" />
<description>
Appends a [PackedFloat64Array] at the end of this array.
</description>
</method>
<method name="bsearch">
<return type="int" />
- <argument index="0" name="value" type="float" />
- <argument index="1" name="before" type="bool" default="true" />
+ <param index="0" name="value" type="float" />
+ <param index="1" name="before" type="bool" default="true" />
<description>
- Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search. Optionally, a [code]before[/code] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array.
+ Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search. Optionally, a [param before] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array.
[b]Note:[/b] Calling [method bsearch] on an unsorted array results in unexpected behavior.
</description>
</method>
+ <method name="clear">
+ <return type="void" />
+ <description>
+ Clears the array. This is equivalent to using [method resize] with a size of [code]0[/code].
+ </description>
+ </method>
<method name="count" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="float" />
+ <param index="0" name="value" type="float" />
<description>
Returns the number of times an element is in the array.
</description>
@@ -70,30 +76,30 @@
</method>
<method name="fill">
<return type="void" />
- <argument index="0" name="value" type="float" />
+ <param index="0" name="value" type="float" />
<description>
Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
</description>
</method>
<method name="find" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="float" />
- <argument index="1" name="from" type="int" default="0" />
+ <param index="0" name="value" type="float" />
+ <param index="1" name="from" type="int" default="0" />
<description>
Searches the array for a value and returns its index or [code]-1[/code] if not found. Optionally, the initial search index can be passed.
</description>
</method>
<method name="has" qualifiers="const">
<return type="bool" />
- <argument index="0" name="value" type="float" />
+ <param index="0" name="value" type="float" />
<description>
- Returns [code]true[/code] if the array contains [code]value[/code].
+ Returns [code]true[/code] if the array contains [param value].
</description>
</method>
<method name="insert">
<return type="int" />
- <argument index="0" name="at_index" type="int" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="at_index" type="int" />
+ <param index="1" name="value" type="float" />
<description>
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
@@ -106,21 +112,21 @@
</method>
<method name="push_back">
<return type="bool" />
- <argument index="0" name="value" type="float" />
+ <param index="0" name="value" type="float" />
<description>
Appends an element at the end of the array.
</description>
</method>
<method name="remove_at">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Removes an element from the array by index.
</description>
</method>
<method name="resize">
<return type="int" />
- <argument index="0" name="new_size" type="int" />
+ <param index="0" name="new_size" type="int" />
<description>
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
@@ -133,16 +139,16 @@
</method>
<method name="rfind" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="float" />
- <argument index="1" name="from" type="int" default="-1" />
+ <param index="0" name="value" type="float" />
+ <param index="1" name="from" type="int" default="-1" />
<description>
Searches the array in reverse order. Optionally, a start search index can be passed. If negative, the start index is considered relative to the end of the array.
</description>
</method>
<method name="set">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="value" type="float" />
<description>
Changes the float at the given index.
</description>
@@ -155,12 +161,12 @@
</method>
<method name="slice" qualifiers="const">
<return type="PackedFloat64Array" />
- <argument index="0" name="begin" type="int" />
- <argument index="1" name="end" type="int" default="2147483647" />
+ <param index="0" name="begin" type="int" />
+ <param index="1" name="end" type="int" default="2147483647" />
<description>
- Returns the slice of the [PackedFloat64Array], from [code]begin[/code] (inclusive) to [code]end[/code] (exclusive), as a new [PackedFloat64Array].
- The absolute value of [code]begin[/code] and [code]end[/code] will be clamped to the array size, so the default value for [code]end[/code] makes it slice to the size of the array by default (i.e. [code]arr.slice(1)[/code] is a shorthand for [code]arr.slice(1, arr.size())[/code]).
- If either [code]begin[/code] or [code]end[/code] are negative, they will be relative to the end of the array (i.e. [code]arr.slice(0, -2)[/code] is a shorthand for [code]arr.slice(0, arr.size() - 2)[/code]).
+ Returns the slice of the [PackedFloat64Array], from [param begin] (inclusive) to [param end] (exclusive), as a new [PackedFloat64Array].
+ The absolute value of [param begin] and [param end] will be clamped to the array size, so the default value for [param end] makes it slice to the size of the array by default (i.e. [code]arr.slice(1)[/code] is a shorthand for [code]arr.slice(1, arr.size())[/code]).
+ If either [param begin] or [param end] are negative, they will be relative to the end of the array (i.e. [code]arr.slice(0, -2)[/code] is a shorthand for [code]arr.slice(0, arr.size() - 2)[/code]).
</description>
</method>
<method name="sort">
@@ -180,26 +186,30 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="PackedFloat64Array" />
+ <param index="0" name="right" type="PackedFloat64Array" />
<description>
+ Returns [code]true[/code] if contents of the arrays differ.
</description>
</operator>
<operator name="operator +">
<return type="PackedFloat64Array" />
- <argument index="0" name="right" type="PackedFloat64Array" />
+ <param index="0" name="right" type="PackedFloat64Array" />
<description>
+ Returns a new [PackedFloat64Array] with contents of [param right] added at the end of this array. For better performance, consider using [method append_array] instead.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="PackedFloat64Array" />
+ <param index="0" name="right" type="PackedFloat64Array" />
<description>
+ Returns [code]true[/code] if contents of both arrays are the same, i.e. they have all equal doubles at the corresponding indices.
</description>
</operator>
<operator name="operator []">
<return type="float" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
+ Returns the [float] at index [param index]. Negative indices can be used to access the elements starting from the end. Using index out of array's bounds will result in an error.
</description>
</operator>
</operators>
diff --git a/doc/classes/PackedInt32Array.xml b/doc/classes/PackedInt32Array.xml
index f8b606d266..2f9032e214 100644
--- a/doc/classes/PackedInt32Array.xml
+++ b/doc/classes/PackedInt32Array.xml
@@ -18,14 +18,14 @@
</constructor>
<constructor name="PackedInt32Array">
<return type="PackedInt32Array" />
- <argument index="0" name="from" type="PackedInt32Array" />
+ <param index="0" name="from" type="PackedInt32Array" />
<description>
Constructs a [PackedInt32Array] as a copy of the given [PackedInt32Array].
</description>
</constructor>
<constructor name="PackedInt32Array">
<return type="PackedInt32Array" />
- <argument index="0" name="from" type="Array" />
+ <param index="0" name="from" type="Array" />
<description>
Constructs a new [PackedInt32Array]. Optionally, you can pass in a generic [Array] that will be converted.
</description>
@@ -34,30 +34,36 @@
<methods>
<method name="append">
<return type="bool" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Appends an element at the end of the array (alias of [method push_back]).
</description>
</method>
<method name="append_array">
<return type="void" />
- <argument index="0" name="array" type="PackedInt32Array" />
+ <param index="0" name="array" type="PackedInt32Array" />
<description>
Appends a [PackedInt32Array] at the end of this array.
</description>
</method>
<method name="bsearch">
<return type="int" />
- <argument index="0" name="value" type="int" />
- <argument index="1" name="before" type="bool" default="true" />
+ <param index="0" name="value" type="int" />
+ <param index="1" name="before" type="bool" default="true" />
<description>
- Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search. Optionally, a [code]before[/code] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array.
+ Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search. Optionally, a [param before] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array.
[b]Note:[/b] Calling [method bsearch] on an unsorted array results in unexpected behavior.
</description>
</method>
+ <method name="clear">
+ <return type="void" />
+ <description>
+ Clears the array. This is equivalent to using [method resize] with a size of [code]0[/code].
+ </description>
+ </method>
<method name="count" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Returns the number of times an element is in the array.
</description>
@@ -70,30 +76,30 @@
</method>
<method name="fill">
<return type="void" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
</description>
</method>
<method name="find" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="int" />
- <argument index="1" name="from" type="int" default="0" />
+ <param index="0" name="value" type="int" />
+ <param index="1" name="from" type="int" default="0" />
<description>
Searches the array for a value and returns its index or [code]-1[/code] if not found. Optionally, the initial search index can be passed.
</description>
</method>
<method name="has" qualifiers="const">
<return type="bool" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
- Returns [code]true[/code] if the array contains [code]value[/code].
+ Returns [code]true[/code] if the array contains [param value].
</description>
</method>
<method name="insert">
<return type="int" />
- <argument index="0" name="at_index" type="int" />
- <argument index="1" name="value" type="int" />
+ <param index="0" name="at_index" type="int" />
+ <param index="1" name="value" type="int" />
<description>
Inserts a new integer at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
@@ -106,21 +112,21 @@
</method>
<method name="push_back">
<return type="bool" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Appends a value to the array.
</description>
</method>
<method name="remove_at">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Removes an element from the array by index.
</description>
</method>
<method name="resize">
<return type="int" />
- <argument index="0" name="new_size" type="int" />
+ <param index="0" name="new_size" type="int" />
<description>
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
@@ -133,16 +139,16 @@
</method>
<method name="rfind" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="int" />
- <argument index="1" name="from" type="int" default="-1" />
+ <param index="0" name="value" type="int" />
+ <param index="1" name="from" type="int" default="-1" />
<description>
Searches the array in reverse order. Optionally, a start search index can be passed. If negative, the start index is considered relative to the end of the array.
</description>
</method>
<method name="set">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="value" type="int" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="value" type="int" />
<description>
Changes the integer at the given index.
</description>
@@ -155,12 +161,12 @@
</method>
<method name="slice" qualifiers="const">
<return type="PackedInt32Array" />
- <argument index="0" name="begin" type="int" />
- <argument index="1" name="end" type="int" default="2147483647" />
+ <param index="0" name="begin" type="int" />
+ <param index="1" name="end" type="int" default="2147483647" />
<description>
- Returns the slice of the [PackedInt32Array], from [code]begin[/code] (inclusive) to [code]end[/code] (exclusive), as a new [PackedInt32Array].
- The absolute value of [code]begin[/code] and [code]end[/code] will be clamped to the array size, so the default value for [code]end[/code] makes it slice to the size of the array by default (i.e. [code]arr.slice(1)[/code] is a shorthand for [code]arr.slice(1, arr.size())[/code]).
- If either [code]begin[/code] or [code]end[/code] are negative, they will be relative to the end of the array (i.e. [code]arr.slice(0, -2)[/code] is a shorthand for [code]arr.slice(0, arr.size() - 2)[/code]).
+ Returns the slice of the [PackedInt32Array], from [param begin] (inclusive) to [param end] (exclusive), as a new [PackedInt32Array].
+ The absolute value of [param begin] and [param end] will be clamped to the array size, so the default value for [param end] makes it slice to the size of the array by default (i.e. [code]arr.slice(1)[/code] is a shorthand for [code]arr.slice(1, arr.size())[/code]).
+ If either [param begin] or [param end] are negative, they will be relative to the end of the array (i.e. [code]arr.slice(0, -2)[/code] is a shorthand for [code]arr.slice(0, arr.size() - 2)[/code]).
</description>
</method>
<method name="sort">
@@ -180,26 +186,31 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="PackedInt32Array" />
+ <param index="0" name="right" type="PackedInt32Array" />
<description>
+ Returns [code]true[/code] if contents of the arrays differ.
</description>
</operator>
<operator name="operator +">
<return type="PackedInt32Array" />
- <argument index="0" name="right" type="PackedInt32Array" />
+ <param index="0" name="right" type="PackedInt32Array" />
<description>
+ Returns a new [PackedInt32Array] with contents of [param right] added at the end of this array. For better performance, consider using [method append_array] instead.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="PackedInt32Array" />
+ <param index="0" name="right" type="PackedInt32Array" />
<description>
+ Returns [code]true[/code] if contents of both arrays are the same, i.e. they have all equal ints at the corresponding indices.
</description>
</operator>
<operator name="operator []">
<return type="int" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
+ Returns the [int] at index [param index]. Negative indices can be used to access the elements starting from the end. Using index out of array's bounds will result in an error.
+ Note that [int] type is 64-bit, unlike the values stored in the array.
</description>
</operator>
</operators>
diff --git a/doc/classes/PackedInt64Array.xml b/doc/classes/PackedInt64Array.xml
index ea3e304d35..5f762cde3e 100644
--- a/doc/classes/PackedInt64Array.xml
+++ b/doc/classes/PackedInt64Array.xml
@@ -18,14 +18,14 @@
</constructor>
<constructor name="PackedInt64Array">
<return type="PackedInt64Array" />
- <argument index="0" name="from" type="PackedInt64Array" />
+ <param index="0" name="from" type="PackedInt64Array" />
<description>
Constructs a [PackedInt64Array] as a copy of the given [PackedInt64Array].
</description>
</constructor>
<constructor name="PackedInt64Array">
<return type="PackedInt64Array" />
- <argument index="0" name="from" type="Array" />
+ <param index="0" name="from" type="Array" />
<description>
Constructs a new [PackedInt64Array]. Optionally, you can pass in a generic [Array] that will be converted.
</description>
@@ -34,30 +34,36 @@
<methods>
<method name="append">
<return type="bool" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Appends an element at the end of the array (alias of [method push_back]).
</description>
</method>
<method name="append_array">
<return type="void" />
- <argument index="0" name="array" type="PackedInt64Array" />
+ <param index="0" name="array" type="PackedInt64Array" />
<description>
Appends a [PackedInt64Array] at the end of this array.
</description>
</method>
<method name="bsearch">
<return type="int" />
- <argument index="0" name="value" type="int" />
- <argument index="1" name="before" type="bool" default="true" />
+ <param index="0" name="value" type="int" />
+ <param index="1" name="before" type="bool" default="true" />
<description>
- Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search. Optionally, a [code]before[/code] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array.
+ Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search. Optionally, a [param before] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array.
[b]Note:[/b] Calling [method bsearch] on an unsorted array results in unexpected behavior.
</description>
</method>
+ <method name="clear">
+ <return type="void" />
+ <description>
+ Clears the array. This is equivalent to using [method resize] with a size of [code]0[/code].
+ </description>
+ </method>
<method name="count" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Returns the number of times an element is in the array.
</description>
@@ -70,30 +76,30 @@
</method>
<method name="fill">
<return type="void" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
</description>
</method>
<method name="find" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="int" />
- <argument index="1" name="from" type="int" default="0" />
+ <param index="0" name="value" type="int" />
+ <param index="1" name="from" type="int" default="0" />
<description>
Searches the array for a value and returns its index or [code]-1[/code] if not found. Optionally, the initial search index can be passed.
</description>
</method>
<method name="has" qualifiers="const">
<return type="bool" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
- Returns [code]true[/code] if the array contains [code]value[/code].
+ Returns [code]true[/code] if the array contains [param value].
</description>
</method>
<method name="insert">
<return type="int" />
- <argument index="0" name="at_index" type="int" />
- <argument index="1" name="value" type="int" />
+ <param index="0" name="at_index" type="int" />
+ <param index="1" name="value" type="int" />
<description>
Inserts a new integer at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
@@ -106,21 +112,21 @@
</method>
<method name="push_back">
<return type="bool" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Appends a value to the array.
</description>
</method>
<method name="remove_at">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Removes an element from the array by index.
</description>
</method>
<method name="resize">
<return type="int" />
- <argument index="0" name="new_size" type="int" />
+ <param index="0" name="new_size" type="int" />
<description>
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
@@ -133,16 +139,16 @@
</method>
<method name="rfind" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="int" />
- <argument index="1" name="from" type="int" default="-1" />
+ <param index="0" name="value" type="int" />
+ <param index="1" name="from" type="int" default="-1" />
<description>
Searches the array in reverse order. Optionally, a start search index can be passed. If negative, the start index is considered relative to the end of the array.
</description>
</method>
<method name="set">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="value" type="int" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="value" type="int" />
<description>
Changes the integer at the given index.
</description>
@@ -155,12 +161,12 @@
</method>
<method name="slice" qualifiers="const">
<return type="PackedInt64Array" />
- <argument index="0" name="begin" type="int" />
- <argument index="1" name="end" type="int" default="2147483647" />
+ <param index="0" name="begin" type="int" />
+ <param index="1" name="end" type="int" default="2147483647" />
<description>
- Returns the slice of the [PackedInt64Array], from [code]begin[/code] (inclusive) to [code]end[/code] (exclusive), as a new [PackedInt64Array].
- The absolute value of [code]begin[/code] and [code]end[/code] will be clamped to the array size, so the default value for [code]end[/code] makes it slice to the size of the array by default (i.e. [code]arr.slice(1)[/code] is a shorthand for [code]arr.slice(1, arr.size())[/code]).
- If either [code]begin[/code] or [code]end[/code] are negative, they will be relative to the end of the array (i.e. [code]arr.slice(0, -2)[/code] is a shorthand for [code]arr.slice(0, arr.size() - 2)[/code]).
+ Returns the slice of the [PackedInt64Array], from [param begin] (inclusive) to [param end] (exclusive), as a new [PackedInt64Array].
+ The absolute value of [param begin] and [param end] will be clamped to the array size, so the default value for [param end] makes it slice to the size of the array by default (i.e. [code]arr.slice(1)[/code] is a shorthand for [code]arr.slice(1, arr.size())[/code]).
+ If either [param begin] or [param end] are negative, they will be relative to the end of the array (i.e. [code]arr.slice(0, -2)[/code] is a shorthand for [code]arr.slice(0, arr.size() - 2)[/code]).
</description>
</method>
<method name="sort">
@@ -180,26 +186,30 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="PackedInt64Array" />
+ <param index="0" name="right" type="PackedInt64Array" />
<description>
+ Returns [code]true[/code] if contents of the arrays differ.
</description>
</operator>
<operator name="operator +">
<return type="PackedInt64Array" />
- <argument index="0" name="right" type="PackedInt64Array" />
+ <param index="0" name="right" type="PackedInt64Array" />
<description>
+ Returns a new [PackedInt64Array] with contents of [param right] added at the end of this array. For better performance, consider using [method append_array] instead.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="PackedInt64Array" />
+ <param index="0" name="right" type="PackedInt64Array" />
<description>
+ Returns [code]true[/code] if contents of both arrays are the same, i.e. they have all equal ints at the corresponding indices.
</description>
</operator>
<operator name="operator []">
<return type="int" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
+ Returns the [int] at index [param index]. Negative indices can be used to access the elements starting from the end. Using index out of array's bounds will result in an error.
</description>
</operator>
</operators>
diff --git a/doc/classes/PackedScene.xml b/doc/classes/PackedScene.xml
index 038b774b97..97595a6984 100644
--- a/doc/classes/PackedScene.xml
+++ b/doc/classes/PackedScene.xml
@@ -22,12 +22,12 @@
AddChild(scene);
[/csharp]
[/codeblocks]
- [b]Example of saving a node with different owners:[/b] The following example creates 3 objects: [Node2D] ([code]node[/code]), [RigidDynamicBody2D] ([code]body[/code]) and [CollisionObject2D] ([code]collision[/code]). [code]collision[/code] is a child of [code]body[/code] which is a child of [code]node[/code]. Only [code]body[/code] is owned by [code]node[/code] and [code]pack[/code] will therefore only save those two nodes, but not [code]collision[/code].
+ [b]Example of saving a node with different owners:[/b] The following example creates 3 objects: [Node2D] ([code]node[/code]), [RigidBody2D] ([code]body[/code]) and [CollisionObject2D] ([code]collision[/code]). [code]collision[/code] is a child of [code]body[/code] which is a child of [code]node[/code]. Only [code]body[/code] is owned by [code]node[/code] and [code]pack[/code] will therefore only save those two nodes, but not [code]collision[/code].
[codeblocks]
[gdscript]
# Create the objects.
var node = Node2D.new()
- var body = RigidDynamicBody2D.new()
+ var body = RigidBody2D.new()
var collision = CollisionShape2D.new()
# Create the object hierarchy.
@@ -48,7 +48,7 @@
[csharp]
// Create the objects.
var node = new Node2D();
- var body = new RigidDynamicBody2D();
+ var body = new RigidBody2D();
var collision = new CollisionShape2D();
// Create the object hierarchy.
@@ -90,14 +90,14 @@
</method>
<method name="instantiate" qualifiers="const">
<return type="Node" />
- <argument index="0" name="edit_state" type="int" enum="PackedScene.GenEditState" default="0" />
+ <param index="0" name="edit_state" type="int" enum="PackedScene.GenEditState" default="0" />
<description>
Instantiates the scene's node hierarchy. Triggers child scene instantiation(s). Triggers a [constant Node.NOTIFICATION_SCENE_INSTANTIATED] notification on the root node.
</description>
</method>
<method name="pack">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="Node" />
+ <param index="0" name="path" type="Node" />
<description>
Pack will ignore any sub-nodes not owned by given node. See [member Node.owner].
</description>
diff --git a/doc/classes/PackedStringArray.xml b/doc/classes/PackedStringArray.xml
index a4653344f0..2c3376d659 100644
--- a/doc/classes/PackedStringArray.xml
+++ b/doc/classes/PackedStringArray.xml
@@ -24,14 +24,14 @@
</constructor>
<constructor name="PackedStringArray">
<return type="PackedStringArray" />
- <argument index="0" name="from" type="PackedStringArray" />
+ <param index="0" name="from" type="PackedStringArray" />
<description>
Constructs a [PackedStringArray] as a copy of the given [PackedStringArray].
</description>
</constructor>
<constructor name="PackedStringArray">
<return type="PackedStringArray" />
- <argument index="0" name="from" type="Array" />
+ <param index="0" name="from" type="Array" />
<description>
Constructs a new [PackedStringArray]. Optionally, you can pass in a generic [Array] that will be converted.
</description>
@@ -40,30 +40,36 @@
<methods>
<method name="append">
<return type="bool" />
- <argument index="0" name="value" type="String" />
+ <param index="0" name="value" type="String" />
<description>
Appends an element at the end of the array (alias of [method push_back]).
</description>
</method>
<method name="append_array">
<return type="void" />
- <argument index="0" name="array" type="PackedStringArray" />
+ <param index="0" name="array" type="PackedStringArray" />
<description>
Appends a [PackedStringArray] at the end of this array.
</description>
</method>
<method name="bsearch">
<return type="int" />
- <argument index="0" name="value" type="String" />
- <argument index="1" name="before" type="bool" default="true" />
+ <param index="0" name="value" type="String" />
+ <param index="1" name="before" type="bool" default="true" />
<description>
- Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search. Optionally, a [code]before[/code] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array.
+ Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search. Optionally, a [param before] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array.
[b]Note:[/b] Calling [method bsearch] on an unsorted array results in unexpected behavior.
</description>
</method>
+ <method name="clear">
+ <return type="void" />
+ <description>
+ Clears the array. This is equivalent to using [method resize] with a size of [code]0[/code].
+ </description>
+ </method>
<method name="count" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="String" />
+ <param index="0" name="value" type="String" />
<description>
Returns the number of times an element is in the array.
</description>
@@ -76,30 +82,30 @@
</method>
<method name="fill">
<return type="void" />
- <argument index="0" name="value" type="String" />
+ <param index="0" name="value" type="String" />
<description>
Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
</description>
</method>
<method name="find" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="String" />
- <argument index="1" name="from" type="int" default="0" />
+ <param index="0" name="value" type="String" />
+ <param index="1" name="from" type="int" default="0" />
<description>
Searches the array for a value and returns its index or [code]-1[/code] if not found. Optionally, the initial search index can be passed.
</description>
</method>
<method name="has" qualifiers="const">
<return type="bool" />
- <argument index="0" name="value" type="String" />
+ <param index="0" name="value" type="String" />
<description>
- Returns [code]true[/code] if the array contains [code]value[/code].
+ Returns [code]true[/code] if the array contains [param value].
</description>
</method>
<method name="insert">
<return type="int" />
- <argument index="0" name="at_index" type="int" />
- <argument index="1" name="value" type="String" />
+ <param index="0" name="at_index" type="int" />
+ <param index="1" name="value" type="String" />
<description>
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
@@ -112,21 +118,21 @@
</method>
<method name="push_back">
<return type="bool" />
- <argument index="0" name="value" type="String" />
+ <param index="0" name="value" type="String" />
<description>
Appends a string element at end of the array.
</description>
</method>
<method name="remove_at">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Removes an element from the array by index.
</description>
</method>
<method name="resize">
<return type="int" />
- <argument index="0" name="new_size" type="int" />
+ <param index="0" name="new_size" type="int" />
<description>
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
@@ -139,16 +145,16 @@
</method>
<method name="rfind" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="String" />
- <argument index="1" name="from" type="int" default="-1" />
+ <param index="0" name="value" type="String" />
+ <param index="1" name="from" type="int" default="-1" />
<description>
Searches the array in reverse order. Optionally, a start search index can be passed. If negative, the start index is considered relative to the end of the array.
</description>
</method>
<method name="set">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="value" type="String" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="value" type="String" />
<description>
Changes the [String] at the given index.
</description>
@@ -161,12 +167,12 @@
</method>
<method name="slice" qualifiers="const">
<return type="PackedStringArray" />
- <argument index="0" name="begin" type="int" />
- <argument index="1" name="end" type="int" default="2147483647" />
+ <param index="0" name="begin" type="int" />
+ <param index="1" name="end" type="int" default="2147483647" />
<description>
- Returns the slice of the [PackedStringArray], from [code]begin[/code] (inclusive) to [code]end[/code] (exclusive), as a new [PackedStringArray].
- The absolute value of [code]begin[/code] and [code]end[/code] will be clamped to the array size, so the default value for [code]end[/code] makes it slice to the size of the array by default (i.e. [code]arr.slice(1)[/code] is a shorthand for [code]arr.slice(1, arr.size())[/code]).
- If either [code]begin[/code] or [code]end[/code] are negative, they will be relative to the end of the array (i.e. [code]arr.slice(0, -2)[/code] is a shorthand for [code]arr.slice(0, arr.size() - 2)[/code]).
+ Returns the slice of the [PackedStringArray], from [param begin] (inclusive) to [param end] (exclusive), as a new [PackedStringArray].
+ The absolute value of [param begin] and [param end] will be clamped to the array size, so the default value for [param end] makes it slice to the size of the array by default (i.e. [code]arr.slice(1)[/code] is a shorthand for [code]arr.slice(1, arr.size())[/code]).
+ If either [param begin] or [param end] are negative, they will be relative to the end of the array (i.e. [code]arr.slice(0, -2)[/code] is a shorthand for [code]arr.slice(0, arr.size() - 2)[/code]).
</description>
</method>
<method name="sort">
@@ -178,32 +184,37 @@
<method name="to_byte_array" qualifiers="const">
<return type="PackedByteArray" />
<description>
+ Returns a [PackedByteArray] with each string encoded as bytes.
</description>
</method>
</methods>
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="PackedStringArray" />
+ <param index="0" name="right" type="PackedStringArray" />
<description>
+ Returns [code]true[/code] if contents of the arrays differ.
</description>
</operator>
<operator name="operator +">
<return type="PackedStringArray" />
- <argument index="0" name="right" type="PackedStringArray" />
+ <param index="0" name="right" type="PackedStringArray" />
<description>
+ Returns a new [PackedStringArray] with contents of [param right] added at the end of this array. For better performance, consider using [method append_array] instead.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="PackedStringArray" />
+ <param index="0" name="right" type="PackedStringArray" />
<description>
+ Returns [code]true[/code] if contents of both arrays are the same, i.e. they have all equal [String]s at the corresponding indices.
</description>
</operator>
<operator name="operator []">
<return type="String" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
+ Returns the [String] at index [param index]. Negative indices can be used to access the elements starting from the end. Using index out of array's bounds will result in an error.
</description>
</operator>
</operators>
diff --git a/doc/classes/PackedVector2Array.xml b/doc/classes/PackedVector2Array.xml
index 8f3e5d173d..25650ef40a 100644
--- a/doc/classes/PackedVector2Array.xml
+++ b/doc/classes/PackedVector2Array.xml
@@ -18,14 +18,14 @@
</constructor>
<constructor name="PackedVector2Array">
<return type="PackedVector2Array" />
- <argument index="0" name="from" type="PackedVector2Array" />
+ <param index="0" name="from" type="PackedVector2Array" />
<description>
Constructs a [PackedVector2Array] as a copy of the given [PackedVector2Array].
</description>
</constructor>
<constructor name="PackedVector2Array">
<return type="PackedVector2Array" />
- <argument index="0" name="from" type="Array" />
+ <param index="0" name="from" type="Array" />
<description>
Constructs a new [PackedVector2Array]. Optionally, you can pass in a generic [Array] that will be converted.
</description>
@@ -34,30 +34,36 @@
<methods>
<method name="append">
<return type="bool" />
- <argument index="0" name="value" type="Vector2" />
+ <param index="0" name="value" type="Vector2" />
<description>
Appends an element at the end of the array (alias of [method push_back]).
</description>
</method>
<method name="append_array">
<return type="void" />
- <argument index="0" name="array" type="PackedVector2Array" />
+ <param index="0" name="array" type="PackedVector2Array" />
<description>
Appends a [PackedVector2Array] at the end of this array.
</description>
</method>
<method name="bsearch">
<return type="int" />
- <argument index="0" name="value" type="Vector2" />
- <argument index="1" name="before" type="bool" default="true" />
+ <param index="0" name="value" type="Vector2" />
+ <param index="1" name="before" type="bool" default="true" />
<description>
- Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search. Optionally, a [code]before[/code] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array.
+ Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search. Optionally, a [param before] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array.
[b]Note:[/b] Calling [method bsearch] on an unsorted array results in unexpected behavior.
</description>
</method>
+ <method name="clear">
+ <return type="void" />
+ <description>
+ Clears the array. This is equivalent to using [method resize] with a size of [code]0[/code].
+ </description>
+ </method>
<method name="count" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="Vector2" />
+ <param index="0" name="value" type="Vector2" />
<description>
Returns the number of times an element is in the array.
</description>
@@ -70,30 +76,30 @@
</method>
<method name="fill">
<return type="void" />
- <argument index="0" name="value" type="Vector2" />
+ <param index="0" name="value" type="Vector2" />
<description>
Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
</description>
</method>
<method name="find" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="Vector2" />
- <argument index="1" name="from" type="int" default="0" />
+ <param index="0" name="value" type="Vector2" />
+ <param index="1" name="from" type="int" default="0" />
<description>
Searches the array for a value and returns its index or [code]-1[/code] if not found. Optionally, the initial search index can be passed.
</description>
</method>
<method name="has" qualifiers="const">
<return type="bool" />
- <argument index="0" name="value" type="Vector2" />
+ <param index="0" name="value" type="Vector2" />
<description>
- Returns [code]true[/code] if the array contains [code]value[/code].
+ Returns [code]true[/code] if the array contains [param value].
</description>
</method>
<method name="insert">
<return type="int" />
- <argument index="0" name="at_index" type="int" />
- <argument index="1" name="value" type="Vector2" />
+ <param index="0" name="at_index" type="int" />
+ <param index="1" name="value" type="Vector2" />
<description>
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
@@ -106,21 +112,21 @@
</method>
<method name="push_back">
<return type="bool" />
- <argument index="0" name="value" type="Vector2" />
+ <param index="0" name="value" type="Vector2" />
<description>
Inserts a [Vector2] at the end.
</description>
</method>
<method name="remove_at">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Removes an element from the array by index.
</description>
</method>
<method name="resize">
<return type="int" />
- <argument index="0" name="new_size" type="int" />
+ <param index="0" name="new_size" type="int" />
<description>
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
@@ -133,16 +139,16 @@
</method>
<method name="rfind" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="Vector2" />
- <argument index="1" name="from" type="int" default="-1" />
+ <param index="0" name="value" type="Vector2" />
+ <param index="1" name="from" type="int" default="-1" />
<description>
Searches the array in reverse order. Optionally, a start search index can be passed. If negative, the start index is considered relative to the end of the array.
</description>
</method>
<method name="set">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="value" type="Vector2" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="value" type="Vector2" />
<description>
Changes the [Vector2] at the given index.
</description>
@@ -155,12 +161,12 @@
</method>
<method name="slice" qualifiers="const">
<return type="PackedVector2Array" />
- <argument index="0" name="begin" type="int" />
- <argument index="1" name="end" type="int" default="2147483647" />
+ <param index="0" name="begin" type="int" />
+ <param index="1" name="end" type="int" default="2147483647" />
<description>
- Returns the slice of the [PackedVector2Array], from [code]begin[/code] (inclusive) to [code]end[/code] (exclusive), as a new [PackedVector2Array].
- The absolute value of [code]begin[/code] and [code]end[/code] will be clamped to the array size, so the default value for [code]end[/code] makes it slice to the size of the array by default (i.e. [code]arr.slice(1)[/code] is a shorthand for [code]arr.slice(1, arr.size())[/code]).
- If either [code]begin[/code] or [code]end[/code] are negative, they will be relative to the end of the array (i.e. [code]arr.slice(0, -2)[/code] is a shorthand for [code]arr.slice(0, arr.size() - 2)[/code]).
+ Returns the slice of the [PackedVector2Array], from [param begin] (inclusive) to [param end] (exclusive), as a new [PackedVector2Array].
+ The absolute value of [param begin] and [param end] will be clamped to the array size, so the default value for [param end] makes it slice to the size of the array by default (i.e. [code]arr.slice(1)[/code] is a shorthand for [code]arr.slice(1, arr.size())[/code]).
+ If either [param begin] or [param end] are negative, they will be relative to the end of the array (i.e. [code]arr.slice(0, -2)[/code] is a shorthand for [code]arr.slice(0, arr.size() - 2)[/code]).
</description>
</method>
<method name="sort">
@@ -172,38 +178,44 @@
<method name="to_byte_array" qualifiers="const">
<return type="PackedByteArray" />
<description>
+ Returns a [PackedByteArray] with each vector encoded as bytes.
</description>
</method>
</methods>
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="PackedVector2Array" />
+ <param index="0" name="right" type="PackedVector2Array" />
<description>
+ Returns [code]true[/code] if contents of the arrays differ.
</description>
</operator>
<operator name="operator *">
<return type="PackedVector2Array" />
- <argument index="0" name="right" type="Transform2D" />
+ <param index="0" name="right" type="Transform2D" />
<description>
+ Transforms (multiplies) all vectors in the array by the [Transform2D] matrix.
</description>
</operator>
<operator name="operator +">
<return type="PackedVector2Array" />
- <argument index="0" name="right" type="PackedVector2Array" />
+ <param index="0" name="right" type="PackedVector2Array" />
<description>
+ Returns a new [PackedVector2Array] with contents of [param right] added at the end of this array. For better performance, consider using [method append_array] instead.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="PackedVector2Array" />
+ <param index="0" name="right" type="PackedVector2Array" />
<description>
+ Returns [code]true[/code] if contents of both arrays are the same, i.e. they have all equal [Vector2]s at the corresponding indices.
</description>
</operator>
<operator name="operator []">
<return type="Vector2" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
+ Returns the [Vector2] at index [param index]. Negative indices can be used to access the elements starting from the end. Using index out of array's bounds will result in an error.
</description>
</operator>
</operators>
diff --git a/doc/classes/PackedVector3Array.xml b/doc/classes/PackedVector3Array.xml
index 1207293c32..22979a5a37 100644
--- a/doc/classes/PackedVector3Array.xml
+++ b/doc/classes/PackedVector3Array.xml
@@ -17,14 +17,14 @@
</constructor>
<constructor name="PackedVector3Array">
<return type="PackedVector3Array" />
- <argument index="0" name="from" type="PackedVector3Array" />
+ <param index="0" name="from" type="PackedVector3Array" />
<description>
Constructs a [PackedVector3Array] as a copy of the given [PackedVector3Array].
</description>
</constructor>
<constructor name="PackedVector3Array">
<return type="PackedVector3Array" />
- <argument index="0" name="from" type="Array" />
+ <param index="0" name="from" type="Array" />
<description>
Constructs a new [PackedVector3Array]. Optionally, you can pass in a generic [Array] that will be converted.
</description>
@@ -33,30 +33,36 @@
<methods>
<method name="append">
<return type="bool" />
- <argument index="0" name="value" type="Vector3" />
+ <param index="0" name="value" type="Vector3" />
<description>
Appends an element at the end of the array (alias of [method push_back]).
</description>
</method>
<method name="append_array">
<return type="void" />
- <argument index="0" name="array" type="PackedVector3Array" />
+ <param index="0" name="array" type="PackedVector3Array" />
<description>
Appends a [PackedVector3Array] at the end of this array.
</description>
</method>
<method name="bsearch">
<return type="int" />
- <argument index="0" name="value" type="Vector3" />
- <argument index="1" name="before" type="bool" default="true" />
+ <param index="0" name="value" type="Vector3" />
+ <param index="1" name="before" type="bool" default="true" />
<description>
- Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search. Optionally, a [code]before[/code] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array.
+ Finds the index of an existing value (or the insertion index that maintains sorting order, if the value is not yet present in the array) using binary search. Optionally, a [param before] specifier can be passed. If [code]false[/code], the returned index comes after all existing entries of the value in the array.
[b]Note:[/b] Calling [method bsearch] on an unsorted array results in unexpected behavior.
</description>
</method>
+ <method name="clear">
+ <return type="void" />
+ <description>
+ Clears the array. This is equivalent to using [method resize] with a size of [code]0[/code].
+ </description>
+ </method>
<method name="count" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="Vector3" />
+ <param index="0" name="value" type="Vector3" />
<description>
Returns the number of times an element is in the array.
</description>
@@ -69,30 +75,30 @@
</method>
<method name="fill">
<return type="void" />
- <argument index="0" name="value" type="Vector3" />
+ <param index="0" name="value" type="Vector3" />
<description>
Assigns the given value to all elements in the array. This can typically be used together with [method resize] to create an array with a given size and initialized elements.
</description>
</method>
<method name="find" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="Vector3" />
- <argument index="1" name="from" type="int" default="0" />
+ <param index="0" name="value" type="Vector3" />
+ <param index="1" name="from" type="int" default="0" />
<description>
Searches the array for a value and returns its index or [code]-1[/code] if not found. Optionally, the initial search index can be passed.
</description>
</method>
<method name="has" qualifiers="const">
<return type="bool" />
- <argument index="0" name="value" type="Vector3" />
+ <param index="0" name="value" type="Vector3" />
<description>
- Returns [code]true[/code] if the array contains [code]value[/code].
+ Returns [code]true[/code] if the array contains [param value].
</description>
</method>
<method name="insert">
<return type="int" />
- <argument index="0" name="at_index" type="int" />
- <argument index="1" name="value" type="Vector3" />
+ <param index="0" name="at_index" type="int" />
+ <param index="1" name="value" type="Vector3" />
<description>
Inserts a new element at a given position in the array. The position must be valid, or at the end of the array ([code]idx == size()[/code]).
</description>
@@ -105,21 +111,21 @@
</method>
<method name="push_back">
<return type="bool" />
- <argument index="0" name="value" type="Vector3" />
+ <param index="0" name="value" type="Vector3" />
<description>
Inserts a [Vector3] at the end.
</description>
</method>
<method name="remove_at">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Removes an element from the array by index.
</description>
</method>
<method name="resize">
<return type="int" />
- <argument index="0" name="new_size" type="int" />
+ <param index="0" name="new_size" type="int" />
<description>
Sets the size of the array. If the array is grown, reserves elements at the end of the array. If the array is shrunk, truncates the array to the new size.
</description>
@@ -132,16 +138,16 @@
</method>
<method name="rfind" qualifiers="const">
<return type="int" />
- <argument index="0" name="value" type="Vector3" />
- <argument index="1" name="from" type="int" default="-1" />
+ <param index="0" name="value" type="Vector3" />
+ <param index="1" name="from" type="int" default="-1" />
<description>
Searches the array in reverse order. Optionally, a start search index can be passed. If negative, the start index is considered relative to the end of the array.
</description>
</method>
<method name="set">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="value" type="Vector3" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="value" type="Vector3" />
<description>
Changes the [Vector3] at the given index.
</description>
@@ -154,12 +160,12 @@
</method>
<method name="slice" qualifiers="const">
<return type="PackedVector3Array" />
- <argument index="0" name="begin" type="int" />
- <argument index="1" name="end" type="int" default="2147483647" />
+ <param index="0" name="begin" type="int" />
+ <param index="1" name="end" type="int" default="2147483647" />
<description>
- Returns the slice of the [PackedVector3Array], from [code]begin[/code] (inclusive) to [code]end[/code] (exclusive), as a new [PackedVector3Array].
- The absolute value of [code]begin[/code] and [code]end[/code] will be clamped to the array size, so the default value for [code]end[/code] makes it slice to the size of the array by default (i.e. [code]arr.slice(1)[/code] is a shorthand for [code]arr.slice(1, arr.size())[/code]).
- If either [code]begin[/code] or [code]end[/code] are negative, they will be relative to the end of the array (i.e. [code]arr.slice(0, -2)[/code] is a shorthand for [code]arr.slice(0, arr.size() - 2)[/code]).
+ Returns the slice of the [PackedVector3Array], from [param begin] (inclusive) to [param end] (exclusive), as a new [PackedVector3Array].
+ The absolute value of [param begin] and [param end] will be clamped to the array size, so the default value for [param end] makes it slice to the size of the array by default (i.e. [code]arr.slice(1)[/code] is a shorthand for [code]arr.slice(1, arr.size())[/code]).
+ If either [param begin] or [param end] are negative, they will be relative to the end of the array (i.e. [code]arr.slice(0, -2)[/code] is a shorthand for [code]arr.slice(0, arr.size() - 2)[/code]).
</description>
</method>
<method name="sort">
@@ -171,38 +177,44 @@
<method name="to_byte_array" qualifiers="const">
<return type="PackedByteArray" />
<description>
+ Returns a [PackedByteArray] with each vector encoded as bytes.
</description>
</method>
</methods>
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="PackedVector3Array" />
+ <param index="0" name="right" type="PackedVector3Array" />
<description>
+ Returns [code]true[/code] if contents of the arrays differ.
</description>
</operator>
<operator name="operator *">
<return type="PackedVector3Array" />
- <argument index="0" name="right" type="Transform3D" />
+ <param index="0" name="right" type="Transform3D" />
<description>
+ Transforms (multiplies) all vectors in the array by the [Transform3D] matrix.
</description>
</operator>
<operator name="operator +">
<return type="PackedVector3Array" />
- <argument index="0" name="right" type="PackedVector3Array" />
+ <param index="0" name="right" type="PackedVector3Array" />
<description>
+ Returns a new [PackedVector3Array] with contents of [param right] added at the end of this array. For better performance, consider using [method append_array] instead.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="PackedVector3Array" />
+ <param index="0" name="right" type="PackedVector3Array" />
<description>
+ Returns [code]true[/code] if contents of both arrays are the same, i.e. they have all equal [Vector3]s at the corresponding indices.
</description>
</operator>
<operator name="operator []">
<return type="Vector3" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
+ Returns the [Vector3] at index [param index]. Negative indices can be used to access the elements starting from the end. Using index out of array's bounds will result in an error.
</description>
</operator>
</operators>
diff --git a/doc/classes/PacketPeer.xml b/doc/classes/PacketPeer.xml
index 40fa90e4da..ab2bc34672 100644
--- a/doc/classes/PacketPeer.xml
+++ b/doc/classes/PacketPeer.xml
@@ -30,25 +30,25 @@
</method>
<method name="get_var">
<return type="Variant" />
- <argument index="0" name="allow_objects" type="bool" default="false" />
+ <param index="0" name="allow_objects" type="bool" default="false" />
<description>
- Gets a Variant. If [code]allow_objects[/code] is [code]true[/code], decoding objects is allowed.
+ Gets a Variant. If [param allow_objects] is [code]true[/code], decoding objects is allowed.
[b]Warning:[/b] Deserialized objects can contain code which gets executed. Do not use this option if the serialized object comes from untrusted sources to avoid potential security threats such as remote code execution.
</description>
</method>
<method name="put_packet">
<return type="int" enum="Error" />
- <argument index="0" name="buffer" type="PackedByteArray" />
+ <param index="0" name="buffer" type="PackedByteArray" />
<description>
Sends a raw packet.
</description>
</method>
<method name="put_var">
<return type="int" enum="Error" />
- <argument index="0" name="var" type="Variant" />
- <argument index="1" name="full_objects" type="bool" default="false" />
+ <param index="0" name="var" type="Variant" />
+ <param index="1" name="full_objects" type="bool" default="false" />
<description>
- Sends a [Variant] as a packet. If [code]full_objects[/code] is [code]true[/code], encoding objects is allowed (and can potentially include code).
+ Sends a [Variant] as a packet. If [param full_objects] is [code]true[/code], encoding objects is allowed (and can potentially include code).
</description>
</method>
</methods>
diff --git a/doc/classes/PacketPeerDTLS.xml b/doc/classes/PacketPeerDTLS.xml
index ee45c42498..e9918bdd3a 100644
--- a/doc/classes/PacketPeerDTLS.xml
+++ b/doc/classes/PacketPeerDTLS.xml
@@ -13,12 +13,12 @@
<methods>
<method name="connect_to_peer">
<return type="int" enum="Error" />
- <argument index="0" name="packet_peer" type="PacketPeerUDP" />
- <argument index="1" name="validate_certs" type="bool" default="true" />
- <argument index="2" name="for_hostname" type="String" default="&quot;&quot;" />
- <argument index="3" name="valid_certificate" type="X509Certificate" default="null" />
+ <param index="0" name="packet_peer" type="PacketPeerUDP" />
+ <param index="1" name="validate_certs" type="bool" default="true" />
+ <param index="2" name="for_hostname" type="String" default="&quot;&quot;" />
+ <param index="3" name="valid_certificate" type="X509Certificate" default="null" />
<description>
- Connects a [code]peer[/code] beginning the DTLS handshake using the underlying [PacketPeerUDP] which must be connected (see [method PacketPeerUDP.connect_to_host]). If [code]validate_certs[/code] is [code]true[/code], [PacketPeerDTLS] will validate that the certificate presented by the remote peer and match it with the [code]for_hostname[/code] argument. You can specify a custom [X509Certificate] to use for validation via the [code]valid_certificate[/code] argument.
+ Connects a [param packet_peer] beginning the DTLS handshake using the underlying [PacketPeerUDP] which must be connected (see [method PacketPeerUDP.connect_to_host]). If [param validate_certs] is [code]true[/code], [PacketPeerDTLS] will validate that the certificate presented by the remote peer and match it with the [param for_hostname] argument. You can specify a custom [X509Certificate] to use for validation via the [param valid_certificate] argument.
</description>
</method>
<method name="disconnect_from_peer">
diff --git a/doc/classes/PacketPeerExtension.xml b/doc/classes/PacketPeerExtension.xml
index 7cf5ef3504..28263b3f59 100644
--- a/doc/classes/PacketPeerExtension.xml
+++ b/doc/classes/PacketPeerExtension.xml
@@ -19,15 +19,15 @@
</method>
<method name="_get_packet" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="r_buffer" type="const uint8_t **" />
- <argument index="1" name="r_buffer_size" type="int32_t*" />
+ <param index="0" name="r_buffer" type="const uint8_t **" />
+ <param index="1" name="r_buffer_size" type="int32_t*" />
<description>
</description>
</method>
<method name="_put_packet" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="p_buffer" type="const uint8_t*" />
- <argument index="1" name="p_buffer_size" type="int" />
+ <param index="0" name="p_buffer" type="const uint8_t*" />
+ <param index="1" name="p_buffer_size" type="int" />
<description>
</description>
</method>
diff --git a/doc/classes/PacketPeerUDP.xml b/doc/classes/PacketPeerUDP.xml
index 7c6622be3c..b635757b2b 100644
--- a/doc/classes/PacketPeerUDP.xml
+++ b/doc/classes/PacketPeerUDP.xml
@@ -12,14 +12,14 @@
<methods>
<method name="bind">
<return type="int" enum="Error" />
- <argument index="0" name="port" type="int" />
- <argument index="1" name="bind_address" type="String" default="&quot;*&quot;" />
- <argument index="2" name="recv_buf_size" type="int" default="65536" />
+ <param index="0" name="port" type="int" />
+ <param index="1" name="bind_address" type="String" default="&quot;*&quot;" />
+ <param index="2" name="recv_buf_size" type="int" default="65536" />
<description>
- Binds this [PacketPeerUDP] to the specified [code]port[/code] and [code]address[/code] with a buffer size [code]recv_buf_size[/code], allowing it to receive incoming packets.
- If [code]address[/code] is set to [code]"*"[/code] (default), the peer will be bound on all available addresses (both IPv4 and IPv6).
- If [code]address[/code] is set to [code]"0.0.0.0"[/code] (for IPv4) or [code]"::"[/code] (for IPv6), the peer will be bound to all available addresses matching that IP type.
- If [code]address[/code] is set to any valid address (e.g. [code]"192.168.1.101"[/code], [code]"::1"[/code], etc), the peer will only be bound to the interface with that addresses (or fail if no interface with the given address exists).
+ Binds this [PacketPeerUDP] to the specified [param port] and [param bind_address] with a buffer size [param recv_buf_size], allowing it to receive incoming packets.
+ If [param bind_address] is set to [code]"*"[/code] (default), the peer will be bound on all available addresses (both IPv4 and IPv6).
+ If [param bind_address] is set to [code]"0.0.0.0"[/code] (for IPv4) or [code]"::"[/code] (for IPv6), the peer will be bound to all available addresses matching that IP type.
+ If [param bind_address] is set to any valid address (e.g. [code]"192.168.1.101"[/code], [code]"::1"[/code], etc), the peer will only be bound to the interface with that addresses (or fail if no interface with the given address exists).
</description>
</method>
<method name="close">
@@ -30,10 +30,10 @@
</method>
<method name="connect_to_host">
<return type="int" enum="Error" />
- <argument index="0" name="host" type="String" />
- <argument index="1" name="port" type="int" />
+ <param index="0" name="host" type="String" />
+ <param index="1" name="port" type="int" />
<description>
- Calling this method connects this UDP peer to the given [code]host[/code]/[code]port[/code] pair. UDP is in reality connectionless, so this option only means that incoming packets from different addresses are automatically discarded, and that outgoing packets are always sent to the connected address (future calls to [method set_dest_address] are not allowed). This method does not send any data to the remote peer, to do that, use [method PacketPeer.put_var] or [method PacketPeer.put_packet] as usual. See also [UDPServer].
+ Calling this method connects this UDP peer to the given [param host]/[param port] pair. UDP is in reality connectionless, so this option only means that incoming packets from different addresses are automatically discarded, and that outgoing packets are always sent to the connected address (future calls to [method set_dest_address] are not allowed). This method does not send any data to the remote peer, to do that, use [method PacketPeer.put_var] or [method PacketPeer.put_packet] as usual. See also [UDPServer].
[b]Note:[/b] Connecting to the remote peer does not help to protect from malicious attacks like IP spoofing, etc. Think about using an encryption technique like SSL or DTLS if you feel like your application is transferring sensitive information.
</description>
</method>
@@ -69,25 +69,25 @@
</method>
<method name="join_multicast_group">
<return type="int" enum="Error" />
- <argument index="0" name="multicast_address" type="String" />
- <argument index="1" name="interface_name" type="String" />
+ <param index="0" name="multicast_address" type="String" />
+ <param index="1" name="interface_name" type="String" />
<description>
- Joins the multicast group specified by [code]multicast_address[/code] using the interface identified by [code]interface_name[/code].
+ Joins the multicast group specified by [param multicast_address] using the interface identified by [param interface_name].
You can join the same multicast group with multiple interfaces. Use [method IP.get_local_interfaces] to know which are available.
[b]Note:[/b] Some Android devices might require the [code]CHANGE_WIFI_MULTICAST_STATE[/code] permission for multicast to work.
</description>
</method>
<method name="leave_multicast_group">
<return type="int" enum="Error" />
- <argument index="0" name="multicast_address" type="String" />
- <argument index="1" name="interface_name" type="String" />
+ <param index="0" name="multicast_address" type="String" />
+ <param index="1" name="interface_name" type="String" />
<description>
- Removes the interface identified by [code]interface_name[/code] from the multicast group specified by [code]multicast_address[/code].
+ Removes the interface identified by [param interface_name] from the multicast group specified by [param multicast_address].
</description>
</method>
<method name="set_broadcast_enabled">
<return type="void" />
- <argument index="0" name="enabled" type="bool" />
+ <param index="0" name="enabled" type="bool" />
<description>
Enable or disable sending of broadcast packets (e.g. [code]set_dest_address("255.255.255.255", 4343)[/code]. This option is disabled by default.
[b]Note:[/b] Some Android devices might require the [code]CHANGE_WIFI_MULTICAST_STATE[/code] permission and this option to be enabled to receive broadcast packets too.
@@ -95,8 +95,8 @@
</method>
<method name="set_dest_address">
<return type="int" enum="Error" />
- <argument index="0" name="host" type="String" />
- <argument index="1" name="port" type="int" />
+ <param index="0" name="host" type="String" />
+ <param index="1" name="port" type="int" />
<description>
Sets the destination address and port for sending packets and variables. A hostname will be resolved using DNS if needed.
[b]Note:[/b] [method set_broadcast_enabled] must be enabled before sending packets to a broadcast address (e.g. [code]255.255.255.255[/code]).
diff --git a/doc/classes/ParticlesMaterial.xml b/doc/classes/ParticleProcessMaterial.xml
index 354fbd462c..a41207e9b3 100644
--- a/doc/classes/ParticlesMaterial.xml
+++ b/doc/classes/ParticleProcessMaterial.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ParticlesMaterial" inherits="Material" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="ParticleProcessMaterial" inherits="Material" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Particle properties for [GPUParticles3D] and [GPUParticles2D] nodes.
</brief_description>
<description>
- ParticlesMaterial defines particle properties and behavior. It is used in the [code]process_material[/code] of [GPUParticles3D] and [GPUParticles2D] emitter nodes.
+ ParticleProcessMaterial defines particle properties and behavior. It is used in the [code]process_material[/code] of [GPUParticles3D] and [GPUParticles2D] emitter nodes.
Some of this material's properties are applied to each particle when emitted, while others can have a [CurveTexture] applied to vary values over the lifetime of the particle.
Particle animation is available only in [GPUParticles2D]. To use it, attach a [CanvasItemMaterial], with [member CanvasItemMaterial.particles_animation] enabled, to the particles node.
</description>
@@ -13,60 +13,60 @@
<methods>
<method name="get_param_max" qualifiers="const">
<return type="float" />
- <argument index="0" name="param" type="int" enum="ParticlesMaterial.Parameter" />
+ <param index="0" name="param" type="int" enum="ParticleProcessMaterial.Parameter" />
<description>
Returns the maximum value range for the given parameter.
</description>
</method>
<method name="get_param_min" qualifiers="const">
<return type="float" />
- <argument index="0" name="param" type="int" enum="ParticlesMaterial.Parameter" />
+ <param index="0" name="param" type="int" enum="ParticleProcessMaterial.Parameter" />
<description>
Returns the minimum value range for the given parameter.
</description>
</method>
<method name="get_param_texture" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="param" type="int" enum="ParticlesMaterial.Parameter" />
+ <param index="0" name="param" type="int" enum="ParticleProcessMaterial.Parameter" />
<description>
Returns the [Texture2D] used by the specified parameter.
</description>
</method>
<method name="get_particle_flag" qualifiers="const">
<return type="bool" />
- <argument index="0" name="particle_flag" type="int" enum="ParticlesMaterial.ParticleFlags" />
+ <param index="0" name="particle_flag" type="int" enum="ParticleProcessMaterial.ParticleFlags" />
<description>
Returns [code]true[/code] if the specified particle flag is enabled. See [enum ParticleFlags] for options.
</description>
</method>
<method name="set_param_max">
<return type="void" />
- <argument index="0" name="param" type="int" enum="ParticlesMaterial.Parameter" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="param" type="int" enum="ParticleProcessMaterial.Parameter" />
+ <param index="1" name="value" type="float" />
<description>
Sets the maximum value range for the given parameter.
</description>
</method>
<method name="set_param_min">
<return type="void" />
- <argument index="0" name="param" type="int" enum="ParticlesMaterial.Parameter" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="param" type="int" enum="ParticleProcessMaterial.Parameter" />
+ <param index="1" name="value" type="float" />
<description>
Sets the minimum value range for the given parameter.
</description>
</method>
<method name="set_param_texture">
<return type="void" />
- <argument index="0" name="param" type="int" enum="ParticlesMaterial.Parameter" />
- <argument index="1" name="texture" type="Texture2D" />
+ <param index="0" name="param" type="int" enum="ParticleProcessMaterial.Parameter" />
+ <param index="1" name="texture" type="Texture2D" />
<description>
Sets the [Texture2D] for the specified [enum Parameter].
</description>
</method>
<method name="set_particle_flag">
<return type="void" />
- <argument index="0" name="particle_flag" type="int" enum="ParticlesMaterial.ParticleFlags" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="particle_flag" type="int" enum="ParticleProcessMaterial.ParticleFlags" />
+ <param index="1" name="enable" type="bool" />
<description>
If [code]true[/code], enables the specified particle flag. See [enum ParticleFlags] for options.
</description>
@@ -115,26 +115,30 @@
<member name="attractor_interaction_enabled" type="bool" setter="set_attractor_interaction_enabled" getter="is_attractor_interaction_enabled" default="true">
True if the interaction with particle attractors is enabled.
</member>
- <member name="collision_bounce" type="float" setter="set_collision_bounce" getter="get_collision_bounce" default="0.0">
- Collision bounciness.
+ <member name="collision_bounce" type="float" setter="set_collision_bounce" getter="get_collision_bounce">
+ The particles' bounciness. Values range from [code]0[/code] (no bounce) to [code]1[/code] (full bounciness). Only effective if [member collision_mode] is [constant COLLISION_RIGID].
</member>
- <member name="collision_enabled" type="bool" setter="set_collision_enabled" getter="is_collision_enabled" default="false">
- True if collisions are enabled for this particle system.
+ <member name="collision_friction" type="float" setter="set_collision_friction" getter="get_collision_friction">
+ The particles' friction. Values range from [code]0[/code] (frictionless) to [code]1[/code] (maximum friction). Only effective if [member collision_mode] is [constant COLLISION_RIGID].
</member>
- <member name="collision_friction" type="float" setter="set_collision_friction" getter="get_collision_friction" default="0.0">
- Collision friction.
+ <member name="collision_mode" type="int" setter="set_collision_mode" getter="get_collision_mode" enum="ParticleProcessMaterial.CollisionMode" default="0">
+ The particles' collision mode.
+ [b]Note:[/b] Particles can only collide with [GPUParticlesCollision3D] nodes, not [PhysicsBody3D] nodes. To make particles collide with various objects, you can add [GPUParticlesCollision3D] nodes as children of [PhysicsBody3D] nodes.
</member>
<member name="collision_use_scale" type="bool" setter="set_collision_use_scale" getter="is_collision_using_scale" default="false">
Should collision take scale into account.
</member>
<member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)">
- Each particle's initial color. If the [GPUParticles2D]'s [code]texture[/code] is defined, it will be multiplied by this color. To have particle display color in a [BaseMaterial3D] make sure to set [member BaseMaterial3D.vertex_color_use_as_albedo] to [code]true[/code].
+ Each particle's initial color. If the [GPUParticles2D]'s [code]texture[/code] is defined, it will be multiplied by this color.
+ [b]Note:[/b] [member color] multiplies the particle mesh's vertex colors. To have a visible effect on a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] [i]must[/i] be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/code] must be inserted in the shader's [code]fragment()[/code] function. Otherwise, [member color] will have no visible effect.
</member>
<member name="color_initial_ramp" type="Texture2D" setter="set_color_initial_ramp" getter="get_color_initial_ramp">
Each particle's initial color will vary along this [GradientTexture1D] (multiplied with [member color]).
+ [b]Note:[/b] [member color_initial_ramp] multiplies the particle mesh's vertex colors. To have a visible effect on a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] [i]must[/i] be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/code] must be inserted in the shader's [code]fragment()[/code] function. Otherwise, [member color_initial_ramp] will have no visible effect.
</member>
<member name="color_ramp" type="Texture2D" setter="set_color_ramp" getter="get_color_ramp">
Each particle's color will vary along this [GradientTexture1D] over its lifetime (multiplied with [member color]).
+ [b]Note:[/b] [member color_ramp] multiplies the particle mesh's vertex colors. To have a visible effect on a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] [i]must[/i] be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/code] must be inserted in the shader's [code]fragment()[/code] function. Otherwise, [member color_ramp] will have no visible effect.
</member>
<member name="damping_curve" type="Texture2D" setter="set_param_texture" getter="get_param_texture">
Damping will vary along this [CurveTexture].
@@ -153,6 +157,7 @@
</member>
<member name="emission_color_texture" type="Texture2D" setter="set_emission_color_texture" getter="get_emission_color_texture">
Particle color will be modulated by color determined by sampling this texture at the same point as the [member emission_point_texture].
+ [b]Note:[/b] [member emission_color_texture] multiplies the particle mesh's vertex colors. To have a visible effect on a [BaseMaterial3D], [member BaseMaterial3D.vertex_color_use_as_albedo] [i]must[/i] be [code]true[/code]. For a [ShaderMaterial], [code]ALBEDO *= COLOR.rgb;[/code] must be inserted in the shader's [code]fragment()[/code] function. Otherwise, [member emission_color_texture] will have no visible effect.
</member>
<member name="emission_normal_texture" type="Texture2D" setter="set_emission_normal_texture" getter="get_emission_normal_texture">
Particle velocity and rotation will be set by sampling this texture at the same point as the [member emission_point_texture]. Used only in [constant EMISSION_SHAPE_DIRECTED_POINTS]. Can be created automatically from mesh or node by selecting "Create Emission Points from Mesh/Node" under the "Particles" tool in the toolbar.
@@ -175,7 +180,7 @@
<member name="emission_ring_radius" type="float" setter="set_emission_ring_radius" getter="get_emission_ring_radius">
The radius of the ring when using the emitter [constant EMISSION_SHAPE_RING].
</member>
- <member name="emission_shape" type="int" setter="set_emission_shape" getter="get_emission_shape" enum="ParticlesMaterial.EmissionShape" default="0">
+ <member name="emission_shape" type="int" setter="set_emission_shape" getter="get_emission_shape" enum="ParticleProcessMaterial.EmissionShape" default="0">
Particles will be emitted inside this region. Use [enum EmissionShape] constants for values.
</member>
<member name="emission_sphere_radius" type="float" setter="set_emission_sphere_radius" getter="get_emission_sphere_radius">
@@ -260,7 +265,7 @@
</member>
<member name="sub_emitter_keep_velocity" type="bool" setter="set_sub_emitter_keep_velocity" getter="get_sub_emitter_keep_velocity" default="false">
</member>
- <member name="sub_emitter_mode" type="int" setter="set_sub_emitter_mode" getter="get_sub_emitter_mode" enum="ParticlesMaterial.SubEmitterMode" default="0">
+ <member name="sub_emitter_mode" type="int" setter="set_sub_emitter_mode" getter="get_sub_emitter_mode" enum="ParticleProcessMaterial.SubEmitterMode" default="0">
</member>
<member name="tangential_accel_curve" type="Texture2D" setter="set_param_texture" getter="get_param_texture">
Each particle's tangential acceleration will vary along this [CurveTexture].
@@ -271,6 +276,42 @@
<member name="tangential_accel_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
Minimum equivalent of [member tangential_accel_max].
</member>
+ <member name="turbulence_enabled" type="bool" setter="set_turbulence_enabled" getter="get_turbulence_enabled" default="false">
+ Enables and disables Turbulence for the particle system.
+ </member>
+ <member name="turbulence_influence_max" type="float" setter="set_param_max" getter="get_param_max" default="0.1">
+ Minimum turbulence influence on each particle.
+ The actual amount of turbulence influence on each particle is calculated as a random value between [member turbulence_influence_min] and [member turbulence_influence_max] and multiplied by the amount of turbulence influence from [member turbulence_influence_over_life].
+ </member>
+ <member name="turbulence_influence_min" type="float" setter="set_param_min" getter="get_param_min" default="0.1">
+ Maximum turbulence influence on each particle.
+ The actual amount of turbulence influence on each particle is calculated as a random value between [member turbulence_influence_min] and [member turbulence_influence_max] and multiplied by the amount of turbulence influence from [member turbulence_influence_over_life].
+ </member>
+ <member name="turbulence_influence_over_life" type="Texture2D" setter="set_param_texture" getter="get_param_texture">
+ Each particle's amount of turbulence will be influenced along this [CurveTexture] over its life time.
+ </member>
+ <member name="turbulence_initial_displacement_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0">
+ Maximum displacement of each particles spawn position by the turbulence.
+ The actual amount of displacement will be a factor of the underlying turbulence multiplied by a random value between [member turbulence_initial_displacement_min] and [member turbulence_initial_displacement_max].
+ </member>
+ <member name="turbulence_initial_displacement_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
+ Minimum displacement of each particles spawn position by the turbulence.
+ The actual amount of displacement will be a factor of the underlying turbulence multiplied by a random value between [member turbulence_initial_displacement_min] and [member turbulence_initial_displacement_max].
+ </member>
+ <member name="turbulence_noise_scale" type="float" setter="set_turbulence_noise_scale" getter="get_turbulence_noise_scale" default="9.0">
+ This value controls the overall scale/frequency of the turbulence noise pattern.
+ A small scale will result in smaller features with more detail while a high scale will result in smoother noise with larger features.
+ </member>
+ <member name="turbulence_noise_speed" type="Vector3" setter="set_turbulence_noise_speed" getter="get_turbulence_noise_speed" default="Vector3(0.5, 0.5, 0.5)">
+ The movement speed of the turbulence pattern. This changes how quickly the noise changes over time.
+ A value of [code]Vector3(0.0, 0.0, 0.0)[/code] will freeze the turbulence pattern in place.
+ </member>
+ <member name="turbulence_noise_speed_random" type="float" setter="set_turbulence_noise_speed_random" getter="get_turbulence_noise_speed_random" default="0.0">
+ Use to influence the noise speed in a random pattern. This helps to break up visible movement patterns.
+ </member>
+ <member name="turbulence_noise_strength" type="float" setter="set_turbulence_noise_strength" getter="get_turbulence_noise_strength" default="1.0">
+ The turbulence noise strength. Increasing this will result in a stronger, more contrasting, noise pattern.
+ </member>
</members>
<constants>
<constant name="PARAM_INITIAL_LINEAR_VELOCITY" value="0" enum="Parameter">
@@ -309,7 +350,7 @@
<constant name="PARAM_ANIM_OFFSET" value="11" enum="Parameter">
Use with [method set_param_min], [method set_param_max], and [method set_param_texture] to set animation offset properties.
</constant>
- <constant name="PARAM_MAX" value="12" enum="Parameter">
+ <constant name="PARAM_MAX" value="15" enum="Parameter">
Represents the size of the [enum Parameter] enum.
</constant>
<constant name="PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY" value="0" enum="ParticleFlags">
@@ -348,6 +389,15 @@
<constant name="EMISSION_SHAPE_MAX" value="7" enum="EmissionShape">
Represents the size of the [enum EmissionShape] enum.
</constant>
+ <constant name="PARAM_TURB_VEL_INFLUENCE" value="13" enum="Parameter">
+ Use with [method set_param_min] and [method set_param_max] to set the turbulence minimum und maximum influence on each particles velocity.
+ </constant>
+ <constant name="PARAM_TURB_INIT_DISPLACEMENT" value="14" enum="Parameter">
+ Use with [method set_param_min] and [method set_param_max] to set the turbulence minimum and maximum displacement of the particles spawn position.
+ </constant>
+ <constant name="PARAM_TURB_INFLUENCE_OVER_LIFE" value="12" enum="Parameter">
+ Use with [method set_param_texture] to set the turbulence influence over the particles life time.
+ </constant>
<constant name="SUB_EMITTER_DISABLED" value="0" enum="SubEmitterMode">
</constant>
<constant name="SUB_EMITTER_CONSTANT" value="1" enum="SubEmitterMode">
@@ -357,6 +407,19 @@
<constant name="SUB_EMITTER_AT_COLLISION" value="3" enum="SubEmitterMode">
</constant>
<constant name="SUB_EMITTER_MAX" value="4" enum="SubEmitterMode">
+ Represents the size of the [enum SubEmitterMode] enum.
+ </constant>
+ <constant name="COLLISION_DISABLED" value="0" enum="CollisionMode">
+ No collision for particles. Particles will go through [GPUParticlesCollision3D] nodes.
+ </constant>
+ <constant name="COLLISION_RIGID" value="1" enum="CollisionMode">
+ [RigidBody3D]-style collision for particles using [GPUParticlesCollision3D] nodes.
+ </constant>
+ <constant name="COLLISION_HIDE_ON_CONTACT" value="2" enum="CollisionMode">
+ Hide particles instantly when colliding with a [GPUParticlesCollision3D] node. This can be combined with a subemitter that uses the [constant COLLISION_RIGID] collision mode to "replace" the parent particle with the subemitter on impact.
+ </constant>
+ <constant name="COLLISION_MAX" value="3" enum="CollisionMode">
+ Represents the size of the [enum CollisionMode] enum.
</constant>
</constants>
</class>
diff --git a/doc/classes/PathFollow2D.xml b/doc/classes/PathFollow2D.xml
index ae4a4b2886..09d6872e10 100644
--- a/doc/classes/PathFollow2D.xml
+++ b/doc/classes/PathFollow2D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
This node takes its parent [Path2D], and returns the coordinates of a point within it, given a distance from the first vertex.
- It is useful for making other nodes follow a path, without coding the movement pattern. For that, the nodes must be children of this node. The descendant nodes will then move accordingly when setting an offset in this node.
+ It is useful for making other nodes follow a path, without coding the movement pattern. For that, the nodes must be children of this node. The descendant nodes will then move accordingly when setting the [member progress] in this node.
</description>
<tutorials>
</tutorials>
@@ -24,15 +24,15 @@
<member name="loop" type="bool" setter="set_loop" getter="has_loop" default="true">
If [code]true[/code], any offset outside the path's length will wrap around, instead of stopping at the ends. Use it for cyclic paths.
</member>
- <member name="offset" type="float" setter="set_offset" getter="get_offset" default="0.0">
- The distance along the path in pixels.
+ <member name="progress" type="float" setter="set_progress" getter="get_progress" default="0.0">
+ The distance along the path, in pixels. Changing this value sets this node's position to a point within the path.
+ </member>
+ <member name="progress_ratio" type="float" setter="set_progress_ratio" getter="get_progress_ratio" default="0.0">
+ The distance along the path as a number in the range 0.0 (for the first vertex) to 1.0 (for the last). This is just another way of expressing the progress within the path, as the offset supplied is multiplied internally by the path's length.
</member>
<member name="rotates" type="bool" setter="set_rotates" getter="is_rotating" default="true">
If [code]true[/code], this node rotates to follow the path, with the +X direction facing forward on the path.
</member>
- <member name="unit_offset" type="float" setter="set_unit_offset" getter="get_unit_offset" default="0.0">
- The distance along the path as a number in the range 0.0 (for the first vertex) to 1.0 (for the last). This is just another way of expressing the offset within the path, as the offset supplied is multiplied internally by the path's length.
- </member>
<member name="v_offset" type="float" setter="set_v_offset" getter="get_v_offset" default="0.0">
The node's offset perpendicular to the curve.
</member>
diff --git a/doc/classes/PathFollow3D.xml b/doc/classes/PathFollow3D.xml
index f9fab07be5..ba7207be8f 100644
--- a/doc/classes/PathFollow3D.xml
+++ b/doc/classes/PathFollow3D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
This node takes its parent [Path3D], and returns the coordinates of a point within it, given a distance from the first vertex.
- It is useful for making other nodes follow a path, without coding the movement pattern. For that, the nodes must be children of this node. The descendant nodes will then move accordingly when setting an offset in this node.
+ It is useful for making other nodes follow a path, without coding the movement pattern. For that, the nodes must be children of this node. The descendant nodes will then move accordingly when setting the [member progress] in this node.
</description>
<tutorials>
</tutorials>
@@ -21,15 +21,15 @@
<member name="loop" type="bool" setter="set_loop" getter="has_loop" default="true">
If [code]true[/code], any offset outside the path's length will wrap around, instead of stopping at the ends. Use it for cyclic paths.
</member>
- <member name="offset" type="float" setter="set_offset" getter="get_offset" default="0.0">
- The distance from the first vertex, measured in 3D units along the path. This sets this node's position to a point within the path.
+ <member name="progress" type="float" setter="set_progress" getter="get_progress" default="0.0">
+ The distance from the first vertex, measured in 3D units along the path. Changing this value sets this node's position to a point within the path.
+ </member>
+ <member name="progress_ratio" type="float" setter="set_progress_ratio" getter="get_progress_ratio" default="0.0">
+ The distance from the first vertex, considering 0.0 as the first vertex and 1.0 as the last. This is just another way of expressing the progress within the path, as the progress supplied is multiplied internally by the path's length.
</member>
<member name="rotation_mode" type="int" setter="set_rotation_mode" getter="get_rotation_mode" enum="PathFollow3D.RotationMode" default="3">
Allows or forbids rotation on one or more axes, depending on the [enum RotationMode] constants being used.
</member>
- <member name="unit_offset" type="float" setter="set_unit_offset" getter="get_unit_offset" default="0.0">
- The distance from the first vertex, considering 0.0 as the first vertex and 1.0 as the last. This is just another way of expressing the offset within the path, as the offset supplied is multiplied internally by the path's length.
- </member>
<member name="v_offset" type="float" setter="set_v_offset" getter="get_v_offset" default="0.0">
The node's offset perpendicular to the curve.
</member>
diff --git a/doc/classes/Performance.xml b/doc/classes/Performance.xml
index 01da9cb9a2..381fa3e9ef 100644
--- a/doc/classes/Performance.xml
+++ b/doc/classes/Performance.xml
@@ -15,11 +15,11 @@
<methods>
<method name="add_custom_monitor">
<return type="void" />
- <argument index="0" name="id" type="StringName" />
- <argument index="1" name="callable" type="Callable" />
- <argument index="2" name="arguments" type="Array" default="[]" />
+ <param index="0" name="id" type="StringName" />
+ <param index="1" name="callable" type="Callable" />
+ <param index="2" name="arguments" type="Array" default="[]" />
<description>
- Adds a custom monitor with the name [code]id[/code]. You can specify the category of the monitor using slash delimiters in [code]id[/code] (for example: [code]"Game/NumberOfNPCs"[/code]). If there is more than one slash delimiter, then the default category is used. The default category is [code]"Custom"[/code]. Prints an error if given [code]id[/code] is already present.
+ Adds a custom monitor with the name [param id]. You can specify the category of the monitor using slash delimiters in [param id] (for example: [code]"Game/NumberOfNPCs"[/code]). If there is more than one slash delimiter, then the default category is used. The default category is [code]"Custom"[/code]. Prints an error if given [param id] is already present.
[codeblocks]
[gdscript]
func _ready():
@@ -73,20 +73,20 @@
</method>
<method name="get_custom_monitor">
<return type="Variant" />
- <argument index="0" name="id" type="StringName" />
+ <param index="0" name="id" type="StringName" />
<description>
- Returns the value of custom monitor with given [code]id[/code]. The callable is called to get the value of custom monitor. See also [method has_custom_monitor]. Prints an error if the given [code]id[/code] is absent.
+ Returns the value of custom monitor with given [param id]. The callable is called to get the value of custom monitor. See also [method has_custom_monitor]. Prints an error if the given [param id] is absent.
</description>
</method>
<method name="get_custom_monitor_names">
- <return type="Array" />
+ <return type="StringName[]" />
<description>
Returns the names of active custom monitors in an [Array].
</description>
</method>
<method name="get_monitor" qualifiers="const">
<return type="float" />
- <argument index="0" name="monitor" type="int" enum="Performance.Monitor" />
+ <param index="0" name="monitor" type="int" enum="Performance.Monitor" />
<description>
Returns the value of one of the available built-in monitors. You should provide one of the [enum Monitor] constants as the argument, like this:
[codeblocks]
@@ -108,16 +108,16 @@
</method>
<method name="has_custom_monitor">
<return type="bool" />
- <argument index="0" name="id" type="StringName" />
+ <param index="0" name="id" type="StringName" />
<description>
- Returns [code]true[/code] if custom monitor with the given [code]id[/code] is present, [code]false[/code] otherwise.
+ Returns [code]true[/code] if custom monitor with the given [param id] is present, [code]false[/code] otherwise.
</description>
</method>
<method name="remove_custom_monitor">
<return type="void" />
- <argument index="0" name="id" type="StringName" />
+ <param index="0" name="id" type="StringName" />
<description>
- Removes the custom monitor with given [code]id[/code]. Prints an error if the given [code]id[/code] is already absent.
+ Removes the custom monitor with given [param id]. Prints an error if the given [param id] is already absent.
</description>
</method>
</methods>
@@ -171,7 +171,7 @@
The amount of render buffer memory used (in bytes). [i]Lower is better.[/i]
</constant>
<constant name="PHYSICS_2D_ACTIVE_OBJECTS" value="16" enum="Monitor">
- Number of active [RigidDynamicBody2D] nodes in the game. [i]Lower is better.[/i]
+ Number of active [RigidBody2D] nodes in the game. [i]Lower is better.[/i]
</constant>
<constant name="PHYSICS_2D_COLLISION_PAIRS" value="17" enum="Monitor">
Number of collision pairs in the 2D physics engine. [i]Lower is better.[/i]
@@ -180,7 +180,7 @@
Number of islands in the 2D physics engine. [i]Lower is better.[/i]
</constant>
<constant name="PHYSICS_3D_ACTIVE_OBJECTS" value="19" enum="Monitor">
- Number of active [RigidDynamicBody3D] and [VehicleBody3D] nodes in the game. [i]Lower is better.[/i]
+ Number of active [RigidBody3D] and [VehicleBody3D] nodes in the game. [i]Lower is better.[/i]
</constant>
<constant name="PHYSICS_3D_COLLISION_PAIRS" value="20" enum="Monitor">
Number of collision pairs in the 3D physics engine. [i]Lower is better.[/i]
diff --git a/doc/classes/PhysicalBone2D.xml b/doc/classes/PhysicalBone2D.xml
index 738568ed03..26fce1a90b 100644
--- a/doc/classes/PhysicalBone2D.xml
+++ b/doc/classes/PhysicalBone2D.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicalBone2D" inherits="RigidDynamicBody2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="PhysicalBone2D" inherits="RigidBody2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A 2D node that can be used for physically aware bones in 2D.
</brief_description>
<description>
- The [code]PhysicalBone2D[/code] node is a [RigidDynamicBody2D]-based node that can be used to make [Bone2D] nodes in a [Skeleton2D] react to physics. This node is very similar to the [PhysicalBone3D] node, just for 2D instead of 3D.
+ The [code]PhysicalBone2D[/code] node is a [RigidBody2D]-based node that can be used to make [Bone2D] nodes in a [Skeleton2D] react to physics. This node is very similar to the [PhysicalBone3D] node, just for 2D instead of 3D.
[b]Note:[/b] To have the Bone2D nodes visually follow the [code]PhysicalBone2D[/code] node, use a [SkeletonModification2DPhysicalBones] modification on the [Skeleton2D] node with the [Bone2D] nodes.
[b]Note:[/b] The PhysicalBone2D node does not automatically create a [Joint2D] node to keep [code]PhysicalBone2D[/code] nodes together. You will need to create these manually. For most cases, you want to use a [PinJoint2D] node. The [code]PhysicalBone2D[/code] node can automatically configure the [Joint2D] node once it's been created as a child node.
</description>
diff --git a/doc/classes/PhysicalBone3D.xml b/doc/classes/PhysicalBone3D.xml
index 7e8cc91766..0768df31cc 100644
--- a/doc/classes/PhysicalBone3D.xml
+++ b/doc/classes/PhysicalBone3D.xml
@@ -9,21 +9,21 @@
<methods>
<method name="_integrate_forces" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="state" type="PhysicsDirectBodyState3D" />
+ <param index="0" name="state" type="PhysicsDirectBodyState3D" />
<description>
Called during physics processing, allowing you to read and safely modify the simulation state for the object. By default, it works in addition to the usual physics behavior, but the [member custom_integrator] property allows you to disable the default behavior and do fully custom force integration for a body.
</description>
</method>
<method name="apply_central_impulse">
<return type="void" />
- <argument index="0" name="impulse" type="Vector3" />
+ <param index="0" name="impulse" type="Vector3" />
<description>
</description>
</method>
<method name="apply_impulse">
<return type="void" />
- <argument index="0" name="impulse" type="Vector3" />
- <argument index="1" name="position" type="Vector3" default="Vector3(0, 0, 0)" />
+ <param index="0" name="impulse" type="Vector3" />
+ <param index="1" name="position" type="Vector3" default="Vector3(0, 0, 0)" />
<description>
</description>
</method>
diff --git a/doc/classes/PhysicsBody2D.xml b/doc/classes/PhysicsBody2D.xml
index 9cebd68d76..e8d7ac9920 100644
--- a/doc/classes/PhysicsBody2D.xml
+++ b/doc/classes/PhysicsBody2D.xml
@@ -12,7 +12,7 @@
<methods>
<method name="add_collision_exception_with">
<return type="void" />
- <argument index="0" name="body" type="Node" />
+ <param index="0" name="body" type="Node" />
<description>
Adds a body to the list of bodies that this body can't collide with.
</description>
@@ -25,34 +25,34 @@
</method>
<method name="move_and_collide">
<return type="KinematicCollision2D" />
- <argument index="0" name="distance" type="Vector2" />
- <argument index="1" name="test_only" type="bool" default="false" />
- <argument index="2" name="safe_margin" type="float" default="0.08" />
+ <param index="0" name="distance" type="Vector2" />
+ <param index="1" name="test_only" type="bool" default="false" />
+ <param index="2" name="safe_margin" type="float" default="0.08" />
<description>
- Moves the body along the vector [code]distance[/code]. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [code]distance[/code] should be computed using [code]delta[/code].
+ Moves the body along the vector [param distance]. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param distance] should be computed using [code]delta[/code].
Returns a [KinematicCollision2D], which contains information about the collision when stopped, or when touching another body along the motion.
- If [code]test_only[/code] is [code]true[/code], the body does not move but the would-be collision information is given.
- [code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody2D.collision/safe_margin] for more details).
+ If [param test_only] is [code]true[/code], the body does not move but the would-be collision information is given.
+ [param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody2D.safe_margin] for more details).
</description>
</method>
<method name="remove_collision_exception_with">
<return type="void" />
- <argument index="0" name="body" type="Node" />
+ <param index="0" name="body" type="Node" />
<description>
Removes a body from the list of bodies that this body can't collide with.
</description>
</method>
<method name="test_move">
<return type="bool" />
- <argument index="0" name="from" type="Transform2D" />
- <argument index="1" name="distance" type="Vector2" />
- <argument index="2" name="collision" type="KinematicCollision2D" default="null" />
- <argument index="3" name="safe_margin" type="float" default="0.08" />
+ <param index="0" name="from" type="Transform2D" />
+ <param index="1" name="distance" type="Vector2" />
+ <param index="2" name="collision" type="KinematicCollision2D" default="null" />
+ <param index="3" name="safe_margin" type="float" default="0.08" />
<description>
- Checks for collisions without moving the body. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [code]distance[/code] should be computed using [code]delta[/code].
- Virtually sets the node's position, scale and rotation to that of the given [Transform2D], then tries to move the body along the vector [code]distance[/code]. Returns [code]true[/code] if a collision would stop the body from moving along the whole path.
- [code]collision[/code] is an optional object of type [KinematicCollision2D], which contains additional information about the collision when stopped, or when touching another body along the motion.
- [code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody2D.collision/safe_margin] for more details).
+ Checks for collisions without moving the body. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param distance] should be computed using [code]delta[/code].
+ Virtually sets the node's position, scale and rotation to that of the given [Transform2D], then tries to move the body along the vector [param distance]. Returns [code]true[/code] if a collision would stop the body from moving along the whole path.
+ [param collision] is an optional object of type [KinematicCollision2D], which contains additional information about the collision when stopped, or when touching another body along the motion.
+ [param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody2D.safe_margin] for more details).
</description>
</method>
</methods>
diff --git a/doc/classes/PhysicsBody3D.xml b/doc/classes/PhysicsBody3D.xml
index 843f813997..310671274f 100644
--- a/doc/classes/PhysicsBody3D.xml
+++ b/doc/classes/PhysicsBody3D.xml
@@ -12,16 +12,16 @@
<methods>
<method name="add_collision_exception_with">
<return type="void" />
- <argument index="0" name="body" type="Node" />
+ <param index="0" name="body" type="Node" />
<description>
Adds a body to the list of bodies that this body can't collide with.
</description>
</method>
<method name="get_axis_lock" qualifiers="const">
<return type="bool" />
- <argument index="0" name="axis" type="int" enum="PhysicsServer3D.BodyAxis" />
+ <param index="0" name="axis" type="int" enum="PhysicsServer3D.BodyAxis" />
<description>
- Returns [code]true[/code] if the specified linear or rotational [code]axis[/code] is locked.
+ Returns [code]true[/code] if the specified linear or rotational [param axis] is locked.
</description>
</method>
<method name="get_collision_exceptions">
@@ -32,46 +32,46 @@
</method>
<method name="move_and_collide">
<return type="KinematicCollision3D" />
- <argument index="0" name="distance" type="Vector3" />
- <argument index="1" name="test_only" type="bool" default="false" />
- <argument index="2" name="safe_margin" type="float" default="0.001" />
- <argument index="3" name="max_collisions" type="int" default="1" />
+ <param index="0" name="distance" type="Vector3" />
+ <param index="1" name="test_only" type="bool" default="false" />
+ <param index="2" name="safe_margin" type="float" default="0.001" />
+ <param index="3" name="max_collisions" type="int" default="1" />
<description>
- Moves the body along the vector [code]distance[/code]. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [code]distance[/code] should be computed using [code]delta[/code].
+ Moves the body along the vector [param distance]. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param distance] should be computed using [code]delta[/code].
The body will stop if it collides. Returns a [KinematicCollision3D], which contains information about the collision when stopped, or when touching another body along the motion.
- If [code]test_only[/code] is [code]true[/code], the body does not move but the would-be collision information is given.
- [code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody3D.collision/safe_margin] for more details).
- [code]max_collisions[/code] allows to retrieve more than one collision result.
+ If [param test_only] is [code]true[/code], the body does not move but the would-be collision information is given.
+ [param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody3D.safe_margin] for more details).
+ [param max_collisions] allows to retrieve more than one collision result.
</description>
</method>
<method name="remove_collision_exception_with">
<return type="void" />
- <argument index="0" name="body" type="Node" />
+ <param index="0" name="body" type="Node" />
<description>
Removes a body from the list of bodies that this body can't collide with.
</description>
</method>
<method name="set_axis_lock">
<return type="void" />
- <argument index="0" name="axis" type="int" enum="PhysicsServer3D.BodyAxis" />
- <argument index="1" name="lock" type="bool" />
+ <param index="0" name="axis" type="int" enum="PhysicsServer3D.BodyAxis" />
+ <param index="1" name="lock" type="bool" />
<description>
- Locks or unlocks the specified linear or rotational [code]axis[/code] depending on the value of [code]lock[/code].
+ Locks or unlocks the specified linear or rotational [param axis] depending on the value of [param lock].
</description>
</method>
<method name="test_move">
<return type="bool" />
- <argument index="0" name="from" type="Transform3D" />
- <argument index="1" name="distance" type="Vector3" />
- <argument index="2" name="collision" type="KinematicCollision3D" default="null" />
- <argument index="3" name="safe_margin" type="float" default="0.001" />
- <argument index="4" name="max_collisions" type="int" default="1" />
+ <param index="0" name="from" type="Transform3D" />
+ <param index="1" name="distance" type="Vector3" />
+ <param index="2" name="collision" type="KinematicCollision3D" default="null" />
+ <param index="3" name="safe_margin" type="float" default="0.001" />
+ <param index="4" name="max_collisions" type="int" default="1" />
<description>
- Checks for collisions without moving the body. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [code]distance[/code] should be computed using [code]delta[/code].
- Virtually sets the node's position, scale and rotation to that of the given [Transform3D], then tries to move the body along the vector [code]distance[/code]. Returns [code]true[/code] if a collision would stop the body from moving along the whole path.
- [code]collision[/code] is an optional object of type [KinematicCollision3D], which contains additional information about the collision when stopped, or when touching another body along the motion.
- [code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody3D.collision/safe_margin] for more details).
- [code]max_collisions[/code] allows to retrieve more than one collision result.
+ Checks for collisions without moving the body. In order to be frame rate independent in [method Node._physics_process] or [method Node._process], [param distance] should be computed using [code]delta[/code].
+ Virtually sets the node's position, scale and rotation to that of the given [Transform3D], then tries to move the body along the vector [param distance]. Returns [code]true[/code] if a collision would stop the body from moving along the whole path.
+ [param collision] is an optional object of type [KinematicCollision3D], which contains additional information about the collision when stopped, or when touching another body along the motion.
+ [param safe_margin] is the extra margin used for collision recovery (see [member CharacterBody3D.safe_margin] for more details).
+ [param max_collisions] allows to retrieve more than one collision result.
</description>
</method>
</methods>
diff --git a/doc/classes/PhysicsDirectBodyState2D.xml b/doc/classes/PhysicsDirectBodyState2D.xml
index 783b0488d8..fdc3a44e9d 100644
--- a/doc/classes/PhysicsDirectBodyState2D.xml
+++ b/doc/classes/PhysicsDirectBodyState2D.xml
@@ -4,7 +4,7 @@
Direct access object to a physics body in the [PhysicsServer2D].
</brief_description>
<description>
- 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 dynamic bodies, and is intended for changing the direct state of that body. See [method RigidDynamicBody2D._integrate_forces].
+ 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 bodies, and is intended for changing the direct state of that body. See [method RigidBody2D._integrate_forces].
</description>
<tutorials>
<link title="Physics introduction">$DOCS_URL/tutorials/physics/physics_introduction.html</link>
@@ -13,7 +13,7 @@
<methods>
<method name="add_constant_central_force">
<return type="void" />
- <argument index="0" name="force" type="Vector2" default="Vector2(0, 0)" />
+ <param index="0" name="force" type="Vector2" default="Vector2(0, 0)" />
<description>
Adds a constant directional force without affecting rotation that keeps being applied over time until cleared with [code]constant_force = Vector2(0, 0)[/code].
This is equivalent to using [method add_constant_force] at the body's center of mass.
@@ -21,23 +21,23 @@
</method>
<method name="add_constant_force">
<return type="void" />
- <argument index="0" name="force" type="Vector2" />
- <argument index="1" name="position" type="Vector2" default="Vector2(0, 0)" />
+ <param index="0" name="force" type="Vector2" />
+ <param index="1" name="position" type="Vector2" default="Vector2(0, 0)" />
<description>
Adds a constant positioned force to the body that keeps being applied over time until cleared with [code]constant_force = Vector2(0, 0)[/code].
- [code]position[/code] is the offset from the body origin in global coordinates.
+ [param position] is the offset from the body origin in global coordinates.
</description>
</method>
<method name="add_constant_torque">
<return type="void" />
- <argument index="0" name="torque" type="float" />
+ <param index="0" name="torque" type="float" />
<description>
Adds a constant rotational force without affecting position that keeps being applied over time until cleared with [code]constant_torque = 0[/code].
</description>
</method>
<method name="apply_central_force">
<return type="void" />
- <argument index="0" name="force" type="Vector2" default="Vector2(0, 0)" />
+ <param index="0" name="force" type="Vector2" default="Vector2(0, 0)" />
<description>
Applies a directional force without affecting rotation. A force is time dependent and meant to be applied every physics update.
This is equivalent to using [method apply_force] at the body's center of mass.
@@ -45,7 +45,7 @@
</method>
<method name="apply_central_impulse">
<return type="void" />
- <argument index="0" name="impulse" type="Vector2" />
+ <param index="0" name="impulse" type="Vector2" />
<description>
Applies a directional impulse without affecting rotation.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
@@ -54,33 +54,33 @@
</method>
<method name="apply_force">
<return type="void" />
- <argument index="0" name="force" type="Vector2" />
- <argument index="1" name="position" type="Vector2" default="Vector2(0, 0)" />
+ <param index="0" name="force" type="Vector2" />
+ <param index="1" name="position" type="Vector2" default="Vector2(0, 0)" />
<description>
Applies a positioned force to the body. A force is time dependent and meant to be applied every physics update.
- [code]position[/code] is the offset from the body origin in global coordinates.
+ [param position] is the offset from the body origin in global coordinates.
</description>
</method>
<method name="apply_impulse">
<return type="void" />
- <argument index="0" name="impulse" type="Vector2" />
- <argument index="1" name="position" type="Vector2" default="Vector2(0, 0)" />
+ <param index="0" name="impulse" type="Vector2" />
+ <param index="1" name="position" type="Vector2" default="Vector2(0, 0)" />
<description>
Applies a positioned impulse to the body.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
- [code]position[/code] is the offset from the body origin in global coordinates.
+ [param position] is the offset from the body origin in global coordinates.
</description>
</method>
<method name="apply_torque">
<return type="void" />
- <argument index="0" name="torque" type="float" />
+ <param index="0" name="torque" type="float" />
<description>
Applies a rotational force without affecting position. A force is time dependent and meant to be applied every physics update.
</description>
</method>
<method name="apply_torque_impulse">
<return type="void" />
- <argument index="0" name="impulse" type="float" />
+ <param index="0" name="impulse" type="float" />
<description>
Applies a rotational impulse to the body without affecting the position.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
@@ -102,42 +102,42 @@
</method>
<method name="get_contact_collider" qualifiers="const">
<return type="RID" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
Returns the collider's [RID].
</description>
</method>
<method name="get_contact_collider_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
Returns the collider's object id.
</description>
</method>
<method name="get_contact_collider_object" qualifiers="const">
<return type="Object" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
Returns the collider object. This depends on how it was created (will return a scene node if such was used to create it).
</description>
</method>
<method name="get_contact_collider_position" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
Returns the contact position in the collider.
</description>
</method>
<method name="get_contact_collider_shape" qualifiers="const">
<return type="int" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
Returns the collider's shape index.
</description>
</method>
<method name="get_contact_collider_velocity_at_position" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
Returns the linear velocity vector at the collider's contact point.
</description>
@@ -146,26 +146,26 @@
<return type="int" />
<description>
Returns the number of contacts this body has with other bodies.
- [b]Note:[/b] By default, this returns 0 unless bodies are configured to monitor contacts. See [member RigidDynamicBody2D.contact_monitor].
+ [b]Note:[/b] By default, this returns 0 unless bodies are configured to monitor contacts. See [member RigidBody2D.contact_monitor].
</description>
</method>
<method name="get_contact_local_normal" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
Returns the local normal at the contact point.
</description>
</method>
<method name="get_contact_local_position" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
Returns the local position of the contact point.
</description>
</method>
<method name="get_contact_local_shape" qualifiers="const">
<return type="int" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
Returns the local shape index of the collision.
</description>
@@ -178,7 +178,7 @@
</method>
<method name="get_velocity_at_local_position" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="local_position" type="Vector2" />
+ <param index="0" name="local_position" type="Vector2" />
<description>
Returns the body's velocity at the given relative position, including both translation and rotation.
</description>
@@ -191,7 +191,7 @@
</method>
<method name="set_constant_force">
<return type="void" />
- <argument index="0" name="force" type="Vector2" />
+ <param index="0" name="force" type="Vector2" />
<description>
Sets the body's total constant positional forces applied during each physics update.
See [method add_constant_force] and [method add_constant_central_force].
@@ -199,7 +199,7 @@
</method>
<method name="set_constant_torque">
<return type="void" />
- <argument index="0" name="torque" type="float" />
+ <param index="0" name="torque" type="float" />
<description>
Sets the body's total constant rotational forces applied during each physics update.
See [method add_constant_torque].
diff --git a/doc/classes/PhysicsDirectBodyState3D.xml b/doc/classes/PhysicsDirectBodyState3D.xml
index 16c53b0727..efe63e4093 100644
--- a/doc/classes/PhysicsDirectBodyState3D.xml
+++ b/doc/classes/PhysicsDirectBodyState3D.xml
@@ -4,7 +4,7 @@
Direct access object to a physics body in the [PhysicsServer3D].
</brief_description>
<description>
- Provides direct access to a physics body in the [PhysicsServer3D], allowing safe changes to physics properties. This object is passed via the direct state callback of dynamic bodies, and is intended for changing the direct state of that body. See [method RigidDynamicBody3D._integrate_forces].
+ Provides direct access to a physics body in the [PhysicsServer3D], allowing safe changes to physics properties. This object is passed via the direct state callback of rigid bodies, and is intended for changing the direct state of that body. See [method RigidBody3D._integrate_forces].
</description>
<tutorials>
<link title="Physics introduction">$DOCS_URL/tutorials/physics/physics_introduction.html</link>
@@ -13,7 +13,7 @@
<methods>
<method name="add_constant_central_force">
<return type="void" />
- <argument index="0" name="force" type="Vector3" default="Vector3(0, 0, 0)" />
+ <param index="0" name="force" type="Vector3" default="Vector3(0, 0, 0)" />
<description>
Adds a constant directional force without affecting rotation that keeps being applied over time until cleared with [code]constant_force = Vector3(0, 0, 0)[/code].
This is equivalent to using [method add_constant_force] at the body's center of mass.
@@ -21,23 +21,23 @@
</method>
<method name="add_constant_force">
<return type="void" />
- <argument index="0" name="force" type="Vector3" />
- <argument index="1" name="position" type="Vector3" default="Vector3(0, 0, 0)" />
+ <param index="0" name="force" type="Vector3" />
+ <param index="1" name="position" type="Vector3" default="Vector3(0, 0, 0)" />
<description>
Adds a constant positioned force to the body that keeps being applied over time until cleared with [code]constant_force = Vector3(0, 0, 0)[/code].
- [code]position[/code] is the offset from the body origin in global coordinates.
+ [param position] is the offset from the body origin in global coordinates.
</description>
</method>
<method name="add_constant_torque">
<return type="void" />
- <argument index="0" name="torque" type="Vector3" />
+ <param index="0" name="torque" type="Vector3" />
<description>
Adds a constant rotational force without affecting position that keeps being applied over time until cleared with [code]constant_torque = Vector3(0, 0, 0)[/code].
</description>
</method>
<method name="apply_central_force">
<return type="void" />
- <argument index="0" name="force" type="Vector3" default="Vector3(0, 0, 0)" />
+ <param index="0" name="force" type="Vector3" default="Vector3(0, 0, 0)" />
<description>
Applies a directional force without affecting rotation. A force is time dependent and meant to be applied every physics update.
This is equivalent to using [method apply_force] at the body's center of mass.
@@ -45,7 +45,7 @@
</method>
<method name="apply_central_impulse">
<return type="void" />
- <argument index="0" name="impulse" type="Vector3" default="Vector3(0, 0, 0)" />
+ <param index="0" name="impulse" type="Vector3" default="Vector3(0, 0, 0)" />
<description>
Applies a directional impulse without affecting rotation.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
@@ -54,33 +54,33 @@
</method>
<method name="apply_force">
<return type="void" />
- <argument index="0" name="force" type="Vector3" />
- <argument index="1" name="position" type="Vector3" default="Vector3(0, 0, 0)" />
+ <param index="0" name="force" type="Vector3" />
+ <param index="1" name="position" type="Vector3" default="Vector3(0, 0, 0)" />
<description>
Applies a positioned force to the body. A force is time dependent and meant to be applied every physics update.
- [code]position[/code] is the offset from the body origin in global coordinates.
+ [param position] is the offset from the body origin in global coordinates.
</description>
</method>
<method name="apply_impulse">
<return type="void" />
- <argument index="0" name="impulse" type="Vector3" />
- <argument index="1" name="position" type="Vector3" default="Vector3(0, 0, 0)" />
+ <param index="0" name="impulse" type="Vector3" />
+ <param index="1" name="position" type="Vector3" default="Vector3(0, 0, 0)" />
<description>
Applies a positioned impulse to the body.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
- [code]position[/code] is the offset from the body origin in global coordinates.
+ [param position] is the offset from the body origin in global coordinates.
</description>
</method>
<method name="apply_torque">
<return type="void" />
- <argument index="0" name="torque" type="Vector3" />
+ <param index="0" name="torque" type="Vector3" />
<description>
Applies a rotational force without affecting position. A force is time dependent and meant to be applied every physics update.
</description>
</method>
<method name="apply_torque_impulse">
<return type="void" />
- <argument index="0" name="impulse" type="Vector3" />
+ <param index="0" name="impulse" type="Vector3" />
<description>
Applies a rotational impulse to the body without affecting the position.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
@@ -102,42 +102,42 @@
</method>
<method name="get_contact_collider" qualifiers="const">
<return type="RID" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
Returns the collider's [RID].
</description>
</method>
<method name="get_contact_collider_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
Returns the collider's object id.
</description>
</method>
<method name="get_contact_collider_object" qualifiers="const">
<return type="Object" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
Returns the collider object.
</description>
</method>
<method name="get_contact_collider_position" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
Returns the contact position in the collider.
</description>
</method>
<method name="get_contact_collider_shape" qualifiers="const">
<return type="int" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
Returns the collider's shape index.
</description>
</method>
<method name="get_contact_collider_velocity_at_position" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
Returns the linear velocity vector at the collider's contact point.
</description>
@@ -146,33 +146,33 @@
<return type="int" />
<description>
Returns the number of contacts this body has with other bodies.
- [b]Note:[/b] By default, this returns 0 unless bodies are configured to monitor contacts. See [member RigidDynamicBody3D.contact_monitor].
+ [b]Note:[/b] By default, this returns 0 unless bodies are configured to monitor contacts. See [member RigidBody3D.contact_monitor].
</description>
</method>
<method name="get_contact_impulse" qualifiers="const">
<return type="float" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
Impulse created by the contact. Only implemented for Bullet physics.
</description>
</method>
<method name="get_contact_local_normal" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
Returns the local normal at the contact point.
</description>
</method>
<method name="get_contact_local_position" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
Returns the local position of the contact point.
</description>
</method>
<method name="get_contact_local_shape" qualifiers="const">
<return type="int" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
Returns the local shape index of the collision.
</description>
@@ -185,7 +185,7 @@
</method>
<method name="get_velocity_at_local_position" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="local_position" type="Vector3" />
+ <param index="0" name="local_position" type="Vector3" />
<description>
Returns the body's velocity at the given relative position, including both translation and rotation.
</description>
@@ -198,7 +198,7 @@
</method>
<method name="set_constant_force">
<return type="void" />
- <argument index="0" name="force" type="Vector3" />
+ <param index="0" name="force" type="Vector3" />
<description>
Sets the body's total constant positional forces applied during each physics update.
See [method add_constant_force] and [method add_constant_central_force].
@@ -206,7 +206,7 @@
</method>
<method name="set_constant_torque">
<return type="void" />
- <argument index="0" name="torque" type="Vector3" />
+ <param index="0" name="torque" type="Vector3" />
<description>
Sets the body's total constant rotational forces applied during each physics update.
See [method add_constant_torque].
diff --git a/doc/classes/PhysicsDirectBodyState3DExtension.xml b/doc/classes/PhysicsDirectBodyState3DExtension.xml
index f0659f8f1b..ade197eadc 100644
--- a/doc/classes/PhysicsDirectBodyState3DExtension.xml
+++ b/doc/classes/PhysicsDirectBodyState3DExtension.xml
@@ -9,58 +9,58 @@
<methods>
<method name="_add_constant_central_force" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="force" type="Vector3" />
+ <param index="0" name="force" type="Vector3" />
<description>
</description>
</method>
<method name="_add_constant_force" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="force" type="Vector3" />
- <argument index="1" name="position" type="Vector3" />
+ <param index="0" name="force" type="Vector3" />
+ <param index="1" name="position" type="Vector3" />
<description>
</description>
</method>
<method name="_add_constant_torque" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="torque" type="Vector3" />
+ <param index="0" name="torque" type="Vector3" />
<description>
</description>
</method>
<method name="_apply_central_force" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="force" type="Vector3" />
+ <param index="0" name="force" type="Vector3" />
<description>
</description>
</method>
<method name="_apply_central_impulse" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="impulse" type="Vector3" />
+ <param index="0" name="impulse" type="Vector3" />
<description>
</description>
</method>
<method name="_apply_force" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="force" type="Vector3" />
- <argument index="1" name="position" type="Vector3" />
+ <param index="0" name="force" type="Vector3" />
+ <param index="1" name="position" type="Vector3" />
<description>
</description>
</method>
<method name="_apply_impulse" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="impulse" type="Vector3" />
- <argument index="1" name="position" type="Vector3" />
+ <param index="0" name="impulse" type="Vector3" />
+ <param index="1" name="position" type="Vector3" />
<description>
</description>
</method>
<method name="_apply_torque" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="torque" type="Vector3" />
+ <param index="0" name="torque" type="Vector3" />
<description>
</description>
</method>
<method name="_apply_torque_impulse" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="impulse" type="Vector3" />
+ <param index="0" name="impulse" type="Vector3" />
<description>
</description>
</method>
@@ -91,37 +91,37 @@
</method>
<method name="_get_contact_collider" qualifiers="virtual const">
<return type="RID" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
</description>
</method>
<method name="_get_contact_collider_id" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
</description>
</method>
<method name="_get_contact_collider_object" qualifiers="virtual const">
<return type="Object" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
</description>
</method>
<method name="_get_contact_collider_position" qualifiers="virtual const">
<return type="Vector3" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
</description>
</method>
<method name="_get_contact_collider_shape" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
</description>
</method>
<method name="_get_contact_collider_velocity_at_position" qualifiers="virtual const">
<return type="Vector3" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
</description>
</method>
@@ -132,25 +132,25 @@
</method>
<method name="_get_contact_impulse" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
</description>
</method>
<method name="_get_contact_local_normal" qualifiers="virtual const">
<return type="Vector3" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
</description>
</method>
<method name="_get_contact_local_position" qualifiers="virtual const">
<return type="Vector3" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
</description>
</method>
<method name="_get_contact_local_shape" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="contact_idx" type="int" />
+ <param index="0" name="contact_idx" type="int" />
<description>
</description>
</method>
@@ -206,7 +206,7 @@
</method>
<method name="_get_velocity_at_local_position" qualifiers="virtual const">
<return type="Vector3" />
- <argument index="0" name="local_position" type="Vector3" />
+ <param index="0" name="local_position" type="Vector3" />
<description>
</description>
</method>
@@ -222,37 +222,37 @@
</method>
<method name="_set_angular_velocity" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="velocity" type="Vector3" />
+ <param index="0" name="velocity" type="Vector3" />
<description>
</description>
</method>
<method name="_set_constant_force" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="force" type="Vector3" />
+ <param index="0" name="force" type="Vector3" />
<description>
</description>
</method>
<method name="_set_constant_torque" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="torque" type="Vector3" />
+ <param index="0" name="torque" type="Vector3" />
<description>
</description>
</method>
<method name="_set_linear_velocity" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="velocity" type="Vector3" />
+ <param index="0" name="velocity" type="Vector3" />
<description>
</description>
</method>
<method name="_set_sleep_state" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="enabled" type="bool" />
+ <param index="0" name="enabled" type="bool" />
<description>
</description>
</method>
<method name="_set_transform" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="transform" type="Transform3D" />
+ <param index="0" name="transform" type="Transform3D" />
<description>
</description>
</method>
diff --git a/doc/classes/PhysicsDirectSpaceState2D.xml b/doc/classes/PhysicsDirectSpaceState2D.xml
index 0b95243fe6..d4cb073d15 100644
--- a/doc/classes/PhysicsDirectSpaceState2D.xml
+++ b/doc/classes/PhysicsDirectSpaceState2D.xml
@@ -12,8 +12,8 @@
</tutorials>
<methods>
<method name="cast_motion">
- <return type="Array" />
- <argument index="0" name="parameters" type="PhysicsShapeQueryParameters2D" />
+ <return type="PackedFloat32Array" />
+ <param index="0" name="parameters" type="PhysicsShapeQueryParameters2D" />
<description>
Checks how far a [Shape2D] can move without colliding. All the parameters for the query, including the shape and the motion, are supplied through a [PhysicsShapeQueryParameters2D] object.
Returns an array with the safe and unsafe proportions (between 0 and 1) of the motion. The safe proportion is the maximum fraction of the motion that can be made without a collision. The unsafe proportion is the minimum fraction of the distance that must be moved for a collision. If no collision is detected a result of [code][1.0, 1.0][/code] will be returned.
@@ -21,9 +21,9 @@
</description>
</method>
<method name="collide_shape">
- <return type="Array" />
- <argument index="0" name="parameters" type="PhysicsShapeQueryParameters2D" />
- <argument index="1" name="max_results" type="int" default="32" />
+ <return type="PackedVector2Array[]" />
+ <param index="0" name="parameters" type="PhysicsShapeQueryParameters2D" />
+ <param index="1" name="max_results" type="int" default="32" />
<description>
Checks the intersections of a shape, given through a [PhysicsShapeQueryParameters2D] object, against the space. The resulting array contains a list of points where the shape intersects another. Like with [method intersect_shape], the number of returned results can be limited to save processing time.
Returned points are a list of pairs of contact points. For each pair the first one is in the shape passed in [PhysicsShapeQueryParameters2D] object, second one is in the collided shape from the physics space.
@@ -31,7 +31,7 @@
</method>
<method name="get_rest_info">
<return type="Dictionary" />
- <argument index="0" name="parameters" type="PhysicsShapeQueryParameters2D" />
+ <param index="0" name="parameters" type="PhysicsShapeQueryParameters2D" />
<description>
Checks the intersections of a shape, given through a [PhysicsShapeQueryParameters2D] object, against the space. If it collides with more than one shape, the nearest one is selected. If the shape did not intersect anything, then an empty dictionary is returned instead.
[b]Note:[/b] This method does not take into account the [code]motion[/code] property of the object. The returned object is a dictionary containing the following fields:
@@ -44,22 +44,22 @@
</description>
</method>
<method name="intersect_point">
- <return type="Array" />
- <argument index="0" name="parameters" type="PhysicsPointQueryParameters2D" />
- <argument index="1" name="max_results" type="int" default="32" />
+ <return type="Dictionary[]" />
+ <param index="0" name="parameters" type="PhysicsPointQueryParameters2D" />
+ <param index="1" name="max_results" type="int" default="32" />
<description>
Checks whether a point is inside any solid shape. Position and other parameters are defined through [PhysicsPointQueryParameters2D]. The shapes the point is inside of are returned in an array containing dictionaries with the following fields:
[code]collider[/code]: The colliding object.
[code]collider_id[/code]: The colliding object's ID.
[code]rid[/code]: The intersecting object's [RID].
[code]shape[/code]: The shape index of the colliding shape.
- The number of intersections can be limited with the [code]max_results[/code] parameter, to reduce the processing time.
+ The number of intersections can be limited with the [param max_results] parameter, to reduce the processing time.
[b]Note:[/b] [ConcavePolygonShape2D]s and [CollisionPolygon2D]s in [code]Segments[/code] build mode are not solid shapes. Therefore, they will not be detected.
</description>
</method>
<method name="intersect_ray">
<return type="Dictionary" />
- <argument index="0" name="parameters" type="PhysicsRayQueryParameters2D" />
+ <param index="0" name="parameters" type="PhysicsRayQueryParameters2D" />
<description>
Intersects a ray in a given space. Ray position and other parameters are defined through [PhysicsRayQueryParameters2D]. The returned object is a dictionary with the following fields:
[code]collider[/code]: The colliding object.
@@ -72,16 +72,16 @@
</description>
</method>
<method name="intersect_shape">
- <return type="Array" />
- <argument index="0" name="parameters" type="PhysicsShapeQueryParameters2D" />
- <argument index="1" name="max_results" type="int" default="32" />
+ <return type="Dictionary[]" />
+ <param index="0" name="parameters" type="PhysicsShapeQueryParameters2D" />
+ <param index="1" name="max_results" type="int" default="32" />
<description>
Checks the intersections of a shape, given through a [PhysicsShapeQueryParameters2D] object, against the space. The intersected shapes are returned in an array containing dictionaries with the following fields:
[code]collider[/code]: The colliding object.
[code]collider_id[/code]: The colliding object's ID.
[code]rid[/code]: The intersecting object's [RID].
[code]shape[/code]: The shape index of the colliding shape.
- The number of intersections can be limited with the [code]max_results[/code] parameter, to reduce the processing time.
+ The number of intersections can be limited with the [param max_results] parameter, to reduce the processing time.
</description>
</method>
</methods>
diff --git a/doc/classes/PhysicsDirectSpaceState3D.xml b/doc/classes/PhysicsDirectSpaceState3D.xml
index 048baed345..cc1cf8a323 100644
--- a/doc/classes/PhysicsDirectSpaceState3D.xml
+++ b/doc/classes/PhysicsDirectSpaceState3D.xml
@@ -12,8 +12,8 @@
</tutorials>
<methods>
<method name="cast_motion">
- <return type="Array" />
- <argument index="0" name="parameters" type="PhysicsShapeQueryParameters3D" />
+ <return type="PackedFloat32Array" />
+ <param index="0" name="parameters" type="PhysicsShapeQueryParameters3D" />
<description>
Checks how far a [Shape3D] can move without colliding. All the parameters for the query, including the shape, are supplied through a [PhysicsShapeQueryParameters3D] object.
Returns an array with the safe and unsafe proportions (between 0 and 1) of the motion. The safe proportion is the maximum fraction of the motion that can be made without a collision. The unsafe proportion is the minimum fraction of the distance that must be moved for a collision. If no collision is detected a result of [code][1.0, 1.0][/code] will be returned.
@@ -21,9 +21,9 @@
</description>
</method>
<method name="collide_shape">
- <return type="Array" />
- <argument index="0" name="parameters" type="PhysicsShapeQueryParameters3D" />
- <argument index="1" name="max_results" type="int" default="32" />
+ <return type="PackedVector2Array[]" />
+ <param index="0" name="parameters" type="PhysicsShapeQueryParameters3D" />
+ <param index="1" name="max_results" type="int" default="32" />
<description>
Checks the intersections of a shape, given through a [PhysicsShapeQueryParameters3D] object, against the space. The resulting array contains a list of points where the shape intersects another. Like with [method intersect_shape], the number of returned results can be limited to save processing time.
Returned points are a list of pairs of contact points. For each pair the first one is in the shape passed in [PhysicsShapeQueryParameters3D] object, second one is in the collided shape from the physics space.
@@ -32,7 +32,7 @@
</method>
<method name="get_rest_info">
<return type="Dictionary" />
- <argument index="0" name="parameters" type="PhysicsShapeQueryParameters3D" />
+ <param index="0" name="parameters" type="PhysicsShapeQueryParameters3D" />
<description>
Checks the intersections of a shape, given through a [PhysicsShapeQueryParameters3D] object, against the space. If it collides with more than one shape, the nearest one is selected. The returned object is a dictionary containing the following fields:
[code]collider_id[/code]: The colliding object's ID.
@@ -46,21 +46,21 @@
</description>
</method>
<method name="intersect_point">
- <return type="Array" />
- <argument index="0" name="parameters" type="PhysicsPointQueryParameters3D" />
- <argument index="1" name="max_results" type="int" default="32" />
+ <return type="Dictionary[]" />
+ <param index="0" name="parameters" type="PhysicsPointQueryParameters3D" />
+ <param index="1" name="max_results" type="int" default="32" />
<description>
Checks whether a point is inside any solid shape. Position and other parameters are defined through [PhysicsPointQueryParameters3D]. The shapes the point is inside of are returned in an array containing dictionaries with the following fields:
[code]collider[/code]: The colliding object.
[code]collider_id[/code]: The colliding object's ID.
[code]rid[/code]: The intersecting object's [RID].
[code]shape[/code]: The shape index of the colliding shape.
- The number of intersections can be limited with the [code]max_results[/code] parameter, to reduce the processing time.
+ The number of intersections can be limited with the [param max_results] parameter, to reduce the processing time.
</description>
</method>
<method name="intersect_ray">
<return type="Dictionary" />
- <argument index="0" name="parameters" type="PhysicsRayQueryParameters3D" />
+ <param index="0" name="parameters" type="PhysicsRayQueryParameters3D" />
<description>
Intersects a ray in a given space. Ray position and other parameters are defined through [PhysicsRayQueryParameters3D]. The returned object is a dictionary with the following fields:
[code]collider[/code]: The colliding object.
@@ -73,16 +73,16 @@
</description>
</method>
<method name="intersect_shape">
- <return type="Array" />
- <argument index="0" name="parameters" type="PhysicsShapeQueryParameters3D" />
- <argument index="1" name="max_results" type="int" default="32" />
+ <return type="Dictionary[]" />
+ <param index="0" name="parameters" type="PhysicsShapeQueryParameters3D" />
+ <param index="1" name="max_results" type="int" default="32" />
<description>
Checks the intersections of a shape, given through a [PhysicsShapeQueryParameters3D] object, against the space. The intersected shapes are returned in an array containing dictionaries with the following fields:
[code]collider[/code]: The colliding object.
[code]collider_id[/code]: The colliding object's ID.
[code]rid[/code]: The intersecting object's [RID].
[code]shape[/code]: The shape index of the colliding shape.
- The number of intersections can be limited with the [code]max_results[/code] parameter, to reduce the processing time.
+ The number of intersections can be limited with the [param max_results] parameter, to reduce the processing time.
[b]Note:[/b] This method does not take into account the [code]motion[/code] property of the object.
</description>
</method>
diff --git a/doc/classes/PhysicsDirectSpaceState3DExtension.xml b/doc/classes/PhysicsDirectSpaceState3DExtension.xml
index f150907963..98593012db 100644
--- a/doc/classes/PhysicsDirectSpaceState3DExtension.xml
+++ b/doc/classes/PhysicsDirectSpaceState3DExtension.xml
@@ -9,89 +9,89 @@
<methods>
<method name="_cast_motion" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="shape_rid" type="RID" />
- <argument index="1" name="transform" type="Transform3D" />
- <argument index="2" name="motion" type="Vector3" />
- <argument index="3" name="margin" type="float" />
- <argument index="4" name="collision_mask" type="int" />
- <argument index="5" name="collide_with_bodies" type="bool" />
- <argument index="6" name="collide_with_areas" type="bool" />
- <argument index="7" name="closest_safe" type="float*" />
- <argument index="8" name="closest_unsafe" type="float*" />
- <argument index="9" name="info" type="PhysicsServer3DExtensionShapeRestInfo*" />
+ <param index="0" name="shape_rid" type="RID" />
+ <param index="1" name="transform" type="Transform3D" />
+ <param index="2" name="motion" type="Vector3" />
+ <param index="3" name="margin" type="float" />
+ <param index="4" name="collision_mask" type="int" />
+ <param index="5" name="collide_with_bodies" type="bool" />
+ <param index="6" name="collide_with_areas" type="bool" />
+ <param index="7" name="closest_safe" type="float*" />
+ <param index="8" name="closest_unsafe" type="float*" />
+ <param index="9" name="info" type="PhysicsServer3DExtensionShapeRestInfo*" />
<description>
</description>
</method>
<method name="_collide_shape" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="shape_rid" type="RID" />
- <argument index="1" name="transform" type="Transform3D" />
- <argument index="2" name="motion" type="Vector3" />
- <argument index="3" name="margin" type="float" />
- <argument index="4" name="collision_mask" type="int" />
- <argument index="5" name="collide_with_bodies" type="bool" />
- <argument index="6" name="collide_with_areas" type="bool" />
- <argument index="7" name="results" type="void*" />
- <argument index="8" name="max_results" type="int" />
- <argument index="9" name="result_count" type="int32_t*" />
+ <param index="0" name="shape_rid" type="RID" />
+ <param index="1" name="transform" type="Transform3D" />
+ <param index="2" name="motion" type="Vector3" />
+ <param index="3" name="margin" type="float" />
+ <param index="4" name="collision_mask" type="int" />
+ <param index="5" name="collide_with_bodies" type="bool" />
+ <param index="6" name="collide_with_areas" type="bool" />
+ <param index="7" name="results" type="void*" />
+ <param index="8" name="max_results" type="int" />
+ <param index="9" name="result_count" type="int32_t*" />
<description>
</description>
</method>
<method name="_get_closest_point_to_object_volume" qualifiers="virtual const">
<return type="Vector3" />
- <argument index="0" name="object" type="RID" />
- <argument index="1" name="point" type="Vector3" />
+ <param index="0" name="object" type="RID" />
+ <param index="1" name="point" type="Vector3" />
<description>
</description>
</method>
<method name="_intersect_point" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="position" type="Vector3" />
- <argument index="1" name="collision_mask" type="int" />
- <argument index="2" name="collide_with_bodies" type="bool" />
- <argument index="3" name="collide_with_areas" type="bool" />
- <argument index="4" name="results" type="PhysicsServer3DExtensionShapeResult*" />
- <argument index="5" name="max_results" type="int" />
+ <param index="0" name="position" type="Vector3" />
+ <param index="1" name="collision_mask" type="int" />
+ <param index="2" name="collide_with_bodies" type="bool" />
+ <param index="3" name="collide_with_areas" type="bool" />
+ <param index="4" name="results" type="PhysicsServer3DExtensionShapeResult*" />
+ <param index="5" name="max_results" type="int" />
<description>
</description>
</method>
<method name="_intersect_ray" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="from" type="Vector3" />
- <argument index="1" name="to" type="Vector3" />
- <argument index="2" name="collision_mask" type="int" />
- <argument index="3" name="collide_with_bodies" type="bool" />
- <argument index="4" name="collide_with_areas" type="bool" />
- <argument index="5" name="hit_from_inside" type="bool" />
- <argument index="6" name="hit_back_faces" type="bool" />
- <argument index="7" name="result" type="PhysicsServer3DExtensionRayResult*" />
+ <param index="0" name="from" type="Vector3" />
+ <param index="1" name="to" type="Vector3" />
+ <param index="2" name="collision_mask" type="int" />
+ <param index="3" name="collide_with_bodies" type="bool" />
+ <param index="4" name="collide_with_areas" type="bool" />
+ <param index="5" name="hit_from_inside" type="bool" />
+ <param index="6" name="hit_back_faces" type="bool" />
+ <param index="7" name="result" type="PhysicsServer3DExtensionRayResult*" />
<description>
</description>
</method>
<method name="_intersect_shape" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="shape_rid" type="RID" />
- <argument index="1" name="transform" type="Transform3D" />
- <argument index="2" name="motion" type="Vector3" />
- <argument index="3" name="margin" type="float" />
- <argument index="4" name="collision_mask" type="int" />
- <argument index="5" name="collide_with_bodies" type="bool" />
- <argument index="6" name="collide_with_areas" type="bool" />
- <argument index="7" name="result_count" type="PhysicsServer3DExtensionShapeResult*" />
- <argument index="8" name="max_results" type="int" />
+ <param index="0" name="shape_rid" type="RID" />
+ <param index="1" name="transform" type="Transform3D" />
+ <param index="2" name="motion" type="Vector3" />
+ <param index="3" name="margin" type="float" />
+ <param index="4" name="collision_mask" type="int" />
+ <param index="5" name="collide_with_bodies" type="bool" />
+ <param index="6" name="collide_with_areas" type="bool" />
+ <param index="7" name="result_count" type="PhysicsServer3DExtensionShapeResult*" />
+ <param index="8" name="max_results" type="int" />
<description>
</description>
</method>
<method name="_rest_info" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="shape_rid" type="RID" />
- <argument index="1" name="transform" type="Transform3D" />
- <argument index="2" name="motion" type="Vector3" />
- <argument index="3" name="margin" type="float" />
- <argument index="4" name="collision_mask" type="int" />
- <argument index="5" name="collide_with_bodies" type="bool" />
- <argument index="6" name="collide_with_areas" type="bool" />
- <argument index="7" name="rest_info" type="PhysicsServer3DExtensionShapeRestInfo*" />
+ <param index="0" name="shape_rid" type="RID" />
+ <param index="1" name="transform" type="Transform3D" />
+ <param index="2" name="motion" type="Vector3" />
+ <param index="3" name="margin" type="float" />
+ <param index="4" name="collision_mask" type="int" />
+ <param index="5" name="collide_with_bodies" type="bool" />
+ <param index="6" name="collide_with_areas" type="bool" />
+ <param index="7" name="rest_info" type="PhysicsServer3DExtensionShapeRestInfo*" />
<description>
</description>
</method>
diff --git a/doc/classes/PhysicsRayQueryParameters2D.xml b/doc/classes/PhysicsRayQueryParameters2D.xml
index 36933ef9a2..5afd3973a0 100644
--- a/doc/classes/PhysicsRayQueryParameters2D.xml
+++ b/doc/classes/PhysicsRayQueryParameters2D.xml
@@ -8,6 +8,22 @@
</description>
<tutorials>
</tutorials>
+ <methods>
+ <method name="create" qualifiers="static">
+ <return type="PhysicsRayQueryParameters2D" />
+ <param index="0" name="from" type="Vector2" />
+ <param index="1" name="to" type="Vector2" />
+ <param index="2" name="collision_mask" type="int" default="4294967295" />
+ <param index="3" name="exclude" type="Array" default="[]" />
+ <description>
+ Returns a new, pre-configured [PhysicsRayQueryParameters2D] object. Use it to quickly create query parameters using the most common options.
+ [codeblock]
+ var query = PhysicsRayQueryParameters2D.create(global_position, global_position + Vector2(0, 100))
+ var collision = get_world_2d().direct_space_state.intersect_ray(query)
+ [/codeblock]
+ </description>
+ </method>
+ </methods>
<members>
<member name="collide_with_areas" type="bool" setter="set_collide_with_areas" getter="is_collide_with_areas_enabled" default="false">
If [code]true[/code], the query will take [Area2D]s into account.
diff --git a/doc/classes/PhysicsRayQueryParameters3D.xml b/doc/classes/PhysicsRayQueryParameters3D.xml
index 4244ec785f..620aa6bf5f 100644
--- a/doc/classes/PhysicsRayQueryParameters3D.xml
+++ b/doc/classes/PhysicsRayQueryParameters3D.xml
@@ -8,6 +8,22 @@
</description>
<tutorials>
</tutorials>
+ <methods>
+ <method name="create" qualifiers="static">
+ <return type="PhysicsRayQueryParameters3D" />
+ <param index="0" name="from" type="Vector3" />
+ <param index="1" name="to" type="Vector3" />
+ <param index="2" name="collision_mask" type="int" default="4294967295" />
+ <param index="3" name="exclude" type="Array" default="[]" />
+ <description>
+ Returns a new, pre-configured [PhysicsRayQueryParameters3D] object. Use it to quickly create query parameters using the most common options.
+ [codeblock]
+ var query = PhysicsRayQueryParameters3D.create(position, position + Vector3(0, -10, 0))
+ var collision = get_world_3d().direct_space_state.intersect_ray(query)
+ [/codeblock]
+ </description>
+ </method>
+ </methods>
<members>
<member name="collide_with_areas" type="bool" setter="set_collide_with_areas" getter="is_collide_with_areas_enabled" default="false">
If [code]true[/code], the query will take [Area3D]s into account.
diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml
index 1413a3ec11..5ae7423a71 100644
--- a/doc/classes/PhysicsServer2D.xml
+++ b/doc/classes/PhysicsServer2D.xml
@@ -11,32 +11,32 @@
<methods>
<method name="area_add_shape">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="shape" type="RID" />
- <argument index="2" name="transform" type="Transform2D" default="Transform2D(1, 0, 0, 1, 0, 0)" />
- <argument index="3" name="disabled" type="bool" default="false" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape" type="RID" />
+ <param index="2" name="transform" type="Transform2D" default="Transform2D(1, 0, 0, 1, 0, 0)" />
+ <param index="3" name="disabled" type="bool" default="false" />
<description>
Adds a shape to the area, along with a transform matrix. Shapes are usually referenced by their index, so you should track which shape has a given index.
</description>
</method>
<method name="area_attach_canvas_instance_id">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="id" type="int" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="id" type="int" />
<description>
</description>
</method>
<method name="area_attach_object_instance_id">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="id" type="int" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="id" type="int" />
<description>
Assigns the area to a descendant of [Object], so it can exist in the node tree.
</description>
</method>
<method name="area_clear_shapes">
<return type="void" />
- <argument index="0" name="area" type="RID" />
+ <param index="0" name="area" type="RID" />
<description>
Removes all shapes from an area. It does not delete the shapes, so they can be reassigned later.
</description>
@@ -49,97 +49,97 @@
</method>
<method name="area_get_canvas_instance_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="area" type="RID" />
+ <param index="0" name="area" type="RID" />
<description>
</description>
</method>
<method name="area_get_object_instance_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="area" type="RID" />
+ <param index="0" name="area" type="RID" />
<description>
Gets the instance ID of the object the area is assigned to.
</description>
</method>
<method name="area_get_param" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer2D.AreaParameter" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.AreaParameter" />
<description>
Returns an area parameter value. See [enum AreaParameter] for a list of available parameters.
</description>
</method>
<method name="area_get_shape" qualifiers="const">
<return type="RID" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
<description>
Returns the [RID] of the nth shape of an area.
</description>
</method>
<method name="area_get_shape_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="area" type="RID" />
+ <param index="0" name="area" type="RID" />
<description>
Returns the number of shapes assigned to an area.
</description>
</method>
<method name="area_get_shape_transform" qualifiers="const">
<return type="Transform2D" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
<description>
Returns the transform matrix of a shape within an area.
</description>
</method>
<method name="area_get_space" qualifiers="const">
<return type="RID" />
- <argument index="0" name="area" type="RID" />
+ <param index="0" name="area" type="RID" />
<description>
Returns the space assigned to the area.
</description>
</method>
<method name="area_get_transform" qualifiers="const">
<return type="Transform2D" />
- <argument index="0" name="area" type="RID" />
+ <param index="0" name="area" type="RID" />
<description>
Returns the transform matrix for an area.
</description>
</method>
<method name="area_remove_shape">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
<description>
Removes a shape from an area. It does not delete the shape, so it can be reassigned later.
</description>
</method>
<method name="area_set_area_monitor_callback">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="callback" type="Callable" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="callback" type="Callable" />
<description>
</description>
</method>
<method name="area_set_collision_layer">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="layer" type="int" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="layer" type="int" />
<description>
Assigns the area to one or many physics layers.
</description>
</method>
<method name="area_set_collision_mask">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="mask" type="int" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="mask" type="int" />
<description>
Sets which physics layers the area will monitor.
</description>
</method>
<method name="area_set_monitor_callback">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="callback" type="Callable" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="callback" type="Callable" />
<description>
Sets the function to call when any body/area enters or exits the area. This callback will be called for any object interacting with the area, and takes five parameters:
1: [constant AREA_BODY_ADDED] or [constant AREA_BODY_REMOVED], depending on whether the object entered or exited the area.
@@ -151,75 +151,75 @@
</method>
<method name="area_set_monitorable">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="monitorable" type="bool" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="monitorable" type="bool" />
<description>
</description>
</method>
<method name="area_set_param">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer2D.AreaParameter" />
- <argument index="2" name="value" type="Variant" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.AreaParameter" />
+ <param index="2" name="value" type="Variant" />
<description>
Sets the value for an area parameter. See [enum AreaParameter] for a list of available parameters.
</description>
</method>
<method name="area_set_shape">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
- <argument index="2" name="shape" type="RID" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="shape" type="RID" />
<description>
Substitutes a given area shape by another. The old shape is selected by its index, the new one by its [RID].
</description>
</method>
<method name="area_set_shape_disabled">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
- <argument index="2" name="disabled" type="bool" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="disabled" type="bool" />
<description>
Disables a given shape in an area.
</description>
</method>
<method name="area_set_shape_transform">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
- <argument index="2" name="transform" type="Transform2D" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="transform" type="Transform2D" />
<description>
Sets the transform matrix for an area shape.
</description>
</method>
<method name="area_set_space">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="space" type="RID" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="space" type="RID" />
<description>
Assigns a space to the area.
</description>
</method>
<method name="area_set_transform">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="transform" type="Transform2D" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="transform" type="Transform2D" />
<description>
Sets the transform matrix for an area.
</description>
</method>
<method name="body_add_collision_exception">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="excepted_body" type="RID" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="excepted_body" type="RID" />
<description>
Adds a body to the list of bodies exempt from collisions.
</description>
</method>
<method name="body_add_constant_central_force">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="force" type="Vector2" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector2" />
<description>
Adds a constant directional force without affecting rotation that keeps being applied over time until cleared with [code]body_set_constant_force(body, Vector2(0, 0))[/code].
This is equivalent to using [method body_add_constant_force] at the body's center of mass.
@@ -227,36 +227,36 @@
</method>
<method name="body_add_constant_force">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="force" type="Vector2" />
- <argument index="2" name="position" type="Vector2" default="Vector2(0, 0)" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector2" />
+ <param index="2" name="position" type="Vector2" default="Vector2(0, 0)" />
<description>
Adds a constant positioned force to the body that keeps being applied over time until cleared with [code]body_set_constant_force(body, Vector2(0, 0))[/code].
- [code]position[/code] is the offset from the body origin in global coordinates.
+ [param position] is the offset from the body origin in global coordinates.
</description>
</method>
<method name="body_add_constant_torque">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="torque" type="float" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="torque" type="float" />
<description>
Adds a constant rotational force without affecting position that keeps being applied over time until cleared with [code]body_set_constant_torque(body, 0)[/code].
</description>
</method>
<method name="body_add_shape">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape" type="RID" />
- <argument index="2" name="transform" type="Transform2D" default="Transform2D(1, 0, 0, 1, 0, 0)" />
- <argument index="3" name="disabled" type="bool" default="false" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape" type="RID" />
+ <param index="2" name="transform" type="Transform2D" default="Transform2D(1, 0, 0, 1, 0, 0)" />
+ <param index="3" name="disabled" type="bool" default="false" />
<description>
Adds a shape to the body, along with a transform matrix. Shapes are usually referenced by their index, so you should track which shape has a given index.
</description>
</method>
<method name="body_apply_central_force">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="force" type="Vector2" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector2" />
<description>
Applies a directional force without affecting rotation. A force is time dependent and meant to be applied every physics update.
This is equivalent to using [method body_apply_force] at the body's center of mass.
@@ -264,8 +264,8 @@
</method>
<method name="body_apply_central_impulse">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="impulse" type="Vector2" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="impulse" type="Vector2" />
<description>
Applies a directional impulse without affecting rotation.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
@@ -274,37 +274,37 @@
</method>
<method name="body_apply_force">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="force" type="Vector2" />
- <argument index="2" name="position" type="Vector2" default="Vector2(0, 0)" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector2" />
+ <param index="2" name="position" type="Vector2" default="Vector2(0, 0)" />
<description>
Applies a positioned force to the body. A force is time dependent and meant to be applied every physics update.
- [code]position[/code] is the offset from the body origin in global coordinates.
+ [param position] is the offset from the body origin in global coordinates.
</description>
</method>
<method name="body_apply_impulse">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="impulse" type="Vector2" />
- <argument index="2" name="position" type="Vector2" default="Vector2(0, 0)" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="impulse" type="Vector2" />
+ <param index="2" name="position" type="Vector2" default="Vector2(0, 0)" />
<description>
Applies a positioned impulse to the body.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
- [code]position[/code] is the offset from the body origin in global coordinates.
+ [param position] is the offset from the body origin in global coordinates.
</description>
</method>
<method name="body_apply_torque">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="torque" type="float" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="torque" type="float" />
<description>
Applies a rotational force without affecting position. A force is time dependent and meant to be applied every physics update.
</description>
</method>
<method name="body_apply_torque_impulse">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="impulse" type="float" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="impulse" type="float" />
<description>
Applies a rotational impulse to the body without affecting the position.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
@@ -312,22 +312,22 @@
</method>
<method name="body_attach_canvas_instance_id">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="id" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="id" type="int" />
<description>
</description>
</method>
<method name="body_attach_object_instance_id">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="id" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="id" type="int" />
<description>
Assigns the area to a descendant of [Object], so it can exist in the node tree.
</description>
</method>
<method name="body_clear_shapes">
<return type="void" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Removes all shapes from a body.
</description>
@@ -340,27 +340,34 @@
</method>
<method name="body_get_canvas_instance_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
</description>
</method>
<method name="body_get_collision_layer" qualifiers="const">
<return type="int" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns the physics layer or layers a body belongs to.
</description>
</method>
<method name="body_get_collision_mask" qualifiers="const">
<return type="int" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns the physics layer or layers a body can collide with.
</description>
</method>
+ <method name="body_get_collision_priority" qualifiers="const">
+ <return type="float" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ Returns the body's collision priority.
+ </description>
+ </method>
<method name="body_get_constant_force" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns the body's total constant positional forces applied during each physics update.
See [method body_add_constant_force] and [method body_add_constant_central_force].
@@ -368,7 +375,7 @@
</method>
<method name="body_get_constant_torque" qualifiers="const">
<return type="float" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns the body's total constant rotational forces applied during each physics update.
See [method body_add_constant_torque].
@@ -376,143 +383,151 @@
</method>
<method name="body_get_continuous_collision_detection_mode" qualifiers="const">
<return type="int" enum="PhysicsServer2D.CCDMode" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns the continuous collision detection mode.
</description>
</method>
<method name="body_get_direct_state">
<return type="PhysicsDirectBodyState2D" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns the [PhysicsDirectBodyState2D] of the body. Returns [code]null[/code] if the body is destroyed or removed from the physics space.
</description>
</method>
<method name="body_get_max_contacts_reported" qualifiers="const">
<return type="int" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns the maximum contacts that can be reported. See [method body_set_max_contacts_reported].
</description>
</method>
<method name="body_get_mode" qualifiers="const">
<return type="int" enum="PhysicsServer2D.BodyMode" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns the body mode.
</description>
</method>
<method name="body_get_object_instance_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Gets the instance ID of the object the area is assigned to.
</description>
</method>
<method name="body_get_param" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer2D.BodyParameter" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.BodyParameter" />
<description>
Returns the value of a body parameter. See [enum BodyParameter] for a list of available parameters.
</description>
</method>
<method name="body_get_shape" qualifiers="const">
<return type="RID" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
<description>
Returns the [RID] of the nth shape of a body.
</description>
</method>
<method name="body_get_shape_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns the number of shapes assigned to a body.
</description>
</method>
<method name="body_get_shape_transform" qualifiers="const">
<return type="Transform2D" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
<description>
Returns the transform matrix of a body shape.
</description>
</method>
<method name="body_get_space" qualifiers="const">
<return type="RID" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns the [RID] of the space assigned to a body.
</description>
</method>
<method name="body_get_state" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="state" type="int" enum="PhysicsServer2D.BodyState" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="state" type="int" enum="PhysicsServer2D.BodyState" />
<description>
Returns a body state.
</description>
</method>
<method name="body_is_omitting_force_integration" qualifiers="const">
<return type="bool" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns whether a body uses a callback function to calculate its own physics (see [method body_set_force_integration_callback]).
</description>
</method>
<method name="body_remove_collision_exception">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="excepted_body" type="RID" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="excepted_body" type="RID" />
<description>
Removes a body from the list of bodies exempt from collisions.
</description>
</method>
<method name="body_remove_shape">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
<description>
Removes a shape from a body. The shape is not deleted, so it can be reused afterwards.
</description>
</method>
<method name="body_reset_mass_properties">
<return type="void" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Restores the default inertia and center of mass based on shapes to cancel any custom values previously set using [method body_set_param].
</description>
</method>
<method name="body_set_axis_velocity">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="axis_velocity" type="Vector2" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="axis_velocity" type="Vector2" />
<description>
Sets an axis velocity. The velocity in the given vector axis will be set as the given vector length. This is useful for jumping behavior.
</description>
</method>
<method name="body_set_collision_layer">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="layer" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="layer" type="int" />
<description>
Sets the physics layer or layers a body belongs to.
</description>
</method>
<method name="body_set_collision_mask">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="mask" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="mask" type="int" />
<description>
Sets the physics layer or layers a body can collide with.
</description>
</method>
+ <method name="body_set_collision_priority">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="priority" type="float" />
+ <description>
+ Sets the body's collision priority.
+ </description>
+ </method>
<method name="body_set_constant_force">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="force" type="Vector2" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector2" />
<description>
Sets the body's total constant positional forces applied during each physics update.
See [method body_add_constant_force] and [method body_add_constant_central_force].
@@ -520,8 +535,8 @@
</method>
<method name="body_set_constant_torque">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="torque" type="float" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="torque" type="float" />
<description>
Sets the body's total constant rotational forces applied during each physics update.
See [method body_add_constant_torque].
@@ -529,8 +544,8 @@
</method>
<method name="body_set_continuous_collision_detection_mode">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="mode" type="int" enum="PhysicsServer2D.CCDMode" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="mode" type="int" enum="PhysicsServer2D.CCDMode" />
<description>
Sets the continuous collision detection mode using one of the [enum CCDMode] constants.
Continuous collision detection tries to predict where a moving body will collide, instead of moving it and correcting its movement if it collided.
@@ -538,9 +553,9 @@
</method>
<method name="body_set_force_integration_callback">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="callable" type="Callable" />
- <argument index="2" name="userdata" type="Variant" default="null" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="callable" type="Callable" />
+ <param index="2" name="userdata" type="Variant" default="null" />
<description>
Sets the function used to calculate physics for an object, if that object allows it (see [method body_set_omit_force_integration]).
The force integration function takes 2 arguments:
@@ -550,87 +565,87 @@
</method>
<method name="body_set_max_contacts_reported">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="amount" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="amount" type="int" />
<description>
- Sets the maximum contacts to report. Bodies can keep a log of the contacts with other bodies, this is enabled by setting the maximum amount of contacts reported to a number greater than 0.
+ Sets the maximum contacts to report. Bodies can keep a log of the contacts with other bodies. This is enabled by setting the maximum number of contacts reported to a number greater than 0.
</description>
</method>
<method name="body_set_mode">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="mode" type="int" enum="PhysicsServer2D.BodyMode" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="mode" type="int" enum="PhysicsServer2D.BodyMode" />
<description>
Sets the body mode using one of the [enum BodyMode] constants.
</description>
</method>
<method name="body_set_omit_force_integration">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
Sets whether a body uses a callback function to calculate its own physics (see [method body_set_force_integration_callback]).
</description>
</method>
<method name="body_set_param">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer2D.BodyParameter" />
- <argument index="2" name="value" type="Variant" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.BodyParameter" />
+ <param index="2" name="value" type="Variant" />
<description>
Sets a body parameter. See [enum BodyParameter] for a list of available parameters.
</description>
</method>
<method name="body_set_shape">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
- <argument index="2" name="shape" type="RID" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="shape" type="RID" />
<description>
Substitutes a given body shape by another. The old shape is selected by its index, the new one by its [RID].
</description>
</method>
<method name="body_set_shape_as_one_way_collision">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
- <argument index="2" name="enable" type="bool" />
- <argument index="3" name="margin" type="float" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="enable" type="bool" />
+ <param index="3" name="margin" type="float" />
<description>
- Enables one way collision on body if [code]enable[/code] is [code]true[/code].
+ Enables one way collision on body if [param enable] is [code]true[/code].
</description>
</method>
<method name="body_set_shape_disabled">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
- <argument index="2" name="disabled" type="bool" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="disabled" type="bool" />
<description>
- Disables shape in body if [code]disable[/code] is [code]true[/code].
+ Disables shape in body if [param disabled] is [code]true[/code].
</description>
</method>
<method name="body_set_shape_transform">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
- <argument index="2" name="transform" type="Transform2D" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="transform" type="Transform2D" />
<description>
Sets the transform matrix for a body shape.
</description>
</method>
<method name="body_set_space">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="space" type="RID" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="space" type="RID" />
<description>
Assigns a space to the body (see [method space_create]).
</description>
</method>
<method name="body_set_state">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="state" type="int" enum="PhysicsServer2D.BodyState" />
- <argument index="2" name="value" type="Variant" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="state" type="int" enum="PhysicsServer2D.BodyState" />
+ <param index="2" name="value" type="Variant" />
<description>
Sets a body state using one of the [enum BodyState] constants.
Note that the method doesn't take effect immediately. The state will change on the next physics frame.
@@ -638,9 +653,9 @@
</method>
<method name="body_test_motion">
<return type="bool" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="parameters" type="PhysicsTestMotionParameters2D" />
- <argument index="2" name="result" type="PhysicsTestMotionResult2D" default="null" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="parameters" type="PhysicsTestMotionParameters2D" />
+ <param index="2" name="result" type="PhysicsTestMotionResult2D" default="null" />
<description>
Returns [code]true[/code] if a collision would result from moving along a motion vector from a given point in space. [PhysicsTestMotionParameters2D] is passed to set motion parameters. [PhysicsTestMotionResult2D] can be passed to return additional information.
</description>
@@ -667,38 +682,38 @@
</method>
<method name="damped_spring_joint_get_param" qualifiers="const">
<return type="float" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer2D.DampedSpringParam" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.DampedSpringParam" />
<description>
Returns the value of a damped spring joint parameter. See [enum DampedSpringParam] for a list of available parameters.
</description>
</method>
<method name="damped_spring_joint_set_param">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer2D.DampedSpringParam" />
- <argument index="2" name="value" type="float" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.DampedSpringParam" />
+ <param index="2" name="value" type="float" />
<description>
Sets a damped spring joint parameter. See [enum DampedSpringParam] for a list of available parameters.
</description>
</method>
<method name="free_rid">
<return type="void" />
- <argument index="0" name="rid" type="RID" />
+ <param index="0" name="rid" type="RID" />
<description>
Destroys any of the objects created by PhysicsServer2D. If the [RID] passed is not one of the objects that can be created by PhysicsServer2D, an error will be sent to the console.
</description>
</method>
<method name="get_process_info">
<return type="int" />
- <argument index="0" name="process_info" type="int" enum="PhysicsServer2D.ProcessInfo" />
+ <param index="0" name="process_info" type="int" enum="PhysicsServer2D.ProcessInfo" />
<description>
Returns information about the current state of the 2D physics engine. See [enum ProcessInfo] for a list of available states.
</description>
</method>
<method name="joint_clear">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
+ <param index="0" name="joint" type="RID" />
<description>
</description>
</method>
@@ -709,54 +724,54 @@
</method>
<method name="joint_get_param" qualifiers="const">
<return type="float" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer2D.JointParam" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.JointParam" />
<description>
Returns the value of a joint parameter.
</description>
</method>
<method name="joint_get_type" qualifiers="const">
<return type="int" enum="PhysicsServer2D.JointType" />
- <argument index="0" name="joint" type="RID" />
+ <param index="0" name="joint" type="RID" />
<description>
Returns a joint's type (see [enum JointType]).
</description>
</method>
<method name="joint_make_damped_spring">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="anchor_a" type="Vector2" />
- <argument index="2" name="anchor_b" type="Vector2" />
- <argument index="3" name="body_a" type="RID" />
- <argument index="4" name="body_b" type="RID" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="anchor_a" type="Vector2" />
+ <param index="2" name="anchor_b" type="Vector2" />
+ <param index="3" name="body_a" type="RID" />
+ <param index="4" name="body_b" type="RID" />
<description>
</description>
</method>
<method name="joint_make_groove">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="groove1_a" type="Vector2" />
- <argument index="2" name="groove2_a" type="Vector2" />
- <argument index="3" name="anchor_b" type="Vector2" />
- <argument index="4" name="body_a" type="RID" />
- <argument index="5" name="body_b" type="RID" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="groove1_a" type="Vector2" />
+ <param index="2" name="groove2_a" type="Vector2" />
+ <param index="3" name="anchor_b" type="Vector2" />
+ <param index="4" name="body_a" type="RID" />
+ <param index="5" name="body_b" type="RID" />
<description>
</description>
</method>
<method name="joint_make_pin">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="anchor" type="Vector2" />
- <argument index="2" name="body_a" type="RID" />
- <argument index="3" name="body_b" type="RID" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="anchor" type="Vector2" />
+ <param index="2" name="body_a" type="RID" />
+ <param index="3" name="body_b" type="RID" />
<description>
</description>
</method>
<method name="joint_set_param">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer2D.JointParam" />
- <argument index="2" name="value" type="float" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.JointParam" />
+ <param index="2" name="value" type="float" />
<description>
Sets a joint parameter. See [enum JointParam] for a list of available parameters.
</description>
@@ -778,29 +793,29 @@
</method>
<method name="set_active">
<return type="void" />
- <argument index="0" name="active" type="bool" />
+ <param index="0" name="active" type="bool" />
<description>
Activates or deactivates the 2D physics engine.
</description>
</method>
<method name="shape_get_data" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="shape" type="RID" />
+ <param index="0" name="shape" type="RID" />
<description>
Returns the shape data.
</description>
</method>
<method name="shape_get_type" qualifiers="const">
<return type="int" enum="PhysicsServer2D.ShapeType" />
- <argument index="0" name="shape" type="RID" />
+ <param index="0" name="shape" type="RID" />
<description>
Returns a shape's type (see [enum ShapeType]).
</description>
</method>
<method name="shape_set_data">
<return type="void" />
- <argument index="0" name="shape" type="RID" />
- <argument index="1" name="data" type="Variant" />
+ <param index="0" name="shape" type="RID" />
+ <param index="1" name="data" type="Variant" />
<description>
Sets the shape data that defines its shape and size. The data to be passed depends on the kind of shape created [method shape_get_type].
</description>
@@ -813,39 +828,39 @@
</method>
<method name="space_get_direct_state">
<return type="PhysicsDirectSpaceState2D" />
- <argument index="0" name="space" type="RID" />
+ <param index="0" name="space" type="RID" />
<description>
Returns the state of a space, a [PhysicsDirectSpaceState2D]. This object can be used to make collision/intersection queries.
</description>
</method>
<method name="space_get_param" qualifiers="const">
<return type="float" />
- <argument index="0" name="space" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer2D.SpaceParameter" />
+ <param index="0" name="space" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.SpaceParameter" />
<description>
Returns the value of a space parameter.
</description>
</method>
<method name="space_is_active" qualifiers="const">
<return type="bool" />
- <argument index="0" name="space" type="RID" />
+ <param index="0" name="space" type="RID" />
<description>
Returns whether the space is active.
</description>
</method>
<method name="space_set_active">
<return type="void" />
- <argument index="0" name="space" type="RID" />
- <argument index="1" name="active" type="bool" />
+ <param index="0" name="space" type="RID" />
+ <param index="1" name="active" type="bool" />
<description>
Marks a space as active. It will not have an effect, unless it is assigned to an area or body.
</description>
</method>
<method name="space_set_param">
<return type="void" />
- <argument index="0" name="space" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer2D.SpaceParameter" />
- <argument index="2" name="value" type="float" />
+ <param index="0" name="space" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer2D.SpaceParameter" />
+ <param index="2" name="value" type="float" />
<description>
Sets the value for a space parameter. See [enum SpaceParameter] for a list of available parameters.
</description>
@@ -882,7 +897,7 @@
Constant to set/get the default solver bias for all physics constraints. A solver bias is a factor controlling how much two objects "rebound", after violating a constraint, to avoid leaving them in that state because of numerical imprecision.
</constant>
<constant name="SPACE_PARAM_SOLVER_ITERATIONS" value="8" enum="SpaceParameter">
- Constant to set/get the number of solver iterations for all contacts and constraints. The greater the amount of iterations, the more accurate the collisions will be. However, a greater amount of iterations requires more CPU power, which can decrease performance.
+ Constant to set/get the number of solver iterations for all contacts and constraints. The greater the number of iterations, the more accurate the collisions will be. However, a greater number of iterations requires more CPU power, which can decrease performance.
</constant>
<constant name="SHAPE_WORLD_BOUNDARY" value="0" enum="ShapeType">
This is the constant for creating world boundary shapes. A world boundary shape is an [i]infinite[/i] line with an origin point, and a normal. Thus, it can be used for front/behind checks.
@@ -965,11 +980,11 @@
<constant name="BODY_MODE_KINEMATIC" value="1" enum="BodyMode">
Constant for kinematic bodies. In this mode, a body can be only moved by user code and collides with other bodies along its path.
</constant>
- <constant name="BODY_MODE_DYNAMIC" value="2" enum="BodyMode">
- Constant for dynamic bodies. In this mode, a body can be pushed by other bodies and has forces applied.
+ <constant name="BODY_MODE_RIGID" value="2" enum="BodyMode">
+ Constant for rigid bodies. In this mode, a body can be pushed by other bodies and has forces applied.
</constant>
- <constant name="BODY_MODE_DYNAMIC_LINEAR" value="3" enum="BodyMode">
- Constant for linear dynamic bodies. In this mode, a body is dynamic but can not rotate, and only its linear velocity is affected by external forces.
+ <constant name="BODY_MODE_RIGID_LINEAR" value="3" enum="BodyMode">
+ Constant for linear rigid bodies. In this mode, a body can not rotate, and only its linear velocity is affected by external forces.
</constant>
<constant name="BODY_PARAM_BOUNCE" value="0" enum="BodyParameter">
Constant to set/get a body's bounce factor.
diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml
index 2e84287227..da9e10c420 100644
--- a/doc/classes/PhysicsServer3D.xml
+++ b/doc/classes/PhysicsServer3D.xml
@@ -11,25 +11,25 @@
<methods>
<method name="area_add_shape">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="shape" type="RID" />
- <argument index="2" name="transform" type="Transform3D" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)" />
- <argument index="3" name="disabled" type="bool" default="false" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape" type="RID" />
+ <param index="2" name="transform" type="Transform3D" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)" />
+ <param index="3" name="disabled" type="bool" default="false" />
<description>
Adds a shape to the area, along with a transform matrix. Shapes are usually referenced by their index, so you should track which shape has a given index.
</description>
</method>
<method name="area_attach_object_instance_id">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="id" type="int" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="id" type="int" />
<description>
Assigns the area to a descendant of [Object], so it can exist in the node tree.
</description>
</method>
<method name="area_clear_shapes">
<return type="void" />
- <argument index="0" name="area" type="RID" />
+ <param index="0" name="area" type="RID" />
<description>
Removes all shapes from an area. It does not delete the shapes, so they can be reassigned later.
</description>
@@ -42,91 +42,91 @@
</method>
<method name="area_get_object_instance_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="area" type="RID" />
+ <param index="0" name="area" type="RID" />
<description>
Gets the instance ID of the object the area is assigned to.
</description>
</method>
<method name="area_get_param" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.AreaParameter" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.AreaParameter" />
<description>
Returns an area parameter value. A list of available parameters is on the [enum AreaParameter] constants.
</description>
</method>
<method name="area_get_shape" qualifiers="const">
<return type="RID" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
<description>
Returns the [RID] of the nth shape of an area.
</description>
</method>
<method name="area_get_shape_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="area" type="RID" />
+ <param index="0" name="area" type="RID" />
<description>
Returns the number of shapes assigned to an area.
</description>
</method>
<method name="area_get_shape_transform" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
<description>
Returns the transform matrix of a shape within an area.
</description>
</method>
<method name="area_get_space" qualifiers="const">
<return type="RID" />
- <argument index="0" name="area" type="RID" />
+ <param index="0" name="area" type="RID" />
<description>
Returns the space assigned to the area.
</description>
</method>
<method name="area_get_transform" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="area" type="RID" />
+ <param index="0" name="area" type="RID" />
<description>
Returns the transform matrix for an area.
</description>
</method>
<method name="area_remove_shape">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
<description>
Removes a shape from an area. It does not delete the shape, so it can be reassigned later.
</description>
</method>
<method name="area_set_area_monitor_callback">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="callback" type="Callable" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="callback" type="Callable" />
<description>
</description>
</method>
<method name="area_set_collision_layer">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="layer" type="int" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="layer" type="int" />
<description>
Assigns the area to one or many physics layers.
</description>
</method>
<method name="area_set_collision_mask">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="mask" type="int" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="mask" type="int" />
<description>
Sets which physics layers the area will monitor.
</description>
</method>
<method name="area_set_monitor_callback">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="callback" type="Callable" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="callback" type="Callable" />
<description>
Sets the function to call when any body/area enters or exits the area. This callback will be called for any object interacting with the area, and takes five parameters:
1: [constant AREA_BODY_ADDED] or [constant AREA_BODY_REMOVED], depending on whether the object entered or exited the area.
@@ -138,82 +138,82 @@
</method>
<method name="area_set_monitorable">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="monitorable" type="bool" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="monitorable" type="bool" />
<description>
</description>
</method>
<method name="area_set_param">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.AreaParameter" />
- <argument index="2" name="value" type="Variant" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.AreaParameter" />
+ <param index="2" name="value" type="Variant" />
<description>
Sets the value for an area parameter. A list of available parameters is on the [enum AreaParameter] constants.
</description>
</method>
<method name="area_set_ray_pickable">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
Sets object pickable with rays.
</description>
</method>
<method name="area_set_shape">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
- <argument index="2" name="shape" type="RID" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="shape" type="RID" />
<description>
Substitutes a given area shape by another. The old shape is selected by its index, the new one by its [RID].
</description>
</method>
<method name="area_set_shape_disabled">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
- <argument index="2" name="disabled" type="bool" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="disabled" type="bool" />
<description>
</description>
</method>
<method name="area_set_shape_transform">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
- <argument index="2" name="transform" type="Transform3D" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="transform" type="Transform3D" />
<description>
Sets the transform matrix for an area shape.
</description>
</method>
<method name="area_set_space">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="space" type="RID" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="space" type="RID" />
<description>
Assigns a space to the area.
</description>
</method>
<method name="area_set_transform">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="transform" type="Transform3D" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="transform" type="Transform3D" />
<description>
Sets the transform matrix for an area.
</description>
</method>
<method name="body_add_collision_exception">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="excepted_body" type="RID" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="excepted_body" type="RID" />
<description>
Adds a body to the list of bodies exempt from collisions.
</description>
</method>
<method name="body_add_constant_central_force">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="force" type="Vector3" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector3" />
<description>
Adds a constant directional force without affecting rotation that keeps being applied over time until cleared with [code]body_set_constant_force(body, Vector3(0, 0, 0))[/code].
This is equivalent to using [method body_add_constant_force] at the body's center of mass.
@@ -221,36 +221,36 @@
</method>
<method name="body_add_constant_force">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="force" type="Vector3" />
- <argument index="2" name="position" type="Vector3" default="Vector3(0, 0, 0)" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector3" />
+ <param index="2" name="position" type="Vector3" default="Vector3(0, 0, 0)" />
<description>
Adds a constant positioned force to the body that keeps being applied over time until cleared with [code]body_set_constant_force(body, Vector3(0, 0, 0))[/code].
- [code]position[/code] is the offset from the body origin in global coordinates.
+ [param position] is the offset from the body origin in global coordinates.
</description>
</method>
<method name="body_add_constant_torque">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="torque" type="Vector3" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="torque" type="Vector3" />
<description>
Adds a constant rotational force without affecting position that keeps being applied over time until cleared with [code]body_set_constant_torque(body, Vector3(0, 0, 0))[/code].
</description>
</method>
<method name="body_add_shape">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape" type="RID" />
- <argument index="2" name="transform" type="Transform3D" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)" />
- <argument index="3" name="disabled" type="bool" default="false" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape" type="RID" />
+ <param index="2" name="transform" type="Transform3D" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)" />
+ <param index="3" name="disabled" type="bool" default="false" />
<description>
Adds a shape to the body, along with a transform matrix. Shapes are usually referenced by their index, so you should track which shape has a given index.
</description>
</method>
<method name="body_apply_central_force">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="force" type="Vector3" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector3" />
<description>
Applies a directional force without affecting rotation. A force is time dependent and meant to be applied every physics update.
This is equivalent to using [method body_apply_force] at the body's center of mass.
@@ -258,8 +258,8 @@
</method>
<method name="body_apply_central_impulse">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="impulse" type="Vector3" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="impulse" type="Vector3" />
<description>
Applies a directional impulse without affecting rotation.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
@@ -268,37 +268,37 @@
</method>
<method name="body_apply_force">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="force" type="Vector3" />
- <argument index="2" name="position" type="Vector3" default="Vector3(0, 0, 0)" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector3" />
+ <param index="2" name="position" type="Vector3" default="Vector3(0, 0, 0)" />
<description>
Applies a positioned force to the body. A force is time dependent and meant to be applied every physics update.
- [code]position[/code] is the offset from the body origin in global coordinates.
+ [param position] is the offset from the body origin in global coordinates.
</description>
</method>
<method name="body_apply_impulse">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="impulse" type="Vector3" />
- <argument index="2" name="position" type="Vector3" default="Vector3(0, 0, 0)" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="impulse" type="Vector3" />
+ <param index="2" name="position" type="Vector3" default="Vector3(0, 0, 0)" />
<description>
Applies a positioned impulse to the body.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
- [code]position[/code] is the offset from the body origin in global coordinates.
+ [param position] is the offset from the body origin in global coordinates.
</description>
</method>
<method name="body_apply_torque">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="torque" type="Vector3" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="torque" type="Vector3" />
<description>
Applies a rotational force without affecting position. A force is time dependent and meant to be applied every physics update.
</description>
</method>
<method name="body_apply_torque_impulse">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="impulse" type="Vector3" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="impulse" type="Vector3" />
<description>
Applies a rotational impulse to the body without affecting the position.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
@@ -306,15 +306,15 @@
</method>
<method name="body_attach_object_instance_id">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="id" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="id" type="int" />
<description>
Assigns the area to a descendant of [Object], so it can exist in the node tree.
</description>
</method>
<method name="body_clear_shapes">
<return type="void" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Removes all shapes from a body.
</description>
@@ -326,21 +326,28 @@
</method>
<method name="body_get_collision_layer" qualifiers="const">
<return type="int" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns the physics layer or layers a body belongs to.
</description>
</method>
<method name="body_get_collision_mask" qualifiers="const">
<return type="int" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns the physics layer or layers a body can collide with.
</description>
</method>
+ <method name="body_get_collision_priority" qualifiers="const">
+ <return type="float" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ Returns the body's collision priority.
+ </description>
+ </method>
<method name="body_get_constant_force" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns the body's total constant positional forces applied during each physics update.
See [method body_add_constant_force] and [method body_add_constant_central_force].
@@ -348,7 +355,7 @@
</method>
<method name="body_get_constant_torque" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns the body's total constant rotational forces applied during each physics update.
See [method body_add_constant_torque].
@@ -356,103 +363,103 @@
</method>
<method name="body_get_direct_state">
<return type="PhysicsDirectBodyState3D" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns the [PhysicsDirectBodyState3D] of the body. Returns [code]null[/code] if the body is destroyed or removed from the physics space.
</description>
</method>
<method name="body_get_max_contacts_reported" qualifiers="const">
<return type="int" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns the maximum contacts that can be reported. See [method body_set_max_contacts_reported].
</description>
</method>
<method name="body_get_mode" qualifiers="const">
<return type="int" enum="PhysicsServer3D.BodyMode" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns the body mode.
</description>
</method>
<method name="body_get_object_instance_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Gets the instance ID of the object the area is assigned to.
</description>
</method>
<method name="body_get_param" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.BodyParameter" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.BodyParameter" />
<description>
Returns the value of a body parameter. A list of available parameters is on the [enum BodyParameter] constants.
</description>
</method>
<method name="body_get_shape" qualifiers="const">
<return type="RID" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
<description>
Returns the [RID] of the nth shape of a body.
</description>
</method>
<method name="body_get_shape_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns the number of shapes assigned to a body.
</description>
</method>
<method name="body_get_shape_transform" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
<description>
Returns the transform matrix of a body shape.
</description>
</method>
<method name="body_get_space" qualifiers="const">
<return type="RID" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns the [RID] of the space assigned to a body.
</description>
</method>
<method name="body_get_state" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="state" type="int" enum="PhysicsServer3D.BodyState" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="state" type="int" enum="PhysicsServer3D.BodyState" />
<description>
Returns a body state.
</description>
</method>
<method name="body_is_axis_locked" qualifiers="const">
<return type="bool" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="axis" type="int" enum="PhysicsServer3D.BodyAxis" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="axis" type="int" enum="PhysicsServer3D.BodyAxis" />
<description>
</description>
</method>
<method name="body_is_continuous_collision_detection_enabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
If [code]true[/code], the continuous collision detection mode is enabled.
</description>
</method>
<method name="body_is_omitting_force_integration" qualifiers="const">
<return type="bool" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns whether a body uses a callback function to calculate its own physics (see [method body_set_force_integration_callback]).
</description>
</method>
<method name="body_remove_collision_exception">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="excepted_body" type="RID" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="excepted_body" type="RID" />
<description>
Removes a body from the list of bodies exempt from collisions.
Continuous collision detection tries to predict where a moving body will collide, instead of moving it and correcting its movement if it collided.
@@ -460,55 +467,63 @@
</method>
<method name="body_remove_shape">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
<description>
Removes a shape from a body. The shape is not deleted, so it can be reused afterwards.
</description>
</method>
<method name="body_reset_mass_properties">
<return type="void" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Restores the default inertia and center of mass based on shapes to cancel any custom values previously set using [method body_set_param].
</description>
</method>
<method name="body_set_axis_lock">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="axis" type="int" enum="PhysicsServer3D.BodyAxis" />
- <argument index="2" name="lock" type="bool" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="axis" type="int" enum="PhysicsServer3D.BodyAxis" />
+ <param index="2" name="lock" type="bool" />
<description>
</description>
</method>
<method name="body_set_axis_velocity">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="axis_velocity" type="Vector3" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="axis_velocity" type="Vector3" />
<description>
Sets an axis velocity. The velocity in the given vector axis will be set as the given vector length. This is useful for jumping behavior.
</description>
</method>
<method name="body_set_collision_layer">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="layer" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="layer" type="int" />
<description>
Sets the physics layer or layers a body belongs to.
</description>
</method>
<method name="body_set_collision_mask">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="mask" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="mask" type="int" />
<description>
Sets the physics layer or layers a body can collide with.
</description>
</method>
+ <method name="body_set_collision_priority">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="priority" type="float" />
+ <description>
+ Sets the body's collision priority.
+ </description>
+ </method>
<method name="body_set_constant_force">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="force" type="Vector3" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector3" />
<description>
Sets the body's total constant positional forces applied during each physics update.
See [method body_add_constant_force] and [method body_add_constant_central_force].
@@ -516,8 +531,8 @@
</method>
<method name="body_set_constant_torque">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="torque" type="Vector3" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="torque" type="Vector3" />
<description>
Sets the body's total constant rotational forces applied during each physics update.
See [method body_add_constant_torque].
@@ -525,8 +540,8 @@
</method>
<method name="body_set_enable_continuous_collision_detection">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
If [code]true[/code], the continuous collision detection mode is enabled.
Continuous collision detection tries to predict where a moving body will collide, instead of moving it and correcting its movement if it collided.
@@ -534,9 +549,9 @@
</method>
<method name="body_set_force_integration_callback">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="callable" type="Callable" />
- <argument index="2" name="userdata" type="Variant" default="null" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="callable" type="Callable" />
+ <param index="2" name="userdata" type="Variant" default="null" />
<description>
Sets the function used to calculate physics for an object, if that object allows it (see [method body_set_omit_force_integration]).
The force integration function takes 2 arguments:
@@ -546,93 +561,93 @@
</method>
<method name="body_set_max_contacts_reported">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="amount" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="amount" type="int" />
<description>
- Sets the maximum contacts to report. Bodies can keep a log of the contacts with other bodies, this is enabled by setting the maximum amount of contacts reported to a number greater than 0.
+ Sets the maximum contacts to report. Bodies can keep a log of the contacts with other bodies. This is enabled by setting the maximum number of contacts reported to a number greater than 0.
</description>
</method>
<method name="body_set_mode">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="mode" type="int" enum="PhysicsServer3D.BodyMode" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="mode" type="int" enum="PhysicsServer3D.BodyMode" />
<description>
Sets the body mode, from one of the [enum BodyMode] constants.
</description>
</method>
<method name="body_set_omit_force_integration">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
Sets whether a body uses a callback function to calculate its own physics (see [method body_set_force_integration_callback]).
</description>
</method>
<method name="body_set_param">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.BodyParameter" />
- <argument index="2" name="value" type="Variant" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.BodyParameter" />
+ <param index="2" name="value" type="Variant" />
<description>
Sets a body parameter. A list of available parameters is on the [enum BodyParameter] constants.
</description>
</method>
<method name="body_set_ray_pickable">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
- Sets the body pickable with rays if [code]enabled[/code] is set.
+ Sets the body pickable with rays if [param enable] is set.
</description>
</method>
<method name="body_set_shape">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
- <argument index="2" name="shape" type="RID" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="shape" type="RID" />
<description>
Substitutes a given body shape by another. The old shape is selected by its index, the new one by its [RID].
</description>
</method>
<method name="body_set_shape_disabled">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
- <argument index="2" name="disabled" type="bool" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="disabled" type="bool" />
<description>
</description>
</method>
<method name="body_set_shape_transform">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
- <argument index="2" name="transform" type="Transform3D" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="transform" type="Transform3D" />
<description>
Sets the transform matrix for a body shape.
</description>
</method>
<method name="body_set_space">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="space" type="RID" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="space" type="RID" />
<description>
Assigns a space to the body (see [method space_create]).
</description>
</method>
<method name="body_set_state">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="state" type="int" enum="PhysicsServer3D.BodyState" />
- <argument index="2" name="value" type="Variant" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="state" type="int" enum="PhysicsServer3D.BodyState" />
+ <param index="2" name="value" type="Variant" />
<description>
Sets a body state (see [enum BodyState] constants).
</description>
</method>
<method name="body_test_motion">
<return type="bool" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="parameters" type="PhysicsTestMotionParameters3D" />
- <argument index="2" name="result" type="PhysicsTestMotionResult3D" default="null" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="parameters" type="PhysicsTestMotionParameters3D" />
+ <param index="2" name="result" type="PhysicsTestMotionResult3D" default="null" />
<description>
Returns [code]true[/code] if a collision would result from moving along a motion vector from a given point in space. [PhysicsTestMotionParameters3D] is passed to set motion parameters. [PhysicsTestMotionResult3D] can be passed to return additional information.
</description>
@@ -654,17 +669,17 @@
</method>
<method name="cone_twist_joint_get_param" qualifiers="const">
<return type="float" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.ConeTwistJointParam" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.ConeTwistJointParam" />
<description>
Gets a cone_twist_joint parameter (see [enum ConeTwistJointParam] constants).
</description>
</method>
<method name="cone_twist_joint_set_param">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.ConeTwistJointParam" />
- <argument index="2" name="value" type="float" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.ConeTwistJointParam" />
+ <param index="2" name="value" type="float" />
<description>
Sets a cone_twist_joint parameter (see [enum ConeTwistJointParam] constants).
</description>
@@ -686,52 +701,52 @@
</method>
<method name="free_rid">
<return type="void" />
- <argument index="0" name="rid" type="RID" />
+ <param index="0" name="rid" type="RID" />
<description>
Destroys any of the objects created by PhysicsServer3D. If the [RID] passed is not one of the objects that can be created by PhysicsServer3D, an error will be sent to the console.
</description>
</method>
<method name="generic_6dof_joint_get_flag" qualifiers="const">
<return type="bool" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="axis" type="int" enum="Vector3.Axis" />
- <argument index="2" name="flag" type="int" enum="PhysicsServer3D.G6DOFJointAxisFlag" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="axis" type="int" enum="Vector3.Axis" />
+ <param index="2" name="flag" type="int" enum="PhysicsServer3D.G6DOFJointAxisFlag" />
<description>
Gets a generic_6_DOF_joint flag (see [enum G6DOFJointAxisFlag] constants).
</description>
</method>
<method name="generic_6dof_joint_get_param" qualifiers="const">
<return type="float" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="axis" type="int" enum="Vector3.Axis" />
- <argument index="2" name="param" type="int" enum="PhysicsServer3D.G6DOFJointAxisParam" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="axis" type="int" enum="Vector3.Axis" />
+ <param index="2" name="param" type="int" enum="PhysicsServer3D.G6DOFJointAxisParam" />
<description>
Gets a generic_6_DOF_joint parameter (see [enum G6DOFJointAxisParam] constants).
</description>
</method>
<method name="generic_6dof_joint_set_flag">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="axis" type="int" enum="Vector3.Axis" />
- <argument index="2" name="flag" type="int" enum="PhysicsServer3D.G6DOFJointAxisFlag" />
- <argument index="3" name="enable" type="bool" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="axis" type="int" enum="Vector3.Axis" />
+ <param index="2" name="flag" type="int" enum="PhysicsServer3D.G6DOFJointAxisFlag" />
+ <param index="3" name="enable" type="bool" />
<description>
Sets a generic_6_DOF_joint flag (see [enum G6DOFJointAxisFlag] constants).
</description>
</method>
<method name="generic_6dof_joint_set_param">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="axis" type="int" enum="Vector3.Axis" />
- <argument index="2" name="param" type="int" enum="PhysicsServer3D.G6DOFJointAxisParam" />
- <argument index="3" name="value" type="float" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="axis" type="int" enum="Vector3.Axis" />
+ <param index="2" name="param" type="int" enum="PhysicsServer3D.G6DOFJointAxisParam" />
+ <param index="3" name="value" type="float" />
<description>
Sets a generic_6_DOF_joint parameter (see [enum G6DOFJointAxisParam] constants).
</description>
</method>
<method name="get_process_info">
<return type="int" />
- <argument index="0" name="process_info" type="int" enum="PhysicsServer3D.ProcessInfo" />
+ <param index="0" name="process_info" type="int" enum="PhysicsServer3D.ProcessInfo" />
<description>
Returns information about the current state of the 3D physics engine. See [enum ProcessInfo] for a list of available states.
</description>
@@ -743,41 +758,41 @@
</method>
<method name="hinge_joint_get_flag" qualifiers="const">
<return type="bool" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="flag" type="int" enum="PhysicsServer3D.HingeJointFlag" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="flag" type="int" enum="PhysicsServer3D.HingeJointFlag" />
<description>
Gets a hinge_joint flag (see [enum HingeJointFlag] constants).
</description>
</method>
<method name="hinge_joint_get_param" qualifiers="const">
<return type="float" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.HingeJointParam" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.HingeJointParam" />
<description>
Gets a hinge_joint parameter (see [enum HingeJointParam]).
</description>
</method>
<method name="hinge_joint_set_flag">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="flag" type="int" enum="PhysicsServer3D.HingeJointFlag" />
- <argument index="2" name="enabled" type="bool" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="flag" type="int" enum="PhysicsServer3D.HingeJointFlag" />
+ <param index="2" name="enabled" type="bool" />
<description>
Sets a hinge_joint flag (see [enum HingeJointFlag] constants).
</description>
</method>
<method name="hinge_joint_set_param">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.HingeJointParam" />
- <argument index="2" name="value" type="float" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.HingeJointParam" />
+ <param index="2" name="value" type="float" />
<description>
Sets a hinge_joint parameter (see [enum HingeJointParam] constants).
</description>
</method>
<method name="joint_clear">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
+ <param index="0" name="joint" type="RID" />
<description>
</description>
</method>
@@ -788,119 +803,119 @@
</method>
<method name="joint_get_solver_priority" qualifiers="const">
<return type="int" />
- <argument index="0" name="joint" type="RID" />
+ <param index="0" name="joint" type="RID" />
<description>
Gets the priority value of the Joint3D.
</description>
</method>
<method name="joint_get_type" qualifiers="const">
<return type="int" enum="PhysicsServer3D.JointType" />
- <argument index="0" name="joint" type="RID" />
+ <param index="0" name="joint" type="RID" />
<description>
Returns the type of the Joint3D.
</description>
</method>
<method name="joint_make_cone_twist">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="body_A" type="RID" />
- <argument index="2" name="local_ref_A" type="Transform3D" />
- <argument index="3" name="body_B" type="RID" />
- <argument index="4" name="local_ref_B" type="Transform3D" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="body_A" type="RID" />
+ <param index="2" name="local_ref_A" type="Transform3D" />
+ <param index="3" name="body_B" type="RID" />
+ <param index="4" name="local_ref_B" type="Transform3D" />
<description>
</description>
</method>
<method name="joint_make_generic_6dof">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="body_A" type="RID" />
- <argument index="2" name="local_ref_A" type="Transform3D" />
- <argument index="3" name="body_B" type="RID" />
- <argument index="4" name="local_ref_B" type="Transform3D" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="body_A" type="RID" />
+ <param index="2" name="local_ref_A" type="Transform3D" />
+ <param index="3" name="body_B" type="RID" />
+ <param index="4" name="local_ref_B" type="Transform3D" />
<description>
</description>
</method>
<method name="joint_make_hinge">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="body_A" type="RID" />
- <argument index="2" name="hinge_A" type="Transform3D" />
- <argument index="3" name="body_B" type="RID" />
- <argument index="4" name="hinge_B" type="Transform3D" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="body_A" type="RID" />
+ <param index="2" name="hinge_A" type="Transform3D" />
+ <param index="3" name="body_B" type="RID" />
+ <param index="4" name="hinge_B" type="Transform3D" />
<description>
</description>
</method>
<method name="joint_make_pin">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="body_A" type="RID" />
- <argument index="2" name="local_A" type="Vector3" />
- <argument index="3" name="body_B" type="RID" />
- <argument index="4" name="local_B" type="Vector3" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="body_A" type="RID" />
+ <param index="2" name="local_A" type="Vector3" />
+ <param index="3" name="body_B" type="RID" />
+ <param index="4" name="local_B" type="Vector3" />
<description>
</description>
</method>
<method name="joint_make_slider">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="body_A" type="RID" />
- <argument index="2" name="local_ref_A" type="Transform3D" />
- <argument index="3" name="body_B" type="RID" />
- <argument index="4" name="local_ref_B" type="Transform3D" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="body_A" type="RID" />
+ <param index="2" name="local_ref_A" type="Transform3D" />
+ <param index="3" name="body_B" type="RID" />
+ <param index="4" name="local_ref_B" type="Transform3D" />
<description>
</description>
</method>
<method name="joint_set_solver_priority">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="priority" type="int" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="priority" type="int" />
<description>
Sets the priority value of the Joint3D.
</description>
</method>
<method name="pin_joint_get_local_a" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="joint" type="RID" />
+ <param index="0" name="joint" type="RID" />
<description>
Returns position of the joint in the local space of body a of the joint.
</description>
</method>
<method name="pin_joint_get_local_b" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="joint" type="RID" />
+ <param index="0" name="joint" type="RID" />
<description>
Returns position of the joint in the local space of body b of the joint.
</description>
</method>
<method name="pin_joint_get_param" qualifiers="const">
<return type="float" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.PinJointParam" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.PinJointParam" />
<description>
Gets a pin_joint parameter (see [enum PinJointParam] constants).
</description>
</method>
<method name="pin_joint_set_local_a">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="local_A" type="Vector3" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="local_A" type="Vector3" />
<description>
Sets position of the joint in the local space of body a of the joint.
</description>
</method>
<method name="pin_joint_set_local_b">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="local_B" type="Vector3" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="local_B" type="Vector3" />
<description>
Sets position of the joint in the local space of body b of the joint.
</description>
</method>
<method name="pin_joint_set_param">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.PinJointParam" />
- <argument index="2" name="value" type="float" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.PinJointParam" />
+ <param index="2" name="value" type="float" />
<description>
Sets a pin_joint parameter (see [enum PinJointParam] constants).
</description>
@@ -912,53 +927,53 @@
</method>
<method name="set_active">
<return type="void" />
- <argument index="0" name="active" type="bool" />
+ <param index="0" name="active" type="bool" />
<description>
Activates or deactivates the 3D physics engine.
</description>
</method>
<method name="shape_get_data" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="shape" type="RID" />
+ <param index="0" name="shape" type="RID" />
<description>
Returns the shape data.
</description>
</method>
<method name="shape_get_type" qualifiers="const">
<return type="int" enum="PhysicsServer3D.ShapeType" />
- <argument index="0" name="shape" type="RID" />
+ <param index="0" name="shape" type="RID" />
<description>
Returns the type of shape (see [enum ShapeType] constants).
</description>
</method>
<method name="shape_set_data">
<return type="void" />
- <argument index="0" name="shape" type="RID" />
- <argument index="1" name="data" type="Variant" />
+ <param index="0" name="shape" type="RID" />
+ <param index="1" name="data" type="Variant" />
<description>
Sets the shape data that defines its shape and size. The data to be passed depends on the kind of shape created [method shape_get_type].
</description>
</method>
<method name="slider_joint_get_param" qualifiers="const">
<return type="float" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.SliderJointParam" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.SliderJointParam" />
<description>
Gets a slider_joint parameter (see [enum SliderJointParam] constants).
</description>
</method>
<method name="slider_joint_set_param">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.SliderJointParam" />
- <argument index="2" name="value" type="float" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.SliderJointParam" />
+ <param index="2" name="value" type="float" />
<description>
Gets a slider_joint parameter (see [enum SliderJointParam] constants).
</description>
</method>
<method name="soft_body_get_bounds" qualifiers="const">
<return type="AABB" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
</description>
</method>
@@ -970,39 +985,39 @@
</method>
<method name="space_get_direct_state">
<return type="PhysicsDirectSpaceState3D" />
- <argument index="0" name="space" type="RID" />
+ <param index="0" name="space" type="RID" />
<description>
Returns the state of a space, a [PhysicsDirectSpaceState3D]. This object can be used to make collision/intersection queries.
</description>
</method>
<method name="space_get_param" qualifiers="const">
<return type="float" />
- <argument index="0" name="space" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.SpaceParameter" />
+ <param index="0" name="space" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.SpaceParameter" />
<description>
Returns the value of a space parameter.
</description>
</method>
<method name="space_is_active" qualifiers="const">
<return type="bool" />
- <argument index="0" name="space" type="RID" />
+ <param index="0" name="space" type="RID" />
<description>
Returns whether the space is active.
</description>
</method>
<method name="space_set_active">
<return type="void" />
- <argument index="0" name="space" type="RID" />
- <argument index="1" name="active" type="bool" />
+ <param index="0" name="space" type="RID" />
+ <param index="1" name="active" type="bool" />
<description>
Marks a space as active. It will not have an effect, unless it is assigned to an area or body.
</description>
</method>
<method name="space_set_param">
<return type="void" />
- <argument index="0" name="space" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.SpaceParameter" />
- <argument index="2" name="value" type="float" />
+ <param index="0" name="space" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.SpaceParameter" />
+ <param index="2" name="value" type="float" />
<description>
Sets the value for a space parameter. A list of available parameters is on the [enum SpaceParameter] constants.
</description>
@@ -1325,11 +1340,11 @@
<constant name="BODY_MODE_KINEMATIC" value="1" enum="BodyMode">
Constant for kinematic bodies. In this mode, a body can be only moved by user code and collides with other bodies along its path.
</constant>
- <constant name="BODY_MODE_DYNAMIC" value="2" enum="BodyMode">
- Constant for dynamic bodies. In this mode, a body can be pushed by other bodies and has forces applied.
+ <constant name="BODY_MODE_RIGID" value="2" enum="BodyMode">
+ Constant for rigid bodies. In this mode, a body can be pushed by other bodies and has forces applied.
</constant>
- <constant name="BODY_MODE_DYNAMIC_LINEAR" value="3" enum="BodyMode">
- Constant for linear dynamic bodies. In this mode, a body is dynamic but can not rotate, and only its linear velocity is affected by external forces.
+ <constant name="BODY_MODE_RIGID_LINEAR" value="3" enum="BodyMode">
+ Constant for linear rigid bodies. In this mode, a body can not rotate, and only its linear velocity is affected by external forces.
</constant>
<constant name="BODY_PARAM_BOUNCE" value="0" enum="BodyParameter">
Constant to set/get a body's bounce factor.
@@ -1422,7 +1437,7 @@
Constant to set/get the maximum time of activity. A body marked as potentially inactive for both linear and angular velocity will be put to sleep after this time.
</constant>
<constant name="SPACE_PARAM_SOLVER_ITERATIONS" value="7" enum="SpaceParameter">
- Constant to set/get the number of solver iterations for contacts and constraints. The greater the amount of iterations, the more accurate the collisions and constraints will be. However, a greater amount of iterations requires more CPU power, which can decrease performance.
+ Constant to set/get the number of solver iterations for contacts and constraints. The greater the number of iterations, the more accurate the collisions and constraints will be. However, a greater number of iterations requires more CPU power, which can decrease performance.
</constant>
<constant name="BODY_AXIS_LINEAR_X" value="1" enum="BodyAxis">
</constant>
diff --git a/doc/classes/PhysicsServer3DExtension.xml b/doc/classes/PhysicsServer3DExtension.xml
index 795f5b86dd..200065de54 100644
--- a/doc/classes/PhysicsServer3DExtension.xml
+++ b/doc/classes/PhysicsServer3DExtension.xml
@@ -9,23 +9,23 @@
<methods>
<method name="_area_add_shape" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="shape" type="RID" />
- <argument index="2" name="transform" type="Transform3D" />
- <argument index="3" name="disabled" type="bool" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape" type="RID" />
+ <param index="2" name="transform" type="Transform3D" />
+ <param index="3" name="disabled" type="bool" />
<description>
</description>
</method>
<method name="_area_attach_object_instance_id" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="id" type="int" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="id" type="int" />
<description>
</description>
</method>
<method name="_area_clear_shapes" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="area" type="RID" />
+ <param index="0" name="area" type="RID" />
<description>
</description>
</method>
@@ -36,236 +36,236 @@
</method>
<method name="_area_get_object_instance_id" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="area" type="RID" />
+ <param index="0" name="area" type="RID" />
<description>
</description>
</method>
<method name="_area_get_param" qualifiers="virtual const">
<return type="Variant" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.AreaParameter" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.AreaParameter" />
<description>
</description>
</method>
<method name="_area_get_shape" qualifiers="virtual const">
<return type="RID" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
<description>
</description>
</method>
<method name="_area_get_shape_count" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="area" type="RID" />
+ <param index="0" name="area" type="RID" />
<description>
</description>
</method>
<method name="_area_get_shape_transform" qualifiers="virtual const">
<return type="Transform3D" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
<description>
</description>
</method>
<method name="_area_get_space" qualifiers="virtual const">
<return type="RID" />
- <argument index="0" name="area" type="RID" />
+ <param index="0" name="area" type="RID" />
<description>
</description>
</method>
<method name="_area_get_transform" qualifiers="virtual const">
<return type="Transform3D" />
- <argument index="0" name="area" type="RID" />
+ <param index="0" name="area" type="RID" />
<description>
</description>
</method>
<method name="_area_remove_shape" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
<description>
</description>
</method>
<method name="_area_set_area_monitor_callback" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="callback" type="Callable" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="callback" type="Callable" />
<description>
</description>
</method>
<method name="_area_set_collision_layer" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="layer" type="int" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="layer" type="int" />
<description>
</description>
</method>
<method name="_area_set_collision_mask" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="mask" type="int" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="mask" type="int" />
<description>
</description>
</method>
<method name="_area_set_monitor_callback" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="callback" type="Callable" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="callback" type="Callable" />
<description>
</description>
</method>
<method name="_area_set_monitorable" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="monitorable" type="bool" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="monitorable" type="bool" />
<description>
</description>
</method>
<method name="_area_set_param" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.AreaParameter" />
- <argument index="2" name="value" type="Variant" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.AreaParameter" />
+ <param index="2" name="value" type="Variant" />
<description>
</description>
</method>
<method name="_area_set_ray_pickable" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
</description>
</method>
<method name="_area_set_shape" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
- <argument index="2" name="shape" type="RID" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="shape" type="RID" />
<description>
</description>
</method>
<method name="_area_set_shape_disabled" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
- <argument index="2" name="disabled" type="bool" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="disabled" type="bool" />
<description>
</description>
</method>
<method name="_area_set_shape_transform" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
- <argument index="2" name="transform" type="Transform3D" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="transform" type="Transform3D" />
<description>
</description>
</method>
<method name="_area_set_space" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="space" type="RID" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="space" type="RID" />
<description>
</description>
</method>
<method name="_area_set_transform" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="area" type="RID" />
- <argument index="1" name="transform" type="Transform3D" />
+ <param index="0" name="area" type="RID" />
+ <param index="1" name="transform" type="Transform3D" />
<description>
</description>
</method>
<method name="_body_add_collision_exception" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="excepted_body" type="RID" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="excepted_body" type="RID" />
<description>
</description>
</method>
<method name="_body_add_constant_central_force" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="force" type="Vector3" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector3" />
<description>
</description>
</method>
<method name="_body_add_constant_force" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="force" type="Vector3" />
- <argument index="2" name="position" type="Vector3" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector3" />
+ <param index="2" name="position" type="Vector3" />
<description>
</description>
</method>
<method name="_body_add_constant_torque" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="torque" type="Vector3" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="torque" type="Vector3" />
<description>
</description>
</method>
<method name="_body_add_shape" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape" type="RID" />
- <argument index="2" name="transform" type="Transform3D" />
- <argument index="3" name="disabled" type="bool" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape" type="RID" />
+ <param index="2" name="transform" type="Transform3D" />
+ <param index="3" name="disabled" type="bool" />
<description>
</description>
</method>
<method name="_body_apply_central_force" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="force" type="Vector3" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector3" />
<description>
</description>
</method>
<method name="_body_apply_central_impulse" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="impulse" type="Vector3" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="impulse" type="Vector3" />
<description>
</description>
</method>
<method name="_body_apply_force" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="force" type="Vector3" />
- <argument index="2" name="position" type="Vector3" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector3" />
+ <param index="2" name="position" type="Vector3" />
<description>
</description>
</method>
<method name="_body_apply_impulse" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="impulse" type="Vector3" />
- <argument index="2" name="position" type="Vector3" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="impulse" type="Vector3" />
+ <param index="2" name="position" type="Vector3" />
<description>
</description>
</method>
<method name="_body_apply_torque" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="torque" type="Vector3" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="torque" type="Vector3" />
<description>
</description>
</method>
<method name="_body_apply_torque_impulse" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="impulse" type="Vector3" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="impulse" type="Vector3" />
<description>
</description>
</method>
<method name="_body_attach_object_instance_id" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="id" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="id" type="int" />
<description>
</description>
</method>
<method name="_body_clear_shapes" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
</description>
</method>
@@ -276,273 +276,286 @@
</method>
<method name="_body_get_collision_layer" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
</description>
</method>
<method name="_body_get_collision_mask" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_get_collision_priority" qualifiers="virtual const">
+ <return type="float" />
+ <param index="0" name="body" type="RID" />
<description>
</description>
</method>
<method name="_body_get_constant_force" qualifiers="virtual const">
<return type="Vector3" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
</description>
</method>
<method name="_body_get_constant_torque" qualifiers="virtual const">
<return type="Vector3" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
</description>
</method>
<method name="_body_get_direct_state" qualifiers="virtual">
<return type="PhysicsDirectBodyState3D" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
</description>
</method>
<method name="_body_get_max_contacts_reported" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
</description>
</method>
<method name="_body_get_mode" qualifiers="virtual const">
<return type="int" enum="PhysicsServer3D.BodyMode" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
</description>
</method>
<method name="_body_get_object_instance_id" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
</description>
</method>
<method name="_body_get_param" qualifiers="virtual const">
<return type="Variant" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.BodyParameter" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.BodyParameter" />
<description>
</description>
</method>
<method name="_body_get_shape" qualifiers="virtual const">
<return type="RID" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
<description>
</description>
</method>
<method name="_body_get_shape_count" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
</description>
</method>
<method name="_body_get_shape_transform" qualifiers="virtual const">
<return type="Transform3D" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
<description>
</description>
</method>
<method name="_body_get_space" qualifiers="virtual const">
<return type="RID" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
</description>
</method>
<method name="_body_get_state" qualifiers="virtual const">
<return type="Variant" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="state" type="int" enum="PhysicsServer3D.BodyState" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="state" type="int" enum="PhysicsServer3D.BodyState" />
<description>
</description>
</method>
<method name="_body_is_axis_locked" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="axis" type="int" enum="PhysicsServer3D.BodyAxis" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="axis" type="int" enum="PhysicsServer3D.BodyAxis" />
<description>
</description>
</method>
<method name="_body_is_continuous_collision_detection_enabled" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
</description>
</method>
<method name="_body_is_omitting_force_integration" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
</description>
</method>
<method name="_body_remove_collision_exception" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="excepted_body" type="RID" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="excepted_body" type="RID" />
<description>
</description>
</method>
<method name="_body_remove_shape" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
<description>
</description>
</method>
<method name="_body_reset_mass_properties" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
</description>
</method>
<method name="_body_set_axis_lock" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="axis" type="int" enum="PhysicsServer3D.BodyAxis" />
- <argument index="2" name="lock" type="bool" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="axis" type="int" enum="PhysicsServer3D.BodyAxis" />
+ <param index="2" name="lock" type="bool" />
<description>
</description>
</method>
<method name="_body_set_axis_velocity" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="axis_velocity" type="Vector3" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="axis_velocity" type="Vector3" />
<description>
</description>
</method>
<method name="_body_set_collision_layer" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="layer" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="layer" type="int" />
<description>
</description>
</method>
<method name="_body_set_collision_mask" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="mask" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="mask" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_body_set_collision_priority" qualifiers="virtual">
+ <return type="void" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="priority" type="float" />
<description>
</description>
</method>
<method name="_body_set_constant_force" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="force" type="Vector3" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="force" type="Vector3" />
<description>
</description>
</method>
<method name="_body_set_constant_torque" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="torque" type="Vector3" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="torque" type="Vector3" />
<description>
</description>
</method>
<method name="_body_set_enable_continuous_collision_detection" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
</description>
</method>
<method name="_body_set_force_integration_callback" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="callable" type="Callable" />
- <argument index="2" name="userdata" type="Variant" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="callable" type="Callable" />
+ <param index="2" name="userdata" type="Variant" />
<description>
</description>
</method>
<method name="_body_set_max_contacts_reported" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="amount" type="int" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="amount" type="int" />
<description>
</description>
</method>
<method name="_body_set_mode" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="mode" type="int" enum="PhysicsServer3D.BodyMode" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="mode" type="int" enum="PhysicsServer3D.BodyMode" />
<description>
</description>
</method>
<method name="_body_set_omit_force_integration" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
</description>
</method>
<method name="_body_set_param" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.BodyParameter" />
- <argument index="2" name="value" type="Variant" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.BodyParameter" />
+ <param index="2" name="value" type="Variant" />
<description>
</description>
</method>
<method name="_body_set_ray_pickable" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
</description>
</method>
<method name="_body_set_shape" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
- <argument index="2" name="shape" type="RID" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="shape" type="RID" />
<description>
</description>
</method>
<method name="_body_set_shape_disabled" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
- <argument index="2" name="disabled" type="bool" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="disabled" type="bool" />
<description>
</description>
</method>
<method name="_body_set_shape_transform" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="shape_idx" type="int" />
- <argument index="2" name="transform" type="Transform3D" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="shape_idx" type="int" />
+ <param index="2" name="transform" type="Transform3D" />
<description>
</description>
</method>
<method name="_body_set_space" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="space" type="RID" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="space" type="RID" />
<description>
</description>
</method>
<method name="_body_set_state" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="state" type="int" enum="PhysicsServer3D.BodyState" />
- <argument index="2" name="value" type="Variant" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="state" type="int" enum="PhysicsServer3D.BodyState" />
+ <param index="2" name="value" type="Variant" />
<description>
</description>
</method>
<method name="_body_test_motion" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="body" type="RID" />
- <argument index="1" name="from" type="Transform3D" />
- <argument index="2" name="motion" type="Vector3" />
- <argument index="3" name="margin" type="float" />
- <argument index="4" name="max_collisions" type="int" />
- <argument index="5" name="collide_separation_ray" type="bool" />
- <argument index="6" name="result" type="PhysicsServer3DExtensionMotionResult*" />
+ <param index="0" name="body" type="RID" />
+ <param index="1" name="from" type="Transform3D" />
+ <param index="2" name="motion" type="Vector3" />
+ <param index="3" name="margin" type="float" />
+ <param index="4" name="max_collisions" type="int" />
+ <param index="5" name="collide_separation_ray" type="bool" />
+ <param index="6" name="result" type="PhysicsServer3DExtensionMotionResult*" />
<description>
</description>
</method>
@@ -563,16 +576,16 @@
</method>
<method name="_cone_twist_joint_get_param" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.ConeTwistJointParam" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.ConeTwistJointParam" />
<description>
</description>
</method>
<method name="_cone_twist_joint_set_param" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.ConeTwistJointParam" />
- <argument index="2" name="value" type="float" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.ConeTwistJointParam" />
+ <param index="2" name="value" type="float" />
<description>
</description>
</method>
@@ -593,47 +606,47 @@
</method>
<method name="_free_rid" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="rid" type="RID" />
+ <param index="0" name="rid" type="RID" />
<description>
</description>
</method>
<method name="_generic_6dof_joint_get_flag" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="axis" type="int" enum="Vector3.Axis" />
- <argument index="2" name="flag" type="int" enum="PhysicsServer3D.G6DOFJointAxisFlag" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="axis" type="int" enum="Vector3.Axis" />
+ <param index="2" name="flag" type="int" enum="PhysicsServer3D.G6DOFJointAxisFlag" />
<description>
</description>
</method>
<method name="_generic_6dof_joint_get_param" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="axis" type="int" enum="Vector3.Axis" />
- <argument index="2" name="param" type="int" enum="PhysicsServer3D.G6DOFJointAxisParam" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="axis" type="int" enum="Vector3.Axis" />
+ <param index="2" name="param" type="int" enum="PhysicsServer3D.G6DOFJointAxisParam" />
<description>
</description>
</method>
<method name="_generic_6dof_joint_set_flag" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="axis" type="int" enum="Vector3.Axis" />
- <argument index="2" name="flag" type="int" enum="PhysicsServer3D.G6DOFJointAxisFlag" />
- <argument index="3" name="enable" type="bool" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="axis" type="int" enum="Vector3.Axis" />
+ <param index="2" name="flag" type="int" enum="PhysicsServer3D.G6DOFJointAxisFlag" />
+ <param index="3" name="enable" type="bool" />
<description>
</description>
</method>
<method name="_generic_6dof_joint_set_param" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="axis" type="int" enum="Vector3.Axis" />
- <argument index="2" name="param" type="int" enum="PhysicsServer3D.G6DOFJointAxisParam" />
- <argument index="3" name="value" type="float" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="axis" type="int" enum="Vector3.Axis" />
+ <param index="2" name="param" type="int" enum="PhysicsServer3D.G6DOFJointAxisParam" />
+ <param index="3" name="value" type="float" />
<description>
</description>
</method>
<method name="_get_process_info" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="process_info" type="int" enum="PhysicsServer3D.ProcessInfo" />
+ <param index="0" name="process_info" type="int" enum="PhysicsServer3D.ProcessInfo" />
<description>
</description>
</method>
@@ -644,37 +657,37 @@
</method>
<method name="_hinge_joint_get_flag" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="flag" type="int" enum="PhysicsServer3D.HingeJointFlag" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="flag" type="int" enum="PhysicsServer3D.HingeJointFlag" />
<description>
</description>
</method>
<method name="_hinge_joint_get_param" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.HingeJointParam" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.HingeJointParam" />
<description>
</description>
</method>
<method name="_hinge_joint_set_flag" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="flag" type="int" enum="PhysicsServer3D.HingeJointFlag" />
- <argument index="2" name="enabled" type="bool" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="flag" type="int" enum="PhysicsServer3D.HingeJointFlag" />
+ <param index="2" name="enabled" type="bool" />
<description>
</description>
</method>
<method name="_hinge_joint_set_param" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.HingeJointParam" />
- <argument index="2" name="value" type="float" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.HingeJointParam" />
+ <param index="2" name="value" type="float" />
<description>
</description>
</method>
<method name="_joint_clear" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
+ <param index="0" name="joint" type="RID" />
<description>
</description>
</method>
@@ -685,111 +698,111 @@
</method>
<method name="_joint_get_solver_priority" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="joint" type="RID" />
+ <param index="0" name="joint" type="RID" />
<description>
</description>
</method>
<method name="_joint_get_type" qualifiers="virtual const">
<return type="int" enum="PhysicsServer3D.JointType" />
- <argument index="0" name="joint" type="RID" />
+ <param index="0" name="joint" type="RID" />
<description>
</description>
</method>
<method name="_joint_make_cone_twist" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="body_A" type="RID" />
- <argument index="2" name="local_ref_A" type="Transform3D" />
- <argument index="3" name="body_B" type="RID" />
- <argument index="4" name="local_ref_B" type="Transform3D" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="body_A" type="RID" />
+ <param index="2" name="local_ref_A" type="Transform3D" />
+ <param index="3" name="body_B" type="RID" />
+ <param index="4" name="local_ref_B" type="Transform3D" />
<description>
</description>
</method>
<method name="_joint_make_generic_6dof" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="body_A" type="RID" />
- <argument index="2" name="local_ref_A" type="Transform3D" />
- <argument index="3" name="body_B" type="RID" />
- <argument index="4" name="local_ref_B" type="Transform3D" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="body_A" type="RID" />
+ <param index="2" name="local_ref_A" type="Transform3D" />
+ <param index="3" name="body_B" type="RID" />
+ <param index="4" name="local_ref_B" type="Transform3D" />
<description>
</description>
</method>
<method name="_joint_make_hinge" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="body_A" type="RID" />
- <argument index="2" name="hinge_A" type="Transform3D" />
- <argument index="3" name="body_B" type="RID" />
- <argument index="4" name="hinge_B" type="Transform3D" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="body_A" type="RID" />
+ <param index="2" name="hinge_A" type="Transform3D" />
+ <param index="3" name="body_B" type="RID" />
+ <param index="4" name="hinge_B" type="Transform3D" />
<description>
</description>
</method>
<method name="_joint_make_pin" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="body_A" type="RID" />
- <argument index="2" name="local_A" type="Vector3" />
- <argument index="3" name="body_B" type="RID" />
- <argument index="4" name="local_B" type="Vector3" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="body_A" type="RID" />
+ <param index="2" name="local_A" type="Vector3" />
+ <param index="3" name="body_B" type="RID" />
+ <param index="4" name="local_B" type="Vector3" />
<description>
</description>
</method>
<method name="_joint_make_slider" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="body_A" type="RID" />
- <argument index="2" name="local_ref_A" type="Transform3D" />
- <argument index="3" name="body_B" type="RID" />
- <argument index="4" name="local_ref_B" type="Transform3D" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="body_A" type="RID" />
+ <param index="2" name="local_ref_A" type="Transform3D" />
+ <param index="3" name="body_B" type="RID" />
+ <param index="4" name="local_ref_B" type="Transform3D" />
<description>
</description>
</method>
<method name="_joint_set_solver_priority" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="priority" type="int" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="priority" type="int" />
<description>
</description>
</method>
<method name="_pin_joint_get_local_a" qualifiers="virtual const">
<return type="Vector3" />
- <argument index="0" name="joint" type="RID" />
+ <param index="0" name="joint" type="RID" />
<description>
</description>
</method>
<method name="_pin_joint_get_local_b" qualifiers="virtual const">
<return type="Vector3" />
- <argument index="0" name="joint" type="RID" />
+ <param index="0" name="joint" type="RID" />
<description>
</description>
</method>
<method name="_pin_joint_get_param" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.PinJointParam" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.PinJointParam" />
<description>
</description>
</method>
<method name="_pin_joint_set_local_a" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="local_A" type="Vector3" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="local_A" type="Vector3" />
<description>
</description>
</method>
<method name="_pin_joint_set_local_b" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="local_B" type="Vector3" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="local_B" type="Vector3" />
<description>
</description>
</method>
<method name="_pin_joint_set_param" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.PinJointParam" />
- <argument index="2" name="value" type="float" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.PinJointParam" />
+ <param index="2" name="value" type="float" />
<description>
</description>
</method>
@@ -800,47 +813,47 @@
</method>
<method name="_set_active" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="active" type="bool" />
+ <param index="0" name="active" type="bool" />
<description>
</description>
</method>
<method name="_shape_get_data" qualifiers="virtual const">
<return type="Variant" />
- <argument index="0" name="shape" type="RID" />
+ <param index="0" name="shape" type="RID" />
<description>
</description>
</method>
<method name="_shape_get_type" qualifiers="virtual const">
<return type="int" enum="PhysicsServer3D.ShapeType" />
- <argument index="0" name="shape" type="RID" />
+ <param index="0" name="shape" type="RID" />
<description>
</description>
</method>
<method name="_shape_set_data" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="shape" type="RID" />
- <argument index="1" name="data" type="Variant" />
+ <param index="0" name="shape" type="RID" />
+ <param index="1" name="data" type="Variant" />
<description>
</description>
</method>
<method name="_slider_joint_get_param" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.SliderJointParam" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.SliderJointParam" />
<description>
</description>
</method>
<method name="_slider_joint_set_param" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="joint" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.SliderJointParam" />
- <argument index="2" name="value" type="float" />
+ <param index="0" name="joint" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.SliderJointParam" />
+ <param index="2" name="value" type="float" />
<description>
</description>
</method>
<method name="_soft_body_get_bounds" qualifiers="virtual const">
<return type="AABB" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
</description>
</method>
@@ -851,35 +864,35 @@
</method>
<method name="_space_get_direct_state" qualifiers="virtual">
<return type="PhysicsDirectSpaceState3D" />
- <argument index="0" name="space" type="RID" />
+ <param index="0" name="space" type="RID" />
<description>
</description>
</method>
<method name="_space_get_param" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="space" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.SpaceParameter" />
+ <param index="0" name="space" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.SpaceParameter" />
<description>
</description>
</method>
<method name="_space_is_active" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="space" type="RID" />
+ <param index="0" name="space" type="RID" />
<description>
</description>
</method>
<method name="_space_set_active" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="space" type="RID" />
- <argument index="1" name="active" type="bool" />
+ <param index="0" name="space" type="RID" />
+ <param index="1" name="active" type="bool" />
<description>
</description>
</method>
<method name="_space_set_param" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="space" type="RID" />
- <argument index="1" name="param" type="int" enum="PhysicsServer3D.SpaceParameter" />
- <argument index="2" name="value" type="float" />
+ <param index="0" name="space" type="RID" />
+ <param index="1" name="param" type="int" enum="PhysicsServer3D.SpaceParameter" />
+ <param index="2" name="value" type="float" />
<description>
</description>
</method>
diff --git a/doc/classes/PhysicsServer3DRenderingServerHandler.xml b/doc/classes/PhysicsServer3DRenderingServerHandler.xml
index a40a2dd1c6..90066aeb2c 100644
--- a/doc/classes/PhysicsServer3DRenderingServerHandler.xml
+++ b/doc/classes/PhysicsServer3DRenderingServerHandler.xml
@@ -9,21 +9,21 @@
<methods>
<method name="_set_aabb" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="aabb" type="AABB" />
+ <param index="0" name="aabb" type="AABB" />
<description>
</description>
</method>
<method name="_set_normal" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="vertex_id" type="int" />
- <argument index="1" name="normals" type="const void*" />
+ <param index="0" name="vertex_id" type="int" />
+ <param index="1" name="normals" type="const void*" />
<description>
</description>
</method>
<method name="_set_vertex" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="vertex_id" type="int" />
- <argument index="1" name="vertices" type="const void*" />
+ <param index="0" name="vertex_id" type="int" />
+ <param index="1" name="vertices" type="const void*" />
<description>
</description>
</method>
diff --git a/doc/classes/PhysicsTestMotionResult3D.xml b/doc/classes/PhysicsTestMotionResult3D.xml
index e347a350c2..f82df1989f 100644
--- a/doc/classes/PhysicsTestMotionResult3D.xml
+++ b/doc/classes/PhysicsTestMotionResult3D.xml
@@ -11,35 +11,35 @@
<methods>
<method name="get_collider" qualifiers="const">
<return type="Object" />
- <argument index="0" name="collision_index" type="int" default="0" />
+ <param index="0" name="collision_index" type="int" default="0" />
<description>
Returns the colliding body's attached [Object] given a collision index (the deepest collision by default), if a collision occurred.
</description>
</method>
<method name="get_collider_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="collision_index" type="int" default="0" />
+ <param index="0" name="collision_index" type="int" default="0" />
<description>
Returns the unique instance ID of the colliding body's attached [Object] given a collision index (the deepest collision by default), if a collision occurred. See [method Object.get_instance_id].
</description>
</method>
<method name="get_collider_rid" qualifiers="const">
<return type="RID" />
- <argument index="0" name="collision_index" type="int" default="0" />
+ <param index="0" name="collision_index" type="int" default="0" />
<description>
Returns the colliding body's [RID] used by the [PhysicsServer3D] given a collision index (the deepest collision by default), if a collision occurred.
</description>
</method>
<method name="get_collider_shape" qualifiers="const">
<return type="int" />
- <argument index="0" name="collision_index" type="int" default="0" />
+ <param index="0" name="collision_index" type="int" default="0" />
<description>
Returns the colliding body's shape index given a collision index (the deepest collision by default), if a collision occurred. See [CollisionObject3D].
</description>
</method>
<method name="get_collider_velocity" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="collision_index" type="int" default="0" />
+ <param index="0" name="collision_index" type="int" default="0" />
<description>
Returns the colliding body's velocity given a collision index (the deepest collision by default), if a collision occurred.
</description>
@@ -52,28 +52,28 @@
</method>
<method name="get_collision_depth" qualifiers="const">
<return type="float" />
- <argument index="0" name="collision_index" type="int" default="0" />
+ <param index="0" name="collision_index" type="int" default="0" />
<description>
Returns the length of overlap along the collision normal given a collision index (the deepest collision by default), if a collision occurred.
</description>
</method>
<method name="get_collision_local_shape" qualifiers="const">
<return type="int" />
- <argument index="0" name="collision_index" type="int" default="0" />
+ <param index="0" name="collision_index" type="int" default="0" />
<description>
Returns the moving object's colliding shape given a collision index (the deepest collision by default), if a collision occurred.
</description>
</method>
<method name="get_collision_normal" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="collision_index" type="int" default="0" />
+ <param index="0" name="collision_index" type="int" default="0" />
<description>
Returns the colliding body's shape's normal at the point of collision given a collision index (the deepest collision by default), if a collision occurred.
</description>
</method>
<method name="get_collision_point" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="collision_index" type="int" default="0" />
+ <param index="0" name="collision_index" type="int" default="0" />
<description>
Returns the point of collision in global coordinates given a collision index (the deepest collision by default), if a collision occurred.
</description>
diff --git a/doc/classes/PinJoint3D.xml b/doc/classes/PinJoint3D.xml
index 013a18b92c..007cdf830d 100644
--- a/doc/classes/PinJoint3D.xml
+++ b/doc/classes/PinJoint3D.xml
@@ -11,15 +11,15 @@
<methods>
<method name="get_param" qualifiers="const">
<return type="float" />
- <argument index="0" name="param" type="int" enum="PinJoint3D.Param" />
+ <param index="0" name="param" type="int" enum="PinJoint3D.Param" />
<description>
Returns the value of the specified parameter.
</description>
</method>
<method name="set_param">
<return type="void" />
- <argument index="0" name="param" type="int" enum="PinJoint3D.Param" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="param" type="int" enum="PinJoint3D.Param" />
+ <param index="1" name="value" type="float" />
<description>
Sets the value of the specified parameter.
</description>
diff --git a/doc/classes/Plane.xml b/doc/classes/Plane.xml
index 32eb71f1c7..e51e3753fc 100644
--- a/doc/classes/Plane.xml
+++ b/doc/classes/Plane.xml
@@ -18,49 +18,49 @@
</constructor>
<constructor name="Plane">
<return type="Plane" />
- <argument index="0" name="from" type="Plane" />
+ <param index="0" name="from" type="Plane" />
<description>
Constructs a [Plane] as a copy of the given [Plane].
</description>
</constructor>
<constructor name="Plane">
<return type="Plane" />
- <argument index="0" name="a" type="float" />
- <argument index="1" name="b" type="float" />
- <argument index="2" name="c" type="float" />
- <argument index="3" name="d" type="float" />
+ <param index="0" name="a" type="float" />
+ <param index="1" name="b" type="float" />
+ <param index="2" name="c" type="float" />
+ <param index="3" name="d" type="float" />
<description>
- Creates a plane from the four parameters. The three components of the resulting plane's [member normal] are [code]a[/code], [code]b[/code] and [code]c[/code], and the plane has a distance of [code]d[/code] from the origin.
+ Creates a plane from the four parameters. The three components of the resulting plane's [member normal] are [param a], [param b] and [param c], and the plane has a distance of [param d] from the origin.
</description>
</constructor>
<constructor name="Plane">
<return type="Plane" />
- <argument index="0" name="normal" type="Vector3" />
+ <param index="0" name="normal" type="Vector3" />
<description>
Creates a plane from the normal vector. The plane will intersect the origin.
</description>
</constructor>
<constructor name="Plane">
<return type="Plane" />
- <argument index="0" name="normal" type="Vector3" />
- <argument index="1" name="d" type="float" />
+ <param index="0" name="normal" type="Vector3" />
+ <param index="1" name="d" type="float" />
<description>
Creates a plane from the normal vector and the plane's distance from the origin.
</description>
</constructor>
<constructor name="Plane">
<return type="Plane" />
- <argument index="0" name="normal" type="Vector3" />
- <argument index="1" name="point" type="Vector3" />
+ <param index="0" name="normal" type="Vector3" />
+ <param index="1" name="point" type="Vector3" />
<description>
Creates a plane from the normal vector and a point on the plane.
</description>
</constructor>
<constructor name="Plane">
<return type="Plane" />
- <argument index="0" name="point1" type="Vector3" />
- <argument index="1" name="point2" type="Vector3" />
- <argument index="2" name="point3" type="Vector3" />
+ <param index="0" name="point1" type="Vector3" />
+ <param index="1" name="point2" type="Vector3" />
+ <param index="2" name="point3" type="Vector3" />
<description>
Creates a plane from the three points, given in clockwise order.
</description>
@@ -75,55 +75,55 @@
</method>
<method name="distance_to" qualifiers="const">
<return type="float" />
- <argument index="0" name="point" type="Vector3" />
+ <param index="0" name="point" type="Vector3" />
<description>
- Returns the shortest distance from the plane to the position [code]point[/code]. If the point is above the plane, the distance will be positive. If below, the distance will be negative.
+ Returns the shortest distance from the plane to the position [param point]. If the point is above the plane, the distance will be positive. If below, the distance will be negative.
</description>
</method>
<method name="has_point" qualifiers="const">
<return type="bool" />
- <argument index="0" name="point" type="Vector3" />
- <argument index="1" name="tolerance" type="float" default="1e-05" />
+ <param index="0" name="point" type="Vector3" />
+ <param index="1" name="tolerance" type="float" default="1e-05" />
<description>
- Returns [code]true[/code] if [code]point[/code] is inside the plane. Comparison uses a custom minimum [code]tolerance[/code] threshold.
+ Returns [code]true[/code] if [param point] is inside the plane. Comparison uses a custom minimum [param tolerance] threshold.
</description>
</method>
<method name="intersect_3" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="b" type="Plane" />
- <argument index="1" name="c" type="Plane" />
+ <param index="0" name="b" type="Plane" />
+ <param index="1" name="c" type="Plane" />
<description>
- Returns the intersection point of the three planes [code]b[/code], [code]c[/code] and this plane. If no intersection is found, [code]null[/code] is returned.
+ Returns the intersection point of the three planes [param b], [param c] and this plane. If no intersection is found, [code]null[/code] is returned.
</description>
</method>
<method name="intersects_ray" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="from" type="Vector3" />
- <argument index="1" name="dir" type="Vector3" />
+ <param index="0" name="from" type="Vector3" />
+ <param index="1" name="dir" type="Vector3" />
<description>
- Returns the intersection point of a ray consisting of the position [code]from[/code] and the direction normal [code]dir[/code] with this plane. If no intersection is found, [code]null[/code] is returned.
+ Returns the intersection point of a ray consisting of the position [param from] and the direction normal [param dir] with this plane. If no intersection is found, [code]null[/code] is returned.
</description>
</method>
<method name="intersects_segment" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="from" type="Vector3" />
- <argument index="1" name="to" type="Vector3" />
+ <param index="0" name="from" type="Vector3" />
+ <param index="1" name="to" type="Vector3" />
<description>
- Returns the intersection point of a segment from position [code]from[/code] to position [code]to[/code] with this plane. If no intersection is found, [code]null[/code] is returned.
+ Returns the intersection point of a segment from position [param from] to position [param to] with this plane. If no intersection is found, [code]null[/code] is returned.
</description>
</method>
<method name="is_equal_approx" qualifiers="const">
<return type="bool" />
- <argument index="0" name="to_plane" type="Plane" />
+ <param index="0" name="to_plane" type="Plane" />
<description>
- Returns [code]true[/code] if this plane and [code]plane[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
+ Returns [code]true[/code] if this plane and [param to_plane] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
<method name="is_point_over" qualifiers="const">
<return type="bool" />
- <argument index="0" name="point" type="Vector3" />
+ <param index="0" name="point" type="Vector3" />
<description>
- Returns [code]true[/code] if [code]point[/code] is located above the plane.
+ Returns [code]true[/code] if [param point] is located above the plane.
</description>
</method>
<method name="normalized" qualifiers="const">
@@ -134,9 +134,9 @@
</method>
<method name="project" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="point" type="Vector3" />
+ <param index="0" name="point" type="Vector3" />
<description>
- Returns the orthogonal projection of [code]point[/code] into a point in the plane.
+ Returns the orthogonal projection of [param point] into a point in the plane.
</description>
</method>
</methods>
@@ -173,15 +173,22 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="Plane" />
+ <param index="0" name="right" type="Plane" />
<description>
Returns [code]true[/code] if the planes are not equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
</description>
</operator>
+ <operator name="operator *">
+ <return type="Plane" />
+ <param index="0" name="right" type="Transform3D" />
+ <description>
+ Inversely transforms (multiplies) the [Plane] by the given [Transform3D] transformation matrix.
+ </description>
+ </operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="Plane" />
+ <param index="0" name="right" type="Plane" />
<description>
Returns [code]true[/code] if the planes are exactly equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
diff --git a/doc/classes/PlaneMesh.xml b/doc/classes/PlaneMesh.xml
index 6b3a7ed548..564b6fe743 100644
--- a/doc/classes/PlaneMesh.xml
+++ b/doc/classes/PlaneMesh.xml
@@ -4,7 +4,7 @@
Class representing a planar [PrimitiveMesh].
</brief_description>
<description>
- Class representing a planar [PrimitiveMesh]. This flat mesh does not have a thickness. By default, this mesh is aligned on the X and Z axes; this default rotation isn't suited for use with billboarded materials. For billboarded materials, use [QuadMesh] instead.
+ Class representing a planar [PrimitiveMesh]. This flat mesh does not have a thickness. By default, this mesh is aligned on the X and Z axes; this default rotation isn't suited for use with billboarded materials. For billboarded materials, change [member orientation] to [constant FACE_Z].
[b]Note:[/b] When using a large textured [PlaneMesh] (e.g. as a floor), you may stumble upon UV jittering issues depending on the camera angle. To solve this, increase [member subdivide_depth] and [member subdivide_width] until you no longer notice UV jittering.
</description>
<tutorials>
@@ -13,6 +13,9 @@
<member name="center_offset" type="Vector3" setter="set_center_offset" getter="get_center_offset" default="Vector3(0, 0, 0)">
Offset of the generated plane. Useful for particles.
</member>
+ <member name="orientation" type="int" setter="set_orientation" getter="get_orientation" enum="PlaneMesh.Orientation" default="1">
+ Direction that the [PlaneMesh] is facing. See [enum Orientation] for options.
+ </member>
<member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2(2, 2)">
Size of the generated plane.
</member>
@@ -23,4 +26,15 @@
Number of subdivision along the X axis.
</member>
</members>
+ <constants>
+ <constant name="FACE_X" value="0" enum="Orientation">
+ [PlaneMesh] will face the positive X-axis.
+ </constant>
+ <constant name="FACE_Y" value="1" enum="Orientation">
+ [PlaneMesh] will face the positive Y-axis. This matches the behaviour of the [PlaneMesh] in Godot 3.x.
+ </constant>
+ <constant name="FACE_Z" value="2" enum="Orientation">
+ [PlaneMesh] will face the positive Z-axis. This matches the behvaiour of the QuadMesh in Godot 3.x.
+ </constant>
+ </constants>
</class>
diff --git a/doc/classes/Polygon2D.xml b/doc/classes/Polygon2D.xml
index 5f75ac6c50..12f8055180 100644
--- a/doc/classes/Polygon2D.xml
+++ b/doc/classes/Polygon2D.xml
@@ -11,10 +11,10 @@
<methods>
<method name="add_bone">
<return type="void" />
- <argument index="0" name="path" type="NodePath" />
- <argument index="1" name="weights" type="PackedFloat32Array" />
+ <param index="0" name="path" type="NodePath" />
+ <param index="1" name="weights" type="PackedFloat32Array" />
<description>
- Adds a bone with the specified [code]path[/code] and [code]weights[/code].
+ Adds a bone with the specified [param path] and [param weights].
</description>
</method>
<method name="clear_bones">
@@ -25,7 +25,7 @@
</method>
<method name="erase_bone">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Removes the specified bone from this [Polygon2D].
</description>
@@ -38,30 +38,30 @@
</method>
<method name="get_bone_path" qualifiers="const">
<return type="NodePath" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Returns the path to the node associated with the specified bone.
</description>
</method>
<method name="get_bone_weights" qualifiers="const">
<return type="PackedFloat32Array" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Returns the height values of the specified bone.
</description>
</method>
<method name="set_bone_path">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="path" type="NodePath" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="path" type="NodePath" />
<description>
Sets the path to the node associated with the specified bone.
</description>
</method>
<method name="set_bone_weights">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="weights" type="PackedFloat32Array" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="weights" type="PackedFloat32Array" />
<description>
Sets the weight values for the specified bone.
</description>
@@ -79,10 +79,10 @@
<member name="internal_vertex_count" type="int" setter="set_internal_vertex_count" getter="get_internal_vertex_count" default="0">
</member>
<member name="invert_border" type="float" setter="set_invert_border" getter="get_invert_border" default="100.0">
- Added padding applied to the bounding box when using [code]invert[/code]. Setting this value too small may result in a "Bad Polygon" error.
+ Added padding applied to the bounding box when [member invert_enabled] is set to [code]true[/code]. Setting this value too small may result in a "Bad Polygon" error.
</member>
- <member name="invert_enable" type="bool" setter="set_invert" getter="get_invert" default="false">
- If [code]true[/code], polygon will be inverted, containing the area outside the defined points and extending to the [code]invert_border[/code].
+ <member name="invert_enabled" type="bool" setter="set_invert_enabled" getter="get_invert_enabled" default="false">
+ If [code]true[/code], the polygon will be inverted, containing the area outside the defined points and extending to the [member invert_border].
</member>
<member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2(0, 0)">
The offset applied to each vertex.
diff --git a/doc/classes/PolygonPathFinder.xml b/doc/classes/PolygonPathFinder.xml
index dbe9978ef5..84d757bfca 100644
--- a/doc/classes/PolygonPathFinder.xml
+++ b/doc/classes/PolygonPathFinder.xml
@@ -9,8 +9,8 @@
<methods>
<method name="find_path">
<return type="PackedVector2Array" />
- <argument index="0" name="from" type="Vector2" />
- <argument index="1" name="to" type="Vector2" />
+ <param index="0" name="from" type="Vector2" />
+ <param index="1" name="to" type="Vector2" />
<description>
</description>
</method>
@@ -21,40 +21,40 @@
</method>
<method name="get_closest_point" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="point" type="Vector2" />
+ <param index="0" name="point" type="Vector2" />
<description>
</description>
</method>
<method name="get_intersections" qualifiers="const">
<return type="PackedVector2Array" />
- <argument index="0" name="from" type="Vector2" />
- <argument index="1" name="to" type="Vector2" />
+ <param index="0" name="from" type="Vector2" />
+ <param index="1" name="to" type="Vector2" />
<description>
</description>
</method>
<method name="get_point_penalty" qualifiers="const">
<return type="float" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
</description>
</method>
<method name="is_point_inside" qualifiers="const">
<return type="bool" />
- <argument index="0" name="point" type="Vector2" />
+ <param index="0" name="point" type="Vector2" />
<description>
</description>
</method>
<method name="set_point_penalty">
<return type="void" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="penalty" type="float" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="penalty" type="float" />
<description>
</description>
</method>
<method name="setup">
<return type="void" />
- <argument index="0" name="points" type="PackedVector2Array" />
- <argument index="1" name="connections" type="PackedInt32Array" />
+ <param index="0" name="points" type="PackedVector2Array" />
+ <param index="1" name="connections" type="PackedInt32Array" />
<description>
</description>
</method>
diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml
index 5da2196f29..00b725d5d7 100644
--- a/doc/classes/PopupMenu.xml
+++ b/doc/classes/PopupMenu.xml
@@ -15,165 +15,165 @@
<methods>
<method name="add_check_item">
<return type="void" />
- <argument index="0" name="label" type="String" />
- <argument index="1" name="id" type="int" default="-1" />
- <argument index="2" name="accel" type="int" enum="Key" default="0" />
+ <param index="0" name="label" type="String" />
+ <param index="1" name="id" type="int" default="-1" />
+ <param index="2" name="accel" type="int" enum="Key" default="0" />
<description>
- Adds a new checkable item with text [code]label[/code].
- An [code]id[/code] can optionally be provided, as well as an accelerator ([code]accel[/code]). If no [code]id[/code] is provided, one will be created from the index. If no [code]accel[/code] is provided then the default [code]0[/code] will be assigned to it. See [method get_item_accelerator] for more info on accelerators.
+ Adds a new checkable item with text [param label].
+ An [param id] can optionally be provided, as well as an accelerator ([param accel]). If no [param id] is provided, one will be created from the index. If no [param accel] is provided then the default [code]0[/code] will be assigned to it. See [method get_item_accelerator] for more info on accelerators.
[b]Note:[/b] Checkable items just display a checkmark, but don't have any built-in checking behavior and must be checked/unchecked manually. See [method set_item_checked] for more info on how to control it.
</description>
</method>
<method name="add_check_shortcut">
<return type="void" />
- <argument index="0" name="shortcut" type="Shortcut" />
- <argument index="1" name="id" type="int" default="-1" />
- <argument index="2" name="global" type="bool" default="false" />
+ <param index="0" name="shortcut" type="Shortcut" />
+ <param index="1" name="id" type="int" default="-1" />
+ <param index="2" name="global" type="bool" default="false" />
<description>
Adds a new checkable item and assigns the specified [Shortcut] to it. Sets the label of the checkbox to the [Shortcut]'s name.
- An [code]id[/code] can optionally be provided. If no [code]id[/code] is provided, one will be created from the index.
+ An [param id] can optionally be provided. If no [param id] is provided, one will be created from the index.
[b]Note:[/b] Checkable items just display a checkmark, but don't have any built-in checking behavior and must be checked/unchecked manually. See [method set_item_checked] for more info on how to control it.
</description>
</method>
<method name="add_icon_check_item">
<return type="void" />
- <argument index="0" name="texture" type="Texture2D" />
- <argument index="1" name="label" type="String" />
- <argument index="2" name="id" type="int" default="-1" />
- <argument index="3" name="accel" type="int" enum="Key" default="0" />
+ <param index="0" name="texture" type="Texture2D" />
+ <param index="1" name="label" type="String" />
+ <param index="2" name="id" type="int" default="-1" />
+ <param index="3" name="accel" type="int" enum="Key" default="0" />
<description>
- Adds a new checkable item with text [code]label[/code] and icon [code]texture[/code].
- An [code]id[/code] can optionally be provided, as well as an accelerator ([code]accel[/code]). If no [code]id[/code] is provided, one will be created from the index. If no [code]accel[/code] is provided then the default [code]0[/code] will be assigned to it. See [method get_item_accelerator] for more info on accelerators.
+ Adds a new checkable item with text [param label] and icon [param texture].
+ An [param id] can optionally be provided, as well as an accelerator ([param accel]). If no [param id] is provided, one will be created from the index. If no [param accel] is provided then the default [code]0[/code] will be assigned to it. See [method get_item_accelerator] for more info on accelerators.
[b]Note:[/b] Checkable items just display a checkmark, but don't have any built-in checking behavior and must be checked/unchecked manually. See [method set_item_checked] for more info on how to control it.
</description>
</method>
<method name="add_icon_check_shortcut">
<return type="void" />
- <argument index="0" name="texture" type="Texture2D" />
- <argument index="1" name="shortcut" type="Shortcut" />
- <argument index="2" name="id" type="int" default="-1" />
- <argument index="3" name="global" type="bool" default="false" />
+ <param index="0" name="texture" type="Texture2D" />
+ <param index="1" name="shortcut" type="Shortcut" />
+ <param index="2" name="id" type="int" default="-1" />
+ <param index="3" name="global" type="bool" default="false" />
<description>
- Adds a new checkable item and assigns the specified [Shortcut] and icon [code]texture[/code] to it. Sets the label of the checkbox to the [Shortcut]'s name.
- An [code]id[/code] can optionally be provided. If no [code]id[/code] is provided, one will be created from the index.
+ Adds a new checkable item and assigns the specified [Shortcut] and icon [param texture] to it. Sets the label of the checkbox to the [Shortcut]'s name.
+ An [param id] can optionally be provided. If no [param id] is provided, one will be created from the index.
[b]Note:[/b] Checkable items just display a checkmark, but don't have any built-in checking behavior and must be checked/unchecked manually. See [method set_item_checked] for more info on how to control it.
</description>
</method>
<method name="add_icon_item">
<return type="void" />
- <argument index="0" name="texture" type="Texture2D" />
- <argument index="1" name="label" type="String" />
- <argument index="2" name="id" type="int" default="-1" />
- <argument index="3" name="accel" type="int" enum="Key" default="0" />
+ <param index="0" name="texture" type="Texture2D" />
+ <param index="1" name="label" type="String" />
+ <param index="2" name="id" type="int" default="-1" />
+ <param index="3" name="accel" type="int" enum="Key" default="0" />
<description>
- Adds a new item with text [code]label[/code] and icon [code]texture[/code].
- An [code]id[/code] can optionally be provided, as well as an accelerator ([code]accel[/code]). If no [code]id[/code] is provided, one will be created from the index. If no [code]accel[/code] is provided then the default [code]0[/code] will be assigned to it. See [method get_item_accelerator] for more info on accelerators.
+ Adds a new item with text [param label] and icon [param texture].
+ An [param id] can optionally be provided, as well as an accelerator ([param accel]). If no [param id] is provided, one will be created from the index. If no [param accel] is provided then the default [code]0[/code] will be assigned to it. See [method get_item_accelerator] for more info on accelerators.
</description>
</method>
<method name="add_icon_radio_check_item">
<return type="void" />
- <argument index="0" name="texture" type="Texture2D" />
- <argument index="1" name="label" type="String" />
- <argument index="2" name="id" type="int" default="-1" />
- <argument index="3" name="accel" type="int" enum="Key" default="0" />
+ <param index="0" name="texture" type="Texture2D" />
+ <param index="1" name="label" type="String" />
+ <param index="2" name="id" type="int" default="-1" />
+ <param index="3" name="accel" type="int" enum="Key" default="0" />
<description>
Same as [method add_icon_check_item], but uses a radio check button.
</description>
</method>
<method name="add_icon_radio_check_shortcut">
<return type="void" />
- <argument index="0" name="texture" type="Texture2D" />
- <argument index="1" name="shortcut" type="Shortcut" />
- <argument index="2" name="id" type="int" default="-1" />
- <argument index="3" name="global" type="bool" default="false" />
+ <param index="0" name="texture" type="Texture2D" />
+ <param index="1" name="shortcut" type="Shortcut" />
+ <param index="2" name="id" type="int" default="-1" />
+ <param index="3" name="global" type="bool" default="false" />
<description>
Same as [method add_icon_check_shortcut], but uses a radio check button.
</description>
</method>
<method name="add_icon_shortcut">
<return type="void" />
- <argument index="0" name="texture" type="Texture2D" />
- <argument index="1" name="shortcut" type="Shortcut" />
- <argument index="2" name="id" type="int" default="-1" />
- <argument index="3" name="global" type="bool" default="false" />
+ <param index="0" name="texture" type="Texture2D" />
+ <param index="1" name="shortcut" type="Shortcut" />
+ <param index="2" name="id" type="int" default="-1" />
+ <param index="3" name="global" type="bool" default="false" />
<description>
- Adds a new item and assigns the specified [Shortcut] and icon [code]texture[/code] to it. Sets the label of the checkbox to the [Shortcut]'s name.
- An [code]id[/code] can optionally be provided. If no [code]id[/code] is provided, one will be created from the index.
+ Adds a new item and assigns the specified [Shortcut] and icon [param texture] to it. Sets the label of the checkbox to the [Shortcut]'s name.
+ An [param id] can optionally be provided. If no [param id] is provided, one will be created from the index.
</description>
</method>
<method name="add_item">
<return type="void" />
- <argument index="0" name="label" type="String" />
- <argument index="1" name="id" type="int" default="-1" />
- <argument index="2" name="accel" type="int" enum="Key" default="0" />
+ <param index="0" name="label" type="String" />
+ <param index="1" name="id" type="int" default="-1" />
+ <param index="2" name="accel" type="int" enum="Key" default="0" />
<description>
- Adds a new item with text [code]label[/code].
- An [code]id[/code] can optionally be provided, as well as an accelerator ([code]accel[/code]). If no [code]id[/code] is provided, one will be created from the index. If no [code]accel[/code] is provided then the default [code]0[/code] will be assigned to it. See [method get_item_accelerator] for more info on accelerators.
- [b]Note:[/b] The provided [code]id[/code] is used only in [signal id_pressed] and [signal id_focused] signals. It's not related to the [code]index[/code] arguments in e.g. [method set_item_checked].
+ Adds a new item with text [param label].
+ An [param id] can optionally be provided, as well as an accelerator ([param accel]). If no [param id] is provided, one will be created from the index. If no [param accel] is provided then the default [code]0[/code] will be assigned to it. See [method get_item_accelerator] for more info on accelerators.
+ [b]Note:[/b] The provided [param id] is used only in [signal id_pressed] and [signal id_focused] signals. It's not related to the [code]index[/code] arguments in e.g. [method set_item_checked].
</description>
</method>
<method name="add_multistate_item">
<return type="void" />
- <argument index="0" name="label" type="String" />
- <argument index="1" name="max_states" type="int" />
- <argument index="2" name="default_state" type="int" default="0" />
- <argument index="3" name="id" type="int" default="-1" />
- <argument index="4" name="accel" type="int" enum="Key" default="0" />
+ <param index="0" name="label" type="String" />
+ <param index="1" name="max_states" type="int" />
+ <param index="2" name="default_state" type="int" default="0" />
+ <param index="3" name="id" type="int" default="-1" />
+ <param index="4" name="accel" type="int" enum="Key" default="0" />
<description>
- Adds a new multistate item with text [code]label[/code].
- Contrarily to normal binary items, multistate items can have more than two states, as defined by [code]max_states[/code]. Each press or activate of the item will increase the state by one. The default value is defined by [code]default_state[/code].
- An [code]id[/code] can optionally be provided, as well as an accelerator ([code]accel[/code]). If no [code]id[/code] is provided, one will be created from the index. If no [code]accel[/code] is provided then the default [code]0[/code] will be assigned to it. See [method get_item_accelerator] for more info on accelerators.
+ Adds a new multistate item with text [param label].
+ Contrarily to normal binary items, multistate items can have more than two states, as defined by [param max_states]. Each press or activate of the item will increase the state by one. The default value is defined by [param default_state].
+ An [param id] can optionally be provided, as well as an accelerator ([param accel]). If no [param id] is provided, one will be created from the index. If no [param accel] is provided then the default [code]0[/code] will be assigned to it. See [method get_item_accelerator] for more info on accelerators.
</description>
</method>
<method name="add_radio_check_item">
<return type="void" />
- <argument index="0" name="label" type="String" />
- <argument index="1" name="id" type="int" default="-1" />
- <argument index="2" name="accel" type="int" enum="Key" default="0" />
+ <param index="0" name="label" type="String" />
+ <param index="1" name="id" type="int" default="-1" />
+ <param index="2" name="accel" type="int" enum="Key" default="0" />
<description>
- Adds a new radio check button with text [code]label[/code].
- An [code]id[/code] can optionally be provided, as well as an accelerator ([code]accel[/code]). If no [code]id[/code] is provided, one will be created from the index. If no [code]accel[/code] is provided then the default [code]0[/code] will be assigned to it. See [method get_item_accelerator] for more info on accelerators.
+ Adds a new radio check button with text [param label].
+ An [param id] can optionally be provided, as well as an accelerator ([param accel]). If no [param id] is provided, one will be created from the index. If no [param accel] is provided then the default [code]0[/code] will be assigned to it. See [method get_item_accelerator] for more info on accelerators.
[b]Note:[/b] Checkable items just display a checkmark, but don't have any built-in checking behavior and must be checked/unchecked manually. See [method set_item_checked] for more info on how to control it.
</description>
</method>
<method name="add_radio_check_shortcut">
<return type="void" />
- <argument index="0" name="shortcut" type="Shortcut" />
- <argument index="1" name="id" type="int" default="-1" />
- <argument index="2" name="global" type="bool" default="false" />
+ <param index="0" name="shortcut" type="Shortcut" />
+ <param index="1" name="id" type="int" default="-1" />
+ <param index="2" name="global" type="bool" default="false" />
<description>
Adds a new radio check button and assigns a [Shortcut] to it. Sets the label of the checkbox to the [Shortcut]'s name.
- An [code]id[/code] can optionally be provided. If no [code]id[/code] is provided, one will be created from the index.
+ An [param id] can optionally be provided. If no [param id] is provided, one will be created from the index.
[b]Note:[/b] Checkable items just display a checkmark, but don't have any built-in checking behavior and must be checked/unchecked manually. See [method set_item_checked] for more info on how to control it.
</description>
</method>
<method name="add_separator">
<return type="void" />
- <argument index="0" name="label" type="String" default="&quot;&quot;" />
- <argument index="1" name="id" type="int" default="-1" />
+ <param index="0" name="label" type="String" default="&quot;&quot;" />
+ <param index="1" name="id" type="int" default="-1" />
<description>
- Adds a separator between items. Separators also occupy an index, which you can set by using the [code]id[/code] parameter.
- A [code]label[/code] can optionally be provided, which will appear at the center of the separator.
+ Adds a separator between items. Separators also occupy an index, which you can set by using the [param id] parameter.
+ A [param label] can optionally be provided, which will appear at the center of the separator.
</description>
</method>
<method name="add_shortcut">
<return type="void" />
- <argument index="0" name="shortcut" type="Shortcut" />
- <argument index="1" name="id" type="int" default="-1" />
- <argument index="2" name="global" type="bool" default="false" />
+ <param index="0" name="shortcut" type="Shortcut" />
+ <param index="1" name="id" type="int" default="-1" />
+ <param index="2" name="global" type="bool" default="false" />
<description>
Adds a [Shortcut].
- An [code]id[/code] can optionally be provided. If no [code]id[/code] is provided, one will be created from the index.
+ An [param id] can optionally be provided. If no [param id] is provided, one will be created from the index.
</description>
</method>
<method name="add_submenu_item">
<return type="void" />
- <argument index="0" name="label" type="String" />
- <argument index="1" name="submenu" type="String" />
- <argument index="2" name="id" type="int" default="-1" />
+ <param index="0" name="label" type="String" />
+ <param index="1" name="submenu" type="String" />
+ <param index="2" name="id" type="int" default="-1" />
<description>
- Adds an item that will act as a submenu of the parent [PopupMenu] node when clicked. The [code]submenu[/code] argument is the name of the child [PopupMenu] node that will be shown when the item is clicked.
- An [code]id[/code] can optionally be provided. If no [code]id[/code] is provided, one will be created from the index.
+ Adds an item that will act as a submenu of the parent [PopupMenu] node when clicked. The [param submenu] argument is the name of the child [PopupMenu] node that will be shown when the item is clicked.
+ An [param id] can optionally be provided. If no [param id] is provided, one will be created from the index.
</description>
</method>
<method name="clear">
@@ -190,312 +190,313 @@
</method>
<method name="get_item_accelerator" qualifiers="const">
<return type="int" enum="Key" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the accelerator of the item at the given [code]index[/code]. Accelerators are special combinations of keys that activate the item, no matter which control is focused.
- </description>
- </method>
- <method name="get_item_horizontal_offset" qualifiers="const">
- <return type="int" />
- <argument index="0" name="index" type="int" />
- <description>
- Returns the horizontal offset of the item at the given [code]index[/code].
+ Returns the accelerator of the item at the given [param index]. Accelerators are special combinations of keys that activate the item, no matter which control is focused.
</description>
</method>
<method name="get_item_icon" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the icon of the item at the given [code]index[/code].
+ Returns the icon of the item at the given [param index].
</description>
</method>
<method name="get_item_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
+ <description>
+ Returns the id of the item at the given [param index]. [code]id[/code] can be manually assigned, while index can not.
+ </description>
+ </method>
+ <method name="get_item_indent" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the id of the item at the given [code]index[/code]. [code]id[/code] can be manually assigned, while index can not.
+ Returns the horizontal offset of the item at the given [param index].
</description>
</method>
<method name="get_item_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
- Returns the index of the item containing the specified [code]id[/code]. Index is automatically assigned to each item by the engine and can not be set manually.
+ Returns the index of the item containing the specified [param id]. Index is automatically assigned to each item by the engine and can not be set manually.
</description>
</method>
<method name="get_item_language" qualifiers="const">
<return type="String" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Returns item's text language code.
</description>
</method>
<method name="get_item_metadata" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Returns the metadata of the specified item, which might be of any type. You can set it with [method set_item_metadata], which provides a simple way of assigning context data to items.
</description>
</method>
<method name="get_item_shortcut" qualifiers="const">
<return type="Shortcut" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the [Shortcut] associated with the item at the given [code]index[/code].
+ Returns the [Shortcut] associated with the item at the given [param index].
</description>
</method>
<method name="get_item_submenu" qualifiers="const">
<return type="String" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the submenu name of the item at the given [code]index[/code]. See [method add_submenu_item] for more info on how to add a submenu.
+ Returns the submenu name of the item at the given [param index]. See [method add_submenu_item] for more info on how to add a submenu.
</description>
</method>
<method name="get_item_text" qualifiers="const">
<return type="String" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the text of the item at the given [code]index[/code].
+ Returns the text of the item at the given [param index].
</description>
</method>
<method name="get_item_text_direction" qualifiers="const">
<return type="int" enum="Control.TextDirection" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Returns item's text base writing direction.
</description>
</method>
<method name="get_item_tooltip" qualifiers="const">
<return type="String" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the tooltip associated with the item at the given [code]index[/code].
+ Returns the tooltip associated with the item at the given [param index].
</description>
</method>
<method name="is_item_checkable" qualifiers="const">
<return type="bool" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns [code]true[/code] if the item at the given [code]index[/code] is checkable in some way, i.e. if it has a checkbox or radio button.
+ Returns [code]true[/code] if the item at the given [param index] is checkable in some way, i.e. if it has a checkbox or radio button.
[b]Note:[/b] Checkable items just display a checkmark or radio button, but don't have any built-in checking behavior and must be checked/unchecked manually.
</description>
</method>
<method name="is_item_checked" qualifiers="const">
<return type="bool" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns [code]true[/code] if the item at the given [code]index[/code] is checked.
+ Returns [code]true[/code] if the item at the given [param index] is checked.
</description>
</method>
<method name="is_item_disabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns [code]true[/code] if the item at the given [code]index[/code] is disabled. When it is disabled it can't be selected, or its action invoked.
+ Returns [code]true[/code] if the item at the given [param index] is disabled. When it is disabled it can't be selected, or its action invoked.
See [method set_item_disabled] for more info on how to disable an item.
</description>
</method>
<method name="is_item_radio_checkable" qualifiers="const">
<return type="bool" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns [code]true[/code] if the item at the given [code]index[/code] has radio button-style checkability.
+ Returns [code]true[/code] if the item at the given [param index] has radio button-style checkability.
[b]Note:[/b] This is purely cosmetic; you must add the logic for checking/unchecking items in radio groups.
</description>
</method>
<method name="is_item_separator" qualifiers="const">
<return type="bool" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Returns [code]true[/code] if the item is a separator. If it is, it will be displayed as a line. See [method add_separator] for more info on how to add a separator.
</description>
</method>
<method name="is_item_shortcut_disabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Returns [code]true[/code] if the specified item's shortcut is disabled.
</description>
</method>
<method name="remove_item">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Removes the item at the given [code]index[/code] from the menu.
+ Removes the item at the given [param index] from the menu.
[b]Note:[/b] The indices of items after the removed item will be shifted by one.
</description>
</method>
<method name="scroll_to_item">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Moves the scroll view to make the item at the given [code]index[/code] visible.
+ Moves the scroll view to make the item at the given [param index] visible.
</description>
</method>
<method name="set_current_index">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Sets the currently focused item as the given [code]index[/code].
+ Sets the currently focused item as the given [param index].
+ Passing [code]-1[/code] as the index makes so that no item is focused.
</description>
</method>
<method name="set_item_accelerator">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="accel" type="int" enum="Key" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="accel" type="int" enum="Key" />
<description>
- Sets the accelerator of the item at the given [code]index[/code]. Accelerators are special combinations of keys that activate the item, no matter which control is focused.
+ Sets the accelerator of the item at the given [param index]. Accelerators are special combinations of keys that activate the item, no matter which control is focused.
</description>
</method>
<method name="set_item_as_checkable">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="enable" type="bool" />
<description>
- Sets whether the item at the given [code]index[/code] has a checkbox. If [code]false[/code], sets the type of the item to plain text.
+ Sets whether the item at the given [param index] has a checkbox. If [code]false[/code], sets the type of the item to plain text.
[b]Note:[/b] Checkable items just display a checkmark, but don't have any built-in checking behavior and must be checked/unchecked manually.
</description>
</method>
<method name="set_item_as_radio_checkable">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="enable" type="bool" />
<description>
- Sets the type of the item at the given [code]index[/code] to radio button. If [code]false[/code], sets the type of the item to plain text.
+ Sets the type of the item at the given [param index] to radio button. If [code]false[/code], sets the type of the item to plain text.
</description>
</method>
<method name="set_item_as_separator">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="enable" type="bool" />
<description>
- Mark the item at the given [code]index[/code] as a separator, which means that it would be displayed as a line. If [code]false[/code], sets the type of the item to plain text.
+ Mark the item at the given [param index] as a separator, which means that it would be displayed as a line. If [code]false[/code], sets the type of the item to plain text.
</description>
</method>
<method name="set_item_checked">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="checked" type="bool" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="checked" type="bool" />
<description>
- Sets the checkstate status of the item at the given [code]index[/code].
+ Sets the checkstate status of the item at the given [param index].
</description>
</method>
<method name="set_item_disabled">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="disabled" type="bool" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="disabled" type="bool" />
<description>
- Enables/disables the item at the given [code]index[/code]. When it is disabled, it can't be selected and its action can't be invoked.
+ Enables/disables the item at the given [param index]. When it is disabled, it can't be selected and its action can't be invoked.
</description>
</method>
- <method name="set_item_horizontal_offset">
+ <method name="set_item_icon">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="offset" type="int" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="icon" type="Texture2D" />
<description>
- Sets the horizontal offset of the item at the given [code]index[/code].
+ Replaces the [Texture2D] icon of the item at the given [param index].
</description>
</method>
- <method name="set_item_icon">
+ <method name="set_item_id">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="icon" type="Texture2D" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="id" type="int" />
<description>
- Replaces the [Texture2D] icon of the item at the given [code]index[/code].
+ Sets the [param id] of the item at the given [param index].
+ The [param id] is used in [signal id_pressed] and [signal id_focused] signals.
</description>
</method>
- <method name="set_item_id">
+ <method name="set_item_indent">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="id" type="int" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="indent" type="int" />
<description>
- Sets the [code]id[/code] of the item at the given [code]index[/code].
- The [code]id[/code] is used in [signal id_pressed] and [signal id_focused] signals.
+ Sets the horizontal offset of the item at the given [param index].
</description>
</method>
<method name="set_item_language">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="language" type="String" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="language" type="String" />
<description>
Sets language code of item's text used for line-breaking and text shaping algorithms, if left empty current locale is used instead.
</description>
</method>
<method name="set_item_metadata">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="metadata" type="Variant" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="metadata" type="Variant" />
<description>
Sets the metadata of an item, which may be of any type. You can later get it with [method get_item_metadata], which provides a simple way of assigning context data to items.
</description>
</method>
<method name="set_item_multistate">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="state" type="int" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="state" type="int" />
<description>
Sets the state of a multistate item. See [method add_multistate_item] for details.
</description>
</method>
<method name="set_item_shortcut">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="shortcut" type="Shortcut" />
- <argument index="2" name="global" type="bool" default="false" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="shortcut" type="Shortcut" />
+ <param index="2" name="global" type="bool" default="false" />
<description>
- Sets a [Shortcut] for the item at the given [code]index[/code].
+ Sets a [Shortcut] for the item at the given [param index].
</description>
</method>
<method name="set_item_shortcut_disabled">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="disabled" type="bool" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="disabled" type="bool" />
<description>
- Disables the [Shortcut] of the item at the given [code]index[/code].
+ Disables the [Shortcut] of the item at the given [param index].
</description>
</method>
<method name="set_item_submenu">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="submenu" type="String" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="submenu" type="String" />
<description>
- Sets the submenu of the item at the given [code]index[/code]. The submenu is the name of a child [PopupMenu] node that would be shown when the item is clicked.
+ Sets the submenu of the item at the given [param index]. The submenu is the name of a child [PopupMenu] node that would be shown when the item is clicked.
</description>
</method>
<method name="set_item_text">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="text" type="String" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="text" type="String" />
<description>
- Sets the text of the item at the given [code]index[/code].
+ Sets the text of the item at the given [param index].
</description>
</method>
<method name="set_item_text_direction">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="direction" type="int" enum="Control.TextDirection" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="direction" type="int" enum="Control.TextDirection" />
<description>
Sets item's text base writing direction.
</description>
</method>
<method name="set_item_tooltip">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="tooltip" type="String" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="tooltip" type="String" />
<description>
- Sets the [String] tooltip of the item at the given [code]index[/code].
+ Sets the [String] tooltip of the item at the given [param index].
</description>
</method>
<method name="toggle_item_checked">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Toggles the check state of the item at the given [code]index[/code].
+ Toggles the check state of the item at the given [param index].
</description>
</method>
<method name="toggle_item_multistate">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Cycle to the next state of a multistate item. See [method add_multistate_item] for details.
</description>
@@ -523,21 +524,25 @@
</members>
<signals>
<signal name="id_focused">
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
- Emitted when user navigated to an item of some [code]id[/code] using [code]ui_up[/code] or [code]ui_down[/code] action.
+ Emitted when user navigated to an item of some [param id] using [code]ui_up[/code] or [code]ui_down[/code] action.
</description>
</signal>
<signal name="id_pressed">
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
- Emitted when an item of some [code]id[/code] is pressed or its accelerator is activated.
+ Emitted when an item of some [param id] is pressed or its accelerator is activated.
</description>
</signal>
<signal name="index_pressed">
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
+ <description>
+ Emitted when an item of some [param index] is pressed or its accelerator is activated.
+ </description>
+ </signal>
+ <signal name="menu_changed">
<description>
- Emitted when an item of some [code]index[/code] is pressed or its accelerator is activated.
</description>
</signal>
</signals>
@@ -566,6 +571,9 @@
<theme_item name="h_separation" data_type="constant" type="int" default="4">
The horizontal space between the item's elements.
</theme_item>
+ <theme_item name="indent" data_type="constant" type="int" default="10">
+ Width of the single indentation level.
+ </theme_item>
<theme_item name="item_end_padding" data_type="constant" type="int" default="2">
</theme_item>
<theme_item name="item_start_padding" data_type="constant" type="int" default="2">
@@ -594,12 +602,21 @@
<theme_item name="checked" data_type="icon" type="Texture2D">
[Texture2D] icon for the checked checkbox items.
</theme_item>
+ <theme_item name="checked_disabled" data_type="icon" type="Texture2D">
+ [Texture2D] icon for the checked checkbox items when they are disabled.
+ </theme_item>
<theme_item name="radio_checked" data_type="icon" type="Texture2D">
[Texture2D] icon for the checked radio button items.
</theme_item>
+ <theme_item name="radio_checked_disabled" data_type="icon" type="Texture2D">
+ [Texture2D] icon for the checked radio button items when they are disabled.
+ </theme_item>
<theme_item name="radio_unchecked" data_type="icon" type="Texture2D">
[Texture2D] icon for the unchecked radio button items.
</theme_item>
+ <theme_item name="radio_unchecked_disabled" data_type="icon" type="Texture2D">
+ [Texture2D] icon for the unchecked radio button items when they are disabled.
+ </theme_item>
<theme_item name="submenu" data_type="icon" type="Texture2D">
[Texture2D] icon for the submenu arrow (for left-to-right layouts).
</theme_item>
@@ -609,6 +626,9 @@
<theme_item name="unchecked" data_type="icon" type="Texture2D">
[Texture2D] icon for the unchecked checkbox items.
</theme_item>
+ <theme_item name="unchecked_disabled" data_type="icon" type="Texture2D">
+ [Texture2D] icon for the unchecked checkbox items when they are disabled.
+ </theme_item>
<theme_item name="hover" data_type="style" type="StyleBox">
[StyleBox] displayed when the [PopupMenu] item is hovered.
</theme_item>
diff --git a/doc/classes/PopupPanel.xml b/doc/classes/PopupPanel.xml
index d850cf20b8..0c6c342f5b 100644
--- a/doc/classes/PopupPanel.xml
+++ b/doc/classes/PopupPanel.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
Class for displaying popups with a panel background. In some cases it might be simpler to use than [Popup], since it provides a configurable background. If you are making windows, better check [Window].
+ If any [Control] node is added as a child of this [PopupPanel], it will be stretched to fit the panel's size (similar to how [PanelContainer] works).
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/PortableCompressedTexture2D.xml b/doc/classes/PortableCompressedTexture2D.xml
index aad72bbb48..c7e2f2fbdc 100644
--- a/doc/classes/PortableCompressedTexture2D.xml
+++ b/doc/classes/PortableCompressedTexture2D.xml
@@ -15,10 +15,10 @@
<methods>
<method name="create_from_image">
<return type="void" />
- <argument index="0" name="image" type="Image" />
- <argument index="1" name="compression_mode" type="int" enum="PortableCompressedTexture2D.CompressionMode" />
- <argument index="2" name="normal_map" type="bool" default="false" />
- <argument index="3" name="lossy_quality" type="float" default="0.8" />
+ <param index="0" name="image" type="Image" />
+ <param index="1" name="compression_mode" type="int" enum="PortableCompressedTexture2D.CompressionMode" />
+ <param index="2" name="normal_map" type="bool" default="false" />
+ <param index="3" name="lossy_quality" type="float" default="0.8" />
<description>
Initializes the compressed texture from a base image. The compression mode must be provided.
If this image will be used as a normal map, the "normal map" flag is recommended, to ensure optimum quality.
@@ -45,7 +45,7 @@
</method>
<method name="set_keep_all_compressed_buffers" qualifiers="static">
<return type="void" />
- <argument index="0" name="keep" type="bool" />
+ <param index="0" name="keep" type="bool" />
<description>
Overrides the flag globally for all textures of this type. This is used primarily by the editor.
</description>
diff --git a/doc/classes/PrimitiveMesh.xml b/doc/classes/PrimitiveMesh.xml
index 7046a21f68..1b9ecdbfa0 100644
--- a/doc/classes/PrimitiveMesh.xml
+++ b/doc/classes/PrimitiveMesh.xml
@@ -4,7 +4,7 @@
Base class for all primitive meshes. Handles applying a [Material] to a primitive mesh.
</brief_description>
<description>
- Base class for all primitive meshes. Handles applying a [Material] to a primitive mesh. Examples include [BoxMesh], [CapsuleMesh], [CylinderMesh], [PlaneMesh], [PrismMesh], [QuadMesh], and [SphereMesh].
+ Base class for all primitive meshes. Handles applying a [Material] to a primitive mesh. Examples include [BoxMesh], [CapsuleMesh], [CylinderMesh], [PlaneMesh], [PrismMesh], and [SphereMesh].
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index b1e3d2f628..fa7fad9e40 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -17,7 +17,7 @@
<methods>
<method name="add_property_info">
<return type="void" />
- <argument index="0" name="hint" type="Dictionary" />
+ <param index="0" name="hint" type="Dictionary" />
<description>
Adds a custom property info to a property. The dictionary must contain:
- [code]name[/code]: [String] (the property's name)
@@ -55,21 +55,21 @@
</method>
<method name="clear">
<return type="void" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
Clears the whole configuration (not recommended, may break things).
</description>
</method>
<method name="get_order" qualifiers="const">
<return type="int" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
Returns the order of a configuration value (influences when saved to the config file).
</description>
</method>
<method name="get_setting" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
Returns the value of a setting.
[b]Example:[/b]
@@ -85,9 +85,9 @@
</method>
<method name="globalize_path" qualifiers="const">
<return type="String" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
- Returns the absolute, native OS path corresponding to the localized [code]path[/code] (starting with [code]res://[/code] or [code]user://[/code]). The returned path will vary depending on the operating system and user preferences. See [url=$DOCS_URL/tutorials/io/data_paths.html]File paths in Godot projects[/url] to see what those paths convert to. See also [method localize_path].
+ Returns the absolute, native OS path corresponding to the localized [param path] (starting with [code]res://[/code] or [code]user://[/code]). The returned path will vary depending on the operating system and user preferences. See [url=$DOCS_URL/tutorials/io/data_paths.html]File paths in Godot projects[/url] to see what those paths convert to. See also [method localize_path].
[b]Note:[/b] [method globalize_path] with [code]res://[/code] will not work in an exported project. Instead, prepend the executable's base directory to the path when running from an exported project:
[codeblock]
var path = ""
@@ -100,47 +100,33 @@
# `path` will contain the absolute path to `hello.txt` next to the executable.
# This is *not* identical to using `ProjectSettings.globalize_path()` with a `res://` path,
# but is close enough in spirit.
- path = OS.get_executable_path().get_base_dir().plus_file("hello.txt")
+ path = OS.get_executable_path().get_base_dir().path_join("hello.txt")
[/codeblock]
</description>
</method>
<method name="has_setting" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
Returns [code]true[/code] if a configuration value is present.
</description>
</method>
<method name="load_resource_pack">
<return type="bool" />
- <argument index="0" name="pack" type="String" />
- <argument index="1" name="replace_files" type="bool" default="true" />
- <argument index="2" name="offset" type="int" default="0" />
+ <param index="0" name="pack" type="String" />
+ <param index="1" name="replace_files" type="bool" default="true" />
+ <param index="2" name="offset" type="int" default="0" />
<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.
+ Loads the contents of the .pck or .zip file specified by [param pack] into the resource filesystem ([code]res://[/code]). Returns [code]true[/code] on success.
+ [b]Note:[/b] If a file from [param pack] shares the same path as a file already in the resource filesystem, any attempts to load that file will use the file from [param pack] unless [param replace_files] is set to [code]false[/code].
+ [b]Note:[/b] The optional [param offset] 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">
<return type="String" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
- Returns the localized path (starting with [code]res://[/code]) corresponding to the absolute, native OS [code]path[/code]. See also [method globalize_path].
- </description>
- </method>
- <method name="property_can_revert">
- <return type="bool" />
- <argument index="0" name="name" type="String" />
- <description>
- Returns [code]true[/code] if the specified property exists and its initial value differs from the current value.
- </description>
- </method>
- <method name="property_get_revert">
- <return type="Variant" />
- <argument index="0" name="name" type="String" />
- <description>
- Returns the specified property's initial value. Returns [code]null[/code] if the property does not exist.
+ Returns the localized path (starting with [code]res://[/code]) corresponding to the absolute, native OS [param path]. See also [method globalize_path].
</description>
</method>
<method name="save">
@@ -152,31 +138,31 @@
</method>
<method name="save_custom">
<return type="int" enum="Error" />
- <argument index="0" name="file" type="String" />
+ <param index="0" name="file" type="String" />
<description>
Saves the configuration to a custom file. The file extension must be [code].godot[/code] (to save in text-based [ConfigFile] format) or [code].binary[/code] (to save in binary format). You can also save [code]override.cfg[/code] file, which is also text, but can be used in exported projects unlike other formats.
</description>
</method>
<method name="set_initial_value">
<return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="value" type="Variant" />
<description>
Sets the specified property's initial value. This is the value the property reverts to.
</description>
</method>
<method name="set_order">
<return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="position" type="int" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="position" type="int" />
<description>
Sets the order of a configuration value (influences when saved to the config file).
</description>
</method>
<method name="set_setting">
<return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="value" type="Variant" />
<description>
Sets the value of a setting.
[b]Example:[/b]
@@ -292,6 +278,8 @@
</member>
<member name="audio/driver/driver" type="String" setter="" getter="">
Specifies the audio driver to use. This setting is platform-dependent as each platform supports different audio drivers. If left empty, the default audio driver will be used.
+ The [code]Dummy[/code] audio driver disables all audio playback and recording, which is useful for non-game applications as it reduces CPU usage. It also prevents the engine from appearing as an application playing audio in the OS' audio mixer.
+ [b]Note:[/b] The driver in use can be overridden at runtime via the [code]--audio-driver[/code] command line argument.
</member>
<member name="audio/driver/enable_input" type="bool" setter="" getter="" default="false">
If [code]true[/code], microphone input will be allowed. This requires appropriate permissions to be set when exporting to Android or iOS.
@@ -344,7 +332,7 @@
Path to logs within the project. Using an [code]user://[/code] path is recommended.
</member>
<member name="debug/file_logging/max_log_files" type="int" setter="" getter="" default="5">
- Specifies the maximum amount of log files allowed (used for rotation).
+ Specifies the maximum number of log files allowed (used for rotation).
</member>
<member name="debug/gdscript/warnings/assert_always_false" type="int" setter="" getter="" default="1">
If [code]enabled[/code], prints a warning or an error when an [code]assert[/code] call always returns false.
@@ -466,7 +454,7 @@
Maximum call stack allowed for debugging GDScript.
</member>
<member name="debug/settings/profiler/max_functions" type="int" setter="" getter="" default="16384">
- Maximum amount of functions per frame allowed when profiling.
+ Maximum number of functions per frame allowed when profiling.
</member>
<member name="debug/settings/stdout/print_fps" type="bool" setter="" getter="" default="false">
Print frames per second to standard output every second.
@@ -476,9 +464,6 @@
<member name="debug/settings/stdout/verbose_stdout" type="bool" setter="" getter="" default="false">
Print more information to standard output when running. It displays information such as memory leaks, which scenes and resources are being loaded, etc. This can also be enabled using the [code]--verbose[/code] or [code]-v[/code] command line argument, even on an exported project. See also [method OS.is_stdout_verbose] and [method @GlobalScope.print_verbose].
</member>
- <member name="debug/settings/visual_script/max_call_stack" type="int" setter="" getter="" default="1024">
- Maximum call stack in visual scripting, to avoid infinite recursion.
- </member>
<member name="debug/shapes/collision/contact_color" type="Color" setter="" getter="" default="Color(1, 0.2, 0.1, 0.8)">
Color of the contact points between collision shapes, visible when "Visible Collision Shapes" is enabled in the Debug menu.
</member>
@@ -543,12 +528,15 @@
Position offset for tooltips, relative to the mouse cursor's hotspot.
</member>
<member name="display/window/dpi/allow_hidpi" type="bool" setter="" getter="" default="true">
- If [code]true[/code], allows HiDPI display on Windows, macOS, Android, iOS and HTML5. If [code]false[/code], the platform's low-DPI fallback will be used on HiDPI displays, which causes the window to be displayed in a blurry or pixelated manner (and can cause various window management bugs). Therefore, it is recommended to make your project scale to [url=$DOCS_URL/tutorials/viewports/multiple_resolutions.html]multiple resolutions[/url] instead of disabling this setting.
+ If [code]true[/code], allows HiDPI display on Windows, macOS, Android, iOS and Web. If [code]false[/code], the platform's low-DPI fallback will be used on HiDPI displays, which causes the window to be displayed in a blurry or pixelated manner (and can cause various window management bugs). Therefore, it is recommended to make your project scale to [url=$DOCS_URL/tutorials/viewports/multiple_resolutions.html]multiple resolutions[/url] instead of disabling this setting.
[b]Note:[/b] This setting has no effect on Linux as DPI-awareness fallbacks are not supported there.
</member>
<member name="display/window/energy_saving/keep_screen_on" type="bool" setter="" getter="" default="true">
If [code]true[/code], keeps the screen on (even in case of inactivity), so the screensaver does not take over. Works on desktop and mobile platforms.
</member>
+ <member name="display/window/energy_saving/keep_screen_on.editor" type="bool" setter="" getter="" default="false">
+ Editor-only override for [member display/window/energy_saving/keep_screen_on]. Does not affect exported projects in debug or release mode.
+ </member>
<member name="display/window/handheld/orientation" type="int" setter="" getter="" default="0">
The default screen orientation to use on mobile devices. See [enum DisplayServer.ScreenOrientation] for possible values.
[b]Note:[/b] When set to a portrait orientation, this project setting does not flip the project resolution's width and height automatically. Instead, you have to set [member display/window/size/viewport_width] and [member display/window/size/viewport_height] accordingly.
@@ -558,37 +546,37 @@
</member>
<member name="display/window/size/always_on_top" type="bool" setter="" getter="" default="false">
Forces the main window to be always on top.
- [b]Note:[/b] This setting is ignored on iOS, Android, and HTML5.
+ [b]Note:[/b] This setting is ignored on iOS, Android, and Web.
</member>
<member name="display/window/size/borderless" type="bool" setter="" getter="" default="false">
Forces the main window to be borderless.
- [b]Note:[/b] This setting is ignored on iOS, Android, and HTML5.
+ [b]Note:[/b] This setting is ignored on iOS, Android, and Web.
</member>
<member name="display/window/size/fullscreen" type="bool" setter="" getter="" default="false">
Sets the main window to full screen when the project starts. Note that this is not [i]exclusive[/i] fullscreen. On Windows and Linux, a borderless window is used to emulate fullscreen. On macOS, a new desktop is used to display the running project.
Regardless of the platform, enabling fullscreen will change the window size to match the monitor's size. Therefore, make sure your project supports [url=$DOCS_URL/tutorials/rendering/multiple_resolutions.html]multiple resolutions[/url] when enabling fullscreen mode.
- [b]Note:[/b] This setting is ignored on iOS, Android, and HTML5.
+ [b]Note:[/b] This setting is ignored on iOS, Android, and Web.
</member>
<member name="display/window/size/resizable" type="bool" setter="" getter="" default="true">
Allows the window to be resizable by default.
[b]Note:[/b] This setting is ignored on iOS.
</member>
- <member name="display/window/size/viewport_height" type="int" setter="" getter="" default="600">
- Sets the game's main viewport height. On desktop platforms, this is also the initial window height.
+ <member name="display/window/size/viewport_height" type="int" setter="" getter="" default="648">
+ Sets the game's main viewport height. On desktop platforms, this is also the initial window height, represented by an indigo-colored rectangle in the 2D editor. Stretch mode settings also use this as a reference when using the [code]canvas_items[/code] or [code]viewport[/code] stretch modes. See also [member display/window/size/viewport_width], [member display/window/size/window_width_override] and [member display/window/size/window_height_override].
</member>
- <member name="display/window/size/viewport_width" type="int" setter="" getter="" default="1024">
- Sets the game's main viewport width. On desktop platforms, this is also the initial window width.
+ <member name="display/window/size/viewport_width" type="int" setter="" getter="" default="1152">
+ Sets the game's main viewport width. On desktop platforms, this is also the initial window width, represented by an indigo-colored rectangle in the 2D editor. Stretch mode settings also use this as a reference when using the [code]canvas_items[/code] or [code]viewport[/code] stretch modes. See also [member display/window/size/viewport_height], [member display/window/size/window_width_override] and [member display/window/size/window_height_override].
</member>
<member name="display/window/size/window_height_override" type="int" setter="" getter="" default="0">
- On desktop platforms, sets the game's initial window height.
- [b]Note:[/b] By default, or when set to 0, the initial window height is the [member display/window/size/viewport_height]. This setting is ignored on iOS, Android, and HTML5.
+ On desktop platforms, overrides the game's initial window height. See also [member display/window/size/window_width_override], [member display/window/size/viewport_width] and [member display/window/size/viewport_height].
+ [b]Note:[/b] By default, or when set to [code]0[/code], the initial window height is the [member display/window/size/viewport_height]. This setting is ignored on iOS, Android, and Web.
</member>
<member name="display/window/size/window_width_override" type="int" setter="" getter="" default="0">
- On desktop platforms, sets the game's initial window width.
- [b]Note:[/b] By default, or when set to 0, the initial window width is the viewport [member display/window/size/viewport_width]. This setting is ignored on iOS, Android, and HTML5.
+ On desktop platforms, overrides the game's initial window width. See also [member display/window/size/window_height_override], [member display/window/size/viewport_width] and [member display/window/size/viewport_height].
+ [b]Note:[/b] By default, or when set to [code]0[/code], the initial window width is the viewport [member display/window/size/viewport_width]. This setting is ignored on iOS, Android, and Web.
</member>
<member name="display/window/vsync/vsync_mode" type="int" setter="" getter="" default="1">
- Sets the VSync mode for the main game window.
+ Sets the V-Sync mode for the main game window.
See [enum DisplayServer.VSyncMode] for possible values and how they affect the behavior of your application.
Depending on the platform and used renderer, the engine will fall back to [code]Enabled[/code], if the desired mode is not supported.
</member>
@@ -660,8 +648,8 @@
<member name="gui/theme/custom_font" type="String" setter="" getter="" default="&quot;&quot;">
Path to a custom [Font] resource to use as default for all GUI elements of the project.
</member>
- <member name="gui/theme/default_font_antialiased" type="bool" setter="" getter="" default="true">
- If set to [code]true[/code], default font uses 8-bit anitialiased glyph rendering. See [member FontFile.antialiased].
+ <member name="gui/theme/default_font_antialiasing" type="int" setter="" getter="" default="1">
+ Font anti-aliasing mode. See [member FontFile.antialiasing],
</member>
<member name="gui/theme/default_font_generate_mipmaps" type="bool" setter="" getter="" default="false">
If set to [code]true[/code], the default font will have mipmaps generated. This prevents text from looking grainy when a [Control] is scaled down, or when a [Label3D] is viewed from a long distance (if [member Label3D.texture_filter] is set to a mode that displays mipmaps).
@@ -681,6 +669,9 @@
</member>
<member name="gui/theme/default_theme_scale" type="float" setter="" getter="" default="1.0">
</member>
+ <member name="gui/theme/lcd_subpixel_layout" type="int" setter="" getter="" default="1">
+ LCD sub-pixel layout used for font anti-aliasing. See [enum TextServer.FontLCDSubpixelLayout].
+ </member>
<member name="gui/timers/incremental_search_max_interval_msec" type="int" setter="" getter="" default="2000">
Timer setting for incremental search in [Tree], [ItemList], etc. controls (in milliseconds).
</member>
@@ -864,6 +855,7 @@
</member>
<member name="input_devices/pen_tablet/driver" type="String" setter="" getter="">
Specifies the tablet driver to use. If left empty, the default driver will be used.
+ [b]Note:[/b] The driver in use can be overridden at runtime via the [code]--tablet-driver[/code] command line argument.
</member>
<member name="input_devices/pen_tablet/driver.windows" type="String" setter="" getter="">
Override for [member input_devices/pen_tablet/driver] on Windows.
@@ -927,6 +919,9 @@
</member>
<member name="internationalization/rendering/text_driver" type="String" setter="" getter="" default="&quot;&quot;">
Specifies the [TextServer] to use. If left empty, the default will be used.
+ "ICU / HarfBuzz / Graphite" is the most advanced text driver, supporting right-to-left typesetting and complex scripts (for languages like Arabic, Hebrew, etc). The "Fallback" text driver does not support right-to-left typesetting and complex scripts.
+ [b]Note:[/b] The driver in use can be overridden at runtime via the [code]--text-driver[/code] command line argument.
+ [b]Note:[/b] There is an additional [code]Dummy[/code] text driver available, which disables all text rendering and font-related functionality. This driver is not listed in the project settings, but it can be enabled when running the editor or project using the [code]--text-driver Dummy[/code] command line argument.
</member>
<member name="layer_names/2d_navigation/layer_1" type="String" setter="" getter="" default="&quot;&quot;">
Optional name for the 2D navigation layer 1. If left empty, the layer will display as "Layer 1".
@@ -1438,20 +1433,6 @@
<member name="memory/limits/multithreaded_server/rid_pool_prealloc" type="int" setter="" getter="" default="60">
This is used by servers when used in multi-threading mode (servers and visual). RIDs are preallocated to avoid stalling the server requesting them on threads. If servers get stalled too often when loading resources in a thread, increase this number.
</member>
- <member name="mono/debugger_agent/port" type="int" setter="" getter="" default="23685">
- </member>
- <member name="mono/debugger_agent/wait_for_debugger" type="bool" setter="" getter="" default="false">
- </member>
- <member name="mono/debugger_agent/wait_timeout" type="int" setter="" getter="" default="3000">
- </member>
- <member name="mono/profiler/args" type="String" setter="" getter="" default="&quot;log:calls,alloc,sample,output=output.mlpd&quot;">
- </member>
- <member name="mono/profiler/enabled" type="bool" setter="" getter="" default="false">
- </member>
- <member name="mono/runtime/unhandled_exception_policy" type="int" setter="" getter="" default="0">
- The policy to use for unhandled Mono (C#) exceptions. The default "Terminate Application" exits the project as soon as an unhandled exception is thrown. "Log Error" logs an error message to the console instead, and will not interrupt the project execution when an unhandled exception is thrown.
- [b]Note:[/b] The unhandled exception policy is always set to "Log Error" in the editor, which also includes C# [code]tool[/code] scripts running within the editor as well as editor plugin code.
- </member>
<member name="navigation/2d/default_cell_size" type="int" setter="" getter="" default="1">
Default cell size for 2D navigation maps. See [method NavigationServer2D.map_set_cell_size].
</member>
@@ -1465,13 +1446,13 @@
Default edge connection margin for 3D navigation maps. See [method NavigationServer3D.map_set_edge_connection_margin].
</member>
<member name="network/limits/debugger/max_chars_per_second" type="int" setter="" getter="" default="32768">
- Maximum amount of characters allowed to send as output from the debugger. Over this value, content is dropped. This helps not to stall the debugger connection.
+ Maximum number of characters allowed to send as output from the debugger. Over this value, content is dropped. This helps not to stall the debugger connection.
</member>
<member name="network/limits/debugger/max_errors_per_second" type="int" setter="" getter="" default="400">
Maximum number of errors allowed to be sent from the debugger. Over this value, content is dropped. This helps not to stall the debugger connection.
</member>
<member name="network/limits/debugger/max_queued_messages" type="int" setter="" getter="" default="2048">
- Maximum amount of messages in the debugger queue. Over this value, content is dropped. This helps to limit the debugger memory usage.
+ Maximum number of messages in the debugger queue. Over this value, content is dropped. This helps to limit the debugger memory usage.
</member>
<member name="network/limits/debugger/max_warnings_per_second" type="int" setter="" getter="" default="400">
Maximum number of warnings allowed to be sent from the debugger. Over this value, content is dropped. This helps not to stall the debugger connection.
@@ -1562,7 +1543,7 @@
Individual shapes can have a specific bias value (see [member Shape2D.custom_solver_bias]).
</member>
<member name="physics/2d/solver/solver_iterations" type="int" setter="" getter="" default="16">
- Number of solver iterations for all contacts and constraints. The greater the amount of iterations, the more accurate the collisions will be. However, a greater amount of iterations requires more CPU power, which can decrease performance. See [constant PhysicsServer2D.SPACE_PARAM_SOLVER_ITERATIONS].
+ Number of solver iterations for all contacts and constraints. The greater the number of iterations, the more accurate the collisions will be. However, a greater number of iterations requires more CPU power, which can decrease performance. See [constant PhysicsServer2D.SPACE_PARAM_SOLVER_ITERATIONS].
</member>
<member name="physics/2d/time_before_sleep" type="float" setter="" getter="" default="0.5">
Time (in seconds) of inactivity before which a 2D physics body will put to sleep. See [constant PhysicsServer2D.SPACE_PARAM_BODY_TIME_TO_SLEEP].
@@ -1630,7 +1611,7 @@
Individual shapes can have a specific bias value (see [member Shape3D.custom_solver_bias]).
</member>
<member name="physics/3d/solver/solver_iterations" type="int" setter="" getter="" default="16">
- Number of solver iterations for all contacts and constraints. The greater the amount of iterations, the more accurate the collisions will be. However, a greater amount of iterations requires more CPU power, which can decrease performance. See [constant PhysicsServer3D.SPACE_PARAM_SOLVER_ITERATIONS].
+ Number of solver iterations for all contacts and constraints. The greater the number of iterations, the more accurate the collisions will be. However, a greater number of iterations requires more CPU power, which can decrease performance. See [constant PhysicsServer3D.SPACE_PARAM_SOLVER_ITERATIONS].
</member>
<member name="physics/3d/time_before_sleep" type="float" setter="" getter="" default="0.5">
Time (in seconds) of inactivity before which a 3D physics body will put to sleep. See [constant PhysicsServer3D.SPACE_PARAM_BODY_TIME_TO_SLEEP].
@@ -1662,13 +1643,13 @@
Sets the number of MSAA samples to use (as a power of two). MSAA is used to reduce aliasing around the edges of polygons. A higher MSAA value results in smoother edges but can be significantly slower on some hardware. See also bilinear scaling 3d [member rendering/scaling_3d/mode] for supersampling, which provides higher quality but is much more expensive.
</member>
<member name="rendering/anti_aliasing/quality/screen_space_aa" type="int" setter="" getter="" default="0">
- Sets the screen-space antialiasing mode for the default screen [Viewport]. Screen-space antialiasing works by selectively blurring edges in a post-process shader. It differs from MSAA which takes multiple coverage samples while rendering objects. Screen-space AA methods are typically faster than MSAA and will smooth out specular aliasing, but tend to make scenes appear blurry. The blurriness can be counteracted to an extent by using a negative mipmap LOD bias ([member rendering/textures/default_filters/texture_mipmap_bias]).
+ Sets the screen-space antialiasing mode for the default screen [Viewport]. Screen-space antialiasing works by selectively blurring edges in a post-process shader. It differs from MSAA which takes multiple coverage samples while rendering objects. Screen-space AA methods are typically faster than MSAA and will smooth out specular aliasing, but tend to make scenes appear blurry. The blurriness is partially counteracted by automatically using a negative mipmap LOD bias (see [member rendering/textures/default_filters/texture_mipmap_bias]).
Another way to combat specular aliasing is to enable [member rendering/anti_aliasing/screen_space_roughness_limiter/enabled].
</member>
<member name="rendering/anti_aliasing/quality/use_debanding" type="bool" setter="" getter="" default="false">
</member>
<member name="rendering/anti_aliasing/quality/use_taa" type="bool" setter="" getter="" default="false">
- Enables Temporal Anti-Aliasing for the default screen [Viewport]. TAA works by jittering the camera and accumulating the images of the last rendered frames, motion vector rendering is used to account for camera and object motion. Enabling TAA can make the image blurrier, which can be counteracted to an extent by using a negative mipmap LOD bias ([member rendering/textures/default_filters/texture_mipmap_bias]).
+ Enables Temporal Anti-Aliasing for the default screen [Viewport]. TAA works by jittering the camera and accumulating the images of the last rendered frames, motion vector rendering is used to account for camera and object motion. Enabling TAA can make the image blurrier, which is partially counteracted by automatically using a negative mipmap LOD bias (see [member rendering/textures/default_filters/texture_mipmap_bias]).
[b]Note:[/b] The implementation is not complete yet, some visual instances such as particles and skinned meshes may show artifacts.
</member>
<member name="rendering/anti_aliasing/screen_space_roughness_limiter/amount" type="float" setter="" getter="" default="0.25">
@@ -1833,7 +1814,7 @@
Max number of omnilights and spotlights renderable per object. At the default value of 8, this means that each surface can be affected by up to 8 omnilights and 8 spotlights. This is further limited by hardware support and [member rendering/limits/opengl/max_renderable_lights]. Setting this low will slightly reduce memory usage, may decrease shader compile times, and may result in faster rendering on low-end, mobile, or web devices.
</member>
<member name="rendering/limits/opengl/max_renderable_elements" type="int" setter="" getter="" default="65536">
- Max amount of elements renderable in a frame. If more elements than this are visible per frame, they will not be drawn. Keep in mind elements refer to mesh surfaces and not meshes themselves. Setting this low will slightly reduce memory usage and may decrease shader compile times, particularly on web. For most uses, the default value is suitable, but consider lowering as much as possible on web export.
+ Max number of elements renderable in a frame. If more elements than this are visible per frame, they will not be drawn. Keep in mind elements refer to mesh surfaces and not meshes themselves. Setting this low will slightly reduce memory usage and may decrease shader compile times, particularly on web. For most uses, the default value is suitable, but consider lowering as much as possible on web export.
</member>
<member name="rendering/limits/opengl/max_renderable_lights" type="int" setter="" getter="" default="32">
Max number of positional lights renderable in a frame. If more lights than this number are used, they will be ignored. Setting this low will slightly reduce memory usage and may decrease shader compile times, particularly on web. For most uses, the default value is suitable, but consider lowering as much as possible on web export.
@@ -1962,14 +1943,18 @@
Lower-end override for [member rendering/shadows/positional_shadow/soft_shadow_filter_quality] on mobile devices, due to performance concerns or driver support.
</member>
<member name="rendering/textures/decals/filter" type="int" setter="" getter="" default="3">
+ The filtering quality to use for [Decal] nodes. When using one of the anisotropic filtering modes, the anisotropic filtering level is controlled by [member rendering/textures/default_filters/anisotropic_filtering_level].
</member>
<member name="rendering/textures/default_filters/anisotropic_filtering_level" type="int" setter="" getter="" default="2">
Sets the maximum number of samples to take when using anisotropic filtering on textures (as a power of two). A higher sample count will result in sharper textures at oblique angles, but is more expensive to compute. A value of [code]0[/code] forcibly disables anisotropic filtering, even on materials where it is enabled.
+ The anisotropic filtering level also affects decals and light projectors if they are configured to use anisotropic filtering. See [member rendering/textures/decals/filter] and [member rendering/textures/light_projectors/filter].
+ [b]Note:[/b] For performance reasons, anisotropic filtering [i]is not enabled by default[/i] on 2D and 3D materials. For this setting to have an effect in 3D, set [member BaseMaterial3D.texture_filter] to [constant BaseMaterial3D.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC] or [constant BaseMaterial3D.TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC] on materials. For this setting to have an effect in 2D, set [member CanvasItem.texture_filter] to [constant CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC] or [constant CanvasItem.TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC] on the [CanvasItem] node displaying the texture (or in [CanvasTexture]). However, anisotropic filtering is rarely useful in 2D, so only enable it for textures in 2D if it makes a meaningful visual difference.
[b]Note:[/b] This property is only read when the project starts. There is currently no way to change this setting at run-time.
</member>
<member name="rendering/textures/default_filters/texture_mipmap_bias" type="float" setter="" getter="" default="0.0">
- Affects the final texture sharpness by reading from a lower or higher mipmap (also called "texture LOD bias"). Negative values make mipmapped textures sharper but grainier when viewed at a distance, while positive values make mipmapped textures blurrier (even when up close). To get sharper textures at a distance without introducing too much graininess, set this between [code]-0.75[/code] and [code]0.0[/code]. Enabling temporal antialiasing ([member rendering/anti_aliasing/quality/use_taa]) can help reduce the graininess visible when using negative mipmap bias.
- [b]Note:[/b] When the 3D scaling mode is set to FSR 1.0, this value is used to adjust the automatic mipmap bias which is calculated internally based on the scale factor. The formula for this is [code]-log2(1.0 / scale) + mipmap_bias[/code].
+ Affects the final texture sharpness by reading from a lower or higher mipmap (also called "texture LOD bias"). Negative values make mipmapped textures sharper but grainier when viewed at a distance, while positive values make mipmapped textures blurrier (even when up close).
+ Enabling temporal antialiasing ([member rendering/anti_aliasing/quality/use_taa]) will automatically apply a [code]-0.5[/code] offset to this value, while enabling FXAA ([member rendering/anti_aliasing/quality/screen_space_aa]) will automatically apply a [code]-0.25[/code] offset to this value. If both TAA and FXAA are enbled at the same time, an offset of [code]-0.75[/code] is applied to this value.
+ [b]Note:[/b] If [member rendering/scaling_3d/scale] is lower than [code]1.0[/code] (exclusive), [member rendering/textures/default_filters/texture_mipmap_bias] is used to adjust the automatic mipmap bias which is calculated internally based on the scale factor. The formula for this is [code]log2(scaling_3d_scale) + mipmap_bias[/code].
[b]Note:[/b] This property is only read when the project starts. To change the mipmap LOD bias at run-time, set [member Viewport.texture_mipmap_bias] instead.
</member>
<member name="rendering/textures/default_filters/use_nearest_mipmap_filter" type="bool" setter="" getter="" default="false">
@@ -1977,6 +1962,7 @@
[b]Note:[/b] This property is only read when the project starts. There is currently no way to change this setting at run-time.
</member>
<member name="rendering/textures/light_projectors/filter" type="int" setter="" getter="" default="3">
+ The filtering quality to use for [OmniLight3D] and [SpotLight3D] projectors. When using one of the anisotropic filtering modes, the anisotropic filtering level is controlled by [member rendering/textures/default_filters/anisotropic_filtering_level].
</member>
<member name="rendering/textures/lossless_compression/force_png" type="bool" setter="" getter="" default="false">
If [code]true[/code], the texture importer will import lossless textures using the PNG format. Otherwise, it will default to using WebP.
diff --git a/doc/classes/Projection.xml b/doc/classes/Projection.xml
index 2bbfd04e9e..5690ea5e95 100644
--- a/doc/classes/Projection.xml
+++ b/doc/classes/Projection.xml
@@ -14,112 +14,122 @@
</constructor>
<constructor name="Projection">
<return type="Projection" />
- <argument index="0" name="from" type="Projection" />
+ <param index="0" name="from" type="Projection" />
<description>
</description>
</constructor>
<constructor name="Projection">
<return type="Projection" />
- <argument index="0" name="from" type="Transform3D" />
+ <param index="0" name="from" type="Transform3D" />
<description>
</description>
</constructor>
+ <constructor name="Projection">
+ <return type="Projection" />
+ <param index="0" name="x_axis" type="Vector4" />
+ <param index="1" name="y_axis" type="Vector4" />
+ <param index="2" name="z_axis" type="Vector4" />
+ <param index="3" name="w_axis" type="Vector4" />
+ <description>
+ Constructs a Projection from four [Vector4] values (matrix columns).
+ </description>
+ </constructor>
</constructors>
<methods>
<method name="create_depth_correction" qualifiers="static">
<return type="Projection" />
- <argument index="0" name="flip_y" type="bool" />
+ <param index="0" name="flip_y" type="bool" />
<description>
</description>
</method>
<method name="create_fit_aabb" qualifiers="static">
<return type="Projection" />
- <argument index="0" name="aabb" type="AABB" />
+ <param index="0" name="aabb" type="AABB" />
<description>
</description>
</method>
<method name="create_for_hmd" qualifiers="static">
<return type="Projection" />
- <argument index="0" name="eye" type="int" />
- <argument index="1" name="aspect" type="float" />
- <argument index="2" name="intraocular_dist" type="float" />
- <argument index="3" name="display_width" type="float" />
- <argument index="4" name="display_to_lens" type="float" />
- <argument index="5" name="oversample" type="float" />
- <argument index="6" name="z_near" type="float" />
- <argument index="7" name="z_far" type="float" />
+ <param index="0" name="eye" type="int" />
+ <param index="1" name="aspect" type="float" />
+ <param index="2" name="intraocular_dist" type="float" />
+ <param index="3" name="display_width" type="float" />
+ <param index="4" name="display_to_lens" type="float" />
+ <param index="5" name="oversample" type="float" />
+ <param index="6" name="z_near" type="float" />
+ <param index="7" name="z_far" type="float" />
<description>
</description>
</method>
<method name="create_frustum" qualifiers="static">
<return type="Projection" />
- <argument index="0" name="left" type="float" />
- <argument index="1" name="right" type="float" />
- <argument index="2" name="bottom" type="float" />
- <argument index="3" name="top" type="float" />
- <argument index="4" name="z_near" type="float" />
- <argument index="5" name="z_far" type="float" />
+ <param index="0" name="left" type="float" />
+ <param index="1" name="right" type="float" />
+ <param index="2" name="bottom" type="float" />
+ <param index="3" name="top" type="float" />
+ <param index="4" name="z_near" type="float" />
+ <param index="5" name="z_far" type="float" />
<description>
</description>
</method>
<method name="create_frustum_aspect" qualifiers="static">
<return type="Projection" />
- <argument index="0" name="size" type="float" />
- <argument index="1" name="aspect" type="float" />
- <argument index="2" name="offset" type="Vector2" />
- <argument index="3" name="z_near" type="float" />
- <argument index="4" name="z_far" type="float" />
- <argument index="5" name="flip_fov" type="bool" default="false" />
+ <param index="0" name="size" type="float" />
+ <param index="1" name="aspect" type="float" />
+ <param index="2" name="offset" type="Vector2" />
+ <param index="3" name="z_near" type="float" />
+ <param index="4" name="z_far" type="float" />
+ <param index="5" name="flip_fov" type="bool" default="false" />
<description>
</description>
</method>
<method name="create_light_atlas_rect" qualifiers="static">
<return type="Projection" />
- <argument index="0" name="rect" type="Rect2" />
+ <param index="0" name="rect" type="Rect2" />
<description>
</description>
</method>
<method name="create_orthogonal" qualifiers="static">
<return type="Projection" />
- <argument index="0" name="left" type="float" />
- <argument index="1" name="right" type="float" />
- <argument index="2" name="bottom" type="float" />
- <argument index="3" name="top" type="float" />
- <argument index="4" name="z_near" type="float" />
- <argument index="5" name="z_far" type="float" />
+ <param index="0" name="left" type="float" />
+ <param index="1" name="right" type="float" />
+ <param index="2" name="bottom" type="float" />
+ <param index="3" name="top" type="float" />
+ <param index="4" name="z_near" type="float" />
+ <param index="5" name="z_far" type="float" />
<description>
</description>
</method>
<method name="create_orthogonal_aspect" qualifiers="static">
<return type="Projection" />
- <argument index="0" name="size" type="float" />
- <argument index="1" name="aspect" type="float" />
- <argument index="2" name="z_near" type="float" />
- <argument index="3" name="z_far" type="float" />
- <argument index="4" name="flip_fov" type="bool" default="false" />
+ <param index="0" name="size" type="float" />
+ <param index="1" name="aspect" type="float" />
+ <param index="2" name="z_near" type="float" />
+ <param index="3" name="z_far" type="float" />
+ <param index="4" name="flip_fov" type="bool" default="false" />
<description>
</description>
</method>
<method name="create_perspective" qualifiers="static">
<return type="Projection" />
- <argument index="0" name="fovy" type="float" />
- <argument index="1" name="aspect" type="float" />
- <argument index="2" name="z_near" type="float" />
- <argument index="3" name="z_far" type="float" />
- <argument index="4" name="flip_fov" type="bool" default="false" />
+ <param index="0" name="fovy" type="float" />
+ <param index="1" name="aspect" type="float" />
+ <param index="2" name="z_near" type="float" />
+ <param index="3" name="z_far" type="float" />
+ <param index="4" name="flip_fov" type="bool" default="false" />
<description>
</description>
</method>
<method name="create_perspective_hmd" qualifiers="static">
<return type="Projection" />
- <argument index="0" name="fovy" type="float" />
- <argument index="1" name="aspect" type="float" />
- <argument index="2" name="z_near" type="float" />
- <argument index="3" name="z_far" type="float" />
- <argument index="4" name="flip_fov" type="bool" />
- <argument index="5" name="eye" type="int" />
- <argument index="6" name="intraocular_dist" type="float" />
- <argument index="7" name=" convergence_dist" type="float" />
+ <param index="0" name="fovy" type="float" />
+ <param index="1" name="aspect" type="float" />
+ <param index="2" name="z_near" type="float" />
+ <param index="3" name="z_far" type="float" />
+ <param index="4" name="flip_fov" type="bool" />
+ <param index="5" name="eye" type="int" />
+ <param index="6" name="intraocular_dist" type="float" />
+ <param index="7" name=" convergence_dist" type="float" />
<description>
</description>
</method>
@@ -150,8 +160,8 @@
</method>
<method name="get_fovy" qualifiers="static">
<return type="float" />
- <argument index="0" name="fovx" type="float" />
- <argument index="1" name="aspect" type="float" />
+ <param index="0" name="fovx" type="float" />
+ <param index="1" name="aspect" type="float" />
<description>
</description>
</method>
@@ -162,13 +172,13 @@
</method>
<method name="get_pixels_per_meter" qualifiers="const">
<return type="int" />
- <argument index="0" name="for_pixel_width" type="int" />
+ <param index="0" name="for_pixel_width" type="int" />
<description>
</description>
</method>
<method name="get_projection_plane" qualifiers="const">
<return type="Plane" />
- <argument index="0" name="plane" type="int" />
+ <param index="0" name="plane" type="int" />
<description>
</description>
</method>
@@ -199,13 +209,13 @@
</method>
<method name="jitter_offseted" qualifiers="const">
<return type="Projection" />
- <argument index="0" name="offset" type="Vector2" />
+ <param index="0" name="offset" type="Vector2" />
<description>
</description>
</method>
<method name="perspective_znear_adjusted" qualifiers="const">
<return type="Projection" />
- <argument index="0" name="new_znear" type="float" />
+ <param index="0" name="new_znear" type="float" />
<description>
</description>
</method>
@@ -241,31 +251,31 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="Projection" />
+ <param index="0" name="right" type="Projection" />
<description>
</description>
</operator>
<operator name="operator *">
<return type="Projection" />
- <argument index="0" name="right" type="Projection" />
+ <param index="0" name="right" type="Projection" />
<description>
</description>
</operator>
<operator name="operator *">
<return type="Vector4" />
- <argument index="0" name="right" type="Vector4" />
+ <param index="0" name="right" type="Vector4" />
<description>
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="Projection" />
+ <param index="0" name="right" type="Projection" />
<description>
</description>
</operator>
<operator name="operator []">
<return type="Vector4" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
</description>
</operator>
diff --git a/doc/classes/PropertyTweener.xml b/doc/classes/PropertyTweener.xml
index e0fbeec7c1..75d9c919aa 100644
--- a/doc/classes/PropertyTweener.xml
+++ b/doc/classes/PropertyTweener.xml
@@ -22,7 +22,7 @@
</method>
<method name="from">
<return type="PropertyTweener" />
- <argument index="0" name="value" type="Variant" />
+ <param index="0" name="value" type="Variant" />
<description>
Sets a custom initial value to the [PropertyTweener]. Example:
[codeblock]
@@ -43,21 +43,21 @@
</method>
<method name="set_delay">
<return type="PropertyTweener" />
- <argument index="0" name="delay" type="float" />
+ <param index="0" name="delay" type="float" />
<description>
Sets the time in seconds after which the [PropertyTweener] will start interpolating. By default there's no delay.
</description>
</method>
<method name="set_ease">
<return type="PropertyTweener" />
- <argument index="0" name="ease" type="int" enum="Tween.EaseType" />
+ <param index="0" name="ease" type="int" enum="Tween.EaseType" />
<description>
Sets the type of used easing from [enum Tween.EaseType]. If not set, the default easing is used from the [Tween] that contains this Tweener.
</description>
</method>
<method name="set_trans">
<return type="PropertyTweener" />
- <argument index="0" name="trans" type="int" enum="Tween.TransitionType" />
+ <param index="0" name="trans" type="int" enum="Tween.TransitionType" />
<description>
Sets the type of used transition from [enum Tween.TransitionType]. If not set, the default transition is used from the [Tween] that contains this Tweener.
</description>
diff --git a/doc/classes/ProxyTexture.xml b/doc/classes/ProxyTexture.xml
deleted file mode 100644
index 778e3f3f69..0000000000
--- a/doc/classes/ProxyTexture.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ProxyTexture" inherits="Texture2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="base" type="Texture2D" setter="set_base" getter="get_base">
- </member>
- </members>
-</class>
diff --git a/doc/classes/QuadMesh.xml b/doc/classes/QuadMesh.xml
deleted file mode 100644
index d641ebaa1f..0000000000
--- a/doc/classes/QuadMesh.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="QuadMesh" inherits="PrimitiveMesh" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- Class representing a square mesh.
- </brief_description>
- <description>
- Class representing a square [PrimitiveMesh]. This flat mesh does not have a thickness. By default, this mesh is aligned on the X and Y axes; this default rotation is more suited for use with billboarded materials. Unlike [PlaneMesh], this mesh doesn't provide subdivision options.
- </description>
- <tutorials>
- <link title="GUI in 3D Demo">https://godotengine.org/asset-library/asset/127</link>
- <link title="2D in 3D Demo">https://godotengine.org/asset-library/asset/129</link>
- </tutorials>
- <members>
- <member name="center_offset" type="Vector3" setter="set_center_offset" getter="get_center_offset" default="Vector3(0, 0, 0)">
- Offset of the generated Quad. Useful for particles.
- </member>
- <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2(1, 1)">
- Size on the X and Y axes.
- </member>
- </members>
-</class>
diff --git a/doc/classes/Quaternion.xml b/doc/classes/Quaternion.xml
index 30e96607da..a521af5709 100644
--- a/doc/classes/Quaternion.xml
+++ b/doc/classes/Quaternion.xml
@@ -21,45 +21,45 @@
</constructor>
<constructor name="Quaternion">
<return type="Quaternion" />
- <argument index="0" name="from" type="Quaternion" />
+ <param index="0" name="from" type="Quaternion" />
<description>
Constructs a [Quaternion] as a copy of the given [Quaternion].
</description>
</constructor>
<constructor name="Quaternion">
<return type="Quaternion" />
- <argument index="0" name="arc_from" type="Vector3" />
- <argument index="1" name="arc_to" type="Vector3" />
+ <param index="0" name="arc_from" type="Vector3" />
+ <param index="1" name="arc_to" type="Vector3" />
<description>
</description>
</constructor>
<constructor name="Quaternion">
<return type="Quaternion" />
- <argument index="0" name="axis" type="Vector3" />
- <argument index="1" name="angle" type="float" />
+ <param index="0" name="axis" type="Vector3" />
+ <param index="1" name="angle" type="float" />
<description>
Constructs a quaternion that will rotate around the given axis by the specified angle. The axis must be a normalized vector.
</description>
</constructor>
<constructor name="Quaternion">
<return type="Quaternion" />
- <argument index="0" name="euler_yxz" type="Vector3" />
+ <param index="0" name="euler_yxz" type="Vector3" />
<description>
</description>
</constructor>
<constructor name="Quaternion">
<return type="Quaternion" />
- <argument index="0" name="from" type="Basis" />
+ <param index="0" name="from" type="Basis" />
<description>
Constructs a quaternion from the given [Basis].
</description>
</constructor>
<constructor name="Quaternion">
<return type="Quaternion" />
- <argument index="0" name="x" type="float" />
- <argument index="1" name="y" type="float" />
- <argument index="2" name="z" type="float" />
- <argument index="3" name="w" type="float" />
+ <param index="0" name="x" type="float" />
+ <param index="1" name="y" type="float" />
+ <param index="2" name="z" type="float" />
+ <param index="3" name="w" type="float" />
<description>
Constructs a quaternion defined by the given values.
</description>
@@ -68,15 +68,15 @@
<methods>
<method name="angle_to" qualifiers="const">
<return type="float" />
- <argument index="0" name="to" type="Quaternion" />
+ <param index="0" name="to" type="Quaternion" />
<description>
- Returns the angle between this quaternion and [code]to[/code]. This is the magnitude of the angle you would need to rotate by to get from one to the other.
- [b]Note:[/b] This method has an abnormally high amount of floating-point error, so methods such as [code]is_zero_approx[/code] will not work reliably.
+ Returns the angle between this quaternion and [param to]. This is the magnitude of the angle you would need to rotate by to get from one to the other.
+ [b]Note:[/b] This method has an abnormally high number of floating-point errors, so methods such as [code]is_zero_approx[/code] will not work reliably.
</description>
</method>
<method name="dot" qualifiers="const">
<return type="float" />
- <argument index="0" name="with" type="Quaternion" />
+ <param index="0" name="with" type="Quaternion" />
<description>
Returns the dot product of two quaternions.
</description>
@@ -110,9 +110,9 @@
</method>
<method name="is_equal_approx" qualifiers="const">
<return type="bool" />
- <argument index="0" name="to" type="Quaternion" />
+ <param index="0" name="to" type="Quaternion" />
<description>
- Returns [code]true[/code] if this quaternion and [code]quat[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
+ Returns [code]true[/code] if this quaternion and [param to] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
<method name="is_normalized" qualifiers="const">
@@ -146,29 +146,43 @@
</method>
<method name="slerp" qualifiers="const">
<return type="Quaternion" />
- <argument index="0" name="to" type="Quaternion" />
- <argument index="1" name="weight" type="float" />
+ <param index="0" name="to" type="Quaternion" />
+ <param index="1" name="weight" type="float" />
<description>
- Returns the result of the spherical linear interpolation between this quaternion and [code]to[/code] by amount [code]weight[/code].
+ Returns the result of the spherical linear interpolation between this quaternion and [param to] by amount [param weight].
[b]Note:[/b] Both quaternions must be normalized.
</description>
</method>
<method name="slerpni" qualifiers="const">
<return type="Quaternion" />
- <argument index="0" name="to" type="Quaternion" />
- <argument index="1" name="weight" type="float" />
+ <param index="0" name="to" type="Quaternion" />
+ <param index="1" name="weight" type="float" />
<description>
- Returns the result of the spherical linear interpolation between this quaternion and [code]to[/code] by amount [code]weight[/code], but without checking if the rotation path is not bigger than 90 degrees.
+ Returns the result of the spherical linear interpolation between this quaternion and [param to] by amount [param weight], but without checking if the rotation path is not bigger than 90 degrees.
</description>
</method>
<method name="spherical_cubic_interpolate" qualifiers="const">
<return type="Quaternion" />
- <argument index="0" name="b" type="Quaternion" />
- <argument index="1" name="pre_a" type="Quaternion" />
- <argument index="2" name="post_b" type="Quaternion" />
- <argument index="3" name="weight" type="float" />
+ <param index="0" name="b" type="Quaternion" />
+ <param index="1" name="pre_a" type="Quaternion" />
+ <param index="2" name="post_b" type="Quaternion" />
+ <param index="3" name="weight" type="float" />
<description>
- Performs a spherical cubic interpolation between quaternions [code]pre_a[/code], this vector, [code]b[/code], and [code]post_b[/code], by the given amount [code]weight[/code].
+ Performs a spherical cubic interpolation between quaternions [param pre_a], this vector, [param b], and [param post_b], by the given amount [param weight].
+ </description>
+ </method>
+ <method name="spherical_cubic_interpolate_in_time" qualifiers="const">
+ <return type="Quaternion" />
+ <param index="0" name="b" type="Quaternion" />
+ <param index="1" name="pre_a" type="Quaternion" />
+ <param index="2" name="post_b" type="Quaternion" />
+ <param index="3" name="weight" type="float" />
+ <param index="4" name="b_t" type="float" />
+ <param index="5" name="pre_a_t" type="float" />
+ <param index="6" name="post_b_t" type="float" />
+ <description>
+ Performs a spherical cubic interpolation between quaternions [param pre_a], this vector, [param b], and [param post_b], by the given amount [param weight].
+ It can perform smoother interpolation than [code]spherical_cubic_interpolate()[/code] by the time values.
</description>
</method>
</methods>
@@ -198,7 +212,7 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="Quaternion" />
+ <param index="0" name="right" type="Quaternion" />
<description>
Returns [code]true[/code] if the quaternions are not equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
@@ -206,63 +220,63 @@
</operator>
<operator name="operator *">
<return type="Quaternion" />
- <argument index="0" name="right" type="Quaternion" />
+ <param index="0" name="right" type="Quaternion" />
<description>
Composes these two quaternions by multiplying them together. This has the effect of rotating the second quaternion (the child) by the first quaternion (the parent).
</description>
</operator>
<operator name="operator *">
<return type="Vector3" />
- <argument index="0" name="right" type="Vector3" />
+ <param index="0" name="right" type="Vector3" />
<description>
Rotates (multiplies) the [Vector3] by the given [Quaternion].
</description>
</operator>
<operator name="operator *">
<return type="Quaternion" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Multiplies each component of the [Quaternion] by the given value. This operation is not meaningful on its own, but it can be used as a part of a larger expression.
</description>
</operator>
<operator name="operator *">
<return type="Quaternion" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Multiplies each component of the [Quaternion] by the given value. This operation is not meaningful on its own, but it can be used as a part of a larger expression.
</description>
</operator>
<operator name="operator +">
<return type="Quaternion" />
- <argument index="0" name="right" type="Quaternion" />
+ <param index="0" name="right" type="Quaternion" />
<description>
Adds each component of the left [Quaternion] to the right [Quaternion]. This operation is not meaningful on its own, but it can be used as a part of a larger expression, such as approximating an intermediate rotation between two nearby rotations.
</description>
</operator>
<operator name="operator -">
<return type="Quaternion" />
- <argument index="0" name="right" type="Quaternion" />
+ <param index="0" name="right" type="Quaternion" />
<description>
Subtracts each component of the left [Quaternion] by the right [Quaternion]. This operation is not meaningful on its own, but it can be used as a part of a larger expression.
</description>
</operator>
<operator name="operator /">
<return type="Quaternion" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Divides each component of the [Quaternion] by the given value. This operation is not meaningful on its own, but it can be used as a part of a larger expression.
</description>
</operator>
<operator name="operator /">
<return type="Quaternion" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Divides each component of the [Quaternion] by the given value. This operation is not meaningful on its own, but it can be used as a part of a larger expression.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="Quaternion" />
+ <param index="0" name="right" type="Quaternion" />
<description>
Returns [code]true[/code] if the quaternions are exactly equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
@@ -270,7 +284,7 @@
</operator>
<operator name="operator []">
<return type="float" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Access quaternion components using their index. [code]q[0][/code] is equivalent to [code]q.x[/code], [code]q[1][/code] is equivalent to [code]q.y[/code], [code]q[2][/code] is equivalent to [code]q.z[/code], and [code]q[3][/code] is equivalent to [code]q.w[/code].
</description>
diff --git a/doc/classes/RDShaderFile.xml b/doc/classes/RDShaderFile.xml
index e719337f22..72bf6faaec 100644
--- a/doc/classes/RDShaderFile.xml
+++ b/doc/classes/RDShaderFile.xml
@@ -9,7 +9,7 @@
<methods>
<method name="get_spirv" qualifiers="const">
<return type="RDShaderSPIRV" />
- <argument index="0" name="version" type="StringName" default="&amp;&quot;&quot;" />
+ <param index="0" name="version" type="StringName" default="&amp;&quot;&quot;" />
<description>
</description>
</method>
@@ -20,8 +20,8 @@
</method>
<method name="set_bytecode">
<return type="void" />
- <argument index="0" name="bytecode" type="RDShaderSPIRV" />
- <argument index="1" name="version" type="StringName" default="&amp;&quot;&quot;" />
+ <param index="0" name="bytecode" type="RDShaderSPIRV" />
+ <param index="1" name="version" type="StringName" default="&amp;&quot;&quot;" />
<description>
</description>
</method>
diff --git a/doc/classes/RDShaderSPIRV.xml b/doc/classes/RDShaderSPIRV.xml
index 4453d7eb27..13dc2c6519 100644
--- a/doc/classes/RDShaderSPIRV.xml
+++ b/doc/classes/RDShaderSPIRV.xml
@@ -9,27 +9,27 @@
<methods>
<method name="get_stage_bytecode" qualifiers="const">
<return type="PackedByteArray" />
- <argument index="0" name="stage" type="int" enum="RenderingDevice.ShaderStage" />
+ <param index="0" name="stage" type="int" enum="RenderingDevice.ShaderStage" />
<description>
</description>
</method>
<method name="get_stage_compile_error" qualifiers="const">
<return type="String" />
- <argument index="0" name="stage" type="int" enum="RenderingDevice.ShaderStage" />
+ <param index="0" name="stage" type="int" enum="RenderingDevice.ShaderStage" />
<description>
</description>
</method>
<method name="set_stage_bytecode">
<return type="void" />
- <argument index="0" name="stage" type="int" enum="RenderingDevice.ShaderStage" />
- <argument index="1" name="bytecode" type="PackedByteArray" />
+ <param index="0" name="stage" type="int" enum="RenderingDevice.ShaderStage" />
+ <param index="1" name="bytecode" type="PackedByteArray" />
<description>
</description>
</method>
<method name="set_stage_compile_error">
<return type="void" />
- <argument index="0" name="stage" type="int" enum="RenderingDevice.ShaderStage" />
- <argument index="1" name="compile_error" type="String" />
+ <param index="0" name="stage" type="int" enum="RenderingDevice.ShaderStage" />
+ <param index="1" name="compile_error" type="String" />
<description>
</description>
</method>
diff --git a/doc/classes/RDShaderSource.xml b/doc/classes/RDShaderSource.xml
index 4c3c21bcb9..ddeae95e39 100644
--- a/doc/classes/RDShaderSource.xml
+++ b/doc/classes/RDShaderSource.xml
@@ -9,14 +9,14 @@
<methods>
<method name="get_stage_source" qualifiers="const">
<return type="String" />
- <argument index="0" name="stage" type="int" enum="RenderingDevice.ShaderStage" />
+ <param index="0" name="stage" type="int" enum="RenderingDevice.ShaderStage" />
<description>
</description>
</method>
<method name="set_stage_source">
<return type="void" />
- <argument index="0" name="stage" type="int" enum="RenderingDevice.ShaderStage" />
- <argument index="1" name="source" type="String" />
+ <param index="0" name="stage" type="int" enum="RenderingDevice.ShaderStage" />
+ <param index="1" name="source" type="String" />
<description>
</description>
</method>
diff --git a/doc/classes/RDTextureFormat.xml b/doc/classes/RDTextureFormat.xml
index fe2f6d7b1c..1b70303d2d 100644
--- a/doc/classes/RDTextureFormat.xml
+++ b/doc/classes/RDTextureFormat.xml
@@ -9,13 +9,13 @@
<methods>
<method name="add_shareable_format">
<return type="void" />
- <argument index="0" name="format" type="int" enum="RenderingDevice.DataFormat" />
+ <param index="0" name="format" type="int" enum="RenderingDevice.DataFormat" />
<description>
</description>
</method>
<method name="remove_shareable_format">
<return type="void" />
- <argument index="0" name="format" type="int" enum="RenderingDevice.DataFormat" />
+ <param index="0" name="format" type="int" enum="RenderingDevice.DataFormat" />
<description>
</description>
</method>
diff --git a/doc/classes/RDUniform.xml b/doc/classes/RDUniform.xml
index 29664d7c40..e4b7883f02 100644
--- a/doc/classes/RDUniform.xml
+++ b/doc/classes/RDUniform.xml
@@ -9,7 +9,7 @@
<methods>
<method name="add_id">
<return type="void" />
- <argument index="0" name="id" type="RID" />
+ <param index="0" name="id" type="RID" />
<description>
</description>
</method>
@@ -19,7 +19,7 @@
</description>
</method>
<method name="get_ids" qualifiers="const">
- <return type="Array" />
+ <return type="RID[]" />
<description>
</description>
</method>
diff --git a/doc/classes/RID.xml b/doc/classes/RID.xml
index 39be605e1b..a6523e4c8b 100644
--- a/doc/classes/RID.xml
+++ b/doc/classes/RID.xml
@@ -17,7 +17,7 @@
</constructor>
<constructor name="RID">
<return type="RID" />
- <argument index="0" name="from" type="RID" />
+ <param index="0" name="from" type="RID" />
<description>
Constructs a [RID] as a copy of the given [RID].
</description>
@@ -40,37 +40,37 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="RID" />
+ <param index="0" name="right" type="RID" />
<description>
</description>
</operator>
<operator name="operator &lt;">
<return type="bool" />
- <argument index="0" name="right" type="RID" />
+ <param index="0" name="right" type="RID" />
<description>
</description>
</operator>
<operator name="operator &lt;=">
<return type="bool" />
- <argument index="0" name="right" type="RID" />
+ <param index="0" name="right" type="RID" />
<description>
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="RID" />
+ <param index="0" name="right" type="RID" />
<description>
</description>
</operator>
<operator name="operator &gt;">
<return type="bool" />
- <argument index="0" name="right" type="RID" />
+ <param index="0" name="right" type="RID" />
<description>
</description>
</operator>
<operator name="operator &gt;=">
<return type="bool" />
- <argument index="0" name="right" type="RID" />
+ <param index="0" name="right" type="RID" />
<description>
</description>
</operator>
diff --git a/doc/classes/RandomNumberGenerator.xml b/doc/classes/RandomNumberGenerator.xml
index 28151e858e..b8a290381f 100644
--- a/doc/classes/RandomNumberGenerator.xml
+++ b/doc/classes/RandomNumberGenerator.xml
@@ -27,18 +27,18 @@
</method>
<method name="randf_range">
<return type="float" />
- <argument index="0" name="from" type="float" />
- <argument index="1" name="to" type="float" />
+ <param index="0" name="from" type="float" />
+ <param index="1" name="to" type="float" />
<description>
- Returns a pseudo-random float between [code]from[/code] and [code]to[/code] (inclusive).
+ Returns a pseudo-random float between [param from] and [param to] (inclusive).
</description>
</method>
<method name="randfn">
<return type="float" />
- <argument index="0" name="mean" type="float" default="0.0" />
- <argument index="1" name="deviation" type="float" default="1.0" />
+ <param index="0" name="mean" type="float" default="0.0" />
+ <param index="1" name="deviation" type="float" default="1.0" />
<description>
- Returns a [url=https://en.wikipedia.org/wiki/Normal_distribution]normally-distributed[/url] pseudo-random number, using Box-Muller transform with the specified [code]mean[/code] and a standard [code]deviation[/code]. This is also called Gaussian distribution.
+ Returns a [url=https://en.wikipedia.org/wiki/Normal_distribution]normally-distributed[/url] pseudo-random number, using Box-Muller transform with the specified [param mean] and a standard [param deviation]. This is also called Gaussian distribution.
</description>
</method>
<method name="randi">
@@ -49,10 +49,10 @@
</method>
<method name="randi_range">
<return type="int" />
- <argument index="0" name="from" type="int" />
- <argument index="1" name="to" type="int" />
+ <param index="0" name="from" type="int" />
+ <param index="1" name="to" type="int" />
<description>
- Returns a pseudo-random 32-bit signed integer between [code]from[/code] and [code]to[/code] (inclusive).
+ Returns a pseudo-random 32-bit signed integer between [param from] and [param to] (inclusive).
</description>
</method>
<method name="randomize">
diff --git a/doc/classes/Range.xml b/doc/classes/Range.xml
index 22793e75d8..16e6e86f9e 100644
--- a/doc/classes/Range.xml
+++ b/doc/classes/Range.xml
@@ -11,14 +11,14 @@
<methods>
<method name="_value_changed" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="new_value" type="float" />
+ <param index="0" name="new_value" type="float" />
<description>
Called when the [Range]'s value is changed (following the same conditions as [signal value_changed]).
</description>
</method>
<method name="share">
<return type="void" />
- <argument index="0" name="with" type="Node" />
+ <param index="0" name="with" type="Node" />
<description>
Binds two [Range]s together along with any ranges previously grouped with either of them. When any of range's member variables change, it will share the new value with all other ranges in its group.
</description>
@@ -69,10 +69,10 @@
</description>
</signal>
<signal name="value_changed">
- <argument index="0" name="value" type="float" />
+ <param index="0" name="value" type="float" />
<description>
Emitted when [member value] changes. When used on a [Slider], this is called continuously while dragging (potentially every frame). If you are performing an expensive operation in a function connected to [signal value_changed], consider using a [i]debouncing[/i] [Timer] to call the function less often.
- [b]Note:[/b] Unlike signals such as [signal LineEdit.text_changed], [signal value_changed] is also emitted when [code]value[/code] is set directly via code.
+ [b]Note:[/b] Unlike signals such as [signal LineEdit.text_changed], [signal value_changed] is also emitted when [param value] is set directly via code.
</description>
</signal>
</signals>
diff --git a/doc/classes/RayCast2D.xml b/doc/classes/RayCast2D.xml
index 2a7d3502df..08627b0bd5 100644
--- a/doc/classes/RayCast2D.xml
+++ b/doc/classes/RayCast2D.xml
@@ -16,14 +16,14 @@
<methods>
<method name="add_exception">
<return type="void" />
- <argument index="0" name="node" type="CollisionObject2D" />
+ <param index="0" name="node" type="CollisionObject2D" />
<description>
Adds a collision exception so the ray does not report collisions with the specified [CollisionObject2D] node.
</description>
</method>
<method name="add_exception_rid">
<return type="void" />
- <argument index="0" name="rid" type="RID" />
+ <param index="0" name="rid" type="RID" />
<description>
Adds a collision exception so the ray does not report collisions with the specified [RID].
</description>
@@ -47,6 +47,12 @@
Returns the first object that the ray intersects, or [code]null[/code] if no object is intersecting the ray (i.e. [method is_colliding] returns [code]false[/code]).
</description>
</method>
+ <method name="get_collider_rid" qualifiers="const">
+ <return type="RID" />
+ <description>
+ Returns the [RID] of the first object that the ray intersects, or an empty [RID] if no object is intersecting the ray (i.e. [method is_colliding] returns [code]false[/code]).
+ </description>
+ </method>
<method name="get_collider_shape" qualifiers="const">
<return type="int" />
<description>
@@ -55,9 +61,9 @@
</method>
<method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
- Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
+ Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="get_collision_normal" qualifiers="const">
@@ -81,24 +87,24 @@
</method>
<method name="remove_exception">
<return type="void" />
- <argument index="0" name="node" type="CollisionObject2D" />
+ <param index="0" name="node" type="CollisionObject2D" />
<description>
Removes a collision exception so the ray does report collisions with the specified [CollisionObject2D] node.
</description>
</method>
<method name="remove_exception_rid">
<return type="void" />
- <argument index="0" name="rid" type="RID" />
+ <param index="0" name="rid" type="RID" />
<description>
Removes a collision exception so the ray does report collisions with the specified [RID].
</description>
</method>
<method name="set_collision_mask_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
- Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
+ Based on [param value], enables or disables the specified layer in the [member collision_mask], given a [param layer_number] between 1 and 32.
</description>
</method>
</methods>
diff --git a/doc/classes/RayCast3D.xml b/doc/classes/RayCast3D.xml
index 65437daa79..1bcd6f1f31 100644
--- a/doc/classes/RayCast3D.xml
+++ b/doc/classes/RayCast3D.xml
@@ -17,14 +17,14 @@
<methods>
<method name="add_exception">
<return type="void" />
- <argument index="0" name="node" type="CollisionObject3D" />
+ <param index="0" name="node" type="CollisionObject3D" />
<description>
Adds a collision exception so the ray does not report collisions with the specified [CollisionObject3D] node.
</description>
</method>
<method name="add_exception_rid">
<return type="void" />
- <argument index="0" name="rid" type="RID" />
+ <param index="0" name="rid" type="RID" />
<description>
Adds a collision exception so the ray does not report collisions with the specified [RID].
</description>
@@ -48,6 +48,12 @@
Returns the first object that the ray intersects, or [code]null[/code] if no object is intersecting the ray (i.e. [method is_colliding] returns [code]false[/code]).
</description>
</method>
+ <method name="get_collider_rid" qualifiers="const">
+ <return type="RID" />
+ <description>
+ Returns the [RID] of the first object that the ray intersects, or an empty [RID] if no object is intersecting the ray (i.e. [method is_colliding] returns [code]false[/code]).
+ </description>
+ </method>
<method name="get_collider_shape" qualifiers="const">
<return type="int" />
<description>
@@ -56,9 +62,9 @@
</method>
<method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
- Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
+ Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="get_collision_normal" qualifiers="const">
@@ -82,24 +88,24 @@
</method>
<method name="remove_exception">
<return type="void" />
- <argument index="0" name="node" type="CollisionObject3D" />
+ <param index="0" name="node" type="CollisionObject3D" />
<description>
Removes a collision exception so the ray does report collisions with the specified [CollisionObject3D] node.
</description>
</method>
<method name="remove_exception_rid">
<return type="void" />
- <argument index="0" name="rid" type="RID" />
+ <param index="0" name="rid" type="RID" />
<description>
Removes a collision exception so the ray does report collisions with the specified [RID].
</description>
</method>
<method name="set_collision_mask_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
- Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
+ Based on [param value], enables or disables the specified layer in the [member collision_mask], given a [param layer_number] between 1 and 32.
</description>
</method>
</methods>
diff --git a/doc/classes/Rect2.xml b/doc/classes/Rect2.xml
index e4b66a9d53..7132f4f0b5 100644
--- a/doc/classes/Rect2.xml
+++ b/doc/classes/Rect2.xml
@@ -23,32 +23,32 @@
</constructor>
<constructor name="Rect2">
<return type="Rect2" />
- <argument index="0" name="from" type="Rect2" />
+ <param index="0" name="from" type="Rect2" />
<description>
Constructs a [Rect2] as a copy of the given [Rect2].
</description>
</constructor>
<constructor name="Rect2">
<return type="Rect2" />
- <argument index="0" name="from" type="Rect2i" />
+ <param index="0" name="from" type="Rect2i" />
<description>
Constructs a [Rect2] from a [Rect2i].
</description>
</constructor>
<constructor name="Rect2">
<return type="Rect2" />
- <argument index="0" name="position" type="Vector2" />
- <argument index="1" name="size" type="Vector2" />
+ <param index="0" name="position" type="Vector2" />
+ <param index="1" name="size" type="Vector2" />
<description>
Constructs a [Rect2] by position and size.
</description>
</constructor>
<constructor name="Rect2">
<return type="Rect2" />
- <argument index="0" name="x" type="float" />
- <argument index="1" name="y" type="float" />
- <argument index="2" name="width" type="float" />
- <argument index="3" name="height" type="float" />
+ <param index="0" name="x" type="float" />
+ <param index="1" name="y" type="float" />
+ <param index="2" name="width" type="float" />
+ <param index="3" name="height" type="float" />
<description>
Constructs a [Rect2] by x, y, width, and height.
</description>
@@ -63,14 +63,14 @@
</method>
<method name="encloses" qualifiers="const">
<return type="bool" />
- <argument index="0" name="b" type="Rect2" />
+ <param index="0" name="b" type="Rect2" />
<description>
Returns [code]true[/code] if this [Rect2] completely encloses another one.
</description>
</method>
<method name="expand" qualifiers="const">
<return type="Rect2" />
- <argument index="0" name="to" type="Vector2" />
+ <param index="0" name="to" type="Vector2" />
<description>
Returns a copy of this [Rect2] expanded to include a given point.
[b]Example:[/b]
@@ -104,27 +104,27 @@
</method>
<method name="grow" qualifiers="const">
<return type="Rect2" />
- <argument index="0" name="amount" type="float" />
+ <param index="0" name="amount" type="float" />
<description>
- Returns a copy of the [Rect2] grown by the specified [code]amount[/code] on all sides.
+ Returns a copy of the [Rect2] grown by the specified [param amount] on all sides.
</description>
</method>
<method name="grow_individual" qualifiers="const">
<return type="Rect2" />
- <argument index="0" name="left" type="float" />
- <argument index="1" name="top" type="float" />
- <argument index="2" name="right" type="float" />
- <argument index="3" name="bottom" type="float" />
+ <param index="0" name="left" type="float" />
+ <param index="1" name="top" type="float" />
+ <param index="2" name="right" type="float" />
+ <param index="3" name="bottom" type="float" />
<description>
Returns a copy of the [Rect2] grown by the specified amount on each side individually.
</description>
</method>
<method name="grow_side" qualifiers="const">
<return type="Rect2" />
- <argument index="0" name="side" type="int" />
- <argument index="1" name="amount" type="float" />
+ <param index="0" name="side" type="int" />
+ <param index="1" name="amount" type="float" />
<description>
- Returns a copy of the [Rect2] grown by the specified [code]amount[/code] on the specified [enum Side].
+ Returns a copy of the [Rect2] grown by the specified [param amount] on the specified [enum Side].
</description>
</method>
<method name="has_no_area" qualifiers="const">
@@ -136,7 +136,7 @@
</method>
<method name="has_point" qualifiers="const">
<return type="bool" />
- <argument index="0" name="point" type="Vector2" />
+ <param index="0" name="point" type="Vector2" />
<description>
Returns [code]true[/code] if the [Rect2] contains a point. By convention, the right and bottom edges of the [Rect2] are considered exclusive, so points on these edges are [b]not[/b] included.
[b]Note:[/b] This method is not reliable for [Rect2] with a [i]negative size[/i]. Use [method abs] to get a positive sized equivalent rectangle to check for contained points.
@@ -144,33 +144,33 @@
</method>
<method name="intersection" qualifiers="const">
<return type="Rect2" />
- <argument index="0" name="b" type="Rect2" />
+ <param index="0" name="b" type="Rect2" />
<description>
- Returns the intersection of this [Rect2] and [code]b[/code].
+ Returns the intersection of this [Rect2] and [param b].
If the rectangles do not intersect, an empty [Rect2] is returned.
</description>
</method>
<method name="intersects" qualifiers="const">
<return type="bool" />
- <argument index="0" name="b" type="Rect2" />
- <argument index="1" name="include_borders" type="bool" default="false" />
+ <param index="0" name="b" type="Rect2" />
+ <param index="1" name="include_borders" type="bool" default="false" />
<description>
Returns [code]true[/code] if the [Rect2] overlaps with [code]b[/code] (i.e. they have at least one point in common).
- If [code]include_borders[/code] is [code]true[/code], they will also be considered overlapping if their borders touch, even without intersection.
+ If [param include_borders] is [code]true[/code], they will also be considered overlapping if their borders touch, even without intersection.
</description>
</method>
<method name="is_equal_approx" qualifiers="const">
<return type="bool" />
- <argument index="0" name="rect" type="Rect2" />
+ <param index="0" name="rect" type="Rect2" />
<description>
- Returns [code]true[/code] if this [Rect2] and [code]rect[/code] are approximately equal, by calling [code]is_equal_approx[/code] on each component.
+ Returns [code]true[/code] if this [Rect2] and [param rect] are approximately equal, by calling [code]is_equal_approx[/code] on each component.
</description>
</method>
<method name="merge" qualifiers="const">
<return type="Rect2" />
- <argument index="0" name="b" type="Rect2" />
+ <param index="0" name="b" type="Rect2" />
<description>
- Returns a larger [Rect2] that contains this [Rect2] and [code]b[/code].
+ Returns a larger [Rect2] that contains this [Rect2] and [param b].
</description>
</method>
</methods>
@@ -189,7 +189,7 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="Rect2" />
+ <param index="0" name="right" type="Rect2" />
<description>
Returns [code]true[/code] if the rectangles are not equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
@@ -197,14 +197,14 @@
</operator>
<operator name="operator *">
<return type="Rect2" />
- <argument index="0" name="right" type="Transform2D" />
+ <param index="0" name="right" type="Transform2D" />
<description>
Inversely transforms (multiplies) the [Rect2] by the given [Transform2D] transformation matrix.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="Rect2" />
+ <param index="0" name="right" type="Rect2" />
<description>
Returns [code]true[/code] if the rectangles are exactly equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
diff --git a/doc/classes/Rect2i.xml b/doc/classes/Rect2i.xml
index c9ae685a15..d5d68bde31 100644
--- a/doc/classes/Rect2i.xml
+++ b/doc/classes/Rect2i.xml
@@ -21,32 +21,32 @@
</constructor>
<constructor name="Rect2i">
<return type="Rect2i" />
- <argument index="0" name="from" type="Rect2i" />
+ <param index="0" name="from" type="Rect2i" />
<description>
Constructs a [Rect2i] as a copy of the given [Rect2i].
</description>
</constructor>
<constructor name="Rect2i">
<return type="Rect2i" />
- <argument index="0" name="from" type="Rect2" />
+ <param index="0" name="from" type="Rect2" />
<description>
Constructs a new [Rect2i] from [Rect2]. The floating point coordinates will be truncated.
</description>
</constructor>
<constructor name="Rect2i">
<return type="Rect2i" />
- <argument index="0" name="position" type="Vector2i" />
- <argument index="1" name="size" type="Vector2i" />
+ <param index="0" name="position" type="Vector2i" />
+ <param index="1" name="size" type="Vector2i" />
<description>
Constructs a [Rect2i] by position and size.
</description>
</constructor>
<constructor name="Rect2i">
<return type="Rect2i" />
- <argument index="0" name="x" type="int" />
- <argument index="1" name="y" type="int" />
- <argument index="2" name="width" type="int" />
- <argument index="3" name="height" type="int" />
+ <param index="0" name="x" type="int" />
+ <param index="1" name="y" type="int" />
+ <param index="2" name="width" type="int" />
+ <param index="3" name="height" type="int" />
<description>
Constructs a [Rect2i] by x, y, width, and height.
</description>
@@ -61,14 +61,14 @@
</method>
<method name="encloses" qualifiers="const">
<return type="bool" />
- <argument index="0" name="b" type="Rect2i" />
+ <param index="0" name="b" type="Rect2i" />
<description>
Returns [code]true[/code] if this [Rect2i] completely encloses another one.
</description>
</method>
<method name="expand" qualifiers="const">
<return type="Rect2i" />
- <argument index="0" name="to" type="Vector2i" />
+ <param index="0" name="to" type="Vector2i" />
<description>
Returns a copy of this [Rect2i] expanded so that the borders align with the given point.
[codeblocks]
@@ -102,27 +102,27 @@
</method>
<method name="grow" qualifiers="const">
<return type="Rect2i" />
- <argument index="0" name="amount" type="int" />
+ <param index="0" name="amount" type="int" />
<description>
- Returns a copy of the [Rect2i] grown by the specified [code]amount[/code] on all sides.
+ Returns a copy of the [Rect2i] grown by the specified [param amount] on all sides.
</description>
</method>
<method name="grow_individual" qualifiers="const">
<return type="Rect2i" />
- <argument index="0" name="left" type="int" />
- <argument index="1" name="top" type="int" />
- <argument index="2" name="right" type="int" />
- <argument index="3" name="bottom" type="int" />
+ <param index="0" name="left" type="int" />
+ <param index="1" name="top" type="int" />
+ <param index="2" name="right" type="int" />
+ <param index="3" name="bottom" type="int" />
<description>
Returns a copy of the [Rect2i] grown by the specified amount on each side individually.
</description>
</method>
<method name="grow_side" qualifiers="const">
<return type="Rect2i" />
- <argument index="0" name="side" type="int" />
- <argument index="1" name="amount" type="int" />
+ <param index="0" name="side" type="int" />
+ <param index="1" name="amount" type="int" />
<description>
- Returns a copy of the [Rect2i] grown by the specified [code]amount[/code] on the specified [enum Side].
+ Returns a copy of the [Rect2i] grown by the specified [param amount] on the specified [enum Side].
</description>
</method>
<method name="has_no_area" qualifiers="const">
@@ -134,7 +134,7 @@
</method>
<method name="has_point" qualifiers="const">
<return type="bool" />
- <argument index="0" name="point" type="Vector2i" />
+ <param index="0" name="point" type="Vector2i" />
<description>
Returns [code]true[/code] if the [Rect2i] contains a point. By convention, the right and bottom edges of the [Rect2i] are considered exclusive, so points on these edges are [b]not[/b] included.
[b]Note:[/b] This method is not reliable for [Rect2i] with a [i]negative size[/i]. Use [method abs] to get a positive sized equivalent rectangle to check for contained points.
@@ -142,7 +142,7 @@
</method>
<method name="intersection" qualifiers="const">
<return type="Rect2i" />
- <argument index="0" name="b" type="Rect2i" />
+ <param index="0" name="b" type="Rect2i" />
<description>
Returns the intersection of this [Rect2i] and [code]b[/code].
If the rectangles do not intersect, an empty [Rect2i] is returned.
@@ -150,16 +150,16 @@
</method>
<method name="intersects" qualifiers="const">
<return type="bool" />
- <argument index="0" name="b" type="Rect2i" />
+ <param index="0" name="b" type="Rect2i" />
<description>
Returns [code]true[/code] if the [Rect2i] overlaps with [code]b[/code] (i.e. they have at least one point in common).
</description>
</method>
<method name="merge" qualifiers="const">
<return type="Rect2i" />
- <argument index="0" name="b" type="Rect2i" />
+ <param index="0" name="b" type="Rect2i" />
<description>
- Returns a larger [Rect2i] that contains this [Rect2i] and [code]b[/code].
+ Returns a larger [Rect2i] that contains this [Rect2i] and [param b].
</description>
</method>
</methods>
@@ -178,14 +178,14 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="Rect2i" />
+ <param index="0" name="right" type="Rect2i" />
<description>
Returns [code]true[/code] if the rectangles are not equal.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="Rect2i" />
+ <param index="0" name="right" type="Rect2i" />
<description>
Returns [code]true[/code] if the rectangles are equal.
</description>
diff --git a/doc/classes/ReflectionProbe.xml b/doc/classes/ReflectionProbe.xml
index ff66a89cb7..fee48dd246 100644
--- a/doc/classes/ReflectionProbe.xml
+++ b/doc/classes/ReflectionProbe.xml
@@ -50,7 +50,7 @@
[b]Note:[/b] [member mesh_lod_threshold] does not affect [GeometryInstance3D] visibility ranges (also known as "manual" LOD or hierarchical LOD).
</member>
<member name="origin_offset" type="Vector3" setter="set_origin_offset" getter="get_origin_offset" default="Vector3(0, 0, 0)">
- Sets the origin offset to be used when this [ReflectionProbe] is in [member box_projection] mode. This can be set to a non-zero value to ensure a reflection fits a rectangle-shaped room, while reducing the amount of objects that "get in the way" of the reflection.
+ Sets the origin offset to be used when this [ReflectionProbe] is in [member box_projection] mode. This can be set to a non-zero value to ensure a reflection fits a rectangle-shaped room, while reducing the number of objects that "get in the way" of the reflection.
</member>
<member name="update_mode" type="int" setter="set_update_mode" getter="get_update_mode" enum="ReflectionProbe.UpdateMode" default="0">
Sets how frequently the [ReflectionProbe] is updated. Can be [constant UPDATE_ONCE] or [constant UPDATE_ALWAYS].
diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml
index 6248394b1a..718a161323 100644
--- a/doc/classes/RenderingDevice.xml
+++ b/doc/classes/RenderingDevice.xml
@@ -9,102 +9,102 @@
<methods>
<method name="barrier">
<return type="void" />
- <argument index="0" name="from" type="int" default="7" />
- <argument index="1" name="to" type="int" default="7" />
+ <param index="0" name="from" type="int" default="7" />
+ <param index="1" name="to" type="int" default="7" />
<description>
</description>
</method>
<method name="buffer_clear">
<return type="int" enum="Error" />
- <argument index="0" name="buffer" type="RID" />
- <argument index="1" name="offset" type="int" />
- <argument index="2" name="size_bytes" type="int" />
- <argument index="3" name="post_barrier" type="int" default="7" />
+ <param index="0" name="buffer" type="RID" />
+ <param index="1" name="offset" type="int" />
+ <param index="2" name="size_bytes" type="int" />
+ <param index="3" name="post_barrier" type="int" default="7" />
<description>
</description>
</method>
<method name="buffer_get_data">
<return type="PackedByteArray" />
- <argument index="0" name="buffer" type="RID" />
+ <param index="0" name="buffer" type="RID" />
<description>
</description>
</method>
<method name="buffer_update">
<return type="int" enum="Error" />
- <argument index="0" name="buffer" type="RID" />
- <argument index="1" name="offset" type="int" />
- <argument index="2" name="size_bytes" type="int" />
- <argument index="3" name="data" type="PackedByteArray" />
- <argument index="4" name="post_barrier" type="int" default="7" />
+ <param index="0" name="buffer" type="RID" />
+ <param index="1" name="offset" type="int" />
+ <param index="2" name="size_bytes" type="int" />
+ <param index="3" name="data" type="PackedByteArray" />
+ <param index="4" name="post_barrier" type="int" default="7" />
<description>
</description>
</method>
<method name="capture_timestamp">
<return type="void" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
</description>
</method>
<method name="compute_list_add_barrier">
<return type="void" />
- <argument index="0" name="compute_list" type="int" />
+ <param index="0" name="compute_list" type="int" />
<description>
</description>
</method>
<method name="compute_list_begin">
<return type="int" />
- <argument index="0" name="allow_draw_overlap" type="bool" default="false" />
+ <param index="0" name="allow_draw_overlap" type="bool" default="false" />
<description>
</description>
</method>
<method name="compute_list_bind_compute_pipeline">
<return type="void" />
- <argument index="0" name="compute_list" type="int" />
- <argument index="1" name="compute_pipeline" type="RID" />
+ <param index="0" name="compute_list" type="int" />
+ <param index="1" name="compute_pipeline" type="RID" />
<description>
</description>
</method>
<method name="compute_list_bind_uniform_set">
<return type="void" />
- <argument index="0" name="compute_list" type="int" />
- <argument index="1" name="uniform_set" type="RID" />
- <argument index="2" name="set_index" type="int" />
+ <param index="0" name="compute_list" type="int" />
+ <param index="1" name="uniform_set" type="RID" />
+ <param index="2" name="set_index" type="int" />
<description>
</description>
</method>
<method name="compute_list_dispatch">
<return type="void" />
- <argument index="0" name="compute_list" type="int" />
- <argument index="1" name="x_groups" type="int" />
- <argument index="2" name="y_groups" type="int" />
- <argument index="3" name="z_groups" type="int" />
+ <param index="0" name="compute_list" type="int" />
+ <param index="1" name="x_groups" type="int" />
+ <param index="2" name="y_groups" type="int" />
+ <param index="3" name="z_groups" type="int" />
<description>
</description>
</method>
<method name="compute_list_end">
<return type="void" />
- <argument index="0" name="post_barrier" type="int" default="7" />
+ <param index="0" name="post_barrier" type="int" default="7" />
<description>
</description>
</method>
<method name="compute_list_set_push_constant">
<return type="void" />
- <argument index="0" name="compute_list" type="int" />
- <argument index="1" name="buffer" type="PackedByteArray" />
- <argument index="2" name="size_bytes" type="int" />
+ <param index="0" name="compute_list" type="int" />
+ <param index="1" name="buffer" type="PackedByteArray" />
+ <param index="2" name="size_bytes" type="int" />
<description>
</description>
</method>
<method name="compute_pipeline_create">
<return type="RID" />
- <argument index="0" name="shader" type="RID" />
- <argument index="1" name="specialization_constants" type="RDPipelineSpecializationConstant[]" default="[]" />
+ <param index="0" name="shader" type="RID" />
+ <param index="1" name="specialization_constants" type="RDPipelineSpecializationConstant[]" default="[]" />
<description>
</description>
</method>
<method name="compute_pipeline_is_valid">
<return type="bool" />
- <argument index="0" name="compute_pieline" type="RID" />
+ <param index="0" name="compute_pieline" type="RID" />
<description>
</description>
</method>
@@ -115,8 +115,8 @@
</method>
<method name="draw_command_begin_label">
<return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="color" type="Color" />
<description>
</description>
</method>
@@ -127,111 +127,119 @@
</method>
<method name="draw_command_insert_label">
<return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="color" type="Color" />
<description>
</description>
</method>
<method name="draw_list_begin">
<return type="int" />
- <argument index="0" name="framebuffer" type="RID" />
- <argument index="1" name="initial_color_action" type="int" enum="RenderingDevice.InitialAction" />
- <argument index="2" name="final_color_action" type="int" enum="RenderingDevice.FinalAction" />
- <argument index="3" name="initial_depth_action" type="int" enum="RenderingDevice.InitialAction" />
- <argument index="4" name="final_depth_action" type="int" enum="RenderingDevice.FinalAction" />
- <argument index="5" name="clear_color_values" type="PackedColorArray" default="PackedColorArray()" />
- <argument index="6" name="clear_depth" type="float" default="1.0" />
- <argument index="7" name="clear_stencil" type="int" default="0" />
- <argument index="8" name="region" type="Rect2" default="Rect2(0, 0, 0, 0)" />
- <argument index="9" name="storage_textures" type="Array" default="[]" />
+ <param index="0" name="framebuffer" type="RID" />
+ <param index="1" name="initial_color_action" type="int" enum="RenderingDevice.InitialAction" />
+ <param index="2" name="final_color_action" type="int" enum="RenderingDevice.FinalAction" />
+ <param index="3" name="initial_depth_action" type="int" enum="RenderingDevice.InitialAction" />
+ <param index="4" name="final_depth_action" type="int" enum="RenderingDevice.FinalAction" />
+ <param index="5" name="clear_color_values" type="PackedColorArray" default="PackedColorArray()" />
+ <param index="6" name="clear_depth" type="float" default="1.0" />
+ <param index="7" name="clear_stencil" type="int" default="0" />
+ <param index="8" name="region" type="Rect2" default="Rect2(0, 0, 0, 0)" />
+ <param index="9" name="storage_textures" type="Array" default="[]" />
<description>
</description>
</method>
<method name="draw_list_begin_for_screen">
<return type="int" />
- <argument index="0" name="screen" type="int" default="0" />
- <argument index="1" name="clear_color" type="Color" default="Color(0, 0, 0, 1)" />
+ <param index="0" name="screen" type="int" default="0" />
+ <param index="1" name="clear_color" type="Color" default="Color(0, 0, 0, 1)" />
<description>
</description>
</method>
<method name="draw_list_begin_split">
<return type="PackedInt64Array" />
- <argument index="0" name="framebuffer" type="RID" />
- <argument index="1" name="splits" type="int" />
- <argument index="2" name="initial_color_action" type="int" enum="RenderingDevice.InitialAction" />
- <argument index="3" name="final_color_action" type="int" enum="RenderingDevice.FinalAction" />
- <argument index="4" name="initial_depth_action" type="int" enum="RenderingDevice.InitialAction" />
- <argument index="5" name="final_depth_action" type="int" enum="RenderingDevice.FinalAction" />
- <argument index="6" name="clear_color_values" type="PackedColorArray" default="PackedColorArray()" />
- <argument index="7" name="clear_depth" type="float" default="1.0" />
- <argument index="8" name="clear_stencil" type="int" default="0" />
- <argument index="9" name="region" type="Rect2" default="Rect2(0, 0, 0, 0)" />
- <argument index="10" name="storage_textures" type="RID[]" default="[]" />
+ <param index="0" name="framebuffer" type="RID" />
+ <param index="1" name="splits" type="int" />
+ <param index="2" name="initial_color_action" type="int" enum="RenderingDevice.InitialAction" />
+ <param index="3" name="final_color_action" type="int" enum="RenderingDevice.FinalAction" />
+ <param index="4" name="initial_depth_action" type="int" enum="RenderingDevice.InitialAction" />
+ <param index="5" name="final_depth_action" type="int" enum="RenderingDevice.FinalAction" />
+ <param index="6" name="clear_color_values" type="PackedColorArray" default="PackedColorArray()" />
+ <param index="7" name="clear_depth" type="float" default="1.0" />
+ <param index="8" name="clear_stencil" type="int" default="0" />
+ <param index="9" name="region" type="Rect2" default="Rect2(0, 0, 0, 0)" />
+ <param index="10" name="storage_textures" type="RID[]" default="[]" />
<description>
</description>
</method>
<method name="draw_list_bind_index_array">
<return type="void" />
- <argument index="0" name="draw_list" type="int" />
- <argument index="1" name="index_array" type="RID" />
+ <param index="0" name="draw_list" type="int" />
+ <param index="1" name="index_array" type="RID" />
<description>
</description>
</method>
<method name="draw_list_bind_render_pipeline">
<return type="void" />
- <argument index="0" name="draw_list" type="int" />
- <argument index="1" name="render_pipeline" type="RID" />
+ <param index="0" name="draw_list" type="int" />
+ <param index="1" name="render_pipeline" type="RID" />
<description>
</description>
</method>
<method name="draw_list_bind_uniform_set">
<return type="void" />
- <argument index="0" name="draw_list" type="int" />
- <argument index="1" name="uniform_set" type="RID" />
- <argument index="2" name="set_index" type="int" />
+ <param index="0" name="draw_list" type="int" />
+ <param index="1" name="uniform_set" type="RID" />
+ <param index="2" name="set_index" type="int" />
<description>
</description>
</method>
<method name="draw_list_bind_vertex_array">
<return type="void" />
- <argument index="0" name="draw_list" type="int" />
- <argument index="1" name="vertex_array" type="RID" />
+ <param index="0" name="draw_list" type="int" />
+ <param index="1" name="vertex_array" type="RID" />
<description>
</description>
</method>
<method name="draw_list_disable_scissor">
<return type="void" />
- <argument index="0" name="draw_list" type="int" />
+ <param index="0" name="draw_list" type="int" />
<description>
</description>
</method>
<method name="draw_list_draw">
<return type="void" />
- <argument index="0" name="draw_list" type="int" />
- <argument index="1" name="use_indices" type="bool" />
- <argument index="2" name="instances" type="int" />
- <argument index="3" name="procedural_vertex_count" type="int" default="0" />
+ <param index="0" name="draw_list" type="int" />
+ <param index="1" name="use_indices" type="bool" />
+ <param index="2" name="instances" type="int" />
+ <param index="3" name="procedural_vertex_count" type="int" default="0" />
<description>
</description>
</method>
<method name="draw_list_enable_scissor">
<return type="void" />
- <argument index="0" name="draw_list" type="int" />
- <argument index="1" name="rect" type="Rect2" default="Rect2(0, 0, 0, 0)" />
+ <param index="0" name="draw_list" type="int" />
+ <param index="1" name="rect" type="Rect2" default="Rect2(0, 0, 0, 0)" />
<description>
</description>
</method>
<method name="draw_list_end">
<return type="void" />
- <argument index="0" name="post_barrier" type="int" default="7" />
+ <param index="0" name="post_barrier" type="int" default="7" />
<description>
</description>
</method>
+ <method name="draw_list_set_blend_constants">
+ <return type="void" />
+ <param index="0" name="draw_list" type="int" />
+ <param index="1" name="color" type="Color" />
+ <description>
+ Sets blend constants for draw list, blend constants are used only if the graphics pipeline is created with [code]DYNAMIC_STATE_BLEND_CONSTANTS[/code] flag set.
+ </description>
+ </method>
<method name="draw_list_set_push_constant">
<return type="void" />
- <argument index="0" name="draw_list" type="int" />
- <argument index="1" name="buffer" type="PackedByteArray" />
- <argument index="2" name="size_bytes" type="int" />
+ <param index="0" name="draw_list" type="int" />
+ <param index="1" name="buffer" type="PackedByteArray" />
+ <param index="2" name="size_bytes" type="int" />
<description>
</description>
</method>
@@ -242,72 +250,78 @@
</method>
<method name="draw_list_switch_to_next_pass_split">
<return type="PackedInt64Array" />
- <argument index="0" name="splits" type="int" />
+ <param index="0" name="splits" type="int" />
<description>
</description>
</method>
<method name="framebuffer_create">
<return type="RID" />
- <argument index="0" name="textures" type="RID[]" />
- <argument index="1" name="validate_with_format" type="int" default="-1" />
- <argument index="2" name="view_count" type="int" default="1" />
+ <param index="0" name="textures" type="RID[]" />
+ <param index="1" name="validate_with_format" type="int" default="-1" />
+ <param index="2" name="view_count" type="int" default="1" />
<description>
</description>
</method>
<method name="framebuffer_create_empty">
<return type="RID" />
- <argument index="0" name="size" type="Vector2i" />
- <argument index="1" name="samples" type="int" enum="RenderingDevice.TextureSamples" default="0" />
- <argument index="2" name="validate_with_format" type="int" default="-1" />
+ <param index="0" name="size" type="Vector2i" />
+ <param index="1" name="samples" type="int" enum="RenderingDevice.TextureSamples" default="0" />
+ <param index="2" name="validate_with_format" type="int" default="-1" />
<description>
</description>
</method>
<method name="framebuffer_create_multipass">
<return type="RID" />
- <argument index="0" name="textures" type="RID[]" />
- <argument index="1" name="passes" type="RDFramebufferPass[]" />
- <argument index="2" name="validate_with_format" type="int" default="-1" />
- <argument index="3" name="view_count" type="int" default="1" />
+ <param index="0" name="textures" type="RID[]" />
+ <param index="1" name="passes" type="RDFramebufferPass[]" />
+ <param index="2" name="validate_with_format" type="int" default="-1" />
+ <param index="3" name="view_count" type="int" default="1" />
<description>
</description>
</method>
<method name="framebuffer_format_create">
<return type="int" />
- <argument index="0" name="attachments" type="RDAttachmentFormat[]" />
- <argument index="1" name="view_count" type="int" default="1" />
+ <param index="0" name="attachments" type="RDAttachmentFormat[]" />
+ <param index="1" name="view_count" type="int" default="1" />
<description>
</description>
</method>
<method name="framebuffer_format_create_empty">
<return type="int" />
- <argument index="0" name="samples" type="int" enum="RenderingDevice.TextureSamples" default="0" />
+ <param index="0" name="samples" type="int" enum="RenderingDevice.TextureSamples" default="0" />
<description>
</description>
</method>
<method name="framebuffer_format_create_multipass">
<return type="int" />
- <argument index="0" name="attachments" type="RDAttachmentFormat[]" />
- <argument index="1" name="passes" type="RDFramebufferPass[]" />
- <argument index="2" name="view_count" type="int" default="1" />
+ <param index="0" name="attachments" type="RDAttachmentFormat[]" />
+ <param index="1" name="passes" type="RDFramebufferPass[]" />
+ <param index="2" name="view_count" type="int" default="1" />
<description>
</description>
</method>
<method name="framebuffer_format_get_texture_samples">
<return type="int" enum="RenderingDevice.TextureSamples" />
- <argument index="0" name="format" type="int" />
- <argument index="1" name="render_pass" type="int" default="0" />
+ <param index="0" name="format" type="int" />
+ <param index="1" name="render_pass" type="int" default="0" />
<description>
</description>
</method>
<method name="framebuffer_get_format">
<return type="int" />
- <argument index="0" name="framebuffer" type="RID" />
+ <param index="0" name="framebuffer" type="RID" />
+ <description>
+ </description>
+ </method>
+ <method name="framebuffer_is_valid" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="framebuffer" type="RID" />
<description>
</description>
</method>
<method name="free_rid">
<return type="void" />
- <argument index="0" name="rid" type="RID" />
+ <param index="0" name="rid" type="RID" />
<description>
</description>
</method>
@@ -318,19 +332,19 @@
</method>
<method name="get_captured_timestamp_cpu_time" qualifiers="const">
<return type="int" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
</description>
</method>
<method name="get_captured_timestamp_gpu_time" qualifiers="const">
<return type="int" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
</description>
</method>
<method name="get_captured_timestamp_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
</description>
</method>
@@ -361,9 +375,9 @@
</method>
<method name="get_driver_resource">
<return type="int" />
- <argument index="0" name="resource" type="int" enum="RenderingDevice.DriverResource" />
- <argument index="1" name="rid" type="RID" />
- <argument index="2" name="index" type="int" />
+ <param index="0" name="resource" type="int" enum="RenderingDevice.DriverResource" />
+ <param index="1" name="rid" type="RID" />
+ <param index="2" name="index" type="int" />
<description>
</description>
</method>
@@ -374,58 +388,58 @@
</method>
<method name="get_memory_usage" qualifiers="const">
<return type="int" />
- <argument index="0" name="type" type="int" enum="RenderingDevice.MemoryType" />
+ <param index="0" name="type" type="int" enum="RenderingDevice.MemoryType" />
<description>
</description>
</method>
<method name="index_array_create">
<return type="RID" />
- <argument index="0" name="index_buffer" type="RID" />
- <argument index="1" name="index_offset" type="int" />
- <argument index="2" name="index_count" type="int" />
+ <param index="0" name="index_buffer" type="RID" />
+ <param index="1" name="index_offset" type="int" />
+ <param index="2" name="index_count" type="int" />
<description>
</description>
</method>
<method name="index_buffer_create">
<return type="RID" />
- <argument index="0" name="size_indices" type="int" />
- <argument index="1" name="format" type="int" enum="RenderingDevice.IndexBufferFormat" />
- <argument index="2" name="data" type="PackedByteArray" default="PackedByteArray()" />
- <argument index="3" name="use_restart_indices" type="bool" default="false" />
+ <param index="0" name="size_indices" type="int" />
+ <param index="1" name="format" type="int" enum="RenderingDevice.IndexBufferFormat" />
+ <param index="2" name="data" type="PackedByteArray" default="PackedByteArray()" />
+ <param index="3" name="use_restart_indices" type="bool" default="false" />
<description>
</description>
</method>
<method name="limit_get" qualifiers="const">
<return type="int" />
- <argument index="0" name="limit" type="int" enum="RenderingDevice.Limit" />
+ <param index="0" name="limit" type="int" enum="RenderingDevice.Limit" />
<description>
</description>
</method>
<method name="render_pipeline_create">
<return type="RID" />
- <argument index="0" name="shader" type="RID" />
- <argument index="1" name="framebuffer_format" type="int" />
- <argument index="2" name="vertex_format" type="int" />
- <argument index="3" name="primitive" type="int" enum="RenderingDevice.RenderPrimitive" />
- <argument index="4" name="rasterization_state" type="RDPipelineRasterizationState" />
- <argument index="5" name="multisample_state" type="RDPipelineMultisampleState" />
- <argument index="6" name="stencil_state" type="RDPipelineDepthStencilState" />
- <argument index="7" name="color_blend_state" type="RDPipelineColorBlendState" />
- <argument index="8" name="dynamic_state_flags" type="int" default="0" />
- <argument index="9" name="for_render_pass" type="int" default="0" />
- <argument index="10" name="specialization_constants" type="RDPipelineSpecializationConstant[]" default="[]" />
+ <param index="0" name="shader" type="RID" />
+ <param index="1" name="framebuffer_format" type="int" />
+ <param index="2" name="vertex_format" type="int" />
+ <param index="3" name="primitive" type="int" enum="RenderingDevice.RenderPrimitive" />
+ <param index="4" name="rasterization_state" type="RDPipelineRasterizationState" />
+ <param index="5" name="multisample_state" type="RDPipelineMultisampleState" />
+ <param index="6" name="stencil_state" type="RDPipelineDepthStencilState" />
+ <param index="7" name="color_blend_state" type="RDPipelineColorBlendState" />
+ <param index="8" name="dynamic_state_flags" type="int" default="0" />
+ <param index="9" name="for_render_pass" type="int" default="0" />
+ <param index="10" name="specialization_constants" type="RDPipelineSpecializationConstant[]" default="[]" />
<description>
</description>
</method>
<method name="render_pipeline_is_valid">
<return type="bool" />
- <argument index="0" name="render_pipeline" type="RID" />
+ <param index="0" name="render_pipeline" type="RID" />
<description>
</description>
</method>
<method name="sampler_create">
<return type="RID" />
- <argument index="0" name="state" type="RDSamplerState" />
+ <param index="0" name="state" type="RDSamplerState" />
<description>
</description>
</method>
@@ -436,61 +450,61 @@
</method>
<method name="screen_get_height" qualifiers="const">
<return type="int" />
- <argument index="0" name="screen" type="int" default="0" />
+ <param index="0" name="screen" type="int" default="0" />
<description>
</description>
</method>
<method name="screen_get_width" qualifiers="const">
<return type="int" />
- <argument index="0" name="screen" type="int" default="0" />
+ <param index="0" name="screen" type="int" default="0" />
<description>
</description>
</method>
<method name="set_resource_name">
<return type="void" />
- <argument index="0" name="id" type="RID" />
- <argument index="1" name="name" type="String" />
+ <param index="0" name="id" type="RID" />
+ <param index="1" name="name" type="String" />
<description>
</description>
</method>
<method name="shader_compile_binary_from_spirv">
<return type="PackedByteArray" />
- <argument index="0" name="spirv_data" type="RDShaderSPIRV" />
- <argument index="1" name="name" type="String" default="&quot;&quot;" />
+ <param index="0" name="spirv_data" type="RDShaderSPIRV" />
+ <param index="1" name="name" type="String" default="&quot;&quot;" />
<description>
</description>
</method>
<method name="shader_compile_spirv_from_source">
<return type="RDShaderSPIRV" />
- <argument index="0" name="shader_source" type="RDShaderSource" />
- <argument index="1" name="allow_cache" type="bool" default="true" />
+ <param index="0" name="shader_source" type="RDShaderSource" />
+ <param index="1" name="allow_cache" type="bool" default="true" />
<description>
</description>
</method>
<method name="shader_create_from_bytecode">
<return type="RID" />
- <argument index="0" name="binary_data" type="PackedByteArray" />
+ <param index="0" name="binary_data" type="PackedByteArray" />
<description>
</description>
</method>
<method name="shader_create_from_spirv">
<return type="RID" />
- <argument index="0" name="spirv_data" type="RDShaderSPIRV" />
- <argument index="1" name="name" type="String" default="&quot;&quot;" />
+ <param index="0" name="spirv_data" type="RDShaderSPIRV" />
+ <param index="1" name="name" type="String" default="&quot;&quot;" />
<description>
</description>
</method>
<method name="shader_get_vertex_input_attribute_mask">
<return type="int" />
- <argument index="0" name="shader" type="RID" />
+ <param index="0" name="shader" type="RID" />
<description>
</description>
</method>
<method name="storage_buffer_create">
<return type="RID" />
- <argument index="0" name="size_bytes" type="int" />
- <argument index="1" name="data" type="PackedByteArray" default="PackedByteArray()" />
- <argument index="2" name="usage" type="int" default="0" />
+ <param index="0" name="size_bytes" type="int" />
+ <param index="1" name="data" type="PackedByteArray" default="PackedByteArray()" />
+ <param index="2" name="usage" type="int" default="0" />
<description>
</description>
</method>
@@ -506,140 +520,140 @@
</method>
<method name="texture_buffer_create">
<return type="RID" />
- <argument index="0" name="size_bytes" type="int" />
- <argument index="1" name="format" type="int" enum="RenderingDevice.DataFormat" />
- <argument index="2" name="data" type="PackedByteArray" default="PackedByteArray()" />
+ <param index="0" name="size_bytes" type="int" />
+ <param index="1" name="format" type="int" enum="RenderingDevice.DataFormat" />
+ <param index="2" name="data" type="PackedByteArray" default="PackedByteArray()" />
<description>
</description>
</method>
<method name="texture_clear">
<return type="int" enum="Error" />
- <argument index="0" name="texture" type="RID" />
- <argument index="1" name="color" type="Color" />
- <argument index="2" name="base_mipmap" type="int" />
- <argument index="3" name="mipmap_count" type="int" />
- <argument index="4" name="base_layer" type="int" />
- <argument index="5" name="layer_count" type="int" />
- <argument index="6" name="post_barrier" type="int" default="7" />
+ <param index="0" name="texture" type="RID" />
+ <param index="1" name="color" type="Color" />
+ <param index="2" name="base_mipmap" type="int" />
+ <param index="3" name="mipmap_count" type="int" />
+ <param index="4" name="base_layer" type="int" />
+ <param index="5" name="layer_count" type="int" />
+ <param index="6" name="post_barrier" type="int" default="7" />
<description>
</description>
</method>
<method name="texture_copy">
<return type="int" enum="Error" />
- <argument index="0" name="from_texture" type="RID" />
- <argument index="1" name="to_texture" type="RID" />
- <argument index="2" name="from_pos" type="Vector3" />
- <argument index="3" name="to_pos" type="Vector3" />
- <argument index="4" name="size" type="Vector3" />
- <argument index="5" name="src_mipmap" type="int" />
- <argument index="6" name="dst_mipmap" type="int" />
- <argument index="7" name="src_layer" type="int" />
- <argument index="8" name="dst_layer" type="int" />
- <argument index="9" name="post_barrier" type="int" default="7" />
+ <param index="0" name="from_texture" type="RID" />
+ <param index="1" name="to_texture" type="RID" />
+ <param index="2" name="from_pos" type="Vector3" />
+ <param index="3" name="to_pos" type="Vector3" />
+ <param index="4" name="size" type="Vector3" />
+ <param index="5" name="src_mipmap" type="int" />
+ <param index="6" name="dst_mipmap" type="int" />
+ <param index="7" name="src_layer" type="int" />
+ <param index="8" name="dst_layer" type="int" />
+ <param index="9" name="post_barrier" type="int" default="7" />
<description>
</description>
</method>
<method name="texture_create">
<return type="RID" />
- <argument index="0" name="format" type="RDTextureFormat" />
- <argument index="1" name="view" type="RDTextureView" />
- <argument index="2" name="data" type="PackedByteArray[]" default="[]" />
+ <param index="0" name="format" type="RDTextureFormat" />
+ <param index="1" name="view" type="RDTextureView" />
+ <param index="2" name="data" type="PackedByteArray[]" default="[]" />
<description>
</description>
</method>
<method name="texture_create_shared">
<return type="RID" />
- <argument index="0" name="view" type="RDTextureView" />
- <argument index="1" name="with_texture" type="RID" />
+ <param index="0" name="view" type="RDTextureView" />
+ <param index="1" name="with_texture" type="RID" />
<description>
</description>
</method>
<method name="texture_create_shared_from_slice">
<return type="RID" />
- <argument index="0" name="view" type="RDTextureView" />
- <argument index="1" name="with_texture" type="RID" />
- <argument index="2" name="layer" type="int" />
- <argument index="3" name="mipmap" type="int" />
- <argument index="4" name="mipmaps" type="int" default="1" />
- <argument index="5" name="slice_type" type="int" enum="RenderingDevice.TextureSliceType" default="0" />
+ <param index="0" name="view" type="RDTextureView" />
+ <param index="1" name="with_texture" type="RID" />
+ <param index="2" name="layer" type="int" />
+ <param index="3" name="mipmap" type="int" />
+ <param index="4" name="mipmaps" type="int" default="1" />
+ <param index="5" name="slice_type" type="int" enum="RenderingDevice.TextureSliceType" default="0" />
<description>
</description>
</method>
<method name="texture_get_data">
<return type="PackedByteArray" />
- <argument index="0" name="texture" type="RID" />
- <argument index="1" name="layer" type="int" />
+ <param index="0" name="texture" type="RID" />
+ <param index="1" name="layer" type="int" />
<description>
</description>
</method>
<method name="texture_is_format_supported_for_usage" qualifiers="const">
<return type="bool" />
- <argument index="0" name="format" type="int" enum="RenderingDevice.DataFormat" />
- <argument index="1" name="usage_flags" type="int" />
+ <param index="0" name="format" type="int" enum="RenderingDevice.DataFormat" />
+ <param index="1" name="usage_flags" type="int" />
<description>
</description>
</method>
<method name="texture_is_shared">
<return type="bool" />
- <argument index="0" name="texture" type="RID" />
+ <param index="0" name="texture" type="RID" />
<description>
</description>
</method>
<method name="texture_is_valid">
<return type="bool" />
- <argument index="0" name="texture" type="RID" />
+ <param index="0" name="texture" type="RID" />
<description>
</description>
</method>
<method name="texture_resolve_multisample">
<return type="int" enum="Error" />
- <argument index="0" name="from_texture" type="RID" />
- <argument index="1" name="to_texture" type="RID" />
- <argument index="2" name="post_barrier" type="int" default="7" />
+ <param index="0" name="from_texture" type="RID" />
+ <param index="1" name="to_texture" type="RID" />
+ <param index="2" name="post_barrier" type="int" default="7" />
<description>
</description>
</method>
<method name="texture_update">
<return type="int" enum="Error" />
- <argument index="0" name="texture" type="RID" />
- <argument index="1" name="layer" type="int" />
- <argument index="2" name="data" type="PackedByteArray" />
- <argument index="3" name="post_barrier" type="int" default="7" />
+ <param index="0" name="texture" type="RID" />
+ <param index="1" name="layer" type="int" />
+ <param index="2" name="data" type="PackedByteArray" />
+ <param index="3" name="post_barrier" type="int" default="7" />
<description>
</description>
</method>
<method name="uniform_buffer_create">
<return type="RID" />
- <argument index="0" name="size_bytes" type="int" />
- <argument index="1" name="data" type="PackedByteArray" default="PackedByteArray()" />
+ <param index="0" name="size_bytes" type="int" />
+ <param index="1" name="data" type="PackedByteArray" default="PackedByteArray()" />
<description>
</description>
</method>
<method name="uniform_set_create">
<return type="RID" />
- <argument index="0" name="uniforms" type="Array" />
- <argument index="1" name="shader" type="RID" />
- <argument index="2" name="shader_set" type="int" />
+ <param index="0" name="uniforms" type="Array" />
+ <param index="1" name="shader" type="RID" />
+ <param index="2" name="shader_set" type="int" />
<description>
</description>
</method>
<method name="uniform_set_is_valid">
<return type="bool" />
- <argument index="0" name="uniform_set" type="RID" />
+ <param index="0" name="uniform_set" type="RID" />
<description>
</description>
</method>
<method name="vertex_buffer_create">
<return type="RID" />
- <argument index="0" name="size_bytes" type="int" />
- <argument index="1" name="data" type="PackedByteArray" default="PackedByteArray()" />
- <argument index="2" name="use_as_storage" type="bool" default="false" />
+ <param index="0" name="size_bytes" type="int" />
+ <param index="1" name="data" type="PackedByteArray" default="PackedByteArray()" />
+ <param index="2" name="use_as_storage" type="bool" default="false" />
<description>
</description>
</method>
<method name="vertex_format_create">
<return type="int" />
- <argument index="0" name="vertex_descriptions" type="RDVertexAttribute[]" />
+ <param index="0" name="vertex_descriptions" type="RDVertexAttribute[]" />
<description>
</description>
</method>
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 9616ab3515..639db6b3b5 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -20,9 +20,9 @@
<methods>
<method name="bake_render_uv2">
<return type="Image[]" />
- <argument index="0" name="base" type="RID" />
- <argument index="1" name="material_overrides" type="Array" />
- <argument index="2" name="image_size" type="Vector2i" />
+ <param index="0" name="base" type="RID" />
+ <param index="1" name="material_overrides" type="Array" />
+ <param index="2" name="image_size" type="Vector2i" />
<description>
</description>
</method>
@@ -40,104 +40,104 @@
</method>
<method name="camera_effects_set_custom_exposure">
<return type="void" />
- <argument index="0" name="camera_effects" type="RID" />
- <argument index="1" name="enable" type="bool" />
- <argument index="2" name="exposure" type="float" />
+ <param index="0" name="camera_effects" type="RID" />
+ <param index="1" name="enable" type="bool" />
+ <param index="2" name="exposure" type="float" />
<description>
</description>
</method>
<method name="camera_effects_set_dof_blur">
<return type="void" />
- <argument index="0" name="camera_effects" type="RID" />
- <argument index="1" name="far_enable" type="bool" />
- <argument index="2" name="far_distance" type="float" />
- <argument index="3" name="far_transition" type="float" />
- <argument index="4" name="near_enable" type="bool" />
- <argument index="5" name="near_distance" type="float" />
- <argument index="6" name="near_transition" type="float" />
- <argument index="7" name="amount" type="float" />
+ <param index="0" name="camera_effects" type="RID" />
+ <param index="1" name="far_enable" type="bool" />
+ <param index="2" name="far_distance" type="float" />
+ <param index="3" name="far_transition" type="float" />
+ <param index="4" name="near_enable" type="bool" />
+ <param index="5" name="near_distance" type="float" />
+ <param index="6" name="near_transition" type="float" />
+ <param index="7" name="amount" type="float" />
<description>
</description>
</method>
<method name="camera_effects_set_dof_blur_bokeh_shape">
<return type="void" />
- <argument index="0" name="shape" type="int" enum="RenderingServer.DOFBokehShape" />
+ <param index="0" name="shape" type="int" enum="RenderingServer.DOFBokehShape" />
<description>
</description>
</method>
<method name="camera_effects_set_dof_blur_quality">
<return type="void" />
- <argument index="0" name="quality" type="int" enum="RenderingServer.DOFBlurQuality" />
- <argument index="1" name="use_jitter" type="bool" />
+ <param index="0" name="quality" type="int" enum="RenderingServer.DOFBlurQuality" />
+ <param index="1" name="use_jitter" type="bool" />
<description>
</description>
</method>
<method name="camera_set_camera_effects">
<return type="void" />
- <argument index="0" name="camera" type="RID" />
- <argument index="1" name="effects" type="RID" />
+ <param index="0" name="camera" type="RID" />
+ <param index="1" name="effects" type="RID" />
<description>
</description>
</method>
<method name="camera_set_cull_mask">
<return type="void" />
- <argument index="0" name="camera" type="RID" />
- <argument index="1" name="layers" type="int" />
+ <param index="0" name="camera" type="RID" />
+ <param index="1" name="layers" type="int" />
<description>
Sets the cull mask associated with this camera. The cull mask describes which 3D layers are rendered by this camera. Equivalent to [member Camera3D.cull_mask].
</description>
</method>
<method name="camera_set_environment">
<return type="void" />
- <argument index="0" name="camera" type="RID" />
- <argument index="1" name="env" type="RID" />
+ <param index="0" name="camera" type="RID" />
+ <param index="1" name="env" type="RID" />
<description>
Sets the environment used by this camera. Equivalent to [member Camera3D.environment].
</description>
</method>
<method name="camera_set_frustum">
<return type="void" />
- <argument index="0" name="camera" type="RID" />
- <argument index="1" name="size" type="float" />
- <argument index="2" name="offset" type="Vector2" />
- <argument index="3" name="z_near" type="float" />
- <argument index="4" name="z_far" type="float" />
+ <param index="0" name="camera" type="RID" />
+ <param index="1" name="size" type="float" />
+ <param index="2" name="offset" type="Vector2" />
+ <param index="3" name="z_near" type="float" />
+ <param index="4" name="z_far" type="float" />
<description>
- Sets camera to use frustum projection. This mode allows adjusting the [code]offset[/code] argument to create "tilted frustum" effects.
+ Sets camera to use frustum projection. This mode allows adjusting the [param offset] argument to create "tilted frustum" effects.
</description>
</method>
<method name="camera_set_orthogonal">
<return type="void" />
- <argument index="0" name="camera" type="RID" />
- <argument index="1" name="size" type="float" />
- <argument index="2" name="z_near" type="float" />
- <argument index="3" name="z_far" type="float" />
+ <param index="0" name="camera" type="RID" />
+ <param index="1" name="size" type="float" />
+ <param index="2" name="z_near" type="float" />
+ <param index="3" name="z_far" type="float" />
<description>
Sets camera to use orthogonal projection, also known as orthographic projection. Objects remain the same size on the screen no matter how far away they are.
</description>
</method>
<method name="camera_set_perspective">
<return type="void" />
- <argument index="0" name="camera" type="RID" />
- <argument index="1" name="fovy_degrees" type="float" />
- <argument index="2" name="z_near" type="float" />
- <argument index="3" name="z_far" type="float" />
+ <param index="0" name="camera" type="RID" />
+ <param index="1" name="fovy_degrees" type="float" />
+ <param index="2" name="z_near" type="float" />
+ <param index="3" name="z_far" type="float" />
<description>
Sets camera to use perspective projection. Objects on the screen becomes smaller when they are far away.
</description>
</method>
<method name="camera_set_transform">
<return type="void" />
- <argument index="0" name="camera" type="RID" />
- <argument index="1" name="transform" type="Transform3D" />
+ <param index="0" name="camera" type="RID" />
+ <param index="1" name="transform" type="Transform3D" />
<description>
Sets [Transform3D] of camera.
</description>
</method>
<method name="camera_set_use_vertical_aspect">
<return type="void" />
- <argument index="0" name="camera" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="camera" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
If [code]true[/code], preserves the horizontal aspect ratio which is equivalent to [constant Camera3D.KEEP_WIDTH]. If [code]false[/code], preserves the vertical aspect ratio which is equivalent to [constant Camera3D.KEEP_HEIGHT].
</description>
@@ -151,181 +151,191 @@
</method>
<method name="canvas_item_add_animation_slice">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="animation_length" type="float" />
- <argument index="2" name="slice_begin" type="float" />
- <argument index="3" name="slice_end" type="float" />
- <argument index="4" name="offset" type="float" default="0.0" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="animation_length" type="float" />
+ <param index="2" name="slice_begin" type="float" />
+ <param index="3" name="slice_end" type="float" />
+ <param index="4" name="offset" type="float" default="0.0" />
<description>
Subsequent drawing commands will be ignored unless they fall within the specified animation slice. This is a faster way to implement animations that loop on background rather than redrawing constantly.
</description>
</method>
<method name="canvas_item_add_circle">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="radius" type="float" />
- <argument index="3" name="color" type="Color" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="radius" type="float" />
+ <param index="3" name="color" type="Color" />
<description>
</description>
</method>
<method name="canvas_item_add_clip_ignore">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="ignore" type="bool" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="ignore" type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="canvas_item_add_lcd_texture_rect_region">
+ <return type="void" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="rect" type="Rect2" />
+ <param index="2" name="texture" type="RID" />
+ <param index="3" name="src_rect" type="Rect2" />
+ <param index="4" name="modulate" type="Color" />
<description>
</description>
</method>
<method name="canvas_item_add_line">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="from" type="Vector2" />
- <argument index="2" name="to" type="Vector2" />
- <argument index="3" name="color" type="Color" />
- <argument index="4" name="width" type="float" default="1.0" />
- <argument index="5" name="antialiased" type="bool" default="false" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="from" type="Vector2" />
+ <param index="2" name="to" type="Vector2" />
+ <param index="3" name="color" type="Color" />
+ <param index="4" name="width" type="float" default="1.0" />
+ <param index="5" name="antialiased" type="bool" default="false" />
<description>
</description>
</method>
<method name="canvas_item_add_mesh">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="mesh" type="RID" />
- <argument index="2" name="transform" type="Transform2D" default="Transform2D(1, 0, 0, 1, 0, 0)" />
- <argument index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="4" name="texture" type="RID" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="mesh" type="RID" />
+ <param index="2" name="transform" type="Transform2D" default="Transform2D(1, 0, 0, 1, 0, 0)" />
+ <param index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="4" name="texture" type="RID" />
<description>
</description>
</method>
<method name="canvas_item_add_msdf_texture_rect_region">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="rect" type="Rect2" />
- <argument index="2" name="texture" type="RID" />
- <argument index="3" name="src_rect" type="Rect2" />
- <argument index="4" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="5" name="outline_size" type="int" default="0" />
- <argument index="6" name="px_range" type="float" default="1.0" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="rect" type="Rect2" />
+ <param index="2" name="texture" type="RID" />
+ <param index="3" name="src_rect" type="Rect2" />
+ <param index="4" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="5" name="outline_size" type="int" default="0" />
+ <param index="6" name="px_range" type="float" default="1.0" />
<description>
</description>
</method>
<method name="canvas_item_add_multimesh">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="mesh" type="RID" />
- <argument index="2" name="texture" type="RID" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="mesh" type="RID" />
+ <param index="2" name="texture" type="RID" />
<description>
</description>
</method>
<method name="canvas_item_add_nine_patch">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="rect" type="Rect2" />
- <argument index="2" name="source" type="Rect2" />
- <argument index="3" name="texture" type="RID" />
- <argument index="4" name="topleft" type="Vector2" />
- <argument index="5" name="bottomright" type="Vector2" />
- <argument index="6" name="x_axis_mode" type="int" enum="RenderingServer.NinePatchAxisMode" default="0" />
- <argument index="7" name="y_axis_mode" type="int" enum="RenderingServer.NinePatchAxisMode" default="0" />
- <argument index="8" name="draw_center" type="bool" default="true" />
- <argument index="9" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="rect" type="Rect2" />
+ <param index="2" name="source" type="Rect2" />
+ <param index="3" name="texture" type="RID" />
+ <param index="4" name="topleft" type="Vector2" />
+ <param index="5" name="bottomright" type="Vector2" />
+ <param index="6" name="x_axis_mode" type="int" enum="RenderingServer.NinePatchAxisMode" default="0" />
+ <param index="7" name="y_axis_mode" type="int" enum="RenderingServer.NinePatchAxisMode" default="0" />
+ <param index="8" name="draw_center" type="bool" default="true" />
+ <param index="9" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
<description>
</description>
</method>
<method name="canvas_item_add_particles">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="particles" type="RID" />
- <argument index="2" name="texture" type="RID" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="particles" type="RID" />
+ <param index="2" name="texture" type="RID" />
<description>
</description>
</method>
<method name="canvas_item_add_polygon">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="points" type="PackedVector2Array" />
- <argument index="2" name="colors" type="PackedColorArray" />
- <argument index="3" name="uvs" type="PackedVector2Array" default="PackedVector2Array()" />
- <argument index="4" name="texture" type="RID" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="points" type="PackedVector2Array" />
+ <param index="2" name="colors" type="PackedColorArray" />
+ <param index="3" name="uvs" type="PackedVector2Array" default="PackedVector2Array()" />
+ <param index="4" name="texture" type="RID" />
<description>
</description>
</method>
<method name="canvas_item_add_polyline">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="points" type="PackedVector2Array" />
- <argument index="2" name="colors" type="PackedColorArray" />
- <argument index="3" name="width" type="float" default="1.0" />
- <argument index="4" name="antialiased" type="bool" default="false" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="points" type="PackedVector2Array" />
+ <param index="2" name="colors" type="PackedColorArray" />
+ <param index="3" name="width" type="float" default="1.0" />
+ <param index="4" name="antialiased" type="bool" default="false" />
<description>
</description>
</method>
<method name="canvas_item_add_primitive">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="points" type="PackedVector2Array" />
- <argument index="2" name="colors" type="PackedColorArray" />
- <argument index="3" name="uvs" type="PackedVector2Array" />
- <argument index="4" name="texture" type="RID" />
- <argument index="5" name="width" type="float" default="1.0" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="points" type="PackedVector2Array" />
+ <param index="2" name="colors" type="PackedColorArray" />
+ <param index="3" name="uvs" type="PackedVector2Array" />
+ <param index="4" name="texture" type="RID" />
+ <param index="5" name="width" type="float" default="1.0" />
<description>
</description>
</method>
<method name="canvas_item_add_rect">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="rect" type="Rect2" />
- <argument index="2" name="color" type="Color" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="rect" type="Rect2" />
+ <param index="2" name="color" type="Color" />
<description>
</description>
</method>
<method name="canvas_item_add_set_transform">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="transform" type="Transform2D" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="transform" type="Transform2D" />
<description>
</description>
</method>
<method name="canvas_item_add_texture_rect">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="rect" type="Rect2" />
- <argument index="2" name="texture" type="RID" />
- <argument index="3" name="tile" type="bool" default="false" />
- <argument index="4" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="5" name="transpose" type="bool" default="false" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="rect" type="Rect2" />
+ <param index="2" name="texture" type="RID" />
+ <param index="3" name="tile" type="bool" default="false" />
+ <param index="4" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="5" name="transpose" type="bool" default="false" />
<description>
</description>
</method>
<method name="canvas_item_add_texture_rect_region">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="rect" type="Rect2" />
- <argument index="2" name="texture" type="RID" />
- <argument index="3" name="src_rect" type="Rect2" />
- <argument index="4" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="5" name="transpose" type="bool" default="false" />
- <argument index="6" name="clip_uv" type="bool" default="true" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="rect" type="Rect2" />
+ <param index="2" name="texture" type="RID" />
+ <param index="3" name="src_rect" type="Rect2" />
+ <param index="4" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="5" name="transpose" type="bool" default="false" />
+ <param index="6" name="clip_uv" type="bool" default="true" />
<description>
</description>
</method>
<method name="canvas_item_add_triangle_array">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="indices" type="PackedInt32Array" />
- <argument index="2" name="points" type="PackedVector2Array" />
- <argument index="3" name="colors" type="PackedColorArray" />
- <argument index="4" name="uvs" type="PackedVector2Array" default="PackedVector2Array()" />
- <argument index="5" name="bones" type="PackedInt32Array" default="PackedInt32Array()" />
- <argument index="6" name="weights" type="PackedFloat32Array" default="PackedFloat32Array()" />
- <argument index="7" name="texture" type="RID" />
- <argument index="8" name="count" type="int" default="-1" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="indices" type="PackedInt32Array" />
+ <param index="2" name="points" type="PackedVector2Array" />
+ <param index="3" name="colors" type="PackedColorArray" />
+ <param index="4" name="uvs" type="PackedVector2Array" default="PackedVector2Array()" />
+ <param index="5" name="bones" type="PackedInt32Array" default="PackedInt32Array()" />
+ <param index="6" name="weights" type="PackedFloat32Array" default="PackedFloat32Array()" />
+ <param index="7" name="texture" type="RID" />
+ <param index="8" name="count" type="int" default="-1" />
<description>
</description>
</method>
<method name="canvas_item_clear">
<return type="void" />
- <argument index="0" name="item" type="RID" />
+ <param index="0" name="item" type="RID" />
<description>
Clears the [CanvasItem] and removes all commands in it.
</description>
@@ -337,170 +347,170 @@
</method>
<method name="canvas_item_set_canvas_group_mode">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="mode" type="int" enum="RenderingServer.CanvasGroupMode" />
- <argument index="2" name="clear_margin" type="float" default="5.0" />
- <argument index="3" name="fit_empty" type="bool" default="false" />
- <argument index="4" name="fit_margin" type="float" default="0.0" />
- <argument index="5" name="blur_mipmaps" type="bool" default="false" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="mode" type="int" enum="RenderingServer.CanvasGroupMode" />
+ <param index="2" name="clear_margin" type="float" default="5.0" />
+ <param index="3" name="fit_empty" type="bool" default="false" />
+ <param index="4" name="fit_margin" type="float" default="0.0" />
+ <param index="5" name="blur_mipmaps" type="bool" default="false" />
<description>
</description>
</method>
<method name="canvas_item_set_clip">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="clip" type="bool" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="clip" type="bool" />
<description>
</description>
</method>
<method name="canvas_item_set_copy_to_backbuffer">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="enabled" type="bool" />
- <argument index="2" name="rect" type="Rect2" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="enabled" type="bool" />
+ <param index="2" name="rect" type="Rect2" />
<description>
Sets the [CanvasItem] to copy a rect to the backbuffer.
</description>
</method>
<method name="canvas_item_set_custom_rect">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="use_custom_rect" type="bool" />
- <argument index="2" name="rect" type="Rect2" default="Rect2(0, 0, 0, 0)" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="use_custom_rect" type="bool" />
+ <param index="2" name="rect" type="Rect2" default="Rect2(0, 0, 0, 0)" />
<description>
</description>
</method>
<method name="canvas_item_set_default_texture_filter">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="filter" type="int" enum="RenderingServer.CanvasItemTextureFilter" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="filter" type="int" enum="RenderingServer.CanvasItemTextureFilter" />
<description>
</description>
</method>
<method name="canvas_item_set_default_texture_repeat">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="repeat" type="int" enum="RenderingServer.CanvasItemTextureRepeat" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="repeat" type="int" enum="RenderingServer.CanvasItemTextureRepeat" />
<description>
</description>
</method>
<method name="canvas_item_set_distance_field_mode">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="enabled" type="bool" />
<description>
</description>
</method>
<method name="canvas_item_set_draw_behind_parent">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="enabled" type="bool" />
<description>
</description>
</method>
<method name="canvas_item_set_draw_index">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="index" type="int" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="index" type="int" />
<description>
Sets the index for the [CanvasItem].
</description>
</method>
<method name="canvas_item_set_light_mask">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="mask" type="int" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="mask" type="int" />
<description>
</description>
</method>
<method name="canvas_item_set_material">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="material" type="RID" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="material" type="RID" />
<description>
Sets a new material to the [CanvasItem].
</description>
</method>
<method name="canvas_item_set_modulate">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="color" type="Color" />
<description>
</description>
</method>
<method name="canvas_item_set_parent">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="parent" type="RID" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="parent" type="RID" />
<description>
</description>
</method>
<method name="canvas_item_set_self_modulate">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="color" type="Color" />
<description>
</description>
</method>
<method name="canvas_item_set_sort_children_by_y">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="enabled" type="bool" />
<description>
</description>
</method>
<method name="canvas_item_set_transform">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="transform" type="Transform2D" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="transform" type="Transform2D" />
<description>
</description>
</method>
<method name="canvas_item_set_use_parent_material">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="enabled" type="bool" />
<description>
Sets if the [CanvasItem] uses its parent's material.
</description>
</method>
<method name="canvas_item_set_visibility_notifier">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="enable" type="bool" />
- <argument index="2" name="area" type="Rect2" />
- <argument index="3" name="enter_callable" type="Callable" />
- <argument index="4" name="exit_callable" type="Callable" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="enable" type="bool" />
+ <param index="2" name="area" type="Rect2" />
+ <param index="3" name="enter_callable" type="Callable" />
+ <param index="4" name="exit_callable" type="Callable" />
<description>
</description>
</method>
<method name="canvas_item_set_visible">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="visible" type="bool" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="visible" type="bool" />
<description>
</description>
</method>
<method name="canvas_item_set_z_as_relative_to_parent">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="enabled" type="bool" />
<description>
If this is enabled, the Z index of the parent will be added to the children's Z index.
</description>
</method>
<method name="canvas_item_set_z_index">
<return type="void" />
- <argument index="0" name="item" type="RID" />
- <argument index="1" name="z_index" type="int" />
+ <param index="0" name="item" type="RID" />
+ <param index="1" name="z_index" type="int" />
<description>
Sets the [CanvasItem]'s Z index, i.e. its draw order (lower indexes are drawn first).
</description>
</method>
<method name="canvas_light_attach_to_canvas">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="canvas" type="RID" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="canvas" type="RID" />
<description>
Attaches the canvas light to the canvas. Removes it from its previous canvas.
</description>
@@ -514,8 +524,8 @@
</method>
<method name="canvas_light_occluder_attach_to_canvas">
<return type="void" />
- <argument index="0" name="occluder" type="RID" />
- <argument index="1" name="canvas" type="RID" />
+ <param index="0" name="occluder" type="RID" />
+ <param index="1" name="canvas" type="RID" />
<description>
Attaches a light occluder to the canvas. Removes it from its previous canvas.
</description>
@@ -529,177 +539,177 @@
</method>
<method name="canvas_light_occluder_set_as_sdf_collision">
<return type="void" />
- <argument index="0" name="occluder" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="occluder" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
</description>
</method>
<method name="canvas_light_occluder_set_enabled">
<return type="void" />
- <argument index="0" name="occluder" type="RID" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="occluder" type="RID" />
+ <param index="1" name="enabled" type="bool" />
<description>
Enables or disables light occluder.
</description>
</method>
<method name="canvas_light_occluder_set_light_mask">
<return type="void" />
- <argument index="0" name="occluder" type="RID" />
- <argument index="1" name="mask" type="int" />
+ <param index="0" name="occluder" type="RID" />
+ <param index="1" name="mask" type="int" />
<description>
The light mask. See [LightOccluder2D] for more information on light masks.
</description>
</method>
<method name="canvas_light_occluder_set_polygon">
<return type="void" />
- <argument index="0" name="occluder" type="RID" />
- <argument index="1" name="polygon" type="RID" />
+ <param index="0" name="occluder" type="RID" />
+ <param index="1" name="polygon" type="RID" />
<description>
Sets a light occluder's polygon.
</description>
</method>
<method name="canvas_light_occluder_set_transform">
<return type="void" />
- <argument index="0" name="occluder" type="RID" />
- <argument index="1" name="transform" type="Transform2D" />
+ <param index="0" name="occluder" type="RID" />
+ <param index="1" name="transform" type="Transform2D" />
<description>
Sets a light occluder's [Transform2D].
</description>
</method>
<method name="canvas_light_set_color">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="color" type="Color" />
<description>
Sets the color for a light.
</description>
</method>
<method name="canvas_light_set_enabled">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="enabled" type="bool" />
<description>
Enables or disables a canvas light.
</description>
</method>
<method name="canvas_light_set_energy">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="energy" type="float" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="energy" type="float" />
<description>
Sets a canvas light's energy.
</description>
</method>
<method name="canvas_light_set_height">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="height" type="float" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="height" type="float" />
<description>
Sets a canvas light's height.
</description>
</method>
<method name="canvas_light_set_item_cull_mask">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="mask" type="int" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="mask" type="int" />
<description>
The light mask. See [LightOccluder2D] for more information on light masks.
</description>
</method>
<method name="canvas_light_set_item_shadow_cull_mask">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="mask" type="int" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="mask" type="int" />
<description>
The binary mask used to determine which layers this canvas light's shadows affects. See [LightOccluder2D] for more information on light masks.
</description>
</method>
<method name="canvas_light_set_layer_range">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="min_layer" type="int" />
- <argument index="2" name="max_layer" type="int" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="min_layer" type="int" />
+ <param index="2" name="max_layer" type="int" />
<description>
The layer range that gets rendered with this light.
</description>
</method>
<method name="canvas_light_set_mode">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="mode" type="int" enum="RenderingServer.CanvasLightMode" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="mode" type="int" enum="RenderingServer.CanvasLightMode" />
<description>
The mode of the light, see [enum CanvasLightMode] constants.
</description>
</method>
<method name="canvas_light_set_shadow_color">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="color" type="Color" />
<description>
Sets the color of the canvas light's shadow.
</description>
</method>
<method name="canvas_light_set_shadow_enabled">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="enabled" type="bool" />
<description>
Enables or disables the canvas light's shadow.
</description>
</method>
<method name="canvas_light_set_shadow_filter">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="filter" type="int" enum="RenderingServer.CanvasLightShadowFilter" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="filter" type="int" enum="RenderingServer.CanvasLightShadowFilter" />
<description>
Sets the canvas light's shadow's filter, see [enum CanvasLightShadowFilter] constants.
</description>
</method>
<method name="canvas_light_set_shadow_smooth">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="smooth" type="float" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="smooth" type="float" />
<description>
Smoothens the shadow. The lower, the smoother.
</description>
</method>
<method name="canvas_light_set_texture">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="texture" type="RID" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="texture" type="RID" />
<description>
Sets the texture to be used by a [PointLight2D]. Equivalent to [member PointLight2D.texture].
</description>
</method>
<method name="canvas_light_set_texture_offset">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="offset" type="Vector2" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="offset" type="Vector2" />
<description>
Sets the offset of a [PointLight2D]'s texture. Equivalent to [member PointLight2D.offset].
</description>
</method>
<method name="canvas_light_set_texture_scale">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="scale" type="float" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="scale" type="float" />
<description>
Sets the scale factor of a [PointLight2D]'s texture. Equivalent to [member PointLight2D.texture_scale].
</description>
</method>
<method name="canvas_light_set_transform">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="transform" type="Transform2D" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="transform" type="Transform2D" />
<description>
Sets the canvas light's [Transform2D].
</description>
</method>
<method name="canvas_light_set_z_range">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="min_z" type="int" />
- <argument index="2" name="max_z" type="int" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="min_z" type="int" />
+ <param index="2" name="max_z" type="int" />
<description>
Sets the Z range of objects that will be affected by this light. Equivalent to [member Light2D.range_z_min] and [member Light2D.range_z_max].
</description>
@@ -713,47 +723,47 @@
</method>
<method name="canvas_occluder_polygon_set_cull_mode">
<return type="void" />
- <argument index="0" name="occluder_polygon" type="RID" />
- <argument index="1" name="mode" type="int" enum="RenderingServer.CanvasOccluderPolygonCullMode" />
+ <param index="0" name="occluder_polygon" type="RID" />
+ <param index="1" name="mode" type="int" enum="RenderingServer.CanvasOccluderPolygonCullMode" />
<description>
Sets an occluder polygons cull mode. See [enum CanvasOccluderPolygonCullMode] constants.
</description>
</method>
<method name="canvas_occluder_polygon_set_shape">
<return type="void" />
- <argument index="0" name="occluder_polygon" type="RID" />
- <argument index="1" name="shape" type="PackedVector2Array" />
- <argument index="2" name="closed" type="bool" />
+ <param index="0" name="occluder_polygon" type="RID" />
+ <param index="1" name="shape" type="PackedVector2Array" />
+ <param index="2" name="closed" type="bool" />
<description>
Sets the shape of the occluder polygon.
</description>
</method>
<method name="canvas_set_disable_scale">
<return type="void" />
- <argument index="0" name="disable" type="bool" />
+ <param index="0" name="disable" type="bool" />
<description>
</description>
</method>
<method name="canvas_set_item_mirroring">
<return type="void" />
- <argument index="0" name="canvas" type="RID" />
- <argument index="1" name="item" type="RID" />
- <argument index="2" name="mirroring" type="Vector2" />
+ <param index="0" name="canvas" type="RID" />
+ <param index="1" name="item" type="RID" />
+ <param index="2" name="mirroring" type="Vector2" />
<description>
A copy of the canvas item will be drawn with a local offset of the mirroring [Vector2].
</description>
</method>
<method name="canvas_set_modulate">
<return type="void" />
- <argument index="0" name="canvas" type="RID" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="canvas" type="RID" />
+ <param index="1" name="color" type="Color" />
<description>
Modulates all colors in the given canvas.
</description>
</method>
<method name="canvas_set_shadow_texture_size">
<return type="void" />
- <argument index="0" name="size" type="int" />
+ <param index="0" name="size" type="int" />
<description>
</description>
</method>
@@ -764,31 +774,31 @@
</method>
<method name="canvas_texture_set_channel">
<return type="void" />
- <argument index="0" name="canvas_texture" type="RID" />
- <argument index="1" name="channel" type="int" enum="RenderingServer.CanvasTextureChannel" />
- <argument index="2" name="texture" type="RID" />
+ <param index="0" name="canvas_texture" type="RID" />
+ <param index="1" name="channel" type="int" enum="RenderingServer.CanvasTextureChannel" />
+ <param index="2" name="texture" type="RID" />
<description>
</description>
</method>
<method name="canvas_texture_set_shading_parameters">
<return type="void" />
- <argument index="0" name="canvas_texture" type="RID" />
- <argument index="1" name="base_color" type="Color" />
- <argument index="2" name="shininess" type="float" />
+ <param index="0" name="canvas_texture" type="RID" />
+ <param index="1" name="base_color" type="Color" />
+ <param index="2" name="shininess" type="float" />
<description>
</description>
</method>
<method name="canvas_texture_set_texture_filter">
<return type="void" />
- <argument index="0" name="canvas_texture" type="RID" />
- <argument index="1" name="filter" type="int" enum="RenderingServer.CanvasItemTextureFilter" />
+ <param index="0" name="canvas_texture" type="RID" />
+ <param index="1" name="filter" type="int" enum="RenderingServer.CanvasItemTextureFilter" />
<description>
</description>
</method>
<method name="canvas_texture_set_texture_repeat">
<return type="void" />
- <argument index="0" name="canvas_texture" type="RID" />
- <argument index="1" name="repeat" type="int" enum="RenderingServer.CanvasItemTextureRepeat" />
+ <param index="0" name="canvas_texture" type="RID" />
+ <param index="1" name="repeat" type="int" enum="RenderingServer.CanvasItemTextureRepeat" />
<description>
</description>
</method>
@@ -804,74 +814,74 @@
</method>
<method name="decal_set_albedo_mix">
<return type="void" />
- <argument index="0" name="decal" type="RID" />
- <argument index="1" name="albedo_mix" type="float" />
+ <param index="0" name="decal" type="RID" />
+ <param index="1" name="albedo_mix" type="float" />
<description>
</description>
</method>
<method name="decal_set_cull_mask">
<return type="void" />
- <argument index="0" name="decal" type="RID" />
- <argument index="1" name="mask" type="int" />
+ <param index="0" name="decal" type="RID" />
+ <param index="1" name="mask" type="int" />
<description>
</description>
</method>
<method name="decal_set_distance_fade">
<return type="void" />
- <argument index="0" name="decal" type="RID" />
- <argument index="1" name="enabled" type="bool" />
- <argument index="2" name="begin" type="float" />
- <argument index="3" name="length" type="float" />
+ <param index="0" name="decal" type="RID" />
+ <param index="1" name="enabled" type="bool" />
+ <param index="2" name="begin" type="float" />
+ <param index="3" name="length" type="float" />
<description>
</description>
</method>
<method name="decal_set_emission_energy">
<return type="void" />
- <argument index="0" name="decal" type="RID" />
- <argument index="1" name="energy" type="float" />
+ <param index="0" name="decal" type="RID" />
+ <param index="1" name="energy" type="float" />
<description>
</description>
</method>
<method name="decal_set_extents">
<return type="void" />
- <argument index="0" name="decal" type="RID" />
- <argument index="1" name="extents" type="Vector3" />
+ <param index="0" name="decal" type="RID" />
+ <param index="1" name="extents" type="Vector3" />
<description>
</description>
</method>
<method name="decal_set_fade">
<return type="void" />
- <argument index="0" name="decal" type="RID" />
- <argument index="1" name="above" type="float" />
- <argument index="2" name="below" type="float" />
+ <param index="0" name="decal" type="RID" />
+ <param index="1" name="above" type="float" />
+ <param index="2" name="below" type="float" />
<description>
</description>
</method>
<method name="decal_set_modulate">
<return type="void" />
- <argument index="0" name="decal" type="RID" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="decal" type="RID" />
+ <param index="1" name="color" type="Color" />
<description>
</description>
</method>
<method name="decal_set_normal_fade">
<return type="void" />
- <argument index="0" name="decal" type="RID" />
- <argument index="1" name="fade" type="float" />
+ <param index="0" name="decal" type="RID" />
+ <param index="1" name="fade" type="float" />
<description>
</description>
</method>
<method name="decal_set_texture">
<return type="void" />
- <argument index="0" name="decal" type="RID" />
- <argument index="1" name="type" type="int" enum="RenderingServer.DecalTexture" />
- <argument index="2" name="texture" type="RID" />
+ <param index="0" name="decal" type="RID" />
+ <param index="1" name="type" type="int" enum="RenderingServer.DecalTexture" />
+ <param index="2" name="texture" type="RID" />
<description>
</description>
</method>
<method name="decals_set_filter">
<return type="void" />
- <argument index="0" name="filter" type="int" enum="RenderingServer.DecalFilter" />
+ <param index="0" name="filter" type="int" enum="RenderingServer.DecalFilter" />
<description>
</description>
</method>
@@ -885,22 +895,22 @@
</method>
<method name="directional_shadow_atlas_set_size">
<return type="void" />
- <argument index="0" name="size" type="int" />
- <argument index="1" name="is_16bits" type="bool" />
+ <param index="0" name="size" type="int" />
+ <param index="1" name="is_16bits" type="bool" />
<description>
</description>
</method>
<method name="directional_soft_shadow_filter_set_quality">
<return type="void" />
- <argument index="0" name="quality" type="int" enum="RenderingServer.ShadowQuality" />
+ <param index="0" name="quality" type="int" enum="RenderingServer.ShadowQuality" />
<description>
</description>
</method>
<method name="environment_bake_panorama">
<return type="Image" />
- <argument index="0" name="environment" type="RID" />
- <argument index="1" name="bake_irradiance" type="bool" />
- <argument index="2" name="size" type="Vector2i" />
+ <param index="0" name="environment" type="RID" />
+ <param index="1" name="bake_irradiance" type="bool" />
+ <param index="2" name="size" type="Vector2i" />
<description>
</description>
</method>
@@ -913,266 +923,266 @@
</method>
<method name="environment_glow_set_use_bicubic_upscale">
<return type="void" />
- <argument index="0" name="enable" type="bool" />
+ <param index="0" name="enable" type="bool" />
<description>
</description>
</method>
<method name="environment_glow_set_use_high_quality">
<return type="void" />
- <argument index="0" name="enable" type="bool" />
+ <param index="0" name="enable" type="bool" />
<description>
</description>
</method>
<method name="environment_set_adjustment">
<return type="void" />
- <argument index="0" name="env" type="RID" />
- <argument index="1" name="enable" type="bool" />
- <argument index="2" name="brightness" type="float" />
- <argument index="3" name="contrast" type="float" />
- <argument index="4" name="saturation" type="float" />
- <argument index="5" name="use_1d_color_correction" type="bool" />
- <argument index="6" name="color_correction" type="RID" />
+ <param index="0" name="env" type="RID" />
+ <param index="1" name="enable" type="bool" />
+ <param index="2" name="brightness" type="float" />
+ <param index="3" name="contrast" type="float" />
+ <param index="4" name="saturation" type="float" />
+ <param index="5" name="use_1d_color_correction" type="bool" />
+ <param index="6" name="color_correction" type="RID" />
<description>
Sets the values to be used with the "Adjustment" post-process effect. See [Environment] for more details.
</description>
</method>
<method name="environment_set_ambient_light">
<return type="void" />
- <argument index="0" name="env" type="RID" />
- <argument index="1" name="color" type="Color" />
- <argument index="2" name="ambient" type="int" enum="RenderingServer.EnvironmentAmbientSource" default="0" />
- <argument index="3" name="energy" type="float" default="1.0" />
- <argument index="4" name="sky_contibution" type="float" default="0.0" />
- <argument index="5" name="reflection_source" type="int" enum="RenderingServer.EnvironmentReflectionSource" default="0" />
+ <param index="0" name="env" type="RID" />
+ <param index="1" name="color" type="Color" />
+ <param index="2" name="ambient" type="int" enum="RenderingServer.EnvironmentAmbientSource" default="0" />
+ <param index="3" name="energy" type="float" default="1.0" />
+ <param index="4" name="sky_contibution" type="float" default="0.0" />
+ <param index="5" name="reflection_source" type="int" enum="RenderingServer.EnvironmentReflectionSource" default="0" />
<description>
</description>
</method>
<method name="environment_set_background">
<return type="void" />
- <argument index="0" name="env" type="RID" />
- <argument index="1" name="bg" type="int" enum="RenderingServer.EnvironmentBG" />
+ <param index="0" name="env" type="RID" />
+ <param index="1" name="bg" type="int" enum="RenderingServer.EnvironmentBG" />
<description>
Sets the [i]BGMode[/i] of the environment. Equivalent to [member Environment.background_mode].
</description>
</method>
<method name="environment_set_bg_color">
<return type="void" />
- <argument index="0" name="env" type="RID" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="env" type="RID" />
+ <param index="1" name="color" type="Color" />
<description>
Color displayed for clear areas of the scene (if using Custom color or Color+Sky background modes).
</description>
</method>
<method name="environment_set_bg_energy">
<return type="void" />
- <argument index="0" name="env" type="RID" />
- <argument index="1" name="energy" type="float" />
+ <param index="0" name="env" type="RID" />
+ <param index="1" name="energy" type="float" />
<description>
Sets the intensity of the background color.
</description>
</method>
<method name="environment_set_canvas_max_layer">
<return type="void" />
- <argument index="0" name="env" type="RID" />
- <argument index="1" name="max_layer" type="int" />
+ <param index="0" name="env" type="RID" />
+ <param index="1" name="max_layer" type="int" />
<description>
Sets the maximum layer to use if using Canvas background mode.
</description>
</method>
<method name="environment_set_fog">
<return type="void" />
- <argument index="0" name="env" type="RID" />
- <argument index="1" name="enable" type="bool" />
- <argument index="2" name="light_color" type="Color" />
- <argument index="3" name="light_energy" type="float" />
- <argument index="4" name="sun_scatter" type="float" />
- <argument index="5" name="density" type="float" />
- <argument index="6" name="height" type="float" />
- <argument index="7" name="height_density" type="float" />
- <argument index="8" name="aerial_perspective" type="float" />
+ <param index="0" name="env" type="RID" />
+ <param index="1" name="enable" type="bool" />
+ <param index="2" name="light_color" type="Color" />
+ <param index="3" name="light_energy" type="float" />
+ <param index="4" name="sun_scatter" type="float" />
+ <param index="5" name="density" type="float" />
+ <param index="6" name="height" type="float" />
+ <param index="7" name="height_density" type="float" />
+ <param index="8" name="aerial_perspective" type="float" />
<description>
</description>
</method>
<method name="environment_set_glow">
<return type="void" />
- <argument index="0" name="env" type="RID" />
- <argument index="1" name="enable" type="bool" />
- <argument index="2" name="levels" type="PackedFloat32Array" />
- <argument index="3" name="intensity" type="float" />
- <argument index="4" name="strength" type="float" />
- <argument index="5" name="mix" type="float" />
- <argument index="6" name="bloom_threshold" type="float" />
- <argument index="7" name="blend_mode" type="int" enum="RenderingServer.EnvironmentGlowBlendMode" />
- <argument index="8" name="hdr_bleed_threshold" type="float" />
- <argument index="9" name="hdr_bleed_scale" type="float" />
- <argument index="10" name="hdr_luminance_cap" type="float" />
- <argument index="11" name="glow_map_strength" type="float" />
- <argument index="12" name="glow_map" type="RID" />
+ <param index="0" name="env" type="RID" />
+ <param index="1" name="enable" type="bool" />
+ <param index="2" name="levels" type="PackedFloat32Array" />
+ <param index="3" name="intensity" type="float" />
+ <param index="4" name="strength" type="float" />
+ <param index="5" name="mix" type="float" />
+ <param index="6" name="bloom_threshold" type="float" />
+ <param index="7" name="blend_mode" type="int" enum="RenderingServer.EnvironmentGlowBlendMode" />
+ <param index="8" name="hdr_bleed_threshold" type="float" />
+ <param index="9" name="hdr_bleed_scale" type="float" />
+ <param index="10" name="hdr_luminance_cap" type="float" />
+ <param index="11" name="glow_map_strength" type="float" />
+ <param index="12" name="glow_map" type="RID" />
<description>
</description>
</method>
<method name="environment_set_sdfgi">
<return type="void" />
- <argument index="0" name="env" type="RID" />
- <argument index="1" name="enable" type="bool" />
- <argument index="2" name="cascades" type="int" />
- <argument index="3" name="min_cell_size" type="float" />
- <argument index="4" name="y_scale" type="int" enum="RenderingServer.EnvironmentSDFGIYScale" />
- <argument index="5" name="use_occlusion" type="bool" />
- <argument index="6" name="bounce_feedback" type="float" />
- <argument index="7" name="read_sky" type="bool" />
- <argument index="8" name="energy" type="float" />
- <argument index="9" name="normal_bias" type="float" />
- <argument index="10" name="probe_bias" type="float" />
+ <param index="0" name="env" type="RID" />
+ <param index="1" name="enable" type="bool" />
+ <param index="2" name="cascades" type="int" />
+ <param index="3" name="min_cell_size" type="float" />
+ <param index="4" name="y_scale" type="int" enum="RenderingServer.EnvironmentSDFGIYScale" />
+ <param index="5" name="use_occlusion" type="bool" />
+ <param index="6" name="bounce_feedback" type="float" />
+ <param index="7" name="read_sky" type="bool" />
+ <param index="8" name="energy" type="float" />
+ <param index="9" name="normal_bias" type="float" />
+ <param index="10" name="probe_bias" type="float" />
<description>
</description>
</method>
<method name="environment_set_sdfgi_frames_to_converge">
<return type="void" />
- <argument index="0" name="frames" type="int" enum="RenderingServer.EnvironmentSDFGIFramesToConverge" />
+ <param index="0" name="frames" type="int" enum="RenderingServer.EnvironmentSDFGIFramesToConverge" />
<description>
</description>
</method>
<method name="environment_set_sdfgi_frames_to_update_light">
<return type="void" />
- <argument index="0" name="frames" type="int" enum="RenderingServer.EnvironmentSDFGIFramesToUpdateLight" />
+ <param index="0" name="frames" type="int" enum="RenderingServer.EnvironmentSDFGIFramesToUpdateLight" />
<description>
</description>
</method>
<method name="environment_set_sdfgi_ray_count">
<return type="void" />
- <argument index="0" name="ray_count" type="int" enum="RenderingServer.EnvironmentSDFGIRayCount" />
+ <param index="0" name="ray_count" type="int" enum="RenderingServer.EnvironmentSDFGIRayCount" />
<description>
</description>
</method>
<method name="environment_set_sky">
<return type="void" />
- <argument index="0" name="env" type="RID" />
- <argument index="1" name="sky" type="RID" />
+ <param index="0" name="env" type="RID" />
+ <param index="1" name="sky" type="RID" />
<description>
Sets the [Sky] to be used as the environment's background when using [i]BGMode[/i] sky. Equivalent to [member Environment.sky].
</description>
</method>
<method name="environment_set_sky_custom_fov">
<return type="void" />
- <argument index="0" name="env" type="RID" />
- <argument index="1" name="scale" type="float" />
+ <param index="0" name="env" type="RID" />
+ <param index="1" name="scale" type="float" />
<description>
Sets a custom field of view for the background [Sky]. Equivalent to [member Environment.sky_custom_fov].
</description>
</method>
<method name="environment_set_sky_orientation">
<return type="void" />
- <argument index="0" name="env" type="RID" />
- <argument index="1" name="orientation" type="Basis" />
+ <param index="0" name="env" type="RID" />
+ <param index="1" name="orientation" type="Basis" />
<description>
Sets the rotation of the background [Sky] expressed as a [Basis]. Equivalent to [member Environment.sky_rotation], where the rotation vector is used to construct the [Basis].
</description>
</method>
<method name="environment_set_ssao">
<return type="void" />
- <argument index="0" name="env" type="RID" />
- <argument index="1" name="enable" type="bool" />
- <argument index="2" name="radius" type="float" />
- <argument index="3" name="intensity" type="float" />
- <argument index="4" name="power" type="float" />
- <argument index="5" name="detail" type="float" />
- <argument index="6" name="horizon" type="float" />
- <argument index="7" name="sharpness" type="float" />
- <argument index="8" name="light_affect" type="float" />
- <argument index="9" name="ao_channel_affect" type="float" />
+ <param index="0" name="env" type="RID" />
+ <param index="1" name="enable" type="bool" />
+ <param index="2" name="radius" type="float" />
+ <param index="3" name="intensity" type="float" />
+ <param index="4" name="power" type="float" />
+ <param index="5" name="detail" type="float" />
+ <param index="6" name="horizon" type="float" />
+ <param index="7" name="sharpness" type="float" />
+ <param index="8" name="light_affect" type="float" />
+ <param index="9" name="ao_channel_affect" type="float" />
<description>
Sets the variables to be used with the screen-space ambient occlusion (SSAO) post-process effect. See [Environment] for more details.
</description>
</method>
<method name="environment_set_ssao_quality">
<return type="void" />
- <argument index="0" name="quality" type="int" enum="RenderingServer.EnvironmentSSAOQuality" />
- <argument index="1" name="half_size" type="bool" />
- <argument index="2" name="adaptive_target" type="float" />
- <argument index="3" name="blur_passes" type="int" />
- <argument index="4" name="fadeout_from" type="float" />
- <argument index="5" name="fadeout_to" type="float" />
+ <param index="0" name="quality" type="int" enum="RenderingServer.EnvironmentSSAOQuality" />
+ <param index="1" name="half_size" type="bool" />
+ <param index="2" name="adaptive_target" type="float" />
+ <param index="3" name="blur_passes" type="int" />
+ <param index="4" name="fadeout_from" type="float" />
+ <param index="5" name="fadeout_to" type="float" />
<description>
Sets the quality level of the screen-space ambient occlusion (SSAO) post-process effect. See [Environment] for more details.
</description>
</method>
<method name="environment_set_ssil_quality">
<return type="void" />
- <argument index="0" name="quality" type="int" enum="RenderingServer.EnvironmentSSILQuality" />
- <argument index="1" name="half_size" type="bool" />
- <argument index="2" name="adaptive_target" type="float" />
- <argument index="3" name="blur_passes" type="int" />
- <argument index="4" name="fadeout_from" type="float" />
- <argument index="5" name="fadeout_to" type="float" />
+ <param index="0" name="quality" type="int" enum="RenderingServer.EnvironmentSSILQuality" />
+ <param index="1" name="half_size" type="bool" />
+ <param index="2" name="adaptive_target" type="float" />
+ <param index="3" name="blur_passes" type="int" />
+ <param index="4" name="fadeout_from" type="float" />
+ <param index="5" name="fadeout_to" type="float" />
<description>
Sets the quality level of the screen-space indirect lighting (SSIL) post-process effect. See [Environment] for more details.
</description>
</method>
<method name="environment_set_ssr">
<return type="void" />
- <argument index="0" name="env" type="RID" />
- <argument index="1" name="enable" type="bool" />
- <argument index="2" name="max_steps" type="int" />
- <argument index="3" name="fade_in" type="float" />
- <argument index="4" name="fade_out" type="float" />
- <argument index="5" name="depth_tolerance" type="float" />
+ <param index="0" name="env" type="RID" />
+ <param index="1" name="enable" type="bool" />
+ <param index="2" name="max_steps" type="int" />
+ <param index="3" name="fade_in" type="float" />
+ <param index="4" name="fade_out" type="float" />
+ <param index="5" name="depth_tolerance" type="float" />
<description>
Sets the variables to be used with the "screen space reflections" post-process effect. See [Environment] for more details.
</description>
</method>
<method name="environment_set_ssr_roughness_quality">
<return type="void" />
- <argument index="0" name="quality" type="int" enum="RenderingServer.EnvironmentSSRRoughnessQuality" />
+ <param index="0" name="quality" type="int" enum="RenderingServer.EnvironmentSSRRoughnessQuality" />
<description>
</description>
</method>
<method name="environment_set_tonemap">
<return type="void" />
- <argument index="0" name="env" type="RID" />
- <argument index="1" name="tone_mapper" type="int" enum="RenderingServer.EnvironmentToneMapper" />
- <argument index="2" name="exposure" type="float" />
- <argument index="3" name="white" type="float" />
- <argument index="4" name="auto_exposure" type="bool" />
- <argument index="5" name="min_luminance" type="float" />
- <argument index="6" name="max_luminance" type="float" />
- <argument index="7" name="auto_exp_speed" type="float" />
- <argument index="8" name="auto_exp_grey" type="float" />
+ <param index="0" name="env" type="RID" />
+ <param index="1" name="tone_mapper" type="int" enum="RenderingServer.EnvironmentToneMapper" />
+ <param index="2" name="exposure" type="float" />
+ <param index="3" name="white" type="float" />
+ <param index="4" name="auto_exposure" type="bool" />
+ <param index="5" name="min_luminance" type="float" />
+ <param index="6" name="max_luminance" type="float" />
+ <param index="7" name="auto_exp_speed" type="float" />
+ <param index="8" name="auto_exp_grey" type="float" />
<description>
Sets the variables to be used with the "tonemap" post-process effect. See [Environment] for more details.
</description>
</method>
<method name="environment_set_volumetric_fog">
<return type="void" />
- <argument index="0" name="env" type="RID" />
- <argument index="1" name="enable" type="bool" />
- <argument index="2" name="density" type="float" />
- <argument index="3" name="albedo" type="Color" />
- <argument index="4" name="emission" type="Color" />
- <argument index="5" name="emission_energy" type="float" />
- <argument index="6" name="anisotropy" type="float" />
- <argument index="7" name="length" type="float" />
- <argument index="8" name="p_detail_spread" type="float" />
- <argument index="9" name="gi_inject" type="float" />
- <argument index="10" name="temporal_reprojection" type="bool" />
- <argument index="11" name="temporal_reprojection_amount" type="float" />
- <argument index="12" name="ambient_inject" type="float" />
+ <param index="0" name="env" type="RID" />
+ <param index="1" name="enable" type="bool" />
+ <param index="2" name="density" type="float" />
+ <param index="3" name="albedo" type="Color" />
+ <param index="4" name="emission" type="Color" />
+ <param index="5" name="emission_energy" type="float" />
+ <param index="6" name="anisotropy" type="float" />
+ <param index="7" name="length" type="float" />
+ <param index="8" name="p_detail_spread" type="float" />
+ <param index="9" name="gi_inject" type="float" />
+ <param index="10" name="temporal_reprojection" type="bool" />
+ <param index="11" name="temporal_reprojection_amount" type="float" />
+ <param index="12" name="ambient_inject" type="float" />
<description>
</description>
</method>
<method name="environment_set_volumetric_fog_filter_active">
<return type="void" />
- <argument index="0" name="active" type="bool" />
+ <param index="0" name="active" type="bool" />
<description>
Enables filtering of the volumetric fog scattering buffer. This results in much smoother volumes with very few under-sampling artifacts.
</description>
</method>
<method name="environment_set_volumetric_fog_volume_size">
<return type="void" />
- <argument index="0" name="size" type="int" />
- <argument index="1" name="depth" type="int" />
+ <param index="0" name="size" type="int" />
+ <param index="1" name="depth" type="int" />
<description>
- Sets the resolution of the volumetric fog's froxel buffer. [code]size[/code] is modified by the screen's aspect ratio and then used to set the width and height of the buffer. While [code]depth[/code] is directly used to set the depth of the buffer.
+ Sets the resolution of the volumetric fog's froxel buffer. [param size] is modified by the screen's aspect ratio and then used to set the width and height of the buffer. While [param depth] is directly used to set the depth of the buffer.
</description>
</method>
<method name="fog_volume_create">
@@ -1183,32 +1193,32 @@
</method>
<method name="fog_volume_set_extents">
<return type="void" />
- <argument index="0" name="fog_volume" type="RID" />
- <argument index="1" name="extents" type="Vector3" />
+ <param index="0" name="fog_volume" type="RID" />
+ <param index="1" name="extents" type="Vector3" />
<description>
Sets the size of the fog volume when shape is [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER] or [constant RenderingServer.FOG_VOLUME_SHAPE_BOX].
</description>
</method>
<method name="fog_volume_set_material">
<return type="void" />
- <argument index="0" name="fog_volume" type="RID" />
- <argument index="1" name="material" type="RID" />
+ <param index="0" name="fog_volume" type="RID" />
+ <param index="1" name="material" type="RID" />
<description>
Sets the [Material] of the fog volume. Can be either a [FogMaterial] or a custom [ShaderMaterial].
</description>
</method>
<method name="fog_volume_set_shape">
<return type="void" />
- <argument index="0" name="fog_volume" type="RID" />
- <argument index="1" name="shape" type="int" enum="RenderingServer.FogVolumeShape" />
+ <param index="0" name="fog_volume" type="RID" />
+ <param index="1" name="shape" type="int" enum="RenderingServer.FogVolumeShape" />
<description>
Sets the shape of the fog volume to either [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER], [constant RenderingServer.FOG_VOLUME_SHAPE_BOX] or [constant RenderingServer.FOG_VOLUME_SHAPE_WORLD].
</description>
</method>
<method name="force_draw">
<return type="void" />
- <argument index="0" name="swap_buffers" type="bool" default="true" />
- <argument index="1" name="frame_step" type="float" default="0.0" />
+ <param index="0" name="swap_buffers" type="bool" default="true" />
+ <param index="1" name="frame_step" type="float" default="0.0" />
<description>
</description>
</method>
@@ -1219,7 +1229,7 @@
</method>
<method name="free_rid">
<return type="void" />
- <argument index="0" name="rid" type="RID" />
+ <param index="0" name="rid" type="RID" />
<description>
Tries to free an object in the RenderingServer.
</description>
@@ -1236,7 +1246,7 @@
</method>
<method name="get_rendering_info">
<return type="int" />
- <argument index="0" name="info" type="int" enum="RenderingServer.RenderingInfo" />
+ <param index="0" name="info" type="int" enum="RenderingServer.RenderingInfo" />
<description>
</description>
</method>
@@ -1288,22 +1298,22 @@
</method>
<method name="gi_set_use_half_resolution">
<return type="void" />
- <argument index="0" name="half_resolution" type="bool" />
+ <param index="0" name="half_resolution" type="bool" />
<description>
- If [code]half_resolution[/code] is [code]true[/code], renders [VoxelGI] and SDFGI ([member Environment.sdfgi_enabled]) buffers at halved resolution (e.g. 960×540 when the viewport size is 1920×1080). This improves performance significantly when VoxelGI or SDFGI is enabled, at the cost of artifacts that may be visible on polygon edges. The loss in quality becomes less noticeable as the viewport resolution increases. [LightmapGI] rendering is not affected by this setting. See also [member ProjectSettings.rendering/global_illumination/gi/use_half_resolution].
+ If [param half_resolution] is [code]true[/code], renders [VoxelGI] and SDFGI ([member Environment.sdfgi_enabled]) buffers at halved resolution (e.g. 960×540 when the viewport size is 1920×1080). This improves performance significantly when VoxelGI or SDFGI is enabled, at the cost of artifacts that may be visible on polygon edges. The loss in quality becomes less noticeable as the viewport resolution increases. [LightmapGI] rendering is not affected by this setting. See also [member ProjectSettings.rendering/global_illumination/gi/use_half_resolution].
</description>
</method>
<method name="global_shader_uniform_add">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="type" type="int" enum="RenderingServer.GlobalShaderUniformType" />
- <argument index="2" name="default_value" type="Variant" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="type" type="int" enum="RenderingServer.GlobalShaderUniformType" />
+ <param index="2" name="default_value" type="Variant" />
<description>
</description>
</method>
<method name="global_shader_uniform_get" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
</description>
</method>
@@ -1314,27 +1324,27 @@
</method>
<method name="global_shader_uniform_get_type" qualifiers="const">
<return type="int" enum="RenderingServer.GlobalShaderUniformType" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
</description>
</method>
<method name="global_shader_uniform_remove">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
</description>
</method>
<method name="global_shader_uniform_set">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="value" type="Variant" />
<description>
</description>
</method>
<method name="global_shader_uniform_set_override">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="value" type="Variant" />
<description>
</description>
</method>
@@ -1346,30 +1356,30 @@
</method>
<method name="has_feature" qualifiers="const">
<return type="bool" />
- <argument index="0" name="feature" type="int" enum="RenderingServer.Features" />
+ <param index="0" name="feature" type="int" enum="RenderingServer.Features" />
<description>
Not yet implemented. Always returns [code]false[/code].
</description>
</method>
<method name="has_os_feature" qualifiers="const">
<return type="bool" />
- <argument index="0" name="feature" type="String" />
+ <param index="0" name="feature" type="String" />
<description>
- Returns [code]true[/code] if the OS supports a certain feature. Features might be [code]s3tc[/code], [code]etc[/code], and [code]etc2[/code].
+ Returns [code]true[/code] if the OS supports a certain [param feature]. Features might be [code]s3tc[/code], [code]etc[/code], and [code]etc2[/code].
</description>
</method>
<method name="instance_attach_object_instance_id">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="id" type="int" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="id" type="int" />
<description>
Attaches a unique Object ID to instance. Object ID must be attached to instance for proper culling with [method instances_cull_aabb], [method instances_cull_convex], and [method instances_cull_ray].
</description>
</method>
<method name="instance_attach_skeleton">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="skeleton" type="RID" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="skeleton" type="RID" />
<description>
Attaches a skeleton to an instance. Removes the previous skeleton from the instance.
</description>
@@ -1384,225 +1394,225 @@
</method>
<method name="instance_create2">
<return type="RID" />
- <argument index="0" name="base" type="RID" />
- <argument index="1" name="scenario" type="RID" />
+ <param index="0" name="base" type="RID" />
+ <param index="1" name="scenario" type="RID" />
<description>
Creates a visual instance, adds it to the RenderingServer, and sets both base and scenario. It can be accessed with the RID that is returned. This RID will be used in all [code]instance_*[/code] RenderingServer functions.
Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method.
</description>
</method>
- <method name="instance_geometry_get_shader_parameter" qualifiers="const">
+ <method name="instance_geometry_get_shader_uniform" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="parameter" type="StringName" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="parameter" type="StringName" />
<description>
</description>
</method>
- <method name="instance_geometry_get_shader_parameter_default_value" qualifiers="const">
+ <method name="instance_geometry_get_shader_uniform_default_value" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="parameter" type="StringName" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="parameter" type="StringName" />
<description>
</description>
</method>
- <method name="instance_geometry_get_shader_parameter_list" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="instance" type="RID" />
+ <method name="instance_geometry_get_shader_uniform_list" qualifiers="const">
+ <return type="Dictionary[]" />
+ <param index="0" name="instance" type="RID" />
<description>
</description>
</method>
<method name="instance_geometry_set_cast_shadows_setting">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="shadow_casting_setting" type="int" enum="RenderingServer.ShadowCastingSetting" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="shadow_casting_setting" type="int" enum="RenderingServer.ShadowCastingSetting" />
<description>
Sets the shadow casting setting to one of [enum ShadowCastingSetting]. Equivalent to [member GeometryInstance3D.cast_shadow].
</description>
</method>
<method name="instance_geometry_set_flag">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="flag" type="int" enum="RenderingServer.InstanceFlags" />
- <argument index="2" name="enabled" type="bool" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="flag" type="int" enum="RenderingServer.InstanceFlags" />
+ <param index="2" name="enabled" type="bool" />
<description>
Sets the flag for a given [enum InstanceFlags]. See [enum InstanceFlags] for more details.
</description>
</method>
<method name="instance_geometry_set_lightmap">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="lightmap" type="RID" />
- <argument index="2" name="lightmap_uv_scale" type="Rect2" />
- <argument index="3" name="lightmap_slice" type="int" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="lightmap" type="RID" />
+ <param index="2" name="lightmap_uv_scale" type="Rect2" />
+ <param index="3" name="lightmap_slice" type="int" />
<description>
</description>
</method>
<method name="instance_geometry_set_lod_bias">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="lod_bias" type="float" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="lod_bias" type="float" />
<description>
</description>
</method>
<method name="instance_geometry_set_material_overlay">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="material" type="RID" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="material" type="RID" />
<description>
Sets a material that will be rendered for all surfaces on top of active materials for the mesh associated with this instance. Equivalent to [member GeometryInstance3D.material_overlay].
</description>
</method>
<method name="instance_geometry_set_material_override">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="material" type="RID" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="material" type="RID" />
<description>
Sets a material that will override the material for all surfaces on the mesh associated with this instance. Equivalent to [member GeometryInstance3D.material_override].
</description>
</method>
- <method name="instance_geometry_set_shader_parameter">
+ <method name="instance_geometry_set_shader_uniform">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="parameter" type="StringName" />
- <argument index="2" name="value" type="Variant" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="parameter" type="StringName" />
+ <param index="2" name="value" type="Variant" />
<description>
</description>
</method>
<method name="instance_geometry_set_transparency">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="transparency" type="float" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="transparency" type="float" />
<description>
Sets the transparency for the given geometry instance. Equivalent to [member GeometryInstance3D.transparency].
- A transparency of [code]0.0[/code] is fully opaque, while [code]1.0[/code] is fully transparent. Values greater than [code]0.0[/code] (exclusive) will force the geometry's materials to go through the transparent pipeline, which is slower to render and can exhibit rendering issues due to incorrect transparency sorting. However, unlike using a transparent material, setting [code]transparency[/code] to a value greater than [code]0.0[/code] (exclusive) will [i]not[/i] disable shadow rendering.
+ A transparency of [code]0.0[/code] is fully opaque, while [code]1.0[/code] is fully transparent. Values greater than [code]0.0[/code] (exclusive) will force the geometry's materials to go through the transparent pipeline, which is slower to render and can exhibit rendering issues due to incorrect transparency sorting. However, unlike using a transparent material, setting [param transparency] to a value greater than [code]0.0[/code] (exclusive) will [i]not[/i] disable shadow rendering.
In spatial shaders, [code]1.0 - transparency[/code] is set as the default value of the [code]ALPHA[/code] built-in.
- [b]Note:[/b] [code]transparency[/code] is clamped between [code]0.0[/code] and [code]1.0[/code], so this property cannot be used to make transparent materials more opaque than they originally are.
+ [b]Note:[/b] [param transparency] is clamped between [code]0.0[/code] and [code]1.0[/code], so this property cannot be used to make transparent materials more opaque than they originally are.
</description>
</method>
<method name="instance_geometry_set_visibility_range">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="min" type="float" />
- <argument index="2" name="max" type="float" />
- <argument index="3" name="min_margin" type="float" />
- <argument index="4" name="max_margin" type="float" />
- <argument index="5" name="fade_mode" type="int" enum="RenderingServer.VisibilityRangeFadeMode" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="min" type="float" />
+ <param index="2" name="max" type="float" />
+ <param index="3" name="min_margin" type="float" />
+ <param index="4" name="max_margin" type="float" />
+ <param index="5" name="fade_mode" type="int" enum="RenderingServer.VisibilityRangeFadeMode" />
<description>
Sets the visibility range values for the given geometry instance. Equivalent to [member GeometryInstance3D.visibility_range_begin] and related properties.
</description>
</method>
<method name="instance_set_base">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="base" type="RID" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="base" type="RID" />
<description>
Sets the base of the instance. A base can be any of the 3D objects that are created in the RenderingServer that can be displayed. For example, any of the light types, mesh, multimesh, immediate geometry, particle system, reflection probe, lightmap, and the GI probe are all types that can be set as the base of an instance in order to be displayed in the scenario.
</description>
</method>
<method name="instance_set_blend_shape_weight">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="shape" type="int" />
- <argument index="2" name="weight" type="float" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="shape" type="int" />
+ <param index="2" name="weight" type="float" />
<description>
Sets the weight for a given blend shape associated with this instance.
</description>
</method>
<method name="instance_set_custom_aabb">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="aabb" type="AABB" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="aabb" type="AABB" />
<description>
Sets a custom AABB to use when culling objects from the view frustum. Equivalent to [method GeometryInstance3D.set_custom_aabb].
</description>
</method>
<method name="instance_set_extra_visibility_margin">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="margin" type="float" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="margin" type="float" />
<description>
Sets a margin to increase the size of the AABB when culling objects from the view frustum. This allows you to avoid culling objects that fall outside the view frustum. Equivalent to [member GeometryInstance3D.extra_cull_margin].
</description>
</method>
<method name="instance_set_ignore_culling">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="enabled" type="bool" />
<description>
</description>
</method>
<method name="instance_set_layer_mask">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="mask" type="int" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="mask" type="int" />
<description>
Sets the render layers that this instance will be drawn to. Equivalent to [member VisualInstance3D.layers].
</description>
</method>
<method name="instance_set_scenario">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="scenario" type="RID" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="scenario" type="RID" />
<description>
Sets the scenario that the instance is in. The scenario is the 3D world that the objects will be displayed in.
</description>
</method>
<method name="instance_set_surface_override_material">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="surface" type="int" />
- <argument index="2" name="material" type="RID" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="surface" type="int" />
+ <param index="2" name="material" type="RID" />
<description>
Sets the override material of a specific surface. Equivalent to [method MeshInstance3D.set_surface_override_material].
</description>
</method>
<method name="instance_set_transform">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="transform" type="Transform3D" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="transform" type="Transform3D" />
<description>
Sets the world space transform of the instance. Equivalent to [member Node3D.transform].
</description>
</method>
<method name="instance_set_visibility_parent">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="parent" type="RID" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="parent" type="RID" />
<description>
Sets the visibility parent for the given instance. Equivalent to [member Node3D.visibility_parent].
</description>
</method>
<method name="instance_set_visible">
<return type="void" />
- <argument index="0" name="instance" type="RID" />
- <argument index="1" name="visible" type="bool" />
+ <param index="0" name="instance" type="RID" />
+ <param index="1" name="visible" type="bool" />
<description>
Sets whether an instance is drawn or not. Equivalent to [member Node3D.visible].
</description>
</method>
<method name="instances_cull_aabb" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="aabb" type="AABB" />
- <argument index="1" name="scenario" type="RID" />
+ <return type="PackedInt64Array" />
+ <param index="0" name="aabb" type="AABB" />
+ <param index="1" name="scenario" type="RID" />
<description>
Returns an array of object IDs intersecting with the provided AABB. Only visual 3D nodes are considered, such as [MeshInstance3D] or [DirectionalLight3D]. Use [method @GlobalScope.instance_from_id] to obtain the actual nodes. A scenario RID must be provided, which is available in the [World3D] you want to query. This forces an update for all resources queued to update.
[b]Warning:[/b] This function is primarily intended for editor usage. For in-game use cases, prefer physics collision.
</description>
</method>
<method name="instances_cull_convex" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="convex" type="Array" />
- <argument index="1" name="scenario" type="RID" />
+ <return type="PackedInt64Array" />
+ <param index="0" name="convex" type="Array" />
+ <param index="1" name="scenario" type="RID" />
<description>
Returns an array of object IDs intersecting with the provided convex shape. Only visual 3D nodes are considered, such as [MeshInstance3D] or [DirectionalLight3D]. Use [method @GlobalScope.instance_from_id] to obtain the actual nodes. A scenario RID must be provided, which is available in the [World3D] you want to query. This forces an update for all resources queued to update.
[b]Warning:[/b] This function is primarily intended for editor usage. For in-game use cases, prefer physics collision.
</description>
</method>
<method name="instances_cull_ray" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="from" type="Vector3" />
- <argument index="1" name="to" type="Vector3" />
- <argument index="2" name="scenario" type="RID" />
+ <return type="PackedInt64Array" />
+ <param index="0" name="from" type="Vector3" />
+ <param index="1" name="to" type="Vector3" />
+ <param index="2" name="scenario" type="RID" />
<description>
Returns an array of object IDs intersecting with the provided 3D ray. Only visual 3D nodes are considered, such as [MeshInstance3D] or [DirectionalLight3D]. Use [method @GlobalScope.instance_from_id] to obtain the actual nodes. A scenario RID must be provided, which is available in the [World3D] you want to query. This forces an update for all resources queued to update.
[b]Warning:[/b] This function is primarily intended for editor usage. For in-game use cases, prefer physics collision.
@@ -1610,120 +1620,120 @@
</method>
<method name="light_directional_set_blend_splits">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
If [code]true[/code], this directional light will blend between shadow map splits resulting in a smoother transition between them. Equivalent to [member DirectionalLight3D.directional_shadow_blend_splits].
</description>
</method>
<method name="light_directional_set_shadow_mode">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="mode" type="int" enum="RenderingServer.LightDirectionalShadowMode" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="mode" type="int" enum="RenderingServer.LightDirectionalShadowMode" />
<description>
Sets the shadow mode for this directional light. Equivalent to [member DirectionalLight3D.directional_shadow_mode]. See [enum LightDirectionalShadowMode] for options.
</description>
</method>
<method name="light_directional_set_sky_mode">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="mode" type="int" enum="RenderingServer.LightDirectionalSkyMode" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="mode" type="int" enum="RenderingServer.LightDirectionalSkyMode" />
<description>
If [code]true[/code], this light will not be used for anything except sky shaders. Use this for lights that impact your sky shader that you may want to hide from affecting the rest of the scene. For example, you may want to enable this when the sun in your sky shader falls below the horizon.
</description>
</method>
<method name="light_omni_set_shadow_mode">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="mode" type="int" enum="RenderingServer.LightOmniShadowMode" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="mode" type="int" enum="RenderingServer.LightOmniShadowMode" />
<description>
Sets whether to use a dual paraboloid or a cubemap for the shadow map. Dual paraboloid is faster but may suffer from artifacts. Equivalent to [member OmniLight3D.omni_shadow_mode].
</description>
</method>
<method name="light_projectors_set_filter">
<return type="void" />
- <argument index="0" name="filter" type="int" enum="RenderingServer.LightProjectorFilter" />
+ <param index="0" name="filter" type="int" enum="RenderingServer.LightProjectorFilter" />
<description>
</description>
</method>
<method name="light_set_bake_mode">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="bake_mode" type="int" enum="RenderingServer.LightBakeMode" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="bake_mode" type="int" enum="RenderingServer.LightBakeMode" />
<description>
</description>
</method>
<method name="light_set_color">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="color" type="Color" />
<description>
Sets the color of the light. Equivalent to [member Light3D.light_color].
</description>
</method>
<method name="light_set_cull_mask">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="mask" type="int" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="mask" type="int" />
<description>
Sets the cull mask for this Light3D. Lights only affect objects in the selected layers. Equivalent to [member Light3D.light_cull_mask].
</description>
</method>
<method name="light_set_distance_fade">
<return type="void" />
- <argument index="0" name="decal" type="RID" />
- <argument index="1" name="enabled" type="bool" />
- <argument index="2" name="begin" type="float" />
- <argument index="3" name="shadow" type="float" />
- <argument index="4" name="length" type="float" />
+ <param index="0" name="decal" type="RID" />
+ <param index="1" name="enabled" type="bool" />
+ <param index="2" name="begin" type="float" />
+ <param index="3" name="shadow" type="float" />
+ <param index="4" name="length" type="float" />
<description>
Sets the distance fade for this Light3D. This acts as a form of level of detail (LOD) and can be used to improve performance. Equivalent to [member Light3D.distance_fade_enabled], [member Light3D.distance_fade_begin], [member Light3D.distance_fade_shadow], and [member Light3D.distance_fade_length].
</description>
</method>
<method name="light_set_max_sdfgi_cascade">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="cascade" type="int" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="cascade" type="int" />
<description>
</description>
</method>
<method name="light_set_negative">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
If [code]true[/code], light will subtract light instead of adding light. Equivalent to [member Light3D.light_negative].
</description>
</method>
<method name="light_set_param">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="param" type="int" enum="RenderingServer.LightParam" />
- <argument index="2" name="value" type="float" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="param" type="int" enum="RenderingServer.LightParam" />
+ <param index="2" name="value" type="float" />
<description>
Sets the specified light parameter. See [enum LightParam] for options. Equivalent to [method Light3D.set_param].
</description>
</method>
<method name="light_set_projector">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="texture" type="RID" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="texture" type="RID" />
<description>
Not implemented in Godot 3.x.
</description>
</method>
<method name="light_set_reverse_cull_face_mode">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="enabled" type="bool" />
<description>
If [code]true[/code], reverses the backface culling of the mesh. This can be useful when you have a flat mesh that has a light behind it. If you need to cast a shadow on both sides of the mesh, set the mesh to use double-sided shadows with [method instance_geometry_set_cast_shadows_setting]. Equivalent to [member Light3D.shadow_reverse_cull_face].
</description>
</method>
<method name="light_set_shadow">
<return type="void" />
- <argument index="0" name="light" type="RID" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="light" type="RID" />
+ <param index="1" name="enabled" type="bool" />
<description>
If [code]true[/code], light will cast shadows. Equivalent to [member Light3D.shadow_enabled].
</description>
@@ -1735,73 +1745,73 @@
</method>
<method name="lightmap_get_probe_capture_bsp_tree" qualifiers="const">
<return type="PackedInt32Array" />
- <argument index="0" name="lightmap" type="RID" />
+ <param index="0" name="lightmap" type="RID" />
<description>
</description>
</method>
<method name="lightmap_get_probe_capture_points" qualifiers="const">
<return type="PackedVector3Array" />
- <argument index="0" name="lightmap" type="RID" />
+ <param index="0" name="lightmap" type="RID" />
<description>
</description>
</method>
<method name="lightmap_get_probe_capture_sh" qualifiers="const">
<return type="PackedColorArray" />
- <argument index="0" name="lightmap" type="RID" />
+ <param index="0" name="lightmap" type="RID" />
<description>
</description>
</method>
<method name="lightmap_get_probe_capture_tetrahedra" qualifiers="const">
<return type="PackedInt32Array" />
- <argument index="0" name="lightmap" type="RID" />
+ <param index="0" name="lightmap" type="RID" />
<description>
</description>
</method>
<method name="lightmap_set_probe_bounds">
<return type="void" />
- <argument index="0" name="lightmap" type="RID" />
- <argument index="1" name="bounds" type="AABB" />
+ <param index="0" name="lightmap" type="RID" />
+ <param index="1" name="bounds" type="AABB" />
<description>
</description>
</method>
<method name="lightmap_set_probe_capture_data">
<return type="void" />
- <argument index="0" name="lightmap" type="RID" />
- <argument index="1" name="points" type="PackedVector3Array" />
- <argument index="2" name="point_sh" type="PackedColorArray" />
- <argument index="3" name="tetrahedra" type="PackedInt32Array" />
- <argument index="4" name="bsp_tree" type="PackedInt32Array" />
+ <param index="0" name="lightmap" type="RID" />
+ <param index="1" name="points" type="PackedVector3Array" />
+ <param index="2" name="point_sh" type="PackedColorArray" />
+ <param index="3" name="tetrahedra" type="PackedInt32Array" />
+ <param index="4" name="bsp_tree" type="PackedInt32Array" />
<description>
</description>
</method>
<method name="lightmap_set_probe_capture_update_speed">
<return type="void" />
- <argument index="0" name="speed" type="float" />
+ <param index="0" name="speed" type="float" />
<description>
</description>
</method>
<method name="lightmap_set_probe_interior">
<return type="void" />
- <argument index="0" name="lightmap" type="RID" />
- <argument index="1" name="interior" type="bool" />
+ <param index="0" name="lightmap" type="RID" />
+ <param index="1" name="interior" type="bool" />
<description>
</description>
</method>
<method name="lightmap_set_textures">
<return type="void" />
- <argument index="0" name="lightmap" type="RID" />
- <argument index="1" name="light" type="RID" />
- <argument index="2" name="uses_sh" type="bool" />
+ <param index="0" name="lightmap" type="RID" />
+ <param index="1" name="light" type="RID" />
+ <param index="2" name="uses_sh" type="bool" />
<description>
</description>
</method>
<method name="make_sphere_mesh">
<return type="RID" />
- <argument index="0" name="latitudes" type="int" />
- <argument index="1" name="longitudes" type="int" />
- <argument index="2" name="radius" type="float" />
+ <param index="0" name="latitudes" type="int" />
+ <param index="1" name="longitudes" type="int" />
+ <param index="2" name="radius" type="float" />
<description>
- Returns a mesh of a sphere with the given amount of horizontal and vertical subdivisions.
+ Returns a mesh of a sphere with the given number of horizontal and vertical subdivisions.
</description>
</method>
<method name="material_create">
@@ -1813,66 +1823,66 @@
</method>
<method name="material_get_param" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="material" type="RID" />
- <argument index="1" name="parameter" type="StringName" />
+ <param index="0" name="material" type="RID" />
+ <param index="1" name="parameter" type="StringName" />
<description>
Returns the value of a certain material's parameter.
</description>
</method>
<method name="material_set_next_pass">
<return type="void" />
- <argument index="0" name="material" type="RID" />
- <argument index="1" name="next_material" type="RID" />
+ <param index="0" name="material" type="RID" />
+ <param index="1" name="next_material" type="RID" />
<description>
Sets an object's next material.
</description>
</method>
<method name="material_set_param">
<return type="void" />
- <argument index="0" name="material" type="RID" />
- <argument index="1" name="parameter" type="StringName" />
- <argument index="2" name="value" type="Variant" />
+ <param index="0" name="material" type="RID" />
+ <param index="1" name="parameter" type="StringName" />
+ <param index="2" name="value" type="Variant" />
<description>
Sets a material's parameter.
</description>
</method>
<method name="material_set_render_priority">
<return type="void" />
- <argument index="0" name="material" type="RID" />
- <argument index="1" name="priority" type="int" />
+ <param index="0" name="material" type="RID" />
+ <param index="1" name="priority" type="int" />
<description>
Sets a material's render priority.
</description>
</method>
<method name="material_set_shader">
<return type="void" />
- <argument index="0" name="shader_material" type="RID" />
- <argument index="1" name="shader" type="RID" />
+ <param index="0" name="shader_material" type="RID" />
+ <param index="1" name="shader" type="RID" />
<description>
Sets a shader material's shader.
</description>
</method>
<method name="mesh_add_surface">
<return type="void" />
- <argument index="0" name="mesh" type="RID" />
- <argument index="1" name="surface" type="Dictionary" />
+ <param index="0" name="mesh" type="RID" />
+ <param index="1" name="surface" type="Dictionary" />
<description>
</description>
</method>
<method name="mesh_add_surface_from_arrays">
<return type="void" />
- <argument index="0" name="mesh" type="RID" />
- <argument index="1" name="primitive" type="int" enum="RenderingServer.PrimitiveType" />
- <argument index="2" name="arrays" type="Array" />
- <argument index="3" name="blend_shapes" type="Array" default="[]" />
- <argument index="4" name="lods" type="Dictionary" default="{}" />
- <argument index="5" name="compress_format" type="int" default="0" />
+ <param index="0" name="mesh" type="RID" />
+ <param index="1" name="primitive" type="int" enum="RenderingServer.PrimitiveType" />
+ <param index="2" name="arrays" type="Array" />
+ <param index="3" name="blend_shapes" type="Array" default="[]" />
+ <param index="4" name="lods" type="Dictionary" default="{}" />
+ <param index="5" name="compress_format" type="int" default="0" />
<description>
</description>
</method>
<method name="mesh_clear">
<return type="void" />
- <argument index="0" name="mesh" type="RID" />
+ <param index="0" name="mesh" type="RID" />
<description>
Removes all surfaces from a mesh.
</description>
@@ -1887,165 +1897,165 @@
</method>
<method name="mesh_create_from_surfaces">
<return type="RID" />
- <argument index="0" name="surfaces" type="Dictionary[]" />
- <argument index="1" name="blend_shape_count" type="int" default="0" />
+ <param index="0" name="surfaces" type="Dictionary[]" />
+ <param index="1" name="blend_shape_count" type="int" default="0" />
<description>
</description>
</method>
<method name="mesh_get_blend_shape_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="mesh" type="RID" />
+ <param index="0" name="mesh" type="RID" />
<description>
Returns a mesh's blend shape count.
</description>
</method>
<method name="mesh_get_blend_shape_mode" qualifiers="const">
<return type="int" enum="RenderingServer.BlendShapeMode" />
- <argument index="0" name="mesh" type="RID" />
+ <param index="0" name="mesh" type="RID" />
<description>
Returns a mesh's blend shape mode.
</description>
</method>
<method name="mesh_get_custom_aabb" qualifiers="const">
<return type="AABB" />
- <argument index="0" name="mesh" type="RID" />
+ <param index="0" name="mesh" type="RID" />
<description>
Returns a mesh's custom aabb.
</description>
</method>
<method name="mesh_get_surface">
<return type="Dictionary" />
- <argument index="0" name="mesh" type="RID" />
- <argument index="1" name="surface" type="int" />
+ <param index="0" name="mesh" type="RID" />
+ <param index="1" name="surface" type="int" />
<description>
</description>
</method>
<method name="mesh_get_surface_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="mesh" type="RID" />
+ <param index="0" name="mesh" type="RID" />
<description>
Returns a mesh's number of surfaces.
</description>
</method>
<method name="mesh_set_blend_shape_mode">
<return type="void" />
- <argument index="0" name="mesh" type="RID" />
- <argument index="1" name="mode" type="int" enum="RenderingServer.BlendShapeMode" />
+ <param index="0" name="mesh" type="RID" />
+ <param index="1" name="mode" type="int" enum="RenderingServer.BlendShapeMode" />
<description>
Sets a mesh's blend shape mode.
</description>
</method>
<method name="mesh_set_custom_aabb">
<return type="void" />
- <argument index="0" name="mesh" type="RID" />
- <argument index="1" name="aabb" type="AABB" />
+ <param index="0" name="mesh" type="RID" />
+ <param index="1" name="aabb" type="AABB" />
<description>
Sets a mesh's custom aabb.
</description>
</method>
<method name="mesh_set_shadow_mesh">
<return type="void" />
- <argument index="0" name="mesh" type="RID" />
- <argument index="1" name="shadow_mesh" type="RID" />
+ <param index="0" name="mesh" type="RID" />
+ <param index="1" name="shadow_mesh" type="RID" />
<description>
</description>
</method>
<method name="mesh_surface_get_arrays" qualifiers="const">
<return type="Array" />
- <argument index="0" name="mesh" type="RID" />
- <argument index="1" name="surface" type="int" />
+ <param index="0" name="mesh" type="RID" />
+ <param index="1" name="surface" type="int" />
<description>
Returns a mesh's surface's buffer arrays.
</description>
</method>
<method name="mesh_surface_get_blend_shape_arrays" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="mesh" type="RID" />
- <argument index="1" name="surface" type="int" />
+ <return type="Array[]" />
+ <param index="0" name="mesh" type="RID" />
+ <param index="1" name="surface" type="int" />
<description>
Returns a mesh's surface's arrays for blend shapes.
</description>
</method>
<method name="mesh_surface_get_format_attribute_stride" qualifiers="const">
<return type="int" />
- <argument index="0" name="format" type="int" />
- <argument index="1" name="vertex_count" type="int" />
+ <param index="0" name="format" type="int" />
+ <param index="1" name="vertex_count" type="int" />
<description>
</description>
</method>
<method name="mesh_surface_get_format_offset" qualifiers="const">
<return type="int" />
- <argument index="0" name="format" type="int" />
- <argument index="1" name="vertex_count" type="int" />
- <argument index="2" name="array_index" type="int" />
+ <param index="0" name="format" type="int" />
+ <param index="1" name="vertex_count" type="int" />
+ <param index="2" name="array_index" type="int" />
<description>
</description>
</method>
<method name="mesh_surface_get_format_skin_stride" qualifiers="const">
<return type="int" />
- <argument index="0" name="format" type="int" />
- <argument index="1" name="vertex_count" type="int" />
+ <param index="0" name="format" type="int" />
+ <param index="1" name="vertex_count" type="int" />
<description>
</description>
</method>
<method name="mesh_surface_get_format_vertex_stride" qualifiers="const">
<return type="int" />
- <argument index="0" name="format" type="int" />
- <argument index="1" name="vertex_count" type="int" />
+ <param index="0" name="format" type="int" />
+ <param index="1" name="vertex_count" type="int" />
<description>
</description>
</method>
<method name="mesh_surface_get_material" qualifiers="const">
<return type="RID" />
- <argument index="0" name="mesh" type="RID" />
- <argument index="1" name="surface" type="int" />
+ <param index="0" name="mesh" type="RID" />
+ <param index="1" name="surface" type="int" />
<description>
Returns a mesh's surface's material.
</description>
</method>
<method name="mesh_surface_set_material">
<return type="void" />
- <argument index="0" name="mesh" type="RID" />
- <argument index="1" name="surface" type="int" />
- <argument index="2" name="material" type="RID" />
+ <param index="0" name="mesh" type="RID" />
+ <param index="1" name="surface" type="int" />
+ <param index="2" name="material" type="RID" />
<description>
Sets a mesh's surface's material.
</description>
</method>
<method name="mesh_surface_update_attribute_region">
<return type="void" />
- <argument index="0" name="mesh" type="RID" />
- <argument index="1" name="surface" type="int" />
- <argument index="2" name="offset" type="int" />
- <argument index="3" name="data" type="PackedByteArray" />
+ <param index="0" name="mesh" type="RID" />
+ <param index="1" name="surface" type="int" />
+ <param index="2" name="offset" type="int" />
+ <param index="3" name="data" type="PackedByteArray" />
<description>
</description>
</method>
<method name="mesh_surface_update_skin_region">
<return type="void" />
- <argument index="0" name="mesh" type="RID" />
- <argument index="1" name="surface" type="int" />
- <argument index="2" name="offset" type="int" />
- <argument index="3" name="data" type="PackedByteArray" />
+ <param index="0" name="mesh" type="RID" />
+ <param index="1" name="surface" type="int" />
+ <param index="2" name="offset" type="int" />
+ <param index="3" name="data" type="PackedByteArray" />
<description>
</description>
</method>
<method name="mesh_surface_update_vertex_region">
<return type="void" />
- <argument index="0" name="mesh" type="RID" />
- <argument index="1" name="surface" type="int" />
- <argument index="2" name="offset" type="int" />
- <argument index="3" name="data" type="PackedByteArray" />
+ <param index="0" name="mesh" type="RID" />
+ <param index="1" name="surface" type="int" />
+ <param index="2" name="offset" type="int" />
+ <param index="3" name="data" type="PackedByteArray" />
<description>
</description>
</method>
<method name="multimesh_allocate_data">
<return type="void" />
- <argument index="0" name="multimesh" type="RID" />
- <argument index="1" name="instances" type="int" />
- <argument index="2" name="transform_format" type="int" enum="RenderingServer.MultimeshTransformFormat" />
- <argument index="3" name="color_format" type="bool" default="false" />
- <argument index="4" name="custom_data_format" type="bool" default="false" />
+ <param index="0" name="multimesh" type="RID" />
+ <param index="1" name="instances" type="int" />
+ <param index="2" name="transform_format" type="int" enum="RenderingServer.MultimeshTransformFormat" />
+ <param index="3" name="color_format" type="bool" default="false" />
+ <param index="4" name="custom_data_format" type="bool" default="false" />
<description>
</description>
</method>
@@ -2059,125 +2069,125 @@
</method>
<method name="multimesh_get_aabb" qualifiers="const">
<return type="AABB" />
- <argument index="0" name="multimesh" type="RID" />
+ <param index="0" name="multimesh" type="RID" />
<description>
Calculates and returns the axis-aligned bounding box that encloses all instances within the multimesh.
</description>
</method>
<method name="multimesh_get_buffer" qualifiers="const">
<return type="PackedFloat32Array" />
- <argument index="0" name="multimesh" type="RID" />
+ <param index="0" name="multimesh" type="RID" />
<description>
</description>
</method>
<method name="multimesh_get_instance_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="multimesh" type="RID" />
+ <param index="0" name="multimesh" type="RID" />
<description>
Returns the number of instances allocated for this multimesh.
</description>
</method>
<method name="multimesh_get_mesh" qualifiers="const">
<return type="RID" />
- <argument index="0" name="multimesh" type="RID" />
+ <param index="0" name="multimesh" type="RID" />
<description>
Returns the RID of the mesh that will be used in drawing this multimesh.
</description>
</method>
<method name="multimesh_get_visible_instances" qualifiers="const">
<return type="int" />
- <argument index="0" name="multimesh" type="RID" />
+ <param index="0" name="multimesh" type="RID" />
<description>
Returns the number of visible instances for this multimesh.
</description>
</method>
<method name="multimesh_instance_get_color" qualifiers="const">
<return type="Color" />
- <argument index="0" name="multimesh" type="RID" />
- <argument index="1" name="index" type="int" />
+ <param index="0" name="multimesh" type="RID" />
+ <param index="1" name="index" type="int" />
<description>
Returns the color by which the specified instance will be modulated.
</description>
</method>
<method name="multimesh_instance_get_custom_data" qualifiers="const">
<return type="Color" />
- <argument index="0" name="multimesh" type="RID" />
- <argument index="1" name="index" type="int" />
+ <param index="0" name="multimesh" type="RID" />
+ <param index="1" name="index" type="int" />
<description>
Returns the custom data associated with the specified instance.
</description>
</method>
<method name="multimesh_instance_get_transform" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="multimesh" type="RID" />
- <argument index="1" name="index" type="int" />
+ <param index="0" name="multimesh" type="RID" />
+ <param index="1" name="index" type="int" />
<description>
Returns the [Transform3D] of the specified instance.
</description>
</method>
<method name="multimesh_instance_get_transform_2d" qualifiers="const">
<return type="Transform2D" />
- <argument index="0" name="multimesh" type="RID" />
- <argument index="1" name="index" type="int" />
+ <param index="0" name="multimesh" type="RID" />
+ <param index="1" name="index" type="int" />
<description>
Returns the [Transform2D] of the specified instance. For use when the multimesh is set to use 2D transforms.
</description>
</method>
<method name="multimesh_instance_set_color">
<return type="void" />
- <argument index="0" name="multimesh" type="RID" />
- <argument index="1" name="index" type="int" />
- <argument index="2" name="color" type="Color" />
+ <param index="0" name="multimesh" type="RID" />
+ <param index="1" name="index" type="int" />
+ <param index="2" name="color" type="Color" />
<description>
Sets the color by which this instance will be modulated. Equivalent to [method MultiMesh.set_instance_color].
</description>
</method>
<method name="multimesh_instance_set_custom_data">
<return type="void" />
- <argument index="0" name="multimesh" type="RID" />
- <argument index="1" name="index" type="int" />
- <argument index="2" name="custom_data" type="Color" />
+ <param index="0" name="multimesh" type="RID" />
+ <param index="1" name="index" type="int" />
+ <param index="2" name="custom_data" type="Color" />
<description>
Sets the custom data for this instance. Custom data is passed as a [Color], but is interpreted as a [code]vec4[/code] in the shader. Equivalent to [method MultiMesh.set_instance_custom_data].
</description>
</method>
<method name="multimesh_instance_set_transform">
<return type="void" />
- <argument index="0" name="multimesh" type="RID" />
- <argument index="1" name="index" type="int" />
- <argument index="2" name="transform" type="Transform3D" />
+ <param index="0" name="multimesh" type="RID" />
+ <param index="1" name="index" type="int" />
+ <param index="2" name="transform" type="Transform3D" />
<description>
Sets the [Transform3D] for this instance. Equivalent to [method MultiMesh.set_instance_transform].
</description>
</method>
<method name="multimesh_instance_set_transform_2d">
<return type="void" />
- <argument index="0" name="multimesh" type="RID" />
- <argument index="1" name="index" type="int" />
- <argument index="2" name="transform" type="Transform2D" />
+ <param index="0" name="multimesh" type="RID" />
+ <param index="1" name="index" type="int" />
+ <param index="2" name="transform" type="Transform2D" />
<description>
Sets the [Transform2D] for this instance. For use when multimesh is used in 2D. Equivalent to [method MultiMesh.set_instance_transform_2d].
</description>
</method>
<method name="multimesh_set_buffer">
<return type="void" />
- <argument index="0" name="multimesh" type="RID" />
- <argument index="1" name="buffer" type="PackedFloat32Array" />
+ <param index="0" name="multimesh" type="RID" />
+ <param index="1" name="buffer" type="PackedFloat32Array" />
<description>
</description>
</method>
<method name="multimesh_set_mesh">
<return type="void" />
- <argument index="0" name="multimesh" type="RID" />
- <argument index="1" name="mesh" type="RID" />
+ <param index="0" name="multimesh" type="RID" />
+ <param index="1" name="mesh" type="RID" />
<description>
Sets the mesh to be drawn by the multimesh. Equivalent to [member MultiMesh.mesh].
</description>
</method>
<method name="multimesh_set_visible_instances">
<return type="void" />
- <argument index="0" name="multimesh" type="RID" />
- <argument index="1" name="visible" type="int" />
+ <param index="0" name="multimesh" type="RID" />
+ <param index="1" name="visible" type="int" />
<description>
Sets the number of instances visible at a given time. If -1, all instances that have been allocated are drawn. Equivalent to [member MultiMesh.visible_instance_count].
</description>
@@ -2189,9 +2199,9 @@
</method>
<method name="occluder_set_mesh">
<return type="void" />
- <argument index="0" name="occluder" type="RID" />
- <argument index="1" name="vertices" type="PackedVector3Array" />
- <argument index="2" name="indices" type="PackedInt32Array" />
+ <param index="0" name="occluder" type="RID" />
+ <param index="1" name="vertices" type="PackedVector3Array" />
+ <param index="2" name="indices" type="PackedInt32Array" />
<description>
</description>
</method>
@@ -2210,70 +2220,70 @@
</method>
<method name="particles_collision_height_field_update">
<return type="void" />
- <argument index="0" name="particles_collision" type="RID" />
+ <param index="0" name="particles_collision" type="RID" />
<description>
</description>
</method>
<method name="particles_collision_set_attractor_attenuation">
<return type="void" />
- <argument index="0" name="particles_collision" type="RID" />
- <argument index="1" name="curve" type="float" />
+ <param index="0" name="particles_collision" type="RID" />
+ <param index="1" name="curve" type="float" />
<description>
</description>
</method>
<method name="particles_collision_set_attractor_directionality">
<return type="void" />
- <argument index="0" name="particles_collision" type="RID" />
- <argument index="1" name="amount" type="float" />
+ <param index="0" name="particles_collision" type="RID" />
+ <param index="1" name="amount" type="float" />
<description>
</description>
</method>
<method name="particles_collision_set_attractor_strength">
<return type="void" />
- <argument index="0" name="particles_collision" type="RID" />
- <argument index="1" name="setrngth" type="float" />
+ <param index="0" name="particles_collision" type="RID" />
+ <param index="1" name="setrngth" type="float" />
<description>
</description>
</method>
<method name="particles_collision_set_box_extents">
<return type="void" />
- <argument index="0" name="particles_collision" type="RID" />
- <argument index="1" name="extents" type="Vector3" />
+ <param index="0" name="particles_collision" type="RID" />
+ <param index="1" name="extents" type="Vector3" />
<description>
</description>
</method>
<method name="particles_collision_set_collision_type">
<return type="void" />
- <argument index="0" name="particles_collision" type="RID" />
- <argument index="1" name="type" type="int" enum="RenderingServer.ParticlesCollisionType" />
+ <param index="0" name="particles_collision" type="RID" />
+ <param index="1" name="type" type="int" enum="RenderingServer.ParticlesCollisionType" />
<description>
</description>
</method>
<method name="particles_collision_set_cull_mask">
<return type="void" />
- <argument index="0" name="particles_collision" type="RID" />
- <argument index="1" name="mask" type="int" />
+ <param index="0" name="particles_collision" type="RID" />
+ <param index="1" name="mask" type="int" />
<description>
</description>
</method>
<method name="particles_collision_set_field_texture">
<return type="void" />
- <argument index="0" name="particles_collision" type="RID" />
- <argument index="1" name="texture" type="RID" />
+ <param index="0" name="particles_collision" type="RID" />
+ <param index="1" name="texture" type="RID" />
<description>
</description>
</method>
<method name="particles_collision_set_height_field_resolution">
<return type="void" />
- <argument index="0" name="particles_collision" type="RID" />
- <argument index="1" name="resolution" type="int" enum="RenderingServer.ParticlesCollisionHeightfieldResolution" />
+ <param index="0" name="particles_collision" type="RID" />
+ <param index="1" name="resolution" type="int" enum="RenderingServer.ParticlesCollisionHeightfieldResolution" />
<description>
</description>
</method>
<method name="particles_collision_set_sphere_radius">
<return type="void" />
- <argument index="0" name="particles_collision" type="RID" />
- <argument index="1" name="radius" type="float" />
+ <param index="0" name="particles_collision" type="RID" />
+ <param index="1" name="radius" type="float" />
<description>
</description>
</method>
@@ -2287,180 +2297,180 @@
</method>
<method name="particles_emit">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="transform" type="Transform3D" />
- <argument index="2" name="velocity" type="Vector3" />
- <argument index="3" name="color" type="Color" />
- <argument index="4" name="custom" type="Color" />
- <argument index="5" name="emit_flags" type="int" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="transform" type="Transform3D" />
+ <param index="2" name="velocity" type="Vector3" />
+ <param index="3" name="color" type="Color" />
+ <param index="4" name="custom" type="Color" />
+ <param index="5" name="emit_flags" type="int" />
<description>
</description>
</method>
<method name="particles_get_current_aabb">
<return type="AABB" />
- <argument index="0" name="particles" type="RID" />
+ <param index="0" name="particles" type="RID" />
<description>
Calculates and returns the axis-aligned bounding box that contains all the particles. Equivalent to [method GPUParticles3D.capture_aabb].
</description>
</method>
<method name="particles_get_emitting">
<return type="bool" />
- <argument index="0" name="particles" type="RID" />
+ <param index="0" name="particles" type="RID" />
<description>
Returns [code]true[/code] if particles are currently set to emitting.
</description>
</method>
<method name="particles_is_inactive">
<return type="bool" />
- <argument index="0" name="particles" type="RID" />
+ <param index="0" name="particles" type="RID" />
<description>
Returns [code]true[/code] if particles are not emitting and particles are set to inactive.
</description>
</method>
<method name="particles_request_process">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
+ <param index="0" name="particles" type="RID" />
<description>
Add particle system to list of particle systems that need to be updated. Update will take place on the next frame, or on the next call to [method instances_cull_aabb], [method instances_cull_convex], or [method instances_cull_ray].
</description>
</method>
<method name="particles_restart">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
+ <param index="0" name="particles" type="RID" />
<description>
Reset the particles on the next update. Equivalent to [method GPUParticles3D.restart].
</description>
</method>
<method name="particles_set_amount">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="amount" type="int" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="amount" type="int" />
<description>
Sets the number of particles to be drawn and allocates the memory for them. Equivalent to [member GPUParticles3D.amount].
</description>
</method>
<method name="particles_set_collision_base_size">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="size" type="float" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="size" type="float" />
<description>
</description>
</method>
<method name="particles_set_custom_aabb">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="aabb" type="AABB" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="aabb" type="AABB" />
<description>
Sets a custom axis-aligned bounding box for the particle system. Equivalent to [member GPUParticles3D.visibility_aabb].
</description>
</method>
<method name="particles_set_draw_order">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="order" type="int" enum="RenderingServer.ParticlesDrawOrder" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="order" type="int" enum="RenderingServer.ParticlesDrawOrder" />
<description>
Sets the draw order of the particles to one of the named enums from [enum ParticlesDrawOrder]. See [enum ParticlesDrawOrder] for options. Equivalent to [member GPUParticles3D.draw_order].
</description>
</method>
<method name="particles_set_draw_pass_mesh">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="pass" type="int" />
- <argument index="2" name="mesh" type="RID" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="pass" type="int" />
+ <param index="2" name="mesh" type="RID" />
<description>
Sets the mesh to be used for the specified draw pass. Equivalent to [member GPUParticles3D.draw_pass_1], [member GPUParticles3D.draw_pass_2], [member GPUParticles3D.draw_pass_3], and [member GPUParticles3D.draw_pass_4].
</description>
</method>
<method name="particles_set_draw_passes">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="count" type="int" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="count" type="int" />
<description>
Sets the number of draw passes to use. Equivalent to [member GPUParticles3D.draw_passes].
</description>
</method>
<method name="particles_set_emission_transform">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="transform" type="Transform3D" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="transform" type="Transform3D" />
<description>
Sets the [Transform3D] that will be used by the particles when they first emit.
</description>
</method>
<method name="particles_set_emitting">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="emitting" type="bool" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="emitting" type="bool" />
<description>
If [code]true[/code], particles will emit over time. Setting to false does not reset the particles, but only stops their emission. Equivalent to [member GPUParticles3D.emitting].
</description>
</method>
<method name="particles_set_explosiveness_ratio">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="ratio" type="float" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="ratio" type="float" />
<description>
Sets the explosiveness ratio. Equivalent to [member GPUParticles3D.explosiveness].
</description>
</method>
<method name="particles_set_fixed_fps">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="fps" type="int" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="fps" type="int" />
<description>
Sets the frame rate that the particle system rendering will be fixed to. Equivalent to [member GPUParticles3D.fixed_fps].
</description>
</method>
<method name="particles_set_fractional_delta">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
If [code]true[/code], uses fractional delta which smooths the movement of the particles. Equivalent to [member GPUParticles3D.fract_delta].
</description>
</method>
<method name="particles_set_interpolate">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
</description>
</method>
<method name="particles_set_lifetime">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="lifetime" type="float" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="lifetime" type="float" />
<description>
Sets the lifetime of each particle in the system. Equivalent to [member GPUParticles3D.lifetime].
</description>
</method>
<method name="particles_set_mode">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="mode" type="int" enum="RenderingServer.ParticlesMode" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="mode" type="int" enum="RenderingServer.ParticlesMode" />
<description>
</description>
</method>
<method name="particles_set_one_shot">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="one_shot" type="bool" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="one_shot" type="bool" />
<description>
If [code]true[/code], particles will emit once and then stop. Equivalent to [member GPUParticles3D.one_shot].
</description>
</method>
<method name="particles_set_pre_process_time">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="time" type="float" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="time" type="float" />
<description>
Sets the preprocess time for the particles' animation. This lets you delay starting an animation until after the particles have begun emitting. Equivalent to [member GPUParticles3D.preprocess].
</description>
</method>
<method name="particles_set_process_material">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="material" type="RID" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="material" type="RID" />
<description>
Sets the material for processing the particles.
[b]Note:[/b] This is not the material used to draw the materials. Equivalent to [member GPUParticles3D.process_material].
@@ -2468,60 +2478,60 @@
</method>
<method name="particles_set_randomness_ratio">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="ratio" type="float" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="ratio" type="float" />
<description>
Sets the emission randomness ratio. This randomizes the emission of particles within their phase. Equivalent to [member GPUParticles3D.randomness].
</description>
</method>
<method name="particles_set_speed_scale">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="scale" type="float" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="scale" type="float" />
<description>
Sets the speed scale of the particle system. Equivalent to [member GPUParticles3D.speed_scale].
</description>
</method>
<method name="particles_set_subemitter">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="subemitter_particles" type="RID" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="subemitter_particles" type="RID" />
<description>
</description>
</method>
<method name="particles_set_trail_bind_poses">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="bind_poses" type="Transform3D[]" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="bind_poses" type="Transform3D[]" />
<description>
</description>
</method>
<method name="particles_set_trails">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="enable" type="bool" />
- <argument index="2" name="length_sec" type="float" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="enable" type="bool" />
+ <param index="2" name="length_sec" type="float" />
<description>
</description>
</method>
<method name="particles_set_transform_align">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="align" type="int" enum="RenderingServer.ParticlesTransformAlign" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="align" type="int" enum="RenderingServer.ParticlesTransformAlign" />
<description>
</description>
</method>
<method name="particles_set_use_local_coordinates">
<return type="void" />
- <argument index="0" name="particles" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="particles" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
If [code]true[/code], particles use local coordinates. If [code]false[/code] they use global coordinates. Equivalent to [member GPUParticles3D.local_coords].
</description>
</method>
<method name="positional_soft_shadow_filter_set_quality">
<return type="void" />
- <argument index="0" name="quality" type="int" enum="RenderingServer.ShadowQuality" />
+ <param index="0" name="quality" type="int" enum="RenderingServer.ShadowQuality" />
<description>
</description>
</method>
@@ -2535,114 +2545,114 @@
</method>
<method name="reflection_probe_set_ambient_color">
<return type="void" />
- <argument index="0" name="probe" type="RID" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="probe" type="RID" />
+ <param index="1" name="color" type="Color" />
<description>
</description>
</method>
<method name="reflection_probe_set_ambient_energy">
<return type="void" />
- <argument index="0" name="probe" type="RID" />
- <argument index="1" name="energy" type="float" />
+ <param index="0" name="probe" type="RID" />
+ <param index="1" name="energy" type="float" />
<description>
</description>
</method>
<method name="reflection_probe_set_ambient_mode">
<return type="void" />
- <argument index="0" name="probe" type="RID" />
- <argument index="1" name="mode" type="int" enum="RenderingServer.ReflectionProbeAmbientMode" />
+ <param index="0" name="probe" type="RID" />
+ <param index="1" name="mode" type="int" enum="RenderingServer.ReflectionProbeAmbientMode" />
<description>
</description>
</method>
<method name="reflection_probe_set_as_interior">
<return type="void" />
- <argument index="0" name="probe" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="probe" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
If [code]true[/code], reflections will ignore sky contribution. Equivalent to [member ReflectionProbe.interior].
</description>
</method>
<method name="reflection_probe_set_cull_mask">
<return type="void" />
- <argument index="0" name="probe" type="RID" />
- <argument index="1" name="layers" type="int" />
+ <param index="0" name="probe" type="RID" />
+ <param index="1" name="layers" type="int" />
<description>
Sets the render cull mask for this reflection probe. Only instances with a matching cull mask will be rendered by this probe. Equivalent to [member ReflectionProbe.cull_mask].
</description>
</method>
<method name="reflection_probe_set_enable_box_projection">
<return type="void" />
- <argument index="0" name="probe" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="probe" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
If [code]true[/code], uses box projection. This can make reflections look more correct in certain situations. Equivalent to [member ReflectionProbe.box_projection].
</description>
</method>
<method name="reflection_probe_set_enable_shadows">
<return type="void" />
- <argument index="0" name="probe" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="probe" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
If [code]true[/code], computes shadows in the reflection probe. This makes the reflection much slower to compute. Equivalent to [member ReflectionProbe.enable_shadows].
</description>
</method>
<method name="reflection_probe_set_extents">
<return type="void" />
- <argument index="0" name="probe" type="RID" />
- <argument index="1" name="extents" type="Vector3" />
+ <param index="0" name="probe" type="RID" />
+ <param index="1" name="extents" type="Vector3" />
<description>
Sets the size of the area that the reflection probe will capture. Equivalent to [member ReflectionProbe.extents].
</description>
</method>
<method name="reflection_probe_set_intensity">
<return type="void" />
- <argument index="0" name="probe" type="RID" />
- <argument index="1" name="intensity" type="float" />
+ <param index="0" name="probe" type="RID" />
+ <param index="1" name="intensity" type="float" />
<description>
Sets the intensity of the reflection probe. Intensity modulates the strength of the reflection. Equivalent to [member ReflectionProbe.intensity].
</description>
</method>
<method name="reflection_probe_set_max_distance">
<return type="void" />
- <argument index="0" name="probe" type="RID" />
- <argument index="1" name="distance" type="float" />
+ <param index="0" name="probe" type="RID" />
+ <param index="1" name="distance" type="float" />
<description>
Sets the max distance away from the probe an object can be before it is culled. Equivalent to [member ReflectionProbe.max_distance].
</description>
</method>
<method name="reflection_probe_set_mesh_lod_threshold">
<return type="void" />
- <argument index="0" name="probe" type="RID" />
- <argument index="1" name="pixels" type="float" />
+ <param index="0" name="probe" type="RID" />
+ <param index="1" name="pixels" type="float" />
<description>
</description>
</method>
<method name="reflection_probe_set_origin_offset">
<return type="void" />
- <argument index="0" name="probe" type="RID" />
- <argument index="1" name="offset" type="Vector3" />
+ <param index="0" name="probe" type="RID" />
+ <param index="1" name="offset" type="Vector3" />
<description>
Sets the origin offset to be used when this reflection probe is in box project mode. Equivalent to [member ReflectionProbe.origin_offset].
</description>
</method>
<method name="reflection_probe_set_resolution">
<return type="void" />
- <argument index="0" name="probe" type="RID" />
- <argument index="1" name="resolution" type="int" />
+ <param index="0" name="probe" type="RID" />
+ <param index="1" name="resolution" type="int" />
<description>
</description>
</method>
<method name="reflection_probe_set_update_mode">
<return type="void" />
- <argument index="0" name="probe" type="RID" />
- <argument index="1" name="mode" type="int" enum="RenderingServer.ReflectionProbeUpdateMode" />
+ <param index="0" name="probe" type="RID" />
+ <param index="1" name="mode" type="int" enum="RenderingServer.ReflectionProbeUpdateMode" />
<description>
Sets how often the reflection probe updates. Can either be once or every frame. See [enum ReflectionProbeUpdateMode] for options.
</description>
</method>
<method name="request_frame_drawn_callback">
<return type="void" />
- <argument index="0" name="callable" type="Callable" />
+ <param index="0" name="callable" type="Callable" />
<description>
Schedules a callback to the given callable after a frame has been drawn.
</description>
@@ -2657,55 +2667,55 @@
</method>
<method name="scenario_set_camera_effects">
<return type="void" />
- <argument index="0" name="scenario" type="RID" />
- <argument index="1" name="effects" type="RID" />
+ <param index="0" name="scenario" type="RID" />
+ <param index="1" name="effects" type="RID" />
<description>
</description>
</method>
<method name="scenario_set_environment">
<return type="void" />
- <argument index="0" name="scenario" type="RID" />
- <argument index="1" name="environment" type="RID" />
+ <param index="0" name="scenario" type="RID" />
+ <param index="1" name="environment" type="RID" />
<description>
Sets the environment that will be used with this scenario.
</description>
</method>
<method name="scenario_set_fallback_environment">
<return type="void" />
- <argument index="0" name="scenario" type="RID" />
- <argument index="1" name="environment" type="RID" />
+ <param index="0" name="scenario" type="RID" />
+ <param index="1" name="environment" type="RID" />
<description>
Sets the fallback environment to be used by this scenario. The fallback environment is used if no environment is set. Internally, this is used by the editor to provide a default environment.
</description>
</method>
<method name="screen_space_roughness_limiter_set_active">
<return type="void" />
- <argument index="0" name="enable" type="bool" />
- <argument index="1" name="amount" type="float" />
- <argument index="2" name="limit" type="float" />
+ <param index="0" name="enable" type="bool" />
+ <param index="1" name="amount" type="float" />
+ <param index="2" name="limit" type="float" />
<description>
</description>
</method>
<method name="set_boot_image">
<return type="void" />
- <argument index="0" name="image" type="Image" />
- <argument index="1" name="color" type="Color" />
- <argument index="2" name="scale" type="bool" />
- <argument index="3" name="use_filter" type="bool" default="true" />
+ <param index="0" name="image" type="Image" />
+ <param index="1" name="color" type="Color" />
+ <param index="2" name="scale" type="bool" />
+ <param index="3" name="use_filter" type="bool" default="true" />
<description>
- Sets a boot image. The color defines the background color. If [code]scale[/code] is [code]true[/code], the image will be scaled to fit the screen size. If [code]use_filter[/code] is [code]true[/code], the image will be scaled with linear interpolation. If [code]use_filter[/code] is [code]false[/code], the image will be scaled with nearest-neighbor interpolation.
+ Sets a boot image. The color defines the background color. If [param scale] is [code]true[/code], the image will be scaled to fit the screen size. If [param use_filter] is [code]true[/code], the image will be scaled with linear interpolation. If [param use_filter] is [code]false[/code], the image will be scaled with nearest-neighbor interpolation.
</description>
</method>
<method name="set_debug_generate_wireframes">
<return type="void" />
- <argument index="0" name="generate" type="bool" />
+ <param index="0" name="generate" type="bool" />
<description>
If [code]true[/code], the engine will generate wireframes for use with the wireframe debug mode.
</description>
</method>
<method name="set_default_clear_color">
<return type="void" />
- <argument index="0" name="color" type="Color" />
+ <param index="0" name="color" type="Color" />
<description>
Sets the default clear color which is used when a specific clear color has not been selected.
</description>
@@ -2719,98 +2729,98 @@
</method>
<method name="shader_get_code" qualifiers="const">
<return type="String" />
- <argument index="0" name="shader" type="RID" />
+ <param index="0" name="shader" type="RID" />
<description>
Returns a shader's code.
</description>
</method>
<method name="shader_get_default_texture_param" qualifiers="const">
<return type="RID" />
- <argument index="0" name="shader" type="RID" />
- <argument index="1" name="param" type="StringName" />
- <argument index="2" name="index" type="int" default="0" />
+ <param index="0" name="shader" type="RID" />
+ <param index="1" name="param" type="StringName" />
+ <param index="2" name="index" type="int" default="0" />
<description>
Returns a default texture from a shader searched by name.
- [b]Note:[/b] If the sampler array is used use [code]index[/code] to access the specified texture.
+ [b]Note:[/b] If the sampler array is used use [param index] to access the specified texture.
</description>
</method>
<method name="shader_get_param_default" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="shader" type="RID" />
- <argument index="1" name="param" type="StringName" />
+ <param index="0" name="shader" type="RID" />
+ <param index="1" name="param" type="StringName" />
<description>
</description>
</method>
- <method name="shader_get_param_list" qualifiers="const">
+ <method name="shader_get_shader_uniform_list" qualifiers="const">
<return type="Dictionary[]" />
- <argument index="0" name="shader" type="RID" />
+ <param index="0" name="shader" type="RID" />
<description>
Returns the parameters of a shader.
</description>
</method>
<method name="shader_set_code">
<return type="void" />
- <argument index="0" name="shader" type="RID" />
- <argument index="1" name="code" type="String" />
+ <param index="0" name="shader" type="RID" />
+ <param index="1" name="code" type="String" />
<description>
</description>
</method>
<method name="shader_set_default_texture_param">
<return type="void" />
- <argument index="0" name="shader" type="RID" />
- <argument index="1" name="param" type="StringName" />
- <argument index="2" name="texture" type="RID" />
- <argument index="3" name="index" type="int" default="0" />
+ <param index="0" name="shader" type="RID" />
+ <param index="1" name="param" type="StringName" />
+ <param index="2" name="texture" type="RID" />
+ <param index="3" name="index" type="int" default="0" />
<description>
Sets a shader's default texture. Overwrites the texture given by name.
- [b]Note:[/b] If the sampler array is used use [code]index[/code] to access the specified texture.
+ [b]Note:[/b] If the sampler array is used use [param index] to access the specified texture.
</description>
</method>
<method name="shader_set_path_hint">
<return type="void" />
- <argument index="0" name="shader" type="RID" />
- <argument index="1" name="path" type="String" />
+ <param index="0" name="shader" type="RID" />
+ <param index="1" name="path" type="String" />
<description>
</description>
</method>
<method name="skeleton_allocate_data">
<return type="void" />
- <argument index="0" name="skeleton" type="RID" />
- <argument index="1" name="bones" type="int" />
- <argument index="2" name="is_2d_skeleton" type="bool" default="false" />
+ <param index="0" name="skeleton" type="RID" />
+ <param index="1" name="bones" type="int" />
+ <param index="2" name="is_2d_skeleton" type="bool" default="false" />
<description>
</description>
</method>
<method name="skeleton_bone_get_transform" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="skeleton" type="RID" />
- <argument index="1" name="bone" type="int" />
+ <param index="0" name="skeleton" type="RID" />
+ <param index="1" name="bone" type="int" />
<description>
Returns the [Transform3D] set for a specific bone of this skeleton.
</description>
</method>
<method name="skeleton_bone_get_transform_2d" qualifiers="const">
<return type="Transform2D" />
- <argument index="0" name="skeleton" type="RID" />
- <argument index="1" name="bone" type="int" />
+ <param index="0" name="skeleton" type="RID" />
+ <param index="1" name="bone" type="int" />
<description>
Returns the [Transform2D] set for a specific bone of this skeleton.
</description>
</method>
<method name="skeleton_bone_set_transform">
<return type="void" />
- <argument index="0" name="skeleton" type="RID" />
- <argument index="1" name="bone" type="int" />
- <argument index="2" name="transform" type="Transform3D" />
+ <param index="0" name="skeleton" type="RID" />
+ <param index="1" name="bone" type="int" />
+ <param index="2" name="transform" type="Transform3D" />
<description>
Sets the [Transform3D] for a specific bone of this skeleton.
</description>
</method>
<method name="skeleton_bone_set_transform_2d">
<return type="void" />
- <argument index="0" name="skeleton" type="RID" />
- <argument index="1" name="bone" type="int" />
- <argument index="2" name="transform" type="Transform2D" />
+ <param index="0" name="skeleton" type="RID" />
+ <param index="1" name="bone" type="int" />
+ <param index="2" name="transform" type="Transform2D" />
<description>
Sets the [Transform2D] for a specific bone of this skeleton.
</description>
@@ -2824,24 +2834,24 @@
</method>
<method name="skeleton_get_bone_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="skeleton" type="RID" />
+ <param index="0" name="skeleton" type="RID" />
<description>
Returns the number of bones allocated for this skeleton.
</description>
</method>
<method name="skeleton_set_base_transform_2d">
<return type="void" />
- <argument index="0" name="skeleton" type="RID" />
- <argument index="1" name="base_transform" type="Transform2D" />
+ <param index="0" name="skeleton" type="RID" />
+ <param index="1" name="base_transform" type="Transform2D" />
<description>
</description>
</method>
<method name="sky_bake_panorama">
<return type="Image" />
- <argument index="0" name="sky" type="RID" />
- <argument index="1" name="energy" type="float" />
- <argument index="2" name="bake_irradiance" type="bool" />
- <argument index="3" name="size" type="Vector2i" />
+ <param index="0" name="sky" type="RID" />
+ <param index="1" name="energy" type="float" />
+ <param index="2" name="bake_irradiance" type="bool" />
+ <param index="3" name="size" type="Vector2i" />
<description>
</description>
</method>
@@ -2854,23 +2864,23 @@
</method>
<method name="sky_set_material">
<return type="void" />
- <argument index="0" name="sky" type="RID" />
- <argument index="1" name="material" type="RID" />
+ <param index="0" name="sky" type="RID" />
+ <param index="1" name="material" type="RID" />
<description>
Sets the material that the sky uses to render the background and reflection maps.
</description>
</method>
<method name="sky_set_mode">
<return type="void" />
- <argument index="0" name="sky" type="RID" />
- <argument index="1" name="mode" type="int" enum="RenderingServer.SkyMode" />
+ <param index="0" name="sky" type="RID" />
+ <param index="1" name="mode" type="int" enum="RenderingServer.SkyMode" />
<description>
</description>
</method>
<method name="sky_set_radiance_size">
<return type="void" />
- <argument index="0" name="sky" type="RID" />
- <argument index="1" name="radiance_size" type="int" />
+ <param index="0" name="sky" type="RID" />
+ <param index="1" name="radiance_size" type="int" />
<description>
</description>
</method>
@@ -2884,46 +2894,46 @@
</method>
<method name="sub_surface_scattering_set_quality">
<return type="void" />
- <argument index="0" name="quality" type="int" enum="RenderingServer.SubSurfaceScatteringQuality" />
+ <param index="0" name="quality" type="int" enum="RenderingServer.SubSurfaceScatteringQuality" />
<description>
</description>
</method>
<method name="sub_surface_scattering_set_scale">
<return type="void" />
- <argument index="0" name="scale" type="float" />
- <argument index="1" name="depth_scale" type="float" />
+ <param index="0" name="scale" type="float" />
+ <param index="1" name="depth_scale" type="float" />
<description>
</description>
</method>
<method name="texture_2d_create">
<return type="RID" />
- <argument index="0" name="image" type="Image" />
+ <param index="0" name="image" type="Image" />
<description>
</description>
</method>
<method name="texture_2d_get" qualifiers="const">
<return type="Image" />
- <argument index="0" name="texture" type="RID" />
+ <param index="0" name="texture" type="RID" />
<description>
</description>
</method>
<method name="texture_2d_layer_get" qualifiers="const">
<return type="Image" />
- <argument index="0" name="texture" type="RID" />
- <argument index="1" name="layer" type="int" />
+ <param index="0" name="texture" type="RID" />
+ <param index="1" name="layer" type="int" />
<description>
</description>
</method>
<method name="texture_2d_layered_create">
<return type="RID" />
- <argument index="0" name="layers" type="Image[]" />
- <argument index="1" name="layered_type" type="int" enum="RenderingServer.TextureLayeredType" />
+ <param index="0" name="layers" type="Image[]" />
+ <param index="1" name="layered_type" type="int" enum="RenderingServer.TextureLayeredType" />
<description>
</description>
</method>
<method name="texture_2d_layered_placeholder_create">
<return type="RID" />
- <argument index="0" name="layered_type" type="int" enum="RenderingServer.TextureLayeredType" />
+ <param index="0" name="layered_type" type="int" enum="RenderingServer.TextureLayeredType" />
<description>
</description>
</method>
@@ -2934,26 +2944,26 @@
</method>
<method name="texture_2d_update">
<return type="void" />
- <argument index="0" name="texture" type="RID" />
- <argument index="1" name="image" type="Image" />
- <argument index="2" name="layer" type="int" />
+ <param index="0" name="texture" type="RID" />
+ <param index="1" name="image" type="Image" />
+ <param index="2" name="layer" type="int" />
<description>
</description>
</method>
<method name="texture_3d_create">
<return type="RID" />
- <argument index="0" name="format" type="int" enum="Image.Format" />
- <argument index="1" name="width" type="int" />
- <argument index="2" name="height" type="int" />
- <argument index="3" name="depth" type="int" />
- <argument index="4" name="mipmaps" type="bool" />
- <argument index="5" name="data" type="Image[]" />
+ <param index="0" name="format" type="int" enum="Image.Format" />
+ <param index="1" name="width" type="int" />
+ <param index="2" name="height" type="int" />
+ <param index="3" name="depth" type="int" />
+ <param index="4" name="mipmaps" type="bool" />
+ <param index="5" name="data" type="Image[]" />
<description>
</description>
</method>
<method name="texture_3d_get" qualifiers="const">
<return type="Image[]" />
- <argument index="0" name="texture" type="RID" />
+ <param index="0" name="texture" type="RID" />
<description>
</description>
</method>
@@ -2964,82 +2974,82 @@
</method>
<method name="texture_3d_update">
<return type="void" />
- <argument index="0" name="texture" type="RID" />
- <argument index="1" name="data" type="Image[]" />
+ <param index="0" name="texture" type="RID" />
+ <param index="1" name="data" type="Image[]" />
<description>
</description>
</method>
<method name="texture_get_path" qualifiers="const">
<return type="String" />
- <argument index="0" name="texture" type="RID" />
+ <param index="0" name="texture" type="RID" />
<description>
</description>
</method>
<method name="texture_proxy_create">
<return type="RID" />
- <argument index="0" name="base" type="RID" />
+ <param index="0" name="base" type="RID" />
<description>
</description>
</method>
<method name="texture_proxy_update">
<return type="void" />
- <argument index="0" name="texture" type="RID" />
- <argument index="1" name="proxy_to" type="RID" />
+ <param index="0" name="texture" type="RID" />
+ <param index="1" name="proxy_to" type="RID" />
<description>
</description>
</method>
<method name="texture_replace">
<return type="void" />
- <argument index="0" name="texture" type="RID" />
- <argument index="1" name="by_texture" type="RID" />
+ <param index="0" name="texture" type="RID" />
+ <param index="1" name="by_texture" type="RID" />
<description>
</description>
</method>
<method name="texture_set_force_redraw_if_visible">
<return type="void" />
- <argument index="0" name="texture" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="texture" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
</description>
</method>
<method name="texture_set_path">
<return type="void" />
- <argument index="0" name="texture" type="RID" />
- <argument index="1" name="path" type="String" />
+ <param index="0" name="texture" type="RID" />
+ <param index="1" name="path" type="String" />
<description>
</description>
</method>
<method name="texture_set_size_override">
<return type="void" />
- <argument index="0" name="texture" type="RID" />
- <argument index="1" name="width" type="int" />
- <argument index="2" name="height" type="int" />
+ <param index="0" name="texture" type="RID" />
+ <param index="1" name="width" type="int" />
+ <param index="2" name="height" type="int" />
<description>
</description>
</method>
<method name="viewport_attach_camera">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="camera" type="RID" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="camera" type="RID" />
<description>
Sets a viewport's camera.
</description>
</method>
<method name="viewport_attach_canvas">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="canvas" type="RID" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="canvas" type="RID" />
<description>
Sets a viewport's canvas.
</description>
</method>
<method name="viewport_attach_to_screen">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="rect" type="Rect2" default="Rect2(0, 0, 0, 0)" />
- <argument index="2" name="screen" type="int" default="0" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="rect" type="Rect2" default="Rect2(0, 0, 0, 0)" />
+ <param index="2" name="screen" type="int" default="0" />
<description>
- Copies the viewport to a region of the screen specified by [code]rect[/code]. If [method viewport_set_render_direct_to_screen] is [code]true[/code], then the viewport does not use a framebuffer and the contents of the viewport are rendered directly to screen. However, note that the root viewport is drawn last, therefore it will draw over the screen. Accordingly, you must set the root viewport to an area that does not cover the area that you have attached this viewport to.
+ Copies the viewport to a region of the screen specified by [param rect]. If [method viewport_set_render_direct_to_screen] is [code]true[/code], then the viewport does not use a framebuffer and the contents of the viewport are rendered directly to screen. However, note that the root viewport is drawn last, therefore it will draw over the screen. Accordingly, you must set the root viewport to an area that does not cover the area that you have attached this viewport to.
For example, you can set the root viewport to not render at all with the following code:
FIXME: The method seems to be non-existent.
[codeblocks]
@@ -3061,185 +3071,185 @@
</method>
<method name="viewport_get_measured_render_time_cpu" qualifiers="const">
<return type="float" />
- <argument index="0" name="viewport" type="RID" />
+ <param index="0" name="viewport" type="RID" />
<description>
</description>
</method>
<method name="viewport_get_measured_render_time_gpu" qualifiers="const">
<return type="float" />
- <argument index="0" name="viewport" type="RID" />
+ <param index="0" name="viewport" type="RID" />
<description>
</description>
</method>
<method name="viewport_get_render_info">
<return type="int" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="type" type="int" enum="RenderingServer.ViewportRenderInfoType" />
- <argument index="2" name="info" type="int" enum="RenderingServer.ViewportRenderInfo" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="type" type="int" enum="RenderingServer.ViewportRenderInfoType" />
+ <param index="2" name="info" type="int" enum="RenderingServer.ViewportRenderInfo" />
<description>
</description>
</method>
<method name="viewport_get_texture" qualifiers="const">
<return type="RID" />
- <argument index="0" name="viewport" type="RID" />
+ <param index="0" name="viewport" type="RID" />
<description>
Returns the viewport's last rendered frame.
</description>
</method>
<method name="viewport_remove_canvas">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="canvas" type="RID" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="canvas" type="RID" />
<description>
Detaches a viewport from a canvas and vice versa.
</description>
</method>
<method name="viewport_set_active">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="active" type="bool" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="active" type="bool" />
<description>
If [code]true[/code], sets the viewport active, else sets it inactive.
</description>
</method>
<method name="viewport_set_canvas_stacking">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="canvas" type="RID" />
- <argument index="2" name="layer" type="int" />
- <argument index="3" name="sublayer" type="int" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="canvas" type="RID" />
+ <param index="2" name="layer" type="int" />
+ <param index="3" name="sublayer" type="int" />
<description>
Sets the stacking order for a viewport's canvas.
- [code]layer[/code] is the actual canvas layer, while [code]sublayer[/code] specifies the stacking order of the canvas among those in the same layer.
+ [param layer] is the actual canvas layer, while [param sublayer] specifies the stacking order of the canvas among those in the same layer.
</description>
</method>
<method name="viewport_set_canvas_transform">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="canvas" type="RID" />
- <argument index="2" name="offset" type="Transform2D" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="canvas" type="RID" />
+ <param index="2" name="offset" type="Transform2D" />
<description>
Sets the transformation of a viewport's canvas.
</description>
</method>
<method name="viewport_set_clear_mode">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="clear_mode" type="int" enum="RenderingServer.ViewportClearMode" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="clear_mode" type="int" enum="RenderingServer.ViewportClearMode" />
<description>
Sets the clear mode of a viewport. See [enum ViewportClearMode] for options.
</description>
</method>
<method name="viewport_set_debug_draw">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="draw" type="int" enum="RenderingServer.ViewportDebugDraw" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="draw" type="int" enum="RenderingServer.ViewportDebugDraw" />
<description>
Sets the debug draw mode of a viewport. See [enum ViewportDebugDraw] for options.
</description>
</method>
<method name="viewport_set_default_canvas_item_texture_filter">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="filter" type="int" enum="RenderingServer.CanvasItemTextureFilter" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="filter" type="int" enum="RenderingServer.CanvasItemTextureFilter" />
<description>
</description>
</method>
<method name="viewport_set_default_canvas_item_texture_repeat">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="repeat" type="int" enum="RenderingServer.CanvasItemTextureRepeat" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="repeat" type="int" enum="RenderingServer.CanvasItemTextureRepeat" />
<description>
</description>
</method>
<method name="viewport_set_disable_2d">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="disable" type="bool" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="disable" type="bool" />
<description>
If [code]true[/code], the viewport's canvas is not rendered.
</description>
</method>
<method name="viewport_set_disable_3d">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="disable" type="bool" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="disable" type="bool" />
<description>
</description>
</method>
<method name="viewport_set_disable_environment">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="disabled" type="bool" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="disabled" type="bool" />
<description>
If [code]true[/code], rendering of a viewport's environment is disabled.
</description>
</method>
<method name="viewport_set_fsr_sharpness">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="sharpness" type="float" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="sharpness" type="float" />
<description>
Determines how sharp the upscaled image will be when using the FSR upscaling mode. Sharpness halves with every whole number. Values go from 0.0 (sharpest) to 2.0. Values above 2.0 won't make a visible difference.
</description>
</method>
<method name="viewport_set_global_canvas_transform">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="transform" type="Transform2D" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="transform" type="Transform2D" />
<description>
Sets the viewport's global transformation matrix.
</description>
</method>
<method name="viewport_set_measure_render_time">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
</description>
</method>
<method name="viewport_set_msaa">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="msaa" type="int" enum="RenderingServer.ViewportMSAA" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="msaa" type="int" enum="RenderingServer.ViewportMSAA" />
<description>
Sets the anti-aliasing mode. See [enum ViewportMSAA] for options.
</description>
</method>
<method name="viewport_set_occlusion_culling_build_quality">
<return type="void" />
- <argument index="0" name="quality" type="int" enum="RenderingServer.ViewportOcclusionCullingBuildQuality" />
+ <param index="0" name="quality" type="int" enum="RenderingServer.ViewportOcclusionCullingBuildQuality" />
<description>
</description>
</method>
<method name="viewport_set_occlusion_rays_per_thread">
<return type="void" />
- <argument index="0" name="rays_per_thread" type="int" />
+ <param index="0" name="rays_per_thread" type="int" />
<description>
</description>
</method>
<method name="viewport_set_parent_viewport">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="parent_viewport" type="RID" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="parent_viewport" type="RID" />
<description>
Sets the viewport's parent to another viewport.
</description>
</method>
<method name="viewport_set_positional_shadow_atlas_quadrant_subdivision">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="quadrant" type="int" />
- <argument index="2" name="subdivision" type="int" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="quadrant" type="int" />
+ <param index="2" name="subdivision" type="int" />
<description>
Sets the shadow atlas quadrant's subdivision.
</description>
</method>
<method name="viewport_set_positional_shadow_atlas_size">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="use_16_bits" type="bool" default="false" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="use_16_bits" type="bool" default="false" />
<description>
Sets the size of the shadow atlas's images (used for omni and spot lights). The value will be rounded up to the nearest power of 2.
[b]Note:[/b] If this is set to [code]0[/code], no shadows will be visible at all (including directional shadows).
@@ -3247,24 +3257,24 @@
</method>
<method name="viewport_set_render_direct_to_screen">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="enabled" type="bool" />
<description>
If [code]true[/code], render the contents of the viewport directly to screen. This allows a low-level optimization where you can skip drawing a viewport to the root viewport. While this optimization can result in a significant increase in speed (especially on older devices), it comes at a cost of usability. When this is enabled, you cannot read from the viewport or from the [code]SCREEN_TEXTURE[/code]. You also lose the benefit of certain window settings, such as the various stretch modes. Another consequence to be aware of is that in 2D the rendering happens in window coordinates, so if you have a viewport that is double the size of the window, and you set this, then only the portion that fits within the window will be drawn, no automatic scaling is possible, even if your game scene is significantly larger than the window size.
</description>
</method>
<method name="viewport_set_scaling_3d_mode">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="scaling_3d_mode" type="int" enum="RenderingServer.ViewportScaling3DMode" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="scaling_3d_mode" type="int" enum="RenderingServer.ViewportScaling3DMode" />
<description>
Sets scaling 3d mode. Bilinear scaling renders at different resolution to either undersample or supersample the viewport. FidelityFX Super Resolution 1.0, abbreviated to FSR, is an upscaling technology that produces high quality images at fast framerates by using a spatially aware upscaling algorithm. FSR is slightly more expensive than bilinear, but it produces significantly higher image quality. FSR should be used where possible.
</description>
</method>
<method name="viewport_set_scaling_3d_scale">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="scale" type="float" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="scale" type="float" />
<description>
Scales the 3D render buffer based on the viewport size uses an image filter specified in [enum ViewportScaling3DMode] to scale the output image to the full viewport size. Values lower than [code]1.0[/code] can be used to speed up 3D rendering at the cost of quality (undersampling). Values greater than [code]1.0[/code] are only valid for bilinear mode and can be used to improve 3D rendering quality at a high performance cost (supersampling). See also [enum ViewportMSAA] for multi-sample antialiasing, which is significantly cheaper but only smoothens the edges of polygons.
When using FSR upscaling, AMD recommends exposing the following values as preset options to users "Ultra Quality: 0.77", "Quality: 0.67", "Balanced: 0.59", "Performance: 0.5" instead of exposing the entire scale.
@@ -3272,8 +3282,8 @@
</method>
<method name="viewport_set_scenario">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="scenario" type="RID" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="scenario" type="RID" />
<description>
Sets a viewport's scenario.
The scenario contains information about environment information, reflection atlas etc.
@@ -3281,46 +3291,46 @@
</method>
<method name="viewport_set_screen_space_aa">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="mode" type="int" enum="RenderingServer.ViewportScreenSpaceAA" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="mode" type="int" enum="RenderingServer.ViewportScreenSpaceAA" />
<description>
</description>
</method>
<method name="viewport_set_sdf_oversize_and_scale">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="oversize" type="int" enum="RenderingServer.ViewportSDFOversize" />
- <argument index="2" name="scale" type="int" enum="RenderingServer.ViewportSDFScale" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="oversize" type="int" enum="RenderingServer.ViewportSDFOversize" />
+ <param index="2" name="scale" type="int" enum="RenderingServer.ViewportSDFScale" />
<description>
</description>
</method>
<method name="viewport_set_size">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="width" type="int" />
- <argument index="2" name="height" type="int" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="width" type="int" />
+ <param index="2" name="height" type="int" />
<description>
Sets the viewport's width and height.
</description>
</method>
<method name="viewport_set_snap_2d_transforms_to_pixel">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="enabled" type="bool" />
<description>
</description>
</method>
<method name="viewport_set_snap_2d_vertices_to_pixel">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="enabled" type="bool" />
<description>
</description>
</method>
<method name="viewport_set_texture_mipmap_bias">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="mipmap_bias" type="float" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="mipmap_bias" type="float" />
<description>
Affects the final texture sharpness by reading from a lower or higher mipmap (also called "texture LOD bias"). Negative values make mipmapped textures sharper but grainier when viewed at a distance, while positive values make mipmapped textures blurrier (even when up close). To get sharper textures at a distance without introducing too much graininess, set this between [code]-0.75[/code] and [code]0.0[/code]. Enabling temporal antialiasing ([member ProjectSettings.rendering/anti_aliasing/quality/use_taa]) can help reduce the graininess visible when using negative mipmap bias.
[b]Note:[/b] When the 3D scaling mode is set to FSR 1.0, this value is used to adjust the automatic mipmap bias which is calculated internally based on the scale factor. The formula for this is [code]-log2(1.0 / scale) + mipmap_bias[/code].
@@ -3328,62 +3338,62 @@
</method>
<method name="viewport_set_transparent_background">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="enabled" type="bool" />
<description>
If [code]true[/code], the viewport renders its background as transparent.
</description>
</method>
<method name="viewport_set_update_mode">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="update_mode" type="int" enum="RenderingServer.ViewportUpdateMode" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="update_mode" type="int" enum="RenderingServer.ViewportUpdateMode" />
<description>
Sets when the viewport should be updated. See [enum ViewportUpdateMode] constants for options.
</description>
</method>
<method name="viewport_set_use_debanding">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
</description>
</method>
<method name="viewport_set_use_occlusion_culling">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
</description>
</method>
<method name="viewport_set_use_taa">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
If [code]true[/code], use Temporal Anti-Aliasing.
</description>
</method>
<method name="viewport_set_use_xr">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="use_xr" type="bool" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="use_xr" type="bool" />
<description>
If [code]true[/code], the viewport uses augmented or virtual reality technologies. See [XRInterface].
</description>
</method>
<method name="viewport_set_vrs_mode">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="mode" type="int" enum="RenderingServer.ViewportVRSMode" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="mode" type="int" enum="RenderingServer.ViewportVRSMode" />
<description>
Sets the Variable Rate Shading (VRS) mode for the viewport. Note, if hardware does not support VRS this property is ignored.
</description>
</method>
<method name="viewport_set_vrs_texture">
<return type="void" />
- <argument index="0" name="viewport" type="RID" />
- <argument index="1" name="texture" type="RID" />
+ <param index="0" name="viewport" type="RID" />
+ <param index="1" name="texture" type="RID" />
<description>
Texture to use when the VRS mode is set to [constant RenderingServer.VIEWPORT_VRS_TEXTURE].
</description>
@@ -3395,29 +3405,29 @@
</method>
<method name="visibility_notifier_set_aabb">
<return type="void" />
- <argument index="0" name="notifier" type="RID" />
- <argument index="1" name="aabb" type="AABB" />
+ <param index="0" name="notifier" type="RID" />
+ <param index="1" name="aabb" type="AABB" />
<description>
</description>
</method>
<method name="visibility_notifier_set_callbacks">
<return type="void" />
- <argument index="0" name="notifier" type="RID" />
- <argument index="1" name="enter_callable" type="Callable" />
- <argument index="2" name="exit_callable" type="Callable" />
+ <param index="0" name="notifier" type="RID" />
+ <param index="1" name="enter_callable" type="Callable" />
+ <param index="2" name="exit_callable" type="Callable" />
<description>
</description>
</method>
<method name="voxel_gi_allocate_data">
<return type="void" />
- <argument index="0" name="voxel_gi" type="RID" />
- <argument index="1" name="to_cell_xform" type="Transform3D" />
- <argument index="2" name="aabb" type="AABB" />
- <argument index="3" name="octree_size" type="Vector3i" />
- <argument index="4" name="octree_cells" type="PackedByteArray" />
- <argument index="5" name="data_cells" type="PackedByteArray" />
- <argument index="6" name="distance_field" type="PackedByteArray" />
- <argument index="7" name="level_counts" type="PackedInt32Array" />
+ <param index="0" name="voxel_gi" type="RID" />
+ <param index="1" name="to_cell_xform" type="Transform3D" />
+ <param index="2" name="aabb" type="AABB" />
+ <param index="3" name="octree_size" type="Vector3i" />
+ <param index="4" name="octree_cells" type="PackedByteArray" />
+ <param index="5" name="data_cells" type="PackedByteArray" />
+ <param index="6" name="distance_field" type="PackedByteArray" />
+ <param index="7" name="level_counts" type="PackedInt32Array" />
<description>
</description>
</method>
@@ -3428,92 +3438,92 @@
</method>
<method name="voxel_gi_get_data_cells" qualifiers="const">
<return type="PackedByteArray" />
- <argument index="0" name="voxel_gi" type="RID" />
+ <param index="0" name="voxel_gi" type="RID" />
<description>
</description>
</method>
<method name="voxel_gi_get_distance_field" qualifiers="const">
<return type="PackedByteArray" />
- <argument index="0" name="voxel_gi" type="RID" />
+ <param index="0" name="voxel_gi" type="RID" />
<description>
</description>
</method>
<method name="voxel_gi_get_level_counts" qualifiers="const">
<return type="PackedInt32Array" />
- <argument index="0" name="voxel_gi" type="RID" />
+ <param index="0" name="voxel_gi" type="RID" />
<description>
</description>
</method>
<method name="voxel_gi_get_octree_cells" qualifiers="const">
<return type="PackedByteArray" />
- <argument index="0" name="voxel_gi" type="RID" />
+ <param index="0" name="voxel_gi" type="RID" />
<description>
</description>
</method>
<method name="voxel_gi_get_octree_size" qualifiers="const">
<return type="Vector3i" />
- <argument index="0" name="voxel_gi" type="RID" />
+ <param index="0" name="voxel_gi" type="RID" />
<description>
</description>
</method>
<method name="voxel_gi_get_to_cell_xform" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="voxel_gi" type="RID" />
+ <param index="0" name="voxel_gi" type="RID" />
<description>
</description>
</method>
<method name="voxel_gi_set_bias">
<return type="void" />
- <argument index="0" name="voxel_gi" type="RID" />
- <argument index="1" name="bias" type="float" />
+ <param index="0" name="voxel_gi" type="RID" />
+ <param index="1" name="bias" type="float" />
<description>
</description>
</method>
<method name="voxel_gi_set_dynamic_range">
<return type="void" />
- <argument index="0" name="voxel_gi" type="RID" />
- <argument index="1" name="range" type="float" />
+ <param index="0" name="voxel_gi" type="RID" />
+ <param index="1" name="range" type="float" />
<description>
</description>
</method>
<method name="voxel_gi_set_energy">
<return type="void" />
- <argument index="0" name="voxel_gi" type="RID" />
- <argument index="1" name="energy" type="float" />
+ <param index="0" name="voxel_gi" type="RID" />
+ <param index="1" name="energy" type="float" />
<description>
</description>
</method>
<method name="voxel_gi_set_interior">
<return type="void" />
- <argument index="0" name="voxel_gi" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="voxel_gi" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
</description>
</method>
<method name="voxel_gi_set_normal_bias">
<return type="void" />
- <argument index="0" name="voxel_gi" type="RID" />
- <argument index="1" name="bias" type="float" />
+ <param index="0" name="voxel_gi" type="RID" />
+ <param index="1" name="bias" type="float" />
<description>
</description>
</method>
<method name="voxel_gi_set_propagation">
<return type="void" />
- <argument index="0" name="voxel_gi" type="RID" />
- <argument index="1" name="amount" type="float" />
+ <param index="0" name="voxel_gi" type="RID" />
+ <param index="1" name="amount" type="float" />
<description>
</description>
</method>
<method name="voxel_gi_set_quality">
<return type="void" />
- <argument index="0" name="quality" type="int" enum="RenderingServer.VoxelGIQuality" />
+ <param index="0" name="quality" type="int" enum="RenderingServer.VoxelGIQuality" />
<description>
</description>
</method>
<method name="voxel_gi_set_use_two_bounces">
<return type="void" />
- <argument index="0" name="voxel_gi" type="RID" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="voxel_gi" type="RID" />
+ <param index="1" name="enable" type="bool" />
<description>
</description>
</method>
@@ -3747,14 +3757,22 @@
Use [Transform3D] to store MultiMesh transform.
</constant>
<constant name="LIGHT_PROJECTOR_FILTER_NEAREST" value="0" enum="LightProjectorFilter">
+ Nearest-neighbor filter for light projectors (use for pixel art light projectors). No mipmaps are used for rendering, which means light projectors at a distance will look sharp but grainy. This has roughly the same performance cost as using mipmaps.
</constant>
- <constant name="LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS" value="1" enum="LightProjectorFilter">
+ <constant name="LIGHT_PROJECTOR_FILTER_LINEAR" value="1" enum="LightProjectorFilter">
+ Linear filter for light projectors (use for non-pixel art light projectors). No mipmaps are used for rendering, which means light projectors at a distance will look smooth but blurry. This has roughly the same performance cost as using mipmaps.
</constant>
- <constant name="LIGHT_PROJECTOR_FILTER_LINEAR" value="2" enum="LightProjectorFilter">
+ <constant name="LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS" value="2" enum="LightProjectorFilter">
+ Nearest-neighbor filter for light projectors (use for pixel art light projectors). Isotropic mipmaps are used for rendering, which means light projectors at a distance will look smooth but blurry. This has roughly the same performance cost as not using mipmaps.
</constant>
<constant name="LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS" value="3" enum="LightProjectorFilter">
+ Linear filter for light projectors (use for non-pixel art light projectors). Isotropic mipmaps are used for rendering, which means light projectors at a distance will look smooth but blurry. This has roughly the same performance cost as not using mipmaps.
</constant>
- <constant name="LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC" value="4" enum="LightProjectorFilter">
+ <constant name="LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC" value="4" enum="LightProjectorFilter">
+ Nearest-neighbor filter for light projectors (use for pixel art light projectors). Anisotropic mipmaps are used for rendering, which means light projectors at a distance will look smooth and sharp when viewed from oblique angles. This looks better compared to isotropic mipmaps, but is slower. The level of anisotropic filtering is defined by [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
+ </constant>
+ <constant name="LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC" value="5" enum="LightProjectorFilter">
+ Linear filter for light projectors (use for non-pixel art light projectors). Anisotropic mipmaps are used for rendering, which means light projectors at a distance will look smooth and sharp when viewed from oblique angles. This looks better compared to isotropic mipmaps, but is slower. The level of anisotropic filtering is defined by [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
</constant>
<constant name="LIGHT_DIRECTIONAL" value="0" enum="LightType">
Is a directional (sun) light.
@@ -3769,6 +3787,7 @@
The light's energy.
</constant>
<constant name="LIGHT_PARAM_INDIRECT_ENERGY" value="1" enum="LightParam">
+ The light's indirect energy multiplier (final indirect energy is [constant LIGHT_PARAM_ENERGY] * [constant LIGHT_PARAM_INDIRECT_ENERGY]).
</constant>
<constant name="LIGHT_PARAM_SPECULAR" value="2" enum="LightParam">
The light's influence on specularity.
@@ -3812,14 +3831,17 @@
<constant name="LIGHT_PARAM_SHADOW_PANCAKE_SIZE" value="15" enum="LightParam">
Sets the size of the directional shadow pancake. The pancake offsets the start of the shadow's camera frustum to provide a higher effective depth resolution for the shadow. However, a high pancake size can cause artifacts in the shadows of large objects that are close to the edge of the frustum. Reducing the pancake size can help. Setting the size to [code]0[/code] turns off the pancaking effect.
</constant>
- <constant name="LIGHT_PARAM_SHADOW_BLUR" value="16" enum="LightParam">
+ <constant name="LIGHT_PARAM_SHADOW_OPACITY" value="16" enum="LightParam">
+ The light's shadow opacity. Values lower than [code]1.0[/code] make the light appear through shadows. This can be used to fake global illumination at a low performance cost.
+ </constant>
+ <constant name="LIGHT_PARAM_SHADOW_BLUR" value="17" 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_SHADOW_VOLUMETRIC_FOG_FADE" value="17" enum="LightParam">
+ <constant name="LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE" value="18" enum="LightParam">
</constant>
- <constant name="LIGHT_PARAM_TRANSMITTANCE_BIAS" value="18" enum="LightParam">
+ <constant name="LIGHT_PARAM_TRANSMITTANCE_BIAS" value="19" enum="LightParam">
</constant>
- <constant name="LIGHT_PARAM_MAX" value="19" enum="LightParam">
+ <constant name="LIGHT_PARAM_MAX" value="20" enum="LightParam">
Represents the size of the [enum LightParam] enum.
</constant>
<constant name="LIGHT_BAKE_DISABLED" value="0" enum="LightBakeMode">
@@ -3896,14 +3918,22 @@
<constant name="DECAL_TEXTURE_MAX" value="4" enum="DecalTexture">
</constant>
<constant name="DECAL_FILTER_NEAREST" value="0" enum="DecalFilter">
+ Nearest-neighbor filter for decals (use for pixel art decals). No mipmaps are used for rendering, which means decals at a distance will look sharp but grainy. This has roughly the same performance cost as using mipmaps.
</constant>
- <constant name="DECAL_FILTER_NEAREST_MIPMAPS" value="1" enum="DecalFilter">
+ <constant name="DECAL_FILTER_LINEAR" value="1" enum="DecalFilter">
+ Linear filter for decals (use for non-pixel art decals). No mipmaps are used for rendering, which means decals at a distance will look smooth but blurry. This has roughly the same performance cost as using mipmaps.
</constant>
- <constant name="DECAL_FILTER_LINEAR" value="2" enum="DecalFilter">
+ <constant name="DECAL_FILTER_NEAREST_MIPMAPS" value="2" enum="DecalFilter">
+ Nearest-neighbor filter for decals (use for pixel art decals). Isotropic mipmaps are used for rendering, which means decals at a distance will look smooth but blurry. This has roughly the same performance cost as not using mipmaps.
</constant>
<constant name="DECAL_FILTER_LINEAR_MIPMAPS" value="3" enum="DecalFilter">
+ Linear filter for decals (use for non-pixel art decals). Isotropic mipmaps are used for rendering, which means decals at a distance will look smooth but blurry. This has roughly the same performance cost as not using mipmaps.
+ </constant>
+ <constant name="DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC" value="4" enum="DecalFilter">
+ Nearest-neighbor filter for decals (use for pixel art decals). Anisotropic mipmaps are used for rendering, which means decals at a distance will look smooth and sharp when viewed from oblique angles. This looks better compared to isotropic mipmaps, but is slower. The level of anisotropic filtering is defined by [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
</constant>
- <constant name="DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC" value="4" enum="DecalFilter">
+ <constant name="DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC" value="5" enum="DecalFilter">
+ Linear filter for decals (use for non-pixel art decals). Anisotropic mipmaps are used for rendering, which means decals at a distance will look smooth and sharp when viewed from oblique angles. This looks better compared to isotropic mipmaps, but is slower. The level of anisotropic filtering is defined by [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
</constant>
<constant name="VOXEL_GI_QUALITY_LOW" value="0" enum="VoxelGIQuality">
</constant>
diff --git a/doc/classes/Resource.xml b/doc/classes/Resource.xml
index b08b1540ab..3adf10da2d 100644
--- a/doc/classes/Resource.xml
+++ b/doc/classes/Resource.xml
@@ -19,11 +19,11 @@
</method>
<method name="duplicate" qualifiers="const">
<return type="Resource" />
- <argument index="0" name="subresources" type="bool" default="false" />
+ <param index="0" name="subresources" type="bool" default="false" />
<description>
Duplicates the resource, returning a new resource with the exported members copied. [b]Note:[/b] To duplicate the resource the constructor is called without arguments. This method will error when the constructor doesn't have default values.
- By default, sub-resources are shared between resource copies for efficiency. This can be changed by passing [code]true[/code] to the [code]subresources[/code] argument which will copy the subresources.
- [b]Note:[/b] If [code]subresources[/code] is [code]true[/code], this method will only perform a shallow copy. Nested resources within subresources will not be duplicated and will still be shared.
+ By default, sub-resources are shared between resource copies for efficiency. This can be changed by passing [code]true[/code] to the [param subresources] argument which will copy the subresources.
+ [b]Note:[/b] If [param subresources] is [code]true[/code], this method will only perform a shallow copy. Nested resources within subresources will not be duplicated and will still be shared.
[b]Note:[/b] When duplicating a resource, only [code]export[/code]ed properties are copied. Other properties will be set to their default value in the new resource.
</description>
</method>
@@ -60,7 +60,7 @@
</method>
<method name="take_over_path">
<return type="void" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Sets the path of the resource, potentially overriding an existing cache entry for this path. This differs from setting [member resource_path], as the latter would error out if another resource was already cached for the given path.
</description>
diff --git a/doc/classes/ResourceFormatLoader.xml b/doc/classes/ResourceFormatLoader.xml
index fef94b5f3b..9b8c8d4d9d 100644
--- a/doc/classes/ResourceFormatLoader.xml
+++ b/doc/classes/ResourceFormatLoader.xml
@@ -13,22 +13,22 @@
<methods>
<method name="_exists" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
</description>
</method>
<method name="_get_classes_used" qualifiers="virtual const">
<return type="PackedStringArray" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
</description>
</method>
<method name="_get_dependencies" qualifiers="virtual const">
<return type="PackedStringArray" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="add_types" type="bool" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="add_types" type="bool" />
<description>
- If implemented, gets the dependencies of a given resource. If [code]add_types[/code] is [code]true[/code], paths should be appended [code]::TypeName[/code], where [code]TypeName[/code] is the class name of the dependency.
+ If implemented, gets the dependencies of a given resource. If [param add_types] is [code]true[/code], paths should be appended [code]::TypeName[/code], where [code]TypeName[/code] is the class name of the dependency.
[b]Note:[/b] Custom resource types defined by scripts aren't known by the [ClassDB], so you might just return [code]"Resource"[/code] for them.
</description>
</method>
@@ -40,7 +40,7 @@
</method>
<method name="_get_resource_type" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Gets the class name of the resource associated with the given path. If the loader cannot handle it, it should return [code]""[/code].
[b]Note:[/b] Custom resource types defined by scripts aren't known by the [ClassDB], so you might just return [code]"Resource"[/code] for them.
@@ -48,13 +48,13 @@
</method>
<method name="_get_resource_uid" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
</description>
</method>
<method name="_handles_type" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="type" type="StringName" />
+ <param index="0" name="type" type="StringName" />
<description>
Tells which resource class this loader can load.
[b]Note:[/b] Custom resource types defined by scripts aren't known by the [ClassDB], so you might just handle [code]"Resource"[/code] for them.
@@ -62,21 +62,21 @@
</method>
<method name="_load" qualifiers="virtual const">
<return type="Variant" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="original_path" type="String" />
- <argument index="2" name="use_sub_threads" type="bool" />
- <argument index="3" name="cache_mode" type="int" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="original_path" type="String" />
+ <param index="2" name="use_sub_threads" type="bool" />
+ <param index="3" name="cache_mode" type="int" />
<description>
- Loads a resource when the engine finds this loader to be compatible. If the loaded resource is the result of an import, [code]original_path[/code] will target the source file. Returns a [Resource] object on success, or an [enum Error] constant in case of failure.
- The [code]cache_mode[/code] property defines whether and how the cache should be used or updated when loading the resource. See [enum CacheMode] for details.
+ Loads a resource when the engine finds this loader to be compatible. If the loaded resource is the result of an import, [param original_path] will target the source file. Returns a [Resource] object on success, or an [enum Error] constant in case of failure.
+ The [param cache_mode] property defines whether and how the cache should be used or updated when loading the resource. See [enum CacheMode] for details.
</description>
</method>
<method name="_rename_dependencies" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="renames" type="Dictionary" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="renames" type="Dictionary" />
<description>
- If implemented, renames dependencies within the given resource and saves it. [code]renames[/code] is a dictionary [code]{ String =&gt; String }[/code] mapping old dependency paths to new paths.
+ If implemented, renames dependencies within the given resource and saves it. [param renames] is a dictionary [code]{ String =&gt; String }[/code] mapping old dependency paths to new paths.
Returns [constant OK] on success, or an [enum Error] constant in case of failure.
</description>
</method>
diff --git a/doc/classes/ResourceFormatSaver.xml b/doc/classes/ResourceFormatSaver.xml
index f9c4ca0d49..05bfcf3446 100644
--- a/doc/classes/ResourceFormatSaver.xml
+++ b/doc/classes/ResourceFormatSaver.xml
@@ -12,25 +12,25 @@
<methods>
<method name="_get_recognized_extensions" qualifiers="virtual const">
<return type="PackedStringArray" />
- <argument index="0" name="resource" type="Resource" />
+ <param index="0" name="resource" type="Resource" />
<description>
Returns the list of extensions available for saving the resource object, provided it is recognized (see [method _recognize]).
</description>
</method>
<method name="_recognize" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="resource" type="Resource" />
+ <param index="0" name="resource" type="Resource" />
<description>
Returns whether the given resource object can be saved by this saver.
</description>
</method>
<method name="_save" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="path" type="Resource" />
- <argument index="1" name="resource" type="String" />
- <argument index="2" name="flags" type="int" />
+ <param index="0" name="resource" type="Resource" />
+ <param index="1" name="path" type="String" />
+ <param index="2" name="flags" type="int" />
<description>
- Saves the given resource object to a file at the target [code]path[/code]. [code]flags[/code] is a bitmask composed with [enum ResourceSaver.SaverFlags] constants.
+ Saves the given resource object to a file at the target [param path]. [param flags] is a bitmask composed with [enum ResourceSaver.SaverFlags] constants.
Returns [constant OK] on success, or an [enum Error] constant in case of failure.
</description>
</method>
diff --git a/doc/classes/ResourceLoader.xml b/doc/classes/ResourceLoader.xml
index 729058c9b3..d51a5293ec 100644
--- a/doc/classes/ResourceLoader.xml
+++ b/doc/classes/ResourceLoader.xml
@@ -14,8 +14,8 @@
<methods>
<method name="add_resource_format_loader">
<return type="void" />
- <argument index="0" name="format_loader" type="ResourceFormatLoader" />
- <argument index="1" name="at_front" type="bool" default="false" />
+ <param index="0" name="format_loader" type="ResourceFormatLoader" />
+ <param index="1" name="at_front" type="bool" default="false" />
<description>
Registers a new [ResourceFormatLoader]. The ResourceLoader will use the ResourceFormatLoader as described in [method load].
This method is performed implicitly for ResourceFormatLoaders written in GDScript (see [ResourceFormatLoader] for more information).
@@ -23,59 +23,59 @@
</method>
<method name="exists">
<return type="bool" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="type_hint" type="String" default="&quot;&quot;" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="type_hint" type="String" default="&quot;&quot;" />
<description>
- Returns whether a recognized resource exists for the given [code]path[/code].
- An optional [code]type_hint[/code] can be used to further specify the [Resource] type that should be handled by the [ResourceFormatLoader]. Anything that inherits from [Resource] can be used as a type hint, for example [Image].
+ Returns whether a recognized resource exists for the given [param path].
+ An optional [param type_hint] can be used to further specify the [Resource] type that should be handled by the [ResourceFormatLoader]. Anything that inherits from [Resource] can be used as a type hint, for example [Image].
</description>
</method>
<method name="get_dependencies">
<return type="PackedStringArray" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
- Returns the dependencies for the resource at the given [code]path[/code].
+ Returns the dependencies for the resource at the given [param path].
</description>
</method>
<method name="get_recognized_extensions_for_type">
<return type="PackedStringArray" />
- <argument index="0" name="type" type="String" />
+ <param index="0" name="type" type="String" />
<description>
Returns the list of recognized extensions for a resource type.
</description>
</method>
<method name="get_resource_uid">
<return type="int" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Returns the ID associated with a given resource path, or [code]-1[/code] when no such ID exists.
</description>
</method>
<method name="has_cached">
<return type="bool" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
- Returns whether a cached resource is available for the given [code]path[/code].
+ Returns whether a cached resource is available for the given [param path].
Once a resource has been loaded by the engine, it is cached in memory for faster access, and future calls to the [method load] method will use the cached version. The cached resource can be overridden by using [method Resource.take_over_path] on a new resource for that same path.
</description>
</method>
<method name="load">
<return type="Resource" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="type_hint" type="String" default="&quot;&quot;" />
- <argument index="2" name="cache_mode" type="int" enum="ResourceLoader.CacheMode" default="1" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="type_hint" type="String" default="&quot;&quot;" />
+ <param index="2" name="cache_mode" type="int" enum="ResourceLoader.CacheMode" default="1" />
<description>
- Loads a resource at the given [code]path[/code], caching the result for further access.
+ Loads a resource at the given [param path], caching the result for further access.
The registered [ResourceFormatLoader]s are queried sequentially to find the first one which can handle the file's extension, and then attempt loading. If loading fails, the remaining ResourceFormatLoaders are also attempted.
- An optional [code]type_hint[/code] can be used to further specify the [Resource] type that should be handled by the [ResourceFormatLoader]. Anything that inherits from [Resource] can be used as a type hint, for example [Image].
- The [code]cache_mode[/code] property defines whether and how the cache should be used or updated when loading the resource. See [enum CacheMode] for details.
+ An optional [param type_hint] can be used to further specify the [Resource] type that should be handled by the [ResourceFormatLoader]. Anything that inherits from [Resource] can be used as a type hint, for example [Image].
+ The [param cache_mode] property defines whether and how the cache should be used or updated when loading the resource. See [enum CacheMode] for details.
Returns an empty resource if no [ResourceFormatLoader] could handle the file.
GDScript has a simplified [method @GDScript.load] built-in method which can be used in most situations, leaving the use of [ResourceLoader] for more advanced scenarios.
</description>
</method>
<method name="load_threaded_get">
<return type="Resource" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Returns the resource loaded by [method load_threaded_request].
If this is called before the loading thread is done (i.e. [method load_threaded_get_status] is not [constant THREAD_LOAD_LOADED]), the calling thread will be blocked until the resource has finished loading.
@@ -83,34 +83,34 @@
</method>
<method name="load_threaded_get_status">
<return type="int" enum="ResourceLoader.ThreadLoadStatus" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="progress" type="Array" default="[]" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="progress" type="Array" default="[]" />
<description>
- Returns the status of a threaded loading operation started with [method load_threaded_request] for the resource at [code]path[/code]. See [enum ThreadLoadStatus] for possible return values.
- An array variable can optionally be passed via [code]progress[/code], and will return a one-element array containing the percentage of completion of the threaded loading.
+ Returns the status of a threaded loading operation started with [method load_threaded_request] for the resource at [param path]. See [enum ThreadLoadStatus] for possible return values.
+ An array variable can optionally be passed via [param progress], and will return a one-element array containing the percentage of completion of the threaded loading.
</description>
</method>
<method name="load_threaded_request">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="type_hint" type="String" default="&quot;&quot;" />
- <argument index="2" name="use_sub_threads" type="bool" default="false" />
- <argument index="3" name="cache_mode" type="int" enum="ResourceLoader.CacheMode" default="1" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="type_hint" type="String" default="&quot;&quot;" />
+ <param index="2" name="use_sub_threads" type="bool" default="false" />
+ <param index="3" name="cache_mode" type="int" enum="ResourceLoader.CacheMode" default="1" />
<description>
- Loads the resource using threads. If [code]use_sub_threads[/code] is [code]true[/code], multiple threads will be used to load the resource, which makes loading faster, but may affect the main thread (and thus cause game slowdowns).
- The [code]cache_mode[/code] property defines whether and how the cache should be used or updated when loading the resource. See [enum CacheMode] for details.
+ Loads the resource using threads. If [param use_sub_threads] is [code]true[/code], multiple threads will be used to load the resource, which makes loading faster, but may affect the main thread (and thus cause game slowdowns).
+ The [param cache_mode] property defines whether and how the cache should be used or updated when loading the resource. See [enum CacheMode] for details.
</description>
</method>
<method name="remove_resource_format_loader">
<return type="void" />
- <argument index="0" name="format_loader" type="ResourceFormatLoader" />
+ <param index="0" name="format_loader" type="ResourceFormatLoader" />
<description>
Unregisters the given [ResourceFormatLoader].
</description>
</method>
<method name="set_abort_on_missing_resources">
<return type="void" />
- <argument index="0" name="abort" type="bool" />
+ <param index="0" name="abort" type="bool" />
<description>
Changes the behavior on missing sub-resources. The default behavior is to abort loading.
</description>
diff --git a/doc/classes/ResourcePreloader.xml b/doc/classes/ResourcePreloader.xml
index 63db131cec..17904697e6 100644
--- a/doc/classes/ResourcePreloader.xml
+++ b/doc/classes/ResourcePreloader.xml
@@ -12,17 +12,17 @@
<methods>
<method name="add_resource">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="resource" type="Resource" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="resource" type="Resource" />
<description>
- Adds a resource to the preloader with the given [code]name[/code]. If a resource with the given [code]name[/code] already exists, the new resource will be renamed to "[code]name[/code] N" where N is an incrementing number starting from 2.
+ Adds a resource to the preloader with the given [param name]. If a resource with the given [param name] already exists, the new resource will be renamed to "[param name] N" where N is an incrementing number starting from 2.
</description>
</method>
<method name="get_resource" qualifiers="const">
<return type="Resource" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Returns the resource associated to [code]name[/code].
+ Returns the resource associated to [param name].
</description>
</method>
<method name="get_resource_list" qualifiers="const">
@@ -33,24 +33,24 @@
</method>
<method name="has_resource" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Returns [code]true[/code] if the preloader contains a resource associated to [code]name[/code].
+ Returns [code]true[/code] if the preloader contains a resource associated to [param name].
</description>
</method>
<method name="remove_resource">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Removes the resource associated to [code]name[/code] from the preloader.
+ Removes the resource associated to [param name] from the preloader.
</description>
</method>
<method name="rename_resource">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="newname" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="newname" type="StringName" />
<description>
- Renames a resource inside the preloader from [code]name[/code] to [code]newname[/code].
+ Renames a resource inside the preloader from [param name] to [param newname].
</description>
</method>
</methods>
diff --git a/doc/classes/ResourceSaver.xml b/doc/classes/ResourceSaver.xml
index 10387a4f14..b0c9056cbc 100644
--- a/doc/classes/ResourceSaver.xml
+++ b/doc/classes/ResourceSaver.xml
@@ -12,8 +12,8 @@
<methods>
<method name="add_resource_format_saver">
<return type="void" />
- <argument index="0" name="format_saver" type="ResourceFormatSaver" />
- <argument index="1" name="at_front" type="bool" default="false" />
+ <param index="0" name="format_saver" type="ResourceFormatSaver" />
+ <param index="1" name="at_front" type="bool" default="false" />
<description>
Registers a new [ResourceFormatSaver]. The ResourceSaver will use the ResourceFormatSaver as described in [method save].
This method is performed implicitly for ResourceFormatSavers written in GDScript (see [ResourceFormatSaver] for more information).
@@ -21,26 +21,26 @@
</method>
<method name="get_recognized_extensions">
<return type="PackedStringArray" />
- <argument index="0" name="type" type="Resource" />
+ <param index="0" name="type" type="Resource" />
<description>
Returns the list of extensions available for saving a resource of a given type.
</description>
</method>
<method name="remove_resource_format_saver">
<return type="void" />
- <argument index="0" name="format_saver" type="ResourceFormatSaver" />
+ <param index="0" name="format_saver" type="ResourceFormatSaver" />
<description>
Unregisters the given [ResourceFormatSaver].
</description>
</method>
<method name="save">
<return type="int" enum="Error" />
- <argument index="0" name="resource" type="Resource" />
- <argument index="1" name="path" type="String" default="&quot;&quot;" />
- <argument index="2" name="flags" type="int" enum="ResourceSaver.SaverFlags" default="0" />
+ <param index="0" name="resource" type="Resource" />
+ <param index="1" name="path" type="String" default="&quot;&quot;" />
+ <param index="2" name="flags" type="int" enum="ResourceSaver.SaverFlags" default="0" />
<description>
- Saves a resource to disk to the given path, using a [ResourceFormatSaver] that recognizes the resource object. If [code]path[/code] is empty, [ResourceSaver] will try to use [member Resource.resource_path].
- The [code]flags[/code] bitmask can be specified to customize the save behavior using [enum SaverFlags] flags.
+ Saves a resource to disk to the given path, using a [ResourceFormatSaver] that recognizes the resource object. If [param path] is empty, [ResourceSaver] will try to use [member Resource.resource_path].
+ The [param flags] bitmask can be specified to customize the save behavior using [enum SaverFlags] flags.
Returns [constant OK] on success.
</description>
</method>
diff --git a/doc/classes/ResourceUID.xml b/doc/classes/ResourceUID.xml
index f91c39b512..7ac5dd58a8 100644
--- a/doc/classes/ResourceUID.xml
+++ b/doc/classes/ResourceUID.xml
@@ -1,64 +1,83 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="ResourceUID" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Singleton for managing a cache of resource UIDs within a project.
</brief_description>
<description>
+ Resources can not only be referenced using their resource paths [code]res://[/code], but alternatively through a unique identifier specified via [code]uid://[/code].
+ Using UIDs allows for the engine to keep references between resources intact, even if the files get renamed or moved.
+ This singleton is responsible for keeping track of all registered resource UIDs of a project, generating new UIDs and converting between the string and integer representation.
</description>
<tutorials>
</tutorials>
<methods>
<method name="add_id">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="path" type="String" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="path" type="String" />
<description>
+ Adds a new UID value which is mapped to the given resource path.
+ Fails with an error if the UID already exists, so be sure to check [method has_id] beforehand, or use [method set_id] instead.
</description>
</method>
<method name="create_id">
<return type="int" />
<description>
+ Generates a random resource UID which is guaranteed to be unique within the list of currently loaded UIDs.
+ In order for this UID to be registered, you must call [method add_id] or [method set_id].
</description>
</method>
<method name="get_id_path" qualifiers="const">
<return type="String" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
+ Returns the path that the given UID value refers to.
+ Fails with an error if the UID does not exist, so be sure to check [method has_id] beforehand.
</description>
</method>
<method name="has_id" qualifiers="const">
<return type="bool" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
+ Returns whether the given UID value is known to the cache.
</description>
</method>
<method name="id_to_text" qualifiers="const">
<return type="String" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
+ Converts the given UID to a [code]uid://[/code] string value.
</description>
</method>
<method name="remove_id">
<return type="void" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
+ Removes a loaded UID value from the cache.
+ Fails with an error if the UID does not exist, so be sure to check [method has_id] beforehand.
</description>
</method>
<method name="set_id">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="path" type="String" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="path" type="String" />
<description>
+ Updates the resource path of an existing UID.
+ Fails with an error if the UID does not exist, so be sure to check [method has_id] beforehand, or use [method add_id] instead.
</description>
</method>
<method name="text_to_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="text_id" type="String" />
+ <param index="0" name="text_id" type="String" />
<description>
+ Extracts the UID value from the given [code]uid://[/code] string.
</description>
</method>
</methods>
<constants>
<constant name="INVALID_ID" value="-1">
+ The value to use for an invalid UID, for example if the resource could not be loaded.
+ Its text representation is [code]uid://&lt;invalid&gt;[/code].
</constant>
</constants>
</class>
diff --git a/doc/classes/RichTextEffect.xml b/doc/classes/RichTextEffect.xml
index 2256839378..c01546524d 100644
--- a/doc/classes/RichTextEffect.xml
+++ b/doc/classes/RichTextEffect.xml
@@ -25,9 +25,9 @@
<methods>
<method name="_process_custom_fx" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="char_fx" type="CharFXTransform" />
+ <param index="0" name="char_fx" type="CharFXTransform" />
<description>
- Override this method to modify properties in [code]char_fx[/code]. The method must return [code]true[/code] if the character could be transformed successfully. If the method returns [code]false[/code], it will skip transformation to avoid displaying broken text.
+ Override this method to modify properties in [param char_fx]. The method must return [code]true[/code] if the character could be transformed successfully. If the method returns [code]false[/code], it will skip transformation to avoid displaying broken text.
</description>
</method>
</methods>
diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml
index 8228bcc442..f4cbf4c442 100644
--- a/doc/classes/RichTextLabel.xml
+++ b/doc/classes/RichTextLabel.xml
@@ -18,28 +18,28 @@
<methods>
<method name="add_image">
<return type="void" />
- <argument index="0" name="image" type="Texture2D" />
- <argument index="1" name="width" type="int" default="0" />
- <argument index="2" name="height" type="int" default="0" />
- <argument index="3" name="color" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="4" name="inline_align" type="int" enum="InlineAlignment" default="5" />
+ <param index="0" name="image" type="Texture2D" />
+ <param index="1" name="width" type="int" default="0" />
+ <param index="2" name="height" type="int" default="0" />
+ <param index="3" name="color" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="4" name="inline_align" type="int" enum="InlineAlignment" default="5" />
<description>
- Adds an image's opening and closing tags to the tag stack, optionally providing a [code]width[/code] and [code]height[/code] to resize the image and a [code]color[/code] to tint the image.
- If [code]width[/code] or [code]height[/code] is set to 0, the image size will be adjusted in order to keep the original aspect ratio.
+ Adds an image's opening and closing tags to the tag stack, optionally providing a [param width] and [param height] to resize the image and a [param color] to tint the image.
+ If [param width] or [param height] is set to 0, the image size will be adjusted in order to keep the original aspect ratio.
</description>
</method>
<method name="add_text">
<return type="void" />
- <argument index="0" name="text" type="String" />
+ <param index="0" name="text" type="String" />
<description>
Adds raw non-BBCode-parsed text to the tag stack.
</description>
</method>
<method name="append_text">
<return type="void" />
- <argument index="0" name="bbcode" type="String" />
+ <param index="0" name="bbcode" type="String" />
<description>
- Parses [code]bbcode[/code] and adds tags to the tag stack as needed.
+ Parses [param bbcode] and adds tags to the tag stack as needed.
[b]Note:[/b] Using this method, you can't close a tag that was opened in a previous [method append_text] call. This is done to improve performance, especially when updating large RichTextLabels since rebuilding the whole BBCode every time would be slower. If you absolutely need to close a tag in a future method call, append the [member text] instead of using [method append_text].
</description>
</method>
@@ -57,7 +57,7 @@
</method>
<method name="get_character_line">
<return type="int" />
- <argument index="0" name="character" type="int" />
+ <param index="0" name="character" type="int" />
<description>
Returns the line number of the character position provided.
[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
@@ -65,7 +65,7 @@
</method>
<method name="get_character_paragraph">
<return type="int" />
- <argument index="0" name="character" type="int" />
+ <param index="0" name="character" type="int" />
<description>
Returns the paragraph number of the character position provided.
[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
@@ -94,7 +94,7 @@
</method>
<method name="get_line_offset">
<return type="float" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns the vertical offset of the line found at the provided index.
[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
@@ -115,7 +115,7 @@
</method>
<method name="get_paragraph_offset">
<return type="float" />
- <argument index="0" name="paragraph" type="int" />
+ <param index="0" name="paragraph" type="int" />
<description>
Returns the vertical offset of the paragraph found at the provided index.
[b]Note:[/b] If [member threaded] is enabled, this method returns a value for the loaded part of the document. Use [method is_ready] or [signal finished] to determine whether document is fully loaded.
@@ -174,9 +174,9 @@
</method>
<method name="install_effect">
<return type="void" />
- <argument index="0" name="effect" type="Variant" />
+ <param index="0" name="effect" type="Variant" />
<description>
- Installs a custom effect. [code]effect[/code] should be a valid [RichTextEffect].
+ Installs a custom effect. [param effect] should be a valid [RichTextEffect].
</description>
</method>
<method name="is_menu_visible" qualifiers="const">
@@ -199,16 +199,16 @@
</method>
<method name="parse_bbcode">
<return type="void" />
- <argument index="0" name="bbcode" type="String" />
+ <param index="0" name="bbcode" type="String" />
<description>
The assignment version of [method append_text]. Clears the tag stack and inserts the new content.
</description>
</method>
<method name="parse_expressions_for_values">
<return type="Dictionary" />
- <argument index="0" name="expressions" type="PackedStringArray" />
+ <param index="0" name="expressions" type="PackedStringArray" />
<description>
- Parses BBCode parameter [code]expressions[/code] into a dictionary.
+ Parses BBCode parameter [param expressions] into a dictionary.
</description>
</method>
<method name="pop">
@@ -219,7 +219,7 @@
</method>
<method name="push_bgcolor">
<return type="void" />
- <argument index="0" name="bgcolor" type="Color" />
+ <param index="0" name="bgcolor" type="Color" />
<description>
Adds a [code][bgcolor][/code] tag to the tag stack.
</description>
@@ -244,57 +244,57 @@
</method>
<method name="push_color">
<return type="void" />
- <argument index="0" name="color" type="Color" />
+ <param index="0" name="color" type="Color" />
<description>
Adds a [code][color][/code] tag to the tag stack.
</description>
</method>
<method name="push_dropcap">
<return type="void" />
- <argument index="0" name="string" type="String" />
- <argument index="1" name="font" type="Font" />
- <argument index="2" name="size" type="int" />
- <argument index="3" name="dropcap_margins" type="Rect2" default="Rect2(0, 0, 0, 0)" />
- <argument index="4" name="color" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="5" name="outline_size" type="int" default="0" />
- <argument index="6" name="outline_color" type="Color" default="Color(0, 0, 0, 0)" />
+ <param index="0" name="string" type="String" />
+ <param index="1" name="font" type="Font" />
+ <param index="2" name="size" type="int" />
+ <param index="3" name="dropcap_margins" type="Rect2" default="Rect2(0, 0, 0, 0)" />
+ <param index="4" name="color" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="5" name="outline_size" type="int" default="0" />
+ <param index="6" name="outline_color" type="Color" default="Color(0, 0, 0, 0)" />
<description>
Adds a [code][dropcap][/code] tag to the tag stack. Drop cap (dropped capital) is a decorative element at the beginning of a paragraph that is larger than the rest of the text.
</description>
</method>
<method name="push_fgcolor">
<return type="void" />
- <argument index="0" name="fgcolor" type="Color" />
+ <param index="0" name="fgcolor" type="Color" />
<description>
Adds a [code][fgcolor][/code] tag to the tag stack.
</description>
</method>
<method name="push_font">
<return type="void" />
- <argument index="0" name="font" type="Font" />
- <argument index="1" name="font_size" type="int" />
+ <param index="0" name="font" type="Font" />
+ <param index="1" name="font_size" type="int" />
<description>
Adds a [code][font][/code] tag to the tag stack. Overrides default fonts for its duration.
</description>
</method>
<method name="push_font_size">
<return type="void" />
- <argument index="0" name="font_size" type="int" />
+ <param index="0" name="font_size" type="int" />
<description>
</description>
</method>
<method name="push_hint">
<return type="void" />
- <argument index="0" name="description" type="String" />
+ <param index="0" name="description" type="String" />
<description>
Adds a [code][hint][/code] tag to the tag stack. Same as BBCode [code][hint=something]{text}[/hint][/code].
</description>
</method>
<method name="push_indent">
<return type="void" />
- <argument index="0" name="level" type="int" />
+ <param index="0" name="level" type="int" />
<description>
- Adds an [code][indent][/code] tag to the tag stack. Multiplies [code]level[/code] by current [member tab_size] to determine new margin length.
+ Adds an [code][indent][/code] tag to the tag stack. Multiplies [param level] by current [member tab_size] to determine new margin length.
</description>
</method>
<method name="push_italics">
@@ -305,16 +305,16 @@
</method>
<method name="push_list">
<return type="void" />
- <argument index="0" name="level" type="int" />
- <argument index="1" name="type" type="int" enum="RichTextLabel.ListType" />
- <argument index="2" name="capitalize" type="bool" />
+ <param index="0" name="level" type="int" />
+ <param index="1" name="type" type="int" enum="RichTextLabel.ListType" />
+ <param index="2" name="capitalize" type="bool" />
<description>
- Adds [code][ol][/code] or [code][ul][/code] tag to the tag stack. Multiplies [code]level[/code] by current [member tab_size] to determine new margin length.
+ Adds [code][ol][/code] or [code][ul][/code] tag to the tag stack. Multiplies [param level] by current [member tab_size] to determine new margin length.
</description>
</method>
<method name="push_meta">
<return type="void" />
- <argument index="0" name="data" type="Variant" />
+ <param index="0" name="data" type="Variant" />
<description>
Adds a [code][meta][/code] tag to the tag stack. Similar to the BBCode [code][url=something]{text}[/url][/code], but supports non-[String] metadata types.
</description>
@@ -333,24 +333,24 @@
</method>
<method name="push_outline_color">
<return type="void" />
- <argument index="0" name="color" type="Color" />
+ <param index="0" name="color" type="Color" />
<description>
Adds a [code][outline_color][/code] tag to the tag stack. Adds text outline for its duration.
</description>
</method>
<method name="push_outline_size">
<return type="void" />
- <argument index="0" name="outline_size" type="int" />
+ <param index="0" name="outline_size" type="int" />
<description>
Adds a [code][outline_size][/code] tag to the tag stack. Overrides default text outline size for its duration.
</description>
</method>
<method name="push_paragraph">
<return type="void" />
- <argument index="0" name="alignment" type="int" enum="HorizontalAlignment" />
- <argument index="1" name="base_direction" type="int" enum="Control.TextDirection" default="0" />
- <argument index="2" name="language" type="String" default="&quot;&quot;" />
- <argument index="3" name="st_parser" type="int" enum="TextServer.StructuredTextParser" default="0" />
+ <param index="0" name="alignment" type="int" enum="HorizontalAlignment" />
+ <param index="1" name="base_direction" type="int" enum="Control.TextDirection" default="0" />
+ <param index="2" name="language" type="String" default="&quot;&quot;" />
+ <param index="3" name="st_parser" type="int" enum="TextServer.StructuredTextParser" default="0" />
<description>
Adds a [code][p][/code] tag to the tag stack.
</description>
@@ -363,8 +363,8 @@
</method>
<method name="push_table">
<return type="void" />
- <argument index="0" name="columns" type="int" />
- <argument index="1" name="inline_align" type="int" enum="InlineAlignment" default="0" />
+ <param index="0" name="columns" type="int" />
+ <param index="1" name="inline_align" type="int" enum="InlineAlignment" default="0" />
<description>
Adds a [code][table=columns,inline_align][/code] tag to the tag stack.
</description>
@@ -377,24 +377,24 @@
</method>
<method name="remove_line">
<return type="bool" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Removes a line of content from the label. Returns [code]true[/code] if the line exists.
- The [code]line[/code] argument is the index of the line to remove, it can take values in the interval [code][0, get_line_count() - 1][/code].
+ The [param line] argument is the index of the line to remove, it can take values in the interval [code][0, get_line_count() - 1][/code].
</description>
</method>
<method name="scroll_to_line">
<return type="void" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
- Scrolls the window's top line to match [code]line[/code].
+ Scrolls the window's top line to match [param line].
</description>
</method>
<method name="scroll_to_paragraph">
<return type="void" />
- <argument index="0" name="paragraph" type="int" />
+ <param index="0" name="paragraph" type="int" />
<description>
- Scrolls the window's top line to match first line of the [code]paragraph[/code].
+ Scrolls the window's top line to match first line of the [param paragraph].
</description>
</method>
<method name="select_all">
@@ -406,43 +406,43 @@
</method>
<method name="set_cell_border_color">
<return type="void" />
- <argument index="0" name="color" type="Color" />
+ <param index="0" name="color" type="Color" />
<description>
Sets color of a table cell border.
</description>
</method>
<method name="set_cell_padding">
<return type="void" />
- <argument index="0" name="padding" type="Rect2" />
+ <param index="0" name="padding" type="Rect2" />
<description>
Sets inner padding of a table cell.
</description>
</method>
<method name="set_cell_row_background_color">
<return type="void" />
- <argument index="0" name="odd_row_bg" type="Color" />
- <argument index="1" name="even_row_bg" type="Color" />
+ <param index="0" name="odd_row_bg" type="Color" />
+ <param index="1" name="even_row_bg" type="Color" />
<description>
Sets color of a table cell. Separate colors for alternating rows can be specified.
</description>
</method>
<method name="set_cell_size_override">
<return type="void" />
- <argument index="0" name="min_size" type="Vector2" />
- <argument index="1" name="max_size" type="Vector2" />
+ <param index="0" name="min_size" type="Vector2" />
+ <param index="1" name="max_size" type="Vector2" />
<description>
Sets minimum and maximum size overrides for a table cell.
</description>
</method>
<method name="set_table_column_expand">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="expand" type="bool" />
- <argument index="2" name="ratio" type="int" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="expand" type="bool" />
+ <param index="2" name="ratio" type="int" />
<description>
- Edits the selected column's expansion options. If [code]expand[/code] is [code]true[/code], the column expands in proportion to its expansion ratio versus the other columns' ratios.
+ Edits the selected column's expansion options. If [param expand] is [code]true[/code], the column expands in proportion to its expansion ratio versus the other columns' ratios.
For example, 2 columns with ratios 3 and 4 plus 70 pixels in available width would expand 30 and 40 pixels, respectively.
- If [code]expand[/code] is [code]false[/code], the column will not contribute to the total ratio.
+ If [param expand] is [code]false[/code], the column will not contribute to the total ratio.
</description>
</method>
</methods>
@@ -480,10 +480,6 @@
<member name="override_selected_font_color" type="bool" setter="set_override_selected_font_color" getter="is_overriding_selected_font_color" default="false">
If [code]true[/code], the label uses the custom font color.
</member>
- <member name="percent_visible" type="float" setter="set_percent_visible" getter="get_percent_visible" default="1.0">
- The range of characters to display, as a [float] between 0.0 and 1.0. When assigned an out of range value, it's the same as assigning 1.0.
- [b]Note:[/b] Setting this property updates [member visible_characters] based on current [method get_total_character_count].
- </member>
<member name="progress_bar_delay" type="int" setter="set_progress_bar_delay" getter="get_progress_bar_delay" default="1000">
The delay after which the loading progress bar is displayed, in milliseconds. Set to [code]-1[/code] to disable progress bar entirely.
[b]Note:[/b] Progress bar is displayed only if [member threaded] is enabled.
@@ -520,11 +516,15 @@
If [code]true[/code], text processing is done in a background thread.
</member>
<member name="visible_characters" type="int" setter="set_visible_characters" getter="get_visible_characters" default="-1">
- The restricted number of characters to display in the label. If [code]-1[/code], all characters will be displayed.
- [b]Note:[/b] Setting this property updates [member percent_visible] based on current [method get_total_character_count].
+ The number of characters to display. If set to [code]-1[/code], all characters are displayed. This can be useful when animating the text appearing in a dialog box.
+ [b]Note:[/b] Setting this property updates [member visible_ratio] accordingly.
</member>
<member name="visible_characters_behavior" type="int" setter="set_visible_characters_behavior" getter="get_visible_characters_behavior" enum="TextServer.VisibleCharactersBehavior" default="0">
- Sets the clipping behavior when [member visible_characters] or [member percent_visible] is set. See [enum TextServer.VisibleCharactersBehavior] for more info.
+ Sets the clipping behavior when [member visible_characters] or [member visible_ratio] is set. See [enum TextServer.VisibleCharactersBehavior] for more info.
+ </member>
+ <member name="visible_ratio" type="float" setter="set_visible_ratio" getter="get_visible_ratio" default="1.0">
+ The fraction of characters to display, relative to the total number of characters (see [method get_total_character_count]). If set to [code]1.0[/code], all characters are displayed. If set to [code]0.5[/code], only half of the characters will be displayed. This can be useful when animating the text appearing in a dialog box.
+ [b]Note:[/b] Setting this property updates [member visible_characters] accordingly.
</member>
</members>
<signals>
@@ -534,19 +534,19 @@
</description>
</signal>
<signal name="meta_clicked">
- <argument index="0" name="meta" type="Variant" />
+ <param index="0" name="meta" type="Variant" />
<description>
Triggered when the user clicks on content between meta tags. If the meta is defined in text, e.g. [code][url={"data"="hi"}]hi[/url][/code], then the parameter for this signal will be a [String] type. If a particular type or an object is desired, the [method push_meta] method must be used to manually insert the data into the tag stack.
</description>
</signal>
<signal name="meta_hover_ended">
- <argument index="0" name="meta" type="Variant" />
+ <param index="0" name="meta" type="Variant" />
<description>
Triggers when the mouse exits a meta tag.
</description>
</signal>
<signal name="meta_hover_started">
- <argument index="0" name="meta" type="Variant" />
+ <param index="0" name="meta" type="Variant" />
<description>
Triggers when the mouse enters a meta tag.
</description>
diff --git a/doc/classes/RigidDynamicBody2D.xml b/doc/classes/RigidBody2D.xml
index 087156989e..9eedc3a24c 100644
--- a/doc/classes/RigidDynamicBody2D.xml
+++ b/doc/classes/RigidBody2D.xml
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RigidDynamicBody2D" inherits="PhysicsBody2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RigidBody2D" inherits="PhysicsBody2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Physics Body which is moved by 2D physics simulation. Useful for objects that have gravity and can be pushed by other objects.
</brief_description>
<description>
- This node implements simulated 2D physics. You do not control a RigidDynamicBody2D directly. Instead, you apply forces to it (gravity, impulses, etc.) and the physics simulation calculates the resulting movement based on its mass, friction, and other physical properties.
+ This node implements simulated 2D physics. You do not control a RigidBody2D directly. Instead, you apply forces to it (gravity, impulses, etc.) and the physics simulation calculates the resulting movement based on its mass, friction, and other physical properties.
You can switch the body's behavior using [member lock_rotation], [member freeze], and [member freeze_mode].
- [b]Note:[/b] You should not change a RigidDynamicBody2D'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.
+ [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].
</description>
@@ -17,14 +17,14 @@
<methods>
<method name="_integrate_forces" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="state" type="PhysicsDirectBodyState2D" />
+ <param index="0" name="state" type="PhysicsDirectBodyState2D" />
<description>
Allows you to read and safely modify the simulation state for the object. Use this instead of [method Node._physics_process] if you need to directly change the body's [code]position[/code] or other physics properties. By default, it works in addition to the usual physics behavior, but [member custom_integrator] allows you to disable the default behavior and write custom force integration for a body.
</description>
</method>
<method name="add_constant_central_force">
<return type="void" />
- <argument index="0" name="force" type="Vector2" />
+ <param index="0" name="force" type="Vector2" />
<description>
Adds a constant directional force without affecting rotation that keeps being applied over time until cleared with [code]constant_force = Vector2(0, 0)[/code].
This is equivalent to using [method add_constant_force] at the body's center of mass.
@@ -32,23 +32,23 @@
</method>
<method name="add_constant_force">
<return type="void" />
- <argument index="0" name="force" type="Vector2" />
- <argument index="1" name="position" type="Vector2" default="Vector2(0, 0)" />
+ <param index="0" name="force" type="Vector2" />
+ <param index="1" name="position" type="Vector2" default="Vector2(0, 0)" />
<description>
Adds a constant positioned force to the body that keeps being applied over time until cleared with [code]constant_force = Vector2(0, 0)[/code].
- [code]position[/code] is the offset from the body origin in global coordinates.
+ [param position] is the offset from the body origin in global coordinates.
</description>
</method>
<method name="add_constant_torque">
<return type="void" />
- <argument index="0" name="torque" type="float" />
+ <param index="0" name="torque" type="float" />
<description>
Adds a constant rotational force without affecting position that keeps being applied over time until cleared with [code]constant_torque = 0[/code].
</description>
</method>
<method name="apply_central_force">
<return type="void" />
- <argument index="0" name="force" type="Vector2" />
+ <param index="0" name="force" type="Vector2" />
<description>
Applies a directional force without affecting rotation. A force is time dependent and meant to be applied every physics update.
This is equivalent to using [method apply_force] at the body's center of mass.
@@ -56,7 +56,7 @@
</method>
<method name="apply_central_impulse">
<return type="void" />
- <argument index="0" name="impulse" type="Vector2" default="Vector2(0, 0)" />
+ <param index="0" name="impulse" type="Vector2" default="Vector2(0, 0)" />
<description>
Applies a directional impulse without affecting rotation.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
@@ -65,33 +65,33 @@
</method>
<method name="apply_force">
<return type="void" />
- <argument index="0" name="force" type="Vector2" />
- <argument index="1" name="position" type="Vector2" default="Vector2(0, 0)" />
+ <param index="0" name="force" type="Vector2" />
+ <param index="1" name="position" type="Vector2" default="Vector2(0, 0)" />
<description>
Applies a positioned force to the body. A force is time dependent and meant to be applied every physics update.
- [code]position[/code] is the offset from the body origin in global coordinates.
+ [param position] is the offset from the body origin in global coordinates.
</description>
</method>
<method name="apply_impulse">
<return type="void" />
- <argument index="0" name="impulse" type="Vector2" />
- <argument index="1" name="position" type="Vector2" default="Vector2(0, 0)" />
+ <param index="0" name="impulse" type="Vector2" />
+ <param index="1" name="position" type="Vector2" default="Vector2(0, 0)" />
<description>
Applies a positioned impulse to the body.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
- [code]position[/code] is the offset from the body origin in global coordinates.
+ [param position] is the offset from the body origin in global coordinates.
</description>
</method>
<method name="apply_torque">
<return type="void" />
- <argument index="0" name="torque" type="float" />
+ <param index="0" name="torque" type="float" />
<description>
Applies a rotational force without affecting position. A force is time dependent and meant to be applied every physics update.
</description>
</method>
<method name="apply_torque_impulse">
<return type="void" />
- <argument index="0" name="torque" type="float" />
+ <param index="0" name="torque" type="float" />
<description>
Applies a rotational impulse to the body without affecting the position.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
@@ -100,13 +100,20 @@
<method name="get_colliding_bodies" qualifiers="const">
<return type="Node2D[]" />
<description>
- Returns a list of the bodies colliding with this one. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions.
+ Returns a list of the bodies colliding with this one. Requires [member contact_monitor] to be set to [code]true[/code] and [member max_contacts_reported] to be set high enough to detect all the collisions.
[b]Note:[/b] The result of this test is not immediate after moving objects. For performance, list of collisions is updated once per frame and before the physics step. Consider using signals instead.
</description>
</method>
+ <method name="get_contact_count" qualifiers="const">
+ <return type="int" />
+ <description>
+ Returns the number of contacts this body has with other bodies. By default, this returns 0 unless bodies are configured to monitor contacts (see [member contact_monitor]).
+ [b]Note:[/b] To retrieve the colliding bodies, use [method get_colliding_bodies].
+ </description>
+ </method>
<method name="set_axis_velocity">
<return type="void" />
- <argument index="0" name="axis_velocity" type="Vector2" />
+ <param index="0" name="axis_velocity" type="Vector2" />
<description>
Sets the body's velocity on the given axis. The velocity in the given vector axis will be set as the given vector length. This is useful for jumping behavior.
</description>
@@ -117,7 +124,7 @@
Damps the body's rotation. By default, the body will use the [b]Default Angular Damp[/b] in [b]Project &gt; Project Settings &gt; Physics &gt; 2d[/b] or any value override set by an [Area2D] the body is in. Depending on [member angular_damp_mode], you can set [member angular_damp] to be added to or to replace the body's damping value.
See [member ProjectSettings.physics/2d/default_angular_damp] for more details about damping.
</member>
- <member name="angular_damp_mode" type="int" setter="set_angular_damp_mode" getter="get_angular_damp_mode" enum="RigidDynamicBody2D.DampMode" default="0">
+ <member name="angular_damp_mode" type="int" setter="set_angular_damp_mode" getter="get_angular_damp_mode" enum="RigidBody2D.DampMode" default="0">
Defines how [member angular_damp] is applied. See [enum DampMode] for possible values.
</member>
<member name="angular_velocity" type="float" setter="set_angular_velocity" getter="get_angular_velocity" default="0.0">
@@ -130,7 +137,7 @@
The body's custom center of mass, relative to the body's origin position, when [member center_of_mass_mode] is set to [constant CENTER_OF_MASS_MODE_CUSTOM]. This is the balanced point of the body, where applied forces only cause linear acceleration. Applying forces outside of the center of mass causes angular acceleration.
When [member center_of_mass_mode] is set to [constant CENTER_OF_MASS_MODE_AUTO] (default value), the center of mass is automatically computed.
</member>
- <member name="center_of_mass_mode" type="int" setter="set_center_of_mass_mode" getter="get_center_of_mass_mode" enum="RigidDynamicBody2D.CenterOfMassMode" default="0">
+ <member name="center_of_mass_mode" type="int" setter="set_center_of_mass_mode" getter="get_center_of_mass_mode" enum="RigidBody2D.CenterOfMassMode" default="0">
Defines the way the body's center of mass is set. See [enum CenterOfMassMode] for possible values.
</member>
<member name="constant_force" type="Vector2" setter="set_constant_force" getter="get_constant_force" default="Vector2(0, 0)">
@@ -142,13 +149,10 @@
See [method add_constant_torque].
</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 RigidDynamicBody2D. See also [member contacts_reported].
+ If [code]true[/code], the RigidBody2D will emit signals when it collides with another RigidBody2D.
+ [b]Note:[/b] By default the maximum contacts reported is set to 0, meaning nothing will be recorded, see [member max_contacts_reported].
</member>
- <member name="contacts_reported" type="int" setter="set_max_contacts_reported" getter="get_max_contacts_reported" default="0">
- The maximum number of contacts that will be recorded. Requires [member contact_monitor] to be set to [code]true[/code].
- [b]Note:[/b] The number of contacts is different from the number of collisions. Collisions between parallel edges will result in two contacts (one at each end).
- </member>
- <member name="continuous_cd" type="int" setter="set_continuous_collision_detection_mode" getter="get_continuous_collision_detection_mode" enum="RigidDynamicBody2D.CCDMode" default="0">
+ <member name="continuous_cd" type="int" setter="set_continuous_collision_detection_mode" getter="get_continuous_collision_detection_mode" enum="RigidBody2D.CCDMode" default="0">
Continuous collision detection mode.
Continuous collision detection tries to predict where a moving body will collide instead of moving it and correcting its movement after collision. Continuous collision detection is slower, but more precise and misses fewer collisions with small, fast-moving objects. Raycasting and shapecasting methods are available. See [enum CCDMode] for details.
</member>
@@ -160,7 +164,7 @@
See [member freeze_mode] to set the body's behavior when frozen.
For a body that is always frozen, use [StaticBody2D] or [AnimatableBody2D] instead.
</member>
- <member name="freeze_mode" type="int" setter="set_freeze_mode" getter="get_freeze_mode" enum="RigidDynamicBody2D.FreezeMode" default="0">
+ <member name="freeze_mode" type="int" setter="set_freeze_mode" getter="get_freeze_mode" enum="RigidBody2D.FreezeMode" default="0">
The body's freeze mode. Can be used to set the body's behavior when [member freeze] is enabled. See [enum FreezeMode] for possible values.
For a body that is always frozen, use [StaticBody2D] or [AnimatableBody2D] instead.
</member>
@@ -175,7 +179,7 @@
Damps the body's movement. By default, the body will use the [b]Default Linear Damp[/b] in [b]Project &gt; Project Settings &gt; Physics &gt; 2d[/b] or any value override set by an [Area2D] the body is in. Depending on [member linear_damp_mode], you can set [member linear_damp] to be added to or to replace the body's damping value.
See [member ProjectSettings.physics/2d/default_linear_damp] for more details about damping.
</member>
- <member name="linear_damp_mode" type="int" setter="set_linear_damp_mode" getter="get_linear_damp_mode" enum="RigidDynamicBody2D.DampMode" default="0">
+ <member name="linear_damp_mode" type="int" setter="set_linear_damp_mode" getter="get_linear_damp_mode" enum="RigidBody2D.DampMode" default="0">
Defines how [member linear_damp] is applied. See [enum DampMode] for possible values.
</member>
<member name="linear_velocity" type="Vector2" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector2(0, 0)">
@@ -187,6 +191,10 @@
<member name="mass" type="float" setter="set_mass" getter="get_mass" default="1.0">
The body's mass.
</member>
+ <member name="max_contacts_reported" type="int" setter="set_max_contacts_reported" getter="get_max_contacts_reported" default="0">
+ The maximum number of contacts that will be recorded. Requires a value greater than 0 and [member contact_monitor] to be set to [code]true[/code] to start to register contacts. Use [method get_contact_count] to retrieve the count or [method get_colliding_bodies] to retrieve bodies that have been collided with.
+ [b]Note:[/b] The number of contacts is different from the number of collisions. Collisions between parallel edges will result in two contacts (one at each end), and collisions between parallel faces will result in four contacts (one at each corner).
+ </member>
<member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override">
The physics material override for the body.
If a material is assigned to this property, it will be used instead of any other physics material, such as an inherited one.
@@ -197,43 +205,43 @@
</members>
<signals>
<signal name="body_entered">
- <argument index="0" name="body" type="Node" />
+ <param index="0" name="body" type="Node" />
<description>
- Emitted when a collision with another [PhysicsBody2D] or [TileMap] occurs. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s.
- [code]body[/code] the [Node], if it exists in the tree, of the other [PhysicsBody2D] or [TileMap].
+ Emitted when a collision with another [PhysicsBody2D] or [TileMap] occurs. Requires [member contact_monitor] to be set to [code]true[/code] and [member max_contacts_reported] to be set high enough to detect all the collisions. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s.
+ [param body] the [Node], if it exists in the tree, of the other [PhysicsBody2D] or [TileMap].
</description>
</signal>
<signal name="body_exited">
- <argument index="0" name="body" type="Node" />
+ <param index="0" name="body" type="Node" />
<description>
- Emitted when the collision with another [PhysicsBody2D] or [TileMap] ends. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s.
- [code]body[/code] the [Node], if it exists in the tree, of the other [PhysicsBody2D] or [TileMap].
+ Emitted when the collision with another [PhysicsBody2D] or [TileMap] ends. Requires [member contact_monitor] to be set to [code]true[/code] and [member max_contacts_reported] to be set high enough to detect all the collisions. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s.
+ [param body] the [Node], if it exists in the tree, of the other [PhysicsBody2D] or [TileMap].
</description>
</signal>
<signal name="body_shape_entered">
- <argument index="0" name="body_rid" type="RID" />
- <argument index="1" name="body" type="Node" />
- <argument index="2" name="body_shape_index" type="int" />
- <argument index="3" name="local_shape_index" type="int" />
+ <param index="0" name="body_rid" type="RID" />
+ <param index="1" name="body" type="Node" />
+ <param index="2" name="body_shape_index" type="int" />
+ <param index="3" name="local_shape_index" type="int" />
<description>
- Emitted when one of this RigidDynamicBody2D's [Shape2D]s collides with another [PhysicsBody2D] or [TileMap]'s [Shape2D]s. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s.
- [code]body_rid[/code] the [RID] of the other [PhysicsBody2D] or [TileSet]'s [CollisionObject2D] used by the [PhysicsServer2D].
- [code]body[/code] the [Node], if it exists in the tree, of the other [PhysicsBody2D] or [TileMap].
- [code]body_shape_index[/code] the index of the [Shape2D] of the other [PhysicsBody2D] or [TileMap] used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code].
- [code]local_shape_index[/code] the index of the [Shape2D] of this RigidDynamicBody2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
+ Emitted when one of this RigidBody2D's [Shape2D]s collides with another [PhysicsBody2D] or [TileMap]'s [Shape2D]s. Requires [member contact_monitor] to be set to [code]true[/code] and [member max_contacts_reported] to be set high enough to detect all the collisions. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s.
+ [param body_rid] the [RID] of the other [PhysicsBody2D] or [TileSet]'s [CollisionObject2D] used by the [PhysicsServer2D].
+ [param body] the [Node], if it exists in the tree, of the other [PhysicsBody2D] or [TileMap].
+ [param body_shape_index] the index of the [Shape2D] of the other [PhysicsBody2D] or [TileMap] used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code].
+ [param local_shape_index] the index of the [Shape2D] of this RigidBody2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
</description>
</signal>
<signal name="body_shape_exited">
- <argument index="0" name="body_rid" type="RID" />
- <argument index="1" name="body" type="Node" />
- <argument index="2" name="body_shape_index" type="int" />
- <argument index="3" name="local_shape_index" type="int" />
+ <param index="0" name="body_rid" type="RID" />
+ <param index="1" name="body" type="Node" />
+ <param index="2" name="body_shape_index" type="int" />
+ <param index="3" name="local_shape_index" type="int" />
<description>
- Emitted when the collision between one of this RigidDynamicBody2D's [Shape2D]s and another [PhysicsBody2D] or [TileMap]'s [Shape2D]s ends. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s.
- [code]body_rid[/code] the [RID] of the other [PhysicsBody2D] or [TileSet]'s [CollisionObject2D] used by the [PhysicsServer2D].
- [code]body[/code] the [Node], if it exists in the tree, of the other [PhysicsBody2D] or [TileMap].
- [code]body_shape_index[/code] the index of the [Shape2D] of the other [PhysicsBody2D] or [TileMap] used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code].
- [code]local_shape_index[/code] the index of the [Shape2D] of this RigidDynamicBody2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
+ Emitted when the collision between one of this RigidBody2D's [Shape2D]s and another [PhysicsBody2D] or [TileMap]'s [Shape2D]s ends. Requires [member contact_monitor] to be set to [code]true[/code] and [member max_contacts_reported] to be set high enough to detect all the collisions. [TileMap]s are detected if the [TileSet] has Collision [Shape2D]s.
+ [param body_rid] the [RID] of the other [PhysicsBody2D] or [TileSet]'s [CollisionObject2D] used by the [PhysicsServer2D].
+ [param body] the [Node], if it exists in the tree, of the other [PhysicsBody2D] or [TileMap].
+ [param body_shape_index] the index of the [Shape2D] of the other [PhysicsBody2D] or [TileMap] used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code].
+ [param local_shape_index] the index of the [Shape2D] of this RigidBody2D used by the [PhysicsServer2D]. Get the [CollisionShape2D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
</description>
</signal>
<signal name="sleeping_state_changed">
diff --git a/doc/classes/RigidDynamicBody3D.xml b/doc/classes/RigidBody3D.xml
index 285176b8b0..3ee3f25df1 100644
--- a/doc/classes/RigidDynamicBody3D.xml
+++ b/doc/classes/RigidBody3D.xml
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RigidDynamicBody3D" inherits="PhysicsBody3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="RigidBody3D" inherits="PhysicsBody3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Physics Body which is moved by 3D physics simulation. Useful for objects that have gravity and can be pushed by other objects.
</brief_description>
<description>
- This is the node that implements full 3D physics. This means that you do not control a RigidDynamicBody3D directly. Instead, you can apply forces to it (gravity, impulses, etc.), and the physics simulation will calculate the resulting movement, collision, bouncing, rotating, etc.
+ This is the node that implements full 3D physics. This means that you do not control a RigidBody3D directly. Instead, you can apply forces to it (gravity, impulses, etc.), and the physics simulation will calculate the resulting movement, collision, bouncing, rotating, etc.
You can switch the body's behavior using [member lock_rotation], [member freeze], and [member freeze_mode].
- [b]Note:[/b] Don't change a RigidDynamicBody3D'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.
+ [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].
</description>
<tutorials>
@@ -17,14 +17,14 @@
<methods>
<method name="_integrate_forces" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="state" type="PhysicsDirectBodyState3D" />
+ <param index="0" name="state" type="PhysicsDirectBodyState3D" />
<description>
Called during physics processing, allowing you to read and safely modify the simulation state for the object. By default, it works in addition to the usual physics behavior, but the [member custom_integrator] property allows you to disable the default behavior and do fully custom force integration for a body.
</description>
</method>
<method name="add_constant_central_force">
<return type="void" />
- <argument index="0" name="force" type="Vector3" />
+ <param index="0" name="force" type="Vector3" />
<description>
Adds a constant directional force without affecting rotation that keeps being applied over time until cleared with [code]constant_force = Vector3(0, 0, 0)[/code].
This is equivalent to using [method add_constant_force] at the body's center of mass.
@@ -32,23 +32,23 @@
</method>
<method name="add_constant_force">
<return type="void" />
- <argument index="0" name="force" type="Vector3" />
- <argument index="1" name="position" type="Vector3" default="Vector3(0, 0, 0)" />
+ <param index="0" name="force" type="Vector3" />
+ <param index="1" name="position" type="Vector3" default="Vector3(0, 0, 0)" />
<description>
Adds a constant positioned force to the body that keeps being applied over time until cleared with [code]constant_force = Vector3(0, 0, 0)[/code].
- [code]position[/code] is the offset from the body origin in global coordinates.
+ [param position] is the offset from the body origin in global coordinates.
</description>
</method>
<method name="add_constant_torque">
<return type="void" />
- <argument index="0" name="torque" type="Vector3" />
+ <param index="0" name="torque" type="Vector3" />
<description>
Adds a constant rotational force without affecting position that keeps being applied over time until cleared with [code]constant_torque = Vector3(0, 0, 0)[/code].
</description>
</method>
<method name="apply_central_force">
<return type="void" />
- <argument index="0" name="force" type="Vector3" />
+ <param index="0" name="force" type="Vector3" />
<description>
Applies a directional force without affecting rotation. A force is time dependent and meant to be applied every physics update.
This is equivalent to using [method apply_force] at the body's center of mass.
@@ -56,7 +56,7 @@
</method>
<method name="apply_central_impulse">
<return type="void" />
- <argument index="0" name="impulse" type="Vector3" />
+ <param index="0" name="impulse" type="Vector3" />
<description>
Applies a directional impulse without affecting rotation.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
@@ -65,54 +65,61 @@
</method>
<method name="apply_force">
<return type="void" />
- <argument index="0" name="force" type="Vector3" />
- <argument index="1" name="position" type="Vector3" default="Vector3(0, 0, 0)" />
+ <param index="0" name="force" type="Vector3" />
+ <param index="1" name="position" type="Vector3" default="Vector3(0, 0, 0)" />
<description>
Applies a positioned force to the body. A force is time dependent and meant to be applied every physics update.
- [code]position[/code] is the offset from the body origin in global coordinates.
+ [param position] is the offset from the body origin in global coordinates.
</description>
</method>
<method name="apply_impulse">
<return type="void" />
- <argument index="0" name="impulse" type="Vector3" />
- <argument index="1" name="position" type="Vector3" default="Vector3(0, 0, 0)" />
+ <param index="0" name="impulse" type="Vector3" />
+ <param index="1" name="position" type="Vector3" default="Vector3(0, 0, 0)" />
<description>
Applies a positioned impulse to the body.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
- [code]position[/code] is the offset from the body origin in global coordinates.
+ [param position] is the offset from the body origin in global coordinates.
</description>
</method>
<method name="apply_torque">
<return type="void" />
- <argument index="0" name="torque" type="Vector3" />
+ <param index="0" name="torque" type="Vector3" />
<description>
Applies a rotational force without affecting position. A force is time dependent and meant to be applied every physics update.
</description>
</method>
<method name="apply_torque_impulse">
<return type="void" />
- <argument index="0" name="impulse" type="Vector3" />
+ <param index="0" name="impulse" type="Vector3" />
<description>
Applies a rotational impulse to the body without affecting the position.
An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
</description>
</method>
<method name="get_colliding_bodies" qualifiers="const">
- <return type="Array" />
+ <return type="Node3D[]" />
<description>
- Returns a list of the bodies colliding with this one. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions.
+ Returns a list of the bodies colliding with this one. Requires [member contact_monitor] to be set to [code]true[/code] and [member max_contacts_reported] to be set high enough to detect all the collisions.
[b]Note:[/b] The result of this test is not immediate after moving objects. For performance, list of collisions is updated once per frame and before the physics step. Consider using signals instead.
</description>
</method>
+ <method name="get_contact_count" qualifiers="const">
+ <return type="int" />
+ <description>
+ Returns the number of contacts this body has with other bodies. By default, this returns 0 unless bodies are configured to monitor contacts (see [member contact_monitor]).
+ [b]Note:[/b] To retrieve the colliding bodies, use [method get_colliding_bodies].
+ </description>
+ </method>
<method name="get_inverse_inertia_tensor" qualifiers="const">
<return type="Basis" />
<description>
- Returns the inverse inertia tensor basis. This is used to calculate the angular acceleration resulting from a torque applied to the [RigidDynamicBody3D].
+ Returns the inverse inertia tensor basis. This is used to calculate the angular acceleration resulting from a torque applied to the [RigidBody3D].
</description>
</method>
<method name="set_axis_velocity">
<return type="void" />
- <argument index="0" name="axis_velocity" type="Vector3" />
+ <param index="0" name="axis_velocity" type="Vector3" />
<description>
Sets an axis velocity. The velocity in the given vector axis will be set as the given vector length. This is useful for jumping behavior.
</description>
@@ -123,11 +130,11 @@
Damps the body's rotation. By default, the body will use the [b]Default Angular Damp[/b] in [b]Project &gt; Project Settings &gt; Physics &gt; 3d[/b] or any value override set by an [Area3D] the body is in. Depending on [member angular_damp_mode], you can set [member angular_damp] to be added to or to replace the body's damping value.
See [member ProjectSettings.physics/3d/default_angular_damp] for more details about damping.
</member>
- <member name="angular_damp_mode" type="int" setter="set_angular_damp_mode" getter="get_angular_damp_mode" enum="RigidDynamicBody3D.DampMode" default="0">
+ <member name="angular_damp_mode" type="int" setter="set_angular_damp_mode" getter="get_angular_damp_mode" enum="RigidBody3D.DampMode" default="0">
Defines how [member angular_damp] is applied. See [enum DampMode] for possible values.
</member>
<member name="angular_velocity" type="Vector3" setter="set_angular_velocity" getter="get_angular_velocity" default="Vector3(0, 0, 0)">
- The RigidDynamicBody3D's rotational velocity in [i]radians[/i] per second.
+ The RigidBody3D's rotational velocity in [i]radians[/i] per second.
</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].
@@ -136,7 +143,7 @@
The body's custom center of mass, relative to the body's origin position, when [member center_of_mass_mode] is set to [constant CENTER_OF_MASS_MODE_CUSTOM]. This is the balanced point of the body, where applied forces only cause linear acceleration. Applying forces outside of the center of mass causes angular acceleration.
When [member center_of_mass_mode] is set to [constant CENTER_OF_MASS_MODE_AUTO] (default value), the center of mass is automatically computed.
</member>
- <member name="center_of_mass_mode" type="int" setter="set_center_of_mass_mode" getter="get_center_of_mass_mode" enum="RigidDynamicBody3D.CenterOfMassMode" default="0">
+ <member name="center_of_mass_mode" type="int" setter="set_center_of_mass_mode" getter="get_center_of_mass_mode" enum="RigidBody3D.CenterOfMassMode" default="0">
Defines the way the body's center of mass is set. See [enum CenterOfMassMode] for possible values.
</member>
<member name="constant_force" type="Vector3" setter="set_constant_force" getter="get_constant_force" default="Vector3(0, 0, 0)">
@@ -148,11 +155,8 @@
See [method add_constant_torque].
</member>
<member name="contact_monitor" type="bool" setter="set_contact_monitor" getter="is_contact_monitor_enabled" default="false">
- If [code]true[/code], the RigidDynamicBody3D will emit signals when it collides with another RigidDynamicBody3D. See also [member contacts_reported].
- </member>
- <member name="contacts_reported" type="int" setter="set_max_contacts_reported" getter="get_max_contacts_reported" default="0">
- The maximum number of contacts that will be recorded. Requires [member contact_monitor] to be set to [code]true[/code].
- [b]Note:[/b] The number of contacts is different from the number of collisions. Collisions between parallel edges will result in two contacts (one at each end), and collisions between parallel faces will result in four contacts (one at each corner).
+ If [code]true[/code], the RigidBody3D will emit signals when it collides with another RigidBody3D.
+ [b]Note:[/b] By default the maximum contacts reported is set to 0, meaning nothing will be recorded, see [member max_contacts_reported].
</member>
<member name="continuous_cd" type="bool" setter="set_use_continuous_collision_detection" getter="is_using_continuous_collision_detection" default="false">
If [code]true[/code], continuous collision detection is used.
@@ -166,12 +170,12 @@
See [member freeze_mode] to set the body's behavior when frozen.
For a body that is always frozen, use [StaticBody3D] or [AnimatableBody3D] instead.
</member>
- <member name="freeze_mode" type="int" setter="set_freeze_mode" getter="get_freeze_mode" enum="RigidDynamicBody3D.FreezeMode" default="0">
+ <member name="freeze_mode" type="int" setter="set_freeze_mode" getter="get_freeze_mode" enum="RigidBody3D.FreezeMode" default="0">
The body's freeze mode. Can be used to set the body's behavior when [member freeze] is enabled. See [enum FreezeMode] for possible values.
For a body that is always frozen, use [StaticBody3D] or [AnimatableBody3D] instead.
</member>
<member name="gravity_scale" type="float" setter="set_gravity_scale" getter="get_gravity_scale" default="1.0">
- This is multiplied by the global 3D gravity setting found in [b]Project &gt; Project Settings &gt; Physics &gt; 3d[/b] to produce RigidDynamicBody3D's gravity. For example, a value of 1 will be normal gravity, 2 will apply double gravity, and 0.5 will apply half gravity to this object.
+ This is multiplied by the global 3D gravity setting found in [b]Project &gt; Project Settings &gt; Physics &gt; 3d[/b] to produce RigidBody3D's gravity. For example, a value of 1 will be normal gravity, 2 will apply double gravity, and 0.5 will apply half gravity to this object.
</member>
<member name="inertia" type="Vector3" setter="set_inertia" getter="get_inertia" default="Vector3(0, 0, 0)">
The body's moment of inertia. This is like mass, but for rotation: it determines how much torque it takes to rotate the body on each axis. The moment of inertia is usually computed automatically from the mass and the shapes, but this property allows you to set a custom value.
@@ -181,7 +185,7 @@
Damps the body's movement. By default, the body will use the [b]Default Linear Damp[/b] in [b]Project &gt; Project Settings &gt; Physics &gt; 3d[/b] or any value override set by an [Area3D] the body is in. Depending on [member linear_damp_mode], you can set [member linear_damp] to be added to or to replace the body's damping value.
See [member ProjectSettings.physics/3d/default_linear_damp] for more details about damping.
</member>
- <member name="linear_damp_mode" type="int" setter="set_linear_damp_mode" getter="get_linear_damp_mode" enum="RigidDynamicBody3D.DampMode" default="0">
+ <member name="linear_damp_mode" type="int" setter="set_linear_damp_mode" getter="get_linear_damp_mode" enum="RigidBody3D.DampMode" default="0">
Defines how [member linear_damp] is applied. See [enum DampMode] for possible values.
</member>
<member name="linear_velocity" type="Vector3" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector3(0, 0, 0)">
@@ -193,6 +197,10 @@
<member name="mass" type="float" setter="set_mass" getter="get_mass" default="1.0">
The body's mass.
</member>
+ <member name="max_contacts_reported" type="int" setter="set_max_contacts_reported" getter="get_max_contacts_reported" default="0">
+ The maximum number of contacts that will be recorded. Requires a value greater than 0 and [member contact_monitor] to be set to [code]true[/code] to start to register contacts. Use [method get_contact_count] to retrieve the count or [method get_colliding_bodies] to retrieve bodies that have been collided with.
+ [b]Note:[/b] The number of contacts is different from the number of collisions. Collisions between parallel edges will result in two contacts (one at each end), and collisions between parallel faces will result in four contacts (one at each corner).
+ </member>
<member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override">
The physics material override for the body.
If a material is assigned to this property, it will be used instead of any other physics material, such as an inherited one.
@@ -203,43 +211,43 @@
</members>
<signals>
<signal name="body_entered">
- <argument index="0" name="body" type="Node" />
+ <param index="0" name="body" type="Node" />
<description>
- Emitted when a collision with another [PhysicsBody3D] or [GridMap] occurs. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s.
- [code]body[/code] the [Node], if it exists in the tree, of the other [PhysicsBody3D] or [GridMap].
+ Emitted when a collision with another [PhysicsBody3D] or [GridMap] occurs. Requires [member contact_monitor] to be set to [code]true[/code] and [member max_contacts_reported] to be set high enough to detect all the collisions. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s.
+ [param body] the [Node], if it exists in the tree, of the other [PhysicsBody3D] or [GridMap].
</description>
</signal>
<signal name="body_exited">
- <argument index="0" name="body" type="Node" />
+ <param index="0" name="body" type="Node" />
<description>
- Emitted when the collision with another [PhysicsBody3D] or [GridMap] ends. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s.
- [code]body[/code] the [Node], if it exists in the tree, of the other [PhysicsBody3D] or [GridMap].
+ Emitted when the collision with another [PhysicsBody3D] or [GridMap] ends. Requires [member contact_monitor] to be set to [code]true[/code] and [member max_contacts_reported] to be set high enough to detect all the collisions. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s.
+ [param body] the [Node], if it exists in the tree, of the other [PhysicsBody3D] or [GridMap].
</description>
</signal>
<signal name="body_shape_entered">
- <argument index="0" name="body_rid" type="RID" />
- <argument index="1" name="body" type="Node" />
- <argument index="2" name="body_shape_index" type="int" />
- <argument index="3" name="local_shape_index" type="int" />
+ <param index="0" name="body_rid" type="RID" />
+ <param index="1" name="body" type="Node" />
+ <param index="2" name="body_shape_index" type="int" />
+ <param index="3" name="local_shape_index" type="int" />
<description>
- Emitted when one of this RigidDynamicBody3D's [Shape3D]s collides with another [PhysicsBody3D] or [GridMap]'s [Shape3D]s. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s.
- [code]body_rid[/code] the [RID] of the other [PhysicsBody3D] or [MeshLibrary]'s [CollisionObject3D] used by the [PhysicsServer3D].
- [code]body[/code] the [Node], if it exists in the tree, of the other [PhysicsBody3D] or [GridMap].
- [code]body_shape_index[/code] the index of the [Shape3D] of the other [PhysicsBody3D] or [GridMap] used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code].
- [code]local_shape_index[/code] the index of the [Shape3D] of this RigidDynamicBody3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
+ Emitted when one of this RigidBody3D's [Shape3D]s collides with another [PhysicsBody3D] or [GridMap]'s [Shape3D]s. Requires [member contact_monitor] to be set to [code]true[/code] and [member max_contacts_reported] to be set high enough to detect all the collisions. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s.
+ [param body_rid] the [RID] of the other [PhysicsBody3D] or [MeshLibrary]'s [CollisionObject3D] used by the [PhysicsServer3D].
+ [param body] the [Node], if it exists in the tree, of the other [PhysicsBody3D] or [GridMap].
+ [param body_shape_index] the index of the [Shape3D] of the other [PhysicsBody3D] or [GridMap] used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code].
+ [param local_shape_index] the index of the [Shape3D] of this RigidBody3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
</description>
</signal>
<signal name="body_shape_exited">
- <argument index="0" name="body_rid" type="RID" />
- <argument index="1" name="body" type="Node" />
- <argument index="2" name="body_shape_index" type="int" />
- <argument index="3" name="local_shape_index" type="int" />
+ <param index="0" name="body_rid" type="RID" />
+ <param index="1" name="body" type="Node" />
+ <param index="2" name="body_shape_index" type="int" />
+ <param index="3" name="local_shape_index" type="int" />
<description>
- Emitted when the collision between one of this RigidDynamicBody3D's [Shape3D]s and another [PhysicsBody3D] or [GridMap]'s [Shape3D]s ends. Requires [member contact_monitor] to be set to [code]true[/code] and [member contacts_reported] to be set high enough to detect all the collisions. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s.
- [code]body_rid[/code] the [RID] of the other [PhysicsBody3D] or [MeshLibrary]'s [CollisionObject3D] used by the [PhysicsServer3D]. [GridMap]s are detected if the Meshes have [Shape3D]s.
- [code]body[/code] the [Node], if it exists in the tree, of the other [PhysicsBody3D] or [GridMap].
- [code]body_shape_index[/code] the index of the [Shape3D] of the other [PhysicsBody3D] or [GridMap] used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code].
- [code]local_shape_index[/code] the index of the [Shape3D] of this RigidDynamicBody3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
+ Emitted when the collision between one of this RigidBody3D's [Shape3D]s and another [PhysicsBody3D] or [GridMap]'s [Shape3D]s ends. Requires [member contact_monitor] to be set to [code]true[/code] and [member max_contacts_reported] to be set high enough to detect all the collisions. [GridMap]s are detected if the [MeshLibrary] has Collision [Shape3D]s.
+ [param body_rid] the [RID] of the other [PhysicsBody3D] or [MeshLibrary]'s [CollisionObject3D] used by the [PhysicsServer3D]. [GridMap]s are detected if the Meshes have [Shape3D]s.
+ [param body] the [Node], if it exists in the tree, of the other [PhysicsBody3D] or [GridMap].
+ [param body_shape_index] the index of the [Shape3D] of the other [PhysicsBody3D] or [GridMap] used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]body.shape_owner_get_owner(body.shape_find_owner(body_shape_index))[/code].
+ [param local_shape_index] the index of the [Shape3D] of this RigidBody3D used by the [PhysicsServer3D]. Get the [CollisionShape3D] node with [code]self.shape_owner_get_owner(self.shape_find_owner(local_shape_index))[/code].
</description>
</signal>
<signal name="sleeping_state_changed">
diff --git a/doc/classes/RootMotionView.xml b/doc/classes/RootMotionView.xml
index 88b8f2cd03..3f3b00e2cb 100644
--- a/doc/classes/RootMotionView.xml
+++ b/doc/classes/RootMotionView.xml
@@ -5,25 +5,25 @@
</brief_description>
<description>
[i]Root motion[/i] refers to an animation technique where a mesh's skeleton is used to give impulse to a character. When working with 3D animations, a popular technique is for animators to use the root skeleton bone to give motion to the rest of the skeleton. This allows animating characters in a way where steps actually match the floor below. It also allows precise interaction with objects during cinematics. See also [AnimationTree].
- [b]Note:[/b] [RootMotionView] is only visible in the editor. It will be hidden automatically in the running project, and will also be converted to a plain [Node] in the running project. This means a script attached to a [RootMotionView] node [i]must[/i] have [code]extends Node[/code] instead of [code]extends RootMotionView[/code]. Additionally, it must not be a [code]@tool[/code] script.
+ [b]Note:[/b] [RootMotionView] is only visible in the editor. It will be hidden automatically in the running project.
</description>
<tutorials>
<link title="Using AnimationTree - Root motion">$DOCS_URL/tutorials/animation/animation_tree.html#root-motion</link>
</tutorials>
<members>
- <member name="animation_path" type="NodePath" setter="set_animation_path" getter="get_animation_path">
+ <member name="animation_path" type="NodePath" setter="set_animation_path" getter="get_animation_path" default="NodePath(&quot;&quot;)">
Path to an [AnimationTree] node to use as a basis for root motion.
</member>
- <member name="cell_size" type="float" setter="set_cell_size" getter="get_cell_size">
+ <member name="cell_size" type="float" setter="set_cell_size" getter="get_cell_size" default="1.0">
The grid's cell size in 3D units.
</member>
- <member name="color" type="Color" setter="set_color" getter="get_color">
+ <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(0.5, 0.5, 1, 1)">
The grid's color.
</member>
- <member name="radius" type="float" setter="set_radius" getter="get_radius">
+ <member name="radius" type="float" setter="set_radius" getter="get_radius" default="10.0">
The grid's radius in 3D units. The grid's opacity will fade gradually as the distance from the origin increases until this [member radius] is reached.
</member>
- <member name="zero_y" type="bool" setter="set_zero_y" getter="get_zero_y">
+ <member name="zero_y" type="bool" setter="set_zero_y" getter="get_zero_y" default="true">
If [code]true[/code], the grid's points will all be on the same Y coordinate ([i]local[/i] Y = 0). If [code]false[/code], the points' original Y coordinate is preserved.
</member>
</members>
diff --git a/doc/classes/SceneState.xml b/doc/classes/SceneState.xml
index d226577a95..acb29838ba 100644
--- a/doc/classes/SceneState.xml
+++ b/doc/classes/SceneState.xml
@@ -12,9 +12,9 @@
<methods>
<method name="get_connection_binds" qualifiers="const">
<return type="Array" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the list of bound parameters for the signal at [code]idx[/code].
+ Returns the list of bound parameters for the signal at [param idx].
</description>
</method>
<method name="get_connection_count" qualifiers="const">
@@ -26,44 +26,44 @@
</method>
<method name="get_connection_flags" qualifiers="const">
<return type="int" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the connection flags for the signal at [code]idx[/code]. See [enum Object.ConnectFlags] constants.
+ Returns the connection flags for the signal at [param idx]. See [enum Object.ConnectFlags] constants.
</description>
</method>
<method name="get_connection_method" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the method connected to the signal at [code]idx[/code].
+ Returns the method connected to the signal at [param idx].
</description>
</method>
<method name="get_connection_signal" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the name of the signal at [code]idx[/code].
+ Returns the name of the signal at [param idx].
</description>
</method>
<method name="get_connection_source" qualifiers="const">
<return type="NodePath" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the path to the node that owns the signal at [code]idx[/code], relative to the root node.
+ Returns the path to the node that owns the signal at [param idx], relative to the root node.
</description>
</method>
<method name="get_connection_target" qualifiers="const">
<return type="NodePath" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the path to the node that owns the method connected to the signal at [code]idx[/code], relative to the root node.
+ Returns the path to the node that owns the method connected to the signal at [param idx], relative to the root node.
</description>
</method>
<method name="get_connection_unbinds" qualifiers="const">
<return type="int" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the number of unbound parameters for the signal at [code]idx[/code].
+ Returns the number of unbound parameters for the signal at [param idx].
</description>
</method>
<method name="get_node_count" qualifiers="const">
@@ -75,91 +75,91 @@
</method>
<method name="get_node_groups" qualifiers="const">
<return type="PackedStringArray" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the list of group names associated with the node at [code]idx[/code].
+ Returns the list of group names associated with the node at [param idx].
</description>
</method>
<method name="get_node_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the node's index, which is its position relative to its siblings. This is only relevant and saved in scenes for cases where new nodes are added to an instantiated or inherited scene among siblings from the base scene. Despite the name, this index is not related to the [code]idx[/code] argument used here and in other methods.
+ Returns the node's index, which is its position relative to its siblings. This is only relevant and saved in scenes for cases where new nodes are added to an instantiated or inherited scene among siblings from the base scene. Despite the name, this index is not related to the [param idx] argument used here and in other methods.
</description>
</method>
<method name="get_node_instance" qualifiers="const">
<return type="PackedScene" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns a [PackedScene] for the node at [code]idx[/code] (i.e. the whole branch starting at this node, with its child nodes and resources), or [code]null[/code] if the node is not an instance.
+ Returns a [PackedScene] for the node at [param idx] (i.e. the whole branch starting at this node, with its child nodes and resources), or [code]null[/code] if the node is not an instance.
</description>
</method>
<method name="get_node_instance_placeholder" qualifiers="const">
<return type="String" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the path to the represented scene file if the node at [code]idx[/code] is an [InstancePlaceholder].
+ Returns the path to the represented scene file if the node at [param idx] is an [InstancePlaceholder].
</description>
</method>
<method name="get_node_name" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the name of the node at [code]idx[/code].
+ Returns the name of the node at [param idx].
</description>
</method>
<method name="get_node_owner_path" qualifiers="const">
<return type="NodePath" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the path to the owner of the node at [code]idx[/code], relative to the root node.
+ Returns the path to the owner of the node at [param idx], relative to the root node.
</description>
</method>
<method name="get_node_path" qualifiers="const">
<return type="NodePath" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="for_parent" type="bool" default="false" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="for_parent" type="bool" default="false" />
<description>
- Returns the path to the node at [code]idx[/code].
- If [code]for_parent[/code] is [code]true[/code], returns the path of the [code]idx[/code] node's parent instead.
+ Returns the path to the node at [param idx].
+ If [param for_parent] is [code]true[/code], returns the path of the [param idx] node's parent instead.
</description>
</method>
<method name="get_node_property_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the number of exported or overridden properties for the node at [code]idx[/code].
+ Returns the number of exported or overridden properties for the node at [param idx].
The [code]prop_idx[/code] argument used to query node property data in other [code]get_node_property_*[/code] methods in the interval [code][0, get_node_property_count() - 1][/code].
</description>
</method>
<method name="get_node_property_name" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="prop_idx" type="int" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="prop_idx" type="int" />
<description>
- Returns the name of the property at [code]prop_idx[/code] for the node at [code]idx[/code].
+ Returns the name of the property at [param prop_idx] for the node at [param idx].
</description>
</method>
<method name="get_node_property_value" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="idx" type="int" />
- <argument index="1" name="prop_idx" type="int" />
+ <param index="0" name="idx" type="int" />
+ <param index="1" name="prop_idx" type="int" />
<description>
- Returns the value of the property at [code]prop_idx[/code] for the node at [code]idx[/code].
+ Returns the value of the property at [param prop_idx] for the node at [param idx].
</description>
</method>
<method name="get_node_type" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the type of the node at [code]idx[/code].
+ Returns the type of the node at [param idx].
</description>
</method>
<method name="is_node_instance_placeholder" qualifiers="const">
<return type="bool" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns [code]true[/code] if the node at [code]idx[/code] is an [InstancePlaceholder].
+ Returns [code]true[/code] if the node at [param idx] is an [InstancePlaceholder].
</description>
</method>
</methods>
diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml
index 9982cc0d60..417703ff01 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -15,39 +15,39 @@
<methods>
<method name="call_group" qualifiers="vararg">
<return type="void" />
- <argument index="0" name="group" type="StringName" />
- <argument index="1" name="method" type="StringName" />
+ <param index="0" name="group" type="StringName" />
+ <param index="1" name="method" type="StringName" />
<description>
- Calls [code]method[/code] on each member of the given group. You can pass arguments to [code]method[/code] by specifying them at the end of the method call. If a node doesn't have the given method or the argument list does not match (either in count or in types), it will be skipped.
+ Calls [param method] on each member of the given group. You can pass arguments to [param method] by specifying them at the end of the method call. If a node doesn't have the given method or the argument list does not match (either in count or in types), it will be skipped.
[b]Note:[/b] [method call_group] will call methods immediately on all members at once, which can cause stuttering if an expensive method is called on lots of members. To wait for one frame after [method call_group] was called, use [method call_group_flags] with the [constant GROUP_CALL_DEFERRED] flag.
</description>
</method>
<method name="call_group_flags" qualifiers="vararg">
<return type="void" />
- <argument index="0" name="flags" type="int" />
- <argument index="1" name="group" type="StringName" />
- <argument index="2" name="method" type="StringName" />
+ <param index="0" name="flags" type="int" />
+ <param index="1" name="group" type="StringName" />
+ <param index="2" name="method" type="StringName" />
<description>
- Calls [code]method[/code] on each member of the given group, respecting the given [enum GroupCallFlags]. You can pass arguments to [code]method[/code] by specifying them at the end of the method call. If a node doesn't have the given method or the argument list does not match (either in count or in types), it will be skipped.
+ Calls [param method] on each member of the given group, respecting the given [enum GroupCallFlags]. You can pass arguments to [param method] by specifying them at the end of the method call. If a node doesn't have the given method or the argument list does not match (either in count or in types), it will be skipped.
[codeblock]
# Call the method in a deferred manner and in reverse order.
get_tree().call_group_flags(SceneTree.GROUP_CALL_DEFERRED | SceneTree.GROUP_CALL_REVERSE)
[/codeblock]
- [b]Note:[/b] Group call flags are used to control the method calling behavior. By default, methods will be called immediately in a way similar to [method call_group]. However, if the [constant GROUP_CALL_DEFERRED] flag is present in the [code]flags[/code] argument, methods will be called with a one-frame delay in a way similar to [method Object.set_deferred].
+ [b]Note:[/b] Group call flags are used to control the method calling behavior. By default, methods will be called immediately in a way similar to [method call_group]. However, if the [constant GROUP_CALL_DEFERRED] flag is present in the [param flags] argument, methods will be called with a one-frame delay in a way similar to [method Object.set_deferred].
</description>
</method>
<method name="change_scene">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
- Changes the running scene to the one at the given [code]path[/code], after loading it into a [PackedScene] and creating a new instance.
- Returns [constant OK] on success, [constant ERR_CANT_OPEN] if the [code]path[/code] cannot be loaded into a [PackedScene], or [constant ERR_CANT_CREATE] if that scene cannot be instantiated.
+ Changes the running scene to the one at the given [param path], after loading it into a [PackedScene] and creating a new instance.
+ Returns [constant OK] on success, [constant ERR_CANT_OPEN] if the [param path] cannot be loaded into a [PackedScene], or [constant ERR_CANT_CREATE] if that scene cannot be instantiated.
[b]Note:[/b] The scene change is deferred, which means that the new scene node is added on the next idle frame. You won't be able to access it immediately after the [method change_scene] call.
</description>
</method>
<method name="change_scene_to">
<return type="int" enum="Error" />
- <argument index="0" name="packed_scene" type="PackedScene" />
+ <param index="0" name="packed_scene" type="PackedScene" />
<description>
Changes the running scene to a new instance of the given [PackedScene].
Returns [constant OK] on success or [constant ERR_CANT_CREATE] if the scene cannot be instantiated.
@@ -56,10 +56,10 @@
</method>
<method name="create_timer">
<return type="SceneTreeTimer" />
- <argument index="0" name="time_sec" type="float" />
- <argument index="1" name="process_always" type="bool" default="true" />
+ <param index="0" name="time_sec" type="float" />
+ <param index="1" name="process_always" type="bool" default="true" />
<description>
- Returns a [SceneTreeTimer] which will [signal SceneTreeTimer.timeout] after the given time in seconds elapsed in this [SceneTree]. If [code]process_always[/code] is set to [code]false[/code], pausing the [SceneTree] will also pause the timer.
+ Returns a [SceneTreeTimer] which will [signal SceneTreeTimer.timeout] after the given time in seconds elapsed in this [SceneTree]. If [param process_always] is set to [code]false[/code], pausing the [SceneTree] will also pause the timer.
Commonly used to create a one-shot delay timer as in the following example:
[codeblocks]
[gdscript]
@@ -88,7 +88,7 @@
</method>
<method name="get_first_node_in_group">
<return type="Node" />
- <argument index="0" name="group" type="StringName" />
+ <param index="0" name="group" type="StringName" />
<description>
Returns the first node in the specified group, or [code]null[/code] if the group is empty or does not exist.
</description>
@@ -101,9 +101,9 @@
</method>
<method name="get_multiplayer" qualifiers="const">
<return type="MultiplayerAPI" />
- <argument index="0" name="for_path" type="NodePath" default="NodePath(&quot;&quot;)" />
+ <param index="0" name="for_path" type="NodePath" default="NodePath(&quot;&quot;)" />
<description>
- Return the [MultiplayerAPI] configured for the given path, or the default one if [code]for_path[/code] is empty.
+ Return the [MultiplayerAPI] configured for the given path, or the default one if [param for_path] is empty.
</description>
</method>
<method name="get_node_count" qualifiers="const">
@@ -113,56 +113,56 @@
</description>
</method>
<method name="get_nodes_in_group">
- <return type="Array" />
- <argument index="0" name="group" type="StringName" />
+ <return type="Node[]" />
+ <param index="0" name="group" type="StringName" />
<description>
Returns a list of all nodes assigned to the given group.
</description>
</method>
<method name="get_processed_tweens">
- <return type="Array" />
+ <return type="Tween[]" />
<description>
Returns an array of currently existing [Tween]s in the [SceneTree] (both running and paused).
</description>
</method>
<method name="has_group" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
Returns [code]true[/code] if the given group exists.
</description>
</method>
<method name="notify_group">
<return type="void" />
- <argument index="0" name="group" type="StringName" />
- <argument index="1" name="notification" type="int" />
+ <param index="0" name="group" type="StringName" />
+ <param index="1" name="notification" type="int" />
<description>
- Sends the given notification to all members of the [code]group[/code].
+ Sends the given notification to all members of the [param group].
[b]Note:[/b] [method notify_group] will immediately notify all members at once, which can cause stuttering if an expensive method is called as a result of sending the notification lots of members. To wait for one frame, use [method notify_group_flags] with the [constant GROUP_CALL_DEFERRED] flag.
</description>
</method>
<method name="notify_group_flags">
<return type="void" />
- <argument index="0" name="call_flags" type="int" />
- <argument index="1" name="group" type="StringName" />
- <argument index="2" name="notification" type="int" />
+ <param index="0" name="call_flags" type="int" />
+ <param index="1" name="group" type="StringName" />
+ <param index="2" name="notification" type="int" />
<description>
- Sends the given notification to all members of the [code]group[/code], respecting the given [enum GroupCallFlags].
- [b]Note:[/b] Group call flags are used to control the notification sending behavior. By default, notifications will be sent immediately in a way similar to [method notify_group]. However, if the [constant GROUP_CALL_DEFERRED] flag is present in the [code]flags[/code] argument, notifications will be sent with a one-frame delay in a way similar to using [code]Object.call_deferred("notification", ...)[/code].
+ Sends the given notification to all members of the [param group], respecting the given [enum GroupCallFlags].
+ [b]Note:[/b] Group call flags are used to control the notification sending behavior. By default, notifications will be sent immediately in a way similar to [method notify_group]. However, if the [constant GROUP_CALL_DEFERRED] flag is present in the [param call_flags] argument, notifications will be sent with a one-frame delay in a way similar to using [code]Object.call_deferred("notification", ...)[/code].
</description>
</method>
<method name="queue_delete">
<return type="void" />
- <argument index="0" name="obj" type="Object" />
+ <param index="0" name="obj" type="Object" />
<description>
Queues the given object for deletion, delaying the call to [method Object.free] to after the current frame.
</description>
</method>
<method name="quit">
<return type="void" />
- <argument index="0" name="exit_code" type="int" default="0" />
+ <param index="0" name="exit_code" type="int" default="0" />
<description>
- Quits the application at the end of the current iteration. Argument [code]exit_code[/code] can optionally be given (defaulting to 0) to customize the exit status code.
+ Quits the application at the end of the current iteration. Argument [param exit_code] can optionally be given (defaulting to 0) to customize the exit status code.
By convention, an exit code of [code]0[/code] indicates success whereas a non-zero exit code indicates an error.
For portability reasons, the exit code should be set between 0 and 125 (inclusive).
[b]Note:[/b] On iOS this method doesn't work. Instead, as recommended by the iOS Human Interface Guidelines, the user is expected to close apps via the Home button.
@@ -177,31 +177,31 @@
</method>
<method name="set_group">
<return type="void" />
- <argument index="0" name="group" type="StringName" />
- <argument index="1" name="property" type="String" />
- <argument index="2" name="value" type="Variant" />
+ <param index="0" name="group" type="StringName" />
+ <param index="1" name="property" type="String" />
+ <param index="2" name="value" type="Variant" />
<description>
- Sets the given [code]property[/code] to [code]value[/code] on all members of the given group.
+ Sets the given [param property] to [param value] on all members of the given group.
[b]Note:[/b] [method set_group] will set the property immediately on all members at once, which can cause stuttering if a property with an expensive setter is set on lots of members. To wait for one frame, use [method set_group_flags] with the [constant GROUP_CALL_DEFERRED] flag.
</description>
</method>
<method name="set_group_flags">
<return type="void" />
- <argument index="0" name="call_flags" type="int" />
- <argument index="1" name="group" type="StringName" />
- <argument index="2" name="property" type="String" />
- <argument index="3" name="value" type="Variant" />
+ <param index="0" name="call_flags" type="int" />
+ <param index="1" name="group" type="StringName" />
+ <param index="2" name="property" type="String" />
+ <param index="3" name="value" type="Variant" />
<description>
- Sets the given [code]property[/code] to [code]value[/code] on all members of the given group, respecting the given [enum GroupCallFlags].
- [b]Note:[/b] Group call flags are used to control the property setting behavior. By default, properties will be set immediately in a way similar to [method set_group]. However, if the [constant GROUP_CALL_DEFERRED] flag is present in the [code]flags[/code] argument, properties will be set with a one-frame delay in a way similar to [method Object.call_deferred].
+ Sets the given [param property] to [param value] on all members of the given group, respecting the given [enum GroupCallFlags].
+ [b]Note:[/b] Group call flags are used to control the property setting behavior. By default, properties will be set immediately in a way similar to [method set_group]. However, if the [constant GROUP_CALL_DEFERRED] flag is present in the [param call_flags] argument, properties will be set with a one-frame delay in a way similar to [method Object.call_deferred].
</description>
</method>
<method name="set_multiplayer">
<return type="void" />
- <argument index="0" name="multiplayer" type="MultiplayerAPI" />
- <argument index="1" name="root_path" type="NodePath" default="NodePath(&quot;&quot;)" />
+ <param index="0" name="multiplayer" type="MultiplayerAPI" />
+ <param index="1" name="root_path" type="NodePath" default="NodePath(&quot;&quot;)" />
<description>
- Sets a custom [MultiplayerAPI] with the given [code]root_path[/code] (controlling also the relative subpaths), or override the default one if [code]root_path[/code] is empty.
+ Sets a custom [MultiplayerAPI] with the given [param root_path] (controlling also the relative subpaths), or override the default one if [param root_path] is empty.
</description>
</method>
</methods>
@@ -215,12 +215,15 @@
</member>
<member name="debug_collisions_hint" type="bool" setter="set_debug_collisions_hint" getter="is_debugging_collisions_hint" default="false">
If [code]true[/code], collision shapes will be visible when running the game from the editor for debugging purposes.
+ [b]Note:[/b] This property is not designed to be changed at run-time. Changing the value of [member debug_collisions_hint] while the project is running will not have the desired effect.
</member>
<member name="debug_navigation_hint" type="bool" setter="set_debug_navigation_hint" getter="is_debugging_navigation_hint" default="false">
If [code]true[/code], navigation polygons will be visible when running the game from the editor for debugging purposes.
+ [b]Note:[/b] This property is not designed to be changed at run-time. Changing the value of [member debug_navigation_hint] while the project is running will not have the desired effect.
</member>
<member name="debug_paths_hint" type="bool" setter="set_debug_paths_hint" getter="is_debugging_paths_hint" default="false">
If [code]true[/code], curves from [Path2D] and [Path3D] nodes will be visible when running the game from the editor for debugging purposes.
+ [b]Note:[/b] This property is not designed to be changed at run-time. Changing the value of [member debug_paths_hint] while the project is running will not have the desired effect.
</member>
<member name="edited_scene_root" type="Node" setter="set_edited_scene_root" getter="get_edited_scene_root">
The root of the edited scene.
@@ -244,25 +247,25 @@
</members>
<signals>
<signal name="node_added">
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
Emitted whenever a node is added to the [SceneTree].
</description>
</signal>
<signal name="node_configuration_warning_changed">
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
Emitted when a node's configuration changed. Only emitted in [code]tool[/code] mode.
</description>
</signal>
<signal name="node_removed">
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
Emitted whenever a node is removed from the [SceneTree].
</description>
</signal>
<signal name="node_renamed">
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
Emitted whenever a node is renamed.
</description>
diff --git a/doc/classes/Script.xml b/doc/classes/Script.xml
index cd8841c8c5..40ec8ed429 100644
--- a/doc/classes/Script.xml
+++ b/doc/classes/Script.xml
@@ -32,7 +32,7 @@
</method>
<method name="get_property_default_value">
<return type="Variant" />
- <argument index="0" name="property" type="StringName" />
+ <param index="0" name="property" type="StringName" />
<description>
Returns the default value of the specified property.
</description>
@@ -44,26 +44,26 @@
</description>
</method>
<method name="get_script_method_list">
- <return type="Array" />
+ <return type="Dictionary[]" />
<description>
Returns the list of methods in this [Script].
</description>
</method>
<method name="get_script_property_list">
- <return type="Array" />
+ <return type="Dictionary[]" />
<description>
Returns the list of properties in this [Script].
</description>
</method>
<method name="get_script_signal_list">
- <return type="Array" />
+ <return type="Dictionary[]" />
<description>
Returns the list of user signals defined in this [Script].
</description>
</method>
<method name="has_script_signal" qualifiers="const">
<return type="bool" />
- <argument index="0" name="signal_name" type="StringName" />
+ <param index="0" name="signal_name" type="StringName" />
<description>
Returns [code]true[/code] if the script, or a base class, defines a signal with the given name.
</description>
@@ -76,9 +76,9 @@
</method>
<method name="instance_has" qualifiers="const">
<return type="bool" />
- <argument index="0" name="base_object" type="Object" />
+ <param index="0" name="base_object" type="Object" />
<description>
- Returns [code]true[/code] if [code]base_object[/code] is an instance of this script.
+ Returns [code]true[/code] if [param base_object] is an instance of this script.
</description>
</method>
<method name="is_tool" qualifiers="const">
@@ -89,7 +89,7 @@
</method>
<method name="reload">
<return type="int" enum="Error" />
- <argument index="0" name="keep_state" type="bool" default="false" />
+ <param index="0" name="keep_state" type="bool" default="false" />
<description>
Reloads the script's class implementation. Returns an error code.
</description>
diff --git a/doc/classes/ScriptCreateDialog.xml b/doc/classes/ScriptCreateDialog.xml
index 79ee95719d..6b608aca4f 100644
--- a/doc/classes/ScriptCreateDialog.xml
+++ b/doc/classes/ScriptCreateDialog.xml
@@ -29,10 +29,10 @@
<methods>
<method name="config">
<return type="void" />
- <argument index="0" name="inherits" type="String" />
- <argument index="1" name="path" type="String" />
- <argument index="2" name="built_in_enabled" type="bool" default="true" />
- <argument index="3" name="load_enabled" type="bool" default="true" />
+ <param index="0" name="inherits" type="String" />
+ <param index="1" name="path" type="String" />
+ <param index="2" name="built_in_enabled" type="bool" default="true" />
+ <param index="3" name="load_enabled" type="bool" default="true" />
<description>
Prefills required fields to configure the ScriptCreateDialog for use.
</description>
@@ -45,7 +45,7 @@
</members>
<signals>
<signal name="script_created">
- <argument index="0" name="script" type="Script" />
+ <param index="0" name="script" type="Script" />
<description>
Emitted when the user clicks the OK button.
</description>
diff --git a/doc/classes/ScriptEditor.xml b/doc/classes/ScriptEditor.xml
index 92488b2392..becaff975e 100644
--- a/doc/classes/ScriptEditor.xml
+++ b/doc/classes/ScriptEditor.xml
@@ -22,35 +22,35 @@
</description>
</method>
<method name="get_open_script_editors" qualifiers="const">
- <return type="Array" />
+ <return type="ScriptEditorBase[]" />
<description>
Returns an array with all [ScriptEditorBase] objects which are currently open in editor.
</description>
</method>
<method name="get_open_scripts" qualifiers="const">
- <return type="Array" />
+ <return type="Script[]" />
<description>
Returns an array with all [Script] objects which are currently open in editor.
</description>
</method>
<method name="goto_line">
<return type="void" />
- <argument index="0" name="line_number" type="int" />
+ <param index="0" name="line_number" type="int" />
<description>
Goes to the specified line in the current script.
</description>
</method>
<method name="open_script_create_dialog">
<return type="void" />
- <argument index="0" name="base_name" type="String" />
- <argument index="1" name="base_path" type="String" />
+ <param index="0" name="base_name" type="String" />
+ <param index="1" name="base_path" type="String" />
<description>
- Opens the script create dialog. The script will extend [code]base_name[/code]. The file extension can be omitted from [code]base_path[/code]. It will be added based on the selected scripting language.
+ Opens the script create dialog. The script will extend [param base_name]. The file extension can be omitted from [param base_path]. It will be added based on the selected scripting language.
</description>
</method>
<method name="register_syntax_highlighter">
<return type="void" />
- <argument index="0" name="syntax_highlighter" type="EditorSyntaxHighlighter" />
+ <param index="0" name="syntax_highlighter" type="EditorSyntaxHighlighter" />
<description>
Registers the [EditorSyntaxHighlighter] to the editor, the [EditorSyntaxHighlighter] will be available on all open scripts.
[b]Note:[/b] Does not apply to scripts that are already opened.
@@ -58,7 +58,7 @@
</method>
<method name="unregister_syntax_highlighter">
<return type="void" />
- <argument index="0" name="syntax_highlighter" type="EditorSyntaxHighlighter" />
+ <param index="0" name="syntax_highlighter" type="EditorSyntaxHighlighter" />
<description>
Unregisters the [EditorSyntaxHighlighter] from the editor.
[b]Note:[/b] The [EditorSyntaxHighlighter] will still be applied to scripts that are already opened.
@@ -67,13 +67,13 @@
</methods>
<signals>
<signal name="editor_script_changed">
- <argument index="0" name="script" type="Script" />
+ <param index="0" name="script" type="Script" />
<description>
Emitted when user changed active script. Argument is a freshly activated [Script].
</description>
</signal>
<signal name="script_close">
- <argument index="0" name="script" type="Script" />
+ <param index="0" name="script" type="Script" />
<description>
Emitted when editor is about to close the active script. Argument is a [Script] that is going to be closed.
</description>
diff --git a/doc/classes/ScriptEditorBase.xml b/doc/classes/ScriptEditorBase.xml
index 3bed1127ee..c365e0971b 100644
--- a/doc/classes/ScriptEditorBase.xml
+++ b/doc/classes/ScriptEditorBase.xml
@@ -11,7 +11,7 @@
<methods>
<method name="add_syntax_highlighter">
<return type="void" />
- <argument index="0" name="highlighter" type="EditorSyntaxHighlighter" />
+ <param index="0" name="highlighter" type="EditorSyntaxHighlighter" />
<description>
Adds a [EditorSyntaxHighlighter] to the open script.
</description>
@@ -30,7 +30,7 @@
</description>
</signal>
<signal name="go_to_help">
- <argument index="0" name="what" type="String" />
+ <param index="0" name="what" type="String" />
<description>
Emitted when the user requests a specific documentation page.
</description>
@@ -41,20 +41,20 @@
</description>
</signal>
<signal name="replace_in_files_requested">
- <argument index="0" name="text" type="String" />
+ <param index="0" name="text" type="String" />
<description>
Emitted when the user request to find and replace text in the file system. Not used by visual scripts.
</description>
</signal>
<signal name="request_help">
- <argument index="0" name="topic" type="String" />
+ <param index="0" name="topic" type="String" />
<description>
Emitted when the user requests contextual help.
</description>
</signal>
<signal name="request_open_script_at_line">
- <argument index="0" name="script" type="Object" />
- <argument index="1" name="line" type="int" />
+ <param index="0" name="script" type="Object" />
+ <param index="1" name="line" type="int" />
<description>
Emitted when the user requests a script.
</description>
@@ -65,7 +65,7 @@
</description>
</signal>
<signal name="search_in_files_requested">
- <argument index="0" name="text" type="String" />
+ <param index="0" name="text" type="String" />
<description>
Emitted when the user request to search text in the file system. Not used by visual scripts.
</description>
diff --git a/doc/classes/ScriptExtension.xml b/doc/classes/ScriptExtension.xml
index 4e432ca9a8..045eadda41 100644
--- a/doc/classes/ScriptExtension.xml
+++ b/doc/classes/ScriptExtension.xml
@@ -44,7 +44,7 @@
</method>
<method name="_get_member_line" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="member" type="StringName" />
+ <param index="0" name="member" type="StringName" />
<description>
</description>
</method>
@@ -55,13 +55,13 @@
</method>
<method name="_get_method_info" qualifiers="virtual const">
<return type="Dictionary" />
- <argument index="0" name="method" type="StringName" />
+ <param index="0" name="method" type="StringName" />
<description>
</description>
</method>
<method name="_get_property_default_value" qualifiers="virtual const">
<return type="Variant" />
- <argument index="0" name="property" type="StringName" />
+ <param index="0" name="property" type="StringName" />
<description>
</description>
</method>
@@ -92,13 +92,19 @@
</method>
<method name="_has_method" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="method" type="StringName" />
+ <param index="0" name="method" type="StringName" />
+ <description>
+ </description>
+ </method>
+ <method name="_has_property_default_value" qualifiers="virtual const">
+ <return type="bool" />
+ <param index="0" name="property" type="StringName" />
<description>
</description>
</method>
<method name="_has_script_signal" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="signal" type="StringName" />
+ <param index="0" name="signal" type="StringName" />
<description>
</description>
</method>
@@ -109,19 +115,19 @@
</method>
<method name="_inherits_script" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="script" type="Script" />
+ <param index="0" name="script" type="Script" />
<description>
</description>
</method>
<method name="_instance_create" qualifiers="virtual const">
<return type="void*" />
- <argument index="0" name="for_object" type="Object" />
+ <param index="0" name="for_object" type="Object" />
<description>
</description>
</method>
<method name="_instance_has" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="object" type="Object" />
+ <param index="0" name="object" type="Object" />
<description>
</description>
</method>
@@ -142,25 +148,25 @@
</method>
<method name="_placeholder_erased" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="placeholder" type="void*" />
+ <param index="0" name="placeholder" type="void*" />
<description>
</description>
</method>
<method name="_placeholder_instance_create" qualifiers="virtual const">
<return type="void*" />
- <argument index="0" name="for_object" type="Object" />
+ <param index="0" name="for_object" type="Object" />
<description>
</description>
</method>
<method name="_reload" qualifiers="virtual">
<return type="int" enum="Error" />
- <argument index="0" name="keep_state" type="bool" />
+ <param index="0" name="keep_state" type="bool" />
<description>
</description>
</method>
<method name="_set_source_code" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="code" type="String" />
+ <param index="0" name="code" type="String" />
<description>
</description>
</method>
diff --git a/doc/classes/ScriptLanguageExtension.xml b/doc/classes/ScriptLanguageExtension.xml
index 45d4cf44fa..2d41f8e880 100644
--- a/doc/classes/ScriptLanguageExtension.xml
+++ b/doc/classes/ScriptLanguageExtension.xml
@@ -9,29 +9,29 @@
<methods>
<method name="_add_global_constant" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="value" type="Variant" />
<description>
</description>
</method>
<method name="_add_named_global_constant" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="value" type="Variant" />
<description>
</description>
</method>
<method name="_alloc_instance_binding_data" qualifiers="virtual">
<return type="void*" />
- <argument index="0" name="object" type="Object" />
+ <param index="0" name="object" type="Object" />
<description>
</description>
</method>
<method name="_auto_indent_code" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="code" type="String" />
- <argument index="1" name="from_line" type="int" />
- <argument index="2" name="to_line" type="int" />
+ <param index="0" name="code" type="String" />
+ <param index="1" name="from_line" type="int" />
+ <param index="2" name="to_line" type="int" />
<description>
</description>
</method>
@@ -42,9 +42,9 @@
</method>
<method name="_complete_code" qualifiers="virtual const">
<return type="Dictionary" />
- <argument index="0" name="code" type="String" />
- <argument index="1" name="path" type="String" />
- <argument index="2" name="owner" type="Object" />
+ <param index="0" name="code" type="String" />
+ <param index="1" name="path" type="String" />
+ <param index="2" name="owner" type="Object" />
<description>
</description>
</method>
@@ -65,8 +65,8 @@
</method>
<method name="_debug_get_globals" qualifiers="virtual">
<return type="Dictionary" />
- <argument index="0" name="max_subitems" type="int" />
- <argument index="1" name="max_depth" type="int" />
+ <param index="0" name="max_subitems" type="int" />
+ <param index="1" name="max_depth" type="int" />
<description>
</description>
</method>
@@ -77,57 +77,57 @@
</method>
<method name="_debug_get_stack_level_function" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="level" type="int" />
+ <param index="0" name="level" type="int" />
<description>
</description>
</method>
<method name="_debug_get_stack_level_instance" qualifiers="virtual">
<return type="void*" />
- <argument index="0" name="level" type="int" />
+ <param index="0" name="level" type="int" />
<description>
</description>
</method>
<method name="_debug_get_stack_level_line" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="level" type="int" />
+ <param index="0" name="level" type="int" />
<description>
</description>
</method>
<method name="_debug_get_stack_level_locals" qualifiers="virtual">
<return type="Dictionary" />
- <argument index="0" name="level" type="int" />
- <argument index="1" name="max_subitems" type="int" />
- <argument index="2" name="max_depth" type="int" />
+ <param index="0" name="level" type="int" />
+ <param index="1" name="max_subitems" type="int" />
+ <param index="2" name="max_depth" type="int" />
<description>
</description>
</method>
<method name="_debug_get_stack_level_members" qualifiers="virtual">
<return type="Dictionary" />
- <argument index="0" name="level" type="int" />
- <argument index="1" name="max_subitems" type="int" />
- <argument index="2" name="max_depth" type="int" />
+ <param index="0" name="level" type="int" />
+ <param index="1" name="max_subitems" type="int" />
+ <param index="2" name="max_depth" type="int" />
<description>
</description>
</method>
<method name="_debug_parse_stack_level_expression" qualifiers="virtual">
<return type="String" />
- <argument index="0" name="level" type="int" />
- <argument index="1" name="expression" type="String" />
- <argument index="2" name="max_subitems" type="int" />
- <argument index="3" name="max_depth" type="int" />
+ <param index="0" name="level" type="int" />
+ <param index="1" name="expression" type="String" />
+ <param index="2" name="max_subitems" type="int" />
+ <param index="3" name="max_depth" type="int" />
<description>
</description>
</method>
<method name="_execute_file" qualifiers="virtual">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
</description>
</method>
<method name="_find_function" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="class_name" type="String" />
- <argument index="1" name="function_name" type="String" />
+ <param index="0" name="class_name" type="String" />
+ <param index="1" name="function_name" type="String" />
<description>
</description>
</method>
@@ -143,13 +143,13 @@
</method>
<method name="_free_instance_binding_data" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="data" type="void*" />
+ <param index="0" name="data" type="void*" />
<description>
</description>
</method>
<method name="_get_built_in_templates" qualifiers="virtual const">
<return type="Dictionary[]" />
- <argument index="0" name="object" type="StringName" />
+ <param index="0" name="object" type="StringName" />
<description>
</description>
</method>
@@ -165,7 +165,7 @@
</method>
<method name="_get_global_class_name" qualifiers="virtual const">
<return type="Dictionary" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
</description>
</method>
@@ -211,7 +211,7 @@
</method>
<method name="_handles_global_class_type" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="type" type="String" />
+ <param index="0" name="type" type="String" />
<description>
</description>
</method>
@@ -227,7 +227,7 @@
</method>
<method name="_is_control_flow_keyword" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="keyword" type="String" />
+ <param index="0" name="keyword" type="String" />
<description>
</description>
</method>
@@ -238,34 +238,34 @@
</method>
<method name="_lookup_code" qualifiers="virtual const">
<return type="Dictionary" />
- <argument index="0" name="code" type="String" />
- <argument index="1" name="symbol" type="String" />
- <argument index="2" name="path" type="String" />
- <argument index="3" name="owner" type="Object" />
+ <param index="0" name="code" type="String" />
+ <param index="1" name="symbol" type="String" />
+ <param index="2" name="path" type="String" />
+ <param index="3" name="owner" type="Object" />
<description>
</description>
</method>
<method name="_make_function" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="class_name" type="String" />
- <argument index="1" name="function_name" type="String" />
- <argument index="2" name="function_args" type="PackedStringArray" />
+ <param index="0" name="class_name" type="String" />
+ <param index="1" name="function_name" type="String" />
+ <param index="2" name="function_args" type="PackedStringArray" />
<description>
</description>
</method>
<method name="_make_template" qualifiers="virtual const">
<return type="Script" />
- <argument index="0" name="template" type="String" />
- <argument index="1" name="class_name" type="String" />
- <argument index="2" name="base_class_name" type="String" />
+ <param index="0" name="template" type="String" />
+ <param index="1" name="class_name" type="String" />
+ <param index="2" name="base_class_name" type="String" />
<description>
</description>
</method>
<method name="_open_in_external_editor" qualifiers="virtual">
<return type="int" enum="Error" />
- <argument index="0" name="script" type="Script" />
- <argument index="1" name="line" type="int" />
- <argument index="2" name="column" type="int" />
+ <param index="0" name="script" type="Script" />
+ <param index="1" name="line" type="int" />
+ <param index="2" name="column" type="int" />
<description>
</description>
</method>
@@ -276,15 +276,15 @@
</method>
<method name="_profiling_get_accumulated_data" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="info_array" type="ScriptLanguageExtensionProfilingInfo*" />
- <argument index="1" name="info_max" type="int" />
+ <param index="0" name="info_array" type="ScriptLanguageExtensionProfilingInfo*" />
+ <param index="1" name="info_max" type="int" />
<description>
</description>
</method>
<method name="_profiling_get_frame_data" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="info_array" type="ScriptLanguageExtensionProfilingInfo*" />
- <argument index="1" name="info_max" type="int" />
+ <param index="0" name="info_array" type="ScriptLanguageExtensionProfilingInfo*" />
+ <param index="1" name="info_max" type="int" />
<description>
</description>
</method>
@@ -300,13 +300,13 @@
</method>
<method name="_refcount_decremented_instance_binding" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="object" type="Object" />
+ <param index="0" name="object" type="Object" />
<description>
</description>
</method>
<method name="_refcount_incremented_instance_binding" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="object" type="Object" />
+ <param index="0" name="object" type="Object" />
<description>
</description>
</method>
@@ -317,14 +317,14 @@
</method>
<method name="_reload_tool_script" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="script" type="Script" />
- <argument index="1" name="soft_reload" type="bool" />
+ <param index="0" name="script" type="Script" />
+ <param index="1" name="soft_reload" type="bool" />
<description>
</description>
</method>
<method name="_remove_named_global_constant" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
</description>
</method>
@@ -350,18 +350,18 @@
</method>
<method name="_validate" qualifiers="virtual const">
<return type="Dictionary" />
- <argument index="0" name="script" type="String" />
- <argument index="1" name="path" type="String" />
- <argument index="2" name="validate_functions" type="bool" />
- <argument index="3" name="validate_errors" type="bool" />
- <argument index="4" name="validate_warnings" type="bool" />
- <argument index="5" name="validate_safe_lines" type="bool" />
+ <param index="0" name="script" type="String" />
+ <param index="1" name="path" type="String" />
+ <param index="2" name="validate_functions" type="bool" />
+ <param index="3" name="validate_errors" type="bool" />
+ <param index="4" name="validate_warnings" type="bool" />
+ <param index="5" name="validate_safe_lines" type="bool" />
<description>
</description>
</method>
<method name="_validate_path" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
</description>
</method>
diff --git a/doc/classes/ScrollContainer.xml b/doc/classes/ScrollContainer.xml
index 1bbf5cb91b..de586fc3d0 100644
--- a/doc/classes/ScrollContainer.xml
+++ b/doc/classes/ScrollContainer.xml
@@ -14,9 +14,9 @@
<methods>
<method name="ensure_control_visible">
<return type="void" />
- <argument index="0" name="control" type="Control" />
+ <param index="0" name="control" type="Control" />
<description>
- Ensures the given [code]control[/code] is visible (must be a direct or indirect child of the ScrollContainer). Used by [member follow_focus].
+ Ensures the given [param control] is visible (must be a direct or indirect child of the ScrollContainer). Used by [member follow_focus].
[b]Note:[/b] This will not work on a node that was just added during the same frame. If you want to scroll to a newly added child, you must wait until the next frame using [signal SceneTree.process_frame]:
[codeblock]
add_child(child_node)
diff --git a/doc/classes/Shader.xml b/doc/classes/Shader.xml
index 10deaf1c41..b7e6d80ccb 100644
--- a/doc/classes/Shader.xml
+++ b/doc/classes/Shader.xml
@@ -12,12 +12,12 @@
<methods>
<method name="get_default_texture_param" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="param" type="StringName" />
- <argument index="1" name="index" type="int" default="0" />
+ <param index="0" name="param" type="StringName" />
+ <param index="1" name="index" type="int" default="0" />
<description>
Returns the texture that is set as default for the specified parameter.
- [b]Note:[/b] [code]param[/code] must match the name of the uniform in the code exactly.
- [b]Note:[/b] If the sampler array is used use [code]index[/code] to access the specified texture.
+ [b]Note:[/b] [param param] must match the name of the uniform in the code exactly.
+ [b]Note:[/b] If the sampler array is used use [param index] to access the specified texture.
</description>
</method>
<method name="get_mode" qualifiers="const">
@@ -26,23 +26,23 @@
Returns the shader mode for the shader, either [constant MODE_CANVAS_ITEM], [constant MODE_SPATIAL] or [constant MODE_PARTICLES].
</description>
</method>
- <method name="has_param" qualifiers="const">
+ <method name="has_uniform" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
Returns [code]true[/code] if the shader has this param defined as a uniform in its code.
- [b]Note:[/b] [code]param[/code] must match the name of the uniform in the code exactly.
+ [b]Note:[/b] [param name] must match the name of the uniform in the code exactly.
</description>
</method>
<method name="set_default_texture_param">
<return type="void" />
- <argument index="0" name="param" type="StringName" />
- <argument index="1" name="texture" type="Texture2D" />
- <argument index="2" name="index" type="int" default="0" />
+ <param index="0" name="param" type="StringName" />
+ <param index="1" name="texture" type="Texture2D" />
+ <param index="2" name="index" type="int" default="0" />
<description>
Sets the default texture to be used with a texture uniform. The default is used if a texture is not set in the [ShaderMaterial].
- [b]Note:[/b] [code]param[/code] must match the name of the uniform in the code exactly.
- [b]Note:[/b] If the sampler array is used use [code]index[/code] to access the specified texture.
+ [b]Note:[/b] [param param] must match the name of the uniform in the code exactly.
+ [b]Note:[/b] If the sampler array is used use [param index] to access the specified texture.
</description>
</method>
</methods>
diff --git a/doc/classes/ShaderMaterial.xml b/doc/classes/ShaderMaterial.xml
index 672b660c34..8d4df87b39 100644
--- a/doc/classes/ShaderMaterial.xml
+++ b/doc/classes/ShaderMaterial.xml
@@ -10,34 +10,20 @@
<link title="Shaders documentation index">$DOCS_URL/tutorials/shaders/index.html</link>
</tutorials>
<methods>
- <method name="get_shader_param" qualifiers="const">
+ <method name="get_shader_uniform" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="param" type="StringName" />
+ <param index="0" name="param" type="StringName" />
<description>
Returns the current value set for this material of a uniform in the shader.
</description>
</method>
- <method name="property_can_revert">
- <return type="bool" />
- <argument index="0" name="name" type="String" />
- <description>
- Returns [code]true[/code] if the property identified by [code]name[/code] can be reverted to a default value.
- </description>
- </method>
- <method name="property_get_revert">
- <return type="Variant" />
- <argument index="0" name="name" type="String" />
- <description>
- Returns the default value of the material property with given [code]name[/code].
- </description>
- </method>
- <method name="set_shader_param">
+ <method name="set_shader_uniform">
<return type="void" />
- <argument index="0" name="param" type="StringName" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="param" type="StringName" />
+ <param index="1" name="value" type="Variant" />
<description>
Changes the value set for this material of a uniform in the shader.
- [b]Note:[/b] [code]param[/code] must match the name of the uniform in the code exactly.
+ [b]Note:[/b] [param param] must match the name of the uniform in the code exactly.
</description>
</method>
</methods>
diff --git a/doc/classes/Shape2D.xml b/doc/classes/Shape2D.xml
index 94fb2d7dc7..34ca228795 100644
--- a/doc/classes/Shape2D.xml
+++ b/doc/classes/Shape2D.xml
@@ -12,58 +12,58 @@
<methods>
<method name="collide">
<return type="bool" />
- <argument index="0" name="local_xform" type="Transform2D" />
- <argument index="1" name="with_shape" type="Shape2D" />
- <argument index="2" name="shape_xform" type="Transform2D" />
+ <param index="0" name="local_xform" type="Transform2D" />
+ <param index="1" name="with_shape" type="Shape2D" />
+ <param index="2" name="shape_xform" type="Transform2D" />
<description>
Returns [code]true[/code] if this shape is colliding with another.
- This method needs the transformation matrix for this shape ([code]local_xform[/code]), the shape to check collisions with ([code]with_shape[/code]), and the transformation matrix of that shape ([code]shape_xform[/code]).
+ This method needs the transformation matrix for this shape ([param local_xform]), the shape to check collisions with ([param with_shape]), and the transformation matrix of that shape ([param shape_xform]).
</description>
</method>
<method name="collide_and_get_contacts">
- <return type="Array" />
- <argument index="0" name="local_xform" type="Transform2D" />
- <argument index="1" name="with_shape" type="Shape2D" />
- <argument index="2" name="shape_xform" type="Transform2D" />
+ <return type="PackedVector2Array" />
+ <param index="0" name="local_xform" type="Transform2D" />
+ <param index="1" name="with_shape" type="Shape2D" />
+ <param index="2" name="shape_xform" type="Transform2D" />
<description>
Returns a list of contact point pairs where this shape touches another.
- If there are no collisions, the returned list is empty. Otherwise, the returned list contains contact points arranged in pairs, with entries alternating between points on the boundary of this shape and points on the boundary of [code]with_shape[/code].
+ If there are no collisions, the returned list is empty. Otherwise, the returned list contains contact points arranged in pairs, with entries alternating between points on the boundary of this shape and points on the boundary of [param with_shape].
A collision pair A, B can be used to calculate the collision normal with [code](B - A).normalized()[/code], and the collision depth with [code](B - A).length()[/code]. This information is typically used to separate shapes, particularly in collision solvers.
- This method needs the transformation matrix for this shape ([code]local_xform[/code]), the shape to check collisions with ([code]with_shape[/code]), and the transformation matrix of that shape ([code]shape_xform[/code]).
+ This method needs the transformation matrix for this shape ([param local_xform]), the shape to check collisions with ([param with_shape]), and the transformation matrix of that shape ([param shape_xform]).
</description>
</method>
<method name="collide_with_motion">
<return type="bool" />
- <argument index="0" name="local_xform" type="Transform2D" />
- <argument index="1" name="local_motion" type="Vector2" />
- <argument index="2" name="with_shape" type="Shape2D" />
- <argument index="3" name="shape_xform" type="Transform2D" />
- <argument index="4" name="shape_motion" type="Vector2" />
+ <param index="0" name="local_xform" type="Transform2D" />
+ <param index="1" name="local_motion" type="Vector2" />
+ <param index="2" name="with_shape" type="Shape2D" />
+ <param index="3" name="shape_xform" type="Transform2D" />
+ <param index="4" name="shape_motion" type="Vector2" />
<description>
Returns whether this shape would collide with another, if a given movement was applied.
- This method needs the transformation matrix for this shape ([code]local_xform[/code]), the movement to test on this shape ([code]local_motion[/code]), the shape to check collisions with ([code]with_shape[/code]), the transformation matrix of that shape ([code]shape_xform[/code]), and the movement to test onto the other object ([code]shape_motion[/code]).
+ This method needs the transformation matrix for this shape ([param local_xform]), the movement to test on this shape ([param local_motion]), the shape to check collisions with ([param with_shape]), the transformation matrix of that shape ([param shape_xform]), and the movement to test onto the other object ([param shape_motion]).
</description>
</method>
<method name="collide_with_motion_and_get_contacts">
- <return type="Array" />
- <argument index="0" name="local_xform" type="Transform2D" />
- <argument index="1" name="local_motion" type="Vector2" />
- <argument index="2" name="with_shape" type="Shape2D" />
- <argument index="3" name="shape_xform" type="Transform2D" />
- <argument index="4" name="shape_motion" type="Vector2" />
+ <return type="PackedVector2Array" />
+ <param index="0" name="local_xform" type="Transform2D" />
+ <param index="1" name="local_motion" type="Vector2" />
+ <param index="2" name="with_shape" type="Shape2D" />
+ <param index="3" name="shape_xform" type="Transform2D" />
+ <param index="4" name="shape_motion" type="Vector2" />
<description>
Returns a list of contact point pairs where this shape would touch another, if a given movement was applied.
- If there would be no collisions, the returned list is empty. Otherwise, the returned list contains contact points arranged in pairs, with entries alternating between points on the boundary of this shape and points on the boundary of [code]with_shape[/code].
+ If there would be no collisions, the returned list is empty. Otherwise, the returned list contains contact points arranged in pairs, with entries alternating between points on the boundary of this shape and points on the boundary of [param with_shape].
A collision pair A, B can be used to calculate the collision normal with [code](B - A).normalized()[/code], and the collision depth with [code](B - A).length()[/code]. This information is typically used to separate shapes, particularly in collision solvers.
- This method needs the transformation matrix for this shape ([code]local_xform[/code]), the movement to test on this shape ([code]local_motion[/code]), the shape to check collisions with ([code]with_shape[/code]), the transformation matrix of that shape ([code]shape_xform[/code]), and the movement to test onto the other object ([code]shape_motion[/code]).
+ This method needs the transformation matrix for this shape ([param local_xform]), the movement to test on this shape ([param local_motion]), the shape to check collisions with ([param with_shape]), the transformation matrix of that shape ([param shape_xform]), and the movement to test onto the other object ([param shape_motion]).
</description>
</method>
<method name="draw">
<return type="void" />
- <argument index="0" name="canvas_item" type="RID" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="canvas_item" type="RID" />
+ <param index="1" name="color" type="Color" />
<description>
- Draws a solid shape onto a [CanvasItem] with the [RenderingServer] API filled with the specified [code]color[/code]. The exact drawing method is specific for each shape and cannot be configured.
+ Draws a solid shape onto a [CanvasItem] with the [RenderingServer] API filled with the specified [param color]. The exact drawing method is specific for each shape and cannot be configured.
</description>
</method>
</methods>
diff --git a/doc/classes/ShapeCast2D.xml b/doc/classes/ShapeCast2D.xml
index 70da03dc6e..36c3beecb1 100644
--- a/doc/classes/ShapeCast2D.xml
+++ b/doc/classes/ShapeCast2D.xml
@@ -14,14 +14,14 @@
<methods>
<method name="add_exception">
<return type="void" />
- <argument index="0" name="node" type="CollisionObject2D" />
+ <param index="0" name="node" type="CollisionObject2D" />
<description>
Adds a collision exception so the shape does not report collisions with the specified [CollisionObject2D] node.
</description>
</method>
<method name="add_exception_rid">
<return type="void" />
- <argument index="0" name="rid" type="RID" />
+ <param index="0" name="rid" type="RID" />
<description>
Adds a collision exception so the shape does not report collisions with the specified [RID].
</description>
@@ -53,16 +53,16 @@
</method>
<method name="get_collider" qualifiers="const">
<return type="Object" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the collided [Object] of one of the multiple collisions at [code]index[/code], or [code]null[/code] if no object is intersecting the shape (i.e. [method is_colliding] returns [code]false[/code]).
+ Returns the collided [Object] of one of the multiple collisions at [param index], or [code]null[/code] if no object is intersecting the shape (i.e. [method is_colliding] returns [code]false[/code]).
</description>
</method>
<method name="get_collider_shape" qualifiers="const">
<return type="int" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the shape ID of the colliding shape of one of the multiple collisions at [code]index[/code], or [code]0[/code] if no object is intersecting the shape (i.e. [method is_colliding] returns [code]false[/code]).
+ Returns the shape ID of the colliding shape of one of the multiple collisions at [param index], or [code]0[/code] if no object is intersecting the shape (i.e. [method is_colliding] returns [code]false[/code]).
</description>
</method>
<method name="get_collision_count" qualifiers="const">
@@ -73,23 +73,23 @@
</method>
<method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
- Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
+ Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="get_collision_normal" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the normal of one of the multiple collisions at [code]index[/code] of the intersecting object.
+ Returns the normal of one of the multiple collisions at [param index] of the intersecting object.
</description>
</method>
<method name="get_collision_point" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the collision point of one of the multiple collisions at [code]index[/code] where the shape intersects the colliding object.
+ Returns the collision point of one of the multiple collisions at [param index] where the shape intersects the colliding object.
[b]Note:[/b] this point is in the [b]global[/b] coordinate system.
</description>
</method>
@@ -101,24 +101,24 @@
</method>
<method name="remove_exception">
<return type="void" />
- <argument index="0" name="node" type="CollisionObject2D" />
+ <param index="0" name="node" type="CollisionObject2D" />
<description>
Removes a collision exception so the shape does report collisions with the specified [CollisionObject2D] node.
</description>
</method>
<method name="remove_exception_rid">
<return type="void" />
- <argument index="0" name="rid" type="RID" />
+ <param index="0" name="rid" type="RID" />
<description>
Removes a collision exception so the shape does report collisions with the specified [RID].
</description>
</method>
<method name="set_collision_mask_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
- Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
+ Based on [param value], enables or disables the specified layer in the [member collision_mask], given a [param layer_number] between 1 and 32.
</description>
</method>
</methods>
diff --git a/doc/classes/ShapeCast3D.xml b/doc/classes/ShapeCast3D.xml
index 085bc9acd1..cbdf660133 100644
--- a/doc/classes/ShapeCast3D.xml
+++ b/doc/classes/ShapeCast3D.xml
@@ -14,14 +14,14 @@
<methods>
<method name="add_exception">
<return type="void" />
- <argument index="0" name="node" type="Object" />
+ <param index="0" name="node" type="Object" />
<description>
Adds a collision exception so the shape does not report collisions with the specified [CollisionObject3D] node.
</description>
</method>
<method name="add_exception_rid">
<return type="void" />
- <argument index="0" name="rid" type="RID" />
+ <param index="0" name="rid" type="RID" />
<description>
Adds a collision exception so the shape does not report collisions with the specified [RID].
</description>
@@ -53,16 +53,16 @@
</method>
<method name="get_collider" qualifiers="const">
<return type="Object" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the collided [Object] of one of the multiple collisions at [code]index[/code], or [code]null[/code] if no object is intersecting the shape (i.e. [method is_colliding] returns [code]false[/code]).
+ Returns the collided [Object] of one of the multiple collisions at [param index], or [code]null[/code] if no object is intersecting the shape (i.e. [method is_colliding] returns [code]false[/code]).
</description>
</method>
<method name="get_collider_shape" qualifiers="const">
<return type="int" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the shape ID of the colliding shape of one of the multiple collisions at [code]index[/code], or [code]0[/code] if no object is intersecting the shape (i.e. [method is_colliding] returns [code]false[/code]).
+ Returns the shape ID of the colliding shape of one of the multiple collisions at [param index], or [code]0[/code] if no object is intersecting the shape (i.e. [method is_colliding] returns [code]false[/code]).
</description>
</method>
<method name="get_collision_count" qualifiers="const">
@@ -73,23 +73,23 @@
</method>
<method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
- Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
+ Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="get_collision_normal" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the normal of one of the multiple collisions at [code]index[/code] of the intersecting object.
+ Returns the normal of one of the multiple collisions at [param index] of the intersecting object.
</description>
</method>
<method name="get_collision_point" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the collision point of one of the multiple collisions at [code]index[/code] where the shape intersects the colliding object.
+ Returns the collision point of one of the multiple collisions at [param index] where the shape intersects the colliding object.
[b]Note:[/b] this point is in the [b]global[/b] coordinate system.
</description>
</method>
@@ -101,31 +101,31 @@
</method>
<method name="remove_exception">
<return type="void" />
- <argument index="0" name="node" type="Object" />
+ <param index="0" name="node" type="Object" />
<description>
Removes a collision exception so the shape does report collisions with the specified [CollisionObject3D] node.
</description>
</method>
<method name="remove_exception_rid">
<return type="void" />
- <argument index="0" name="rid" type="RID" />
+ <param index="0" name="rid" type="RID" />
<description>
Removes a collision exception so the shape does report collisions with the specified [RID].
</description>
</method>
<method name="resource_changed">
<return type="void" />
- <argument index="0" name="resource" type="Resource" />
+ <param index="0" name="resource" type="Resource" />
<description>
This method is used internally to update the debug gizmo in the editor. Any code placed in this function will be called whenever the [member shape] resource is modified.
</description>
</method>
<method name="set_collision_mask_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
- Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
+ Based on [param value], enables or disables the specified layer in the [member collision_mask], given a [param layer_number] between 1 and 32.
</description>
</method>
</methods>
diff --git a/doc/classes/Shortcut.xml b/doc/classes/Shortcut.xml
index 46524a1d74..f30a5a5e7c 100644
--- a/doc/classes/Shortcut.xml
+++ b/doc/classes/Shortcut.xml
@@ -24,9 +24,9 @@
</method>
<method name="matches_event" qualifiers="const">
<return type="bool" />
- <argument index="0" name="event" type="InputEvent" />
+ <param index="0" name="event" type="InputEvent" />
<description>
- Returns whether any [InputEvent] in [member events] equals [code]event[/code].
+ Returns whether any [InputEvent] in [member events] equals [param event].
</description>
</method>
</methods>
diff --git a/doc/classes/Signal.xml b/doc/classes/Signal.xml
index 049e7f8777..d99477ee95 100644
--- a/doc/classes/Signal.xml
+++ b/doc/classes/Signal.xml
@@ -18,25 +18,25 @@
</constructor>
<constructor name="Signal">
<return type="Signal" />
- <argument index="0" name="from" type="Signal" />
+ <param index="0" name="from" type="Signal" />
<description>
Constructs a [Signal] as a copy of the given [Signal].
</description>
</constructor>
<constructor name="Signal">
<return type="Signal" />
- <argument index="0" name="object" type="Object" />
- <argument index="1" name="signal" type="StringName" />
+ <param index="0" name="object" type="Object" />
+ <param index="1" name="signal" type="StringName" />
<description>
- Creates a new [Signal] with the name [code]signal[/code] in the specified [code]object[/code].
+ Creates a new [Signal] with the name [param signal] in the specified [param object].
</description>
</constructor>
</constructors>
<methods>
<method name="connect">
<return type="int" />
- <argument index="0" name="callable" type="Callable" />
- <argument index="1" name="flags" type="int" default="0" />
+ <param index="0" name="callable" type="Callable" />
+ <param index="1" name="flags" type="int" default="0" />
<description>
Connects this signal to the specified [Callable], optionally providing connection flags. You can provide additional arguments to the connected method call by using [method Callable.bind].
[codeblock]
@@ -50,7 +50,7 @@
</method>
<method name="disconnect">
<return type="void" />
- <argument index="0" name="callable" type="Callable" />
+ <param index="0" name="callable" type="Callable" />
<description>
Disconnects this signal from the specified [Callable].
</description>
@@ -87,7 +87,7 @@
</method>
<method name="is_connected" qualifiers="const">
<return type="bool" />
- <argument index="0" name="callable" type="Callable" />
+ <param index="0" name="callable" type="Callable" />
<description>
Returns [code]true[/code] if the specified [Callable] is connected to this signal.
</description>
@@ -101,13 +101,13 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="Signal" />
+ <param index="0" name="right" type="Signal" />
<description>
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="Signal" />
+ <param index="0" name="right" type="Signal" />
<description>
</description>
</operator>
diff --git a/doc/classes/Skeleton2D.xml b/doc/classes/Skeleton2D.xml
index 7867e5afa3..808f93b491 100644
--- a/doc/classes/Skeleton2D.xml
+++ b/doc/classes/Skeleton2D.xml
@@ -13,17 +13,17 @@
<methods>
<method name="execute_modifications">
<return type="void" />
- <argument index="0" name="delta" type="float" />
- <argument index="1" name="execution_mode" type="int" />
+ <param index="0" name="delta" type="float" />
+ <param index="1" name="execution_mode" type="int" />
<description>
Executes all the modifications on the [SkeletonModificationStack2D], if the Skeleton3D has one assigned.
</description>
</method>
<method name="get_bone">
<return type="Bone2D" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns a [Bone2D] from the node hierarchy parented by Skeleton2D. The object to return is identified by the parameter [code]idx[/code]. Bones are indexed by descending the node hierarchy from top to bottom, adding the children of each branch before moving to the next sibling.
+ Returns a [Bone2D] from the node hierarchy parented by Skeleton2D. The object to return is identified by the parameter [param idx]. Bones are indexed by descending the node hierarchy from top to bottom, adding the children of each branch before moving to the next sibling.
</description>
</method>
<method name="get_bone_count" qualifiers="const">
@@ -34,9 +34,9 @@
</method>
<method name="get_bone_local_pose_override">
<return type="Transform2D" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
- Returns the local pose override transform for [code]bone_idx[/code].
+ Returns the local pose override transform for [param bone_idx].
</description>
</method>
<method name="get_modification_stack" qualifiers="const">
@@ -53,19 +53,19 @@
</method>
<method name="set_bone_local_pose_override">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="override_pose" type="Transform2D" />
- <argument index="2" name="strength" type="float" />
- <argument index="3" name="persistent" type="bool" />
+ <param index="0" name="bone_idx" type="int" />
+ <param index="1" name="override_pose" type="Transform2D" />
+ <param index="2" name="strength" type="float" />
+ <param index="3" name="persistent" type="bool" />
<description>
- Sets the local pose transform, [code]pose[/code], for the bone at [code]bone_idx[/code].
- [code]amount[/code] is the interpolation strength that will be used when applying the pose, and [code]persistent[/code] determines if the applied pose will remain.
- [b]Note:[/b] The pose transform needs to be a local transform relative to the [Bone2D] node at [code]bone_idx[/code]!
+ Sets the local pose transform, [param override_pose], for the bone at [param bone_idx].
+ [param strength] is the interpolation strength that will be used when applying the pose, and [param persistent] determines if the applied pose will remain.
+ [b]Note:[/b] The pose transform needs to be a local transform relative to the [Bone2D] node at [param bone_idx]!
</description>
</method>
<method name="set_modification_stack">
<return type="void" />
- <argument index="0" name="modification_stack" type="SkeletonModificationStack2D" />
+ <param index="0" name="modification_stack" type="SkeletonModificationStack2D" />
<description>
Sets the [SkeletonModificationStack2D] attached to this skeleton.
</description>
diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml
index 6295724aa2..45ca330b87 100644
--- a/doc/classes/Skeleton3D.xml
+++ b/doc/classes/Skeleton3D.xml
@@ -15,18 +15,9 @@
<methods>
<method name="add_bone">
<return type="void" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
- Adds a bone, with name [code]name[/code]. [method get_bone_count] will become the bone index.
- </description>
- </method>
- <method name="add_bone_child">
- <return type="void" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="child_bone_idx" type="int" />
- <description>
- Takes the given bone pose/transform and converts it to a world transform, relative to the [Skeleton3D] node.
- This is useful for using the bone transform in calculations with transforms from [Node3D]-based nodes.
+ Adds a bone, with name [param name]. [method get_bone_count] will become the bone index.
</description>
</method>
<method name="clear_bones">
@@ -54,17 +45,17 @@
</method>
<method name="execute_modifications">
<return type="void" />
- <argument index="0" name="delta" type="float" />
- <argument index="1" name="execution_mode" type="int" />
+ <param index="0" name="delta" type="float" />
+ <param index="1" name="execution_mode" type="int" />
<description>
Executes all the modifications on the [SkeletonModificationStack3D], if the Skeleton3D has one assigned.
</description>
</method>
<method name="find_bone" qualifiers="const">
<return type="int" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
- Returns the bone index that matches [code]name[/code] as its name.
+ Returns the bone index that matches [param name] as its name.
</description>
</method>
<method name="force_update_all_bone_transforms">
@@ -75,104 +66,104 @@
</method>
<method name="force_update_bone_child_transform">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
- Force updates the bone transform for the bone at [code]bone_idx[/code] and all of its children.
+ Force updates the bone transform for the bone at [param bone_idx] and all of its children.
</description>
</method>
<method name="get_bone_children">
<return type="PackedInt32Array" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
- Returns an array containing the bone indexes of all the children node of the passed in bone, [code]bone_idx[/code].
+ Returns an array containing the bone indexes of all the children node of the passed in bone, [param bone_idx].
</description>
</method>
<method name="get_bone_count" qualifiers="const">
<return type="int" />
<description>
- Returns the amount of bones in the skeleton.
+ Returns the number of bones in the skeleton.
</description>
</method>
<method name="get_bone_global_pose" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
Returns the overall transform of the specified bone, with respect to the skeleton. Being relative to the skeleton frame, this is not the actual "global" transform of the bone.
</description>
</method>
<method name="get_bone_global_pose_no_override" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
Returns the overall transform of the specified bone, with respect to the skeleton, but without any global pose overrides. Being relative to the skeleton frame, this is not the actual "global" transform of the bone.
</description>
</method>
<method name="get_bone_global_pose_override" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
- Returns the global pose override transform for [code]bone_idx[/code].
+ Returns the global pose override transform for [param bone_idx].
</description>
</method>
<method name="get_bone_global_rest" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
- Returns the global rest transform for [code]bone_idx[/code].
+ Returns the global rest transform for [param bone_idx].
</description>
</method>
<method name="get_bone_local_pose_override" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
- Returns the local pose override transform for [code]bone_idx[/code].
+ Returns the local pose override transform for [param bone_idx].
</description>
</method>
<method name="get_bone_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
- Returns the name of the bone at index [code]index[/code].
+ Returns the name of the bone at index [param bone_idx].
</description>
</method>
<method name="get_bone_parent" qualifiers="const">
<return type="int" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
- Returns the bone index which is the parent of the bone at [code]bone_idx[/code]. If -1, then bone has no parent.
- [b]Note:[/b] The parent bone returned will always be less than [code]bone_idx[/code].
+ Returns the bone index which is the parent of the bone at [param bone_idx]. If -1, then bone has no parent.
+ [b]Note:[/b] The parent bone returned will always be less than [param bone_idx].
</description>
</method>
<method name="get_bone_pose" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
Returns the pose transform of the specified bone. Pose is applied on top of the custom pose, which is applied on top the rest pose.
</description>
</method>
<method name="get_bone_pose_position" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
</description>
</method>
<method name="get_bone_pose_rotation" qualifiers="const">
<return type="Quaternion" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
</description>
</method>
<method name="get_bone_pose_scale" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
</description>
</method>
<method name="get_bone_rest" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
- Returns the rest transform for a bone [code]bone_idx[/code].
+ Returns the rest transform for a bone [param bone_idx].
</description>
</method>
<method name="get_modification_stack">
@@ -189,8 +180,8 @@
</method>
<method name="global_pose_to_local_pose">
<return type="Transform3D" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="global_pose" type="Transform3D" />
+ <param index="0" name="bone_idx" type="int" />
+ <param index="1" name="global_pose" type="Transform3D" />
<description>
Takes the passed-in global pose and converts it to local pose transform.
This can be used to easily convert a global pose from [method get_bone_global_pose] to a global transform in [method set_bone_local_pose_override].
@@ -198,7 +189,7 @@
</method>
<method name="global_pose_to_world_transform">
<return type="Transform3D" />
- <argument index="0" name="global_pose" type="Transform3D" />
+ <param index="0" name="global_pose" type="Transform3D" />
<description>
Takes the passed-in global pose and converts it to a world transform.
This can be used to easily convert a global pose from [method get_bone_global_pose] to a global transform usable with a node's transform, like [member Node3D.global_transform] for example.
@@ -206,26 +197,26 @@
</method>
<method name="global_pose_z_forward_to_bone_forward">
<return type="Basis" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="basis" type="Basis" />
+ <param index="0" name="bone_idx" type="int" />
+ <param index="1" name="basis" type="Basis" />
<description>
- Rotates the given [Basis] so that the forward axis of the Basis is facing in the forward direction of the bone at [code]bone_idx[/code].
+ Rotates the given [Basis] so that the forward axis of the Basis is facing in the forward direction of the bone at [param bone_idx].
This is helper function to make using [method Transform3D.looking_at] easier with bone poses.
</description>
</method>
<method name="is_bone_enabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
- Returns whether the bone pose for the bone at [code]bone_idx[/code] is enabled.
+ Returns whether the bone pose for the bone at [param bone_idx] is enabled.
</description>
</method>
<method name="local_pose_to_global_pose">
<return type="Transform3D" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="local_pose" type="Transform3D" />
+ <param index="0" name="bone_idx" type="int" />
+ <param index="1" name="local_pose" type="Transform3D" />
<description>
- Converts the passed-in local pose to a global pose relative to the inputted bone, [code]bone_idx[/code].
+ Converts the passed-in local pose to a global pose relative to the inputted bone, [param bone_idx].
This could be used to convert [method get_bone_pose] for use with the [method set_bone_global_pose_override] function.
</description>
</method>
@@ -237,23 +228,23 @@
</method>
<method name="physical_bones_add_collision_exception">
<return type="void" />
- <argument index="0" name="exception" type="RID" />
+ <param index="0" name="exception" type="RID" />
<description>
Adds a collision exception to the physical bone.
- Works just like the [RigidDynamicBody3D] node.
+ Works just like the [RigidBody3D] node.
</description>
</method>
<method name="physical_bones_remove_collision_exception">
<return type="void" />
- <argument index="0" name="exception" type="RID" />
+ <param index="0" name="exception" type="RID" />
<description>
Removes a collision exception to the physical bone.
- Works just like the [RigidDynamicBody3D] node.
+ Works just like the [RigidBody3D] node.
</description>
</method>
<method name="physical_bones_start_simulation">
<return type="void" />
- <argument index="0" name="bones" type="StringName[]" default="[]" />
+ <param index="0" name="bones" type="StringName[]" default="[]" />
<description>
Tells the [PhysicalBone3D] nodes in the Skeleton to start simulating and reacting to the physics world.
Optionally, a list of bone names can be passed-in, allowing only the passed-in bones to be simulated.
@@ -267,122 +258,118 @@
</method>
<method name="register_skin">
<return type="SkinReference" />
- <argument index="0" name="skin" type="Skin" />
+ <param index="0" name="skin" type="Skin" />
<description>
Binds the given Skin to the Skeleton.
</description>
</method>
- <method name="remove_bone_child">
+ <method name="reset_bone_pose">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="child_bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
- Removes the passed in child bone index, [code]child_bone_idx[/code], from the passed-in bone, [code]bone_idx[/code], if it exists.
- [b]Note:[/b] This does not remove the child bone, but instead it removes the connection it has to the parent bone.
+ Sets the bone pose to rest for [param bone_idx].
</description>
</method>
- <method name="set_bone_children">
+ <method name="reset_bone_poses">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="bone_children" type="PackedInt32Array" />
<description>
- Sets the children for the passed in bone, [code]bone_idx[/code], to the passed-in array of bone indexes, [code]bone_children[/code].
+ Sets all bone poses to rests.
</description>
</method>
<method name="set_bone_enabled">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="enabled" type="bool" default="true" />
+ <param index="0" name="bone_idx" type="int" />
+ <param index="1" name="enabled" type="bool" default="true" />
<description>
- Disables the pose for the bone at [code]bone_idx[/code] if [code]false[/code], enables the bone pose if [code]true[/code].
+ Disables the pose for the bone at [param bone_idx] if [code]false[/code], enables the bone pose if [code]true[/code].
</description>
</method>
<method name="set_bone_global_pose_override">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="pose" type="Transform3D" />
- <argument index="2" name="amount" type="float" />
- <argument index="3" name="persistent" type="bool" default="false" />
+ <param index="0" name="bone_idx" type="int" />
+ <param index="1" name="pose" type="Transform3D" />
+ <param index="2" name="amount" type="float" />
+ <param index="3" name="persistent" type="bool" default="false" />
<description>
- Sets the global pose transform, [code]pose[/code], for the bone at [code]bone_idx[/code].
- [code]amount[/code] is the interpolation strength that will be used when applying the pose, and [code]persistent[/code] determines if the applied pose will remain.
+ Sets the global pose transform, [param pose], for the bone at [param bone_idx].
+ [param amount] is the interpolation strength that will be used when applying the pose, and [param persistent] determines if the applied pose will remain.
[b]Note:[/b] The pose transform needs to be a global pose! Use [method world_transform_to_global_pose] to convert a world transform, like one you can get from a [Node3D], to a global pose.
</description>
</method>
<method name="set_bone_local_pose_override">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="pose" type="Transform3D" />
- <argument index="2" name="amount" type="float" />
- <argument index="3" name="persistent" type="bool" default="false" />
+ <param index="0" name="bone_idx" type="int" />
+ <param index="1" name="pose" type="Transform3D" />
+ <param index="2" name="amount" type="float" />
+ <param index="3" name="persistent" type="bool" default="false" />
<description>
- Sets the local pose transform, [code]pose[/code], for the bone at [code]bone_idx[/code].
- [code]amount[/code] is the interpolation strength that will be used when applying the pose, and [code]persistent[/code] determines if the applied pose will remain.
+ Sets the local pose transform, [param pose], for the bone at [param bone_idx].
+ [param amount] is the interpolation strength that will be used when applying the pose, and [param persistent] determines if the applied pose will remain.
[b]Note:[/b] The pose transform needs to be a local pose! Use [method global_pose_to_local_pose] to convert a global pose to a local pose.
</description>
</method>
<method name="set_bone_name">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="name" type="String" />
+ <param index="0" name="bone_idx" type="int" />
+ <param index="1" name="name" type="String" />
<description>
</description>
</method>
<method name="set_bone_parent">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="parent_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
+ <param index="1" name="parent_idx" type="int" />
<description>
- Sets the bone index [code]parent_idx[/code] as the parent of the bone at [code]bone_idx[/code]. If -1, then bone has no parent.
- [b]Note:[/b] [code]parent_idx[/code] must be less than [code]bone_idx[/code].
+ Sets the bone index [param parent_idx] as the parent of the bone at [param bone_idx]. If -1, then bone has no parent.
+ [b]Note:[/b] [param parent_idx] must be less than [param bone_idx].
</description>
</method>
<method name="set_bone_pose_position">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="position" type="Vector3" />
+ <param index="0" name="bone_idx" type="int" />
+ <param index="1" name="position" type="Vector3" />
<description>
</description>
</method>
<method name="set_bone_pose_rotation">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="rotation" type="Quaternion" />
+ <param index="0" name="bone_idx" type="int" />
+ <param index="1" name="rotation" type="Quaternion" />
<description>
</description>
</method>
<method name="set_bone_pose_scale">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="scale" type="Vector3" />
+ <param index="0" name="bone_idx" type="int" />
+ <param index="1" name="scale" type="Vector3" />
<description>
</description>
</method>
<method name="set_bone_rest">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="rest" type="Transform3D" />
+ <param index="0" name="bone_idx" type="int" />
+ <param index="1" name="rest" type="Transform3D" />
<description>
- Sets the rest transform for bone [code]bone_idx[/code].
+ Sets the rest transform for bone [param bone_idx].
</description>
</method>
<method name="set_modification_stack">
<return type="void" />
- <argument index="0" name="modification_stack" type="SkeletonModificationStack3D" />
+ <param index="0" name="modification_stack" type="SkeletonModificationStack3D" />
<description>
- Sets the modification stack for this skeleton to the passed-in modification stack, [code]modification_stack[/code].
+ Sets the modification stack for this skeleton to the passed-in modification stack, [param modification_stack].
</description>
</method>
<method name="unparent_bone_and_rest">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
- Unparents the bone at [code]bone_idx[/code] and sets its rest position to that of its parent prior to being reset.
+ Unparents the bone at [param bone_idx] and sets its rest position to that of its parent prior to being reset.
</description>
</method>
<method name="world_transform_to_global_pose">
<return type="Transform3D" />
- <argument index="0" name="world_transform" type="Transform3D" />
+ <param index="0" name="world_transform" type="Transform3D" />
<description>
Takes the passed-in global transform and converts it to a global pose.
This can be used to easily convert a global transform from [member Node3D.global_transform] to a global pose usable with [method set_bone_global_pose_override], for example.
@@ -401,12 +388,12 @@
</members>
<signals>
<signal name="bone_enabled_changed">
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
</description>
</signal>
<signal name="bone_pose_changed">
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
This signal is emitted when one of the bones in the Skeleton3D node have changed their pose. This is used to inform nodes that rely on bone positions that one of the bones in the Skeleton3D have changed their transform/pose.
</description>
diff --git a/doc/classes/SkeletonIK3D.xml b/doc/classes/SkeletonIK3D.xml
index 0545469e4c..788ba3e248 100644
--- a/doc/classes/SkeletonIK3D.xml
+++ b/doc/classes/SkeletonIK3D.xml
@@ -20,7 +20,7 @@
</method>
<method name="start">
<return type="void" />
- <argument index="0" name="one_time" type="bool" default="false" />
+ <param index="0" name="one_time" type="bool" default="false" />
<description>
</description>
</method>
diff --git a/doc/classes/SkeletonModification2D.xml b/doc/classes/SkeletonModification2D.xml
index 8ce9bf5731..46d32aef41 100644
--- a/doc/classes/SkeletonModification2D.xml
+++ b/doc/classes/SkeletonModification2D.xml
@@ -19,26 +19,26 @@
</method>
<method name="_execute" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="delta" type="float" />
+ <param index="0" name="delta" type="float" />
<description>
Executes the given modification. This is where the modification performs whatever function it is designed to do.
</description>
</method>
<method name="_setup_modification" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="modification_stack" type="SkeletonModificationStack2D" />
+ <param index="0" name="modification_stack" type="SkeletonModificationStack2D" />
<description>
Called when the modification is setup. This is where the modification performs initialization.
</description>
</method>
<method name="clamp_angle">
<return type="float" />
- <argument index="0" name="angle" type="float" />
- <argument index="1" name="min" type="float" />
- <argument index="2" name="max" type="float" />
- <argument index="3" name="invert" type="bool" />
+ <param index="0" name="angle" type="float" />
+ <param index="1" name="min" type="float" />
+ <param index="2" name="max" type="float" />
+ <param index="3" name="invert" type="bool" />
<description>
- Takes a angle and clamps it so it is within the passed-in [code]min[/code] and [code]max[/code] range. [code]invert[/code] will inversely clamp the angle, clamping it to the range outside of the given bounds.
+ Takes a angle and clamps it so it is within the passed-in [param min] and [param max] range. [param invert] will inversely clamp the angle, clamping it to the range outside of the given bounds.
</description>
</method>
<method name="get_editor_draw_gizmo" qualifiers="const">
@@ -61,14 +61,14 @@
</method>
<method name="set_editor_draw_gizmo">
<return type="void" />
- <argument index="0" name="draw_gizmo" type="bool" />
+ <param index="0" name="draw_gizmo" type="bool" />
<description>
Sets whether this modification will call [method _draw_editor_gizmo] in the Godot editor to draw modification-specific gizmos.
</description>
</method>
<method name="set_is_setup">
<return type="void" />
- <argument index="0" name="is_setup" type="bool" />
+ <param index="0" name="is_setup" type="bool" />
<description>
Manually allows you to set the setup state of the modification. This function should only rarely be used, as the [SkeletonModificationStack2D] the modification is bound to should handle setting the modification up.
</description>
diff --git a/doc/classes/SkeletonModification2DCCDIK.xml b/doc/classes/SkeletonModification2DCCDIK.xml
index a613787a3e..c8fee3f94d 100644
--- a/doc/classes/SkeletonModification2DCCDIK.xml
+++ b/doc/classes/SkeletonModification2DCCDIK.xml
@@ -14,114 +14,114 @@
<methods>
<method name="get_ccdik_joint_bone2d_node" qualifiers="const">
<return type="NodePath" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the [Bone2D] node assigned to the CCDIK joint at [code]joint_idx[/code].
+ Returns the [Bone2D] node assigned to the CCDIK joint at [param joint_idx].
</description>
</method>
<method name="get_ccdik_joint_bone_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the index of the [Bone2D] node assigned to the CCDIK joint at [code]joint_idx[/code].
+ Returns the index of the [Bone2D] node assigned to the CCDIK joint at [param joint_idx].
</description>
</method>
<method name="get_ccdik_joint_constraint_angle_invert" qualifiers="const">
<return type="bool" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns whether the CCDIK joint at [code]joint_idx[/code] uses an inverted joint constraint. See [method set_ccdik_joint_constraint_angle_invert] for details.
+ Returns whether the CCDIK joint at [param joint_idx] uses an inverted joint constraint. See [method set_ccdik_joint_constraint_angle_invert] for details.
</description>
</method>
<method name="get_ccdik_joint_constraint_angle_max" qualifiers="const">
<return type="float" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the maximum angle constraint for the joint at [code]joint_idx[/code].
+ Returns the maximum angle constraint for the joint at [param joint_idx].
</description>
</method>
<method name="get_ccdik_joint_constraint_angle_min" qualifiers="const">
<return type="float" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the minimum angle constraint for the joint at [code]joint_idx[/code].
+ Returns the minimum angle constraint for the joint at [param joint_idx].
</description>
</method>
<method name="get_ccdik_joint_enable_constraint" qualifiers="const">
<return type="bool" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns whether angle constraints on the CCDIK joint at [code]joint_idx[/code] are enabled.
+ Returns whether angle constraints on the CCDIK joint at [param joint_idx] are enabled.
</description>
</method>
<method name="get_ccdik_joint_rotate_from_joint" qualifiers="const">
<return type="bool" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns whether the joint at [code]joint_idx[/code] is set to rotate from the joint, [code]true[/code], or to rotate from the tip, [code]false[/code]. The default is to rotate from the tip.
+ Returns whether the joint at [param joint_idx] is set to rotate from the joint, [code]true[/code], or to rotate from the tip, [code]false[/code]. The default is to rotate from the tip.
</description>
</method>
<method name="set_ccdik_joint_bone2d_node">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="bone2d_nodepath" type="NodePath" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="bone2d_nodepath" type="NodePath" />
<description>
- Sets the [Bone2D] node assigned to the CCDIK joint at [code]joint_idx[/code].
+ Sets the [Bone2D] node assigned to the CCDIK joint at [param joint_idx].
</description>
</method>
<method name="set_ccdik_joint_bone_index">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="bone_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="bone_idx" type="int" />
<description>
- Sets the bone index, [code]bone_index[/code], of the CCDIK joint at [code]joint_idx[/code]. When possible, this will also update the [code]bone2d_node[/code] of the CCDIK joint based on data provided by the linked skeleton.
+ Sets the bone index, [param bone_idx], of the CCDIK joint at [param joint_idx]. When possible, this will also update the [code]bone2d_node[/code] of the CCDIK joint based on data provided by the linked skeleton.
</description>
</method>
<method name="set_ccdik_joint_constraint_angle_invert">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="invert" type="bool" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="invert" type="bool" />
<description>
- Sets whether the CCDIK joint at [code]joint_idx[/code] uses an inverted joint constraint.
+ Sets whether the CCDIK joint at [param joint_idx] uses an inverted joint constraint.
An inverted joint constraint only constraints the CCDIK joint to the angles [i]outside of[/i] the inputted minimum and maximum angles. For this reason, it is referred to as an inverted joint constraint, as it constraints the joint to the outside of the inputted values.
</description>
</method>
<method name="set_ccdik_joint_constraint_angle_max">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="angle_max" type="float" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="angle_max" type="float" />
<description>
- Sets the maximum angle constraint for the joint at [code]joint_idx[/code].
+ Sets the maximum angle constraint for the joint at [param joint_idx].
</description>
</method>
<method name="set_ccdik_joint_constraint_angle_min">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="angle_min" type="float" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="angle_min" type="float" />
<description>
- Sets the minimum angle constraint for the joint at [code]joint_idx[/code].
+ Sets the minimum angle constraint for the joint at [param joint_idx].
</description>
</method>
<method name="set_ccdik_joint_enable_constraint">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="enable_constraint" type="bool" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="enable_constraint" type="bool" />
<description>
- Determines whether angle constraints on the CCDIK joint at [code]joint_idx[/code] are enabled. When [code]true[/code], constraints will be enabled and taken into account when solving.
+ Determines whether angle constraints on the CCDIK joint at [param joint_idx] are enabled. When [code]true[/code], constraints will be enabled and taken into account when solving.
</description>
</method>
<method name="set_ccdik_joint_rotate_from_joint">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="rotate_from_joint" type="bool" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="rotate_from_joint" type="bool" />
<description>
- Sets whether the joint at [code]joint_idx[/code] is set to rotate from the joint, [code]true[/code], or to rotate from the tip, [code]false[/code].
+ Sets whether the joint at [param joint_idx] is set to rotate from the joint, [code]true[/code], or to rotate from the tip, [code]false[/code].
</description>
</method>
</methods>
<members>
<member name="ccdik_data_chain_length" type="int" setter="set_ccdik_data_chain_length" getter="get_ccdik_data_chain_length" default="0">
- The amount of CCDIK joints in the CCDIK modification.
+ The number of CCDIK joints in the CCDIK modification.
</member>
<member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
The NodePath to the node that is the target for the CCDIK modification. This node is what the CCDIK chain will attempt to rotate the bone chain to.
diff --git a/doc/classes/SkeletonModification2DFABRIK.xml b/doc/classes/SkeletonModification2DFABRIK.xml
index 883d4aa04b..ff3a65fe1a 100644
--- a/doc/classes/SkeletonModification2DFABRIK.xml
+++ b/doc/classes/SkeletonModification2DFABRIK.xml
@@ -15,69 +15,69 @@
<methods>
<method name="get_fabrik_joint_bone2d_node" qualifiers="const">
<return type="NodePath" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the [Bone2D] node assigned to the FABRIK joint at [code]joint_idx[/code].
+ Returns the [Bone2D] node assigned to the FABRIK joint at [param joint_idx].
</description>
</method>
<method name="get_fabrik_joint_bone_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the index of the [Bone2D] node assigned to the FABRIK joint at [code]joint_idx[/code].
+ Returns the index of the [Bone2D] node assigned to the FABRIK joint at [param joint_idx].
</description>
</method>
<method name="get_fabrik_joint_magnet_position" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the magnet position vector for the joint at [code]joint_idx[/code].
+ Returns the magnet position vector for the joint at [param joint_idx].
</description>
</method>
<method name="get_fabrik_joint_use_target_rotation" qualifiers="const">
<return type="bool" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
Returns whether the joint is using the target's rotation rather than allowing FABRIK to rotate the joint. This option only applies to the tip/final joint in the chain.
</description>
</method>
<method name="set_fabrik_joint_bone2d_node">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="bone2d_nodepath" type="NodePath" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="bone2d_nodepath" type="NodePath" />
<description>
- Sets the [Bone2D] node assigned to the FABRIK joint at [code]joint_idx[/code].
+ Sets the [Bone2D] node assigned to the FABRIK joint at [param joint_idx].
</description>
</method>
<method name="set_fabrik_joint_bone_index">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="bone_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="bone_idx" type="int" />
<description>
- Sets the bone index, [code]bone_index[/code], of the FABRIK joint at [code]joint_idx[/code]. When possible, this will also update the [code]bone2d_node[/code] of the FABRIK joint based on data provided by the linked skeleton.
+ Sets the bone index, [param bone_idx], of the FABRIK joint at [param joint_idx]. When possible, this will also update the [code]bone2d_node[/code] of the FABRIK joint based on data provided by the linked skeleton.
</description>
</method>
<method name="set_fabrik_joint_magnet_position">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="magnet_position" type="Vector2" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="magnet_position" type="Vector2" />
<description>
- Sets the magnet position vector for the joint at [code]joint_idx[/code].
+ Sets the magnet position vector for the joint at [param joint_idx].
</description>
</method>
<method name="set_fabrik_joint_use_target_rotation">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="use_target_rotation" type="bool" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="use_target_rotation" type="bool" />
<description>
- Sets whether the joint at [code]joint_idx[/code] will use the target node's rotation rather than letting FABRIK rotate the node.
+ Sets whether the joint at [param joint_idx] will use the target node's rotation rather than letting FABRIK rotate the node.
[b]Note:[/b] This option only works for the tip/final joint in the chain. For all other nodes, this option will be ignored.
</description>
</method>
</methods>
<members>
<member name="fabrik_data_chain_length" type="int" setter="set_fabrik_data_chain_length" getter="get_fabrik_data_chain_length" default="0">
- The amount of FABRIK joints in the FABRIK modification.
+ The number of FABRIK joints in the FABRIK modification.
</member>
<member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
The NodePath to the node that is the target for the FABRIK modification. This node is what the FABRIK chain will attempt to rotate the bone chain to.
diff --git a/doc/classes/SkeletonModification2DJiggle.xml b/doc/classes/SkeletonModification2DJiggle.xml
index 9948239eb8..7329b2d865 100644
--- a/doc/classes/SkeletonModification2DJiggle.xml
+++ b/doc/classes/SkeletonModification2DJiggle.xml
@@ -19,58 +19,58 @@
</method>
<method name="get_jiggle_joint_bone2d_node" qualifiers="const">
<return type="NodePath" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the [Bone2D] node assigned to the Jiggle joint at [code]joint_idx[/code].
+ Returns the [Bone2D] node assigned to the Jiggle joint at [param joint_idx].
</description>
</method>
<method name="get_jiggle_joint_bone_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the index of the [Bone2D] node assigned to the Jiggle joint at [code]joint_idx[/code].
+ Returns the index of the [Bone2D] node assigned to the Jiggle joint at [param joint_idx].
</description>
</method>
<method name="get_jiggle_joint_damping" qualifiers="const">
<return type="float" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the amount of damping of the Jiggle joint at [code]joint_idx[/code].
+ Returns the amount of damping of the Jiggle joint at [param joint_idx].
</description>
</method>
<method name="get_jiggle_joint_gravity" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns a [Vector2] representing the amount of gravity the Jiggle joint at [code]joint_idx[/code] is influenced by.
+ Returns a [Vector2] representing the amount of gravity the Jiggle joint at [param joint_idx] is influenced by.
</description>
</method>
<method name="get_jiggle_joint_mass" qualifiers="const">
<return type="float" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the amount of mass of the jiggle joint at [code]joint_idx[/code].
+ Returns the amount of mass of the jiggle joint at [param joint_idx].
</description>
</method>
<method name="get_jiggle_joint_override" qualifiers="const">
<return type="bool" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns a boolean that indicates whether the joint at [code]joint_idx[/code] is overriding the default Jiggle joint data defined in the modification.
+ Returns a boolean that indicates whether the joint at [param joint_idx] is overriding the default Jiggle joint data defined in the modification.
</description>
</method>
<method name="get_jiggle_joint_stiffness" qualifiers="const">
<return type="float" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the stiffness of the Jiggle joint at [code]joint_idx[/code].
+ Returns the stiffness of the Jiggle joint at [param joint_idx].
</description>
</method>
<method name="get_jiggle_joint_use_gravity" qualifiers="const">
<return type="bool" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns a boolean that indicates whether the joint at [code]joint_idx[/code] is using gravity or not.
+ Returns a boolean that indicates whether the joint at [param joint_idx] is using gravity or not.
</description>
</method>
<method name="get_use_colliders" qualifiers="const">
@@ -81,78 +81,78 @@
</method>
<method name="set_collision_mask">
<return type="void" />
- <argument index="0" name="collision_mask" type="int" />
+ <param index="0" name="collision_mask" type="int" />
<description>
Sets the collision mask that the Jiggle modifier will use when reacting to colliders, if the Jiggle modifier is set to take colliders into account.
</description>
</method>
<method name="set_jiggle_joint_bone2d_node">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="bone2d_node" type="NodePath" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="bone2d_node" type="NodePath" />
<description>
- Sets the [Bone2D] node assigned to the Jiggle joint at [code]joint_idx[/code].
+ Sets the [Bone2D] node assigned to the Jiggle joint at [param joint_idx].
</description>
</method>
<method name="set_jiggle_joint_bone_index">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="bone_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="bone_idx" type="int" />
<description>
- Sets the bone index, [code]bone_index[/code], of the Jiggle joint at [code]joint_idx[/code]. When possible, this will also update the [code]bone2d_node[/code] of the Jiggle joint based on data provided by the linked skeleton.
+ Sets the bone index, [param bone_idx], of the Jiggle joint at [param joint_idx]. When possible, this will also update the [code]bone2d_node[/code] of the Jiggle joint based on data provided by the linked skeleton.
</description>
</method>
<method name="set_jiggle_joint_damping">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="damping" type="float" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="damping" type="float" />
<description>
- Sets the amount of dampening of the Jiggle joint at [code]joint_idx[/code].
+ Sets the amount of dampening of the Jiggle joint at [param joint_idx].
</description>
</method>
<method name="set_jiggle_joint_gravity">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="gravity" type="Vector2" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="gravity" type="Vector2" />
<description>
- Sets the gravity vector of the Jiggle joint at [code]joint_idx[/code].
+ Sets the gravity vector of the Jiggle joint at [param joint_idx].
</description>
</method>
<method name="set_jiggle_joint_mass">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="mass" type="float" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="mass" type="float" />
<description>
- Sets the of mass of the Jiggle joint at [code]joint_idx[/code].
+ Sets the of mass of the Jiggle joint at [param joint_idx].
</description>
</method>
<method name="set_jiggle_joint_override">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="override" type="bool" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="override" type="bool" />
<description>
- Sets whether the Jiggle joint at [code]joint_idx[/code] should override the default Jiggle joint settings. Setting this to [code]true[/code] will make the joint use its own settings rather than the default ones attached to the modification.
+ Sets whether the Jiggle joint at [param joint_idx] should override the default Jiggle joint settings. Setting this to [code]true[/code] will make the joint use its own settings rather than the default ones attached to the modification.
</description>
</method>
<method name="set_jiggle_joint_stiffness">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="stiffness" type="float" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="stiffness" type="float" />
<description>
- Sets the of stiffness of the Jiggle joint at [code]joint_idx[/code].
+ Sets the of stiffness of the Jiggle joint at [param joint_idx].
</description>
</method>
<method name="set_jiggle_joint_use_gravity">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="use_gravity" type="bool" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="use_gravity" type="bool" />
<description>
- Sets whether the Jiggle joint at [code]joint_idx[/code] should use gravity.
+ Sets whether the Jiggle joint at [param joint_idx] should use gravity.
</description>
</method>
<method name="set_use_colliders">
<return type="void" />
- <argument index="0" name="use_colliders" type="bool" />
+ <param index="0" name="use_colliders" type="bool" />
<description>
If [code]true[/code], the Jiggle modifier will take colliders into account, keeping them from entering into these collision objects.
</description>
diff --git a/doc/classes/SkeletonModification2DLookAt.xml b/doc/classes/SkeletonModification2DLookAt.xml
index 802801fbef..4747b06056 100644
--- a/doc/classes/SkeletonModification2DLookAt.xml
+++ b/doc/classes/SkeletonModification2DLookAt.xml
@@ -41,14 +41,14 @@
</method>
<method name="set_additional_rotation">
<return type="void" />
- <argument index="0" name="rotation" type="float" />
+ <param index="0" name="rotation" type="float" />
<description>
Sets the amount of additional rotation that is to be applied after executing the modification. This allows for offsetting the results by the inputted rotation amount.
</description>
</method>
<method name="set_constraint_angle_invert">
<return type="void" />
- <argument index="0" name="invert" type="bool" />
+ <param index="0" name="invert" type="bool" />
<description>
When [code]true[/code], the modification will use an inverted joint constraint.
An inverted joint constraint only constraints the [Bone2D] to the angles [i]outside of[/i] the inputted minimum and maximum angles. For this reason, it is referred to as an inverted joint constraint, as it constraints the joint to the outside of the inputted values.
@@ -56,21 +56,21 @@
</method>
<method name="set_constraint_angle_max">
<return type="void" />
- <argument index="0" name="angle_max" type="float" />
+ <param index="0" name="angle_max" type="float" />
<description>
Sets the constraint's maximum allowed angle.
</description>
</method>
<method name="set_constraint_angle_min">
<return type="void" />
- <argument index="0" name="angle_min" type="float" />
+ <param index="0" name="angle_min" type="float" />
<description>
Sets the constraint's minimum allowed angle.
</description>
</method>
<method name="set_enable_constraint">
<return type="void" />
- <argument index="0" name="enable_constraint" type="bool" />
+ <param index="0" name="enable_constraint" type="bool" />
<description>
Sets whether this modification will use constraints or not. When [code]true[/code], constraints will be applied when solving the LookAt modification.
</description>
diff --git a/doc/classes/SkeletonModification2DPhysicalBones.xml b/doc/classes/SkeletonModification2DPhysicalBones.xml
index 9fb7b6d215..d5f46b2ea0 100644
--- a/doc/classes/SkeletonModification2DPhysicalBones.xml
+++ b/doc/classes/SkeletonModification2DPhysicalBones.xml
@@ -17,23 +17,23 @@
</method>
<method name="get_physical_bone_node" qualifiers="const">
<return type="NodePath" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the [PhysicalBone2D] node at [code]joint_idx[/code].
+ Returns the [PhysicalBone2D] node at [param joint_idx].
</description>
</method>
<method name="set_physical_bone_node">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="physicalbone2d_node" type="NodePath" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="physicalbone2d_node" type="NodePath" />
<description>
- Sets the [PhysicalBone2D] node at [code]joint_idx[/code].
+ Sets the [PhysicalBone2D] node at [param joint_idx].
[b]Note:[/b] This is just the index used for this modification, not the bone index used in the [Skeleton2D].
</description>
</method>
<method name="start_simulation">
<return type="void" />
- <argument index="0" name="bones" type="StringName[]" default="[]" />
+ <param index="0" name="bones" type="StringName[]" default="[]" />
<description>
Tell the [PhysicalBone2D] nodes to start simulating and interacting with the physics world.
Optionally, an array of bone names can be passed to this function, and that will cause only [PhysicalBone2D] nodes with those names to start simulating.
@@ -41,7 +41,7 @@
</method>
<method name="stop_simulation">
<return type="void" />
- <argument index="0" name="bones" type="StringName[]" default="[]" />
+ <param index="0" name="bones" type="StringName[]" default="[]" />
<description>
Tell the [PhysicalBone2D] nodes to stop simulating and interacting with the physics world.
Optionally, an array of bone names can be passed to this function, and that will cause only [PhysicalBone2D] nodes with those names to stop simulating.
@@ -50,7 +50,7 @@
</methods>
<members>
<member name="physical_bone_chain_length" type="int" setter="set_physical_bone_chain_length" getter="get_physical_bone_chain_length" default="0">
- The amount of [PhysicalBone2D] nodes linked in this modification.
+ The number of [PhysicalBone2D] nodes linked in this modification.
</member>
</members>
</class>
diff --git a/doc/classes/SkeletonModification2DStackHolder.xml b/doc/classes/SkeletonModification2DStackHolder.xml
index f66f88d6b5..791dea2fb1 100644
--- a/doc/classes/SkeletonModification2DStackHolder.xml
+++ b/doc/classes/SkeletonModification2DStackHolder.xml
@@ -18,7 +18,7 @@
</method>
<method name="set_held_modification_stack">
<return type="void" />
- <argument index="0" name="held_modification_stack" type="SkeletonModificationStack2D" />
+ <param index="0" name="held_modification_stack" type="SkeletonModificationStack2D" />
<description>
Sets the [SkeletonModificationStack2D] that this modification is holding. This modification stack will then be executed when this modification is executed.
</description>
diff --git a/doc/classes/SkeletonModification2DTwoBoneIK.xml b/doc/classes/SkeletonModification2DTwoBoneIK.xml
index 956e94dce8..edd5431a0c 100644
--- a/doc/classes/SkeletonModification2DTwoBoneIK.xml
+++ b/doc/classes/SkeletonModification2DTwoBoneIK.xml
@@ -36,28 +36,28 @@
</method>
<method name="set_joint_one_bone2d_node">
<return type="void" />
- <argument index="0" name="bone2d_node" type="NodePath" />
+ <param index="0" name="bone2d_node" type="NodePath" />
<description>
Sets the [Bone2D] node that is being used as the first bone in the TwoBoneIK modification.
</description>
</method>
<method name="set_joint_one_bone_idx">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
Sets the index of the [Bone2D] node that is being used as the first bone in the TwoBoneIK modification.
</description>
</method>
<method name="set_joint_two_bone2d_node">
<return type="void" />
- <argument index="0" name="bone2d_node" type="NodePath" />
+ <param index="0" name="bone2d_node" type="NodePath" />
<description>
Sets the [Bone2D] node that is being used as the second bone in the TwoBoneIK modification.
</description>
</method>
<method name="set_joint_two_bone_idx">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
Sets the index of the [Bone2D] node that is being used as the second bone in the TwoBoneIK modification.
</description>
diff --git a/doc/classes/SkeletonModification3D.xml b/doc/classes/SkeletonModification3D.xml
index b21c9a2be9..8457179651 100644
--- a/doc/classes/SkeletonModification3D.xml
+++ b/doc/classes/SkeletonModification3D.xml
@@ -12,14 +12,14 @@
<methods>
<method name="_execute" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="delta" type="float" />
+ <param index="0" name="delta" type="float" />
<description>
Executes the given modification. This is where the modification performs whatever function it is designed to do.
</description>
</method>
<method name="_setup_modification" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="modification_stack" type="SkeletonModificationStack3D" />
+ <param index="0" name="modification_stack" type="SkeletonModificationStack3D" />
<description>
Sets up the modification so it can be executed. This function should be called automatically by the [SkeletonModificationStack3D] containing this modification.
If you need to initialize a modification before use, this is the place to do it!
@@ -27,12 +27,12 @@
</method>
<method name="clamp_angle">
<return type="float" />
- <argument index="0" name="angle" type="float" />
- <argument index="1" name="min" type="float" />
- <argument index="2" name="max" type="float" />
- <argument index="3" name="invert" type="bool" />
+ <param index="0" name="angle" type="float" />
+ <param index="1" name="min" type="float" />
+ <param index="2" name="max" type="float" />
+ <param index="3" name="invert" type="bool" />
<description>
- Takes a angle and clamps it so it is within the passed-in [code]min[/code] and [code]max[/code] range. [code]invert[/code] will inversely clamp the angle, clamping it to the range outside of the given bounds.
+ Takes a angle and clamps it so it is within the passed-in [param min] and [param max] range. [param invert] will inversely clamp the angle, clamping it to the range outside of the given bounds.
</description>
</method>
<method name="get_is_setup" qualifiers="const">
@@ -49,7 +49,7 @@
</method>
<method name="set_is_setup">
<return type="void" />
- <argument index="0" name="is_setup" type="bool" />
+ <param index="0" name="is_setup" type="bool" />
<description>
Manually allows you to set the setup state of the modification. This function should only rarely be used, as the [SkeletonModificationStack3D] the modification is bound to should handle setting the modification up.
</description>
diff --git a/doc/classes/SkeletonModification3DCCDIK.xml b/doc/classes/SkeletonModification3DCCDIK.xml
index 6f5409ed4d..dec0fbe99f 100644
--- a/doc/classes/SkeletonModification3DCCDIK.xml
+++ b/doc/classes/SkeletonModification3DCCDIK.xml
@@ -14,114 +14,114 @@
<methods>
<method name="get_ccdik_joint_bone_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the bone index of the bone assigned to the CCDIK joint at [code]joint_idx[/code].
+ Returns the bone index of the bone assigned to the CCDIK joint at [param joint_idx].
</description>
</method>
<method name="get_ccdik_joint_bone_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the name of the bone that is assigned to the CCDIK joint at [code]joint_idx[/code].
+ Returns the name of the bone that is assigned to the CCDIK joint at [param joint_idx].
</description>
</method>
<method name="get_ccdik_joint_ccdik_axis" qualifiers="const">
<return type="int" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the integer representing the joint axis of the CCDIK joint at [code]joint_idx[/code].
+ Returns the integer representing the joint axis of the CCDIK joint at [param joint_idx].
</description>
</method>
<method name="get_ccdik_joint_constraint_angle_max" qualifiers="const">
<return type="float" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the maximum angle constraint for the joint at [code]joint_idx[/code]. [b]Note:[/b] This angle is in degrees!
+ Returns the maximum angle constraint for the joint at [param joint_idx]. [b]Note:[/b] This angle is in degrees!
</description>
</method>
<method name="get_ccdik_joint_constraint_angle_min" qualifiers="const">
<return type="float" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the minimum angle constraint for the joint at [code]joint_idx[/code]. [b]Note:[/b] This angle is in degrees!
+ Returns the minimum angle constraint for the joint at [param joint_idx]. [b]Note:[/b] This angle is in degrees!
</description>
</method>
<method name="get_ccdik_joint_constraint_invert" qualifiers="const">
<return type="bool" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns whether the CCDIK joint at [code]joint_idx[/code] uses an inverted joint constraint. See [method set_ccdik_joint_constraint_invert] for details.
+ Returns whether the CCDIK joint at [param joint_idx] uses an inverted joint constraint. See [method set_ccdik_joint_constraint_invert] for details.
</description>
</method>
<method name="get_ccdik_joint_enable_joint_constraint" qualifiers="const">
<return type="bool" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Enables angle constraints to the CCDIK joint at [code]joint_idx[/code].
+ Enables angle constraints to the CCDIK joint at [param joint_idx].
</description>
</method>
<method name="set_ccdik_joint_bone_index">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="bone_index" type="int" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="bone_index" type="int" />
<description>
- Sets the bone index, [code]bone_index[/code], of the CCDIK joint at [code]joint_idx[/code]. When possible, this will also update the [code]bone_name[/code] of the CCDIK joint based on data provided by the linked skeleton.
+ Sets the bone index, [param bone_index], of the CCDIK joint at [param joint_idx]. When possible, this will also update the [code]bone_name[/code] of the CCDIK joint based on data provided by the linked skeleton.
</description>
</method>
<method name="set_ccdik_joint_bone_name">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="bone_name" type="String" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="bone_name" type="String" />
<description>
- Sets the bone name, [code]bone_name[/code], of the CCDIK joint at [code]joint_idx[/code]. When possible, this will also update the [code]bone_index[/code] of the CCDIK joint based on data provided by the linked skeleton.
+ Sets the bone name, [param bone_name], of the CCDIK joint at [param joint_idx]. When possible, this will also update the [code]bone_index[/code] of the CCDIK joint based on data provided by the linked skeleton.
</description>
</method>
<method name="set_ccdik_joint_ccdik_axis">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="axis" type="int" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="axis" type="int" />
<description>
- Sets the joint axis of the CCDIK joint at [code]joint_idx[/code] to the passed-in joint axis, [code]axis[/code].
+ Sets the joint axis of the CCDIK joint at [param joint_idx] to the passed-in joint axis, [param axis].
</description>
</method>
<method name="set_ccdik_joint_constraint_angle_max">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="max_angle" type="float" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="max_angle" type="float" />
<description>
- Sets the maximum angle constraint for the joint at [code]joint_idx[/code]. [b]Note:[/b] This angle must be in radians!
+ Sets the maximum angle constraint for the joint at [param joint_idx]. [b]Note:[/b] This angle must be in radians!
</description>
</method>
<method name="set_ccdik_joint_constraint_angle_min">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="min_angle" type="float" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="min_angle" type="float" />
<description>
- Sets the minimum angle constraint for the joint at [code]joint_idx[/code]. [b]Note:[/b] This angle must be in radians!
+ Sets the minimum angle constraint for the joint at [param joint_idx]. [b]Note:[/b] This angle must be in radians!
</description>
</method>
<method name="set_ccdik_joint_constraint_invert">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="invert" type="bool" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="invert" type="bool" />
<description>
- Sets whether the CCDIK joint at [code]joint_idx[/code] uses an inverted joint constraint.
+ Sets whether the CCDIK joint at [param joint_idx] uses an inverted joint constraint.
An inverted joint constraint only constraints the CCDIK joint to the angles [i]outside of[/i] the inputted minimum and maximum angles. For this reason, it is referred to as an inverted joint constraint, as it constraints the joint to the outside of the inputted values.
</description>
</method>
<method name="set_ccdik_joint_enable_joint_constraint">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="enable" type="bool" />
<description>
- Sets whether joint constraints are enabled for the CCDIK joint at [code]joint_idx[/code].
+ Sets whether joint constraints are enabled for the CCDIK joint at [param joint_idx].
</description>
</method>
</methods>
<members>
<member name="ccdik_data_chain_length" type="int" setter="set_ccdik_data_chain_length" getter="get_ccdik_data_chain_length" default="0">
- The amount of CCDIK joints in the CCDIK modification.
+ The number of CCDIK joints in the CCDIK modification.
</member>
<member name="high_quality_solve" type="bool" setter="set_use_high_quality_solve" getter="get_use_high_quality_solve" default="true">
When true, the CCDIK algorithm will perform a higher quality solve that returns more natural results. A high quality solve requires more computation power to solve though, and therefore can be disabled to save performance.
diff --git a/doc/classes/SkeletonModification3DFABRIK.xml b/doc/classes/SkeletonModification3DFABRIK.xml
index 41f78fab41..325cc2a12e 100644
--- a/doc/classes/SkeletonModification3DFABRIK.xml
+++ b/doc/classes/SkeletonModification3DFABRIK.xml
@@ -15,56 +15,56 @@
<methods>
<method name="fabrik_joint_auto_calculate_length">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Will attempt to automatically calculate the length of the bone assigned to the FABRIK joint at [code]joint_idx[/code].
+ Will attempt to automatically calculate the length of the bone assigned to the FABRIK joint at [param joint_idx].
</description>
</method>
<method name="get_fabrik_joint_auto_calculate_length" qualifiers="const">
<return type="bool" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns a boolean that indicates whether this modification will attempt to autocalculate the length of the bone assigned to the FABRIK joint at [code]joint_idx[/code].
+ Returns a boolean that indicates whether this modification will attempt to autocalculate the length of the bone assigned to the FABRIK joint at [param joint_idx].
</description>
</method>
<method name="get_fabrik_joint_bone_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the bone index of the bone assigned to the FABRIK joint at [code]joint_idx[/code].
+ Returns the bone index of the bone assigned to the FABRIK joint at [param joint_idx].
</description>
</method>
<method name="get_fabrik_joint_bone_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the name of the bone that is assigned to the FABRIK joint at [code]joint_idx[/code].
+ Returns the name of the bone that is assigned to the FABRIK joint at [param joint_idx].
</description>
</method>
<method name="get_fabrik_joint_length" qualifiers="const">
<return type="float" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the length of the FABRIK joint at [code]joint_idx[/code].
+ Returns the length of the FABRIK joint at [param joint_idx].
</description>
</method>
<method name="get_fabrik_joint_magnet" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the magnet vector of the FABRIK joint at [code]joint_idx[/code].
+ Returns the magnet vector of the FABRIK joint at [param joint_idx].
</description>
</method>
<method name="get_fabrik_joint_tip_node" qualifiers="const">
<return type="NodePath" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the [Node3D]-based node placed at the tip of the FABRIK joint at [code]joint_idx[/code], if one has been set.
+ Returns the [Node3D]-based node placed at the tip of the FABRIK joint at [param joint_idx], if one has been set.
</description>
</method>
<method name="get_fabrik_joint_use_target_basis" qualifiers="const">
<return type="bool" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
Returns a boolean indicating whether the FABRIK joint uses the target's [Basis] for its rotation.
[b]Note:[/b] This option is only available for the final bone in the FABRIK chain, with this setting being ignored for all other bones.
@@ -72,75 +72,75 @@
</method>
<method name="get_fabrik_joint_use_tip_node" qualifiers="const">
<return type="bool" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Sets the [Node3D]-based node that will be used as the tip of the FABRIK joint at [code]joint_idx[/code].
+ Sets the [Node3D]-based node that will be used as the tip of the FABRIK joint at [param joint_idx].
</description>
</method>
<method name="set_fabrik_joint_auto_calculate_length">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="auto_calculate_length" type="bool" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="auto_calculate_length" type="bool" />
<description>
- When [code]true[/code], this modification will attempt to automatically calculate the length of the bone for the FABRIK joint at [code]joint_idx[/code]. It does this by either using the tip node assigned, if there is one assigned, or the distance the of the bone's children, if the bone has any. If the bone has no children and no tip node is assigned, then the modification [b]cannot[/b] autocalculate the joint's length. In this case, the joint length should be entered manually or a tip node assigned.
+ When [code]true[/code], this modification will attempt to automatically calculate the length of the bone for the FABRIK joint at [param joint_idx]. It does this by either using the tip node assigned, if there is one assigned, or the distance the of the bone's children, if the bone has any. If the bone has no children and no tip node is assigned, then the modification [b]cannot[/b] autocalculate the joint's length. In this case, the joint length should be entered manually or a tip node assigned.
</description>
</method>
<method name="set_fabrik_joint_bone_index">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="bone_index" type="int" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="bone_index" type="int" />
<description>
- Sets the bone index, [code]bone_index[/code], of the FABRIK joint at [code]joint_idx[/code]. When possible, this will also update the [code]bone_name[/code] of the FABRIK joint based on data provided by the [Skeleton3D].
+ Sets the bone index, [param bone_index], of the FABRIK joint at [param joint_idx]. When possible, this will also update the [code]bone_name[/code] of the FABRIK joint based on data provided by the [Skeleton3D].
</description>
</method>
<method name="set_fabrik_joint_bone_name">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="bone_name" type="String" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="bone_name" type="String" />
<description>
- Sets the bone name, [code]bone_name[/code], of the FABRIK joint at [code]joint_idx[/code]. When possible, this will also update the [code]bone_index[/code] of the FABRIK joint based on data provided by the [Skeleton3D].
+ Sets the bone name, [param bone_name], of the FABRIK joint at [param joint_idx]. When possible, this will also update the [code]bone_index[/code] of the FABRIK joint based on data provided by the [Skeleton3D].
</description>
</method>
<method name="set_fabrik_joint_length">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="length" type="float" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="length" type="float" />
<description>
- Sets the joint length, [code]length[/code], of the FABRIK joint at [code]joint_idx[/code].
+ Sets the joint length, [param length], of the FABRIK joint at [param joint_idx].
</description>
</method>
<method name="set_fabrik_joint_magnet">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="magnet_position" type="Vector3" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="magnet_position" type="Vector3" />
<description>
- Sets the magenet position to [code]magnet_position[/code] for the joint at [code]joint_idx[/code]. The magnet position is used to nudge the joint in that direction when solving, which gives some control over how that joint will bend when being solved.
+ Sets the magenet position to [param magnet_position] for the joint at [param joint_idx]. The magnet position is used to nudge the joint in that direction when solving, which gives some control over how that joint will bend when being solved.
</description>
</method>
<method name="set_fabrik_joint_tip_node">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="tip_node" type="NodePath" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="tip_node" type="NodePath" />
<description>
- Sets the nodepath of the FARIK joint at [code]joint_idx[/code] to [code]tip_node[/code]. The tip node is used to calculate the length of the FABRIK joint when set to automatically calculate joint length.
+ Sets the nodepath of the FARIK joint at [param joint_idx] to [param tip_node]. The tip node is used to calculate the length of the FABRIK joint when set to automatically calculate joint length.
[b]Note:[/b] The tip node should generally be a child node of a [BoneAttachment3D] node attached to the bone that this FABRIK joint operates on, with the child node being offset so it is at the end of the bone.
</description>
</method>
<method name="set_fabrik_joint_use_target_basis">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="use_target_basis" type="bool" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="use_target_basis" type="bool" />
<description>
- Sets whether the FABRIK joint at [code]joint_idx[/code] uses the target's [Basis] for its rotation.
+ Sets whether the FABRIK joint at [param joint_idx] uses the target's [Basis] for its rotation.
[b]Note:[/b] This option is only available for the final bone in the FABRIK chain, with this setting being ignored for all other bones.
</description>
</method>
<method name="set_fabrik_joint_use_tip_node">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="use_tip_node" type="bool" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="use_tip_node" type="bool" />
<description>
- Sets whether the tip node should be used when autocalculating the joint length for the FABRIK joint at [code]joint_idx[/code]. This will only work if there is a node assigned to the tip nodepath for this joint.
+ Sets whether the tip node should be used when autocalculating the joint length for the FABRIK joint at [param joint_idx]. This will only work if there is a node assigned to the tip nodepath for this joint.
</description>
</method>
</methods>
diff --git a/doc/classes/SkeletonModification3DJiggle.xml b/doc/classes/SkeletonModification3DJiggle.xml
index 697de4a580..ef469d42ea 100644
--- a/doc/classes/SkeletonModification3DJiggle.xml
+++ b/doc/classes/SkeletonModification3DJiggle.xml
@@ -19,65 +19,65 @@
</method>
<method name="get_jiggle_joint_bone_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the bone index of the bone assigned to the Jiggle joint at [code]joint_idx[/code].
+ Returns the bone index of the bone assigned to the Jiggle joint at [param joint_idx].
</description>
</method>
<method name="get_jiggle_joint_bone_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the name of the bone that is assigned to the Jiggle joint at [code]joint_idx[/code].
+ Returns the name of the bone that is assigned to the Jiggle joint at [param joint_idx].
</description>
</method>
<method name="get_jiggle_joint_damping" qualifiers="const">
<return type="float" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the amount of dampening of the Jiggle joint at [code]joint_idx[/code].
+ Returns the amount of dampening of the Jiggle joint at [param joint_idx].
</description>
</method>
<method name="get_jiggle_joint_gravity" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns a [Vector3] representign the amount of gravity the Jiggle joint at [code]joint_idx[/code] is influenced by.
+ Returns a [Vector3] representign the amount of gravity the Jiggle joint at [param joint_idx] is influenced by.
</description>
</method>
<method name="get_jiggle_joint_mass" qualifiers="const">
<return type="float" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the amount of mass of the Jiggle joint at [code]joint_idx[/code].
+ Returns the amount of mass of the Jiggle joint at [param joint_idx].
</description>
</method>
<method name="get_jiggle_joint_override" qualifiers="const">
<return type="bool" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns a boolean that indicates whether the joint at [code]joint_idx[/code] is overriding the default jiggle joint data defined in the modification.
+ Returns a boolean that indicates whether the joint at [param joint_idx] is overriding the default jiggle joint data defined in the modification.
</description>
</method>
<method name="get_jiggle_joint_roll" qualifiers="const">
<return type="float" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
Returns the amount of roll/twist applied to the bone that the Jiggle joint is applied to.
</description>
</method>
<method name="get_jiggle_joint_stiffness" qualifiers="const">
<return type="float" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns the stiffness of the Jiggle joint at [code]joint_idx[/code].
+ Returns the stiffness of the Jiggle joint at [param joint_idx].
</description>
</method>
<method name="get_jiggle_joint_use_gravity" qualifiers="const">
<return type="bool" />
- <argument index="0" name="joint_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
<description>
- Returns a boolean that indicates whether the joint at [code]joint_idx[/code] is using gravity or not.
+ Returns a boolean that indicates whether the joint at [param joint_idx] is using gravity or not.
</description>
</method>
<method name="get_use_colliders" qualifiers="const">
@@ -88,86 +88,86 @@
</method>
<method name="set_collision_mask">
<return type="void" />
- <argument index="0" name="mask" type="int" />
+ <param index="0" name="mask" type="int" />
<description>
Sets the collision mask that the Jiggle modifier takes into account when performing physics calculations.
</description>
</method>
<method name="set_jiggle_joint_bone_index">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="bone_idx" type="int" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="bone_idx" type="int" />
<description>
- Sets the bone index, [code]bone_index[/code], of the Jiggle joint at [code]joint_idx[/code]. When possible, this will also update the [code]bone_name[/code] of the Jiggle joint based on data provided by the [Skeleton3D].
+ Sets the bone index, [param bone_idx], of the Jiggle joint at [param joint_idx]. When possible, this will also update the [code]bone_name[/code] of the Jiggle joint based on data provided by the [Skeleton3D].
</description>
</method>
<method name="set_jiggle_joint_bone_name">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="name" type="String" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="name" type="String" />
<description>
- Sets the bone name, [code]bone_name[/code], of the Jiggle joint at [code]joint_idx[/code]. When possible, this will also update the [code]bone_index[/code] of the Jiggle joint based on data provided by the [Skeleton3D].
+ Sets the bone name, [param name], of the Jiggle joint at [param joint_idx]. When possible, this will also update the [code]bone_index[/code] of the Jiggle joint based on data provided by the [Skeleton3D].
</description>
</method>
<method name="set_jiggle_joint_damping">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="damping" type="float" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="damping" type="float" />
<description>
- Sets the amount of dampening of the Jiggle joint at [code]joint_idx[/code].
+ Sets the amount of dampening of the Jiggle joint at [param joint_idx].
</description>
</method>
<method name="set_jiggle_joint_gravity">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="gravity" type="Vector3" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="gravity" type="Vector3" />
<description>
- Sets the gravity vector of the Jiggle joint at [code]joint_idx[/code].
+ Sets the gravity vector of the Jiggle joint at [param joint_idx].
</description>
</method>
<method name="set_jiggle_joint_mass">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="mass" type="float" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="mass" type="float" />
<description>
- Sets the of mass of the Jiggle joint at [code]joint_idx[/code].
+ Sets the of mass of the Jiggle joint at [param joint_idx].
</description>
</method>
<method name="set_jiggle_joint_override">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="override" type="bool" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="override" type="bool" />
<description>
- Sets whether the Jiggle joint at [code]joint_idx[/code] should override the default Jiggle joint settings. Setting this to true will make the joint use its own settings rather than the default ones attached to the modification.
+ Sets whether the Jiggle joint at [param joint_idx] should override the default Jiggle joint settings. Setting this to true will make the joint use its own settings rather than the default ones attached to the modification.
</description>
</method>
<method name="set_jiggle_joint_roll">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="roll" type="float" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="roll" type="float" />
<description>
Sets the amount of roll/twist on the bone the Jiggle joint is attached to.
</description>
</method>
<method name="set_jiggle_joint_stiffness">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="stiffness" type="float" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="stiffness" type="float" />
<description>
- Sets the of stiffness of the Jiggle joint at [code]joint_idx[/code].
+ Sets the of stiffness of the Jiggle joint at [param joint_idx].
</description>
</method>
<method name="set_jiggle_joint_use_gravity">
<return type="void" />
- <argument index="0" name="joint_idx" type="int" />
- <argument index="1" name="use_gravity" type="bool" />
+ <param index="0" name="joint_idx" type="int" />
+ <param index="1" name="use_gravity" type="bool" />
<description>
- Sets whether the Jiggle joint at [code]joint_idx[/code] should use gravity.
+ Sets whether the Jiggle joint at [param joint_idx] should use gravity.
</description>
</method>
<method name="set_use_colliders">
<return type="void" />
- <argument index="0" name="use_colliders" type="bool" />
+ <param index="0" name="use_colliders" type="bool" />
<description>
When [code]true[/code], the Jiggle modifier will use raycasting to prevent the Jiggle joints from rotating themselves into collision objects when solving.
</description>
diff --git a/doc/classes/SkeletonModification3DLookAt.xml b/doc/classes/SkeletonModification3DLookAt.xml
index 90330c4cf0..3602cfad95 100644
--- a/doc/classes/SkeletonModification3DLookAt.xml
+++ b/doc/classes/SkeletonModification3DLookAt.xml
@@ -29,20 +29,20 @@
</method>
<method name="set_additional_rotation">
<return type="void" />
- <argument index="0" name="additional_rotation" type="Vector3" />
+ <param index="0" name="additional_rotation" type="Vector3" />
<description>
Sets the amount of extra rotation to be applied after the LookAt modification executes. This allows you to adjust the finished result.
</description>
</method>
<method name="set_lock_rotation_plane">
<return type="void" />
- <argument index="0" name="plane" type="int" />
+ <param index="0" name="plane" type="int" />
<description>
</description>
</method>
<method name="set_lock_rotation_to_plane">
<return type="void" />
- <argument index="0" name="lock_to_plane" type="bool" />
+ <param index="0" name="lock_to_plane" type="bool" />
<description>
When [code]true[/code], the LookAt modification will limit its rotation to a single plane in 3D space. The plane used can be configured using the [code]set_lock_rotation_plane[/code] function.
</description>
diff --git a/doc/classes/SkeletonModification3DStackHolder.xml b/doc/classes/SkeletonModification3DStackHolder.xml
index d5ed770fc0..24240236a4 100644
--- a/doc/classes/SkeletonModification3DStackHolder.xml
+++ b/doc/classes/SkeletonModification3DStackHolder.xml
@@ -18,7 +18,7 @@
</method>
<method name="set_held_modification_stack">
<return type="void" />
- <argument index="0" name="held_modification_stack" type="SkeletonModificationStack3D" />
+ <param index="0" name="held_modification_stack" type="SkeletonModificationStack3D" />
<description>
Sets the [SkeletonModificationStack3D] that this modification is holding. This modification stack will then be executed when this modification is executed.
</description>
diff --git a/doc/classes/SkeletonModification3DTwoBoneIK.xml b/doc/classes/SkeletonModification3DTwoBoneIK.xml
index 0576591e2e..6618ebbcfb 100644
--- a/doc/classes/SkeletonModification3DTwoBoneIK.xml
+++ b/doc/classes/SkeletonModification3DTwoBoneIK.xml
@@ -91,7 +91,7 @@
</method>
<method name="set_auto_calculate_joint_length">
<return type="void" />
- <argument index="0" name="auto_calculate_joint_length" type="bool" />
+ <param index="0" name="auto_calculate_joint_length" type="bool" />
<description>
If true, the TwoBoneIK modification will attempt to autocalculate the lengths of the bones being used. The first bone will be calculated by using the distance from the origin of the first bone to the origin of the second bone.
The second bone will be calculated either using the tip node if that setting is enabled, or by using the distances of the second bone's children. If the tip node is not enabled and the bone has no children, then the length cannot be autocalculated. In this case, the length will either have to be manually inputted or a tip node used to calculate the length.
@@ -99,70 +99,70 @@
</method>
<method name="set_joint_one_bone_idx">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
- Sets the bone index, [code]bone_index[/code], of the first bone. When possible, this will also update the [code]bone_name[/code] of the first bone based on data provided by the [Skeleton3D].
+ Sets the bone index, [param bone_idx], of the first bone. When possible, this will also update the [code]bone_name[/code] of the first bone based on data provided by the [Skeleton3D].
</description>
</method>
<method name="set_joint_one_bone_name">
<return type="void" />
- <argument index="0" name="bone_name" type="String" />
+ <param index="0" name="bone_name" type="String" />
<description>
- Sets the bone name, [code]bone_name[/code], of the first bone. When possible, this will also update the [code]bone_index[/code] of the first bone based on data provided by the [Skeleton3D].
+ Sets the bone name, [param bone_name], of the first bone. When possible, this will also update the [code]bone_index[/code] of the first bone based on data provided by the [Skeleton3D].
</description>
</method>
<method name="set_joint_one_length">
<return type="void" />
- <argument index="0" name="bone_length" type="float" />
+ <param index="0" name="bone_length" type="float" />
<description>
Sets the length of the first bone in the TwoBoneIK modification.
</description>
</method>
<method name="set_joint_one_roll">
<return type="void" />
- <argument index="0" name="roll" type="float" />
+ <param index="0" name="roll" type="float" />
<description>
Sets the amount of roll/twist applied to the first bone in the TwoBoneIK modification.
</description>
</method>
<method name="set_joint_two_bone_idx">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
- Sets the bone index, [code]bone_index[/code], of the second bone. When possible, this will also update the [code]bone_name[/code] of the second bone based on data provided by the [Skeleton3D].
+ Sets the bone index, [param bone_idx], of the second bone. When possible, this will also update the [code]bone_name[/code] of the second bone based on data provided by the [Skeleton3D].
</description>
</method>
<method name="set_joint_two_bone_name">
<return type="void" />
- <argument index="0" name="bone_name" type="String" />
+ <param index="0" name="bone_name" type="String" />
<description>
- Sets the bone name, [code]bone_name[/code], of the second bone. When possible, this will also update the [code]bone_index[/code] of the second bone based on data provided by the [Skeleton3D].
+ Sets the bone name, [param bone_name], of the second bone. When possible, this will also update the [code]bone_index[/code] of the second bone based on data provided by the [Skeleton3D].
</description>
</method>
<method name="set_joint_two_length">
<return type="void" />
- <argument index="0" name="bone_length" type="float" />
+ <param index="0" name="bone_length" type="float" />
<description>
Sets the length of the second bone in the TwoBoneIK modification.
</description>
</method>
<method name="set_joint_two_roll">
<return type="void" />
- <argument index="0" name="roll" type="float" />
+ <param index="0" name="roll" type="float" />
<description>
Sets the amount of roll/twist applied to the second bone in the TwoBoneIK modification.
</description>
</method>
<method name="set_pole_node">
<return type="void" />
- <argument index="0" name="pole_nodepath" type="NodePath" />
+ <param index="0" name="pole_nodepath" type="NodePath" />
<description>
Sets the node to be used as the for the pole of the TwoBoneIK. When a node is set and the modification is set to use the pole node, the TwoBoneIK modification will bend the nodes in the direction towards this node when the bones need to bend.
</description>
</method>
<method name="set_tip_node">
<return type="void" />
- <argument index="0" name="tip_nodepath" type="NodePath" />
+ <param index="0" name="tip_nodepath" type="NodePath" />
<description>
Sets the node to be used as the tip for the second bone. This is used to calculate the length and position of the end of the second bone in the TwoBoneIK modification.
[b]Note:[/b] The tip node should generally be a child node of a [BoneAttachment3D] node attached to the second bone, with the child node being offset so it is at the end of the bone.
@@ -170,14 +170,14 @@
</method>
<method name="set_use_pole_node">
<return type="void" />
- <argument index="0" name="use_pole_node" type="bool" />
+ <param index="0" name="use_pole_node" type="bool" />
<description>
When [code]true[/code], the TwoBoneIK modification will bend the bones towards the pole node, if one has been set. This gives control over the direction the TwoBoneIK solver will bend, which is helpful for joints like elbows that only bend in certain directions.
</description>
</method>
<method name="set_use_tip_node">
<return type="void" />
- <argument index="0" name="use_tip_node" type="bool" />
+ <param index="0" name="use_tip_node" type="bool" />
<description>
When [code]true[/code], the TwoBoneIK modification will use the tip node to calculate the distance and position of the end/tip of the second bone. This is the most stable solution for knowing the tip position and length of the second bone.
</description>
diff --git a/doc/classes/SkeletonModificationStack2D.xml b/doc/classes/SkeletonModificationStack2D.xml
index 9ddb8856ce..950e52e622 100644
--- a/doc/classes/SkeletonModificationStack2D.xml
+++ b/doc/classes/SkeletonModificationStack2D.xml
@@ -13,31 +13,31 @@
<methods>
<method name="add_modification">
<return type="void" />
- <argument index="0" name="modification" type="SkeletonModification2D" />
+ <param index="0" name="modification" type="SkeletonModification2D" />
<description>
Adds the passed-in [SkeletonModification2D] to the stack.
</description>
</method>
<method name="delete_modification">
<return type="void" />
- <argument index="0" name="mod_idx" type="int" />
+ <param index="0" name="mod_idx" type="int" />
<description>
- Deletes the [SkeletonModification2D] at the index position [code]mod_idx[/code], if it exists.
+ Deletes the [SkeletonModification2D] at the index position [param mod_idx], if it exists.
</description>
</method>
<method name="enable_all_modifications">
<return type="void" />
- <argument index="0" name="enabled" type="bool" />
+ <param index="0" name="enabled" type="bool" />
<description>
Enables all [SkeletonModification2D]s in the stack.
</description>
</method>
<method name="execute">
<return type="void" />
- <argument index="0" name="delta" type="float" />
- <argument index="1" name="execution_mode" type="int" />
+ <param index="0" name="delta" type="float" />
+ <param index="1" name="execution_mode" type="int" />
<description>
- Executes all of the [SkeletonModification2D]s in the stack that use the same execution mode as the passed-in [code]execution_mode[/code], starting from index [code]0[/code] to [member modification_count].
+ Executes all of the [SkeletonModification2D]s in the stack that use the same execution mode as the passed-in [param execution_mode], starting from index [code]0[/code] to [member modification_count].
[b]Note:[/b] The order of the modifications can matter depending on the modifications. For example, modifications on a spine should operate before modifications on the arms in order to get proper results.
</description>
</method>
@@ -49,9 +49,9 @@
</method>
<method name="get_modification" qualifiers="const">
<return type="SkeletonModification2D" />
- <argument index="0" name="mod_idx" type="int" />
+ <param index="0" name="mod_idx" type="int" />
<description>
- Returns the [SkeletonModification2D] at the passed-in index, [code]mod_idx[/code].
+ Returns the [SkeletonModification2D] at the passed-in index, [param mod_idx].
</description>
</method>
<method name="get_skeleton" qualifiers="const">
@@ -62,10 +62,10 @@
</method>
<method name="set_modification">
<return type="void" />
- <argument index="0" name="mod_idx" type="int" />
- <argument index="1" name="modification" type="SkeletonModification2D" />
+ <param index="0" name="mod_idx" type="int" />
+ <param index="1" name="modification" type="SkeletonModification2D" />
<description>
- Sets the modification at [code]mod_idx[/code] to the passed-in modification, [code]modification[/code].
+ Sets the modification at [param mod_idx] to the passed-in modification, [param modification].
</description>
</method>
<method name="setup">
diff --git a/doc/classes/SkeletonModificationStack3D.xml b/doc/classes/SkeletonModificationStack3D.xml
index fc952f6864..34c7099bca 100644
--- a/doc/classes/SkeletonModificationStack3D.xml
+++ b/doc/classes/SkeletonModificationStack3D.xml
@@ -12,31 +12,31 @@
<methods>
<method name="add_modification">
<return type="void" />
- <argument index="0" name="modification" type="SkeletonModification3D" />
+ <param index="0" name="modification" type="SkeletonModification3D" />
<description>
Adds the passed-in [SkeletonModification3D] to the stack.
</description>
</method>
<method name="delete_modification">
<return type="void" />
- <argument index="0" name="mod_idx" type="int" />
+ <param index="0" name="mod_idx" type="int" />
<description>
- Deletes the [SkeletonModification3D] at the index position [code]mod_idx[/code], if it exists.
+ Deletes the [SkeletonModification3D] at the index position [param mod_idx], if it exists.
</description>
</method>
<method name="enable_all_modifications">
<return type="void" />
- <argument index="0" name="enabled" type="bool" />
+ <param index="0" name="enabled" type="bool" />
<description>
Enables all [SkeletonModification3D]s in the stack.
</description>
</method>
<method name="execute">
<return type="void" />
- <argument index="0" name="delta" type="float" />
- <argument index="1" name="execution_mode" type="int" />
+ <param index="0" name="delta" type="float" />
+ <param index="1" name="execution_mode" type="int" />
<description>
- Executes all of the [SkeletonModification3D]s in the stack that use the same execution mode as the passed-in [code]execution_mode[/code], starting from index [code]0[/code] to [member modification_count].
+ Executes all of the [SkeletonModification3D]s in the stack that use the same execution mode as the passed-in [param execution_mode], starting from index [code]0[/code] to [member modification_count].
[b]Note:[/b] The order of the modifications can matter depending on the modifications. For example, modifications on a spine should operate before modifications on the arms in order to get proper results.
</description>
</method>
@@ -48,9 +48,9 @@
</method>
<method name="get_modification" qualifiers="const">
<return type="SkeletonModification3D" />
- <argument index="0" name="mod_idx" type="int" />
+ <param index="0" name="mod_idx" type="int" />
<description>
- Returns the [SkeletonModification3D] at the passed-in index, [code]mod_idx[/code].
+ Returns the [SkeletonModification3D] at the passed-in index, [param mod_idx].
</description>
</method>
<method name="get_skeleton" qualifiers="const">
@@ -61,10 +61,10 @@
</method>
<method name="set_modification">
<return type="void" />
- <argument index="0" name="mod_idx" type="int" />
- <argument index="1" name="modification" type="SkeletonModification3D" />
+ <param index="0" name="mod_idx" type="int" />
+ <param index="1" name="modification" type="SkeletonModification3D" />
<description>
- Sets the modification at [code]mod_idx[/code] to the passed-in modification, [code]modification[/code].
+ Sets the modification at [param mod_idx] to the passed-in modification, [param modification].
</description>
</method>
<method name="setup">
@@ -79,7 +79,7 @@
When true, the modification's in the stack will be called. This is handled automatically through the [Skeleton3D] node.
</member>
<member name="modification_count" type="int" setter="set_modification_count" getter="get_modification_count" default="0">
- The amount of modifications in the stack.
+ The number of modifications in the stack.
</member>
<member name="strength" type="float" setter="set_strength" getter="get_strength" default="1.0">
The interpolation strength of the modifications in stack. A value of [code]0[/code] will make it where the modifications are not applied, a strength of [code]0.5[/code] will be half applied, and a strength of [code]1[/code] will allow the modifications to be fully applied and override the skeleton bone poses.
diff --git a/doc/classes/SkeletonProfile.xml b/doc/classes/SkeletonProfile.xml
index 5c2d0eefb4..55d21f3224 100644
--- a/doc/classes/SkeletonProfile.xml
+++ b/doc/classes/SkeletonProfile.xml
@@ -11,149 +11,149 @@
<methods>
<method name="find_bone" qualifiers="const">
<return type="int" />
- <argument index="0" name="bone_name" type="StringName" />
+ <param index="0" name="bone_name" type="StringName" />
<description>
- Returns the bone index that matches [code]bone_name[/code] as its name.
+ Returns the bone index that matches [param bone_name] as its name.
</description>
</method>
<method name="get_bone_name" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
- Returns the name of the bone at [code]bone_idx[/code] that will be the key name in the [BoneMap].
+ Returns the name of the bone at [param bone_idx] that will be the key name in the [BoneMap].
In the retargeting process, the returned bone name is the bone name of the target skeleton.
</description>
</method>
<method name="get_bone_parent" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
- Returns the name of the bone which is the parent to the bone at [code]bone_idx[/code]. The result is empty if the bone has no parent.
+ Returns the name of the bone which is the parent to the bone at [param bone_idx]. The result is empty if the bone has no parent.
</description>
</method>
<method name="get_bone_tail" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
- Returns the name of the bone which is the tail of the bone at [code]bone_idx[/code].
+ Returns the name of the bone which is the tail of the bone at [param bone_idx].
</description>
</method>
<method name="get_group" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
- Returns the group of the bone at [code]bone_idx[/code].
+ Returns the group of the bone at [param bone_idx].
</description>
</method>
<method name="get_group_name" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="group_idx" type="int" />
+ <param index="0" name="group_idx" type="int" />
<description>
- Returns the name of the group at [code]group_idx[/code] that will be the drawing group in the [BoneMap] editor.
+ Returns the name of the group at [param group_idx] that will be the drawing group in the [BoneMap] editor.
</description>
</method>
<method name="get_handle_offset" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
- Returns the offset of the bone at [code]bone_idx[/code] that will be the button position in the [BoneMap] editor.
+ Returns the offset of the bone at [param bone_idx] that will be the button position in the [BoneMap] editor.
This is the offset with origin at the top left corner of the square.
</description>
</method>
<method name="get_reference_pose" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
- Returns the reference pose transform for bone [code]bone_idx[/code].
+ Returns the reference pose transform for bone [param bone_idx].
</description>
</method>
<method name="get_tail_direction" qualifiers="const">
<return type="int" enum="SkeletonProfile.TailDirection" />
- <argument index="0" name="bone_idx" type="int" />
+ <param index="0" name="bone_idx" type="int" />
<description>
- Returns the tail direction of the bone at [code]bone_idx[/code].
+ Returns the tail direction of the bone at [param bone_idx].
</description>
</method>
<method name="get_texture" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="group_idx" type="int" />
+ <param index="0" name="group_idx" type="int" />
<description>
- Returns the texture of the group at [code]group_idx[/code] that will be the drawing group background image in the [BoneMap] editor.
+ Returns the texture of the group at [param group_idx] that will be the drawing group background image in the [BoneMap] editor.
</description>
</method>
<method name="set_bone_name">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="bone_name" type="StringName" />
+ <param index="0" name="bone_idx" type="int" />
+ <param index="1" name="bone_name" type="StringName" />
<description>
- Sets the name of the bone at [code]bone_idx[/code] that will be the key name in the [BoneMap].
+ Sets the name of the bone at [param bone_idx] that will be the key name in the [BoneMap].
In the retargeting process, the setting bone name is the bone name of the target skeleton.
</description>
</method>
<method name="set_bone_parent">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="bone_parent" type="StringName" />
+ <param index="0" name="bone_idx" type="int" />
+ <param index="1" name="bone_parent" type="StringName" />
<description>
- Sets the bone with name [code]bone_parent[/code] as the parent of the bone at [code]bone_idx[/code]. If an empty string is passed, then the bone has no parent.
+ Sets the bone with name [param bone_parent] as the parent of the bone at [param bone_idx]. If an empty string is passed, then the bone has no parent.
</description>
</method>
<method name="set_bone_tail">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="bone_tail" type="StringName" />
+ <param index="0" name="bone_idx" type="int" />
+ <param index="1" name="bone_tail" type="StringName" />
<description>
- Sets the bone with name [code]bone_tail[/code] as the tail of the bone at [code]bone_idx[/code].
+ Sets the bone with name [param bone_tail] as the tail of the bone at [param bone_idx].
</description>
</method>
<method name="set_group">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="group" type="StringName" />
+ <param index="0" name="bone_idx" type="int" />
+ <param index="1" name="group" type="StringName" />
<description>
- Sets the group of the bone at [code]bone_idx[/code].
+ Sets the group of the bone at [param bone_idx].
</description>
</method>
<method name="set_group_name">
<return type="void" />
- <argument index="0" name="group_idx" type="int" />
- <argument index="1" name="group_name" type="StringName" />
+ <param index="0" name="group_idx" type="int" />
+ <param index="1" name="group_name" type="StringName" />
<description>
- Sets the name of the group at [code]group_idx[/code] that will be the drawing group in the [BoneMap] editor.
+ Sets the name of the group at [param group_idx] that will be the drawing group in the [BoneMap] editor.
</description>
</method>
<method name="set_handle_offset">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="handle_offset" type="Vector2" />
+ <param index="0" name="bone_idx" type="int" />
+ <param index="1" name="handle_offset" type="Vector2" />
<description>
- Sets the offset of the bone at [code]bone_idx[/code] that will be the button position in the [BoneMap] editor.
+ Sets the offset of the bone at [param bone_idx] that will be the button position in the [BoneMap] editor.
This is the offset with origin at the top left corner of the square.
</description>
</method>
<method name="set_reference_pose">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="bone_name" type="Transform3D" />
+ <param index="0" name="bone_idx" type="int" />
+ <param index="1" name="bone_name" type="Transform3D" />
<description>
- Sets the reference pose transform for bone [code]bone_idx[/code].
+ Sets the reference pose transform for bone [param bone_idx].
</description>
</method>
<method name="set_tail_direction">
<return type="void" />
- <argument index="0" name="bone_idx" type="int" />
- <argument index="1" name="tail_direction" type="int" enum="SkeletonProfile.TailDirection" />
+ <param index="0" name="bone_idx" type="int" />
+ <param index="1" name="tail_direction" type="int" enum="SkeletonProfile.TailDirection" />
<description>
- Sets the tail direction of the bone at [code]bone_idx[/code].
+ Sets the tail direction of the bone at [param bone_idx].
[b]Note:[/b] This only specifies the method of calculation. The actual coordinates required should be stored in an external skeleton, so the calculation itself needs to be done externally.
</description>
</method>
<method name="set_texture">
<return type="void" />
- <argument index="0" name="group_idx" type="int" />
- <argument index="1" name="texture" type="Texture2D" />
+ <param index="0" name="group_idx" type="int" />
+ <param index="1" name="texture" type="Texture2D" />
<description>
- Sets the texture of the group at [code]group_idx[/code] that will be the drawing group background image in the [BoneMap] editor.
+ Sets the texture of the group at [param group_idx] that will be the drawing group background image in the [BoneMap] editor.
</description>
</method>
</methods>
diff --git a/doc/classes/Skin.xml b/doc/classes/Skin.xml
index af1af7bad2..ea60bd707d 100644
--- a/doc/classes/Skin.xml
+++ b/doc/classes/Skin.xml
@@ -9,15 +9,15 @@
<methods>
<method name="add_bind">
<return type="void" />
- <argument index="0" name="bone" type="int" />
- <argument index="1" name="pose" type="Transform3D" />
+ <param index="0" name="bone" type="int" />
+ <param index="1" name="pose" type="Transform3D" />
<description>
</description>
</method>
<method name="add_named_bind">
<return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="pose" type="Transform3D" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="pose" type="Transform3D" />
<description>
</description>
</method>
@@ -28,7 +28,7 @@
</method>
<method name="get_bind_bone" qualifiers="const">
<return type="int" />
- <argument index="0" name="bind_index" type="int" />
+ <param index="0" name="bind_index" type="int" />
<description>
</description>
</method>
@@ -39,40 +39,40 @@
</method>
<method name="get_bind_name" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="bind_index" type="int" />
+ <param index="0" name="bind_index" type="int" />
<description>
</description>
</method>
<method name="get_bind_pose" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="bind_index" type="int" />
+ <param index="0" name="bind_index" type="int" />
<description>
</description>
</method>
<method name="set_bind_bone">
<return type="void" />
- <argument index="0" name="bind_index" type="int" />
- <argument index="1" name="bone" type="int" />
+ <param index="0" name="bind_index" type="int" />
+ <param index="1" name="bone" type="int" />
<description>
</description>
</method>
<method name="set_bind_count">
<return type="void" />
- <argument index="0" name="bind_count" type="int" />
+ <param index="0" name="bind_count" type="int" />
<description>
</description>
</method>
<method name="set_bind_name">
<return type="void" />
- <argument index="0" name="bind_index" type="int" />
- <argument index="1" name="name" type="StringName" />
+ <param index="0" name="bind_index" type="int" />
+ <param index="1" name="name" type="StringName" />
<description>
</description>
</method>
<method name="set_bind_pose">
<return type="void" />
- <argument index="0" name="bind_index" type="int" />
- <argument index="1" name="pose" type="Transform3D" />
+ <param index="0" name="bind_index" type="int" />
+ <param index="1" name="pose" type="Transform3D" />
<description>
</description>
</method>
diff --git a/doc/classes/Slider.xml b/doc/classes/Slider.xml
index 4139530db1..c3dbd69e59 100644
--- a/doc/classes/Slider.xml
+++ b/doc/classes/Slider.xml
@@ -25,9 +25,9 @@
</members>
<signals>
<signal name="drag_ended">
- <argument index="0" name="value_changed" type="bool" />
+ <param index="0" name="value_changed" type="bool" />
<description>
- Emitted when dragging stops. If [code]value_changed[/code] is true, [member Range.value] is different from the value when you started the dragging.
+ Emitted when dragging stops. If [param value_changed] is true, [member Range.value] is different from the value when you started the dragging.
</description>
</signal>
<signal name="drag_started">
diff --git a/doc/classes/SliderJoint3D.xml b/doc/classes/SliderJoint3D.xml
index d62cf8aac4..a67c38b12d 100644
--- a/doc/classes/SliderJoint3D.xml
+++ b/doc/classes/SliderJoint3D.xml
@@ -11,14 +11,14 @@
<methods>
<method name="get_param" qualifiers="const">
<return type="float" />
- <argument index="0" name="param" type="int" enum="SliderJoint3D.Param" />
+ <param index="0" name="param" type="int" enum="SliderJoint3D.Param" />
<description>
</description>
</method>
<method name="set_param">
<return type="void" />
- <argument index="0" name="param" type="int" enum="SliderJoint3D.Param" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="param" type="int" enum="SliderJoint3D.Param" />
+ <param index="1" name="value" type="float" />
<description>
</description>
</method>
@@ -28,7 +28,7 @@
The amount of damping of the rotation when the limit is surpassed.
A lower damping value allows a rotation initiated by body A to travel to body B slower.
</member>
- <member name="angular_limit/lower_angle" type="float" setter="_set_lower_limit_angular" getter="_get_lower_limit_angular" default="0.0">
+ <member name="angular_limit/lower_angle" type="float" setter="set_param" getter="get_param" default="0.0">
The lower limit of rotation in the slider.
</member>
<member name="angular_limit/restitution" type="float" setter="set_param" getter="get_param" default="0.7">
@@ -39,7 +39,7 @@
A factor applied to the all rotation once the limit is surpassed.
Makes all rotation slower when between 0 and 1.
</member>
- <member name="angular_limit/upper_angle" type="float" setter="_set_upper_limit_angular" getter="_get_upper_limit_angular" default="0.0">
+ <member name="angular_limit/upper_angle" type="float" setter="set_param" getter="get_param" default="0.0">
The upper limit of rotation in the slider.
</member>
<member name="angular_motion/damping" type="float" setter="set_param" getter="get_param" default="1.0">
diff --git a/doc/classes/SoftDynamicBody3D.xml b/doc/classes/SoftBody3D.xml
index 86552f30f6..7006bca6f0 100644
--- a/doc/classes/SoftDynamicBody3D.xml
+++ b/doc/classes/SoftBody3D.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SoftDynamicBody3D" inherits="MeshInstance3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SoftBody3D" inherits="MeshInstance3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A soft mesh physics body.
</brief_description>
<description>
A deformable physics body. Used to create elastic or deformable objects such as cloth, rubber, or other flexible materials.
- [b]Note:[/b] There are many known bugs in [SoftDynamicBody3D]. Therefore, it's not recommended to use them for things that can affect gameplay (such as a player character made entirely out of soft bodies).
+ [b]Note:[/b] There are many known bugs in [SoftBody3D]. Therefore, it's not recommended to use them for things that can affect gameplay (such as a player character made entirely out of soft bodies).
</description>
<tutorials>
<link title="SoftBody">$DOCS_URL/tutorials/physics/soft_body.html</link>
@@ -13,29 +13,29 @@
<methods>
<method name="add_collision_exception_with">
<return type="void" />
- <argument index="0" name="body" type="Node" />
+ <param index="0" name="body" type="Node" />
<description>
Adds a body to the list of bodies that this body can't collide with.
</description>
</method>
<method name="get_collision_exceptions">
- <return type="Array" />
+ <return type="PhysicsBody3D[]" />
<description>
Returns an array of nodes that were added as collision exceptions for this body.
</description>
</method>
<method name="get_collision_layer_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
- Returns whether or not the specified layer of the [member collision_layer] is enabled, given a [code]layer_number[/code] between 1 and 32.
+ Returns whether or not the specified layer of the [member collision_layer] is enabled, given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
- Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
+ Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="get_physics_rid" qualifiers="const">
@@ -45,63 +45,63 @@
</method>
<method name="get_point_transform">
<return type="Vector3" />
- <argument index="0" name="point_index" type="int" />
+ <param index="0" name="point_index" type="int" />
<description>
Returns local translation of a vertex in the surface array.
</description>
</method>
<method name="is_point_pinned" qualifiers="const">
<return type="bool" />
- <argument index="0" name="point_index" type="int" />
+ <param index="0" name="point_index" type="int" />
<description>
Returns [code]true[/code] if vertex is set to pinned.
</description>
</method>
<method name="remove_collision_exception_with">
<return type="void" />
- <argument index="0" name="body" type="Node" />
+ <param index="0" name="body" type="Node" />
<description>
Removes a body from the list of bodies that this body can't collide with.
</description>
</method>
<method name="set_collision_layer_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
- Based on [code]value[/code], enables or disables the specified layer in the [member collision_layer], given a [code]layer_number[/code] between 1 and 32.
+ Based on [code]value[/code], enables or disables the specified layer in the [member collision_layer], given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="set_collision_mask_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
- Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
+ Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [param layer_number] between 1 and 32.
</description>
</method>
<method name="set_point_pinned">
<return type="void" />
- <argument index="0" name="point_index" type="int" />
- <argument index="1" name="pinned" type="bool" />
- <argument index="2" name="attachment_path" type="NodePath" default="NodePath(&quot;&quot;)" />
+ <param index="0" name="point_index" type="int" />
+ <param index="1" name="pinned" type="bool" />
+ <param index="2" name="attachment_path" type="NodePath" default="NodePath(&quot;&quot;)" />
<description>
- Sets the pinned state of a surface vertex. When set to [code]true[/code], the optional [code]attachment_path[/code] can define a [Node3D] the pinned vertex will be attached to.
+ Sets the pinned state of a surface vertex. When set to [code]true[/code], the optional [param attachment_path] can define a [Node3D] the pinned vertex will be attached to.
</description>
</method>
</methods>
<members>
<member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="1">
- The physics layers this SoftDynamicBody3D [b]is in[/b]. Collision objects can exist in one or more of 32 different layers. See also [member collision_mask].
+ The physics layers this SoftBody3D [b]is in[/b]. Collision objects can exist in one or more of 32 different layers. See also [member collision_mask].
[b]Note:[/b] Object A can detect a contact with object B only if object B is in any of the layers that object A scans. See [url=$DOCS_URL/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 SoftDynamicBody3D [b]scans[/b]. Collision objects can scan one or more of 32 different layers. See also [member collision_layer].
+ The physics layers this SoftBody3D [b]scans[/b]. Collision objects can scan one or more of 32 different layers. See also [member collision_layer].
[b]Note:[/b] Object A can detect a contact with object B only if object B is in any of the layers that object A scans. See [url=$DOCS_URL/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>
- <member name="disable_mode" type="int" setter="set_disable_mode" getter="get_disable_mode" enum="SoftDynamicBody3D.DisableMode" default="0">
+ <member name="disable_mode" type="int" setter="set_disable_mode" getter="get_disable_mode" enum="SoftBody3D.DisableMode" default="0">
Defines the behavior in physics when [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED]. See [enum DisableMode] for more details about the different modes.
</member>
<member name="drag_coefficient" type="float" setter="set_drag_coefficient" getter="get_drag_coefficient" default="0.0">
@@ -109,23 +109,23 @@
<member name="linear_stiffness" type="float" setter="set_linear_stiffness" getter="get_linear_stiffness" default="0.5">
</member>
<member name="parent_collision_ignore" type="NodePath" setter="set_parent_collision_ignore" getter="get_parent_collision_ignore" default="NodePath(&quot;&quot;)">
- [NodePath] to a [CollisionObject3D] this SoftDynamicBody3D should avoid clipping.
+ [NodePath] to a [CollisionObject3D] this SoftBody3D should avoid clipping.
</member>
<member name="pressure_coefficient" type="float" setter="set_pressure_coefficient" getter="get_pressure_coefficient" default="0.0">
</member>
<member name="ray_pickable" type="bool" setter="set_ray_pickable" getter="is_ray_pickable" default="true">
- If [code]true[/code], the [SoftDynamicBody3D] will respond to [RayCast3D]s.
+ If [code]true[/code], the [SoftBody3D] will respond to [RayCast3D]s.
</member>
<member name="simulation_precision" type="int" setter="set_simulation_precision" getter="get_simulation_precision" default="5">
Increasing this value will improve the resulting simulation, but can affect performance. Use with care.
</member>
<member name="total_mass" type="float" setter="set_total_mass" getter="get_total_mass" default="1.0">
- The SoftDynamicBody3D's mass.
+ The SoftBody3D's mass.
</member>
</members>
<constants>
<constant name="DISABLE_MODE_REMOVE" value="0" enum="DisableMode">
- When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], remove from the physics simulation to stop all physics interactions with this [SoftDynamicBody3D].
+ When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], remove from the physics simulation to stop all physics interactions with this [SoftBody3D].
Automatically re-added to the physics simulation when the [Node] is processed again.
</constant>
<constant name="DISABLE_MODE_KEEP_ACTIVE" value="1" enum="DisableMode">
diff --git a/doc/classes/SpinBox.xml b/doc/classes/SpinBox.xml
index e84f9c38ff..8df039794a 100644
--- a/doc/classes/SpinBox.xml
+++ b/doc/classes/SpinBox.xml
@@ -47,6 +47,9 @@
<members>
<member name="alignment" type="int" setter="set_horizontal_alignment" getter="get_horizontal_alignment" enum="HorizontalAlignment" default="0">
</member>
+ <member name="custom_arrow_step" type="float" setter="set_custom_arrow_step" getter="get_custom_arrow_step" default="0.0">
+ If not [code]0[/code], [code]value[/code] will always be rounded to a multiple of [code]custom_arrow_step[/code] when interacting with the arrow buttons of the [SpinBox].
+ </member>
<member name="editable" type="bool" setter="set_editable" getter="is_editable" default="true">
If [code]true[/code], the [SpinBox] will be editable. Otherwise, it will be read only.
</member>
diff --git a/doc/classes/SplitContainer.xml b/doc/classes/SplitContainer.xml
index f2bc65f8df..fb4b9466b5 100644
--- a/doc/classes/SplitContainer.xml
+++ b/doc/classes/SplitContainer.xml
@@ -30,7 +30,7 @@
</members>
<signals>
<signal name="dragged">
- <argument index="0" name="offset" type="int" />
+ <param index="0" name="offset" type="int" />
<description>
Emitted when the dragger is dragged by user.
</description>
diff --git a/doc/classes/SpringArm3D.xml b/doc/classes/SpringArm3D.xml
index d89b8f4549..29331e3071 100644
--- a/doc/classes/SpringArm3D.xml
+++ b/doc/classes/SpringArm3D.xml
@@ -14,7 +14,7 @@
<methods>
<method name="add_excluded_object">
<return type="void" />
- <argument index="0" name="RID" type="RID" />
+ <param index="0" name="RID" type="RID" />
<description>
Adds the [PhysicsBody3D] object with the given [RID] to the list of [PhysicsBody3D] objects excluded from the collision check.
</description>
@@ -33,7 +33,7 @@
</method>
<method name="remove_excluded_object">
<return type="bool" />
- <argument index="0" name="RID" type="RID" />
+ <param index="0" name="RID" type="RID" />
<description>
Removes the given [RID] from the list of [PhysicsBody3D] objects excluded from the collision check.
</description>
diff --git a/doc/classes/Sprite2D.xml b/doc/classes/Sprite2D.xml
index 2edc13a12b..83532721b2 100644
--- a/doc/classes/Sprite2D.xml
+++ b/doc/classes/Sprite2D.xml
@@ -41,7 +41,7 @@
</method>
<method name="is_pixel_opaque" qualifiers="const">
<return type="bool" />
- <argument index="0" name="pos" type="Vector2" />
+ <param index="0" name="pos" type="Vector2" />
<description>
Returns [code]true[/code], if the pixel at the given position is opaque and [code]false[/code] in other case.
[b]Note:[/b] It also returns [code]false[/code], if the sprite's texture is [code]null[/code] or if the given position is invalid.
diff --git a/doc/classes/Sprite3D.xml b/doc/classes/Sprite3D.xml
index 22437027c5..956e646702 100644
--- a/doc/classes/Sprite3D.xml
+++ b/doc/classes/Sprite3D.xml
@@ -24,7 +24,7 @@
The region of the atlas texture to display. [member region_enabled] must be [code]true[/code].
</member>
<member name="texture" type="Texture2D" setter="set_texture" getter="get_texture">
- [Texture2D] object to draw.
+ [Texture2D] object to draw. If [member GeometryInstance3D.material_override] is used, this will be overridden. The size information is still used.
</member>
<member name="vframes" type="int" setter="set_vframes" getter="get_vframes" default="1">
The number of rows in the sprite sheet.
diff --git a/doc/classes/SpriteBase3D.xml b/doc/classes/SpriteBase3D.xml
index bc381578d9..5fa984e7a0 100644
--- a/doc/classes/SpriteBase3D.xml
+++ b/doc/classes/SpriteBase3D.xml
@@ -17,7 +17,7 @@
</method>
<method name="get_draw_flag" qualifiers="const">
<return type="bool" />
- <argument index="0" name="flag" type="int" enum="SpriteBase3D.DrawFlags" />
+ <param index="0" name="flag" type="int" enum="SpriteBase3D.DrawFlags" />
<description>
Returns the value of the specified flag.
</description>
@@ -30,8 +30,8 @@
</method>
<method name="set_draw_flag">
<return type="void" />
- <argument index="0" name="flag" type="int" enum="SpriteBase3D.DrawFlags" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="flag" type="int" enum="SpriteBase3D.DrawFlags" />
+ <param index="1" name="enabled" type="bool" />
<description>
If [code]true[/code], the specified flag will be enabled. See [enum SpriteBase3D.DrawFlags] for a list of flags.
</description>
diff --git a/doc/classes/SpriteFrames.xml b/doc/classes/SpriteFrames.xml
index 0d423630d4..e9721495dd 100644
--- a/doc/classes/SpriteFrames.xml
+++ b/doc/classes/SpriteFrames.xml
@@ -12,23 +12,23 @@
<methods>
<method name="add_animation">
<return type="void" />
- <argument index="0" name="anim" type="StringName" />
+ <param index="0" name="anim" type="StringName" />
<description>
Adds a new animation to the library.
</description>
</method>
<method name="add_frame">
<return type="void" />
- <argument index="0" name="anim" type="StringName" />
- <argument index="1" name="frame" type="Texture2D" />
- <argument index="2" name="at_position" type="int" default="-1" />
+ <param index="0" name="anim" type="StringName" />
+ <param index="1" name="frame" type="Texture2D" />
+ <param index="2" name="at_position" type="int" default="-1" />
<description>
Adds a frame to the given animation.
</description>
</method>
<method name="clear">
<return type="void" />
- <argument index="0" name="anim" type="StringName" />
+ <param index="0" name="anim" type="StringName" />
<description>
Removes all frames from the given animation.
</description>
@@ -41,7 +41,7 @@
</method>
<method name="get_animation_loop" qualifiers="const">
<return type="bool" />
- <argument index="0" name="anim" type="StringName" />
+ <param index="0" name="anim" type="StringName" />
<description>
Returns [code]true[/code] if the given animation is configured to loop when it finishes playing. Otherwise, returns [code]false[/code].
</description>
@@ -54,77 +54,77 @@
</method>
<method name="get_animation_speed" qualifiers="const">
<return type="float" />
- <argument index="0" name="anim" type="StringName" />
+ <param index="0" name="anim" type="StringName" />
<description>
The animation's speed in frames per second.
</description>
</method>
<method name="get_frame" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="anim" type="StringName" />
- <argument index="1" name="idx" type="int" />
+ <param index="0" name="anim" type="StringName" />
+ <param index="1" name="idx" type="int" />
<description>
Returns the animation's selected frame.
</description>
</method>
<method name="get_frame_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="anim" type="StringName" />
+ <param index="0" name="anim" type="StringName" />
<description>
Returns the number of frames in the animation.
</description>
</method>
<method name="has_animation" qualifiers="const">
<return type="bool" />
- <argument index="0" name="anim" type="StringName" />
+ <param index="0" name="anim" type="StringName" />
<description>
If [code]true[/code], the named animation exists.
</description>
</method>
<method name="remove_animation">
<return type="void" />
- <argument index="0" name="anim" type="StringName" />
+ <param index="0" name="anim" type="StringName" />
<description>
Removes the given animation.
</description>
</method>
<method name="remove_frame">
<return type="void" />
- <argument index="0" name="anim" type="StringName" />
- <argument index="1" name="idx" type="int" />
+ <param index="0" name="anim" type="StringName" />
+ <param index="1" name="idx" type="int" />
<description>
Removes the animation's selected frame.
</description>
</method>
<method name="rename_animation">
<return type="void" />
- <argument index="0" name="anim" type="StringName" />
- <argument index="1" name="newname" type="StringName" />
+ <param index="0" name="anim" type="StringName" />
+ <param index="1" name="newname" type="StringName" />
<description>
- Changes the animation's name to [code]newname[/code].
+ Changes the animation's name to [param newname].
</description>
</method>
<method name="set_animation_loop">
<return type="void" />
- <argument index="0" name="anim" type="StringName" />
- <argument index="1" name="loop" type="bool" />
+ <param index="0" name="anim" type="StringName" />
+ <param index="1" name="loop" type="bool" />
<description>
If [code]true[/code], the animation will loop.
</description>
</method>
<method name="set_animation_speed">
<return type="void" />
- <argument index="0" name="anim" type="StringName" />
- <argument index="1" name="speed" type="float" />
+ <param index="0" name="anim" type="StringName" />
+ <param index="1" name="speed" type="float" />
<description>
The animation's speed in frames per second.
</description>
</method>
<method name="set_frame">
<return type="void" />
- <argument index="0" name="anim" type="StringName" />
- <argument index="1" name="idx" type="int" />
- <argument index="2" name="txt" type="Texture2D" />
+ <param index="0" name="anim" type="StringName" />
+ <param index="1" name="idx" type="int" />
+ <param index="2" name="txt" type="Texture2D" />
<description>
Sets the texture of the given frame.
</description>
diff --git a/doc/classes/StaticBody2D.xml b/doc/classes/StaticBody2D.xml
index e6e3559ae0..21c160b780 100644
--- a/doc/classes/StaticBody2D.xml
+++ b/doc/classes/StaticBody2D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Static body for 2D physics.
- A static body is a simple body that can't be moved by external forces or contacts. It is ideal for implementing objects in the environment, such as walls or platforms. In contrast to [RigidDynamicBody2D], it doesn't consume any CPU resources as long as they don't move.
+ A static body is a simple body that can't be moved by external forces or contacts. It is ideal for implementing objects in the environment, such as walls or platforms. In contrast to [RigidBody2D], it doesn't consume any CPU resources as long as they don't move.
They have extra functionalities to move and affect other bodies:
[b]Static transform change:[/b] Static bodies can be moved by animation or script. In this case, they are just teleported and don't affect other bodies on their path.
[b]Constant velocity:[/b] When [member constant_linear_velocity] or [member constant_angular_velocity] is set, static bodies don't move themselves but affect touching bodies as if they were moving. This is useful for simulating conveyor belts or conveyor wheels.
diff --git a/doc/classes/StaticBody3D.xml b/doc/classes/StaticBody3D.xml
index a29f5fc147..daa71d1168 100644
--- a/doc/classes/StaticBody3D.xml
+++ b/doc/classes/StaticBody3D.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
Static body for 3D physics.
- A static body is a simple body that can't be moved by external forces or contacts. It is ideal for implementing objects in the environment, such as walls or platforms. In contrast to [RigidDynamicBody3D], it doesn't consume any CPU resources as long as they don't move.
+ A static body is a simple body that can't be moved by external forces or contacts. It is ideal for implementing objects in the environment, such as walls or platforms. In contrast to [RigidBody3D], it doesn't consume any CPU resources as long as they don't move.
They have extra functionalities to move and affect other bodies:
[b]Static transform change:[/b] Static bodies can be moved by animation or script. In this case, they are just teleported and don't affect other bodies on their path.
[b]Constant velocity:[/b] When [member constant_linear_velocity] or [member constant_angular_velocity] is set, static bodies don't move themselves but affect touching bodies as if they were moving. This is useful for simulating conveyor belts or conveyor wheels.
diff --git a/doc/classes/StreamPeer.xml b/doc/classes/StreamPeer.xml
index bd69867001..4188563695 100644
--- a/doc/classes/StreamPeer.xml
+++ b/doc/classes/StreamPeer.xml
@@ -37,14 +37,14 @@
<method name="get_available_bytes" qualifiers="const">
<return type="int" />
<description>
- Returns the amount of bytes this [StreamPeer] has available.
+ Returns the number of bytes this [StreamPeer] has available.
</description>
</method>
<method name="get_data">
<return type="Array" />
- <argument index="0" name="bytes" type="int" />
+ <param index="0" name="bytes" type="int" />
<description>
- Returns a chunk data with the received bytes. The amount of bytes to be received can be requested in the [code]bytes[/code] argument. If not enough bytes are available, the function will block until the desired amount is received. This function returns two values, an [enum @GlobalScope.Error] code and a data array.
+ Returns a chunk data with the received bytes. The number of bytes to be received can be requested in the [param bytes] argument. If not enough bytes are available, the function will block until the desired amount is received. This function returns two values, an [enum @GlobalScope.Error] code and a data array.
</description>
</method>
<method name="get_double">
@@ -61,16 +61,16 @@
</method>
<method name="get_partial_data">
<return type="Array" />
- <argument index="0" name="bytes" type="int" />
+ <param index="0" name="bytes" type="int" />
<description>
- Returns a chunk data with the received bytes. The amount of bytes to be received can be requested in the "bytes" argument. If not enough bytes are available, the function will return how many were actually received. This function returns two values, an [enum @GlobalScope.Error] code, and a data array.
+ Returns a chunk data with the received bytes. The number of bytes to be received can be requested in the "bytes" argument. If not enough bytes are available, the function will return how many were actually received. This function returns two values, an [enum @GlobalScope.Error] code, and a data array.
</description>
</method>
<method name="get_string">
<return type="String" />
- <argument index="0" name="bytes" type="int" default="-1" />
+ <param index="0" name="bytes" type="int" default="-1" />
<description>
- Gets an ASCII string with byte-length [code]bytes[/code] from the stream. If [code]bytes[/code] is negative (default) the length will be read from the stream using the reverse process of [method put_string].
+ Gets an ASCII string with byte-length [param bytes] from the stream. If [param bytes] is negative (default) the length will be read from the stream using the reverse process of [method put_string].
</description>
</method>
<method name="get_u16">
@@ -99,78 +99,78 @@
</method>
<method name="get_utf8_string">
<return type="String" />
- <argument index="0" name="bytes" type="int" default="-1" />
+ <param index="0" name="bytes" type="int" default="-1" />
<description>
- Gets an UTF-8 string with byte-length [code]bytes[/code] from the stream (this decodes the string sent as UTF-8). If [code]bytes[/code] is negative (default) the length will be read from the stream using the reverse process of [method put_utf8_string].
+ Gets an UTF-8 string with byte-length [param bytes] from the stream (this decodes the string sent as UTF-8). If [param bytes] is negative (default) the length will be read from the stream using the reverse process of [method put_utf8_string].
</description>
</method>
<method name="get_var">
<return type="Variant" />
- <argument index="0" name="allow_objects" type="bool" default="false" />
+ <param index="0" name="allow_objects" type="bool" default="false" />
<description>
- Gets a Variant from the stream. If [code]allow_objects[/code] is [code]true[/code], decoding objects is allowed.
+ Gets a Variant from the stream. If [param allow_objects] is [code]true[/code], decoding objects is allowed.
[b]Warning:[/b] Deserialized objects can contain code which gets executed. Do not use this option if the serialized object comes from untrusted sources to avoid potential security threats such as remote code execution.
</description>
</method>
<method name="put_16">
<return type="void" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Puts a signed 16-bit value into the stream.
</description>
</method>
<method name="put_32">
<return type="void" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Puts a signed 32-bit value into the stream.
</description>
</method>
<method name="put_64">
<return type="void" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Puts a signed 64-bit value into the stream.
</description>
</method>
<method name="put_8">
<return type="void" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Puts a signed byte into the stream.
</description>
</method>
<method name="put_data">
<return type="int" enum="Error" />
- <argument index="0" name="data" type="PackedByteArray" />
+ <param index="0" name="data" type="PackedByteArray" />
<description>
Sends a chunk of data through the connection, blocking if necessary until the data is done sending. This function returns an [enum @GlobalScope.Error] code.
</description>
</method>
<method name="put_double">
<return type="void" />
- <argument index="0" name="value" type="float" />
+ <param index="0" name="value" type="float" />
<description>
Puts a double-precision float into the stream.
</description>
</method>
<method name="put_float">
<return type="void" />
- <argument index="0" name="value" type="float" />
+ <param index="0" name="value" type="float" />
<description>
Puts a single-precision float into the stream.
</description>
</method>
<method name="put_partial_data">
<return type="Array" />
- <argument index="0" name="data" type="PackedByteArray" />
+ <param index="0" name="data" type="PackedByteArray" />
<description>
Sends a chunk of data through the connection. If all the data could not be sent at once, only part of it will. This function returns two values, an [enum @GlobalScope.Error] code and an integer, describing how much data was actually sent.
</description>
</method>
<method name="put_string">
<return type="void" />
- <argument index="0" name="value" type="String" />
+ <param index="0" name="value" type="String" />
<description>
Puts a zero-terminated ASCII string into the stream prepended by a 32-bit unsigned integer representing its size.
[b]Note:[/b] To put an ASCII string without prepending its size, you can use [method put_data]:
@@ -186,35 +186,35 @@
</method>
<method name="put_u16">
<return type="void" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Puts an unsigned 16-bit value into the stream.
</description>
</method>
<method name="put_u32">
<return type="void" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Puts an unsigned 32-bit value into the stream.
</description>
</method>
<method name="put_u64">
<return type="void" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Puts an unsigned 64-bit value into the stream.
</description>
</method>
<method name="put_u8">
<return type="void" />
- <argument index="0" name="value" type="int" />
+ <param index="0" name="value" type="int" />
<description>
Puts an unsigned byte into the stream.
</description>
</method>
<method name="put_utf8_string">
<return type="void" />
- <argument index="0" name="value" type="String" />
+ <param index="0" name="value" type="String" />
<description>
Puts a zero-terminated UTF-8 string into the stream prepended by a 32 bits unsigned integer representing its size.
[b]Note:[/b] To put an UTF-8 string without prepending its size, you can use [method put_data]:
@@ -230,10 +230,10 @@
</method>
<method name="put_var">
<return type="void" />
- <argument index="0" name="value" type="Variant" />
- <argument index="1" name="full_objects" type="bool" default="false" />
+ <param index="0" name="value" type="Variant" />
+ <param index="1" name="full_objects" type="bool" default="false" />
<description>
- Puts a Variant into the stream. If [code]full_objects[/code] is [code]true[/code] encoding objects is allowed (and can potentially include code).
+ Puts a Variant into the stream. If [param full_objects] is [code]true[/code] encoding objects is allowed (and can potentially include code).
</description>
</method>
</methods>
diff --git a/doc/classes/StreamPeerBuffer.xml b/doc/classes/StreamPeerBuffer.xml
index de725aef5b..4bef9f44b7 100644
--- a/doc/classes/StreamPeerBuffer.xml
+++ b/doc/classes/StreamPeerBuffer.xml
@@ -36,16 +36,16 @@
</method>
<method name="resize">
<return type="void" />
- <argument index="0" name="size" type="int" />
+ <param index="0" name="size" type="int" />
<description>
Resizes the [member data_array]. This [i]doesn't[/i] update the cursor.
</description>
</method>
<method name="seek">
<return type="void" />
- <argument index="0" name="position" type="int" />
+ <param index="0" name="position" type="int" />
<description>
- Moves the cursor to the specified position. [code]position[/code] must be a valid index of [member data_array].
+ Moves the cursor to the specified position. [param position] must be a valid index of [member data_array].
</description>
</method>
</methods>
diff --git a/doc/classes/StreamPeerExtension.xml b/doc/classes/StreamPeerExtension.xml
index a3a08c530c..46783de275 100644
--- a/doc/classes/StreamPeerExtension.xml
+++ b/doc/classes/StreamPeerExtension.xml
@@ -14,33 +14,33 @@
</method>
<method name="_get_data" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="r_buffer" type="uint8_t*" />
- <argument index="1" name="r_bytes" type="int" />
- <argument index="2" name="r_received" type="int32_t*" />
+ <param index="0" name="r_buffer" type="uint8_t*" />
+ <param index="1" name="r_bytes" type="int" />
+ <param index="2" name="r_received" type="int32_t*" />
<description>
</description>
</method>
<method name="_get_partial_data" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="r_buffer" type="uint8_t*" />
- <argument index="1" name="r_bytes" type="int" />
- <argument index="2" name="r_received" type="int32_t*" />
+ <param index="0" name="r_buffer" type="uint8_t*" />
+ <param index="1" name="r_bytes" type="int" />
+ <param index="2" name="r_received" type="int32_t*" />
<description>
</description>
</method>
<method name="_put_data" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="p_data" type="const uint8_t*" />
- <argument index="1" name="p_bytes" type="int" />
- <argument index="2" name="r_sent" type="int32_t*" />
+ <param index="0" name="p_data" type="const uint8_t*" />
+ <param index="1" name="p_bytes" type="int" />
+ <param index="2" name="r_sent" type="int32_t*" />
<description>
</description>
</method>
<method name="_put_partial_data" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="p_data" type="const uint8_t*" />
- <argument index="1" name="p_bytes" type="int" />
- <argument index="2" name="r_sent" type="int32_t*" />
+ <param index="0" name="p_data" type="const uint8_t*" />
+ <param index="1" name="p_bytes" type="int" />
+ <param index="2" name="r_sent" type="int32_t*" />
<description>
</description>
</method>
diff --git a/doc/classes/StreamPeerSSL.xml b/doc/classes/StreamPeerSSL.xml
index 70762cbf6c..9d21b91416 100644
--- a/doc/classes/StreamPeerSSL.xml
+++ b/doc/classes/StreamPeerSSL.xml
@@ -13,23 +13,23 @@
<methods>
<method name="accept_stream">
<return type="int" enum="Error" />
- <argument index="0" name="stream" type="StreamPeer" />
- <argument index="1" name="private_key" type="CryptoKey" />
- <argument index="2" name="certificate" type="X509Certificate" />
- <argument index="3" name="chain" type="X509Certificate" default="null" />
+ <param index="0" name="stream" type="StreamPeer" />
+ <param index="1" name="private_key" type="CryptoKey" />
+ <param index="2" name="certificate" type="X509Certificate" />
+ <param index="3" name="chain" type="X509Certificate" default="null" />
<description>
- Accepts a peer connection as a server using the given [code]private_key[/code] and providing the given [code]certificate[/code] to the client. You can pass the optional [code]chain[/code] parameter to provide additional CA chain information along with the certificate.
+ Accepts a peer connection as a server using the given [param private_key] and providing the given [param certificate] to the client. You can pass the optional [param chain] parameter to provide additional CA chain information along with the certificate.
</description>
</method>
<method name="connect_to_stream">
<return type="int" enum="Error" />
- <argument index="0" name="stream" type="StreamPeer" />
- <argument index="1" name="validate_certs" type="bool" default="false" />
- <argument index="2" name="for_hostname" type="String" default="&quot;&quot;" />
- <argument index="3" name="valid_certificate" type="X509Certificate" default="null" />
+ <param index="0" name="stream" type="StreamPeer" />
+ <param index="1" name="validate_certs" type="bool" default="false" />
+ <param index="2" name="for_hostname" type="String" default="&quot;&quot;" />
+ <param index="3" name="valid_certificate" type="X509Certificate" default="null" />
<description>
- Connects to a peer using an underlying [StreamPeer] [code]stream[/code]. If [code]validate_certs[/code] is [code]true[/code], [StreamPeerSSL] will validate that the certificate presented by the peer matches the [code]for_hostname[/code].
- [b]Note:[/b] Specifying a custom [code]valid_certificate[/code] is not supported in HTML5 exports due to browsers restrictions.
+ Connects to a peer using an underlying [StreamPeer] [param stream]. If [param validate_certs] is [code]true[/code], [StreamPeerSSL] will validate that the certificate presented by the peer matches the [param for_hostname].
+ [b]Note:[/b] Specifying a custom [param valid_certificate] is not supported in Web exports due to browsers restrictions.
</description>
</method>
<method name="disconnect_from_stream">
diff --git a/doc/classes/StreamPeerTCP.xml b/doc/classes/StreamPeerTCP.xml
index f06cf5c7a2..c08fb82797 100644
--- a/doc/classes/StreamPeerTCP.xml
+++ b/doc/classes/StreamPeerTCP.xml
@@ -12,17 +12,17 @@
<methods>
<method name="bind">
<return type="int" enum="Error" />
- <argument index="0" name="port" type="int" />
- <argument index="1" name="host" type="String" default="&quot;*&quot;" />
+ <param index="0" name="port" type="int" />
+ <param index="1" name="host" type="String" default="&quot;*&quot;" />
<description>
Opens the TCP socket, and binds it to the specified local address.
- This method is generally not needed, and only used to force the subsequent call to [method connect_to_host] to use the specified [code]host[/code] and [code]port[/code] as source address. This can be desired in some NAT punchthrough techniques, or when forcing the source network interface.
+ This method is generally not needed, and only used to force the subsequent call to [method connect_to_host] to use the specified [param host] and [param port] as source address. This can be desired in some NAT punchthrough techniques, or when forcing the source network interface.
</description>
</method>
<method name="connect_to_host">
<return type="int" enum="Error" />
- <argument index="0" name="host" type="String" />
- <argument index="1" name="port" type="int" />
+ <param index="0" name="host" type="String" />
+ <param index="1" name="port" type="int" />
<description>
Connects to the specified [code]host:port[/code] pair. A hostname will be resolved if valid. Returns [constant OK] on success.
</description>
@@ -65,9 +65,9 @@
</method>
<method name="set_no_delay">
<return type="void" />
- <argument index="0" name="enabled" type="bool" />
+ <param index="0" name="enabled" type="bool" />
<description>
- If [code]enabled[/code] is [code]true[/code], packets will be sent immediately. If [code]enabled[/code] is [code]false[/code] (the default), packet transfers will be delayed and combined using [url=https://en.wikipedia.org/wiki/Nagle%27s_algorithm]Nagle's algorithm[/url].
+ If [param enabled] is [code]true[/code], packets will be sent immediately. If [param enabled] is [code]false[/code] (the default), packet transfers will be delayed and combined using [url=https://en.wikipedia.org/wiki/Nagle%27s_algorithm]Nagle's algorithm[/url].
[b]Note:[/b] It's recommended to leave this disabled for applications that send large packets or need to transfer a lot of data, as enabling this can decrease the total available bandwidth.
</description>
</method>
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index 9f197dae02..c111528c06 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -18,21 +18,21 @@
</constructor>
<constructor name="String">
<return type="String" />
- <argument index="0" name="from" type="String" />
+ <param index="0" name="from" type="String" />
<description>
Constructs a [String] as a copy of the given [String].
</description>
</constructor>
<constructor name="String">
<return type="String" />
- <argument index="0" name="from" type="NodePath" />
+ <param index="0" name="from" type="NodePath" />
<description>
Constructs a new String from the given [NodePath].
</description>
</constructor>
<constructor name="String">
<return type="String" />
- <argument index="0" name="from" type="StringName" />
+ <param index="0" name="from" type="StringName" />
<description>
Constructs a new String from the given [StringName].
</description>
@@ -41,7 +41,7 @@
<methods>
<method name="begins_with" qualifiers="const">
<return type="bool" />
- <argument index="0" name="text" type="String" />
+ <param index="0" name="text" type="String" />
<description>
Returns [code]true[/code] if the string begins with the given string.
</description>
@@ -92,17 +92,17 @@
</method>
<method name="casecmp_to" qualifiers="const">
<return type="int" />
- <argument index="0" name="to" type="String" />
+ <param index="0" name="to" type="String" />
<description>
Performs a case-sensitive comparison to another string. Returns [code]-1[/code] if less than, [code]1[/code] if greater than, or [code]0[/code] if equal. "less than" or "greater than" are determined by the [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode code points[/url] of each string, which roughly matches the alphabetical order.
- [b]Behavior with different string lengths:[/b] Returns [code]1[/code] if the "base" string is longer than the [code]to[/code] string or [code]-1[/code] if the "base" string is shorter than the [code]to[/code] string. Keep in mind this length is determined by the number of Unicode codepoints, [i]not[/i] the actual visible characters.
- [b]Behavior with empty strings:[/b] Returns [code]-1[/code] if the "base" string is empty, [code]1[/code] if the [code]to[/code] string is empty or [code]0[/code] if both strings are empty.
+ [b]Behavior with different string lengths:[/b] Returns [code]1[/code] if the "base" string is longer than the [param to] string or [code]-1[/code] if the "base" string is shorter than the [param to] string. Keep in mind this length is determined by the number of Unicode codepoints, [i]not[/i] the actual visible characters.
+ [b]Behavior with empty strings:[/b] Returns [code]-1[/code] if the "base" string is empty, [code]1[/code] if the [param to] string is empty or [code]0[/code] if both strings are empty.
To get a boolean result from a string comparison, use the [code]==[/code] operator instead. See also [method nocasecmp_to] and [method naturalnocasecmp_to].
</description>
</method>
<method name="chr" qualifiers="static">
<return type="String" />
- <argument index="0" name="char" type="int" />
+ <param index="0" name="char" type="int" />
<description>
Directly converts an decimal integer to a unicode character. Tables of these characters can be found in various locations, for example [url=https://unicodelookup.com/]here.[/url]
[codeblock]
@@ -113,27 +113,27 @@
</method>
<method name="contains" qualifiers="const">
<return type="bool" />
- <argument index="0" name="what" type="String" />
+ <param index="0" name="what" type="String" />
<description>
Returns [code]true[/code] if the string contains the given string.
</description>
</method>
<method name="count" qualifiers="const">
<return type="int" />
- <argument index="0" name="what" type="String" />
- <argument index="1" name="from" type="int" default="0" />
- <argument index="2" name="to" type="int" default="0" />
+ <param index="0" name="what" type="String" />
+ <param index="1" name="from" type="int" default="0" />
+ <param index="2" name="to" type="int" default="0" />
<description>
- Returns the number of occurrences of substring [code]what[/code] between [code]from[/code] and [code]to[/code] positions. If [code]from[/code] and [code]to[/code] equals 0 the whole string will be used. If only [code]to[/code] equals 0 the remained substring will be used.
+ Returns the number of occurrences of substring [param what] between [param from] and [param to] positions. If [param from] and [param to] equals 0 the whole string will be used. If only [param to] equals 0 the remained substring will be used.
</description>
</method>
<method name="countn" qualifiers="const">
<return type="int" />
- <argument index="0" name="what" type="String" />
- <argument index="1" name="from" type="int" default="0" />
- <argument index="2" name="to" type="int" default="0" />
+ <param index="0" name="what" type="String" />
+ <param index="1" name="from" type="int" default="0" />
+ <param index="2" name="to" type="int" default="0" />
<description>
- Returns the number of occurrences of substring [code]what[/code] (ignoring case) between [code]from[/code] and [code]to[/code] positions. If [code]from[/code] and [code]to[/code] equals 0 the whole string will be used. If only [code]to[/code] equals 0 the remained substring will be used.
+ Returns the number of occurrences of substring [param what] (ignoring case) between [param from] and [param to] positions. If [param from] and [param to] equals 0 the whole string will be used. If only [param to] equals 0 the remained substring will be used.
</description>
</method>
<method name="dedent" qualifiers="const">
@@ -144,15 +144,15 @@
</method>
<method name="ends_with" qualifiers="const">
<return type="bool" />
- <argument index="0" name="text" type="String" />
+ <param index="0" name="text" type="String" />
<description>
Returns [code]true[/code] if the string ends with the given string.
</description>
</method>
<method name="find" qualifiers="const">
<return type="int" />
- <argument index="0" name="what" type="String" />
- <argument index="1" name="from" type="int" default="0" />
+ <param index="0" name="what" type="String" />
+ <param index="1" name="from" type="int" default="0" />
<description>
Returns the index of the [b]first[/b] case-sensitive occurrence of the specified string in this instance, or [code]-1[/code]. Optionally, the starting search index can be specified, continuing to the end of the string.
[b]Note:[/b] If you just want to know whether a string contains a substring, use the [code]in[/code] operator as follows:
@@ -169,19 +169,19 @@
</method>
<method name="findn" qualifiers="const">
<return type="int" />
- <argument index="0" name="what" type="String" />
- <argument index="1" name="from" type="int" default="0" />
+ <param index="0" name="what" type="String" />
+ <param index="1" name="from" type="int" default="0" />
<description>
Returns the index of the [b]first[/b] case-insensitive occurrence of the specified string in this instance, or [code]-1[/code]. Optionally, the starting search index can be specified, continuing to the end of the string.
</description>
</method>
<method name="format" qualifiers="const">
<return type="String" />
- <argument index="0" name="values" type="Variant" />
- <argument index="1" name="placeholder" type="String" default="&quot;{_}&quot;" />
+ <param index="0" name="values" type="Variant" />
+ <param index="1" name="placeholder" type="String" default="&quot;{_}&quot;" />
<description>
- Formats the string by replacing all occurrences of [code]placeholder[/code] with the elements of [code]values[/code].
- [code]values[/code] can be a [Dictionary] or an [Array]. Any underscores in [code]placeholder[/code] will be replaced with the corresponding keys in advance. Array elements use their index as keys.
+ Formats the string by replacing all occurrences of [param placeholder] with the elements of [param values].
+ [param values] can be a [Dictionary] or an [Array]. Any underscores in [param placeholder] will be replaced with the corresponding keys in advance. Array elements use their index as keys.
[codeblock]
# Prints: Waiting for Godot is a play by Samuel Beckett, and Godot Engine is named after it.
var use_array_values = "Waiting for {0} is a play by {1}, and {0} Engine is named after it."
@@ -190,7 +190,7 @@
# Prints: User 42 is Godot.
print("User {id} is {name}.".format({"id": 42, "name": "Godot"}))
[/codeblock]
- Some additional handling is performed when [code]values[/code] is an array. If [code]placeholder[/code] does not contain an underscore, the elements of the array will be used to replace one occurrence of the placeholder in turn; If an array element is another 2-element array, it'll be interpreted as a key-value pair.
+ Some additional handling is performed when [param values] is an array. If [param placeholder] does not contain an underscore, the elements of the array will be used to replace one occurrence of the placeholder in turn; If an array element is another 2-element array, it'll be interpreted as a key-value pair.
[codeblock]
# Prints: User 42 is Godot.
print("User {} is {}.".format([42, "Godot"], "{}"))
@@ -234,10 +234,10 @@
</method>
<method name="get_slice" qualifiers="const">
<return type="String" />
- <argument index="0" name="delimiter" type="String" />
- <argument index="1" name="slice" type="int" />
+ <param index="0" name="delimiter" type="String" />
+ <param index="1" name="slice" type="int" />
<description>
- Splits a string using a [code]delimiter[/code] and returns a substring at index [code]slice[/code]. Returns an empty string if the index doesn't exist.
+ Splits a string using a [param delimiter] and returns a substring at index [param slice]. Returns an empty string if the index doesn't exist.
This is a more performant alternative to [method split] for cases when you need only one element from the array at a fixed index.
Example:
[codeblock]
@@ -247,17 +247,17 @@
</method>
<method name="get_slice_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="delimiter" type="String" />
+ <param index="0" name="delimiter" type="String" />
<description>
- Splits a string using a [code]delimiter[/code] and returns a number of slices.
+ Splits a string using a [param delimiter] and returns a number of slices.
</description>
</method>
<method name="get_slicec" qualifiers="const">
<return type="String" />
- <argument index="0" name="delimiter" type="int" />
- <argument index="1" name="slice" type="int" />
+ <param index="0" name="delimiter" type="int" />
+ <param index="1" name="slice" type="int" />
<description>
- Splits a string using a Unicode character with code [code]delimiter[/code] and returns a substring at index [code]slice[/code]. Returns an empty string if the index doesn't exist.
+ Splits a string using a Unicode character with code [param delimiter] and returns a substring at index [param slice]. Returns an empty string if the index doesn't exist.
This is a more performant alternative to [method split] for cases when you need only one element from the array at a fixed index.
</description>
</method>
@@ -286,7 +286,7 @@
</method>
<method name="humanize_size" qualifiers="static">
<return type="String" />
- <argument index="0" name="size" type="int" />
+ <param index="0" name="size" type="int" />
<description>
Converts an integer representing a number of bytes into a human-readable form.
Note that this output is in [url=https://en.wikipedia.org/wiki/Binary_prefix#IEC_prefixes]IEC prefix format[/url], and includes [code]B[/code], [code]KiB[/code], [code]MiB[/code], [code]GiB[/code], [code]TiB[/code], [code]PiB[/code], and [code]EiB[/code].
@@ -294,19 +294,19 @@
</method>
<method name="indent" qualifiers="const">
<return type="String" />
- <argument index="0" name="prefix" type="String" />
+ <param index="0" name="prefix" type="String" />
<description>
- Returns a copy of the string with lines indented with [code]prefix[/code].
+ Returns a copy of the string with lines indented with [param prefix].
For example, the string can be indented with two tabs using [code]"\t\t"[/code], or four spaces using [code]" "[/code]. The prefix can be any string so it can also be used to comment out strings with e.g. [code]"# "[/code]. See also [method dedent] to remove indentation.
[b]Note:[/b] Empty lines are kept empty.
</description>
</method>
<method name="insert" qualifiers="const">
<return type="String" />
- <argument index="0" name="position" type="int" />
- <argument index="1" name="what" type="String" />
+ <param index="0" name="position" type="int" />
+ <param index="1" name="what" type="String" />
<description>
- Returns a copy of the string with the substring [code]what[/code] inserted at the given position.
+ Returns a copy of the string with the substring [param what] inserted at the given [param position].
</description>
</method>
<method name="is_absolute_path" qualifiers="const">
@@ -329,14 +329,14 @@
</method>
<method name="is_subsequence_of" qualifiers="const">
<return type="bool" />
- <argument index="0" name="text" type="String" />
+ <param index="0" name="text" type="String" />
<description>
Returns [code]true[/code] if this string is a subsequence of the given string.
</description>
</method>
<method name="is_subsequence_ofn" qualifiers="const">
<return type="bool" />
- <argument index="0" name="text" type="String" />
+ <param index="0" name="text" type="String" />
<description>
Returns [code]true[/code] if this string is a subsequence of the given string, without considering case.
</description>
@@ -362,9 +362,9 @@
</method>
<method name="is_valid_hex_number" qualifiers="const">
<return type="bool" />
- <argument index="0" name="with_prefix" type="bool" default="false" />
+ <param index="0" name="with_prefix" type="bool" default="false" />
<description>
- Returns [code]true[/code] if this string contains a valid hexadecimal number. If [code]with_prefix[/code] is [code]true[/code], then a validity of the hexadecimal number is determined by [code]0x[/code] prefix, for instance: [code]0xDEADC0DE[/code].
+ Returns [code]true[/code] if this string contains a valid hexadecimal number. If [param with_prefix] is [code]true[/code], then a validity of the hexadecimal number is determined by [code]0x[/code] prefix, for instance: [code]0xDEADC0DE[/code].
</description>
</method>
<method name="is_valid_html_color" qualifiers="const">
@@ -405,9 +405,9 @@
</method>
<method name="join" qualifiers="const">
<return type="String" />
- <argument index="0" name="parts" type="PackedStringArray" />
+ <param index="0" name="parts" type="PackedStringArray" />
<description>
- Returns a [String] which is the concatenation of the [code]parts[/code]. The separator between elements is the string providing this method.
+ Returns a [String] which is the concatenation of the [param parts]. The separator between elements is the string providing this method.
Example:
[codeblocks]
[gdscript]
@@ -427,9 +427,9 @@
</method>
<method name="left" qualifiers="const">
<return type="String" />
- <argument index="0" name="length" type="int" />
+ <param index="0" name="length" type="int" />
<description>
- Returns a number of characters from the left of the string. If negative [code]length[/code] is used, the characters are counted downwards from [String]'s length.
+ Returns a number of characters from the left of the string. If negative [param length] is used, the characters are counted downwards from [String]'s length.
Examples:
[codeblock]
print("sample text".left(3)) #prints "sam"
@@ -440,35 +440,35 @@
<method name="length" qualifiers="const">
<return type="int" />
<description>
- Returns the string's amount of characters.
+ Returns the number of characters in the string.
</description>
</method>
<method name="lpad" qualifiers="const">
<return type="String" />
- <argument index="0" name="min_length" type="int" />
- <argument index="1" name="character" type="String" default="&quot; &quot;" />
+ <param index="0" name="min_length" type="int" />
+ <param index="1" name="character" type="String" default="&quot; &quot;" />
<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.
+ Formats a string to be at least [param min_length] long by adding [param character]s to the left of the string.
</description>
</method>
<method name="lstrip" qualifiers="const">
<return type="String" />
- <argument index="0" name="chars" type="String" />
+ <param index="0" name="chars" type="String" />
<description>
- Returns a copy of the string with characters removed from the left. The [code]chars[/code] argument is a string specifying the set of characters to be removed.
- [b]Note:[/b] The [code]chars[/code] is not a prefix. See [method trim_prefix] method that will remove a single prefix string rather than a set of characters.
+ Returns a copy of the string with characters removed from the left. The [param chars] argument is a string specifying the set of characters to be removed.
+ [b]Note:[/b] The [param chars] is not a prefix. See [method trim_prefix] method that will remove a single prefix string rather than a set of characters.
</description>
</method>
<method name="match" qualifiers="const">
<return type="bool" />
- <argument index="0" name="expr" type="String" />
+ <param index="0" name="expr" type="String" />
<description>
Does a simple case-sensitive expression match, where [code]"*"[/code] matches zero or more arbitrary characters and [code]"?"[/code] matches any single character except a period ([code]"."[/code]). An empty string or empty expression always evaluates to [code]false[/code].
</description>
</method>
<method name="matchn" qualifiers="const">
<return type="bool" />
- <argument index="0" name="expr" type="String" />
+ <param index="0" name="expr" type="String" />
<description>
Does a simple case-insensitive expression match, where [code]"*"[/code] matches zero or more arbitrary characters and [code]"?"[/code] matches any single character except a period ([code]"."[/code]). An empty string or empty expression always evaluates to [code]false[/code].
</description>
@@ -487,32 +487,32 @@
</method>
<method name="naturalnocasecmp_to" qualifiers="const">
<return type="int" />
- <argument index="0" name="to" type="String" />
+ <param index="0" name="to" type="String" />
<description>
Performs a case-insensitive [i]natural order[/i] comparison to another string. Returns [code]-1[/code] if less than, [code]1[/code] if greater than, or [code]0[/code] if equal. "less than" or "greater than" are determined by the [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode code points[/url] of each string, which roughly matches the alphabetical order. Internally, lowercase characters will be converted to uppercase during the comparison.
When used for sorting, natural order comparison will order suites of numbers as expected by most people. If you sort the numbers from 1 to 10 using natural order, you will get [code][1, 2, 3, ...][/code] instead of [code][1, 10, 2, 3, ...][/code].
- [b]Behavior with different string lengths:[/b] Returns [code]1[/code] if the "base" string is longer than the [code]to[/code] string or [code]-1[/code] if the "base" string is shorter than the [code]to[/code] string. Keep in mind this length is determined by the number of Unicode codepoints, [i]not[/i] the actual visible characters.
- [b]Behavior with empty strings:[/b] Returns [code]-1[/code] if the "base" string is empty, [code]1[/code] if the [code]to[/code] string is empty or [code]0[/code] if both strings are empty.
+ [b]Behavior with different string lengths:[/b] Returns [code]1[/code] if the "base" string is longer than the [param to] string or [code]-1[/code] if the "base" string is shorter than the [param to] string. Keep in mind this length is determined by the number of Unicode codepoints, [i]not[/i] the actual visible characters.
+ [b]Behavior with empty strings:[/b] Returns [code]-1[/code] if the "base" string is empty, [code]1[/code] if the [param to] string is empty or [code]0[/code] if both strings are empty.
To get a boolean result from a string comparison, use the [code]==[/code] operator instead. See also [method nocasecmp_to] and [method casecmp_to].
</description>
</method>
<method name="nocasecmp_to" qualifiers="const">
<return type="int" />
- <argument index="0" name="to" type="String" />
+ <param index="0" name="to" type="String" />
<description>
Performs a case-insensitive comparison to another string. Returns [code]-1[/code] if less than, [code]1[/code] if greater than, or [code]0[/code] if equal. "less than" or "greater than" are determined by the [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode code points[/url] of each string, which roughly matches the alphabetical order. Internally, lowercase characters will be converted to uppercase during the comparison.
- [b]Behavior with different string lengths:[/b] Returns [code]1[/code] if the "base" string is longer than the [code]to[/code] string or [code]-1[/code] if the "base" string is shorter than the [code]to[/code] string. Keep in mind this length is determined by the number of Unicode codepoints, [i]not[/i] the actual visible characters.
- [b]Behavior with empty strings:[/b] Returns [code]-1[/code] if the "base" string is empty, [code]1[/code] if the [code]to[/code] string is empty or [code]0[/code] if both strings are empty.
+ [b]Behavior with different string lengths:[/b] Returns [code]1[/code] if the "base" string is longer than the [param to] string or [code]-1[/code] if the "base" string is shorter than the [param to] string. Keep in mind this length is determined by the number of Unicode codepoints, [i]not[/i] the actual visible characters.
+ [b]Behavior with empty strings:[/b] Returns [code]-1[/code] if the "base" string is empty, [code]1[/code] if the [param to] string is empty or [code]0[/code] if both strings are empty.
To get a boolean result from a string comparison, use the [code]==[/code] operator instead. See also [method casecmp_to] and [method naturalnocasecmp_to].
</description>
</method>
<method name="num" qualifiers="static">
<return type="String" />
- <argument index="0" name="number" type="float" />
- <argument index="1" name="decimals" type="int" default="-1" />
+ <param index="0" name="number" type="float" />
+ <param index="1" name="decimals" type="int" default="-1" />
<description>
Converts a [float] to a string representation of a decimal number.
- The number of decimal places can be specified with [code]decimals[/code]. If [code]decimals[/code] is [code]-1[/code] (default), decimal places will be automatically adjusted so that the string representation has 14 significant digits (counting both digits to the left and the right of the decimal point).
+ The number of decimal places can be specified with [param decimals]. If [param decimals] is [code]-1[/code] (default), decimal places will be automatically adjusted so that the string representation has 14 significant digits (counting both digits to the left and the right of the decimal point).
Trailing zeros are not included in the string. The last digit will be rounded and not truncated.
Some examples:
[codeblock]
@@ -522,7 +522,7 @@
# Last digit will be rounded up here, which reduces total digit count since
# trailing zeros are removed:
String.num(42.129999, 5) # "42.13"
- # If `decimals` is not specified, the total amount of significant digits is 14:
+ # If `decimals` is not specified, the total number of significant digits is 14:
String.num(-0.0000012345432123454321) # "-0.00000123454321"
String.num(-10000.0000012345432123454321) # "-10000.0000012345"
[/codeblock]
@@ -530,93 +530,93 @@
</method>
<method name="num_int64" qualifiers="static">
<return type="String" />
- <argument index="0" name="number" type="int" />
- <argument index="1" name="base" type="int" default="10" />
- <argument index="2" name="capitalize_hex" type="bool" default="false" />
+ <param index="0" name="number" type="int" />
+ <param index="1" name="base" type="int" default="10" />
+ <param index="2" name="capitalize_hex" type="bool" default="false" />
<description>
Converts a signed [int] to a string representation of a number.
</description>
</method>
<method name="num_scientific" qualifiers="static">
<return type="String" />
- <argument index="0" name="number" type="float" />
+ <param index="0" name="number" type="float" />
<description>
</description>
</method>
<method name="num_uint64" qualifiers="static">
<return type="String" />
- <argument index="0" name="number" type="int" />
- <argument index="1" name="base" type="int" default="10" />
- <argument index="2" name="capitalize_hex" type="bool" default="false" />
+ <param index="0" name="number" type="int" />
+ <param index="1" name="base" type="int" default="10" />
+ <param index="2" name="capitalize_hex" type="bool" default="false" />
<description>
Converts a unsigned [int] to a string representation of a number.
</description>
</method>
<method name="pad_decimals" qualifiers="const">
<return type="String" />
- <argument index="0" name="digits" type="int" />
+ <param index="0" name="digits" type="int" />
<description>
- Formats a number to have an exact number of [code]digits[/code] after the decimal point.
+ Formats a number to have an exact number of [param digits] after the decimal point.
</description>
</method>
<method name="pad_zeros" qualifiers="const">
<return type="String" />
- <argument index="0" name="digits" type="int" />
+ <param index="0" name="digits" type="int" />
<description>
- Formats a number to have an exact number of [code]digits[/code] before the decimal point.
+ Formats a number to have an exact number of [param digits] before the decimal point.
</description>
</method>
- <method name="plus_file" qualifiers="const">
+ <method name="path_join" qualifiers="const">
<return type="String" />
- <argument index="0" name="file" type="String" />
+ <param index="0" name="file" type="String" />
<description>
- If the string is a path, this concatenates [code]file[/code] at the end of the string as a subpath. E.g. [code]"this/is".plus_file("path") == "this/is/path"[/code].
+ If the string is a path, this concatenates [param file] at the end of the string as a subpath. E.g. [code]"this/is".path_join("path") == "this/is/path"[/code].
</description>
</method>
<method name="repeat" qualifiers="const">
<return type="String" />
- <argument index="0" name="count" type="int" />
+ <param index="0" name="count" type="int" />
<description>
Returns original string repeated a number of times. The number of repetitions is given by the argument.
</description>
</method>
<method name="replace" qualifiers="const">
<return type="String" />
- <argument index="0" name="what" type="String" />
- <argument index="1" name="forwhat" type="String" />
+ <param index="0" name="what" type="String" />
+ <param index="1" name="forwhat" type="String" />
<description>
Replaces occurrences of a case-sensitive substring with the given one inside the string.
</description>
</method>
<method name="replacen" qualifiers="const">
<return type="String" />
- <argument index="0" name="what" type="String" />
- <argument index="1" name="forwhat" type="String" />
+ <param index="0" name="what" type="String" />
+ <param index="1" name="forwhat" type="String" />
<description>
Replaces occurrences of a case-insensitive substring with the given one inside the string.
</description>
</method>
<method name="rfind" qualifiers="const">
<return type="int" />
- <argument index="0" name="what" type="String" />
- <argument index="1" name="from" type="int" default="-1" />
+ <param index="0" name="what" type="String" />
+ <param index="1" name="from" type="int" default="-1" />
<description>
Returns the index of the [b]last[/b] case-sensitive occurrence of the specified string in this instance, or [code]-1[/code]. Optionally, the starting search index can be specified, continuing to the beginning of the string.
</description>
</method>
<method name="rfindn" qualifiers="const">
<return type="int" />
- <argument index="0" name="what" type="String" />
- <argument index="1" name="from" type="int" default="-1" />
+ <param index="0" name="what" type="String" />
+ <param index="1" name="from" type="int" default="-1" />
<description>
Returns the index of the [b]last[/b] case-insensitive occurrence of the specified string in this instance, or [code]-1[/code]. Optionally, the starting search index can be specified, continuing to the beginning of the string.
</description>
</method>
<method name="right" qualifiers="const">
<return type="String" />
- <argument index="0" name="length" type="int" />
+ <param index="0" name="length" type="int" />
<description>
- Returns a number of characters from the right of the string. If negative [code]length[/code] is used, the characters are counted downwards from [String]'s length.
+ Returns a number of characters from the right of the string. If negative [param length] is used, the characters are counted downwards from [String]'s length.
Examples:
[codeblock]
print("sample text".right(3)) #prints "ext"
@@ -626,21 +626,22 @@
</method>
<method name="rpad" qualifiers="const">
<return type="String" />
- <argument index="0" name="min_length" type="int" />
- <argument index="1" name="character" type="String" default="&quot; &quot;" />
+ <param index="0" name="min_length" type="int" />
+ <param index="1" name="character" type="String" default="&quot; &quot;" />
<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.
+ Formats a string to be at least [param min_length] long by adding [param character]s to the right of the string.
</description>
</method>
<method name="rsplit" qualifiers="const">
<return type="PackedStringArray" />
- <argument index="0" name="delimiter" type="String" />
- <argument index="1" name="allow_empty" type="bool" default="true" />
- <argument index="2" name="maxsplit" type="int" default="0" />
+ <param index="0" name="delimiter" type="String" />
+ <param index="1" name="allow_empty" type="bool" default="true" />
+ <param index="2" name="maxsplit" type="int" default="0" />
<description>
- Splits the string by a [code]delimiter[/code] string and returns an array of the substrings, starting from right.
+ Splits the string by a [param delimiter] string and returns an array of the substrings, starting from right.
The splits in the returned array are sorted in the same order as the original string, from left to right.
- If [code]maxsplit[/code] is specified, it defines the number of splits to do from the right up to [code]maxsplit[/code]. The default value of 0 means that all items are split, thus giving the same result as [method split].
+ If [param allow_empty] is [code]true[/code], and there are two adjacent delimiters in the string, it will add an empty string to the array of substrings at this position.
+ If [param maxsplit] is specified, it defines the number of splits to do from the right up to [param maxsplit]. The default value of 0 means that all items are split, thus giving the same result as [method split].
Example:
[codeblocks]
[gdscript]
@@ -658,10 +659,10 @@
</method>
<method name="rstrip" qualifiers="const">
<return type="String" />
- <argument index="0" name="chars" type="String" />
+ <param index="0" name="chars" type="String" />
<description>
- Returns a copy of the string with characters removed from the right. The [code]chars[/code] argument is a string specifying the set of characters to be removed.
- [b]Note:[/b] The [code]chars[/code] is not a suffix. See [method trim_suffix] method that will remove a single suffix string rather than a set of characters.
+ Returns a copy of the string with characters removed from the right. The [param chars] argument is a string specifying the set of characters to be removed.
+ [b]Note:[/b] The [param chars] is not a suffix. See [method trim_suffix] method that will remove a single suffix string rather than a set of characters.
</description>
</method>
<method name="sha1_buffer" qualifiers="const">
@@ -690,7 +691,7 @@
</method>
<method name="similarity" qualifiers="const">
<return type="float" />
- <argument index="0" name="text" type="String" />
+ <param index="0" name="text" type="String" />
<description>
Returns the similarity index ([url=https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient]Sorensen-Dice coefficient[/url]) of this string compared to another. A result of 1.0 means totally similar, while 0.0 means totally dissimilar.
[codeblock]
@@ -709,12 +710,13 @@
</method>
<method name="split" qualifiers="const">
<return type="PackedStringArray" />
- <argument index="0" name="delimiter" type="String" />
- <argument index="1" name="allow_empty" type="bool" default="true" />
- <argument index="2" name="maxsplit" type="int" default="0" />
+ <param index="0" name="delimiter" type="String" />
+ <param index="1" name="allow_empty" type="bool" default="true" />
+ <param index="2" name="maxsplit" type="int" default="0" />
<description>
- Splits the string by a [code]delimiter[/code] string and returns an array of the substrings. The [code]delimiter[/code] can be of any length.
- If [code]maxsplit[/code] is specified, it defines the number of splits to do from the left up to [code]maxsplit[/code]. The default value of [code]0[/code] means that all items are split.
+ Splits the string by a [param delimiter] string and returns an array of the substrings. The [param delimiter] can be of any length.
+ If [param allow_empty] is [code]true[/code], and there are two adjacent delimiters in the string, it will add an empty string to the array of substrings at this position.
+ If [param maxsplit] is specified, it defines the number of splits to do from the left up to [param maxsplit]. The default value of [code]0[/code] means that all items are split.
If you need only one element from the array at a specific index, [method get_slice] is a more performant option.
Example:
[codeblocks]
@@ -737,17 +739,18 @@
</method>
<method name="split_floats" qualifiers="const">
<return type="PackedFloat32Array" />
- <argument index="0" name="delimiter" type="String" />
- <argument index="1" name="allow_empty" type="bool" default="true" />
+ <param index="0" name="delimiter" type="String" />
+ <param index="1" name="allow_empty" type="bool" default="true" />
<description>
Splits the string in floats by using a delimiter string and returns an array of the substrings.
For example, [code]"1,2.5,3"[/code] will return [code][1,2.5,3][/code] if split by [code]","[/code].
+ If [param allow_empty] is [code]true[/code], and there are two adjacent delimiters in the string, it will add an empty string to the array of substrings at this position.
</description>
</method>
<method name="strip_edges" qualifiers="const">
<return type="String" />
- <argument index="0" name="left" type="bool" default="true" />
- <argument index="1" name="right" type="bool" default="true" />
+ <param index="0" name="left" type="bool" default="true" />
+ <param index="1" name="right" type="bool" default="true" />
<description>
Returns a copy of the string stripped of any non-printable character (including tabulations, spaces and line breaks) at the beginning and the end. The optional arguments are used to toggle stripping on the left and right edges respectively.
</description>
@@ -760,10 +763,10 @@
</method>
<method name="substr" qualifiers="const">
<return type="String" />
- <argument index="0" name="from" type="int" />
- <argument index="1" name="len" type="int" default="-1" />
+ <param index="0" name="from" type="int" />
+ <param index="1" name="len" type="int" default="-1" />
<description>
- Returns part of the string from the position [code]from[/code] with length [code]len[/code]. Argument [code]len[/code] is optional and using [code]-1[/code] will return remaining characters from given position.
+ Returns part of the string from the position [param from] with length [param len]. Argument [param len] is optional and using [code]-1[/code] will return remaining characters from given position.
</description>
</method>
<method name="to_ascii_buffer" qualifiers="const">
@@ -827,23 +830,23 @@
</method>
<method name="trim_prefix" qualifiers="const">
<return type="String" />
- <argument index="0" name="prefix" type="String" />
+ <param index="0" name="prefix" type="String" />
<description>
Removes a given string from the start if it starts with it or leaves the string unchanged.
</description>
</method>
<method name="trim_suffix" qualifiers="const">
<return type="String" />
- <argument index="0" name="suffix" type="String" />
+ <param index="0" name="suffix" type="String" />
<description>
Removes a given string from the end if it ends with it or leaves the string unchanged.
</description>
</method>
<method name="unicode_at" qualifiers="const">
<return type="int" />
- <argument index="0" name="at" type="int" />
+ <param index="0" name="at" type="int" />
<description>
- Returns the character code at position [code]at[/code].
+ Returns the character code at position [param at].
</description>
</method>
<method name="uri_decode" qualifiers="const">
@@ -882,9 +885,9 @@
</method>
<method name="xml_escape" qualifiers="const">
<return type="String" />
- <argument index="0" name="escape_quotes" type="bool" default="false" />
+ <param index="0" name="escape_quotes" type="bool" default="false" />
<description>
- Returns a copy of the string with special characters escaped using the XML standard. If [code]escape_quotes[/code] is [code]true[/code], the single quote ([code]'[/code]) and double quote ([code]"[/code]) characters are also escaped.
+ Returns a copy of the string with special characters escaped using the XML standard. If [param escape_quotes] is [code]true[/code], the single quote ([code]'[/code]) and double quote ([code]"[/code]) characters are also escaped.
</description>
</method>
<method name="xml_unescape" qualifiers="const">
@@ -897,73 +900,73 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="String" />
+ <param index="0" name="right" type="String" />
<description>
</description>
</operator>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="StringName" />
+ <param index="0" name="right" type="StringName" />
<description>
</description>
</operator>
<operator name="operator %">
<return type="String" />
- <argument index="0" name="right" type="Variant" />
+ <param index="0" name="right" type="Variant" />
<description>
</description>
</operator>
<operator name="operator +">
<return type="String" />
- <argument index="0" name="right" type="String" />
+ <param index="0" name="right" type="String" />
<description>
</description>
</operator>
<operator name="operator +">
<return type="String" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
</description>
</operator>
<operator name="operator &lt;">
<return type="bool" />
- <argument index="0" name="right" type="String" />
+ <param index="0" name="right" type="String" />
<description>
</description>
</operator>
<operator name="operator &lt;=">
<return type="bool" />
- <argument index="0" name="right" type="String" />
+ <param index="0" name="right" type="String" />
<description>
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="String" />
+ <param index="0" name="right" type="String" />
<description>
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="StringName" />
+ <param index="0" name="right" type="StringName" />
<description>
</description>
</operator>
<operator name="operator &gt;">
<return type="bool" />
- <argument index="0" name="right" type="String" />
+ <param index="0" name="right" type="String" />
<description>
</description>
</operator>
<operator name="operator &gt;=">
<return type="bool" />
- <argument index="0" name="right" type="String" />
+ <param index="0" name="right" type="String" />
<description>
</description>
</operator>
<operator name="operator []">
<return type="String" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
</description>
</operator>
diff --git a/doc/classes/StringName.xml b/doc/classes/StringName.xml
index a2bcac9788..c40d8929fc 100644
--- a/doc/classes/StringName.xml
+++ b/doc/classes/StringName.xml
@@ -19,14 +19,14 @@
</constructor>
<constructor name="StringName">
<return type="StringName" />
- <argument index="0" name="from" type="StringName" />
+ <param index="0" name="from" type="StringName" />
<description>
Constructs a [StringName] as a copy of the given [StringName].
</description>
</constructor>
<constructor name="StringName">
<return type="StringName" />
- <argument index="0" name="from" type="String" />
+ <param index="0" name="from" type="String" />
<description>
Creates a new [StringName] from the given [String]. [code]StringName("example")[/code] is equivalent to [code]&amp;"example"[/code].
</description>
@@ -43,49 +43,49 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="String" />
+ <param index="0" name="right" type="String" />
<description>
</description>
</operator>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="StringName" />
+ <param index="0" name="right" type="StringName" />
<description>
</description>
</operator>
<operator name="operator &lt;">
<return type="bool" />
- <argument index="0" name="right" type="StringName" />
+ <param index="0" name="right" type="StringName" />
<description>
</description>
</operator>
<operator name="operator &lt;=">
<return type="bool" />
- <argument index="0" name="right" type="StringName" />
+ <param index="0" name="right" type="StringName" />
<description>
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="String" />
+ <param index="0" name="right" type="String" />
<description>
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="StringName" />
+ <param index="0" name="right" type="StringName" />
<description>
</description>
</operator>
<operator name="operator &gt;">
<return type="bool" />
- <argument index="0" name="right" type="StringName" />
+ <param index="0" name="right" type="StringName" />
<description>
</description>
</operator>
<operator name="operator &gt;=">
<return type="bool" />
- <argument index="0" name="right" type="StringName" />
+ <param index="0" name="right" type="StringName" />
<description>
</description>
</operator>
diff --git a/doc/classes/StyleBox.xml b/doc/classes/StyleBox.xml
index d863e3c652..d9c19a0c86 100644
--- a/doc/classes/StyleBox.xml
+++ b/doc/classes/StyleBox.xml
@@ -12,8 +12,8 @@
<methods>
<method name="_draw" qualifiers="virtual const">
<return type="void" />
- <argument index="0" name="to_canvas_item" type="RID" />
- <argument index="1" name="rect" type="Rect2" />
+ <param index="0" name="to_canvas_item" type="RID" />
+ <param index="1" name="rect" type="Rect2" />
<description>
</description>
</method>
@@ -24,27 +24,27 @@
</method>
<method name="_get_draw_rect" qualifiers="virtual const">
<return type="Rect2" />
- <argument index="0" name="rect" type="Rect2" />
+ <param index="0" name="rect" type="Rect2" />
<description>
</description>
</method>
<method name="_get_style_margin" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="side" type="int" enum="Side" />
+ <param index="0" name="side" type="int" enum="Side" />
<description>
</description>
</method>
<method name="_test_mask" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="point" type="Vector2" />
- <argument index="1" name="rect" type="Rect2" />
+ <param index="0" name="point" type="Vector2" />
+ <param index="1" name="rect" type="Rect2" />
<description>
</description>
</method>
<method name="draw" qualifiers="const">
<return type="void" />
- <argument index="0" name="canvas_item" type="RID" />
- <argument index="1" name="rect" type="Rect2" />
+ <param index="0" name="canvas_item" type="RID" />
+ <param index="1" name="rect" type="Rect2" />
<description>
Draws this stylebox using a canvas item identified by the given [RID].
The [RID] value can either be the result of [method CanvasItem.get_canvas_item] called on an existing [CanvasItem]-derived node, or directly from creating a canvas item in the [RenderingServer] with [method RenderingServer.canvas_item_create].
@@ -64,14 +64,14 @@
</method>
<method name="get_default_margin" qualifiers="const">
<return type="float" />
- <argument index="0" name="margin" type="int" enum="Side" />
+ <param index="0" name="margin" type="int" enum="Side" />
<description>
Returns the default margin of the specified [enum Side].
</description>
</method>
<method name="get_margin" qualifiers="const">
<return type="float" />
- <argument index="0" name="margin" type="int" enum="Side" />
+ <param index="0" name="margin" type="int" enum="Side" />
<description>
Returns the content margin offset for the specified [enum Side].
Positive values reduce size inwards, unlike [Control]'s margin values.
@@ -91,16 +91,16 @@
</method>
<method name="set_default_margin">
<return type="void" />
- <argument index="0" name="margin" type="int" enum="Side" />
- <argument index="1" name="offset" type="float" />
+ <param index="0" name="margin" type="int" enum="Side" />
+ <param index="1" name="offset" type="float" />
<description>
- Sets the default value of the specified [enum Side] to [code]offset[/code] pixels.
+ Sets the default value of the specified [enum Side] to [param offset] pixels.
</description>
</method>
<method name="test_mask" qualifiers="const">
<return type="bool" />
- <argument index="0" name="point" type="Vector2" />
- <argument index="1" name="rect" type="Rect2" />
+ <param index="0" name="point" type="Vector2" />
+ <param index="1" name="rect" type="Rect2" />
<description>
Test a position in a rectangle, return whether it passes the mask test.
</description>
diff --git a/doc/classes/StyleBoxFlat.xml b/doc/classes/StyleBoxFlat.xml
index c80f8dcbb1..c4024fa4b5 100644
--- a/doc/classes/StyleBoxFlat.xml
+++ b/doc/classes/StyleBoxFlat.xml
@@ -26,7 +26,7 @@
<methods>
<method name="get_border_width" qualifiers="const">
<return type="int" />
- <argument index="0" name="margin" type="int" enum="Side" />
+ <param index="0" name="margin" type="int" enum="Side" />
<description>
Returns the specified [enum Side]'s border width.
</description>
@@ -39,81 +39,81 @@
</method>
<method name="get_corner_radius" qualifiers="const">
<return type="int" />
- <argument index="0" name="corner" type="int" enum="Corner" />
+ <param index="0" name="corner" type="int" enum="Corner" />
<description>
- Returns the given [code]corner[/code]'s radius. See [enum Corner] for possible values.
+ Returns the given [param corner]'s radius. See [enum Corner] for possible values.
</description>
</method>
<method name="get_expand_margin" qualifiers="const">
<return type="float" />
- <argument index="0" name="margin" type="int" enum="Side" />
+ <param index="0" name="margin" type="int" enum="Side" />
<description>
Returns the size of the specified [enum Side]'s expand margin.
</description>
</method>
<method name="set_border_width">
<return type="void" />
- <argument index="0" name="margin" type="int" enum="Side" />
- <argument index="1" name="width" type="int" />
+ <param index="0" name="margin" type="int" enum="Side" />
+ <param index="1" name="width" type="int" />
<description>
- Sets the specified [enum Side]'s border width to [code]width[/code] pixels.
+ Sets the specified [enum Side]'s border width to [param width] pixels.
</description>
</method>
<method name="set_border_width_all">
<return type="void" />
- <argument index="0" name="width" type="int" />
+ <param index="0" name="width" type="int" />
<description>
- Sets the border width to [code]width[/code] pixels for all sides.
+ Sets the border width to [param width] pixels for all sides.
</description>
</method>
<method name="set_corner_radius">
<return type="void" />
- <argument index="0" name="corner" type="int" enum="Corner" />
- <argument index="1" name="radius" type="int" />
+ <param index="0" name="corner" type="int" enum="Corner" />
+ <param index="1" name="radius" type="int" />
<description>
- Sets the corner radius to [code]radius[/code] pixels for the given [code]corner[/code]. See [enum Corner] for possible values.
+ Sets the corner radius to [param radius] pixels for the given [param corner]. See [enum Corner] for possible values.
</description>
</method>
<method name="set_corner_radius_all">
<return type="void" />
- <argument index="0" name="radius" type="int" />
+ <param index="0" name="radius" type="int" />
<description>
- Sets the corner radius to [code]radius[/code] pixels for all corners.
+ Sets the corner radius to [param radius] pixels for all corners.
</description>
</method>
<method name="set_corner_radius_individual">
<return type="void" />
- <argument index="0" name="radius_top_left" type="int" />
- <argument index="1" name="radius_top_right" type="int" />
- <argument index="2" name="radius_bottom_right" type="int" />
- <argument index="3" name="radius_bottom_left" type="int" />
+ <param index="0" name="radius_top_left" type="int" />
+ <param index="1" name="radius_top_right" type="int" />
+ <param index="2" name="radius_bottom_right" type="int" />
+ <param index="3" name="radius_bottom_left" type="int" />
<description>
- Sets the corner radius for each corner to [code]radius_top_left[/code], [code]radius_top_right[/code], [code]radius_bottom_right[/code], and [code]radius_bottom_left[/code] pixels.
+ Sets the corner radius for each corner to [param radius_top_left], [param radius_top_right], [param radius_bottom_right], and [param radius_bottom_left] pixels.
</description>
</method>
<method name="set_expand_margin">
<return type="void" />
- <argument index="0" name="margin" type="int" enum="Side" />
- <argument index="1" name="size" type="float" />
+ <param index="0" name="margin" type="int" enum="Side" />
+ <param index="1" name="size" type="float" />
<description>
- Sets the expand margin to [code]size[/code] pixels for the specified [enum Side].
+ Sets the expand margin to [param size] pixels for the specified [enum Side].
</description>
</method>
<method name="set_expand_margin_all">
<return type="void" />
- <argument index="0" name="size" type="float" />
+ <param index="0" name="size" type="float" />
<description>
- Sets the expand margin to [code]size[/code] pixels for all margins.
+ Sets the expand margin to [param size] pixels for all margins.
</description>
</method>
<method name="set_expand_margin_individual">
<return type="void" />
- <argument index="0" name="size_left" type="float" />
- <argument index="1" name="size_top" type="float" />
- <argument index="2" name="size_right" type="float" />
- <argument index="3" name="size_bottom" type="float" />
+ <param index="0" name="size_left" type="float" />
+ <param index="1" name="size_top" type="float" />
+ <param index="2" name="size_right" type="float" />
+ <param index="3" name="size_bottom" type="float" />
<description>
- Sets the expand margin for each margin to [code]size_left[/code], [code]size_top[/code], [code]size_right[/code], and [code]size_bottom[/code] pixels.
+ Sets the expand margin for each margin to [param size_left], [param size_top], [param size_right], and [param size_bottom] pixels.
</description>
</method>
</methods>
diff --git a/doc/classes/StyleBoxTexture.xml b/doc/classes/StyleBoxTexture.xml
index 8c324d4e37..7db70e630d 100644
--- a/doc/classes/StyleBoxTexture.xml
+++ b/doc/classes/StyleBoxTexture.xml
@@ -11,49 +11,49 @@
<methods>
<method name="get_expand_margin_size" qualifiers="const">
<return type="float" />
- <argument index="0" name="margin" type="int" enum="Side" />
+ <param index="0" name="margin" type="int" enum="Side" />
<description>
Returns the expand margin size of the specified [enum Side].
</description>
</method>
<method name="get_margin_size" qualifiers="const">
<return type="float" />
- <argument index="0" name="margin" type="int" enum="Side" />
+ <param index="0" name="margin" type="int" enum="Side" />
<description>
Returns the margin size of the specified [enum Side].
</description>
</method>
<method name="set_expand_margin_all">
<return type="void" />
- <argument index="0" name="size" type="float" />
+ <param index="0" name="size" type="float" />
<description>
- Sets the expand margin to [code]size[/code] pixels for all margins.
+ Sets the expand margin to [param size] pixels for all margins.
</description>
</method>
<method name="set_expand_margin_individual">
<return type="void" />
- <argument index="0" name="size_left" type="float" />
- <argument index="1" name="size_top" type="float" />
- <argument index="2" name="size_right" type="float" />
- <argument index="3" name="size_bottom" type="float" />
+ <param index="0" name="size_left" type="float" />
+ <param index="1" name="size_top" type="float" />
+ <param index="2" name="size_right" type="float" />
+ <param index="3" name="size_bottom" type="float" />
<description>
- Sets the expand margin for each margin to [code]size_left[/code], [code]size_top[/code], [code]size_right[/code], and [code]size_bottom[/code] pixels.
+ Sets the expand margin for each margin to [param size_left], [param size_top], [param size_right], and [param size_bottom] pixels.
</description>
</method>
<method name="set_expand_margin_size">
<return type="void" />
- <argument index="0" name="margin" type="int" enum="Side" />
- <argument index="1" name="size" type="float" />
+ <param index="0" name="margin" type="int" enum="Side" />
+ <param index="1" name="size" type="float" />
<description>
- Sets the expand margin to [code]size[/code] pixels for the specified [enum Side].
+ Sets the expand margin to [param size] pixels for the specified [enum Side].
</description>
</method>
<method name="set_margin_size">
<return type="void" />
- <argument index="0" name="margin" type="int" enum="Side" />
- <argument index="1" name="size" type="float" />
+ <param index="0" name="margin" type="int" enum="Side" />
+ <param index="1" name="size" type="float" />
<description>
- Sets the margin to [code]size[/code] pixels for the specified [enum Side].
+ Sets the margin to [param size] pixels for the specified [enum Side].
</description>
</method>
</methods>
diff --git a/doc/classes/SubViewport.xml b/doc/classes/SubViewport.xml
index b62c294f2c..7020cae1de 100644
--- a/doc/classes/SubViewport.xml
+++ b/doc/classes/SubViewport.xml
@@ -25,7 +25,7 @@
The update mode when the sub-viewport is used as a render target.
</member>
<member name="size" type="Vector2i" setter="set_size" getter="get_size" default="Vector2i(512, 512)">
- The width and height of the sub-viewport.
+ The width and height of the sub-viewport. Must be set to a value greater than or equal to 2 pixels on both dimensions. Otherwise, nothing will be displayed.
</member>
<member name="size_2d_override" type="Vector2i" setter="set_size_2d_override" getter="get_size_2d_override" default="Vector2i(0, 0)">
The 2D size override of the sub-viewport. If either the width or height is [code]0[/code], the override is disabled.
diff --git a/doc/classes/SurfaceTool.xml b/doc/classes/SurfaceTool.xml
index ad638a680b..ccec691107 100644
--- a/doc/classes/SurfaceTool.xml
+++ b/doc/classes/SurfaceTool.xml
@@ -33,19 +33,19 @@
<methods>
<method name="add_index">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Adds a vertex to index array if you are using indexed vertices. Does not need to be called before adding vertices.
</description>
</method>
<method name="add_triangle_fan">
<return type="void" />
- <argument index="0" name="vertices" type="PackedVector3Array" />
- <argument index="1" name="uvs" type="PackedVector2Array" default="PackedVector2Array()" />
- <argument index="2" name="colors" type="PackedColorArray" default="PackedColorArray()" />
- <argument index="3" name="uv2s" type="PackedVector2Array" default="PackedVector2Array()" />
- <argument index="4" name="normals" type="PackedVector3Array" default="PackedVector3Array()" />
- <argument index="5" name="tangents" type="Array" default="[]" />
+ <param index="0" name="vertices" type="PackedVector3Array" />
+ <param index="1" name="uvs" type="PackedVector2Array" default="PackedVector2Array()" />
+ <param index="2" name="colors" type="PackedColorArray" default="PackedColorArray()" />
+ <param index="3" name="uv2s" type="PackedVector2Array" default="PackedVector2Array()" />
+ <param index="4" name="normals" type="PackedVector3Array" default="PackedVector3Array()" />
+ <param index="5" name="tangents" type="Array" default="[]" />
<description>
Inserts a triangle fan made of array data into [Mesh] being constructed.
Requires the primitive type be set to [constant Mesh.PRIMITIVE_TRIANGLES].
@@ -53,23 +53,23 @@
</method>
<method name="add_vertex">
<return type="void" />
- <argument index="0" name="vertex" type="Vector3" />
+ <param index="0" name="vertex" type="Vector3" />
<description>
Specifies the position of current vertex. Should be called after specifying other vertex properties (e.g. Color, UV).
</description>
</method>
<method name="append_from">
<return type="void" />
- <argument index="0" name="existing" type="Mesh" />
- <argument index="1" name="surface" type="int" />
- <argument index="2" name="transform" type="Transform3D" />
+ <param index="0" name="existing" type="Mesh" />
+ <param index="1" name="surface" type="int" />
+ <param index="2" name="transform" type="Transform3D" />
<description>
Append vertices from a given [Mesh] surface onto the current vertex array with specified [Transform3D].
</description>
</method>
<method name="begin">
<return type="void" />
- <argument index="0" name="primitive" type="int" enum="Mesh.PrimitiveType" />
+ <param index="0" name="primitive" type="int" enum="Mesh.PrimitiveType" />
<description>
Called before adding any vertices. Takes the primitive type as an argument (e.g. [constant Mesh.PRIMITIVE_TRIANGLES]).
</description>
@@ -82,11 +82,11 @@
</method>
<method name="commit">
<return type="ArrayMesh" />
- <argument index="0" name="existing" type="ArrayMesh" default="null" />
- <argument index="1" name="flags" type="int" default="0" />
+ <param index="0" name="existing" type="ArrayMesh" default="null" />
+ <param index="1" name="flags" type="int" default="0" />
<description>
Returns a constructed [ArrayMesh] from current information passed in. If an existing [ArrayMesh] is passed in as an argument, will add an extra surface to the existing [ArrayMesh].
- [b]FIXME:[/b] Document possible values for [code]flags[/code], it changed in 4.0. Likely some combinations of [enum Mesh.ArrayFormat].
+ [b]FIXME:[/b] Document possible values for [param flags], it changed in 4.0. Likely some combinations of [enum Mesh.ArrayFormat].
</description>
</method>
<method name="commit_to_arrays">
@@ -97,17 +97,17 @@
</method>
<method name="create_from">
<return type="void" />
- <argument index="0" name="existing" type="Mesh" />
- <argument index="1" name="surface" type="int" />
+ <param index="0" name="existing" type="Mesh" />
+ <param index="1" name="surface" type="int" />
<description>
Creates a vertex array from an existing [Mesh].
</description>
</method>
<method name="create_from_blend_shape">
<return type="void" />
- <argument index="0" name="existing" type="Mesh" />
- <argument index="1" name="surface" type="int" />
- <argument index="2" name="blend_shape" type="String" />
+ <param index="0" name="existing" type="Mesh" />
+ <param index="1" name="surface" type="int" />
+ <param index="2" name="blend_shape" type="String" />
<description>
Creates a vertex array from the specified blend shape of an existing [Mesh]. This can be used to extract a specific pose from a blend shape.
</description>
@@ -120,18 +120,18 @@
</method>
<method name="generate_lod">
<return type="PackedInt32Array" />
- <argument index="0" name="nd_threshold" type="float" />
- <argument index="1" name="target_index_count" type="int" default="3" />
+ <param index="0" name="nd_threshold" type="float" />
+ <param index="1" name="target_index_count" type="int" default="3" />
<description>
- Generates a LOD for a given [code]nd_threshold[/code] in linear units (square root of quadric error metric), using at most [code]target_index_count[/code] indices.
+ Generates a LOD for a given [param nd_threshold] in linear units (square root of quadric error metric), using at most [param target_index_count] indices.
Deprecated. Unused internally and neglects to preserve normals or UVs. Consider using [method ImporterMesh.generate_lods] instead.
</description>
</method>
<method name="generate_normals">
<return type="void" />
- <argument index="0" name="flip" type="bool" default="false" />
+ <param index="0" name="flip" type="bool" default="false" />
<description>
- Generates normals from vertices so you do not have to do it manually. If [code]flip[/code] is [code]true[/code], the resulting normals will be inverted. [method generate_normals] should be called [i]after[/i] generating geometry and [i]before[/i] committing the mesh using [method commit] or [method commit_to_arrays]. For correct display of normal-mapped surfaces, you will also have to generate tangents using [method generate_tangents].
+ Generates normals from vertices so you do not have to do it manually. If [param flip] is [code]true[/code], the resulting normals will be inverted. [method generate_normals] should be called [i]after[/i] generating geometry and [i]before[/i] committing the mesh using [method commit] or [method commit_to_arrays]. For correct display of normal-mapped surfaces, you will also have to generate tangents using [method generate_tangents].
[b]Note:[/b] [method generate_normals] only works if the primitive type to be set to [constant Mesh.PRIMITIVE_TRIANGLES].
</description>
</method>
@@ -149,9 +149,9 @@
</method>
<method name="get_custom_format" qualifiers="const">
<return type="int" enum="SurfaceTool.CustomFormat" />
- <argument index="0" name="channel_index" type="int" />
+ <param index="0" name="channel_index" type="int" />
<description>
- Returns the format for custom [code]channel_index[/code] (currently up to 4). Returns [constant CUSTOM_MAX] if this custom channel is unused.
+ Returns the format for custom [param channel_index] (currently up to 4). Returns [constant CUSTOM_MAX] if this custom channel is unused.
</description>
</method>
<method name="get_primitive_type" qualifiers="const">
@@ -182,14 +182,14 @@
</method>
<method name="set_bones">
<return type="void" />
- <argument index="0" name="bones" type="PackedInt32Array" />
+ <param index="0" name="bones" type="PackedInt32Array" />
<description>
- Specifies an array of bones to use for the [i]next[/i] vertex. [code]bones[/code] must contain 4 integers.
+ Specifies an array of bones to use for the [i]next[/i] vertex. [param bones] must contain 4 integers.
</description>
</method>
<method name="set_color">
<return type="void" />
- <argument index="0" name="color" type="Color" />
+ <param index="0" name="color" type="Color" />
<description>
Specifies a [Color] to use for the [i]next[/i] vertex. If every vertex needs to have this information set and you fail to submit it for the first vertex, this information may not be used at all.
[b]Note:[/b] The material must have [member BaseMaterial3D.vertex_color_use_as_albedo] enabled for the vertex color to be visible.
@@ -197,39 +197,39 @@
</method>
<method name="set_custom">
<return type="void" />
- <argument index="0" name="channel_index" type="int" />
- <argument index="1" name="custom_color" type="Color" />
+ <param index="0" name="channel_index" type="int" />
+ <param index="1" name="custom_color" type="Color" />
<description>
- Sets the custom value on this vertex for [code]channel_index[/code].
- [method set_custom_format] must be called first for this [code]channel_index[/code]. Formats which are not RGBA will ignore other color channels.
+ Sets the custom value on this vertex for [param channel_index].
+ [method set_custom_format] must be called first for this [param channel_index]. Formats which are not RGBA will ignore other color channels.
</description>
</method>
<method name="set_custom_format">
<return type="void" />
- <argument index="0" name="channel_index" type="int" />
- <argument index="1" name="format" type="int" enum="SurfaceTool.CustomFormat" />
+ <param index="0" name="channel_index" type="int" />
+ <param index="1" name="format" type="int" enum="SurfaceTool.CustomFormat" />
<description>
- Sets the color format for this custom [code]channel_index[/code]. Use [constant CUSTOM_MAX] to disable.
+ Sets the color format for this custom [param channel_index]. Use [constant CUSTOM_MAX] to disable.
Must be invoked after [method begin] and should be set before [method commit] or [method commit_to_arrays].
</description>
</method>
<method name="set_material">
<return type="void" />
- <argument index="0" name="material" type="Material" />
+ <param index="0" name="material" type="Material" />
<description>
Sets [Material] to be used by the [Mesh] you are constructing.
</description>
</method>
<method name="set_normal">
<return type="void" />
- <argument index="0" name="normal" type="Vector3" />
+ <param index="0" name="normal" type="Vector3" />
<description>
Specifies a normal to use for the [i]next[/i] vertex. If every vertex needs to have this information set and you fail to submit it for the first vertex, this information may not be used at all.
</description>
</method>
<method name="set_skin_weight_count">
<return type="void" />
- <argument index="0" name="count" type="int" enum="SurfaceTool.SkinWeightCount" />
+ <param index="0" name="count" type="int" enum="SurfaceTool.SkinWeightCount" />
<description>
Set to [constant SKIN_8_WEIGHTS] to indicate that up to 8 bone influences per vertex may be used.
By default, only 4 bone influences are used ([constant SKIN_4_WEIGHTS])
@@ -238,37 +238,37 @@
</method>
<method name="set_smooth_group">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Specifies whether the current vertex (if using only vertex arrays) or current index (if also using index arrays) should use smooth normals for normal calculation.
</description>
</method>
<method name="set_tangent">
<return type="void" />
- <argument index="0" name="tangent" type="Plane" />
+ <param index="0" name="tangent" type="Plane" />
<description>
Specifies a tangent to use for the [i]next[/i] vertex. If every vertex needs to have this information set and you fail to submit it for the first vertex, this information may not be used at all.
</description>
</method>
<method name="set_uv">
<return type="void" />
- <argument index="0" name="uv" type="Vector2" />
+ <param index="0" name="uv" type="Vector2" />
<description>
Specifies a set of UV coordinates to use for the [i]next[/i] vertex. If every vertex needs to have this information set and you fail to submit it for the first vertex, this information may not be used at all.
</description>
</method>
<method name="set_uv2">
<return type="void" />
- <argument index="0" name="uv2" type="Vector2" />
+ <param index="0" name="uv2" type="Vector2" />
<description>
Specifies an optional second set of UV coordinates to use for the [i]next[/i] vertex. If every vertex needs to have this information set and you fail to submit it for the first vertex, this information may not be used at all.
</description>
</method>
<method name="set_weights">
<return type="void" />
- <argument index="0" name="weights" type="PackedFloat32Array" />
+ <param index="0" name="weights" type="PackedFloat32Array" />
<description>
- Specifies weight values to use for the [i]next[/i] vertex. [code]weights[/code] must contain 4 values. If every vertex needs to have this information set and you fail to submit it for the first vertex, this information may not be used at all.
+ Specifies weight values to use for the [i]next[/i] vertex. [param weights] must contain 4 values. If every vertex needs to have this information set and you fail to submit it for the first vertex, this information may not be used at all.
</description>
</method>
</methods>
diff --git a/doc/classes/SyntaxHighlighter.xml b/doc/classes/SyntaxHighlighter.xml
index 70cbd83371..fcac96c04d 100644
--- a/doc/classes/SyntaxHighlighter.xml
+++ b/doc/classes/SyntaxHighlighter.xml
@@ -19,7 +19,7 @@
</method>
<method name="_get_line_syntax_highlighting" qualifiers="virtual const">
<return type="Dictionary" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Virtual method which can be overridden to return syntax highlighting data.
See [method get_line_syntax_highlighting] for more details.
@@ -40,7 +40,7 @@
</method>
<method name="get_line_syntax_highlighting">
<return type="Dictionary" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns syntax highlighting data for a single line. If the line is not cached, calls [method _get_line_syntax_highlighting] to calculate the data.
The return [Dictionary] is column number to [Dictionary]. The column number notes the start of a region, the region will end if another region is found, or at the end of the line. The nested [Dictionary] contains the data for that region, currently only the key "color" is supported.
diff --git a/doc/classes/SystemFont.xml b/doc/classes/SystemFont.xml
index b1b78f1705..c235843f3b 100644
--- a/doc/classes/SystemFont.xml
+++ b/doc/classes/SystemFont.xml
@@ -13,8 +13,8 @@
<tutorials>
</tutorials>
<members>
- <member name="antialiased" type="bool" setter="set_antialiased" getter="is_antialiased" default="true">
- If set to [code]true[/code], font 8-bit anitialiased glyph rendering is supported and enabled.
+ <member name="antialiasing" type="int" setter="set_antialiasing" getter="get_antialiasing" enum="TextServer.FontAntialiasing" default="1">
+ Font anti-aliasing mode.
</member>
<member name="fallbacks" type="Font[]" setter="set_fallbacks" getter="get_fallbacks" default="[]">
Array of fallback [Font]s.
@@ -34,6 +34,9 @@
<member name="hinting" type="int" setter="set_hinting" getter="get_hinting" enum="TextServer.Hinting" default="1">
Font hinting mode.
</member>
+ <member name="multichannel_signed_distance_field" type="bool" setter="set_multichannel_signed_distance_field" getter="is_multichannel_signed_distance_field" default="false">
+ If set to [code]true[/code], glyphs of all sizes are rendered using single multichannel signed distance field generated from the dynamic font vector data.
+ </member>
<member name="oversampling" type="float" setter="set_oversampling" getter="get_oversampling" default="0.0">
Font oversampling factor, if set to [code]0.0[/code] global oversampling factor is used instead.
</member>
diff --git a/doc/classes/TCPServer.xml b/doc/classes/TCPServer.xml
index 06fe4de9e2..fbed80bcfa 100644
--- a/doc/classes/TCPServer.xml
+++ b/doc/classes/TCPServer.xml
@@ -30,13 +30,13 @@
</method>
<method name="listen">
<return type="int" enum="Error" />
- <argument index="0" name="port" type="int" />
- <argument index="1" name="bind_address" type="String" default="&quot;*&quot;" />
+ <param index="0" name="port" type="int" />
+ <param index="1" name="bind_address" type="String" default="&quot;*&quot;" />
<description>
- Listen on the [code]port[/code] binding to [code]bind_address[/code].
- If [code]bind_address[/code] is set as [code]"*"[/code] (default), the server will listen on all available addresses (both IPv4 and IPv6).
- If [code]bind_address[/code] is set as [code]"0.0.0.0"[/code] (for IPv4) or [code]"::"[/code] (for IPv6), the server will listen on all available addresses matching that IP type.
- If [code]bind_address[/code] is set to any valid address (e.g. [code]"192.168.1.101"[/code], [code]"::1"[/code], etc), the server will only listen on the interface with that addresses (or fail if no interface with the given address exists).
+ Listen on the [param port] binding to [param bind_address].
+ If [param bind_address] is set as [code]"*"[/code] (default), the server will listen on all available addresses (both IPv4 and IPv6).
+ If [param bind_address] is set as [code]"0.0.0.0"[/code] (for IPv4) or [code]"::"[/code] (for IPv6), the server will listen on all available addresses matching that IP type.
+ If [param bind_address] is set to any valid address (e.g. [code]"192.168.1.101"[/code], [code]"::1"[/code], etc), the server will only listen on the interface with that addresses (or fail if no interface with the given address exists).
</description>
</method>
<method name="stop">
diff --git a/doc/classes/TabBar.xml b/doc/classes/TabBar.xml
index 79d52b70fb..713c016651 100644
--- a/doc/classes/TabBar.xml
+++ b/doc/classes/TabBar.xml
@@ -11,15 +11,15 @@
<methods>
<method name="add_tab">
<return type="void" />
- <argument index="0" name="title" type="String" default="&quot;&quot;" />
- <argument index="1" name="icon" type="Texture2D" default="null" />
+ <param index="0" name="title" type="String" default="&quot;&quot;" />
+ <param index="1" name="icon" type="Texture2D" default="null" />
<description>
Adds a new tab.
</description>
</method>
<method name="ensure_tab_visible">
<return type="void" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Moves the scroll view to make the tab visible.
</description>
@@ -38,28 +38,28 @@
</method>
<method name="get_tab_button_icon" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="tab_idx" type="int" />
+ <param index="0" name="tab_idx" type="int" />
<description>
- Returns the [Texture2D] for the right button of the tab at index [code]tab_idx[/code] or [code]null[/code] if the button has no [Texture2D].
+ Returns the [Texture2D] for the right button of the tab at index [param tab_idx] or [code]null[/code] if the button has no [Texture2D].
</description>
</method>
<method name="get_tab_icon" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="tab_idx" type="int" />
+ <param index="0" name="tab_idx" type="int" />
<description>
- Returns the [Texture2D] for the tab at index [code]tab_idx[/code] or [code]null[/code] if the tab has no [Texture2D].
+ Returns the [Texture2D] for the tab at index [param tab_idx] or [code]null[/code] if the tab has no [Texture2D].
</description>
</method>
<method name="get_tab_idx_at_point" qualifiers="const">
<return type="int" />
- <argument index="0" name="point" type="Vector2" />
+ <param index="0" name="point" type="Vector2" />
<description>
- Returns the index of the tab at local coordinates [code]point[/code]. Returns [code]-1[/code] if the point is outside the control boundaries or if there's no tab at the queried position.
+ Returns the index of the tab at local coordinates [param point]. Returns [code]-1[/code] if the point is outside the control boundaries or if there's no tab at the queried position.
</description>
</method>
<method name="get_tab_language" qualifiers="const">
<return type="String" />
- <argument index="0" name="tab_idx" type="int" />
+ <param index="0" name="tab_idx" type="int" />
<description>
Returns tab title language code.
</description>
@@ -72,108 +72,108 @@
</method>
<method name="get_tab_rect" qualifiers="const">
<return type="Rect2" />
- <argument index="0" name="tab_idx" type="int" />
+ <param index="0" name="tab_idx" type="int" />
<description>
Returns tab [Rect2] with local position and size.
</description>
</method>
<method name="get_tab_text_direction" qualifiers="const">
<return type="int" enum="Control.TextDirection" />
- <argument index="0" name="tab_idx" type="int" />
+ <param index="0" name="tab_idx" type="int" />
<description>
Returns tab title text base writing direction.
</description>
</method>
<method name="get_tab_title" qualifiers="const">
<return type="String" />
- <argument index="0" name="tab_idx" type="int" />
+ <param index="0" name="tab_idx" type="int" />
<description>
- Returns the title of the tab at index [code]tab_idx[/code].
+ Returns the title of the tab at index [param tab_idx].
</description>
</method>
<method name="is_tab_disabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="tab_idx" type="int" />
+ <param index="0" name="tab_idx" type="int" />
<description>
- Returns [code]true[/code] if the tab at index [code]tab_idx[/code] is disabled.
+ Returns [code]true[/code] if the tab at index [param tab_idx] is disabled.
</description>
</method>
<method name="is_tab_hidden" qualifiers="const">
<return type="bool" />
- <argument index="0" name="tab_idx" type="int" />
+ <param index="0" name="tab_idx" type="int" />
<description>
- Returns [code]true[/code] if the tab at index [code]tab_idx[/code] is hidden.
+ Returns [code]true[/code] if the tab at index [param tab_idx] is hidden.
</description>
</method>
<method name="move_tab">
<return type="void" />
- <argument index="0" name="from" type="int" />
- <argument index="1" name="to" type="int" />
+ <param index="0" name="from" type="int" />
+ <param index="1" name="to" type="int" />
<description>
- Moves a tab from [code]from[/code] to [code]to[/code].
+ Moves a tab from [param from] to [param to].
</description>
</method>
<method name="remove_tab">
<return type="void" />
- <argument index="0" name="tab_idx" type="int" />
+ <param index="0" name="tab_idx" type="int" />
<description>
- Removes the tab at index [code]tab_idx[/code].
+ Removes the tab at index [param tab_idx].
</description>
</method>
<method name="set_tab_button_icon">
<return type="void" />
- <argument index="0" name="tab_idx" type="int" />
- <argument index="1" name="icon" type="Texture2D" />
+ <param index="0" name="tab_idx" type="int" />
+ <param index="1" name="icon" type="Texture2D" />
<description>
- Sets an [code]icon[/code] for the button of the tab at index [code]tab_idx[/code] (located to the right, before the close button), making it visible and clickable (See [signal tab_button_pressed]). Giving it a [code]null[/code] value will hide the button.
+ Sets an [param icon] for the button of the tab at index [param tab_idx] (located to the right, before the close button), making it visible and clickable (See [signal tab_button_pressed]). Giving it a [code]null[/code] value will hide the button.
</description>
</method>
<method name="set_tab_disabled">
<return type="void" />
- <argument index="0" name="tab_idx" type="int" />
- <argument index="1" name="disabled" type="bool" />
+ <param index="0" name="tab_idx" type="int" />
+ <param index="1" name="disabled" type="bool" />
<description>
- If [code]disabled[/code] is [code]true[/code], disables the tab at index [code]tab_idx[/code], making it non-interactable.
+ If [param disabled] is [code]true[/code], disables the tab at index [param tab_idx], making it non-interactable.
</description>
</method>
<method name="set_tab_hidden">
<return type="void" />
- <argument index="0" name="tab_idx" type="int" />
- <argument index="1" name="hidden" type="bool" />
+ <param index="0" name="tab_idx" type="int" />
+ <param index="1" name="hidden" type="bool" />
<description>
- If [code]hidden[/code] is [code]true[/code], hides the tab at index [code]tab_idx[/code], making it disappear from the tab area.
+ If [param hidden] is [code]true[/code], hides the tab at index [param tab_idx], making it disappear from the tab area.
</description>
</method>
<method name="set_tab_icon">
<return type="void" />
- <argument index="0" name="tab_idx" type="int" />
- <argument index="1" name="icon" type="Texture2D" />
+ <param index="0" name="tab_idx" type="int" />
+ <param index="1" name="icon" type="Texture2D" />
<description>
- Sets an [code]icon[/code] for the tab at index [code]tab_idx[/code].
+ Sets an [param icon] for the tab at index [param tab_idx].
</description>
</method>
<method name="set_tab_language">
<return type="void" />
- <argument index="0" name="tab_idx" type="int" />
- <argument index="1" name="language" type="String" />
+ <param index="0" name="tab_idx" type="int" />
+ <param index="1" name="language" type="String" />
<description>
Sets language code of tab title used for line-breaking and text shaping algorithms, if left empty current locale is used instead.
</description>
</method>
<method name="set_tab_text_direction">
<return type="void" />
- <argument index="0" name="tab_idx" type="int" />
- <argument index="1" name="direction" type="int" enum="Control.TextDirection" />
+ <param index="0" name="tab_idx" type="int" />
+ <param index="1" name="direction" type="int" enum="Control.TextDirection" />
<description>
Sets tab title base writing direction.
</description>
</method>
<method name="set_tab_title">
<return type="void" />
- <argument index="0" name="tab_idx" type="int" />
- <argument index="1" name="title" type="String" />
+ <param index="0" name="tab_idx" type="int" />
+ <param index="1" name="title" type="String" />
<description>
- Sets a [code]title[/code] for the tab at index [code]tab_idx[/code].
+ Sets a [param title] for the tab at index [param tab_idx].
</description>
</method>
</methods>
@@ -215,31 +215,31 @@
</members>
<signals>
<signal name="active_tab_rearranged">
- <argument index="0" name="idx_to" type="int" />
+ <param index="0" name="idx_to" type="int" />
<description>
Emitted when the active tab is rearranged via mouse drag. See [member drag_to_rearrange_enabled].
</description>
</signal>
<signal name="tab_button_pressed">
- <argument index="0" name="tab" type="int" />
+ <param index="0" name="tab" type="int" />
<description>
Emitted when a tab's right button is pressed. See [method set_tab_button_icon].
</description>
</signal>
<signal name="tab_changed">
- <argument index="0" name="tab" type="int" />
+ <param index="0" name="tab" type="int" />
<description>
Emitted when switching to another tab.
</description>
</signal>
<signal name="tab_clicked">
- <argument index="0" name="tab" type="int" />
+ <param index="0" name="tab" type="int" />
<description>
Emitted when a tab is clicked, even if it is the current tab.
</description>
</signal>
<signal name="tab_close_pressed">
- <argument index="0" name="tab" type="int" />
+ <param index="0" name="tab" type="int" />
<description>
Emitted when a tab's close button is pressed.
[b]Note:[/b] Tabs are not removed automatically once the close button is pressed, this behavior needs to be programmed manually. For example:
@@ -254,19 +254,19 @@
</description>
</signal>
<signal name="tab_hovered">
- <argument index="0" name="tab" type="int" />
+ <param index="0" name="tab" type="int" />
<description>
Emitted when a tab is hovered by the mouse.
</description>
</signal>
<signal name="tab_rmb_clicked">
- <argument index="0" name="tab" type="int" />
+ <param index="0" name="tab" type="int" />
<description>
Emitted when a tab is right-clicked. [member select_with_rmb] must be enabled.
</description>
</signal>
<signal name="tab_selected">
- <argument index="0" name="tab" type="int" />
+ <param index="0" name="tab" type="int" />
<description>
Emitted when a tab is selected via click or script, even if it is the current tab.
</description>
diff --git a/doc/classes/TabContainer.xml b/doc/classes/TabContainer.xml
index 10b5f730ad..74f258072c 100644
--- a/doc/classes/TabContainer.xml
+++ b/doc/classes/TabContainer.xml
@@ -33,16 +33,16 @@
</method>
<method name="get_tab_button_icon" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="tab_idx" type="int" />
+ <param index="0" name="tab_idx" type="int" />
<description>
- Returns the button icon from the tab at index [code]tab_idx[/code].
+ Returns the button icon from the tab at index [param tab_idx].
</description>
</method>
<method name="get_tab_control" qualifiers="const">
<return type="Control" />
- <argument index="0" name="tab_idx" type="int" />
+ <param index="0" name="tab_idx" type="int" />
<description>
- Returns the [Control] node from the tab at index [code]tab_idx[/code].
+ Returns the [Control] node from the tab at index [param tab_idx].
</description>
</method>
<method name="get_tab_count" qualifiers="const">
@@ -53,91 +53,91 @@
</method>
<method name="get_tab_icon" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="tab_idx" type="int" />
+ <param index="0" name="tab_idx" type="int" />
<description>
- Returns the [Texture2D] for the tab at index [code]tab_idx[/code] or [code]null[/code] if the tab has no [Texture2D].
+ Returns the [Texture2D] for the tab at index [param tab_idx] or [code]null[/code] if the tab has no [Texture2D].
</description>
</method>
<method name="get_tab_idx_at_point" qualifiers="const">
<return type="int" />
- <argument index="0" name="point" type="Vector2" />
+ <param index="0" name="point" type="Vector2" />
<description>
- Returns the index of the tab at local coordinates [code]point[/code]. Returns [code]-1[/code] if the point is outside the control boundaries or if there's no tab at the queried position.
+ Returns the index of the tab at local coordinates [param point]. Returns [code]-1[/code] if the point is outside the control boundaries or if there's no tab at the queried position.
</description>
</method>
<method name="get_tab_idx_from_control" qualifiers="const">
<return type="int" />
- <argument index="0" name="control" type="Control" />
+ <param index="0" name="control" type="Control" />
<description>
- Returns the index of the tab tied to the given [code]control[/code]. The control must be a child of the [TabContainer].
+ Returns the index of the tab tied to the given [param control]. The control must be a child of the [TabContainer].
</description>
</method>
<method name="get_tab_title" qualifiers="const">
<return type="String" />
- <argument index="0" name="tab_idx" type="int" />
+ <param index="0" name="tab_idx" type="int" />
<description>
- Returns the title of the tab at index [code]tab_idx[/code]. Tab titles default to the name of the indexed child node, but this can be overridden with [method set_tab_title].
+ Returns the title of the tab at index [param tab_idx]. Tab titles default to the name of the indexed child node, but this can be overridden with [method set_tab_title].
</description>
</method>
<method name="is_tab_disabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="tab_idx" type="int" />
+ <param index="0" name="tab_idx" type="int" />
<description>
- Returns [code]true[/code] if the tab at index [code]tab_idx[/code] is disabled.
+ Returns [code]true[/code] if the tab at index [param tab_idx] is disabled.
</description>
</method>
<method name="is_tab_hidden" qualifiers="const">
<return type="bool" />
- <argument index="0" name="tab_idx" type="int" />
+ <param index="0" name="tab_idx" type="int" />
<description>
- Returns [code]true[/code] if the tab at index [code]tab_idx[/code] is hidden.
+ Returns [code]true[/code] if the tab at index [param tab_idx] is hidden.
</description>
</method>
<method name="set_popup">
<return type="void" />
- <argument index="0" name="popup" type="Node" />
+ <param index="0" name="popup" type="Node" />
<description>
If set on a [Popup] node instance, a popup menu icon appears in the top-right corner of the [TabContainer] (setting it to [code]null[/code] will make it go away). Clicking it will expand the [Popup] node.
</description>
</method>
<method name="set_tab_button_icon">
<return type="void" />
- <argument index="0" name="tab_idx" type="int" />
- <argument index="1" name="icon" type="Texture2D" />
+ <param index="0" name="tab_idx" type="int" />
+ <param index="1" name="icon" type="Texture2D" />
<description>
- Sets the button icon from the tab at index [code]tab_idx[/code].
+ Sets the button icon from the tab at index [param tab_idx].
</description>
</method>
<method name="set_tab_disabled">
<return type="void" />
- <argument index="0" name="tab_idx" type="int" />
- <argument index="1" name="disabled" type="bool" />
+ <param index="0" name="tab_idx" type="int" />
+ <param index="1" name="disabled" type="bool" />
<description>
- If [code]disabled[/code] is [code]true[/code], disables the tab at index [code]tab_idx[/code], making it non-interactable.
+ If [param disabled] is [code]true[/code], disables the tab at index [param tab_idx], making it non-interactable.
</description>
</method>
<method name="set_tab_hidden">
<return type="void" />
- <argument index="0" name="tab_idx" type="int" />
- <argument index="1" name="hidden" type="bool" />
+ <param index="0" name="tab_idx" type="int" />
+ <param index="1" name="hidden" type="bool" />
<description>
- If [code]hidden[/code] is [code]true[/code], hides the tab at index [code]tab_idx[/code], making it disappear from the tab area.
+ If [param hidden] is [code]true[/code], hides the tab at index [param tab_idx], making it disappear from the tab area.
</description>
</method>
<method name="set_tab_icon">
<return type="void" />
- <argument index="0" name="tab_idx" type="int" />
- <argument index="1" name="icon" type="Texture2D" />
+ <param index="0" name="tab_idx" type="int" />
+ <param index="1" name="icon" type="Texture2D" />
<description>
- Sets an icon for the tab at index [code]tab_idx[/code].
+ Sets an icon for the tab at index [param tab_idx].
</description>
</method>
<method name="set_tab_title">
<return type="void" />
- <argument index="0" name="tab_idx" type="int" />
- <argument index="1" name="title" type="String" />
+ <param index="0" name="tab_idx" type="int" />
+ <param index="1" name="title" type="String" />
<description>
- Sets a custom title for the tab at index [code]tab_idx[/code] (tab titles default to the name of the indexed child node). Set it back to the child's name to make the tab default to it again.
+ Sets a custom title for the tab at index [param tab_idx] (tab titles default to the name of the indexed child node). Set it back to the child's name to make the tab default to it again.
</description>
</method>
</methods>
@@ -175,19 +175,19 @@
</description>
</signal>
<signal name="tab_button_pressed">
- <argument index="0" name="tab" type="int" />
+ <param index="0" name="tab" type="int" />
<description>
Emitted when the user clicks on the button icon on this tab.
</description>
</signal>
<signal name="tab_changed">
- <argument index="0" name="tab" type="int" />
+ <param index="0" name="tab" type="int" />
<description>
Emitted when switching to another tab.
</description>
</signal>
<signal name="tab_selected">
- <argument index="0" name="tab" type="int" />
+ <param index="0" name="tab" type="int" />
<description>
Emitted when a tab is selected, even if it is the current tab.
</description>
diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml
index 18a4893f03..aa7ce85f3a 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -30,9 +30,9 @@
</method>
<method name="_handle_unicode_input" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="unicode_char" type="int" />
+ <param index="0" name="unicode_char" type="int" />
<description>
- Override this method to define what happens when the types in the provided key [code]unicode[/code].
+ Override this method to define what happens when the user types in the provided key [param unicode_char].
</description>
</method>
<method name="_paste" qualifiers="virtual">
@@ -50,9 +50,9 @@
</method>
<method name="add_gutter">
<return type="void" />
- <argument index="0" name="at" type="int" default="-1" />
+ <param index="0" name="at" type="int" default="-1" />
<description>
- Register a new gutter to this [TextEdit]. Use [code]at[/code] to have a specific gutter order. A value of [code]-1[/code] appends the gutter to the right.
+ Register a new gutter to this [TextEdit]. Use [param at] to have a specific gutter order. A value of [code]-1[/code] appends the gutter to the right.
</description>
</method>
<method name="adjust_viewport_to_caret">
@@ -147,7 +147,7 @@
</method>
<method name="get_first_non_whitespace_column" qualifiers="const">
<return type="int" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns the first column containing a non-whitespace character.
</description>
@@ -161,35 +161,35 @@
<method name="get_gutter_count" qualifiers="const">
<return type="int" />
<description>
- Returns the total amount of gutters registered.
+ Returns the number of gutters registered.
</description>
</method>
<method name="get_gutter_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="gutter" type="int" />
+ <param index="0" name="gutter" type="int" />
<description>
Returns the name of the gutter at the given index.
</description>
</method>
<method name="get_gutter_type" qualifiers="const">
<return type="int" enum="TextEdit.GutterType" />
- <argument index="0" name="gutter" type="int" />
+ <param index="0" name="gutter" type="int" />
<description>
Returns the type of the gutter at the given index.
</description>
</method>
<method name="get_gutter_width" qualifiers="const">
<return type="int" />
- <argument index="0" name="gutter" type="int" />
+ <param index="0" name="gutter" type="int" />
<description>
Returns the width of the gutter at the given index.
</description>
</method>
<method name="get_indent_level" qualifiers="const">
<return type="int" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
- Returns the amount of spaces and [code]tab * tab_size[/code] before the first char.
+ Returns the number of spaces and [code]tab * tab_size[/code] before the first char.
</description>
</method>
<method name="get_last_full_visible_line" qualifiers="const">
@@ -212,62 +212,62 @@
</method>
<method name="get_line" qualifiers="const">
<return type="String" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns the text of a specific line.
</description>
</method>
<method name="get_line_background_color" qualifiers="const">
<return type="Color" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns the current background color of the line. [code]Color(0, 0, 0, 0)[/code] is returned if no color is set.
</description>
</method>
<method name="get_line_column_at_pos" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="position" type="Vector2i" />
- <argument index="1" name="allow_out_of_bounds" type="bool" default="true" />
+ <param index="0" name="position" type="Vector2i" />
+ <param index="1" name="allow_out_of_bounds" type="bool" default="true" />
<description>
- Returns the line and column at the given position. In the returned vector, [code]x[/code] is the column, [code]y[/code] is the line. If [code]allow_out_of_bounds[/code] is [code]false[/code] and the position is not over the text, both vector values will be set to [code]-1[/code].
+ Returns the line and column at the given position. In the returned vector, [code]x[/code] is the column, [code]y[/code] is the line. If [param allow_out_of_bounds] is [code]false[/code] and the position is not over the text, both vector values will be set to [code]-1[/code].
</description>
</method>
<method name="get_line_count" qualifiers="const">
<return type="int" />
<description>
- Returns the amount of total lines in the text.
+ Returns the number of lines in the text.
</description>
</method>
<method name="get_line_gutter_icon" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="gutter" type="int" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="gutter" type="int" />
<description>
- Returns the icon currently in [code]gutter[/code] at [code]line[/code].
+ Returns the icon currently in [param gutter] at [param line].
</description>
</method>
<method name="get_line_gutter_item_color" qualifiers="const">
<return type="Color" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="gutter" type="int" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="gutter" type="int" />
<description>
- Returns the color currently in [code]gutter[/code] at [code]line[/code].
+ Returns the color currently in [param gutter] at [param line].
</description>
</method>
<method name="get_line_gutter_metadata" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="gutter" type="int" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="gutter" type="int" />
<description>
- Returns the metadata currently in [code]gutter[/code] at [code]line[/code].
+ Returns the metadata currently in [param gutter] at [param line].
</description>
</method>
<method name="get_line_gutter_text" qualifiers="const">
<return type="String" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="gutter" type="int" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="gutter" type="int" />
<description>
- Returns the text currently in [code]gutter[/code] at [code]line[/code].
+ Returns the text currently in [param gutter] at [param line].
</description>
</method>
<method name="get_line_height" qualifiers="const">
@@ -278,30 +278,30 @@
</method>
<method name="get_line_width" qualifiers="const">
<return type="int" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="wrap_index" type="int" default="-1" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="wrap_index" type="int" default="-1" />
<description>
- Returns the width in pixels of the [code]wrap_index[/code] on [code]line[/code].
+ Returns the width in pixels of the [param wrap_index] on [param line].
</description>
</method>
<method name="get_line_wrap_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns the number of times the given line is wrapped.
</description>
</method>
<method name="get_line_wrap_index_at_column" qualifiers="const">
<return type="int" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="column" type="int" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="column" type="int" />
<description>
Returns the wrap index of the given line column.
</description>
</method>
<method name="get_line_wrapped_text" qualifiers="const">
<return type="PackedStringArray" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns an array of [String]s representing each wrapped index.
</description>
@@ -321,49 +321,49 @@
</method>
<method name="get_minimap_line_at_pos" qualifiers="const">
<return type="int" />
- <argument index="0" name="position" type="Vector2i" />
+ <param index="0" name="position" type="Vector2i" />
<description>
- Returns the equivalent minimap line at [code]position[/code]
+ Returns the equivalent minimap line at [param position]
</description>
</method>
<method name="get_minimap_visible_lines" qualifiers="const">
<return type="int" />
<description>
- Returns the total amount of lines that can be draw on the minimap.
+ Returns the number of lines that may be drawn on the minimap.
</description>
</method>
<method name="get_next_visible_line_index_offset_from" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="wrap_index" type="int" />
- <argument index="2" name="visible_amount" type="int" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="wrap_index" type="int" />
+ <param index="2" name="visible_amount" type="int" />
<description>
Similar to [method get_next_visible_line_offset_from], but takes into account the line wrap indexes. In the returned vector, [code]x[/code] is the line, [code]y[/code] is the wrap index.
</description>
</method>
<method name="get_next_visible_line_offset_from" qualifiers="const">
<return type="int" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="visible_amount" type="int" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="visible_amount" type="int" />
<description>
- Returns the count to the next visible line from [code]line[/code] to [code]line + visible_amount[/code]. Can also count backwards. For example if a [TextEdit] has 5 lines with lines 2 and 3 hidden, calling this with [code]line = 1, visible_amount = 1[/code] would return 3.
+ Returns the count to the next visible line from [param line] to [code]line + visible_amount[/code]. Can also count backwards. For example if a [TextEdit] has 5 lines with lines 2 and 3 hidden, calling this with [code]line = 1, visible_amount = 1[/code] would return 3.
</description>
</method>
<method name="get_pos_at_line_column" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="column" type="int" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="column" type="int" />
<description>
- Returns the local position for the given [code]line[/code] and [code]column[/code]. If [code]x[/code] or [code]y[/code] of the returned vector equal [code]-1[/code], the position is outside of the viewable area of the control.
+ Returns the local position for the given [param line] and [param column]. If [code]x[/code] or [code]y[/code] of the returned vector equal [code]-1[/code], the position is outside of the viewable area of the control.
[b]Note:[/b] The Y position corresponds to the bottom side of the line. Use [method get_rect_at_line_column] to get the top side position.
</description>
</method>
<method name="get_rect_at_line_column" qualifiers="const">
<return type="Rect2i" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="column" type="int" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="column" type="int" />
<description>
- Returns the local position and size for the grapheme at the given [code]line[/code] and [code]column[/code]. If [code]x[/code] or [code]y[/code] position of the returned rect equal [code]-1[/code], the position is outside of the viewable area of the control.
+ Returns the local position and size for the grapheme at the given [param line] and [param column]. If [code]x[/code] or [code]y[/code] position of the returned rect equal [code]-1[/code], the position is outside of the viewable area of the control.
[b]Note:[/b] The Y position of the returned rect corresponds to the top side of the line, unlike [method get_pos_at_line_column] which returns the bottom side.
</description>
</method>
@@ -375,10 +375,10 @@
</method>
<method name="get_scroll_pos_for_line" qualifiers="const">
<return type="float" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="wrap_index" type="int" default="0" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="wrap_index" type="int" default="0" />
<description>
- Returns the scroll position for [code]wrap_index[/code] of [code]line[/code].
+ Returns the scroll position for [param wrap_index] of [param line].
</description>
</method>
<method name="get_selected_text" qualifiers="const">
@@ -444,7 +444,7 @@
<method name="get_total_visible_line_count" qualifiers="const">
<return type="int" />
<description>
- Returns the total amount of lines that could be draw.
+ Returns the number of lines that may be drawn.
</description>
</method>
<method name="get_version" qualifiers="const">
@@ -461,17 +461,17 @@
</method>
<method name="get_visible_line_count_in_range" qualifiers="const">
<return type="int" />
- <argument index="0" name="from_line" type="int" />
- <argument index="1" name="to_line" type="int" />
+ <param index="0" name="from_line" type="int" />
+ <param index="1" name="to_line" type="int" />
<description>
Returns the total number of visible + wrapped lines between the two lines.
</description>
</method>
<method name="get_word_at_pos" qualifiers="const">
<return type="String" />
- <argument index="0" name="position" type="Vector2" />
+ <param index="0" name="position" type="Vector2" />
<description>
- Returns the word at [code]position[/code].
+ Returns the word at [param position].
</description>
</method>
<method name="get_word_under_caret" qualifiers="const">
@@ -506,15 +506,15 @@
</method>
<method name="insert_line_at">
<return type="void" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="text" type="String" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="text" type="String" />
<description>
- Inserts a new line with [code]text[/code] at [code]line[/code].
+ Inserts a new line with [param text] at [param line].
</description>
</method>
<method name="insert_text_at_caret">
<return type="void" />
- <argument index="0" name="text" type="String" />
+ <param index="0" name="text" type="String" />
<description>
Insert the specified text at the caret position.
</description>
@@ -533,36 +533,36 @@
</method>
<method name="is_gutter_clickable" qualifiers="const">
<return type="bool" />
- <argument index="0" name="gutter" type="int" />
+ <param index="0" name="gutter" type="int" />
<description>
Returns whether the gutter is clickable.
</description>
</method>
<method name="is_gutter_drawn" qualifiers="const">
<return type="bool" />
- <argument index="0" name="gutter" type="int" />
+ <param index="0" name="gutter" type="int" />
<description>
Returns whether the gutter is currently drawn.
</description>
</method>
<method name="is_gutter_overwritable" qualifiers="const">
<return type="bool" />
- <argument index="0" name="gutter" type="int" />
+ <param index="0" name="gutter" type="int" />
<description>
Returns whether the gutter is overwritable.
</description>
</method>
<method name="is_line_gutter_clickable" qualifiers="const">
<return type="bool" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="gutter" type="int" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="gutter" type="int" />
<description>
Returns whether the gutter on the given line is clickable.
</description>
</method>
<method name="is_line_wrapped" qualifiers="const">
<return type="bool" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns if the given line is wrapped.
</description>
@@ -575,9 +575,9 @@
</method>
<method name="is_mouse_over_selection" qualifiers="const">
<return type="bool" />
- <argument index="0" name="edges" type="bool" />
+ <param index="0" name="edges" type="bool" />
<description>
- Returns whether the mouse is over selection. If [code]edges[/code] is [code]true[/code], the edges are considered part of the selection.
+ Returns whether the mouse is over selection. If [param edges] is [code]true[/code], the edges are considered part of the selection.
</description>
</method>
<method name="is_overtype_mode_enabled" qualifiers="const">
@@ -588,17 +588,17 @@
</method>
<method name="menu_option">
<return type="void" />
- <argument index="0" name="option" type="int" />
+ <param index="0" name="option" type="int" />
<description>
Triggers a right-click menu action by the specified index. See [enum MenuItems] for a list of available indexes.
</description>
</method>
<method name="merge_gutters">
<return type="void" />
- <argument index="0" name="from_line" type="int" />
- <argument index="1" name="to_line" type="int" />
+ <param index="0" name="from_line" type="int" />
+ <param index="1" name="to_line" type="int" />
<description>
- Merge the gutters from [code]from_line[/code] into [code]to_line[/code]. Only overwritable gutters will be copied.
+ Merge the gutters from [param from_line] into [param to_line]. Only overwritable gutters will be copied.
</description>
</method>
<method name="paste">
@@ -615,17 +615,17 @@
</method>
<method name="remove_gutter">
<return type="void" />
- <argument index="0" name="gutter" type="int" />
+ <param index="0" name="gutter" type="int" />
<description>
Removes the gutter from this [TextEdit].
</description>
</method>
<method name="remove_text">
<return type="void" />
- <argument index="0" name="from_line" type="int" />
- <argument index="1" name="from_column" type="int" />
- <argument index="2" name="to_line" type="int" />
- <argument index="3" name="to_column" type="int" />
+ <param index="0" name="from_line" type="int" />
+ <param index="1" name="from_column" type="int" />
+ <param index="2" name="to_line" type="int" />
+ <param index="3" name="to_column" type="int" />
<description>
Removes text between the given positions.
[b]Note:[/b] This does not adjust the caret or selection, which as a result it can end up in an invalid position.
@@ -633,10 +633,10 @@
</method>
<method name="search" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="text" type="String" />
- <argument index="1" name="flags" type="int" />
- <argument index="2" name="from_line" type="int" />
- <argument index="3" name="from_colum" type="int" />
+ <param index="0" name="text" type="String" />
+ <param index="1" name="flags" type="int" />
+ <param index="2" name="from_line" type="int" />
+ <param index="3" name="from_colum" type="int" />
<description>
Perform a search inside the text. Search flags can be specified in the [enum SearchFlags] enum.
In the returned vector, [code]x[/code] is the column, [code]y[/code] is the line. If no results are found, both are equal to [code]-1[/code].
@@ -662,10 +662,10 @@
</method>
<method name="select">
<return type="void" />
- <argument index="0" name="from_line" type="int" />
- <argument index="1" name="from_column" type="int" />
- <argument index="2" name="to_line" type="int" />
- <argument index="3" name="to_column" type="int" />
+ <param index="0" name="from_line" type="int" />
+ <param index="1" name="from_column" type="int" />
+ <param index="2" name="to_line" type="int" />
+ <param index="3" name="to_column" type="int" />
<description>
Perform selection, from line/column to line/column.
If [member selecting_enabled] is [code]false[/code], no selection will occur.
@@ -686,214 +686,214 @@
</method>
<method name="set_caret_column">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="adjust_viewport" type="bool" default="true" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="adjust_viewport" type="bool" default="true" />
<description>
- Moves the caret to the specified [code]column[/code] index.
- If [code]adjust_viewport[/code] is [code]true[/code], the viewport will center at the caret position after the move occurs.
+ Moves the caret to the specified [param column] index.
+ If [param adjust_viewport] is [code]true[/code], the viewport will center at the caret position after the move occurs.
</description>
</method>
<method name="set_caret_line">
<return type="void" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="adjust_viewport" type="bool" default="true" />
- <argument index="2" name="can_be_hidden" type="bool" default="true" />
- <argument index="3" name="wrap_index" type="int" default="0" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="adjust_viewport" type="bool" default="true" />
+ <param index="2" name="can_be_hidden" type="bool" default="true" />
+ <param index="3" name="wrap_index" type="int" default="0" />
<description>
- Moves the caret to the specified [code]line[/code] index.
- If [code]adjust_viewport[/code] is [code]true[/code], the viewport will center at the caret position after the move occurs.
- If [code]can_be_hidden[/code] is [code]true[/code], the specified [code]line[/code] can be hidden.
+ Moves the caret to the specified [param line] index.
+ If [param adjust_viewport] is [code]true[/code], the viewport will center at the caret position after the move occurs.
+ If [param can_be_hidden] is [code]true[/code], the specified [code]line[/code] can be hidden.
</description>
</method>
<method name="set_gutter_clickable">
<return type="void" />
- <argument index="0" name="gutter" type="int" />
- <argument index="1" name="clickable" type="bool" />
+ <param index="0" name="gutter" type="int" />
+ <param index="1" name="clickable" type="bool" />
<description>
Sets the gutter as clickable. This will change the mouse cursor to a pointing hand when hovering over the gutter.
</description>
</method>
<method name="set_gutter_custom_draw">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="draw_callback" type="Callable" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="draw_callback" type="Callable" />
<description>
Set a custom draw method for the gutter. The callback method must take the following args: [code]line: int, gutter: int, Area: Rect2[/code].
</description>
</method>
<method name="set_gutter_draw">
<return type="void" />
- <argument index="0" name="gutter" type="int" />
- <argument index="1" name="draw" type="bool" />
+ <param index="0" name="gutter" type="int" />
+ <param index="1" name="draw" type="bool" />
<description>
Sets whether the gutter should be drawn.
</description>
</method>
<method name="set_gutter_name">
<return type="void" />
- <argument index="0" name="gutter" type="int" />
- <argument index="1" name="name" type="String" />
+ <param index="0" name="gutter" type="int" />
+ <param index="1" name="name" type="String" />
<description>
Sets the name of the gutter.
</description>
</method>
<method name="set_gutter_overwritable">
<return type="void" />
- <argument index="0" name="gutter" type="int" />
- <argument index="1" name="overwritable" type="bool" />
+ <param index="0" name="gutter" type="int" />
+ <param index="1" name="overwritable" type="bool" />
<description>
Sets the gutter to overwritable. See [method merge_gutters].
</description>
</method>
<method name="set_gutter_type">
<return type="void" />
- <argument index="0" name="gutter" type="int" />
- <argument index="1" name="type" type="int" enum="TextEdit.GutterType" />
+ <param index="0" name="gutter" type="int" />
+ <param index="1" name="type" type="int" enum="TextEdit.GutterType" />
<description>
Sets the type of gutter.
</description>
</method>
<method name="set_gutter_width">
<return type="void" />
- <argument index="0" name="gutter" type="int" />
- <argument index="1" name="width" type="int" />
+ <param index="0" name="gutter" type="int" />
+ <param index="1" name="width" type="int" />
<description>
Set the width of the gutter.
</description>
</method>
<method name="set_line">
<return type="void" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="new_text" type="String" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="new_text" type="String" />
<description>
Sets the text for a specific line.
</description>
</method>
<method name="set_line_as_center_visible">
<return type="void" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="wrap_index" type="int" default="0" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="wrap_index" type="int" default="0" />
<description>
- Positions the [code]wrap_index[/code] of [code]line[/code] at the center of the viewport.
+ Positions the [param wrap_index] of [param line] at the center of the viewport.
</description>
</method>
<method name="set_line_as_first_visible">
<return type="void" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="wrap_index" type="int" default="0" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="wrap_index" type="int" default="0" />
<description>
- Positions the [code]wrap_index[/code] of [code]line[/code] at the top of the viewport.
+ Positions the [param wrap_index] of [param line] at the top of the viewport.
</description>
</method>
<method name="set_line_as_last_visible">
<return type="void" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="wrap_index" type="int" default="0" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="wrap_index" type="int" default="0" />
<description>
- Positions the [code]wrap_index[/code] of [code]line[/code] at the bottom of the viewport.
+ Positions the [param wrap_index] of [param line] at the bottom of the viewport.
</description>
</method>
<method name="set_line_background_color">
<return type="void" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="color" type="Color" />
<description>
Sets the current background color of the line. Set to [code]Color(0, 0, 0, 0)[/code] for no color.
</description>
</method>
<method name="set_line_gutter_clickable">
<return type="void" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="gutter" type="int" />
- <argument index="2" name="clickable" type="bool" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="gutter" type="int" />
+ <param index="2" name="clickable" type="bool" />
<description>
- Sets the [code]gutter[/code] on [code]line[/code] as clickable.
+ If [param clickable] is [code]true[/code], makes the [param gutter] on [param line] clickable. See [signal gutter_clicked].
</description>
</method>
<method name="set_line_gutter_icon">
<return type="void" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="gutter" type="int" />
- <argument index="2" name="icon" type="Texture2D" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="gutter" type="int" />
+ <param index="2" name="icon" type="Texture2D" />
<description>
- Sets the icon for [code]gutter[/code] on [code]line[/code].
+ Sets the icon for [param gutter] on [param line] to [param icon].
</description>
</method>
<method name="set_line_gutter_item_color">
<return type="void" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="gutter" type="int" />
- <argument index="2" name="color" type="Color" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="gutter" type="int" />
+ <param index="2" name="color" type="Color" />
<description>
- Sets the color for [code]gutter[/code] on [code]line[/code].
+ Sets the color for [param gutter] on [param line] to [param color].
</description>
</method>
<method name="set_line_gutter_metadata">
<return type="void" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="gutter" type="int" />
- <argument index="2" name="metadata" type="Variant" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="gutter" type="int" />
+ <param index="2" name="metadata" type="Variant" />
<description>
- Sets the metadata for [code]gutter[/code] on [code]line[/code].
+ Sets the metadata for [param gutter] on [param line] to [param metadata].
</description>
</method>
<method name="set_line_gutter_text">
<return type="void" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="gutter" type="int" />
- <argument index="2" name="text" type="String" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="gutter" type="int" />
+ <param index="2" name="text" type="String" />
<description>
- Sets the text for [code]gutter[/code] on [code]line[/code].
+ Sets the text for [param gutter] on [param line] to [param text].
</description>
</method>
<method name="set_overtype_mode_enabled">
<return type="void" />
- <argument index="0" name="enabled" type="bool" />
+ <param index="0" name="enabled" type="bool" />
<description>
If [code]true[/code], sets the user into overtype mode. When the user types in this mode, it will override existing text.
</description>
</method>
<method name="set_search_flags">
<return type="void" />
- <argument index="0" name="flags" type="int" />
+ <param index="0" name="flags" type="int" />
<description>
- Sets the search flags. This is used with [method set_search_text] to highlight occurrences of the searched text. Search flags can be specified from the [enum SearchFlags] enum.
+ Sets the search [param flags]. This is used with [method set_search_text] to highlight occurrences of the searched text. Search flags can be specified from the [enum SearchFlags] enum.
</description>
</method>
<method name="set_search_text">
<return type="void" />
- <argument index="0" name="search_text" type="String" />
+ <param index="0" name="search_text" type="String" />
<description>
Sets the search text. See [method set_search_flags].
</description>
</method>
<method name="set_selection_mode">
<return type="void" />
- <argument index="0" name="mode" type="int" enum="TextEdit.SelectionMode" />
- <argument index="1" name="line" type="int" default="-1" />
- <argument index="2" name="column" type="int" default="-1" />
+ <param index="0" name="mode" type="int" enum="TextEdit.SelectionMode" />
+ <param index="1" name="line" type="int" default="-1" />
+ <param index="2" name="column" type="int" default="-1" />
<description>
Sets the current selection mode.
</description>
</method>
<method name="set_tab_size">
<return type="void" />
- <argument index="0" name="size" type="int" />
+ <param index="0" name="size" type="int" />
<description>
Sets the tab size for the [TextEdit] to use.
</description>
</method>
<method name="set_tooltip_request_func">
<return type="void" />
- <argument index="0" name="callback" type="Callable" />
+ <param index="0" name="callback" type="Callable" />
<description>
Provide custom tooltip text. The callback method must take the following args: [code]hovered_word: String[/code]
</description>
</method>
<method name="swap_lines">
<return type="void" />
- <argument index="0" name="from_line" type="int" />
- <argument index="1" name="to_line" type="int" />
+ <param index="0" name="from_line" type="int" />
+ <param index="1" name="to_line" type="int" />
<description>
Swaps the two lines.
</description>
@@ -1036,8 +1036,8 @@
</description>
</signal>
<signal name="gutter_clicked">
- <argument index="0" name="line" type="int" />
- <argument index="1" name="gutter" type="int" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="gutter" type="int" />
<description>
Emitted when a gutter is clicked.
</description>
@@ -1048,11 +1048,11 @@
</description>
</signal>
<signal name="lines_edited_from">
- <argument index="0" name="from_line" type="int" />
- <argument index="1" name="to_line" type="int" />
+ <param index="0" name="from_line" type="int" />
+ <param index="1" name="to_line" type="int" />
<description>
Emitted immediately when the text changes.
- When text is added [code]from_line[/code] will be less then [code]to_line[/code]. On a remove [code]to_line[/code] will be less then [code]from_line[/code].
+ When text is added [param from_line] will be less then [param to_line]. On a remove [param to_line] will be less then [param from_line].
</description>
</signal>
<signal name="text_changed">
diff --git a/doc/classes/TextLine.xml b/doc/classes/TextLine.xml
index 601650db2e..471c1a9040 100644
--- a/doc/classes/TextLine.xml
+++ b/doc/classes/TextLine.xml
@@ -11,21 +11,21 @@
<methods>
<method name="add_object">
<return type="bool" />
- <argument index="0" name="key" type="Variant" />
- <argument index="1" name="size" type="Vector2" />
- <argument index="2" name="inline_align" type="int" enum="InlineAlignment" default="5" />
- <argument index="3" name="length" type="int" default="1" />
+ <param index="0" name="key" type="Variant" />
+ <param index="1" name="size" type="Vector2" />
+ <param index="2" name="inline_align" type="int" enum="InlineAlignment" default="5" />
+ <param index="3" name="length" type="int" default="1" />
<description>
- Adds inline object to the text buffer, [code]key[/code] must be unique. In the text, object is represented as [code]length[/code] object replacement characters.
+ Adds inline object to the text buffer, [param key] must be unique. In the text, object is represented as [param length] object replacement characters.
</description>
</method>
<method name="add_string">
<return type="bool" />
- <argument index="0" name="text" type="String" />
- <argument index="1" name="font" type="Font" />
- <argument index="2" name="font_size" type="int" />
- <argument index="3" name="language" type="String" default="&quot;&quot;" />
- <argument index="4" name="meta" type="Variant" default="null" />
+ <param index="0" name="text" type="String" />
+ <param index="1" name="font" type="Font" />
+ <param index="2" name="font_size" type="int" />
+ <param index="3" name="language" type="String" default="&quot;&quot;" />
+ <param index="4" name="meta" type="Variant" default="null" />
<description>
Adds text span and font to draw it.
</description>
@@ -38,21 +38,21 @@
</method>
<method name="draw" qualifiers="const">
<return type="void" />
- <argument index="0" name="canvas" type="RID" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="color" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="0" name="canvas" type="RID" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="color" type="Color" default="Color(1, 1, 1, 1)" />
<description>
- Draw text into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box.
+ Draw text into a canvas item at a given position, with [param color]. [param pos] specifies the top left corner of the bounding box.
</description>
</method>
<method name="draw_outline" qualifiers="const">
<return type="void" />
- <argument index="0" name="canvas" type="RID" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="outline_size" type="int" default="1" />
- <argument index="3" name="color" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="0" name="canvas" type="RID" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="outline_size" type="int" default="1" />
+ <param index="3" name="color" type="Color" default="Color(1, 1, 1, 1)" />
<description>
- Draw text into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box.
+ Draw text into a canvas item at a given position, with [param color]. [param pos] specifies the top left corner of the bounding box.
</description>
</method>
<method name="get_line_ascent" qualifiers="const">
@@ -87,7 +87,7 @@
</method>
<method name="get_object_rect" qualifiers="const">
<return type="Rect2" />
- <argument index="0" name="key" type="Variant" />
+ <param index="0" name="key" type="Variant" />
<description>
Returns bounding rectangle of the inline object.
</description>
@@ -112,23 +112,23 @@
</method>
<method name="hit_test" qualifiers="const">
<return type="int" />
- <argument index="0" name="coords" type="float" />
+ <param index="0" name="coords" type="float" />
<description>
Returns caret character offset at the specified pixel offset at the baseline. This function always returns a valid position.
</description>
</method>
<method name="resize_object">
<return type="bool" />
- <argument index="0" name="key" type="Variant" />
- <argument index="1" name="size" type="Vector2" />
- <argument index="2" name="inline_align" type="int" enum="InlineAlignment" default="5" />
+ <param index="0" name="key" type="Variant" />
+ <param index="1" name="size" type="Vector2" />
+ <param index="2" name="inline_align" type="int" enum="InlineAlignment" default="5" />
<description>
Sets new size and alignment of embedded object.
</description>
</method>
<method name="set_bidi_override">
<return type="void" />
- <argument index="0" name="override" type="Array" />
+ <param index="0" name="override" type="Array" />
<description>
Overrides BiDi for the structured text.
Override ranges should cover full source text without overlaps. BiDi algorithm will be used on each range separately.
@@ -136,7 +136,7 @@
</method>
<method name="tab_align">
<return type="void" />
- <argument index="0" name="tab_stops" type="PackedFloat32Array" />
+ <param index="0" name="tab_stops" type="PackedFloat32Array" />
<description>
Aligns text to the given tab-stops.
</description>
diff --git a/doc/classes/TextMesh.xml b/doc/classes/TextMesh.xml
index 17a0ca32e4..678b95cc72 100644
--- a/doc/classes/TextMesh.xml
+++ b/doc/classes/TextMesh.xml
@@ -11,6 +11,9 @@
<tutorials>
</tutorials>
<members>
+ <member name="autowrap_mode" type="int" setter="set_autowrap_mode" getter="get_autowrap_mode" enum="TextServer.AutowrapMode" default="0">
+ If set to something other than [constant TextServer.AUTOWRAP_OFF], the text gets wrapped inside the node's bounding rectangle. If you resize the node, it will change its height automatically to show all the text. To see how each mode behaves, see [enum TextServer.AutowrapMode].
+ </member>
<member name="curve_step" type="float" setter="set_curve_step" getter="get_curve_step" default="0.5">
Step (in pixels) used to approximate Bézier curves.
</member>
@@ -29,6 +32,12 @@
<member name="language" type="String" setter="set_language" getter="get_language" default="&quot;&quot;">
Language code used for text shaping algorithms, if left empty current locale is used instead.
</member>
+ <member name="line_spacing" type="float" setter="set_line_spacing" getter="get_line_spacing" default="0.0">
+ Vertical space between lines in multiline [TextMesh].
+ </member>
+ <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2(0, 0)">
+ The text drawing offset (in pixels).
+ </member>
<member name="pixel_size" type="float" setter="set_pixel_size" getter="get_pixel_size" default="0.01">
The size of one pixel's width on the text to scale it in 3D.
</member>
@@ -47,6 +56,9 @@
<member name="uppercase" type="bool" setter="set_uppercase" getter="is_uppercase" default="false">
If [code]true[/code], all the text displays as UPPERCASE.
</member>
+ <member name="vertical_alignment" type="int" setter="set_vertical_alignment" getter="get_vertical_alignment" enum="VerticalAlignment" default="1">
+ Controls the text's vertical alignment. Supports top, center, bottom. Set it to one of the [enum VerticalAlignment] constants.
+ </member>
<member name="width" type="float" setter="set_width" getter="get_width" default="500.0">
Text width (in pixels), used for fill alignment.
</member>
diff --git a/doc/classes/TextParagraph.xml b/doc/classes/TextParagraph.xml
index c733d8fcee..e0729ba844 100644
--- a/doc/classes/TextParagraph.xml
+++ b/doc/classes/TextParagraph.xml
@@ -11,21 +11,21 @@
<methods>
<method name="add_object">
<return type="bool" />
- <argument index="0" name="key" type="Variant" />
- <argument index="1" name="size" type="Vector2" />
- <argument index="2" name="inline_align" type="int" enum="InlineAlignment" default="5" />
- <argument index="3" name="length" type="int" default="1" />
+ <param index="0" name="key" type="Variant" />
+ <param index="1" name="size" type="Vector2" />
+ <param index="2" name="inline_align" type="int" enum="InlineAlignment" default="5" />
+ <param index="3" name="length" type="int" default="1" />
<description>
- Adds inline object to the text buffer, [code]key[/code] must be unique. In the text, object is represented as [code]length[/code] object replacement characters.
+ Adds inline object to the text buffer, [param key] must be unique. In the text, object is represented as [param length] object replacement characters.
</description>
</method>
<method name="add_string">
<return type="bool" />
- <argument index="0" name="text" type="String" />
- <argument index="1" name="font" type="Font" />
- <argument index="2" name="font_size" type="int" />
- <argument index="3" name="language" type="String" default="&quot;&quot;" />
- <argument index="4" name="meta" type="Variant" default="null" />
+ <param index="0" name="text" type="String" />
+ <param index="1" name="font" type="Font" />
+ <param index="2" name="font_size" type="int" />
+ <param index="3" name="language" type="String" default="&quot;&quot;" />
+ <param index="4" name="meta" type="Variant" default="null" />
<description>
Adds text span and font to draw it.
</description>
@@ -44,63 +44,63 @@
</method>
<method name="draw" qualifiers="const">
<return type="void" />
- <argument index="0" name="canvas" type="RID" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="color" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="3" name="dc_color" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="0" name="canvas" type="RID" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="color" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="3" name="dc_color" type="Color" default="Color(1, 1, 1, 1)" />
<description>
- Draw all lines of the text and drop cap into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box.
+ Draw all lines of the text and drop cap into a canvas item at a given position, with [param color]. [param pos] specifies the top left corner of the bounding box.
</description>
</method>
<method name="draw_dropcap" qualifiers="const">
<return type="void" />
- <argument index="0" name="canvas" type="RID" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="color" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="0" name="canvas" type="RID" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="color" type="Color" default="Color(1, 1, 1, 1)" />
<description>
- Draw drop cap into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box.
+ Draw drop cap into a canvas item at a given position, with [param color]. [param pos] specifies the top left corner of the bounding box.
</description>
</method>
<method name="draw_dropcap_outline" qualifiers="const">
<return type="void" />
- <argument index="0" name="canvas" type="RID" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="outline_size" type="int" default="1" />
- <argument index="3" name="color" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="0" name="canvas" type="RID" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="outline_size" type="int" default="1" />
+ <param index="3" name="color" type="Color" default="Color(1, 1, 1, 1)" />
<description>
- Draw drop cap outline into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box.
+ Draw drop cap outline into a canvas item at a given position, with [param color]. [param pos] specifies the top left corner of the bounding box.
</description>
</method>
<method name="draw_line" qualifiers="const">
<return type="void" />
- <argument index="0" name="canvas" type="RID" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="line" type="int" />
- <argument index="3" name="color" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="0" name="canvas" type="RID" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="line" type="int" />
+ <param index="3" name="color" type="Color" default="Color(1, 1, 1, 1)" />
<description>
- Draw single line of text into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box.
+ Draw single line of text into a canvas item at a given position, with [param color]. [param pos] specifies the top left corner of the bounding box.
</description>
</method>
<method name="draw_line_outline" qualifiers="const">
<return type="void" />
- <argument index="0" name="canvas" type="RID" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="line" type="int" />
- <argument index="3" name="outline_size" type="int" default="1" />
- <argument index="4" name="color" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="0" name="canvas" type="RID" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="line" type="int" />
+ <param index="3" name="outline_size" type="int" default="1" />
+ <param index="4" name="color" type="Color" default="Color(1, 1, 1, 1)" />
<description>
- Draw outline of the single line of text into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box.
+ Draw outline of the single line of text into a canvas item at a given position, with [param color]. [param pos] specifies the top left corner of the bounding box.
</description>
</method>
<method name="draw_outline" qualifiers="const">
<return type="void" />
- <argument index="0" name="canvas" type="RID" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="outline_size" type="int" default="1" />
- <argument index="3" name="color" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="4" name="dc_color" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="0" name="canvas" type="RID" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="outline_size" type="int" default="1" />
+ <param index="3" name="color" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="4" name="dc_color" type="Color" default="Color(1, 1, 1, 1)" />
<description>
- Draw outlines of all lines of the text and drop cap into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box.
+ Draw outlines of all lines of the text and drop cap into a canvas item at a given position, with [param color]. [param pos] specifies the top left corner of the bounding box.
</description>
</method>
<method name="get_dropcap_lines" qualifiers="const">
@@ -123,7 +123,7 @@
</method>
<method name="get_line_ascent" qualifiers="const">
<return type="float" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns the text line ascent (number of pixels above the baseline for horizontal layout or to the left of baseline for vertical).
</description>
@@ -136,64 +136,64 @@
</method>
<method name="get_line_descent" qualifiers="const">
<return type="float" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns the text line descent (number of pixels below the baseline for horizontal layout or to the right of baseline for vertical).
</description>
</method>
<method name="get_line_object_rect" qualifiers="const">
<return type="Rect2" />
- <argument index="0" name="line" type="int" />
- <argument index="1" name="key" type="Variant" />
+ <param index="0" name="line" type="int" />
+ <param index="1" name="key" type="Variant" />
<description>
Returns bounding rectangle of the inline object.
</description>
</method>
<method name="get_line_objects" qualifiers="const">
<return type="Array" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns array of inline objects in the line.
</description>
</method>
<method name="get_line_range" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns character range of the line.
</description>
</method>
<method name="get_line_rid" qualifiers="const">
<return type="RID" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns TextServer line buffer RID.
</description>
</method>
<method name="get_line_size" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns size of the bounding box of the line of text.
</description>
</method>
<method name="get_line_underline_position" qualifiers="const">
<return type="float" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns pixel offset of the underline below the baseline.
</description>
</method>
<method name="get_line_underline_thickness" qualifiers="const">
<return type="float" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns thickness of the underline.
</description>
</method>
<method name="get_line_width" qualifiers="const">
<return type="float" />
- <argument index="0" name="line" type="int" />
+ <param index="0" name="line" type="int" />
<description>
Returns width (for horizontal layout) or height (for vertical) of the line of text.
</description>
@@ -218,23 +218,23 @@
</method>
<method name="hit_test" qualifiers="const">
<return type="int" />
- <argument index="0" name="coords" type="Vector2" />
+ <param index="0" name="coords" type="Vector2" />
<description>
Returns caret character offset at the specified coordinates. This function always returns a valid position.
</description>
</method>
<method name="resize_object">
<return type="bool" />
- <argument index="0" name="key" type="Variant" />
- <argument index="1" name="size" type="Vector2" />
- <argument index="2" name="inline_align" type="int" enum="InlineAlignment" default="5" />
+ <param index="0" name="key" type="Variant" />
+ <param index="1" name="size" type="Vector2" />
+ <param index="2" name="inline_align" type="int" enum="InlineAlignment" default="5" />
<description>
Sets new size and alignment of embedded object.
</description>
</method>
<method name="set_bidi_override">
<return type="void" />
- <argument index="0" name="override" type="Array" />
+ <param index="0" name="override" type="Array" />
<description>
Overrides BiDi for the structured text.
Override ranges should cover full source text without overlaps. BiDi algorithm will be used on each range separately.
@@ -242,18 +242,18 @@
</method>
<method name="set_dropcap">
<return type="bool" />
- <argument index="0" name="text" type="String" />
- <argument index="1" name="font" type="Font" />
- <argument index="2" name="font_size" type="int" />
- <argument index="3" name="dropcap_margins" type="Rect2" default="Rect2(0, 0, 0, 0)" />
- <argument index="4" name="language" type="String" default="&quot;&quot;" />
+ <param index="0" name="text" type="String" />
+ <param index="1" name="font" type="Font" />
+ <param index="2" name="font_size" type="int" />
+ <param index="3" name="dropcap_margins" type="Rect2" default="Rect2(0, 0, 0, 0)" />
+ <param index="4" name="language" type="String" default="&quot;&quot;" />
<description>
Sets drop cap, overrides previously set drop cap. Drop cap (dropped capital) is a decorative element at the beginning of a paragraph that is larger than the rest of the text.
</description>
</method>
<method name="tab_align">
<return type="void" />
- <argument index="0" name="tab_stops" type="PackedFloat32Array" />
+ <param index="0" name="tab_stops" type="PackedFloat32Array" />
<description>
Aligns paragraph to the given tab-stops.
</description>
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index e1b676427b..aad83211f5 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -17,29 +17,29 @@
</method>
<method name="create_shaped_text">
<return type="RID" />
- <argument index="0" name="direction" type="int" enum="TextServer.Direction" default="0" />
- <argument index="1" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
+ <param index="0" name="direction" type="int" enum="TextServer.Direction" default="0" />
+ <param index="1" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
- Creates new buffer for complex text layout, with the given [code]direction[/code] and [code]orientation[/code]. To free the resulting buffer, use [method free_rid] method.
+ Creates new buffer for complex text layout, with the given [param direction] and [param orientation]. To free the resulting buffer, use [method free_rid] method.
[b]Note:[/b] Direction is ignored if server does not support [constant FEATURE_BIDI_LAYOUT] feature (supported by [TextServerAdvanced]).
[b]Note:[/b] Orientation is ignored if server does not support [constant FEATURE_VERTICAL_LAYOUT] feature (supported by [TextServerAdvanced]).
</description>
</method>
<method name="draw_hex_code_box" qualifiers="const">
<return type="void" />
- <argument index="0" name="canvas" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="pos" type="Vector2" />
- <argument index="3" name="index" type="int" />
- <argument index="4" name="color" type="Color" />
+ <param index="0" name="canvas" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="pos" type="Vector2" />
+ <param index="3" name="index" type="int" />
+ <param index="4" name="color" type="Color" />
<description>
Draws box displaying character hexadecimal code. Used for replacing missing characters.
</description>
</method>
<method name="font_clear_glyphs">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
<description>
Removes all rendered glyphs information from the cache entry.
[b]Note:[/b] This function will not remove textures associated with the glyphs, use [method font_remove_texture] to remove them manually.
@@ -47,23 +47,23 @@
</method>
<method name="font_clear_kerning_map">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
<description>
Removes all kerning overrides.
</description>
</method>
<method name="font_clear_size_cache">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Removes all font sizes from the cache entry.
</description>
</method>
<method name="font_clear_textures">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
<description>
Removes all textures from font cache entry.
[b]Note:[/b] This function will not remove glyphs associated with the texture, use [method font_remove_glyph] to remove them manually.
@@ -71,80 +71,87 @@
</method>
<method name="font_draw_glyph" qualifiers="const">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="canvas" type="RID" />
- <argument index="2" name="size" type="int" />
- <argument index="3" name="pos" type="Vector2" />
- <argument index="4" name="index" type="int" />
- <argument index="5" name="color" type="Color" default="Color(1, 1, 1, 1)" />
- <description>
- Draws single glyph into a canvas item at the position, using [code]font_rid[/code] at the size [code]size[/code].
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="canvas" type="RID" />
+ <param index="2" name="size" type="int" />
+ <param index="3" name="pos" type="Vector2" />
+ <param index="4" name="index" type="int" />
+ <param index="5" name="color" type="Color" default="Color(1, 1, 1, 1)" />
+ <description>
+ Draws single glyph into a canvas item at the position, using [param font_rid] at the size [param size].
[b]Note:[/b] Glyph index is specific to the font, use glyphs indices returned by [method shaped_text_get_glyphs] or [method font_get_glyph_index].
[b]Note:[/b] If there are pending glyphs to render, calling this function might trigger the texture cache update.
</description>
</method>
<method name="font_draw_glyph_outline" qualifiers="const">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="canvas" type="RID" />
- <argument index="2" name="size" type="int" />
- <argument index="3" name="outline_size" type="int" />
- <argument index="4" name="pos" type="Vector2" />
- <argument index="5" name="index" type="int" />
- <argument index="6" name="color" type="Color" default="Color(1, 1, 1, 1)" />
- <description>
- Draws single glyph outline of size [code]outline_size[/code] into a canvas item at the position, using [code]font_rid[/code] at the size [code]size[/code].
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="canvas" type="RID" />
+ <param index="2" name="size" type="int" />
+ <param index="3" name="outline_size" type="int" />
+ <param index="4" name="pos" type="Vector2" />
+ <param index="5" name="index" type="int" />
+ <param index="6" name="color" type="Color" default="Color(1, 1, 1, 1)" />
+ <description>
+ Draws single glyph outline of size [param outline_size] into a canvas item at the position, using [param font_rid] at the size [param size].
[b]Note:[/b] Glyph index is specific to the font, use glyphs indices returned by [method shaped_text_get_glyphs] or [method font_get_glyph_index].
[b]Note:[/b] If there are pending glyphs to render, calling this function might trigger the texture cache update.
</description>
</method>
+ <method name="font_get_antialiasing" qualifiers="const">
+ <return type="int" enum="TextServer.FontAntialiasing" />
+ <param index="0" name="font_rid" type="RID" />
+ <description>
+ Returns font anti-aliasing mode.
+ </description>
+ </method>
<method name="font_get_ascent" qualifiers="const">
<return type="float" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
<description>
Returns the font ascent (number of pixels above the baseline).
</description>
</method>
<method name="font_get_descent" qualifiers="const">
<return type="float" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
<description>
Returns the font descent (number of pixels below the baseline).
</description>
</method>
<method name="font_get_embolden" qualifiers="const">
<return type="float" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns font embolden strength.
</description>
</method>
<method name="font_get_face_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns number of faces in the TrueType / OpenType collection.
</description>
</method>
<method name="font_get_face_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Recturns an active face index in the TrueType / OpenType collection.
</description>
</method>
<method name="font_get_fixed_size" qualifiers="const">
<return type="int" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns bitmap font fixed size.
</description>
</method>
<method name="font_get_generate_mipmaps" qualifiers="const">
<return type="bool" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns [code]true[/code] if font texture mipmap generation is enabled.
</description>
@@ -157,9 +164,9 @@
</method>
<method name="font_get_glyph_advance" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="glyph" type="int" />
<description>
Returns glyph advance (offset of the next glyph).
[b]Note:[/b] Advance for glyphs outlines is the same as the base glyph advance and is not saved.
@@ -167,9 +174,9 @@
</method>
<method name="font_get_glyph_contours" qualifiers="const">
<return type="Dictionary" />
- <argument index="0" name="font" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="index" type="int" />
+ <param index="0" name="font" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="index" type="int" />
<description>
Returns outline contours of the glyph as a [code]Dictionary[/code] with the following contents:
[code]points[/code] - [PackedVector3Array], containing outline points. [code]x[/code] and [code]y[/code] are point coordinates. [code]z[/code] is the type of the point, using the [enum ContourPointTag] values.
@@ -179,54 +186,54 @@
</method>
<method name="font_get_glyph_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="char" type="int" />
- <argument index="3" name="variation_selector" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="char" type="int" />
+ <param index="3" name="variation_selector" type="int" />
<description>
- Returns the glyph index of a [code]char[/code], optionally modified by the [code]variation_selector[/code].
+ Returns the glyph index of a [param char], optionally modified by the [param variation_selector].
</description>
</method>
<method name="font_get_glyph_list" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
+ <return type="PackedInt32Array" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
<description>
Returns list of rendered glyphs in the cache entry.
</description>
</method>
<method name="font_get_glyph_offset" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
<description>
Returns glyph offset from the baseline.
</description>
</method>
<method name="font_get_glyph_size" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
<description>
Returns size of the glyph.
</description>
</method>
<method name="font_get_glyph_texture_idx" qualifiers="const">
<return type="int" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
<description>
Returns index of the cache texture containing the glyph.
</description>
</method>
<method name="font_get_glyph_texture_rid" qualifiers="const">
<return type="RID" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
<description>
Returns resource id of the cache texture containing the glyph.
[b]Note:[/b] If there are pending glyphs to render, calling this function might trigger the texture cache update.
@@ -234,9 +241,9 @@
</method>
<method name="font_get_glyph_texture_size" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
<description>
Returns size of the cache texture containing the glyph.
[b]Note:[/b] If there are pending glyphs to render, calling this function might trigger the texture cache update.
@@ -244,251 +251,244 @@
</method>
<method name="font_get_glyph_uv_rect" qualifiers="const">
<return type="Rect2" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
<description>
Returns rectangle in the cache texture containing the glyph.
</description>
</method>
<method name="font_get_hinting" qualifiers="const">
<return type="int" enum="TextServer.Hinting" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns the font hinting mode. Used by dynamic fonts only.
</description>
</method>
<method name="font_get_kerning" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="glyph_pair" type="Vector2i" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="glyph_pair" type="Vector2i" />
<description>
Returns kerning for the pair of glyphs.
</description>
</method>
<method name="font_get_kerning_list" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
+ <return type="Vector2i[]" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
<description>
Returns list of the kerning overrides.
</description>
</method>
<method name="font_get_language_support_override">
<return type="bool" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="language" type="String" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="language" type="String" />
<description>
- Returns [code]true[/code] if support override is enabled for the [code]language[/code].
+ Returns [code]true[/code] if support override is enabled for the [param language].
</description>
</method>
<method name="font_get_language_support_overrides">
<return type="PackedStringArray" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns list of language support overrides.
</description>
</method>
<method name="font_get_msdf_pixel_range" qualifiers="const">
<return type="int" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns the width of the range around the shape between the minimum and maximum representable signed distance.
</description>
</method>
<method name="font_get_msdf_size" qualifiers="const">
<return type="int" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns source font size used to generate MSDF textures.
</description>
</method>
<method name="font_get_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns font family name.
</description>
</method>
<method name="font_get_opentype_feature_overrides" qualifiers="const">
<return type="Dictionary" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns font OpenType feature set override.
</description>
</method>
<method name="font_get_oversampling" qualifiers="const">
<return type="float" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns font oversampling factor, if set to [code]0.0[/code] global oversampling factor is used instead. Used by dynamic fonts only.
</description>
</method>
<method name="font_get_scale" qualifiers="const">
<return type="float" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
<description>
Returns scaling factor of the color bitmap font.
</description>
</method>
<method name="font_get_script_support_override">
<return type="bool" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="script" type="String" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="script" type="String" />
<description>
- Returns [code]true[/code] if support override is enabled for the [code]script[/code].
+ Returns [code]true[/code] if support override is enabled for the [param script].
</description>
</method>
<method name="font_get_script_support_overrides">
<return type="PackedStringArray" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns list of script support overrides.
</description>
</method>
<method name="font_get_size_cache_list" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="font_rid" type="RID" />
+ <return type="Vector2i[]" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns list of the font sizes in the cache. Each size is [code]Vector2i[/code] with font size and outline size.
</description>
</method>
<method name="font_get_style" qualifiers="const">
<return type="int" enum="TextServer.FontStyle" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns font style flags, see [enum FontStyle].
</description>
</method>
<method name="font_get_style_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns font style name.
</description>
</method>
<method name="font_get_subpixel_positioning" qualifiers="const">
<return type="int" enum="TextServer.SubpixelPositioning" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns font sub-pixel glyph positioning mode.
</description>
</method>
<method name="font_get_supported_chars" qualifiers="const">
<return type="String" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns a string containing all the characters available in the font.
</description>
</method>
<method name="font_get_texture_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
<description>
Returns number of textures used by font cache entry.
</description>
</method>
<method name="font_get_texture_image" qualifiers="const">
<return type="Image" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="texture_index" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="texture_index" type="int" />
<description>
Returns font cache texture image data.
</description>
</method>
<method name="font_get_texture_offsets" qualifiers="const">
<return type="PackedInt32Array" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="texture_index" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="texture_index" type="int" />
<description>
Returns array containing the first free pixel in the each column of texture. Should be the same size as texture width or empty.
</description>
</method>
<method name="font_get_transform" qualifiers="const">
<return type="Transform2D" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns 2D transform applied to the font outlines.
</description>
</method>
<method name="font_get_underline_position" qualifiers="const">
<return type="float" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
<description>
Returns pixel offset of the underline below the baseline.
</description>
</method>
<method name="font_get_underline_thickness" qualifiers="const">
<return type="float" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
<description>
Returns thickness of the underline in pixels.
</description>
</method>
<method name="font_get_variation_coordinates" qualifiers="const">
<return type="Dictionary" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns variation coordinates for the specified font cache entry. See [method font_supported_variation_list] for more info.
</description>
</method>
<method name="font_has_char" qualifiers="const">
<return type="bool" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="char" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="char" type="int" />
<description>
- Returns [code]true[/code] if a Unicode [code]char[/code] is available in the font.
- </description>
- </method>
- <method name="font_is_antialiased" qualifiers="const">
- <return type="bool" />
- <argument index="0" name="font_rid" type="RID" />
- <description>
- Returns [code]true[/code] if font 8-bit anitialiased glyph rendering is supported and enabled.
+ Returns [code]true[/code] if a Unicode [param char] is available in the font.
</description>
</method>
<method name="font_is_force_autohinter" qualifiers="const">
<return type="bool" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns [code]true[/code] if auto-hinting is supported and preferred over font built-in hinting. Used by dynamic fonts only.
</description>
</method>
<method name="font_is_language_supported" qualifiers="const">
<return type="bool" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="language" type="String" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="language" type="String" />
<description>
Returns [code]true[/code], if font supports given language ([url=https://en.wikipedia.org/wiki/ISO_639-1]ISO 639[/url] code).
</description>
</method>
<method name="font_is_multichannel_signed_distance_field" qualifiers="const">
<return type="bool" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns [code]true[/code] if glyphs of all sizes are rendered using single multichannel signed distance field generated from the dynamic font vector data.
</description>
</method>
<method name="font_is_script_supported" qualifiers="const">
<return type="bool" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="script" type="String" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="script" type="String" />
<description>
Returns [code]true[/code], if font supports given script (ISO 15924 code).
</description>
</method>
<method name="font_remove_glyph">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
<description>
Removes specified rendered glyph information from the cache entry.
[b]Note:[/b] This function will not remove textures associated with the glyphs, use [method font_remove_texture] to remove them manually.
@@ -496,42 +496,42 @@
</method>
<method name="font_remove_kerning">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="glyph_pair" type="Vector2i" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="glyph_pair" type="Vector2i" />
<description>
Removes kerning override for the pair of glyphs.
</description>
</method>
<method name="font_remove_language_support_override">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="language" type="String" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="language" type="String" />
<description>
Remove language support override.
</description>
</method>
<method name="font_remove_script_support_override">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="script" type="String" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="script" type="String" />
<description>
Removes script support override.
</description>
</method>
<method name="font_remove_size_cache">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
<description>
Removes specified font size from the cache entry.
</description>
</method>
<method name="font_remove_texture">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="texture_index" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="texture_index" type="int" />
<description>
Removes specified texture from the cache entry.
[b]Note:[/b] This function will not remove glyphs associated with the texture, remove them manually, using [method font_remove_glyph].
@@ -539,100 +539,100 @@
</method>
<method name="font_render_glyph">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="index" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="index" type="int" />
<description>
Renders specified glyph to the font cache texture.
</description>
</method>
<method name="font_render_range">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="start" type="int" />
- <argument index="3" name="end" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="start" type="int" />
+ <param index="3" name="end" type="int" />
<description>
Renders the range of characters to the font cache texture.
</description>
</method>
- <method name="font_set_antialiased">
+ <method name="font_set_antialiasing">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="antialiased" type="bool" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="antialiasing" type="int" enum="TextServer.FontAntialiasing" />
<description>
- If set to [code]true[/code], 8-bit antialiased glyph rendering is used, otherwise 1-bit rendering is used. Used by dynamic fonts only.
+ Sets font anti-aliasing mode.
</description>
</method>
<method name="font_set_ascent">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="ascent" type="float" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="ascent" type="float" />
<description>
Sets the font ascent (number of pixels above the baseline).
</description>
</method>
<method name="font_set_data">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="data" type="PackedByteArray" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="data" type="PackedByteArray" />
<description>
Sets font source data, e.g contents of the dynamic font source file.
</description>
</method>
<method name="font_set_descent">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="descent" type="float" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="descent" type="float" />
<description>
Sets the font descent (number of pixels below the baseline).
</description>
</method>
<method name="font_set_embolden">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="strength" type="float" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="strength" type="float" />
<description>
- Sets font embolden strength. If [code]strength[/code] is not equal to zero, emboldens the font outlines. Negative values reduce the outline thickness.
+ Sets font embolden strength. If [param strength] is not equal to zero, emboldens the font outlines. Negative values reduce the outline thickness.
</description>
</method>
<method name="font_set_face_index">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="face_index" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="face_index" type="int" />
<description>
Sets an active face index in the TrueType / OpenType collection.
</description>
</method>
<method name="font_set_fixed_size">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="fixed_size" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="fixed_size" type="int" />
<description>
Sets bitmap font fixed size. If set to value greater than zero, same cache entry will be used for all font sizes.
</description>
</method>
<method name="font_set_force_autohinter">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="force_autohinter" type="bool" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="force_autohinter" type="bool" />
<description>
If set to [code]true[/code] auto-hinting is preferred over font built-in hinting.
</description>
</method>
<method name="font_set_generate_mipmaps">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="generate_mipmaps" type="bool" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="generate_mipmaps" type="bool" />
<description>
If set to [code]true[/code] font texture mipmap generation is enabled.
</description>
</method>
<method name="font_set_global_oversampling">
<return type="void" />
- <argument index="0" name="oversampling" type="float" />
+ <param index="0" name="oversampling" type="float" />
<description>
Sets oversampling factor, shared by all font in the TextServer.
[b]Note:[/b] This value can be automatically changed by display server.
@@ -640,10 +640,10 @@
</method>
<method name="font_set_glyph_advance">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="glyph" type="int" />
- <argument index="3" name="advance" type="Vector2" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="glyph" type="int" />
+ <param index="3" name="advance" type="Vector2" />
<description>
Sets glyph advance (offset of the next glyph).
[b]Note:[/b] Advance for glyphs outlines is the same as the base glyph advance and is not saved.
@@ -651,91 +651,91 @@
</method>
<method name="font_set_glyph_offset">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
- <argument index="3" name="offset" type="Vector2" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
+ <param index="3" name="offset" type="Vector2" />
<description>
Sets glyph offset from the baseline.
</description>
</method>
<method name="font_set_glyph_size">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
- <argument index="3" name="gl_size" type="Vector2" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
+ <param index="3" name="gl_size" type="Vector2" />
<description>
Sets size of the glyph.
</description>
</method>
<method name="font_set_glyph_texture_idx">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
- <argument index="3" name="texture_idx" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
+ <param index="3" name="texture_idx" type="int" />
<description>
Sets index of the cache texture containing the glyph.
</description>
</method>
<method name="font_set_glyph_uv_rect">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
- <argument index="3" name="uv_rect" type="Rect2" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
+ <param index="3" name="uv_rect" type="Rect2" />
<description>
Sets rectangle in the cache texture containing the glyph.
</description>
</method>
<method name="font_set_hinting">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="hinting" type="int" enum="TextServer.Hinting" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="hinting" type="int" enum="TextServer.Hinting" />
<description>
Sets font hinting mode. Used by dynamic fonts only.
</description>
</method>
<method name="font_set_kerning">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="glyph_pair" type="Vector2i" />
- <argument index="3" name="kerning" type="Vector2" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="glyph_pair" type="Vector2i" />
+ <param index="3" name="kerning" type="Vector2" />
<description>
Sets kerning for the pair of glyphs.
</description>
</method>
<method name="font_set_language_support_override">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="language" type="String" />
- <argument index="2" name="supported" type="bool" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="language" type="String" />
+ <param index="2" name="supported" type="bool" />
<description>
Adds override for [method font_is_language_supported].
</description>
</method>
<method name="font_set_msdf_pixel_range">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="msdf_pixel_range" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="msdf_pixel_range" type="int" />
<description>
Sets the width of the range around the shape between the minimum and maximum representable signed distance.
</description>
</method>
<method name="font_set_msdf_size">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="msdf_size" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="msdf_size" type="int" />
<description>
Sets source font size used to generate MSDF textures.
</description>
</method>
<method name="font_set_multichannel_signed_distance_field">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="msdf" type="bool" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="msdf" type="bool" />
<description>
If set to [code]true[/code], glyphs of all sizes are rendered using single multichannel signed distance field generated from the dynamic font vector data. MSDF rendering allows displaying the font at any scaling factor without blurriness, and without incurring a CPU cost when the font size changes (since the font no longer needs to be rasterized on the CPU). As a downside, font hinting is not available with MSDF. The lack of font hinting may result in less crisp and less readable fonts at small sizes.
[b]Note:[/b] MSDF font rendering does not render glyphs with overlapping shapes correctly. Overlapping shapes are not valid per the OpenType standard, but are still commonly found in many font files, especially those converted by Google Fonts. To avoid issues with overlapping glyphs, consider downloading the font file directly from the type foundry instead of relying on Google Fonts.
@@ -743,94 +743,94 @@
</method>
<method name="font_set_name">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="name" type="String" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="name" type="String" />
<description>
Sets the font family name.
</description>
</method>
<method name="font_set_opentype_feature_overrides">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="overrides" type="Dictionary" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="overrides" type="Dictionary" />
<description>
Sets font OpenType feature set override.
</description>
</method>
<method name="font_set_oversampling">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="oversampling" type="float" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="oversampling" type="float" />
<description>
Sets font oversampling factor, if set to [code]0.0[/code] global oversampling factor is used instead. Used by dynamic fonts only.
</description>
</method>
<method name="font_set_scale">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="scale" type="float" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="scale" type="float" />
<description>
Sets scaling factor of the color bitmap font.
</description>
</method>
<method name="font_set_script_support_override">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="script" type="String" />
- <argument index="2" name="supported" type="bool" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="script" type="String" />
+ <param index="2" name="supported" type="bool" />
<description>
Adds override for [method font_is_script_supported].
</description>
</method>
<method name="font_set_style">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="style" type="int" enum="TextServer.FontStyle" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="style" type="int" enum="TextServer.FontStyle" />
<description>
Sets the font style flags, see [enum FontStyle].
</description>
</method>
<method name="font_set_style_name">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="name" type="String" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="name" type="String" />
<description>
Sets the font style name.
</description>
</method>
<method name="font_set_subpixel_positioning">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="subpixel_positioning" type="int" enum="TextServer.SubpixelPositioning" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="subpixel_positioning" type="int" enum="TextServer.SubpixelPositioning" />
<description>
Sets font sub-pixel glyph positioning mode.
</description>
</method>
<method name="font_set_texture_image">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="texture_index" type="int" />
- <argument index="3" name="image" type="Image" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="texture_index" type="int" />
+ <param index="3" name="image" type="Image" />
<description>
Sets font cache texture image data.
</description>
</method>
<method name="font_set_texture_offsets">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="texture_index" type="int" />
- <argument index="3" name="offset" type="PackedInt32Array" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="texture_index" type="int" />
+ <param index="3" name="offset" type="PackedInt32Array" />
<description>
Sets array containing the first free pixel in the each column of texture. Should be the same size as texture width or empty.
</description>
</method>
<method name="font_set_transform">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="transform" type="Transform2D" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="transform" type="Transform2D" />
<description>
Sets 2D transform, applied to the font outlines, can be used for slanting, flipping and rotating glyphs.
For example, to simulate italic typeface by slanting, apply the following transform [code]Transform2D(1.0, slant, 0.0, 1.0, 0.0, 0.0)[/code].
@@ -838,55 +838,55 @@
</method>
<method name="font_set_underline_position">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="underline_position" type="float" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="underline_position" type="float" />
<description>
Sets pixel offset of the underline below the baseline.
</description>
</method>
<method name="font_set_underline_thickness">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="underline_thickness" type="float" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="underline_thickness" type="float" />
<description>
Sets thickness of the underline in pixels.
</description>
</method>
<method name="font_set_variation_coordinates">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="variation_coordinates" type="Dictionary" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="variation_coordinates" type="Dictionary" />
<description>
Sets variation coordinates for the specified font cache entry. See [method font_supported_variation_list] for more info.
</description>
</method>
<method name="font_supported_feature_list" qualifiers="const">
<return type="Dictionary" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns the dictionary of the supported OpenType features.
</description>
</method>
<method name="font_supported_variation_list" qualifiers="const">
<return type="Dictionary" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns the dictionary of the supported OpenType variation coordinates.
</description>
</method>
<method name="format_number" qualifiers="const">
<return type="String" />
- <argument index="0" name="number" type="String" />
- <argument index="1" name="language" type="String" default="&quot;&quot;" />
+ <param index="0" name="number" type="String" />
+ <param index="1" name="language" type="String" default="&quot;&quot;" />
<description>
- Converts a number from the Western Arabic (0..9) to the numeral systems used in [code]language[/code].
+ Converts a number from the Western Arabic (0..9) to the numeral systems used in [param language].
</description>
</method>
<method name="free_rid">
<return type="void" />
- <argument index="0" name="rid" type="RID" />
+ <param index="0" name="rid" type="RID" />
<description>
Frees an object created by this [TextServer].
</description>
@@ -899,8 +899,8 @@
</method>
<method name="get_hex_code_box_size" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="size" type="int" />
- <argument index="1" name="index" type="int" />
+ <param index="0" name="size" type="int" />
+ <param index="1" name="index" type="int" />
<description>
Returns size of the replacement character (box with character hexadecimal code that is drawn in place of invalid characters).
</description>
@@ -925,28 +925,53 @@
</method>
<method name="has">
<return type="bool" />
- <argument index="0" name="rid" type="RID" />
+ <param index="0" name="rid" type="RID" />
<description>
- Returns [code]true[/code] if [code]rid[/code] is valid resource owned by this text server.
+ Returns [code]true[/code] if [param rid] is valid resource owned by this text server.
</description>
</method>
<method name="has_feature" qualifiers="const">
<return type="bool" />
- <argument index="0" name="feature" type="int" enum="TextServer.Feature" />
+ <param index="0" name="feature" type="int" enum="TextServer.Feature" />
<description>
Returns [code]true[/code] if the server supports a feature.
</description>
</method>
+ <method name="is_confusable" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="string" type="String" />
+ <param index="1" name="dict" type="PackedStringArray" />
+ <description>
+ Returns index of the first string in [param dict] which is visually confusable with the [param string], or [code]-1[/code] if none is found.
+ [b]Note:[/b] This method doesn't detect invisible characters, for spoof detection use it in combination with [method spoof_check].
+ [b]Note:[/b] Always returns [code]-1[/code] if the server does not support the [constant FEATURE_UNICODE_SECURITY] feature.
+ </description>
+ </method>
<method name="is_locale_right_to_left" qualifiers="const">
<return type="bool" />
- <argument index="0" name="locale" type="String" />
+ <param index="0" name="locale" type="String" />
<description>
Returns [code]true[/code] if locale is right-to-left.
</description>
</method>
+ <method name="is_valid_identifier" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="string" type="String" />
+ <description>
+ Returns [code]true[/code] is [param string] is a valid identifier.
+ If the text server supports the [constant FEATURE_UNICODE_IDENTIFIERS] feature, a valid identifier must:
+ - Conform to normalization form C.
+ - Begin with a Unicode character of class XID_Start or [code]"_"[/code].
+ - May contain Unicode characters of class XID_Continue in the other positions.
+ - Use UAX #31 recommended scripts only (mixed scripts are allowed).
+ If the [constant FEATURE_UNICODE_IDENTIFIERS] feature is not supported, a valid identifier must:
+ - Begin with a Unicode character of class XID_Start or [code]"_"[/code].
+ - May contain Unicode characters of class XID_Continue in the other positions.
+ </description>
+ </method>
<method name="load_support_data">
<return type="bool" />
- <argument index="0" name="filename" type="String" />
+ <param index="0" name="filename" type="String" />
<description>
Loads optional TextServer database (e.g. ICU break iterators and dictionaries).
[b]Note:[/b] This function should be called before any other TextServer functions used, otherwise it won't have any effect.
@@ -954,38 +979,38 @@
</method>
<method name="name_to_tag" qualifiers="const">
<return type="int" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
Converts readable feature, variation, script or language name to OpenType tag.
</description>
</method>
<method name="parse_number" qualifiers="const">
<return type="String" />
- <argument index="0" name="number" type="String" />
- <argument index="1" name="language" type="String" default="&quot;&quot;" />
+ <param index="0" name="number" type="String" />
+ <param index="1" name="language" type="String" default="&quot;&quot;" />
<description>
- Converts a number from the numeral systems used in [code]language[/code] to Western Arabic (0..9).
+ Converts [param number] from the numeral systems used in [param language] to Western Arabic (0..9).
</description>
</method>
<method name="parse_structured_text" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="parser_type" type="int" enum="TextServer.StructuredTextParser" />
- <argument index="1" name="args" type="Array" />
- <argument index="2" name="text" type="String" />
+ <return type="Vector2i[]" />
+ <param index="0" name="parser_type" type="int" enum="TextServer.StructuredTextParser" />
+ <param index="1" name="args" type="Array" />
+ <param index="2" name="text" type="String" />
<description>
Default implementation of the BiDi algorithm override function. See [enum StructuredTextParser] for more info.
</description>
</method>
<method name="percent_sign" qualifiers="const">
<return type="String" />
- <argument index="0" name="language" type="String" default="&quot;&quot;" />
+ <param index="0" name="language" type="String" default="&quot;&quot;" />
<description>
- Returns percent sign used in the [code]language[/code].
+ Returns percent sign used in the [param language].
</description>
</method>
<method name="save_support_data" qualifiers="const">
<return type="bool" />
- <argument index="0" name="filename" type="String" />
+ <param index="0" name="filename" type="String" />
<description>
Saves optional TextServer database (e.g. ICU break iterators and dictionaries) to the file.
[b]Note:[/b] This function is used by during project export, to include TextServer database.
@@ -993,98 +1018,98 @@
</method>
<method name="shaped_get_span_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns number of text spans added using [method shaped_text_add_string] or [method shaped_text_add_object].
</description>
</method>
<method name="shaped_get_span_meta" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="index" type="int" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="index" type="int" />
<description>
Returns text span metadata.
</description>
</method>
<method name="shaped_set_span_update_font">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="index" type="int" />
- <argument index="2" name="fonts" type="Array" />
- <argument index="3" name="size" type="int" />
- <argument index="4" name="opentype_features" type="Dictionary" default="{}" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="index" type="int" />
+ <param index="2" name="fonts" type="Array" />
+ <param index="3" name="size" type="int" />
+ <param index="4" name="opentype_features" type="Dictionary" default="{}" />
<description>
Changes text span font, font size and OpenType features, without changing the text.
</description>
</method>
<method name="shaped_text_add_object">
<return type="bool" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="key" type="Variant" />
- <argument index="2" name="size" type="Vector2" />
- <argument index="3" name="inline_align" type="int" enum="InlineAlignment" default="5" />
- <argument index="4" name="length" type="int" default="1" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="key" type="Variant" />
+ <param index="2" name="size" type="Vector2" />
+ <param index="3" name="inline_align" type="int" enum="InlineAlignment" default="5" />
+ <param index="4" name="length" type="int" default="1" />
<description>
- Adds inline object to the text buffer, [code]key[/code] must be unique. In the text, object is represented as [code]length[/code] object replacement characters.
+ Adds inline object to the text buffer, [param key] must be unique. In the text, object is represented as [param length] object replacement characters.
</description>
</method>
<method name="shaped_text_add_string">
<return type="bool" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="text" type="String" />
- <argument index="2" name="fonts" type="Array" />
- <argument index="3" name="size" type="int" />
- <argument index="4" name="opentype_features" type="Dictionary" default="{}" />
- <argument index="5" name="language" type="String" default="&quot;&quot;" />
- <argument index="6" name="meta" type="Variant" default="null" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="text" type="String" />
+ <param index="2" name="fonts" type="Array" />
+ <param index="3" name="size" type="int" />
+ <param index="4" name="opentype_features" type="Dictionary" default="{}" />
+ <param index="5" name="language" type="String" default="&quot;&quot;" />
+ <param index="6" name="meta" type="Variant" default="null" />
<description>
Adds text span and font to draw it to the text buffer.
</description>
</method>
<method name="shaped_text_clear">
<return type="void" />
- <argument index="0" name="rid" type="RID" />
+ <param index="0" name="rid" type="RID" />
<description>
Clears text buffer (removes text and inline objects).
</description>
</method>
<method name="shaped_text_draw" qualifiers="const">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="canvas" type="RID" />
- <argument index="2" name="pos" type="Vector2" />
- <argument index="3" name="clip_l" type="float" default="-1" />
- <argument index="4" name="clip_r" type="float" default="-1" />
- <argument index="5" name="color" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="canvas" type="RID" />
+ <param index="2" name="pos" type="Vector2" />
+ <param index="3" name="clip_l" type="float" default="-1" />
+ <param index="4" name="clip_r" type="float" default="-1" />
+ <param index="5" name="color" type="Color" default="Color(1, 1, 1, 1)" />
<description>
- Draw shaped text into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the leftmost point of the baseline (for horizontal layout) or topmost point of the baseline (for vertical layout).
+ Draw shaped text into a canvas item at a given position, with [param color]. [param pos] specifies the leftmost point of the baseline (for horizontal layout) or topmost point of the baseline (for vertical layout).
</description>
</method>
<method name="shaped_text_draw_outline" qualifiers="const">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="canvas" type="RID" />
- <argument index="2" name="pos" type="Vector2" />
- <argument index="3" name="clip_l" type="float" default="-1" />
- <argument index="4" name="clip_r" type="float" default="-1" />
- <argument index="5" name="outline_size" type="int" default="1" />
- <argument index="6" name="color" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="canvas" type="RID" />
+ <param index="2" name="pos" type="Vector2" />
+ <param index="3" name="clip_l" type="float" default="-1" />
+ <param index="4" name="clip_r" type="float" default="-1" />
+ <param index="5" name="outline_size" type="int" default="1" />
+ <param index="6" name="color" type="Color" default="Color(1, 1, 1, 1)" />
<description>
- Draw the outline of the shaped text into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the leftmost point of the baseline (for horizontal layout) or topmost point of the baseline (for vertical layout).
+ Draw the outline of the shaped text into a canvas item at a given position, with [param color]. [param pos] specifies the leftmost point of the baseline (for horizontal layout) or topmost point of the baseline (for vertical layout).
</description>
</method>
<method name="shaped_text_fit_to_width">
<return type="float" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="width" type="float" />
- <argument index="2" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="width" type="float" />
+ <param index="2" name="jst_flags" type="int" enum="TextServer.JustificationFlag" default="3" />
<description>
Adjusts text with to fit to specified width, returns new text width.
</description>
</method>
<method name="shaped_text_get_ascent" qualifiers="const">
<return type="float" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns the text ascent (number of pixels above the baseline for horizontal layout or to the left of baseline for vertical).
[b]Note:[/b] Overall ascent can be higher than font ascent, if some glyphs are displaced from the baseline.
@@ -1092,22 +1117,22 @@
</method>
<method name="shaped_text_get_carets" qualifiers="const">
<return type="Dictionary" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="position" type="int" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="position" type="int" />
<description>
- Returns shapes of the carets corresponding to the character offset [code]position[/code] in the text. Returned caret shape is 1 pixel wide rectangle.
+ Returns shapes of the carets corresponding to the character offset [param position] in the text. Returned caret shape is 1 pixel wide rectangle.
</description>
</method>
<method name="shaped_text_get_custom_punctuation" qualifiers="const">
<return type="String" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns custom punctuation character list, used for word breaking. If set to empty string, server defaults are used.
</description>
</method>
<method name="shaped_text_get_descent" qualifiers="const">
<return type="float" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns the text descent (number of pixels below the baseline for horizontal layout or to the right of baseline for vertical).
[b]Note:[/b] Overall descent can be higher than font descent, if some glyphs are displaced from the baseline.
@@ -1115,130 +1140,130 @@
</method>
<method name="shaped_text_get_direction" qualifiers="const">
<return type="int" enum="TextServer.Direction" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns direction of the text.
</description>
</method>
<method name="shaped_text_get_dominant_direction_in_range" qualifiers="const">
<return type="int" enum="TextServer.Direction" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="start" type="int" />
- <argument index="2" name="end" type="int" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="start" type="int" />
+ <param index="2" name="end" type="int" />
<description>
Returns dominant direction of in the range of text.
</description>
</method>
<method name="shaped_text_get_ellipsis_glyph_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns number of glyphs in the ellipsis.
</description>
</method>
<method name="shaped_text_get_ellipsis_glyphs" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="shaped" type="RID" />
+ <return type="Dictionary[]" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns array of the glyphs in the ellipsis.
</description>
</method>
<method name="shaped_text_get_ellipsis_pos" qualifiers="const">
<return type="int" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns position of the ellipsis.
</description>
</method>
<method name="shaped_text_get_glyph_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns number of glyphs in the buffer.
</description>
</method>
<method name="shaped_text_get_glyphs" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="shaped" type="RID" />
+ <return type="Dictionary[]" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns an array of glyphs in the visual order.
</description>
</method>
<method name="shaped_text_get_grapheme_bounds" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="pos" type="int" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="pos" type="int" />
<description>
Returns composite character's bounds as offsets from the start of the line.
</description>
</method>
<method name="shaped_text_get_inferred_direction" qualifiers="const">
<return type="int" enum="TextServer.Direction" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns direction of the text, inferred by the BiDi algorithm.
</description>
</method>
<method name="shaped_text_get_line_breaks" qualifiers="const">
<return type="PackedInt32Array" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="width" type="float" />
- <argument index="2" name="start" type="int" default="0" />
- <argument index="3" name="break_flags" type="int" enum="TextServer.LineBreakFlag" default="3" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="width" type="float" />
+ <param index="2" name="start" type="int" default="0" />
+ <param index="3" name="break_flags" type="int" enum="TextServer.LineBreakFlag" default="3" />
<description>
Breaks text to the lines and returns character ranges for each line.
</description>
</method>
<method name="shaped_text_get_line_breaks_adv" qualifiers="const">
<return type="PackedInt32Array" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="width" type="PackedFloat32Array" />
- <argument index="2" name="start" type="int" default="0" />
- <argument index="3" name="once" type="bool" default="true" />
- <argument index="4" name="break_flags" type="int" enum="TextServer.LineBreakFlag" default="3" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="width" type="PackedFloat32Array" />
+ <param index="2" name="start" type="int" default="0" />
+ <param index="3" name="once" type="bool" default="true" />
+ <param index="4" name="break_flags" type="int" enum="TextServer.LineBreakFlag" default="3" />
<description>
Breaks text to the lines and columns. Returns character ranges for each segment.
</description>
</method>
<method name="shaped_text_get_object_rect" qualifiers="const">
<return type="Rect2" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="key" type="Variant" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="key" type="Variant" />
<description>
Returns bounding rectangle of the inline object.
</description>
</method>
<method name="shaped_text_get_objects" qualifiers="const">
<return type="Array" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns array of inline objects.
</description>
</method>
<method name="shaped_text_get_orientation" qualifiers="const">
<return type="int" enum="TextServer.Orientation" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns text orientation.
</description>
</method>
<method name="shaped_text_get_parent" qualifiers="const">
<return type="RID" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns the parent buffer from which the substring originates.
</description>
</method>
<method name="shaped_text_get_preserve_control" qualifiers="const">
<return type="bool" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns [code]true[/code] if text buffer is configured to display control characters.
</description>
</method>
<method name="shaped_text_get_preserve_invalid" qualifiers="const">
<return type="bool" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns [code]true[/code] if text buffer is configured to display hexadecimal codes in place of invalid characters.
[b]Note:[/b] If set to [code]false[/code], nothing is displayed in place of invalid characters.
@@ -1246,133 +1271,133 @@
</method>
<method name="shaped_text_get_range" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns substring buffer character range in the parent buffer.
</description>
</method>
<method name="shaped_text_get_selection" qualifiers="const">
<return type="PackedVector2Array" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="start" type="int" />
- <argument index="2" name="end" type="int" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="start" type="int" />
+ <param index="2" name="end" type="int" />
<description>
Returns selection rectangles for the specified character range.
</description>
</method>
<method name="shaped_text_get_size" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns size of the text.
</description>
</method>
<method name="shaped_text_get_spacing" qualifiers="const">
<return type="int" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="spacing" type="int" enum="TextServer.SpacingType" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="spacing" type="int" enum="TextServer.SpacingType" />
<description>
Returns extra spacing added between glyphs or lines in pixels.
</description>
</method>
<method name="shaped_text_get_trim_pos" qualifiers="const">
<return type="int" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns the position of the overrun trim.
</description>
</method>
<method name="shaped_text_get_underline_position" qualifiers="const">
<return type="float" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns pixel offset of the underline below the baseline.
</description>
</method>
<method name="shaped_text_get_underline_thickness" qualifiers="const">
<return type="float" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns thickness of the underline.
</description>
</method>
<method name="shaped_text_get_width" qualifiers="const">
<return type="float" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns width (for horizontal layout) or height (for vertical) of the text.
</description>
</method>
<method name="shaped_text_get_word_breaks" qualifiers="const">
<return type="PackedInt32Array" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="grapheme_flags" type="int" enum="TextServer.GraphemeFlag" default="264" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="grapheme_flags" type="int" enum="TextServer.GraphemeFlag" default="264" />
<description>
- Breaks text into words and returns array of character ranges. Use [code]grapheme_flags[/code] to set what characters are used for breaking (see [enum GraphemeFlag]).
+ Breaks text into words and returns array of character ranges. Use [param grapheme_flags] to set what characters are used for breaking (see [enum GraphemeFlag]).
</description>
</method>
<method name="shaped_text_hit_test_grapheme" qualifiers="const">
<return type="int" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="coords" type="float" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="coords" type="float" />
<description>
Returns grapheme index at the specified pixel offset at the baseline, or [code]-1[/code] if none is found.
</description>
</method>
<method name="shaped_text_hit_test_position" qualifiers="const">
<return type="int" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="coords" type="float" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="coords" type="float" />
<description>
Returns caret character offset at the specified pixel offset at the baseline. This function always returns a valid position.
</description>
</method>
<method name="shaped_text_is_ready" qualifiers="const">
<return type="bool" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns [code]true[/code] if buffer is successfully shaped.
</description>
</method>
<method name="shaped_text_next_grapheme_pos" qualifiers="const">
<return type="int" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="pos" type="int" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="pos" type="int" />
<description>
- Returns composite character end position closest to the [code]pos[/code].
+ Returns composite character end position closest to the [param pos].
</description>
</method>
<method name="shaped_text_overrun_trim_to_width">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="width" type="float" default="0" />
- <argument index="2" name="overrun_trim_flags" type="int" enum="TextServer.TextOverrunFlag" default="0" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="width" type="float" default="0" />
+ <param index="2" name="overrun_trim_flags" type="int" enum="TextServer.TextOverrunFlag" default="0" />
<description>
Trims text if it exceeds the given width.
</description>
</method>
<method name="shaped_text_prev_grapheme_pos" qualifiers="const">
<return type="int" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="pos" type="int" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="pos" type="int" />
<description>
- Returns composite character start position closest to the [code]pos[/code].
+ Returns composite character start position closest to the [param pos].
</description>
</method>
<method name="shaped_text_resize_object">
<return type="bool" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="key" type="Variant" />
- <argument index="2" name="size" type="Vector2" />
- <argument index="3" name="inline_align" type="int" enum="InlineAlignment" default="5" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="key" type="Variant" />
+ <param index="2" name="size" type="Vector2" />
+ <param index="3" name="inline_align" type="int" enum="InlineAlignment" default="5" />
<description>
Sets new size and alignment of embedded object.
</description>
</method>
<method name="shaped_text_set_bidi_override">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="override" type="Array" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="override" type="Array" />
<description>
Overrides BiDi for the structured text.
Override ranges should cover full source text without overlaps. BiDi algorithm will be used on each range separately.
@@ -1380,16 +1405,16 @@
</method>
<method name="shaped_text_set_custom_punctuation">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="punct" type="String" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="punct" type="String" />
<description>
Sets custom punctuation character list, used for word breaking. If set to empty string, server defaults are used.
</description>
</method>
<method name="shaped_text_set_direction">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="direction" type="int" enum="TextServer.Direction" default="0" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="direction" type="int" enum="TextServer.Direction" default="0" />
<description>
Sets desired text direction. If set to [code]TEXT_DIRECTION_AUTO[/code], direction will be detected based on the buffer contents and current locale.
[b]Note:[/b] Direction is ignored if server does not support [constant FEATURE_BIDI_LAYOUT] feature (supported by [TextServerAdvanced]).
@@ -1397,8 +1422,8 @@
</method>
<method name="shaped_text_set_orientation">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="orientation" type="int" enum="TextServer.Orientation" default="0" />
<description>
Sets desired text orientation.
[b]Note:[/b] Orientation is ignored if server does not support [constant FEATURE_VERTICAL_LAYOUT] feature (supported by [TextServerAdvanced]).
@@ -1406,73 +1431,81 @@
</method>
<method name="shaped_text_set_preserve_control">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="enabled" type="bool" />
<description>
If set to [code]true[/code] text buffer will display control characters.
</description>
</method>
<method name="shaped_text_set_preserve_invalid">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="enabled" type="bool" />
<description>
If set to [code]true[/code] text buffer will display invalid characters as hexadecimal codes, otherwise nothing is displayed.
</description>
</method>
<method name="shaped_text_set_spacing">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="spacing" type="int" enum="TextServer.SpacingType" />
- <argument index="2" name="value" type="int" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="spacing" type="int" enum="TextServer.SpacingType" />
+ <param index="2" name="value" type="int" />
<description>
Sets extra spacing added between glyphs or lines in pixels.
</description>
</method>
<method name="shaped_text_shape">
<return type="bool" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Shapes buffer if it's not shaped. Returns [code]true[/code] if the string is shaped successfully.
[b]Note:[/b] It is not necessary to call this function manually, buffer will be shaped automatically as soon as any of its output data is requested.
</description>
</method>
<method name="shaped_text_sort_logical">
- <return type="Array" />
- <argument index="0" name="shaped" type="RID" />
+ <return type="Dictionary[]" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns text glyphs in the logical order.
</description>
</method>
<method name="shaped_text_substr" qualifiers="const">
<return type="RID" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="start" type="int" />
- <argument index="2" name="length" type="int" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="start" type="int" />
+ <param index="2" name="length" type="int" />
<description>
- Returns text buffer for the substring of the text in the [code]shaped[/code] text buffer (including inline objects).
+ Returns text buffer for the substring of the text in the [param shaped] text buffer (including inline objects).
</description>
</method>
<method name="shaped_text_tab_align">
<return type="float" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="tab_stops" type="PackedFloat32Array" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="tab_stops" type="PackedFloat32Array" />
<description>
Aligns shaped text to the given tab-stops.
</description>
</method>
+ <method name="spoof_check" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="string" type="String" />
+ <description>
+ Returns [code]true[/code] if [param string] is likely to be an attempt at confusing the reader.
+ [b]Note:[/b] Always returns [code]false[/code] if the server does not support the [constant FEATURE_UNICODE_SECURITY] feature.
+ </description>
+ </method>
<method name="string_get_word_breaks" qualifiers="const">
<return type="PackedInt32Array" />
- <argument index="0" name="string" type="String" />
- <argument index="1" name="language" type="String" default="&quot;&quot;" />
+ <param index="0" name="string" type="String" />
+ <param index="1" name="language" type="String" default="&quot;&quot;" />
<description>
Returns array of the word break character offsets.
</description>
</method>
<method name="string_to_lower" qualifiers="const">
<return type="String" />
- <argument index="0" name="string" type="String" />
- <argument index="1" name="language" type="String" default="&quot;&quot;" />
+ <param index="0" name="string" type="String" />
+ <param index="1" name="language" type="String" default="&quot;&quot;" />
<description>
Returns the string converted to lowercase.
[b]Note:[/b] Casing is locale dependent and context sensitive if server support [constant FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION] feature (supported by [TextServerAdvanced]).
@@ -1481,8 +1514,8 @@
</method>
<method name="string_to_upper" qualifiers="const">
<return type="String" />
- <argument index="0" name="string" type="String" />
- <argument index="1" name="language" type="String" default="&quot;&quot;" />
+ <param index="0" name="string" type="String" />
+ <param index="1" name="language" type="String" default="&quot;&quot;" />
<description>
Returns the string converted to uppercase.
[b]Note:[/b] Casing is locale dependent and context sensitive if server support [constant FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION] feature (supported by [TextServerAdvanced]).
@@ -1491,7 +1524,7 @@
</method>
<method name="strip_diacritics" qualifiers="const">
<return type="String" />
- <argument index="0" name="string" type="String" />
+ <param index="0" name="string" type="String" />
<description>
Strips diacritics from the string.
[b]Note:[/b] The result may be longer or shorter than the original.
@@ -1499,13 +1532,39 @@
</method>
<method name="tag_to_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="tag" type="int" />
+ <param index="0" name="tag" type="int" />
<description>
Converts OpenType tag to readable feature, variation, script or language name.
</description>
</method>
</methods>
<constants>
+ <constant name="FONT_ANTIALIASING_NONE" value="0" enum="FontAntialiasing">
+ Font glyphs are rasterized as 1-bit bitmaps.
+ </constant>
+ <constant name="FONT_ANTIALIASING_GRAY" value="1" enum="FontAntialiasing">
+ Font glyphs are rasterized as 8-bit grayscale anti-aliased bitmaps.
+ </constant>
+ <constant name="FONT_ANTIALIASING_LCD" value="2" enum="FontAntialiasing">
+ Font glyphs are rasterized for LCD screens.
+ LCD sub-pixel layout is determined by the value of [code]gui/theme/lcd_subpixel_layout[/code] project settings.
+ LCD sub-pixel anti-aliasing mode is suitable only for rendering horizontal, unscaled text in 2D.
+ </constant>
+ <constant name="FONT_LCD_SUBPIXEL_LAYOUT_NONE" value="0" enum="FontLCDSubpixelLayout">
+ Unknown or unsupported sub-pixel layout, LCD sub-pixel anti-aliasing is disabled.
+ </constant>
+ <constant name="FONT_LCD_SUBPIXEL_LAYOUT_HRGB" value="1" enum="FontLCDSubpixelLayout">
+ Horizontal RGB sub-pixel layout.
+ </constant>
+ <constant name="FONT_LCD_SUBPIXEL_LAYOUT_HBGR" value="2" enum="FontLCDSubpixelLayout">
+ Horizontal BGR sub-pixel layout.
+ </constant>
+ <constant name="FONT_LCD_SUBPIXEL_LAYOUT_VRGB" value="3" enum="FontLCDSubpixelLayout">
+ Vertical RGB sub-pixel layout.
+ </constant>
+ <constant name="FONT_LCD_SUBPIXEL_LAYOUT_VBGR" value="4" enum="FontLCDSubpixelLayout">
+ Vertical BGR sub-pixel layout.
+ </constant>
<constant name="DIRECTION_AUTO" value="0" enum="Direction">
Text direction is determined based on contents and current locale.
</constant>
@@ -1573,13 +1632,13 @@
Displays glyphs that are mapped to the first [member Label.visible_characters] or [member RichTextLabel.visible_characters] characters from the beginning of the text.
</constant>
<constant name="VC_GLYPHS_AUTO" value="2" enum="VisibleCharactersBehavior">
- Displays [member Label.percent_visible] or [member RichTextLabel.percent_visible] glyphs, starting from the left or from the right, depending on [member Control.layout_direction] value.
+ Displays [member Label.visible_ratio] or [member RichTextLabel.visible_ratio] glyphs, starting from the left or from the right, depending on [member Control.layout_direction] value.
</constant>
<constant name="VC_GLYPHS_LTR" value="3" enum="VisibleCharactersBehavior">
- Displays [member Label.percent_visible] or [member RichTextLabel.percent_visible] glyphs, starting from the left.
+ Displays [member Label.visible_ratio] or [member RichTextLabel.visible_ratio] glyphs, starting from the left.
</constant>
<constant name="VC_GLYPHS_RTL" value="4" enum="VisibleCharactersBehavior">
- Displays [member Label.percent_visible] or [member RichTextLabel.percent_visible] glyphs, starting from the right.
+ Displays [member Label.visible_ratio] or [member RichTextLabel.visible_ratio] glyphs, starting from the right.
</constant>
<constant name="OVERRUN_NO_TRIMMING" value="0" enum="OverrunBehavior">
No text trimming is performed.
@@ -1646,6 +1705,9 @@
<constant name="GRAPHEME_IS_CONNECTED" value="1024" enum="GraphemeFlag" is_bitfield="true">
Grapheme is connected to the previous grapheme. Breaking line before this grapheme is not safe.
</constant>
+ <constant name="GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL" value="2048" enum="GraphemeFlag" is_bitfield="true">
+ It is safe to insert a U+0640 before this grapheme for elongation.
+ </constant>
<constant name="HINTING_NONE" value="0" enum="Hinting">
Disables font hinting (smoother but less crisp).
</constant>
@@ -1671,10 +1733,10 @@
Glyph horizontal position is rounded to one quarter of the pixel size, each glyph is rasterized up to four times.
</constant>
<constant name="SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE" value="20" enum="SubpixelPositioning">
- Maximum font size which will use one half of the pixel subpixel positioning in [constants SUBPIXEL_POSITIONING_AUTO] mode.
+ Maximum font size which will use one half of the pixel subpixel positioning in [constant SUBPIXEL_POSITIONING_AUTO] mode.
</constant>
<constant name="SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE" value="16" enum="SubpixelPositioning">
- Maximum font size which will use one quarter of the pixel subpixel positioning in [constants SUBPIXEL_POSITIONING_AUTO] mode.
+ Maximum font size which will use one quarter of the pixel subpixel positioning in [constant SUBPIXEL_POSITIONING_AUTO] mode.
</constant>
<constant name="FEATURE_SIMPLE_LAYOUT" value="1" enum="Feature">
TextServer supports simple text layouts.
@@ -1713,7 +1775,13 @@
TextServer supports locale dependent and context sensitive case conversion.
</constant>
<constant name="FEATURE_USE_SUPPORT_DATA" value="4096" enum="Feature">
- TextServer require external data file for some features.
+ TextServer require external data file for some features, see [method load_support_data].
+ </constant>
+ <constant name="FEATURE_UNICODE_IDENTIFIERS" value="8192" enum="Feature">
+ TextServer supports UAX #31 identifier validation, see [method is_valid_identifier].
+ </constant>
+ <constant name="FEATURE_UNICODE_SECURITY" value="16384" enum="Feature">
+ TextServer supports [url=https://unicode.org/reports/tr36/]Unicode Technical Report #36[/url] and [url=https://unicode.org/reports/tr39/]Unicode Technical Standard #39[/url] based spoof detection features.
</constant>
<constant name="CONTOUR_CURVE_TAG_ON" value="1" enum="ContourPointTag">
Contour point is on the curve.
diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml
index 4501ec744a..23eb25dc10 100644
--- a/doc/classes/TextServerExtension.xml
+++ b/doc/classes/TextServerExtension.xml
@@ -17,19 +17,19 @@
</method>
<method name="create_shaped_text" qualifiers="virtual">
<return type="RID" />
- <argument index="0" name="direction" type="int" enum="TextServer.Direction" />
- <argument index="1" name="orientation" type="int" enum="TextServer.Orientation" />
+ <param index="0" name="direction" type="int" enum="TextServer.Direction" />
+ <param index="1" name="orientation" type="int" enum="TextServer.Orientation" />
<description>
- Creates new buffer for complex text layout, with the given [code]direction[/code] and [code]orientation[/code]. To free the resulting buffer, use [method free_rid] method.
+ Creates new buffer for complex text layout, with the given [param direction] and [param orientation]. To free the resulting buffer, use [method free_rid] method.
</description>
</method>
<method name="draw_hex_code_box" qualifiers="virtual const">
<return type="void" />
- <argument index="0" name="canvas" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="pos" type="Vector2" />
- <argument index="3" name="index" type="int" />
- <argument index="4" name="color" type="Color" />
+ <param index="0" name="canvas" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="pos" type="Vector2" />
+ <param index="3" name="index" type="int" />
+ <param index="4" name="color" type="Color" />
<description>
Draws box displaying character hexadecimal code. Used for replacing missing characters.
[b]Note:[/b] If this method is not implemented in the plugin, the default implementation will be used.
@@ -37,107 +37,114 @@
</method>
<method name="font_clear_glyphs" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
<description>
Removes all rendered glyphs information from the cache entry.
</description>
</method>
<method name="font_clear_kerning_map" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
<description>
Removes all kerning overrides.
</description>
</method>
<method name="font_clear_size_cache" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Removes all font sizes from the cache entry.
</description>
</method>
<method name="font_clear_textures" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
<description>
Removes all textures from font cache entry.
</description>
</method>
<method name="font_draw_glyph" qualifiers="virtual const">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="canvas" type="RID" />
- <argument index="2" name="size" type="int" />
- <argument index="3" name="pos" type="Vector2" />
- <argument index="4" name="index" type="int" />
- <argument index="5" name="color" type="Color" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="canvas" type="RID" />
+ <param index="2" name="size" type="int" />
+ <param index="3" name="pos" type="Vector2" />
+ <param index="4" name="index" type="int" />
+ <param index="5" name="color" type="Color" />
<description>
- Draws single glyph into a canvas item at the position, using [code]font_rid[/code] at the size [code]size[/code].
+ Draws single glyph into a canvas item at the position, using [param font_rid] at the size [param size].
</description>
</method>
<method name="font_draw_glyph_outline" qualifiers="virtual const">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="canvas" type="RID" />
- <argument index="2" name="size" type="int" />
- <argument index="3" name="outline_size" type="int" />
- <argument index="4" name="pos" type="Vector2" />
- <argument index="5" name="index" type="int" />
- <argument index="6" name="color" type="Color" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="canvas" type="RID" />
+ <param index="2" name="size" type="int" />
+ <param index="3" name="outline_size" type="int" />
+ <param index="4" name="pos" type="Vector2" />
+ <param index="5" name="index" type="int" />
+ <param index="6" name="color" type="Color" />
<description>
- Draws single glyph outline of size [code]outline_size[/code] into a canvas item at the position, using [code]font_rid[/code] at the size [code]size[/code].
+ Draws single glyph outline of size [param outline_size] into a canvas item at the position, using [param font_rid] at the size [param size].
+ </description>
+ </method>
+ <method name="font_get_antialiasing" qualifiers="virtual const">
+ <return type="int" enum="TextServer.FontAntialiasing" />
+ <param index="0" name="font_rid" type="RID" />
+ <description>
+ Returns font anti-aliasing mode.
</description>
</method>
<method name="font_get_ascent" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
<description>
Returns the font ascent (number of pixels above the baseline).
</description>
</method>
<method name="font_get_descent" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
<description>
Returns the font descent (number of pixels below the baseline).
</description>
</method>
<method name="font_get_embolden" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns font embolden strength.
</description>
</method>
<method name="font_get_face_count" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns number of faces in the TrueType / OpenType collection.
</description>
</method>
<method name="font_get_face_index" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns an active face index in the TrueType / OpenType collection.
</description>
</method>
<method name="font_get_fixed_size" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns bitmap font fixed size.
</description>
</method>
<method name="font_get_generate_mipmaps" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns [code]true[/code] if font texture mipmap generation is enabled.
</description>
@@ -150,18 +157,18 @@
</method>
<method name="font_get_glyph_advance" qualifiers="virtual const">
<return type="Vector2" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="glyph" type="int" />
<description>
Returns glyph advance (offset of the next glyph).
</description>
</method>
<method name="font_get_glyph_contours" qualifiers="virtual const">
<return type="Dictionary" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="index" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="index" type="int" />
<description>
Returns outline contours of the glyph as a [code]Dictionary[/code] with the following contents:
[code]points[/code] - [PackedVector3Array], containing outline points. [code]x[/code] and [code]y[/code] are point coordinates. [code]z[/code] is the type of the point, using the [enum TextServer.ContourPointTag] values.
@@ -171,465 +178,458 @@
</method>
<method name="font_get_glyph_index" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="char" type="int" />
- <argument index="3" name="variation_selector" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="char" type="int" />
+ <param index="3" name="variation_selector" type="int" />
<description>
- Returns the glyph index of a [code]char[/code], optionally modified by the [code]variation_selector[/code].
+ Returns the glyph index of a [param char], optionally modified by the [param variation_selector].
</description>
</method>
<method name="font_get_glyph_list" qualifiers="virtual const">
- <return type="Array" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
+ <return type="PackedInt32Array" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
<description>
Returns list of rendered glyphs in the cache entry.
</description>
</method>
<method name="font_get_glyph_offset" qualifiers="virtual const">
<return type="Vector2" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
<description>
Returns glyph offset from the baseline.
</description>
</method>
<method name="font_get_glyph_size" qualifiers="virtual const">
<return type="Vector2" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
<description>
Returns size of the glyph.
</description>
</method>
<method name="font_get_glyph_texture_idx" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
<description>
Returns index of the cache texture containing the glyph.
</description>
</method>
<method name="font_get_glyph_texture_rid" qualifiers="virtual const">
<return type="RID" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
<description>
Returns resource id of the cache texture containing the glyph.
</description>
</method>
<method name="font_get_glyph_texture_size" qualifiers="virtual const">
<return type="Vector2" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
<description>
Returns size of the cache texture containing the glyph.
</description>
</method>
<method name="font_get_glyph_uv_rect" qualifiers="virtual const">
<return type="Rect2" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
<description>
Returns rectangle in the cache texture containing the glyph.
</description>
</method>
<method name="font_get_hinting" qualifiers="virtual const">
<return type="int" enum="TextServer.Hinting" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns the font hinting mode. Used by dynamic fonts only.
</description>
</method>
<method name="font_get_kerning" qualifiers="virtual const">
<return type="Vector2" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="glyph_pair" type="Vector2i" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="glyph_pair" type="Vector2i" />
<description>
Returns kerning for the pair of glyphs.
</description>
</method>
<method name="font_get_kerning_list" qualifiers="virtual const">
- <return type="Array" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
+ <return type="Vector2i[]" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
<description>
Returns list of the kerning overrides.
</description>
</method>
<method name="font_get_language_support_override" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="language" type="String" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="language" type="String" />
<description>
- Returns [code]true[/code] if support override is enabled for the [code]language[/code].
+ Returns [code]true[/code] if support override is enabled for the [param language].
</description>
</method>
<method name="font_get_language_support_overrides" qualifiers="virtual">
<return type="PackedStringArray" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns list of language support overrides.
</description>
</method>
<method name="font_get_msdf_pixel_range" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns the width of the range around the shape between the minimum and maximum representable signed distance.
</description>
</method>
<method name="font_get_msdf_size" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns source font size used to generate MSDF textures.
</description>
</method>
<method name="font_get_name" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns font family name.
</description>
</method>
<method name="font_get_opentype_feature_overrides" qualifiers="virtual const">
<return type="Dictionary" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns font OpenType feature set override.
</description>
</method>
<method name="font_get_oversampling" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns font oversampling factor, if set to [code]0.0[/code] global oversampling factor is used instead. Used by dynamic fonts only.
</description>
</method>
<method name="font_get_scale" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
<description>
Returns scaling factor of the color bitmap font.
</description>
</method>
<method name="font_get_script_support_override" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="script" type="String" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="script" type="String" />
<description>
- Returns [code]true[/code] if support override is enabled for the [code]script[/code].
+ Returns [code]true[/code] if support override is enabled for the [param script].
</description>
</method>
<method name="font_get_script_support_overrides" qualifiers="virtual">
<return type="PackedStringArray" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns list of script support overrides.
</description>
</method>
<method name="font_get_size_cache_list" qualifiers="virtual const">
- <return type="Array" />
- <argument index="0" name="font_rid" type="RID" />
+ <return type="Vector2i[]" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns list of the font sizes in the cache. Each size is [code]Vector2i[/code] with font size and outline size.
</description>
</method>
<method name="font_get_style" qualifiers="virtual const">
<return type="int" enum="TextServer.FontStyle" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns font style flags, see [enum TextServer.FontStyle].
</description>
</method>
<method name="font_get_style_name" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns font style name.
</description>
</method>
<method name="font_get_subpixel_positioning" qualifiers="virtual const">
<return type="int" enum="TextServer.SubpixelPositioning" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns font sub-pixel glyph positioning mode.
</description>
</method>
<method name="font_get_supported_chars" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns a string containing all the characters available in the font.
</description>
</method>
<method name="font_get_texture_count" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
<description>
Returns number of textures used by font cache entry.
</description>
</method>
<method name="font_get_texture_image" qualifiers="virtual const">
<return type="Image" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="texture_index" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="texture_index" type="int" />
<description>
Returns font cache texture image data.
</description>
</method>
<method name="font_get_texture_offsets" qualifiers="virtual const">
<return type="PackedInt32Array" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="texture_index" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="texture_index" type="int" />
<description>
Returns array containing the first free pixel in the each column of texture. Should be the same size as texture width or empty.
</description>
</method>
<method name="font_get_transform" qualifiers="virtual const">
<return type="Transform2D" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns 2D transform applied to the font outlines.
</description>
</method>
<method name="font_get_underline_position" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
<description>
Returns pixel offset of the underline below the baseline.
</description>
</method>
<method name="font_get_underline_thickness" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
<description>
Returns thickness of the underline in pixels.
</description>
</method>
<method name="font_get_variation_coordinates" qualifiers="virtual const">
<return type="Dictionary" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns variation coordinates for the specified font cache entry. See [method font_supported_variation_list] for more info.
</description>
</method>
<method name="font_has_char" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="char" type="int" />
- <description>
- Returns [code]true[/code] if a Unicode [code]char[/code] is available in the font.
- </description>
- </method>
- <method name="font_is_antialiased" qualifiers="virtual const">
- <return type="bool" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="char" type="int" />
<description>
- Returns [code]true[/code] if font 8-bit anitialiased glyph rendering is supported and enabled.
+ Returns [code]true[/code] if a Unicode [param char] is available in the font.
</description>
</method>
<method name="font_is_force_autohinter" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns [code]true[/code] if auto-hinting is supported and preferred over font built-in hinting. Used by dynamic fonts only.
</description>
</method>
<method name="font_is_language_supported" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="language" type="String" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="language" type="String" />
<description>
Returns [code]true[/code], if font supports given language ([url=https://en.wikipedia.org/wiki/ISO_639-1]ISO 639[/url] code).
</description>
</method>
<method name="font_is_multichannel_signed_distance_field" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns [code]true[/code] if glyphs of all sizes are rendered using single multichannel signed distance field generated from the dynamic font vector data.
</description>
</method>
<method name="font_is_script_supported" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="script" type="String" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="script" type="String" />
<description>
Returns [code]true[/code], if font supports given script (ISO 15924 code).
</description>
</method>
<method name="font_remove_glyph" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
<description>
Removes specified rendered glyph information from the cache entry.
</description>
</method>
<method name="font_remove_kerning" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="glyph_pair" type="Vector2i" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="glyph_pair" type="Vector2i" />
<description>
Removes kerning override for the pair of glyphs.
</description>
</method>
<method name="font_remove_language_support_override" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="language" type="String" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="language" type="String" />
<description>
Remove language support override.
</description>
</method>
<method name="font_remove_script_support_override" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="script" type="String" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="script" type="String" />
<description>
Removes script support override.
</description>
</method>
<method name="font_remove_size_cache" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
<description>
Removes specified font size from the cache entry.
</description>
</method>
<method name="font_remove_texture" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="texture_index" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="texture_index" type="int" />
<description>
Removes specified texture from the cache entry.
</description>
</method>
<method name="font_render_glyph" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="index" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="index" type="int" />
<description>
Renders specified glyph to the font cache texture.
</description>
</method>
<method name="font_render_range" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="start" type="int" />
- <argument index="3" name="end" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="start" type="int" />
+ <param index="3" name="end" type="int" />
<description>
Renders the range of characters to the font cache texture.
</description>
</method>
- <method name="font_set_antialiased" qualifiers="virtual">
+ <method name="font_set_antialiasing" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="antialiased" type="bool" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="antialiasing" type="int" enum="TextServer.FontAntialiasing" />
<description>
- If set to [code]true[/code], 8-bit antialiased glyph rendering is used, otherwise 1-bit rendering is used. Used by dynamic fonts only.
+ Sets font anti-aliasing mode.
</description>
</method>
<method name="font_set_ascent" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="ascent" type="float" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="ascent" type="float" />
<description>
Sets the font ascent (number of pixels above the baseline).
</description>
</method>
<method name="font_set_data" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="data" type="PackedByteArray" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="data" type="PackedByteArray" />
<description>
Sets font source data, e.g contents of the dynamic font source file.
</description>
</method>
<method name="font_set_data_ptr" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="data_ptr" type="const uint8_t*" />
- <argument index="2" name="data_size" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="data_ptr" type="const uint8_t*" />
+ <param index="2" name="data_size" type="int" />
<description>
- Sets font source data, e.g contents of the dynamic font source file. [code]data_ptr[/code] memory buffer must remain accessible during font lifetime.
+ Sets font source data, e.g contents of the dynamic font source file. [param data_ptr] memory buffer must remain accessible during font lifetime.
</description>
</method>
<method name="font_set_descent" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="descent" type="float" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="descent" type="float" />
<description>
Sets the font descent (number of pixels below the baseline).
</description>
</method>
<method name="font_set_embolden" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="strength" type="float" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="strength" type="float" />
<description>
- Sets font embolden strength. If [code]strength[/code] is not equal to zero, emboldens the font outlines. Negative values reduce the outline thickness.
+ Sets font embolden strength. If [param strength] is not equal to zero, emboldens the font outlines. Negative values reduce the outline thickness.
</description>
</method>
<method name="font_set_face_index" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="face_index" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="face_index" type="int" />
<description>
Sets an active face index in the TrueType / OpenType collection.
</description>
</method>
<method name="font_set_fixed_size" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="fixed_size" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="fixed_size" type="int" />
<description>
Sets bitmap font fixed size. If set to value greater than zero, same cache entry will be used for all font sizes.
</description>
</method>
<method name="font_set_force_autohinter" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="force_autohinter" type="bool" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="force_autohinter" type="bool" />
<description>
If set to [code]true[/code] auto-hinting is preferred over font built-in hinting.
</description>
</method>
<method name="font_set_generate_mipmaps" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="generate_mipmaps" type="bool" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="generate_mipmaps" type="bool" />
<description>
If set to [code]true[/code] font texture mipmap generation is enabled.
</description>
</method>
<method name="font_set_global_oversampling" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="oversampling" type="float" />
+ <param index="0" name="oversampling" type="float" />
<description>
Sets oversampling factor, shared by all font in the TextServer.
[b]Note:[/b] This value can be automatically changed by display server.
@@ -637,101 +637,101 @@
</method>
<method name="font_set_glyph_advance" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="glyph" type="int" />
- <argument index="3" name="advance" type="Vector2" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="glyph" type="int" />
+ <param index="3" name="advance" type="Vector2" />
<description>
Sets glyph advance (offset of the next glyph).
</description>
</method>
<method name="font_set_glyph_offset" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
- <argument index="3" name="offset" type="Vector2" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
+ <param index="3" name="offset" type="Vector2" />
<description>
Sets glyph offset from the baseline.
</description>
</method>
<method name="font_set_glyph_size" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
- <argument index="3" name="gl_size" type="Vector2" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
+ <param index="3" name="gl_size" type="Vector2" />
<description>
Sets size of the glyph.
</description>
</method>
<method name="font_set_glyph_texture_idx" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
- <argument index="3" name="texture_idx" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
+ <param index="3" name="texture_idx" type="int" />
<description>
Sets index of the cache texture containing the glyph.
</description>
</method>
<method name="font_set_glyph_uv_rect" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="glyph" type="int" />
- <argument index="3" name="uv_rect" type="Rect2" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="glyph" type="int" />
+ <param index="3" name="uv_rect" type="Rect2" />
<description>
Sets rectangle in the cache texture containing the glyph.
</description>
</method>
<method name="font_set_hinting" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="hinting" type="int" enum="TextServer.Hinting" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="hinting" type="int" enum="TextServer.Hinting" />
<description>
Sets font hinting mode. Used by dynamic fonts only.
</description>
</method>
<method name="font_set_kerning" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="glyph_pair" type="Vector2i" />
- <argument index="3" name="kerning" type="Vector2" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="glyph_pair" type="Vector2i" />
+ <param index="3" name="kerning" type="Vector2" />
<description>
Sets kerning for the pair of glyphs.
</description>
</method>
<method name="font_set_language_support_override" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="language" type="String" />
- <argument index="2" name="supported" type="bool" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="language" type="String" />
+ <param index="2" name="supported" type="bool" />
<description>
Adds override for [method font_is_language_supported].
</description>
</method>
<method name="font_set_msdf_pixel_range" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="msdf_pixel_range" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="msdf_pixel_range" type="int" />
<description>
Sets the width of the range around the shape between the minimum and maximum representable signed distance.
</description>
</method>
<method name="font_set_msdf_size" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="msdf_size" type="int" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="msdf_size" type="int" />
<description>
Sets source font size used to generate MSDF textures.
</description>
</method>
<method name="font_set_multichannel_signed_distance_field" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="msdf" type="bool" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="msdf" type="bool" />
<description>
If set to [code]true[/code], glyphs of all sizes are rendered using single multichannel signed distance field generated from the dynamic font vector data. MSDF rendering allows displaying the font at any scaling factor without blurriness, and without incurring a CPU cost when the font size changes (since the font no longer needs to be rasterized on the CPU). As a downside, font hinting is not available with MSDF. The lack of font hinting may result in less crisp and less readable fonts at small sizes.
[b]Note:[/b] MSDF font rendering does not render glyphs with overlapping shapes correctly. Overlapping shapes are not valid per the OpenType standard, but are still commonly found in many font files, especially those converted by Google Fonts. To avoid issues with overlapping glyphs, consider downloading the font file directly from the type foundry instead of relying on Google Fonts.
@@ -739,94 +739,94 @@
</method>
<method name="font_set_name" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="name" type="String" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="name" type="String" />
<description>
Sets the font family name.
</description>
</method>
<method name="font_set_opentype_feature_overrides" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="overrides" type="Dictionary" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="overrides" type="Dictionary" />
<description>
Sets font OpenType feature set override.
</description>
</method>
<method name="font_set_oversampling" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="oversampling" type="float" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="oversampling" type="float" />
<description>
Sets font oversampling factor, if set to [code]0.0[/code] global oversampling factor is used instead. Used by dynamic fonts only.
</description>
</method>
<method name="font_set_scale" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="scale" type="float" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="scale" type="float" />
<description>
Sets scaling factor of the color bitmap font.
</description>
</method>
<method name="font_set_script_support_override" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="script" type="String" />
- <argument index="2" name="supported" type="bool" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="script" type="String" />
+ <param index="2" name="supported" type="bool" />
<description>
Adds override for [method font_is_script_supported].
</description>
</method>
<method name="font_set_style" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="style" type="int" enum="TextServer.FontStyle" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="style" type="int" enum="TextServer.FontStyle" />
<description>
Sets the font style flags, see [enum TextServer.FontStyle].
</description>
</method>
<method name="font_set_style_name" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="name_style" type="String" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="name_style" type="String" />
<description>
Sets the font style name.
</description>
</method>
<method name="font_set_subpixel_positioning" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="subpixel_positioning" type="int" enum="TextServer.SubpixelPositioning" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="subpixel_positioning" type="int" enum="TextServer.SubpixelPositioning" />
<description>
Sets font sub-pixel glyph positioning mode.
</description>
</method>
<method name="font_set_texture_image" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="texture_index" type="int" />
- <argument index="3" name="image" type="Image" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="texture_index" type="int" />
+ <param index="3" name="image" type="Image" />
<description>
Sets font cache texture image data.
</description>
</method>
<method name="font_set_texture_offsets" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="texture_index" type="int" />
- <argument index="3" name="offset" type="PackedInt32Array" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="texture_index" type="int" />
+ <param index="3" name="offset" type="PackedInt32Array" />
<description>
Sets array containing the first free pixel in the each column of texture. Should be the same size as texture width or empty.
</description>
</method>
<method name="font_set_transform" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="transform" type="Transform2D" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="transform" type="Transform2D" />
<description>
Sets 2D transform, applied to the font outlines, can be used for slanting, flipping and rotating glyphs.
For example, to simulate italic typeface by slanting, apply the following transform [code]Transform2D(1.0, slant, 0.0, 1.0, 0.0, 0.0)[/code].
@@ -834,55 +834,55 @@
</method>
<method name="font_set_underline_position" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="underline_position" type="float" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="underline_position" type="float" />
<description>
Sets pixel offset of the underline below the baseline.
</description>
</method>
<method name="font_set_underline_thickness" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="size" type="int" />
- <argument index="2" name="underline_thickness" type="float" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="size" type="int" />
+ <param index="2" name="underline_thickness" type="float" />
<description>
Sets thickness of the underline in pixels.
</description>
</method>
<method name="font_set_variation_coordinates" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="font_rid" type="RID" />
- <argument index="1" name="variation_coordinates" type="Dictionary" />
+ <param index="0" name="font_rid" type="RID" />
+ <param index="1" name="variation_coordinates" type="Dictionary" />
<description>
Sets variation coordinates for the specified font cache entry. See [method font_supported_variation_list] for more info.
</description>
</method>
<method name="font_supported_feature_list" qualifiers="virtual const">
<return type="Dictionary" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns the dictionary of the supported OpenType features.
</description>
</method>
<method name="font_supported_variation_list" qualifiers="virtual const">
<return type="Dictionary" />
- <argument index="0" name="font_rid" type="RID" />
+ <param index="0" name="font_rid" type="RID" />
<description>
Returns the dictionary of the supported OpenType variation coordinates.
</description>
</method>
<method name="format_number" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="string" type="String" />
- <argument index="1" name="language" type="String" />
+ <param index="0" name="string" type="String" />
+ <param index="1" name="language" type="String" />
<description>
- Converts a number from the Western Arabic (0..9) to the numeral systems used in [code]language[/code].
+ Converts a number from the Western Arabic (0..9) to the numeral systems used in [param language].
</description>
</method>
<method name="free_rid" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="rid" type="RID" />
+ <param index="0" name="rid" type="RID" />
<description>
Frees an object created by this [TextServer].
</description>
@@ -895,8 +895,8 @@
</method>
<method name="get_hex_code_box_size" qualifiers="virtual const">
<return type="Vector2" />
- <argument index="0" name="size" type="int" />
- <argument index="1" name="index" type="int" />
+ <param index="0" name="size" type="int" />
+ <param index="1" name="index" type="int" />
<description>
Returns size of the replacement character (box with character hexadecimal code that is drawn in place of invalid characters).
[b]Note:[/b] If this method is not implemented in the plugin, the default implementation will be used.
@@ -922,65 +922,80 @@
</method>
<method name="has" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="rid" type="RID" />
+ <param index="0" name="rid" type="RID" />
<description>
- Returns [code]true[/code] if [code]rid[/code] is valid resource owned by this text server.
+ Returns [code]true[/code] if [param rid] is valid resource owned by this text server.
</description>
</method>
<method name="has_feature" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="feature" type="int" enum="TextServer.Feature" />
+ <param index="0" name="feature" type="int" enum="TextServer.Feature" />
<description>
Returns [code]true[/code] if the server supports a feature.
</description>
</method>
+ <method name="is_confusable" qualifiers="virtual const">
+ <return type="int" />
+ <param index="0" name="string" type="String" />
+ <param index="1" name="dict" type="PackedStringArray" />
+ <description>
+ Returns index of the first string in [param dict] which is visually confusable with the [param string], or [code]-1[/code] if none is found.
+ </description>
+ </method>
<method name="is_locale_right_to_left" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="locale" type="String" />
+ <param index="0" name="locale" type="String" />
<description>
Returns [code]true[/code] if locale is right-to-left.
</description>
</method>
+ <method name="is_valid_identifier" qualifiers="virtual const">
+ <return type="bool" />
+ <param index="0" name="string" type="String" />
+ <description>
+ Returns [code]true[/code] is [param string] is a valid identifier.
+ </description>
+ </method>
<method name="load_support_data" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="filename" type="String" />
+ <param index="0" name="filename" type="String" />
<description>
Loads optional TextServer database (e.g. ICU break iterators and dictionaries).
</description>
</method>
<method name="name_to_tag" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
Converts readable feature, variation, script or language name to OpenType tag.
</description>
</method>
<method name="parse_number" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="string" type="String" />
- <argument index="1" name="language" type="String" />
+ <param index="0" name="string" type="String" />
+ <param index="1" name="language" type="String" />
<description>
- Converts a number from the numeral systems used in [code]language[/code] to Western Arabic (0..9).
+ Converts a number from the numeral systems used in [param language] to Western Arabic (0..9).
</description>
</method>
<method name="parse_structured_text" qualifiers="virtual const">
- <return type="Array" />
- <argument index="0" name="parser_type" type="int" enum="TextServer.StructuredTextParser" />
- <argument index="1" name="args" type="Array" />
- <argument index="2" name="text" type="String" />
+ <return type="Vector2i[]" />
+ <param index="0" name="parser_type" type="int" enum="TextServer.StructuredTextParser" />
+ <param index="1" name="args" type="Array" />
+ <param index="2" name="text" type="String" />
<description>
</description>
</method>
<method name="percent_sign" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="language" type="String" />
+ <param index="0" name="language" type="String" />
<description>
- Returns percent sign used in the [code]language[/code].
+ Returns percent sign used in the [param language].
</description>
</method>
<method name="save_support_data" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="filename" type="String" />
+ <param index="0" name="filename" type="String" />
<description>
Saves optional TextServer database (e.g. ICU break iterators and dictionaries) to the file.
[b]Note:[/b] This function is used by during project export, to include TextServer database.
@@ -988,140 +1003,140 @@
</method>
<method name="shaped_get_span_count" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns number of text spans added using [method shaped_text_add_string] or [method shaped_text_add_object].
</description>
</method>
<method name="shaped_get_span_meta" qualifiers="virtual const">
<return type="Variant" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="index" type="int" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="index" type="int" />
<description>
Returns text span metadata.
</description>
</method>
<method name="shaped_set_span_update_font" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="index" type="int" />
- <argument index="2" name="fonts" type="Array" />
- <argument index="3" name="size" type="int" />
- <argument index="4" name="opentype_features" type="Dictionary" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="index" type="int" />
+ <param index="2" name="fonts" type="Array" />
+ <param index="3" name="size" type="int" />
+ <param index="4" name="opentype_features" type="Dictionary" />
<description>
Changes text span font, font size and OpenType features, without changing the text.
</description>
</method>
<method name="shaped_text_add_object" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="key" type="Variant" />
- <argument index="2" name="size" type="Vector2" />
- <argument index="3" name="inline_align" type="int" enum="InlineAlignment" />
- <argument index="4" name="length" type="int" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="key" type="Variant" />
+ <param index="2" name="size" type="Vector2" />
+ <param index="3" name="inline_align" type="int" enum="InlineAlignment" />
+ <param index="4" name="length" type="int" />
<description>
- Adds inline object to the text buffer, [code]key[/code] must be unique. In the text, object is represented as [code]length[/code] object replacement characters.
+ Adds inline object to the text buffer, [param key] must be unique. In the text, object is represented as [param length] object replacement characters.
</description>
</method>
<method name="shaped_text_add_string" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="text" type="String" />
- <argument index="2" name="fonts" type="Array" />
- <argument index="3" name="size" type="int" />
- <argument index="4" name="opentype_features" type="Dictionary" />
- <argument index="5" name="language" type="String" />
- <argument index="6" name="meta" type="Variant" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="text" type="String" />
+ <param index="2" name="fonts" type="Array" />
+ <param index="3" name="size" type="int" />
+ <param index="4" name="opentype_features" type="Dictionary" />
+ <param index="5" name="language" type="String" />
+ <param index="6" name="meta" type="Variant" />
<description>
Adds text span and font to draw it to the text buffer.
</description>
</method>
<method name="shaped_text_clear" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Clears text buffer (removes text and inline objects).
</description>
</method>
<method name="shaped_text_draw" qualifiers="virtual const">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="canvas" type="RID" />
- <argument index="2" name="pos" type="Vector2" />
- <argument index="3" name="clip_l" type="float" />
- <argument index="4" name="clip_r" type="float" />
- <argument index="5" name="color" type="Color" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="canvas" type="RID" />
+ <param index="2" name="pos" type="Vector2" />
+ <param index="3" name="clip_l" type="float" />
+ <param index="4" name="clip_r" type="float" />
+ <param index="5" name="color" type="Color" />
<description>
- Draw shaped text into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the leftmost point of the baseline (for horizontal layout) or topmost point of the baseline (for vertical layout).
+ Draw shaped text into a canvas item at a given position, with [param color]. [param pos] specifies the leftmost point of the baseline (for horizontal layout) or topmost point of the baseline (for vertical layout).
[b]Note:[/b] If this method is not implemented in the plugin, the default implementation will be used.
</description>
</method>
<method name="shaped_text_draw_outline" qualifiers="virtual const">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="canvas" type="RID" />
- <argument index="2" name="pos" type="Vector2" />
- <argument index="3" name="clip_l" type="float" />
- <argument index="4" name="clip_r" type="float" />
- <argument index="5" name="outline_size" type="int" />
- <argument index="6" name="color" type="Color" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="canvas" type="RID" />
+ <param index="2" name="pos" type="Vector2" />
+ <param index="3" name="clip_l" type="float" />
+ <param index="4" name="clip_r" type="float" />
+ <param index="5" name="outline_size" type="int" />
+ <param index="6" name="color" type="Color" />
<description>
- Draw the outline of the shaped text into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the leftmost point of the baseline (for horizontal layout) or topmost point of the baseline (for vertical layout).
+ Draw the outline of the shaped text into a canvas item at a given position, with [param color]. [param pos] specifies the leftmost point of the baseline (for horizontal layout) or topmost point of the baseline (for vertical layout).
[b]Note:[/b] If this method is not implemented in the plugin, the default implementation will be used.
</description>
</method>
<method name="shaped_text_fit_to_width" qualifiers="virtual">
<return type="float" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="width" type="float" />
- <argument index="2" name="jst_flags" type="int" enum="TextServer.JustificationFlag" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="width" type="float" />
+ <param index="2" name="jst_flags" type="int" enum="TextServer.JustificationFlag" />
<description>
Adjusts text with to fit to specified width, returns new text width.
</description>
</method>
<method name="shaped_text_get_ascent" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns the text ascent (number of pixels above the baseline for horizontal layout or to the left of baseline for vertical).
</description>
</method>
<method name="shaped_text_get_carets" qualifiers="virtual const">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="position" type="int" />
- <argument index="2" name="caret" type="CaretInfo*" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="position" type="int" />
+ <param index="2" name="caret" type="CaretInfo*" />
<description>
- Returns shapes of the carets corresponding to the character offset [code]position[/code] in the text. Returned caret shape is 1 pixel wide rectangle.
+ Returns shapes of the carets corresponding to the character offset [param position] in the text. Returned caret shape is 1 pixel wide rectangle.
[b]Note:[/b] If this method is not implemented in the plugin, the default implementation will be used.
</description>
</method>
<method name="shaped_text_get_custom_punctuation" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns custom punctuation character list, used for word breaking. If set to empty string, server defaults are used.
</description>
</method>
<method name="shaped_text_get_descent" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns the text descent (number of pixels below the baseline for horizontal layout or to the right of baseline for vertical).
</description>
</method>
<method name="shaped_text_get_direction" qualifiers="virtual const">
<return type="int" enum="TextServer.Direction" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns direction of the text.
</description>
</method>
<method name="shaped_text_get_dominant_direction_in_range" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="start" type="int" />
- <argument index="2" name="end" type="int" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="start" type="int" />
+ <param index="2" name="end" type="int" />
<description>
Returns dominant direction of in the range of text.
[b]Note:[/b] If this method is not implemented in the plugin, the default implementation will be used.
@@ -1129,43 +1144,43 @@
</method>
<method name="shaped_text_get_ellipsis_glyph_count" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns number of glyphs in the ellipsis.
</description>
</method>
<method name="shaped_text_get_ellipsis_glyphs" qualifiers="virtual const">
<return type="const Glyph*" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns array of the glyphs in the ellipsis.
</description>
</method>
<method name="shaped_text_get_ellipsis_pos" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns position of the ellipsis.
</description>
</method>
<method name="shaped_text_get_glyph_count" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns number of glyphs in the buffer.
</description>
</method>
<method name="shaped_text_get_glyphs" qualifiers="virtual const">
<return type="const Glyph*" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns an array of glyphs in the visual order.
</description>
</method>
<method name="shaped_text_get_grapheme_bounds" qualifiers="virtual const">
<return type="Vector2" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="pos" type="int" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="pos" type="int" />
<description>
Returns composite character's bounds as offsets from the start of the line.
[b]Note:[/b] If this method is not implemented in the plugin, the default implementation will be used.
@@ -1173,17 +1188,17 @@
</method>
<method name="shaped_text_get_inferred_direction" qualifiers="virtual const">
<return type="int" enum="TextServer.Direction" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns direction of the text, inferred by the BiDi algorithm.
</description>
</method>
<method name="shaped_text_get_line_breaks" qualifiers="virtual const">
<return type="PackedInt32Array" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="width" type="float" />
- <argument index="2" name="start" type="int" />
- <argument index="3" name="break_flags" type="int" enum="TextServer.LineBreakFlag" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="width" type="float" />
+ <param index="2" name="start" type="int" />
+ <param index="3" name="break_flags" type="int" enum="TextServer.LineBreakFlag" />
<description>
Breaks text to the lines and returns character ranges for each line.
[b]Note:[/b] If this method is not implemented in the plugin, the default implementation will be used.
@@ -1191,11 +1206,11 @@
</method>
<method name="shaped_text_get_line_breaks_adv" qualifiers="virtual const">
<return type="PackedInt32Array" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="width" type="PackedFloat32Array" />
- <argument index="2" name="start" type="int" />
- <argument index="3" name="once" type="bool" />
- <argument index="4" name="break_flags" type="int" enum="TextServer.LineBreakFlag" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="width" type="PackedFloat32Array" />
+ <param index="2" name="start" type="int" />
+ <param index="3" name="once" type="bool" />
+ <param index="4" name="break_flags" type="int" enum="TextServer.LineBreakFlag" />
<description>
Breaks text to the lines and columns. Returns character ranges for each segment.
[b]Note:[/b] If this method is not implemented in the plugin, the default implementation will be used.
@@ -1203,43 +1218,43 @@
</method>
<method name="shaped_text_get_object_rect" qualifiers="virtual const">
<return type="Rect2" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="key" type="Variant" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="key" type="Variant" />
<description>
Returns bounding rectangle of the inline object.
</description>
</method>
<method name="shaped_text_get_objects" qualifiers="virtual const">
<return type="Array" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns array of inline objects.
</description>
</method>
<method name="shaped_text_get_orientation" qualifiers="virtual const">
<return type="int" enum="TextServer.Orientation" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
eturns text orientation.
</description>
</method>
<method name="shaped_text_get_parent" qualifiers="virtual const">
<return type="RID" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns the parent buffer from which the substring originates.
</description>
</method>
<method name="shaped_text_get_preserve_control" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns [code]true[/code] if text buffer is configured to display control characters.
</description>
</method>
<method name="shaped_text_get_preserve_invalid" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns [code]true[/code] if text buffer is configured to display hexadecimal codes in place of invalid characters.
[b]Note:[/b] If set to [code]false[/code], nothing is displayed in place of invalid characters.
@@ -1247,16 +1262,16 @@
</method>
<method name="shaped_text_get_range" qualifiers="virtual const">
<return type="Vector2i" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns substring buffer character range in the parent buffer.
</description>
</method>
<method name="shaped_text_get_selection" qualifiers="virtual const">
<return type="PackedVector2Array" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="start" type="int" />
- <argument index="2" name="end" type="int" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="start" type="int" />
+ <param index="2" name="end" type="int" />
<description>
Returns selection rectangles for the specified character range.
[b]Note:[/b] If this method is not implemented in the plugin, the default implementation will be used.
@@ -1264,51 +1279,51 @@
</method>
<method name="shaped_text_get_size" qualifiers="virtual const">
<return type="Vector2" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns size of the text.
</description>
</method>
<method name="shaped_text_get_spacing" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="spacing" type="int" enum="TextServer.SpacingType" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="spacing" type="int" enum="TextServer.SpacingType" />
<description>
Returns extra spacing added between glyphs or lines in pixels.
</description>
</method>
<method name="shaped_text_get_trim_pos" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns the position of the overrun trim.
</description>
</method>
<method name="shaped_text_get_underline_position" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns pixel offset of the underline below the baseline.
</description>
</method>
<method name="shaped_text_get_underline_thickness" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns thickness of the underline.
</description>
</method>
<method name="shaped_text_get_width" qualifiers="virtual const">
<return type="float" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns width (for horizontal layout) or height (for vertical) of the text.
</description>
</method>
<method name="shaped_text_get_word_breaks" qualifiers="virtual const">
<return type="PackedInt32Array" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="grapheme_flags" type="int" enum="TextServer.GraphemeFlag" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="grapheme_flags" type="int" enum="TextServer.GraphemeFlag" />
<description>
Breaks text into words and returns array of character ranges.
[b]Note:[/b] If this method is not implemented in the plugin, the default implementation will be used.
@@ -1316,8 +1331,8 @@
</method>
<method name="shaped_text_hit_test_grapheme" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="coord" type="float" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="coord" type="float" />
<description>
Returns grapheme index at the specified pixel offset at the baseline, or [code]-1[/code] if none is found.
[b]Note:[/b] If this method is not implemented in the plugin, the default implementation will be used.
@@ -1325,8 +1340,8 @@
</method>
<method name="shaped_text_hit_test_position" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="coord" type="float" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="coord" type="float" />
<description>
Returns caret character offset at the specified pixel offset at the baseline. This function always returns a valid position.
[b]Note:[/b] If this method is not implemented in the plugin, the default implementation will be used.
@@ -1334,52 +1349,52 @@
</method>
<method name="shaped_text_is_ready" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns [code]true[/code] if buffer is successfully shaped.
</description>
</method>
<method name="shaped_text_next_grapheme_pos" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="pos" type="int" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="pos" type="int" />
<description>
- Returns composite character end position closest to the [code]pos[/code].
+ Returns composite character end position closest to the [param pos].
[b]Note:[/b] If this method is not implemented in the plugin, the default implementation will be used.
</description>
</method>
<method name="shaped_text_overrun_trim_to_width" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="width" type="float" />
- <argument index="2" name="trim_flags" type="int" enum="TextServer.TextOverrunFlag" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="width" type="float" />
+ <param index="2" name="trim_flags" type="int" enum="TextServer.TextOverrunFlag" />
<description>
Trims text if it exceeds the given width.
</description>
</method>
<method name="shaped_text_prev_grapheme_pos" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="pos" type="int" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="pos" type="int" />
<description>
- Returns composite character start position closest to the [code]pos[/code].
+ Returns composite character start position closest to the [param pos].
[b]Note:[/b] If this method is not implemented in the plugin, the default implementation will be used.
</description>
</method>
<method name="shaped_text_resize_object" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="key" type="Variant" />
- <argument index="2" name="size" type="Vector2" />
- <argument index="3" name="inline_align" type="int" enum="InlineAlignment" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="key" type="Variant" />
+ <param index="2" name="size" type="Vector2" />
+ <param index="3" name="inline_align" type="int" enum="InlineAlignment" />
<description>
Sets new size and alignment of embedded object.
</description>
</method>
<method name="shaped_text_set_bidi_override" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="override" type="Array" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="override" type="Array" />
<description>
Overrides BiDi for the structured text.
Override ranges should cover full source text without overlaps. BiDi algorithm will be used on each range separately.
@@ -1387,87 +1402,87 @@
</method>
<method name="shaped_text_set_custom_punctuation" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="punct" type="String" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="punct" type="String" />
<description>
Sets custom punctuation character list, used for word breaking. If set to empty string, server defaults are used.
</description>
</method>
<method name="shaped_text_set_direction" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="direction" type="int" enum="TextServer.Direction" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="direction" type="int" enum="TextServer.Direction" />
<description>
- Sets desired text direction. If set to [code]TEXT_DIRECTION_AUTO[/code], direction will be detected based on the buffer contents and current locale.
+ Sets desired text [param direction]. If set to [code]TEXT_DIRECTION_AUTO[/code], direction will be detected based on the buffer contents and current locale.
</description>
</method>
<method name="shaped_text_set_orientation" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="orientation" type="int" enum="TextServer.Orientation" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="orientation" type="int" enum="TextServer.Orientation" />
<description>
Sets desired text orientation.
</description>
</method>
<method name="shaped_text_set_preserve_control" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="enabled" type="bool" />
<description>
If set to [code]true[/code] text buffer will display control characters.
</description>
</method>
<method name="shaped_text_set_preserve_invalid" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="enabled" type="bool" />
<description>
If set to [code]true[/code] text buffer will display invalid characters as hexadecimal codes, otherwise nothing is displayed.
</description>
</method>
<method name="shaped_text_set_spacing" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="spacing" type="int" enum="TextServer.SpacingType" />
- <argument index="2" name="value" type="int" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="spacing" type="int" enum="TextServer.SpacingType" />
+ <param index="2" name="value" type="int" />
<description>
Sets extra spacing added between glyphs or lines in pixels.
</description>
</method>
<method name="shaped_text_shape" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Shapes buffer if it's not shaped. Returns [code]true[/code] if the string is shaped successfully.
</description>
</method>
<method name="shaped_text_sort_logical" qualifiers="virtual">
<return type="const Glyph*" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Returns text glyphs in the logical order.
</description>
</method>
<method name="shaped_text_substr" qualifiers="virtual const">
<return type="RID" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="start" type="int" />
- <argument index="2" name="length" type="int" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="start" type="int" />
+ <param index="2" name="length" type="int" />
<description>
- Returns text buffer for the substring of the text in the [code]shaped[/code] text buffer (including inline objects).
+ Returns text buffer for the substring of the text in the [param shaped] text buffer (including inline objects).
</description>
</method>
<method name="shaped_text_tab_align" qualifiers="virtual">
<return type="float" />
- <argument index="0" name="shaped" type="RID" />
- <argument index="1" name="tab_stops" type="PackedFloat32Array" />
+ <param index="0" name="shaped" type="RID" />
+ <param index="1" name="tab_stops" type="PackedFloat32Array" />
<description>
Aligns shaped text to the given tab-stops.
</description>
</method>
<method name="shaped_text_update_breaks" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Updates line breaking positions in the text buffer.
[b]Note:[/b] This method is used by default line/word breaking methods, and its implementation might be omitted if custom line breaking in implemented.
@@ -1475,39 +1490,46 @@
</method>
<method name="shaped_text_update_justification_ops" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="shaped" type="RID" />
+ <param index="0" name="shaped" type="RID" />
<description>
Updates line justification positions (word breaks and elongations) in the text buffer.
[b]Note:[/b] This method is used by default line/word breaking methods, and its implementation might be omitted if custom line breaking in implemented.
</description>
</method>
+ <method name="spoof_check" qualifiers="virtual const">
+ <return type="bool" />
+ <param index="0" name="string" type="String" />
+ <description>
+ Returns [code]true[/code] if [param string] is likely to be an attempt at confusing the reader.
+ </description>
+ </method>
<method name="string_get_word_breaks" qualifiers="virtual const">
<return type="PackedInt32Array" />
- <argument index="0" name="string" type="String" />
- <argument index="1" name="language" type="String" />
+ <param index="0" name="string" type="String" />
+ <param index="1" name="language" type="String" />
<description>
Returns array of the word break character offsets.
</description>
</method>
<method name="string_to_lower" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="string" type="String" />
- <argument index="1" name="language" type="String" />
+ <param index="0" name="string" type="String" />
+ <param index="1" name="language" type="String" />
<description>
Returns the string converted to lowercase.
</description>
</method>
<method name="string_to_upper" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="string" type="String" />
- <argument index="1" name="language" type="String" />
+ <param index="0" name="string" type="String" />
+ <param index="1" name="language" type="String" />
<description>
Returns the string converted to uppercase.
</description>
</method>
<method name="strip_diacritics" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="string" type="String" />
+ <param index="0" name="string" type="String" />
<description>
Strips diacritics from the string.
[b]Note:[/b] If this method is not implemented in the plugin, the default implementation will be used.
@@ -1515,7 +1537,7 @@
</method>
<method name="tag_to_name" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="tag" type="int" />
+ <param index="0" name="tag" type="int" />
<description>
Converts OpenType tag to readable feature, variation, script or language name.
</description>
diff --git a/doc/classes/TextServerManager.xml b/doc/classes/TextServerManager.xml
index 7eff19038c..9477e5ec54 100644
--- a/doc/classes/TextServerManager.xml
+++ b/doc/classes/TextServerManager.xml
@@ -12,21 +12,21 @@
<methods>
<method name="add_interface">
<return type="void" />
- <argument index="0" name="interface" type="TextServer" />
+ <param index="0" name="interface" type="TextServer" />
<description>
Registers an [TextServer] interface.
</description>
</method>
<method name="find_interface" qualifiers="const">
<return type="TextServer" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
Finds an interface by its name.
</description>
</method>
<method name="get_interface" qualifiers="const">
<return type="TextServer" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns the interface registered at a given index.
</description>
@@ -38,7 +38,7 @@
</description>
</method>
<method name="get_interfaces" qualifiers="const">
- <return type="Array" />
+ <return type="Dictionary[]" />
<description>
Returns a list of available interfaces the index and name of each interface.
</description>
@@ -51,14 +51,14 @@
</method>
<method name="remove_interface">
<return type="void" />
- <argument index="0" name="interface" type="TextServer" />
+ <param index="0" name="interface" type="TextServer" />
<description>
Removes interface. All fonts and shaped text caches should be freed before removing interface.
</description>
</method>
<method name="set_primary_interface">
<return type="void" />
- <argument index="0" name="index" type="TextServer" />
+ <param index="0" name="index" type="TextServer" />
<description>
Sets the primary [TextServer] interface.
</description>
@@ -66,13 +66,13 @@
</methods>
<signals>
<signal name="interface_added">
- <argument index="0" name="interface_name" type="StringName" />
+ <param index="0" name="interface_name" type="StringName" />
<description>
Emitted when a new interface has been added.
</description>
</signal>
<signal name="interface_removed">
- <argument index="0" name="interface_name" type="StringName" />
+ <param index="0" name="interface_name" type="StringName" />
<description>
Emitted when an interface is removed.
</description>
diff --git a/doc/classes/Texture2D.xml b/doc/classes/Texture2D.xml
index 3721058d25..14e89a1b74 100644
--- a/doc/classes/Texture2D.xml
+++ b/doc/classes/Texture2D.xml
@@ -14,31 +14,31 @@
<methods>
<method name="_draw" qualifiers="virtual const">
<return type="void" />
- <argument index="0" name="to_canvas_item" type="RID" />
- <argument index="1" name="pos" type="Vector2" />
- <argument index="2" name="modulate" type="Color" />
- <argument index="3" name="transpose" type="bool" />
+ <param index="0" name="to_canvas_item" type="RID" />
+ <param index="1" name="pos" type="Vector2" />
+ <param index="2" name="modulate" type="Color" />
+ <param index="3" name="transpose" type="bool" />
<description>
</description>
</method>
<method name="_draw_rect" qualifiers="virtual const">
<return type="void" />
- <argument index="0" name="to_canvas_item" type="RID" />
- <argument index="1" name="rect" type="Rect2" />
- <argument index="2" name="tile" type="bool" />
- <argument index="3" name="modulate" type="Color" />
- <argument index="4" name="transpose" type="bool" />
+ <param index="0" name="to_canvas_item" type="RID" />
+ <param index="1" name="rect" type="Rect2" />
+ <param index="2" name="tile" type="bool" />
+ <param index="3" name="modulate" type="Color" />
+ <param index="4" name="transpose" type="bool" />
<description>
</description>
</method>
<method name="_draw_rect_region" qualifiers="virtual const">
<return type="void" />
- <argument index="0" name="tp_canvas_item" type="RID" />
- <argument index="1" name="rect" type="Rect2" />
- <argument index="2" name="src_rect" type="Rect2" />
- <argument index="3" name="modulate" type="Color" />
- <argument index="4" name="transpose" type="bool" />
- <argument index="5" name="clip_uv" type="bool" />
+ <param index="0" name="tp_canvas_item" type="RID" />
+ <param index="1" name="rect" type="Rect2" />
+ <param index="2" name="src_rect" type="Rect2" />
+ <param index="3" name="modulate" type="Color" />
+ <param index="4" name="transpose" type="bool" />
+ <param index="5" name="clip_uv" type="bool" />
<description>
</description>
</method>
@@ -59,40 +59,40 @@
</method>
<method name="_is_pixel_opaque" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="x" type="int" />
- <argument index="1" name="y" type="int" />
+ <param index="0" name="x" type="int" />
+ <param index="1" name="y" type="int" />
<description>
</description>
</method>
<method name="draw" qualifiers="const">
<return type="void" />
- <argument index="0" name="canvas_item" type="RID" />
- <argument index="1" name="position" type="Vector2" />
- <argument index="2" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="3" name="transpose" type="bool" default="false" />
+ <param index="0" name="canvas_item" type="RID" />
+ <param index="1" name="position" type="Vector2" />
+ <param index="2" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="3" name="transpose" type="bool" default="false" />
<description>
- Draws the texture using a [CanvasItem] with the [RenderingServer] API at the specified [code]position[/code].
+ Draws the texture using a [CanvasItem] with the [RenderingServer] API at the specified [param position].
</description>
</method>
<method name="draw_rect" qualifiers="const">
<return type="void" />
- <argument index="0" name="canvas_item" type="RID" />
- <argument index="1" name="rect" type="Rect2" />
- <argument index="2" name="tile" type="bool" />
- <argument index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="4" name="transpose" type="bool" default="false" />
+ <param index="0" name="canvas_item" type="RID" />
+ <param index="1" name="rect" type="Rect2" />
+ <param index="2" name="tile" type="bool" />
+ <param index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="4" name="transpose" type="bool" default="false" />
<description>
Draws the texture using a [CanvasItem] with the [RenderingServer] API.
</description>
</method>
<method name="draw_rect_region" qualifiers="const">
<return type="void" />
- <argument index="0" name="canvas_item" type="RID" />
- <argument index="1" name="rect" type="Rect2" />
- <argument index="2" name="src_rect" type="Rect2" />
- <argument index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
- <argument index="4" name="transpose" type="bool" default="false" />
- <argument index="5" name="clip_uv" type="bool" default="true" />
+ <param index="0" name="canvas_item" type="RID" />
+ <param index="1" name="rect" type="Rect2" />
+ <param index="2" name="src_rect" type="Rect2" />
+ <param index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)" />
+ <param index="4" name="transpose" type="bool" default="false" />
+ <param index="5" name="clip_uv" type="bool" default="true" />
<description>
Draws a part of the texture using a [CanvasItem] with the [RenderingServer] API.
</description>
diff --git a/doc/classes/TextureLayered.xml b/doc/classes/TextureLayered.xml
index 3445329f32..7b528e2082 100644
--- a/doc/classes/TextureLayered.xml
+++ b/doc/classes/TextureLayered.xml
@@ -21,7 +21,7 @@
</method>
<method name="_get_layer_data" qualifiers="virtual const">
<return type="Image" />
- <argument index="0" name="layer_index" type="int" />
+ <param index="0" name="layer_index" type="int" />
<description>
</description>
</method>
@@ -59,9 +59,9 @@
</method>
<method name="get_layer_data" qualifiers="const">
<return type="Image" />
- <argument index="0" name="layer" type="int" />
+ <param index="0" name="layer" type="int" />
<description>
- Returns an [Image] resource with the data from specified [code]layer[/code].
+ Returns an [Image] resource with the data from specified [param layer].
</description>
</method>
<method name="get_layered_type" qualifiers="const">
diff --git a/doc/classes/TextureProgressBar.xml b/doc/classes/TextureProgressBar.xml
index 4ea072a25f..fcdb18e10d 100644
--- a/doc/classes/TextureProgressBar.xml
+++ b/doc/classes/TextureProgressBar.xml
@@ -11,14 +11,14 @@
<methods>
<method name="get_stretch_margin" qualifiers="const">
<return type="int" />
- <argument index="0" name="margin" type="int" enum="Side" />
+ <param index="0" name="margin" type="int" enum="Side" />
<description>
</description>
</method>
<method name="set_stretch_margin">
<return type="void" />
- <argument index="0" name="margin" type="int" enum="Side" />
- <argument index="1" name="value" type="int" />
+ <param index="0" name="margin" type="int" enum="Side" />
+ <param index="1" name="value" type="int" />
<description>
</description>
</method>
diff --git a/doc/classes/Theme.xml b/doc/classes/Theme.xml
index 7f4e0645c8..7fc01ea353 100644
--- a/doc/classes/Theme.xml
+++ b/doc/classes/Theme.xml
@@ -15,7 +15,7 @@
<methods>
<method name="add_type">
<return type="void" />
- <argument index="0" name="theme_type" type="StringName" />
+ <param index="0" name="theme_type" type="StringName" />
<description>
Adds an empty theme type for every valid data type.
[b]Note:[/b] Empty types are not saved with the theme. This method only exists to perform in-memory changes to the resource. Use available [code]set_*[/code] methods to add theme items.
@@ -29,90 +29,90 @@
</method>
<method name="clear_color">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
<description>
- Removes the [Color] property defined by [code]name[/code] and [code]theme_type[/code], if it exists.
+ Removes the [Color] property defined by [param name] and [param theme_type], if it exists.
Fails if it doesn't exist. Use [method has_color] to check for existence.
</description>
</method>
<method name="clear_constant">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
<description>
- Removes the constant property defined by [code]name[/code] and [code]theme_type[/code], if it exists.
+ Removes the constant property defined by [param name] and [param theme_type], if it exists.
Fails if it doesn't exist. Use [method has_constant] to check for existence.
</description>
</method>
<method name="clear_font">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
<description>
- Removes the [Font] property defined by [code]name[/code] and [code]theme_type[/code], if it exists.
+ Removes the [Font] property defined by [param name] and [param theme_type], if it exists.
Fails if it doesn't exist. Use [method has_font] to check for existence.
</description>
</method>
<method name="clear_font_size">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
<description>
- Removes the font size property defined by [code]name[/code] and [code]theme_type[/code], if it exists.
+ Removes the font size property defined by [param name] and [param theme_type], if it exists.
Fails if it doesn't exist. Use [method has_font_size] to check for existence.
</description>
</method>
<method name="clear_icon">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
<description>
- Removes the icon property defined by [code]name[/code] and [code]theme_type[/code], if it exists.
+ Removes the icon property defined by [param name] and [param theme_type], if it exists.
Fails if it doesn't exist. Use [method has_icon] to check for existence.
</description>
</method>
<method name="clear_stylebox">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
<description>
- Removes the [StyleBox] property defined by [code]name[/code] and [code]theme_type[/code], if it exists.
+ Removes the [StyleBox] property defined by [param name] and [param theme_type], if it exists.
Fails if it doesn't exist. Use [method has_stylebox] to check for existence.
</description>
</method>
<method name="clear_theme_item">
<return type="void" />
- <argument index="0" name="data_type" type="int" enum="Theme.DataType" />
- <argument index="1" name="name" type="StringName" />
- <argument index="2" name="theme_type" type="StringName" />
+ <param index="0" name="data_type" type="int" enum="Theme.DataType" />
+ <param index="1" name="name" type="StringName" />
+ <param index="2" name="theme_type" type="StringName" />
<description>
- Removes the theme property of [code]data_type[/code] defined by [code]name[/code] and [code]theme_type[/code], if it exists.
+ Removes the theme property of [param data_type] defined by [param name] and [param theme_type], if it exists.
Fails if it doesn't exist. Use [method has_theme_item] to check for existence.
[b]Note:[/b] This method is analogous to calling the corresponding data type specific method, but can be used for more generalized logic.
</description>
</method>
<method name="clear_type_variation">
<return type="void" />
- <argument index="0" name="theme_type" type="StringName" />
+ <param index="0" name="theme_type" type="StringName" />
<description>
- Unmarks [code]theme_type[/code] as being a variation of another theme type. See [method set_type_variation].
+ Unmarks [param theme_type] as being a variation of another theme type. See [method set_type_variation].
</description>
</method>
<method name="get_color" qualifiers="const">
<return type="Color" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
<description>
- Returns the [Color] property defined by [code]name[/code] and [code]theme_type[/code], if it exists.
+ Returns the [Color] property defined by [param name] and [param theme_type], if it exists.
Returns the default color value if the property doesn't exist. Use [method has_color] to check for existence.
</description>
</method>
<method name="get_color_list" qualifiers="const">
<return type="PackedStringArray" />
- <argument index="0" name="theme_type" type="String" />
+ <param index="0" name="theme_type" type="String" />
<description>
- Returns a list of names for [Color] properties defined with [code]theme_type[/code]. Use [method get_color_type_list] to get a list of possible theme type names.
+ Returns a list of names for [Color] properties defined with [param theme_type]. Use [method get_color_type_list] to get a list of possible theme type names.
</description>
</method>
<method name="get_color_type_list" qualifiers="const">
@@ -123,18 +123,18 @@
</method>
<method name="get_constant" qualifiers="const">
<return type="int" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
<description>
- Returns the constant property defined by [code]name[/code] and [code]theme_type[/code], if it exists.
+ Returns the constant property defined by [param name] and [param theme_type], if it exists.
Returns [code]0[/code] if the property doesn't exist. Use [method has_constant] to check for existence.
</description>
</method>
<method name="get_constant_list" qualifiers="const">
<return type="PackedStringArray" />
- <argument index="0" name="theme_type" type="String" />
+ <param index="0" name="theme_type" type="String" />
<description>
- Returns a list of names for constant properties defined with [code]theme_type[/code]. Use [method get_constant_type_list] to get a list of possible theme type names.
+ Returns a list of names for constant properties defined with [param theme_type]. Use [method get_constant_type_list] to get a list of possible theme type names.
</description>
</method>
<method name="get_constant_type_list" qualifiers="const">
@@ -145,36 +145,36 @@
</method>
<method name="get_font" qualifiers="const">
<return type="Font" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
<description>
- Returns the [Font] property defined by [code]name[/code] and [code]theme_type[/code], if it exists.
+ Returns the [Font] property defined by [param name] and [param theme_type], if it exists.
Returns the default theme font if the property doesn't exist and the default theme font is set up (see [member default_font]). Use [method has_font] to check for existence of the property and [method has_default_font] to check for existence of the default theme font.
- Returns the engine fallback font value, if neither exist.
+ Returns the engine fallback font value, if neither exist (see [member ThemeDB.fallback_font]).
</description>
</method>
<method name="get_font_list" qualifiers="const">
<return type="PackedStringArray" />
- <argument index="0" name="theme_type" type="String" />
+ <param index="0" name="theme_type" type="String" />
<description>
- Returns a list of names for [Font] properties defined with [code]theme_type[/code]. Use [method get_font_type_list] to get a list of possible theme type names.
+ Returns a list of names for [Font] properties defined with [param theme_type]. Use [method get_font_type_list] to get a list of possible theme type names.
</description>
</method>
<method name="get_font_size" qualifiers="const">
<return type="int" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
<description>
- Returns the font size property defined by [code]name[/code] and [code]theme_type[/code], if it exists.
+ Returns the font size property defined by [param name] and [param theme_type], if it exists.
Returns the default theme font size if the property doesn't exist and the default theme font size is set up (see [member default_font_size]). Use [method has_font_size] to check for existence of the property and [method has_default_font_size] to check for existence of the default theme font.
- Returns the engine fallback font size value, if neither exist.
+ Returns the engine fallback font size value, if neither exist (see [member ThemeDB.fallback_font_size]).
</description>
</method>
<method name="get_font_size_list" qualifiers="const">
<return type="PackedStringArray" />
- <argument index="0" name="theme_type" type="String" />
+ <param index="0" name="theme_type" type="String" />
<description>
- Returns a list of names for font size properties defined with [code]theme_type[/code]. Use [method get_font_size_type_list] to get a list of possible theme type names.
+ Returns a list of names for font size properties defined with [param theme_type]. Use [method get_font_size_type_list] to get a list of possible theme type names.
</description>
</method>
<method name="get_font_size_type_list" qualifiers="const">
@@ -191,18 +191,18 @@
</method>
<method name="get_icon" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
<description>
- Returns the icon property defined by [code]name[/code] and [code]theme_type[/code], if it exists.
- Returns the engine fallback icon value if the property doesn't exist. Use [method has_icon] to check for existence.
+ Returns the icon property defined by [param name] and [param theme_type], if it exists.
+ Returns the engine fallback icon value if the property doesn't exist (see [member ThemeDB.fallback_icon]). Use [method has_icon] to check for existence.
</description>
</method>
<method name="get_icon_list" qualifiers="const">
<return type="PackedStringArray" />
- <argument index="0" name="theme_type" type="String" />
+ <param index="0" name="theme_type" type="String" />
<description>
- Returns a list of names for icon properties defined with [code]theme_type[/code]. Use [method get_icon_type_list] to get a list of possible theme type names.
+ Returns a list of names for icon properties defined with [param theme_type]. Use [method get_icon_type_list] to get a list of possible theme type names.
</description>
</method>
<method name="get_icon_type_list" qualifiers="const">
@@ -213,18 +213,18 @@
</method>
<method name="get_stylebox" qualifiers="const">
<return type="StyleBox" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
<description>
- Returns the [StyleBox] property defined by [code]name[/code] and [code]theme_type[/code], if it exists.
- Returns the engine fallback stylebox value if the property doesn't exist. Use [method has_stylebox] to check for existence.
+ Returns the [StyleBox] property defined by [param name] and [param theme_type], if it exists.
+ Returns the engine fallback stylebox value if the property doesn't exist (see [member ThemeDB.fallback_stylebox]). Use [method has_stylebox] to check for existence.
</description>
</method>
<method name="get_stylebox_list" qualifiers="const">
<return type="PackedStringArray" />
- <argument index="0" name="theme_type" type="String" />
+ <param index="0" name="theme_type" type="String" />
<description>
- Returns a list of names for [StyleBox] properties defined with [code]theme_type[/code]. Use [method get_stylebox_type_list] to get a list of possible theme type names.
+ Returns a list of names for [StyleBox] properties defined with [param theme_type]. Use [method get_stylebox_type_list] to get a list of possible theme type names.
</description>
</method>
<method name="get_stylebox_type_list" qualifiers="const">
@@ -235,29 +235,29 @@
</method>
<method name="get_theme_item" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="data_type" type="int" enum="Theme.DataType" />
- <argument index="1" name="name" type="StringName" />
- <argument index="2" name="theme_type" type="StringName" />
+ <param index="0" name="data_type" type="int" enum="Theme.DataType" />
+ <param index="1" name="name" type="StringName" />
+ <param index="2" name="theme_type" type="StringName" />
<description>
- Returns the theme property of [code]data_type[/code] defined by [code]name[/code] and [code]theme_type[/code], if it exists.
- Returns the engine fallback icon value if the property doesn't exist. Use [method has_theme_item] to check for existence.
+ Returns the theme property of [param data_type] defined by [param name] and [param theme_type], if it exists.
+ Returns the engine fallback icon value if the property doesn't exist (see [ThemeDB]). Use [method has_theme_item] to check for existence.
[b]Note:[/b] This method is analogous to calling the corresponding data type specific method, but can be used for more generalized logic.
</description>
</method>
<method name="get_theme_item_list" qualifiers="const">
<return type="PackedStringArray" />
- <argument index="0" name="data_type" type="int" enum="Theme.DataType" />
- <argument index="1" name="theme_type" type="String" />
+ <param index="0" name="data_type" type="int" enum="Theme.DataType" />
+ <param index="1" name="theme_type" type="String" />
<description>
- Returns a list of names for properties of [code]data_type[/code] defined with [code]theme_type[/code]. Use [method get_theme_item_type_list] to get a list of possible theme type names.
+ Returns a list of names for properties of [param data_type] defined with [param theme_type]. Use [method get_theme_item_type_list] to get a list of possible theme type names.
[b]Note:[/b] This method is analogous to calling the corresponding data type specific method, but can be used for more generalized logic.
</description>
</method>
<method name="get_theme_item_type_list" qualifiers="const">
<return type="PackedStringArray" />
- <argument index="0" name="data_type" type="int" enum="Theme.DataType" />
+ <param index="0" name="data_type" type="int" enum="Theme.DataType" />
<description>
- Returns a list of all unique theme type names for [code]data_type[/code] properties. Use [method get_type_list] to get a list of all unique theme types.
+ Returns a list of all unique theme type names for [param data_type] properties. Use [method get_type_list] to get a list of all unique theme types.
[b]Note:[/b] This method is analogous to calling the corresponding data type specific method, but can be used for more generalized logic.
</description>
</method>
@@ -269,33 +269,33 @@
</method>
<method name="get_type_variation_base" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="theme_type" type="StringName" />
+ <param index="0" name="theme_type" type="StringName" />
<description>
- Returns the name of the base theme type if [code]theme_type[/code] is a valid variation type. Returns an empty string otherwise.
+ Returns the name of the base theme type if [param theme_type] is a valid variation type. Returns an empty string otherwise.
</description>
</method>
<method name="get_type_variation_list" qualifiers="const">
<return type="PackedStringArray" />
- <argument index="0" name="base_type" type="StringName" />
+ <param index="0" name="base_type" type="StringName" />
<description>
- Returns a list of all type variations for the given [code]base_type[/code].
+ Returns a list of all type variations for the given [param base_type].
</description>
</method>
<method name="has_color" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
<description>
- Returns [code]true[/code] if the [Color] property defined by [code]name[/code] and [code]theme_type[/code] exists.
+ Returns [code]true[/code] if the [Color] property defined by [param name] and [param theme_type] exists.
Returns [code]false[/code] if it doesn't exist. Use [method set_color] to define it.
</description>
</method>
<method name="has_constant" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
<description>
- Returns [code]true[/code] if the constant property defined by [code]name[/code] and [code]theme_type[/code] exists.
+ Returns [code]true[/code] if the constant property defined by [param name] and [param theme_type] exists.
Returns [code]false[/code] if it doesn't exist. Use [method set_constant] to define it.
</description>
</method>
@@ -322,236 +322,235 @@
</method>
<method name="has_font" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
<description>
- Returns [code]true[/code] if the [Font] property defined by [code]name[/code] and [code]theme_type[/code] exists, or if the default theme font is set up (see [method has_default_font]).
+ Returns [code]true[/code] if the [Font] property defined by [param name] and [param theme_type] exists, or if the default theme font is set up (see [method has_default_font]).
Returns [code]false[/code] if neither exist. Use [method set_font] to define the property.
</description>
</method>
<method name="has_font_size" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
<description>
- Returns [code]true[/code] if [member default_font_size] has a valid value.
- Returns [code]false[/code] if it doesn't. The value must be greater than [code]0[/code] to be considered valid.
+ Returns [code]true[/code] if the font size property defined by [param name] and [param theme_type] exists, or if the default theme font size is set up (see [method has_default_font_size]).
+ Returns [code]false[/code] if neither exist. Use [method set_font_size] to define the property.
</description>
</method>
<method name="has_icon" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
<description>
- Returns [code]true[/code] if the icon property defined by [code]name[/code] and [code]theme_type[/code] exists.
+ Returns [code]true[/code] if the icon property defined by [param name] and [param theme_type] exists.
Returns [code]false[/code] if it doesn't exist. Use [method set_icon] to define it.
</description>
</method>
<method name="has_stylebox" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
<description>
- Returns [code]true[/code] if the [StyleBox] property defined by [code]name[/code] and [code]theme_type[/code] exists.
+ Returns [code]true[/code] if the [StyleBox] property defined by [param name] and [param theme_type] exists.
Returns [code]false[/code] if it doesn't exist. Use [method set_stylebox] to define it.
</description>
</method>
<method name="has_theme_item" qualifiers="const">
<return type="bool" />
- <argument index="0" name="data_type" type="int" enum="Theme.DataType" />
- <argument index="1" name="name" type="StringName" />
- <argument index="2" name="theme_type" type="StringName" />
+ <param index="0" name="data_type" type="int" enum="Theme.DataType" />
+ <param index="1" name="name" type="StringName" />
+ <param index="2" name="theme_type" type="StringName" />
<description>
- Returns [code]true[/code] if the theme property of [code]data_type[/code] defined by [code]name[/code] and [code]theme_type[/code] exists.
+ Returns [code]true[/code] if the theme property of [param data_type] defined by [param name] and [param theme_type] exists.
Returns [code]false[/code] if it doesn't exist. Use [method set_theme_item] to define it.
[b]Note:[/b] This method is analogous to calling the corresponding data type specific method, but can be used for more generalized logic.
</description>
</method>
<method name="is_type_variation" qualifiers="const">
<return type="bool" />
- <argument index="0" name="theme_type" type="StringName" />
- <argument index="1" name="base_type" type="StringName" />
+ <param index="0" name="theme_type" type="StringName" />
+ <param index="1" name="base_type" type="StringName" />
<description>
- Returns [code]true[/code] if [code]theme_type[/code] is marked as a variation of [code]base_type[/code].
+ Returns [code]true[/code] if [param theme_type] is marked as a variation of [param base_type].
</description>
</method>
<method name="merge_with">
<return type="void" />
- <argument index="0" name="other" type="Theme" />
+ <param index="0" name="other" type="Theme" />
<description>
- Adds missing and overrides existing definitions with values from the [code]other[/code] theme resource.
+ Adds missing and overrides existing definitions with values from the [param other] theme resource.
[b]Note:[/b] This modifies the current theme. If you want to merge two themes together without modifying either one, create a new empty theme and merge the other two into it one after another.
</description>
</method>
<method name="remove_type">
<return type="void" />
- <argument index="0" name="theme_type" type="StringName" />
+ <param index="0" name="theme_type" type="StringName" />
<description>
Removes the theme type, gracefully discarding defined theme items. If the type is a variation, this information is also erased. If the type is a base for type variations, those variations lose their base.
</description>
</method>
<method name="rename_color">
<return type="void" />
- <argument index="0" name="old_name" type="StringName" />
- <argument index="1" name="name" type="StringName" />
- <argument index="2" name="theme_type" type="StringName" />
+ <param index="0" name="old_name" type="StringName" />
+ <param index="1" name="name" type="StringName" />
+ <param index="2" name="theme_type" type="StringName" />
<description>
- Renames the [Color] property defined by [code]old_name[/code] and [code]theme_type[/code] to [code]name[/code], if it exists.
+ Renames the [Color] property defined by [param old_name] and [param theme_type] to [param name], if it exists.
Fails if it doesn't exist, or if a similar property with the new name already exists. Use [method has_color] to check for existence, and [method clear_color] to remove the existing property.
</description>
</method>
<method name="rename_constant">
<return type="void" />
- <argument index="0" name="old_name" type="StringName" />
- <argument index="1" name="name" type="StringName" />
- <argument index="2" name="theme_type" type="StringName" />
+ <param index="0" name="old_name" type="StringName" />
+ <param index="1" name="name" type="StringName" />
+ <param index="2" name="theme_type" type="StringName" />
<description>
- Renames the constant property defined by [code]old_name[/code] and [code]theme_type[/code] to [code]name[/code], if it exists.
+ Renames the constant property defined by [param old_name] and [param theme_type] to [param name], if it exists.
Fails if it doesn't exist, or if a similar property with the new name already exists. Use [method has_constant] to check for existence, and [method clear_constant] to remove the existing property.
</description>
</method>
<method name="rename_font">
<return type="void" />
- <argument index="0" name="old_name" type="StringName" />
- <argument index="1" name="name" type="StringName" />
- <argument index="2" name="theme_type" type="StringName" />
+ <param index="0" name="old_name" type="StringName" />
+ <param index="1" name="name" type="StringName" />
+ <param index="2" name="theme_type" type="StringName" />
<description>
- Renames the [Font] property defined by [code]old_name[/code] and [code]theme_type[/code] to [code]name[/code], if it exists.
+ Renames the [Font] property defined by [param old_name] and [param theme_type] to [param name], if it exists.
Fails if it doesn't exist, or if a similar property with the new name already exists. Use [method has_font] to check for existence, and [method clear_font] to remove the existing property.
</description>
</method>
<method name="rename_font_size">
<return type="void" />
- <argument index="0" name="old_name" type="StringName" />
- <argument index="1" name="name" type="StringName" />
- <argument index="2" name="theme_type" type="StringName" />
+ <param index="0" name="old_name" type="StringName" />
+ <param index="1" name="name" type="StringName" />
+ <param index="2" name="theme_type" type="StringName" />
<description>
- Returns [code]true[/code] if the font size property defined by [code]name[/code] and [code]theme_type[/code] exists, or if the default theme font size is set up (see [method has_default_font_size]).
- Returns [code]false[/code] if neither exist. Use [method set_font_size] to define the property.
+ Renames the font size property defined by [param old_name] and [param theme_type] to [param name], if it exists.
+ Fails if it doesn't exist, or if a similar property with the new name already exists. Use [method has_font_size] to check for existence, and [method clear_font_size] to remove the existing property.
</description>
</method>
<method name="rename_icon">
<return type="void" />
- <argument index="0" name="old_name" type="StringName" />
- <argument index="1" name="name" type="StringName" />
- <argument index="2" name="theme_type" type="StringName" />
+ <param index="0" name="old_name" type="StringName" />
+ <param index="1" name="name" type="StringName" />
+ <param index="2" name="theme_type" type="StringName" />
<description>
- Renames the icon property defined by [code]old_name[/code] and [code]theme_type[/code] to [code]name[/code], if it exists.
+ Renames the icon property defined by [param old_name] and [param theme_type] to [param name], if it exists.
Fails if it doesn't exist, or if a similar property with the new name already exists. Use [method has_icon] to check for existence, and [method clear_icon] to remove the existing property.
</description>
</method>
<method name="rename_stylebox">
<return type="void" />
- <argument index="0" name="old_name" type="StringName" />
- <argument index="1" name="name" type="StringName" />
- <argument index="2" name="theme_type" type="StringName" />
+ <param index="0" name="old_name" type="StringName" />
+ <param index="1" name="name" type="StringName" />
+ <param index="2" name="theme_type" type="StringName" />
<description>
- Renames the [StyleBox] property defined by [code]old_name[/code] and [code]theme_type[/code] to [code]name[/code], if it exists.
+ Renames the [StyleBox] property defined by [param old_name] and [param theme_type] to [param name], if it exists.
Fails if it doesn't exist, or if a similar property with the new name already exists. Use [method has_stylebox] to check for existence, and [method clear_stylebox] to remove the existing property.
</description>
</method>
<method name="rename_theme_item">
<return type="void" />
- <argument index="0" name="data_type" type="int" enum="Theme.DataType" />
- <argument index="1" name="old_name" type="StringName" />
- <argument index="2" name="name" type="StringName" />
- <argument index="3" name="theme_type" type="StringName" />
+ <param index="0" name="data_type" type="int" enum="Theme.DataType" />
+ <param index="1" name="old_name" type="StringName" />
+ <param index="2" name="name" type="StringName" />
+ <param index="3" name="theme_type" type="StringName" />
<description>
- Renames the theme property of [code]data_type[/code] defined by [code]old_name[/code] and [code]theme_type[/code] to [code]name[/code], if it exists.
+ Renames the theme property of [param data_type] defined by [param old_name] and [param theme_type] to [param name], if it exists.
Fails if it doesn't exist, or if a similar property with the new name already exists. Use [method has_theme_item] to check for existence, and [method clear_theme_item] to remove the existing property.
[b]Note:[/b] This method is analogous to calling the corresponding data type specific method, but can be used for more generalized logic.
</description>
</method>
<method name="set_color">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
- <argument index="2" name="color" type="Color" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
+ <param index="2" name="color" type="Color" />
<description>
- Creates or changes the value of the [Color] property defined by [code]name[/code] and [code]theme_type[/code]. Use [method clear_color] to remove the property.
+ Creates or changes the value of the [Color] property defined by [param name] and [param theme_type]. Use [method clear_color] to remove the property.
</description>
</method>
<method name="set_constant">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
- <argument index="2" name="constant" type="int" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
+ <param index="2" name="constant" type="int" />
<description>
- Creates or changes the value of the constant property defined by [code]name[/code] and [code]theme_type[/code]. Use [method clear_constant] to remove the property.
+ Creates or changes the value of the constant property defined by [param name] and [param theme_type]. Use [method clear_constant] to remove the property.
</description>
</method>
<method name="set_font">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
- <argument index="2" name="font" type="Font" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
+ <param index="2" name="font" type="Font" />
<description>
- Creates or changes the value of the [Font] property defined by [code]name[/code] and [code]theme_type[/code]. Use [method clear_font] to remove the property.
+ Creates or changes the value of the [Font] property defined by [param name] and [param theme_type]. Use [method clear_font] to remove the property.
</description>
</method>
<method name="set_font_size">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
- <argument index="2" name="font_size" type="int" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
+ <param index="2" name="font_size" type="int" />
<description>
- Renames the font size property defined by [code]old_name[/code] and [code]theme_type[/code] to [code]name[/code], if it exists.
- Fails if it doesn't exist, or if a similar property with the new name already exists. Use [method has_font_size] to check for existence, and [method clear_font_size] to remove the existing property.
+ Creates or changes the value of the font size property defined by [param name] and [param theme_type]. Use [method clear_font_size] to remove the property.
</description>
</method>
<method name="set_icon">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
- <argument index="2" name="texture" type="Texture2D" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
+ <param index="2" name="texture" type="Texture2D" />
<description>
- Creates or changes the value of the icon property defined by [code]name[/code] and [code]theme_type[/code]. Use [method clear_icon] to remove the property.
+ Creates or changes the value of the icon property defined by [param name] and [param theme_type]. Use [method clear_icon] to remove the property.
</description>
</method>
<method name="set_stylebox">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" />
- <argument index="2" name="texture" type="StyleBox" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" />
+ <param index="2" name="texture" type="StyleBox" />
<description>
- Creates or changes the value of the [StyleBox] property defined by [code]name[/code] and [code]theme_type[/code]. Use [method clear_stylebox] to remove the property.
+ Creates or changes the value of the [StyleBox] property defined by [param name] and [param theme_type]. Use [method clear_stylebox] to remove the property.
</description>
</method>
<method name="set_theme_item">
<return type="void" />
- <argument index="0" name="data_type" type="int" enum="Theme.DataType" />
- <argument index="1" name="name" type="StringName" />
- <argument index="2" name="theme_type" type="StringName" />
- <argument index="3" name="value" type="Variant" />
+ <param index="0" name="data_type" type="int" enum="Theme.DataType" />
+ <param index="1" name="name" type="StringName" />
+ <param index="2" name="theme_type" type="StringName" />
+ <param index="3" name="value" type="Variant" />
<description>
- Creates or changes the value of the theme property of [code]data_type[/code] defined by [code]name[/code] and [code]theme_type[/code]. Use [method clear_theme_item] to remove the property.
- Fails if the [code]value[/code] type is not accepted by [code]data_type[/code].
+ Creates or changes the value of the theme property of [param data_type] defined by [param name] and [param theme_type]. Use [method clear_theme_item] to remove the property.
+ Fails if the [param value] type is not accepted by [param data_type].
[b]Note:[/b] This method is analogous to calling the corresponding data type specific method, but can be used for more generalized logic.
</description>
</method>
<method name="set_type_variation">
<return type="void" />
- <argument index="0" name="theme_type" type="StringName" />
- <argument index="1" name="base_type" type="StringName" />
+ <param index="0" name="theme_type" type="StringName" />
+ <param index="1" name="base_type" type="StringName" />
<description>
- Marks [code]theme_type[/code] as a variation of [code]base_type[/code].
- This adds [code]theme_type[/code] as a suggested option for [member Control.theme_type_variation] on a [Control] that is of the [code]base_type[/code] class.
- Variations can also be nested, i.e. [code]base_type[/code] can be another variation. If a chain of variations ends with a [code]base_type[/code] matching the class of the [Control], the whole chain is going to be suggested as options.
+ Marks [param theme_type] as a variation of [param base_type].
+ This adds [param theme_type] as a suggested option for [member Control.theme_type_variation] on a [Control] that is of the [param base_type] class.
+ Variations can also be nested, i.e. [param base_type] can be another variation. If a chain of variations ends with a [param base_type] matching the class of the [Control], the whole chain is going to be suggested as options.
[b]Note:[/b] Suggestions only show up if this theme resource is set as the project default theme. See [member ProjectSettings.gui/theme/custom].
</description>
</method>
</methods>
<members>
<member name="default_base_scale" type="float" setter="set_default_base_scale" getter="get_default_base_scale" default="0.0">
- The default base scale factor of this theme resource. Used by some controls to scale their visual properties based on the global scale factor. If this value is set to [code]0.0[/code], the global scale factor is used.
+ The default base scale factor of this theme resource. Used by some controls to scale their visual properties based on the global scale factor. If this value is set to [code]0.0[/code], the global scale factor is used (see [member ThemeDB.fallback_base_scale]).
Use [method has_default_base_scale] to check if this value is valid.
</member>
<member name="default_font" type="Font" setter="set_default_font" getter="get_default_font">
- The default font of this theme resource. Used as the default value when trying to fetch a font resource that doesn't exist in this theme or is in invalid state. If the default font is also missing or invalid, the engine fallback value is used.
+ The default font of this theme resource. Used as the default value when trying to fetch a font resource that doesn't exist in this theme or is in invalid state. If the default font is also missing or invalid, the engine fallback value is used (see [member ThemeDB.fallback_font]).
Use [method has_default_font] to check if this value is valid.
</member>
<member name="default_font_size" type="int" setter="set_default_font_size" getter="get_default_font_size" default="-1">
- The default font size of this theme resource. Used as the default value when trying to fetch a font size value that doesn't exist in this theme or is in invalid state. If the default font size is also missing or invalid, the engine fallback value is used.
+ The default font size of this theme resource. Used as the default value when trying to fetch a font size value that doesn't exist in this theme or is in invalid state. If the default font size is also missing or invalid, the engine fallback value is used (see [member ThemeDB.fallback_font_size]).
Values below [code]0[/code] are invalid and can be used to unset the property. Use [method has_default_font_size] to check if this value is valid.
</member>
</members>
diff --git a/doc/classes/ThemeDB.xml b/doc/classes/ThemeDB.xml
new file mode 100644
index 0000000000..6003ffb28e
--- /dev/null
+++ b/doc/classes/ThemeDB.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="ThemeDB" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ An engine singleton providing access to static [Theme] information, such as default and project theme, and fallback values.
+ </brief_description>
+ <description>
+ This engine singleton provides access to static information about [Theme] resources used by the engine and by your projects. You can fetch the default engine theme, as well as your project configured theme.
+ [ThemeDB] also contains fallback values for theme properties.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_default_theme">
+ <return type="Theme" />
+ <description>
+ Returns a reference to the default engine [Theme]. This theme resource is responsible for the out-of-the-box look of [Control] nodes and cannot be overridden.
+ </description>
+ </method>
+ <method name="get_project_theme">
+ <return type="Theme" />
+ <description>
+ Returns a reference to the custom project [Theme]. This theme resources allows to override the default engine theme for every control node in the project.
+ To set the project theme, see [member ProjectSettings.gui/theme/custom].
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="fallback_base_scale" type="float" setter="set_fallback_base_scale" getter="get_fallback_base_scale" default="1.0">
+ The fallback base scale factor of every [Control] node and [Theme] resource. Used when no other value is available to the control.
+ See also [member Theme.default_base_scale].
+ </member>
+ <member name="fallback_font" type="Font" setter="set_fallback_font" getter="get_fallback_font">
+ The fallback font of every [Control] node and [Theme] resource. Used when no other value is available to the control.
+ See also [member Theme.default_font].
+ </member>
+ <member name="fallback_font_size" type="int" setter="set_fallback_font_size" getter="get_fallback_font_size" default="16">
+ The fallback font size of every [Control] node and [Theme] resource. Used when no other value is available to the control.
+ See also [member Theme.default_font_size].
+ </member>
+ <member name="fallback_icon" type="Texture2D" setter="set_fallback_icon" getter="get_fallback_icon">
+ The fallback icon of every [Control] node and [Theme] resource. Used when no other value is available to the control.
+ </member>
+ <member name="fallback_stylebox" type="StyleBox" setter="set_fallback_stylebox" getter="get_fallback_stylebox">
+ The fallback stylebox of every [Control] node and [Theme] resource. Used when no other value is available to the control.
+ </member>
+ </members>
+ <signals>
+ <signal name="fallback_changed">
+ <description>
+ Emitted when one of the fallback values had been changed. Use it to refresh the look of controls that may rely on the fallback theme items.
+ </description>
+ </signal>
+ </signals>
+</class>
diff --git a/doc/classes/Thread.xml b/doc/classes/Thread.xml
index 513daff37c..846dae0bae 100644
--- a/doc/classes/Thread.xml
+++ b/doc/classes/Thread.xml
@@ -34,12 +34,12 @@
</method>
<method name="start">
<return type="int" enum="Error" />
- <argument index="0" name="callable" type="Callable" />
- <argument index="1" name="priority" type="int" enum="Thread.Priority" default="1" />
+ <param index="0" name="callable" type="Callable" />
+ <param index="1" name="priority" type="int" enum="Thread.Priority" default="1" />
<description>
- Starts a new [Thread] that calls [code]callable[/code].
+ Starts a new [Thread] that calls [param callable].
If the method takes some arguments, you can pass them using [method Callable.bind].
- The [code]priority[/code] of the [Thread] can be changed by passing a value from the [enum Priority] enum.
+ The [param priority] of the [Thread] can be changed by passing a value from the [enum Priority] enum.
Returns [constant OK] on success, or [constant ERR_CANT_CREATE] on failure.
</description>
</method>
diff --git a/doc/classes/TileData.xml b/doc/classes/TileData.xml
index 66cf602e5d..798a536a88 100644
--- a/doc/classes/TileData.xml
+++ b/doc/classes/TileData.xml
@@ -9,188 +9,188 @@
<methods>
<method name="add_collision_polygon">
<return type="void" />
- <argument index="0" name="layer_id" type="int" />
+ <param index="0" name="layer_id" type="int" />
<description>
Adds a collision polygon to the tile on the given TileSet physics layer.
</description>
</method>
<method name="get_collision_polygon_one_way_margin" qualifiers="const">
<return type="float" />
- <argument index="0" name="layer_id" type="int" />
- <argument index="1" name="polygon_index" type="int" />
+ <param index="0" name="layer_id" type="int" />
+ <param index="1" name="polygon_index" type="int" />
<description>
- Returns the one-way margin (for one-way platforms) of the polygon at index [code]polygon_index[/code] for TileSet physics layer with index [code]layer_id[/code].
+ Returns the one-way margin (for one-way platforms) of the polygon at index [param polygon_index] for TileSet physics layer with index [param layer_id].
</description>
</method>
<method name="get_collision_polygon_points" qualifiers="const">
<return type="PackedVector2Array" />
- <argument index="0" name="layer_id" type="int" />
- <argument index="1" name="polygon_index" type="int" />
+ <param index="0" name="layer_id" type="int" />
+ <param index="1" name="polygon_index" type="int" />
<description>
- Returns the points of the polygon at index [code]polygon_index[/code] for TileSet physics layer with index [code]layer_id[/code].
+ Returns the points of the polygon at index [param polygon_index] for TileSet physics layer with index [param layer_id].
</description>
</method>
<method name="get_collision_polygons_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="layer_id" type="int" />
+ <param index="0" name="layer_id" type="int" />
<description>
- Returns how many polygons the tile has for TileSet physics layer with index [code]layer_id[/code].
+ Returns how many polygons the tile has for TileSet physics layer with index [param layer_id].
</description>
</method>
<method name="get_constant_angular_velocity" qualifiers="const">
<return type="float" />
- <argument index="0" name="layer_id" type="int" />
+ <param index="0" name="layer_id" type="int" />
<description>
Returns the constant angular velocity applied to objects colliding with this tile.
</description>
</method>
<method name="get_constant_linear_velocity" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="layer_id" type="int" />
+ <param index="0" name="layer_id" type="int" />
<description>
Returns the constant linear velocity applied to objects colliding with this tile.
</description>
</method>
<method name="get_custom_data" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="layer_name" type="String" />
+ <param index="0" name="layer_name" type="String" />
<description>
- Returns the custom data value for custom data layer named [code]layer_name[/code].
+ Returns the custom data value for custom data layer named [param layer_name].
</description>
</method>
<method name="get_custom_data_by_layer_id" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="layer_id" type="int" />
+ <param index="0" name="layer_id" type="int" />
<description>
- Returns the custom data value for custom data layer with index [code]layer_id[/code].
+ Returns the custom data value for custom data layer with index [param layer_id].
</description>
</method>
<method name="get_navigation_polygon" qualifiers="const">
<return type="NavigationPolygon" />
- <argument index="0" name="layer_id" type="int" />
+ <param index="0" name="layer_id" type="int" />
<description>
- Returns the navigation polygon of the tile for the TileSet navigation layer with index [code]layer_id[/code].
+ Returns the navigation polygon of the tile for the TileSet navigation layer with index [param layer_id].
</description>
</method>
<method name="get_occluder" qualifiers="const">
<return type="OccluderPolygon2D" />
- <argument index="0" name="layer_id" type="int" />
+ <param index="0" name="layer_id" type="int" />
<description>
- Returns the occluder polygon of the tile for the TileSet occlusion layer with index [code]layer_id[/code].
+ Returns the occluder polygon of the tile for the TileSet occlusion layer with index [param layer_id].
</description>
</method>
<method name="get_terrain_peering_bit" qualifiers="const">
<return type="int" />
- <argument index="0" name="peering_bit" type="int" enum="TileSet.CellNeighbor" />
+ <param index="0" name="peering_bit" type="int" enum="TileSet.CellNeighbor" />
<description>
- Returns the tile's terrain bit for the given [code]peering_bit[/code] direction.
+ Returns the tile's terrain bit for the given [param peering_bit] direction.
</description>
</method>
<method name="is_collision_polygon_one_way" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_id" type="int" />
- <argument index="1" name="polygon_index" type="int" />
+ <param index="0" name="layer_id" type="int" />
+ <param index="1" name="polygon_index" type="int" />
<description>
- Returns whether one-way collisions are enabled for the polygon at index [code]polygon_index[/code] for TileSet physics layer with index [code]layer_id[/code].
+ Returns whether one-way collisions are enabled for the polygon at index [param polygon_index] for TileSet physics layer with index [param layer_id].
</description>
</method>
<method name="remove_collision_polygon">
<return type="void" />
- <argument index="0" name="layer_id" type="int" />
- <argument index="1" name="polygon_index" type="int" />
+ <param index="0" name="layer_id" type="int" />
+ <param index="1" name="polygon_index" type="int" />
<description>
- Removes the polygon at index [code]polygon_index[/code] for TileSet physics layer with index [code]layer_id[/code].
+ Removes the polygon at index [param polygon_index] for TileSet physics layer with index [param layer_id].
</description>
</method>
<method name="set_collision_polygon_one_way">
<return type="void" />
- <argument index="0" name="layer_id" type="int" />
- <argument index="1" name="polygon_index" type="int" />
- <argument index="2" name="one_way" type="bool" />
+ <param index="0" name="layer_id" type="int" />
+ <param index="1" name="polygon_index" type="int" />
+ <param index="2" name="one_way" type="bool" />
<description>
- Enables/disables one-way collisions on the polygon at index [code]polygon_index[/code] for TileSet physics layer with index [code]layer_id[/code].
+ Enables/disables one-way collisions on the polygon at index [param polygon_index] for TileSet physics layer with index [param layer_id].
</description>
</method>
<method name="set_collision_polygon_one_way_margin">
<return type="void" />
- <argument index="0" name="layer_id" type="int" />
- <argument index="1" name="polygon_index" type="int" />
- <argument index="2" name="one_way_margin" type="float" />
+ <param index="0" name="layer_id" type="int" />
+ <param index="1" name="polygon_index" type="int" />
+ <param index="2" name="one_way_margin" type="float" />
<description>
- Enables/disables one-way collisions on the polygon at index [code]polygon_index[/code] for TileSet physics layer with index [code]layer_id[/code].
+ Enables/disables one-way collisions on the polygon at index [param polygon_index] for TileSet physics layer with index [param layer_id].
</description>
</method>
<method name="set_collision_polygon_points">
<return type="void" />
- <argument index="0" name="layer_id" type="int" />
- <argument index="1" name="polygon_index" type="int" />
- <argument index="2" name="polygon" type="PackedVector2Array" />
+ <param index="0" name="layer_id" type="int" />
+ <param index="1" name="polygon_index" type="int" />
+ <param index="2" name="polygon" type="PackedVector2Array" />
<description>
- Sets the points of the polygon at index [code]polygon_index[/code] for TileSet physics layer with index [code]layer_id[/code].
+ Sets the points of the polygon at index [param polygon_index] for TileSet physics layer with index [param layer_id].
</description>
</method>
<method name="set_collision_polygons_count">
<return type="void" />
- <argument index="0" name="layer_id" type="int" />
- <argument index="1" name="polygons_count" type="int" />
+ <param index="0" name="layer_id" type="int" />
+ <param index="1" name="polygons_count" type="int" />
<description>
- Sets the polygons count for TileSet physics layer with index [code]layer_id[/code].
+ Sets the polygons count for TileSet physics layer with index [param layer_id].
</description>
</method>
<method name="set_constant_angular_velocity">
<return type="void" />
- <argument index="0" name="layer_id" type="int" />
- <argument index="1" name="velocity" type="float" />
+ <param index="0" name="layer_id" type="int" />
+ <param index="1" name="velocity" type="float" />
<description>
Sets the constant angular velocity. This does not rotate the tile. This angular velocity is applied to objects colliding with this tile.
</description>
</method>
<method name="set_constant_linear_velocity">
<return type="void" />
- <argument index="0" name="layer_id" type="int" />
- <argument index="1" name="velocity" type="Vector2" />
+ <param index="0" name="layer_id" type="int" />
+ <param index="1" name="velocity" type="Vector2" />
<description>
Sets the constant linear velocity. This does not move the tile. This linear velocity is applied to objects colliding with this tile. This is useful to create conveyor belts.
</description>
</method>
<method name="set_custom_data">
<return type="void" />
- <argument index="0" name="layer_name" type="String" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="layer_name" type="String" />
+ <param index="1" name="value" type="Variant" />
<description>
- Sets the tile's custom data value for the TileSet custom data layer with name [code]layer_name[/code].
+ Sets the tile's custom data value for the TileSet custom data layer with name [param layer_name].
</description>
</method>
<method name="set_custom_data_by_layer_id">
<return type="void" />
- <argument index="0" name="layer_id" type="int" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="layer_id" type="int" />
+ <param index="1" name="value" type="Variant" />
<description>
- Sets the tile's custom data value for the TileSet custom data layer with index [code]layer_id[/code].
+ Sets the tile's custom data value for the TileSet custom data layer with index [param layer_id].
</description>
</method>
<method name="set_navigation_polygon">
<return type="void" />
- <argument index="0" name="layer_id" type="int" />
- <argument index="1" name="navigation_polygon" type="NavigationPolygon" />
+ <param index="0" name="layer_id" type="int" />
+ <param index="1" name="navigation_polygon" type="NavigationPolygon" />
<description>
- Sets the navigation polygon for the TileSet navigation layer with index [code]layer_id[/code].
+ Sets the navigation polygon for the TileSet navigation layer with index [param layer_id].
</description>
</method>
<method name="set_occluder">
<return type="void" />
- <argument index="0" name="layer_id" type="int" />
- <argument index="1" name="occluder_polygon" type="OccluderPolygon2D" />
+ <param index="0" name="layer_id" type="int" />
+ <param index="1" name="occluder_polygon" type="OccluderPolygon2D" />
<description>
- Sets the occluder for the TileSet occlusion layer with index [code]layer_id[/code].
+ Sets the occluder for the TileSet occlusion layer with index [param layer_id].
</description>
</method>
<method name="set_terrain_peering_bit">
<return type="void" />
- <argument index="0" name="peering_bit" type="int" enum="TileSet.CellNeighbor" />
- <argument index="1" name="terrain" type="int" />
+ <param index="0" name="peering_bit" type="int" enum="TileSet.CellNeighbor" />
+ <param index="1" name="terrain" type="int" />
<description>
- Sets the tile's terrain bit for the given [code]peering_bit[/code] direction.
+ Sets the tile's terrain bit for the given [param peering_bit] direction.
</description>
</method>
</methods>
diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml
index d532f583e6..e76c696021 100644
--- a/doc/classes/TileMap.xml
+++ b/doc/classes/TileMap.xml
@@ -18,30 +18,30 @@
<methods>
<method name="_tile_data_runtime_update" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="layer" type="int" />
- <argument index="1" name="coords" type="Vector2i" />
- <argument index="2" name="tile_data" type="TileData" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="coords" type="Vector2i" />
+ <param index="2" name="tile_data" type="TileData" />
<description>
Called with a TileData object about to be used internally by the TileMap, allowing its modification at runtime.
- This method is only called if [method _use_tile_data_runtime_update] is implemented and returns [code]true[/code] for the given tile [code]coords[/coords] and [code]layer[/code].
- [b]Warning:[/b] The [code]tile_data[/code] object's sub-resources are the same as the one in the TileSet. Modifying them might impact the whole TileSet. Instead, make sure to duplicate those resources.
- [b]Note:[/b] If the properties of [code]tile_data[/code] object should change over time, use [method force_update] to trigger a TileMap update.
+ This method is only called if [method _use_tile_data_runtime_update] is implemented and returns [code]true[/code] for the given tile [param coords] and [param layer].
+ [b]Warning:[/b] The [param tile_data] object's sub-resources are the same as the one in the TileSet. Modifying them might impact the whole TileSet. Instead, make sure to duplicate those resources.
+ [b]Note:[/b] If the properties of [param tile_data] object should change over time, use [method force_update] to trigger a TileMap update.
</description>
</method>
<method name="_use_tile_data_runtime_update" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="layer" type="int" />
- <argument index="1" name="coords" type="Vector2i" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="coords" type="Vector2i" />
<description>
- Should return [code]true[/code] if the tile at coordinates [code]coords[/coords] on layer [code]layer[/code] requires a runtime update.
+ Should return [code]true[/code] if the tile at coordinates [param coords] on layer [param layer] requires a runtime update.
[b]Warning:[/b] Make sure this function only return [code]true[/code] when needed. Any tile processed at runtime without a need for it will imply a significant performance penalty.
</description>
</method>
<method name="add_layer">
<return type="void" />
- <argument index="0" name="to_position" type="int" />
+ <param index="0" name="to_position" type="int" />
<description>
- Adds a layer at the given position [code]to_position[/code] in the array. If [code]to_position[/code] is -1, adds it at the end of the array.
+ Adds a layer at the given position [param to_position] in the array. If [param to_position] is negative, the position is counted from the end, with [code]-1[/code] adding the layer at the end of the array.
</description>
</method>
<method name="clear">
@@ -52,17 +52,17 @@
</method>
<method name="clear_layer">
<return type="void" />
- <argument index="0" name="layer" type="int" />
+ <param index="0" name="layer" type="int" />
<description>
Clears all cells on the given layer.
</description>
</method>
<method name="erase_cell">
<return type="void" />
- <argument index="0" name="layer" type="int" />
- <argument index="1" name="coords" type="Vector2i" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="coords" type="Vector2i" />
<description>
- Erases the cell on layer [code]layer[/code] at coordinates [code]coords[/code].
+ Erases the cell on layer [param layer] at coordinates [param coords].
</description>
</method>
<method name="fix_invalid_tiles">
@@ -73,71 +73,81 @@
</method>
<method name="force_update">
<return type="void" />
- <argument index="0" name="layer" type="int" default="-1" />
+ <param index="0" name="layer" type="int" default="-1" />
<description>
- Triggers an update of the TileMap. If [code]layer[/code] is provided, only updates the given layer.
+ Triggers an update of the TileMap. If [param layer] is provided, only updates the given layer.
[b]Note:[/b] The TileMap node updates automatically when one of its properties is modified. A manual update is only needed if runtime modifications (implemented in [method _tile_data_runtime_update]) need to be applied.
- [b]Warning:[/b] Updating the TileMap is a performance demanding task. Limit occurrences of those updates to the minimum and limit the amount tiles they impact (by segregating tiles updated often to a dedicated layer for example).
+ [b]Warning:[/b] Updating the TileMap is computationally expensive and may impact performance. Try to limit the number of updates and the tiles they impact (by placing frequently updated tiles in a dedicated layer for example).
</description>
</method>
<method name="get_cell_alternative_tile" qualifiers="const">
<return type="int" />
- <argument index="0" name="layer" type="int" />
- <argument index="1" name="coords" type="Vector2i" />
- <argument index="2" name="use_proxies" type="bool" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="coords" type="Vector2i" />
+ <param index="2" name="use_proxies" type="bool" default="false" />
<description>
- Returns the tile alternative ID of the cell on layer [code]layer[/code] at [code]coords[/code]. If [code]use_proxies[/code] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy].
+ Returns the tile alternative ID of the cell on layer [param layer] at [param coords]. If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy].
</description>
</method>
<method name="get_cell_atlas_coords" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="layer" type="int" />
- <argument index="1" name="coords" type="Vector2i" />
- <argument index="2" name="use_proxies" type="bool" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="coords" type="Vector2i" />
+ <param index="2" name="use_proxies" type="bool" default="false" />
<description>
- Returns the tile atlas coordinates ID of the cell on layer [code]layer[/code] at coordinates [code]coords[/code]. If [code]use_proxies[/code] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy].
+ Returns the tile atlas coordinates ID of the cell on layer [param layer] at coordinates [param coords]. If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy].
</description>
</method>
<method name="get_cell_source_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="layer" type="int" />
- <argument index="1" name="coords" type="Vector2i" />
- <argument index="2" name="use_proxies" type="bool" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="coords" type="Vector2i" />
+ <param index="2" name="use_proxies" type="bool" default="false" />
<description>
- Returns the tile source ID of the cell on layer [code]layer[/code] at coordinates [code]coords[/code]. If [code]use_proxies[/code] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy].
+ Returns the tile source ID of the cell on layer [param layer] at coordinates [param coords]. If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy].
+ </description>
+ </method>
+ <method name="get_cell_tile_data" qualifiers="const">
+ <return type="TileData" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="coords" type="Vector2i" />
+ <param index="2" name="use_proxies" type="bool" default="false" />
+ <description>
+ Returns the [TileData] object associated with the given cell, or [code]null[/code] if the cell is not a [TileSetAtlasSource].
+ If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy].
</description>
</method>
<method name="get_coords_for_body_rid">
<return type="Vector2i" />
- <argument index="0" name="body" type="RID" />
+ <param index="0" name="body" type="RID" />
<description>
Returns the coordinates of the tile for given physics body RID. Such RID can be retrieved from [method KinematicCollision2D.get_collider_rid], when colliding with a tile.
</description>
</method>
<method name="get_layer_modulate" qualifiers="const">
<return type="Color" />
- <argument index="0" name="layer" type="int" />
+ <param index="0" name="layer" type="int" />
<description>
Returns a TileMap layer's modulate.
</description>
</method>
<method name="get_layer_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="layer" type="int" />
+ <param index="0" name="layer" type="int" />
<description>
Returns a TileMap layer's name.
</description>
</method>
<method name="get_layer_y_sort_origin" qualifiers="const">
<return type="int" />
- <argument index="0" name="layer" type="int" />
+ <param index="0" name="layer" type="int" />
<description>
Returns a TileMap layer's Y sort origin.
</description>
</method>
<method name="get_layer_z_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="layer" type="int" />
+ <param index="0" name="layer" type="int" />
<description>
Returns a TileMap layer's Z-index value.
</description>
@@ -149,30 +159,30 @@
</method>
<method name="get_neighbor_cell" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="coords" type="Vector2i" />
- <argument index="1" name="neighbor" type="int" enum="TileSet.CellNeighbor" />
+ <param index="0" name="coords" type="Vector2i" />
+ <param index="1" name="neighbor" type="int" enum="TileSet.CellNeighbor" />
<description>
- Returns the neighboring cell to the one at coordinates [code]coords[/code], identified by the [code]neighbor[/code] direction. This method takes into account the different layouts a TileMap can take.
+ Returns the neighboring cell to the one at coordinates [param coords], identified by the [param neighbor] direction. This method takes into account the different layouts a TileMap can take.
</description>
</method>
<method name="get_pattern">
<return type="TileMapPattern" />
- <argument index="0" name="layer" type="int" />
- <argument index="1" name="coords_array" type="Vector2i[]" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="coords_array" type="Vector2i[]" />
<description>
Creates a new [TileMapPattern] from the given layer and set of cells.
</description>
</method>
<method name="get_surrounding_tiles">
<return type="Vector2i[]" />
- <argument index="0" name="coords" type="Vector2i" />
+ <param index="0" name="coords" type="Vector2i" />
<description>
- Returns the list of all neighbourings cells to the one at [code]coords[/code]
+ Returns the list of all neighbourings cells to the one at [param coords]
</description>
</method>
<method name="get_used_cells" qualifiers="const">
<return type="Vector2i[]" />
- <argument index="0" name="layer" type="int" />
+ <param index="0" name="layer" type="int" />
<description>
Returns a [Vector2] array with the positions of all cells containing a tile in the given layer. A cell is considered empty if its source identifier equals -1, its atlas coordinates identifiers is [code]Vector2(-1, -1)[/code] and its alternative identifier is -1.
</description>
@@ -185,30 +195,30 @@
</method>
<method name="is_layer_enabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer" type="int" />
+ <param index="0" name="layer" type="int" />
<description>
Returns if a layer is enabled.
</description>
</method>
<method name="is_layer_y_sort_enabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer" type="int" />
+ <param index="0" name="layer" type="int" />
<description>
Returns if a layer Y-sorts its tiles.
</description>
</method>
<method name="map_pattern">
<return type="Vector2i" />
- <argument index="0" name="position_in_tilemap" type="Vector2i" />
- <argument index="1" name="coords_in_pattern" type="Vector2i" />
- <argument index="2" name="pattern" type="TileMapPattern" />
+ <param index="0" name="position_in_tilemap" type="Vector2i" />
+ <param index="1" name="coords_in_pattern" type="Vector2i" />
+ <param index="2" name="pattern" type="TileMapPattern" />
<description>
- Returns for the given coordinate [code]coords_in_pattern[/code] in a [TileMapPattern] the corresponding cell coordinates if the pattern was pasted at the [code]position_in_tilemap[/code] coordinates (see [method set_pattern]). This mapping is required as in half-offset tile shapes, the mapping might not work by calculating [code]position_in_tile_map + coords_in_pattern[/code]
+ Returns for the given coordinate [param coords_in_pattern] in a [TileMapPattern] the corresponding cell coordinates if the pattern was pasted at the [param position_in_tilemap] coordinates (see [method set_pattern]). This mapping is required as in half-offset tile shapes, the mapping might not work by calculating [code]position_in_tile_map + coords_in_pattern[/code]
</description>
</method>
<method name="map_to_world" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="map_position" type="Vector2i" />
+ <param index="0" name="map_position" type="Vector2i" />
<description>
Returns a local position of the center of the cell at the given tilemap (grid-based) coordinates.
[b]Note:[/b] This doesn't correspond to the visual position of the tile, i.e. it ignores the [member TileData.texture_offset] property of individual tiles.
@@ -216,121 +226,127 @@
</method>
<method name="move_layer">
<return type="void" />
- <argument index="0" name="layer" type="int" />
- <argument index="1" name="to_position" type="int" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="to_position" type="int" />
<description>
- Moves the layer at index [code]layer_index[/code] to the given position [code]to_position[/code] in the array.
+ Moves the layer at index [param layer] to the given position [param to_position] in the array.
</description>
</method>
<method name="remove_layer">
<return type="void" />
- <argument index="0" name="layer" type="int" />
+ <param index="0" name="layer" type="int" />
<description>
- Removes the layer at index [code]layer[/code].
+ Removes the layer at index [param layer].
</description>
</method>
<method name="set_cell">
<return type="void" />
- <argument index="0" name="layer" type="int" />
- <argument index="1" name="coords" type="Vector2i" />
- <argument index="2" name="source_id" type="int" default="-1" />
- <argument index="3" name="atlas_coords" type="Vector2i" default="Vector2i(-1, -1)" />
- <argument index="4" name="alternative_tile" type="int" default="0" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="coords" type="Vector2i" />
+ <param index="2" name="source_id" type="int" default="-1" />
+ <param index="3" name="atlas_coords" type="Vector2i" default="Vector2i(-1, -1)" />
+ <param index="4" name="alternative_tile" type="int" default="0" />
<description>
- Sets the tile indentifiers for the cell on layer [code]layer[/code] at coordinates [code]coords[/code]. Each tile of the [TileSet] is identified using three parts:
- - The source identifier [code]source_id[/code] identifies a [TileSetSource] identifier. See [method TileSet.set_source_id],
- - The atlas coordinates identifier [code]atlas_coords[/code] identifies a tile coordinates in the atlas (if the source is a [TileSetAtlasSource]. For [TileSetScenesCollectionSource] it should be 0),
- - The alternative tile identifier [code]alternative_tile[/code] identifies a tile alternative the source is a [TileSetAtlasSource], and the scene for a [TileSetScenesCollectionSource].
+ Sets the tile indentifiers for the cell on layer [param layer] at coordinates [param coords]. Each tile of the [TileSet] is identified using three parts:
+ - The source identifier [param source_id] identifies a [TileSetSource] identifier. See [method TileSet.set_source_id],
+ - The atlas coordinates identifier [param atlas_coords] identifies a tile coordinates in the atlas (if the source is a [TileSetAtlasSource]. For [TileSetScenesCollectionSource] it should be 0),
+ - The alternative tile identifier [param alternative_tile] identifies a tile alternative the source is a [TileSetAtlasSource], and the scene for a [TileSetScenesCollectionSource].
</description>
</method>
<method name="set_cells_terrain_connect">
<return type="void" />
- <argument index="0" name="layer" type="int" />
- <argument index="1" name="cells" type="Vector2i[]" />
- <argument index="2" name="terrain_set" type="int" />
- <argument index="3" name="terrain" type="int" />
- <argument index="4" name="ignore_empty_terrains" type="bool" default="true" />
- <description>
- Update all the cells in the [code]cells[/code] coordinates array so that they use the given [code]terrain[/code] for the given [code]terrain_set[/code]. If an updated cell has the same terrain as one of its neighboring cells, this function tries to join the two. This function might update neighboring tiles if needed to create correct terrain transitions. If [code]ignore_empty_terrains[/code] is true, empty terrains will be ignored when trying to find the best fitting tile for the given terrain constraints.
- If [code]ignore_empty_terrains[/code] is true, empty terrains will be ignored when trying to find the best fitting tile for the given terrain constraints.
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="cells" type="Vector2i[]" />
+ <param index="2" name="terrain_set" type="int" />
+ <param index="3" name="terrain" type="int" />
+ <param index="4" name="ignore_empty_terrains" type="bool" default="true" />
+ <description>
+ Update all the cells in the [param cells] coordinates array so that they use the given [param terrain] for the given [param terrain_set]. If an updated cell has the same terrain as one of its neighboring cells, this function tries to join the two. This function might update neighboring tiles if needed to create correct terrain transitions.
+ If [param ignore_empty_terrains] is true, empty terrains will be ignored when trying to find the best fitting tile for the given terrain constraints.
[b]Note:[/b] To work correctly, [code]set_cells_terrain_connect[/code] requires the TileMap's TileSet to have terrains set up with all required terrain combinations. Otherwise, it may produce unexpected results.
</description>
</method>
<method name="set_cells_terrain_path">
<return type="void" />
- <argument index="0" name="layer" type="int" />
- <argument index="1" name="path" type="Vector2i[]" />
- <argument index="2" name="terrain_set" type="int" />
- <argument index="3" name="terrain" type="int" />
- <argument index="4" name="ignore_empty_terrains" type="bool" default="true" />
- <description>
- Update all the cells in the [code]cells[/code] coordinates array so that they use the given [code]terrain[/code] for the given [code]terrain_set[/code]. The function will also connect two successive cell in the path with the same terrain. This function might update neighboring tiles if needed to create correct terrain transitions.
- If [code]ignore_empty_terrains[/code] is true, empty terrains will be ignored when trying to find the best fitting tile for the given terrain constraints.
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="path" type="Vector2i[]" />
+ <param index="2" name="terrain_set" type="int" />
+ <param index="3" name="terrain" type="int" />
+ <param index="4" name="ignore_empty_terrains" type="bool" default="true" />
+ <description>
+ Update all the cells in the [param path] coordinates array so that they use the given [param terrain] for the given [param terrain_set]. The function will also connect two successive cell in the path with the same terrain. This function might update neighboring tiles if needed to create correct terrain transitions.
+ If [param ignore_empty_terrains] is true, empty terrains will be ignored when trying to find the best fitting tile for the given terrain constraints.
[b]Note:[/b] To work correctly, [code]set_cells_terrain_path[/code] requires the TileMap's TileSet to have terrains set up with all required terrain combinations. Otherwise, it may produce unexpected results.
</description>
</method>
<method name="set_layer_enabled">
<return type="void" />
- <argument index="0" name="layer" type="int" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="enabled" type="bool" />
<description>
- Enables or disables the layer [code]layer[/code]. A disabled layer is not processed at all (no rendering, no physics, etc...).
+ Enables or disables the layer [param layer]. A disabled layer is not processed at all (no rendering, no physics, etc...).
+ If [param layer] is negative, the layers are accessed from the last one.
</description>
</method>
<method name="set_layer_modulate">
<return type="void" />
- <argument index="0" name="layer" type="int" />
- <argument index="1" name="enabled" type="Color" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="modulate" type="Color" />
<description>
Sets a layer's color. It will be multiplied by tile's color and TileMap's modulate.
+ If [code]layer[/code] is negative, the layers are accessed from the last one.
</description>
</method>
<method name="set_layer_name">
<return type="void" />
- <argument index="0" name="layer" type="int" />
- <argument index="1" name="name" type="String" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="name" type="String" />
<description>
Sets a layer's name. This is mostly useful in the editor.
+ If [code]layer[/code] is negative, the layers are accessed from the last one.
</description>
</method>
<method name="set_layer_y_sort_enabled">
<return type="void" />
- <argument index="0" name="layer" type="int" />
- <argument index="1" name="y_sort_enabled" type="bool" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="y_sort_enabled" type="bool" />
<description>
Enables or disables a layer's Y-sorting. If a layer is Y-sorted, the layer will behave as a CanvasItem node where each of its tile gets Y-sorted.
Y-sorted layers should usually be on different Z-index values than not Y-sorted layers, otherwise, each of those layer will be Y-sorted as whole with the Y-sorted one. This is usually an undesired behvaior.
+ If [code]layer[/code] is negative, the layers are accessed from the last one.
</description>
</method>
<method name="set_layer_y_sort_origin">
<return type="void" />
- <argument index="0" name="layer" type="int" />
- <argument index="1" name="y_sort_origin" type="int" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="y_sort_origin" type="int" />
<description>
Sets a layer's Y-sort origin value. This Y-sort origin value is added to each tile's Y-sort origin value.
This allows, for example, to fake a different height level on each layer. This can be useful for top-down view games.
+ If [code]layer[/code] is negative, the layers are accessed from the last one.
</description>
</method>
<method name="set_layer_z_index">
<return type="void" />
- <argument index="0" name="layer" type="int" />
- <argument index="1" name="z_index" type="int" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="z_index" type="int" />
<description>
Sets a layers Z-index value. This Z-index is added to each tile's Z-index value.
+ If [code]layer[/code] is negative, the layers are accessed from the last one.
</description>
</method>
<method name="set_pattern">
<return type="void" />
- <argument index="0" name="layer" type="int" />
- <argument index="1" name="position" type="Vector2i" />
- <argument index="2" name="pattern" type="TileMapPattern" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="position" type="Vector2i" />
+ <param index="2" name="pattern" type="TileMapPattern" />
<description>
- Paste the given [TileMapPattern] at the given [code]position[/code] and [code]layer[/code] in the tile map.
+ Paste the given [TileMapPattern] at the given [param position] and [param layer] in the tile map.
</description>
</method>
<method name="world_to_map" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="world_position" type="Vector2" />
+ <param index="0" name="world_position" type="Vector2" />
<description>
Returns the tilemap (grid-based) coordinates corresponding to the given local position.
</description>
diff --git a/doc/classes/TileMapPattern.xml b/doc/classes/TileMapPattern.xml
index 5fe514d3da..30bb174313 100644
--- a/doc/classes/TileMapPattern.xml
+++ b/doc/classes/TileMapPattern.xml
@@ -12,23 +12,23 @@
<methods>
<method name="get_cell_alternative_tile" qualifiers="const">
<return type="int" />
- <argument index="0" name="coords" type="Vector2i" />
+ <param index="0" name="coords" type="Vector2i" />
<description>
- Returns the tile alternative ID of the cell at [code]coords[/code].
+ Returns the tile alternative ID of the cell at [param coords].
</description>
</method>
<method name="get_cell_atlas_coords" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="coords" type="Vector2i" />
+ <param index="0" name="coords" type="Vector2i" />
<description>
- Returns the tile atlas coordinates ID of the cell at [code]coords[/code].
+ Returns the tile atlas coordinates ID of the cell at [param coords].
</description>
</method>
<method name="get_cell_source_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="coords" type="Vector2i" />
+ <param index="0" name="coords" type="Vector2i" />
<description>
- Returns the tile source ID of the cell at [code]coords[/code].
+ Returns the tile source ID of the cell at [param coords].
</description>
</method>
<method name="get_size" qualifiers="const">
@@ -45,7 +45,7 @@
</method>
<method name="has_cell" qualifiers="const">
<return type="bool" />
- <argument index="0" name="coords" type="Vector2i" />
+ <param index="0" name="coords" type="Vector2i" />
<description>
Returns whether the pattern has a tile at the given coordinates.
</description>
@@ -58,25 +58,25 @@
</method>
<method name="remove_cell">
<return type="void" />
- <argument index="0" name="coords" type="Vector2i" />
- <argument index="1" name="update_size" type="bool" />
+ <param index="0" name="coords" type="Vector2i" />
+ <param index="1" name="update_size" type="bool" />
<description>
Remove the cell at the given coordinates.
</description>
</method>
<method name="set_cell">
<return type="void" />
- <argument index="0" name="coords" type="Vector2i" />
- <argument index="1" name="source_id" type="int" default="-1" />
- <argument index="2" name="atlas_coords" type="Vector2i" default="Vector2i(-1, -1)" />
- <argument index="3" name="alternative_tile" type="int" default="-1" />
+ <param index="0" name="coords" type="Vector2i" />
+ <param index="1" name="source_id" type="int" default="-1" />
+ <param index="2" name="atlas_coords" type="Vector2i" default="Vector2i(-1, -1)" />
+ <param index="3" name="alternative_tile" type="int" default="-1" />
<description>
- Sets the tile indentifiers for the cell at coordinates [code]coords[/code]. See [method TileMap.set_cell].
+ Sets the tile indentifiers for the cell at coordinates [param coords]. See [method TileMap.set_cell].
</description>
</method>
<method name="set_size">
<return type="void" />
- <argument index="0" name="size" type="Vector2i" />
+ <param index="0" name="size" type="Vector2i" />
<description>
Sets the size of the pattern.
</description>
diff --git a/doc/classes/TileSet.xml b/doc/classes/TileSet.xml
index 180e868ef8..7ced16d1af 100644
--- a/doc/classes/TileSet.xml
+++ b/doc/classes/TileSet.xml
@@ -24,66 +24,66 @@
<methods>
<method name="add_custom_data_layer">
<return type="void" />
- <argument index="0" name="to_position" type="int" default="-1" />
+ <param index="0" name="to_position" type="int" default="-1" />
<description>
- Adds a custom data layer to the TileSet at the given position [code]to_position[/code] in the array. If [code]to_position[/code] is -1, adds it at the end of the array.
+ Adds a custom data layer to the TileSet at the given position [param to_position] in the array. If [param to_position] is -1, adds it at the end of the array.
Custom data layers allow assigning custom properties to atlas tiles.
</description>
</method>
<method name="add_navigation_layer">
<return type="void" />
- <argument index="0" name="to_position" type="int" default="-1" />
+ <param index="0" name="to_position" type="int" default="-1" />
<description>
- Adds a navigation layer to the TileSet at the given position [code]to_position[/code] in the array. If [code]to_position[/code] is -1, adds it at the end of the array.
+ Adds a navigation layer to the TileSet at the given position [param to_position] in the array. If [param to_position] is -1, adds it at the end of the array.
Navigation layers allow assigning a navigable area to atlas tiles.
</description>
</method>
<method name="add_occlusion_layer">
<return type="void" />
- <argument index="0" name="to_position" type="int" default="-1" />
+ <param index="0" name="to_position" type="int" default="-1" />
<description>
- Adds an occlusion layer to the TileSet at the given position [code]to_position[/code] in the array. If [code]to_position[/code] is -1, adds it at the end of the array.
+ Adds an occlusion layer to the TileSet at the given position [param to_position] in the array. If [param to_position] is -1, adds it at the end of the array.
Occlusion layers allow assigning occlusion polygons to atlas tiles.
</description>
</method>
<method name="add_pattern">
<return type="int" />
- <argument index="0" name="pattern" type="TileMapPattern" />
- <argument index="1" name="index" type="int" default="-1" />
+ <param index="0" name="pattern" type="TileMapPattern" />
+ <param index="1" name="index" type="int" default="-1" />
<description>
- Adds a [TileMapPattern] to be stored in the TileSet resource. If provided, insert it at the given [code]index[/code].
+ Adds a [TileMapPattern] to be stored in the TileSet resource. If provided, insert it at the given [param index].
</description>
</method>
<method name="add_physics_layer">
<return type="void" />
- <argument index="0" name="to_position" type="int" default="-1" />
+ <param index="0" name="to_position" type="int" default="-1" />
<description>
- Adds a physics layer to the TileSet at the given position [code]to_position[/code] in the array. If [code]to_position[/code] is -1, adds it at the end of the array.
+ Adds a physics layer to the TileSet at the given position [param to_position] in the array. If [param to_position] is -1, adds it at the end of the array.
Physics layers allow assigning collision polygons to atlas tiles.
</description>
</method>
<method name="add_source">
<return type="int" />
- <argument index="0" name="source" type="TileSetSource" />
- <argument index="1" name="atlas_source_id_override" type="int" default="-1" />
+ <param index="0" name="source" type="TileSetSource" />
+ <param index="1" name="atlas_source_id_override" type="int" default="-1" />
<description>
- Adds a [TileSetSource] to the TileSet. If [code]atlas_source_id_override[/code] is not -1, also set its source ID. Otherwise, a unique identifier is automatically generated.
+ Adds a [TileSetSource] to the TileSet. If [param atlas_source_id_override] is not -1, also set its source ID. Otherwise, a unique identifier is automatically generated.
The function returns the added source source ID or -1 if the source could not be added.
</description>
</method>
<method name="add_terrain">
<return type="void" />
- <argument index="0" name="terrain_set" type="int" />
- <argument index="1" name="to_position" type="int" default="-1" />
+ <param index="0" name="terrain_set" type="int" />
+ <param index="1" name="to_position" type="int" default="-1" />
<description>
- Adds a new terrain to the given terrain set [code]terrain_set[/code] at the given position [code]to_position[/code] in the array. If [code]to_position[/code] is -1, adds it at the end of the array.
+ Adds a new terrain to the given terrain set [param terrain_set] at the given position [param to_position] in the array. If [param to_position] is -1, adds it at the end of the array.
</description>
</method>
<method name="add_terrain_set">
<return type="void" />
- <argument index="0" name="to_position" type="int" default="-1" />
+ <param index="0" name="to_position" type="int" default="-1" />
<description>
- Adds a new terrain set at the given position [code]to_position[/code] in the array. If [code]to_position[/code] is -1, adds it at the end of the array.
+ Adds a new terrain set at the given position [param to_position] in the array. If [param to_position] is -1, adds it at the end of the array.
</description>
</method>
<method name="cleanup_invalid_tile_proxies">
@@ -100,9 +100,9 @@
</method>
<method name="get_alternative_level_tile_proxy">
<return type="Array" />
- <argument index="0" name="source_from" type="int" />
- <argument index="1" name="coords_from" type="Vector2i" />
- <argument index="2" name="alternative_from" type="int" />
+ <param index="0" name="source_from" type="int" />
+ <param index="1" name="coords_from" type="Vector2i" />
+ <param index="2" name="alternative_from" type="int" />
<description>
Returns the alternative-level proxy for the given identifiers. The returned array contains the three proxie's target identifiers (source ID, atlas coords ID and alternative tile ID).
If the TileSet has no proxy for the given identifiers, returns an empty Array.
@@ -110,8 +110,8 @@
</method>
<method name="get_coords_level_tile_proxy">
<return type="Array" />
- <argument index="0" name="source_from" type="int" />
- <argument index="1" name="coords_from" type="Vector2i" />
+ <param index="0" name="source_from" type="int" />
+ <param index="1" name="coords_from" type="Vector2i" />
<description>
Returns the coordinate-level proxy for the given identifiers. The returned array contains the two target identifiers of the proxy (source ID and atlas coordinates ID).
If the TileSet has no proxy for the given identifiers, returns an empty Array.
@@ -119,21 +119,21 @@
</method>
<method name="get_custom_data_layer_by_name" qualifiers="const">
<return type="int" />
- <argument index="0" name="layer_name" type="String" />
+ <param index="0" name="layer_name" type="String" />
<description>
Returns the index of the custom data layer identified by the given name.
</description>
</method>
<method name="get_custom_data_layer_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="layer_index" type="int" />
+ <param index="0" name="layer_index" type="int" />
<description>
Returns the name of the custom data layer identified by the given index.
</description>
</method>
<method name="get_custom_data_layer_type" qualifiers="const">
<return type="int" enum="Variant.Type" />
- <argument index="0" name="layer_index" type="int" />
+ <param index="0" name="layer_index" type="int" />
<description>
Returns the type of the custom data layer identified by the given index.
</description>
@@ -146,7 +146,7 @@
</method>
<method name="get_navigation_layer_layers" qualifiers="const">
<return type="int" />
- <argument index="0" name="layer_index" type="int" />
+ <param index="0" name="layer_index" type="int" />
<description>
Returns the navigation layers (as in the Navigation server) of the gives TileSet navigation layer.
</description>
@@ -165,14 +165,14 @@
</method>
<method name="get_occlusion_layer_light_mask" qualifiers="const">
<return type="int" />
- <argument index="0" name="layer_index" type="int" />
+ <param index="0" name="layer_index" type="int" />
<description>
Returns the light mask of the occlusion layer.
</description>
</method>
<method name="get_occlusion_layer_sdf_collision" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_index" type="int" />
+ <param index="0" name="layer_index" type="int" />
<description>
Returns if the occluders from this layer use [code]sdf_collision[/code].
</description>
@@ -185,9 +185,9 @@
</method>
<method name="get_pattern">
<return type="TileMapPattern" />
- <argument index="0" name="index" type="int" default="-1" />
+ <param index="0" name="index" type="int" default="-1" />
<description>
- Returns the [TileMapPattern] at the given [code]index[/code].
+ Returns the [TileMapPattern] at the given [param index].
</description>
</method>
<method name="get_patterns_count">
@@ -198,21 +198,21 @@
</method>
<method name="get_physics_layer_collision_layer" qualifiers="const">
<return type="int" />
- <argument index="0" name="layer_index" type="int" />
+ <param index="0" name="layer_index" type="int" />
<description>
Returns the collision layer (as in the physics server) bodies on the given TileSet's physics layer are in.
</description>
</method>
<method name="get_physics_layer_collision_mask" qualifiers="const">
<return type="int" />
- <argument index="0" name="layer_index" type="int" />
+ <param index="0" name="layer_index" type="int" />
<description>
Returns the collision mask of bodies on the given TileSet's physics layer.
</description>
</method>
<method name="get_physics_layer_physics_material" qualifiers="const">
<return type="PhysicsMaterial" />
- <argument index="0" name="layer_index" type="int" />
+ <param index="0" name="layer_index" type="int" />
<description>
Returns the physics material of bodies on the given TileSet's physics layer.
</description>
@@ -225,9 +225,9 @@
</method>
<method name="get_source" qualifiers="const">
<return type="TileSetSource" />
- <argument index="0" name="source_id" type="int" />
+ <param index="0" name="source_id" type="int" />
<description>
- Returns the [TileSetSource] with ID [code]source_id[/code].
+ Returns the [TileSetSource] with ID [param source_id].
</description>
</method>
<method name="get_source_count" qualifiers="const">
@@ -238,14 +238,14 @@
</method>
<method name="get_source_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the source ID for source with index [code]index[/code].
+ Returns the source ID for source with index [param index].
</description>
</method>
<method name="get_source_level_tile_proxy">
<return type="int" />
- <argument index="0" name="source_from" type="int" />
+ <param index="0" name="source_from" type="int" />
<description>
Returns the source-level proxy for the given source identifier.
If the TileSet has no proxy for the given identifier, returns -1.
@@ -253,23 +253,23 @@
</method>
<method name="get_terrain_color" qualifiers="const">
<return type="Color" />
- <argument index="0" name="terrain_set" type="int" />
- <argument index="1" name="terrain_index" type="int" />
+ <param index="0" name="terrain_set" type="int" />
+ <param index="1" name="terrain_index" type="int" />
<description>
Returns a terrain's color.
</description>
</method>
<method name="get_terrain_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="terrain_set" type="int" />
- <argument index="1" name="terrain_index" type="int" />
+ <param index="0" name="terrain_set" type="int" />
+ <param index="1" name="terrain_index" type="int" />
<description>
Returns a terrain's name.
</description>
</method>
<method name="get_terrain_set_mode" qualifiers="const">
<return type="int" enum="TileSet.TerrainMode" />
- <argument index="0" name="terrain_set" type="int" />
+ <param index="0" name="terrain_set" type="int" />
<description>
Returns a terrain set mode.
</description>
@@ -282,47 +282,47 @@
</method>
<method name="get_terrains_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="terrain_set" type="int" />
+ <param index="0" name="terrain_set" type="int" />
<description>
Returns the number of terrains in the given terrain set.
</description>
</method>
<method name="has_alternative_level_tile_proxy">
<return type="bool" />
- <argument index="0" name="source_from" type="int" />
- <argument index="1" name="coords_from" type="Vector2i" />
- <argument index="2" name="alternative_from" type="int" />
+ <param index="0" name="source_from" type="int" />
+ <param index="1" name="coords_from" type="Vector2i" />
+ <param index="2" name="alternative_from" type="int" />
<description>
Returns if there is and alternative-level proxy for the given identifiers.
</description>
</method>
<method name="has_coords_level_tile_proxy">
<return type="bool" />
- <argument index="0" name="source_from" type="int" />
- <argument index="1" name="coords_from" type="Vector2i" />
+ <param index="0" name="source_from" type="int" />
+ <param index="1" name="coords_from" type="Vector2i" />
<description>
Returns if there is a coodinates-level proxy for the given identifiers.
</description>
</method>
<method name="has_source" qualifiers="const">
<return type="bool" />
- <argument index="0" name="source_id" type="int" />
+ <param index="0" name="source_id" type="int" />
<description>
Returns if this TileSet has a source for the given source ID.
</description>
</method>
<method name="has_source_level_tile_proxy">
<return type="bool" />
- <argument index="0" name="source_from" type="int" />
+ <param index="0" name="source_from" type="int" />
<description>
Returns if there is a source-level proxy for the given source ID.
</description>
</method>
<method name="map_tile_proxy" qualifiers="const">
<return type="Array" />
- <argument index="0" name="source_from" type="int" />
- <argument index="1" name="coords_from" type="Vector2i" />
- <argument index="2" name="alternative_from" type="int" />
+ <param index="0" name="source_from" type="int" />
+ <param index="1" name="coords_from" type="Vector2i" />
+ <param index="2" name="alternative_from" type="int" />
<description>
According to the configured proxies, maps the provided indentifiers to a new set of identifiers. The source ID, atlas coordinates ID and alternative tile ID are returned as a 3 elements Array.
This function first look for matching alternative-level proxies, then coordinates-level proxies, then source-level proxies.
@@ -331,142 +331,142 @@
</method>
<method name="move_custom_data_layer">
<return type="void" />
- <argument index="0" name="layer_index" type="int" />
- <argument index="1" name="to_position" type="int" />
+ <param index="0" name="layer_index" type="int" />
+ <param index="1" name="to_position" type="int" />
<description>
- Moves the custom data layer at index [code]layer_index[/code] to the given position [code]to_position[/code] in the array. Also updates the atlas tiles accordingly.
+ Moves the custom data layer at index [param layer_index] to the given position [param to_position] in the array. Also updates the atlas tiles accordingly.
</description>
</method>
<method name="move_navigation_layer">
<return type="void" />
- <argument index="0" name="layer_index" type="int" />
- <argument index="1" name="to_position" type="int" />
+ <param index="0" name="layer_index" type="int" />
+ <param index="1" name="to_position" type="int" />
<description>
- Moves the navigation layer at index [code]layer_index[/code] to the given position [code]to_position[/code] in the array. Also updates the atlas tiles accordingly.
+ Moves the navigation layer at index [param layer_index] to the given position [param to_position] in the array. Also updates the atlas tiles accordingly.
</description>
</method>
<method name="move_occlusion_layer">
<return type="void" />
- <argument index="0" name="layer_index" type="int" />
- <argument index="1" name="to_position" type="int" />
+ <param index="0" name="layer_index" type="int" />
+ <param index="1" name="to_position" type="int" />
<description>
- Moves the occlusion layer at index [code]layer_index[/code] to the given position [code]to_position[/code] in the array. Also updates the atlas tiles accordingly.
+ Moves the occlusion layer at index [param layer_index] to the given position [param to_position] in the array. Also updates the atlas tiles accordingly.
</description>
</method>
<method name="move_physics_layer">
<return type="void" />
- <argument index="0" name="layer_index" type="int" />
- <argument index="1" name="to_position" type="int" />
+ <param index="0" name="layer_index" type="int" />
+ <param index="1" name="to_position" type="int" />
<description>
- Moves the physics layer at index [code]layer_index[/code] to the given position [code]to_position[/code] in the array. Also updates the atlas tiles accordingly.
+ Moves the physics layer at index [param layer_index] to the given position [param to_position] in the array. Also updates the atlas tiles accordingly.
</description>
</method>
<method name="move_terrain">
<return type="void" />
- <argument index="0" name="terrain_set" type="int" />
- <argument index="1" name="terrain_index" type="int" />
- <argument index="2" name="to_position" type="int" />
+ <param index="0" name="terrain_set" type="int" />
+ <param index="1" name="terrain_index" type="int" />
+ <param index="2" name="to_position" type="int" />
<description>
- Moves the terrain at index [code]terrain_index[/code] for terrain set [code]terrain_set[/code] to the given position [code]to_position[/code] in the array. Also updates the atlas tiles accordingly.
+ Moves the terrain at index [param terrain_index] for terrain set [param terrain_set] to the given position [param to_position] in the array. Also updates the atlas tiles accordingly.
</description>
</method>
<method name="move_terrain_set">
<return type="void" />
- <argument index="0" name="terrain_set" type="int" />
- <argument index="1" name="to_position" type="int" />
+ <param index="0" name="terrain_set" type="int" />
+ <param index="1" name="to_position" type="int" />
<description>
- Moves the terrain set at index [code]terrain_set[/code] to the given position [code]to_position[/code] in the array. Also updates the atlas tiles accordingly.
+ Moves the terrain set at index [param terrain_set] to the given position [param to_position] in the array. Also updates the atlas tiles accordingly.
</description>
</method>
<method name="remove_alternative_level_tile_proxy">
<return type="void" />
- <argument index="0" name="source_from" type="int" />
- <argument index="1" name="coords_from" type="Vector2i" />
- <argument index="2" name="alternative_from" type="int" />
+ <param index="0" name="source_from" type="int" />
+ <param index="1" name="coords_from" type="Vector2i" />
+ <param index="2" name="alternative_from" type="int" />
<description>
Removes an alternative-level proxy for the given identifiers.
</description>
</method>
<method name="remove_coords_level_tile_proxy">
<return type="void" />
- <argument index="0" name="source_from" type="int" />
- <argument index="1" name="coords_from" type="Vector2i" />
+ <param index="0" name="source_from" type="int" />
+ <param index="1" name="coords_from" type="Vector2i" />
<description>
Removes a coordinates-level proxy for the given identifiers.
</description>
</method>
<method name="remove_custom_data_layer">
<return type="void" />
- <argument index="0" name="layer_index" type="int" />
+ <param index="0" name="layer_index" type="int" />
<description>
- Removes the custom data layer at index [code]layer_index[/code]. Also updates the atlas tiles accordingly.
+ Removes the custom data layer at index [param layer_index]. Also updates the atlas tiles accordingly.
</description>
</method>
<method name="remove_navigation_layer">
<return type="void" />
- <argument index="0" name="layer_index" type="int" />
+ <param index="0" name="layer_index" type="int" />
<description>
- Removes the navigation layer at index [code]layer_index[/code]. Also updates the atlas tiles accordingly.
+ Removes the navigation layer at index [param layer_index]. Also updates the atlas tiles accordingly.
</description>
</method>
<method name="remove_occlusion_layer">
<return type="void" />
- <argument index="0" name="layer_index" type="int" />
+ <param index="0" name="layer_index" type="int" />
<description>
- Removes the occlusion layer at index [code]layer_index[/code]. Also updates the atlas tiles accordingly.
+ Removes the occlusion layer at index [param layer_index]. Also updates the atlas tiles accordingly.
</description>
</method>
<method name="remove_pattern">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Remove the [TileMapPattern] at the given index.
</description>
</method>
<method name="remove_physics_layer">
<return type="void" />
- <argument index="0" name="layer_index" type="int" />
+ <param index="0" name="layer_index" type="int" />
<description>
- Removes the physics layer at index [code]layer_index[/code]. Also updates the atlas tiles accordingly.
+ Removes the physics layer at index [param layer_index]. Also updates the atlas tiles accordingly.
</description>
</method>
<method name="remove_source">
<return type="void" />
- <argument index="0" name="source_id" type="int" />
+ <param index="0" name="source_id" type="int" />
<description>
Removes the source with the given source ID.
</description>
</method>
<method name="remove_source_level_tile_proxy">
<return type="void" />
- <argument index="0" name="source_from" type="int" />
+ <param index="0" name="source_from" type="int" />
<description>
Removes a source-level tile proxy.
</description>
</method>
<method name="remove_terrain">
<return type="void" />
- <argument index="0" name="terrain_set" type="int" />
- <argument index="1" name="terrain_index" type="int" />
+ <param index="0" name="terrain_set" type="int" />
+ <param index="1" name="terrain_index" type="int" />
<description>
- Removes the terrain at index [code]terrain_index[/code] in the given terrain set [code]terrain_set[/code]. Also updates the atlas tiles accordingly.
+ Removes the terrain at index [param terrain_index] in the given terrain set [param terrain_set]. Also updates the atlas tiles accordingly.
</description>
</method>
<method name="remove_terrain_set">
<return type="void" />
- <argument index="0" name="terrain_set" type="int" />
+ <param index="0" name="terrain_set" type="int" />
<description>
- Removes the terrain set at index [code]terrain_set[/code]. Also updates the atlas tiles accordingly.
+ Removes the terrain set at index [param terrain_set]. Also updates the atlas tiles accordingly.
</description>
</method>
<method name="set_alternative_level_tile_proxy">
<return type="void" />
- <argument index="0" name="source_from" type="int" />
- <argument index="1" name="coords_from" type="Vector2i" />
- <argument index="2" name="alternative_from" type="int" />
- <argument index="3" name="source_to" type="int" />
- <argument index="4" name="coords_to" type="Vector2i" />
- <argument index="5" name="alternative_to" type="int" />
+ <param index="0" name="source_from" type="int" />
+ <param index="1" name="coords_from" type="Vector2i" />
+ <param index="2" name="alternative_from" type="int" />
+ <param index="3" name="source_to" type="int" />
+ <param index="4" name="coords_to" type="Vector2i" />
+ <param index="5" name="alternative_to" type="int" />
<description>
Create an alternative-level proxy for the given identifiers. A proxy will map set of tile identifiers to another set of identifiers.
This can be used to replace a tile in all TileMaps using this TileSet, as TileMap nodes will find and use the proxy's target tile when one is available.
@@ -475,10 +475,10 @@
</method>
<method name="set_coords_level_tile_proxy">
<return type="void" />
- <argument index="0" name="p_source_from" type="int" />
- <argument index="1" name="coords_from" type="Vector2i" />
- <argument index="2" name="source_to" type="int" />
- <argument index="3" name="coords_to" type="Vector2i" />
+ <param index="0" name="p_source_from" type="int" />
+ <param index="1" name="coords_from" type="Vector2i" />
+ <param index="2" name="source_to" type="int" />
+ <param index="3" name="coords_to" type="Vector2i" />
<description>
Creates a coordinates-level proxy for the given identifiers. A proxy will map set of tile identifiers to another set of identifiers. The alternative tile ID is kept the same when using coordinates-level proxies.
This can be used to replace a tile in all TileMaps using this TileSet, as TileMap nodes will find and use the proxy's target tile when one is available.
@@ -487,80 +487,80 @@
</method>
<method name="set_custom_data_layer_name">
<return type="void" />
- <argument index="0" name="layer_index" type="int" />
- <argument index="1" name="layer_name" type="String" />
+ <param index="0" name="layer_index" type="int" />
+ <param index="1" name="layer_name" type="String" />
<description>
Sets the name of the custom data layer identified by the given index. Names are identifiers of the layer therefore if the name is already taken it will fail and raise an error.
</description>
</method>
<method name="set_custom_data_layer_type">
<return type="void" />
- <argument index="0" name="layer_index" type="int" />
- <argument index="1" name="layer_type" type="int" enum="Variant.Type" />
+ <param index="0" name="layer_index" type="int" />
+ <param index="1" name="layer_type" type="int" enum="Variant.Type" />
<description>
Sets the type of the custom data layer identified by the given index.
</description>
</method>
<method name="set_navigation_layer_layers">
<return type="void" />
- <argument index="0" name="layer_index" type="int" />
- <argument index="1" name="layers" type="int" />
+ <param index="0" name="layer_index" type="int" />
+ <param index="1" name="layers" type="int" />
<description>
Sets the navigation layers (as in the navigation server) for navigation regions is the given TileSet navigation layer.
</description>
</method>
<method name="set_occlusion_layer_light_mask">
<return type="void" />
- <argument index="0" name="layer_index" type="int" />
- <argument index="1" name="light_mask" type="int" />
+ <param index="0" name="layer_index" type="int" />
+ <param index="1" name="light_mask" type="int" />
<description>
Sets the occlusion layer (as in the rendering server) for occluders in the given TileSet occlusion layer.
</description>
</method>
<method name="set_occlusion_layer_sdf_collision">
<return type="void" />
- <argument index="0" name="layer_index" type="int" />
- <argument index="1" name="sdf_collision" type="bool" />
+ <param index="0" name="layer_index" type="int" />
+ <param index="1" name="sdf_collision" type="bool" />
<description>
Enables or disables sdf collision for occluders in the given TileSet occlusion layer.
</description>
</method>
<method name="set_physics_layer_collision_layer">
<return type="void" />
- <argument index="0" name="layer_index" type="int" />
- <argument index="1" name="layer" type="int" />
+ <param index="0" name="layer_index" type="int" />
+ <param index="1" name="layer" type="int" />
<description>
Sets the physics layer (as in the physics server) for bodies in the given TileSet physics layer.
</description>
</method>
<method name="set_physics_layer_collision_mask">
<return type="void" />
- <argument index="0" name="layer_index" type="int" />
- <argument index="1" name="mask" type="int" />
+ <param index="0" name="layer_index" type="int" />
+ <param index="1" name="mask" type="int" />
<description>
Sets the physics layer (as in the physics server) for bodies in the given TileSet physics layer.
</description>
</method>
<method name="set_physics_layer_physics_material">
<return type="void" />
- <argument index="0" name="layer_index" type="int" />
- <argument index="1" name="physics_material" type="PhysicsMaterial" />
+ <param index="0" name="layer_index" type="int" />
+ <param index="1" name="physics_material" type="PhysicsMaterial" />
<description>
Sets the physics material for bodies in the given TileSet physics layer.
</description>
</method>
<method name="set_source_id">
<return type="void" />
- <argument index="0" name="source_id" type="int" />
- <argument index="1" name="new_source_id" type="int" />
+ <param index="0" name="source_id" type="int" />
+ <param index="1" name="new_source_id" type="int" />
<description>
Changes a source's ID.
</description>
</method>
<method name="set_source_level_tile_proxy">
<return type="void" />
- <argument index="0" name="source_from" type="int" />
- <argument index="1" name="source_to" type="int" />
+ <param index="0" name="source_from" type="int" />
+ <param index="1" name="source_to" type="int" />
<description>
Creates a source-level proxy for the given source ID. A proxy will map set of tile identifiers to another set of identifiers. Both the atlac coordinates ID and the alternative tile ID are kept the same when using source-level proxies.
This can be used to replace a source in all TileMaps using this TileSet, as TileMap nodes will find and use the proxy's target source when one is available.
@@ -569,26 +569,26 @@
</method>
<method name="set_terrain_color">
<return type="void" />
- <argument index="0" name="terrain_set" type="int" />
- <argument index="1" name="terrain_index" type="int" />
- <argument index="2" name="color" type="Color" />
+ <param index="0" name="terrain_set" type="int" />
+ <param index="1" name="terrain_index" type="int" />
+ <param index="2" name="color" type="Color" />
<description>
Sets a terrain's color. This color is used for identifying the different terrains in the TileSet editor.
</description>
</method>
<method name="set_terrain_name">
<return type="void" />
- <argument index="0" name="terrain_set" type="int" />
- <argument index="1" name="terrain_index" type="int" />
- <argument index="2" name="name" type="String" />
+ <param index="0" name="terrain_set" type="int" />
+ <param index="1" name="terrain_index" type="int" />
+ <param index="2" name="name" type="String" />
<description>
Sets a terrain's name.
</description>
</method>
<method name="set_terrain_set_mode">
<return type="void" />
- <argument index="0" name="terrain_set" type="int" />
- <argument index="1" name="mode" type="int" enum="TileSet.TerrainMode" />
+ <param index="0" name="terrain_set" type="int" />
+ <param index="1" name="mode" type="int" enum="TileSet.TerrainMode" />
<description>
Sets a terrain mode. Each mode determines which bits of a tile shape is used to match the neighbouring tiles' terrains.
</description>
diff --git a/doc/classes/TileSetAtlasSource.xml b/doc/classes/TileSetAtlasSource.xml
index db4e52f661..df469cd030 100644
--- a/doc/classes/TileSetAtlasSource.xml
+++ b/doc/classes/TileSetAtlasSource.xml
@@ -17,19 +17,19 @@
<methods>
<method name="create_alternative_tile">
<return type="int" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
- <argument index="1" name="alternative_id_override" type="int" default="-1" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
+ <param index="1" name="alternative_id_override" type="int" default="-1" />
<description>
- Creates an alternative tile for the tile at coords [code]atlas_coords[/code]. If [code]alternative_id_override[/code] is -1, give it an automatically generated unique ID, or assigns it the given ID otherwise.
- Returns the new alternative identifier, or -1 if the alternative could not be created with a provided [code]alternative_id_override[/code].
+ Creates an alternative tile for the tile at coordinates [param atlas_coords]. If [param alternative_id_override] is -1, give it an automatically generated unique ID, or assigns it the given ID otherwise.
+ Returns the new alternative identifier, or -1 if the alternative could not be created with a provided [param alternative_id_override].
</description>
</method>
<method name="create_tile">
<return type="void" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
- <argument index="1" name="size" type="Vector2i" default="Vector2i(1, 1)" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
+ <param index="1" name="size" type="Vector2i" default="Vector2i(1, 1)" />
<description>
- Creates a new tile at coords [code]atlas_coords[/code] with size [code]size[/code].
+ Creates a new tile at coordinates [param atlas_coords] with the given [param size].
</description>
</method>
<method name="get_atlas_grid_size" qualifiers="const">
@@ -40,7 +40,7 @@
</method>
<method name="get_next_alternative_tile_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
<description>
Returns the alternative ID a following call to [method create_alternative_tile] would return.
</description>
@@ -53,184 +53,184 @@
</method>
<method name="get_runtime_tile_texture_region" qualifiers="const">
<return type="Rect2i" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
- <argument index="1" name="frame" type="int" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
+ <param index="1" name="frame" type="int" />
<description>
- Returns the region of the tile at coordinates [code]atlas_coords[/code] for frame [code]frame[/code] inside the texture returned by [method get_runtime_texture].
+ Returns the region of the tile at coordinates [param atlas_coords] for the given [param frame] inside the texture returned by [method get_runtime_texture].
[b]Note:[/b] If [member use_texture_padding] is [code]false[/code], returns the same as [method get_tile_texture_region].
</description>
</method>
<method name="get_tile_animation_columns" qualifiers="const">
<return type="int" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
<description>
- Returns how many columns the tile at [code]atlas_coords[/code] has in its animation layout.
+ Returns how many columns the tile at [param atlas_coords] has in its animation layout.
</description>
</method>
<method name="get_tile_animation_frame_duration" qualifiers="const">
<return type="float" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
- <argument index="1" name="frame_index" type="int" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
+ <param index="1" name="frame_index" type="int" />
<description>
- Returns the animation frame duration of frame [code]frame_index[/code] for the tile at coordinates [code]atlas_coords[/code].
+ Returns the animation frame duration of frame [param frame_index] for the tile at coordinates [param atlas_coords].
</description>
</method>
<method name="get_tile_animation_frames_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
<description>
- Returns how many animation frames has the tile at coordinates [code]atlas_coords[/code].
+ Returns how many animation frames has the tile at coordinates [param atlas_coords].
</description>
</method>
<method name="get_tile_animation_separation" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
<description>
- Returns the separation (as in the atlas grid) between each frame of an animated tile at coordinates [code]atlas_coords[/code].
+ Returns the separation (as in the atlas grid) between each frame of an animated tile at coordinates [param atlas_coords].
</description>
</method>
<method name="get_tile_animation_speed" qualifiers="const">
<return type="float" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
<description>
- Returns the animation speed of the tile at coordinates [code]atlas_coords[/code].
+ Returns the animation speed of the tile at coordinates [param atlas_coords].
</description>
</method>
<method name="get_tile_animation_total_duration" qualifiers="const">
<return type="float" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
<description>
- Returns the sum of the sum of the frame durations of the tile at coordinates [code]atlas_coords[/code]. This value needs to be divided by the animation speed to get the actual animation loop duration.
+ Returns the sum of the sum of the frame durations of the tile at coordinates [param atlas_coords]. This value needs to be divided by the animation speed to get the actual animation loop duration.
</description>
</method>
<method name="get_tile_at_coords" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
<description>
- If there is a tile covering the [code]atlas_coords[/code] coordinates, returns the top-left coordinates of the tile (thus its coordinate ID). Returns [code]Vector2i(-1, -1)[/code] otherwise.
+ If there is a tile covering the [param atlas_coords] coordinates, returns the top-left coordinates of the tile (thus its coordinate ID). Returns [code]Vector2i(-1, -1)[/code] otherwise.
</description>
</method>
<method name="get_tile_data" qualifiers="const">
<return type="TileData" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
- <argument index="1" name="alternative_tile" type="int" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
+ <param index="1" name="alternative_tile" type="int" />
<description>
Returns the [TileData] object for the given atlas coordinates and alternative ID.
</description>
</method>
<method name="get_tile_size_in_atlas" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
<description>
- Returns the size of the tile (in the grid coordinates system) at coordinates [code]atlas_coords[/code].
+ Returns the size of the tile (in the grid coordinates system) at coordinates [param atlas_coords].
</description>
</method>
<method name="get_tile_texture_region" qualifiers="const">
<return type="Rect2i" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
- <argument index="1" name="frame" type="int" default="0" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
+ <param index="1" name="frame" type="int" default="0" />
<description>
- Returns a tile's texture region in the atlas texture. For animated tiles, a [code]frame[/code] argument might be provided for the different frames of the animation.
+ Returns a tile's texture region in the atlas texture. For animated tiles, a [param frame] argument might be provided for the different frames of the animation.
</description>
</method>
<method name="get_tiles_to_be_removed_on_change">
<return type="PackedVector2Array" />
- <argument index="0" name="texture" type="Texture2D" />
- <argument index="1" name="margins" type="Vector2i" />
- <argument index="2" name="separation" type="Vector2i" />
- <argument index="3" name="texture_region_size" type="Vector2i" />
+ <param index="0" name="texture" type="Texture2D" />
+ <param index="1" name="margins" type="Vector2i" />
+ <param index="2" name="separation" type="Vector2i" />
+ <param index="3" name="texture_region_size" type="Vector2i" />
<description>
- Returns an array of tiles coordinates ID that will be automatically removed when modifying one or several of those properties: [code]texture[/code], [code]margins[/code], [code]separation[/code] or [code]texture_region_size[/code]. This can be used to undo changes that would have caused tiles data loss.
+ Returns an array of tiles coordinates ID that will be automatically removed when modifying one or several of those properties: [param texture], [param margins], [param separation] or [param texture_region_size]. This can be used to undo changes that would have caused tiles data loss.
</description>
</method>
<method name="has_room_for_tile" qualifiers="const">
<return type="bool" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
- <argument index="1" name="size" type="Vector2i" />
- <argument index="2" name="animation_columns" type="int" />
- <argument index="3" name="animation_separation" type="Vector2i" />
- <argument index="4" name="frames_count" type="int" />
- <argument index="5" name="ignored_tile" type="Vector2i" default="Vector2i(-1, -1)" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
+ <param index="1" name="size" type="Vector2i" />
+ <param index="2" name="animation_columns" type="int" />
+ <param index="3" name="animation_separation" type="Vector2i" />
+ <param index="4" name="frames_count" type="int" />
+ <param index="5" name="ignored_tile" type="Vector2i" default="Vector2i(-1, -1)" />
<description>
- Returns whether there is enough room in an atlas to create/modify a tile with the given properties. If [code]ignored_tile[/code] is provided, act as is the given tile was not present in the atlas. This may be used when you want to modify a tile's properties.
+ Returns whether there is enough room in an atlas to create/modify a tile with the given properties. If [param ignored_tile] is provided, act as is the given tile was not present in the atlas. This may be used when you want to modify a tile's properties.
</description>
</method>
<method name="move_tile_in_atlas">
<return type="void" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
- <argument index="1" name="new_atlas_coords" type="Vector2i" default="Vector2i(-1, -1)" />
- <argument index="2" name="new_size" type="Vector2i" default="Vector2i(-1, -1)" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
+ <param index="1" name="new_atlas_coords" type="Vector2i" default="Vector2i(-1, -1)" />
+ <param index="2" name="new_size" type="Vector2i" default="Vector2i(-1, -1)" />
<description>
- Move the tile and its alternatives at the [code]atlas_coords[/code] coordinates to the [code]new_atlas_coords[/code] coordinates with the [code]new_size[/code] size. This functions will fail if a tile is already present in the given area.
- If [code]new_atlas_coords[/code] is [code]Vector2i(-1, -1)[/code], keeps the tile's coordinates. If [code]new_size[/code] is [code]Vector2i(-1, -1)[/code], keeps the tile's size.
+ Move the tile and its alternatives at the [param atlas_coords] coordinates to the [param new_atlas_coords] coordinates with the [param new_size] size. This functions will fail if a tile is already present in the given area.
+ If [param new_atlas_coords] is [code]Vector2i(-1, -1)[/code], keeps the tile's coordinates. If [param new_size] is [code]Vector2i(-1, -1)[/code], keeps the tile's size.
To avoid an error, first check if a move is possible using [method has_room_for_tile].
</description>
</method>
<method name="remove_alternative_tile">
<return type="void" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
- <argument index="1" name="alternative_tile" type="int" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
+ <param index="1" name="alternative_tile" type="int" />
<description>
- Remove a tile's alternative with alternative ID [code]alternative_tile[/code].
- Calling this function with [code]alternative_tile[/code] equals to 0 will fail, as the base tile alternative cannot be removed.
+ Remove a tile's alternative with alternative ID [param alternative_tile].
+ Calling this function with [param alternative_tile] equals to 0 will fail, as the base tile alternative cannot be removed.
</description>
</method>
<method name="remove_tile">
<return type="void" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
<description>
- Remove a tile and its alternative at coordinates [code]atlas_coords[/code].
+ Remove a tile and its alternative at coordinates [param atlas_coords].
</description>
</method>
<method name="set_alternative_tile_id">
<return type="void" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
- <argument index="1" name="alternative_tile" type="int" />
- <argument index="2" name="new_id" type="int" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
+ <param index="1" name="alternative_tile" type="int" />
+ <param index="2" name="new_id" type="int" />
<description>
- Change a tile's alternative ID from [code]alternative_tile[/code] to [code]new_id[/code].
- Calling this function with [code]alternative_id[/code] equals to 0 will fail, as the base tile alternative cannot be moved.
+ Change a tile's alternative ID from [param alternative_tile] to [param new_id].
+ Calling this function with [param new_id] of 0 will fail, as the base tile alternative cannot be moved.
</description>
</method>
<method name="set_tile_animation_columns">
<return type="void" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
- <argument index="1" name="frame_columns" type="int" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
+ <param index="1" name="frame_columns" type="int" />
<description>
- Sets the number of columns in the animation layout of the tile at coordinates [code]atlas_coords[/code]. If set to 0, then the different frames of the animation are laid out as a single horizontal line in the atlas.
+ Sets the number of columns in the animation layout of the tile at coordinates [param atlas_coords]. If set to 0, then the different frames of the animation are laid out as a single horizontal line in the atlas.
</description>
</method>
<method name="set_tile_animation_frame_duration">
<return type="void" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
- <argument index="1" name="frame_index" type="int" />
- <argument index="2" name="duration" type="float" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
+ <param index="1" name="frame_index" type="int" />
+ <param index="2" name="duration" type="float" />
<description>
- Sets the animation frame duration of frame [code]frame_index[/code] for the tile at coordinates [code]atlas_coords[/code].
+ Sets the animation frame [param duration] of frame [param frame_index] for the tile at coordinates [param atlas_coords].
</description>
</method>
<method name="set_tile_animation_frames_count">
<return type="void" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
- <argument index="1" name="frames_count" type="int" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
+ <param index="1" name="frames_count" type="int" />
<description>
- Sets how many animation frames the tile at coordinates [code]atlas_coords[/code] has.
+ Sets how many animation frames the tile at coordinates [param atlas_coords] has.
</description>
</method>
<method name="set_tile_animation_separation">
<return type="void" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
- <argument index="1" name="separation" type="Vector2i" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
+ <param index="1" name="separation" type="Vector2i" />
<description>
- Sets the margin (in grid tiles) between each tile in the animation layout of the tile at coordinates [code]atlas_coords[/code] has.
+ Sets the margin (in grid tiles) between each tile in the animation layout of the tile at coordinates [param atlas_coords] has.
</description>
</method>
<method name="set_tile_animation_speed">
<return type="void" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
- <argument index="1" name="speed" type="float" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
+ <param index="1" name="speed" type="float" />
<description>
- Sets the animation speed of the tile at coordinates [code]atlas_coords[/code] has.
+ Sets the animation speed of the tile at coordinates [param atlas_coords] has.
</description>
</method>
</methods>
diff --git a/doc/classes/TileSetScenesCollectionSource.xml b/doc/classes/TileSetScenesCollectionSource.xml
index a8ef253933..ec8fe2ad54 100644
--- a/doc/classes/TileSetScenesCollectionSource.xml
+++ b/doc/classes/TileSetScenesCollectionSource.xml
@@ -12,8 +12,8 @@
<methods>
<method name="create_scene_tile">
<return type="int" />
- <argument index="0" name="packed_scene" type="PackedScene" />
- <argument index="1" name="id_override" type="int" default="-1" />
+ <param index="0" name="packed_scene" type="PackedScene" />
+ <param index="1" name="id_override" type="int" default="-1" />
<description>
Creates a scene-based tile out of the given scene.
Returns a newly generated unique ID.
@@ -27,23 +27,23 @@
</method>
<method name="get_scene_tile_display_placeholder" qualifiers="const">
<return type="bool" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
- Returns whether the scene tile with id [code]id[/code] displays a placeholder in the editor.
+ Returns whether the scene tile with [param id] displays a placeholder in the editor.
</description>
</method>
<method name="get_scene_tile_id">
<return type="int" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the scene tile ID of the scene tile at index [code]index[/code].
+ Returns the scene tile ID of the scene tile at [param index].
</description>
</method>
<method name="get_scene_tile_scene" qualifiers="const">
<return type="PackedScene" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
- Returns the [PackedScene] resource of scene tile with id [code]id[/code].
+ Returns the [PackedScene] resource of scene tile with [param id].
</description>
</method>
<method name="get_scene_tiles_count">
@@ -54,40 +54,40 @@
</method>
<method name="has_scene_tile_id">
<return type="bool" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
- Returns whether this TileSet source has a scene tile with id [code]id[/code].
+ Returns whether this TileSet source has a scene tile with [param id].
</description>
</method>
<method name="remove_scene_tile">
<return type="void" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
- Remove the scene tile with id [code]id[/code].
+ Remove the scene tile with [param id].
</description>
</method>
<method name="set_scene_tile_display_placeholder">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="display_placeholder" type="bool" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="display_placeholder" type="bool" />
<description>
- Sets whether or not the scene tile with id [code]id[/code] should display a placeholder in the editor. This might be useful for scenes that are not visible.
+ Sets whether or not the scene tile with [param id] should display a placeholder in the editor. This might be useful for scenes that are not visible.
</description>
</method>
<method name="set_scene_tile_id">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="new_id" type="int" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="new_id" type="int" />
<description>
- Changes a scene tile's ID from [code]id[/code] to [code]new_id[/code]. This will fail if there is already a tile with a ID equal to [code]new_id[/code].
+ Changes a scene tile's ID from [param id] to [param new_id]. This will fail if there is already a tile with a ID equal to [param new_id].
</description>
</method>
<method name="set_scene_tile_scene">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="packed_scene" type="PackedScene" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="packed_scene" type="PackedScene" />
<description>
- Assigns a [PackedScene] resource to the scene tile with id [code]id[/code]. This will fail if the scene does not extend CanvasItem, as positioning properties are needed to place the scene on the TileMap.
+ Assigns a [PackedScene] resource to the scene tile with [param id]. This will fail if the scene does not extend CanvasItem, as positioning properties are needed to place the scene on the TileMap.
</description>
</method>
</methods>
diff --git a/doc/classes/TileSetSource.xml b/doc/classes/TileSetSource.xml
index 3d23975e37..e88e725bf4 100644
--- a/doc/classes/TileSetSource.xml
+++ b/doc/classes/TileSetSource.xml
@@ -15,26 +15,26 @@
<methods>
<method name="get_alternative_tile_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
- <argument index="1" name="index" type="int" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
+ <param index="1" name="index" type="int" />
<description>
- Returns the alternative ID for the tile with coordinates ID [code]atlas_coords[/code] at index [code]index[/code].
+ Returns the alternative ID for the tile with coordinates ID [param atlas_coords] at index [param index].
</description>
</method>
<method name="get_alternative_tiles_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
<description>
- Returns the number of alternatives tiles for the coordinates ID [code]atlas_coords[/code].
+ Returns the number of alternatives tiles for the coordinates ID [param atlas_coords].
For [TileSetAtlasSource], this always return at least 1, as the base tile with ID 0 is always part of the alternatives list.
Returns -1 if there is not tile at the given coords.
</description>
</method>
<method name="get_tile_id" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns the tile coordinates ID of the tile with index [code]index[/code].
+ Returns the tile coordinates ID of the tile with index [param index].
</description>
</method>
<method name="get_tiles_count" qualifiers="const">
@@ -45,17 +45,17 @@
</method>
<method name="has_alternative_tile" qualifiers="const">
<return type="bool" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
- <argument index="1" name="alternative_tile" type="int" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
+ <param index="1" name="alternative_tile" type="int" />
<description>
- Returns if the base tile at coordinates [code]atlas_coords[/code] has an alternative with ID [code]alternative_tile[/code].
+ Returns if the base tile at coordinates [param atlas_coords] has an alternative with ID [param alternative_tile].
</description>
</method>
<method name="has_tile" qualifiers="const">
<return type="bool" />
- <argument index="0" name="atlas_coords" type="Vector2i" />
+ <param index="0" name="atlas_coords" type="Vector2i" />
<description>
- Returns if this atlas has a tile with coordinates ID [code]atlas_coordinates[/code].
+ Returns if this atlas has a tile with coordinates ID [param atlas_coords].
</description>
</method>
</methods>
diff --git a/doc/classes/Time.xml b/doc/classes/Time.xml
index 5fc85c869b..cdbe30c444 100644
--- a/doc/classes/Time.xml
+++ b/doc/classes/Time.xml
@@ -15,54 +15,54 @@
<methods>
<method name="get_date_dict_from_system" qualifiers="const">
<return type="Dictionary" />
- <argument index="0" name="utc" type="bool" default="false" />
+ <param index="0" name="utc" type="bool" default="false" />
<description>
Returns the current date as a dictionary of keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]weekday[/code], and [code]dst[/code] (Daylight Savings Time).
- The returned values are in the system's local time when [code]utc[/code] is false, otherwise they are in UTC.
+ The returned values are in the system's local time when [param utc] is [code]false[/code], otherwise they are in UTC.
</description>
</method>
<method name="get_date_dict_from_unix_time" qualifiers="const">
<return type="Dictionary" />
- <argument index="0" name="unix_time_val" type="int" />
+ <param index="0" name="unix_time_val" type="int" />
<description>
Converts the given Unix timestamp to a dictionary of keys: [code]year[/code], [code]month[/code], [code]day[/code], and [code]weekday[/code].
</description>
</method>
<method name="get_date_string_from_system" qualifiers="const">
<return type="String" />
- <argument index="0" name="utc" type="bool" default="false" />
+ <param index="0" name="utc" type="bool" default="false" />
<description>
Returns the current date as an ISO 8601 date string (YYYY-MM-DD).
- The returned values are in the system's local time when [code]utc[/code] is false, otherwise they are in UTC.
+ The returned values are in the system's local time when [param utc] is [code]false[/code], otherwise they are in UTC.
</description>
</method>
<method name="get_date_string_from_unix_time" qualifiers="const">
<return type="String" />
- <argument index="0" name="unix_time_val" type="int" />
+ <param index="0" name="unix_time_val" type="int" />
<description>
Converts the given Unix timestamp to an ISO 8601 date string (YYYY-MM-DD).
</description>
</method>
<method name="get_datetime_dict_from_datetime_string" qualifiers="const">
<return type="Dictionary" />
- <argument index="0" name="datetime" type="String" />
- <argument index="1" name="weekday" type="bool" />
+ <param index="0" name="datetime" type="String" />
+ <param index="1" name="weekday" type="bool" />
<description>
Converts the given ISO 8601 date and time string (YYYY-MM-DDTHH:MM:SS) to a dictionary of keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]weekday[/code], [code]hour[/code], [code]minute[/code], and [code]second[/code].
- If [code]weekday[/code] is false, then the [code]weekday[/code] entry is excluded (the calculation is relatively expensive).
+ If [param weekday] is [code]false[/code], then the [code]weekday[/code] entry is excluded (the calculation is relatively expensive).
[b]Note:[/b] Any decimal fraction in the time string will be ignored silently.
</description>
</method>
<method name="get_datetime_dict_from_system" qualifiers="const">
<return type="Dictionary" />
- <argument index="0" name="utc" type="bool" default="false" />
+ <param index="0" name="utc" type="bool" default="false" />
<description>
Returns the current date as a dictionary of keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]weekday[/code], [code]hour[/code], [code]minute[/code], and [code]second[/code].
</description>
</method>
<method name="get_datetime_dict_from_unix_time" qualifiers="const">
<return type="Dictionary" />
- <argument index="0" name="unix_time_val" type="int" />
+ <param index="0" name="unix_time_val" type="int" />
<description>
Converts the given Unix timestamp to a dictionary of keys: [code]year[/code], [code]month[/code], [code]day[/code], and [code]weekday[/code].
The returned Dictionary's values will be the same as the [method get_datetime_dict_from_system] if the Unix timestamp is the current time, with the exception of Daylight Savings Time as it cannot be determined from the epoch.
@@ -70,37 +70,37 @@
</method>
<method name="get_datetime_string_from_datetime_dict" qualifiers="const">
<return type="String" />
- <argument index="0" name="datetime" type="Dictionary" />
- <argument index="1" name="use_space" type="bool" />
+ <param index="0" name="datetime" type="Dictionary" />
+ <param index="1" name="use_space" type="bool" />
<description>
Converts the given dictionary of keys to an ISO 8601 date and time string (YYYY-MM-DDTHH:MM:SS).
The given dictionary can be populated with the following keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]hour[/code], [code]minute[/code], and [code]second[/code]. Any other entries (including [code]dst[/code]) are ignored.
If the dictionary is empty, [code]0[/code] is returned. If some keys are omitted, they default to the equivalent values for the Unix epoch timestamp 0 (1970-01-01 at 00:00:00).
- If [code]use_space[/code] is true, use a space instead of the letter T in the middle.
+ If [param use_space] is [code]true[/code], the date and time bits are separated by an empty space character instead of the letter T.
</description>
</method>
<method name="get_datetime_string_from_system" qualifiers="const">
<return type="String" />
- <argument index="0" name="utc" type="bool" default="false" />
- <argument index="1" name="use_space" type="bool" default="false" />
+ <param index="0" name="utc" type="bool" default="false" />
+ <param index="1" name="use_space" type="bool" default="false" />
<description>
Returns the current date and time as an ISO 8601 date and time string (YYYY-MM-DDTHH:MM:SS).
- The returned values are in the system's local time when [code]utc[/code] is false, otherwise they are in UTC.
- If [code]use_space[/code] is true, use a space instead of the letter T in the middle.
+ The returned values are in the system's local time when [param utc] is [code]false[/code], otherwise they are in UTC.
+ If [param use_space] is [code]true[/code], the date and time bits are separated by an empty space character instead of the letter T.
</description>
</method>
<method name="get_datetime_string_from_unix_time" qualifiers="const">
<return type="String" />
- <argument index="0" name="unix_time_val" type="int" />
- <argument index="1" name="use_space" type="bool" default="false" />
+ <param index="0" name="unix_time_val" type="int" />
+ <param index="1" name="use_space" type="bool" default="false" />
<description>
Converts the given Unix timestamp to an ISO 8601 date and time string (YYYY-MM-DDTHH:MM:SS).
- If [code]use_space[/code] is true, use a space instead of the letter T in the middle.
+ If [param use_space] is [code]true[/code], the date and time bits are separated by an empty space character instead of the letter T.
</description>
</method>
<method name="get_offset_string_from_offset_minutes" qualifiers="const">
<return type="String" />
- <argument index="0" name="offset_minutes" type="int" />
+ <param index="0" name="offset_minutes" type="int" />
<description>
Converts the given timezone offset in minutes to a timezone offset string. For example, -480 returns "-08:00", 345 returns "+05:45", and 0 returns "+00:00".
</description>
@@ -121,30 +121,30 @@
</method>
<method name="get_time_dict_from_system" qualifiers="const">
<return type="Dictionary" />
- <argument index="0" name="utc" type="bool" default="false" />
+ <param index="0" name="utc" type="bool" default="false" />
<description>
Returns the current time as a dictionary of keys: [code]hour[/code], [code]minute[/code], and [code]second[/code].
- The returned values are in the system's local time when [code]utc[/code] is false, otherwise they are in UTC.
+ The returned values are in the system's local time when [param utc] is [code]false[/code], otherwise they are in UTC.
</description>
</method>
<method name="get_time_dict_from_unix_time" qualifiers="const">
<return type="Dictionary" />
- <argument index="0" name="unix_time_val" type="int" />
+ <param index="0" name="unix_time_val" type="int" />
<description>
Converts the given time to a dictionary of keys: [code]hour[/code], [code]minute[/code], and [code]second[/code].
</description>
</method>
<method name="get_time_string_from_system" qualifiers="const">
<return type="String" />
- <argument index="0" name="utc" type="bool" default="false" />
+ <param index="0" name="utc" type="bool" default="false" />
<description>
Returns the current time as an ISO 8601 time string (HH:MM:SS).
- The returned values are in the system's local time when [code]utc[/code] is false, otherwise they are in UTC.
+ The returned values are in the system's local time when [param utc] is [code]false[/code], otherwise they are in UTC.
</description>
</method>
<method name="get_time_string_from_unix_time" qualifiers="const">
<return type="String" />
- <argument index="0" name="unix_time_val" type="int" />
+ <param index="0" name="unix_time_val" type="int" />
<description>
Converts the given Unix timestamp to an ISO 8601 time string (HH:MM:SS).
</description>
@@ -157,7 +157,7 @@
</method>
<method name="get_unix_time_from_datetime_dict" qualifiers="const">
<return type="int" />
- <argument index="0" name="datetime" type="Dictionary" />
+ <param index="0" name="datetime" type="Dictionary" />
<description>
Converts a dictionary of time values to a Unix timestamp.
The given dictionary can be populated with the following keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]hour[/code], [code]minute[/code], and [code]second[/code]. Any other entries (including [code]dst[/code]) are ignored.
@@ -168,7 +168,7 @@
</method>
<method name="get_unix_time_from_datetime_string" qualifiers="const">
<return type="int" />
- <argument index="0" name="datetime" type="String" />
+ <param index="0" name="datetime" type="String" />
<description>
Converts the given ISO 8601 date and/or time string to a Unix timestamp. The string can contain a date only, a time only, or both.
[b]Note:[/b] Unix timestamps are often in UTC. This method does not do any timezone conversion, so the timestamp will be in the same timezone as the given datetime string.
diff --git a/doc/classes/Timer.xml b/doc/classes/Timer.xml
index ebe25ed55e..d171797e80 100644
--- a/doc/classes/Timer.xml
+++ b/doc/classes/Timer.xml
@@ -19,9 +19,9 @@
</method>
<method name="start">
<return type="void" />
- <argument index="0" name="time_sec" type="float" default="-1" />
+ <param index="0" name="time_sec" type="float" default="-1" />
<description>
- Starts the timer. Sets [member wait_time] to [code]time_sec[/code] if [code]time_sec &gt; 0[/code]. This also resets the remaining time to [member wait_time].
+ Starts the timer. Sets [member wait_time] to [param time_sec] if [code]time_sec &gt; 0[/code]. This also resets the remaining time to [member wait_time].
[b]Note:[/b] This method will not resume a paused timer. See [member paused].
</description>
</method>
diff --git a/doc/classes/TorusMesh.xml b/doc/classes/TorusMesh.xml
new file mode 100644
index 0000000000..6b83152793
--- /dev/null
+++ b/doc/classes/TorusMesh.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="TorusMesh" inherits="PrimitiveMesh" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ Class representing a torus [PrimitiveMesh].
+ </brief_description>
+ <description>
+ Class representing a torus [PrimitiveMesh].
+ </description>
+ <tutorials>
+ </tutorials>
+ <members>
+ <member name="inner_radius" type="float" setter="set_inner_radius" getter="get_inner_radius" default="0.5">
+ The inner radius of the torus.
+ </member>
+ <member name="outer_radius" type="float" setter="set_outer_radius" getter="get_outer_radius" default="1.0">
+ The outer radius of the torus.
+ </member>
+ <member name="ring_segments" type="int" setter="set_ring_segments" getter="get_ring_segments" default="32">
+ The number of edges each ring of the torus is constructed of.
+ </member>
+ <member name="rings" type="int" setter="set_rings" getter="get_rings" default="64">
+ The number of slices the torus is constructed of.
+ </member>
+ </members>
+</class>
diff --git a/doc/classes/Transform2D.xml b/doc/classes/Transform2D.xml
index 924b4cd8e4..905b3d77af 100644
--- a/doc/classes/Transform2D.xml
+++ b/doc/classes/Transform2D.xml
@@ -22,34 +22,34 @@
</constructor>
<constructor name="Transform2D">
<return type="Transform2D" />
- <argument index="0" name="from" type="Transform2D" />
+ <param index="0" name="from" type="Transform2D" />
<description>
Constructs a [Transform2D] as a copy of the given [Transform2D].
</description>
</constructor>
<constructor name="Transform2D">
<return type="Transform2D" />
- <argument index="0" name="rotation" type="float" />
- <argument index="1" name="position" type="Vector2" />
+ <param index="0" name="rotation" type="float" />
+ <param index="1" name="position" type="Vector2" />
<description>
Constructs the transform from a given angle (in radians) and position.
</description>
</constructor>
<constructor name="Transform2D">
<return type="Transform2D" />
- <argument index="0" name="rotation" type="float" />
- <argument index="1" name="scale" type="Vector2" />
- <argument index="2" name="skew" type="float" />
- <argument index="3" name="position" type="Vector2" />
+ <param index="0" name="rotation" type="float" />
+ <param index="1" name="scale" type="Vector2" />
+ <param index="2" name="skew" type="float" />
+ <param index="3" name="position" type="Vector2" />
<description>
Constructs the transform from a given angle (in radians), scale, skew (in radians) and position.
</description>
</constructor>
<constructor name="Transform2D">
<return type="Transform2D" />
- <argument index="0" name="x_axis" type="Vector2" />
- <argument index="1" name="y_axis" type="Vector2" />
- <argument index="2" name="origin" type="Vector2" />
+ <param index="0" name="x_axis" type="Vector2" />
+ <param index="1" name="y_axis" type="Vector2" />
+ <param index="2" name="origin" type="Vector2" />
<description>
Constructs the transform from 3 [Vector2] values representing [member x], [member y], and the [member origin] (the three column vectors).
</description>
@@ -64,7 +64,7 @@
</method>
<method name="basis_xform" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="v" type="Vector2" />
+ <param index="0" name="v" type="Vector2" />
<description>
Returns a vector transformed (multiplied) by the basis matrix.
This method does not account for translation (the origin vector).
@@ -72,7 +72,7 @@
</method>
<method name="basis_xform_inv" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="v" type="Vector2" />
+ <param index="0" name="v" type="Vector2" />
<description>
Returns a vector transformed (multiplied) by the inverse basis matrix.
This method does not account for translation (the origin vector).
@@ -104,10 +104,10 @@
</method>
<method name="interpolate_with" qualifiers="const">
<return type="Transform2D" />
- <argument index="0" name="xform" type="Transform2D" />
- <argument index="1" name="weight" type="float" />
+ <param index="0" name="xform" type="Transform2D" />
+ <param index="1" name="weight" type="float" />
<description>
- Returns a transform interpolated between this transform and another by a given [code]weight[/code] (on the range of 0.0 to 1.0).
+ Returns a transform interpolated between this transform and another by a given [param weight] (on the range of 0.0 to 1.0).
</description>
</method>
<method name="inverse" qualifiers="const">
@@ -118,16 +118,16 @@
</method>
<method name="is_equal_approx" qualifiers="const">
<return type="bool" />
- <argument index="0" name="xform" type="Transform2D" />
+ <param index="0" name="xform" type="Transform2D" />
<description>
Returns [code]true[/code] if this transform and [code]transform[/code] are approximately equal, by calling [code]is_equal_approx[/code] on each component.
</description>
</method>
<method name="looking_at" qualifiers="const">
<return type="Transform2D" />
- <argument index="0" name="target" type="Vector2" default="Vector2(0, 0)" />
+ <param index="0" name="target" type="Vector2" default="Vector2(0, 0)" />
<description>
- Returns a copy of the transform rotated such that it's rotation on the X-axis points towards the [code]target[/code] position.
+ Returns a copy of the transform rotated such that it's rotation on the X-axis points towards the [param target] position.
Operations take place in global space.
</description>
</method>
@@ -139,28 +139,54 @@
</method>
<method name="rotated" qualifiers="const">
<return type="Transform2D" />
- <argument index="0" name="angle" type="float" />
+ <param index="0" name="angle" type="float" />
<description>
- Returns a copy of the transform rotated by the given [code]angle[/code] (in radians), using matrix multiplication.
+ Returns a copy of the transform rotated by the given [param angle] (in radians).
+ This method is an optimized version of multiplying the given transform [code]X[/code]
+ with a corresponding rotation transform [code]R[/code] from the left, i.e., [code]R * X[/code].
+ This can be seen as transforming with respect to the global/parent frame.
+ </description>
+ </method>
+ <method name="rotated_local" qualifiers="const">
+ <return type="Transform2D" />
+ <param index="0" name="angle" type="float" />
+ <description>
+ Returns a copy of the transform rotated by the given [param angle] (in radians).
+ This method is an optimized version of multiplying the given transform [code]X[/code]
+ with a corresponding rotation transform [code]R[/code] from the right, i.e., [code]X * R[/code].
+ This can be seen as transforming with respect to the local frame.
</description>
</method>
<method name="scaled" qualifiers="const">
<return type="Transform2D" />
- <argument index="0" name="scale" type="Vector2" />
+ <param index="0" name="scale" type="Vector2" />
+ <description>
+ Returns a copy of the transform scaled by the given [param scale] factor.
+ This method is an optimized version of multiplying the given transform [code]X[/code]
+ with a corresponding scaling transform [code]S[/code] from the left, i.e., [code]S * X[/code].
+ This can be seen as transforming with respect to the global/parent frame.
+ </description>
+ </method>
+ <method name="scaled_local" qualifiers="const">
+ <return type="Transform2D" />
+ <param index="0" name="scale" type="Vector2" />
<description>
- Returns a copy of the transform scaled by the given [code]scale[/code] factor, using matrix multiplication.
+ Returns a copy of the transform scaled by the given [param scale] factor.
+ This method is an optimized version of multiplying the given transform [code]X[/code]
+ with a corresponding scaling transform [code]S[/code] from the right, i.e., [code]X * S[/code].
+ This can be seen as transforming with respect to the local frame.
</description>
</method>
<method name="set_rotation">
<return type="void" />
- <argument index="0" name="rotation" type="float" />
+ <param index="0" name="rotation" type="float" />
<description>
Sets the transform's rotation (in radians).
</description>
</method>
<method name="set_scale">
<return type="void" />
- <argument index="0" name="scale" type="Vector2" />
+ <param index="0" name="scale" type="Vector2" />
<description>
Sets the transform's scale.
[b]Note:[/b] Negative X scales in 2D are not decomposable from the transformation matrix. Due to the way scale is represented with transformation matrices in Godot, negative scales on the X axis will be changed to negative scales on the Y axis and a rotation of 180 degrees when decomposed.
@@ -168,17 +194,29 @@
</method>
<method name="set_skew">
<return type="void" />
- <argument index="0" name="skew" type="float" />
+ <param index="0" name="skew" type="float" />
<description>
Sets the transform's skew (in radians).
</description>
</method>
+ <method name="translated" qualifiers="const">
+ <return type="Transform2D" />
+ <param index="0" name="offset" type="Vector2" />
+ <description>
+ Returns a copy of the transform translated by the given [param offset].
+ This method is an optimized version of multiplying the given transform [code]X[/code]
+ with a corresponding translation transform [code]T[/code] from the left, i.e., [code]T * X[/code].
+ This can be seen as transforming with respect to the global/parent frame.
+ </description>
+ </method>
<method name="translated_local" qualifiers="const">
<return type="Transform2D" />
- <argument index="0" name="offset" type="Vector2" />
+ <param index="0" name="offset" type="Vector2" />
<description>
- Returns a copy of the transform translated by the given [code]offset[/code], relative to the transform's basis vectors.
- Unlike [method rotated] and [method scaled], this does not use matrix multiplication.
+ Returns a copy of the transform translated by the given [param offset].
+ This method is an optimized version of multiplying the given transform [code]X[/code]
+ with a corresponding translation transform [code]T[/code] from the right, i.e., [code]X * T[/code].
+ This can be seen as transforming with respect to the local frame.
</description>
</method>
</methods>
@@ -207,7 +245,7 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="Transform2D" />
+ <param index="0" name="right" type="Transform2D" />
<description>
Returns [code]true[/code] if the transforms are not equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
@@ -215,49 +253,49 @@
</operator>
<operator name="operator *">
<return type="PackedVector2Array" />
- <argument index="0" name="right" type="PackedVector2Array" />
+ <param index="0" name="right" type="PackedVector2Array" />
<description>
Transforms (multiplies) each element of the [Vector2] array by the given [Transform2D] matrix.
</description>
</operator>
<operator name="operator *">
<return type="Rect2" />
- <argument index="0" name="right" type="Rect2" />
+ <param index="0" name="right" type="Rect2" />
<description>
Transforms (multiplies) the [Rect2] by the given [Transform2D] matrix.
</description>
</operator>
<operator name="operator *">
<return type="Transform2D" />
- <argument index="0" name="right" type="Transform2D" />
+ <param index="0" name="right" type="Transform2D" />
<description>
Composes these two transformation matrices by multiplying them together. This has the effect of transforming the second transform (the child) by the first transform (the parent).
</description>
</operator>
<operator name="operator *">
<return type="Vector2" />
- <argument index="0" name="right" type="Vector2" />
+ <param index="0" name="right" type="Vector2" />
<description>
Transforms (multiplies) the [Vector2] by the given [Transform2D] matrix.
</description>
</operator>
<operator name="operator *">
<return type="Transform2D" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
This operator multiplies all components of the [Transform2D], including the origin vector, which scales it uniformly.
</description>
</operator>
<operator name="operator *">
<return type="Transform2D" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
This operator multiplies all components of the [Transform2D], including the origin vector, which scales it uniformly.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="Transform2D" />
+ <param index="0" name="right" type="Transform2D" />
<description>
Returns [code]true[/code] if the transforms are exactly equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
@@ -265,7 +303,7 @@
</operator>
<operator name="operator []">
<return type="Vector2" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Access transform components using their index. [code]t[0][/code] is equivalent to [code]t.x[/code], [code]t[1][/code] is equivalent to [code]t.y[/code], and [code]t[2][/code] is equivalent to [code]t.origin[/code].
</description>
diff --git a/doc/classes/Transform3D.xml b/doc/classes/Transform3D.xml
index de1db718c2..14aa72b80c 100644
--- a/doc/classes/Transform3D.xml
+++ b/doc/classes/Transform3D.xml
@@ -24,31 +24,31 @@
</constructor>
<constructor name="Transform3D">
<return type="Transform3D" />
- <argument index="0" name="from" type="Transform3D" />
+ <param index="0" name="from" type="Transform3D" />
<description>
Constructs a [Transform3D] as a copy of the given [Transform3D].
</description>
</constructor>
<constructor name="Transform3D">
<return type="Transform3D" />
- <argument index="0" name="basis" type="Basis" />
- <argument index="1" name="origin" type="Vector3" />
+ <param index="0" name="basis" type="Basis" />
+ <param index="1" name="origin" type="Vector3" />
<description>
Constructs a Transform3D from a [Basis] and [Vector3].
</description>
</constructor>
<constructor name="Transform3D">
<return type="Transform3D" />
- <argument index="0" name="from" type="Projection" />
+ <param index="0" name="from" type="Projection" />
<description>
</description>
</constructor>
<constructor name="Transform3D">
<return type="Transform3D" />
- <argument index="0" name="x_axis" type="Vector3" />
- <argument index="1" name="y_axis" type="Vector3" />
- <argument index="2" name="z_axis" type="Vector3" />
- <argument index="3" name="origin" type="Vector3" />
+ <param index="0" name="x_axis" type="Vector3" />
+ <param index="1" name="y_axis" type="Vector3" />
+ <param index="2" name="z_axis" type="Vector3" />
+ <param index="3" name="origin" type="Vector3" />
<description>
Constructs a Transform3D from four [Vector3] values (matrix columns). Each axis corresponds to local basis vectors (some of which may be scaled).
</description>
@@ -63,10 +63,10 @@
</method>
<method name="interpolate_with" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="xform" type="Transform3D" />
- <argument index="1" name="weight" type="float" />
+ <param index="0" name="xform" type="Transform3D" />
+ <param index="1" name="weight" type="float" />
<description>
- Returns a transform interpolated between this transform and another by a given [code]weight[/code] (on the range of 0.0 to 1.0).
+ Returns a transform interpolated between this transform and another by a given [param weight] (on the range of 0.0 to 1.0).
</description>
</method>
<method name="inverse" qualifiers="const">
@@ -77,18 +77,18 @@
</method>
<method name="is_equal_approx" qualifiers="const">
<return type="bool" />
- <argument index="0" name="xform" type="Transform3D" />
+ <param index="0" name="xform" type="Transform3D" />
<description>
Returns [code]true[/code] if this transform and [code]transform[/code] are approximately equal, by calling [code]is_equal_approx[/code] on each component.
</description>
</method>
<method name="looking_at" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="target" type="Vector3" />
- <argument index="1" name="up" type="Vector3" default="Vector3(0, 1, 0)" />
+ <param index="0" name="target" type="Vector3" />
+ <param index="1" name="up" type="Vector3" default="Vector3(0, 1, 0)" />
<description>
- Returns a copy of the transform rotated such that the forward axis (-Z) points towards the [code]target[/code] position.
- The up axis (+Y) points as close to the [code]up[/code] vector as possible while staying perpendicular to the forward axis. The resulting transform is orthonormalized. The existing rotation, scale, and skew information from the original transform is discarded. The [code]target[/code] and [code]up[/code] vectors cannot be zero, cannot be parallel to each other, and are defined in global/parent space.
+ Returns a copy of the transform rotated such that the forward axis (-Z) points towards the [param target] position.
+ The up axis (+Y) points as close to the [param up] vector as possible while staying perpendicular to the forward axis. The resulting transform is orthonormalized. The existing rotation, scale, and skew information from the original transform is discarded. The [param target] and [param up] vectors cannot be zero, cannot be parallel to each other, and are defined in global/parent space.
</description>
</method>
<method name="orthonormalized" qualifiers="const">
@@ -99,33 +99,74 @@
</method>
<method name="rotated" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="axis" type="Vector3" />
- <argument index="1" name="angle" type="float" />
+ <param index="0" name="axis" type="Vector3" />
+ <param index="1" name="angle" type="float" />
<description>
- Returns a copy of the transform rotated around the given [code]axis[/code] by the given [code]angle[/code] (in radians), using matrix multiplication. The [code]axis[/code] must be a normalized vector.
+ Returns a copy of the transform rotated around the given [param axis] by the given [param angle] (in radians).
+ The [param axis] must be a normalized vector.
+ This method is an optimized version of multiplying the given transform [code]X[/code]
+ with a corresponding rotation transform [code]R[/code] from the left, i.e., [code]R * X[/code].
+ This can be seen as transforming with respect to the global/parent frame.
+ </description>
+ </method>
+ <method name="rotated_local" qualifiers="const">
+ <return type="Transform3D" />
+ <param index="0" name="axis" type="Vector3" />
+ <param index="1" name="angle" type="float" />
+ <description>
+ Returns a copy of the transform rotated around the given [param axis] by the given [param angle] (in radians).
+ The [param axis] must be a normalized vector.
+ This method is an optimized version of multiplying the given transform [code]X[/code]
+ with a corresponding rotation transform [code]R[/code] from the right, i.e., [code]X * R[/code].
+ This can be seen as transforming with respect to the local frame.
</description>
</method>
<method name="scaled" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="scale" type="Vector3" />
+ <param index="0" name="scale" type="Vector3" />
+ <description>
+ Returns a copy of the transform scaled by the given [param scale] factor.
+ This method is an optimized version of multiplying the given transform [code]X[/code]
+ with a corresponding scaling transform [code]S[/code] from the left, i.e., [code]S * X[/code].
+ This can be seen as transforming with respect to the global/parent frame.
+ </description>
+ </method>
+ <method name="scaled_local" qualifiers="const">
+ <return type="Transform3D" />
+ <param index="0" name="scale" type="Vector3" />
<description>
- Returns a copy of the transform with its basis and origin scaled by the given [code]scale[/code] factor, using matrix multiplication.
+ Returns a copy of the transform scaled by the given [param scale] factor.
+ This method is an optimized version of multiplying the given transform [code]X[/code]
+ with a corresponding scaling transform [code]S[/code] from the right, i.e., [code]X * S[/code].
+ This can be seen as transforming with respect to the local frame.
</description>
</method>
<method name="spherical_interpolate_with" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="xform" type="Transform3D" />
- <argument index="1" name="weight" type="float" />
+ <param index="0" name="xform" type="Transform3D" />
+ <param index="1" name="weight" type="float" />
<description>
- Returns a transform spherically interpolated between this transform and another by a given [code]weight[/code] (on the range of 0.0 to 1.0).
+ Returns a transform spherically interpolated between this transform and another by a given [param weight] (on the range of 0.0 to 1.0).
+ </description>
+ </method>
+ <method name="translated" qualifiers="const">
+ <return type="Transform3D" />
+ <param index="0" name="offset" type="Vector3" />
+ <description>
+ Returns a copy of the transform translated by the given [param offset].
+ This method is an optimized version of multiplying the given transform [code]X[/code]
+ with a corresponding translation transform [code]T[/code] from the left, i.e., [code]T * X[/code].
+ This can be seen as transforming with respect to the global/parent frame.
</description>
</method>
<method name="translated_local" qualifiers="const">
<return type="Transform3D" />
- <argument index="0" name="offset" type="Vector3" />
+ <param index="0" name="offset" type="Vector3" />
<description>
- Returns a copy of the transform translated by the given [code]offset[/code], relative to the transform's basis vectors.
- Unlike [method rotated] and [method scaled], this does not use matrix multiplication.
+ Returns a copy of the transform translated by the given [param offset].
+ This method is an optimized version of multiplying the given transform [code]X[/code]
+ with a corresponding translation transform [code]T[/code] from the right, i.e., [code]X * T[/code].
+ This can be seen as transforming with respect to the local frame.
</description>
</method>
</methods>
@@ -154,7 +195,7 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="Transform3D" />
+ <param index="0" name="right" type="Transform3D" />
<description>
Returns [code]true[/code] if the transforms are not equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
@@ -162,49 +203,56 @@
</operator>
<operator name="operator *">
<return type="AABB" />
- <argument index="0" name="right" type="AABB" />
+ <param index="0" name="right" type="AABB" />
<description>
Transforms (multiplies) the [AABB] by the given [Transform3D] matrix.
</description>
</operator>
<operator name="operator *">
<return type="PackedVector3Array" />
- <argument index="0" name="right" type="PackedVector3Array" />
+ <param index="0" name="right" type="PackedVector3Array" />
<description>
Transforms (multiplies) each element of the [Vector3] array by the given [Transform3D] matrix.
</description>
</operator>
<operator name="operator *">
+ <return type="Plane" />
+ <param index="0" name="right" type="Plane" />
+ <description>
+ Transforms (multiplies) the [Plane] by the given [Transform3D] transformation matrix.
+ </description>
+ </operator>
+ <operator name="operator *">
<return type="Transform3D" />
- <argument index="0" name="right" type="Transform3D" />
+ <param index="0" name="right" type="Transform3D" />
<description>
Composes these two transformation matrices by multiplying them together. This has the effect of transforming the second transform (the child) by the first transform (the parent).
</description>
</operator>
<operator name="operator *">
<return type="Vector3" />
- <argument index="0" name="right" type="Vector3" />
+ <param index="0" name="right" type="Vector3" />
<description>
Transforms (multiplies) the [Vector3] by the given [Transform3D] matrix.
</description>
</operator>
<operator name="operator *">
<return type="Transform3D" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
This operator multiplies all components of the [Transform3D], including the origin vector, which scales it uniformly.
</description>
</operator>
<operator name="operator *">
<return type="Transform3D" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
This operator multiplies all components of the [Transform3D], including the origin vector, which scales it uniformly.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="Transform3D" />
+ <param index="0" name="right" type="Transform3D" />
<description>
Returns [code]true[/code] if the transforms are exactly equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
diff --git a/doc/classes/Translation.xml b/doc/classes/Translation.xml
index 7aafbc68c6..314be9adf8 100644
--- a/doc/classes/Translation.xml
+++ b/doc/classes/Translation.xml
@@ -13,27 +13,27 @@
<methods>
<method name="_get_message" qualifiers="virtual const">
<return type="StringName" />
- <argument index="0" name="src_message" type="StringName" />
- <argument index="1" name="context" type="StringName" />
+ <param index="0" name="src_message" type="StringName" />
+ <param index="1" name="context" type="StringName" />
<description>
Virtual method to override [method get_message].
</description>
</method>
<method name="_get_plural_message" qualifiers="virtual const">
<return type="StringName" />
- <argument index="0" name="src_message" type="StringName" />
- <argument index="1" name="src_plural_message" type="StringName" />
- <argument index="2" name="n" type="int" />
- <argument index="3" name="context" type="StringName" />
+ <param index="0" name="src_message" type="StringName" />
+ <param index="1" name="src_plural_message" type="StringName" />
+ <param index="2" name="n" type="int" />
+ <param index="3" name="context" type="StringName" />
<description>
Virtual method to override [method get_plural_message].
</description>
</method>
<method name="add_message">
<return type="void" />
- <argument index="0" name="src_message" type="StringName" />
- <argument index="1" name="xlated_message" type="StringName" />
- <argument index="2" name="context" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="src_message" type="StringName" />
+ <param index="1" name="xlated_message" type="StringName" />
+ <param index="2" name="context" type="StringName" default="&quot;&quot;" />
<description>
Adds a message if nonexistent, followed by its translation.
An additional context could be used to specify the translation context or differentiate polysemic words.
@@ -41,9 +41,9 @@
</method>
<method name="add_plural_message">
<return type="void" />
- <argument index="0" name="src_message" type="StringName" />
- <argument index="1" name="xlated_messages" type="PackedStringArray" />
- <argument index="2" name="context" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="src_message" type="StringName" />
+ <param index="1" name="xlated_messages" type="PackedStringArray" />
+ <param index="2" name="context" type="StringName" default="&quot;&quot;" />
<description>
Adds a message involving plural translation if nonexistent, followed by its translation.
An additional context could be used to specify the translation context or differentiate polysemic words.
@@ -51,16 +51,16 @@
</method>
<method name="erase_message">
<return type="void" />
- <argument index="0" name="src_message" type="StringName" />
- <argument index="1" name="context" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="src_message" type="StringName" />
+ <param index="1" name="context" type="StringName" default="&quot;&quot;" />
<description>
Erases a message.
</description>
</method>
<method name="get_message" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="src_message" type="StringName" />
- <argument index="1" name="context" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="src_message" type="StringName" />
+ <param index="1" name="context" type="StringName" default="&quot;&quot;" />
<description>
Returns a message's translation.
</description>
@@ -79,13 +79,13 @@
</method>
<method name="get_plural_message" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="src_message" type="StringName" />
- <argument index="1" name="src_plural_message" type="StringName" />
- <argument index="2" name="n" type="int" />
- <argument index="3" name="context" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="src_message" type="StringName" />
+ <param index="1" name="src_plural_message" type="StringName" />
+ <param index="2" name="n" type="int" />
+ <param index="3" name="context" type="StringName" default="&quot;&quot;" />
<description>
Returns a message's translation involving plurals.
- 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.
+ The number [param n] 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.
</description>
</method>
</methods>
diff --git a/doc/classes/TranslationServer.xml b/doc/classes/TranslationServer.xml
index a4cf070ede..7b18d8ddb6 100644
--- a/doc/classes/TranslationServer.xml
+++ b/doc/classes/TranslationServer.xml
@@ -13,7 +13,7 @@
<methods>
<method name="add_translation">
<return type="void" />
- <argument index="0" name="translation" type="Translation" />
+ <param index="0" name="translation" type="Translation" />
<description>
Adds a [Translation] resource.
</description>
@@ -26,8 +26,8 @@
</method>
<method name="compare_locales" qualifiers="const">
<return type="int" />
- <argument index="0" name="locale_a" type="String" />
- <argument index="1" name="locale_b" type="String" />
+ <param index="0" name="locale_a" type="String" />
+ <param index="1" name="locale_b" type="String" />
<description>
Compares two locales and return similarity score between [code]0[/code](no match) and [code]10[/code](full match).
</description>
@@ -52,20 +52,20 @@
</method>
<method name="get_country_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="country" type="String" />
+ <param index="0" name="country" type="String" />
<description>
- Returns readable country name for the [code]country[/code] code.
+ Returns readable country name for the [param country] code.
</description>
</method>
<method name="get_language_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="language" type="String" />
+ <param index="0" name="language" type="String" />
<description>
- Returns readable language name for the [code]language[/code] code.
+ Returns readable language name for the [param language] code.
</description>
</method>
<method name="get_loaded_locales" qualifiers="const">
- <return type="Array" />
+ <return type="PackedStringArray" />
<description>
Returns an array of all loaded locales of the project.
</description>
@@ -79,16 +79,16 @@
</method>
<method name="get_locale_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="locale" type="String" />
+ <param index="0" name="locale" type="String" />
<description>
Returns a locale's language and its variant (e.g. [code]"en_US"[/code] would return [code]"English (United States)"[/code]).
</description>
</method>
<method name="get_script_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="script" type="String" />
+ <param index="0" name="script" type="String" />
<description>
- Returns readable script name for the [code]script[/code] code.
+ Returns readable script name for the [param script] code.
</description>
</method>
<method name="get_tool_locale">
@@ -100,17 +100,17 @@
</method>
<method name="get_translation_object">
<return type="Translation" />
- <argument index="0" name="locale" type="String" />
+ <param index="0" name="locale" type="String" />
<description>
- Returns the [Translation] instance based on the [code]locale[/code] passed in.
- It will return [code]null[/code] if there is no [Translation] instance that matches the [code]locale[/code].
+ Returns the [Translation] instance based on the [param locale] passed in.
+ It will return [code]null[/code] if there is no [Translation] instance that matches the [param locale].
</description>
</method>
<method name="pseudolocalize" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="message" type="StringName" />
+ <param index="0" name="message" type="StringName" />
<description>
- Returns the pseudolocalized string based on the [code]p_message[/code] passed in.
+ Returns the pseudolocalized string based on the [param message] passed in.
</description>
</method>
<method name="reload_pseudolocalization">
@@ -121,43 +121,43 @@
</method>
<method name="remove_translation">
<return type="void" />
- <argument index="0" name="translation" type="Translation" />
+ <param index="0" name="translation" type="Translation" />
<description>
Removes the given translation from the server.
</description>
</method>
<method name="set_locale">
<return type="void" />
- <argument index="0" name="locale" type="String" />
+ <param index="0" name="locale" type="String" />
<description>
- Sets the locale of the project. The [code]locale[/code] string will be standardized to match known locales (e.g. [code]en-US[/code] would be matched to [code]en_US[/code]).
+ Sets the locale of the project. The [param locale] string will be standardized to match known locales (e.g. [code]en-US[/code] would be matched to [code]en_US[/code]).
If translations have been loaded beforehand for the new locale, they will be applied.
</description>
</method>
<method name="standardize_locale" qualifiers="const">
<return type="String" />
- <argument index="0" name="locale" type="String" />
+ <param index="0" name="locale" type="String" />
<description>
- Returns [code]locale[/code] string standardized to match known locales (e.g. [code]en-US[/code] would be matched to [code]en_US[/code]).
+ Returns [param locale] string standardized to match known locales (e.g. [code]en-US[/code] would be matched to [code]en_US[/code]).
</description>
</method>
<method name="translate" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="message" type="StringName" />
- <argument index="1" name="context" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="message" type="StringName" />
+ <param index="1" name="context" type="StringName" default="&quot;&quot;" />
<description>
Returns the current locale's translation for the given message (key) and context.
</description>
</method>
<method name="translate_plural" qualifiers="const">
<return type="StringName" />
- <argument index="0" name="message" type="StringName" />
- <argument index="1" name="plural_message" type="StringName" />
- <argument index="2" name="n" type="int" />
- <argument index="3" name="context" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="message" type="StringName" />
+ <param index="1" name="plural_message" type="StringName" />
+ <param index="2" name="n" type="int" />
+ <param index="3" name="context" type="StringName" default="&quot;&quot;" />
<description>
Returns the current locale's translation for the given message (key), plural_message and context.
- 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.
+ The number [param n] 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.
</description>
</method>
</methods>
diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml
index b06be0cf99..bf66d9f12a 100644
--- a/doc/classes/Tree.xml
+++ b/doc/classes/Tree.xml
@@ -44,12 +44,12 @@
</method>
<method name="create_item">
<return type="TreeItem" />
- <argument index="0" name="parent" type="TreeItem" default="null" />
- <argument index="1" name="idx" type="int" default="-1" />
+ <param index="0" name="parent" type="TreeItem" default="null" />
+ <param index="1" name="idx" type="int" default="-1" />
<description>
- Creates an item in the tree and adds it as a child of [code]parent[/code], which can be either a valid [TreeItem] or [code]null[/code].
- If [code]parent[/code] is [code]null[/code], the root item will be the parent, or the new item will be the root itself if the tree is empty.
- The new item will be the [code]idx[/code]th child of parent, or it will be the last child if there are not enough siblings.
+ Creates an item in the tree and adds it as a child of [param parent], which can be either a valid [TreeItem] or [code]null[/code].
+ If [param parent] is [code]null[/code], the root item will be the parent, or the new item will be the root itself if the tree is empty.
+ The new item will be the [param idx]th child of parent, or it will be the last child if there are not enough siblings.
</description>
</method>
<method name="edit_selected">
@@ -68,48 +68,48 @@
</method>
<method name="get_button_id_at_position" qualifiers="const">
<return type="int" />
- <argument index="0" name="position" type="Vector2" />
+ <param index="0" name="position" type="Vector2" />
<description>
- Returns the button id at [code]position[/code], or -1 if no button is there.
+ Returns the button id at [param position], or -1 if no button is there.
</description>
</method>
<method name="get_column_at_position" qualifiers="const">
<return type="int" />
- <argument index="0" name="position" type="Vector2" />
+ <param index="0" name="position" type="Vector2" />
<description>
- Returns the column index at [code]position[/code], or -1 if no item is there.
+ Returns the column index at [param position], or -1 if no item is there.
</description>
</method>
<method name="get_column_expand_ratio" qualifiers="const">
<return type="int" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
</description>
</method>
<method name="get_column_title" qualifiers="const">
<return type="String" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Returns the column's title.
</description>
</method>
<method name="get_column_title_direction" qualifiers="const">
<return type="int" enum="Control.TextDirection" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Returns column title base writing direction.
</description>
</method>
<method name="get_column_title_language" qualifiers="const">
<return type="String" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Returns column title language code.
</description>
</method>
<method name="get_column_width" qualifiers="const">
<return type="int" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Returns the column's width in pixels.
</description>
@@ -122,9 +122,9 @@
</method>
<method name="get_drop_section_at_position" qualifiers="const">
<return type="int" />
- <argument index="0" name="position" type="Vector2" />
+ <param index="0" name="position" type="Vector2" />
<description>
- Returns the drop section at [code]position[/code], or -100 if no item is there.
+ Returns the drop section at [param position], or -100 if no item is there.
Values -1, 0, or 1 will be returned for the "above item", "on item", and "below item" drop sections, respectively. See [enum DropModeFlags] for a description of each drop section.
To get the item which the returned drop section is relative to, use [method get_item_at_position].
</description>
@@ -163,26 +163,26 @@
</method>
<method name="get_item_area_rect" qualifiers="const">
<return type="Rect2" />
- <argument index="0" name="item" type="TreeItem" />
- <argument index="1" name="column" type="int" default="-1" />
- <argument index="2" name="button_index" type="int" default="-1" />
+ <param index="0" name="item" type="TreeItem" />
+ <param index="1" name="column" type="int" default="-1" />
+ <param index="2" name="button_index" type="int" default="-1" />
<description>
- Returns the rectangle area for the specified [TreeItem]. If [code]column[/code] is specified, only get the position and size of that column, otherwise get the rectangle containing all columns. If a button index is specified, the rectangle of that button will be returned.
+ Returns the rectangle area for the specified [TreeItem]. If [param column] is specified, only get the position and size of that column, otherwise get the rectangle containing all columns. If a button index is specified, the rectangle of that button will be returned.
</description>
</method>
<method name="get_item_at_position" qualifiers="const">
<return type="TreeItem" />
- <argument index="0" name="position" type="Vector2" />
+ <param index="0" name="position" type="Vector2" />
<description>
Returns the tree item at the specified position (relative to the tree origin position).
</description>
</method>
<method name="get_next_selected">
<return type="TreeItem" />
- <argument index="0" name="from" type="TreeItem" />
+ <param index="0" name="from" type="TreeItem" />
<description>
Returns the next selected [TreeItem] after the given one, or [code]null[/code] if the end is reached.
- If [code]from[/code] is [code]null[/code], this returns the first selected item.
+ If [param from] is [code]null[/code], this returns the first selected item.
</description>
</method>
<method name="get_pressed_button" qualifiers="const">
@@ -221,74 +221,74 @@
</method>
<method name="is_column_clipping_content" qualifiers="const">
<return type="bool" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
</description>
</method>
<method name="is_column_expanding" qualifiers="const">
<return type="bool" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
</description>
</method>
<method name="scroll_to_item">
<return type="void" />
- <argument index="0" name="item" type="TreeItem" />
- <argument index="1" name="center_on_item" type="bool" default="false" />
+ <param index="0" name="item" type="TreeItem" />
+ <param index="1" name="center_on_item" type="bool" default="false" />
<description>
Causes the [Tree] to jump to the specified [TreeItem].
</description>
</method>
<method name="set_column_clip_content">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="enable" type="bool" />
<description>
</description>
</method>
<method name="set_column_custom_minimum_width">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="min_width" type="int" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="min_width" type="int" />
<description>
Overrides the calculated minimum width of a column. It can be set to `0` to restore the default behavior. Columns that have the "Expand" flag will use their "min_width" in a similar fashion to [member Control.size_flags_stretch_ratio].
</description>
</method>
<method name="set_column_expand">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="expand" type="bool" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="expand" type="bool" />
<description>
If [code]true[/code], the column will have the "Expand" flag of [Control]. Columns that have the "Expand" flag will use their "min_width" in a similar fashion to [member Control.size_flags_stretch_ratio].
</description>
</method>
<method name="set_column_expand_ratio">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="ratio" type="int" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="ratio" type="int" />
<description>
</description>
</method>
<method name="set_column_title">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="title" type="String" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="title" type="String" />
<description>
Sets the title of a column.
</description>
</method>
<method name="set_column_title_direction">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="direction" type="int" enum="Control.TextDirection" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="direction" type="int" enum="Control.TextDirection" />
<description>
Sets column title base writing direction.
</description>
</method>
<method name="set_column_title_language">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="language" type="String" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="language" type="String" />
<description>
Sets language code of column title used for line-breaking and text shaping algorithms, if left empty current locale is used instead.
</description>
@@ -331,10 +331,10 @@
</members>
<signals>
<signal name="button_clicked">
- <argument index="0" name="item" type="TreeItem" />
- <argument index="1" name="column" type="int" />
- <argument index="2" name="id" type="int" />
- <argument index="3" name="mouse_button_index" type="int" />
+ <param index="0" name="item" type="TreeItem" />
+ <param index="1" name="column" type="int" />
+ <param index="2" name="id" type="int" />
+ <param index="3" name="mouse_button_index" type="int" />
<description>
Emitted when a button on the tree was pressed (see [method TreeItem.add_button]).
</description>
@@ -345,33 +345,34 @@
</description>
</signal>
<signal name="check_propagated_to_item">
- <argument index="0" name="item" type="TreeItem" />
- <argument index="1" name="column" type="int" />
+ <param index="0" name="item" type="TreeItem" />
+ <param index="1" name="column" type="int" />
<description>
Emitted when [method TreeItem.propagate_check] is called. Connect to this signal to process the items that are affected when [method TreeItem.propagate_check] is invoked. The order that the items affected will be processed is as follows: the item that invoked the method, children of that item, and finally parents of that item.
</description>
</signal>
- <signal name="column_title_pressed">
- <argument index="0" name="column" type="int" />
+ <signal name="column_title_clicked">
+ <param index="0" name="column" type="int" />
+ <param index="1" name="mouse_button_index" type="int" />
<description>
- Emitted when a column's title is pressed.
+ Emitted when a column's title is clicked with either [constant MOUSE_BUTTON_LEFT] or [constant MOUSE_BUTTON_RIGHT].
</description>
</signal>
<signal name="custom_item_clicked">
- <argument index="0" name="mouse_button_index" type="int" />
+ <param index="0" name="mouse_button_index" type="int" />
<description>
Emitted when an item with [constant TreeItem.CELL_MODE_CUSTOM] is clicked with a mouse button.
</description>
</signal>
<signal name="custom_popup_edited">
- <argument index="0" name="arrow_clicked" type="bool" />
+ <param index="0" name="arrow_clicked" type="bool" />
<description>
Emitted when a cell with the [constant TreeItem.CELL_MODE_CUSTOM] is clicked to be edited.
</description>
</signal>
<signal name="empty_clicked">
- <argument index="0" name="position" type="Vector2" />
- <argument index="1" name="mouse_button_index" type="int" />
+ <param index="0" name="position" type="Vector2" />
+ <param index="1" name="mouse_button_index" type="int" />
<description>
Emitted when a mouse button is clicked in the empty space of the tree.
</description>
@@ -382,7 +383,7 @@
</description>
</signal>
<signal name="item_collapsed">
- <argument index="0" name="item" type="TreeItem" />
+ <param index="0" name="item" type="TreeItem" />
<description>
Emitted when an item is collapsed by a click on the folding arrow.
</description>
@@ -403,8 +404,8 @@
</description>
</signal>
<signal name="item_mouse_selected">
- <argument index="0" name="position" type="Vector2" />
- <argument index="1" name="mouse_button_index" type="int" />
+ <param index="0" name="position" type="Vector2" />
+ <param index="1" name="mouse_button_index" type="int" />
<description>
Emitted when an item is selected with a mouse button.
</description>
@@ -415,9 +416,9 @@
</description>
</signal>
<signal name="multi_selected">
- <argument index="0" name="item" type="TreeItem" />
- <argument index="1" name="column" type="int" />
- <argument index="2" name="selected" type="bool" />
+ <param index="0" name="item" type="TreeItem" />
+ <param index="1" name="column" type="int" />
+ <param index="2" name="selected" type="bool" />
<description>
Emitted instead of [code]item_selected[/code] if [code]select_mode[/code] is [constant SELECT_MULTI].
</description>
@@ -461,7 +462,7 @@
<theme_item name="custom_button_font_highlight" data_type="color" type="Color" default="Color(0.95, 0.95, 0.95, 1)">
Text [Color] for a [constant TreeItem.CELL_MODE_CUSTOM] mode cell when it's hovered.
</theme_item>
- <theme_item name="drop_position_color" data_type="color" type="Color" default="Color(1, 0.3, 0.2, 1)">
+ <theme_item name="drop_position_color" data_type="color" type="Color" default="Color(1, 1, 1, 1)">
[Color] used to draw possible drop locations. See [enum DropModeFlags] constants for further description of drop locations.
</theme_item>
<theme_item name="font_color" data_type="color" type="Color" default="Color(0.7, 0.7, 0.7, 1)">
diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml
index fbba1147a2..6d4408cf61 100644
--- a/doc/classes/TreeItem.xml
+++ b/doc/classes/TreeItem.xml
@@ -12,108 +12,108 @@
<methods>
<method name="add_button">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="button" type="Texture2D" />
- <argument index="2" name="id" type="int" default="-1" />
- <argument index="3" name="disabled" type="bool" default="false" />
- <argument index="4" name="tooltip" type="String" default="&quot;&quot;" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="button" type="Texture2D" />
+ <param index="2" name="id" type="int" default="-1" />
+ <param index="3" name="disabled" type="bool" default="false" />
+ <param index="4" name="tooltip" type="String" default="&quot;&quot;" />
<description>
- Adds a button with [Texture2D] [code]button[/code] at column [code]column[/code]. The [code]id[/code] is used to identify the button. If not specified, the next available index is used, which may be retrieved by calling [method get_button_count] immediately before this method. Optionally, the button can be [code]disabled[/code] and have a [code]tooltip[/code].
+ Adds a button with [Texture2D] [param button] at column [param column]. The [param id] is used to identify the button. If not specified, the next available index is used, which may be retrieved by calling [method get_button_count] immediately before this method. Optionally, the button can be [param disabled] and have a [param tooltip].
</description>
</method>
<method name="call_recursive" qualifiers="vararg">
<return type="void" />
- <argument index="0" name="method" type="StringName" />
+ <param index="0" name="method" type="StringName" />
<description>
- Calls the [code]method[/code] on the actual TreeItem and its children recursively. Pass parameters as a comma separated list.
+ Calls the [param method] on the actual TreeItem and its children recursively. Pass parameters as a comma separated list.
</description>
</method>
<method name="clear_custom_bg_color">
<return type="void" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Resets the background color for the given column to default.
</description>
</method>
<method name="clear_custom_color">
<return type="void" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Resets the color for the given column to default.
</description>
</method>
<method name="create_child">
<return type="TreeItem" />
- <argument index="0" name="idx" type="int" default="-1" />
+ <param index="0" name="idx" type="int" default="-1" />
<description>
Creates an item and adds it as a child.
- The new item will be inserted as position [code]idx[/code] (the default value [code]-1[/code] means the last position), or it will be the last child if [code]idx[/code] is higher than the child count.
+ The new item will be inserted as position [param idx] (the default value [code]-1[/code] means the last position), or it will be the last child if [param idx] is higher than the child count.
</description>
</method>
<method name="deselect">
<return type="void" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Deselects the given column.
</description>
</method>
<method name="erase_button">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="button_idx" type="int" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="button_idx" type="int" />
<description>
- Removes the button at index [code]button_idx[/code] in column [code]column[/code].
+ Removes the button at index [param button_idx] in column [param column].
</description>
</method>
<method name="get_button" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="button_idx" type="int" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="button_idx" type="int" />
<description>
- Returns the [Texture2D] of the button at index [code]button_idx[/code] in column [code]column[/code].
+ Returns the [Texture2D] of the button at index [param button_idx] in column [param column].
</description>
</method>
<method name="get_button_by_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="id" type="int" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="id" type="int" />
<description>
- Returns the button index if there is a button with id [code]id[/code] in column [code]column[/code], otherwise returns -1.
+ Returns the button index if there is a button with id [param id] in column [param column], otherwise returns -1.
</description>
</method>
<method name="get_button_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
- Returns the number of buttons in column [code]column[/code].
+ Returns the number of buttons in column [param column].
</description>
</method>
<method name="get_button_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="button_idx" type="int" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="button_idx" type="int" />
<description>
- Returns the id for the button at index [code]button_idx[/code] in column [code]column[/code].
+ Returns the id for the button at index [param button_idx] in column [param column].
</description>
</method>
<method name="get_button_tooltip" qualifiers="const">
<return type="String" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="button_idx" type="int" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="button_idx" type="int" />
<description>
- Returns the tooltip string for the button at index [code]button_idx[/code] in column [code]column[/code].
+ Returns the tooltip string for the button at index [param button_idx] in column [param column].
</description>
</method>
<method name="get_cell_mode" qualifiers="const">
<return type="int" enum="TreeItem.TreeCellMode" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Returns the column's cell mode.
</description>
</method>
<method name="get_child">
<return type="TreeItem" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Returns a child item by its index (see [method get_child_count]). This method is often used for iterating all children of an item.
Negative indices access the children from the last one.
@@ -126,42 +126,42 @@
</description>
</method>
<method name="get_children">
- <return type="Array" />
+ <return type="TreeItem[]" />
<description>
Returns an array of references to the item's children.
</description>
</method>
<method name="get_custom_bg_color" qualifiers="const">
<return type="Color" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
- Returns the custom background color of column [code]column[/code].
+ Returns the custom background color of column [param column].
</description>
</method>
<method name="get_custom_color" qualifiers="const">
<return type="Color" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
- Returns the custom color of column [code]column[/code].
+ Returns the custom color of column [param column].
</description>
</method>
<method name="get_custom_font" qualifiers="const">
<return type="Font" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
- Returns custom font used to draw text in the column [code]column[/code].
+ Returns custom font used to draw text in the column [param column].
</description>
</method>
<method name="get_custom_font_size" qualifiers="const">
<return type="int" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
- Returns custom font size used to draw text in the column [code]column[/code].
+ Returns custom font size used to draw text in the column [param column].
</description>
</method>
<method name="get_expand_right" qualifiers="const">
<return type="bool" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Returns [code]true[/code] if [code]expand_right[/code] is set.
</description>
@@ -174,28 +174,28 @@
</method>
<method name="get_icon" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Returns the given column's icon [Texture2D]. Error if no icon is set.
</description>
</method>
<method name="get_icon_max_width" qualifiers="const">
<return type="int" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Returns the column's icon's maximum width.
</description>
</method>
<method name="get_icon_modulate" qualifiers="const">
<return type="Color" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Returns the [Color] modulating the column's icon.
</description>
</method>
<method name="get_icon_region" qualifiers="const">
<return type="Rect2" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Returns the icon [Texture2D] region as [Rect2].
</description>
@@ -208,14 +208,14 @@
</method>
<method name="get_language" qualifiers="const">
<return type="String" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Returns item's text language code.
</description>
</method>
<method name="get_metadata" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Returns the metadata value that was set for the given column using [method set_metadata].
</description>
@@ -228,10 +228,10 @@
</method>
<method name="get_next_visible">
<return type="TreeItem" />
- <argument index="0" name="wrap" type="bool" default="false" />
+ <param index="0" name="wrap" type="bool" default="false" />
<description>
Returns the next visible sibling TreeItem in the tree or a null object if there is none.
- If [code]wrap[/code] is enabled, the method will wrap around to the first visible element in the tree when called on the last visible element, otherwise it returns [code]null[/code].
+ If [param wrap] is enabled, the method will wrap around to the first visible element in the tree when called on the last visible element, otherwise it returns [code]null[/code].
</description>
</method>
<method name="get_parent" qualifiers="const">
@@ -248,69 +248,69 @@
</method>
<method name="get_prev_visible">
<return type="TreeItem" />
- <argument index="0" name="wrap" type="bool" default="false" />
+ <param index="0" name="wrap" type="bool" default="false" />
<description>
Returns the previous visible sibling TreeItem in the tree or a null object if there is none.
- If [code]wrap[/code] is enabled, the method will wrap around to the last visible element in the tree when called on the first visible element, otherwise it returns [code]null[/code].
+ If [param wrap] is enabled, the method will wrap around to the last visible element in the tree when called on the first visible element, otherwise it returns [code]null[/code].
</description>
</method>
<method name="get_range" qualifiers="const">
<return type="float" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Returns the value of a [constant CELL_MODE_RANGE] column.
</description>
</method>
<method name="get_range_config">
<return type="Dictionary" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Returns a dictionary containing the range parameters for a given column. The keys are "min", "max", "step", and "expr".
</description>
</method>
<method name="get_structured_text_bidi_override" qualifiers="const">
<return type="int" enum="TextServer.StructuredTextParser" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
</description>
</method>
<method name="get_structured_text_bidi_override_options" qualifiers="const">
<return type="Array" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
</description>
</method>
<method name="get_suffix" qualifiers="const">
<return type="String" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Gets the suffix string shown after the column value.
</description>
</method>
<method name="get_text" qualifiers="const">
<return type="String" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Returns the given column's text.
</description>
</method>
<method name="get_text_alignment" qualifiers="const">
<return type="int" enum="HorizontalAlignment" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Returns the given column's text alignment.
</description>
</method>
<method name="get_text_direction" qualifiers="const">
<return type="int" enum="Control.TextDirection" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Returns item's text base writing direction.
</description>
</method>
<method name="get_tooltip" qualifiers="const">
<return type="String" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
Returns the given column's tooltip.
</description>
@@ -323,326 +323,326 @@
</method>
<method name="is_button_disabled" qualifiers="const">
<return type="bool" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="button_idx" type="int" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="button_idx" type="int" />
<description>
- Returns [code]true[/code] if the button at index [code]button_idx[/code] for the given column is disabled.
+ Returns [code]true[/code] if the button at index [param button_idx] for the given [param column] is disabled.
</description>
</method>
<method name="is_checked" qualifiers="const">
<return type="bool" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
- Returns [code]true[/code] if the given column is checked.
+ Returns [code]true[/code] if the given [param column] is checked.
</description>
</method>
<method name="is_custom_set_as_button" qualifiers="const">
<return type="bool" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
</description>
</method>
<method name="is_editable">
<return type="bool" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
- Returns [code]true[/code] if column [code]column[/code] is editable.
+ Returns [code]true[/code] if the given [param column] is editable.
</description>
</method>
<method name="is_indeterminate" qualifiers="const">
<return type="bool" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
- Returns [code]true[/code] if the given column is indeterminate.
+ Returns [code]true[/code] if the given [param column] is indeterminate.
</description>
</method>
<method name="is_selectable" qualifiers="const">
<return type="bool" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
- Returns [code]true[/code] if column [code]column[/code] is selectable.
+ Returns [code]true[/code] if the given [param column] is selectable.
</description>
</method>
<method name="is_selected">
<return type="bool" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
- Returns [code]true[/code] if column [code]column[/code] is selected.
+ Returns [code]true[/code] if the given [param column] is selected.
</description>
</method>
<method name="move_after">
<return type="void" />
- <argument index="0" name="item" type="TreeItem" />
+ <param index="0" name="item" type="TreeItem" />
<description>
- Moves this TreeItem right after the given [code]item[/code].
+ Moves this TreeItem right after the given [param item].
[b]Note:[/b] You can't move to the root or move the root.
</description>
</method>
<method name="move_before">
<return type="void" />
- <argument index="0" name="item" type="TreeItem" />
+ <param index="0" name="item" type="TreeItem" />
<description>
- Moves this TreeItem right before the given [code]item[/code].
+ Moves this TreeItem right before the given [param item].
[b]Note:[/b] You can't move to the root or move the root.
</description>
</method>
<method name="propagate_check">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="emit_signal" type="bool" default="true" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="emit_signal" type="bool" default="true" />
<description>
- Propagates this item's checked status to its children and parents for the given [code]column[/code]. It is possible to process the items affected by this method call by connecting to [signal Tree.check_propagated_to_item]. The order that the items affected will be processed is as follows: the item invoking this method, children of that item, and finally parents of that item. If [code]emit_signal[/code] is [code]false[/code], then [signal Tree.check_propagated_to_item] will not be emitted.
+ Propagates this item's checked status to its children and parents for the given [param column]. It is possible to process the items affected by this method call by connecting to [signal Tree.check_propagated_to_item]. The order that the items affected will be processed is as follows: the item invoking this method, children of that item, and finally parents of that item. If [param emit_signal] is [code]false[/code], then [signal Tree.check_propagated_to_item] will not be emitted.
</description>
</method>
<method name="remove_child">
<return type="void" />
- <argument index="0" name="child" type="TreeItem" />
+ <param index="0" name="child" type="TreeItem" />
<description>
Removes the given child [TreeItem] and all its children from the [Tree]. Note that it doesn't free the item from memory, so it can be reused later. To completely remove a [TreeItem] use [method Object.free].
</description>
</method>
<method name="select">
<return type="void" />
- <argument index="0" name="column" type="int" />
+ <param index="0" name="column" type="int" />
<description>
- Selects the column [code]column[/code].
+ Selects the given [param column].
</description>
</method>
<method name="set_button">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="button_idx" type="int" />
- <argument index="2" name="button" type="Texture2D" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="button_idx" type="int" />
+ <param index="2" name="button" type="Texture2D" />
<description>
- Sets the given column's button [Texture2D] at index [code]button_idx[/code] to [code]button[/code].
+ Sets the given column's button [Texture2D] at index [param button_idx] to [param button].
</description>
</method>
<method name="set_button_disabled">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="button_idx" type="int" />
- <argument index="2" name="disabled" type="bool" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="button_idx" type="int" />
+ <param index="2" name="disabled" type="bool" />
<description>
- If [code]true[/code], disables the button at index [code]button_idx[/code] in column [code]column[/code].
+ If [code]true[/code], disables the button at index [param button_idx] in the given [param column].
</description>
</method>
<method name="set_cell_mode">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="mode" type="int" enum="TreeItem.TreeCellMode" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="mode" type="int" enum="TreeItem.TreeCellMode" />
<description>
- Sets the given column's cell mode to [code]mode[/code]. See [enum TreeCellMode] constants.
+ Sets the given column's cell mode to [param mode]. See [enum TreeCellMode] constants.
</description>
</method>
<method name="set_checked">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="checked" type="bool" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="checked" type="bool" />
<description>
- If [code]true[/code], the column [code]column[/code] is checked. Clears column's indeterminate status.
+ If [code]true[/code], the given [param column] is checked. Clears column's indeterminate status.
</description>
</method>
<method name="set_custom_as_button">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="enable" type="bool" />
<description>
</description>
</method>
<method name="set_custom_bg_color">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="color" type="Color" />
- <argument index="2" name="just_outline" type="bool" default="false" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="color" type="Color" />
+ <param index="2" name="just_outline" type="bool" default="false" />
<description>
Sets the given column's custom background color and whether to just use it as an outline.
</description>
</method>
<method name="set_custom_color">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="color" type="Color" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="color" type="Color" />
<description>
Sets the given column's custom color.
</description>
</method>
<method name="set_custom_draw">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="object" type="Object" />
- <argument index="2" name="callback" type="StringName" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="object" type="Object" />
+ <param index="2" name="callback" type="StringName" />
<description>
- Sets the given column's custom draw callback to [code]callback[/code] method on [code]object[/code].
- The [code]callback[/code] should accept two arguments: the [TreeItem] that is drawn and its position and size as a [Rect2].
+ Sets the given column's custom draw callback to [param callback] method on [param object].
+ The [param callback] should accept two arguments: the [TreeItem] that is drawn and its position and size as a [Rect2].
</description>
</method>
<method name="set_custom_font">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="font" type="Font" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="font" type="Font" />
<description>
- Sets custom font used to draw text in the column [code]column[/code].
+ Sets custom font used to draw text in the given [param column].
</description>
</method>
<method name="set_custom_font_size">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="font_size" type="int" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="font_size" type="int" />
<description>
- Sets custom font size used to draw text in the column [code]column[/code].
+ Sets custom font size used to draw text in the given [param column].
</description>
</method>
<method name="set_editable">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="enabled" type="bool" />
<description>
- If [code]true[/code], column [code]column[/code] is editable.
+ If [code]true[/code], the given [param column] is editable.
</description>
</method>
<method name="set_expand_right">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="enable" type="bool" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="enable" type="bool" />
<description>
- If [code]true[/code], column [code]column[/code] is expanded to the right.
+ If [code]true[/code], the given [param column] is expanded to the right.
</description>
</method>
<method name="set_icon">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="texture" type="Texture2D" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="texture" type="Texture2D" />
<description>
Sets the given column's icon [Texture2D].
</description>
</method>
<method name="set_icon_max_width">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="width" type="int" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="width" type="int" />
<description>
Sets the given column's icon's maximum width.
</description>
</method>
<method name="set_icon_modulate">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="modulate" type="Color" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="modulate" type="Color" />
<description>
- Modulates the given column's icon with [code]modulate[/code].
+ Modulates the given column's icon with [param modulate].
</description>
</method>
<method name="set_icon_region">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="region" type="Rect2" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="region" type="Rect2" />
<description>
Sets the given column's icon's texture region.
</description>
</method>
<method name="set_indeterminate">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="indeterminate" type="bool" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="indeterminate" type="bool" />
<description>
- If [code]true[/code], the column [code]column[/code] is marked indeterminate.
+ If [code]true[/code], the given [param column] is marked [param indeterminate].
[b]Note:[/b] If set [code]true[/code] from [code]false[/code], then column is cleared of checked status.
</description>
</method>
<method name="set_language">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="language" type="String" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="language" type="String" />
<description>
Sets language code of item's text used for line-breaking and text shaping algorithms, if left empty current locale is used instead.
</description>
</method>
<method name="set_metadata">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="meta" type="Variant" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="meta" type="Variant" />
<description>
Sets the metadata value for the given column, which can be retrieved later using [method get_metadata]. This can be used, for example, to store a reference to the original data.
</description>
</method>
<method name="set_range">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="value" type="float" />
<description>
Sets the value of a [constant CELL_MODE_RANGE] column.
</description>
</method>
<method name="set_range_config">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="min" type="float" />
- <argument index="2" name="max" type="float" />
- <argument index="3" name="step" type="float" />
- <argument index="4" name="expr" type="bool" default="false" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="min" type="float" />
+ <param index="2" name="max" type="float" />
+ <param index="3" name="step" type="float" />
+ <param index="4" name="expr" type="bool" default="false" />
<description>
Sets the range of accepted values for a column. The column must be in the [constant CELL_MODE_RANGE] mode.
- If [code]expr[/code] is [code]true[/code], the edit mode slider will use an exponential scale as with [member Range.exp_edit].
+ If [param expr] is [code]true[/code], the edit mode slider will use an exponential scale as with [member Range.exp_edit].
</description>
</method>
<method name="set_selectable">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="selectable" type="bool" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="selectable" type="bool" />
<description>
If [code]true[/code], the given column is selectable.
</description>
</method>
<method name="set_structured_text_bidi_override">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="parser" type="int" enum="TextServer.StructuredTextParser" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="parser" type="int" enum="TextServer.StructuredTextParser" />
<description>
</description>
</method>
<method name="set_structured_text_bidi_override_options">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="args" type="Array" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="args" type="Array" />
<description>
</description>
</method>
<method name="set_suffix">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="text" type="String" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="text" type="String" />
<description>
Sets a string to be shown after a column's value (for example, a unit abbreviation).
</description>
</method>
<method name="set_text">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="text" type="String" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="text" type="String" />
<description>
Sets the given column's text value.
</description>
</method>
<method name="set_text_alignment">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="text_alignment" type="int" enum="HorizontalAlignment" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="text_alignment" type="int" enum="HorizontalAlignment" />
<description>
Sets the given column's text alignment. See [enum HorizontalAlignment] for possible values.
</description>
</method>
<method name="set_text_direction">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="direction" type="int" enum="Control.TextDirection" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="direction" type="int" enum="Control.TextDirection" />
<description>
Sets item's text base writing direction.
</description>
</method>
<method name="set_tooltip">
<return type="void" />
- <argument index="0" name="column" type="int" />
- <argument index="1" name="tooltip" type="String" />
+ <param index="0" name="column" type="int" />
+ <param index="1" name="tooltip" type="String" />
<description>
Sets the given column's tooltip text.
</description>
diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml
index b18232f5c3..c7fc78c1d3 100644
--- a/doc/classes/Tween.xml
+++ b/doc/classes/Tween.xml
@@ -45,9 +45,9 @@
<methods>
<method name="bind_node">
<return type="Tween" />
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
- Binds this [Tween] with the given [code]node[/code]. [Tween]s are processed directly by the [SceneTree], so they run independently of the animated nodes. When you bind a [Node] with the [Tween], the [Tween] will halt the animation when the object is not inside tree and the [Tween] will be automatically killed when the bound object is freed. Also [constant TWEEN_PAUSE_BOUND] will make the pausing behavior dependent on the bound node.
+ Binds this [Tween] with the given [param node]. [Tween]s are processed directly by the [SceneTree], so they run independently of the animated nodes. When you bind a [Node] with the [Tween], the [Tween] will halt the animation when the object is not inside tree and the [Tween] will be automatically killed when the bound object is freed. Also [constant TWEEN_PAUSE_BOUND] will make the pausing behavior dependent on the bound node.
For a shorter way to create and bind a [Tween], you can use [method Node.create_tween].
</description>
</method>
@@ -65,9 +65,9 @@
</method>
<method name="custom_step">
<return type="bool" />
- <argument index="0" name="delta" type="float" />
+ <param index="0" name="delta" type="float" />
<description>
- Processes the [Tween] by the given [code]delta[/code] value, in seconds. This is mostly useful for manual control when the [Tween] is paused. It can also be used to end the [Tween] animation immediately, by setting [code]delta[/code] longer than the whole duration of the [Tween] animation.
+ Processes the [Tween] by the given [param delta] value, in seconds. This is mostly useful for manual control when the [Tween] is paused. It can also be used to end the [Tween] animation immediately, by setting [param delta] longer than the whole duration of the [Tween] animation.
Returns [code]true[/code] if the [Tween] still has [Tweener]s that haven't finished.
[b]Note:[/b] The [Tween] will become invalid in the next processing frame after its animation finishes. Calling [method stop] after performing [method custom_step] instead keeps and resets the [Tween].
</description>
@@ -81,19 +81,19 @@
</method>
<method name="interpolate_value" qualifiers="static">
<return type="Variant" />
- <argument index="0" name="initial_value" type="Variant" />
- <argument index="1" name="delta_value" type="Variant" />
- <argument index="2" name="elapsed_time" type="float" />
- <argument index="3" name="duration" type="float" />
- <argument index="4" name="trans_type" type="int" enum="Tween.TransitionType" />
- <argument index="5" name="ease_type" type="int" enum="Tween.EaseType" />
+ <param index="0" name="initial_value" type="Variant" />
+ <param index="1" name="delta_value" type="Variant" />
+ <param index="2" name="elapsed_time" type="float" />
+ <param index="3" name="duration" type="float" />
+ <param index="4" name="trans_type" type="int" enum="Tween.TransitionType" />
+ <param index="5" name="ease_type" type="int" enum="Tween.EaseType" />
<description>
This method can be used for manual interpolation of a value, when you don't want [Tween] to do animating for you. It's similar to [method @GlobalScope.lerp], but with support for custom transition and easing.
- [code]initial_value[/code] is the starting value of the interpolation.
- [code]delta_value[/code] is the change of the value in the interpolation, i.e. it's equal to [code]final_value - initial_value[/code].
- [code]elapsed_time[/code] is the time in seconds that passed after the interpolation started and it's used to control the position of the interpolation. E.g. when it's equal to half of the [code]duration[/code], the interpolated value will be halfway between initial and final values. This value can also be greater than [code]duration[/code] or lower than 0, which will extrapolate the value.
- [code]duration[/code] is the total time of the interpolation.
- [b]Note:[/b] If [code]duration[/code] is equal to [code]0[/code], the method will always return the final value, regardless of [code]elapsed_time[/code] provided.
+ [param initial_value] is the starting value of the interpolation.
+ [param delta_value] is the change of the value in the interpolation, i.e. it's equal to [code]final_value - initial_value[/code].
+ [param elapsed_time] is the time in seconds that passed after the interpolation started and it's used to control the position of the interpolation. E.g. when it's equal to half of the [param duration], the interpolated value will be halfway between initial and final values. This value can also be greater than [param duration] or lower than 0, which will extrapolate the value.
+ [param duration] is the total time of the interpolation.
+ [b]Note:[/b] If [param duration] is equal to [code]0[/code], the method will always return the final value, regardless of [param elapsed_time] provided.
</description>
</method>
<method name="is_running">
@@ -142,14 +142,14 @@
</method>
<method name="set_ease">
<return type="Tween" />
- <argument index="0" name="ease" type="int" enum="Tween.EaseType" />
+ <param index="0" name="ease" type="int" enum="Tween.EaseType" />
<description>
Sets the default ease type for [PropertyTweener]s and [MethodTweener]s animated by this [Tween].
</description>
</method>
<method name="set_loops">
<return type="Tween" />
- <argument index="0" name="loops" type="int" default="0" />
+ <param index="0" name="loops" type="int" default="0" />
<description>
Sets the number of times the tweening sequence will be repeated, i.e. [code]set_loops(2)[/code] will run the animation twice.
Calling this method without arguments will make the [Tween] run infinitely, until either it is killed with [method kill], the [Tween]'s bound node is freed, or all the animated objects have been freed (which makes further animation impossible).
@@ -158,14 +158,14 @@
</method>
<method name="set_parallel">
<return type="Tween" />
- <argument index="0" name="parallel" type="bool" default="true" />
+ <param index="0" name="parallel" type="bool" default="true" />
<description>
- If [code]parallel[/code] is [code]true[/code], the [Tweener]s appended after this method will by default run simultaneously, as opposed to sequentially.
+ If [param parallel] is [code]true[/code], the [Tweener]s appended after this method will by default run simultaneously, as opposed to sequentially.
</description>
</method>
<method name="set_pause_mode">
<return type="Tween" />
- <argument index="0" name="mode" type="int" enum="Tween.TweenPauseMode" />
+ <param index="0" name="mode" type="int" enum="Tween.TweenPauseMode" />
<description>
Determines the behavior of the [Tween] when the [SceneTree] is paused. Check [enum TweenPauseMode] for options.
Default value is [constant TWEEN_PAUSE_BOUND].
@@ -173,7 +173,7 @@
</method>
<method name="set_process_mode">
<return type="Tween" />
- <argument index="0" name="mode" type="int" enum="Tween.TweenProcessMode" />
+ <param index="0" name="mode" type="int" enum="Tween.TweenProcessMode" />
<description>
Determines whether the [Tween] should run during idle frame (see [method Node._process]) or physics frame (see [method Node._physics_process].
Default value is [constant TWEEN_PROCESS_IDLE].
@@ -181,14 +181,14 @@
</method>
<method name="set_speed_scale">
<return type="Tween" />
- <argument index="0" name="speed" type="float" />
+ <param index="0" name="speed" type="float" />
<description>
Scales the speed of tweening. This affects all [Tweener]s and their delays.
</description>
</method>
<method name="set_trans">
<return type="Tween" />
- <argument index="0" name="trans" type="int" enum="Tween.TransitionType" />
+ <param index="0" name="trans" type="int" enum="Tween.TransitionType" />
<description>
Sets the default transition type for [PropertyTweener]s and [MethodTweener]s animated by this [Tween].
</description>
@@ -201,7 +201,7 @@
</method>
<method name="tween_callback">
<return type="CallbackTweener" />
- <argument index="0" name="callback" type="Callable" />
+ <param index="0" name="callback" type="Callable" />
<description>
Creates and appends a [CallbackTweener]. This method can be used to call an arbitrary method in any object. Use [method Callable.bind] to bind additional arguments for the call.
Example: object that keeps shooting every 1 second.
@@ -219,9 +219,9 @@
</method>
<method name="tween_interval">
<return type="IntervalTweener" />
- <argument index="0" name="time" type="float" />
+ <param index="0" name="time" type="float" />
<description>
- Creates and appends an [IntervalTweener]. This method can be used to create delays in the tween animation, as an alternative to using the delay in other [Tweener]s, or when there's no animation (in which case the [Tween] acts as a timer). [code]time[/code] is the length of the interval, in seconds.
+ Creates and appends an [IntervalTweener]. This method can be used to create delays in the tween animation, as an alternative to using the delay in other [Tweener]s, or when there's no animation (in which case the [Tween] acts as a timer). [param time] is the length of the interval, in seconds.
Example: creating an interval in code execution.
[codeblock]
# ... some code
@@ -242,12 +242,12 @@
</method>
<method name="tween_method">
<return type="MethodTweener" />
- <argument index="0" name="method" type="Callable" />
- <argument index="1" name="from" type="Variant" />
- <argument index="2" name="to" type="Variant" />
- <argument index="3" name="duration" type="float" />
+ <param index="0" name="method" type="Callable" />
+ <param index="1" name="from" type="Variant" />
+ <param index="2" name="to" type="Variant" />
+ <param index="3" name="duration" type="float" />
<description>
- Creates and appends a [MethodTweener]. This method is similar to a combination of [method tween_callback] and [method tween_property]. It calls a method over time with a tweened value provided as an argument. The value is tweened between [code]from[/code] and [code]to[/code] over the time specified by [code]duration[/code], in seconds. Use [method Callable.bind] to bind additional arguments for the call. You can use [method MethodTweener.set_ease] and [method MethodTweener.set_trans] to tweak the easing and transition of the value or [method MethodTweener.set_delay] to delay the tweening.
+ Creates and appends a [MethodTweener]. This method is similar to a combination of [method tween_callback] and [method tween_property]. It calls a method over time with a tweened value provided as an argument. The value is tweened between [param from] and [param to] over the time specified by [param duration], in seconds. Use [method Callable.bind] to bind additional arguments for the call. You can use [method MethodTweener.set_ease] and [method MethodTweener.set_trans] to tweak the easing and transition of the value or [method MethodTweener.set_delay] to delay the tweening.
Example: making a 3D object look from one point to another point.
[codeblock]
var tween = create_tween()
@@ -266,12 +266,12 @@
</method>
<method name="tween_property">
<return type="PropertyTweener" />
- <argument index="0" name="object" type="Object" />
- <argument index="1" name="property" type="NodePath" />
- <argument index="2" name="final_val" type="Variant" />
- <argument index="3" name="duration" type="float" />
+ <param index="0" name="object" type="Object" />
+ <param index="1" name="property" type="NodePath" />
+ <param index="2" name="final_val" type="Variant" />
+ <param index="3" name="duration" type="float" />
<description>
- Creates and appends a [PropertyTweener]. This method tweens a [code]property[/code] of an [code]object[/code] between an initial value and [code]final_val[/code] in a span of time equal to [code]duration[/code], in seconds. The initial value by default is the property's value at the time the tweening of the [PropertyTweener] starts. For example:
+ Creates and appends a [PropertyTweener]. This method tweens a [param property] of an [param object] between an initial value and [param final_val] in a span of time equal to [param duration], in seconds. The initial value by default is the property's value at the time the tweening of the [PropertyTweener] starts. For example:
[codeblock]
var tween = create_tween()
tween.tween_property($Sprite, "position", Vector2(100, 200), 1)
@@ -296,13 +296,13 @@
</description>
</signal>
<signal name="loop_finished">
- <argument index="0" name="loop_count" type="int" />
+ <param index="0" name="loop_count" type="int" />
<description>
Emitted when a full loop is complete (see [method set_loops]), providing the loop index. This signal is not emitted after the final loop, use [signal finished] instead for this case.
</description>
</signal>
<signal name="step_finished">
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Emitted when one step of the [Tween] is complete, providing the step index. One step is either a single [Tweener] or a group of [Tweener]s running in parallel.
</description>
diff --git a/doc/classes/UDPServer.xml b/doc/classes/UDPServer.xml
index 6fb4d50c0c..c3a3a49a80 100644
--- a/doc/classes/UDPServer.xml
+++ b/doc/classes/UDPServer.xml
@@ -143,10 +143,10 @@
</method>
<method name="listen">
<return type="int" enum="Error" />
- <argument index="0" name="port" type="int" />
- <argument index="1" name="bind_address" type="String" default="&quot;*&quot;" />
+ <param index="0" name="port" type="int" />
+ <param index="1" name="bind_address" type="String" default="&quot;*&quot;" />
<description>
- Starts the server by opening a UDP socket listening on the given port. You can optionally specify a [code]bind_address[/code] to only listen for packets sent to that address. See also [method PacketPeerUDP.bind].
+ Starts the server by opening a UDP socket listening on the given [param port]. You can optionally specify a [param bind_address] to only listen for packets sent to that address. See also [method PacketPeerUDP.bind].
</description>
</method>
<method name="poll">
diff --git a/doc/classes/UndoRedo.xml b/doc/classes/UndoRedo.xml
index 80a548ceaf..3ef59b1c39 100644
--- a/doc/classes/UndoRedo.xml
+++ b/doc/classes/UndoRedo.xml
@@ -64,74 +64,74 @@
<methods>
<method name="add_do_method" qualifiers="vararg">
<return type="void" />
- <argument index="0" name="object" type="Object" />
- <argument index="1" name="method" type="StringName" />
+ <param index="0" name="object" type="Object" />
+ <param index="1" name="method" type="StringName" />
<description>
- Register a method that will be called when the action is committed.
+ Register a [param method] that will be called when the action is committed.
</description>
</method>
<method name="add_do_property">
<return type="void" />
- <argument index="0" name="object" type="Object" />
- <argument index="1" name="property" type="StringName" />
- <argument index="2" name="value" type="Variant" />
+ <param index="0" name="object" type="Object" />
+ <param index="1" name="property" type="StringName" />
+ <param index="2" name="value" type="Variant" />
<description>
- Register a property value change for "do".
+ Register a [param property] that would change its value to [param value] when the action is committed.
</description>
</method>
<method name="add_do_reference">
<return type="void" />
- <argument index="0" name="object" type="Object" />
+ <param index="0" name="object" type="Object" />
<description>
Register a reference for "do" that will be erased if the "do" history is lost. This is useful mostly for new nodes created for the "do" call. Do not use for resources.
</description>
</method>
<method name="add_undo_method" qualifiers="vararg">
<return type="void" />
- <argument index="0" name="object" type="Object" />
- <argument index="1" name="method" type="StringName" />
+ <param index="0" name="object" type="Object" />
+ <param index="1" name="method" type="StringName" />
<description>
- Register a method that will be called when the action is undone.
+ Register a [param method] that will be called when the action is undone.
</description>
</method>
<method name="add_undo_property">
<return type="void" />
- <argument index="0" name="object" type="Object" />
- <argument index="1" name="property" type="StringName" />
- <argument index="2" name="value" type="Variant" />
+ <param index="0" name="object" type="Object" />
+ <param index="1" name="property" type="StringName" />
+ <param index="2" name="value" type="Variant" />
<description>
- Register a property value change for "undo".
+ Register a [param property] that would change its value to [param value] when the action is undone.
</description>
</method>
<method name="add_undo_reference">
<return type="void" />
- <argument index="0" name="object" type="Object" />
+ <param index="0" name="object" type="Object" />
<description>
Register a reference for "undo" that will be erased if the "undo" history is lost. This is useful mostly for nodes removed with the "do" call (not the "undo" call!).
</description>
</method>
<method name="clear_history">
<return type="void" />
- <argument index="0" name="increase_version" type="bool" default="true" />
+ <param index="0" name="increase_version" type="bool" default="true" />
<description>
Clear the undo/redo history and associated references.
- Passing [code]false[/code] to [code]increase_version[/code] will prevent the version number to be increased from this.
+ Passing [code]false[/code] to [param increase_version] will prevent the version number from increasing when the history is cleared.
</description>
</method>
<method name="commit_action">
<return type="void" />
- <argument index="0" name="execute" type="bool" default="true" />
+ <param index="0" name="execute" type="bool" default="true" />
<description>
- Commit the action. If [code]execute[/code] is true (default), all "do" methods/properties are called/set when this function is called.
+ Commit the action. If [param execute] is [code]true[/code] (which it is by default), all "do" methods/properties are called/set when this function is called.
</description>
</method>
<method name="create_action">
<return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="merge_mode" type="int" enum="UndoRedo.MergeMode" default="0" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="merge_mode" type="int" enum="UndoRedo.MergeMode" default="0" />
<description>
Create a new action. After this is called, do all your calls to [method add_do_method], [method add_undo_method], [method add_do_property], and [method add_undo_property], then commit the action with [method commit_action].
- The way actions are merged is dictated by the [code]merge_mode[/code] argument. See [enum MergeMode] for details.
+ The way actions are merged is dictated by [param merge_mode]. See [enum MergeMode] for details.
</description>
</method>
<method name="end_force_keep_in_merge_ends">
@@ -142,7 +142,7 @@
</method>
<method name="get_action_name">
<return type="String" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Gets the action name from its index.
</description>
diff --git a/doc/classes/Variant.xml b/doc/classes/Variant.xml
index 0d6fcd0ef5..6b384d6a77 100644
--- a/doc/classes/Variant.xml
+++ b/doc/classes/Variant.xml
@@ -23,7 +23,6 @@
[/codeblocks]
Godot tracks all scripting API variables within Variants. Without even realizing it, you use Variants all the time. When a particular language enforces its own rules for keeping data typed, then that language is applying its own custom logic over the base Variant scripting API.
- GDScript automatically wrap values in them. It keeps all data in plain Variants by default and then optionally enforces custom static typing rules on variable types.
- - VisualScript tracks properties inside Variants as well, but it also uses static typing. The GUI interface enforces that properties have a particular type that doesn't change over time.
- C# is statically typed, but uses the Mono [code]object[/code] type in place of Godot's Variant class when it needs to represent a dynamic value. [code]object[/code] is the Mono runtime's equivalent of the same concept.
The global [method @GlobalScope.typeof] function returns the enumerated value of the Variant type stored in the current variable (see [enum Variant.Type]).
[codeblocks]
diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml
index 454db51919..2197947126 100644
--- a/doc/classes/Vector2.xml
+++ b/doc/classes/Vector2.xml
@@ -25,24 +25,24 @@
</constructor>
<constructor name="Vector2">
<return type="Vector2" />
- <argument index="0" name="from" type="Vector2" />
+ <param index="0" name="from" type="Vector2" />
<description>
Constructs a [Vector2] as a copy of the given [Vector2].
</description>
</constructor>
<constructor name="Vector2">
<return type="Vector2" />
- <argument index="0" name="from" type="Vector2i" />
+ <param index="0" name="from" type="Vector2i" />
<description>
Constructs a new [Vector2] from [Vector2i].
</description>
</constructor>
<constructor name="Vector2">
<return type="Vector2" />
- <argument index="0" name="x" type="float" />
- <argument index="1" name="y" type="float" />
+ <param index="0" name="x" type="float" />
+ <param index="1" name="y" type="float" />
<description>
- Constructs a new [Vector2] from the given [code]x[/code] and [code]y[/code].
+ Constructs a new [Vector2] from the given [param x] and [param y].
</description>
</constructor>
</constructors>
@@ -64,7 +64,7 @@
</method>
<method name="angle_to" qualifiers="const">
<return type="float" />
- <argument index="0" name="to" type="Vector2" />
+ <param index="0" name="to" type="Vector2" />
<description>
Returns the angle to the given vector, in radians.
[url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/vector2_angle_to.png]Illustration of the returned angle.[/url]
@@ -72,7 +72,7 @@
</method>
<method name="angle_to_point" qualifiers="const">
<return type="float" />
- <argument index="0" name="to" type="Vector2" />
+ <param index="0" name="to" type="Vector2" />
<description>
Returns the angle between the line connecting the two points and the X axis, in radians.
[code]a.angle_to_point(b)[/code] is equivalent of doing [code](b - a).angle()[/code].
@@ -87,17 +87,17 @@
</method>
<method name="bezier_interpolate" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="control_1" type="Vector2" />
- <argument index="1" name="control_2" type="Vector2" />
- <argument index="2" name="end" type="Vector2" />
- <argument index="3" name="t" type="float" />
+ <param index="0" name="control_1" type="Vector2" />
+ <param index="1" name="control_2" type="Vector2" />
+ <param index="2" name="end" type="Vector2" />
+ <param index="3" name="t" type="float" />
<description>
- Returns the point at the given [code]t[/code] on the [url=https://en.wikipedia.org/wiki/B%C3%A9zier_curve]Bezier curve[/url] defined by this vector and the given [code]control_1[/code], [code]control_2[/code], and [code]end[/code] points.
+ Returns the point at the given [param t] on the [url=https://en.wikipedia.org/wiki/B%C3%A9zier_curve]Bezier curve[/url] defined by this vector and the given [param control_1], [param control_2], and [param end] points.
</description>
</method>
<method name="bounce" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="n" type="Vector2" />
+ <param index="0" name="n" type="Vector2" />
<description>
Returns the vector "bounced off" from a plane defined by the given normal.
</description>
@@ -110,58 +110,72 @@
</method>
<method name="clamp" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="min" type="Vector2" />
- <argument index="1" name="max" type="Vector2" />
+ <param index="0" name="min" type="Vector2" />
+ <param index="1" name="max" type="Vector2" />
<description>
- Returns a new vector with all components clamped between the components of [code]min[/code] and [code]max[/code], by running [method @GlobalScope.clamp] on each component.
+ Returns a new vector with all components clamped between the components of [param min] and [param max], by running [method @GlobalScope.clamp] on each component.
</description>
</method>
<method name="cross" qualifiers="const">
<return type="float" />
- <argument index="0" name="with" type="Vector2" />
+ <param index="0" name="with" type="Vector2" />
<description>
- Returns the 2D analog of the cross product for this vector and [code]with[/code].
+ Returns the 2D analog of the cross product for this vector and [param with].
This is the signed area of the parallelogram formed by the two vectors. If the second vector is clockwise from the first vector, then the cross product is the positive area. If counter-clockwise, the cross product is the negative area.
[b]Note:[/b] Cross product is not defined in 2D mathematically. This method embeds the 2D vectors in the XY plane of 3D space and uses their cross product's Z component as the analog.
</description>
</method>
<method name="cubic_interpolate" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="b" type="Vector2" />
- <argument index="1" name="pre_a" type="Vector2" />
- <argument index="2" name="post_b" type="Vector2" />
- <argument index="3" name="weight" type="float" />
+ <param index="0" name="b" type="Vector2" />
+ <param index="1" name="pre_a" type="Vector2" />
+ <param index="2" name="post_b" type="Vector2" />
+ <param index="3" name="weight" type="float" />
<description>
- Cubically interpolates between this vector and [code]b[/code] using [code]pre_a[/code] and [code]post_b[/code] as handles, and returns the result at position [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ Cubically interpolates between this vector and [param b] using [param pre_a] and [param post_b] as handles, and returns the result at position [param weight]. [param weight] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ </description>
+ </method>
+ <method name="cubic_interpolate_in_time" qualifiers="const">
+ <return type="Vector2" />
+ <param index="0" name="b" type="Vector2" />
+ <param index="1" name="pre_a" type="Vector2" />
+ <param index="2" name="post_b" type="Vector2" />
+ <param index="3" name="weight" type="float" />
+ <param index="4" name="b_t" type="float" />
+ <param index="5" name="pre_a_t" type="float" />
+ <param index="6" name="post_b_t" type="float" />
+ <description>
+ Cubically interpolates between this vector and [param b] using [param pre_a] and [param post_b] as handles, and returns the result at position [param weight]. [param weight] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ It can perform smoother interpolation than [code]cubic_interpolate()[/code] by the time values.
</description>
</method>
<method name="direction_to" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="to" type="Vector2" />
+ <param index="0" name="to" type="Vector2" />
<description>
- Returns the normalized vector pointing from this vector to [code]to[/code]. This is equivalent to using [code](b - a).normalized()[/code].
+ Returns the normalized vector pointing from this vector to [param to]. This is equivalent to using [code](b - a).normalized()[/code].
</description>
</method>
<method name="distance_squared_to" qualifiers="const">
<return type="float" />
- <argument index="0" name="to" type="Vector2" />
+ <param index="0" name="to" type="Vector2" />
<description>
- Returns the squared distance between this vector and [code]to[/code].
+ Returns the squared distance between this vector and [param to].
This method runs faster than [method distance_to], so prefer it if you need to compare vectors or need the squared distance for some formula.
</description>
</method>
<method name="distance_to" qualifiers="const">
<return type="float" />
- <argument index="0" name="to" type="Vector2" />
+ <param index="0" name="to" type="Vector2" />
<description>
- Returns the distance between this vector and [code]to[/code].
+ Returns the distance between this vector and [param to].
</description>
</method>
<method name="dot" qualifiers="const">
<return type="float" />
- <argument index="0" name="with" type="Vector2" />
+ <param index="0" name="with" type="Vector2" />
<description>
- Returns the dot product of this vector and [code]with[/code]. This can be used to compare the angle between two vectors. For example, this can be used to determine whether an enemy is facing the player.
+ Returns the dot product of this vector and [param with]. This can be used to compare the angle between two vectors. For example, this can be used to determine whether an enemy is facing the player.
The dot product will be [code]0[/code] for a straight angle (90 degrees), greater than 0 for angles narrower than 90 degrees and lower than 0 for angles wider than 90 degrees.
When using unit (normalized) vectors, the result will always be between [code]-1.0[/code] (180 degree angle) when the vectors are facing opposite directions, and [code]1.0[/code] (0 degree angle) when the vectors are aligned.
[b]Note:[/b] [code]a.dot(b)[/code] is equivalent to [code]b.dot(a)[/code].
@@ -175,9 +189,9 @@
</method>
<method name="from_angle" qualifiers="static">
<return type="Vector2" />
- <argument index="0" name="angle" type="float" />
+ <param index="0" name="angle" type="float" />
<description>
- Creates a unit [Vector2] rotated to the given [code]angle[/code] in radians. This is equivalent to doing [code]Vector2(cos(angle), sin(angle))[/code] or [code]Vector2.RIGHT.rotated(angle)[/code].
+ Creates a unit [Vector2] rotated to the given [param angle] in radians. This is equivalent to doing [code]Vector2(cos(angle), sin(angle))[/code] or [code]Vector2.RIGHT.rotated(angle)[/code].
[codeblock]
print(Vector2.from_angle(0)) # Prints (1, 0).
print(Vector2(1, 0).angle()) # Prints 0, which is the angle used above.
@@ -187,7 +201,7 @@
</method>
<method name="is_equal_approx" qualifiers="const">
<return type="bool" />
- <argument index="0" name="to" type="Vector2" />
+ <param index="0" name="to" type="Vector2" />
<description>
Returns [code]true[/code] if this vector and [code]v[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
@@ -213,17 +227,17 @@
</method>
<method name="lerp" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="to" type="Vector2" />
- <argument index="1" name="weight" type="float" />
+ <param index="0" name="to" type="Vector2" />
+ <param index="1" name="weight" type="float" />
<description>
- Returns the result of the linear interpolation between this vector and [code]to[/code] by amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ Returns the result of the linear interpolation between this vector and [param to] by amount [param weight]. [param weight] is on the range of 0.0 to 1.0, representing the amount of interpolation.
</description>
</method>
<method name="limit_length" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="length" type="float" default="1.0" />
+ <param index="0" name="length" type="float" default="1.0" />
<description>
- Returns the vector with a maximum length by limiting its length to [code]length[/code].
+ Returns the vector with a maximum length by limiting its length to [param length].
</description>
</method>
<method name="max_axis_index" qualifiers="const">
@@ -240,10 +254,10 @@
</method>
<method name="move_toward" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="to" type="Vector2" />
- <argument index="1" name="delta" type="float" />
+ <param index="0" name="to" type="Vector2" />
+ <param index="1" name="delta" type="float" />
<description>
- Returns a new vector moved toward [code]to[/code] by the fixed [code]delta[/code] amount. Will not go past the final value.
+ Returns a new vector moved toward [param to] by the fixed [param delta] amount. Will not go past the final value.
</description>
</method>
<method name="normalized" qualifiers="const">
@@ -260,37 +274,37 @@
</method>
<method name="posmod" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="mod" type="float" />
+ <param index="0" name="mod" type="float" />
<description>
- Returns a vector composed of the [method @GlobalScope.fposmod] of this vector's components and [code]mod[/code].
+ Returns a vector composed of the [method @GlobalScope.fposmod] of this vector's components and [param mod].
</description>
</method>
<method name="posmodv" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="modv" type="Vector2" />
+ <param index="0" name="modv" type="Vector2" />
<description>
- Returns a vector composed of the [method @GlobalScope.fposmod] of this vector's components and [code]modv[/code]'s components.
+ Returns a vector composed of the [method @GlobalScope.fposmod] of this vector's components and [param modv]'s components.
</description>
</method>
<method name="project" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="b" type="Vector2" />
+ <param index="0" name="b" type="Vector2" />
<description>
Returns this vector projected onto the vector [code]b[/code].
</description>
</method>
<method name="reflect" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="n" type="Vector2" />
+ <param index="0" name="n" type="Vector2" />
<description>
- Returns the vector reflected (i.e. mirrored, or symmetric) over a line defined by the given direction vector [code]n[/code].
+ Returns the vector reflected (i.e. mirrored, or symmetric) over a line defined by the given direction vector [param n].
</description>
</method>
<method name="rotated" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="angle" type="float" />
+ <param index="0" name="angle" type="float" />
<description>
- Returns the vector rotated by [code]angle[/code] (in radians). See also [method @GlobalScope.deg2rad].
+ Returns the vector rotated by [param angle] (in radians). See also [method @GlobalScope.deg_to_rad].
</description>
</method>
<method name="round" qualifiers="const">
@@ -307,25 +321,25 @@
</method>
<method name="slerp" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="to" type="Vector2" />
- <argument index="1" name="weight" type="float" />
+ <param index="0" name="to" type="Vector2" />
+ <param index="1" name="weight" type="float" />
<description>
- Returns the result of spherical linear interpolation between this vector and [code]to[/code], by amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ Returns the result of spherical linear interpolation between this vector and [param to], by amount [param weight]. [param weight] is on the range of 0.0 to 1.0, representing the amount of interpolation.
This method also handles interpolating the lengths if the input vectors have different lengths. For the special case of one or both input vectors having zero length, this method behaves like [method lerp].
</description>
</method>
<method name="slide" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="n" type="Vector2" />
+ <param index="0" name="n" type="Vector2" />
<description>
Returns this vector slid along a plane defined by the given normal.
</description>
</method>
<method name="snapped" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="step" type="Vector2" />
+ <param index="0" name="step" type="Vector2" />
<description>
- Returns this vector with each component snapped to the nearest multiple of [code]step[/code]. This can also be used to round to an arbitrary number of decimals.
+ Returns this vector with each component snapped to the nearest multiple of [param step]. This can also be used to round to an arbitrary number of decimals.
</description>
</method>
</methods>
@@ -369,7 +383,7 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="Vector2" />
+ <param index="0" name="right" type="Vector2" />
<description>
Returns [code]true[/code] if the vectors are not equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
@@ -377,14 +391,14 @@
</operator>
<operator name="operator *">
<return type="Vector2" />
- <argument index="0" name="right" type="Transform2D" />
+ <param index="0" name="right" type="Transform2D" />
<description>
Inversely transforms (multiplies) the [Vector2] by the given [Transform2D] transformation matrix.
</description>
</operator>
<operator name="operator *">
<return type="Vector2" />
- <argument index="0" name="right" type="Vector2" />
+ <param index="0" name="right" type="Vector2" />
<description>
Multiplies each component of the [Vector2] by the components of the given [Vector2].
[codeblock]
@@ -394,21 +408,21 @@
</operator>
<operator name="operator *">
<return type="Vector2" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Multiplies each component of the [Vector2] by the given [float].
</description>
</operator>
<operator name="operator *">
<return type="Vector2" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Multiplies each component of the [Vector2] by the given [int].
</description>
</operator>
<operator name="operator +">
<return type="Vector2" />
- <argument index="0" name="right" type="Vector2" />
+ <param index="0" name="right" type="Vector2" />
<description>
Adds each component of the [Vector2] by the components of the given [Vector2].
[codeblock]
@@ -418,7 +432,7 @@
</operator>
<operator name="operator -">
<return type="Vector2" />
- <argument index="0" name="right" type="Vector2" />
+ <param index="0" name="right" type="Vector2" />
<description>
Subtracts each component of the [Vector2] by the components of the given [Vector2].
[codeblock]
@@ -428,7 +442,7 @@
</operator>
<operator name="operator /">
<return type="Vector2" />
- <argument index="0" name="right" type="Vector2" />
+ <param index="0" name="right" type="Vector2" />
<description>
Divides each component of the [Vector2] by the components of the given [Vector2].
[codeblock]
@@ -438,35 +452,35 @@
</operator>
<operator name="operator /">
<return type="Vector2" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Divides each component of the [Vector2] by the given [float].
</description>
</operator>
<operator name="operator /">
<return type="Vector2" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Divides each component of the [Vector2] by the given [int].
</description>
</operator>
<operator name="operator &lt;">
<return type="bool" />
- <argument index="0" name="right" type="Vector2" />
+ <param index="0" name="right" type="Vector2" />
<description>
- Compares two [Vector2] vectors by first checking if the X value of the left vector is less than the X value of the [code]right[/code] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors. This operator is useful for sorting vectors.
+ Compares two [Vector2] vectors by first checking if the X value of the left vector is less than the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator &lt;=">
<return type="bool" />
- <argument index="0" name="right" type="Vector2" />
+ <param index="0" name="right" type="Vector2" />
<description>
- Compares two [Vector2] vectors by first checking if the X value of the left vector is less than or equal to the X value of the [code]right[/code] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors. This operator is useful for sorting vectors.
+ Compares two [Vector2] vectors by first checking if the X value of the left vector is less than or equal to the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="Vector2" />
+ <param index="0" name="right" type="Vector2" />
<description>
Returns [code]true[/code] if the vectors are exactly equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
@@ -474,23 +488,23 @@
</operator>
<operator name="operator &gt;">
<return type="bool" />
- <argument index="0" name="right" type="Vector2" />
+ <param index="0" name="right" type="Vector2" />
<description>
- Compares two [Vector2] vectors by first checking if the X value of the left vector is greater than the X value of the [code]right[/code] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors. This operator is useful for sorting vectors.
+ Compares two [Vector2] vectors by first checking if the X value of the left vector is greater than the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator &gt;=">
<return type="bool" />
- <argument index="0" name="right" type="Vector2" />
+ <param index="0" name="right" type="Vector2" />
<description>
- Compares two [Vector2] vectors by first checking if the X value of the left vector is greater than or equal to the X value of the [code]right[/code] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors. This operator is useful for sorting vectors.
+ Compares two [Vector2] vectors by first checking if the X value of the left vector is greater than or equal to the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator []">
<return type="float" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Access vector components using their index. [code]v[0][/code] is equivalent to [code]v.x[/code], and [code]v[1][/code] is equivalent to [code]v.y[/code].
+ Access vector components using their [param index]. [code]v[0][/code] is equivalent to [code]v.x[/code], and [code]v[1][/code] is equivalent to [code]v.y[/code].
</description>
</operator>
<operator name="operator unary+">
diff --git a/doc/classes/Vector2i.xml b/doc/classes/Vector2i.xml
index 28d68b6e44..eab880e57f 100644
--- a/doc/classes/Vector2i.xml
+++ b/doc/classes/Vector2i.xml
@@ -22,24 +22,24 @@
</constructor>
<constructor name="Vector2i">
<return type="Vector2i" />
- <argument index="0" name="from" type="Vector2i" />
+ <param index="0" name="from" type="Vector2i" />
<description>
Constructs a [Vector2i] as a copy of the given [Vector2i].
</description>
</constructor>
<constructor name="Vector2i">
<return type="Vector2i" />
- <argument index="0" name="from" type="Vector2" />
+ <param index="0" name="from" type="Vector2" />
<description>
Constructs a new [Vector2i] from [Vector2]. The floating point coordinates will be truncated.
</description>
</constructor>
<constructor name="Vector2i">
<return type="Vector2i" />
- <argument index="0" name="x" type="int" />
- <argument index="1" name="y" type="int" />
+ <param index="0" name="x" type="int" />
+ <param index="1" name="y" type="int" />
<description>
- Constructs a new [Vector2i] from the given [code]x[/code] and [code]y[/code].
+ Constructs a new [Vector2i] from the given [param x] and [param y].
</description>
</constructor>
</constructors>
@@ -58,10 +58,10 @@
</method>
<method name="clamp" qualifiers="const">
<return type="Vector2i" />
- <argument index="0" name="min" type="Vector2i" />
- <argument index="1" name="max" type="Vector2i" />
+ <param index="0" name="min" type="Vector2i" />
+ <param index="1" name="max" type="Vector2i" />
<description>
- Returns a new vector with all components clamped between the components of [code]min[/code] and [code]max[/code], by running [method @GlobalScope.clamp] on each component.
+ Returns a new vector with all components clamped between the components of [param min] and [param max], by running [method @GlobalScope.clamp] on each component.
</description>
</method>
<method name="length" qualifiers="const">
@@ -133,14 +133,14 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="Vector2i" />
+ <param index="0" name="right" type="Vector2i" />
<description>
Returns [code]true[/code] if the vectors are not equal.
</description>
</operator>
<operator name="operator %">
<return type="Vector2i" />
- <argument index="0" name="right" type="Vector2i" />
+ <param index="0" name="right" type="Vector2i" />
<description>
Gets the remainder of each component of the [Vector2i] with the components of the given [Vector2i]. This operation uses truncated division, which is often not desired as it does not work well with negative numbers. Consider using [method @GlobalScope.posmod] instead if you want to handle negative numbers.
[codeblock]
@@ -150,7 +150,7 @@
</operator>
<operator name="operator %">
<return type="Vector2i" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Gets the remainder of each component of the [Vector2i] with the the given [int]. This operation uses truncated division, which is often not desired as it does not work well with negative numbers. Consider using [method @GlobalScope.posmod] instead if you want to handle negative numbers.
[codeblock]
@@ -160,7 +160,7 @@
</operator>
<operator name="operator *">
<return type="Vector2i" />
- <argument index="0" name="right" type="Vector2i" />
+ <param index="0" name="right" type="Vector2i" />
<description>
Multiplies each component of the [Vector2i] by the components of the given [Vector2i].
[codeblock]
@@ -170,7 +170,7 @@
</operator>
<operator name="operator *">
<return type="Vector2" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Multiplies each component of the [Vector2i] by the given [float]. Returns a [Vector2].
[codeblock]
@@ -180,14 +180,14 @@
</operator>
<operator name="operator *">
<return type="Vector2i" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Multiplies each component of the [Vector2i] by the given [int].
</description>
</operator>
<operator name="operator +">
<return type="Vector2i" />
- <argument index="0" name="right" type="Vector2i" />
+ <param index="0" name="right" type="Vector2i" />
<description>
Adds each component of the [Vector2i] by the components of the given [Vector2i].
[codeblock]
@@ -197,7 +197,7 @@
</operator>
<operator name="operator -">
<return type="Vector2i" />
- <argument index="0" name="right" type="Vector2i" />
+ <param index="0" name="right" type="Vector2i" />
<description>
Subtracts each component of the [Vector2i] by the components of the given [Vector2i].
[codeblock]
@@ -207,7 +207,7 @@
</operator>
<operator name="operator /">
<return type="Vector2i" />
- <argument index="0" name="right" type="Vector2i" />
+ <param index="0" name="right" type="Vector2i" />
<description>
Divides each component of the [Vector2i] by the components of the given [Vector2i].
[codeblock]
@@ -217,7 +217,7 @@
</operator>
<operator name="operator /">
<return type="Vector2" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Divides each component of the [Vector2i] by the given [float]. Returns a [Vector2].
[codeblock]
@@ -227,51 +227,51 @@
</operator>
<operator name="operator /">
<return type="Vector2i" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Divides each component of the [Vector2i] by the given [int].
</description>
</operator>
<operator name="operator &lt;">
<return type="bool" />
- <argument index="0" name="right" type="Vector2i" />
+ <param index="0" name="right" type="Vector2i" />
<description>
- Compares two [Vector2i] vectors by first checking if the X value of the left vector is less than the X value of the [code]right[/code] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors. This operator is useful for sorting vectors.
+ Compares two [Vector2i] vectors by first checking if the X value of the left vector is less than the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator &lt;=">
<return type="bool" />
- <argument index="0" name="right" type="Vector2i" />
+ <param index="0" name="right" type="Vector2i" />
<description>
- Compares two [Vector2i] vectors by first checking if the X value of the left vector is less than or equal to the X value of the [code]right[/code] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors. This operator is useful for sorting vectors.
+ Compares two [Vector2i] vectors by first checking if the X value of the left vector is less than or equal to the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="Vector2i" />
+ <param index="0" name="right" type="Vector2i" />
<description>
Returns [code]true[/code] if the vectors are equal.
</description>
</operator>
<operator name="operator &gt;">
<return type="bool" />
- <argument index="0" name="right" type="Vector2i" />
+ <param index="0" name="right" type="Vector2i" />
<description>
- Compares two [Vector2i] vectors by first checking if the X value of the left vector is greater than the X value of the [code]right[/code] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors. This operator is useful for sorting vectors.
+ Compares two [Vector2i] vectors by first checking if the X value of the left vector is greater than the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator &gt;=">
<return type="bool" />
- <argument index="0" name="right" type="Vector2i" />
+ <param index="0" name="right" type="Vector2i" />
<description>
- Compares two [Vector2i] vectors by first checking if the X value of the left vector is greater than or equal to the X value of the [code]right[/code] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors. This operator is useful for sorting vectors.
+ Compares two [Vector2i] vectors by first checking if the X value of the left vector is greater than or equal to the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator []">
<return type="int" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Access vector components using their index. [code]v[0][/code] is equivalent to [code]v.x[/code], and [code]v[1][/code] is equivalent to [code]v.y[/code].
+ Access vector components using their [param index]. [code]v[0][/code] is equivalent to [code]v.x[/code], and [code]v[1][/code] is equivalent to [code]v.y[/code].
</description>
</operator>
<operator name="operator unary+">
diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml
index c181720a66..150d53845c 100644
--- a/doc/classes/Vector3.xml
+++ b/doc/classes/Vector3.xml
@@ -25,23 +25,23 @@
</constructor>
<constructor name="Vector3">
<return type="Vector3" />
- <argument index="0" name="from" type="Vector3" />
+ <param index="0" name="from" type="Vector3" />
<description>
Constructs a [Vector3] as a copy of the given [Vector3].
</description>
</constructor>
<constructor name="Vector3">
<return type="Vector3" />
- <argument index="0" name="from" type="Vector3i" />
+ <param index="0" name="from" type="Vector3i" />
<description>
Constructs a new [Vector3] from [Vector3i].
</description>
</constructor>
<constructor name="Vector3">
<return type="Vector3" />
- <argument index="0" name="x" type="float" />
- <argument index="1" name="y" type="float" />
- <argument index="2" name="z" type="float" />
+ <param index="0" name="x" type="float" />
+ <param index="1" name="y" type="float" />
+ <param index="2" name="z" type="float" />
<description>
Returns a [Vector3] with the given components.
</description>
@@ -56,24 +56,24 @@
</method>
<method name="angle_to" qualifiers="const">
<return type="float" />
- <argument index="0" name="to" type="Vector3" />
+ <param index="0" name="to" type="Vector3" />
<description>
Returns the unsigned minimum angle to the given vector, in radians.
</description>
</method>
<method name="bezier_interpolate" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="control_1" type="Vector3" />
- <argument index="1" name="control_2" type="Vector3" />
- <argument index="2" name="end" type="Vector3" />
- <argument index="3" name="t" type="float" />
+ <param index="0" name="control_1" type="Vector3" />
+ <param index="1" name="control_2" type="Vector3" />
+ <param index="2" name="end" type="Vector3" />
+ <param index="3" name="t" type="float" />
<description>
- Returns the point at the given [code]t[/code] on the [url=https://en.wikipedia.org/wiki/B%C3%A9zier_curve]Bezier curve[/url] defined by this vector and the given [code]control_1[/code], [code]control_2[/code], and [code]end[/code] points.
+ Returns the point at the given [param t] on the [url=https://en.wikipedia.org/wiki/B%C3%A9zier_curve]Bezier curve[/url] defined by this vector and the given [param control_1], [param control_2], and [param end] points.
</description>
</method>
<method name="bounce" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="n" type="Vector3" />
+ <param index="0" name="n" type="Vector3" />
<description>
Returns the vector "bounced off" from a plane defined by the given normal.
</description>
@@ -86,56 +86,70 @@
</method>
<method name="clamp" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="min" type="Vector3" />
- <argument index="1" name="max" type="Vector3" />
+ <param index="0" name="min" type="Vector3" />
+ <param index="1" name="max" type="Vector3" />
<description>
- Returns a new vector with all components clamped between the components of [code]min[/code] and [code]max[/code], by running [method @GlobalScope.clamp] on each component.
+ Returns a new vector with all components clamped between the components of [param min] and [param max], by running [method @GlobalScope.clamp] on each component.
</description>
</method>
<method name="cross" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="with" type="Vector3" />
+ <param index="0" name="with" type="Vector3" />
<description>
- Returns the cross product of this vector and [code]with[/code].
+ Returns the cross product of this vector and [param with].
</description>
</method>
<method name="cubic_interpolate" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="b" type="Vector3" />
- <argument index="1" name="pre_a" type="Vector3" />
- <argument index="2" name="post_b" type="Vector3" />
- <argument index="3" name="weight" type="float" />
+ <param index="0" name="b" type="Vector3" />
+ <param index="1" name="pre_a" type="Vector3" />
+ <param index="2" name="post_b" type="Vector3" />
+ <param index="3" name="weight" type="float" />
<description>
- Performs a cubic interpolation between this vector and [code]b[/code] using [code]pre_a[/code] and [code]post_b[/code] as handles, and returns the result at position [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ Performs a cubic interpolation between this vector and [param b] using [param pre_a] and [param post_b] as handles, and returns the result at position [param weight]. [param weight] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ </description>
+ </method>
+ <method name="cubic_interpolate_in_time" qualifiers="const">
+ <return type="Vector3" />
+ <param index="0" name="b" type="Vector3" />
+ <param index="1" name="pre_a" type="Vector3" />
+ <param index="2" name="post_b" type="Vector3" />
+ <param index="3" name="weight" type="float" />
+ <param index="4" name="b_t" type="float" />
+ <param index="5" name="pre_a_t" type="float" />
+ <param index="6" name="post_b_t" type="float" />
+ <description>
+ Performs a cubic interpolation between this vector and [param b] using [param pre_a] and [param post_b] as handles, and returns the result at position [param weight]. [param weight] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ It can perform smoother interpolation than [code]cubic_interpolate()[/code] by the time values.
</description>
</method>
<method name="direction_to" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="to" type="Vector3" />
+ <param index="0" name="to" type="Vector3" />
<description>
- Returns the normalized vector pointing from this vector to [code]to[/code]. This is equivalent to using [code](b - a).normalized()[/code].
+ Returns the normalized vector pointing from this vector to [param to]. This is equivalent to using [code](b - a).normalized()[/code].
</description>
</method>
<method name="distance_squared_to" qualifiers="const">
<return type="float" />
- <argument index="0" name="to" type="Vector3" />
+ <param index="0" name="to" type="Vector3" />
<description>
- Returns the squared distance between this vector and [code]to[/code].
+ Returns the squared distance between this vector and [param to].
This method runs faster than [method distance_to], so prefer it if you need to compare vectors or need the squared distance for some formula.
</description>
</method>
<method name="distance_to" qualifiers="const">
<return type="float" />
- <argument index="0" name="to" type="Vector3" />
+ <param index="0" name="to" type="Vector3" />
<description>
- Returns the distance between this vector and [code]to[/code].
+ Returns the distance between this vector and [param to].
</description>
</method>
<method name="dot" qualifiers="const">
<return type="float" />
- <argument index="0" name="with" type="Vector3" />
+ <param index="0" name="with" type="Vector3" />
<description>
- Returns the dot product of this vector and [code]with[/code]. This can be used to compare the angle between two vectors. For example, this can be used to determine whether an enemy is facing the player.
+ Returns the dot product of this vector and [param with]. This can be used to compare the angle between two vectors. For example, this can be used to determine whether an enemy is facing the player.
The dot product will be [code]0[/code] for a straight angle (90 degrees), greater than 0 for angles narrower than 90 degrees and lower than 0 for angles wider than 90 degrees.
When using unit (normalized) vectors, the result will always be between [code]-1.0[/code] (180 degree angle) when the vectors are facing opposite directions, and [code]1.0[/code] (0 degree angle) when the vectors are aligned.
[b]Note:[/b] [code]a.dot(b)[/code] is equivalent to [code]b.dot(a)[/code].
@@ -155,9 +169,9 @@
</method>
<method name="is_equal_approx" qualifiers="const">
<return type="bool" />
- <argument index="0" name="to" type="Vector3" />
+ <param index="0" name="to" type="Vector3" />
<description>
- Returns [code]true[/code] if this vector and [code]v[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
+ Returns [code]true[/code] if this vector and [param to] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
<method name="is_normalized" qualifiers="const">
@@ -181,17 +195,17 @@
</method>
<method name="lerp" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="to" type="Vector3" />
- <argument index="1" name="weight" type="float" />
+ <param index="0" name="to" type="Vector3" />
+ <param index="1" name="weight" type="float" />
<description>
- Returns the result of the linear interpolation between this vector and [code]to[/code] by amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ Returns the result of the linear interpolation between this vector and [param to] by amount [param weight]. [param weight] is on the range of 0.0 to 1.0, representing the amount of interpolation.
</description>
</method>
<method name="limit_length" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="length" type="float" default="1.0" />
+ <param index="0" name="length" type="float" default="1.0" />
<description>
- Returns the vector with a maximum length by limiting its length to [code]length[/code].
+ Returns the vector with a maximum length by limiting its length to [param length].
</description>
</method>
<method name="max_axis_index" qualifiers="const">
@@ -208,10 +222,10 @@
</method>
<method name="move_toward" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="to" type="Vector3" />
- <argument index="1" name="delta" type="float" />
+ <param index="0" name="to" type="Vector3" />
+ <param index="1" name="delta" type="float" />
<description>
- Returns a new vector moved toward [code]to[/code] by the fixed [code]delta[/code] amount. Will not go past the final value.
+ Returns a new vector moved toward [param to] by the fixed [param delta] amount. Will not go past the final value.
</description>
</method>
<method name="normalized" qualifiers="const">
@@ -222,7 +236,7 @@
</method>
<method name="octahedron_decode" qualifiers="static">
<return type="Vector3" />
- <argument index="0" name="uv" type="Vector2" />
+ <param index="0" name="uv" type="Vector2" />
<description>
</description>
</method>
@@ -233,45 +247,45 @@
</method>
<method name="outer" qualifiers="const">
<return type="Basis" />
- <argument index="0" name="with" type="Vector3" />
+ <param index="0" name="with" type="Vector3" />
<description>
- Returns the outer product with [code]with[/code].
+ Returns the outer product with [param with].
</description>
</method>
<method name="posmod" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="mod" type="float" />
+ <param index="0" name="mod" type="float" />
<description>
- Returns a vector composed of the [method @GlobalScope.fposmod] of this vector's components and [code]mod[/code].
+ Returns a vector composed of the [method @GlobalScope.fposmod] of this vector's components and [param mod].
</description>
</method>
<method name="posmodv" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="modv" type="Vector3" />
+ <param index="0" name="modv" type="Vector3" />
<description>
- Returns a vector composed of the [method @GlobalScope.fposmod] of this vector's components and [code]modv[/code]'s components.
+ Returns a vector composed of the [method @GlobalScope.fposmod] of this vector's components and [param modv]'s components.
</description>
</method>
<method name="project" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="b" type="Vector3" />
+ <param index="0" name="b" type="Vector3" />
<description>
- Returns this vector projected onto the vector [code]b[/code].
+ Returns this vector projected onto the vector [param b].
</description>
</method>
<method name="reflect" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="n" type="Vector3" />
+ <param index="0" name="n" type="Vector3" />
<description>
Returns this vector reflected from a plane defined by the given normal.
</description>
</method>
<method name="rotated" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="axis" type="Vector3" />
- <argument index="1" name="angle" type="float" />
+ <param index="0" name="axis" type="Vector3" />
+ <param index="1" name="angle" type="float" />
<description>
- Rotates this vector around a given axis by [code]angle[/code] (in radians). The axis must be a normalized vector.
+ Rotates this vector around a given axis by [param angle] (in radians). The axis must be a normalized vector.
</description>
</method>
<method name="round" qualifiers="const">
@@ -288,33 +302,33 @@
</method>
<method name="signed_angle_to" qualifiers="const">
<return type="float" />
- <argument index="0" name="to" type="Vector3" />
- <argument index="1" name="axis" type="Vector3" />
+ <param index="0" name="to" type="Vector3" />
+ <param index="1" name="axis" type="Vector3" />
<description>
- Returns the signed angle to the given vector, in radians. The sign of the angle is positive in a counter-clockwise direction and negative in a clockwise direction when viewed from the side specified by the [code]axis[/code].
+ Returns the signed angle to the given vector, in radians. The sign of the angle is positive in a counter-clockwise direction and negative in a clockwise direction when viewed from the side specified by the [param axis].
</description>
</method>
<method name="slerp" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="to" type="Vector3" />
- <argument index="1" name="weight" type="float" />
+ <param index="0" name="to" type="Vector3" />
+ <param index="1" name="weight" type="float" />
<description>
- Returns the result of spherical linear interpolation between this vector and [code]to[/code], by amount [code]weight[/code]. [code]weight[/code] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ Returns the result of spherical linear interpolation between this vector and [param to], by amount [param weight]. [param weight] is on the range of 0.0 to 1.0, representing the amount of interpolation.
This method also handles interpolating the lengths if the input vectors have different lengths. For the special case of one or both input vectors having zero length, this method behaves like [method lerp].
</description>
</method>
<method name="slide" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="n" type="Vector3" />
+ <param index="0" name="n" type="Vector3" />
<description>
Returns this vector slid along a plane defined by the given normal.
</description>
</method>
<method name="snapped" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="step" type="Vector3" />
+ <param index="0" name="step" type="Vector3" />
<description>
- Returns this vector with each component snapped to the nearest multiple of [code]step[/code]. This can also be used to round to an arbitrary number of decimals.
+ Returns this vector with each component snapped to the nearest multiple of [param step]. This can also be used to round to an arbitrary number of decimals.
</description>
</method>
</methods>
@@ -370,7 +384,7 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="Vector3" />
+ <param index="0" name="right" type="Vector3" />
<description>
Returns [code]true[/code] if the vectors are not equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
@@ -378,28 +392,28 @@
</operator>
<operator name="operator *">
<return type="Vector3" />
- <argument index="0" name="right" type="Basis" />
+ <param index="0" name="right" type="Basis" />
<description>
Inversely transforms (multiplies) the [Vector3] by the given [Basis] matrix.
</description>
</operator>
<operator name="operator *">
<return type="Vector3" />
- <argument index="0" name="right" type="Quaternion" />
+ <param index="0" name="right" type="Quaternion" />
<description>
Inversely transforms (multiplies) the [Vector3] by the given [Quaternion].
</description>
</operator>
<operator name="operator *">
<return type="Vector3" />
- <argument index="0" name="right" type="Transform3D" />
+ <param index="0" name="right" type="Transform3D" />
<description>
Inversely transforms (multiplies) the [Vector3] by the given [Transform3D] transformation matrix.
</description>
</operator>
<operator name="operator *">
<return type="Vector3" />
- <argument index="0" name="right" type="Vector3" />
+ <param index="0" name="right" type="Vector3" />
<description>
Multiplies each component of the [Vector3] by the components of the given [Vector3].
[codeblock]
@@ -409,21 +423,21 @@
</operator>
<operator name="operator *">
<return type="Vector3" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Multiplies each component of the [Vector3] by the given [float].
</description>
</operator>
<operator name="operator *">
<return type="Vector3" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Multiplies each component of the [Vector3] by the given [int].
</description>
</operator>
<operator name="operator +">
<return type="Vector3" />
- <argument index="0" name="right" type="Vector3" />
+ <param index="0" name="right" type="Vector3" />
<description>
Adds each component of the [Vector3] by the components of the given [Vector3].
[codeblock]
@@ -433,7 +447,7 @@
</operator>
<operator name="operator -">
<return type="Vector3" />
- <argument index="0" name="right" type="Vector3" />
+ <param index="0" name="right" type="Vector3" />
<description>
Subtracts each component of the [Vector3] by the components of the given [Vector3].
[codeblock]
@@ -443,7 +457,7 @@
</operator>
<operator name="operator /">
<return type="Vector3" />
- <argument index="0" name="right" type="Vector3" />
+ <param index="0" name="right" type="Vector3" />
<description>
Divides each component of the [Vector3] by the components of the given [Vector3].
[codeblock]
@@ -453,35 +467,35 @@
</operator>
<operator name="operator /">
<return type="Vector3" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Divides each component of the [Vector3] by the given [float].
</description>
</operator>
<operator name="operator /">
<return type="Vector3" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Divides each component of the [Vector3] by the given [int].
</description>
</operator>
<operator name="operator &lt;">
<return type="bool" />
- <argument index="0" name="right" type="Vector3" />
+ <param index="0" name="right" type="Vector3" />
<description>
- Compares two [Vector3] vectors by first checking if the X value of the left vector is less than the X value of the [code]right[/code] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, and then with the Z values. This operator is useful for sorting vectors.
+ Compares two [Vector3] vectors by first checking if the X value of the left vector is less than the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, and then with the Z values. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator &lt;=">
<return type="bool" />
- <argument index="0" name="right" type="Vector3" />
+ <param index="0" name="right" type="Vector3" />
<description>
- Compares two [Vector3] vectors by first checking if the X value of the left vector is less than or equal to the X value of the [code]right[/code] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, and then with the Z values. This operator is useful for sorting vectors.
+ Compares two [Vector3] vectors by first checking if the X value of the left vector is less than or equal to the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, and then with the Z values. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="Vector3" />
+ <param index="0" name="right" type="Vector3" />
<description>
Returns [code]true[/code] if the vectors are exactly equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
@@ -489,23 +503,23 @@
</operator>
<operator name="operator &gt;">
<return type="bool" />
- <argument index="0" name="right" type="Vector3" />
+ <param index="0" name="right" type="Vector3" />
<description>
- Compares two [Vector3] vectors by first checking if the X value of the left vector is greater than the X value of the [code]right[/code] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, and then with the Z values. This operator is useful for sorting vectors.
+ Compares two [Vector3] vectors by first checking if the X value of the left vector is greater than the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, and then with the Z values. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator &gt;=">
<return type="bool" />
- <argument index="0" name="right" type="Vector3" />
+ <param index="0" name="right" type="Vector3" />
<description>
- Compares two [Vector3] vectors by first checking if the X value of the left vector is greater than or equal to the X value of the [code]right[/code] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, and then with the Z values. This operator is useful for sorting vectors.
+ Compares two [Vector3] vectors by first checking if the X value of the left vector is greater than or equal to the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, and then with the Z values. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator []">
<return type="float" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Access vector components using their index. [code]v[0][/code] is equivalent to [code]v.x[/code], [code]v[1][/code] is equivalent to [code]v.y[/code], and [code]v[2][/code] is equivalent to [code]v.z[/code].
+ Access vector components using their [param index]. [code]v[0][/code] is equivalent to [code]v.x[/code], [code]v[1][/code] is equivalent to [code]v.y[/code], and [code]v[2][/code] is equivalent to [code]v.z[/code].
</description>
</operator>
<operator name="operator unary+">
diff --git a/doc/classes/Vector3i.xml b/doc/classes/Vector3i.xml
index ebb518792f..1c2a033f7a 100644
--- a/doc/classes/Vector3i.xml
+++ b/doc/classes/Vector3i.xml
@@ -22,23 +22,23 @@
</constructor>
<constructor name="Vector3i">
<return type="Vector3i" />
- <argument index="0" name="from" type="Vector3i" />
+ <param index="0" name="from" type="Vector3i" />
<description>
Constructs a [Vector3i] as a copy of the given [Vector3i].
</description>
</constructor>
<constructor name="Vector3i">
<return type="Vector3i" />
- <argument index="0" name="from" type="Vector3" />
+ <param index="0" name="from" type="Vector3" />
<description>
Constructs a new [Vector3i] from [Vector3]. The floating point coordinates will be truncated.
</description>
</constructor>
<constructor name="Vector3i">
<return type="Vector3i" />
- <argument index="0" name="x" type="int" />
- <argument index="1" name="y" type="int" />
- <argument index="2" name="z" type="int" />
+ <param index="0" name="x" type="int" />
+ <param index="1" name="y" type="int" />
+ <param index="2" name="z" type="int" />
<description>
Returns a [Vector3i] with the given components.
</description>
@@ -53,10 +53,10 @@
</method>
<method name="clamp" qualifiers="const">
<return type="Vector3i" />
- <argument index="0" name="min" type="Vector3i" />
- <argument index="1" name="max" type="Vector3i" />
+ <param index="0" name="min" type="Vector3i" />
+ <param index="1" name="max" type="Vector3i" />
<description>
- Returns a new vector with all components clamped between the components of [code]min[/code] and [code]max[/code], by running [method @GlobalScope.clamp] on each component.
+ Returns a new vector with all components clamped between the components of [param min] and [param max], by running [method @GlobalScope.clamp] on each component.
</description>
</method>
<method name="length" qualifiers="const">
@@ -140,14 +140,14 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="Vector3i" />
+ <param index="0" name="right" type="Vector3i" />
<description>
Returns [code]true[/code] if the vectors are not equal.
</description>
</operator>
<operator name="operator %">
<return type="Vector3i" />
- <argument index="0" name="right" type="Vector3i" />
+ <param index="0" name="right" type="Vector3i" />
<description>
Gets the remainder of each component of the [Vector3i] with the components of the given [Vector3i]. This operation uses truncated division, which is often not desired as it does not work well with negative numbers. Consider using [method @GlobalScope.posmod] instead if you want to handle negative numbers.
[codeblock]
@@ -157,7 +157,7 @@
</operator>
<operator name="operator %">
<return type="Vector3i" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Gets the remainder of each component of the [Vector3i] with the the given [int]. This operation uses truncated division, which is often not desired as it does not work well with negative numbers. Consider using [method @GlobalScope.posmod] instead if you want to handle negative numbers.
[codeblock]
@@ -167,7 +167,7 @@
</operator>
<operator name="operator *">
<return type="Vector3i" />
- <argument index="0" name="right" type="Vector3i" />
+ <param index="0" name="right" type="Vector3i" />
<description>
Multiplies each component of the [Vector3i] by the components of the given [Vector3i].
[codeblock]
@@ -177,7 +177,7 @@
</operator>
<operator name="operator *">
<return type="Vector3" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Multiplies each component of the [Vector3i] by the given [float]. Returns a [Vector3].
[codeblock]
@@ -187,14 +187,14 @@
</operator>
<operator name="operator *">
<return type="Vector3i" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Multiplies each component of the [Vector3i] by the given [int].
</description>
</operator>
<operator name="operator +">
<return type="Vector3i" />
- <argument index="0" name="right" type="Vector3i" />
+ <param index="0" name="right" type="Vector3i" />
<description>
Adds each component of the [Vector3i] by the components of the given [Vector3i].
[codeblock]
@@ -204,7 +204,7 @@
</operator>
<operator name="operator -">
<return type="Vector3i" />
- <argument index="0" name="right" type="Vector3i" />
+ <param index="0" name="right" type="Vector3i" />
<description>
Subtracts each component of the [Vector3i] by the components of the given [Vector3i].
[codeblock]
@@ -214,7 +214,7 @@
</operator>
<operator name="operator /">
<return type="Vector3i" />
- <argument index="0" name="right" type="Vector3i" />
+ <param index="0" name="right" type="Vector3i" />
<description>
Divides each component of the [Vector3i] by the components of the given [Vector3i].
[codeblock]
@@ -224,7 +224,7 @@
</operator>
<operator name="operator /">
<return type="Vector3" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Divides each component of the [Vector3i] by the given [float]. Returns a [Vector3].
[codeblock]
@@ -234,51 +234,51 @@
</operator>
<operator name="operator /">
<return type="Vector3i" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Divides each component of the [Vector3i] by the given [int].
</description>
</operator>
<operator name="operator &lt;">
<return type="bool" />
- <argument index="0" name="right" type="Vector3i" />
+ <param index="0" name="right" type="Vector3i" />
<description>
- Compares two [Vector3i] vectors by first checking if the X value of the left vector is less than the X value of the [code]right[/code] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, and then with the Z values. This operator is useful for sorting vectors.
+ Compares two [Vector3i] vectors by first checking if the X value of the left vector is less than the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, and then with the Z values. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator &lt;=">
<return type="bool" />
- <argument index="0" name="right" type="Vector3i" />
+ <param index="0" name="right" type="Vector3i" />
<description>
- Compares two [Vector3i] vectors by first checking if the X value of the left vector is less than or equal to the X value of the [code]right[/code] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, and then with the Z values. This operator is useful for sorting vectors.
+ Compares two [Vector3i] vectors by first checking if the X value of the left vector is less than or equal to the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, and then with the Z values. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="Vector3i" />
+ <param index="0" name="right" type="Vector3i" />
<description>
Returns [code]true[/code] if the vectors are equal.
</description>
</operator>
<operator name="operator &gt;">
<return type="bool" />
- <argument index="0" name="right" type="Vector3i" />
+ <param index="0" name="right" type="Vector3i" />
<description>
- Compares two [Vector3i] vectors by first checking if the X value of the left vector is greater than the X value of the [code]right[/code] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, and then with the Z values. This operator is useful for sorting vectors.
+ Compares two [Vector3i] vectors by first checking if the X value of the left vector is greater than the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, and then with the Z values. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator &gt;=">
<return type="bool" />
- <argument index="0" name="right" type="Vector3i" />
+ <param index="0" name="right" type="Vector3i" />
<description>
- Compares two [Vector3i] vectors by first checking if the X value of the left vector is greater than or equal to the X value of the [code]right[/code] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, and then with the Z values. This operator is useful for sorting vectors.
+ Compares two [Vector3i] vectors by first checking if the X value of the left vector is greater than or equal to the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, and then with the Z values. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator []">
<return type="int" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Access vector components using their index. [code]v[0][/code] is equivalent to [code]v.x[/code], [code]v[1][/code] is equivalent to [code]v.y[/code], and [code]v[2][/code] is equivalent to [code]v.z[/code].
+ Access vector components using their [param index]. [code]v[0][/code] is equivalent to [code]v.x[/code], [code]v[1][/code] is equivalent to [code]v.y[/code], and [code]v[2][/code] is equivalent to [code]v.z[/code].
</description>
</operator>
<operator name="operator unary+">
diff --git a/doc/classes/Vector4.xml b/doc/classes/Vector4.xml
index da0df2672e..b9f509cfe7 100644
--- a/doc/classes/Vector4.xml
+++ b/doc/classes/Vector4.xml
@@ -19,24 +19,24 @@
</constructor>
<constructor name="Vector4">
<return type="Vector4" />
- <argument index="0" name="from" type="Vector4" />
+ <param index="0" name="from" type="Vector4" />
<description>
Constructs a [Vector4] as a copy of the given [Vector4].
</description>
</constructor>
<constructor name="Vector4">
<return type="Vector4" />
- <argument index="0" name="from" type="Vector4i" />
+ <param index="0" name="from" type="Vector4i" />
<description>
Constructs a new [Vector4] from [Vector4i].
</description>
</constructor>
<constructor name="Vector4">
<return type="Vector4" />
- <argument index="0" name="x" type="float" />
- <argument index="1" name="y" type="float" />
- <argument index="2" name="z" type="float" />
- <argument index="3" name="w" type="float" />
+ <param index="0" name="x" type="float" />
+ <param index="1" name="y" type="float" />
+ <param index="2" name="z" type="float" />
+ <param index="3" name="w" type="float" />
<description>
Returns a [Vector4] with the given components.
</description>
@@ -57,17 +57,63 @@
</method>
<method name="clamp" qualifiers="const">
<return type="Vector4" />
- <argument index="0" name="min" type="Vector4" />
- <argument index="1" name="max" type="Vector4" />
+ <param index="0" name="min" type="Vector4" />
+ <param index="1" name="max" type="Vector4" />
<description>
- Returns a new vector with all components clamped between the components of [code]min[/code] and [code]max[/code], by running [method @GlobalScope.clamp] on each component.
+ Returns a new vector with all components clamped between the components of [param min] and [param max], by running [method @GlobalScope.clamp] on each component.
+ </description>
+ </method>
+ <method name="cubic_interpolate" qualifiers="const">
+ <return type="Vector4" />
+ <param index="0" name="b" type="Vector4" />
+ <param index="1" name="pre_a" type="Vector4" />
+ <param index="2" name="post_b" type="Vector4" />
+ <param index="3" name="weight" type="float" />
+ <description>
+ Performs a cubic interpolation between this vector and [param b] using [param pre_a] and [param post_b] as handles, and returns the result at position [param weight]. [param weight] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ </description>
+ </method>
+ <method name="cubic_interpolate_in_time" qualifiers="const">
+ <return type="Vector4" />
+ <param index="0" name="b" type="Vector4" />
+ <param index="1" name="pre_a" type="Vector4" />
+ <param index="2" name="post_b" type="Vector4" />
+ <param index="3" name="weight" type="float" />
+ <param index="4" name="b_t" type="float" />
+ <param index="5" name="pre_a_t" type="float" />
+ <param index="6" name="post_b_t" type="float" />
+ <description>
+ Performs a cubic interpolation between this vector and [param b] using [param pre_a] and [param post_b] as handles, and returns the result at position [param weight]. [param weight] is on the range of 0.0 to 1.0, representing the amount of interpolation.
+ It can perform smoother interpolation than [code]cubic_interpolate()[/code] by the time values.
+ </description>
+ </method>
+ <method name="direction_to" qualifiers="const">
+ <return type="Vector4" />
+ <param index="0" name="to" type="Vector4" />
+ <description>
+ Returns the normalized vector pointing from this vector to [param to]. This is equivalent to using [code](b - a).normalized()[/code].
+ </description>
+ </method>
+ <method name="distance_squared_to" qualifiers="const">
+ <return type="float" />
+ <param index="0" name="to" type="Vector4" />
+ <description>
+ Returns the squared distance between this vector and [param to].
+ This method runs faster than [method distance_to], so prefer it if you need to compare vectors or need the squared distance for some formula.
+ </description>
+ </method>
+ <method name="distance_to" qualifiers="const">
+ <return type="float" />
+ <param index="0" name="to" type="Vector4" />
+ <description>
+ Returns the distance between this vector and [param to].
</description>
</method>
<method name="dot" qualifiers="const">
<return type="float" />
- <argument index="0" name="with" type="Vector4" />
+ <param index="0" name="with" type="Vector4" />
<description>
- Returns the dot product of this vector and [code]with[/code].
+ Returns the dot product of this vector and [param with].
</description>
</method>
<method name="floor" qualifiers="const">
@@ -84,9 +130,9 @@
</method>
<method name="is_equal_approx" qualifiers="const">
<return type="bool" />
- <argument index="0" name="with" type="Vector4" />
+ <param index="0" name="with" type="Vector4" />
<description>
- Returns [code]true[/code] if this vector and [code]v[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
+ Returns [code]true[/code] if this vector and [param with] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component.
</description>
</method>
<method name="is_normalized" qualifiers="const">
@@ -109,10 +155,10 @@
</method>
<method name="lerp" qualifiers="const">
<return type="Vector4" />
- <argument index="0" name="to" type="Vector4" />
- <argument index="1" name="weight" type="float" />
+ <param index="0" name="to" type="Vector4" />
+ <param index="1" name="weight" type="float" />
<description>
- Returns the result of the linear interpolation between this vector and [code]to[/code] by amount [code]weight[/code]. [code]weight[/code] is on the range of [code]0.0[/code] to [code]1.0[/code], representing the amount of interpolation.
+ Returns the result of the linear interpolation between this vector and [param to] by amount [param weight]. [param weight] is on the range of [code]0.0[/code] to [code]1.0[/code], representing the amount of interpolation.
</description>
</method>
<method name="max_axis_index" qualifiers="const">
@@ -133,6 +179,20 @@
Returns the vector scaled to unit length. Equivalent to [code]v / v.length()[/code].
</description>
</method>
+ <method name="posmod" qualifiers="const">
+ <return type="Vector4" />
+ <param index="0" name="mod" type="float" />
+ <description>
+ Returns a vector composed of the [method @GlobalScope.fposmod] of this vector's components and [param mod].
+ </description>
+ </method>
+ <method name="posmodv" qualifiers="const">
+ <return type="Vector4" />
+ <param index="0" name="modv" type="Vector4" />
+ <description>
+ Returns a vector composed of the [method @GlobalScope.fposmod] of this vector's components and [param modv]'s components.
+ </description>
+ </method>
<method name="round" qualifiers="const">
<return type="Vector4" />
<description>
@@ -145,6 +205,13 @@
Returns a new vector with each component set to one or negative one, depending on the signs of the components, or zero if the component is zero, by calling [method @GlobalScope.sign] on each component.
</description>
</method>
+ <method name="snapped" qualifiers="const">
+ <return type="Vector4" />
+ <param index="0" name="step" type="Vector4" />
+ <description>
+ Returns this vector with each component snapped to the nearest multiple of [param step]. This can also be used to round to an arbitrary number of decimals.
+ </description>
+ </method>
</methods>
<members>
<member name="w" type="float" setter="" getter="" default="0.0">
@@ -186,7 +253,7 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="Vector4" />
+ <param index="0" name="right" type="Vector4" />
<description>
Returns [code]true[/code] if the vectors are not equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
@@ -194,14 +261,14 @@
</operator>
<operator name="operator *">
<return type="Vector4" />
- <argument index="0" name="right" type="Projection" />
+ <param index="0" name="right" type="Projection" />
<description>
Inversely transforms (multiplies) the [Vector4] by the given [Projection] matrix.
</description>
</operator>
<operator name="operator *">
<return type="Vector4" />
- <argument index="0" name="right" type="Vector4" />
+ <param index="0" name="right" type="Vector4" />
<description>
Multiplies each component of the [Vector4] by the components of the given [Vector4].
[codeblock]
@@ -211,7 +278,7 @@
</operator>
<operator name="operator *">
<return type="Vector4" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Multiplies each component of the [Vector4] by the given [float].
[codeblock]
@@ -221,14 +288,14 @@
</operator>
<operator name="operator *">
<return type="Vector4" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Multiplies each component of the [Vector4] by the given [int].
</description>
</operator>
<operator name="operator +">
<return type="Vector4" />
- <argument index="0" name="right" type="Vector4" />
+ <param index="0" name="right" type="Vector4" />
<description>
Adds each component of the [Vector4] by the components of the given [Vector4].
[codeblock]
@@ -238,7 +305,7 @@
</operator>
<operator name="operator -">
<return type="Vector4" />
- <argument index="0" name="right" type="Vector4" />
+ <param index="0" name="right" type="Vector4" />
<description>
Subtracts each component of the [Vector4] by the components of the given [Vector4].
[codeblock]
@@ -248,7 +315,7 @@
</operator>
<operator name="operator /">
<return type="Vector4" />
- <argument index="0" name="right" type="Vector4" />
+ <param index="0" name="right" type="Vector4" />
<description>
Divides each component of the [Vector4] by the components of the given [Vector4].
[codeblock]
@@ -258,7 +325,7 @@
</operator>
<operator name="operator /">
<return type="Vector4" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Divides each component of the [Vector4] by the given [float].
[codeblock]
@@ -268,28 +335,28 @@
</operator>
<operator name="operator /">
<return type="Vector4" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Divides each component of the [Vector4] by the given [int].
</description>
</operator>
<operator name="operator &lt;">
<return type="bool" />
- <argument index="0" name="right" type="Vector4" />
+ <param index="0" name="right" type="Vector4" />
<description>
- Compares two [Vector4] vectors by first checking if the X value of the left vector is less than the X value of the [code]right[/code] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, Z values of the two vectors, and then with the W values. This operator is useful for sorting vectors.
+ Compares two [Vector4] vectors by first checking if the X value of the left vector is less than the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, Z values of the two vectors, and then with the W values. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator &lt;=">
<return type="bool" />
- <argument index="0" name="right" type="Vector4" />
+ <param index="0" name="right" type="Vector4" />
<description>
- Compares two [Vector4] vectors by first checking if the X value of the left vector is less than or equal to the X value of the [code]right[/code] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, Z values of the two vectors, and then with the W values. This operator is useful for sorting vectors.
+ Compares two [Vector4] vectors by first checking if the X value of the left vector is less than or equal to the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, Z values of the two vectors, and then with the W values. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="Vector4" />
+ <param index="0" name="right" type="Vector4" />
<description>
Returns [code]true[/code] if the vectors are exactly equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method is_equal_approx] instead, which is more reliable.
@@ -297,23 +364,23 @@
</operator>
<operator name="operator &gt;">
<return type="bool" />
- <argument index="0" name="right" type="Vector4" />
+ <param index="0" name="right" type="Vector4" />
<description>
- Compares two [Vector4] vectors by first checking if the X value of the left vector is greater than the X value of the [code]right[/code] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, Z values of the two vectors, and then with the W values. This operator is useful for sorting vectors.
+ Compares two [Vector4] vectors by first checking if the X value of the left vector is greater than the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, Z values of the two vectors, and then with the W values. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator &gt;=">
<return type="bool" />
- <argument index="0" name="right" type="Vector4" />
+ <param index="0" name="right" type="Vector4" />
<description>
- Access vector components using their index. [code]v[0][/code] is equivalent to [code]v.x[/code], [code]v[1][/code] is equivalent to [code]v.y[/code], and [code]v[2][/code] is equivalent to [code]v.z[/code].
+ Compares two [Vector4] vectors by first checking if the X value of the left vector is greater than or equal to the X value of the [param right] vector. If the X values are exactly equal, then it repeats this check with the Y values of the two vectors, Z values of the two vectors, and then with the W values. This operator is useful for sorting vectors.
</description>
</operator>
<operator name="operator []">
<return type="float" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Access vector components using their index. [code]v[0][/code] is equivalent to [code]v.x[/code], [code]v[1][/code] is equivalent to [code]v.y[/code], [code]v[2][/code] is equivalent to [code]v.z[/code], and [code]v[3][/code] is equivalent to [code]v.w[/code].
+ Access vector components using their [param index]. [code]v[0][/code] is equivalent to [code]v.x[/code], [code]v[1][/code] is equivalent to [code]v.y[/code], [code]v[2][/code] is equivalent to [code]v.z[/code], and [code]v[3][/code] is equivalent to [code]v.w[/code].
</description>
</operator>
<operator name="operator unary+">
diff --git a/doc/classes/Vector4i.xml b/doc/classes/Vector4i.xml
index 6acce12e9f..9a36c3c4fa 100644
--- a/doc/classes/Vector4i.xml
+++ b/doc/classes/Vector4i.xml
@@ -14,22 +14,22 @@
</constructor>
<constructor name="Vector4i">
<return type="Vector4i" />
- <argument index="0" name="from" type="Vector4i" />
+ <param index="0" name="from" type="Vector4i" />
<description>
</description>
</constructor>
<constructor name="Vector4i">
<return type="Vector4i" />
- <argument index="0" name="from" type="Vector4" />
+ <param index="0" name="from" type="Vector4" />
<description>
</description>
</constructor>
<constructor name="Vector4i">
<return type="Vector4i" />
- <argument index="0" name="x" type="int" />
- <argument index="1" name="y" type="int" />
- <argument index="2" name="z" type="int" />
- <argument index="3" name="w" type="int" />
+ <param index="0" name="x" type="int" />
+ <param index="1" name="y" type="int" />
+ <param index="2" name="z" type="int" />
+ <param index="3" name="w" type="int" />
<description>
</description>
</constructor>
@@ -42,8 +42,8 @@
</method>
<method name="clamp" qualifiers="const">
<return type="Vector4i" />
- <argument index="0" name="min" type="Vector4i" />
- <argument index="1" name="max" type="Vector4i" />
+ <param index="0" name="min" type="Vector4i" />
+ <param index="1" name="max" type="Vector4i" />
<description>
</description>
</method>
@@ -100,103 +100,103 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="Vector4i" />
+ <param index="0" name="right" type="Vector4i" />
<description>
</description>
</operator>
<operator name="operator %">
<return type="Vector4i" />
- <argument index="0" name="right" type="Vector4i" />
+ <param index="0" name="right" type="Vector4i" />
<description>
</description>
</operator>
<operator name="operator %">
<return type="Vector4i" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
</description>
</operator>
<operator name="operator *">
<return type="Vector4i" />
- <argument index="0" name="right" type="Vector4i" />
+ <param index="0" name="right" type="Vector4i" />
<description>
</description>
</operator>
<operator name="operator *">
<return type="Vector4" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
</description>
</operator>
<operator name="operator *">
<return type="Vector4i" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
</description>
</operator>
<operator name="operator +">
<return type="Vector4i" />
- <argument index="0" name="right" type="Vector4i" />
+ <param index="0" name="right" type="Vector4i" />
<description>
</description>
</operator>
<operator name="operator -">
<return type="Vector4i" />
- <argument index="0" name="right" type="Vector4i" />
+ <param index="0" name="right" type="Vector4i" />
<description>
</description>
</operator>
<operator name="operator /">
<return type="Vector4i" />
- <argument index="0" name="right" type="Vector4i" />
+ <param index="0" name="right" type="Vector4i" />
<description>
</description>
</operator>
<operator name="operator /">
<return type="Vector4" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
</description>
</operator>
<operator name="operator /">
<return type="Vector4i" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
</description>
</operator>
<operator name="operator &lt;">
<return type="bool" />
- <argument index="0" name="right" type="Vector4i" />
+ <param index="0" name="right" type="Vector4i" />
<description>
</description>
</operator>
<operator name="operator &lt;=">
<return type="bool" />
- <argument index="0" name="right" type="Vector4i" />
+ <param index="0" name="right" type="Vector4i" />
<description>
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="Vector4i" />
+ <param index="0" name="right" type="Vector4i" />
<description>
</description>
</operator>
<operator name="operator &gt;">
<return type="bool" />
- <argument index="0" name="right" type="Vector4i" />
+ <param index="0" name="right" type="Vector4i" />
<description>
</description>
</operator>
<operator name="operator &gt;=">
<return type="bool" />
- <argument index="0" name="right" type="Vector4i" />
+ <param index="0" name="right" type="Vector4i" />
<description>
</description>
</operator>
<operator name="operator []">
<return type="int" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
</description>
</operator>
diff --git a/doc/classes/VehicleBody3D.xml b/doc/classes/VehicleBody3D.xml
index 08309a8ecc..e1689133de 100644
--- a/doc/classes/VehicleBody3D.xml
+++ b/doc/classes/VehicleBody3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VehicleBody3D" inherits="RigidDynamicBody3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VehicleBody3D" inherits="RigidBody3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Physics body that simulates the behavior of a car.
</brief_description>
@@ -13,14 +13,14 @@
</tutorials>
<members>
<member name="brake" type="float" setter="set_brake" getter="get_brake" default="0.0">
- Slows down the vehicle by applying a braking force. The vehicle is only slowed down if the wheels are in contact with a surface. The force you need to apply to adequately slow down your vehicle depends on the [member RigidDynamicBody3D.mass] of the vehicle. For a vehicle with a mass set to 1000, try a value in the 25 - 30 range for hard braking.
+ Slows down the vehicle by applying a braking force. The vehicle is only slowed down if the wheels are in contact with a surface. The force you need to apply to adequately slow down your vehicle depends on the [member RigidBody3D.mass] of the vehicle. For a vehicle with a mass set to 1000, try a value in the 25 - 30 range for hard braking.
</member>
<member name="engine_force" type="float" setter="set_engine_force" getter="get_engine_force" default="0.0">
- Accelerates the vehicle by applying an engine force. The vehicle is only sped up if the wheels that have [member VehicleWheel3D.use_as_traction] set to [code]true[/code] and are in contact with a surface. The [member RigidDynamicBody3D.mass] of the vehicle has an effect on the acceleration of the vehicle. For a vehicle with a mass set to 1000, try a value in the 25 - 50 range for acceleration.
+ Accelerates the vehicle by applying an engine force. The vehicle is only sped up if the wheels that have [member VehicleWheel3D.use_as_traction] set to [code]true[/code] and are in contact with a surface. The [member RigidBody3D.mass] of the vehicle has an effect on the acceleration of the vehicle. For a vehicle with a mass set to 1000, try a value in the 25 - 50 range for acceleration.
[b]Note:[/b] The simulation does not take the effect of gears into account, you will need to add logic for this if you wish to simulate gears.
A negative value will result in the vehicle reversing.
</member>
- <member name="mass" type="float" setter="set_mass" getter="get_mass" overrides="RigidDynamicBody3D" default="40.0" />
+ <member name="mass" type="float" setter="set_mass" getter="get_mass" overrides="RigidBody3D" default="40.0" />
<member name="steering" type="float" setter="set_steering" getter="get_steering" default="0.0">
The steering angle for the vehicle, in radians. Setting this to a non-zero value will result in the vehicle turning when it's moving. Wheels that have [member VehicleWheel3D.use_as_steering] set to [code]true[/code] will automatically be rotated.
</member>
diff --git a/doc/classes/VehicleWheel3D.xml b/doc/classes/VehicleWheel3D.xml
index ac126f824e..827c7e8f57 100644
--- a/doc/classes/VehicleWheel3D.xml
+++ b/doc/classes/VehicleWheel3D.xml
@@ -39,7 +39,7 @@
</methods>
<members>
<member name="brake" type="float" setter="set_brake" getter="get_brake" default="0.0">
- Slows down the wheel by applying a braking force. The wheel is only slowed down if it is in contact with a surface. The force you need to apply to adequately slow down your vehicle depends on the [member RigidDynamicBody3D.mass] of the vehicle. For a vehicle with a mass set to 1000, try a value in the 25 - 30 range for hard braking.
+ Slows down the wheel by applying a braking force. The wheel is only slowed down if it is in contact with a surface. The force you need to apply to adequately slow down your vehicle depends on the [member RigidBody3D.mass] of the vehicle. For a vehicle with a mass set to 1000, try a value in the 25 - 30 range for hard braking.
</member>
<member name="damping_compression" type="float" setter="set_damping_compression" getter="get_damping_compression" default="0.83">
The damping applied to the spring when the spring is being compressed. This value should be between 0.0 (no damping) and 1.0. A value of 0.0 means the car will keep bouncing as the spring keeps its energy. A good value for this is around 0.3 for a normal car, 0.5 for a race car.
@@ -48,7 +48,7 @@
The damping applied to the spring when relaxing. This value should be between 0.0 (no damping) and 1.0. This value should always be slightly higher than the [member damping_compression] property. For a [member damping_compression] value of 0.3, try a relaxation value of 0.5.
</member>
<member name="engine_force" type="float" setter="set_engine_force" getter="get_engine_force" default="0.0">
- Accelerates the wheel by applying an engine force. The wheel is only sped up if it is in contact with a surface. The [member RigidDynamicBody3D.mass] of the vehicle has an effect on the acceleration of the vehicle. For a vehicle with a mass set to 1000, try a value in the 25 - 50 range for acceleration.
+ Accelerates the wheel by applying an engine force. The wheel is only sped up if it is in contact with a surface. The [member RigidBody3D.mass] of the vehicle has an effect on the acceleration of the vehicle. For a vehicle with a mass set to 1000, try a value in the 25 - 50 range for acceleration.
[b]Note:[/b] The simulation does not take the effect of gears into account, you will need to add logic for this if you wish to simulate gears.
A negative value will result in the wheel reversing.
</member>
@@ -56,7 +56,7 @@
The steering angle for the wheel, in radians. Setting this to a non-zero value will result in the vehicle turning when it's moving.
</member>
<member name="suspension_max_force" type="float" setter="set_suspension_max_force" getter="get_suspension_max_force" default="6000.0">
- The maximum force the spring can resist. This value should be higher than a quarter of the [member RigidDynamicBody3D.mass] of the [VehicleBody3D] or the spring will not carry the weight of the vehicle. Good results are often obtained by a value that is about 3× to 4× this number.
+ The maximum force the spring can resist. This value should be higher than a quarter of the [member RigidBody3D.mass] of the [VehicleBody3D] or the spring will not carry the weight of the vehicle. Good results are often obtained by a value that is about 3× to 4× this number.
</member>
<member name="suspension_stiffness" type="float" setter="set_suspension_stiffness" getter="get_suspension_stiffness" default="5.88">
This value defines the stiffness of the suspension. Use a value lower than 50 for an off-road car, a value between 50 and 100 for a race car and try something around 200 for something like a Formula 1 car.
diff --git a/doc/classes/VelocityTracker3D.xml b/doc/classes/VelocityTracker3D.xml
deleted file mode 100644
index 45ded446eb..0000000000
--- a/doc/classes/VelocityTracker3D.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VelocityTracker3D" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_tracked_linear_velocity" qualifiers="const">
- <return type="Vector3" />
- <description>
- </description>
- </method>
- <method name="reset">
- <return type="void" />
- <argument index="0" name="position" type="Vector3" />
- <description>
- </description>
- </method>
- <method name="update_position">
- <return type="void" />
- <argument index="0" name="position" type="Vector3" />
- <description>
- </description>
- </method>
- </methods>
- <members>
- <member name="track_physics_step" type="bool" setter="set_track_physics_step" getter="is_tracking_physics_step" default="false">
- </member>
- </members>
-</class>
diff --git a/doc/classes/VideoStreamPlayer.xml b/doc/classes/VideoStreamPlayer.xml
index f6594ff9e7..2774f1fb42 100644
--- a/doc/classes/VideoStreamPlayer.xml
+++ b/doc/classes/VideoStreamPlayer.xml
@@ -7,7 +7,7 @@
Control node for playing video streams using [VideoStream] resources.
Supported video formats are [url=https://www.theora.org/]Ogg Theora[/url] ([code].ogv[/code], [VideoStreamTheora]) and any format exposed via a GDExtension plugin.
[b]Note:[/b] Due to a bug, VideoStreamPlayer does not support localization remapping yet.
- [b]Warning:[/b] On HTML5, video playback [i]will[/i] perform poorly due to missing architecture-specific assembly optimizations.
+ [b]Warning:[/b] On Web, video playback [i]will[/i] perform poorly due to missing architecture-specific assembly optimizations.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index 0808a8f1cf..0071834ccd 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -59,15 +59,15 @@
</method>
<method name="get_positional_shadow_atlas_quadrant_subdiv" qualifiers="const">
<return type="int" enum="Viewport.PositionalShadowAtlasQuadrantSubdiv" />
- <argument index="0" name="quadrant" type="int" />
+ <param index="0" name="quadrant" type="int" />
<description>
Returns the [enum PositionalShadowAtlasQuadrantSubdiv] of the specified quadrant.
</description>
</method>
<method name="get_render_info">
<return type="int" />
- <argument index="0" name="type" type="int" enum="Viewport.RenderInfoType" />
- <argument index="1" name="info" type="int" enum="Viewport.RenderInfo" />
+ <param index="0" name="type" type="int" enum="Viewport.RenderInfoType" />
+ <param index="1" name="info" type="int" enum="Viewport.RenderInfo" />
<description>
</description>
</method>
@@ -133,22 +133,21 @@
</method>
<method name="push_input">
<return type="void" />
- <argument index="0" name="event" type="InputEvent" />
- <argument index="1" name="in_local_coords" type="bool" default="false" />
+ <param index="0" name="event" type="InputEvent" />
+ <param index="1" name="in_local_coords" type="bool" default="false" />
<description>
</description>
</method>
<method name="push_text_input">
<return type="void" />
- <argument index="0" name="text" type="String" />
+ <param index="0" name="text" type="String" />
<description>
- Returns [code]true[/code] if the viewport is currently embedding windows.
</description>
</method>
<method name="push_unhandled_input">
<return type="void" />
- <argument index="0" name="event" type="InputEvent" />
- <argument index="1" name="in_local_coords" type="bool" default="false" />
+ <param index="0" name="event" type="InputEvent" />
+ <param index="1" name="in_local_coords" type="bool" default="false" />
<description>
</description>
</method>
@@ -160,15 +159,15 @@
</method>
<method name="set_positional_shadow_atlas_quadrant_subdiv">
<return type="void" />
- <argument index="0" name="quadrant" type="int" />
- <argument index="1" name="subdiv" type="int" enum="Viewport.PositionalShadowAtlasQuadrantSubdiv" />
+ <param index="0" name="quadrant" type="int" />
+ <param index="1" name="subdiv" type="int" enum="Viewport.PositionalShadowAtlasQuadrantSubdiv" />
<description>
Sets the number of subdivisions to use in the specified quadrant. A higher number of subdivisions allows you to have more shadows in the scene at once, but reduces the quality of the shadows. A good practice is to have quadrants with a varying number of subdivisions and to have as few subdivisions as possible.
</description>
</method>
<method name="warp_mouse">
<return type="void" />
- <argument index="0" name="position" type="Vector2" />
+ <param index="0" name="position" type="Vector2" />
<description>
Moves the mouse pointer to the specified position in this [Viewport] using the coordinate system of this [Viewport].
</description>
@@ -267,8 +266,9 @@
<member name="snap_2d_vertices_to_pixel" type="bool" setter="set_snap_2d_vertices_to_pixel" getter="is_snap_2d_vertices_to_pixel_enabled" default="false">
</member>
<member name="texture_mipmap_bias" type="float" setter="set_texture_mipmap_bias" getter="get_texture_mipmap_bias" default="0.0">
- Affects the final texture sharpness by reading from a lower or higher mipmap (also called "texture LOD bias"). Negative values make mipmapped textures sharper but grainier when viewed at a distance, while positive values make mipmapped textures blurrier (even when up close). To get sharper textures at a distance without introducing too much graininess, set this between [code]-0.75[/code] and [code]0.0[/code]. Enabling temporal antialiasing ([member ProjectSettings.rendering/anti_aliasing/quality/use_taa]) can help reduce the graininess visible when using negative mipmap bias.
- [b]Note:[/b] When the 3D scaling mode is set to FSR 1.0, this value is used to adjust the automatic mipmap bias which is calculated internally based on the scale factor. The formula for this is [code]-log2(1.0 / scale) + mipmap_bias[/code].
+ Affects the final texture sharpness by reading from a lower or higher mipmap (also called "texture LOD bias"). Negative values make mipmapped textures sharper but grainier when viewed at a distance, while positive values make mipmapped textures blurrier (even when up close).
+ Enabling temporal antialiasing ([member use_taa]) will automatically apply a [code]-0.5[/code] offset to this value, while enabling FXAA ([member screen_space_aa]) will automatically apply a [code]-0.25[/code] offset to this value. If both TAA and FXAA are enbled at the same time, an offset of [code]-0.75[/code] is applied to this value.
+ [b]Note:[/b] If [member scaling_3d_scale] is lower than [code]1.0[/code] (exclusive), [member texture_mipmap_bias] is used to adjust the automatic mipmap bias which is calculated internally based on the scale factor. The formula for this is [code]log2(scaling_3d_scale) + mipmap_bias[/code].
To control this property on the root viewport, set the [member ProjectSettings.rendering/textures/default_filters/texture_mipmap_bias] project setting.
</member>
<member name="transparent_bg" type="bool" setter="set_transparent_background" getter="has_transparent_background" default="false">
@@ -302,7 +302,7 @@
</members>
<signals>
<signal name="gui_focus_changed">
- <argument index="0" name="node" type="Control" />
+ <param index="0" name="node" type="Control" />
<description>
Emitted when a Control node grabs keyboard focus.
</description>
diff --git a/doc/classes/VisibleOnScreenEnabler3D.xml b/doc/classes/VisibleOnScreenEnabler3D.xml
index 5e03870005..a3f925ed3a 100644
--- a/doc/classes/VisibleOnScreenEnabler3D.xml
+++ b/doc/classes/VisibleOnScreenEnabler3D.xml
@@ -4,7 +4,7 @@
Enables certain nodes only when approximately visible.
</brief_description>
<description>
- The VisibleOnScreenEnabler3D will disable [RigidDynamicBody3D] and [AnimationPlayer] nodes when they are not visible. It will only affect other nodes within the same scene as the VisibleOnScreenEnabler3D itself.
+ The VisibleOnScreenEnabler3D will disable [RigidBody3D] and [AnimationPlayer] nodes when they are not visible. It will only affect other nodes within the same scene as the VisibleOnScreenEnabler3D itself.
If you just want to receive notifications, use [VisibleOnScreenNotifier3D] instead.
[b]Note:[/b] VisibleOnScreenEnabler3D uses an approximate heuristic for performance reasons. It doesn't take walls and other occlusion into account. The heuristic is an implementation detail and may change in future versions. If you need precise visibility checking, use another method such as adding an [Area3D] node as a child of a [Camera3D] node and/or [method Vector3.dot].
[b]Note:[/b] VisibleOnScreenEnabler3D will not affect nodes added after scene initialization.
diff --git a/doc/classes/VisualInstance3D.xml b/doc/classes/VisualInstance3D.xml
index 2468042850..9574686506 100644
--- a/doc/classes/VisualInstance3D.xml
+++ b/doc/classes/VisualInstance3D.xml
@@ -34,7 +34,7 @@
</method>
<method name="get_layer_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
Returns whether or not the specified layer of the [member layers] is enabled, given a [code]layer_number[/code] between 1 and 20.
</description>
@@ -48,17 +48,17 @@
</method>
<method name="set_base">
<return type="void" />
- <argument index="0" name="base" type="RID" />
+ <param index="0" name="base" type="RID" />
<description>
Sets the resource that is instantiated by this [VisualInstance3D], which changes how the engine handles the [VisualInstance3D] under the hood. Equivalent to [method RenderingServer.instance_set_base].
</description>
</method>
<method name="set_layer_mask_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
- Based on [code]value[/code], enables or disables the specified layer in the [member layers], given a [code]layer_number[/code] between 1 and 20.
+ Based on [param value], enables or disables the specified layer in the [member layers], given a [param layer_number] between 1 and 20.
</description>
</method>
</methods>
diff --git a/doc/classes/VisualShader.xml b/doc/classes/VisualShader.xml
index 64d901cd79..a2089ae2b8 100644
--- a/doc/classes/VisualShader.xml
+++ b/doc/classes/VisualShader.xml
@@ -12,154 +12,154 @@
<methods>
<method name="add_node">
<return type="void" />
- <argument index="0" name="type" type="int" enum="VisualShader.Type" />
- <argument index="1" name="node" type="VisualShaderNode" />
- <argument index="2" name="position" type="Vector2" />
- <argument index="3" name="id" type="int" />
+ <param index="0" name="type" type="int" enum="VisualShader.Type" />
+ <param index="1" name="node" type="VisualShaderNode" />
+ <param index="2" name="position" type="Vector2" />
+ <param index="3" name="id" type="int" />
<description>
- Adds the specified node to the shader.
+ Adds the specified [param node] to the shader.
</description>
</method>
<method name="add_varying">
<return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="mode" type="int" enum="VisualShader.VaryingMode" />
- <argument index="2" name="type" type="int" enum="VisualShader.VaryingType" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="mode" type="int" enum="VisualShader.VaryingMode" />
+ <param index="2" name="type" type="int" enum="VisualShader.VaryingType" />
<description>
</description>
</method>
<method name="can_connect_nodes" qualifiers="const">
<return type="bool" />
- <argument index="0" name="type" type="int" enum="VisualShader.Type" />
- <argument index="1" name="from_node" type="int" />
- <argument index="2" name="from_port" type="int" />
- <argument index="3" name="to_node" type="int" />
- <argument index="4" name="to_port" type="int" />
+ <param index="0" name="type" type="int" enum="VisualShader.Type" />
+ <param index="1" name="from_node" type="int" />
+ <param index="2" name="from_port" type="int" />
+ <param index="3" name="to_node" type="int" />
+ <param index="4" name="to_port" type="int" />
<description>
Returns [code]true[/code] if the specified nodes and ports can be connected together.
</description>
</method>
<method name="connect_nodes">
<return type="int" enum="Error" />
- <argument index="0" name="type" type="int" enum="VisualShader.Type" />
- <argument index="1" name="from_node" type="int" />
- <argument index="2" name="from_port" type="int" />
- <argument index="3" name="to_node" type="int" />
- <argument index="4" name="to_port" type="int" />
+ <param index="0" name="type" type="int" enum="VisualShader.Type" />
+ <param index="1" name="from_node" type="int" />
+ <param index="2" name="from_port" type="int" />
+ <param index="3" name="to_node" type="int" />
+ <param index="4" name="to_port" type="int" />
<description>
Connects the specified nodes and ports.
</description>
</method>
<method name="connect_nodes_forced">
<return type="void" />
- <argument index="0" name="type" type="int" enum="VisualShader.Type" />
- <argument index="1" name="from_node" type="int" />
- <argument index="2" name="from_port" type="int" />
- <argument index="3" name="to_node" type="int" />
- <argument index="4" name="to_port" type="int" />
+ <param index="0" name="type" type="int" enum="VisualShader.Type" />
+ <param index="1" name="from_node" type="int" />
+ <param index="2" name="from_port" type="int" />
+ <param index="3" name="to_node" type="int" />
+ <param index="4" name="to_port" type="int" />
<description>
Connects the specified nodes and ports, even if they can't be connected. Such connection is invalid and will not function properly.
</description>
</method>
<method name="disconnect_nodes">
<return type="void" />
- <argument index="0" name="type" type="int" enum="VisualShader.Type" />
- <argument index="1" name="from_node" type="int" />
- <argument index="2" name="from_port" type="int" />
- <argument index="3" name="to_node" type="int" />
- <argument index="4" name="to_port" type="int" />
+ <param index="0" name="type" type="int" enum="VisualShader.Type" />
+ <param index="1" name="from_node" type="int" />
+ <param index="2" name="from_port" type="int" />
+ <param index="3" name="to_node" type="int" />
+ <param index="4" name="to_port" type="int" />
<description>
Connects the specified nodes and ports.
</description>
</method>
<method name="get_node" qualifiers="const">
<return type="VisualShaderNode" />
- <argument index="0" name="type" type="int" enum="VisualShader.Type" />
- <argument index="1" name="id" type="int" />
+ <param index="0" name="type" type="int" enum="VisualShader.Type" />
+ <param index="1" name="id" type="int" />
<description>
- Returns the shader node instance with specified [code]type[/code] and [code]id[/code].
+ Returns the shader node instance with specified [param type] and [param id].
</description>
</method>
<method name="get_node_connections" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="type" type="int" enum="VisualShader.Type" />
+ <return type="Dictionary[]" />
+ <param index="0" name="type" type="int" enum="VisualShader.Type" />
<description>
Returns the list of connected nodes with the specified type.
</description>
</method>
<method name="get_node_list" qualifiers="const">
<return type="PackedInt32Array" />
- <argument index="0" name="type" type="int" enum="VisualShader.Type" />
+ <param index="0" name="type" type="int" enum="VisualShader.Type" />
<description>
Returns the list of all nodes in the shader with the specified type.
</description>
</method>
<method name="get_node_position" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="type" type="int" enum="VisualShader.Type" />
- <argument index="1" name="id" type="int" />
+ <param index="0" name="type" type="int" enum="VisualShader.Type" />
+ <param index="1" name="id" type="int" />
<description>
Returns the position of the specified node within the shader graph.
</description>
</method>
<method name="get_valid_node_id" qualifiers="const">
<return type="int" />
- <argument index="0" name="type" type="int" enum="VisualShader.Type" />
+ <param index="0" name="type" type="int" enum="VisualShader.Type" />
<description>
</description>
</method>
<method name="has_varying" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
</description>
</method>
<method name="is_node_connection" qualifiers="const">
<return type="bool" />
- <argument index="0" name="type" type="int" enum="VisualShader.Type" />
- <argument index="1" name="from_node" type="int" />
- <argument index="2" name="from_port" type="int" />
- <argument index="3" name="to_node" type="int" />
- <argument index="4" name="to_port" type="int" />
+ <param index="0" name="type" type="int" enum="VisualShader.Type" />
+ <param index="1" name="from_node" type="int" />
+ <param index="2" name="from_port" type="int" />
+ <param index="3" name="to_node" type="int" />
+ <param index="4" name="to_port" type="int" />
<description>
Returns [code]true[/code] if the specified node and port connection exist.
</description>
</method>
<method name="remove_node">
<return type="void" />
- <argument index="0" name="type" type="int" enum="VisualShader.Type" />
- <argument index="1" name="id" type="int" />
+ <param index="0" name="type" type="int" enum="VisualShader.Type" />
+ <param index="1" name="id" type="int" />
<description>
Removes the specified node from the shader.
</description>
</method>
<method name="remove_varying">
<return type="void" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
</description>
</method>
<method name="replace_node">
<return type="void" />
- <argument index="0" name="type" type="int" enum="VisualShader.Type" />
- <argument index="1" name="id" type="int" />
- <argument index="2" name="new_class" type="StringName" />
+ <param index="0" name="type" type="int" enum="VisualShader.Type" />
+ <param index="1" name="id" type="int" />
+ <param index="2" name="new_class" type="StringName" />
<description>
Replaces the specified node with a node of new class type.
</description>
</method>
<method name="set_mode">
<return type="void" />
- <argument index="0" name="mode" type="int" enum="Shader.Mode" />
+ <param index="0" name="mode" type="int" enum="Shader.Mode" />
<description>
Sets the mode of this shader.
</description>
</method>
<method name="set_node_position">
<return type="void" />
- <argument index="0" name="type" type="int" enum="VisualShader.Type" />
- <argument index="1" name="id" type="int" />
- <argument index="2" name="position" type="Vector2" />
+ <param index="0" name="type" type="int" enum="VisualShader.Type" />
+ <param index="1" name="id" type="int" />
+ <param index="2" name="position" type="Vector2" />
<description>
Sets the position of the specified node.
</description>
@@ -206,17 +206,19 @@
</constant>
<constant name="VARYING_TYPE_FLOAT" value="0" enum="VaryingType">
</constant>
- <constant name="VARYING_TYPE_VECTOR_2D" value="1" enum="VaryingType">
+ <constant name="VARYING_TYPE_INT" value="1" enum="VaryingType">
</constant>
- <constant name="VARYING_TYPE_VECTOR_3D" value="2" enum="VaryingType">
+ <constant name="VARYING_TYPE_VECTOR_2D" value="2" enum="VaryingType">
</constant>
- <constant name="VARYING_TYPE_VECTOR_4D" value="3" enum="VaryingType">
+ <constant name="VARYING_TYPE_VECTOR_3D" value="3" enum="VaryingType">
</constant>
- <constant name="VARYING_TYPE_COLOR" value="4" enum="VaryingType">
+ <constant name="VARYING_TYPE_VECTOR_4D" value="4" enum="VaryingType">
</constant>
- <constant name="VARYING_TYPE_TRANSFORM" value="5" enum="VaryingType">
+ <constant name="VARYING_TYPE_BOOLEAN" value="5" enum="VaryingType">
</constant>
- <constant name="VARYING_TYPE_MAX" value="6" enum="VaryingType">
+ <constant name="VARYING_TYPE_TRANSFORM" value="6" enum="VaryingType">
+ </constant>
+ <constant name="VARYING_TYPE_MAX" value="7" enum="VaryingType">
</constant>
<constant name="NODE_ID_INVALID" value="-1">
</constant>
diff --git a/doc/classes/VisualShaderNode.xml b/doc/classes/VisualShaderNode.xml
index 7220731a8a..1f3397f39c 100644
--- a/doc/classes/VisualShaderNode.xml
+++ b/doc/classes/VisualShaderNode.xml
@@ -24,32 +24,32 @@
</method>
<method name="get_input_port_default_value" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="port" type="int" />
+ <param index="0" name="port" type="int" />
<description>
- Returns the default value of the input [code]port[/code].
+ Returns the default value of the input [param port].
</description>
</method>
<method name="remove_input_port_default_value">
<return type="void" />
- <argument index="0" name="port" type="int" />
+ <param index="0" name="port" type="int" />
<description>
- Removes the default value of the input [code]port[/code].
+ Removes the default value of the input [param port].
</description>
</method>
<method name="set_default_input_values">
<return type="void" />
- <argument index="0" name="values" type="Array" />
+ <param index="0" name="values" type="Array" />
<description>
Sets the default input ports values using an [Array] of the form [code][index0, value0, index1, value1, ...][/code]. For example: [code][0, Vector3(0, 0, 0), 1, Vector3(0, 0, 0)][/code].
</description>
</method>
<method name="set_input_port_default_value">
<return type="void" />
- <argument index="0" name="port" type="int" />
- <argument index="1" name="value" type="Variant" />
- <argument index="2" name="prev_value" type="Variant" default="null" />
+ <param index="0" name="port" type="int" />
+ <param index="1" name="value" type="Variant" />
+ <param index="2" name="prev_value" type="Variant" default="null" />
<description>
- Sets the default value for the selected input [code]port[/code].
+ Sets the default [param value] for the selected input [param port].
</description>
</method>
</methods>
diff --git a/doc/classes/VisualShaderNodeCustom.xml b/doc/classes/VisualShaderNodeCustom.xml
index 0a962a4aa4..d96969b383 100644
--- a/doc/classes/VisualShaderNodeCustom.xml
+++ b/doc/classes/VisualShaderNodeCustom.xml
@@ -25,15 +25,15 @@
</method>
<method name="_get_code" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="input_vars" type="String[]" />
- <argument index="1" name="output_vars" type="String[]" />
- <argument index="2" name="mode" type="int" enum="Shader.Mode" />
- <argument index="3" name="type" type="int" enum="VisualShader.Type" />
+ <param index="0" name="input_vars" type="String[]" />
+ <param index="1" name="output_vars" type="String[]" />
+ <param index="2" name="mode" type="int" enum="Shader.Mode" />
+ <param index="3" name="type" type="int" enum="VisualShader.Type" />
<description>
Override this method to define the actual shader code of the associated custom node. The shader code should be returned as a string, which can have multiple lines (the [code]"""[/code] multiline string construct can be used for convenience).
- The [code]input_vars[/code] and [code]output_vars[/code] arrays contain the string names of the various input and output variables, as defined by [code]_get_input_*[/code] and [code]_get_output_*[/code] virtual methods in this class.
+ The [param input_vars] and [param output_vars] arrays contain the string names of the various input and output variables, as defined by [code]_get_input_*[/code] and [code]_get_output_*[/code] virtual methods in this class.
The output ports can be assigned values in the shader code. For example, [code]return output_vars[0] + " = " + input_vars[0] + ";"[/code].
- You can customize the generated code based on the shader [code]mode[/code] (see [enum Shader.Mode]) and/or [code]type[/code] (see [enum VisualShader.Type]).
+ You can customize the generated code based on the shader [param mode] (see [enum Shader.Mode]) and/or [param type] (see [enum VisualShader.Type]).
Defining this method is [b]required[/b].
</description>
</method>
@@ -46,35 +46,35 @@
</method>
<method name="_get_func_code" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="mode" type="int" enum="Shader.Mode" />
- <argument index="1" name="type" type="int" enum="VisualShader.Type" />
+ <param index="0" name="mode" type="int" enum="Shader.Mode" />
+ <param index="1" name="type" type="int" enum="VisualShader.Type" />
<description>
Override this method to add a shader code to the beginning of each shader function (once). The shader code should be returned as a string, which can have multiple lines (the [code]"""[/code] multiline string construct can be used for convenience).
If there are multiple custom nodes of different types which use this feature the order of each insertion is undefined.
- You can customize the generated code based on the shader [code]mode[/code] (see [enum Shader.Mode]) and/or [code]type[/code] (see [enum VisualShader.Type]).
+ You can customize the generated code based on the shader [param mode] (see [enum Shader.Mode]) and/or [param type] (see [enum VisualShader.Type]).
Defining this method is [b]optional[/b].
</description>
</method>
<method name="_get_global_code" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="mode" type="int" enum="Shader.Mode" />
+ <param index="0" name="mode" type="int" enum="Shader.Mode" />
<description>
Override this method to add shader code on top of the global shader, to define your own standard library of reusable methods, varyings, constants, uniforms, etc. The shader code should be returned as a string, which can have multiple lines (the [code]"""[/code] multiline string construct can be used for convenience).
Be careful with this functionality as it can cause name conflicts with other custom nodes, so be sure to give the defined entities unique names.
- You can customize the generated code based on the shader [code]mode[/code] (see [enum Shader.Mode]).
+ You can customize the generated code based on the shader [param mode] (see [enum Shader.Mode]).
Defining this method is [b]optional[/b].
</description>
</method>
<method name="_get_input_port_count" qualifiers="virtual const">
<return type="int" />
<description>
- Override this method to define the amount of input ports of the associated custom node.
+ Override this method to define the number of input ports of the associated custom node.
Defining this method is [b]required[/b]. If not overridden, the node has no input ports.
</description>
</method>
<method name="_get_input_port_name" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="port" type="int" />
+ <param index="0" name="port" type="int" />
<description>
Override this method to define the names of input ports of the associated custom node. The names are used both for the input slots in the editor and as identifiers in the shader code, and are passed in the [code]input_vars[/code] array in [method _get_code].
Defining this method is [b]optional[/b], but recommended. If not overridden, input ports are named as [code]"in" + str(port)[/code].
@@ -82,7 +82,7 @@
</method>
<method name="_get_input_port_type" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="port" type="int" />
+ <param index="0" name="port" type="int" />
<description>
Override this method to define the returned type of each input port of the associated custom node (see [enum VisualShaderNode.PortType] for possible types).
Defining this method is [b]optional[/b], but recommended. If not overridden, input ports will return the [constant VisualShaderNode.PORT_TYPE_SCALAR] type.
@@ -98,13 +98,13 @@
<method name="_get_output_port_count" qualifiers="virtual const">
<return type="int" />
<description>
- Override this method to define the amount of output ports of the associated custom node.
+ Override this method to define the number of output ports of the associated custom node.
Defining this method is [b]required[/b]. If not overridden, the node has no output ports.
</description>
</method>
<method name="_get_output_port_name" qualifiers="virtual const">
<return type="String" />
- <argument index="0" name="port" type="int" />
+ <param index="0" name="port" type="int" />
<description>
Override this method to define the names of output ports of the associated custom node. The names are used both for the output slots in the editor and as identifiers in the shader code, and are passed in the [code]output_vars[/code] array in [method _get_code].
Defining this method is [b]optional[/b], but recommended. If not overridden, output ports are named as [code]"out" + str(port)[/code].
@@ -112,7 +112,7 @@
</method>
<method name="_get_output_port_type" qualifiers="virtual const">
<return type="int" />
- <argument index="0" name="port" type="int" />
+ <param index="0" name="port" type="int" />
<description>
Override this method to define the returned type of each output port of the associated custom node (see [enum VisualShaderNode.PortType] for possible types).
Defining this method is [b]optional[/b], but recommended. If not overridden, output ports will return the [constant VisualShaderNode.PORT_TYPE_SCALAR] type.
@@ -127,10 +127,10 @@
</method>
<method name="_is_available" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="mode" type="int" enum="Shader.Mode" />
- <argument index="1" name="type" type="int" enum="VisualShader.Type" />
+ <param index="0" name="mode" type="int" enum="Shader.Mode" />
+ <param index="1" name="type" type="int" enum="VisualShader.Type" />
<description>
- Override this method to prevent the node to be visible in the member dialog for the certain [code]mode[/code] (see [enum Shader.Mode]) and/or [code]type[/code] (see [enum VisualShader.Type]).
+ Override this method to prevent the node to be visible in the member dialog for the certain [param mode] (see [enum Shader.Mode]) and/or [param type] (see [enum VisualShader.Type]).
Defining this method is [b]optional[/b]. If not overridden, it's [code]true[/code].
</description>
</method>
diff --git a/doc/classes/VisualShaderNodeDistanceFade.xml b/doc/classes/VisualShaderNodeDistanceFade.xml
new file mode 100644
index 0000000000..8ea0857776
--- /dev/null
+++ b/doc/classes/VisualShaderNodeDistanceFade.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeDistanceFade" inherits="VisualShaderNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/doc/classes/VisualShaderNodeExpression.xml b/doc/classes/VisualShaderNodeExpression.xml
index c4f010f3c0..6b2dc2f2cb 100644
--- a/doc/classes/VisualShaderNodeExpression.xml
+++ b/doc/classes/VisualShaderNodeExpression.xml
@@ -4,7 +4,7 @@
A custom visual shader graph expression written in Godot Shading Language.
</brief_description>
<description>
- Custom Godot Shading Language expression, with a custom amount of input and output ports.
+ Custom Godot Shading Language expression, with a custom number of input and output ports.
The provided code is directly injected into the graph's matching shader function ([code]vertex[/code], [code]fragment[/code], or [code]light[/code]), so it cannot be used to declare functions, varyings, uniforms, or global constants. See [VisualShaderNodeGlobalExpression] for such global definitions.
</description>
<tutorials>
diff --git a/doc/classes/VisualShaderNodeGroupBase.xml b/doc/classes/VisualShaderNodeGroupBase.xml
index 1b724b00d6..dcc94f0b24 100644
--- a/doc/classes/VisualShaderNodeGroupBase.xml
+++ b/doc/classes/VisualShaderNodeGroupBase.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeGroupBase" inherits="VisualShaderNodeResizableBase" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- Base class for a family of nodes with variable amount of input and output ports within the visual shader graph.
+ Base class for a family of nodes with variable number of input and output ports within the visual shader graph.
</brief_description>
<description>
Currently, has no direct usage, use the derived classes instead.
@@ -11,20 +11,20 @@
<methods>
<method name="add_input_port">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="type" type="int" />
- <argument index="2" name="name" type="String" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="type" type="int" />
+ <param index="2" name="name" type="String" />
<description>
- Adds an input port with the specified [code]type[/code] (see [enum VisualShaderNode.PortType]) and [code]name[/code].
+ Adds an input port with the specified [param type] (see [enum VisualShaderNode.PortType]) and [param name].
</description>
</method>
<method name="add_output_port">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="type" type="int" />
- <argument index="2" name="name" type="String" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="type" type="int" />
+ <param index="2" name="name" type="String" />
<description>
- Adds an output port with the specified [code]type[/code] (see [enum VisualShaderNode.PortType]) and [code]name[/code].
+ Adds an output port with the specified [param type] (see [enum VisualShaderNode.PortType]) and [param name].
</description>
</method>
<method name="clear_input_ports">
@@ -77,81 +77,81 @@
</method>
<method name="has_input_port" qualifiers="const">
<return type="bool" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Returns [code]true[/code] if the specified input port exists.
</description>
</method>
<method name="has_output_port" qualifiers="const">
<return type="bool" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Returns [code]true[/code] if the specified output port exists.
</description>
</method>
<method name="is_valid_port_name" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
Returns [code]true[/code] if the specified port name does not override an existed port name and is valid within the shader.
</description>
</method>
<method name="remove_input_port">
<return type="void" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Removes the specified input port.
</description>
</method>
<method name="remove_output_port">
<return type="void" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Removes the specified output port.
</description>
</method>
<method name="set_input_port_name">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="name" type="String" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="name" type="String" />
<description>
Renames the specified input port.
</description>
</method>
<method name="set_input_port_type">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="type" type="int" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="type" type="int" />
<description>
Sets the specified input port's type (see [enum VisualShaderNode.PortType]).
</description>
</method>
<method name="set_inputs">
<return type="void" />
- <argument index="0" name="inputs" type="String" />
+ <param index="0" name="inputs" type="String" />
<description>
Defines all input ports using a [String] formatted as a colon-separated list: [code]id,type,name;[/code] (see [method add_input_port]).
</description>
</method>
<method name="set_output_port_name">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="name" type="String" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="name" type="String" />
<description>
Renames the specified output port.
</description>
</method>
<method name="set_output_port_type">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="type" type="int" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="type" type="int" />
<description>
Sets the specified output port's type (see [enum VisualShaderNode.PortType]).
</description>
</method>
<method name="set_outputs">
<return type="void" />
- <argument index="0" name="outputs" type="String" />
+ <param index="0" name="outputs" type="String" />
<description>
Defines all output ports using a [String] formatted as a colon-separated list: [code]id,type,name;[/code] (see [method add_output_port]).
</description>
diff --git a/doc/classes/VisualShaderNodeLinearSceneDepth.xml b/doc/classes/VisualShaderNodeLinearSceneDepth.xml
new file mode 100644
index 0000000000..fa8c01ac0a
--- /dev/null
+++ b/doc/classes/VisualShaderNodeLinearSceneDepth.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeLinearSceneDepth" inherits="VisualShaderNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/doc/classes/VisualShaderNodeProximityFade.xml b/doc/classes/VisualShaderNodeProximityFade.xml
new file mode 100644
index 0000000000..25051eed71
--- /dev/null
+++ b/doc/classes/VisualShaderNodeProximityFade.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeProximityFade" inherits="VisualShaderNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/doc/classes/VisualShaderNodeRandomRange.xml b/doc/classes/VisualShaderNodeRandomRange.xml
new file mode 100644
index 0000000000..adc83d808c
--- /dev/null
+++ b/doc/classes/VisualShaderNodeRandomRange.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeRandomRange" inherits="VisualShaderNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/doc/classes/VisualShaderNodeRemap.xml b/doc/classes/VisualShaderNodeRemap.xml
new file mode 100644
index 0000000000..5a73a76e7f
--- /dev/null
+++ b/doc/classes/VisualShaderNodeRemap.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeRemap" inherits="VisualShaderNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/doc/classes/VisualShaderNodeTextureUniform.xml b/doc/classes/VisualShaderNodeTextureUniform.xml
index bff6f2015d..9014f79f54 100644
--- a/doc/classes/VisualShaderNodeTextureUniform.xml
+++ b/doc/classes/VisualShaderNodeTextureUniform.xml
@@ -39,12 +39,15 @@
Represents the size of the [enum TextureType] enum.
</constant>
<constant name="COLOR_DEFAULT_WHITE" value="0" enum="ColorDefault">
- Defaults to white color.
+ Defaults to fully opaque white color.
</constant>
<constant name="COLOR_DEFAULT_BLACK" value="1" enum="ColorDefault">
- Defaults to black color.
+ Defaults to fully opaque black color.
</constant>
- <constant name="COLOR_DEFAULT_MAX" value="2" enum="ColorDefault">
+ <constant name="COLOR_DEFAULT_TRANSPARENT" value="2" enum="ColorDefault">
+ Defaults to fully transparent black color.
+ </constant>
+ <constant name="COLOR_DEFAULT_MAX" value="3" enum="ColorDefault">
Represents the size of the [enum ColorDefault] enum.
</constant>
<constant name="FILTER_DEFAULT" value="0" enum="TextureFilter">
diff --git a/doc/classes/VisualShaderNodeUVFunc.xml b/doc/classes/VisualShaderNodeUVFunc.xml
index 37a9769a10..541991b790 100644
--- a/doc/classes/VisualShaderNodeUVFunc.xml
+++ b/doc/classes/VisualShaderNodeUVFunc.xml
@@ -17,7 +17,7 @@
Translates [code]uv[/code] by using [code]scale[/code] and [code]offset[/code] values using the following formula: [code]uv = uv + offset * scale[/code]. [code]uv[/code] port is connected to [code]UV[/code] built-in by default.
</constant>
<constant name="FUNC_SCALING" value="1" enum="Function">
- Scales [code]uv[/uv] by using [code]scale[/code] and [code]pivot[/code] values using the following formula: [code]uv = (uv - pivot) * scale + pivot[/code]. [code]uv[/code] port is connected to [code]UV[/code] built-in by default.
+ Scales [code]uv[/code] by using [code]scale[/code] and [code]pivot[/code] values using the following formula: [code]uv = (uv - pivot) * scale + pivot[/code]. [code]uv[/code] port is connected to [code]UV[/code] built-in by default.
</constant>
<constant name="FUNC_MAX" value="2" enum="Function">
Represents the size of the [enum Function] enum.
diff --git a/doc/classes/VisualShaderNodeUVPolarCoord.xml b/doc/classes/VisualShaderNodeUVPolarCoord.xml
new file mode 100644
index 0000000000..8582939db3
--- /dev/null
+++ b/doc/classes/VisualShaderNodeUVPolarCoord.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualShaderNodeUVPolarCoord" inherits="VisualShaderNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/doc/classes/VisualShaderNodeVectorRefract.xml b/doc/classes/VisualShaderNodeVectorRefract.xml
index d12188ea55..003b505671 100644
--- a/doc/classes/VisualShaderNodeVectorRefract.xml
+++ b/doc/classes/VisualShaderNodeVectorRefract.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualShaderNodeVectorRefract" inherits="VisualShaderNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="VisualShaderNodeVectorRefract" inherits="VisualShaderNodeVectorBase" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- Returns the [Vector3] that points in the direction of refraction. For use within the visual shader graph.
+ Returns the vector that points in the direction of refraction. For use within the visual shader graph.
</brief_description>
<description>
Translated to [code]refract(I, N, eta)[/code] in the shader language, where [code]I[/code] is the incident vector, [code]N[/code] is the normal vector and [code]eta[/code] is the ratio of the indices of the refraction.
diff --git a/doc/classes/VoxelGI.xml b/doc/classes/VoxelGI.xml
index d941185d33..ba4995a5fb 100644
--- a/doc/classes/VoxelGI.xml
+++ b/doc/classes/VoxelGI.xml
@@ -16,8 +16,8 @@
<methods>
<method name="bake">
<return type="void" />
- <argument index="0" name="from_node" type="Node" default="null" />
- <argument index="1" name="create_visual_debug" type="bool" default="false" />
+ <param index="0" name="from_node" type="Node" default="null" />
+ <param index="1" name="create_visual_debug" type="bool" default="false" />
<description>
Bakes the effect from all [GeometryInstance3D]s marked with [constant GeometryInstance3D.GI_MODE_STATIC] and [Light3D]s marked with either [constant Light3D.BAKE_STATIC] or [constant Light3D.BAKE_DYNAMIC]. If [code]create_visual_debug[/code] is [code]true[/code], after baking the light, this will generate a [MultiMesh] that has a cube representing each solid cell with each cube colored to the cell's albedo color. This can be used to visualize the [VoxelGI]'s data and debug any issues that may be occurring.
[b]Note:[/b] [method bake] works from the editor and in exported projects. This makes it suitable for procedurally generated or user-built levels. Baking a [VoxelGI] node generally takes from 5 to 20 seconds in most scenes. Reducing [member subdiv] can speed up baking.
diff --git a/doc/classes/VoxelGIData.xml b/doc/classes/VoxelGIData.xml
index 9198da4bc6..92b2e66e5a 100644
--- a/doc/classes/VoxelGIData.xml
+++ b/doc/classes/VoxelGIData.xml
@@ -13,13 +13,13 @@
<methods>
<method name="allocate">
<return type="void" />
- <argument index="0" name="to_cell_xform" type="Transform3D" />
- <argument index="1" name="aabb" type="AABB" />
- <argument index="2" name="octree_size" type="Vector3" />
- <argument index="3" name="octree_cells" type="PackedByteArray" />
- <argument index="4" name="data_cells" type="PackedByteArray" />
- <argument index="5" name="distance_field" type="PackedByteArray" />
- <argument index="6" name="level_counts" type="PackedInt32Array" />
+ <param index="0" name="to_cell_xform" type="Transform3D" />
+ <param index="1" name="aabb" type="AABB" />
+ <param index="2" name="octree_size" type="Vector3" />
+ <param index="3" name="octree_cells" type="PackedByteArray" />
+ <param index="4" name="data_cells" type="PackedByteArray" />
+ <param index="5" name="distance_field" type="PackedByteArray" />
+ <param index="6" name="level_counts" type="PackedInt32Array" />
<description>
</description>
</method>
diff --git a/doc/classes/WeakRef.xml b/doc/classes/WeakRef.xml
index f80381acda..ea520178c7 100644
--- a/doc/classes/WeakRef.xml
+++ b/doc/classes/WeakRef.xml
@@ -12,7 +12,7 @@
<method name="get_ref" qualifiers="const">
<return type="Variant" />
<description>
- Returns the [Object] this weakref is referring to.
+ Returns the [Object] this weakref is referring to. Returns [code]null[/code] if that object no longer exists.
</description>
</method>
</methods>
diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml
index f4eaaac2e1..2c0a694ef9 100644
--- a/doc/classes/Window.xml
+++ b/doc/classes/Window.xml
@@ -30,9 +30,9 @@
</method>
<method name="get_flag" qualifiers="const">
<return type="bool" />
- <argument index="0" name="flag" type="int" enum="Window.Flags" />
+ <param index="0" name="flag" type="int" enum="Window.Flags" />
<description>
- Returns [code]true[/code] if the flag is set.
+ Returns [code]true[/code] if the [param flag] is set.
</description>
</method>
<method name="get_layout_direction" qualifiers="const">
@@ -49,19 +49,19 @@
</method>
<method name="get_theme_color" qualifiers="const">
<return type="Color" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns the [Color] at [code]name[/code] if the theme has [code]theme_type[/code].
+ Returns the [Color] at [param name] if the theme has [param theme_type].
See [method Control.get_theme_color] for more details.
</description>
</method>
<method name="get_theme_constant" qualifiers="const">
<return type="int" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns the constant at [code]name[/code] if the theme has [code]theme_type[/code].
+ Returns the constant at [param name] if the theme has [param theme_type].
See [method Control.get_theme_color] for more details.
</description>
</method>
@@ -88,37 +88,37 @@
</method>
<method name="get_theme_font" qualifiers="const">
<return type="Font" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns the [Font] at [code]name[/code] if the theme has [code]theme_type[/code].
+ Returns the [Font] at [param name] if the theme has [param theme_type].
See [method Control.get_theme_color] for more details.
</description>
</method>
<method name="get_theme_font_size" qualifiers="const">
<return type="int" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns the font size at [code]name[/code] if the theme has [code]theme_type[/code].
+ Returns the font size at [param name] if the theme has [param theme_type].
See [method Control.get_theme_color] for more details.
</description>
</method>
<method name="get_theme_icon" qualifiers="const">
<return type="Texture2D" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns the icon at [code]name[/code] if the theme has [code]theme_type[/code].
+ Returns the icon at [param name] if the theme has [param theme_type].
See [method Control.get_theme_color] for more details.
</description>
</method>
<method name="get_theme_stylebox" qualifiers="const">
<return type="StyleBox" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns the [StyleBox] at [code]name[/code] if the theme has [code]theme_type[/code].
+ Returns the [StyleBox] at [param name] if the theme has [param theme_type].
See [method Control.get_theme_color] for more details.
</description>
</method>
@@ -136,50 +136,50 @@
</method>
<method name="has_theme_color" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns [code]true[/code] if [Color] with [code]name[/code] is in [code]theme_type[/code].
+ Returns [code]true[/code] if [Color] with [param name] is in [param theme_type].
</description>
</method>
<method name="has_theme_constant" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns [code]true[/code] if constant with [code]name[/code] is in [code]theme_type[/code].
+ Returns [code]true[/code] if constant with [param name] is in [param theme_type].
</description>
</method>
<method name="has_theme_font" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns [code]true[/code] if [Font] with [code]name[/code] is in [code]theme_type[/code].
+ Returns [code]true[/code] if [Font] with [param name] is in [param theme_type].
</description>
</method>
<method name="has_theme_font_size" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns [code]true[/code] if font size with [code]name[/code] is in [code]theme_type[/code].
+ Returns [code]true[/code] if font size with [param name] is in [param theme_type].
</description>
</method>
<method name="has_theme_icon" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns [code]true[/code] if icon with [code]name[/code] is in [code]theme_type[/code].
+ Returns [code]true[/code] if icon with [param name] is in [param theme_type].
</description>
</method>
<method name="has_theme_stylebox" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="theme_type" type="StringName" default="&quot;&quot;" />
<description>
- Returns [code]true[/code] if [StyleBox] with [code]name[/code] is in [code]theme_type[/code].
+ Returns [code]true[/code] if [StyleBox] with [param name] is in [param theme_type].
</description>
</method>
<method name="hide">
@@ -220,15 +220,15 @@
</method>
<method name="popup">
<return type="void" />
- <argument index="0" name="rect" type="Rect2i" default="Rect2i(0, 0, 0, 0)" />
+ <param index="0" name="rect" type="Rect2i" default="Rect2i(0, 0, 0, 0)" />
<description>
- Shows the [Window] and makes it transient (see [member transient]). If [code]rect[/code] is provided, it will be set as the [Window]'s size.
+ Shows the [Window] and makes it transient (see [member transient]). If [param rect] is provided, it will be set as the [Window]'s size.
Fails if called on the main window.
</description>
</method>
<method name="popup_centered">
<return type="void" />
- <argument index="0" name="minsize" type="Vector2i" default="Vector2i(0, 0)" />
+ <param index="0" name="minsize" type="Vector2i" default="Vector2i(0, 0)" />
<description>
Popups the [Window] at the center of the current screen, with optionally given minimum size.
If the [Window] is embedded, it will be centered in the parent [Viewport] instead.
@@ -236,8 +236,8 @@
</method>
<method name="popup_centered_clamped">
<return type="void" />
- <argument index="0" name="minsize" type="Vector2i" default="Vector2i(0, 0)" />
- <argument index="1" name="fallback_ratio" type="float" default="0.75" />
+ <param index="0" name="minsize" type="Vector2i" default="Vector2i(0, 0)" />
+ <param index="1" name="fallback_ratio" type="float" default="0.75" />
<description>
Popups the [Window] centered inside its parent [Window].
[code]fallback_ratio[/code] determines the maximum size of the [Window], in relation to its parent.
@@ -245,14 +245,14 @@
</method>
<method name="popup_centered_ratio">
<return type="void" />
- <argument index="0" name="ratio" type="float" default="0.8" />
+ <param index="0" name="ratio" type="float" default="0.8" />
<description>
- Popups the [Window] centered inside its parent [Window] and sets its size as a [code]ratio[/code] of parent's size.
+ Popups the [Window] centered inside its parent [Window] and sets its size as a [param ratio] of parent's size.
</description>
</method>
<method name="popup_on_parent">
<return type="void" />
- <argument index="0" name="parent_rect" type="Rect2i" />
+ <param index="0" name="parent_rect" type="Rect2i" />
<description>
Popups the [Window] with a position shifted by parent [Window]'s position.
If the [Window] is embedded, has the same effect as [method popup].
@@ -272,36 +272,36 @@
</method>
<method name="set_flag">
<return type="void" />
- <argument index="0" name="flag" type="int" enum="Window.Flags" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="flag" type="int" enum="Window.Flags" />
+ <param index="1" name="enabled" type="bool" />
<description>
Sets a specified window flag.
</description>
</method>
<method name="set_ime_active">
<return type="void" />
- <argument index="0" name="active" type="bool" />
+ <param index="0" name="active" type="bool" />
<description>
- If [code]active[/code] is [code]true[/code], enables system's native IME (Input Method Editor).
+ If [param active] is [code]true[/code], enables system's native IME (Input Method Editor).
</description>
</method>
<method name="set_ime_position">
<return type="void" />
- <argument index="0" name="position" type="Vector2i" />
+ <param index="0" name="position" type="Vector2i" />
<description>
Moves IME to the given position.
</description>
</method>
<method name="set_layout_direction">
<return type="void" />
- <argument index="0" name="direction" type="int" enum="Window.LayoutDirection" />
+ <param index="0" name="direction" type="int" enum="Window.LayoutDirection" />
<description>
Sets layout direction and text writing direction. Right-to-left layouts are necessary for certain languages (e.g. Arabic and Hebrew).
</description>
</method>
<method name="set_use_font_oversampling">
<return type="void" />
- <argument index="0" name="enable" type="bool" />
+ <param index="0" name="enable" type="bool" />
<description>
Enables font oversampling. This makes fonts look better when they are scaled up.
</description>
@@ -342,11 +342,16 @@
If [code]true[/code], the [Window] will be in exclusive mode. Exclusive windows are always on top of their parent and will block all input going to the parent [Window].
Needs [member transient] enabled to work.
</member>
+ <member name="extend_to_title" type="bool" setter="set_flag" getter="get_flag" default="false">
+ If [code]true[/code], the [Window] contents is expanded to the full size of the window, window title bar is transparent.
+ </member>
<member name="max_size" type="Vector2i" setter="set_max_size" getter="get_max_size" default="Vector2i(0, 0)">
If non-zero, the [Window] can't be resized to be bigger than this size.
+ [b]Note:[/b] This property will be ignored if the value is lower than [member min_size].
</member>
<member name="min_size" type="Vector2i" setter="set_min_size" getter="get_min_size" default="Vector2i(0, 0)">
If non-zero, the [Window] can't be resized to be smaller than this size.
+ [b]Note:[/b] This property will be ignored in favor of [method get_contents_minimum_size] if [member wrap_controls] is enabled and if its size is bigger.
</member>
<member name="mode" type="int" setter="set_mode" getter="get_mode" enum="Window.Mode" default="0">
Set's the window's current mode.
@@ -388,7 +393,7 @@
If [code]true[/code], the window is visible.
</member>
<member name="wrap_controls" type="bool" setter="set_wrap_controls" getter="is_wrapping_controls" default="false">
- If [code]true[/code], the window's size will automatically update when a child node is added or removed.
+ If [code]true[/code], the window's size will automatically update when a child node is added or removed, ignoring [member min_size] if the new size is bigger.
If [code]false[/code], you need to call [method child_controls_changed] manually.
</member>
</members>
@@ -405,7 +410,7 @@
</description>
</signal>
<signal name="files_dropped">
- <argument index="0" name="files" type="PackedStringArray" />
+ <param index="0" name="files" type="PackedStringArray" />
<description>
Emitted when files are dragged from the OS file manager and dropped in the game window. The argument is a list of file paths.
Note that this method only works with non-embedded windows, i.e. the main window and [Window]-derived nodes when [member Viewport.gui_embed_subwindows] is disabled in the main viewport.
@@ -446,7 +451,7 @@
</signal>
<signal name="theme_changed">
<description>
- Emitted when the [member theme] is modified or changed to another [Theme].
+ Emitted when the [constant NOTIFICATION_THEME_CHANGED] notification is sent.
</description>
</signal>
<signal name="visibility_changed">
@@ -455,7 +460,7 @@
</description>
</signal>
<signal name="window_input">
- <argument index="0" name="event" type="InputEvent" />
+ <param index="0" name="event" type="InputEvent" />
<description>
Emitted when the [Window] is currently focused and receives any input, passing the received event as an argument.
</description>
@@ -465,6 +470,13 @@
<constant name="NOTIFICATION_VISIBILITY_CHANGED" value="30">
Emitted when [Window]'s visibility changes, right before [signal visibility_changed].
</constant>
+ <constant name="NOTIFICATION_THEME_CHANGED" value="32">
+ Sent when the node needs to refresh its theme items. This happens in one of the following cases:
+ - The [member theme] property is changed on this node or any of its ancestors.
+ - The [member theme_type_variation] property is changed on this node.
+ - The node enters the scene tree.
+ [b]Note:[/b] As an optimization, this notification won't be sent from changes that occur while this node is outside of the scene tree. Instead, all of the theme item updates can be applied at once when the node enters the scene tree.
+ </constant>
<constant name="MODE_WINDOWED" value="0" enum="Mode">
Windowed mode, i.e. [Window] doesn't occupy whole screen (unless set to the size of the screen).
</constant>
@@ -501,7 +513,10 @@
<constant name="FLAG_POPUP" value="5" enum="Flags">
Whether the window is popup or a regular window. Set with [member popup_window].
</constant>
- <constant name="FLAG_MAX" value="6" enum="Flags">
+ <constant name="FLAG_EXTEND_TO_TITLE" value="6" enum="Flags">
+ Window contents is expanded to the full size of the window, window title bar is transparent.
+ </constant>
+ <constant name="FLAG_MAX" value="7" enum="Flags">
Max value of the [enum Flags].
</constant>
<constant name="CONTENT_SCALE_MODE_DISABLED" value="0" enum="ContentScaleMode">
diff --git a/doc/classes/WorkerThreadPool.xml b/doc/classes/WorkerThreadPool.xml
index 4f614bdadb..fced54ae7f 100644
--- a/doc/classes/WorkerThreadPool.xml
+++ b/doc/classes/WorkerThreadPool.xml
@@ -9,49 +9,49 @@
<methods>
<method name="add_group_task">
<return type="int" />
- <argument index="0" name="action" type="Callable" />
- <argument index="1" name="elements" type="int" />
- <argument index="2" name="tasks_needed" type="int" default="-1" />
- <argument index="3" name="high_priority" type="bool" default="false" />
- <argument index="4" name="description" type="String" default="&quot;&quot;" />
+ <param index="0" name="action" type="Callable" />
+ <param index="1" name="elements" type="int" />
+ <param index="2" name="tasks_needed" type="int" default="-1" />
+ <param index="3" name="high_priority" type="bool" default="false" />
+ <param index="4" name="description" type="String" default="&quot;&quot;" />
<description>
</description>
</method>
<method name="add_task">
<return type="int" />
- <argument index="0" name="action" type="Callable" />
- <argument index="1" name="high_priority" type="bool" default="false" />
- <argument index="2" name="description" type="String" default="&quot;&quot;" />
+ <param index="0" name="action" type="Callable" />
+ <param index="1" name="high_priority" type="bool" default="false" />
+ <param index="2" name="description" type="String" default="&quot;&quot;" />
<description>
</description>
</method>
<method name="get_group_processed_element_count" qualifiers="const">
<return type="int" />
- <argument index="0" name="group_id" type="int" />
+ <param index="0" name="group_id" type="int" />
<description>
</description>
</method>
<method name="is_group_task_completed" qualifiers="const">
<return type="bool" />
- <argument index="0" name="group_id" type="int" />
+ <param index="0" name="group_id" type="int" />
<description>
</description>
</method>
<method name="is_task_completed" qualifiers="const">
<return type="bool" />
- <argument index="0" name="task_id" type="int" />
+ <param index="0" name="task_id" type="int" />
<description>
</description>
</method>
<method name="wait_for_group_task_completion">
<return type="void" />
- <argument index="0" name="group_id" type="int" />
+ <param index="0" name="group_id" type="int" />
<description>
</description>
</method>
<method name="wait_for_task_completion">
<return type="void" />
- <argument index="0" name="task_id" type="int" />
+ <param index="0" name="task_id" type="int" />
<description>
</description>
</method>
diff --git a/doc/classes/X509Certificate.xml b/doc/classes/X509Certificate.xml
index 581aba05e4..d8f54d0ec5 100644
--- a/doc/classes/X509Certificate.xml
+++ b/doc/classes/X509Certificate.xml
@@ -12,16 +12,16 @@
<methods>
<method name="load">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
- Loads a certificate from [code]path[/code] ("*.crt" file).
+ Loads a certificate from [param path] ("*.crt" file).
</description>
</method>
<method name="save">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
- Saves a certificate to the given [code]path[/code] (should be a "*.crt" file).
+ Saves a certificate to the given [param path] (should be a "*.crt" file).
</description>
</method>
</methods>
diff --git a/doc/classes/XMLParser.xml b/doc/classes/XMLParser.xml
index 79ab33045f..26480f0c18 100644
--- a/doc/classes/XMLParser.xml
+++ b/doc/classes/XMLParser.xml
@@ -12,21 +12,21 @@
<method name="get_attribute_count" qualifiers="const">
<return type="int" />
<description>
- Gets the amount of attributes in the current element.
+ Gets the number of attributes in the current element.
</description>
</method>
<method name="get_attribute_name" qualifiers="const">
<return type="String" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Gets the name of the attribute specified by the index in [code]idx[/code] argument.
+ Gets the name of the attribute specified by the [param idx] index.
</description>
</method>
<method name="get_attribute_value" qualifiers="const">
<return type="String" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Gets the value of the attribute specified by the index in [code]idx[/code] argument.
+ Gets the value of the attribute specified by the [param idx] index.
</description>
</method>
<method name="get_current_line" qualifiers="const">
@@ -37,16 +37,16 @@
</method>
<method name="get_named_attribute_value" qualifiers="const">
<return type="String" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
- Gets the value of a certain attribute of the current element by name. This will raise an error if the element has no such attribute.
+ Gets the value of a certain attribute of the current element by [param name]. This will raise an error if the element has no such attribute.
</description>
</method>
<method name="get_named_attribute_value_safe" qualifiers="const">
<return type="String" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
- Gets the value of a certain attribute of the current element by name. This will return an empty [String] if the attribute is not found.
+ Gets the value of a certain attribute of the current element by [param name]. This will return an empty [String] if the attribute is not found.
</description>
</method>
<method name="get_node_data" qualifiers="const">
@@ -75,7 +75,7 @@
</method>
<method name="has_attribute" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
Check whether the current element has a certain attribute.
</description>
@@ -88,16 +88,16 @@
</method>
<method name="open">
<return type="int" enum="Error" />
- <argument index="0" name="file" type="String" />
+ <param index="0" name="file" type="String" />
<description>
- Opens an XML file for parsing. This returns an error code.
+ Opens an XML [param file] for parsing. This returns an error code.
</description>
</method>
<method name="open_buffer">
<return type="int" enum="Error" />
- <argument index="0" name="buffer" type="PackedByteArray" />
+ <param index="0" name="buffer" type="PackedByteArray" />
<description>
- Opens an XML raw buffer for parsing. This returns an error code.
+ Opens an XML raw [param buffer] for parsing. This returns an error code.
</description>
</method>
<method name="read">
@@ -108,7 +108,7 @@
</method>
<method name="seek">
<return type="int" enum="Error" />
- <argument index="0" name="position" type="int" />
+ <param index="0" name="position" type="int" />
<description>
Moves the buffer cursor to a certain offset (since the beginning) and read the next node there. This returns an error code.
</description>
diff --git a/doc/classes/XRController3D.xml b/doc/classes/XRController3D.xml
index ff4aec46e1..9e192177e5 100644
--- a/doc/classes/XRController3D.xml
+++ b/doc/classes/XRController3D.xml
@@ -15,9 +15,9 @@
<methods>
<method name="get_axis" qualifiers="const">
<return type="Vector2" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Returns a [Vector2] for the input with the given [code]name[/code]. This is used for thumbsticks and thumbpads found on many controllers.
+ Returns a [Vector2] for the input with the given [param name]. This is used for thumbsticks and thumbpads found on many controllers.
</description>
</method>
<method name="get_tracker_hand" qualifiers="const">
@@ -28,42 +28,42 @@
</method>
<method name="get_value" qualifiers="const">
<return type="float" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Returns a numeric value for the input with the given [code]name[/code]. This is used for triggers and grip sensors.
+ Returns a numeric value for the input with the given [param name]. This is used for triggers and grip sensors.
</description>
</method>
<method name="is_button_pressed" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Returns [code]true[/code] if the button with the given [code]name[/code] is pressed.
+ Returns [code]true[/code] if the button with the given [param name] is pressed.
</description>
</method>
</methods>
<signals>
<signal name="button_pressed">
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
Emitted when a button on this controller is pressed.
</description>
</signal>
<signal name="button_released">
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
Emitted when a button on this controller is released.
</description>
</signal>
<signal name="input_axis_changed">
- <argument index="0" name="name" type="String" />
- <argument index="1" name="value" type="Vector2" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="value" type="Vector2" />
<description>
Emitted when a thumbstick or thumbpad on this controller is moved.
</description>
</signal>
<signal name="input_value_changed">
- <argument index="0" name="name" type="String" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="value" type="float" />
<description>
Emitted when a trigger or similar input on this controller changes value.
</description>
diff --git a/doc/classes/XRInterface.xml b/doc/classes/XRInterface.xml
index 26b7699af2..6296b95e6c 100644
--- a/doc/classes/XRInterface.xml
+++ b/doc/classes/XRInterface.xml
@@ -71,30 +71,30 @@
</method>
<method name="set_play_area_mode">
<return type="bool" />
- <argument index="0" name="mode" type="int" enum="XRInterface.PlayAreaMode" />
+ <param index="0" name="mode" type="int" enum="XRInterface.PlayAreaMode" />
<description>
Sets the active play area mode, will return [code]false[/code] if the mode can't be used with this interface.
</description>
</method>
<method name="supports_play_area_mode">
<return type="bool" />
- <argument index="0" name="mode" type="int" enum="XRInterface.PlayAreaMode" />
+ <param index="0" name="mode" type="int" enum="XRInterface.PlayAreaMode" />
<description>
Call this to find out if a given play area mode is supported by this interface.
</description>
</method>
<method name="trigger_haptic_pulse">
<return type="void" />
- <argument index="0" name="action_name" type="String" />
- <argument index="1" name="tracker_name" type="StringName" />
- <argument index="2" name="frequency" type="float" />
- <argument index="3" name="amplitude" type="float" />
- <argument index="4" name="duration_sec" type="float" />
- <argument index="5" name="delay_sec" type="float" />
+ <param index="0" name="action_name" type="String" />
+ <param index="1" name="tracker_name" type="StringName" />
+ <param index="2" name="frequency" type="float" />
+ <param index="3" name="amplitude" type="float" />
+ <param index="4" name="duration_sec" type="float" />
+ <param index="5" name="delay_sec" type="float" />
<description>
Triggers a haptic pulse on a device associated with this interface.
- [code]action_name[/code] is the name of the action for this pulse.
- [code]tracker_name[/code] is optional and can be used to direct the pulse to a specific device provided that device is bound to this haptic.
+ [param action_name] is the name of the action for this pulse.
+ [param tracker_name] is optional and can be used to direct the pulse to a specific device provided that device is bound to this haptic.
</description>
</method>
<method name="uninitialize">
@@ -117,7 +117,7 @@
</members>
<signals>
<signal name="play_area_changed">
- <argument index="0" name="mode" type="int" />
+ <param index="0" name="mode" type="int" />
<description>
Emitted when the play area is changed. This can be a result of the player resetting the boundary or entering a new play area, the player changing the play area mode, the world scale changing or the player resetting their headset orientation.
</description>
diff --git a/doc/classes/XRInterfaceExtension.xml b/doc/classes/XRInterfaceExtension.xml
index 1642ae61f7..06ef18b534 100644
--- a/doc/classes/XRInterfaceExtension.xml
+++ b/doc/classes/XRInterfaceExtension.xml
@@ -59,10 +59,10 @@
</method>
<method name="_get_projection_for_view" qualifiers="virtual">
<return type="PackedFloat64Array" />
- <argument index="0" name="view" type="int" />
- <argument index="1" name="aspect" type="float" />
- <argument index="2" name="z_near" type="float" />
- <argument index="3" name="z_far" type="float" />
+ <param index="0" name="view" type="int" />
+ <param index="1" name="aspect" type="float" />
+ <param index="2" name="z_near" type="float" />
+ <param index="3" name="z_far" type="float" />
<description>
Returns the projection matrix for the given view as a [PackedFloat64Array].
</description>
@@ -75,7 +75,7 @@
</method>
<method name="_get_suggested_pose_names" qualifiers="virtual const">
<return type="PackedStringArray" />
- <argument index="0" name="tracker_name" type="StringName" />
+ <param index="0" name="tracker_name" type="StringName" />
<description>
Returns a [PackedStringArray] with pose names configured by this interface. Note that user configuration can override this list.
</description>
@@ -94,8 +94,8 @@
</method>
<method name="_get_transform_for_view" qualifiers="virtual">
<return type="Transform3D" />
- <argument index="0" name="view" type="int" />
- <argument index="1" name="cam_transform" type="Transform3D" />
+ <param index="0" name="view" type="int" />
+ <param index="1" name="cam_transform" type="Transform3D" />
<description>
Returns a [Transform3D] for a given view.
</description>
@@ -125,22 +125,22 @@
</method>
<method name="_notification" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="what" type="int" />
+ <param index="0" name="what" type="int" />
<description>
Informs the interface of an applicable system notification.
</description>
</method>
<method name="_post_draw_viewport" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="render_target" type="RID" />
- <argument index="1" name="screen_rect" type="Rect2" />
+ <param index="0" name="render_target" type="RID" />
+ <param index="1" name="screen_rect" type="Rect2" />
<description>
Called after the XR [Viewport] draw logic has completed.
</description>
</method>
<method name="_pre_draw_viewport" qualifiers="virtual">
<return type="bool" />
- <argument index="0" name="render_target" type="RID" />
+ <param index="0" name="render_target" type="RID" />
<description>
Called if this is our primary [XRInterfaceExtension] before we start processing a [Viewport] for every active XR [Viewport], returns [code]true[/code] if that viewport should be rendered. An XR interface may return [code]false[/code] if the user has taken off their headset and we can pause rendering.
</description>
@@ -159,33 +159,33 @@
</method>
<method name="_set_anchor_detection_is_enabled" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="enabled" type="bool" />
+ <param index="0" name="enabled" type="bool" />
<description>
Enables anchor detection on this interface if supported.
</description>
</method>
<method name="_set_play_area_mode" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="mode" type="int" />
+ <param index="0" name="mode" type="int" />
<description>
Set the play area mode for this interface.
</description>
</method>
<method name="_supports_play_area_mode" qualifiers="virtual const">
<return type="bool" />
- <argument index="0" name="mode" type="int" enum="XRInterface.PlayAreaMode" />
+ <param index="0" name="mode" type="int" enum="XRInterface.PlayAreaMode" />
<description>
Returns [code]true[/code] if this interface supports this play area mode.
</description>
</method>
<method name="_trigger_haptic_pulse" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="action_name" type="String" />
- <argument index="1" name="tracker_name" type="StringName" />
- <argument index="2" name="frequency" type="float" />
- <argument index="3" name="amplitude" type="float" />
- <argument index="4" name="duration_sec" type="float" />
- <argument index="5" name="delay_sec" type="float" />
+ <param index="0" name="action_name" type="String" />
+ <param index="1" name="tracker_name" type="StringName" />
+ <param index="2" name="frequency" type="float" />
+ <param index="3" name="amplitude" type="float" />
+ <param index="4" name="duration_sec" type="float" />
+ <param index="5" name="delay_sec" type="float" />
<description>
Triggers a haptic pulse to be emitted on the specified tracker.
</description>
@@ -198,24 +198,24 @@
</method>
<method name="add_blit">
<return type="void" />
- <argument index="0" name="render_target" type="RID" />
- <argument index="1" name="src_rect" type="Rect2" />
- <argument index="2" name="dst_rect" type="Rect2i" />
- <argument index="3" name="use_layer" type="bool" />
- <argument index="4" name="layer" type="int" />
- <argument index="5" name="apply_lens_distortion" type="bool" />
- <argument index="6" name="eye_center" type="Vector2" />
- <argument index="7" name="k1" type="float" />
- <argument index="8" name="k2" type="float" />
- <argument index="9" name="upscale" type="float" />
- <argument index="10" name="aspect_ratio" type="float" />
+ <param index="0" name="render_target" type="RID" />
+ <param index="1" name="src_rect" type="Rect2" />
+ <param index="2" name="dst_rect" type="Rect2i" />
+ <param index="3" name="use_layer" type="bool" />
+ <param index="4" name="layer" type="int" />
+ <param index="5" name="apply_lens_distortion" type="bool" />
+ <param index="6" name="eye_center" type="Vector2" />
+ <param index="7" name="k1" type="float" />
+ <param index="8" name="k2" type="float" />
+ <param index="9" name="upscale" type="float" />
+ <param index="10" name="aspect_ratio" type="float" />
<description>
Blits our render results to screen optionally applying lens distortion. This can only be called while processing [code]_commit_views[/code].
</description>
</method>
<method name="get_render_target_texture">
<return type="RID" />
- <argument index="0" name="render_target" type="RID" />
+ <param index="0" name="render_target" type="RID" />
<description>
Returns a valid [RID] for a texture to which we should render the current frame if supported by the interface.
</description>
diff --git a/doc/classes/XRNode3D.xml b/doc/classes/XRNode3D.xml
index bb9dccc2e0..1507a3fe45 100644
--- a/doc/classes/XRNode3D.xml
+++ b/doc/classes/XRNode3D.xml
@@ -29,14 +29,14 @@
</method>
<method name="trigger_haptic_pulse">
<return type="void" />
- <argument index="0" name="action_name" type="String" />
- <argument index="1" name="frequency" type="float" />
- <argument index="2" name="amplitude" type="float" />
- <argument index="3" name="duration_sec" type="float" />
- <argument index="4" name="delay_sec" type="float" />
+ <param index="0" name="action_name" type="String" />
+ <param index="1" name="frequency" type="float" />
+ <param index="2" name="amplitude" type="float" />
+ <param index="3" name="duration_sec" type="float" />
+ <param index="4" name="delay_sec" type="float" />
<description>
Triggers a haptic pulse on a device associated with this interface.
- [code]action_name[/code] is the name of the action for this pulse.
+ [param action_name] is the name of the action for this pulse.
</description>
</method>
</methods>
diff --git a/doc/classes/XRPositionalTracker.xml b/doc/classes/XRPositionalTracker.xml
index c146b27fcb..db2910f25e 100644
--- a/doc/classes/XRPositionalTracker.xml
+++ b/doc/classes/XRPositionalTracker.xml
@@ -14,47 +14,47 @@
<methods>
<method name="get_input" qualifiers="const">
<return type="Variant" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
Returns an input for this tracker. It can return a boolean, float or [Vector2] value depending on whether the input is a button, trigger or thumbstick/thumbpad.
</description>
</method>
<method name="get_pose" qualifiers="const">
<return type="XRPose" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Returns the current [XRPose] state object for the bound [code]pose[/code].
+ Returns the current [XRPose] state object for the bound [param name] pose.
</description>
</method>
<method name="has_pose" qualifiers="const">
<return type="bool" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
- Returns [code]true[/code] if the bound [code]tracker[/code] is available and is currently tracking the bound [code]pose[/code].
+ Returns [code]true[/code] if the tracker is available and is currently tracking the bound [param name] pose.
</description>
</method>
<method name="invalidate_pose">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
+ <param index="0" name="name" type="StringName" />
<description>
Marks this pose as invalid, we don't clear the last reported state but it allows users to decide if trackers need to be hidden if we loose tracking or just remain at their last known position.
</description>
</method>
<method name="set_input">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="value" type="Variant" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="value" type="Variant" />
<description>
Changes the value for the given input. This method is called by a [XRInterface] implementation and should not be used directly.
</description>
</method>
<method name="set_pose">
<return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="transform" type="Transform3D" />
- <argument index="2" name="linear_velocity" type="Vector3" />
- <argument index="3" name="angular_velocity" type="Vector3" />
- <argument index="4" name="tracking_confidence" type="int" enum="XRPose.TrackingConfidence" />
+ <param index="0" name="name" type="StringName" />
+ <param index="1" name="transform" type="Transform3D" />
+ <param index="2" name="linear_velocity" type="Vector3" />
+ <param index="3" name="angular_velocity" type="Vector3" />
+ <param index="4" name="tracking_confidence" type="int" enum="XRPose.TrackingConfidence" />
<description>
Sets the transform, linear velocity, angular velocity and tracking confidence for the given pose. This method is called by a [XRInterface] implementation and should not be used directly.
</description>
@@ -81,39 +81,39 @@
</members>
<signals>
<signal name="button_pressed">
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
Emitted when a button on this tracker is pressed. Note that many XR runtimes allow other inputs to be mapped to buttons.
</description>
</signal>
<signal name="button_released">
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
Emitted when a button on this tracker is released.
</description>
</signal>
<signal name="input_axis_changed">
- <argument index="0" name="name" type="String" />
- <argument index="1" name="vector" type="Vector2" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="vector" type="Vector2" />
<description>
Emitted when a thumbstick or thumbpad on this tracker moves.
</description>
</signal>
<signal name="input_value_changed">
- <argument index="0" name="name" type="String" />
- <argument index="1" name="value" type="float" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="value" type="float" />
<description>
Emitted when a trigger or similar input on this tracker changes value.
</description>
</signal>
<signal name="pose_changed">
- <argument index="0" name="pose" type="XRPose" />
+ <param index="0" name="pose" type="XRPose" />
<description>
Emitted when the state of a pose tracked by this tracker changes.
</description>
</signal>
<signal name="profile_changed">
- <argument index="0" name="role" type="String" />
+ <param index="0" name="role" type="String" />
<description>
Emitted when the profile of our tracker changes.
</description>
diff --git a/doc/classes/XRServer.xml b/doc/classes/XRServer.xml
index d3cb958cbc..48b00323d3 100644
--- a/doc/classes/XRServer.xml
+++ b/doc/classes/XRServer.xml
@@ -12,22 +12,22 @@
<methods>
<method name="add_interface">
<return type="void" />
- <argument index="0" name="interface" type="XRInterface" />
+ <param index="0" name="interface" type="XRInterface" />
<description>
Registers an [XRInterface] object.
</description>
</method>
<method name="add_tracker">
<return type="void" />
- <argument index="0" name="tracker" type="XRPositionalTracker" />
+ <param index="0" name="tracker" type="XRPositionalTracker" />
<description>
Registers a new [XRPositionalTracker] that tracks a spatial location in real space.
</description>
</method>
<method name="center_on_hmd">
<return type="void" />
- <argument index="0" name="rotation_mode" type="int" enum="XRServer.RotationMode" />
- <argument index="1" name="keep_height" type="bool" />
+ <param index="0" name="rotation_mode" type="int" enum="XRServer.RotationMode" />
+ <param index="1" name="keep_height" type="bool" />
<description>
This is an important function to understand correctly. AR and VR platforms all handle positioning slightly differently.
For platforms that do not offer spatial tracking, our origin point (0,0,0) is the location of our HMD, but you have little control over the direction the player is facing in the real world.
@@ -39,9 +39,9 @@
</method>
<method name="find_interface" qualifiers="const">
<return type="XRInterface" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
- Finds an interface by its name. For instance, if your project uses capabilities of an AR/VR platform, you can find the interface for that platform by name and initialize it.
+ Finds an interface by its [param name]. For instance, if your project uses capabilities of an AR/VR platform, you can find the interface for that platform by name and initialize it.
</description>
</method>
<method name="get_hmd_transform">
@@ -52,9 +52,9 @@
</method>
<method name="get_interface" qualifiers="const">
<return type="XRInterface" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
- Returns the interface registered at a given index in our list of interfaces.
+ Returns the interface registered at the given [param idx] index in the list of interfaces.
</description>
</method>
<method name="get_interface_count" qualifiers="const">
@@ -64,7 +64,7 @@
</description>
</method>
<method name="get_interfaces" qualifiers="const">
- <return type="Array" />
+ <return type="Dictionary[]" />
<description>
Returns a list of available interfaces the ID and name of each interface.
</description>
@@ -77,30 +77,30 @@
</method>
<method name="get_tracker" qualifiers="const">
<return type="XRPositionalTracker" />
- <argument index="0" name="tracker_name" type="StringName" />
+ <param index="0" name="tracker_name" type="StringName" />
<description>
- Returns the positional tracker with this name.
+ Returns the positional tracker with the given [param tracker_name].
</description>
</method>
<method name="get_trackers">
<return type="Dictionary" />
- <argument index="0" name="tracker_types" type="int" />
+ <param index="0" name="tracker_types" type="int" />
<description>
- Returns a dictionary of trackers for this type.
+ Returns a dictionary of trackers for [param tracker_types].
</description>
</method>
<method name="remove_interface">
<return type="void" />
- <argument index="0" name="interface" type="XRInterface" />
+ <param index="0" name="interface" type="XRInterface" />
<description>
- Removes this interface.
+ Removes this [param interface].
</description>
</method>
<method name="remove_tracker">
<return type="void" />
- <argument index="0" name="tracker" type="XRPositionalTracker" />
+ <param index="0" name="tracker" type="XRPositionalTracker" />
<description>
- Removes this positional tracker.
+ Removes this positional [param tracker].
</description>
</method>
</methods>
@@ -114,34 +114,34 @@
</members>
<signals>
<signal name="interface_added">
- <argument index="0" name="interface_name" type="StringName" />
+ <param index="0" name="interface_name" type="StringName" />
<description>
Emitted when a new interface has been added.
</description>
</signal>
<signal name="interface_removed">
- <argument index="0" name="interface_name" type="StringName" />
+ <param index="0" name="interface_name" type="StringName" />
<description>
Emitted when an interface is removed.
</description>
</signal>
<signal name="tracker_added">
- <argument index="0" name="tracker_name" type="StringName" />
- <argument index="1" name="type" type="int" />
+ <param index="0" name="tracker_name" type="StringName" />
+ <param index="1" name="type" type="int" />
<description>
Emitted when a new tracker has been added. If you don't use a fixed number of controllers or if you're using [XRAnchor3D]s for an AR solution, it is important to react to this signal to add the appropriate [XRController3D] or [XRAnchor3D] nodes related to this new tracker.
</description>
</signal>
<signal name="tracker_removed">
- <argument index="0" name="tracker_name" type="StringName" />
- <argument index="1" name="type" type="int" />
+ <param index="0" name="tracker_name" type="StringName" />
+ <param index="1" name="type" type="int" />
<description>
Emitted when a tracker is removed. You should remove any [XRController3D] or [XRAnchor3D] points if applicable. This is not mandatory, the nodes simply become inactive and will be made active again when a new tracker becomes available (i.e. a new controller is switched on that takes the place of the previous one).
</description>
</signal>
<signal name="tracker_updated">
- <argument index="0" name="tracker_name" type="StringName" />
- <argument index="1" name="type" type="int" />
+ <param index="0" name="tracker_name" type="StringName" />
+ <param index="1" name="type" type="int" />
<description>
Emitted when an existing tracker has been updated. This can happen if the user switches controllers.
</description>
diff --git a/doc/classes/bool.xml b/doc/classes/bool.xml
index 374b703636..d0ef664281 100644
--- a/doc/classes/bool.xml
+++ b/doc/classes/bool.xml
@@ -100,21 +100,21 @@
</constructor>
<constructor name="bool">
<return type="bool" />
- <argument index="0" name="from" type="bool" />
+ <param index="0" name="from" type="bool" />
<description>
Constructs a [bool] as a copy of the given [bool].
</description>
</constructor>
<constructor name="bool">
<return type="bool" />
- <argument index="0" name="from" type="float" />
+ <param index="0" name="from" type="float" />
<description>
Cast a [float] value to a boolean value, this method will return [code]false[/code] if [code]0.0[/code] is passed in, and [code]true[/code] for all other floats.
</description>
</constructor>
<constructor name="bool">
<return type="bool" />
- <argument index="0" name="from" type="int" />
+ <param index="0" name="from" type="int" />
<description>
Cast an [int] value to a boolean value, this method will return [code]false[/code] if [code]0[/code] is passed in, and [code]true[/code] for all other ints.
</description>
@@ -123,28 +123,28 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="bool" />
+ <param index="0" name="right" type="bool" />
<description>
Returns [code]true[/code] if two bools are different, i.e. one is [code]true[/code] and the other is [code]false[/code].
</description>
</operator>
<operator name="operator &lt;">
<return type="bool" />
- <argument index="0" name="right" type="bool" />
+ <param index="0" name="right" type="bool" />
<description>
Returns [code]true[/code] if the left operand is [code]false[/code] and the right operand is [code]true[/code].
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="bool" />
+ <param index="0" name="right" type="bool" />
<description>
Returns [code]true[/code] if two bools are equal, i.e. both are [code]true[/code] or both are [code]false[/code].
</description>
</operator>
<operator name="operator &gt;">
<return type="bool" />
- <argument index="0" name="right" type="bool" />
+ <param index="0" name="right" type="bool" />
<description>
Returns [code]true[/code] if the left operand is [code]true[/code] and the right operand is [code]false[/code].
</description>
diff --git a/doc/classes/float.xml b/doc/classes/float.xml
index a7c6533ef5..9d685b9cd0 100644
--- a/doc/classes/float.xml
+++ b/doc/classes/float.xml
@@ -21,21 +21,21 @@
</constructor>
<constructor name="float">
<return type="float" />
- <argument index="0" name="from" type="float" />
+ <param index="0" name="from" type="float" />
<description>
Constructs a [float] as a copy of the given [float].
</description>
</constructor>
<constructor name="float">
<return type="float" />
- <argument index="0" name="from" type="bool" />
+ <param index="0" name="from" type="bool" />
<description>
Cast a [bool] value to a floating-point value, [code]float(true)[/code] will be equal to 1.0 and [code]float(false)[/code] will be equal to 0.0.
</description>
</constructor>
<constructor name="float">
<return type="float" />
- <argument index="0" name="from" type="int" />
+ <param index="0" name="from" type="int" />
<description>
Cast an [int] value to a floating-point value, [code]float(1)[/code] will be equal to [code]1.0[/code].
</description>
@@ -44,21 +44,21 @@
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Returns [code]true[/code] if two floats are different from each other.
</description>
</operator>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Returns [code]true[/code] if the integer has different value than the float.
</description>
</operator>
<operator name="operator *">
<return type="Color" />
- <argument index="0" name="right" type="Color" />
+ <param index="0" name="right" type="Color" />
<description>
Multiplies each component of the [Color] by the given [float].
[codeblock]
@@ -68,14 +68,14 @@
</operator>
<operator name="operator *">
<return type="Quaternion" />
- <argument index="0" name="right" type="Quaternion" />
+ <param index="0" name="right" type="Quaternion" />
<description>
Multiplies each component of the [Quaternion] by the given [float]. This operation is not meaningful on its own, but it can be used as a part of a larger expression.
</description>
</operator>
<operator name="operator *">
<return type="Vector2" />
- <argument index="0" name="right" type="Vector2" />
+ <param index="0" name="right" type="Vector2" />
<description>
Multiplies each component of the [Vector2] by the given [float].
[codeblock]
@@ -85,7 +85,7 @@
</operator>
<operator name="operator *">
<return type="Vector2" />
- <argument index="0" name="right" type="Vector2i" />
+ <param index="0" name="right" type="Vector2i" />
<description>
Multiplies each component of the [Vector2i] by the given [float]. Returns a [Vector2].
[codeblock]
@@ -95,14 +95,14 @@
</operator>
<operator name="operator *">
<return type="Vector3" />
- <argument index="0" name="right" type="Vector3" />
+ <param index="0" name="right" type="Vector3" />
<description>
Multiplies each component of the [Vector3] by the given [float].
</description>
</operator>
<operator name="operator *">
<return type="Vector3" />
- <argument index="0" name="right" type="Vector3i" />
+ <param index="0" name="right" type="Vector3i" />
<description>
Multiplies each component of the [Vector3i] by the given [float]. Returns a [Vector3].
[codeblock]
@@ -112,115 +112,115 @@
</operator>
<operator name="operator *">
<return type="Vector4" />
- <argument index="0" name="right" type="Vector4" />
+ <param index="0" name="right" type="Vector4" />
<description>
</description>
</operator>
<operator name="operator *">
<return type="Vector4" />
- <argument index="0" name="right" type="Vector4i" />
+ <param index="0" name="right" type="Vector4i" />
<description>
</description>
</operator>
<operator name="operator *">
<return type="float" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Multiplies two [float]s.
</description>
</operator>
<operator name="operator *">
<return type="float" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Multiplies a [float] and an [int]. The result is a [float].
</description>
</operator>
<operator name="operator **">
<return type="float" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
</description>
</operator>
<operator name="operator **">
<return type="float" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
</description>
</operator>
<operator name="operator +">
<return type="float" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Adds two floats.
</description>
</operator>
<operator name="operator +">
<return type="float" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Adds a [float] and an [int]. The result is a [float].
</description>
</operator>
<operator name="operator -">
<return type="float" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Subtracts a float from a float.
</description>
</operator>
<operator name="operator -">
<return type="float" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Subtracts an [int] from a [float]. The result is a [float].
</description>
</operator>
<operator name="operator /">
<return type="float" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Divides two floats.
</description>
</operator>
<operator name="operator /">
<return type="float" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Divides a [float] by an [int]. The result is a [float].
</description>
</operator>
<operator name="operator &lt;">
<return type="bool" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Returns [code]true[/code] the left float is less than the right one.
</description>
</operator>
<operator name="operator &lt;">
<return type="bool" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Returns [code]true[/code] if this [float] is less than the given [int].
</description>
</operator>
<operator name="operator &lt;=">
<return type="bool" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Returns [code]true[/code] the left integer is less than or equal to the right one.
</description>
</operator>
<operator name="operator &lt;=">
<return type="bool" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Returns [code]true[/code] if this [float] is less than or equal to the given [int].
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Returns [code]true[/code] if both floats are exactly equal.
[b]Note:[/b] Due to floating-point precision errors, consider using [method @GlobalScope.is_equal_approx] or [method @GlobalScope.is_zero_approx] instead, which are more reliable.
@@ -228,35 +228,35 @@
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Returns [code]true[/code] if the [float] and the given [int] are equal.
</description>
</operator>
<operator name="operator &gt;">
<return type="bool" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Returns [code]true[/code] the left float is greater than the right one.
</description>
</operator>
<operator name="operator &gt;">
<return type="bool" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Returns [code]true[/code] if this [float] is greater than the given [int].
</description>
</operator>
<operator name="operator &gt;=">
<return type="bool" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Returns [code]true[/code] the left float is greater than or equal to the right one.
</description>
</operator>
<operator name="operator &gt;=">
<return type="bool" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Returns [code]true[/code] if this [float] is greater than or equal to the given [int].
</description>
diff --git a/doc/classes/int.xml b/doc/classes/int.xml
index 6b492ca923..78e2e7d18f 100644
--- a/doc/classes/int.xml
+++ b/doc/classes/int.xml
@@ -47,44 +47,44 @@
</constructor>
<constructor name="int">
<return type="int" />
- <argument index="0" name="from" type="int" />
+ <param index="0" name="from" type="int" />
<description>
Constructs an [int] as a copy of the given [int].
</description>
</constructor>
<constructor name="int">
<return type="int" />
- <argument index="0" name="from" type="bool" />
+ <param index="0" name="from" type="bool" />
<description>
Cast a [bool] value to an integer value, [code]int(true)[/code] will be equals to 1 and [code]int(false)[/code] will be equals to 0.
</description>
</constructor>
<constructor name="int">
<return type="int" />
- <argument index="0" name="from" type="float" />
+ <param index="0" name="from" type="float" />
<description>
- Cast a float value to an integer value, this method simply removes the number fractions (i.e. rounds [code]from[/code] towards zero), so for example [code]int(2.7)[/code] will be equals to 2, [code]int(0.1)[/code] will be equals to 0 and [code]int(-2.7)[/code] will be equals to -2. This operation is also called truncation.
+ Cast a float value to an integer value, this method simply removes the number fractions (i.e. rounds [param from] towards zero), so for example [code]int(2.7)[/code] will be equals to 2, [code]int(0.1)[/code] will be equals to 0 and [code]int(-2.7)[/code] will be equals to -2. This operation is also called truncation.
</description>
</constructor>
</constructors>
<operators>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Returns [code]true[/code] if operands are different from each other.
</description>
</operator>
<operator name="operator !=">
<return type="bool" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Returns [code]true[/code] if operands are different from each other.
</description>
</operator>
<operator name="operator %">
<return type="int" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Returns the remainder after dividing two integers. This operation uses truncated division, which is often not desired as it does not work well with negative numbers. Consider using [method @GlobalScope.posmod] instead if you want to handle negative numbers.
[codeblock]
@@ -96,7 +96,7 @@
</operator>
<operator name="operator &amp;">
<return type="int" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Returns the result of bitwise [code]AND[/code] operation for two integers.
[codeblock]
@@ -114,21 +114,21 @@
</operator>
<operator name="operator *">
<return type="Color" />
- <argument index="0" name="right" type="Color" />
+ <param index="0" name="right" type="Color" />
<description>
Multiplies each component of the [Color] by the given [int].
</description>
</operator>
<operator name="operator *">
<return type="Quaternion" />
- <argument index="0" name="right" type="Quaternion" />
+ <param index="0" name="right" type="Quaternion" />
<description>
Multiplies each component of the [Quaternion] by the given [int]. This operation is not meaningful on its own, but it can be used as a part of a larger expression.
</description>
</operator>
<operator name="operator *">
<return type="Vector2" />
- <argument index="0" name="right" type="Vector2" />
+ <param index="0" name="right" type="Vector2" />
<description>
Multiplies each component of the [Vector2] by the given [int].
[codeblock]
@@ -138,101 +138,101 @@
</operator>
<operator name="operator *">
<return type="Vector2i" />
- <argument index="0" name="right" type="Vector2i" />
+ <param index="0" name="right" type="Vector2i" />
<description>
Multiplies each component of the [Vector2i] by the given [int].
</description>
</operator>
<operator name="operator *">
<return type="Vector3" />
- <argument index="0" name="right" type="Vector3" />
+ <param index="0" name="right" type="Vector3" />
<description>
Multiplies each component of the [Vector3] by the given [int].
</description>
</operator>
<operator name="operator *">
<return type="Vector3i" />
- <argument index="0" name="right" type="Vector3i" />
+ <param index="0" name="right" type="Vector3i" />
<description>
Multiplies each component of the [Vector3i] by the given [int].
</description>
</operator>
<operator name="operator *">
<return type="Vector4" />
- <argument index="0" name="right" type="Vector4" />
+ <param index="0" name="right" type="Vector4" />
<description>
</description>
</operator>
<operator name="operator *">
<return type="Vector4i" />
- <argument index="0" name="right" type="Vector4i" />
+ <param index="0" name="right" type="Vector4i" />
<description>
</description>
</operator>
<operator name="operator *">
<return type="float" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Multiplies an [int] and a [float]. The result is a [float].
</description>
</operator>
<operator name="operator *">
<return type="int" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Multiplies two [int]s.
</description>
</operator>
<operator name="operator **">
<return type="float" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
</description>
</operator>
<operator name="operator **">
<return type="int" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
</description>
</operator>
<operator name="operator +">
<return type="String" />
- <argument index="0" name="right" type="String" />
+ <param index="0" name="right" type="String" />
<description>
Adds Unicode character with code [int] to the [String].
</description>
</operator>
<operator name="operator +">
<return type="float" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Adds an [int] and a [float]. The result is a [float].
</description>
</operator>
<operator name="operator +">
<return type="int" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Adds two integers.
</description>
</operator>
<operator name="operator -">
<return type="float" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Subtracts a [float] from an [int]. The result is a [float].
</description>
</operator>
<operator name="operator -">
<return type="int" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Subtracts two integers.
</description>
</operator>
<operator name="operator /">
<return type="float" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Divides an [int] by a [float]. The result is a [float].
[codeblock]
@@ -242,7 +242,7 @@
</operator>
<operator name="operator /">
<return type="int" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Divides two integers. The decimal part of the result is discarded (truncated).
[codeblock]
@@ -253,21 +253,21 @@
</operator>
<operator name="operator &lt;">
<return type="bool" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Returns [code]true[/code] if this [int] is less than the given [float].
</description>
</operator>
<operator name="operator &lt;">
<return type="bool" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Returns [code]true[/code] the left integer is less than the right one.
</description>
</operator>
<operator name="operator &lt;&lt;">
<return type="int" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Performs bitwise shift left operation on the integer. Effectively the same as multiplying by a power of 2.
[codeblock]
@@ -278,63 +278,63 @@
</operator>
<operator name="operator &lt;=">
<return type="bool" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Returns [code]true[/code] if this [int] is less than or equal to the given [float].
</description>
</operator>
<operator name="operator &lt;=">
<return type="bool" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Returns [code]true[/code] the left integer is less than or equal to the right one.
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Returns [code]true[/code] if the integer is equal to the given [float].
</description>
</operator>
<operator name="operator ==">
<return type="bool" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Returns [code]true[/code] if both integers are equal.
</description>
</operator>
<operator name="operator &gt;">
<return type="bool" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Returns [code]true[/code] if this [int] is greater than the given [float].
</description>
</operator>
<operator name="operator &gt;">
<return type="bool" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Returns [code]true[/code] the left integer is greater than the right one.
</description>
</operator>
<operator name="operator &gt;=">
<return type="bool" />
- <argument index="0" name="right" type="float" />
+ <param index="0" name="right" type="float" />
<description>
Returns [code]true[/code] if this [int] is greater than or equal to the given [float].
</description>
</operator>
<operator name="operator &gt;=">
<return type="bool" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Returns [code]true[/code] the left integer is greater than or equal to the right one.
</description>
</operator>
<operator name="operator &gt;&gt;">
<return type="int" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Performs bitwise shift right operation on the integer. Effectively the same as dividing by a power of 2.
[codeblock]
@@ -345,7 +345,7 @@
</operator>
<operator name="operator ^">
<return type="int" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Returns the result of bitwise [code]XOR[/code] operation for two integers.
[codeblock]
@@ -368,7 +368,7 @@
</operator>
<operator name="operator |">
<return type="int" />
- <argument index="0" name="right" type="int" />
+ <param index="0" name="right" type="int" />
<description>
Returns the result of bitwise [code]OR[/code] operation for two integers.
[codeblock]
diff --git a/doc/tools/doc_status.py b/doc/tools/doc_status.py
index cc0733cab2..376addcff0 100755
--- a/doc/tools/doc_status.py
+++ b/doc/tools/doc_status.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
import fnmatch
import os
@@ -7,6 +7,7 @@ import re
import math
import platform
import xml.etree.ElementTree as ET
+from typing import Dict, List, Set
################################################################################
# Config #
@@ -103,13 +104,13 @@ overall_progress_description_weight = 10
################################################################################
-def validate_tag(elem, tag):
+def validate_tag(elem: ET.Element, tag: str) -> None:
if elem.tag != tag:
print('Tag mismatch, expected "' + tag + '", got ' + elem.tag)
sys.exit(255)
-def color(color, string):
+def color(color: str, string: str) -> str:
if flags["c"] and terminal_supports_color():
color_format = ""
for code in colors[color]:
@@ -122,7 +123,7 @@ def color(color, string):
ansi_escape = re.compile(r"\x1b[^m]*m")
-def nonescape_len(s):
+def nonescape_len(s: str) -> int:
return len(ansi_escape.sub("", s))
@@ -142,14 +143,14 @@ def terminal_supports_color():
class ClassStatusProgress:
- def __init__(self, described=0, total=0):
- self.described = described
- self.total = total
+ def __init__(self, described: int = 0, total: int = 0):
+ self.described: int = described
+ self.total: int = total
- def __add__(self, other):
+ def __add__(self, other: "ClassStatusProgress"):
return ClassStatusProgress(self.described + other.described, self.total + other.total)
- def increment(self, described):
+ def increment(self, described: bool):
if described:
self.described += 1
self.total += 1
@@ -163,7 +164,7 @@ class ClassStatusProgress:
else:
return self.to_colored_string()
- def to_colored_string(self, format="{has}/{total}", pad_format="{pad_described}{s}{pad_total}"):
+ def to_colored_string(self, format: str = "{has}/{total}", pad_format: str = "{pad_described}{s}{pad_total}"):
ratio = float(self.described) / float(self.total) if self.total != 0 else 1
percent = int(round(100 * ratio))
s = format.format(has=str(self.described), total=str(self.total), percent=str(percent))
@@ -183,11 +184,11 @@ class ClassStatusProgress:
class ClassStatus:
- def __init__(self, name=""):
- self.name = name
- self.has_brief_description = True
- self.has_description = True
- self.progresses = {
+ def __init__(self, name: str = ""):
+ self.name: str = name
+ self.has_brief_description: bool = True
+ self.has_description: bool = True
+ self.progresses: Dict[str, ClassStatusProgress] = {
"methods": ClassStatusProgress(),
"constants": ClassStatusProgress(),
"members": ClassStatusProgress(),
@@ -197,7 +198,7 @@ class ClassStatus:
"constructors": ClassStatusProgress(),
}
- def __add__(self, other):
+ def __add__(self, other: "ClassStatus"):
new_status = ClassStatus()
new_status.name = self.name
new_status.has_brief_description = self.has_brief_description and other.has_brief_description
@@ -222,8 +223,8 @@ class ClassStatus:
sum += self.progresses[k].total
return sum < 1
- def make_output(self):
- output = {}
+ def make_output(self) -> Dict[str, str]:
+ output: Dict[str, str] = {}
output["name"] = color("name", self.name)
ok_string = color("part_good", "OK")
@@ -263,22 +264,24 @@ class ClassStatus:
return output
@staticmethod
- def generate_for_class(c):
+ def generate_for_class(c: ET.Element):
status = ClassStatus()
status.name = c.attrib["name"]
for tag in list(c):
+ len_tag_text = 0 if (tag.text is None) else len(tag.text.strip())
if tag.tag == "brief_description":
- status.has_brief_description = len(tag.text.strip()) > 0
+ status.has_brief_description = len_tag_text > 0
elif tag.tag == "description":
- status.has_description = len(tag.text.strip()) > 0
+ status.has_description = len_tag_text > 0
elif tag.tag in ["methods", "signals", "operators", "constructors"]:
for sub_tag in list(tag):
descr = sub_tag.find("description")
- status.progresses[tag.tag].increment(len(descr.text.strip()) > 0)
+ increment = (descr is not None) and (descr.text is not None) and len(descr.text.strip()) > 0
+ status.progresses[tag.tag].increment(increment)
elif tag.tag in ["constants", "members", "theme_items"]:
for sub_tag in list(tag):
if not sub_tag.text is None:
@@ -297,9 +300,9 @@ class ClassStatus:
# Arguments #
################################################################################
-input_file_list = []
-input_class_list = []
-merged_file = ""
+input_file_list: List[str] = []
+input_class_list: List[str] = []
+merged_file: str = ""
for arg in sys.argv[1:]:
try:
@@ -373,8 +376,8 @@ if len(input_file_list) < 1 or flags["h"]:
# Parse class list #
################################################################################
-class_names = []
-classes = {}
+class_names: List[str] = []
+classes: Dict[str, ET.Element] = {}
for file in input_file_list:
tree = ET.parse(file)
@@ -396,10 +399,10 @@ class_names.sort()
if len(input_class_list) < 1:
input_class_list = ["*"]
-filtered_classes = set()
+filtered_classes_set: Set[str] = set()
for pattern in input_class_list:
- filtered_classes |= set(fnmatch.filter(class_names, pattern))
-filtered_classes = list(filtered_classes)
+ filtered_classes_set |= set(fnmatch.filter(class_names, pattern))
+filtered_classes = list(filtered_classes_set)
filtered_classes.sort()
################################################################################
@@ -413,7 +416,6 @@ table_column_chars = "|"
total_status = ClassStatus("Total")
for cn in filtered_classes:
-
c = classes[cn]
validate_tag(c, "class")
status = ClassStatus.generate_for_class(c)
@@ -427,7 +429,7 @@ for cn in filtered_classes:
continue
out = status.make_output()
- row = []
+ row: List[str] = []
for column in table_columns:
if column in out:
row.append(out[column])
@@ -464,7 +466,7 @@ if flags["a"]:
# without having to scroll back to the top.
table.append(table_column_names)
-table_column_sizes = []
+table_column_sizes: List[int] = []
for row in table:
for cell_i, cell in enumerate(row):
if cell_i >= len(table_column_sizes):
@@ -477,7 +479,6 @@ for cell_i in range(len(table[0])):
divider_string += (
table_row_chars[1] + table_row_chars[2] * (table_column_sizes[cell_i]) + table_row_chars[1] + table_row_chars[0]
)
-print(divider_string)
for row_i, row in enumerate(table):
row_string = table_column_chars
diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py
index 469bb4a310..bc50e39812 100755
--- a/doc/tools/make_rst.py
+++ b/doc/tools/make_rst.py
@@ -9,15 +9,13 @@ import re
import sys
import xml.etree.ElementTree as ET
from collections import OrderedDict
+from typing import List, Dict, TextIO, Tuple, Optional, Any, Union
# Import hardcoded version information from version.py
root_directory = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../")
sys.path.append(root_directory) # Include the root directory
import version
-# Uncomment to do type checks. I have it commented out so it works below Python 3.5
-# from typing import List, Dict, TextIO, Tuple, Iterable, Optional, DefaultDict, Any, Union
-
# $DOCS_URL/path/to/page.html(#fragment-tag)
GODOT_DOCS_PATTERN = re.compile(r"^\$DOCS_URL/(.*)\.html(#.*)?$")
@@ -61,127 +59,21 @@ BASE_STRINGS = [
"This method doesn't need an instance to be called, so it can be called directly using the class name.",
"This method describes a valid operator to use with this type as left-hand operand.",
]
-strings_l10n = {}
-
-STYLES = {}
-
-
-def print_error(error, state): # type: (str, State) -> None
- print("{}{}ERROR:{} {}{}".format(STYLES["red"], STYLES["bold"], STYLES["regular"], error, STYLES["reset"]))
- state.num_errors += 1
-
-
-class TypeName:
- def __init__(self, type_name, enum=None): # type: (str, Optional[str]) -> None
- self.type_name = type_name
- self.enum = enum
-
- def to_rst(self, state): # type: ("State") -> str
- if self.enum is not None:
- return make_enum(self.enum, state)
- elif self.type_name == "void":
- return "void"
- else:
- return make_type(self.type_name, state)
-
- @classmethod
- def from_element(cls, element): # type: (ET.Element) -> "TypeName"
- return cls(element.attrib["type"], element.get("enum"))
-
-
-class PropertyDef:
- def __init__(
- self, name, type_name, setter, getter, text, default_value, overrides
- ): # type: (str, TypeName, Optional[str], Optional[str], Optional[str], Optional[str], Optional[str]) -> None
- self.name = name
- self.type_name = type_name
- self.setter = setter
- self.getter = getter
- self.text = text
- self.default_value = default_value
- self.overrides = overrides
-
-
-class ParameterDef:
- def __init__(self, name, type_name, default_value): # type: (str, TypeName, Optional[str]) -> None
- self.name = name
- self.type_name = type_name
- self.default_value = default_value
-
-
-class SignalDef:
- def __init__(self, name, parameters, description): # type: (str, List[ParameterDef], Optional[str]) -> None
- self.name = name
- self.parameters = parameters
- self.description = description
-
-
-class MethodDef:
- def __init__(
- self, name, return_type, parameters, description, qualifiers
- ): # type: (str, TypeName, List[ParameterDef], Optional[str], Optional[str]) -> None
- self.name = name
- self.return_type = return_type
- self.parameters = parameters
- self.description = description
- self.qualifiers = qualifiers
+strings_l10n: Dict[str, str] = {}
-
-class ConstantDef:
- def __init__(self, name, value, text, bitfield): # type: (str, str, Optional[str], Optional[bool]) -> None
- self.name = name
- self.value = value
- self.text = text
- self.is_bitfield = bitfield
-
-
-class EnumDef:
- def __init__(self, name, bitfield): # type: (str, Optional[bool]) -> None
- self.name = name
- self.values = OrderedDict() # type: OrderedDict[str, ConstantDef]
- self.is_bitfield = bitfield
-
-
-class ThemeItemDef:
- def __init__(
- self, name, type_name, data_name, text, default_value
- ): # type: (str, TypeName, str, Optional[str], Optional[str]) -> None
- self.name = name
- self.type_name = type_name
- self.data_name = data_name
- self.text = text
- self.default_value = default_value
-
-
-class ClassDef:
- def __init__(self, name): # type: (str) -> None
- self.name = name
- self.constants = OrderedDict() # type: OrderedDict[str, ConstantDef]
- self.enums = OrderedDict() # type: OrderedDict[str, EnumDef]
- self.properties = OrderedDict() # type: OrderedDict[str, PropertyDef]
- self.constructors = OrderedDict() # type: OrderedDict[str, List[MethodDef]]
- self.methods = OrderedDict() # type: OrderedDict[str, List[MethodDef]]
- self.operators = OrderedDict() # type: OrderedDict[str, List[MethodDef]]
- self.signals = OrderedDict() # type: OrderedDict[str, SignalDef]
- self.annotations = OrderedDict() # type: OrderedDict[str, List[MethodDef]]
- self.theme_items = OrderedDict() # type: OrderedDict[str, ThemeItemDef]
- self.inherits = None # type: Optional[str]
- self.brief_description = None # type: Optional[str]
- self.description = None # type: Optional[str]
- self.tutorials = [] # type: List[Tuple[str, str]]
-
- # Used to match the class with XML source for output filtering purposes.
- self.filepath = "" # type: str
+STYLES: Dict[str, str] = {}
class State:
- def __init__(self): # type: () -> None
+ def __init__(self) -> None:
self.num_errors = 0
- self.classes = OrderedDict() # type: OrderedDict[str, ClassDef]
- self.current_class = "" # type: str
+ self.num_warnings = 0
+ self.classes: OrderedDict[str, ClassDef] = OrderedDict()
+ self.current_class: str = ""
- def parse_class(self, class_root, filepath): # type: (ET.Element, str) -> None
+ def parse_class(self, class_root: ET.Element, filepath: str) -> None:
class_name = class_root.attrib["name"]
+ self.current_class = class_name
class_def = ClassDef(class_name)
self.classes[class_name] = class_def
@@ -233,11 +125,10 @@ class State:
return_element = constructor.find("return")
if return_element is not None:
return_type = TypeName.from_element(return_element)
-
else:
return_type = TypeName("void")
- params = parse_arguments(constructor)
+ params = self.parse_params(constructor, "constructor")
desc_element = constructor.find("description")
method_desc = None
@@ -245,6 +136,7 @@ class State:
method_desc = desc_element.text
method_def = MethodDef(method_name, return_type, params, method_desc, qualifiers)
+ method_def.definition_name = "constructor"
if method_name not in class_def.constructors:
class_def.constructors[method_name] = []
@@ -265,7 +157,7 @@ class State:
else:
return_type = TypeName("void")
- params = parse_arguments(method)
+ params = self.parse_params(method, "method")
desc_element = method.find("description")
method_desc = None
@@ -293,7 +185,7 @@ class State:
else:
return_type = TypeName("void")
- params = parse_arguments(operator)
+ params = self.parse_params(operator, "operator")
desc_element = operator.find("description")
method_desc = None
@@ -301,6 +193,7 @@ class State:
method_desc = desc_element.text
method_def = MethodDef(method_name, return_type, params, method_desc, qualifiers)
+ method_def.definition_name = "operator"
if method_name not in class_def.operators:
class_def.operators[method_name] = []
@@ -314,7 +207,7 @@ class State:
constant_name = constant.attrib["name"]
value = constant.attrib["value"]
enum = constant.get("enum")
- is_bitfield = constant.get("is_bitfield") or False
+ is_bitfield = constant.get("is_bitfield") == "true"
constant_def = ConstantDef(constant_name, value, constant.text, is_bitfield)
if enum is None:
if constant_name in class_def.constants:
@@ -341,14 +234,14 @@ class State:
annotation_name = annotation.attrib["name"]
qualifiers = annotation.get("qualifiers")
- params = parse_arguments(annotation)
+ params = self.parse_params(annotation, "annotation")
desc_element = annotation.find("description")
annotation_desc = None
if desc_element is not None:
annotation_desc = desc_element.text
- annotation_def = MethodDef(annotation_name, return_type, params, annotation_desc, qualifiers)
+ annotation_def = AnnotationDef(annotation_name, params, annotation_desc, qualifiers)
if annotation_name not in class_def.annotations:
class_def.annotations[annotation_name] = []
@@ -365,7 +258,7 @@ class State:
print_error('{}.xml: Duplicate signal "{}".'.format(class_name, signal_name), self)
continue
- params = parse_arguments(signal)
+ params = self.parse_params(signal, "signal")
desc_element = signal.find("description")
signal_desc = None
@@ -413,31 +306,190 @@ class State:
if link.text is not None:
class_def.tutorials.append((link.text.strip(), link.get("title", "")))
- def sort_classes(self): # type: () -> None
+ self.current_class = ""
+
+ def parse_params(self, root: ET.Element, context: str) -> List["ParameterDef"]:
+ param_elements = root.findall("param")
+ params: Any = [None] * len(param_elements)
+
+ for param_index, param_element in enumerate(param_elements):
+ param_name = param_element.attrib["name"]
+ index = int(param_element.attrib["index"])
+ type_name = TypeName.from_element(param_element)
+ default = param_element.get("default")
+
+ if param_name.strip() == "" or param_name.startswith("_unnamed_arg"):
+ print_error(
+ '{}.xml: Empty argument name in {} "{}" at position {}.'.format(
+ self.current_class, context, root.attrib["name"], param_index
+ ),
+ self,
+ )
+
+ params[index] = ParameterDef(param_name, type_name, default)
+
+ cast: List[ParameterDef] = params
+
+ return cast
+
+ def sort_classes(self) -> None:
self.classes = OrderedDict(sorted(self.classes.items(), key=lambda t: t[0]))
-def parse_arguments(root): # type: (ET.Element) -> List[ParameterDef]
- param_elements = root.findall("argument")
- params = [None] * len(param_elements) # type: Any
- for param_element in param_elements:
- param_name = param_element.attrib["name"]
- index = int(param_element.attrib["index"])
- type_name = TypeName.from_element(param_element)
- default = param_element.get("default")
+class TypeName:
+ def __init__(self, type_name: str, enum: Optional[str] = None) -> None:
+ self.type_name = type_name
+ self.enum = enum
+
+ def to_rst(self, state: State) -> str:
+ if self.enum is not None:
+ return make_enum(self.enum, state)
+ elif self.type_name == "void":
+ return "void"
+ else:
+ return make_type(self.type_name, state)
+
+ @classmethod
+ def from_element(cls, element: ET.Element) -> "TypeName":
+ return cls(element.attrib["type"], element.get("enum"))
+
+
+class DefinitionBase:
+ def __init__(
+ self,
+ definition_name: str,
+ name: str,
+ ) -> None:
+ self.definition_name = definition_name
+ self.name = name
+
+
+class PropertyDef(DefinitionBase):
+ def __init__(
+ self,
+ name: str,
+ type_name: TypeName,
+ setter: Optional[str],
+ getter: Optional[str],
+ text: Optional[str],
+ default_value: Optional[str],
+ overrides: Optional[str],
+ ) -> None:
+ super().__init__("property", name)
+
+ self.type_name = type_name
+ self.setter = setter
+ self.getter = getter
+ self.text = text
+ self.default_value = default_value
+ self.overrides = overrides
+
+
+class ParameterDef(DefinitionBase):
+ def __init__(self, name: str, type_name: TypeName, default_value: Optional[str]) -> None:
+ super().__init__("parameter", name)
+
+ self.type_name = type_name
+ self.default_value = default_value
+
+
+class SignalDef(DefinitionBase):
+ def __init__(self, name: str, parameters: List[ParameterDef], description: Optional[str]) -> None:
+ super().__init__("signal", name)
+
+ self.parameters = parameters
+ self.description = description
+
+
+class AnnotationDef(DefinitionBase):
+ def __init__(
+ self,
+ name: str,
+ parameters: List[ParameterDef],
+ description: Optional[str],
+ qualifiers: Optional[str],
+ ) -> None:
+ super().__init__("annotation", name)
+
+ self.parameters = parameters
+ self.description = description
+ self.qualifiers = qualifiers
+
+
+class MethodDef(DefinitionBase):
+ def __init__(
+ self,
+ name: str,
+ return_type: TypeName,
+ parameters: List[ParameterDef],
+ description: Optional[str],
+ qualifiers: Optional[str],
+ ) -> None:
+ super().__init__("method", name)
+
+ self.return_type = return_type
+ self.parameters = parameters
+ self.description = description
+ self.qualifiers = qualifiers
+
- params[index] = ParameterDef(param_name, type_name, default)
+class ConstantDef(DefinitionBase):
+ def __init__(self, name: str, value: str, text: Optional[str], bitfield: bool) -> None:
+ super().__init__("constant", name)
- cast = params # type: List[ParameterDef]
+ self.value = value
+ self.text = text
+ self.is_bitfield = bitfield
- return cast
+class EnumDef(DefinitionBase):
+ def __init__(self, name: str, bitfield: bool) -> None:
+ super().__init__("enum", name)
-def main(): # type: () -> None
+ self.values: OrderedDict[str, ConstantDef] = OrderedDict()
+ self.is_bitfield = bitfield
+
+
+class ThemeItemDef(DefinitionBase):
+ def __init__(
+ self, name: str, type_name: TypeName, data_name: str, text: Optional[str], default_value: Optional[str]
+ ) -> None:
+ super().__init__("theme item", name)
+
+ self.type_name = type_name
+ self.data_name = data_name
+ self.text = text
+ self.default_value = default_value
+
+
+class ClassDef(DefinitionBase):
+ def __init__(self, name: str) -> None:
+ super().__init__("class", name)
+
+ self.constants: OrderedDict[str, ConstantDef] = OrderedDict()
+ self.enums: OrderedDict[str, EnumDef] = OrderedDict()
+ self.properties: OrderedDict[str, PropertyDef] = OrderedDict()
+ self.constructors: OrderedDict[str, List[MethodDef]] = OrderedDict()
+ self.methods: OrderedDict[str, List[MethodDef]] = OrderedDict()
+ self.operators: OrderedDict[str, List[MethodDef]] = OrderedDict()
+ self.signals: OrderedDict[str, SignalDef] = OrderedDict()
+ self.annotations: OrderedDict[str, List[AnnotationDef]] = OrderedDict()
+ self.theme_items: OrderedDict[str, ThemeItemDef] = OrderedDict()
+ self.inherits: Optional[str] = None
+ self.brief_description: Optional[str] = None
+ self.description: Optional[str] = None
+ self.tutorials: List[Tuple[str, str]] = []
+
+ # Used to match the class with XML source for output filtering purposes.
+ self.filepath: str = ""
+
+
+# Entry point for the RST generator.
+def main() -> None:
# Enable ANSI escape code support on Windows 10 and later (for colored console output).
# <https://bugs.python.org/issue29059>
if platform.system().lower() == "windows":
- from ctypes import windll, c_int, byref
+ from ctypes import windll, c_int, byref # type: ignore
stdout_handle = windll.kernel32.GetStdHandle(c_int(-11))
mode = c_int(0)
@@ -466,6 +518,7 @@ def main(): # type: () -> None
should_color = args.color or (hasattr(sys.stdout, "isatty") and sys.stdout.isatty())
STYLES["red"] = "\x1b[91m" if should_color else ""
STYLES["green"] = "\x1b[92m" if should_color else ""
+ STYLES["yellow"] = "\x1b[93m" if should_color else ""
STYLES["bold"] = "\x1b[1m" if should_color else ""
STYLES["regular"] = "\x1b[22m" if should_color else ""
STYLES["reset"] = "\x1b[0m" if should_color else ""
@@ -491,7 +544,7 @@ def main(): # type: () -> None
print("Checking for errors in the XML class reference...")
- file_list = [] # type: List[str]
+ file_list: List[str] = []
for path in args.path:
# Cut off trailing slashes so os.path.basename doesn't choke.
@@ -515,7 +568,7 @@ def main(): # type: () -> None
file_list.append(path)
- classes = {} # type: Dict[str, ET.Element]
+ classes: Dict[str, Tuple[ET.Element, str]] = {}
state = State()
for cur_file in file_list:
@@ -550,12 +603,29 @@ def main(): # type: () -> None
# Create the output folder recursively if it doesn't already exist.
os.makedirs(args.output, exist_ok=True)
+ print("Generating the RST class reference...")
+
for class_name, class_def in state.classes.items():
if args.filter and not pattern.search(class_def.filepath):
continue
state.current_class = class_name
make_rst_class(class_def, state, args.dry_run, args.output)
+ print("")
+
+ if state.num_warnings >= 2:
+ print(
+ "{}{} warnings were found in the class reference XML. Please check the messages above.{}".format(
+ STYLES["yellow"], state.num_warnings, STYLES["reset"]
+ )
+ )
+ elif state.num_warnings == 1:
+ print(
+ "{}1 warning was found in the class reference XML. Please check the messages above.{}".format(
+ STYLES["yellow"], STYLES["reset"]
+ )
+ )
+
if state.num_errors == 0:
print("{}No errors found in the class reference XML.{}".format(STYLES["green"], STYLES["reset"]))
if not args.dry_run:
@@ -576,7 +646,20 @@ def main(): # type: () -> None
exit(1)
-def translate(string): # type: (str) -> str
+# Common helpers.
+
+
+def print_error(error: str, state: State) -> None:
+ print("{}{}ERROR:{} {}{}".format(STYLES["red"], STYLES["bold"], STYLES["regular"], error, STYLES["reset"]))
+ state.num_errors += 1
+
+
+def print_warning(error: str, state: State) -> None:
+ print("{}{}WARNING:{} {}{}".format(STYLES["yellow"], STYLES["bold"], STYLES["regular"], error, STYLES["reset"]))
+ state.num_warnings += 1
+
+
+def translate(string: str) -> str:
"""Translate a string based on translations sourced from `doc/translations/*.po`
for a language if defined via the --lang command line argument.
Returns the original string if no translation exists.
@@ -584,7 +667,10 @@ def translate(string): # type: (str) -> str
return strings_l10n.get(string, string)
-def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, State, bool, str) -> None
+# Generator methods.
+
+
+def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: str) -> None:
class_name = class_def.name
if dry_run:
@@ -635,8 +721,8 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
break
f.write("\n\n")
- # Descendents
- inherited = []
+ # Descendants
+ inherited: List[str] = []
for c in state.classes.values():
if c.inherits and c.inherits.strip() == class_name:
inherited.append(c.name)
@@ -651,12 +737,12 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
# Brief description
if class_def.brief_description is not None:
- f.write(rstize_text(class_def.brief_description.strip(), state) + "\n\n")
+ f.write(format_text_block(class_def.brief_description.strip(), class_def, state) + "\n\n")
# Class description
if class_def.description is not None and class_def.description.strip() != "":
f.write(make_heading("Description", "-"))
- f.write(rstize_text(class_def.description.strip(), state) + "\n\n")
+ f.write(format_text_block(class_def.description.strip(), class_def, state) + "\n\n")
# Online tutorials
if len(class_def.tutorials) > 0:
@@ -667,7 +753,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
# Properties overview
if len(class_def.properties) > 0:
f.write(make_heading("Properties", "-"))
- ml = [] # type: List[Tuple[str, str, str]]
+ ml: List[Tuple[Optional[str], ...]] = []
for property_def in class_def.properties.values():
type_rst = property_def.type_name.to_rst(state)
default = property_def.default_value
@@ -683,7 +769,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
# Constructors, Methods, Operators overview
if len(class_def.constructors) > 0:
f.write(make_heading("Constructors", "-"))
- ml = []
+ ml: List[Tuple[Optional[str], ...]] = []
for method_list in class_def.constructors.values():
for m in method_list:
ml.append(make_method_signature(class_def, m, "constructor", state))
@@ -691,7 +777,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
if len(class_def.methods) > 0:
f.write(make_heading("Methods", "-"))
- ml = []
+ ml: List[Tuple[Optional[str], ...]] = []
for method_list in class_def.methods.values():
for m in method_list:
ml.append(make_method_signature(class_def, m, "method", state))
@@ -699,7 +785,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
if len(class_def.operators) > 0:
f.write(make_heading("Operators", "-"))
- ml = []
+ ml: List[Tuple[Optional[str], ...]] = []
for method_list in class_def.operators.values():
for m in method_list:
ml.append(make_method_signature(class_def, m, "operator", state))
@@ -708,7 +794,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
# Theme properties
if len(class_def.theme_items) > 0:
f.write(make_heading("Theme Properties", "-"))
- pl = []
+ pl: List[Tuple[Optional[str], ...]] = []
for theme_item_def in class_def.theme_items.values():
ref = ":ref:`{0}<class_{2}_theme_{1}_{0}>`".format(
theme_item_def.name, theme_item_def.data_name, class_name
@@ -730,7 +816,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
f.write("- {}\n\n".format(signature))
if signal.description is not None and signal.description.strip() != "":
- f.write(rstize_text(signal.description.strip(), state) + "\n\n")
+ f.write(format_text_block(signal.description.strip(), signal, state) + "\n\n")
index += 1
@@ -760,7 +846,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
f.write("- **{}** = **{}**".format(value.name, value.value))
if value.text is not None and value.text.strip() != "":
# If value.text contains a bullet point list, each entry needs additional indentation
- f.write(" --- " + indent_bullets(rstize_text(value.text.strip(), state)))
+ f.write(" --- " + indent_bullets(format_text_block(value.text.strip(), value, state)))
f.write("\n\n")
@@ -777,10 +863,11 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
for constant in class_def.constants.values():
f.write("- **{}** = **{}**".format(constant.name, constant.value))
if constant.text is not None and constant.text.strip() != "":
- f.write(" --- " + rstize_text(constant.text.strip(), state))
+ f.write(" --- " + format_text_block(constant.text.strip(), constant, state))
f.write("\n\n")
+ # Annotations
if len(class_def.annotations) > 0:
f.write(make_heading("Annotations", "-"))
index = 0
@@ -791,13 +878,13 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
f.write("----\n\n")
if i == 0:
- f.write(".. _class_{}_annotation_{}:\n\n".format(class_name, m.name.strip("@")))
+ f.write(".. _class_{}_annotation_{}:\n\n".format(class_name, m.name))
- ret_type, signature = make_method_signature(class_def, m, "", state)
- f.write("- {} {}\n\n".format(ret_type, signature))
+ _, signature = make_method_signature(class_def, m, "", state)
+ f.write("- {}\n\n".format(signature))
if m.description is not None and m.description.strip() != "":
- f.write(rstize_text(m.description.strip(), state) + "\n\n")
+ f.write(format_text_block(m.description.strip(), m, state) + "\n\n")
index += 1
@@ -816,7 +903,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
f.write(".. _class_{}_property_{}:\n\n".format(class_name, property_def.name))
f.write("- {} **{}**\n\n".format(property_def.type_name.to_rst(state), property_def.name))
- info = []
+ info: List[Tuple[Optional[str], ...]] = []
# Not using translate() for now as it breaks table formatting.
if property_def.default_value is not None:
info.append(("*" + "Default" + "*", property_def.default_value))
@@ -829,7 +916,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
format_table(f, info)
if property_def.text is not None and property_def.text.strip() != "":
- f.write(rstize_text(property_def.text.strip(), state) + "\n\n")
+ f.write(format_text_block(property_def.text.strip(), property_def, state) + "\n\n")
index += 1
@@ -850,7 +937,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
f.write("- {} {}\n\n".format(ret_type, signature))
if m.description is not None and m.description.strip() != "":
- f.write(rstize_text(m.description.strip(), state) + "\n\n")
+ f.write(format_text_block(m.description.strip(), m, state) + "\n\n")
index += 1
@@ -870,7 +957,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
f.write("- {} {}\n\n".format(ret_type, signature))
if m.description is not None and m.description.strip() != "":
- f.write(rstize_text(m.description.strip(), state) + "\n\n")
+ f.write(format_text_block(m.description.strip(), m, state) + "\n\n")
index += 1
@@ -894,7 +981,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
f.write("- {} {}\n\n".format(ret_type, signature))
if m.description is not None and m.description.strip() != "":
- f.write(rstize_text(m.description.strip(), state) + "\n\n")
+ f.write(format_text_block(m.description.strip(), m, state) + "\n\n")
index += 1
@@ -919,85 +1006,185 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
format_table(f, info)
if theme_item_def.text is not None and theme_item_def.text.strip() != "":
- f.write(rstize_text(theme_item_def.text.strip(), state) + "\n\n")
+ f.write(format_text_block(theme_item_def.text.strip(), theme_item_def, state) + "\n\n")
index += 1
f.write(make_footer())
-def escape_rst(text, until_pos=-1): # type: (str, int) -> str
- # Escape \ character, otherwise it ends up as an escape character in rst
- pos = 0
- while True:
- pos = text.find("\\", pos, until_pos)
- if pos == -1:
- break
- text = text[:pos] + "\\\\" + text[pos + 1 :]
- pos += 2
+def make_type(klass: str, state: State) -> str:
+ if klass.find("*") != -1: # Pointer, ignore
+ return klass
+ link_type = klass
+ if link_type.endswith("[]"): # Typed array, strip [] to link to contained type.
+ link_type = link_type[:-2]
+ if link_type in state.classes:
+ return ":ref:`{}<class_{}>`".format(klass, link_type)
+ print_error('{}.xml: Unresolved type "{}".'.format(state.current_class, klass), state)
+ return klass
- # Escape * character to avoid interpreting it as emphasis
- pos = 0
- while True:
- pos = text.find("*", pos, until_pos)
- if pos == -1:
- break
- text = text[:pos] + "\*" + text[pos + 1 :]
- pos += 2
- # Escape _ character at the end of a word to avoid interpreting it as an inline hyperlink
- pos = 0
- while True:
- pos = text.find("_", pos, until_pos)
- if pos == -1:
- break
- if not text[pos + 1].isalnum(): # don't escape within a snake_case word
- text = text[:pos] + "\_" + text[pos + 1 :]
- pos += 2
- else:
- pos += 1
+def make_enum(t: str, state: State) -> str:
+ p = t.find(".")
+ if p >= 0:
+ c = t[0:p]
+ e = t[p + 1 :]
+ # Variant enums live in GlobalScope but still use periods.
+ if c == "Variant":
+ c = "@GlobalScope"
+ e = "Variant." + e
+ else:
+ c = state.current_class
+ e = t
+ if c in state.classes and e not in state.classes[c].enums:
+ c = "@GlobalScope"
- return text
+ if c in state.classes and e in state.classes[c].enums:
+ return ":ref:`{0}<enum_{1}_{0}>`".format(e, c)
+ # Don't fail for `Vector3.Axis`, as this enum is a special case which is expected not to be resolved.
+ if "{}.{}".format(c, e) != "Vector3.Axis":
+ print_error('{}.xml: Unresolved enum "{}".'.format(state.current_class, t), state)
-def format_codeblock(code_type, post_text, indent_level, state): # types: str, str, int, state
- end_pos = post_text.find("[/" + code_type + "]")
- if end_pos == -1:
- print_error("{}.xml: [" + code_type + "] without a closing tag.".format(state.current_class), state)
- return None
+ return t
- code_text = post_text[len("[" + code_type + "]") : end_pos]
- post_text = post_text[end_pos:]
- # Remove extraneous tabs
- code_pos = 0
- while True:
- code_pos = code_text.find("\n", code_pos)
- if code_pos == -1:
- break
+def make_method_signature(
+ class_def: ClassDef, definition: Union[AnnotationDef, MethodDef, SignalDef], ref_type: str, state: State
+) -> Tuple[str, str]:
+ ret_type = ""
- to_skip = 0
- while code_pos + to_skip + 1 < len(code_text) and code_text[code_pos + to_skip + 1] == "\t":
- to_skip += 1
+ is_method_def = isinstance(definition, MethodDef)
+ if is_method_def:
+ ret_type = definition.return_type.to_rst(state)
- if to_skip > indent_level:
- print_error(
- "{}.xml: Four spaces should be used for indentation within [{}].".format(
- state.current_class, code_type
- ),
- state,
+ qualifiers = None
+ if is_method_def or isinstance(definition, AnnotationDef):
+ qualifiers = definition.qualifiers
+
+ out = ""
+
+ if is_method_def and ref_type != "":
+ if ref_type == "operator":
+ out += ":ref:`{0}<class_{1}_{2}_{3}_{4}>` ".format(
+ definition.name.replace("<", "\\<"), # So operator "<" gets correctly displayed.
+ class_def.name,
+ ref_type,
+ sanitize_operator_name(definition.name, state),
+ definition.return_type.type_name,
)
+ else:
+ out += ":ref:`{0}<class_{1}_{2}_{0}>` ".format(definition.name, class_def.name, ref_type)
+ else:
+ out += "**{}** ".format(definition.name)
- if len(code_text[code_pos + to_skip + 1 :]) == 0:
- code_text = code_text[:code_pos] + "\n"
- code_pos += 1
+ out += "**(**"
+ for i, arg in enumerate(definition.parameters):
+ if i > 0:
+ out += ", "
else:
- code_text = code_text[:code_pos] + "\n " + code_text[code_pos + to_skip + 1 :]
- code_pos += 5 - to_skip
- return ["\n[" + code_type + "]" + code_text + post_text, len("\n[" + code_type + "]" + code_text)]
+ out += " "
+
+ out += "{} {}".format(arg.type_name.to_rst(state), arg.name)
+
+ if arg.default_value is not None:
+ out += "=" + arg.default_value
+
+ if qualifiers is not None and "vararg" in qualifiers:
+ if len(definition.parameters) > 0:
+ out += ", ..."
+ else:
+ out += " ..."
+
+ out += " **)**"
+
+ if qualifiers is not None:
+ # Use substitutions for abbreviations. This is used to display tooltips on hover.
+ # See `make_footer()` for descriptions.
+ for qualifier in qualifiers.split():
+ out += " |" + qualifier + "|"
+
+ return ret_type, out
+
+
+def make_heading(title: str, underline: str, l10n: bool = True) -> str:
+ if l10n:
+ new_title = translate(title)
+ if new_title != title:
+ title = new_title
+ underline *= 2 # Double length to handle wide chars.
+ return title + "\n" + (underline * len(title)) + "\n\n"
-def rstize_text(text, state): # type: (str, State) -> str
+def make_footer() -> str:
+ # Generate reusable abbreviation substitutions.
+ # This way, we avoid bloating the generated rST with duplicate abbreviations.
+ # fmt: off
+ return (
+ ".. |virtual| replace:: :abbr:`virtual (" + translate("This method should typically be overridden by the user to have any effect.") + ")`\n"
+ ".. |const| replace:: :abbr:`const (" + translate("This method has no side effects. It doesn't modify any of the instance's member variables.") + ")`\n"
+ ".. |vararg| replace:: :abbr:`vararg (" + translate("This method accepts any number of arguments after the ones described here.") + ")`\n"
+ ".. |constructor| replace:: :abbr:`constructor (" + translate("This method is used to construct a type.") + ")`\n"
+ ".. |static| replace:: :abbr:`static (" + translate("This method doesn't need an instance to be called, so it can be called directly using the class name.") + ")`\n"
+ ".. |operator| replace:: :abbr:`operator (" + translate("This method describes a valid operator to use with this type as left-hand operand.") + ")`\n"
+ )
+ # fmt: on
+
+
+def make_link(url: str, title: str) -> str:
+ match = GODOT_DOCS_PATTERN.search(url)
+ if match:
+ groups = match.groups()
+ if match.lastindex == 2:
+ # Doc reference with fragment identifier: emit direct link to section with reference to page, for example:
+ # `#calling-javascript-from-script in Exporting For Web`
+ # Or use the title if provided.
+ if title != "":
+ return "`" + title + " <../" + groups[0] + ".html" + groups[1] + ">`__"
+ return "`" + groups[1] + " <../" + groups[0] + ".html" + groups[1] + ">`__ in :doc:`../" + groups[0] + "`"
+ elif match.lastindex == 1:
+ # Doc reference, for example:
+ # `Math`
+ if title != "":
+ return ":doc:`" + title + " <../" + groups[0] + ">`"
+ return ":doc:`../" + groups[0] + "`"
+
+ # External link, for example:
+ # `http://enet.bespin.org/usergroup0.html`
+ if title != "":
+ return "`" + title + " <" + url + ">`__"
+ return "`" + url + " <" + url + ">`__"
+
+
+# Formatting helpers.
+
+
+RESERVED_FORMATTING_TAGS = ["i", "b", "u", "code", "kbd", "center", "url", "br"]
+RESERVED_CODEBLOCK_TAGS = ["codeblocks", "codeblock", "gdscript", "csharp"]
+RESERVED_CROSSLINK_TAGS = ["method", "member", "signal", "constant", "enum", "annotation", "theme_item", "param"]
+
+
+def is_in_tagset(tag_text: str, tagset: List[str]) -> bool:
+ for tag in tagset:
+ # Complete match.
+ if tag_text == tag:
+ return True
+ # Tag with arguments.
+ if tag_text.startswith(tag + " "):
+ return True
+ # Tag with arguments, special case for [url].
+ if tag_text.startswith(tag + "="):
+ return True
+
+ return False
+
+
+def format_text_block(
+ text: str,
+ context: Union[DefinitionBase, None],
+ state: State,
+) -> str:
# Linebreak + tabs in the XML should become two line breaks unless in a "codeblock"
pos = 0
while True:
@@ -1033,11 +1220,14 @@ def rstize_text(text, state): # type: (str, State) -> str
next_brac_pos = text.find("[")
text = escape_rst(text, next_brac_pos)
+ context_name = format_context_name(context)
+
# Handle [tags]
inside_code = False
+ inside_code_tag = ""
+ inside_code_tabs = False
pos = 0
tag_depth = 0
- previous_pos = 0
while True:
pos = text.find("[", pos)
if pos == -1:
@@ -1054,188 +1244,336 @@ def rstize_text(text, state): # type: (str, State) -> str
escape_pre = False
escape_post = False
+ # Tag is a reference to a class.
if tag_text in state.classes:
if tag_text == state.current_class:
- # We don't want references to the same class
+ # Don't create a link to the same class, format it as inline code.
tag_text = "``{}``".format(tag_text)
else:
tag_text = make_type(tag_text, state)
escape_pre = True
escape_post = True
- else: # command
+
+ # Tag is a cross-reference or a formating directive.
+ else:
cmd = tag_text
space_pos = tag_text.find(" ")
- if cmd == "/codeblock" or cmd == "/gdscript" or cmd == "/csharp":
- tag_text = ""
- tag_depth -= 1
- inside_code = False
- # Strip newline if the tag was alone on one
- if pre_text[-1] == "\n":
- pre_text = pre_text[:-1]
- elif cmd == "/code":
- tag_text = "``"
- tag_depth -= 1
- inside_code = False
- escape_post = True
- elif inside_code:
- tag_text = "[" + tag_text + "]"
- elif cmd.find("html") == 0:
- param = tag_text[space_pos + 1 :]
- tag_text = param
- elif (
- cmd.startswith("method")
- or cmd.startswith("member")
- or cmd.startswith("signal")
- or cmd.startswith("constant")
- or cmd.startswith("theme_item")
- ):
- param = tag_text[space_pos + 1 :]
-
- if param.find(".") != -1:
- ss = param.split(".")
- if len(ss) > 2:
- print_error('{}.xml: Bad reference: "{}".'.format(state.current_class, param), state)
- class_param, method_param = ss
- else:
- class_param = state.current_class
- method_param = param
-
- ref_type = ""
- if class_param in state.classes:
- class_def = state.classes[class_param]
- if cmd.startswith("constructor"):
- if method_param not in class_def.constructors:
- print_error(
- '{}.xml: Unresolved constructor "{}".'.format(state.current_class, param), state
- )
- ref_type = "_constructor"
- if cmd.startswith("method"):
- if method_param not in class_def.methods:
- print_error('{}.xml: Unresolved method "{}".'.format(state.current_class, param), state)
- ref_type = "_method"
- if cmd.startswith("operator"):
- if method_param not in class_def.operators:
- print_error('{}.xml: Unresolved operator "{}".'.format(state.current_class, param), state)
- ref_type = "_operator"
-
- elif cmd.startswith("member"):
- if method_param not in class_def.properties:
- print_error('{}.xml: Unresolved member "{}".'.format(state.current_class, param), state)
- ref_type = "_property"
-
- elif cmd.startswith("theme_item"):
- if method_param not in class_def.theme_items:
- print_error('{}.xml: Unresolved theme item "{}".'.format(state.current_class, param), state)
- ref_type = "_theme_{}".format(class_def.theme_items[method_param].data_name)
-
- elif cmd.startswith("signal"):
- if method_param not in class_def.signals:
- print_error('{}.xml: Unresolved signal "{}".'.format(state.current_class, param), state)
- ref_type = "_signal"
-
- elif cmd.startswith("annotation"):
- if method_param not in class_def.annotations:
- print_error('{}.xml: Unresolved annotation "{}".'.format(state.current_class, param), state)
- ref_type = "_annotation"
-
- elif cmd.startswith("constant"):
- found = False
-
- # Search in the current class
- search_class_defs = [class_def]
-
- if param.find(".") == -1:
- # Also search in @GlobalScope as a last resort if no class was specified
- search_class_defs.append(state.classes["@GlobalScope"])
-
- for search_class_def in search_class_defs:
- if method_param in search_class_def.constants:
- class_param = search_class_def.name
- found = True
-
- else:
- for enum in search_class_def.enums.values():
- if method_param in enum.values:
- class_param = search_class_def.name
- found = True
- break
-
- if not found:
- print_error('{}.xml: Unresolved constant "{}".'.format(state.current_class, param), state)
- ref_type = "_constant"
+ # Anything identified as a tag inside of a code block is valid,
+ # unless it's a matching closing tag.
+ if inside_code:
+ # Exiting codeblocks and inline code tags.
+
+ if inside_code_tag == cmd[1:]:
+ if cmd == "/codeblock" or cmd == "/gdscript" or cmd == "/csharp":
+ tag_text = ""
+ tag_depth -= 1
+ inside_code = False
+ # Strip newline if the tag was alone on one
+ if pre_text[-1] == "\n":
+ pre_text = pre_text[:-1]
+
+ elif cmd == "/code":
+ tag_text = "``"
+ tag_depth -= 1
+ inside_code = False
+ escape_post = True
else:
- print_error(
- '{}.xml: Unresolved type reference "{}" in method reference "{}".'.format(
- state.current_class, class_param, param
- ),
- state,
- )
-
- repl_text = method_param
- if class_param != state.current_class:
- repl_text = "{}.{}".format(class_param, method_param)
- tag_text = ":ref:`{}<class_{}{}_{}>`".format(repl_text, class_param, ref_type, method_param)
- escape_pre = True
- escape_post = True
- elif cmd.find("image=") == 0:
- tag_text = "" # '![](' + cmd[6:] + ')'
- elif cmd.find("url=") == 0:
- # URLs are handled in full here as we need to extract the optional link
- # title to use `make_link`.
- link_url = cmd[4:]
- endurl_pos = text.find("[/url]", endq_pos + 1)
- if endurl_pos == -1:
- print_error(
- "{}.xml: Tag depth mismatch for [url]: no closing [/url]".format(state.current_class), state
- )
- break
- link_title = text[endq_pos + 1 : endurl_pos]
- tag_text = make_link(link_url, link_title)
+ if cmd.startswith("/"):
+ print_warning(
+ '{}.xml: Potential error inside of a code tag, found a string that looks like a closing tag "[{}]" in {}.'.format(
+ state.current_class, cmd, context_name
+ ),
+ state,
+ )
- pre_text = text[:pos]
- post_text = text[endurl_pos + 6 :]
+ tag_text = "[" + tag_text + "]"
- if pre_text and pre_text[-1] not in MARKUP_ALLOWED_PRECEDENT:
- pre_text += "\ "
- if post_text and post_text[0] not in MARKUP_ALLOWED_SUBSEQUENT:
- post_text = "\ " + post_text
+ # Entering codeblocks and inline code tags.
- text = pre_text + tag_text + post_text
- pos = len(pre_text) + len(tag_text)
- previous_pos = pos
- continue
- elif cmd == "center":
+ elif cmd == "codeblocks":
tag_depth += 1
- tag_text = ""
- elif cmd == "/center":
+ tag_text = "\n.. tabs::"
+ inside_code_tabs = True
+ elif cmd == "/codeblocks":
tag_depth -= 1
tag_text = ""
- elif cmd == "codeblock":
- tag_depth += 1
- tag_text = "\n::\n"
- inside_code = True
- elif cmd == "gdscript":
+ inside_code_tabs = False
+
+ elif cmd == "codeblock" or cmd == "gdscript" or cmd == "csharp":
tag_depth += 1
- tag_text = "\n .. code-tab:: gdscript\n"
+
+ if cmd == "gdscript":
+ if not inside_code_tabs:
+ print_error(
+ "{}.xml: GDScript code block is used outside of [codeblocks] in {}.".format(
+ state.current_class, cmd, context_name
+ ),
+ state,
+ )
+ tag_text = "\n .. code-tab:: gdscript\n"
+ elif cmd == "csharp":
+ if not inside_code_tabs:
+ print_error(
+ "{}.xml: C# code block is used outside of [codeblocks] in {}.".format(
+ state.current_class, cmd, context_name
+ ),
+ state,
+ )
+ tag_text = "\n .. code-tab:: csharp\n"
+ else:
+ tag_text = "\n::\n"
+
inside_code = True
- elif cmd == "csharp":
+ inside_code_tag = cmd
+
+ elif cmd == "code":
+ tag_text = "``"
tag_depth += 1
- tag_text = "\n .. code-tab:: csharp\n"
inside_code = True
- elif cmd == "codeblocks":
- tag_depth += 1
- tag_text = "\n.. tabs::"
- elif cmd == "/codeblocks":
- tag_depth -= 1
- tag_text = ""
+ inside_code_tag = cmd
+ escape_pre = True
+
+ # Cross-references to items in this or other class documentation pages.
+ elif is_in_tagset(cmd, RESERVED_CROSSLINK_TAGS):
+ link_type: str = ""
+ link_target: str = ""
+ if space_pos >= 0:
+ link_type = tag_text[:space_pos]
+ link_target = tag_text[space_pos + 1 :].strip()
+
+ if link_target == "":
+ print_error(
+ '{}.xml: Empty cross-reference link "{}" in {}.'.format(state.current_class, cmd, context_name),
+ state,
+ )
+ tag_text = ""
+ else:
+ if (
+ cmd.startswith("method")
+ or cmd.startswith("constructor")
+ or cmd.startswith("operator")
+ or cmd.startswith("member")
+ or cmd.startswith("signal")
+ or cmd.startswith("annotation")
+ or cmd.startswith("theme_item")
+ or cmd.startswith("constant")
+ ):
+ if link_target.find(".") != -1:
+ ss = link_target.split(".")
+ if len(ss) > 2:
+ print_error(
+ '{}.xml: Bad reference "{}" in {}.'.format(
+ state.current_class, link_target, context_name
+ ),
+ state,
+ )
+ class_param, method_param = ss
+
+ else:
+ class_param = state.current_class
+ method_param = link_target
+
+ # Default to the tag command name. This works by default for most tags,
+ # but member and theme_item have special cases.
+ ref_type = "_{}".format(link_type)
+ if link_type == "member":
+ ref_type = "_property"
+
+ if class_param in state.classes:
+ class_def = state.classes[class_param]
+
+ if cmd.startswith("method") and method_param not in class_def.methods:
+ print_error(
+ '{}.xml: Unresolved method reference "{}" in {}.'.format(
+ state.current_class, link_target, context_name
+ ),
+ state,
+ )
+
+ elif cmd.startswith("constructor") and method_param not in class_def.constructors:
+ print_error(
+ '{}.xml: Unresolved constructor reference "{}" in {}.'.format(
+ state.current_class, link_target, context_name
+ ),
+ state,
+ )
+
+ elif cmd.startswith("operator") and method_param not in class_def.operators:
+ print_error(
+ '{}.xml: Unresolved operator reference "{}" in {}.'.format(
+ state.current_class, link_target, context_name
+ ),
+ state,
+ )
+
+ elif cmd.startswith("member") and method_param not in class_def.properties:
+ print_error(
+ '{}.xml: Unresolved member reference "{}" in {}.'.format(
+ state.current_class, link_target, context_name
+ ),
+ state,
+ )
+
+ elif cmd.startswith("signal") and method_param not in class_def.signals:
+ print_error(
+ '{}.xml: Unresolved signal reference "{}" in {}.'.format(
+ state.current_class, link_target, context_name
+ ),
+ state,
+ )
+
+ elif cmd.startswith("annotation") and method_param not in class_def.annotations:
+ print_error(
+ '{}.xml: Unresolved annotation reference "{}" in {}.'.format(
+ state.current_class, link_target, context_name
+ ),
+ state,
+ )
+
+ elif cmd.startswith("theme_item"):
+ if method_param not in class_def.theme_items:
+ print_error(
+ '{}.xml: Unresolved theme item reference "{}" in {}.'.format(
+ state.current_class, link_target, context_name
+ ),
+ state,
+ )
+ else:
+ # Needs theme data type to be properly linked, which we cannot get without a class.
+ ref_type = "_theme_{}".format(class_def.theme_items[method_param].data_name)
+
+ elif cmd.startswith("constant"):
+ found = False
+
+ # Search in the current class
+ search_class_defs = [class_def]
+
+ if link_target.find(".") == -1:
+ # Also search in @GlobalScope as a last resort if no class was specified
+ search_class_defs.append(state.classes["@GlobalScope"])
+
+ for search_class_def in search_class_defs:
+ if method_param in search_class_def.constants:
+ class_param = search_class_def.name
+ found = True
+
+ else:
+ for enum in search_class_def.enums.values():
+ if method_param in enum.values:
+ class_param = search_class_def.name
+ found = True
+ break
+
+ if not found:
+ print_error(
+ '{}.xml: Unresolved constant reference "{}" in {}.'.format(
+ state.current_class, link_target, context_name
+ ),
+ state,
+ )
+
+ else:
+ print_error(
+ '{}.xml: Unresolved type reference "{}" in method reference "{}" in {}.'.format(
+ state.current_class, class_param, link_target, context_name
+ ),
+ state,
+ )
+
+ repl_text = method_param
+ if class_param != state.current_class:
+ repl_text = "{}.{}".format(class_param, method_param)
+ tag_text = ":ref:`{}<class_{}{}_{}>`".format(repl_text, class_param, ref_type, method_param)
+ escape_pre = True
+ escape_post = True
+
+ elif cmd.startswith("enum"):
+ tag_text = make_enum(link_target, state)
+ escape_pre = True
+ escape_post = True
+
+ elif cmd.startswith("param"):
+ valid_context = (
+ isinstance(context, MethodDef)
+ or isinstance(context, SignalDef)
+ or isinstance(context, AnnotationDef)
+ )
+ if not valid_context:
+ print_error(
+ '{}.xml: Argument reference "{}" used outside of method, signal, or annotation context in {}.'.format(
+ state.current_class, link_target, context_name
+ ),
+ state,
+ )
+ else:
+ context_params: List[ParameterDef] = context.parameters
+ found = False
+ for param_def in context_params:
+ if param_def.name == link_target:
+ found = True
+ break
+ if not found:
+ print_error(
+ '{}.xml: Unresolved argument reference "{}" in {}.'.format(
+ state.current_class, link_target, context_name
+ ),
+ state,
+ )
+
+ tag_text = "``{}``".format(link_target)
+
+ # Formatting directives.
+
+ elif is_in_tagset(cmd, ["url"]):
+ if cmd.startswith("url="):
+ # URLs are handled in full here as we need to extract the optional link
+ # title to use `make_link`.
+ link_url = cmd[4:]
+ endurl_pos = text.find("[/url]", endq_pos + 1)
+ if endurl_pos == -1:
+ print_error(
+ "{}.xml: Tag depth mismatch for [url]: no closing [/url] in {}.".format(
+ state.current_class, context_name
+ ),
+ state,
+ )
+ break
+ link_title = text[endq_pos + 1 : endurl_pos]
+ tag_text = make_link(link_url, link_title)
+
+ pre_text = text[:pos]
+ post_text = text[endurl_pos + 6 :]
+
+ if pre_text and pre_text[-1] not in MARKUP_ALLOWED_PRECEDENT:
+ pre_text += "\ "
+ if post_text and post_text[0] not in MARKUP_ALLOWED_SUBSEQUENT:
+ post_text = "\ " + post_text
+
+ text = pre_text + tag_text + post_text
+ pos = len(pre_text) + len(tag_text)
+ continue
+ else:
+ print_error(
+ '{}.xml: Misformatted [url] tag "{}" in {}.'.format(state.current_class, cmd, context_name),
+ state,
+ )
+
elif cmd == "br":
# Make a new paragraph instead of a linebreak, rst is not so linebreak friendly
tag_text = "\n\n"
# Strip potential leading spaces
while post_text[0] == " ":
post_text = post_text[1:]
+
+ elif cmd == "center" or cmd == "/center":
+ if cmd == "/center":
+ tag_depth -= 1
+ else:
+ tag_depth += 1
+ tag_text = ""
+
elif cmd == "i" or cmd == "/i":
if cmd == "/i":
tag_depth -= 1
@@ -1244,6 +1582,7 @@ def rstize_text(text, state): # type: (str, State) -> str
tag_depth += 1
escape_pre = True
tag_text = "*"
+
elif cmd == "b" or cmd == "/b":
if cmd == "/b":
tag_depth -= 1
@@ -1252,6 +1591,7 @@ def rstize_text(text, state): # type: (str, State) -> str
tag_depth += 1
escape_pre = True
tag_text = "**"
+
elif cmd == "u" or cmd == "/u":
if cmd == "/u":
tag_depth -= 1
@@ -1260,25 +1600,31 @@ def rstize_text(text, state): # type: (str, State) -> str
tag_depth += 1
escape_pre = True
tag_text = ""
- elif cmd == "code":
- tag_text = "``"
- tag_depth += 1
- inside_code = True
- escape_pre = True
- elif cmd == "kbd":
- tag_text = ":kbd:`"
- tag_depth += 1
- escape_pre = True
- elif cmd == "/kbd":
+
+ elif cmd == "kbd" or cmd == "/kbd":
tag_text = "`"
- tag_depth -= 1
- escape_post = True
- elif cmd.startswith("enum "):
- tag_text = make_enum(cmd[5:], state)
- escape_pre = True
- escape_post = True
+ if cmd == "/kbd":
+ tag_depth -= 1
+ escape_post = True
+ else:
+ tag_text = ":kbd:" + tag_text
+ tag_depth += 1
+ escape_pre = True
+
+ # Invalid syntax checks.
+ elif cmd.startswith("/"):
+ print_error(
+ '{}.xml: Unrecognized closing tag "{}" in {}.'.format(state.current_class, cmd, context_name), state
+ )
+
+ tag_text = "[" + tag_text + "]"
+
else:
- tag_text = make_type(tag_text, state)
+ print_error(
+ '{}.xml: Unrecognized opening tag "{}" in {}.'.format(state.current_class, cmd, context_name), state
+ )
+
+ tag_text = "``{}``".format(tag_text)
escape_pre = True
escape_post = True
@@ -1310,17 +1656,98 @@ def rstize_text(text, state): # type: (str, State) -> str
text = pre_text + tag_text + post_text
pos = len(pre_text) + len(tag_text)
- previous_pos = pos
if tag_depth > 0:
print_error(
- "{}.xml: Tag depth mismatch: too many (or too little) open/close tags.".format(state.current_class), state
+ "{}.xml: Tag depth mismatch: too many (or too little) open/close tags in {}.".format(
+ state.current_class, context_name
+ ),
+ state,
)
return text
-def format_table(f, data, remove_empty_columns=False): # type: (TextIO, Iterable[Tuple[str, ...]], bool) -> None
+def format_context_name(context: Union[DefinitionBase, None]) -> str:
+ context_name: str = "unknown context"
+ if context is not None:
+ context_name = '{} "{}" description'.format(context.definition_name, context.name)
+
+ return context_name
+
+
+def escape_rst(text: str, until_pos: int = -1) -> str:
+ # Escape \ character, otherwise it ends up as an escape character in rst
+ pos = 0
+ while True:
+ pos = text.find("\\", pos, until_pos)
+ if pos == -1:
+ break
+ text = text[:pos] + "\\\\" + text[pos + 1 :]
+ pos += 2
+
+ # Escape * character to avoid interpreting it as emphasis
+ pos = 0
+ while True:
+ pos = text.find("*", pos, until_pos)
+ if pos == -1:
+ break
+ text = text[:pos] + "\*" + text[pos + 1 :]
+ pos += 2
+
+ # Escape _ character at the end of a word to avoid interpreting it as an inline hyperlink
+ pos = 0
+ while True:
+ pos = text.find("_", pos, until_pos)
+ if pos == -1:
+ break
+ if not text[pos + 1].isalnum(): # don't escape within a snake_case word
+ text = text[:pos] + "\_" + text[pos + 1 :]
+ pos += 2
+ else:
+ pos += 1
+
+ return text
+
+
+def format_codeblock(code_type: str, post_text: str, indent_level: int, state: State) -> Union[Tuple[str, int], None]:
+ end_pos = post_text.find("[/" + code_type + "]")
+ if end_pos == -1:
+ print_error("{}.xml: [" + code_type + "] without a closing tag.".format(state.current_class), state)
+ return None
+
+ code_text = post_text[len("[" + code_type + "]") : end_pos]
+ post_text = post_text[end_pos:]
+
+ # Remove extraneous tabs
+ code_pos = 0
+ while True:
+ code_pos = code_text.find("\n", code_pos)
+ if code_pos == -1:
+ break
+
+ to_skip = 0
+ while code_pos + to_skip + 1 < len(code_text) and code_text[code_pos + to_skip + 1] == "\t":
+ to_skip += 1
+
+ if to_skip > indent_level:
+ print_error(
+ "{}.xml: Four spaces should be used for indentation within [{}].".format(
+ state.current_class, code_type
+ ),
+ state,
+ )
+
+ if len(code_text[code_pos + to_skip + 1 :]) == 0:
+ code_text = code_text[:code_pos] + "\n"
+ code_pos += 1
+ else:
+ code_text = code_text[:code_pos] + "\n " + code_text[code_pos + to_skip + 1 :]
+ code_pos += 5 - to_skip
+ return ("\n[" + code_type + "]" + code_text + post_text, len("\n[" + code_type + "]" + code_text))
+
+
+def format_table(f: TextIO, data: List[Tuple[Optional[str], ...]], remove_empty_columns: bool = False) -> None:
if len(data) == 0:
return
@@ -1351,146 +1778,7 @@ def format_table(f, data, remove_empty_columns=False): # type: (TextIO, Iterabl
f.write("\n")
-def make_type(klass, state): # type: (str, State) -> str
- if klass.find("*") != -1: # Pointer, ignore
- return klass
- link_type = klass
- if link_type.endswith("[]"): # Typed array, strip [] to link to contained type.
- link_type = link_type[:-2]
- if link_type in state.classes:
- return ":ref:`{}<class_{}>`".format(klass, link_type)
- print_error('{}.xml: Unresolved type "{}".'.format(state.current_class, klass), state)
- return klass
-
-
-def make_enum(t, state): # type: (str, State) -> str
- p = t.find(".")
- if p >= 0:
- c = t[0:p]
- e = t[p + 1 :]
- # Variant enums live in GlobalScope but still use periods.
- if c == "Variant":
- c = "@GlobalScope"
- e = "Variant." + e
- else:
- c = state.current_class
- e = t
- if c in state.classes and e not in state.classes[c].enums:
- c = "@GlobalScope"
-
- if c in state.classes and e in state.classes[c].enums:
- return ":ref:`{0}<enum_{1}_{0}>`".format(e, c)
-
- # Don't fail for `Vector3.Axis`, as this enum is a special case which is expected not to be resolved.
- if "{}.{}".format(c, e) != "Vector3.Axis":
- print_error('{}.xml: Unresolved enum "{}".'.format(state.current_class, t), state)
-
- return t
-
-
-def make_method_signature(
- class_def, method_def, ref_type, state
-): # type: (ClassDef, Union[MethodDef, SignalDef], str, State) -> Tuple[str, str]
- ret_type = " "
-
- if isinstance(method_def, MethodDef):
- ret_type = method_def.return_type.to_rst(state)
-
- out = ""
-
- if ref_type != "":
- if ref_type == "operator":
- out += ":ref:`{0}<class_{1}_{2}_{3}_{4}>` ".format(
- method_def.name.replace("<", "\\<"), # So operator "<" gets correctly displayed.
- class_def.name,
- ref_type,
- sanitize_operator_name(method_def.name, state),
- method_def.return_type.type_name,
- )
- else:
- out += ":ref:`{0}<class_{1}_{2}_{0}>` ".format(method_def.name, class_def.name, ref_type)
- else:
- out += "**{}** ".format(method_def.name)
-
- out += "**(**"
- for i, arg in enumerate(method_def.parameters):
- if i > 0:
- out += ", "
- else:
- out += " "
-
- out += "{} {}".format(arg.type_name.to_rst(state), arg.name)
-
- if arg.default_value is not None:
- out += "=" + arg.default_value
-
- if isinstance(method_def, MethodDef) and method_def.qualifiers is not None and "vararg" in method_def.qualifiers:
- if len(method_def.parameters) > 0:
- out += ", ..."
- else:
- out += " ..."
-
- out += " **)**"
-
- if isinstance(method_def, MethodDef) and method_def.qualifiers is not None:
- # Use substitutions for abbreviations. This is used to display tooltips on hover.
- # See `make_footer()` for descriptions.
- for qualifier in method_def.qualifiers.split():
- out += " |" + qualifier + "|"
-
- return ret_type, out
-
-
-def make_heading(title, underline, l10n=True): # type: (str, str, bool) -> str
- if l10n:
- new_title = translate(title)
- if new_title != title:
- title = new_title
- underline *= 2 # Double length to handle wide chars.
- return title + "\n" + (underline * len(title)) + "\n\n"
-
-
-def make_footer(): # type: () -> str
- # Generate reusable abbreviation substitutions.
- # This way, we avoid bloating the generated rST with duplicate abbreviations.
- # fmt: off
- return (
- ".. |virtual| replace:: :abbr:`virtual (" + translate("This method should typically be overridden by the user to have any effect.") + ")`\n"
- ".. |const| replace:: :abbr:`const (" + translate("This method has no side effects. It doesn't modify any of the instance's member variables.") + ")`\n"
- ".. |vararg| replace:: :abbr:`vararg (" + translate("This method accepts any number of arguments after the ones described here.") + ")`\n"
- ".. |constructor| replace:: :abbr:`constructor (" + translate("This method is used to construct a type.") + ")`\n"
- ".. |static| replace:: :abbr:`static (" + translate("This method doesn't need an instance to be called, so it can be called directly using the class name.") + ")`\n"
- ".. |operator| replace:: :abbr:`operator (" + translate("This method describes a valid operator to use with this type as left-hand operand.") + ")`\n"
- )
- # fmt: on
-
-
-def make_link(url, title): # type: (str, str) -> str
- match = GODOT_DOCS_PATTERN.search(url)
- if match:
- groups = match.groups()
- if match.lastindex == 2:
- # Doc reference with fragment identifier: emit direct link to section with reference to page, for example:
- # `#calling-javascript-from-script in Exporting For Web`
- # Or use the title if provided.
- if title != "":
- return "`" + title + " <../" + groups[0] + ".html" + groups[1] + ">`__"
- return "`" + groups[1] + " <../" + groups[0] + ".html" + groups[1] + ">`__ in :doc:`../" + groups[0] + "`"
- elif match.lastindex == 1:
- # Doc reference, for example:
- # `Math`
- if title != "":
- return ":doc:`" + title + " <../" + groups[0] + ">`"
- return ":doc:`../" + groups[0] + "`"
- else:
- # External link, for example:
- # `http://enet.bespin.org/usergroup0.html`
- if title != "":
- return "`" + title + " <" + url + ">`__"
- return "`" + url + " <" + url + ">`__"
-
-
-def sanitize_operator_name(dirty_name, state): # type: (str, State) -> str
+def sanitize_operator_name(dirty_name: str, state: State) -> str:
clear_name = dirty_name.replace("operator ", "")
if clear_name == "!=":
@@ -1548,7 +1836,7 @@ def sanitize_operator_name(dirty_name, state): # type: (str, State) -> str
return clear_name
-def indent_bullets(text): # type: (str) -> str
+def indent_bullets(text: str) -> str:
# Take the text and check each line for a bullet point represented by "-".
# Where found, indent the given line by a further "\t".
# Used to properly indent bullet points contained in the description for enum values.
diff --git a/doc/translations/fr.po b/doc/translations/fr.po
index 2866dc9b70..44d40e1bd5 100644
--- a/doc/translations/fr.po
+++ b/doc/translations/fr.po
@@ -61,7 +61,7 @@ msgstr ""
"Project-Id-Version: Godot Engine class reference\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-07-27 05:24+0000\n"
+"PO-Revision-Date: 2022-08-04 05:23+0000\n"
"Last-Translator: Maxime Leroy <lisacintosh@gmail.com>\n"
"Language-Team: French <https://hosted.weblate.org/projects/godot-engine/"
"godot-class-reference/fr/>\n"
@@ -548,7 +548,6 @@ msgstr ""
"[/codeblock]"
#: modules/gdscript/doc_classes/@GDScript.xml
-#, fuzzy
msgid ""
"Compares two values by checking their actual contents, recursing into any "
"[Array] or [Dictionary] up to its deepest level.\n"
@@ -574,15 +573,15 @@ msgstr ""
"- Pour [code]null[/code], [code]int[/code], [code]float[/code], "
"[code]String[/code], [code]Object[/code] et [code]RID[/code], les résultats "
"de [code]deep_equal[/code] et [code]==[/code] sont les mêmes.\n"
-"- Pour [code]Dictionary[/code], [code]==[/code] considère que l'égalité est "
-"respéctée si et seulement si les deux variables pointent vers le même "
-"[code]Dictionary[/code], sans recursion ou connaissance du contenu des "
+"- Pour les [code]Dictionary[/code], [code]==[/code] considère que l'égalité "
+"est respectée si et seulement si les deux variables pointent vers le même "
+"[code]Dictionary[/code], sans récursion ou comparaison du contenu des "
"variables.\n"
-"- For [code]Array[/code], [code]==[/code] considère que l'égalité est "
-"respéctée si et seulement si chaque élement du premier [code]Tableau[/code] "
+"- Pour les [code]Array[/code], [code]==[/code] considère que l'égalité est "
+"respectée si et seulement si chaque élément du premier [code]Array[/code] "
"est égal à l'élément au même index du second [code]Array[/code], évalué par "
-"[code]==[/code] lui même. Cela implique que [code]==[/code] recurses dans un "
-"[code]Array[/code], mais pas dans un [code]Dictionary[/code].\n"
+"[code]==[/code] lui-même. Cela implique un récursion avec [code]==[/code] "
+"pour les [code]Array[/code], mais pas les [code]Dictionary[/code].\n"
"Rapidement, dès qu'un [code]Dictionary[/code] est potentiellement impliqué, "
"si une vraie comparaison du contenu est souhaité, il faut utiliser "
"[code]deep_equal[/code]."
@@ -608,7 +607,6 @@ msgstr ""
"nouveau en une instance. Utile pour la désérialisation."
#: modules/gdscript/doc_classes/@GDScript.xml
-#, fuzzy
msgid ""
"Returns an \"eased\" value of [code]x[/code] based on an easing function "
"defined with [code]curve[/code]. This easing function is based on an "
@@ -634,13 +632,15 @@ msgstr ""
"nombre à virgule flottante, avec des valeurs spécifiques conduisant aux "
"comportements suivants:\n"
"[codeblock]\n"
-"- Inférieur à -1.0 (exclusif): Ease in-out\n"
-"- 1.0: Linéaire\n"
-"- Entre -1.0 et 0.0 (exclusif): Ease out-in\n"
-"- 0.0: Constante\n"
-"- Entre 0.0 et 1.0 (exclusif): Ease in\n"
-"- 1.0: Linéaire\n"
-"- Supérieur à 1.0 (exclusif): Ease out\n"
+"- Inférieur à -1.0 (exclus) : Plus lent au début et à la fin (\"ease in-out\""
+")\n"
+"- 1.0 : Linéaire\n"
+"- Entre -1.0 et 0.0 (exclus) : Plus rapide au début et à la fin (\"ease out-"
+"in\")\n"
+"- 0.0 : Constante\n"
+"- Entre 0.0 et 1.0 (exclus) : Plus lent au début (\"ease in\")\n"
+"- 1.0 : Linéaire\n"
+"- Supérieur à 1.0 (exclus) : Plus lent à la fin (\"ease out\")\n"
"[/codeblock]\n"
"[url=https://raw.githubusercontent.com/godotengine/godot-docs/3.4/img/"
"ease_cheatsheet.png]ease() curve values cheatsheet[/url]\n"
@@ -1423,7 +1423,6 @@ msgstr ""
"ou un avertissement est affiché."
#: modules/gdscript/doc_classes/@GDScript.xml
-#, fuzzy
msgid ""
"Like [method print], but includes the current stack frame when running with "
"the debugger turned on.\n"
@@ -1433,11 +1432,12 @@ msgid ""
" At: res://test.gd:15:_process()\n"
"[/codeblock]"
msgstr ""
-"Affiche la trace d'appels à l'emplacement du code, ne fonctionne que lorsque "
-"le débogueur est activé.\n"
+"Comme [method prunt], mais inclus la frame de la pile actuelle quand le "
+"débogueur est activé.\n"
"La sortie dans la console ressemblerait à ceci :\n"
"[codeblock]\n"
-"Frame 0 - res://test.gd:16 in function '_process'\n"
+"Test print\n"
+" At: res://test.gd:15:_process()\n"
"[/codeblock]"
#: modules/gdscript/doc_classes/@GDScript.xml
@@ -1824,7 +1824,6 @@ msgstr ""
"[/codeblock]"
#: modules/gdscript/doc_classes/@GDScript.xml
-#, fuzzy
msgid ""
"Returns the result of smoothly interpolating the value of [code]s[/code] "
"between [code]0[/code] and [code]1[/code], based on the where [code]s[/code] "
@@ -1850,25 +1849,26 @@ msgid ""
"-1.6521) return values[/url]"
msgstr ""
"Retourne le résultat de l'interpolation douce de la valeur [code]s[/code] "
-"entre [code]0[/code] et [code]1[/code], basée sur la position de [code]s[/"
-"code] entre [code]from[/code] et [code]to[/code].\n"
-"La valeur de retour est [code]0[/code] si [code]s <= from[/code], et "
+"entre [code]0[/code] et [code]1[/code], basée sur la position de "
+"[code]s[/code] entre [code]from[/code] et [code]to[/code].\n"
+"La valeur retournée est [code]0[/code] si [code]s <= from[/code], et "
"[code]1[/code] si [code]s >= to[/code]. Si [code]s[/code] se trouve entre "
"[code]from[/code] et [code]to[/code], la valeur retournée suit une courbe en "
-"S qui représente les positions de [code]s[/code] entre[code]0[/code] and "
+"S qui représente les positions de [code]s[/code] entre[code]0[/code] et "
"[code]1[/code].\n"
-"Cette courbe en S est l'interpolateur cubique d'Hermite, obtenu par "
-"[code]f(y) = 3*y^2 - 2*y^3[/code] où [code]y = (x-from) / (to-from)[/code].\n"
-"[codeblock]\n"
-"smoothstep(0, 2, -5.0) # Renvoie 0.0\n"
-"smoothstep(0, 2, 0.5) # Renvoie 0.15625\n"
-"smoothstep(0, 2, 1.0) # Renvoie 0.5\n"
-"smoothstep(0, 2, 2.0) # Renvoie 1.0\n"
+"Cette courbe en S est l'interpolation cubique d'Hermite, obtenu par la "
+"fonction mathématique [code]f(y) = 3*y^2 - 2*y^3[/code] où [code]y = (x-from)"
+" / (to-from)[/code].\n"
+"[codeblock]\n"
+"smoothstep(0, 2, -5.0) # Retourne 0.0\n"
+"smoothstep(0, 2, 0.5) # Retourne 0.15625\n"
+"smoothstep(0, 2, 1.0) # Retourne 0.5\n"
+"smoothstep(0, 2, 2.0) # Retourne 1.0\n"
"[/codeblock]\n"
-"Comparé à [method ease] avec une valeur de courbe de [code]-1.6521[/code], "
-"[method smoothstep] retourne la courbe la plus douce possible sans change "
-"brusque dans la dérivée. Si vous avez besoin d'effectuer des transitions "
-"plus avancées, utilisez [Tween] ou [AnimationPlayer].\n"
+"Comparé à l'utilisateur [method ease] avec une valeur de courbe de [code]-1."
+"6521[/code], [method smoothstep] retourne la courbe la plus douce possible, "
+"sans changement brusque de dérivée. Si vous avez besoin d'effectuer des "
+"transitions plus avancées, utilisez [Tween] ou [AnimationPlayer].\n"
"[url=https://raw.githubusercontent.com/godotengine/godot-docs/3.4/img/"
"smoothstep_ease_comparison.png]Comparaison entre les valeurs retournées par "
"smoothstep() et ease(x, -1.6521)[/url]"
@@ -4510,13 +4510,12 @@ msgstr ""
"les couches de physique 2D optionnellement nommées."
#: doc/classes/@GlobalScope.xml
-#, fuzzy
msgid ""
"Hints that an integer property is a bitmask using the optionally named 2D "
"navigation layers."
msgstr ""
-"Indique qu'une propriété nombre entier est un masque de bits utilisant les "
-"couches de rendu 2D optionnellement nommées."
+"Indique qu'une propriété de nombre entier est un masque de bits indiquant "
+"des calques de navigation 2D, qui peuvent être nommées."
#: doc/classes/@GlobalScope.xml
msgid ""
@@ -4535,13 +4534,12 @@ msgstr ""
"couches de physique 3D optionnellement nommées."
#: doc/classes/@GlobalScope.xml
-#, fuzzy
msgid ""
"Hints that an integer property is a bitmask using the optionally named 3D "
"navigation layers."
msgstr ""
-"Indique qu'une propriété nombre entier est un masque de bits utilisant les "
-"couches de rendu 2D optionnellement nommées."
+"Indique qu'une propriété de nombre entier est un masque de bits indiquant "
+"des calques de navigation 3D, qui peuvent être nommées."
#: doc/classes/@GlobalScope.xml
msgid ""
@@ -4660,9 +4658,10 @@ msgid "The property is a translatable string."
msgstr "La propriété est une chaîne de caractères traduisible."
#: doc/classes/@GlobalScope.xml
-#, fuzzy
msgid "Used to group properties together in the editor. See [EditorInspector]."
-msgstr "Utilisé pour rassembler des propriétés ensemble dans l'éditeur."
+msgstr ""
+"Utilisé pour rassembler des propriétés ensemble dans l'éditeur. Voir "
+"[EditorInspector]."
#: doc/classes/@GlobalScope.xml
msgid "Used to categorize properties together in the editor."
@@ -5443,10 +5442,11 @@ msgid "Maximum value for the mode enum."
msgstr "Valeur maximale pour le mode énumeration."
#: doc/classes/AnimatedSprite.xml
-#, fuzzy
msgid ""
"Sprite node that contains multiple textures as frames to play for animation."
-msgstr "Nœud de sprite qui peut utiliser plusieurs textures pour l'animation."
+msgstr ""
+"Le nœud de sprite qui peut utiliser plusieurs textures pour jouer une "
+"animation."
#: doc/classes/AnimatedSprite.xml
msgid ""
@@ -7372,7 +7372,7 @@ msgstr "Le type de transition."
#: doc/classes/AnimationNodeStateMachineTransition.xml
msgid "The time to cross-fade between this state and the next."
-msgstr ""
+msgstr "La durée du fondu entre cet état et le suivant."
#: doc/classes/AnimationNodeStateMachineTransition.xml
msgid "Emitted when [member advance_condition] is changed."
@@ -7515,9 +7515,8 @@ msgstr ""
"processus."
#: doc/classes/AnimationPlayer.xml
-#, fuzzy
msgid "Animation tutorial index"
-msgstr "Nœud d'animation."
+msgstr ""
#: doc/classes/AnimationPlayer.xml
msgid ""
@@ -8099,9 +8098,8 @@ msgstr ""
"connectés à l'emplacement spécifié.."
#: doc/classes/AnimationTreePlayer.xml
-#, fuzzy
msgid "Returns the blend amount of a Blend2 node given its name."
-msgstr "Retourne le nombre de clés d'une piste donnée."
+msgstr ""
#: doc/classes/AnimationTreePlayer.xml
msgid ""
@@ -8129,9 +8127,8 @@ msgstr ""
"code]. Les enfants modifiés du node's continuent d'être animés."
#: doc/classes/AnimationTreePlayer.xml
-#, fuzzy
msgid "Returns the blend amount of a Blend3 node given its name."
-msgstr "Retourne le nombre de clés d'une piste donnée."
+msgstr ""
#: doc/classes/AnimationTreePlayer.xml
msgid ""
@@ -8152,9 +8149,8 @@ msgstr ""
"de B+ est à 0. À 1, la sortie est l'entrée B+."
#: doc/classes/AnimationTreePlayer.xml
-#, fuzzy
msgid "Returns the blend amount of a Blend4 node given its name."
-msgstr "Retourne le nombre de clés d'une piste donnée."
+msgstr ""
#: doc/classes/AnimationTreePlayer.xml
msgid ""
@@ -8186,9 +8182,8 @@ msgid "Returns a [PoolStringArray] containing the name of all nodes."
msgstr "Retourne un [PoolStringArray] contenant le nom de tous les nœuds."
#: doc/classes/AnimationTreePlayer.xml
-#, fuzzy
msgid "Returns the mix amount of a Mix node given its name."
-msgstr "Retourne le nombre de clés d'une piste donnée."
+msgstr ""
#: doc/classes/AnimationTreePlayer.xml
msgid ""
@@ -8234,23 +8229,20 @@ msgstr ""
"position."
#: doc/classes/AnimationTreePlayer.xml
-#, fuzzy
msgid "Returns the autostart delay of a OneShot node given its name."
-msgstr "Retourne la valeur d'une clé donnée dans une piste donnée."
+msgstr ""
#: doc/classes/AnimationTreePlayer.xml
msgid "Returns the autostart random delay of a OneShot node given its name."
msgstr ""
#: doc/classes/AnimationTreePlayer.xml
-#, fuzzy
msgid "Returns the fade in time of a OneShot node given its name."
-msgstr "Retourne le nom du nœud d'animation donné."
+msgstr ""
#: doc/classes/AnimationTreePlayer.xml
-#, fuzzy
msgid "Returns the fade out time of a OneShot node given its name."
-msgstr "Retourne la valeur d'une clé donnée dans une piste donnée."
+msgstr ""
#: doc/classes/AnimationTreePlayer.xml
msgid "Returns whether a OneShot node will auto restart given its name."
@@ -8364,13 +8356,10 @@ msgstr ""
"transition nommé [code]id[/code]."
#: doc/classes/AnimationTreePlayer.xml
-#, fuzzy
msgid ""
"Returns the index of the currently evaluated input for the transition node "
"with name [code]id[/code]."
msgstr ""
-"Retourne la distance la plus courte de l'avion à la position [code]point [/"
-"code]."
#: doc/classes/AnimationTreePlayer.xml
msgid ""
@@ -8382,11 +8371,10 @@ msgstr ""
"de transition."
#: doc/classes/AnimationTreePlayer.xml
-#, fuzzy
msgid ""
"Returns the cross fade time for the transition node with name [code]id[/"
"code]."
-msgstr "Retourne le nom du nœud à [code]idx[/code]."
+msgstr ""
#: doc/classes/AnimationTreePlayer.xml
msgid ""
@@ -8399,13 +8387,10 @@ msgstr ""
"vers la prochaine entrée dès que la transition se termine."
#: doc/classes/AnimationTreePlayer.xml
-#, fuzzy
msgid ""
"The transition node with name [code]id[/code] sets its current input at "
"[code]input_idx[/code]."
msgstr ""
-"Change la position de l'index de la piste [code]idx[/code] à celui définie "
-"par [code]to_idx[/code]."
#: doc/classes/AnimationTreePlayer.xml
msgid ""
@@ -8424,13 +8409,10 @@ msgstr ""
"nommé [code]id[/code]."
#: doc/classes/AnimationTreePlayer.xml
-#, fuzzy
msgid ""
"The transition node with name [code]id[/code] sets its cross fade time to "
"[code]time_sec[/code]."
msgstr ""
-"Change la position de l'index de la piste [code]idx[/code] à celui définie "
-"par [code]to_idx[/code]."
#: doc/classes/AnimationTreePlayer.xml
msgid ""
@@ -9590,7 +9572,7 @@ msgid ""
"element, the slower [method pop_at] will be."
msgstr ""
"Retire et retourne l'élément du tableau à la [code]position[/code]. Si "
-"négatif, [code]position[/code] part de la la fin du tableau vers le début. "
+"négatif, [code]position[/code] part de la fin du tableau vers le début. "
"Laisse le tableau intact et retourne [code]null[/code] si le tableau est "
"vide ou s'il la position est en dehors des limites du tableau. Un message "
"d'erreur est affiché lorsque la position est en dehors des limites du "
@@ -9932,7 +9914,7 @@ msgid ""
"(see [method add_surface_from_arrays])."
msgstr ""
"Retourne la longueur des indices du tableau d'indices pour la surface "
-"spécifiée (voir [method add_surface_from_arrays].)"
+"spécifiée (voir [method add_surface_from_arrays])."
#: doc/classes/ArrayMesh.xml
msgid ""
@@ -9940,7 +9922,7 @@ msgid ""
"(see [method add_surface_from_arrays])."
msgstr ""
"Retourne la longueur des sommets du tableau des sommets dans la surface "
-"spécifiée (voir [method add_surface_from_arrays].)"
+"spécifiée (voir [method add_surface_from_arrays])."
#: doc/classes/ArrayMesh.xml
msgid ""
@@ -9988,7 +9970,7 @@ msgstr ""
#: doc/classes/ArrayMesh.xml
msgid "Sets the blend shape mode to one of [enum Mesh.BlendShapeMode]."
-msgstr "Définit le mode de forme de mélange avec [enum Mesh.BlendShapeMode]"
+msgstr "Définit le mode de forme de mélange avec [enum Mesh.BlendShapeMode]."
#: doc/classes/ArrayMesh.xml doc/classes/PrimitiveMesh.xml
msgid ""
@@ -10001,10 +9983,8 @@ msgstr ""
"lors de l'utilisation d'un shader qui décale les sommets."
#: doc/classes/ArrayMesh.xml
-#, fuzzy
msgid "Value used internally when no indices are present."
-msgstr ""
-"La valeur par défaut utilisée pour index_array_len quand il n'y pas d'indice."
+msgstr "La valeur par défaut utilisée en interne quand il n'y pas d'indice."
#: doc/classes/ArrayMesh.xml
msgid "Amount of weights/bone indices per vertex (always 4)."
@@ -10227,7 +10207,6 @@ msgstr ""
"constamment mise à jour [code]mesh_updated[/code]."
#: doc/classes/ARVRCamera.xml
-#, fuzzy
msgid ""
"A camera node with a few overrules for AR/VR applied, such as location "
"tracking."
@@ -10384,7 +10363,6 @@ msgstr ""
"identifiant inférieur est éteint."
#: doc/classes/ARVRController.xml
-#, fuzzy
msgid ""
"The degree to which the controller vibrates. Ranges from [code]0.0[/code] to "
"[code]1.0[/code]. If changed, updates [member ARVRPositionalTracker.rumble] "
@@ -10393,8 +10371,8 @@ msgid ""
"for a limited duration."
msgstr ""
"L'intensité de vibration du contrôleur. L'intervalle va de [code]0.0[/code] "
-"à [code]1.0[/code] avec une précision de [code]0.01[/code]. Si changé, met à "
-"jour [membrez ARVRPositionalTracker.rumble] en conséquence.\n"
+"à [code]1.0[/code]. Si changé, [member ARVRPositionalTracker.rumble] sera "
+"mis à jour en conséquence.\n"
"C'est une propriété utile à animer si vous souhaitez que le contrôleur vibre "
"pendant une durée limitée."
@@ -10564,6 +10542,7 @@ msgstr "Cette interface est compatible avec le rendu stéréoscopique."
#: doc/classes/ARVRInterface.xml
msgid "This interface supports AR (video background and real world tracking)."
msgstr ""
+"Cette interface supporte la AR (arrière-plan vidéo et suivi du monde réel)."
#: doc/classes/ARVRInterface.xml
msgid ""
@@ -10640,9 +10619,8 @@ msgstr ""
"lumières sont éteintes, etc.)."
#: modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml
-#, fuzzy
msgid "GDNative wrapper for an ARVR interface."
-msgstr "Classe de base pour une implémentation d’interface AR / VR."
+msgstr "L'encapsulation GDNative pour les interfaces ARVR."
#: modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml
msgid ""
@@ -11074,7 +11052,6 @@ msgstr ""
"position du joueur."
#: doc/classes/AspectRatioContainer.xml
-#, fuzzy
msgid "Container that preserves its child controls' aspect ratio."
msgstr "Un conteneur qui préserve le ratio d'aspect des contrôles enfants."
@@ -11097,19 +11074,16 @@ msgstr ""
#: doc/classes/PanelContainer.xml doc/classes/ScrollContainer.xml
#: doc/classes/SplitContainer.xml doc/classes/TabContainer.xml
#: doc/classes/VBoxContainer.xml doc/classes/VSplitContainer.xml
-#, fuzzy
msgid "GUI containers"
-msgstr "Conteneur à onglets."
+msgstr "Conteneurs d'interface"
#: doc/classes/AspectRatioContainer.xml
-#, fuzzy
msgid "Specifies the horizontal relative position of child controls."
-msgstr "La séparation horizontale des nœuds enfants."
+msgstr "Définit la position horizontale relative des nœuds enfants."
#: doc/classes/AspectRatioContainer.xml
-#, fuzzy
msgid "Specifies the vertical relative position of child controls."
-msgstr "La séparation verticale des nœuds enfants."
+msgstr "Définit la position verticale relative des nœuds enfants."
#: doc/classes/AspectRatioContainer.xml
msgid ""
@@ -11160,19 +11134,17 @@ msgstr ""
"de limiter la visibilité à seulement la taille du conteneur."
#: doc/classes/AspectRatioContainer.xml
-#, fuzzy
msgid ""
"Aligns child controls with the beginning (left or top) of the container."
-msgstr "Aligne les enfants avec le début du conteneur."
+msgstr "Aligne les enfants au début (à gauche ou en haut) du conteneur."
#: doc/classes/AspectRatioContainer.xml
msgid "Aligns child controls with the center of the container."
msgstr "Aligne les contrôles enfants au centre du conteneur."
#: doc/classes/AspectRatioContainer.xml
-#, fuzzy
msgid "Aligns child controls with the end (right or bottom) of the container."
-msgstr "Aligne les enfants avec le centre du conteneur."
+msgstr "Aligne les enfants à la fin (à droite ou en-bas) du conteneur."
#: doc/classes/AStar.xml
msgid ""
@@ -11657,14 +11629,13 @@ msgstr ""
"position et sont facteur de poids seront mis à jour avec la valeur donnée."
#: doc/classes/AStar2D.xml
-#, fuzzy
msgid ""
"Returns whether there is a connection/segment between the given points. If "
"[code]bidirectional[/code] is [code]false[/code], returns whether movement "
"from [code]id[/code] to [code]to_id[/code] is possible through this segment."
msgstr ""
"Retourne si les deux points donnés sont directement reliés par un segment. "
-"Si [code]bidirectionnel[/code] est [code]false[/code], retourne si le "
+"Si [code]bidirectional[/code] est [code]false[/code], retourne si le "
"mouvement d'identifiant [code]id[/code] vers l'autre identifiant "
"[code]to_id[/code] est possible par ce segment."
@@ -11852,11 +11823,10 @@ msgstr ""
"sont ignorés pour les AtlasTexture."
#: doc/classes/AtlasTexture.xml
-#, fuzzy
msgid "The texture that contains the atlas. Can be any [Texture] subtype."
msgstr ""
-"La texture qui contient l'atlas. Peut être de n'importe quel sous-type "
-"[Texture2D]."
+"La texture qui contient l'atlas. Peut être de n'importe quel sous-type de "
+"[Texture]."
#: doc/classes/AtlasTexture.xml
msgid ""
@@ -11991,9 +11961,8 @@ msgstr ""
"pas assez de données disponibles."
#: doc/classes/AudioEffectCapture.xml
-#, fuzzy
msgid "Returns the total size of the internal ring buffer in frames."
-msgstr "Renvoie le reste de deux vecteurs."
+msgstr ""
#: doc/classes/AudioEffectCapture.xml
msgid ""
@@ -12004,15 +11973,13 @@ msgstr ""
"mémoire est pleine."
#: doc/classes/AudioEffectCapture.xml
-#, fuzzy
msgid ""
"Returns the number of frames available to read using [method get_buffer]."
-msgstr "Retourne le nombre de formes assignées à une zone."
+msgstr ""
#: doc/classes/AudioEffectCapture.xml
-#, fuzzy
msgid "Returns the number of audio frames inserted from the audio bus."
-msgstr "Renvoie le nombre de points sur l'axe de mélange."
+msgstr ""
#: doc/classes/AudioEffectCapture.xml
msgid ""
@@ -13013,7 +12980,6 @@ msgid "Returns the names of all audio devices detected on the system."
msgstr "Retourne les noms de tous les appareils audio détectés sur le système."
#: doc/classes/AudioServer.xml
-#, fuzzy
msgid "Returns the sample rate at the output of the [AudioServer]."
msgstr "Retourne le débit de sortie du [AudioServer]."
@@ -13298,14 +13264,11 @@ msgstr ""
"pour lire l'audio généré en temps réel."
#: doc/classes/AudioStreamGeneratorPlayback.xml
-#, fuzzy
msgid ""
"Returns [code]true[/code] if a buffer of the size [code]amount[/code] can be "
"pushed to the audio sample data buffer without overflowing it, [code]false[/"
"code] otherwise."
msgstr ""
-"Retourne [code]true[/code] si le paramètre spécifié par [code]name[/code] "
-"existe, [code]false[/code] autrement."
#: doc/classes/AudioStreamGeneratorPlayback.xml
msgid "Clears the audio sample data buffer."
@@ -13347,9 +13310,8 @@ msgstr ""
"[i]moins[/i] efficace avec GDScript."
#: modules/minimp3/doc_classes/AudioStreamMP3.xml
-#, fuzzy
msgid "MP3 audio stream driver."
-msgstr "Pilote de flux audio OGG Vorbis."
+msgstr "Le pilote de flux audio MP3."
#: modules/minimp3/doc_classes/AudioStreamMP3.xml
#: modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml
@@ -14149,9 +14111,8 @@ msgstr ""
"[constant ENVIRONMENT_MODE_CUSTOM_SKY]."
#: doc/classes/BakedLightmap.xml
-#, fuzzy
msgid "The rotation of the baked custom sky."
-msgstr "La racine de la scène éditée."
+msgstr ""
#: doc/classes/BakedLightmap.xml
msgid ""
@@ -14260,9 +14221,8 @@ msgid "Currently unused."
msgstr "Actuellement inutilisé."
#: doc/classes/BakedLightmap.xml
-#, fuzzy
msgid "Returns when the baker cannot save per-mesh textures to file."
-msgstr "Renvoie l'arc tangente des paramètres."
+msgstr ""
#: doc/classes/BakedLightmap.xml
msgid "The size of the generated lightmaps is too large."
@@ -14363,7 +14323,6 @@ msgstr ""
"défini par l'enumération [enum DrawMode]."
#: doc/classes/BaseButton.xml
-#, fuzzy
msgid ""
"Returns [code]true[/code] if the mouse has entered the button and has not "
"left it yet."
@@ -15497,14 +15456,12 @@ msgid "Returns the current pressed button."
msgstr "Renvoie le bouton actuellement enfoncé."
#: doc/classes/ButtonGroup.xml
-#, fuzzy
msgid "Emitted when one of the buttons of the group is pressed."
-msgstr "Émis lorsqu’un bouton de ce contrôleur est appuyé."
+msgstr "Émis lorsqu’un des boutons de ce groupe est appuyé."
#: doc/classes/CallbackTweener.xml
-#, fuzzy
msgid "Calls the specified method after optional delay."
-msgstr "Verrouille l'axe linéaire et de rotation spécifié."
+msgstr "Appelle la méthode spécifiée après un délai optionnel."
#: doc/classes/CallbackTweener.xml
msgid ""
@@ -16088,7 +16045,7 @@ msgid ""
"Left margin needed to drag the camera. A value of [code]1[/code] makes the "
"camera move only when reaching the edge of the screen."
msgstr ""
-"La marge gauche nécessaire pour pour glisser la caméra. Une valeur de "
+"La marge gauche nécessaire pour glisser la caméra. Une valeur de "
"[code]1[/code] ne déplace la caméra que lorsqu'elle atteint le bord de "
"l'écran."
@@ -16097,7 +16054,7 @@ msgid ""
"Right margin needed to drag the camera. A value of [code]1[/code] makes the "
"camera move only when reaching the edge of the screen."
msgstr ""
-"La marge droite nécessaire pour pour glisser la caméra. Une valeur de "
+"La marge droite nécessaire pour glisser la caméra. Une valeur de "
"[code]1[/code] ne déplace la caméra que lorsqu'elle atteint le bord de "
"l'écran."
@@ -16106,7 +16063,7 @@ msgid ""
"Top margin needed to drag the camera. A value of [code]1[/code] makes the "
"camera move only when reaching the edge of the screen."
msgstr ""
-"La marge supérieure nécessaire pour pour glisser la caméra. Une valeur de "
+"La marge supérieure nécessaire pour glisser la caméra. Une valeur de "
"[code]1[/code] ne déplacer la caméra que lorsqu'elle atteint le bord de "
"l'écran."
@@ -16222,9 +16179,8 @@ msgstr ""
"La méthode de mise à jour de la camera. Voir [enum Camera2DProcessMode]."
#: doc/classes/Camera2D.xml
-#, fuzzy
msgid "If [code]true[/code], the camera view rotates with the target."
-msgstr "Si [code]true[/code], le bouton \"add preset\" est activé."
+msgstr ""
#: doc/classes/Camera2D.xml
msgid ""
@@ -16312,9 +16268,8 @@ msgid "Returns the unique ID for this feed."
msgstr "Retourne l'identifiant unique de ce flux."
#: doc/classes/CameraFeed.xml
-#, fuzzy
msgid "Returns the camera's name."
-msgstr "Renvoie le nom de l'élément."
+msgstr "Retourne le nom de la caméra."
#: doc/classes/CameraFeed.xml
msgid "Returns the position of camera on the device."
@@ -16384,20 +16339,18 @@ msgstr ""
"iOS. Sur les autres plates-formes, aucun [CameraFeed] ne sera disponible."
#: doc/classes/CameraServer.xml
-#, fuzzy
msgid "Adds the camera [code]feed[/code] to the camera server."
-msgstr "Ajoute un [Shape2D] au propriétaire de la forme."
+msgstr ""
#: doc/classes/CameraServer.xml
msgid "Returns an array of [CameraFeed]s."
msgstr "Retourne un tableau de [CameraFeed]s."
#: doc/classes/CameraServer.xml
-#, fuzzy
msgid ""
"Returns the [CameraFeed] corresponding to the camera with the given "
"[code]index[/code]."
-msgstr "Retourne la position du point à l'index [code]point[/code]."
+msgstr ""
#: doc/classes/CameraServer.xml
msgid "Returns the number of [CameraFeed]s registered."
@@ -16408,14 +16361,12 @@ msgid "Removes the specified camera [code]feed[/code]."
msgstr "Supprime le flux de caméra [code]feed[/code] spécifié."
#: doc/classes/CameraServer.xml
-#, fuzzy
msgid "Emitted when a [CameraFeed] is added (e.g. a webcam is plugged in)."
-msgstr "Émis lorsqu'une interface est supprimée."
+msgstr ""
#: doc/classes/CameraServer.xml
-#, fuzzy
msgid "Emitted when a [CameraFeed] is removed (e.g. a webcam is unplugged)."
-msgstr "Émis lorsqu'une interface est supprimée."
+msgstr ""
#: doc/classes/CameraServer.xml
msgid "The RGBA camera image."
@@ -17451,9 +17402,8 @@ msgstr ""
"[CanvasLayer] n'est pas propagée aux calques enfants."
#: doc/classes/CanvasLayer.xml
-#, fuzzy
msgid "Emitted when visibility of the layer is changed. See [member visible]."
-msgstr "Émis lorsque le VisibilityNotifier3D quitte la vue d'un [Camera3D]."
+msgstr ""
#: doc/classes/CanvasModulate.xml
msgid "Tint the entire canvas."
@@ -17548,13 +17498,12 @@ msgstr ""
"contrôler le rendu de caractères individuels dans un [RichTextEffect]."
#: doc/classes/CharFXTransform.xml
-#, fuzzy
msgid ""
"The index of the current character (starting from 0) for the "
"[RichTextLabel]'s BBCode text. Setting this property won't affect drawing."
msgstr ""
-"L'index du caractère actuel (commence à 0). Régler cette propriété n'affecte "
-"pas l'affichage."
+"L'index du caractère actuel (commence à 0) pour le texte BBCode du "
+"[RichTextLabel]. Régler cette propriété n'affecte pas l'affichage."
#: doc/classes/CharFXTransform.xml
msgid ""
@@ -17633,13 +17582,12 @@ msgstr ""
"pixels)."
#: doc/classes/CharFXTransform.xml
-#, fuzzy
msgid ""
"The index of the current character (starting from 0) for this "
"[RichTextEffect] custom block. Setting this property won't affect drawing."
msgstr ""
-"L'index du caractère actuel (commence à 0). Régler cette propriété n'affecte "
-"pas l'affichage."
+"L'index du caractère actuel (commence à 0) pour le bloc personnalisé du "
+"[RichTextEffect]. Régler cette propriété n'affecte pas l'affichage."
#: doc/classes/CharFXTransform.xml
msgid ""
@@ -17757,10 +17705,9 @@ msgid "The check icon to display when the [CheckBox] is unchecked."
msgstr "L'icône de la coche à afficher quand la [CheckBox] est décochée."
#: doc/classes/CheckBox.xml
-#, fuzzy
msgid ""
"The check icon to display when the [CheckBox] is unchecked and disabled."
-msgstr "Icône à afficher lorsque le [CheckButton] est coché et désactivé."
+msgstr "L'icône à afficher lorsque le [CheckBox] est décoché et désactivé."
#: doc/classes/CheckBox.xml
msgid ""
@@ -17977,10 +17924,9 @@ msgstr ""
"code] de la [code]class[/code] ou de ses parents."
#: doc/classes/ClassDB.xml
-#, fuzzy
msgid ""
"Returns an array with all the enums of [code]class[/code] or its ancestry."
-msgstr "Retourne si la [code]class[/code] spécifiée est disponible ou non."
+msgstr ""
#: doc/classes/ClassDB.xml
msgid ""
@@ -18252,7 +18198,7 @@ msgid ""
msgstr ""
"CollisionObject est la classe de base pour les objets physiques. Il peut "
"contenir n'importe quel nombre de formes [Shape] de collision. Chaque forme "
-"doit être assignée à un [i]propriétaire de forme[ /i]. Le CollisionObject "
+"doit être assignée à un [i]propriétaire de forme[/i]. Le CollisionObject "
"peut avoir n'importe quel nombre de propriétaires de forme. Les "
"propriétaires de forme ne sont pas des nœuds et ne apparaissent pas dans "
"l'éditeur, mais sont accessibles par le code en utilisant les méthodes "
@@ -18361,20 +18307,18 @@ msgid "Returns the parent object of the given shape owner."
msgstr "Retourne l'objet parent du propriétaire de la forme spécifié."
#: doc/classes/CollisionObject.xml
-#, fuzzy
msgid "Returns the [Shape] with the given id from the given shape owner."
-msgstr "Retourne le [RID] de la énième forme d'une zone."
+msgstr ""
#: doc/classes/CollisionObject.xml doc/classes/CollisionObject2D.xml
msgid "Returns the number of shapes the given shape owner contains."
msgstr "Retourne le nombre de formes que le propriétaire de forme contient."
#: doc/classes/CollisionObject.xml
-#, fuzzy
msgid ""
"Returns the child index of the [Shape] with the given id from the given "
"shape owner."
-msgstr "Retourne la liste de tous les nœuds du shader avec le type spécifié."
+msgstr ""
#: doc/classes/CollisionObject.xml
msgid "Returns the shape owner's [Transform]."
@@ -18839,11 +18783,12 @@ msgid "2D Kinematic Character Demo"
msgstr "Démo de caractère cinétique 2D"
#: doc/classes/CollisionShape2D.xml
-#, fuzzy
msgid ""
"A disabled collision shape has no effect in the world. This property should "
"be changed with [method Object.set_deferred]."
-msgstr "Une forme de collision désactivée n’a aucun effet dans le monde."
+msgstr ""
+"Une forme de collision désactivée n’a aucun effet dans le monde. Cette "
+"propriété devrait être modifiée avec [method Object.set_deferred]."
#: doc/classes/CollisionShape2D.xml
msgid ""
@@ -19976,9 +19921,8 @@ msgstr ""
"performance)."
#: doc/classes/ColorPicker.xml
-#, fuzzy
msgid "If [code]true[/code], shows an alpha channel slider (opacity)."
-msgstr "Si [code]true[/code], le GraphNode est sélectionné."
+msgstr ""
#: doc/classes/ColorPicker.xml
msgid ""
@@ -21003,15 +20947,12 @@ msgstr ""
"[/codeblock]"
#: doc/classes/Control.xml
-#, fuzzy
msgid ""
"Creates a local override for a theme constant with the specified [code]name[/"
"code]. Local overrides always take precedence when fetching theme items for "
"the control.\n"
"See also [method get_constant], [method remove_constant_override]."
msgstr ""
-"Retourne [code]true[/code] si le paramètre spécifié par [code]name[/code] "
-"existe, [code]false[/code] autrement."
#: doc/classes/Control.xml
msgid ""
@@ -21393,9 +21334,8 @@ msgstr ""
"Retourne la taille minimale de ce contrôle. Voir [member rect_min_size]."
#: doc/classes/Control.xml
-#, fuzzy
msgid "Returns the width/height occupied in the parent control."
-msgstr "Renvoie la largeur / hauteur occupée dans le contrôle du parent."
+msgstr "Retourne la largeur / hauteur occupée dans le contrôle du parent."
#: doc/classes/Control.xml
msgid "Returns the parent control node."
@@ -21500,7 +21440,7 @@ msgid ""
"See [method get_color] for details."
msgstr ""
"Retourne [code]true[/code] s'il y a un [Theme] correspondant dans "
-"l'arborescence qui a une propriété de constante nommée [/code]name[/code] et "
+"l'arborescence qui a une propriété de constante nommée [code]name[/code] et "
"du type de thème [code]theme_type[/code].\n"
"Voir [method get_color] pour plus de détails."
@@ -21644,37 +21584,31 @@ msgstr ""
"clavier."
#: doc/classes/Control.xml
-#, fuzzy
msgid ""
"Removes a theme override for a [Color] with the given [code]name[/code]."
-msgstr "Supprime l’animation avec la touche [code]name[/code]."
+msgstr ""
#: doc/classes/Control.xml
-#, fuzzy
msgid ""
"Removes a theme override for a constant with the given [code]name[/code]."
-msgstr "Supprime l’animation avec la touche [code]name[/code]."
+msgstr ""
#: doc/classes/Control.xml
-#, fuzzy
msgid "Removes a theme override for a [Font] with the given [code]name[/code]."
-msgstr "Supprime l’animation avec la touche [code]name[/code]."
+msgstr ""
#: doc/classes/Control.xml
-#, fuzzy
msgid "Removes a theme override for an icon with the given [code]name[/code]."
-msgstr "Supprime l’animation avec la touche [code]name[/code]."
+msgstr ""
#: doc/classes/Control.xml
-#, fuzzy
msgid "Removes a theme override for a shader with the given [code]name[/code]."
-msgstr "Retourne la position du point à l'index [code]point[/code]."
+msgstr ""
#: doc/classes/Control.xml
-#, fuzzy
msgid ""
"Removes a theme override for a [StyleBox] with the given [code]name[/code]."
-msgstr "Supprime l’animation avec la touche [code]name[/code]."
+msgstr ""
#: doc/classes/Control.xml
msgid ""
@@ -22627,20 +22561,20 @@ msgstr ""
"Affiche le curseur en croix du système quand l'utilisateur survole ce nœud."
#: doc/classes/Control.xml
-#, fuzzy
msgid ""
"Show the system's wait mouse cursor when the user hovers the node. Often an "
"hourglass."
msgstr ""
-"Affiche le curseur en croix du système quand l'utilisateur survole ce nœud."
+"Affiche le curseur d'attente du système quand l'utilisateur survole ce nœud. "
+"Souvent un sablier."
#: doc/classes/Control.xml
-#, fuzzy
msgid ""
"Show the system's busy mouse cursor when the user hovers the node. Often an "
"arrow with a small hourglass."
msgstr ""
-"Affiche le curseur en croix du système quand l'utilisateur survole ce nœud."
+"Affiche le curseur d'occupation du système quand l'utilisateur survole ce "
+"nœud. Souvent une flèche avec un petit sablier."
#: doc/classes/Control.xml
msgid ""
@@ -23056,10 +22990,10 @@ msgid ""
"variables, like [member anchor_left]. To change all 4 anchors at once, use "
"[method set_anchors_preset]."
msgstr ""
-"Magnétise l'un des 4 côtés d'ancrage à l'origine de l'ancrage [code]Rect[/"
-"code], en haut à gauche. Utilisez-le avec l'une des variables membres "
-"[code]anchor_[* /code], comme [member anchor_left]. Pour modifier les 4 "
-"ancres à la fois, utilisez [method set_anchors_preset]."
+"Magnétise l'un des 4 côtés d'ancrage à l'origine de l'ancrage "
+"[code]Rect[/code], en haut à gauche. Utilisez-le avec l'une des variables "
+"membres [code]anchor_*[/code], comme [member anchor_left]. Pour modifier les "
+"4 ancres à la fois, utilisez [method set_anchors_preset]."
#: doc/classes/Control.xml
msgid ""
@@ -23070,18 +23004,19 @@ msgid ""
msgstr ""
"Magnétise l'un des 4 côtés d'ancrage à l'extrémité de l'extrémité "
"[code]Rect[/code], en bas à droite. Utilisez-le avec l'une des variables "
-"membres [code]anchor_[* /code], comme [member anchor_left]. Pour modifier "
-"les 4 ancres à la fois, utilisez [method set_anchors_preset]."
+"membres [code]anchor_*[/code], comme [member anchor_left]. Pour modifier les "
+"4 ancres à la fois, utilisez [method set_anchors_preset]."
#: doc/classes/ConvexPolygonShape.xml
msgid "Convex polygon shape for 3D physics."
msgstr "Forme de polygone convexe pour la physique 3D."
#: doc/classes/ConvexPolygonShape.xml
-#, fuzzy
msgid ""
"Convex polygon shape resource, which can be added to a [PhysicsBody] or area."
-msgstr "Ressource de forme de polygone concave 2D pour la physique."
+msgstr ""
+"Un ressource de forme de polygone convexe, qui peut être ajoutée à un "
+"[PhysicsBody] ou une aire."
#: doc/classes/ConvexPolygonShape.xml
msgid "The list of 3D points forming the convex polygon shape."
@@ -24348,7 +24283,6 @@ msgid ""
msgstr ""
#: modules/csg/doc_classes/CSGCylinder.xml
-#, fuzzy
msgid ""
"If [code]true[/code] a cone is created, the [member radius] will only apply "
"to one side."
@@ -24551,9 +24485,8 @@ msgstr ""
"aucun maillage ne sera généré."
#: modules/csg/doc_classes/CSGPolygon.xml
-#, fuzzy
msgid "If [code]true[/code], applies smooth shading to the extrusions."
-msgstr "Si [code]true[/code], l’audio est stéréo."
+msgstr ""
#: modules/csg/doc_classes/CSGPolygon.xml
msgid ""
@@ -24785,7 +24718,6 @@ msgid "Only intersecting geometry remains, the rest is removed."
msgstr "Il ne reste que la géométrie d'intersection, le reste est supprimé."
#: modules/csg/doc_classes/CSGShape.xml
-#, fuzzy
msgid ""
"The second shape is subtracted from the first, leaving a dent with its shape."
msgstr ""
@@ -24874,13 +24806,12 @@ msgstr ""
"le tore aura un aspect de rendu plat."
#: modules/mono/doc_classes/CSharpScript.xml
-#, fuzzy
msgid ""
"A script implemented in the C# programming language (Mono-enabled builds "
"only)."
msgstr ""
-"Un script implémenté dans le langage de programmation C# (uniquement des "
-"compilations Mono-activé)."
+"Un script implémenté en langage C# (uniquement pour les versions où Mono est "
+"activé)."
#: modules/mono/doc_classes/CSharpScript.xml
msgid ""
@@ -24909,9 +24840,8 @@ msgid ""
msgstr ""
#: doc/classes/CubeMap.xml
-#, fuzzy
msgid "Returns the [CubeMap]'s height."
-msgstr "Retourne la hauteur de texture."
+msgstr "Retourne la hauteur du [CubeMap]."
#: doc/classes/CubeMap.xml
msgid ""
@@ -24922,9 +24852,8 @@ msgstr ""
"constantes [enum Side]."
#: doc/classes/CubeMap.xml
-#, fuzzy
msgid "Returns the [CubeMap]'s width."
-msgstr "Renvoie la largeur de texture."
+msgstr "Renvoie la largeur du [CubeMap]."
#: doc/classes/CubeMap.xml
msgid ""
@@ -24951,9 +24880,8 @@ msgstr ""
"défini à [constant STORAGE_COMPRESS_LOSSY]."
#: doc/classes/CubeMap.xml
-#, fuzzy
msgid "The [CubeMap]'s storage mode. See [enum Storage] constants."
-msgstr "Convertit le format de l’image. Voir les constantes [enum Format]."
+msgstr ""
#: doc/classes/CubeMap.xml
msgid "Store the [CubeMap] without any compression."
@@ -25370,13 +25298,13 @@ msgid ""
"list."
msgstr ""
"Ajoute un point à une courbe à la [code]position[/code] par rapport à la "
-"position de la [Curve2D], avec des points de contrôle d'entrée [code]in[/"
-"code] et de sortie [code]out[/code].\n"
+"position de la [Curve2D], avec des points de contrôle d'entrée "
+"[code]in[/code] et de sortie [code]out[/code].\n"
"Si [code]at_position[/code] est spécifié, le point est inséré juste avant ce "
"numéro de point [code]at_position[/code], en déplaçant ce point (et tous les "
-"autres points qui suivent) après le point inséré. Si [code]at_position[/"
-"code] n'est pas donné, ou est une valeur invalide ([code]at_position < 0[/"
-"code] ou [code]at_position >= [method get_point_count][/code,) le point sera "
+"autres points qui suivent) après le point inséré. Si [code]at_position[/code]"
+" n'est pas donné, ou est une valeur invalide ([code]at_position < 0[/code] "
+"ou [code]at_position >= [method get_point_count][/code]), le point sera "
"ajouté en dernier."
#: doc/classes/Curve2D.xml doc/classes/Curve3D.xml
@@ -25796,9 +25724,8 @@ msgstr ""
"courbes et/ou de les enregistrer dans des fichiers d'image."
#: doc/classes/CurveTexture.xml
-#, fuzzy
msgid "The [Curve] that is rendered onto the texture."
-msgstr "La [code]curve[/code] rendue sur la texture."
+msgstr "La [Curve] qui est rendue dans la texture."
#: doc/classes/CurveTexture.xml
msgid ""
@@ -25878,9 +25805,8 @@ msgid "The cylinder's radius."
msgstr "Le rayon du cylindre."
#: doc/classes/DampedSpringJoint2D.xml
-#, fuzzy
msgid "Damped spring constraint for 2D physics."
-msgstr "Contrainte de ressort amortie pour la physique 2D."
+msgstr "Une contrainte de ressort avec amortissement pour la physique 2D."
#: doc/classes/DampedSpringJoint2D.xml
msgid ""
@@ -26491,9 +26417,9 @@ msgid ""
msgstr ""
"Change le dossier actuellement ouvert par celui donné en argument. "
"L'argument peut être relatif au répertoire actuel (par exemple "
-"[code]nouveau_dossier[/code] ou [code]./dossier[ /code,)] ou être un chemin "
+"[code]nouveau_dossier[/code] ou [code]./dossier[/code]), ou être un chemin "
"absolu (par exemple [code]/tmp/dossier[/code] ou [code]res://parent/"
-"dossier[ /code)].\n"
+"dossier[/code]).\n"
"Retourne une des constantes de code [enum Error] (et [code]OK[/code] en cas "
"de succès)."
@@ -27116,9 +27042,8 @@ msgid "Disables font hinting (smoother but less crisp)."
msgstr ""
#: doc/classes/DynamicFontData.xml
-#, fuzzy
msgid "Use the light font hinting mode."
-msgstr "Utilisez le mode d’allusion de police de lumière."
+msgstr "Utilise le mode d'indice de police légère."
#: doc/classes/DynamicFontData.xml
msgid "Use the default font hinting mode (crisper but less smooth)."
@@ -27379,15 +27304,15 @@ msgstr ""
"[method save_to_file]."
#: doc/classes/EditorFeatureProfile.xml
-#, fuzzy
msgid ""
"Saves the editor feature profile to a file in JSON format. It can then be "
"imported using the feature profile manager's [b]Import[/b] button or the "
"[method load_from_file] method."
msgstr ""
"Enregistre le profil de fonctionnalité de l'éditeur dans un fichier au "
-"format JSON. Il peut ensuite être importé en utilisant le bouton [b]Import[/"
-"b] ou la méthode [method load_from_file]."
+"format JSON. Il peut ensuite être importé en utilisant le bouton "
+"[b]Importer[/b] du gestionnaire de profils ou via la méthode [method "
+"load_from_file]."
#: doc/classes/EditorFeatureProfile.xml
msgid ""
@@ -27546,7 +27471,7 @@ msgid ""
"code], [code]user://[/code], and the local file system."
msgstr ""
"L'emplacement à partir duquel l'utilisateur peut sélectionner un fichier, y "
-"compris [code]res://[/code], [code]user://[code], et le système de fichiers "
+"compris [code]res://[/code], [code]user://[/code], et le système de fichiers "
"local."
#: doc/classes/EditorFileDialog.xml
@@ -27686,7 +27611,7 @@ msgstr ""
"fichiers, leurs types, etc.\n"
"[b]Note :[/b] Cette classe ne devrait pas être instanciée directement. "
"Accédez plutôt à l'instance unique avec [method EditorInterface."
-"get_resource_filesystem]"
+"get_resource_filesystem]."
#: doc/classes/EditorFileSystem.xml
msgid ""
@@ -27716,7 +27641,6 @@ msgstr ""
"en train d'être scanné."
#: doc/classes/EditorFileSystem.xml
-#, fuzzy
msgid "Returns [code]true[/code] if the filesystem is being scanned."
msgstr "Retourne [code]true[/code] si le système de fichier a été scanné."
@@ -27927,8 +27851,8 @@ msgid ""
msgstr ""
"Les [EditorImportPlugin] fournissent un moyen d'étendre la fonctionnalité "
"d'importation des ressources dans l'éditeur. Utilisez-les pour importer des "
-"ressources depuis des formats de de fichier personnalisés ou pour proposer "
-"une alternative aux importateurs existants de l'éditeur.\n"
+"ressources depuis des formats de fichier personnalisés ou pour proposer une "
+"alternative aux importateurs existants de l'éditeur.\n"
"Les EditorImportPlugins fonctionnent pas associés certaines extensions de "
"fichiers avec un type de ressource. Voir [method get_recognized_extensions] "
"et [method get_resource_type]. Ils peuvent aussi spécifier des préréglages "
@@ -28122,10 +28046,8 @@ msgstr ""
"surcharge de cette méthode."
#: doc/classes/EditorInspector.xml
-#, fuzzy
msgid "A control used to edit properties of an object."
-msgstr ""
-"Contrôle personnalisé pour modifier les propriétés à ajouter à l’inspecteur."
+msgstr "Un contrôle pour modifier les propriétés d'un objet."
#: doc/classes/EditorInspector.xml
msgid ""
@@ -28520,22 +28442,16 @@ msgstr ""
"[code]object[/code]."
#: doc/classes/EditorInterface.xml
-#, fuzzy
msgid ""
"Returns [code]true[/code] if a scene is currently being played, [code]false[/"
"code] otherwise. Paused scenes are considered as being played."
msgstr ""
-"Retourne [code]true[/code] si la chaîne de caractères commence par la chaîne "
-"de caractères donnée, ou [code]false[/code] le cas échéant."
#: doc/classes/EditorInterface.xml
-#, fuzzy
msgid ""
"Returns [code]true[/code] if the specified [code]plugin[/code] is enabled. "
"The plugin name is the same as its directory name."
msgstr ""
-"Renvoie [code]true[/code] (vrai) si [code]s[/code] vaut zéro ou quasiment "
-"zéro."
#: doc/classes/EditorInterface.xml
msgid ""
@@ -29315,29 +29231,25 @@ msgid "Removes a custom type added by [method add_custom_type]."
msgstr "Supprime un type personnalisé ajouté par [method add_custom_type]."
#: doc/classes/EditorPlugin.xml
-#, fuzzy
msgid "Removes an export plugin registered by [method add_export_plugin]."
-msgstr "Supprime un type personnalisé ajouté par [method add_custom_type]."
+msgstr ""
#: doc/classes/EditorPlugin.xml
-#, fuzzy
msgid "Removes an import plugin registered by [method add_import_plugin]."
-msgstr "Supprime un type personnalisé ajouté par [method add_custom_type]."
+msgstr ""
#: doc/classes/EditorPlugin.xml
msgid "Removes an inspector plugin registered by [method add_import_plugin]"
msgstr "Supprime un type personnalisé ajouté par [method add_custom_type]"
#: doc/classes/EditorPlugin.xml
-#, fuzzy
msgid ""
"Removes a scene importer registered by [method add_scene_import_plugin]."
-msgstr "Supprime un type personnalisé ajouté par [method add_custom_type]."
+msgstr ""
#: doc/classes/EditorPlugin.xml
-#, fuzzy
msgid "Removes a gizmo plugin registered by [method add_spatial_gizmo_plugin]."
-msgstr "Supprime un type personnalisé ajouté par [method add_custom_type]."
+msgstr ""
#: doc/classes/EditorPlugin.xml
msgid "Removes a menu [code]name[/code] from [b]Project > Tools[/b]."
@@ -29528,7 +29440,7 @@ msgid ""
"must be previously added using [method Node.add_child]."
msgstr ""
"Place le contrôle [code]editor[/code] sous le label de la propriété. Le "
-"contrôle doit d'abord être ajouté avec [method Node.add_child]"
+"contrôle doit d'abord être ajouté avec [method Node.add_child]."
#: doc/classes/EditorProperty.xml
msgid "When this virtual function is called, you must update your editor."
@@ -29588,9 +29500,9 @@ msgid ""
"Emit it if you want multiple properties modified at the same time. Do not "
"use if added via [method EditorInspectorPlugin.parse_property]."
msgstr ""
-"Emettez-le si vous voulez plusieurs propriétés modifiées en même temps. Ne "
+"Émettez-le si vous voulez plusieurs propriétés modifiées en même temps. Ne "
"pas utiliser s'il a été ajouté avec [method EditorInspectorPlugin."
-"parse_property]"
+"parse_property]."
#: doc/classes/EditorProperty.xml
msgid "Used by sub-inspectors. Emit it if what was selected was an Object ID."
@@ -29739,9 +29651,8 @@ msgstr ""
"set_toggle_pressed] pour définir manuellement cet état."
#: doc/classes/EditorResourcePicker.xml
-#, fuzzy
msgid "Emitted when the value of the edited resource was changed."
-msgstr "Émis à chaque fois que la ressource change."
+msgstr "Émis quand le valeur d'une ressource modifiée a été changée."
#: doc/classes/EditorResourcePicker.xml
msgid ""
@@ -29767,7 +29678,7 @@ msgstr ""
"fichiers.\n"
"[b]Note :[/b] Cette classe ne devrait pas être instanciée directement. "
"Accédez plutôt à l'instance unique en utilisant [method EditorInterface."
-"get_resource_previewer]"
+"get_resource_previewer]."
#: doc/classes/EditorResourcePreview.xml
msgid "Create an own, custom preview generator."
@@ -30174,7 +30085,7 @@ msgstr ""
"Cet objet gère la sélection dans le SceneTree dans l'éditeur.\n"
"[b]Note :[/b] Cette classe ne devrait pas être instanciée directement. "
"Accédez plutôt à l'instance unique en utilisant [method EditorInterface."
-"get_selection]"
+"get_selection]."
#: doc/classes/EditorSelection.xml
msgid ""
@@ -30572,12 +30483,11 @@ msgid ""
msgstr ""
"Retourne le [EditorSpatialGizmoPlugin] qui possède ce manipulateur. Il est "
"utile de récupérer les matériaux en utilisant [method "
-"EditorSpatialGizmoPlugin.get_material]"
+"EditorSpatialGizmoPlugin.get_material]."
#: doc/classes/EditorSpatialGizmo.xml
-#, fuzzy
msgid "Returns the Spatial node associated with this gizmo."
-msgstr "Retourne le chemin d’accès au nœud associé à l’os spécifié."
+msgstr ""
#: doc/classes/EditorSpatialGizmo.xml
msgid ""
@@ -30778,9 +30688,8 @@ msgid ""
msgstr ""
#: doc/classes/EditorSpinSlider.xml
-#, fuzzy
msgid "If [code]true[/code], the slider is hidden."
-msgstr "Si [code]true[/code], la flèche de réduction est masquée."
+msgstr "Si [code]true[/code], le glisseur est masqué."
#: doc/classes/EditorVCSInterface.xml
msgid ""
@@ -30809,10 +30718,8 @@ msgstr ""
"hériter de [EditorVCSInterface] et surcharger ces fonctions virtuelles."
#: doc/classes/EditorVCSInterface.xml
-#, fuzzy
msgid "Checks out a [code]branch_name[/code] in the VCS."
msgstr ""
-"Supprime un [code]name[/code] de chargement automatique à partir de la liste."
#: doc/classes/EditorVCSInterface.xml
msgid ""
@@ -30821,9 +30728,8 @@ msgid ""
msgstr ""
#: doc/classes/EditorVCSInterface.xml
-#, fuzzy
msgid "Creates a new branch named [code]branch_name[/code] in the VCS."
-msgstr "Crée une instance de [code]class[/code]."
+msgstr ""
#: doc/classes/EditorVCSInterface.xml
msgid ""
@@ -30854,9 +30760,8 @@ msgid ""
msgstr ""
#: doc/classes/EditorVCSInterface.xml
-#, fuzzy
msgid "Gets the current branch name defined in the VCS."
-msgstr "Définit le trame présentement visible de l'animation."
+msgstr ""
#: doc/classes/EditorVCSInterface.xml
msgid ""
@@ -30920,9 +30825,8 @@ msgid ""
msgstr ""
#: doc/classes/EditorVCSInterface.xml
-#, fuzzy
msgid "Remove a branch from the local VCS."
-msgstr "Supprime un nœud de la sélection."
+msgstr ""
#: doc/classes/EditorVCSInterface.xml
msgid "Remove a remote from the local VCS."
@@ -30944,9 +30848,8 @@ msgid ""
msgstr ""
#: doc/classes/EditorVCSInterface.xml
-#, fuzzy
msgid "Stages the file present at [code]file_path[/code] to the staged area."
-msgstr "Ajoute un [Shape2D] au propriétaire de la forme."
+msgstr ""
#: doc/classes/EditorVCSInterface.xml
msgid ""
@@ -31056,9 +30959,8 @@ msgid "A commit is encountered from the commit area."
msgstr ""
#: doc/classes/EditorVCSInterface.xml
-#, fuzzy
msgid "A file is encountered from the staged area."
-msgstr "Statut : Déconnecté du serveur."
+msgstr ""
#: doc/classes/EditorVCSInterface.xml
msgid "A file is encountered from the unstaged area."
@@ -31578,14 +31480,12 @@ msgid "The [Sky] resource's rotation expressed as a [Basis]."
msgstr "La rotation du [Sky] exprimée par un [Basis]."
#: doc/classes/Environment.xml
-#, fuzzy
msgid "The [Sky] resource's rotation expressed as Euler angles in radians."
-msgstr "La rotation de la texture en radians."
+msgstr ""
#: doc/classes/Environment.xml
-#, fuzzy
msgid "The [Sky] resource's rotation expressed as Euler angles in degrees."
-msgstr "La rotation de la texture en degrés."
+msgstr ""
#: doc/classes/Environment.xml
msgid "The amount of far blur for the depth-of-field effect."
@@ -31599,9 +31499,8 @@ msgstr ""
"rendu."
#: doc/classes/Environment.xml
-#, fuzzy
msgid "If [code]true[/code], enables the depth-of-field far blur effect."
-msgstr "Si [code]true[/code], active le drapeau spécifié."
+msgstr "Si [code]true[/code], active l'effet de flou de profondeur lointain."
#: doc/classes/Environment.xml
msgid ""
@@ -31921,11 +31820,10 @@ msgid ""
msgstr ""
#: doc/classes/Environment.xml
-#, fuzzy
msgid ""
"The secondary screen-space ambient occlusion intensity. See also [member "
"ssao_radius2]."
-msgstr "Le rayon d'occlusion ambiante de l'espace de l'écran primaire."
+msgstr ""
#: doc/classes/Environment.xml
msgid ""
@@ -33063,7 +32961,7 @@ msgstr ""
#: doc/classes/FlowContainer.xml
#, fuzzy
msgid "Base class for flow containers."
-msgstr "Classe de base pour les conteneurs de boîtes."
+msgstr "La classe de base pour les conteneurs de flux."
#: doc/classes/FlowContainer.xml
msgid ""
@@ -33074,7 +32972,6 @@ msgid ""
msgstr ""
#: doc/classes/FlowContainer.xml
-#, fuzzy
msgid "Returns the current line count."
msgstr "Retourne le numéro de la ligne actuelle."
@@ -33144,30 +33041,24 @@ msgid ""
msgstr ""
#: doc/classes/Font.xml
-#, fuzzy
msgid "Returns resource id of the cache texture containing the char."
-msgstr "Retourne l'identifiant OpenGL de l'image de cette texture."
+msgstr ""
#: doc/classes/Font.xml
-#, fuzzy
msgid "Returns size of the cache texture containing the char."
-msgstr "Retourne la position du contact sur le collisionneur."
+msgstr ""
#: doc/classes/Font.xml
-#, fuzzy
msgid "Returns char offset from the baseline."
-msgstr "Retourne le décalage de la texture de la tuile."
+msgstr ""
#: doc/classes/Font.xml
-#, fuzzy
msgid "Returns size of the char."
-msgstr "Renvoie le sinus du paramètre."
+msgstr "Retourne la taille du caractère."
#: doc/classes/Font.xml
-#, fuzzy
msgid "Returns rectangle in the cache texture containing the char."
msgstr ""
-"Retourne un rectangle englobant les tuiles utilisées (non vides) de la carte."
#: doc/classes/Font.xml
msgid "Returns the font descent (number of pixels below the baseline)."
@@ -33203,9 +33094,8 @@ msgid ""
msgstr ""
#: doc/classes/Font.xml
-#, fuzzy
msgid "Contour point is on the curve."
-msgstr "Supprime tous les points de la courbe."
+msgstr ""
#: doc/classes/Font.xml
msgid ""
@@ -34039,18 +33929,17 @@ msgstr ""
"fin."
#: doc/classes/Geometry.xml
-#, fuzzy
msgid ""
"Given an array of [Vector2]s representing tiles, builds an atlas. The "
"returned dictionary has two keys: [code]points[/code] is an array of "
"[Vector2] that specifies the positions of each tile, [code]size[/code] "
"contains the overall size of the whole atlas as [Vector2]."
msgstr ""
-"À partir d'un tableau de [Vector2] représentant des tuiles, construit un "
+"À partir d'un tableau de [Vector2] représentant des tuiles, ça construit un "
"atlas. Le dictionnaire retourné a deux clés : [code]points[/code] est un "
"tableau de [Vector2] qui précise les positions de chaque tuile, et "
-"[code]size[/code] contient la taille globale de l'atlas entier sous forme de "
-"[Vector2]."
+"[code]size[/code] contient la taille globale de l'atlas en entier sous forme "
+"d'un [Vector2]."
#: doc/classes/Geometry.xml
msgid ""
@@ -34095,19 +33984,20 @@ msgid ""
msgstr ""
"Gonfle ou dégonfle [code]polygon[/code] par la quantité [code]delta[/code] "
"unités (pixels) dans toutes les directions. Si [code]delta[/code] est "
-"positif, le polygone décale chaque sommet vers l'extérieur. Si [code]delta[/"
-"code] est négatif, décale chaque sommet vers l'intérieur. Retourne une liste "
-"des polygones parce que gonflage/dégonflage peut produire plusieurs "
-"polygones distinctes. Retourne un tableau vide si [code]delta[/code] est "
-"négatif et la valeur absolue de celui-ci dépasse approximativement les "
-"dimensions du rectangle minimal englobant du polygone.\n"
+"positif, le polygone décale chaque sommet vers l'extérieur. Si "
+"[code]delta[/code] est négatif, décale chaque sommet vers l'intérieur. "
+"Retourne une liste des polygones parce que gonflage/dégonflage peut produire "
+"plusieurs polygones distinctes. Retourne un tableau vide si "
+"[code]delta[/code] est négatif et la valeur absolue de celui-ci dépasse "
+"approximativement les dimensions du rectangle minimal englobant du polygone."
+"\n"
"Les sommets de chaque polygone sont arrondis suivant [code]join_type[/code], "
"voir [enum PolyJoinType].\n"
"L'opération peut fournir un polygone extérieur (la limite extérieure) et "
"plusieurs polygones à intérieur (représentant les trous) qui pourraient être "
-"distingués en appelant [méthode is_polygon_clockwise].\n"
-"[b]Note :[/b] Pour transformer les sommets en polygone, utilisez la méthode "
-"[méthode Transform2D.xform]:\n"
+"distingués en appelant [method is_polygon_clockwise].\n"
+"[b]Note :[/b] Pour transformer les sommets en polygone, utilisez la méthode ["
+"method Transform2D.xform]:\n"
"[codeblock]\n"
"var polygon = PoolVector2Array([Vector2(0, 0), Vector2(100, 0), Vector2(100, "
"100), Vector2(0, 100)])\n"
@@ -34132,15 +34022,16 @@ msgid ""
"(hole) produced which could be distinguished by calling [method "
"is_polygon_clockwise]."
msgstr ""
-"par la quantité [code]delta[/code] unités (pixels) dans toutes les "
-"directions. Si [code]delta[/code] est positif, le polygone décale chaque "
-"sommet vers l'extérieur. Retourne une liste des polygones parce que gonflage/"
-"dégonflage peut produire plusieurs polygones distinctes. Si [code]delta[/"
-"code] est négatif, retourne un tableau vide.\n"
+"Gonfle ou dégonfle [code]polyline[/code] par la quantité [code]delta[/code] "
+"d'unités (pixels) dans toutes les directions. Si [code]delta[/code] est "
+"positif, le polygone décale chaque sommet vers l'extérieur. Retourne une "
+"liste des polygones parce que gonflage/dégonflage peut produire plusieurs "
+"polygones distinctes. Si [code]delta[/code] est négatif, retourne un tableau "
+"vide.\n"
"Les sommets de chaque polygone sont arrondis suivant [code]join_type[/code], "
"voir [enum PolyJoinType].\n"
-"Chaque point d'extrémité du polygone sera arrondi suivant [code]end_type[/"
-"code], voir [enum PolyEndType].\n"
+"Chaque point d'extrémité du polygone sera arrondi suivant "
+"[code]end_type[/code], voir [enum PolyEndType].\n"
"L'opération peut fournir un polygone extérieur (la limite extérieur) et "
"plusieurs polygones à intérieur (représentant les trous) qui pourraient être "
"distingués en appelant [method is_polygon_clockwise]."
@@ -34383,39 +34274,35 @@ msgid ""
msgstr ""
#: doc/classes/GeometryInstance.xml
-#, fuzzy
msgid ""
"The GeometryInstance's max LOD distance.\n"
"[b]Note:[/b] This property currently has no effect."
msgstr ""
-"La distance min LOD de GeometryInstance3D.\n"
+"La distance maximale pour ce LOD de la GeometryInstance.\n"
"[b]Remarque :[/b] Cette propriété n’a actuellement aucun effet."
#: doc/classes/GeometryInstance.xml
-#, fuzzy
msgid ""
"The GeometryInstance's max LOD margin.\n"
"[b]Note:[/b] This property currently has no effect."
msgstr ""
-"La distance min LOD de GeometryInstance3D.\n"
+"La marge maximale pour ce LOD de la GeometryInstance.\n"
"[b]Remarque :[/b] Cette propriété n’a actuellement aucun effet."
#: doc/classes/GeometryInstance.xml
-#, fuzzy
msgid ""
"The GeometryInstance's min LOD distance.\n"
"[b]Note:[/b] This property currently has no effect."
msgstr ""
-"La distance min LOD de GeometryInstance3D.\n"
+"La distance minimale pour ce LOD de la GeometryInstance.\n"
"[b]Remarque :[/b] Cette propriété n’a actuellement aucun effet."
#: doc/classes/GeometryInstance.xml
-#, fuzzy
msgid ""
"The GeometryInstance's min LOD margin.\n"
"[b]Note:[/b] This property currently has no effect."
msgstr ""
-"La distance min LOD de GeometryInstance3D.\n"
+"La marge minimale pour ce LOD de la GeometryInstance.\n"
"[b]Remarque :[/b] Cette propriété n’a actuellement aucun effet."
#: doc/classes/GeometryInstance.xml
@@ -34952,13 +34839,10 @@ msgstr ""
"[code]false[/code] sinon."
#: modules/mono/doc_classes/GodotSharp.xml
-#, fuzzy
msgid ""
"Returns [code]true[/code] if the Mono runtime is shutting down, [code]false[/"
"code] otherwise."
msgstr ""
-"Renvoie [code]true[/code] (vrai) si [code]s[/code] vaut zéro ou quasiment "
-"zéro."
#: modules/mono/doc_classes/GodotSharp.xml
msgid ""
@@ -35640,14 +35524,12 @@ msgid "Returns the type of the output connection [code]idx[/code]."
msgstr "Retourne le type de connexion pour la sortie [code]idx[/code]."
#: doc/classes/GraphNode.xml
-#, fuzzy
msgid "Returns the left (input) [Color] of the slot [code]idx[/code]."
-msgstr "Retourne le type du nœud à [code]idx[/code]."
+msgstr ""
#: doc/classes/GraphNode.xml
-#, fuzzy
msgid "Returns the right (output) [Color] of the slot [code]idx[/code]."
-msgstr "Retourne le type du nœud à [code]idx[/code]."
+msgstr ""
#: doc/classes/GraphNode.xml
msgid "Returns the left (input) type of the slot [code]idx[/code]."
@@ -35690,17 +35572,17 @@ msgid ""
"methods. You must enable at least one side of the slot to do so."
msgstr ""
"Définit les propriétés de l'emplacement avec identifiant [code]idx[/code].\n"
-"Si [code]enable_left[code]/[code]right[/code], un port apparaîtra et "
+"Si [code]enable_left[/code]/[code]right[/code], un port apparaîtra et "
"l'emplacement pourra être connectée de ce côté.\n"
-"[code]type_left[code]/[code]right[/code] est un type arbitraire du port. "
+"[code]type_left[/code]/[code]right[/code] est un type arbitraire du port. "
"Seuls les ports avec le même type peuvent être connectés.\n"
-"[code]color_left[code]/[code]right[/code] est la teinte de l'icône du port "
+"[code]color_left[/code]/[code]right[/code] est la teinte de l'icône du port "
"de ce côté.\n"
-"[code]custom_left[code]/[code]right[/code] est une texture personnalisée "
+"[code]custom_left[/code]/[code]right[/code] est une texture personnalisée "
"pour le port de ce côté.\n"
"[b]Note :[/b] Cette méthode ne définit que les propriétés de l'emplacement. "
-"Pour créer l'emplacement, ajoutez un enfant dérivé de [Control] au "
-"GraphNode.\n"
+"Pour créer l'emplacement, ajoutez un enfant dérivé de [Control] au GraphNode."
+"\n"
"Les propriétés individuelles peuvent être définies en utilisant l'une des "
"méthodes [code]set_slot_*[/code]. Vous devez activer au moins un côté de "
"l'emplacement pour le faire."
@@ -36069,13 +35951,10 @@ msgstr ""
"dans la grille."
#: modules/gridmap/doc_classes/GridMap.xml
-#, fuzzy
msgid ""
"Returns an array of all cells with the given item index specified in "
"[code]item[/code]."
msgstr ""
-"Renvoie la texture de l’atlas de police de caractères à l’index [code]idx[/"
-"code]."
#: modules/gridmap/doc_classes/GridMap.xml
msgid ""
@@ -36112,13 +35991,10 @@ msgid ""
msgstr ""
#: modules/gridmap/doc_classes/GridMap.xml
-#, fuzzy
msgid ""
"If [code]true[/code], this GridMap uses cell navmesh resources to create "
"navigation regions."
msgstr ""
-"Si [code]true[/code], met à jour les animations en réponse aux notifications "
-"liées au processus."
#: modules/gridmap/doc_classes/GridMap.xml
msgid "If [code]true[/code], grid items are centered on the X axis."
@@ -36330,9 +36206,8 @@ msgid "The horizontal space between the [HBoxContainer]'s elements."
msgstr "L'espace horizontal entre les éléments du [HBoxContainer]."
#: doc/classes/HeightMapShape.xml
-#, fuzzy
msgid "Height map shape for 3D physics."
-msgstr "Forme de polygone convexe pour la physique 3D."
+msgstr "La forme de carte de hauteurs pour la physique 3D."
#: doc/classes/HeightMapShape.xml
msgid ""
@@ -36605,14 +36480,13 @@ msgid "Displayed when the decrement button is being pressed."
msgstr "Affiché quand le bouton de reduction est appuyé."
#: doc/classes/HScrollBar.xml
-#, fuzzy
msgid ""
"Icon used as a button to scroll the [ScrollBar] right. Supports custom step "
"using the [member ScrollBar.custom_step] property."
msgstr ""
-"Icône utilisée comme bouton pour faire défiler la [ScrollBar] correctement. "
-"Supporte l'étape personnalisée en utilisant la propriété [member ScrollBar."
-"custom_step]."
+"L'icône utilisée comme bouton pour faire défiler la [ScrollBar] vers la "
+"droite. Supporte une étape personnalisée en utilisant la propriété [member "
+"ScrollBar.custom_step]."
#: doc/classes/HScrollBar.xml doc/classes/VScrollBar.xml
msgid "Displayed when the mouse cursor hovers over the increment button."
@@ -36631,7 +36505,7 @@ msgstr ""
#: doc/classes/HScrollBar.xml doc/classes/VScrollBar.xml
#, fuzzy
msgid "Used when the mouse hovers over the grabber."
-msgstr "Utilisé lorsque la souris survole le grappin."
+msgstr "Utilisé lorsque la souris survole le glisseur."
#: doc/classes/HScrollBar.xml doc/classes/VScrollBar.xml
msgid "Used when the grabber is being dragged."
@@ -37722,7 +37596,6 @@ msgid "A node with the ability to send HTTP(S) requests."
msgstr "Un nœud qui permet d'envoyer des requêtes HTTP(S)."
#: doc/classes/HTTPRequest.xml
-#, fuzzy
msgid ""
"A node with the ability to send HTTP requests. Uses [HTTPClient] "
"internally.\n"
@@ -37802,28 +37675,28 @@ msgstr ""
"des fichiers ou du contenu web via HTTP.\n"
"[b]Avertissement :[/b] Voir les notes et avertissements du [HTTPClient] pour "
"les limites, notamment concernant la sécurité SSL.\n"
-"[b]Exemple pour contacter une API REST et afficher les champs retournés :[/"
-"b]\n"
+"[b]Exemple pour contacter une API REST et afficher les champs retournés :[/b]"
+"\n"
"[codeblock]\n"
"func _ready():\n"
-" # Créer un nœud de requête HTTP et le connecter au signal de "
-"complétion.\n"
+" # Créer un nœud de requête HTTP et le connecter au signal de complétion."
+"\n"
" var http_request = HTTPRequest.new()\n"
" add_child(http_request)\n"
" http_request.connect(\"request_completed\", self, "
"\"_http_request_completed\")\n"
"\n"
-" # Lancer une requête GET. L'URL en-dessous retourne un JSON au moment de "
+" # Lancer une requête GET. L'URL en dessous retourne un JSON au moment de "
"l'écriture de ce tutoriel.\n"
" var error = http_request.request(\"https://httpbin.org/get\")\n"
" if error != OK:\n"
" push_error(\"Une erreur est survenue dans la requête HTTP.\")\n"
"\n"
-" # Lancer une requête POST. L'URL en-dessous retourne un JSON au moment "
+" # Lancer une requête POST. L'URL en dessous retourne un JSON au moment "
"de l'écriture de ce tutoriel.\n"
" # Note : Don't make simultaneous requests using a single HTTPRequest "
"node.\n"
-" # Le code en-dessous est uniquement donné comme exemple.\n"
+" # Le code en dessous est uniquement donné comme exemple.\n"
" var body = {\"nom\": \"Godette\"}\n"
" error = http_request.request(\"https://httpbin.org/post\", [], true, "
"HTTPClient.METHOD_POST, body)\n"
@@ -37843,14 +37716,14 @@ msgstr ""
"HTTPRequest:[/b]\n"
"[codeblock]\n"
"func _ready():\n"
-" # Créer un nœud de requête HTTP et le connecter au signal de "
-"complétion.\n"
+" # Créer un nœud de requête HTTP et le connecter au signal de complétion."
+"\n"
" var http_request = HTTPRequest.new()\n"
" add_child(http_request)\n"
" http_request.connect(\"request_completed\", self, "
"\"_http_request_completed\")\n"
"\n"
-" # Lancer une requête HTTP. L'URL en-dessous retourne une image PNG au "
+" # Lancer une requête HTTP. L'URL en dessous retourne une image PNG au "
"moment de l'écriture de ce tutoriel.\n"
" var error = http_request.request(\"https://via.placeholder.com/512\")\n"
" if error != OK:\n"
@@ -37957,11 +37830,12 @@ msgid ""
msgstr ""
#: doc/classes/HTTPRequest.xml
-#, fuzzy
msgid ""
"Maximum number of allowed redirects. This is used to prevent endless "
"redirect loops."
-msgstr "Nombre maximal de redirections autorisées."
+msgstr ""
+"Le nombre maximal de redirections autorisées. C'est utilisé pour éviter les "
+"redirections infinies."
#: doc/classes/HTTPRequest.xml
msgid ""
@@ -38175,9 +38049,8 @@ msgid "Fills [code]rect[/code] with [code]color[/code]."
msgstr "Remplis le [code]rect[/code] avec la [code]color[/code]."
#: doc/classes/Image.xml
-#, fuzzy
msgid "Blends low-alpha pixels with nearby pixels."
-msgstr "Mélange les pixels à faible alpha avec les pixels à proximité."
+msgstr "Mélange les pixels à faible opacité avec ceux proches."
#: doc/classes/Image.xml
msgid "Flips the image horizontally."
@@ -38959,9 +38832,8 @@ msgid ""
msgstr ""
#: doc/classes/ImageTexture.xml
-#, fuzzy
msgid "Returns the format of the texture, one of [enum Image.Format]."
-msgstr "Renvoie l'inverse de la racine carrée du paramètre."
+msgstr ""
#: doc/classes/ImageTexture.xml
msgid ""
@@ -39206,11 +39078,10 @@ msgid ""
msgstr ""
#: doc/classes/Input.xml
-#, fuzzy
msgid ""
"Returns the current value of the joypad axis at given index (see [enum "
"JoystickList])."
-msgstr "Retourne l'état actuel de ce canal, voir [enum ChannelState]."
+msgstr ""
#: doc/classes/Input.xml
msgid "Returns the index of the provided axis name."
@@ -39510,10 +39381,9 @@ msgid ""
msgstr ""
#: doc/classes/Input.xml
-#, fuzzy
msgid "Controls the mouse mode. See [enum MouseMode] for more information."
msgstr ""
-"Définit le mode de la souris. Voir les constantes pour plus d'informations."
+"Définit le mode de la souris. Voir [enum MouseMode] pour plus d'informations."
#: doc/classes/Input.xml
msgid ""
@@ -39830,9 +39700,8 @@ msgid ""
msgstr ""
#: doc/classes/InputEventAction.xml
-#, fuzzy
msgid "InputEvent: Actions"
-msgstr "Type d’évènement d’entrée pour les actions."
+msgstr "Évènements d’entrée : les actions"
#: doc/classes/InputEventAction.xml
msgid "The action's name. Actions are accessed via this [String]."
@@ -40011,9 +39880,8 @@ msgid "Wikipedia General MIDI Instrument List"
msgstr ""
#: doc/classes/InputEventMIDI.xml
-#, fuzzy
msgid "Wikipedia Piano Key Frequencies List"
-msgstr "https://en.wikipedia.org/wiki/Piano_key_frequencies#List"
+msgstr "La liste des fréquences des touches de piano sur Wikipédia"
#: doc/classes/InputEventMIDI.xml
msgid ""
@@ -40187,12 +40055,12 @@ msgid "Mouse and input coordinates"
msgstr "Les coordonnées de la souris"
#: doc/classes/InputEventMouseMotion.xml
-#, fuzzy
msgid ""
"Returns [code]true[/code] when using the eraser end of a stylus pen.\n"
"[b]Note:[/b] This property is implemented on Linux, macOS and Windows."
msgstr ""
-"Retourne le nombre de disposition de clavier.\n"
+"Retourne [code]true[/code] lors de l'utilisation de la gomme (l'autre "
+"extrémité) d'un stylet.\n"
"[b]Note :[/b] Cette méthode est implémentée sous Linux, macOS et Windows."
#: doc/classes/InputEventMouseMotion.xml
@@ -40554,11 +40422,11 @@ msgstr ""
"automatiquement."
#: doc/classes/InterpolatedCamera.xml
-#, fuzzy
msgid ""
"The camera's process callback. See [enum InterpolatedCameraProcessMode]."
msgstr ""
-"La méthode de mise à jour de la camera. Voir [enum Camera2DProcessMode]."
+"La méthode de mise à jour de la camera. Voir [enum "
+"InterpolatedCameraProcessMode]."
#: doc/classes/InterpolatedCamera.xml
msgid ""
@@ -41824,14 +41692,14 @@ msgid ""
msgstr ""
#: doc/classes/KinematicBody.xml doc/classes/KinematicBody2D.xml
-#, fuzzy
msgid ""
"Returns the number of times the body collided and changed direction during "
"the last call to [method move_and_slide] or [method "
"move_and_slide_with_snap]."
msgstr ""
-"Renvoie le nombre de fois où le corps est entré en collision et a changé de "
-"direction au cours du dernier appel vers [method move_and_slide]."
+"Retourne le nombre de fois où le corps est entré en collision et a changé de "
+"direction au cours du dernier appel vers [method move_and_slide] ou [method "
+"move_and_slide_with_snap]."
#: doc/classes/KinematicBody.xml doc/classes/KinematicBody2D.xml
msgid ""
@@ -42433,9 +42301,8 @@ msgid "Background [StyleBox] for the [Label]."
msgstr "Le [StyleBox] d'arrière-plan pour le [Label]."
#: doc/classes/Label3D.xml
-#, fuzzy
msgid "Displays plain text in a 3D world."
-msgstr "Nœud de sprite en 2D dans un monde en 3D."
+msgstr "Affiche du texte dans un monde en 3D."
#: doc/classes/Label3D.xml
msgid ""
@@ -42450,62 +42317,50 @@ msgid ""
msgstr ""
#: doc/classes/Label3D.xml
-#, fuzzy
msgid ""
"If [code]true[/code], the specified flag will be enabled. See [enum Label3D."
"DrawFlags] for a list of flags."
msgstr ""
-"Si [code]true[/code], active l'option donné. Voir [enum Flags] pour ces "
-"options."
+"Si [code]true[/code], active le drapeau spécifié. Voir [enum Label3D."
+"DrawFlags] pour la liste des drapeaux."
#: doc/classes/Label3D.xml
-#, fuzzy
msgid ""
"The alpha cutting mode to use for the sprite. See [enum AlphaCutMode] for "
"possible values."
msgstr ""
-"Le mode d'orientation de la TileMap. Voir [enum Mode] pour les valeurs "
-"possibles."
#: doc/classes/Label3D.xml doc/classes/SpatialMaterial.xml
msgid "Threshold at which the alpha scissor will discard values."
msgstr "Le seuil à partir duquel le ciseau alpha ignorera les valeurs."
#: doc/classes/Label3D.xml
-#, fuzzy
msgid "If [code]true[/code], wraps the text to the [member width]."
-msgstr "Si [code]true[/code], cache la ligne à l'index spécifié."
+msgstr ""
#: doc/classes/Label3D.xml
-#, fuzzy
msgid ""
"The billboard mode to use for the label. See [enum SpatialMaterial."
"BillboardMode] for possible values."
msgstr ""
-"La direction de remplissage. Voir [enum FillMode] pour les valeurs possibles."
#: doc/classes/Label3D.xml
-#, fuzzy
msgid ""
"If [code]true[/code], text can be seen from the back as well, if "
"[code]false[/code], it is invisible when looking at it from behind."
msgstr ""
-"Si [code]true[/code], la ligne sera verticale. Si [code]false[/code], elle "
-"sera horizontale."
#: doc/classes/Label3D.xml doc/classes/SpriteBase3D.xml
-#, fuzzy
msgid ""
"If [code]true[/code], the label is rendered at the same size regardless of "
"distance."
msgstr ""
-"Si [code]true[/code], l'objet est affiché à la même taille indépendamment de "
-"sa distance à la caméra."
+"Si [code]true[/code], le label est affiché à la même taille indépendamment "
+"de sa distance à la caméra."
#: doc/classes/Label3D.xml
-#, fuzzy
msgid "[Font] used for the [Label3D]'s text."
-msgstr "[Font] utilisée pour le texte du [Label]."
+msgstr "La [Font] utilisée pour le texte du [Label3D]."
#: doc/classes/Label3D.xml
msgid ""
@@ -42516,14 +42371,13 @@ msgstr ""
"droite. Réglez-le à l'une des constantes de [enum Align]."
#: doc/classes/Label3D.xml
-#, fuzzy
msgid "Vertical space between lines in multiline [Label3D]."
-msgstr "L'espace vertical entre les lignes en multiligne [Label]."
+msgstr ""
+"L'espacement vertical entre les lignes en mode multi-ligne d'un [Label3D]."
#: doc/classes/Label3D.xml
-#, fuzzy
msgid "Text [Color] of the [Label3D]."
-msgstr "La [Color] par défaut du texte du [Label]."
+msgstr "La [Color] du texte du [Label3D]."
#: doc/classes/Label3D.xml doc/classes/SpatialMaterial.xml
#: doc/classes/SpriteBase3D.xml
@@ -42535,17 +42389,14 @@ msgstr ""
"sera dessiné suivant son ordre de rendu et non suivant sa distance."
#: doc/classes/Label3D.xml
-#, fuzzy
msgid "The text drawing offset (in pixels)."
-msgstr "Le décalage du dessin de la texture."
+msgstr ""
#: doc/classes/Label3D.xml
-#, fuzzy
msgid "The tint of [Font]'s outline."
-msgstr "La hauteur du cylindre."
+msgstr "Le teinte du contour de la [Font]."
#: doc/classes/Label3D.xml
-#, fuzzy
msgid ""
"Sets the render priority for the text outline. Higher priority objects will "
"be sorted in front of lower priority objects.\n"
@@ -42556,23 +42407,21 @@ msgid ""
"This is because opaque objects are not sorted, while transparent objects are "
"sorted from back to front (subject to priority)."
msgstr ""
-"Définit la priorité de rendu pour la bordure du texte. Des objets plus "
-"prioritaires seront affichés par-dessus des objets moins inférieurs.\n"
-"[b]Note: [/b] Cela ne s'applique que si [member alpha_cut] est défini à "
-"[constant ALPHA_CUT_DISABLED] (c'est la valeur par défaut).\n"
+"Définit la priorité de rendu pour la bordure du texte. Les objets les plus "
+"prioritaires seront affichés par-dessus des objets les moins prioritaires.\n"
+"[b]Note :[/b] Cela ne s'applique que si [member alpha_cut] est défini à ["
+"constant ALPHA_CUT_DISABLED] (c'est la valeur par défaut).\n"
"[b]Note :[/b] Cela ne s'applique qu'au tri des objets transparents. Cela "
"n'affectera pas la façon dont les objets transparents sont triés par rapport "
"aux objets opaques. C'est parce que les objets opaques ne sont pas triés, "
-"alors que les objets transparents sont triés de l'arrière à l'avant (et "
+"alors que les objets transparents sont triés de l'arrière vers l'avant (et "
"suivant leur priorité)."
#: doc/classes/Label3D.xml
-#, fuzzy
msgid "The size of one pixel's width on the label to scale it in 3D."
-msgstr "La taille d'un des pixels de la sprite pour définir sa taille en 3D."
+msgstr "La taille d'un des pixels du label pour définir sa taille en 3D."
#: doc/classes/Label3D.xml
-#, fuzzy
msgid ""
"Sets the render priority for the text. Higher priority objects will be "
"sorted in front of lower priority objects.\n"
@@ -42583,22 +42432,21 @@ msgid ""
"This is because opaque objects are not sorted, while transparent objects are "
"sorted from back to front (subject to priority)."
msgstr ""
-"Définit la priorité de rendu pour le texte. Des objets plus prioritaires "
-"seront affichés par-dessus des objets moins inférieurs.\n"
-"[b]Note: [/b] Cela ne s'applique que si [member alpha_cut] est défini à "
-"[constant ALPHA_CUT_DISABLED] (c'est la valeur par défaut).\n"
+"Définit la priorité de rendu pour le texte. Les objets les plus prioritaires "
+"seront affichés par-dessus des objets les moins prioritaires.\n"
+"[b]Note :[/b] Cela ne s'applique que si [member alpha_cut] est défini à ["
+"constant ALPHA_CUT_DISABLED] (c'est la valeur par défaut).\n"
"[b]Note :[/b] Cela ne s'applique qu'au tri des objets transparents. Cela "
"n'affectera pas la façon dont les objets transparents sont triés par rapport "
"aux objets opaques. C'est parce que les objets opaques ne sont pas triés, "
-"alors que les objets transparents sont triés de l'arrière à l'avant (et "
+"alors que les objets transparents sont triés de l'arrière vers l'avant (et "
"suivant leur priorité)."
#: doc/classes/Label3D.xml
-#, fuzzy
msgid ""
"If [code]true[/code], the [Light] in the [Environment] has effects on the "
"label."
-msgstr "Si [code]true[/code], ce [HTTPClient] a une réponse disponible."
+msgstr ""
#: doc/classes/Label3D.xml
msgid ""
@@ -42615,18 +42463,16 @@ msgstr ""
"l'alignement de remplissage."
#: doc/classes/Label3D.xml
-#, fuzzy
msgid "If set, lights in the environment affect the label."
-msgstr "Si [code]true[/code], ce [HTTPClient] a une réponse disponible."
+msgstr ""
#: doc/classes/Label3D.xml
-#, fuzzy
msgid ""
"If set, text can be seen from the back as well. If not, the text is "
"invisible when looking at it from behind."
msgstr ""
-"Si défini, le texte sera aussi visible de derrière. Sinon, le texture n'est "
-"invisible que de face."
+"Si défini, le texte sera aussi visible de derrière. Sinon, la texture ne "
+"sera visible que de face."
#: doc/classes/Label3D.xml doc/classes/SpatialMaterial.xml
#: doc/classes/SpriteBase3D.xml
@@ -42738,9 +42584,8 @@ msgid "Returns the offset of the piece with the index [code]idx[/code]."
msgstr "Retourne le décalage de la pièce à l'index [code]idx[/code]."
#: doc/classes/LargeTexture.xml
-#, fuzzy
msgid "Returns the [Texture] of the piece with the index [code]idx[/code]."
-msgstr "Retourne la position du point à l'index [code]point[/code]."
+msgstr ""
#: doc/classes/LargeTexture.xml
msgid ""
@@ -42751,12 +42596,10 @@ msgstr ""
"code]."
#: doc/classes/LargeTexture.xml
-#, fuzzy
msgid ""
"Sets the [Texture] of the piece with index [code]idx[/code] to "
"[code]texture[/code]."
msgstr ""
-"Déplace l’élément de l’index [code]from_idx[/code] à [code]to_idx[/code]."
#: doc/classes/LargeTexture.xml
msgid "Sets the size of this [LargeTexture]."
@@ -42908,7 +42751,7 @@ msgstr ""
"utile lorsque vous avez un maillage plat qui a une lumière derrière elle. Si "
"vous avez besoin de lancer une ombre sur les deux côtés du maillage, "
"définissez le maillage pour utiliser les deux faces avec [constant "
-"GeometryInstance.SHADOW_CASTING_SETTING_DOUBLE_SIDED]"
+"GeometryInstance.SHADOW_CASTING_SETTING_DOUBLE_SIDED]."
#: doc/classes/Light.xml
msgid "Constant for accessing [member light_energy]."
@@ -43109,7 +42952,6 @@ msgstr ""
"les Light2D."
#: doc/classes/Light2D.xml
-#, fuzzy
msgid "Shadow buffer size."
msgstr "Taille du tampon d'ombre."
@@ -43275,7 +43117,7 @@ msgstr ""
"polygone à la fois. Pour augmenter cette limite, ouvrez les paramètres du "
"projet et augmentez [member ProjectSettings.rendering/limits/buffers/"
"canvas_polygon_buffer_size_kb] et [member ProjectSettings.rendering/limits/"
-"buffers/canvas_polygon_index_buffer_size_kb]"
+"buffers/canvas_polygon_index_buffer_size_kb]."
#: doc/classes/Line2D.xml
msgid ""
@@ -43335,6 +43177,19 @@ msgid ""
"perform antialiasing. 2D batching is also still supported with those "
"antialiased lines."
msgstr ""
+"Si [code]true[/code], la bordure de la ligne essayera d'activer "
+"anticrénelage en dessinant de fines lignes en OpenGL sur les bords de la "
+"ligne.\n"
+"[b]Note :[/b] Line2D n'est pas accéléré par lots si [code]antialiased[/code] "
+"est [code]true[/code].\n"
+"[b]Note :[/b] En raison de son fonctionnement, l'anticrénelage calculé en "
+"interne n'est pas correct pour les lignes semi-transparents voire peut ne "
+"pas fonctionner sur certaines plateformes. Vous pouvez corriger ce problème "
+"en installant le greffon [url=https://github.com/godot-extended-libraries/"
+"godot-antialiased-line2d]Antialiased Line2D[/url] puis créez un nœud "
+"\"AntialiasedPolygon2D\". Ce nœud utilise des texture avec des mipmaps "
+"personnalisés pour afficher l'anticrénelage. L'accélération par lot est "
+"toujours supporté même avec les lignes avec anticrénelage."
#: doc/classes/Line2D.xml
msgid ""
@@ -43361,6 +43216,8 @@ msgid ""
"The gradient is drawn through the whole line from start to finish. The "
"default color will not be used if a gradient is set."
msgstr ""
+"Le dégradé est dessiné par toute la ligne du début à la fin. La couleur par "
+"défaut ne sera pas utilisée si un dégradé est défini."
#: doc/classes/Line2D.xml
msgid "The style for the points between the start and the end."
@@ -43371,6 +43228,9 @@ msgid ""
"The points that form the lines. The line is drawn between every point set in "
"this array. Points are interpreted as local vectors."
msgstr ""
+"Les points qui forment les lignes. La ligne est tracée entre chaque point "
+"défini dans ce tableau. Les points sont interprétés comme des vecteurs "
+"locaux."
#: doc/classes/Line2D.xml
msgid ""
@@ -43381,24 +43241,37 @@ msgid ""
"width]. For thin lines, this value should be reduced to a number between "
"[code]2[/code] and [code]4[/code] to improve performance."
msgstr ""
+"Le lissage des coins et des bouts. Les valeurs plus élevées affichent des "
+"coins plus lisses, mais demandent plus de ressources pour le rendu. Ceci "
+"n'est utilisé que si un coin ou un bout est défini comme arrondi.\n"
+"[b]Note :[/b] La valeur par défaut est réglée pour les lignes avec la "
+"largeur [member width] par défaut. Pour les lignes fines, cette valeur "
+"devrait être réduite à entre [code]2[/code] et [code]4[/code] pour améliorer "
+"les performances."
#: doc/classes/Line2D.xml
msgid ""
"The direction difference in radians between vector points. This value is "
"only used if [member joint_mode] is set to [constant LINE_JOINT_SHARP]."
msgstr ""
+"La différence de direction entre les points vectoriels. Cette valeur n'est "
+"utilisée que si [member joint_mode] est [constant LINE_JOINT_SHARP]."
#: doc/classes/Line2D.xml
msgid ""
"The texture used for the line's texture. Uses [code]texture_mode[/code] for "
"drawing style."
msgstr ""
+"La texture utilisée pour la texture de la ligne. Utilise "
+"[code]texture_mode[/code] pour le style de dessin."
#: doc/classes/Line2D.xml
msgid ""
"The style to render the [code]texture[/code] on the line. Use [enum "
"LineTextureMode] constants."
msgstr ""
+"Le style de rendu de la [code]texture[/code] sur la ligne. Utilisez une des "
+"constantes [enum LineTextureMode]."
#: doc/classes/Line2D.xml
msgid "The line's width."
@@ -43409,12 +43282,16 @@ msgid ""
"The line's width varies with the curve. The original width is simply "
"multiply by the value of the Curve."
msgstr ""
+"La largeur de la ligne dépend selon la courbe. La largeur originale est "
+"simplement multipliée par la valeur de la Curve."
#: doc/classes/Line2D.xml
msgid ""
"The line's joints will be pointy. If [code]sharp_limit[/code] is greater "
"than the rotation of a joint, it becomes a bevel joint instead."
msgstr ""
+"Les coins de la ligne sont pointus. Si [code]sharp_limit[/code] est plus "
+"grand que l'angle d'un coin, ça devient un biseau."
#: doc/classes/Line2D.xml
msgid "The line's joints will be bevelled/chamfered."
@@ -43422,7 +43299,7 @@ msgstr ""
#: doc/classes/Line2D.xml
msgid "The line's joints will be rounded."
-msgstr ""
+msgstr "Les coins de la ligne seront arrondis."
#: doc/classes/Line2D.xml
msgid "Don't draw a line cap."
@@ -43440,6 +43317,7 @@ msgstr "Dessine le bout de la ligne avec un arrondi."
msgid ""
"Takes the left pixels of the texture and renders it over the whole line."
msgstr ""
+"Utilise les pixels de gauche de la texture pour le rendu de toute la ligne."
#: doc/classes/Line2D.xml
msgid ""
@@ -43452,10 +43330,12 @@ msgid ""
"Stretches the texture across the line. Import the texture with [b]Repeat[/b] "
"disabled for best results."
msgstr ""
+"Étire la texture à travers la ligne. Importez la texture avec la "
+"[b]répétition[/b] désactivée pour de meilleurs résultats."
#: doc/classes/LineEdit.xml
msgid "Control that provides single-line string editing."
-msgstr ""
+msgstr "Le Control qui fournit l'édition d'un texte d'une seule ligne."
#: doc/classes/LineEdit.xml
msgid ""
@@ -43543,6 +43423,9 @@ msgid ""
"[code]from_column[/code] to [code]to_column[/code]. Both parameters should "
"be within the text's length."
msgstr ""
+"Supprime une section du [member text] allant de la position "
+"[code]from_column[/code] à [code]to_column[/code]. Les deux paramètres "
+"doivent être de la longueur du texte."
#: doc/classes/LineEdit.xml doc/classes/RichTextLabel.xml
msgid "Clears the current selection."
@@ -43556,12 +43439,19 @@ msgid ""
"may cause a crash. If you wish to hide it or any of its children, use their "
"[member CanvasItem.visible] property."
msgstr ""
+"Retourne le [PopupMenu] de ce [LineEdit]. Par défaut, ce menu s'affiche "
+"lorsque le clic-droit sur le [LineEdit].\n"
+"[b]Avertissement :[/b] Il s'agit d'un nœud interne requis, le retirer et le "
+"supprimer peut causer un plantage. Si vous voulez le cacher, lui ou un de "
+"ses enfants, utilisez la propriété [member CanvasItem.visible]."
#: doc/classes/LineEdit.xml
msgid ""
"Returns the scroll offset due to [member caret_position], as a number of "
"characters."
msgstr ""
+"Retourne le décalage du défilement suivant [member caret_position], en tant "
+"que nombre de caractères."
#: doc/classes/LineEdit.xml doc/classes/TextEdit.xml
msgid "Returns the selection begin column."
@@ -43572,9 +43462,8 @@ msgid "Returns the selection end column."
msgstr "Retourne la colonne de fin de sélection."
#: doc/classes/LineEdit.xml
-#, fuzzy
msgid "Returns [code]true[/code] if the user has selected text."
-msgstr "Retourne [code]true[/code] si le minuteur est arrêté."
+msgstr "Retourne [code]true[/code] si l'utilisateur a sélectionné du texte."
#: doc/classes/LineEdit.xml
msgid "Executes a given action as defined in the [enum MenuItems] enum."
@@ -43642,13 +43531,12 @@ msgstr "Si [code]true[/code], le menu contextuel apparaitra au clic-droit."
#: doc/classes/LineEdit.xml doc/classes/RichTextLabel.xml
#: doc/classes/TextEdit.xml
-#, fuzzy
msgid ""
"If [code]true[/code], the selected text will be deselected when focus is "
"lost."
msgstr ""
-"Si [code]true[/code], la cellule actuellement sélectionnée peut être "
-"sélectionnée à nouveau."
+"Si [code]true[/code], le texte actuellement sélectionné sera désélectionné "
+"quand le focus sera perdu."
#: doc/classes/LineEdit.xml
msgid ""
@@ -44366,35 +44254,58 @@ msgid ""
"add_constant_override(\"margin_right\", margin_value)\n"
"[/codeblock]"
msgstr ""
+"Ajoute une marge supérieure, gauche, inférieure et droite à tous les nœuds "
+"[Control] qui sont des enfants directs du conteneur. Pour contrôler la marge "
+"du [MarginContainer], utilisez les propriétés [code]margin_*[/code] du "
+"thèmes listées ci-dessous.\n"
+"[b]Note :[/b] Soyez prudent, les valeurs des marges de [Control] sont "
+"différentes des valeurs de marge constante. Si vous souhaitez modifier les "
+"valeurs de marge personnalisées du [MarginContainer] par code, vous devez "
+"utiliser les exemples suivants :\n"
+"[codeblock]\n"
+"# Cet exemple suppose que ce script hérite de MarginContainer.\n"
+"var margin_value = 100\n"
+"add_constant_override(\"margin_top\", margin_value)\n"
+"add_constant_override(\"margin_left\", margin_value)\n"
+"add_constant_override(\"margin_bottom\", margin_value)\n"
+"add_constant_override(\"margin_right\", margin_value)\n"
+"[/codeblock]"
#: doc/classes/MarginContainer.xml
msgid ""
"All direct children of [MarginContainer] will have a bottom margin of "
"[code]margin_bottom[/code] pixels."
msgstr ""
+"Tous les enfants directs de [MarginContainer] auront la marge du bas de "
+"[code]margin_bottom[/code] pixels."
#: doc/classes/MarginContainer.xml
msgid ""
"All direct children of [MarginContainer] will have a left margin of "
"[code]margin_left[/code] pixels."
msgstr ""
+"Tous les enfants directs de [MarginContainer] auront la marge gauche de "
+"[code]margin_left[/code] pixels."
#: doc/classes/MarginContainer.xml
msgid ""
"All direct children of [MarginContainer] will have a right margin of "
"[code]margin_right[/code] pixels."
msgstr ""
+"Tous les enfants directs de [MarginContainer] auront la marge droite de "
+"[code]margin_right[/code] pixels."
#: doc/classes/MarginContainer.xml
msgid ""
"All direct children of [MarginContainer] will have a top margin of "
"[code]margin_top[/code] pixels."
msgstr ""
+"Tous les enfants directs de [MarginContainer] auront la marge du haut de "
+"[code]margin_top[/code] pixels."
#: doc/classes/Marshalls.xml
-#, fuzzy
msgid "Data transformation (marshalling) and encoding helpers."
-msgstr "Transformation de données (marshalling) et assistants d'encodage."
+msgstr "Transformation de données (\"marshalling\") et assistants d'encodage."
#: doc/classes/Marshalls.xml
msgid "Provides data transformation and encoding utility functions."
@@ -44403,13 +44314,12 @@ msgstr ""
"données."
#: doc/classes/Marshalls.xml
-#, fuzzy
msgid ""
"Returns a decoded [PoolByteArray] corresponding to the Base64-encoded string "
"[code]base64_str[/code]."
msgstr ""
-"Renvoie un [PoolByteArray] décodé correspondant à la chaîne de caractères "
-"encodée en Base64 [code]base64_str[/code]."
+"Retourne un [PoolByteArray] décodé correspondant à la chaîne de caractères "
+"[code]base64_str[/code] encodée en Base64."
#: doc/classes/Marshalls.xml
msgid ""
@@ -44981,6 +44891,9 @@ msgid ""
"Uses specified surface of given [Mesh] to populate data for MeshDataTool.\n"
"Requires [Mesh] with primitive type [constant Mesh.PRIMITIVE_TRIANGLES]."
msgstr ""
+"Utiliser la surface spécifiée de [Mesh] pour construire les données pour le "
+"MeshDataTool.\n"
+"Nécessite un [Mesh] de type primitif [constant Mesh.PRIMITIVE_TRIANGES]."
#: doc/classes/MeshDataTool.xml
msgid "Returns the number of edges in this [Mesh]."
@@ -45000,6 +44913,9 @@ msgid ""
"Vertex argument can only be 0 or 1 because edges are comprised of two "
"vertices."
msgstr ""
+"Retourne l'index des sommet spécifiés reliés au bord donné.\n"
+"L'argument du sommet ne peut être que 0 ou 1 car les bords ne sont composés "
+"que de deux sommets."
#: doc/classes/MeshDataTool.xml
msgid "Returns the number of faces in this [Mesh]."
@@ -45010,6 +44926,9 @@ msgid ""
"Returns specified edge associated with given face.\n"
"Edge argument must be either 0, 1, or 2 because a face only has three edges."
msgstr ""
+"Retourne le bord spécifié associé au face donné.\n"
+"L'argument du bord doit être soit 0, 1 ou 2 parce qu'une face n'a que trois "
+"bords."
#: doc/classes/MeshDataTool.xml
msgid "Returns the metadata associated with the given face."
@@ -45025,6 +44944,9 @@ msgid ""
"Vertex argument must be either 0, 1, or 2 because faces contain three "
"vertices."
msgstr ""
+"Retourne le vertx spécifié du face donné.\n"
+"L'argument du sommet doit être soit 0, 1 ou 2 parce que les faces ne "
+"contiennent que trois sommets."
#: doc/classes/MeshDataTool.xml
msgid ""
@@ -45035,6 +44957,12 @@ msgid ""
"ARRAY_FORMAT_NORMAL] is [code]2[/code].\n"
"See [enum ArrayMesh.ArrayFormat] for a list of format flags."
msgstr ""
+"Retourne le format du [Mesh]. Le format est un entier composé des drapeaux "
+"de format du [Mesh]. Par exemple, un maillage contenant à la fois des "
+"sommets et des normales retournerait un format de [code]3[/code] parce que ["
+"constant ArrayMesh.ARRAY_FORMAT_VERTEX] est [code]1[/code] et [constant "
+"ArrayMesh.ARRAY_FORMAT_NORMAL] est [code]2[/code].\n"
+"Voir [enum ArrayMesh.ArrayFormat] pour une liste de drapeaux de format."
#: doc/classes/MeshDataTool.xml
msgid "Returns the material assigned to the [Mesh]."
@@ -45149,6 +45077,13 @@ msgid ""
"[Mesh] has to be instanced more than thousands of times at close proximity, "
"consider using a [MultiMesh] in a [MultiMeshInstance] instead."
msgstr ""
+"MeshInstance est un nœud qui prend une ressource [Mesh] et l'ajoute au "
+"scénario actuel en créant une instance. C'est la classe la plus souvent "
+"utilisée pour obtenir la géométrie 3D pour le rendu et peut être utilisé "
+"pour l'instance d'un seul [Mesh] dans de nombreux endroits. Cela permet de "
+"réutiliser la géométrie et d'économiser des ressources. Lorsqu'un [Mesh] "
+"doit être instancié plusieurs milliers de fois les uns proches des autres, "
+"préférez plutôt un [MultiMesh] dans un [MultiMeshInstance]."
#: doc/classes/MeshInstance.xml
msgid ""
@@ -45161,6 +45096,16 @@ msgid ""
"If [code]simplify[/code] is [code]true[/code], the geometry can be further "
"simplified to reduce the amount of vertices. Disabled by default."
msgstr ""
+"Cette aide crée un nœud [StaticBody] enfant avec une forme de collision "
+"[ConvexPolygonShape] calculée à partir de la géométrie du maillage. Elle est "
+"principalement utilisée pour les essais.\n"
+"Si [code]clean[/code] est [code]true[/code] (par défaut), les doublons et "
+"les sommets intérieurs sont automatiquement supprimés. Vous pouvez le "
+"définir à [code]false[/code] pour rendre le processus de création plus "
+"rapide.\n"
+"Si [code]simplify[/code] est [code]true[/code], la géométrie pourra être "
+"simplifiée pour réduire la quantité de sommets, ce qui est désactivé par "
+"défaut."
#: doc/classes/MeshInstance.xml
msgid ""
@@ -45199,11 +45144,15 @@ msgid ""
"[method Mesh.surface_get_material] to get materials associated with the "
"[Mesh] resource."
msgstr ""
+"Retourne la surcharge [Material] pour une surface de la ressource [Mesh].\n"
+"[b]Note :[/b] Cette fonction ne retourne que les matériaux associés à la "
+"[i]surchage[/i] de la [MeshInstance]. Préférez [method get_active_material] "
+"ou [method Mesh.surface_get_material] pour obtenir des matériaux associés à "
+"la ressource [Mesh]."
#: doc/classes/MeshInstance.xml
-#, fuzzy
msgid "Returns the number of surface override materials."
-msgstr "Retourne le nombre de surfaces du matériau."
+msgstr "Retourne le nombre de surcharges des surfaces du matériau."
#: doc/classes/MeshInstance.xml
msgid ""
@@ -45213,6 +45162,12 @@ msgid ""
"In order to be mergeable, properties of the [MeshInstance] must match, and "
"each surface must match, in terms of material, attributes and vertex format."
msgstr ""
+"Retourne [code]true[/code] si cette [MeshInstance] peut être fusionnée avec "
+"l'autre instance [code]other_mesh_instance[/code], en utilisant la fonction ["
+"method MeshInstance.merge_meshes].\n"
+"Pour pouvoir être fusionnées, les propriétés des [MeshInstance] doivent "
+"correspondre, et chaque surface doit correspondre, en termes de matériau, "
+"d'attributs et de format des sommets."
#: doc/classes/MeshInstance.xml
msgid ""
@@ -45237,6 +45192,26 @@ msgid ""
"Also note that any initial data in the destination [MeshInstance] data will "
"be discarded."
msgstr ""
+"Cette fonction peut fusionner les données de plusieurs [MeshInstance] "
+"sources en une seule [MeshInstance] finale (le MeshInstance sur laquel la "
+"fonction est appelée). Ceci est principalement utile pour améliorer les "
+"performances en réduisant le nombre de appels de dessin et de [Node].\n"
+"Le fusions ne doivent être faites que sur des maillages simples et ne "
+"contenant pas d'animation.\n"
+"Les sommets finaux peuvent soit être retournés dans l'espace global, soit "
+"dans l'espace local par rapport à la transformation globale de la "
+"[MeshInstance] finale (ce nœud doit être à l'intérieur du [SceneTree] pour "
+"l'espace local pour fonctionner).\n"
+"La fonction effectuera un contrôle final de compatibilité entre les "
+"[MeshInstance] par défaut, cela devrait toujours être utilisé à moins que "
+"vous n'ayez préalablement vérifié la compatibilité avec [method MeshInstance."
+"is_mergeable_with]. Si la vérification est ignorée et que les maillages sont "
+"fusionnés, vous pouvez voir des erreurs de rendu.\n"
+"[b]Note :[/b] Les exigences de similitude entre les maillages sont assez "
+"strictes. Elles peuvent être vérifiés avec [method MeshInstance."
+"is_mergeable_with], avant d'appeler [method MeshInstance.merge_meshes]\n"
+"Notez également que toutes les données initiales dans la [MeshInstance] "
+"finale seront supprimées."
#: doc/classes/MeshInstance.xml
msgid ""
@@ -45244,6 +45219,9 @@ msgid ""
"resource. This material is associated with this [MeshInstance] rather than "
"with the [Mesh] resource."
msgstr ""
+"Définit la surcharge [Material] pour la surface spécifiée de la ressource "
+"[Mesh]. Ce matériel est associé à cette ressource [MeshInstance] plutôt qu'à "
+"la ressource [Mesh]."
#: doc/classes/MeshInstance.xml
msgid "The [Mesh] resource for the instance."
@@ -45336,9 +45314,8 @@ msgid "Returns the item's mesh."
msgstr "Retourne le maillage de l'élément."
#: doc/classes/MeshLibrary.xml
-#, fuzzy
msgid "Returns the transform applied to the item's mesh."
-msgstr "Retourne la matrice de transformation de la toile de cet objet."
+msgstr ""
#: doc/classes/MeshLibrary.xml
msgid "Returns the item's name."
@@ -45381,9 +45358,8 @@ msgid "Sets the item's mesh."
msgstr "Définit le maillage de l'élément."
#: doc/classes/MeshLibrary.xml
-#, fuzzy
msgid "Sets the transform to apply to the item's mesh."
-msgstr "Retourne la matrice de transformation de la toile de cet objet."
+msgstr ""
#: doc/classes/MeshLibrary.xml
msgid ""
@@ -45607,6 +45583,18 @@ msgid ""
"(4 bytes as is) and [code]COLOR_FLOAT[/code] / [code]CUSTOM_DATA_FLOAT[/"
"code] is stored as 4 floats."
msgstr ""
+"Définit toutes les données relatives aux instances en une seule fois. Ceci "
+"est particulièrement utile lors du chargement des données du disque ou de la "
+"préparation des données de GDNative.\n"
+"Toutes les données sont empaquetées dans un grand tableau flottant. Un "
+"tableau peut ressembler à ceci : la Transform pour l'instance 1, les données "
+"de couleur pour l'instance 1, des données personnalisées pour l'instance 1, "
+"la Transform pour l'instance 2, les données de couleur pour l'instance 2, "
+"etc.\n"
+"[Transform] est enregistré avec 12 flottants, [Transform2D] avec 8 "
+"flottants, [code]COLOR_8BIT[/code] / [code]CUSTOM_DATA_8BIT[/code] avec 1 "
+"flottant (4 octets en général) et [code]COLOR_FLOAT[/code] / "
+"[code]CUSTOM_DATA_FLOAT[/code] avec 4 flottants."
#: doc/classes/MultiMesh.xml
msgid ""
@@ -45619,6 +45607,16 @@ msgid ""
"When the order of instances is coherent, the simpler [method MultiMesh."
"set_as_bulk_array] can still be used with interpolation."
msgstr ""
+"Une version alternative de [method MultiMesh.set_as_bulk_array] qui peut "
+"être utilisée avec [i]l'interpolation physique[/i]. Cette méthode prend deux "
+"tableaux, et peut définir les données pour la trame actuelle et précédente "
+"en une seule fois. Le rendu interpolera automatiquement les données entre "
+"ces deux trames.\n"
+"Ceci est utile pour les situations où l'ordre des instances peut changer "
+"d'une trame physique à l'autre, comme les systèmes de particules.\n"
+"Lorsque l'ordre des instances est cohérent, la méthode [method MultiMesh."
+"set_as_bulk_array] plus simple peut encore être utilisée avec "
+"l'interpolation."
#: doc/classes/MultiMesh.xml
msgid ""
@@ -45628,6 +45626,11 @@ msgid ""
"[code]null[/code] on the [MultiMesh] and [member SpatialMaterial."
"vertex_color_use_as_albedo] is [code]true[/code] on the material."
msgstr ""
+"Définit la couleur d'une instance spécifique en [i]multipliant[/i] les "
+"couleurs des sommets existants du maillage.\n"
+"Pour que la couleur soit modifiée, assurez-vous que [member color_format] "
+"n'est pas [code]null[/code] pour le [MultiMesh] et [member SpatialMaterial."
+"vertex_color_use_as_albedo] est [code]true[/code] dans le matériau."
#: doc/classes/MultiMesh.xml
msgid ""
@@ -45635,6 +45638,10 @@ msgid ""
"just a container for 4 floating point numbers. The format of the number can "
"change depending on the [enum CustomDataFormat] used."
msgstr ""
+"Définit des données personnalisées pour une instance spécifique. Bien que "
+"[Color] soit utilisée, ce n'est qu'un conteneur pour 4 flottants qui peut "
+"servir à autre chose. Le format du nombre peut changer en fonction du [enum "
+"CustomDataFormat] utilisé."
#: doc/classes/MultiMesh.xml
msgid "Sets the [Transform] for a specific instance."
@@ -45646,11 +45653,11 @@ msgstr "Définit la [Transform2D] pour l'instance spécifiée."
#: doc/classes/MultiMesh.xml
msgid "Format of colors in color array that gets passed to shader."
-msgstr ""
+msgstr "Le format des couleurs dans le tableau de couleurs passé au shader."
#: doc/classes/MultiMesh.xml
msgid "Format of custom data in custom data array that gets passed to shader."
-msgstr ""
+msgstr "Le format des données personnalisées dans ce tableau passé au shader."
#: doc/classes/MultiMesh.xml
msgid ""
@@ -45658,6 +45665,9 @@ msgid ""
"buffers. By default, all instances are drawn but you can limit this with "
"[member visible_instance_count]."
msgstr ""
+"Le nombre de cas qui seront affichés. Cela effacera et re-dimensionnera les "
+"mémoires tampons. Par défaut, toutes les instantes sont dessinées mais vous "
+"pouvez les limiter avec [member visible_instance_count]."
#: doc/classes/MultiMesh.xml
msgid "Mesh to be drawn."
@@ -45672,6 +45682,14 @@ msgid ""
"special cases mentioned above, the quality should be comparable to high "
"quality."
msgstr ""
+"Choisis si vous utilisez une méthode d'interpolation qui favorise la vitesse "
+"ou la qualité.\n"
+"Lors de l'utilisation de faibles taux de trames physiques (généralement "
+"inférieur à 20) ou de taux élevés de rotation d'objets, vous pouvez obtenir "
+"de meilleurs résultats à partir du réglage de haute qualité.\n"
+"[b]Note :[/b] La qualité rapide ne correspond pas à la qualité basse. Sauf "
+"dans les cas particuliers mentionnés ci-dessus, la qualité devrait être "
+"comparable à la qualité."
#: doc/classes/MultiMesh.xml
msgid "Format of transform used to transform mesh, either 2D or 3D."
@@ -45684,6 +45702,8 @@ msgid ""
"Limits the number of instances drawn, -1 draws all instances. Changing this "
"does not change the sizes of the buffers."
msgstr ""
+"Limite le nombre d'instances affichées, et -1 les dessine toutes. Changer "
+"cela ne change pas la taille des mémoires tampons."
#: doc/classes/MultiMesh.xml
msgid "Use this when using 2D transforms."
@@ -45702,12 +45722,17 @@ msgid ""
"Compress [Color] data into 8 bits when passing to shader. This uses less "
"memory and can be faster, but the [Color] loses precision."
msgstr ""
+"Compresse les données [Color] en 8 bits quand elles seront passées au "
+"shader. Cela utilise moins de mémoire et peut être plus rapide, mais les "
+"[Color] perdent en précision."
#: doc/classes/MultiMesh.xml
msgid ""
"The [Color] passed into [method set_instance_color] will use 4 floats. Use "
"this for highest precision [Color]."
msgstr ""
+"La [Color] passée dans [method set_instance_color] utilisera 4 flottants. "
+"Utilisez ceci pour la plus haute précision [Color]."
#: doc/classes/MultiMesh.xml
msgid "Use when you are not using per-instance custom data."
@@ -45899,12 +45924,16 @@ msgid ""
"Emitted when this MultiplayerAPI's [member network_peer] successfully "
"connected to a server. Only emitted on clients."
msgstr ""
+"Émis lorsque le [member network_peer] de ce MultijoueurAPI est connecté avec "
+"succès à un serveur. Seulement émis aux clients."
#: doc/classes/MultiplayerAPI.xml
msgid ""
"Emitted when this MultiplayerAPI's [member network_peer] fails to establish "
"a connection to a server. Only emitted on clients."
msgstr ""
+"Émis lorsque le [member network_peer] de ce MultijoueurAPI ne parvient pas à "
+"établir une connexion à un serveur. Seulement émis aux clients."
#: doc/classes/MultiplayerAPI.xml
msgid ""
@@ -45913,6 +45942,11 @@ msgid ""
"clients connect to the same server. Upon connecting to a server, a client "
"also receives this signal for the server (with ID being 1)."
msgstr ""
+"Émis lorsque le [member network_peer] de ce MultiplayerAPI se connecte à un "
+"nouveau pair. L'identifiant est celui du nouveau pair. Les clients sont "
+"informés lorsque d'autres clients se connectent au même serveur. En se "
+"connectant à un serveur, un client reçoit également ce signal pour le "
+"serveur (avec identifiant étant à 1)."
#: doc/classes/MultiplayerAPI.xml
msgid ""
@@ -45920,6 +45954,9 @@ msgid ""
"peer. Clients get notified when other clients disconnect from the same "
"server."
msgstr ""
+"Émis lorsque le [member network_peer] de ce MultiplayerAPI se déconnecte "
+"d'un pair. Les clients sont informés lorsque d'autres clients se "
+"déconnectent du même serveur."
#: doc/classes/MultiplayerAPI.xml
msgid ""
@@ -45927,12 +45964,18 @@ msgid ""
"[code]packet[/code] with custom data (see [method send_bytes]). ID is the "
"peer ID of the peer that sent the packet."
msgstr ""
+"Émis lorsque le [member network_peer] de ce MultijoueurAPI reçoit un "
+"[code]packet[/code] avec des données personnalisées (voir [method "
+"send_bytes)]. L'identifiant est l'identifiant par les pairs de l'équipe qui "
+"a envoyé le paquet."
#: doc/classes/MultiplayerAPI.xml
msgid ""
"Emitted when this MultiplayerAPI's [member network_peer] disconnects from "
"server. Only emitted on clients."
msgstr ""
+"Émis lorsque le [member network_peer] de ce MultijoueurAPI se déconnecte du "
+"serveur. Seulement émis sur les clients."
#: doc/classes/MultiplayerAPI.xml
msgid ""
@@ -45973,34 +46016,47 @@ msgid ""
"[i]Deprecated.[/i] Use [constant RPC_MODE_PUPPET] instead. Analogous to the "
"[code]slave[/code] keyword."
msgstr ""
+"[i]Obsolète.[/i] Utilisez plutôt [constant RPC_MODE_PUPPET]. Similaire au "
+"mot-clé [code]slave[/code]."
#: doc/classes/MultiplayerAPI.xml
msgid ""
"Behave like [constant RPC_MODE_REMOTE] but also make the call or property "
"change locally. Analogous to the [code]remotesync[/code] keyword."
msgstr ""
+"Se comporte comme [constant RPC_MODE_REMOTE] mais fait aussi l'appel ou le "
+"changement d'un propriété en local. Similaire au mot-clé "
+"[code]remotesync[/code]."
#: doc/classes/MultiplayerAPI.xml
msgid ""
"[i]Deprecated.[/i] Use [constant RPC_MODE_REMOTESYNC] instead. Analogous to "
"the [code]sync[/code] keyword."
msgstr ""
+"[i]Obsolète.[/i] Utilisez plutôt [constant RPC_MODE_REMOTESYNC]. Similaire "
+"au mot-clé [code]sync[/code]."
#: doc/classes/MultiplayerAPI.xml
msgid ""
"Behave like [constant RPC_MODE_MASTER] but also make the call or property "
"change locally. Analogous to the [code]mastersync[/code] keyword."
msgstr ""
+"Se comporte comme [constant RPC_MODE_MASTER] mais fait aussi l'appel ou le "
+"changement d'une propriété en local. Similaire au mot-clé "
+"[code]mastersync[/code]."
#: doc/classes/MultiplayerAPI.xml
msgid ""
"Behave like [constant RPC_MODE_PUPPET] but also make the call or property "
"change locally. Analogous to the [code]puppetsync[/code] keyword."
msgstr ""
+"Se comporte comme [constant RPC_MODE_PUPPET] mais fait aussi l'appel ou le "
+"changement d'une propriété en local. Similaire au mot-clé "
+"[code]puppetsync[/code]."
#: doc/classes/Mutex.xml
msgid "A synchronization mutex (mutual exclusion)."
-msgstr ""
+msgstr "Un mutex de synchronisation (exclusion mutuelle)."
#: doc/classes/Mutex.xml
msgid ""
@@ -46117,6 +46173,9 @@ msgid ""
"Returns the owner of the [NavigationMesh] which contains the navigation "
"point closest to the point given. This is usually a [NavigationMeshInstance]."
msgstr ""
+"Retourne le propriétaire du [NavigationMesh] qui contient le point de "
+"navigation le plus proche du point donné. C'est généralement une "
+"[NavigationMeshInstance]."
#: doc/classes/Navigation.xml
msgid ""
@@ -46127,9 +46186,8 @@ msgid ""
msgstr ""
#: doc/classes/Navigation.xml
-#, fuzzy
msgid "Returns the [RID] of the navigation map on the [NavigationServer]."
-msgstr "Retourne le [RID] de la énième forme d'une zone."
+msgstr ""
#: doc/classes/Navigation.xml
msgid ""
@@ -46141,6 +46199,13 @@ msgid ""
"agent properties associated with each [NavigationMesh] (radius, height, "
"etc.) are considered in the path calculation, otherwise they are ignored."
msgstr ""
+"[i]Obsolète.[/i] Le nœud [Navigation] la méthode [method get_simple_path] "
+"sont obsolètes se seront retiré dans une prochaine version. Utilisez plutôt ["
+"method NavigationServer.map_get_path].\n"
+"Retourne le chemin entre deux points donnés. Les points sont des coordonées "
+"locales. Si [code]optimize[/code] est [code]true[/code] (par défaut), les "
+"propriétés de l'agent associées à chaque [NavigationMesh] (rayon, hauteur, "
+"etc.) sont considérés dans le calcul du chemin, sinon ils sont ignorés."
#: doc/classes/Navigation.xml
msgid "The cell height to use for fields."
@@ -46166,12 +46231,16 @@ msgid ""
"Defines which direction is up. By default, this is [code](0, 1, 0)[/code], "
"which is the world's \"up\" direction."
msgstr ""
+"Définit la direction. Par défaut, il s'agit de [code](0, 1, 0)[/code], qui "
+"est la direction du haut (\"up\")."
#: doc/classes/Navigation.xml doc/classes/Navigation2DServer.xml
#: doc/classes/NavigationServer.xml
msgid ""
"Emitted when a navigation map is updated, when a region moves or is modified."
msgstr ""
+"Émis quand une carte de navigation est mise à jour, ou quand une région se "
+"déplace ou est modifiée."
#: doc/classes/Navigation2D.xml
msgid "2D navigation and pathfinding node."
@@ -46220,9 +46289,8 @@ msgid ""
msgstr ""
#: doc/classes/Navigation2DServer.xml
-#, fuzzy
msgid "Server interface for low-level 2D navigation access."
-msgstr "Interface de serveur pour l'accès audio de bas niveau."
+msgstr ""
#: doc/classes/Navigation2DServer.xml
#, fuzzy
@@ -46260,16 +46328,16 @@ msgstr ""
"de navigation. Ensemble, ces cartes définissent les aires navigables dans le "
"monde 2D. Pour que deux régions soient connectées entre elles, elles doivent "
"avoir une bordure en commun. Une bordure (\"edge\") est considérée connectée "
-"à une autre si elles ont deux sommets rapprochés de moins de la distance "
-"[member Navigation.edge_connection_margin].\n"
+"à une autre si elles ont deux sommets rapprochés de moins de la distance ["
+"member Navigation.edge_connection_margin].\n"
"Pour utiliser le système d'évitement, vous devez utiliser des agents. Vous "
"pouvez définir la vitesse cible d'un agent, puis le serveur émettra une "
"méthode de rappel avec la vitesse modifiée.\n"
"[b]Note :[/b] Le système d'évitement des collisions ignorent les régions. "
"Utiliser la vitesse modifiée telle quelle peut déplacer un agent hors de la "
-"surface de navigable. C'est une limite du système d'évitement des collision, "
-"et certaines situations plus complexes peuvent nécessiter l'utilisation du "
-"moteur physique.\n"
+"surface de navigable. C'est une limite du système d'évitement des "
+"collisions, et certaines situations plus complexes peuvent nécessiter "
+"l'utilisation du moteur physique.\n"
"Le serveur garde en mémoire tous les appels et les exécutent durant la phase "
"de synchronisation. Cela veut dire que vous pouvez demander n'importe quel "
"changement sur l'ensemble des cartes, via n'importe quel fil d'exécution, "
@@ -46284,11 +46352,12 @@ msgid ""
"Returns the navigation map [RID] the requested [code]agent[/code] is "
"currently assigned to."
msgstr ""
+"Retourne le [RID] de la carte de navigation auquel le [code]agent[/code] "
+"spécifié est actuellement assigné."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
-#, fuzzy
msgid "Returns [code]true[/code] if the map got changed the previous frame."
-msgstr "Renvoie [code]true[/code] si le chemin donné est filtré."
+msgstr ""
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
msgid ""
@@ -46314,11 +46383,13 @@ msgid ""
"navigation. The larger this number, the longer the running time of the "
"simulation. If the number is too low, the simulation will not be safe."
msgstr ""
+"Définit le nombre maximal d'autres agents que cet agent prend en compte dans "
+"la navigation. Plus ce nombre est grand, plus la durée de la simulation est "
+"longue. Si le nombre est trop bas, la simulation ne sera pas fiable."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
-#, fuzzy
msgid "Sets the maximum speed of the agent. Must be positive."
-msgstr "Obtient le nom d'un entrée par son index."
+msgstr ""
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
msgid ""
@@ -46326,11 +46397,14 @@ msgid ""
"the navigation. The larger this number, the longer the running time of the "
"simulation. If the number is too low, the simulation will not be safe."
msgstr ""
+"Définit la distance maximale avec d'autres agents que cet agent prend en "
+"compte dans la navigation. Plus ce nombre est grand, plus la durée de la "
+"simulation est longue. Si le nombre est trop bas, la simulation ne sera pas "
+"fiable."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
-#, fuzzy
msgid "Sets the position of the agent in world space."
-msgstr "Définit la position du nœud spécifié."
+msgstr ""
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
msgid "Sets the radius of the agent."
@@ -46348,11 +46422,14 @@ msgid ""
"agents, but the less freedom this agent has in choosing its velocities. Must "
"be positive."
msgstr ""
+"La quantité minimale de temps pour laquelle les vitesses de l'agent "
+"calculées par la simulation sont fiables pour les autres agents. Plus ce "
+"nombre est grand, plus tôt cet agent répondra à la présence d'autres agents, "
+"mais moins il aura de liberté pour choisir sa vitesse. Ça doit être positif."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
-#, fuzzy
msgid "Sets the current velocity of the agent."
-msgstr "Définit le trame présentement visible de l'animation."
+msgstr ""
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
msgid "Destroys the given RID."
@@ -46364,6 +46441,9 @@ msgid ""
"returns both 2D and 3D created navigation maps as there is technically no "
"distinction between them."
msgstr ""
+"Retourne tous les [RID] des cartes de navigation créées sur le "
+"NavigationServer. Cela renvoie les cartes de navigation 2D et aussi 3D car "
+"il n'y a techniquement aucune distinction entre eux."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
msgid "Create a new map."
@@ -46397,19 +46477,47 @@ msgid ""
"but it can also introduce bugs if used inappropriately without much "
"foresight."
msgstr ""
+"Cette fonction force immédiatement la synchronisation de la navigation "
+"spécifiée par le [RID] spécifié par [code]map[/code]. Par défaut, les cartes "
+"de navigation ne sont synchronisées qu'à la fin de chaque trame physique. "
+"Cette fonction peut être utilisée pour calculer immédiatement tous les "
+"maillages de navigation et les connexions entre les régions de la carte de "
+"navigation. Cela permet d'interroger un chemin de navigation pour une carte "
+"modifiée immédiatement et dans la même trame (plusieurs fois si nécessaire)."
+"\n"
+"En raison de restrictions techniques, la file de commandes actuelle de "
+"NavigationServer sera exécutée aussitôt. Cela signifie que toutes les "
+"commandes de mise à jour en attente pour cette trame de physique seront "
+"exécutées, même celles destinées à d'autres cartes, régions et agents qui ne "
+"font pas partie de la carte spécifiée. Le calcul coûteux des maillages de "
+"navigation et des connexions de régions d'une carte ne sera fait que pour la "
+"carte spécifiée. D'autres cartes recevront la synchronisation normale à la "
+"fin de la trame physique. Si la carte spécifiée reçoit des changements après "
+"la mise à jour forcée, elle sera à nouveau mise à jour aussi bien lorsque "
+"les autres cartes recevront leur mise à jour.\n"
+"Le traitement d'évitement et l'envoi des signaux [code]safe_velocity[/code] "
+"ne sont pas affectés par cette fonction et continuent de se produire pour "
+"tous les cartes et agents à la fin de la trame physique.\n"
+"[b]Note :[/b] Une grande pouvoir implique une grande responsabilité. Cette "
+"fonction ne devrait être utilisée que par les utilisateurs qui savent "
+"vraiment ce qu'ils font et ont une bonne raison de l'utiliser. Pour "
+"effectuer une mise à jour immédiate d'une carte de navigation, il faut "
+"verrouiller le NavigationServer et exécuter toute la file de commandes du "
+"NavigationServer. Non seulement cela peut affecter sévèrement les "
+"performances du jeu, mais il peut également introduire des bugs si ça n'est "
+"pas fait avec le plus grand soin."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
msgid ""
"Returns all navigation agents [RID]s that are currently assigned to the "
"requested navigation [code]map[/code]."
msgstr ""
+"Retourne tous [RID] des agents de navigation qui sont actuellement affectés "
+"à la navigation [code]map[/code] spécifiée."
#: doc/classes/Navigation2DServer.xml
-#, fuzzy
msgid "Returns the map cell height. [b]Note:[/b] Currently not implemented."
msgstr ""
-"Retourne l'actuelle ligne du fichier interprété (actuellement non "
-"implémenté)."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
msgid "Returns the map cell size."
@@ -46428,12 +46536,16 @@ msgid ""
"Returns the owner region RID for the point returned by [method "
"map_get_closest_point]."
msgstr ""
+"Retourne la région propriétaire du RID pour le point retourné par [method "
+"map_get_closest_point]."
#: doc/classes/Navigation2DServer.xml
msgid ""
"Returns the edge connection margin of the map. The edge connection margin is "
"a distance used to connect two regions."
msgstr ""
+"Retourne la marge de raccordement du bord de la carte. La marge de "
+"raccordement est une distance utilisée pour relier deux régions."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
msgid ""
@@ -46441,38 +46553,42 @@ msgid ""
"[code]navigation_layers[/code] is a bitmask of all region layers that are "
"allowed to be in the path."
msgstr ""
+"Retourne le chemin de navigation pour atteindre la destination de l'origine. "
+"[code]navigation_layers[/code] est un bitmask de toutes les calques de la "
+"région qui sont autorisées à être dans le chemin."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
msgid ""
"Returns all navigation regions [RID]s that are currently assigned to the "
"requested navigation [code]map[/code]."
msgstr ""
+"Retourne toutes les régions de navigation [RID] qui sont actuellement "
+"affectées à la navigation demandée [code]map[/code]."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
-#, fuzzy
msgid "Returns [code]true[/code] if the map is active."
-msgstr "Retourne [code]true[/code] si l'[AABB] est vide."
+msgstr ""
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
msgid "Sets the map active."
msgstr "Définit la carte comme active."
#: doc/classes/Navigation2DServer.xml
-#, fuzzy
msgid ""
"Set the map cell height used to weld the navigation mesh polygons. [b]Note:[/"
"b] Currently not implemented."
-msgstr "Définit le polygone de navigation de la tuile."
+msgstr ""
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
-#, fuzzy
msgid "Set the map cell size used to weld the navigation mesh polygons."
-msgstr "Définit le polygone de navigation de la tuile."
+msgstr ""
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
msgid ""
"Set the map edge connection margin used to weld the compatible region edges."
msgstr ""
+"Définit la marge de connexion de bord de la carte utilisée pour fusionner "
+"les bords compatibles de la région."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
msgid "Creates a new region."
@@ -46484,6 +46600,8 @@ msgid ""
"index between 0 and the return value of [method "
"region_get_connections_count]."
msgstr ""
+"Retourne le point de fin d'une porte de connexion. [code]connection[/code] "
+"est un indice entre 0 et la valeur de [method region_get_connections_count]."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
msgid ""
@@ -46491,33 +46609,36 @@ msgid ""
"an index between 0 and the return value of [method "
"region_get_connections_count]."
msgstr ""
+"Retourne le point de départ d'une porte de connexion. [code]connection[/code]"
+" est un indice entre 0 et la valeur de [method region_get_connections_count]."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
msgid ""
"Returns how many connections this [code]region[/code] has with other regions "
"in the map."
msgstr ""
+"Retourne le nombre de connexions ce [code]region[/code] a avec les autres "
+"régions de la carte."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
-#, fuzzy
msgid "Returns the [code]enter_cost[/code] of this [code]region[/code]."
-msgstr "Retourne [code]true[/code] si le [code]signal[/code] donné existe."
+msgstr ""
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
msgid ""
"Returns the navigation map [RID] the requested [code]region[/code] is "
"currently assigned to."
msgstr ""
+"Retourne le [RID] de la carte de navigation à laquelle la [code]region[/code]"
+" spécifiée est actuellement assignée."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
-#, fuzzy
msgid "Returns the region's navigation layers."
-msgstr "Retourne le maillage de navigation de l'élément."
+msgstr "Retourne les calques de navigation de la région."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
-#, fuzzy
msgid "Returns the [code]travel_cost[/code] of this [code]region[/code]."
-msgstr "Retourne [code]true[/code] si le [code]signal[/code] donné existe."
+msgstr ""
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
msgid ""
@@ -46551,16 +46672,12 @@ msgstr ""
"le résultat peut être inattendu."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
-#, fuzzy
msgid "Sets the [code]enter_cost[/code] for this [code]region[/code]."
msgstr ""
-"Définit la [code]position[/code] du point avec l'identifiant [code]id[/code] "
-"spécifié."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
-#, fuzzy
msgid "Sets the map for the region."
-msgstr "Retourne la hauteur du contenu."
+msgstr "Définit la carte de la région."
#: doc/classes/Navigation2DServer.xml
msgid ""
@@ -46569,24 +46686,19 @@ msgid ""
msgstr ""
"Définit les calques de navigation de la région. Cela permet de sélectionner "
"les régions à partir d'une requête de chemin (en utilisant [method "
-"Navigation2DServer.map_get_path])"
+"Navigation2DServer.map_get_path])."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
-#, fuzzy
msgid "Sets the navigation mesh for the region."
-msgstr "Définit le polygone de navigation de la tuile."
+msgstr "Définit le polygone de navigation de la région."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
-#, fuzzy
msgid "Sets the global transformation for the region."
-msgstr "Retourne la matrice de transformation globale de cet élément."
+msgstr "Retourne la transformation globale de cette région."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
-#, fuzzy
msgid "Sets the [code]travel_cost[/code] for this [code]region[/code]."
msgstr ""
-"Définit la [code]position[/code] du point avec l'identifiant [code]id[/code] "
-"spécifié."
#: doc/classes/NavigationAgent.xml
msgid "3D agent used in navigation for collision avoidance."
@@ -46714,23 +46826,20 @@ msgstr ""
"la NavigationAgent."
#: doc/classes/NavigationAgent.xml
-#, fuzzy
msgid "Returns the [RID] of this agent on the [NavigationServer]."
-msgstr "Retourne le [RID] de la énième forme d'une zone."
+msgstr "Retourne le [RID] de cet agent dans le [NavigationServer]."
#: doc/classes/NavigationAgent.xml doc/classes/NavigationAgent2D.xml
-#, fuzzy
msgid ""
"Returns the user-defined target location (set with [method "
"set_target_location])."
-msgstr "Renvoie le mode de remplacement de l’espace pour la zone."
+msgstr ""
#: doc/classes/NavigationAgent.xml doc/classes/NavigationAgent2D.xml
-#, fuzzy
msgid ""
"Returns [code]true[/code] if the navigation path's final location has been "
"reached."
-msgstr "Renvoie [code]true[/code] si le chemin donné est filtré."
+msgstr ""
#: doc/classes/NavigationAgent.xml doc/classes/NavigationAgent2D.xml
msgid ""
@@ -46827,14 +46936,12 @@ msgstr ""
"déplacer sur un plan horizontal."
#: doc/classes/NavigationAgent.xml doc/classes/NavigationAgent2D.xml
-#, fuzzy
msgid "The maximum number of neighbors for the agent to consider."
-msgstr "La valeur de luminance maximale pour l'exposition automatique."
+msgstr ""
#: doc/classes/NavigationAgent.xml doc/classes/NavigationAgent2D.xml
-#, fuzzy
msgid "The maximum speed that an agent can move."
-msgstr "Rotation maximale à travers la charnière."
+msgstr "La vitesse maximale à laquelle un agent peut se déplacer."
#: doc/classes/NavigationAgent.xml
msgid ""
@@ -46848,9 +46955,8 @@ msgstr ""
"correspondant."
#: doc/classes/NavigationAgent.xml doc/classes/NavigationAgent2D.xml
-#, fuzzy
msgid "The distance to search for other agents."
-msgstr "L’instance n’a pas de type."
+msgstr ""
#: doc/classes/NavigationAgent.xml doc/classes/NavigationAgent2D.xml
msgid ""
@@ -46929,9 +47035,8 @@ msgstr ""
"doit être positif."
#: doc/classes/NavigationAgent.xml doc/classes/NavigationAgent2D.xml
-#, fuzzy
msgid "Notifies when the final location is reached."
-msgstr "Avertit quand une animation commence à jouer."
+msgstr ""
#: doc/classes/NavigationAgent.xml doc/classes/NavigationAgent2D.xml
msgid ""
@@ -47008,9 +47113,8 @@ msgstr ""
"navigation."
#: doc/classes/NavigationAgent2D.xml
-#, fuzzy
msgid "Returns the [RID] of this agent on the [Navigation2DServer]."
-msgstr "Retourne le [RID] de la énième forme d'une zone."
+msgstr "Retourne le [RID] de cet agent dans le [Navigation2DServer]."
#: doc/classes/NavigationAgent2D.xml
msgid ""
@@ -47090,11 +47194,10 @@ msgid ""
msgstr ""
#: doc/classes/NavigationMesh.xml
-#, fuzzy
msgid ""
"Returns whether the specified [code]bit[/code] of the [member "
"geometry_collision_mask] is set."
-msgstr "Retourne si la [code]class[/code] spécifiée est disponible ou non."
+msgstr ""
#: doc/classes/NavigationMesh.xml doc/classes/NavigationPolygon.xml
msgid ""
@@ -47105,9 +47208,8 @@ msgstr ""
"créé."
#: doc/classes/NavigationMesh.xml
-#, fuzzy
msgid "Returns the number of polygons in the navigation mesh."
-msgstr "Renvoie le nombre de points sur l'axe de mélange."
+msgstr ""
#: doc/classes/NavigationMesh.xml
msgid ""
@@ -47118,17 +47220,16 @@ msgstr ""
"créé."
#: doc/classes/NavigationMesh.xml
-#, fuzzy
msgid ""
"If [code]value[/code] is [code]true[/code], sets the specified [code]bit[/"
"code] in the [member geometry_collision_mask].\n"
"If [code]value[/code] is [code]false[/code], clears the specified [code]bit[/"
"code] in the [member geometry_collision_mask]."
msgstr ""
-"Si [code]value[/code] est [code]true[/code]], définit le [code]bit[/code] "
-"spécifié dans le masque [nom collision_mask].\n"
-"Si [code]value[/code] est [code]false[/code], rétablit le [code]bit[/code] "
-"spécifié dans le masque [nom collision_mask]."
+"Si [code]value[/code] est [code]true[/code], définit le [code]bit[/code] "
+"spécifié dans le masque [member geometry_collision_mask].\n"
+"Si [code]value[/code] est [code]false[/code], efface le [code]bit[/code] "
+"spécifié dans le masque [member geometry_collision_mask]."
#: doc/classes/NavigationMesh.xml doc/classes/NavigationPolygon.xml
msgid ""
@@ -47152,9 +47253,8 @@ msgid ""
msgstr ""
#: doc/classes/NavigationMesh.xml
-#, fuzzy
msgid "The maximum slope that is considered walkable, in degrees."
-msgstr "Rotation maximale à travers la charnière."
+msgstr ""
#: doc/classes/NavigationMesh.xml
msgid ""
@@ -47203,9 +47303,8 @@ msgid "The position offset applied to the [member filter_baking_aabb] [AABB]."
msgstr ""
#: doc/classes/NavigationMesh.xml
-#, fuzzy
msgid "If [code]true[/code], marks spans that are ledges as non-walkable."
-msgstr "Si [code]true[/code], les titres des colonnes sont visibles."
+msgstr ""
#: doc/classes/NavigationMesh.xml
msgid ""
@@ -47214,13 +47313,10 @@ msgid ""
msgstr ""
#: doc/classes/NavigationMesh.xml
-#, fuzzy
msgid ""
"If [code]true[/code], marks walkable spans as not walkable if the clearance "
"above the span is less than [member agent_height]."
msgstr ""
-"Si [code]true[/code], les particules sera émise une seule fois puis "
-"arrêtées. Équivalent à [member Particles.one_shot]."
#: doc/classes/NavigationMesh.xml
msgid ""
@@ -47489,18 +47585,16 @@ msgstr ""
"geometry_source_geometry_mode] de la ressource [NavigationMesh]."
#: doc/classes/NavigationMeshGenerator.xml
-#, fuzzy
msgid ""
"Removes all polygons and vertices from the provided [code]nav_mesh[/code] "
"resource."
-msgstr "Supprime l’animation avec la touche [code]name[/code]."
+msgstr ""
#: doc/classes/NavigationMeshInstance.xml
msgid "An instance of a [NavigationMesh]."
msgstr "Une instance de [NavigationMesh]."
#: doc/classes/NavigationMeshInstance.xml
-#, fuzzy
msgid ""
"An instance of a [NavigationMesh]. It tells the [Navigation] node what can "
"be navigated and what cannot, based on the [NavigationMesh] resource.\n"
@@ -47533,7 +47627,7 @@ msgstr ""
"relier deux régions. Ils doivent partager un même bord.\n"
"Le coût d'entrée dans cette région d'une autre région peut être contrôlé "
"avec la valeur [member enter_cost].\n"
-"[b]Note : [/b] Cette valeur n'est pas ajoutée au coût du chemin lorsque la "
+"[b]Note :[/b] Cette valeur n'est pas ajoutée au coût du chemin lorsque la "
"position de départ est déjà dans cette région.\n"
"Le coût des distances de voyage dans cette région peut être contrôlé avec le "
"multiplicateur [member travel_cost]."
@@ -47550,6 +47644,18 @@ msgid ""
"operating systems that cannot use threads (such as HTML5 with threads "
"disabled)."
msgstr ""
+"Pré-calcule le [NavigationMesh]. Si [code]on_thread[/code] est défini à "
+"[code]true[/code] (par défaut), le pré-calcul est fait sur un fil "
+"d'exécution séparé. Le pré-calcul sur un fil d'exécution séparé est utile "
+"parce que la navigation est une opération relativement coûteuse. Lorsqu'il "
+"est terminé, il définit automatiquement ce nouveau [NavigationMesh]. "
+"Veuillez noter que le pré-calcul sur le fil d'exécution séparé peut être "
+"très lent si la géométrie est composée de plein de maillages puisque l'accès "
+"asynchrone à chaque maillage nécessite une lourde synchronisation. De plus, "
+"veuillez noter que le pré-calculs sur un fil d'exécution séparé est "
+"automatiquement désactivée sur les systèmes d'exploitation qui ne peuvent "
+"pas utiliser des fils d'exécution (comme HTML5 si cette fonction est "
+"désactivée)."
#: doc/classes/NavigationMeshInstance.xml
msgid ""
@@ -47558,6 +47664,10 @@ msgid ""
"identify the [NavigationMeshInstance] closest to a point on the merged "
"navigation map."
msgstr ""
+"Retourne le [RID] de cette région sur [NavigationServer]. Combiné avec ["
+"method NavigationServer.map_get_closest_point_owner], peut être utilisé pour "
+"identifier le [NavigationMeshInstance] le plus proche d'un point d'une carte "
+"de navigation fusionnée."
#: doc/classes/NavigationMeshInstance.xml
msgid "Determines if the [NavigationMeshInstance] is enabled or disabled."
@@ -47590,11 +47700,13 @@ msgid ""
"are multiplied with [code]travel_cost[/code] for determining the shortest "
"path."
msgstr ""
+"Lorsque le cheminement se déplace à l'intérieur de cette région, les "
+"distances parcourues sont multipliées par [code]travel_cost[/code] pour "
+"déterminer le chemin le plus court."
#: doc/classes/NavigationMeshInstance.xml
-#, fuzzy
msgid "Notifies when the navigation mesh bake operation is completed."
-msgstr "Avertit quand une animation commence à jouer."
+msgstr ""
#: doc/classes/NavigationMeshInstance.xml
msgid "Notifies when the [NavigationMesh] has changed."
@@ -47613,12 +47725,22 @@ msgid ""
"[b]Note:[/b] Obstacles are intended as a last resort option for constantly "
"moving objects that cannot be (re)baked to a navigation mesh efficiently."
msgstr ""
+"Obstacle 3D utilisé dans la navigation pour éviter les collisions. "
+"L'obstacle a besoin de données de navigation pour fonctionner correctement. "
+"Cela peut être fait avec l'obstacle comme enfant d'un nœud [Navigation], ou "
+"en utilisant [method set_navigation]. [NavigationObstacle] est sûr lors des "
+"trames physiques.\n"
+"[b]Note :[/b] Les obstacles sont conçus comme dernière option pour les "
+"objets constamment mobiles qui ne peuvent pas être pré-calculés efficacement "
+"dans un maillage de navigation."
#: doc/classes/NavigationObstacle.xml
msgid ""
"Returns the [Navigation] node that the obstacle is using for its navigation "
"system."
msgstr ""
+"Retourne le nœud [Navigation] que l'obstacle utilise pour son système de "
+"navigation."
#: doc/classes/NavigationObstacle.xml
msgid "Returns the [RID] of this obstacle on the [NavigationServer]."
@@ -47629,18 +47751,24 @@ msgid ""
"Sets the [Navigation] node used by the obstacle. Useful when you don't want "
"to make the obstacle a child of a [Navigation] node."
msgstr ""
+"Définit le nœud [Navigation] utilisé par l'obstacle. Utile lorsque vous ne "
+"voulez pas faire l'obstacle un enfant d'un nœud [Navigation]."
#: doc/classes/NavigationObstacle.xml doc/classes/NavigationObstacle2D.xml
msgid ""
"Enables radius estimation algorithm which uses parent's collision shapes to "
"determine the obstacle radius."
msgstr ""
+"Active l'algorithme d'estimation de rayon qui utilise les formes de "
+"collision des parents pour déterminer le rayon des obstacles."
#: doc/classes/NavigationObstacle.xml doc/classes/NavigationObstacle2D.xml
msgid ""
"The radius of the agent. Used only if [member estimate_radius] is set to "
"[code]false[/code]."
msgstr ""
+"Le rayon de l'agent. Utilisé uniquement si [member estimate_radius] est "
+"[code]false[/code]."
#: doc/classes/NavigationObstacle2D.xml
msgid "2D obstacle used in navigation for collision avoidance."
@@ -47655,12 +47783,22 @@ msgid ""
"[b]Note:[/b] Obstacles are intended as a last resort option for constantly "
"moving objects that cannot be (re)baked to a navigation mesh efficiently."
msgstr ""
+"L'obstacle 2D utilisé dans la navigation pour éviter les collisions. "
+"L'obstacle a besoin de données de navigation pour fonctionner correctement. "
+"Cela peut être fait avec l'obstacle comme enfant d'un nœud [Navigation2D], "
+"ou en utilisant [method set_navigation]. [NavigationObstacle2D] est sûr lors "
+"des trames physiques.\n"
+"[b]Note :[/b] Les obstacles sont conçus comme dernière option pour les "
+"objets constamment mobiles qui ne peuvent pas être pré-calculés efficacement "
+"dans un maillage de navigation."
#: doc/classes/NavigationObstacle2D.xml
msgid ""
"Returns the [Navigation2D] node that the obstacle is using for its "
"navigation system."
msgstr ""
+"Retourne le nœud [Navigation2D] que l'obstacle utilise pour son système de "
+"navigation."
#: doc/classes/NavigationObstacle2D.xml
msgid "Returns the [RID] of this obstacle on the [Navigation2DServer]."
@@ -47671,12 +47809,16 @@ msgid ""
"Sets the [Navigation2D] node used by the obstacle. Useful when you don't "
"want to make the obstacle a child of a [Navigation2D] node."
msgstr ""
+"Définit le nœud [Navigation2D] utilisé par l'obstacle. Utile lorsque vous ne "
+"voulez pas faire l'obstacle un enfant d'un nœud [Navigation2D]."
#: doc/classes/NavigationPolygon.xml
msgid ""
"A node that has methods to draw outlines or use indices of vertices to "
"create navigation polygons."
msgstr ""
+"Un nœud qui a des méthodes pour dessiner des contours ou utiliser des "
+"indices de sommets pour créer des polygones de navigation."
#: doc/classes/NavigationPolygon.xml
msgid ""
@@ -47702,6 +47844,27 @@ msgid ""
"$NavigationPolygonInstance.navpoly = polygon\n"
"[/codeblock]"
msgstr ""
+"Il y a deux façons de créer des polygones. Soit en utilisant la méthode ["
+"method add_outline], soit en utilisant la méthode [method add_polygon].\n"
+"Avec [method add_outline] :\n"
+"[codeblock]\n"
+"var polygon = NavigationPolygon.new()\n"
+"var outline = PoolVector2Array([Vector2(0, 0), Vector2(0, 50), Vector2(50, "
+"50), Vector2(50, 0)])\n"
+"polygon.add_outline(outline)\n"
+"polygon.make_polygons_from_outlines()\n"
+"$NavigationPolygonInstance.navpoly = polygon\n"
+"[/codeblock]\n"
+"Avec [method add_polygon] et les indices du tableau des sommets :\n"
+"[codeblock]\n"
+"var polygon = NavigationPolygon.new()\n"
+"var vertices = PoolVector2Array([Vector2(0, 0), Vector2(0, 50), Vector2(50, "
+"50), Vector2(50, 0)])\n"
+"polygon.set_vertices(vertices)\n"
+"var indices = PoolIntArray([0, 1, 2, 3])\n"
+"polygon.add_polygon(indices)\n"
+"$NavigationPolygonInstance.navpoly = polygon\n"
+"[/codeblock]"
#: doc/classes/NavigationPolygon.xml
msgid ""
@@ -47710,6 +47873,10 @@ msgid ""
"make_polygons_from_outlines] in order for this array to be converted to "
"polygons that the engine will use."
msgstr ""
+"Ajoute un [PoolVector2Array] qui contient les sommets d'un contour au "
+"tableau interne qui contient tous les contours. Vous devez appeler [method "
+"make_polygons_from_outlines] afin que ce tableau soit converti en polygones "
+"que le moteur pourra utiliser."
#: doc/classes/NavigationPolygon.xml
msgid ""
@@ -47718,18 +47885,26 @@ msgid ""
"to call [method make_polygons_from_outlines] in order for this array to be "
"converted to polygons that the engine will use."
msgstr ""
+"Ajoute un [PoolVector2Array] qui contient les sommets d'un contour au "
+"tableau interne qui contient tous les contours à une position fixe. Vous "
+"devez appeler [method make_polygons_from_outlines] afin que ce tableau soit "
+"converti en polygones que le pourra utiliser."
#: doc/classes/NavigationPolygon.xml
msgid ""
"Clears the array of the outlines, but it doesn't clear the vertices and the "
"polygons that were created by them."
msgstr ""
+"Efface le tableau des contours, mais ça n'efface pas les sommets et les "
+"polygones qui ont été créés par eux."
#: doc/classes/NavigationPolygon.xml
msgid ""
"Clears the array of polygons, but it doesn't clear the array of outlines and "
"vertices."
msgstr ""
+"Efface le tableau des polygones, mais ça n'effacera pas le tableau des "
+"contours et des sommets."
#: doc/classes/NavigationPolygon.xml
msgid ""
@@ -47738,17 +47913,25 @@ msgid ""
"NavigationServer.region_set_navmesh] API directly (as 2D uses the 3D server "
"behind the scene)."
msgstr ""
+"Retourne le [NavigationMesh] résultant de ce polygone de navigation. Ce "
+"navmesh peut être utilisé pour mettre à jour le navmesh d'une région avec "
+"l'API [method NavigationServer.region_set_navmesh] directement (comme la 2D "
+"utilise le serveur 3D en interne)."
#: doc/classes/NavigationPolygon.xml
msgid ""
"Returns a [PoolVector2Array] containing the vertices of an outline that was "
"created in the editor or by script."
msgstr ""
+"Retourne un [PoolVector2Array] contenant les sommets d'un contour qui a été "
+"créé dans l'éditeur ou par un script."
#: doc/classes/NavigationPolygon.xml
msgid ""
"Returns the number of outlines that were created in the editor or by script."
msgstr ""
+"Retourne le nombre de contours qui ont été créés dans l'éditeur ou par un "
+"script."
#: doc/classes/NavigationPolygon.xml
msgid "Returns the count of all polygons."
@@ -47759,30 +47942,35 @@ msgid ""
"Returns a [PoolVector2Array] containing all the vertices being used to "
"create the polygons."
msgstr ""
+"Retourne un [PoolVector2Array] contenant tous les sommets utilisés pour "
+"créer les polygones."
#: doc/classes/NavigationPolygon.xml
msgid "Creates polygons from the outlines added in the editor or by script."
msgstr ""
+"Crée des polygones des contours ajoutés dans l'éditeur ou par un script."
#: doc/classes/NavigationPolygon.xml
msgid ""
"Removes an outline created in the editor or by script. You have to call "
"[method make_polygons_from_outlines] for the polygons to update."
msgstr ""
+"Enlève un aperçu créé dans l'éditeur ou par un script. Vous devez appeler ["
+"method make_polygons_from_outlines] pour mettre à jour les polygones."
#: doc/classes/NavigationPolygon.xml
msgid ""
"Changes an outline created in the editor or by script. You have to call "
"[method make_polygons_from_outlines] for the polygons to update."
msgstr ""
+"Change un aperçu créé dans l'éditeur ou par un script. Vous devez appeler ["
+"method make_polygons_from_outlines] pour mettre à jour les polygones."
#: doc/classes/NavigationPolygonInstance.xml
-#, fuzzy
msgid "A region of the 2D navigation map."
-msgstr "Prépare le maillage de navigation."
+msgstr ""
#: doc/classes/NavigationPolygonInstance.xml
-#, fuzzy
msgid ""
"A region of the navigation map. It tells the [Navigation2DServer] what can "
"be navigated and what cannot, based on its [NavigationPolygon] resource.\n"
@@ -47801,24 +47989,24 @@ msgid ""
"The pathfinding cost of traveling distances inside this region can be "
"controlled with the [member travel_cost] multiplier."
msgstr ""
-"Une instance de [NavigationMesh]. Il signale au nœud [Navigation] ce qui "
-"peut être navigué et ce qui ne peut pas, basé sur la ressource "
-"[NavigationMesh].\n"
-"Par défaut ce nœud s'enregistrera à la carte de navigation du [World] par "
-"défaut. Si ce nœud est un enfant d'un nœud [Navigation], il s'inscrira à la "
-"carte de navigation du nœud de navigation.\n"
-"Deux régions peuvent être reliées l'une à l'autre si elles partagent un même "
-"bord. Vous pouvez définir la distance minimale entre deux sommets "
-"nécessaires pour connecter deux bords en utilisant [method NavigationServer."
-"map_set_edge_connection_margin]\n"
-"[b]Note :[/b] Le chevauchement de deux régions n'est pas suffisant pour "
-"relier deux régions. Ils doivent partager un même bord.\n"
-"Le coût d'entrée dans cette région d'une autre région peut être contrôlé "
+"Une région de la carte de navigation. Il indique au [Navigation2DServer] ce "
+"qui peut être navigué et ce qui ne peut pas l'être, en fonction de sa "
+"ressource [NavigationPolygon].\n"
+"Par défaut ce nœud s'enregistrera à la carte de navigation du [World2D] par "
+"défaut. Si ce nœud est un enfant d'un nœud [Navigation2D], il s'inscrirea à "
+"la carte de navigation du nœud de navigation.\n"
+"Deux régions peuvent être reliées l'une à l'autre si elles partagent un bord "
+"similaire. Vous pouvez définir la distance minimale entre deux sommets "
+"nécessaires pour connecter deux bords en utilisant [method Navigation2DServer"
+".map_set_edge_connection_margin]\n"
+"[b]Note :[/b] Embiquer deux régions ne suffit pas pour relier ces deux "
+"régions. Elles doivent partager un bord similaire.\n"
+"Le coût de cheminement de cette région vers une autre peut être contrôlé "
"avec la valeur [member enter_cost].\n"
-"[b]Note : [/b] Cette valeur n'est pas ajoutée au coût du chemin lorsque la "
+"[b]Note :[/b] Cette valeur n'est pas ajoutée au coût du chemin lorsque la "
"position de départ est déjà dans cette région.\n"
-"Le coût des distances de voyage dans cette région peut être contrôlé avec le "
-"multiplicateur [member travel_cost]."
+"Le coût de parcours des distances de cheminement à l'intérieur de cette "
+"région peut être contrôlé avec le multiplicateur [member travel_cost]."
#: doc/classes/NavigationPolygonInstance.xml
msgid ""
@@ -47827,11 +48015,14 @@ msgid ""
"identify the [NavigationPolygonInstance] closest to a point on the merged "
"navigation map."
msgstr ""
+"Retourne le [RID] de cette région sur le [Navigation2DServer]. Combiné avec ["
+"method Navigation2DServer.map_get_closest_point_propriétaire] peut permettre "
+"d'identifier le [NavigationPolygonInstance] le plus proche d'un point sur la "
+"carte de navigation fusionnée."
#: doc/classes/NavigationPolygonInstance.xml
-#, fuzzy
msgid "Determines if the [NavigationPolygonInstance] is enabled or disabled."
-msgstr "Détermine si le [NavigationMeshInstance] est actif ou non."
+msgstr "Détermine si la [NavigationPolygonInstance] est active ou non."
#: doc/classes/NavigationPolygonInstance.xml
msgid ""
@@ -47842,14 +48033,12 @@ msgid ""
msgstr ""
#: doc/classes/NavigationPolygonInstance.xml
-#, fuzzy
msgid "The [NavigationPolygon] resource to use."
-msgstr "La ressource [NavigationMesh] à utiliser."
+msgstr "La ressource [NavigationPolygon] à utiliser."
#: doc/classes/NavigationServer.xml
-#, fuzzy
msgid "Server interface for low-level 3D navigation access."
-msgstr "Interface de serveur pour l'accès audio de bas niveau."
+msgstr ""
#: doc/classes/NavigationServer.xml
#, fuzzy
@@ -47899,15 +48088,13 @@ msgstr ""
"sans soucis."
#: doc/classes/NavigationServer.xml
-#, fuzzy
msgid "Returns the map cell height."
-msgstr "Retourne la taille du tableau."
+msgstr ""
#: doc/classes/NavigationServer.xml
-#, fuzzy
msgid ""
"Returns the normal for the point returned by [method map_get_closest_point]."
-msgstr "Renvoie l'inverse de la racine carrée du paramètre."
+msgstr ""
#: doc/classes/NavigationServer.xml
msgid ""
@@ -47921,15 +48108,16 @@ msgid ""
"Returns the edge connection margin of the map. This distance is the minimum "
"vertex distance needed to connect two edges from different regions."
msgstr ""
+"Retourne la marge de raccordement du bord de la carte. Cette distance est la "
+"distance minimale nécessaire pour relier deux bords de différentes régions."
#: doc/classes/NavigationServer.xml
msgid "Returns the map's up direction."
msgstr "Retourne la direction haut de la carte."
#: doc/classes/NavigationServer.xml
-#, fuzzy
msgid "Set the map cell height used to weld the navigation mesh polygons."
-msgstr "Définit le polygone de navigation de la tuile."
+msgstr ""
#: doc/classes/NavigationServer.xml
msgid "Sets the map up direction."
@@ -47942,6 +48130,10 @@ msgid ""
"called in the main thread.\n"
"[b]Note:[/b] This function is not thread safe."
msgstr ""
+"Traite les agents d'évitement de collision.\n"
+"Le résultat de ce processus est nécessaire par le serveur de physique, de "
+"sorte que cela doit être appelé dans le fil d'exécution principal.\n"
+"[b]Note :[/b] Cette fonction n'est pas sûre entre plusieurs fils d'exécution."
#: doc/classes/NavigationServer.xml
msgid "Bakes the navigation mesh."
@@ -47952,6 +48144,9 @@ msgid ""
"Set the region's navigation layers. This allows selecting regions from a "
"path request (when using [method NavigationServer.map_get_path])."
msgstr ""
+"Définir les calques de navigation de la région. Cela permet de sélectionner "
+"les régions à partir d'une requête de chemin (en utilisant [method "
+"NavigationServer.map_get_path])."
#: doc/classes/NavigationServer.xml
msgid "Control activation of this server."
@@ -47986,16 +48181,16 @@ msgid ""
msgstr ""
#: doc/classes/NetworkedMultiplayerCustom.xml
-#, fuzzy
msgid ""
"Set the state of the connection. See [enum NetworkedMultiplayerPeer."
"ConnectionStatus]."
-msgstr "Retourne l'état actuel de la connexion. Voir [enum ConnexionStatus]."
+msgstr ""
+"Retourne l'état actuel de la connexion. Voir [enum NetworkedMultiplayerPeer."
+"ConnectionStatus]."
#: doc/classes/NetworkedMultiplayerCustom.xml
-#, fuzzy
msgid "Set the max packet size that this peer can handle."
-msgstr "Définit la texture de lumière à utiliser pour cette instance."
+msgstr ""
#: doc/classes/NetworkedMultiplayerCustom.xml
msgid ""
@@ -48074,7 +48269,7 @@ msgstr ""
"Créer un client qui se connecte au serveur à [code]address[/code] donnée via "
"le [code]port[/code]. L'adresse donnée doit être soit un nom de domaine "
"entièrement qualifié (ex.: [code]\"www.example.com\"[/code]) ou une adresse "
-"IP en format IPv4 ou IPv6 (par exemple [code]\"192.168.1.1\"[/code)]. Le "
+"IP en format IPv4 ou IPv6 (par exemple [code]\"192.168.1.1\"[/code]). Le "
"[code]port[/code] est le port que le serveur écoute. Les paramètres "
"[code]in_bandwidth[/code] et [code]out_bandwidth[/code] peuvent être "
"utilisés pour limiter la bande passante entrante et sortante, en octets par "
@@ -48087,9 +48282,9 @@ msgstr ""
"client a été créé, [constant ERR_ALREADY_IN_USE] si ce "
"NetworkedMultiplayerENet a déjà une connexion ouverte (dans quel cas vous "
"devez appeler [method close_connection] d'abord) ou [constant "
-"ERR_CANT_CREATE] si le client ne peut pas être créé. Si [code]client_port[/"
-"code] est spécifié, le client écoutera également le port donné ; ceci est "
-"utile pour certaines techniques NAT transversale."
+"ERR_CANT_CREATE] si le client ne peut pas être créé. Si "
+"[code]client_port[/code] est spécifié, le client écoutera également le port "
+"donné ; ceci est utile pour certaines techniques NAT transversale."
#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml
msgid ""
@@ -48145,8 +48340,8 @@ msgid ""
"Returns the channel of the next packet that will be retrieved via [method "
"PacketPeer.get_packet]."
msgstr ""
-"Retourne le canal du prochain paquet qui sera récupéré via [method "
-"PacketPeer.get_packet]"
+"Retourne le canal du prochain paquet qui sera récupéré via [method PacketPeer"
+".get_packet]."
#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml
#: modules/websocket/doc_classes/WebSocketServer.xml
@@ -48288,7 +48483,6 @@ msgstr ""
"create_client] est utilisé à la place."
#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml
-#, fuzzy
msgid ""
"Enable or disable certificate verification when [member use_dtls] is "
"[code]true[/code]."
@@ -48874,7 +49068,7 @@ msgstr ""
"dans un script). Si le nœud a des enfants, sa méthode [méthod enter_tree] "
"sera appelée d'abord, puis ensuite celle de ses enfants.\n"
"Correspond à la notification [constant NOTIFICATION_ENTER_TREE] dans [method "
-"Object._notification]"
+"Object._notification]."
#: doc/classes/Node.xml
msgid ""
@@ -49255,18 +49449,13 @@ msgid ""
"[method get_node] instead. To avoid using [method find_parent] too often, "
"consider caching the node reference into a variable."
msgstr ""
-"Trouve un parent de ce nœud dont le nom correspond à [code]mask[/code] "
-"suivant le même fonctionnement que pour [method String.match] (c'est-à-dire "
-"sensible à la casse, que [code]\"*\"[/code] correspond à un zéro au un seul "
-"caractère, et que [code]\"?\"[/code] correspond à n'importe quel unique "
-"caractère sauf [code]\".\"[/code]). Retourne [code]null[/code] si aucun "
-"[Node] correspondant n'est trouvée.\n"
+"Trouve le premier parent de ce nœud dont le nom correspond à "
+"[code]mask[/code] suivant le même fonctionnement que pour [method String."
+"match] (c'est-à-dire sensible à la casse, que [code]\"*\"[/code] correspond "
+"à un zéro au un seul caractère, et que [code]\"?\"[/code] correspond à "
+"n'importe quel unique caractère sauf [code]\".\"[/code]).\n"
"[b]Note :[/b] La correspondance ne se fait pas sur le chemin complet mais "
"juste les noms des nœuds.\n"
-"Si [code]owned[/code] est [code]true[/code], cette méthode ne trouve que des "
-"nœuds dont le propriétaire est ce nœud. Ceci est particulièrement important "
-"pour les scènes instanciée par un script, parce que ces scènes n'ont pas de "
-"propriétaire.\n"
"[b]Note :[/b] Comme cette méthode liste tous les parents d'un nœud, c'est le "
"moyen le plus lent d'obtenir une référence à un autre nœud. Dans la mesure "
"du possible, essayez plutôt d'utiliser [method get_node]. Pour éviter "
@@ -49420,7 +49609,7 @@ msgid ""
"[/codeblock]"
msgstr ""
"Récupère un nœud et une de ses ressources comme spécifié par le sous-nom de "
-"son [NodePath] (ex.: [code]Area2D/CollisionShape2D:shape[/code)]. Si "
+"son [NodePath] (ex.: [code]Area2D/CollisionShape2D:shape[/code]). Si "
"plusieurs ressources imbriquées sont spécifiées dans le [NodePath], seul le "
"dernier sera récupéré.\n"
"La valeur de retour est un tableau de 3 éléments : le premier élément est le "
@@ -49480,10 +49669,10 @@ msgid ""
"processing unless the frames per second is changed via [member Engine."
"iterations_per_second]."
msgstr ""
-"Retourne le temps écoulé (en secondes) depuis la dernière trame physique "
-"(voir [method _physics_process]). C'est toujours une valeur constante dans "
-"le traitement de la physique à moins que les trames par seconde ne soient "
-"changés via [member Engine.iterations_per_second]"
+"Retourne le temps écoulé (en secondes) depuis la dernière trame physique ("
+"voir [method _physics_process]). C'est toujours une valeur constante dans le "
+"traitement de la physique à moins que les trames par seconde ne soient "
+"changés via [member Engine.iterations_per_second]."
#: doc/classes/Node.xml
msgid ""
@@ -49601,12 +49790,12 @@ msgid ""
"See [member SceneTree.physics_interpolation] and [member ProjectSettings."
"physics/common/physics_interpolation]."
msgstr ""
-"Retourne [code]true[/code] si l'interpolation physique est activée (voir "
-"[member physics_interpolation_mode]) [b]et[/b] activée dans [SceneTree].\n"
+"Retourne [code]true[/code] si l'interpolation physique est activée (voir ["
+"member physics_interpolation_mode]) [b]et[/b] activée dans [SceneTree].\n"
"Il s'agit d'une version pratique de [method is_physics_interpolated] qui "
"vérifie également si l'interpolation physique est activée globalement.\n"
"Voir [member SceneTree.physics_interpolation] et [member ProjectSettings."
-"physics/common/physics_interpolation]"
+"physics/common/physics_interpolation]."
#: doc/classes/Node.xml
msgid ""
@@ -49700,7 +49889,7 @@ msgstr ""
"Imprime l'arborescence dans la console. Utilisé principalement à des fins de "
"débogage. Cette version affiche le chemin par rapport au nœud actuel, ce qui "
"est utile pour le copier/coller dans la fonction [method get_node].\n"
-"[ b]Exemple de sortie:[/b]\n"
+"[b]Exemple de sortie:[/b]\n"
"[codeblock]\n"
"TheGame\n"
"TheGame/Menu\n"
@@ -49729,7 +49918,7 @@ msgstr ""
"Cette version affiche une représentation plus graphique semblable à ce qui "
"est affiché dans l'inspecteur de scène. C'est utile pour inspecter les "
"grands arborescences.\n"
-"[ b]Exemple de sortie:[/b]\n"
+"[b]Exemple de sortie:[/b]\n"
"[codeblock]\n"
" â”–â•´TheGame\n"
" â” â•´Menu\n"
@@ -49851,7 +50040,7 @@ msgstr ""
"d'enfants que le nœud remplacé avait.\n"
"[b]Note :[/b] Le nœud remplacé n'est pas automatiquement libéré, donc vous "
"devez le garder dans une variable pour une utilisation ultérieure ou le "
-"libérer en utilisant [method Object.free]"
+"libérer en utilisant [method Object.free]."
#: doc/classes/Node.xml
msgid ""
@@ -49938,13 +50127,13 @@ msgid ""
"By default, methods are not exposed to networking (and RPCs). See also "
"[method rset] and [method rset_config] for properties."
msgstr ""
-"Change le mode RPC pour la [code]method[/code] donné pour le [code]mode[/"
-"code] spécifié. Voir [enum MultiplayerAPI.RPCMode]. Une alternative est "
-"d'annoter les méthodes et les propriétés avec les mots-clés correspondants "
-"([code]remote[/code], [code]master[/code], [code]puppet[/code], "
-"[code]remotesync[/code], [code]mastersync[/code], [code]puppetsync[/code)]. "
-"Par défaut, les méthodes ne sont pas exposées au réseaut (et aux RPC). Voir "
-"aussi [method rset] et [method rset_config] pour les propriétés."
+"Change le mode RPC pour la [code]method[/code] donné pour le "
+"[code]mode[/code] spécifié. Voir [enum MultiplayerAPI.RPCMode]. Une "
+"alternative est d'annoter les méthodes et les propriétés avec les mots-clés "
+"correspondants ([code]remote[/code], [code]master[/code], [code]puppet[/code]"
+", [code]remotesync[/code], [code]mastersync[/code], [code]puppetsync[/code])"
+". Par défaut, les méthodes ne sont pas exposées au réseaut (et aux RPC). "
+"Voir aussi [method rset] et [method rset_config] pour les propriétés."
#: doc/classes/Node.xml
msgid ""
@@ -49998,10 +50187,10 @@ msgstr ""
"Change le mode RPC pour la [code]property[/code] donnée au [code]mode[/code] "
"spécifié. Voir [enum MultiplayerAPI.RPCMode]. Une alternative est "
"l'annotation des méthodes et des propriétés avec les mots-clés "
-"correspondants ([code]remote[/code], [code]master[/code], [code]puppet[/"
-"code], [code]remotesync[/code], [code]mastersync[/code], [code]puppetsync[/"
-"code)]. Par défaut, les propriétés ne sont pas exposées au réseau (et au "
-"RPC). Voir aussi [method rpc] et [method rpc_config] pour les méthodes."
+"correspondants ([code]remote[/code], [code]master[/code], [code]puppet[/code]"
+", [code]remotesync[/code], [code]mastersync[/code], [code]puppetsync[/code])"
+". Par défaut, les propriétés ne sont pas exposées au réseau (et au RPC). "
+"Voir aussi [method rpc] et [method rpc_config] pour les méthodes."
#: doc/classes/Node.xml
msgid ""
@@ -50249,11 +50438,13 @@ msgid ""
msgstr ""
#: doc/classes/Node.xml
-#, fuzzy
msgid ""
"Notification received when the node is about to exit a [SceneTree].\n"
"This notification is emitted [i]after[/i] the related [signal tree_exiting]."
-msgstr "La notification reçue quand le nœud va quitter le [SceneTree]."
+msgstr ""
+"La notification reçue quand le nœud va quitter le [SceneTree].\n"
+"Cette notification est émise [i]après[/i] le signal [signal tree_exiting] "
+"correspondant."
#: doc/classes/Node.xml
msgid "Notification received when the node is moved in the parent."
@@ -50547,9 +50738,8 @@ msgid ""
msgstr ""
#: doc/classes/NodePath.xml
-#, fuzzy
msgid "Pre-parsed scene tree path."
-msgstr "Chemin de l'arborescence des scènes pré-analysé."
+msgstr "Le chemin pré-analysé de l'arborescence des scènes."
#: doc/classes/NodePath.xml
msgid ""
@@ -51580,19 +51770,16 @@ msgid "Sets an individual hole point position."
msgstr "Définit la position d'un trou simple."
#: doc/classes/OccluderShapePolygon.xml
-#, fuzzy
msgid "Sets an individual polygon point position."
-msgstr "Définit la position d'un polygone simple."
+msgstr "Définit la position d'un seul point d'un polygone."
#: doc/classes/OccluderShapePolygon.xml
-#, fuzzy
msgid "Allows changing the hole geometry from code."
-msgstr "Dessine une géométrie simple à partir du code."
+msgstr ""
#: doc/classes/OccluderShapePolygon.xml
-#, fuzzy
msgid "Allows changing the polygon geometry from code."
-msgstr "Dessine une géométrie simple à partir du code."
+msgstr ""
#: doc/classes/OccluderShapePolygon.xml
msgid ""
@@ -51862,18 +52049,16 @@ msgid "Returns the text of the item at index [code]idx[/code]."
msgstr "Retourne le texte de l'élément à l'index [code]idx[/code]."
#: doc/classes/OptionButton.xml
-#, fuzzy
msgid "Returns the tooltip of the item at index [code]idx[/code]."
-msgstr "Retourne le texte de l'élément à l'index [code]idx[/code]."
+msgstr "Retourne l'infobulle de l'élément à l'index [code]idx[/code]."
#: doc/classes/OptionButton.xml
-#, fuzzy
msgid ""
"Returns the ID of the selected item, or [code]-1[/code] if no item is "
"selected."
msgstr ""
-"Retourne la position de l’élément qui a actuellement le focus. Ou retourne "
-"[code]-1[/code] si aucun n'a le focus."
+"Retourne l'identifiant de l’élément sélectionné, ou [code]-1[/code] si aucun "
+"n'est sélectionné."
#: doc/classes/OptionButton.xml
msgid ""
@@ -51926,9 +52111,8 @@ msgid "Sets the text of the item at index [code]idx[/code]."
msgstr "Définit le texte pour l'élément à l'index [code]idx[/code]."
#: doc/classes/OptionButton.xml
-#, fuzzy
msgid "Sets the tooltip of the item at index [code]idx[/code]."
-msgstr "Définit le texte pour l'élément à l'index [code]idx[/code]."
+msgstr "Définit l'infobulle pour l'élément à l'index [code]idx[/code]."
#: doc/classes/OptionButton.xml
msgid ""
@@ -52051,9 +52235,8 @@ msgstr ""
"fils d'exécutions."
#: doc/classes/OS.xml
-#, fuzzy
msgid "Centers the window on the screen if in windowed mode."
-msgstr "Définit la position du nœud spécifié."
+msgstr ""
#: doc/classes/OS.xml
msgid ""
@@ -52212,18 +52395,16 @@ msgid ""
msgstr ""
#: doc/classes/OS.xml
-#, fuzzy
msgid "Returns the scancode of the given string (e.g. \"Escape\")."
-msgstr "Renvoie le reste de deux vecteurs."
+msgstr ""
#: doc/classes/OS.xml
msgid "Returns the total number of available audio drivers."
msgstr "Retourne le nombre total de périphériques audio."
#: doc/classes/OS.xml
-#, fuzzy
msgid "Returns the audio driver name for the given index."
-msgstr "Retourne le sommet à l’index donné."
+msgstr ""
#: doc/classes/OS.xml
msgid ""
@@ -52642,14 +52823,13 @@ msgid ""
msgstr ""
#: doc/classes/OS.xml
-#, fuzzy
msgid "Returns the epoch time of the operating system in milliseconds."
-msgstr "Retourne le temps epoch du système d'exploitation en millisecondes."
+msgstr ""
+"Retourne l'heure de l'époque du système d'exploitation en millisecondes."
#: doc/classes/OS.xml
-#, fuzzy
msgid "Returns the epoch time of the operating system in seconds."
-msgstr "Retourne le temps epoch du système d'exploitation en secondes."
+msgstr "Retourne l'heure de l'époque du système d'exploitation en secondes."
#: doc/classes/OS.xml
msgid ""
@@ -52766,9 +52946,8 @@ msgid ""
msgstr ""
#: doc/classes/OS.xml
-#, fuzzy
msgid "Returns the number of video drivers supported on the current platform."
-msgstr "Renvoie le nombre de points sur l'axe de mélange."
+msgstr ""
#: doc/classes/OS.xml
msgid ""
@@ -52816,9 +52995,8 @@ msgid ""
msgstr ""
#: doc/classes/OS.xml
-#, fuzzy
msgid "Returns [code]true[/code] if there is content on the clipboard."
-msgstr "Retourne [code]true[/code] si l'[AABB] est plate ou vide."
+msgstr "Retourne [code]true[/code] si le presse-papiers n'est pas vide."
#: doc/classes/OS.xml
msgid ""
@@ -52840,19 +53018,19 @@ msgid ""
msgstr ""
#: doc/classes/OS.xml
-#, fuzzy
msgid ""
"Returns [code]true[/code] if the device has a touchscreen or emulates one."
-msgstr "Retourne [code]true[/code] (vrai) si la chaîne de caractères est vide."
+msgstr ""
+"Retourne [code]true[/code] si le périphérique à un écran tactile ou en "
+"simule un."
#: doc/classes/OS.xml
-#, fuzzy
msgid ""
"Returns [code]true[/code] if the platform has a virtual keyboard, "
"[code]false[/code] otherwise."
msgstr ""
-"Retourne [code]true[/code] si la chaîne de caractères est vide, ou "
-"[code]false[/code] le cas échéant."
+"Retourne [code]true[/code] si la plateforme à un clavier virtuel (non "
+"physique), ou [code]false[/code] sinon."
#: doc/classes/OS.xml
msgid "Hides the virtual keyboard if it is shown, does nothing otherwise."
@@ -52887,11 +53065,10 @@ msgid ""
msgstr ""
#: doc/classes/OS.xml
-#, fuzzy
msgid ""
"Returns [code]true[/code] if the input scancode corresponds to a Unicode "
"character."
-msgstr "Retourne [code]true[/code] si l'[AABB] chevauche une autre."
+msgstr ""
#: doc/classes/OS.xml
msgid ""
@@ -53196,7 +53373,6 @@ msgstr ""
"Windows."
#: doc/classes/OS.xml
-#, fuzzy
msgid ""
"Requests the OS to open a resource with the most appropriate program. For "
"example:\n"
@@ -53223,12 +53399,12 @@ msgstr ""
"d'accueil de Godot dans le navigateur web par défaut.\n"
"- [code]OS.shell_open(\"mailto:example@example.com\")[/code] ouvrira le "
"client mail par défaut avec le champs destinataire définit à "
-"[code]example@example.com[/code]. Voir [url=https://blog.escapecreative.com/"
-"customizing-mailto-links/]Personnaliser les liens [code]mailto:[/code][/url] "
-"pour la liste des champs qui peuvent être ajoutés.\n"
+"[code]example@example.com[/code]. Voir [url=https://datatracker.ietf.org/doc/"
+"html/rfc2368]RFC 2368 - The [code]mailto[/code] URL scheme[/url] pour la "
+"liste des champs qui peuvent être ajoutés.\n"
"Utilisez [method ProjectSettings.globalize_path] pour convertir un chemin "
-"[code]res://[/code] ou [code]user://[/code] en chemin système pour utiliser "
-"avec cette méthode.\n"
+"[code]res://[/code] ou [code]user://[/code] en chemin système qui peut être "
+"utilisé avec cette méthode.\n"
"[b]Note :[/b] Cette méthode est implémentée sous Android, iOS, HTML5, Linux, "
"macOS et Windows."
@@ -53272,12 +53448,12 @@ msgid ""
msgstr ""
#: doc/classes/OS.xml
-#, fuzzy
msgid ""
"If [code]true[/code], the engine tries to keep the screen on while the game "
"is running. Useful on mobile."
msgstr ""
-"Si [code]true[/code], le mouvement linéaire à travers l’axe Z est limité."
+"Si [code]true[/code], Le moteur tente de garder l'écran allumé quand le jeu "
+"est lancé. Utile sur les mobiles."
#: doc/classes/OS.xml
msgid ""
@@ -54335,9 +54511,8 @@ msgid ""
msgstr ""
#: doc/classes/Particles.xml
-#, fuzzy
msgid "Maximum number of draw passes supported."
-msgstr "Nombre maximal de passes de tirage prises en charge."
+msgstr "Le nombre maximal de passes de dessin supporté."
#: doc/classes/Particles2D.xml
msgid "GPU-based 2D particle emitter."
@@ -55015,11 +55190,10 @@ msgstr ""
"dans les versions finales."
#: doc/classes/Performance.xml
-#, fuzzy
msgid "Available static memory. Not available in release builds."
msgstr ""
"La mémoire statique disponible. N'est pas utilisable dans les versions "
-"finales."
+"exportés sans le mode débogage."
#: doc/classes/Performance.xml
msgid "Available dynamic memory. Not available in release builds."
@@ -55852,9 +56026,8 @@ msgid ""
msgstr ""
#: doc/classes/Physics2DServer.xml
-#, fuzzy
msgid "Returns the value of a damped spring joint parameter."
-msgstr "Renvoie la valeur opposée du paramètre."
+msgstr ""
#: doc/classes/Physics2DServer.xml
#, fuzzy
@@ -55862,8 +56035,8 @@ msgid ""
"Sets a damped spring joint parameter. See [enum DampedStringParam] for a "
"list of available parameters."
msgstr ""
-"Définit la valeur d’un paramètre de zone. Voir [enum AreaParameter] pour une "
-"liste de paramètres disponibles."
+"Définit la valeur d’un paramètre de zone. Voir [enum DampedStringParam] pour "
+"une liste de paramètres disponibles."
#: doc/classes/Physics2DServer.xml
msgid ""
@@ -56831,18 +57004,16 @@ msgid "Creates a [SliderJoint]."
msgstr "Crée un [SliderJoint]."
#: doc/classes/PhysicsServer.xml
-#, fuzzy
msgid "Gets the priority value of the Joint."
-msgstr "Renvoie la valeur opposée du paramètre."
+msgstr ""
#: doc/classes/PhysicsServer.xml
msgid "Returns the type of the Joint."
msgstr "Retourne le type de Joint."
#: doc/classes/PhysicsServer.xml
-#, fuzzy
msgid "Sets the priority value of the Joint."
-msgstr "Renvoie la valeur opposée du paramètre."
+msgstr "Définit la priorité de la valeur du Joint."
#: doc/classes/PhysicsServer.xml
msgid ""
@@ -57123,20 +57294,17 @@ msgid ""
msgstr ""
#: doc/classes/PhysicsServer.xml
-#, fuzzy
msgid "If set, linear motion is possible within the given limits."
msgstr ""
-"Si [code]set[/code] il y a un mouvement linéaire possible dans les limites "
-"données."
+"Si définit, le mouvement linéaire est possible dans les limites données."
#: doc/classes/PhysicsServer.xml
msgid "If set, rotational motion is possible."
msgstr "Si définit, la rotation est possible."
#: doc/classes/PhysicsServer.xml
-#, fuzzy
msgid "If set, there is a rotational motor across these axes."
-msgstr "La vitesse de toutes les rotations à travers l’axe X."
+msgstr ""
#: doc/classes/PhysicsServer.xml
msgid ""
@@ -57197,14 +57365,12 @@ msgid "Sets the [Shape] that will be used for collision/intersection queries."
msgstr ""
#: doc/classes/PhysicsShapeQueryParameters.xml
-#, fuzzy
msgid "If [code]true[/code], the query will take [Area]s into account."
-msgstr "Si [code]true[/code], la texture sera centrée."
+msgstr "Si [code]true[/code], le requête prendra les [Area] en compte."
#: doc/classes/PhysicsShapeQueryParameters.xml
-#, fuzzy
msgid "If [code]true[/code], the query will take [PhysicsBody]s into account."
-msgstr "Si [code]true[/code], la texture sera centrée."
+msgstr "Si [code]true[/code], le requête prendra les [PhysicsBody] en compte."
#: doc/classes/PinJoint.xml
#, fuzzy
@@ -57230,13 +57396,10 @@ msgid ""
msgstr ""
#: doc/classes/PinJoint.xml
-#, fuzzy
msgid ""
"If above 0, this value is the maximum value for an impulse that this Joint "
"produces."
msgstr ""
-"Retourne quand la mot clé [code]keyword[/code] spécifié a une couleur de "
-"défini ou non."
#: doc/classes/PinJoint2D.xml
#, fuzzy
@@ -57275,11 +57438,8 @@ msgid ""
msgstr ""
#: doc/classes/Plane.xml
-#, fuzzy
msgid "Creates a plane from the three points, given in clockwise order."
-msgstr ""
-"Crée un plan à partir des trois points, donné dans le sens des aiguilles "
-"d’une montre."
+msgstr "Crée un plan à partir de trois points, spécifiés dans le sens horaire."
#: doc/classes/Plane.xml
msgid "Creates a plane from the normal and the plane's distance to the origin."
@@ -57507,9 +57667,8 @@ msgid "Returns the path to the node associated with the specified bone."
msgstr "Retourne le chemin d’accès au nœud associé à l’os spécifié."
#: doc/classes/Polygon2D.xml
-#, fuzzy
msgid "Returns the height values of the specified bone."
-msgstr "Retourne la hauteur de l'os spécifié."
+msgstr "Retourne les valeurs de hauteur de l'os spécifié."
#: doc/classes/Polygon2D.xml
msgid "Sets the path to the node associated with the specified bone."
@@ -57780,9 +57939,8 @@ msgstr "Change l'octet à la position donnée."
#: doc/classes/PoolIntArray.xml doc/classes/PoolRealArray.xml
#: doc/classes/PoolStringArray.xml doc/classes/PoolVector2Array.xml
#: doc/classes/PoolVector3Array.xml
-#, fuzzy
msgid "Sorts the elements of the array in ascending order."
-msgstr "Retire l' élément du tableau à l'index donné."
+msgstr "Tris les éléments du tableau dans l'ordre croissant."
#: doc/classes/PoolByteArray.xml
msgid ""
@@ -57794,7 +57952,6 @@ msgstr ""
"nouveau [PoolByteArray]. Chaque index négatif partira de la fin du tableau."
#: doc/classes/PoolColorArray.xml
-#, fuzzy
msgid "A pooled array of [Color]s."
msgstr "Un tableau compacté de [Color]."
@@ -57959,9 +58116,8 @@ msgid "Changes the int at the given index."
msgstr "Modifie le [int] à l’index donné."
#: doc/classes/PoolRealArray.xml
-#, fuzzy
msgid "A pooled array of real numbers ([float])."
-msgstr "Un tableau compacté de flottants ([float])."
+msgstr "Un tableau compacté de nombres réels (des flottants, [float])."
#: doc/classes/PoolRealArray.xml
msgid ""
@@ -58040,7 +58196,6 @@ msgid "Changes the float at the given index."
msgstr "Change la flottant à la position donnée."
#: doc/classes/PoolStringArray.xml
-#, fuzzy
msgid "A pooled array of [String]s."
msgstr "Un tableau compacté de [String]."
@@ -58119,7 +58274,6 @@ msgid "Changes the [String] at the given index."
msgstr "Change la [String] à la position donnée."
#: doc/classes/PoolVector2Array.xml
-#, fuzzy
msgid "A pooled array of [Vector2]s."
msgstr "Un tableau compacté de [Vector2]."
@@ -58201,7 +58355,6 @@ msgid "A pooled array of [Vector3]."
msgstr "Un tableau compacté de [Vector3]."
#: doc/classes/PoolVector3Array.xml
-#, fuzzy
msgid ""
"An array specifically designed to hold [Vector3]. Optimized for memory "
"usage, does not fragment the memory.\n"
@@ -58364,9 +58517,8 @@ msgstr ""
"[WindowDialog]."
#: doc/classes/PopupDialog.xml
-#, fuzzy
msgid "Sets a custom [StyleBox] for the panel of the [PopupDialog]."
-msgstr "[StyleBox] par défaut pour le [Button]."
+msgstr ""
#: doc/classes/PopupMenu.xml
msgid "PopupMenu displays a list of options."
@@ -58596,7 +58748,6 @@ msgid ""
msgstr ""
#: doc/classes/PopupMenu.xml
-#, fuzzy
msgid ""
"Returns the tooltip associated with the specified index [code]idx[/code]."
msgstr "Retourne l'infobulle associée avec l'index [code]idx[/code] spécifié."
@@ -58659,9 +58810,8 @@ msgid ""
msgstr ""
#: doc/classes/PopupMenu.xml
-#, fuzzy
msgid "Sets the currently focused item as the given [code]index[/code]."
-msgstr "Retourne la position du point à l'index [code]point[/code]."
+msgstr ""
#: doc/classes/PopupMenu.xml
msgid "Hides the [PopupMenu] when the window loses focus."
@@ -58751,11 +58901,10 @@ msgstr ""
"spécifié."
#: doc/classes/PopupMenu.xml
-#, fuzzy
msgid ""
"Toggles the check state of the item of the specified index [code]idx[/code]."
msgstr ""
-"Active l'état de contrôle de l'élément de l'index spécifié [code]idx[/code]."
+"Bascule l'état de contrôle de l'élément de l'index [code]idx[/code] spécifié."
#: doc/classes/PopupMenu.xml
msgid ""
@@ -59169,9 +59318,8 @@ msgid ""
msgstr ""
#: doc/classes/ProceduralSky.xml
-#, fuzzy
msgid "Amount of energy contribution from the sun."
-msgstr "Montant de la contribution énergétique du ciel."
+msgstr "La quantité de contribution énergétique du ciel."
#: doc/classes/ProceduralSky.xml
msgid "The sun's height using polar coordinates."
@@ -59423,6 +59571,16 @@ msgid ""
"specify the offset in bytes to the start of the resource pack. This is only "
"supported for .pck files."
msgstr ""
+"Charge le contenu du fichier .pck ou .zip spécifié par [code]pack[/code] "
+"dans le système de fichiers de ressources ([code]res://[/code]). Retourne "
+"[code]true[/code] en cas de succès.\n"
+"[b]Note :[/b] Si un fichier de [code]pack[/code] partage le même chemin "
+"qu'un fichier déjà dans le système de fichiers de ressources, toute "
+"tentative de charger ce fichier utilisera le fichier de [code]pack[/code] "
+"sauf si [code]replace_files[/code] est défini à [code]false[/code].\n"
+"[b]Note :[/b] Le paramètre optionnel [code]offset[/code] peut être utilisé "
+"pour spécifier le décalage en octets au début du pack de ressources. Ceci "
+"n'est pris en charge que pour les fichiers .pck."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -59430,18 +59588,25 @@ msgid ""
"to the absolute, native OS [code]path[/code]. See also [method "
"globalize_path]."
msgstr ""
+"Retourne le chemin localisé (démarrant par [code]res://[/code]) "
+"correspondant au chemin [code]path[/code] absolu et natif du système "
+"d'exploitation. Voir aussi [method globalize_path]."
#: doc/classes/ProjectSettings.xml
msgid ""
"Returns [code]true[/code] if the specified property exists and its initial "
"value differs from the current value."
msgstr ""
+"Retourne [code]true[/code] si la propriété spécifiée existe et sa valeur "
+"initiale diffère de la valeur actuelle."
#: doc/classes/ProjectSettings.xml
msgid ""
"Returns the specified property's initial value. Returns [code]null[/code] if "
"the property does not exist."
msgstr ""
+"Retourne la valeur initiale de la propriété spécifiée. Retourne "
+"[code]null[/code] si la propriété n'existe pas."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -59451,6 +59616,12 @@ msgid ""
"want to change project settings in exported projects, use [method "
"save_custom] to save [code]override.cfg[/code] file."
msgstr ""
+"Enregistre la configuration du fichier [code]project.godot[/code].\n"
+"[b]Note :[/b] Cette méthode est destinée à être utilisée par les greffons de "
+"l'éditeur, puisque [ProjectSettings] ne peut pas être modifié puis chargé "
+"directement dans une application lancée. Si vous voulez modifier les "
+"paramètres de projet depuis un projet exporté, utilisez [method save_custom] "
+"pour enregistrer le fichier [code]override.cfg[/code]."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -59460,18 +59631,28 @@ msgid ""
"code] file, which is also text, but can be used in exported projects unlike "
"other formats."
msgstr ""
+"Enregistre la configuration vers un fichier personnalisé. L'extension de "
+"fichier doit être [code].godot[/code] (pour enregistrer dans le format "
+"[ConfigFile] au format texte) ou [code].binary[/code] (pour enregistrer au "
+"format binaire). Vous pouvez également enregistrer le fichier [code]override."
+"cfg[/code], qui est également au format texte, mais peut être utilisé dans "
+"des projets exportés contrairement aux autres formats."
#: doc/classes/ProjectSettings.xml
msgid ""
"Sets the specified property's initial value. This is the value the property "
"reverts to."
msgstr ""
+"Définit la valeur initiale de la propriété spécifiée. C'est cette valeur qui "
+"sera rétablie pour cette propriété."
#: doc/classes/ProjectSettings.xml
msgid ""
"Sets the order of a configuration value (influences when saved to the config "
"file)."
msgstr ""
+"Définit l'ordre d'une valeur de configuration (qui a une influence quand "
+"sauvegardée dans le fichier de configuration)."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -59483,6 +59664,14 @@ msgid ""
"This can also be used to erase custom project settings. To do this change "
"the setting value to [code]null[/code]."
msgstr ""
+"Définit la valeur d'un réglage.\n"
+"[b]Exemple :[/b]\n"
+"[codeblock]\n"
+"ProjectSettings.set_setting(\"application/config/name\", \"Example\")\n"
+"/[codeblock]\n"
+"Cela peut également être utilisé pour effacer les paramètres de projet "
+"personnalisés. Pour ce faire, utilisez la valeur [code]null[/code] pour le "
+"réglage."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -59507,6 +59696,9 @@ msgid ""
"(preserving the aspect ratio) when the engine starts. If [code]false[/code], "
"the engine will leave it at the default pixel size."
msgstr ""
+"Si [code]true[/code], étire l'image au lancement du jeu suivant la taille de "
+"la fenêtre (et préserve le ratio). Si [code]false[/code], l'image sera "
+"affichée par défaut suivant sa taille en pixels."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -59515,6 +59707,10 @@ msgid ""
"[b]Note:[/b] Only effective if [member application/boot_splash/show_image] "
"is [code]true[/code]."
msgstr ""
+"Le chemin vers une image utilisée au lancement du jeu. Si vide, l'image avec "
+"le logo de Godot sera affichée à la place.\n"
+"[b]Note :[/b] Ne fonctionne que si [member application/boot_splash/"
+"show_image] est [code]true[/code]."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -59523,6 +59719,10 @@ msgid ""
"displays the plain color specified in [member application/boot_splash/"
"bg_color]."
msgstr ""
+"Si [code]true[/code], affiche l'image spécifiée dans [member application/"
+"boot_splash/image] lorsque le moteur démarre. Si [code]false[/code], affiche "
+"seulement la couleur spécifiée dans [member application/boot_splash/"
+"bg_color]."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -59530,6 +59730,10 @@ msgid ""
"(recommended for high-resolution artwork). If [code]false[/code], uses "
"nearest-neighbor interpolation (recommended for pixel art)."
msgstr ""
+"Si [code]true[/code], applique le filtrage linéaire pour l'étirement de "
+"l'image (recommandé pour les images à haute résolution.) Si "
+"[code]false[/code], utilise l'interpolation la plus proche (recommandée pour "
+"le pixel-art)."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -59543,24 +59747,41 @@ msgid ""
"The [member application/config/use_custom_user_dir] setting must be enabled "
"for this to take effect."
msgstr ""
+"Ce dossier utilisateur est utilisé pour stocker des données persistantes (le "
+"système de fichiers [code]user://[/code]). Si laissé vide, "
+"[code]user://[/code] va pointer vers un dossier spécifique au projet suivant "
+"la configuration de Godot (voir [method OS.get_user_data_dir]). Si un nom de "
+"dossier personnalisé est défini, ce nom sera utilisé à la place, puis ajouté "
+"au dossier de données utilisateur spécifique au système (le même dossier "
+"parent que celui configuration Godot documenté dans [method OS."
+"get_user_data_dir]).\n"
+"Le paramètre [member application/config/use_custom_user_dir] doit être actif "
+"pour que cela fonctionne."
#: doc/classes/ProjectSettings.xml
msgid ""
"The project's description, displayed as a tooltip in the Project Manager "
"when hovering the project."
msgstr ""
+"La description du projet, affichée en tant qu'infobulle dans le Gestionnaire "
+"de projet quand le projet est survolé."
#: doc/classes/ProjectSettings.xml
msgid ""
"Icon used for the project, set when project loads. Exporters will also use "
"this icon when possible."
msgstr ""
+"L'icône utilisée pour le projet, défini au chargement du projet. Les "
+"exportateurs utiliseront également cette icône si possible."
#: doc/classes/ProjectSettings.xml
msgid ""
"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 OS.set_native_icon]."
msgstr ""
+"L'icône définit dans le format [code].icns[/code] utilisé sur macOS pour "
+"définir l'icône du jeu. Ceci est fait automatiquement au lancement en "
+"appelant [method OS.set_native_icon]."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -59609,12 +59830,28 @@ msgid ""
"default can impact compatibility with some external tools or plugins which "
"expect the default [code].import[/code] folder."
msgstr ""
+"Si [code]true[/code], le projet utilisera un dossier caché ([code]."
+"import[/code]) pour stocker des données spécifiques au projet (métadonnées, "
+"cache des shaders, etc.)\n"
+"Si [code]false[/code], un dossier non caché ([code]import[/code]) sera "
+"utilisé à la place.\n"
+"[b]Note :[/b] Vous devez redémarrer l'application après avoir modifié ce "
+"réglage.\n"
+"[b]Note :[/b] Changer cette valeur peut aider sur les plateformes ou avec "
+"des outils tiers où les modèles de dossier cachés ne sont pas autorisés. Il "
+"suffit de modifier ce paramètre si vous savez que votre environnement "
+"l'exige, car le changer par défaut peut impacter la compatibilité avec "
+"certains outils ou greffons externes qui s'attendent à ce que le dossier par "
+"défaut soit [code].import[/code]."
#: doc/classes/ProjectSettings.xml
msgid ""
"Icon set in [code].ico[/code] format used on Windows to set the game's icon. "
"This is done automatically on start by calling [method OS.set_native_icon]."
msgstr ""
+"L'icône définit dans le format [code].ico[/code] utilisé sur Windows pour "
+"définir l'icône du jeu. Ceci est fait automatiquement au lancement en "
+"appelant [method OS.set_native_icon]."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -59844,11 +60081,10 @@ msgstr ""
"ne généreront pas d'avertissements."
#: doc/classes/ProjectSettings.xml
-#, fuzzy
msgid ""
"If [code]true[/code], enables warnings when the type of the default value "
"set to an exported variable is different than the specified export type."
-msgstr "Si [code]true[/code], le filtrage est activé."
+msgstr ""
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -60000,17 +60236,14 @@ msgstr ""
"qui n'est pas garantie d'exister dans la classe à la compilation."
#: doc/classes/ProjectSettings.xml
-#, fuzzy
msgid ""
"If [code]true[/code], enables warnings when a function parameter is unused."
msgstr ""
-"Si [code]true[/code], le mouvement linéaire à travers l’axe Z est limité."
#: doc/classes/ProjectSettings.xml
-#, fuzzy
msgid ""
"If [code]true[/code], enables warnings when a member variable is unused."
-msgstr "Si [code]true[/code], le filtrage est activé."
+msgstr ""
#: doc/classes/ProjectSettings.xml
msgid "If [code]true[/code], enables warnings when a signal is unused."
@@ -60100,42 +60333,57 @@ msgstr ""
#: doc/classes/ProjectSettings.xml
msgid "Maximum call stack in visual scripting, to avoid infinite recursion."
msgstr ""
+"Le nombre maximal de la pile d'appels dans le script visuel, pour éviter une "
+"récursion infinie."
#: doc/classes/ProjectSettings.xml
msgid ""
"Color of the contact points between collision shapes, visible when \"Visible "
"Collision Shapes\" is enabled in the Debug menu."
msgstr ""
+"La couleur des points de contact entre les formes de collision, visible "
+"lorsque \"Formes de collision visibles\" est activé dans le menu Débogage."
#: doc/classes/ProjectSettings.xml
msgid ""
"Sets whether 2D physics will display collision outlines in game when "
"\"Visible Collision Shapes\" is enabled in the Debug menu."
msgstr ""
+"Définit si la physique 2D affichera les contours de collision dans le jeu "
+"lorsque \"Formes de collision visibles\" est activé dans le menu Débogage."
#: doc/classes/ProjectSettings.xml
msgid ""
"Maximum number of contact points between collision shapes to display when "
"\"Visible Collision Shapes\" is enabled in the Debug menu."
msgstr ""
+"Le nombre maximal de points de contact entre les formes de collision à "
+"afficher lorsque \"Formes de collision visibles\" est activé dans le menu "
+"Débogage."
#: doc/classes/ProjectSettings.xml
msgid ""
"Color of the collision shapes, visible when \"Visible Collision Shapes\" is "
"enabled in the Debug menu."
msgstr ""
+"La couleur des formes de collision, visible lorsque \"Formes de collision "
+"visibles\" est activé dans le menu Débogage."
#: doc/classes/ProjectSettings.xml
msgid ""
"Color of the disabled navigation geometry, visible when \"Visible "
"Navigation\" is enabled in the Debug menu."
msgstr ""
+"La couleur de la géométrie de navigation désactivée, visible lorsque "
+"\"Navigation visible\" est activée dans le menu Débogage."
#: doc/classes/ProjectSettings.xml
msgid ""
"Color of the navigation geometry, visible when \"Visible Navigation\" is "
"enabled in the Debug menu."
msgstr ""
+"La couleur de la géométrie de navigation, visible lorsque \"Navigation "
+"visible\" est activée dans le menu Débogage."
#: doc/classes/ProjectSettings.xml
msgid "Custom image for the mouse cursor (limited to 256×256)."
@@ -60332,18 +60580,25 @@ msgid ""
"Load the previously opened VCS plugin when the editor starts up. This is set "
"to [code]true[/code] whenever a new VCS plugin is initialized."
msgstr ""
+"Charge le greffon VCS précédemment ouvert dès que l'éditeur démarre. Ceci "
+"est défini à [code]true[/code] chaque fois qu'un nouveau greffon VCS est "
+"initialisé."
#: doc/classes/ProjectSettings.xml
msgid ""
"Last loaded VCS plugin name. Used to autoload the plugin when the editor "
"starts up."
msgstr ""
+"Le dernier nom de greffon VCS chargé. Utilisé pour recharger le greffon dès "
+"que l'éditeur démarre."
#: doc/classes/ProjectSettings.xml
msgid ""
"Default value for [member ScrollContainer.scroll_deadzone], which will be "
"used for all [ScrollContainer]s unless overridden."
msgstr ""
+"La valeur par défaut pour [member ScrollContainer.scroll_deadzone], qui sera "
+"utilisé pour tous les [ScrollContainer] à moins d'être surchargé."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -60363,6 +60618,8 @@ msgid ""
"If [code]true[/code], swaps OK and Cancel buttons in dialogs on Windows and "
"UWP to follow interface conventions."
msgstr ""
+"Si [code]true[/code], échange des boutons OK et Annuler dans les dialogues "
+"sur Windows et UWP pour suivre les conventions d'interface."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -60375,6 +60632,8 @@ msgid ""
"Path to a custom [Font] resource to use as default for all GUI elements of "
"the project."
msgstr ""
+"Le chemin vers une [Font] personnalisée à utiliser par défaut pour tous les "
+"éléments graphiques du projet."
#: doc/classes/ProjectSettings.xml
msgid "If [code]true[/code], makes sure the theme used works with HiDPI."
@@ -60578,208 +60837,278 @@ msgid ""
"If [code]true[/code], sends mouse input events when tapping or swiping on "
"the touchscreen."
msgstr ""
+"Si [code]true[/code], envoie des événements d'entrée de la souris lorsque "
+"vous tapez ou glissez sur l'écran tactile."
#: doc/classes/ProjectSettings.xml
msgid ""
"If [code]true[/code], sends touch input events when clicking or dragging the "
"mouse."
msgstr ""
+"Si [code]true[/code], envoie des événements d'entrée tactile lorsque vous "
+"cliquez ou faites glisser la souris."
#: doc/classes/ProjectSettings.xml
msgid "Default delay for touch events. This only affects iOS devices."
msgstr ""
+"Un retard par défaut pour les événements tactiles. Cela n'affecte que les "
+"appareils iOS."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 1. If left empty, the layer will "
"display as \"Layer 1\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 1. Si vide, le "
+"calque s'affichera comme \"Calque 1\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 10. If left empty, the layer will "
"display as \"Layer 10\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 10. Si vide, la "
+"calque s'affichera comme \"Calque 10\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 11. If left empty, the layer will "
"display as \"Layer 11\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 11. Si vide, la "
+"calque s'affichera comme \"Calque 11\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 12. If left empty, the layer will "
"display as \"Layer 12\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 12. Si vide, la "
+"calque s'affichera comme \"Calque 12\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 13. If left empty, the layer will "
"display as \"Layer 13\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 13. Si vide, la "
+"calque s'affichera comme \"Calque 13\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 14. If left empty, the layer will "
"display as \"Layer 14\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 14. Si vide, la "
+"calque s'affichera comme \"Calque 14\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 15. If left empty, the layer will "
"display as \"Layer 15\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 15. Si vide, la "
+"calque s'affichera comme \"Calque 15\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 16. If left empty, the layer will "
"display as \"Layer 16\"."
msgstr ""
+"Nom facultatif pour la calque de navigation 2D numéro 16. Si vide, la calque "
+"s'affichera comme \"Calque 16\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 17. If left empty, the layer will "
"display as \"Layer 17\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 17. Si vide, la "
+"calque s'affichera comme \"Calque 17\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 18. If left empty, the layer will "
"display as \"Layer 18\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 18. Si vide, la "
+"calque s'affichera comme \"Calque 18\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 19. If left empty, the layer will "
"display as \"Layer 19\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 19. Si vide, la "
+"calque s'affichera comme \"Calque 19\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 2. If left empty, the layer will "
"display as \"Layer 2\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 2. Si vide, la "
+"calque affichera comme « calque 2 »."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 20. If left empty, the layer will "
"display as \"Layer 20\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 20. Si vide, la "
+"calque s'affichera comme \"Calque 20\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 21. If left empty, the layer will "
"display as \"Layer 21\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 21. Si vide, la "
+"calque s'affichera comme \"Calque 21\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 22. If left empty, the layer will "
"display as \"Layer 22\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 22. Si vide, la "
+"calque s'affichera comme \"Calque 22\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 23. If left empty, the layer will "
"display as \"Layer 23\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 23. Si vide, la "
+"calque s'affichera comme \"Calque 23\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 24. If left empty, the layer will "
"display as \"Layer 24\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 24. Si vide, la "
+"calque s'affichera comme \"Calque 24\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 25. If left empty, the layer will "
"display as \"Layer 25\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 25. Si vide, la "
+"calque s'affichera comme \"Calque 25\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 26. If left empty, the layer will "
"display as \"Layer 26\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 26. Si vide, la "
+"calque s'affichera comme \"Calque 26\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 27. If left empty, the layer will "
"display as \"Layer 27\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 27. Si vide, la "
+"calque s'affichera comme \"Calque 27\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 28. If left empty, the layer will "
"display as \"Layer 28\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 28. Si vide, la "
+"calque s'affichera comme \"Calque 28\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 29. If left empty, the layer will "
"display as \"Layer 29\"."
msgstr ""
+"Nom facultatif pour la calque de navigation 2D numéro 29. Si vide, la calque "
+"s'affichera comme \"Calque 29\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 3. If left empty, the layer will "
"display as \"Layer 3\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 3. Si vide, la "
+"calque s'affichera comme « calque 3 »."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 30. If left empty, the layer will "
"display as \"Layer 30\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 30. Si vide, la "
+"calque s'affichera comme \"Calque 30\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 31. If left empty, the layer will "
"display as \"Layer 31\"."
msgstr ""
+"Nom facultatif pour la calque de navigation 2D numéro 31. Si vide, la calque "
+"s'affichera comme \"Calque 31\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 32. If left empty, the layer will "
"display as \"Layer 32\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 32. Si vide, la "
+"calque s'affichera comme \"Calque 32\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 4. If left empty, the layer will "
"display as \"Layer 4\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 4. Si vide, la "
+"calque apparaîtra comme \"Calque 4\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 5. If left empty, the layer will "
"display as \"Layer 5\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 5. Si vide, le "
+"calque affichera comme \"Calque 5\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 6. If left empty, the layer will "
"display as \"Layer 6\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 6. Si vide, la "
+"calque apparaîtra comme \"Calque 6\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 7. If left empty, the layer will "
"display as \"Layer 7\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 7. Si vide, la "
+"calque s'affichera comme « calque 7 »."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 8. If left empty, the layer will "
"display as \"Layer 8\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 8. Si vide, la "
+"calque s'affichera comme \"Calque 8\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 2D navigation layer 9. If left empty, the layer will "
"display as \"Layer 9\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 2D numéro 9. Si vide, la "
+"calque s'affichera comme \"Calque 9\"."
#: doc/classes/ProjectSettings.xml
msgid "Optional name for the 2D physics layer 1."
@@ -60994,192 +61323,256 @@ msgid ""
"Optional name for the 3D navigation layer 1. If left empty, the layer will "
"display as \"Layer 1\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 1. Si vide, le "
+"calque s'affichera comme \"Calque 1\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 10. If left empty, the layer will "
"display as \"Layer 10\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 10. Si vide, la "
+"calque s'affichera comme \"Calque 10\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 11. If left empty, the layer will "
"display as \"Layer 11\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 11. Si vide, la "
+"calque s'affichera comme \"Calque 11\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 12. If left empty, the layer will "
"display as \"Layer 12\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 12. Si vide, la "
+"calque s'affichera comme \"Calque 12\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 13. If left empty, the layer will "
"display as \"Layer 13\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 13. Si vide, la "
+"calque s'affichera comme \"Calque 13\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 14. If left empty, the layer will "
"display as \"Layer 14\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 14. Si vide, la "
+"calque s'affichera comme \"Calque 14\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 15. If left empty, the layer will "
"display as \"Layer 15\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 15. Si vide, la "
+"calque s'affichera comme \"Calque 15\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 16. If left empty, the layer will "
"display as \"Layer 16\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 16. Si vide, la "
+"calque s'affichera comme \"Calque 16\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 17. If left empty, the layer will "
"display as \"Layer 17\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 17. Si vide, la "
+"calque s'affichera comme \"Calque 17\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 18. If left empty, the layer will "
"display as \"Layer 18\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 18. Si vide, la "
+"calque s'affichera comme \"Calque 18\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 19. If left empty, the layer will "
"display as \"Layer 19\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 19. Si vide, la "
+"calque s'affichera comme \"Calque 19\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 2. If left empty, the layer will "
"display as \"Layer 2\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 2. Si vide, la "
+"calque affichera comme « calque 2 »."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 20. If left empty, the layer will "
"display as \"Layer 20\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 20. Si vide, la "
+"calque s'affichera comme \"Calque 20\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 21. If left empty, the layer will "
"display as \"Layer 21\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 21. Si vide, la "
+"calque s'affichera comme \"Calque 21\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 22. If left empty, the layer will "
"display as \"Layer 22\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 22. Si vide, la "
+"calque s'affichera comme \"Calque 22\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 23. If left empty, the layer will "
"display as \"Layer 23\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 23. Si vide, la "
+"calque s'affichera comme \"Calque 23\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 24. If left empty, the layer will "
"display as \"Layer 24\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 24. Si vide, la "
+"calque s'affichera comme \"Calque 24\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 25. If left empty, the layer will "
"display as \"Layer 25\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 25. Si vide, la "
+"calque s'affichera comme \"Calque 25\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 26. If left empty, the layer will "
"display as \"Layer 26\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 26. Si vide, la "
+"calque s'affichera comme \"Calque 26\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 27. If left empty, the layer will "
"display as \"Layer 27\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 27. Si vide, la "
+"calque s'affichera comme \"Calque 27\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 28. If left empty, the layer will "
"display as \"Layer 28\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 28. Si vide, la "
+"calque s'affichera comme \"Calque 28\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 29. If left empty, the layer will "
"display as \"Layer 29\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 29. Si vide, la "
+"calque s'affichera comme \"Calque 29\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 3. If left empty, the layer will "
"display as \"Layer 3\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 3. Si vide, la "
+"calque s'affichera comme « calque 3 »."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 30. If left empty, the layer will "
"display as \"Layer 30\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 30. Si vide, la "
+"calque s'affichera comme \"Calque 30\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 31. If left empty, the layer will "
"display as \"Layer 31\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 31. Si vide, la "
+"calque s'affichera comme \"Calque 31\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 32. If left empty, the layer will "
"display as \"Layer 32\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 32. Si vide, la "
+"calque s'affichera comme \"Calque 32\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 4. If left empty, the layer will "
"display as \"Layer 4\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 4. Si vide, la "
+"calque apparaîtra comme \"Calque 4\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 5. If left empty, the layer will "
"display as \"Layer 5\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 5. Si vide, le "
+"calque affichera comme \"Calque 5\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 6. If left empty, the layer will "
"display as \"Layer 6\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 6. Si vide, la "
+"calque apparaîtra comme \"Calque 6\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 7. If left empty, the layer will "
"display as \"Layer 7\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 7. Si vide, la "
+"calque s'affichera comme « calque 7 »."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 8. If left empty, the layer will "
"display as \"Layer 8\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 8. Si vide, la "
+"calque s'affichera comme \"Calque 8\"."
#: doc/classes/ProjectSettings.xml
msgid ""
"Optional name for the 3D navigation layer 9. If left empty, the layer will "
"display as \"Layer 9\"."
msgstr ""
+"Le nom optionnel pour la calque de navigation 3D numéro 9. Si vide, la "
+"calque s'affichera comme \"Calque 9\"."
#: doc/classes/ProjectSettings.xml
msgid "Optional name for the 3D physics layer 1."
@@ -61394,6 +61787,8 @@ msgid ""
"The locale to fall back to if a translation isn't available in a given "
"language. If left empty, [code]en[/code] (English) will be used."
msgstr ""
+"Le langage de repli si une traduction n'est pas disponible dans une langue "
+"donnée. Si laissé vide, [code]en[/code] (anglais) sera utilisé."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -61412,6 +61807,9 @@ msgid ""
"Desktop override for [member logging/file_logging/enable_file_logging], as "
"log files are not readily accessible on mobile/Web platforms."
msgstr ""
+"Le surcharge du bureau pour [member logging/file_logging/enable_file_logging]"
+", car les fichiers de journaux ne sont pas facilement accessibles sur les "
+"plateformes mobiles et web."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -62212,6 +62610,12 @@ msgid ""
"[b]Note:[/b] This setting is only meaningful if [member rendering/gles3/"
"shaders/shader_compilation_mode] is [b]not[/b] [code]Synchronous[/code]."
msgstr ""
+"La valeur par défaut est une surcharge très conservatrice pour [member "
+"rendering/gles3/shaders/max_simultaneous_compiles].\n"
+"Selon les appareils spécifiques que vous ciblez, vous pouvez vouloir "
+"l'augmenter.\n"
+"[b]Note :[/b] Ce paramètre n'est utile que si [nomm rendering/gles3/shaders/"
+"shader_compilation_mode] n'est [b]pas[/b] à [code]Synchrone[/code]."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -62222,6 +62626,12 @@ msgid ""
"[b]Note:[/b] This setting is only meaningful if [member rendering/gles3/"
"shaders/shader_compilation_mode] is [b]not[/b] [code]Synchronous[/code]."
msgstr ""
+"La valeur par défaut est une surcharge très conservatrice pour [member "
+"rendering/gles3/shaders/max_simultaneous_compiles].\n"
+"Selon les navigateurs spécifiques que vous ciblez, vous pouvez vouloir "
+"l'augmenter.\n"
+"[b]Note :[/b] Ce paramètre n'est utile que si [nomm rendering/gles3/shaders/"
+"shader_compilation_mode] n'est [b]pas[/b] à [code]Synchrone[/code]."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -62231,6 +62641,11 @@ msgid ""
"[b]Note:[/b] This setting is only meaningful if [member rendering/gles3/"
"shaders/shader_compilation_mode] is set to [code]Asynchronous + Cache[/code]."
msgstr ""
+"La taille maximale, en mégaoctets, que le cache de ubershader peut "
+"atteindre. Au démarrage, les entrées les moins récemment utilisées seront "
+"supprimées jusqu'à ce que la taille totale soit dans les limites.\n"
+"[b]Note :[/b] Ce paramètre n'est utile que si [nomm rendering/gles3/shaders/"
+"shader_compilation_mode] est défini à [code]Synchrone + Cache[/code]."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -62240,6 +62655,11 @@ msgid ""
"[b]Note:[/b] This setting is only meaningful if [member rendering/gles3/"
"shaders/shader_compilation_mode] is set to [code]Asynchronous + Cache[/code]."
msgstr ""
+"Une surcharge pour [member rendering/gles3/shaders/shader_cache_size_mb], de "
+"sorte qu'une taille maximale plus petite peut être configurée pour les "
+"plates-formes mobiles, où l'espace de stockage est plus limité.\n"
+"[b]Note :[/b] Ce paramètre n'est utile que si [nomm rendering/gles3/shaders/"
+"shader_compilation_mode] est défini à [code]Synchrone + Cache[/code]."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -62251,6 +62671,13 @@ msgid ""
"[b]Note:[/b] This setting is only meaningful if [member rendering/gles3/"
"shaders/shader_compilation_mode] is set to [code]Asynchronous + Cache[/code]."
msgstr ""
+"Une surcharge pour [member rendering/gles3/shaders/shader_cache_size_mb], de "
+"sorte qu'une taille maximale plus petite peut être configurée pour les "
+"plateformes web, où l'espace de stockage est plus limité.\n"
+"[b]Note :[/b] Actuellement, le caisson d'ombrage n'est généralement pas "
+"disponible sur les plateformes Web.\n"
+"[b]Note :[/b] Ce paramètre n'est utile que si [nomm rendering/gles3/shaders/"
+"shader_compilation_mode] est défini à [code]Synchrone + Cache[/code]."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -62300,24 +62727,33 @@ msgid ""
"Max buffer size for blend shapes. Any blend shape bigger than this will not "
"work."
msgstr ""
+"La capacité maximale de la mémoire tampon pour les formes de mélange. Toute "
+"forme de mélange plus grande que cela ne fonctionnera pas."
#: doc/classes/ProjectSettings.xml
msgid ""
"Max buffer size for drawing polygons. Any polygon bigger than this will not "
"work."
msgstr ""
+"La capacity maximale de la mémoire tampon pour dessiner des polygones. Tout "
+"polygone plus grand que cela ne fonctionnera pas."
#: doc/classes/ProjectSettings.xml
msgid ""
"Max index buffer size for drawing polygons. Any polygon bigger than this "
"will not work."
msgstr ""
+"La capacity maximale de la mémoire tampon pour le dessin des polygones. Tout "
+"polygone plus grand que cela ne fonctionnera pas."
#: doc/classes/ProjectSettings.xml
msgid ""
"Max buffer size for drawing immediate objects (ImmediateGeometry nodes). "
"Nodes using more than this size will not work."
msgstr ""
+"La capacity maximale de la mémoire tampon pour le dessin d'objets immédiats ("
+"les nœuds ImmediateGeometry). Les nœuds utilisant plus que cette taille ne "
+"fonctionneront pas."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -62363,13 +62799,10 @@ msgid ""
msgstr ""
#: doc/classes/ProjectSettings.xml
-#, fuzzy
msgid ""
"If [code]true[/code], the texture importer will import lossless textures "
"using the PNG format. Otherwise, it will default to using WebP."
msgstr ""
-"Si [code]true[/code], la [SpinBox] sera modifiable. Sinon, elle sera en "
-"lecture seule."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -62379,6 +62812,12 @@ msgid ""
"Note that compression levels above 6 are very slow and offer very little "
"savings."
msgstr ""
+"Le niveau de compression par défaut pour le format WebP sans perte. Des "
+"niveaux plus élevés entraînent des fichiers plus petits mais une plus lente "
+"vitesse de compression. La vitesse de décompression ne dépend pas du niveau "
+"de compression. Les valeurs supportées vont de 0 à 9. Notez que les niveaux "
+"de compression supérieurs à 6 sont très lents et offrent une très petite "
+"réduction du poids du fichier."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -62387,6 +62826,11 @@ msgid ""
"attributes data. Recommended to be enabled if targeting mobile devices. "
"Requires manual reimport of meshes after toggling."
msgstr ""
+"À l'importation, les données des sommets de maillage seront divisées en deux "
+"flux dans une seule mémoire tampon pour les sommets, l'une pour les données "
+"de position et l'autre pour les données d'attributs. Recommandé si vous "
+"ciblez des appareils mobiles. Nécessite de réimporter manuellement toutes "
+"les meshes après l'activation."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -62398,6 +62842,14 @@ msgid ""
"A greater number of polygons can potentially cull more objects, however the "
"cost of culling calculations scales with the number of occluders."
msgstr ""
+"Détermine le nombre maximal d'occulteurs de polygones qui seront utilisés à "
+"tout moment.\n"
+"Même si vous pouvez avoir de nombreux occulteurs dans une même scène, à "
+"chaque trame, le système choisira parmi ces plus pertinents basés sur une "
+"métrique de l'espace à l'écran, afin de donner la meilleure performance "
+"globale.\n"
+"Un plus grand nombre de polygones peut potentiellement masquer plus "
+"d'objets, cependant les performances baissent avec le nombre d'occulteurs."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -62407,6 +62859,12 @@ msgid ""
"choose from these the most relevant based on a screen space metric, in order "
"to give the best overall performance."
msgstr ""
+"Détermine le nombre maximal d'occulteurs de sphère qui seront utilisés à "
+"tout moment.\n"
+"Même si vous pouvez avoir de nombreux occulteurs dans une même scène, à "
+"chaque trame, le système choisira parmi ces plus pertinents basés sur une "
+"métrique de l'espace à l'écran, afin de donner la meilleure performance "
+"globale."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -62417,6 +62875,12 @@ msgid ""
"It will flip named portal meshes (i.e. [code]-portal[/code]) on the initial "
"conversion to [Portal] nodes."
msgstr ""
+"La convention par défaut est de pointer vers l'extérieur (la face vers "
+"l'extérieur) de la salle source.\n"
+"Si vous construisez accidentellement votre niveau avec des portails faisant "
+"face de la mauvaise manière, ce réglage peut corriger le problème.\n"
+"Cela va inverser le maillages nommés de portail (c'est-à-dire finissant par "
+"[code]-portal[/code]) pour les nœuds [Portal]."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -62427,14 +62891,11 @@ msgstr ""
"[b]Note :[/b] Cela sera automatiquement désactivé dans les exports."
#: doc/classes/ProjectSettings.xml
-#, fuzzy
msgid ""
"If [code]true[/code], gameplay callbacks will be sent as [code]signals[/"
"code]. If [code]false[/code], they will be sent as [code]notifications[/"
"code]."
msgstr ""
-"Si [code]true[/code], l’état de la clé est pressé. Si [code]false[/code], "
-"l’état de la clé est libéré."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -62450,6 +62911,8 @@ msgid ""
"Show logs during PVS generation.\n"
"[b]Note:[/b] This will automatically be disabled in exports."
msgstr ""
+"Afficher les journaux pendant la génération du PVS.\n"
+"[b]Note :[/b] Cela sera automatiquement désactivé dans les exportations."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -62784,6 +63247,9 @@ msgid ""
"Lower-end override for [member rendering/quality/shadows/filter_mode] on "
"mobile devices, due to performance concerns or driver support."
msgstr ""
+"Surcharge pour les appareils bas de gamme pour [le rendu de membre/qualité/"
+"shadows/filter_mode] sur les appareils mobiles, en raison de performance "
+"plus faibles ou du support des pilotes."
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -62944,6 +63410,8 @@ msgid ""
"Objects can use this signal to restrict reading of settings only to "
"situations where a change has been made."
msgstr ""
+"Les objets peuvent utiliser ce signal pour restreindre leur lecture aux "
+"seuls paramètres modifiés."
#: doc/classes/PropertyTweener.xml
msgid "Interpolates an [Object]'s property over time."
@@ -62957,6 +63425,11 @@ msgid ""
"to create [PropertyTweener]. Any [PropertyTweener] created manually will not "
"function correctly."
msgstr ""
+"[PropertyTweener] est utilisé pour interpoler une propriété dans un objet. "
+"Voir [method SceneTreeTween.tween_property] pour plus d'informations.\n"
+"[b]Note :[/b] [method SceneTreeTween.tween_property] est le seul moyen "
+"correct de créer un [PropertyTweener]. Les [PropertyTweener] créés "
+"manuellement ne fonctionneront pas correctement."
#: doc/classes/PropertyTweener.xml
msgid ""
@@ -62968,6 +63441,13 @@ msgid ""
"as_relative() #the node will move by 100 pixels to the right\n"
"[/codeblock]"
msgstr ""
+"Quand appellé, la valeur finale sera utilisée comme valeur relative. Par "
+"exemple :\n"
+"[codeblock]\n"
+"var tween = get_tree().create_tween()\n"
+"tween.tween_property(self, \"position\", Vector2.RIGHT * 100, 1)."
+"as_relative() # Le nœud sera déplacé de 100 pixels sur la droite\n"
+"/[codeblock]"
#: doc/classes/PropertyTweener.xml
msgid ""
@@ -62979,6 +63459,14 @@ msgid ""
"(200, 100)\n"
"[/codeblock]"
msgstr ""
+"Définit une valeur initiale personnalisée pour le [PropertyTweener]. Par "
+"exemple :\n"
+"[codeblock]\n"
+"var tween = get_tree().create_tween()\n"
+"tween.tween_property(self, \"position\", Vector2(200, 100), 1).from(Vector2("
+"100, 100) # Ça déplacera le nœud de la position (100, 100) jusqu'à (200, 100)"
+"\n"
+"/[codeblock]"
#: doc/classes/PropertyTweener.xml
msgid ""
@@ -62993,6 +63481,16 @@ msgid ""
"from_current()\n"
"[/codeblock]"
msgstr ""
+"Fait que ce [PropertyTweener] utilisera la valeur de propriété actuelle "
+"(c'est-à-dire au moment de créer ce [PropertyTweener]) comme point de "
+"départ. Ceci est pareil que [method from] avec la valeur actuelle. Ces deux "
+"appels sont identiques :\n"
+"[codeblock]\n"
+"tween.tween_property(self, \"position\", Vector2(200, 100), 1).from(position)"
+"\n"
+"tween.tween_property(self, \"position\", Vector2(200, 100), 1).from_current()"
+"\n"
+"/[codeblock]"
#: doc/classes/PropertyTweener.xml
msgid ""
@@ -63003,9 +63501,8 @@ msgstr ""
"interpolation. Par défaut, il n'y a pas de délai."
#: doc/classes/ProximityGroup.xml
-#, fuzzy
msgid "General-purpose 3D proximity detection node."
-msgstr "Nœud de détection de proximité pour usage général."
+msgstr "Un nœud de détection de proximité 3D pour un usage général."
#: doc/classes/ProximityGroup.xml
msgid ""
@@ -63077,11 +63574,16 @@ msgid ""
"If the [member dispatch_mode] is set to [constant MODE_PROXY] (the default), "
"all calls are delegated to their respective parent [Node]."
msgstr ""
+"Appelle la méthode et les paramètres donnés à tous les [ProximityGroup] qui "
+"s'intersectent.\n"
+"Si le [member dispatch_mode] est [constant MODE_PROXY] (par défaut), tous "
+"les appels sont délégués à leur parent [Node] respectif."
#: doc/classes/ProximityGroup.xml
msgid ""
"Specifies which node gets contacted on a call of method [method broadcast]."
msgstr ""
+"Spécifie quel nœud est contacté sur un appel de méthode [method broadcast]."
#: doc/classes/ProximityGroup.xml
msgid ""
@@ -63091,6 +63593,11 @@ msgid ""
"proximity checks at the cost of performance, since more groups will be "
"created."
msgstr ""
+"La taille de l'espace en unités 3D. Cela définit également la quantité de "
+"coordonnées requises pour calculer si deux nœuds [ProximityGroup] sont en "
+"intersection ou non. Des valeurs plus petites de [member grid_radius] "
+"peuvent être utilisées pour des vérifications de proximité plus précises "
+"mais avec de moins bonnes performances, car plus de groupes seront créés."
#: doc/classes/ProximityGroup.xml
msgid ""
@@ -63117,13 +63624,15 @@ msgstr ""
#: doc/classes/ProximityGroup.xml
msgid "This [ProximityGroup]'s parent will be target of [method broadcast]."
-msgstr ""
+msgstr "Le parent de ce [ProximityGroup] sera la cible de [method broadcast]."
#: doc/classes/ProximityGroup.xml
msgid ""
"This [ProximityGroup] will emit the [signal broadcast] [i]signal[/i] when "
"calling the [method broadcast] [i]method[/i]."
msgstr ""
+"Ce [ProximityGroup] émettra le [i]signal[/i] [signal broadcast] lors de "
+"l'appel de la [i]méthode[/i] [method broadcast]."
#: doc/classes/QuadMesh.xml
msgid "Class representing a square mesh."
@@ -63186,9 +63695,8 @@ msgstr ""
"spécifié. L'axe doit être un vecteur normalisé."
#: doc/classes/Quat.xml
-#, fuzzy
msgid "Constructs a quaternion defined by the given values."
-msgstr "Construit une nouvelle chaîne de caractères à partir du [Plane] donné."
+msgstr ""
#: doc/classes/Quat.xml
msgid ""
@@ -63206,6 +63714,9 @@ msgid ""
"code], this vector, [code]b[/code], and [code]post_b[/code], by the given "
"amount [code]weight[/code]."
msgstr ""
+"Exécute une interpolation sphérique cubique entre les quaternions "
+"[code]pre_a[/code], ce vecteur, [code]b[/code], et [code]post_b[/code], par "
+"la quantité [code]weight[/code] spécifiée."
#: doc/classes/Quat.xml
msgid "Returns the dot product of two quaternions."
@@ -63218,6 +63729,10 @@ msgid ""
"quaternion. Returned vector contains the rotation angles in the format (X "
"angle, Y angle, Z angle)."
msgstr ""
+"Retourne les angles d'Euler (selon la convention YXZ : lors de la "
+"décomposition, d'abord Z, puis X, et enfin Y) correspondant à la rotation "
+"représentée par un quaternion d'unité. Le vecteur retourné contient les "
+"angles de rotation dans le format (angle X, angle Y, angle Z)."
#: doc/classes/Quat.xml
msgid "Returns the inverse of the quaternion."
@@ -63254,6 +63769,8 @@ msgid ""
"Sets the quaternion to a rotation which rotates around axis by the specified "
"angle, in radians. The axis must be a normalized vector."
msgstr ""
+"Définit le quaternion avec une rotation qui tourne autour de l'axe par "
+"l'angle spécifié, en radians. L'axe doit être un vecteur normalisé."
#: doc/classes/Quat.xml
msgid ""
@@ -63261,6 +63778,9 @@ msgid ""
"convention: when decomposing, first Z, then X, and Y last), given in the "
"vector format as (X angle, Y angle, Z angle)."
msgstr ""
+"Définit le quaternion avec une rotation spécifiée par les angles d'Euler ("
+"selon la convention YXZ : lors de la décomposition, d'abord Z, puis X, et "
+"enfin Y), donnée dans le format vectoriel comme (angle X, angle Y, angle Z)."
#: doc/classes/Quat.xml
msgid ""
@@ -63268,6 +63788,10 @@ msgid ""
"quaternion and [code]to[/code] by amount [code]weight[/code].\n"
"[b]Note:[/b] Both quaternions must be normalized."
msgstr ""
+"Retourne le résultat de l'interpolation linéaire sphérique entre ce "
+"quaternion et [code]to[/code] par la quantité [code]weight[/code] spécifiée."
+"\n"
+"[b]Note :[/b] Les deux quaternions doivent être normalisés."
#: doc/classes/Quat.xml
msgid ""
@@ -63275,6 +63799,9 @@ msgid ""
"quaternion and [code]to[/code] by amount [code]weight[/code], but without "
"checking if the rotation path is not bigger than 90 degrees."
msgstr ""
+"Retourne le résultat de l'interpolation linéaire sphérique entre ce "
+"quaternion et [code]to[/code] par la quantité [code]weight[/code] spécifiée, "
+"mais sans vérifier si la rotation n'est pas supérieure à 90 degrés."
#: doc/classes/Quat.xml
msgid "Returns a vector transformed (multiplied) by this quaternion."
@@ -63318,6 +63845,9 @@ msgid ""
"[Basis] matrix. If a vector is transformed by an identity quaternion, it "
"will not change."
msgstr ""
+"La quaternion d'identité, sans rotation. Équivalent à la matrice [Basis] "
+"d'identité. Si un vecteur est transformé par un quaternion d'identité, il ne "
+"changera pas."
#: doc/classes/RandomNumberGenerator.xml
msgid "A class for generating pseudo-random numbers."
@@ -63483,22 +64013,21 @@ msgstr ""
"avec une valeur personnalisée, utilisez plutôt [member seed]."
#: doc/classes/Range.xml
-#, fuzzy
msgid "Abstract base class for range-based controls."
-msgstr "Classe de base abstraite pour les contrôles basés sur la portée."
+msgstr "Une classe de base abstraite pour les contrôles basés sur la portée."
#: doc/classes/Range.xml
-#, fuzzy
msgid ""
"Range is a base class for [Control] nodes that change a floating-point "
"[member value] between a [member min_value] and [member max_value], using a "
"configured [member step] and [member page] size. See e.g. [ScrollBar] and "
"[Slider] for examples of higher level nodes using Range."
msgstr ""
-"Range est une classe de base des nœuds [Control] qui change une [code]value[/"
-"code] flottante entre le [code]minimum[/code] et le [code]maximum[/code], "
-"par étape [code]step[/code] et par [code]page[/code], par exemple un "
-"[ScrollBar]."
+"Range est une classe de base des nœuds [Control] qui change une "
+"[code]value[/code] flottante entre le [code]minimum[/code] et le "
+"[code]maximum[/code], par étape [code]step[/code] et par [code]page[/code], "
+"par exemple un [ScrollBar]. Voir [ScrollBar] et [Slider] pour des exemples "
+"de nœuds de haut niveau utilisant des Range."
#: doc/classes/Range.xml
msgid ""
@@ -63509,7 +64038,7 @@ msgstr ""
#: doc/classes/Range.xml
msgid "Stops the [Range] from sharing its member variables with any other."
-msgstr ""
+msgstr "Arrête le [Range] de partager ses variables membres avec les autres."
#: doc/classes/Range.xml
msgid ""
@@ -63530,6 +64059,9 @@ msgid ""
"If [code]true[/code], and [code]min_value[/code] is greater than 0, "
"[code]value[/code] will be represented exponentially rather than linearly."
msgstr ""
+"Si [code]true[/code], et [code]min_value[/code] est supérieur à 0, "
+"[code]value[/code] sera représenté de façon exponentielle plutôt que "
+"linéaire."
#: doc/classes/Range.xml
msgid ""
@@ -63553,6 +64085,9 @@ msgid ""
"multiplied by [code]page[/code] over the difference between [code]min_value[/"
"code] and [code]max_value[/code]."
msgstr ""
+"La taille de la page. Utilisé principalement pour [ScrollBar]. La longueur "
+"de la barre de défilement est multipliée par [code]page[/code] divisé par la "
+"différence entre [code]min_value[/code] et [code]max_value[/code]."
#: doc/classes/Range.xml
msgid "The value mapped between 0 and 1."
@@ -63657,12 +64192,17 @@ msgid ""
"[code]0[/code] if no object is intersecting the ray (i.e. [method "
"is_colliding] returns [code]false[/code])."
msgstr ""
+"Retourne l'identifiant de forme du premier objet que le rayon intersecte, ou "
+"[code]0[/code] si aucun objet n'intersecte le rayon (c'est-à-dire [method "
+"is_colliding] renvoie [code]false[/code])."
#: doc/classes/RayCast.xml
msgid ""
"Returns [code]true[/code] if the bit index passed is turned on.\n"
"[b]Note:[/b] Bit indices range from 0-19."
msgstr ""
+"Retourne [code]true[/code] si l'index de bit est activé.\n"
+"[b]Note :[/b] Les indices de bit vont de 0 à 19."
#: doc/classes/RayCast.xml doc/classes/RayCast2D.xml
msgid ""
@@ -63674,6 +64214,10 @@ msgid ""
"Returns the collision point at which the ray intersects the closest object.\n"
"[b]Note:[/b] This point is in the [b]global[/b] coordinate system."
msgstr ""
+"Retourne le point de collision où le rayon intersecte l'objet le plus proche."
+"\n"
+"[b]Note :[/b] Ce point se trouve dans le système de coordonnées "
+"[b]global[/b]."
#: doc/classes/RayCast.xml doc/classes/RayCast2D.xml
msgid ""
@@ -63704,21 +64248,24 @@ msgid ""
"Sets the bit index passed to the [code]value[/code] passed.\n"
"[b]Note:[/b] Bit indexes range from 0-19."
msgstr ""
+"Définit l'index de bit transmis à la [code]valeur[/code] passée.\n"
+"[b]Note :[/b] Les index de bit vont de 0-19."
#: doc/classes/RayCast.xml doc/classes/RayCast2D.xml
msgid ""
"The ray's destination point, relative to the RayCast's [code]position[/code]."
msgstr ""
+"Le point de destination du rayon, par rapport à la [code]position[/code] du "
+"RayCast."
#: doc/classes/RayCast.xml
-#, fuzzy
msgid "If [code]true[/code], collision with [Area]s will be reported."
-msgstr "Si [code]true[/code], les collisions seront signalées."
+msgstr "Si [code]true[/code], les collisions avec les [Area] seront signalées."
#: doc/classes/RayCast.xml
-#, fuzzy
msgid "If [code]true[/code], collision with [PhysicsBody]s will be reported."
-msgstr "Si [code]true[/code], les collisions seront signalées."
+msgstr ""
+"Si [code]true[/code], les collisions avec les [PhysicsBody] seront signalées."
#: doc/classes/RayCast.xml doc/classes/RayCast2D.xml
msgid ""
@@ -63751,11 +64298,12 @@ msgid "If [code]true[/code], collisions will be reported."
msgstr "Si [code]true[/code], les collisions seront signalées."
#: doc/classes/RayCast.xml
-#, fuzzy
msgid ""
"If [code]true[/code], collisions will be ignored for this RayCast's "
"immediate parent."
-msgstr "Si [code]true[/code], les collisions seront signalées."
+msgstr ""
+"Si [code]true[/code], les collisions seront ignorées avec le parent direct "
+"de ce RayCast."
#: doc/classes/RayCast2D.xml
msgid ""
@@ -63781,6 +64329,8 @@ msgid ""
"Sets or clears individual bits on the collision mask. This makes selecting "
"the areas scanned easier."
msgstr ""
+"Définit ou efface des bits individuels sur le masque de collision. Cela "
+"facilite le choix des aires scannées."
#: doc/classes/RayCast2D.xml
msgid "If [code]true[/code], collision with [Area2D]s will be reported."
@@ -63812,6 +64362,10 @@ msgid ""
"itself from whatever is touching its far endpoint. It's often useful for "
"characters."
msgstr ""
+"Une forme en rayon pour les collisions en 3D, qui peuvt être placée dans un "
+"[PhysicsBody] ou une [Area]. Un rayon n'est pas vraiment un corps de "
+"collision ; il tente plutôt de se séparer de ce qui touche son point "
+"d'extrémité lointain. Il est souvent utile pour les caractères."
#: doc/classes/RayShape.xml doc/classes/RayShape2D.xml
msgid "The ray's length."
@@ -63833,11 +64387,13 @@ msgid ""
"it tries to separate itself from whatever is touching its far endpoint. It's "
"often useful for characters."
msgstr ""
+"Une forme en rayon pour les collisions 2D. Un rayon n'est pas vraiment un "
+"corps de collision ; il tente plutôt de se séparer de ce qui touche son "
+"point d'extrémité lointain. Il est souvent utile pour les caractères."
#: doc/classes/Rect2.xml
-#, fuzzy
msgid "2D axis-aligned bounding box."
-msgstr "Boîte de délimitation alignée sur l'axe."
+msgstr "La boîte de délimitation 2D alignée sur les axes."
#: doc/classes/Rect2.xml
msgid ""
@@ -63865,6 +64421,9 @@ msgid ""
"top-left corner is the origin and [code]width[/code] and [code]height[/code] "
"are positive."
msgstr ""
+"Retourne un [Rect2] avec la même position et aire, modifié de sorte que le "
+"coin supérieur gauche est l'origine et [code]width[/code] et "
+"[code]height[/code] soient positifs."
#: doc/classes/Rect2.xml
msgid "Returns the intersection of this [Rect2] and b."
@@ -63886,11 +64445,19 @@ msgid ""
"var rect2 = rect.expand(Vector2(0, -1))\n"
"[/codeblock]"
msgstr ""
+"Retourne une copie de ce [Rect2] élargi pour inclure le point donné.\n"
+"[b]Exemple :[/b]\n"
+"[codeblock]\n"
+"# position (-3, 2), size (1, 1)\n"
+"var rect = Rect2(Vector2(-3, 2), Vector2(1, 1))\n"
+"# position (-3, -1), size (3, 4), contient donc à la fois `rect` et Vector2("
+"0, -1)\n"
+"var rect2 = rect.expand(Vector2(0, -1))\n"
+"/[codeblock]"
#: doc/classes/Rect2.xml
-#, fuzzy
msgid "Returns the area of the [Rect2]. See also [method has_no_area]."
-msgstr "Retourne la zone du [Rect2]."
+msgstr "Retourne l'aire du [Rect2]. Voir aussi [method has_no_area]."
#: doc/classes/Rect2.xml
msgid ""
@@ -63905,12 +64472,16 @@ msgid ""
"Returns a copy of the [Rect2] grown a given amount of units towards all the "
"sides."
msgstr ""
+"Retourne une copie du [Rect2] aggrandi par une quantité donnée d'unités vers "
+"tous les côtés."
#: doc/classes/Rect2.xml
msgid ""
"Returns a copy of the [Rect2] grown a given amount of units towards each "
"direction individually."
msgstr ""
+"Retourne une copie du [Rect2] aggrandi par une quantité donnée d'unités vers "
+"chaque direction individuellement."
#: doc/classes/Rect2.xml
msgid ""
@@ -63927,6 +64498,10 @@ msgid ""
"[b]Note:[/b] If the [Rect2] has a negative size and is not flat or empty, "
"[method has_no_area] will return [code]true[/code]."
msgstr ""
+"Retourne [code]true[/code] si le [Rect2] est plat ou vide, ou "
+"[code]false[/code] sinon. Voir aussi [method get_area].\n"
+"[b]Note :[/b] Si le [Rect2] a une taille négative et n'est pas plat ou vide, "
+"[method has_no_area] retournera [code]true[/code]."
#: doc/classes/Rect2.xml
msgid ""
@@ -63945,6 +64520,11 @@ msgid ""
"If [code]include_borders[/code] is [code]true[/code], they will also be "
"considered overlapping if their borders touch, even without intersection."
msgstr ""
+"Retourne [code]true[/code] si le [Rect2] se chevauche avec [code]b[/code] "
+"(c'est-à-dire qu'ils ont au moins un point en commun).\n"
+"Si [code]include_borders[/code] est [code]true[/code], ils seront également "
+"considérés comme se chevauchant si leurs bordures touchent, même sans "
+"intersection."
#: doc/classes/Rect2.xml
msgid ""
@@ -63952,6 +64532,9 @@ msgid ""
"approximately equal, by calling [code]is_equal_approx[/code] on each "
"component."
msgstr ""
+"Retourne [code]true[/code] si ce [Rect2] et [code]rect[/code] sont "
+"approximativement égaux, en appelant [code]is_equal_approx[/code] sur chaque "
+"composant."
#: doc/classes/Rect2.xml
msgid "Returns a larger [Rect2] that contains this [Rect2] and [code]b[/code]."
@@ -63968,12 +64551,16 @@ msgid ""
"Rectangle shape for 2D collisions. This shape is useful for modeling box-"
"like 2D objects."
msgstr ""
+"Une forme rectangulaire pour les collisions 2D. Cette forme est utile pour "
+"les objets 2D de type boîte."
#: doc/classes/RectangleShape2D.xml
msgid ""
"The rectangle's half extents. The width and height of this shape is twice "
"the half extents."
msgstr ""
+"La demi-taille du rectangle. La largeur et la hauteur de cette forme sont "
+"deux fois plus grandes."
#: doc/classes/Reference.xml
msgid "Base class for reference-counted objects."
@@ -64002,6 +64589,9 @@ msgid ""
"what you are doing.\n"
"Returns whether the initialization was successful."
msgstr ""
+"Initialise le compteur de référence interne. Utilisez ceci seulement si vous "
+"savez vraiment ce que vous faites.\n"
+"Retourne si l'initialisation a été réussie."
#: doc/classes/Reference.xml
msgid ""
@@ -64010,6 +64600,10 @@ msgid ""
"Returns [code]true[/code] if the increment was successful, [code]false[/"
"code] otherwise."
msgstr ""
+"Augmente le compteur de référence interne. Utilisez ceci seulement si vous "
+"savez vraiment ce que vous faites.\n"
+"Retourne [code]true[/code] si l'augmentation a réussi, [code]false[/code] "
+"sinon."
#: doc/classes/Reference.xml
msgid ""
@@ -64018,6 +64612,10 @@ msgid ""
"Returns [code]true[/code] if the decrement was successful, [code]false[/"
"code] otherwise."
msgstr ""
+"Diminue le compteur de référence interne. Utilisez ceci seulement si vous "
+"savez vraiment ce que vous faites.\n"
+"Retourne [code]true[/code] si la diminution a réussi, [code]false[/code] "
+"sinon."
#: doc/classes/ReferenceRect.xml
msgid "Reference frame for GUI."
@@ -64030,6 +64628,10 @@ msgid ""
"display a rectangle filled with a solid color, consider using [ColorRect] "
"instead."
msgstr ""
+"Une boîte rectangulaire qui n'affiche que la couleur [member border_color] "
+"sur ses bordures. [ReferenceRect] n'a pas de [Color] de remplissage. Si vous "
+"devez afficher un rectangle rempli avec une couleur, utilisez plutôt "
+"[ColorRect]."
#: doc/classes/ReferenceRect.xml
msgid "Sets the border [Color] of the [ReferenceRect]."
@@ -64040,19 +64642,24 @@ msgid ""
"Sets the border width of the [ReferenceRect]. The border grows both inwards "
"and outwards with respect to the rectangle box."
msgstr ""
+"Définit la largeur de la bordure du [ReferenceRect]. La bordure va à la fois "
+"vers l'intérieur et vers l'extérieur par rapport aux limites du rectangle."
#: doc/classes/ReferenceRect.xml
msgid ""
"If set to [code]true[/code], the [ReferenceRect] will only be visible while "
"in editor. Otherwise, [ReferenceRect] will be visible in game."
msgstr ""
+"Si définit à [code]true[/code], le [ReferenceRect] ne sera visible que dans "
+"l'éditeur. Sinon, [ReferenceRect] sera aussi visible dans le jeu."
#: doc/classes/ReflectionProbe.xml
-#, fuzzy
msgid ""
"Captures its surroundings to create fast, accurate reflections from a given "
"point."
-msgstr "Capture son environnement pour créer des réflexions."
+msgstr ""
+"Capture son environnement pour créer des réflexions rapides et précises "
+"depuis un point donné."
#: doc/classes/ReflectionProbe.xml
msgid ""
@@ -64128,6 +64735,8 @@ msgid ""
"Sets the ambient light color to be used when this probe is set to [member "
"interior_enable]."
msgstr ""
+"Définit la couleur de la lumière ambiante à utiliser lorsque cette sonde est "
+"définie à [membrer interior_enable]."
#: doc/classes/ReflectionProbe.xml
msgid ""
@@ -64135,22 +64744,25 @@ msgid ""
"light for this reflection probe when set to [member interior_enable]. Useful "
"so that ambient light matches the color of the room."
msgstr ""
+"Définit la valeur de contribution pour la quantité de lumière ambiante "
+"affectée par la réflexion pour cette sonde que [member interior_enable] est "
+"activé. Utile pour que la lumière ambiante corresponde à la couleur de la "
+"pièce."
#: doc/classes/ReflectionProbe.xml
msgid ""
"Sets the energy multiplier for this reflection probe's ambient light "
"contribution when set to [member interior_enable]."
msgstr ""
+"Définit le multiplicateur d'énergie pour cette sonde de réflexion de la "
+"lumière ambiante quand défini à [member interior_enable]."
#: doc/classes/ReflectionProbe.xml
-#, fuzzy
msgid ""
"If [code]true[/code], reflections will ignore sky contribution. Ambient "
"lighting is then controlled by the [code]interior_ambient_*[/code] "
"properties."
msgstr ""
-"Retourne la profondeur de la texture. La profondeur est la 3ème dimension "
-"(généralement l'axe Z)."
#: doc/classes/ReflectionProbe.xml
msgid ""
@@ -64698,9 +65310,8 @@ msgid ""
msgstr ""
#: doc/classes/ResourceImporter.xml
-#, fuzzy
msgid "Base class for the implementation of core resource importers."
-msgstr "Classe de base pour une implémentation d’interface AR / VR."
+msgstr ""
#: doc/classes/ResourceImporter.xml
msgid ""
@@ -64714,9 +65325,8 @@ msgid "Import plugins"
msgstr "Importer des plugins"
#: doc/classes/ResourceImporter.xml
-#, fuzzy
msgid "The default import order."
-msgstr "La police par défaut du thème."
+msgstr ""
#: doc/classes/ResourceImporter.xml
msgid ""
@@ -64739,13 +65349,10 @@ msgid ""
msgstr ""
#: doc/classes/ResourceInteractiveLoader.xml
-#, fuzzy
msgid ""
"Returns the loaded resource if the load operation completed successfully, "
"[code]null[/code] otherwise."
msgstr ""
-"Retourne [code]true[/code] si la chaîne de caractères commence par la chaîne "
-"de caractères donnée, ou [code]false[/code] le cas échéant."
#: doc/classes/ResourceInteractiveLoader.xml
msgid ""
@@ -65147,9 +65754,8 @@ msgid ""
msgstr ""
#: doc/classes/RichTextLabel.xml
-#, fuzzy
msgid "Returns the current selection text. Does not include BBCodes."
-msgstr "Retourne le numéro de la ligne actuelle."
+msgstr ""
#: doc/classes/RichTextLabel.xml
msgid ""
@@ -65445,24 +66051,20 @@ msgid "Makes text fill width."
msgstr "Rempli le texte en largeur."
#: doc/classes/RichTextLabel.xml
-#, fuzzy
msgid "Aligns top of the inline image to the top of the text."
-msgstr "La hauteur de la boite mesuré depuis son centre."
+msgstr ""
#: doc/classes/RichTextLabel.xml
-#, fuzzy
msgid "Aligns center of the inline image to the center of the text."
-msgstr "Aligne les enfants avec le centre du conteneur."
+msgstr ""
#: doc/classes/RichTextLabel.xml
-#, fuzzy
msgid "Aligns bottom of the inline image to the baseline of the text."
-msgstr "La hauteur de la boite mesuré depuis son centre."
+msgstr ""
#: doc/classes/RichTextLabel.xml
-#, fuzzy
msgid "Aligns bottom of the inline image to the bottom of the text."
-msgstr "Aligne les enfants avec le centre du conteneur."
+msgstr ""
#: doc/classes/RichTextLabel.xml
msgid "Each list item has a number marker."
@@ -65543,7 +66145,6 @@ msgid "The default text font."
msgstr "La police par défaut du texte."
#: doc/classes/RichTextLabel.xml
-#, fuzzy
msgid "The background used when the [RichTextLabel] is focused."
msgstr "L'arrière-plan utilisé quand le [RichTextLabel] a le focus."
@@ -65685,16 +66286,15 @@ msgid "Locks the specified linear or rotational axis."
msgstr "Verrouille l'axe linéaire et de rotation spécifié."
#: doc/classes/RigidBody.xml
-#, fuzzy
msgid ""
"Damps the body's rotational forces. If this value is different from -1.0 it "
"will be added to any angular damp derived from the world or areas.\n"
"See [member ProjectSettings.physics/3d/default_angular_damp] for more "
"details about damping."
msgstr ""
-"La vitesse à laquelle les objets arrêtent de tourner dans cette zone. "
-"Représente la vitesse angulaire perdue par seconde.\n"
-"Voir [membre ProjectSettings.physics/2d/default_angular_damp] pour plus de "
+"Amortit les forces de rotation du corps. Si cette valeur est différente de -"
+"1.0, elle sera ajoutée aux amortissements obtenues du monde et des aires.\n"
+"Voir [membre ProjectSettings.physics/3d/default_angular_damp] pour plus de "
"détails sur l'amortissement."
#: doc/classes/RigidBody.xml
@@ -66017,9 +66617,8 @@ msgid "The body's total applied force."
msgstr "La force appliquée totale du corps."
#: doc/classes/RigidBody2D.xml
-#, fuzzy
msgid "The body's total applied torque."
-msgstr "La force appliquée totale du corps."
+msgstr "La force totale appliquée au corps."
#: doc/classes/RigidBody2D.xml
msgid ""
@@ -66581,9 +67180,8 @@ msgid "Path to an [AnimationTree] node to use as a basis for root motion."
msgstr ""
#: doc/classes/RootMotionView.xml
-#, fuzzy
msgid "The grid's cell size in 3D units."
-msgstr "La taille de cellule du TileMap."
+msgstr "La taille de cellule de la grille en unités 3D."
#: doc/classes/RootMotionView.xml
msgid "The grid's color."
@@ -66596,14 +67194,11 @@ msgid ""
msgstr ""
#: doc/classes/RootMotionView.xml
-#, fuzzy
msgid ""
"If [code]true[/code], the grid's points will all be on the same Y coordinate "
"([i]local[/i] Y = 0). If [code]false[/code], the points' original Y "
"coordinate is preserved."
msgstr ""
-"Si [code]true[/code], l’état de la clé est pressé. Si [code]false[/code], "
-"l’état de la clé est libéré."
#: doc/classes/SceneState.xml
msgid "A script interface to a scene file's data."
@@ -67000,13 +67595,11 @@ msgid ""
msgstr ""
#: doc/classes/SceneTree.xml
-#, fuzzy
msgid ""
"If [code]true[/code], the application automatically accepts quitting.\n"
"For mobile platforms, see [member quit_on_go_back]."
msgstr ""
-"Si [code]true[/code], l'application accepte automatiquement de se fermer. "
-"Activé par défaut.\n"
+"Si [code]true[/code], l'application accepte automatiquement de se fermer.\n"
"Pour les plateformes mobiles, voir [method set_quit_on_go_back]."
#: doc/classes/SceneTree.xml
@@ -67093,9 +67686,8 @@ msgstr ""
"les nouvelles connexions entrantes."
#: doc/classes/SceneTree.xml
-#, fuzzy
msgid "The [SceneTree]'s root [Viewport]."
-msgstr "La [Window] racine de [SceneTree]."
+msgstr "La [Viewport] racine du [SceneTree]."
#: doc/classes/SceneTree.xml
msgid ""
@@ -67133,9 +67725,8 @@ msgid ""
msgstr ""
#: doc/classes/SceneTree.xml
-#, fuzzy
msgid "Emitted whenever global menu item is clicked."
-msgstr "Émis lorsqu’un élément est sélectionné."
+msgstr "Émis quand le menu global est cliqué."
#: doc/classes/SceneTree.xml
msgid ""
@@ -67177,9 +67768,8 @@ msgid "Emitted whenever a node is removed from the [SceneTree]."
msgstr "Émit quand un nœud est retiré du [SceneTree]."
#: doc/classes/SceneTree.xml
-#, fuzzy
msgid "Emitted whenever a node is renamed."
-msgstr "Émis chaque fois qu’un nœud est renommé."
+msgstr "Émis quand un nœud est renommé."
#: doc/classes/SceneTree.xml
msgid ""
@@ -67279,7 +67869,6 @@ msgid "One-shot timer."
msgstr "Minuteur à un coup."
#: doc/classes/SceneTreeTimer.xml
-#, fuzzy
msgid ""
"A one-shot timer managed by the scene tree, which emits [signal timeout] on "
"completion. See also [method SceneTree.create_timer].\n"
@@ -67305,16 +67894,16 @@ msgstr ""
" yield(get_tree().create_timer(1.0), \"timeout\")\n"
" print(\"Minuteur terminé.\")\n"
"[/codeblock]\n"
-"Le minuteur sera automatiquement une fois terminé."
+"Le minuteur sera automatiquement une fois terminé. Pour garder le minuteur, "
+"vous pouvez maintenir une référence vers lui. Voir [Reference]."
#: doc/classes/SceneTreeTimer.xml
msgid "The time remaining (in seconds)."
msgstr "Le temps restant (en secondes)."
#: doc/classes/SceneTreeTimer.xml doc/classes/Timer.xml
-#, fuzzy
msgid "Emitted when the timer reaches 0."
-msgstr "Émis lorsque la minuterie atteint 0."
+msgstr "Émis quand le minuteur atteint 0."
#: doc/classes/SceneTreeTween.xml
msgid ""
@@ -67692,7 +68281,6 @@ msgstr ""
"[/codeblock]"
#: doc/classes/SceneTreeTween.xml
-#, fuzzy
msgid ""
"Creates and appends an [IntervalTweener]. This method can be used to create "
"delays in the tween animation, as an alternative to using the delay in other "
@@ -67722,7 +68310,7 @@ msgstr ""
"délais des autres [Tweener] ou quand il n'y a pas d'animation (dans ce cas "
"le [SceneTreeTween] se comportement comme un minuteur). [code]time[/code] "
"est le durée du délai, en secondes.\n"
-"Exemple : créer un délai de 2s dans l'exécution du code.\n"
+"Exemple : créer un délai dans l'exécution du code.\n"
"[codeblock]\n"
"# ... du code\n"
"yield(create_tween().tween_interval(2), \"finished\")\n"
@@ -67796,7 +68384,6 @@ msgstr ""
"[/codeblock]"
#: doc/classes/SceneTreeTween.xml
-#, fuzzy
msgid ""
"Creates and appends a [PropertyTweener]. This method tweens a "
"[code]property[/code] of an [code]object[/code] between an initial value and "
@@ -67838,14 +68425,14 @@ msgstr ""
"tween.tween_property($Sprite, \"position\", Vector2(200, 300), 1)\n"
"[/codeblock]\n"
"déplacera la sprite de sa position actuelle à la position (100, 200) puis "
-"ensuite à (200, 300). Si vous utilisez [method PropertyTweener.from] ou "
-"[method PropertyTweener.from_current], la position de départ sera celle "
+"ensuite à (200, 300). Si vous utilisez [method PropertyTweener.from] ou ["
+"method PropertyTweener.from_current], la position de départ sera celle "
"spécifiée et non l'actuelle. Voir les autres méthodes de [PropertyTweener] "
"pour connaitre les possibilités.\n"
"[b]Note :[/b] Vous pouvez trouver les noms corrects des propriétés en "
"survolant ces propriétés dans l'inspecteur de Godot. Vous pouvez aussi "
-"fournir un seul composant de cette propriété directement en utilisant "
-"[code]\"property:component\"[/code] (ex. [code]position:x[/code]), alors "
+"fournir un seul composant de cette propriété directement en utilisant [code]"
+"\"property:component\"[/code] (ex. [code]position:x[/code]), alors "
"l'interpolation ne se fera que sur cet unique composant.\n"
"Exemple : déplacer un objet deux fois depuis la même position vers "
"différentes positions, avec différents types de transition.\n"
@@ -67893,11 +68480,10 @@ msgid "If [SceneTree] is paused, the [SceneTreeTween] will also pause."
msgstr "Si le [SceneTree] est en pause, le [SceneTreeTween] le sera aussi."
#: doc/classes/SceneTreeTween.xml
-#, fuzzy
msgid ""
"The [SceneTreeTween] will process regardless of whether [SceneTree] is "
"paused."
-msgstr "Arrête la mise à jour quand le [SceneTree] est en pause."
+msgstr ""
#: doc/classes/Script.xml
msgid "A class stored as a resource."
@@ -68233,7 +68819,6 @@ msgid ""
msgstr ""
#: doc/classes/Shader.xml
-#, fuzzy
msgid "A custom shader program."
msgstr "Un programme de shader personnalisé."
@@ -68583,9 +69168,8 @@ msgid ""
msgstr ""
#: doc/classes/Skeleton.xml
-#, fuzzy
msgid "Sets the pose transform for bone [code]bone_idx[/code]."
-msgstr "Définit le décalage à partir de [code]0.5[/code]."
+msgstr ""
#: doc/classes/Skeleton.xml
msgid "Sets the rest transform for bone [code]bone_idx[/code]."
@@ -68925,14 +69509,12 @@ msgid ""
msgstr ""
#: doc/classes/SoftBody.xml
-#, fuzzy
msgid "Returns local translation of a vertex in the surface array."
-msgstr "Renvoie la matrice de transformation d’une forme dans une zone."
+msgstr ""
#: doc/classes/SoftBody.xml
-#, fuzzy
msgid "Returns [code]true[/code] if vertex is set to pinned."
-msgstr "Retourne [code]true[/code] si l'[AABB] est plate ou vide."
+msgstr ""
#: doc/classes/SoftBody.xml
msgid ""
@@ -68968,13 +69550,10 @@ msgid "[NodePath] to a [CollisionObject] this SoftBody should avoid clipping."
msgstr ""
#: doc/classes/SoftBody.xml
-#, fuzzy
msgid ""
"If [code]true[/code], the [SoftBody] is simulated in physics. Can be set to "
"[code]false[/code] to pause the physics simulation."
msgstr ""
-"Si [code]true[/code], l’état de la clé est pressé. Si [code]false[/code], "
-"l’état de la clé est libéré."
#: doc/classes/SoftBody.xml
msgid "If [code]true[/code], the [SoftBody] will respond to [RayCast]s."
@@ -69695,7 +70274,6 @@ msgstr ""
"à un point donné."
#: doc/classes/SpatialMaterial.xml
-#, fuzzy
msgid ""
"Forces a conversion of the [member albedo_texture] from sRGB space to linear "
"space."
@@ -69887,11 +70465,10 @@ msgid ""
msgstr ""
#: doc/classes/SpatialMaterial.xml
-#, fuzzy
msgid ""
"If [code]true[/code], enables the vertex grow setting. See [member "
"params_grow_amount]."
-msgstr "Si [code]true[/code], active le drapeau spécifié."
+msgstr ""
#: doc/classes/SpatialMaterial.xml
msgid "Grows object vertices in the direction of their normals."
@@ -70178,9 +70755,8 @@ msgid "Texture specifying per-pixel depth."
msgstr "La texture spécifiant la profondeur par pixel."
#: doc/classes/SpatialMaterial.xml
-#, fuzzy
msgid "Texture specifying per-pixel subsurface scattering."
-msgstr "La texture spécifiant par pixel de diffusion souterraine."
+msgstr "La texture spécifiant la transluminescence par pixel."
#: doc/classes/SpatialMaterial.xml
msgid "Texture specifying per-pixel transmission color."
@@ -70392,10 +70968,9 @@ msgstr ""
"emission_texture]."
#: doc/classes/SpatialMaterial.xml
-#, fuzzy
msgid "Use alpha scissor. Set by [member params_use_alpha_scissor]."
msgstr ""
-"Utilise un ciseau pour l'alpha. Définit par [member "
+"Utilise un ciseau pour l'opacité. Définit par [member "
"params_use_alpha_scissor]."
#: doc/classes/SpatialMaterial.xml
@@ -70819,9 +71394,8 @@ msgstr ""
"collision."
#: doc/classes/SpringArm.xml
-#, fuzzy
msgid "Returns the spring arm's current length."
-msgstr "Retourne la chaîne de caractères convertie en minuscules."
+msgstr ""
#: doc/classes/SpringArm.xml
msgid ""
@@ -71046,7 +71620,6 @@ msgid "The size of one pixel's width on the sprite to scale it in 3D."
msgstr "La taille d'un des pixels de la sprite pour définir sa taille en 3D."
#: doc/classes/SpriteBase3D.xml
-#, fuzzy
msgid ""
"Sets the render priority for the sprite. Higher priority objects will be "
"sorted in front of lower priority objects.\n"
@@ -71057,22 +71630,21 @@ msgid ""
"This is because opaque objects are not sorted, while transparent objects are "
"sorted from back to front (subject to priority)."
msgstr ""
-"Définit la priorité de rendu pour le texte. Des objets plus prioritaires "
-"seront affichés par-dessus des objets moins inférieurs.\n"
-"[b]Note: [/b] Cela ne s'applique que si [member alpha_cut] est défini à "
-"[constant ALPHA_CUT_DISABLED] (c'est la valeur par défaut).\n"
+"Définit la priorité de rendu pour le texte. Les objets plus prioritaires "
+"seront affichés par-dessus les objets les moins prioritaites.\n"
+"[b]Note :[/b] Cela ne s'applique que si [member alpha_cut] est défini à ["
+"constant ALPHA_CUT_DISABLED] (c'est la valeur par défaut).\n"
"[b]Note :[/b] Cela ne s'applique qu'au tri des objets transparents. Cela "
"n'affectera pas la façon dont les objets transparents sont triés par rapport "
"aux objets opaques. C'est parce que les objets opaques ne sont pas triés, "
-"alors que les objets transparents sont triés de l'arrière à l'avant (et "
+"alors que les objets transparents sont triés de l'arrière vers l'avant (et "
"suivant leur priorité)."
#: doc/classes/SpriteBase3D.xml
-#, fuzzy
msgid ""
"If [code]true[/code], the [Light] in the [Environment] has effects on the "
"sprite."
-msgstr "Si [code]true[/code], ce [HTTPClient] a une réponse disponible."
+msgstr ""
#: doc/classes/SpriteBase3D.xml
msgid ""
@@ -71132,13 +71704,10 @@ msgid "Removes all animations. A \"default\" animation will be created."
msgstr "Retire toutes les animations. Une animation \"défaut\" sera créée."
#: doc/classes/SpriteFrames.xml
-#, fuzzy
msgid ""
"Returns [code]true[/code] if the given animation is configured to loop when "
"it finishes playing. Otherwise, returns [code]false[/code]."
msgstr ""
-"Retourne [code]true[/code] si la piste donnée est importée. Sinon retourne "
-"[code]false[/code]."
#: doc/classes/SpriteFrames.xml
msgid ""
@@ -71460,9 +72029,8 @@ msgid ""
msgstr ""
#: doc/classes/StreamPeerBuffer.xml
-#, fuzzy
msgid "Data buffer stream peer."
-msgstr "Homologue de flux SSL."
+msgstr ""
#: doc/classes/StreamPeerBuffer.xml
msgid ""
@@ -72361,22 +72929,20 @@ msgstr ""
"répétitions est donné en argument."
#: doc/classes/String.xml
-#, fuzzy
msgid ""
"Replaces occurrences of a case-sensitive substring with the given one inside "
"the string."
msgstr ""
-"Remplacer les occurrences d'une sous-chaine sensible à la casse avec l'autre "
-"donnée."
+"Remplace les occurrences sensibles à la casse à l'intérieur d'une chaine par "
+"la sous-chaine donnée."
#: doc/classes/String.xml
-#, fuzzy
msgid ""
"Replaces occurrences of a case-insensitive substring with the given one "
"inside the string."
msgstr ""
-"Remplacer les occurrences d'une sous-chaine insensible à la casse avec "
-"l'autre donnée."
+"Remplace les occurrences insensibles à la casse à l'intérieur d'une chaine "
+"par la sous-chaine donnée."
#: doc/classes/String.xml
msgid ""
@@ -72893,7 +73459,6 @@ msgstr ""
"[code]corner[/code] spécifié. Voir [enum Corner] pour les valeurs possibles."
#: doc/classes/StyleBoxFlat.xml
-#, fuzzy
msgid "Sets the corner radius to [code]radius[/code] pixels for all corners."
msgstr ""
"Définit le rayon d’angle sur [code]radius[/code] pixels pour tous les coins."
@@ -73629,11 +74194,11 @@ msgstr ""
"est désactivé."
#: doc/classes/TabContainer.xml
-#, fuzzy
msgid ""
"Returns [code]true[/code] if the tab at index [code]tab_idx[/code] is hidden."
msgstr ""
-"Retourne [code]true[/code] si la piste à l'index [code]idx[/code] est active."
+"Retourne [code]true[/code] si l'onglet à l'index [code]tab_idx[/code] est "
+"masqué."
#: doc/classes/TabContainer.xml doc/classes/Tabs.xml
msgid ""
@@ -73701,13 +74266,10 @@ msgid ""
msgstr ""
#: doc/classes/TabContainer.xml
-#, fuzzy
msgid ""
"If [code]true[/code], all tabs are drawn in front of the panel. If "
"[code]false[/code], inactive tabs are drawn behind the panel."
msgstr ""
-"Si [code]true[/code], l’état de la clé est pressé. Si [code]false[/code], "
-"l’état de la clé est libéré."
#: doc/classes/TabContainer.xml
msgid ""
@@ -73858,12 +74420,11 @@ msgid "Tabs control."
msgstr "Contrôle des onglets."
#: doc/classes/Tabs.xml
-#, fuzzy
msgid ""
"Simple tabs control, similar to [TabContainer] but is only in charge of "
"drawing tabs, not interacting with children."
msgstr ""
-"Contrôle des onglets simples, similaire à [TabContainer] mais il est "
+"Un contrôle simple des onglets, similaire à [TabContainer] mais il est "
"uniquement chargé du dessin des onglets, et non de l’interaction avec les "
"enfants."
@@ -73941,12 +74502,10 @@ msgid "Select tab at index [code]tab_idx[/code]."
msgstr "Sélectionne l'onglet à l'index [code]tab_idx[/code]."
#: doc/classes/Tabs.xml
-#, fuzzy
msgid ""
"if [code]true[/code], the mouse's scroll wheel can be used to navigate the "
"scroll view."
msgstr ""
-"Si [code]true[/code], l’état du bouton de la souris est un double-clic."
#: doc/classes/Tabs.xml
msgid "The alignment of all tabs. See [enum TabAlign] for details."
@@ -74189,9 +74748,8 @@ msgid "Returns the amount of total lines in the text."
msgstr "Retourne le nombre total de lignes dans le texte."
#: doc/classes/TextEdit.xml
-#, fuzzy
msgid "Returns the height of a largest line."
-msgstr "Retourne la hauteur du contenu."
+msgstr ""
#: doc/classes/TextEdit.xml
msgid ""
@@ -74202,14 +74760,12 @@ msgstr ""
"code]."
#: doc/classes/TextEdit.xml
-#, fuzzy
msgid "Returns the number of times the given line is wrapped."
-msgstr "Renvoie le nombre de lignes visibles."
+msgstr ""
#: doc/classes/TextEdit.xml
-#, fuzzy
msgid "Returns an array of [String]s representing each wrapped index."
-msgstr "Retourne une représentation [String] de l'évènement."
+msgstr ""
#: doc/classes/TextEdit.xml
msgid ""
@@ -74254,19 +74810,16 @@ msgid "Returns the selection end line."
msgstr "Retourne la ligne de fin de sélection."
#: doc/classes/TextEdit.xml
-#, fuzzy
msgid "Returns the total width of all gutters and internal padding."
-msgstr "Retourne le nombre de pistes dans l'animation."
+msgstr ""
#: doc/classes/TextEdit.xml
-#, fuzzy
msgid "Returns the total amount of lines that could be drawn."
-msgstr "Retourne la position du contact sur le collisionneur."
+msgstr ""
#: doc/classes/TextEdit.xml
-#, fuzzy
msgid "Returns the number of visible lines, including wrapped text."
-msgstr "Renvoie le nombre de lignes visibles."
+msgstr ""
#: doc/classes/TextEdit.xml
msgid ""
@@ -74309,34 +74862,26 @@ msgstr ""
"marque-page."
#: doc/classes/TextEdit.xml
-#, fuzzy
msgid ""
"Returns [code]true[/code] when the specified [code]line[/code] has a "
"breakpoint."
msgstr ""
-"Retourne [code]true[/code] si la piste à l'index [code]idx[/code] est active."
#: doc/classes/TextEdit.xml
-#, fuzzy
msgid ""
"Returns [code]true[/code] when the specified [code]line[/code] is marked as "
"safe."
msgstr ""
-"Retourne [code]true[/code] si la piste à l'index [code]idx[/code] est active."
#: doc/classes/TextEdit.xml
-#, fuzzy
msgid "Returns if the given line is wrapped."
-msgstr "Renvoie le texte de la colonne donnée."
+msgstr ""
#: doc/classes/TextEdit.xml
-#, fuzzy
msgid ""
"Returns whether the mouse is over selection. If [code]edges[/code] is "
"[code]true[/code], the edges are considered part of the selection."
msgstr ""
-"Renvoie [code]true[/code] (vrai) si [code]a[/code] et [code]b[/code] sont "
-"approximativement égaux l'un à l'autre."
#: doc/classes/TextEdit.xml
msgid "Returns [code]true[/code] if the selection is active."
@@ -74412,15 +74957,14 @@ msgid "Sets the text for a specific line."
msgstr "Définit le texte pour la ligne spécifiée."
#: doc/classes/TextEdit.xml
-#, fuzzy
msgid ""
"Bookmarks the [code]line[/code] if [code]bookmark[/code] is [code]true[/"
"code]. Deletes the bookmark if [code]bookmark[/code] is [code]false[/code].\n"
"Bookmarks are shown in the [member breakpoint_gutter]."
msgstr ""
-"Ajoute un marque-page pour la ligne [code]line[/code] si [code]bookmark[/"
-"code] est [code]true[/code]. Supprime le marque-page si [code]bookmark[/"
-"code] est [code]false[/code].\n"
+"Ajoute un marque-page pour la ligne [code]line[/code] si "
+"[code]bookmark[/code] est [code]true[/code]. Supprime le marque-page si "
+"[code]bookmark[/code] est [code]false[/code].\n"
"Les marque-pages sont affichés dans [member breakpoint_gutter]."
#: doc/classes/TextEdit.xml
@@ -74486,9 +75030,8 @@ msgid "If [code]true[/code], a right-click displays the context menu."
msgstr "Si [code]true[/code], un clic droit affiche le menu contextuel."
#: doc/classes/TextEdit.xml
-#, fuzzy
msgid "If [code]true[/code], allow drag and drop of selected text."
-msgstr "Si [code]true[/code], la valeur peut être sélectionnée et modifiée."
+msgstr ""
#: doc/classes/TextEdit.xml
msgid ""
@@ -74592,13 +75135,10 @@ msgid ""
msgstr ""
#: doc/classes/TextEdit.xml
-#, fuzzy
msgid ""
"If [code]true[/code], any custom color properties that have been set for "
"this [TextEdit] will be visible."
msgstr ""
-"Si [code]true[/code], les présélections de couleurs enregistrées sont "
-"visibles."
#: doc/classes/TextEdit.xml
msgid "String value of the [TextEdit]."
@@ -74748,9 +75288,8 @@ msgstr ""
"Définit le [StyleBox] de ce [TextEdit] quand [member readonly] est activé."
#: doc/classes/TextMesh.xml
-#, fuzzy
msgid "Generate an [PrimitiveMesh] from the text."
-msgstr "Générer un [TriangleMesh] à partir du maillage."
+msgstr "Génère un [PrimitiveMesh] à partir du texte."
#: doc/classes/TextMesh.xml
msgid ""
@@ -74775,9 +75314,8 @@ msgid ""
msgstr ""
#: doc/classes/TextMesh.xml
-#, fuzzy
msgid "[Font] used for the [TextMesh]'s text."
-msgstr "[Font] utilisée pour le texte du [Label]."
+msgstr "La [Font] utilisée pour le texte du [TextMesh]."
#: doc/classes/TextMesh.xml
msgid ""
@@ -74786,14 +75324,12 @@ msgid ""
msgstr ""
#: doc/classes/TextMesh.xml
-#, fuzzy
msgid "The size of one pixel's width on the text to scale it in 3D."
-msgstr "La taille d'un des pixels de la sprite pour définir sa taille en 3D."
+msgstr "La taille d'un des pixels du texte pour définir sa taille en 3D."
#: doc/classes/TextMesh.xml
-#, fuzzy
msgid "The text to generate mesh from."
-msgstr "Le type à partir duquel obtenir la constante."
+msgstr ""
#: doc/classes/Texture.xml
msgid "Texture for 2D and 3D."
@@ -74851,9 +75387,8 @@ msgid "Returns the texture width."
msgstr "Renvoie la largeur de texture."
#: doc/classes/Texture.xml
-#, fuzzy
msgid "Returns [code]true[/code] if this [Texture] has an alpha channel."
-msgstr "Retourne [code]true[/code] (vrai) si la chaîne de caractères est vide."
+msgstr ""
#: doc/classes/Texture.xml
msgid ""
@@ -74912,9 +75447,8 @@ msgid "Texture is a video surface."
msgstr "La texture est une surface vidéo."
#: doc/classes/Texture3D.xml
-#, fuzzy
msgid "Texture with 3 dimensions."
-msgstr "Retourne les dimensions de bitmap."
+msgstr ""
#: doc/classes/Texture3D.xml
msgid ""
@@ -75498,46 +76032,33 @@ msgid "Clears all values on the theme."
msgstr "Efface toutes les valeurs de ce thème."
#: doc/classes/Theme.xml
-#, fuzzy
msgid ""
"Clears the [Color] at [code]name[/code] if the theme has [code]node_type[/"
"code]."
-msgstr "Multiplie le transform [code]a[/code] par le transform [code]b[/code]."
+msgstr ""
#: doc/classes/Theme.xml
-#, fuzzy
msgid ""
"Clears the constant at [code]name[/code] if the theme has [code]node_type[/"
"code]."
msgstr ""
-"Retourne [code]true[/code] si la chaîne de caractères est vide (longueur de "
-"la chaîne égale à [code]0[/code])."
#: doc/classes/Theme.xml
-#, fuzzy
msgid ""
"Clears the [Font] at [code]name[/code] if the theme has [code]node_type[/"
"code]."
msgstr ""
-"Retourne [code]true[/code] si la chaîne de caractères est vide (longueur de "
-"la chaîne égale à [code]0[/code])."
#: doc/classes/Theme.xml
-#, fuzzy
msgid ""
"Clears the icon at [code]name[/code] if the theme has [code]node_type[/code]."
msgstr ""
-"Retourne [code]true[/code] si la chaîne de caractères est vide (longueur de "
-"la chaîne égale à [code]0[/code])."
#: doc/classes/Theme.xml
-#, fuzzy
msgid ""
"Clears [StyleBox] at [code]name[/code] if the theme has [code]node_type[/"
"code]."
msgstr ""
-"Retourne [code]true[/code] si la chaîne de caractères est vide (longueur de "
-"la chaîne égale à [code]0[/code])."
#: doc/classes/Theme.xml
msgid ""
@@ -75560,13 +76081,10 @@ msgid "Sets the theme's values to a copy of a given theme."
msgstr "Définit les valeurs du thème à partir d'une copie d'un thème donné."
#: doc/classes/Theme.xml
-#, fuzzy
msgid ""
"Returns the [Color] at [code]name[/code] if the theme has [code]node_type[/"
"code]."
msgstr ""
-"Retourne [code]true[/code] si la chaîne de caractères est vide (longueur de "
-"la chaîne égale à [code]0[/code])."
#: doc/classes/Theme.xml
msgid ""
@@ -75581,13 +76099,10 @@ msgid ""
msgstr ""
#: doc/classes/Theme.xml
-#, fuzzy
msgid ""
"Returns the constant at [code]name[/code] if the theme has [code]node_type[/"
"code]."
msgstr ""
-"Retourne [code]true[/code] si la chaîne de caractères est vide (longueur de "
-"la chaîne égale à [code]0[/code])."
#: doc/classes/Theme.xml
msgid ""
@@ -75623,13 +76138,10 @@ msgid ""
msgstr ""
#: doc/classes/Theme.xml
-#, fuzzy
msgid ""
"Returns the icon [Texture] at [code]name[/code] if the theme has "
"[code]node_type[/code]."
msgstr ""
-"Retourne [code]true[/code] si la chaîne de caractères est vide (longueur de "
-"la chaîne égale à [code]0[/code])."
#: doc/classes/Theme.xml
msgid ""
@@ -75706,11 +76218,9 @@ msgid ""
msgstr ""
#: doc/classes/Theme.xml
-#, fuzzy
msgid ""
"Returns a list of all type variations for the given [code]base_type[/code]."
msgstr ""
-"Retourne l'index de l'élément avec l'identifiant [code]id[/code] spécifié."
#: doc/classes/Theme.xml
msgid ""
@@ -75730,13 +76240,10 @@ msgid ""
msgstr ""
#: doc/classes/Theme.xml
-#, fuzzy
msgid ""
"Returns [code]true[/code] if this theme has a valid [member default_font] "
"value."
msgstr ""
-"Retourne [code]true[/code] si la chaîne de caractères est vide (longueur de "
-"la chaîne égale à [code]0[/code])."
#: doc/classes/Theme.xml
msgid ""
@@ -75770,13 +76277,10 @@ msgid ""
msgstr ""
#: doc/classes/Theme.xml
-#, fuzzy
msgid ""
"Returns [code]true[/code] if [code]theme_type[/code] is marked as a "
"variation of [code]base_type[/code]."
msgstr ""
-"Retourne [code]true[/code] si la piste donnée est importée. Sinon retourne "
-"[code]false[/code]."
#: doc/classes/Theme.xml
msgid ""
@@ -75903,9 +76407,8 @@ msgid ""
msgstr ""
#: doc/classes/Theme.xml
-#, fuzzy
msgid "Theme's [Color] item type."
-msgstr "Le type [Color] du thème."
+msgstr "Le type de l'élément [Color] du thème."
#: doc/classes/Theme.xml
msgid "Theme's constant item type."
@@ -76074,13 +76577,10 @@ msgid ""
msgstr ""
#: doc/classes/TileMap.xml
-#, fuzzy
msgid ""
"Returns an array of all cells with the given tile index specified in "
"[code]id[/code]."
msgstr ""
-"Renvoie la texture de l’atlas de police de caractères à l’index [code]idx[/"
-"code]."
#: doc/classes/TileMap.xml
msgid "Returns a rectangle enclosing the used (non-empty) tiles of the map."
@@ -76195,9 +76695,8 @@ msgid ""
msgstr ""
#: doc/classes/TileMap.xml
-#, fuzzy
msgid "If [code]true[/code], this TileMap bakes a navigation region."
-msgstr "Si [code]true[/code], l'animation nommée existe."
+msgstr ""
#: doc/classes/TileMap.xml
#, fuzzy
@@ -76231,11 +76730,10 @@ msgstr ""
"valeurs possibles."
#: doc/classes/TileMap.xml
-#, fuzzy
msgid ""
"If [code]true[/code], the TileMap's direct children will be drawn in order "
"of their Y coordinate."
-msgstr "Si [code]true[/code], la frontière de la ligne sera anti-aliasée."
+msgstr ""
#: doc/classes/TileMap.xml
msgid ""
@@ -76391,7 +76889,6 @@ msgid "Tile origin at its bottom-left corner."
msgstr "Origine de tuile à son coin inférieur gauche."
#: doc/classes/TileSet.xml
-#, fuzzy
msgid "Tile library for tilemaps."
msgstr "La bibliothèque des tuiles pour les cartes."
@@ -77233,7 +77730,6 @@ msgstr ""
"[InputEventAction]."
#: doc/classes/TouchScreenButton.xml
-#, fuzzy
msgid "The button's bitmask."
msgstr "Le masque binaire du bouton."
@@ -77644,9 +78140,8 @@ msgid "Clears the server from all translations."
msgstr "Efface le serveur de toutes les traductions."
#: doc/classes/TranslationServer.xml
-#, fuzzy
msgid "Returns an array of all loaded locales of the project."
-msgstr "Renvoie la valeur absolue du paramètre."
+msgstr ""
#: doc/classes/TranslationServer.xml
msgid ""
@@ -77889,9 +78384,8 @@ msgid ""
msgstr ""
#: doc/classes/Tree.xml
-#, fuzzy
msgid "Causes the [Tree] to jump to the specified [TreeItem]."
-msgstr "Définit la position du nœud spécifié."
+msgstr ""
#: doc/classes/Tree.xml
msgid ""
@@ -78329,13 +78823,10 @@ msgstr ""
"[code]column[/code]."
#: doc/classes/TreeItem.xml
-#, fuzzy
msgid ""
"Returns the [Texture] of the button at index [code]button_idx[/code] in "
"column [code]column[/code]."
msgstr ""
-"Rentourne [code]true[/code] (vrai) si le bouton d'index [code]button[/code] "
-"est préssé. Voir [enum JoyButtonList]."
#: doc/classes/TreeItem.xml
msgid ""
@@ -78350,13 +78841,10 @@ msgid "Returns the number of buttons in column [code]column[/code]."
msgstr "Retourne le nombre de boutons dans la colonne [code]column[/code]."
#: doc/classes/TreeItem.xml
-#, fuzzy
msgid ""
"Returns the id for the button at index [code]button_idx[/code] in column "
"[code]column[/code]."
msgstr ""
-"Rentourne [code]true[/code] (vrai) si le bouton d'index [code]button[/code] "
-"est préssé. Voir [enum JoyButtonList]."
#: doc/classes/TreeItem.xml
msgid ""
@@ -78367,9 +78855,8 @@ msgstr ""
"[code]button_idx[/code] dans la colonne [code]column[/code]."
#: doc/classes/TreeItem.xml
-#, fuzzy
msgid "Returns the column's cell mode."
-msgstr "Retourne le mode de la cellule de la colonne."
+msgstr "Retourne le mode des cellules de la colonne."
#: doc/classes/TreeItem.xml
msgid ""
@@ -78391,9 +78878,8 @@ msgid "Returns [code]true[/code] if [code]expand_right[/code] is set."
msgstr "Retourne [code]true[/code] si [code]expand_right[/code] est défini."
#: doc/classes/TreeItem.xml
-#, fuzzy
msgid "Returns the given column's icon [Texture]. Error if no icon is set."
-msgstr "Retourne l'alignement du texte de la colonne donnée."
+msgstr ""
#: doc/classes/TreeItem.xml
msgid "Returns the column's icon's maximum width."
@@ -78414,16 +78900,14 @@ msgid ""
msgstr ""
#: doc/classes/TreeItem.xml
-#, fuzzy
msgid ""
"Returns the next sibling TreeItem in the tree or a null object if there is "
"none."
msgstr ""
-"Retourne le TreeItem précédent dans l'arbre ou un objet nul s'il n'y en a "
-"pas."
+"Retourne le TreeItem suivant dans l'arborescence, ou l'objet null s'il n'y "
+"en a pas."
#: doc/classes/TreeItem.xml
-#, fuzzy
msgid ""
"Returns the next visible sibling TreeItem in the tree or a null object if "
"there is none.\n"
@@ -78431,7 +78915,8 @@ msgid ""
"visible element in the tree when called on the last visible element, "
"otherwise it returns [code]null[/code]."
msgstr ""
-"Retourne le TreeItem suivant visible dans l'arborescence ou null si aucun.\n"
+"Retourne le TreeItem voisin suivant visible dans l'arborescence, ou null si "
+"aucun.\n"
"Si [code]wrap[/code] est activé, la méthode repartira depuis le premier "
"élément visible de l'arborescence si elle est appelé sur le dernier élément, "
"sinon elle retournera [code]null[/code]."
@@ -78441,16 +78926,14 @@ msgid "Returns the parent TreeItem or a null object if there is none."
msgstr "Renvoie le TreeItem parent ou un objet nul s’il n’y en a pas."
#: doc/classes/TreeItem.xml
-#, fuzzy
msgid ""
"Returns the previous sibling TreeItem in the tree or a null object if there "
"is none."
msgstr ""
-"Retourne le TreeItem précédent dans l'arbre ou un objet nul s'il n'y en a "
-"pas."
+"Retourne le TreeItem précédent dans l'arborescence, ou l'objet null s'il n'y "
+"en a pas."
#: doc/classes/TreeItem.xml
-#, fuzzy
msgid ""
"Returns the previous visible sibling TreeItem in the tree or a null object "
"if there is none.\n"
@@ -78458,8 +78941,8 @@ msgid ""
"visible element in the tree when called on the first visible element, "
"otherwise it returns [code]null[/code]."
msgstr ""
-"Retourne le TreeItem précédent visible dans l'arborescence ou null si "
-"aucun.\n"
+"Retourne le TreeItem voisin précédent visible dans l'arborescence, ou null "
+"si aucun.\n"
"Si [code]wrap[/code] est activé, la méthode repartira depuis le dernier "
"élément visible de l'arborescence si elle est appelé sur le premier élément, "
"sinon elle retournera [code]null[/code]."
@@ -78541,12 +79024,10 @@ msgid "Selects the column [code]column[/code]."
msgstr "Sélectionne la colonne [code]column[/code]."
#: doc/classes/TreeItem.xml
-#, fuzzy
msgid ""
"Sets the given column's button [Texture] at index [code]button_idx[/code] to "
"[code]button[/code]."
msgstr ""
-"Déplace l’élément de l’index [code]from_idx[/code] à [code]to_idx[/code]."
#: doc/classes/TreeItem.xml
msgid ""
@@ -78846,7 +79327,6 @@ msgid ""
msgstr ""
#: doc/classes/Tween.xml
-#, fuzzy
msgid ""
"Resets all tweens to their initial values (the ones given, not those before "
"the tween)."
@@ -79960,9 +80440,8 @@ msgid "Vertical box container."
msgstr "Conteneur vertical."
#: doc/classes/VBoxContainer.xml
-#, fuzzy
msgid "Vertical box container. See [BoxContainer]."
-msgstr "Conteneur vertical. Voir [BoxContainer]."
+msgstr "Conteneur de boites vertical. Voir [BoxContainer]."
#: doc/classes/VBoxContainer.xml
msgid "The vertical space between the [VBoxContainer]'s elements."
@@ -80186,9 +80665,8 @@ msgid ""
msgstr ""
#: doc/classes/Vector2.xml doc/classes/Vector3.xml
-#, fuzzy
msgid "Returns this vector projected onto the vector [code]b[/code]."
-msgstr "Retourne le vecteur projeté sur le vecteur [code]b[/code]."
+msgstr "Retourne ce vecteur projeté sur le vecteur [code]b[/code]."
#: doc/classes/Vector2.xml
msgid ""
@@ -80197,13 +80675,12 @@ msgid ""
msgstr ""
#: doc/classes/Vector2.xml
-#, fuzzy
msgid ""
"Returns the vector rotated by [code]angle[/code] (in radians). See also "
"[method @GDScript.deg2rad]."
msgstr ""
-"Retourne le vecteur pivoté par [code]phi[/code] en radians. Voir aussi "
-"[method @GDScript.deg2rad]."
+"Retourne le vecteur pivoté par [code]angle[/code] (en radians). Voir aussi ["
+"method @GDScript.deg2rad]."
#: doc/classes/Vector2.xml doc/classes/Vector3.xml
msgid ""
@@ -80805,7 +81282,6 @@ msgid ""
msgstr ""
#: modules/gdnative/doc_classes/VideoStreamGDNative.xml
-#, fuzzy
msgid "[VideoStream] resource for video formats implemented via GDNative."
msgstr ""
"La ressource [VideoStream] pour les formats vidéo implémentés via GDNative."
@@ -80961,12 +81437,10 @@ msgid "Returns the topmost modal in the stack."
msgstr "Retourne la vue exclusive la plus en avant dans la pile."
#: doc/classes/Viewport.xml
-#, fuzzy
msgid ""
"Returns the mouse's position in this [Viewport] using the coordinate system "
"of this [Viewport]."
msgstr ""
-"Retourne la position de la souris par rapport à la position de cet élément."
#: doc/classes/Viewport.xml
msgid "Returns information about the viewport from the rendering pipeline."
@@ -80977,9 +81451,8 @@ msgid "Returns the [enum ShadowAtlasQuadrantSubdiv] of the specified quadrant."
msgstr ""
#: doc/classes/Viewport.xml
-#, fuzzy
msgid "Returns the size override set with [method set_size_override]."
-msgstr "Renvoie le mode de remplacement de l’espace pour la zone."
+msgstr ""
#: doc/classes/Viewport.xml
msgid ""
@@ -81009,9 +81482,8 @@ msgid ""
msgstr ""
#: doc/classes/Viewport.xml
-#, fuzzy
msgid "Returns [code]true[/code] if there are visible modals on-screen."
-msgstr "Retourne [code]true[/code] si la colonne donnée est cochée."
+msgstr ""
#: doc/classes/Viewport.xml
msgid "Returns [code]true[/code] if the drag operation is successful."
@@ -81074,9 +81546,8 @@ msgid ""
msgstr ""
#: doc/classes/Viewport.xml
-#, fuzzy
msgid "If [code]true[/code], the viewport will be used in AR/VR process."
-msgstr "Si [code]true[/code], la texture sera centrée."
+msgstr ""
#: doc/classes/Viewport.xml
msgid "If [code]true[/code], the viewport will process 2D audio streams."
@@ -81260,10 +81731,8 @@ msgid ""
msgstr ""
#: doc/classes/Viewport.xml
-#, fuzzy
msgid "If [code]true[/code], the size override affects stretch as well."
msgstr ""
-"Si [code]true[/code], le mouvement linéaire à travers l’axe Z est limité."
#: doc/classes/Viewport.xml
msgid ""
@@ -81294,9 +81763,8 @@ msgid ""
msgstr ""
#: doc/classes/Viewport.xml
-#, fuzzy
msgid "The custom [World] which can be used as 3D environment source."
-msgstr "Une constante [Transform], qui peut être utilisée comme nœud d’entrée."
+msgstr ""
#: doc/classes/Viewport.xml
msgid "The custom [World2D] which can be used as 2D environment source."
@@ -81397,14 +81865,12 @@ msgid "Amount of surface changes in frame."
msgstr "Le nombre de surfaces changées à chaque trame."
#: doc/classes/Viewport.xml
-#, fuzzy
msgid "Amount of draw calls in frame."
-msgstr "Le nombre d'appels d'affichage à chaque trame."
+msgstr "Le nombre d'appels de dessin à chaque trame."
#: doc/classes/Viewport.xml
-#, fuzzy
msgid "Amount of items or joined items in frame."
-msgstr "Quantité d’objets dans le cadre."
+msgstr ""
#: doc/classes/Viewport.xml
msgid "Represents the size of the [enum RenderInfo] enum."
@@ -81651,15 +82117,14 @@ msgid "This enabler will stop [Particles2D] nodes."
msgstr "Cet activateur arrêtera les nœuds [Particles2D]."
#: doc/classes/VisibilityEnabler2D.xml
-#, fuzzy
msgid "This enabler will stop the parent's [method Node._process] function."
-msgstr "Cet activateur arrêtera la fonction _process du parent."
+msgstr "Cet activateur arrêtera la fonction [method Node._process] du parent."
#: doc/classes/VisibilityEnabler2D.xml
-#, fuzzy
msgid ""
"This enabler will stop the parent's [method Node._physics_process] function."
-msgstr "Cet activateur arrêtera la fonction _physics_process du parent."
+msgstr ""
+"Cet activateur arrêtera la fonction [method Node._physics_process] du parent."
#: doc/classes/VisibilityEnabler2D.xml
msgid "This enabler will stop [AnimatedSprite] nodes animations."
@@ -81713,15 +82178,12 @@ msgid ""
msgstr ""
#: doc/classes/VisibilityNotifier.xml
-#, fuzzy
msgid "Emitted when the VisibilityNotifier enters a [Camera]'s view."
-msgstr ""
-"Émis lorsque le VisibilityNotifier3D entre dans la vue d’un [Camera3D]."
+msgstr "Émis lorsque le VisibilityNotifier entre dans la vue d’un [Camera]."
#: doc/classes/VisibilityNotifier.xml
-#, fuzzy
msgid "Emitted when the VisibilityNotifier exits a [Camera]'s view."
-msgstr "Émis lorsque le VisibilityNotifier3D quitte la vue d'un [Camera3D]."
+msgstr "Émis lorsque le VisibilityNotifier quitte la vue d'un [Camera]."
#: doc/classes/VisibilityNotifier.xml
msgid "Emitted when the VisibilityNotifier enters the screen."
@@ -81754,9 +82216,8 @@ msgid ""
msgstr ""
#: doc/classes/VisibilityNotifier2D.xml
-#, fuzzy
msgid "The VisibilityNotifier2D's bounding rectangle."
-msgstr "Rectangle englobant de VisibilityNotifier2D."
+msgstr "Le rectangle englobant du VisibilityNotifier2D."
#: doc/classes/VisibilityNotifier2D.xml
msgid "Emitted when the VisibilityNotifier2D enters the screen."
@@ -81794,6 +82255,8 @@ msgid ""
"Returns the [AABB] (also known as the bounding box) for this "
"[VisualInstance]. See also [method get_transformed_aabb]."
msgstr ""
+"Retourne le [AABB] (\"bounding box\") pour cette [VisualInstance]. Voir "
+"aussi [method get_transformed_aaabb]."
#: doc/classes/VisualInstance.xml
msgid ""
@@ -81801,6 +82264,8 @@ msgid ""
"example, if the Node is a [MeshInstance], this will return the RID of the "
"associated [Mesh]."
msgstr ""
+"Retourne le RID de la ressource associée à cette [VisualInstance]. Par "
+"exemple, si le nœud est une [MeshInstance], cela retournera le RID du [Mesh]."
#: doc/classes/VisualInstance.xml
msgid ""
@@ -81808,12 +82273,18 @@ msgid ""
"by [method VisualServer.instance_create]. This RID is needed if you want to "
"call [VisualServer] functions directly on this [VisualInstance]."
msgstr ""
+"Retourne le RID de cette instance. Ce RID est le même que le RID retourné "
+"par [method VisualServer.instance_create]. Ce RID est nécessaire si vous "
+"voulez appeler les fonctions [VisualServer] directement sur cette "
+"[VisualInstance]."
#: doc/classes/VisualInstance.xml
msgid ""
"Returns [code]true[/code] when the specified layer is enabled in [member "
"layers] and [code]false[/code] otherwise."
msgstr ""
+"Retourne [code]true[/code] si le calque spécifié est actif, ou "
+"[code]false[/code] sinon."
#: doc/classes/VisualInstance.xml
msgid ""
@@ -81822,6 +82293,11 @@ msgid ""
"Transformed in this case means the [AABB] plus the position, rotation, and "
"scale of the [Spatial]'s [Transform]. See also [method get_aabb]."
msgstr ""
+"Retourne la [AABB] (\"bounding box\") transformée pour cette "
+"[VisualInstance].\n"
+"Transformé dans ce cas veut dire la [AABB] plus sa position, la rotation et "
+"la mise à l'échelle de la [Transform] du [Spatial]. Voir aussi [method "
+"get_aabb]."
#: doc/classes/VisualInstance.xml
msgid ""
@@ -81829,6 +82305,9 @@ msgid ""
"changes how the engine handles the [VisualInstance] under the hood. "
"Equivalent to [method VisualServer.instance_set_base]."
msgstr ""
+"Définit la ressource qui est instanciée par cette [VisualInstance] qui "
+"modifie la façon dont le moteur gère la [VisualInstance] en interne. "
+"Équivalent à [method VisualServer.instance_set_base]."
#: doc/classes/VisualInstance.xml
msgid "Enables a particular layer in [member layers]."
@@ -81840,10 +82319,14 @@ msgid ""
"This object will only be visible for [Camera]s whose cull mask includes the "
"render object this [VisualInstance] is set to."
msgstr ""
+"Le(s) calque(s) de rendu où cette [VisualInstance] est dessinée.\n"
+"Cet objet ne sera visible que pour les [Camera] où le masque de cull inclut "
+"l'objet de rendu auquel [VisualInstance] est défini."
#: modules/visual_script/doc_classes/VisualScript.xml
msgid "A script implemented in the Visual Script programming environment."
msgstr ""
+"Un script implémenté dans l'environnement de programmation Visual Script."
#: modules/visual_script/doc_classes/VisualScript.xml
msgid ""
@@ -81872,6 +82355,8 @@ msgid ""
"Add a variable to the VisualScript, optionally giving it a default value or "
"marking it as exported."
msgstr ""
+"Ajouter une variable au VisualScript, en option lui donnant une valeur par "
+"défaut ou la marquant comme exporté."
#: modules/visual_script/doc_classes/VisualScript.xml
msgid ""
@@ -81927,7 +82412,7 @@ msgstr ""
#: modules/visual_script/doc_classes/VisualScript.xml
msgid "Returns the id of a function's entry point node."
-msgstr ""
+msgstr "Retourne l'identifiant d'un nœud de point d'entrée de la fonction."
#: modules/visual_script/doc_classes/VisualScript.xml
msgid "Returns the position of the center of the screen for a given function."
@@ -81954,6 +82439,8 @@ msgid ""
"Returns the information for a given variable as a dictionary. The "
"information includes its name, type, hint and usage."
msgstr ""
+"Retourne les informations d'une variable donnée dans un dictionnaire. Les "
+"informations comprennent son nom, son type, un indice et son usage."
#: modules/visual_script/doc_classes/VisualScript.xml
msgid "Returns whether a signal exists with the specified name."
@@ -82014,16 +82501,23 @@ msgid ""
"Unlike [method data_connect], there isn't a [code]to_port[/code], since the "
"target node can have only one sequence port."
msgstr ""
+"Connecte deux ports d'une séquence. L'exécution passera de "
+"[code]from_output[/code] de [code]from_node[/code] vers [code]to_node[/code]."
+"\n"
+"Contrairement à [method data_connect], il n'y a pas ∂e [code]to_port[/code], "
+"puisque le nœud cible ne peut avoir qu'un seul port dans la séquence."
#: modules/visual_script/doc_classes/VisualScript.xml
msgid ""
"Disconnect two sequence ports previously connected with [method "
"sequence_connect]."
msgstr ""
+"Déconnecte deux ports de séquence précédemment connectés avec [method "
+"sequence_connect]."
#: modules/visual_script/doc_classes/VisualScript.xml
msgid "Position the center of the screen for a function."
-msgstr ""
+msgstr "Positionne le centre de l'écran sur une fonction."
#: modules/visual_script/doc_classes/VisualScript.xml
msgid "Set the base type of the script."
@@ -82054,13 +82548,15 @@ msgstr "Émis quand les ports d'un nœud ont changés."
#: modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml
msgid "A Visual Script node representing a constant from the base types."
-msgstr ""
+msgstr "Un nœud Visual Script représentant une constante d'un type de base."
#: modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml
msgid ""
"A Visual Script node representing a constant from base types, such as "
"[constant Vector3.AXIS_X]."
msgstr ""
+"Un nœud Visual Script représentant une constante des types de base, comme ["
+"constant Vector3.AXIS_X]."
#: modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml
msgid "The type to get the constant from."
@@ -82072,7 +82568,7 @@ msgstr "Le nom de la constante à retourner."
#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
msgid "A Visual Script node used to call built-in functions."
-msgstr ""
+msgstr "Un nœud Visual Script utilisé pour appeler des fonctions intégrées."
#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
msgid ""
@@ -82080,6 +82576,9 @@ msgid ""
"function or an utility function.\n"
"See also [@GDScript], for the same functions in the GDScript language."
msgstr ""
+"Une fonction intégrée utilisée dans un [VisualScript]. C'est généralement "
+"une fonction de mathématiques ou une fonction utilitaire.\n"
+"Voir aussi @[GDScript], pour les mêmes fonctions dans le langage GDScript."
#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
msgid "The function to be executed."
@@ -82126,6 +82625,8 @@ msgid ""
"Return the arc tangent of the input, using the signs of both parameters to "
"determine the exact angle."
msgstr ""
+"Retourner l'arc tangente de l'entrée, en utilisant les signes des deux "
+"paramètres pour déterminer l'angle exact."
#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
msgid "Return the square root of the input."
@@ -82144,6 +82645,8 @@ msgid ""
"Return the positive remainder of one input divided by the other, using "
"floating-point numbers."
msgstr ""
+"Retourner le reste positif d'une entrée divisée par l'autre, en utilisant "
+"des flottants."
#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
msgid "Return the input rounded down."
@@ -82166,6 +82669,8 @@ msgid ""
"Return the sign of the input, turning it into 1, -1, or 0. Useful to "
"determine if the input is positive or negative."
msgstr ""
+"Retourner le signe de l'entrée, le transformant en 1, -1, ou 0. Utile pour "
+"déterminer si l'entrée est positive ou négative."
#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
msgid "Return the input raised to a given power."
@@ -82176,18 +82681,26 @@ msgid ""
"Return the natural logarithm of the input. Note that this is not the typical "
"base-10 logarithm function calculators use."
msgstr ""
+"Retourner le logarithme népérien de l'entrée. Notez que ce n'est pas "
+"l'utilisation typique des calculatrices avec la fonction logarithme en "
+"base-10."
#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
msgid ""
"Return the mathematical constant [b]e[/b] raised to the specified power of "
"the input. [b]e[/b] has an approximate value of 2.71828."
msgstr ""
+"Retourner la constante mathématique [b]e[/b] à la puissance spécifiée par "
+"l'entrée. [b]e[/b] a une valeur approximativement égal à 2.71828."
#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
msgid ""
"Return whether the input is NaN (Not a Number) or not. NaN is usually "
"produced by dividing 0 by 0, though other ways exist."
msgstr ""
+"Retourne si l'entrée la valeur spéciale NaN qui signifie que ce n'est pas un "
+"nombre (\"Not a Number\") ou non. NaN est généralement produit en divisant 0 "
+"par 0, entre autre."
#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
msgid ""
@@ -82195,6 +82708,8 @@ msgid ""
"Infinity is usually produced by dividing a number by 0, though other ways "
"exist."
msgstr ""
+"Retourne si l'entrée est un nombre flottant infini ou non. L'infini est "
+"généralement produit en divisant un nombre par 0, entre autre."
#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
msgid ""
@@ -82207,7 +82722,6 @@ msgstr ""
"progressive."
#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
-#, fuzzy
msgid ""
"Return the number of digit places after the decimal that the first non-zero "
"digit occurs."
@@ -82217,13 +82731,16 @@ msgstr ""
#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
msgid "Return the input snapped to a given step."
-msgstr ""
+msgstr "Retourner l'entrée arrondie à l'étape donnée la plus proche."
#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
msgid ""
"Return a number linearly interpolated between the first two inputs, based on "
"the third input. Uses the formula [code]a + (a - b) * t[/code]."
msgstr ""
+"Retourner un nombre linéairement interpolé entre les deux premières entrées, "
+"basé sur la troisième entrée. Utilise la formule [code]a + (a - b) * "
+"t[/code]."
#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
msgid "Moves the number toward a value, based on the third input."
@@ -82250,12 +82767,17 @@ msgid ""
"N (where N is smaller than 2^32 - 1), you can use it with the remainder "
"function."
msgstr ""
+"Retourner une entier de 32 bits aléatoire. Pour obtenir une valeur aléatoire "
+"entre 0 et N (où N est plus petit que 2^32 - 1), vous pouvez l'utiliser avec "
+"la fonction modulo (retournant le reste de la division euclidienne)."
#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
msgid ""
"Return a random floating-point value between 0 and 1. To obtain a random "
"value between 0 to N, you can use it with multiplication."
msgstr ""
+"Retourner un flottant aléatoire entre 0 et 1. Pour obtenir une valeur "
+"aléatoire entre 0 à N, vous pouvez multiplier cette valeur avec N."
#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
msgid "Return a random floating-point value between the two inputs."
@@ -82304,6 +82826,9 @@ msgid ""
"never outside it. Equivalent to [code]min(max(input, range_low), range_high)"
"[/code]."
msgstr ""
+"Retourner l'entrée limitée à l'intervalle donné, s'assurant que le résultat "
+"n'est jamais en dehors de l'intervalle. Équivalent à [code]min(max(input, "
+"minimum), maximum)[/code]."
#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
msgid "Return the nearest power of 2 to the input."
@@ -82326,6 +82851,8 @@ msgid ""
"Return the type of the input as an integer. Check [enum Variant.Type] for "
"the integers that might be returned."
msgstr ""
+"Retourner le type d'entrée en entier. Regardez [enum Variant.Type] pour les "
+"valeurs des entiers qui peuvent être retournés."
#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
msgid "Checks if a type is registered in the [ClassDB]."
@@ -82378,6 +82905,8 @@ msgid ""
"Return the [Color] with the given name and alpha ranging from 0 to 1.\n"
"[b]Note:[/b] Names are defined in [code]color_names.inc[/code]."
msgstr ""
+"Retourner la [Color] avec le nom donné et alpha allant de 0 à 1.\n"
+"[b]Note :[/b] Les noms sont définis dans [code]color_names.inc[/code]."
#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
msgid ""
@@ -82389,6 +82918,14 @@ msgid ""
"return t * t * (3.0 - 2.0 * t)\n"
"[/codeblock]"
msgstr ""
+"Retourner un nombre correctement interpolé entre les deux premières entrées, "
+"en fonction de la troisième entrée. Comme [constant MATH_LERP], mais "
+"interpole plus rapidement au début et plus lentement à la fin. Utiliser la "
+"formule d'interpolation de Hermite:\n"
+"[codeblock]\n"
+"var t = clamp((weight - from) / (to - from), 0.0, 1.0)\n"
+"return t * t * (3.0 - 2.0 * t)\n"
+"[/codeblock]"
#: modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
msgid "Represents the size of the [enum BuiltinFunc] enum."
@@ -82503,6 +83040,8 @@ msgid ""
"A Visual Script node which calls a base type constructor. It can be used for "
"type conversion as well."
msgstr ""
+"Un nœud Visual Script qui appelle un constructeur de type de base. Il peut "
+"également être utilisé pour la conversion de type."
#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml
msgid "A scripted Visual Script node."
@@ -82511,6 +83050,8 @@ msgstr "Un nœud Visual Script scripté."
#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml
msgid "A custom Visual Script node which can be scripted in powerful ways."
msgstr ""
+"Un nœud Visual Script personnalisé qui peut être scripté de plein de "
+"manières."
#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml
msgid "Return the node's title."
@@ -82564,6 +83105,8 @@ msgid ""
"Return the specified output port's hint. See the [enum @GlobalScope."
"PropertyHint] hints."
msgstr ""
+"Retourne l'indice du port de sortie spécifié. Voir les indices dans [enum "
+"@GlobalScope.PropertyHint]."
#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml
msgid "Return the specified output port's hint string."
@@ -82574,10 +83117,11 @@ msgid "Return the specified output port's name."
msgstr "Retourne le nom du port de sortie spécifié."
#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml
-#, fuzzy
msgid ""
"Return the specified output port's type. See the [enum Variant.Type] values."
-msgstr "Représente la taille de l'énumération [enum Variant.Type]."
+msgstr ""
+"Retourne le type du port de sortie spécifié. Voir [enum Variant.Type] "
+"valeurs."
#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml
msgid ""
@@ -82585,6 +83129,9 @@ msgid ""
"[b]sequence[/b] port (if there is none, on the place that is usually taken "
"by it)."
msgstr ""
+"Retourne le texte du nœud personnalisé, qui est affiché juste à côté du port "
+"d'entrée [b]séquence[/b] (s'il n'y en a aucun, à l'emplacement où "
+"habituellement pris par lui)."
#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml
msgid ""
@@ -82617,18 +83164,24 @@ msgstr ""
#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml
msgid "The start mode used the first time when [method _step] is called."
msgstr ""
+"Le mode de démarrage a utilisé la première fois que [method _step] est "
+"appelée."
#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml
msgid ""
"The start mode used when [method _step] is called after coming back from a "
"[constant STEP_PUSH_STACK_BIT]."
msgstr ""
+"Le mode de démarrage utilisé lorsque [method _step] est appelé après être "
+"revenu de [constant STEP_PUSH_STACK_BIT]."
#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml
msgid ""
"The start mode used when [method _step] is called after resuming from "
"[constant STEP_YIELD_BIT]."
msgstr ""
+"Le mode de démarrage utilisé lorsque [method _step] est appelé après être "
+"revenu de [constant STEP_YIELD_BIT]."
#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml
msgid ""
@@ -82644,6 +83197,9 @@ msgid ""
"Hint used by [method _step] to tell that control should return back, either "
"hitting a previous [constant STEP_PUSH_STACK_BIT] or exiting the function."
msgstr ""
+"L'indice utilisé par [method _step] pour dire que la commande doit revenir, "
+"soit en atteignant un précédent [constant STEP_PUSH_STACK_BIT] ou en sortant "
+"de la fonction."
#: modules/visual_script/doc_classes/VisualScriptCustomNode.xml
msgid ""
@@ -82659,11 +83215,17 @@ msgid ""
"Using this requires you to have at least one working memory slot, which is "
"used for the [VisualScriptFunctionState]."
msgstr ""
+"L'indice utilisé par [method _step] pour dire que la fonction doit être "
+"attendue.\n"
+"En utilisant cela, vous devez avoir au moins un emplacement de mémoire "
+"fonctionnel, qui est utilisé pour [VisualScriptFunctionState]."
#: modules/visual_script/doc_classes/VisualScriptDeconstruct.xml
msgid ""
"A Visual Script node which deconstructs a base type instance into its parts."
msgstr ""
+"Un nœud Visual Script qui déconstruit une instance de type de base en ses "
+"différentes parties."
#: modules/visual_script/doc_classes/VisualScriptDeconstruct.xml
msgid "The type to deconstruct."
@@ -82674,12 +83236,16 @@ msgid ""
"Add a custom Visual Script node to the editor. It'll be placed under "
"\"Custom Nodes\" with the [code]category[/code] as the parameter."
msgstr ""
+"Ajoute un nœud Visual Script personnalisé à l'éditeur. Il sera placé sous "
+"\"Nœuds personnalisés\" avec la [code]category[/code] en paramètre."
#: modules/visual_script/doc_classes/VisualScriptEditor.xml
msgid ""
"Remove a custom Visual Script node from the editor. Custom nodes already "
"placed on scripts won't be removed."
msgstr ""
+"Retire un nœud Visual Script personnalisé de l'éditeur. Les nœuds "
+"personnalisés déjà placés sur des scripts ne seront pas supprimés."
#: modules/visual_script/doc_classes/VisualScriptEditor.xml
msgid "Emitted when a custom Visual Script node is added or removed."
@@ -82697,6 +83263,11 @@ msgid ""
"[b]Output Ports:[/b]\n"
"- Sequence"
msgstr ""
+"Émet un signal spécifié quand il est exécuté.\n"
+"[b]Ports d'entrée :[/b]\n"
+"- Séquence : [code]emit[/code]\n"
+"[b]Ports de sortie :[/b]\n"
+"- Séquence"
#: modules/visual_script/doc_classes/VisualScriptEmitSignal.xml
msgid "The signal to emit."
@@ -82704,16 +83275,15 @@ msgstr "Le signal à émettre."
#: modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml
msgid "A Visual Script node returning a singleton from [@GlobalScope]."
-msgstr ""
+msgstr "Un nœud Visual Script retournant un singleton parmi @[GlobalScope]."
#: modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml
msgid "The singleton's name."
msgstr "Le nom du singleton."
#: modules/visual_script/doc_classes/VisualScriptExpression.xml
-#, fuzzy
msgid "A Visual Script node that can execute a custom expression."
-msgstr "Un nœud Visual Script utilisé pour annoter le script."
+msgstr "Un nœud Visual Script qui peut exécuter une expression personnalisée."
#: modules/visual_script/doc_classes/VisualScriptExpression.xml
msgid ""
@@ -82734,9 +83304,8 @@ msgid ""
msgstr ""
#: modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
-#, fuzzy
msgid "A Visual Script node for calling a function."
-msgstr "Un nœud Visual Script utilisé pour annoter le script."
+msgstr "Un nœud Visual Script pour appeler une fonction."
#: modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
msgid ""
@@ -82750,6 +83319,8 @@ msgid ""
"The script to be used when [member call_mode] is set to [constant "
"CALL_MODE_INSTANCE]."
msgstr ""
+"Le script à utiliser lorsque [member call_mode] est défini à [constant "
+"CALL_MODE_INSTANCE]."
#: modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
#: modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
@@ -82757,18 +83328,24 @@ msgid ""
"The base type to be used when [member call_mode] is set to [constant "
"CALL_MODE_INSTANCE]."
msgstr ""
+"Le type de base à utiliser lorsque [member call_mode] est défini à [constant "
+"CALL_MODE_INSTANCE]."
#: modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
msgid ""
"The type to be used when [member call_mode] is set to [constant "
"CALL_MODE_BASIC_TYPE]."
msgstr ""
+"Le type à utiliser lorsque [member call_mode] est défini à [constant "
+"CALL_MODE_BASIC_TYPE]."
#: modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
msgid ""
"[code]call_mode[/code] determines the target object on which the method will "
"be called. See [enum CallMode] for options."
msgstr ""
+"[code]call_mode[/code] détermine l'objet cible sur lequel la méthode sera "
+"appelée. Voir [enum CallMode] pour les options."
#: modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
msgid "The name of the function to be called."
@@ -82780,12 +83357,16 @@ msgid ""
"The node path to use when [member call_mode] is set to [constant "
"CALL_MODE_NODE_PATH]."
msgstr ""
+"Le chemin nœud à utiliser lorsque [member call_mode] est défini à [constant "
+"CALL_MODE_NODE_PATH]."
#: modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
msgid ""
"The mode for RPC calls. See [method Node.rpc] for more details and [enum "
"RPCCallMode] for available options."
msgstr ""
+"Le mode pour les appels RPC. Voir [method Node.rpc] pour plus de détails et ["
+"enum RPCCallMode] pour les options disponibles."
#: modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
msgid ""
@@ -82801,12 +83382,17 @@ msgid ""
"Can't be higher than the number of available default arguments in the "
"method's declaration."
msgstr ""
+"Le nombre d'arguments par défaut qui seront utilisés lors de l'appel de la "
+"fonction. Ne peut être supérieur au nombre d'arguments par défaut "
+"disponibles dans la déclaration de la méthode."
#: modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
msgid ""
"If [code]false[/code], call errors (e.g. wrong number of arguments) will be "
"ignored."
msgstr ""
+"Si [code]false[/code], les erreurs d'appel (par exemple le nombre erroné "
+"d'arguments) seront ignorées."
#: modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
msgid "The method will be called on this [Object]."
@@ -82815,12 +83401,15 @@ msgstr "La méthode sera appelée sur cet [Object]."
#: modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
msgid "The method will be called on the given [Node] in the scene tree."
msgstr ""
+"La méthode sera appelée sur le [Node] donné dans l'arborescence de la scène."
#: modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
msgid ""
"The method will be called on an instanced node with the given type and "
"script."
msgstr ""
+"La méthode sera appelée sur un nœud instancié avec le type et le script "
+"donnés."
#: modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
msgid "The method will be called on a GDScript basic type (e.g. [Vector2])."
@@ -82852,6 +83441,8 @@ msgid ""
"The method will be called remotely for the given peer, using an unreliable "
"protocol."
msgstr ""
+"La méthode sera appelée à distance pour le pair donné, en utilisant un "
+"protocole non fiable."
#: modules/visual_script/doc_classes/VisualScriptFunctionState.xml
msgid "A Visual Script node representing a function state."
@@ -82862,12 +83453,16 @@ msgid ""
"[VisualScriptFunctionState] is returned from [VisualScriptYield] and can be "
"used to resume a paused function call."
msgstr ""
+"[VisualScriptFunctionState] est retourné depuis [VisualScriptYield] et peut "
+"être utilisé pour reprendre un appel de fonction en pause."
#: modules/visual_script/doc_classes/VisualScriptFunctionState.xml
msgid ""
"Connects this [VisualScriptFunctionState] to a signal in the given object to "
"automatically resume when it's emitted."
msgstr ""
+"Connecte ce [VisualScriptFunctionState] à un signal dans l'objet donné pour "
+"reprendre automatiquement lorsqu'il est émis."
#: modules/visual_script/doc_classes/VisualScriptFunctionState.xml
msgid "Returns whether the function state is valid."
@@ -82876,61 +83471,63 @@ msgstr "Retourne si l'état de la fonction est valide."
#: modules/visual_script/doc_classes/VisualScriptFunctionState.xml
msgid "Resumes the function to run from the point it was yielded."
msgstr ""
+"Reprend la fonction à exécuter à partir du point où elle a été suspendue."
#: modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml
-#, fuzzy
msgid "A Visual Script node returning a constant from [@GlobalScope]."
-msgstr "Un nœud Visual Script utilisé pour annoter le script."
+msgstr "Un nœud Visual Script retournant une constante de [@GlobalScope]."
#: modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml
msgid "The constant to be used."
msgstr "La constante à utiliser."
#: modules/visual_script/doc_classes/VisualScriptIndexGet.xml
-#, fuzzy
msgid "A Visual Script node for getting a value from an array or a dictionary."
msgstr ""
-"Nœud de script visuel utilisé pour créer un tableau à partir d’une liste "
-"d’éléments."
+"Un nœud Visual Script pour obtenir une valeur d'un tableau ou d'un "
+"dictionnaire."
#: modules/visual_script/doc_classes/VisualScriptIndexGet.xml
msgid ""
"[VisualScriptIndexGet] will return the value stored in an array or a "
"dictionary under the given index."
msgstr ""
+"[VisualScriptIndexGet] retourne la valeur enregistrée dans un tableau ou un "
+"dictionnaire à l'index donné."
#: modules/visual_script/doc_classes/VisualScriptIndexSet.xml
-#, fuzzy
msgid "A Visual Script node for setting a value in an array or a dictionary."
msgstr ""
-"Nœud de script visuel utilisé pour créer un tableau à partir d’une liste "
-"d’éléments."
+"Un nœud Visual Script pour définir une valeur dans un tableau ou un "
+"dictionnaire."
#: modules/visual_script/doc_classes/VisualScriptIndexSet.xml
msgid ""
"[VisualScriptIndexSet] will set the value stored in an array or a dictionary "
"under the given index to the provided new value."
msgstr ""
+"[VisualScriptIndexSet] définira la valeur enregistrée dans un tableau ou un "
+"dictionnaire à l'index donné avec la nouvelle valeur fournie."
#: modules/visual_script/doc_classes/VisualScriptInputAction.xml
-#, fuzzy
msgid "A Visual Script node returning a state of an action."
-msgstr "Un nœud Visual Script utilisé pour annoter le script."
+msgstr "Un nœud Visual Script retournant l'état de l'action."
#: modules/visual_script/doc_classes/VisualScriptInputAction.xml
msgid ""
"[VisualScriptInputAction] can be used to check if an action is pressed or "
"released."
msgstr ""
+"[VisualScriptInputAction] peut être utilisé pour vérifier si une action est "
+"pressée ou relâchée."
#: modules/visual_script/doc_classes/VisualScriptInputAction.xml
msgid "Name of the action."
msgstr "Le nom de l'action."
#: modules/visual_script/doc_classes/VisualScriptInputAction.xml
-#, fuzzy
msgid "State of the action to check. See [enum Mode] for options."
-msgstr "La fonction à calculer. Voir [enum Function] pour les options."
+msgstr "L'état de l'action à vérifier. Voir [enum Mode] pour les options."
#: modules/visual_script/doc_classes/VisualScriptInputAction.xml
msgid "[code]True[/code] if action is pressed."
@@ -82969,32 +83566,31 @@ msgstr ""
#: modules/visual_script/doc_classes/VisualScriptLists.xml
msgid "A Visual Script virtual class for in-graph editable nodes."
msgstr ""
+"Une classe virtuelle Visual Script pour les nœuds modifiables dans le graphe."
#: modules/visual_script/doc_classes/VisualScriptLists.xml
msgid ""
"A Visual Script virtual class that defines the shape and the default "
"behavior of the nodes that have to be in-graph editable nodes."
msgstr ""
+"Une classe virtuelle Visual Script qui définit la forme et le comportement "
+"par défaut des nœuds qui doivent être des nœuds modifiables dans le graphe."
#: modules/visual_script/doc_classes/VisualScriptLists.xml
-#, fuzzy
msgid "Adds an input port to the Visual Script node."
-msgstr "Un nœud Visual Script scripté."
+msgstr "Ajoute un port d'entrée au nœud Visual Script."
#: modules/visual_script/doc_classes/VisualScriptLists.xml
-#, fuzzy
msgid "Adds an output port to the Visual Script node."
-msgstr "Un nœud Visual Script scripté."
+msgstr "Ajoute un port de sortie au nœud Visual Script."
#: modules/visual_script/doc_classes/VisualScriptLists.xml
-#, fuzzy
msgid "Removes an input port from the Visual Script node."
-msgstr "Supprime un nœud de la sélection."
+msgstr "Supprime un port d'entrée du nœud Visual Script."
#: modules/visual_script/doc_classes/VisualScriptLists.xml
-#, fuzzy
msgid "Removes an output port from the Visual Script node."
-msgstr "Supprime un nœud de la sélection."
+msgstr "Supprime un port de sortie du nœud Visual Script."
#: modules/visual_script/doc_classes/VisualScriptLists.xml
msgid "Sets the name of an input port."
@@ -83127,13 +83723,15 @@ msgstr ""
#: modules/visual_script/doc_classes/VisualScriptNode.xml
msgid "Returns the [VisualScript] instance the node is bound to."
-msgstr ""
+msgstr "Retourne l'instance [VisualScript] liée à ce nœud."
#: modules/visual_script/doc_classes/VisualScriptNode.xml
msgid ""
"Notify that the node's ports have changed. Usually used in conjunction with "
"[VisualScriptCustomNode] ."
msgstr ""
+"Notifie quand les ports de ce nœud ont changé. Habituellement utilisé avec "
+"[VisualScriptCustomNode] ."
#: modules/visual_script/doc_classes/VisualScriptNode.xml
msgid "Change the default value of a given port."
@@ -83144,11 +83742,8 @@ msgid "Emitted when the available input/output ports are changed."
msgstr "Émis quand les ports entrants/sortants sont changés."
#: modules/visual_script/doc_classes/VisualScriptOperator.xml
-#, fuzzy
msgid "A Visual Script node that performs an operation on two values."
-msgstr ""
-"Nœud de script visuel utilisé pour créer un tableau à partir d’une liste "
-"d’éléments."
+msgstr "Un nœud Visual Script qui effectue une opération sur deux valeurs."
#: modules/visual_script/doc_classes/VisualScriptOperator.xml
msgid ""
@@ -83160,21 +83755,18 @@ msgid ""
msgstr ""
#: modules/visual_script/doc_classes/VisualScriptOperator.xml
-#, fuzzy
msgid ""
"The operation to be performed. See [enum Variant.Operator] for available "
"options."
msgstr ""
-"Type de multiplication à effectuer. Voir [enum Operator] pour les options."
+"Le type d'opération à effectuer. Voir [enum Variant.Operator] pour les "
+"options disponibles."
#: modules/visual_script/doc_classes/VisualScriptOperator.xml
-#, fuzzy
msgid ""
"The type of the values for this operation. See [enum Variant.Type] for "
"available options."
msgstr ""
-"Définit la valeur d’un paramètre de zone. Voir [enum AreaParameter] pour une "
-"liste de paramètres disponibles."
#: modules/visual_script/doc_classes/VisualScriptPreload.xml
msgid "Creates a new [Resource] or loads one from the filesystem."
@@ -83195,17 +83787,17 @@ msgid "The [Resource] to load."
msgstr "La [Resource] à charger."
#: modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
-#, fuzzy
msgid "A Visual Script node returning a value of a property from an [Object]."
msgstr ""
-"Nœud de script visuel utilisé pour créer un tableau à partir d’une liste "
-"d’éléments."
+"Un nœud Visual Script retournant une valeur d'une propriété d'un [Object]."
#: modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
msgid ""
"[VisualScriptPropertyGet] can return a value of any property from the "
"current object or other objects."
msgstr ""
+"[VisualScriptPropertyGet] peut renvoyer une valeur de toute propriété de "
+"l'objet courant ou d'autres objets."
#: modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
#: modules/visual_script/doc_classes/VisualScriptPropertySet.xml
@@ -83213,6 +83805,8 @@ msgid ""
"The script to be used when [member set_mode] is set to [constant "
"CALL_MODE_INSTANCE]."
msgstr ""
+"Le script à utiliser lorsque [member set_mode] est défini à [constant "
+"CALL_MODE_INSTANCE]."
#: modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
#: modules/visual_script/doc_classes/VisualScriptPropertySet.xml
@@ -83220,6 +83814,8 @@ msgid ""
"The base type to be used when [member set_mode] is set to [constant "
"CALL_MODE_INSTANCE]."
msgstr ""
+"Le type de base à utiliser lorsque [member set_mode] est défini à [constant "
+"CALL_MODE_INSTANCE]."
#: modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
#: modules/visual_script/doc_classes/VisualScriptPropertySet.xml
@@ -83227,12 +83823,16 @@ msgid ""
"The type to be used when [member set_mode] is set to [constant "
"CALL_MODE_BASIC_TYPE]."
msgstr ""
+"Le type à utiliser lorsque [member set_mode] est défini à [constant "
+"CALL_MODE_BASIC_TYPE]."
#: modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
msgid ""
"The indexed name of the property to retrieve. See [method Object."
"get_indexed] for details."
msgstr ""
+"Le nom indexé de la propriété à récupérer. Voir [method Object.get_indexed] "
+"pour plus de détails."
#: modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
#: modules/visual_script/doc_classes/VisualScriptPropertySet.xml
@@ -83240,34 +83840,40 @@ msgid ""
"The node path to use when [member set_mode] is set to [constant "
"CALL_MODE_NODE_PATH]."
msgstr ""
+"Le chemin du nœud à utiliser lorsque [member set_mode] est défini à ["
+"constant CALL_MODE_NODE_PATH]."
#: modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
msgid ""
"The name of the property to retrieve. Changing this will clear [member "
"index]."
msgstr ""
+"Le nom de la propriété à récupérer. Changer cela effecera [member index]."
#: modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
msgid ""
"[code]set_mode[/code] determines the target object from which the property "
"will be retrieved. See [enum CallMode] for options."
msgstr ""
+"[code]set_mode[/code] détermine l'objet cible à partir duquel la propriété "
+"sera récupérée. Voir [enum CallMode] pour les options."
#: modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
msgid "The property will be retrieved from this [Object]."
msgstr "La propriété sera récupérée depuis cet [Object]."
#: modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
-#, fuzzy
msgid "The property will be retrieved from the given [Node] in the scene tree."
msgstr ""
-"Le propriété est sérialisé et sauvegardé dans le fichier de la scène(défaut)."
+"La propriété sera récupérée du [Node] donné dans l'arborescence de la scène."
#: modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
msgid ""
"The property will be retrieved from an instanced node with the given type "
"and script."
msgstr ""
+"La propriété sera récupérée à partir d'un nœud instancié avec le type et le "
+"script donnés."
#: modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
msgid ""
@@ -83277,23 +83883,23 @@ msgstr ""
"[Vector2])."
#: modules/visual_script/doc_classes/VisualScriptPropertySet.xml
-#, fuzzy
msgid "A Visual Script node that sets a property of an [Object]."
-msgstr "Un nœud Visual Script utilisé pour annoter le script."
+msgstr "Un nœud de script visuel qui définit une propriété d'un [Object]."
#: modules/visual_script/doc_classes/VisualScriptPropertySet.xml
msgid ""
"[VisualScriptPropertySet] can set the value of any property from the current "
"object or other objects."
msgstr ""
+"[VisualScriptPropertySet] peut définir la valeur de toute propriété à partir "
+"de l'objet courant ou d'autres objets."
#: modules/visual_script/doc_classes/VisualScriptPropertySet.xml
-#, fuzzy
msgid ""
"The additional operation to perform when assigning. See [enum AssignOp] for "
"options."
msgstr ""
-"L'opérateur additionelle à effectuer lors de l'assignation. Voir [enum "
+"L'opérateur d'addition à effectuer lors de l'assignation. Voir [enum "
"AssignOp] pour les options."
#: modules/visual_script/doc_classes/VisualScriptPropertySet.xml
@@ -83301,32 +83907,37 @@ msgid ""
"The indexed name of the property to set. See [method Object.set_indexed] for "
"details."
msgstr ""
+"Le nom indexé de la propriété à définir. Voir [method Object.set_indexed] "
+"pour plus de détails."
#: modules/visual_script/doc_classes/VisualScriptPropertySet.xml
msgid ""
"The name of the property to set. Changing this will clear [member index]."
-msgstr ""
+msgstr "Le nom de la propriété à définir. Changer cela effecera [member index]."
#: modules/visual_script/doc_classes/VisualScriptPropertySet.xml
msgid ""
"[code]set_mode[/code] determines the target object on which the property "
"will be set. See [enum CallMode] for options."
msgstr ""
+"[code]set_mode[/code] détermine l'objet cible sur lequel la propriété sera "
+"définie. Voir [enum CallMode] pour les options."
#: modules/visual_script/doc_classes/VisualScriptPropertySet.xml
msgid "The property will be set on this [Object]."
msgstr "La propriété sera définie dans cet [Object]."
#: modules/visual_script/doc_classes/VisualScriptPropertySet.xml
-#, fuzzy
msgid "The property will be set on the given [Node] in the scene tree."
msgstr ""
-"Le propriété est sérialisé et sauvegardé dans le fichier de la scène(défaut)."
+"La propriété sera placée sur le [Node] donné dans l'arborescence de la scène."
#: modules/visual_script/doc_classes/VisualScriptPropertySet.xml
msgid ""
"The property will be set on an instanced node with the given type and script."
msgstr ""
+"La propriété sera définie sur un nœud instancié avec le type et le script "
+"donnés."
#: modules/visual_script/doc_classes/VisualScriptPropertySet.xml
msgid "The property will be set on a GDScript basic type (e.g. [Vector2])."
@@ -83372,36 +83983,48 @@ msgid ""
"A modulo operation will be performed on the property and the value. "
"Equivalent of doing [code]%=[/code]."
msgstr ""
+"Une opération modulo sera effectuée sur la propriété et la valeur. Revient à "
+"écrire [code]%=[/code]."
#: modules/visual_script/doc_classes/VisualScriptPropertySet.xml
msgid ""
"The property will be binarly shifted to the left by the given value. "
"Equivalent of doing [code]<<[/code]."
msgstr ""
+"La propriété sera transférée à gauche par la valeur donnée. Revient de "
+"écrire [code]<<[/code]."
#: modules/visual_script/doc_classes/VisualScriptPropertySet.xml
msgid ""
"The property will be binarly shifted to the right by the given value. "
"Equivalent of doing [code]>>[/code]."
msgstr ""
+"La propriété sera transférée à droite par la valeur donnée. Revient de "
+"écrire [code]>>[/code]."
#: modules/visual_script/doc_classes/VisualScriptPropertySet.xml
msgid ""
"A binary [code]AND[/code] operation will be performed on the property. "
"Equivalent of doing [code]&=[/code]."
msgstr ""
+"Une opération binaire [code]AND[/code] (et) sera effectuée sur la propriété. "
+"Revient à écrire [code]&=[/code]."
#: modules/visual_script/doc_classes/VisualScriptPropertySet.xml
msgid ""
"A binary [code]OR[/code] operation will be performed on the property. "
"Equivalent of doing [code]|=[/code]."
msgstr ""
+"Une opération binaire [code]OR[/code] (ou) sera effectuée sur la propriété. "
+"Revient à écrire [code]|=[/code]."
#: modules/visual_script/doc_classes/VisualScriptPropertySet.xml
msgid ""
"A binary [code]XOR[/code] operation will be performed on the property. "
"Equivalent of doing [code]^=[/code]."
msgstr ""
+"Une opération binaire [code]XOR[/code] (ou exclusif) sera effectuée sur la "
+"propriété. Revient à écrire [code]^=[/code]."
#: modules/visual_script/doc_classes/VisualScriptReturn.xml
msgid "Exits a function and returns an optional value."
@@ -83536,9 +84159,8 @@ msgid ""
msgstr ""
#: modules/visual_script/doc_classes/VisualScriptTypeCast.xml
-#, fuzzy
msgid "A Visual Script node that casts the given value to another type."
-msgstr "Un nœud Visual Script utilisé pour annoter le script."
+msgstr ""
#: modules/visual_script/doc_classes/VisualScriptTypeCast.xml
msgid ""
@@ -83606,9 +84228,8 @@ msgid ""
msgstr ""
#: modules/visual_script/doc_classes/VisualScriptYield.xml
-#, fuzzy
msgid "A Visual Script node used to pause a function execution."
-msgstr "Un nœud Visual Script utilisé pour annoter le script."
+msgstr "Un nœud Visual Script pour mettre en pause l'exécution d'une fonction."
#: modules/visual_script/doc_classes/VisualScriptYield.xml
msgid ""
@@ -83617,11 +84238,11 @@ msgid ""
msgstr ""
#: modules/visual_script/doc_classes/VisualScriptYield.xml
-#, fuzzy
msgid ""
"The mode to use for yielding. See [enum YieldMode] for available options."
msgstr ""
-"Type de multiplication à effectuer. Voir [enum Operator] pour les options."
+"Le mode à utiliser pour suspendre. Voir [enum YieldMode] pour les options "
+"disponibles."
#: modules/visual_script/doc_classes/VisualScriptYield.xml
msgid "The time to wait when [member mode] is set to [constant YIELD_WAIT]."
@@ -83640,9 +84261,8 @@ msgid "Yields a function and waits the given time."
msgstr ""
#: modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
-#, fuzzy
msgid "A Visual Script node yielding for a signal."
-msgstr "Un nœud Visual Script utilisé pour annoter le script."
+msgstr "Un nœud Visual Script pour attendre un signal."
#: modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
msgid ""
@@ -83657,6 +84277,8 @@ msgid ""
"[code]call_mode[/code] determines the target object to wait for the signal "
"emission. See [enum CallMode] for options."
msgstr ""
+"[code]call_mode[/code] détermine l'objet cible à attendre avant l'émission "
+"du signal. Voir [enum CallMode] pour les options."
#: modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
msgid "The signal name to be waited for."
@@ -83668,11 +84290,11 @@ msgstr "Un signal depuis cet [Object] sera utilisé."
#: modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
msgid "A signal from the given [Node] in the scene tree will be used."
-msgstr ""
+msgstr "Un signal du [Node] donné dans l'arborescence de la scène sera utilisé."
#: modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
msgid "A signal from an instanced node with the given type will be used."
-msgstr ""
+msgstr "Un signal d'un nœud instancié avec le type donné sera utilisé."
#: doc/classes/VisualServer.xml
msgid "Server for anything visible."
@@ -83711,12 +84333,15 @@ msgstr ""
#: doc/classes/VisualServer.xml
msgid "Sets images to be rendered in the window margin."
msgstr ""
+"Définit des images dont le rendu sera fait dans les marges de la fenêtre."
#: doc/classes/VisualServer.xml
msgid ""
"Sets margin size, where black bars (or images, if [method "
"black_bars_set_images] was used) are rendered."
msgstr ""
+"Définit la taille de la marge, où des barres noires (ou des images, si ["
+"method black_bars_set_images] est utilisé) sont rendues."
#: doc/classes/VisualServer.xml
msgid ""
@@ -83781,6 +84406,10 @@ msgid ""
"the vertical aspect ratio which is equivalent to [constant Camera."
"KEEP_HEIGHT]."
msgstr ""
+"Si [code]true[/code], conserve le rapport d'aspect horizontal qui est "
+"équivalent à [constant Camera.KEEP_WIDTH]. Si [code]false[/code], conserve "
+"le rapport d'aspect vertical qui est équivalent à [constant Camera."
+"KEEP_HEIGHT]."
#: doc/classes/VisualServer.xml
msgid ""
@@ -83801,12 +84430,9 @@ msgid "Adds a circle command to the [CanvasItem]'s draw commands."
msgstr "Ajouter un cercle aux commandes de dessin du [CanvasItem]."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid ""
"If ignore is [code]true[/code], the VisualServer does not perform clipping."
msgstr ""
-"Si [code]true[/code], le multithreading est utilisé pour améliorer les "
-"performances."
#: doc/classes/VisualServer.xml
msgid "Adds a line command to the [CanvasItem]'s draw commands."
@@ -83821,6 +84447,8 @@ msgid ""
"Adds a [MultiMesh] to the [CanvasItem]'s draw commands. Only affects its "
"aabb at the moment."
msgstr ""
+"Ajoute un [MultiMesh] aux commandes d'affichage du [CanvasItem]. N'affecte "
+"que son aabb pour le moment."
#: doc/classes/VisualServer.xml
msgid ""
@@ -83842,6 +84470,8 @@ msgid ""
"Adds a polyline, which is a line from multiple points with a width, to the "
"[CanvasItem]'s draw commands."
msgstr ""
+"Ajoute une suite de lignes, qui est une ligne de plusieurs points avec une "
+"largeur, aux commandes d'affichage du [CanvasItem]."
#: doc/classes/VisualServer.xml
msgid "Adds a primitive to the [CanvasItem]'s draw commands."
@@ -83866,6 +84496,8 @@ msgstr "Ajouter un rectangle texturé aux commandes de dessin du [CanvasItem]."
msgid ""
"Adds a texture rect with region setting to the [CanvasItem]'s draw commands."
msgstr ""
+"Ajoute un rectangle de texture, avec des réglages de la région à afficher, "
+"aux commandes d'affichage du [CanvasItem]."
#: doc/classes/VisualServer.xml
msgid "Adds a triangle array to the [CanvasItem]'s draw commands."
@@ -83874,7 +84506,7 @@ msgstr ""
#: doc/classes/VisualServer.xml
msgid "Clears the [CanvasItem] and removes all commands in it."
-msgstr ""
+msgstr "Efface le [CanvasItem] et enlève toutes les commandes."
#: doc/classes/VisualServer.xml
msgid ""
@@ -83891,7 +84523,6 @@ msgstr ""
"méthode statique [method free_rid] du VisualServer."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Sets clipping for the [CanvasItem]."
msgstr "Définit la coupure pour le [CanvasItem]."
@@ -83937,6 +84568,9 @@ msgid ""
"Sets the parent for the [CanvasItem]. The parent can be another canvas item, "
"or it can be the root canvas that is attached to the viewport."
msgstr ""
+"Définit le parent du [CanvasItem]. Le parent peut être un autre élément de "
+"toile, ou il peut être la toile racine qui est attachée à la fenêtre "
+"d'affichage."
#: doc/classes/VisualServer.xml
msgid "Sets the color that modulates the [CanvasItem] without children."
@@ -83958,9 +84592,8 @@ msgid "Sets if the [CanvasItem] uses its parent's material."
msgstr "Définit si le [CanvasItem] utilise le même matériau que son parent."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Sets if the canvas item (including its children) is visible."
-msgstr "Masquer le [CanvasItem] s’il est actuellement visible."
+msgstr "Définit si la toile (y compris ses enfants) est visible."
#: doc/classes/VisualServer.xml
msgid ""
@@ -84043,9 +84676,8 @@ msgid "Sets a canvas light's energy."
msgstr "Définit l'énergie d'une lumière du canevas."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Sets a canvas light's height."
-msgstr "Définit la hauteur d’une toile."
+msgstr ""
#: doc/classes/VisualServer.xml
msgid ""
@@ -84059,19 +84691,23 @@ msgstr ""
#: doc/classes/VisualServer.xml
msgid "The mode of the light, see [enum CanvasLightMode] constants."
-msgstr ""
+msgstr "Le mode de la lumière, voir les constantes [enum CanvasLightMode]."
#: doc/classes/VisualServer.xml
msgid ""
"Sets the texture's scale factor of the light. Equivalent to [member Light2D."
"texture_scale]."
msgstr ""
+"Définit le facteur d'échelle de la texture de lumière. Équivalent à [member "
+"Light2D.texture_scale]"
#: doc/classes/VisualServer.xml
msgid ""
"Sets the width of the shadow buffer, size gets scaled to the next power of "
"two for this."
msgstr ""
+"Définit la largeur du tampon d'ombre, la taille est arrondie à la puissance "
+"de deux suivante pour cela."
#: doc/classes/VisualServer.xml
msgid "Sets the color of the canvas light's shadow."
@@ -84143,11 +84779,11 @@ msgstr ""
#: doc/classes/VisualServer.xml
msgid "Sets the shape of the occluder polygon."
-msgstr ""
+msgstr "Définit la forme du polygone occulteur."
#: doc/classes/VisualServer.xml
msgid "Sets the shape of the occluder polygon as lines."
-msgstr ""
+msgstr "Définit la forme du polygone occulteur avec des lignes."
#: doc/classes/VisualServer.xml
msgid ""
@@ -84209,6 +84845,8 @@ msgstr ""
#: doc/classes/VisualServer.xml
msgid "Sets the ambient light parameters. See [Environment] for more details."
msgstr ""
+"Définit les paramètres de lumière ambiante. Voir [Environnement] pour plus "
+"de détails."
#: doc/classes/VisualServer.xml
msgid ""
@@ -84250,18 +84888,24 @@ msgid ""
"Sets the variables to be used with the scene fog. See [Environment] for more "
"details."
msgstr ""
+"Définit les variables à utiliser avec le brouillard de scène. Voir "
+"[Environnement] pour plus de détails."
#: doc/classes/VisualServer.xml
msgid ""
"Sets the variables to be used with the fog depth effect. See [Environment] "
"for more details."
msgstr ""
+"Définit les variables à utiliser avec l'effet de profondeur du brouillard. "
+"Voir [Environnement] pour plus de détails."
#: doc/classes/VisualServer.xml
msgid ""
"Sets the variables to be used with the fog height effect. See [Environment] "
"for more details."
msgstr ""
+"Définit les variables à utiliser avec l'effet de hauteur du brouillard. Voir "
+"[Environnement] pour plus de détails."
#: doc/classes/VisualServer.xml
msgid ""
@@ -84280,12 +84924,16 @@ msgid ""
"Sets a custom field of view for the background [Sky]. Equivalent to [member "
"Environment.background_sky_custom_fov]."
msgstr ""
+"Définit un angle de vue personnalisé pour le ciel [Sky] en arrière-plan. "
+"Équivalent à [member Environnement.background_sky_custom_fov]"
#: doc/classes/VisualServer.xml
msgid ""
"Sets the rotation of the background [Sky] expressed as a [Basis]. Equivalent "
"to [member Environment.background_sky_orientation]."
msgstr ""
+"Définit la rotation du ciel [Sky] en arrière-plan exprimé avec une [Basis]. "
+"Équivalent à [member Environnement.background_sky_orientation]"
#: doc/classes/VisualServer.xml
msgid ""
@@ -84329,6 +84977,7 @@ msgstr "Essaye de supprimer un objet dans le VisualServer."
#: doc/classes/VisualServer.xml
msgid "Returns a certain information, see [enum RenderInfo] for options."
msgstr ""
+"Retourne une information précise, voir [enum RenderInfo] pour les options."
#: doc/classes/VisualServer.xml
msgid "Returns the id of the test cube. Creates one if none exists."
@@ -84346,6 +84995,10 @@ msgid ""
"[b]Note:[/b] When running a headless or server binary, this function returns "
"an empty string."
msgstr ""
+"Retourne le nom de l'adaptateur vidéo (par exemple \"GeForce GTX 1080/PCIe/"
+"SSE2\").\n"
+"[b]Note :[/b] Lors de l'exécution d'une version sans graphique ou de "
+"serveur, cette fonction retourne une chaîne vide."
#: doc/classes/VisualServer.xml
msgid ""
@@ -84353,6 +85006,10 @@ msgid ""
"[b]Note:[/b] When running a headless or server binary, this function returns "
"an empty string."
msgstr ""
+"Retourne le vendeur de l'adaptateur vidéo (par exemple \"NVIDIA Corporation\""
+").\n"
+"[b]Note :[/b] Lors de l'exécution d'une version sans graphique ou de "
+"serveur, cette fonction retourne une chaîne vide."
#: doc/classes/VisualServer.xml
msgid "Returns the id of a white texture. Creates one if none exists."
@@ -84395,21 +85052,24 @@ msgstr ""
"Retourne la taille de la cellule définit par [method gi_probe_set_cell_size]."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Returns the data used by the GI probe."
-msgstr "Renvoie l’espace affecté à la zone."
+msgstr "Retourne les données utilisées par la sonde GI."
#: doc/classes/VisualServer.xml
msgid ""
"Returns the dynamic range set for this GI probe. Equivalent to [member "
"GIProbe.dynamic_range]."
msgstr ""
+"Retourne la gamme dynamique pour cette sonde GI. Équivalent à [member GIProbe"
+".dynamic_range]"
#: doc/classes/VisualServer.xml
msgid ""
"Returns the energy multiplier for this GI probe. Equivalent to [member "
"GIProbe.energy]."
msgstr ""
+"Retourne le multiplicateur d'énergie pour cette sonde GI. Équivalent à ["
+"member GIProbe.energy]"
#: doc/classes/VisualServer.xml
msgid ""
@@ -84422,6 +85082,8 @@ msgid ""
"Returns the propagation value for this GI probe. Equivalent to [member "
"GIProbe.propagation]."
msgstr ""
+"Retourne la valeur de propagation de cette sonde GI. Équivalent à [member "
+"GIProbe.propagation]"
#: doc/classes/VisualServer.xml
msgid "Returns the Transform set by [method gi_probe_set_to_cell_xform]."
@@ -84432,15 +85094,14 @@ msgid ""
"Returns [code]true[/code] if the GI probe data associated with this GI probe "
"is compressed. Equivalent to [member GIProbe.compress]."
msgstr ""
+"Retourne [code]true[/code] si les données de cette sonde GI sont "
+"compressées. Équivalent à [member GIProbe.compress]"
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid ""
"Returns [code]true[/code] if the GI probe is set to interior, meaning it "
"does not account for sky light. Equivalent to [member GIProbe.interior]."
msgstr ""
-"Si [code]true[/code], les réflexions ignoreront la contribution du ciel. "
-"Équivalent à [member ReflectionProbe.interior]."
#: doc/classes/VisualServer.xml
msgid ""
@@ -84506,9 +85167,8 @@ msgid ""
msgstr ""
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Sets the to cell [Transform] for this GI probe."
-msgstr "Retourne la matrice de transformation globale de cet élément."
+msgstr ""
#: doc/classes/VisualServer.xml
msgid ""
@@ -84591,9 +85251,8 @@ msgid ""
msgstr ""
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Sets the material to be used to draw the [ImmediateGeometry]."
-msgstr "Retourne le matériel affecté à la [ImmediateGeometry3D]."
+msgstr "Définit le matériel utilisé pour afficher le [ImmediateGeometry]."
#: doc/classes/VisualServer.xml
msgid ""
@@ -84875,13 +85534,10 @@ msgid ""
msgstr ""
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid ""
"If [code]true[/code], light will subtract light instead of adding light. "
"Equivalent to [member Light.light_negative]."
msgstr ""
-"Si [code]true[/code], les réflexions ignoreront la contribution du ciel. "
-"Équivalent à [member ReflectionProbe.interior]."
#: doc/classes/VisualServer.xml
msgid ""
@@ -84899,13 +85555,10 @@ msgid ""
msgstr ""
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid ""
"If [code]true[/code], light will cast shadows. Equivalent to [member Light."
"shadow_enabled]."
msgstr ""
-"Si [code]true[/code], les réflexions ignoreront la contribution du ciel. "
-"Équivalent à [member ReflectionProbe.interior]."
#: doc/classes/VisualServer.xml
msgid ""
@@ -84942,19 +85595,16 @@ msgstr ""
"en utilisant la [method instance_set_base] utilisant le RID retourné."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Returns the size of the lightmap capture area."
-msgstr "Renvoie le sinus du paramètre."
+msgstr ""
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Returns the energy multiplier used by the lightmap capture."
-msgstr "Renvoie le nombre de textures dans l’atlas BitmapFont."
+msgstr ""
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Returns the octree used by the lightmap capture."
-msgstr "Renvoie l’espace affecté à la zone."
+msgstr ""
#: doc/classes/VisualServer.xml
msgid ""
@@ -84962,9 +85612,8 @@ msgid ""
msgstr ""
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Returns the cell transform for this lightmap capture's octree."
-msgstr "Retourne la matrice de transformation de la toile de cet objet."
+msgstr ""
#: doc/classes/VisualServer.xml
msgid "Returns [code]true[/code] if capture is in \"interior\" mode."
@@ -85032,13 +85681,10 @@ msgid "Returns the value of a certain material's parameter."
msgstr "Retourne la valeur du paramètre du matériau."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid ""
"Returns the default value for the param if available. Returns [code]null[/"
"code] otherwise."
msgstr ""
-"Retourne la valeur par défaut du paramètre nommé [code]name[/code] du "
-"matériau."
#: doc/classes/VisualServer.xml
msgid ""
@@ -85055,9 +85701,8 @@ msgid "Sets an object's next material."
msgstr "Définit le prochain matériau d’un objet."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Sets a material's parameter."
-msgstr "Définit le paramètre d’un matériau."
+msgstr "Définit le paramètre d'un matériau."
#: doc/classes/VisualServer.xml
msgid "Sets a material's render priority."
@@ -85120,7 +85765,7 @@ msgstr "Supprime la surface d'un maillage."
#: doc/classes/VisualServer.xml
#, fuzzy
msgid "Sets a mesh's blend shape count."
-msgstr "Retourne le nombre de formes de mélange d’un maillage."
+msgstr "Définit le nombre de formes de mélange d’un maillage."
#: doc/classes/VisualServer.xml
msgid "Sets a mesh's blend shape mode."
@@ -85135,19 +85780,16 @@ msgid "Returns a mesh's surface's aabb."
msgstr "Retourne l’aabb de la surface d'un maillage."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Returns a mesh's surface's vertex buffer."
-msgstr "Retourne l’aabb personnalisé d’un maillage."
+msgstr ""
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Returns a mesh's surface's amount of indices."
-msgstr "Renvoie le nombre de points de la Ligne2D."
+msgstr ""
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Returns a mesh's surface's amount of vertices."
-msgstr "Renvoie le nombre de points de la Ligne2D."
+msgstr ""
#: doc/classes/VisualServer.xml
msgid "Returns a mesh's surface's buffer arrays."
@@ -85158,32 +85800,28 @@ msgid "Returns a mesh's surface's arrays for blend shapes."
msgstr ""
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Returns the format of a mesh's surface."
-msgstr "Retourne le nom de la méthode d'une piste de méthode."
+msgstr "Retourne le format d'une surface d'un maillage."
#: doc/classes/VisualServer.xml
msgid "Function is unused in Godot 3.x."
msgstr "Cette fonction n'est pas utilisée dans Godot 3.x."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Returns a mesh's surface's index buffer."
-msgstr "Retourne le mode de forme de mélange d’un maillage."
+msgstr ""
#: doc/classes/VisualServer.xml
msgid "Returns a mesh's surface's material."
msgstr "Retourne le matériau de la surface du maillage."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Returns the primitive type of a mesh's surface."
-msgstr "Retourne le nom de la méthode d'une piste de méthode."
+msgstr ""
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Returns the aabb of a mesh's surface's skeleton."
-msgstr "Retourne la traduction d’un message."
+msgstr ""
#: doc/classes/VisualServer.xml
msgid "Sets a mesh's surface's material."
@@ -85457,13 +86095,10 @@ msgid ""
msgstr ""
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid ""
"If [code]true[/code], uses fractional delta which smooths the movement of "
"the particles. Equivalent to [member Particles.fract_delta]."
msgstr ""
-"Si [code]true[/code], les réflexions ignoreront la contribution du ciel. "
-"Équivalent à [member ReflectionProbe.interior]."
#: doc/classes/VisualServer.xml
msgid ""
@@ -85533,13 +86168,12 @@ msgstr ""
"retourné."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid ""
"If [code]true[/code], reflections will ignore sky contribution. Equivalent "
"to [member ReflectionProbe.interior_enable]."
msgstr ""
"Si [code]true[/code], les réflexions ignoreront la contribution du ciel. "
-"Équivalent à [member ReflectionProbe.interior]."
+"Équivalent à [member ReflectionProbe.interior_enable]."
#: doc/classes/VisualServer.xml
msgid ""
@@ -85575,23 +86209,17 @@ msgid ""
msgstr ""
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid ""
"Sets the ambient light color for this reflection probe when set to interior "
"mode. Equivalent to [member ReflectionProbe.interior_ambient_color]."
msgstr ""
-"Si [code]true[/code], les réflexions ignoreront la contribution du ciel. "
-"Équivalent à [member ReflectionProbe.interior]."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid ""
"Sets the energy multiplier for this reflection probes ambient light "
"contribution when set to interior mode. Equivalent to [member "
"ReflectionProbe.interior_ambient_energy]."
msgstr ""
-"Si [code]true[/code], les réflexions ignoreront la contribution du ciel. "
-"Équivalent à [member ReflectionProbe.interior]."
#: doc/classes/VisualServer.xml
msgid ""
@@ -85709,9 +86337,8 @@ msgid ""
msgstr ""
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Enables or disables occlusion culling."
-msgstr "Active ou désactive une lumière du canevas."
+msgstr "Active ou désactive le culling de l'occlusion."
#: doc/classes/VisualServer.xml
msgid ""
@@ -85728,7 +86355,6 @@ msgstr ""
"méthode statique [method free_rid] du VisualServer."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Returns a shader's code."
msgstr "Retourne le code d'un shader."
@@ -85741,7 +86367,6 @@ msgid "Returns the parameters of a shader."
msgstr "Retourne les paramètres d'un shader."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Sets a shader's code."
msgstr "Définit le code d'un shader."
@@ -85826,14 +86451,12 @@ msgstr ""
"utilisant la [method instance_set_base] utilisant le RID retourné."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Allocates the GPU memory for the texture."
-msgstr "La largeur de la texture."
+msgstr ""
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Binds the texture to a texture slot."
-msgstr "Alignez le texte à gauche."
+msgstr ""
#: doc/classes/VisualServer.xml
msgid ""
@@ -85856,9 +86479,8 @@ msgstr ""
"Crée une texture, alloue l'espace pour une image, et remplit avec l'image."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Returns a list of all the textures and their information."
-msgstr "Retourne le nombre de pistes dans l'animation."
+msgstr ""
#: doc/classes/VisualServer.xml
msgid ""
@@ -85877,9 +86499,8 @@ msgid "Returns the flags of a texture."
msgstr "Retourne les drapeaux de la texture."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Returns the format of the texture's image."
-msgstr "Renvoie le reste de deux vecteurs."
+msgstr ""
#: doc/classes/VisualServer.xml
msgid "Returns the texture's height."
@@ -85980,13 +86601,10 @@ msgid ""
msgstr ""
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid ""
"If [code]true[/code], the image will be stored in the texture's images array "
"if overwritten."
msgstr ""
-"Si [code]true[/code], la [SpinBox] sera modifiable. Sinon, elle sera en "
-"lecture seule."
#: doc/classes/VisualServer.xml
msgid "Sets a viewport's camera."
@@ -85997,7 +86615,6 @@ msgid "Sets a viewport's canvas."
msgstr "Définit le canevas de la fenêtre d'affichage."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid ""
"Copies viewport to a region of the screen specified by [code]rect[/code]. If "
"[member Viewport.render_direct_to_screen] is [code]true[/code], then "
@@ -86034,7 +86651,7 @@ msgstr ""
" $Viewport.set_attach_to_screen_rect(Rect2(0, 0, 600, 600))\n"
"[/codeblock]\n"
"Utiliser cette méthode peut permettre d'améliorer considérablement les "
-"performances, surtout sur les appareils peut puissants. Par contre, cela "
+"performances, surtout sur les appareils peu puissants. Par contre, cela "
"nécessite de gérer manuellement les fenêtres d'affichage. Pour plus "
"d'optimisations, voir [method viewport_set_render_direct_to_screen]."
@@ -86212,11 +86829,10 @@ msgid ""
msgstr ""
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid ""
"Sets the viewport's 2D/3D mode. See [enum ViewportUsage] constants for "
"options."
-msgstr "Convertit le format de l’image. Voir les constantes [enum Format]."
+msgstr ""
#: doc/classes/VisualServer.xml
msgid ""
@@ -86290,16 +86906,12 @@ msgid "Number of weights/bones per vertex."
msgstr "Nombre de poids / os par sommet."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "The minimum Z-layer for canvas items."
-msgstr ""
-"Le niveau minimal du calque de profondeur pour les éléments de canevas."
+msgstr "Le niveau minimal du calque de profondeur pour les éléments de canevas."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "The maximum Z-layer for canvas items."
-msgstr ""
-"Le niveau maximal du calque de profondeur pour les éléments de canevas."
+msgstr "Le niveau maximal du calque de profondeur pour les éléments de canevas."
#: doc/classes/VisualServer.xml
msgid ""
@@ -86361,7 +86973,6 @@ msgid "A 3-dimensional texture with width, height, and depth."
msgstr "Une texture à 3 dimensions, largeur et hauteur, et profondeur."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Repeats the texture (instead of clamp to edge)."
msgstr "Répète la texture (plutôt que de s'arrêter aux bordures)."
@@ -86755,9 +87366,8 @@ msgid "Number of draw calls during this frame."
msgstr "Nombre d'appels d'affichage pour cette trame."
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid "Number of 2d items drawn this frame."
-msgstr "Nombre de changements de surface pendant cette image."
+msgstr "Le nombre d'éléments 2D affichés dans cette trame."
#: doc/classes/VisualServer.xml
msgid "Number of 2d draw calls during this frame."
@@ -87432,11 +88042,8 @@ msgstr "Sera traduit en [code]uniform bool[/code] dans le code du shader."
#: doc/classes/VisualShaderNodeScalarUniform.xml
#: doc/classes/VisualShaderNodeTransformUniform.xml
#: doc/classes/VisualShaderNodeVec3Uniform.xml
-#, fuzzy
msgid "A default value to be assigned within the shader."
msgstr ""
-"Un opérateur scalaire à virgule flottante à utiliser dans le graphique du "
-"nuanceur visuel."
#: doc/classes/VisualShaderNodeBooleanUniform.xml
#: doc/classes/VisualShaderNodeColorUniform.xml
@@ -87729,7 +88336,6 @@ msgid ""
msgstr ""
#: doc/classes/VisualShaderNodeCompare.xml
-#, fuzzy
msgid ""
"The result will be true if all of component in vector satisfy the comparison "
"condition."
@@ -87738,7 +88344,6 @@ msgstr ""
"condition de comparaison."
#: doc/classes/VisualShaderNodeCompare.xml
-#, fuzzy
msgid ""
"The result will be true if any of component in vector satisfy the comparison "
"condition."
@@ -87747,11 +88352,8 @@ msgstr ""
"condition de comparaison."
#: doc/classes/VisualShaderNodeCubeMap.xml
-#, fuzzy
msgid "A [CubeMap] sampling node to be used within the visual shader graph."
msgstr ""
-"Un opérateur scalaire à virgule flottante à utiliser dans le graphique du "
-"nuanceur visuel."
#: doc/classes/VisualShaderNodeCubeMap.xml
msgid ""
@@ -87818,11 +88420,8 @@ msgid ""
msgstr ""
#: doc/classes/VisualShaderNodeCubeMapUniform.xml
-#, fuzzy
msgid "A [CubeMap] uniform node to be used within the visual shader graph."
msgstr ""
-"Un tableau uniforme de texture 2D à utiliser dans le graphique de l'ombrage "
-"visuel."
#: doc/classes/VisualShaderNodeCubeMapUniform.xml
msgid ""
@@ -88498,13 +89097,12 @@ msgid "Defaults to black color."
msgstr "Par défaut à la couleur noire."
#: doc/classes/VisualShaderNodeTextureUniformTriplanar.xml
-#, fuzzy
msgid ""
"Performs a uniform texture lookup with triplanar within the visual shader "
"graph."
msgstr ""
-"Effectue une recherche de texture uniforme avec triplanaire dans le "
-"graphique de nuanceur visuel."
+"Effectue une projection de texture uniforme en triplanaire dans le graphe du "
+"Visual Shader."
#: doc/classes/VisualShaderNodeTextureUniformTriplanar.xml
msgid ""
@@ -88513,12 +89111,11 @@ msgid ""
msgstr ""
#: doc/classes/VisualShaderNodeTransformCompose.xml
-#, fuzzy
msgid ""
"Composes a [Transform] from four [Vector3]s within the visual shader graph."
msgstr ""
-"Compose un [Transform] à partir de quatre [Vector3] dans le graphique du "
-"nuanceur visuel."
+"Compose un [Transform] à partir de quatre [Vector3] dans le graphe du Visual "
+"Shader."
#: doc/classes/VisualShaderNodeTransformCompose.xml
msgid ""
@@ -88632,11 +89229,10 @@ msgid "Translated to [code]uniform mat4[/code] in the shader language."
msgstr "Sera traduit en [code]uniform mat4[/code] dans le code du shader."
#: doc/classes/VisualShaderNodeTransformVecMult.xml
-#, fuzzy
msgid ""
"Multiplies a [Transform] and a [Vector3] within the visual shader graph."
msgstr ""
-"Multiplie un [Transform] et un [Vector3] dans le graphique de shader visuel."
+"Multiplie un [Transform] et un [Vector3] dans le graphe du Visual Shader."
#: doc/classes/VisualShaderNodeTransformVecMult.xml
msgid ""
@@ -88679,7 +89275,7 @@ msgstr ""
#: doc/classes/VisualShaderNodeUniform.xml
#, fuzzy
msgid "A base type for the uniforms within the visual shader graph."
-msgstr "Type de base pour les uniformes dans le graphique du nuanceur visuel."
+msgstr "Le type de base pour les uniformes dans le graphe du Visual Shader."
#: doc/classes/VisualShaderNodeUniform.xml
msgid ""
@@ -89236,10 +89832,9 @@ msgid "Closes this data channel, notifying the other peer."
msgstr "Ferme ce canal de données, en notifiant l’autre homologue."
#: modules/webrtc/doc_classes/WebRTCDataChannel.xml
-#, fuzzy
msgid ""
"Returns the number of bytes currently queued to be sent over this channel."
-msgstr "Retourne le nombre de traqueurs actuellement enregistrés."
+msgstr ""
#: modules/webrtc/doc_classes/WebRTCDataChannel.xml
msgid ""
@@ -89330,7 +89925,6 @@ msgid "The channel was created, but it's still trying to connect."
msgstr "Le canal a été créé, mais il essaie toujours de se connecter."
#: modules/webrtc/doc_classes/WebRTCDataChannel.xml
-#, fuzzy
msgid "The channel is currently open, and data can flow over it."
msgstr "Le canal est actuellement ouvert, et les données peuvent y circuler."
@@ -89439,9 +90033,8 @@ msgid ""
msgstr ""
#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml
-#, fuzzy
msgid "Interface to a WebRTC peer connection."
-msgstr "Interface vers une connexion homologue WebRTC."
+msgstr "L'interface de connexion par pair via WebRTC."
#: modules/webrtc/doc_classes/WebRTCPeerConnection.xml
msgid ""
@@ -90495,14 +91088,12 @@ msgid ""
msgstr ""
#: doc/classes/WindowDialog.xml
-#, fuzzy
msgid "The vertical offset of the title text."
-msgstr "Décalage vertical du texte du titre."
+msgstr "Le décalage vertical du texte du titre."
#: doc/classes/WindowDialog.xml
-#, fuzzy
msgid "The font used to draw the title."
-msgstr "La police utilisée pour le texte en gras."
+msgstr ""
#: doc/classes/WindowDialog.xml
msgid "The icon for the close button."
@@ -90548,10 +91139,9 @@ msgid ""
msgstr ""
#: doc/classes/World.xml
-#, fuzzy
msgid ""
"The [RID] of this world's navigation map. Used by the [NavigationServer]."
-msgstr "Retourne le [RID] de la énième forme d'une zone."
+msgstr ""
#: doc/classes/World.xml
msgid "The World's visual scenario."
@@ -90586,10 +91176,9 @@ msgid ""
msgstr ""
#: doc/classes/World2D.xml
-#, fuzzy
msgid ""
"The [RID] of this world's navigation map. Used by the [Navigation2DServer]."
-msgstr "Retourne le [RID] de la énième forme d'une zone."
+msgstr ""
#: doc/classes/World2D.xml
msgid ""
diff --git a/doc/translations/it.po b/doc/translations/it.po
index 3acfabc091..e07c906b29 100644
--- a/doc/translations/it.po
+++ b/doc/translations/it.po
@@ -30,8 +30,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine class reference\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
-"PO-Revision-Date: 2022-07-23 03:56+0000\n"
-"Last-Translator: AndreWharn <andrewharnofficial@gmail.com>\n"
+"PO-Revision-Date: 2022-07-31 16:43+0000\n"
+"Last-Translator: Mirko <miknsop@gmail.com>\n"
"Language-Team: Italian <https://hosted.weblate.org/projects/godot-engine/"
"godot-class-reference/it/>\n"
"Language: it\n"
@@ -62,6 +62,7 @@ msgid "Theme Properties"
msgstr "Proprietà del tema"
#: doc/tools/make_rst.py
+#, fuzzy
msgid "Signals"
msgstr "Segnali"
@@ -56960,7 +56961,7 @@ msgstr ""
#: doc/classes/Spatial.xml
msgid "Introduction to 3D"
-msgstr ""
+msgstr "Introduzione al 3D"
#: doc/classes/Spatial.xml doc/classes/Vector3.xml
msgid "All 3D Demos"
diff --git a/doc/translations/pt_BR.po b/doc/translations/pt_BR.po
index 74758850c7..ea624fdf2c 100644
--- a/doc/translations/pt_BR.po
+++ b/doc/translations/pt_BR.po
@@ -41,12 +41,13 @@
# Fabio Moura de Oliveira <ccmaismais@yahoo.com>, 2022.
# Daniel Abrante <danielabrante@protonmail.com>, 2022.
# lucas rossy brasil coelho <lucasrossy270@gmail.com>, 2022.
+# Felipe Kinoshita <kinofhek@gmail.com>, 2022.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine class reference\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
-"PO-Revision-Date: 2022-06-16 18:58+0000\n"
-"Last-Translator: lucas rossy brasil coelho <lucasrossy270@gmail.com>\n"
+"PO-Revision-Date: 2022-08-04 06:40+0000\n"
+"Last-Translator: Felipe Kinoshita <kinofhek@gmail.com>\n"
"Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/"
"godot-engine/godot-class-reference/pt_BR/>\n"
"Language: pt_BR\n"
@@ -54,7 +55,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.13-dev\n"
+"X-Generator: Weblate 4.14-dev\n"
#: doc/tools/make_rst.py
msgid "Description"
@@ -76754,6 +76755,13 @@ msgid ""
"the same space as the parent YSort, allowing to better organize a scene or "
"divide it in multiple ones, yet keep the unique sorting."
msgstr ""
+"Classifique todos os nós filhos com base em suas posições Y. O nó filho deve "
+"herdar de [CanvasItem] para ser classificado. Os nós que têm uma posição Y "
+"mais alta serão desenhados mais tarde, então eles aparecerão no topo dos nós "
+"que têm uma posição Y mais baixa. O aninhamento de nós YSort é possível. Os "
+"nós YSort filhos serão classificados no mesmo espaço que o YSort pai, "
+"permitindo organizar melhor uma cena ou dividi-la em várias outras, mas "
+"manter a classificação única."
#: doc/classes/YSort.xml
msgid ""
diff --git a/doc/translations/ru.po b/doc/translations/ru.po
index 985198198a..b148868ce6 100644
--- a/doc/translations/ru.po
+++ b/doc/translations/ru.po
@@ -49,21 +49,22 @@
# FuzzMix <fmwolfiechad@gmail.com>, 2022.
# МÐÐ69К <weblate@mah69k.net>, 2022.
# Vadim Mitroshkin <Vadim7540@yandex.ru>, 2022.
+# SonicStalker Games <dmitriyusolsev1971@gmail.com>, 2022.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine class reference\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
-"PO-Revision-Date: 2022-07-03 00:44+0000\n"
-"Last-Translator: Bozhko Artyom Dmitrievich <jek_sun@mail.ru>\n"
+"PO-Revision-Date: 2022-08-04 06:40+0000\n"
+"Last-Translator: SonicStalker Games <dmitriyusolsev1971@gmail.com>\n"
"Language-Team: Russian <https://hosted.weblate.org/projects/godot-engine/"
"godot-class-reference/ru/>\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8-bit\n"
-"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
-"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 4.13.1-dev\n"
+"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
+"X-Generator: Weblate 4.14-dev\n"
#: doc/tools/make_rst.py
msgid "Description"
@@ -620,11 +621,11 @@ msgstr ""
"[codeblock]\n"
"- Меньше -1,0 (не включаÑ): Облегчение вхождениÑ-выхождениÑ\n"
"- 1.0: Линейный\n"
-"- От -1,0 до 0,0 (не включаÑ): Облегчение в\n"
+"- От -1,0 до 0,0 (не включаÑ): Облегчение выхождениÑ-вхождениÑ\n"
"- 0.0: ПоÑтоÑнный\n"
-"- От 0,0 до 1,0 (не включаÑ): Облегчение\n"
+"- От 0,0 до 1,0 (не включаÑ): Облегчение выхождениÑ(только выход)\n"
"- 1.0: Линейный\n"
-"- Больше 1,0 (не включаÑ): Облегчение\n"
+"- Больше 1,0 (не включаÑ): Облегчение вхождениÑ(только вход)\n"
"[/codeblock]\n"
"[url=https://raw.githubusercontent.com/godotengine/godot-docs/3.4/img/"
"ease_cheatsheet.png]ease() Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ ÐºÑ€Ð¸Ð²Ð¾Ð¹ шпаргалка[/url]\n"
@@ -1402,7 +1403,6 @@ msgstr ""
"траÑÑировка Ñтека при печати ошибки или предупреждениÑ."
#: modules/gdscript/doc_classes/@GDScript.xml
-#, fuzzy
msgid ""
"Like [method print], but includes the current stack frame when running with "
"the debugger turned on.\n"
@@ -1412,10 +1412,12 @@ msgid ""
" At: res://test.gd:15:_process()\n"
"[/codeblock]"
msgstr ""
-"Печатает трек Ñтека вызовов, работает только еÑли включён отладчик.\n"
+"Как [method print], но включает в ÑÐµÐ±Ñ Ñ‚ÐµÐºÑƒÑ‰Ð¸Ð¹ кадр Ñтека когда запушен Ñ "
+"включенным отладчиком.\n"
"Вывод в конÑоли будет выглÑдеть примерно так:\n"
"[codeblock]\n"
-"Frame 0 - res://test.gd:16 in function '_process'\n"
+"Test print\n"
+" At: res://test.gd:15:_process()\n"
"[/codeblock]"
#: modules/gdscript/doc_classes/@GDScript.xml
@@ -1830,19 +1832,30 @@ msgstr ""
"Возвращает результат плавной интерполÑции Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ [code]s[/code] между "
"[code]0[/code] и [code]1[/code], в завиÑимоÑти от того, где находитÑÑ "
"[code]s[/code] отноÑительно [code]from[/code] и [code]to[/code].\n"
+"\n"
"Возвращаемое значение равно [code]0[/code], еÑли [code]s <= from[/code] и "
"[code]1[/code], еÑли[code]s >= to[/code]. ЕÑли [code]s[/code] находитÑÑ "
"между [code]from[/code] и [code]to[/code], то возвращаемое значение Ñледует "
"S-образной кривой, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ ÑоответÑтвует значению [code]s[/code] между "
"[code]0[/code] и [code]1[/code].\n"
+"\n"
"S-Ð¾Ð±Ñ€Ð°Ð·Ð½Ð°Ñ ÐºÑ€Ð¸Ð²Ð°Ñ ÑвлÑетÑÑ ÐºÑƒÐ±Ð¸Ñ‡ÐµÑким Ñрмитовым Ñплайном, заданным функцией "
"[code]f(s) = 3*s^2 - 2*s^3[/code].\n"
+"\n"
"[codeblock]\n"
"smoothstep(0, 2, -5.0) # Returns 0.0\n"
"smoothstep(0, 2, 0.5) # Returns 0.15625\n"
"smoothstep(0, 2, 1.0) # Returns 0.5\n"
"smoothstep(0, 2, 2.0) # Returns 1.0\n"
-"[/codeblock]"
+"[/codeblock]\n"
+"\n"
+"Compared to [method ease] with a curve value of [code]-1.6521[/code], ["
+"method smoothstep] returns the smoothest possible curve with no sudden "
+"changes in the derivative. If you need to perform more advanced transitions, "
+"use [Tween] or [AnimationPlayer].\n"
+"[url=https://raw.githubusercontent.com/godotengine/godot-docs/3.5/img/"
+"smoothstep_ease_comparison.png]Comparison between smoothstep() and ease(x, -1"
+".6521) return values[/url]"
#: modules/gdscript/doc_classes/@GDScript.xml
#, fuzzy
diff --git a/doc/translations/zh_CN.po b/doc/translations/zh_CN.po
index 76ea804df5..7647bf0081 100644
--- a/doc/translations/zh_CN.po
+++ b/doc/translations/zh_CN.po
@@ -62,7 +62,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine class reference\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
-"PO-Revision-Date: 2022-07-26 01:54+0000\n"
+"PO-Revision-Date: 2022-07-31 16:43+0000\n"
"Last-Translator: Haoyu Qiu <timothyqiu32@gmail.com>\n"
"Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/"
"godot-engine/godot-class-reference/zh_Hans/>\n"
@@ -1322,7 +1322,6 @@ msgstr ""
"在打å°é”™è¯¯æˆ–警告时还会显示堆栈跟踪。"
#: modules/gdscript/doc_classes/@GDScript.xml
-#, fuzzy
msgid ""
"Like [method print], but includes the current stack frame when running with "
"the debugger turned on.\n"
@@ -1332,10 +1331,11 @@ msgid ""
" At: res://test.gd:15:_process()\n"
"[/codeblock]"
msgstr ""
-"在代ç ä½ç½®æ‰“å°å †æ ˆè½¨è¿¹ï¼Œä»…在打开调试器的情况下è¿è¡Œã€‚\n"
-"控制å°ä¸­çš„输出如下所示:\n"
+"与 [method print] 类似,但在打开调试器è¿è¡Œæ—¶è¿˜ä¼šåŒ…å«å½“剿 ˆå¸§ã€‚\n"
+"控制å°ä¸­çš„输出应该是类似这样的:\n"
"[codeblock]\n"
-"Frame 0 - res://test.gd:16 in function '_process'\n"
+"Test print\n"
+" At: res://test.gd:15:_process()\n"
"[/codeblock]"
#: modules/gdscript/doc_classes/@GDScript.xml
@@ -9581,7 +9581,6 @@ msgstr ""
"åˆ¶å™¨ä¹Ÿå°†ä¿æŒç›¸åŒçš„ ID。"
#: doc/classes/ARVRController.xml
-#, fuzzy
msgid ""
"The degree to which the controller vibrates. Ranges from [code]0.0[/code] to "
"[code]1.0[/code]. If changed, updates [member ARVRPositionalTracker.rumble] "
@@ -9589,9 +9588,8 @@ msgid ""
"This is a useful property to animate if you want the controller to vibrate "
"for a limited duration."
msgstr ""
-"控制器振动的程度。范围从 [code]0.0[/code] 到 [code]1.0[/code],精度 "
-"[code].01[/code]。如果更改,会相应地更新 [member ARVRPositionalTracker."
-"rumble]。\n"
+"控制器振动的程度。范围从 [code]0.0[/code] 到 [code]1.0[/code]。如果更改,"
+"会相应地更新 [member ARVRPositionalTracker.rumble]。\n"
"如果你想让控制器在é™å®šæ—¶é—´å†…振动,这是一个有用的属性,å¯ä»¥å°†å…¶åŠ¨ç”»åŒ–ã€‚"
#: doc/classes/ARVRController.xml
@@ -14589,6 +14587,10 @@ msgid ""
"current, setting one camera's [member current] to [code]false[/code] will "
"cause the other camera to be made current."
msgstr ""
+"如果为 [code]true[/code],则祖级 [Viewport] 正在使用这个相机。\n"
+"如果场景中有多个相机,总会有一个被设为当å‰ç›¸æœºã€‚例如,å‡è®¾åœºæ™¯ä¸­å­˜åœ¨ä¸¤ä¸ª "
+"[Camera] èŠ‚ç‚¹å¹¶ä¸”åªæœ‰ä¸€ä¸ªä¸ºå½“å‰ç›¸æœºï¼Œé‚£ä¹ˆå¦‚果把æŸä¸€ä¸ªç›¸æœºçš„ [member current] "
+"设为 [code]false[/code] 就会导致å¦ä¸€ä¸ªç›¸æœºè¢«è®¾ä¸ºå½“å‰ç›¸æœºã€‚"
#: doc/classes/Camera.xml
msgid ""
@@ -17985,7 +17987,7 @@ msgstr "é“奇è“色。"
#: doc/classes/Color.xml
msgid "Firebrick color."
-msgstr "ç«ç –的颜色。"
+msgstr "è€ç«ç –红色。"
#: doc/classes/Color.xml
msgid "Floral white color."
@@ -17997,11 +17999,11 @@ msgstr "森林绿色。"
#: doc/classes/Color.xml
msgid "Fuchsia color."
-msgstr "紫红色的颜色。"
+msgstr "洋红色。"
#: doc/classes/Color.xml
msgid "Gainsboro color."
-msgstr "庚斯伯勒颜色。"
+msgstr "庚斯伯勒ç°è‰²ã€‚"
#: doc/classes/Color.xml
msgid "Ghost white color."
@@ -18013,7 +18015,7 @@ msgstr "金色。"
#: doc/classes/Color.xml
msgid "Goldenrod color."
-msgstr "金黄的颜色。"
+msgstr "金èŠè‰²ã€‚"
#: doc/classes/Color.xml
msgid "Gray color."
@@ -18033,7 +18035,7 @@ msgstr "蜜露色。"
#: doc/classes/Color.xml
msgid "Hot pink color."
-msgstr "炙热的粉红色。"
+msgstr "亮粉色。"
#: doc/classes/Color.xml
msgid "Indian red color."
@@ -18057,7 +18059,7 @@ msgstr "è–°è¡£è‰è‰²ã€‚"
#: doc/classes/Color.xml
msgid "Lavender blush color."
-msgstr "è–°è¡£è‰è…®çº¢çš„颜色。"
+msgstr "è–°è¡£è‰ç´«çº¢è‰²ã€‚"
#: doc/classes/Color.xml
msgid "Lawn green color."
@@ -18081,7 +18083,7 @@ msgstr "æ·¡é’色。"
#: doc/classes/Color.xml
msgid "Light goldenrod color."
-msgstr "淡淡的金黄色。"
+msgstr "亮金èŠé»„色。"
#: doc/classes/Color.xml
msgid "Light gray color."
@@ -22935,7 +22937,7 @@ msgstr ""
msgid ""
"A script implemented in the C# programming language (Mono-enabled builds "
"only)."
-msgstr "用C#编程语言实现的脚本(仅å¯ç”¨Mono的版本)。"
+msgstr "用 C# 编程语言实现的脚本(仅 Mono 版本中存在)。"
#: modules/mono/doc_classes/CSharpScript.xml
msgid ""
@@ -22943,14 +22945,14 @@ msgid ""
"class and is only available in Mono-enabled Godot builds.\n"
"See also [GodotSharp]."
msgstr ""
-"此类表示C#脚本。它与[GDScript]类的C#等效,并且仅在å¯ç”¨äº†Monoçš„Godot版本中å¯"
-"用。\n"
-"å¦è¯·å‚阅[GodotSharp]。"
+"这个类表示 C# 脚本,是 [GDScript] 类在 C# 中的对等体,仅在å¯ç”¨äº† Mono çš„ "
+"Godot 版本中å¯ç”¨ã€‚\n"
+"å¦è¯·å‚阅 [GodotSharp]。"
#: modules/mono/doc_classes/CSharpScript.xml
#: modules/gdnative/doc_classes/PluginScript.xml
msgid "Returns a new instance of the script."
-msgstr "返回脚本的新实例。"
+msgstr "返回该脚本的新实例。"
#: doc/classes/CubeMap.xml
msgid "A CubeMap is a 6-sided 3D texture."
@@ -23267,7 +23269,7 @@ msgstr "釿–°è®¡ç®—曲线的烘焙点缓存。"
msgid ""
"Removes points that are closer than [code]CMP_EPSILON[/code] (0.00001) units "
"to their neighbor on the curve."
-msgstr "移除比曲线上的相邻点近[code]CMP_EPSILON[/code](0.00001)个å•ä½çš„点。"
+msgstr "移除比曲线上的相邻点近 [code]CMP_EPSILON[/code](0.00001)个å•ä½çš„点。"
#: doc/classes/Curve.xml doc/classes/Curve2D.xml doc/classes/Curve3D.xml
msgid "Removes all points from the curve."
@@ -23462,9 +23464,9 @@ msgid ""
"the index is out of bounds, the function sends an error to the console, and "
"returns [code](0, 0)[/code]."
msgstr ""
-"返回指å‘顶点[code]idx[/code]的控制点ä½ç½®ã€‚返回的ä½ç½®æ˜¯ç›¸å¯¹äºŽé¡¶ç‚¹[code]idx[/"
-"code]çš„ã€‚å¦‚æžœç´¢å¼•è¶…å‡ºäº†èŒƒå›´ï¼Œå‡½æ•°ä¼šå‘æŽ§åˆ¶å°å‘é€ä¸€æ¡é”™è¯¯ï¼Œå¹¶è¿”回 [code](0, 0)"
-"[/code]。"
+"返回指å‘顶点 [code]idx[/code] 的控制点ä½ç½®ã€‚返回的ä½ç½®æ˜¯ç›¸å¯¹äºŽé¡¶ç‚¹ "
+"[code]idx[/code] çš„ã€‚å¦‚æžœç´¢å¼•è¶…å‡ºäº†èŒƒå›´ï¼Œå‡½æ•°ä¼šå‘æŽ§åˆ¶å°å‘é€ä¸€æ¡é”™è¯¯ï¼Œå¹¶è¿”回 "
+"[code](0, 0)[/code]。"
#: doc/classes/Curve2D.xml
msgid ""
@@ -23473,9 +23475,9 @@ msgid ""
"code]. If the index is out of bounds, the function sends an error to the "
"console, and returns [code](0, 0)[/code]."
msgstr ""
-"返回从顶点[code]idx[/code]引出的控制点ä½ç½®ã€‚返回的ä½ç½®æ˜¯ç›¸å¯¹äºŽé¡¶ç‚¹ "
-"[code]idx[/code]ã€‚å¦‚æžœç´¢å¼•è¶Šç•Œï¼Œå‡½æ•°ä¼šå‘æŽ§åˆ¶å°å‘é€é”™è¯¯ï¼Œå¹¶è¿”回 [code](0, 0)[/"
-"code]。"
+"返回从顶点 [code]idx[/code] 引出的控制点ä½ç½®ã€‚返回的ä½ç½®æ˜¯ç›¸å¯¹äºŽé¡¶ç‚¹ "
+"[code]idx[/code]ã€‚å¦‚æžœç´¢å¼•è¶Šç•Œï¼Œå‡½æ•°ä¼šå‘æŽ§åˆ¶å°å‘é€é”™è¯¯ï¼Œå¹¶è¿”回 [code](0, "
+"0)[/code]。"
#: doc/classes/Curve2D.xml
msgid ""
@@ -25234,9 +25236,9 @@ msgid ""
"appear in the inspector when selecting a node that extends the class "
"specified by [code]class_name[/code]."
msgstr ""
-"如果[code]class_name[/code]指定的类中的[code]property[/code]被ç¦ç”¨ï¼Œåˆ™è¿”回 "
-"[code]true[/code]。当属性被ç¦ç”¨æ—¶ï¼Œå½“[code]class_name[/code]类被指定为类的(ç»§"
-"承)父节点时,它将ä¸ä¼šå‡ºçŽ°åœ¨æ£€æŸ¥å™¨ä¸­ã€‚"
+"如果 [code]class_name[/code] 指定的类中的 [code]property[/code] 属性被ç¦ç”¨ï¼Œ"
+"则返回 [code]true[/code]。ç¦ç”¨æŸä¸€å±žæ€§åŽï¼Œå½“选中继承自 "
+"[code]class_name[/code] 类的节点时,该属性将ä¸ä¼šå‡ºçŽ°åœ¨æ£€æŸ¥å™¨ä¸­ã€‚"
#: doc/classes/EditorFeatureProfile.xml
msgid ""
@@ -25252,18 +25254,19 @@ msgid ""
"format obtained by using the feature profile manager's [b]Export[/b] button "
"or the [method save_to_file] method."
msgstr ""
-"从文件中加载一个编辑器功能é…置文件。该文件必须éµå¾ªJSONæ ¼å¼ï¼Œé€šè¿‡ä½¿ç”¨åŠŸèƒ½é…ç½®"
-"文件管ç†å™¨çš„[b]Export[/b]按钮或[method save_to_file]方法获得。"
+"从文件中加载一个编辑器功能é…置文件。该文件必须éµå¾ª JSON "
+"æ ¼å¼ï¼Œé€šè¿‡ä½¿ç”¨åŠŸèƒ½é…置文件管ç†å™¨çš„[b]导出[/b]按钮或 [method save_to_file] "
+"方法获得。"
#: doc/classes/EditorFeatureProfile.xml
-#, fuzzy
msgid ""
"Saves the editor feature profile to a file in JSON format. It can then be "
"imported using the feature profile manager's [b]Import[/b] button or the "
"[method load_from_file] method."
msgstr ""
-"将编辑器的功能é…ç½®ä¿å­˜åˆ°JSONæ ¼å¼çš„æ–‡ä»¶ä¸­ã€‚ç„¶åŽå¯ä»¥ä½¿ç”¨ç‰¹å¾é…置文件管ç†å™¨çš„[b]"
-"导入[/b]按钮或[method load_from_file]按钮导入它。"
+"将编辑器的功能é…ç½®ä¿å­˜åˆ° JSON "
+"æ ¼å¼çš„æ–‡ä»¶ä¸­ã€‚ç„¶åŽå¯ä»¥ä½¿ç”¨åŠŸèƒ½é…置文件管ç†å™¨çš„[b]导入[/b]按钮或 [method "
+"load_from_file] 方法导入它。"
#: doc/classes/EditorFeatureProfile.xml
msgid ""
@@ -25271,8 +25274,9 @@ msgid ""
"by [code]class_name[/code]. When disabled, the class won't appear in the "
"Create New Node dialog."
msgstr ""
-"如果 [code]disable[/code] 是 [code]true[/code],则ç¦ç”¨ [code]class_name[/"
-"code] 指定的类。被ç¦ç”¨æ—¶ï¼Œè¯¥ç±»ä¸ä¼šå‡ºçŽ°åœ¨â€œåˆ›å»ºæ–° Nodeâ€å¯¹è¯æ¡†ä¸­ã€‚"
+"如果 [code]disable[/code] 为 [code]true[/code],则ç¦ç”¨ "
+"[code]class_name[/code] 指定的类。ç¦ç”¨åŽï¼Œè¯¥ç±»ä¸ä¼šå‡ºçŽ°åœ¨â€œåˆ›å»ºæ–° "
+"Nodeâ€å¯¹è¯æ¡†ä¸­ã€‚"
#: doc/classes/EditorFeatureProfile.xml
msgid ""
@@ -25281,9 +25285,9 @@ msgid ""
"appear in the Create New Node dialog but the inspector will be read-only "
"when selecting a node that extends the class."
msgstr ""
-"如果 [code]disable[/code] 为 [code]true[/code],则ç¦ç”¨ [code]class_name[/"
-"code] 指定的类的编辑。ç¦ç”¨æ—¶ï¼Œç±»ä»ç„¶ä¼šå‡ºçŽ°åœ¨â€œåˆ›å»ºæ–° Nodeâ€å¯¹è¯æ¡†ä¸­ï¼Œä½†åœ¨é€‰æ‹©ç»§"
-"承的节点时,检查器将åªè¯»ã€‚"
+"如果 [code]disable[/code] 为 [code]true[/code],则ç¦ç”¨ "
+"[code]class_name[/code] 指定的类的编辑。ç¦ç”¨åŽï¼Œè¯¥ç±»ä»ç„¶ä¼šå‡ºçŽ°åœ¨â€œåˆ›å»ºæ–° "
+"Nodeâ€å¯¹è¯æ¡†ä¸­ï¼Œä½†åœ¨é€‰ä¸­ç»§æ‰¿çš„节点时,检查器将åªè¯»ã€‚"
#: doc/classes/EditorFeatureProfile.xml
msgid ""
@@ -25292,9 +25296,10 @@ msgid ""
"When a property is disabled, it won't appear in the inspector when selecting "
"a node that extends the class specified by [code]class_name[/code]."
msgstr ""
-"如果 [code]disable[/code] 是 [code]true[/code],则ç¦ç”¨ [code]class_name[/"
-"code] 指定的类中的 [code]property[/code] 的编辑。当属性被ç¦ç”¨æ—¶ï¼Œå½“选择继承 "
-"[code]class_name[/code] 指定的类的节点时,它将ä¸ä¼šå‡ºçŽ°åœ¨æ£€æŸ¥å™¨ä¸­ã€‚"
+"如果 [code]disable[/code] 为 [code]true[/code],则ç¦ç”¨ "
+"[code]class_name[/code] 指定的类中的 [code]property[/code] "
+"属性的编辑。ç¦ç”¨æŸä¸€å±žæ€§åŽï¼Œé€‰ä¸­ç»§æ‰¿è‡ª [code]class_name[/code] "
+"指定的类的节点时,这个属性将ä¸ä¼šå‡ºçŽ°åœ¨æ£€æŸ¥å™¨ä¸­ã€‚"
#: doc/classes/EditorFeatureProfile.xml
msgid ""
@@ -25325,7 +25330,7 @@ msgstr ""
msgid ""
"The AssetLib tab. If this feature is disabled, the AssetLib tab won't "
"display."
-msgstr "AssetLib选项å¡ã€‚如果ç¦ç”¨æ­¤åŠŸèƒ½ï¼Œåˆ™ä¸ä¼šæ˜¾ç¤ºAssetLib选项å¡ã€‚"
+msgstr "AssetLib 选项å¡ã€‚如果ç¦ç”¨æ­¤åŠŸèƒ½ï¼Œåˆ™ä¸ä¼šæ˜¾ç¤º AssetLib 选项å¡ã€‚"
#: doc/classes/EditorFeatureProfile.xml
msgid ""
@@ -29678,14 +29683,13 @@ msgid "The default exposure used for tonemapping."
msgstr "用于色调映射的默认æ›å…‰ã€‚"
#: doc/classes/Environment.xml
-#, fuzzy
msgid ""
"The tonemapping mode to use. Tonemapping is the process that \"converts\" "
"HDR values to be suitable for rendering on a SDR display. (Godot doesn't "
"support rendering on HDR displays yet.)"
msgstr ""
-"è¦ä½¿ç”¨çš„色调映射模å¼ã€‚色调映射是“转æ¢â€HDR 值以适åˆåœ¨ LDR 显示器上呈现的过程。"
-"(Godot å°šä¸æ”¯æŒåœ¨ HDR 显示器上进行渲染。)"
+"è¦ä½¿ç”¨çš„色调映射模å¼ã€‚色调映射是将 HDR 值“转æ¢â€ä¸ºé€‚åˆåœ¨ SDR "
+"显示器上呈现的值过程。(Godot å°šä¸æ”¯æŒåœ¨ HDR 显示器上进行渲染。)"
#: doc/classes/Environment.xml
msgid ""
@@ -31958,16 +31962,16 @@ msgstr ""
"[b]注æ„:[/b]直线是使用方å‘å‘é‡è€Œä¸æ˜¯ç»ˆç‚¹æŒ‡å®šçš„。"
#: doc/classes/Geometry.xml
-#, fuzzy
msgid ""
"Given an array of [Vector2]s representing tiles, builds an atlas. The "
"returned dictionary has two keys: [code]points[/code] is an array of "
"[Vector2] that specifies the positions of each tile, [code]size[/code] "
"contains the overall size of the whole atlas as [Vector2]."
msgstr ""
-"给定表示图å—çš„[Vector2]数组,构建一个地图集。返回的字典有两个键:"
-"[code]points[/code]是[Vector2]çš„å‘é‡ï¼Œç”¨äºŽæŒ‡å®šæ¯ä¸ªå›¾å—çš„ä½ç½®ï¼Œ[code]size[/"
-"code]åŒ…å«æ•´ä¸ªå›¾é›†çš„æ•´ä½“大å°ï¼Œä½œä¸º[Vector2]。"
+"给定表示图å—çš„ [Vector2] "
+"数组,构建一个地图集。返回的字典有两个键:[code]points[/code] 是 [Vector2] "
+"的数组,用于指定æ¯ä¸ªå›¾å—çš„ä½ç½®ï¼Œ[code]size[/code] åŒ…å«æ•´ä¸ªå›¾é›†çš„æ•´ä½“大å°ï¼Œ"
+"是一个 [Vector2]。"
#: doc/classes/Geometry.xml
msgid ""
@@ -33247,9 +33251,7 @@ msgstr "å°å›¾çŸ©å½¢çš„大å°ã€‚地图自身基于网格区域的大å°ï¼Œå¹¶è¢«
msgid ""
"If [code]true[/code], enables disconnection of existing connections in the "
"GraphEdit by dragging the right end."
-msgstr ""
-"如果为 [code]true[/code],通过拖动å³ç«¯ï¼Œå¯ä»¥æ–­å¼€å›¾å½¢ç¼–辑GraphEdit中现有的连"
-"接。"
+msgstr "如果为 [code]true[/code],通过拖动å³ç«¯ï¼Œå¯ä»¥æ–­å¼€ GraphEdit 中现有的连接。"
#: doc/classes/GraphEdit.xml
msgid "The scroll offset."
@@ -33306,9 +33308,9 @@ msgid ""
"code] slot of the [code]from[/code] GraphNode and the [code]to_slot[/code] "
"slot of the [code]to[/code] GraphNode is attempted to be created."
msgstr ""
-"当试图创建[code]æ¥è‡ªfrom[/code]图形节点GraphNode1çš„[code]from_slot[/code]槽和"
-"[code]to[/code]图形节点GraphNode2çš„[code]to_slot[/code]槽之间的连接时,会å‘图"
-"形编辑GraphEditå‘出。"
+"å°è¯•创建从 [code]from[/code] GraphNode çš„ [code]from_slot[/code] 槽到 "
+"[code]to[/code] GraphNode çš„ [code]to_slot[/code] 槽之间的连接时,会å‘该 "
+"GraphEdit å‘出。"
#: doc/classes/GraphEdit.xml
msgid ""
@@ -33335,9 +33337,9 @@ msgid ""
"slot of [code]from[/code] GraphNode and [code]to_slot[/code] slot of "
"[code]to[/code] GraphNode is attempted to be removed."
msgstr ""
-"当试图移除 [code]from[/code] 图形节点GraphNode1的 [code]from_slot[/code]槽和"
-"[code]to[/code] 图形节点GraphNode çš„[code]to_slot[/code] 槽之间的连接时,会å‘"
-"é€åˆ°å›¾å½¢ç¼–辑GraphEdit。"
+"å°è¯•移除从 [code]from[/code] GraphNode çš„ [code]from_slot[/code] 槽到 "
+"[code]to[/code] GraphNode çš„ [code]to_slot[/code] 槽之间的连接时,会å‘该 "
+"GraphEdit å‘出。"
#: doc/classes/GraphEdit.xml
msgid ""
@@ -33561,9 +33563,8 @@ msgstr ""
msgid ""
"Sets the [Color] of the right (output) side of the slot [code]idx[/code] to "
"[code]color_right[/code]."
-msgstr ""
-"å°†æ’æ§½[code]idx[/code]çš„å³ä¾§ï¼ˆè¾“出)的颜色[Color]设置为[code]color_right[/"
-"code]。"
+msgstr "å°†æ’æ§½ [code]idx[/code] çš„å³ä¾§ï¼ˆè¾“出)的颜色 [Color] 设置为 "
+"[code]color_right[/code]。"
#: doc/classes/GraphNode.xml
msgid ""
@@ -33599,7 +33600,7 @@ msgstr ""
#: doc/classes/GraphNode.xml
msgid "If [code]true[/code], the GraphNode is a comment node."
-msgstr "如果为 [code]true[/code],则 GraphNode 是注释节点。"
+msgstr "如果为 [code]true[/code],则该 GraphNode 是注释节点。"
#: doc/classes/GraphNode.xml
msgid ""
@@ -33627,7 +33628,7 @@ msgstr ""
#: doc/classes/GraphNode.xml
msgid "If [code]true[/code], the GraphNode is selected."
-msgstr "如果为 [code]true[/code],图形节点GraphNode被选中。"
+msgstr "如果为 [code]true[/code],则该 GraphNode 被选中。"
#: doc/classes/GraphNode.xml
msgid ""
@@ -41016,7 +41017,6 @@ msgid "The tint of [Font]'s outline."
msgstr "对 [Font] 轮廓的染色。"
#: doc/classes/Label3D.xml
-#, fuzzy
msgid ""
"Sets the render priority for the text outline. Higher priority objects will "
"be sorted in front of lower priority objects.\n"
@@ -41028,8 +41028,8 @@ msgid ""
"sorted from back to front (subject to priority)."
msgstr ""
"设置文本轮廓的渲染优先级。优先级高的物体将被排åºåœ¨ä¼˜å…ˆçº§ä½Žçš„物体å‰é¢ã€‚\n"
-"[b]注æ„:[/b]仅在 [member alpha_cut] 为 [constant ALPHA_CUT_DISABLED](默认"
-"值)时适用。\n"
+"[b]注æ„:[/b]仅在 [member alpha_cut] 为 [constant "
+"ALPHA_CUT_DISABLED](默认值)时适用。\n"
"[b]注æ„:[/b]ä»…é€‚ç”¨äºŽé€æ˜Žç‰©ä½“的排åºã€‚è¿™ä¸ä¼šå½±å“逿˜Žç‰©ä½“相对于ä¸é€æ˜Žç‰©ä½“的排åº"
"æ–¹å¼ã€‚这是因为ä¸é€æ˜Žå¯¹è±¡ä¸è¢«æŽ’åºï¼Œè€Œé€æ˜Žå¯¹è±¡åˆ™ä»ŽåŽå¾€å‰æŽ’åºï¼ˆå–决于优先级)。"
@@ -41038,7 +41038,6 @@ msgid "The size of one pixel's width on the label to scale it in 3D."
msgstr "标签上一个åƒç´ å®½åº¦çš„大å°ï¼Œä»¥ 3D 缩放。"
#: doc/classes/Label3D.xml
-#, fuzzy
msgid ""
"Sets the render priority for the text. Higher priority objects will be "
"sorted in front of lower priority objects.\n"
@@ -41050,8 +41049,8 @@ msgid ""
"sorted from back to front (subject to priority)."
msgstr ""
"设置文本的渲染优先级。优先级高的物体将被排åºåœ¨ä¼˜å…ˆçº§ä½Žçš„物体å‰é¢ã€‚\n"
-"[b]注æ„:[/b]仅在 [member alpha_cut] 为 [constant ALPHA_CUT_DISABLED](默认"
-"值)时适用。\n"
+"[b]注æ„:[/b]仅在 [member alpha_cut] 为 [constant "
+"ALPHA_CUT_DISABLED](默认值)时适用。\n"
"[b]注æ„:[/b]ä»…é€‚ç”¨äºŽé€æ˜Žç‰©ä½“的排åºã€‚è¿™ä¸ä¼šå½±å“逿˜Žç‰©ä½“相对于ä¸é€æ˜Žç‰©ä½“的排åº"
"æ–¹å¼ã€‚这是因为ä¸é€æ˜Žå¯¹è±¡ä¸è¢«æŽ’åºï¼Œè€Œé€æ˜Žå¯¹è±¡åˆ™ä»ŽåŽå¾€å‰æŽ’åºï¼ˆå–决于优先级)。"
@@ -41077,11 +41076,10 @@ msgid "If set, lights in the environment affect the label."
msgstr "如果打开,环境中的ç¯å…‰ä¼šå½±å“该标签。"
#: doc/classes/Label3D.xml
-#, fuzzy
msgid ""
"If set, text can be seen from the back as well. If not, the text is "
"invisible when looking at it from behind."
-msgstr "如果打开,从åŽé¢ä¹Ÿå¯ä»¥çœ‹åˆ°æ–‡æœ¬ï¼Œå¦‚æžœä¸æ‰“开,从åŽé¢çœ‹å®ƒæ˜¯ä¸å¯è§çš„。"
+msgstr "如果打开,从åŽé¢ä¹Ÿå¯ä»¥çœ‹åˆ°æ–‡æœ¬ã€‚å¦‚æžœä¸æ‰“开,从åŽé¢çœ‹è¯¥æ–‡æœ¬æ˜¯ä¸å¯è§çš„。"
#: doc/classes/Label3D.xml doc/classes/SpatialMaterial.xml
#: doc/classes/SpriteBase3D.xml
@@ -46077,7 +46075,6 @@ msgid "An instance of a [NavigationMesh]."
msgstr "[NavigationMesh] 的一个实例。"
#: doc/classes/NavigationMeshInstance.xml
-#, fuzzy
msgid ""
"An instance of a [NavigationMesh]. It tells the [Navigation] node what can "
"be navigated and what cannot, based on the [NavigationMesh] resource.\n"
@@ -46096,13 +46093,13 @@ msgid ""
"The cost of traveling distances inside this region can be controlled with "
"the [member travel_cost] multiplier."
msgstr ""
-"[NavigationMesh] 的实例。[Navigation] 节点根æ®å®ƒçš„ [NavigationMesh] èµ„æºæ¥ç¡®"
-"定哪些å¯ä»¥è¿›è¡Œå¯¼èˆªã€å“ªäº›ä¸èƒ½ã€‚\n"
+"[NavigationMesh] 的实例。[Navigation] 节点根æ®å®ƒçš„ [NavigationMesh] "
+"èµ„æºæ¥ç¡®å®šå“ªäº›å¯ä»¥è¿›è¡Œå¯¼èˆªã€å“ªäº›ä¸èƒ½ã€‚\n"
"默认情况下,这个节点会在默认的 [World] 导航地图中进行注册。如果这个节点是 "
"[Navigation] 节点的å­é¡¹ï¼Œå°±ä¼šåœ¨è¯¥å¯¼èˆªèŠ‚ç‚¹çš„å¯¼èˆªåœ°å›¾ä¸­è¿›è¡Œæ³¨å†Œã€‚\n"
"如果两个地图共享类似的边界,就å¯ä»¥ç›¸äº’连接。你å¯ä»¥é€šè¿‡ [method "
-"NavigationServer.map_set_edge_connection_margin] 设置两个顶点连接两æ¡è¾¹ç•Œæ‰€éœ€"
-"的最å°è·ç¦»ã€‚\n"
+"NavigationServer.map_set_edge_connection_margin] "
+"设置两个顶点连接两æ¡è¾¹ç•Œæ‰€éœ€çš„æœ€å°è·ç¦»ã€‚\n"
"[b]注æ„:[/b]将两个地区的导航网格相互é‡å å¹¶ä¸è¶³ä»¥å°†å…¶ç›¸è¿žã€‚它们必须共享类似的"
"边界。\n"
"从å¦ä¸€ä¸ªåœ°åŒºè¿›å…¥è¿™ä¸ªåœ°å›¾çš„æ¶ˆè€—å¯ä»¥é€šè¿‡ [member enter_cost] 进行控制。\n"
@@ -46415,7 +46412,6 @@ msgid "A region of the 2D navigation map."
msgstr "2D 导航地图上的一个地区。"
#: doc/classes/NavigationPolygonInstance.xml
-#, fuzzy
msgid ""
"A region of the navigation map. It tells the [Navigation2DServer] what can "
"be navigated and what cannot, based on its [NavigationPolygon] resource.\n"
@@ -46434,13 +46430,13 @@ msgid ""
"The pathfinding cost of traveling distances inside this region can be "
"controlled with the [member travel_cost] multiplier."
msgstr ""
-"导航地图上的地区。[Navigation2DServer] æ ¹æ®å®ƒçš„ [NavigationPolygon] èµ„æºæ¥ç¡®"
-"定哪些å¯ä»¥è¿›è¡Œå¯¼èˆªã€å“ªäº›ä¸èƒ½ã€‚\n"
+"导航地图上的地区。[Navigation2DServer] æ ¹æ®å®ƒçš„ [NavigationPolygon] "
+"èµ„æºæ¥ç¡®å®šå“ªäº›å¯ä»¥è¿›è¡Œå¯¼èˆªã€å“ªäº›ä¸èƒ½ã€‚\n"
"默认情况下,这个节点会在默认的 [World2D] 导航地图中进行注册。如果这个节点是 "
"[Navigation2D] 节点的å­é¡¹ï¼Œå°±ä¼šåœ¨è¯¥å¯¼èˆªèŠ‚ç‚¹çš„å¯¼èˆªåœ°å›¾ä¸­è¿›è¡Œæ³¨å†Œã€‚\n"
"如果两个地图共享类似的边界,就å¯ä»¥ç›¸äº’连接。你å¯ä»¥é€šè¿‡ [method "
-"Navigation2DServer.map_set_edge_connection_margin] 设置两个顶点连接两æ¡è¾¹ç•Œæ‰€"
-"需的最å°è·ç¦»ã€‚\n"
+"Navigation2DServer.map_set_edge_connection_margin] "
+"设置两个顶点连接两æ¡è¾¹ç•Œæ‰€éœ€çš„æœ€å°è·ç¦»ã€‚\n"
"[b]注æ„:[/b]将两个地区的导航网格相互é‡å å¹¶ä¸è¶³ä»¥å°†å…¶ç›¸è¿žã€‚它们必须共享类似的"
"边界。\n"
"从å¦ä¸€ä¸ªåœ°åŒºè¿›å…¥è¿™ä¸ªåœ°å›¾çš„寻路消耗å¯ä»¥é€šè¿‡ [member enter_cost] 进行控制。\n"
@@ -46587,7 +46583,7 @@ msgstr "控制这个æœåŠ¡å™¨æ˜¯å¦æ¿€æ´»ã€‚"
msgid ""
"A [NetworkedMultiplayerPeer] implementation that can be controlled from a "
"script."
-msgstr ""
+msgstr "对 [NetworkedMultiplayerPeer] 的一ç§å®žçŽ°ï¼Œèƒ½å¤Ÿé€šè¿‡è„šæœ¬æŽ§åˆ¶ã€‚"
#: doc/classes/NetworkedMultiplayerCustom.xml
msgid ""
@@ -46596,6 +46592,9 @@ msgid ""
"Its purpose is to allow adding a new backend for the high-Level multiplayer "
"API without needing to use GDNative."
msgstr ""
+"对 [NetworkedMultiplayerPeer] 的一ç§å®žçŽ°ï¼Œèƒ½å¤Ÿä½œä¸º [member MultiplayerAPI."
+"network_peer] 使用并且通过脚本控制。\n"
+"其目的是为高级多人 API 添加新的åŽç«¯ï¼Œä¸å¿…使用 GDNative。"
#: doc/classes/NetworkedMultiplayerCustom.xml
msgid ""
@@ -46604,24 +46603,26 @@ msgid ""
"(originating from the [signal packet_generated] signal on the sending peer), "
"passing it to this method will deliver it locally."
msgstr ""
+"呿œ¬åœ° [MultiplayerAPI] 传递数æ®åŒ…。\n"
+"当你的脚本通过网络收到其他对等体的数æ®åŒ…时(å‘逿–¹å‘出 [signal "
+"packet_generated] ä¿¡å·ï¼‰ï¼Œå°†å…¶ä¼ é€’给这个方法会在本地进行传递。"
#: doc/classes/NetworkedMultiplayerCustom.xml
msgid ""
"Initialize the peer with the given [code]peer_id[/code] (must be between 1 "
"and 2147483647)."
-msgstr ""
+msgstr "使用给定的 [code]peer_id[/code] åˆå§‹åŒ–该对等体(必须在 1 å’Œ 2147483647 "
+"之间)。"
#: doc/classes/NetworkedMultiplayerCustom.xml
-#, fuzzy
msgid ""
"Set the state of the connection. See [enum NetworkedMultiplayerPeer."
"ConnectionStatus]."
-msgstr "返回连接的当å‰çжæ€ã€‚è§ [enum ConnectionStatus]。"
+msgstr "设置连接的状æ€ã€‚è§ [enum NetworkedMultiplayerPeer.ConnectionStatus]。"
#: doc/classes/NetworkedMultiplayerCustom.xml
-#, fuzzy
msgid "Set the max packet size that this peer can handle."
-msgstr "设置该实例使用的光照图。"
+msgstr "设置这个对等体所能够处ç†çš„æœ€å¤§æ•°æ®åŒ…大å°ã€‚"
#: doc/classes/NetworkedMultiplayerCustom.xml
msgid ""
@@ -46630,6 +46631,9 @@ msgid ""
"the network (which should call [method deliver_packet] with the data when "
"it's received)."
msgstr ""
+"当本地 [MultiplayerAPI] ç”Ÿæˆæ•°æ®åŒ…时触å‘。\n"
+"你的脚本应当获å–这个数æ®åŒ…并将其通过网络å‘é€ç»™è¯·æ±‚的对等体("
+"å¯¹æ–¹æ”¶åˆ°è¯¥æ•°æ®æ—¶åº”当调用 [method deliver_packet])。"
#: modules/enet/doc_classes/NetworkedMultiplayerENet.xml
msgid ""
@@ -50336,6 +50340,10 @@ msgid ""
"series don't support cubemap shadows and will fall back to dual paraboloid "
"shadows as a result."
msgstr ""
+"为这个 [OmniLight] 使用的阴影渲染模å¼ã€‚è§ [enum ShadowMode]。\n"
+"[b]注æ„:[/b]在 GLES2 ä¸­ï¼Œåªæœ‰æ”¯æŒæ·±åº¦ç«‹æ–¹ä½“贴图功能的 GPU æ‰æ”¯æŒ [constant "
+"SHADOW_CUBE]。Radeon HD 4000 系列等较è€çš„ GPU "
+"䏿”¯æŒç«‹æ–¹ä½“è´´å›¾é˜´å½±ï¼Œå› æ­¤ä¼šå›žé€€åˆ°ä½¿ç”¨åŒæŠ›ç‰©é¢é˜´å½±ã€‚"
#: doc/classes/OmniLight.xml
msgid ""
@@ -50345,14 +50353,13 @@ msgstr ""
"é˜´å½±è¢«æ¸²æŸ“åˆ°ä¸€ä¸ªåŒæŠ›ç‰©é¢çº¹ç†ã€‚比 [constant SHADOW_CUBE] 更快,但质é‡è¾ƒå·®ã€‚"
#: doc/classes/OmniLight.xml
-#, fuzzy
msgid ""
"Shadows are rendered to a cubemap. Slower than [constant "
"SHADOW_DUAL_PARABOLOID], but higher-quality. Only supported on GPUs that "
"feature support for depth cubemaps."
msgstr ""
-"阴影被渲染æˆä¸€ä¸ªç«‹æ–¹ä½“贴图。比 [constant SHADOW_DUAL_PARABOLOID] æ…¢ï¼Œä½†è´¨é‡æ›´"
-"高。"
+"阴影被渲染至一个立方体贴图。比 [constant SHADOW_DUAL_PARABOLOID] "
+"æ…¢ï¼Œä½†è´¨é‡æ›´é«˜ã€‚ä»…åœ¨æ”¯æŒæ·±åº¦ç«‹æ–¹ä½“贴图功能的 GPU 上支æŒã€‚"
#: doc/classes/OmniLight.xml
msgid "Use more detail vertically when computing the shadow."
@@ -72901,7 +72908,6 @@ msgid "The size of one pixel's width on the sprite to scale it in 3D."
msgstr "ç²¾çµä¸Šä¸€ä¸ªåƒç´ å®½åº¦çš„大å°ï¼Œä»¥ 3D 缩放。"
#: doc/classes/SpriteBase3D.xml
-#, fuzzy
msgid ""
"Sets the render priority for the sprite. Higher priority objects will be "
"sorted in front of lower priority objects.\n"
@@ -72912,9 +72918,9 @@ msgid ""
"This is because opaque objects are not sorted, while transparent objects are "
"sorted from back to front (subject to priority)."
msgstr ""
-"设置精çµçš„æ¸²æŸ“优先级。优先级高的物体将被排åºåœ¨ä¼˜å…ˆçº§ä½Žçš„物体å‰é¢ã€‚\n"
-"[b]注æ„:[/b]仅在 [member alpha_cut] 为 [constant ALPHA_CUT_DISABLED](默认"
-"值)时适用。\n"
+"设置该精çµçš„æ¸²æŸ“优先级。优先级高的物体将被排åºåœ¨ä¼˜å…ˆçº§ä½Žçš„物体å‰é¢ã€‚\n"
+"[b]注æ„:[/b]仅在 [member alpha_cut] 为 [constant "
+"ALPHA_CUT_DISABLED](默认值)时适用。\n"
"[b]注æ„:[/b]ä»…é€‚ç”¨äºŽé€æ˜Žç‰©ä½“的排åºã€‚è¿™ä¸ä¼šå½±å“逿˜Žç‰©ä½“相对于ä¸é€æ˜Žç‰©ä½“的排åº"
"æ–¹å¼ã€‚这是因为ä¸é€æ˜Žå¯¹è±¡ä¸è¢«æŽ’åºï¼Œè€Œé€æ˜Žå¯¹è±¡åˆ™ä»ŽåŽå¾€å‰æŽ’åºï¼ˆå–决于优先级)。"
@@ -76499,14 +76505,13 @@ msgid "Sets the text for a specific line."
msgstr "设置特定行的文本。"
#: doc/classes/TextEdit.xml
-#, fuzzy
msgid ""
"Bookmarks the [code]line[/code] if [code]bookmark[/code] is [code]true[/"
"code]. Deletes the bookmark if [code]bookmark[/code] is [code]false[/code].\n"
"Bookmarks are shown in the [member breakpoint_gutter]."
msgstr ""
-"如果 [code]bookmark[/code] 为 true,则为行 [code]line[/code] 设置书签。如果 "
-"[code]bookmark[/code] 为 false,则删除该书签。\n"
+"如果 [code]bookmark[/code] 为 [code]true[/code],则为行 [code]line[/code] "
+"设置书签。如果 [code]bookmark[/code] 为 [code]false[/code],则删除该书签。\n"
"书签显示在 [member breakpoint_gutter] 中。"
#: doc/classes/TextEdit.xml
@@ -80906,14 +80911,12 @@ msgid ""
msgstr "返回使用 [method set_metadata] 为指定列设置的元数æ®ã€‚"
#: doc/classes/TreeItem.xml
-#, fuzzy
msgid ""
"Returns the next sibling TreeItem in the tree or a null object if there is "
"none."
-msgstr "返回树中的下一个 TreeItem,如果没有,则返回一个空对象。"
+msgstr "返回树中的下一个兄弟 TreeItem,如果没有,则返回一个空对象。"
#: doc/classes/TreeItem.xml
-#, fuzzy
msgid ""
"Returns the next visible sibling TreeItem in the tree or a null object if "
"there is none.\n"
@@ -80921,8 +80924,8 @@ msgid ""
"visible element in the tree when called on the last visible element, "
"otherwise it returns [code]null[/code]."
msgstr ""
-"返回树中下一个å¯è§çš„ TreeItem,如果没有,则返回空对象。\n"
-"如果 [code]wrap[/code] 被å¯ç”¨ï¼Œå½“在最åŽä¸€ä¸ªå¯è§å…ƒç´ ä¸Šè°ƒç”¨æ—¶ï¼Œè¯¥æ–¹æ³•将环绕到树"
+"返回树中下一个å¯è§çš„兄弟 TreeItem,如果没有,则返回空对象。\n"
+"如果å¯ç”¨äº† [code]wrap[/code],当在最åŽä¸€ä¸ªå¯è§å…ƒç´ ä¸Šè°ƒç”¨æ—¶ï¼Œè¯¥æ–¹æ³•将环绕到树"
"中的第一个å¯è§å…ƒç´ ï¼Œå¦åˆ™å®ƒå°†è¿”回 [code]null[/code]。"
#: doc/classes/TreeItem.xml
@@ -80930,14 +80933,12 @@ msgid "Returns the parent TreeItem or a null object if there is none."
msgstr "返回父级 TreeItem,如果没有,则返回一个空对象。"
#: doc/classes/TreeItem.xml
-#, fuzzy
msgid ""
"Returns the previous sibling TreeItem in the tree or a null object if there "
"is none."
-msgstr "返回树中的å‰ä¸€ä¸ª TreeItem,如果没有,则返回一个空对象。"
+msgstr "返回树中的å‰ä¸€ä¸ªå…„弟 TreeItem,如果没有,则返回一个空对象。"
#: doc/classes/TreeItem.xml
-#, fuzzy
msgid ""
"Returns the previous visible sibling TreeItem in the tree or a null object "
"if there is none.\n"
@@ -80945,8 +80946,8 @@ msgid ""
"visible element in the tree when called on the first visible element, "
"otherwise it returns [code]null[/code]."
msgstr ""
-"返回树中å‰ä¸€ä¸ªå¯è§çš„ TreeItem,如果没有,则返回 null 对象。\n"
-"如果 [code]wrap[/code] 被å¯ç”¨ï¼Œå½“在第一个å¯è§å…ƒç´ ä¸Šè°ƒç”¨æ—¶ï¼Œè¯¥æ–¹æ³•将环绕到树中"
+"返回树中å‰ä¸€ä¸ªå¯è§çš„兄弟 TreeItem,如果没有,则返回 null 对象。\n"
+"如果å¯ç”¨äº† [code]wrap[/code],当在第一个å¯è§å…ƒç´ ä¸Šè°ƒç”¨æ—¶ï¼Œè¯¥æ–¹æ³•将环绕到树中"
"最åŽä¸€ä¸ªå¯è§å…ƒç´ ï¼Œå¦åˆ™å®ƒå°†è¿”回 [code]null[/code]。"
#: doc/classes/TreeItem.xml
@@ -89273,6 +89274,10 @@ msgid ""
"viewport_set_use_32_bpc_depth].\n"
"[b]Note:[/b] Only available on the GLES3 backend."
msgstr ""
+"如果为 "
+"[code]true[/code],该视区会渲染至高动æ€èŒƒå›´ï¼ˆHDRï¼‰è€Œä¸æ˜¯æ ‡å‡†åЍæ€èŒƒå›´ï¼ˆSDR)。"
+"å¦è¯·å‚阅 [method viewport_set_use_32_bpc_depth]。\n"
+"[b]注æ„:[/b]仅在 GLES3 åŽç«¯å¯ç”¨ã€‚"
#: doc/classes/VisualServer.xml
msgid "If [code]true[/code], the viewport's canvas is not rendered."
@@ -89370,7 +89375,6 @@ msgid ""
msgstr "设置视窗的 2D/3D 模å¼ã€‚é€‰é¡¹è§ [enum ViewportUsage] 常é‡ã€‚"
#: doc/classes/VisualServer.xml
-#, fuzzy
msgid ""
"If [code]true[/code], allocates the viewport's framebuffer with full "
"floating-point precision (32-bit) instead of half floating-point precision "
@@ -89378,11 +89382,9 @@ msgid ""
"on the same [Viewport] to set HDR to [code]true[/code].\n"
"[b]Note:[/b] Only available on the GLES3 backend."
msgstr ""
-"如果为 [code]true[/code],分é…该视窗的帧缓冲时将使用完整浮点数精度(32 ä½ï¼‰è€Œ"
-"䏿˜¯åŠæµ®ç‚¹æ•°ç²¾åº¦ï¼ˆ16 ä½ï¼‰ã€‚ä»…åœ¨åŒæ—¶å¯ç”¨ [member hdr] 时有效。\n"
-"[b]注æ„:[/b]å¯ç”¨è¿™ä¸ªè®¾ç½®ä¸ä¼šæå‡æ¸²æŸ“è´¨é‡ã€‚ä½¿ç”¨å®Œæ•´æµ®ç‚¹æ•°ç²¾åº¦è¾ƒæ…¢ï¼Œä¸€èˆ¬åªæœ‰è¦"
-"求更高精度的高级ç€è‰²å™¨éœ€è¦ä½¿ç”¨ã€‚如果是è¦å‡å°‘æ¡å¸¦æ•ˆåº”,请å¯ç”¨ [member "
-"debanding]。\n"
+"如果为 [code]true[/code],分é…该视区的帧缓冲时将使用完整浮点数精度(32 "
+"ä½ï¼‰è€Œä¸æ˜¯åŠæµ®ç‚¹æ•°ç²¾åº¦ï¼ˆ16 ä½ï¼‰ã€‚åªæœ‰åœ¨åŒä¸€ä¸ª [Viewport] 上通过 [method "
+"viewport_set_use_32_bpc_depth] 将 HDR 设为 [code]true[/code] 时有效。\n"
"[b]注æ„:[/b]仅在 GLES3 åŽç«¯ä¸­å¯ç”¨ã€‚"
#: doc/classes/VisualServer.xml
diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp
index f86c4d82ef..f4c87da9e9 100644
--- a/drivers/alsa/audio_driver_alsa.cpp
+++ b/drivers/alsa/audio_driver_alsa.cpp
@@ -50,7 +50,7 @@ Error AudioDriverALSA::init_device() {
// If there is a specified device check that it is really present
if (device_name != "Default") {
- Array list = get_device_list();
+ PackedStringArray list = get_device_list();
if (list.find(device_name) == -1) {
device_name = "Default";
new_device = "Default";
@@ -168,9 +168,8 @@ Error AudioDriverALSA::init() {
return ERR_CANT_OPEN;
}
- active = false;
- thread_exited = false;
- exit_thread = false;
+ active.clear();
+ exit_thread.clear();
Error err = init_device();
if (err == OK) {
@@ -183,11 +182,11 @@ Error AudioDriverALSA::init() {
void AudioDriverALSA::thread_func(void *p_udata) {
AudioDriverALSA *ad = static_cast<AudioDriverALSA *>(p_udata);
- while (!ad->exit_thread) {
+ while (!ad->exit_thread.is_set()) {
ad->lock();
ad->start_counting_ticks();
- if (!ad->active) {
+ if (!ad->active.is_set()) {
for (uint64_t i = 0; i < ad->period_size * ad->channels; i++) {
ad->samples_out.write[i] = 0;
}
@@ -203,7 +202,7 @@ void AudioDriverALSA::thread_func(void *p_udata) {
int todo = ad->period_size;
int total = 0;
- while (todo && !ad->exit_thread) {
+ while (todo && !ad->exit_thread.is_set()) {
int16_t *src = (int16_t *)ad->samples_out.ptr();
int wrote = snd_pcm_writei(ad->pcm_handle, (void *)(src + (total * ad->channels)), todo);
@@ -222,8 +221,8 @@ void AudioDriverALSA::thread_func(void *p_udata) {
wrote = snd_pcm_recover(ad->pcm_handle, wrote, 0);
if (wrote < 0) {
ERR_PRINT("ALSA: Failed and can't recover: " + String(snd_strerror(wrote)));
- ad->active = false;
- ad->exit_thread = true;
+ ad->active.clear();
+ ad->exit_thread.set();
}
}
}
@@ -241,8 +240,8 @@ void AudioDriverALSA::thread_func(void *p_udata) {
err = ad->init_device();
if (err != OK) {
- ad->active = false;
- ad->exit_thread = true;
+ ad->active.clear();
+ ad->exit_thread.set();
}
}
}
@@ -250,12 +249,10 @@ void AudioDriverALSA::thread_func(void *p_udata) {
ad->stop_counting_ticks();
ad->unlock();
}
-
- ad->thread_exited = true;
}
void AudioDriverALSA::start() {
- active = true;
+ active.set();
}
int AudioDriverALSA::get_mix_rate() const {
@@ -266,8 +263,8 @@ AudioDriver::SpeakerMode AudioDriverALSA::get_speaker_mode() const {
return speaker_mode;
}
-Array AudioDriverALSA::get_device_list() {
- Array list;
+PackedStringArray AudioDriverALSA::get_device_list() {
+ PackedStringArray list;
list.push_back("Default");
@@ -327,7 +324,7 @@ void AudioDriverALSA::finish_device() {
}
void AudioDriverALSA::finish() {
- exit_thread = true;
+ exit_thread.set();
thread.wait_to_finish();
finish_device();
diff --git a/drivers/alsa/audio_driver_alsa.h b/drivers/alsa/audio_driver_alsa.h
index dbb40fa088..fa1dba38ed 100644
--- a/drivers/alsa/audio_driver_alsa.h
+++ b/drivers/alsa/audio_driver_alsa.h
@@ -35,6 +35,7 @@
#include "core/os/mutex.h"
#include "core/os/thread.h"
+#include "core/templates/safe_refcount.h"
#include "servers/audio_server.h"
#include "asound-so_wrap.h"
@@ -64,9 +65,8 @@ class AudioDriverALSA : public AudioDriver {
snd_pcm_uframes_t period_size;
int channels = 0;
- bool active = false;
- bool thread_exited = false;
- mutable bool exit_thread = false;
+ SafeFlag active;
+ SafeFlag exit_thread;
public:
const char *get_name() const {
@@ -77,7 +77,7 @@ public:
virtual void start();
virtual int get_mix_rate() const;
virtual SpeakerMode get_speaker_mode() const;
- virtual Array get_device_list();
+ virtual PackedStringArray get_device_list();
virtual String get_device();
virtual void set_device(String device);
virtual void lock();
diff --git a/drivers/alsamidi/midi_driver_alsamidi.cpp b/drivers/alsamidi/midi_driver_alsamidi.cpp
index c334146dd2..d2a0076023 100644
--- a/drivers/alsamidi/midi_driver_alsamidi.cpp
+++ b/drivers/alsamidi/midi_driver_alsamidi.cpp
@@ -79,7 +79,7 @@ void MIDIDriverALSAMidi::thread_func(void *p_udata) {
int expected_size = 255;
int bytes = 0;
- while (!md->exit_thread) {
+ while (!md->exit_thread.is_set()) {
int ret;
md->lock();
@@ -149,14 +149,14 @@ Error MIDIDriverALSAMidi::open() {
}
snd_device_name_free_hint(hints);
- exit_thread = false;
+ exit_thread.clear();
thread.start(MIDIDriverALSAMidi::thread_func, this);
return OK;
}
void MIDIDriverALSAMidi::close() {
- exit_thread = true;
+ exit_thread.set();
thread.wait_to_finish();
for (int i = 0; i < connected_inputs.size(); i++) {
@@ -193,7 +193,7 @@ PackedStringArray MIDIDriverALSAMidi::get_connected_inputs() {
}
MIDIDriverALSAMidi::MIDIDriverALSAMidi() {
- exit_thread = false;
+ exit_thread.clear();
}
MIDIDriverALSAMidi::~MIDIDriverALSAMidi() {
diff --git a/drivers/alsamidi/midi_driver_alsamidi.h b/drivers/alsamidi/midi_driver_alsamidi.h
index b0fa8c297a..ac3530b1b2 100644
--- a/drivers/alsamidi/midi_driver_alsamidi.h
+++ b/drivers/alsamidi/midi_driver_alsamidi.h
@@ -36,6 +36,7 @@
#include "core/os/midi_driver.h"
#include "core/os/mutex.h"
#include "core/os/thread.h"
+#include "core/templates/safe_refcount.h"
#include "core/templates/vector.h"
#include "../alsa/asound-so_wrap.h"
@@ -47,7 +48,7 @@ class MIDIDriverALSAMidi : public MIDIDriver {
Vector<snd_rawmidi_t *> connected_inputs;
- bool exit_thread;
+ SafeFlag exit_thread;
static void thread_func(void *p_udata);
diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp
index cc38c2352f..1db85e2a60 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.cpp
+++ b/drivers/coreaudio/audio_driver_coreaudio.cpp
@@ -215,6 +215,7 @@ OSStatus AudioDriverCoreAudio::input_callback(void *inRefCon,
}
ad->lock();
+ ad->start_counting_ticks();
AudioBufferList bufferList;
bufferList.mNumberBuffers = 1;
@@ -237,6 +238,7 @@ OSStatus AudioDriverCoreAudio::input_callback(void *inRefCon,
ERR_PRINT("AudioUnitRender failed, code: " + itos(result));
}
+ ad->stop_counting_ticks();
ad->unlock();
return result;
@@ -493,8 +495,8 @@ Error AudioDriverCoreAudio::capture_stop() {
#ifdef MACOS_ENABLED
-Array AudioDriverCoreAudio::_get_device_list(bool capture) {
- Array list;
+PackedStringArray AudioDriverCoreAudio::_get_device_list(bool capture) {
+ PackedStringArray list;
list.push_back("Default");
@@ -637,7 +639,7 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) {
}
}
-Array AudioDriverCoreAudio::get_device_list() {
+PackedStringArray AudioDriverCoreAudio::get_device_list() {
return _get_device_list();
}
@@ -659,7 +661,7 @@ void AudioDriverCoreAudio::capture_set_device(const String &p_name) {
}
}
-Array AudioDriverCoreAudio::capture_get_device_list() {
+PackedStringArray AudioDriverCoreAudio::capture_get_device_list() {
return _get_device_list(true);
}
diff --git a/drivers/coreaudio/audio_driver_coreaudio.h b/drivers/coreaudio/audio_driver_coreaudio.h
index 7fac8a99ed..aac5077bb1 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.h
+++ b/drivers/coreaudio/audio_driver_coreaudio.h
@@ -59,7 +59,7 @@ class AudioDriverCoreAudio : public AudioDriver {
Vector<int16_t> input_buf;
#ifdef MACOS_ENABLED
- Array _get_device_list(bool capture = false);
+ PackedStringArray _get_device_list(bool capture = false);
void _set_device(const String &device, bool capture = false);
static OSStatus input_device_address_cb(AudioObjectID inObjectID,
@@ -107,11 +107,11 @@ public:
void stop();
#ifdef MACOS_ENABLED
- virtual Array get_device_list();
+ virtual PackedStringArray get_device_list();
virtual String get_device();
virtual void set_device(String device);
- virtual Array capture_get_device_list();
+ virtual PackedStringArray capture_get_device_list();
virtual void capture_set_device(const String &p_name);
virtual String capture_get_device();
#endif
diff --git a/drivers/gles3/effects/copy_effects.cpp b/drivers/gles3/effects/copy_effects.cpp
index c8e6c2b476..de0181f887 100644
--- a/drivers/gles3/effects/copy_effects.cpp
+++ b/drivers/gles3/effects/copy_effects.cpp
@@ -111,6 +111,7 @@ CopyEffects::~CopyEffects() {
glDeleteVertexArrays(1, &screen_triangle_array);
glDeleteBuffers(1, &quad);
glDeleteVertexArrays(1, &quad_array);
+ copy.shader.version_free(copy.shader_version);
}
void CopyEffects::copy_to_rect(const Rect2i &p_rect) {
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index d4ac3c993a..a960fced1f 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -201,6 +201,7 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
bool material_screen_texture_found = false;
Rect2 back_buffer_rect;
bool backbuffer_copy = false;
+ bool backbuffer_gen_mipmaps = false;
Item *ci = p_item_list;
Item *canvas_group_owner = nullptr;
@@ -225,6 +226,7 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
if (!material_screen_texture_found) {
backbuffer_copy = true;
back_buffer_rect = Rect2();
+ backbuffer_gen_mipmaps = md->shader_data->uses_screen_texture_mipmaps;
}
}
@@ -282,7 +284,7 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
item_count = 0;
- texture_storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect, true);
+ texture_storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect, backbuffer_gen_mipmaps);
backbuffer_copy = false;
material_screen_texture_found = true; //after a backbuffer copy, screen texture makes no further copies
@@ -320,6 +322,7 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
RID prev_material;
uint32_t index = 0;
GLES3::CanvasShaderData::BlendMode last_blend_mode = GLES3::CanvasShaderData::BLEND_MODE_MIX;
+ Color last_blend_color;
GLES3::CanvasShaderData *shader_data_cache = nullptr;
state.current_tex = texture_storage->texture_gl_get_default(GLES3::DEFAULT_GL_TEXTURE_WHITE);
@@ -376,8 +379,80 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
GLES3::CanvasShaderData::BlendMode blend_mode = shader_data_cache ? shader_data_cache->blend_mode : GLES3::CanvasShaderData::BLEND_MODE_MIX;
- if (last_blend_mode != blend_mode) {
- if (last_blend_mode == GLES3::CanvasShaderData::BLEND_MODE_DISABLED) {
+ _render_item(p_to_render_target, ci, canvas_transform_inverse, current_clip, p_lights, index, blend_mode, last_blend_mode, last_blend_color);
+ }
+ // Render last command
+ _render_batch(index);
+}
+
+void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, uint32_t &r_index, GLES3::CanvasShaderData::BlendMode p_blend_mode, GLES3::CanvasShaderData::BlendMode &r_last_blend_mode, Color &r_last_blend_color) {
+ // Used by Polygon and Mesh.
+ static const GLenum prim[5] = { GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP };
+
+ RS::CanvasItemTextureFilter current_filter = state.default_filter;
+ RS::CanvasItemTextureRepeat current_repeat = state.default_repeat;
+
+ if (p_item->texture_filter != RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT) {
+ current_filter = p_item->texture_filter;
+ }
+
+ if (p_item->texture_repeat != RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) {
+ current_repeat = p_item->texture_repeat;
+ }
+
+ Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform;
+ Transform2D draw_transform; // Used by transform command
+
+ Color base_color = p_item->final_modulate;
+
+ uint32_t base_flags = 0;
+
+ bool reclip = false;
+
+ bool skipping = false;
+
+ const Item::Command *c = p_item->commands;
+ while (c) {
+ if (skipping && c->type != Item::Command::TYPE_ANIMATION_SLICE) {
+ c = c->next;
+ continue;
+ }
+
+ if (c->type != Item::Command::TYPE_MESH) {
+ // For Meshes, this gets updated below.
+ _update_transform_2d_to_mat2x3(base_transform * draw_transform, state.instance_data_array[r_index].world);
+ }
+
+ for (int i = 0; i < 4; i++) {
+ state.instance_data_array[r_index].modulation[i] = 0.0;
+ state.instance_data_array[r_index].ninepatch_margins[i] = 0.0;
+ state.instance_data_array[r_index].src_rect[i] = 0.0;
+ state.instance_data_array[r_index].dst_rect[i] = 0.0;
+ state.instance_data_array[r_index].lights[i] = uint32_t(0);
+ }
+ state.instance_data_array[r_index].color_texture_pixel_size[0] = 0.0;
+ state.instance_data_array[r_index].color_texture_pixel_size[1] = 0.0;
+
+ state.instance_data_array[r_index].pad[0] = 0.0;
+ state.instance_data_array[r_index].pad[1] = 0.0;
+
+ state.instance_data_array[r_index].flags = base_flags | (state.instance_data_array[r_index == 0 ? 0 : r_index - 1].flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); //reset on each command for sanity, keep canvastexture binding config
+
+ GLES3::CanvasShaderData::BlendMode blend_mode = p_blend_mode;
+ Color blend_color;
+
+ if (c->type == Item::Command::TYPE_RECT) {
+ const Item::CommandRect *rect = static_cast<const Item::CommandRect *>(c);
+ if (rect->flags & CANVAS_RECT_LCD) {
+ blend_mode = GLES3::CanvasShaderData::BLEND_MODE_LCD;
+ blend_color = rect->modulate;
+ }
+ }
+
+ if (r_last_blend_mode != blend_mode || r_last_blend_color != blend_color) {
+ _render_batch(r_index);
+
+ if (r_last_blend_mode == GLES3::CanvasShaderData::BLEND_MODE_DISABLED) {
// re-enable it
glEnable(GL_BLEND);
} else if (blend_mode == GLES3::CanvasShaderData::BLEND_MODE_DISABLED) {
@@ -390,6 +465,16 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
// Nothing to do here.
} break;
+ case GLES3::CanvasShaderData::BLEND_MODE_LCD: {
+ glBlendEquation(GL_FUNC_ADD);
+ if (state.transparent_render_target) {
+ glBlendFuncSeparate(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ } else {
+ glBlendFuncSeparate(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_ZERO, GL_ONE);
+ }
+ glBlendColor(blend_color.r, blend_color.g, blend_color.b, blend_color.a);
+
+ } break;
case GLES3::CanvasShaderData::BLEND_MODE_MIX: {
glBlendEquation(GL_FUNC_ADD);
if (state.transparent_render_target) {
@@ -435,68 +520,10 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
} break;
}
- last_blend_mode = blend_mode;
+ r_last_blend_mode = blend_mode;
+ r_last_blend_color = blend_color;
}
- _render_item(p_to_render_target, ci, canvas_transform_inverse, current_clip, p_lights, index);
- }
- // Render last command
- _render_batch(index);
-}
-
-void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, uint32_t &r_index) {
- // Used by Polygon and Mesh.
- static const GLenum prim[5] = { GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP };
-
- RS::CanvasItemTextureFilter current_filter = state.default_filter;
- RS::CanvasItemTextureRepeat current_repeat = state.default_repeat;
-
- if (p_item->texture_filter != RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT) {
- current_filter = p_item->texture_filter;
- }
-
- if (p_item->texture_repeat != RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) {
- current_repeat = p_item->texture_repeat;
- }
-
- Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform;
- Transform2D draw_transform; // Used by transform command
-
- Color base_color = p_item->final_modulate;
-
- uint32_t base_flags = 0;
-
- bool reclip = false;
-
- bool skipping = false;
-
- const Item::Command *c = p_item->commands;
- while (c) {
- if (skipping && c->type != Item::Command::TYPE_ANIMATION_SLICE) {
- c = c->next;
- continue;
- }
-
- if (c->type != Item::Command::TYPE_MESH) {
- // For Meshes, this gets updated below.
- _update_transform_2d_to_mat2x3(base_transform * draw_transform, state.instance_data_array[r_index].world);
- }
-
- for (int i = 0; i < 4; i++) {
- state.instance_data_array[r_index].modulation[i] = 0.0;
- state.instance_data_array[r_index].ninepatch_margins[i] = 0.0;
- state.instance_data_array[r_index].src_rect[i] = 0.0;
- state.instance_data_array[r_index].dst_rect[i] = 0.0;
- state.instance_data_array[r_index].lights[i] = uint32_t(0);
- }
- state.instance_data_array[r_index].color_texture_pixel_size[0] = 0.0;
- state.instance_data_array[r_index].color_texture_pixel_size[1] = 0.0;
-
- state.instance_data_array[r_index].pad[0] = 0.0;
- state.instance_data_array[r_index].pad[1] = 0.0;
-
- state.instance_data_array[r_index].flags = base_flags | (state.instance_data_array[r_index == 0 ? 0 : r_index - 1].flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); //reset on each command for sanity, keep canvastexture binding config
-
switch (c->type) {
case Item::Command::TYPE_RECT: {
const Item::CommandRect *rect = static_cast<const Item::CommandRect *>(c);
@@ -567,6 +594,8 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
state.instance_data_array[r_index].msdf[1] = rect->outline; // Outline size.
state.instance_data_array[r_index].msdf[2] = 0.f; // Reserved.
state.instance_data_array[r_index].msdf[3] = 0.f; // Reserved.
+ } else if (rect->flags & CANVAS_RECT_LCD) {
+ state.instance_data_array[r_index].flags |= FLAGS_USE_LCD;
}
state.instance_data_array[r_index].modulation[0] = rect->modulate.r * base_color.r;
@@ -993,7 +1022,7 @@ void RasterizerCanvasGLES3::_bind_instance_data_buffer(uint32_t p_max_index) {
}
glBindBufferBase(GL_UNIFORM_BUFFER, INSTANCE_UNIFORM_LOCATION, state.canvas_instance_data_buffers[state.current_buffer]);
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
//WebGL 2.0 does not support mapping buffers, so use slow glBufferData instead
glBufferData(GL_UNIFORM_BUFFER, sizeof(InstanceData) * p_max_index, state.instance_data_array, GL_DYNAMIC_DRAW);
#else
@@ -1608,6 +1637,8 @@ void fragment() {
RasterizerCanvasGLES3::~RasterizerCanvasGLES3() {
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+ memdelete_arr(state.instance_data_array);
+
GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_free(state.canvas_shader_default_version);
material_storage->material_free(default_canvas_group_material);
material_storage->shader_free(default_canvas_group_shader);
diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h
index f920e37130..372ac00493 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.h
+++ b/drivers/gles3/rasterizer_canvas_gles3.h
@@ -73,6 +73,7 @@ class RasterizerCanvasGLES3 : public RendererCanvasRender {
FLAGS_DEFAULT_SPECULAR_MAP_USED = (1 << 27),
FLAGS_USE_MSDF = (1 << 28),
+ FLAGS_USE_LCD = (1 << 29),
};
enum {
@@ -249,7 +250,7 @@ public:
void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) override;
void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer = false);
- void _render_item(RID p_render_target, const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, uint32_t &r_index);
+ void _render_item(RID p_render_target, const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, uint32_t &r_index, GLES3::CanvasShaderData::BlendMode p_blend_mode, GLES3::CanvasShaderData::BlendMode &r_last_blend_mode, Color &r_last_blend_color);
void _render_batch(uint32_t &p_max_index);
void _bind_instance_data_buffer(uint32_t p_max_index);
void _allocate_instance_data_buffer();
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index 33303b1e38..7537636356 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -69,7 +69,7 @@
#endif
#endif
-#if !defined(IOS_ENABLED) && !defined(JAVASCRIPT_ENABLED)
+#if !defined(IOS_ENABLED) && !defined(WEB_ENABLED)
// We include EGL below to get debug callback on GLES2 platforms,
// but EGL is not available on iOS.
#define CAN_DEBUG
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 26d84aa6a3..cb479dda39 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -496,7 +496,7 @@ void RasterizerSceneGLES3::_update_dirty_skys() {
while (sky) {
if (sky->radiance == 0) {
- sky->mipmap_count = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBA8) - 2;
+ sky->mipmap_count = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBA8) - 1;
// Left uninitialized, will attach a texture at render time
glGenFramebuffers(1, &sky->radiance_framebuffer);
@@ -523,7 +523,7 @@ void RasterizerSceneGLES3::_update_dirty_skys() {
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, sky->mipmap_count);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, sky->mipmap_count - 1);
glGenTextures(1, &sky->raw_radiance);
glBindTexture(GL_TEXTURE_CUBE_MAP, sky->raw_radiance);
@@ -544,7 +544,8 @@ void RasterizerSceneGLES3::_update_dirty_skys() {
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0);
- glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, sky->mipmap_count);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, sky->mipmap_count - 1);
+
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
}
@@ -647,7 +648,7 @@ void RasterizerSceneGLES3::_setup_sky(RID p_env, RID p_render_buffers, const Pag
float angular_diameter = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
if (angular_diameter > 0.0) {
- angular_diameter = Math::tan(Math::deg2rad(angular_diameter));
+ angular_diameter = Math::tan(Math::deg_to_rad(angular_diameter));
} else {
angular_diameter = 0.0;
}
@@ -701,6 +702,7 @@ void RasterizerSceneGLES3::_setup_sky(RID p_env, RID p_render_buffers, const Pag
}
if (!sky->radiance) {
+ _invalidate_sky(sky);
_update_dirty_skys();
}
}
@@ -865,7 +867,6 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, cm.matrix[2][0], cm.matrix[0][0], cm.matrix[2][1], cm.matrix[1][1], shader_data->version, SkyShaderGLES3::MODE_CUBEMAP);
- // Bind a vertex array or else OpenGL complains. We won't actually use it
glBindVertexArray(sky_globals.screen_triangle_array);
glViewport(0, 0, sky->radiance_size, sky->radiance_size);
@@ -879,7 +880,7 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
}
if (update_single_frame) {
- for (int i = 0; i <= max_processing_layer; i++) {
+ for (int i = 0; i < max_processing_layer; i++) {
_filter_sky_radiance(sky, i);
}
} else {
@@ -889,7 +890,7 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
sky->reflection_dirty = false;
} else {
- if (sky_mode == RS::SKY_MODE_INCREMENTAL && sky->processing_layer <= max_processing_layer) {
+ if (sky_mode == RS::SKY_MODE_INCREMENTAL && sky->processing_layer < max_processing_layer) {
_filter_sky_radiance(sky, sky->processing_layer);
sky->processing_layer++;
}
@@ -1005,7 +1006,9 @@ void RasterizerSceneGLES3::_filter_sky_radiance(Sky *p_sky, int p_base_layer) {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, p_sky->radiance, p_base_layer);
#ifdef DEBUG_ENABLED
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- ERR_CONTINUE(status != GL_FRAMEBUFFER_COMPLETE);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ WARN_PRINT("Could not bind sky radiance face: " + itos(i) + ", status: " + GLES3::TextureStorage::get_singleton()->get_framebuffer_error(status));
+ }
#endif
material_storage->shaders.cubemap_filter_shader.version_set_uniform(CubemapFilterShaderGLES3::FACE_ID, i, scene_globals.cubemap_filter_shader_version, mode);
@@ -1515,7 +1518,7 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
light_data.color[2] = linear_col.b;
float size = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
- light_data.size = 1.0 - Math::cos(Math::deg2rad(size)); //angle to cosine offset
+ light_data.size = 1.0 - Math::cos(Math::deg_to_rad(size)); //angle to cosine offset
light_data.specular = light_storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR);
@@ -1642,27 +1645,27 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
light_data.inv_spot_attenuation = 1.0f / light_storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ATTENUATION);
float spot_angle = light_storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ANGLE);
- light_data.cos_spot_angle = Math::cos(Math::deg2rad(spot_angle));
+ light_data.cos_spot_angle = Math::cos(Math::deg_to_rad(spot_angle));
light_data.specular_amount = light_storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR) * 2.0;
- light_data.shadow_enabled = false;
+ light_data.shadow_opacity = 0.0;
}
// TODO, to avoid stalls, should rotate between 3 buffers based on frame index.
// TODO, consider mapping the buffer as in 2D
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_OMNILIGHT_UNIFORM_LOCATION, scene_state.omni_light_buffer);
if (r_omni_light_count) {
- glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_OMNILIGHT_UNIFORM_LOCATION, scene_state.omni_light_buffer);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(LightData) * r_omni_light_count, scene_state.omni_lights);
}
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_SPOTLIGHT_UNIFORM_LOCATION, scene_state.spot_light_buffer);
if (r_spot_light_count) {
- glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_SPOTLIGHT_UNIFORM_LOCATION, scene_state.spot_light_buffer);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(LightData) * r_spot_light_count, scene_state.spot_lights);
}
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DIRECTIONAL_LIGHT_UNIFORM_LOCATION, scene_state.directional_light_buffer);
if (r_directional_light_count) {
- glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DIRECTIONAL_LIGHT_UNIFORM_LOCATION, scene_state.directional_light_buffer);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(DirectionalLightData) * r_directional_light_count, scene_state.directional_lights);
}
glBindBuffer(GL_UNIFORM_BUFFER, 0);
@@ -2146,7 +2149,9 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params,
index_array_gl = mesh_storage->mesh_surface_get_index_buffer(mesh_surface, surf->lod_index);
if (prev_vertex_array_gl != vertex_array_gl) {
- glBindVertexArray(vertex_array_gl);
+ if (vertex_array_gl != 0) {
+ glBindVertexArray(vertex_array_gl);
+ }
prev_vertex_array_gl = vertex_array_gl;
}
@@ -2303,7 +2308,7 @@ void RasterizerSceneGLES3::render_buffers_configure(RID p_render_buffers, RID p_
glGenTextures(1, &rb->depth_texture);
glBindTexture(GL_TEXTURE_2D, rb->depth_texture);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, rt->size.x, rt->size.y, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
@@ -2421,6 +2426,8 @@ void RasterizerSceneGLES3::light_projectors_set_filter(RS::LightProjectorFilter
}
RasterizerSceneGLES3::RasterizerSceneGLES3() {
+ singleton = this;
+
GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
GLES3::Config *config = GLES3::Config::get_singleton();
@@ -2620,6 +2627,8 @@ RasterizerSceneGLES3::~RasterizerSceneGLES3() {
glDeleteBuffers(1, &sky_globals.directional_light_buffer);
memdelete_arr(sky_globals.directional_lights);
memdelete_arr(sky_globals.last_frame_directional_lights);
+
+ singleton = nullptr;
}
#endif // GLES3_ENABLED
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index e227b2df82..a54d87a3a3 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -165,7 +165,7 @@ private:
float inv_spot_attenuation;
float cos_spot_angle;
float specular_amount;
- uint32_t shadow_enabled;
+ float shadow_opacity;
};
static_assert(sizeof(LightData) % 16 == 0, "LightData size must be a multiple of 16 bytes");
diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp
index 21ccef3518..033f10dbc5 100644
--- a/drivers/gles3/shader_gles3.cpp
+++ b/drivers/gles3/shader_gles3.cpp
@@ -472,7 +472,7 @@ String ShaderGLES3::_version_get_sha1(Version *p_version) const {
bool ShaderGLES3::_load_from_cache(Version *p_version) {
#if 0
String sha1 = _version_get_sha1(p_version);
- String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache";
+ String path = shader_cache_dir.path_join(name).path_join(base_sha256).path_join(sha1) + ".cache";
Ref<FileAccess> f = FileAccess::open(path, FileAccess::READ);
if (f.is_null()) {
@@ -538,7 +538,7 @@ bool ShaderGLES3::_load_from_cache(Version *p_version) {
void ShaderGLES3::_save_to_cache(Version *p_version) {
#if 0
String sha1 = _version_get_sha1(p_version);
- String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache";
+ String path = shader_cache_dir.path_join(name).path_join(base_sha256).path_join(sha1) + ".cache";
Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE);
ERR_FAIL_COND(f.is_null());
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index 4df818cd4c..5ec25327be 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -473,7 +473,13 @@ void main() {
float a = clamp(d * px_size + 0.5, 0.0, 1.0);
color.a = a * color.a;
}
-
+ } else if (bool(draw_data[draw_data_instance].flags & FLAGS_USE_LCD)) {
+ vec4 lcd_sample = texture(color_texture, uv);
+ if (lcd_sample.a == 1.0) {
+ color.rgb = lcd_sample.rgb * color.a;
+ } else {
+ color = vec4(0.0, 0.0, 0.0, 0.0);
+ }
} else {
#else
{
diff --git a/drivers/gles3/shaders/canvas_uniforms_inc.glsl b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
index 852dccf415..6b61fe9375 100644
--- a/drivers/gles3/shaders/canvas_uniforms_inc.glsl
+++ b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
@@ -25,6 +25,7 @@
#define FLAGS_DEFAULT_SPECULAR_MAP_USED uint(1 << 27)
#define FLAGS_USE_MSDF uint(1 << 28)
+#define FLAGS_USE_LCD uint(1 << 29)
// must be always 128 bytes long
struct DrawData {
diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl
index 57f0d7d0b8..88464876f1 100644
--- a/drivers/gles3/shaders/cubemap_filter.glsl
+++ b/drivers/gles3/shaders/cubemap_filter.glsl
@@ -106,12 +106,12 @@ void main() {
T[2] = N;
for (int sample_num = 0; sample_num < sample_count; sample_num++) {
- vec4 sample = sample_directions_mip[sample_num];
- vec3 L = T * sample.xyz;
- vec3 val = textureLod(source_cube, L, sample.w).rgb;
+ vec4 sample_direction_mip = sample_directions_mip[sample_num];
+ vec3 L = T * sample_direction_mip.xyz;
+ vec3 val = textureLod(source_cube, L, sample_direction_mip.w).rgb;
// Mix using linear
val = srgb_to_linear(val);
- sum.rgb += val * sample.z;
+ sum.rgb += val * sample_direction_mip.z;
}
sum /= weight;
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index cd88ba6cb7..c7fdd6ebd8 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -35,8 +35,8 @@ USE_RADIANCE_MAP = true
/*
from RenderingServer:
ARRAY_VERTEX = 0, // RG32F or RGB32F (depending on 2D bit)
-ARRAY_NORMAL = 1, // A2B10G10R10, A is ignored.
-ARRAY_TANGENT = 2, // A2B10G10R10, A flips sign of binormal.
+ARRAY_NORMAL = 1, // RG16 octahedral compression
+ARRAY_TANGENT = 2, // RG16 octahedral compression, sign stored in sign of G
ARRAY_COLOR = 3, // RGBA8
ARRAY_TEX_UV = 4, // RG32F
ARRAY_TEX_UV2 = 5, // RG32F
@@ -54,11 +54,11 @@ layout(location = 0) in highp vec3 vertex_attrib;
/* clang-format on */
#ifdef NORMAL_USED
-layout(location = 1) in vec3 normal_attrib;
+layout(location = 1) in vec2 normal_attrib;
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-layout(location = 2) in vec4 tangent_attrib;
+layout(location = 2) in vec2 tangent_attrib;
#endif
#if defined(COLOR_USED)
@@ -97,6 +97,13 @@ layout(location = 10) in uvec4 bone_attrib;
layout(location = 11) in vec4 weight_attrib;
#endif
+vec3 oct_to_vec3(vec2 e) {
+ vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));
+ float t = max(-v.z, 0.0);
+ v.xy += t * -sign(v.xy);
+ return v;
+}
+
#ifdef USE_INSTANCING
layout(location = 12) in highp vec4 instance_xform0;
layout(location = 13) in highp vec4 instance_xform1;
@@ -209,13 +216,14 @@ void main() {
#endif
#ifdef NORMAL_USED
- vec3 normal = normal_attrib * 2.0 - 1.0;
+ vec3 normal = oct_to_vec3(normal_attrib * 2.0 - 1.0);
#endif
highp mat3 model_normal_matrix = mat3(model_matrix);
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
- vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0;
- float binormalf = tangent_attrib.a * 2.0 - 1.0;
+ vec2 signed_tangent_attrib = tangent_attrib * 2.0 - 1.0;
+ vec3 tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0));
+ float binormalf = sign(signed_tangent_attrib.y);
vec3 binormal = normalize(cross(normal, tangent) * binormalf);
#endif
@@ -495,7 +503,7 @@ struct LightData { //this structure needs to be as packed as possible
mediump float cone_attenuation;
mediump float cone_angle;
mediump float specular_amount;
- bool shadow_enabled;
+ mediump float shadow_opacity;
};
#ifndef DISABLE_LIGHT_OMNI
layout(std140) uniform OmniLightData { // ubo:5
@@ -686,7 +694,10 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
#endif // LIGHT_ANISOTROPY_USED
// F
float cLdotH5 = SchlickFresnel(cLdotH);
- vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0);
+ // Calculate Fresnel using cheap approximate specular occlusion term from Filament:
+ // https://google.github.io/filament/Filament.html#lighting/occlusion/specularocclusion
+ float f90 = clamp(50.0 * f0.g, 0.0, 1.0);
+ vec3 F = f0 + (f90 - f0) * cLdotH5;
vec3 specular_brdf_NL = cNdotL * D * F * G;
@@ -751,7 +762,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
if (omni_lights[idx].size > 0.0) {
float t = omni_lights[idx].size / max(0.001, light_length);
- size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
+ size_A = max(0.0, 1.0 - 1.0 / sqrt(1.0 + t * t));
}
light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, omni_attenuation, f0, roughness, metallic, omni_lights[idx].specular_amount, albedo, alpha,
@@ -800,7 +811,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
if (spot_lights[idx].size > 0.0) {
float t = spot_lights[idx].size / max(0.001, light_length);
- size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
+ size_A = max(0.0, 1.0 - 1.0 / sqrt(1.0 + t * t));
}
light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, spot_attenuation, f0, roughness, metallic, spot_lights[idx].specular_amount, albedo, alpha,
@@ -1049,6 +1060,7 @@ void main() {
#else
vec3 ref_vec = reflect(-view, normal);
#endif
+ ref_vec = mix(ref_vec, normal, roughness * roughness);
float horizon = min(1.0 + dot(ref_vec, normal), 1.0);
ref_vec = scene_data.radiance_inverse_xform * ref_vec;
specular_light = textureLod(radiance_map, ref_vec, roughness * RADIANCE_MAX_LOD).rgb;
@@ -1107,7 +1119,7 @@ void main() {
float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y;
vec2 env = vec2(-1.04, 1.04) * a004 + r.zw;
- specular_light *= env.x * f0 + env.y;
+ specular_light *= env.x * f0 + env.y * clamp(50.0 * f0.g, 0.0, 1.0);
#endif
}
diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp
index f2809734a9..6cc65e7bb2 100644
--- a/drivers/gles3/storage/config.cpp
+++ b/drivers/gles3/storage/config.cpp
@@ -64,7 +64,14 @@ Config::Config() {
#else
float_texture_supported = extensions.has("GL_ARB_texture_float") || extensions.has("GL_OES_texture_float");
etc2_supported = true;
+#if defined(ANDROID_ENABLED) || defined(IOS_ENABLED)
+ // Some Android devices report support for S3TC but we don't expect that and don't export the textures.
+ // This could be fixed but so few devices support it that it doesn't seem useful (and makes bigger APKs).
+ // For good measure we do the same hack for iOS, just in case.
+ s3tc_supported = false;
+#else
s3tc_supported = extensions.has("GL_EXT_texture_compression_dxt1") || extensions.has("GL_EXT_texture_compression_s3tc") || extensions.has("WEBGL_compressed_texture_s3tc");
+#endif
rgtc_supported = extensions.has("GL_EXT_texture_compression_rgtc") || extensions.has("GL_ARB_texture_compression_rgtc") || extensions.has("EXT_texture_compression_rgtc");
#endif
diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp
index 22578c9e91..e2781bfbc0 100644
--- a/drivers/gles3/storage/light_storage.cpp
+++ b/drivers/gles3/storage/light_storage.cpp
@@ -70,6 +70,7 @@ void LightStorage::_light_initialize(RID p_light, RS::LightType p_type) {
light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET] = 0.6;
light.param[RS::LIGHT_PARAM_SHADOW_FADE_START] = 0.8;
light.param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 1.0;
+ light.param[RS::LIGHT_PARAM_SHADOW_OPACITY] = 1.0;
light.param[RS::LIGHT_PARAM_SHADOW_BIAS] = 0.02;
light.param[RS::LIGHT_PARAM_SHADOW_BLUR] = 0;
light.param[RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE] = 20.0;
@@ -317,7 +318,7 @@ AABB LightStorage::light_get_aabb(RID p_light) const {
switch (light->type) {
case RS::LIGHT_SPOT: {
float len = light->param[RS::LIGHT_PARAM_RANGE];
- float size = Math::tan(Math::deg2rad(light->param[RS::LIGHT_PARAM_SPOT_ANGLE])) * len;
+ float size = Math::tan(Math::deg_to_rad(light->param[RS::LIGHT_PARAM_SPOT_ANGLE])) * len;
return AABB(Vector3(-size, -size, -len), Vector3(size * 2, size * 2, len));
};
case RS::LIGHT_OMNI: {
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index 68045930b0..a64c7f7200 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -1083,6 +1083,12 @@ void MaterialData::update_textures(const HashMap<StringName, Variant> &p_paramet
Vector<RID> textures;
+ if (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE ||
+ p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE ||
+ p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
+ continue;
+ }
+
if (p_texture_uniforms[i].global) {
uses_global_textures = true;
@@ -1156,6 +1162,9 @@ void MaterialData::update_textures(const HashMap<StringName, Variant> &p_paramet
case ShaderLanguage::ShaderNode::Uniform::HINT_DEFAULT_BLACK: {
gl_texture = texture_storage->texture_gl_get_default(DEFAULT_GL_TEXTURE_BLACK);
} break;
+ case ShaderLanguage::ShaderNode::Uniform::HINT_DEFAULT_TRANSPARENT: {
+ gl_texture = texture_storage->texture_gl_get_default(DEFAULT_GL_TEXTURE_TRANSPARENT);
+ } break;
case ShaderLanguage::ShaderNode::Uniform::HINT_ANISOTROPY: {
gl_texture = texture_storage->texture_gl_get_default(DEFAULT_GL_TEXTURE_ANISO);
} break;
@@ -1447,8 +1456,8 @@ MaterialStorage::MaterialStorage() {
actions.renames["UV2"] = "uv2_interp";
actions.renames["COLOR"] = "color_interp";
actions.renames["POINT_SIZE"] = "gl_PointSize";
- actions.renames["INSTANCE_ID"] = "gl_InstanceIndex";
- actions.renames["VERTEX_ID"] = "gl_VertexIndex";
+ actions.renames["INSTANCE_ID"] = "gl_InstanceID";
+ actions.renames["VERTEX_ID"] = "gl_VertexID";
actions.renames["ALPHA_SCISSOR_THRESHOLD"] = "alpha_scissor_threshold";
actions.renames["ALPHA_HASH_SCALE"] = "alpha_hash_scale";
@@ -1489,9 +1498,9 @@ MaterialStorage::MaterialStorage() {
actions.renames["POINT_COORD"] = "gl_PointCoord";
actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
actions.renames["SCREEN_UV"] = "screen_uv";
- actions.renames["SCREEN_TEXTURE"] = "color_buffer";
- actions.renames["DEPTH_TEXTURE"] = "depth_buffer";
- actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer";
+ //actions.renames["SCREEN_TEXTURE"] = "color_buffer"; //Not implemented in 3D yet.
+ //actions.renames["DEPTH_TEXTURE"] = "depth_buffer"; // Not implemented in 3D yet.
+ //actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer"; // Not implemented in 3D yet
actions.renames["DEPTH"] = "gl_FragDepth";
actions.renames["OUTPUT_IS_SRGB"] = "true";
actions.renames["FOG"] = "fog";
@@ -1505,6 +1514,11 @@ MaterialStorage::MaterialStorage() {
actions.renames["CUSTOM3"] = "custom3_attrib";
actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
+ actions.renames["NODE_POSITION_WORLD"] = "model_matrix[3].xyz";
+ actions.renames["CAMERA_POSITION_WORLD"] = "scene_data.inv_view_matrix[3].xyz";
+ actions.renames["CAMERA_DIRECTION_WORLD"] = "scene_data.view_matrix[3].xyz";
+ actions.renames["NODE_POSITION_VIEW"] = "(model_matrix * scene_data.view_matrix)[3].xyz";
+
actions.renames["VIEW_INDEX"] = "ViewIndex";
actions.renames["VIEW_MONO_LEFT"] = "0";
actions.renames["VIEW_RIGHT"] = "1";
@@ -2320,11 +2334,14 @@ void MaterialStorage::global_shader_uniforms_instance_update(RID p_instance, int
ShaderLanguage::TYPE_VEC3, // vec3
ShaderLanguage::TYPE_IVEC3, //vec3i
ShaderLanguage::TYPE_MAX, //xform2d not supported here
+ ShaderLanguage::TYPE_VEC4, //vec4
+ ShaderLanguage::TYPE_IVEC4, //vec4i
ShaderLanguage::TYPE_VEC4, //plane
ShaderLanguage::TYPE_VEC4, //quat
ShaderLanguage::TYPE_MAX, //aabb not supported here
ShaderLanguage::TYPE_MAX, //basis not supported here
ShaderLanguage::TYPE_MAX, //xform not supported here
+ ShaderLanguage::TYPE_MAX, //projection not supported here
ShaderLanguage::TYPE_VEC4 //color
};
@@ -2511,11 +2528,11 @@ String MaterialStorage::shader_get_code(RID p_shader) const {
return shader->code;
}
-void MaterialStorage::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const {
+void MaterialStorage::shader_get_shader_uniform_list(RID p_shader, List<PropertyInfo> *p_param_list) const {
GLES3::Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_COND(!shader);
if (shader->data) {
- return shader->data->get_param_list(p_param_list);
+ return shader->data->get_shader_uniform_list(p_param_list);
}
}
@@ -2747,14 +2764,14 @@ bool MaterialStorage::material_casts_shadows(RID p_material) {
return true; //by default everything casts shadows
}
-void MaterialStorage::material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) {
+void MaterialStorage::material_get_instance_shader_uniforms(RID p_material, List<InstanceShaderParam> *r_parameters) {
GLES3::Material *material = material_owner.get_or_null(p_material);
ERR_FAIL_COND(!material);
if (material->shader && material->shader->data) {
material->shader->data->get_instance_param_list(r_parameters);
if (material->next_pass.is_valid()) {
- material_get_instance_shader_parameters(material->next_pass, r_parameters);
+ material_get_instance_shader_uniforms(material->next_pass, r_parameters);
}
}
}
@@ -2778,6 +2795,7 @@ void CanvasShaderData::set_code(const String &p_code) {
ubo_size = 0;
uniforms.clear();
uses_screen_texture = false;
+ uses_screen_texture_mipmaps = false;
uses_sdf = false;
uses_time = false;
@@ -2788,7 +2806,6 @@ void CanvasShaderData::set_code(const String &p_code) {
ShaderCompiler::GeneratedCode gen_code;
int blend_modei = BLEND_MODE_MIX;
- uses_screen_texture = false;
ShaderCompiler::IdentifierActions actions;
actions.entry_point_stages["vertex"] = ShaderCompiler::STAGE_VERTEX;
@@ -2815,6 +2832,7 @@ void CanvasShaderData::set_code(const String &p_code) {
}
blend_mode = BlendMode(blend_modei);
+ uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
#if 0
print_line("**compiling shader:");
@@ -2822,12 +2840,16 @@ void CanvasShaderData::set_code(const String &p_code) {
for (int i = 0; i < gen_code.defines.size(); i++) {
print_line(gen_code.defines[i]);
}
+
+ HashMap<String, String>::Iterator el = gen_code.code.begin();
+ while (el) {
+ print_line("\n**code " + el->key + ":\n" + el->value);
+ ++el;
+ }
+
print_line("\n**uniforms:\n" + gen_code.uniforms);
- print_line("\n**vertex_globals:\n" + gen_code.vertex_global);
- print_line("\n**vertex_code:\n" + gen_code.vertex);
- print_line("\n**fragment_globals:\n" + gen_code.fragment_global);
- print_line("\n**fragment_code:\n" + gen_code.fragment);
- print_line("\n**light_code:\n" + gen_code.light);
+ print_line("\n**vertex_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX]);
+ print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
#endif
Vector<StringName> texture_uniform_names;
@@ -2862,11 +2884,14 @@ void CanvasShaderData::set_default_texture_param(const StringName &p_name, RID p
}
}
-void CanvasShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+void CanvasShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
HashMap<int, StringName> order;
for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL ||
+ E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE ||
+ E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE ||
+ E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
continue;
}
if (E.value.texture_order >= 0) {
@@ -3059,12 +3084,16 @@ void SkyShaderData::set_code(const String &p_code) {
for (int i = 0; i < gen_code.defines.size(); i++) {
print_line(gen_code.defines[i]);
}
+
+ HashMap<String, String>::Iterator el = gen_code.code.begin();
+ while (el) {
+ print_line("\n**code " + el->key + ":\n" + el->value);
+ ++el;
+ }
+
print_line("\n**uniforms:\n" + gen_code.uniforms);
- // print_line("\n**vertex_globals:\n" + gen_code.vertex_global);
- // print_line("\n**vertex_code:\n" + gen_code.vertex);
- print_line("\n**fragment_globals:\n" + gen_code.fragment_global);
- print_line("\n**fragment_code:\n" + gen_code.fragment);
- print_line("\n**light_code:\n" + gen_code.light);
+ print_line("\n**vertex_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX]);
+ print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
#endif
Vector<StringName> texture_uniform_names;
@@ -3099,7 +3128,7 @@ void SkyShaderData::set_default_texture_param(const StringName &p_name, RID p_te
}
}
-void SkyShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+void SkyShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
RBMap<int, StringName> order;
for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
@@ -3242,7 +3271,6 @@ void SceneShaderData::set_code(const String &p_code) {
valid = false;
ubo_size = 0;
uniforms.clear();
- uses_screen_texture = false;
if (code.is_empty()) {
return; //just invalid, but no error
@@ -3367,6 +3395,7 @@ void SceneShaderData::set_code(const String &p_code) {
vertex_input_mask |= uses_custom3 << 8;
vertex_input_mask |= uses_bones << 9;
vertex_input_mask |= uses_weights << 10;
+ uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
#if 0
print_line("**compiling shader:");
@@ -3375,11 +3404,10 @@ void SceneShaderData::set_code(const String &p_code) {
print_line(gen_code.defines[i]);
}
- Map<String, String>::Element *el = gen_code.code.front();
+ HashMap<String, String>::Iterator el = gen_code.code.begin();
while (el) {
- print_line("\n**code " + el->key() + ":\n" + el->value());
-
- el = el->next();
+ print_line("\n**code " + el->key + ":\n" + el->value);
+ ++el;
}
print_line("\n**uniforms:\n" + gen_code.uniforms);
@@ -3424,11 +3452,14 @@ void SceneShaderData::set_default_texture_param(const StringName &p_name, RID p_
}
}
-void SceneShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+void SceneShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
RBMap<int, StringName> order;
for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL ||
+ E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE ||
+ E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE ||
+ E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
continue;
}
diff --git a/drivers/gles3/storage/material_storage.h b/drivers/gles3/storage/material_storage.h
index 8fc15ddcba..a2a7554821 100644
--- a/drivers/gles3/storage/material_storage.h
+++ b/drivers/gles3/storage/material_storage.h
@@ -54,7 +54,7 @@ namespace GLES3 {
struct ShaderData {
virtual void set_code(const String &p_Code) = 0;
virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) = 0;
- virtual void get_param_list(List<PropertyInfo> *p_param_list) const = 0;
+ virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const = 0;
virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const = 0;
virtual bool is_param_texture(const StringName &p_param) const = 0;
@@ -142,6 +142,7 @@ struct CanvasShaderData : public ShaderData {
BLEND_MODE_MUL,
BLEND_MODE_PMALPHA,
BLEND_MODE_DISABLED,
+ BLEND_MODE_LCD,
};
bool valid;
@@ -159,12 +160,13 @@ struct CanvasShaderData : public ShaderData {
HashMap<StringName, HashMap<int, RID>> default_texture_params;
bool uses_screen_texture = false;
+ bool uses_screen_texture_mipmaps = false;
bool uses_sdf = false;
bool uses_time = false;
virtual void set_code(const String &p_Code);
virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
- virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
virtual bool is_param_texture(const StringName &p_param) const;
@@ -215,7 +217,7 @@ struct SkyShaderData : public ShaderData {
virtual void set_code(const String &p_Code);
virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
- virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
virtual bool is_param_texture(const StringName &p_param) const;
virtual bool is_animated() const;
@@ -312,6 +314,7 @@ struct SceneShaderData : public ShaderData {
bool uses_sss;
bool uses_transmittance;
bool uses_screen_texture;
+ bool uses_screen_texture_mipmaps;
bool uses_depth_texture;
bool uses_normal_texture;
bool uses_time;
@@ -335,7 +338,7 @@ struct SceneShaderData : public ShaderData {
virtual void set_code(const String &p_Code);
virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
- virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
virtual bool is_param_texture(const StringName &p_param) const;
@@ -545,7 +548,7 @@ public:
virtual void shader_set_code(RID p_shader, const String &p_code) override;
virtual void shader_set_path_hint(RID p_shader, const String &p_path) override;
virtual String shader_get_code(RID p_shader) const override;
- virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const override;
+ virtual void shader_get_shader_uniform_list(RID p_shader, List<PropertyInfo> *p_param_list) const override;
virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture, int p_index) override;
virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name, int p_index) const override;
@@ -576,7 +579,7 @@ public:
virtual bool material_is_animated(RID p_material) override;
virtual bool material_casts_shadows(RID p_material) override;
- virtual void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) override;
+ virtual void material_get_instance_shader_uniforms(RID p_material, List<InstanceShaderParam> *r_parameters) override;
virtual void material_update_dependency(RID p_material, DependencyTracker *p_instance) override;
diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp
index 88b81805fa..ddf94af5b8 100644
--- a/drivers/gles3/storage/mesh_storage.cpp
+++ b/drivers/gles3/storage/mesh_storage.cpp
@@ -124,11 +124,11 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
} break;
case RS::ARRAY_NORMAL: {
- stride += sizeof(int32_t);
+ stride += sizeof(uint16_t) * 2;
} break;
case RS::ARRAY_TANGENT: {
- stride += sizeof(int32_t);
+ stride += sizeof(uint16_t) * 2;
} break;
case RS::ARRAY_COLOR: {
@@ -186,11 +186,13 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
s->format = p_surface.format;
s->primitive = p_surface.primitive;
- glGenBuffers(1, &s->vertex_buffer);
- glBindBuffer(GL_ARRAY_BUFFER, s->vertex_buffer);
- glBufferData(GL_ARRAY_BUFFER, p_surface.vertex_data.size(), p_surface.vertex_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
- glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
- s->vertex_buffer_size = p_surface.vertex_data.size();
+ if (p_surface.vertex_data.size()) {
+ glGenBuffers(1, &s->vertex_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, s->vertex_buffer);
+ glBufferData(GL_ARRAY_BUFFER, p_surface.vertex_data.size(), p_surface.vertex_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+ s->vertex_buffer_size = p_surface.vertex_data.size();
+ }
if (p_surface.attribute_data.size()) {
glGenBuffers(1, &s->attribute_buffer);
@@ -214,7 +216,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
}
if (p_surface.index_count) {
- bool is_index_16 = p_surface.vertex_count <= 65536;
+ bool is_index_16 = p_surface.vertex_count <= 65536 && p_surface.vertex_count > 0;
glGenBuffers(1, &s->index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, p_surface.index_data.size(), p_surface.index_data.ptr(), GL_STATIC_DRAW);
@@ -238,6 +240,8 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
}
}
+ ERR_FAIL_COND_MSG(!p_surface.index_count && !p_surface.vertex_count, "Meshes must contain a vertex array, an index array, or both");
+
s->aabb = p_surface.aabb;
s->bone_aabbs = p_surface.bone_aabbs; //only really useful for returning them.
@@ -255,7 +259,10 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
mesh->bone_aabbs.resize(p_surface.bone_aabbs.size());
}
for (int i = 0; i < p_surface.bone_aabbs.size(); i++) {
- mesh->bone_aabbs.write[i].merge_with(p_surface.bone_aabbs[i]);
+ const AABB &bone = p_surface.bone_aabbs[i];
+ if (!bone.has_no_volume()) {
+ mesh->bone_aabbs.write[i].merge_with(bone);
+ }
}
mesh->aabb.merge_with(p_surface.aabb);
}
@@ -337,7 +344,9 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const {
RS::SurfaceData sd;
sd.format = s.format;
- sd.vertex_data = Utilities::buffer_get_data(GL_ARRAY_BUFFER, s.vertex_buffer, s.vertex_buffer_size);
+ if (s.vertex_buffer != 0) {
+ sd.vertex_data = Utilities::buffer_get_data(GL_ARRAY_BUFFER, s.vertex_buffer, s.vertex_buffer_size);
+ }
if (s.attribute_buffer != 0) {
sd.attribute_data = Utilities::buffer_get_data(GL_ARRAY_BUFFER, s.attribute_buffer, s.attribute_buffer_size);
@@ -595,17 +604,16 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
} break;
case RS::ARRAY_NORMAL: {
attribs[i].offset = vertex_stride;
- // Will need to change to accommodate octahedral compression
- attribs[i].size = 4;
- attribs[i].type = GL_UNSIGNED_INT_2_10_10_10_REV;
- vertex_stride += sizeof(float);
+ attribs[i].size = 2;
+ attribs[i].type = GL_UNSIGNED_SHORT;
+ vertex_stride += sizeof(uint16_t) * 2;
attribs[i].normalized = GL_TRUE;
} break;
case RS::ARRAY_TANGENT: {
attribs[i].offset = vertex_stride;
- attribs[i].size = 4;
- attribs[i].type = GL_UNSIGNED_INT_2_10_10_10_REV;
- vertex_stride += sizeof(float);
+ attribs[i].size = 2;
+ attribs[i].type = GL_UNSIGNED_SHORT;
+ vertex_stride += sizeof(uint16_t) * 2;
attribs[i].normalized = GL_TRUE;
} break;
case RS::ARRAY_COLOR: {
@@ -1347,7 +1355,7 @@ void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_b
_multimesh_mark_all_dirty(multimesh, false, true); //update AABB
} else if (multimesh->mesh.is_valid()) {
//if we have a mesh set, we need to re-generate the AABB from the new data
- const float *data = multimesh->data_cache.ptr();
+ const float *data = p_buffer.ptr();
_multimesh_re_create_aabb(multimesh, data, multimesh->instances);
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
diff --git a/drivers/gles3/storage/mesh_storage.h b/drivers/gles3/storage/mesh_storage.h
index 339380b3b0..74f5800795 100644
--- a/drivers/gles3/storage/mesh_storage.h
+++ b/drivers/gles3/storage/mesh_storage.h
@@ -75,7 +75,7 @@ struct Mesh {
// Cache vertex arrays so they can be created
struct Version {
uint32_t input_mask = 0;
- GLuint vertex_array;
+ GLuint vertex_array = 0;
Attrib attribs[RS::ARRAY_MAX];
};
@@ -92,7 +92,7 @@ struct Mesh {
float edge_length = 0.0;
uint32_t index_count = 0;
uint32_t index_buffer_size = 0;
- GLuint index_buffer;
+ GLuint index_buffer = 0;
};
LOD *lods = nullptr;
@@ -175,7 +175,7 @@ struct MultiMesh {
bool *data_cache_dirty_regions = nullptr;
uint32_t data_cache_used_dirty_regions = 0;
- GLuint buffer;
+ GLuint buffer = 0;
bool dirty = false;
MultiMesh *dirty_list = nullptr;
@@ -362,7 +362,7 @@ public:
_FORCE_INLINE_ GLenum mesh_surface_get_index_type(void *p_surface) const {
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
- return s->vertex_count <= 65536 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
+ return (s->vertex_count <= 65536 && s->vertex_count > 0) ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
}
// Use this to cache Vertex Array Objects so they are only generated once
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index c05f516548..543638e8ff 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -115,6 +115,17 @@ TextureStorage::TextureStorage() {
texture_2d_layered_initialize(default_gl_textures[DEFAULT_GL_TEXTURE_CUBEMAP_BLACK], images, RS::TEXTURE_LAYERED_CUBEMAP);
}
+ { // transparent black
+ Ref<Image> image;
+ image.instantiate();
+ image->create(4, 4, true, Image::FORMAT_RGBA8);
+ image->fill(Color(0, 0, 0, 0));
+ image->generate_mipmaps();
+
+ default_gl_textures[DEFAULT_GL_TEXTURE_TRANSPARENT] = texture_allocate();
+ texture_2d_initialize(default_gl_textures[DEFAULT_GL_TEXTURE_TRANSPARENT], image);
+ }
+
{
Ref<Image> image;
image.instantiate();
diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h
index 77ec1da6f5..71f713bc9f 100644
--- a/drivers/gles3/storage/texture_storage.h
+++ b/drivers/gles3/storage/texture_storage.h
@@ -103,6 +103,7 @@ namespace GLES3 {
enum DefaultGLTexture {
DEFAULT_GL_TEXTURE_WHITE,
DEFAULT_GL_TEXTURE_BLACK,
+ DEFAULT_GL_TEXTURE_TRANSPARENT,
DEFAULT_GL_TEXTURE_NORMAL,
DEFAULT_GL_TEXTURE_ANISO,
DEFAULT_GL_TEXTURE_DEPTH,
diff --git a/drivers/png/SCsub b/drivers/png/SCsub
index 39d296e7cf..fe8c8fa8cc 100644
--- a/drivers/png/SCsub
+++ b/drivers/png/SCsub
@@ -30,14 +30,14 @@ if env["builtin_libpng"]:
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
env_png.Prepend(CPPPATH=[thirdparty_dir])
- # Needed for drivers includes and in platform/javascript
+ # Needed for drivers includes and in platform/web.
env.Prepend(CPPPATH=[thirdparty_dir])
# Currently .ASM filter_neon.S does not compile on NT.
import os
# Enable ARM NEON instructions on 32-bit Android to compile more optimized code.
- use_neon = "android_arch" in env and env["android_arch"] == "armv7" and os.name != "nt"
+ use_neon = env["platform"] == "android" and env["arch"] == "arm32" and os.name != "nt"
if use_neon:
env_png.Append(CPPDEFINES=[("PNG_ARM_NEON_OPT", 2)])
else:
diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp
index 917bfec574..8d2f8a7ed6 100644
--- a/drivers/png/image_loader_png.cpp
+++ b/drivers/png/image_loader_png.cpp
@@ -36,7 +36,7 @@
#include <string.h>
-Error ImageLoaderPNG::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) {
+Error ImageLoaderPNG::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) {
const uint64_t buffer_size = f->get_length();
Vector<uint8_t> file_buffer;
Error err = file_buffer.resize(buffer_size);
@@ -48,7 +48,7 @@ Error ImageLoaderPNG::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_f
f->get_buffer(writer, buffer_size);
}
const uint8_t *reader = file_buffer.ptr();
- return PNGDriverCommon::png_to_image(reader, buffer_size, p_force_linear, p_image);
+ return PNGDriverCommon::png_to_image(reader, buffer_size, p_flags & FLAG_FORCE_LINEAR, p_image);
}
void ImageLoaderPNG::get_recognized_extensions(List<String> *p_extensions) const {
diff --git a/drivers/png/image_loader_png.h b/drivers/png/image_loader_png.h
index 9bcfb720d3..91c3c8925f 100644
--- a/drivers/png/image_loader_png.h
+++ b/drivers/png/image_loader_png.h
@@ -40,7 +40,7 @@ private:
static Ref<Image> load_mem_png(const uint8_t *p_png, int p_size);
public:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderPNG();
};
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
index a6c35b6837..b25cf1d5b4 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
@@ -178,7 +178,7 @@ Error AudioDriverPulseAudio::detect_channels(bool capture) {
Error AudioDriverPulseAudio::init_device() {
// If there is a specified device check that it is really present
if (device_name != "Default") {
- Array list = get_device_list();
+ PackedStringArray list = get_device_list();
if (list.find(device_name) == -1) {
device_name = "Default";
new_device = "Default";
@@ -285,9 +285,8 @@ Error AudioDriverPulseAudio::init() {
return ERR_CANT_OPEN;
}
- active = false;
- thread_exited = false;
- exit_thread = false;
+ active.clear();
+ exit_thread.clear();
mix_rate = GLOBAL_GET("audio/driver/mix_rate");
@@ -384,7 +383,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
size_t avail_bytes = 0;
uint64_t default_device_msec = OS::get_singleton()->get_ticks_msec();
- while (!ad->exit_thread) {
+ while (!ad->exit_thread.is_set()) {
size_t read_bytes = 0;
size_t written_bytes = 0;
@@ -392,7 +391,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
ad->lock();
ad->start_counting_ticks();
- if (!ad->active) {
+ if (!ad->active.is_set()) {
ad->samples_out.fill(0);
} else {
ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw());
@@ -462,8 +461,8 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
err = ad->init_device();
if (err != OK) {
- ad->active = false;
- ad->exit_thread = true;
+ ad->active.clear();
+ ad->exit_thread.set();
break;
}
}
@@ -501,8 +500,8 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
Error err = ad->init_device();
if (err != OK) {
ERR_PRINT("PulseAudio: init_device error");
- ad->active = false;
- ad->exit_thread = true;
+ ad->active.clear();
+ ad->exit_thread.set();
break;
}
@@ -555,8 +554,8 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
err = ad->capture_init_device();
if (err != OK) {
- ad->active = false;
- ad->exit_thread = true;
+ ad->active.clear();
+ ad->exit_thread.set();
break;
}
}
@@ -571,12 +570,10 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
OS::get_singleton()->delay_usec(1000);
}
}
-
- ad->thread_exited = true;
}
void AudioDriverPulseAudio::start() {
- active = true;
+ active.set();
}
int AudioDriverPulseAudio::get_mix_rate() const {
@@ -599,7 +596,7 @@ void AudioDriverPulseAudio::pa_sinklist_cb(pa_context *c, const pa_sink_info *l,
ad->pa_status++;
}
-Array AudioDriverPulseAudio::get_device_list() {
+PackedStringArray AudioDriverPulseAudio::get_device_list() {
pa_devices.clear();
pa_devices.push_back("Default");
@@ -661,7 +658,7 @@ void AudioDriverPulseAudio::finish() {
return;
}
- exit_thread = true;
+ exit_thread.set();
thread.wait_to_finish();
finish_device();
@@ -681,7 +678,7 @@ void AudioDriverPulseAudio::finish() {
Error AudioDriverPulseAudio::capture_init_device() {
// If there is a specified device check that it is really present
if (capture_device_name != "Default") {
- Array list = capture_get_device_list();
+ PackedStringArray list = capture_get_device_list();
if (list.find(capture_device_name) == -1) {
capture_device_name = "Default";
capture_new_device = "Default";
@@ -785,7 +782,7 @@ void AudioDriverPulseAudio::pa_sourcelist_cb(pa_context *c, const pa_source_info
ad->pa_status++;
}
-Array AudioDriverPulseAudio::capture_get_device_list() {
+PackedStringArray AudioDriverPulseAudio::capture_get_device_list() {
pa_rec_devices.clear();
pa_rec_devices.push_back("Default");
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h
index af96489972..85e328b49f 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.h
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.h
@@ -35,6 +35,7 @@
#include "core/os/mutex.h"
#include "core/os/thread.h"
+#include "core/templates/safe_refcount.h"
#include "servers/audio_server.h"
#include "pulse-so_wrap.h"
@@ -67,12 +68,11 @@ class AudioDriverPulseAudio : public AudioDriver {
int channels = 0;
int pa_ready = 0;
int pa_status = 0;
- Array pa_devices;
- Array pa_rec_devices;
+ PackedStringArray pa_devices;
+ PackedStringArray pa_rec_devices;
- bool active = false;
- bool thread_exited = false;
- mutable bool exit_thread = false;
+ SafeFlag active;
+ SafeFlag exit_thread;
float latency = 0;
@@ -103,11 +103,11 @@ public:
virtual int get_mix_rate() const;
virtual SpeakerMode get_speaker_mode() const;
- virtual Array get_device_list();
+ virtual PackedStringArray get_device_list();
virtual String get_device();
virtual void set_device(String device);
- virtual Array capture_get_device_list();
+ virtual PackedStringArray capture_get_device_list();
virtual void capture_set_device(const String &p_name);
virtual String capture_get_device();
diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp
index b8b72b8d30..55ea952696 100644
--- a/drivers/unix/dir_access_unix.cpp
+++ b/drivers/unix/dir_access_unix.cpp
@@ -69,7 +69,7 @@ bool DirAccessUnix::file_exists(String p_file) {
GLOBAL_LOCK_FUNCTION
if (p_file.is_relative_path()) {
- p_file = current_dir.plus_file(p_file);
+ p_file = current_dir.path_join(p_file);
}
p_file = fix_path(p_file);
@@ -88,7 +88,7 @@ bool DirAccessUnix::dir_exists(String p_dir) {
GLOBAL_LOCK_FUNCTION
if (p_dir.is_relative_path()) {
- p_dir = get_current_dir().plus_file(p_dir);
+ p_dir = get_current_dir().path_join(p_dir);
}
p_dir = fix_path(p_dir);
@@ -103,7 +103,7 @@ bool DirAccessUnix::is_readable(String p_dir) {
GLOBAL_LOCK_FUNCTION
if (p_dir.is_relative_path()) {
- p_dir = get_current_dir().plus_file(p_dir);
+ p_dir = get_current_dir().path_join(p_dir);
}
p_dir = fix_path(p_dir);
@@ -114,7 +114,7 @@ bool DirAccessUnix::is_writable(String p_dir) {
GLOBAL_LOCK_FUNCTION
if (p_dir.is_relative_path()) {
- p_dir = get_current_dir().plus_file(p_dir);
+ p_dir = get_current_dir().path_join(p_dir);
}
p_dir = fix_path(p_dir);
@@ -123,7 +123,7 @@ bool DirAccessUnix::is_writable(String p_dir) {
uint64_t DirAccessUnix::get_modified_time(String p_file) {
if (p_file.is_relative_path()) {
- p_file = current_dir.plus_file(p_file);
+ p_file = current_dir.path_join(p_file);
}
p_file = fix_path(p_file);
@@ -159,7 +159,7 @@ String DirAccessUnix::get_next() {
// known if it points to a directory. stat() will resolve the link
// for us.
if (entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK) {
- String f = current_dir.plus_file(fname);
+ String f = current_dir.path_join(fname);
struct stat flags;
if (stat(f.utf8().get_data(), &flags) == 0) {
@@ -315,7 +315,7 @@ Error DirAccessUnix::make_dir(String p_dir) {
GLOBAL_LOCK_FUNCTION
if (p_dir.is_relative_path()) {
- p_dir = get_current_dir().plus_file(p_dir);
+ p_dir = get_current_dir().path_join(p_dir);
}
p_dir = fix_path(p_dir);
@@ -350,7 +350,7 @@ Error DirAccessUnix::change_dir(String p_dir) {
// try_dir is the directory we are trying to change into
String try_dir = "";
if (p_dir.is_relative_path()) {
- String next_dir = current_dir.plus_file(p_dir);
+ String next_dir = current_dir.path_join(p_dir);
next_dir = next_dir.simplify_path();
try_dir = next_dir;
} else {
@@ -394,13 +394,13 @@ String DirAccessUnix::get_current_dir(bool p_include_drive) const {
Error DirAccessUnix::rename(String p_path, String p_new_path) {
if (p_path.is_relative_path()) {
- p_path = get_current_dir().plus_file(p_path);
+ p_path = get_current_dir().path_join(p_path);
}
p_path = fix_path(p_path);
if (p_new_path.is_relative_path()) {
- p_new_path = get_current_dir().plus_file(p_new_path);
+ p_new_path = get_current_dir().path_join(p_new_path);
}
p_new_path = fix_path(p_new_path);
@@ -410,7 +410,7 @@ Error DirAccessUnix::rename(String p_path, String p_new_path) {
Error DirAccessUnix::remove(String p_path) {
if (p_path.is_relative_path()) {
- p_path = get_current_dir().plus_file(p_path);
+ p_path = get_current_dir().path_join(p_path);
}
p_path = fix_path(p_path);
@@ -429,7 +429,7 @@ Error DirAccessUnix::remove(String p_path) {
bool DirAccessUnix::is_link(String p_file) {
if (p_file.is_relative_path()) {
- p_file = get_current_dir().plus_file(p_file);
+ p_file = get_current_dir().path_join(p_file);
}
p_file = fix_path(p_file);
@@ -444,7 +444,7 @@ bool DirAccessUnix::is_link(String p_file) {
String DirAccessUnix::read_link(String p_file) {
if (p_file.is_relative_path()) {
- p_file = get_current_dir().plus_file(p_file);
+ p_file = get_current_dir().path_join(p_file);
}
p_file = fix_path(p_file);
@@ -461,7 +461,7 @@ String DirAccessUnix::read_link(String p_file) {
Error DirAccessUnix::create_link(String p_source, String p_target) {
if (p_target.is_relative_path()) {
- p_target = get_current_dir().plus_file(p_target);
+ p_target = get_current_dir().path_join(p_target);
}
p_source = fix_path(p_source);
diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h
index 18f435f942..f5dca7c282 100644
--- a/drivers/unix/dir_access_unix.h
+++ b/drivers/unix/dir_access_unix.h
@@ -52,39 +52,39 @@ protected:
virtual bool is_hidden(const String &p_name);
public:
- virtual Error list_dir_begin(); ///< This starts dir listing
- virtual String get_next();
- virtual bool current_is_dir() const;
- virtual bool current_is_hidden() const;
+ virtual Error list_dir_begin() override; ///< This starts dir listing
+ virtual String get_next() override;
+ virtual bool current_is_dir() const override;
+ virtual bool current_is_hidden() const override;
- virtual void list_dir_end(); ///<
+ virtual void list_dir_end() override; ///<
- virtual int get_drive_count();
- virtual String get_drive(int p_drive);
- virtual int get_current_drive();
- virtual bool drives_are_shortcuts();
+ virtual int get_drive_count() override;
+ virtual String get_drive(int p_drive) override;
+ virtual int get_current_drive() override;
+ virtual bool drives_are_shortcuts() override;
- virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success
- virtual String get_current_dir(bool p_include_drive = true) const; ///< return current dir location
- virtual Error make_dir(String p_dir);
+ virtual Error change_dir(String p_dir) override; ///< can be relative or absolute, return false on success
+ virtual String get_current_dir(bool p_include_drive = true) const override; ///< return current dir location
+ virtual Error make_dir(String p_dir) override;
- virtual bool file_exists(String p_file);
- virtual bool dir_exists(String p_dir);
- virtual bool is_readable(String p_dir);
- virtual bool is_writable(String p_dir);
+ virtual bool file_exists(String p_file) override;
+ virtual bool dir_exists(String p_dir) override;
+ virtual bool is_readable(String p_dir) override;
+ virtual bool is_writable(String p_dir) override;
virtual uint64_t get_modified_time(String p_file);
- virtual Error rename(String p_path, String p_new_path);
- virtual Error remove(String p_path);
+ virtual Error rename(String p_path, String p_new_path) override;
+ virtual Error remove(String p_path) override;
- virtual bool is_link(String p_file);
- virtual String read_link(String p_file);
- virtual Error create_link(String p_source, String p_target);
+ virtual bool is_link(String p_file) override;
+ virtual String read_link(String p_file) override;
+ virtual Error create_link(String p_source, String p_target) override;
- virtual uint64_t get_space_left();
+ virtual uint64_t get_space_left() override;
- virtual String get_filesystem_type() const;
+ virtual String get_filesystem_type() const override;
DirAccessUnix();
~DirAccessUnix();
diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h
index d61fc08f57..297c34e454 100644
--- a/drivers/unix/file_access_unix.h
+++ b/drivers/unix/file_access_unix.h
@@ -54,33 +54,33 @@ class FileAccessUnix : public FileAccess {
public:
static CloseNotificationFunc close_notification_func;
- virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual bool is_open() const; ///< true when file is open
+ virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual bool is_open() const override; ///< true when file is open
- virtual String get_path() const; /// returns the path for the current open file
- virtual String get_path_absolute() const; /// returns the absolute path for the current open file
+ virtual String get_path() const override; /// returns the path for the current open file
+ virtual String get_path_absolute() const override; /// returns the absolute path for the current open file
- virtual void seek(uint64_t p_position); ///< seek to a given position
- virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual uint64_t get_position() const; ///< get position in the file
- virtual uint64_t get_length() const; ///< get size of the file
+ virtual void seek(uint64_t p_position) override; ///< seek to a given position
+ virtual void seek_end(int64_t p_position = 0) override; ///< seek from the end of file
+ virtual uint64_t get_position() const override; ///< get position in the file
+ virtual uint64_t get_length() const override; ///< get size of the file
- virtual bool eof_reached() const; ///< reading passed EOF
+ virtual bool eof_reached() const override; ///< reading passed EOF
- virtual uint8_t get_8() const; ///< get a byte
- virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
+ virtual uint8_t get_8() const override; ///< get a byte
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
- virtual Error get_error() const; ///< get last error
+ virtual Error get_error() const override; ///< get last error
- virtual void flush();
- virtual void store_8(uint8_t p_dest); ///< store a byte
- virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
+ virtual void flush() override;
+ virtual void store_8(uint8_t p_dest) override; ///< store a byte
+ virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
- virtual bool file_exists(const String &p_path); ///< return true if a file exists
+ virtual bool file_exists(const String &p_path) override; ///< return true if a file exists
- virtual uint64_t _get_modified_time(const String &p_file);
- virtual uint32_t _get_unix_permissions(const String &p_file);
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions);
+ virtual uint64_t _get_modified_time(const String &p_file) override;
+ virtual uint32_t _get_unix_permissions(const String &p_file) override;
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override;
FileAccessUnix() {}
virtual ~FileAccessUnix();
diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp
index 2deeb79957..0dc2efedc1 100644
--- a/drivers/unix/ip_unix.cpp
+++ b/drivers/unix/ip_unix.cpp
@@ -95,12 +95,12 @@ void IPUnix::_resolve_hostname(List<IPAddress> &r_addresses, const String &p_hos
int s = getaddrinfo(p_hostname.utf8().get_data(), nullptr, &hints, &result);
if (s != 0) {
- ERR_PRINT("getaddrinfo failed! Cannot resolve hostname.");
+ print_verbose("getaddrinfo failed! Cannot resolve hostname.");
return;
}
if (result == nullptr || result->ai_addr == nullptr) {
- ERR_PRINT("Invalid response from getaddrinfo");
+ print_verbose("Invalid response from getaddrinfo");
if (result) {
freeaddrinfo(result);
}
diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp
index f172f31b24..86adf33d62 100644
--- a/drivers/unix/net_socket_posix.cpp
+++ b/drivers/unix/net_socket_posix.cpp
@@ -50,7 +50,7 @@
#include <netinet/in.h>
#include <sys/socket.h>
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
#include <arpa/inet.h>
#endif
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index 5bf14056ab..384f46c8df 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -92,7 +92,7 @@ static void _setup_clock() {
_clock_start = mach_absolute_time() * _clock_scale;
}
#else
-#if defined(CLOCK_MONOTONIC_RAW) && !defined(JAVASCRIPT_ENABLED) // This is a better clock on Linux.
+#if defined(CLOCK_MONOTONIC_RAW) && !defined(WEB_ENABLED) // This is a better clock on Linux.
#define GODOT_CLOCK CLOCK_MONOTONIC_RAW
#else
#define GODOT_CLOCK CLOCK_MONOTONIC
@@ -292,7 +292,7 @@ uint64_t OS_Unix::get_ticks_usec() const {
Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) {
#ifdef __EMSCRIPTEN__
// Don't compile this code at all to avoid undefined references.
- // Actual virtual call goes to OS_JavaScript.
+ // Actual virtual call goes to OS_Web.
ERR_FAIL_V(ERR_BUG);
#else
if (r_pipe) {
@@ -366,7 +366,7 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, St
Error OS_Unix::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) {
#ifdef __EMSCRIPTEN__
// Don't compile this code at all to avoid undefined references.
- // Actual virtual call goes to OS_JavaScript.
+ // Actual virtual call goes to OS_Web.
ERR_FAIL_V(ERR_BUG);
#else
pid_t pid = fork();
@@ -454,12 +454,12 @@ Error OS_Unix::open_dynamic_library(const String p_path, void *&p_library_handle
if (!FileAccess::exists(path)) {
// This code exists so GDExtension can load .so files from within the executable path.
- path = get_executable_path().get_base_dir().plus_file(p_path.get_file());
+ path = get_executable_path().get_base_dir().path_join(p_path.get_file());
}
if (!FileAccess::exists(path)) {
// This code exists so GDExtension can load .so files from a standard unix location.
- path = get_executable_path().get_base_dir().plus_file("../lib").plus_file(p_path.get_file());
+ path = get_executable_path().get_base_dir().path_join("../lib").path_join(p_path.get_file());
}
p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
@@ -526,13 +526,13 @@ String OS_Unix::get_user_data_dir() const {
if (custom_dir.is_empty()) {
custom_dir = appname;
}
- return get_data_path().plus_file(custom_dir);
+ return get_data_path().path_join(custom_dir);
} else {
- return get_data_path().plus_file(get_godot_dir_name()).plus_file("app_userdata").plus_file(appname);
+ return get_data_path().path_join(get_godot_dir_name()).path_join("app_userdata").path_join(appname);
}
}
- return get_data_path().plus_file(get_godot_dir_name()).plus_file("app_userdata").plus_file("[unnamed project]");
+ return get_data_path().path_join(get_godot_dir_name()).path_join("app_userdata").path_join("[unnamed project]");
}
String OS_Unix::get_executable_path() const {
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index 0979ae9e16..f2d78636d7 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -46,7 +46,7 @@
static const uint32_t SMALL_ALLOCATION_MAX_SIZE = 4096;
-// Get the Vulkan object information and possible stage access types (bitwise OR'd with incoming values)
+// Get the Vulkan object information and possible stage access types (bitwise OR'd with incoming values).
RenderingDeviceVulkan::Buffer *RenderingDeviceVulkan::_get_buffer_from_owner(RID p_buffer, VkPipelineStageFlags &r_stage_mask, VkAccessFlags &r_access_mask, uint32_t p_post_barrier) {
Buffer *buffer = nullptr;
if (vertex_buffer_owner.owns(p_buffer)) {
@@ -108,8 +108,8 @@ RenderingDeviceVulkan::Buffer *RenderingDeviceVulkan::_get_buffer_from_owner(RID
}
static void update_external_dependency_for_store(VkSubpassDependency2KHR &dependency, bool is_sampled, bool is_storage, bool is_depth) {
- // Transitioning from write to read, protect the shaders that may use this next
- // Allow for copies/image layout transitions
+ // Transitioning from write to read, protect the shaders that may use this next.
+ // Allow for copies/image layout transitions.
dependency.dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT;
dependency.dstAccessMask |= VK_ACCESS_TRANSFER_READ_BIT;
@@ -125,7 +125,7 @@ static void update_external_dependency_for_store(VkSubpassDependency2KHR &depend
}
if (is_depth) {
- // Depth resources have additional stages that may be interested in them
+ // Depth resources have additional stages that may be interested in them.
dependency.dstStageMask |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
dependency.dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
}
@@ -146,7 +146,7 @@ void RenderingDeviceVulkan::_add_dependency(RID p_id, RID p_depends_on) {
}
void RenderingDeviceVulkan::_free_dependencies(RID p_id) {
- //direct dependencies must be freed
+ // Direct dependencies must be freed.
HashMap<RID, HashSet<RID>>::Iterator E = dependency_map.find(p_id);
if (E) {
@@ -156,7 +156,7 @@ void RenderingDeviceVulkan::_free_dependencies(RID p_id) {
dependency_map.remove(E);
}
- //reverse dependencies must be unreferenced
+ // Reverse dependencies must be unreferenced.
E = reverse_dependency_map.find(p_id);
if (E) {
@@ -860,7 +860,7 @@ uint32_t RenderingDeviceVulkan::get_image_format_pixel_size(DataFormat p_format)
case DATA_FORMAT_D24_UNORM_S8_UINT:
return 4;
case DATA_FORMAT_D32_SFLOAT_S8_UINT:
- return 5; //?
+ return 5; // ?
case DATA_FORMAT_BC1_RGB_UNORM_BLOCK:
case DATA_FORMAT_BC1_RGB_SRGB_BLOCK:
case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK:
@@ -995,7 +995,7 @@ void RenderingDeviceVulkan::get_compressed_image_format_block_dimensions(DataFor
case DATA_FORMAT_EAC_R11_SNORM_BLOCK:
case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK:
case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK:
- case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: //again, not sure about astc
+ case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: // Again, not sure about astc.
case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK:
case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK:
case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK:
@@ -1073,7 +1073,7 @@ uint32_t RenderingDeviceVulkan::get_compressed_image_format_block_byte_size(Data
case DATA_FORMAT_EAC_R11G11_UNORM_BLOCK:
case DATA_FORMAT_EAC_R11G11_SNORM_BLOCK:
return 16;
- case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: //again, not sure about astc
+ case DATA_FORMAT_ASTC_4x4_UNORM_BLOCK: // Again, not sure about astc.
case DATA_FORMAT_ASTC_4x4_SRGB_BLOCK:
case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK:
case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK:
@@ -1101,7 +1101,7 @@ uint32_t RenderingDeviceVulkan::get_compressed_image_format_block_byte_size(Data
case DATA_FORMAT_ASTC_12x10_SRGB_BLOCK:
case DATA_FORMAT_ASTC_12x12_UNORM_BLOCK:
case DATA_FORMAT_ASTC_12x12_SRGB_BLOCK:
- return 8; //wrong
+ return 8; // Wrong.
default: {
}
}
@@ -1110,7 +1110,7 @@ uint32_t RenderingDeviceVulkan::get_compressed_image_format_block_byte_size(Data
uint32_t RenderingDeviceVulkan::get_compressed_image_format_pixel_rshift(DataFormat p_format) {
switch (p_format) {
- case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: //these formats are half byte size, so rshift is 1
+ case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: // These formats are half byte size, so rshift is 1.
case DATA_FORMAT_BC1_RGB_SRGB_BLOCK:
case DATA_FORMAT_BC1_RGBA_UNORM_BLOCK:
case DATA_FORMAT_BC1_RGBA_SRGB_BLOCK:
@@ -1184,7 +1184,7 @@ uint32_t RenderingDeviceVulkan::get_image_format_required_size(DataFormat p_form
}
uint32_t RenderingDeviceVulkan::get_image_required_mipmaps(uint32_t p_width, uint32_t p_height, uint32_t p_depth) {
- //formats and block size don't really matter here since they can all go down to 1px (even if block is larger)
+ // Formats and block size don't really matter here since they can all go down to 1px (even if block is larger).
uint32_t w = p_width;
uint32_t h = p_height;
uint32_t d = p_depth;
@@ -1402,16 +1402,16 @@ Error RenderingDeviceVulkan::_insert_staging_block() {
}
Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_t p_required_align, uint32_t &r_alloc_offset, uint32_t &r_alloc_size, bool p_can_segment) {
- //determine a block to use
+ // Determine a block to use.
r_alloc_size = p_amount;
while (true) {
r_alloc_offset = 0;
- //see if we can use current block
+ // See if we can use current block.
if (staging_buffer_blocks[staging_buffer_current].frame_used == frames_drawn) {
- //we used this block this frame, let's see if there is still room
+ // We used this block this frame, let's see if there is still room.
uint32_t write_from = staging_buffer_blocks[staging_buffer_current].fill_amount;
@@ -1425,107 +1425,107 @@ Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_
int32_t available_bytes = int32_t(staging_buffer_block_size) - int32_t(write_from);
if ((int32_t)p_amount < available_bytes) {
- //all is good, we should be ok, all will fit
+ // All is good, we should be ok, all will fit.
r_alloc_offset = write_from;
} else if (p_can_segment && available_bytes >= (int32_t)p_required_align) {
- //ok all won't fit but at least we can fit a chunkie
- //all is good, update what needs to be written to
+ // Ok all won't fit but at least we can fit a chunkie.
+ // All is good, update what needs to be written to.
r_alloc_offset = write_from;
r_alloc_size = available_bytes - (available_bytes % p_required_align);
} else {
- //can't fit it into this buffer.
- //will need to try next buffer
+ // Can't fit it into this buffer.
+ // Will need to try next buffer.
staging_buffer_current = (staging_buffer_current + 1) % staging_buffer_blocks.size();
- // before doing anything, though, let's check that we didn't manage to fill all blocks
- // possible in a single frame
+ // Before doing anything, though, let's check that we didn't manage to fill all blocks.
+ // Possible in a single frame.
if (staging_buffer_blocks[staging_buffer_current].frame_used == frames_drawn) {
- //guess we did.. ok, let's see if we can insert a new block..
+ // Guess we did.. ok, let's see if we can insert a new block.
if ((uint64_t)staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) {
- //we can, so we are safe
+ // We can, so we are safe.
Error err = _insert_staging_block();
if (err) {
return err;
}
- //claim for this frame
+ // Claim for this frame.
staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
} else {
// Ok, worst case scenario, all the staging buffers belong to this frame
// and this frame is not even done.
- // If this is the main thread, it means the user is likely loading a lot of resources at once,
- // otherwise, the thread should just be blocked until the next frame (currently unimplemented)
+ // If this is the main thread, it means the user is likely loading a lot of resources at once,.
+ // Otherwise, the thread should just be blocked until the next frame (currently unimplemented).
- if (false) { //separate thread from render
+ if (false) { // Separate thread from render.
//block_until_next_frame()
continue;
} else {
- //flush EVERYTHING including setup commands. IF not immediate, also need to flush the draw commands
+ // Flush EVERYTHING including setup commands. IF not immediate, also need to flush the draw commands.
_flush(true);
- //clear the whole staging buffer
+ // Clear the whole staging buffer.
for (int i = 0; i < staging_buffer_blocks.size(); i++) {
staging_buffer_blocks.write[i].frame_used = 0;
staging_buffer_blocks.write[i].fill_amount = 0;
}
- //claim current
+ // Claim current.
staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
}
}
} else {
- //not from current frame, so continue and try again
+ // Not from current frame, so continue and try again.
continue;
}
}
} else if (staging_buffer_blocks[staging_buffer_current].frame_used <= frames_drawn - frame_count) {
- //this is an old block, which was already processed, let's reuse
+ // This is an old block, which was already processed, let's reuse.
staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
staging_buffer_blocks.write[staging_buffer_current].fill_amount = 0;
} else {
- //this block may still be in use, let's not touch it unless we have to, so.. can we create a new one?
+ // This block may still be in use, let's not touch it unless we have to, so.. can we create a new one?
if ((uint64_t)staging_buffer_blocks.size() * staging_buffer_block_size < staging_buffer_max_size) {
- //we are still allowed to create a new block, so let's do that and insert it for current pos
+ // We are still allowed to create a new block, so let's do that and insert it for current pos.
Error err = _insert_staging_block();
if (err) {
return err;
}
- //claim for this frame
+ // Claim for this frame.
staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
} else {
- // oops, we are out of room and we can't create more.
- // let's flush older frames.
+ // Oops, we are out of room and we can't create more.
+ // Let's flush older frames.
// The logic here is that if a game is loading a lot of data from the main thread, it will need to be stalled anyway.
// If loading from a separate thread, we can block that thread until next frame when more room is made (not currently implemented, though).
if (false) {
- //separate thread from render
+ // Separate thread from render.
//block_until_next_frame()
- continue; //and try again
+ continue; // And try again.
} else {
_flush(false);
for (int i = 0; i < staging_buffer_blocks.size(); i++) {
- //clear all blocks but the ones from this frame
+ // Clear all blocks but the ones from this frame.
int block_idx = (i + staging_buffer_current) % staging_buffer_blocks.size();
if (staging_buffer_blocks[block_idx].frame_used == frames_drawn) {
- break; //ok, we reached something from this frame, abort
+ break; // Ok, we reached something from this frame, abort.
}
staging_buffer_blocks.write[block_idx].frame_used = 0;
staging_buffer_blocks.write[block_idx].fill_amount = 0;
}
- //claim for current frame
+ // Claim for current frame.
staging_buffer_blocks.write[staging_buffer_current].frame_used = frames_drawn;
}
}
}
- //all was good, break
+ // All was good, break.
break;
}
@@ -1535,7 +1535,7 @@ Error RenderingDeviceVulkan::_staging_buffer_allocate(uint32_t p_amount, uint32_
}
Error RenderingDeviceVulkan::_buffer_update(Buffer *p_buffer, size_t p_offset, const uint8_t *p_data, size_t p_data_size, bool p_use_draw_command_buffer, uint32_t p_required_align) {
- //submitting may get chunked for various reasons, so convert this to a task
+ // Submitting may get chunked for various reasons, so convert this to a task.
size_t to_submit = p_data_size;
size_t submit_from = 0;
@@ -1548,7 +1548,7 @@ Error RenderingDeviceVulkan::_buffer_update(Buffer *p_buffer, size_t p_offset, c
return err;
}
- //map staging buffer (It's CPU and coherent)
+ // Map staging buffer (It's CPU and coherent).
void *data_ptr = nullptr;
{
@@ -1556,12 +1556,12 @@ Error RenderingDeviceVulkan::_buffer_update(Buffer *p_buffer, size_t p_offset, c
ERR_FAIL_COND_V_MSG(vkerr, ERR_CANT_CREATE, "vmaMapMemory failed with error " + itos(vkerr) + ".");
}
- //copy to staging buffer
+ // Copy to staging buffer.
memcpy(((uint8_t *)data_ptr) + block_write_offset, p_data + submit_from, block_write_amount);
- //unmap
+ // Unmap.
vmaUnmapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation);
- //insert a command to copy this
+ // Insert a command to copy this.
VkBufferCopy region;
region.srcOffset = block_write_offset;
@@ -1587,13 +1587,13 @@ void RenderingDeviceVulkan::_memory_barrier(VkPipelineStageFlags p_src_stage_mas
mem_barrier.dstAccessMask = p_dst_sccess;
if (p_src_stage_mask == 0 || p_dst_stage_mask == 0) {
- return; //no barrier, since this is invalid
+ return; // No barrier, since this is invalid.
}
vkCmdPipelineBarrier(p_sync_with_draw ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer, p_src_stage_mask, p_dst_stage_mask, 0, 1, &mem_barrier, 0, nullptr, 0, nullptr);
}
void RenderingDeviceVulkan::_full_barrier(bool p_sync_with_draw) {
- //used for debug
+ // Used for debug.
_memory_barrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_ACCESS_INDIRECT_COMMAND_READ_BIT |
VK_ACCESS_INDEX_READ_BIT |
@@ -1662,8 +1662,8 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
#ifndef ANDROID_ENABLED
// vkCreateImage fails with format list on Android (VK_ERROR_OUT_OF_HOST_MEMORY)
- VkImageFormatListCreateInfoKHR format_list_create_info; //keep out of the if, needed for creation
- Vector<VkFormat> allowed_formats; //keep out of the if, needed for creation
+ VkImageFormatListCreateInfoKHR format_list_create_info; // Keep out of the if, needed for creation.
+ Vector<VkFormat> allowed_formats; // Keep out of the if, needed for creation.
#endif
if (p_format.shareable_formats.size()) {
image_create_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
@@ -1736,7 +1736,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
image_create_info.samples = rasterization_sample_count[p_format.samples];
image_create_info.tiling = (p_format.usage_bits & TEXTURE_USAGE_CPU_READ_BIT) ? VK_IMAGE_TILING_LINEAR : VK_IMAGE_TILING_OPTIMAL;
- //usage
+ // Usage.
image_create_info.usage = 0;
if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) {
@@ -1800,7 +1800,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
}
{
- //validate that this image is supported for the intended use
+ // Validate that this image is supported for the intended use.
VkFormatProperties properties;
vkGetPhysicalDeviceFormatProperties(context->get_physical_device(), image_create_info.format, &properties);
VkFormatFeatureFlags flags;
@@ -1841,7 +1841,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
}
}
- //some view validation
+ // Some view validation.
if (p_view.format_override != DATA_FORMAT_MAX) {
ERR_FAIL_INDEX_V(p_view.format_override, DATA_FORMAT_MAX, RID());
@@ -1851,7 +1851,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
ERR_FAIL_INDEX_V(p_view.swizzle_b, TEXTURE_SWIZZLE_MAX, RID());
ERR_FAIL_INDEX_V(p_view.swizzle_a, TEXTURE_SWIZZLE_MAX, RID());
- //allocate memory
+ // Allocate memory.
uint32_t width, height;
uint32_t image_size = get_image_format_required_size(p_format.format, p_format.width, p_format.height, p_format.depth, p_format.mipmaps, &width, &height);
@@ -1888,19 +1888,19 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
texture.samples = p_format.samples;
texture.allowed_shared_formats = p_format.shareable_formats;
- //set base layout based on usage priority
+ // Set base layout based on usage priority.
if (p_format.usage_bits & TEXTURE_USAGE_SAMPLING_BIT) {
- //first priority, readable
+ // First priority, readable.
texture.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
} else if (p_format.usage_bits & TEXTURE_USAGE_STORAGE_BIT) {
- //second priority, storage
+ // Second priority, storage.
texture.layout = VK_IMAGE_LAYOUT_GENERAL;
} else if (p_format.usage_bits & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
- //third priority, color or depth
+ // Third priority, color or depth.
texture.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
@@ -1925,7 +1925,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
texture.bound = false;
- //create view
+ // Create view.
VkImageViewCreateInfo image_view_create_info;
image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
@@ -1982,7 +1982,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
ERR_FAIL_V_MSG(RID(), "vkCreateImageView failed with error " + itos(err) + ".");
}
- //barrier to set layout
+ // Barrier to set layout.
{
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
@@ -2004,6 +2004,9 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T
}
RID id = texture_owner.make_rid(texture);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
if (p_data.size()) {
for (uint32_t i = 0; i < image_create_info.arrayLayers; i++) {
@@ -2019,13 +2022,13 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID
Texture *src_texture = texture_owner.get_or_null(p_with_texture);
ERR_FAIL_COND_V(!src_texture, RID());
- if (src_texture->owner.is_valid()) { //ahh this is a share
+ if (src_texture->owner.is_valid()) { // Ahh this is a share.
p_with_texture = src_texture->owner;
src_texture = texture_owner.get_or_null(src_texture->owner);
- ERR_FAIL_COND_V(!src_texture, RID()); //this is a bug
+ ERR_FAIL_COND_V(!src_texture, RID()); // This is a bug.
}
- //create view
+ // Create view.
Texture texture = *src_texture;
@@ -2086,7 +2089,7 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID
usage_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
usage_info.pNext = nullptr;
if (p_view.format_override != DATA_FORMAT_MAX) {
- //need to validate usage with vulkan
+ // Need to validate usage with vulkan.
usage_info.usage = 0;
@@ -2133,6 +2136,9 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID
texture.owner = p_with_texture;
RID id = texture_owner.make_rid(texture);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
_add_dependency(id, p_with_texture);
return id;
@@ -2145,9 +2151,9 @@ RID RenderingDeviceVulkan::texture_create_from_extension(TextureType p_type, Dat
Texture texture;
texture.image = image;
- // if we leave texture.allocation as a nullptr, would that be enough to detect we don't "own" the image?
- // also leave texture.allocation_info alone
- // we'll set texture.view later on
+ // If we leave texture.allocation as a nullptr, would that be enough to detect we don't "own" the image?
+ // Also leave texture.allocation_info alone.
+ // We'll set texture.view later on.
texture.type = p_type;
texture.format = p_format;
texture.samples = p_samples;
@@ -2155,14 +2161,14 @@ RID RenderingDeviceVulkan::texture_create_from_extension(TextureType p_type, Dat
texture.height = p_height;
texture.depth = p_depth;
texture.layers = p_layers;
- texture.mipmaps = 0; // maybe make this settable too?
+ texture.mipmaps = 0; // Maybe make this settable too?
texture.usage_flags = p_flags;
texture.base_mipmap = 0;
texture.base_layer = 0;
texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_UNORM);
texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_SRGB);
- // Do we need to do something with texture.layout ?
+ // Do we need to do something with texture.layout?
if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
texture.read_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT;
@@ -2176,7 +2182,7 @@ RID RenderingDeviceVulkan::texture_create_from_extension(TextureType p_type, Dat
texture.barrier_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT;
}
- // Create a view for us to use
+ // Create a view for us to use.
VkImageViewCreateInfo image_view_create_info;
image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
@@ -2207,7 +2213,7 @@ RID RenderingDeviceVulkan::texture_create_from_extension(TextureType p_type, Dat
VK_COMPONENT_SWIZZLE_A
};
- // hardcode for now, maybe make this settable from outside..
+ // Hardcode for now, maybe make this settable from outside.
image_view_create_info.components.r = component_swizzles[TEXTURE_SWIZZLE_R];
image_view_create_info.components.g = component_swizzles[TEXTURE_SWIZZLE_G];
image_view_create_info.components.b = component_swizzles[TEXTURE_SWIZZLE_B];
@@ -2230,7 +2236,7 @@ RID RenderingDeviceVulkan::texture_create_from_extension(TextureType p_type, Dat
ERR_FAIL_V_MSG(RID(), "vkCreateImageView failed with error " + itos(err) + ".");
}
- //barrier to set layout
+ // Barrier to set layout.
{
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
@@ -2252,6 +2258,9 @@ RID RenderingDeviceVulkan::texture_create_from_extension(TextureType p_type, Dat
}
RID id = texture_owner.make_rid(texture);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
return id;
}
@@ -2262,10 +2271,10 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p
Texture *src_texture = texture_owner.get_or_null(p_with_texture);
ERR_FAIL_COND_V(!src_texture, RID());
- if (src_texture->owner.is_valid()) { //ahh this is a share
+ if (src_texture->owner.is_valid()) { // Ahh this is a share.
p_with_texture = src_texture->owner;
src_texture = texture_owner.get_or_null(src_texture->owner);
- ERR_FAIL_COND_V(!src_texture, RID()); //this is a bug
+ ERR_FAIL_COND_V(!src_texture, RID()); // This is a bug.
}
ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_CUBEMAP && (src_texture->type != TEXTURE_TYPE_CUBE && src_texture->type != TEXTURE_TYPE_CUBE_ARRAY), RID(),
@@ -2277,7 +2286,7 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p
ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_2D_ARRAY && (src_texture->type != TEXTURE_TYPE_2D_ARRAY), RID(),
"Can only create an array slice from a 2D array mipmap");
- //create view
+ // Create view.
ERR_FAIL_UNSIGNED_INDEX_V(p_mipmap, src_texture->mipmaps, RID());
ERR_FAIL_COND_V(p_mipmap + p_mipmaps > src_texture->mipmaps, RID());
@@ -2377,6 +2386,9 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p
texture.owner = p_with_texture;
RID id = texture_owner.make_rid(texture);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
_add_dependency(id, p_with_texture);
return id;
@@ -2414,7 +2426,7 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co
if (texture->owner != RID()) {
p_texture = texture->owner;
texture = texture_owner.get_or_null(texture->owner);
- ERR_FAIL_COND_V(!texture, ERR_BUG); //this is a bug
+ ERR_FAIL_COND_V(!texture, ERR_BUG); // This is a bug.
}
ERR_FAIL_COND_V_MSG(texture->bound, ERR_CANT_ACQUIRE_RESOURCE,
@@ -2436,7 +2448,7 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co
if (required_align == 1) {
required_align = get_image_format_pixel_size(texture->format);
}
- if ((required_align % 4) != 0) { //alignment rules are really strange
+ if ((required_align % 4) != 0) { // Alignment rules are really strange.
required_align *= 4;
}
@@ -2449,7 +2461,7 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co
VkCommandBuffer command_buffer = p_use_setup_queue ? frames[frame].setup_command_buffer : frames[frame].draw_command_buffer;
- //barrier to transfer
+ // Barrier to transfer.
{
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
@@ -2483,7 +2495,7 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co
const uint8_t *read_ptr_mipmap = r + mipmap_offset;
image_size = image_total - mipmap_offset;
- for (uint32_t z = 0; z < depth; z++) { //for 3D textures, depth may be > 0
+ for (uint32_t z = 0; z < depth; z++) { // For 3D textures, depth may be > 0.
const uint8_t *read_ptr = read_ptr_mipmap + image_size * z / depth;
@@ -2505,7 +2517,7 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co
uint8_t *write_ptr;
- { //map
+ { // Map.
void *data_ptr = nullptr;
VkResult vkerr = vmaMapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation, &data_ptr);
ERR_FAIL_COND_V_MSG(vkerr, ERR_CANT_CREATE, "vmaMapMemory failed with error " + itos(vkerr) + ".");
@@ -2520,11 +2532,11 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co
ERR_FAIL_COND_V(region_h % block_h, ERR_BUG);
if (block_w != 1 || block_h != 1) {
- //compressed image (blocks)
- //must copy a block region
+ // Compressed image (blocks).
+ // Must copy a block region.
uint32_t block_size = get_compressed_image_format_block_byte_size(texture->format);
- //re-create current variables in blocky format
+ // Re-create current variables in blocky format.
uint32_t xb = x / block_w;
uint32_t yb = y / block_h;
uint32_t wb = width / block_w;
@@ -2533,19 +2545,19 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co
uint32_t region_hb = region_h / block_h;
_copy_region(read_ptr, write_ptr, xb, yb, region_wb, region_hb, wb, block_size);
} else {
- //regular image (pixels)
- //must copy a pixel region
+ // Regular image (pixels).
+ // Must copy a pixel region.
_copy_region(read_ptr, write_ptr, x, y, region_w, region_h, width, pixel_size);
}
- { //unmap
+ { // Unmap.
vmaUnmapMemory(allocator, staging_buffer_blocks[staging_buffer_current].allocation);
}
VkBufferImageCopy buffer_image_copy;
buffer_image_copy.bufferOffset = alloc_offset;
- buffer_image_copy.bufferRowLength = 0; //tightly packed
- buffer_image_copy.bufferImageHeight = 0; //tightly packed
+ buffer_image_copy.bufferRowLength = 0; // Tightly packed.
+ buffer_image_copy.bufferImageHeight = 0; // Tightly packed.
buffer_image_copy.imageSubresource.aspectMask = texture->read_aspect_mask;
buffer_image_copy.imageSubresource.mipLevel = mm_i;
@@ -2572,7 +2584,7 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co
logic_height = MAX(1u, logic_height >> 1);
}
- //barrier to restore layout
+ // Barrier to restore layout.
{
uint32_t barrier_flags = 0;
uint32_t access_flags = 0;
@@ -2659,7 +2671,7 @@ Vector<uint8_t> RenderingDeviceVulkan::_texture_get_data_from_image(Texture *tex
const uint8_t *slice_read_ptr = ((uint8_t *)img_mem) + layout.offset + z * layout.depthPitch;
if (block_size > 1) {
- //compressed
+ // Compressed.
uint32_t line_width = (block_size * (width / blockw));
for (uint32_t y = 0; y < height / blockh; y++) {
const uint8_t *rptr = slice_read_ptr + y * layout.rowPitch;
@@ -2669,7 +2681,7 @@ Vector<uint8_t> RenderingDeviceVulkan::_texture_get_data_from_image(Texture *tex
}
} else {
- //uncompressed
+ // Uncompressed.
for (uint32_t y = 0; y < height; y++) {
const uint8_t *rptr = slice_read_ptr + y * layout.rowPitch;
uint8_t *wptr = write_ptr + y * pixel_size * width;
@@ -2705,19 +2717,19 @@ Vector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t
ERR_FAIL_COND_V(p_layer >= layer_count, Vector<uint8_t>());
if (tex->usage_flags & TEXTURE_USAGE_CPU_READ_BIT) {
- //does not need anything fancy, map and read.
+ // Does not need anything fancy, map and read.
return _texture_get_data_from_image(tex, tex->image, tex->allocation, p_layer);
} else {
- //compute total image size
+ // Compute total image size.
uint32_t width, height, depth;
uint32_t buffer_size = get_image_format_required_size(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps, &width, &height, &depth);
- //allocate buffer
- VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; //makes more sense to retrieve
+ // Allocate buffer.
+ VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; // Makes more sense to retrieve.
Buffer tmp_buffer;
_buffer_allocate(&tmp_buffer, buffer_size, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_AUTO_PREFER_HOST, VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT);
- { //Source image barrier
+ { // Source image barrier.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = nullptr;
@@ -2773,7 +2785,7 @@ Vector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t
offset += size;
}
- { //restore src
+ { // Restore src.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = nullptr;
@@ -2888,9 +2900,9 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
VkCommandBuffer command_buffer = frames[frame].draw_command_buffer;
{
- //PRE Copy the image
+ // PRE Copy the image.
- { //Source
+ { // Source.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = nullptr;
@@ -2910,7 +2922,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
- { //Dest
+ { // Dest.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = nullptr;
@@ -2931,7 +2943,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
- //COPY
+ // COPY.
{
VkImageCopy image_copy_region;
@@ -2958,7 +2970,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
vkCmdCopyImage(command_buffer, src_tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_tex->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy_region);
}
- // RESTORE LAYOUT for SRC and DST
+ // RESTORE LAYOUT for SRC and DST.
uint32_t barrier_flags = 0;
uint32_t access_flags = 0;
@@ -2979,7 +2991,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
barrier_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
}
- { //restore src
+ { // Restore src.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = nullptr;
@@ -2999,7 +3011,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, barrier_flags, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
- { //make dst readable
+ { // Make dst readable.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
@@ -3066,9 +3078,9 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID
VkCommandBuffer command_buffer = frames[frame].draw_command_buffer;
{
- //PRE Copy the image
+ // PRE Copy the image.
- { //Source
+ { // Source.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = nullptr;
@@ -3088,7 +3100,7 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
- { //Dest
+ { // Dest.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = nullptr;
@@ -3109,7 +3121,7 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
- //COPY
+ // COPY.
{
VkImageResolve image_copy_region;
@@ -3136,7 +3148,7 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID
vkCmdResolveImage(command_buffer, src_tex->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_tex->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy_region);
}
- // RESTORE LAYOUT for SRC and DST
+ // RESTORE LAYOUT for SRC and DST.
uint32_t barrier_flags = 0;
uint32_t access_flags = 0;
@@ -3157,7 +3169,7 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID
barrier_flags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
}
- { //restore src
+ { // Restore src.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = nullptr;
@@ -3177,7 +3189,7 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID
vkCmdPipelineBarrier(command_buffer, VK_ACCESS_TRANSFER_WRITE_BIT, barrier_flags, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
}
- { //make dst readable
+ { // Make dst readable.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
@@ -3230,13 +3242,13 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color,
VkImageLayout clear_layout = (src_tex->layout == VK_IMAGE_LAYOUT_GENERAL) ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
- // NOTE: Perhaps the valid stages/accesses for a given owner should be a property of the owner. (Here and places like _get_buffer_from_owner)
+ // NOTE: Perhaps the valid stages/accesses for a given owner should be a property of the owner. (Here and places like _get_buffer_from_owner.)
const VkPipelineStageFlags valid_texture_stages = VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
constexpr VkAccessFlags read_access = VK_ACCESS_SHADER_READ_BIT;
constexpr VkAccessFlags read_write_access = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
const VkAccessFlags valid_texture_access = (src_tex->usage_flags & TEXTURE_USAGE_STORAGE_BIT) ? read_write_access : read_access;
- { // Barrier from previous access with optional layout change (see clear_layout logic above)
+ { // Barrier from previous access with optional layout change (see clear_layout logic above).
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = nullptr;
@@ -3272,7 +3284,7 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color,
vkCmdClearColorImage(command_buffer, src_tex->image, clear_layout, &clear_color, 1, &range);
- { // Barrier to post clear accesses (changing back the layout if needed)
+ { // Barrier to post clear accesses (changing back the layout if needed).
uint32_t barrier_flags = 0;
uint32_t access_flags = 0;
@@ -3328,7 +3340,7 @@ bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_f
_THREAD_SAFE_METHOD_
- //validate that this image is supported for the intended use
+ // Validate that this image is supported for the intended use.
VkFormatProperties properties;
vkGetPhysicalDeviceFormatProperties(context->get_physical_device(), vulkan_formats[p_format], &properties);
VkFormatFeatureFlags flags;
@@ -3372,12 +3384,12 @@ bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_f
/********************/
VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, InitialAction p_initial_action, FinalAction p_final_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, uint32_t p_view_count, Vector<TextureSamples> *r_samples) {
- // Set up dependencies from/to external equivalent to the default (implicit) one, and then amend them
+ // Set up dependencies from/to external equivalent to the default (implicit) one, and then amend them.
const VkPipelineStageFlags default_access_mask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
- VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | // From Section 7.1 of Vulkan API Spec v1.1.148
+ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | // From Section 7.1 of Vulkan API Spec v1.1.148.
VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR;
VkPipelineStageFlags reading_stages = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT;
@@ -3420,20 +3432,20 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
bool is_depth = p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
// We can setup a framebuffer where we write to our VRS texture to set it up.
- // We make the assumption here that if our texture is actually used as our VRS attachment,
- // it is used as such for each subpass. This is fairly certain seeing the restrictions on subpasses.
+ // We make the assumption here that if our texture is actually used as our VRS attachment.
+ // It is used as such for each subpass. This is fairly certain seeing the restrictions on subpasses.
bool is_vrs = p_attachments[i].usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT && i == p_passes[0].vrs_attachment;
if (is_vrs) {
- // For VRS we only read, there is no writing to this texture
+ // For VRS we only read, there is no writing to this texture.
description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
description.initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
} else {
- // For each UNDEFINED, assume the prior use was a *read*, as we'd be discarding the output of a write
- // Also, each UNDEFINED will do an immediate layout transition (write), s.t. we must ensure execution synchronization vs.
+ // For each UNDEFINED, assume the prior use was a *read*, as we'd be discarding the output of a write.
+ // Also, each UNDEFINED will do an immediate layout transition (write), s.t. we must ensure execution synchronization vs
// the read. If this is a performance issue, one could track the actual last accessor of each resource, adding only that
- // stage
+ // stage.
switch (is_depth ? p_initial_depth_action : p_initial_action) {
case INITIAL_ACTION_CLEAR_REGION:
@@ -3450,7 +3462,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
} else {
description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
+ description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there.
dependency_from_external.srcStageMask |= reading_stages;
}
} break;
@@ -3467,7 +3479,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
} else {
description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
+ description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there.
dependency_from_external.srcStageMask |= reading_stages;
}
} break;
@@ -3478,13 +3490,13 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
} else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
+ description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there.
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
dependency_from_external.srcStageMask |= reading_stages;
} else {
description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
+ description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there.
dependency_from_external.srcStageMask |= reading_stages;
}
} break;
@@ -3501,12 +3513,12 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
} else {
description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
+ description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there.
dependency_from_external.srcStageMask |= reading_stages;
}
} break;
default: {
- ERR_FAIL_V(VK_NULL_HANDLE); //should never reach here
+ ERR_FAIL_V(VK_NULL_HANDLE); // Should never reach here.
}
}
}
@@ -3517,7 +3529,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
int last_pass = p_passes.size() - 1;
if (is_depth) {
- //likely missing depth resolve?
+ // Likely missing depth resolve?
if (p_passes[last_pass].depth_attachment == i) {
used_last = true;
}
@@ -3527,7 +3539,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
}
} else {
if (p_passes[last_pass].resolve_attachments.size()) {
- //if using resolve attachments, check resolve attachments
+ // If using resolve attachments, check resolve attachments.
for (int j = 0; j < p_passes[last_pass].resolve_attachments.size(); j++) {
if (p_passes[last_pass].resolve_attachments[j] == i) {
used_last = true;
@@ -3567,13 +3579,13 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
}
if (is_vrs) {
- // We don't change our VRS texture during this process
+ // We don't change our VRS texture during this process.
description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
description.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
- // TODO do we need to update our external dependency ?
+ // TODO: Do we need to update our external dependency?
// update_external_dependency_for_store(dependency_to_external, is_sampled, is_storage, false);
} else {
switch (is_depth ? final_depth_action : final_action) {
@@ -3591,8 +3603,8 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
} else {
description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
- // TODO: What does this mean about the next usage (and thus appropriate dependency masks
+ description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there.
+ // TODO: What does this mean about the next usage (and thus appropriate dependency masks.
}
} break;
case FINAL_ACTION_DISCARD: {
@@ -3607,7 +3619,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
} else {
description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- description.finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
+ description.finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there.
}
} break;
case FINAL_ACTION_CONTINUE: {
@@ -3622,12 +3634,12 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
} else {
description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- description.finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there
+ description.finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; // Don't care what is there.
}
} break;
default: {
- ERR_FAIL_V(VK_NULL_HANDLE); //should never reach here
+ ERR_FAIL_V(VK_NULL_HANDLE); // Should never reach here.
}
}
}
@@ -3711,7 +3723,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
reference.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
attachment_last_pass[attachment] = i;
}
- reference.aspectMask = 0; // TODO we need to set this here, possibly VK_IMAGE_ASPECT_COLOR_BIT ??
+ reference.aspectMask = 0; // TODO: We need to set this here, possibly VK_IMAGE_ASPECT_COLOR_BIT?
input_references.push_back(reference);
}
@@ -3737,7 +3749,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
bool multisample = p_attachments[attachment].samples > TEXTURE_SAMPLES_1;
ERR_FAIL_COND_V_MSG(multisample, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachments can't be multisample.");
reference.attachment = attachment_remap[attachment];
- reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
+ reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
attachment_last_pass[attachment] = i;
}
reference.aspectMask = 0;
@@ -3806,7 +3818,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), preserve attachment (" + itos(j) + ").");
if (attachment_last_pass[attachment] != i) {
- //preserve can still be used to keep depth or color from being discarded after use
+ // Preserve can still be used to keep depth or color from being discarded after use.
attachment_last_pass[attachment] = i;
preserve_references.push_back(attachment);
}
@@ -3875,14 +3887,14 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
subpass_dependencies.push_back(dependency);
}
/*
- // NOTE: Big Mallet Approach -- any layout transition causes a full barrier
+ // NOTE: Big Mallet Approach -- any layout transition causes a full barrier.
if (reference.layout != description.initialLayout) {
- // NOTE: this should be smarter based on the texture's knowledge of its previous role
+ // NOTE: This should be smarter based on the texture's knowledge of its previous role.
dependency_from_external.srcStageMask |= VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
dependency_from_external.srcAccessMask |= VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
}
if (reference.layout != description.finalLayout) {
- // NOTE: this should be smarter based on the texture's knowledge of its subsequent role
+ // NOTE: This should be smarter based on the texture's knowledge of its subsequent role.
dependency_to_external.dstStageMask |= VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
dependency_to_external.dstAccessMask |= VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
}
@@ -3923,7 +3935,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
VkRenderPassMultiviewCreateInfo render_pass_multiview_create_info;
if (p_view_count > 1) {
- // this may no longer be needed with the new settings already including this
+ // This may no longer be needed with the new settings already including this.
const VulkanContext::MultiviewCapabilities capabilities = context->get_multiview_capabilities();
@@ -3933,7 +3945,7 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
// Make sure we limit this to the number of views we support.
ERR_FAIL_COND_V_MSG(p_view_count > capabilities.max_view_count, VK_NULL_HANDLE, "Hardware does not support requested number of views for Multiview render pass");
- // Set view masks for each subpass
+ // Set view masks for each subpass.
for (uint32_t i = 0; i < subpasses.size(); i++) {
view_masks.push_back(view_mask);
}
@@ -3971,7 +3983,7 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c
passes.push_back(pass);
return framebuffer_format_create_multipass(p_format, passes, p_view_count);
}
-RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, Vector<FramebufferPass> &p_passes, uint32_t p_view_count) {
+RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, uint32_t p_view_count) {
_THREAD_SAFE_METHOD_
FramebufferFormatKey key;
@@ -3981,14 +3993,14 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c
const RBMap<FramebufferFormatKey, FramebufferFormatID>::Element *E = framebuffer_format_cache.find(key);
if (E) {
- //exists, return
+ // Exists, return.
return E->get();
}
Vector<TextureSamples> samples;
- VkRenderPass render_pass = _render_pass_create(p_attachments, p_passes, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, p_view_count, &samples); //actions don't matter for this use case
+ VkRenderPass render_pass = _render_pass_create(p_attachments, p_passes, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, p_view_count, &samples); // Actions don't matter for this use case.
- if (render_pass == VK_NULL_HANDLE) { //was likely invalid
+ if (render_pass == VK_NULL_HANDLE) { // Was likely invalid.
return INVALID_ID;
}
FramebufferFormatID id = FramebufferFormatID(framebuffer_format_cache.size()) | (FramebufferFormatID(ID_TYPE_FRAMEBUFFER_FORMAT) << FramebufferFormatID(ID_BASE_SHIFT));
@@ -4009,7 +4021,7 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c
const RBMap<FramebufferFormatKey, FramebufferFormatID>::Element *E = framebuffer_format_cache.find(key);
if (E) {
- //exists, return
+ // Exists, return.
return E->get();
}
@@ -4019,7 +4031,7 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c
subpass.flags = 0;
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.viewMask = 0;
- subpass.inputAttachmentCount = 0; //unsupported for now
+ subpass.inputAttachmentCount = 0; // Unsupported for now.
subpass.pInputAttachments = nullptr;
subpass.colorAttachmentCount = 0;
subpass.pColorAttachments = nullptr;
@@ -4046,7 +4058,7 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c
ERR_FAIL_COND_V_MSG(res, 0, "vkCreateRenderPass2KHR for empty fb failed with error " + itos(res) + ".");
- if (render_pass == VK_NULL_HANDLE) { //was likely invalid
+ if (render_pass == VK_NULL_HANDLE) { // Was likely invalid.
return INVALID_ID;
}
@@ -4082,7 +4094,11 @@ RID RenderingDeviceVulkan::framebuffer_create_empty(const Size2i &p_size, Textur
framebuffer.size = p_size;
framebuffer.view_count = 1;
- return framebuffer_owner.make_rid(framebuffer);
+ RID id = framebuffer_owner.make_rid(framebuffer);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ return id;
}
RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check, uint32_t p_view_count) {
@@ -4110,7 +4126,7 @@ RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attac
return framebuffer_create_multipass(p_texture_attachments, passes, p_format_check, p_view_count);
}
-RID RenderingDeviceVulkan::framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) {
+RID RenderingDeviceVulkan::framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, const Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) {
_THREAD_SAFE_METHOD_
Vector<AttachmentFormat> attachments;
@@ -4130,9 +4146,9 @@ RID RenderingDeviceVulkan::framebuffer_create_multipass(const Vector<RID> &p_tex
size.height = texture->height;
size_set = true;
} else if (texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT) {
- // If this is not the first attachement we assume this is used as the VRS attachment
- // in this case this texture will be 1/16th the size of the color attachement.
- // So we skip the size check
+ // If this is not the first attachement we assume this is used as the VRS attachment.
+ // In this case this texture will be 1/16th the size of the color attachement.
+ // So we skip the size check.
} else {
ERR_FAIL_COND_V_MSG((uint32_t)size.width != texture->width || (uint32_t)size.height != texture->height, RID(),
"All textures in a framebuffer should be the same size.");
@@ -4162,6 +4178,9 @@ RID RenderingDeviceVulkan::framebuffer_create_multipass(const Vector<RID> &p_tex
framebuffer.view_count = p_view_count;
RID id = framebuffer_owner.make_rid(framebuffer);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
for (int i = 0; i < p_texture_attachments.size(); i++) {
if (p_texture_attachments[i].is_valid()) {
@@ -4181,6 +4200,22 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_get_form
return framebuffer->format_id;
}
+bool RenderingDeviceVulkan::framebuffer_is_valid(RID p_framebuffer) const {
+ _THREAD_SAFE_METHOD_
+
+ return framebuffer_owner.owns(p_framebuffer);
+}
+
+void RenderingDeviceVulkan::framebuffer_set_invalidation_callback(RID p_framebuffer, InvalidationCallback p_callback, void *p_userdata) {
+ _THREAD_SAFE_METHOD_
+
+ Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);
+ ERR_FAIL_COND(!framebuffer);
+
+ framebuffer->invalidated_callback = p_callback;
+ framebuffer->invalidated_callback_userdata = p_userdata;
+}
+
/*****************/
/**** SAMPLER ****/
/*****************/
@@ -4223,7 +4258,11 @@ RID RenderingDeviceVulkan::sampler_create(const SamplerState &p_state) {
VkResult res = vkCreateSampler(device, &sampler_create_info, nullptr, &sampler);
ERR_FAIL_COND_V_MSG(res, RID(), "vkCreateSampler failed with error " + itos(res) + ".");
- return sampler_owner.make_rid(sampler);
+ RID id = sampler_owner.make_rid(sampler);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ return id;
}
/**********************/
@@ -4252,10 +4291,14 @@ RID RenderingDeviceVulkan::vertex_buffer_create(uint32_t p_size_bytes, const Vec
_buffer_memory_barrier(buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, false);
}
- return vertex_buffer_owner.make_rid(buffer);
+ RID id = vertex_buffer_owner.make_rid(buffer);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ return id;
}
-// Internally reference counted, this ID is warranted to be unique for the same description, but needs to be freed as many times as it was allocated
+// Internally reference counted, this ID is warranted to be unique for the same description, but needs to be freed as many times as it was allocated.
RenderingDevice::VertexFormatID RenderingDeviceVulkan::vertex_format_create(const Vector<VertexAttribute> &p_vertex_formats) {
_THREAD_SAFE_METHOD_
@@ -4267,7 +4310,7 @@ RenderingDevice::VertexFormatID RenderingDeviceVulkan::vertex_format_create(cons
return *idptr;
}
- //does not exist, create one and cache it
+ // Does not exist, create one and cache it.
VertexDescriptionCache vdcache;
vdcache.bindings = memnew_arr(VkVertexInputBindingDescription, p_vertex_formats.size());
vdcache.attributes = memnew_arr(VkVertexInputAttributeDescription, p_vertex_formats.size());
@@ -4323,25 +4366,25 @@ RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFo
vertex_array.vertex_count = p_vertex_count;
vertex_array.description = p_vertex_format;
- vertex_array.max_instances_allowed = 0xFFFFFFFF; //by default as many as you want
+ vertex_array.max_instances_allowed = 0xFFFFFFFF; // By default as many as you want.
for (int i = 0; i < p_src_buffers.size(); i++) {
Buffer *buffer = vertex_buffer_owner.get_or_null(p_src_buffers[i]);
- //validate with buffer
+ // Validate with buffer.
{
const VertexAttribute &atf = vd.vertex_formats[i];
uint32_t element_size = get_format_vertex_size(atf.format);
- ERR_FAIL_COND_V(element_size == 0, RID()); //should never happens since this was prevalidated
+ ERR_FAIL_COND_V(element_size == 0, RID()); // Should never happens since this was prevalidated.
if (atf.frequency == VERTEX_FREQUENCY_VERTEX) {
- //validate size for regular drawing
+ // Validate size for regular drawing.
uint64_t total_size = uint64_t(atf.stride) * (p_vertex_count - 1) + atf.offset + element_size;
ERR_FAIL_COND_V_MSG(total_size > buffer->size, RID(),
"Attachment (" + itos(i) + ") will read past the end of the buffer.");
} else {
- //validate size for instances drawing
+ // Validate size for instances drawing.
uint64_t available = buffer->size - atf.offset;
ERR_FAIL_COND_V_MSG(available < element_size, RID(),
"Attachment (" + itos(i) + ") uses instancing, but it's just too small.");
@@ -4352,7 +4395,7 @@ RID RenderingDeviceVulkan::vertex_array_create(uint32_t p_vertex_count, VertexFo
}
vertex_array.buffers.push_back(buffer->buffer);
- vertex_array.offsets.push_back(0); //offset unused, but passing anyway
+ vertex_array.offsets.push_back(0); // Offset unused, but passing anyway.
}
RID id = vertex_array_owner.make_rid(vertex_array);
@@ -4387,7 +4430,7 @@ RID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBuff
const uint16_t *index16 = (const uint16_t *)r;
for (uint32_t i = 0; i < p_index_count; i++) {
if (p_use_restart_indices && index16[i] == 0xFFFF) {
- continue; //restart index, ignore
+ continue; // Restart index, ignore.
}
index_buffer.max_index = MAX(index16[i], index_buffer.max_index);
}
@@ -4395,7 +4438,7 @@ RID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBuff
const uint32_t *index32 = (const uint32_t *)r;
for (uint32_t i = 0; i < p_index_count; i++) {
if (p_use_restart_indices && index32[i] == 0xFFFFFFFF) {
- continue; //restart index, ignore
+ continue; // Restart index, ignore.
}
index_buffer.max_index = MAX(index32[i], index_buffer.max_index);
}
@@ -4413,7 +4456,11 @@ RID RenderingDeviceVulkan::index_buffer_create(uint32_t p_index_count, IndexBuff
_buffer_update(&index_buffer, 0, r, data_size);
_buffer_memory_barrier(index_buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_INDEX_READ_BIT, false);
}
- return index_buffer_owner.make_rid(index_buffer);
+ RID id = index_buffer_owner.make_rid(index_buffer);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ return id;
}
RID RenderingDeviceVulkan::index_array_create(RID p_index_buffer, uint32_t p_index_offset, uint32_t p_index_count) {
@@ -4490,7 +4537,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
case glslang::EbtSampler: {
//print_line("DEBUG: IsSampler");
if (reflection.getType()->getSampler().dim == glslang::EsdBuffer) {
- //texture buffers
+ // Texture buffers.
if (reflection.getType()->getSampler().isCombined()) {
layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
info.type = UNIFORM_TYPE_SAMPLER_WITH_TEXTURE_BUFFER;
@@ -4590,7 +4637,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
} break;*/
default: {
if (reflection.getType()->getQualifier().hasOffset() || reflection.name.find(".") != std::string::npos) {
- //member of uniform block?
+ // Member of uniform block?
return true;
}
@@ -4627,10 +4674,10 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
uint32_t binding = reflection.getType()->getQualifier().layoutBinding;
if (set < (uint32_t)bindings.size()) {
- //check if this already exists
+ // Check if this already exists.
for (int i = 0; i < bindings[set].size(); i++) {
if (bindings[set][i].binding == binding) {
- //already exists, verify that it's the same type
+ // 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 + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(binding) + " with different uniform type.";
@@ -4638,7 +4685,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
return false;
}
- //also, verify that it's the same size
+ // 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 + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(binding) + " with different uniform size.";
@@ -4646,7 +4693,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
return false;
}
- //just append stage mask and return
+ // Just append stage mask and return.
bindings.write[set].write[i].stageFlags |= shader_stage_masks[p_stage];
uniform_infos.write[set].write[i].stages |= 1 << p_stage;
return true;
@@ -4655,7 +4702,7 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
}
layout_binding.binding = binding;
layout_binding.stageFlags = shader_stage_masks[p_stage];
- layout_binding.pImmutableSamplers = nullptr; //no support for this yet
+ layout_binding.pImmutableSamplers = nullptr; // No support for this yet.
info.stages = 1 << p_stage;
info.binding = binding;
@@ -4674,9 +4721,9 @@ bool RenderingDeviceVulkan::_uniform_add_binding(Vector<Vector<VkDescriptorSetLa
}
#endif
-//version 1: initial
-//version 2: Added shader name
-//version 3: Added writable
+// Version 1: initial.
+// Version 2: Added shader name.
+// Version 3: Added writable.
#define SHADER_BINARY_VERSION 3
@@ -4688,7 +4735,7 @@ struct RenderingDeviceVulkanShaderBinaryDataBinding {
uint32_t type;
uint32_t binding;
uint32_t stages;
- uint32_t length; //size of arrays (in total elements), or ubos (in bytes * total elements)
+ uint32_t length; // Size of arrays (in total elements), or ubos (in bytes * total elements).
uint32_t writable;
};
@@ -4729,7 +4776,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
binary_data.push_constant_size = 0;
binary_data.push_constants_vk_stage = 0;
- Vector<Vector<RenderingDeviceVulkanShaderBinaryDataBinding>> uniform_info; //set bindings
+ Vector<Vector<RenderingDeviceVulkanShaderBinaryDataBinding>> uniform_info; // Set bindings.
Vector<RenderingDeviceVulkanShaderBinarySpecializationConstant> specialization_constants;
uint32_t stages_processed = 0;
@@ -4763,7 +4810,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
uint32_t stage = p_spirv[i].shader_stage;
if (binding_count > 0) {
- //Parse bindings
+ // Parse bindings.
Vector<SpvReflectDescriptorBinding *> bindings;
bindings.resize(binding_count);
@@ -4870,23 +4917,23 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
"On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' uses a set (" + itos(set) + ") index larger than what is supported by the hardware (" + itos(limits.maxBoundDescriptorSets) + ").");
if (set < (uint32_t)uniform_info.size()) {
- //check if this already exists
+ // Check if this already exists.
bool exists = false;
for (int k = 0; k < uniform_info[set].size(); k++) {
if (uniform_info[set][k].binding == (uint32_t)info.binding) {
- //already exists, verify that it's the same type
+ // Already exists, verify that it's the same type.
ERR_FAIL_COND_V_MSG(uniform_info[set][k].type != info.type, Vector<uint8_t>(),
"On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different uniform type.");
- //also, verify that it's the same size
+ // Also, verify that it's the same size.
ERR_FAIL_COND_V_MSG(uniform_info[set][k].length != info.length, Vector<uint8_t>(),
"On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different uniform size.");
- //also, verify that it has the same writability
+ // Also, verify that it has the same writability.
ERR_FAIL_COND_V_MSG(uniform_info[set][k].writable != info.writable, Vector<uint8_t>(),
"On shader stage '" + String(shader_stage_names[stage]) + "', uniform '" + binding.name + "' trying to re-use location for set=" + itos(set) + ", binding=" + itos(info.binding) + " with different writability.");
- //just append stage mask and return
+ // Just append stage mask and return.
uniform_info.write[set].write[k].stages |= 1 << stage;
exists = true;
break;
@@ -4894,7 +4941,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
}
if (exists) {
- continue; //merged
+ continue; // Merged.
}
}
@@ -4909,7 +4956,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
}
{
- //specialization constants
+ // Specialization constants.
uint32_t sc_count = 0;
result = spvReflectEnumerateSpecializationConstants(&module, &sc_count, nullptr);
@@ -4930,7 +4977,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
SpvReflectSpecializationConstant *spc = spec_constants[j];
sconst.constant_id = spc->constant_id;
- sconst.int_value = 0.0; // clear previous value JIC
+ sconst.int_value = 0.0; // Clear previous value JIC.
switch (spc->constant_type) {
case SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL: {
sconst.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
@@ -4980,7 +5027,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
"Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed obtaining input variables.");
for (uint32_t j = 0; j < iv_count; j++) {
- if (input_vars[j] && input_vars[j]->decoration_flags == 0) { //regular input
+ if (input_vars[j] && input_vars[j]->decoration_flags == 0) { // Regular input.
binary_data.vertex_input_mask |= (1 << uint32_t(input_vars[j]->location));
}
}
@@ -5049,7 +5096,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
Vector<Vector<uint8_t>> compressed_stages;
Vector<uint32_t> smolv_size;
- Vector<uint32_t> zstd_size; //if 0, stdno t used
+ Vector<uint32_t> zstd_size; // If 0, zstd not used.
uint32_t stages_binary_size = 0;
@@ -5061,7 +5108,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
ERR_FAIL_V_MSG(Vector<uint8_t>(), "Error compressing shader stage :" + String(shader_stage_names[p_spirv[i].shader_stage]));
} else {
smolv_size.push_back(smolv.size());
- { //zstd
+ { // zstd.
Vector<uint8_t> zstd;
zstd.resize(Compression::get_max_compressed_buffer_size(smolv.size(), Compression::MODE_ZSTD));
int dst_size = Compression::compress(zstd.ptrw(), &smolv[0], smolv.size(), Compression::MODE_ZSTD);
@@ -5074,7 +5121,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
Vector<uint8_t> smv;
smv.resize(smolv.size());
memcpy(smv.ptrw(), &smolv[0], smolv.size());
- zstd_size.push_back(0); //not using zstd
+ zstd_size.push_back(0); // Not using zstd.
compressed_stages.push_back(smv);
}
}
@@ -5094,12 +5141,12 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
binary_data.shader_name_len = shader_name_utf.length();
- uint32_t total_size = sizeof(uint32_t) * 3; //header + version + main datasize;
+ uint32_t total_size = sizeof(uint32_t) * 3; // Header + version + main datasize;.
total_size += sizeof(RenderingDeviceVulkanShaderBinaryData);
total_size += binary_data.shader_name_len;
- if ((binary_data.shader_name_len % 4) != 0) { //alignment rules are really strange
+ if ((binary_data.shader_name_len % 4) != 0) { // Alignment rules are really strange.
total_size += 4 - (binary_data.shader_name_len % 4);
}
@@ -5110,7 +5157,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
total_size += sizeof(RenderingDeviceVulkanShaderBinarySpecializationConstant) * specialization_constants.size();
- total_size += compressed_stages.size() * sizeof(uint32_t) * 3; //sizes
+ total_size += compressed_stages.size() * sizeof(uint32_t) * 3; // Sizes.
total_size += stages_binary_size;
Vector<uint8_t> ret;
@@ -5121,7 +5168,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
binptr[0] = 'G';
binptr[1] = 'V';
binptr[2] = 'B';
- binptr[3] = 'D'; //godot vulkan binary data
+ binptr[3] = 'D'; // Godot vulkan binary data.
offset += 4;
encode_uint32(SHADER_BINARY_VERSION, binptr + offset);
offset += sizeof(uint32_t);
@@ -5132,7 +5179,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve
memcpy(binptr + offset, shader_name_utf.ptr(), binary_data.shader_name_len);
offset += binary_data.shader_name_len;
- if ((binary_data.shader_name_len % 4) != 0) { //alignment rules are really strange
+ if ((binary_data.shader_name_len % 4) != 0) { // Alignment rules are really strange.
offset += 4 - (binary_data.shader_name_len % 4);
}
@@ -5180,7 +5227,7 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
uint32_t binsize = p_shader_binary.size();
uint32_t read_offset = 0;
- //consistency check
+ // Consistency check.
ERR_FAIL_COND_V(binsize < sizeof(uint32_t) * 3 + sizeof(RenderingDeviceVulkanShaderBinaryData), RID());
ERR_FAIL_COND_V(binptr[0] != 'G' || binptr[1] != 'V' || binptr[2] != 'B' || binptr[3] != 'D', RID());
@@ -5210,7 +5257,7 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
if (binary_data.shader_name_len) {
name.parse_utf8((const char *)(binptr + read_offset), binary_data.shader_name_len);
read_offset += binary_data.shader_name_len;
- if ((binary_data.shader_name_len % 4) != 0) { //alignment rules are really strange
+ if ((binary_data.shader_name_len % 4) != 0) { // Alignment rules are really strange.
read_offset += 4 - (binary_data.shader_name_len % 4);
}
}
@@ -5327,7 +5374,7 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
const uint8_t *src_smolv = nullptr;
if (zstd_size > 0) {
- //decompress to smolv
+ // Decompress to smolv.
smolv.resize(smolv_size);
int dec_smolv_size = Compression::decompress(smolv.ptrw(), smolv.size(), binptr + read_offset, zstd_size, Compression::MODE_ZSTD);
ERR_FAIL_COND_V(dec_smolv_size != (int32_t)smolv_size, RID());
@@ -5356,7 +5403,7 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
ERR_FAIL_COND_V(read_offset != binsize, RID());
- //all good, let's create modules
+ // All good, let's create modules.
_THREAD_SAFE_METHOD_
@@ -5412,11 +5459,11 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
shader.pipeline_stages.push_back(shader_stage);
}
- //proceed to create descriptor sets
+ // Proceed to create descriptor sets.
if (success) {
for (int i = 0; i < set_bindings.size(); i++) {
- //empty ones are fine if they were not used according to spec (binding count will be 0)
+ // Empty ones are fine if they were not used according to spec (binding count will be 0).
VkDescriptorSetLayoutCreateInfo layout_create_info;
layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layout_create_info.pNext = nullptr;
@@ -5435,13 +5482,13 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
Shader::Set set;
set.descriptor_set_layout = layout;
set.uniform_info = uniform_info[i];
- //sort and hash
+ // Sort and hash.
set.uniform_info.sort();
- uint32_t format = 0; //no format, default
+ uint32_t format = 0; // No format, default.
if (set.uniform_info.size()) {
- //has data, needs an actual format;
+ // Has data, needs an actual format.
UniformSetFormat usformat;
usformat.uniform_info = set.uniform_info;
RBMap<UniformSetFormat, uint32_t>::Element *E = uniform_set_format_cache.find(usformat);
@@ -5459,7 +5506,7 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
}
if (success) {
- //create pipeline layout
+ // Create pipeline layout.
VkPipelineLayoutCreateInfo pipeline_layout_create_info;
pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipeline_layout_create_info.pNext = nullptr;
@@ -5498,7 +5545,7 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
}
if (!success) {
- //clean up if failed
+ // Clean up if failed.
for (int i = 0; i < shader.pipeline_stages.size(); i++) {
vkDestroyShaderModule(device, shader.pipeline_stages[i].module, nullptr);
}
@@ -5510,7 +5557,11 @@ RID RenderingDeviceVulkan::shader_create_from_bytecode(const Vector<uint8_t> &p_
ERR_FAIL_V_MSG(RID(), error_text);
}
- return shader_owner.make_rid(shader);
+ RID id = shader_owner.make_rid(shader);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ return id;
}
uint32_t RenderingDeviceVulkan::shader_get_vertex_input_attribute_mask(RID p_shader) {
@@ -5543,7 +5594,11 @@ RID RenderingDeviceVulkan::uniform_buffer_create(uint32_t p_size_bytes, const Ve
_buffer_update(&buffer, 0, r, data_size);
_buffer_memory_barrier(buffer.buffer, 0, data_size, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_UNIFORM_READ_BIT, false);
}
- return uniform_buffer_owner.make_rid(buffer);
+ RID id = uniform_buffer_owner.make_rid(buffer);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ return id;
}
RID RenderingDeviceVulkan::storage_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data, uint32_t p_usage) {
@@ -5613,8 +5668,12 @@ RID RenderingDeviceVulkan::texture_buffer_create(uint32_t p_size_elements, DataF
ERR_FAIL_V_MSG(RID(), "Unable to create buffer view, error " + itos(res) + ".");
}
- //allocate the view
- return texture_buffer_owner.make_rid(texture_buffer);
+ // Allocate the view.
+ RID id = texture_buffer_owner.make_rid(texture_buffer);
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ return id;
}
RenderingDeviceVulkan::DescriptorPool *RenderingDeviceVulkan::_descriptor_pool_allocate(const DescriptorPoolKey &p_key) {
@@ -5632,17 +5691,17 @@ RenderingDeviceVulkan::DescriptorPool *RenderingDeviceVulkan::_descriptor_pool_a
}
if (!pool) {
- //create a new one
+ // Create a new one.
pool = memnew(DescriptorPool);
pool->usage = 0;
VkDescriptorPoolCreateInfo descriptor_pool_create_info;
descriptor_pool_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
descriptor_pool_create_info.pNext = nullptr;
- descriptor_pool_create_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; // can't think how somebody may NOT need this flag..
+ descriptor_pool_create_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; // Can't think how somebody may NOT need this flag.
descriptor_pool_create_info.maxSets = max_descriptors_per_pool;
Vector<VkDescriptorPoolSize> sizes;
- //here comes more vulkan API strangeness
+ // Here comes more vulkan API strangeness.
if (p_key.uniform_type[UNIFORM_TYPE_SAMPLER]) {
VkDescriptorPoolSize s;
@@ -5742,7 +5801,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
ERR_FAIL_COND_V_MSG(p_shader_set >= (uint32_t)shader->sets.size() || shader->sets[p_shader_set].uniform_info.size() == 0, RID(),
"Desired set (" + itos(p_shader_set) + ") not used by shader.");
- //see that all sets in shader are satisfied
+ // See that all sets in shader are satisfied.
const Shader::Set &set = shader->sets[p_shader_set];
@@ -5755,11 +5814,11 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
Vector<VkWriteDescriptorSet> writes;
DescriptorPoolKey pool_key;
- //to keep them alive until update call
+ // To keep them alive until update call.
List<Vector<VkDescriptorBufferInfo>> buffer_infos;
List<Vector<VkBufferView>> buffer_views;
List<Vector<VkDescriptorImageInfo>> image_infos;
- //used for verification to make sure a uniform set does not use a framebuffer bound texture
+ // Used for verification to make sure a uniform set does not use a framebuffer bound texture.
LocalVector<UniformSet::AttachableTexture> attachable_textures;
Vector<Texture *> mutable_sampled_textures;
Vector<Texture *> mutable_storage_textures;
@@ -5780,14 +5839,14 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
ERR_FAIL_COND_V_MSG(uniform.uniform_type != set_uniform.type, RID(),
"Mismatch uniform type for binding (" + itos(set_uniform.binding) + "), set (" + itos(p_shader_set) + "). Expected '" + shader_uniform_names[set_uniform.type] + "', supplied: '" + shader_uniform_names[uniform.uniform_type] + "'.");
- VkWriteDescriptorSet write; //common header
+ VkWriteDescriptorSet write; // Common header.
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write.pNext = nullptr;
- write.dstSet = VK_NULL_HANDLE; //will assign afterwards when everything is valid
+ write.dstSet = VK_NULL_HANDLE; // Will assign afterwards when everything is valid.
write.dstBinding = set_uniform.binding;
write.dstArrayElement = 0;
write.descriptorCount = 0;
- write.descriptorType = VK_DESCRIPTOR_TYPE_MAX_ENUM; //Invalid value.
+ write.descriptorType = VK_DESCRIPTOR_TYPE_MAX_ENUM; // Invalid value.
write.pImageInfo = nullptr;
write.pBufferInfo = nullptr;
write.pTexelBufferView = nullptr;
@@ -5860,12 +5919,12 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
}
if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) {
- //can also be used as storage, add to mutable sampled
+ // Can also be used as storage, add to mutable sampled.
mutable_sampled_textures.push_back(texture);
}
if (texture->owner.is_valid()) {
texture = texture_owner.get_or_null(texture->owner);
- ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen
+ ERR_FAIL_COND_V(!texture, RID()); // Bug, should never happen.
}
img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@@ -5913,13 +5972,13 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
}
if (texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT) {
- //can also be used as storage, add to mutable sampled
+ // Can also be used as storage, add to mutable sampled.
mutable_sampled_textures.push_back(texture);
}
if (texture->owner.is_valid()) {
texture = texture_owner.get_or_null(texture->owner);
- ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen
+ ERR_FAIL_COND_V(!texture, RID()); // Bug, should never happen.
}
img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@@ -5961,13 +6020,13 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
img_info.imageView = texture->view;
if (texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT) {
- //can also be used as storage, add to mutable sampled
+ // Can also be used as storage, add to mutable sampled.
mutable_storage_textures.push_back(texture);
}
if (texture->owner.is_valid()) {
texture = texture_owner.get_or_null(texture->owner);
- ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen
+ ERR_FAIL_COND_V(!texture, RID()); // Bug, should never happen.
}
img_info.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
@@ -6057,7 +6116,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
type_size = uniform.get_id_count() / 2;
} break;
case UNIFORM_TYPE_IMAGE_BUFFER: {
- //todo
+ // Todo.
} break;
case UNIFORM_TYPE_UNIFORM_BUFFER: {
@@ -6093,7 +6152,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
}
ERR_FAIL_COND_V_MSG(!buffer, RID(), "Storage buffer supplied (binding: " + itos(uniform.binding) + ") is invalid.");
- //if 0, then it's sized on link time
+ // If 0, then it's sized on link time.
ERR_FAIL_COND_V_MSG(set_uniform.length > 0 && buffer->size != (uint32_t)set_uniform.length, RID(),
"Storage buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ").");
@@ -6132,7 +6191,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
if (texture->owner.is_valid()) {
texture = texture_owner.get_or_null(texture->owner);
- ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen
+ ERR_FAIL_COND_V(!texture, RID()); // Bug, should never happen.
}
img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
@@ -6160,7 +6219,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
pool_key.uniform_type[set_uniform.type] += type_size;
}
- //need a descriptor pool
+ // Need a descriptor pool.
DescriptorPool *pool = _descriptor_pool_allocate(pool_key);
ERR_FAIL_COND_V(!pool, RID());
@@ -6177,7 +6236,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
VkResult res = vkAllocateDescriptorSets(device, &descriptor_set_allocate_info, &descriptor_set);
if (res) {
- _descriptor_pool_free(pool_key, pool); // meh
+ _descriptor_pool_free(pool_key, pool); // Meh.
ERR_FAIL_V_MSG(RID(), "Cannot allocate descriptor sets, error " + itos(res) + ".");
}
@@ -6193,7 +6252,10 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
uniform_set.shader_id = p_shader;
RID id = uniform_set_owner.make_rid(uniform_set);
- //add dependencies
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ // Add dependencies.
_add_dependency(id, p_shader);
for (uint32_t i = 0; i < uniform_count; i++) {
const Uniform &uniform = uniforms[i];
@@ -6203,7 +6265,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
}
}
- //write the contents
+ // Write the contents.
if (writes.size()) {
for (int i = 0; i < writes.size(); i++) {
writes.write[i].dstSet = descriptor_set;
@@ -6218,7 +6280,7 @@ bool RenderingDeviceVulkan::uniform_set_is_valid(RID p_uniform_set) {
return uniform_set_owner.owns(p_uniform_set);
}
-void RenderingDeviceVulkan::uniform_set_set_invalidation_callback(RID p_uniform_set, UniformSetInvalidatedCallback p_callback, void *p_userdata) {
+void RenderingDeviceVulkan::uniform_set_set_invalidation_callback(RID p_uniform_set, InvalidationCallback p_callback, void *p_userdata) {
UniformSet *us = uniform_set_owner.get_or_null(p_uniform_set);
ERR_FAIL_COND(!us);
us->invalidated_callback = p_callback;
@@ -6236,7 +6298,7 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint
VkPipelineStageFlags dst_stage_mask = 0;
VkAccessFlags dst_access = 0;
if (p_post_barrier & BARRIER_MASK_TRANSFER) {
- // Protect subsequent updates...
+ // Protect subsequent updates.
dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
dst_access = VK_ACCESS_TRANSFER_WRITE_BIT;
}
@@ -6248,7 +6310,7 @@ Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint
ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER,
"Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end.");
- // no barrier should be needed here
+ // No barrier should be needed here.
// _buffer_memory_barrier(buffer->buffer, p_offset, p_size, dst_stage_mask, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_access, VK_ACCESS_TRANSFER_WRITE_BIT, true);
Error err = _buffer_update(buffer, p_offset, (uint8_t *)p_data, p_size, p_post_barrier);
@@ -6284,7 +6346,7 @@ Error RenderingDeviceVulkan::buffer_clear(RID p_buffer, uint32_t p_offset, uint3
VkPipelineStageFlags dst_stage_mask = 0;
VkAccessFlags dst_access = 0;
if (p_post_barrier & BARRIER_MASK_TRANSFER) {
- // Protect subsequent updates...
+ // Protect subsequent updates.
dst_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
dst_access = VK_ACCESS_TRANSFER_WRITE_BIT;
}
@@ -6297,7 +6359,7 @@ Error RenderingDeviceVulkan::buffer_clear(RID p_buffer, uint32_t p_offset, uint3
ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER,
"Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end.");
- // should not be needed
+ // Should not be needed.
// _buffer_memory_barrier(buffer->buffer, p_offset, p_size, dst_stage_mask, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_access, VK_ACCESS_TRANSFER_WRITE_BIT, p_post_barrier);
vkCmdFillBuffer(frames[frame].draw_command_buffer, buffer->buffer, p_offset, p_size, 0);
@@ -6318,10 +6380,10 @@ Error RenderingDeviceVulkan::buffer_clear(RID p_buffer, uint32_t p_offset, uint3
Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) {
_THREAD_SAFE_METHOD_
- // It could be this buffer was just created
+ // It could be this buffer was just created.
VkPipelineShaderStageCreateFlags src_stage_mask = VK_PIPELINE_STAGE_TRANSFER_BIT;
VkAccessFlags src_access_mask = VK_ACCESS_TRANSFER_WRITE_BIT;
- // Get the vulkan buffer and the potential stage/access possible
+ // Get the vulkan buffer and the potential stage/access possible.
Buffer *buffer = _get_buffer_from_owner(p_buffer, src_stage_mask, src_access_mask, BARRIER_MASK_ALL);
if (!buffer) {
ERR_FAIL_V_MSG(Vector<uint8_t>(), "Buffer is either invalid or this type of buffer can't be retrieved. Only Index and Vertex buffers allow retrieving.");
@@ -6338,8 +6400,8 @@ Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) {
region.srcOffset = 0;
region.dstOffset = 0;
region.size = buffer->size;
- vkCmdCopyBuffer(command_buffer, buffer->buffer, tmp_buffer.buffer, 1, &region); //dst buffer is in CPU, but I wonder if src buffer needs a barrier for this..
- //flush everything so memory can be safely mapped
+ vkCmdCopyBuffer(command_buffer, buffer->buffer, tmp_buffer.buffer, 1, &region); // Dst buffer is in CPU, but I wonder if src buffer needs a barrier for this.
+ // Flush everything so memory can be safely mapped.
_flush(true);
void *buffer_mem;
@@ -6367,7 +6429,7 @@ Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) {
RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass, const Vector<PipelineSpecializationConstant> &p_specialization_constants) {
_THREAD_SAFE_METHOD_
- //needs a shader
+ // Needs a shader.
Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_COND_V(!shader, RID());
@@ -6375,13 +6437,13 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
"Compute shaders can't be used in render pipelines");
if (p_framebuffer_format == INVALID_ID) {
- //if nothing provided, use an empty one (no attachments)
+ // If nothing provided, use an empty one (no attachments).
p_framebuffer_format = framebuffer_format_create(Vector<AttachmentFormat>());
}
ERR_FAIL_COND_V(!framebuffer_formats.has(p_framebuffer_format), RID());
const FramebufferFormat &fb_format = framebuffer_formats[p_framebuffer_format];
- { //validate shader vs framebuffer
+ { // Validate shader vs framebuffer.
ERR_FAIL_COND_V_MSG(p_for_render_pass >= uint32_t(fb_format.E->key().passes.size()), RID(), "Render pass requested for pipeline creation (" + itos(p_for_render_pass) + ") is out of bounds");
const FramebufferPass &pass = fb_format.E->key().passes[p_for_render_pass];
@@ -6394,17 +6456,17 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
ERR_FAIL_COND_V_MSG(shader->fragment_output_mask != output_mask, RID(),
"Mismatch fragment shader output mask (" + itos(shader->fragment_output_mask) + ") and framebuffer color output mask (" + itos(output_mask) + ") when binding both in render pipeline.");
}
- //vertex
+ // Vertex.
VkPipelineVertexInputStateCreateInfo pipeline_vertex_input_state_create_info;
if (p_vertex_format != INVALID_ID) {
- //uses vertices, else it does not
+ // Uses vertices, else it does not.
ERR_FAIL_COND_V(!vertex_formats.has(p_vertex_format), RID());
const VertexDescriptionCache &vd = vertex_formats[p_vertex_format];
pipeline_vertex_input_state_create_info = vd.create_info;
- //validate with inputs
+ // Validate with inputs.
for (uint32_t i = 0; i < 32; i++) {
if (!(shader->vertex_input_mask & (1UL << i))) {
continue;
@@ -6421,7 +6483,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
}
} else {
- //does not use vertices
+ // Does not use vertices.
pipeline_vertex_input_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
pipeline_vertex_input_state_create_info.pNext = nullptr;
pipeline_vertex_input_state_create_info.flags = 0;
@@ -6433,7 +6495,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
ERR_FAIL_COND_V_MSG(shader->vertex_input_mask != 0, RID(),
"Shader contains vertex inputs, but no vertex input description was provided for pipeline creation.");
}
- //input assembly
+ // Input assembly.
ERR_FAIL_INDEX_V(p_render_primitive, RENDER_PRIMITIVE_MAX, RID());
@@ -6459,7 +6521,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
input_assembly_create_info.topology = topology_list[p_render_primitive];
input_assembly_create_info.primitiveRestartEnable = (p_render_primitive == RENDER_PRIMITIVE_TRIANGLE_STRIPS_WITH_RESTART_INDEX);
- //tessellation
+ // Tessellation.
VkPipelineTessellationStateCreateInfo tessellation_create_info;
tessellation_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
tessellation_create_info.pNext = nullptr;
@@ -6471,12 +6533,12 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
viewport_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewport_state_create_info.pNext = nullptr;
viewport_state_create_info.flags = 0;
- viewport_state_create_info.viewportCount = 1; //if VR extensions are supported at some point, this will have to be customizable in the framebuffer format
+ viewport_state_create_info.viewportCount = 1; // If VR extensions are supported at some point, this will have to be customizable in the framebuffer format.
viewport_state_create_info.pViewports = nullptr;
viewport_state_create_info.scissorCount = 1;
viewport_state_create_info.pScissors = nullptr;
- //rasterization
+ // Rasterization.
VkPipelineRasterizationStateCreateInfo rasterization_state_create_info;
rasterization_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterization_state_create_info.pNext = nullptr;
@@ -6499,7 +6561,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
rasterization_state_create_info.depthBiasSlopeFactor = p_rasterization_state.depth_bias_slope_factor;
rasterization_state_create_info.lineWidth = p_rasterization_state.line_width;
- //multisample
+ // Multisample.
VkPipelineMultisampleStateCreateInfo multisample_state_create_info;
multisample_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisample_state_create_info.pNext = nullptr;
@@ -6510,7 +6572,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
multisample_state_create_info.minSampleShading = p_multisample_state.min_sample_shading;
Vector<VkSampleMask> sample_mask;
if (p_multisample_state.sample_mask.size()) {
- //use sample mask
+ // Use sample mask.
const int rasterization_sample_mask_expected_size[TEXTURE_SAMPLES_MAX] = {
1, 2, 4, 8, 16, 32, 64
};
@@ -6528,7 +6590,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
multisample_state_create_info.alphaToCoverageEnable = p_multisample_state.enable_alpha_to_coverage;
multisample_state_create_info.alphaToOneEnable = p_multisample_state.enable_alpha_to_one;
- //depth stencil
+ // Depth stencil.
VkPipelineDepthStencilStateCreateInfo depth_stencil_state_create_info;
depth_stencil_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
@@ -6568,7 +6630,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
depth_stencil_state_create_info.minDepthBounds = p_depth_stencil_state.depth_range_min;
depth_stencil_state_create_info.maxDepthBounds = p_depth_stencil_state.depth_range_max;
- //blend state
+ // Blend state.
VkPipelineColorBlendStateCreateInfo color_blend_state_create_info;
color_blend_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
color_blend_state_create_info.pNext = nullptr;
@@ -6639,15 +6701,15 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
color_blend_state_create_info.blendConstants[2] = p_blend_state.blend_constant.b;
color_blend_state_create_info.blendConstants[3] = p_blend_state.blend_constant.a;
- //dynamic state
+ // Dynamic state.
VkPipelineDynamicStateCreateInfo dynamic_state_create_info;
dynamic_state_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamic_state_create_info.pNext = nullptr;
dynamic_state_create_info.flags = 0;
- Vector<VkDynamicState> dynamic_states; //vulkan is weird..
+ Vector<VkDynamicState> dynamic_states; // Vulkan is weird.
- dynamic_states.push_back(VK_DYNAMIC_STATE_VIEWPORT); //viewport and scissor are always dynamic
+ dynamic_states.push_back(VK_DYNAMIC_STATE_VIEWPORT); // Viewport and scissor are always dynamic.
dynamic_states.push_back(VK_DYNAMIC_STATE_SCISSOR);
if (p_dynamic_state_flags & DYNAMIC_STATE_LINE_WIDTH) {
@@ -6686,19 +6748,19 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
VkPipelineFragmentShadingRateStateCreateInfoKHR vrs_create_info;
if (context->get_vrs_capabilities().attachment_vrs_supported) {
// If VRS is used, this defines how the different VRS types are combined.
- // combinerOps[0] decides how we use the output of pipeline and primitive (drawcall) VRS
- // combinerOps[1] decides how we use the output of combinerOps[0] and our attachment VRS
+ // combinerOps[0] decides how we use the output of pipeline and primitive (drawcall) VRS.
+ // combinerOps[1] decides how we use the output of combinerOps[0] and our attachment VRS.
vrs_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR;
vrs_create_info.pNext = nullptr;
vrs_create_info.fragmentSize = { 4, 4 };
- vrs_create_info.combinerOps[0] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; // We don't use pipeline/primitive VRS so this really doesn't matter
- vrs_create_info.combinerOps[1] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR; // always use the outcome of attachment VRS if enabled
+ vrs_create_info.combinerOps[0] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR; // We don't use pipeline/primitive VRS so this really doesn't matter.
+ vrs_create_info.combinerOps[1] = VK_FRAGMENT_SHADING_RATE_COMBINER_OP_REPLACE_KHR; // Always use the outcome of attachment VRS if enabled.
graphics_pipeline_nextptr = &vrs_create_info;
}
- //finally, pipeline create info
+ // Finally, pipeline create info.
VkGraphicsPipelineCreateInfo graphics_pipeline_create_info;
graphics_pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
@@ -6716,9 +6778,9 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
specialization_info.resize(pipeline_stages.size());
specialization_map_entries.resize(pipeline_stages.size());
for (int i = 0; i < shader->specialization_constants.size(); i++) {
- //see if overridden
+ // See if overridden.
const Shader::SpecializationConstant &sc = shader->specialization_constants[i];
- data_ptr[i] = sc.constant.int_value; //just copy the 32 bits
+ data_ptr[i] = sc.constant.int_value; // Just copy the 32 bits.
for (int j = 0; j < p_specialization_constants.size(); j++) {
const PipelineSpecializationConstant &psc = p_specialization_constants[j];
@@ -6813,9 +6875,12 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
};
pipeline.validation.primitive_minimum = primitive_minimum[p_render_primitive];
#endif
- //create ID to associate with this pipeline
+ // Create ID to associate with this pipeline.
RID id = render_pipeline_owner.make_rid(pipeline);
- //now add all the dependencies
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ // Now add all the dependencies.
_add_dependency(id, p_shader);
return id;
}
@@ -6832,14 +6897,14 @@ bool RenderingDeviceVulkan::render_pipeline_is_valid(RID p_pipeline) {
RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants) {
_THREAD_SAFE_METHOD_
- //needs a shader
+ // Needs a shader.
Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_COND_V(!shader, RID());
ERR_FAIL_COND_V_MSG(!shader->is_compute, RID(),
"Non-compute shaders can't be used in compute pipelines");
- //finally, pipeline create info
+ // Finally, pipeline create info.
VkComputePipelineCreateInfo compute_pipeline_create_info;
compute_pipeline_create_info.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
@@ -6859,9 +6924,9 @@ RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader, const Vector<Pi
specialization_constant_data.resize(shader->specialization_constants.size());
uint32_t *data_ptr = specialization_constant_data.ptrw();
for (int i = 0; i < shader->specialization_constants.size(); i++) {
- //see if overridden
+ // See if overridden.
const Shader::SpecializationConstant &sc = shader->specialization_constants[i];
- data_ptr[i] = sc.constant.int_value; //just copy the 32 bits
+ data_ptr[i] = sc.constant.int_value; // Just copy the 32 bits.
for (int j = 0; j < p_specialization_constants.size(); j++) {
const PipelineSpecializationConstant &psc = p_specialization_constants[j];
@@ -6902,9 +6967,12 @@ RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader, const Vector<Pi
pipeline.local_group_size[1] = shader->compute_local_size[1];
pipeline.local_group_size[2] = shader->compute_local_size[2];
- //create ID to associate with this pipeline
+ // Create ID to associate with this pipeline.
RID id = compute_pipeline_owner.make_rid(pipeline);
- //now add all the dependencies
+#ifdef DEV_ENABLED
+ set_resource_name(id, "RID:" + itos(id.get_id()));
+#endif
+ // Now add all the dependencies.
_add_dependency(id, p_shader);
return id;
}
@@ -6934,7 +7002,7 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::screen_get_framebuff
_THREAD_SAFE_METHOD_
ERR_FAIL_COND_V_MSG(local_device.is_valid(), INVALID_ID, "Local devices have no screen");
- //very hacky, but not used often per frame so I guess ok
+ // Very hacky, but not used often per frame so I guess ok.
VkFormat vkformat = context->get_screen_format();
DataFormat format = DATA_FORMAT_MAX;
for (int i = 0; i < DATA_FORMAT_MAX; i++) {
@@ -7036,7 +7104,7 @@ Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebu
vk.view_count = p_framebuffer->view_count;
if (!p_framebuffer->framebuffers.has(vk)) {
- //need to create this version
+ // Need to create this version.
Framebuffer::Version version;
version.render_pass = _render_pass_create(framebuffer_formats[p_framebuffer->format_id].E->key().attachments, framebuffer_formats[p_framebuffer->format_id].E->key().passes, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_framebuffer->view_count);
@@ -7112,7 +7180,7 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff
}
if (color_index < p_clear_colors.size() && texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) {
- ERR_FAIL_INDEX_V(color_index, p_clear_colors.size(), ERR_BUG); //a bug
+ ERR_FAIL_INDEX_V(color_index, p_clear_colors.size(), ERR_BUG); // A bug.
Color clear_color = p_clear_colors[color_index];
clear_value.color.float32[0] = clear_color.r;
clear_value.color.float32[1] = clear_color.g;
@@ -7143,7 +7211,7 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff
ERR_CONTINUE_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), "Supplied storage texture " + itos(i) + " for draw list is not set to be used for storage.");
if (texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT) {
- //must change layout to general
+ // Must change layout to general.
VkImageMemoryBarrier image_memory_barrier;
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_memory_barrier.pNext = nullptr;
@@ -7171,7 +7239,7 @@ Error RenderingDeviceVulkan::_draw_list_render_pass_begin(Framebuffer *framebuff
vkCmdBeginRenderPass(command_buffer, &render_pass_begin, subpass_contents);
- //mark textures as bound
+ // Mark textures as bound.
draw_list_bound_textures.clear();
draw_list_unbind_color_textures = p_final_color_action != FINAL_ACTION_CONTINUE;
draw_list_unbind_depth_textures = p_final_depth_action != FINAL_ACTION_CONTINUE;
@@ -7248,7 +7316,7 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu
bool needs_clear_color = false;
bool needs_clear_depth = false;
- if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { //check custom region
+ if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { // Check custom region.
Rect2i viewport(viewport_offset, viewport_size);
Rect2i regioni = p_region;
if (!(regioni.position.x >= viewport.position.x) && (regioni.position.y >= viewport.position.y) &&
@@ -7277,13 +7345,13 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu
}
}
- if (p_initial_color_action == INITIAL_ACTION_CLEAR || needs_clear_color) { //check clear values
+ if (p_initial_color_action == INITIAL_ACTION_CLEAR || needs_clear_color) { // Check clear values.
int color_count = 0;
for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
Texture *texture = texture_owner.get_or_null(framebuffer->texture_ids[i]);
// We only check for our VRS usage bit if this is not the first texture id.
// If it is the first we're likely populating our VRS texture.
- // Bit dirty but..
+ // Bit dirty but...
if (!texture || (!(texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) && !(i != 0 && texture->usage_flags & TEXTURE_USAGE_VRS_ATTACHMENT_BIT))) {
color_count++;
}
@@ -7355,7 +7423,7 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p
bool needs_clear_color = false;
bool needs_clear_depth = false;
- if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { //check custom region
+ if (p_region != Rect2() && p_region != Rect2(Vector2(), viewport_size)) { // Check custom region.
Rect2i viewport(viewport_offset, viewport_size);
Rect2i regioni = p_region;
if (!(regioni.position.x >= viewport.position.x) && (regioni.position.y >= viewport.position.y) &&
@@ -7377,7 +7445,7 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p
}
}
- if (p_initial_color_action == INITIAL_ACTION_CLEAR || needs_clear_color) { //check clear values
+ if (p_initial_color_action == INITIAL_ACTION_CLEAR || needs_clear_color) { // Check clear values.
int color_count = 0;
for (int i = 0; i < framebuffer->texture_ids.size(); i++) {
@@ -7463,7 +7531,7 @@ RenderingDeviceVulkan::DrawList *RenderingDeviceVulkan::_get_draw_list_ptr(DrawL
return nullptr;
}
- uint64_t index = p_id & ((DrawListID(1) << DrawListID(ID_BASE_SHIFT)) - 1); //mask
+ uint64_t index = p_id & ((DrawListID(1) << DrawListID(ID_BASE_SHIFT)) - 1); // Mask.
if (index >= draw_list_count) {
return nullptr;
@@ -7475,6 +7543,16 @@ RenderingDeviceVulkan::DrawList *RenderingDeviceVulkan::_get_draw_list_ptr(DrawL
}
}
+void RenderingDeviceVulkan::draw_list_set_blend_constants(DrawListID p_list, const Color &p_color) {
+ DrawList *dl = _get_draw_list_ptr(p_list);
+ ERR_FAIL_COND(!dl);
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
+#endif
+
+ vkCmdSetBlendConstants(dl->command_buffer, p_color.components);
+}
+
void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline) {
DrawList *dl = _get_draw_list_ptr(p_list);
ERR_FAIL_COND(!dl);
@@ -7489,7 +7567,7 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RI
#endif
if (p_render_pipeline == dl->state.pipeline) {
- return; //redundant state, return.
+ return; // Redundant state, return.
}
dl->state.pipeline = p_render_pipeline;
@@ -7498,17 +7576,17 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RI
vkCmdBindPipeline(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->pipeline);
if (dl->state.pipeline_shader != pipeline->shader) {
- // shader changed, so descriptor sets may become incompatible.
+ // Shader changed, so descriptor sets may become incompatible.
- //go through ALL sets, and unbind them (and all those above) if the format is different
+ // Go through ALL sets, and unbind them (and all those above) if the format is different.
- uint32_t pcount = pipeline->set_formats.size(); //formats count in this pipeline
+ uint32_t pcount = pipeline->set_formats.size(); // Formats count in this pipeline.
dl->state.set_count = MAX(dl->state.set_count, pcount);
- const uint32_t *pformats = pipeline->set_formats.ptr(); //pipeline set formats
+ const uint32_t *pformats = pipeline->set_formats.ptr(); // Pipeline set formats.
- bool sets_valid = true; //once invalid, all above become invalid
+ bool sets_valid = true; // Once invalid, all above become invalid.
for (uint32_t i = 0; i < pcount; i++) {
- //if a part of the format is different, invalidate it (and the rest)
+ // If a part of the format is different, invalidate it (and the rest).
if (!sets_valid || dl->state.sets[i].pipeline_expected_format != pformats[i]) {
dl->state.sets[i].bound = false;
dl->state.sets[i].pipeline_expected_format = pformats[i];
@@ -7517,11 +7595,11 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RI
}
for (uint32_t i = pcount; i < dl->state.set_count; i++) {
- //unbind the ones above (not used) if exist
+ // Unbind the ones above (not used) if exist.
dl->state.sets[i].bound = false;
}
- dl->state.set_count = pcount; //update set count
+ dl->state.set_count = pcount; // Update set count.
if (pipeline->push_constant_size) {
dl->state.pipeline_push_constant_stages = pipeline->push_constant_stages;
@@ -7534,7 +7612,7 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RI
}
#ifdef DEBUG_ENABLED
- //update render pass pipeline info
+ // Update render pass pipeline info.
dl->validation.pipeline_active = true;
dl->validation.pipeline_dynamic_state = pipeline->validation.dynamic_state;
dl->validation.pipeline_vertex_format = pipeline->validation.vertex_format;
@@ -7564,8 +7642,8 @@ void RenderingDeviceVulkan::draw_list_bind_uniform_set(DrawListID p_list, RID p_
dl->state.set_count = p_index;
}
- dl->state.sets[p_index].descriptor_set = uniform_set->descriptor_set; //update set pointer
- dl->state.sets[p_index].bound = false; //needs rebind
+ dl->state.sets[p_index].descriptor_set = uniform_set->descriptor_set; // Update set pointer.
+ dl->state.sets[p_index].bound = false; // Needs rebind.
dl->state.sets[p_index].uniform_set_format = uniform_set->format;
dl->state.sets[p_index].uniform_set = p_uniform_set;
@@ -7583,7 +7661,7 @@ void RenderingDeviceVulkan::draw_list_bind_uniform_set(DrawListID p_list, RID p_
}
#ifdef DEBUG_ENABLED
- { //validate that textures bound are not attached as framebuffer bindings
+ { // Validate that textures bound are not attached as framebuffer bindings.
uint32_t attachable_count = uniform_set->attachable_textures.size();
const UniformSet::AttachableTexture *attachable_ptr = uniform_set->attachable_textures.ptr();
uint32_t bound_count = draw_list_bound_textures.size();
@@ -7609,7 +7687,7 @@ void RenderingDeviceVulkan::draw_list_bind_vertex_array(DrawListID p_list, RID p
ERR_FAIL_COND(!vertex_array);
if (dl->state.vertex_array == p_vertex_array) {
- return; //already set
+ return; // Already set.
}
dl->state.vertex_array = p_vertex_array;
@@ -7633,7 +7711,7 @@ void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_
ERR_FAIL_COND(!index_array);
if (dl->state.index_array == p_index_array) {
- return; //already set
+ return; // Already set.
}
dl->state.index_array = p_index_array;
@@ -7685,30 +7763,30 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices
ERR_FAIL_COND_MSG(!dl->validation.pipeline_active,
"No render pipeline was set before attempting to draw.");
if (dl->validation.pipeline_vertex_format != INVALID_ID) {
- //pipeline uses vertices, validate format
+ // Pipeline uses vertices, validate format.
ERR_FAIL_COND_MSG(dl->validation.vertex_format == INVALID_ID,
"No vertex array was bound, and render pipeline expects vertices.");
- //make sure format is right
+ // Make sure format is right.
ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format != dl->validation.vertex_format,
"The vertex format used to create the pipeline does not match the vertex format bound.");
- //make sure number of instances is valid
+ // Make sure number of instances is valid.
ERR_FAIL_COND_MSG(p_instances > dl->validation.vertex_max_instances_allowed,
"Number of instances requested (" + itos(p_instances) + " is larger than the maximum number supported by the bound vertex array (" + itos(dl->validation.vertex_max_instances_allowed) + ").");
}
if (dl->validation.pipeline_push_constant_size > 0) {
- //using push constants, check that they were supplied
+ // Using push constants, check that they were supplied.
ERR_FAIL_COND_MSG(!dl->validation.pipeline_push_constant_supplied,
"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");
}
#endif
- //Bind descriptor sets
+ // Bind descriptor sets.
for (uint32_t i = 0; i < dl->state.set_count; i++) {
if (dl->state.sets[i].pipeline_expected_format == 0) {
- continue; //nothing expected by this pipeline
+ continue; // Nothing expected by this pipeline.
}
#ifdef DEBUG_ENABLED
if (dl->state.sets[i].pipeline_expected_format != dl->state.sets[i].uniform_set_format) {
@@ -7723,7 +7801,7 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices
}
#endif
if (!dl->state.sets[i].bound) {
- //All good, see if this requires re-binding
+ // All good, see if this requires re-binding.
vkCmdBindDescriptorSets(dl->command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, dl->state.pipeline_layout, i, 1, &dl->state.sets[i].descriptor_set, 0, nullptr);
dl->state.sets[i].bound = true;
}
@@ -7737,12 +7815,6 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices
ERR_FAIL_COND_MSG(!dl->validation.index_array_size,
"Draw command requested indices, but no index buffer was set.");
- if (dl->validation.pipeline_vertex_format != INVALID_ID) {
- //uses vertices, do some vertex validations
- ERR_FAIL_COND_MSG(dl->validation.vertex_array_size < dl->validation.index_array_max_index,
- "Index array references (max index: " + itos(dl->validation.index_array_max_index) + ") indices beyond the vertex array size (" + itos(dl->validation.vertex_array_size) + ").");
- }
-
ERR_FAIL_COND_MSG(dl->validation.pipeline_uses_restart_indices != dl->validation.index_buffer_uses_restart_indices,
"The usage of restart indices in index buffer does not match the render primitive in the pipeline.");
#endif
@@ -7864,7 +7936,7 @@ Error RenderingDeviceVulkan::draw_list_switch_to_next_pass_split(uint32_t p_spli
}
Error RenderingDeviceVulkan::_draw_list_allocate(const Rect2i &p_viewport, uint32_t p_splits, uint32_t p_subpass) {
- // Lock while draw_list is active
+ // Lock while draw_list is active.
_THREAD_SAFE_LOCK_
if (p_splits == 0) {
@@ -7891,7 +7963,7 @@ Error RenderingDeviceVulkan::_draw_list_allocate(const Rect2i &p_viewport, uint3
VkCommandBuffer command_buffer;
VkCommandBufferAllocateInfo cmdbuf;
- //no command buffer exists, create it.
+ // No command buffer exists, create it.
cmdbuf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
cmdbuf.pNext = nullptr;
cmdbuf.commandPool = split_draw_list_allocators[i].command_pool;
@@ -7910,7 +7982,7 @@ Error RenderingDeviceVulkan::_draw_list_allocate(const Rect2i &p_viewport, uint3
draw_list_split = true;
for (uint32_t i = 0; i < p_splits; i++) {
- //take a command buffer and initialize it
+ // Take a command buffer and initialize it.
VkCommandBuffer command_buffer = split_draw_list_allocators[i].command_buffers[frame];
VkCommandBufferInheritanceInfo inheritance_info;
@@ -7920,7 +7992,7 @@ Error RenderingDeviceVulkan::_draw_list_allocate(const Rect2i &p_viewport, uint3
inheritance_info.subpass = p_subpass;
inheritance_info.framebuffer = draw_list_vkframebuffer;
inheritance_info.occlusionQueryEnable = false;
- inheritance_info.queryFlags = 0; //?
+ inheritance_info.queryFlags = 0; // ?
inheritance_info.pipelineStatistics = 0;
VkCommandBufferBeginInfo cmdbuf_begin;
@@ -7953,7 +8025,7 @@ Error RenderingDeviceVulkan::_draw_list_allocate(const Rect2i &p_viewport, uint3
void RenderingDeviceVulkan::_draw_list_free(Rect2i *r_last_viewport) {
if (draw_list_split) {
- //send all command buffers
+ // Send all command buffers.
VkCommandBuffer *command_buffers = (VkCommandBuffer *)alloca(sizeof(VkCommandBuffer) * draw_list_count);
for (uint32_t i = 0; i < draw_list_count; i++) {
vkEndCommandBuffer(draw_list[i].command_buffer);
@@ -7973,12 +8045,12 @@ void RenderingDeviceVulkan::_draw_list_free(Rect2i *r_last_viewport) {
if (r_last_viewport) {
*r_last_viewport = draw_list->viewport;
}
- //just end the list
+ // Just end the list.
memdelete(draw_list);
draw_list = nullptr;
}
- // draw_list is no longer active
+ // Draw_list is no longer active.
_THREAD_SAFE_UNLOCK_
}
@@ -7993,7 +8065,7 @@ void RenderingDeviceVulkan::draw_list_end(uint32_t p_post_barrier) {
for (int i = 0; i < draw_list_bound_textures.size(); i++) {
Texture *texture = texture_owner.get_or_null(draw_list_bound_textures[i]);
- ERR_CONTINUE(!texture); //wtf
+ ERR_CONTINUE(!texture); // Wtf.
if (draw_list_unbind_color_textures && (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT)) {
texture->bound = false;
}
@@ -8065,8 +8137,8 @@ void RenderingDeviceVulkan::draw_list_end(uint32_t p_post_barrier) {
draw_list_storage_textures.clear();
// To ensure proper synchronization, we must make sure rendering is done before:
- // * Some buffer is copied
- // * Another render pass happens (since we may be done)
+ // * Some buffer is copied.
+ // * Another render pass happens (since we may be done).
VkMemoryBarrier mem_barrier;
mem_barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
@@ -8091,7 +8163,7 @@ RenderingDevice::ComputeListID RenderingDeviceVulkan::compute_list_begin(bool p_
ERR_FAIL_COND_V_MSG(!p_allow_draw_overlap && draw_list != nullptr, INVALID_ID, "Only one draw list can be active at the same time.");
ERR_FAIL_COND_V_MSG(compute_list != nullptr, INVALID_ID, "Only one draw/compute list can be active at the same time.");
- // Lock while compute_list is active
+ // Lock while compute_list is active.
_THREAD_SAFE_LOCK_
compute_list = memnew(ComputeList);
@@ -8111,7 +8183,7 @@ void RenderingDeviceVulkan::compute_list_bind_compute_pipeline(ComputeListID p_l
ERR_FAIL_COND(!pipeline);
if (p_compute_pipeline == cl->state.pipeline) {
- return; //redundant state, return.
+ return; // Redundant state, return.
}
cl->state.pipeline = p_compute_pipeline;
@@ -8120,17 +8192,17 @@ void RenderingDeviceVulkan::compute_list_bind_compute_pipeline(ComputeListID p_l
vkCmdBindPipeline(cl->command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->pipeline);
if (cl->state.pipeline_shader != pipeline->shader) {
- // shader changed, so descriptor sets may become incompatible.
+ // Shader changed, so descriptor sets may become incompatible.
- //go through ALL sets, and unbind them (and all those above) if the format is different
+ // Go through ALL sets, and unbind them (and all those above) if the format is different.
- uint32_t pcount = pipeline->set_formats.size(); //formats count in this pipeline
+ uint32_t pcount = pipeline->set_formats.size(); // Formats count in this pipeline.
cl->state.set_count = MAX(cl->state.set_count, pcount);
- const uint32_t *pformats = pipeline->set_formats.ptr(); //pipeline set formats
+ const uint32_t *pformats = pipeline->set_formats.ptr(); // Pipeline set formats.
- bool sets_valid = true; //once invalid, all above become invalid
+ bool sets_valid = true; // Once invalid, all above become invalid.
for (uint32_t i = 0; i < pcount; i++) {
- //if a part of the format is different, invalidate it (and the rest)
+ // If a part of the format is different, invalidate it (and the rest).
if (!sets_valid || cl->state.sets[i].pipeline_expected_format != pformats[i]) {
cl->state.sets[i].bound = false;
cl->state.sets[i].pipeline_expected_format = pformats[i];
@@ -8139,11 +8211,11 @@ void RenderingDeviceVulkan::compute_list_bind_compute_pipeline(ComputeListID p_l
}
for (uint32_t i = pcount; i < cl->state.set_count; i++) {
- //unbind the ones above (not used) if exist
+ // Unbind the ones above (not used) if exist.
cl->state.sets[i].bound = false;
}
- cl->state.set_count = pcount; //update set count
+ cl->state.set_count = pcount; // Update set count.
if (pipeline->push_constant_size) {
cl->state.pipeline_push_constant_stages = pipeline->push_constant_stages;
@@ -8159,7 +8231,7 @@ void RenderingDeviceVulkan::compute_list_bind_compute_pipeline(ComputeListID p_l
}
#ifdef DEBUG_ENABLED
- //update compute pass pipeline info
+ // Update compute pass pipeline info.
cl->validation.pipeline_active = true;
cl->validation.pipeline_push_constant_size = pipeline->push_constant_size;
#endif
@@ -8187,8 +8259,8 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list,
cl->state.set_count = p_index;
}
- cl->state.sets[p_index].descriptor_set = uniform_set->descriptor_set; //update set pointer
- cl->state.sets[p_index].bound = false; //needs rebind
+ cl->state.sets[p_index].descriptor_set = uniform_set->descriptor_set; // Update set pointer.
+ cl->state.sets[p_index].bound = false; // Needs rebind.
cl->state.sets[p_index].uniform_set_format = uniform_set->format;
cl->state.sets[p_index].uniform_set = p_uniform_set;
@@ -8291,7 +8363,7 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list,
textures_to_storage[i]->layout = VK_IMAGE_LAYOUT_GENERAL;
- cl->state.textures_to_sampled_layout.insert(textures_to_storage[i]); //needs to go back to sampled layout afterwards
+ cl->state.textures_to_sampled_layout.insert(textures_to_storage[i]); // Needs to go back to sampled layout afterwards.
}
}
@@ -8304,7 +8376,7 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list,
}
#if 0
- { //validate that textures bound are not attached as framebuffer bindings
+ { // Validate that textures bound are not attached as framebuffer bindings.
uint32_t attachable_count = uniform_set->attachable_textures.size();
const RID *attachable_ptr = uniform_set->attachable_textures.ptr();
uint32_t bound_count = draw_list_bound_textures.size();
@@ -8364,18 +8436,18 @@ void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t
ERR_FAIL_COND_MSG(!cl->validation.pipeline_active, "No compute pipeline was set before attempting to draw.");
if (cl->validation.pipeline_push_constant_size > 0) {
- //using push constants, check that they were supplied
+ // Using push constants, check that they were supplied.
ERR_FAIL_COND_MSG(!cl->validation.pipeline_push_constant_supplied,
"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");
}
#endif
- //Bind descriptor sets
+ // Bind descriptor sets.
for (uint32_t i = 0; i < cl->state.set_count; i++) {
if (cl->state.sets[i].pipeline_expected_format == 0) {
- continue; //nothing expected by this pipeline
+ continue; // Nothing expected by this pipeline.
}
#ifdef DEBUG_ENABLED
if (cl->state.sets[i].pipeline_expected_format != cl->state.sets[i].uniform_set_format) {
@@ -8390,7 +8462,7 @@ void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t
}
#endif
if (!cl->state.sets[i].bound) {
- //All good, see if this requires re-binding
+ // All good, see if this requires re-binding.
vkCmdBindDescriptorSets(cl->command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, cl->state.pipeline_layout, i, 1, &cl->state.sets[i].descriptor_set, 0, nullptr);
cl->state.sets[i].bound = true;
}
@@ -8416,7 +8488,7 @@ void RenderingDeviceVulkan::compute_list_dispatch_threads(ComputeListID p_list,
ERR_FAIL_COND_MSG(!cl->validation.pipeline_active, "No compute pipeline was set before attempting to draw.");
if (cl->validation.pipeline_push_constant_size > 0) {
- //using push constants, check that they were supplied
+ // Using push constants, check that they were supplied.
ERR_FAIL_COND_MSG(!cl->validation.pipeline_push_constant_supplied,
"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");
}
@@ -8447,18 +8519,18 @@ void RenderingDeviceVulkan::compute_list_dispatch_indirect(ComputeListID p_list,
ERR_FAIL_COND_MSG(!cl->validation.pipeline_active, "No compute pipeline was set before attempting to draw.");
if (cl->validation.pipeline_push_constant_size > 0) {
- //using push constants, check that they were supplied
+ // Using push constants, check that they were supplied.
ERR_FAIL_COND_MSG(!cl->validation.pipeline_push_constant_supplied,
"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");
}
#endif
- //Bind descriptor sets
+ // Bind descriptor sets.
for (uint32_t i = 0; i < cl->state.set_count; i++) {
if (cl->state.sets[i].pipeline_expected_format == 0) {
- continue; //nothing expected by this pipeline
+ continue; // Nothing expected by this pipeline.
}
#ifdef DEBUG_ENABLED
if (cl->state.sets[i].pipeline_expected_format != cl->state.sets[i].uniform_set_format) {
@@ -8473,7 +8545,7 @@ void RenderingDeviceVulkan::compute_list_dispatch_indirect(ComputeListID p_list,
}
#endif
if (!cl->state.sets[i].bound) {
- //All good, see if this requires re-binding
+ // All good, see if this requires re-binding.
vkCmdBindDescriptorSets(cl->command_buffer, VK_PIPELINE_BIND_POINT_COMPUTE, cl->state.pipeline_layout, i, 1, &cl->state.sets[i].descriptor_set, 0, nullptr);
cl->state.sets[i].bound = true;
}
@@ -8567,7 +8639,7 @@ void RenderingDeviceVulkan::compute_list_end(uint32_t p_post_barrier) {
memdelete(compute_list);
compute_list = nullptr;
- // compute_list is no longer active
+ // Compute_list is no longer active.
_THREAD_SAFE_UNLOCK_
}
@@ -8660,7 +8732,7 @@ void RenderingDeviceVulkan::draw_list_render_secondary_to_framebuffer(ID p_frame
"Draw list index (" + itos(i) + ") is created with a framebuffer format incompatible with this render pass.");
if (dl->validation.active) {
- //needs to be closed, so close it.
+ // Needs to be closed, so close it.
vkEndCommandBuffer(dl->command_buffer);
dl->validation.active = false;
}
@@ -8677,7 +8749,15 @@ void RenderingDeviceVulkan::draw_list_render_secondary_to_framebuffer(ID p_frame
#endif
void RenderingDeviceVulkan::_free_internal(RID p_id) {
- //push everything so it's disposed of next time this frame index is processed (means, it's safe to do it)
+#ifdef DEV_ENABLED
+ String resource_name;
+ if (resource_names.has(p_id)) {
+ resource_name = resource_names[p_id];
+ resource_names.erase(p_id);
+ }
+#endif
+
+ // Push everything so it's disposed of next time this frame index is processed (means, it's safe to do it).
if (texture_owner.owns(p_id)) {
Texture *texture = texture_owner.get_or_null(p_id);
frames[frame].textures_to_dispose_of.push_back(*texture);
@@ -8685,6 +8765,11 @@ void RenderingDeviceVulkan::_free_internal(RID p_id) {
} else if (framebuffer_owner.owns(p_id)) {
Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_id);
frames[frame].framebuffers_to_dispose_of.push_back(*framebuffer);
+
+ if (framebuffer->invalidated_callback != nullptr) {
+ framebuffer->invalidated_callback(framebuffer->invalidated_callback_userdata);
+ }
+
framebuffer_owner.free(p_id);
} else if (sampler_owner.owns(p_id)) {
VkSampler *sampler = sampler_owner.get_or_null(p_id);
@@ -8741,30 +8826,34 @@ void RenderingDeviceVulkan::_free_internal(RID p_id) {
frames[frame].compute_pipelines_to_dispose_of.push_back(*pipeline);
compute_pipeline_owner.free(p_id);
} else {
+#ifdef DEV_ENABLED
+ ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id()) + " " + resource_name);
+#else
ERR_PRINT("Attempted to free invalid ID: " + itos(p_id.get_id()));
+#endif
}
}
void RenderingDeviceVulkan::free(RID p_id) {
_THREAD_SAFE_METHOD_
- _free_dependencies(p_id); //recursively erase dependencies first, to avoid potential API problems
+ _free_dependencies(p_id); // Recursively erase dependencies first, to avoid potential API problems.
_free_internal(p_id);
}
-// The full list of resources that can be named is in the VkObjectType enum
+// The full list of resources that can be named is in the VkObjectType enum.
// We just expose the resources that are owned and can be accessed easily.
void RenderingDeviceVulkan::set_resource_name(RID p_id, const String p_name) {
if (texture_owner.owns(p_id)) {
Texture *texture = texture_owner.get_or_null(p_id);
if (texture->owner.is_null()) {
- // Don't set the source texture's name when calling on a texture view
+ // Don't set the source texture's name when calling on a texture view.
context->set_object_name(VK_OBJECT_TYPE_IMAGE, uint64_t(texture->image), p_name);
}
context->set_object_name(VK_OBJECT_TYPE_IMAGE_VIEW, uint64_t(texture->view), p_name + " View");
} else if (framebuffer_owner.owns(p_id)) {
//Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_id);
- // Not implemented for now as the relationship between Framebuffer and RenderPass is very complex
+ // Not implemented for now as the relationship between Framebuffer and RenderPass is very complex.
} else if (sampler_owner.owns(p_id)) {
VkSampler *sampler = sampler_owner.get_or_null(p_id);
context->set_object_name(VK_OBJECT_TYPE_SAMPLER, uint64_t(*sampler), p_name);
@@ -8803,7 +8892,11 @@ void RenderingDeviceVulkan::set_resource_name(RID p_id, const String p_name) {
context->set_object_name(VK_OBJECT_TYPE_PIPELINE_LAYOUT, uint64_t(pipeline->pipeline_layout), p_name + " Layout");
} else {
ERR_PRINT("Attempted to name invalid ID: " + itos(p_id.get_id()));
+ return;
}
+#ifdef DEV_ENABLED
+ resource_names[p_id] = p_name;
+#endif
}
void RenderingDeviceVulkan::draw_command_begin_label(String p_label_name, const Color p_color) {
@@ -8847,17 +8940,17 @@ void RenderingDeviceVulkan::_finalize_command_bufers() {
ERR_PRINT("Found open compute list at the end of the frame, this should never happen (further compute will likely not work).");
}
- { //complete the setup buffer (that needs to be processed before anything else)
+ { // Complete the setup buffer (that needs to be processed before anything else).
vkEndCommandBuffer(frames[frame].setup_command_buffer);
vkEndCommandBuffer(frames[frame].draw_command_buffer);
}
}
void RenderingDeviceVulkan::_begin_frame() {
- //erase pending resources
+ // Erase pending resources.
_free_pending_resources(frame);
- //create setup command buffer and set as the setup buffer
+ // Create setup command buffer and set as the setup buffer.
{
VkCommandBufferBeginInfo cmdbuf_begin;
@@ -8876,13 +8969,13 @@ void RenderingDeviceVulkan::_begin_frame() {
if (local_device.is_null()) {
context->append_command_buffer(frames[frame].draw_command_buffer);
- context->set_setup_buffer(frames[frame].setup_command_buffer); //append now so it's added before everything else
+ context->set_setup_buffer(frames[frame].setup_command_buffer); // Append now so it's added before everything else.
}
}
- //advance current frame
+ // Advance current frame.
frames_drawn++;
- //advance staging buffer if used
+ // Advance staging buffer if used.
if (staging_buffer_used) {
staging_buffer_current = (staging_buffer_current + 1) % staging_buffer_blocks.size();
staging_buffer_used = false;
@@ -8907,7 +9000,7 @@ void RenderingDeviceVulkan::swap_buffers() {
_finalize_command_bufers();
screen_prepared = false;
- //swap buffers
+ // Swap buffers.
context->swap_buffers();
frame = (frame + 1) % frame_count;
@@ -8953,15 +9046,15 @@ VmaPool RenderingDeviceVulkan::_find_or_create_small_allocs_pool(uint32_t p_mem_
pci.pMemoryAllocateNext = nullptr;
VmaPool pool = VK_NULL_HANDLE;
VkResult res = vmaCreatePool(allocator, &pci, &pool);
- small_allocs_pools[p_mem_type_index] = pool; // Don't try to create it again if failed the first time
+ small_allocs_pools[p_mem_type_index] = pool; // Don't try to create it again if failed the first time.
ERR_FAIL_COND_V_MSG(res, pool, "vmaCreatePool failed with error " + itos(res) + ".");
return pool;
}
void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
- //free in dependency usage order, so nothing weird happens
- //pipelines
+ // Free in dependency usage order, so nothing weird happens.
+ // Pipelines.
while (frames[p_frame].render_pipelines_to_dispose_of.front()) {
RenderPipeline *pipeline = &frames[p_frame].render_pipelines_to_dispose_of.front()->get();
@@ -8978,7 +9071,7 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
frames[p_frame].compute_pipelines_to_dispose_of.pop_front();
}
- //uniform sets
+ // Uniform sets.
while (frames[p_frame].uniform_sets_to_dispose_of.front()) {
UniformSet *uniform_set = &frames[p_frame].uniform_sets_to_dispose_of.front()->get();
@@ -8988,7 +9081,7 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
frames[p_frame].uniform_sets_to_dispose_of.pop_front();
}
- //buffer views
+ // Buffer views.
while (frames[p_frame].buffer_views_to_dispose_of.front()) {
VkBufferView buffer_view = frames[p_frame].buffer_views_to_dispose_of.front()->get();
@@ -8997,19 +9090,19 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
frames[p_frame].buffer_views_to_dispose_of.pop_front();
}
- //shaders
+ // Shaders.
while (frames[p_frame].shaders_to_dispose_of.front()) {
Shader *shader = &frames[p_frame].shaders_to_dispose_of.front()->get();
- //descriptor set layout for each set
+ // Descriptor set layout for each set.
for (int i = 0; i < shader->sets.size(); i++) {
vkDestroyDescriptorSetLayout(device, shader->sets[i].descriptor_set_layout, nullptr);
}
- //pipeline layout
+ // Pipeline layout.
vkDestroyPipelineLayout(device, shader->pipeline_layout, nullptr);
- //shaders themselves
+ // Shaders themselves.
for (int i = 0; i < shader->pipeline_stages.size(); i++) {
vkDestroyShaderModule(device, shader->pipeline_stages[i].module, nullptr);
}
@@ -9017,7 +9110,7 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
frames[p_frame].shaders_to_dispose_of.pop_front();
}
- //samplers
+ // Samplers.
while (frames[p_frame].samplers_to_dispose_of.front()) {
VkSampler sampler = frames[p_frame].samplers_to_dispose_of.front()->get();
@@ -9026,12 +9119,12 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
frames[p_frame].samplers_to_dispose_of.pop_front();
}
- //framebuffers
+ // Framebuffers.
while (frames[p_frame].framebuffers_to_dispose_of.front()) {
Framebuffer *framebuffer = &frames[p_frame].framebuffers_to_dispose_of.front()->get();
for (const KeyValue<Framebuffer::VersionKey, Framebuffer::Version> &E : framebuffer->framebuffers) {
- //first framebuffer, then render pass because it depends on it
+ // First framebuffer, then render pass because it depends on it.
vkDestroyFramebuffer(device, E.value.framebuffer, nullptr);
vkDestroyRenderPass(device, E.value.render_pass, nullptr);
}
@@ -9039,7 +9132,7 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
frames[p_frame].framebuffers_to_dispose_of.pop_front();
}
- //textures
+ // Textures.
while (frames[p_frame].textures_to_dispose_of.front()) {
Texture *texture = &frames[p_frame].textures_to_dispose_of.front()->get();
@@ -9048,14 +9141,14 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
}
vkDestroyImageView(device, texture->view, nullptr);
if (texture->owner.is_null()) {
- //actually owns the image and the allocation too
+ // Actually owns the image and the allocation too.
image_memory -= texture->allocation_info.size;
vmaDestroyImage(allocator, texture->image, texture->allocation);
}
frames[p_frame].textures_to_dispose_of.pop_front();
}
- //buffers
+ // Buffers.
while (frames[p_frame].buffers_to_dispose_of.front()) {
_buffer_free(&frames[p_frame].buffers_to_dispose_of.front()->get());
@@ -9087,9 +9180,9 @@ uint64_t RenderingDeviceVulkan::get_memory_usage(MemoryType p_type) const {
void RenderingDeviceVulkan::_flush(bool p_current_frame) {
if (local_device.is_valid() && !p_current_frame) {
- return; //flushing previous frames has no effect with local device
+ return; // Flushing previous frames has no effect with local device.
}
- //not doing this crashes RADV (undefined behavior)
+ // Not doing this crashes RADV (undefined behavior).
if (p_current_frame) {
vkEndCommandBuffer(frames[frame].setup_command_buffer);
vkEndCommandBuffer(frames[frame].draw_command_buffer);
@@ -9113,7 +9206,7 @@ void RenderingDeviceVulkan::_flush(bool p_current_frame) {
} else {
context->flush(p_current_frame, p_current_frame);
- //re-create the setup command
+ // Re-create the setup command.
if (p_current_frame) {
VkCommandBufferBeginInfo cmdbuf_begin;
cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
@@ -9123,7 +9216,7 @@ void RenderingDeviceVulkan::_flush(bool p_current_frame) {
VkResult err = vkBeginCommandBuffer(frames[frame].setup_command_buffer, &cmdbuf_begin);
ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + ".");
- context->set_setup_buffer(frames[frame].setup_command_buffer); //append now so it's added before everything else
+ context->set_setup_buffer(frames[frame].setup_command_buffer); // Append now so it's added before everything else.
}
if (p_current_frame) {
@@ -9141,7 +9234,7 @@ void RenderingDeviceVulkan::_flush(bool p_current_frame) {
}
void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_device) {
- // get our device capabilities
+ // Get our device capabilities.
{
device_capabilities.version_major = p_context->get_vulkan_major();
device_capabilities.version_minor = p_context->get_vulkan_minor();
@@ -9154,12 +9247,12 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
local_device = p_context->local_device_create();
device = p_context->local_device_get_vk_device(local_device);
} else {
- frame_count = p_context->get_swapchain_image_count() + 1; //always need one extra to ensure it's unused at any time, without having to use a fence for this.
+ frame_count = p_context->get_swapchain_image_count() + 1; // Always need one extra to ensure it's unused at any time, without having to use a fence for this.
}
limits = p_context->get_device_limits();
max_timestamp_query_elements = 256;
- { //initialize allocator
+ { // Initialize allocator.
VmaAllocatorCreateInfo allocatorInfo;
memset(&allocatorInfo, 0, sizeof(VmaAllocatorCreateInfo));
@@ -9171,11 +9264,11 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
frames.resize(frame_count);
frame = 0;
- //create setup and frame buffers
+ // Create setup and frame buffers.
for (int i = 0; i < frame_count; i++) {
frames[i].index = 0;
- { //create command pool, one per frame is recommended
+ { // Create command pool, one per frame is recommended.
VkCommandPoolCreateInfo cmd_pool_info;
cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
cmd_pool_info.pNext = nullptr;
@@ -9186,10 +9279,10 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
ERR_FAIL_COND_MSG(res, "vkCreateCommandPool failed with error " + itos(res) + ".");
}
- { //create command buffers
+ { // Create command buffers.
VkCommandBufferAllocateInfo cmdbuf;
- //no command buffer exists, create it.
+ // No command buffer exists, create it.
cmdbuf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
cmdbuf.pNext = nullptr;
cmdbuf.commandPool = frames[i].command_pool;
@@ -9204,7 +9297,7 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
}
{
- //create query pool
+ // Create query pool.
VkQueryPoolCreateInfo query_pool_create_info;
query_pool_create_info.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
query_pool_create_info.flags = 0;
@@ -9226,8 +9319,8 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
}
{
- //begin the first command buffer for the first frame, so
- //setting up things can be done in the meantime until swap_buffers(), which is called before advance.
+ // Begin the first command buffer for the first frame, so
+ // setting up things can be done in the meantime until swap_buffers(), which is called before advance.
VkCommandBufferBeginInfo cmdbuf_begin;
cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmdbuf_begin.pNext = nullptr;
@@ -9240,42 +9333,42 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
err = vkBeginCommandBuffer(frames[0].draw_command_buffer, &cmdbuf_begin);
ERR_FAIL_COND_MSG(err, "vkBeginCommandBuffer failed with error " + itos(err) + ".");
if (local_device.is_null()) {
- context->set_setup_buffer(frames[0].setup_command_buffer); //append now so it's added before everything else
+ context->set_setup_buffer(frames[0].setup_command_buffer); // Append now so it's added before everything else.
context->append_command_buffer(frames[0].draw_command_buffer);
}
}
- // Note: If adding new project settings here, also duplicate their definition in
+ // NOTE: If adding new project settings here, also duplicate their definition in
// rendering_server.cpp for headless doctool.
staging_buffer_block_size = GLOBAL_DEF("rendering/vulkan/staging_buffer/block_size_kb", 256);
staging_buffer_block_size = MAX(4u, staging_buffer_block_size);
- staging_buffer_block_size *= 1024; //kb -> bytes
+ staging_buffer_block_size *= 1024; // Kb -> bytes.
staging_buffer_max_size = GLOBAL_DEF("rendering/vulkan/staging_buffer/max_size_mb", 128);
staging_buffer_max_size = MAX(1u, staging_buffer_max_size);
staging_buffer_max_size *= 1024 * 1024;
if (staging_buffer_max_size < staging_buffer_block_size * 4) {
- //validate enough blocks
+ // Validate enough blocks.
staging_buffer_max_size = staging_buffer_block_size * 4;
}
texture_upload_region_size_px = GLOBAL_DEF("rendering/vulkan/staging_buffer/texture_upload_region_size_px", 64);
texture_upload_region_size_px = nearest_power_of_2_templated(texture_upload_region_size_px);
- frames_drawn = frame_count; //start from frame count, so everything else is immediately old
+ frames_drawn = frame_count; // Start from frame count, so everything else is immediately old.
- //ensure current staging block is valid and at least one per frame exists
+ // Ensure current staging block is valid and at least one per frame exists.
staging_buffer_current = 0;
staging_buffer_used = false;
for (int i = 0; i < frame_count; i++) {
- //staging was never used, create a block
+ // Staging was never used, create a block.
Error err = _insert_staging_block();
ERR_CONTINUE(err != OK);
}
max_descriptors_per_pool = GLOBAL_DEF("rendering/vulkan/descriptor_pools/max_descriptors_per_pool", 64);
- //check to make sure DescriptorPoolKey is good
+ // Check to make sure DescriptorPoolKey is good.
static_assert(sizeof(uint64_t) * 3 >= UNIFORM_TYPE_MAX * sizeof(uint16_t));
draw_list = nullptr;
@@ -9296,6 +9389,11 @@ void RenderingDeviceVulkan::_free_rids(T &p_owner, const char *p_type) {
WARN_PRINT(vformat("%d RIDs of type \"%s\" were leaked.", owned.size(), p_type));
}
for (const RID &E : owned) {
+#ifdef DEV_ENABLED
+ if (resource_names.has(E)) {
+ print_line(String(" - ") + resource_names[E]);
+ }
+#endif
free(E);
}
}
@@ -9305,7 +9403,7 @@ void RenderingDeviceVulkan::capture_timestamp(const String &p_name) {
ERR_FAIL_COND_MSG(draw_list != nullptr, "Capturing timestamps during draw list creation is not allowed. Offending timestamp was: " + p_name);
ERR_FAIL_COND(frames[frame].timestamp_count >= max_timestamp_query_elements);
- //this should be optional for profiling, else it will slow things down
+ // This should be optional for profiling, else it will slow things down.
{
VkMemoryBarrier memoryBarrier;
@@ -9431,7 +9529,7 @@ uint64_t RenderingDeviceVulkan::get_driver_resource(DriverResource p_resource, R
return uint64_t(render_pipeline->pipeline);
} break;
default: {
- // not supported for this driver
+ // Not supported for this driver.
return 0;
} break;
}
@@ -9468,9 +9566,9 @@ static void mult64to128(uint64_t u, uint64_t v, uint64_t &h, uint64_t &l) {
uint64_t RenderingDeviceVulkan::get_captured_timestamp_gpu_time(uint32_t p_index) const {
ERR_FAIL_UNSIGNED_INDEX_V(p_index, frames[frame].timestamp_result_count, 0);
- // this sucks because timestampPeriod multiplier is a float, while the timestamp is 64 bits nanosecs.
- // so, in cases like nvidia which give you enormous numbers and 1 as multiplier, multiplying is next to impossible
- // need to do 128 bits fixed point multiplication to get the right value
+ // This sucks because timestampPeriod multiplier is a float, while the timestamp is 64 bits nanosecs.
+ // So, in cases like nvidia which give you enormous numbers and 1 as multiplier, multiplying is next to impossible.
+ // Need to do 128 bits fixed point multiplication to get the right value.
uint64_t shift_bits = 16;
@@ -9583,7 +9681,7 @@ uint64_t RenderingDeviceVulkan::limit_get(Limit p_limit) const {
}
void RenderingDeviceVulkan::finalize() {
- //free all resources
+ // Free all resources.
_flush(false);
@@ -9601,7 +9699,7 @@ void RenderingDeviceVulkan::finalize() {
_free_rids(framebuffer_owner, "Framebuffer");
_free_rids(sampler_owner, "Sampler");
{
- //for textures it's a bit more difficult because they may be shared
+ // For textures it's a bit more difficult because they may be shared.
List<RID> owned;
texture_owner.get_owned_list(&owned);
if (owned.size()) {
@@ -9610,23 +9708,33 @@ void RenderingDeviceVulkan::finalize() {
} else {
WARN_PRINT(vformat("%d RIDs of type \"Texture\" were leaked.", owned.size()));
}
- //free shared first
+ // Free shared first.
for (List<RID>::Element *E = owned.front(); E;) {
List<RID>::Element *N = E->next();
if (texture_is_shared(E->get())) {
+#ifdef DEV_ENABLED
+ if (resource_names.has(E->get())) {
+ print_line(String(" - ") + resource_names[E->get()]);
+ }
+#endif
free(E->get());
owned.erase(E);
}
E = N;
}
- //free non shared second, this will avoid an error trying to free unexisting textures due to dependencies.
+ // Free non shared second, this will avoid an error trying to free unexisting textures due to dependencies.
for (const RID &E : owned) {
+#ifdef DEV_ENABLED
+ if (resource_names.has(E)) {
+ print_line(String(" - ") + resource_names[E]);
+ }
+#endif
free(E);
}
}
}
- //free everything pending
+ // Free everything pending.
for (int i = 0; i < frame_count; i++) {
int f = (frame + i) % frame_count;
_free_pending_resources(f);
@@ -9662,7 +9770,7 @@ void RenderingDeviceVulkan::finalize() {
}
framebuffer_formats.clear();
- //all these should be clear at this point
+ // All these should be clear at this point.
ERR_FAIL_COND(descriptor_pools.size());
ERR_FAIL_COND(dependency_map.size());
ERR_FAIL_COND(reverse_dependency_map.size());
diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h
index 7c8021251f..6007e1ab4d 100644
--- a/drivers/vulkan/rendering_device_vulkan.h
+++ b/drivers/vulkan/rendering_device_vulkan.h
@@ -96,13 +96,13 @@ class RenderingDeviceVulkan : public RenderingDevice {
ID_TYPE_SPLIT_DRAW_LIST,
ID_TYPE_COMPUTE_LIST,
ID_TYPE_MAX,
- ID_BASE_SHIFT = 58 //5 bits for ID types
+ ID_BASE_SHIFT = 58 // 5 bits for ID types.
};
VkDevice device = VK_NULL_HANDLE;
- HashMap<RID, HashSet<RID>> dependency_map; //IDs to IDs that depend on it
- HashMap<RID, HashSet<RID>> reverse_dependency_map; //same as above, but in reverse
+ HashMap<RID, HashSet<RID>> dependency_map; // IDs to IDs that depend on it.
+ HashMap<RID, HashSet<RID>> reverse_dependency_map; // Same as above, but in reverse.
void _add_dependency(RID p_id, RID p_depends_on);
void _free_dependencies(RID p_id);
@@ -152,7 +152,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
uint32_t read_aspect_mask = 0;
uint32_t barrier_aspect_mask = 0;
- bool bound = false; //bound to framebffer
+ bool bound = false; // Bound to framebffer.
RID owner;
};
@@ -214,7 +214,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
uint32_t usage = 0;
VkBuffer buffer = VK_NULL_HANDLE;
VmaAllocation allocation = nullptr;
- VkDescriptorBufferInfo buffer_info; //used for binding
+ VkDescriptorBufferInfo buffer_info; // Used for binding.
Buffer() {
}
};
@@ -256,7 +256,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
const FramebufferPass *key_pass_ptr = p_key.passes.ptr();
for (uint32_t i = 0; i < pass_size; i++) {
- { //compare color attachments
+ { // Compare color attachments.
uint32_t attachment_size = pass_ptr[i].color_attachments.size();
uint32_t key_attachment_size = key_pass_ptr[i].color_attachments.size();
if (attachment_size != key_attachment_size) {
@@ -271,7 +271,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
}
}
}
- { //compare input attachments
+ { // Compare input attachments.
uint32_t attachment_size = pass_ptr[i].input_attachments.size();
uint32_t key_attachment_size = key_pass_ptr[i].input_attachments.size();
if (attachment_size != key_attachment_size) {
@@ -286,7 +286,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
}
}
}
- { //compare resolve attachments
+ { // Compare resolve attachments.
uint32_t attachment_size = pass_ptr[i].resolve_attachments.size();
uint32_t key_attachment_size = key_pass_ptr[i].resolve_attachments.size();
if (attachment_size != key_attachment_size) {
@@ -301,7 +301,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
}
}
}
- { //compare preserve attachments
+ { // Compare preserve attachments.
uint32_t attachment_size = pass_ptr[i].preserve_attachments.size();
uint32_t key_attachment_size = key_pass_ptr[i].preserve_attachments.size();
if (attachment_size != key_attachment_size) {
@@ -343,7 +343,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
}
}
- return false; //equal
+ return false; // Equal.
}
};
@@ -353,9 +353,9 @@ class RenderingDeviceVulkan : public RenderingDevice {
RBMap<FramebufferFormatKey, FramebufferFormatID> framebuffer_format_cache;
struct FramebufferFormat {
const RBMap<FramebufferFormatKey, FramebufferFormatID>::Element *E;
- VkRenderPass render_pass = VK_NULL_HANDLE; //here for constructing shaders, never used, see section (7.2. Render Pass Compatibility from Vulkan spec)
+ VkRenderPass render_pass = VK_NULL_HANDLE; // Here for constructing shaders, never used, see section (7.2. Render Pass Compatibility from Vulkan spec).
Vector<TextureSamples> pass_samples;
- uint32_t view_count = 1; // number of views
+ uint32_t view_count = 1; // Number of views.
};
HashMap<FramebufferFormatID, FramebufferFormat> framebuffer_formats;
@@ -392,10 +392,12 @@ class RenderingDeviceVulkan : public RenderingDevice {
uint32_t storage_mask = 0;
Vector<RID> texture_ids;
+ InvalidationCallback invalidated_callback = nullptr;
+ void *invalidated_callback_userdata = nullptr;
struct Version {
VkFramebuffer framebuffer = VK_NULL_HANDLE;
- VkRenderPass render_pass = VK_NULL_HANDLE; //this one is owned
+ VkRenderPass render_pass = VK_NULL_HANDLE; // This one is owned.
uint32_t subpass_count = 1;
};
@@ -452,7 +454,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
return false;
}
}
- return true; //they are equal
+ return true; // They are equal.
}
}
@@ -497,14 +499,14 @@ class RenderingDeviceVulkan : public RenderingDevice {
int vertex_count = 0;
uint32_t max_instances_allowed = 0;
- Vector<VkBuffer> buffers; //not owned, just referenced
+ Vector<VkBuffer> buffers; // Not owned, just referenced.
Vector<VkDeviceSize> offsets;
};
RID_Owner<VertexArray, true> vertex_array_owner;
struct IndexBuffer : public Buffer {
- uint32_t max_index = 0; //used for validation
+ uint32_t max_index = 0; // Used for validation.
uint32_t index_count = 0;
VkIndexType index_type = VK_INDEX_TYPE_NONE_NV;
bool supports_restart_indices = false;
@@ -513,8 +515,8 @@ class RenderingDeviceVulkan : public RenderingDevice {
RID_Owner<IndexBuffer, true> index_buffer_owner;
struct IndexArray {
- uint32_t max_index = 0; //remember the maximum index here too, for validation
- VkBuffer buffer; //not owned, inherited from index buffer
+ uint32_t max_index = 0; // Remember the maximum index here too, for validation.
+ VkBuffer buffer; // Not owned, inherited from index buffer.
uint32_t offset = 0;
uint32_t indices = 0;
VkIndexType index_type = VK_INDEX_TYPE_NONE_NV;
@@ -548,7 +550,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
bool writable = false;
int binding = 0;
uint32_t stages = 0;
- int length = 0; //size of arrays (in total elements), or ubos (in bytes * total elements)
+ int length = 0; // Size of arrays (in total elements), or ubos (in bytes * total elements).
bool operator!=(const UniformInfo &p_info) const {
return (binding != p_info.binding || type != p_info.type || writable != p_info.writable || stages != p_info.stages || length != p_info.length);
@@ -620,7 +622,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
VkDescriptorSetLayout descriptor_set_layout = VK_NULL_HANDLE;
};
- uint32_t vertex_input_mask = 0; //inputs used, this is mostly for validation
+ uint32_t vertex_input_mask = 0; // Inputs used, this is mostly for validation.
uint32_t fragment_output_mask = 0;
struct PushConstant {
@@ -643,7 +645,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
Vector<VkPipelineShaderStageCreateInfo> pipeline_stages;
Vector<SpecializationConstant> specialization_constants;
VkPipelineLayout pipeline_layout = VK_NULL_HANDLE;
- String name; //used for debug
+ String name; // Used for debug.
};
String _shader_uniform_debug(RID p_shader, int p_set = -1);
@@ -715,7 +717,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
RID_Owner<Buffer, true> uniform_buffer_owner;
RID_Owner<Buffer, true> storage_buffer_owner;
- //texture buffer needs a view
+ // Texture buffer needs a view.
struct TextureBuffer {
Buffer buffer;
VkBufferView view = VK_NULL_HANDLE;
@@ -738,16 +740,16 @@ class RenderingDeviceVulkan : public RenderingDevice {
DescriptorPool *pool = nullptr;
DescriptorPoolKey pool_key;
VkDescriptorSet descriptor_set = VK_NULL_HANDLE;
- //VkPipelineLayout pipeline_layout; //not owned, inherited from shader
+ //VkPipelineLayout pipeline_layout; // Not owned, inherited from shader.
struct AttachableTexture {
uint32_t bind;
RID texture;
};
- LocalVector<AttachableTexture> attachable_textures; //used for validation
- Vector<Texture *> mutable_sampled_textures; //used for layout change
- Vector<Texture *> mutable_storage_textures; //used for layout change
- UniformSetInvalidatedCallback invalidated_callback = nullptr;
+ LocalVector<AttachableTexture> attachable_textures; // Used for validation.
+ Vector<Texture *> mutable_sampled_textures; // Used for layout change.
+ Vector<Texture *> mutable_storage_textures; // Used for layout change.
+ InvalidationCallback invalidated_callback = nullptr;
void *invalidated_callback_userdata = nullptr;
};
@@ -769,7 +771,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
// was not supplied as intended.
struct RenderPipeline {
- //Cached values for validation
+ // Cached values for validation.
#ifdef DEBUG_ENABLED
struct Validation {
FramebufferFormatID framebuffer_format = 0;
@@ -781,10 +783,10 @@ class RenderingDeviceVulkan : public RenderingDevice {
uint32_t primitive_divisor = 0;
} validation;
#endif
- //Actual pipeline
+ // Actual pipeline.
RID shader;
Vector<uint32_t> set_formats;
- VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; // not owned, needed for push constants
+ VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; // Not owned, needed for push constants.
VkPipeline pipeline = VK_NULL_HANDLE;
uint32_t push_constant_size = 0;
uint32_t push_constant_stages = 0;
@@ -795,7 +797,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
struct ComputePipeline {
RID shader;
Vector<uint32_t> set_formats;
- VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; // not owned, needed for push constants
+ VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; // Not owned, needed for push constants.
VkPipeline pipeline = VK_NULL_HANDLE;
uint32_t push_constant_size = 0;
uint32_t push_constant_stages = 0;
@@ -821,7 +823,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
struct SplitDrawListAllocator {
VkCommandPool command_pool = VK_NULL_HANDLE;
- Vector<VkCommandBuffer> command_buffers; //one for each frame
+ Vector<VkCommandBuffer> command_buffers; // One for each frame.
};
Vector<SplitDrawListAllocator> split_draw_list_allocators;
@@ -973,7 +975,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
// when the frame is cycled.
struct Frame {
- //list in usage order, from last to free to first to free
+ // List in usage order, from last to free to first to free.
List<Buffer> buffers_to_dispose_of;
List<Texture> textures_to_dispose_of;
List<Framebuffer> framebuffers_to_dispose_of;
@@ -985,8 +987,8 @@ class RenderingDeviceVulkan : public RenderingDevice {
List<ComputePipeline> compute_pipelines_to_dispose_of;
VkCommandPool command_pool = VK_NULL_HANDLE;
- VkCommandBuffer setup_command_buffer = VK_NULL_HANDLE; //used at the beginning of every frame for set-up
- VkCommandBuffer draw_command_buffer = VK_NULL_HANDLE; //used at the beginning of every frame for set-up
+ VkCommandBuffer setup_command_buffer = VK_NULL_HANDLE; // Used at the beginning of every frame for set-up.
+ VkCommandBuffer draw_command_buffer = VK_NULL_HANDLE; // Used at the beginning of every frame for set-up.
struct Timestamp {
String description;
@@ -1007,9 +1009,9 @@ class RenderingDeviceVulkan : public RenderingDevice {
uint32_t max_timestamp_query_elements = 0;
- TightLocalVector<Frame> frames; //frames available, for main device they are cycled (usually 3), for local devices only 1
- int frame = 0; //current frame
- int frame_count = 0; //total amount of frames
+ TightLocalVector<Frame> frames; // Frames available, for main device they are cycled (usually 3), for local devices only 1.
+ int frame = 0; // Current frame.
+ int frame_count = 0; // Total amount of frames.
uint64_t frames_drawn = 0;
RID local_device;
bool local_device_processing = false;
@@ -1036,6 +1038,10 @@ class RenderingDeviceVulkan : public RenderingDevice {
void _finalize_command_bufers();
void _begin_frame();
+#ifdef DEV_ENABLED
+ HashMap<RID, String> resource_names;
+#endif
+
public:
virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t>> &p_data = Vector<Vector<uint8_t>>());
virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture);
@@ -1059,13 +1065,15 @@ public:
/*********************/
virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format, uint32_t p_view_count = 1);
- virtual FramebufferFormatID framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, Vector<FramebufferPass> &p_passes, uint32_t p_view_count = 1);
+ virtual FramebufferFormatID framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, uint32_t p_view_count = 1);
virtual FramebufferFormatID framebuffer_format_create_empty(TextureSamples p_samples = TEXTURE_SAMPLES_1);
virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format, uint32_t p_pass = 0);
virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1);
- virtual RID framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1);
+ virtual RID framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, const Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1);
virtual RID framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples = TEXTURE_SAMPLES_1, FramebufferFormatID p_format_check = INVALID_ID);
+ virtual bool framebuffer_is_valid(RID p_framebuffer) const;
+ virtual void framebuffer_set_invalidation_callback(RID p_framebuffer, InvalidationCallback p_callback, void *p_userdata);
virtual FramebufferFormatID framebuffer_get_format(RID p_framebuffer);
@@ -1081,7 +1089,7 @@ public:
virtual RID vertex_buffer_create(uint32_t p_size_bytes, const Vector<uint8_t> &p_data = Vector<uint8_t>(), bool p_use_as_storage = false);
- // Internally reference counted, this ID is warranted to be unique for the same description, but needs to be freed as many times as it was allocated
+ // Internally reference counted, this ID is warranted to be unique for the same description, but needs to be freed as many times as it was allocated.
virtual VertexFormatID vertex_format_create(const Vector<VertexAttribute> &p_vertex_formats);
virtual RID vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const Vector<RID> &p_src_buffers);
@@ -1110,9 +1118,9 @@ public:
virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set);
virtual bool uniform_set_is_valid(RID p_uniform_set);
- virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, UniformSetInvalidatedCallback p_callback, void *p_userdata);
+ virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, InvalidationCallback p_callback, void *p_userdata);
- virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL); //works for any buffer
+ virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL); // Works for any buffer.
virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, uint32_t p_post_barrier = BARRIER_MASK_ALL);
virtual Vector<uint8_t> buffer_get_data(RID p_buffer);
@@ -1147,6 +1155,7 @@ public:
virtual DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>());
virtual Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>());
+ virtual void draw_list_set_blend_constants(DrawListID p_list, const Color &p_color);
virtual void draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline);
virtual void draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index);
virtual void draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array);
@@ -1210,10 +1219,10 @@ public:
void initialize(VulkanContext *p_context, bool p_local_device = false);
void finalize();
- virtual void swap_buffers(); //for main device
+ virtual void swap_buffers(); // For main device.
- virtual void submit(); //for local device
- virtual void sync(); //for local device
+ virtual void submit(); // For local device.
+ virtual void sync(); // For local device.
virtual uint32_t get_frame_delay() const;
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index 0d8a3310fd..b52179b4f3 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -237,7 +237,7 @@ Error VulkanContext::_get_preferred_validation_layers(uint32_t *count, const cha
{ "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", "VK_LAYER_LUNARG_object_tracker", "VK_LAYER_LUNARG_core_validation", "VK_LAYER_GOOGLE_unique_objects" }
};
- // Clear out-arguments
+ // Clear out-arguments.
*count = 0;
if (names != nullptr) {
*names = nullptr;
@@ -441,7 +441,7 @@ String VulkanContext::SubgroupCapabilities::supported_stages_desc() const {
res += ", STAGE_MESH_NV";
}
- return res.substr(2); // Remove first ", "
+ return res.substr(2); // Remove first ", ".
}
uint32_t VulkanContext::SubgroupCapabilities::supported_operations_flags_rd() const {
@@ -506,7 +506,7 @@ String VulkanContext::SubgroupCapabilities::supported_operations_desc() const {
res += ", FEATURE_PARTITIONED_NV";
}
- return res.substr(2); // Remove first ", "
+ return res.substr(2); // Remove first ", ".
}
Error VulkanContext::_check_capabilities() {
@@ -641,8 +641,8 @@ Error VulkanContext::_check_capabilities() {
subgroup_capabilities.supportedStages = subgroupProperties.supportedStages;
subgroup_capabilities.supportedOperations = subgroupProperties.supportedOperations;
// Note: quadOperationsInAllStages will be true if:
- // - supportedStages has VK_SHADER_STAGE_ALL_GRAPHICS + VK_SHADER_STAGE_COMPUTE_BIT
- // - supportedOperations has VK_SUBGROUP_FEATURE_QUAD_BIT
+ // - supportedStages has VK_SHADER_STAGE_ALL_GRAPHICS + VK_SHADER_STAGE_COMPUTE_BIT.
+ // - supportedOperations has VK_SUBGROUP_FEATURE_QUAD_BIT.
subgroup_capabilities.quadOperationsInAllStages = subgroupProperties.quadOperationsInAllStages;
if (vrs_capabilities.pipeline_vrs_supported || vrs_capabilities.primitive_vrs_supported || vrs_capabilities.attachment_vrs_supported) {
@@ -654,7 +654,7 @@ Error VulkanContext::_check_capabilities() {
print_verbose(" Primitive fragment shading rate");
}
if (vrs_capabilities.attachment_vrs_supported) {
- // TODO expose these somehow to the end user
+ // TODO expose these somehow to the end user.
vrs_capabilities.min_texel_size.x = vrsProperties.minFragmentShadingRateAttachmentTexelSize.width;
vrs_capabilities.min_texel_size.y = vrsProperties.minFragmentShadingRateAttachmentTexelSize.height;
vrs_capabilities.max_texel_size.x = vrsProperties.maxFragmentShadingRateAttachmentTexelSize.width;
@@ -731,7 +731,7 @@ Error VulkanContext::_create_instance() {
VkDebugUtilsMessengerCreateInfoEXT dbg_messenger_create_info;
VkDebugReportCallbackCreateInfoEXT dbg_report_callback_create_info{};
if (enabled_debug_utils) {
- // VK_EXT_debug_utils style
+ // VK_EXT_debug_utils style.
dbg_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
dbg_messenger_create_info.pNext = nullptr;
dbg_messenger_create_info.flags = 0;
@@ -902,8 +902,8 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) {
}
} else {
// TODO: At least on Linux Laptops integrated GPUs fail with Vulkan in many instances.
- // The device should really be a preference, but for now choosing a discrete GPU over the
- // integrated one is better than the default.
+ // The device should really be a preference, but for now choosing a discrete GPU over the
+ // integrated one is better than the default.
int type_selected = -1;
print_verbose("Vulkan devices:");
@@ -1175,7 +1175,7 @@ Error VulkanContext::_create_device() {
VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs_features;
if (vrs_capabilities.pipeline_vrs_supported || vrs_capabilities.primitive_vrs_supported || vrs_capabilities.attachment_vrs_supported) {
- // insert into our chain to enable these features if they are available
+ // Insert into our chain to enable these features if they are available.
vrs_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR;
vrs_features.pNext = nextptr;
vrs_features.pipelineFragmentShadingRate = vrs_capabilities.pipeline_vrs_supported;
@@ -1436,6 +1436,24 @@ bool VulkanContext::_use_validation_layers() {
return Engine::get_singleton()->is_validation_layers_enabled();
}
+VkExtent2D VulkanContext::_compute_swapchain_extent(const VkSurfaceCapabilitiesKHR &p_surf_capabilities, int *p_window_width, int *p_window_height) const {
+ // Width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
+ if (p_surf_capabilities.currentExtent.width == 0xFFFFFFFF) {
+ // If the surface size is undefined, the size is set to the size
+ // of the images requested, which must fit within the minimum and
+ // maximum values.
+ VkExtent2D extent = {};
+ extent.width = CLAMP((uint32_t)(*p_window_width), p_surf_capabilities.minImageExtent.width, p_surf_capabilities.maxImageExtent.width);
+ extent.height = CLAMP((uint32_t)(*p_window_height), p_surf_capabilities.minImageExtent.height, p_surf_capabilities.maxImageExtent.height);
+ return extent;
+ } else {
+ // If the surface size is defined, the swap chain size must match.
+ *p_window_width = p_surf_capabilities.currentExtent.width;
+ *p_window_height = p_surf_capabilities.currentExtent.height;
+ return p_surf_capabilities.currentExtent;
+ }
+}
+
Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, VkSurfaceKHR p_surface, int p_width, int p_height) {
ERR_FAIL_COND_V(windows.has(p_window_id), ERR_INVALID_PARAMETER);
@@ -1576,32 +1594,7 @@ Error VulkanContext::_update_swap_chain(Window *window) {
ERR_FAIL_V(ERR_CANT_CREATE);
}
- VkExtent2D swapchainExtent;
- // Width and height are either both 0xFFFFFFFF, or both not 0xFFFFFFFF.
- if (surfCapabilities.currentExtent.width == 0xFFFFFFFF) {
- // If the surface size is undefined, the size is set to the size
- // of the images requested, which must fit within the minimum and
- // maximum values.
- swapchainExtent.width = window->width;
- swapchainExtent.height = window->height;
-
- if (swapchainExtent.width < surfCapabilities.minImageExtent.width) {
- swapchainExtent.width = surfCapabilities.minImageExtent.width;
- } else if (swapchainExtent.width > surfCapabilities.maxImageExtent.width) {
- swapchainExtent.width = surfCapabilities.maxImageExtent.width;
- }
-
- if (swapchainExtent.height < surfCapabilities.minImageExtent.height) {
- swapchainExtent.height = surfCapabilities.minImageExtent.height;
- } else if (swapchainExtent.height > surfCapabilities.maxImageExtent.height) {
- swapchainExtent.height = surfCapabilities.maxImageExtent.height;
- }
- } else {
- // If the surface size is defined, the swap chain size must match.
- swapchainExtent = surfCapabilities.currentExtent;
- window->width = surfCapabilities.currentExtent.width;
- window->height = surfCapabilities.currentExtent.height;
- }
+ VkExtent2D swapchainExtent = _compute_swapchain_extent(surfCapabilities, &window->width, &window->height);
if (window->width == 0 || window->height == 0) {
free(presentModes);
@@ -1611,17 +1604,17 @@ Error VulkanContext::_update_swap_chain(Window *window) {
// The FIFO present mode is guaranteed by the spec to be supported
// and to have no tearing. It's a great default present mode to use.
- // There are times when you may wish to use another present mode. The
- // following code shows how to select them, and the comments provide some
- // reasons you may wish to use them.
+ // There are times when you may wish to use another present mode. The
+ // following code shows how to select them, and the comments provide some
+ // reasons you may wish to use them.
//
// It should be noted that Vulkan 1.0 doesn't provide a method for
- // synchronizing rendering with the presentation engine's display. There
+ // synchronizing rendering with the presentation engine's display. There
// is a method provided for throttling rendering with the display, but
// there are some presentation engines for which this method will not work.
// If an application doesn't throttle its rendering, and if it renders much
// faster than the refresh rate of the display, this can waste power on
- // mobile devices. That is because power is being spent rendering images
+ // mobile devices. That is because power is being spent rendering images
// that may never be seen.
// VK_PRESENT_MODE_IMMEDIATE_KHR is for applications that don't care about
@@ -1666,7 +1659,22 @@ Error VulkanContext::_update_swap_chain(Window *window) {
if (present_mode_available) {
window->presentMode = requested_present_mode;
} else {
- WARN_PRINT("Requested VSync mode is not available!");
+ String present_mode_string;
+ switch (window->vsync_mode) {
+ case DisplayServer::VSYNC_MAILBOX:
+ present_mode_string = "Mailbox";
+ break;
+ case DisplayServer::VSYNC_ADAPTIVE:
+ present_mode_string = "Adaptive";
+ break;
+ case DisplayServer::VSYNC_ENABLED:
+ present_mode_string = "Enabled";
+ break;
+ case DisplayServer::VSYNC_DISABLED:
+ present_mode_string = "Disabled";
+ break;
+ }
+ WARN_PRINT(vformat("The requested V-Sync mode %s is not available. Falling back to V-Sync mode Enabled.", present_mode_string));
window->vsync_mode = DisplayServer::VSYNC_ENABLED; // Set to default.
}
@@ -1684,7 +1692,7 @@ Error VulkanContext::_update_swap_chain(Window *window) {
// If maxImageCount is 0, we can ask for as many images as we want;
// otherwise we're limited to maxImageCount.
if ((surfCapabilities.maxImageCount > 0) && (desiredNumOfSwapchainImages > surfCapabilities.maxImageCount)) {
- // Application must settle for fewer images than desired:
+ // Application must settle for fewer images than desired.
desiredNumOfSwapchainImages = surfCapabilities.maxImageCount;
}
@@ -2028,14 +2036,14 @@ Error VulkanContext::prepare_buffers() {
}
do {
- // Get the index of the next available swapchain image:
+ // Get the index of the next available swapchain image.
err =
fpAcquireNextImageKHR(device, w->swapchain, UINT64_MAX,
w->image_acquired_semaphores[frame_index], VK_NULL_HANDLE, &w->current_buffer);
if (err == VK_ERROR_OUT_OF_DATE_KHR) {
// Swapchain is out of date (e.g. the window was resized) and
- // must be recreated:
+ // must be recreated.
print_verbose("Vulkan: Early out of date swapchain, recreating.");
// resize_notify();
_update_swap_chain(w);
@@ -2068,7 +2076,7 @@ Error VulkanContext::swap_buffers() {
#if 0
if (VK_GOOGLE_display_timing_enabled) {
// Look at what happened to previous presents, and make appropriate
- // adjustments in timing:
+ // adjustments in timing.
DemoUpdateTargetIPD(demo);
// Note: a real application would position its geometry to that it's in
@@ -2231,7 +2239,7 @@ Error VulkanContext::swap_buffers() {
uint64_t curtime = getTimeInNanoseconds();
if (curtime == 0) {
// Since we didn't find out the current time, don't give a
- // desiredPresentTime:
+ // desiredPresentTime.
ptime.desiredPresentTime = 0;
} else {
ptime.desiredPresentTime = curtime + (target_IPD >> 1);
@@ -2263,7 +2271,7 @@ Error VulkanContext::swap_buffers() {
if (err == VK_ERROR_OUT_OF_DATE_KHR) {
// Swapchain is out of date (e.g. the window was resized) and
- // must be recreated:
+ // must be recreated.
print_verbose("Vulkan: Swapchain is out of date, recreating.");
resize_notify();
} else if (err == VK_SUBOPTIMAL_KHR) {
@@ -2471,12 +2479,12 @@ String VulkanContext::get_device_pipeline_cache_uuid() const {
}
DisplayServer::VSyncMode VulkanContext::get_vsync_mode(DisplayServer::WindowID p_window) const {
- ERR_FAIL_COND_V_MSG(!windows.has(p_window), DisplayServer::VSYNC_ENABLED, "Could not get VSync mode for window with WindowID " + itos(p_window) + " because it does not exist.");
+ ERR_FAIL_COND_V_MSG(!windows.has(p_window), DisplayServer::VSYNC_ENABLED, "Could not get V-Sync mode for window with WindowID " + itos(p_window) + " because it does not exist.");
return windows[p_window].vsync_mode;
}
void VulkanContext::set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode) {
- ERR_FAIL_COND_MSG(!windows.has(p_window), "Could not set VSync mode for window with WindowID " + itos(p_window) + " because it does not exist.");
+ ERR_FAIL_COND_MSG(!windows.has(p_window), "Could not set V-Sync mode for window with WindowID " + itos(p_window) + " because it does not exist.");
windows[p_window].vsync_mode = p_mode;
_update_swap_chain(&windows[p_window]);
}
diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h
index 35e7ce7db8..9889cf336b 100644
--- a/drivers/vulkan/vulkan_context.h
+++ b/drivers/vulkan/vulkan_context.h
@@ -70,9 +70,9 @@ public:
};
struct VRSCapabilities {
- bool pipeline_vrs_supported; // We can specify our fragment rate on a pipeline level
- bool primitive_vrs_supported; // We can specify our fragment rate on each drawcall
- bool attachment_vrs_supported; // We can provide a density map attachment on our framebuffer
+ bool pipeline_vrs_supported; // We can specify our fragment rate on a pipeline level.
+ bool primitive_vrs_supported; // We can specify our fragment rate on each drawcall.
+ bool attachment_vrs_supported; // We can provide a density map attachment on our framebuffer.
Size2i min_texel_size;
Size2i max_texel_size;
@@ -107,7 +107,7 @@ private:
bool device_initialized = false;
bool inst_initialized = false;
- // Vulkan 1.0 doesn't return version info so we assume this by default until we know otherwise
+ // Vulkan 1.0 doesn't return version info so we assume this by default until we know otherwise.
uint32_t vulkan_major = 1;
uint32_t vulkan_minor = 0;
uint32_t vulkan_patch = 0;
@@ -266,8 +266,10 @@ protected:
Error _get_preferred_validation_layers(uint32_t *count, const char *const **names);
+ virtual VkExtent2D _compute_swapchain_extent(const VkSurfaceCapabilitiesKHR &p_surf_capabilities, int *p_window_width, int *p_window_height) const;
+
public:
- // Extension calls
+ // Extension calls.
VkResult vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass);
uint32_t get_vulkan_major() const { return vulkan_major; };
diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp
index 3a62850339..fb90b776cf 100644
--- a/drivers/wasapi/audio_driver_wasapi.cpp
+++ b/drivers/wasapi/audio_driver_wasapi.cpp
@@ -501,11 +501,11 @@ Error AudioDriverWASAPI::init_capture_device(bool reinit) {
}
Error AudioDriverWASAPI::audio_device_finish(AudioDeviceWASAPI *p_device) {
- if (p_device->active) {
+ if (p_device->active.is_set()) {
if (p_device->audio_client) {
p_device->audio_client->Stop();
}
- p_device->active = false;
+ p_device->active.clear();
}
SAFE_RELEASE(p_device->audio_client)
@@ -533,8 +533,7 @@ Error AudioDriverWASAPI::init() {
ERR_PRINT("WASAPI: init_render_device error");
}
- exit_thread = false;
- thread_exited = false;
+ exit_thread.clear();
thread.start(thread_func, this);
@@ -553,8 +552,8 @@ AudioDriver::SpeakerMode AudioDriverWASAPI::get_speaker_mode() const {
return get_speaker_mode_by_total_channels(channels);
}
-Array AudioDriverWASAPI::audio_device_get_list(bool p_capture) {
- Array list;
+PackedStringArray AudioDriverWASAPI::audio_device_get_list(bool p_capture) {
+ PackedStringArray list;
IMMDeviceCollection *devices = nullptr;
IMMDeviceEnumerator *enumerator = nullptr;
@@ -563,14 +562,14 @@ Array AudioDriverWASAPI::audio_device_get_list(bool p_capture) {
CoInitialize(nullptr);
HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator);
- ERR_FAIL_COND_V(hr != S_OK, Array());
+ ERR_FAIL_COND_V(hr != S_OK, PackedStringArray());
hr = enumerator->EnumAudioEndpoints(p_capture ? eCapture : eRender, DEVICE_STATE_ACTIVE, &devices);
- ERR_FAIL_COND_V(hr != S_OK, Array());
+ ERR_FAIL_COND_V(hr != S_OK, PackedStringArray());
UINT count = 0;
hr = devices->GetCount(&count);
- ERR_FAIL_COND_V(hr != S_OK, Array());
+ ERR_FAIL_COND_V(hr != S_OK, PackedStringArray());
for (ULONG i = 0; i < count; i++) {
IMMDevice *device = nullptr;
@@ -600,7 +599,7 @@ Array AudioDriverWASAPI::audio_device_get_list(bool p_capture) {
return list;
}
-Array AudioDriverWASAPI::get_device_list() {
+PackedStringArray AudioDriverWASAPI::get_device_list() {
return audio_device_get_list(false);
}
@@ -684,7 +683,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) {
uint32_t avail_frames = 0;
uint32_t write_ofs = 0;
- while (!ad->exit_thread) {
+ while (!ad->exit_thread.is_set()) {
uint32_t read_frames = 0;
uint32_t written_frames = 0;
@@ -692,7 +691,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) {
ad->lock();
ad->start_counting_ticks();
- if (ad->audio_output.active) {
+ if (ad->audio_output.active.is_set()) {
ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw());
} else {
for (int i = 0; i < ad->samples_in.size(); i++) {
@@ -758,7 +757,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) {
}
} else {
ERR_PRINT("WASAPI: Get buffer error");
- ad->exit_thread = true;
+ ad->exit_thread.set();
}
}
} else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) {
@@ -807,7 +806,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) {
write_ofs = 0;
}
- if (ad->audio_input.active) {
+ if (ad->audio_input.active.is_set()) {
UINT32 packet_length = 0;
BYTE *data;
UINT32 num_frames_available;
@@ -886,8 +885,6 @@ void AudioDriverWASAPI::thread_func(void *p_udata) {
OS::get_singleton()->delay_usec(1000);
}
}
-
- ad->thread_exited = true;
}
void AudioDriverWASAPI::start() {
@@ -896,7 +893,7 @@ void AudioDriverWASAPI::start() {
if (hr != S_OK) {
ERR_PRINT("WASAPI: Start failed");
} else {
- audio_output.active = true;
+ audio_output.active.set();
}
}
}
@@ -910,7 +907,7 @@ void AudioDriverWASAPI::unlock() {
}
void AudioDriverWASAPI::finish() {
- exit_thread = true;
+ exit_thread.set();
thread.wait_to_finish();
finish_capture_device();
@@ -924,19 +921,19 @@ Error AudioDriverWASAPI::capture_start() {
return err;
}
- if (audio_input.active) {
+ if (audio_input.active.is_set()) {
return FAILED;
}
audio_input.audio_client->Start();
- audio_input.active = true;
+ audio_input.active.set();
return OK;
}
Error AudioDriverWASAPI::capture_stop() {
- if (audio_input.active) {
+ if (audio_input.active.is_set()) {
audio_input.audio_client->Stop();
- audio_input.active = false;
+ audio_input.active.clear();
return OK;
}
@@ -950,7 +947,7 @@ void AudioDriverWASAPI::capture_set_device(const String &p_name) {
unlock();
}
-Array AudioDriverWASAPI::capture_get_device_list() {
+PackedStringArray AudioDriverWASAPI::capture_get_device_list() {
return audio_device_get_list(true);
}
diff --git a/drivers/wasapi/audio_driver_wasapi.h b/drivers/wasapi/audio_driver_wasapi.h
index 9058077a1f..c30a54c042 100644
--- a/drivers/wasapi/audio_driver_wasapi.h
+++ b/drivers/wasapi/audio_driver_wasapi.h
@@ -35,6 +35,7 @@
#include "core/os/mutex.h"
#include "core/os/thread.h"
+#include "core/templates/safe_refcount.h"
#include "servers/audio_server.h"
#include <audioclient.h>
@@ -48,7 +49,7 @@ class AudioDriverWASAPI : public AudioDriver {
IAudioClient *audio_client = nullptr;
IAudioRenderClient *render_client = nullptr;
IAudioCaptureClient *capture_client = nullptr;
- bool active = false;
+ SafeFlag active;
WORD format_tag = 0;
WORD bits_per_sample = 0;
@@ -76,8 +77,7 @@ class AudioDriverWASAPI : public AudioDriver {
float real_latency = 0.0;
bool using_audio_client_3 = false;
- bool thread_exited = false;
- mutable bool exit_thread = false;
+ SafeFlag exit_thread;
static _FORCE_INLINE_ void write_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i, int32_t sample);
static _FORCE_INLINE_ int32_t read_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i);
@@ -91,7 +91,7 @@ class AudioDriverWASAPI : public AudioDriver {
Error audio_device_init(AudioDeviceWASAPI *p_device, bool p_capture, bool reinit);
Error audio_device_finish(AudioDeviceWASAPI *p_device);
- Array audio_device_get_list(bool p_capture);
+ PackedStringArray audio_device_get_list(bool p_capture);
public:
virtual const char *get_name() const {
@@ -103,7 +103,7 @@ public:
virtual int get_mix_rate() const;
virtual float get_latency();
virtual SpeakerMode get_speaker_mode() const;
- virtual Array get_device_list();
+ virtual PackedStringArray get_device_list();
virtual String get_device();
virtual void set_device(String device);
virtual void lock();
@@ -112,7 +112,7 @@ public:
virtual Error capture_start();
virtual Error capture_stop();
- virtual Array capture_get_device_list();
+ virtual PackedStringArray capture_get_device_list();
virtual void capture_set_device(const String &p_name);
virtual String capture_get_device();
diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp
index 881575d245..11fd29c8f5 100644
--- a/drivers/windows/dir_access_windows.cpp
+++ b/drivers/windows/dir_access_windows.cpp
@@ -157,7 +157,7 @@ Error DirAccessWindows::make_dir(String p_dir) {
p_dir = fix_path(p_dir);
if (p_dir.is_relative_path()) {
- p_dir = current_dir.plus_file(p_dir);
+ p_dir = current_dir.path_join(p_dir);
}
p_dir = p_dir.replace("/", "\\");
@@ -213,7 +213,7 @@ bool DirAccessWindows::file_exists(String p_file) {
GLOBAL_LOCK_FUNCTION
if (!p_file.is_absolute_path()) {
- p_file = get_current_dir().plus_file(p_file);
+ p_file = get_current_dir().path_join(p_file);
}
p_file = fix_path(p_file);
@@ -232,7 +232,7 @@ bool DirAccessWindows::dir_exists(String p_dir) {
GLOBAL_LOCK_FUNCTION
if (p_dir.is_relative_path()) {
- p_dir = get_current_dir().plus_file(p_dir);
+ p_dir = get_current_dir().path_join(p_dir);
}
p_dir = fix_path(p_dir);
@@ -247,13 +247,13 @@ bool DirAccessWindows::dir_exists(String p_dir) {
Error DirAccessWindows::rename(String p_path, String p_new_path) {
if (p_path.is_relative_path()) {
- p_path = get_current_dir().plus_file(p_path);
+ p_path = get_current_dir().path_join(p_path);
}
p_path = fix_path(p_path);
if (p_new_path.is_relative_path()) {
- p_new_path = get_current_dir().plus_file(p_new_path);
+ p_new_path = get_current_dir().path_join(p_new_path);
}
p_new_path = fix_path(p_new_path);
@@ -291,7 +291,7 @@ Error DirAccessWindows::rename(String p_path, String p_new_path) {
Error DirAccessWindows::remove(String p_path) {
if (p_path.is_relative_path()) {
- p_path = get_current_dir().plus_file(p_path);
+ p_path = get_current_dir().path_join(p_path);
}
p_path = fix_path(p_path);
@@ -402,6 +402,8 @@ DirAccessWindows::DirAccessWindows() {
}
DirAccessWindows::~DirAccessWindows() {
+ list_dir_end();
+
memdelete(p);
}
diff --git a/drivers/windows/dir_access_windows.h b/drivers/windows/dir_access_windows.h
index fbb07ddef8..c2835b3347 100644
--- a/drivers/windows/dir_access_windows.h
+++ b/drivers/windows/dir_access_windows.h
@@ -54,33 +54,33 @@ class DirAccessWindows : public DirAccess {
bool _cishidden = false;
public:
- virtual Error list_dir_begin(); ///< This starts dir listing
- virtual String get_next();
- virtual bool current_is_dir() const;
- virtual bool current_is_hidden() const;
- virtual void list_dir_end(); ///<
+ virtual Error list_dir_begin() override; ///< This starts dir listing
+ virtual String get_next() override;
+ virtual bool current_is_dir() const override;
+ virtual bool current_is_hidden() const override;
+ virtual void list_dir_end() override; ///<
- virtual int get_drive_count();
- virtual String get_drive(int p_drive);
+ virtual int get_drive_count() override;
+ virtual String get_drive(int p_drive) override;
- virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success
- virtual String get_current_dir(bool p_include_drive = true) const; ///< return current dir location
+ virtual Error change_dir(String p_dir) override; ///< can be relative or absolute, return false on success
+ virtual String get_current_dir(bool p_include_drive = true) const override; ///< return current dir location
- virtual bool file_exists(String p_file);
- virtual bool dir_exists(String p_dir);
+ virtual bool file_exists(String p_file) override;
+ virtual bool dir_exists(String p_dir) override;
- virtual Error make_dir(String p_dir);
+ virtual Error make_dir(String p_dir) override;
- virtual Error rename(String p_path, String p_new_path);
- virtual Error remove(String p_path);
+ virtual Error rename(String p_path, String p_new_path) override;
+ virtual Error remove(String p_path) override;
- virtual bool is_link(String p_file) { return false; };
- virtual String read_link(String p_file) { return p_file; };
- virtual Error create_link(String p_source, String p_target) { return FAILED; };
+ virtual bool is_link(String p_file) override { return false; };
+ virtual String read_link(String p_file) override { return p_file; };
+ virtual Error create_link(String p_source, String p_target) override { return FAILED; };
- uint64_t get_space_left();
+ uint64_t get_space_left() override;
- virtual String get_filesystem_type() const;
+ virtual String get_filesystem_type() const override;
DirAccessWindows();
~DirAccessWindows();
diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h
index 5d67b6ca4f..8629bb936b 100644
--- a/drivers/windows/file_access_windows.h
+++ b/drivers/windows/file_access_windows.h
@@ -51,33 +51,33 @@ class FileAccessWindows : public FileAccess {
void _close();
public:
- virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file
- virtual bool is_open() const; ///< true when file is open
+ virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
+ virtual bool is_open() const override; ///< true when file is open
- virtual String get_path() const; /// returns the path for the current open file
- virtual String get_path_absolute() const; /// returns the absolute path for the current open file
+ virtual String get_path() const override; /// returns the path for the current open file
+ virtual String get_path_absolute() const override; /// returns the absolute path for the current open file
- virtual void seek(uint64_t p_position); ///< seek to a given position
- virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual uint64_t get_position() const; ///< get position in the file
- virtual uint64_t get_length() const; ///< get size of the file
+ virtual void seek(uint64_t p_position) override; ///< seek to a given position
+ virtual void seek_end(int64_t p_position = 0) override; ///< seek from the end of file
+ virtual uint64_t get_position() const override; ///< get position in the file
+ virtual uint64_t get_length() const override; ///< get size of the file
- virtual bool eof_reached() const; ///< reading passed EOF
+ virtual bool eof_reached() const override; ///< reading passed EOF
- virtual uint8_t get_8() const; ///< get a byte
- virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
+ virtual uint8_t get_8() const override; ///< get a byte
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
- virtual Error get_error() const; ///< get last error
+ virtual Error get_error() const override; ///< get last error
- virtual void flush();
- virtual void store_8(uint8_t p_dest); ///< store a byte
- virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
+ virtual void flush() override;
+ virtual void store_8(uint8_t p_dest) override; ///< store a byte
+ virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes
- virtual bool file_exists(const String &p_name); ///< return true if a file exists
+ virtual bool file_exists(const String &p_name) override; ///< return true if a file exists
- uint64_t _get_modified_time(const String &p_file);
- virtual uint32_t _get_unix_permissions(const String &p_file);
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions);
+ uint64_t _get_modified_time(const String &p_file) override;
+ virtual uint32_t _get_unix_permissions(const String &p_file) override;
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override;
FileAccessWindows() {}
virtual ~FileAccessWindows();
diff --git a/drivers/xaudio2/audio_driver_xaudio2.cpp b/drivers/xaudio2/audio_driver_xaudio2.cpp
index c32c7cf1e5..6c48c1a844 100644
--- a/drivers/xaudio2/audio_driver_xaudio2.cpp
+++ b/drivers/xaudio2/audio_driver_xaudio2.cpp
@@ -38,9 +38,8 @@ const char *AudioDriverXAudio2::get_name() const {
}
Error AudioDriverXAudio2::init() {
- active = false;
- thread_exited = false;
- exit_thread = false;
+ active.clear();
+ exit_thread.clear();
pcm_open = false;
samples_in = nullptr;
@@ -86,17 +85,19 @@ Error AudioDriverXAudio2::init() {
void AudioDriverXAudio2::thread_func(void *p_udata) {
AudioDriverXAudio2 *ad = static_cast<AudioDriverXAudio2 *>(p_udata);
- while (!ad->exit_thread) {
- if (!ad->active) {
+ while (!ad->exit_thread.is_set()) {
+ if (!ad->active.is_set()) {
for (int i = 0; i < AUDIO_BUFFERS; i++) {
ad->xaudio_buffer[i].Flags = XAUDIO2_END_OF_STREAM;
}
} else {
ad->lock();
+ ad->start_counting_ticks();
ad->audio_server_process(ad->buffer_size, ad->samples_in);
+ ad->stop_counting_ticks();
ad->unlock();
for (unsigned int i = 0; i < ad->buffer_size * ad->channels; i++) {
@@ -117,12 +118,10 @@ void AudioDriverXAudio2::thread_func(void *p_udata) {
}
}
}
-
- ad->thread_exited = true;
}
void AudioDriverXAudio2::start() {
- active = true;
+ active.set();
HRESULT hr = source_voice->Start(0);
ERR_FAIL_COND_MSG(hr != S_OK, "Error starting XAudio2 driver. Error code: " + itos(hr) + ".");
}
@@ -154,7 +153,7 @@ void AudioDriverXAudio2::unlock() {
}
void AudioDriverXAudio2::finish() {
- exit_thread = true;
+ exit_thread.set();
thread.wait_to_finish();
if (source_voice) {
diff --git a/drivers/xaudio2/audio_driver_xaudio2.h b/drivers/xaudio2/audio_driver_xaudio2.h
index 81432ceb8e..0f64d54a1f 100644
--- a/drivers/xaudio2/audio_driver_xaudio2.h
+++ b/drivers/xaudio2/audio_driver_xaudio2.h
@@ -33,6 +33,7 @@
#include "core/os/mutex.h"
#include "core/os/thread.h"
+#include "core/templates/safe_refcount.h"
#include "servers/audio_server.h"
#include <mmsystem.h>
@@ -77,9 +78,8 @@ class AudioDriverXAudio2 : public AudioDriver {
int channels = 0;
- bool active = false;
- bool thread_exited = false;
- mutable bool exit_thread = false;
+ SafeFlag active;
+ SafeFlag exit_thread;
bool pcm_open = false;
WAVEFORMATEX wave_format = { 0 };
diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp
index 462f314471..7cfedffcbf 100644
--- a/editor/action_map_editor.cpp
+++ b/editor/action_map_editor.cpp
@@ -732,9 +732,9 @@ InputEventConfigurationDialog::InputEventConfigurationDialog() {
store_command_checkbox->set_pressed(true);
store_command_checkbox->set_text(TTR("Store Command"));
#ifdef APPLE_STYLE_KEYS
- store_command_checkbox->set_tooltip(TTR("Toggles between serializing 'command' and 'meta'. Used for compatibility with Windows/Linux style keyboard."));
+ store_command_checkbox->set_tooltip_text(TTR("Toggles between serializing 'command' and 'meta'. Used for compatibility with Windows/Linux style keyboard."));
#else
- store_command_checkbox->set_tooltip(TTR("Toggles between serializing 'command' and 'control'. Used for compatibility with Apple Style keyboards."));
+ store_command_checkbox->set_tooltip_text(TTR("Toggles between serializing 'command' and 'control'. Used for compatibility with Apple Style keyboards."));
#endif
mod_container->add_child(store_command_checkbox);
@@ -745,7 +745,7 @@ InputEventConfigurationDialog::InputEventConfigurationDialog() {
physical_key_checkbox = memnew(CheckBox);
physical_key_checkbox->set_text(TTR("Use Physical Keycode"));
- physical_key_checkbox->set_tooltip(TTR("Stores the physical position of the key on the keyboard rather than the key's value. Used for compatibility with non-latin layouts.\nThis should generally be enabled for most game shortcuts, but not in non-game applications."));
+ physical_key_checkbox->set_tooltip_text(TTR("Stores the physical position of the key on the keyboard rather than the key's value. Used for compatibility with non-latin layouts.\nThis should generally be enabled for most game shortcuts, but not in non-game applications."));
physical_key_checkbox->connect("toggled", callable_mp(this, &InputEventConfigurationDialog::_physical_keycode_toggled));
physical_key_checkbox->hide();
additional_options_container->add_child(physical_key_checkbox);
@@ -805,7 +805,7 @@ String ActionMapEditor::_check_new_action_name(const String &p_name) {
void ActionMapEditor::_add_edit_text_changed(const String &p_name) {
String error = _check_new_action_name(p_name);
- add_button->set_tooltip(error);
+ add_button->set_tooltip_text(error);
add_button->set_disabled(!error.is_empty());
}
@@ -1061,6 +1061,9 @@ void ActionMapEditor::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
action_list_search->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
+ if (!actions_cache.is_empty()) {
+ update_action_list();
+ }
} break;
}
}
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp
index ab9afda803..9af8b907c4 100644
--- a/editor/animation_bezier_editor.cpp
+++ b/editor/animation_bezier_editor.cpp
@@ -32,6 +32,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/view_panner.h"
#include "scene/resources/text_line.h"
@@ -40,7 +41,7 @@
float AnimationBezierTrackEdit::_bezier_h_to_pixel(float p_h) {
float h = p_h;
h = (h - v_scroll) / v_zoom;
- h = (get_size().height / 2) - h;
+ h = (get_size().height / 2.0) - h;
return h;
}
@@ -51,10 +52,10 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
int right_limit = get_size().width;
//selection may have altered the order of keys
- RBMap<float, int> key_order;
+ RBMap<real_t, int> key_order;
for (int i = 0; i < animation->track_get_key_count(p_track); i++) {
- float ofs = animation->track_get_key_time(p_track, i);
+ real_t ofs = animation->track_get_key_time(p_track, i);
if (moving_selection && selection.has(IntPair(p_track, i))) {
ofs += moving_selection_offset.x;
}
@@ -62,7 +63,7 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
key_order[ofs] = i;
}
- for (RBMap<float, int>::Element *E = key_order.front(); E; E = E->next()) {
+ for (RBMap<real_t, int>::Element *E = key_order.front(); E; E = E->next()) {
int i = E->get();
if (!E->next()) {
@@ -74,7 +75,7 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
float offset = animation->track_get_key_time(p_track, i);
float height = animation->bezier_track_get_key_value(p_track, i);
Vector2 out_handle = animation->bezier_track_get_key_out_handle(p_track, i);
- if (p_track == moving_handle_track && moving_handle != 0 && moving_handle_key == i) {
+ if (p_track == moving_handle_track && (moving_handle == -1 || moving_handle == 1) && moving_handle_key == i) {
out_handle = moving_handle_right;
}
@@ -88,7 +89,7 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
float offset_n = animation->track_get_key_time(p_track, i_n);
float height_n = animation->bezier_track_get_key_value(p_track, i_n);
Vector2 in_handle = animation->bezier_track_get_key_in_handle(p_track, i_n);
- if (p_track == moving_handle_track && moving_handle != 0 && moving_handle_key == i_n) {
+ if (p_track == moving_handle_track && (moving_handle == -1 || moving_handle == 1) && moving_handle_key == i_n) {
in_handle = moving_handle_left;
}
@@ -138,7 +139,7 @@ void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
//narrow high and low as much as possible
for (int k = 0; k < iterations; k++) {
- float middle = (low + high) / 2;
+ float middle = (low + high) / 2.0;
Vector2 interp = start.bezier_interpolate(out_handle, in_handle, end, middle);
@@ -315,7 +316,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
int h = MAX(text_buf.get_size().y, icon->get_height());
- draw_texture(icon, Point2(ofs, vofs + int(h - icon->get_height()) / 2));
+ draw_texture(icon, Point2(ofs, vofs + int(h - icon->get_height()) / 2.0));
ofs += icon->get_width();
margin = icon->get_width();
@@ -328,6 +329,8 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
}
}
+ Color dc = get_theme_color(SNAME("disabled_font_color"), SNAME("Editor"));
+
Ref<Texture2D> remove = get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"));
float remove_hpos = limit - hsep - remove->get_width();
@@ -400,25 +403,29 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
Vector2 string_pos = Point2(margin, vofs);
text_buf.draw(get_canvas_item(), string_pos, cc);
- float icon_start_height = vofs + rect.size.y / 2;
- Rect2 remove_rect = Rect2(remove_hpos, icon_start_height - remove->get_height() / 2, remove->get_width(), remove->get_height());
- draw_texture(remove, remove_rect.position);
+ float icon_start_height = vofs + rect.size.y / 2.0;
+ Rect2 remove_rect = Rect2(remove_hpos, icon_start_height - remove->get_height() / 2.0, remove->get_width(), remove->get_height());
+ if (read_only) {
+ draw_texture(remove, remove_rect.position, dc);
+ } else {
+ draw_texture(remove, remove_rect.position);
+ }
- Rect2 lock_rect = Rect2(lock_hpos, icon_start_height - lock->get_height() / 2, lock->get_width(), lock->get_height());
+ Rect2 lock_rect = Rect2(lock_hpos, icon_start_height - lock->get_height() / 2.0, lock->get_width(), lock->get_height());
if (locked_tracks.has(current_track)) {
draw_texture(lock, lock_rect.position);
} else {
draw_texture(unlock, lock_rect.position);
}
- Rect2 visible_rect = Rect2(visibility_hpos, icon_start_height - visible->get_height() / 2, visible->get_width(), visible->get_height());
+ Rect2 visible_rect = Rect2(visibility_hpos, icon_start_height - visible->get_height() / 2.0, visible->get_width(), visible->get_height());
if (hidden_tracks.has(current_track)) {
draw_texture(hidden, visible_rect.position);
} else {
draw_texture(visible, visible_rect.position);
}
- Rect2 solo_rect = Rect2(solo_hpos, icon_start_height - solo->get_height() / 2, solo->get_width(), solo->get_height());
+ Rect2 solo_rect = Rect2(solo_hpos, icon_start_height - solo->get_height() / 2.0, solo->get_width(), solo->get_height());
draw_texture(solo, solo_rect.position);
RBMap<int, Rect2> track_icons;
@@ -449,7 +456,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
bool first = true;
int prev_iv = 0;
for (int i = font->get_height(font_size); i < get_size().height; i++) {
- float ofs = get_size().height / 2 - i;
+ float ofs = get_size().height / 2.0 - i;
ofs *= v_zoom;
ofs += v_scroll;
@@ -488,7 +495,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
Vector2 pos((offset - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value));
if (pos.x >= limit && pos.x <= right_limit) {
- draw_texture(point, pos - point->get_size() / 2, E.value);
+ draw_texture(point, pos - point->get_size() / 2.0, E.value);
}
}
}
@@ -540,14 +547,15 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
Vector2 pos((offset - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value));
Vector2 in_vec = animation->bezier_track_get_key_in_handle(i, j);
- if (moving_handle != 0 && moving_handle_track == i && moving_handle_key == j) {
+
+ if ((moving_handle == 1 || moving_handle == -1) && moving_handle_track == i && moving_handle_key == j) {
in_vec = moving_handle_left;
}
Vector2 pos_in(((offset + in_vec.x) - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value + in_vec.y));
Vector2 out_vec = animation->bezier_track_get_key_out_handle(i, j);
- if (moving_handle != 0 && moving_handle_track == i && moving_handle_key == j) {
+ if ((moving_handle == 1 || moving_handle == -1) && moving_handle_track == i && moving_handle_key == j) {
out_vec = moving_handle_right;
}
@@ -562,7 +570,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
ep.track = i;
ep.key = j;
if (pos.x >= limit && pos.x <= right_limit) {
- ep.point_rect.position = (pos - bezier_icon->get_size() / 2).floor();
+ ep.point_rect.position = (pos - bezier_icon->get_size() / 2.0).floor();
ep.point_rect.size = bezier_icon->get_size();
if (selection.has(IntPair(i, j))) {
draw_texture(selected_icon, ep.point_rect.position);
@@ -577,18 +585,22 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
}
ep.point_rect = ep.point_rect.grow(ep.point_rect.size.width * 0.5);
}
+ ep.point_rect = ep.point_rect.grow(ep.point_rect.size.width * 0.5);
+
if (i == selected_track || selection.has(IntPair(i, j))) {
- if (pos_in.x >= limit && pos_in.x <= right_limit) {
- ep.in_rect.position = (pos_in - bezier_handle_icon->get_size() / 2).floor();
- ep.in_rect.size = bezier_handle_icon->get_size();
- draw_texture(bezier_handle_icon, ep.in_rect.position);
- ep.in_rect = ep.in_rect.grow(ep.in_rect.size.width * 0.5);
- }
- if (pos_out.x >= limit && pos_out.x <= right_limit) {
- ep.out_rect.position = (pos_out - bezier_handle_icon->get_size() / 2).floor();
- ep.out_rect.size = bezier_handle_icon->get_size();
- draw_texture(bezier_handle_icon, ep.out_rect.position);
- ep.out_rect = ep.out_rect.grow(ep.out_rect.size.width * 0.5);
+ if (animation->bezier_track_get_key_handle_mode(i, j) != Animation::HANDLE_MODE_LINEAR) {
+ if (pos_in.x >= limit && pos_in.x <= right_limit) {
+ ep.in_rect.position = (pos_in - bezier_handle_icon->get_size() / 2.0).floor();
+ ep.in_rect.size = bezier_handle_icon->get_size();
+ draw_texture(bezier_handle_icon, ep.in_rect.position);
+ ep.in_rect = ep.in_rect.grow(ep.in_rect.size.width * 0.5);
+ }
+ if (pos_out.x >= limit && pos_out.x <= right_limit) {
+ ep.out_rect.position = (pos_out - bezier_handle_icon->get_size() / 2.0).floor();
+ ep.out_rect.size = bezier_handle_icon->get_size();
+ draw_texture(bezier_handle_icon, ep.out_rect.position);
+ ep.out_rect = ep.out_rect.grow(ep.out_rect.size.width * 0.5);
+ }
}
}
if (!locked_tracks.has(i)) {
@@ -632,8 +644,9 @@ Ref<Animation> AnimationBezierTrackEdit::get_animation() const {
return animation;
}
-void AnimationBezierTrackEdit::set_animation_and_track(const Ref<Animation> &p_animation, int p_track) {
+void AnimationBezierTrackEdit::set_animation_and_track(const Ref<Animation> &p_animation, int p_track, bool p_read_only) {
animation = p_animation;
+ read_only = p_read_only;
selected_track = p_track;
update();
}
@@ -642,7 +655,7 @@ Size2 AnimationBezierTrackEdit::get_minimum_size() const {
return Vector2(1, 1);
}
-void AnimationBezierTrackEdit::set_undo_redo(UndoRedo *p_undo_redo) {
+void AnimationBezierTrackEdit::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
undo_redo = p_undo_redo;
}
@@ -656,7 +669,6 @@ void AnimationBezierTrackEdit::set_editor(AnimationTrackEditor *p_editor) {
editor = p_editor;
connect("clear_selection", Callable(editor, "_clear_selection").bind(false));
connect("select_key", Callable(editor, "_key_selected"), CONNECT_DEFERRED);
- connect("deselect_key", Callable(editor, "_key_deselected"), CONNECT_DEFERRED);
}
void AnimationBezierTrackEdit::_play_position_draw() {
@@ -677,7 +689,7 @@ void AnimationBezierTrackEdit::_play_position_draw() {
}
}
-void AnimationBezierTrackEdit::set_play_position(float p_pos) {
+void AnimationBezierTrackEdit::set_play_position(real_t p_pos) {
play_position_pos = p_pos;
play_position->update();
}
@@ -715,7 +727,7 @@ void AnimationBezierTrackEdit::set_filtered(bool p_filtered) {
continue; // Skip track due to not selected.
}
- set_animation_and_track(animation, i);
+ set_animation_and_track(animation, i, read_only);
break;
}
}
@@ -778,13 +790,14 @@ void AnimationBezierTrackEdit::_clear_selection() {
update();
}
-void AnimationBezierTrackEdit::_change_selected_keys_handle_mode(Animation::HandleMode p_mode) {
+void AnimationBezierTrackEdit::_change_selected_keys_handle_mode(Animation::HandleMode p_mode, bool p_auto) {
undo_redo->create_action(TTR("Update Selected Key Handles"));
- double ratio = timeline->get_zoom_scale() * v_zoom;
- for (const IntPair &E : selection) {
- const IntPair track_key_pair = E;
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_handle_mode", track_key_pair.first, track_key_pair.second, animation->bezier_track_get_key_handle_mode(track_key_pair.first, track_key_pair.second), ratio);
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_handle_mode", track_key_pair.first, track_key_pair.second, p_mode, ratio);
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ const IntPair track_key_pair = E->get();
+ undo_redo->add_undo_method(editor, "_bezier_track_set_key_handle_mode", animation.ptr(), track_key_pair.first, track_key_pair.second, animation->bezier_track_get_key_handle_mode(track_key_pair.first, track_key_pair.second), Animation::HANDLE_SET_MODE_NONE);
+ undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track_key_pair.first, track_key_pair.second, animation->bezier_track_get_key_in_handle(track_key_pair.first, track_key_pair.second));
+ undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track_key_pair.first, track_key_pair.second, animation->bezier_track_get_key_out_handle(track_key_pair.first, track_key_pair.second));
+ undo_redo->add_do_method(editor, "_bezier_track_set_key_handle_mode", animation.ptr(), track_key_pair.first, track_key_pair.second, p_mode, p_auto ? Animation::HANDLE_SET_MODE_AUTO : Animation::HANDLE_SET_MODE_RESET);
}
undo_redo->commit_action();
}
@@ -796,7 +809,7 @@ void AnimationBezierTrackEdit::_clear_selection_for_anim(const Ref<Animation> &p
_clear_selection();
}
-void AnimationBezierTrackEdit::_select_at_anim(const Ref<Animation> &p_anim, int p_track, float p_pos) {
+void AnimationBezierTrackEdit::_select_at_anim(const Ref<Animation> &p_anim, int p_track, real_t p_pos) {
if (!(animation == p_anim)) {
return;
}
@@ -805,7 +818,7 @@ void AnimationBezierTrackEdit::_select_at_anim(const Ref<Animation> &p_anim, int
ERR_FAIL_COND(idx < 0);
selection.insert(IntPair(p_track, idx));
- emit_signal(SNAME("select_key"), p_track, idx, true);
+ emit_signal(SNAME("select_key"), idx, true, p_track);
update();
}
@@ -819,12 +832,16 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (p_event->is_pressed()) {
if (ED_GET_SHORTCUT("animation_editor/duplicate_selection")->matches_event(p_event)) {
- duplicate_selection();
+ if (!read_only) {
+ duplicate_selection();
+ }
accept_event();
}
if (ED_GET_SHORTCUT("animation_editor/delete_selection")->matches_event(p_event)) {
- delete_selection();
+ if (!read_only) {
+ delete_selection();
+ }
accept_event();
}
}
@@ -857,16 +874,16 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
return;
}
- float minimum_time = INFINITY;
- float maximum_time = -INFINITY;
- float minimum_value = INFINITY;
- float maximum_value = -INFINITY;
+ real_t minimum_time = INFINITY;
+ real_t maximum_time = -INFINITY;
+ real_t minimum_value = INFINITY;
+ real_t maximum_value = -INFINITY;
for (const IntPair &E : selection) {
IntPair key_pair = E;
- float time = animation->track_get_key_time(key_pair.first, key_pair.second);
- float value = animation->bezier_track_get_key_value(key_pair.first, key_pair.second);
+ real_t time = animation->track_get_key_time(key_pair.first, key_pair.second);
+ real_t value = animation->bezier_track_get_key_value(key_pair.first, key_pair.second);
minimum_time = MIN(time, minimum_time);
maximum_time = MAX(time, maximum_time);
@@ -876,8 +893,8 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
float width = get_size().width - timeline->get_name_limit() - timeline->get_buttons_width();
float padding = width * 0.1;
- float desired_scale = (width - padding / 2) / (maximum_time - minimum_time);
- minimum_time = MAX(0, minimum_time - (padding / 2) / desired_scale);
+ float desired_scale = (width - padding / 2.0) / (maximum_time - minimum_time);
+ minimum_time = MAX(0, minimum_time - (padding / 2.0) / desired_scale);
float zv = Math::pow(100 / desired_scale, 0.125f);
if (zv < 1) {
@@ -917,26 +934,33 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {
menu_insert_key = mb->get_position();
if (menu_insert_key.x >= limit && menu_insert_key.x <= get_size().width) {
- Vector2 popup_pos = get_screen_position() + mb->get_position();
+ if (!read_only) {
+ Vector2 popup_pos = get_screen_position() + mb->get_position();
- menu->clear();
- if (!locked_tracks.has(selected_track) || locked_tracks.has(selected_track)) {
- menu->add_icon_item(bezier_icon, TTR("Insert Key Here"), MENU_KEY_INSERT);
- }
- if (selection.size()) {
- menu->add_separator();
- menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Duplicate Selected Key(s)"), MENU_KEY_DUPLICATE);
- menu->add_separator();
- menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete Selected Key(s)"), MENU_KEY_DELETE);
- menu->add_separator();
- menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesFree"), SNAME("EditorIcons")), TTR("Make Handles Free"), MENU_KEY_SET_HANDLE_FREE);
- menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesBalanced"), SNAME("EditorIcons")), TTR("Make Handles Balanced"), MENU_KEY_SET_HANDLE_BALANCED);
- }
+ menu->clear();
+ if (!locked_tracks.has(selected_track) || locked_tracks.has(selected_track)) {
+ menu->add_icon_item(bezier_icon, TTR("Insert Key Here"), MENU_KEY_INSERT);
+ }
+ if (selection.size()) {
+ menu->add_separator();
+ menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Duplicate Selected Key(s)"), MENU_KEY_DUPLICATE);
+ menu->add_separator();
+ menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete Selected Key(s)"), MENU_KEY_DELETE);
+ menu->add_separator();
+ menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesFree"), SNAME("EditorIcons")), TTR("Make Handles Free"), MENU_KEY_SET_HANDLE_FREE);
+ menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesLinear"), SNAME("EditorIcons")), TTR("Make Handles Linear"), MENU_KEY_SET_HANDLE_LINEAR);
+ menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesBalanced"), SNAME("EditorIcons")), TTR("Make Handles Balanced"), MENU_KEY_SET_HANDLE_BALANCED);
+ menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesMirror"), SNAME("EditorIcons")), TTR("Make Handles Mirrored"), MENU_KEY_SET_HANDLE_MIRRORED);
+ menu->add_separator();
+ menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesBalanced"), SNAME("EditorIcons")), TTR("Make Handles Balanced (Auto Tangent)"), MENU_KEY_SET_HANDLE_AUTO_BALANCED);
+ menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesMirror"), SNAME("EditorIcons")), TTR("Make Handles Mirrored (Auto Tangent)"), MENU_KEY_SET_HANDLE_AUTO_MIRRORED);
+ }
- if (menu->get_item_count()) {
- menu->reset_size();
- menu->set_position(popup_pos);
- menu->popup();
+ if (menu->get_item_count()) {
+ menu->reset_size();
+ menu->set_position(popup_pos);
+ menu->popup();
+ }
}
}
}
@@ -945,7 +969,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
for (const KeyValue<int, Rect2> &E : subtracks) {
if (E.value.has_point(mb->get_position())) {
if (!locked_tracks.has(E.key) && !hidden_tracks.has(E.key)) {
- set_animation_and_track(animation, E.key);
+ set_animation_and_track(animation, E.key, read_only);
_clear_selection();
}
return;
@@ -958,30 +982,33 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
for (const KeyValue<int, Rect2> &I : track_icons) {
if (I.value.has_point(mb->get_position())) {
if (I.key == REMOVE_ICON) {
- undo_redo->create_action("Remove Bezier Track");
-
- undo_redo->add_do_method(this, "_update_locked_tracks_after", track);
- undo_redo->add_do_method(this, "_update_hidden_tracks_after", track);
-
- undo_redo->add_do_method(animation.ptr(), "remove_track", track);
+ if (!read_only) {
+ undo_redo->create_action("Remove Bezier Track");
+
+ undo_redo->add_do_method(this, "_update_locked_tracks_after", track);
+ undo_redo->add_do_method(this, "_update_hidden_tracks_after", track);
+
+ undo_redo->add_do_method(animation.ptr(), "remove_track", track);
+
+ undo_redo->add_undo_method(animation.ptr(), "add_track", Animation::TrackType::TYPE_BEZIER, track);
+ undo_redo->add_undo_method(animation.ptr(), "track_set_path", track, animation->track_get_path(track));
+
+ for (int i = 0; i < animation->track_get_key_count(track); ++i) {
+ undo_redo->add_undo_method(
+ this,
+ "_bezier_track_insert_key",
+ track,
+ animation->track_get_key_time(track, i),
+ animation->bezier_track_get_key_value(track, i),
+ animation->bezier_track_get_key_in_handle(track, i),
+ animation->bezier_track_get_key_out_handle(track, i),
+ animation->bezier_track_get_key_handle_mode(track, i));
+ }
- undo_redo->add_undo_method(animation.ptr(), "add_track", Animation::TrackType::TYPE_BEZIER, track);
- undo_redo->add_undo_method(animation.ptr(), "track_set_path", track, animation->track_get_path(track));
+ undo_redo->commit_action();
- for (int i = 0; i < animation->track_get_key_count(track); ++i) {
- undo_redo->add_undo_method(
- animation.ptr(),
- "bezier_track_insert_key",
- track, animation->track_get_key_time(track, i),
- animation->bezier_track_get_key_value(track, i),
- animation->bezier_track_get_key_in_handle(track, i),
- animation->bezier_track_get_key_out_handle(track, i),
- animation->bezier_track_get_key_handle_mode(track, i));
+ selected_track = CLAMP(selected_track, 0, animation->get_track_count() - 1);
}
-
- undo_redo->commit_action();
-
- selected_track = CLAMP(selected_track, 0, animation->get_track_count() - 1);
return;
} else if (I.key == LOCK_ICON) {
if (locked_tracks.has(track)) {
@@ -991,7 +1018,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (selected_track == track) {
for (int i = 0; i < animation->get_track_count(); ++i) {
if (!locked_tracks.has(i) && animation->track_get_type(i) == Animation::TrackType::TYPE_BEZIER) {
- set_animation_and_track(animation, i);
+ set_animation_and_track(animation, i, read_only);
break;
}
}
@@ -1007,7 +1034,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (selected_track == track) {
for (int i = 0; i < animation->get_track_count(); ++i) {
if (!hidden_tracks.has(i) && animation->track_get_type(i) == Animation::TrackType::TYPE_BEZIER) {
- set_animation_and_track(animation, i);
+ set_animation_and_track(animation, i, read_only);
break;
}
}
@@ -1046,7 +1073,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
}
}
- set_animation_and_track(animation, track);
+ set_animation_and_track(animation, track, read_only);
solo_track = track;
}
update();
@@ -1078,6 +1105,9 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
moving_selection = false;
moving_selection_from_key = pair.second;
moving_selection_from_track = pair.first;
+ moving_handle_track = pair.first;
+ moving_handle_left = animation->bezier_track_get_key_in_handle(pair.first, pair.second);
+ moving_handle_right = animation->bezier_track_get_key_out_handle(pair.first, pair.second);
moving_selection_offset = Vector2();
select_single_attempt = pair;
update();
@@ -1087,57 +1117,60 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
moving_selection_from_key = pair.second;
moving_selection_from_track = pair.first;
moving_selection_offset = Vector2();
- set_animation_and_track(animation, pair.first);
+ moving_handle_track = pair.first;
+ moving_handle_left = animation->bezier_track_get_key_in_handle(pair.first, pair.second);
+ moving_handle_right = animation->bezier_track_get_key_out_handle(pair.first, pair.second);
selection.clear();
selection.insert(pair);
- update();
+ set_animation_and_track(animation, pair.first, read_only);
}
return;
}
}
- if (edit_points[i].in_rect.has_point(mb->get_position())) {
- moving_handle = -1;
- moving_handle_key = edit_points[i].key;
- moving_handle_track = edit_points[i].track;
- moving_handle_left = animation->bezier_track_get_key_in_handle(edit_points[i].track, edit_points[i].key);
- moving_handle_right = animation->bezier_track_get_key_out_handle(edit_points[i].track, edit_points[i].key);
- update();
- return;
- }
+ if (!read_only) {
+ if (edit_points[i].in_rect.has_point(mb->get_position())) {
+ moving_handle = -1;
+ moving_handle_key = edit_points[i].key;
+ moving_handle_track = edit_points[i].track;
+ moving_handle_left = animation->bezier_track_get_key_in_handle(edit_points[i].track, edit_points[i].key);
+ moving_handle_right = animation->bezier_track_get_key_out_handle(edit_points[i].track, edit_points[i].key);
+ update();
+ return;
+ }
- if (edit_points[i].out_rect.has_point(mb->get_position())) {
- moving_handle = 1;
- moving_handle_key = edit_points[i].key;
- moving_handle_track = edit_points[i].track;
- moving_handle_left = animation->bezier_track_get_key_in_handle(edit_points[i].track, edit_points[i].key);
- moving_handle_right = animation->bezier_track_get_key_out_handle(edit_points[i].track, edit_points[i].key);
- update();
- return;
+ if (edit_points[i].out_rect.has_point(mb->get_position())) {
+ moving_handle = 1;
+ moving_handle_key = edit_points[i].key;
+ moving_handle_track = edit_points[i].track;
+ moving_handle_left = animation->bezier_track_get_key_in_handle(edit_points[i].track, edit_points[i].key);
+ moving_handle_right = animation->bezier_track_get_key_out_handle(edit_points[i].track, edit_points[i].key);
+ update();
+ return;
+ }
}
}
//insert new point
if (mb->get_position().x >= limit && mb->get_position().x < get_size().width && mb->is_command_pressed()) {
Array new_point;
- new_point.resize(6);
+ new_point.resize(5);
- float h = (get_size().height / 2 - mb->get_position().y) * v_zoom + v_scroll;
+ float h = (get_size().height / 2.0 - mb->get_position().y) * v_zoom + v_scroll;
new_point[0] = h;
new_point[1] = -0.25;
new_point[2] = 0;
new_point[3] = 0.25;
new_point[4] = 0;
- new_point[5] = 0;
- float time = ((mb->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
+ real_t time = ((mb->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
while (animation->track_find_key(selected_track, time, true) != -1) {
time += 0.001;
}
undo_redo->create_action(TTR("Add Bezier Point"));
- undo_redo->add_do_method(animation.ptr(), "track_insert_key", selected_track, time, new_point);
+ undo_redo->add_do_method(animation.ptr(), "bezier_track_insert_key", selected_track, time, new_point);
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time);
undo_redo->commit_action();
@@ -1191,7 +1224,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
selection.insert(IntPair(edit_points[i].track, edit_points[i].key));
if (!track_set) {
track_set = true;
- set_animation_and_track(animation, edit_points[i].track);
+ set_animation_and_track(animation, edit_points[i].track, read_only);
}
}
}
@@ -1201,10 +1234,10 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
//select by clicking on curve
int track_count = animation->get_track_count();
- float animation_length = animation->get_length();
+ real_t animation_length = animation->get_length();
animation->set_length(real_t(INT_MAX)); //bezier_track_interpolate doesn't find keys if they exist beyond anim length
- float time = ((mb->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
+ real_t time = ((mb->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
for (int i = 0; i < track_count; ++i) {
if (animation->track_get_type(i) != Animation::TrackType::TYPE_BEZIER || hidden_tracks.has(i) || locked_tracks.has(i)) {
@@ -1215,7 +1248,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
float track_height = _bezier_h_to_pixel(track_h);
if (abs(mb->get_position().y - track_height) < 10) {
- set_animation_and_track(animation, i);
+ set_animation_and_track(animation, i, read_only);
break;
}
}
@@ -1228,103 +1261,123 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
update();
}
- if (moving_handle != 0 && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
- undo_redo->create_action(TTR("Move Bezier Points"));
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", selected_track, moving_handle_key, moving_handle_left);
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", selected_track, moving_handle_key, moving_handle_right);
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", selected_track, moving_handle_key, animation->bezier_track_get_key_in_handle(selected_track, moving_handle_key));
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", selected_track, moving_handle_key, animation->bezier_track_get_key_out_handle(selected_track, moving_handle_key));
- undo_redo->commit_action();
+ if (moving_selection_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
+ if (!read_only) {
+ if (moving_selection) {
+ //combit it
- moving_handle = 0;
- update();
- }
+ undo_redo->create_action(TTR("Move Bezier Points"));
- if (moving_selection_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
- if (moving_selection) {
- //combit it
+ List<AnimMoveRestore> to_restore;
+ List<Animation::HandleMode> to_restore_handle_modes;
+ // 1-remove the keys
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->get().first, E->get().second);
+ }
+ // 2- remove overlapped keys
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ real_t newtime = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
- undo_redo->create_action(TTR("Move Bezier Points"));
+ int idx = animation->track_find_key(E->get().first, newtime, true);
+ if (idx == -1) {
+ continue;
+ }
- List<AnimMoveRestore> to_restore;
- // 1-remove the keys
- for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
- undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->get().first, E->get().second);
- }
- // 2- remove overlapped keys
- for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
- float newtime = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
+ if (selection.has(IntPair(E->get().first, idx))) {
+ continue; //already in selection, don't save
+ }
- int idx = animation->track_find_key(E->get().first, newtime, true);
- if (idx == -1) {
- continue;
- }
+ undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", E->get().first, newtime);
+ AnimMoveRestore amr;
- if (selection.has(IntPair(E->get().first, idx))) {
- continue; //already in selection, don't save
- }
+ amr.key = animation->track_get_key_value(E->get().first, idx);
+ amr.track = E->get().first;
+ amr.time = newtime;
- undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", E->get().first, newtime);
- AnimMoveRestore amr;
+ to_restore.push_back(amr);
+ to_restore_handle_modes.push_back(animation->bezier_track_get_key_handle_mode(E->get().first, idx));
+ }
- amr.key = animation->track_get_key_value(E->get().first, idx);
- amr.track = E->get().first;
- amr.time = newtime;
+ // 3-move the keys (re insert them)
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ real_t newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
+ Array key = animation->track_get_key_value(E->get().first, E->get().second);
+ real_t h = key[0];
+ h += moving_selection_offset.y;
+ key[0] = h;
+ undo_redo->add_do_method(
+ this,
+ "_bezier_track_insert_key",
+ E->get().first,
+ newpos,
+ key[0],
+ Vector2(key[1], key[2]),
+ Vector2(key[3], key[4]),
+ animation->bezier_track_get_key_handle_mode(E->get().first, E->get().second));
+ }
- to_restore.push_back(amr);
- }
+ // 4-(undo) remove inserted keys
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ real_t newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->get().first, newpos);
+ }
- // 3-move the keys (re insert them)
- for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
- float newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
- Array key = animation->track_get_key_value(E->get().first, E->get().second);
- float h = key[0];
- h += moving_selection_offset.y;
- key[0] = h;
- undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->get().first, newpos, key, 1);
- }
+ // 5-(undo) reinsert keys
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ real_t oldpos = animation->track_get_key_time(E->get().first, E->get().second);
+ Array key = animation->track_get_key_value(E->get().first, E->get().second);
+ undo_redo->add_undo_method(
+ this,
+ "_bezier_track_insert_key",
+ E->get().first,
+ oldpos,
+ key[0],
+ Vector2(key[1], key[2]),
+ Vector2(key[3], key[4]),
+ animation->bezier_track_get_key_handle_mode(E->get().first, E->get().second));
+ }
- // 4-(undo) remove inserted keys
- for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
- float newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->get().first, newpos);
- }
+ // 6-(undo) reinsert overlapped keys
+ for (int i = 0; i < to_restore.size(); i++) {
+ const AnimMoveRestore &amr = to_restore[i];
+ Array key = amr.key;
+ undo_redo->add_undo_method(animation.ptr(), "track_insert_key", amr.track, amr.time, amr.key, 1);
+ undo_redo->add_undo_method(
+ this,
+ "_bezier_track_insert_key",
+ amr.track,
+ amr.time,
+ key[0],
+ Vector2(key[1], key[2]),
+ Vector2(key[3], key[4]),
+ to_restore_handle_modes[i]);
+ }
- // 5-(undo) reinsert keys
- for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
- float oldpos = animation->track_get_key_time(E->get().first, E->get().second);
- undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->get().first, oldpos, animation->track_get_key_value(E->get().first, E->get().second), 1);
- }
+ undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
+ undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
- // 6-(undo) reinsert overlapped keys
- for (const AnimMoveRestore &amr : to_restore) {
- undo_redo->add_undo_method(animation.ptr(), "track_insert_key", amr.track, amr.time, amr.key, 1);
- }
+ // 7-reselect
- undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
- undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
+ for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
+ real_t oldpos = animation->track_get_key_time(E->get().first, E->get().second);
+ real_t newpos = editor->snap_time(oldpos + moving_selection_offset.x);
- // 7-reselect
+ undo_redo->add_do_method(this, "_select_at_anim", animation, E->get().first, newpos);
+ undo_redo->add_undo_method(this, "_select_at_anim", animation, E->get().first, oldpos);
+ }
- for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
- float oldpos = animation->track_get_key_time(E->get().first, E->get().second);
- float newpos = editor->snap_time(oldpos + moving_selection_offset.x);
+ undo_redo->commit_action();
- undo_redo->add_do_method(this, "_select_at_anim", animation, E->get().first, newpos);
- undo_redo->add_undo_method(this, "_select_at_anim", animation, E->get().first, oldpos);
+ moving_selection = false;
+ } else if (select_single_attempt != IntPair(-1, -1)) {
+ selection.clear();
+ selection.insert(select_single_attempt);
+ set_animation_and_track(animation, select_single_attempt.first, read_only);
}
- undo_redo->commit_action();
-
- moving_selection = false;
- } else if (select_single_attempt != IntPair(-1, -1)) {
- selection.clear();
- selection.insert(select_single_attempt);
- set_animation_and_track(animation, select_single_attempt.first);
+ moving_selection_attempt = false;
+ update();
}
-
- moving_selection_attempt = false;
- update();
}
Ref<InputEventMouseMotion> mm = p_event;
@@ -1334,10 +1387,16 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
select_single_attempt = IntPair(-1, -1);
}
- float y = (get_size().height / 2 - mm->get_position().y) * v_zoom + v_scroll;
+ float y = (get_size().height / 2.0 - mm->get_position().y) * v_zoom + v_scroll;
float x = editor->snap_time(((mm->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value());
- moving_selection_offset = Vector2(x - animation->track_get_key_time(moving_selection_from_track, moving_selection_from_key), y - animation->bezier_track_get_key_value(moving_selection_from_track, moving_selection_from_key));
+ if (!read_only) {
+ moving_selection_offset = Vector2(x - animation->track_get_key_time(moving_selection_from_track, moving_selection_from_key), y - animation->bezier_track_get_key_value(moving_selection_from_track, moving_selection_from_key));
+ }
+
+ additional_moving_handle_lefts.clear();
+ additional_moving_handle_rights.clear();
+
update();
}
@@ -1356,8 +1415,8 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
update();
}
- if (moving_handle != 0 && mm.is_valid()) {
- float y = (get_size().height / 2 - mm->get_position().y) * v_zoom + v_scroll;
+ if ((moving_handle == 1 || moving_handle == -1) && mm.is_valid()) {
+ float y = (get_size().height / 2.0 - mm->get_position().y) * v_zoom + v_scroll;
float x = editor->snap_time((mm->get_position().x - timeline->get_name_limit()) / timeline->get_zoom_scale()) + timeline->get_value();
Vector2 key_pos = Vector2(animation->track_get_key_time(selected_track, moving_handle_key), animation->bezier_track_get_key_value(selected_track, moving_handle_key));
@@ -1370,8 +1429,10 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (moving_handle == -1) {
moving_handle_left = moving_handle_value;
- if (animation->bezier_track_get_key_handle_mode(moving_handle_track, moving_handle_key) == Animation::HANDLE_MODE_BALANCED) {
- double ratio = timeline->get_zoom_scale() * v_zoom;
+ Animation::HandleMode handle_mode = animation->bezier_track_get_key_handle_mode(moving_handle_track, moving_handle_key);
+
+ if (handle_mode == Animation::HANDLE_MODE_BALANCED) {
+ real_t ratio = timeline->get_zoom_scale() * v_zoom;
Transform2D xform;
xform.set_scale(Vector2(1.0, 1.0 / ratio));
@@ -1379,12 +1440,16 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
Vector2 vec_in = xform.xform(moving_handle_left);
moving_handle_right = xform.affine_inverse().xform(-vec_in.normalized() * vec_out.length());
+ } else if (handle_mode == Animation::HANDLE_MODE_MIRRORED) {
+ moving_handle_right = -moving_handle_left;
}
} else if (moving_handle == 1) {
moving_handle_right = moving_handle_value;
- if (animation->bezier_track_get_key_handle_mode(moving_handle_track, moving_handle_key) == Animation::HANDLE_MODE_BALANCED) {
- double ratio = timeline->get_zoom_scale() * v_zoom;
+ Animation::HandleMode handle_mode = animation->bezier_track_get_key_handle_mode(moving_handle_track, moving_handle_key);
+
+ if (handle_mode == Animation::HANDLE_MODE_BALANCED) {
+ real_t ratio = timeline->get_zoom_scale() * v_zoom;
Transform2D xform;
xform.set_scale(Vector2(1.0, 1.0 / ratio));
@@ -1392,27 +1457,29 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
Vector2 vec_out = xform.xform(moving_handle_right);
moving_handle_left = xform.affine_inverse().xform(-vec_out.normalized() * vec_in.length());
+ } else if (handle_mode == Animation::HANDLE_MODE_MIRRORED) {
+ moving_handle_left = -moving_handle_right;
}
}
update();
}
- bool is_finishing_key_handle_drag = moving_handle != 0 && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT;
- if (is_finishing_key_handle_drag) {
- undo_redo->create_action(TTR("Move Bezier Points"));
- if (moving_handle == -1) {
- double ratio = timeline->get_zoom_scale() * v_zoom;
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, moving_handle_left, ratio);
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_in_handle(moving_handle_track, moving_handle_key), ratio);
- } else if (moving_handle == 1) {
- double ratio = timeline->get_zoom_scale() * v_zoom;
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, moving_handle_right, ratio);
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_out_handle(moving_handle_track, moving_handle_key), ratio);
+ if ((moving_handle == -1 || moving_handle == 1) && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
+ if (!read_only) {
+ undo_redo->create_action(TTR("Move Bezier Points"));
+ if (moving_handle == -1) {
+ real_t ratio = timeline->get_zoom_scale() * v_zoom;
+ undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, moving_handle_left, ratio);
+ undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_in_handle(moving_handle_track, moving_handle_key), ratio);
+ } else if (moving_handle == 1) {
+ real_t ratio = timeline->get_zoom_scale() * v_zoom;
+ undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, moving_handle_right, ratio);
+ undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_out_handle(moving_handle_track, moving_handle_key), ratio);
+ }
+ undo_redo->commit_action();
+ moving_handle = 0;
+ update();
}
- undo_redo->commit_action();
-
- moving_handle = 0;
- update();
}
}
@@ -1443,7 +1510,7 @@ void AnimationBezierTrackEdit::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_or
timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() * 1.05);
}
}
- v_scroll = v_scroll + (p_origin.y - get_size().y / 2) * (v_zoom - v_zoom_orig);
+ v_scroll = v_scroll + (p_origin.y - get_size().y / 2.0) * (v_zoom - v_zoom_orig);
update();
}
@@ -1452,20 +1519,19 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
case MENU_KEY_INSERT: {
if (animation->get_track_count() > 0) {
Array new_point;
- new_point.resize(6);
+ new_point.resize(5);
- float h = (get_size().height / 2 - menu_insert_key.y) * v_zoom + v_scroll;
+ float h = (get_size().height / 2.0 - menu_insert_key.y) * v_zoom + v_scroll;
new_point[0] = h;
new_point[1] = -0.25;
new_point[2] = 0;
new_point[3] = 0.25;
new_point[4] = 0;
- new_point[5] = Animation::HANDLE_MODE_BALANCED;
int limit = timeline->get_name_limit();
- float time = ((menu_insert_key.x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
+ real_t time = ((menu_insert_key.x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
while (animation->track_find_key(selected_track, time, true) != -1) {
time += 0.001;
@@ -1475,8 +1541,8 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
undo_redo->add_do_method(animation.ptr(), "track_insert_key", selected_track, time, new_point);
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time);
undo_redo->commit_action();
+ update();
}
-
} break;
case MENU_KEY_DUPLICATE: {
duplicate_selection();
@@ -1487,9 +1553,21 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
case MENU_KEY_SET_HANDLE_FREE: {
_change_selected_keys_handle_mode(Animation::HANDLE_MODE_FREE);
} break;
+ case MENU_KEY_SET_HANDLE_LINEAR: {
+ _change_selected_keys_handle_mode(Animation::HANDLE_MODE_LINEAR);
+ } break;
case MENU_KEY_SET_HANDLE_BALANCED: {
_change_selected_keys_handle_mode(Animation::HANDLE_MODE_BALANCED);
} break;
+ case MENU_KEY_SET_HANDLE_MIRRORED: {
+ _change_selected_keys_handle_mode(Animation::HANDLE_MODE_MIRRORED);
+ } break;
+ case MENU_KEY_SET_HANDLE_AUTO_BALANCED: {
+ _change_selected_keys_handle_mode(Animation::HANDLE_MODE_BALANCED, true);
+ } break;
+ case MENU_KEY_SET_HANDLE_AUTO_MIRRORED: {
+ _change_selected_keys_handle_mode(Animation::HANDLE_MODE_MIRRORED, true);
+ } break;
}
}
@@ -1498,9 +1576,9 @@ void AnimationBezierTrackEdit::duplicate_selection() {
return;
}
- float top_time = 1e10;
+ real_t top_time = 1e10;
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
- float t = animation->track_get_key_time(E->get().first, E->get().second);
+ real_t t = animation->track_get_key_time(E->get().first, E->get().second);
if (t < top_time) {
top_time = t;
}
@@ -1508,17 +1586,17 @@ void AnimationBezierTrackEdit::duplicate_selection() {
undo_redo->create_action(TTR("Anim Duplicate Keys"));
- List<Pair<int, float>> new_selection_values;
+ List<Pair<int, real_t>> new_selection_values;
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
- float t = animation->track_get_key_time(E->get().first, E->get().second);
- float dst_time = t + (timeline->get_play_position() - top_time);
+ real_t t = animation->track_get_key_time(E->get().first, E->get().second);
+ real_t dst_time = t + (timeline->get_play_position() - top_time);
int existing_idx = animation->track_find_key(E->get().first, dst_time, true);
undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->get().first, dst_time, animation->track_get_key_value(E->get().first, E->get().second), animation->track_get_key_transition(E->get().first, E->get().second));
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->get().first, dst_time);
- Pair<int, float> p;
+ Pair<int, real_t> p;
p.first = E->get().first;
p.second = dst_time;
new_selection_values.push_back(p);
@@ -1533,9 +1611,9 @@ void AnimationBezierTrackEdit::duplicate_selection() {
//reselect duplicated
selection.clear();
- for (const Pair<int, float> &E : new_selection_values) {
+ for (const Pair<int, real_t> &E : new_selection_values) {
int track = E.first;
- float time = E.second;
+ real_t time = E.second;
int existing_idx = animation->track_find_key(track, time, true);
@@ -1565,18 +1643,24 @@ void AnimationBezierTrackEdit::delete_selection() {
}
}
+void AnimationBezierTrackEdit::_bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const Animation::HandleMode p_handle_mode) {
+ ERR_FAIL_COND(animation.is_null());
+ int idx = animation->bezier_track_insert_key(p_track, p_time, p_value, p_in_handle, p_out_handle);
+ animation->bezier_track_set_key_handle_mode(p_track, idx, p_handle_mode);
+}
+
void AnimationBezierTrackEdit::_bind_methods() {
- ClassDB::bind_method("_clear_selection", &AnimationBezierTrackEdit::_clear_selection);
- ClassDB::bind_method("_clear_selection_for_anim", &AnimationBezierTrackEdit::_clear_selection_for_anim);
- ClassDB::bind_method("_select_at_anim", &AnimationBezierTrackEdit::_select_at_anim);
- ClassDB::bind_method("_update_hidden_tracks_after", &AnimationBezierTrackEdit::_update_hidden_tracks_after);
- ClassDB::bind_method("_update_locked_tracks_after", &AnimationBezierTrackEdit::_update_locked_tracks_after);
+ ClassDB::bind_method(D_METHOD("_clear_selection"), &AnimationBezierTrackEdit::_clear_selection);
+ ClassDB::bind_method(D_METHOD("_clear_selection_for_anim"), &AnimationBezierTrackEdit::_clear_selection_for_anim);
+ ClassDB::bind_method(D_METHOD("_select_at_anim"), &AnimationBezierTrackEdit::_select_at_anim);
+ ClassDB::bind_method(D_METHOD("_update_hidden_tracks_after"), &AnimationBezierTrackEdit::_update_hidden_tracks_after);
+ ClassDB::bind_method(D_METHOD("_update_locked_tracks_after"), &AnimationBezierTrackEdit::_update_locked_tracks_after);
+ ClassDB::bind_method(D_METHOD("_bezier_track_insert_key"), &AnimationBezierTrackEdit::_bezier_track_insert_key);
ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::FLOAT, "position"), PropertyInfo(Variant::BOOL, "drag")));
ADD_SIGNAL(MethodInfo("remove_request", PropertyInfo(Variant::INT, "track")));
ADD_SIGNAL(MethodInfo("insert_key", PropertyInfo(Variant::FLOAT, "offset")));
- ADD_SIGNAL(MethodInfo("select_key", PropertyInfo(Variant::INT, "track"), PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "single")));
- ADD_SIGNAL(MethodInfo("deselect_key", PropertyInfo(Variant::INT, "track"), PropertyInfo(Variant::INT, "index")));
+ ADD_SIGNAL(MethodInfo("select_key", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "single"), PropertyInfo(Variant::INT, "track")));
ADD_SIGNAL(MethodInfo("clear_selection"));
ADD_SIGNAL(MethodInfo("close_request"));
diff --git a/editor/animation_bezier_editor.h b/editor/animation_bezier_editor.h
index 22b58a6703..beb7a5e9c6 100644
--- a/editor/animation_bezier_editor.h
+++ b/editor/animation_bezier_editor.h
@@ -32,8 +32,9 @@
#define ANIMATION_BEZIER_EDITOR_H
#include "animation_track_editor.h"
-#include "core/templates/rb_set.h"
+#include "core/templates/hashfuncs.h"
+class EditorUndoRedoManager;
class ViewPanner;
class AnimationBezierTrackEdit : public Control {
@@ -44,16 +45,21 @@ class AnimationBezierTrackEdit : public Control {
MENU_KEY_DUPLICATE,
MENU_KEY_DELETE,
MENU_KEY_SET_HANDLE_FREE,
+ MENU_KEY_SET_HANDLE_LINEAR,
MENU_KEY_SET_HANDLE_BALANCED,
+ MENU_KEY_SET_HANDLE_MIRRORED,
+ MENU_KEY_SET_HANDLE_AUTO_BALANCED,
+ MENU_KEY_SET_HANDLE_AUTO_MIRRORED,
};
AnimationTimelineEdit *timeline = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
Node *root = nullptr;
Control *play_position = nullptr; //separate control used to draw so updates for only position changed are much faster
- float play_position_pos = 0;
+ real_t play_position_pos = 0;
Ref<Animation> animation;
+ bool read_only = false;
int selected_track = 0;
Vector<Rect2> view_rects;
@@ -110,25 +116,37 @@ class AnimationBezierTrackEdit : public Control {
Vector2 box_selection_from;
Vector2 box_selection_to;
- int moving_handle = 0; //0 no move -1 or +1 out
+ int moving_handle = 0; //0 no move -1 or +1 out, 2 both (drawing only)
int moving_handle_key = 0;
int moving_handle_track = 0;
Vector2 moving_handle_left;
Vector2 moving_handle_right;
int moving_handle_mode = 0; // value from Animation::HandleMode
+ struct PairHasher {
+ static _FORCE_INLINE_ uint32_t hash(const Pair<int, int> &p_value) {
+ int32_t hash = 23;
+ hash = hash * 31 * hash_one_uint64(p_value.first);
+ hash = hash * 31 * hash_one_uint64(p_value.second);
+ return hash;
+ }
+ };
+
+ HashMap<Pair<int, int>, Vector2, PairHasher> additional_moving_handle_lefts;
+ HashMap<Pair<int, int>, Vector2, PairHasher> additional_moving_handle_rights;
+
void _clear_selection();
void _clear_selection_for_anim(const Ref<Animation> &p_anim);
- void _select_at_anim(const Ref<Animation> &p_anim, int p_track, float p_pos);
- void _change_selected_keys_handle_mode(Animation::HandleMode p_mode);
+ void _select_at_anim(const Ref<Animation> &p_anim, int p_track, real_t p_pos);
+ void _change_selected_keys_handle_mode(Animation::HandleMode p_mode, bool p_auto = false);
Vector2 menu_insert_key;
struct AnimMoveRestore {
int track = 0;
- float time = 0;
+ double time = 0;
Variant key;
- float transition = 0;
+ real_t transition = 0;
};
AnimationTrackEditor *editor = nullptr;
@@ -143,7 +161,7 @@ class AnimationBezierTrackEdit : public Control {
Vector<EditPoint> edit_points;
- struct SelectionCompare {
+ struct PairCompare {
bool operator()(const IntPair &lh, const IntPair &rh) {
if (lh.first == rh.first) {
return lh.second < rh.second;
@@ -153,7 +171,7 @@ class AnimationBezierTrackEdit : public Control {
}
};
- typedef RBSet<IntPair, SelectionCompare> SelectionSet;
+ typedef RBSet<IntPair, PairCompare> SelectionSet;
SelectionSet selection;
@@ -176,21 +194,23 @@ public:
Ref<Animation> get_animation() const;
- void set_animation_and_track(const Ref<Animation> &p_animation, int p_track);
+ void set_animation_and_track(const Ref<Animation> &p_animation, int p_track, bool p_read_only);
virtual Size2 get_minimum_size() const override;
- void set_undo_redo(UndoRedo *p_undo_redo);
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void set_timeline(AnimationTimelineEdit *p_timeline);
void set_editor(AnimationTrackEditor *p_editor);
void set_root(Node *p_root);
void set_filtered(bool p_filtered);
- void set_play_position(float p_pos);
+ void set_play_position(real_t p_pos);
void update_play_position();
void duplicate_selection();
void delete_selection();
+ void _bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const Animation::HandleMode p_handle_mode);
+
AnimationBezierTrackEdit();
};
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index e66aa88eb9..aaaf3e6f04 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -35,8 +35,11 @@
#include "editor/animation_bezier_editor.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/animation_player_editor_plugin.h"
#include "scene/animation/animation_player.h"
+#include "scene/animation/tween.h"
+#include "scene/gui/separator.h"
#include "scene/gui/view_panner.h"
#include "scene/main/window.h"
#include "scene/scene_string_names.h"
@@ -47,6 +50,7 @@ class AnimationTrackKeyEdit : public Object {
public:
bool setting = false;
+ bool animation_read_only = false;
bool _hide_script_from_inspector() {
return true;
@@ -56,12 +60,17 @@ public:
return true;
}
+ bool _is_read_only() {
+ return animation_read_only;
+ }
+
static void _bind_methods() {
- ClassDB::bind_method("_update_obj", &AnimationTrackKeyEdit::_update_obj);
- ClassDB::bind_method("_key_ofs_changed", &AnimationTrackKeyEdit::_key_ofs_changed);
- ClassDB::bind_method("_hide_script_from_inspector", &AnimationTrackKeyEdit::_hide_script_from_inspector);
- ClassDB::bind_method("get_root_path", &AnimationTrackKeyEdit::get_root_path);
- ClassDB::bind_method("_dont_undo_redo", &AnimationTrackKeyEdit::_dont_undo_redo);
+ ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationTrackKeyEdit::_update_obj);
+ ClassDB::bind_method(D_METHOD("_key_ofs_changed"), &AnimationTrackKeyEdit::_key_ofs_changed);
+ ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationTrackKeyEdit::_hide_script_from_inspector);
+ ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationTrackKeyEdit::get_root_path);
+ ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationTrackKeyEdit::_dont_undo_redo);
+ ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationTrackKeyEdit::_is_read_only);
}
void _fix_node_path(Variant &value) {
@@ -342,8 +351,8 @@ public:
setting = true;
undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS);
int prev = animation->bezier_track_get_key_handle_mode(track, key);
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key, value);
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key, prev);
+ undo_redo->add_do_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, value);
+ undo_redo->add_undo_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, prev);
undo_redo->add_do_method(this, "_update_obj", animation);
undo_redo->add_undo_method(this, "_update_obj", animation);
undo_redo->commit_action();
@@ -628,10 +637,16 @@ public:
} break;
case Animation::TYPE_BEZIER: {
+ Animation::HandleMode hm = animation->bezier_track_get_key_handle_mode(track, key);
p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("value")));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("in_handle")));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("out_handle")));
- p_list->push_back(PropertyInfo(Variant::INT, PNAME("handle_mode"), PROPERTY_HINT_ENUM, "Free,Balanced"));
+ if (hm == Animation::HANDLE_MODE_LINEAR) {
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("in_handle"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("out_handle"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY));
+ } else {
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("in_handle")));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("out_handle")));
+ }
+ p_list->push_back(PropertyInfo(Variant::INT, PNAME("handle_mode"), PROPERTY_HINT_ENUM, "Free,Linear,Balanced,Mirrored"));
} break;
case Animation::TYPE_AUDIO: {
@@ -673,7 +688,7 @@ public:
}
}
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
Ref<Animation> animation;
int track = -1;
float key_ofs = 0;
@@ -702,6 +717,7 @@ class AnimationMultiTrackKeyEdit : public Object {
public:
bool setting = false;
+ bool animation_read_only = false;
bool _hide_script_from_inspector() {
return true;
@@ -711,12 +727,17 @@ public:
return true;
}
+ bool _is_read_only() {
+ return animation_read_only;
+ }
+
static void _bind_methods() {
- ClassDB::bind_method("_update_obj", &AnimationMultiTrackKeyEdit::_update_obj);
- ClassDB::bind_method("_key_ofs_changed", &AnimationMultiTrackKeyEdit::_key_ofs_changed);
- ClassDB::bind_method("_hide_script_from_inspector", &AnimationMultiTrackKeyEdit::_hide_script_from_inspector);
- ClassDB::bind_method("get_root_path", &AnimationMultiTrackKeyEdit::get_root_path);
- ClassDB::bind_method("_dont_undo_redo", &AnimationMultiTrackKeyEdit::_dont_undo_redo);
+ ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationMultiTrackKeyEdit::_update_obj);
+ ClassDB::bind_method(D_METHOD("_key_ofs_changed"), &AnimationMultiTrackKeyEdit::_key_ofs_changed);
+ ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationMultiTrackKeyEdit::_hide_script_from_inspector);
+ ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationMultiTrackKeyEdit::get_root_path);
+ ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationMultiTrackKeyEdit::_dont_undo_redo);
+ ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationMultiTrackKeyEdit::_is_read_only);
}
void _fix_node_path(Variant &value, NodePath &base) {
@@ -957,8 +978,8 @@ public:
undo_redo->create_action(TTR("Anim Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
}
Vector2 prev = animation->bezier_track_get_key_in_handle(track, key);
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, value);
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, prev);
+ undo_redo->add_do_method(this, "_bezier_track_set_key_in_handle", track, key, value);
+ undo_redo->add_undo_method(this, "_bezier_track_set_key_in_handle", track, key, prev);
update_obj = true;
} else if (name == "out_handle") {
const Variant &value = p_value;
@@ -968,8 +989,8 @@ public:
undo_redo->create_action(TTR("Anim Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
}
Vector2 prev = animation->bezier_track_get_key_out_handle(track, key);
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, value);
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, prev);
+ undo_redo->add_do_method(this, "_bezier_track_set_key_out_handle", track, key, value);
+ undo_redo->add_undo_method(this, "_bezier_track_set_key_out_handle", track, key, prev);
update_obj = true;
} else if (name == "handle_mode") {
const Variant &value = p_value;
@@ -979,8 +1000,8 @@ public:
undo_redo->create_action(TTR("Anim Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
}
int prev = animation->bezier_track_get_key_handle_mode(track, key);
- undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key, value);
- undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_handle_mode", track, key, prev);
+ undo_redo->add_do_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, value);
+ undo_redo->add_undo_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, prev);
update_obj = true;
}
} break;
@@ -1311,7 +1332,7 @@ public:
p_list->push_back(PropertyInfo(Variant::FLOAT, "value"));
p_list->push_back(PropertyInfo(Variant::VECTOR2, "in_handle"));
p_list->push_back(PropertyInfo(Variant::VECTOR2, "out_handle"));
- p_list->push_back(PropertyInfo(Variant::INT, "handle_mode", PROPERTY_HINT_ENUM, "Free,Balanced"));
+ p_list->push_back(PropertyInfo(Variant::INT, "handle_mode", PROPERTY_HINT_ENUM, "Free,Linear,Balanced,Mirrored"));
} break;
case Animation::TYPE_AUDIO: {
p_list->push_back(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"));
@@ -1361,7 +1382,7 @@ public:
bool use_fps = false;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
void notify_change() {
notify_property_list_changed();
@@ -1415,22 +1436,32 @@ void AnimationTimelineEdit::_anim_length_changed(double p_new_len) {
}
void AnimationTimelineEdit::_anim_loop_pressed() {
- undo_redo->create_action(TTR("Change Animation Loop"));
- switch (animation->get_loop_mode()) {
- case Animation::LOOP_NONE: {
- undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_LINEAR);
- } break;
- case Animation::LOOP_LINEAR: {
- undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_PINGPONG);
- } break;
- case Animation::LOOP_PINGPONG: {
- undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_NONE);
- } break;
- default:
- break;
+ if (!read_only) {
+ undo_redo->create_action(TTR("Change Animation Loop"));
+ switch (animation->get_loop_mode()) {
+ case Animation::LOOP_NONE: {
+ undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_LINEAR);
+ } break;
+ case Animation::LOOP_LINEAR: {
+ undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_PINGPONG);
+ } break;
+ case Animation::LOOP_PINGPONG: {
+ undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_NONE);
+ } break;
+ default:
+ break;
+ }
+ undo_redo->add_undo_method(animation.ptr(), "set_loop_mode", animation->get_loop_mode());
+ undo_redo->commit_action();
+ } else {
+ String base_path = animation->get_path();
+ if (FileAccess::exists(base_path + ".import")) {
+ EditorNode::get_singleton()->show_warning(TTR("Can't change loop mode on animation instanced from imported scene."));
+ } else {
+ EditorNode::get_singleton()->show_warning(TTR("Can't change loop mode on animation embedded in another scene."));
+ }
+ update_values();
}
- undo_redo->add_undo_method(animation.ptr(), "set_loop_mode", animation->get_loop_mode());
- undo_redo->commit_action();
}
int AnimationTimelineEdit::get_buttons_width() const {
@@ -1655,11 +1686,17 @@ void AnimationTimelineEdit::_notification(int p_what) {
}
}
-void AnimationTimelineEdit::set_animation(const Ref<Animation> &p_animation) {
+void AnimationTimelineEdit::set_animation(const Ref<Animation> &p_animation, bool p_read_only) {
animation = p_animation;
+ read_only = p_read_only;
+
if (animation.is_valid()) {
len_hb->show();
- add_track->show();
+ if (read_only) {
+ add_track->hide();
+ } else {
+ add_track->show();
+ }
play_position->show();
} else {
len_hb->hide();
@@ -1679,7 +1716,7 @@ Size2 AnimationTimelineEdit::get_minimum_size() const {
return ms;
}
-void AnimationTimelineEdit::set_undo_redo(UndoRedo *p_undo_redo) {
+void AnimationTimelineEdit::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
undo_redo = p_undo_redo;
}
@@ -1714,13 +1751,13 @@ void AnimationTimelineEdit::update_values() {
if (use_fps && animation->get_step() > 0) {
length->set_value(animation->get_length() / animation->get_step());
length->set_step(1);
- length->set_tooltip(TTR("Animation length (frames)"));
- time_icon->set_tooltip(TTR("Animation length (frames)"));
+ length->set_tooltip_text(TTR("Animation length (frames)"));
+ time_icon->set_tooltip_text(TTR("Animation length (frames)"));
} else {
length->set_value(animation->get_length());
length->set_step(0.001);
- length->set_tooltip(TTR("Animation length (seconds)"));
- time_icon->set_tooltip(TTR("Animation length (seconds)"));
+ length->set_tooltip_text(TTR("Animation length (seconds)"));
+ time_icon->set_tooltip_text(TTR("Animation length (seconds)"));
}
switch (animation->get_loop_mode()) {
@@ -1905,7 +1942,7 @@ AnimationTimelineEdit::AnimationTimelineEdit() {
len_hb->add_child(expander);
time_icon = memnew(TextureRect);
time_icon->set_v_size_flags(SIZE_SHRINK_CENTER);
- time_icon->set_tooltip(TTR("Animation length (seconds)"));
+ time_icon->set_tooltip_text(TTR("Animation length (seconds)"));
len_hb->add_child(time_icon);
length = memnew(EditorSpinSlider);
length->set_min(0.001);
@@ -1914,12 +1951,12 @@ AnimationTimelineEdit::AnimationTimelineEdit() {
length->set_allow_greater(true);
length->set_custom_minimum_size(Vector2(70 * EDSCALE, 0));
length->set_hide_slider(true);
- length->set_tooltip(TTR("Animation length (seconds)"));
+ length->set_tooltip_text(TTR("Animation length (seconds)"));
length->connect("value_changed", callable_mp(this, &AnimationTimelineEdit::_anim_length_changed));
len_hb->add_child(length);
loop = memnew(Button);
loop->set_flat(true);
- loop->set_tooltip(TTR("Animation Looping"));
+ loop->set_tooltip_text(TTR("Animation Looping"));
loop->connect("pressed", callable_mp(this, &AnimationTimelineEdit::_anim_loop_pressed));
loop->set_toggle_mode(true);
len_hb->add_child(loop);
@@ -1981,6 +2018,8 @@ void AnimationTrackEdit::_notification(int p_what) {
Color linecolor = color;
linecolor.a = 0.2;
+ Color dc = get_theme_color(SNAME("disabled_font_color"), SNAME("Editor"));
+
// NAMES AND ICONS //
{
@@ -2083,11 +2122,12 @@ void AnimationTrackEdit::_notification(int p_what) {
get_theme_icon(SNAME("InterpWrapClamp"), SNAME("EditorIcons")),
get_theme_icon(SNAME("InterpWrapLoop"), SNAME("EditorIcons")),
};
-
- Ref<Texture2D> interp_icon[3] = {
+ Ref<Texture2D> interp_icon[5] = {
get_theme_icon(SNAME("InterpRaw"), SNAME("EditorIcons")),
get_theme_icon(SNAME("InterpLinear"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons"))
+ get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons")),
+ get_theme_icon(SNAME("InterpLinearAngle"), SNAME("EditorIcons")),
+ get_theme_icon(SNAME("InterpCubicAngle"), SNAME("EditorIcons")),
};
Ref<Texture2D> cont_icon[4] = {
get_theme_icon(SNAME("TrackContinuous"), SNAME("EditorIcons")),
@@ -2130,14 +2170,18 @@ void AnimationTrackEdit::_notification(int p_what) {
ofs += update_icon->get_width() + hsep / 2;
update_mode_rect.size.x += hsep / 2;
- if (animation->track_get_type(track) == Animation::TYPE_VALUE) {
- draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
- update_mode_rect.size.x += down_icon->get_width();
- } else if (animation->track_get_type(track) == Animation::TYPE_BEZIER) {
- Ref<Texture2D> bezier_icon = get_theme_icon(SNAME("EditBezier"), SNAME("EditorIcons"));
- update_mode_rect.size.x += down_icon->get_width();
+ if (!read_only) {
+ if (animation->track_get_type(track) == Animation::TYPE_VALUE) {
+ draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
+ update_mode_rect.size.x += down_icon->get_width();
+ } else if (animation->track_get_type(track) == Animation::TYPE_BEZIER) {
+ Ref<Texture2D> bezier_icon = get_theme_icon(SNAME("EditBezier"), SNAME("EditorIcons"));
+ update_mode_rect.size.x += down_icon->get_width();
- update_mode_rect = Rect2();
+ update_mode_rect = Rect2();
+ } else {
+ update_mode_rect = Rect2();
+ }
} else {
update_mode_rect = Rect2();
}
@@ -2168,7 +2212,7 @@ void AnimationTrackEdit::_notification(int p_what) {
ofs += icon->get_width() + hsep / 2;
interp_mode_rect.size.x += hsep / 2;
- if (!animation->track_is_compressed(track) && (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_BLEND_SHAPE || animation->track_get_type(track) == Animation::TYPE_POSITION_3D || animation->track_get_type(track) == Animation::TYPE_SCALE_3D || animation->track_get_type(track) == Animation::TYPE_ROTATION_3D)) {
+ if (!read_only && !animation->track_is_compressed(track) && (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_BLEND_SHAPE || animation->track_get_type(track) == Animation::TYPE_POSITION_3D || animation->track_get_type(track) == Animation::TYPE_SCALE_3D || animation->track_get_type(track) == Animation::TYPE_ROTATION_3D)) {
draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
interp_mode_rect.size.x += down_icon->get_width();
} else {
@@ -2201,7 +2245,7 @@ void AnimationTrackEdit::_notification(int p_what) {
ofs += icon->get_width() + hsep / 2;
loop_wrap_rect.size.x += hsep / 2;
- if (!animation->track_is_compressed(track) && (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_BLEND_SHAPE || animation->track_get_type(track) == Animation::TYPE_POSITION_3D || animation->track_get_type(track) == Animation::TYPE_SCALE_3D || animation->track_get_type(track) == Animation::TYPE_ROTATION_3D)) {
+ if (!read_only && !animation->track_is_compressed(track) && (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_BLEND_SHAPE || animation->track_get_type(track) == Animation::TYPE_POSITION_3D || animation->track_get_type(track) == Animation::TYPE_SCALE_3D || animation->track_get_type(track) == Animation::TYPE_ROTATION_3D)) {
draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
loop_wrap_rect.size.x += down_icon->get_width();
} else {
@@ -2222,7 +2266,11 @@ void AnimationTrackEdit::_notification(int p_what) {
remove_rect.position.y = int(get_size().height - icon->get_height()) / 2;
remove_rect.size = icon->get_size();
- draw_texture(icon, remove_rect.position);
+ if (read_only) {
+ draw_texture(icon, remove_rect.position, dc);
+ } else {
+ draw_texture(icon, remove_rect.position);
+ }
}
}
@@ -2438,8 +2486,10 @@ Ref<Animation> AnimationTrackEdit::get_animation() const {
return animation;
}
-void AnimationTrackEdit::set_animation_and_track(const Ref<Animation> &p_animation, int p_track) {
+void AnimationTrackEdit::set_animation_and_track(const Ref<Animation> &p_animation, int p_track, bool p_read_only) {
animation = p_animation;
+ read_only = p_read_only;
+
track = p_track;
update();
@@ -2466,10 +2516,14 @@ Size2 AnimationTrackEdit::get_minimum_size() const {
return Vector2(1, max_h + separation);
}
-void AnimationTrackEdit::set_undo_redo(UndoRedo *p_undo_redo) {
+void AnimationTrackEdit::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
undo_redo = p_undo_redo;
}
+Ref<EditorUndoRedoManager> AnimationTrackEdit::get_undo_redo() const {
+ return undo_redo;
+}
+
void AnimationTrackEdit::set_timeline(AnimationTimelineEdit *p_timeline) {
timeline = p_timeline;
timeline->set_track_edit(this);
@@ -2679,9 +2733,15 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
case Animation::HANDLE_MODE_FREE: {
text += TTR("Handle mode: Free\n");
} break;
+ case Animation::HANDLE_MODE_LINEAR: {
+ text += TTR("Handle mode: Linear\n");
+ } break;
case Animation::HANDLE_MODE_BALANCED: {
text += TTR("Handle mode: Balanced\n");
} break;
+ case Animation::HANDLE_MODE_MIRRORED: {
+ text += TTR("Handle mode: Mirrored\n");
+ } break;
}
} break;
case Animation::TYPE_AUDIO: {
@@ -2720,17 +2780,23 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (p_event->is_pressed()) {
if (ED_GET_SHORTCUT("animation_editor/duplicate_selection")->matches_event(p_event)) {
- emit_signal(SNAME("duplicate_request"));
+ if (!read_only) {
+ emit_signal(SNAME("duplicate_request"));
+ }
accept_event();
}
if (ED_GET_SHORTCUT("animation_editor/duplicate_selection_transposed")->matches_event(p_event)) {
- emit_signal(SNAME("duplicate_transpose_request"));
+ if (!read_only) {
+ emit_signal(SNAME("duplicate_transpose_request"));
+ }
accept_event();
}
if (ED_GET_SHORTCUT("animation_editor/delete_selection")->matches_event(p_event)) {
- emit_signal(SNAME("delete_request"));
+ if (!read_only) {
+ emit_signal(SNAME("delete_request"));
+ }
accept_event();
}
}
@@ -2739,79 +2805,98 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
Point2 pos = mb->get_position();
- if (check_rect.has_point(pos)) {
- undo_redo->create_action(TTR("Toggle Track Enabled"));
- undo_redo->add_do_method(animation.ptr(), "track_set_enabled", track, !animation->track_is_enabled(track));
- undo_redo->add_undo_method(animation.ptr(), "track_set_enabled", track, animation->track_is_enabled(track));
- undo_redo->commit_action();
- update();
- accept_event();
- }
+ if (!read_only) {
+ if (check_rect.has_point(pos)) {
+ undo_redo->create_action(TTR("Toggle Track Enabled"));
+ undo_redo->add_do_method(animation.ptr(), "track_set_enabled", track, !animation->track_is_enabled(track));
+ undo_redo->add_undo_method(animation.ptr(), "track_set_enabled", track, animation->track_is_enabled(track));
+ undo_redo->commit_action();
+ update();
+ accept_event();
+ }
- // Don't overlap track keys if they start at 0.
- if (path_rect.has_point(pos + Size2(type_icon->get_width(), 0))) {
- clicking_on_name = true;
- accept_event();
- }
+ // Don't overlap track keys if they start at 0.
+ if (path_rect.has_point(pos + Size2(type_icon->get_width(), 0))) {
+ clicking_on_name = true;
+ accept_event();
+ }
- if (update_mode_rect.has_point(pos)) {
- if (!menu) {
- menu = memnew(PopupMenu);
- add_child(menu);
- menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected));
+ if (update_mode_rect.has_point(pos)) {
+ if (!menu) {
+ menu = memnew(PopupMenu);
+ add_child(menu);
+ menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected));
+ }
+ menu->clear();
+ menu->add_icon_item(get_theme_icon(SNAME("TrackContinuous"), SNAME("EditorIcons")), TTR("Continuous"), MENU_CALL_MODE_CONTINUOUS);
+ menu->add_icon_item(get_theme_icon(SNAME("TrackDiscrete"), SNAME("EditorIcons")), TTR("Discrete"), MENU_CALL_MODE_DISCRETE);
+ menu->add_icon_item(get_theme_icon(SNAME("TrackTrigger"), SNAME("EditorIcons")), TTR("Trigger"), MENU_CALL_MODE_TRIGGER);
+ menu->add_icon_item(get_theme_icon(SNAME("TrackCapture"), SNAME("EditorIcons")), TTR("Capture"), MENU_CALL_MODE_CAPTURE);
+ menu->reset_size();
+
+ Vector2 popup_pos = get_screen_position() + update_mode_rect.position + Vector2(0, update_mode_rect.size.height);
+ menu->set_position(popup_pos);
+ menu->popup();
+ accept_event();
}
- menu->clear();
- menu->add_icon_item(get_theme_icon(SNAME("TrackContinuous"), SNAME("EditorIcons")), TTR("Continuous"), MENU_CALL_MODE_CONTINUOUS);
- menu->add_icon_item(get_theme_icon(SNAME("TrackDiscrete"), SNAME("EditorIcons")), TTR("Discrete"), MENU_CALL_MODE_DISCRETE);
- menu->add_icon_item(get_theme_icon(SNAME("TrackTrigger"), SNAME("EditorIcons")), TTR("Trigger"), MENU_CALL_MODE_TRIGGER);
- menu->add_icon_item(get_theme_icon(SNAME("TrackCapture"), SNAME("EditorIcons")), TTR("Capture"), MENU_CALL_MODE_CAPTURE);
- menu->reset_size();
-
- Vector2 popup_pos = get_screen_position() + update_mode_rect.position + Vector2(0, update_mode_rect.size.height);
- menu->set_position(popup_pos);
- menu->popup();
- accept_event();
- }
- if (interp_mode_rect.has_point(pos)) {
- if (!menu) {
- menu = memnew(PopupMenu);
- add_child(menu);
- menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected));
+ if (interp_mode_rect.has_point(pos)) {
+ if (!menu) {
+ menu = memnew(PopupMenu);
+ add_child(menu);
+ menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected));
+ }
+ menu->clear();
+ menu->add_icon_item(get_theme_icon(SNAME("InterpRaw"), SNAME("EditorIcons")), TTR("Nearest"), MENU_INTERPOLATION_NEAREST);
+ menu->add_icon_item(get_theme_icon(SNAME("InterpLinear"), SNAME("EditorIcons")), TTR("Linear"), MENU_INTERPOLATION_LINEAR);
+ menu->add_icon_item(get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons")), TTR("Cubic"), MENU_INTERPOLATION_CUBIC);
+ // Check is angle property.
+ AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton();
+ if (ape) {
+ AnimationPlayer *ap = ape->get_player();
+ if (ap) {
+ NodePath path = animation->track_get_path(track);
+ Node *nd = ap->get_node(ap->get_root())->get_node(NodePath(path.get_concatenated_names()));
+ StringName prop = path.get_concatenated_subnames();
+ PropertyInfo prop_info;
+ ClassDB::get_property_info(nd->get_class(), prop, &prop_info);
+ bool is_angle = prop_info.type == Variant::FLOAT && prop_info.hint_string.find("radians") != -1;
+ if (is_angle) {
+ menu->add_icon_item(get_theme_icon(SNAME("InterpLinearAngle"), SNAME("EditorIcons")), TTR("Linear Angle"), MENU_INTERPOLATION_LINEAR_ANGLE);
+ menu->add_icon_item(get_theme_icon(SNAME("InterpCubicAngle"), SNAME("EditorIcons")), TTR("Cubic Angle"), MENU_INTERPOLATION_CUBIC_ANGLE);
+ }
+ }
+ }
+ menu->reset_size();
+
+ Vector2 popup_pos = get_screen_position() + interp_mode_rect.position + Vector2(0, interp_mode_rect.size.height);
+ menu->set_position(popup_pos);
+ menu->popup();
+ accept_event();
}
- menu->clear();
- menu->add_icon_item(get_theme_icon(SNAME("InterpRaw"), SNAME("EditorIcons")), TTR("Nearest"), MENU_INTERPOLATION_NEAREST);
- menu->add_icon_item(get_theme_icon(SNAME("InterpLinear"), SNAME("EditorIcons")), TTR("Linear"), MENU_INTERPOLATION_LINEAR);
- menu->add_icon_item(get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons")), TTR("Cubic"), MENU_INTERPOLATION_CUBIC);
- menu->reset_size();
-
- Vector2 popup_pos = get_screen_position() + interp_mode_rect.position + Vector2(0, interp_mode_rect.size.height);
- menu->set_position(popup_pos);
- menu->popup();
- accept_event();
- }
- if (loop_wrap_rect.has_point(pos)) {
- if (!menu) {
- menu = memnew(PopupMenu);
- add_child(menu);
- menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected));
+ if (loop_wrap_rect.has_point(pos)) {
+ if (!menu) {
+ menu = memnew(PopupMenu);
+ add_child(menu);
+ menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected));
+ }
+ menu->clear();
+ menu->add_icon_item(get_theme_icon(SNAME("InterpWrapClamp"), SNAME("EditorIcons")), TTR("Clamp Loop Interp"), MENU_LOOP_CLAMP);
+ menu->add_icon_item(get_theme_icon(SNAME("InterpWrapLoop"), SNAME("EditorIcons")), TTR("Wrap Loop Interp"), MENU_LOOP_WRAP);
+ menu->reset_size();
+
+ Vector2 popup_pos = get_screen_position() + loop_wrap_rect.position + Vector2(0, loop_wrap_rect.size.height);
+ menu->set_position(popup_pos);
+ menu->popup();
+ accept_event();
}
- menu->clear();
- menu->add_icon_item(get_theme_icon(SNAME("InterpWrapClamp"), SNAME("EditorIcons")), TTR("Clamp Loop Interp"), MENU_LOOP_CLAMP);
- menu->add_icon_item(get_theme_icon(SNAME("InterpWrapLoop"), SNAME("EditorIcons")), TTR("Wrap Loop Interp"), MENU_LOOP_WRAP);
- menu->reset_size();
-
- Vector2 popup_pos = get_screen_position() + loop_wrap_rect.position + Vector2(0, loop_wrap_rect.size.height);
- menu->set_position(popup_pos);
- menu->popup();
- accept_event();
- }
- if (remove_rect.has_point(pos)) {
- emit_signal(SNAME("remove_request"), track);
- accept_event();
- return;
+ if (remove_rect.has_point(pos)) {
+ emit_signal(SNAME("remove_request"), track);
+ accept_event();
+ return;
+ }
}
// Check keyframes.
@@ -2871,6 +2956,11 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
moving_selection_attempt = true;
moving_selection_from_ofs = (mb->get_position().x - limit) / timeline->get_zoom_scale();
}
+
+ if (read_only) {
+ moving_selection_attempt = false;
+ moving_selection_from_ofs = 0.0f;
+ }
accept_event();
}
}
@@ -2882,33 +2972,35 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (pos.x >= timeline->get_name_limit() && pos.x <= get_size().width - timeline->get_buttons_width()) {
// Can do something with menu too! show insert key.
float offset = (pos.x - timeline->get_name_limit()) / timeline->get_zoom_scale();
- if (!menu) {
- menu = memnew(PopupMenu);
- add_child(menu);
- menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected));
- }
+ if (!read_only) {
+ if (!menu) {
+ menu = memnew(PopupMenu);
+ add_child(menu);
+ menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected));
+ }
- menu->clear();
- menu->add_icon_item(get_theme_icon(SNAME("Key"), SNAME("EditorIcons")), TTR("Insert Key"), MENU_KEY_INSERT);
- if (editor->is_selection_active()) {
- menu->add_separator();
- menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Duplicate Key(s)"), MENU_KEY_DUPLICATE);
+ menu->clear();
+ menu->add_icon_item(get_theme_icon(SNAME("Key"), SNAME("EditorIcons")), TTR("Insert Key"), MENU_KEY_INSERT);
+ if (editor->is_selection_active()) {
+ menu->add_separator();
+ menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Duplicate Key(s)"), MENU_KEY_DUPLICATE);
- AnimationPlayer *player = AnimationPlayerEditor::get_singleton()->get_player();
- if (!player->has_animation(SceneStringNames::get_singleton()->RESET) || animation != player->get_animation(SceneStringNames::get_singleton()->RESET)) {
- menu->add_icon_item(get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")), TTR("Add RESET Value(s)"), MENU_KEY_ADD_RESET);
- }
+ AnimationPlayer *player = AnimationPlayerEditor::get_singleton()->get_player();
+ if (!player->has_animation(SceneStringNames::get_singleton()->RESET) || animation != player->get_animation(SceneStringNames::get_singleton()->RESET)) {
+ menu->add_icon_item(get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")), TTR("Add RESET Value(s)"), MENU_KEY_ADD_RESET);
+ }
- menu->add_separator();
- menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete Key(s)"), MENU_KEY_DELETE);
- }
- menu->reset_size();
+ menu->add_separator();
+ menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete Key(s)"), MENU_KEY_DELETE);
+ }
+ menu->reset_size();
- menu->set_position(get_screen_position() + get_local_mouse_position());
- menu->popup();
+ menu->set_position(get_screen_position() + get_local_mouse_position());
+ menu->popup();
- insert_at_pos = offset + timeline->get_value();
- accept_event();
+ insert_at_pos = offset + timeline->get_value();
+ accept_event();
+ }
}
}
@@ -3115,7 +3207,9 @@ void AnimationTrackEdit::_menu_selected(int p_index) {
} break;
case MENU_INTERPOLATION_NEAREST:
case MENU_INTERPOLATION_LINEAR:
- case MENU_INTERPOLATION_CUBIC: {
+ case MENU_INTERPOLATION_CUBIC:
+ case MENU_INTERPOLATION_LINEAR_ANGLE:
+ case MENU_INTERPOLATION_CUBIC_ANGLE: {
Animation::InterpolationType interp_mode = Animation::InterpolationType(p_index - MENU_INTERPOLATION_NEAREST);
undo_redo->create_action(TTR("Change Animation Interpolation Mode"));
undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", track, interp_mode);
@@ -3195,7 +3289,6 @@ void AnimationTrackEdit::_bind_methods() {
ADD_SIGNAL(MethodInfo("insert_key", PropertyInfo(Variant::FLOAT, "offset")));
ADD_SIGNAL(MethodInfo("select_key", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "single")));
ADD_SIGNAL(MethodInfo("deselect_key", PropertyInfo(Variant::INT, "index")));
- ADD_SIGNAL(MethodInfo("bezier_edit"));
ADD_SIGNAL(MethodInfo("move_selection_begin"));
ADD_SIGNAL(MethodInfo("move_selection", PropertyInfo(Variant::FLOAT, "offset")));
@@ -3353,25 +3446,28 @@ void AnimationTrackEditor::remove_track_edit_plugin(const Ref<AnimationTrackEdit
track_edit_plugins.erase(p_plugin);
}
-void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim) {
+void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim, bool p_read_only) {
if (animation != p_anim && _get_track_selected() >= 0) {
track_edits[_get_track_selected()]->release_focus();
}
if (animation.is_valid()) {
- animation->disconnect("changed", callable_mp(this, &AnimationTrackEditor::_animation_changed));
+ animation->disconnect("tracks_changed", callable_mp(this, &AnimationTrackEditor::_animation_changed));
+ animation->disconnect("changed", callable_mp(this, &AnimationTrackEditor::_sync_animation_change));
_clear_selection();
}
animation = p_anim;
- timeline->set_animation(p_anim);
+ read_only = p_read_only;
+ timeline->set_animation(p_anim, read_only);
_cancel_bezier_edit();
_update_tracks();
if (animation.is_valid()) {
- animation->connect("changed", callable_mp(this, &AnimationTrackEditor::_animation_changed));
+ animation->connect("tracks_changed", callable_mp(this, &AnimationTrackEditor::_animation_changed), CONNECT_DEFERRED);
+ animation->connect("changed", callable_mp(this, &AnimationTrackEditor::_sync_animation_change), CONNECT_DEFERRED);
hscroll->show();
- edit->set_disabled(false);
+ edit->set_disabled(read_only);
step->set_block_signals(true);
_update_step_spinbox();
@@ -3500,13 +3596,11 @@ void AnimationTrackEditor::set_state(const Dictionary &p_state) {
}
void AnimationTrackEditor::cleanup() {
- set_animation(Ref<Animation>());
+ set_animation(Ref<Animation>(), read_only);
}
void AnimationTrackEditor::_name_limit_changed() {
- for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
- }
+ _redraw_tracks();
}
void AnimationTrackEditor::_timeline_changed(float p_new_pos, bool p_drag, bool p_timeline_only) {
@@ -3601,9 +3695,7 @@ void AnimationTrackEditor::set_anim_pos(float p_pos) {
for (int i = 0; i < track_edits.size(); i++) {
track_edits[i]->set_play_position(p_pos);
}
- for (int i = 0; i < groups.size(); i++) {
- groups[i]->update();
- }
+ _redraw_groups();
bezier_edit->set_play_position(p_pos);
}
@@ -4283,13 +4375,12 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
} break;
case Animation::TYPE_BEZIER: {
Array array;
- array.resize(6);
+ array.resize(5);
array[0] = p_id.value;
array[1] = -0.25;
array[2] = 0;
array[3] = 0.25;
array[4] = 0;
- array[5] = Animation::HANDLE_MODE_BALANCED;
value = array;
bezier_edit_icon->set_disabled(false);
@@ -4377,6 +4468,27 @@ void AnimationTrackEditor::_update_tracks() {
return;
}
+ bool read_only = false;
+ if (!animation->get_path().is_resource_file()) {
+ int srpos = animation->get_path().find("::");
+ if (srpos != -1) {
+ String base = animation->get_path().substr(0, srpos);
+ if (ResourceLoader::get_resource_type(base) == "PackedScene") {
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ read_only = true;
+ }
+ } else {
+ if (FileAccess::exists(base + ".import")) {
+ read_only = true;
+ }
+ }
+ }
+ } else {
+ if (FileAccess::exists(animation->get_path() + ".import")) {
+ read_only = true;
+ }
+ }
+
RBMap<String, VBoxContainer *> group_sort;
bool use_grouping = !view_group->is_pressed();
@@ -4484,7 +4596,7 @@ void AnimationTrackEditor::_update_tracks() {
g->set_type_and_name(icon, name, animation->track_get_path(i));
g->set_root(root);
- g->set_tooltip(tooltip);
+ g->set_tooltip_text(tooltip);
g->set_timeline(timeline);
groups.push_back(g);
VBoxContainer *vb = memnew(VBoxContainer);
@@ -4505,7 +4617,7 @@ void AnimationTrackEditor::_update_tracks() {
track_edit->set_undo_redo(undo_redo);
track_edit->set_timeline(timeline);
track_edit->set_root(root);
- track_edit->set_animation_and_track(animation, i);
+ track_edit->set_animation_and_track(animation, i, read_only);
track_edit->set_play_position(timeline->get_play_position());
track_edit->set_editor(this);
@@ -4531,11 +4643,31 @@ void AnimationTrackEditor::_update_tracks() {
}
}
+void AnimationTrackEditor::_redraw_tracks() {
+ for (int i = 0; i < track_edits.size(); i++) {
+ track_edits[i]->update();
+ }
+}
+
+void AnimationTrackEditor::_redraw_groups() {
+ for (int i = 0; i < groups.size(); i++) {
+ groups[i]->update();
+ }
+}
+
+void AnimationTrackEditor::_sync_animation_change() {
+ bezier_edit->update();
+}
+
void AnimationTrackEditor::_animation_changed() {
if (animation_changing_awaiting_update) {
return; // All will be updated, don't bother with anything.
}
+ if (key_edit) {
+ _update_key_edit();
+ }
+
if (key_edit && key_edit->setting) {
// If editing a key, just update the edited track, makes refresh less costly.
if (key_edit->track < track_edits.size()) {
@@ -4604,12 +4736,8 @@ void AnimationTrackEditor::_animation_update() {
}
if (same) {
- for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
- }
- for (int i = 0; i < groups.size(); i++) {
- groups[i]->update();
- }
+ _redraw_tracks();
+ _redraw_groups();
} else {
_update_tracks();
}
@@ -4659,12 +4787,8 @@ void AnimationTrackEditor::_notification(int p_what) {
}
void AnimationTrackEditor::_update_scroll(double) {
- for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
- }
- for (int i = 0; i < groups.size(); i++) {
- groups[i]->update();
- }
+ _redraw_tracks();
+ _redraw_groups();
}
void AnimationTrackEditor::_update_step(double p_new_step) {
@@ -4692,7 +4816,7 @@ void AnimationTrackEditor::_dropped_track(int p_from_track, int p_to_track) {
return;
}
- _clear_selection();
+ _clear_selection(true);
undo_redo->create_action(TTR("Rearrange Tracks"));
undo_redo->add_do_method(animation.ptr(), "track_move_to", p_from_track, p_to_track);
// Take into account that the position of the tracks that come after the one removed will change.
@@ -4870,14 +4994,11 @@ void AnimationTrackEditor::_new_track_property_selected(String p_name) {
void AnimationTrackEditor::_timeline_value_changed(double) {
timeline->update_play_position();
+ _redraw_tracks();
for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
track_edits[i]->update_play_position();
}
-
- for (int i = 0; i < groups.size(); i++) {
- groups[i]->update();
- }
+ _redraw_groups();
bezier_edit->update();
bezier_edit->update_play_position();
@@ -4995,13 +5116,12 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
Variant value;
_find_hint_for_track(p_track, bp, &value);
Array arr;
- arr.resize(6);
+ arr.resize(5);
arr[0] = value;
arr[1] = -0.25;
arr[2] = 0;
arr[3] = 0.25;
arr[4] = 0;
- arr[5] = 0;
undo_redo->create_action(TTR("Add Track Key"));
undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_track, p_ofs, arr);
@@ -5089,10 +5209,7 @@ void AnimationTrackEditor::_key_selected(int p_key, bool p_single, int p_track)
ki.pos = animation->track_get_key_time(p_track, p_key);
selection[sk] = ki;
- for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
- }
-
+ _redraw_tracks();
_update_key_edit();
}
@@ -5106,10 +5223,7 @@ void AnimationTrackEditor::_key_deselected(int p_key, int p_track) {
selection.erase(sk);
- for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
- }
-
+ _redraw_tracks();
_update_key_edit();
}
@@ -5120,10 +5234,7 @@ void AnimationTrackEditor::_move_selection_begin() {
void AnimationTrackEditor::_move_selection(float p_offset) {
moving_selection_offset = p_offset;
-
- for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
- }
+ _redraw_tracks();
}
struct _AnimMoveRestore {
@@ -5160,9 +5271,7 @@ void AnimationTrackEditor::_clear_selection(bool p_update) {
selection.clear();
if (p_update) {
- for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
- }
+ _redraw_tracks();
}
_clear_key_edit();
@@ -5177,6 +5286,7 @@ void AnimationTrackEditor::_update_key_edit() {
if (selection.size() == 1) {
key_edit = memnew(AnimationTrackKeyEdit);
key_edit->animation = animation;
+ key_edit->animation_read_only = read_only;
key_edit->track = selection.front()->key().track;
key_edit->use_fps = timeline->is_using_fps();
@@ -5193,6 +5303,7 @@ void AnimationTrackEditor::_update_key_edit() {
} else if (selection.size() > 1) {
multi_key_edit = memnew(AnimationMultiTrackKeyEdit);
multi_key_edit->animation = animation;
+ multi_key_edit->animation_read_only = read_only;
RBMap<int, List<float>> key_ofs_map;
RBMap<int, NodePath> base_map;
@@ -5318,21 +5429,16 @@ void AnimationTrackEditor::_move_selection_commit() {
undo_redo->add_undo_method(this, "_select_at_anim", animation, E->key().track, oldpos);
}
- undo_redo->commit_action();
-
moving_selection = false;
- for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
- }
-
+ undo_redo->add_do_method(this, "_redraw_tracks");
+ undo_redo->add_undo_method(this, "_redraw_tracks");
+ undo_redo->commit_action();
_update_key_edit();
}
void AnimationTrackEditor::_move_selection_cancel() {
moving_selection = false;
- for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
- }
+ _redraw_tracks();
}
bool AnimationTrackEditor::is_moving_selection() const {
@@ -5375,7 +5481,7 @@ void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
track_edits[track_edits.size() - 1]->grab_focus();
}
} else {
- _clear_selection(); // Clear it.
+ _clear_selection(true); // Clear it.
}
box_selection->hide();
@@ -5395,7 +5501,7 @@ void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
if (!box_selection->is_visible_in_tree()) {
if (!mm->is_command_pressed() && !mm->is_shift_pressed()) {
- _clear_selection();
+ _clear_selection(true);
}
box_selection->show();
}
@@ -5472,12 +5578,19 @@ void AnimationTrackEditor::_cancel_bezier_edit() {
void AnimationTrackEditor::_bezier_edit(int p_for_track) {
_clear_selection(); // Bezier probably wants to use a separate selection mode.
bezier_edit->set_root(root);
- bezier_edit->set_animation_and_track(animation, p_for_track);
+ bezier_edit->set_animation_and_track(animation, p_for_track, read_only);
scroll->hide();
bezier_edit->show();
// Search everything within the track and curve - edit it.
}
+void AnimationTrackEditor::_bezier_track_set_key_handle_mode(Animation *p_anim, int p_track, int p_index, Animation::HandleMode p_mode, Animation::HandleSetMode p_set_mode) {
+ if (!p_anim) {
+ return;
+ }
+ p_anim->bezier_track_set_key_handle_mode(p_track, p_index, p_mode, p_set_mode);
+}
+
void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) {
// Duplicait!
if (selection.size() && animation.is_valid() && (!transpose || (_get_track_selected() >= 0 && _get_track_selected() < animation->get_track_count()))) {
@@ -5535,32 +5648,21 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) {
}
}
- undo_redo->commit_action();
+ undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
+ undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
// Reselect duplicated.
-
RBMap<SelectedKey, KeyInfo> new_selection;
for (const Pair<int, float> &E : new_selection_values) {
- int track = E.first;
- float time = E.second;
-
- int existing_idx = animation->track_find_key(track, time, true);
-
- if (existing_idx == -1) {
- continue;
- }
- SelectedKey sk2;
- sk2.track = track;
- sk2.key = existing_idx;
-
- KeyInfo ki;
- ki.pos = time;
-
- new_selection[sk2] = ki;
+ undo_redo->add_do_method(this, "_select_at_anim", animation, E.first, E.second);
+ }
+ for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
+ undo_redo->add_undo_method(this, "_select_at_anim", animation, E->key().track, E->get().pos);
}
- selection = new_selection;
- _update_tracks();
+ undo_redo->add_do_method(this, "_redraw_tracks");
+ undo_redo->add_undo_method(this, "_redraw_tracks");
+ undo_redo->commit_action();
_update_key_edit();
}
}
@@ -5881,8 +5983,110 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
undo_redo->add_undo_method(this, "_select_at_anim", animation, E->key().track, oldpos);
}
#undef NEW_POS
+
+ undo_redo->add_do_method(this, "_redraw_tracks");
+ undo_redo->add_undo_method(this, "_redraw_tracks");
+ undo_redo->commit_action();
+ _update_key_edit();
+
+ } break;
+
+ case EDIT_EASE_SELECTION: {
+ ease_dialog->popup_centered(Size2(200, 100) * EDSCALE);
+ } break;
+ case EDIT_EASE_CONFIRM: {
+ undo_redo->create_action(TTR("Make Easing Keys"));
+
+ Tween::TransitionType transition_type = static_cast<Tween::TransitionType>(transition_selection->get_selected_id());
+ Tween::EaseType ease_type = static_cast<Tween::EaseType>(ease_selection->get_selected_id());
+ float fps = ease_fps->get_value();
+ double dur_step = 1.0 / fps;
+
+ // Organize track and key.
+ HashMap<int, Vector<int>> keymap;
+ Vector<int> tracks;
+ for (const KeyValue<SelectedKey, KeyInfo> &E : selection) {
+ if (!tracks.has(E.key.track)) {
+ tracks.append(E.key.track);
+ }
+ }
+ for (int i = 0; i < tracks.size(); i++) {
+ switch (animation->track_get_type(tracks[i])) {
+ case Animation::TYPE_VALUE:
+ case Animation::TYPE_POSITION_3D:
+ case Animation::TYPE_ROTATION_3D:
+ case Animation::TYPE_SCALE_3D:
+ case Animation::TYPE_BLEND_SHAPE: {
+ Vector<int> keys;
+ for (const KeyValue<SelectedKey, KeyInfo> &E : selection) {
+ if (E.key.track == tracks[i]) {
+ keys.append(E.key.key);
+ }
+ }
+ keys.sort();
+ keymap.insert(tracks[i], keys);
+ } break;
+ default: {
+ } break;
+ }
+ }
+
+ // Make easing.
+ HashMap<int, Vector<int>>::Iterator E = keymap.begin();
+ while (E) {
+ int track = E->key;
+ Vector<int> keys = E->value;
+ int len = keys.size() - 1;
+
+ // Special case for angle interpolation.
+ bool is_using_angle = animation->track_get_interpolation_type(track) == Animation::INTERPOLATION_LINEAR_ANGLE || animation->track_get_interpolation_type(track) == Animation::INTERPOLATION_CUBIC_ANGLE;
+
+ // Make insert queue.
+ Vector<Pair<real_t, Variant>> insert_queue;
+ for (int i = 0; i < len; i++) {
+ // Check neighboring keys.
+ if (keys[i] + 1 == keys[i + 1]) {
+ double from_t = animation->track_get_key_time(track, keys[i]);
+ double to_t = animation->track_get_key_time(track, keys[i + 1]);
+ Variant from_v = animation->track_get_key_value(track, keys[i]);
+ Variant to_v = animation->track_get_key_value(track, keys[i + 1]);
+ if (is_using_angle) {
+ real_t a = from_v;
+ real_t b = to_v;
+ real_t to_diff = fmod(b - a, Math_TAU);
+ to_v = a + fmod(2.0 * to_diff, Math_TAU) - to_diff;
+ }
+ Variant delta_v;
+ Variant::sub(to_v, from_v, delta_v);
+ double duration = to_t - from_t;
+ double fixed_duration = duration - 0.01; // Prevent to overwrap keys...
+ for (double delta_t = dur_step; delta_t < fixed_duration; delta_t += dur_step) {
+ Pair<real_t, Variant> keydata;
+ keydata.first = from_t + delta_t;
+ keydata.second = Tween::interpolate_variant(from_v, delta_v, delta_t, duration, transition_type, ease_type);
+ insert_queue.append(keydata);
+ }
+ }
+ }
+
+ // Do insertion.
+ for (int i = 0; i < insert_queue.size(); i++) {
+ undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, insert_queue[i].first, insert_queue[i].second);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, insert_queue[i].first);
+ }
+
+ ++E;
+ }
+
+ undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
+ undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
+ undo_redo->add_do_method(this, "_redraw_tracks");
+ undo_redo->add_undo_method(this, "_redraw_tracks");
undo_redo->commit_action();
+ _update_key_edit();
+
} break;
+
case EDIT_DUPLICATE_SELECTION: {
if (bezier_edit->is_visible()) {
bezier_edit->duplicate_selection();
@@ -5899,6 +6103,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
} break;
case EDIT_ADD_RESET_KEY: {
undo_redo->create_action(TTR("Anim Add RESET Keys"));
+
Ref<Animation> reset = _create_and_get_reset_animation();
int reset_tracks = reset->get_track_count();
HashSet<int> tracks_added;
@@ -5943,6 +6148,10 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
}
}
+ undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
+ undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
+ undo_redo->add_do_method(this, "_redraw_tracks");
+ undo_redo->add_undo_method(this, "_redraw_tracks");
undo_redo->commit_action();
} break;
@@ -5961,6 +6170,8 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
}
undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
+ undo_redo->add_do_method(this, "_redraw_tracks");
+ undo_redo->add_undo_method(this, "_redraw_tracks");
undo_redo->commit_action();
_update_key_edit();
}
@@ -5972,18 +6183,137 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
case EDIT_GOTO_PREV_STEP: {
goto_prev_step(false);
} break;
+
case EDIT_APPLY_RESET: {
AnimationPlayerEditor::get_singleton()->get_player()->apply_reset(true);
+ } break;
+
+ case EDIT_BAKE_ANIMATION: {
+ bake_dialog->popup_centered(Size2(200, 100) * EDSCALE);
+ } break;
+ case EDIT_BAKE_ANIMATION_CONFIRM: {
+ undo_redo->create_action(TTR("Bake Animation as Linear keys."));
+
+ int track_len = animation->get_track_count();
+ bool b_trs = bake_trs->is_pressed();
+ bool b_bs = bake_blendshape->is_pressed();
+ bool b_v = bake_value->is_pressed();
+
+ double anim_len = animation->get_length() + CMP_EPSILON; // For end key.
+ float fps = bake_fps->get_value();
+ double dur_step = 1.0 / fps;
+
+ for (int i = 0; i < track_len; i++) {
+ bool do_bake = false;
+ Animation::TrackType type = animation->track_get_type(i);
+ do_bake |= b_trs && (type == Animation::TYPE_POSITION_3D || type == Animation::TYPE_ROTATION_3D || type == Animation::TYPE_SCALE_3D);
+ do_bake |= b_bs && type == Animation::TYPE_BLEND_SHAPE;
+ do_bake |= b_v && type == Animation::TYPE_VALUE;
+ if (do_bake && !animation->track_is_compressed(i)) {
+ Animation::InterpolationType it = animation->track_get_interpolation_type(i);
+ if (it == Animation::INTERPOLATION_NEAREST) {
+ continue; // Nearest and Angle interpolation cannot be baked.
+ }
+
+ // Special case for angle interpolation.
+ bool is_using_angle = it == Animation::INTERPOLATION_LINEAR_ANGLE || it == Animation::INTERPOLATION_CUBIC_ANGLE;
+
+ // Make insert queue.
+ Vector<Pair<real_t, Variant>> insert_queue;
+
+ switch (type) {
+ case Animation::TYPE_POSITION_3D: {
+ for (double delta_t = 0.0; delta_t <= anim_len; delta_t += dur_step) {
+ Pair<real_t, Variant> keydata;
+ keydata.first = delta_t;
+ Vector3 v;
+ animation->position_track_interpolate(i, delta_t, &v);
+ keydata.second = v;
+ insert_queue.append(keydata);
+ }
+ } break;
+ case Animation::TYPE_ROTATION_3D: {
+ for (double delta_t = 0.0; delta_t <= anim_len; delta_t += dur_step) {
+ Pair<real_t, Variant> keydata;
+ keydata.first = delta_t;
+ Quaternion v;
+ animation->rotation_track_interpolate(i, delta_t, &v);
+ keydata.second = v;
+ insert_queue.append(keydata);
+ }
+ } break;
+ case Animation::TYPE_SCALE_3D: {
+ for (double delta_t = 0.0; delta_t <= anim_len; delta_t += dur_step) {
+ Pair<real_t, Variant> keydata;
+ keydata.first = delta_t;
+ Vector3 v;
+ animation->scale_track_interpolate(i, delta_t, &v);
+ keydata.second = v;
+ insert_queue.append(keydata);
+ }
+ } break;
+ case Animation::TYPE_BLEND_SHAPE: {
+ for (double delta_t = 0.0; delta_t <= anim_len; delta_t += dur_step) {
+ Pair<real_t, Variant> keydata;
+ keydata.first = delta_t;
+ float v;
+ animation->blend_shape_track_interpolate(i, delta_t, &v);
+ keydata.second = v;
+ insert_queue.append(keydata);
+ }
+ } break;
+ case Animation::TYPE_VALUE: {
+ for (double delta_t = 0.0; delta_t < anim_len; delta_t += dur_step) {
+ Pair<real_t, Variant> keydata;
+ keydata.first = delta_t;
+ keydata.second = animation->value_track_interpolate(i, delta_t);
+ insert_queue.append(keydata);
+ }
+ } break;
+ default: {
+ } break;
+ }
+
+ // Cleanup keys.
+ int key_len = animation->track_get_key_count(i);
+ for (int j = key_len - 1; j >= 0; j--) {
+ undo_redo->add_do_method(animation.ptr(), "track_remove_key", i, j);
+ }
+
+ // Insert keys.
+ undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", i, is_using_angle ? Animation::INTERPOLATION_LINEAR_ANGLE : Animation::INTERPOLATION_LINEAR);
+ for (int j = insert_queue.size() - 1; j >= 0; j--) {
+ undo_redo->add_do_method(animation.ptr(), "track_insert_key", i, insert_queue[j].first, insert_queue[j].second);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", i, insert_queue[j].first);
+ }
+
+ // Undo methods.
+ undo_redo->add_undo_method(animation.ptr(), "track_set_interpolation_type", i, animation->track_get_interpolation_type(i));
+ for (int j = key_len - 1; j >= 0; j--) {
+ undo_redo->add_undo_method(animation.ptr(), "track_insert_key", i, animation->track_get_key_time(i, j), animation->track_get_key_value(i, j), animation->track_get_key_transition(i, j));
+ }
+ }
+ }
+
+ undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
+ undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
+ undo_redo->add_do_method(this, "_redraw_tracks");
+ undo_redo->add_undo_method(this, "_redraw_tracks");
+ undo_redo->commit_action();
+ _update_key_edit();
} break;
+
case EDIT_OPTIMIZE_ANIMATION: {
optimize_dialog->popup_centered(Size2(250, 180) * EDSCALE);
} break;
case EDIT_OPTIMIZE_ANIMATION_CONFIRM: {
- animation->optimize(optimize_linear_error->get_value(), optimize_angular_error->get_value(), optimize_max_angle->get_value());
- _update_tracks();
- undo_redo->clear_history();
+ animation->optimize(optimize_velocity_error->get_value(), optimize_angular_error->get_value(), optimize_precision_error->get_value());
+ _redraw_tracks();
+ _update_key_edit();
+ undo_redo->clear_history(true, undo_redo->get_history_id_for_object(animation.ptr()));
+ undo_redo->clear_history(true, undo_redo->get_history_id_for_object(this));
} break;
case EDIT_CLEAN_UP_ANIMATION: {
@@ -6051,7 +6381,8 @@ void AnimationTrackEditor::_cleanup_animation(Ref<Animation> p_animation) {
}
}
- undo_redo->clear_history();
+ undo_redo->clear_history(true, undo_redo->get_history_id_for_object(animation.ptr()));
+ undo_redo->clear_history(true, undo_redo->get_history_id_for_object(this));
_update_tracks();
}
@@ -6073,13 +6404,8 @@ void AnimationTrackEditor::_selection_changed() {
if (selected_filter->is_pressed()) {
_update_tracks(); // Needs updatin.
} else {
- for (int i = 0; i < track_edits.size(); i++) {
- track_edits[i]->update();
- }
-
- for (int i = 0; i < groups.size(); i++) {
- groups[i]->update();
- }
+ _redraw_tracks();
+ _redraw_groups();
}
}
@@ -6138,15 +6464,18 @@ void AnimationTrackEditor::_select_all_tracks_for_copy() {
}
void AnimationTrackEditor::_bind_methods() {
- ClassDB::bind_method("_animation_update", &AnimationTrackEditor::_animation_update);
- ClassDB::bind_method("_track_grab_focus", &AnimationTrackEditor::_track_grab_focus);
- ClassDB::bind_method("_update_tracks", &AnimationTrackEditor::_update_tracks);
- ClassDB::bind_method("_clear_selection_for_anim", &AnimationTrackEditor::_clear_selection_for_anim);
- ClassDB::bind_method("_select_at_anim", &AnimationTrackEditor::_select_at_anim);
+ ClassDB::bind_method(D_METHOD("_animation_update"), &AnimationTrackEditor::_animation_update);
+ ClassDB::bind_method(D_METHOD("_track_grab_focus"), &AnimationTrackEditor::_track_grab_focus);
+ ClassDB::bind_method(D_METHOD("_update_tracks"), &AnimationTrackEditor::_update_tracks);
+ ClassDB::bind_method(D_METHOD("_redraw_tracks"), &AnimationTrackEditor::_redraw_tracks);
+ ClassDB::bind_method(D_METHOD("_clear_selection_for_anim"), &AnimationTrackEditor::_clear_selection_for_anim);
+ ClassDB::bind_method(D_METHOD("_select_at_anim"), &AnimationTrackEditor::_select_at_anim);
- ClassDB::bind_method("_key_selected", &AnimationTrackEditor::_key_selected); // Still used by some connect_compat.
- ClassDB::bind_method("_key_deselected", &AnimationTrackEditor::_key_deselected); // Still used by some connect_compat.
- ClassDB::bind_method("_clear_selection", &AnimationTrackEditor::_clear_selection); // Still used by some connect_compat.
+ ClassDB::bind_method(D_METHOD("_key_selected"), &AnimationTrackEditor::_key_selected); // Still used by some connect_compat.
+ ClassDB::bind_method(D_METHOD("_key_deselected"), &AnimationTrackEditor::_key_deselected); // Still used by some connect_compat.
+ ClassDB::bind_method(D_METHOD("_clear_selection"), &AnimationTrackEditor::_clear_selection); // Still used by some connect_compat.
+
+ ClassDB::bind_method(D_METHOD("_bezier_track_set_key_handle_mode", "animation", "track_idx", "key_idx", "key_handle_mode", "key_handle_set_mode"), &AnimationTrackEditor::_bezier_track_set_key_handle_mode, DEFVAL(Animation::HANDLE_SET_MODE_NONE));
ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::FLOAT, "position"), PropertyInfo(Variant::BOOL, "drag"), PropertyInfo(Variant::BOOL, "timeline_only")));
ADD_SIGNAL(MethodInfo("keying_changed"));
@@ -6221,7 +6550,7 @@ void AnimationTrackEditor::_pick_track_filter_input(const Ref<InputEvent> &p_ie)
}
AnimationTrackEditor::AnimationTrackEditor() {
- undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ undo_redo = EditorNode::get_undo_redo();
main_panel = memnew(PanelContainer);
main_panel->set_focus_mode(FOCUS_ALL); // Allow panel to have focus so that shortcuts work as expected.
@@ -6298,7 +6627,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
imported_anim_warning = memnew(Button);
imported_anim_warning->hide();
imported_anim_warning->set_text(TTR("Imported Scene"));
- imported_anim_warning->set_tooltip(TTR("Warning: Editing imported animation"));
+ imported_anim_warning->set_tooltip_text(TTR("Warning: Editing imported animation"));
imported_anim_warning->connect("pressed", callable_mp(this, &AnimationTrackEditor::_show_imported_anim_warning));
bottom_hb->add_child(imported_anim_warning);
@@ -6309,7 +6638,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
bezier_edit_icon->set_disabled(true);
bezier_edit_icon->set_toggle_mode(true);
bezier_edit_icon->connect("pressed", callable_mp(this, &AnimationTrackEditor::_toggle_bezier_edit));
- bezier_edit_icon->set_tooltip(TTR("Toggle between the bezier curve editor and track editor."));
+ bezier_edit_icon->set_tooltip_text(TTR("Toggle between the bezier curve editor and track editor."));
bottom_hb->add_child(bezier_edit_icon);
@@ -6317,7 +6646,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
selected_filter->set_flat(true);
selected_filter->connect("pressed", callable_mp(this, &AnimationTrackEditor::_view_group_toggle)); // Same function works the same.
selected_filter->set_toggle_mode(true);
- selected_filter->set_tooltip(TTR("Only show tracks from nodes selected in tree."));
+ selected_filter->set_tooltip_text(TTR("Only show tracks from nodes selected in tree."));
bottom_hb->add_child(selected_filter);
@@ -6325,7 +6654,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
view_group->set_flat(true);
view_group->connect("pressed", callable_mp(this, &AnimationTrackEditor::_view_group_toggle));
view_group->set_toggle_mode(true);
- view_group->set_tooltip(TTR("Group tracks by node or display them as plain list."));
+ view_group->set_tooltip_text(TTR("Group tracks by node or display them as plain list."));
bottom_hb->add_child(view_group);
bottom_hb->add_child(memnew(VSeparator));
@@ -6344,7 +6673,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
step->set_step(0.001);
step->set_hide_slider(true);
step->set_custom_minimum_size(Size2(100, 0) * EDSCALE);
- step->set_tooltip(TTR("Animation step value."));
+ step->set_tooltip_text(TTR("Animation step value."));
bottom_hb->add_child(step);
step->connect("value_changed", callable_mp(this, &AnimationTrackEditor::_update_step));
step->set_read_only(true);
@@ -6376,13 +6705,15 @@ AnimationTrackEditor::AnimationTrackEditor() {
edit->set_text(TTR("Edit"));
edit->set_flat(false);
edit->set_disabled(true);
- edit->set_tooltip(TTR("Animation properties."));
+ edit->set_tooltip_text(TTR("Animation properties."));
edit->get_popup()->add_item(TTR("Copy Tracks"), EDIT_COPY_TRACKS);
edit->get_popup()->add_item(TTR("Paste Tracks"), EDIT_PASTE_TRACKS);
edit->get_popup()->add_separator();
edit->get_popup()->add_item(TTR("Scale Selection"), EDIT_SCALE_SELECTION);
edit->get_popup()->add_item(TTR("Scale From Cursor"), EDIT_SCALE_FROM_CURSOR);
edit->get_popup()->add_separator();
+ edit->get_popup()->add_item(TTR("Make Easing Selection"), EDIT_EASE_SELECTION);
+ edit->get_popup()->add_separator();
edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/duplicate_selection", TTR("Duplicate Selection"), KeyModifierMask::CMD | Key::D), EDIT_DUPLICATE_SELECTION);
edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/duplicate_selection_transposed", TTR("Duplicate Transposed"), KeyModifierMask::SHIFT | KeyModifierMask::CMD | Key::D), EDIT_DUPLICATE_TRANSPOSED);
edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/add_reset_value", TTR("Add RESET Value(s)")));
@@ -6395,8 +6726,9 @@ AnimationTrackEditor::AnimationTrackEditor() {
edit->get_popup()->add_separator();
edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/apply_reset", TTR("Apply Reset")), EDIT_APPLY_RESET);
edit->get_popup()->add_separator();
- edit->get_popup()->add_item(TTR("Optimize Animation"), EDIT_OPTIMIZE_ANIMATION);
- edit->get_popup()->add_item(TTR("Clean-Up Animation"), EDIT_CLEAN_UP_ANIMATION);
+ edit->get_popup()->add_item(TTR("Bake Animation"), EDIT_BAKE_ANIMATION);
+ edit->get_popup()->add_item(TTR("Optimize Animation (no undo)"), EDIT_OPTIMIZE_ANIMATION);
+ edit->get_popup()->add_item(TTR("Clean-Up Animation (no undo)"), EDIT_CLEAN_UP_ANIMATION);
edit->get_popup()->connect("id_pressed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed));
edit->get_popup()->connect("about_to_popup", callable_mp(this, &AnimationTrackEditor::_edit_menu_about_to_popup));
@@ -6456,25 +6788,24 @@ AnimationTrackEditor::AnimationTrackEditor() {
VBoxContainer *optimize_vb = memnew(VBoxContainer);
optimize_dialog->add_child(optimize_vb);
- optimize_linear_error = memnew(SpinBox);
- optimize_linear_error->set_max(1.0);
- optimize_linear_error->set_min(0.001);
- optimize_linear_error->set_step(0.001);
- optimize_linear_error->set_value(0.05);
- optimize_vb->add_margin_child(TTR("Max. Linear Error:"), optimize_linear_error);
+ optimize_velocity_error = memnew(SpinBox);
+ optimize_velocity_error->set_max(1.0);
+ optimize_velocity_error->set_min(0.001);
+ optimize_velocity_error->set_step(0.001);
+ optimize_velocity_error->set_value(0.01);
+ optimize_vb->add_margin_child(TTR("Max. Velocity Error:"), optimize_velocity_error);
optimize_angular_error = memnew(SpinBox);
optimize_angular_error->set_max(1.0);
optimize_angular_error->set_min(0.001);
optimize_angular_error->set_step(0.001);
optimize_angular_error->set_value(0.01);
-
optimize_vb->add_margin_child(TTR("Max. Angular Error:"), optimize_angular_error);
- optimize_max_angle = memnew(SpinBox);
- optimize_vb->add_margin_child(TTR("Max Optimizable Angle:"), optimize_max_angle);
- optimize_max_angle->set_max(360.0);
- optimize_max_angle->set_min(0.0);
- optimize_max_angle->set_step(0.1);
- optimize_max_angle->set_value(22);
+ optimize_precision_error = memnew(SpinBox);
+ optimize_precision_error->set_max(6);
+ optimize_precision_error->set_min(1);
+ optimize_precision_error->set_step(1);
+ optimize_precision_error->set_value(3);
+ optimize_vb->add_margin_child(TTR("Max. Precision Error:"), optimize_precision_error);
optimize_dialog->set_ok_button_text(TTR("Optimize"));
optimize_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_OPTIMIZE_ANIMATION_CONFIRM));
@@ -6518,6 +6849,88 @@ AnimationTrackEditor::AnimationTrackEditor() {
scale_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_SCALE_CONFIRM));
add_child(scale_dialog);
+ //
+ ease_dialog = memnew(ConfirmationDialog);
+ ease_dialog->set_title(TTR("Select Transition and Easing"));
+ ease_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_EASE_CONFIRM));
+ add_child(ease_dialog);
+ GridContainer *ease_grid = memnew(GridContainer);
+ ease_grid->set_columns(2);
+ ease_dialog->add_child(ease_grid);
+ transition_selection = memnew(OptionButton);
+ transition_selection->add_item("Linear", Tween::TRANS_LINEAR);
+ transition_selection->add_item("Sine", Tween::TRANS_SINE);
+ transition_selection->add_item("Quint", Tween::TRANS_QUINT);
+ transition_selection->add_item("Quart", Tween::TRANS_QUART);
+ transition_selection->add_item("Quad", Tween::TRANS_QUAD);
+ transition_selection->add_item("Expo", Tween::TRANS_EXPO);
+ transition_selection->add_item("Elastic", Tween::TRANS_ELASTIC);
+ transition_selection->add_item("Cubic", Tween::TRANS_CUBIC);
+ transition_selection->add_item("Circ", Tween::TRANS_CIRC);
+ transition_selection->add_item("Bounce", Tween::TRANS_BOUNCE);
+ transition_selection->add_item("Back", Tween::TRANS_BACK);
+ transition_selection->select(Tween::TRANS_LINEAR); // Default
+ ease_selection = memnew(OptionButton);
+ ease_selection->add_item("In", Tween::EASE_IN);
+ ease_selection->add_item("Out", Tween::EASE_OUT);
+ ease_selection->add_item("InOut", Tween::EASE_IN_OUT);
+ ease_selection->add_item("OutIn", Tween::EASE_OUT_IN);
+ ease_selection->select(Tween::EASE_IN_OUT); // Default
+ ease_fps = memnew(SpinBox);
+ ease_fps->set_min(1);
+ ease_fps->set_max(999);
+ ease_fps->set_step(1);
+ ease_fps->set_value(30); // Default
+ Label *ease_label1 = memnew(Label);
+ Label *ease_label2 = memnew(Label);
+ Label *ease_label3 = memnew(Label);
+ ease_label1->set_text("Transition Type:");
+ ease_label2->set_text("Ease Type:");
+ ease_label3->set_text("FPS:");
+ ease_grid->add_child(ease_label1);
+ ease_grid->add_child(transition_selection);
+ ease_grid->add_child(ease_label2);
+ ease_grid->add_child(ease_selection);
+ ease_grid->add_child(ease_label3);
+ ease_grid->add_child(ease_fps);
+
+ //
+ bake_dialog = memnew(ConfirmationDialog);
+ bake_dialog->set_title(TTR("Anim. Baker"));
+ bake_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_BAKE_ANIMATION_CONFIRM));
+ add_child(bake_dialog);
+ GridContainer *bake_grid = memnew(GridContainer);
+ bake_grid->set_columns(2);
+ bake_dialog->add_child(bake_grid);
+ bake_trs = memnew(CheckBox);
+ bake_trs->set_pressed(true);
+ bake_blendshape = memnew(CheckBox);
+ bake_blendshape->set_pressed(true);
+ bake_value = memnew(CheckBox);
+ bake_value->set_pressed(true);
+ bake_fps = memnew(SpinBox);
+ bake_fps->set_min(1);
+ bake_fps->set_max(999);
+ bake_fps->set_step(1);
+ bake_fps->set_value(30); // Default
+ Label *bake_label1 = memnew(Label);
+ Label *bake_label2 = memnew(Label);
+ Label *bake_label3 = memnew(Label);
+ Label *bake_label4 = memnew(Label);
+ bake_label1->set_text("Pos/Rot/Scl3D Track:");
+ bake_label2->set_text("Blendshape Track:");
+ bake_label3->set_text("Value Track:");
+ bake_label4->set_text("FPS:");
+ bake_grid->add_child(bake_label1);
+ bake_grid->add_child(bake_trs);
+ bake_grid->add_child(bake_label2);
+ bake_grid->add_child(bake_blendshape);
+ bake_grid->add_child(bake_label3);
+ bake_grid->add_child(bake_value);
+ bake_grid->add_child(bake_label4);
+ bake_grid->add_child(bake_fps);
+
+ //
track_copy_dialog = memnew(ConfirmationDialog);
add_child(track_copy_dialog);
track_copy_dialog->set_title(TTR("Select Tracks to Copy"));
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
index 9e693eaffd..ac69b88e99 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -32,11 +32,16 @@
#define ANIMATION_TRACK_EDITOR_H
#include "editor/editor_data.h"
+#include "editor/editor_properties.h"
#include "editor/editor_spin_slider.h"
#include "editor/property_selector.h"
+#include "scene/3d/node_3d.h"
+#include "scene/gui/check_box.h"
#include "scene/gui/control.h"
#include "scene/gui/menu_button.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/panel_container.h"
#include "scene/gui/scroll_bar.h"
#include "scene/gui/slider.h"
#include "scene/gui/spin_box.h"
@@ -52,6 +57,8 @@ class AnimationTimelineEdit : public Range {
GDCLASS(AnimationTimelineEdit, Range);
Ref<Animation> animation;
+ bool read_only = false;
+
AnimationTrackEdit *track_edit = nullptr;
int name_limit = 0;
Range *zoom = nullptr;
@@ -72,7 +79,7 @@ class AnimationTimelineEdit : public Range {
void _anim_loop_pressed();
void _play_position_draw();
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
Rect2 hsize_rect;
bool editing = false;
@@ -102,11 +109,11 @@ public:
float get_zoom_scale() const;
virtual Size2 get_minimum_size() const override;
- void set_animation(const Ref<Animation> &p_animation);
+ void set_animation(const Ref<Animation> &p_animation, bool p_read_only);
void set_track_edit(AnimationTrackEdit *p_track_edit);
void set_zoom(Range *p_zoom);
Range *get_zoom() const { return zoom; }
- void set_undo_redo(UndoRedo *p_undo_redo);
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void set_play_position(float p_pos);
float get_play_position() const;
@@ -137,6 +144,8 @@ class AnimationTrackEdit : public Control {
MENU_INTERPOLATION_NEAREST,
MENU_INTERPOLATION_LINEAR,
MENU_INTERPOLATION_CUBIC,
+ MENU_INTERPOLATION_LINEAR_ANGLE,
+ MENU_INTERPOLATION_CUBIC_ANGLE,
MENU_LOOP_WRAP,
MENU_LOOP_CLAMP,
MENU_KEY_INSERT,
@@ -146,7 +155,7 @@ class AnimationTrackEdit : public Control {
};
AnimationTimelineEdit *timeline = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
Popup *path_popup = nullptr;
LineEdit *path = nullptr;
Node *root = nullptr;
@@ -155,6 +164,7 @@ class AnimationTrackEdit : public Control {
NodePath node_path;
Ref<Animation> animation;
+ bool read_only = false;
int track = 0;
Rect2 check_rect;
@@ -226,12 +236,12 @@ public:
Ref<Animation> get_animation() const;
AnimationTimelineEdit *get_timeline() const { return timeline; }
AnimationTrackEditor *get_editor() const { return editor; }
- UndoRedo *get_undo_redo() const { return undo_redo; }
+ Ref<EditorUndoRedoManager> get_undo_redo() const;
NodePath get_path() const;
- void set_animation_and_track(const Ref<Animation> &p_animation, int p_track);
+ void set_animation_and_track(const Ref<Animation> &p_animation, int p_track, bool p_read_only);
virtual Size2 get_minimum_size() const override;
- void set_undo_redo(UndoRedo *p_undo_redo);
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void set_timeline(AnimationTimelineEdit *p_timeline);
void set_editor(AnimationTrackEditor *p_editor);
void set_root(Node *p_root);
@@ -286,6 +296,7 @@ class AnimationTrackEditor : public VBoxContainer {
GDCLASS(AnimationTrackEditor, VBoxContainer);
Ref<Animation> animation;
+ bool read_only = false;
Node *root = nullptr;
MenuButton *edit = nullptr;
@@ -314,10 +325,13 @@ class AnimationTrackEditor : public VBoxContainer {
Vector<AnimationTrackEditGroup *> groups;
bool animation_changing_awaiting_update = false;
- void _animation_update();
+ void _animation_update(); // Updated by AnimationTrackEditor(this)
int _get_track_selected();
+ void _sync_animation_change();
void _animation_changed();
void _update_tracks();
+ void _redraw_tracks();
+ void _redraw_groups();
void _name_limit_changed();
void _timeline_changed(float p_new_pos, bool p_drag, bool p_timeline_only);
@@ -325,7 +339,7 @@ class AnimationTrackEditor : public VBoxContainer {
void _animation_track_remove_request(int p_track, Ref<Animation> p_from_animation);
void _track_grab_focus(int p_track);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
void _update_scroll(double);
void _update_step(double p_new_step);
@@ -439,13 +453,20 @@ class AnimationTrackEditor : public VBoxContainer {
void _toggle_bezier_edit();
void _cancel_bezier_edit();
void _bezier_edit(int p_for_track);
+ void _bezier_track_set_key_handle_mode(Animation *p_anim, int p_track, int p_index, Animation::HandleMode p_mode, Animation::HandleSetMode p_set_mode = Animation::HANDLE_SET_MODE_NONE);
////////////// edit menu stuff
+ ConfirmationDialog *bake_dialog = nullptr;
+ CheckBox *bake_trs = nullptr;
+ CheckBox *bake_blendshape = nullptr;
+ CheckBox *bake_value = nullptr;
+ SpinBox *bake_fps = nullptr;
+
ConfirmationDialog *optimize_dialog = nullptr;
- SpinBox *optimize_linear_error = nullptr;
+ SpinBox *optimize_velocity_error = nullptr;
SpinBox *optimize_angular_error = nullptr;
- SpinBox *optimize_max_angle = nullptr;
+ SpinBox *optimize_precision_error = nullptr;
ConfirmationDialog *cleanup_dialog = nullptr;
CheckBox *cleanup_keys = nullptr;
@@ -455,6 +476,11 @@ class AnimationTrackEditor : public VBoxContainer {
ConfirmationDialog *scale_dialog = nullptr;
SpinBox *scale = nullptr;
+ ConfirmationDialog *ease_dialog = nullptr;
+ OptionButton *transition_selection = nullptr;
+ OptionButton *ease_selection = nullptr;
+ SpinBox *ease_fps = nullptr;
+
void _select_all_tracks_for_copy();
void _edit_menu_about_to_popup();
@@ -478,9 +504,9 @@ class AnimationTrackEditor : public VBoxContainer {
NodePath full_path;
NodePath base_path;
Animation::TrackType track_type = Animation::TYPE_ANIMATION;
- Animation::InterpolationType interp_type = Animation::INTERPOLATION_CUBIC;
+ Animation::InterpolationType interp_type = Animation::INTERPOLATION_CUBIC_ANGLE;
Animation::UpdateMode update_mode = Animation::UPDATE_CAPTURE;
- Animation::LoopMode loop_mode = Animation::LOOP_LINEAR;
+ Animation::LoopMode loop_mode = Animation::LOOP_PINGPONG;
bool loop_wrap = false;
bool enabled = false;
@@ -512,6 +538,8 @@ public:
EDIT_SCALE_SELECTION,
EDIT_SCALE_FROM_CURSOR,
EDIT_SCALE_CONFIRM,
+ EDIT_EASE_SELECTION,
+ EDIT_EASE_CONFIRM,
EDIT_DUPLICATE_SELECTION,
EDIT_DUPLICATE_TRANSPOSED,
EDIT_ADD_RESET_KEY,
@@ -520,6 +548,8 @@ public:
EDIT_GOTO_NEXT_STEP_TIMELINE_ONLY, // Next step without updating animation.
EDIT_GOTO_PREV_STEP,
EDIT_APPLY_RESET,
+ EDIT_BAKE_ANIMATION,
+ EDIT_BAKE_ANIMATION_CONFIRM,
EDIT_OPTIMIZE_ANIMATION,
EDIT_OPTIMIZE_ANIMATION_CONFIRM,
EDIT_CLEAN_UP_ANIMATION,
@@ -529,7 +559,7 @@ public:
void add_track_edit_plugin(const Ref<AnimationTrackEditPlugin> &p_plugin);
void remove_track_edit_plugin(const Ref<AnimationTrackEditPlugin> &p_plugin);
- void set_animation(const Ref<Animation> &p_anim);
+ void set_animation(const Ref<Animation> &p_anim, bool p_read_only);
Ref<Animation> get_current_animation() const;
void set_root(Node *p_root);
Node *get_root() const;
diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp
index cd40b53919..ab64aaa24d 100644
--- a/editor/animation_track_editor_plugins.cpp
+++ b/editor/animation_track_editor_plugins.cpp
@@ -33,6 +33,7 @@
#include "editor/audio_stream_preview.h"
#include "editor/editor_resource_preview.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/2d/animated_sprite_2d.h"
#include "scene/2d/sprite_2d.h"
#include "scene/3d/sprite_3d.h"
diff --git a/editor/array_property_edit.cpp b/editor/array_property_edit.cpp
index 58527ee4d1..ab0e801c88 100644
--- a/editor/array_property_edit.cpp
+++ b/editor/array_property_edit.cpp
@@ -32,6 +32,7 @@
#include "core/io/marshalls.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
#define ITEMS_PER_PAGE 100
@@ -87,7 +88,7 @@ bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) {
return true;
}
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Resize Array"));
ur->add_do_method(this, "_set_size", newsize);
ur->add_undo_method(this, "_set_size", size);
@@ -134,7 +135,7 @@ bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) {
Callable::CallError ce;
Variant new_value;
Variant::construct(Variant::Type(type), new_value, nullptr, 0, ce);
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Array Value Type"));
ur->add_do_method(this, "_set_value", idx, new_value);
@@ -150,7 +151,7 @@ bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) {
Variant arr = get_array();
Variant value = arr.get(idx);
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Array Value"));
ur->add_do_method(this, "_set_value", idx, p_value);
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index 99ca82b311..2b1584b20c 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -1045,6 +1045,8 @@ void CodeTextEditor::update_editor_settings() {
guideline_cols.append(EditorSettings::get_singleton()->get("text_editor/appearance/guidelines/line_length_guideline_soft_column"));
}
text_editor->set_line_length_guidelines(guideline_cols);
+ } else {
+ text_editor->set_line_length_guidelines(TypedArray<int>());
}
}
@@ -1787,7 +1789,7 @@ void CodeTextEditor::toggle_bookmark() {
}
void CodeTextEditor::goto_next_bookmark() {
- Array bmarks = text_editor->get_bookmarked_lines();
+ PackedInt32Array bmarks = text_editor->get_bookmarked_lines();
if (bmarks.size() <= 0) {
return;
}
@@ -1811,7 +1813,7 @@ void CodeTextEditor::goto_next_bookmark() {
}
void CodeTextEditor::goto_prev_bookmark() {
- Array bmarks = text_editor->get_bookmarked_lines();
+ PackedInt32Array bmarks = text_editor->get_bookmarked_lines();
if (bmarks.size() <= 0) {
return;
}
@@ -1860,14 +1862,15 @@ void CodeTextEditor::update_toggle_scripts_button() {
} else {
toggle_scripts_button->set_icon(get_theme_icon(ScriptEditor::get_singleton()->is_scripts_panel_toggled() ? SNAME("Back") : SNAME("Forward"), SNAME("EditorIcons")));
}
- toggle_scripts_button->set_tooltip(vformat("%s (%s)", TTR("Toggle Scripts Panel"), ED_GET_SHORTCUT("script_editor/toggle_scripts_panel")->get_as_text()));
+ toggle_scripts_button->set_tooltip_text(vformat("%s (%s)", TTR("Toggle Scripts Panel"), ED_GET_SHORTCUT("script_editor/toggle_scripts_panel")->get_as_text()));
}
CodeTextEditor::CodeTextEditor() {
code_complete_func = nullptr;
ED_SHORTCUT("script_editor/zoom_in", TTR("Zoom In"), KeyModifierMask::CMD | Key::EQUAL);
ED_SHORTCUT("script_editor/zoom_out", TTR("Zoom Out"), KeyModifierMask::CMD | Key::MINUS);
- ED_SHORTCUT("script_editor/reset_zoom", TTR("Reset Zoom"), KeyModifierMask::CMD | Key::KEY_0);
+ ED_SHORTCUT_ARRAY("script_editor/reset_zoom", TTR("Reset Zoom"),
+ { int32_t(KeyModifierMask::CMD | Key::KEY_0), int32_t(KeyModifierMask::CMD | Key::KP_0) });
text_editor = memnew(CodeEdit);
add_child(text_editor);
@@ -1952,7 +1955,7 @@ CodeTextEditor::CodeTextEditor() {
error_button->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER);
error_button->set_default_cursor_shape(CURSOR_POINTING_HAND);
error_button->connect("pressed", callable_mp(this, &CodeTextEditor::_error_button_pressed));
- error_button->set_tooltip(TTR("Errors"));
+ error_button->set_tooltip_text(TTR("Errors"));
set_error_count(0);
// Warnings
@@ -1962,14 +1965,14 @@ CodeTextEditor::CodeTextEditor() {
warning_button->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER);
warning_button->set_default_cursor_shape(CURSOR_POINTING_HAND);
warning_button->connect("pressed", callable_mp(this, &CodeTextEditor::_warning_button_pressed));
- warning_button->set_tooltip(TTR("Warnings"));
+ warning_button->set_tooltip_text(TTR("Warnings"));
set_warning_count(0);
// Line and column
line_and_col_txt = memnew(Label);
status_bar->add_child(line_and_col_txt);
line_and_col_txt->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER);
- line_and_col_txt->set_tooltip(TTR("Line and column numbers."));
+ line_and_col_txt->set_tooltip_text(TTR("Line and column numbers."));
line_and_col_txt->set_mouse_filter(MOUSE_FILTER_STOP);
text_editor->connect("gui_input", callable_mp(this, &CodeTextEditor::_text_editor_gui_input));
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index 6fdd9563fb..587c16c229 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -34,6 +34,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/scene_tree_dock.h"
#include "plugins/script_editor_plugin.h"
@@ -459,7 +460,7 @@ ConnectDialog::ConnectDialog() {
vbc_right->add_margin_child(TTR("Extra Call Arguments:"), bind_editor, true);
unbind_count = memnew(SpinBox);
- unbind_count->set_tooltip(TTR("Allows to drop arguments sent by signal emitter."));
+ unbind_count->set_tooltip_text(TTR("Allows to drop arguments sent by signal emitter."));
unbind_count->connect("value_changed", callable_mp(this, &ConnectDialog::_unbind_count_changed));
vbc_right->add_margin_child(TTR("Unbind Signal Arguments:"), unbind_count);
@@ -480,13 +481,13 @@ ConnectDialog::ConnectDialog() {
deferred = memnew(CheckBox);
deferred->set_h_size_flags(0);
deferred->set_text(TTR("Deferred"));
- deferred->set_tooltip(TTR("Defers the signal, storing it in a queue and only firing it at idle time."));
+ deferred->set_tooltip_text(TTR("Defers the signal, storing it in a queue and only firing it at idle time."));
vbc_right->add_child(deferred);
oneshot = memnew(CheckBox);
oneshot->set_h_size_flags(0);
oneshot->set_text(TTR("Oneshot"));
- oneshot->set_tooltip(TTR("Disconnects the signal after its first emission."));
+ oneshot->set_tooltip_text(TTR("Disconnects the signal after its first emission."));
vbc_right->add_child(oneshot);
cdbinds = memnew(ConnectDialogBinds);
@@ -839,6 +840,9 @@ void ConnectionsDock::_handle_signal_menu_option(int p_option) {
disconnect_all_dialog->set_text(vformat(TTR("Are you sure you want to remove all connections from the \"%s\" signal?"), signal_name));
disconnect_all_dialog->popup_centered();
} break;
+ case COPY_NAME: {
+ DisplayServer::get_singleton()->clipboard_set(item->get_metadata(0).operator Dictionary()["name"]);
+ } break;
}
}
@@ -924,6 +928,10 @@ void ConnectionsDock::_bind_methods() {
ClassDB::bind_method("update_tree", &ConnectionsDock::update_tree);
}
+void ConnectionsDock::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
+ undo_redo = p_undo_redo;
+}
+
void ConnectionsDock::set_node(Node *p_node) {
selected_node = p_node;
update_tree();
@@ -1159,6 +1167,7 @@ ConnectionsDock::ConnectionsDock() {
signal_menu->connect("id_pressed", callable_mp(this, &ConnectionsDock::_handle_signal_menu_option));
signal_menu->add_item(TTR("Connect..."), CONNECT);
signal_menu->add_item(TTR("Disconnect All"), DISCONNECT_ALL);
+ signal_menu->add_item(TTR("Copy Name"), COPY_NAME);
slot_menu = memnew(PopupMenu);
add_child(slot_menu);
diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h
index d141d1a880..352c5c99d6 100644
--- a/editor/connections_dialog.h
+++ b/editor/connections_dialog.h
@@ -31,7 +31,6 @@
#ifndef CONNECTIONS_DIALOG_H
#define CONNECTIONS_DIALOG_H
-#include "core/object/undo_redo.h"
#include "editor/editor_inspector.h"
#include "editor/scene_tree_editor.h"
#include "scene/gui/button.h"
@@ -48,6 +47,7 @@
#include "scene/gui/tree.h"
class ConnectDialogBinds;
+class EditorUndoRedoManager;
class ConnectDialog : public ConfirmationDialog {
GDCLASS(ConnectDialog, ConfirmationDialog);
@@ -177,13 +177,14 @@ class ConnectionsDock : public VBoxContainer {
//Right-click Pop-up Menu Options.
enum SignalMenuOption {
CONNECT,
- DISCONNECT_ALL
+ DISCONNECT_ALL,
+ COPY_NAME,
};
enum SlotMenuOption {
EDIT,
GO_TO_SCRIPT,
- DISCONNECT
+ DISCONNECT,
};
Node *selected_node = nullptr;
@@ -194,7 +195,7 @@ class ConnectionsDock : public VBoxContainer {
Button *connect_button = nullptr;
PopupMenu *signal_menu = nullptr;
PopupMenu *slot_menu = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
LineEdit *search_box = nullptr;
HashMap<StringName, HashMap<StringName, String>> descr_cache;
@@ -225,7 +226,7 @@ protected:
static void _bind_methods();
public:
- void set_undoredo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; }
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void set_node(Node *p_node);
void update_tree();
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index e6168f4924..7e5b818307 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -38,7 +38,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
-void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode, const String &p_select_type) {
+void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode, const String &p_select_type, const String &p_select_name) {
_fill_type_list();
icon_fallback = search_options->has_theme_icon(base_type, SNAME("EditorIcons")) ? base_type : "Object";
@@ -57,7 +57,11 @@ void CreateDialog::popup_create(bool p_dont_clear, bool p_replace_mode, const St
_update_search();
if (p_replace_mode) {
- set_title(vformat(TTR("Change %s Type"), base_type));
+ if (!p_select_name.is_empty()) {
+ set_title(vformat(TTR("Convert %s from %s"), p_select_name, p_select_type));
+ } else {
+ set_title(vformat(TTR("Convert %s"), p_select_type));
+ }
set_ok_button_text(TTR("Change"));
} else {
set_title(vformat(TTR("Create New %s"), base_type));
@@ -379,7 +383,7 @@ void CreateDialog::_confirmed() {
}
{
- Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("create_recent." + base_type), FileAccess::WRITE);
+ Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("create_recent." + base_type), FileAccess::WRITE);
if (f.is_valid()) {
f->store_line(selected_item);
@@ -656,7 +660,7 @@ void CreateDialog::_save_and_update_favorite_list() {
TreeItem *root = favorites->create_item();
{
- Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("favorites." + base_type), FileAccess::WRITE);
+ Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites." + base_type), FileAccess::WRITE);
if (f.is_valid()) {
for (int i = 0; i < favorite_list.size(); i++) {
String l = favorite_list[i];
@@ -682,7 +686,7 @@ void CreateDialog::_save_and_update_favorite_list() {
void CreateDialog::_load_favorites_and_history() {
String dir = EditorPaths::get_singleton()->get_project_settings_dir();
- Ref<FileAccess> f = FileAccess::open(dir.plus_file("create_recent." + base_type), FileAccess::READ);
+ Ref<FileAccess> f = FileAccess::open(dir.path_join("create_recent." + base_type), FileAccess::READ);
if (f.is_valid()) {
while (!f->eof_reached()) {
String l = f->get_line().strip_edges();
@@ -694,7 +698,7 @@ void CreateDialog::_load_favorites_and_history() {
}
}
- f = FileAccess::open(dir.plus_file("favorites." + base_type), FileAccess::READ);
+ f = FileAccess::open(dir.path_join("favorites." + base_type), FileAccess::READ);
if (f.is_valid()) {
while (!f->eof_reached()) {
String l = f->get_line().strip_edges();
@@ -776,7 +780,7 @@ CreateDialog::CreateDialog() {
favorite = memnew(Button);
favorite->set_toggle_mode(true);
- favorite->set_tooltip(TTR("(Un)favorite selected item."));
+ favorite->set_tooltip_text(TTR("(Un)favorite selected item."));
favorite->connect("pressed", callable_mp(this, &CreateDialog::_favorite_toggled));
search_hb->add_child(favorite);
vbc->add_margin_child(TTR("Search:"), search_hb);
diff --git a/editor/create_dialog.h b/editor/create_dialog.h
index 04094108ad..f7731d2726 100644
--- a/editor/create_dialog.h
+++ b/editor/create_dialog.h
@@ -120,7 +120,7 @@ public:
void set_preferred_search_result_type(const String &p_preferred_type) { preferred_search_result_type = p_preferred_type; }
String get_preferred_search_result_type() { return preferred_search_result_type; }
- void popup_create(bool p_dont_clear, bool p_replace_mode = false, const String &p_select_type = "Node");
+ void popup_create(bool p_dont_clear, bool p_replace_mode = false, const String &p_select_type = "Node", const String &p_select_name = "");
CreateDialog();
};
diff --git a/editor/debugger/debug_adapter/debug_adapter_parser.cpp b/editor/debugger/debug_adapter/debug_adapter_parser.cpp
index 3c3e4faa6f..ac41306cde 100644
--- a/editor/debugger/debug_adapter/debug_adapter_parser.cpp
+++ b/editor/debugger/debug_adapter/debug_adapter_parser.cpp
@@ -201,7 +201,7 @@ Dictionary DebugAdapterParser::req_launch(const Dictionary &p_params) const {
}
} else if (platform_string == "web") {
for (int i = 0; i < EditorExport::get_singleton()->get_export_platform_count(); i++) {
- if (EditorExport::get_singleton()->get_export_platform(i)->get_name() == "HTML5") {
+ if (EditorExport::get_singleton()->get_export_platform(i)->get_name() == "Web") {
idx = i;
break;
}
diff --git a/editor/debugger/editor_debugger_inspector.cpp b/editor/debugger/editor_debugger_inspector.cpp
index 58206efc20..6c0ba55ec8 100644
--- a/editor/debugger/editor_debugger_inspector.cpp
+++ b/editor/debugger/editor_debugger_inspector.cpp
@@ -85,6 +85,7 @@ void EditorDebuggerRemoteObject::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_variant"), &EditorDebuggerRemoteObject::get_variant);
ClassDB::bind_method(D_METHOD("clear"), &EditorDebuggerRemoteObject::clear);
ClassDB::bind_method(D_METHOD("get_remote_object_id"), &EditorDebuggerRemoteObject::get_remote_object_id);
+ ClassDB::bind_method(D_METHOD("_is_read_only"), &EditorDebuggerRemoteObject::_is_read_only);
ADD_SIGNAL(MethodInfo("value_edited", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::STRING, "property"), PropertyInfo("value")));
}
diff --git a/editor/debugger/editor_debugger_inspector.h b/editor/debugger/editor_debugger_inspector.h
index 5aac4dbf11..c595e0acaa 100644
--- a/editor/debugger/editor_debugger_inspector.h
+++ b/editor/debugger/editor_debugger_inspector.h
@@ -50,6 +50,7 @@ public:
HashMap<StringName, Variant> prop_values;
ObjectID get_remote_object_id() { return remote_object_id; };
+ bool _is_read_only() { return true; };
String get_title();
Variant get_variant(const StringName &p_name);
diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp
index 472e53c0e8..9fd7fa578f 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -30,6 +30,7 @@
#include "editor_debugger_node.h"
+#include "core/object/undo_redo.h"
#include "editor/debugger/editor_debugger_tree.h"
#include "editor/debugger/script_editor_debugger.h"
#include "editor/editor_log.h"
@@ -83,8 +84,6 @@ EditorDebuggerNode::EditorDebuggerNode() {
inspect_edited_object_timeout = EDITOR_DEF("debugger/remote_inspect_refresh_interval", 0.2);
EditorNode *editor = EditorNode::get_singleton();
- editor->get_undo_redo()->set_method_notify_callback(_method_changeds, this);
- editor->get_undo_redo()->set_property_notify_callback(_property_changeds, this);
editor->get_pause_button()->connect("pressed", callable_mp(this, &EditorDebuggerNode::_paused));
}
@@ -181,6 +180,11 @@ void EditorDebuggerNode::_bind_methods() {
ADD_SIGNAL(MethodInfo("breakpoint_toggled", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "line"), PropertyInfo(Variant::BOOL, "enabled")));
}
+void EditorDebuggerNode::register_undo_redo(UndoRedo *p_undo_redo) {
+ p_undo_redo->set_method_notify_callback(_method_changeds, this);
+ p_undo_redo->set_property_notify_callback(_property_changeds, this);
+}
+
EditorDebuggerRemoteObject *EditorDebuggerNode::get_inspected_remote_object() {
return Object::cast_to<EditorDebuggerRemoteObject>(ObjectDB::get_instance(EditorNode::get_singleton()->get_editor_selection_history()->get_current()));
}
diff --git a/editor/debugger/editor_debugger_node.h b/editor/debugger/editor_debugger_node.h
index 4c9ad49ac4..e79e60b180 100644
--- a/editor/debugger/editor_debugger_node.h
+++ b/editor/debugger/editor_debugger_node.h
@@ -41,6 +41,7 @@ class EditorDebuggerRemoteObject;
class MenuButton;
class ScriptEditorDebugger;
class TabContainer;
+class UndoRedo;
class EditorDebuggerNode : public MarginContainer {
GDCLASS(EditorDebuggerNode, MarginContainer);
@@ -152,6 +153,7 @@ protected:
public:
static EditorDebuggerNode *get_singleton() { return singleton; }
+ void register_undo_redo(UndoRedo *p_undo_redo);
ScriptEditorDebugger *get_current_debugger() const;
ScriptEditorDebugger *get_default_debugger() const;
diff --git a/editor/debugger/editor_profiler.cpp b/editor/debugger/editor_profiler.cpp
index 28b5d4be15..b49cab9df7 100644
--- a/editor/debugger/editor_profiler.cpp
+++ b/editor/debugger/editor_profiler.cpp
@@ -607,7 +607,7 @@ EditorProfiler::EditorProfiler() {
display_time = memnew(OptionButton);
display_time->add_item(TTR("Inclusive"));
display_time->add_item(TTR("Self"));
- display_time->set_tooltip(TTR("Inclusive: Includes time from other functions called by this function.\nUse this to spot bottlenecks.\n\nSelf: Only count the time spent in the function itself, not in other functions called by that function.\nUse this to find individual functions to optimize."));
+ display_time->set_tooltip_text(TTR("Inclusive: Includes time from other functions called by this function.\nUse this to spot bottlenecks.\n\nSelf: Only count the time spent in the function itself, not in other functions called by that function.\nUse this to find individual functions to optimize."));
display_time->connect("item_selected", callable_mp(this, &EditorProfiler::_combo_changed));
hb->add_child(display_time);
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index ac2e958c5b..fab211f18c 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -369,7 +369,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da
}
}
- vmem_total->set_tooltip(TTR("Bytes:") + " " + itos(total));
+ vmem_total->set_tooltip_text(TTR("Bytes:") + " " + itos(total));
vmem_total->set_text(String::humanize_size(total));
} else if (p_msg == "stack_dump") {
@@ -776,7 +776,7 @@ void ScriptEditorDebugger::_set_reason_text(const String &p_reason, MessageType
reason->add_theme_color_override("font_color", get_theme_color(SNAME("success_color"), SNAME("Editor")));
}
reason->set_text(p_reason);
- reason->set_tooltip(p_reason.word_wrap(80));
+ reason->set_tooltip_text(p_reason.word_wrap(80));
}
void ScriptEditorDebugger::_notification(int p_what) {
@@ -964,7 +964,7 @@ void ScriptEditorDebugger::stop() {
peer->close();
peer.unref();
reason->set_text("");
- reason->set_tooltip("");
+ reason->set_tooltip_text("");
}
node_path_cache.clear();
@@ -1706,7 +1706,7 @@ ScriptEditorDebugger::ScriptEditorDebugger() {
skip_breakpoints = memnew(Button);
skip_breakpoints->set_flat(true);
hbc->add_child(skip_breakpoints);
- skip_breakpoints->set_tooltip(TTR("Skip Breakpoints"));
+ skip_breakpoints->set_tooltip_text(TTR("Skip Breakpoints"));
skip_breakpoints->connect("pressed", callable_mp(this, &ScriptEditorDebugger::debug_skip_breakpoints));
hbc->add_child(memnew(VSeparator));
@@ -1714,7 +1714,7 @@ ScriptEditorDebugger::ScriptEditorDebugger() {
copy = memnew(Button);
copy->set_flat(true);
hbc->add_child(copy);
- copy->set_tooltip(TTR("Copy Error"));
+ copy->set_tooltip_text(TTR("Copy Error"));
copy->connect("pressed", callable_mp(this, &ScriptEditorDebugger::debug_copy));
hbc->add_child(memnew(VSeparator));
@@ -1722,14 +1722,14 @@ ScriptEditorDebugger::ScriptEditorDebugger() {
step = memnew(Button);
step->set_flat(true);
hbc->add_child(step);
- step->set_tooltip(TTR("Step Into"));
+ step->set_tooltip_text(TTR("Step Into"));
step->set_shortcut(ED_GET_SHORTCUT("debugger/step_into"));
step->connect("pressed", callable_mp(this, &ScriptEditorDebugger::debug_step));
next = memnew(Button);
next->set_flat(true);
hbc->add_child(next);
- next->set_tooltip(TTR("Step Over"));
+ next->set_tooltip_text(TTR("Step Over"));
next->set_shortcut(ED_GET_SHORTCUT("debugger/step_over"));
next->connect("pressed", callable_mp(this, &ScriptEditorDebugger::debug_next));
@@ -1738,14 +1738,14 @@ ScriptEditorDebugger::ScriptEditorDebugger() {
dobreak = memnew(Button);
dobreak->set_flat(true);
hbc->add_child(dobreak);
- dobreak->set_tooltip(TTR("Break"));
+ dobreak->set_tooltip_text(TTR("Break"));
dobreak->set_shortcut(ED_GET_SHORTCUT("debugger/break"));
dobreak->connect("pressed", callable_mp(this, &ScriptEditorDebugger::debug_break));
docontinue = memnew(Button);
docontinue->set_flat(true);
hbc->add_child(docontinue);
- docontinue->set_tooltip(TTR("Continue"));
+ docontinue->set_tooltip_text(TTR("Continue"));
docontinue->set_shortcut(ED_GET_SHORTCUT("debugger/continue"));
docontinue->connect("pressed", callable_mp(this, &ScriptEditorDebugger::debug_continue));
@@ -1917,7 +1917,7 @@ ScriptEditorDebugger::ScriptEditorDebugger() {
vmem_hb->add_child(vmem_refresh);
vmem_export = memnew(Button);
vmem_export->set_flat(true);
- vmem_export->set_tooltip(TTR("Export list to a CSV file"));
+ vmem_export->set_tooltip_text(TTR("Export list to a CSV file"));
vmem_hb->add_child(vmem_export);
vmem_vb->add_child(vmem_hb);
vmem_refresh->connect("pressed", callable_mp(this, &ScriptEditorDebugger::_video_mem_request));
@@ -1959,15 +1959,18 @@ ScriptEditorDebugger::ScriptEditorDebugger() {
info_left->set_columns(2);
misc->add_child(info_left);
clicked_ctrl = memnew(LineEdit);
+ clicked_ctrl->set_editable(false);
clicked_ctrl->set_h_size_flags(SIZE_EXPAND_FILL);
info_left->add_child(memnew(Label(TTR("Clicked Control:"))));
info_left->add_child(clicked_ctrl);
clicked_ctrl_type = memnew(LineEdit);
+ clicked_ctrl_type->set_editable(false);
info_left->add_child(memnew(Label(TTR("Clicked Control Type:"))));
info_left->add_child(clicked_ctrl_type);
scene_tree = memnew(SceneDebuggerTree);
live_edit_root = memnew(LineEdit);
+ live_edit_root->set_editable(false);
live_edit_root->set_h_size_flags(SIZE_EXPAND_FILL);
{
diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp
index 5b4da0e32b..43961a7ceb 100644
--- a/editor/dependency_editor.cpp
+++ b/editor/dependency_editor.cpp
@@ -417,6 +417,45 @@ void DependencyRemoveDialog::_find_all_removed_dependencies(EditorFileSystemDire
}
}
+void DependencyRemoveDialog::_find_localization_remaps_of_removed_files(Vector<RemovedDependency> &p_removed) {
+ for (KeyValue<String, String> &files : all_remove_files) {
+ const String &path = files.key;
+
+ // Look for dependencies in the translation remaps.
+ if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/translation_remaps")) {
+ Dictionary remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
+
+ if (remaps.has(path)) {
+ RemovedDependency dep;
+ dep.file = TTR("Localization remap");
+ dep.file_type = "";
+ dep.dependency = path;
+ dep.dependency_folder = files.value;
+ p_removed.push_back(dep);
+ }
+
+ Array remap_keys = remaps.keys();
+ for (int j = 0; j < remap_keys.size(); j++) {
+ PackedStringArray remapped_files = remaps[remap_keys[j]];
+ for (int k = 0; k < remapped_files.size(); k++) {
+ int splitter_pos = remapped_files[k].rfind(":");
+ String res_path = remapped_files[k].substr(0, splitter_pos);
+ if (res_path == path) {
+ String locale_name = remapped_files[k].substr(splitter_pos + 1);
+
+ RemovedDependency dep;
+ dep.file = vformat(TTR("Localization remap for path '%s' and locale '%s'."), remap_keys[j], locale_name);
+ dep.file_type = "";
+ dep.dependency = path;
+ dep.dependency_folder = files.value;
+ p_removed.push_back(dep);
+ }
+ }
+ }
+ }
+ }
+}
+
void DependencyRemoveDialog::_build_removed_dependency_tree(const Vector<RemovedDependency> &p_removed) {
owners->clear();
owners->create_item(); // root
@@ -473,6 +512,7 @@ void DependencyRemoveDialog::show(const Vector<String> &p_folders, const Vector<
Vector<RemovedDependency> removed_deps;
_find_all_removed_dependencies(EditorFileSystem::get_singleton()->get_filesystem(), removed_deps);
+ _find_localization_remaps_of_removed_files(removed_deps);
removed_deps.sort();
if (removed_deps.is_empty()) {
owners->hide();
diff --git a/editor/dependency_editor.h b/editor/dependency_editor.h
index 96d82d58eb..6e39015ec3 100644
--- a/editor/dependency_editor.h
+++ b/editor/dependency_editor.h
@@ -119,6 +119,7 @@ class DependencyRemoveDialog : public ConfirmationDialog {
void _find_files_in_removed_folder(EditorFileSystemDirectory *efsd, const String &p_folder);
void _find_all_removed_dependencies(EditorFileSystemDirectory *efsd, Vector<RemovedDependency> &p_removed);
+ void _find_localization_remaps_of_removed_files(Vector<RemovedDependency> &p_removed);
void _build_removed_dependency_tree(const Vector<RemovedDependency> &p_removed);
void ok_pressed() override;
diff --git a/editor/dictionary_property_edit.cpp b/editor/dictionary_property_edit.cpp
index 630265e268..f16c5402ad 100644
--- a/editor/dictionary_property_edit.cpp
+++ b/editor/dictionary_property_edit.cpp
@@ -30,6 +30,7 @@
#include "dictionary_property_edit.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
void DictionaryPropertyEdit::_notif_change() {
notify_property_list_changed();
@@ -118,7 +119,7 @@ bool DictionaryPropertyEdit::_set(const StringName &p_name, const Variant &p_val
int index = pn.substr(0, slash).to_int();
if (type == "key" && index < keys.size()) {
const Variant &key = keys[index];
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Dictionary Key"));
ur->add_do_method(this, "_set_key", key, p_value);
@@ -130,7 +131,7 @@ bool DictionaryPropertyEdit::_set(const StringName &p_name, const Variant &p_val
const Variant &key = keys[index];
if (dict.has(key)) {
Variant value = dict[key];
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Dictionary Value"));
ur->add_do_method(this, "_set_value", key, p_value);
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index a819458417..ec9a744e57 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -41,6 +41,7 @@
#include "core/version.h"
#include "editor/editor_settings.h"
#include "scene/resources/theme.h"
+#include "scene/theme/theme_db.h"
// Used for a hack preserving Mono properties on non-Mono builds.
#include "modules/modules_enabled.gen.h" // For mono.
@@ -337,311 +338,318 @@ static Variant get_documentation_default_value(const StringName &p_class_name, c
}
void DocTools::generate(bool p_basic_types) {
- List<StringName> classes;
- ClassDB::get_class_list(&classes);
- classes.sort_custom<StringName::AlphCompare>();
- // Move ProjectSettings, so that other classes can register properties there.
- classes.move_to_back(classes.find("ProjectSettings"));
-
- bool skip_setter_getter_methods = true;
-
- while (classes.size()) {
- HashSet<StringName> setters_getters;
-
- String name = classes.front()->get();
- if (!ClassDB::is_class_exposed(name)) {
- print_verbose(vformat("Class '%s' is not exposed, skipping.", name));
- classes.pop_front();
- continue;
- }
-
- String cname = name;
-
- class_list[cname] = DocData::ClassDoc();
- DocData::ClassDoc &c = class_list[cname];
- c.name = cname;
- c.inherits = ClassDB::get_parent_class(name);
+ // Add ClassDB-exposed classes.
+ {
+ List<StringName> classes;
+ ClassDB::get_class_list(&classes);
+ classes.sort_custom<StringName::AlphCompare>();
+ // Move ProjectSettings, so that other classes can register properties there.
+ classes.move_to_back(classes.find("ProjectSettings"));
+
+ bool skip_setter_getter_methods = true;
+
+ // Populate documentation data for each exposed class.
+ while (classes.size()) {
+ String name = classes.front()->get();
+ if (!ClassDB::is_class_exposed(name)) {
+ print_verbose(vformat("Class '%s' is not exposed, skipping.", name));
+ classes.pop_front();
+ continue;
+ }
- List<PropertyInfo> properties;
- List<PropertyInfo> own_properties;
-
- // Special case for editor and project settings, so they can be documented.
- if (name == "EditorSettings") {
- // We don't create the full blown EditorSettings (+ config file) with `create()`,
- // instead we just make a local instance to get default values.
- Ref<EditorSettings> edset = memnew(EditorSettings);
- edset->get_property_list(&properties);
- own_properties = properties;
- } else if (name == "ProjectSettings") {
- ProjectSettings::get_singleton()->get_property_list(&properties);
- own_properties = properties;
- } else {
- ClassDB::get_property_list(name, &properties);
- ClassDB::get_property_list(name, &own_properties, true);
- }
+ String cname = name;
+ // Property setters and getters do not get exposed as individual methods.
+ HashSet<StringName> setters_getters;
- properties.sort();
- own_properties.sort();
+ class_list[cname] = DocData::ClassDoc();
+ DocData::ClassDoc &c = class_list[cname];
+ c.name = cname;
+ c.inherits = ClassDB::get_parent_class(name);
- List<PropertyInfo>::Element *EO = own_properties.front();
- for (const PropertyInfo &E : properties) {
- bool inherited = true;
- if (EO && EO->get() == E) {
- inherited = false;
- EO = EO->next();
- }
+ List<PropertyInfo> properties;
+ List<PropertyInfo> own_properties;
- if (E.usage & PROPERTY_USAGE_GROUP || E.usage & PROPERTY_USAGE_SUBGROUP || E.usage & PROPERTY_USAGE_CATEGORY || E.usage & PROPERTY_USAGE_INTERNAL || (E.type == Variant::NIL && E.usage & PROPERTY_USAGE_ARRAY)) {
- continue;
+ // Special case for editor and project settings, so they can be documented.
+ if (name == "EditorSettings") {
+ // We don't create the full blown EditorSettings (+ config file) with `create()`,
+ // instead we just make a local instance to get default values.
+ Ref<EditorSettings> edset = memnew(EditorSettings);
+ edset->get_property_list(&properties);
+ own_properties = properties;
+ } else if (name == "ProjectSettings") {
+ ProjectSettings::get_singleton()->get_property_list(&properties);
+ own_properties = properties;
+ } else {
+ ClassDB::get_property_list(name, &properties);
+ ClassDB::get_property_list(name, &own_properties, true);
}
- DocData::PropertyDoc prop;
- prop.name = E.name;
- prop.overridden = inherited;
+ properties.sort();
+ own_properties.sort();
- if (inherited) {
- String parent = ClassDB::get_parent_class(c.name);
- while (!ClassDB::has_property(parent, prop.name, true)) {
- parent = ClassDB::get_parent_class(parent);
+ List<PropertyInfo>::Element *EO = own_properties.front();
+ for (const PropertyInfo &E : properties) {
+ bool inherited = true;
+ if (EO && EO->get() == E) {
+ inherited = false;
+ EO = EO->next();
}
- prop.overrides = parent;
- }
-
- bool default_value_valid = false;
- Variant default_value;
- if (name == "EditorSettings") {
- if (E.name == "resource_local_to_scene" || E.name == "resource_name" || E.name == "resource_path" || E.name == "script") {
- // Don't include spurious properties in the generated EditorSettings class reference.
+ if (E.usage & PROPERTY_USAGE_GROUP || E.usage & PROPERTY_USAGE_SUBGROUP || E.usage & PROPERTY_USAGE_CATEGORY || E.usage & PROPERTY_USAGE_INTERNAL || (E.type == Variant::NIL && E.usage & PROPERTY_USAGE_ARRAY)) {
continue;
}
- }
- if (name == "ProjectSettings") {
- // Special case for project settings, so that settings are not taken from the current project's settings
- if (E.name == "script" || !ProjectSettings::get_singleton()->is_builtin_setting(E.name)) {
- continue;
- }
- if (E.usage & PROPERTY_USAGE_EDITOR) {
- if (!ProjectSettings::get_singleton()->get_ignore_value_in_docs(E.name)) {
- default_value = ProjectSettings::get_singleton()->property_get_revert(E.name);
- default_value_valid = true;
+ DocData::PropertyDoc prop;
+ prop.name = E.name;
+ prop.overridden = inherited;
+
+ if (inherited) {
+ String parent = ClassDB::get_parent_class(c.name);
+ while (!ClassDB::has_property(parent, prop.name, true)) {
+ parent = ClassDB::get_parent_class(parent);
}
+ prop.overrides = parent;
}
- } else {
- default_value = get_documentation_default_value(name, E.name, default_value_valid);
- if (inherited) {
- bool base_default_value_valid = false;
- Variant base_default_value = get_documentation_default_value(ClassDB::get_parent_class(name), E.name, base_default_value_valid);
- if (!default_value_valid || !base_default_value_valid || default_value == base_default_value) {
+
+ bool default_value_valid = false;
+ Variant default_value;
+
+ if (name == "EditorSettings") {
+ if (E.name == "resource_local_to_scene" || E.name == "resource_name" || E.name == "resource_path" || E.name == "script") {
+ // Don't include spurious properties in the generated EditorSettings class reference.
continue;
}
}
- }
- if (default_value_valid && default_value.get_type() != Variant::OBJECT) {
- prop.default_value = default_value.get_construct_string().replace("\n", " ");
- }
-
- StringName setter = ClassDB::get_property_setter(name, E.name);
- StringName getter = ClassDB::get_property_getter(name, E.name);
-
- prop.setter = setter;
- prop.getter = getter;
-
- bool found_type = false;
- if (getter != StringName()) {
- MethodBind *mb = ClassDB::get_method(name, getter);
- if (mb) {
- PropertyInfo retinfo = mb->get_return_info();
-
- found_type = true;
- if (retinfo.type == Variant::INT && retinfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) {
- prop.enumeration = retinfo.class_name;
- prop.type = "int";
- } else if (retinfo.class_name != StringName()) {
- prop.type = retinfo.class_name;
- } else if (retinfo.type == Variant::ARRAY && retinfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
- prop.type = retinfo.hint_string + "[]";
- } else if (retinfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
- prop.type = retinfo.hint_string;
- } else if (retinfo.type == Variant::NIL && retinfo.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
- prop.type = "Variant";
- } else if (retinfo.type == Variant::NIL) {
- prop.type = "void";
- } else {
- prop.type = Variant::get_type_name(retinfo.type);
+ if (name == "ProjectSettings") {
+ // Special case for project settings, so that settings are not taken from the current project's settings
+ if (E.name == "script" || !ProjectSettings::get_singleton()->is_builtin_setting(E.name)) {
+ continue;
+ }
+ if (E.usage & PROPERTY_USAGE_EDITOR) {
+ if (!ProjectSettings::get_singleton()->get_ignore_value_in_docs(E.name)) {
+ default_value = ProjectSettings::get_singleton()->property_get_revert(E.name);
+ default_value_valid = true;
+ }
+ }
+ } else {
+ default_value = get_documentation_default_value(name, E.name, default_value_valid);
+ if (inherited) {
+ bool base_default_value_valid = false;
+ Variant base_default_value = get_documentation_default_value(ClassDB::get_parent_class(name), E.name, base_default_value_valid);
+ if (!default_value_valid || !base_default_value_valid || default_value == base_default_value) {
+ continue;
+ }
}
}
- setters_getters.insert(getter);
- }
+ if (default_value_valid && default_value.get_type() != Variant::OBJECT) {
+ prop.default_value = default_value.get_construct_string().replace("\n", " ");
+ }
- if (setter != StringName()) {
- setters_getters.insert(setter);
- }
+ StringName setter = ClassDB::get_property_setter(name, E.name);
+ StringName getter = ClassDB::get_property_getter(name, E.name);
+
+ prop.setter = setter;
+ prop.getter = getter;
+
+ bool found_type = false;
+ if (getter != StringName()) {
+ MethodBind *mb = ClassDB::get_method(name, getter);
+ if (mb) {
+ PropertyInfo retinfo = mb->get_return_info();
+
+ found_type = true;
+ if (retinfo.type == Variant::INT && retinfo.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) {
+ prop.enumeration = retinfo.class_name;
+ prop.type = "int";
+ } else if (retinfo.class_name != StringName()) {
+ prop.type = retinfo.class_name;
+ } else if (retinfo.type == Variant::ARRAY && retinfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
+ prop.type = retinfo.hint_string + "[]";
+ } else if (retinfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
+ prop.type = retinfo.hint_string;
+ } else if (retinfo.type == Variant::NIL && retinfo.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
+ prop.type = "Variant";
+ } else if (retinfo.type == Variant::NIL) {
+ prop.type = "void";
+ } else {
+ prop.type = Variant::get_type_name(retinfo.type);
+ }
+ }
- if (!found_type) {
- if (E.type == Variant::OBJECT && E.hint == PROPERTY_HINT_RESOURCE_TYPE) {
- prop.type = E.hint_string;
- } else {
- prop.type = Variant::get_type_name(E.type);
+ setters_getters.insert(getter);
}
- }
- c.properties.push_back(prop);
- }
+ if (setter != StringName()) {
+ setters_getters.insert(setter);
+ }
- List<MethodInfo> method_list;
- ClassDB::get_method_list(name, &method_list, true);
- method_list.sort();
+ if (!found_type) {
+ if (E.type == Variant::OBJECT && E.hint == PROPERTY_HINT_RESOURCE_TYPE) {
+ prop.type = E.hint_string;
+ } else {
+ prop.type = Variant::get_type_name(E.type);
+ }
+ }
- for (const MethodInfo &E : method_list) {
- if (E.name.is_empty() || (E.name[0] == '_' && !(E.flags & METHOD_FLAG_VIRTUAL))) {
- continue; //hidden, don't count
+ c.properties.push_back(prop);
}
- if (skip_setter_getter_methods && setters_getters.has(E.name)) {
- // Don't skip parametric setters and getters, i.e. method which require
- // one or more parameters to define what property should be set or retrieved.
- // E.g. CPUParticles3D::set_param(Parameter param, float value).
- if (E.arguments.size() == 0 /* getter */ || (E.arguments.size() == 1 && E.return_val.type == Variant::NIL /* setter */)) {
- continue;
- }
- }
+ List<MethodInfo> method_list;
+ ClassDB::get_method_list(name, &method_list, true);
+ method_list.sort();
- DocData::MethodDoc method;
- DocData::method_doc_from_methodinfo(method, E, "");
+ for (const MethodInfo &E : method_list) {
+ if (E.name.is_empty() || (E.name[0] == '_' && !(E.flags & METHOD_FLAG_VIRTUAL))) {
+ continue; //hidden, don't count
+ }
- Vector<Error> errs = ClassDB::get_method_error_return_values(name, E.name);
- if (errs.size()) {
- if (!errs.has(OK)) {
- errs.insert(0, OK);
+ if (skip_setter_getter_methods && setters_getters.has(E.name)) {
+ // Don't skip parametric setters and getters, i.e. method which require
+ // one or more parameters to define what property should be set or retrieved.
+ // E.g. CPUParticles3D::set_param(Parameter param, float value).
+ if (E.arguments.size() == 0 /* getter */ || (E.arguments.size() == 1 && E.return_val.type == Variant::NIL /* setter */)) {
+ continue;
+ }
}
- for (int i = 0; i < errs.size(); i++) {
- if (!method.errors_returned.has(errs[i])) {
- method.errors_returned.push_back(errs[i]);
+
+ DocData::MethodDoc method;
+ DocData::method_doc_from_methodinfo(method, E, "");
+
+ Vector<Error> errs = ClassDB::get_method_error_return_values(name, E.name);
+ if (errs.size()) {
+ if (!errs.has(OK)) {
+ errs.insert(0, OK);
+ }
+ for (int i = 0; i < errs.size(); i++) {
+ if (!method.errors_returned.has(errs[i])) {
+ method.errors_returned.push_back(errs[i]);
+ }
}
}
+
+ c.methods.push_back(method);
}
- c.methods.push_back(method);
- }
+ List<MethodInfo> signal_list;
+ ClassDB::get_signal_list(name, &signal_list, true);
- List<MethodInfo> signal_list;
- ClassDB::get_signal_list(name, &signal_list, true);
+ if (signal_list.size()) {
+ for (List<MethodInfo>::Element *EV = signal_list.front(); EV; EV = EV->next()) {
+ DocData::MethodDoc signal;
+ signal.name = EV->get().name;
+ for (int i = 0; i < EV->get().arguments.size(); i++) {
+ const PropertyInfo &arginfo = EV->get().arguments[i];
+ DocData::ArgumentDoc argument;
+ DocData::argument_doc_from_arginfo(argument, arginfo);
- if (signal_list.size()) {
- for (List<MethodInfo>::Element *EV = signal_list.front(); EV; EV = EV->next()) {
- DocData::MethodDoc signal;
- signal.name = EV->get().name;
- for (int i = 0; i < EV->get().arguments.size(); i++) {
- const PropertyInfo &arginfo = EV->get().arguments[i];
- DocData::ArgumentDoc argument;
- DocData::argument_doc_from_arginfo(argument, arginfo);
+ signal.arguments.push_back(argument);
+ }
- signal.arguments.push_back(argument);
+ c.signals.push_back(signal);
}
-
- c.signals.push_back(signal);
}
- }
- List<String> constant_list;
- ClassDB::get_integer_constant_list(name, &constant_list, true);
+ List<String> constant_list;
+ ClassDB::get_integer_constant_list(name, &constant_list, true);
+
+ for (const String &E : constant_list) {
+ DocData::ConstantDoc constant;
+ constant.name = E;
+ constant.value = itos(ClassDB::get_integer_constant(name, E));
+ constant.is_value_valid = true;
+ constant.enumeration = ClassDB::get_integer_constant_enum(name, E);
+ constant.is_bitfield = ClassDB::is_enum_bitfield(name, constant.enumeration);
+ c.constants.push_back(constant);
+ }
- for (const String &E : constant_list) {
- DocData::ConstantDoc constant;
- constant.name = E;
- constant.value = itos(ClassDB::get_integer_constant(name, E));
- constant.is_value_valid = true;
- constant.enumeration = ClassDB::get_integer_constant_enum(name, E);
- constant.is_bitfield = ClassDB::is_enum_bitfield(name, constant.enumeration);
- c.constants.push_back(constant);
- }
+ // Theme items.
+ {
+ List<StringName> l;
+
+ ThemeDB::get_singleton()->get_default_theme()->get_color_list(cname, &l);
+ for (const StringName &E : l) {
+ DocData::ThemeItemDoc tid;
+ tid.name = E;
+ tid.type = "Color";
+ tid.data_type = "color";
+ tid.default_value = Variant(ThemeDB::get_singleton()->get_default_theme()->get_color(E, cname)).get_construct_string().replace("\n", " ");
+ c.theme_properties.push_back(tid);
+ }
- // Theme items.
- {
- List<StringName> l;
-
- Theme::get_default()->get_color_list(cname, &l);
- for (const StringName &E : l) {
- DocData::ThemeItemDoc tid;
- tid.name = E;
- tid.type = "Color";
- tid.data_type = "color";
- tid.default_value = Variant(Theme::get_default()->get_color(E, cname)).get_construct_string().replace("\n", " ");
- c.theme_properties.push_back(tid);
- }
+ l.clear();
+ ThemeDB::get_singleton()->get_default_theme()->get_constant_list(cname, &l);
+ for (const StringName &E : l) {
+ DocData::ThemeItemDoc tid;
+ tid.name = E;
+ tid.type = "int";
+ tid.data_type = "constant";
+ tid.default_value = itos(ThemeDB::get_singleton()->get_default_theme()->get_constant(E, cname));
+ c.theme_properties.push_back(tid);
+ }
- l.clear();
- Theme::get_default()->get_constant_list(cname, &l);
- for (const StringName &E : l) {
- DocData::ThemeItemDoc tid;
- tid.name = E;
- tid.type = "int";
- tid.data_type = "constant";
- tid.default_value = itos(Theme::get_default()->get_constant(E, cname));
- c.theme_properties.push_back(tid);
- }
+ l.clear();
+ ThemeDB::get_singleton()->get_default_theme()->get_font_list(cname, &l);
+ for (const StringName &E : l) {
+ DocData::ThemeItemDoc tid;
+ tid.name = E;
+ tid.type = "Font";
+ tid.data_type = "font";
+ c.theme_properties.push_back(tid);
+ }
- l.clear();
- Theme::get_default()->get_font_list(cname, &l);
- for (const StringName &E : l) {
- DocData::ThemeItemDoc tid;
- tid.name = E;
- tid.type = "Font";
- tid.data_type = "font";
- c.theme_properties.push_back(tid);
- }
+ l.clear();
+ ThemeDB::get_singleton()->get_default_theme()->get_font_size_list(cname, &l);
+ for (const StringName &E : l) {
+ DocData::ThemeItemDoc tid;
+ tid.name = E;
+ tid.type = "int";
+ tid.data_type = "font_size";
+ c.theme_properties.push_back(tid);
+ }
- l.clear();
- Theme::get_default()->get_font_size_list(cname, &l);
- for (const StringName &E : l) {
- DocData::ThemeItemDoc tid;
- tid.name = E;
- tid.type = "int";
- tid.data_type = "font_size";
- c.theme_properties.push_back(tid);
- }
+ l.clear();
+ ThemeDB::get_singleton()->get_default_theme()->get_icon_list(cname, &l);
+ for (const StringName &E : l) {
+ DocData::ThemeItemDoc tid;
+ tid.name = E;
+ tid.type = "Texture2D";
+ tid.data_type = "icon";
+ c.theme_properties.push_back(tid);
+ }
- l.clear();
- Theme::get_default()->get_icon_list(cname, &l);
- for (const StringName &E : l) {
- DocData::ThemeItemDoc tid;
- tid.name = E;
- tid.type = "Texture2D";
- tid.data_type = "icon";
- c.theme_properties.push_back(tid);
- }
+ l.clear();
+ ThemeDB::get_singleton()->get_default_theme()->get_stylebox_list(cname, &l);
+ for (const StringName &E : l) {
+ DocData::ThemeItemDoc tid;
+ tid.name = E;
+ tid.type = "StyleBox";
+ tid.data_type = "style";
+ c.theme_properties.push_back(tid);
+ }
- l.clear();
- Theme::get_default()->get_stylebox_list(cname, &l);
- for (const StringName &E : l) {
- DocData::ThemeItemDoc tid;
- tid.name = E;
- tid.type = "StyleBox";
- tid.data_type = "style";
- c.theme_properties.push_back(tid);
+ c.theme_properties.sort();
}
- c.theme_properties.sort();
+ classes.pop_front();
}
-
- classes.pop_front();
}
+ // Add a dummy Variant entry.
{
- // So we can document the concept of Variant even if it's not a usable class per se.
+ // This allows us to document the concept of Variant even though
+ // it's not a ClassDB-exposed class.
class_list["Variant"] = DocData::ClassDoc();
class_list["Variant"].name = "Variant";
}
+ // If we don't want to populate basic types, break here.
if (!p_basic_types) {
return;
}
- // Add Variant types.
+ // Add Variant data types.
for (int i = 0; i < Variant::VARIANT_MAX; i++) {
if (i == Variant::NIL) {
continue; // Not exposed outside of 'null', should not be in class list.
@@ -809,14 +817,14 @@ void DocTools::generate(bool p_basic_types) {
}
}
- //built in constants and functions
-
+ // Add global API (servers, engine singletons, global constants) and Variant utility functions.
{
String cname = "@GlobalScope";
class_list[cname] = DocData::ClassDoc();
DocData::ClassDoc &c = class_list[cname];
c.name = cname;
+ // Global constants.
for (int i = 0; i < CoreConstants::get_global_constant_count(); i++) {
DocData::ConstantDoc cd;
cd.name = CoreConstants::get_global_constant_name(i);
@@ -830,10 +838,11 @@ void DocTools::generate(bool p_basic_types) {
c.constants.push_back(cd);
}
+ // Servers/engine singletons.
List<Engine::Singleton> singletons;
Engine::get_singleton()->get_singletons(&singletons);
- //servers (this is kind of hackish)
+ // FIXME: this is kind of hackish...
for (const Engine::Singleton &s : singletons) {
DocData::PropertyDoc pd;
if (!s.ptr) {
@@ -847,13 +856,14 @@ void DocTools::generate(bool p_basic_types) {
c.properties.push_back(pd);
}
+ // Variant utility functions.
List<StringName> utility_functions;
Variant::get_utility_function_list(&utility_functions);
utility_functions.sort_custom<StringName::AlphCompare>();
for (const StringName &E : utility_functions) {
DocData::MethodDoc md;
md.name = E;
- //return
+ // Utility function's return type.
if (Variant::has_utility_function_return_value(E)) {
PropertyInfo pi;
pi.type = Variant::get_utility_function_return_type(E);
@@ -865,6 +875,7 @@ void DocTools::generate(bool p_basic_types) {
md.return_type = ad.type;
}
+ // Utility function's arguments.
if (Variant::is_utility_function_vararg(E)) {
md.qualifiers = "vararg";
} else {
@@ -885,11 +896,10 @@ void DocTools::generate(bool p_basic_types) {
}
}
- // Built-in script reference.
- // We only add a doc entry for languages which actually define any built-in
- // methods or constants.
-
+ // Add scripting language built-ins.
{
+ // We only add a doc entry for languages which actually define any built-in
+ // methods, constants, or annotations.
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
ScriptLanguage *lang = ScriptServer::get_language(i);
String cname = "@" + lang->get_name();
@@ -1010,7 +1020,7 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> &
} else if (name == "returns_error") {
ERR_FAIL_COND_V(!parser->has_attribute("number"), ERR_FILE_CORRUPT);
method.errors_returned.push_back(parser->get_attribute_value("number").to_int());
- } else if (name == "argument") {
+ } else if (name == "param") {
DocData::ArgumentDoc argument;
ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
argument.name = parser->get_attribute_value("name");
@@ -1061,7 +1071,7 @@ Error DocTools::load_classes(const String &p_dir) {
while (!path.is_empty()) {
if (!da->current_is_dir() && path.ends_with("xml")) {
Ref<XMLParser> parser = memnew(XMLParser);
- Error err2 = parser->open(p_dir.plus_file(path));
+ Error err2 = parser->open(p_dir.path_join(path));
if (err2) {
return err2;
}
@@ -1341,9 +1351,9 @@ static void _write_method_doc(Ref<FileAccess> f, const String &p_name, Vector<Do
}
if (!a.default_value.is_empty()) {
- _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\"" + enum_text + " default=\"" + a.default_value.xml_escape(true) + "\" />");
+ _write_string(f, 3, "<param index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\"" + enum_text + " default=\"" + a.default_value.xml_escape(true) + "\" />");
} else {
- _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\"" + enum_text + " />");
+ _write_string(f, 3, "<param index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\"" + enum_text + " />");
}
}
@@ -1370,7 +1380,7 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
}
Error err;
- String save_file = save_path.plus_file(c.name + ".xml");
+ String save_file = save_path.path_join(c.name + ".xml");
Ref<FileAccess> f = FileAccess::open(save_file, FileAccess::WRITE, &err);
ERR_CONTINUE_MSG(err != OK, "Can't write doc file: " + save_file + ".");
diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp
index 17aa67cd45..7baaffb1be 100644
--- a/editor/editor_about.cpp
+++ b/editor/editor_about.cpp
@@ -147,7 +147,7 @@ EditorAbout::EditorAbout() {
// Set the text to copy in metadata as it slightly differs from the button's text.
version_btn->set_meta(META_TEXT_TO_COPY, "v" VERSION_FULL_BUILD + hash);
version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER);
- version_btn->set_tooltip(TTR("Click to copy."));
+ version_btn->set_tooltip_text(TTR("Click to copy."));
version_btn->connect("pressed", callable_mp(this, &EditorAbout::_version_button_pressed));
version_info_vbc->add_child(version_btn);
diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp
index b6d7bbc45f..a95cc4981a 100644
--- a/editor/editor_audio_buses.cpp
+++ b/editor/editor_audio_buses.cpp
@@ -38,6 +38,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "filesystem_dock.h"
#include "scene/resources/font.h"
#include "servers/audio_server.h"
@@ -280,7 +281,7 @@ void EditorAudioBus::_name_changed(const String &p_new_name) {
}
updating_bus = true;
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
StringName current = AudioServer::get_singleton()->get_bus_name(get_index());
ur->create_action(TTR("Rename Audio Bus"));
@@ -321,7 +322,7 @@ void EditorAudioBus::_volume_changed(float p_normalized) {
slider->set_value(_scaled_db_to_normalized_volume(Math::round(p_db)));
}
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Audio Bus Volume"), UndoRedo::MERGE_ENDS);
ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", get_index(), p_db);
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", get_index(), AudioServer::get_singleton()->get_bus_volume_db(get_index()));
@@ -394,7 +395,7 @@ void EditorAudioBus::_show_value(float slider_value) {
// Also set the preview text as a standard Control tooltip.
// This way, it can be seen when the slider is merely hovered (instead of dragged).
- slider->set_tooltip(text);
+ slider->set_tooltip_text(text);
audio_value_preview_label->set_text(text);
const Vector2 slider_size = slider->get_size();
const Vector2 slider_position = slider->get_global_position();
@@ -415,7 +416,7 @@ void EditorAudioBus::_hide_value_preview() {
void EditorAudioBus::_solo_toggled() {
updating_bus = true;
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Toggle Audio Bus Solo"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_solo", get_index(), solo->is_pressed());
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_solo", get_index(), AudioServer::get_singleton()->is_bus_solo(get_index()));
@@ -429,7 +430,7 @@ void EditorAudioBus::_solo_toggled() {
void EditorAudioBus::_mute_toggled() {
updating_bus = true;
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Toggle Audio Bus Mute"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_mute", get_index(), mute->is_pressed());
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_mute", get_index(), AudioServer::get_singleton()->is_bus_mute(get_index()));
@@ -443,7 +444,7 @@ void EditorAudioBus::_mute_toggled() {
void EditorAudioBus::_bypass_toggled() {
updating_bus = true;
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Toggle Audio Bus Bypass Effects"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_bypass_effects", get_index(), bypass->is_pressed());
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_bypass_effects", get_index(), AudioServer::get_singleton()->is_bus_bypassing_effects(get_index()));
@@ -457,7 +458,7 @@ void EditorAudioBus::_bypass_toggled() {
void EditorAudioBus::_send_selected(int p_which) {
updating_bus = true;
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Select Audio Bus Send"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_send", get_index(), send->get_item_text(p_which));
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_send", get_index(), AudioServer::get_singleton()->get_bus_send(get_index()));
@@ -507,7 +508,7 @@ void EditorAudioBus::_effect_edited() {
int index = effect->get_metadata(0);
updating_bus = true;
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Select Audio Bus Send"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), index, effect->is_checked(0));
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), index, AudioServer::get_singleton()->is_bus_effect_enabled(get_index(), index));
@@ -534,7 +535,7 @@ void EditorAudioBus::_effect_add(int p_which) {
afxr->set_name(effect_options->get_item_text(p_which));
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Add Audio Bus Effect"));
ur->add_do_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), afxr, -1);
ur->add_undo_method(AudioServer::get_singleton(), "remove_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect_count(get_index()));
@@ -688,7 +689,7 @@ void EditorAudioBus::drop_data_fw(const Point2 &p_point, const Variant &p_data,
bool enabled = AudioServer::get_singleton()->is_bus_effect_enabled(bus, effect);
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Move Bus Effect"));
ur->add_do_method(AudioServer::get_singleton(), "remove_bus_effect", bus, effect);
ur->add_do_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect(bus, effect), paste_at);
@@ -730,7 +731,7 @@ void EditorAudioBus::_delete_effect_pressed(int p_option) {
int index = item->get_metadata(0);
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Delete Bus Effect"));
ur->add_do_method(AudioServer::get_singleton(), "remove_bus_effect", get_index(), index);
ur->add_undo_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect(get_index(), index), index);
@@ -778,7 +779,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
buses = p_buses;
is_master = p_is_master;
- set_tooltip(TTR("Drag & drop to rearrange."));
+ set_tooltip_text(TTR("Drag & drop to rearrange."));
VBoxContainer *vb = memnew(VBoxContainer);
add_child(vb);
@@ -795,21 +796,21 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
solo = memnew(Button);
solo->set_flat(true);
solo->set_toggle_mode(true);
- solo->set_tooltip(TTR("Solo"));
+ solo->set_tooltip_text(TTR("Solo"));
solo->set_focus_mode(FOCUS_NONE);
solo->connect("pressed", callable_mp(this, &EditorAudioBus::_solo_toggled));
hbc->add_child(solo);
mute = memnew(Button);
mute->set_flat(true);
mute->set_toggle_mode(true);
- mute->set_tooltip(TTR("Mute"));
+ mute->set_tooltip_text(TTR("Mute"));
mute->set_focus_mode(FOCUS_NONE);
mute->connect("pressed", callable_mp(this, &EditorAudioBus::_mute_toggled));
hbc->add_child(mute);
bypass = memnew(Button);
bypass->set_flat(true);
bypass->set_toggle_mode(true);
- bypass->set_tooltip(TTR("Bypass"));
+ bypass->set_tooltip_text(TTR("Bypass"));
bypass->set_focus_mode(FOCUS_NONE);
bypass->connect("pressed", callable_mp(this, &EditorAudioBus::_bypass_toggled));
hbc->add_child(bypass);
@@ -935,7 +936,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
bus_options->set_shortcut_context(this);
bus_options->set_h_size_flags(SIZE_SHRINK_END);
bus_options->set_anchor(SIDE_RIGHT, 0.0);
- bus_options->set_tooltip(TTR("Bus Options"));
+ bus_options->set_tooltip_text(TTR("Bus Options"));
hbc->add_child(bus_options);
bus_popup = bus_options->get_popup();
@@ -1063,7 +1064,7 @@ void EditorAudioBuses::_notification(int p_what) {
}
void EditorAudioBuses::_add_bus() {
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Add Audio Bus"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_count", AudioServer::get_singleton()->get_bus_count() + 1);
@@ -1095,7 +1096,7 @@ void EditorAudioBuses::_delete_bus(Object *p_which) {
return;
}
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Delete Audio Bus"));
ur->add_do_method(AudioServer::get_singleton(), "remove_bus", index);
@@ -1117,7 +1118,7 @@ void EditorAudioBuses::_delete_bus(Object *p_which) {
void EditorAudioBuses::_duplicate_bus(int p_which) {
int add_at_pos = p_which + 1;
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Duplicate Audio Bus"));
ur->add_do_method(AudioServer::get_singleton(), "add_bus", add_at_pos);
ur->add_do_method(AudioServer::get_singleton(), "set_bus_name", add_at_pos, AudioServer::get_singleton()->get_bus_name(p_which) + " Copy");
@@ -1140,7 +1141,7 @@ void EditorAudioBuses::_reset_bus_volume(Object *p_which) {
EditorAudioBus *bus = Object::cast_to<EditorAudioBus>(p_which);
int index = bus->get_index();
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Reset Bus Volume"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", index, 0.f);
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", index, AudioServer::get_singleton()->get_bus_volume_db(index));
@@ -1160,7 +1161,7 @@ void EditorAudioBuses::_request_drop_end() {
}
void EditorAudioBuses::_drop_at_index(int p_bus, int p_index) {
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Move Audio Bus"));
ur->add_do_method(AudioServer::get_singleton(), "move_bus", p_bus, p_index);
@@ -1219,7 +1220,7 @@ void EditorAudioBuses::_load_default_layout() {
file->set_text(String(TTR("Layout:")) + " " + layout_path.get_file());
AudioServer::get_singleton()->set_bus_layout(state);
_update_buses();
- EditorNode::get_singleton()->get_undo_redo()->clear_history();
+ EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
call_deferred(SNAME("_select_layout"));
}
@@ -1235,7 +1236,7 @@ void EditorAudioBuses::_file_dialog_callback(const String &p_string) {
file->set_text(String(TTR("Layout:")) + " " + p_string.get_file());
AudioServer::get_singleton()->set_bus_layout(state);
_update_buses();
- EditorNode::get_singleton()->get_undo_redo()->clear_history();
+ EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
call_deferred(SNAME("_select_layout"));
} else if (file_dialog->get_file_mode() == EditorFileDialog::FILE_MODE_SAVE_FILE) {
@@ -1255,7 +1256,7 @@ void EditorAudioBuses::_file_dialog_callback(const String &p_string) {
edited_path = p_string;
file->set_text(String(TTR("Layout:")) + " " + p_string.get_file());
_update_buses();
- EditorNode::get_singleton()->get_undo_redo()->clear_history();
+ EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
call_deferred(SNAME("_select_layout"));
}
}
@@ -1281,7 +1282,7 @@ EditorAudioBuses::EditorAudioBuses() {
add = memnew(Button);
top_hb->add_child(add);
add->set_text(TTR("Add Bus"));
- add->set_tooltip(TTR("Add a new Audio Bus to this layout."));
+ add->set_tooltip_text(TTR("Add a new Audio Bus to this layout."));
add->connect("pressed", callable_mp(this, &EditorAudioBuses::_add_bus));
VSeparator *separator = memnew(VSeparator);
@@ -1289,25 +1290,25 @@ EditorAudioBuses::EditorAudioBuses() {
load = memnew(Button);
load->set_text(TTR("Load"));
- load->set_tooltip(TTR("Load an existing Bus Layout."));
+ load->set_tooltip_text(TTR("Load an existing Bus Layout."));
top_hb->add_child(load);
load->connect("pressed", callable_mp(this, &EditorAudioBuses::_load_layout));
save_as = memnew(Button);
save_as->set_text(TTR("Save As"));
- save_as->set_tooltip(TTR("Save this Bus Layout to a file."));
+ save_as->set_tooltip_text(TTR("Save this Bus Layout to a file."));
top_hb->add_child(save_as);
save_as->connect("pressed", callable_mp(this, &EditorAudioBuses::_save_as_layout));
_default = memnew(Button);
_default->set_text(TTR("Load Default"));
- _default->set_tooltip(TTR("Load the default Bus Layout."));
+ _default->set_tooltip_text(TTR("Load the default Bus Layout."));
top_hb->add_child(_default);
_default->connect("pressed", callable_mp(this, &EditorAudioBuses::_load_default_layout));
_new = memnew(Button);
_new->set_text(TTR("Create"));
- _new->set_tooltip(TTR("Create a new Bus Layout."));
+ _new->set_tooltip_text(TTR("Create a new Bus Layout."));
top_hb->add_child(_new);
_new->connect("pressed", callable_mp(this, &EditorAudioBuses::_new_layout));
@@ -1354,7 +1355,7 @@ void EditorAudioBuses::open_layout(const String &p_path) {
file->set_text(p_path.get_file());
AudioServer::get_singleton()->set_bus_layout(state);
_update_buses();
- EditorNode::get_singleton()->get_undo_redo()->clear_history();
+ EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
call_deferred(SNAME("_select_layout"));
}
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp
index ee4955d0a0..6d44654617 100644
--- a/editor/editor_autoload_settings.cpp
+++ b/editor/editor_autoload_settings.cpp
@@ -35,6 +35,7 @@
#include "editor/editor_file_dialog.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/filesystem_dock.h"
#include "project_settings_editor.h"
#include "scene/main/window.h"
@@ -163,7 +164,7 @@ void EditorAutoloadSettings::_autoload_add() {
if (!fpath.ends_with("/")) {
fpath = fpath.get_base_dir();
}
- dialog->config("Node", fpath.plus_file(vformat("%s.gd", autoload_add_name->get_text().camelcase_to_underscore())), false, false);
+ dialog->config("Node", fpath.path_join(vformat("%s.gd", autoload_add_name->get_text().camelcase_to_underscore())), false, false);
dialog->popup_centered();
} else {
if (autoload_add(autoload_add_name->get_text(), autoload_add_path->get_text())) {
@@ -193,7 +194,7 @@ void EditorAutoloadSettings::_autoload_edited() {
TreeItem *ti = tree->get_edited();
int column = tree->get_edited_column();
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
if (column == 0) {
String name = ti->get_text(0);
@@ -288,7 +289,7 @@ void EditorAutoloadSettings::_autoload_button_pressed(Object *p_item, int p_colu
String name = "autoload/" + ti->get_text(0);
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
switch (p_button) {
case BUTTON_OPEN: {
@@ -713,7 +714,7 @@ void EditorAutoloadSettings::drop_data_fw(const Point2 &p_point, const Variant &
orders.sort();
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
undo_redo->create_action(TTR("Rearrange Autoloads"));
@@ -757,7 +758,7 @@ bool EditorAutoloadSettings::autoload_add(const String &p_name, const String &p_
name = "autoload/" + name;
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
undo_redo->create_action(TTR("Add Autoload"));
// Singleton autoloads are represented with a leading "*" in their path.
@@ -783,7 +784,7 @@ bool EditorAutoloadSettings::autoload_add(const String &p_name, const String &p_
void EditorAutoloadSettings::autoload_remove(const String &p_name) {
String name = "autoload/" + p_name;
- UndoRedo *undo_redo = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
int order = ProjectSettings::get_singleton()->get_order(name);
diff --git a/editor/editor_build_profile.cpp b/editor/editor_build_profile.cpp
index d093ab518e..0f0ab4a339 100644
--- a/editor/editor_build_profile.cpp
+++ b/editor/editor_build_profile.cpp
@@ -46,19 +46,68 @@ const char *EditorBuildProfile::build_option_identifiers[BUILD_OPTION_MAX] = {
"disable_3d_physics",
"disable_navigation",
"openxr",
+ "rendering_device", // FIXME: there's no scons option to disable rendering device
"opengl3",
"vulkan",
+ "module_text_server_fb_enabled",
+ "module_text_server_adv_enabled",
+ "module_freetype_enabled",
+ "brotli",
+ "graphite",
+ "module_msdfgen_enabled"
+};
+
+const bool EditorBuildProfile::build_option_disabled_by_default[BUILD_OPTION_MAX] = {
+ // This maps to SCons build options.
+ false, // 3D
+ false, // PHYSICS_2D
+ false, // PHYSICS_3D
+ false, // NAVIGATION
+ false, // XR
+ false, // RENDERING_DEVICE
+ false, // OPENGL
+ false, // VULKAN
+ true, // TEXT_SERVER_FALLBACK
+ false, // TEXT_SERVER_COMPLEX
+ false, // DYNAMIC_FONTS
+ false, // WOFF2_FONTS
+ false, // GRPAHITE_FONTS
+ false, // MSDFGEN
};
const bool EditorBuildProfile::build_option_disable_values[BUILD_OPTION_MAX] = {
// This maps to SCons build options.
- true,
- true,
- true,
- true,
- false,
- false,
- false
+ true, // 3D
+ true, // PHYSICS_2D
+ true, // PHYSICS_3D
+ true, // NAVIGATION
+ false, // XR
+ false, // RENDERING_DEVICE
+ false, // OPENGL
+ false, // VULKAN
+ false, // TEXT_SERVER_FALLBACK
+ false, // TEXT_SERVER_COMPLEX
+ false, // DYNAMIC_FONTS
+ false, // WOFF2_FONTS
+ false, // GRPAHITE_FONTS
+ false, // MSDFGEN
+};
+
+const EditorBuildProfile::BuildOptionCategory EditorBuildProfile::build_option_category[BUILD_OPTION_MAX] = {
+ BUILD_OPTION_CATEGORY_GENERAL, // 3D
+ BUILD_OPTION_CATEGORY_GENERAL, // PHYSICS_2D
+ BUILD_OPTION_CATEGORY_GENERAL, // PHYSICS_3D
+ BUILD_OPTION_CATEGORY_GENERAL, // NAVIGATION
+ BUILD_OPTION_CATEGORY_GENERAL, // XR
+ BUILD_OPTION_CATEGORY_GENERAL, // RENDERING_DEVICE
+ BUILD_OPTION_CATEGORY_GENERAL, // OPENGL
+ BUILD_OPTION_CATEGORY_GENERAL, // VULKAN
+ BUILD_OPTION_CATEGORY_TEXT_SERVER, // TEXT_SERVER_FALLBACK
+ BUILD_OPTION_CATEGORY_TEXT_SERVER, // TEXT_SERVER_COMPLEX
+ BUILD_OPTION_CATEGORY_TEXT_SERVER, // DYNAMIC_FONTS
+ BUILD_OPTION_CATEGORY_TEXT_SERVER, // WOFF2_FONTS
+ BUILD_OPTION_CATEGORY_TEXT_SERVER, // GRPAHITE_FONTS
+ BUILD_OPTION_CATEGORY_TEXT_SERVER, // MSDFGEN
};
void EditorBuildProfile::set_disable_class(const StringName &p_class, bool p_disabled) {
@@ -127,6 +176,12 @@ String EditorBuildProfile::get_build_option_name(BuildOption p_build_option) {
TTRC("RenderingDevice"),
TTRC("OpenGL"),
TTRC("Vulkan"),
+ TTRC("Text Server: Fallback"),
+ TTRC("Text Server: Advanced"),
+ TTRC("TTF, OTF, Type 1, WOFF1 Fonts"),
+ TTRC("WOFF2 Fonts"),
+ TTRC("SIL Graphite Fonts"),
+ TTRC("Multi-channel Signed Distance Field Font Rendering"),
};
return TTRGET(build_option_names[p_build_option]);
}
@@ -143,11 +198,33 @@ String EditorBuildProfile::get_build_option_description(BuildOption p_build_opti
TTRC("RenderingDevice based rendering (if disabled, the OpenGL back-end is required)."),
TTRC("OpenGL back-end (if disabled, the RenderingDevice back-end is required)."),
TTRC("Vulkan back-end of RenderingDevice."),
+ TTRC("Fallback implementation of Text Server\nSupports basic text layouts."),
+ TTRC("Text Server implementation powered by ICU and HarfBuzz libraries.\nSupports complex text layouts, BiDi, and contextual OpenType font features."),
+ TTRC("TrueType, OpenType, Type 1, and WOFF1 font format support using FreeType library (if disabled, WOFF2 support is also disabled)."),
+ TTRC("WOFF2 font format support using FreeType and Brotli libraries."),
+ TTRC("SIL Graphite smart font technology support (supported by Advanced Text Server only)."),
+ TTRC("Multi-channel signed distance field font rendering support using msdfgen library (pre-rendered MSDF fonts can be used even if this option disabled)."),
};
return TTRGET(build_option_descriptions[p_build_option]);
}
+EditorBuildProfile::BuildOptionCategory EditorBuildProfile::get_build_option_category(BuildOption p_build_option) {
+ ERR_FAIL_INDEX_V(p_build_option, BUILD_OPTION_MAX, BUILD_OPTION_CATEGORY_GENERAL);
+ return build_option_category[p_build_option];
+}
+
+String EditorBuildProfile::get_build_option_category_name(BuildOptionCategory p_build_option_category) {
+ ERR_FAIL_INDEX_V(p_build_option_category, BUILD_OPTION_CATEGORY_MAX, String());
+
+ const char *build_option_subcategories[BUILD_OPTION_CATEGORY_MAX]{
+ TTRC("General Features:"),
+ TTRC("Text Rendering and Font Options:"),
+ };
+
+ return TTRGET(build_option_subcategories[p_build_option_category]);
+}
+
Error EditorBuildProfile::save_to_file(const String &p_path) {
Dictionary data;
data["type"] = "build_profile";
@@ -160,8 +237,12 @@ Error EditorBuildProfile::save_to_file(const String &p_path) {
Dictionary dis_build_options;
for (int i = 0; i < BUILD_OPTION_MAX; i++) {
- if (build_options_disabled[i]) {
- dis_build_options[build_option_identifiers[i]] = build_option_disable_values[i];
+ if (build_options_disabled[i] != build_option_disabled_by_default[i]) {
+ if (build_options_disabled[i]) {
+ dis_build_options[build_option_identifiers[i]] = build_option_disable_values[i];
+ } else {
+ dis_build_options[build_option_identifiers[i]] = !build_option_disable_values[i];
+ }
}
}
@@ -211,7 +292,7 @@ Error EditorBuildProfile::load_from_file(const String &p_path) {
}
for (int i = 0; i < BUILD_OPTION_MAX; i++) {
- build_options_disabled[i] = false;
+ build_options_disabled[i] = build_option_disabled_by_default[i];
}
if (data.has("disabled_build_options")) {
@@ -259,10 +340,24 @@ void EditorBuildProfile::_bind_methods() {
BIND_ENUM_CONSTANT(BUILD_OPTION_RENDERING_DEVICE);
BIND_ENUM_CONSTANT(BUILD_OPTION_OPENGL);
BIND_ENUM_CONSTANT(BUILD_OPTION_VULKAN);
+ BIND_ENUM_CONSTANT(BUILD_OPTION_TEXT_SERVER_FALLBACK);
+ BIND_ENUM_CONSTANT(BUILD_OPTION_TEXT_SERVER_ADVANCED);
+ BIND_ENUM_CONSTANT(BUILD_OPTION_DYNAMIC_FONTS);
+ BIND_ENUM_CONSTANT(BUILD_OPTION_WOFF2_FONTS);
+ BIND_ENUM_CONSTANT(BUILD_OPTION_GRPAHITE_FONTS);
+ BIND_ENUM_CONSTANT(BUILD_OPTION_MSDFGEN);
BIND_ENUM_CONSTANT(BUILD_OPTION_MAX);
+
+ BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_GENERAL);
+ BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_TEXT_SERVER);
+ BIND_ENUM_CONSTANT(BUILD_OPTION_CATEGORY_MAX);
}
-EditorBuildProfile::EditorBuildProfile() {}
+EditorBuildProfile::EditorBuildProfile() {
+ for (int i = 0; i < EditorBuildProfile::BUILD_OPTION_MAX; i++) {
+ build_options_disabled[i] = build_option_disabled_by_default[i];
+ }
+}
//////////////////////////
@@ -633,11 +728,18 @@ void EditorBuildProfileManager::_update_edited_profile() {
TreeItem *root = class_list->create_item();
- TreeItem *build_options = class_list->create_item(root);
- build_options->set_text(0, TTR("General Features:"));
+ HashMap<EditorBuildProfile::BuildOptionCategory, TreeItem *> subcats;
+ for (int i = 0; i < EditorBuildProfile::BUILD_OPTION_CATEGORY_MAX; i++) {
+ TreeItem *build_cat;
+ build_cat = class_list->create_item(root);
+
+ build_cat->set_text(0, EditorBuildProfile::get_build_option_category_name(EditorBuildProfile::BuildOptionCategory(i)));
+ subcats[EditorBuildProfile::BuildOptionCategory(i)] = build_cat;
+ }
+
for (int i = 0; i < EditorBuildProfile::BUILD_OPTION_MAX; i++) {
TreeItem *build_option;
- build_option = class_list->create_item(build_options);
+ build_option = class_list->create_item(subcats[EditorBuildProfile::get_build_option_category(EditorBuildProfile::BuildOption(i))]);
build_option->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
build_option->set_text(0, EditorBuildProfile::get_build_option_name(EditorBuildProfile::BuildOption(i)));
diff --git a/editor/editor_build_profile.h b/editor/editor_build_profile.h
index bb6494b8c9..606c415429 100644
--- a/editor/editor_build_profile.h
+++ b/editor/editor_build_profile.h
@@ -53,7 +53,19 @@ public:
BUILD_OPTION_RENDERING_DEVICE,
BUILD_OPTION_OPENGL,
BUILD_OPTION_VULKAN,
- BUILD_OPTION_MAX
+ BUILD_OPTION_TEXT_SERVER_FALLBACK,
+ BUILD_OPTION_TEXT_SERVER_ADVANCED,
+ BUILD_OPTION_DYNAMIC_FONTS,
+ BUILD_OPTION_WOFF2_FONTS,
+ BUILD_OPTION_GRPAHITE_FONTS,
+ BUILD_OPTION_MSDFGEN,
+ BUILD_OPTION_MAX,
+ };
+
+ enum BuildOptionCategory {
+ BUILD_OPTION_CATEGORY_GENERAL,
+ BUILD_OPTION_CATEGORY_TEXT_SERVER,
+ BUILD_OPTION_CATEGORY_MAX,
};
private:
@@ -65,7 +77,9 @@ private:
bool build_options_disabled[BUILD_OPTION_MAX] = {};
static const char *build_option_identifiers[BUILD_OPTION_MAX];
+ static const bool build_option_disabled_by_default[BUILD_OPTION_MAX];
static const bool build_option_disable_values[BUILD_OPTION_MAX];
+ static const BuildOptionCategory build_option_category[BUILD_OPTION_MAX];
String _get_build_option_name(BuildOption p_build_option) { return get_build_option_name(p_build_option); }
@@ -93,11 +107,15 @@ public:
static String get_build_option_name(BuildOption p_build_option);
static String get_build_option_description(BuildOption p_build_option);
static bool get_build_option_disable_value(BuildOption p_build_option);
+ static BuildOptionCategory get_build_option_category(BuildOption p_build_option);
+
+ static String get_build_option_category_name(BuildOptionCategory p_build_option_category);
EditorBuildProfile();
};
VARIANT_ENUM_CAST(EditorBuildProfile::BuildOption)
+VARIANT_ENUM_CAST(EditorBuildProfile::BuildOptionCategory)
class EditorFileSystemDirectory;
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index 2d4945db14..231ae198d2 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -35,6 +35,7 @@
#include "core/io/resource_loader.h"
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/script_editor_plugin.h"
#include "scene/resources/packed_scene.h"
@@ -364,13 +365,13 @@ void EditorData::restore_editor_global_states() {
void EditorData::paste_object_params(Object *p_object) {
ERR_FAIL_NULL(p_object);
- undo_redo.create_action(TTR("Paste Params"));
+ undo_redo_manager->create_action(TTR("Paste Params"));
for (const PropertyData &E : clipboard) {
String name = E.name;
- undo_redo.add_do_property(p_object, name, E.value);
- undo_redo.add_undo_property(p_object, name, p_object->get(name));
+ undo_redo_manager->add_do_property(p_object, name, E.value);
+ undo_redo_manager->add_undo_property(p_object, name, p_object->get(name));
}
- undo_redo.commit_action();
+ undo_redo_manager->commit_action();
}
bool EditorData::call_build() {
@@ -383,8 +384,49 @@ bool EditorData::call_build() {
return result;
}
-UndoRedo &EditorData::get_undo_redo() {
- return undo_redo;
+void EditorData::set_scene_as_saved(int p_idx) {
+ if (p_idx == -1) {
+ p_idx = current_edited_scene;
+ }
+ ERR_FAIL_INDEX(p_idx, edited_scene.size());
+
+ get_undo_redo()->set_history_as_saved(edited_scene[p_idx].history_id);
+}
+
+bool EditorData::is_scene_changed(int p_idx) {
+ if (p_idx == -1) {
+ p_idx = current_edited_scene;
+ }
+ ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), false);
+
+ uint64_t current_scene_version = get_undo_redo()->get_or_create_history(edited_scene[p_idx].history_id).undo_redo->get_version();
+ bool is_changed = edited_scene[p_idx].last_checked_version != current_scene_version;
+ edited_scene.write[p_idx].last_checked_version = current_scene_version;
+ return is_changed;
+}
+
+int EditorData::get_scene_history_id_from_path(const String &p_path) const {
+ for (const EditedScene &E : edited_scene) {
+ if (E.path == p_path) {
+ return E.history_id;
+ }
+ }
+ return 0;
+}
+
+int EditorData::get_current_edited_scene_history_id() const {
+ if (current_edited_scene != -1) {
+ return edited_scene[current_edited_scene].history_id;
+ }
+ return 0;
+}
+
+int EditorData::get_scene_history_id(int p_idx) const {
+ return edited_scene[p_idx].history_id;
+}
+
+Ref<EditorUndoRedoManager> &EditorData::get_undo_redo() {
+ return undo_redo_manager;
}
void EditorData::add_undo_redo_inspector_hook_callback(Callable p_callable) {
@@ -415,12 +457,12 @@ Callable EditorData::get_move_array_element_function(const StringName &p_class)
}
void EditorData::remove_editor_plugin(EditorPlugin *p_plugin) {
- p_plugin->undo_redo = nullptr;
+ p_plugin->undo_redo = Ref<EditorUndoRedoManager>();
editor_plugins.erase(p_plugin);
}
void EditorData::add_editor_plugin(EditorPlugin *p_plugin) {
- p_plugin->undo_redo = &undo_redo;
+ p_plugin->undo_redo = undo_redo_manager;
editor_plugins.push_back(p_plugin);
}
@@ -505,8 +547,8 @@ int EditorData::add_edited_scene(int p_at_pos) {
es.path = String();
es.file_modified_time = 0;
es.history_current = -1;
- es.version = 0;
es.live_edit_root = NodePath(String("/root"));
+ es.history_id = last_created_scene++;
if (p_at_pos == edited_scene.size()) {
edited_scene.push_back(es);
@@ -547,6 +589,7 @@ void EditorData::remove_scene(int p_idx) {
ScriptEditor::get_singleton()->close_builtin_scripts_from_scene(edited_scene[p_idx].path);
}
+ undo_redo_manager->discard_history(edited_scene[p_idx].history_id);
edited_scene.remove_at(p_idx);
}
@@ -679,26 +722,10 @@ Vector<EditorData::EditedScene> EditorData::get_edited_scenes() const {
return out_edited_scenes_list;
}
-void EditorData::set_edited_scene_version(uint64_t version, int p_scene_idx) {
- ERR_FAIL_INDEX(current_edited_scene, edited_scene.size());
- if (p_scene_idx < 0) {
- edited_scene.write[current_edited_scene].version = version;
- } else {
- ERR_FAIL_INDEX(p_scene_idx, edited_scene.size());
- edited_scene.write[p_scene_idx].version = version;
- }
-}
-
-uint64_t EditorData::get_scene_version(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), 0);
- return edited_scene[p_idx].version;
-}
-
void EditorData::set_scene_modified_time(int p_idx, uint64_t p_time) {
if (p_idx == -1) {
p_idx = current_edited_scene;
}
-
ERR_FAIL_INDEX(p_idx, edited_scene.size());
edited_scene.write[p_idx].file_modified_time = p_time;
@@ -991,6 +1018,7 @@ void EditorData::script_class_load_icon_paths() {
EditorData::EditorData() {
current_edited_scene = -1;
+ undo_redo_manager.instantiate();
script_class_load_icon_paths();
}
@@ -1115,8 +1143,8 @@ void EditorSelection::_emit_change() {
emitted = false;
}
-Array EditorSelection::_get_transformable_selected_nodes() {
- Array ret;
+TypedArray<Node> EditorSelection::_get_transformable_selected_nodes() {
+ TypedArray<Node> ret;
for (const Node *E : selected_node_list) {
ret.push_back(E);
diff --git a/editor/editor_data.h b/editor/editor_data.h
index 351c63f4b9..1da188c546 100644
--- a/editor/editor_data.h
+++ b/editor/editor_data.h
@@ -31,12 +31,12 @@
#ifndef EDITOR_DATA_H
#define EDITOR_DATA_H
-#include "core/object/undo_redo.h"
#include "core/templates/list.h"
#include "scene/resources/texture.h"
class ConfigFile;
class EditorPlugin;
+class EditorUndoRedoManager;
/**
* Stores the history of objects which have been selected for editing in the Editor & the Inspector.
@@ -118,8 +118,9 @@ public:
Vector<EditorSelectionHistory::HistoryElement> history_stored;
int history_current = 0;
Dictionary custom_state;
- uint64_t version = 0;
NodePath live_edit_root;
+ int history_id = 0;
+ uint64_t last_checked_version = 0;
};
private:
@@ -132,12 +133,13 @@ private:
HashMap<String, Vector<CustomType>> custom_types;
List<PropertyData> clipboard;
- UndoRedo undo_redo;
+ Ref<EditorUndoRedoManager> undo_redo_manager;
Vector<Callable> undo_redo_callbacks;
HashMap<StringName, Callable> move_element_functions;
Vector<EditedScene> edited_scene;
- int current_edited_scene;
+ int current_edited_scene = -1;
+ int last_created_scene = 1;
bool _find_updated_instances(Node *p_root, Node *p_node, HashSet<String> &checked_paths);
@@ -166,7 +168,7 @@ public:
int get_editor_plugin_count() const;
EditorPlugin *get_editor_plugin(int p_idx);
- UndoRedo &get_undo_redo();
+ Ref<EditorUndoRedoManager> &get_undo_redo();
void add_undo_redo_inspector_hook_callback(Callable p_callable); // Callbacks should have this signature: void (Object* undo_redo, Object *modified_object, String property, Variant new_value)
void remove_undo_redo_inspector_hook_callback(Callable p_callable);
const Vector<Callable> get_undo_redo_inspector_hook_callback();
@@ -200,7 +202,6 @@ public:
void set_scene_path(int p_idx, const String &p_path);
Ref<Script> get_scene_root_script(int p_idx) const;
void set_edited_scene_version(uint64_t version, int p_scene_idx = -1);
- uint64_t get_scene_version(int p_idx) const;
void set_scene_modified_time(int p_idx, uint64_t p_time);
uint64_t get_scene_modified_time(int p_idx) const;
void clear_edited_scenes();
@@ -210,6 +211,13 @@ public:
void move_edited_scene_to_index(int p_idx);
bool call_build();
+ void set_scene_as_saved(int p_idx);
+ bool is_scene_changed(int p_idx);
+
+ int get_scene_history_id_from_path(const String &p_path) const;
+ int get_current_edited_scene_history_id() const;
+ int get_scene_history_id(int p_idx) const;
+
void set_plugin_window_layout(Ref<ConfigFile> p_layout);
void get_plugin_window_layout(Ref<ConfigFile> p_layout);
@@ -263,7 +271,7 @@ class EditorSelection : public Object {
List<Node *> selected_node_list;
void _update_node_list();
- Array _get_transformable_selected_nodes();
+ TypedArray<Node> _get_transformable_selected_nodes();
void _emit_change();
protected:
diff --git a/editor/editor_dir_dialog.cpp b/editor/editor_dir_dialog.cpp
index 4071722185..3bb050ce77 100644
--- a/editor/editor_dir_dialog.cpp
+++ b/editor/editor_dir_dialog.cpp
@@ -172,7 +172,7 @@ void EditorDirDialog::_make_dir_confirm() {
mkdirerr->popup_centered(Size2(250, 80) * EDSCALE);
} else {
opened_paths.insert(dir);
- //reload(dir.plus_file(makedirname->get_text()));
+ //reload(dir.path_join(makedirname->get_text()));
EditorFileSystem::get_singleton()->scan_changes(); //we created a dir, so rescan changes
}
makedirname->set_text(""); // reset label
diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp
index ab6dec7eeb..45d7fa9357 100644
--- a/editor/editor_feature_profile.cpp
+++ b/editor/editor_feature_profile.cpp
@@ -315,7 +315,7 @@ void EditorFeatureProfileManager::_notification(int p_what) {
current_profile = EDITOR_GET("_default_feature_profile");
if (!current_profile.is_empty()) {
current.instantiate();
- Error err = current->load_from_file(EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(current_profile + ".profile"));
+ Error err = current->load_from_file(EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(current_profile + ".profile"));
if (err != OK) {
ERR_PRINT("Error loading default feature profile: " + current_profile);
current_profile = String();
@@ -324,6 +324,11 @@ void EditorFeatureProfileManager::_notification(int p_what) {
}
_update_profile_list(current_profile);
} break;
+
+ case NOTIFICATION_THEME_CHANGED: {
+ // Make sure that the icons are correctly adjusted if the theme's lightness was switched.
+ _update_selected_profile();
+ } break;
}
}
@@ -341,7 +346,7 @@ void EditorFeatureProfileManager::_update_profile_list(const String &p_select_pr
if (p_select_profile.is_empty()) { //default, keep
if (profile_list->get_selected() >= 0) {
selected_profile = profile_list->get_item_metadata(profile_list->get_selected());
- if (!FileAccess::exists(EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(selected_profile + ".profile"))) {
+ if (!FileAccess::exists(EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(selected_profile + ".profile"))) {
selected_profile = String(); //does not exist
}
}
@@ -470,7 +475,7 @@ void EditorFeatureProfileManager::_create_new_profile() {
EditorNode::get_singleton()->show_warning(TTR("Profile must be a valid filename and must not contain '.'"));
return;
}
- String file = EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(name + ".profile");
+ String file = EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(name + ".profile");
if (FileAccess::exists(file)) {
EditorNode::get_singleton()->show_warning(TTR("Profile with this name already exists."));
return;
@@ -749,8 +754,8 @@ void EditorFeatureProfileManager::_update_selected_profile() {
} else {
//reload edited, if different from current
edited.instantiate();
- Error err = edited->load_from_file(EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(profile + ".profile"));
- ERR_FAIL_COND_MSG(err != OK, "Error when loading editor feature profile from file '" + EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(profile + ".profile") + "'.");
+ Error err = edited->load_from_file(EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(profile + ".profile"));
+ ERR_FAIL_COND_MSG(err != OK, "Error when loading editor feature profile from file '" + EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(profile + ".profile") + "'.");
}
updating_features = true;
@@ -805,7 +810,7 @@ void EditorFeatureProfileManager::_import_profiles(const Vector<String> &p_paths
return;
}
- String dst_file = EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(basefile);
+ String dst_file = EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(basefile);
if (FileAccess::exists(dst_file)) {
EditorNode::get_singleton()->show_warning(vformat(TTR("Profile '%s' already exists. Remove it first before importing, import aborted."), basefile.get_basename()));
@@ -820,7 +825,7 @@ void EditorFeatureProfileManager::_import_profiles(const Vector<String> &p_paths
Error err = profile->load_from_file(p_paths[i]);
ERR_CONTINUE(err != OK);
String basefile = p_paths[i].get_file();
- String dst_file = EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(basefile);
+ String dst_file = EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(basefile);
profile->save_to_file(dst_file);
}
@@ -844,7 +849,7 @@ void EditorFeatureProfileManager::_save_and_update() {
ERR_FAIL_COND(edited_path.is_empty());
ERR_FAIL_COND(edited.is_null());
- edited->save_to_file(EditorPaths::get_singleton()->get_feature_profiles_dir().plus_file(edited_path + ".profile"));
+ edited->save_to_file(EditorPaths::get_singleton()->get_feature_profiles_dir().path_join(edited_path + ".profile"));
if (edited == current) {
update_timer->start();
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index 2f1134e8ef..e24aa995c8 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -251,7 +251,7 @@ void EditorFileDialog::_file_submitted(const String &p_file) {
}
void EditorFileDialog::_save_confirm_pressed() {
- String f = dir_access->get_current_dir().plus_file(file->get_text());
+ String f = dir_access->get_current_dir().path_join(file->get_text());
_save_to_recent();
hide();
emit_signal(SNAME("file_selected"), f);
@@ -284,7 +284,7 @@ void EditorFileDialog::_post_popup() {
}
if (is_visible() && !get_current_file().is_empty()) {
- _request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+ _request_single_thumbnail(get_current_dir().path_join(get_current_file()));
}
if (is_visible()) {
@@ -381,7 +381,7 @@ void EditorFileDialog::_action_pressed() {
Vector<String> files;
for (int i = 0; i < item_list->get_item_count(); i++) {
if (item_list->is_selected(i)) {
- files.push_back(fbase.plus_file(item_list->get_item_text(i)));
+ files.push_back(fbase.path_join(item_list->get_item_text(i)));
}
}
@@ -395,7 +395,7 @@ void EditorFileDialog::_action_pressed() {
}
String file_text = file->get_text();
- String f = file_text.is_absolute_path() ? file_text : dir_access->get_current_dir().plus_file(file_text);
+ String f = file_text.is_absolute_path() ? file_text : dir_access->get_current_dir().path_join(file_text);
if ((mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_FILE) && dir_access->file_exists(f)) {
_save_to_recent();
@@ -410,7 +410,7 @@ void EditorFileDialog::_action_pressed() {
if (item_list->is_selected(i)) {
Dictionary d = item_list->get_item_metadata(i);
if (d["dir"]) {
- path = path.plus_file(d["name"]);
+ path = path.path_join(d["name"]);
break;
}
@@ -461,7 +461,7 @@ void EditorFileDialog::_action_pressed() {
if (!valid && filterSliceCount > 0) {
String str = (flt.get_slice(",", 0).strip_edges());
f += str.substr(1, str.length() - 1);
- _request_single_thumbnail(get_current_dir().plus_file(f.get_file()));
+ _request_single_thumbnail(get_current_dir().path_join(f.get_file()));
file->set_text(f.get_file());
valid = true;
}
@@ -505,7 +505,7 @@ void EditorFileDialog::_item_selected(int p_item) {
if (!d["dir"]) {
file->set_text(d["name"]);
- _request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+ _request_single_thumbnail(get_current_dir().path_join(get_current_file()));
} else if (mode == FILE_MODE_OPEN_DIR) {
set_ok_button_text(TTR("Select This Folder"));
}
@@ -523,7 +523,7 @@ void EditorFileDialog::_multi_selected(int p_item, bool p_selected) {
if (!d["dir"] && p_selected) {
file->set_text(d["name"]);
- _request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+ _request_single_thumbnail(get_current_dir().path_join(get_current_file()));
}
get_ok_button()->set_disabled(_is_open_should_be_disabled());
@@ -830,7 +830,7 @@ void EditorFileDialog::update_file_list() {
Dictionary d;
d["name"] = dir_name;
- d["path"] = cdir.plus_file(dir_name);
+ d["path"] = cdir.path_join(dir_name);
d["dir"] = true;
item_list->set_item_metadata(-1, d);
@@ -879,7 +879,7 @@ void EditorFileDialog::update_file_list() {
item_list->add_item(files.front()->get());
if (get_icon_func) {
- Ref<Texture2D> icon = get_icon_func(cdir.plus_file(files.front()->get()));
+ Ref<Texture2D> icon = get_icon_func(cdir.path_join(files.front()->get()));
if (display_mode == DISPLAY_THUMBNAILS) {
item_list->set_item_icon(-1, file_thumbnail);
item_list->set_item_tag_icon(-1, icon);
@@ -891,7 +891,7 @@ void EditorFileDialog::update_file_list() {
Dictionary d;
d["name"] = files.front()->get();
d["dir"] = false;
- String fullpath = cdir.plus_file(files.front()->get());
+ String fullpath = cdir.path_join(files.front()->get());
d["path"] = fullpath;
item_list->set_item_metadata(-1, d);
@@ -995,7 +995,7 @@ String EditorFileDialog::get_current_file() const {
}
String EditorFileDialog::get_current_path() const {
- return dir_access->get_current_dir().plus_file(file->get_text());
+ return dir_access->get_current_dir().path_join(file->get_text());
}
void EditorFileDialog::set_current_dir(const String &p_dir) {
@@ -1014,7 +1014,7 @@ void EditorFileDialog::set_current_file(const String &p_file) {
_focus_file_text();
if (is_visible()) {
- _request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
+ _request_single_thumbnail(get_current_dir().path_join(get_current_file()));
}
}
@@ -1625,13 +1625,13 @@ EditorFileDialog::EditorFileDialog() {
dir_prev = memnew(Button);
dir_prev->set_flat(true);
- dir_prev->set_tooltip(TTR("Go to previous folder."));
+ dir_prev->set_tooltip_text(TTR("Go to previous folder."));
dir_next = memnew(Button);
dir_next->set_flat(true);
- dir_next->set_tooltip(TTR("Go to next folder."));
+ dir_next->set_tooltip_text(TTR("Go to next folder."));
dir_up = memnew(Button);
dir_up->set_flat(true);
- dir_up->set_tooltip(TTR("Go to parent folder."));
+ dir_up->set_tooltip_text(TTR("Go to parent folder."));
pathhb->add_child(dir_prev);
pathhb->add_child(dir_next);
@@ -1655,14 +1655,14 @@ EditorFileDialog::EditorFileDialog() {
refresh = memnew(Button);
refresh->set_flat(true);
- refresh->set_tooltip(TTR("Refresh files."));
+ refresh->set_tooltip_text(TTR("Refresh files."));
refresh->connect("pressed", callable_mp(this, &EditorFileDialog::update_file_list));
pathhb->add_child(refresh);
favorite = memnew(Button);
favorite->set_flat(true);
favorite->set_toggle_mode(true);
- favorite->set_tooltip(TTR("(Un)favorite current folder."));
+ favorite->set_tooltip_text(TTR("(Un)favorite current folder."));
favorite->connect("pressed", callable_mp(this, &EditorFileDialog::_favorite_pressed));
pathhb->add_child(favorite);
@@ -1670,7 +1670,7 @@ EditorFileDialog::EditorFileDialog() {
show_hidden->set_flat(true);
show_hidden->set_toggle_mode(true);
show_hidden->set_pressed(is_showing_hidden_files());
- show_hidden->set_tooltip(TTR("Toggle the visibility of hidden files."));
+ show_hidden->set_tooltip_text(TTR("Toggle the visibility of hidden files."));
show_hidden->connect("toggled", callable_mp(this, &EditorFileDialog::set_show_hidden_files));
pathhb->add_child(show_hidden);
@@ -1685,7 +1685,7 @@ EditorFileDialog::EditorFileDialog() {
mode_thumbnails->set_toggle_mode(true);
mode_thumbnails->set_pressed(display_mode == DISPLAY_THUMBNAILS);
mode_thumbnails->set_button_group(view_mode_group);
- mode_thumbnails->set_tooltip(TTR("View items as a grid of thumbnails."));
+ mode_thumbnails->set_tooltip_text(TTR("View items as a grid of thumbnails."));
pathhb->add_child(mode_thumbnails);
mode_list = memnew(Button);
@@ -1694,7 +1694,7 @@ EditorFileDialog::EditorFileDialog() {
mode_list->set_toggle_mode(true);
mode_list->set_pressed(display_mode == DISPLAY_LIST);
mode_list->set_button_group(view_mode_group);
- mode_list->set_tooltip(TTR("View items as a list."));
+ mode_list->set_tooltip_text(TTR("View items as a list."));
pathhb->add_child(mode_list);
shortcuts_container = memnew(HBoxContainer);
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 1a105c7fe8..177bc6d2b2 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -99,7 +99,7 @@ String EditorFileSystemDirectory::get_path() const {
String p;
const EditorFileSystemDirectory *d = this;
while (d->parent) {
- p = d->name.plus_file(p);
+ p = d->name.path_join(p);
d = d->parent;
}
@@ -110,7 +110,7 @@ String EditorFileSystemDirectory::get_file_path(int p_idx) const {
String file = get_file(p_idx);
const EditorFileSystemDirectory *d = this;
while (d->parent) {
- file = d->name.plus_file(file);
+ file = d->name.path_join(file);
d = d->parent;
}
@@ -219,7 +219,7 @@ void EditorFileSystem::_scan_filesystem() {
String project = ProjectSettings::get_singleton()->get_resource_path();
- String fscache = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(CACHE_FILE_NAME);
+ String fscache = EditorPaths::get_singleton()->get_project_settings_dir().path_join(CACHE_FILE_NAME);
{
Ref<FileAccess> f = FileAccess::open(fscache, FileAccess::READ);
@@ -261,7 +261,7 @@ void EditorFileSystem::_scan_filesystem() {
String file;
file = name;
- name = cpath.plus_file(name);
+ name = cpath.path_join(name);
FileCache fc;
fc.type = split[1];
@@ -289,7 +289,7 @@ void EditorFileSystem::_scan_filesystem() {
}
}
- String update_cache = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("filesystem_update4");
+ String update_cache = EditorPaths::get_singleton()->get_project_settings_dir().path_join("filesystem_update4");
if (FileAccess::exists(update_cache)) {
{
@@ -332,7 +332,7 @@ void EditorFileSystem::_scan_filesystem() {
void EditorFileSystem::_save_filesystem_cache() {
group_file_cache.clear();
- String fscache = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(CACHE_FILE_NAME);
+ String fscache = EditorPaths::get_singleton()->get_project_settings_dir().path_join(CACHE_FILE_NAME);
Ref<FileAccess> f = FileAccess::open(fscache, FileAccess::WRITE);
ERR_FAIL_COND_MSG(f.is_null(), "Cannot create file '" + fscache + "'. Check user write permissions.");
@@ -758,7 +758,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
continue;
}
- if (_should_skip_directory(cd.plus_file(f))) {
+ if (_should_skip_directory(cd.path_join(f))) {
continue;
}
@@ -822,7 +822,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
EditorFileSystemDirectory::FileInfo *fi = memnew(EditorFileSystemDirectory::FileInfo);
fi->file = E->get();
- String path = cd.plus_file(fi->file);
+ String path = cd.path_join(fi->file);
FileCache *fc = file_cache.getptr(path);
uint64_t mt = FileAccess::get_modified_time(path);
@@ -982,7 +982,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
int idx = p_dir->find_dir_index(f);
if (idx == -1) {
- if (_should_skip_directory(cd.plus_file(f))) {
+ if (_should_skip_directory(cd.path_join(f))) {
continue;
}
@@ -991,7 +991,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
efd->parent = p_dir;
efd->name = f;
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
- d->change_dir(cd.plus_file(f));
+ d->change_dir(cd.path_join(f));
_scan_new_dir(efd, d, p_progress.get_sub(1, 1));
ItemAction ia;
@@ -1017,7 +1017,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
EditorFileSystemDirectory::FileInfo *fi = memnew(EditorFileSystemDirectory::FileInfo);
fi->file = f;
- String path = cd.plus_file(fi->file);
+ String path = cd.path_join(fi->file);
fi->modified_time = FileAccess::get_modified_time(path);
fi->import_modified_time = 0;
fi->type = ResourceLoader::get_resource_type(path);
@@ -1066,7 +1066,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
continue;
}
- String path = cd.plus_file(p_dir->files[i]->file);
+ String path = cd.path_join(p_dir->files[i]->file);
if (import_extensions.has(p_dir->files[i]->file.get_extension().to_lower())) {
//check here if file must be imported or not
@@ -1192,11 +1192,6 @@ void EditorFileSystem::scan_changes() {
void EditorFileSystem::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- call_deferred(SNAME("scan")); //this should happen after every editor node entered the tree
-
- } break;
-
case NOTIFICATION_EXIT_TREE: {
Thread &active_thread = thread.is_started() ? thread : thread_sources;
if (use_threads && active_thread.is_started()) {
@@ -1457,7 +1452,7 @@ EditorFileSystemDirectory *EditorFileSystem::get_filesystem_path(const String &p
void EditorFileSystem::_save_late_updated_files() {
//files that already existed, and were modified, need re-scanning for dependencies upon project restart. This is done via saving this special file
- String fscache = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("filesystem_update4");
+ String fscache = EditorPaths::get_singleton()->get_project_settings_dir().path_join("filesystem_update4");
Ref<FileAccess> f = FileAccess::open(fscache, FileAccess::WRITE);
ERR_FAIL_COND_MSG(f.is_null(), "Cannot create file '" + fscache + "'. Check user write permissions.");
for (const String &E : late_update_files) {
@@ -2203,12 +2198,12 @@ bool EditorFileSystem::_should_skip_directory(const String &p_path) {
return true;
}
- if (FileAccess::exists(p_path.plus_file("project.godot"))) {
+ if (FileAccess::exists(p_path.path_join("project.godot"))) {
// skip if another project inside this
return true;
}
- if (FileAccess::exists(p_path.plus_file(".gdignore"))) {
+ if (FileAccess::exists(p_path.path_join(".gdignore"))) {
// skip if a `.gdignore` file is inside this
return true;
}
diff --git a/editor/editor_folding.cpp b/editor/editor_folding.cpp
index c1d6e505db..d455e0248e 100644
--- a/editor/editor_folding.cpp
+++ b/editor/editor_folding.cpp
@@ -56,7 +56,7 @@ void EditorFolding::save_resource_folding(const Ref<Resource> &p_resource, const
config->set_value("folding", "sections_unfolded", unfolds);
String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
- file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(file);
+ file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file);
config->save(file);
}
@@ -74,7 +74,7 @@ void EditorFolding::load_resource_folding(Ref<Resource> p_resource, const String
config.instantiate();
String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
- file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(file);
+ file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file);
if (config->load(file) != OK) {
return;
@@ -150,7 +150,7 @@ void EditorFolding::save_scene_folding(const Node *p_scene, const String &p_path
config->set_value("folding", "nodes_folded", nodes_folded);
String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
- file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(file);
+ file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file);
config->save(file);
}
@@ -160,7 +160,7 @@ void EditorFolding::load_scene_folding(Node *p_scene, const String &p_path) {
String path = EditorPaths::get_singleton()->get_project_settings_dir();
String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
- file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(file);
+ file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file);
if (config->load(file) != OK) {
return;
@@ -214,7 +214,7 @@ void EditorFolding::load_scene_folding(Node *p_scene, const String &p_path) {
bool EditorFolding::has_folding_data(const String &p_path) {
String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg";
- file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(file);
+ file = EditorPaths::get_singleton()->get_project_settings_dir().path_join(file);
return FileAccess::exists(file);
}
diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp
index a02051c8ee..fffe77f1c4 100644
--- a/editor/editor_fonts.cpp
+++ b/editor/editor_fonts.cpp
@@ -37,7 +37,7 @@
#include "scene/resources/default_theme/default_theme.h"
#include "scene/resources/font.h"
-Ref<FontFile> load_external_font(const String &p_path, TextServer::Hinting p_hinting, bool p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_msdf = false, TypedArray<Font> *r_fallbacks = nullptr) {
+Ref<FontFile> load_external_font(const String &p_path, TextServer::Hinting p_hinting, TextServer::FontAntialiasing p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_msdf = false, TypedArray<Font> *r_fallbacks = nullptr) {
Ref<FontFile> font;
font.instantiate();
@@ -45,7 +45,7 @@ Ref<FontFile> load_external_font(const String &p_path, TextServer::Hinting p_hin
font->set_data(data);
font->set_multichannel_signed_distance_field(p_msdf);
- font->set_antialiased(p_aa);
+ font->set_antialiasing(p_aa);
font->set_hinting(p_hinting);
font->set_force_autohinter(p_autohint);
font->set_subpixel_positioning(p_font_subpixel_positioning);
@@ -57,13 +57,13 @@ Ref<FontFile> load_external_font(const String &p_path, TextServer::Hinting p_hin
return font;
}
-Ref<FontFile> load_internal_font(const uint8_t *p_data, size_t p_size, TextServer::Hinting p_hinting, bool p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_msdf = false, TypedArray<Font> *r_fallbacks = nullptr) {
+Ref<FontFile> load_internal_font(const uint8_t *p_data, size_t p_size, TextServer::Hinting p_hinting, TextServer::FontAntialiasing p_aa, bool p_autohint, TextServer::SubpixelPositioning p_font_subpixel_positioning, bool p_msdf = false, TypedArray<Font> *r_fallbacks = nullptr) {
Ref<FontFile> font;
font.instantiate();
font->set_data_ptr(p_data, p_size);
font->set_multichannel_signed_distance_field(p_msdf);
- font->set_antialiased(p_aa);
+ font->set_antialiasing(p_aa);
font->set_hinting(p_hinting);
font->set_force_autohinter(p_autohint);
font->set_subpixel_positioning(p_font_subpixel_positioning);
@@ -91,7 +91,7 @@ Ref<FontVariation> make_bold_font(const Ref<Font> &p_font, double p_embolden, Ty
void editor_register_fonts(Ref<Theme> p_theme) {
Ref<DirAccess> dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- bool font_antialiased = (bool)EditorSettings::get_singleton()->get("interface/editor/font_antialiased");
+ TextServer::FontAntialiasing font_antialiasing = (TextServer::FontAntialiasing)(int)EditorSettings::get_singleton()->get("interface/editor/font_antialiasing");
int font_hinting_setting = (int)EditorSettings::get_singleton()->get("interface/editor/font_hinting");
TextServer::SubpixelPositioning font_subpixel_positioning = (TextServer::SubpixelPositioning)(int)EditorSettings::get_singleton()->get("interface/editor/font_subpixel_positioning");
@@ -123,47 +123,47 @@ void editor_register_fonts(Ref<Theme> p_theme) {
const int default_font_size = int(EDITOR_GET("interface/editor/main_font_size")) * EDSCALE;
const float embolden_strength = 0.6;
- Ref<Font> default_font = load_internal_font(_font_NotoSans_Regular, _font_NotoSans_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false);
- Ref<Font> default_font_msdf = load_internal_font(_font_NotoSans_Regular, _font_NotoSans_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, true);
+ Ref<Font> default_font = load_internal_font(_font_NotoSans_Regular, _font_NotoSans_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false);
+ Ref<Font> default_font_msdf = load_internal_font(_font_NotoSans_Regular, _font_NotoSans_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, true);
TypedArray<Font> fallbacks;
- Ref<FontFile> arabic_font = load_internal_font(_font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> bengali_font = load_internal_font(_font_NotoSansBengaliUI_Regular, _font_NotoSansBengaliUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> devanagari_font = load_internal_font(_font_NotoSansDevanagariUI_Regular, _font_NotoSansDevanagariUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> georgian_font = load_internal_font(_font_NotoSansGeorgian_Regular, _font_NotoSansGeorgian_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> hebrew_font = load_internal_font(_font_NotoSansHebrew_Regular, _font_NotoSansHebrew_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> malayalam_font = load_internal_font(_font_NotoSansMalayalamUI_Regular, _font_NotoSansMalayalamUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> oriya_font = load_internal_font(_font_NotoSansOriyaUI_Regular, _font_NotoSansOriyaUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> sinhala_font = load_internal_font(_font_NotoSansSinhalaUI_Regular, _font_NotoSansSinhalaUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> tamil_font = load_internal_font(_font_NotoSansTamilUI_Regular, _font_NotoSansTamilUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> telugu_font = load_internal_font(_font_NotoSansTeluguUI_Regular, _font_NotoSansTeluguUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> thai_font = load_internal_font(_font_NotoSansThaiUI_Regular, _font_NotoSansThaiUI_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> fallback_font = load_internal_font(_font_DroidSansFallback, _font_DroidSansFallback_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
- Ref<FontFile> japanese_font = load_internal_font(_font_DroidSansJapanese, _font_DroidSansJapanese_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> arabic_font = load_internal_font(_font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> bengali_font = load_internal_font(_font_NotoSansBengaliUI_Regular, _font_NotoSansBengaliUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> devanagari_font = load_internal_font(_font_NotoSansDevanagariUI_Regular, _font_NotoSansDevanagariUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> georgian_font = load_internal_font(_font_NotoSansGeorgian_Regular, _font_NotoSansGeorgian_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> hebrew_font = load_internal_font(_font_NotoSansHebrew_Regular, _font_NotoSansHebrew_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> malayalam_font = load_internal_font(_font_NotoSansMalayalamUI_Regular, _font_NotoSansMalayalamUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> oriya_font = load_internal_font(_font_NotoSansOriyaUI_Regular, _font_NotoSansOriyaUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> sinhala_font = load_internal_font(_font_NotoSansSinhalaUI_Regular, _font_NotoSansSinhalaUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> tamil_font = load_internal_font(_font_NotoSansTamilUI_Regular, _font_NotoSansTamilUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> telugu_font = load_internal_font(_font_NotoSansTeluguUI_Regular, _font_NotoSansTeluguUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> thai_font = load_internal_font(_font_NotoSansThaiUI_Regular, _font_NotoSansThaiUI_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> fallback_font = load_internal_font(_font_DroidSansFallback, _font_DroidSansFallback_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
+ Ref<FontFile> japanese_font = load_internal_font(_font_DroidSansJapanese, _font_DroidSansJapanese_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks);
default_font->set_fallbacks(fallbacks);
default_font_msdf->set_fallbacks(fallbacks);
- Ref<FontFile> default_font_bold = load_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false);
- Ref<FontFile> default_font_bold_msdf = load_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, true);
+ Ref<FontFile> default_font_bold = load_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false);
+ Ref<FontFile> default_font_bold_msdf = load_internal_font(_font_NotoSans_Bold, _font_NotoSans_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, true);
TypedArray<Font> fallbacks_bold;
- Ref<FontFile> arabic_font_bold = load_internal_font(_font_NotoNaskhArabicUI_Bold, _font_NotoNaskhArabicUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
- Ref<FontFile> bengali_font_bold = load_internal_font(_font_NotoSansBengaliUI_Bold, _font_NotoSansBengaliUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
- Ref<FontFile> devanagari_font_bold = load_internal_font(_font_NotoSansDevanagariUI_Bold, _font_NotoSansDevanagariUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
- Ref<FontFile> georgian_font_bold = load_internal_font(_font_NotoSansGeorgian_Bold, _font_NotoSansGeorgian_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
- Ref<FontFile> hebrew_font_bold = load_internal_font(_font_NotoSansHebrew_Bold, _font_NotoSansHebrew_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
- Ref<FontFile> malayalam_font_bold = load_internal_font(_font_NotoSansMalayalamUI_Bold, _font_NotoSansMalayalamUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
- Ref<FontFile> oriya_font_bold = load_internal_font(_font_NotoSansOriyaUI_Bold, _font_NotoSansOriyaUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
- Ref<FontFile> sinhala_font_bold = load_internal_font(_font_NotoSansSinhalaUI_Bold, _font_NotoSansSinhalaUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
- Ref<FontFile> tamil_font_bold = load_internal_font(_font_NotoSansTamilUI_Bold, _font_NotoSansTamilUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
- Ref<FontFile> telugu_font_bold = load_internal_font(_font_NotoSansTeluguUI_Bold, _font_NotoSansTeluguUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
- Ref<FontFile> thai_font_bold = load_internal_font(_font_NotoSansThaiUI_Bold, _font_NotoSansThaiUI_Bold_size, font_hinting, font_antialiased, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> arabic_font_bold = load_internal_font(_font_NotoNaskhArabicUI_Bold, _font_NotoNaskhArabicUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> bengali_font_bold = load_internal_font(_font_NotoSansBengaliUI_Bold, _font_NotoSansBengaliUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> devanagari_font_bold = load_internal_font(_font_NotoSansDevanagariUI_Bold, _font_NotoSansDevanagariUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> georgian_font_bold = load_internal_font(_font_NotoSansGeorgian_Bold, _font_NotoSansGeorgian_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> hebrew_font_bold = load_internal_font(_font_NotoSansHebrew_Bold, _font_NotoSansHebrew_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> malayalam_font_bold = load_internal_font(_font_NotoSansMalayalamUI_Bold, _font_NotoSansMalayalamUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> oriya_font_bold = load_internal_font(_font_NotoSansOriyaUI_Bold, _font_NotoSansOriyaUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> sinhala_font_bold = load_internal_font(_font_NotoSansSinhalaUI_Bold, _font_NotoSansSinhalaUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> tamil_font_bold = load_internal_font(_font_NotoSansTamilUI_Bold, _font_NotoSansTamilUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> telugu_font_bold = load_internal_font(_font_NotoSansTeluguUI_Bold, _font_NotoSansTeluguUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
+ Ref<FontFile> thai_font_bold = load_internal_font(_font_NotoSansThaiUI_Bold, _font_NotoSansThaiUI_Bold_size, font_hinting, font_antialiasing, true, font_subpixel_positioning, false, &fallbacks_bold);
Ref<FontVariation> fallback_font_bold = make_bold_font(fallback_font, embolden_strength, &fallbacks_bold);
Ref<FontVariation> japanese_font_bold = make_bold_font(japanese_font, embolden_strength, &fallbacks_bold);
default_font_bold->set_fallbacks(fallbacks_bold);
default_font_bold_msdf->set_fallbacks(fallbacks_bold);
- Ref<FontFile> default_font_mono = load_internal_font(_font_JetBrainsMono_Regular, _font_JetBrainsMono_Regular_size, font_hinting, font_antialiased, true, font_subpixel_positioning);
+ Ref<FontFile> default_font_mono = load_internal_font(_font_JetBrainsMono_Regular, _font_JetBrainsMono_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning);
default_font_mono->set_fallbacks(fallbacks);
// Init base font configs and load custom fonts.
@@ -174,7 +174,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
Ref<FontVariation> default_fc;
default_fc.instantiate();
if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) {
- Ref<FontFile> custom_font = load_external_font(custom_font_path, font_hinting, font_antialiased, true, font_subpixel_positioning);
+ Ref<FontFile> custom_font = load_external_font(custom_font_path, font_hinting, font_antialiasing, true, font_subpixel_positioning);
{
TypedArray<Font> fallback_custom;
fallback_custom.push_back(default_font);
@@ -191,7 +191,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
Ref<FontVariation> default_fc_msdf;
default_fc_msdf.instantiate();
if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) {
- Ref<FontFile> custom_font = load_external_font(custom_font_path, font_hinting, font_antialiased, true, font_subpixel_positioning);
+ Ref<FontFile> custom_font = load_external_font(custom_font_path, font_hinting, font_antialiasing, true, font_subpixel_positioning);
{
TypedArray<Font> fallback_custom;
fallback_custom.push_back(default_font_msdf);
@@ -208,7 +208,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
Ref<FontVariation> bold_fc;
bold_fc.instantiate();
if (custom_font_path_bold.length() > 0 && dir->file_exists(custom_font_path_bold)) {
- Ref<FontFile> custom_font = load_external_font(custom_font_path_bold, font_hinting, font_antialiased, true, font_subpixel_positioning);
+ Ref<FontFile> custom_font = load_external_font(custom_font_path_bold, font_hinting, font_antialiasing, true, font_subpixel_positioning);
{
TypedArray<Font> fallback_custom;
fallback_custom.push_back(default_font_bold);
@@ -216,7 +216,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
}
bold_fc->set_base_font(custom_font);
} else if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) {
- Ref<FontFile> custom_font = load_external_font(custom_font_path, font_hinting, font_antialiased, true, font_subpixel_positioning);
+ Ref<FontFile> custom_font = load_external_font(custom_font_path, font_hinting, font_antialiasing, true, font_subpixel_positioning);
{
TypedArray<Font> fallback_custom;
fallback_custom.push_back(default_font_bold);
@@ -234,7 +234,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
Ref<FontVariation> bold_fc_msdf;
bold_fc_msdf.instantiate();
if (custom_font_path_bold.length() > 0 && dir->file_exists(custom_font_path_bold)) {
- Ref<FontFile> custom_font = load_external_font(custom_font_path_bold, font_hinting, font_antialiased, true, font_subpixel_positioning);
+ Ref<FontFile> custom_font = load_external_font(custom_font_path_bold, font_hinting, font_antialiasing, true, font_subpixel_positioning);
{
TypedArray<Font> fallback_custom;
fallback_custom.push_back(default_font_bold_msdf);
@@ -242,7 +242,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
}
bold_fc_msdf->set_base_font(custom_font);
} else if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) {
- Ref<FontFile> custom_font = load_external_font(custom_font_path, font_hinting, font_antialiased, true, font_subpixel_positioning);
+ Ref<FontFile> custom_font = load_external_font(custom_font_path, font_hinting, font_antialiasing, true, font_subpixel_positioning);
{
TypedArray<Font> fallback_custom;
fallback_custom.push_back(default_font_bold_msdf);
@@ -260,7 +260,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
Ref<FontVariation> mono_fc;
mono_fc.instantiate();
if (custom_font_path_source.length() > 0 && dir->file_exists(custom_font_path_source)) {
- Ref<FontFile> custom_font = load_external_font(custom_font_path_source, font_hinting, font_antialiased, true, font_subpixel_positioning);
+ Ref<FontFile> custom_font = load_external_font(custom_font_path_source, font_hinting, font_antialiasing, true, font_subpixel_positioning);
{
TypedArray<Font> fallback_custom;
fallback_custom.push_back(default_font_mono);
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 5c3038c468..97f5363bb8 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -239,6 +239,27 @@ void EditorHelp::_add_type(const String &p_type, const String &p_enum) {
class_desc->pop();
}
+void EditorHelp::_add_type_icon(const String &p_type, int p_size) {
+ Ref<Texture2D> icon;
+ if (has_theme_icon(p_type, SNAME("EditorIcons"))) {
+ icon = get_theme_icon(p_type, SNAME("EditorIcons"));
+ } else if (ClassDB::class_exists(p_type) && ClassDB::is_parent_class(p_type, "Object")) {
+ icon = get_theme_icon(SNAME("Object"), SNAME("EditorIcons"));
+ } else {
+ icon = get_theme_icon(SNAME("ArrowRight"), SNAME("EditorIcons"));
+ }
+
+ Vector2i size = Vector2i(icon->get_width(), icon->get_height());
+ if (p_size > 0) {
+ // Ensures icon scales proportionally on both axis, based on icon height.
+ float ratio = p_size / float(size.height);
+ size.width *= ratio;
+ size.height *= ratio;
+ }
+
+ class_desc->add_image(icon, size.width, size.height);
+}
+
String EditorHelp::_fix_constant(const String &p_constant) const {
if (p_constant.strip_edges() == "4294967295") {
return "0xFFFFFFFF";
@@ -530,22 +551,13 @@ void EditorHelp::_update_doc() {
DocData::ClassDoc cd = doc->class_list[edited_class]; // Make a copy, so we can sort without worrying.
- Ref<Texture2D> icon;
- if (has_theme_icon(edited_class, SNAME("EditorIcons"))) {
- icon = get_theme_icon(edited_class, SNAME("EditorIcons"));
- } else if (ClassDB::class_exists(edited_class) && ClassDB::is_parent_class(edited_class, "Object")) {
- icon = get_theme_icon(SNAME("Object"), SNAME("EditorIcons"));
- } else {
- icon = get_theme_icon(SNAME("ArrowRight"), SNAME("EditorIcons"));
- }
-
// Class name
section_line.push_back(Pair<String, int>(TTR("Top"), 0));
class_desc->push_font(doc_title_font);
class_desc->push_font_size(doc_title_font_size);
class_desc->push_color(title_color);
class_desc->add_text(TTR("Class:") + " ");
- class_desc->add_image(icon, icon->get_width(), icon->get_height());
+ _add_type_icon(edited_class, doc_title_font_size);
class_desc->add_text(" ");
class_desc->push_color(headline_color);
_add_text(edited_class);
@@ -566,6 +578,8 @@ void EditorHelp::_update_doc() {
String inherits = cd.inherits;
while (!inherits.is_empty()) {
+ _add_type_icon(inherits);
+ class_desc->add_text(" "); // Extra space, otherwise icon borrows hyperlink from _add_type().
_add_type(inherits);
inherits = doc->class_list[inherits].inherits;
@@ -597,7 +611,8 @@ void EditorHelp::_update_doc() {
if (prev) {
class_desc->add_text(" , ");
}
-
+ _add_type_icon(E.value.name);
+ class_desc->add_text(" "); // Extra space, otherwise icon borrows hyperlink from _add_type().
_add_type(E.value.name);
prev = true;
}
@@ -1785,7 +1800,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
p_rt->add_text("[");
pos = brk_pos + 1;
- } else if (tag.begins_with("method ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ") || tag.begins_with("constant ") || tag.begins_with("theme_item ")) {
+ } else if (tag.begins_with("method ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ") || tag.begins_with("constant ") || tag.begins_with("annotation ") || tag.begins_with("theme_item ")) {
const int tag_end = tag.find(" ");
const String link_tag = tag.substr(0, tag_end);
const String link_target = tag.substr(tag_end + 1, tag.length()).lstrip(" ");
@@ -1803,6 +1818,21 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
p_rt->pop();
pos = brk_end + 1;
+ } else if (tag.begins_with("param ")) {
+ const int tag_end = tag.find(" ");
+ const String param_name = tag.substr(tag_end + 1, tag.length()).lstrip(" ");
+
+ // Use monospace font with translucent background color to make code easier to distinguish from other text.
+ p_rt->push_font(doc_code_font);
+ p_rt->push_bgcolor(Color(0.5, 0.5, 0.5, 0.15));
+ p_rt->push_color(code_color);
+ p_rt->add_text(param_name);
+ p_rt->pop();
+ p_rt->pop();
+ p_rt->pop();
+
+ pos = brk_end + 1;
+
} else if (doc->class_list.has(tag)) {
// Class reference tag such as [Node2D] or [SceneTree].
// Use monospace font with translucent colored background color to make clickable references
@@ -1899,7 +1929,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
}
String image = bbcode.substr(brk_end + 1, end - brk_end - 1);
- Ref<Texture2D> texture = ResourceLoader::load(base_path.plus_file(image), "Texture2D");
+ Ref<Texture2D> texture = ResourceLoader::load(base_path.path_join(image), "Texture2D");
if (texture.is_valid()) {
p_rt->add_image(texture);
}
@@ -1916,7 +1946,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
} else if (tag.begins_with("font=")) {
String fnt = tag.substr(5, tag.length());
- Ref<Font> font = ResourceLoader::load(base_path.plus_file(fnt), "Font");
+ Ref<Font> font = ResourceLoader::load(base_path.path_join(fnt), "Font");
if (font.is_valid()) {
p_rt->push_font(font);
} else {
@@ -2063,7 +2093,7 @@ void EditorHelp::update_toggle_scripts_button() {
} else {
toggle_scripts_button->set_icon(get_theme_icon(ScriptEditor::get_singleton()->is_scripts_panel_toggled() ? SNAME("Back") : SNAME("Forward"), SNAME("EditorIcons")));
}
- toggle_scripts_button->set_tooltip(vformat("%s (%s)", TTR("Toggle Scripts Panel"), ED_GET_SHORTCUT("script_editor/toggle_scripts_panel")->get_as_text()));
+ toggle_scripts_button->set_tooltip_text(vformat("%s (%s)", TTR("Toggle Scripts Panel"), ED_GET_SHORTCUT("script_editor/toggle_scripts_panel")->get_as_text()));
}
void EditorHelp::_bind_methods() {
diff --git a/editor/editor_help.h b/editor/editor_help.h
index 9f8da938f1..c9c1afb51b 100644
--- a/editor/editor_help.h
+++ b/editor/editor_help.h
@@ -153,6 +153,7 @@ class EditorHelp : public VBoxContainer {
//void _button_pressed(int p_idx);
void _add_type(const String &p_type, const String &p_enum = String());
+ void _add_type_icon(const String &p_type, int p_size = 0);
void _add_method(const DocData::MethodDoc &p_method, bool p_overview = true);
void _add_bulletpoint();
diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp
index 297d1226e3..b4678d8363 100644
--- a/editor/editor_help_search.cpp
+++ b/editor/editor_help_search.cpp
@@ -206,7 +206,7 @@ EditorHelpSearch::EditorHelpSearch() {
case_sensitive_button = memnew(Button);
case_sensitive_button->set_flat(true);
- case_sensitive_button->set_tooltip(TTR("Case Sensitive"));
+ case_sensitive_button->set_tooltip_text(TTR("Case Sensitive"));
case_sensitive_button->connect("pressed", callable_mp(this, &EditorHelpSearch::_update_results));
case_sensitive_button->set_toggle_mode(true);
case_sensitive_button->set_focus_mode(Control::FOCUS_NONE);
@@ -214,7 +214,7 @@ EditorHelpSearch::EditorHelpSearch() {
hierarchy_button = memnew(Button);
hierarchy_button->set_flat(true);
- hierarchy_button->set_tooltip(TTR("Show Hierarchy"));
+ hierarchy_button->set_tooltip_text(TTR("Show Hierarchy"));
hierarchy_button->connect("pressed", callable_mp(this, &EditorHelpSearch::_update_results));
hierarchy_button->set_toggle_mode(true);
hierarchy_button->set_pressed(true);
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index e06e3cbc5f..5033f842d5 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -340,6 +340,8 @@ void EditorProperty::_notification(int p_what) {
draw_string(font, Point2(ofs, v_ofs + font->get_ascent(font_size)), label, HORIZONTAL_ALIGNMENT_LEFT, text_limit, font_size, color);
}
+ ofs = size.width;
+
if (keying) {
Ref<Texture2D> key;
@@ -349,7 +351,7 @@ void EditorProperty::_notification(int p_what) {
key = get_theme_icon(SNAME("Key"), SNAME("EditorIcons"));
}
- ofs = size.width - key->get_width() - get_theme_constant(SNAME("hseparator"), SNAME("Tree"));
+ ofs -= key->get_width() + get_theme_constant(SNAME("hseparator"), SNAME("Tree"));
Color color2(1, 1, 1);
if (keying_hover) {
@@ -373,7 +375,7 @@ void EditorProperty::_notification(int p_what) {
close = get_theme_icon(SNAME("Close"), SNAME("EditorIcons"));
- ofs = size.width - close->get_width() - get_theme_constant(SNAME("hseparator"), SNAME("Tree"));
+ ofs -= close->get_width() + get_theme_constant(SNAME("hseparator"), SNAME("Tree"));
Color color2(1, 1, 1);
if (delete_hover) {
@@ -432,11 +434,11 @@ bool EditorProperty::is_read_only() const {
}
Variant EditorPropertyRevert::get_property_revert_value(Object *p_object, const StringName &p_property, bool *r_is_valid) {
- if (p_object->has_method("property_can_revert") && p_object->call("property_can_revert", p_property)) {
+ if (p_object->property_can_revert(p_property)) {
if (r_is_valid) {
*r_is_valid = true;
}
- return p_object->call("property_get_revert", p_property);
+ return p_object->property_get_revert(p_property);
}
return PropertyUtils::get_property_default_value(p_object, p_property, r_is_valid);
@@ -894,14 +896,9 @@ static Control *make_help_bit(const String &p_text, bool p_property) {
}
Control *EditorProperty::make_custom_tooltip(const String &p_text) const {
- tooltip_text = p_text;
return make_help_bit(p_text, true);
}
-String EditorProperty::get_tooltip_text() const {
- return tooltip_text;
-}
-
void EditorProperty::menu_option(int p_option) {
switch (p_option) {
case MENU_COPY_PROPERTY: {
@@ -949,7 +946,6 @@ void EditorProperty::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_edited_property"), &EditorProperty::get_edited_property);
ClassDB::bind_method(D_METHOD("get_edited_object"), &EditorProperty::get_edited_object);
- ClassDB::bind_method(D_METHOD("get_tooltip_text"), &EditorProperty::get_tooltip_text);
ClassDB::bind_method(D_METHOD("update_property"), &EditorProperty::update_property);
ClassDB::bind_method(D_METHOD("add_focusable", "control"), &EditorProperty::add_focusable);
@@ -965,7 +961,7 @@ void EditorProperty::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keying"), "set_keying", "is_keying");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deletable"), "set_deletable", "is_deletable");
- ADD_SIGNAL(MethodInfo("property_changed", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
+ ADD_SIGNAL(MethodInfo("property_changed", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), PropertyInfo(Variant::STRING_NAME, "field"), PropertyInfo(Variant::BOOL, "changing")));
ADD_SIGNAL(MethodInfo("multiple_properties_changed", PropertyInfo(Variant::PACKED_STRING_ARRAY, "properties"), PropertyInfo(Variant::ARRAY, "value")));
ADD_SIGNAL(MethodInfo("property_keyed", PropertyInfo(Variant::STRING_NAME, "property")));
ADD_SIGNAL(MethodInfo("property_deleted", PropertyInfo(Variant::STRING_NAME, "property")));
@@ -1127,7 +1123,6 @@ void EditorInspectorCategory::_notification(int p_what) {
}
Control *EditorInspectorCategory::make_custom_tooltip(const String &p_text) const {
- tooltip_text = p_text;
return make_help_bit(p_text, false);
}
@@ -1146,14 +1141,6 @@ Size2 EditorInspectorCategory::get_minimum_size() const {
return ms;
}
-void EditorInspectorCategory::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_tooltip_text"), &EditorInspectorCategory::get_tooltip_text);
-}
-
-String EditorInspectorCategory::get_tooltip_text() const {
- return tooltip_text;
-}
-
EditorInspectorCategory::EditorInspectorCategory() {
}
@@ -1613,12 +1600,11 @@ void EditorInspectorArray::_rmb_popup_id_pressed(int p_id) {
_clear_array();
break;
case OPTION_RESIZE_ARRAY:
- new_size = count;
- new_size_line_edit->set_text(Variant(new_size));
+ new_size_spin_box->set_value(count);
resize_dialog->get_ok_button()->set_disabled(true);
- resize_dialog->popup_centered();
- new_size_line_edit->grab_focus();
- new_size_line_edit->select_all();
+ resize_dialog->popup_centered(Size2i(250, 0) * EDSCALE);
+ new_size_spin_box->get_line_edit()->grab_focus();
+ new_size_spin_box->get_line_edit()->select_all();
break;
default:
break;
@@ -1677,7 +1663,7 @@ void EditorInspectorArray::_panel_gui_input(Ref<InputEvent> p_event, int p_index
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == MouseButton::RIGHT) {
+ if (movable && mb->get_button_index() == MouseButton::RIGHT) {
popup_array_index_pressed = begin_array_index + p_index;
rmb_popup->set_item_disabled(OPTION_MOVE_UP, popup_array_index_pressed == 0);
rmb_popup->set_item_disabled(OPTION_MOVE_DOWN, popup_array_index_pressed == count - 1);
@@ -1702,7 +1688,7 @@ void EditorInspectorArray::_move_element(int p_element_index, int p_to_pos) {
// Call the function.
Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name());
if (move_function.is_valid()) {
- Variant args[] = { (Object *)undo_redo, object, array_element_prefix, p_element_index, p_to_pos };
+ Variant args[] = { undo_redo.ptr(), object, array_element_prefix, p_element_index, p_to_pos };
const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] };
Variant return_value;
Callable::CallError call_error;
@@ -1712,43 +1698,112 @@ void EditorInspectorArray::_move_element(int p_element_index, int p_to_pos) {
}
} else if (mode == MODE_USE_COUNT_PROPERTY) {
ERR_FAIL_COND(p_to_pos < -1 || p_to_pos > count);
- List<PropertyInfo> object_property_list;
- object->get_property_list(&object_property_list);
- Array properties_as_array = _extract_properties_as_array(object_property_list);
- properties_as_array.resize(count);
+ if (!swap_method.is_empty()) {
+ ERR_FAIL_COND(!object->has_method(swap_method));
- // For undoing things
- undo_redo->add_undo_property(object, count_property, properties_as_array.size());
- for (int i = 0; i < (int)properties_as_array.size(); i++) {
- Dictionary d = Dictionary(properties_as_array[i]);
- Array keys = d.keys();
- for (int j = 0; j < keys.size(); j++) {
- String key = keys[j];
- undo_redo->add_undo_property(object, vformat(key, i), d[key]);
- }
- }
+ // Swap method was provided, use it.
+ if (p_element_index < 0) {
+ // Add an element at position
+ undo_redo->add_do_property(object, count_property, count + 1);
+ if (p_to_pos >= 0) {
+ for (int i = count; i > p_to_pos; i--) {
+ undo_redo->add_do_method(object, swap_method, i, i - 1);
+ }
+ for (int i = p_to_pos; i < count; i++) {
+ undo_redo->add_undo_method(object, swap_method, i, i + 1);
+ }
+ }
+ undo_redo->add_undo_property(object, count_property, count);
+
+ } else if (p_to_pos < 0) {
+ if (count > 0) {
+ // Remove element at position
+ undo_redo->add_undo_property(object, count_property, count);
+
+ List<PropertyInfo> object_property_list;
+ object->get_property_list(&object_property_list);
+
+ for (int i = p_element_index; i < count - 1; i++) {
+ undo_redo->add_do_method(object, swap_method, i, i + 1);
+ }
+
+ for (int i = count; i > p_element_index; i--) {
+ undo_redo->add_undo_method(object, swap_method, i, i - 1);
+ }
+
+ String erase_prefix = String(array_element_prefix) + itos(p_element_index);
+
+ for (const PropertyInfo &E : object_property_list) {
+ if (E.name.begins_with(erase_prefix)) {
+ undo_redo->add_undo_property(object, E.name, object->get(E.name));
+ }
+ }
+
+ undo_redo->add_do_property(object, count_property, count - 1);
+ }
+ } else {
+ if (p_to_pos > p_element_index) {
+ p_to_pos--;
+ }
+
+ if (p_to_pos < p_element_index) {
+ for (int i = p_element_index; i > p_to_pos; i--) {
+ undo_redo->add_do_method(object, swap_method, i, i - 1);
+ }
+ for (int i = p_to_pos; i < p_element_index; i++) {
+ undo_redo->add_undo_method(object, swap_method, i, i + 1);
+ }
+ } else if (p_to_pos > p_element_index) {
+ for (int i = p_element_index; i < p_to_pos; i++) {
+ undo_redo->add_do_method(object, swap_method, i, i + 1);
+ }
- if (p_element_index < 0) {
- // Add an element.
- properties_as_array.insert(p_to_pos < 0 ? properties_as_array.size() : p_to_pos, Dictionary());
- } else if (p_to_pos < 0) {
- // Delete the element.
- properties_as_array.remove_at(p_element_index);
+ for (int i = p_to_pos; i > p_element_index; i--) {
+ undo_redo->add_undo_method(object, swap_method, i, i - 1);
+ }
+ }
+ }
} else {
- // Move the element.
- properties_as_array.insert(p_to_pos, properties_as_array[p_element_index].duplicate());
- properties_as_array.remove_at(p_to_pos < p_element_index ? p_element_index + 1 : p_element_index);
- }
+ // Use standard properties.
+ List<PropertyInfo> object_property_list;
+ object->get_property_list(&object_property_list);
- // Change the array size then set the properties.
- undo_redo->add_do_property(object, count_property, properties_as_array.size());
- for (int i = 0; i < (int)properties_as_array.size(); i++) {
- Dictionary d = properties_as_array[i];
- Array keys = d.keys();
- for (int j = 0; j < keys.size(); j++) {
- String key = keys[j];
- undo_redo->add_do_property(object, vformat(key, i), d[key]);
+ Array properties_as_array = _extract_properties_as_array(object_property_list);
+ properties_as_array.resize(count);
+
+ // For undoing things
+ undo_redo->add_undo_property(object, count_property, properties_as_array.size());
+ for (int i = 0; i < (int)properties_as_array.size(); i++) {
+ Dictionary d = Dictionary(properties_as_array[i]);
+ Array keys = d.keys();
+ for (int j = 0; j < keys.size(); j++) {
+ String key = keys[j];
+ undo_redo->add_undo_property(object, vformat(key, i), d[key]);
+ }
+ }
+
+ if (p_element_index < 0) {
+ // Add an element.
+ properties_as_array.insert(p_to_pos < 0 ? properties_as_array.size() : p_to_pos, Dictionary());
+ } else if (p_to_pos < 0) {
+ // Delete the element.
+ properties_as_array.remove_at(p_element_index);
+ } else {
+ // Move the element.
+ properties_as_array.insert(p_to_pos, properties_as_array[p_element_index].duplicate());
+ properties_as_array.remove_at(p_to_pos < p_element_index ? p_element_index + 1 : p_element_index);
+ }
+
+ // Change the array size then set the properties.
+ undo_redo->add_do_property(object, count_property, properties_as_array.size());
+ for (int i = 0; i < (int)properties_as_array.size(); i++) {
+ Dictionary d = properties_as_array[i];
+ Array keys = d.keys();
+ for (int j = 0; j < keys.size(); j++) {
+ String key = keys[j];
+ undo_redo->add_do_property(object, vformat(key, i), d[key]);
+ }
}
}
}
@@ -1777,7 +1832,7 @@ void EditorInspectorArray::_clear_array() {
// Call the function.
Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name());
if (move_function.is_valid()) {
- Variant args[] = { (Object *)undo_redo, object, array_element_prefix, i, -1 };
+ Variant args[] = { undo_redo.ptr(), object, array_element_prefix, i, -1 };
const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] };
Variant return_value;
Callable::CallError call_error;
@@ -1830,7 +1885,7 @@ void EditorInspectorArray::_resize_array(int p_size) {
// Call the function.
Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name());
if (move_function.is_valid()) {
- Variant args[] = { (Object *)undo_redo, object, array_element_prefix, -1, -1 };
+ Variant args[] = { undo_redo.ptr(), object, array_element_prefix, -1, -1 };
const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] };
Variant return_value;
Callable::CallError call_error;
@@ -1849,7 +1904,7 @@ void EditorInspectorArray::_resize_array(int p_size) {
// Call the function.
Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name());
if (move_function.is_valid()) {
- Variant args[] = { (Object *)undo_redo, object, array_element_prefix, i, -1 };
+ Variant args[] = { undo_redo.ptr(), object, array_element_prefix, i, -1 };
const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] };
Variant return_value;
Callable::CallError call_error;
@@ -1944,36 +1999,21 @@ int EditorInspectorArray::_drop_position() const {
return -1;
}
-void EditorInspectorArray::_new_size_line_edit_text_changed(String p_text) {
- bool valid = false;
- if (p_text.is_valid_int()) {
- int val = p_text.to_int();
- if (val > 0 && val != count) {
- valid = true;
- }
+void EditorInspectorArray::_resize_dialog_confirmed() {
+ if (int(new_size_spin_box->get_value()) == count) {
+ return;
}
- resize_dialog->get_ok_button()->set_disabled(!valid);
+
+ resize_dialog->hide();
+ _resize_array(int(new_size_spin_box->get_value()));
}
-void EditorInspectorArray::_new_size_line_edit_text_submitted(String p_text) {
- bool valid = false;
- if (p_text.is_valid_int()) {
- int val = p_text.to_int();
- if (val > 0 && val != count) {
- new_size = val;
- valid = true;
- }
- }
- if (valid) {
- resize_dialog->hide();
- _resize_array(new_size);
- } else {
- new_size_line_edit->set_text(Variant(new_size));
- }
+void EditorInspectorArray::_new_size_spin_box_value_changed(float p_value) {
+ resize_dialog->get_ok_button()->set_disabled(int(p_value) == count);
}
-void EditorInspectorArray::_resize_dialog_confirmed() {
- _new_size_line_edit_text_submitted(new_size_line_edit->get_text());
+void EditorInspectorArray::_new_size_spin_box_text_submitted(String p_text) {
+ _resize_dialog_confirmed();
}
void EditorInspectorArray::_setup() {
@@ -1988,6 +2028,20 @@ void EditorInspectorArray::_setup() {
page = CLAMP(page, 0, max_page);
}
+ Ref<Font> numbers_font;
+ int numbers_min_w = 0;
+
+ if (numbered) {
+ numbers_font = get_theme_font(SNAME("bold"), SNAME("EditorFonts"));
+ int digits_found = count;
+ String test;
+ while (digits_found) {
+ test += "8";
+ digits_found /= 10;
+ }
+ numbers_min_w = numbers_font->get_string_size(test).width;
+ }
+
for (int i = 0; i < (int)array_elements.size(); i++) {
ArrayElement &ae = array_elements[i];
@@ -1997,7 +2051,7 @@ void EditorInspectorArray::_setup() {
ae.panel->set_mouse_filter(MOUSE_FILTER_PASS);
ae.panel->set_drag_forwarding(this);
ae.panel->set_meta("index", begin_array_index + i);
- ae.panel->set_tooltip(vformat(TTR("Element %d: %s%d*"), i, array_element_prefix, i));
+ ae.panel->set_tooltip_text(vformat(TTR("Element %d: %s%d*"), i, array_element_prefix, i));
ae.panel->connect("focus_entered", callable_mp((CanvasItem *)ae.panel, &PanelContainer::update));
ae.panel->connect("focus_exited", callable_mp((CanvasItem *)ae.panel, &PanelContainer::update));
ae.panel->connect("draw", callable_mp(this, &EditorInspectorArray::_panel_draw).bind(i));
@@ -2022,19 +2076,38 @@ void EditorInspectorArray::_setup() {
ae.margin->add_child(ae.hbox);
// Move button.
- ae.move_texture_rect = memnew(TextureRect);
- ae.move_texture_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
- ae.move_texture_rect->set_default_cursor_shape(Control::CURSOR_MOVE);
- if (is_inside_tree()) {
- ae.move_texture_rect->set_texture(get_theme_icon(SNAME("TripleBar"), SNAME("EditorIcons")));
+ if (movable) {
+ ae.move_texture_rect = memnew(TextureRect);
+ ae.move_texture_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
+ ae.move_texture_rect->set_default_cursor_shape(Control::CURSOR_MOVE);
+
+ if (is_inside_tree()) {
+ ae.move_texture_rect->set_texture(get_theme_icon(SNAME("TripleBar"), SNAME("EditorIcons")));
+ }
+ ae.hbox->add_child(ae.move_texture_rect);
+ }
+
+ if (numbered) {
+ ae.number = memnew(Label);
+ ae.number->add_theme_font_override("font", numbers_font);
+ ae.number->set_custom_minimum_size(Size2(numbers_min_w, 0));
+ ae.number->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
+ ae.number->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
+ ae.number->set_text(itos(begin_array_index + i));
+ ae.hbox->add_child(ae.number);
}
- ae.hbox->add_child(ae.move_texture_rect);
// Right vbox.
ae.vbox = memnew(VBoxContainer);
ae.vbox->set_h_size_flags(SIZE_EXPAND_FILL);
ae.vbox->set_v_size_flags(SIZE_EXPAND_FILL);
ae.hbox->add_child(ae.vbox);
+
+ ae.erase = memnew(Button);
+ ae.erase->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ ae.erase->set_v_size_flags(SIZE_SHRINK_CENTER);
+ ae.erase->connect("pressed", callable_mp(this, &EditorInspectorArray::_remove_item).bind(begin_array_index + i));
+ ae.hbox->add_child(ae.erase);
}
// Hide/show the add button.
@@ -2049,7 +2122,14 @@ void EditorInspectorArray::_setup() {
}
}
+void EditorInspectorArray::_remove_item(int p_index) {
+ _move_element(p_index, -1);
+}
+
Variant EditorInspectorArray::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
+ if (!movable) {
+ return Variant();
+ }
int index = p_from->get_meta("index");
Dictionary dict;
dict["type"] = "property_array_element";
@@ -2071,6 +2151,9 @@ void EditorInspectorArray::drop_data_fw(const Point2 &p_point, const Variant &p_
}
bool EditorInspectorArray::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+ if (!movable) {
+ return false;
+ }
// First, update drawing.
control_dropping->update();
@@ -2100,13 +2183,19 @@ void EditorInspectorArray::_notification(int p_what) {
for (int i = 0; i < (int)array_elements.size(); i++) {
ArrayElement &ae = array_elements[i];
- ae.move_texture_rect->set_texture(get_theme_icon(SNAME("TripleBar"), SNAME("EditorIcons")));
+ if (ae.move_texture_rect) {
+ ae.move_texture_rect->set_texture(get_theme_icon(SNAME("TripleBar"), SNAME("EditorIcons")));
+ }
Size2 min_size = get_theme_stylebox(SNAME("Focus"), SNAME("EditorStyles"))->get_minimum_size();
ae.margin->add_theme_constant_override("margin_left", min_size.x / 2);
ae.margin->add_theme_constant_override("margin_top", min_size.y / 2);
ae.margin->add_theme_constant_override("margin_right", min_size.x / 2);
ae.margin->add_theme_constant_override("margin_bottom", min_size.y / 2);
+
+ if (ae.erase) {
+ ae.erase->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ }
}
add_button->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
@@ -2138,27 +2227,35 @@ void EditorInspectorArray::_bind_methods() {
ADD_SIGNAL(MethodInfo("page_change_request"));
}
-void EditorInspectorArray::set_undo_redo(UndoRedo *p_undo_redo) {
+void EditorInspectorArray::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
undo_redo = p_undo_redo;
}
-void EditorInspectorArray::setup_with_move_element_function(Object *p_object, String p_label, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable) {
+void EditorInspectorArray::setup_with_move_element_function(Object *p_object, String p_label, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable, bool p_numbered, int p_page_length, const String &p_add_item_text) {
count_property = "";
mode = MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION;
array_element_prefix = p_array_element_prefix;
page = p_page;
+ movable = p_movable;
+ page_length = p_page_length;
+ numbered = p_numbered;
EditorInspectorSection::setup(String(p_array_element_prefix) + "_array", p_label, p_object, p_bg_color, p_foldable, 0);
_setup();
}
-void EditorInspectorArray::setup_with_count_property(Object *p_object, String p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable) {
+void EditorInspectorArray::setup_with_count_property(Object *p_object, String p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable, bool p_numbered, int p_page_length, const String &p_add_item_text, const String &p_swap_method) {
count_property = p_count_property;
mode = MODE_USE_COUNT_PROPERTY;
array_element_prefix = p_array_element_prefix;
page = p_page;
+ movable = p_movable;
+ page_length = p_page_length;
+ numbered = p_numbered;
+ swap_method = p_swap_method;
+ add_button->set_text(p_add_item_text);
EditorInspectorSection::setup(String(count_property) + "_array", p_label, p_object, p_bg_color, p_foldable, 0);
_setup();
@@ -2216,10 +2313,11 @@ EditorInspectorArray::EditorInspectorArray() {
VBoxContainer *resize_dialog_vbox = memnew(VBoxContainer);
resize_dialog->add_child(resize_dialog_vbox);
- new_size_line_edit = memnew(LineEdit);
- new_size_line_edit->connect("text_changed", callable_mp(this, &EditorInspectorArray::_new_size_line_edit_text_changed));
- new_size_line_edit->connect("text_submitted", callable_mp(this, &EditorInspectorArray::_new_size_line_edit_text_submitted));
- resize_dialog_vbox->add_margin_child(TTRC("New Size:"), new_size_line_edit);
+ new_size_spin_box = memnew(SpinBox);
+ new_size_spin_box->set_max(16384);
+ new_size_spin_box->connect("value_changed", callable_mp(this, &EditorInspectorArray::_new_size_spin_box_value_changed));
+ new_size_spin_box->get_line_edit()->connect("text_submitted", callable_mp(this, &EditorInspectorArray::_new_size_spin_box_text_submitted));
+ resize_dialog_vbox->add_margin_child(TTRC("New Size:"), new_size_spin_box);
vbox->connect("visibility_changed", callable_mp(this, &EditorInspectorArray::_vbox_visibility_changed));
}
@@ -2391,7 +2489,7 @@ Button *EditorInspector::create_inspector_action_button(const String &p_text) {
return button;
}
-void EditorInspector::set_undo_redo(UndoRedo *p_undo_redo) {
+void EditorInspector::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
undo_redo = p_undo_redo;
}
@@ -2517,15 +2615,28 @@ void EditorInspector::update_tree() {
valid_plugins.push_back(inspector_plugins[i]);
}
- // Decide if properties should be drawn with the warning color (yellow).
+ // Decide if properties should be drawn with the warning color (yellow),
+ // or if the whole object should be considered read-only.
bool draw_warning = false;
+ bool all_read_only = false;
if (is_inside_tree()) {
+ if (object->has_method("_is_read_only")) {
+ all_read_only = object->call("_is_read_only");
+ }
+
Node *nod = Object::cast_to<Node>(object);
Node *es = EditorNode::get_singleton()->get_edited_scene();
if (nod && es != nod && nod->get_owner() != es) {
// Draw in warning color edited nodes that are not in the currently edited scene,
// as changes may be lost in the future.
draw_warning = true;
+ } else {
+ if (!all_read_only) {
+ Resource *res = Object::cast_to<Resource>(object);
+ if (res) {
+ all_read_only = EditorNode::get_singleton()->is_resource_read_only(res);
+ }
+ }
}
}
@@ -2539,7 +2650,6 @@ void EditorInspector::update_tree() {
List<PropertyInfo> plist;
object->get_property_list(&plist, true);
- _update_script_class_properties(*object, plist);
HashMap<VBoxContainer *, HashMap<String, VBoxContainer *>> vbox_per_path;
HashMap<String, EditorInspectorArray *> editor_inspector_array_per_prefix;
@@ -2552,7 +2662,7 @@ void EditorInspector::update_tree() {
_parse_added_editors(main_vbox, nullptr, ped);
}
- StringName type_name;
+ StringName doc_name;
// Get the lists of editors for properties.
for (List<PropertyInfo>::Element *E_property = plist.front(); E_property; E_property = E_property->next()) {
@@ -2624,18 +2734,28 @@ void EditorInspector::update_tree() {
category_vbox = nullptr; //reset
String type = p.name;
- type_name = p.name;
+ String label = p.name;
+ doc_name = p.name;
// Set the category icon.
if (!ClassDB::class_exists(type) && !ScriptServer::is_global_class(type) && p.hint_string.length() && FileAccess::exists(p.hint_string)) {
// If we have a category inside a script, search for the first script with a valid icon.
Ref<Script> script = ResourceLoader::load(p.hint_string, "Script");
StringName base_type;
+ StringName name;
if (script.is_valid()) {
base_type = script->get_instance_base_type();
+ name = EditorNode::get_editor_data().script_class_get_name(script->get_path());
+ Vector<DocData::ClassDoc> docs = script->get_documentation();
+ if (!docs.is_empty()) {
+ doc_name = docs[0].name;
+ }
+ if (name != StringName() && label != name) {
+ label = name;
+ }
}
while (script.is_valid()) {
- StringName name = EditorNode::get_editor_data().script_class_get_name(script->get_path());
+ name = EditorNode::get_editor_data().script_class_get_name(script->get_path());
String icon_path = EditorNode::get_editor_data().script_class_get_icon_path(name);
if (name != StringName() && icon_path.length()) {
category->icon = ResourceLoader::load(icon_path, "Texture");
@@ -2654,21 +2774,21 @@ void EditorInspector::update_tree() {
}
// Set the category label.
- category->label = type;
+ category->label = label;
if (use_doc_hints) {
// Sets the category tooltip to show documentation.
- if (!class_descr_cache.has(type_name)) {
+ if (!class_descr_cache.has(doc_name)) {
String descr;
DocTools *dd = EditorHelp::get_doc_data();
- HashMap<String, DocData::ClassDoc>::Iterator E = dd->class_list.find(type_name);
+ HashMap<String, DocData::ClassDoc>::Iterator E = dd->class_list.find(doc_name);
if (E) {
descr = DTR(E->value.brief_description);
}
- class_descr_cache[type_name] = descr;
+ class_descr_cache[doc_name] = descr;
}
- category->set_tooltip(p.name + "::" + (class_descr_cache[type_name].is_empty() ? "" : class_descr_cache[type_name]));
+ category->set_tooltip_text(p.name + "::" + (class_descr_cache[doc_name].is_empty() ? "" : class_descr_cache[doc_name]));
}
// Add editors at the start of a category.
@@ -2861,7 +2981,7 @@ void EditorInspector::update_tree() {
Color c = sscolor;
c.a /= level;
section->setup(acc_path, label, object, c, use_folding, section_depth);
- section->set_tooltip(tooltip);
+ section->set_tooltip_text(tooltip);
// Add editors at the start of a group.
for (Ref<EditorInspectorPlugin> &ped : valid_plugins) {
@@ -2887,9 +3007,34 @@ void EditorInspector::update_tree() {
StringName array_element_prefix;
Color c = sscolor;
c.a /= level;
+
+ Vector<String> class_name_components = String(p.class_name).split(",");
+
+ int page_size = 5;
+ bool movable = true;
+ bool numbered = false;
+ bool foldable = use_folding;
+ String add_button_text;
+ String swap_method;
+ for (int i = (p.type == Variant::NIL ? 1 : 2); i < class_name_components.size(); i++) {
+ if (class_name_components[i].begins_with("page_size") && class_name_components[i].get_slice_count("=") == 2) {
+ page_size = class_name_components[i].get_slice("=", 1).to_int();
+ } else if (class_name_components[i].begins_with("add_button_text") && class_name_components[i].get_slice_count("=") == 2) {
+ add_button_text = class_name_components[i].get_slice("=", 1).strip_edges();
+ } else if (class_name_components[i] == "static") {
+ movable = false;
+ } else if (class_name_components[i] == "numbered") {
+ numbered = true;
+ } else if (class_name_components[i] == "unfoldable") {
+ foldable = false;
+ } else if (class_name_components[i].begins_with("swap_method") && class_name_components[i].get_slice_count("=") == 2) {
+ swap_method = class_name_components[i].get_slice("=", 1).strip_edges();
+ }
+ }
+
if (p.type == Variant::NIL) {
// Setup the array to use a method to create/move/delete elements.
- array_element_prefix = p.class_name;
+ array_element_prefix = class_name_components[0];
editor_inspector_array = memnew(EditorInspectorArray);
String array_label = path.contains("/") ? path.substr(path.rfind("/") + 1) : path;
@@ -2900,13 +3045,14 @@ void EditorInspector::update_tree() {
editor_inspector_array->set_undo_redo(undo_redo);
} else if (p.type == Variant::INT) {
// Setup the array to use the count property and built-in functions to create/move/delete elements.
- Vector<String> class_name_components = String(p.class_name).split(",");
- if (class_name_components.size() == 2) {
+ if (class_name_components.size() >= 2) {
array_element_prefix = class_name_components[1];
editor_inspector_array = memnew(EditorInspectorArray);
int page = per_array_page.has(array_element_prefix) ? per_array_page[array_element_prefix] : 0;
- editor_inspector_array->setup_with_count_property(object, class_name_components[0], p.name, array_element_prefix, page, c, use_folding);
+
+ editor_inspector_array->setup_with_count_property(object, class_name_components[0], p.name, array_element_prefix, page, c, foldable, movable, numbered, page_size, add_button_text, swap_method);
editor_inspector_array->connect("page_change_request", callable_mp(this, &EditorInspector::_page_change_request).bind(array_element_prefix));
+
editor_inspector_array->set_undo_redo(undo_redo);
}
}
@@ -2915,6 +3061,7 @@ void EditorInspector::update_tree() {
current_vbox->add_child(editor_inspector_array);
editor_inspector_array_per_prefix[array_element_prefix] = editor_inspector_array;
}
+
continue;
}
@@ -2939,7 +3086,7 @@ void EditorInspector::update_tree() {
// Build the doc hint, to use as tooltip.
// Get the class name.
- StringName classname = type_name == "" ? object->get_class_name() : type_name;
+ StringName classname = doc_name == "" ? object->get_class_name() : doc_name;
if (!object_class.is_empty()) {
classname = object_class;
}
@@ -3032,7 +3179,6 @@ void EditorInspector::update_tree() {
ep->property_usage = p.usage;
//and set label?
}
-
if (!editors[i].label.is_empty()) {
ep->set_label(editors[i].label);
} else {
@@ -3059,7 +3205,7 @@ void EditorInspector::update_tree() {
ep->set_checkable(checkable);
ep->set_checked(checked);
ep->set_keying(keying);
- ep->set_read_only(property_read_only);
+ ep->set_read_only(property_read_only || all_read_only);
ep->set_deletable(deletable_properties || p.name.begins_with("metadata/"));
}
@@ -3079,9 +3225,9 @@ void EditorInspector::update_tree() {
ep->connect("resource_selected", callable_mp(this, &EditorInspector::_resource_selected), CONNECT_DEFERRED);
ep->connect("object_id_selected", callable_mp(this, &EditorInspector::_object_id_selected), CONNECT_DEFERRED);
if (!doc_info.description.is_empty()) {
- ep->set_tooltip(property_prefix + p.name + "::" + doc_info.description);
+ ep->set_tooltip_text(property_prefix + p.name + "::" + doc_info.description);
} else {
- ep->set_tooltip(property_prefix + p.name);
+ ep->set_tooltip_text(property_prefix + p.name);
}
ep->set_doc_path(doc_info.path);
ep->update_property();
@@ -3097,10 +3243,18 @@ void EditorInspector::update_tree() {
}
if (!hide_metadata) {
+ // Add 4px of spacing between the "Add Metadata" button and the content above it.
+ Control *spacer = memnew(Control);
+ spacer->set_custom_minimum_size(Size2(0, 4) * EDSCALE);
+ main_vbox->add_child(spacer);
+
Button *add_md = EditorInspector::create_inspector_action_button(TTR("Add Metadata"));
add_md->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
add_md->connect(SNAME("pressed"), callable_mp(this, &EditorInspector::_show_add_meta_dialog));
main_vbox->add_child(add_md);
+ if (all_read_only) {
+ add_md->set_disabled(true);
+ }
}
// Get the lists of to add at the end.
@@ -3373,7 +3527,7 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo
}
}
- if (!undo_redo || bool(object->call("_dont_undo_redo"))) {
+ if (!undo_redo.is_valid() || bool(object->call("_dont_undo_redo"))) {
object->set(p_name, p_value);
if (p_refresh_all) {
_edit_request_change(object, "");
@@ -3396,18 +3550,27 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo
undo_redo->add_undo_property(object, p_name, value);
}
- PropertyInfo prop_info;
- if (ClassDB::get_property_info(object->get_class_name(), p_name, &prop_info)) {
- for (const String &linked_prop : prop_info.linked_properties) {
- valid = false;
- value = object->get(linked_prop, &valid);
- if (valid) {
- undo_redo->add_undo_property(object, linked_prop, value);
- }
+ List<StringName> linked_properties;
+ ClassDB::get_linked_properties_info(object->get_class_name(), p_name, &linked_properties);
+
+ for (const StringName &linked_prop : linked_properties) {
+ valid = false;
+ Variant undo_value = object->get(linked_prop, &valid);
+ if (valid) {
+ undo_redo->add_undo_property(object, linked_prop, undo_value);
+ }
+ }
+
+ PackedStringArray linked_properties_dynamic = object->call("_get_linked_undo_properties", p_name, p_value);
+ for (int i = 0; i < linked_properties_dynamic.size(); i++) {
+ valid = false;
+ Variant undo_value = object->get(linked_properties_dynamic[i], &valid);
+ if (valid) {
+ undo_redo->add_undo_property(object, linked_properties_dynamic[i], undo_value);
}
}
- Variant v_undo_redo = (Object *)undo_redo;
+ Variant v_undo_redo = undo_redo;
Variant v_object = object;
Variant v_name = p_name;
for (int i = 0; i < EditorNode::get_singleton()->get_editor_data().get_undo_redo_inspector_hook_callback().size(); i++) {
@@ -3583,7 +3746,7 @@ void EditorInspector::_property_pinned(const String &p_path, bool p_pinned) {
Node *node = Object::cast_to<Node>(object);
ERR_FAIL_COND(!node);
- if (undo_redo) {
+ if (undo_redo.is_valid()) {
undo_redo->create_action(vformat(p_pinned ? TTR("Pinned %s") : TTR("Unpinned %s"), p_path));
undo_redo->add_do_method(node, "_set_property_pinned", p_path, p_pinned);
undo_redo->add_undo_method(node, "_set_property_pinned", p_path, !p_pinned);
@@ -3759,93 +3922,6 @@ void EditorInspector::_feature_profile_changed() {
update_tree();
}
-void EditorInspector::_update_script_class_properties(const Object &p_object, List<PropertyInfo> &r_list) const {
- Ref<Script> script = p_object.get_script();
- if (script.is_null()) {
- return;
- }
-
- List<Ref<Script>> classes;
-
- // NodeC -> NodeB -> NodeA
- while (script.is_valid()) {
- classes.push_front(script);
- script = script->get_base_script();
- }
-
- if (classes.is_empty()) {
- return;
- }
-
- // Script Variables -> to insert: NodeC..B..A -> bottom (insert_here)
- List<PropertyInfo>::Element *script_variables = nullptr;
- List<PropertyInfo>::Element *bottom = nullptr;
- List<PropertyInfo>::Element *insert_here = nullptr;
- for (List<PropertyInfo>::Element *E = r_list.front(); E; E = E->next()) {
- PropertyInfo &pi = E->get();
- if (pi.name != "Script Variables") {
- continue;
- }
- script_variables = E;
- bottom = r_list.insert_after(script_variables, PropertyInfo());
- insert_here = bottom;
- break;
- }
-
- HashSet<StringName> added;
- for (const Ref<Script> &s : classes) {
- String path = s->get_path();
- String name = EditorNode::get_editor_data().script_class_get_name(path);
- if (name.is_empty()) {
- if (s->is_built_in()) {
- if (s->get_name().is_empty()) {
- name = TTR("Built-in script");
- } else {
- name = vformat("%s (%s)", s->get_name(), TTR("Built-in"));
- }
- } else {
- name = path.get_file();
- }
- }
-
- List<PropertyInfo> props;
- s->get_script_property_list(&props);
-
- // Script Variables -> NodeA -> bottom (insert_here)
- List<PropertyInfo>::Element *category = r_list.insert_before(insert_here, PropertyInfo(Variant::NIL, name, PROPERTY_HINT_NONE, path, PROPERTY_USAGE_CATEGORY));
-
- // Script Variables -> NodeA -> A props... -> bottom (insert_here)
- for (List<PropertyInfo>::Element *P = props.front(); P; P = P->next()) {
- PropertyInfo &pi = P->get();
- if (added.has(pi.name)) {
- continue;
- }
- added.insert(pi.name);
-
- r_list.insert_before(insert_here, pi);
-
- List<PropertyInfo>::Element *prop_below = bottom->next();
- while (prop_below) {
- if (prop_below->get() == pi) {
- List<PropertyInfo>::Element *to_delete = prop_below;
- prop_below = prop_below->next();
- r_list.erase(to_delete);
- } else {
- prop_below = prop_below->next();
- }
- }
- }
-
- // Script Variables -> NodeA (insert_here) -> A props... -> bottom
- insert_here = category;
- }
-
- if (script_variables) {
- r_list.erase(script_variables);
- r_list.erase(bottom);
- }
-}
-
void EditorInspector::set_restrict_to_basic_settings(bool p_restrict) {
restrict_to_basic = p_restrict;
update_tree();
@@ -3952,7 +4028,6 @@ void EditorInspector::_bind_methods() {
EditorInspector::EditorInspector() {
object = nullptr;
- undo_redo = nullptr;
main_vbox = memnew(VBoxContainer);
main_vbox->set_h_size_flags(SIZE_EXPAND_FILL);
main_vbox->add_theme_constant_override("separation", 0);
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index 54533de960..474078853a 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -31,6 +31,7 @@
#ifndef EDITOR_INSPECTOR_H
#define EDITOR_INSPECTOR_H
+#include "editor/editor_undo_redo_manager.h"
#include "editor_property_name_processor.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
@@ -39,10 +40,9 @@
#include "scene/gui/option_button.h"
#include "scene/gui/panel_container.h"
#include "scene/gui/scroll_container.h"
+#include "scene/gui/spin_box.h"
#include "scene/gui/texture_rect.h"
-class UndoRedo;
-
class EditorPropertyRevert {
public:
static bool get_instantiated_node_original_property(Node *p_node, const StringName &p_prop, Variant &value, bool p_check_class_default = true);
@@ -117,8 +117,6 @@ private:
Control *bottom_editor = nullptr;
PopupMenu *menu = nullptr;
- mutable String tooltip_text;
-
HashMap<StringName, Variant> cache;
GDVIRTUAL0(_update_property)
@@ -199,8 +197,6 @@ public:
void set_object_and_property(Object *p_object, const StringName &p_property);
virtual Control *make_custom_tooltip(const String &p_text) const override;
- String get_tooltip_text() const;
-
void set_draw_top_bg(bool p_draw) { draw_top_bg = p_draw; }
bool can_revert_to_default() const { return can_revert; }
@@ -254,18 +250,13 @@ class EditorInspectorCategory : public Control {
Ref<Texture2D> icon;
String label;
- mutable String tooltip_text;
-
protected:
void _notification(int p_what);
- static void _bind_methods();
public:
virtual Size2 get_minimum_size() const override;
virtual Control *make_custom_tooltip(const String &p_text) const override;
- String get_tooltip_text() const;
-
EditorInspectorCategory();
};
@@ -312,7 +303,7 @@ public:
class EditorInspectorArray : public EditorInspectorSection {
GDCLASS(EditorInspectorArray, EditorInspectorSection);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
enum Mode {
MODE_NONE,
@@ -321,6 +312,7 @@ class EditorInspectorArray : public EditorInspectorSection {
} mode;
StringName count_property;
StringName array_element_prefix;
+ String swap_method;
int count = 0;
@@ -332,8 +324,7 @@ class EditorInspectorArray : public EditorInspectorSection {
Button *add_button = nullptr;
AcceptDialog *resize_dialog = nullptr;
- int new_size = 0;
- LineEdit *new_size_line_edit = nullptr;
+ SpinBox *new_size_spin_box = nullptr;
// Pagination
int page_length = 5;
@@ -342,6 +333,9 @@ class EditorInspectorArray : public EditorInspectorSection {
int begin_array_index = 0;
int end_array_index = 0;
+ bool movable = true;
+ bool numbered = false;
+
enum MenuOptions {
OPTION_MOVE_UP = 0,
OPTION_MOVE_DOWN,
@@ -359,7 +353,9 @@ class EditorInspectorArray : public EditorInspectorSection {
MarginContainer *margin = nullptr;
HBoxContainer *hbox = nullptr;
TextureRect *move_texture_rect = nullptr;
+ Label *number = nullptr;
VBoxContainer *vbox = nullptr;
+ Button *erase = nullptr;
};
LocalVector<ArrayElement> array_elements;
@@ -384,8 +380,8 @@ class EditorInspectorArray : public EditorInspectorSection {
Array _extract_properties_as_array(const List<PropertyInfo> &p_list);
int _drop_position() const;
- void _new_size_line_edit_text_changed(String p_text);
- void _new_size_line_edit_text_submitted(String p_text);
+ void _new_size_spin_box_value_changed(float p_value);
+ void _new_size_spin_box_text_submitted(String p_text);
void _resize_dialog_confirmed();
void _update_elements_visibility();
@@ -395,15 +391,17 @@ class EditorInspectorArray : public EditorInspectorSection {
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
+ void _remove_item(int p_index);
+
protected:
void _notification(int p_what);
static void _bind_methods();
public:
- void set_undo_redo(UndoRedo *p_undo_redo);
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
- void setup_with_move_element_function(Object *p_object, String p_label, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable);
- void setup_with_count_property(Object *p_object, String p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable);
+ void setup_with_move_element_function(Object *p_object, String p_label, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = "");
+ void setup_with_count_property(Object *p_object, String p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = "", const String &p_swap_method = "");
VBoxContainer *get_vbox(int p_index);
EditorInspectorArray();
@@ -440,7 +438,7 @@ public:
class EditorInspector : public ScrollContainer {
GDCLASS(EditorInspector, ScrollContainer);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
enum {
MAX_PLUGINS = 1024
};
@@ -528,7 +526,6 @@ class EditorInspector : public ScrollContainer {
void _vscroll_changed(double);
void _feature_profile_changed();
- void _update_script_class_properties(const Object &p_object, List<PropertyInfo> &r_list) const;
bool _is_property_disabled_by_feature_profile(const StringName &p_property);
@@ -555,7 +552,7 @@ public:
static EditorProperty *instantiate_property_editor(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false);
- void set_undo_redo(UndoRedo *p_undo_redo);
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
String get_selected_path() const;
diff --git a/editor/editor_locale_dialog.cpp b/editor/editor_locale_dialog.cpp
index cd8150d235..87da67fb05 100644
--- a/editor/editor_locale_dialog.cpp
+++ b/editor/editor_locale_dialog.cpp
@@ -33,6 +33,7 @@
#include "core/config/project_settings.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/check_button.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/option_button.h"
@@ -492,7 +493,7 @@ EditorLocaleDialog::EditorLocaleDialog() {
{
lang_code = memnew(LineEdit);
lang_code->set_max_length(3);
- lang_code->set_tooltip("Language");
+ lang_code->set_tooltip_text("Language");
vb_language->add_child(lang_code);
}
hb_locale->add_child(vb_language);
@@ -508,7 +509,7 @@ EditorLocaleDialog::EditorLocaleDialog() {
{
script_code = memnew(LineEdit);
script_code->set_max_length(4);
- script_code->set_tooltip("Script");
+ script_code->set_tooltip_text("Script");
vb_script->add_child(script_code);
}
hb_locale->add_child(vb_script);
@@ -524,7 +525,7 @@ EditorLocaleDialog::EditorLocaleDialog() {
{
country_code = memnew(LineEdit);
country_code->set_max_length(2);
- country_code->set_tooltip("Country");
+ country_code->set_tooltip_text("Country");
vb_country->add_child(country_code);
}
hb_locale->add_child(vb_country);
@@ -541,7 +542,7 @@ EditorLocaleDialog::EditorLocaleDialog() {
variant_code = memnew(LineEdit);
variant_code->set_h_size_flags(Control::SIZE_EXPAND_FILL);
variant_code->set_placeholder("Variant");
- variant_code->set_tooltip("Variant");
+ variant_code->set_tooltip_text("Variant");
vb_variant->add_child(variant_code);
}
hb_locale->add_child(vb_variant);
diff --git a/editor/editor_locale_dialog.h b/editor/editor_locale_dialog.h
index 7a4828e83a..8ac642a038 100644
--- a/editor/editor_locale_dialog.h
+++ b/editor/editor_locale_dialog.h
@@ -40,7 +40,7 @@ class VBoxContainer;
class LineEdit;
class Tree;
class OptionButton;
-class UndoRedo;
+class EditorUndoRedoManager;
class EditorLocaleDialog : public ConfirmationDialog {
GDCLASS(EditorLocaleDialog, ConfirmationDialog);
@@ -63,7 +63,7 @@ class EditorLocaleDialog : public ConfirmationDialog {
Tree *script_list = nullptr;
Tree *cnt_list = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
bool locale_set = false;
bool updating_lists = false;
diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp
index 38cc85bb4e..a3d4296edb 100644
--- a/editor/editor_log.cpp
+++ b/editor/editor_log.cpp
@@ -93,6 +93,12 @@ void EditorLog::_update_theme() {
collapse_button->set_icon(get_theme_icon(SNAME("CombineLines"), SNAME("EditorIcons")));
show_search_button->set_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
search_box->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
+
+ theme_cache.error_color = get_theme_color(SNAME("error_color"), SNAME("Editor"));
+ theme_cache.error_icon = get_theme_icon(SNAME("Error"), SNAME("EditorIcons"));
+ theme_cache.warning_color = get_theme_color(SNAME("warning_color"), SNAME("Editor"));
+ theme_cache.warning_icon = get_theme_icon(SNAME("Warning"), SNAME("EditorIcons"));
+ theme_cache.message_color = get_theme_color(SNAME("font_color"), SNAME("Editor")) * Color(1, 1, 1, 0.6);
}
void EditorLog::_notification(int p_what) {
@@ -125,7 +131,7 @@ void EditorLog::_save_state() {
Ref<ConfigFile> config;
config.instantiate();
// Load and amend existing config if it exists.
- config->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+ config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
const String section = "editor_log";
for (const KeyValue<MessageType, LogFilter *> &E : type_filter_map) {
@@ -135,7 +141,7 @@ void EditorLog::_save_state() {
config->set_value(section, "collapse", collapse);
config->set_value(section, "show_search", search_box->is_visible());
- config->save(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+ config->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
}
void EditorLog::_load_state() {
@@ -143,7 +149,7 @@ void EditorLog::_load_state() {
Ref<ConfigFile> config;
config.instantiate();
- config->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+ config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
// Run the below code even if config->load returns an error, since we want the defaults to be set even if the file does not exist yet.
const String section = "editor_log";
@@ -218,6 +224,10 @@ void EditorLog::set_tool_button(Button *p_tool_button) {
tool_button = p_tool_button;
}
+void EditorLog::register_undo_redo(UndoRedo *p_undo_redo) {
+ p_undo_redo->set_commit_notify_callback(_undo_redo_cbk, this);
+}
+
void EditorLog::_undo_redo_cbk(void *p_self, const String &p_name) {
EditorLog *self = static_cast<EditorLog *>(p_self);
self->add_message(p_name, EditorLog::MSG_TYPE_EDITOR);
@@ -242,6 +252,11 @@ void EditorLog::_rebuild_log() {
}
void EditorLog::_add_log_line(LogMessage &p_message, bool p_replace_previous) {
+ if (!is_inside_tree()) {
+ // The log will be built all at once when it enters the tree and has its theme items.
+ return;
+ }
+
// Only add the message to the log if it passes the filters.
bool filter_active = type_filter_map[p_message.type]->is_active();
String search_text = search_box->get_text();
@@ -264,22 +279,22 @@ void EditorLog::_add_log_line(LogMessage &p_message, bool p_replace_previous) {
case MSG_TYPE_STD_RICH: {
} break;
case MSG_TYPE_ERROR: {
- log->push_color(get_theme_color(SNAME("error_color"), SNAME("Editor")));
- Ref<Texture2D> icon = get_theme_icon(SNAME("Error"), SNAME("EditorIcons"));
+ log->push_color(theme_cache.error_color);
+ Ref<Texture2D> icon = theme_cache.error_icon;
log->add_image(icon);
log->add_text(" ");
tool_button->set_icon(icon);
} break;
case MSG_TYPE_WARNING: {
- log->push_color(get_theme_color(SNAME("warning_color"), SNAME("Editor")));
- Ref<Texture2D> icon = get_theme_icon(SNAME("Warning"), SNAME("EditorIcons"));
+ log->push_color(theme_cache.warning_color);
+ Ref<Texture2D> icon = theme_cache.warning_icon;
log->add_image(icon);
log->add_text(" ");
tool_button->set_icon(icon);
} break;
case MSG_TYPE_EDITOR: {
// Distinguish editor messages from messages printed by the project
- log->push_color(get_theme_color(SNAME("font_color"), SNAME("Editor")) * Color(1, 1, 1, 0.6));
+ log->push_color(theme_cache.message_color);
} break;
}
@@ -404,7 +419,7 @@ EditorLog::EditorLog() {
collapse_button = memnew(Button);
collapse_button->set_flat(true);
collapse_button->set_focus_mode(FOCUS_NONE);
- collapse_button->set_tooltip(TTR("Collapse duplicate messages into one log entry. Shows number of occurrences."));
+ collapse_button->set_tooltip_text(TTR("Collapse duplicate messages into one log entry. Shows number of occurrences."));
collapse_button->set_toggle_mode(true);
collapse_button->set_pressed(false);
collapse_button->connect("toggled", callable_mp(this, &EditorLog::_set_collapse));
@@ -452,8 +467,6 @@ EditorLog::EditorLog() {
add_error_handler(&eh);
current = Thread::get_caller_id();
-
- EditorNode::get_undo_redo()->set_commit_notify_callback(_undo_redo_cbk, this);
}
void EditorLog::deinit() {
diff --git a/editor/editor_log.h b/editor/editor_log.h
index 003a148b9b..43d7037414 100644
--- a/editor/editor_log.h
+++ b/editor/editor_log.h
@@ -41,6 +41,8 @@
#include "scene/gui/texture_button.h"
#include "scene/gui/texture_rect.h"
+class UndoRedo;
+
class EditorLog : public HBoxContainer {
GDCLASS(EditorLog, HBoxContainer);
@@ -67,6 +69,16 @@ private:
}
};
+ struct {
+ Color error_color;
+ Ref<Texture2D> error_icon;
+
+ Color warning_color;
+ Ref<Texture2D> warning_icon;
+
+ Color message_color;
+ } theme_cache;
+
// Encapsulates all data and functionality regarding filters.
struct LogFilter {
private:
@@ -83,7 +95,7 @@ private:
toggle_button->set_toggle_mode(true);
toggle_button->set_pressed(true);
toggle_button->set_text(itos(message_count));
- toggle_button->set_tooltip(TTR(p_tooltip));
+ toggle_button->set_tooltip_text(TTR(p_tooltip));
// Don't tint the icon even when in "pressed" state.
toggle_button->add_theme_color_override("icon_color_pressed", Color(1, 1, 1, 1));
toggle_button->set_focus_mode(FOCUS_NONE);
@@ -172,6 +184,7 @@ protected:
public:
void add_message(const String &p_msg, MessageType p_type = MSG_TYPE_STD);
void set_tool_button(Button *p_tool_button);
+ void register_undo_redo(UndoRedo *p_undo_redo);
void deinit();
void clear();
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index e9aceb684f..0b0c0a953a 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -54,6 +54,7 @@
#include "scene/gui/dialogs.h"
#include "scene/gui/file_dialog.h"
#include "scene/gui/link_button.h"
+#include "scene/gui/menu_bar.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
#include "scene/gui/panel_container.h"
@@ -104,6 +105,7 @@
#include "editor/editor_themes.h"
#include "editor/editor_toaster.h"
#include "editor/editor_translation_parser.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/export/editor_export.h"
#include "editor/export/export_template_manager.h"
#include "editor/export/project_export.h"
@@ -141,6 +143,7 @@
#include "editor/plugins/bone_map_editor_plugin.h"
#include "editor/plugins/camera_3d_editor_plugin.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
+#include "editor/plugins/cast_2d_editor_plugin.h"
#include "editor/plugins/collision_polygon_2d_editor_plugin.h"
#include "editor/plugins/collision_shape_2d_editor_plugin.h"
#include "editor/plugins/control_editor_plugin.h"
@@ -176,7 +179,6 @@
#include "editor/plugins/physical_bone_3d_editor_plugin.h"
#include "editor/plugins/polygon_2d_editor_plugin.h"
#include "editor/plugins/polygon_3d_editor_plugin.h"
-#include "editor/plugins/ray_cast_2d_editor_plugin.h"
#include "editor/plugins/resource_preloader_editor_plugin.h"
#include "editor/plugins/root_motion_editor_plugin.h"
#include "editor/plugins/script_editor_plugin.h"
@@ -348,8 +350,7 @@ void EditorNode::_update_scene_tabs() {
icon = EditorNode::get_singleton()->get_object_icon(type_node, "Node");
}
- int current = editor_data.get_edited_scene();
- bool unsaved = (i == current) ? saved_version != editor_data.get_undo_redo().get_version() : editor_data.get_scene_version(i) != 0;
+ bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i));
scene_tabs->add_tab(disambiguated_scene_names[i] + (unsaved ? "(*)" : ""), icon);
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU)) {
@@ -596,15 +597,15 @@ void EditorNode::_notification(int p_what) {
opening_prev = false;
}
- bool unsaved_cache_changed = false;
- if (unsaved_cache != (saved_version != editor_data.get_undo_redo().get_version())) {
- unsaved_cache = (saved_version != editor_data.get_undo_redo().get_version());
- unsaved_cache_changed = true;
+ bool global_unsaved = get_undo_redo()->is_history_unsaved(EditorUndoRedoManager::GLOBAL_HISTORY);
+ bool scene_or_global_unsaved = global_unsaved || get_undo_redo()->is_history_unsaved(editor_data.get_current_edited_scene_history_id());
+ if (unsaved_cache != scene_or_global_unsaved) {
+ unsaved_cache = scene_or_global_unsaved;
+ _update_title();
}
- if (last_checked_version != editor_data.get_undo_redo().get_version()) {
+ if (editor_data.is_scene_changed(-1)) {
_update_scene_tabs();
- last_checked_version = editor_data.get_undo_redo().get_version();
}
// Update the animation frame of the update spinner.
@@ -630,7 +631,7 @@ void EditorNode::_notification(int p_what) {
ResourceImporterTexture::get_singleton()->update_imports();
- if (settings_changed || unsaved_cache_changed) {
+ if (settings_changed) {
_update_title();
}
@@ -660,6 +661,7 @@ void EditorNode::_notification(int p_what) {
command_palette->register_shortcuts_as_command();
+ MessageQueue::get_singleton()->push_callable(callable_mp(this, &EditorNode::_begin_first_scan));
/* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */
} break;
@@ -751,11 +753,7 @@ void EditorNode::_notification(int p_what) {
scene_tabs->add_theme_style_override("tab_selected", gui_base->get_theme_stylebox(SNAME("SceneTabFG"), SNAME("EditorStyles")));
scene_tabs->add_theme_style_override("tab_unselected", gui_base->get_theme_stylebox(SNAME("SceneTabBG"), SNAME("EditorStyles")));
- file_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
- project_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
- debug_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
- settings_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
- help_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
+ main_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
}
scene_tabs->set_max_tab_width(int(EDITOR_GET("interface/scene_tabs/maximum_width")) * EDSCALE);
@@ -803,16 +801,15 @@ void EditorNode::_notification(int p_what) {
dock_tab_move_right->set_icon(theme->get_icon(SNAME("Forward"), SNAME("EditorIcons")));
}
- PopupMenu *p = help_menu->get_popup();
- p->set_item_icon(p->get_item_index(HELP_SEARCH), gui_base->get_theme_icon(SNAME("HelpSearch"), SNAME("EditorIcons")));
- p->set_item_icon(p->get_item_index(HELP_DOCS), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
- p->set_item_icon(p->get_item_index(HELP_QA), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
- p->set_item_icon(p->get_item_index(HELP_REPORT_A_BUG), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
- p->set_item_icon(p->get_item_index(HELP_SUGGEST_A_FEATURE), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
- p->set_item_icon(p->get_item_index(HELP_SEND_DOCS_FEEDBACK), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
- p->set_item_icon(p->get_item_index(HELP_COMMUNITY), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
- p->set_item_icon(p->get_item_index(HELP_ABOUT), gui_base->get_theme_icon(SNAME("Godot"), SNAME("EditorIcons")));
- p->set_item_icon(p->get_item_index(HELP_SUPPORT_GODOT_DEVELOPMENT), gui_base->get_theme_icon(SNAME("Heart"), SNAME("EditorIcons")));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_SEARCH), gui_base->get_theme_icon(SNAME("HelpSearch"), SNAME("EditorIcons")));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_DOCS), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_QA), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_REPORT_A_BUG), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_SUGGEST_A_FEATURE), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_SEND_DOCS_FEEDBACK), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_COMMUNITY), gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_ABOUT), gui_base->get_theme_icon(SNAME("Godot"), SNAME("EditorIcons")));
+ help_menu->set_item_icon(help_menu->get_item_index(HELP_SUPPORT_GODOT_DEVELOPMENT), gui_base->get_theme_icon(SNAME("Heart"), SNAME("EditorIcons")));
for (int i = 0; i < main_editor_buttons.size(); i++) {
main_editor_buttons.write[i]->add_theme_font_override("font", gui_base->get_theme_font(SNAME("main_button_font"), SNAME("EditorFonts")));
@@ -848,7 +845,7 @@ void EditorNode::_update_update_spinner() {
update_popup->set_item_checked(update_popup->get_item_index(SETTINGS_UPDATE_WHEN_CHANGED), !update_continuously);
if (update_continuously) {
- update_spinner->set_tooltip(TTR("Spins when the editor window redraws.\nUpdate Continuously is enabled, which can increase power usage. Click to disable it."));
+ update_spinner->set_tooltip_text(TTR("Spins when the editor window redraws.\nUpdate Continuously is enabled, which can increase power usage. Click to disable it."));
// Use a different color for the update spinner when Update Continuously is enabled,
// as this feature should only be enabled for troubleshooting purposes.
@@ -858,7 +855,7 @@ void EditorNode::_update_update_spinner() {
update_spinner->set_self_modulate(
gui_base->get_theme_color(SNAME("error_color"), SNAME("Editor")) * (dark_theme ? Color(1.1, 1.1, 1.1) : Color(4.25, 4.25, 4.25)));
} else {
- update_spinner->set_tooltip(TTR("Spins when the editor window redraws."));
+ update_spinner->set_tooltip_text(TTR("Spins when the editor window redraws."));
update_spinner->set_self_modulate(Color(1, 1, 1));
}
@@ -1047,6 +1044,8 @@ void EditorNode::_sources_changed(bool p_exist) {
if (waiting_for_first_scan) {
waiting_for_first_scan = false;
+ Engine::get_singleton()->startup_benchmark_end_measure(); // editor_scan_and_reimport
+
// Reload the global shader variables, but this time
// loading textures, as they are now properly imported.
RenderingServer::get_singleton()->global_shader_uniforms_load_settings(true);
@@ -1059,8 +1058,16 @@ void EditorNode::_sources_changed(bool p_exist) {
_load_docks();
if (!defer_load_scene.is_empty()) {
+ Engine::get_singleton()->startup_benchmark_begin_measure("editor_load_scene");
load_scene(defer_load_scene);
defer_load_scene = "";
+ Engine::get_singleton()->startup_benchmark_end_measure();
+
+ if (use_startup_benchmark) {
+ Engine::get_singleton()->startup_dump(startup_benchmark_file);
+ startup_benchmark_file = String();
+ use_startup_benchmark = false;
+ }
}
}
}
@@ -1089,7 +1096,7 @@ void EditorNode::_scan_external_changes() {
}
}
- String project_settings_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("project.godot");
+ String project_settings_path = ProjectSettings::get_singleton()->get_resource_path().path_join("project.godot");
if (FileAccess::get_modified_time(project_settings_path) > ProjectSettings::get_singleton()->get_last_saved_time()) {
TreeItem *ti = disk_changed_list->create_item(r);
ti->set_text(0, "project.godot");
@@ -1131,7 +1138,6 @@ void EditorNode::_reload_modified_scenes() {
}
}
- get_undo_redo()->clear_history(false);
set_current_scene(current_idx);
_update_scene_tabs();
disk_changed->hide();
@@ -1244,7 +1250,9 @@ void EditorNode::save_resource_in_path(const Ref<Resource> &p_resource, const St
}
void EditorNode::save_resource(const Ref<Resource> &p_resource) {
- if (p_resource->get_path().is_resource_file()) {
+ // If the resource has been imported, ask the user to use a different path in order to save it.
+ String path = p_resource->get_path();
+ if (path.is_resource_file() && !FileAccess::exists(path + ".import")) {
save_resource_in_path(p_resource, p_resource->get_path());
} else {
save_resource_as(p_resource);
@@ -1254,11 +1262,18 @@ void EditorNode::save_resource(const Ref<Resource> &p_resource) {
void EditorNode::save_resource_as(const Ref<Resource> &p_resource, const String &p_at_path) {
{
String path = p_resource->get_path();
- int srpos = path.find("::");
- if (srpos != -1) {
- String base = path.substr(0, srpos);
- if (!get_edited_scene() || get_edited_scene()->get_scene_file_path() != base) {
- show_warning(TTR("This resource can't be saved because it does not belong to the edited scene. Make it unique first."));
+ if (!path.is_resource_file()) {
+ int srpos = path.find("::");
+ if (srpos != -1) {
+ String base = path.substr(0, srpos);
+ if (!get_edited_scene() || get_edited_scene()->get_scene_file_path() != base) {
+ show_warning(TTR("This resource can't be saved because it does not belong to the edited scene. Make it unique first."));
+ return;
+ }
+ }
+ } else {
+ if (FileAccess::exists(path + ".import")) {
+ show_warning(TTR("This resource can't be saved because it was imported from another file. Make it unique first."));
return;
}
}
@@ -1378,7 +1393,7 @@ void EditorNode::_get_scene_metadata(const String &p_file) {
return;
}
- String path = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg");
+ String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg");
Ref<ConfigFile> cf;
cf.instantiate();
@@ -1410,7 +1425,7 @@ void EditorNode::_set_scene_metadata(const String &p_file, int p_idx) {
return;
}
- String path = EditorPaths::get_singleton()->get_project_settings_dir().plus_file(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg");
+ String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg");
Ref<ConfigFile> cf;
cf.instantiate();
@@ -1606,7 +1621,7 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
// Save thumbnail directly, as thumbnailer may not update due to actual scene not changing md5.
String temp_path = EditorPaths::get_singleton()->get_cache_dir();
String cache_base = ProjectSettings::get_singleton()->globalize_path(p_file).md5_text();
- cache_base = temp_path.plus_file("resthumb-" + cache_base);
+ cache_base = temp_path.path_join("resthumb-" + cache_base);
// Does not have it, try to load a cached thumbnail.
String file = cache_base + ".png";
@@ -1685,6 +1700,8 @@ int EditorNode::_save_external_resources() {
saved++;
}
+ get_undo_redo()->set_history_as_saved(EditorUndoRedoManager::GLOBAL_HISTORY);
+
return saved;
}
@@ -1766,11 +1783,7 @@ void EditorNode::_save_scene(String p_file, int idx) {
if (err == OK) {
scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(p_file));
- if (idx < 0 || idx == editor_data.get_edited_scene()) {
- set_current_version(editor_data.get_undo_redo().get_version());
- } else {
- editor_data.set_edited_scene_version(0, idx);
- }
+ editor_data.set_scene_as_saved(idx);
editor_data.set_scene_modified_time(idx, FileAccess::get_modified_time(p_file));
editor_folding.save_scene_folding(scene, p_file);
@@ -1815,15 +1828,15 @@ void EditorNode::restart_editor() {
List<String> args;
+ for (const String &a : Main::get_forwardable_cli_arguments(Main::CLI_SCOPE_TOOL)) {
+ args.push_back(a);
+ }
+
args.push_back("--path");
args.push_back(ProjectSettings::get_singleton()->get_resource_path());
args.push_back("-e");
- if (OS::get_singleton()->is_disable_crash_handler()) {
- args.push_back("--disable-crash-handler");
- }
-
if (!to_reopen.is_empty()) {
args.push_back(to_reopen);
}
@@ -1862,12 +1875,9 @@ void EditorNode::_mark_unsaved_scenes() {
}
String path = node->get_scene_file_path();
- if (!(path.is_empty() || FileAccess::exists(path))) {
- if (i == editor_data.get_edited_scene()) {
- set_current_version(-1);
- } else {
- editor_data.set_edited_scene_version(-1, i);
- }
+ if (!path.is_empty() && !FileAccess::exists(path)) {
+ // Mark scene tab as unsaved if the file is gone.
+ get_undo_redo()->set_history_as_unsaved(editor_data.get_scene_history_id(i));
}
}
@@ -1942,6 +1952,21 @@ void EditorNode::_dialog_action(String p_file) {
}
} break;
+ case FILE_SAVE_AND_RUN_MAIN_SCENE: {
+ ProjectSettings::get_singleton()->set("application/run/main_scene", p_file);
+ ProjectSettings::get_singleton()->save();
+
+ if (file->get_file_mode() == EditorFileDialog::FILE_MODE_SAVE_FILE) {
+ _save_default_environment();
+ _save_scene_with_preview(p_file);
+ if ((bool)pick_main_scene->get_meta("from_native", false)) {
+ run_native->resume_run_native();
+ } else {
+ _run(false, p_file);
+ }
+ }
+ } break;
+
case FILE_EXPORT_MESH_LIBRARY: {
Ref<MeshLibrary> ml;
if (file_export_lib_merge->is_pressed() && FileAccess::exists(p_file)) {
@@ -2202,11 +2227,19 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
Object *prev_inspected_object = InspectorDock::get_inspector_singleton()->get_edited_object();
bool disable_folding = bool(EDITOR_GET("interface/inspector/disable_folding"));
- bool stay_in_script_editor_on_node_selected = bool(EDITOR_GET("text_editor/behavior/navigation/stay_in_script_editor_on_node_selected"));
bool is_resource = current_obj->is_class("Resource");
bool is_node = current_obj->is_class("Node");
+ bool stay_in_script_editor_on_node_selected = bool(EDITOR_GET("text_editor/behavior/navigation/stay_in_script_editor_on_node_selected"));
+ bool skip_main_plugin = false;
+
+ String editable_info; // None by default.
+ bool info_is_warning = false;
- String editable_warning; // None by default.
+ if (current_obj->has_method("_is_read_only")) {
+ if (current_obj->call("_is_read_only")) {
+ editable_info = TTR("This object is marked as read-only, so it's not editable.");
+ }
+ }
if (is_resource) {
Resource *current_res = Object::cast_to<Resource>(current_obj);
@@ -2220,16 +2253,25 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
int subr_idx = current_res->get_path().find("::");
if (subr_idx != -1) {
String base_path = current_res->get_path().substr(0, subr_idx);
- if (FileAccess::exists(base_path + ".import")) {
- editable_warning = TTR("This resource belongs to a scene that was imported, so it's not editable.\nPlease read the documentation relevant to importing scenes to better understand this workflow.");
+ if (!base_path.is_resource_file()) {
+ if (FileAccess::exists(base_path + ".import")) {
+ if (get_edited_scene() && get_edited_scene()->get_scene_file_path() == base_path) {
+ info_is_warning = true;
+ }
+ editable_info = TTR("This resource belongs to a scene that was imported, so it's not editable.\nPlease read the documentation relevant to importing scenes to better understand this workflow.");
+ } else {
+ if ((!get_edited_scene() || get_edited_scene()->get_scene_file_path() != base_path) && ResourceLoader::get_resource_type(base_path) == "PackedScene") {
+ editable_info = TTR("This resource belongs to a scene that was instantiated or inherited.\nChanges to it must be made inside the original scene.");
+ }
+ }
} else {
- if ((!get_edited_scene() || get_edited_scene()->get_scene_file_path() != base_path) && ResourceLoader::get_resource_type(base_path) == "PackedScene") {
- editable_warning = TTR("This resource belongs to a scene that was instantiated or inherited.\nChanges to it won't be kept when saving the current scene.");
+ if (FileAccess::exists(base_path + ".import")) {
+ editable_info = TTR("This resource belongs to a scene that was imported, so it's not editable.\nPlease read the documentation relevant to importing scenes to better understand this workflow.");
}
}
} else if (current_res->get_path().is_resource_file()) {
if (FileAccess::exists(current_res->get_path() + ".import")) {
- editable_warning = TTR("This resource was imported, so it's not editable. Change its settings in the import panel and then re-import.");
+ editable_info = TTR("This resource was imported, so it's not editable. Change its settings in the import panel and then re-import.");
}
}
} else if (is_node) {
@@ -2241,8 +2283,8 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
NodeDock::get_singleton()->set_node(current_node);
SceneTreeDock::get_singleton()->set_selected(current_node);
InspectorDock::get_singleton()->update(current_node);
- if (!inspector_only) {
- inspector_only = stay_in_script_editor_on_node_selected && ScriptEditor::get_singleton()->is_visible_in_tree();
+ if (!inspector_only && !skip_main_plugin) {
+ skip_main_plugin = stay_in_script_editor_on_node_selected && ScriptEditor::get_singleton()->is_visible_in_tree();
}
} else {
NodeDock::get_singleton()->set_node(nullptr);
@@ -2253,7 +2295,8 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
if (get_edited_scene() && !get_edited_scene()->get_scene_file_path().is_empty()) {
String source_scene = get_edited_scene()->get_scene_file_path();
if (FileAccess::exists(source_scene + ".import")) {
- editable_warning = TTR("This scene was imported, so changes to it won't be kept.\nInstancing it or inheriting will allow making changes to it.\nPlease read the documentation relevant to importing scenes to better understand this workflow.");
+ editable_info = TTR("This scene was imported, so changes to it won't be kept.\nInstancing it or inheriting will allow making changes to it.\nPlease read the documentation relevant to importing scenes to better understand this workflow.");
+ info_is_warning = true;
}
}
@@ -2261,7 +2304,7 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
Node *selected_node = nullptr;
if (current_obj->is_class("EditorDebuggerRemoteObject")) {
- editable_warning = TTR("This is a remote object, so changes to it won't be kept.\nPlease read the documentation relevant to debugging to better understand this workflow.");
+ editable_info = TTR("This is a remote object, so it's not editable.\nPlease read the documentation relevant to debugging to better understand this workflow.");
disable_folding = true;
} else if (current_obj->is_class("MultiNodeEdit")) {
Node *scene = get_edited_scene();
@@ -2296,7 +2339,10 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
InspectorDock::get_inspector_singleton()->update_tree();
}
- InspectorDock::get_singleton()->set_warning(editable_warning);
+ InspectorDock::get_singleton()->set_info(
+ info_is_warning ? TTR("Changes may be lost!") : TTR("This object is read-only."),
+ editable_info,
+ info_is_warning);
if (InspectorDock::get_inspector_singleton()->is_using_folding() == disable_folding) {
InspectorDock::get_inspector_singleton()->set_use_folding(!disable_folding);
@@ -2318,7 +2364,7 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
}
}
- if (main_plugin) {
+ if (main_plugin && !skip_main_plugin) {
// Special case if use of external editor is true.
Resource *current_res = Object::cast_to<Resource>(current_obj);
if (main_plugin->get_name() == "Script" && !current_obj->is_class("VisualScript") && current_res && !current_res->is_built_in() && (bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor")) || overrides_external_editor(current_obj))) {
@@ -2386,7 +2432,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
String run_filename;
- if (p_current || (editor_data.get_edited_scene_root() && !p_custom.is_empty() && p_custom == editor_data.get_edited_scene_root()->get_scene_file_path())) {
+ if ((p_current && p_custom.is_empty()) || (editor_data.get_edited_scene_root() && !p_custom.is_empty() && p_custom == editor_data.get_edited_scene_root()->get_scene_file_path())) {
Node *scene = editor_data.get_edited_scene_root();
if (!scene) {
@@ -2395,10 +2441,8 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
}
if (scene->get_scene_file_path().is_empty()) {
- current_menu_option = -1;
- _menu_option(FILE_SAVE_AS_SCENE);
- // Set the option to save and run so when the dialog is accepted, the scene runs.
current_menu_option = FILE_SAVE_AND_RUN;
+ _menu_option_confirm(FILE_SAVE_AS_SCENE, true);
file->set_title(TTR("Save scene before running..."));
return;
}
@@ -2413,6 +2457,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
if (!ensure_main_scene(false)) {
return;
}
+ run_filename = GLOBAL_DEF_BASIC("application/run/main_scene", "");
}
if (bool(EDITOR_GET("run/auto_save/save_before_running"))) {
@@ -2449,15 +2494,19 @@ void EditorNode::_run(bool p_current, const String &p_custom) {
emit_signal(SNAME("play_pressed"));
if (p_current) {
+ run_current_filename = run_filename;
play_scene_button->set_pressed(true);
play_scene_button->set_icon(gui_base->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
+ play_scene_button->set_tooltip_text(TTR("Reload the played scene."));
} else if (!p_custom.is_empty()) {
run_custom_filename = p_custom;
play_custom_scene_button->set_pressed(true);
play_custom_scene_button->set_icon(gui_base->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
+ play_custom_scene_button->set_tooltip_text(TTR("Reload the played scene."));
} else {
play_button->set_pressed(true);
play_button->set_icon(gui_base->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
+ play_button->set_tooltip_text(TTR("Reload the played scene."));
}
stop_button->set_disabled(false);
@@ -2482,9 +2531,22 @@ void EditorNode::_run_native(const Ref<EditorExportPreset> &p_preset) {
}
}
+void EditorNode::_reset_play_buttons() {
+ play_button->set_pressed(false);
+ play_button->set_icon(gui_base->get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
+ play_button->set_tooltip_text(TTR("Play the project."));
+ play_scene_button->set_pressed(false);
+ play_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayScene"), SNAME("EditorIcons")));
+ play_scene_button->set_tooltip_text(TTR("Play the edited scene."));
+ play_custom_scene_button->set_pressed(false);
+ play_custom_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayCustom"), SNAME("EditorIcons")));
+ play_custom_scene_button->set_tooltip_text(TTR("Play a custom scene."));
+}
+
void EditorNode::_android_build_source_selected(const String &p_file) {
export_template_manager->install_android_template_from_file(p_file);
}
+
void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
if (!p_confirmed) { // FIXME: this may be a hack.
current_menu_option = (MenuOptions)p_option;
@@ -2710,9 +2772,9 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
if ((int)Input::get_singleton()->get_mouse_button_mask() & 0x7) {
log->add_message(TTR("Can't undo while mouse buttons are pressed."), EditorLog::MSG_TYPE_EDITOR);
} else {
- String action = editor_data.get_undo_redo().get_current_action_name();
+ String action = editor_data.get_undo_redo()->get_current_action_name();
- if (!editor_data.get_undo_redo().undo()) {
+ if (!editor_data.get_undo_redo()->undo()) {
log->add_message(TTR("Nothing to undo."), EditorLog::MSG_TYPE_EDITOR);
} else if (!action.is_empty()) {
log->add_message(vformat(TTR("Undo: %s"), action), EditorLog::MSG_TYPE_EDITOR);
@@ -2723,10 +2785,10 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
if ((int)Input::get_singleton()->get_mouse_button_mask() & 0x7) {
log->add_message(TTR("Can't redo while mouse buttons are pressed."), EditorLog::MSG_TYPE_EDITOR);
} else {
- if (!editor_data.get_undo_redo().redo()) {
+ if (!editor_data.get_undo_redo()->redo()) {
log->add_message(TTR("Nothing to redo."), EditorLog::MSG_TYPE_EDITOR);
} else {
- String action = editor_data.get_undo_redo().get_current_action_name();
+ String action = editor_data.get_undo_redo()->get_current_action_name();
log->add_message(vformat(TTR("Redo: %s"), action), EditorLog::MSG_TYPE_EDITOR);
}
}
@@ -2761,7 +2823,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
ERR_PRINT("Failed to load scene");
}
editor_data.move_edited_scene_to_index(cur_idx);
- get_undo_redo()->clear_history(false);
+ get_undo_redo()->clear_history(false, editor_data.get_current_edited_scene_history_id());
scene_tabs->set_current_tab(cur_idx);
} break;
@@ -2776,7 +2838,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
quick_run->set_title(TTR("Quick Run Scene..."));
play_custom_scene_button->set_pressed(false);
} else {
- String last_custom_scene = run_custom_filename;
+ String last_custom_scene = run_custom_filename; // This is necessary to have a copy of the string.
run_play_custom(last_custom_scene);
}
@@ -2788,13 +2850,9 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
editor_run.stop();
run_custom_filename.clear();
- play_button->set_pressed(false);
- play_button->set_icon(gui_base->get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
- play_scene_button->set_pressed(false);
- play_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayScene"), SNAME("EditorIcons")));
- play_custom_scene_button->set_pressed(false);
- play_custom_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayCustom"), SNAME("EditorIcons")));
+ run_current_filename.clear();
stop_button->set_disabled(true);
+ _reset_play_buttons();
if (bool(EDITOR_GET("run/output/always_close_output_on_stop"))) {
for (int i = 0; i < bottom_panel_items.size(); i++) {
@@ -2817,7 +2875,12 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
} break;
case RUN_PLAY_SCENE: {
- run_play_current();
+ if (run_current_filename.is_empty() || editor_run.get_status() == EditorRun::STATUS_STOP) {
+ run_play_current();
+ } else {
+ String last_current_scene = run_current_filename; // This is necessary to have a copy of the string.
+ run_play_custom(last_current_scene);
+ }
} break;
case RUN_SETTINGS: {
@@ -2845,7 +2908,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
OS::get_singleton()->shell_open(String("file://") + OS::get_singleton()->get_user_data_dir());
} break;
case FILE_EXPLORE_ANDROID_BUILD_TEMPLATES: {
- OS::get_singleton()->shell_open("file://" + ProjectSettings::get_singleton()->get_resource_path().plus_file("android"));
+ OS::get_singleton()->shell_open("file://" + ProjectSettings::get_singleton()->get_resource_path().path_join("android"));
} break;
case FILE_QUIT:
case RUN_PROJECT_MANAGER:
@@ -3074,8 +3137,7 @@ int EditorNode::_next_unsaved_scene(bool p_valid_filename, int p_start) {
if (!editor_data.get_edited_scene_root(i)) {
continue;
}
- int current = editor_data.get_edited_scene();
- bool unsaved = (i == current) ? saved_version != editor_data.get_undo_redo().get_version() : editor_data.get_scene_version(i) != 0;
+ bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i));
if (unsaved) {
String scene_filename = editor_data.get_edited_scene_root(i)->get_scene_file_path();
if (p_valid_filename && scene_filename.length() == 0) {
@@ -3161,6 +3223,9 @@ void EditorNode::_discard_changes(const String &p_str) {
String exec = OS::get_singleton()->get_executable_path();
List<String> args;
+ for (const String &a : Main::get_forwardable_cli_arguments(Main::CLI_SCOPE_TOOL)) {
+ args.push_back(a);
+ }
args.push_back("--path");
args.push_back(exec.get_base_dir());
args.push_back("--project-manager");
@@ -3180,17 +3245,15 @@ void EditorNode::_update_file_menu_opened() {
Ref<Shortcut> reopen_closed_scene_sc = ED_GET_SHORTCUT("editor/reopen_closed_scene");
reopen_closed_scene_sc->set_name(TTR("Reopen Closed Scene"));
- PopupMenu *pop = file_menu->get_popup();
- pop->set_item_disabled(pop->get_item_index(FILE_OPEN_PREV), previous_scenes.is_empty());
+ file_menu->set_item_disabled(file_menu->get_item_index(FILE_OPEN_PREV), previous_scenes.is_empty());
- const UndoRedo &undo_redo = editor_data.get_undo_redo();
- pop->set_item_disabled(pop->get_item_index(EDIT_UNDO), !undo_redo.has_undo());
- pop->set_item_disabled(pop->get_item_index(EDIT_REDO), !undo_redo.has_redo());
+ Ref<EditorUndoRedoManager> undo_redo = editor_data.get_undo_redo();
+ file_menu->set_item_disabled(file_menu->get_item_index(EDIT_UNDO), !undo_redo->has_undo());
+ file_menu->set_item_disabled(file_menu->get_item_index(EDIT_REDO), !undo_redo->has_redo());
}
void EditorNode::_update_file_menu_closed() {
- PopupMenu *pop = file_menu->get_popup();
- pop->set_item_disabled(pop->get_item_index(FILE_OPEN_PREV), false);
+ file_menu->set_item_disabled(file_menu->get_item_index(FILE_OPEN_PREV), false);
}
Control *EditorNode::get_main_control() {
@@ -3382,7 +3445,7 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled,
// Only try to load the script if it has a name. Else, the plugin has no init script.
if (script_path.length() > 0) {
- script_path = addon_path.get_base_dir().plus_file(script_path);
+ script_path = addon_path.get_base_dir().path_join(script_path);
script = ResourceLoader::load(script_path);
if (script.is_null()) {
@@ -3442,7 +3505,6 @@ void EditorNode::_remove_edited_scene(bool p_change_tab) {
_scene_tab_changed(new_index);
}
editor_data.remove_scene(old_index);
- editor_data.get_undo_redo().clear_history(false);
_update_title();
_update_scene_tabs();
}
@@ -3498,7 +3560,6 @@ Dictionary EditorNode::_get_main_scene_state() {
state["main_tab"] = _get_current_main_editor();
state["scene_tree_offset"] = SceneTreeDock::get_singleton()->get_tree_editor()->get_scene_tree()->get_vscroll_bar()->get_value();
state["property_edit_offset"] = InspectorDock::get_inspector_singleton()->get_scroll_offset();
- state["saved_version"] = saved_version;
state["node_filter"] = SceneTreeDock::get_singleton()->get_filter();
return state;
}
@@ -3558,11 +3619,6 @@ void EditorNode::_set_main_scene_state(Dictionary p_state, Node *p_for_scene) {
editor_data.notify_edited_scene_changed();
}
-void EditorNode::set_current_version(uint64_t p_version) {
- saved_version = p_version;
- editor_data.set_edited_scene_version(p_version);
-}
-
bool EditorNode::is_changing_scene() const {
return changing_scene;
}
@@ -3582,7 +3638,7 @@ void EditorNode::set_current_scene(int p_idx) {
editor_folding.load_scene_folding(editor_data.get_edited_scene_root(p_idx), editor_data.get_scene_path(p_idx));
}
- call_deferred(SNAME("_clear_undo_history"));
+ get_undo_redo()->clear_history(false, editor_data.get_scene_history_id(p_idx));
}
changing_scene = true;
@@ -3599,8 +3655,8 @@ void EditorNode::set_current_scene(int p_idx) {
Node *new_scene = editor_data.get_edited_scene_root();
- if (Object::cast_to<Popup>(new_scene)) {
- Object::cast_to<Popup>(new_scene)->show();
+ if (Popup *p = Object::cast_to<Popup>(new_scene)) {
+ p->show();
}
SceneTreeDock::get_singleton()->set_edited_scene(new_scene);
@@ -3618,6 +3674,7 @@ void EditorNode::set_current_scene(int p_idx) {
_edit_current(true);
_update_title();
+ _update_scene_tabs();
call_deferred(SNAME("_set_main_scene_state"), state, get_edited_scene()); // Do after everything else is done setting up.
}
@@ -3645,6 +3702,18 @@ void EditorNode::fix_dependencies(const String &p_for_file) {
int EditorNode::new_scene() {
int idx = editor_data.add_edited_scene(-1);
+ // Remove placeholder empty scene.
+ if (editor_data.get_edited_scene_count() > 1) {
+ for (int i = 0; i < editor_data.get_edited_scene_count() - 1; i++) {
+ bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i));
+ if (!unsaved && editor_data.get_scene_path(i).is_empty()) {
+ editor_data.remove_scene(i);
+ idx--;
+ }
+ }
+ }
+ idx = MAX(idx, 0);
+
_scene_tab_changed(idx);
editor_data.clear_editor_states();
_update_scene_tabs();
@@ -3776,7 +3845,6 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
set_edited_scene(new_scene);
_get_scene_metadata(p_scene);
- saved_version = editor_data.get_undo_redo().get_version();
_update_title();
_update_scene_tabs();
_add_to_recent_scenes(lpath);
@@ -3819,6 +3887,37 @@ void EditorNode::edit_foreign_resource(Ref<Resource> p_resource) {
InspectorDock::get_singleton()->call_deferred("edit_resource", p_resource);
}
+bool EditorNode::is_resource_read_only(Ref<Resource> p_resource) {
+ ERR_FAIL_COND_V(p_resource.is_null(), false);
+
+ String path = p_resource->get_path();
+ if (!path.is_resource_file()) {
+ // If the resource name contains '::', that means it is a subresource embedded in another resource.
+ int srpos = path.find("::");
+ if (srpos != -1) {
+ String base = path.substr(0, srpos);
+ // If the base resource is a packed scene, we treat it as read-only if it is not the currently edited scene.
+ if (ResourceLoader::get_resource_type(base) == "PackedScene") {
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ return true;
+ }
+ } else {
+ // If a corresponding .import file exists for the base file, we assume it to be imported and should therefore treated as read-only.
+ if (FileAccess::exists(base + ".import")) {
+ return true;
+ }
+ }
+ }
+ } else {
+ // The resource is not a subresource, but if it has an .import file, it's imported so treat it as read only.
+ if (FileAccess::exists(path + ".import")) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void EditorNode::request_instance_scene(const String &p_path) {
SceneTreeDock::get_singleton()->instantiate(p_path);
}
@@ -3827,6 +3926,10 @@ void EditorNode::request_instantiate_scenes(const Vector<String> &p_files) {
SceneTreeDock::get_singleton()->instantiate_scenes(p_files);
}
+Ref<EditorUndoRedoManager> &EditorNode::get_undo_redo() {
+ return singleton->editor_data.get_undo_redo();
+}
+
void EditorNode::_inherit_request(String p_file) {
current_menu_option = FILE_NEW_INHERITED_SCENE;
_dialog_action(p_file);
@@ -3987,6 +4090,7 @@ void EditorNode::register_editor_types() {
GDREGISTER_CLASS(EditorSpinSlider);
GDREGISTER_CLASS(EditorResourcePicker);
GDREGISTER_CLASS(EditorScriptPicker);
+ GDREGISTER_ABSTRACT_CLASS(EditorUndoRedoManager);
GDREGISTER_ABSTRACT_CLASS(FileSystemDock);
GDREGISTER_VIRTUAL_CLASS(EditorFileSystemImportFormatSupportQuery);
@@ -4101,8 +4205,15 @@ void EditorNode::_pick_main_scene_custom_action(const String &p_custom_action_na
}
pick_main_scene->hide();
- current_menu_option = SETTINGS_PICK_MAIN_SCENE;
- _dialog_action(scene->get_scene_file_path());
+
+ if (!FileAccess::exists(scene->get_scene_file_path())) {
+ current_menu_option = FILE_SAVE_AND_RUN_MAIN_SCENE;
+ _menu_option_confirm(FILE_SAVE_AS_SCENE, true);
+ file->set_title(TTR("Save scene before running..."));
+ } else {
+ current_menu_option = SETTINGS_PICK_MAIN_SCENE;
+ _dialog_action(scene->get_scene_file_path());
+ }
}
}
@@ -4302,6 +4413,15 @@ void EditorNode::_editor_file_dialog_unregister(EditorFileDialog *p_dialog) {
Vector<EditorNodeInitCallback> EditorNode::_init_callbacks;
+void EditorNode::_begin_first_scan() {
+ Engine::get_singleton()->startup_benchmark_begin_measure("editor_scan_and_import");
+ EditorFileSystem::get_singleton()->scan();
+}
+void EditorNode::set_use_startup_benchmark(bool p_use_startup_benchmark, const String &p_startup_benchmark_file) {
+ use_startup_benchmark = p_use_startup_benchmark;
+ startup_benchmark_file = p_startup_benchmark_file;
+}
+
Error EditorNode::export_preset(const String &p_preset, const String &p_path, bool p_debug, bool p_pack_only) {
export_defer.preset = p_preset;
export_defer.path = p_path;
@@ -4610,13 +4730,13 @@ void EditorNode::_save_docks() {
Ref<ConfigFile> config;
config.instantiate();
// Load and amend existing config if it exists.
- config->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+ config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
_save_docks_to_config(config, "docks");
_save_open_scenes_to_config(config, "EditorNode");
editor_data.get_plugin_window_layout(config);
- config->save(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+ config->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
}
void EditorNode::_save_docks_to_config(Ref<ConfigFile> p_layout, const String &p_section) {
@@ -4680,7 +4800,7 @@ void EditorNode::_dock_split_dragged(int ofs) {
void EditorNode::_load_docks() {
Ref<ConfigFile> config;
config.instantiate();
- Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+ Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
if (err != OK) {
// No config.
if (overridden_default_layout >= 0) {
@@ -4913,7 +5033,7 @@ bool EditorNode::has_scenes_in_session() {
}
Ref<ConfigFile> config;
config.instantiate();
- Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg"));
+ Error err = config->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("editor_layout.cfg"));
if (err != OK) {
return false;
}
@@ -4976,8 +5096,9 @@ void EditorNode::run_play_current() {
}
void EditorNode::run_play_custom(const String &p_custom) {
+ bool is_current = !run_current_filename.is_empty();
_menu_option_confirm(RUN_STOP, true);
- _run(false, p_custom);
+ _run(is_current, p_custom);
}
void EditorNode::run_stop() {
@@ -5112,9 +5233,7 @@ void EditorNode::_scene_tab_closed(int p_tab, int option) {
return;
}
- bool unsaved = (p_tab == editor_data.get_edited_scene())
- ? saved_version != editor_data.get_undo_redo().get_version()
- : editor_data.get_scene_version(p_tab) != 0;
+ bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(p_tab));
if (unsaved) {
save_confirmation->set_ok_button_text(TTR("Save & Close"));
save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), !scene->get_scene_file_path().is_empty() ? scene->get_scene_file_path() : "unsaved scene"));
@@ -5226,23 +5345,10 @@ void EditorNode::_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_p
void EditorNode::_scene_tab_changed(int p_tab) {
tab_preview_panel->hide();
- bool unsaved = (saved_version != editor_data.get_undo_redo().get_version());
-
if (p_tab == editor_data.get_edited_scene()) {
return; // Pointless.
}
-
- uint64_t next_scene_version = editor_data.get_scene_version(p_tab);
-
- editor_data.get_undo_redo().create_action(TTR("Switch Scene Tab"));
- editor_data.get_undo_redo().add_do_method(this, "set_current_version", unsaved ? saved_version : 0);
- editor_data.get_undo_redo().add_do_method(this, "set_current_scene", p_tab);
- editor_data.get_undo_redo().add_do_method(this, "set_current_version", next_scene_version == 0 ? editor_data.get_undo_redo().get_version() + 1 : next_scene_version);
-
- editor_data.get_undo_redo().add_undo_method(this, "set_current_version", next_scene_version);
- editor_data.get_undo_redo().add_undo_method(this, "set_current_scene", editor_data.get_edited_scene());
- editor_data.get_undo_redo().add_undo_method(this, "set_current_version", saved_version);
- editor_data.get_undo_redo().commit_action();
+ set_current_scene(p_tab);
}
Button *EditorNode::add_bottom_panel_item(String p_text, Control *p_item) {
@@ -5579,7 +5685,7 @@ void EditorNode::_add_dropped_files_recursive(const Vector<String> &p_files, Str
for (int i = 0; i < p_files.size(); i++) {
String from = p_files[i];
- String to = to_path.plus_file(from.get_file());
+ String to = to_path.path_join(from.get_file());
if (dir->dir_exists(from)) {
Vector<String> sub_files;
@@ -5594,7 +5700,7 @@ void EditorNode::_add_dropped_files_recursive(const Vector<String> &p_files, Str
continue;
}
- sub_files.push_back(from.plus_file(next_file));
+ sub_files.push_back(from.path_join(next_file));
next_file = sub_dir->get_next();
}
@@ -5628,7 +5734,7 @@ void EditorNode::reload_scene(const String &p_path) {
if (scene_idx == -1) {
if (get_edited_scene()) {
// Scene is not open, so at it might be instantiated. We'll refresh the whole scene later.
- editor_data.get_undo_redo().clear_history();
+ editor_data.get_undo_redo()->clear_history(false, editor_data.get_current_edited_scene_history_id());
}
return;
}
@@ -5644,7 +5750,7 @@ void EditorNode::reload_scene(const String &p_path) {
// Adjust index so tab is back a the previous position.
editor_data.move_edited_scene_to_index(scene_idx);
- get_undo_redo()->clear_history();
+ get_undo_redo()->clear_history(false, editor_data.get_scene_history_id(scene_idx));
// Recover the tab.
scene_tabs->set_current_tab(current_tab);
@@ -5822,13 +5928,13 @@ void EditorNode::_bind_methods() {
ClassDB::bind_method("set_edited_scene", &EditorNode::set_edited_scene);
ClassDB::bind_method("open_request", &EditorNode::open_request);
ClassDB::bind_method("edit_foreign_resource", &EditorNode::edit_foreign_resource);
+ ClassDB::bind_method("is_resource_read_only", &EditorNode::is_resource_read_only);
ClassDB::bind_method("_close_messages", &EditorNode::_close_messages);
ClassDB::bind_method("_show_messages", &EditorNode::_show_messages);
ClassDB::bind_method("stop_child_process", &EditorNode::stop_child_process);
ClassDB::bind_method("set_current_scene", &EditorNode::set_current_scene);
- ClassDB::bind_method("set_current_version", &EditorNode::set_current_version);
ClassDB::bind_method("_thumbnail_done", &EditorNode::_thumbnail_done);
ClassDB::bind_method("_set_main_scene_state", &EditorNode::_set_main_scene_state);
ClassDB::bind_method("_update_recent_scenes", &EditorNode::_update_recent_scenes);
@@ -6129,7 +6235,7 @@ EditorNode::EditorNode() {
rmp.instantiate();
EditorInspector::add_inspector_plugin(rmp);
- Ref<EditorInspectorShaderModePlugin> smp;
+ Ref<EditorInspectorVisualShaderModePlugin> smp;
smp.instantiate();
EditorInspector::add_inspector_plugin(smp);
}
@@ -6152,12 +6258,11 @@ EditorNode::EditorNode() {
add_child(editor_export);
// Exporters might need the theme.
+ EditorColorMap::create();
theme = create_custom_theme();
register_exporters();
- ClassDB::set_class_enabled("RootMotionView", true);
-
EDITOR_DEF("interface/editor/save_on_focus_loss", false);
EDITOR_DEF("interface/editor/show_update_spinner", false);
EDITOR_DEF("interface/editor/update_continuously", false);
@@ -6221,7 +6326,7 @@ EditorNode::EditorNode() {
main_vbox->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, 8);
main_vbox->add_theme_constant_override("separation", 8 * EDSCALE);
- menu_hb = memnew(HBoxContainer);
+ menu_hb = memnew(EditorTitleBar);
main_vbox->add_child(menu_hb);
left_l_hsplit = memnew(HSplitContainer);
@@ -6410,7 +6515,7 @@ EditorNode::EditorNode() {
scene_tab_add = memnew(Button);
scene_tab_add->set_flat(true);
- scene_tab_add->set_tooltip(TTR("Add a new scene."));
+ scene_tab_add->set_tooltip_text(TTR("Add a new scene."));
scene_tab_add->set_icon(gui_base->get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
scene_tab_add->add_theme_color_override("icon_normal_color", Color(0.6f, 0.6f, 0.6f, 0.8f));
scene_tabs->add_child(scene_tab_add);
@@ -6426,7 +6531,7 @@ EditorNode::EditorNode() {
ED_SHORTCUT_AND_COMMAND("editor/distraction_free_mode", TTR("Distraction Free Mode"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::F11);
ED_SHORTCUT_OVERRIDE("editor/distraction_free_mode", "macos", KeyModifierMask::CMD | KeyModifierMask::CTRL | Key::D);
distraction_free->set_shortcut(ED_GET_SHORTCUT("editor/distraction_free_mode"));
- distraction_free->set_tooltip(TTR("Toggle distraction-free mode."));
+ distraction_free->set_tooltip_text(TTR("Toggle distraction-free mode."));
distraction_free->connect("pressed", callable_mp(this, &EditorNode::_toggle_distraction_free_mode));
distraction_free->set_icon(gui_base->get_theme_icon(SNAME("DistractionFree"), SNAME("EditorIcons")));
distraction_free->set_toggle_mode(true);
@@ -6451,20 +6556,34 @@ EditorNode::EditorNode() {
main_control->add_theme_constant_override("separation", 0);
scene_root_parent->add_child(main_control);
- HBoxContainer *left_menu_hb = memnew(HBoxContainer);
- menu_hb->add_child(left_menu_hb);
+ bool global_menu = !bool(EDITOR_GET("interface/editor/use_embedded_menu")) && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU);
+ bool can_expand = bool(EDITOR_GET("interface/editor/expand_to_title")) && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_EXTEND_TO_TITLE);
- file_menu = memnew(MenuButton);
- file_menu->set_flat(false);
- file_menu->set_switch_on_hover(true);
- file_menu->set_text(TTR("Scene"));
- file_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
- left_menu_hb->add_child(file_menu);
+ if (can_expand) {
+ // Add spacer to avoid other controls under window minimize/maximize/close buttons (left side).
+ Control *menu_spacer = memnew(Control);
+ menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ menu_spacer->set_custom_minimum_size(Size2(DisplayServer::get_singleton()->window_get_safe_title_margins(DisplayServer::MAIN_WINDOW_ID).x, 0));
+ menu_hb->add_child(menu_spacer);
+ }
+
+ main_menu = memnew(MenuBar);
+ menu_hb->add_child(main_menu);
+ main_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
+ main_menu->set_flat(true);
+ main_menu->set_start_index(0); // Main menu, add to the start of global menu.
+ main_menu->set_prefer_global_menu(global_menu);
+ main_menu->set_switch_on_hover(true);
+
+ file_menu = memnew(PopupMenu);
+ file_menu->set_name(TTR("Scene"));
+ main_menu->add_child(file_menu);
+ main_menu->set_menu_tooltip(0, TTR("Operations with scene files."));
prev_scene = memnew(Button);
prev_scene->set_flat(true);
prev_scene->set_icon(gui_base->get_theme_icon(SNAME("PrevScene"), SNAME("EditorIcons")));
- prev_scene->set_tooltip(TTR("Go to previously opened scene."));
+ prev_scene->set_tooltip_text(TTR("Go to previously opened scene."));
prev_scene->set_disabled(true);
prev_scene->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(FILE_OPEN_PREV));
gui_base->add_child(prev_scene);
@@ -6529,84 +6648,75 @@ EditorNode::EditorNode() {
command_palette->set_title(TTR("Command Palette"));
gui_base->add_child(command_palette);
- PopupMenu *p;
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/new_scene", TTR("New Scene"), KeyModifierMask::CMD + Key::N), FILE_NEW_SCENE);
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/new_inherited_scene", TTR("New Inherited Scene..."), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::N), FILE_NEW_INHERITED_SCENE);
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/open_scene", TTR("Open Scene..."), KeyModifierMask::CMD + Key::O), FILE_OPEN_SCENE);
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/reopen_closed_scene", TTR("Reopen Closed Scene"), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::T), FILE_OPEN_PREV);
+ file_menu->add_submenu_item(TTR("Open Recent"), "RecentScenes", FILE_OPEN_RECENT);
- file_menu->set_tooltip(TTR("Operations with scene files."));
+ file_menu->add_separator();
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_scene", TTR("Save Scene"), KeyModifierMask::CMD + Key::S), FILE_SAVE_SCENE);
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_scene_as", TTR("Save Scene As..."), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::S), FILE_SAVE_AS_SCENE);
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_all_scenes", TTR("Save All Scenes"), KeyModifierMask::CMD + KeyModifierMask::SHIFT + KeyModifierMask::ALT + Key::S), FILE_SAVE_ALL_SCENES);
- p = file_menu->get_popup();
+ file_menu->add_separator();
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/new_scene", TTR("New Scene"), KeyModifierMask::CMD + Key::N), FILE_NEW_SCENE);
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/new_inherited_scene", TTR("New Inherited Scene..."), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::N), FILE_NEW_INHERITED_SCENE);
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/open_scene", TTR("Open Scene..."), KeyModifierMask::CMD + Key::O), FILE_OPEN_SCENE);
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/reopen_closed_scene", TTR("Reopen Closed Scene"), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::T), FILE_OPEN_PREV);
- p->add_submenu_item(TTR("Open Recent"), "RecentScenes", FILE_OPEN_RECENT);
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open", TTR("Quick Open..."), KeyModifierMask::SHIFT + KeyModifierMask::ALT + Key::O), FILE_QUICK_OPEN);
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open_scene", TTR("Quick Open Scene..."), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::O), FILE_QUICK_OPEN_SCENE);
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open_script", TTR("Quick Open Script..."), KeyModifierMask::CMD + KeyModifierMask::ALT + Key::O), FILE_QUICK_OPEN_SCRIPT);
- p->add_separator();
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_scene", TTR("Save Scene"), KeyModifierMask::CMD + Key::S), FILE_SAVE_SCENE);
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_scene_as", TTR("Save Scene As..."), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::S), FILE_SAVE_AS_SCENE);
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/save_all_scenes", TTR("Save All Scenes"), KeyModifierMask::CMD + KeyModifierMask::SHIFT + KeyModifierMask::ALT + Key::S), FILE_SAVE_ALL_SCENES);
-
- p->add_separator();
-
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open", TTR("Quick Open..."), KeyModifierMask::SHIFT + KeyModifierMask::ALT + Key::O), FILE_QUICK_OPEN);
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open_scene", TTR("Quick Open Scene..."), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::O), FILE_QUICK_OPEN_SCENE);
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open_script", TTR("Quick Open Script..."), KeyModifierMask::CMD + KeyModifierMask::ALT + Key::O), FILE_QUICK_OPEN_SCRIPT);
-
- p->add_separator();
+ file_menu->add_separator();
export_as_menu = memnew(PopupMenu);
export_as_menu->set_name("Export");
- p->add_child(export_as_menu);
- p->add_submenu_item(TTR("Export As..."), "Export");
+ file_menu->add_child(export_as_menu);
+ file_menu->add_submenu_item(TTR("Export As..."), "Export");
export_as_menu->add_shortcut(ED_SHORTCUT("editor/export_as_mesh_library", TTR("MeshLibrary...")), FILE_EXPORT_MESH_LIBRARY);
export_as_menu->connect("index_pressed", callable_mp(this, &EditorNode::_export_as_menu_option));
- p->add_separator();
- p->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO, true);
- p->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO, true);
+ file_menu->add_separator();
+ file_menu->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO, true);
+ file_menu->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO, true);
- p->add_separator();
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/reload_saved_scene", TTR("Reload Saved Scene")), EDIT_RELOAD_SAVED_SCENE);
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/close_scene", TTR("Close Scene"), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::W), FILE_CLOSE);
+ file_menu->add_separator();
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/reload_saved_scene", TTR("Reload Saved Scene")), EDIT_RELOAD_SAVED_SCENE);
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/close_scene", TTR("Close Scene"), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::W), FILE_CLOSE);
recent_scenes = memnew(PopupMenu);
recent_scenes->set_name("RecentScenes");
- p->add_child(recent_scenes);
+ file_menu->add_child(recent_scenes);
recent_scenes->connect("id_pressed", callable_mp(this, &EditorNode::_open_recent_scene));
- p->add_separator();
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/file_quit", TTR("Quit"), KeyModifierMask::CMD + Key::Q), FILE_QUIT, true);
-
- project_menu = memnew(MenuButton);
- project_menu->set_flat(false);
- project_menu->set_switch_on_hover(true);
- project_menu->set_tooltip(TTR("Miscellaneous project or scene-wide tools."));
- project_menu->set_text(TTR("Project"));
- project_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
- left_menu_hb->add_child(project_menu);
+ if (!global_menu || !OS::get_singleton()->has_feature("macos")) {
+ // On macOS "Quit" and "About" options are in the "app" menu.
+ file_menu->add_separator();
+ file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/file_quit", TTR("Quit"), KeyModifierMask::CMD + Key::Q), FILE_QUIT, true);
+ }
- p = project_menu->get_popup();
+ project_menu = memnew(PopupMenu);
+ project_menu->set_name(TTR("Project"));
+ main_menu->add_child(project_menu);
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/project_settings", TTR("Project Settings..."), Key::NONE, TTR("Project Settings")), RUN_SETTINGS);
- p->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
+ project_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/project_settings", TTR("Project Settings..."), Key::NONE, TTR("Project Settings")), RUN_SETTINGS);
+ project_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
vcs_actions_menu = VersionControlEditorPlugin::get_singleton()->get_version_control_actions_panel();
vcs_actions_menu->set_name("Version Control");
vcs_actions_menu->connect("index_pressed", callable_mp(this, &EditorNode::_version_control_menu_option));
- p->add_separator();
- p->add_child(vcs_actions_menu);
- p->add_submenu_item(TTR("Version Control"), "Version Control");
+ project_menu->add_separator();
+ project_menu->add_child(vcs_actions_menu);
+ project_menu->add_submenu_item(TTR("Version Control"), "Version Control");
vcs_actions_menu->add_item(TTR("Create Version Control Metadata"), RUN_VCS_METADATA);
vcs_actions_menu->add_item(TTR("Set Up Version Control"), RUN_VCS_SETTINGS);
vcs_actions_menu->add_item(TTR("Shut Down Version Control"), RUN_VCS_SHUT_DOWN);
- p->add_separator();
- p->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/export", TTR("Export..."), Key::NONE, TTR("Export")), FILE_EXPORT_PROJECT);
- p->add_item(TTR("Install Android Build Template..."), FILE_INSTALL_ANDROID_SOURCE);
- p->add_item(TTR("Open User Data Folder"), RUN_USER_DATA_FOLDER);
+ project_menu->add_separator();
+ project_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/export", TTR("Export..."), Key::NONE, TTR("Export")), FILE_EXPORT_PROJECT);
+ project_menu->add_item(TTR("Install Android Build Template..."), FILE_INSTALL_ANDROID_SOURCE);
+ project_menu->add_item(TTR("Open User Data Folder"), RUN_USER_DATA_FOLDER);
- p->add_separator();
- p->add_item(TTR("Customize Engine Build Configuration..."), TOOLS_BUILD_PROFILE_MANAGER);
- p->add_separator();
+ project_menu->add_separator();
+ project_menu->add_item(TTR("Customize Engine Build Configuration..."), TOOLS_BUILD_PROFILE_MANAGER);
+ project_menu->add_separator();
plugin_config_dialog = memnew(PluginConfigDialog);
plugin_config_dialog->connect("plugin_ready", callable_mp(this, &EditorNode::_on_plugin_ready));
@@ -6615,15 +6725,20 @@ EditorNode::EditorNode() {
tool_menu = memnew(PopupMenu);
tool_menu->set_name("Tools");
tool_menu->connect("index_pressed", callable_mp(this, &EditorNode::_tool_menu_option));
- p->add_child(tool_menu);
- p->add_submenu_item(TTR("Tools"), "Tools");
+ project_menu->add_child(tool_menu);
+ project_menu->add_submenu_item(TTR("Tools"), "Tools");
tool_menu->add_item(TTR("Orphan Resource Explorer..."), TOOLS_ORPHAN_RESOURCES);
- p->add_separator();
- p->add_shortcut(ED_SHORTCUT("editor/reload_current_project", TTR("Reload Current Project")), RELOAD_CURRENT_PROJECT);
+ project_menu->add_separator();
+ project_menu->add_shortcut(ED_SHORTCUT("editor/reload_current_project", TTR("Reload Current Project")), RELOAD_CURRENT_PROJECT);
ED_SHORTCUT_AND_COMMAND("editor/quit_to_project_list", TTR("Quit to Project List"), KeyModifierMask::CMD + KeyModifierMask::SHIFT + Key::Q);
ED_SHORTCUT_OVERRIDE("editor/quit_to_project_list", "macos", KeyModifierMask::SHIFT + KeyModifierMask::ALT + Key::Q);
- p->add_shortcut(ED_GET_SHORTCUT("editor/quit_to_project_list"), RUN_PROJECT_MANAGER, true);
+ project_menu->add_shortcut(ED_GET_SHORTCUT("editor/quit_to_project_list"), RUN_PROJECT_MANAGER, true);
+
+ // Spacer to center 2D / 3D / Script buttons.
+ Control *left_spacer = memnew(Control);
+ left_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ menu_hb->add_child(left_spacer);
menu_hb->add_spacer();
@@ -6631,85 +6746,81 @@ EditorNode::EditorNode() {
menu_hb->add_child(main_editor_button_vb);
// Options are added and handled by DebuggerEditorPlugin.
- debug_menu = memnew(MenuButton);
- debug_menu->set_flat(false);
- debug_menu->set_switch_on_hover(true);
- debug_menu->set_text(TTR("Debug"));
- debug_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
- left_menu_hb->add_child(debug_menu);
+ debug_menu = memnew(PopupMenu);
+ debug_menu->set_name(TTR("Debug"));
+ main_menu->add_child(debug_menu);
menu_hb->add_spacer();
- settings_menu = memnew(MenuButton);
- settings_menu->set_flat(false);
- settings_menu->set_switch_on_hover(true);
- settings_menu->set_text(TTR("Editor"));
- settings_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
- left_menu_hb->add_child(settings_menu);
-
- p = settings_menu->get_popup();
+ settings_menu = memnew(PopupMenu);
+ settings_menu->set_name(TTR("Editor"));
+ main_menu->add_child(settings_menu);
ED_SHORTCUT_AND_COMMAND("editor/editor_settings", TTR("Editor Settings..."));
ED_SHORTCUT_OVERRIDE("editor/editor_settings", "macos", KeyModifierMask::CMD + Key::COMMA);
- p->add_shortcut(ED_GET_SHORTCUT("editor/editor_settings"), SETTINGS_PREFERENCES);
- p->add_shortcut(ED_SHORTCUT("editor/command_palette", TTR("Command Palette..."), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::P), HELP_COMMAND_PALETTE);
- p->add_separator();
+ settings_menu->add_shortcut(ED_GET_SHORTCUT("editor/editor_settings"), SETTINGS_PREFERENCES);
+ settings_menu->add_shortcut(ED_SHORTCUT("editor/command_palette", TTR("Command Palette..."), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::P), HELP_COMMAND_PALETTE);
+ settings_menu->add_separator();
editor_layouts = memnew(PopupMenu);
editor_layouts->set_name("Layouts");
- p->add_child(editor_layouts);
+ settings_menu->add_child(editor_layouts);
editor_layouts->connect("id_pressed", callable_mp(this, &EditorNode::_layout_menu_option));
- p->add_submenu_item(TTR("Editor Layout"), "Layouts");
- p->add_separator();
+ settings_menu->add_submenu_item(TTR("Editor Layout"), "Layouts");
+ settings_menu->add_separator();
ED_SHORTCUT_AND_COMMAND("editor/take_screenshot", TTR("Take Screenshot"), KeyModifierMask::CTRL | Key::F12);
ED_SHORTCUT_OVERRIDE("editor/take_screenshot", "macos", KeyModifierMask::CMD | Key::F12);
- p->add_shortcut(ED_GET_SHORTCUT("editor/take_screenshot"), EDITOR_SCREENSHOT);
+ settings_menu->add_shortcut(ED_GET_SHORTCUT("editor/take_screenshot"), EDITOR_SCREENSHOT);
- p->set_item_tooltip(-1, TTR("Screenshots are stored in the Editor Data/Settings Folder."));
+ settings_menu->set_item_tooltip(-1, TTR("Screenshots are stored in the Editor Data/Settings Folder."));
ED_SHORTCUT_AND_COMMAND("editor/fullscreen_mode", TTR("Toggle Fullscreen"), KeyModifierMask::SHIFT | Key::F11);
ED_SHORTCUT_OVERRIDE("editor/fullscreen_mode", "macos", KeyModifierMask::CMD | KeyModifierMask::CTRL | Key::F);
- p->add_shortcut(ED_GET_SHORTCUT("editor/fullscreen_mode"), SETTINGS_TOGGLE_FULLSCREEN);
+ settings_menu->add_shortcut(ED_GET_SHORTCUT("editor/fullscreen_mode"), SETTINGS_TOGGLE_FULLSCREEN);
- p->add_separator();
+ settings_menu->add_separator();
if (OS::get_singleton()->get_data_path() == OS::get_singleton()->get_config_path()) {
// Configuration and data folders are located in the same place (Windows/MacOS).
- p->add_item(TTR("Open Editor Data/Settings Folder"), SETTINGS_EDITOR_DATA_FOLDER);
+ settings_menu->add_item(TTR("Open Editor Data/Settings Folder"), SETTINGS_EDITOR_DATA_FOLDER);
} else {
// Separate configuration and data folders (Linux).
- p->add_item(TTR("Open Editor Data Folder"), SETTINGS_EDITOR_DATA_FOLDER);
- p->add_item(TTR("Open Editor Settings Folder"), SETTINGS_EDITOR_CONFIG_FOLDER);
+ settings_menu->add_item(TTR("Open Editor Data Folder"), SETTINGS_EDITOR_DATA_FOLDER);
+ settings_menu->add_item(TTR("Open Editor Settings Folder"), SETTINGS_EDITOR_CONFIG_FOLDER);
}
- p->add_separator();
+ settings_menu->add_separator();
- p->add_item(TTR("Manage Editor Features..."), SETTINGS_MANAGE_FEATURE_PROFILES);
- p->add_item(TTR("Manage Export Templates..."), SETTINGS_MANAGE_EXPORT_TEMPLATES);
+ settings_menu->add_item(TTR("Manage Editor Features..."), SETTINGS_MANAGE_FEATURE_PROFILES);
+ settings_menu->add_item(TTR("Manage Export Templates..."), SETTINGS_MANAGE_EXPORT_TEMPLATES);
- help_menu = memnew(MenuButton);
- help_menu->set_flat(false);
- help_menu->set_switch_on_hover(true);
- help_menu->set_text(TTR("Help"));
- help_menu->add_theme_style_override("hover", gui_base->get_theme_stylebox(SNAME("MenuHover"), SNAME("EditorStyles")));
- left_menu_hb->add_child(help_menu);
+ help_menu = memnew(PopupMenu);
+ help_menu->set_name(TTR("Help"));
+ main_menu->add_child(help_menu);
- p = help_menu->get_popup();
- p->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
+ help_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
ED_SHORTCUT_AND_COMMAND("editor/editor_help", TTR("Search Help"), Key::F1);
ED_SHORTCUT_OVERRIDE("editor/editor_help", "macos", KeyModifierMask::ALT | Key::SPACE);
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("HelpSearch"), SNAME("EditorIcons")), ED_GET_SHORTCUT("editor/editor_help"), HELP_SEARCH);
- p->add_separator();
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/online_docs", TTR("Online Documentation")), HELP_DOCS);
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/q&a", TTR("Questions & Answers")), HELP_QA);
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/report_a_bug", TTR("Report a Bug")), HELP_REPORT_A_BUG);
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/suggest_a_feature", TTR("Suggest a Feature")), HELP_SUGGEST_A_FEATURE);
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/send_docs_feedback", TTR("Send Docs Feedback")), HELP_SEND_DOCS_FEEDBACK);
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/community", TTR("Community")), HELP_COMMUNITY);
- p->add_separator();
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Godot"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/about", TTR("About Godot")), HELP_ABOUT);
- p->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Heart"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/support_development", TTR("Support Godot Development")), HELP_SUPPORT_GODOT_DEVELOPMENT);
+ help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("HelpSearch"), SNAME("EditorIcons")), ED_GET_SHORTCUT("editor/editor_help"), HELP_SEARCH);
+ help_menu->add_separator();
+ help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/online_docs", TTR("Online Documentation")), HELP_DOCS);
+ help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/q&a", TTR("Questions & Answers")), HELP_QA);
+ help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/report_a_bug", TTR("Report a Bug")), HELP_REPORT_A_BUG);
+ help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/suggest_a_feature", TTR("Suggest a Feature")), HELP_SUGGEST_A_FEATURE);
+ help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/send_docs_feedback", TTR("Send Docs Feedback")), HELP_SEND_DOCS_FEEDBACK);
+ help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("ExternalLink"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/community", TTR("Community")), HELP_COMMUNITY);
+ help_menu->add_separator();
+ if (!global_menu || !OS::get_singleton()->has_feature("macos")) {
+ // On macOS "Quit" and "About" options are in the "app" menu.
+ help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Godot"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/about", TTR("About Godot")), HELP_ABOUT);
+ }
+ help_menu->add_icon_shortcut(gui_base->get_theme_icon(SNAME("Heart"), SNAME("EditorIcons")), ED_SHORTCUT_AND_COMMAND("editor/support_development", TTR("Support Godot Development")), HELP_SUPPORT_GODOT_DEVELOPMENT);
+
+ // Spacer to center 2D / 3D / Script buttons.
+ Control *right_spacer = memnew(Control);
+ right_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ menu_hb->add_child(right_spacer);
HBoxContainer *play_hb = memnew(HBoxContainer);
menu_hb->add_child(play_hb);
@@ -6718,10 +6829,8 @@ EditorNode::EditorNode() {
play_button->set_flat(true);
play_hb->add_child(play_button);
play_button->set_toggle_mode(true);
- play_button->set_icon(gui_base->get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons")));
play_button->set_focus_mode(Control::FOCUS_NONE);
play_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY));
- play_button->set_tooltip(TTR("Play the project."));
ED_SHORTCUT_AND_COMMAND("editor/play", TTR("Play"), Key::F5);
ED_SHORTCUT_OVERRIDE("editor/play", "macos", KeyModifierMask::CMD | Key::B);
@@ -6732,7 +6841,7 @@ EditorNode::EditorNode() {
pause_button->set_toggle_mode(true);
pause_button->set_icon(gui_base->get_theme_icon(SNAME("Pause"), SNAME("EditorIcons")));
pause_button->set_focus_mode(Control::FOCUS_NONE);
- pause_button->set_tooltip(TTR("Pause the scene execution for debugging."));
+ pause_button->set_tooltip_text(TTR("Pause the scene execution for debugging."));
pause_button->set_disabled(true);
play_hb->add_child(pause_button);
@@ -6746,7 +6855,7 @@ EditorNode::EditorNode() {
stop_button->set_focus_mode(Control::FOCUS_NONE);
stop_button->set_icon(gui_base->get_theme_icon(SNAME("Stop"), SNAME("EditorIcons")));
stop_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_STOP));
- stop_button->set_tooltip(TTR("Stop the scene."));
+ stop_button->set_tooltip_text(TTR("Stop the scene."));
stop_button->set_disabled(true);
ED_SHORTCUT("editor/stop", TTR("Stop"), Key::F8);
@@ -6762,9 +6871,7 @@ EditorNode::EditorNode() {
play_hb->add_child(play_scene_button);
play_scene_button->set_toggle_mode(true);
play_scene_button->set_focus_mode(Control::FOCUS_NONE);
- play_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayScene"), SNAME("EditorIcons")));
play_scene_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY_SCENE));
- play_scene_button->set_tooltip(TTR("Play the edited scene."));
ED_SHORTCUT_AND_COMMAND("editor/play_scene", TTR("Play Scene"), Key::F6);
ED_SHORTCUT_OVERRIDE("editor/play_scene", "macos", KeyModifierMask::CMD | Key::R);
@@ -6775,9 +6882,9 @@ EditorNode::EditorNode() {
play_hb->add_child(play_custom_scene_button);
play_custom_scene_button->set_toggle_mode(true);
play_custom_scene_button->set_focus_mode(Control::FOCUS_NONE);
- play_custom_scene_button->set_icon(gui_base->get_theme_icon(SNAME("PlayCustom"), SNAME("EditorIcons")));
play_custom_scene_button->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(RUN_PLAY_CUSTOM_SCENE));
- play_custom_scene_button->set_tooltip(TTR("Play custom scene"));
+
+ _reset_play_buttons();
ED_SHORTCUT_AND_COMMAND("editor/play_custom_scene", TTR("Play Custom Scene"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::F5);
ED_SHORTCUT_OVERRIDE("editor/play_custom_scene", "macos", KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::R);
@@ -6790,7 +6897,7 @@ EditorNode::EditorNode() {
write_movie_button->set_pressed(false);
write_movie_button->set_icon(gui_base->get_theme_icon(SNAME("MainMovieWrite"), SNAME("EditorIcons")));
write_movie_button->set_focus_mode(Control::FOCUS_NONE);
- write_movie_button->set_tooltip(TTR("Enable Movie Maker mode.\nThe project will run at stable FPS and the visual and audio output will be recorded to a video file."));
+ write_movie_button->set_tooltip_text(TTR("Enable Movie Maker mode.\nThe project will run at stable FPS and the visual and audio output will be recorded to a video file."));
// This button behaves differently, so color it as such.
write_movie_button->add_theme_color_override("icon_normal_color", Color(1, 1, 1, 0.7));
@@ -6814,6 +6921,14 @@ EditorNode::EditorNode() {
right_menu_hb->add_child(rendering_driver);
+ if (can_expand) {
+ // Add spacer to avoid other controls under the window minimize/maximize/close buttons (right side).
+ Control *menu_spacer = memnew(Control);
+ menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ menu_spacer->set_custom_minimum_size(Size2(DisplayServer::get_singleton()->window_get_safe_title_margins(DisplayServer::MAIN_WINDOW_ID).y, 0));
+ menu_hb->add_child(menu_spacer);
+ }
+
// Only display the render drivers that are available for this display driver.
int display_driver_idx = OS::get_singleton()->get_display_driver_id();
Vector<String> render_drivers = DisplayServer::get_create_function_rendering_drivers(display_driver_idx);
@@ -6858,7 +6973,7 @@ EditorNode::EditorNode() {
right_menu_hb->add_child(update_spinner);
update_spinner->set_icon(gui_base->get_theme_icon(SNAME("Progress1"), SNAME("EditorIcons")));
update_spinner->get_popup()->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
- p = update_spinner->get_popup();
+ PopupMenu *p = update_spinner->get_popup();
p->add_radio_check_item(TTR("Update Continuously"), SETTINGS_UPDATE_CONTINUOUSLY);
p->add_radio_check_item(TTR("Update When Changed"), SETTINGS_UPDATE_WHEN_CHANGED);
p->add_separator();
@@ -6876,6 +6991,7 @@ EditorNode::EditorNode() {
filesystem_dock->connect("inherit", callable_mp(this, &EditorNode::_inherit_request));
filesystem_dock->connect("instance", callable_mp(this, &EditorNode::_instantiate_request));
filesystem_dock->connect("display_mode_changed", callable_mp(this, &EditorNode::_save_docks));
+ get_project_settings()->connect_filesystem_dock_signals(filesystem_dock);
// Scene: Top left.
dock_slot[DOCK_SLOT_LEFT_UR]->add_child(SceneTreeDock::get_singleton());
@@ -6968,7 +7084,7 @@ EditorNode::EditorNode() {
// Fade out the version label to be less prominent, but still readable.
version_btn->set_self_modulate(Color(1, 1, 1, 0.65));
version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER);
- version_btn->set_tooltip(TTR("Click to copy."));
+ version_btn->set_tooltip_text(TTR("Click to copy."));
version_btn->connect("pressed", callable_mp(this, &EditorNode::_version_button_pressed));
version_info_vbc->add_child(version_btn);
@@ -7077,11 +7193,11 @@ EditorNode::EditorNode() {
gui_base->add_child(file_script);
file_script->connect("file_selected", callable_mp(this, &EditorNode::_dialog_action));
- file_menu->get_popup()->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
+ file_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
file_menu->connect("about_to_popup", callable_mp(this, &EditorNode::_update_file_menu_opened));
- file_menu->get_popup()->connect("popup_hide", callable_mp(this, &EditorNode::_update_file_menu_closed));
+ file_menu->connect("popup_hide", callable_mp(this, &EditorNode::_update_file_menu_closed));
- settings_menu->get_popup()->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
+ settings_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
file->connect("file_selected", callable_mp(this, &EditorNode::_dialog_action));
file_templates->connect("file_selected", callable_mp(this, &EditorNode::_dialog_action));
@@ -7192,7 +7308,7 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(NavigationPolygonEditorPlugin));
add_editor_plugin(memnew(Path2DEditorPlugin));
add_editor_plugin(memnew(Polygon2DEditorPlugin));
- add_editor_plugin(memnew(RayCast2DEditorPlugin));
+ add_editor_plugin(memnew(Cast2DEditorPlugin));
add_editor_plugin(memnew(Skeleton2DEditorPlugin));
add_editor_plugin(memnew(Sprite2DEditorPlugin));
add_editor_plugin(memnew(TilesEditorPlugin));
@@ -7229,7 +7345,7 @@ EditorNode::EditorNode() {
canvas_item_mat_convert.instantiate();
resource_conversion_plugins.push_back(canvas_item_mat_convert);
- Ref<ParticlesMaterialConversionPlugin> particles_mat_convert;
+ Ref<ParticleProcessMaterialConversionPlugin> particles_mat_convert;
particles_mat_convert.instantiate();
resource_conversion_plugins.push_back(particles_mat_convert);
@@ -7364,11 +7480,22 @@ EditorNode::EditorNode() {
screenshot_timer = memnew(Timer);
screenshot_timer->set_one_shot(true);
- screenshot_timer->set_wait_time(settings_menu->get_popup()->get_submenu_popup_delay() + 0.1f);
+ screenshot_timer->set_wait_time(settings_menu->get_submenu_popup_delay() + 0.1f);
screenshot_timer->connect("timeout", callable_mp(this, &EditorNode::_request_screenshot));
add_child(screenshot_timer);
screenshot_timer->set_owner(get_owner());
+ // Adjust spacers to center 2D / 3D / Script buttons.
+ int max_w = MAX(play_hb->get_minimum_size().x + right_menu_hb->get_minimum_size().x, main_menu->get_minimum_size().x);
+ left_spacer->set_custom_minimum_size(Size2(MAX(0, max_w - main_menu->get_minimum_size().x), 0));
+ right_spacer->set_custom_minimum_size(Size2(MAX(0, max_w - play_hb->get_minimum_size().x - right_menu_hb->get_minimum_size().x), 0));
+
+ // Extend menu bar to window title.
+ if (can_expand) {
+ DisplayServer::get_singleton()->window_set_flag(DisplayServer::WINDOW_FLAG_EXTEND_TO_TITLE, true, DisplayServer::MAIN_WINDOW_ID);
+ menu_hb->set_can_move_window(true);
+ }
+
String exec = OS::get_singleton()->get_executable_path();
// Save editor executable path for third-party tools.
EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "executable_path", exec);
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 0201e84eaf..792d2fc879 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -35,6 +35,7 @@
#include "editor/editor_folding.h"
#include "editor/editor_native_shader_source_visualizer.h"
#include "editor/editor_run.h"
+#include "editor/editor_title_bar.h"
#include "editor/export/editor_export.h"
#include "editor/inspector_dock.h"
@@ -72,12 +73,14 @@ class EditorRun;
class EditorRunNative;
class EditorSettingsDialog;
class EditorToaster;
+class EditorUndoRedoManager;
class ExportTemplateManager;
class FileDialog;
class FileSystemDock;
class HSplitContainer;
class ImportDock;
class LinkButton;
+class MenuBar;
class MenuButton;
class NodeDock;
class OrphanResourcesDialog;
@@ -141,6 +144,7 @@ private:
FILE_SAVE_AS_SCENE,
FILE_SAVE_ALL_SCENES,
FILE_SAVE_AND_RUN,
+ FILE_SAVE_AND_RUN_MAIN_SCENE,
FILE_SHOW_IN_FILESYSTEM,
FILE_EXPORT_PROJECT,
FILE_EXPORT_MESH_LIBRARY,
@@ -319,13 +323,14 @@ private:
HBoxContainer *bottom_hb = nullptr;
Control *vp_base = nullptr;
- HBoxContainer *menu_hb = nullptr;
+ EditorTitleBar *menu_hb = nullptr;
Control *main_control = nullptr;
- MenuButton *file_menu = nullptr;
- MenuButton *project_menu = nullptr;
- MenuButton *debug_menu = nullptr;
- MenuButton *settings_menu = nullptr;
- MenuButton *help_menu = nullptr;
+ MenuBar *main_menu = nullptr;
+ PopupMenu *file_menu = nullptr;
+ PopupMenu *project_menu = nullptr;
+ PopupMenu *debug_menu = nullptr;
+ PopupMenu *settings_menu = nullptr;
+ PopupMenu *help_menu = nullptr;
PopupMenu *tool_menu = nullptr;
PopupMenu *export_as_menu = nullptr;
Button *export_button = nullptr;
@@ -466,10 +471,9 @@ private:
String _tmp_import_path;
String external_file;
String open_navigate;
- String run_custom_filename;
- uint64_t saved_version = 1;
- uint64_t last_checked_version = 0;
+ String run_custom_filename;
+ String run_current_filename;
DynamicFontImportSettings *fontdata_import_settings = nullptr;
SceneImportSettings *scene_import_settings = nullptr;
@@ -579,6 +583,7 @@ private:
void _run(bool p_current = false, const String &p_custom = "");
void _run_native(const Ref<EditorExportPreset> &p_preset);
+ void _reset_play_buttons();
void _add_to_recent_scenes(const String &p_scene);
void _update_recent_scenes();
@@ -679,6 +684,10 @@ private:
void _bottom_panel_switch(bool p_enable, int p_idx);
void _bottom_panel_raise_toggled(bool);
+ void _begin_first_scan();
+ bool use_startup_benchmark = false;
+ String startup_benchmark_file;
+
protected:
friend class FileSystemDock;
@@ -702,7 +711,7 @@ public:
static EditorLog *get_log() { return singleton->log; }
static EditorData &get_editor_data() { return singleton->editor_data; }
static EditorFolding &get_editor_folding() { return singleton->editor_folding; }
- static UndoRedo *get_undo_redo() { return &singleton->editor_data.get_undo_redo(); }
+ static Ref<EditorUndoRedoManager> &get_undo_redo();
static HBoxContainer *get_menu_hb() { return singleton->menu_hb; }
static VSplitContainer *get_top_split() { return singleton->top_split; }
@@ -771,6 +780,8 @@ public:
void open_request(const String &p_path);
void edit_foreign_resource(Ref<Resource> p_resource);
+ bool is_resource_read_only(Ref<Resource> p_resource);
+
bool is_changing_scene() const;
Control *get_main_control();
@@ -786,7 +797,6 @@ public:
bool is_scene_open(const String &p_path);
- void set_current_version(uint64_t p_version);
void set_current_scene(int p_idx);
void setup_color_picker(ColorPicker *picker);
@@ -813,6 +823,7 @@ public:
void _copy_warning(const String &p_str);
+ void set_use_startup_benchmark(bool p_use_startup_benchmark, const String &p_startup_benchmark_file);
Error export_preset(const String &p_preset, const String &p_path, bool p_debug, bool p_pack_only);
Control *get_gui_base() { return gui_base; }
diff --git a/editor/editor_path.cpp b/editor/editor_path.cpp
index dc77b5fea9..a8f8f7ab97 100644
--- a/editor/editor_path.cpp
+++ b/editor/editor_path.cpp
@@ -72,7 +72,7 @@ void EditorPath::_add_children_to_popup(Object *p_obj, int p_depth) {
int index = sub_objects_menu->get_item_count();
sub_objects_menu->add_icon_item(icon, proper_name, objects.size());
- sub_objects_menu->set_item_horizontal_offset(index, p_depth * 10 * EDSCALE);
+ sub_objects_menu->set_item_indent(index, p_depth);
objects.push_back(obj->get_instance_id());
_add_children_to_popup(obj, p_depth + 1);
@@ -80,6 +80,11 @@ void EditorPath::_add_children_to_popup(Object *p_obj, int p_depth) {
}
void EditorPath::_show_popup() {
+ if (sub_objects_menu->is_visible()) {
+ sub_objects_menu->hide();
+ return;
+ }
+
sub_objects_menu->clear();
Size2 size = get_size();
@@ -145,14 +150,14 @@ void EditorPath::update_path() {
}
current_object_label->set_text(" " + name); // An extra space so the text is not too close of the icon.
- set_tooltip(obj->get_class());
+ set_tooltip_text(obj->get_class());
}
}
}
void EditorPath::clear_path() {
set_disabled(true);
- set_tooltip("");
+ set_tooltip_text("");
current_object_label->set_text("");
current_object_icon->set_texture(nullptr);
@@ -226,5 +231,5 @@ EditorPath::EditorPath(EditorSelectionHistory *p_history) {
sub_objects_menu->connect("about_to_popup", callable_mp(this, &EditorPath::_about_to_show));
sub_objects_menu->connect("id_pressed", callable_mp(this, &EditorPath::_id_pressed));
- set_tooltip(TTR("Open a list of sub-resources."));
+ set_tooltip_text(TTR("Open a list of sub-resources."));
}
diff --git a/editor/editor_paths.cpp b/editor/editor_paths.cpp
index b6364e1ab7..54d4660cb6 100644
--- a/editor/editor_paths.cpp
+++ b/editor/editor_paths.cpp
@@ -67,19 +67,19 @@ String EditorPaths::get_self_contained_file() const {
}
String EditorPaths::get_export_templates_dir() const {
- return get_data_dir().plus_file(export_templates_folder);
+ return get_data_dir().path_join(export_templates_folder);
}
String EditorPaths::get_project_settings_dir() const {
- return get_project_data_dir().plus_file("editor");
+ return get_project_data_dir().path_join("editor");
}
String EditorPaths::get_text_editor_themes_dir() const {
- return get_config_dir().plus_file(text_editor_themes_folder);
+ return get_config_dir().path_join(text_editor_themes_folder);
}
String EditorPaths::get_script_templates_dir() const {
- return get_config_dir().plus_file(script_templates_folder);
+ return get_config_dir().path_join(script_templates_folder);
}
String EditorPaths::get_project_script_templates_dir() const {
@@ -87,7 +87,7 @@ String EditorPaths::get_project_script_templates_dir() const {
}
String EditorPaths::get_feature_profiles_dir() const {
- return get_config_dir().plus_file(feature_profiles_folder);
+ return get_config_dir().path_join(feature_profiles_folder);
}
void EditorPaths::create() {
@@ -119,8 +119,8 @@ EditorPaths::EditorPaths() {
String exe_path = OS::get_singleton()->get_executable_path().get_base_dir();
// On macOS, look outside .app bundle, since .app bundle is read-only.
- if (OS::get_singleton()->has_feature("macos") && exe_path.ends_with("MacOS") && exe_path.plus_file("..").simplify_path().ends_with("Contents")) {
- exe_path = exe_path.plus_file("../../..").simplify_path();
+ if (OS::get_singleton()->has_feature("macos") && exe_path.ends_with("MacOS") && exe_path.path_join("..").simplify_path().ends_with("Contents")) {
+ exe_path = exe_path.path_join("../../..").simplify_path();
}
{
Ref<DirAccess> d = DirAccess::create_for_path(exe_path);
@@ -141,24 +141,24 @@ EditorPaths::EditorPaths() {
if (self_contained) {
// editor is self contained, all in same folder
data_path = exe_path;
- data_dir = data_path.plus_file("editor_data");
+ data_dir = data_path.path_join("editor_data");
config_path = exe_path;
config_dir = data_dir;
cache_path = exe_path;
- cache_dir = data_dir.plus_file("cache");
+ cache_dir = data_dir.path_join("cache");
} else {
// Typically XDG_DATA_HOME or %APPDATA%.
data_path = OS::get_singleton()->get_data_path();
- data_dir = data_path.plus_file(OS::get_singleton()->get_godot_dir_name());
+ data_dir = data_path.path_join(OS::get_singleton()->get_godot_dir_name());
// Can be different from data_path e.g. on Linux or macOS.
config_path = OS::get_singleton()->get_config_path();
- config_dir = config_path.plus_file(OS::get_singleton()->get_godot_dir_name());
+ config_dir = config_path.path_join(OS::get_singleton()->get_godot_dir_name());
// Can be different from above paths, otherwise a subfolder of data_dir.
cache_path = OS::get_singleton()->get_cache_path();
if (cache_path == data_path) {
- cache_dir = data_dir.plus_file("cache");
+ cache_dir = data_dir.path_join("cache");
} else {
- cache_dir = cache_path.plus_file(OS::get_singleton()->get_godot_dir_name());
+ cache_dir = cache_path.path_join(OS::get_singleton()->get_godot_dir_name());
}
}
@@ -232,7 +232,7 @@ EditorPaths::EditorPaths() {
}
// Check that the project data directory '.gdignore' file exists
- String project_data_gdignore_file_path = project_data_dir.plus_file(".gdignore");
+ String project_data_gdignore_file_path = project_data_dir.path_join(".gdignore");
if (!FileAccess::exists(project_data_gdignore_file_path)) {
// Add an empty .gdignore file to avoid scan.
Ref<FileAccess> f = FileAccess::open(project_data_gdignore_file_path, FileAccess::WRITE);
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index 566c22f5a9..b0bd500ef8 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -35,6 +35,7 @@
#include "editor/editor_paths.h"
#include "editor/editor_resource_preview.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/export/editor_export.h"
#include "editor/filesystem_dock.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
@@ -47,7 +48,7 @@
#include "scene/gui/popup_menu.h"
#include "servers/rendering_server.h"
-Array EditorInterface::_make_mesh_previews(const Array &p_meshes, int p_preview_size) {
+TypedArray<Texture2D> EditorInterface::_make_mesh_previews(const Array &p_meshes, int p_preview_size) {
Vector<Ref<Mesh>> meshes;
for (int i = 0; i < p_meshes.size(); i++) {
@@ -55,7 +56,7 @@ Array EditorInterface::_make_mesh_previews(const Array &p_meshes, int p_preview_
}
Vector<Ref<Texture2D>> textures = make_mesh_previews(meshes, nullptr, p_preview_size);
- Array ret;
+ TypedArray<Texture2D> ret;
for (int i = 0; i < textures.size(); i++) {
ret.push_back(textures[i]);
}
@@ -215,8 +216,8 @@ Node *EditorInterface::get_edited_scene_root() {
return EditorNode::get_singleton()->get_edited_scene();
}
-Array EditorInterface::get_open_scenes() const {
- Array ret;
+PackedStringArray EditorInterface::get_open_scenes() const {
+ PackedStringArray ret;
Vector<EditorData::EditedScene> scenes = EditorNode::get_editor_data().get_edited_scenes();
int scns_amount = scenes.size();
@@ -312,6 +313,13 @@ void EditorInterface::set_distraction_free_mode(bool p_enter) {
EditorNode::get_singleton()->set_distraction_free_mode(p_enter);
}
+void EditorInterface::restart_editor(bool p_save) {
+ if (p_save) {
+ EditorNode::get_singleton()->save_all_scenes();
+ }
+ EditorNode::get_singleton()->restart_editor();
+}
+
bool EditorInterface::is_distraction_free_mode_enabled() const {
return EditorNode::get_singleton()->is_distraction_free_mode_enabled();
}
@@ -360,6 +368,7 @@ void EditorInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("save_scene"), &EditorInterface::save_scene);
ClassDB::bind_method(D_METHOD("save_scene_as", "path", "with_preview"), &EditorInterface::save_scene_as, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("restart_editor", "save"), &EditorInterface::restart_editor, DEFVAL(true));
ClassDB::bind_method(D_METHOD("set_main_screen_editor", "name"), &EditorInterface::set_main_screen_editor);
ClassDB::bind_method(D_METHOD("set_distraction_free_mode", "enter"), &EditorInterface::set_distraction_free_mode);
@@ -445,7 +454,7 @@ void EditorPlugin::add_control_to_container(CustomControlContainer p_location, C
CanvasItemEditor::get_singleton()->get_bottom_split()->add_child(p_control);
} break;
- case CONTAINER_PROPERTY_EDITOR_BOTTOM: {
+ case CONTAINER_INSPECTOR_BOTTOM: {
InspectorDock::get_singleton()->get_addon_area()->add_child(p_control);
} break;
@@ -498,7 +507,7 @@ void EditorPlugin::remove_control_from_container(CustomControlContainer p_locati
CanvasItemEditor::get_singleton()->get_bottom_split()->remove_child(p_control);
} break;
- case CONTAINER_PROPERTY_EDITOR_BOTTOM: {
+ case CONTAINER_INSPECTOR_BOTTOM: {
InspectorDock::get_singleton()->get_addon_area()->remove_child(p_control);
} break;
@@ -885,7 +894,7 @@ void EditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("make_bottom_panel_item_visible", "item"), &EditorPlugin::make_bottom_panel_item_visible);
ClassDB::bind_method(D_METHOD("hide_bottom_panel"), &EditorPlugin::hide_bottom_panel);
- ClassDB::bind_method(D_METHOD("get_undo_redo"), &EditorPlugin::_get_undo_redo);
+ ClassDB::bind_method(D_METHOD("get_undo_redo"), &EditorPlugin::get_undo_redo);
ClassDB::bind_method(D_METHOD("add_undo_redo_inspector_hook_callback", "callable"), &EditorPlugin::add_undo_redo_inspector_hook_callback);
ClassDB::bind_method(D_METHOD("remove_undo_redo_inspector_hook_callback", "callable"), &EditorPlugin::remove_undo_redo_inspector_hook_callback);
ClassDB::bind_method(D_METHOD("queue_save_layout"), &EditorPlugin::queue_save_layout);
@@ -950,7 +959,7 @@ void EditorPlugin::_bind_methods() {
BIND_ENUM_CONSTANT(CONTAINER_CANVAS_EDITOR_SIDE_LEFT);
BIND_ENUM_CONSTANT(CONTAINER_CANVAS_EDITOR_SIDE_RIGHT);
BIND_ENUM_CONSTANT(CONTAINER_CANVAS_EDITOR_BOTTOM);
- BIND_ENUM_CONSTANT(CONTAINER_PROPERTY_EDITOR_BOTTOM);
+ BIND_ENUM_CONSTANT(CONTAINER_INSPECTOR_BOTTOM);
BIND_ENUM_CONSTANT(CONTAINER_PROJECT_SETTING_TAB_LEFT);
BIND_ENUM_CONSTANT(CONTAINER_PROJECT_SETTING_TAB_RIGHT);
@@ -965,6 +974,10 @@ void EditorPlugin::_bind_methods() {
BIND_ENUM_CONSTANT(DOCK_SLOT_MAX);
}
+Ref<EditorUndoRedoManager> EditorPlugin::get_undo_redo() {
+ return undo_redo;
+}
+
EditorPluginCreateFunc EditorPlugins::creation_funcs[MAX_CREATE_FUNCS];
int EditorPlugins::creation_func_count = 0;
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index 84c63d1021..8357f0960a 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -53,6 +53,7 @@ class EditorImportPlugin;
class EditorExportPlugin;
class EditorNode3DGizmoPlugin;
class EditorResourcePreview;
+class EditorUndoRedoManager;
class EditorFileSystem;
class EditorToolAddons;
class EditorPaths;
@@ -66,7 +67,7 @@ protected:
static void _bind_methods();
static EditorInterface *singleton;
- Array _make_mesh_previews(const Array &p_meshes, int p_preview_size);
+ TypedArray<Texture2D> _make_mesh_previews(const Array &p_meshes, int p_preview_size);
public:
static EditorInterface *get_singleton() { return singleton; }
@@ -86,7 +87,7 @@ public:
String get_playing_scene() const;
Node *get_edited_scene_root();
- Array get_open_scenes() const;
+ PackedStringArray get_open_scenes() const;
ScriptEditor *get_script_editor();
EditorCommandPalette *get_command_palette() const;
@@ -116,6 +117,7 @@ public:
Error save_scene();
void save_scene_as(const String &p_scene, bool p_with_preview = true);
+ void restart_editor(bool p_save = true);
Vector<Ref<Texture2D>> make_mesh_previews(const Vector<Ref<Mesh>> &p_meshes, Vector<Transform3D> *p_transforms, int p_preview_size);
@@ -129,9 +131,7 @@ public:
class EditorPlugin : public Node {
GDCLASS(EditorPlugin, Node);
friend class EditorData;
- UndoRedo *undo_redo = nullptr;
-
- UndoRedo *_get_undo_redo() { return undo_redo; }
+ Ref<EditorUndoRedoManager> undo_redo;
bool input_event_forwarding_always_enabled = false;
bool force_draw_over_forwarding_enabled = false;
@@ -144,7 +144,7 @@ protected:
void _notification(int p_what);
static void _bind_methods();
- UndoRedo &get_undo_redo() { return *undo_redo; }
+ Ref<EditorUndoRedoManager> get_undo_redo();
void add_custom_type(const String &p_type, const String &p_base, const Ref<Script> &p_script, const Ref<Texture2D> &p_icon);
void remove_custom_type(const String &p_type);
@@ -184,7 +184,7 @@ public:
CONTAINER_CANVAS_EDITOR_SIDE_LEFT,
CONTAINER_CANVAS_EDITOR_SIDE_RIGHT,
CONTAINER_CANVAS_EDITOR_BOTTOM,
- CONTAINER_PROPERTY_EDITOR_BOTTOM,
+ CONTAINER_INSPECTOR_BOTTOM,
CONTAINER_PROJECT_SETTING_TAB_LEFT,
CONTAINER_PROJECT_SETTING_TAB_RIGHT,
};
diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp
index 5a010a66c1..e5a5a372ad 100644
--- a/editor/editor_plugin_settings.cpp
+++ b/editor/editor_plugin_settings.cpp
@@ -178,8 +178,8 @@ Vector<String> EditorPluginSettings::_get_plugins(const String &p_dir) {
continue;
}
- const String full_path = p_dir.plus_file(path);
- const String plugin_config = full_path.plus_file("plugin.cfg");
+ const String full_path = p_dir.path_join(path);
+ const String plugin_config = full_path.path_join("plugin.cfg");
if (FileAccess::exists(plugin_config)) {
plugins.push_back(plugin_config);
} else {
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 09c55d5d24..0e69c0e2f4 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -99,6 +99,10 @@ void EditorPropertyText::set_string_name(bool p_enabled) {
string_name = p_enabled;
}
+void EditorPropertyText::set_secret(bool p_enabled) {
+ text->set_secret(p_enabled);
+}
+
void EditorPropertyText::set_placeholder(const String &p_string) {
text->set_placeholder(p_string);
}
@@ -133,6 +137,11 @@ void EditorPropertyMultilineText::_text_changed() {
void EditorPropertyMultilineText::_open_big_text() {
if (!big_text_dialog) {
big_text = memnew(TextEdit);
+ if (expression) {
+ big_text->set_syntax_highlighter(text->get_syntax_highlighter());
+ big_text->add_theme_font_override("font", get_theme_font(SNAME("expression"), SNAME("EditorFonts")));
+ big_text->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("expression_size"), SNAME("EditorFonts")));
+ }
big_text->connect("text_changed", callable_mp(this, &EditorPropertyMultilineText::_big_text_changed));
big_text->set_line_wrapping_mode(TextEdit::LineWrappingMode::LINE_WRAPPING_BOUNDARY);
big_text_dialog = memnew(AcceptDialog);
@@ -162,12 +171,24 @@ void EditorPropertyMultilineText::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
Ref<Texture2D> df = get_theme_icon(SNAME("DistractionFree"), SNAME("EditorIcons"));
open_big_text->set_icon(df);
- Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
- int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label"));
- text->set_custom_minimum_size(Vector2(0, font->get_height(font_size) * 6));
- text->add_theme_font_override("font", get_theme_font("expression", "EditorFonts"));
- text->add_theme_font_size_override("font_size", get_theme_font_size("expression_size", "EditorFonts"));
+ Ref<Font> font;
+ int font_size;
+ if (expression) {
+ font = get_theme_font(SNAME("expression"), SNAME("EditorFonts"));
+ font_size = get_theme_font_size(SNAME("expression_size"), SNAME("EditorFonts"));
+
+ text->add_theme_font_override("font", font);
+ text->add_theme_font_size_override("font_size", font_size);
+ if (big_text) {
+ big_text->add_theme_font_override("font", font);
+ big_text->add_theme_font_size_override("font_size", font_size);
+ }
+ } else {
+ font = get_theme_font(SNAME("font"), SNAME("TextEdit"));
+ font_size = get_theme_font_size(SNAME("font_size"), SNAME("TextEdit"));
+ }
+ text->set_custom_minimum_size(Vector2(0, font->get_height(font_size) * 6));
} break;
}
}
@@ -375,7 +396,7 @@ void EditorPropertyLocale::_locale_pressed() {
void EditorPropertyLocale::update_property() {
String locale_code = get_edited_object()->get(get_edited_property());
locale->set_text(locale_code);
- locale->set_tooltip(locale_code);
+ locale->set_tooltip_text(locale_code);
}
void EditorPropertyLocale::setup(const String &p_hint_text) {
@@ -464,7 +485,7 @@ void EditorPropertyPath::_path_pressed() {
void EditorPropertyPath::update_property() {
String full_path = get_edited_object()->get(get_edited_property());
path->set_text(full_path);
- path->set_tooltip(full_path);
+ path->set_tooltip_text(full_path);
}
void EditorPropertyPath::setup(const Vector<String> &p_extensions, bool p_folder, bool p_global) {
@@ -490,13 +511,55 @@ void EditorPropertyPath::_path_focus_exited() {
_path_selected(path->get_text());
}
+void EditorPropertyPath::_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
+ const Dictionary drag_data = p_data;
+ if (!drag_data.has("type")) {
+ return;
+ }
+ if (String(drag_data["type"]) != "files") {
+ return;
+ }
+ const Vector<String> filesPaths = drag_data["files"];
+ if (filesPaths.size() == 0) {
+ return;
+ }
+
+ emit_changed(get_edited_property(), filesPaths[0]);
+ update_property();
+}
+
+bool EditorPropertyPath::_can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+ const Dictionary drag_data = p_data;
+ if (!drag_data.has("type")) {
+ return false;
+ }
+ if (String(drag_data["type"]) != "files") {
+ return false;
+ }
+ const Vector<String> filesPaths = drag_data["files"];
+ if (filesPaths.size() == 0) {
+ return false;
+ }
+
+ for (const String &extension : extensions) {
+ if (filesPaths[0].ends_with(extension.substr(1, extension.size() - 1))) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void EditorPropertyPath::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "position", "data", "from"), &EditorPropertyPath::_can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_drop_data_fw", "position", "data", "from"), &EditorPropertyPath::_drop_data_fw);
}
EditorPropertyPath::EditorPropertyPath() {
HBoxContainer *path_hb = memnew(HBoxContainer);
add_child(path_hb);
path = memnew(LineEdit);
+ path->set_drag_forwarding(this);
path->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE);
path_hb->add_child(path);
path->connect("text_submitted", callable_mp(this, &EditorPropertyPath::_path_selected));
@@ -1088,6 +1151,17 @@ void EditorPropertyLayersGrid::_bind_methods() {
ADD_SIGNAL(MethodInfo("rename_confirmed", PropertyInfo(Variant::INT, "layer_id"), PropertyInfo(Variant::STRING, "new_name")));
}
+void EditorPropertyLayers::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ button->set_normal_texture(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
+ button->set_pressed_texture(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
+ button->set_disabled_texture(get_theme_icon(SNAME("GuiTabMenu"), SNAME("EditorIcons")));
+ } break;
+ }
+}
+
void EditorPropertyLayers::_set_read_only(bool p_read_only) {
button->set_disabled(p_read_only);
grid->set_read_only(p_read_only);
@@ -1224,9 +1298,9 @@ EditorPropertyLayers::EditorPropertyLayers() {
grid->set_h_size_flags(SIZE_EXPAND_FILL);
hb->add_child(grid);
- button = memnew(Button);
+ button = memnew(TextureButton);
+ button->set_stretch_mode(TextureButton::STRETCH_KEEP_CENTERED);
button->set_toggle_mode(true);
- button->set_text("...");
button->connect("pressed", callable_mp(this, &EditorPropertyLayers::_button_pressed));
hb->add_child(button);
@@ -1388,7 +1462,7 @@ void EditorPropertyFloat::_value_changed(double val) {
}
if (angle_in_radians) {
- val = Math::deg2rad(val);
+ val = Math::deg_to_rad(val);
}
emit_changed(get_edited_property(), val);
}
@@ -1396,7 +1470,7 @@ void EditorPropertyFloat::_value_changed(double val) {
void EditorPropertyFloat::update_property() {
double val = get_edited_object()->get(get_edited_property());
if (angle_in_radians) {
- val = Math::rad2deg(val);
+ val = Math::rad_to_deg(val);
}
setting = true;
spin->set_value(val);
@@ -1580,6 +1654,11 @@ void EditorPropertyEasing::_spin_value_changed(double p_value) {
// which can cause crashes and other issues.
p_value = CLAMP(p_value, -1'000'000, 1'000'000);
+ if (positive_only) {
+ // Force a positive or zero value if a negative value was manually entered by double-clicking.
+ p_value = MAX(0.0, p_value);
+ }
+
emit_changed(get_edited_property(), p_value);
_spin_focus_exited();
}
@@ -1591,9 +1670,9 @@ void EditorPropertyEasing::_spin_focus_exited() {
easing_draw->update();
}
-void EditorPropertyEasing::setup(bool p_full, bool p_flip) {
+void EditorPropertyEasing::setup(bool p_positive_only, bool p_flip) {
flip = p_flip;
- full = p_full;
+ positive_only = p_positive_only;
}
void EditorPropertyEasing::_notification(int p_what) {
@@ -1601,13 +1680,13 @@ void EditorPropertyEasing::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED:
case NOTIFICATION_ENTER_TREE: {
preset->clear();
- preset->add_icon_item(get_theme_icon(SNAME("CurveConstant"), SNAME("EditorIcons")), "Zero", EASING_ZERO);
preset->add_icon_item(get_theme_icon(SNAME("CurveLinear"), SNAME("EditorIcons")), "Linear", EASING_LINEAR);
- preset->add_icon_item(get_theme_icon(SNAME("CurveIn"), SNAME("EditorIcons")), "In", EASING_IN);
- preset->add_icon_item(get_theme_icon(SNAME("CurveOut"), SNAME("EditorIcons")), "Out", EASING_OUT);
- if (full) {
- preset->add_icon_item(get_theme_icon(SNAME("CurveInOut"), SNAME("EditorIcons")), "In-Out", EASING_IN_OUT);
- preset->add_icon_item(get_theme_icon(SNAME("CurveOutIn"), SNAME("EditorIcons")), "Out-In", EASING_OUT_IN);
+ preset->add_icon_item(get_theme_icon(SNAME("CurveIn"), SNAME("EditorIcons")), "Ease In", EASING_IN);
+ preset->add_icon_item(get_theme_icon(SNAME("CurveOut"), SNAME("EditorIcons")), "Ease Out", EASING_OUT);
+ preset->add_icon_item(get_theme_icon(SNAME("CurveConstant"), SNAME("EditorIcons")), "Zero", EASING_ZERO);
+ if (!positive_only) {
+ preset->add_icon_item(get_theme_icon(SNAME("CurveInOut"), SNAME("EditorIcons")), "Ease In-Out", EASING_IN_OUT);
+ preset->add_icon_item(get_theme_icon(SNAME("CurveOutIn"), SNAME("EditorIcons")), "Ease Out-In", EASING_OUT_IN);
}
easing_draw->set_custom_minimum_size(Size2(0, get_theme_font(SNAME("font"), SNAME("Label"))->get_height(get_theme_font_size(SNAME("font_size"), SNAME("Label"))) * 2));
} break;
@@ -1913,9 +1992,9 @@ void EditorPropertyVector3::_value_changed(double val, const String &p_name) {
v3.y = spin[1]->get_value();
v3.z = spin[2]->get_value();
if (angle_in_radians) {
- v3.x = Math::deg2rad(v3.x);
- v3.y = Math::deg2rad(v3.y);
- v3.z = Math::deg2rad(v3.z);
+ v3.x = Math::deg_to_rad(v3.x);
+ v3.y = Math::deg_to_rad(v3.y);
+ v3.z = Math::deg_to_rad(v3.z);
}
emit_changed(get_edited_property(), v3, p_name);
}
@@ -1947,9 +2026,9 @@ void EditorPropertyVector3::_update_ratio() {
void EditorPropertyVector3::update_using_vector(Vector3 p_vector) {
if (angle_in_radians) {
- p_vector.x = Math::rad2deg(p_vector.x);
- p_vector.y = Math::rad2deg(p_vector.y);
- p_vector.z = Math::rad2deg(p_vector.z);
+ p_vector.x = Math::rad_to_deg(p_vector.x);
+ p_vector.y = Math::rad_to_deg(p_vector.y);
+ p_vector.z = Math::rad_to_deg(p_vector.z);
}
setting = true;
spin[0]->set_value(p_vector.x);
@@ -1964,9 +2043,9 @@ Vector3 EditorPropertyVector3::get_vector() {
v3.y = spin[1]->get_value();
v3.z = spin[2]->get_value();
if (angle_in_radians) {
- v3.x = Math::deg2rad(v3.x);
- v3.y = Math::deg2rad(v3.y);
- v3.z = Math::deg2rad(v3.z);
+ v3.x = Math::deg_to_rad(v3.x);
+ v3.y = Math::deg_to_rad(v3.y);
+ v3.z = Math::deg_to_rad(v3.z);
}
return v3;
@@ -2538,8 +2617,47 @@ void EditorPropertyQuaternion::_set_read_only(bool p_read_only) {
for (int i = 0; i < 4; i++) {
spin[i]->set_read_only(p_read_only);
}
+ for (int i = 0; i < 3; i++) {
+ euler[i]->set_read_only(p_read_only);
+ }
};
+void EditorPropertyQuaternion::_edit_custom_value() {
+ if (edit_button->is_pressed()) {
+ edit_custom_bc->show();
+ for (int i = 0; i < 3; i++) {
+ euler[i]->grab_focus();
+ }
+ } else {
+ edit_custom_bc->hide();
+ for (int i = 0; i < 4; i++) {
+ spin[i]->grab_focus();
+ }
+ }
+ update_property();
+}
+
+void EditorPropertyQuaternion::_custom_value_changed(double val) {
+ if (setting) {
+ return;
+ }
+
+ edit_euler.x = euler[0]->get_value();
+ edit_euler.y = euler[1]->get_value();
+ edit_euler.z = euler[2]->get_value();
+
+ Vector3 v;
+ v.x = Math::deg_to_rad(edit_euler.x);
+ v.y = Math::deg_to_rad(edit_euler.y);
+ v.z = Math::deg_to_rad(edit_euler.z);
+
+ Quaternion temp_q = Quaternion(v);
+ spin[0]->set_value(temp_q.x);
+ spin[1]->set_value(temp_q.y);
+ spin[2]->set_value(temp_q.z);
+ spin[3]->set_value(temp_q.w);
+}
+
void EditorPropertyQuaternion::_value_changed(double val, const String &p_name) {
if (setting) {
return;
@@ -2550,9 +2668,18 @@ void EditorPropertyQuaternion::_value_changed(double val, const String &p_name)
p.y = spin[1]->get_value();
p.z = spin[2]->get_value();
p.w = spin[3]->get_value();
+
emit_changed(get_edited_property(), p, p_name);
}
+bool EditorPropertyQuaternion::is_grabbing_euler() {
+ bool is_grabbing = false;
+ for (int i = 0; i < 3; i++) {
+ is_grabbing |= euler[i]->is_grabbing();
+ }
+ return is_grabbing;
+}
+
void EditorPropertyQuaternion::update_property() {
Quaternion val = get_edited_object()->get(get_edited_property());
setting = true;
@@ -2560,9 +2687,22 @@ void EditorPropertyQuaternion::update_property() {
spin[1]->set_value(val.y);
spin[2]->set_value(val.z);
spin[3]->set_value(val.w);
+ if (!is_grabbing_euler()) {
+ Vector3 v = val.normalized().get_euler_yxz();
+ edit_euler.x = Math::rad_to_deg(v.x);
+ edit_euler.y = Math::rad_to_deg(v.y);
+ edit_euler.z = Math::rad_to_deg(v.z);
+ euler[0]->set_value(edit_euler.x);
+ euler[1]->set_value(edit_euler.y);
+ euler[2]->set_value(edit_euler.z);
+ }
setting = false;
}
+void EditorPropertyQuaternion::_warning_pressed() {
+ warning_dialog->popup_centered();
+}
+
void EditorPropertyQuaternion::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
@@ -2571,6 +2711,13 @@ void EditorPropertyQuaternion::_notification(int p_what) {
for (int i = 0; i < 4; i++) {
spin[i]->add_theme_color_override("label_color", colors[i]);
}
+ for (int i = 0; i < 3; i++) {
+ euler[i]->add_theme_color_override("label_color", colors[i]);
+ }
+ edit_button->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
+ euler_label->add_theme_color_override(SNAME("font_color"), get_theme_color(SNAME("property_color"), SNAME("Editor")));
+ warning->set_icon(get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons")));
+ warning->add_theme_color_override(SNAME("font_color"), get_theme_color(SNAME("warning_color"), SNAME("Editor")));
} break;
}
}
@@ -2578,7 +2725,7 @@ void EditorPropertyQuaternion::_notification(int p_what) {
void EditorPropertyQuaternion::_bind_methods() {
}
-void EditorPropertyQuaternion::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix) {
+void EditorPropertyQuaternion::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix, bool p_hide_editor) {
for (int i = 0; i < 4; i++) {
spin[i]->set_min(p_min);
spin[i]->set_max(p_max);
@@ -2590,28 +2737,50 @@ void EditorPropertyQuaternion::setup(double p_min, double p_max, double p_step,
// a generic way to store 4 values, so we'll still respect the suffix.
spin[i]->set_suffix(p_suffix);
}
+
+ for (int i = 0; i < 3; i++) {
+ euler[i]->set_min(-360);
+ euler[i]->set_max(360);
+ euler[i]->set_step(0.1);
+ euler[i]->set_hide_slider(false);
+ euler[i]->set_allow_greater(true);
+ euler[i]->set_allow_lesser(true);
+ euler[i]->set_suffix(U"\u00B0");
+ }
+
+ if (p_hide_editor) {
+ edit_button->hide();
+ }
}
EditorPropertyQuaternion::EditorPropertyQuaternion() {
bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector_types_editing");
- BoxContainer *bc;
-
+ VBoxContainer *bc = memnew(VBoxContainer);
+ edit_custom_bc = memnew(VBoxContainer);
+ BoxContainer *edit_custom_layout;
if (horizontal) {
- bc = memnew(HBoxContainer);
- add_child(bc);
+ default_layout = memnew(HBoxContainer);
+ edit_custom_layout = memnew(HBoxContainer);
set_bottom_editor(bc);
} else {
- bc = memnew(VBoxContainer);
- add_child(bc);
+ default_layout = memnew(VBoxContainer);
+ edit_custom_layout = memnew(VBoxContainer);
}
+ edit_custom_bc->hide();
+ add_child(bc);
+ edit_custom_bc->set_h_size_flags(SIZE_EXPAND_FILL);
+ default_layout->set_h_size_flags(SIZE_EXPAND_FILL);
+ edit_custom_layout->set_h_size_flags(SIZE_EXPAND_FILL);
+ bc->add_child(default_layout);
+ bc->add_child(edit_custom_bc);
static const char *desc[4] = { "x", "y", "z", "w" };
for (int i = 0; i < 4; i++) {
spin[i] = memnew(EditorSpinSlider);
spin[i]->set_flat(true);
spin[i]->set_label(desc[i]);
- bc->add_child(spin[i]);
+ default_layout->add_child(spin[i]);
add_focusable(spin[i]);
spin[i]->connect("value_changed", callable_mp(this, &EditorPropertyQuaternion::_value_changed).bind(desc[i]));
if (horizontal) {
@@ -2619,6 +2788,41 @@ EditorPropertyQuaternion::EditorPropertyQuaternion() {
}
}
+ warning = memnew(Button);
+ warning->set_text(TTR("Temporary Euler may be changed implicitly!"));
+ warning->set_clip_text(true);
+ warning->connect("pressed", callable_mp(this, &EditorPropertyQuaternion::_warning_pressed));
+ warning_dialog = memnew(AcceptDialog);
+ add_child(warning_dialog);
+ warning_dialog->set_text(TTR("Temporary Euler will not be stored in the object with the original value. Instead, it will be stored as Quaternion with irreversible conversion.\nThis is due to the fact that the result of Euler->Quaternion can be determined uniquely, but the result of Quaternion->Euler can be multi-existent."));
+
+ euler_label = memnew(Label);
+ euler_label->set_text("Temporary Euler");
+
+ edit_custom_bc->add_child(warning);
+ edit_custom_bc->add_child(edit_custom_layout);
+ edit_custom_layout->add_child(euler_label);
+
+ for (int i = 0; i < 3; i++) {
+ euler[i] = memnew(EditorSpinSlider);
+ euler[i]->set_flat(true);
+ euler[i]->set_label(desc[i]);
+ edit_custom_layout->add_child(euler[i]);
+ add_focusable(euler[i]);
+ euler[i]->connect("value_changed", callable_mp(this, &EditorPropertyQuaternion::_custom_value_changed));
+ if (horizontal) {
+ euler[i]->set_h_size_flags(SIZE_EXPAND_FILL);
+ }
+ }
+
+ edit_button = memnew(Button);
+ edit_button->set_flat(true);
+ edit_button->set_toggle_mode(true);
+ default_layout->add_child(edit_button);
+ edit_button->connect("pressed", callable_mp(this, &EditorPropertyQuaternion::_edit_custom_value));
+
+ add_focusable(edit_button);
+
if (!horizontal) {
set_label_reference(spin[0]); //show text and buttons around this
}
@@ -3311,14 +3515,14 @@ void EditorPropertyColor::update_property() {
// Add a tooltip to display each channel's values without having to click the ColorPickerButton
if (picker->is_editing_alpha()) {
- picker->set_tooltip(vformat(
+ picker->set_tooltip_text(vformat(
"R: %s\nG: %s\nB: %s\nA: %s",
rtos(color.r).pad_decimals(2),
rtos(color.g).pad_decimals(2),
rtos(color.b).pad_decimals(2),
rtos(color.a).pad_decimals(2)));
} else {
- picker->set_tooltip(vformat(
+ picker->set_tooltip_text(vformat(
"R: %s\nG: %s\nB: %s",
rtos(color.r).pad_decimals(2),
rtos(color.g).pad_decimals(2),
@@ -3476,7 +3680,7 @@ void EditorPropertyNodePath::update_property() {
p = get_edited_object()->get(get_edited_property());
}
- assign->set_tooltip(p);
+ assign->set_tooltip_text(p);
if (p == NodePath()) {
assign->set_icon(Ref<Texture2D>());
assign->set_text(TTR("Assign..."));
@@ -3578,20 +3782,24 @@ void EditorPropertyResource::_set_read_only(bool p_read_only) {
resource_picker->set_editable(!p_read_only);
};
-void EditorPropertyResource::_resource_selected(const Ref<Resource> &p_resource, bool p_edit) {
+void EditorPropertyResource::_resource_selected(const Ref<Resource> &p_resource, bool p_inspect) {
if (p_resource->is_built_in() && !p_resource->get_path().is_empty()) {
String parent = p_resource->get_path().get_slice("::", 0);
List<String> extensions;
ResourceLoader::get_recognized_extensions_for_type("PackedScene", &extensions);
- if (extensions.find(parent.get_extension()) && (!EditorNode::get_singleton()->get_edited_scene() || EditorNode::get_singleton()->get_edited_scene()->get_scene_file_path() != parent)) {
- // If the resource belongs to another scene, edit it in that scene instead.
- EditorNode::get_singleton()->call_deferred("edit_foreign_resource", p_resource);
- return;
+ if (p_inspect) {
+ if (extensions.find(parent.get_extension()) && (!EditorNode::get_singleton()->get_edited_scene() || EditorNode::get_singleton()->get_edited_scene()->get_scene_file_path() != parent)) {
+ // If the resource belongs to another (non-imported) scene, edit it in that scene instead.
+ if (!FileAccess::exists(parent + ".import")) {
+ EditorNode::get_singleton()->call_deferred("edit_foreign_resource", p_resource);
+ return;
+ }
+ }
}
}
- if (!p_edit && use_sub_inspector) {
+ if (!p_inspect && use_sub_inspector) {
bool unfold = !get_edited_object()->editor_is_section_unfolded(get_edited_property());
get_edited_object()->editor_set_section_unfold(get_edited_property(), unfold);
update_property();
@@ -4105,20 +4313,20 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
case Variant::FLOAT: {
if (p_hint == PROPERTY_HINT_EXP_EASING) {
EditorPropertyEasing *editor = memnew(EditorPropertyEasing);
- bool full = true;
+ bool positive_only = false;
bool flip = false;
- Vector<String> hints = p_hint_text.split(",");
+ const Vector<String> hints = p_hint_text.split(",");
for (int i = 0; i < hints.size(); i++) {
- String h = hints[i].strip_edges();
- if (h == "attenuation") {
+ const String hint = hints[i].strip_edges();
+ if (hint == "attenuation") {
flip = true;
}
- if (h == "inout") {
- full = true;
+ if (hint == "positive_only") {
+ positive_only = true;
}
}
- editor->setup(full, flip);
+ editor->setup(positive_only, flip);
return editor;
} else {
@@ -4204,6 +4412,9 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
EditorPropertyText *editor = memnew(EditorPropertyText);
if (p_hint == PROPERTY_HINT_PLACEHOLDER_TEXT) {
editor->set_placeholder(p_hint_text);
+ } else if (p_hint == PROPERTY_HINT_PASSWORD) {
+ editor->set_secret(true);
+ editor->set_placeholder(p_hint_text);
}
return editor;
}
@@ -4282,7 +4493,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
case Variant::QUATERNION: {
EditorPropertyQuaternion *editor = memnew(EditorPropertyQuaternion);
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step);
- editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.suffix);
+ editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.suffix, p_hint == PROPERTY_HINT_HIDE_QUATERNION_EDIT);
return editor;
} break;
case Variant::AABB: {
@@ -4328,6 +4539,9 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
EditorPropertyText *editor = memnew(EditorPropertyText);
if (p_hint == PROPERTY_HINT_PLACEHOLDER_TEXT) {
editor->set_placeholder(p_hint_text);
+ } else if (p_hint == PROPERTY_HINT_PASSWORD) {
+ editor->set_secret(true);
+ editor->set_placeholder(p_hint_text);
}
editor->set_string_name(true);
return editor;
diff --git a/editor/editor_properties.h b/editor/editor_properties.h
index cfe0c2f38c..d6c9510634 100644
--- a/editor/editor_properties.h
+++ b/editor/editor_properties.h
@@ -67,6 +67,7 @@ public:
void set_string_name(bool p_enabled);
virtual void update_property() override;
void set_placeholder(const String &p_string);
+ void set_secret(bool p_enabled);
EditorPropertyText();
};
@@ -142,6 +143,8 @@ class EditorPropertyPath : public EditorProperty {
void _path_selected(const String &p_path);
void _path_pressed();
void _path_focus_exited();
+ void _drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
+ bool _can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
protected:
virtual void _set_read_only(bool p_read_only) override;
@@ -340,13 +343,14 @@ private:
String basename;
LayerType layer_type;
PopupMenu *layers = nullptr;
- Button *button = nullptr;
+ TextureButton *button = nullptr;
void _button_pressed();
void _menu_pressed(int p_menu);
void _refresh_names();
protected:
+ void _notification(int p_what);
virtual void _set_read_only(bool p_read_only) override;
static void _bind_methods();
@@ -443,6 +447,7 @@ class EditorPropertyEasing : public EditorProperty {
bool dragging = false;
bool full = false;
bool flip = false;
+ bool positive_only = false;
enum {
EASING_ZERO,
@@ -471,7 +476,7 @@ protected:
public:
virtual void update_property() override;
- void setup(bool p_full, bool p_flip);
+ void setup(bool p_positive_only, bool p_flip);
EditorPropertyEasing();
};
@@ -621,9 +626,26 @@ public:
class EditorPropertyQuaternion : public EditorProperty {
GDCLASS(EditorPropertyQuaternion, EditorProperty);
+ BoxContainer *default_layout = nullptr;
EditorSpinSlider *spin[4];
bool setting = false;
+
+ Button *warning = nullptr;
+ AcceptDialog *warning_dialog = nullptr;
+
+ Label *euler_label = nullptr;
+ VBoxContainer *edit_custom_bc = nullptr;
+ EditorSpinSlider *euler[3];
+ Button *edit_button = nullptr;
+
+ Vector3 edit_euler = Vector3();
+
void _value_changed(double p_val, const String &p_name);
+ void _edit_custom_value();
+ void _custom_value_changed(double p_val);
+ void _warning_pressed();
+
+ bool is_grabbing_euler();
protected:
virtual void _set_read_only(bool p_read_only) override;
@@ -632,7 +654,7 @@ protected:
public:
virtual void update_property() override;
- void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String());
+ void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String(), bool p_hide_editor = false);
EditorPropertyQuaternion();
};
@@ -831,7 +853,7 @@ class EditorPropertyResource : public EditorProperty {
bool updating_theme = false;
bool opened_editor = false;
- void _resource_selected(const Ref<Resource> &p_resource, bool p_edit);
+ void _resource_selected(const Ref<Resource> &p_resource, bool p_inspect);
void _resource_changed(const Ref<Resource> &p_resource);
void _viewport_selected(const NodePath &p_path);
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index 9a83082d1e..f6953e8866 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -1111,7 +1111,7 @@ void EditorPropertyDictionary::update_property() {
if (i < amount) {
String cs = key.get_construct_string();
prop->set_label(key.get_construct_string());
- prop->set_tooltip(cs);
+ prop->set_tooltip_text(cs);
change_index = i + offset;
} else if (i == amount) {
prop->set_label(TTR("New Key:"));
@@ -1361,7 +1361,7 @@ void EditorPropertyLocalizableString::update_property() {
String cs = key.get_construct_string();
prop->set_label(cs);
- prop->set_tooltip(cs);
+ prop->set_tooltip_text(cs);
remove_index = i + offset;
prop->set_selectable(false);
diff --git a/editor/editor_property_name_processor.cpp b/editor/editor_property_name_processor.cpp
index 09d2992e07..a2dfa4f80e 100644
--- a/editor/editor_property_name_processor.cpp
+++ b/editor/editor_property_name_processor.cpp
@@ -106,6 +106,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["aabb"] = "AABB";
capitalize_string_remaps["adb"] = "ADB";
capitalize_string_remaps["ao"] = "AO";
+ capitalize_string_remaps["api"] = "API";
capitalize_string_remaps["apk"] = "APK";
capitalize_string_remaps["arm64-v8a"] = "arm64-v8a";
capitalize_string_remaps["armeabi-v7a"] = "armeabi-v7a";
@@ -114,6 +115,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["bidi"] = "BiDi";
capitalize_string_remaps["bp"] = "BP";
capitalize_string_remaps["bpc"] = "BPC";
+ capitalize_string_remaps["bpm"] = "BPM";
capitalize_string_remaps["bptc"] = "BPTC";
capitalize_string_remaps["bvh"] = "BVH";
capitalize_string_remaps["ca"] = "CA";
@@ -171,6 +173,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["k1"] = "K1";
capitalize_string_remaps["k2"] = "K2";
capitalize_string_remaps["kb"] = "(KB)"; // Unit.
+ capitalize_string_remaps["lcd"] = "LCD";
capitalize_string_remaps["ldr"] = "LDR";
capitalize_string_remaps["lod"] = "LOD";
capitalize_string_remaps["lowpass"] = "Low-pass";
@@ -189,11 +192,14 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["opengl"] = "OpenGL";
capitalize_string_remaps["opentype"] = "OpenType";
capitalize_string_remaps["openxr"] = "OpenXR";
+ capitalize_string_remaps["osslsigncode"] = "osslsigncode";
capitalize_string_remaps["pck"] = "PCK";
capitalize_string_remaps["png"] = "PNG";
capitalize_string_remaps["po2"] = "(Power of 2)"; // Unit.
capitalize_string_remaps["pvrtc"] = "PVRTC";
capitalize_string_remaps["pvs"] = "PVS";
+ capitalize_string_remaps["rcedit"] = "rcedit";
+ capitalize_string_remaps["rcodesign"] = "rcodesign";
capitalize_string_remaps["rgb"] = "RGB";
capitalize_string_remaps["rid"] = "RID";
capitalize_string_remaps["rmb"] = "RMB";
@@ -203,6 +209,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["sdfgi"] = "SDFGI";
capitalize_string_remaps["sdk"] = "SDK";
capitalize_string_remaps["sec"] = "(sec)"; // Unit.
+ capitalize_string_remaps["signtool"] = "signtool";
capitalize_string_remaps["sms"] = "SMS";
capitalize_string_remaps["srgb"] = "sRGB";
capitalize_string_remaps["ssao"] = "SSAO";
@@ -235,6 +242,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["webp"] = "WebP";
capitalize_string_remaps["webrtc"] = "WebRTC";
capitalize_string_remaps["websocket"] = "WebSocket";
+ capitalize_string_remaps["wine"] = "wine";
capitalize_string_remaps["wifi"] = "Wi-Fi";
capitalize_string_remaps["x86"] = "x86";
capitalize_string_remaps["xr"] = "XR";
diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp
index d850773a6d..ce05026696 100644
--- a/editor/editor_resource_picker.cpp
+++ b/editor/editor_resource_picker.cpp
@@ -62,7 +62,7 @@ void EditorResourcePicker::_update_resource() {
if (edited_resource == Ref<Resource>()) {
assign_button->set_icon(Ref<Texture2D>());
assign_button->set_text(TTR("[empty]"));
- assign_button->set_tooltip("");
+ assign_button->set_tooltip_text("");
} else {
assign_button->set_icon(EditorNode::get_singleton()->get_object_icon(edited_resource.operator->(), "Object"));
@@ -73,14 +73,16 @@ void EditorResourcePicker::_update_resource() {
} else {
assign_button->set_text(edited_resource->get_class());
}
- assign_button->set_tooltip(resource_path + TTR("Type:") + " " + edited_resource->get_class());
+ assign_button->set_tooltip_text(resource_path + TTR("Type:") + " " + edited_resource->get_class());
// Preview will override the above, so called at the end.
EditorResourcePreview::get_singleton()->queue_edited_resource_preview(edited_resource, this, "_update_resource_preview", edited_resource->get_instance_id());
}
} else if (edited_resource.is_valid()) {
- assign_button->set_tooltip(resource_path + TTR("Type:") + " " + edited_resource->get_class());
+ assign_button->set_tooltip_text(resource_path + TTR("Type:") + " " + edited_resource->get_class());
}
+
+ assign_button->set_disabled(!editable && !edited_resource.is_valid());
}
void EditorResourcePicker::_update_resource_preview(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, ObjectID p_obj) {
@@ -106,7 +108,7 @@ void EditorResourcePicker::_update_resource_preview(const String &p_path, const
preview_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
thumbnail_size *= EDSCALE;
- assign_button->set_custom_minimum_size(Size2(MIN(1, assign_button_min_size.x), MIN(thumbnail_size, assign_button_min_size.y)));
+ assign_button->set_custom_minimum_size(Size2(MAX(1, assign_button_min_size.x), MAX(thumbnail_size, assign_button_min_size.y)));
}
preview_rect->set_texture(p_preview);
@@ -171,20 +173,50 @@ void EditorResourcePicker::_update_menu_items() {
edit_menu->clear();
// Add options for creating specific subtypes of the base resource type.
- set_create_options(edit_menu);
+ if (is_editable()) {
+ set_create_options(edit_menu);
- // Add an option to load a resource from a file using the QuickOpen dialog.
- edit_menu->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Quick Load"), OBJ_MENU_QUICKLOAD);
+ // Add an option to load a resource from a file using the QuickOpen dialog.
+ edit_menu->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Quick Load"), OBJ_MENU_QUICKLOAD);
- // Add an option to load a resource from a file using the regular file dialog.
- edit_menu->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Load"), OBJ_MENU_LOAD);
+ // Add an option to load a resource from a file using the regular file dialog.
+ edit_menu->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Load"), OBJ_MENU_LOAD);
+ }
// Add options for changing existing value of the resource.
if (edited_resource.is_valid()) {
- edit_menu->add_icon_item(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")), TTR("Edit"), OBJ_MENU_EDIT);
- edit_menu->add_icon_item(get_theme_icon(SNAME("Clear"), SNAME("EditorIcons")), TTR("Clear"), OBJ_MENU_CLEAR);
- edit_menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Make Unique"), OBJ_MENU_MAKE_UNIQUE);
- edit_menu->add_icon_item(get_theme_icon(SNAME("Save"), SNAME("EditorIcons")), TTR("Save"), OBJ_MENU_SAVE);
+ // Determine if the edited resource is part of another scene (foreign) which was imported
+ bool is_edited_resource_foreign_import = EditorNode::get_singleton()->is_resource_read_only(edited_resource);
+
+ // If the resource is determined to be foreign and imported, change the menu entry's description to 'inspect' rather than 'edit'
+ // since will only be able to view its properties in read-only mode.
+ if (is_edited_resource_foreign_import) {
+ // The 'Search' icon is a magnifying glass, which seems appropriate, but maybe a bespoke icon is preferred here.
+ edit_menu->add_icon_item(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")), TTR("Inspect"), OBJ_MENU_INSPECT);
+ } else {
+ edit_menu->add_icon_item(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")), TTR("Edit"), OBJ_MENU_INSPECT);
+ }
+
+ if (is_editable()) {
+ edit_menu->add_icon_item(get_theme_icon(SNAME("Clear"), SNAME("EditorIcons")), TTR("Clear"), OBJ_MENU_CLEAR);
+ edit_menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Make Unique"), OBJ_MENU_MAKE_UNIQUE);
+
+ // Check whether the resource has subresources.
+ List<PropertyInfo> property_list;
+ edited_resource->get_property_list(&property_list);
+ bool has_subresources = false;
+ for (PropertyInfo &p : property_list) {
+ if ((p.type == Variant::OBJECT) && (p.hint == PROPERTY_HINT_RESOURCE_TYPE) && (p.name != "script")) {
+ has_subresources = true;
+ break;
+ }
+ }
+ if (has_subresources) {
+ edit_menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Make Unique (Recursive)"), OBJ_MENU_MAKE_UNIQUE_RECURSIVE);
+ }
+
+ edit_menu->add_icon_item(get_theme_icon(SNAME("Save"), SNAME("EditorIcons")), TTR("Save"), OBJ_MENU_SAVE);
+ }
if (edited_resource->get_path().is_resource_file()) {
edit_menu->add_separator();
@@ -195,14 +227,16 @@ void EditorResourcePicker::_update_menu_items() {
// Add options to copy/paste resource.
Ref<Resource> cb = EditorSettings::get_singleton()->get_resource_clipboard();
bool paste_valid = false;
- if (cb.is_valid()) {
- if (base_type.is_empty()) {
- paste_valid = true;
- } else {
- for (int i = 0; i < base_type.get_slice_count(","); i++) {
- if (ClassDB::is_parent_class(cb->get_class(), base_type.get_slice(",", i))) {
- paste_valid = true;
- break;
+ if (is_editable()) {
+ if (cb.is_valid()) {
+ if (base_type.is_empty()) {
+ paste_valid = true;
+ } else {
+ for (int i = 0; i < base_type.get_slice_count(","); i++) {
+ if (ClassDB::is_parent_class(cb->get_class(), base_type.get_slice(",", i))) {
+ paste_valid = true;
+ break;
+ }
}
}
}
@@ -221,7 +255,7 @@ void EditorResourcePicker::_update_menu_items() {
}
// Add options to convert existing resource to another type of resource.
- if (edited_resource.is_valid()) {
+ if (is_editable() && edited_resource.is_valid()) {
Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(edited_resource);
if (conversions.size()) {
edit_menu->add_separator();
@@ -280,7 +314,7 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) {
quick_open->set_title(TTR("Resource"));
} break;
- case OBJ_MENU_EDIT: {
+ case OBJ_MENU_INSPECT: {
if (edited_resource.is_valid()) {
emit_signal(SNAME("resource_selected"), edited_resource, true);
}
@@ -297,28 +331,22 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) {
return;
}
- List<PropertyInfo> property_list;
- edited_resource->get_property_list(&property_list);
- List<Pair<String, Variant>> propvalues;
- for (const PropertyInfo &pi : property_list) {
- Pair<String, Variant> p;
- if (pi.usage & PROPERTY_USAGE_STORAGE) {
- p.first = pi.name;
- p.second = edited_resource->get(pi.name);
- }
+ Ref<Resource> unique_resource = edited_resource->duplicate();
+ ERR_FAIL_COND(unique_resource.is_null());
+
+ edited_resource = unique_resource;
+ emit_signal(SNAME("resource_changed"), edited_resource);
+ _update_resource();
+ } break;
- propvalues.push_back(p);
+ case OBJ_MENU_MAKE_UNIQUE_RECURSIVE: {
+ if (edited_resource.is_null()) {
+ return;
}
- String orig_type = edited_resource->get_class();
- Object *inst = ClassDB::instantiate(orig_type);
- Ref<Resource> unique_resource = Ref<Resource>(Object::cast_to<Resource>(inst));
+ Ref<Resource> unique_resource = edited_resource->duplicate(true);
ERR_FAIL_COND(unique_resource.is_null());
- for (const Pair<String, Variant> &p : propvalues) {
- unique_resource->set(p.first, p.second);
- }
-
edited_resource = unique_resource;
emit_signal(SNAME("resource_changed"), edited_resource);
_update_resource();
@@ -482,20 +510,21 @@ void EditorResourcePicker::_button_draw() {
}
void EditorResourcePicker::_button_input(const Ref<InputEvent> &p_event) {
- if (!editable) {
- return;
- }
-
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
if (mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) {
- _update_menu_items();
-
- Vector2 pos = get_screen_position() + mb->get_position();
- edit_menu->reset_size();
- edit_menu->set_position(pos);
- edit_menu->popup();
+ // Only attempt to update and show the menu if we have
+ // a valid resource or the Picker is editable, as
+ // there will otherwise be nothing to display.
+ if (edited_resource.is_valid() || is_editable()) {
+ _update_menu_items();
+
+ Vector2 pos = get_screen_position() + mb->get_position();
+ edit_menu->reset_size();
+ edit_menu->set_position(pos);
+ edit_menu->popup();
+ }
}
}
}
@@ -725,7 +754,7 @@ void EditorResourcePicker::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "toggle_mode"), "set_toggle_mode", "is_toggle_mode");
- ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), PropertyInfo(Variant::BOOL, "edit")));
+ ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), PropertyInfo(Variant::BOOL, "inspect")));
ADD_SIGNAL(MethodInfo("resource_changed", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource")));
}
@@ -857,7 +886,7 @@ void EditorResourcePicker::set_toggle_pressed(bool p_pressed) {
void EditorResourcePicker::set_editable(bool p_editable) {
editable = p_editable;
- assign_button->set_disabled(!editable);
+ assign_button->set_disabled(!editable && !edited_resource.is_valid());
edit_button->set_visible(editable);
}
diff --git a/editor/editor_resource_picker.h b/editor/editor_resource_picker.h
index d36e742bcd..3d6127e656 100644
--- a/editor/editor_resource_picker.h
+++ b/editor/editor_resource_picker.h
@@ -63,9 +63,10 @@ class EditorResourcePicker : public HBoxContainer {
enum MenuOption {
OBJ_MENU_LOAD,
OBJ_MENU_QUICKLOAD,
- OBJ_MENU_EDIT,
+ OBJ_MENU_INSPECT,
OBJ_MENU_CLEAR,
OBJ_MENU_MAKE_UNIQUE,
+ OBJ_MENU_MAKE_UNIQUE_RECURSIVE,
OBJ_MENU_SAVE,
OBJ_MENU_COPY,
OBJ_MENU_PASTE,
diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp
index c0ea2b743e..706b77c142 100644
--- a/editor/editor_resource_preview.cpp
+++ b/editor/editor_resource_preview.cpp
@@ -244,7 +244,7 @@ void EditorResourcePreview::_iterate() {
} else {
String temp_path = EditorPaths::get_singleton()->get_cache_dir();
String cache_base = ProjectSettings::get_singleton()->globalize_path(item.path).md5_text();
- cache_base = temp_path.plus_file("resthumb-" + cache_base);
+ cache_base = temp_path.path_join("resthumb-" + cache_base);
//does not have it, try to load a cached thumbnail
diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp
index 6ce8625daa..3b828951e4 100644
--- a/editor/editor_run.cpp
+++ b/editor/editor_run.cpp
@@ -33,6 +33,7 @@
#include "core/config/project_settings.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "main/main.h"
#include "servers/display_server.h"
EditorRun::Status EditorRun::get_status() const {
@@ -46,6 +47,10 @@ String EditorRun::get_running_scene() const {
Error EditorRun::run(const String &p_scene, const String &p_write_movie) {
List<String> args;
+ for (const String &a : Main::get_forwardable_cli_arguments(Main::CLI_SCOPE_PROJECT)) {
+ args.push_back(a);
+ }
+
String resource_path = ProjectSettings::get_singleton()->get_resource_path();
if (!resource_path.is_empty()) {
args.push_back("--path");
@@ -105,10 +110,6 @@ Error EditorRun::run(const String &p_scene, const String &p_write_movie) {
screen -= 3;
}
- if (OS::get_singleton()->is_disable_crash_handler()) {
- args.push_back("--disable-crash-handler");
- }
-
Rect2 screen_rect;
screen_rect.position = DisplayServer::get_singleton()->screen_get_position(screen);
screen_rect.size = DisplayServer::get_singleton()->screen_get_size(screen);
diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp
index d8b738be17..3e8f17085d 100644
--- a/editor/editor_run_native.cpp
+++ b/editor/editor_run_native.cpp
@@ -77,9 +77,9 @@ void EditorRunNative::_notification(int p_what) {
mb->get_popup()->clear();
mb->show();
if (dc == 1) {
- mb->set_tooltip(eep->get_option_tooltip(0));
+ mb->set_tooltip_text(eep->get_option_tooltip(0));
} else {
- mb->set_tooltip(eep->get_options_tooltip());
+ mb->set_tooltip_text(eep->get_options_tooltip());
for (int i = 0; i < dc; i++) {
mb->get_popup()->add_icon_item(eep->get_option_icon(i), eep->get_option_label(i));
mb->get_popup()->set_item_tooltip(-1, eep->get_option_tooltip(i));
diff --git a/editor/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp
index 801a1a4641..1faefb5af7 100644
--- a/editor/editor_sectioned_inspector.cpp
+++ b/editor/editor_sectioned_inspector.cpp
@@ -113,12 +113,12 @@ class SectionedInspectorFilter : public Object {
}
}
- bool property_can_revert(const String &p_name) {
- return edited->call("property_can_revert", section + "/" + p_name);
+ bool property_can_revert(const StringName &p_name) {
+ return edited->property_can_revert(section + "/" + p_name);
}
- Variant property_get_revert(const String &p_name) {
- return edited->call("property_get_revert", section + "/" + p_name);
+ Variant property_get_revert(const StringName &p_name) {
+ return edited->property_get_revert(section + "/" + p_name);
}
protected:
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 4846fd6478..edd44b0a3a 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -406,6 +406,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("interface/editor/debug/enable_pseudolocalization", false);
set_restart_if_changed("interface/editor/debug/enable_pseudolocalization", true);
// Use pseudolocalization in editor.
+ EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/use_embedded_menu", false, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ EDITOR_SETTING_USAGE(Variant::BOOL, PROPERTY_HINT_NONE, "interface/editor/expand_to_title", true, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
EDITOR_SETTING_USAGE(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/editor/custom_display_scale", 1.0, "0.5,3,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "interface/editor/main_font_size", 14, "8,48,1")
@@ -413,7 +415,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/code_font_contextual_ligatures", 0, "Default,Disable Contextual Alternates (Coding Ligatures),Use Custom OpenType Feature Set")
_initial_set("interface/editor/code_font_custom_opentype_features", "");
_initial_set("interface/editor/code_font_custom_variations", "");
- _initial_set("interface/editor/font_antialiased", true);
+ EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/font_antialiasing", 1, "None,Grayscale,LCD sub-pixel")
#ifdef MACOS_ENABLED
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/editor/font_hinting", 0, "Auto (None),None,Light,Normal")
#else
@@ -685,7 +687,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// Visual editors
EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/visual_editors/minimap_opacity", 0.85, "0.0,1.0,0.01")
EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/visual_editors/lines_curvature", 0.5, "0.0,1.0,0.01")
- EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "editors/visual_editors/visualshader/port_preview_size", 160, "100,400,0.01")
+ EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "editors/visual_editors/visual_shader/port_preview_size", 160, "100,400,0.01")
/* Run */
@@ -854,7 +856,7 @@ void EditorSettings::create() {
// Validate editor config file.
Ref<DirAccess> dir = DirAccess::open(EditorPaths::get_singleton()->get_config_dir());
String config_file_name = "editor_settings-" + itos(VERSION_MAJOR) + ".tres";
- config_file_path = EditorPaths::get_singleton()->get_config_dir().plus_file(config_file_name);
+ config_file_path = EditorPaths::get_singleton()->get_config_dir().path_join(config_file_name);
if (!dir->file_exists(config_file_name)) {
goto fail;
}
@@ -885,7 +887,7 @@ fail:
if (extra_config->has_section("init_projects")) {
Vector<String> list = extra_config->get_value("init_projects", "list");
for (int i = 0; i < list.size(); i++) {
- list.write[i] = exe_path.plus_file(list[i]);
+ list.write[i] = exe_path.path_join(list[i]);
}
extra_config->set_value("init_projects", "list", list);
}
@@ -962,8 +964,8 @@ void EditorSettings::save() {
}
}
-Array EditorSettings::get_changed_settings() const {
- Array arr;
+PackedStringArray EditorSettings::get_changed_settings() const {
+ PackedStringArray arr;
for (const String &setting : changed_settings) {
arr.push_back(setting);
}
@@ -1073,24 +1075,25 @@ Variant _EDITOR_GET(const String &p_setting) {
return EditorSettings::get_singleton()->get(p_setting);
}
-bool EditorSettings::property_can_revert(const String &p_setting) {
- if (!props.has(p_setting)) {
+bool EditorSettings::_property_can_revert(const StringName &p_name) const {
+ if (!props.has(p_name)) {
return false;
}
- if (!props[p_setting].has_default_value) {
+ if (!props[p_name].has_default_value) {
return false;
}
- return props[p_setting].initial != props[p_setting].variant;
+ return props[p_name].initial != props[p_name].variant;
}
-Variant EditorSettings::property_get_revert(const String &p_setting) {
- if (!props.has(p_setting) || !props[p_setting].has_default_value) {
- return Variant();
+bool EditorSettings::_property_get_revert(const StringName &p_name, Variant &r_property) const {
+ if (!props.has(p_name) || !props[p_name].has_default_value) {
+ return false;
}
- return props[p_setting].initial;
+ r_property = props[p_name].initial;
+ return true;
}
void EditorSettings::add_property_hint(const PropertyInfo &p_hint) {
@@ -1103,7 +1106,7 @@ void EditorSettings::add_property_hint(const PropertyInfo &p_hint) {
void EditorSettings::set_project_metadata(const String &p_section, const String &p_key, Variant p_data) {
Ref<ConfigFile> cf = memnew(ConfigFile);
- String path = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("project_metadata.cfg");
+ String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join("project_metadata.cfg");
Error err;
err = cf->load(path);
ERR_FAIL_COND_MSG(err != OK && err != ERR_FILE_NOT_FOUND, "Cannot load editor settings from file '" + path + "'.");
@@ -1114,7 +1117,7 @@ void EditorSettings::set_project_metadata(const String &p_section, const String
Variant EditorSettings::get_project_metadata(const String &p_section, const String &p_key, Variant p_default) const {
Ref<ConfigFile> cf = memnew(ConfigFile);
- String path = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("project_metadata.cfg");
+ String path = EditorPaths::get_singleton()->get_project_settings_dir().path_join("project_metadata.cfg");
Error err = cf->load(path);
if (err != OK) {
return p_default;
@@ -1126,9 +1129,9 @@ void EditorSettings::set_favorites(const Vector<String> &p_favorites) {
favorites = p_favorites;
String favorites_file;
if (Engine::get_singleton()->is_project_manager_hint()) {
- favorites_file = EditorPaths::get_singleton()->get_config_dir().plus_file("favorite_dirs");
+ favorites_file = EditorPaths::get_singleton()->get_config_dir().path_join("favorite_dirs");
} else {
- favorites_file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("favorites");
+ favorites_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites");
}
Ref<FileAccess> f = FileAccess::open(favorites_file, FileAccess::WRITE);
if (f.is_valid()) {
@@ -1146,9 +1149,9 @@ void EditorSettings::set_recent_dirs(const Vector<String> &p_recent_dirs) {
recent_dirs = p_recent_dirs;
String recent_dirs_file;
if (Engine::get_singleton()->is_project_manager_hint()) {
- recent_dirs_file = EditorPaths::get_singleton()->get_config_dir().plus_file("recent_dirs");
+ recent_dirs_file = EditorPaths::get_singleton()->get_config_dir().path_join("recent_dirs");
} else {
- recent_dirs_file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("recent_dirs");
+ recent_dirs_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("recent_dirs");
}
Ref<FileAccess> f = FileAccess::open(recent_dirs_file, FileAccess::WRITE);
if (f.is_valid()) {
@@ -1166,11 +1169,11 @@ void EditorSettings::load_favorites_and_recent_dirs() {
String favorites_file;
String recent_dirs_file;
if (Engine::get_singleton()->is_project_manager_hint()) {
- favorites_file = EditorPaths::get_singleton()->get_config_dir().plus_file("favorite_dirs");
- recent_dirs_file = EditorPaths::get_singleton()->get_config_dir().plus_file("recent_dirs");
+ favorites_file = EditorPaths::get_singleton()->get_config_dir().path_join("favorite_dirs");
+ recent_dirs_file = EditorPaths::get_singleton()->get_config_dir().path_join("recent_dirs");
} else {
- favorites_file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("favorites");
- recent_dirs_file = EditorPaths::get_singleton()->get_project_settings_dir().plus_file("recent_dirs");
+ favorites_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites");
+ recent_dirs_file = EditorPaths::get_singleton()->get_project_settings_dir().path_join("recent_dirs");
}
Ref<FileAccess> f = FileAccess::open(favorites_file, FileAccess::READ);
if (f.is_valid()) {
@@ -1233,7 +1236,7 @@ void EditorSettings::load_text_editor_theme() {
return; // sorry for "Settings changed" console spam
}
- String theme_path = EditorPaths::get_singleton()->get_text_editor_themes_dir().plus_file(p_file + ".tet");
+ String theme_path = EditorPaths::get_singleton()->get_text_editor_themes_dir().path_join(p_file + ".tet");
Ref<ConfigFile> cf = memnew(ConfigFile);
Error err = cf->load(theme_path);
@@ -1270,7 +1273,7 @@ bool EditorSettings::import_text_editor_theme(String p_file) {
Ref<DirAccess> d = DirAccess::open(EditorPaths::get_singleton()->get_text_editor_themes_dir());
if (d.is_valid()) {
- d->copy(p_file, EditorPaths::get_singleton()->get_text_editor_themes_dir().plus_file(p_file.get_file()));
+ d->copy(p_file, EditorPaths::get_singleton()->get_text_editor_themes_dir().path_join(p_file.get_file()));
return true;
}
}
@@ -1283,7 +1286,7 @@ bool EditorSettings::save_text_editor_theme() {
if (_is_default_text_editor_theme(p_file.get_file().to_lower())) {
return false;
}
- String theme_path = EditorPaths::get_singleton()->get_text_editor_themes_dir().plus_file(p_file + ".tet");
+ String theme_path = EditorPaths::get_singleton()->get_text_editor_themes_dir().path_join(p_file + ".tet");
return _save_text_editor_theme(theme_path);
}
@@ -1336,7 +1339,7 @@ Vector<String> EditorSettings::get_script_templates(const String &p_extension, c
}
String EditorSettings::get_editor_layouts_config() const {
- return EditorPaths::get_singleton()->get_config_dir().plus_file("editor_layouts.cfg");
+ return EditorPaths::get_singleton()->get_config_dir().path_join("editor_layouts.cfg");
}
float EditorSettings::get_auto_display_scale() const {
@@ -1474,8 +1477,11 @@ void ED_SHORTCUT_OVERRIDE_ARRAY(const String &p_path, const String &p_feature, c
}
}
- // Directly override the existing shortcut.
- sc->set_events(events);
+ // Override the existing shortcut only if it wasn't customized by the user (i.e. still "original").
+ if (Shortcut::is_event_array_equal(sc->get_events(), sc->get_meta("original"))) {
+ sc->set_events(events);
+ }
+
sc->set_meta("original", events.duplicate(true));
}
@@ -1621,8 +1627,6 @@ void EditorSettings::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_setting", "name"), &EditorSettings::get_setting);
ClassDB::bind_method(D_METHOD("erase", "property"), &EditorSettings::erase);
ClassDB::bind_method(D_METHOD("set_initial_value", "name", "value", "update_current"), &EditorSettings::set_initial_value);
- ClassDB::bind_method(D_METHOD("property_can_revert", "name"), &EditorSettings::property_can_revert);
- ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &EditorSettings::property_get_revert);
ClassDB::bind_method(D_METHOD("add_property_info", "info"), &EditorSettings::_add_property_info_bind);
ClassDB::bind_method(D_METHOD("set_project_metadata", "section", "key", "data"), &EditorSettings::set_project_metadata);
diff --git a/editor/editor_settings.h b/editor/editor_settings.h
index 5faeec88c8..09bc4caa22 100644
--- a/editor/editor_settings.h
+++ b/editor/editor_settings.h
@@ -100,6 +100,8 @@ private:
void _initial_set(const StringName &p_name, const Variant &p_value);
void _get_property_list(List<PropertyInfo> *p_list) const;
void _add_property_info_bind(const Dictionary &p_info);
+ bool _property_can_revert(const StringName &p_name) const;
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
void _load_defaults(Ref<ConfigFile> p_extra_config = Ref<ConfigFile>());
void _load_godot2_text_editor_theme();
@@ -138,10 +140,8 @@ public:
_set_only(p_setting, p_value);
}
}
- bool property_can_revert(const String &p_setting);
- Variant property_get_revert(const String &p_setting);
void add_property_hint(const PropertyInfo &p_hint);
- Array get_changed_settings() const;
+ PackedStringArray get_changed_settings() const;
bool check_changed_settings_in_group(const String &p_setting_prefix) const;
void mark_setting_changed(const String &p_setting);
diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp
index 08ff63551f..67c602ad2d 100644
--- a/editor/editor_settings_dialog.cpp
+++ b/editor/editor_settings_dialog.cpp
@@ -40,6 +40,7 @@
#include "editor/editor_property_name_processor.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/margin_container.h"
void EditorSettingsDialog::ok_pressed() {
@@ -124,9 +125,9 @@ void EditorSettingsDialog::_notification(int p_what) {
} break;
case NOTIFICATION_READY: {
- undo_redo->set_method_notify_callback(EditorDebuggerNode::_method_changeds, nullptr);
- undo_redo->set_property_notify_callback(EditorDebuggerNode::_property_changeds, nullptr);
- undo_redo->set_commit_notify_callback(_undo_redo_callback, this);
+ undo_redo->get_or_create_history(EditorUndoRedoManager::GLOBAL_HISTORY).undo_redo->set_method_notify_callback(EditorDebuggerNode::_method_changeds, nullptr);
+ undo_redo->get_or_create_history(EditorUndoRedoManager::GLOBAL_HISTORY).undo_redo->set_property_notify_callback(EditorDebuggerNode::_property_changeds, nullptr);
+ undo_redo->get_or_create_history(EditorUndoRedoManager::GLOBAL_HISTORY).undo_redo->set_commit_notify_callback(_undo_redo_callback, this);
} break;
case NOTIFICATION_ENTER_TREE: {
@@ -680,7 +681,7 @@ void EditorSettingsDialog::_bind_methods() {
EditorSettingsDialog::EditorSettingsDialog() {
set_title(TTR("Editor Settings"));
- undo_redo = memnew(UndoRedo);
+ undo_redo = EditorNode::get_undo_redo();
tabs = memnew(TabContainer);
tabs->set_theme_type_variation("TabContainerOdd");
@@ -776,5 +777,4 @@ EditorSettingsDialog::EditorSettingsDialog() {
}
EditorSettingsDialog::~EditorSettingsDialog() {
- memdelete(undo_redo);
}
diff --git a/editor/editor_settings_dialog.h b/editor/editor_settings_dialog.h
index a1ea54c6fb..87ed6a77eb 100644
--- a/editor/editor_settings_dialog.h
+++ b/editor/editor_settings_dialog.h
@@ -40,6 +40,8 @@
#include "scene/gui/tab_container.h"
#include "scene/gui/texture_rect.h"
+class EditorUndoRedoManager;
+
class EditorSettingsDialog : public AcceptDialog {
GDCLASS(EditorSettingsDialog, AcceptDialog);
@@ -73,7 +75,7 @@ class EditorSettingsDialog : public AcceptDialog {
Timer *timer = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
virtual void cancel_pressed() override;
virtual void ok_pressed() override;
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index 20e9d7a3df..b9a3e9decf 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -149,6 +149,10 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) {
}
void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) {
+ if (read_only) {
+ return;
+ }
+
Ref<InputEventMouseButton> mb = p_event;
if (grabbing_grabber) {
@@ -605,6 +609,10 @@ bool EditorSpinSlider::is_flat() const {
return flat;
}
+bool EditorSpinSlider::is_grabbing() const {
+ return grabbing_grabber || grabbing_spinner;
+}
+
void EditorSpinSlider::_focus_entered() {
_ensure_input_popup();
Rect2 gr = get_screen_rect();
diff --git a/editor/editor_spin_slider.h b/editor/editor_spin_slider.h
index f0adf5b7a1..afcaa3e4b6 100644
--- a/editor/editor_spin_slider.h
+++ b/editor/editor_spin_slider.h
@@ -110,6 +110,8 @@ public:
void set_flat(bool p_enable);
bool is_flat() const;
+ bool is_grabbing() const;
+
void setup_and_show() { _focus_entered(); }
LineEdit *get_line_edit();
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index da7105c94c..d20caef51c 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -32,7 +32,6 @@
#include "core/error/error_macros.h"
#include "core/io/resource_loader.h"
-#include "core/variant/dictionary.h"
#include "editor/editor_fonts.h"
#include "editor/editor_icons.gen.h"
#include "editor/editor_scale.h"
@@ -43,6 +42,118 @@
#include "modules/svg/image_loader_svg.h"
#endif
+HashMap<Color, Color> EditorColorMap::editor_color_map;
+
+void EditorColorMap::add_color_pair(const String p_from_color, const String p_to_color) {
+ editor_color_map[Color::html(p_from_color)] = Color::html(p_to_color);
+}
+
+void EditorColorMap::create() {
+ // Some of the colors below are listed for completeness sake.
+ // This can be a basis for proper palette validation later.
+
+ // Convert: FROM TO
+ add_color_pair("#478cbf", "#478cbf"); // Godot Blue
+ add_color_pair("#414042", "#414042"); // Godot Gray
+
+ add_color_pair("#ffffff", "#414141"); // Pure white
+ add_color_pair("#000000", "#bfbfbf"); // Pure black
+ // Keep pure RGB colors as is, but list them for explicitly.
+ add_color_pair("#ff0000", "#ff0000"); // Pure red
+ add_color_pair("#00ff00", "#00ff00"); // Pure green
+ add_color_pair("#0000ff", "#0000ff"); // Pure blue
+
+ // GUI Colors
+ add_color_pair("#e0e0e0", "#5a5a5a"); // Common icon color
+ add_color_pair("#fefefe", "#fefefe"); // Forced light color
+ add_color_pair("#808080", "#808080"); // GUI disabled color
+ add_color_pair("#b3b3b3", "#363636"); // GUI disabled light color
+ add_color_pair("#699ce8", "#699ce8"); // GUI highlight color
+ add_color_pair("#f9f9f9", "#606060"); // Scrollbar grabber highlight color
+
+ add_color_pair("#c38ef1", "#a85de9"); // Animation
+ add_color_pair("#fc7f7f", "#cd3838"); // Spatial
+ add_color_pair("#8da5f3", "#3d64dd"); // 2D
+ add_color_pair("#4b70ea", "#1a3eac"); // 2D Dark
+ add_color_pair("#8eef97", "#2fa139"); // Control
+
+ add_color_pair("#5fb2ff", "#0079f0"); // Selection (blue)
+ add_color_pair("#003e7a", "#2b74bb"); // Selection (darker blue)
+ add_color_pair("#f7f5cf", "#615f3a"); // Gizmo (yellow)
+
+ // Rainbow
+ add_color_pair("#ff4545", "#ff2929"); // Red
+ add_color_pair("#ffe345", "#ffe337"); // Yellow
+ add_color_pair("#80ff45", "#74ff34"); // Green
+ add_color_pair("#45ffa2", "#2cff98"); // Aqua
+ add_color_pair("#45d7ff", "#22ccff"); // Blue
+ add_color_pair("#8045ff", "#702aff"); // Purple
+ add_color_pair("#ff4596", "#ff2781"); // Pink
+
+ // Audio gradients
+ add_color_pair("#e1da5b", "#d6cf4b"); // Yellow
+
+ add_color_pair("#62aeff", "#1678e0"); // Frozen gradient top
+ add_color_pair("#75d1e6", "#41acc5"); // Frozen gradient middle
+ add_color_pair("#84ffee", "#49ccba"); // Frozen gradient bottom
+
+ add_color_pair("#f70000", "#c91616"); // Color track red
+ add_color_pair("#eec315", "#d58c0b"); // Color track orange
+ add_color_pair("#dbee15", "#b7d10a"); // Color track yellow
+ add_color_pair("#288027", "#218309"); // Color track green
+
+ // Resource groups
+ add_color_pair("#ffca5f", "#fea900"); // Mesh resource (orange)
+ add_color_pair("#2998ff", "#68b6ff"); // Shape resource (blue)
+ add_color_pair("#a2d2ff", "#4998e3"); // Shape resource (light blue)
+
+ // Animation editor tracks
+ // The property track icon color is set by the common icon color.
+ add_color_pair("#ea7940", "#bd5e2c"); // 3D Position track
+ add_color_pair("#ff2b88", "#bd165f"); // 3D Rotation track
+ add_color_pair("#eac840", "#bd9d1f"); // 3D Scale track
+ add_color_pair("#3cf34e", "#16a827"); // Call Method track
+ add_color_pair("#2877f6", "#236be6"); // Bezier Curve track
+ add_color_pair("#eae440", "#9f9722"); // Audio Playback track
+ add_color_pair("#a448f0", "#9853ce"); // Animation Playback track
+ add_color_pair("#5ad5c4", "#0a9c88"); // Blend Shape track
+
+ // Control layouts
+ add_color_pair("#d6d6d6", "#474747"); // Highlighted part
+ add_color_pair("#474747", "#d6d6d6"); // Background part
+ add_color_pair("#919191", "#6e6e6e"); // Border part
+
+ // TileSet editor icons
+ add_color_pair("#fce00e", "#aa8d24"); // New Single Tile
+ add_color_pair("#0e71fc", "#0350bd"); // New Autotile
+ add_color_pair("#c6ced4", "#828f9b"); // New Atlas
+
+ // Visual script
+ add_color_pair("#41ecad", "#25e3a0"); // VisualScript variant
+ add_color_pair("#6f91f0", "#6d8eeb"); // VisualScript bool
+ add_color_pair("#5abbef", "#4fb2e9"); // VisualScript int
+ add_color_pair("#35d4f4", "#27ccf0"); // VisualScript float
+ add_color_pair("#4593ec", "#4690e7"); // VisualScript String
+ add_color_pair("#ac73f1", "#ad76ee"); // VisualScript Vector2
+ add_color_pair("#f1738f", "#ee758e"); // VisualScript Rect2
+ add_color_pair("#de66f0", "#dc6aed"); // VisualScript Vector3
+ add_color_pair("#b9ec41", "#96ce1a"); // VisualScript Transform2D
+ add_color_pair("#f74949", "#f77070"); // VisualScript Plane
+ add_color_pair("#ec418e", "#ec69a3"); // VisualScript Quat
+ add_color_pair("#ee5677", "#ee7991"); // VisualScript AABB
+ add_color_pair("#e1ec41", "#b2bb19"); // VisualScript Basis
+ add_color_pair("#f68f45", "#f49047"); // VisualScript Transform
+ add_color_pair("#417aec", "#6993ec"); // VisualScript NodePath
+ add_color_pair("#41ec80", "#2ce573"); // VisualScript RID
+ add_color_pair("#55f3e3", "#12d5c3"); // VisualScript Object
+ add_color_pair("#54ed9e", "#57e99f"); // VisualScript Dictionary
+ // Visual shaders
+ add_color_pair("#77ce57", "#67c046"); // Vector funcs
+ add_color_pair("#ea686c", "#d95256"); // Vector transforms
+ add_color_pair("#eac968", "#d9b64f"); // Textures and cubemaps
+ add_color_pair("#cf68ea", "#c050dd"); // Functions and expressions
+}
+
static Ref<StyleBoxTexture> make_stylebox(Ref<Texture2D> p_texture, float p_left, float p_top, float p_right, float p_bottom, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1, bool p_draw_center = true) {
Ref<StyleBoxTexture> style(memnew(StyleBoxTexture));
style->set_texture(p_texture);
@@ -113,7 +224,7 @@ static Ref<Texture2D> flip_icon(Ref<Texture2D> p_texture, bool p_flip_y = false,
#ifdef MODULE_SVG_ENABLED
// See also `generate_icon()` in `scene/resources/default_theme.cpp`.
-static Ref<ImageTexture> editor_generate_icon(int p_index, bool p_convert_color, float p_scale = EDSCALE, float p_saturation = 1.0, Dictionary p_convert_colors = Dictionary()) {
+static Ref<ImageTexture> editor_generate_icon(int p_index, float p_scale, float p_saturation, const HashMap<Color, Color> &p_convert_colors = HashMap<Color, Color>()) {
Ref<Image> img = memnew(Image);
// Upsample icon generation only if the editor scale isn't an integer multiplier.
@@ -121,8 +232,7 @@ static Ref<ImageTexture> editor_generate_icon(int p_index, bool p_convert_color,
// with integer editor scales.
const bool upsample = !Math::is_equal_approx(Math::round(p_scale), p_scale);
ImageLoaderSVG img_loader;
- img_loader.set_replace_colors(p_convert_colors);
- img_loader.create_image_from_string(img, editor_icons_sources[p_index], p_scale, upsample, p_convert_color);
+ img_loader.create_image_from_string(img, editor_icons_sources[p_index], p_scale, upsample, p_convert_colors);
if (p_saturation != 1.0) {
img->adjust_bcs(1.0, 1.0, p_saturation);
}
@@ -132,126 +242,18 @@ static Ref<ImageTexture> editor_generate_icon(int p_index, bool p_convert_color,
}
#endif
-#ifndef ADD_CONVERT_COLOR
-#define ADD_CONVERT_COLOR(dictionary, old_color, new_color) dictionary[Color::html(old_color)] = Color::html(new_color)
-#endif
-
void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme = true, int p_thumb_size = 32, bool p_only_thumbs = false, float p_icon_saturation = 1.0) {
#ifdef MODULE_SVG_ENABLED
- // The default icon theme is designed to be used for a dark theme.
- // This dictionary stores Color values to convert to other colors
- // for better readability on a light theme.
- // Godot Color values are used to avoid the ambiguity of strings
- // (where "#ffffff", "fff", and "white" are all equivalent).
- Dictionary dark_icon_color_dictionary;
+ HashMap<Color, Color> icon_color_map;
// The names of the icons to never convert, even if one of their colors
// are contained in the dictionary above.
HashSet<StringName> exceptions;
- // Some of the colors below are listed for completeness sake.
- // This can be a basis for proper palette validation later.
if (!p_dark_theme) {
- // Convert color: FROM TO
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#478cbf", "#478cbf"); // Godot Blue
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#414042", "#414042"); // Godot Gray
-
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ffffff", "#414141"); // Pure white
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#000000", "#bfbfbf"); // Pure black
- // Keep pure RGB colors as is, but list them for explicitly.
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ff0000", "#ff0000"); // Pure red
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#00ff00", "#00ff00"); // Pure green
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#0000ff", "#0000ff"); // Pure blue
-
- // GUI Colors
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#e0e0e0", "#5a5a5a"); // Common icon color
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#fefefe", "#fefefe"); // Forced light color
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#808080", "#808080"); // GUI disabled color
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#b3b3b3", "#363636"); // GUI disabled light color
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#699ce8", "#699ce8"); // GUI highlight color
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f9f9f9", "#606060"); // Scrollbar grabber highlight color
-
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#c38ef1", "#a85de9"); // Animation
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#fc7f7f", "#cd3838"); // Spatial
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#8da5f3", "#3d64dd"); // 2D
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#4b70ea", "#1a3eac"); // 2D Dark
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#8eef97", "#2fa139"); // Control
-
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#5fb2ff", "#0079f0"); // Selection (blue)
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#003e7a", "#2b74bb"); // Selection (darker blue)
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f7f5cf", "#615f3a"); // Gizmo (yellow)
-
- // Rainbow
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ff4545", "#ff2929"); // Red
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ffe345", "#ffe337"); // Yellow
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#80ff45", "#74ff34"); // Green
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#45ffa2", "#2cff98"); // Aqua
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#45d7ff", "#22ccff"); // Blue
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#8045ff", "#702aff"); // Purple
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ff4596", "#ff2781"); // Pink
-
- // Audio gradients
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#e1da5b", "#d6cf4b"); // Yellow
-
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#62aeff", "#1678e0"); // Frozen gradient top
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#75d1e6", "#41acc5"); // Frozen gradient middle
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#84ffee", "#49ccba"); // Frozen gradient bottom
-
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f70000", "#c91616"); // Color track red
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#eec315", "#d58c0b"); // Color track orange
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#dbee15", "#b7d10a"); // Color track yellow
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#288027", "#218309"); // Color track green
-
- // Resource groups
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ffca5f", "#fea900"); // Mesh resource (orange)
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#2998ff", "#68b6ff"); // Shape resource (blue)
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#a2d2ff", "#4998e3"); // Shape resource (light blue)
-
- // Animation editor tracks
- // The property track icon color is set by the common icon color.
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ea7940", "#bd5e2c"); // 3D Position track
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ff2b88", "#bd165f"); // 3D Rotation track
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#eac840", "#bd9d1f"); // 3D Scale track
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#3cf34e", "#16a827"); // Call Method track
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#2877f6", "#236be6"); // Bezier Curve track
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#eae440", "#9f9722"); // Audio Playback track
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#a448f0", "#9853ce"); // Animation Playback track
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#5ad5c4", "#0a9c88"); // Blend Shape track
-
- // Control layouts
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#d6d6d6", "#474747"); // Highlighted part
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#474747", "#d6d6d6"); // Background part
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#919191", "#6e6e6e"); // Border part
-
- // TileSet editor icons
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#fce00e", "#aa8d24"); // New Single Tile
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#0e71fc", "#0350bd"); // New Autotile
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#c6ced4", "#828f9b"); // New Atlas
-
- // Visual script
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#41ecad", "#25e3a0"); // VisualScript variant
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#6f91f0", "#6d8eeb"); // VisualScript bool
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#5abbef", "#4fb2e9"); // VisualScript int
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#35d4f4", "#27ccf0"); // VisualScript float
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#4593ec", "#4690e7"); // VisualScript String
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ac73f1", "#ad76ee"); // VisualScript Vector2
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f1738f", "#ee758e"); // VisualScript Rect2
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#de66f0", "#dc6aed"); // VisualScript Vector3
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#b9ec41", "#96ce1a"); // VisualScript Transform2D
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f74949", "#f77070"); // VisualScript Plane
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ec418e", "#ec69a3"); // VisualScript Quat
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ee5677", "#ee7991"); // VisualScript AABB
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#e1ec41", "#b2bb19"); // VisualScript Basis
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#f68f45", "#f49047"); // VisualScript Transform
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#417aec", "#6993ec"); // VisualScript NodePath
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#41ec80", "#2ce573"); // VisualScript RID
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#55f3e3", "#12d5c3"); // VisualScript Object
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#54ed9e", "#57e99f"); // VisualScript Dictionary
- // Visual shaders
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#77ce57", "#67c046"); // Vector funcs
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#ea686c", "#d95256"); // Vector transforms
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#eac968", "#d9b64f"); // Textures and cubemaps
- ADD_CONVERT_COLOR(dark_icon_color_dictionary, "#cf68ea", "#c050dd"); // Functions and expressions
+ for (KeyValue<Color, Color> &E : EditorColorMap::get()) {
+ icon_color_map[E.key] = E.value;
+ }
exceptions.insert("EditorPivot");
exceptions.insert("EditorHandle");
@@ -291,18 +293,18 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
const Color error_color = p_theme->get_color(SNAME("error_color"), SNAME("Editor"));
const Color success_color = p_theme->get_color(SNAME("success_color"), SNAME("Editor"));
const Color warning_color = p_theme->get_color(SNAME("warning_color"), SNAME("Editor"));
- dark_icon_color_dictionary[Color::html("#ff5f5f")] = error_color;
- dark_icon_color_dictionary[Color::html("#5fff97")] = success_color;
- dark_icon_color_dictionary[Color::html("#ffdd65")] = warning_color;
+ icon_color_map[Color::html("#ff5f5f")] = error_color;
+ icon_color_map[Color::html("#5fff97")] = success_color;
+ icon_color_map[Color::html("#ffdd65")] = warning_color;
// Use the accent color for some icons (checkbox, radio, toggle, etc.).
- Dictionary accent_color_icon_color_dictionary;
+ HashMap<Color, Color> accent_color_map;
HashSet<StringName> accent_color_icons;
const Color accent_color = p_theme->get_color(SNAME("accent_color"), SNAME("Editor"));
- accent_color_icon_color_dictionary[Color::html("699ce8")] = accent_color;
+ accent_color_map[Color::html("699ce8")] = accent_color;
if (accent_color.get_luminance() > 0.75) {
- accent_color_icon_color_dictionary[Color::html("ffffff")] = Color(0.2, 0.2, 0.2);
+ accent_color_map[Color::html("ffffff")] = Color(0.2, 0.2, 0.2);
}
accent_color_icons.insert("GuiChecked");
@@ -318,7 +320,7 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
Ref<ImageTexture> icon;
if (accent_color_icons.has(editor_icons_names[i])) {
- icon = editor_generate_icon(i, true, EDSCALE, 1.0, accent_color_icon_color_dictionary);
+ icon = editor_generate_icon(i, EDSCALE, 1.0, accent_color_map);
} else {
float saturation = p_icon_saturation;
@@ -327,7 +329,11 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
}
const int is_exception = exceptions.has(editor_icons_names[i]);
- icon = editor_generate_icon(i, !is_exception, EDSCALE, saturation, dark_icon_color_dictionary);
+ if (is_exception) {
+ icon = editor_generate_icon(i, EDSCALE, saturation);
+ } else {
+ icon = editor_generate_icon(i, EDSCALE, saturation, icon_color_map);
+ }
}
p_theme->set_icon(editor_icons_names[i], SNAME("EditorIcons"), icon);
@@ -342,7 +348,13 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
for (int i = 0; i < editor_bg_thumbs_count; i++) {
const int index = editor_bg_thumbs_indices[i];
const int is_exception = exceptions.has(editor_icons_names[index]);
- const Ref<ImageTexture> icon = editor_generate_icon(index, !p_dark_theme && !is_exception, scale, force_filter, dark_icon_color_dictionary);
+
+ Ref<ImageTexture> icon;
+ if (!p_dark_theme && !is_exception) {
+ icon = editor_generate_icon(index, scale, force_filter, icon_color_map);
+ } else {
+ icon = editor_generate_icon(index, scale, force_filter);
+ }
p_theme->set_icon(editor_icons_names[index], SNAME("EditorIcons"), icon);
}
@@ -351,7 +363,13 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
for (int i = 0; i < editor_md_thumbs_count; i++) {
const int index = editor_md_thumbs_indices[i];
const bool is_exception = exceptions.has(editor_icons_names[index]);
- const Ref<ImageTexture> icon = editor_generate_icon(index, !p_dark_theme && !is_exception, scale, force_filter, dark_icon_color_dictionary);
+
+ Ref<ImageTexture> icon;
+ if (!p_dark_theme && !is_exception) {
+ icon = editor_generate_icon(index, scale, force_filter, icon_color_map);
+ } else {
+ icon = editor_generate_icon(index, scale, force_filter);
+ }
p_theme->set_icon(editor_icons_names[index], SNAME("EditorIcons"), icon);
}
@@ -458,6 +476,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color font_color = mono_color.lerp(base_color, 0.25);
const Color font_hover_color = mono_color.lerp(base_color, 0.125);
const Color font_focus_color = mono_color.lerp(base_color, 0.125);
+ const Color font_hover_pressed_color = font_hover_color.lerp(accent_color, 0.74);
const Color font_disabled_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.3);
const Color font_readonly_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.65);
const Color font_placeholder_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.6);
@@ -518,8 +537,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Color warning_color = Color(1, 0.87, 0.4);
Color error_color = Color(1, 0.47, 0.42);
Color property_color = font_color.lerp(Color(0.5, 0.5, 0.5), 0.5);
- Color readonly_color = property_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.5);
- Color readonly_warning_color = error_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.5);
+ Color readonly_color = property_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.25);
+ Color readonly_warning_color = error_color.lerp(dark_theme ? Color(0, 0, 0) : Color(1, 1, 1), 0.25);
if (!dark_theme) {
// Darken some colors to be readable on a light background
@@ -641,6 +660,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Add a highlight line at the top of the selected tab.
style_tab_selected->set_border_width_all(0);
+ style_tab_selected->set_default_margin(SIDE_LEFT, widget_default_margin.x - border_width);
style_tab_selected->set_border_width(SIDE_TOP, Math::round(2 * EDSCALE));
// Make the highlight line prominent, but not too prominent as to not be distracting.
Color tab_highlight = dark_color_2.lerp(accent_color, 0.75);
@@ -653,6 +673,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// We can't prevent them with both rounded corners and non-zero border width, though
style_tab_selected->set_expand_margin_size(SIDE_BOTTOM, corner_width > 0 ? corner_width : border_width);
+ // When using a border width greater than 0, visually line up the left of the selected tab with the underlying panel.
+ style_tab_selected->set_expand_margin_size(SIDE_LEFT, -border_width);
+
style_tab_selected->set_default_margin(SIDE_LEFT, widget_default_margin.x + 2 * EDSCALE);
style_tab_selected->set_default_margin(SIDE_RIGHT, widget_default_margin.x + 2 * EDSCALE);
style_tab_selected->set_default_margin(SIDE_BOTTOM, widget_default_margin.y);
@@ -728,6 +751,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_color", "MenuButton", font_color);
theme->set_color("font_hover_color", "MenuButton", font_hover_color);
+ theme->set_color("font_hover_pressed_color", "MenuButton", font_hover_pressed_color);
theme->set_color("font_focus_color", "MenuButton", font_focus_color);
theme->set_stylebox("MenuHover", "EditorStyles", style_widget_hover);
@@ -741,6 +765,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_color", "Button", font_color);
theme->set_color("font_hover_color", "Button", font_hover_color);
+ theme->set_color("font_hover_pressed_color", "Button", font_hover_pressed_color);
theme->set_color("font_focus_color", "Button", font_focus_color);
theme->set_color("font_pressed_color", "Button", accent_color);
theme->set_color("font_disabled_color", "Button", font_disabled_color);
@@ -784,6 +809,26 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
editor_log_button_pressed->set_border_color(accent_color);
theme->set_stylebox("pressed", "EditorLogFilterButton", editor_log_button_pressed);
+ // MenuBar
+ theme->set_stylebox("normal", "MenuBar", style_widget);
+ theme->set_stylebox("hover", "MenuBar", style_widget_hover);
+ theme->set_stylebox("pressed", "MenuBar", style_widget_pressed);
+ theme->set_stylebox("focus", "MenuBar", style_widget_focus);
+ theme->set_stylebox("disabled", "MenuBar", style_widget_disabled);
+
+ theme->set_color("font_color", "MenuBar", font_color);
+ theme->set_color("font_hover_color", "MenuBar", font_hover_color);
+ theme->set_color("font_hover_pressed_color", "MenuBar", font_hover_pressed_color);
+ theme->set_color("font_focus_color", "MenuBar", font_focus_color);
+ theme->set_color("font_pressed_color", "MenuBar", accent_color);
+ theme->set_color("font_disabled_color", "MenuBar", font_disabled_color);
+
+ theme->set_color("icon_normal_color", "MenuBar", icon_normal_color);
+ theme->set_color("icon_hover_color", "MenuBar", icon_hover_color);
+ theme->set_color("icon_focus_color", "MenuBar", icon_focus_color);
+ theme->set_color("icon_pressed_color", "MenuBar", icon_pressed_color);
+ theme->set_color("icon_disabled_color", "MenuBar", icon_disabled_color);
+
// OptionButton
Ref<StyleBoxFlat> style_option_button_focus = style_widget_focus->duplicate();
Ref<StyleBoxFlat> style_option_button_normal = style_widget->duplicate();
@@ -810,6 +855,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_color", "OptionButton", font_color);
theme->set_color("font_hover_color", "OptionButton", font_hover_color);
+ theme->set_color("font_hover_pressed_color", "OptionButton", font_hover_pressed_color);
theme->set_color("font_focus_color", "OptionButton", font_focus_color);
theme->set_color("font_pressed_color", "OptionButton", accent_color);
theme->set_color("font_disabled_color", "OptionButton", font_disabled_color);
@@ -830,6 +876,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("pressed", "CheckButton", style_menu);
theme->set_stylebox("disabled", "CheckButton", style_menu);
theme->set_stylebox("hover", "CheckButton", style_menu);
+ theme->set_stylebox("hover_pressed", "CheckButton", style_menu);
theme->set_icon("on", "CheckButton", theme->get_icon(SNAME("GuiToggleOn"), SNAME("EditorIcons")));
theme->set_icon("on_disabled", "CheckButton", theme->get_icon(SNAME("GuiToggleOnDisabled"), SNAME("EditorIcons")));
@@ -843,6 +890,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_color", "CheckButton", font_color);
theme->set_color("font_hover_color", "CheckButton", font_hover_color);
+ theme->set_color("font_hover_pressed_color", "CheckButton", font_hover_pressed_color);
theme->set_color("font_focus_color", "CheckButton", font_focus_color);
theme->set_color("font_pressed_color", "CheckButton", accent_color);
theme->set_color("font_disabled_color", "CheckButton", font_disabled_color);
@@ -867,6 +915,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("pressed", "CheckBox", sb_checkbox);
theme->set_stylebox("disabled", "CheckBox", sb_checkbox);
theme->set_stylebox("hover", "CheckBox", sb_checkbox);
+ theme->set_stylebox("hover_pressed", "CheckBox", sb_checkbox);
theme->set_icon("checked", "CheckBox", theme->get_icon(SNAME("GuiChecked"), SNAME("EditorIcons")));
theme->set_icon("unchecked", "CheckBox", theme->get_icon(SNAME("GuiUnchecked"), SNAME("EditorIcons")));
theme->set_icon("radio_checked", "CheckBox", theme->get_icon(SNAME("GuiRadioChecked"), SNAME("EditorIcons")));
@@ -878,6 +927,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_color", "CheckBox", font_color);
theme->set_color("font_hover_color", "CheckBox", font_hover_color);
+ theme->set_color("font_hover_pressed_color", "CheckBox", font_hover_pressed_color);
theme->set_color("font_focus_color", "CheckBox", font_focus_color);
theme->set_color("font_pressed_color", "CheckBox", accent_color);
theme->set_color("font_disabled_color", "CheckBox", font_disabled_color);
@@ -895,18 +945,20 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("panel", "PopupDialog", style_popup);
// PopupMenu
- const int popup_menu_margin_size = default_margin_size * 1.5 * EDSCALE;
Ref<StyleBoxFlat> style_popup_menu = style_popup->duplicate();
// Use 1 pixel for the sides, since if 0 is used, the highlight of hovered items is drawn
// on top of the popup border. This causes a 'gap' in the panel border when an item is highlighted,
// and it looks weird. 1px solves this.
- style_popup_menu->set_default_margin(SIDE_LEFT, 1 * EDSCALE);
- style_popup_menu->set_default_margin(SIDE_TOP, popup_menu_margin_size);
- style_popup_menu->set_default_margin(SIDE_RIGHT, 1 * EDSCALE);
- style_popup_menu->set_default_margin(SIDE_BOTTOM, popup_menu_margin_size);
+ style_popup_menu->set_default_margin(SIDE_LEFT, EDSCALE);
+ style_popup_menu->set_default_margin(SIDE_TOP, 2 * EDSCALE);
+ style_popup_menu->set_default_margin(SIDE_RIGHT, EDSCALE);
+ style_popup_menu->set_default_margin(SIDE_BOTTOM, 2 * EDSCALE);
// Always display a border for PopupMenus so they can be distinguished from their background.
- style_popup_menu->set_border_width_all(1 * EDSCALE);
+ style_popup_menu->set_border_width_all(EDSCALE);
style_popup_menu->set_border_color(dark_color_2);
+ // Popups are separate windows by default in the editor. Windows currently don't support per-pixel transparency
+ // in 4.0, and even if it was, it may not always work in practice (e.g. running with compositing disabled).
+ style_popup_menu->set_corner_radius_all(0);
theme->set_stylebox("panel", "PopupMenu", style_popup_menu);
Ref<StyleBoxFlat> style_menu_hover = style_widget_hover->duplicate();
@@ -939,12 +991,12 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Force the v_separation to be even so that the spacing on top and bottom is even.
// If the vsep is odd and cannot be split into 2 even groups (of pixels), then it will be lopsided.
- // We add 2 to the vsep to give it some extra spacing which looks a bit more modern (see Windows, for example)
- int vsep_base = extra_spacing + default_margin_size + 2;
- int force_even_vsep = vsep_base + (vsep_base % 2);
+ // We add 2 to the vsep to give it some extra spacing which looks a bit more modern (see Windows, for example).
+ const int vsep_base = extra_spacing + default_margin_size + 6;
+ const int force_even_vsep = vsep_base + (vsep_base % 2);
theme->set_constant("v_separation", "PopupMenu", force_even_vsep * EDSCALE);
- theme->set_constant("item_start_padding", "PopupMenu", popup_menu_margin_size * EDSCALE);
- theme->set_constant("item_end_padding", "PopupMenu", popup_menu_margin_size * EDSCALE);
+ theme->set_constant("item_start_padding", "PopupMenu", default_margin_size * 1.5 * EDSCALE);
+ theme->set_constant("item_end_padding", "PopupMenu", default_margin_size * 1.5 * EDSCALE);
// Sub-inspectors
for (int i = 0; i < 16; i++) {
@@ -1257,7 +1309,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("focus", "LineEdit", style_widget_focus);
theme->set_stylebox("read_only", "LineEdit", style_line_edit_disabled);
theme->set_icon("clear", "LineEdit", theme->get_icon(SNAME("GuiClose"), SNAME("EditorIcons")));
- theme->set_color("read_only", "LineEdit", font_disabled_color);
theme->set_color("font_color", "LineEdit", font_color);
theme->set_color("font_selected_color", "LineEdit", mono_color);
theme->set_color("font_uneditable_color", "LineEdit", font_readonly_color);
@@ -1434,6 +1485,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("focus", "LinkButton", style_empty);
theme->set_color("font_color", "LinkButton", font_color);
theme->set_color("font_hover_color", "LinkButton", font_hover_color);
+ theme->set_color("font_hover_pressed_color", "LinkButton", font_hover_pressed_color);
theme->set_color("font_focus_color", "LinkButton", font_focus_color);
theme->set_color("font_pressed_color", "LinkButton", accent_color);
theme->set_color("font_disabled_color", "LinkButton", font_disabled_color);
@@ -1450,12 +1502,23 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_tooltip->set_bg_color(dark_color_3 * Color(0.8, 0.8, 0.8, 0.9));
style_tooltip->set_border_width_all(0);
theme->set_color("font_color", "TooltipLabel", font_hover_color);
- theme->set_color("font_color_shadow", "TooltipLabel", Color(0, 0, 0, 0));
+ theme->set_color("font_shadow_color", "TooltipLabel", Color(0, 0, 0, 0));
theme->set_stylebox("panel", "TooltipPanel", style_tooltip);
// PopupPanel
theme->set_stylebox("panel", "PopupPanel", style_popup);
+ Ref<StyleBoxFlat> control_editor_popup_style = style_popup->duplicate();
+ control_editor_popup_style->set_shadow_size(0);
+ control_editor_popup_style->set_default_margin(SIDE_LEFT, default_margin_size * EDSCALE);
+ control_editor_popup_style->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE);
+ control_editor_popup_style->set_default_margin(SIDE_RIGHT, default_margin_size * EDSCALE);
+ control_editor_popup_style->set_default_margin(SIDE_BOTTOM, default_margin_size * EDSCALE);
+ control_editor_popup_style->set_border_width_all(0);
+
+ theme->set_stylebox("panel", "ControlEditorPopupPanel", control_editor_popup_style);
+ theme->set_type_variation("ControlEditorPopupPanel", "PopupPanel");
+
// SpinBox
theme->set_icon("updown", "SpinBox", theme->get_icon(SNAME("GuiSpinboxUpdown"), SNAME("EditorIcons")));
theme->set_icon("updown_disabled", "SpinBox", theme->get_icon(SNAME("GuiSpinboxUpdownDisabled"), SNAME("EditorIcons")));
@@ -1660,6 +1723,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_dictionary_add_item->set_expand_margin_size(SIDE_RIGHT, 4 * EDSCALE);
theme->set_stylebox("DictionaryAddItem", "EditorStyles", style_dictionary_add_item);
+ Ref<StyleBoxEmpty> vshader_label_style = make_empty_stylebox(2, 1, 2, 1);
+ theme->set_stylebox("label_style", "VShaderEditor", vshader_label_style);
+
// adaptive script theme constants
// for comments and elements with lower relevance
const Color dim_color = Color(font_color.r, font_color.g, font_color.b, 0.5);
@@ -1809,14 +1875,14 @@ Ref<Theme> create_custom_theme(const Ref<Theme> p_theme) {
return theme;
}
-Ref<ImageTexture> create_unscaled_default_project_icon() {
-#ifdef MODULE_SVG_ENABLED
+/**
+ * Returns the SVG code for the default project icon.
+ */
+String get_default_project_icon() {
for (int i = 0; i < editor_icons_count; i++) {
- // ESCALE should never affect size of the icon
if (strcmp(editor_icons_names[i], "DefaultProjectIcon") == 0) {
- return editor_generate_icon(i, false, 1.0);
+ return String(editor_icons_sources[i]);
}
}
-#endif
- return Ref<ImageTexture>(memnew(ImageTexture));
+ return String();
}
diff --git a/editor/editor_themes.h b/editor/editor_themes.h
index 95184b9d4a..37db8160fa 100644
--- a/editor/editor_themes.h
+++ b/editor/editor_themes.h
@@ -34,10 +34,24 @@
#include "scene/resources/texture.h"
#include "scene/resources/theme.h"
+// The default icon theme is designed to be used for a dark theme. This map stores
+// Color values to convert to other colors for better readability on a light theme.
+class EditorColorMap {
+ // Godot Color values are used to avoid the ambiguity of strings
+ // (where "#ffffff", "fff", and "white" are all equivalent).
+ static HashMap<Color, Color> editor_color_map;
+
+public:
+ static void create();
+ static void add_color_pair(const String p_from_color, const String p_to_color);
+
+ static HashMap<Color, Color> &get() { return editor_color_map; };
+};
+
Ref<Theme> create_editor_theme(Ref<Theme> p_theme = nullptr);
Ref<Theme> create_custom_theme(Ref<Theme> p_theme = nullptr);
-Ref<ImageTexture> create_unscaled_default_project_icon();
+String get_default_project_icon();
#endif // EDITOR_THEMES_H
diff --git a/modules/mono/glue/arguments_vector.h b/editor/editor_title_bar.cpp
index 4405809887..06dcea1f8a 100644
--- a/modules/mono/glue/arguments_vector.h
+++ b/editor/editor_title_bar.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* arguments_vector.h */
+/* editor_title_bar.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,40 +28,59 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef ARGUMENTS_VECTOR_H
-#define ARGUMENTS_VECTOR_H
+#include "editor/editor_title_bar.h"
-#include "core/os/memory.h"
-
-template <typename T, int POOL_SIZE = 5>
-struct ArgumentsVector {
-private:
- T pool[POOL_SIZE];
- T *_ptr = nullptr;
- int size;
-
- ArgumentsVector() = delete;
- ArgumentsVector(const ArgumentsVector &) = delete;
-
-public:
- T *ptr() { return _ptr; }
- T &get(int p_idx) { return _ptr[p_idx]; }
- void set(int p_idx, const T &p_value) { _ptr[p_idx] = p_value; }
+void EditorTitleBar::input(const Ref<InputEvent> &p_event) {
+ if (!can_move) {
+ return;
+ }
- explicit ArgumentsVector(int p_size) :
- size(p_size) {
- if (p_size <= POOL_SIZE) {
- _ptr = pool;
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid() && moving) {
+ if ((mm->get_button_mask() & MouseButton::LEFT) == MouseButton::LEFT) {
+ Window *w = Object::cast_to<Window>(get_viewport());
+ if (w) {
+ Point2 mouse = DisplayServer::get_singleton()->mouse_get_position();
+ w->set_position(mouse - click_pos);
+ }
} else {
- _ptr = memnew_arr(T, p_size);
+ moving = false;
}
}
- ~ArgumentsVector() {
- if (size > POOL_SIZE) {
- memdelete_arr(_ptr);
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid() && has_point(mb->get_position())) {
+ Window *w = Object::cast_to<Window>(get_viewport());
+ if (w) {
+ if (mb->get_button_index() == MouseButton::LEFT) {
+ if (mb->is_pressed()) {
+ click_pos = DisplayServer::get_singleton()->mouse_get_position() - w->get_position();
+ moving = true;
+ } else {
+ moving = false;
+ }
+ }
+ if (mb->get_button_index() == MouseButton::LEFT && mb->is_double_click() && mb->is_pressed()) {
+ if (DisplayServer::get_singleton()->window_maximize_on_title_dbl_click()) {
+ if (w->get_mode() == Window::MODE_WINDOWED) {
+ w->set_mode(Window::MODE_MAXIMIZED);
+ } else if (w->get_mode() == Window::MODE_MAXIMIZED) {
+ w->set_mode(Window::MODE_WINDOWED);
+ }
+ } else if (DisplayServer::get_singleton()->window_minimize_on_title_dbl_click()) {
+ w->set_mode(Window::MODE_MINIMIZED);
+ }
+ moving = false;
+ }
}
}
-};
+}
+
+void EditorTitleBar::set_can_move_window(bool p_enabled) {
+ can_move = p_enabled;
+ set_process_input(can_move);
+}
-#endif // ARGUMENTS_VECTOR_H
+bool EditorTitleBar::get_can_move_window() const {
+ return can_move;
+}
diff --git a/modules/mono/utils/mono_reg_utils.h b/editor/editor_title_bar.h
index 5be60d4930..ad6ec37ac9 100644
--- a/modules/mono/utils/mono_reg_utils.h
+++ b/editor/editor_title_bar.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* mono_reg_utils.h */
+/* editor_title_bar.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,27 +28,26 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef MONO_REG_UTILS_H
-#define MONO_REG_UTILS_H
+#ifndef EDITOR_TITLE_BAR_H
+#define EDITOR_TITLE_BAR_H
-#ifdef WINDOWS_ENABLED
+#include "scene/gui/box_container.h"
+#include "scene/main/window.h"
-#include "core/string/ustring.h"
+class EditorTitleBar : public HBoxContainer {
+ GDCLASS(EditorTitleBar, HBoxContainer);
-struct MonoRegInfo {
- String version;
- String install_root_dir;
- String assembly_dir;
- String config_dir;
- String bin_dir;
-};
-
-namespace MonoRegUtils {
+ Point2i click_pos;
+ bool moving = false;
+ bool can_move = false;
-MonoRegInfo find_mono();
-String find_msbuild_tools_path();
-} // namespace MonoRegUtils
+protected:
+ virtual void input(const Ref<InputEvent> &p_event) override;
+ static void _bind_methods(){};
-#endif // WINDOWS_ENABLED
+public:
+ void set_can_move_window(bool p_enabled);
+ bool get_can_move_window() const;
+};
-#endif // MONO_REG_UTILS_H
+#endif // EDITOR_TITLE_BAR_H
diff --git a/editor/editor_toaster.cpp b/editor/editor_toaster.cpp
index 050cde6069..bb29b1c171 100644
--- a/editor/editor_toaster.cpp
+++ b/editor/editor_toaster.cpp
@@ -236,11 +236,11 @@ void EditorToaster::_auto_hide_or_free_toasts() {
}
if (toasts.is_empty()) {
- main_button->set_tooltip(TTR("No notifications."));
+ main_button->set_tooltip_text(TTR("No notifications."));
main_button->set_modulate(Color(0.5, 0.5, 0.5));
main_button->set_disabled(true);
} else {
- main_button->set_tooltip(TTR("Show notifications."));
+ main_button->set_tooltip_text(TTR("Show notifications."));
main_button->set_modulate(Color(1, 1, 1));
main_button->set_disabled(false);
}
@@ -341,7 +341,7 @@ void EditorToaster::_repop_old() {
Control *EditorToaster::popup(Control *p_control, Severity p_severity, double p_time, String p_tooltip) {
// Create the panel according to the severity.
PanelContainer *panel = memnew(PanelContainer);
- panel->set_tooltip(p_tooltip);
+ panel->set_tooltip_text(p_tooltip);
switch (p_severity) {
case SEVERITY_INFO:
panel->add_theme_style_override("panel", info_panel_style_background);
@@ -518,7 +518,7 @@ EditorToaster::EditorToaster() {
// Main button.
main_button = memnew(Button);
- main_button->set_tooltip(TTR("No notifications."));
+ main_button->set_tooltip_text(TTR("No notifications."));
main_button->set_modulate(Color(0.5, 0.5, 0.5));
main_button->set_disabled(true);
main_button->set_flat(true);
@@ -534,7 +534,7 @@ EditorToaster::EditorToaster() {
add_child(disable_notifications_panel);
disable_notifications_button = memnew(Button);
- disable_notifications_button->set_tooltip(TTR("Silence the notifications."));
+ disable_notifications_button->set_tooltip_text(TTR("Silence the notifications."));
disable_notifications_button->set_flat(true);
disable_notifications_button->connect("pressed", callable_mp(this, &EditorToaster::_set_notifications_enabled).bind(false));
disable_notifications_panel->add_child(disable_notifications_button);
diff --git a/editor/editor_undo_redo_manager.cpp b/editor/editor_undo_redo_manager.cpp
new file mode 100644
index 0000000000..eca2b3143b
--- /dev/null
+++ b/editor/editor_undo_redo_manager.cpp
@@ -0,0 +1,442 @@
+/*************************************************************************/
+/* editor_undo_redo_manager.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "editor_undo_redo_manager.h"
+
+#include "core/io/resource.h"
+#include "core/os/os.h"
+#include "core/templates/local_vector.h"
+#include "editor/editor_log.h"
+#include "editor/editor_node.h"
+#include "scene/main/node.h"
+
+EditorUndoRedoManager::History &EditorUndoRedoManager::get_or_create_history(int p_idx) {
+ if (!history_map.has(p_idx)) {
+ History history;
+ history.undo_redo = memnew(UndoRedo);
+ history.id = p_idx;
+ history_map[p_idx] = history;
+
+ EditorNode::get_singleton()->get_log()->register_undo_redo(history.undo_redo);
+ EditorDebuggerNode::get_singleton()->register_undo_redo(history.undo_redo);
+ }
+ return history_map[p_idx];
+}
+
+UndoRedo *EditorUndoRedoManager::get_history_undo_redo(int p_idx) const {
+ ERR_FAIL_COND_V(!history_map.has(p_idx), nullptr);
+ return history_map[p_idx].undo_redo;
+}
+
+int EditorUndoRedoManager::get_history_id_for_object(Object *p_object) const {
+ int history_id = INVALID_HISTORY;
+
+ if (Node *node = Object::cast_to<Node>(p_object)) {
+ Node *edited_scene = EditorNode::get_singleton()->get_edited_scene();
+
+ if (edited_scene && (node == edited_scene || edited_scene->is_ancestor_of(node))) {
+ int idx = EditorNode::get_singleton()->get_editor_data().get_current_edited_scene_history_id();
+ if (idx > 0) {
+ history_id = idx;
+ }
+ }
+ }
+
+ if (Resource *res = Object::cast_to<Resource>(p_object)) {
+ if (res->is_built_in()) {
+ if (res->get_path().is_empty()) {
+ int idx = EditorNode::get_singleton()->get_editor_data().get_current_edited_scene_history_id();
+ if (idx > 0) {
+ history_id = idx;
+ }
+ } else {
+ int idx = EditorNode::get_singleton()->get_editor_data().get_scene_history_id_from_path(res->get_path().get_slice("::", 0));
+ if (idx > 0) {
+ history_id = idx;
+ }
+ }
+ }
+ }
+
+ if (history_id == INVALID_HISTORY) {
+ if (pending_action.history_id != INVALID_HISTORY) {
+ history_id = pending_action.history_id;
+ } else {
+ history_id = GLOBAL_HISTORY;
+ }
+ }
+ return history_id;
+}
+
+EditorUndoRedoManager::History &EditorUndoRedoManager::get_history_for_object(Object *p_object) {
+ int history_id = get_history_id_for_object(p_object);
+ ERR_FAIL_COND_V_MSG(pending_action.history_id != INVALID_HISTORY && history_id != pending_action.history_id, get_or_create_history(pending_action.history_id), vformat("UndoRedo history mismatch: expected %d, got %d.", pending_action.history_id, history_id));
+
+ History &history = get_or_create_history(history_id);
+ if (pending_action.history_id == INVALID_HISTORY) {
+ pending_action.history_id = history_id;
+ history.undo_redo->create_action(pending_action.action_name, pending_action.merge_mode);
+ }
+
+ return history;
+}
+
+void EditorUndoRedoManager::create_action_for_history(const String &p_name, int p_history_id, UndoRedo::MergeMode p_mode) {
+ pending_action.action_name = p_name;
+ pending_action.timestamp = OS::get_singleton()->get_unix_time();
+ pending_action.merge_mode = p_mode;
+
+ if (p_history_id != INVALID_HISTORY) {
+ pending_action.history_id = p_history_id;
+ History &history = get_or_create_history(p_history_id);
+ history.undo_redo->create_action(pending_action.action_name, pending_action.merge_mode);
+ }
+}
+
+void EditorUndoRedoManager::create_action(const String &p_name, UndoRedo::MergeMode p_mode, Object *p_custom_context) {
+ create_action_for_history(p_name, INVALID_HISTORY, p_mode);
+
+ if (p_custom_context) {
+ // This assigns context to pending action.
+ get_history_for_object(p_custom_context);
+ }
+}
+
+void EditorUndoRedoManager::add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
+ UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo;
+ undo_redo->add_do_methodp(p_object, p_method, p_args, p_argcount);
+}
+
+void EditorUndoRedoManager::add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount) {
+ UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo;
+ undo_redo->add_undo_methodp(p_object, p_method, p_args, p_argcount);
+}
+
+void EditorUndoRedoManager::_add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ if (p_argcount < 2) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 0;
+ return;
+ }
+
+ if (p_args[0]->get_type() != Variant::OBJECT) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+ return;
+ }
+
+ if (p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 1;
+ r_error.expected = Variant::STRING_NAME;
+ return;
+ }
+
+ r_error.error = Callable::CallError::CALL_OK;
+
+ Object *object = *p_args[0];
+ StringName method = *p_args[1];
+
+ add_do_methodp(object, method, p_args + 2, p_argcount - 2);
+}
+
+void EditorUndoRedoManager::_add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ if (p_argcount < 2) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 0;
+ return;
+ }
+
+ if (p_args[0]->get_type() != Variant::OBJECT) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::OBJECT;
+ return;
+ }
+
+ if (p_args[1]->get_type() != Variant::STRING_NAME && p_args[1]->get_type() != Variant::STRING) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 1;
+ r_error.expected = Variant::STRING_NAME;
+ return;
+ }
+
+ r_error.error = Callable::CallError::CALL_OK;
+
+ Object *object = *p_args[0];
+ StringName method = *p_args[1];
+
+ add_undo_methodp(object, method, p_args + 2, p_argcount - 2);
+}
+
+void EditorUndoRedoManager::add_do_property(Object *p_object, const StringName &p_property, const Variant &p_value) {
+ UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo;
+ undo_redo->add_do_property(p_object, p_property, p_value);
+}
+
+void EditorUndoRedoManager::add_undo_property(Object *p_object, const StringName &p_property, const Variant &p_value) {
+ UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo;
+ undo_redo->add_undo_property(p_object, p_property, p_value);
+}
+
+void EditorUndoRedoManager::add_do_reference(Object *p_object) {
+ UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo;
+ undo_redo->add_do_reference(p_object);
+}
+
+void EditorUndoRedoManager::add_undo_reference(Object *p_object) {
+ UndoRedo *undo_redo = get_history_for_object(p_object).undo_redo;
+ undo_redo->add_undo_reference(p_object);
+}
+
+void EditorUndoRedoManager::commit_action(bool p_execute) {
+ ERR_FAIL_COND(pending_action.history_id == INVALID_HISTORY);
+ is_committing = true;
+
+ History &history = get_or_create_history(pending_action.history_id);
+ history.undo_redo->commit_action(p_execute);
+ history.redo_stack.clear();
+
+ if (!history.undo_stack.is_empty()) {
+ const Action &prev_action = history.undo_stack.back()->get();
+ if (pending_action.merge_mode != UndoRedo::MERGE_DISABLE && pending_action.merge_mode == prev_action.merge_mode && pending_action.action_name == prev_action.action_name) {
+ // Discard action if it should be merged (UndoRedo handles merging internally).
+ pending_action = Action();
+ is_committing = false;
+ return;
+ }
+ }
+
+ history.undo_stack.push_back(pending_action);
+ pending_action = Action();
+ is_committing = false;
+}
+
+bool EditorUndoRedoManager::is_committing_action() const {
+ return is_committing;
+}
+
+bool EditorUndoRedoManager::undo() {
+ if (!has_undo()) {
+ return false;
+ }
+
+ History *selected_history = nullptr;
+ double global_timestamp = 0;
+
+ // Pick the history with greatest last action timestamp (either global or current scene).
+ {
+ History &history = get_or_create_history(GLOBAL_HISTORY);
+ if (!history.undo_stack.is_empty()) {
+ selected_history = &history;
+ global_timestamp = history.undo_stack.back()->get().timestamp;
+ }
+ }
+
+ {
+ History &history = get_or_create_history(EditorNode::get_editor_data().get_current_edited_scene_history_id());
+ if (!history.undo_stack.is_empty() && history.undo_stack.back()->get().timestamp > global_timestamp) {
+ selected_history = &history;
+ }
+ }
+
+ if (selected_history) {
+ Action action = selected_history->undo_stack.back()->get();
+ selected_history->undo_stack.pop_back();
+ selected_history->redo_stack.push_back(action);
+ return selected_history->undo_redo->undo();
+ }
+ return false;
+}
+
+bool EditorUndoRedoManager::redo() {
+ if (!has_redo()) {
+ return false;
+ }
+
+ History *selected_history = nullptr;
+ double global_timestamp = INFINITY;
+
+ // Pick the history with lowest last action timestamp (either global or current scene).
+ {
+ History &history = get_or_create_history(GLOBAL_HISTORY);
+ if (!history.redo_stack.is_empty()) {
+ selected_history = &history;
+ global_timestamp = history.redo_stack.back()->get().timestamp;
+ }
+ }
+
+ {
+ History &history = get_or_create_history(EditorNode::get_editor_data().get_current_edited_scene_history_id());
+ if (!history.redo_stack.is_empty() && history.redo_stack.back()->get().timestamp < global_timestamp) {
+ selected_history = &history;
+ }
+ }
+
+ if (selected_history) {
+ Action action = selected_history->redo_stack.back()->get();
+ selected_history->redo_stack.pop_back();
+ selected_history->undo_stack.push_back(action);
+ return selected_history->undo_redo->redo();
+ }
+ return false;
+}
+
+void EditorUndoRedoManager::set_history_as_saved(int p_id) {
+ History &history = get_or_create_history(p_id);
+ history.saved_version = history.undo_redo->get_version();
+}
+
+void EditorUndoRedoManager::set_history_as_unsaved(int p_id) {
+ History &history = get_or_create_history(p_id);
+ history.saved_version = -1;
+}
+
+bool EditorUndoRedoManager::is_history_unsaved(int p_id) {
+ History &history = get_or_create_history(p_id);
+ return history.undo_redo->get_version() != history.saved_version;
+}
+
+bool EditorUndoRedoManager::has_undo() {
+ for (const KeyValue<int, History> &E : history_map) {
+ if ((E.key == GLOBAL_HISTORY || E.key == EditorNode::get_editor_data().get_current_edited_scene_history_id()) && !E.value.undo_stack.is_empty()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool EditorUndoRedoManager::has_redo() {
+ for (const KeyValue<int, History> &E : history_map) {
+ if ((E.key == GLOBAL_HISTORY || E.key == EditorNode::get_editor_data().get_current_edited_scene_history_id()) && !E.value.redo_stack.is_empty()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void EditorUndoRedoManager::clear_history(bool p_increase_version, int p_idx) {
+ if (p_idx != INVALID_HISTORY) {
+ get_or_create_history(p_idx).undo_redo->clear_history(p_increase_version);
+ if (!p_increase_version) {
+ set_history_as_saved(p_idx);
+ }
+ return;
+ }
+
+ for (const KeyValue<int, History> &E : history_map) {
+ E.value.undo_redo->clear_history(p_increase_version);
+ set_history_as_saved(E.key);
+ }
+}
+
+String EditorUndoRedoManager::get_current_action_name() {
+ if (has_undo()) {
+ History *selected_history = nullptr;
+ double global_timestamp = 0;
+
+ // Pick the history with greatest last action timestamp (either global or current scene).
+ {
+ History &history = get_or_create_history(GLOBAL_HISTORY);
+ if (!history.undo_stack.is_empty()) {
+ selected_history = &history;
+ global_timestamp = history.undo_stack.back()->get().timestamp;
+ }
+ }
+
+ {
+ History &history = get_or_create_history(EditorNode::get_editor_data().get_current_edited_scene_history_id());
+ if (!history.undo_stack.is_empty() && history.undo_stack.back()->get().timestamp > global_timestamp) {
+ selected_history = &history;
+ }
+ }
+
+ if (selected_history) {
+ return selected_history->undo_redo->get_current_action_name();
+ }
+ }
+ return "";
+}
+
+void EditorUndoRedoManager::discard_history(int p_idx, bool p_erase_from_map) {
+ ERR_FAIL_COND(!history_map.has(p_idx));
+ History &history = history_map[p_idx];
+
+ if (history.undo_redo) {
+ memdelete(history.undo_redo);
+ history.undo_redo = nullptr;
+ }
+
+ if (p_erase_from_map) {
+ history_map.erase(p_idx);
+ }
+}
+
+void EditorUndoRedoManager::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("create_action", "name", "merge_mode", "custom_context"), &EditorUndoRedoManager::create_action, DEFVAL(UndoRedo::MERGE_DISABLE), DEFVAL((Object *)nullptr));
+ ClassDB::bind_method(D_METHOD("commit_action", "execute"), &EditorUndoRedoManager::commit_action, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("is_committing_action"), &EditorUndoRedoManager::is_committing_action);
+
+ {
+ MethodInfo mi;
+ mi.name = "add_do_method";
+ mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "object"));
+ mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method"));
+
+ ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "add_do_method", &EditorUndoRedoManager::_add_do_method, mi, varray(), false);
+ }
+
+ {
+ MethodInfo mi;
+ mi.name = "add_undo_method";
+ mi.arguments.push_back(PropertyInfo(Variant::OBJECT, "object"));
+ mi.arguments.push_back(PropertyInfo(Variant::STRING_NAME, "method"));
+
+ ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "add_undo_method", &EditorUndoRedoManager::_add_undo_method, mi, varray(), false);
+ }
+
+ ClassDB::bind_method(D_METHOD("add_do_property", "object", "property", "value"), &EditorUndoRedoManager::add_do_property);
+ ClassDB::bind_method(D_METHOD("add_undo_property", "object", "property", "value"), &EditorUndoRedoManager::add_undo_property);
+ ClassDB::bind_method(D_METHOD("add_do_reference", "object"), &EditorUndoRedoManager::add_do_reference);
+ ClassDB::bind_method(D_METHOD("add_undo_reference", "object"), &EditorUndoRedoManager::add_undo_reference);
+
+ ClassDB::bind_method(D_METHOD("get_object_history_id", "object"), &EditorUndoRedoManager::get_history_id_for_object);
+ ClassDB::bind_method(D_METHOD("get_history_undo_redo", "id"), &EditorUndoRedoManager::get_history_undo_redo);
+
+ BIND_ENUM_CONSTANT(GLOBAL_HISTORY);
+ BIND_ENUM_CONSTANT(INVALID_HISTORY);
+}
+
+EditorUndoRedoManager::~EditorUndoRedoManager() {
+ for (const KeyValue<int, History> &E : history_map) {
+ discard_history(E.key, false);
+ }
+}
diff --git a/editor/editor_undo_redo_manager.h b/editor/editor_undo_redo_manager.h
new file mode 100644
index 0000000000..c4d85daa22
--- /dev/null
+++ b/editor/editor_undo_redo_manager.h
@@ -0,0 +1,134 @@
+/*************************************************************************/
+/* editor_undo_redo_manager.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef EDITOR_UNDO_REDO_MANAGER_H
+#define EDITOR_UNDO_REDO_MANAGER_H
+
+#include "core/object/class_db.h"
+#include "core/object/ref_counted.h"
+#include "core/object/undo_redo.h"
+
+class EditorUndoRedoManager : public RefCounted {
+ GDCLASS(EditorUndoRedoManager, RefCounted);
+
+public:
+ enum SpecialHistory {
+ GLOBAL_HISTORY = 0,
+ INVALID_HISTORY = -99,
+ };
+
+private:
+ struct Action {
+ int history_id = INVALID_HISTORY;
+ double timestamp = 0;
+ String action_name;
+ UndoRedo::MergeMode merge_mode = UndoRedo::MERGE_DISABLE;
+ };
+
+ struct History {
+ int id = INVALID_HISTORY;
+ UndoRedo *undo_redo = nullptr;
+ uint64_t saved_version = 1;
+ List<Action> undo_stack;
+ List<Action> redo_stack;
+ };
+
+ HashMap<int, History> history_map;
+ Action pending_action;
+
+ bool is_committing = false;
+
+protected:
+ static void _bind_methods();
+
+public:
+ History &get_or_create_history(int p_idx);
+ UndoRedo *get_history_undo_redo(int p_idx) const;
+ int get_history_id_for_object(Object *p_object) const;
+ History &get_history_for_object(Object *p_object);
+
+ void create_action_for_history(const String &p_name, int p_history_id, UndoRedo::MergeMode p_mode = UndoRedo::MERGE_DISABLE);
+ void create_action(const String &p_name = "", UndoRedo::MergeMode p_mode = UndoRedo::MERGE_DISABLE, Object *p_custom_context = nullptr);
+
+ void add_do_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount);
+ void add_undo_methodp(Object *p_object, const StringName &p_method, const Variant **p_args, int p_argcount);
+
+ template <typename... VarArgs>
+ void add_do_method(Object *p_object, const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+
+ add_do_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
+ template <typename... VarArgs>
+ void add_undo_method(Object *p_object, const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+
+ add_undo_methodp(p_object, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+ }
+
+ void _add_do_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+ void _add_undo_method(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
+
+ void add_do_property(Object *p_object, const StringName &p_property, const Variant &p_value);
+ void add_undo_property(Object *p_object, const StringName &p_property, const Variant &p_value);
+ void add_do_reference(Object *p_object);
+ void add_undo_reference(Object *p_object);
+
+ void commit_action(bool p_execute = true);
+ bool is_committing_action() const;
+
+ bool undo();
+ bool redo();
+ void clear_history(bool p_increase_version = true, int p_idx = INVALID_HISTORY);
+
+ void set_history_as_saved(int p_idx);
+ void set_history_as_unsaved(int p_idx);
+ bool is_history_unsaved(int p_idx);
+ bool has_undo();
+ bool has_redo();
+
+ String get_current_action_name();
+
+ void discard_history(int p_idx, bool p_erase_from_map = true);
+ ~EditorUndoRedoManager();
+};
+
+VARIANT_ENUM_CAST(EditorUndoRedoManager::SpecialHistory);
+
+#endif // EDITOR_UNDO_REDO_MANAGER_H
diff --git a/editor/editor_vcs_interface.cpp b/editor/editor_vcs_interface.cpp
index 3f2012cc16..53cc8d5b22 100644
--- a/editor/editor_vcs_interface.cpp
+++ b/editor/editor_vcs_interface.cpp
@@ -82,8 +82,8 @@ void EditorVCSInterface::_unstage_file(String p_file_path) {
void EditorVCSInterface::_commit(String p_msg) {
}
-Array EditorVCSInterface::_get_file_diff(String p_file_path) {
- return Array();
+TypedArray<Dictionary> EditorVCSInterface::_get_file_diff(String p_file_path) {
+ return TypedArray<Dictionary>();
}
bool EditorVCSInterface::_shut_down() {
@@ -133,11 +133,11 @@ void EditorVCSInterface::commit(String p_msg) {
}
}
-Array EditorVCSInterface::get_file_diff(String p_file_path) {
+TypedArray<Dictionary> EditorVCSInterface::get_file_diff(String p_file_path) {
if (is_addon_ready()) {
return call("_get_file_diff", p_file_path);
}
- return Array();
+ return TypedArray<Dictionary>();
}
bool EditorVCSInterface::shut_down() {
@@ -168,14 +168,14 @@ void EditorVCSInterface::set_singleton(EditorVCSInterface *p_singleton) {
void EditorVCSInterface::create_vcs_metadata_files(VCSMetadata p_vcs_metadata_type, String &p_dir) {
if (p_vcs_metadata_type == VCSMetadata::GIT) {
- Ref<FileAccess> f = FileAccess::open(p_dir.plus_file(".gitignore"), FileAccess::WRITE);
+ Ref<FileAccess> f = FileAccess::open(p_dir.path_join(".gitignore"), FileAccess::WRITE);
if (f.is_null()) {
ERR_FAIL_MSG(TTR("Couldn't create .gitignore in project path."));
} else {
f->store_line("# Godot 4+ specific ignores");
f->store_line(".godot/");
}
- f = FileAccess::open(p_dir.plus_file(".gitattributes"), FileAccess::WRITE);
+ f = FileAccess::open(p_dir.path_join(".gitattributes"), FileAccess::WRITE);
if (f.is_null()) {
ERR_FAIL_MSG(TTR("Couldn't create .gitattributes in project path."));
} else {
diff --git a/editor/editor_vcs_interface.h b/editor/editor_vcs_interface.h
index 6a6fca7eba..d6d7ffa0e9 100644
--- a/editor/editor_vcs_interface.h
+++ b/editor/editor_vcs_interface.h
@@ -52,7 +52,7 @@ protected:
virtual void _stage_file(String p_file_path);
virtual void _unstage_file(String p_file_path);
virtual void _commit(String p_msg);
- virtual Array _get_file_diff(String p_file_path);
+ virtual TypedArray<Dictionary> _get_file_diff(String p_file_path);
virtual bool _shut_down();
virtual String _get_project_name();
virtual String _get_vcs_name();
@@ -76,7 +76,7 @@ public:
void stage_file(String p_file_path);
void unstage_file(String p_file_path);
void commit(String p_msg);
- Array get_file_diff(String p_file_path);
+ TypedArray<Dictionary> get_file_diff(String p_file_path);
bool shut_down();
String get_project_name();
String get_vcs_name();
diff --git a/editor/export/editor_export.cpp b/editor/export/editor_export.cpp
index 31f408eedb..d291040bd2 100644
--- a/editor/export/editor_export.cpp
+++ b/editor/export/editor_export.cpp
@@ -312,12 +312,14 @@ void EditorExport::update_export_presets() {
// Clear the preset properties and values prior to reloading
preset->properties.clear();
preset->values.clear();
+ preset->update_visibility.clear();
for (const EditorExportPlatform::ExportOption &E : options) {
preset->properties.push_back(E.option);
StringName option_name = E.option.name;
preset->values[option_name] = previous_values.has(option_name) ? previous_values[option_name] : E.default_value;
+ preset->update_visibility[option_name] = E.update_visibility;
}
}
}
diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp
index 34b407779e..e07b5e4cdb 100644
--- a/editor/export/editor_export_platform.cpp
+++ b/editor/export/editor_export_platform.cpp
@@ -295,7 +295,7 @@ Ref<ImageTexture> EditorExportPlatform::get_option_icon(int p_index) const {
String EditorExportPlatform::find_export_template(String template_file_name, String *err) const {
String current_version = VERSION_FULL_CONFIG;
- String template_path = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(current_version).plus_file(template_file_name);
+ String template_path = EditorPaths::get_singleton()->get_export_templates_dir().path_join(current_version).path_join(template_file_name);
if (FileAccess::exists(template_path)) {
return template_path;
@@ -323,6 +323,7 @@ Ref<EditorExportPreset> EditorExportPlatform::create_preset() {
for (const ExportOption &E : options) {
preset->properties.push_back(E.option);
preset->values[E.option.name] = E.default_value;
+ preset->update_visibility[E.option.name] = E.update_visibility;
}
return preset;
@@ -429,24 +430,21 @@ void EditorExportPlatform::_edit_filter_list(HashSet<String> &r_list, const Stri
_edit_files_with_filter(da, filters, r_list, exclude);
}
-EditorExportPlatform::FeatureContainers EditorExportPlatform::get_feature_containers(const Ref<EditorExportPreset> &p_preset, bool p_debug) const {
+HashSet<String> EditorExportPlatform::get_features(const Ref<EditorExportPreset> &p_preset, bool p_debug) const {
Ref<EditorExportPlatform> platform = p_preset->get_platform();
List<String> feature_list;
platform->get_platform_features(&feature_list);
platform->get_preset_features(p_preset, &feature_list);
- FeatureContainers result;
+ HashSet<String> result;
for (const String &E : feature_list) {
- result.features.insert(E);
- result.features_pv.push_back(E);
+ result.insert(E);
}
if (p_debug) {
- result.features.insert("debug");
- result.features_pv.push_back("debug");
+ result.insert("debug");
} else {
- result.features.insert("release");
- result.features_pv.push_back("release");
+ result.insert("release");
}
if (!p_preset->get_custom_features().is_empty()) {
@@ -455,8 +453,7 @@ EditorExportPlatform::FeatureContainers EditorExportPlatform::get_feature_contai
for (int i = 0; i < tmp_custom_list.size(); i++) {
String f = tmp_custom_list[i].strip_edges();
if (!f.is_empty()) {
- result.features.insert(f);
- result.features_pv.push_back(f);
+ result.insert(f);
}
}
}
@@ -465,14 +462,18 @@ EditorExportPlatform::FeatureContainers EditorExportPlatform::get_feature_contai
}
EditorExportPlatform::ExportNotifier::ExportNotifier(EditorExportPlatform &p_platform, const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
- FeatureContainers features = p_platform.get_feature_containers(p_preset, p_debug);
+ HashSet<String> features = p_platform.get_features(p_preset, p_debug);
Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
//initial export plugin callback
for (int i = 0; i < export_plugins.size(); i++) {
if (export_plugins[i]->get_script_instance()) { //script based
- export_plugins.write[i]->_export_begin_script(features.features_pv, p_debug, p_path, p_flags);
+ PackedStringArray features_psa;
+ for (const String &feature : features) {
+ features_psa.push_back(feature);
+ }
+ export_plugins.write[i]->_export_begin_script(features_psa, p_debug, p_path, p_flags);
} else {
- export_plugins.write[i]->_export_begin(features.features, p_debug, p_path, p_flags);
+ export_plugins.write[i]->_export_begin(features, p_debug, p_path, p_flags);
}
}
}
@@ -621,9 +622,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
export_plugins.write[i]->_clear();
}
- FeatureContainers feature_containers = get_feature_containers(p_preset, p_debug);
- HashSet<String> &features = feature_containers.features;
- Vector<String> &features_pv = feature_containers.features_pv;
+ HashSet<String> features = get_features(p_preset, p_debug);
//store everything in the export medium
int idx = 0;
@@ -709,7 +708,11 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
bool do_export = true;
for (int i = 0; i < export_plugins.size(); i++) {
if (export_plugins[i]->get_script_instance()) { //script based
- export_plugins.write[i]->_export_file_script(path, type, features_pv);
+ PackedStringArray features_psa;
+ for (const String &feature : features) {
+ features_psa.push_back(feature);
+ }
+ export_plugins.write[i]->_export_file_script(path, type, features_psa);
} else {
export_plugins.write[i]->_export_file(path, type, features);
}
@@ -845,7 +848,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
}
} else {
// Use default text server data.
- String icu_data_file = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_icu_data");
+ String icu_data_file = EditorPaths::get_singleton()->get_cache_dir().path_join("tmp_icu_data");
TS->save_support_data(icu_data_file);
Vector<uint8_t> array = FileAccess::get_file_as_array(icu_data_file);
err = p_func(p_udata, ts_data, array, idx, total, enc_in_filters, enc_ex_filters, key);
@@ -858,7 +861,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
}
String config_file = "project.binary";
- String engine_cfb = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp" + config_file);
+ String engine_cfb = EditorPaths::get_singleton()->get_cache_dir().path_join("tmp" + config_file);
ProjectSettings::get_singleton()->save_custom(engine_cfb, custom_map, custom_list);
Vector<uint8_t> data = FileAccess::get_file_as_array(engine_cfb);
DirAccess::remove_file_or_error(engine_cfb);
@@ -882,7 +885,7 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, b
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
da->make_dir_recursive(EditorPaths::get_singleton()->get_cache_dir());
- String tmppath = EditorPaths::get_singleton()->get_cache_dir().plus_file("packtmp");
+ String tmppath = EditorPaths::get_singleton()->get_cache_dir().path_join("packtmp");
Ref<FileAccess> ftmp = FileAccess::open(tmppath, FileAccess::WRITE);
if (ftmp.is_null()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Save PCK"), vformat(TTR("Cannot create file \"%s\"."), tmppath));
@@ -1174,5 +1177,23 @@ void EditorExportPlatform::gen_export_flags(Vector<String> &r_flags, int p_flags
}
}
+bool EditorExportPlatform::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+ String templates_error;
+ bool valid_export_configuration = has_valid_export_configuration(p_preset, templates_error, r_missing_templates);
+
+ String project_configuration_error;
+ bool valid_project_configuration = has_valid_project_configuration(p_preset, project_configuration_error);
+
+ if (!templates_error.is_empty()) {
+ r_error += templates_error;
+ }
+
+ if (!project_configuration_error.is_empty()) {
+ r_error += project_configuration_error;
+ }
+
+ return valid_export_configuration && valid_project_configuration;
+}
+
EditorExportPlatform::EditorExportPlatform() {
}
diff --git a/editor/export/editor_export_platform.h b/editor/export/editor_export_platform.h
index 832a0cf846..bbdb47e041 100644
--- a/editor/export/editor_export_platform.h
+++ b/editor/export/editor_export_platform.h
@@ -85,11 +85,6 @@ private:
EditorProgress *ep = nullptr;
};
- struct FeatureContainers {
- HashSet<String> features;
- Vector<String> features_pv;
- };
-
Vector<ExportMessage> messages;
void _export_find_resources(EditorFileSystemDirectory *p_dir, HashSet<String> &p_paths);
@@ -110,7 +105,7 @@ protected:
~ExportNotifier();
};
- FeatureContainers get_feature_containers(const Ref<EditorExportPreset> &p_preset, bool p_debug) const;
+ HashSet<String> get_features(const Ref<EditorExportPreset> &p_preset, bool p_debug) const;
bool exists_export_template(String template_file_name, String *err) const;
String find_export_template(String template_file_name, String *err = nullptr) const;
@@ -122,10 +117,12 @@ public:
struct ExportOption {
PropertyInfo option;
Variant default_value;
+ bool update_visibility = false;
- ExportOption(const PropertyInfo &p_info, const Variant &p_default) :
+ ExportOption(const PropertyInfo &p_info, const Variant &p_default, bool p_update_visibility = false) :
option(p_info),
- default_value(p_default) {
+ default_value(p_default),
+ update_visibility(p_update_visibility) {
}
ExportOption() {}
};
@@ -141,13 +138,13 @@ public:
messages.push_back(msg);
switch (p_type) {
case EXPORT_MESSAGE_INFO: {
- print_line(vformat("%s: %s\n", msg.category, msg.text));
+ print_line(vformat("%s: %s", msg.category, msg.text));
} break;
case EXPORT_MESSAGE_WARNING: {
- WARN_PRINT(vformat("%s: %s\n", msg.category, msg.text));
+ WARN_PRINT(vformat("%s: %s", msg.category, msg.text));
} break;
case EXPORT_MESSAGE_ERROR: {
- ERR_PRINT(vformat("%s: %s\n", msg.category, msg.text));
+ ERR_PRINT(vformat("%s: %s", msg.category, msg.text));
} break;
default:
break;
@@ -175,7 +172,7 @@ public:
virtual void get_export_options(List<ExportOption> *r_options) = 0;
virtual bool should_update_export_options() { return false; }
- virtual bool get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const { return true; }
+ virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const { return true; }
virtual String get_os_name() const = 0;
virtual String get_name() const = 0;
@@ -205,7 +202,9 @@ public:
virtual Ref<Texture2D> get_run_icon() const { return get_logo(); }
String test_etc2() const;
- virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const = 0;
+ bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const;
+ virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const = 0;
+ virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const = 0;
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const = 0;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) = 0;
diff --git a/editor/export/editor_export_platform_pc.cpp b/editor/export/editor_export_platform_pc.cpp
index 5e0044f2ae..8538414523 100644
--- a/editor/export/editor_export_platform_pc.cpp
+++ b/editor/export/editor_export_platform_pc.cpp
@@ -75,7 +75,7 @@ Ref<Texture2D> EditorExportPlatformPC::get_logo() const {
return logo;
}
-bool EditorExportPlatformPC::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+bool EditorExportPlatformPC::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
String err;
bool valid = false;
@@ -106,6 +106,10 @@ bool EditorExportPlatformPC::can_export(const Ref<EditorExportPreset> &p_preset,
return valid;
}
+bool EditorExportPlatformPC::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const {
+ return true;
+}
+
Error EditorExportPlatformPC::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
@@ -181,9 +185,9 @@ Error EditorExportPlatformPC::export_project_data(const Ref<EditorExportPreset>
String src_path = ProjectSettings::get_singleton()->globalize_path(so_files[i].path);
String target_path;
if (so_files[i].target.is_empty()) {
- target_path = p_path.get_base_dir().plus_file(src_path.get_file());
+ target_path = p_path.get_base_dir().path_join(src_path.get_file());
} else {
- target_path = p_path.get_base_dir().plus_file(so_files[i].target).plus_file(src_path.get_file());
+ target_path = p_path.get_base_dir().path_join(so_files[i].target).path_join(src_path.get_file());
}
if (da->dir_exists(src_path)) {
diff --git a/editor/export/editor_export_platform_pc.h b/editor/export/editor_export_platform_pc.h
index bdb86e924a..cf96db6c2d 100644
--- a/editor/export/editor_export_platform_pc.h
+++ b/editor/export/editor_export_platform_pc.h
@@ -52,7 +52,8 @@ public:
virtual String get_os_name() const override;
virtual Ref<Texture2D> get_logo() const override;
- virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path);
virtual String get_template_file_name(const String &p_target, const String &p_arch) const = 0;
diff --git a/editor/export/editor_export_plugin.cpp b/editor/export/editor_export_plugin.cpp
index cf3a9b0810..27a671a919 100644
--- a/editor/export/editor_export_plugin.cpp
+++ b/editor/export/editor_export_plugin.cpp
@@ -181,7 +181,7 @@ void EditorExportTextSceneToBinaryPlugin::_export_file(const String &p_path, con
if (!convert) {
return;
}
- String tmp_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpfile.res");
+ String tmp_path = EditorPaths::get_singleton()->get_cache_dir().path_join("tmpfile.res");
Error err = ResourceFormatLoaderText::convert_file_to_binary(p_path, tmp_path);
if (err != OK) {
DirAccess::remove_file_or_error(tmp_path);
diff --git a/editor/export/editor_export_preset.cpp b/editor/export/editor_export_preset.cpp
index cdf69e727d..4411ad11bc 100644
--- a/editor/export/editor_export_preset.cpp
+++ b/editor/export/editor_export_preset.cpp
@@ -34,6 +34,9 @@ bool EditorExportPreset::_set(const StringName &p_name, const Variant &p_value)
if (values.has(p_name)) {
values[p_name] = p_value;
EditorExport::singleton->save_presets();
+ if (update_visibility[p_name]) {
+ notify_property_list_changed();
+ }
return true;
}
@@ -51,7 +54,7 @@ bool EditorExportPreset::_get(const StringName &p_name, Variant &r_ret) const {
void EditorExportPreset::_get_property_list(List<PropertyInfo> *p_list) const {
for (const PropertyInfo &E : properties) {
- if (platform->get_export_option_visibility(E.name, values)) {
+ if (platform->get_export_option_visibility(this, E.name, values)) {
p_list->push_back(E);
}
}
diff --git a/editor/export/editor_export_preset.h b/editor/export/editor_export_preset.h
index 00109396b0..0c780c45cd 100644
--- a/editor/export/editor_export_preset.h
+++ b/editor/export/editor_export_preset.h
@@ -67,6 +67,7 @@ private:
List<PropertyInfo> properties;
HashMap<StringName, Variant> values;
+ HashMap<StringName, bool> update_visibility;
String name;
diff --git a/editor/export/export_template_manager.cpp b/editor/export/export_template_manager.cpp
index a7d9d7f068..0ecbc9a8a3 100644
--- a/editor/export/export_template_manager.cpp
+++ b/editor/export/export_template_manager.cpp
@@ -91,7 +91,7 @@ void ExportTemplateManager::_update_template_status() {
install_options_vb->show();
if (templates.has(current_version)) {
- current_installed_path->set_text(templates_dir.plus_file(current_version));
+ current_installed_path->set_text(templates_dir.path_join(current_version));
}
}
@@ -146,7 +146,7 @@ void ExportTemplateManager::_download_template(const String &p_url, bool p_skip_
download_progress_hb->show();
_set_current_progress_status(TTR("Starting the download..."));
- download_templates->set_download_file(EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_templates.tpz"));
+ download_templates->set_download_file(EditorPaths::get_singleton()->get_cache_dir().path_join("tmp_templates.tpz"));
download_templates->set_use_threads(true);
const String proxy_host = EDITOR_GET("network/http_proxy/host");
@@ -440,7 +440,7 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_
}
Ref<DirAccess> d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- String template_path = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(version);
+ String template_path = EditorPaths::get_singleton()->get_export_templates_dir().path_join(version);
Error err = d->make_dir_recursive(template_path);
if (err != OK) {
EditorNode::get_singleton()->show_warning(TTR("Error creating path for extracting templates:") + "\n" + template_path);
@@ -486,12 +486,12 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_
if (base_dir != contents_dir && base_dir.begins_with(contents_dir)) {
base_dir = base_dir.substr(contents_dir.length(), file_path.length()).trim_prefix("/");
- file = base_dir.plus_file(file);
+ file = base_dir.path_join(file);
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
ERR_CONTINUE(da.is_null());
- String output_dir = template_path.plus_file(base_dir);
+ String output_dir = template_path.path_join(base_dir);
if (!DirAccess::exists(output_dir)) {
Error mkdir_err = da->make_dir_recursive(output_dir);
@@ -503,7 +503,7 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_
p->step(TTR("Importing:") + " " + file, fc);
}
- String to_write = template_path.plus_file(file);
+ String to_write = template_path.path_join(file);
Ref<FileAccess> f = FileAccess::open(to_write, FileAccess::WRITE);
if (f.is_null()) {
@@ -544,14 +544,14 @@ void ExportTemplateManager::_uninstall_template_confirmed() {
Error err = da->change_dir(templates_dir);
ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir + "'.");
err = da->change_dir(uninstall_version);
- ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir.plus_file(uninstall_version) + "'.");
+ ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir.path_join(uninstall_version) + "'.");
err = da->erase_contents_recursive();
- ERR_FAIL_COND_MSG(err != OK, "Could not remove all templates in '" + templates_dir.plus_file(uninstall_version) + "'.");
+ ERR_FAIL_COND_MSG(err != OK, "Could not remove all templates in '" + templates_dir.path_join(uninstall_version) + "'.");
da->change_dir("..");
err = da->remove(uninstall_version);
- ERR_FAIL_COND_MSG(err != OK, "Could not remove templates directory at '" + templates_dir.plus_file(uninstall_version) + "'.");
+ ERR_FAIL_COND_MSG(err != OK, "Could not remove templates directory at '" + templates_dir.path_join(uninstall_version) + "'.");
_update_template_status();
}
@@ -618,7 +618,7 @@ void ExportTemplateManager::_installed_table_button_cbk(Object *p_item, int p_co
void ExportTemplateManager::_open_template_folder(const String &p_version) {
const String &templates_dir = EditorPaths::get_singleton()->get_export_templates_dir();
- OS::get_singleton()->shell_open("file://" + templates_dir.plus_file(p_version));
+ OS::get_singleton()->shell_open("file://" + templates_dir.path_join(p_version));
}
void ExportTemplateManager::popup_manager() {
@@ -641,13 +641,13 @@ void ExportTemplateManager::_hide_dialog() {
}
bool ExportTemplateManager::can_install_android_template() {
- const String templates_dir = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(VERSION_FULL_CONFIG);
- return FileAccess::exists(templates_dir.plus_file("android_source.zip"));
+ const String templates_dir = EditorPaths::get_singleton()->get_export_templates_dir().path_join(VERSION_FULL_CONFIG);
+ return FileAccess::exists(templates_dir.path_join("android_source.zip"));
}
Error ExportTemplateManager::install_android_template() {
- const String &templates_path = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(VERSION_FULL_CONFIG);
- const String &source_zip = templates_path.plus_file("android_source.zip");
+ const String &templates_path = EditorPaths::get_singleton()->get_export_templates_dir().path_join(VERSION_FULL_CONFIG);
+ const String &source_zip = templates_path.path_join("android_source.zip");
ERR_FAIL_COND_V(!FileAccess::exists(source_zip), ERR_CANT_OPEN);
return install_android_template_from_file(source_zip);
}
@@ -723,11 +723,11 @@ Error ExportTemplateManager::install_android_template_from_file(const String &p_
unzCloseCurrentFile(pkg);
if (!dirs_tested.has(base_dir)) {
- da->make_dir_recursive(String("android/build").plus_file(base_dir));
+ da->make_dir_recursive(String("android/build").path_join(base_dir));
dirs_tested.insert(base_dir);
}
- String to_write = String("res://android/build").plus_file(path);
+ String to_write = String("res://android/build").path_join(path);
Ref<FileAccess> f = FileAccess::open(to_write, FileAccess::WRITE);
if (f.is_valid()) {
f->store_buffer(data.ptr(), data.size());
@@ -868,13 +868,13 @@ ExportTemplateManager::ExportTemplateManager() {
current_open_button = memnew(Button);
current_open_button->set_text(TTR("Open Folder"));
- current_open_button->set_tooltip(TTR("Open the folder containing installed templates for the current version."));
+ current_open_button->set_tooltip_text(TTR("Open the folder containing installed templates for the current version."));
current_installed_hb->add_child(current_open_button);
current_open_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_open_template_folder).bind(VERSION_FULL_CONFIG));
current_uninstall_button = memnew(Button);
current_uninstall_button->set_text(TTR("Uninstall"));
- current_uninstall_button->set_tooltip(TTR("Uninstall templates for the current version."));
+ current_uninstall_button->set_tooltip_text(TTR("Uninstall templates for the current version."));
current_installed_hb->add_child(current_uninstall_button);
current_uninstall_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_uninstall_template).bind(VERSION_FULL_CONFIG));
@@ -915,14 +915,14 @@ ExportTemplateManager::ExportTemplateManager() {
Button *download_current_button = memnew(Button);
download_current_button->set_text(TTR("Download and Install"));
- download_current_button->set_tooltip(TTR("Download and install templates for the current version from the best possible mirror."));
+ download_current_button->set_tooltip_text(TTR("Download and install templates for the current version from the best possible mirror."));
download_install_hb->add_child(download_current_button);
download_current_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_download_current));
// Update downloads buttons to prevent unsupported downloads.
if (!downloads_available) {
download_current_button->set_disabled(true);
- download_current_button->set_tooltip(TTR("Official export templates aren't available for development builds."));
+ download_current_button->set_tooltip_text(TTR("Official export templates aren't available for development builds."));
}
HBoxContainer *install_file_hb = memnew(HBoxContainer);
@@ -931,7 +931,7 @@ ExportTemplateManager::ExportTemplateManager() {
install_file_button = memnew(Button);
install_file_button->set_text(TTR("Install from File"));
- install_file_button->set_tooltip(TTR("Install templates from a local file."));
+ install_file_button->set_tooltip_text(TTR("Install templates from a local file."));
install_file_hb->add_child(install_file_button);
install_file_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_install_file));
@@ -956,7 +956,7 @@ ExportTemplateManager::ExportTemplateManager() {
Button *download_cancel_button = memnew(Button);
download_cancel_button->set_text(TTR("Cancel"));
- download_cancel_button->set_tooltip(TTR("Cancel the download of the templates."));
+ download_cancel_button->set_tooltip_text(TTR("Cancel the download of the templates."));
download_progress_hb->add_child(download_cancel_button);
download_cancel_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_cancel_template_download));
diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp
index a20f19efc8..00a0e08d3a 100644
--- a/editor/export/project_export.cpp
+++ b/editor/export/project_export.cpp
@@ -38,6 +38,7 @@
#include "editor/editor_properties.h"
#include "editor/editor_scale.h"
#include "editor/export/editor_export.h"
+#include "scene/gui/check_button.h"
#include "scene/gui/link_button.h"
#include "scene/gui/tree.h"
@@ -184,9 +185,9 @@ void ProjectExportDialog::_update_export_all() {
export_all_button->set_disabled(!can_export);
if (can_export) {
- export_all_button->set_tooltip(TTR("Export the project for all the presets defined."));
+ export_all_button->set_tooltip_text(TTR("Export the project for all the presets defined."));
} else {
- export_all_button->set_tooltip(TTR("All presets must have an export path defined for Export All to work."));
+ export_all_button->set_tooltip_text(TTR("All presets must have an export path defined for Export All to work."));
}
}
@@ -218,6 +219,7 @@ void ProjectExportDialog::_edit_preset(int p_index) {
export_path->show();
duplicate_preset->set_disabled(false);
delete_preset->set_disabled(false);
+ get_ok_button()->set_disabled(false);
name->set_text(current->get_name());
List<String> extension_list = current->get_platform()->get_binary_extensions(current);
@@ -264,7 +266,6 @@ void ProjectExportDialog::_edit_preset(int p_index) {
export_warning->hide();
export_button->set_disabled(true);
- get_ok_button()->set_disabled(true);
} else {
if (error != String()) {
Vector<String> items = error.split("\n", false);
@@ -284,7 +285,6 @@ void ProjectExportDialog::_edit_preset(int p_index) {
export_error->hide();
export_templates_error->hide();
export_button->set_disabled(false);
- get_ok_button()->set_disabled(false);
}
custom_features->set_text(current->get_custom_features());
@@ -1020,12 +1020,12 @@ ProjectExportDialog::ProjectExportDialog() {
mc->add_child(presets);
presets->connect("item_selected", callable_mp(this, &ProjectExportDialog::_edit_preset));
duplicate_preset = memnew(Button);
- duplicate_preset->set_tooltip(TTR("Duplicate"));
+ duplicate_preset->set_tooltip_text(TTR("Duplicate"));
duplicate_preset->set_flat(true);
preset_hb->add_child(duplicate_preset);
duplicate_preset->connect("pressed", callable_mp(this, &ProjectExportDialog::_duplicate_preset));
delete_preset = memnew(Button);
- delete_preset->set_tooltip(TTR("Delete"));
+ delete_preset->set_tooltip_text(TTR("Delete"));
delete_preset->set_flat(true);
preset_hb->add_child(delete_preset);
delete_preset->connect("pressed", callable_mp(this, &ProjectExportDialog::_delete_preset));
@@ -1041,7 +1041,7 @@ ProjectExportDialog::ProjectExportDialog() {
name->connect("text_changed", callable_mp(this, &ProjectExportDialog::_name_changed));
runnable = memnew(CheckButton);
runnable->set_text(TTR("Runnable"));
- runnable->set_tooltip(TTR("If checked, the preset will be available for use in one-click deploy.\nOnly one preset per platform may be marked as runnable."));
+ runnable->set_tooltip_text(TTR("If checked, the preset will be available for use in one-click deploy.\nOnly one preset per platform may be marked as runnable."));
runnable->connect("pressed", callable_mp(this, &ProjectExportDialog::_runnable_pressed));
settings_vb->add_child(runnable);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 6638e2f42f..ffe9b8130b 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -146,7 +146,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory
file_item->set_text(0, fi.name);
file_item->set_structured_text_bidi_override(0, TextServer::STRUCTURED_TEXT_FILE);
file_item->set_icon(0, _get_tree_item_icon(!fi.import_broken, fi.type));
- String file_metadata = lpath.plus_file(fi.name);
+ String file_metadata = lpath.path_join(fi.name);
file_item->set_metadata(0, file_metadata);
if (!p_select_in_favorites && path == file_metadata) {
file_item->select(0);
@@ -614,11 +614,11 @@ void FileSystemDock::_set_file_display(bool p_active) {
if (p_active) {
file_list_display_mode = FILE_LIST_DISPLAY_LIST;
button_file_list_display_mode->set_icon(get_theme_icon(SNAME("FileThumbnail"), SNAME("EditorIcons")));
- button_file_list_display_mode->set_tooltip(TTR("View items as a grid of thumbnails."));
+ button_file_list_display_mode->set_tooltip_text(TTR("View items as a grid of thumbnails."));
} else {
file_list_display_mode = FILE_LIST_DISPLAY_THUMBNAILS;
button_file_list_display_mode->set_icon(get_theme_icon(SNAME("FileList"), SNAME("EditorIcons")));
- button_file_list_display_mode->set_tooltip(TTR("View items as a list."));
+ button_file_list_display_mode->set_tooltip_text(TTR("View items as a list."));
}
_update_file_list(true);
@@ -867,7 +867,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
String dname = efd->get_subdir(i)->get_name();
files->add_item(dname, folder_icon, true);
- files->set_item_metadata(-1, directory.plus_file(dname) + "/");
+ files->set_item_metadata(-1, directory.path_join(dname) + "/");
files->set_item_icon_modulate(-1, folder_color);
if (cselection.has(dname)) {
@@ -880,7 +880,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) {
for (int i = 0; i < efd->get_file_count(); i++) {
FileInfo fi;
fi.name = efd->get_file(i);
- fi.path = directory.plus_file(fi.name);
+ fi.path = directory.path_join(fi.name);
fi.type = efd->get_file_type(i);
fi.import_broken = !efd->get_file_import_is_valid(i);
fi.modified_time = efd->get_file_modified_time(i);
@@ -1531,14 +1531,13 @@ void FileSystemDock::_folder_removed(String p_folder) {
void FileSystemDock::_rename_operation_confirm() {
String new_name = rename_dialog_text->get_text().strip_edges();
- String old_name = tree->get_selected()->get_text(0);
if (new_name.length() == 0) {
EditorNode::get_singleton()->show_warning(TTR("No name provided."));
return;
} else if (new_name.contains("/") || new_name.contains("\\") || new_name.contains(":")) {
EditorNode::get_singleton()->show_warning(TTR("Name contains invalid characters."));
return;
- } else if (to_rename.is_file && old_name.get_extension() != new_name.get_extension()) {
+ } else if (to_rename.is_file && to_rename.path.get_extension() != new_name.get_extension()) {
if (!EditorFileSystem::get_singleton()->get_valid_extensions().find(new_name.get_extension())) {
EditorNode::get_singleton()->show_warning(TTR("This file extension is not recognized by the editor.\nIf you want to rename it anyway, use your operating system's file manager.\nAfter renaming to an unknown extension, the file won't be shown in the editor anymore."));
return;
@@ -1546,7 +1545,7 @@ void FileSystemDock::_rename_operation_confirm() {
}
String old_path = to_rename.path.ends_with("/") ? to_rename.path.substr(0, to_rename.path.length() - 1) : to_rename.path;
- String new_path = old_path.get_base_dir().plus_file(new_name);
+ String new_path = old_path.get_base_dir().path_join(new_name);
if (old_path == new_path) {
return;
}
@@ -1606,7 +1605,7 @@ void FileSystemDock::_duplicate_operation_confirm() {
base_dir = base_dir.get_base_dir();
}
- String new_path = base_dir.plus_file(new_name);
+ String new_path = base_dir.path_join(new_name);
// Present a more user friendly warning for name conflict
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
@@ -1631,7 +1630,7 @@ Vector<String> FileSystemDock::_check_existing() {
String &p_to_path = to_move_path;
for (int i = 0; i < to_move.size(); i++) {
String ol_pth = to_move[i].path.ends_with("/") ? to_move[i].path.substr(0, to_move[i].path.length() - 1) : to_move[i].path;
- String p_new_path = p_to_path.plus_file(ol_pth.get_file());
+ String p_new_path = p_to_path.path_join(ol_pth.get_file());
FileOrFolder p_item = to_move[i];
String old_path = (p_item.is_file || p_item.path.ends_with("/")) ? p_item.path : (p_item.path + "/");
@@ -1663,7 +1662,7 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_ove
// Check groups.
for (int i = 0; i < to_move.size(); i++) {
if (to_move[i].is_file && EditorFileSystem::get_singleton()->is_group_file(to_move[i].path)) {
- EditorFileSystem::get_singleton()->move_group_file(to_move[i].path, p_to_path.plus_file(to_move[i].path.get_file()));
+ EditorFileSystem::get_singleton()->move_group_file(to_move[i].path, p_to_path.path_join(to_move[i].path.get_file()));
}
}
@@ -1672,7 +1671,7 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_ove
bool is_moved = false;
for (int i = 0; i < to_move.size(); i++) {
String old_path = to_move[i].path.ends_with("/") ? to_move[i].path.substr(0, to_move[i].path.length() - 1) : to_move[i].path;
- String new_path = p_to_path.plus_file(old_path.get_file());
+ String new_path = p_to_path.path_join(old_path.get_file());
if (old_path != new_path) {
_try_move_item(to_move[i], new_path, file_renames, folder_renames);
is_moved = true;
@@ -2006,7 +2005,7 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
if (!fpath.ends_with("/")) {
fpath = fpath.get_base_dir();
}
- make_script_dialog->config("Node", fpath.plus_file("new_script.gd"), false, false);
+ make_script_dialog->config("Node", fpath.path_join("new_script.gd"), false, false);
make_script_dialog->popup_centered();
} break;
@@ -2048,15 +2047,15 @@ void FileSystemDock::_resource_created() {
String type_name = new_resource_dialog->get_selected_type();
if (type_name == "Shader") {
- make_shader_dialog->config(fpath.plus_file("new_shader"), false, false, 0);
+ make_shader_dialog->config(fpath.path_join("new_shader"), false, false, 0);
make_shader_dialog->popup_centered();
return;
} else if (type_name == "VisualShader") {
- make_shader_dialog->config(fpath.plus_file("new_shader"), false, false, 1);
+ make_shader_dialog->config(fpath.path_join("new_shader"), false, false, 1);
make_shader_dialog->popup_centered();
return;
} else if (type_name == "ShaderInclude") {
- make_shader_dialog->config(fpath.plus_file("new_shader_include"), false, false, 2);
+ make_shader_dialog->config(fpath.path_join("new_shader_include"), false, false, 2);
make_shader_dialog->popup_centered();
return;
}
@@ -2371,11 +2370,11 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
String new_path_base;
if (to_move[i].is_file) {
- new_path = to_dir.plus_file(to_move[i].path.get_file());
+ new_path = to_dir.path_join(to_move[i].path.get_file());
new_path_base = new_path.get_basename() + " (%d)." + new_path.get_extension();
} else {
PackedStringArray path_split = to_move[i].path.split("/");
- new_path = to_dir.plus_file(path_split[path_split.size() - 2]);
+ new_path = to_dir.path_join(path_split[path_split.size() - 2]);
new_path_base = new_path + " (%d)";
}
@@ -2978,7 +2977,7 @@ void FileSystemDock::_file_sort_popup(int p_id) {
MenuButton *FileSystemDock::_create_file_menu_button() {
MenuButton *button = memnew(MenuButton);
button->set_flat(true);
- button->set_tooltip(TTR("Sort files"));
+ button->set_tooltip_text(TTR("Sort files"));
PopupMenu *p = button->get_popup();
p->connect("id_pressed", callable_mp(this, &FileSystemDock::_file_sort_popup));
@@ -3041,14 +3040,14 @@ FileSystemDock::FileSystemDock() {
button_hist_prev->set_flat(true);
button_hist_prev->set_disabled(true);
button_hist_prev->set_focus_mode(FOCUS_NONE);
- button_hist_prev->set_tooltip(TTR("Previous Folder/File"));
+ button_hist_prev->set_tooltip_text(TTR("Previous Folder/File"));
toolbar_hbc->add_child(button_hist_prev);
button_hist_next = memnew(Button);
button_hist_next->set_flat(true);
button_hist_next->set_disabled(true);
button_hist_next->set_focus_mode(FOCUS_NONE);
- button_hist_next->set_tooltip(TTR("Next Folder/File"));
+ button_hist_next->set_tooltip_text(TTR("Next Folder/File"));
toolbar_hbc->add_child(button_hist_next);
current_path = memnew(LineEdit);
@@ -3060,7 +3059,7 @@ FileSystemDock::FileSystemDock() {
button_reload = memnew(Button);
button_reload->connect("pressed", callable_mp(this, &FileSystemDock::_rescan));
button_reload->set_focus_mode(FOCUS_NONE);
- button_reload->set_tooltip(TTR("Re-Scan Filesystem"));
+ button_reload->set_tooltip_text(TTR("Re-Scan Filesystem"));
button_reload->hide();
toolbar_hbc->add_child(button_reload);
@@ -3068,7 +3067,7 @@ FileSystemDock::FileSystemDock() {
button_toggle_display_mode->set_toggle_mode(true);
button_toggle_display_mode->connect("toggled", callable_mp(this, &FileSystemDock::_toggle_split_mode));
button_toggle_display_mode->set_focus_mode(FOCUS_NONE);
- button_toggle_display_mode->set_tooltip(TTR("Toggle Split Mode"));
+ button_toggle_display_mode->set_tooltip_text(TTR("Toggle Split Mode"));
button_toggle_display_mode->set_flat(true);
toolbar_hbc->add_child(button_toggle_display_mode);
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index 81b71b5609..16c5003fdc 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -168,7 +168,7 @@ void FindInFiles::_iterate() {
String folder_name = folders_to_scan[folders_to_scan.size() - 1];
pop_back(folders_to_scan);
- _current_dir = _current_dir.plus_file(folder_name);
+ _current_dir = _current_dir.path_join(folder_name);
PackedStringArray sub_dirs;
_scan_dir("res://" + _current_dir, sub_dirs);
@@ -246,7 +246,7 @@ void FindInFiles::_scan_dir(String path, PackedStringArray &out_folders) {
} else {
String file_ext = file.get_extension();
if (_extension_filter.has(file_ext)) {
- _files_to_scan.push_back(path.plus_file(file));
+ _files_to_scan.push_back(path.path_join(file));
}
}
}
@@ -373,7 +373,7 @@ FindInFilesDialog::FindInFilesDialog() {
Label *filter_label = memnew(Label);
filter_label->set_text(TTR("Filters:"));
- filter_label->set_tooltip(TTR("Include the files with the following extensions. Add or remove them in ProjectSettings."));
+ filter_label->set_tooltip_text(TTR("Include the files with the following extensions. Add or remove them in ProjectSettings."));
gc->add_child(filter_label);
_filters_container = memnew(HBoxContainer);
diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp
index f16097f109..15add50fd4 100644
--- a/editor/groups_editor.cpp
+++ b/editor/groups_editor.cpp
@@ -32,6 +32,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/scene_tree_dock.h"
#include "editor/scene_tree_editor.h"
#include "scene/gui/box_container.h"
@@ -397,6 +398,10 @@ void GroupDialog::_notification(int p_what) {
}
}
+void GroupDialog::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
+ undo_redo = p_undo_redo;
+}
+
void GroupDialog::edit() {
popup_centered();
@@ -696,6 +701,10 @@ void GroupsEditor::update_tree() {
}
}
+void GroupsEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
+ undo_redo = p_undo_redo;
+}
+
void GroupsEditor::set_current(Node *p_node) {
node = p_node;
update_tree();
diff --git a/editor/groups_editor.h b/editor/groups_editor.h
index fec8913e31..8bbea4e652 100644
--- a/editor/groups_editor.h
+++ b/editor/groups_editor.h
@@ -31,7 +31,6 @@
#ifndef GROUPS_EDITOR_H
#define GROUPS_EDITOR_H
-#include "core/object/undo_redo.h"
#include "editor/scene_tree_editor.h"
#include "scene/gui/button.h"
#include "scene/gui/dialogs.h"
@@ -40,6 +39,8 @@
#include "scene/gui/popup.h"
#include "scene/gui/tree.h"
+class EditorUndoRedoManager;
+
class GroupDialog : public AcceptDialog {
GDCLASS(GroupDialog, AcceptDialog);
@@ -68,7 +69,7 @@ class GroupDialog : public AcceptDialog {
String selected_group;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
void _group_selected();
@@ -103,7 +104,7 @@ public:
};
void edit();
- void set_undo_redo(UndoRedo *p_undoredo) { undo_redo = p_undoredo; }
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
GroupDialog();
};
@@ -119,7 +120,7 @@ class GroupsEditor : public VBoxContainer {
Button *add = nullptr;
Tree *tree = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
void update_tree();
void _add_group(const String &p_group = "");
@@ -137,7 +138,7 @@ public:
COPY_GROUP,
};
- void set_undo_redo(UndoRedo *p_undoredo) { undo_redo = p_undoredo; }
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void set_current(Node *p_node);
GroupsEditor();
diff --git a/editor/icons/AudioStream.svg b/editor/icons/AudioStream.svg
new file mode 100644
index 0000000000..5d92dc25a5
--- /dev/null
+++ b/editor/icons/AudioStream.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="8" x2="8" y1="1" y2="15"><stop offset="0" stop-color="#ff5f5f"/><stop offset=".5" stop-color="#e1da5b"/><stop offset="1" stop-color="#5fff97"/></linearGradient><path d="m12 2a-1 1 0 0 1 1 1-1 1 0 0 1 -1 1c-4.4301 0-8 3.5699-8 8a-1 1 0 0 1 -1 1-1 1 0 0 1 -1-1c0-5.511 4.489-10 10-10zm0 4a-1 1 0 0 1 1 1-1 1 0 0 1 -1 1c-2.221 0-4 1.779-4 4a-1 1 0 0 1 -1 1-1 1 0 0 1 -1-1c0-3.3018 2.6981-6 6-6zm0 4a-2 2 0 0 1 2 2-2 2 0 0 1 -2 2-2 2 0 0 1 -2-2-2 2 0 0 1 2-2z" fill="url(#a)"/></svg>
diff --git a/editor/icons/AudioStreamGenerator.svg b/editor/icons/AudioStreamGenerator.svg
new file mode 100644
index 0000000000..55b0fb9d92
--- /dev/null
+++ b/editor/icons/AudioStreamGenerator.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="8" x2="8" y1="1" y2="15"><stop offset="0" stop-color="#ff5f5f"/><stop offset=".5" stop-color="#e1da5b"/><stop offset="1" stop-color="#5fff97"/></linearGradient><path d="m14 9-3 5-3-12-3 7-3-2" fill="none" stroke="url(#a)" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></svg>
diff --git a/editor/icons/AudioStreamMicrophone.svg b/editor/icons/AudioStreamMicrophone.svg
new file mode 100644
index 0000000000..51009e9d53
--- /dev/null
+++ b/editor/icons/AudioStreamMicrophone.svg
@@ -0,0 +1 @@
+<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="8" x2="8" y1="1" y2="15"><stop offset="0" stop-color="#ff5f5f"/><stop offset=".5" stop-color="#e1da5b"/><stop offset="1" stop-color="#5fff97"/></linearGradient><path d="m7 1c-1.108 0-2 .892-2 2h2v1h-2v2h2v1h-2c0 1.108.892 2 2 2v4l-2 2h6l-2-2v-4c1.108 0 2-.892 2-2h-2v-1h2v-2h-2v-1h2c0-1.108-.892-2-2-2z" fill="url(#a)"/></svg>
diff --git a/editor/icons/AudioStreamRandomizer.svg b/editor/icons/AudioStreamRandomizer.svg
new file mode 100644
index 0000000000..1696dff795
--- /dev/null
+++ b/editor/icons/AudioStreamRandomizer.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="8" x2="8" y1="1" y2="15"><stop offset="0" stop-color="#ff5f5f"/><stop offset=".5" stop-color="#e1da5b"/><stop offset="1" stop-color="#5fff97"/></linearGradient><path d="m7.9999997 1c6.6837543 0 7.0000003.3165085 7.0000003 7.0057779 0 6.6877711-.286255 6.9755641-6.9367525 6.9938021-3.0191555.008313-4.4456225-.105997-5.1863245-.415726-1.570375-.65669-1.876923-1.727949-1.876923-6.5780761 0-6.6892694.316247-7.0057779 6.9999997-7.0057779zm3.5299143 1.7638478c-1.5662016 0-2.4379256 1.7724432-1.475213 2.9973439.738933.9401693 2.041543 1.025967 2.876923.1899002 1.183646-1.1846229.303279-3.1872441-1.40171-3.1872441zm-3.5760682 3.2710739c-1.5661974 0-2.4379268 1.7707341-1.4752138 2.9956331.7389365.9401892 2.0415435 1.0276772 2.8769233.191611 1.1836457-1.1846231.3032798-3.1872441-1.4017095-3.1872441zm-3.5538458 3.4729499c-.958537.031867-1.875214.7423284-1.875214 1.8493884 0 1.564955 2.248443 2.516522 3.249573 1.375494.7905175-.900982.8551191-1.664857.208547-2.487522-.416627-.5300879-1.007786-.7565128-1.582906-.7373604z" fill="url(#a)"/></svg>
diff --git a/editor/icons/BezierHandlesBalanced.svg b/editor/icons/BezierHandlesBalanced.svg
index 911029e431..b1778b1a5e 100644
--- a/editor/icons/BezierHandlesBalanced.svg
+++ b/editor/icons/BezierHandlesBalanced.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.2881355-6.847458 6.5762712-8.1355935c5.0847459.9491522 5.9661009 8.1355925 5.9661009 8.1355925" fill="none" stroke="#5fb2ff" stroke-miterlimit="4.9" stroke-width="1.7"/><ellipse cx="1.898304" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><path d="m7.4559186 5.1473018-4.7355323 1.5541798" fill="none" stroke="#5fb2ff" stroke-width=".618"/><path d="m10.790357 4.2063094-2.5009748.9433136" fill="none" stroke="#5fb2ff" stroke-width=".614897"/><g fill="#e0e0e0"><ellipse cx="8.271187" cy="4.779661" rx="1.267586" ry="1.199789"/><path d="m1.7157324 5.8754878a1.2675855 1.1997888 0 0 0 -1.26757806 1.1992188 1.2675855 1.1997888 0 0 0 1.26757806 1.1992187 1.2675855 1.1997888 0 0 0 1.2675781-1.1992187 1.2675855 1.1997888 0 0 0 -1.2675781-1.1992188zm.00195.4238282a.84677333.80148375 0 0 1 .8476593.8007812.84677333.80148375 0 0 1 -.8476562.8007812.84677333.80148375 0 0 1 -.84765616-.8007812.84677333.80148375 0 0 1 .84765616-.8007812z"/><path d="m11.909414 2.4642073a1.2836218 1.231838 0 0 0 -1.283614 1.2312528 1.2836218 1.231838 0 0 0 1.283614 1.2312527 1.2836218 1.231838 0 0 0 1.283614-1.2312527 1.2836218 1.231838 0 0 0 -1.283614-1.2312528zm.002.4351497a.85748593.82289328 0 0 1 .858383.8221719.85748593.82289328 0 0 1 -.85838.822172.85748593.82289328 0 0 1 -.858379-.822172.85748593.82289328 0 0 1 .858379-.8221719z"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.2881355-6.847458 6.5762712-8.1355935c5.0847459.9491522 5.9661009 8.1355925 5.9661009 8.1355925" fill="none" stroke="#87b1d7" stroke-miterlimit="4.9" stroke-width=".5"/><path d="m2.4962504 7.6963851 10.1811806-3.7166314" fill="none" stroke="#61b2ff" stroke-width="1.5"/><g fill="#e0e0e0"><ellipse cx="1.898304" cy="13.491526" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" rx="1.267586" ry="1.199789"/><ellipse cx="8.338983" cy="5.491526" rx="1.267586" ry="1.199789"/><path d="m1.6910776 6.7273a1.2675855 1.1997888 0 0 0 -1.26757808 1.1992188 1.2675855 1.1997888 0 0 0 1.26757808 1.1992187 1.2675855 1.1997888 0 0 0 1.2675781-1.1992187 1.2675855 1.1997888 0 0 0 -1.2675781-1.1992188zm.00195.4238282a.84677333.80148375 0 0 1 .8476593.8007812.84677333.80148375 0 0 1 -.8476562.8007812.84677333.80148375 0 0 1 -.84765618-.8007812.84677333.80148375 0 0 1 .84765618-.8007812z"/><path d="m13.40948 2.2963899a1.2836218 1.231838 0 0 0 -1.283614 1.2312528 1.2836218 1.231838 0 0 0 1.283614 1.2312526 1.2836218 1.231838 0 0 0 1.283614-1.2312526 1.2836218 1.231838 0 0 0 -1.283614-1.2312528zm.002.4351497a.85748593.82289328 0 0 1 .858383.8221719.85748593.82289328 0 0 1 -.85838.8221719.85748593.82289328 0 0 1 -.858379-.8221719.85748593.82289328 0 0 1 .858379-.8221719z"/></g></svg>
diff --git a/editor/icons/BezierHandlesFree.svg b/editor/icons/BezierHandlesFree.svg
index 6e91288c79..c7bff530ae 100644
--- a/editor/icons/BezierHandlesFree.svg
+++ b/editor/icons/BezierHandlesFree.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.2881355-6.847458 6.5762712-8.1355935c5.0847459.9491522 5.9661009 8.1355925 5.9661009 8.1355925" fill="none" stroke="#5fb2ff" stroke-miterlimit="4.9" stroke-width="1.7"/><ellipse cx="1.898304" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><path d="m7.6850253 4.7560401-3.776127.6607599" fill="none" stroke="#5fb2ff" stroke-width=".805138"/><path d="m11.695505 2.3941651-2.999121 2.2935078" fill="none" stroke="#5fb2ff" stroke-width=".730798"/><g fill="#e0e0e0"><ellipse cx="8.271187" cy="4.779661" rx="1.267586" ry="1.199789"/><path d="m2.4961199 4.3976698a1.1997888 1.2675855 80.074672 0 0 -1.0419038 1.3997559 1.1997888 1.2675855 80.074672 0 0 1.4553094.9627848 1.1997888 1.2675855 80.074672 0 0 1.0419037-1.3997558 1.1997888 1.2675855 80.074672 0 0 -1.4553093-.9627849zm.074974.4171488a.80148375.84677333 80.074672 0 1 .9729986.6426896.80148375.84677333 80.074672 0 1 -.6969432.934902.80148375.84677333 80.074672 0 1 -.9729958-.6426902.80148375.84677333 80.074672 0 1 .6969432-.934902z"/><path d="m11.838896.64428913a1.231838 1.2836218 52.593897 0 0 -.271701 1.75779027 1.231838 1.2836218 52.593897 0 0 1.767576.1983008 1.231838 1.2836218 52.593897 0 0 .271701-1.75779027 1.231838 1.2836218 52.593897 0 0 -1.767576-.1983008zm.265925.3444462a.82289328.85748593 52.593897 0 1 1.181294.13165847.82289328.85748593 52.593897 0 1 -.182417 1.1745241.82289328.85748593 52.593897 0 1 -1.181291-.1316609.82289328.85748593 52.593897 0 1 .182417-1.17452347z"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.3064631-5.1979735 6.5945988-6.486109c5.0847463.9491522 5.9477733 6.486108 5.9477733 6.486108" fill="none" stroke="#87b1d7" stroke-miterlimit="4.9" stroke-width=".5"/><path d="m2.3554991 8.5165019 6.0018116-1.3754919 2.0717113-4.6377276" fill="none" stroke="#61b3ff" stroke-width="1.5"/><g fill="#e0e0e0"><ellipse cx="1.898304" cy="13.491526" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" rx="1.267586" ry="1.199789"/><ellipse cx="8.35731" cy="7.14101" rx="1.267586" ry="1.199789"/><path d="m1.3048251 7.4400522a1.1997888 1.2675855 80.074672 0 0 -1.04190379 1.3997559 1.1997888 1.2675855 80.074672 0 0 1.45530939.9627848 1.1997888 1.2675855 80.074672 0 0 1.0419037-1.3997558 1.1997888 1.2675855 80.074672 0 0 -1.4553093-.9627849zm.074974.4171488a.80148375.84677333 80.074672 0 1 .9729986.6426896.80148375.84677333 80.074672 0 1 -.6969432.934902.80148375.84677333 80.074672 0 1 -.97299579-.6426902.80148375.84677333 80.074672 0 1 .69694319-.934902z"/><path d="m10.024463.73592688a1.231838 1.2836218 52.593897 0 0 -.2717015 1.75779042 1.231838 1.2836218 52.593897 0 0 1.7675765.1983008 1.231838 1.2836218 52.593897 0 0 .271701-1.75779042 1.231838 1.2836218 52.593897 0 0 -1.767576-.1983008zm.265925.34444622a.82289328.85748593 52.593897 0 1 1.181294.1316585.82289328.85748593 52.593897 0 1 -.182417 1.1745242.82289328.85748593 52.593897 0 1 -1.181291-.1316609.82289328.85748593 52.593897 0 1 .182417-1.1745236z"/></g></svg>
diff --git a/editor/icons/BezierHandlesLinear.svg b/editor/icons/BezierHandlesLinear.svg
new file mode 100644
index 0000000000..2667779dcb
--- /dev/null
+++ b/editor/icons/BezierHandlesLinear.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8.2711868 4.7796612-6.3728828 8.7118648z" fill="none" stroke="#87b1d7" stroke-miterlimit="4.9" stroke-width=".5"/><ellipse cx="1.898304" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><path d="m14.237288 13.491526-5.9661012-8.7118648" fill="none" stroke="#87b1d7" stroke-miterlimit="4.9" stroke-width=".5"/><path d="m5.6316733 8.3879317 2.6395135-3.6082705 2.4416832 3.5654122" fill="none" stroke="#61b2ff" stroke-width="1.5"/><g fill="#e0e0e0"><ellipse cx="14.237288" cy="13.491526" rx="1.267586" ry="1.199789"/><ellipse cx="8.271187" cy="4.779661" rx="1.267586" ry="1.199789"/><path d="m5.0847454 7.9363749a1.2675855 1.1997888 0 0 0 -1.2675781 1.1992188 1.2675855 1.1997888 0 0 0 1.2675781 1.1992183 1.2675855 1.1997888 0 0 0 1.2675781-1.1992183 1.2675855 1.1997888 0 0 0 -1.2675781-1.1992188zm.00195.4238282a.84677333.80148375 0 0 1 .8476593.8007812.84677333.80148375 0 0 1 -.8476562.8007812.84677333.80148375 0 0 1 -.8476562-.8007812.84677333.80148375 0 0 1 .8476562-.8007812z"/><path d="m11.254237 7.9043407a1.2836218 1.231838 0 0 0 -1.2836135 1.2312528 1.2836218 1.231838 0 0 0 1.2836135 1.2312525 1.2836218 1.231838 0 0 0 1.283614-1.2312525 1.2836218 1.231838 0 0 0 -1.283614-1.2312528zm.002.4351497a.85748593.82289328 0 0 1 .858383.8221719.85748593.82289328 0 0 1 -.85838.822172.85748593.82289328 0 0 1 -.858379-.822172.85748593.82289328 0 0 1 .858379-.8221719z"/></g></svg>
diff --git a/editor/icons/BezierHandlesMirror.svg b/editor/icons/BezierHandlesMirror.svg
index 9180e31921..07817f7247 100644
--- a/editor/icons/BezierHandlesMirror.svg
+++ b/editor/icons/BezierHandlesMirror.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.2881355-6.847458 6.5762712-8.1355935c5.0847459.9491522 5.9661009 8.1355925 5.9661009 8.1355925" fill="none" stroke="#5fb2ff" stroke-miterlimit="4.9" stroke-width="1.7"/><ellipse cx="1.898304" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><path d="m8.2033896 4.6779662h-3.8335021" fill="none" stroke="#5fb2ff" stroke-width=".805138"/><path d="m11.931789 4.6440679h-3.7283994" fill="none" stroke="#5fb2ff" stroke-width=".716709"/><g fill="#e0e0e0"><ellipse cx="8.271187" cy="4.779661" rx="1.267586" ry="1.199789"/><path d="m3.1539157 3.4305762a1.2675855 1.1997888 0 0 0 -1.2675781 1.1992188 1.2675855 1.1997888 0 0 0 1.2675781 1.1992187 1.2675855 1.1997888 0 0 0 1.2675781-1.1992187 1.2675855 1.1997888 0 0 0 -1.2675781-1.1992188zm.00195.4238282a.84677333.80148375 0 0 1 .8476593.8007812.84677333.80148375 0 0 1 -.8476562.8007812.84677333.80148375 0 0 1 -.8476562-.8007812.84677333.80148375 0 0 1 .8476562-.8007812z"/><path d="m13.093969 3.3750567a1.2675855 1.1997888 0 0 0 -1.267578 1.1992188 1.2675855 1.1997888 0 0 0 1.267578 1.1992187 1.2675855 1.1997888 0 0 0 1.267578-1.1992187 1.2675855 1.1997888 0 0 0 -1.267578-1.1992188zm.002.4238282a.84677333.80148375 0 0 1 .847659.8007812.84677333.80148375 0 0 1 -.847656.8007812.84677333.80148375 0 0 1 -.847656-.8007812.84677333.80148375 0 0 1 .847656-.8007812z"/></g></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1.7627119 13.627119s1.2881355-6.847458 6.5762712-8.1355935c5.0847459.9491522 5.9661009 8.1355925 5.9661009 8.1355925" fill="none" stroke="#87b1d7" stroke-miterlimit="4.9" stroke-width=".5"/><ellipse cx="1.898304" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><ellipse cx="14.237288" cy="13.491526" fill="#e0e0e0" rx="1.267586" ry="1.199789"/><path d="m8.3389831 5.4915255-5.8519685.0395137" fill="none" stroke="#5fb2ff" stroke-width="1.5"/><path d="m13.814033 5.4419288-5.4750499.0156984" fill="none" stroke="#5fb2ff" stroke-width="1.5"/><g fill="#e0e0e0"><ellipse cx="8.40678" cy="5.593221" rx="1.267586" ry="1.199789"/><path d="m1.6400247 4.2441355a1.2675855 1.1997888 0 0 0 -1.26757814 1.1992188 1.2675855 1.1997888 0 0 0 1.26757814 1.1992187 1.2675855 1.1997888 0 0 0 1.2675781-1.1992187 1.2675855 1.1997888 0 0 0 -1.2675781-1.1992188zm.00195.4238282a.84677333.80148375 0 0 1 .8476593.8007812.84677333.80148375 0 0 1 -.8476562.8007812.84677333.80148375 0 0 1 -.84765624-.8007812.84677333.80148375 0 0 1 .84765624-.8007812z"/><path d="m14.659116 4.188616a1.2675855 1.1997888 0 0 0 -1.267578 1.1992188 1.2675855 1.1997888 0 0 0 1.267578 1.1992187 1.2675855 1.1997888 0 0 0 1.267578-1.1992187 1.2675855 1.1997888 0 0 0 -1.267578-1.1992188zm.002.4238282a.84677333.80148375 0 0 1 .847659.8007812.84677333.80148375 0 0 1 -.847656.8007812.84677333.80148375 0 0 1 -.847656-.8007812.84677333.80148375 0 0 1 .847656-.8007812z"/></g></svg>
diff --git a/editor/icons/ContainerLayout.svg b/editor/icons/ContainerLayout.svg
new file mode 100644
index 0000000000..feabc2c350
--- /dev/null
+++ b/editor/icons/ContainerLayout.svg
@@ -0,0 +1 @@
+<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill-rule="nonzero"><path d="m3 1c-1.105 0-2 .895-2 2h2zm2 0v2h2v-2zm4 0v2h2v-2zm4 0v2h2c0-1.105-.895-2-2-2zm-12 4v2h2v-2zm12 0v2h2v-2zm-12 4v2h2v-2zm12 0v2h2v-2zm-12 4c0 1.105.895 2 2 2v-2zm4 0v2h2v-2zm4 0v2h2v-2zm4 0v2c1.105 0 2-.895 2-2z" fill="#8eef97"/><path d="m7 7h4v4h-4z" fill="#d6d6d6"/></g></svg>
diff --git a/editor/icons/ControlLayout.svg b/editor/icons/ControlLayout.svg
index 11dd2554be..8503e3313c 100644
--- a/editor/icons/ControlLayout.svg
+++ b/editor/icons/ControlLayout.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v14h14v-14zm2 2h3v3h-3zm5 0h5v3h-5zm-5 5h3v5h-3zm5 0h5v5h-5z" fill="#8eef97"/></svg>
+<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill-rule="nonzero"><path d="m11.793 8v-2h-3.793v-2.113h-2v2.113h-2.142v2h2.142v3.967h2v-3.967z" fill="#d6d6d6"/><path d="m8 .345c-4.199 0-7.655 3.456-7.655 7.655s3.456 7.655 7.655 7.655 7.655-3.456 7.655-7.655-3.456-7.655-7.655-7.655zm0 1.999c3.103 0 5.656 2.553 5.656 5.656s-2.553 5.656-5.656 5.656-5.656-2.553-5.656-5.656 2.553-5.656 5.656-5.656z" fill="#8eef97"/></g></svg>
diff --git a/editor/icons/CurveIn.svg b/editor/icons/CurveIn.svg
index 2ad44dc654..fefad9ce6c 100644
--- a/editor/icons/CurveIn.svg
+++ b/editor/icons/CurveIn.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c5 0 8-3 8-8" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg>
+<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c5 0 8-3 8-8" fill="none" stroke="#80ff45" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg>
diff --git a/editor/icons/CurveInOut.svg b/editor/icons/CurveInOut.svg
index 292dac4573..f099cb83f1 100644
--- a/editor/icons/CurveInOut.svg
+++ b/editor/icons/CurveInOut.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c5 0 3-8 8-8" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg>
+<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c5 0 3-8 8-8" fill="none" stroke="#45d7ff" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg>
diff --git a/editor/icons/CurveLinear.svg b/editor/icons/CurveLinear.svg
index 3c1fb2a0e2..41d37c9329 100644
--- a/editor/icons/CurveLinear.svg
+++ b/editor/icons/CurveLinear.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4 8-8" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg>
+<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4 8-8" fill="none" stroke="#ffe345" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg>
diff --git a/editor/icons/CurveOut.svg b/editor/icons/CurveOut.svg
index dfa9a26144..19710aa38d 100644
--- a/editor/icons/CurveOut.svg
+++ b/editor/icons/CurveOut.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c0-5 3-8 8-8" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg>
+<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c0-5 3-8 8-8" fill="none" stroke="#45ffa2" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg>
diff --git a/editor/icons/CurveOutIn.svg b/editor/icons/CurveOutIn.svg
index 9a6463d0e9..7f200432bf 100644
--- a/editor/icons/CurveOutIn.svg
+++ b/editor/icons/CurveOutIn.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c0-5 8-3 8-8" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg>
+<svg height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c0-5 8-3 8-8" fill="none" stroke="#ff4596" stroke-linecap="round" stroke-width="2" transform="translate(0 -1040.4)"/></svg>
diff --git a/editor/icons/DefaultProjectIcon.svg b/editor/icons/DefaultProjectIcon.svg
index f81ba4d390..adc26df6c2 100644
--- a/editor/icons/DefaultProjectIcon.svg
+++ b/editor/icons/DefaultProjectIcon.svg
@@ -1 +1 @@
-<svg height="64" viewBox="0 0 64 64" width="64" xmlns="http://www.w3.org/2000/svg"><g stroke-linejoin="round"><path d="m8 0c-4.432 0-8 3.568-8 8v48c0 4.432 3.568 8 8 8h48c4.432 0 8-3.568 8-8v-48c0-4.432-3.568-8-8-8z" fill="#355570" stroke-linecap="round" stroke-width="2"/><path d="m8 0c-4.432 0-8 3.568-8 8v48c0 4.432 3.568 8 8 8h48c4.432 0 8-3.568 8-8v-48c0-4.432-3.568-8-8-8zm0 2h48c3.324 0 6 2.676 6 6v48c0 3.324-2.676 6-6 6h-48c-3.324 0-6-2.676-6-6v-48c0-3.324 2.676-6 6-6z" fill-opacity=".19608" stroke-linecap="round" stroke-width="2"/><path d="m27.254 10c-2.1314.47383-4.2401 1.134-6.2168 2.1289.04521 1.7455.15796 3.4164.38672 5.1152-.76768.4919-1.574.91443-2.291 1.4902-.72854.5604-1.4731 1.0965-2.1328 1.752-1.3179-.8716-2.7115-1.691-4.1484-2.4141-1.549 1.667-2.9985 3.4672-4.1816 5.4805.89011 1.4399 1.8209 2.7894 2.8242 4.0703h.027343v9.9453 1.2617 1.1504l-.009765 1.6309h-.001953c.0031.7321.011718 1.5356.011718 1.6953 0 7.1942 9.1264 10.652 20.465 10.691h.013672.013672c11.338-.04 20.461-3.4972 20.461-10.691 0-.1626.010282-.96271.013672-1.6953h-.001953l-.011719-1.6309v-.98633l.003907-.001953v-11.369h.027343c1.0035-1.2809 1.9337-2.6304 2.8242-4.0703-1.1827-2.0133-2.6327-3.8135-4.1816-5.4805-1.4366.7231-2.8325 1.5425-4.1504 2.4141-.65947-.6555-1.4013-1.1916-2.1309-1.752-.71682-.5758-1.5248-.99833-2.291-1.4902.22813-1.6988.3413-3.3697.38672-5.1152-1.977-.99494-4.0863-1.6551-6.2188-2.1289-.85139 1.4309-1.6285 2.9812-2.3066 4.4961-.80409-.1344-1.613-.18571-2.4219-.19531h-.015625-.015625c-.81037.01-1.6176.060513-2.4219.19531-.67768-1.5149-1.4559-3.0652-2.3086-4.4961z" fill="#fff" stroke="#fff" stroke-width="3"/></g><g stroke-width=".32031" transform="matrix(.050279 0 0 .050279 6.2574 1.18)"><path d="m0 0s-.325 1.994-.515 1.976l-36.182-3.491c-2.879-.278-5.115-2.574-5.317-5.459l-.994-14.247-27.992-1.997-1.904 12.912c-.424 2.872-2.932 5.037-5.835 5.037h-38.188c-2.902 0-5.41-2.165-5.834-5.037l-1.905-12.912-27.992 1.997-.994 14.247c-.202 2.886-2.438 5.182-5.317 5.46l-36.2 3.49c-.187.018-.324-1.978-.511-1.978l-.049-7.83 30.658-4.944 1.004-14.374c.203-2.91 2.551-5.263 5.463-5.472l38.551-2.75c.146-.01.29-.016.434-.016 2.897 0 5.401 2.166 5.825 5.038l1.959 13.286h28.005l1.959-13.286c.423-2.871 2.93-5.037 5.831-5.037.142 0 .284.005.423.015l38.556 2.75c2.911.209 5.26 2.562 5.463 5.472l1.003 14.374 30.645 4.966z" fill="#fff" transform="matrix(4.1626 0 0 -4.1626 919.24 771.67)"/><path d="m0 0v-59.041c.108-.001.216-.005.323-.015l36.196-3.49c1.896-.183 3.382-1.709 3.514-3.609l1.116-15.978 31.574-2.253 2.175 14.747c.282 1.912 1.922 3.329 3.856 3.329h38.188c1.933 0 3.573-1.417 3.855-3.329l2.175-14.747 31.575 2.253 1.115 15.978c.133 1.9 1.618 3.425 3.514 3.609l36.182 3.49c.107.01.214.014.322.015v4.711l.015.005v54.325h.134c4.795 6.12 9.232 12.569 13.487 19.449-5.651 9.62-12.575 18.217-19.976 26.182-6.864-3.455-13.531-7.369-19.828-11.534-3.151 3.132-6.7 5.694-10.186 8.372-3.425 2.751-7.285 4.768-10.946 7.118 1.09 8.117 1.629 16.108 1.846 24.448-9.446 4.754-19.519 7.906-29.708 10.17-4.068-6.837-7.788-14.241-11.028-21.479-3.842.642-7.702.88-11.567.926v.006c-.027 0-.052-.006-.075-.006-.024 0-.049.006-.073.006v-.006c-3.872-.046-7.729-.284-11.572-.926-3.238 7.238-6.956 14.642-11.03 21.479-10.184-2.264-20.258-5.416-29.703-10.17.216-8.34.755-16.331 1.848-24.448-3.668-2.35-7.523-4.367-10.949-7.118-3.481-2.678-7.036-5.24-10.188-8.372-6.297 4.165-12.962 8.079-19.828 11.534-7.401-7.965-14.321-16.562-19.974-26.182 4.253-6.88 8.693-13.329 13.487-19.449z" fill="#478cbf" transform="matrix(4.1626 0 0 -4.1626 104.7 525.91)"/><path d="m0 0-1.121-16.063c-.135-1.936-1.675-3.477-3.611-3.616l-38.555-2.751c-.094-.007-.188-.01-.281-.01-1.916 0-3.569 1.406-3.852 3.33l-2.211 14.994h-31.459l-2.211-14.994c-.297-2.018-2.101-3.469-4.133-3.32l-38.555 2.751c-1.936.139-3.476 1.68-3.611 3.616l-1.121 16.063-32.547 3.138c.015-3.498.06-7.33.06-8.093 0-34.374 43.605-50.896 97.781-51.086h.133c54.176.19 97.766 16.712 97.766 51.086 0 .777.047 4.593.063 8.093z" fill="#478cbf" transform="matrix(4.1626 0 0 -4.1626 784.07 817.24)"/><path d="m0 0c0-12.052-9.765-21.815-21.813-21.815-12.042 0-21.81 9.763-21.81 21.815 0 12.044 9.768 21.802 21.81 21.802 12.048 0 21.813-9.758 21.813-21.802" fill="#fff" transform="matrix(4.1626 0 0 -4.1626 389.21 625.67)"/><path d="m0 0c0-7.994-6.479-14.473-14.479-14.473-7.996 0-14.479 6.479-14.479 14.473s6.483 14.479 14.479 14.479c8 0 14.479-6.485 14.479-14.479" fill="#414042" transform="matrix(4.1626 0 0 -4.1626 367.37 631.06)"/><path d="m0 0c-3.878 0-7.021 2.858-7.021 6.381v20.081c0 3.52 3.143 6.381 7.021 6.381s7.028-2.861 7.028-6.381v-20.081c0-3.523-3.15-6.381-7.028-6.381" fill="#fff" transform="matrix(4.1626 0 0 -4.1626 511.99 724.74)"/><path d="m0 0c0-12.052 9.765-21.815 21.815-21.815 12.041 0 21.808 9.763 21.808 21.815 0 12.044-9.767 21.802-21.808 21.802-12.05 0-21.815-9.758-21.815-21.802" fill="#fff" transform="matrix(4.1626 0 0 -4.1626 634.79 625.67)"/><path d="m0 0c0-7.994 6.477-14.473 14.471-14.473 8.002 0 14.479 6.479 14.479 14.473s-6.477 14.479-14.479 14.479c-7.994 0-14.471-6.485-14.471-14.479" fill="#414042" transform="matrix(4.1626 0 0 -4.1626 656.64 631.06)"/></g></svg>
+<svg height="128" width="128" xmlns="http://www.w3.org/2000/svg"><g transform="translate(32 32)"><path d="m-16-32c-8.86 0-16 7.13-16 15.99v95.98c0 8.86 7.13 15.99 16 15.99h96c8.86 0 16-7.13 16-15.99v-95.98c0-8.85-7.14-15.99-16-15.99z" fill="#363d52"/><path d="m-16-32c-8.86 0-16 7.13-16 15.99v95.98c0 8.86 7.13 15.99 16 15.99h96c8.86 0 16-7.13 16-15.99v-95.98c0-8.85-7.14-15.99-16-15.99zm0 4h96c6.64 0 12 5.35 12 11.99v95.98c0 6.64-5.35 11.99-12 11.99h-96c-6.64 0-12-5.35-12-11.99v-95.98c0-6.64 5.36-11.99 12-11.99z" fill-opacity=".4"/></g><g stroke-width="9.92746" transform="matrix(.10073078 0 0 .10073078 12.425923 2.256365)"><path d="m0 0s-.325 1.994-.515 1.976l-36.182-3.491c-2.879-.278-5.115-2.574-5.317-5.459l-.994-14.247-27.992-1.997-1.904 12.912c-.424 2.872-2.932 5.037-5.835 5.037h-38.188c-2.902 0-5.41-2.165-5.834-5.037l-1.905-12.912-27.992 1.997-.994 14.247c-.202 2.886-2.438 5.182-5.317 5.46l-36.2 3.49c-.187.018-.324-1.978-.511-1.978l-.049-7.83 30.658-4.944 1.004-14.374c.203-2.91 2.551-5.263 5.463-5.472l38.551-2.75c.146-.01.29-.016.434-.016 2.897 0 5.401 2.166 5.825 5.038l1.959 13.286h28.005l1.959-13.286c.423-2.871 2.93-5.037 5.831-5.037.142 0 .284.005.423.015l38.556 2.75c2.911.209 5.26 2.562 5.463 5.472l1.003 14.374 30.645 4.966z" fill="#fff" transform="matrix(4.162611 0 0 -4.162611 919.24059 771.67186)"/><path d="m0 0v-47.514-6.035-5.492c.108-.001.216-.005.323-.015l36.196-3.49c1.896-.183 3.382-1.709 3.514-3.609l1.116-15.978 31.574-2.253 2.175 14.747c.282 1.912 1.922 3.329 3.856 3.329h38.188c1.933 0 3.573-1.417 3.855-3.329l2.175-14.747 31.575 2.253 1.115 15.978c.133 1.9 1.618 3.425 3.514 3.609l36.182 3.49c.107.01.214.014.322.015v4.711l.015.005v54.325c5.09692 6.4164715 9.92323 13.494208 13.621 19.449-5.651 9.62-12.575 18.217-19.976 26.182-6.864-3.455-13.531-7.369-19.828-11.534-3.151 3.132-6.7 5.694-10.186 8.372-3.425 2.751-7.285 4.768-10.946 7.118 1.09 8.117 1.629 16.108 1.846 24.448-9.446 4.754-19.519 7.906-29.708 10.17-4.068-6.837-7.788-14.241-11.028-21.479-3.842.642-7.702.88-11.567.926v.006c-.027 0-.052-.006-.075-.006-.024 0-.049.006-.073.006v-.006c-3.872-.046-7.729-.284-11.572-.926-3.238 7.238-6.956 14.642-11.03 21.479-10.184-2.264-20.258-5.416-29.703-10.17.216-8.34.755-16.331 1.848-24.448-3.668-2.35-7.523-4.367-10.949-7.118-3.481-2.678-7.036-5.24-10.188-8.372-6.297 4.165-12.962 8.079-19.828 11.534-7.401-7.965-14.321-16.562-19.974-26.182 4.4426579-6.973692 9.2079702-13.9828876 13.621-19.449z" fill="#478cbf" transform="matrix(4.162611 0 0 -4.162611 104.69892 525.90697)"/><path d="m0 0-1.121-16.063c-.135-1.936-1.675-3.477-3.611-3.616l-38.555-2.751c-.094-.007-.188-.01-.281-.01-1.916 0-3.569 1.406-3.852 3.33l-2.211 14.994h-31.459l-2.211-14.994c-.297-2.018-2.101-3.469-4.133-3.32l-38.555 2.751c-1.936.139-3.476 1.68-3.611 3.616l-1.121 16.063-32.547 3.138c.015-3.498.06-7.33.06-8.093 0-34.374 43.605-50.896 97.781-51.086h.066.067c54.176.19 97.766 16.712 97.766 51.086 0 .777.047 4.593.063 8.093z" fill="#478cbf" transform="matrix(4.162611 0 0 -4.162611 784.07144 817.24284)"/><path d="m0 0c0-12.052-9.765-21.815-21.813-21.815-12.042 0-21.81 9.763-21.81 21.815 0 12.044 9.768 21.802 21.81 21.802 12.048 0 21.813-9.758 21.813-21.802" fill="#fff" transform="matrix(4.162611 0 0 -4.162611 389.21484 625.67104)"/><path d="m0 0c0-7.994-6.479-14.473-14.479-14.473-7.996 0-14.479 6.479-14.479 14.473s6.483 14.479 14.479 14.479c8 0 14.479-6.485 14.479-14.479" fill="#414042" transform="matrix(4.162611 0 0 -4.162611 367.36686 631.05679)"/><path d="m0 0c-3.878 0-7.021 2.858-7.021 6.381v20.081c0 3.52 3.143 6.381 7.021 6.381s7.028-2.861 7.028-6.381v-20.081c0-3.523-3.15-6.381-7.028-6.381" fill="#fff" transform="matrix(4.162611 0 0 -4.162611 511.99336 724.73954)"/><path d="m0 0c0-12.052 9.765-21.815 21.815-21.815 12.041 0 21.808 9.763 21.808 21.815 0 12.044-9.767 21.802-21.808 21.802-12.05 0-21.815-9.758-21.815-21.802" fill="#fff" transform="matrix(4.162611 0 0 -4.162611 634.78706 625.67104)"/><path d="m0 0c0-7.994 6.477-14.473 14.471-14.473 8.002 0 14.479 6.479 14.479 14.473s-6.477 14.479-14.479 14.479c-7.994 0-14.471-6.485-14.471-14.479" fill="#414042" transform="matrix(4.162611 0 0 -4.162611 656.64056 631.05679)"/></g></svg>
diff --git a/editor/icons/InterpCubicAngle.svg b/editor/icons/InterpCubicAngle.svg
new file mode 100644
index 0000000000..e302d556dc
--- /dev/null
+++ b/editor/icons/InterpCubicAngle.svg
@@ -0,0 +1 @@
+<svg enable-background="new 0 0 16 8" height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="#5fff95" stroke-linecap="round"><path d="m2 6c5 0 3-4 6-4s1 4 6 4" stroke-width="2"/><circle cx="14" cy="2" r="1.5" stroke-linejoin="round"/></g></svg>
diff --git a/editor/icons/InterpLinearAngle.svg b/editor/icons/InterpLinearAngle.svg
new file mode 100644
index 0000000000..af4e87a6cb
--- /dev/null
+++ b/editor/icons/InterpLinearAngle.svg
@@ -0,0 +1 @@
+<svg enable-background="new 0 0 16 8" height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="#fd995f" stroke-linecap="round" stroke-linejoin="round"><path d="m2 6 6-4 6 4" stroke-width="2"/><circle cx="14" cy="2" r="1.5"/></g></svg>
diff --git a/editor/icons/Position2D.svg b/editor/icons/Marker2D.svg
index 191f0b2a03..191f0b2a03 100644
--- a/editor/icons/Position2D.svg
+++ b/editor/icons/Marker2D.svg
diff --git a/editor/icons/Position3D.svg b/editor/icons/Marker3D.svg
index 894b195589..894b195589 100644
--- a/editor/icons/Position3D.svg
+++ b/editor/icons/Marker3D.svg
diff --git a/editor/icons/MenuBar.svg b/editor/icons/MenuBar.svg
new file mode 100644
index 0000000000..0a53f07f85
--- /dev/null
+++ b/editor/icons/MenuBar.svg
@@ -0,0 +1 @@
+<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2 6a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V7a1 1 0 0 0-1-1Zm1 2h10v2H3Zm0 3h10v2H3ZM1 1v4h6V1Zm1 1h4L4 4Z" fill="#8eef97"/></svg>
diff --git a/editor/icons/NodeInfo.svg b/editor/icons/NodeInfo.svg
new file mode 100644
index 0000000000..4e3f0c42d0
--- /dev/null
+++ b/editor/icons/NodeInfo.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 1a7 7 0 0 0 -7 7 7 7 0 0 0 7 7 7 7 0 0 0 7-7 7 7 0 0 0 -7-7zm-1 3h2v2h-2zm0 3h2v5h-2z" fill="#fff"/></svg>
diff --git a/editor/icons/NodeWarnings2.svg b/editor/icons/NodeWarnings2.svg
new file mode 100644
index 0000000000..e0385c28d1
--- /dev/null
+++ b/editor/icons/NodeWarnings2.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8.0292969 2.0019531a1.0001 1.0001 0 0 0 -.8867188.484375l-6 9.9999999a1.0001 1.0001 0 0 0 .8574219 1.513672h12a1.0001 1.0001 0 0 0 .857422-1.513672l-2.326172-3.876953c-.89392-.5083134-1.507327-1.4610509-1.529297-2.5488281l-2.1445311-3.5742188a1.0001 1.0001 0 0 0 -.828125-.484375zm-1.0292969 2.9980469h2v5h-2zm0 6h2v2h-2z" fill="#ffdd65"/><g fill="#f95252"><path d="m14 0a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z"/><path d="m15.447266 4.6210938c-.430501.2402237-.923653.3789062-1.447266.3789062-.522676 0-1.015355-.1375274-1.445312-.3769531a2 2 0 0 0 -.554688 1.3769531 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -.552734-1.3789062z"/></g></svg>
diff --git a/editor/icons/NodeWarnings3.svg b/editor/icons/NodeWarnings3.svg
new file mode 100644
index 0000000000..53c0e70034
--- /dev/null
+++ b/editor/icons/NodeWarnings3.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8.0292969 2.0019531a1.0001 1.0001 0 0 0 -.8867188.484375l-6 9.9999999a1.0001 1.0001 0 0 0 .8574219 1.513672h12a1.0001 1.0001 0 0 0 .982422-1.171875c-.308689.108606-.638692.171875-.982422.171875-1.645008 0-3-1.354992-3-3a1.0001 1.0001 0 0 0 0-.0019531c.002071-.7569921.302544-1.4803618.818359-2.0332031-.464296-.5178712-.798903-1.1662278-.816406-1.9042969l-2.1445311-3.5742188a1.0001 1.0001 0 0 0 -.828125-.484375zm-1.0292969 2.9980469h2v5h-2zm6.095703 4.7636719c-.02286.0837076-.095296.1479891-.095703.2363281v.001953c.001004.551209.418791.97816.964844.996094l-.712891-1.1875001c-.051505-.0169949-.103183-.0337067-.15625-.046875zm-6.095703 1.2363281h2v2h-2z" fill="#ffdd65"/><path d="m14 0a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2zm1.447266 4.6210938c-.430501.2402237-.923653.3789062-1.447266.3789062-.522676 0-1.015355-.1375274-1.445312-.3769531a2 2 0 0 0 -.554688 1.3769531 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -.552734-1.3789062zm0 4c-.430501.2402236-.923653.3789062-1.447266.3789062-.522676 0-1.015355-.1375274-1.445312-.3769531a2 2 0 0 0 -.554688 1.3769531 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -.552734-1.3789062z" fill="#f95252" stroke-dashoffset="16.5" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></svg>
diff --git a/editor/icons/NodeWarnings4Plus.svg b/editor/icons/NodeWarnings4Plus.svg
new file mode 100644
index 0000000000..64c0a0671d
--- /dev/null
+++ b/editor/icons/NodeWarnings4Plus.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8.0292969 2.0019531a1.0001 1.0001 0 0 0 -.8867188.484375l-6 9.9999999a1.0001 1.0001 0 0 0 .8574219 1.513672h9a1.0001 1.0001 0 0 0 0-.001953c.002025-.740254.278882-1.453739.773438-2.001953-.478045-.532242-.773438-1.231924-.773438-1.996094a1.0001 1.0001 0 0 0 0-.0019531c.002071-.7569921.302544-1.4803618.818359-2.0332031-.464296-.5178713-.798903-1.1662278-.816406-1.9042969l-2.1445311-3.5742188a1.0001 1.0001 0 0 0 -.828125-.484375zm-1.0292969 2.9980469h2v5h-2zm6.095703 4.7636719c-.02286.0837076-.095296.1479891-.095703.2363281v.001953c.001004.551209.418791.97816.964844.996094l-.712891-1.1875001c-.051505-.0169949-.103183-.0337067-.15625-.046875zm-6.095703 1.2363281h2v2h-2zm6.095703 2.763672c-.02286.083707-.095296.147988-.095703.236328h1c-.326848 0-.598793-.160518-.904297-.236328z" fill="#ffdd65"/><g fill="#f95252" stroke-dashoffset="16.5" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="m14 0a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -2-2z"/><path d="m15.447266 8.6210938c-.430501.2402236-.923653.3789062-1.447266.3789062-.522676 0-1.015355-.1375274-1.445312-.3769531a2 2 0 0 0 -.554688 1.3769531 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -.552734-1.3789062z"/><path d="m15.447266 4.6210938c-.430501.2402237-.923653.3789062-1.447266.3789062-.522676 0-1.015355-.1375274-1.445312-.3769531a2 2 0 0 0 -.554688 1.3769531 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -.552734-1.3789062z"/><path d="m15.447266 12.621094c-.430501.240224-.923653.378906-1.447266.378906-.522676 0-1.015355-.137527-1.445312-.376953a2 2 0 0 0 -.554688 1.376953 2 2 0 0 0 2 2 2 2 0 0 0 2-2 2 2 0 0 0 -.552734-1.378906z"/></g></svg>
diff --git a/editor/icons/ParticlesMaterial.svg b/editor/icons/ParticleProcessMaterial.svg
index 33598980a5..33598980a5 100644
--- a/editor/icons/ParticlesMaterial.svg
+++ b/editor/icons/ParticleProcessMaterial.svg
diff --git a/editor/icons/RigidDynamicBody2D.svg b/editor/icons/RigidBody2D.svg
index 5d08e991ae..5d08e991ae 100644
--- a/editor/icons/RigidDynamicBody2D.svg
+++ b/editor/icons/RigidBody2D.svg
diff --git a/editor/icons/RigidDynamicBody3D.svg b/editor/icons/RigidBody3D.svg
index 7f5db4ce88..7f5db4ce88 100644
--- a/editor/icons/RigidDynamicBody3D.svg
+++ b/editor/icons/RigidBody3D.svg
diff --git a/editor/icons/SoftDynamicBody3D.svg b/editor/icons/SoftBody3D.svg
index 7bc9a22c22..7bc9a22c22 100644
--- a/editor/icons/SoftDynamicBody3D.svg
+++ b/editor/icons/SoftBody3D.svg
diff --git a/editor/icons/TorusMesh.svg b/editor/icons/TorusMesh.svg
new file mode 100644
index 0000000000..2ed973d3cf
--- /dev/null
+++ b/editor/icons/TorusMesh.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><ellipse cx="8" cy="7.5" fill="none" rx="6" ry="3.5" stroke="#ffca5f" stroke-linecap="square" stroke-linejoin="round" stroke-width="2"/></svg>
diff --git a/editor/import/audio_stream_import_settings.cpp b/editor/import/audio_stream_import_settings.cpp
index f3709efab6..cc7c5809d6 100644
--- a/editor/import/audio_stream_import_settings.cpp
+++ b/editor/import/audio_stream_import_settings.cpp
@@ -526,7 +526,7 @@ AudioStreamImportSettings::AudioStreamImportSettings() {
loop_hb->add_theme_constant_override("separation", 4 * EDSCALE);
loop = memnew(CheckBox);
loop->set_text(TTR("Enable"));
- loop->set_tooltip(TTR("Enable looping."));
+ loop->set_tooltip_text(TTR("Enable looping."));
loop->connect("toggled", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1));
loop_hb->add_child(loop);
loop_hb->add_spacer();
@@ -535,7 +535,7 @@ AudioStreamImportSettings::AudioStreamImportSettings() {
loop_offset->set_max(10000);
loop_offset->set_step(0.001);
loop_offset->set_suffix("sec");
- loop_offset->set_tooltip(TTR("Loop offset (from beginning). Note that if BPM is set, this setting will be ignored."));
+ loop_offset->set_tooltip_text(TTR("Loop offset (from beginning). Note that if BPM is set, this setting will be ignored."));
loop_offset->connect("value_changed", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1));
loop_hb->add_child(loop_offset);
main_vbox->add_margin_child(TTR("Loop:"), loop_hb);
@@ -549,14 +549,14 @@ AudioStreamImportSettings::AudioStreamImportSettings() {
bpm_edit = memnew(SpinBox);
bpm_edit->set_max(400);
bpm_edit->set_step(0.01);
- bpm_edit->set_tooltip(TTR("Configure the Beats Per Measure (tempo) used for the interactive streams.\nThis is required in order to configure beat information."));
+ bpm_edit->set_tooltip_text(TTR("Configure the Beats Per Measure (tempo) used for the interactive streams.\nThis is required in order to configure beat information."));
bpm_edit->connect("value_changed", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1));
interactive_hb->add_child(bpm_edit);
interactive_hb->add_spacer();
bar_beats_label = memnew(Label(TTR("Beats/Bar:")));
interactive_hb->add_child(bar_beats_label);
bar_beats_edit = memnew(SpinBox);
- bar_beats_edit->set_tooltip(TTR("Configure the Beats Per Bar. This used for music-aware transitions between AudioStreams."));
+ bar_beats_edit->set_tooltip_text(TTR("Configure the Beats Per Bar. This used for music-aware transitions between AudioStreams."));
bar_beats_edit->set_min(2);
bar_beats_edit->set_max(32);
bar_beats_edit->connect("value_changed", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1));
@@ -567,7 +567,7 @@ AudioStreamImportSettings::AudioStreamImportSettings() {
beats_enabled->connect("toggled", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1));
interactive_hb->add_child(beats_enabled);
beats_edit = memnew(SpinBox);
- beats_edit->set_tooltip(TTR("Configure the amount of Beats used for music-aware looping. If zero, it will be autodetected from the length.\nIt is recommended to set this value (either manually or by clicking on a beat number in the preview) to ensure looping works properly."));
+ beats_edit->set_tooltip_text(TTR("Configure the amount of Beats used for music-aware looping. If zero, it will be autodetected from the length.\nIt is recommended to set this value (either manually or by clicking on a beat number in the preview) to ensure looping works properly."));
beats_edit->set_max(99999);
beats_edit->connect("value_changed", callable_mp(this, &AudioStreamImportSettings::_settings_changed).unbind(1));
interactive_hb->add_child(beats_edit);
diff --git a/editor/import/collada.cpp b/editor/import/collada.cpp
index f4d19fe8b6..5d8e453395 100644
--- a/editor/import/collada.cpp
+++ b/editor/import/collada.cpp
@@ -131,7 +131,7 @@ Transform3D Collada::Node::compute_transform(const Collada &state) const {
switch (xf.op) {
case XForm::OP_ROTATE: {
if (xf.data.size() >= 4) {
- xform_step.rotate(Vector3(xf.data[0], xf.data[1], xf.data[2]), Math::deg2rad(xf.data[3]));
+ xform_step.rotate(Vector3(xf.data[0], xf.data[1], xf.data[2]), Math::deg_to_rad(xf.data[3]));
}
} break;
case XForm::OP_SCALE: {
@@ -289,7 +289,7 @@ void Collada::_parse_image(XMLParser &parser) {
String path = parser.get_attribute_value("source").strip_edges();
if (!path.contains("://") && path.is_relative_path()) {
// path is relative to file being loaded, so convert to a resource path
- image.path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().plus_file(path.uri_decode()));
+ image.path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().path_join(path.uri_decode()));
}
} else {
while (parser.read() == OK) {
@@ -302,7 +302,7 @@ void Collada::_parse_image(XMLParser &parser) {
if (!path.contains("://") && path.is_relative_path()) {
// path is relative to file being loaded, so convert to a resource path
- path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().plus_file(path));
+ path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().path_join(path));
} else if (path.find("file:///") == 0) {
path = path.replace_first("file:///", "");
diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp
index 043681aa87..0575f3cbf3 100644
--- a/editor/import/dynamic_font_import_settings.cpp
+++ b/editor/import/dynamic_font_import_settings.cpp
@@ -449,8 +449,8 @@ void DynamicFontImportSettings::_main_prop_changed(const String &p_edited_proper
// Update font preview.
if (font_preview.is_valid()) {
- if (p_edited_property == "antialiased") {
- font_preview->set_antialiased(import_settings_data->get("antialiased"));
+ if (p_edited_property == "antialiasing") {
+ font_preview->set_antialiasing((TextServer::FontAntialiasing)import_settings_data->get("antialiasing").operator int());
} else if (p_edited_property == "generate_mipmaps") {
font_preview->set_generate_mipmaps(import_settings_data->get("generate_mipmaps"));
} else if (p_edited_property == "multichannel_signed_distance_field") {
@@ -574,6 +574,12 @@ void DynamicFontImportSettings::_variations_validate() {
}
}
}
+ if ((TextServer::FontAntialiasing)(int)import_settings_data->get("antialiasing") == TextServer::FONT_ANTIALIASING_LCD) {
+ warn += "\n" + TTR("Note: LCD sub-pixel anti-aliasing is selected, each of the glyphs will be pre-rendered for all supported sub-pixel layouts (5x).");
+ }
+ if ((TextServer::SubpixelPositioning)(int)import_settings_data->get("subpixel_positioning") != TextServer::SUBPIXEL_POSITIONING_DISABLED) {
+ warn += "\n" + TTR("Note: Sub-pixel positioning is selected, each of the glyphs might be pre-rendered for multiple sub-pixel offsets (up to 4x).");
+ }
if (warn.is_empty()) {
label_warn->set_text("");
label_warn->hide();
@@ -881,7 +887,7 @@ void DynamicFontImportSettings::_re_import() {
HashMap<StringName, Variant> main_settings;
main_settings["face_index"] = import_settings_data->get("face_index");
- main_settings["antialiased"] = import_settings_data->get("antialiased");
+ main_settings["antialiasing"] = import_settings_data->get("antialiasing");
main_settings["generate_mipmaps"] = import_settings_data->get("generate_mipmaps");
main_settings["multichannel_signed_distance_field"] = import_settings_data->get("multichannel_signed_distance_field");
main_settings["msdf_pixel_range"] = import_settings_data->get("msdf_pixel_range");
@@ -1079,7 +1085,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) {
import_settings_data->notify_property_list_changed();
if (font_preview.is_valid()) {
- font_preview->set_antialiased(import_settings_data->get("antialiased"));
+ font_preview->set_antialiasing((TextServer::FontAntialiasing)import_settings_data->get("antialiasing").operator int());
font_preview->set_multichannel_signed_distance_field(import_settings_data->get("multichannel_signed_distance_field"));
font_preview->set_msdf_pixel_range(import_settings_data->get("msdf_pixel_range"));
font_preview->set_msdf_size(import_settings_data->get("msdf_size"));
@@ -1108,7 +1114,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() {
options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::NIL, "Rendering", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant()));
- options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "antialiased"), true));
+ options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD sub-pixel"), 1));
options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "generate_mipmaps"), false));
options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "msdf_pixel_range", PROPERTY_HINT_RANGE, "1,100,1"), 8));
@@ -1233,7 +1239,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() {
add_var = memnew(Button);
page2_hb_vars->add_child(add_var);
- add_var->set_tooltip(TTR("Add configuration"));
+ add_var->set_tooltip_text(TTR("Add configuration"));
add_var->set_icon(add_var->get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
add_var->connect("pressed", callable_mp(this, &DynamicFontImportSettings::_variation_add));
diff --git a/editor/import/editor_import_plugin.cpp b/editor/import/editor_import_plugin.cpp
index e822b4963a..3305f241c0 100644
--- a/editor/import/editor_import_plugin.cpp
+++ b/editor/import/editor_import_plugin.cpp
@@ -115,7 +115,7 @@ void EditorImportPlugin::get_import_options(const String &p_path, List<ResourceI
Array needed;
needed.push_back("name");
needed.push_back("default_value");
- Array options;
+ TypedArray<Dictionary> options;
if (GDVIRTUAL_CALL(_get_import_options, p_path, p_preset, options)) {
for (int i = 0; i < options.size(); i++) {
Dictionary d = options[i];
diff --git a/editor/import/editor_import_plugin.h b/editor/import/editor_import_plugin.h
index 4548513b6f..e9749c240f 100644
--- a/editor/import/editor_import_plugin.h
+++ b/editor/import/editor_import_plugin.h
@@ -32,6 +32,7 @@
#define EDITOR_IMPORT_PLUGIN_H
#include "core/io/resource_importer.h"
+#include "core/variant/typed_array.h"
class EditorImportPlugin : public ResourceImporter {
GDCLASS(EditorImportPlugin, ResourceImporter);
@@ -44,7 +45,7 @@ protected:
GDVIRTUAL0RC(int, _get_preset_count)
GDVIRTUAL1RC(String, _get_preset_name, int)
GDVIRTUAL0RC(Vector<String>, _get_recognized_extensions)
- GDVIRTUAL2RC(Array, _get_import_options, String, int)
+ GDVIRTUAL2RC(TypedArray<Dictionary>, _get_import_options, String, int)
GDVIRTUAL0RC(String, _get_save_extension)
GDVIRTUAL0RC(String, _get_resource_type)
GDVIRTUAL0RC(float, _get_priority)
diff --git a/editor/import/post_import_plugin_skeleton_rest_fixer.cpp b/editor/import/post_import_plugin_skeleton_rest_fixer.cpp
index 4f00bd120a..6f775c7ea8 100644
--- a/editor/import/post_import_plugin_skeleton_rest_fixer.cpp
+++ b/editor/import/post_import_plugin_skeleton_rest_fixer.cpp
@@ -38,16 +38,16 @@
void PostImportPluginSkeletonRestFixer::get_internal_import_options(InternalImportCategory p_category, List<ResourceImporter::ImportOption> *r_options) {
if (p_category == INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE) {
+ r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/apply_node_transforms"), true));
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/normalize_position_tracks"), true));
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/overwrite_axis"), true));
-
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/rest_fixer/fix_silhouette/enable"), false));
- r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::FLOAT, "retarget/rest_fixer/fix_silhouette/threshold"), 15));
-
// TODO: PostImportPlugin need to be implemented such as validate_option(PropertyInfo &property, const Dictionary &p_options).
// get_internal_option_visibility() is not sufficient because it can only retrieve options implemented in the core and can only read option values.
// r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::ARRAY, "retarget/rest_fixer/filter", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::STRING_NAME, PROPERTY_HINT_ENUM, "Hips,Spine,Chest")), Array()));
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::ARRAY, "retarget/rest_fixer/fix_silhouette/filter", PROPERTY_HINT_ARRAY_TYPE, "StringName"), Array()));
+ r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::FLOAT, "retarget/rest_fixer/fix_silhouette/threshold"), 15));
+ r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::FLOAT, "retarget/rest_fixer/fix_silhouette/base_height_adjustment", PROPERTY_HINT_RANGE, "-1,1,0.01"), 0.0));
}
}
@@ -67,6 +67,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
if (!src_skeleton) {
return;
}
+
bool is_renamed = bool(p_options["retarget/bone_renamer/rename_bones"]);
Array filter = p_options["retarget/rest_fixer/fix_silhouette/filter"];
bool is_rest_changed = false;
@@ -89,44 +90,96 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
}
}
- // Set motion scale to Skeleton if normalize position tracks.
- if (bool(p_options["retarget/rest_fixer/normalize_position_tracks"])) {
- int src_bone_idx = src_skeleton->find_bone(profile->get_scale_base_bone());
- if (src_bone_idx >= 0) {
- real_t motion_scale = abs(src_skeleton->get_bone_global_rest(src_bone_idx).origin.y);
- if (motion_scale > 0) {
- src_skeleton->set_motion_scale(motion_scale);
+ // Apply node transforms.
+ if (bool(p_options["retarget/rest_fixer/apply_node_transforms"])) {
+ LocalVector<Transform3D> old_skeleton_rest;
+ LocalVector<Transform3D> old_skeleton_global_rest;
+ for (int i = 0; i < src_skeleton->get_bone_count(); i++) {
+ old_skeleton_rest.push_back(src_skeleton->get_bone_rest(i));
+ old_skeleton_global_rest.push_back(src_skeleton->get_bone_global_rest(i));
+ }
+
+ Transform3D global_transform;
+ Node *pr = src_skeleton;
+ while (pr) {
+ Node3D *pr3d = Object::cast_to<Node3D>(pr);
+ if (pr3d) {
+ global_transform = pr3d->get_transform() * global_transform;
+ pr3d->set_transform(Transform3D());
}
+ pr = pr->get_parent();
}
+ Vector3 scl = global_transform.basis.get_scale_local();
- TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
- while (nodes.size()) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
- List<StringName> anims;
- ap->get_animation_list(&anims);
- for (const StringName &name : anims) {
- Ref<Animation> anim = ap->get_animation(name);
- int track_len = anim->get_track_count();
- for (int i = 0; i < track_len; i++) {
- if (anim->track_get_path(i).get_subname_count() != 1 || anim->track_get_type(i) != Animation::TYPE_POSITION_3D) {
- continue;
- }
+ Vector<int> bones_to_process = src_skeleton->get_parentless_bones();
+ for (int i = 0; i < bones_to_process.size(); i++) {
+ src_skeleton->set_bone_rest(bones_to_process[i], global_transform.orthonormalized() * src_skeleton->get_bone_rest(bones_to_process[i]));
+ }
- if (anim->track_is_compressed(i)) {
- continue; // Shouldn't occur in internal_process().
- }
+ while (bones_to_process.size() > 0) {
+ int src_idx = bones_to_process[0];
+ bones_to_process.erase(src_idx);
+ Vector<int> src_children = src_skeleton->get_bone_children(src_idx);
+ for (int i = 0; i < src_children.size(); i++) {
+ bones_to_process.push_back(src_children[i]);
+ }
+ src_skeleton->set_bone_rest(src_idx, Transform3D(src_skeleton->get_bone_rest(src_idx).basis, src_skeleton->get_bone_rest(src_idx).origin * scl));
+ }
- String track_path = String(anim->track_get_path(i).get_concatenated_names());
- Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path));
- if (node) {
- Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
- if (track_skeleton) {
+ // Fix animation.
+ bones_to_process = src_skeleton->get_parentless_bones();
+ {
+ TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
+ while (nodes.size()) {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
+ List<StringName> anims;
+ ap->get_animation_list(&anims);
+ for (const StringName &name : anims) {
+ Ref<Animation> anim = ap->get_animation(name);
+ int track_len = anim->get_track_count();
+ for (int i = 0; i < track_len; i++) {
+ if (anim->track_get_path(i).get_subname_count() != 1 || !(anim->track_get_type(i) == Animation::TYPE_POSITION_3D || anim->track_get_type(i) == Animation::TYPE_ROTATION_3D || anim->track_get_type(i) == Animation::TYPE_SCALE_3D)) {
+ continue;
+ }
+
+ if (anim->track_is_compressed(i)) {
+ continue; // Shouldn't occur in internal_process().
+ }
+
+ String track_path = String(anim->track_get_path(i).get_concatenated_names());
+ Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path));
+ if (node) {
+ Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
if (track_skeleton && track_skeleton == src_skeleton) {
- real_t mlt = 1 / src_skeleton->get_motion_scale();
- int key_len = anim->track_get_key_count(i);
- for (int j = 0; j < key_len; j++) {
- Vector3 pos = static_cast<Vector3>(anim->track_get_key_value(i, j));
- anim->track_set_key_value(i, j, pos * mlt);
+ StringName bn = anim->track_get_path(i).get_subname(0);
+ if (bn) {
+ int bone_idx = src_skeleton->find_bone(bn);
+ int key_len = anim->track_get_key_count(i);
+ if (anim->track_get_type(i) == Animation::TYPE_POSITION_3D) {
+ if (bones_to_process.has(bone_idx)) {
+ for (int j = 0; j < key_len; j++) {
+ Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j));
+ anim->track_set_key_value(i, j, global_transform.basis.xform(ps) + global_transform.origin);
+ }
+ } else {
+ for (int j = 0; j < key_len; j++) {
+ Vector3 ps = static_cast<Vector3>(anim->track_get_key_value(i, j));
+ anim->track_set_key_value(i, j, ps * scl);
+ }
+ }
+ } else if (bones_to_process.has(bone_idx)) {
+ if (anim->track_get_type(i) == Animation::TYPE_ROTATION_3D) {
+ for (int j = 0; j < key_len; j++) {
+ Quaternion qt = static_cast<Quaternion>(anim->track_get_key_value(i, j));
+ anim->track_set_key_value(i, j, global_transform.basis.get_rotation_quaternion() * qt);
+ }
+ } else {
+ for (int j = 0; j < key_len; j++) {
+ Basis sc = Basis().scaled(static_cast<Vector3>(anim->track_get_key_value(i, j)));
+ anim->track_set_key_value(i, j, (global_transform.basis * sc).get_scale());
+ }
+ }
+ }
}
}
}
@@ -134,6 +187,8 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
}
}
}
+
+ is_rest_changed = true;
}
// Complement Rotation track for compatibility between different rests.
@@ -269,7 +324,7 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
Vector3 src_dir = src_tail - src_head;
// Rotate rest.
- if (Math::abs(Math::rad2deg(src_dir.angle_to(prof_dir))) > float(p_options["retarget/rest_fixer/fix_silhouette/threshold"])) {
+ if (Math::abs(Math::rad_to_deg(src_dir.angle_to(prof_dir))) > float(p_options["retarget/rest_fixer/fix_silhouette/threshold"])) {
// Get rotation difference.
Vector3 up_vec; // Need to rotate other than roll axis.
switch (Vector3(abs(src_dir.x), abs(src_dir.y), abs(src_dir.z)).min_axis_index()) {
@@ -303,6 +358,52 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
}
}
+ // Adjust scale base bone height.
+ float base_adjustment = float(p_options["retarget/rest_fixer/fix_silhouette/base_height_adjustment"]);
+ if (!Math::is_zero_approx(base_adjustment)) {
+ StringName scale_base_bone_name = profile->get_scale_base_bone();
+ int src_bone_idx = src_skeleton->find_bone(scale_base_bone_name);
+ Transform3D src_rest = src_skeleton->get_bone_rest(src_bone_idx);
+ src_skeleton->set_bone_rest(src_bone_idx, Transform3D(src_rest.basis, Vector3(src_rest.origin.x, src_rest.origin.y + base_adjustment, src_rest.origin.z)));
+
+ TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
+ while (nodes.size()) {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
+ List<StringName> anims;
+ ap->get_animation_list(&anims);
+ for (const StringName &name : anims) {
+ Ref<Animation> anim = ap->get_animation(name);
+ int track_len = anim->get_track_count();
+ for (int i = 0; i < track_len; i++) {
+ if (anim->track_get_path(i).get_subname_count() != 1 || anim->track_get_type(i) != Animation::TYPE_POSITION_3D) {
+ continue;
+ }
+
+ if (anim->track_is_compressed(i)) {
+ continue; // Shouldn't occur in internal_process().
+ }
+
+ String track_path = String(anim->track_get_path(i).get_concatenated_names());
+ Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path));
+ if (node) {
+ Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
+ if (track_skeleton && track_skeleton == src_skeleton) {
+ StringName bn = anim->track_get_path(i).get_concatenated_subnames();
+ if (bn == scale_base_bone_name) {
+ int key_len = anim->track_get_key_count(i);
+ for (int j = 0; j < key_len; j++) {
+ Vector3 pos = static_cast<Vector3>(anim->track_get_key_value(i, j));
+ pos.y += base_adjustment;
+ anim->track_set_key_value(i, j, pos);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
// For skin modification in overwrite rest.
for (int i = 0; i < src_skeleton->get_bone_count(); i++) {
silhouette_diff_w[i] = old_skeleton_global_rest[i] * src_skeleton->get_bone_global_rest(i).inverse();
@@ -311,6 +412,51 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
is_rest_changed = true;
}
+ // Set motion scale to Skeleton if normalize position tracks.
+ if (bool(p_options["retarget/rest_fixer/normalize_position_tracks"])) {
+ int src_bone_idx = src_skeleton->find_bone(profile->get_scale_base_bone());
+ if (src_bone_idx >= 0) {
+ real_t motion_scale = abs(src_skeleton->get_bone_global_rest(src_bone_idx).origin.y);
+ if (motion_scale > 0) {
+ src_skeleton->set_motion_scale(motion_scale);
+ }
+ }
+
+ TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
+ while (nodes.size()) {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
+ List<StringName> anims;
+ ap->get_animation_list(&anims);
+ for (const StringName &name : anims) {
+ Ref<Animation> anim = ap->get_animation(name);
+ int track_len = anim->get_track_count();
+ for (int i = 0; i < track_len; i++) {
+ if (anim->track_get_path(i).get_subname_count() != 1 || anim->track_get_type(i) != Animation::TYPE_POSITION_3D) {
+ continue;
+ }
+
+ if (anim->track_is_compressed(i)) {
+ continue; // Shouldn't occur in internal_process().
+ }
+
+ String track_path = String(anim->track_get_path(i).get_concatenated_names());
+ Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path));
+ if (node) {
+ Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
+ if (track_skeleton && track_skeleton == src_skeleton) {
+ real_t mlt = 1 / src_skeleton->get_motion_scale();
+ int key_len = anim->track_get_key_count(i);
+ for (int j = 0; j < key_len; j++) {
+ Vector3 pos = static_cast<Vector3>(anim->track_get_key_value(i, j));
+ anim->track_set_key_value(i, j, pos * mlt);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
// Overwrite axis.
if (bool(p_options["retarget/rest_fixer/overwrite_axis"])) {
LocalVector<Transform3D> old_skeleton_rest;
@@ -367,32 +513,6 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
src_skeleton->set_bone_rest(src_idx, Transform3D(tgt_rot, diff.xform(src_skeleton->get_bone_rest(src_idx).origin)));
}
- // Fix skin.
- {
- TypedArray<Node> nodes = p_base_scene->find_children("*", "ImporterMeshInstance3D");
- while (nodes.size()) {
- ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(nodes.pop_back());
- Ref<Skin> skin = mi->get_skin();
- if (skin.is_valid()) {
- Node *node = mi->get_node(mi->get_skeleton_path());
- if (node) {
- Skeleton3D *mesh_skeleton = Object::cast_to<Skeleton3D>(node);
- if (mesh_skeleton && node == src_skeleton) {
- int skin_len = skin->get_bind_count();
- for (int i = 0; i < skin_len; i++) {
- StringName bn = skin->get_bind_name(i);
- int bone_idx = src_skeleton->find_bone(bn);
- if (bone_idx >= 0) {
- Transform3D new_rest = silhouette_diff[i] * src_skeleton->get_bone_global_rest(bone_idx);
- skin->set_bind_pose(i, new_rest.inverse());
- }
- }
- }
- }
- }
- }
- }
-
// Fix animation.
{
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
@@ -471,8 +591,34 @@ void PostImportPluginSkeletonRestFixer::internal_process(InternalImportCategory
is_rest_changed = true;
}
- // Init skeleton pose to new rest.
if (is_rest_changed) {
+ // Fix skin.
+ {
+ TypedArray<Node> nodes = p_base_scene->find_children("*", "ImporterMeshInstance3D");
+ while (nodes.size()) {
+ ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(nodes.pop_back());
+ Ref<Skin> skin = mi->get_skin();
+ if (skin.is_valid()) {
+ Node *node = mi->get_node(mi->get_skeleton_path());
+ if (node) {
+ Skeleton3D *mesh_skeleton = Object::cast_to<Skeleton3D>(node);
+ if (mesh_skeleton && node == src_skeleton) {
+ int skin_len = skin->get_bind_count();
+ for (int i = 0; i < skin_len; i++) {
+ StringName bn = skin->get_bind_name(i);
+ int bone_idx = src_skeleton->find_bone(bn);
+ if (bone_idx >= 0) {
+ Transform3D new_rest = silhouette_diff[i] * src_skeleton->get_bone_global_rest(bone_idx);
+ skin->set_bind_pose(i, new_rest.inverse());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Init skeleton pose to new rest.
for (int i = 0; i < src_skeleton->get_bone_count(); i++) {
Transform3D fixed_rest = src_skeleton->get_bone_rest(i);
src_skeleton->set_bone_pose_position(i, fixed_rest.origin);
diff --git a/editor/import/resource_importer_dynamic_font.cpp b/editor/import/resource_importer_dynamic_font.cpp
index 32fd94b093..c822cd0fec 100644
--- a/editor/import/resource_importer_dynamic_font.cpp
+++ b/editor/import/resource_importer_dynamic_font.cpp
@@ -105,7 +105,7 @@ void ResourceImporterDynamicFont::get_import_options(const String &p_path, List<
r_options->push_back(ImportOption(PropertyInfo(Variant::NIL, "Rendering", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant()));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "antialiased"), true));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD sub-pixel"), 1));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "generate_mipmaps"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), (msdf) ? true : false));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "msdf_pixel_range", PROPERTY_HINT_RANGE, "1,100,1"), 8));
@@ -139,7 +139,7 @@ void ResourceImporterDynamicFont::show_advanced_options(const String &p_path) {
Error ResourceImporterDynamicFont::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
print_verbose("Importing dynamic font from: " + p_source_file);
- bool antialiased = p_options["antialiased"];
+ int antialiasing = p_options["antialiasing"];
bool generate_mipmaps = p_options["generate_mipmaps"];
bool msdf = p_options["multichannel_signed_distance_field"];
int px_range = p_options["msdf_pixel_range"];
@@ -159,7 +159,7 @@ Error ResourceImporterDynamicFont::import(const String &p_source_file, const Str
Ref<FontFile> font;
font.instantiate();
font->set_data(data);
- font->set_antialiased(antialiased);
+ font->set_antialiasing((TextServer::FontAntialiasing)antialiasing);
font->set_generate_mipmaps(generate_mipmaps);
font->set_multichannel_signed_distance_field(msdf);
font->set_msdf_pixel_range(px_range);
diff --git a/editor/import/resource_importer_imagefont.cpp b/editor/import/resource_importer_imagefont.cpp
index 374cbe7ce2..58c2061051 100644
--- a/editor/import/resource_importer_imagefont.cpp
+++ b/editor/import/resource_importer_imagefont.cpp
@@ -99,7 +99,7 @@ Error ResourceImporterImageFont::import(const String &p_source_file, const Strin
Ref<FontFile> font;
font.instantiate();
- font->set_antialiased(false);
+ font->set_antialiasing(TextServer::FONT_ANTIALIASING_NONE);
font->set_generate_mipmaps(false);
font->set_multichannel_signed_distance_field(false);
font->set_fixed_size(base_size);
diff --git a/editor/import/resource_importer_layered_texture.cpp b/editor/import/resource_importer_layered_texture.cpp
index a5dfd67d18..ed83535421 100644
--- a/editor/import/resource_importer_layered_texture.cpp
+++ b/editor/import/resource_importer_layered_texture.cpp
@@ -139,7 +139,7 @@ void ResourceImporterLayeredTexture::get_import_options(const String &p_path, Li
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "compress/lossy_quality", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.7));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/hdr_compression", PROPERTY_HINT_ENUM, "Disabled,Opaque Only,Always"), 1));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/bptc_ldr", PROPERTY_HINT_ENUM, "Disabled,Enabled,RGBA Only"), 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/channel_pack", PROPERTY_HINT_ENUM, "sRGB Friendly,Optimized"), 0));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/channel_pack", PROPERTY_HINT_ENUM, "sRGB Friendly,Optimized,Normal Map (RG Channels)"), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "mipmaps/generate"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "mipmaps/limit", PROPERTY_HINT_RANGE, "-1,256"), -1));
@@ -250,7 +250,7 @@ void ResourceImporterLayeredTexture::_save_tex(Vector<Ref<Image>> p_images, cons
}
if (p_mipmaps) {
- p_images.write[i]->generate_mipmaps();
+ p_images.write[i]->generate_mipmaps(p_csource == Image::COMPRESS_SOURCE_NORMAL);
} else {
p_images.write[i]->clear_mipmaps();
}
@@ -327,7 +327,7 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const
Ref<Image> image;
image.instantiate();
- Error err = ImageLoader::load_image(p_source_file, image, nullptr, false, 1.0);
+ Error err = ImageLoader::load_image(p_source_file, image);
if (err != OK) {
return err;
}
@@ -354,6 +354,9 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const
Image::CompressSource csource = Image::COMPRESS_SOURCE_GENERIC;
if (channel_pack == 0) {
csource = Image::COMPRESS_SOURCE_SRGB;
+ } else if (channel_pack == 2) {
+ // force normal
+ csource = Image::COMPRESS_SOURCE_NORMAL;
}
Image::UsedChannels used_channels = image->detect_used_channels(csource);
@@ -391,7 +394,7 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const
texture_import->bptc_ldr = bptc_ldr;
texture_import->mipmaps = mipmaps;
texture_import->used_channels = used_channels;
- _check_compress_ctex(texture_import);
+ _check_compress_ctex(p_source_file, texture_import);
if (r_metadata) {
Dictionary metadata;
metadata["vram_texture"] = compress_mode == COMPRESS_VRAM_COMPRESSED;
@@ -472,7 +475,7 @@ ResourceImporterLayeredTexture::ResourceImporterLayeredTexture() {
ResourceImporterLayeredTexture::~ResourceImporterLayeredTexture() {
}
-void ResourceImporterLayeredTexture::_check_compress_ctex(Ref<LayeredTextureImport> r_texture_import) {
+void ResourceImporterLayeredTexture::_check_compress_ctex(const String &p_source_file, Ref<LayeredTextureImport> r_texture_import) {
String extension = get_save_extension();
ERR_FAIL_NULL(r_texture_import->csource);
if (r_texture_import->compress_mode != COMPRESS_VRAM_COMPRESSED) {
@@ -542,5 +545,5 @@ void ResourceImporterLayeredTexture::_check_compress_ctex(Ref<LayeredTextureImpo
}
return;
}
- EditorNode::add_io_error(TTR("Warning, no suitable PC VRAM compression enabled in Project Settings. This texture will not display correctly on PC."));
+ EditorNode::add_io_error(vformat(TTR("%s: No suitable PC VRAM compression algorithm enabled in Project Settings (S3TC or BPTC). This texture may not display correctly on desktop platforms."), p_source_file));
}
diff --git a/editor/import/resource_importer_layered_texture.h b/editor/import/resource_importer_layered_texture.h
index 5a29010c3b..e292390fb3 100644
--- a/editor/import/resource_importer_layered_texture.h
+++ b/editor/import/resource_importer_layered_texture.h
@@ -87,7 +87,7 @@ protected:
static ResourceImporterLayeredTexture *singleton;
public:
- void _check_compress_ctex(Ref<LayeredTextureImport> r_texture_import);
+ void _check_compress_ctex(const String &p_source_file, Ref<LayeredTextureImport> r_texture_import);
static ResourceImporterLayeredTexture *get_singleton() { return singleton; }
virtual String get_importer_name() const override;
diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp
index d1c4e1f8dd..fe70fd58b5 100644
--- a/editor/import/resource_importer_obj.cpp
+++ b/editor/import/resource_importer_obj.cpp
@@ -129,7 +129,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S
if (p.is_absolute_path()) {
path = p;
} else {
- path = base_path.plus_file(p);
+ path = base_path.path_join(p);
}
Ref<Texture2D> texture = ResourceLoader::load(path);
@@ -149,7 +149,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S
if (p.is_absolute_path()) {
path = p;
} else {
- path = base_path.plus_file(p);
+ path = base_path.path_join(p);
}
Ref<Texture2D> texture = ResourceLoader::load(path);
@@ -169,7 +169,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S
if (p.is_absolute_path()) {
path = p;
} else {
- path = base_path.plus_file(p);
+ path = base_path.path_join(p);
}
Ref<Texture2D> texture = ResourceLoader::load(path);
@@ -184,7 +184,7 @@ static Error _parse_material_library(const String &p_path, HashMap<String, Ref<S
ERR_FAIL_COND_V(current.is_null(), ERR_FILE_CORRUPT);
String p = l.replace("map_bump", "").replace("\\", "/").strip_edges();
- String path = base_path.plus_file(p);
+ String path = base_path.path_join(p);
Ref<Texture2D> texture = ResourceLoader::load(path);
@@ -405,7 +405,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
HashMap<String, Ref<StandardMaterial3D>> lib;
String lib_path = current_material_library;
if (lib_path.is_relative_path()) {
- lib_path = p_path.get_base_dir().plus_file(current_material_library);
+ lib_path = p_path.get_base_dir().path_join(current_material_library);
}
Error err = _parse_material_library(lib_path, lib, r_missing_deps);
if (err == OK) {
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 3c0de61d24..62cb6e4167 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -565,7 +565,7 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, HashMap<R
_pre_gen_shape_list(mesh, shapes, true);
}
- RigidDynamicBody3D *rigid_body = memnew(RigidDynamicBody3D);
+ RigidBody3D *rigid_body = memnew(RigidBody3D);
rigid_body->set_name(_fixstr(name, "rigid_body"));
p_node->replace_by(rigid_body);
rigid_body->set_transform(mi->get_transform());
@@ -850,12 +850,12 @@ Node *ResourceImporterScene::_post_fix_animations(Node *p_node, Node *p_root, co
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
bool use_optimizer = node_settings["optimizer/enabled"];
- float anim_optimizer_linerr = node_settings["optimizer/max_linear_error"];
+ float anim_optimizer_linerr = node_settings["optimizer/max_velocity_error"];
float anim_optimizer_angerr = node_settings["optimizer/max_angular_error"];
- float anim_optimizer_maxang = node_settings["optimizer/max_angle"];
+ int anim_optimizer_preerr = node_settings["optimizer/max_precision_error"];
if (use_optimizer) {
- _optimize_animations(ap, anim_optimizer_linerr, anim_optimizer_angerr, anim_optimizer_maxang);
+ _optimize_animations(ap, anim_optimizer_linerr, anim_optimizer_angerr, anim_optimizer_preerr);
}
bool use_compression = node_settings["compression/enabled"];
@@ -1060,7 +1060,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
base = col;
} break;
case MESH_PHYSICS_RIGID_BODY_AND_MESH: {
- RigidDynamicBody3D *rigid_body = memnew(RigidDynamicBody3D);
+ RigidBody3D *rigid_body = memnew(RigidBody3D);
rigid_body->set_name(p_node->get_name());
p_node->replace_by(rigid_body);
rigid_body->set_transform(mi->get_transform() * get_collision_shapes_transform(node_settings));
@@ -1386,12 +1386,12 @@ void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_
al->remove_animation("default"); // Remove default (no longer needed).
}
-void ResourceImporterScene::_optimize_animations(AnimationPlayer *anim, float p_max_lin_error, float p_max_ang_error, float p_max_angle) {
+void ResourceImporterScene::_optimize_animations(AnimationPlayer *anim, float p_max_vel_error, float p_max_ang_error, int p_prc_error) {
List<StringName> anim_names;
anim->get_animation_list(&anim_names);
for (const StringName &E : anim_names) {
Ref<Animation> a = anim->get_animation(E);
- a->optimize(p_max_lin_error, p_max_ang_error, Math::deg2rad(p_max_angle));
+ a->optimize(p_max_vel_error, p_max_ang_error, p_prc_error);
}
}
@@ -1467,9 +1467,9 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p
case INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE: {
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "import/skip_import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "optimizer/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
- r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_linear_error"), 0.05));
- r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_angular_error"), 0.01));
- r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_angle"), 22));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_velocity_error", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.01));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "optimizer/max_angular_error", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.01));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "optimizer/max_precision_error", PROPERTY_HINT_NONE, "1,6,1"), 3));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compression/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compression/page_size", PROPERTY_HINT_RANGE, "4,512,1,suffix:kb"), 8));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_tracks/position", PROPERTY_HINT_ENUM, "IfPresent,IfPresentForAll,Never"), 1));
diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h
index b336931476..da37893cc5 100644
--- a/editor/import/resource_importer_scene.h
+++ b/editor/import/resource_importer_scene.h
@@ -280,7 +280,7 @@ public:
Ref<Animation> _save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, String p_save_to_path, bool p_keep_custom_tracks);
void _create_clips(AnimationPlayer *anim, const Array &p_clips, bool p_bake_all);
- void _optimize_animations(AnimationPlayer *anim, float p_max_lin_error, float p_max_ang_error, float p_max_angle);
+ void _optimize_animations(AnimationPlayer *anim, float p_max_vel_error, float p_max_ang_error, int p_prc_error);
void _compress_animations(AnimationPlayer *anim, int p_page_size_kb);
Node *pre_import(const String &p_source_file, const HashMap<StringName, Variant> &p_options);
diff --git a/editor/import/resource_importer_shader_file.cpp b/editor/import/resource_importer_shader_file.cpp
index d3079141e0..55afd71c76 100644
--- a/editor/import/resource_importer_shader_file.cpp
+++ b/editor/import/resource_importer_shader_file.cpp
@@ -79,7 +79,7 @@ static String _include_function(const String &p_path, void *userpointer) {
String include = p_path;
if (include.is_relative_path()) {
- include = base_path->plus_file(include);
+ include = base_path->path_join(include);
}
Ref<FileAccess> file_inc = FileAccess::open(include, FileAccess::READ, &err);
diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp
index deb3047864..17b94ec706 100644
--- a/editor/import/resource_importer_texture.cpp
+++ b/editor/import/resource_importer_texture.cpp
@@ -409,11 +409,26 @@ void ResourceImporterTexture::_save_ctex(const Ref<Image> &p_image, const String
}
Error ResourceImporterTexture::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
+ // Parse import options.
+ int32_t loader_flags = ImageFormatLoader::FLAG_NONE;
+
+ // Compression.
CompressMode compress_mode = CompressMode(int(p_options["compress/mode"]));
const float lossy = p_options["compress/lossy_quality"];
const int pack_channels = p_options["compress/channel_pack"];
+ const int normal = p_options["compress/normal_map"];
+ const int hdr_compression = p_options["compress/hdr_compression"];
+ const int bptc_ldr = p_options["compress/bptc_ldr"];
+
+ // Mipmaps.
const bool mipmaps = p_options["mipmaps/generate"];
const uint32_t mipmap_limit = mipmaps ? uint32_t(p_options["mipmaps/limit"]) : uint32_t(-1);
+
+ // Roughness.
+ const int roughness = p_options["roughness/mode"];
+ const String normal_map = p_options["roughness/src_normal"];
+
+ // Processing.
const bool fix_alpha_border = p_options["process/fix_alpha_border"];
const bool premult_alpha = p_options["process/premult_alpha"];
const bool normal_map_invert_y = p_options["process/normal_map_invert_y"];
@@ -421,29 +436,29 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
const bool stream = false;
const int size_limit = p_options["process/size_limit"];
const bool hdr_as_srgb = p_options["process/hdr_as_srgb"];
+ if (hdr_as_srgb) {
+ loader_flags |= ImageFormatLoader::FLAG_FORCE_LINEAR;
+ }
const bool hdr_clamp_exposure = p_options["process/hdr_clamp_exposure"];
- const int normal = p_options["compress/normal_map"];
- const int hdr_compression = p_options["compress/hdr_compression"];
- const int bptc_ldr = p_options["compress/bptc_ldr"];
- const int roughness = p_options["roughness/mode"];
- const String normal_map = p_options["roughness/src_normal"];
+
float scale = 1.0;
+ // SVG-specific options.
if (p_options.has("svg/scale")) {
scale = p_options["svg/scale"];
}
Ref<Image> normal_image;
Image::RoughnessChannel roughness_channel = Image::ROUGHNESS_CHANNEL_R;
-
if (mipmaps && roughness > 1 && FileAccess::exists(normal_map)) {
normal_image.instantiate();
if (ImageLoader::load_image(normal_map, normal_image) == OK) {
roughness_channel = Image::RoughnessChannel(roughness - 2);
}
}
+
Ref<Image> image;
image.instantiate();
- Error err = ImageLoader::load_image(p_source_file, image, nullptr, hdr_as_srgb, scale);
+ Error err = ImageLoader::load_image(p_source_file, image, nullptr, loader_flags, scale);
if (err != OK) {
return err;
}
@@ -597,7 +612,7 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
}
if (!ok_on_pc) {
- EditorNode::add_io_error(TTR("Warning, no suitable PC VRAM compression enabled in Project Settings. This texture will not display correctly on PC."));
+ EditorNode::add_io_error(vformat(TTR("%s: No suitable desktop VRAM compression algorithm enabled in Project Settings (S3TC or BPTC). This texture may not display correctly on desktop platforms."), p_source_file));
}
} else {
//import normally
diff --git a/editor/import/resource_importer_texture_atlas.cpp b/editor/import/resource_importer_texture_atlas.cpp
index bae1b903c6..9171f04f42 100644
--- a/editor/import/resource_importer_texture_atlas.cpp
+++ b/editor/import/resource_importer_texture_atlas.cpp
@@ -382,7 +382,6 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file
mesh_texture->set_mesh(mesh);
texture = mesh_texture;
- //mesh
}
String save_path = p_base_paths[E.key] + ".res";
diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp
index a1e00f7d30..1dcae2841b 100644
--- a/editor/import/resource_importer_wav.cpp
+++ b/editor/import/resource_importer_wav.cpp
@@ -390,7 +390,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
int first = 0;
int last = (frames / format_channels) - 1;
bool found = false;
- float limit = Math::db2linear(TRIM_DB_LIMIT);
+ float limit = Math::db_to_linear(TRIM_DB_LIMIT);
for (int i = 0; i < data.size() / format_channels; i++) {
float ampChannelSum = 0;
diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp
index 6c12464b5a..21292d3282 100644
--- a/editor/import/scene_import_settings.cpp
+++ b/editor/import/scene_import_settings.cpp
@@ -1029,7 +1029,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
item->set_metadata(0, E.key);
item->set_editable(0, true);
item->set_checked(0, true);
- String path = p_path.plus_file(name);
+ String path = p_path.path_join(name);
if (external_extension_type->get_selected() == 0) {
path += ".tres";
} else {
@@ -1082,7 +1082,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
item->set_metadata(0, E.key);
item->set_editable(0, true);
item->set_checked(0, true);
- String path = p_path.plus_file(name);
+ String path = p_path.path_join(name);
if (external_extension_type->get_selected() == 0) {
path += ".tres";
} else {
@@ -1134,7 +1134,7 @@ void SceneImportSettings::_save_dir_callback(const String &p_path) {
item->set_metadata(0, E.key);
item->set_editable(0, true);
item->set_checked(0, true);
- String path = p_path.plus_file(name);
+ String path = p_path.path_join(name);
if (external_extension_type->get_selected() == 0) {
path += ".tres";
} else {
diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp
index 087ef48b56..4732268256 100644
--- a/editor/import_dock.cpp
+++ b/editor/import_dock.cpp
@@ -584,12 +584,12 @@ void ImportDock::_set_dirty(bool p_dirty) {
// Add a dirty marker to notify the user that they should reimport the selected resource to see changes.
import->set_text(TTR("Reimport") + " (*)");
import->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
- import->set_tooltip(TTR("You have pending changes that haven't been applied yet. Click Reimport to apply changes made to the import options.\nSelecting another resource in the FileSystem dock without clicking Reimport first will discard changes made in the Import dock."));
+ import->set_tooltip_text(TTR("You have pending changes that haven't been applied yet. Click Reimport to apply changes made to the import options.\nSelecting another resource in the FileSystem dock without clicking Reimport first will discard changes made in the Import dock."));
} else {
// Remove the dirty marker on the Reimport button.
import->set_text(TTR("Reimport"));
import->remove_theme_color_override("font_color");
- import->set_tooltip("");
+ import->set_tooltip_text("");
}
}
@@ -628,6 +628,9 @@ ImportDock::ImportDock() {
content->add_margin_child(TTR("Import As:"), hb);
import_as = memnew(OptionButton);
import_as->set_disabled(true);
+ import_as->set_fit_to_longest_item(false);
+ import_as->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
+ import_as->set_h_size_flags(SIZE_EXPAND_FILL);
import_as->connect("item_selected", callable_mp(this, &ImportDock::_importer_selected));
hb->add_child(import_as);
import_as->set_h_size_flags(SIZE_EXPAND_FILL);
diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp
index 79d94246ad..7af04e17c1 100644
--- a/editor/inspector_dock.cpp
+++ b/editor/inspector_dock.cpp
@@ -178,7 +178,8 @@ void InspectorDock::_menu_option_confirm(int p_option, bool p_confirmed) {
}
}
- editor_data->get_undo_redo().clear_history();
+ int history_id = editor_data->get_undo_redo()->get_history_for_object(current).id;
+ editor_data->get_undo_redo()->clear_history(true, history_id);
EditorNode::get_singleton()->get_editor_plugins_over()->edit(nullptr);
EditorNode::get_singleton()->get_editor_plugins_over()->edit(current);
@@ -246,7 +247,7 @@ void InspectorDock::_resource_file_selected(String p_file) {
}
if (res.is_null()) {
- warning_dialog->set_text(TTR("Failed to load resource."));
+ info_dialog->set_text(TTR("Failed to load resource."));
return;
};
@@ -408,8 +409,8 @@ void InspectorDock::_menu_expand_revertable() {
inspector->expand_revertable();
}
-void InspectorDock::_warning_pressed() {
- warning_dialog->popup_centered();
+void InspectorDock::_info_pressed() {
+ info_dialog->popup_centered();
}
Container *InspectorDock::get_addon_area() {
@@ -445,8 +446,13 @@ void InspectorDock::_notification(int p_what) {
history_menu->set_icon(get_theme_icon(SNAME("History"), SNAME("EditorIcons")));
object_menu->set_icon(get_theme_icon(SNAME("Tools"), SNAME("EditorIcons")));
search->set_right_icon(get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
- warning->set_icon(get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons")));
- warning->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
+ if (info_is_warning) {
+ info->set_icon(get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons")));
+ info->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
+ } else {
+ info->set_icon(get_theme_icon(SNAME("NodeInfo"), SNAME("EditorIcons")));
+ info->add_theme_color_override("font_color", get_theme_color(SNAME("font_color"), SNAME("Editor")));
+ }
} break;
}
}
@@ -475,11 +481,22 @@ void InspectorDock::open_resource(const String &p_type) {
_load_resource(p_type);
}
-void InspectorDock::set_warning(const String &p_message) {
- warning->hide();
- if (!p_message.is_empty()) {
- warning->show();
- warning_dialog->set_text(p_message);
+void InspectorDock::set_info(const String &p_button_text, const String &p_message, bool p_is_warning) {
+ info->hide();
+ info_is_warning = p_is_warning;
+
+ if (info_is_warning) {
+ info->set_icon(get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons")));
+ info->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
+ } else {
+ info->set_icon(get_theme_icon(SNAME("NodeInfo"), SNAME("EditorIcons")));
+ info->add_theme_color_override("font_color", get_theme_color(SNAME("font_color"), SNAME("Editor")));
+ }
+
+ if (!p_button_text.is_empty() && !p_message.is_empty()) {
+ info->show();
+ info->set_text(p_button_text);
+ info_dialog->set_text(p_message);
}
}
@@ -514,7 +531,7 @@ void InspectorDock::update(Object *p_object) {
resource_extra_popup->set_item_disabled(resource_extra_popup->get_item_index(RESOURCE_MAKE_BUILT_IN), !is_resource || is_text_file);
if (!is_object || is_text_file) {
- warning->hide();
+ info->hide();
editor_path->clear_path();
return;
}
@@ -616,20 +633,20 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) {
resource_new_button = memnew(Button);
resource_new_button->set_flat(true);
- resource_new_button->set_tooltip(TTR("Create a new resource in memory and edit it."));
+ resource_new_button->set_tooltip_text(TTR("Create a new resource in memory and edit it."));
general_options_hb->add_child(resource_new_button);
resource_new_button->connect("pressed", callable_mp(this, &InspectorDock::_new_resource));
resource_new_button->set_focus_mode(Control::FOCUS_NONE);
resource_load_button = memnew(Button);
resource_load_button->set_flat(true);
- resource_load_button->set_tooltip(TTR("Load an existing resource from disk and edit it."));
+ resource_load_button->set_tooltip_text(TTR("Load an existing resource from disk and edit it."));
general_options_hb->add_child(resource_load_button);
resource_load_button->connect("pressed", callable_mp(this, &InspectorDock::_open_resource_selector));
resource_load_button->set_focus_mode(Control::FOCUS_NONE);
resource_save_button = memnew(MenuButton);
- resource_save_button->set_tooltip(TTR("Save the currently edited resource."));
+ resource_save_button->set_tooltip_text(TTR("Save the currently edited resource."));
general_options_hb->add_child(resource_save_button);
resource_save_button->get_popup()->add_item(TTR("Save"), RESOURCE_SAVE);
resource_save_button->get_popup()->add_item(TTR("Save As..."), RESOURCE_SAVE_AS);
@@ -638,7 +655,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) {
resource_save_button->set_disabled(true);
resource_extra_button = memnew(MenuButton);
- resource_extra_button->set_tooltip(TTR("Extra resource options."));
+ resource_extra_button->set_tooltip_text(TTR("Extra resource options."));
general_options_hb->add_child(resource_extra_button);
resource_extra_button->connect("about_to_popup", callable_mp(this, &InspectorDock::_prepare_resource_extra_popup));
resource_extra_button->get_popup()->add_icon_shortcut(get_theme_icon(SNAME("ActionPaste"), SNAME("EditorIcons")), ED_SHORTCUT("property_editor/paste_resource", TTR("Edit Resource from Clipboard")), RESOURCE_EDIT_CLIPBOARD);
@@ -654,19 +671,19 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) {
backward_button = memnew(Button);
backward_button->set_flat(true);
general_options_hb->add_child(backward_button);
- backward_button->set_tooltip(TTR("Go to the previous edited object in history."));
+ backward_button->set_tooltip_text(TTR("Go to the previous edited object in history."));
backward_button->set_disabled(true);
backward_button->connect("pressed", callable_mp(this, &InspectorDock::_edit_back));
forward_button = memnew(Button);
forward_button->set_flat(true);
general_options_hb->add_child(forward_button);
- forward_button->set_tooltip(TTR("Go to the next edited object in history."));
+ forward_button->set_tooltip_text(TTR("Go to the next edited object in history."));
forward_button->set_disabled(true);
forward_button->connect("pressed", callable_mp(this, &InspectorDock::_edit_forward));
history_menu = memnew(MenuButton);
- history_menu->set_tooltip(TTR("History of recently edited objects."));
+ history_menu->set_tooltip_text(TTR("History of recently edited objects."));
general_options_hb->add_child(history_menu);
history_menu->connect("about_to_popup", callable_mp(this, &InspectorDock::_prepare_history));
history_menu->get_popup()->connect("id_pressed", callable_mp(this, &InspectorDock::_select_history));
@@ -680,7 +697,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) {
open_docs_button = memnew(Button);
open_docs_button->set_flat(true);
open_docs_button->set_disabled(true);
- open_docs_button->set_tooltip(TTR("Open documentation for this object."));
+ open_docs_button->set_tooltip_text(TTR("Open documentation for this object."));
open_docs_button->set_shortcut(ED_SHORTCUT("property_editor/open_help", TTR("Open Documentation")));
subresource_hb->add_child(open_docs_button);
open_docs_button->connect("pressed", callable_mp(this, &InspectorDock::_menu_option).bind(OBJECT_REQUEST_HELP));
@@ -702,16 +719,15 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) {
object_menu = memnew(MenuButton);
object_menu->set_shortcut_context(this);
property_tools_hb->add_child(object_menu);
- object_menu->set_tooltip(TTR("Manage object properties."));
+ object_menu->set_tooltip_text(TTR("Manage object properties."));
object_menu->get_popup()->connect("about_to_popup", callable_mp(this, &InspectorDock::_prepare_menu));
object_menu->get_popup()->connect("id_pressed", callable_mp(this, &InspectorDock::_menu_option));
- warning = memnew(Button);
- add_child(warning);
- warning->set_text(TTR("Changes may be lost!"));
- warning->set_clip_text(true);
- warning->hide();
- warning->connect("pressed", callable_mp(this, &InspectorDock::_warning_pressed));
+ info = memnew(Button);
+ add_child(info);
+ info->set_clip_text(true);
+ info->hide();
+ info->connect("pressed", callable_mp(this, &InspectorDock::_info_pressed));
unique_resources_confirmation = memnew(ConfirmationDialog);
add_child(unique_resources_confirmation);
@@ -736,8 +752,8 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) {
unique_resources_confirmation->connect("confirmed", callable_mp(this, &InspectorDock::_menu_confirm_current));
- warning_dialog = memnew(AcceptDialog);
- EditorNode::get_singleton()->get_gui_base()->add_child(warning_dialog);
+ info_dialog = memnew(AcceptDialog);
+ EditorNode::get_singleton()->get_gui_base()->add_child(info_dialog);
load_resource_dialog = memnew(EditorFileDialog);
add_child(load_resource_dialog);
@@ -755,7 +771,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) {
inspector->set_property_name_style(EditorPropertyNameProcessor::get_default_inspector_style());
inspector->set_use_folding(!bool(EDITOR_GET("interface/inspector/disable_folding")));
inspector->register_text_enter(search);
- inspector->set_undo_redo(&editor_data->get_undo_redo());
+ inspector->set_undo_redo(editor_data->get_undo_redo());
inspector->set_use_filter(true); // TODO: check me
diff --git a/editor/inspector_dock.h b/editor/inspector_dock.h
index e32410151f..5ebcbf70c7 100644
--- a/editor/inspector_dock.h
+++ b/editor/inspector_dock.h
@@ -93,8 +93,9 @@ class InspectorDock : public VBoxContainer {
MenuButton *object_menu = nullptr;
EditorPath *editor_path = nullptr;
- Button *warning = nullptr;
- AcceptDialog *warning_dialog = nullptr;
+ bool info_is_warning = false; // Display in yellow and use warning icon if true.
+ Button *info = nullptr;
+ AcceptDialog *info_dialog = nullptr;
int current_option = -1;
ConfirmationDialog *unique_resources_confirmation = nullptr;
@@ -118,7 +119,7 @@ class InspectorDock : public VBoxContainer {
void _paste_resource();
void _prepare_resource_extra_popup();
- void _warning_pressed();
+ void _info_pressed();
void _resource_created();
void _resource_selected(const Ref<Resource> &p_res, const String &p_property);
void _edit_forward();
@@ -145,7 +146,7 @@ public:
void edit_resource(const Ref<Resource> &p_resource);
void open_resource(const String &p_type);
void clear();
- void set_warning(const String &p_message);
+ void set_info(const String &p_button_text, const String &p_message, bool p_is_warning);
void update(Object *p_object);
Container *get_addon_area();
EditorInspector *get_inspector() { return inspector; }
diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp
index 0325f4bd5c..77a1700ebf 100644
--- a/editor/localization_editor.cpp
+++ b/editor/localization_editor.cpp
@@ -36,6 +36,8 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_translation_parser.h"
+#include "editor/editor_undo_redo_manager.h"
+#include "editor/filesystem_dock.h"
#include "editor/pot_generator.h"
#include "scene/gui/control.h"
@@ -379,6 +381,95 @@ void LocalizationEditor::_update_pot_file_extensions() {
}
}
+void LocalizationEditor::connect_filesystem_dock_signals(FileSystemDock *p_fs_dock) {
+ p_fs_dock->connect("files_moved", callable_mp(this, &LocalizationEditor::_filesystem_files_moved));
+ p_fs_dock->connect("file_removed", callable_mp(this, &LocalizationEditor::_filesystem_file_removed));
+}
+
+void LocalizationEditor::_filesystem_files_moved(const String &p_old_file, const String &p_new_file) {
+ // Update remaps if the moved file is a part of them.
+ Dictionary remaps;
+ bool remaps_changed = false;
+
+ if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/translation_remaps")) {
+ remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
+ }
+
+ // Check for the keys.
+ if (remaps.has(p_old_file)) {
+ PackedStringArray remapped_files = remaps[p_old_file];
+ remaps.erase(p_old_file);
+ remaps[p_new_file] = remapped_files;
+ remaps_changed = true;
+ print_verbose(vformat("Changed remap key \"%s\" to \"%s\" due to a moved file.", p_old_file, p_new_file));
+ }
+
+ // Check for the Array elements of the values.
+ Array remap_keys = remaps.keys();
+ for (int i = 0; i < remap_keys.size(); i++) {
+ PackedStringArray remapped_files = remaps[remap_keys[i]];
+ bool remapped_files_updated = false;
+
+ for (int j = 0; j < remapped_files.size(); j++) {
+ int splitter_pos = remapped_files[j].rfind(":");
+ String res_path = remapped_files[j].substr(0, splitter_pos);
+
+ if (res_path == p_old_file) {
+ String locale_name = remapped_files[j].substr(splitter_pos + 1);
+ // Replace the element at that index.
+ remapped_files.insert(j, p_new_file + ":" + locale_name);
+ remapped_files.remove_at(j + 1);
+ remaps_changed = true;
+ remapped_files_updated = true;
+ print_verbose(vformat("Changed remap value \"%s\" to \"%s\" of key \"%s\" due to a moved file.", res_path + ":" + locale_name, remapped_files[j], remap_keys[i]));
+ }
+ }
+
+ if (remapped_files_updated) {
+ remaps[remap_keys[i]] = remapped_files;
+ }
+ }
+
+ if (remaps_changed) {
+ ProjectSettings::get_singleton()->set_setting("internationalization/locale/translation_remaps", remaps);
+ update_translations();
+ emit_signal("localization_changed");
+ }
+}
+
+void LocalizationEditor::_filesystem_file_removed(const String &p_file) {
+ // Check if the remaps are affected.
+ Dictionary remaps;
+
+ if (ProjectSettings::get_singleton()->has_setting("internationalization/locale/translation_remaps")) {
+ remaps = ProjectSettings::get_singleton()->get("internationalization/locale/translation_remaps");
+ }
+
+ bool remaps_changed = remaps.has(p_file);
+
+ if (!remaps_changed) {
+ Array remap_keys = remaps.keys();
+ for (int i = 0; i < remap_keys.size() && !remaps_changed; i++) {
+ PackedStringArray remapped_files = remaps[remap_keys[i]];
+ for (int j = 0; j < remapped_files.size() && !remaps_changed; j++) {
+ int splitter_pos = remapped_files[j].rfind(":");
+ String res_path = remapped_files[j].substr(0, splitter_pos);
+ remaps_changed = p_file == res_path;
+ if (remaps_changed) {
+ print_verbose(vformat("Remap value \"%s\" of key \"%s\" has been removed from the file system.", remapped_files[j], remap_keys[i]));
+ }
+ }
+ }
+ } else {
+ print_verbose(vformat("Remap key \"%s\" has been removed from the file system.", p_file));
+ }
+
+ if (remaps_changed) {
+ update_translations();
+ emit_signal("localization_changed");
+ }
+}
+
void LocalizationEditor::update_translations() {
if (updating_translations) {
return;
@@ -432,6 +523,13 @@ void LocalizationEditor::update_translations() {
t->set_tooltip(0, keys[i]);
t->set_metadata(0, keys[i]);
t->add_button(0, get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), 0, false, TTR("Remove"));
+
+ // Display that it has been removed if this is the case.
+ if (!FileAccess::exists(keys[i])) {
+ t->set_text(0, t->get_text(0) + vformat(" (%s)", TTR("Removed")));
+ t->set_tooltip(0, vformat(TTR("%s cannot be found."), t->get_tooltip(0)));
+ }
+
if (keys[i] == remap_selected) {
t->select(0);
translation_res_option_add_button->set_disabled(false);
@@ -454,6 +552,12 @@ void LocalizationEditor::update_translations() {
t2->set_editable(1, true);
t2->set_metadata(1, path);
t2->set_tooltip(1, locale);
+
+ // Display that it has been removed if this is the case.
+ if (!FileAccess::exists(path)) {
+ t2->set_text(0, t2->get_text(0) + vformat(" (%s)", TTR("Removed")));
+ t2->set_tooltip(0, vformat(TTR("%s cannot be found."), t2->get_tooltip(0)));
+ }
}
}
}
diff --git a/editor/localization_editor.h b/editor/localization_editor.h
index 4b41a90cc2..ecac171fe3 100644
--- a/editor/localization_editor.h
+++ b/editor/localization_editor.h
@@ -36,6 +36,7 @@
#include "scene/gui/tree.h"
class EditorFileDialog;
+class FileSystemDock;
class LocalizationEditor : public VBoxContainer {
GDCLASS(LocalizationEditor, VBoxContainer);
@@ -55,7 +56,7 @@ class LocalizationEditor : public VBoxContainer {
EditorFileDialog *pot_file_open_dialog = nullptr;
EditorFileDialog *pot_generate_dialog = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
bool updating_translations = false;
String localization_changed;
@@ -81,6 +82,9 @@ class LocalizationEditor : public VBoxContainer {
void _pot_generate(const String &p_file);
void _update_pot_file_extensions();
+ void _filesystem_files_moved(const String &p_old_file, const String &p_new_file);
+ void _filesystem_file_removed(const String &p_file);
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -88,6 +92,7 @@ protected:
public:
void add_translation(const String &p_translation);
void update_translations();
+ void connect_filesystem_dock_signals(FileSystemDock *p_fs_dock);
LocalizationEditor();
};
diff --git a/editor/multi_node_edit.cpp b/editor/multi_node_edit.cpp
index a694b8d754..70cc54668d 100644
--- a/editor/multi_node_edit.cpp
+++ b/editor/multi_node_edit.cpp
@@ -32,6 +32,7 @@
#include "core/math/math_fieldwise.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
bool MultiNodeEdit::_set(const StringName &p_name, const Variant &p_value) {
return _set_impl(p_name, p_value, "");
@@ -54,7 +55,7 @@ bool MultiNodeEdit::_set_impl(const StringName &p_name, const Variant &p_value,
node_path_target = es->get_node(p_value);
}
- UndoRedo *ur = EditorNode::get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("MultiNode Set") + " " + String(name), UndoRedo::MERGE_ENDS);
for (const NodePath &E : nodes) {
diff --git a/editor/node_dock.cpp b/editor/node_dock.cpp
index 986370f537..55fa2f22dd 100644
--- a/editor/node_dock.cpp
+++ b/editor/node_dock.cpp
@@ -117,7 +117,7 @@ NodeDock::NodeDock() {
groups_button->connect("pressed", callable_mp(this, &NodeDock::show_groups));
connections = memnew(ConnectionsDock);
- connections->set_undoredo(EditorNode::get_undo_redo());
+ connections->set_undo_redo(EditorNode::get_undo_redo());
add_child(connections);
connections->set_v_size_flags(SIZE_EXPAND_FILL);
connections->hide();
diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp
index 6d323572e6..71ff77e9bc 100644
--- a/editor/plugin_config_dialog.cpp
+++ b/editor/plugin_config_dialog.cpp
@@ -62,7 +62,7 @@ void PluginConfigDialog::_on_confirmed() {
if (script_name.get_extension().is_empty()) {
script_name += "." + ext;
}
- String script_path = path.plus_file(script_name);
+ String script_path = path.path_join(script_name);
Ref<ConfigFile> cf = memnew(ConfigFile);
cf->set_value("plugin", "name", name_edit->get_text());
@@ -71,7 +71,7 @@ void PluginConfigDialog::_on_confirmed() {
cf->set_value("plugin", "version", version_edit->get_text());
cf->set_value("plugin", "script", script_name);
- cf->save(path.plus_file("plugin.cfg"));
+ cf->save(path.path_join("plugin.cfg"));
if (!_edit_mode) {
String class_name = script_name.get_basename();
@@ -111,32 +111,32 @@ void PluginConfigDialog::_on_required_text_changed(const String &) {
name_validation->set_texture(valid_icon);
subfolder_validation->set_texture(valid_icon);
script_validation->set_texture(valid_icon);
- name_validation->set_tooltip("");
- subfolder_validation->set_tooltip("");
- script_validation->set_tooltip("");
+ name_validation->set_tooltip_text("");
+ subfolder_validation->set_tooltip_text("");
+ script_validation->set_tooltip_text("");
// Change valid status to invalid depending on conditions.
Vector<String> errors;
if (name_edit->get_text().is_empty()) {
is_valid = false;
name_validation->set_texture(invalid_icon);
- name_validation->set_tooltip(TTR("Plugin name cannot be blank."));
+ name_validation->set_tooltip_text(TTR("Plugin name cannot be blank."));
}
if ((!script_edit->get_text().get_extension().is_empty() && script_edit->get_text().get_extension() != ext) || script_edit->get_text().ends_with(".")) {
is_valid = false;
script_validation->set_texture(invalid_icon);
- script_validation->set_tooltip(vformat(TTR("Script extension must match chosen language extension (.%s)."), ext));
+ script_validation->set_tooltip_text(vformat(TTR("Script extension must match chosen language extension (.%s)."), ext));
}
if (!subfolder_edit->get_text().is_empty() && !subfolder_edit->get_text().is_valid_filename()) {
is_valid = false;
subfolder_validation->set_texture(invalid_icon);
- subfolder_validation->set_tooltip(TTR("Subfolder name is not a valid folder name."));
+ subfolder_validation->set_tooltip_text(TTR("Subfolder name is not a valid folder name."));
} else {
String path = "res://addons/" + _get_subfolder();
if (!_edit_mode && DirAccess::exists(path)) { // Only show this error if in "create" mode.
is_valid = false;
subfolder_validation->set_texture(invalid_icon);
- subfolder_validation->set_tooltip(TTR("Subfolder cannot be one which already exists."));
+ subfolder_validation->set_tooltip_text(TTR("Subfolder cannot be one which already exists."));
}
}
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index cb77cd78bf..c928b95642 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -36,6 +36,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/separator.h"
bool AbstractPolygon2DEditor::Vertex::operator==(const AbstractPolygon2DEditor::Vertex &p_vertex) const {
@@ -234,13 +235,13 @@ void AbstractPolygon2DEditor::disable_polygon_editing(bool p_disable, String p_r
button_delete->set_disabled(p_disable);
if (p_disable) {
- button_create->set_tooltip(p_reason);
- button_edit->set_tooltip(p_reason);
- button_delete->set_tooltip(p_reason);
+ button_create->set_tooltip_text(p_reason);
+ button_edit->set_tooltip_text(p_reason);
+ button_delete->set_tooltip_text(p_reason);
} else {
- button_create->set_tooltip(TTR("Create points."));
- button_edit->set_tooltip(TTR("Edit points.\nLMB: Move Point\nRMB: Erase Point"));
- button_delete->set_tooltip(TTR("Erase points."));
+ button_create->set_tooltip_text(TTR("Create points."));
+ button_edit->set_tooltip_text(TTR("Edit points.\nLMB: Move Point\nRMB: Erase Point"));
+ button_delete->set_tooltip_text(TTR("Erase points."));
}
}
@@ -294,9 +295,9 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
_commit_action();
return true;
} else {
- pre_move_edit = vertices;
edited_point = PosVertex(insert.polygon, insert.vertex + 1, xform.affine_inverse().xform(insert.pos));
vertices.insert(edited_point.vertex, edited_point.pos);
+ pre_move_edit = vertices;
selected_point = Vertex(edited_point.polygon, edited_point.vertex);
edge_point = PosVertex();
diff --git a/editor/plugins/abstract_polygon_2d_editor.h b/editor/plugins/abstract_polygon_2d_editor.h
index 696fd7b637..1fbbe67c8d 100644
--- a/editor/plugins/abstract_polygon_2d_editor.h
+++ b/editor/plugins/abstract_polygon_2d_editor.h
@@ -36,6 +36,7 @@
#include "scene/gui/box_container.h"
class CanvasItemEditor;
+class EditorUndoRedoManager;
class AbstractPolygon2DEditor : public HBoxContainer {
GDCLASS(AbstractPolygon2DEditor, HBoxContainer);
@@ -99,7 +100,7 @@ protected:
int mode = MODE_EDIT;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
virtual void _menu_option(int p_option);
void _wip_changed();
diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp
index 32d97c65a9..3b7829c37b 100644
--- a/editor/plugins/animation_blend_space_1d_editor.cpp
+++ b/editor/plugins/animation_blend_space_1d_editor.cpp
@@ -35,6 +35,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/animation/animation_blend_tree.h"
StringName AnimationNodeBlendSpace1DEditor::get_blend_position_path() const {
@@ -47,7 +48,9 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) {
if (selected_point != -1) {
- _erase_selected();
+ if (!read_only) {
+ _erase_selected();
+ }
accept_event();
}
}
@@ -55,62 +58,64 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (mb->get_button_index() == MouseButton::LEFT && tool_create->is_pressed()))) {
- menu->clear();
- animations_menu->clear();
- animations_to_add.clear();
+ if (!read_only) {
+ menu->clear();
+ animations_menu->clear();
+ animations_to_add.clear();
- List<StringName> classes;
- ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
- classes.sort_custom<StringName::AlphCompare>();
+ List<StringName> classes;
+ ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
+ classes.sort_custom<StringName::AlphCompare>();
- menu->add_submenu_item(TTR("Add Animation"), "animations");
+ menu->add_submenu_item(TTR("Add Animation"), "animations");
- AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
- ERR_FAIL_COND(!gp);
+ AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
+ ERR_FAIL_COND(!gp);
- if (gp->has_node(gp->get_animation_player())) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
+ if (gp->has_node(gp->get_animation_player())) {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
- if (ap) {
- List<StringName> names;
- ap->get_animation_list(&names);
+ if (ap) {
+ List<StringName> names;
+ ap->get_animation_list(&names);
- for (const StringName &E : names) {
- animations_menu->add_icon_item(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")), E);
- animations_to_add.push_back(E);
+ for (const StringName &E : names) {
+ animations_menu->add_icon_item(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")), E);
+ animations_to_add.push_back(E);
+ }
}
}
- }
- for (const StringName &E : classes) {
- String name = String(E).replace_first("AnimationNode", "");
- if (name == "Animation" || name == "StartState" || name == "EndState") {
- continue;
- }
+ for (const StringName &E : classes) {
+ String name = String(E).replace_first("AnimationNode", "");
+ if (name == "Animation" || name == "StartState" || name == "EndState") {
+ continue;
+ }
- int idx = menu->get_item_count();
- menu->add_item(vformat(TTR("Add %s"), name), idx);
- menu->set_item_metadata(idx, E);
- }
+ int idx = menu->get_item_count();
+ menu->add_item(vformat(TTR("Add %s"), name), idx);
+ menu->set_item_metadata(idx, E);
+ }
- Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
- if (clipb.is_valid()) {
+ Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
+ if (clipb.is_valid()) {
+ menu->add_separator();
+ menu->add_item(TTR("Paste"), MENU_PASTE);
+ }
menu->add_separator();
- menu->add_item(TTR("Paste"), MENU_PASTE);
- }
- menu->add_separator();
- menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
+ menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
- menu->set_position(blend_space_draw->get_screen_position() + mb->get_position());
- menu->reset_size();
- menu->popup();
+ menu->set_position(blend_space_draw->get_screen_position() + mb->get_position());
+ menu->reset_size();
+ menu->popup();
- add_point_pos = (mb->get_position() / blend_space_draw->get_size()).x;
- add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
- add_point_pos += blend_space->get_min_space();
+ add_point_pos = (mb->get_position() / blend_space_draw->get_size()).x;
+ add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
+ add_point_pos += blend_space->get_min_space();
- if (snap->is_pressed()) {
- add_point_pos = Math::snapped(add_point_pos, blend_space->get_snap());
+ if (snap->is_pressed()) {
+ add_point_pos = Math::snapped(add_point_pos, blend_space->get_snap());
+ }
}
}
@@ -137,31 +142,33 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
}
if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == MouseButton::LEFT) {
- if (dragging_selected) {
- // move
- float point = blend_space->get_blend_point_position(selected_point);
- point += drag_ofs.x;
+ if (!read_only) {
+ if (dragging_selected) {
+ // move
+ float point = blend_space->get_blend_point_position(selected_point);
+ point += drag_ofs.x;
+
+ if (snap->is_pressed()) {
+ point = Math::snapped(point, blend_space->get_snap());
+ }
- if (snap->is_pressed()) {
- point = Math::snapped(point, blend_space->get_snap());
+ updating = true;
+ undo_redo->create_action(TTR("Move Node Point"));
+ undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
+ undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
+ undo_redo->add_do_method(this, "_update_space");
+ undo_redo->add_undo_method(this, "_update_space");
+ undo_redo->add_do_method(this, "_update_edited_point_pos");
+ undo_redo->add_undo_method(this, "_update_edited_point_pos");
+ undo_redo->commit_action();
+ updating = false;
+ _update_edited_point_pos();
}
- updating = true;
- undo_redo->create_action(TTR("Move Node Point"));
- undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
- undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
- undo_redo->add_do_method(this, "_update_space");
- undo_redo->add_undo_method(this, "_update_space");
- undo_redo->add_do_method(this, "_update_edited_point_pos");
- undo_redo->add_undo_method(this, "_update_edited_point_pos");
- undo_redo->commit_action();
- updating = false;
- _update_edited_point_pos();
+ dragging_selected_attempt = false;
+ dragging_selected = false;
+ blend_space_draw->update();
}
-
- dragging_selected_attempt = false;
- dragging_selected = false;
- blend_space_draw->update();
}
// *set* the blend
@@ -254,10 +261,12 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_draw() {
for (int i = 0; i < blend_space->get_blend_point_count(); i++) {
float point = blend_space->get_blend_point_position(i);
- if (dragging_selected && selected_point == i) {
- point += drag_ofs.x;
- if (snap->is_pressed()) {
- point = Math::snapped(point, blend_space->get_snap());
+ if (!read_only) {
+ if (dragging_selected && selected_point == i) {
+ point += drag_ofs.x;
+ if (snap->is_pressed()) {
+ point = Math::snapped(point, blend_space->get_snap());
+ }
}
}
@@ -474,7 +483,7 @@ void AnimationNodeBlendSpace1DEditor::_update_edited_point_pos() {
void AnimationNodeBlendSpace1DEditor::_update_tool_erase() {
bool point_valid = selected_point >= 0 && selected_point < blend_space->get_blend_point_count();
- tool_erase->set_disabled(!point_valid);
+ tool_erase->set_disabled(!point_valid || read_only);
if (point_valid) {
Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
@@ -485,7 +494,11 @@ void AnimationNodeBlendSpace1DEditor::_update_tool_erase() {
open_editor->hide();
}
- edit_hb->show();
+ if (!read_only) {
+ edit_hb->show();
+ } else {
+ edit_hb->hide();
+ }
} else {
edit_hb->hide();
}
@@ -589,10 +602,20 @@ bool AnimationNodeBlendSpace1DEditor::can_edit(const Ref<AnimationNode> &p_node)
void AnimationNodeBlendSpace1DEditor::edit(const Ref<AnimationNode> &p_node) {
blend_space = p_node;
+ read_only = false;
if (!blend_space.is_null()) {
+ read_only = EditorNode::get_singleton()->is_resource_read_only(blend_space);
+
_update_space();
}
+
+ tool_create->set_disabled(read_only);
+ edit_value->set_editable(!read_only);
+ label_value->set_editable(!read_only);
+ min_value->set_editable(!read_only);
+ max_value->set_editable(!read_only);
+ sync->set_disabled(read_only);
}
AnimationNodeBlendSpace1DEditor *AnimationNodeBlendSpace1DEditor::singleton = nullptr;
@@ -612,7 +635,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
tool_blend->set_button_group(bg);
top_hb->add_child(tool_blend);
tool_blend->set_pressed(true);
- tool_blend->set_tooltip(TTR("Set the blending position within the space"));
+ tool_blend->set_tooltip_text(TTR("Set the blending position within the space"));
tool_blend->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch).bind(3));
tool_select = memnew(Button);
@@ -620,7 +643,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
tool_select->set_toggle_mode(true);
tool_select->set_button_group(bg);
top_hb->add_child(tool_select);
- tool_select->set_tooltip(TTR("Select and move points, create points with RMB."));
+ tool_select->set_tooltip_text(TTR("Select and move points, create points with RMB."));
tool_select->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch).bind(0));
tool_create = memnew(Button);
@@ -628,7 +651,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
tool_create->set_toggle_mode(true);
tool_create->set_button_group(bg);
top_hb->add_child(tool_create);
- tool_create->set_tooltip(TTR("Create points."));
+ tool_create->set_tooltip_text(TTR("Create points."));
tool_create->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch).bind(1));
tool_erase_sep = memnew(VSeparator);
@@ -636,7 +659,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
tool_erase = memnew(Button);
tool_erase->set_flat(true);
top_hb->add_child(tool_erase);
- tool_erase->set_tooltip(TTR("Erase points."));
+ tool_erase->set_tooltip_text(TTR("Erase points."));
tool_erase->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_erase_selected));
top_hb->add_child(memnew(VSeparator));
@@ -646,7 +669,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
snap->set_toggle_mode(true);
top_hb->add_child(snap);
snap->set_pressed(true);
- snap->set_tooltip(TTR("Enable snap and show grid."));
+ snap->set_tooltip_text(TTR("Enable snap and show grid."));
snap->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_snap_toggled));
snap_value = memnew(SpinBox);
diff --git a/editor/plugins/animation_blend_space_1d_editor.h b/editor/plugins/animation_blend_space_1d_editor.h
index 9b06f3248f..c8b01cb54b 100644
--- a/editor/plugins/animation_blend_space_1d_editor.h
+++ b/editor/plugins/animation_blend_space_1d_editor.h
@@ -40,10 +40,13 @@
#include "scene/gui/separator.h"
#include "scene/gui/tree.h"
+class EditorUndoRedoManager;
+
class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendSpace1DEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendSpace1D> blend_space;
+ bool read_only = false;
HBoxContainer *goto_parent_hb = nullptr;
Button *goto_parent = nullptr;
@@ -76,7 +79,7 @@ class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
bool updating = false;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
static AnimationNodeBlendSpace1DEditor *singleton;
diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp
index dc764725dd..d904ccb5e0 100644
--- a/editor/plugins/animation_blend_space_2d_editor.cpp
+++ b/editor/plugins/animation_blend_space_2d_editor.cpp
@@ -39,6 +39,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/animation/animation_blend_tree.h"
#include "scene/animation/animation_player.h"
#include "scene/gui/menu_button.h"
@@ -59,11 +60,29 @@ void AnimationNodeBlendSpace2DEditor::edit(const Ref<AnimationNode> &p_node) {
blend_space->disconnect("triangles_updated", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_blend_space_changed));
}
blend_space = p_node;
+ read_only = false;
if (!blend_space.is_null()) {
+ read_only = EditorNode::get_singleton()->is_resource_read_only(blend_space);
+
blend_space->connect("triangles_updated", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_blend_space_changed));
_update_space();
}
+
+ tool_create->set_disabled(read_only);
+ interpolation->set_disabled(read_only);
+ max_x_value->set_editable(!read_only);
+ min_x_value->set_editable(!read_only);
+ max_y_value->set_editable(!read_only);
+ min_y_value->set_editable(!read_only);
+ label_x->set_editable(!read_only);
+ label_y->set_editable(!read_only);
+ edit_x->set_editable(!read_only);
+ edit_y->set_editable(!read_only);
+ tool_triangle->set_disabled(read_only);
+ auto_triangles->set_disabled(read_only);
+ sync->set_disabled(read_only);
+ interpolation->set_disabled(read_only);
}
StringName AnimationNodeBlendSpace2DEditor::get_blend_position_path() const {
@@ -75,7 +94,9 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
Ref<InputEventKey> k = p_event;
if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) {
if (selected_point != -1 || selected_triangle != -1) {
- _erase_selected();
+ if (!read_only) {
+ _erase_selected();
+ }
accept_event();
}
}
@@ -83,57 +104,59 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->is_pressed() && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (mb->get_button_index() == MouseButton::LEFT && tool_create->is_pressed()))) {
- menu->clear();
- animations_menu->clear();
- animations_to_add.clear();
- List<StringName> classes;
- classes.sort_custom<StringName::AlphCompare>();
-
- ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
- menu->add_submenu_item(TTR("Add Animation"), "animations");
-
- AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
- ERR_FAIL_COND(!gp);
- if (gp && gp->has_node(gp->get_animation_player())) {
- AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
- if (ap) {
- List<StringName> names;
- ap->get_animation_list(&names);
- for (const StringName &E : names) {
- animations_menu->add_icon_item(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")), E);
- animations_to_add.push_back(E);
+ if (!read_only) {
+ menu->clear();
+ animations_menu->clear();
+ animations_to_add.clear();
+ List<StringName> classes;
+ classes.sort_custom<StringName::AlphCompare>();
+
+ ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
+ menu->add_submenu_item(TTR("Add Animation"), "animations");
+
+ AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_tree();
+ ERR_FAIL_COND(!gp);
+ if (gp && gp->has_node(gp->get_animation_player())) {
+ AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player()));
+ if (ap) {
+ List<StringName> names;
+ ap->get_animation_list(&names);
+ for (const StringName &E : names) {
+ animations_menu->add_icon_item(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")), E);
+ animations_to_add.push_back(E);
+ }
}
}
- }
- for (const StringName &E : classes) {
- String name = String(E).replace_first("AnimationNode", "");
- if (name == "Animation" || name == "StartState" || name == "EndState") {
- continue; // nope
+ for (const StringName &E : classes) {
+ String name = String(E).replace_first("AnimationNode", "");
+ if (name == "Animation" || name == "StartState" || name == "EndState") {
+ continue; // nope
+ }
+ int idx = menu->get_item_count();
+ menu->add_item(vformat(TTR("Add %s"), name), idx);
+ menu->set_item_metadata(idx, E);
}
- int idx = menu->get_item_count();
- menu->add_item(vformat(TTR("Add %s"), name), idx);
- menu->set_item_metadata(idx, E);
- }
- Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
- if (clipb.is_valid()) {
+ Ref<AnimationNode> clipb = EditorSettings::get_singleton()->get_resource_clipboard();
+ if (clipb.is_valid()) {
+ menu->add_separator();
+ menu->add_item(TTR("Paste"), MENU_PASTE);
+ }
menu->add_separator();
- menu->add_item(TTR("Paste"), MENU_PASTE);
- }
- menu->add_separator();
- menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
-
- menu->set_position(blend_space_draw->get_screen_position() + mb->get_position());
- menu->reset_size();
- menu->popup();
- add_point_pos = (mb->get_position() / blend_space_draw->get_size());
- add_point_pos.y = 1.0 - add_point_pos.y;
- add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
- add_point_pos += blend_space->get_min_space();
-
- if (snap->is_pressed()) {
- add_point_pos = add_point_pos.snapped(blend_space->get_snap());
+ menu->add_item(TTR("Load..."), MENU_LOAD_FILE);
+
+ menu->set_position(blend_space_draw->get_screen_position() + mb->get_position());
+ menu->reset_size();
+ menu->popup();
+ add_point_pos = (mb->get_position() / blend_space_draw->get_size());
+ add_point_pos.y = 1.0 - add_point_pos.y;
+ add_point_pos *= (blend_space->get_max_space() - blend_space->get_min_space());
+ add_point_pos += blend_space->get_min_space();
+
+ if (snap->is_pressed()) {
+ add_point_pos = add_point_pos.snapped(blend_space->get_snap());
+ }
}
}
@@ -221,17 +244,19 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
point = point.snapped(blend_space->get_snap());
}
- updating = true;
- undo_redo->create_action(TTR("Move Node Point"));
- undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
- undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
- undo_redo->add_do_method(this, "_update_space");
- undo_redo->add_undo_method(this, "_update_space");
- undo_redo->add_do_method(this, "_update_edited_point_pos");
- undo_redo->add_undo_method(this, "_update_edited_point_pos");
- undo_redo->commit_action();
- updating = false;
- _update_edited_point_pos();
+ if (!read_only) {
+ updating = true;
+ undo_redo->create_action(TTR("Move Node Point"));
+ undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
+ undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
+ undo_redo->add_do_method(this, "_update_space");
+ undo_redo->add_undo_method(this, "_update_space");
+ undo_redo->add_do_method(this, "_update_edited_point_pos");
+ undo_redo->add_undo_method(this, "_update_edited_point_pos");
+ undo_redo->commit_action();
+ updating = false;
+ _update_edited_point_pos();
+ }
}
dragging_selected_attempt = false;
dragging_selected = false;
@@ -258,7 +283,9 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
if (mm.is_valid() && dragging_selected_attempt) {
dragging_selected = true;
- drag_ofs = ((mm->get_position() - drag_from) / blend_space_draw->get_size()) * (blend_space->get_max_space() - blend_space->get_min_space()) * Vector2(1, -1);
+ if (!read_only) {
+ drag_ofs = ((mm->get_position() - drag_from) / blend_space_draw->get_size()) * (blend_space->get_max_space() - blend_space->get_min_space()) * Vector2(1, -1);
+ }
blend_space_draw->update();
_update_edited_point_pos();
}
@@ -354,7 +381,10 @@ void AnimationNodeBlendSpace2DEditor::_add_animation_type(int p_index) {
}
void AnimationNodeBlendSpace2DEditor::_update_tool_erase() {
- tool_erase->set_disabled(!(selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) && !(selected_triangle >= 0 && selected_triangle < blend_space->get_triangle_count()));
+ tool_erase->set_disabled(
+ (!(selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) && !(selected_triangle >= 0 && selected_triangle < blend_space->get_triangle_count())) ||
+ read_only);
+
if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) {
Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
if (AnimationTreeEditor::get_singleton()->can_edit(an)) {
@@ -362,7 +392,11 @@ void AnimationNodeBlendSpace2DEditor::_update_tool_erase() {
} else {
open_editor->hide();
}
- edit_hb->show();
+ if (!read_only) {
+ edit_hb->show();
+ } else {
+ edit_hb->hide();
+ }
} else {
edit_hb->hide();
}
@@ -502,10 +536,12 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
points.clear();
for (int i = 0; i < blend_space->get_blend_point_count(); i++) {
Vector2 point = blend_space->get_blend_point_position(i);
- if (dragging_selected && selected_point == i) {
- point += drag_ofs;
- if (snap->is_pressed()) {
- point = point.snapped(blend_space->get_snap());
+ if (!read_only) {
+ if (dragging_selected && selected_point == i) {
+ point += drag_ofs;
+ if (snap->is_pressed()) {
+ point = point.snapped(blend_space->get_snap());
+ }
}
}
point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
@@ -832,7 +868,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
tool_blend->set_button_group(bg);
top_hb->add_child(tool_blend);
tool_blend->set_pressed(true);
- tool_blend->set_tooltip(TTR("Set the blending position within the space"));
+ tool_blend->set_tooltip_text(TTR("Set the blending position within the space"));
tool_blend->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_tool_switch).bind(3));
tool_select = memnew(Button);
@@ -840,7 +876,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
tool_select->set_toggle_mode(true);
tool_select->set_button_group(bg);
top_hb->add_child(tool_select);
- tool_select->set_tooltip(TTR("Select and move points, create points with RMB."));
+ tool_select->set_tooltip_text(TTR("Select and move points, create points with RMB."));
tool_select->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_tool_switch).bind(0));
tool_create = memnew(Button);
@@ -848,7 +884,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
tool_create->set_toggle_mode(true);
tool_create->set_button_group(bg);
top_hb->add_child(tool_create);
- tool_create->set_tooltip(TTR("Create points."));
+ tool_create->set_tooltip_text(TTR("Create points."));
tool_create->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_tool_switch).bind(1));
tool_triangle = memnew(Button);
@@ -856,7 +892,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
tool_triangle->set_toggle_mode(true);
tool_triangle->set_button_group(bg);
top_hb->add_child(tool_triangle);
- tool_triangle->set_tooltip(TTR("Create triangles by connecting points."));
+ tool_triangle->set_tooltip_text(TTR("Create triangles by connecting points."));
tool_triangle->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_tool_switch).bind(2));
tool_erase_sep = memnew(VSeparator);
@@ -864,7 +900,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
tool_erase = memnew(Button);
tool_erase->set_flat(true);
top_hb->add_child(tool_erase);
- tool_erase->set_tooltip(TTR("Erase points and triangles."));
+ tool_erase->set_tooltip_text(TTR("Erase points and triangles."));
tool_erase->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_erase_selected));
tool_erase->set_disabled(true);
@@ -875,7 +911,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
top_hb->add_child(auto_triangles);
auto_triangles->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled));
auto_triangles->set_toggle_mode(true);
- auto_triangles->set_tooltip(TTR("Generate blend triangles automatically (instead of manually)"));
+ auto_triangles->set_tooltip_text(TTR("Generate blend triangles automatically (instead of manually)"));
top_hb->add_child(memnew(VSeparator));
@@ -884,7 +920,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
snap->set_toggle_mode(true);
top_hb->add_child(snap);
snap->set_pressed(true);
- snap->set_tooltip(TTR("Enable snap and show grid."));
+ snap->set_tooltip_text(TTR("Enable snap and show grid."));
snap->connect("pressed", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_snap_toggled));
snap_x = memnew(SpinBox);
diff --git a/editor/plugins/animation_blend_space_2d_editor.h b/editor/plugins/animation_blend_space_2d_editor.h
index 26471df051..1f015a1804 100644
--- a/editor/plugins/animation_blend_space_2d_editor.h
+++ b/editor/plugins/animation_blend_space_2d_editor.h
@@ -40,10 +40,13 @@
#include "scene/gui/separator.h"
#include "scene/gui/tree.h"
+class EditorUndoRedoManager;
+
class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendSpace2DEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendSpace2D> blend_space;
+ bool read_only = false;
PanelContainer *panel = nullptr;
Button *tool_blend = nullptr;
@@ -82,7 +85,7 @@ class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin {
bool updating;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
static AnimationNodeBlendSpace2DEditor *singleton;
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index 79be2d04b3..8dd3223b19 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -39,6 +39,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/animation/animation_player.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
@@ -133,6 +134,8 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
GraphNode *node = memnew(GraphNode);
graph->add_child(node);
+ node->set_draggable(!read_only);
+
Ref<AnimationNode> agnode = blend_tree->get_node(E);
ERR_CONTINUE(!agnode.is_valid());
@@ -145,9 +148,10 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
if (String(E) != "output") {
LineEdit *name = memnew(LineEdit);
name->set_text(E);
+ name->set_editable(!read_only);
name->set_expand_to_text_length_enabled(true);
node->add_child(name);
- node->set_slot(0, false, 0, Color(), true, 0, get_theme_color(SNAME("font_color"), SNAME("Label")));
+ node->set_slot(0, false, 0, Color(), true, read_only ? -1 : 0, get_theme_color(SNAME("font_color"), SNAME("Label")));
name->connect("text_submitted", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed).bind(agnode), CONNECT_DEFERRED);
name->connect("focus_exited", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed_focus_out).bind(name, agnode), CONNECT_DEFERRED);
base = 1;
@@ -159,7 +163,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
Label *in_name = memnew(Label);
node->add_child(in_name);
in_name->set_text(agnode->get_input_name(i));
- node->set_slot(base + i, true, 0, get_theme_color(SNAME("font_color"), SNAME("Label")), false, 0, Color());
+ node->set_slot(base + i, true, read_only ? -1 : 0, get_theme_color(SNAME("font_color"), SNAME("Label")), false, 0, Color());
}
List<PropertyInfo> pinfo;
@@ -171,6 +175,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
String base_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E) + "/" + F.name;
EditorProperty *prop = EditorInspector::instantiate_property_editor(AnimationTreeEditor::get_singleton()->get_tree(), F.type, base_path, F.hint, F.hint_string, F.usage);
if (prop) {
+ prop->set_read_only(read_only);
prop->set_object_and_property(AnimationTreeEditor::get_singleton()->get_tree(), base_path);
prop->update_property();
prop->set_name_split_ratio(0);
@@ -194,12 +199,16 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
if (agnode->has_filter()) {
node->add_child(memnew(HSeparator));
- Button *edit_filters = memnew(Button);
- edit_filters->set_text(TTR("Edit Filters"));
- edit_filters->set_icon(get_theme_icon(SNAME("AnimationFilter"), SNAME("EditorIcons")));
- node->add_child(edit_filters);
- edit_filters->connect("pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_edit_filters).bind(E), CONNECT_DEFERRED);
- edit_filters->set_h_size_flags(SIZE_SHRINK_CENTER);
+ Button *inspect_filters = memnew(Button);
+ if (read_only) {
+ inspect_filters->set_text(TTR("Inspect Filters"));
+ } else {
+ inspect_filters->set_text(TTR("Edit Filters"));
+ }
+ inspect_filters->set_icon(get_theme_icon(SNAME("AnimationFilter"), SNAME("EditorIcons")));
+ node->add_child(inspect_filters);
+ inspect_filters->connect("pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_inspect_filters).bind(E), CONNECT_DEFERRED);
+ inspect_filters->set_h_size_flags(SIZE_SHRINK_CENTER);
}
Ref<AnimationNodeAnimation> anim = agnode;
@@ -207,6 +216,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
MenuButton *mb = memnew(MenuButton);
mb->set_text(anim->get_animation());
mb->set_icon(get_theme_icon(SNAME("Animation"), SNAME("EditorIcons")));
+ mb->set_disabled(read_only);
Array options;
node->add_child(memnew(HSeparator));
@@ -369,10 +379,18 @@ void AnimationNodeBlendTreeEditor::_popup(bool p_has_input_ports, const Vector2
}
void AnimationNodeBlendTreeEditor::_popup_request(const Vector2 &p_position) {
+ if (read_only) {
+ return;
+ }
+
_popup(false, graph->get_screen_position() + graph->get_local_mouse_position(), p_position);
}
void AnimationNodeBlendTreeEditor::_connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position) {
+ if (read_only) {
+ return;
+ }
+
Ref<AnimationNode> node = blend_tree->get_node(p_from);
if (node.is_valid()) {
from_node = p_from;
@@ -381,6 +399,10 @@ void AnimationNodeBlendTreeEditor::_connection_to_empty(const String &p_from, in
}
void AnimationNodeBlendTreeEditor::_connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position) {
+ if (read_only) {
+ return;
+ }
+
Ref<AnimationNode> node = blend_tree->get_node(p_to);
if (node.is_valid()) {
to_node = p_to;
@@ -401,6 +423,10 @@ void AnimationNodeBlendTreeEditor::_node_dragged(const Vector2 &p_from, const Ve
}
void AnimationNodeBlendTreeEditor::_connection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) {
+ if (read_only) {
+ return;
+ }
+
AnimationNodeBlendTree::ConnectionError err = blend_tree->can_connect_node(p_to, p_to_index, p_from);
if (err != AnimationNodeBlendTree::CONNECTION_OK) {
@@ -417,6 +443,10 @@ void AnimationNodeBlendTreeEditor::_connection_request(const String &p_from, int
}
void AnimationNodeBlendTreeEditor::_disconnection_request(const String &p_from, int p_from_index, const String &p_to, int p_to_index) {
+ if (read_only) {
+ return;
+ }
+
graph->disconnect_node(p_from, p_from_index, p_to, p_to_index);
updating = true;
@@ -444,6 +474,10 @@ void AnimationNodeBlendTreeEditor::_anim_selected(int p_index, Array p_options,
}
void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) {
+ if (read_only) {
+ return;
+ }
+
undo_redo->create_action(TTR("Delete Node"));
undo_redo->add_do_method(blend_tree.ptr(), "remove_node", p_which);
undo_redo->add_undo_method(blend_tree.ptr(), "add_node", p_which, blend_tree->get_node(p_which), blend_tree.ptr()->get_node_position(p_which));
@@ -463,6 +497,10 @@ void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) {
}
void AnimationNodeBlendTreeEditor::_delete_nodes_request(const TypedArray<StringName> &p_nodes) {
+ if (read_only) {
+ return;
+ }
+
List<StringName> to_erase;
if (p_nodes.is_empty()) {
@@ -494,6 +532,10 @@ void AnimationNodeBlendTreeEditor::_delete_nodes_request(const TypedArray<String
}
void AnimationNodeBlendTreeEditor::_node_selected(Object *p_node) {
+ if (read_only) {
+ return;
+ }
+
GraphNode *gn = Object::cast_to<GraphNode>(p_node);
ERR_FAIL_COND(!gn);
@@ -678,7 +720,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
}
}
- ti->set_editable(0, true);
+ ti->set_editable(0, !read_only);
ti->set_selectable(0, true);
ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
ti->set_text(0, concat);
@@ -691,7 +733,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
ti = filters->create_item(ti);
ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
ti->set_text(0, concat);
- ti->set_editable(0, true);
+ ti->set_editable(0, !read_only);
ti->set_selectable(0, true);
ti->set_checked(0, anode->is_path_filtered(path));
ti->set_metadata(0, path);
@@ -713,7 +755,7 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
ti = filters->create_item(ti);
ti->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
ti->set_text(0, types_text);
- ti->set_editable(0, true);
+ ti->set_editable(0, !read_only);
ti->set_selectable(0, true);
ti->set_checked(0, anode->is_path_filtered(path));
ti->set_metadata(0, path);
@@ -726,7 +768,15 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano
return true;
}
-void AnimationNodeBlendTreeEditor::_edit_filters(const String &p_which) {
+void AnimationNodeBlendTreeEditor::_inspect_filters(const String &p_which) {
+ if (read_only) {
+ filter_dialog->set_title(TTR("Inspect Filtered Tracks:"));
+ } else {
+ filter_dialog->set_title(TTR("Edit Filtered Tracks:"));
+ }
+
+ filter_enabled->set_disabled(read_only);
+
Ref<AnimationNode> anode = blend_tree->get_node(p_which);
ERR_FAIL_COND(!anode.is_valid());
@@ -837,6 +887,10 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) {
}
void AnimationNodeBlendTreeEditor::_scroll_changed(const Vector2 &p_scroll) {
+ if (read_only) {
+ return;
+ }
+
if (updating) {
return;
}
@@ -943,13 +997,20 @@ void AnimationNodeBlendTreeEditor::edit(const Ref<AnimationNode> &p_node) {
blend_tree = p_node;
+ read_only = false;
+
if (blend_tree.is_null()) {
hide();
} else {
+ read_only = EditorNode::get_singleton()->is_resource_read_only(blend_tree);
+
blend_tree->connect("removed_from_graph", callable_mp(this, &AnimationNodeBlendTreeEditor::_removed_from_graph));
_update_graph();
}
+
+ add_node->set_disabled(read_only);
+ graph->set_arrange_nodes_button_hidden(read_only);
}
AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
@@ -985,6 +1046,7 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
graph->get_zoom_hbox()->move_child(add_node, 0);
add_node->get_popup()->connect("id_pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_add_node));
add_node->connect("about_to_popup", callable_mp(this, &AnimationNodeBlendTreeEditor::_update_options_menu).bind(false));
+ add_node->set_disabled(read_only);
add_options.push_back(AddOption("Animation", "AnimationNodeAnimation"));
add_options.push_back(AddOption("OneShot", "AnimationNodeOneShot", 2));
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h
index 18199676b8..30a54930a2 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.h
+++ b/editor/plugins/animation_blend_tree_editor_plugin.h
@@ -41,11 +41,15 @@
class ProgressBar;
class EditorFileDialog;
+class EditorUndoRedoManager;
class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeBlendTreeEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeBlendTree> blend_tree;
+
+ bool read_only = false;
+
GraphEdit *graph = nullptr;
MenuButton *add_node = nullptr;
Vector2 position_from_popup_menu;
@@ -54,7 +58,7 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
PanelContainer *error_panel = nullptr;
Label *error_label = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
AcceptDialog *filter_dialog = nullptr;
Tree *filters = nullptr;
@@ -105,7 +109,7 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
void _delete_nodes_request(const TypedArray<StringName> &p_nodes);
bool _update_filters(const Ref<AnimationNode> &anode);
- void _edit_filters(const String &p_which);
+ void _inspect_filters(const String &p_which);
void _filter_edited();
void _filter_toggled();
Ref<AnimationNode> _filter_edit;
diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp
index cae33edecb..f9e5aa799a 100644
--- a/editor/plugins/animation_library_editor.cpp
+++ b/editor/plugins/animation_library_editor.cpp
@@ -32,6 +32,7 @@
#include "editor/editor_file_dialog.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
void AnimationLibraryEditor::set_animation_player(Object *p_player) {
player = p_player;
@@ -92,7 +93,7 @@ void AnimationLibraryEditor::_add_library_validate(const String &p_name) {
void AnimationLibraryEditor::_add_library_confirm() {
if (adding_animation) {
String anim_name = add_library_name->get_text();
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo();
Ref<AnimationLibrary> al = player->call("get_animation_library", adding_animation_to_library);
ERR_FAIL_COND(!al.is_valid());
@@ -109,7 +110,7 @@ void AnimationLibraryEditor::_add_library_confirm() {
} else {
String lib_name = add_library_name->get_text();
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo();
Ref<AnimationLibrary> al;
al.instantiate();
@@ -149,13 +150,35 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) {
}
switch (p_id) {
case FILE_MENU_SAVE_LIBRARY: {
- if (al->get_path().is_resource_file()) {
+ if (al->get_path().is_resource_file() && !FileAccess::exists(al->get_path() + ".import")) {
EditorNode::get_singleton()->save_resource(al);
break;
}
[[fallthrough]];
}
case FILE_MENU_SAVE_AS_LIBRARY: {
+ // Check if we're allowed to save this
+ {
+ String al_path = al->get_path();
+ if (!al_path.is_resource_file()) {
+ int srpos = al_path.find("::");
+ if (srpos != -1) {
+ String base = al_path.substr(0, srpos);
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ error_dialog->set_text(TTR("This animation library can't be saved because it does not belong to the edited scene. Make it unique first."));
+ error_dialog->popup_centered();
+ return;
+ }
+ }
+ } else {
+ if (FileAccess::exists(al_path + ".import")) {
+ error_dialog->set_text(TTR("This animation library can't be saved because it was imported from another file. Make it unique first."));
+ error_dialog->popup_centered();
+ return;
+ }
+ }
+ }
+
file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
file_dialog->set_title(TTR("Save Library"));
if (al->get_path().is_resource_file()) {
@@ -178,7 +201,10 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) {
Ref<AnimationLibrary> ald = al->duplicate();
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ // TODO: should probably make all foreign animations assigned to this library
+ // unique too.
+
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo();
undo_redo->create_action(vformat(TTR("Make Animation Library Unique: %s"), lib_name));
undo_redo->add_do_method(player, "remove_animation_library", lib_name);
undo_redo->add_do_method(player, "add_animation_library", lib_name, ald);
@@ -188,19 +214,43 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) {
undo_redo->add_undo_method(this, "_update_editor", player);
undo_redo->commit_action();
+ update_tree();
+
} break;
case FILE_MENU_EDIT_LIBRARY: {
EditorNode::get_singleton()->push_item(al.ptr());
} break;
case FILE_MENU_SAVE_ANIMATION: {
- if (anim->get_path().is_resource_file()) {
+ if (anim->get_path().is_resource_file() && !FileAccess::exists(anim->get_path() + ".import")) {
EditorNode::get_singleton()->save_resource(anim);
break;
}
[[fallthrough]];
}
case FILE_MENU_SAVE_AS_ANIMATION: {
+ // Check if we're allowed to save this
+ {
+ String anim_path = al->get_path();
+ if (!anim_path.is_resource_file()) {
+ int srpos = anim_path.find("::");
+ if (srpos != -1) {
+ String base = anim_path.substr(0, srpos);
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ error_dialog->set_text(TTR("This animation can't be saved because it does not belong to the edited scene. Make it unique first."));
+ error_dialog->popup_centered();
+ return;
+ }
+ }
+ } else {
+ if (FileAccess::exists(anim_path + ".import")) {
+ error_dialog->set_text(TTR("This animation can't be saved because it was imported from another file. Make it unique first."));
+ error_dialog->popup_centered();
+ return;
+ }
+ }
+ }
+
file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
file_dialog->set_title(TTR("Save Animation"));
if (anim->get_path().is_resource_file()) {
@@ -223,7 +273,7 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) {
Ref<Animation> animd = anim->duplicate();
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo();
undo_redo->create_action(vformat(TTR("Make Animation Unique: %s"), anim_name));
undo_redo->add_do_method(al.ptr(), "remove_animation", anim_name);
undo_redo->add_do_method(al.ptr(), "add_animation", anim_name, animd);
@@ -232,6 +282,8 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) {
undo_redo->add_do_method(this, "_update_editor", player);
undo_redo->add_undo_method(this, "_update_editor", player);
undo_redo->commit_action();
+
+ update_tree();
} break;
case FILE_MENU_EDIT_ANIMATION: {
EditorNode::get_singleton()->push_item(anim.ptr());
@@ -269,7 +321,7 @@ void AnimationLibraryEditor::_load_file(String p_path) {
name = p_path.get_file().get_basename() + " " + itos(attempt);
}
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo();
undo_redo->create_action(vformat(TTR("Add Animation Library: %s"), name));
undo_redo->add_do_method(player, "add_animation_library", name, al);
@@ -307,7 +359,7 @@ void AnimationLibraryEditor::_load_file(String p_path) {
name = p_path.get_file().get_basename() + " " + itos(attempt);
}
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo();
undo_redo->create_action(vformat(TTR("Load Animation into Library: %s"), name));
undo_redo->add_do_method(al.ptr(), "add_animation", name, anim);
@@ -323,7 +375,7 @@ void AnimationLibraryEditor::_load_file(String p_path) {
EditorNode::get_singleton()->save_resource_in_path(al, p_path);
if (al->get_path() != prev_path) { // Save successful.
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo();
undo_redo->create_action(vformat(TTR("Save Animation library to File: %s"), file_dialog_library));
undo_redo->add_do_method(al.ptr(), "set_path", al->get_path());
@@ -344,7 +396,7 @@ void AnimationLibraryEditor::_load_file(String p_path) {
String prev_path = anim->get_path();
EditorNode::get_singleton()->save_resource_in_path(anim, p_path);
if (anim->get_path() != prev_path) { // Save successful.
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo();
undo_redo->create_action(vformat(TTR("Save Animation to File: %s"), file_dialog_animation));
undo_redo->add_do_method(anim.ptr(), "set_path", anim->get_path());
@@ -362,7 +414,7 @@ void AnimationLibraryEditor::_item_renamed() {
String text = ti->get_text(0);
String old_text = ti->get_metadata(0);
bool restore_text = false;
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo();
if (String(text).contains("/") || String(text).contains(":") || String(text).contains(",") || String(text).contains("[")) {
restore_text = true;
@@ -476,7 +528,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int
name = base_name + " (" + itos(attempt) + ")";
}
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo();
undo_redo->create_action(vformat(TTR("Add Animation to Library: %s"), name));
undo_redo->add_do_method(al.ptr(), "add_animation", name, anim);
@@ -502,7 +554,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int
file_dialog_library = lib_name;
} break;
case LIB_BUTTON_DELETE: {
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo();
undo_redo->create_action(vformat(TTR("Remove Animation Library: %s"), lib_name));
undo_redo->add_do_method(player, "remove_animation_library", lib_name);
undo_redo->add_undo_method(player, "add_animation_library", lib_name, al);
@@ -543,7 +595,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int
} break;
case ANIM_BUTTON_DELETE: {
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo();
undo_redo->create_action(vformat(TTR("Remove Animation from Library: %s"), anim_name));
undo_redo->add_do_method(al.ptr(), "remove_animation", anim_name);
undo_redo->add_undo_method(al.ptr(), "add_animation", anim_name, anim);
@@ -577,19 +629,45 @@ void AnimationLibraryEditor::update_tree() {
} else {
libitem->set_suffix(0, "");
}
- libitem->set_editable(0, true);
- libitem->set_metadata(0, K);
- libitem->set_icon(0, get_theme_icon("AnimationLibrary", "EditorIcons"));
- libitem->add_button(0, get_theme_icon("Add", "EditorIcons"), LIB_BUTTON_ADD, false, TTR("Add Animation to Library"));
- libitem->add_button(0, get_theme_icon("Load", "EditorIcons"), LIB_BUTTON_LOAD, false, TTR("Load animation from file and add to library"));
- libitem->add_button(0, get_theme_icon("ActionPaste", "EditorIcons"), LIB_BUTTON_PASTE, false, TTR("Paste Animation to Library from clipboard"));
+
Ref<AnimationLibrary> al = player->call("get_animation_library", K);
- if (al->get_path().is_resource_file()) {
- libitem->set_text(1, al->get_path().get_file());
- libitem->set_tooltip(1, al->get_path());
- } else {
+ bool animation_library_is_foreign = false;
+ String al_path = al->get_path();
+ if (!al_path.is_resource_file()) {
libitem->set_text(1, TTR("[built-in]"));
+ libitem->set_tooltip(1, al_path);
+ int srpos = al_path.find("::");
+ if (srpos != -1) {
+ String base = al_path.substr(0, srpos);
+ if (ResourceLoader::get_resource_type(base) == "PackedScene") {
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ animation_library_is_foreign = true;
+ libitem->set_text(1, TTR("[foreign]"));
+ }
+ } else {
+ if (FileAccess::exists(base + ".import")) {
+ animation_library_is_foreign = true;
+ libitem->set_text(1, TTR("[imported]"));
+ }
+ }
+ }
+ } else {
+ if (FileAccess::exists(al_path + ".import")) {
+ animation_library_is_foreign = true;
+ libitem->set_text(1, TTR("[imported]"));
+ } else {
+ libitem->set_text(1, al_path.get_file());
+ }
}
+
+ libitem->set_editable(0, !animation_library_is_foreign);
+ libitem->set_metadata(0, K);
+ libitem->set_icon(0, get_theme_icon("AnimationLibrary", "EditorIcons"));
+
+ libitem->add_button(0, get_theme_icon("Add", "EditorIcons"), LIB_BUTTON_ADD, animation_library_is_foreign, TTR("Add Animation to Library"));
+ libitem->add_button(0, get_theme_icon("Load", "EditorIcons"), LIB_BUTTON_LOAD, animation_library_is_foreign, TTR("Load animation from file and add to library"));
+ libitem->add_button(0, get_theme_icon("ActionPaste", "EditorIcons"), LIB_BUTTON_PASTE, animation_library_is_foreign, TTR("Paste Animation to Library from clipboard"));
+
libitem->add_button(1, get_theme_icon("Save", "EditorIcons"), LIB_BUTTON_FILE, false, TTR("Save animation library to resource on disk"));
libitem->add_button(1, get_theme_icon("Remove", "EditorIcons"), LIB_BUTTON_DELETE, false, TTR("Remove animation library"));
@@ -600,20 +678,38 @@ void AnimationLibraryEditor::update_tree() {
for (const StringName &L : animations) {
TreeItem *anitem = tree->create_item(libitem);
anitem->set_text(0, L);
- anitem->set_editable(0, true);
+ anitem->set_editable(0, !animation_library_is_foreign);
anitem->set_metadata(0, L);
anitem->set_icon(0, get_theme_icon("Animation", "EditorIcons"));
- anitem->add_button(0, get_theme_icon("ActionCopy", "EditorIcons"), ANIM_BUTTON_COPY, false, TTR("Copy animation to clipboard"));
- Ref<Animation> anim = al->get_animation(L);
+ anitem->add_button(0, get_theme_icon("ActionCopy", "EditorIcons"), ANIM_BUTTON_COPY, animation_library_is_foreign, TTR("Copy animation to clipboard"));
- if (anim->get_path().is_resource_file()) {
- anitem->set_text(1, anim->get_path().get_file());
- anitem->set_tooltip(1, anim->get_path());
- } else {
+ Ref<Animation> anim = al->get_animation(L);
+ String anim_path = anim->get_path();
+ if (!anim_path.is_resource_file()) {
anitem->set_text(1, TTR("[built-in]"));
+ anitem->set_tooltip(1, anim_path);
+ int srpos = anim_path.find("::");
+ if (srpos != -1) {
+ String base = anim_path.substr(0, srpos);
+ if (ResourceLoader::get_resource_type(base) == "PackedScene") {
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ anitem->set_text(1, TTR("[foreign]"));
+ }
+ } else {
+ if (FileAccess::exists(base + ".import")) {
+ anitem->set_text(1, TTR("[imported]"));
+ }
+ }
+ }
+ } else {
+ if (FileAccess::exists(anim_path + ".import")) {
+ anitem->set_text(1, TTR("[imported]"));
+ } else {
+ anitem->set_text(1, anim_path.get_file());
+ }
}
- anitem->add_button(1, get_theme_icon("Save", "EditorIcons"), ANIM_BUTTON_FILE, false, TTR("Save animation to resource on disk"));
- anitem->add_button(1, get_theme_icon("Remove", "EditorIcons"), ANIM_BUTTON_DELETE, false, TTR("Remove animation from Library"));
+ anitem->add_button(1, get_theme_icon("Save", "EditorIcons"), ANIM_BUTTON_FILE, animation_library_is_foreign, TTR("Save animation to resource on disk"));
+ anitem->add_button(1, get_theme_icon("Remove", "EditorIcons"), ANIM_BUTTON_DELETE, animation_library_is_foreign, TTR("Remove animation from Library"));
}
}
}
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 57203ec147..1ab60e8fc8 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -55,7 +55,7 @@ void AnimationPlayerEditor::_node_removed(Node *p_node) {
set_process(false);
- track_editor->set_animation(Ref<Animation>());
+ track_editor->set_animation(Ref<Animation>(), true);
track_editor->set_root(nullptr);
track_editor->show_select_node_warning(true);
_update_player();
@@ -283,7 +283,28 @@ void AnimationPlayerEditor::_animation_selected(int p_which) {
Ref<Animation> anim = player->get_animation(current);
{
- track_editor->set_animation(anim);
+ bool animation_library_is_foreign = false;
+ if (!anim->get_path().is_resource_file()) {
+ int srpos = anim->get_path().find("::");
+ if (srpos != -1) {
+ String base = anim->get_path().substr(0, srpos);
+ if (ResourceLoader::get_resource_type(base) == "PackedScene") {
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ animation_library_is_foreign = true;
+ }
+ } else {
+ if (FileAccess::exists(base + ".import")) {
+ animation_library_is_foreign = true;
+ }
+ }
+ }
+ } else {
+ if (FileAccess::exists(anim->get_path() + ".import")) {
+ animation_library_is_foreign = true;
+ }
+ }
+
+ track_editor->set_animation(anim, animation_library_is_foreign);
Node *root = player->get_node(player->get_root());
if (root) {
track_editor->set_root(root);
@@ -292,7 +313,7 @@ void AnimationPlayerEditor::_animation_selected(int p_which) {
frame->set_max((double)anim->get_length());
} else {
- track_editor->set_animation(Ref<Animation>());
+ track_editor->set_animation(Ref<Animation>(), true);
track_editor->set_root(nullptr);
}
@@ -751,14 +772,36 @@ void AnimationPlayerEditor::_animation_edit() {
String current = _get_current();
if (current != String()) {
Ref<Animation> anim = player->get_animation(current);
- track_editor->set_animation(anim);
+
+ bool animation_library_is_foreign = false;
+ if (!anim->get_path().is_resource_file()) {
+ int srpos = anim->get_path().find("::");
+ if (srpos != -1) {
+ String base = anim->get_path().substr(0, srpos);
+ if (ResourceLoader::get_resource_type(base) == "PackedScene") {
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ animation_library_is_foreign = true;
+ }
+ } else {
+ if (FileAccess::exists(base + ".import")) {
+ animation_library_is_foreign = true;
+ }
+ }
+ }
+ } else {
+ if (FileAccess::exists(anim->get_path() + ".import")) {
+ animation_library_is_foreign = true;
+ }
+ }
+
+ track_editor->set_animation(anim, animation_library_is_foreign);
Node *root = player->get_node(player->get_root());
if (root) {
track_editor->set_root(root);
}
} else {
- track_editor->set_animation(Ref<Animation>());
+ track_editor->set_animation(Ref<Animation>(), true);
track_editor->set_root(nullptr);
}
}
@@ -800,25 +843,50 @@ void AnimationPlayerEditor::_update_player() {
animation->clear();
+ tool_anim->set_disabled(player == nullptr);
+ pin->set_disabled(player == nullptr);
+
if (!player) {
AnimationPlayerEditor::get_singleton()->get_track_editor()->update_keying();
return;
}
List<StringName> libraries;
- if (player) {
- player->get_animation_library_list(&libraries);
- }
+ player->get_animation_library_list(&libraries);
int active_idx = -1;
bool no_anims_found = true;
+ bool foreign_global_anim_lib = false;
for (const StringName &K : libraries) {
if (K != StringName()) {
animation->add_separator(K);
}
+ // Check if the global library is foreign since we want to disable options for adding/remove/renaming animations if it is.
Ref<AnimationLibrary> library = player->get_animation_library(K);
+ if (K == "") {
+ if (!library->get_path().is_resource_file()) {
+ int srpos = library->get_path().find("::");
+ if (srpos != -1) {
+ String base = library->get_path().substr(0, srpos);
+ if (ResourceLoader::get_resource_type(base) == "PackedScene") {
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ foreign_global_anim_lib = true;
+ }
+ } else {
+ if (FileAccess::exists(base + ".import")) {
+ foreign_global_anim_lib = true;
+ }
+ }
+ }
+ } else {
+ if (FileAccess::exists(library->get_path() + ".import")) {
+ foreign_global_anim_lib = true;
+ }
+ }
+ }
+
List<StringName> animlist;
library->get_animation_list(&animlist);
@@ -835,7 +903,13 @@ void AnimationPlayerEditor::_update_player() {
no_anims_found = false;
}
}
-#define ITEM_CHECK_DISABLED(m_item) tool_anim->get_popup()->set_item_disabled(tool_anim->get_popup()->get_item_index(m_item), no_anims_found)
+#define ITEM_CHECK_DISABLED(m_item) tool_anim->get_popup()->set_item_disabled(tool_anim->get_popup()->get_item_index(m_item), foreign_global_anim_lib)
+
+ ITEM_CHECK_DISABLED(TOOL_NEW_ANIM);
+
+#undef ITEM_CHECK_DISABLED
+
+#define ITEM_CHECK_DISABLED(m_item) tool_anim->get_popup()->set_item_disabled(tool_anim->get_popup()->get_item_index(m_item), no_anims_found || foreign_global_anim_lib)
ITEM_CHECK_DISABLED(TOOL_DUPLICATE_ANIM);
ITEM_CHECK_DISABLED(TOOL_RENAME_ANIM);
@@ -853,10 +927,8 @@ void AnimationPlayerEditor::_update_player() {
frame->set_editable(!no_anims_found);
animation->set_disabled(no_anims_found);
autoplay->set_disabled(no_anims_found);
- tool_anim->set_disabled(player == nullptr);
onion_toggle->set_disabled(no_anims_found);
onion_skinning->set_disabled(no_anims_found);
- pin->set_disabled(player == nullptr);
_update_animation_list_icons();
@@ -877,7 +949,29 @@ void AnimationPlayerEditor::_update_player() {
if (!no_anims_found) {
String current = animation->get_item_text(animation->get_selected());
Ref<Animation> anim = player->get_animation(current);
- track_editor->set_animation(anim);
+
+ bool animation_library_is_foreign = false;
+ if (!anim->get_path().is_resource_file()) {
+ int srpos = anim->get_path().find("::");
+ if (srpos != -1) {
+ String base = anim->get_path().substr(0, srpos);
+ if (ResourceLoader::get_resource_type(base) == "PackedScene") {
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ animation_library_is_foreign = true;
+ }
+ } else {
+ if (FileAccess::exists(base + ".import")) {
+ animation_library_is_foreign = true;
+ }
+ }
+ }
+ } else {
+ if (FileAccess::exists(anim->get_path() + ".import")) {
+ animation_library_is_foreign = true;
+ }
+ }
+
+ track_editor->set_animation(anim, animation_library_is_foreign);
Node *root = player->get_node(player->get_root());
if (root) {
track_editor->set_root(root);
@@ -950,6 +1044,10 @@ void AnimationPlayerEditor::_update_name_dialog_library_dropdown() {
}
}
+void AnimationPlayerEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
+ undo_redo = p_undo_redo;
+}
+
void AnimationPlayerEditor::edit(AnimationPlayer *p_player) {
if (player && pin->is_pressed()) {
return; // Ignore, pinned.
@@ -1426,19 +1524,19 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
// Render every past/future step with the capture shader.
RS::get_singleton()->canvas_item_set_material(onion.capture.canvas_item, onion.capture.material->get_rid());
- onion.capture.material->set_shader_param("bkg_color", GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
- onion.capture.material->set_shader_param("differences_only", onion.differences_only);
- onion.capture.material->set_shader_param("present", onion.differences_only ? RS::get_singleton()->viewport_get_texture(present_rid) : RID());
+ onion.capture.material->set_shader_uniform("bkg_color", GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
+ onion.capture.material->set_shader_uniform("differences_only", onion.differences_only);
+ onion.capture.material->set_shader_uniform("present", onion.differences_only ? RS::get_singleton()->viewport_get_texture(present_rid) : RID());
int step_off_a = onion.past ? -onion.steps : 0;
int step_off_b = onion.future ? onion.steps : 0;
int cidx = 0;
- onion.capture.material->set_shader_param("dir_color", onion.force_white_modulate ? Color(1, 1, 1) : Color(EDITOR_GET("editors/animation/onion_layers_past_color")));
+ onion.capture.material->set_shader_uniform("dir_color", onion.force_white_modulate ? Color(1, 1, 1) : Color(EDITOR_GET("editors/animation/onion_layers_past_color")));
for (int step_off = step_off_a; step_off <= step_off_b; step_off++) {
if (step_off == 0) {
// Skip present step and switch to the color of future.
if (!onion.force_white_modulate) {
- onion.capture.material->set_shader_param("dir_color", EDITOR_GET("editors/animation/onion_layers_future_color"));
+ onion.capture.material->set_shader_uniform("dir_color", EDITOR_GET("editors/animation/onion_layers_future_color"));
}
continue;
}
@@ -1547,28 +1645,28 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
play_bw_from = memnew(Button);
play_bw_from->set_flat(true);
- play_bw_from->set_tooltip(TTR("Play selected animation backwards from current pos. (A)"));
+ play_bw_from->set_tooltip_text(TTR("Play selected animation backwards from current pos. (A)"));
hb->add_child(play_bw_from);
play_bw = memnew(Button);
play_bw->set_flat(true);
- play_bw->set_tooltip(TTR("Play selected animation backwards from end. (Shift+A)"));
+ play_bw->set_tooltip_text(TTR("Play selected animation backwards from end. (Shift+A)"));
hb->add_child(play_bw);
stop = memnew(Button);
stop->set_flat(true);
stop->set_toggle_mode(true);
hb->add_child(stop);
- stop->set_tooltip(TTR("Stop animation playback. (S)"));
+ stop->set_tooltip_text(TTR("Stop animation playback. (S)"));
play = memnew(Button);
play->set_flat(true);
- play->set_tooltip(TTR("Play selected animation from start. (Shift+D)"));
+ play->set_tooltip_text(TTR("Play selected animation from start. (Shift+D)"));
hb->add_child(play);
play_from = memnew(Button);
play_from->set_flat(true);
- play_from->set_tooltip(TTR("Play selected animation from current pos. (D)"));
+ play_from->set_tooltip_text(TTR("Play selected animation from current pos. (D)"));
hb->add_child(play_from);
frame = memnew(SpinBox);
@@ -1576,7 +1674,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
frame->set_custom_minimum_size(Size2(80, 0) * EDSCALE);
frame->set_stretch_ratio(2);
frame->set_step(0.0001);
- frame->set_tooltip(TTR("Animation position (in seconds)."));
+ frame->set_tooltip_text(TTR("Animation position (in seconds)."));
hb->add_child(memnew(VSeparator));
@@ -1584,7 +1682,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
hb->add_child(scale);
scale->set_h_size_flags(SIZE_EXPAND_FILL);
scale->set_stretch_ratio(1);
- scale->set_tooltip(TTR("Scale animation playback globally for the node."));
+ scale->set_tooltip_text(TTR("Scale animation playback globally for the node."));
scale->hide();
delete_dialog = memnew(ConfirmationDialog);
@@ -1594,7 +1692,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
tool_anim = memnew(MenuButton);
tool_anim->set_shortcut_context(this);
tool_anim->set_flat(false);
- tool_anim->set_tooltip(TTR("Animation Tools"));
+ tool_anim->set_tooltip_text(TTR("Animation Tools"));
tool_anim->set_text(TTR("Animation"));
tool_anim->get_popup()->add_shortcut(ED_SHORTCUT("animation_player_editor/new_animation", TTR("New")), TOOL_NEW_ANIM);
tool_anim->get_popup()->add_separator();
@@ -1613,13 +1711,13 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
animation = memnew(OptionButton);
hb->add_child(animation);
animation->set_h_size_flags(SIZE_EXPAND_FILL);
- animation->set_tooltip(TTR("Display list of animations in player."));
+ animation->set_tooltip_text(TTR("Display list of animations in player."));
animation->set_clip_text(true);
autoplay = memnew(Button);
autoplay->set_flat(true);
hb->add_child(autoplay);
- autoplay->set_tooltip(TTR("Autoplay on Load"));
+ autoplay->set_tooltip_text(TTR("Autoplay on Load"));
hb->add_child(memnew(VSeparator));
@@ -1632,12 +1730,12 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
onion_toggle = memnew(Button);
onion_toggle->set_flat(true);
onion_toggle->set_toggle_mode(true);
- onion_toggle->set_tooltip(TTR("Enable Onion Skinning"));
+ onion_toggle->set_tooltip_text(TTR("Enable Onion Skinning"));
onion_toggle->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_onion_skinning_menu).bind(ONION_SKINNING_ENABLE));
hb->add_child(onion_toggle);
onion_skinning = memnew(MenuButton);
- onion_skinning->set_tooltip(TTR("Onion Skinning Options"));
+ onion_skinning->set_tooltip_text(TTR("Onion Skinning Options"));
onion_skinning->get_popup()->add_separator(TTR("Directions"));
// TRANSLATORS: Opposite of "Future", refers to a direction in animation onion skinning.
onion_skinning->get_popup()->add_check_item(TTR("Past"), ONION_SKINNING_PAST);
@@ -1660,7 +1758,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
pin = memnew(Button);
pin->set_flat(true);
pin->set_toggle_mode(true);
- pin->set_tooltip(TTR("Pin AnimationPlayer"));
+ pin->set_tooltip_text(TTR("Pin AnimationPlayer"));
hb->add_child(pin);
pin->connect("pressed", callable_mp(this, &AnimationPlayerEditor::_pin_pressed));
@@ -1830,7 +1928,7 @@ void AnimationPlayerEditorPlugin::_update_keying() {
}
void AnimationPlayerEditorPlugin::edit(Object *p_object) {
- anim_editor->set_undo_redo(&get_undo_redo());
+ anim_editor->set_undo_redo(get_undo_redo());
if (!p_object) {
return;
}
diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h
index 3b1de070fa..a37a9debef 100644
--- a/editor/plugins/animation_player_editor_plugin.h
+++ b/editor/plugins/animation_player_editor_plugin.h
@@ -41,6 +41,7 @@
#include "scene/gui/texture_button.h"
#include "scene/gui/tree.h"
+class EditorUndoRedoManager;
class AnimationPlayerEditorPlugin;
class AnimationPlayerEditor : public VBoxContainer {
@@ -100,7 +101,7 @@ class AnimationPlayerEditor : public VBoxContainer {
LineEdit *name = nullptr;
OptionButton *library = nullptr;
Label *name_title = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
Ref<Texture2D> autoplay_icon;
Ref<Texture2D> reset_icon;
@@ -233,7 +234,7 @@ public:
void ensure_visibility();
- void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; }
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void edit(AnimationPlayer *p_player);
void forward_force_draw_over_viewport(Control *p_overlay);
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index 473450b292..be1e531cb8 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -39,6 +39,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/animation/animation_blend_tree.h"
#include "scene/animation/animation_player.h"
#include "scene/gui/menu_button.h"
@@ -55,7 +56,11 @@ bool AnimationNodeStateMachineEditor::can_edit(const Ref<AnimationNode> &p_node)
void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) {
state_machine = p_node;
+ read_only = false;
+
if (state_machine.is_valid()) {
+ read_only = EditorNode::get_singleton()->is_resource_read_only(state_machine);
+
selected_transition_from = StringName();
selected_transition_to = StringName();
selected_transition_index = -1;
@@ -65,6 +70,9 @@ void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) {
_update_mode();
_update_graph();
}
+
+ tool_create->set_disabled(read_only);
+ tool_connect->set_disabled(read_only);
}
void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEvent> &p_event) {
@@ -76,7 +84,9 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
Ref<InputEventKey> k = p_event;
if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) {
if (selected_node != StringName() || !selected_nodes.is_empty() || selected_transition_to != StringName() || selected_transition_from != StringName()) {
- _erase_selected();
+ if (!read_only) {
+ _erase_selected();
+ }
accept_event();
}
}
@@ -94,9 +104,11 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
Ref<InputEventMouseButton> mb = p_event;
// Add new node
- if (mb.is_valid() && mb->is_pressed() && !box_selecting && !connecting && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (tool_create->is_pressed() && mb->get_button_index() == MouseButton::LEFT))) {
- connecting_from = StringName();
- _open_menu(mb->get_position());
+ if (!read_only) {
+ if (mb.is_valid() && mb->is_pressed() && !box_selecting && !connecting && ((tool_select->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) || (tool_create->is_pressed() && mb->get_button_index() == MouseButton::LEFT))) {
+ connecting_from = StringName();
+ _open_menu(mb->get_position());
+ }
}
// Select node or push a field inside
@@ -120,22 +132,24 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
return;
}
- if (node_rects[i].name.has_point(mb->get_position()) && state_machine->can_edit_node(node_rects[i].node_name)) { // edit name
- Ref<StyleBox> line_sb = get_theme_stylebox(SNAME("normal"), SNAME("LineEdit"));
+ if (!read_only) {
+ if (node_rects[i].name.has_point(mb->get_position()) && state_machine->can_edit_node(node_rects[i].node_name)) { // edit name
+ Ref<StyleBox> line_sb = get_theme_stylebox(SNAME("normal"), SNAME("LineEdit"));
- Rect2 edit_rect = node_rects[i].name;
- edit_rect.position -= line_sb->get_offset();
- edit_rect.size += line_sb->get_minimum_size();
+ Rect2 edit_rect = node_rects[i].name;
+ edit_rect.position -= line_sb->get_offset();
+ edit_rect.size += line_sb->get_minimum_size();
- name_edit_popup->set_position(state_machine_draw->get_screen_position() + edit_rect.position);
- name_edit_popup->set_size(edit_rect.size);
- name_edit->set_text(node_rects[i].node_name);
- name_edit_popup->popup();
- name_edit->grab_focus();
- name_edit->select_all();
+ name_edit_popup->set_position(state_machine_draw->get_screen_position() + edit_rect.position);
+ name_edit_popup->set_size(edit_rect.size);
+ name_edit->set_text(node_rects[i].node_name);
+ name_edit_popup->popup();
+ name_edit->grab_focus();
+ name_edit->select_all();
- prev_name = node_rects[i].node_name;
- return;
+ prev_name = node_rects[i].node_name;
+ return;
+ }
}
if (node_rects[i].edit.has_point(mb->get_position())) { //edit name
@@ -318,7 +332,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
// Move mouse while connecting
- if (mm.is_valid() && connecting) {
+ if (mm.is_valid() && connecting && !read_only) {
connecting_to = mm->get_position();
connecting_to_node = StringName();
state_machine_draw->update();
@@ -332,7 +346,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
// Move mouse while moving a node
- if (mm.is_valid() && dragging_selected_attempt) {
+ if (mm.is_valid() && dragging_selected_attempt && !read_only) {
dragging_selected = true;
drag_ofs = mm->get_position() - drag_from;
snap_x = StringName();
@@ -462,9 +476,9 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
to = String(transition_lines[closest].multi_transitions[i].to_node);
tooltip += "\n" + from + " -> " + to;
}
- state_machine_draw->set_tooltip(tooltip);
+ state_machine_draw->set_tooltip_text(tooltip);
} else {
- state_machine_draw->set_tooltip("");
+ state_machine_draw->set_tooltip_text("");
}
}
}
@@ -477,17 +491,21 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
Control::CursorShape AnimationNodeStateMachineEditor::get_cursor_shape(const Point2 &p_pos) const {
- // Put ibeam (text cursor) over names to make it clearer that they are editable.
- Transform2D xform = panel->get_transform() * state_machine_draw->get_transform();
- Point2 pos = xform.xform_inv(p_pos);
Control::CursorShape cursor_shape = get_default_cursor_shape();
-
- for (int i = node_rects.size() - 1; i >= 0; i--) { // Inverse to draw order.
- if (node_rects[i].node.has_point(pos)) {
- if (node_rects[i].name.has_point(pos)) {
- cursor_shape = Control::CURSOR_IBEAM;
+ if (!read_only) {
+ // Put ibeam (text cursor) over names to make it clearer that they are editable.
+ Transform2D xform = panel->get_transform() * state_machine_draw->get_transform();
+ Point2 pos = xform.xform_inv(p_pos);
+
+ for (int i = node_rects.size() - 1; i >= 0; i--) { // Inverse to draw order.
+ if (node_rects[i].node.has_point(pos)) {
+ if (node_rects[i].name.has_point(pos)) {
+ if (state_machine->can_edit_node(node_rects[i].node_name)) {
+ cursor_shape = Control::CURSOR_IBEAM;
+ }
+ }
+ break;
}
- break;
}
}
return cursor_shape;
@@ -1847,9 +1865,9 @@ void AnimationNodeStateMachineEditor::_update_mode() {
tool_erase_hb->show();
bool nothing_selected = selected_nodes.is_empty() && selected_transition_from == StringName() && selected_transition_to == StringName();
bool start_end_selected = selected_nodes.size() == 1 && (*selected_nodes.begin() == state_machine->start_node || *selected_nodes.begin() == state_machine->end_node);
- tool_erase->set_disabled(nothing_selected || start_end_selected);
+ tool_erase->set_disabled(nothing_selected || start_end_selected || read_only);
- if (selected_nodes.is_empty() || start_end_selected) {
+ if (selected_nodes.is_empty() || start_end_selected || read_only) {
tool_group->set_disabled(true);
tool_group->set_visible(true);
tool_ungroup->set_visible(false);
@@ -1899,7 +1917,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
tool_select->set_toggle_mode(true);
tool_select->set_button_group(bg);
tool_select->set_pressed(true);
- tool_select->set_tooltip(TTR("Select and move nodes.\nRMB: Add node at position clicked.\nShift+LMB+Drag: Connects the selected node with another node or creates a new node if you select an area without nodes."));
+ tool_select->set_tooltip_text(TTR("Select and move nodes.\nRMB: Add node at position clicked.\nShift+LMB+Drag: Connects the selected node with another node or creates a new node if you select an area without nodes."));
tool_select->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_update_mode), CONNECT_DEFERRED);
tool_create = memnew(Button);
@@ -1907,7 +1925,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
top_hb->add_child(tool_create);
tool_create->set_toggle_mode(true);
tool_create->set_button_group(bg);
- tool_create->set_tooltip(TTR("Create new nodes."));
+ tool_create->set_tooltip_text(TTR("Create new nodes."));
tool_create->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_update_mode), CONNECT_DEFERRED);
tool_connect = memnew(Button);
@@ -1915,7 +1933,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
top_hb->add_child(tool_connect);
tool_connect->set_toggle_mode(true);
tool_connect->set_button_group(bg);
- tool_connect->set_tooltip(TTR("Connect nodes."));
+ tool_connect->set_tooltip_text(TTR("Connect nodes."));
tool_connect->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_update_mode), CONNECT_DEFERRED);
tool_erase_hb = memnew(HBoxContainer);
@@ -1924,21 +1942,21 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
tool_group = memnew(Button);
tool_group->set_flat(true);
- tool_group->set_tooltip(TTR("Group Selected Node(s)") + " (Ctrl+G)");
+ tool_group->set_tooltip_text(TTR("Group Selected Node(s)") + " (Ctrl+G)");
tool_group->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_group_selected_nodes));
tool_group->set_disabled(true);
tool_erase_hb->add_child(tool_group);
tool_ungroup = memnew(Button);
tool_ungroup->set_flat(true);
- tool_ungroup->set_tooltip(TTR("Ungroup Selected Node") + " (Ctrl+Shift+G)");
+ tool_ungroup->set_tooltip_text(TTR("Ungroup Selected Node") + " (Ctrl+Shift+G)");
tool_ungroup->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_ungroup_selected_nodes));
tool_ungroup->set_visible(false);
tool_erase_hb->add_child(tool_ungroup);
tool_erase = memnew(Button);
tool_erase->set_flat(true);
- tool_erase->set_tooltip(TTR("Remove selected node or transition."));
+ tool_erase->set_tooltip_text(TTR("Remove selected node or transition."));
tool_erase->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_erase_selected).bind(false));
tool_erase->set_disabled(true);
tool_erase_hb->add_child(tool_erase);
diff --git a/editor/plugins/animation_state_machine_editor.h b/editor/plugins/animation_state_machine_editor.h
index 165940e639..3a59e94a5f 100644
--- a/editor/plugins/animation_state_machine_editor.h
+++ b/editor/plugins/animation_state_machine_editor.h
@@ -40,12 +40,15 @@
#include "scene/gui/tree.h"
class EditorFileDialog;
+class EditorUndoRedoManager;
class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
GDCLASS(AnimationNodeStateMachineEditor, AnimationTreeNodeEditorPlugin);
Ref<AnimationNodeStateMachine> state_machine;
+ bool read_only = false;
+
Button *tool_select = nullptr;
Button *tool_create = nullptr;
Button *tool_connect = nullptr;
@@ -76,7 +79,7 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
bool updating = false;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
static AnimationNodeStateMachineEditor *singleton;
diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp
index bce4c9de8e..ed231c446b 100644
--- a/editor/plugins/animation_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_tree_editor_plugin.cpp
@@ -59,10 +59,11 @@ void AnimationTreeEditor::edit(AnimationTree *p_tree) {
Vector<String> path;
if (tree && tree->has_meta("_tree_edit_path")) {
path = tree->get_meta("_tree_edit_path");
- edit_path(path);
} else {
current_root = ObjectID();
}
+
+ edit_path(path);
}
void AnimationTreeEditor::_path_button_pressed(int p_path) {
@@ -129,6 +130,11 @@ void AnimationTreeEditor::edit_path(const Vector<String> &p_path) {
} else {
current_root = ObjectID();
edited_path = button_path;
+
+ for (int i = 0; i < editors.size(); i++) {
+ editors[i]->edit(Ref<AnimationNode>());
+ editors[i]->hide();
+ }
}
_update_path();
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index 8ee162d085..41383edafe 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -487,7 +487,7 @@ void EditorAssetLibraryItemDownload::_make_request() {
retry_button->hide();
download->cancel_request();
- download->set_download_file(EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_asset_" + itos(asset_id)) + ".zip");
+ download->set_download_file(EditorPaths::get_singleton()->get_cache_dir().path_join("tmp_asset_" + itos(asset_id)) + ".zip");
Error err = download->request(host);
if (err != OK) {
@@ -730,7 +730,7 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PackedB
PackedByteArray image_data = p_data;
if (use_cache) {
- String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text());
+ String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().path_join("assetimage_" + image_queue[p_queue_id].image_url.md5_text());
Ref<FileAccess> file = FileAccess::open(cache_filename_base + ".data", FileAccess::READ);
if (file.is_valid()) {
@@ -804,7 +804,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons
if (p_code != HTTPClient::RESPONSE_NOT_MODIFIED) {
for (int i = 0; i < headers.size(); i++) {
if (headers[i].findn("ETag:") == 0) { // Save etag
- String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().plus_file("assetimage_" + image_queue[p_queue_id].image_url.md5_text());
+ String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().path_join("assetimage_" + image_queue[p_queue_id].image_url.md5_text());
String new_etag = headers[i].substr(headers[i].find(":") + 1, headers[i].length()).strip_edges();
Ref<FileAccess> file = FileAccess::open(cache_filename_base + ".etag", FileAccess::WRITE);
if (file.is_valid()) {
@@ -846,7 +846,7 @@ void EditorAssetLibrary::_update_image_queue() {
List<int> to_delete;
for (KeyValue<int, ImageQueue> &E : image_queue) {
if (!E.value.active && current_images < max_images) {
- String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().plus_file("assetimage_" + E.value.image_url.md5_text());
+ String cache_filename_base = EditorPaths::get_singleton()->get_cache_dir().path_join("assetimage_" + E.value.image_url.md5_text());
Vector<String> headers;
if (FileAccess::exists(cache_filename_base + ".etag") && FileAccess::exists(cache_filename_base + ".data")) {
@@ -1595,7 +1595,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
///////
bool AssetLibraryEditorPlugin::is_available() {
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
// Asset Library can't work on Web editor for now as most assets are sourced
// directly from GitHub which does not set CORS.
return false;
diff --git a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp
index 9e551ae0ed..d670197c53 100644
--- a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp
+++ b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp
@@ -31,6 +31,7 @@
#include "audio_stream_randomizer_editor_plugin.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
void AudioStreamRandomizerEditorPlugin::edit(Object *p_object) {
}
@@ -43,8 +44,8 @@ void AudioStreamRandomizerEditorPlugin::make_visible(bool p_visible) {
}
void AudioStreamRandomizerEditorPlugin::_move_stream_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) {
- UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo);
- ERR_FAIL_COND(!undo_redo);
+ Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_COND(undo_redo.is_null());
AudioStreamRandomizer *randomizer = Object::cast_to<AudioStreamRandomizer>(p_edited);
if (!randomizer) {
diff --git a/editor/plugins/bone_map_editor_plugin.cpp b/editor/plugins/bone_map_editor_plugin.cpp
index 70775c1ee2..c16dca00a3 100644
--- a/editor/plugins/bone_map_editor_plugin.cpp
+++ b/editor/plugins/bone_map_editor_plugin.cpp
@@ -47,6 +47,9 @@ void BoneMapperButton::fetch_textures() {
set_offset(SIDE_TOP, 0);
set_offset(SIDE_BOTTOM, 0);
+ // Hack to avoid handle color darkening...
+ set_modulate(EditorSettings::get_singleton()->is_dark_theme() ? Color(1, 1, 1) : Color(4.25, 4.25, 4.25));
+
circle = memnew(TextureRect);
circle->set_texture(get_theme_icon(SNAME("BoneMapperHandleCircle"), SNAME("EditorIcons")));
add_child(circle);
@@ -98,14 +101,24 @@ BoneMapperButton::~BoneMapperButton() {
}
void BoneMapperItem::create_editor() {
- skeleton_bone_selector = memnew(EditorPropertyTextEnum);
- skeleton_bone_selector->setup(skeleton_bone_names, false, true);
+ HBoxContainer *hbox = memnew(HBoxContainer);
+ add_child(hbox);
+
+ skeleton_bone_selector = memnew(EditorPropertyText);
skeleton_bone_selector->set_label(profile_bone_name);
skeleton_bone_selector->set_selectable(false);
+ skeleton_bone_selector->set_h_size_flags(SIZE_EXPAND_FILL);
skeleton_bone_selector->set_object_and_property(bone_map.ptr(), "bone_map/" + String(profile_bone_name));
skeleton_bone_selector->update_property();
skeleton_bone_selector->connect("property_changed", callable_mp(this, &BoneMapperItem::_value_changed));
- add_child(skeleton_bone_selector);
+ hbox->add_child(skeleton_bone_selector);
+
+ picker_button = memnew(Button);
+ picker_button->set_icon(get_theme_icon(SNAME("ClassList"), SNAME("EditorIcons")));
+ picker_button->connect("pressed", callable_mp(this, &BoneMapperItem::_open_picker));
+ hbox->add_child(picker_button);
+
+ add_child(memnew(HSeparator));
}
void BoneMapperItem::_update_property() {
@@ -114,6 +127,10 @@ void BoneMapperItem::_update_property() {
}
}
+void BoneMapperItem::_open_picker() {
+ emit_signal(SNAME("pick"), profile_bone_name);
+}
+
void BoneMapperItem::_value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) {
bone_map->set(p_property, p_value);
}
@@ -133,25 +150,153 @@ void BoneMapperItem::_notification(int p_what) {
}
void BoneMapperItem::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("pick", PropertyInfo(Variant::STRING_NAME, "profile_bone_name")));
}
-BoneMapperItem::BoneMapperItem(Ref<BoneMap> &p_bone_map, PackedStringArray p_skeleton_bone_names, const StringName &p_profile_bone_name) {
+BoneMapperItem::BoneMapperItem(Ref<BoneMap> &p_bone_map, const StringName &p_profile_bone_name) {
bone_map = p_bone_map;
- skeleton_bone_names = p_skeleton_bone_names;
profile_bone_name = p_profile_bone_name;
}
BoneMapperItem::~BoneMapperItem() {
}
+void BonePicker::create_editors() {
+ set_title(TTR("Bone Picker:"));
+
+ VBoxContainer *vbox = memnew(VBoxContainer);
+ add_child(vbox);
+
+ bones = memnew(Tree);
+ bones->set_select_mode(Tree::SELECT_SINGLE);
+ bones->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ bones->set_hide_root(true);
+ bones->connect("item_activated", callable_mp(this, &BonePicker::_confirm));
+ vbox->add_child(bones);
+
+ create_bones_tree(skeleton);
+}
+
+void BonePicker::create_bones_tree(Skeleton3D *p_skeleton) {
+ bones->clear();
+
+ if (!p_skeleton) {
+ return;
+ }
+
+ TreeItem *root = bones->create_item();
+
+ HashMap<int, TreeItem *> items;
+
+ items.insert(-1, root);
+
+ Ref<Texture> bone_icon = get_theme_icon(SNAME("BoneAttachment3D"), SNAME("EditorIcons"));
+
+ Vector<int> bones_to_process = p_skeleton->get_parentless_bones();
+ bool is_first = true;
+ while (bones_to_process.size() > 0) {
+ int current_bone_idx = bones_to_process[0];
+ bones_to_process.erase(current_bone_idx);
+
+ Vector<int> current_bone_child_bones = p_skeleton->get_bone_children(current_bone_idx);
+ int child_bone_size = current_bone_child_bones.size();
+ for (int i = 0; i < child_bone_size; i++) {
+ bones_to_process.push_back(current_bone_child_bones[i]);
+ }
+
+ const int parent_idx = p_skeleton->get_bone_parent(current_bone_idx);
+ TreeItem *parent_item = items.find(parent_idx)->value;
+
+ TreeItem *joint_item = bones->create_item(parent_item);
+ items.insert(current_bone_idx, joint_item);
+
+ joint_item->set_text(0, p_skeleton->get_bone_name(current_bone_idx));
+ joint_item->set_icon(0, bone_icon);
+ joint_item->set_selectable(0, true);
+ joint_item->set_metadata(0, "bones/" + itos(current_bone_idx));
+ if (is_first) {
+ is_first = false;
+ } else {
+ joint_item->set_collapsed(true);
+ }
+ }
+}
+
+void BonePicker::_confirm() {
+ _ok_pressed();
+}
+
+void BonePicker::popup_bones_tree(const Size2i &p_minsize) {
+ popup_centered(p_minsize);
+}
+
+bool BonePicker::has_selected_bone() {
+ TreeItem *selected = bones->get_selected();
+ if (!selected) {
+ return false;
+ }
+ return true;
+}
+
+StringName BonePicker::get_selected_bone() {
+ TreeItem *selected = bones->get_selected();
+ if (!selected) {
+ return StringName();
+ }
+ return selected->get_text(0);
+}
+
+void BonePicker::_bind_methods() {
+}
+
+void BonePicker::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ create_editors();
+ } break;
+ }
+}
+
+BonePicker::BonePicker(Skeleton3D *p_skeleton) {
+ skeleton = p_skeleton;
+}
+
+BonePicker::~BonePicker() {
+}
+
void BoneMapper::create_editor() {
+ // Create Bone picker.
+ picker = memnew(BonePicker(skeleton));
+ picker->connect("confirmed", callable_mp(this, &BoneMapper::_apply_picker_selection));
+ add_child(picker, false, INTERNAL_MODE_FRONT);
+
+ profile_selector = memnew(EditorPropertyResource);
+ profile_selector->setup(bone_map.ptr(), "profile", "SkeletonProfile");
+ profile_selector->set_label("Profile");
+ profile_selector->set_selectable(false);
+ profile_selector->set_object_and_property(bone_map.ptr(), "profile");
+ profile_selector->update_property();
+ profile_selector->connect("property_changed", callable_mp(this, &BoneMapper::_profile_changed));
+ add_child(profile_selector);
+ add_child(memnew(HSeparator));
+
+ HBoxContainer *group_hbox = memnew(HBoxContainer);
+ add_child(group_hbox);
+
profile_group_selector = memnew(EditorPropertyEnum);
profile_group_selector->set_label("Group");
profile_group_selector->set_selectable(false);
+ profile_group_selector->set_h_size_flags(SIZE_EXPAND_FILL);
profile_group_selector->set_object_and_property(this, "current_group_idx");
profile_group_selector->update_property();
profile_group_selector->connect("property_changed", callable_mp(this, &BoneMapper::_value_changed));
- add_child(profile_group_selector);
+ group_hbox->add_child(profile_group_selector);
+
+ clear_mapping_button = memnew(Button);
+ clear_mapping_button->set_icon(get_theme_icon(SNAME("Clear"), SNAME("EditorIcons")));
+ clear_mapping_button->set_tooltip_text(TTR("Clear mappings in current group."));
+ clear_mapping_button->connect("pressed", callable_mp(this, &BoneMapper::_clear_mapping_current_group));
+ group_hbox->add_child(clear_mapping_button);
bone_mapper_field = memnew(AspectRatioContainer);
bone_mapper_field->set_stretch_mode(AspectRatioContainer::STRETCH_FIT);
@@ -175,9 +320,6 @@ void BoneMapper::create_editor() {
mapper_item_vbox = memnew(VBoxContainer);
add_child(mapper_item_vbox);
- separator = memnew(HSeparator);
- add_child(separator);
-
recreate_items();
}
@@ -201,6 +343,18 @@ void BoneMapper::update_group_idx() {
}
}
+void BoneMapper::_pick_bone(const StringName &p_bone_name) {
+ picker_key_name = p_bone_name;
+ picker->popup_bones_tree(Size2(500, 500) * EDSCALE);
+}
+
+void BoneMapper::_apply_picker_selection() {
+ if (!picker->has_selected_bone()) {
+ return;
+ }
+ bone_map->set_skeleton_bone_name(picker_key_name, picker->get_selected_bone());
+}
+
void BoneMapper::set_current_group_idx(int p_group_idx) {
current_group_idx = p_group_idx;
recreate_editor();
@@ -282,6 +436,7 @@ void BoneMapper::clear_items() {
// Clear items.
int len = bone_mapper_items.size();
for (int i = 0; i < len; i++) {
+ bone_mapper_items[i]->disconnect("pick", callable_mp(this, &BoneMapper::_pick_bone));
mapper_item_vbox->remove_child(bone_mapper_items[i]);
memdelete(bone_mapper_items[i]);
}
@@ -293,16 +448,11 @@ void BoneMapper::recreate_items() {
// Create items by profile.
Ref<SkeletonProfile> profile = bone_map->get_profile();
if (profile.is_valid()) {
- PackedStringArray skeleton_bone_names;
- int len = skeleton->get_bone_count();
- for (int i = 0; i < len; i++) {
- skeleton_bone_names.push_back(skeleton->get_bone_name(i));
- }
-
- len = profile->get_bone_size();
+ int len = profile->get_bone_size();
for (int i = 0; i < len; i++) {
StringName bn = profile->get_bone_name(i);
- bone_mapper_items.append(memnew(BoneMapperItem(bone_map, skeleton_bone_names, bn)));
+ bone_mapper_items.append(memnew(BoneMapperItem(bone_map, bn)));
+ bone_mapper_items[i]->connect("pick", callable_mp(this, &BoneMapper::_pick_bone), CONNECT_DEFERRED);
mapper_item_vbox->add_child(bone_mapper_items[i]);
}
}
@@ -363,11 +513,754 @@ void BoneMapper::_update_state() {
}
}
+void BoneMapper::_clear_mapping_current_group() {
+ if (bone_map.is_valid()) {
+ Ref<SkeletonProfile> profile = bone_map->get_profile();
+ if (profile.is_valid() && profile->get_group_size() > 0) {
+ int len = profile->get_bone_size();
+ for (int i = 0; i < len; i++) {
+ if (profile->get_group(i) == profile->get_group_name(current_group_idx)) {
+ bone_map->_set_skeleton_bone_name(profile->get_bone_name(i), StringName());
+ }
+ }
+ recreate_items();
+ }
+ }
+}
+
+#ifdef MODULE_REGEX_ENABLED
+int BoneMapper::search_bone_by_name(Skeleton3D *p_skeleton, Vector<String> p_picklist, BoneSegregation p_segregation, int p_parent, int p_child, int p_children_count) {
+ // There may be multiple candidates hit by existing the subsidiary bone.
+ // The one with the shortest name is probably the original.
+ LocalVector<String> hit_list;
+ String shortest = "";
+
+ for (int word_idx = 0; word_idx < p_picklist.size(); word_idx++) {
+ RegEx re = RegEx(p_picklist[word_idx]);
+ if (p_child == -1) {
+ Vector<int> bones_to_process = p_parent == -1 ? p_skeleton->get_parentless_bones() : p_skeleton->get_bone_children(p_parent);
+ while (bones_to_process.size() > 0) {
+ int idx = bones_to_process[0];
+ bones_to_process.erase(idx);
+ Vector<int> children = p_skeleton->get_bone_children(idx);
+ for (int i = 0; i < children.size(); i++) {
+ bones_to_process.push_back(children[i]);
+ }
+
+ if (p_children_count == 0 && children.size() > 0) {
+ continue;
+ }
+ if (p_children_count > 0 && children.size() < p_children_count) {
+ continue;
+ }
+
+ String bn = skeleton->get_bone_name(idx);
+ if (!re.search(bn.to_lower()).is_null() && guess_bone_segregation(bn) == p_segregation) {
+ hit_list.push_back(bn);
+ }
+ }
+
+ if (hit_list.size() > 0) {
+ shortest = hit_list[0];
+ for (uint32_t i = 0; i < hit_list.size(); i++) {
+ if (hit_list[i].length() < shortest.length()) {
+ shortest = hit_list[i]; // Prioritize parent.
+ }
+ }
+ }
+ } else {
+ int idx = skeleton->get_bone_parent(p_child);
+ while (idx != p_parent && idx >= 0) {
+ Vector<int> children = p_skeleton->get_bone_children(idx);
+ if (p_children_count == 0 && children.size() > 0) {
+ continue;
+ }
+ if (p_children_count > 0 && children.size() < p_children_count) {
+ continue;
+ }
+
+ String bn = skeleton->get_bone_name(idx);
+ if (!re.search(bn.to_lower()).is_null() && guess_bone_segregation(bn) == p_segregation) {
+ hit_list.push_back(bn);
+ }
+ idx = skeleton->get_bone_parent(idx);
+ }
+
+ if (hit_list.size() > 0) {
+ shortest = hit_list[0];
+ for (uint32_t i = 0; i < hit_list.size(); i++) {
+ if (hit_list[i].length() <= shortest.length()) {
+ shortest = hit_list[i]; // Prioritize parent.
+ }
+ }
+ }
+ }
+
+ if (shortest != "") {
+ break;
+ }
+ }
+
+ if (shortest == "") {
+ return -1;
+ }
+
+ return skeleton->find_bone(shortest);
+}
+
+BoneMapper::BoneSegregation BoneMapper::guess_bone_segregation(String p_bone_name) {
+ String fixed_bn = p_bone_name.camelcase_to_underscore().to_lower();
+
+ LocalVector<String> left_words;
+ left_words.push_back("(?<![a-zA-Z])left");
+ left_words.push_back("(?<![a-zA-Z0-9])l(?![a-zA-Z0-9])");
+
+ LocalVector<String> right_words;
+ right_words.push_back("(?<![a-zA-Z])right");
+ right_words.push_back("(?<![a-zA-Z0-9])r(?![a-zA-Z0-9])");
+
+ for (uint32_t i = 0; i < left_words.size(); i++) {
+ RegEx re_l = RegEx(left_words[i]);
+ if (!re_l.search(fixed_bn).is_null()) {
+ return BONE_SEGREGATION_LEFT;
+ }
+ RegEx re_r = RegEx(right_words[i]);
+ if (!re_r.search(fixed_bn).is_null()) {
+ return BONE_SEGREGATION_RIGHT;
+ }
+ }
+
+ return BONE_SEGREGATION_NONE;
+}
+
+void BoneMapper::_run_auto_mapping() {
+ auto_mapping_process(bone_map);
+ recreate_items();
+}
+
+void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) {
+ WARN_PRINT("Run auto mapping.");
+
+ int bone_idx = -1;
+ Vector<String> picklist; // Use Vector<String> because match words have priority.
+ Vector<int> search_path;
+
+ // 1. Guess Hips
+ picklist.push_back("hip");
+ picklist.push_back("pelvis");
+ picklist.push_back("waist");
+ picklist.push_back("torso");
+ int hips = search_bone_by_name(skeleton, picklist);
+ if (hips == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess Hips. Abort auto mapping.");
+ return; // If there is no Hips, we cannot guess bone after then.
+ } else {
+ p_bone_map->_set_skeleton_bone_name("Hips", skeleton->get_bone_name(hips));
+ }
+ picklist.clear();
+
+ // 2. Guess Root
+ bone_idx = skeleton->get_bone_parent(hips);
+ while (bone_idx >= 0) {
+ search_path.push_back(bone_idx);
+ bone_idx = skeleton->get_bone_parent(bone_idx);
+ }
+ if (search_path.size() == 0) {
+ bone_idx = -1;
+ } else if (search_path.size() == 1) {
+ bone_idx = search_path[0]; // It is only one bone which can be root.
+ } else {
+ bool found = false;
+ for (int i = 0; i < search_path.size(); i++) {
+ RegEx re = RegEx("root");
+ if (!re.search(skeleton->get_bone_name(search_path[i]).to_lower()).is_null()) {
+ bone_idx = search_path[i]; // Name match is preferred.
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ for (int i = 0; i < search_path.size(); i++) {
+ if (Vector3(0, 0, 0).is_equal_approx(skeleton->get_bone_global_rest(search_path[i]).origin)) {
+ bone_idx = search_path[i]; // The bone existing at the origin is appropriate as a root.
+ found = true;
+ break;
+ }
+ }
+ }
+ if (!found) {
+ bone_idx = search_path[search_path.size() - 1]; // Ambiguous, but most parental bone selected.
+ }
+ }
+ if (bone_idx == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess Root."); // Root is not required, so continue.
+ } else {
+ p_bone_map->_set_skeleton_bone_name("Root", skeleton->get_bone_name(bone_idx));
+ }
+ bone_idx = -1;
+ search_path.clear();
+
+ // 3. Guess Neck
+ picklist.push_back("neck");
+ picklist.push_back("head"); // For no neck model.
+ picklist.push_back("face"); // Same above.
+ int neck = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_NONE, hips);
+ picklist.clear();
+
+ // 4. Guess Head
+ picklist.push_back("head");
+ picklist.push_back("face");
+ int head = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_NONE, neck);
+ if (head == -1) {
+ search_path = skeleton->get_bone_children(neck);
+ if (search_path.size() == 1) {
+ head = search_path[0]; // Maybe only one child of the Neck is Head.
+ }
+ }
+ if (head == -1) {
+ if (neck != -1) {
+ head = neck; // The head animation should have more movement.
+ neck = -1;
+ p_bone_map->_set_skeleton_bone_name("Head", skeleton->get_bone_name(head));
+ } else {
+ WARN_PRINT("Auto Mapping couldn't guess Neck or Head."); // Continued for guessing on the other bones. But abort when guessing spines step.
+ }
+ } else {
+ p_bone_map->_set_skeleton_bone_name("Neck", skeleton->get_bone_name(neck));
+ p_bone_map->_set_skeleton_bone_name("Head", skeleton->get_bone_name(head));
+ }
+ picklist.clear();
+ search_path.clear();
+
+ int neck_or_head = neck != -1 ? neck : (head != -1 ? head : -1);
+ if (neck_or_head != -1) {
+ // 4-1. Guess Eyes
+ picklist.push_back("eye(?!.*(brow|lash|lid))");
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, neck_or_head);
+ if (bone_idx == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess LeftEye.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("LeftEye", skeleton->get_bone_name(bone_idx));
+ }
+ bone_idx = -1;
+
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, neck_or_head);
+ if (bone_idx == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess RightEye.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("RightEye", skeleton->get_bone_name(bone_idx));
+ }
+ bone_idx = -1;
+ picklist.clear();
+
+ // 4-2. Guess Jaw
+ picklist.push_back("jaw");
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_NONE, neck_or_head);
+ if (bone_idx == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess Jaw.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("Jaw", skeleton->get_bone_name(bone_idx));
+ }
+ bone_idx = -1;
+ picklist.clear();
+ }
+
+ // 5. Guess Foots
+ picklist.push_back("foot");
+ picklist.push_back("ankle");
+ int left_foot = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips);
+ if (left_foot == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess LeftFoot.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("LeftFoot", skeleton->get_bone_name(left_foot));
+ }
+ int right_foot = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, hips);
+ if (right_foot == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess RightFoot.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("RightFoot", skeleton->get_bone_name(right_foot));
+ }
+ picklist.clear();
+
+ // 5-1. Guess LowerLegs
+ picklist.push_back("(low|under).*leg");
+ picklist.push_back("knee");
+ picklist.push_back("shin");
+ picklist.push_back("calf");
+ picklist.push_back("leg");
+ int left_lower_leg = -1;
+ if (left_foot != -1) {
+ left_lower_leg = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips, left_foot);
+ }
+ if (left_lower_leg == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess LeftLowerLeg.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("LeftLowerLeg", skeleton->get_bone_name(left_lower_leg));
+ }
+ int right_lower_leg = -1;
+ if (right_foot != -1) {
+ right_lower_leg = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, hips, right_foot);
+ }
+ if (right_lower_leg == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess RightLowerLeg.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("RightLowerLeg", skeleton->get_bone_name(right_lower_leg));
+ }
+ picklist.clear();
+
+ // 5-2. Guess UpperLegs
+ picklist.push_back("up.*leg");
+ picklist.push_back("thigh");
+ picklist.push_back("leg");
+ if (left_lower_leg != -1) {
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips, left_lower_leg);
+ }
+ if (bone_idx == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess LeftUpperLeg.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("LeftUpperLeg", skeleton->get_bone_name(bone_idx));
+ }
+ bone_idx = -1;
+ if (right_lower_leg != -1) {
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, hips, right_lower_leg);
+ }
+ if (bone_idx == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess RightUpperLeg.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("RightUpperLeg", skeleton->get_bone_name(bone_idx));
+ }
+ bone_idx = -1;
+ picklist.clear();
+
+ // 5-3. Guess Toes
+ picklist.push_back("toe");
+ picklist.push_back("ball");
+ if (left_foot != -1) {
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, left_foot);
+ if (bone_idx == -1) {
+ search_path = skeleton->get_bone_children(left_foot);
+ if (search_path.size() == 1) {
+ bone_idx = search_path[0]; // Maybe only one child of the Foot is Toes.
+ }
+ search_path.clear();
+ }
+ }
+ if (bone_idx == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess LeftToes.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("LeftToes", skeleton->get_bone_name(bone_idx));
+ }
+ bone_idx = -1;
+ if (right_foot != -1) {
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, right_foot);
+ if (bone_idx == -1) {
+ search_path = skeleton->get_bone_children(right_foot);
+ if (search_path.size() == 1) {
+ bone_idx = search_path[0]; // Maybe only one child of the Foot is Toes.
+ }
+ search_path.clear();
+ }
+ }
+ if (bone_idx == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess RightToes.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("RightToes", skeleton->get_bone_name(bone_idx));
+ }
+ bone_idx = -1;
+ picklist.clear();
+
+ // 6. Guess Hands
+ picklist.push_back("hand");
+ picklist.push_back("wrist");
+ picklist.push_back("palm");
+ picklist.push_back("fingers");
+ int left_hand_or_palm = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips, -1, 5);
+ if (left_hand_or_palm == -1) {
+ // Ambiguous, but try again for fewer finger models.
+ left_hand_or_palm = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips);
+ }
+ int left_hand = left_hand_or_palm; // Check for the presence of a wrist, since bones with five children may be palmar.
+ while (left_hand != -1) {
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips, left_hand);
+ if (bone_idx == -1) {
+ break;
+ }
+ left_hand = bone_idx;
+ }
+ if (left_hand == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess LeftHand.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("LeftHand", skeleton->get_bone_name(left_hand));
+ }
+ bone_idx = -1;
+ int right_hand_or_palm = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, hips, -1, 5);
+ if (right_hand_or_palm == -1) {
+ // Ambiguous, but try again for fewer finger models.
+ right_hand_or_palm = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, hips);
+ }
+ int right_hand = right_hand_or_palm;
+ while (right_hand != -1) {
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, hips, right_hand);
+ if (bone_idx == -1) {
+ break;
+ }
+ right_hand = bone_idx;
+ }
+ if (right_hand == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess RightHand.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("RightHand", skeleton->get_bone_name(right_hand));
+ }
+ bone_idx = -1;
+ picklist.clear();
+
+ // 6-1. Guess Finger
+ bool named_finger_is_found = false;
+ LocalVector<String> fingers;
+ fingers.push_back("thumb|pollex");
+ fingers.push_back("index|fore");
+ fingers.push_back("middle");
+ fingers.push_back("ring");
+ fingers.push_back("little|pinkie|pinky");
+ if (left_hand_or_palm != -1) {
+ LocalVector<LocalVector<String>> left_fingers_map;
+ left_fingers_map.resize(5);
+ left_fingers_map[0].push_back("LeftThumbMetacarpal");
+ left_fingers_map[0].push_back("LeftThumbProximal");
+ left_fingers_map[0].push_back("LeftThumbDistal");
+ left_fingers_map[1].push_back("LeftIndexProximal");
+ left_fingers_map[1].push_back("LeftIndexIntermediate");
+ left_fingers_map[1].push_back("LeftIndexDistal");
+ left_fingers_map[2].push_back("LeftMiddleProximal");
+ left_fingers_map[2].push_back("LeftMiddleIntermediate");
+ left_fingers_map[2].push_back("LeftMiddleDistal");
+ left_fingers_map[3].push_back("LeftRingProximal");
+ left_fingers_map[3].push_back("LeftRingIntermediate");
+ left_fingers_map[3].push_back("LeftRingDistal");
+ left_fingers_map[4].push_back("LeftLittleProximal");
+ left_fingers_map[4].push_back("LeftLittleIntermediate");
+ left_fingers_map[4].push_back("LeftLittleDistal");
+ for (int i = 0; i < 5; i++) {
+ picklist.push_back(fingers[i]);
+ int finger = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, left_hand_or_palm, -1, 0);
+ if (finger != -1) {
+ while (finger != left_hand_or_palm && finger >= 0) {
+ search_path.push_back(finger);
+ finger = skeleton->get_bone_parent(finger);
+ }
+ search_path.reverse();
+ if (search_path.size() == 1) {
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ named_finger_is_found = true;
+ } else if (search_path.size() == 2) {
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][1], skeleton->get_bone_name(search_path[1]));
+ named_finger_is_found = true;
+ } else if (search_path.size() >= 3) {
+ search_path = search_path.slice(-3); // Eliminate the possibility of carpal bone.
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][1], skeleton->get_bone_name(search_path[1]));
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][2], skeleton->get_bone_name(search_path[2]));
+ named_finger_is_found = true;
+ }
+ }
+ picklist.clear();
+ search_path.clear();
+ }
+
+ // It is a bit corner case, but possibly the finger names are sequentially numbered...
+ if (!named_finger_is_found) {
+ picklist.push_back("finger");
+ RegEx finger_re = RegEx("finger");
+ search_path = skeleton->get_bone_children(left_hand_or_palm);
+ Vector<String> finger_names;
+ for (int i = 0; i < search_path.size(); i++) {
+ String bn = skeleton->get_bone_name(search_path[i]);
+ if (!finger_re.search(bn.to_lower()).is_null()) {
+ finger_names.push_back(bn);
+ }
+ }
+ finger_names.sort(); // Order by lexicographic, normal use cases never have more than 10 fingers in one hand.
+ search_path.clear();
+ for (int i = 0; i < finger_names.size(); i++) {
+ if (i >= 5) {
+ break;
+ }
+ int finger_root = skeleton->find_bone(finger_names[i]);
+ int finger = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, finger_root, -1, 0);
+ if (finger != -1) {
+ while (finger != finger_root && finger >= 0) {
+ search_path.push_back(finger);
+ finger = skeleton->get_bone_parent(finger);
+ }
+ }
+ search_path.push_back(finger_root);
+ search_path.reverse();
+ if (search_path.size() == 1) {
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ } else if (search_path.size() == 2) {
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][1], skeleton->get_bone_name(search_path[1]));
+ } else if (search_path.size() >= 3) {
+ search_path = search_path.slice(-3); // Eliminate the possibility of carpal bone.
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][1], skeleton->get_bone_name(search_path[1]));
+ p_bone_map->_set_skeleton_bone_name(left_fingers_map[i][2], skeleton->get_bone_name(search_path[2]));
+ }
+ search_path.clear();
+ }
+ picklist.clear();
+ }
+ }
+ named_finger_is_found = false;
+ if (right_hand_or_palm != -1) {
+ LocalVector<LocalVector<String>> right_fingers_map;
+ right_fingers_map.resize(5);
+ right_fingers_map[0].push_back("RightThumbMetacarpal");
+ right_fingers_map[0].push_back("RightThumbProximal");
+ right_fingers_map[0].push_back("RightThumbDistal");
+ right_fingers_map[1].push_back("RightIndexProximal");
+ right_fingers_map[1].push_back("RightIndexIntermediate");
+ right_fingers_map[1].push_back("RightIndexDistal");
+ right_fingers_map[2].push_back("RightMiddleProximal");
+ right_fingers_map[2].push_back("RightMiddleIntermediate");
+ right_fingers_map[2].push_back("RightMiddleDistal");
+ right_fingers_map[3].push_back("RightRingProximal");
+ right_fingers_map[3].push_back("RightRingIntermediate");
+ right_fingers_map[3].push_back("RightRingDistal");
+ right_fingers_map[4].push_back("RightLittleProximal");
+ right_fingers_map[4].push_back("RightLittleIntermediate");
+ right_fingers_map[4].push_back("RightLittleDistal");
+ for (int i = 0; i < 5; i++) {
+ picklist.push_back(fingers[i]);
+ int finger = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, right_hand_or_palm, -1, 0);
+ if (finger != -1) {
+ while (finger != right_hand_or_palm && finger >= 0) {
+ search_path.push_back(finger);
+ finger = skeleton->get_bone_parent(finger);
+ }
+ search_path.reverse();
+ if (search_path.size() == 1) {
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ named_finger_is_found = true;
+ } else if (search_path.size() == 2) {
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][1], skeleton->get_bone_name(search_path[1]));
+ named_finger_is_found = true;
+ } else if (search_path.size() >= 3) {
+ search_path = search_path.slice(-3); // Eliminate the possibility of carpal bone.
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][1], skeleton->get_bone_name(search_path[1]));
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][2], skeleton->get_bone_name(search_path[2]));
+ named_finger_is_found = true;
+ }
+ }
+ picklist.clear();
+ search_path.clear();
+ }
+
+ // It is a bit corner case, but possibly the finger names are sequentially numbered...
+ if (!named_finger_is_found) {
+ picklist.push_back("finger");
+ RegEx finger_re = RegEx("finger");
+ search_path = skeleton->get_bone_children(right_hand_or_palm);
+ Vector<String> finger_names;
+ for (int i = 0; i < search_path.size(); i++) {
+ String bn = skeleton->get_bone_name(search_path[i]);
+ if (!finger_re.search(bn.to_lower()).is_null()) {
+ finger_names.push_back(bn);
+ }
+ }
+ finger_names.sort(); // Order by lexicographic, normal use cases never have more than 10 fingers in one hand.
+ search_path.clear();
+ for (int i = 0; i < finger_names.size(); i++) {
+ if (i >= 5) {
+ break;
+ }
+ int finger_root = skeleton->find_bone(finger_names[i]);
+ int finger = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, finger_root, -1, 0);
+ if (finger != -1) {
+ while (finger != finger_root && finger >= 0) {
+ search_path.push_back(finger);
+ finger = skeleton->get_bone_parent(finger);
+ }
+ }
+ search_path.push_back(finger_root);
+ search_path.reverse();
+ if (search_path.size() == 1) {
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ } else if (search_path.size() == 2) {
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][1], skeleton->get_bone_name(search_path[1]));
+ } else if (search_path.size() >= 3) {
+ search_path = search_path.slice(-3); // Eliminate the possibility of carpal bone.
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][0], skeleton->get_bone_name(search_path[0]));
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][1], skeleton->get_bone_name(search_path[1]));
+ p_bone_map->_set_skeleton_bone_name(right_fingers_map[i][2], skeleton->get_bone_name(search_path[2]));
+ }
+ search_path.clear();
+ }
+ picklist.clear();
+ }
+ }
+
+ // 7. Guess Arms
+ picklist.push_back("shoulder");
+ picklist.push_back("clavicle");
+ picklist.push_back("collar");
+ int left_shoulder = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, hips);
+ if (left_shoulder == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess LeftShoulder.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("LeftShoulder", skeleton->get_bone_name(left_shoulder));
+ }
+ int right_shoulder = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, hips);
+ if (right_shoulder == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess RightShoulder.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("RightShoulder", skeleton->get_bone_name(right_shoulder));
+ }
+ picklist.clear();
+
+ // 7-1. Guess LowerArms
+ picklist.push_back("(low|fore).*arm");
+ picklist.push_back("elbow");
+ picklist.push_back("arm");
+ int left_lower_arm = -1;
+ if (left_shoulder != -1 && left_hand_or_palm != -1) {
+ left_lower_arm = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, left_shoulder, left_hand_or_palm);
+ }
+ if (left_lower_arm == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess LeftLowerArm.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("LeftLowerArm", skeleton->get_bone_name(left_lower_arm));
+ }
+ int right_lower_arm = -1;
+ if (right_shoulder != -1 && right_hand_or_palm != -1) {
+ right_lower_arm = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, right_shoulder, right_hand_or_palm);
+ }
+ if (right_lower_arm == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess RightLowerArm.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("RightLowerArm", skeleton->get_bone_name(right_lower_arm));
+ }
+ picklist.clear();
+
+ // 7-2. Guess UpperArms
+ picklist.push_back("up.*arm");
+ picklist.push_back("arm");
+ if (left_shoulder != -1 && left_lower_arm != -1) {
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_LEFT, left_shoulder, left_lower_arm);
+ }
+ if (bone_idx == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess LeftUpperArm.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("LeftUpperArm", skeleton->get_bone_name(bone_idx));
+ }
+ bone_idx = -1;
+ if (right_shoulder != -1 && right_lower_arm != -1) {
+ bone_idx = search_bone_by_name(skeleton, picklist, BONE_SEGREGATION_RIGHT, right_shoulder, right_lower_arm);
+ }
+ if (bone_idx == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess RightUpperArm.");
+ } else {
+ p_bone_map->_set_skeleton_bone_name("RightUpperArm", skeleton->get_bone_name(bone_idx));
+ }
+ bone_idx = -1;
+ picklist.clear();
+
+ // 8. Guess UpperChest or Chest
+ if (neck_or_head == -1) {
+ return; // Abort.
+ }
+ int chest_or_upper_chest = skeleton->get_bone_parent(neck_or_head);
+ bool is_appropriate = true;
+ if (left_shoulder != -1) {
+ bone_idx = skeleton->get_bone_parent(left_shoulder);
+ bool detect = false;
+ while (bone_idx != hips && bone_idx >= 0) {
+ if (bone_idx == chest_or_upper_chest) {
+ detect = true;
+ break;
+ }
+ bone_idx = skeleton->get_bone_parent(bone_idx);
+ }
+ if (!detect) {
+ is_appropriate = false;
+ }
+ bone_idx = -1;
+ }
+ if (right_shoulder != -1) {
+ bone_idx = skeleton->get_bone_parent(right_shoulder);
+ bool detect = false;
+ while (bone_idx != hips && bone_idx >= 0) {
+ if (bone_idx == chest_or_upper_chest) {
+ detect = true;
+ break;
+ }
+ bone_idx = skeleton->get_bone_parent(bone_idx);
+ }
+ if (!detect) {
+ is_appropriate = false;
+ }
+ bone_idx = -1;
+ }
+ if (!is_appropriate) {
+ if (skeleton->get_bone_parent(left_shoulder) == skeleton->get_bone_parent(right_shoulder)) {
+ chest_or_upper_chest = skeleton->get_bone_parent(left_shoulder);
+ } else {
+ chest_or_upper_chest = -1;
+ }
+ }
+ if (chest_or_upper_chest == -1) {
+ WARN_PRINT("Auto Mapping couldn't guess Chest or UpperChest. Abort auto mapping.");
+ return; // Will be not able to guess Spines.
+ }
+
+ // 9. Guess Spines
+ bone_idx = skeleton->get_bone_parent(chest_or_upper_chest);
+ while (bone_idx != hips && bone_idx >= 0) {
+ search_path.push_back(bone_idx);
+ bone_idx = skeleton->get_bone_parent(bone_idx);
+ }
+ search_path.reverse();
+ if (search_path.size() == 0) {
+ p_bone_map->_set_skeleton_bone_name("Spine", skeleton->get_bone_name(chest_or_upper_chest)); // Maybe chibi model...?
+ } else if (search_path.size() == 1) {
+ p_bone_map->_set_skeleton_bone_name("Spine", skeleton->get_bone_name(search_path[0]));
+ p_bone_map->_set_skeleton_bone_name("Chest", skeleton->get_bone_name(chest_or_upper_chest));
+ } else if (search_path.size() >= 2) {
+ p_bone_map->_set_skeleton_bone_name("Spine", skeleton->get_bone_name(search_path[0]));
+ p_bone_map->_set_skeleton_bone_name("Chest", skeleton->get_bone_name(search_path[search_path.size() - 1])); // Probably UppeChest's parent is appropriate.
+ p_bone_map->_set_skeleton_bone_name("UpperChest", skeleton->get_bone_name(chest_or_upper_chest));
+ }
+ bone_idx = -1;
+ search_path.clear();
+
+ WARN_PRINT("Finish auto mapping.");
+}
+#endif // MODULE_REGEX_ENABLED
+
void BoneMapper::_value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) {
set(p_property, p_value);
recreate_editor();
}
+void BoneMapper::_profile_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) {
+ bone_map->set(p_property, p_value);
+
+ // Run auto mapping when setting SkeletonProfileHumanoid by GUI Editor.
+ Ref<SkeletonProfile> profile = bone_map->get_profile();
+ if (profile.is_valid()) {
+ SkeletonProfileHumanoid *hmn = Object::cast_to<SkeletonProfileHumanoid>(profile.ptr());
+ if (hmn) {
+#ifdef MODULE_REGEX_ENABLED
+ _run_auto_mapping();
+#endif // MODULE_REGEX_ENABLED
+ }
+ }
+}
+
void BoneMapper::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_current_group_idx", "current_group_idx"), &BoneMapper::set_current_group_idx);
ClassDB::bind_method(D_METHOD("get_current_group_idx"), &BoneMapper::get_current_group_idx);
@@ -444,10 +1337,6 @@ void BoneMapEditor::_notification(int p_what) {
create_editors();
} break;
case NOTIFICATION_EXIT_TREE: {
- if (bone_mapper) {
- remove_child(bone_mapper);
- bone_mapper->queue_delete();
- }
skeleton = nullptr;
} break;
}
diff --git a/editor/plugins/bone_map_editor_plugin.h b/editor/plugins/bone_map_editor_plugin.h
index 339547ea10..0541ce6eac 100644
--- a/editor/plugins/bone_map_editor_plugin.h
+++ b/editor/plugins/bone_map_editor_plugin.h
@@ -34,6 +34,12 @@
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/editor_properties.h"
+
+#include "modules/modules_enabled.gen.h" // For regex.
+#ifdef MODULE_REGEX_ENABLED
+#include "modules/regex/regex.h"
+#endif
+
#include "scene/3d/skeleton_3d.h"
#include "scene/gui/color_rect.h"
#include "scene/gui/dialogs.h"
@@ -79,12 +85,13 @@ class BoneMapperItem : public VBoxContainer {
int button_id = -1;
StringName profile_bone_name;
- PackedStringArray skeleton_bone_names;
Ref<BoneMap> bone_map;
- EditorPropertyTextEnum *skeleton_bone_selector;
+ EditorPropertyText *skeleton_bone_selector;
+ Button *picker_button;
void _update_property();
+ void _open_picker();
protected:
void _notification(int p_what);
@@ -95,20 +102,49 @@ protected:
public:
void assign_button_id(int p_button_id);
- BoneMapperItem(Ref<BoneMap> &p_bone_map, PackedStringArray p_skeleton_bone_names, const StringName &p_profile_bone_name = StringName());
+ BoneMapperItem(Ref<BoneMap> &p_bone_map, const StringName &p_profile_bone_name = StringName());
~BoneMapperItem();
};
+class BonePicker : public AcceptDialog {
+ GDCLASS(BonePicker, AcceptDialog);
+
+ Skeleton3D *skeleton = nullptr;
+ Tree *bones = nullptr;
+
+public:
+ void popup_bones_tree(const Size2i &p_minsize = Size2i());
+ bool has_selected_bone();
+ StringName get_selected_bone();
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+ void _confirm();
+
+private:
+ void create_editors();
+ void create_bones_tree(Skeleton3D *p_skeleton);
+
+public:
+ BonePicker(Skeleton3D *p_skeleton);
+ ~BonePicker();
+};
+
class BoneMapper : public VBoxContainer {
GDCLASS(BoneMapper, VBoxContainer);
Skeleton3D *skeleton;
Ref<BoneMap> bone_map;
+ EditorPropertyResource *profile_selector;
+
Vector<BoneMapperItem *> bone_mapper_items;
+ Button *clear_mapping_button;
+
VBoxContainer *mapper_item_vbox;
- HSeparator *separator;
int current_group_idx = 0;
int current_bone_idx = -1;
@@ -126,10 +162,31 @@ class BoneMapper : public VBoxContainer {
void update_group_idx();
void _update_state();
+ /* Bone picker */
+ BonePicker *picker = nullptr;
+ StringName picker_key_name;
+ void _pick_bone(const StringName &p_bone_name);
+ void _apply_picker_selection();
+ void _clear_mapping_current_group();
+
+#ifdef MODULE_REGEX_ENABLED
+ /* For auto mapping */
+ enum BoneSegregation {
+ BONE_SEGREGATION_NONE,
+ BONE_SEGREGATION_LEFT,
+ BONE_SEGREGATION_RIGHT
+ };
+ int search_bone_by_name(Skeleton3D *p_skeleton, Vector<String> p_picklist, BoneSegregation p_segregation = BONE_SEGREGATION_NONE, int p_parent = -1, int p_child = -1, int p_children_count = -1);
+ BoneSegregation guess_bone_segregation(String p_bone_name);
+ void auto_mapping_process(Ref<BoneMap> &p_bone_map);
+ void _run_auto_mapping();
+#endif // MODULE_REGEX_ENABLED
+
protected:
void _notification(int p_what);
static void _bind_methods();
virtual void _value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing);
+ virtual void _profile_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing);
public:
void set_current_group_idx(int p_group_idx);
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 964570e1bd..37c79d4974 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -40,6 +40,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/editor_toaster.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/animation_player_editor_plugin.h"
#include "editor/plugins/script_editor_plugin.h"
#include "editor/scene_tree_dock.h"
@@ -53,6 +54,7 @@
#include "scene/gui/flow_container.h"
#include "scene/gui/grid_container.h"
#include "scene/gui/nine_patch_rect.h"
+#include "scene/gui/separator.h"
#include "scene/gui/subviewport_container.h"
#include "scene/gui/view_panner.h"
#include "scene/main/canvas_layer.h"
@@ -221,8 +223,8 @@ public:
grid_step_x->set_value(p_grid_step.x);
grid_step_y->set_value(p_grid_step.y);
primary_grid_steps->set_value(p_primary_grid_steps);
- rotation_offset->set_value(Math::rad2deg(p_rotation_offset));
- rotation_step->set_value(Math::rad2deg(p_rotation_step));
+ rotation_offset->set_value(Math::rad_to_deg(p_rotation_offset));
+ rotation_step->set_value(Math::rad_to_deg(p_rotation_step));
scale_step->set_value(p_scale_step);
}
@@ -230,8 +232,8 @@ public:
p_grid_offset = Point2(grid_offset_x->get_value(), grid_offset_y->get_value());
p_grid_step = Point2(grid_step_x->get_value(), grid_step_y->get_value());
p_primary_grid_steps = int(primary_grid_steps->get_value());
- p_rotation_offset = Math::deg2rad(rotation_offset->get_value());
- p_rotation_step = Math::deg2rad(rotation_step->get_value());
+ p_rotation_offset = Math::deg_to_rad(rotation_offset->get_value());
+ p_rotation_step = Math::deg_to_rad(rotation_step->get_value());
p_scale_step = scale_step->get_value();
}
};
@@ -1445,7 +1447,7 @@ bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) {
drag_selection,
vformat(TTR("Rotate CanvasItem \"%s\" to %d degrees"),
drag_selection[0]->get_name(),
- Math::rad2deg(drag_selection[0]->_edit_get_rotation())),
+ Math::rad_to_deg(drag_selection[0]->_edit_get_rotation())),
true);
}
@@ -2956,6 +2958,9 @@ void CanvasItemEditor::_draw_ruler_tool() {
Point2 corner = Point2(begin.x, end.y);
Vector2 length_vector = (begin - end).abs() / zoom;
+ const real_t horizontal_angle_rad = length_vector.angle();
+ const real_t vertical_angle_rad = Math_PI / 2.0 - horizontal_angle_rad;
+
Ref<Font> font = get_theme_font(SNAME("bold"), SNAME("EditorFonts"));
int font_size = get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts"));
Color font_color = get_theme_color(SNAME("font_color"), SNAME("Editor"));
@@ -2972,6 +2977,42 @@ void CanvasItemEditor::_draw_ruler_tool() {
text_pos.x = CLAMP(text_pos.x, text_width / 2, viewport->get_rect().size.x - text_width * 1.5);
text_pos.y = CLAMP(text_pos.y, text_height * 1.5, viewport->get_rect().size.y - text_height * 1.5);
+ // Draw lines.
+ viewport->draw_line(begin, end, ruler_primary_color, Math::round(EDSCALE * 3));
+
+ bool draw_secondary_lines = !(Math::is_equal_approx(begin.y, corner.y) || Math::is_equal_approx(end.x, corner.x));
+ if (draw_secondary_lines) {
+ viewport->draw_line(begin, corner, ruler_secondary_color, Math::round(EDSCALE));
+ viewport->draw_line(corner, end, ruler_secondary_color, Math::round(EDSCALE));
+
+ // Angle arcs.
+ int arc_point_count = 8;
+ real_t arc_radius_max_length_percent = 0.1;
+ real_t ruler_length = length_vector.length() * zoom;
+ real_t arc_max_radius = 50.0;
+ real_t arc_line_width = 2.0;
+
+ const Vector2 end_to_begin = (end - begin);
+
+ real_t arc_1_start_angle = end_to_begin.x < 0
+ ? (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 - vertical_angle_rad : Math_PI / 2.0)
+ : (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 : Math_PI / 2.0 - vertical_angle_rad);
+ real_t arc_1_end_angle = arc_1_start_angle + vertical_angle_rad;
+ // Constrain arc to triangle height & max size.
+ real_t arc_1_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.y)), arc_max_radius);
+
+ real_t arc_2_start_angle = end_to_begin.x < 0
+ ? (end_to_begin.y < 0 ? 0.0 : -horizontal_angle_rad)
+ : (end_to_begin.y < 0 ? Math_PI - horizontal_angle_rad : Math_PI);
+ real_t arc_2_end_angle = arc_2_start_angle + horizontal_angle_rad;
+ // Constrain arc to triangle width & max size.
+ real_t arc_2_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.x)), arc_max_radius);
+
+ viewport->draw_arc(begin, arc_1_radius, arc_1_start_angle, arc_1_end_angle, arc_point_count, ruler_primary_color, Math::round(EDSCALE * arc_line_width));
+ viewport->draw_arc(end, arc_2_radius, arc_2_start_angle, arc_2_end_angle, arc_point_count, ruler_primary_color, Math::round(EDSCALE * arc_line_width));
+ }
+
+ // Draw text.
if (begin.is_equal_approx(end)) {
viewport->draw_string_outline(font, text_pos, (String)ruler_tool_origin, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, text_pos, (String)ruler_tool_origin, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color);
@@ -2983,17 +3024,7 @@ void CanvasItemEditor::_draw_ruler_tool() {
viewport->draw_string_outline(font, text_pos, TS->format_number(vformat("%.1f px", length_vector.length())), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, text_pos, TS->format_number(vformat("%.1f px", length_vector.length())), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color);
- bool draw_secondary_lines = !(Math::is_equal_approx(begin.y, corner.y) || Math::is_equal_approx(end.x, corner.x));
-
- viewport->draw_line(begin, end, ruler_primary_color, Math::round(EDSCALE * 3));
- if (draw_secondary_lines) {
- viewport->draw_line(begin, corner, ruler_secondary_color, Math::round(EDSCALE));
- viewport->draw_line(corner, end, ruler_secondary_color, Math::round(EDSCALE));
- }
-
if (draw_secondary_lines) {
- const real_t horizontal_angle_rad = length_vector.angle();
- const real_t vertical_angle_rad = Math_PI / 2.0 - horizontal_angle_rad;
const int horizontal_angle = round(180 * horizontal_angle_rad / Math_PI);
const int vertical_angle = round(180 * vertical_angle_rad / Math_PI);
@@ -3030,32 +3061,6 @@ void CanvasItemEditor::_draw_ruler_tool() {
}
viewport->draw_string_outline(font, h_angle_text_pos, TS->format_number(vformat(String::utf8("%d°"), horizontal_angle)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, outline_size, outline_color);
viewport->draw_string(font, h_angle_text_pos, TS->format_number(vformat(String::utf8("%d°"), horizontal_angle)), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_secondary_color);
-
- // Angle arcs
- int arc_point_count = 8;
- real_t arc_radius_max_length_percent = 0.1;
- real_t ruler_length = length_vector.length() * zoom;
- real_t arc_max_radius = 50.0;
- real_t arc_line_width = 2.0;
-
- const Vector2 end_to_begin = (end - begin);
-
- real_t arc_1_start_angle = end_to_begin.x < 0
- ? (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 - vertical_angle_rad : Math_PI / 2.0)
- : (end_to_begin.y < 0 ? 3.0 * Math_PI / 2.0 : Math_PI / 2.0 - vertical_angle_rad);
- real_t arc_1_end_angle = arc_1_start_angle + vertical_angle_rad;
- // Constrain arc to triangle height & max size
- real_t arc_1_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.y)), arc_max_radius);
-
- real_t arc_2_start_angle = end_to_begin.x < 0
- ? (end_to_begin.y < 0 ? 0.0 : -horizontal_angle_rad)
- : (end_to_begin.y < 0 ? Math_PI - horizontal_angle_rad : Math_PI);
- real_t arc_2_end_angle = arc_2_start_angle + horizontal_angle_rad;
- // Constrain arc to triangle width & max size
- real_t arc_2_radius = MIN(MIN(arc_radius_max_length_percent * ruler_length, ABS(end_to_begin.x)), arc_max_radius);
-
- viewport->draw_arc(begin, arc_1_radius, arc_1_start_angle, arc_1_end_angle, arc_point_count, ruler_primary_color, Math::round(EDSCALE * arc_line_width));
- viewport->draw_arc(end, arc_2_radius, arc_2_start_angle, arc_2_end_angle, arc_point_count, ruler_primary_color, Math::round(EDSCALE * arc_line_width));
}
if (grid_snap_active) {
@@ -3671,7 +3676,7 @@ void CanvasItemEditor::_draw_transform_message() {
} break;
case DRAG_ROTATE: {
- real_t delta = Math::rad2deg(current_transform.get_rotation() - original_transform.get_rotation());
+ real_t delta = Math::rad_to_deg(current_transform.get_rotation() - original_transform.get_rotation());
transform_message = TTR("Rotating:") + " " + FORMAT(delta) + String::utf8(" °");
} break;
@@ -3987,6 +3992,10 @@ void CanvasItemEditor::_selection_changed() {
selected_from_canvas = false;
}
+void CanvasItemEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
+ undo_redo = p_undo_redo;
+}
+
void CanvasItemEditor::edit(CanvasItem *p_canvas_item) {
Array selection = editor_selection->get_selected_nodes();
if (selection.size() != 1 || Object::cast_to<Node>(selection[0]) != p_canvas_item) {
@@ -4236,13 +4245,13 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation,
Control *ctrl = Object::cast_to<Control>(canvas_item);
if (key_pos) {
- te->insert_node_value_key(ctrl, "rect_position", ctrl->get_position(), p_on_existing);
+ te->insert_node_value_key(ctrl, "position", ctrl->get_position(), p_on_existing);
}
if (key_rot) {
- te->insert_node_value_key(ctrl, "rect_rotation", ctrl->get_rotation(), p_on_existing);
+ te->insert_node_value_key(ctrl, "rotation", ctrl->get_rotation(), p_on_existing);
}
if (key_scale) {
- te->insert_node_value_key(ctrl, "rect_size", ctrl->get_size(), p_on_existing);
+ te->insert_node_value_key(ctrl, "size", ctrl->get_size(), p_on_existing);
}
}
}
@@ -4252,11 +4261,11 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation,
void CanvasItemEditor::_update_override_camera_button(bool p_game_running) {
if (p_game_running) {
override_camera_button->set_disabled(false);
- override_camera_button->set_tooltip(TTR("Project Camera Override\nOverrides the running project's camera with the editor viewport camera."));
+ override_camera_button->set_tooltip_text(TTR("Project Camera Override\nOverrides the running project's camera with the editor viewport camera."));
} else {
override_camera_button->set_disabled(true);
override_camera_button->set_pressed(false);
- override_camera_button->set_tooltip(TTR("Project Camera Override\nNo project instance running. Run the project from the editor to use this feature."));
+ override_camera_button->set_tooltip_text(TTR("Project Camera Override\nNo project instance running. Run the project from the editor to use this feature."));
}
}
@@ -5019,17 +5028,36 @@ CanvasItemEditor::CanvasItemEditor() {
controls_vb->set_begin(Point2(5, 5));
// To ensure that scripts can parse the list of shortcuts correctly, we have to define
- // those shortcuts one by one. Define shortcut before using it (by EditorZoomWidget)
- ED_SHORTCUT("canvas_item_editor/zoom_3.125_percent", TTR("Zoom to 3.125%"), KeyModifierMask::SHIFT | Key::KEY_5);
- ED_SHORTCUT("canvas_item_editor/zoom_6.25_percent", TTR("Zoom to 6.25%"), KeyModifierMask::SHIFT | Key::KEY_4);
- ED_SHORTCUT("canvas_item_editor/zoom_12.5_percent", TTR("Zoom to 12.5%"), KeyModifierMask::SHIFT | Key::KEY_3);
- ED_SHORTCUT("canvas_item_editor/zoom_25_percent", TTR("Zoom to 25%"), KeyModifierMask::SHIFT | Key::KEY_2);
- ED_SHORTCUT("canvas_item_editor/zoom_50_percent", TTR("Zoom to 50%"), KeyModifierMask::SHIFT | Key::KEY_1);
- ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_100_percent", TTR("Zoom to 100%"), { (int32_t)Key::KEY_1, (int32_t)(KeyModifierMask::CMD | Key::KEY_0) });
- ED_SHORTCUT("canvas_item_editor/zoom_200_percent", TTR("Zoom to 200%"), Key::KEY_2);
- ED_SHORTCUT("canvas_item_editor/zoom_400_percent", TTR("Zoom to 400%"), Key::KEY_3);
- ED_SHORTCUT("canvas_item_editor/zoom_800_percent", TTR("Zoom to 800%"), Key::KEY_4);
- ED_SHORTCUT("canvas_item_editor/zoom_1600_percent", TTR("Zoom to 1600%"), Key::KEY_5);
+ // those shortcuts one by one. Define shortcut before using it (by EditorZoomWidget).
+ ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_3.125_percent", TTR("Zoom to 3.125%"),
+ { int32_t(KeyModifierMask::SHIFT | Key::KEY_5), int32_t(KeyModifierMask::SHIFT | Key::KP_5) });
+
+ ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_6.25_percent", TTR("Zoom to 6.25%"),
+ { int32_t(KeyModifierMask::SHIFT | Key::KEY_4), int32_t(KeyModifierMask::SHIFT | Key::KP_4) });
+
+ ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_12.5_percent", TTR("Zoom to 12.5%"),
+ { int32_t(KeyModifierMask::SHIFT | Key::KEY_3), int32_t(KeyModifierMask::SHIFT | Key::KP_3) });
+
+ ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_25_percent", TTR("Zoom to 25%"),
+ { int32_t(KeyModifierMask::SHIFT | Key::KEY_2), int32_t(KeyModifierMask::SHIFT | Key::KP_2) });
+
+ ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_50_percent", TTR("Zoom to 50%"),
+ { int32_t(KeyModifierMask::SHIFT | Key::KEY_1), int32_t(KeyModifierMask::SHIFT | Key::KP_1) });
+
+ ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_100_percent", TTR("Zoom to 100%"),
+ { int32_t(Key::KEY_1), int32_t(KeyModifierMask::CMD | Key::KEY_0), int32_t(Key::KP_1), int32_t(KeyModifierMask::CMD | Key::KP_0) });
+
+ ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_200_percent", TTR("Zoom to 200%"),
+ { int32_t(Key::KEY_2), int32_t(Key::KP_2) });
+
+ ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_400_percent", TTR("Zoom to 400%"),
+ { int32_t(Key::KEY_3), int32_t(Key::KP_3) });
+
+ ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_800_percent", TTR("Zoom to 800%"),
+ { int32_t(Key::KEY_4), int32_t(Key::KP_4) });
+
+ ED_SHORTCUT_ARRAY("canvas_item_editor/zoom_1600_percent", TTR("Zoom to 1600%"),
+ { int32_t(Key::KEY_5), int32_t(Key::KP_5) });
zoom_widget = memnew(EditorZoomWidget);
controls_vb->add_child(zoom_widget);
@@ -5076,7 +5104,7 @@ CanvasItemEditor::CanvasItemEditor() {
select_button->set_pressed(true);
select_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/select_mode", TTR("Select Mode"), Key::Q));
select_button->set_shortcut_context(this);
- select_button->set_tooltip(keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Drag: Rotate selected node around pivot.") + "\n" + TTR("Alt+Drag: Move selected node.") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Alt+Drag: Scale selected node.") + "\n" + TTR("V: Set selected node's pivot position.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("RMB: Add node at position clicked."));
+ select_button->set_tooltip_text(keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Drag: Rotate selected node around pivot.") + "\n" + TTR("Alt+Drag: Move selected node.") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Alt+Drag: Scale selected node.") + "\n" + TTR("V: Set selected node's pivot position.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked.") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("RMB: Add node at position clicked."));
main_menu_hbox->add_child(memnew(VSeparator));
@@ -5087,7 +5115,7 @@ CanvasItemEditor::CanvasItemEditor() {
move_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_MOVE));
move_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/move_mode", TTR("Move Mode"), Key::W));
move_button->set_shortcut_context(this);
- move_button->set_tooltip(TTR("Move Mode"));
+ move_button->set_tooltip_text(TTR("Move Mode"));
rotate_button = memnew(Button);
rotate_button->set_flat(true);
@@ -5096,7 +5124,7 @@ CanvasItemEditor::CanvasItemEditor() {
rotate_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_ROTATE));
rotate_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/rotate_mode", TTR("Rotate Mode"), Key::E));
rotate_button->set_shortcut_context(this);
- rotate_button->set_tooltip(TTR("Rotate Mode"));
+ rotate_button->set_tooltip_text(TTR("Rotate Mode"));
scale_button = memnew(Button);
scale_button->set_flat(true);
@@ -5105,7 +5133,7 @@ CanvasItemEditor::CanvasItemEditor() {
scale_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_SCALE));
scale_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/scale_mode", TTR("Scale Mode"), Key::S));
scale_button->set_shortcut_context(this);
- scale_button->set_tooltip(TTR("Shift: Scale proportionally."));
+ scale_button->set_tooltip_text(TTR("Shift: Scale proportionally."));
main_menu_hbox->add_child(memnew(VSeparator));
@@ -5114,14 +5142,14 @@ CanvasItemEditor::CanvasItemEditor() {
main_menu_hbox->add_child(list_select_button);
list_select_button->set_toggle_mode(true);
list_select_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_LIST_SELECT));
- list_select_button->set_tooltip(TTR("Show list of selectable nodes at position clicked."));
+ list_select_button->set_tooltip_text(TTR("Show list of selectable nodes at position clicked."));
pivot_button = memnew(Button);
pivot_button->set_flat(true);
main_menu_hbox->add_child(pivot_button);
pivot_button->set_toggle_mode(true);
pivot_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_EDIT_PIVOT));
- pivot_button->set_tooltip(TTR("Click to change object's rotation pivot."));
+ pivot_button->set_tooltip_text(TTR("Click to change object's rotation pivot."));
pan_button = memnew(Button);
pan_button->set_flat(true);
@@ -5130,7 +5158,7 @@ CanvasItemEditor::CanvasItemEditor() {
pan_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_PAN));
pan_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/pan_mode", TTR("Pan Mode"), Key::G));
pan_button->set_shortcut_context(this);
- pan_button->set_tooltip(TTR("You can also use Pan View shortcut (Space by default) to pan in any mode."));
+ pan_button->set_tooltip_text(TTR("You can also use Pan View shortcut (Space by default) to pan in any mode."));
ruler_button = memnew(Button);
ruler_button->set_flat(true);
@@ -5139,7 +5167,7 @@ CanvasItemEditor::CanvasItemEditor() {
ruler_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_button_tool_select).bind(TOOL_RULER));
ruler_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/ruler_mode", TTR("Ruler Mode"), Key::R));
ruler_button->set_shortcut_context(this);
- ruler_button->set_tooltip(TTR("Ruler Mode"));
+ ruler_button->set_tooltip_text(TTR("Ruler Mode"));
main_menu_hbox->add_child(memnew(VSeparator));
@@ -5148,7 +5176,7 @@ CanvasItemEditor::CanvasItemEditor() {
main_menu_hbox->add_child(smart_snap_button);
smart_snap_button->set_toggle_mode(true);
smart_snap_button->connect("toggled", callable_mp(this, &CanvasItemEditor::_button_toggle_smart_snap));
- smart_snap_button->set_tooltip(TTR("Toggle smart snapping."));
+ smart_snap_button->set_tooltip_text(TTR("Toggle smart snapping."));
smart_snap_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/use_smart_snap", TTR("Use Smart Snap"), KeyModifierMask::SHIFT | Key::S));
smart_snap_button->set_shortcut_context(this);
@@ -5157,7 +5185,7 @@ CanvasItemEditor::CanvasItemEditor() {
main_menu_hbox->add_child(grid_snap_button);
grid_snap_button->set_toggle_mode(true);
grid_snap_button->connect("toggled", callable_mp(this, &CanvasItemEditor::_button_toggle_grid_snap));
- grid_snap_button->set_tooltip(TTR("Toggle grid snapping."));
+ grid_snap_button->set_tooltip_text(TTR("Toggle grid snapping."));
grid_snap_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/use_grid_snap", TTR("Use Grid Snap"), KeyModifierMask::SHIFT | Key::G));
grid_snap_button->set_shortcut_context(this);
@@ -5165,7 +5193,7 @@ CanvasItemEditor::CanvasItemEditor() {
snap_config_menu->set_shortcut_context(this);
main_menu_hbox->add_child(snap_config_menu);
snap_config_menu->set_h_size_flags(SIZE_SHRINK_END);
- snap_config_menu->set_tooltip(TTR("Snapping Options"));
+ snap_config_menu->set_tooltip_text(TTR("Snapping Options"));
snap_config_menu->set_switch_on_hover(true);
PopupMenu *p = snap_config_menu->get_popup();
@@ -5199,7 +5227,7 @@ CanvasItemEditor::CanvasItemEditor() {
main_menu_hbox->add_child(lock_button);
lock_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(LOCK_SELECTED));
- lock_button->set_tooltip(TTR("Lock selected node, preventing selection and movement."));
+ lock_button->set_tooltip_text(TTR("Lock selected node, preventing selection and movement."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
lock_button->set_shortcut(ED_SHORTCUT("editor/lock_selected_nodes", TTR("Lock Selected Node(s)"), KeyModifierMask::CMD | Key::L));
@@ -5207,7 +5235,7 @@ CanvasItemEditor::CanvasItemEditor() {
unlock_button->set_flat(true);
main_menu_hbox->add_child(unlock_button);
unlock_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(UNLOCK_SELECTED));
- unlock_button->set_tooltip(TTR("Unlock selected node, allowing selection and movement."));
+ unlock_button->set_tooltip_text(TTR("Unlock selected node, allowing selection and movement."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
unlock_button->set_shortcut(ED_SHORTCUT("editor/unlock_selected_nodes", TTR("Unlock Selected Node(s)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::L));
@@ -5215,7 +5243,7 @@ CanvasItemEditor::CanvasItemEditor() {
group_button->set_flat(true);
main_menu_hbox->add_child(group_button);
group_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(GROUP_SELECTED));
- group_button->set_tooltip(TTR("Makes sure the object's children are not selectable."));
+ group_button->set_tooltip_text(TTR("Make selected node's children not selectable."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
group_button->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KeyModifierMask::CMD | Key::G));
@@ -5223,7 +5251,7 @@ CanvasItemEditor::CanvasItemEditor() {
ungroup_button->set_flat(true);
main_menu_hbox->add_child(ungroup_button);
ungroup_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(UNGROUP_SELECTED));
- ungroup_button->set_tooltip(TTR("Restores the object's children's ability to be selected."));
+ ungroup_button->set_tooltip_text(TTR("Make selected node's children selectable."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
ungroup_button->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::G));
@@ -5232,7 +5260,7 @@ CanvasItemEditor::CanvasItemEditor() {
skeleton_menu = memnew(MenuButton);
skeleton_menu->set_shortcut_context(this);
main_menu_hbox->add_child(skeleton_menu);
- skeleton_menu->set_tooltip(TTR("Skeleton Options"));
+ skeleton_menu->set_tooltip_text(TTR("Skeleton Options"));
skeleton_menu->set_switch_on_hover(true);
p = skeleton_menu->get_popup();
@@ -5312,7 +5340,7 @@ CanvasItemEditor::CanvasItemEditor() {
key_loc_button->set_pressed(true);
key_loc_button->set_focus_mode(FOCUS_NONE);
key_loc_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(ANIM_INSERT_POS));
- key_loc_button->set_tooltip(TTR("Translation mask for inserting keys."));
+ key_loc_button->set_tooltip_text(TTR("Translation mask for inserting keys."));
animation_hb->add_child(key_loc_button);
key_rot_button = memnew(Button);
@@ -5321,7 +5349,7 @@ CanvasItemEditor::CanvasItemEditor() {
key_rot_button->set_pressed(true);
key_rot_button->set_focus_mode(FOCUS_NONE);
key_rot_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(ANIM_INSERT_ROT));
- key_rot_button->set_tooltip(TTR("Rotation mask for inserting keys."));
+ key_rot_button->set_tooltip_text(TTR("Rotation mask for inserting keys."));
animation_hb->add_child(key_rot_button);
key_scale_button = memnew(Button);
@@ -5329,14 +5357,14 @@ CanvasItemEditor::CanvasItemEditor() {
key_scale_button->set_toggle_mode(true);
key_scale_button->set_focus_mode(FOCUS_NONE);
key_scale_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(ANIM_INSERT_SCALE));
- key_scale_button->set_tooltip(TTR("Scale mask for inserting keys."));
+ key_scale_button->set_tooltip_text(TTR("Scale mask for inserting keys."));
animation_hb->add_child(key_scale_button);
key_insert_button = memnew(Button);
key_insert_button->set_flat(true);
key_insert_button->set_focus_mode(FOCUS_NONE);
key_insert_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback).bind(ANIM_INSERT_KEY));
- key_insert_button->set_tooltip(TTR("Insert keys (based on mask)."));
+ key_insert_button->set_tooltip_text(TTR("Insert keys (based on mask)."));
key_insert_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/anim_insert_key", TTR("Insert Key"), Key::INSERT));
key_insert_button->set_shortcut_context(this);
animation_hb->add_child(key_insert_button);
@@ -5345,14 +5373,14 @@ CanvasItemEditor::CanvasItemEditor() {
key_auto_insert_button->set_flat(true);
key_auto_insert_button->set_toggle_mode(true);
key_auto_insert_button->set_focus_mode(FOCUS_NONE);
- key_auto_insert_button->set_tooltip(TTR("Auto insert keys when objects are translated, rotated or scaled (based on mask).\nKeys are only added to existing tracks, no new tracks will be created.\nKeys must be inserted manually for the first time."));
+ key_auto_insert_button->set_tooltip_text(TTR("Auto insert keys when objects are translated, rotated or scaled (based on mask).\nKeys are only added to existing tracks, no new tracks will be created.\nKeys must be inserted manually for the first time."));
key_auto_insert_button->set_shortcut(ED_SHORTCUT("canvas_item_editor/anim_auto_insert_key", TTR("Auto Insert Key")));
key_auto_insert_button->set_shortcut_context(this);
animation_hb->add_child(key_auto_insert_button);
animation_menu = memnew(MenuButton);
animation_menu->set_shortcut_context(this);
- animation_menu->set_tooltip(TTR("Animation Key and Pose Options"));
+ animation_menu->set_tooltip_text(TTR("Animation Key and Pose Options"));
animation_hb->add_child(animation_menu);
animation_menu->get_popup()->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback));
animation_menu->set_switch_on_hover(true);
@@ -5399,7 +5427,7 @@ CanvasItemEditor::CanvasItemEditor() {
CanvasItemEditor *CanvasItemEditor::singleton = nullptr;
void CanvasItemEditorPlugin::edit(Object *p_object) {
- canvas_item_editor->set_undo_redo(&get_undo_redo());
+ canvas_item_editor->set_undo_redo(EditorNode::get_undo_redo());
canvas_item_editor->edit(Object::cast_to<CanvasItem>(p_object));
}
@@ -5535,51 +5563,39 @@ bool CanvasItemEditorViewport::_cyclical_dependency_exists(const String &p_targe
void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &path, const Point2 &p_point) {
// Adjust casing according to project setting. The file name is expected to be in snake_case, but will work for others.
String name = path.get_file().get_basename();
- switch (ProjectSettings::get_singleton()->get("editor/node_naming/name_casing").operator int()) {
- case NAME_CASING_PASCAL_CASE:
- name = name.capitalize().replace(" ", "");
- break;
- case NAME_CASING_CAMEL_CASE:
- name = name.capitalize().replace(" ", "");
- name[0] = name.to_lower()[0];
- break;
- case NAME_CASING_SNAKE_CASE:
- name = name.capitalize().replace(" ", "_").to_lower();
- break;
- }
- child->set_name(name);
+ child->set_name(Node::adjust_name_casing(name));
Ref<Texture2D> texture = ResourceCache::get_ref(path);
if (parent) {
- editor_data->get_undo_redo().add_do_method(parent, "add_child", child, true);
- editor_data->get_undo_redo().add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
- editor_data->get_undo_redo().add_do_reference(child);
- editor_data->get_undo_redo().add_undo_method(parent, "remove_child", child);
+ editor_data->get_undo_redo()->add_do_method(parent, "add_child", child, true);
+ editor_data->get_undo_redo()->add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
+ editor_data->get_undo_redo()->add_do_reference(child);
+ editor_data->get_undo_redo()->add_undo_method(parent, "remove_child", child);
} else { // If no parent is selected, set as root node of the scene.
- editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "set_edited_scene", child);
- editor_data->get_undo_redo().add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
- editor_data->get_undo_redo().add_do_reference(child);
- editor_data->get_undo_redo().add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
+ editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "set_edited_scene", child);
+ editor_data->get_undo_redo()->add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
+ editor_data->get_undo_redo()->add_do_reference(child);
+ editor_data->get_undo_redo()->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
}
if (parent) {
String new_name = parent->validate_child_name(child);
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
- editor_data->get_undo_redo().add_do_method(ed, "live_debug_create_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent), child->get_class(), new_name);
- editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent)) + "/" + new_name));
+ editor_data->get_undo_redo()->add_do_method(ed, "live_debug_create_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent), child->get_class(), new_name);
+ editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent)) + "/" + new_name));
}
if (Object::cast_to<TouchScreenButton>(child) || Object::cast_to<TextureButton>(child)) {
- editor_data->get_undo_redo().add_do_property(child, "texture_normal", texture);
+ editor_data->get_undo_redo()->add_do_property(child, "texture_normal", texture);
} else {
- editor_data->get_undo_redo().add_do_property(child, "texture", texture);
+ editor_data->get_undo_redo()->add_do_property(child, "texture", texture);
}
// make visible for certain node type
if (Object::cast_to<Control>(child)) {
Size2 texture_size = texture->get_size();
- editor_data->get_undo_redo().add_do_property(child, "rect_size", texture_size);
+ editor_data->get_undo_redo()->add_do_property(child, "rect_size", texture_size);
} else if (Object::cast_to<Polygon2D>(child)) {
Size2 texture_size = texture->get_size();
Vector<Vector2> list = {
@@ -5588,7 +5604,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &
Vector2(texture_size.width, texture_size.height),
Vector2(0, texture_size.height)
};
- editor_data->get_undo_redo().add_do_property(child, "polygon", list);
+ editor_data->get_undo_redo()->add_do_property(child, "polygon", list);
}
// Compute the global position
@@ -5597,7 +5613,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &
// there's nothing to be used as source position so snapping will work as absolute if enabled
target_position = canvas_item_editor->snap_point(target_position);
- editor_data->get_undo_redo().add_do_method(child, "set_global_position", target_position);
+ editor_data->get_undo_redo()->add_do_method(child, "set_global_position", target_position);
}
bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, const Point2 &p_point) {
@@ -5622,15 +5638,15 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons
instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(path));
- editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene, true);
- editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_owner", edited_scene);
- editor_data->get_undo_redo().add_do_reference(instantiated_scene);
- editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instantiated_scene);
+ editor_data->get_undo_redo()->add_do_method(parent, "add_child", instantiated_scene, true);
+ editor_data->get_undo_redo()->add_do_method(instantiated_scene, "set_owner", edited_scene);
+ editor_data->get_undo_redo()->add_do_reference(instantiated_scene);
+ editor_data->get_undo_redo()->add_undo_method(parent, "remove_child", instantiated_scene);
String new_name = parent->validate_child_name(instantiated_scene);
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
- editor_data->get_undo_redo().add_do_method(ed, "live_debug_instance_node", edited_scene->get_path_to(parent), path, new_name);
- editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)) + "/" + new_name));
+ editor_data->get_undo_redo()->add_do_method(ed, "live_debug_instance_node", edited_scene->get_path_to(parent), path, new_name);
+ editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)) + "/" + new_name));
CanvasItem *instance_ci = Object::cast_to<CanvasItem>(instantiated_scene);
if (instance_ci) {
@@ -5644,7 +5660,7 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons
// Preserve instance position of the original scene.
target_pos += instance_ci->_edit_get_position();
- editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_position", target_pos);
+ editor_data->get_undo_redo()->add_do_method(instantiated_scene, "set_position", target_pos);
}
return true;
@@ -5662,7 +5678,7 @@ void CanvasItemEditorViewport::_perform_drop_data() {
Vector<String> error_files;
- editor_data->get_undo_redo().create_action(TTR("Create Node"));
+ editor_data->get_undo_redo()->create_action(TTR("Create Node"));
for (int i = 0; i < selected_files.size(); i++) {
String path = selected_files[i];
@@ -5693,7 +5709,7 @@ void CanvasItemEditorViewport::_perform_drop_data() {
}
}
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->commit_action();
if (error_files.size() > 0) {
String files_str;
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 04fd819dec..0a840d6fd6 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -45,6 +45,7 @@
class EditorData;
class CanvasItemEditorViewport;
class ViewPanner;
+class EditorUndoRedoManager;
class CanvasItemEditorSelectedItem : public Object {
GDCLASS(CanvasItemEditorSelectedItem, Object);
@@ -214,7 +215,7 @@ private:
int primary_grid_steps = 8;
int grid_step_multiplier = 0;
- real_t snap_rotation_step = Math::deg2rad(15.0);
+ real_t snap_rotation_step = Math::deg_to_rad(15.0);
real_t snap_rotation_offset = 0.0;
real_t snap_scale_step = 0.1f;
bool smart_snap_active = false;
@@ -400,7 +401,7 @@ private:
void _prepare_grid_menu();
void _on_grid_menu_id_pressed(int p_id);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
List<CanvasItem *> _get_edited_canvas_items(bool retrieve_locked = false, bool remove_canvas_item_if_parent_in_selection = true);
Rect2 _get_encompassing_rect_from_list(List<CanvasItem *> p_list);
@@ -547,7 +548,7 @@ public:
Tool get_current_tool() { return tool; }
void set_current_tool(Tool p_tool);
- void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; }
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void edit(CanvasItem *p_canvas_item);
void focus_selection();
diff --git a/editor/plugins/ray_cast_2d_editor_plugin.cpp b/editor/plugins/cast_2d_editor_plugin.cpp
index 6f247a37ef..a8d255f997 100644
--- a/editor/plugins/ray_cast_2d_editor_plugin.cpp
+++ b/editor/plugins/cast_2d_editor_plugin.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* ray_cast_2d_editor_plugin.cpp */
+/* cast_2d_editor_plugin.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,30 +28,33 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "ray_cast_2d_editor_plugin.h"
+#include "cast_2d_editor_plugin.h"
#include "canvas_item_editor_plugin.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
+#include "scene/2d/ray_cast_2d.h"
+#include "scene/2d/shape_cast_2d.h"
-void RayCast2DEditor::_notification(int p_what) {
+void Cast2DEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- get_tree()->connect("node_removed", callable_mp(this, &RayCast2DEditor::_node_removed));
+ get_tree()->connect("node_removed", callable_mp(this, &Cast2DEditor::_node_removed));
} break;
case NOTIFICATION_EXIT_TREE: {
- get_tree()->disconnect("node_removed", callable_mp(this, &RayCast2DEditor::_node_removed));
+ get_tree()->disconnect("node_removed", callable_mp(this, &Cast2DEditor::_node_removed));
} break;
}
}
-void RayCast2DEditor::_node_removed(Node *p_node) {
+void Cast2DEditor::_node_removed(Node *p_node) {
if (p_node == node) {
node = nullptr;
}
}
-bool RayCast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
+bool Cast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
if (!node || !node->is_visible_in_tree()) {
return false;
}
@@ -60,10 +63,12 @@ bool RayCast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) {
+ Vector2 target_position = node->get("target_position");
+
if (mb->is_pressed()) {
- if (xform.xform(node->get_target_position()).distance_to(mb->get_position()) < 8) {
+ if (xform.xform(target_position).distance_to(mb->get_position()) < 8) {
pressed = true;
- original_target_position = node->get_target_position();
+ original_target_position = target_position;
return true;
} else {
@@ -73,9 +78,9 @@ bool RayCast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
}
} else if (pressed) {
undo_redo->create_action(TTR("Set target_position"));
- undo_redo->add_do_method(node, "set_target_position", node->get_target_position());
+ undo_redo->add_do_property(node, "target_position", target_position);
undo_redo->add_do_method(canvas_item_editor, "update_viewport");
- undo_redo->add_undo_method(node, "set_target_position", original_target_position);
+ undo_redo->add_undo_property(node, "target_position", original_target_position);
undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
@@ -90,7 +95,7 @@ bool RayCast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
Vector2 point = canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mm->get_position()));
point = node->get_global_transform().affine_inverse().xform(point);
- node->set_target_position(point);
+ node->set("target_position", point);
canvas_item_editor->update_viewport();
node->notify_property_list_changed();
@@ -100,7 +105,7 @@ bool RayCast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
return false;
}
-void RayCast2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
+void Cast2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
if (!node || !node->is_visible_in_tree()) {
return;
}
@@ -108,16 +113,16 @@ void RayCast2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
Transform2D gt = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
const Ref<Texture2D> handle = get_theme_icon(SNAME("EditorHandle"), SNAME("EditorIcons"));
- p_overlay->draw_texture(handle, gt.xform(node->get_target_position()) - handle->get_size() / 2);
+ p_overlay->draw_texture(handle, gt.xform((Vector2)node->get("target_position")) - handle->get_size() / 2);
}
-void RayCast2DEditor::edit(Node *p_node) {
+void Cast2DEditor::edit(Node2D *p_node) {
if (!canvas_item_editor) {
canvas_item_editor = CanvasItemEditor::get_singleton();
}
- if (p_node) {
- node = Object::cast_to<RayCast2D>(p_node);
+ if (Object::cast_to<RayCast2D>(p_node) || Object::cast_to<ShapeCast2D>(p_node)) {
+ node = p_node;
} else {
node = nullptr;
}
@@ -125,27 +130,27 @@ void RayCast2DEditor::edit(Node *p_node) {
canvas_item_editor->update_viewport();
}
-RayCast2DEditor::RayCast2DEditor() {
+Cast2DEditor::Cast2DEditor() {
undo_redo = EditorNode::get_singleton()->get_undo_redo();
}
///////////////////////
-void RayCast2DEditorPlugin::edit(Object *p_object) {
- ray_cast_2d_editor->edit(Object::cast_to<RayCast2D>(p_object));
+void Cast2DEditorPlugin::edit(Object *p_object) {
+ cast_2d_editor->edit(Object::cast_to<Node2D>(p_object));
}
-bool RayCast2DEditorPlugin::handles(Object *p_object) const {
- return Object::cast_to<RayCast2D>(p_object) != nullptr;
+bool Cast2DEditorPlugin::handles(Object *p_object) const {
+ return Object::cast_to<RayCast2D>(p_object) != nullptr || Object::cast_to<ShapeCast2D>(p_object) != nullptr;
}
-void RayCast2DEditorPlugin::make_visible(bool p_visible) {
+void Cast2DEditorPlugin::make_visible(bool p_visible) {
if (!p_visible) {
edit(nullptr);
}
}
-RayCast2DEditorPlugin::RayCast2DEditorPlugin() {
- ray_cast_2d_editor = memnew(RayCast2DEditor);
- EditorNode::get_singleton()->get_gui_base()->add_child(ray_cast_2d_editor);
+Cast2DEditorPlugin::Cast2DEditorPlugin() {
+ cast_2d_editor = memnew(Cast2DEditor);
+ EditorNode::get_singleton()->get_gui_base()->add_child(cast_2d_editor);
}
diff --git a/editor/plugins/ray_cast_2d_editor_plugin.h b/editor/plugins/cast_2d_editor_plugin.h
index 74628da0e4..85ff497bc7 100644
--- a/editor/plugins/ray_cast_2d_editor_plugin.h
+++ b/editor/plugins/cast_2d_editor_plugin.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* ray_cast_2d_editor_plugin.h */
+/* cast_2d_editor_plugin.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,20 +28,21 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef RAY_CAST_2D_EDITOR_PLUGIN_H
-#define RAY_CAST_2D_EDITOR_PLUGIN_H
+#ifndef CAST_2D_EDITOR_PLUGIN_H
+#define CAST_2D_EDITOR_PLUGIN_H
#include "editor/editor_plugin.h"
-#include "scene/2d/ray_cast_2d.h"
+#include "scene/2d/node_2d.h"
class CanvasItemEditor;
+class EditorUndoRedoManager;
-class RayCast2DEditor : public Control {
- GDCLASS(RayCast2DEditor, Control);
+class Cast2DEditor : public Control {
+ GDCLASS(Cast2DEditor, Control);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
CanvasItemEditor *canvas_item_editor = nullptr;
- RayCast2D *node;
+ Node2D *node;
bool pressed = false;
Point2 original_target_position;
@@ -53,27 +54,27 @@ protected:
public:
bool forward_canvas_gui_input(const Ref<InputEvent> &p_event);
void forward_canvas_draw_over_viewport(Control *p_overlay);
- void edit(Node *p_node);
+ void edit(Node2D *p_node);
- RayCast2DEditor();
+ Cast2DEditor();
};
-class RayCast2DEditorPlugin : public EditorPlugin {
- GDCLASS(RayCast2DEditorPlugin, EditorPlugin);
+class Cast2DEditorPlugin : public EditorPlugin {
+ GDCLASS(Cast2DEditorPlugin, EditorPlugin);
- RayCast2DEditor *ray_cast_2d_editor = nullptr;
+ Cast2DEditor *cast_2d_editor = nullptr;
public:
- virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return ray_cast_2d_editor->forward_canvas_gui_input(p_event); }
- virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override { ray_cast_2d_editor->forward_canvas_draw_over_viewport(p_overlay); }
+ virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) override { return cast_2d_editor->forward_canvas_gui_input(p_event); }
+ virtual void forward_canvas_draw_over_viewport(Control *p_overlay) override { cast_2d_editor->forward_canvas_draw_over_viewport(p_overlay); }
- virtual String get_name() const override { return "RayCast2D"; }
+ virtual String get_name() const override { return "Cast2D"; }
bool has_main_screen() const override { return false; }
virtual void edit(Object *p_object) override;
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool visible) override;
- RayCast2DEditorPlugin();
+ Cast2DEditorPlugin();
};
-#endif // RAY_CAST_2D_EDITOR_PLUGIN_H
+#endif // CAST_2D_EDITOR_PLUGIN_H
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp
index af20064a8d..11992ad10e 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp
@@ -33,6 +33,7 @@
#include "canvas_item_editor_plugin.h"
#include "core/os/keyboard.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/resources/capsule_shape_2d.h"
#include "scene/resources/circle_shape_2d.h"
#include "scene/resources/concave_polygon_shape_2d.h"
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.h b/editor/plugins/collision_shape_2d_editor_plugin.h
index f7de05ddd1..49e0820ae9 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.h
+++ b/editor/plugins/collision_shape_2d_editor_plugin.h
@@ -35,6 +35,7 @@
#include "scene/2d/collision_shape_2d.h"
class CanvasItemEditor;
+class EditorUndoRedoManager;
class CollisionShape2DEditor : public Control {
GDCLASS(CollisionShape2DEditor, Control);
@@ -61,7 +62,7 @@ class CollisionShape2DEditor : public Control {
Point2(1, -1),
};
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
CanvasItemEditor *canvas_item_editor = nullptr;
CollisionShape2D *node = nullptr;
diff --git a/editor/plugins/control_editor_plugin.cpp b/editor/plugins/control_editor_plugin.cpp
index 2756e45cf4..bb6092755e 100644
--- a/editor/plugins/control_editor_plugin.cpp
+++ b/editor/plugins/control_editor_plugin.cpp
@@ -31,10 +31,14 @@
#include "control_editor_plugin.h"
#include "editor/editor_node.h"
+#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "scene/gui/separator.h"
+// Inspector controls.
+
void ControlPositioningWarning::_update_warning() {
if (!control_node) {
title_icon->set_texture(nullptr);
@@ -49,7 +53,7 @@ void ControlPositioningWarning::_update_warning() {
title_label->set_text(TTR("This node doesn't have a control parent."));
hint_label->set_text(TTR("Use the appropriate layout properties depending on where you are going to put it."));
} else if (Object::cast_to<Container>(parent_node)) {
- title_icon->set_texture(get_theme_icon(SNAME("Container"), SNAME("EditorIcons")));
+ title_icon->set_texture(get_theme_icon(SNAME("ContainerLayout"), SNAME("EditorIcons")));
title_label->set_text(TTR("This node is a child of a container."));
hint_label->set_text(TTR("Use container properties for positioning."));
} else {
@@ -65,14 +69,14 @@ void ControlPositioningWarning::_update_toggler() {
Ref<Texture2D> arrow;
if (hint_label->is_visible()) {
arrow = get_theme_icon(SNAME("arrow"), SNAME("Tree"));
- set_tooltip(TTR("Collapse positioning hint."));
+ set_tooltip_text(TTR("Collapse positioning hint."));
} else {
if (is_layout_rtl()) {
arrow = get_theme_icon(SNAME("arrow_collapsed"), SNAME("Tree"));
} else {
arrow = get_theme_icon(SNAME("arrow_collapsed_mirrored"), SNAME("Tree"));
}
- set_tooltip(TTR("Expand positioning hint."));
+ set_tooltip_text(TTR("Expand positioning hint."));
}
hint_icon->set_texture(arrow);
@@ -448,37 +452,280 @@ bool EditorInspectorPluginControl::parse_property(Object *p_object, const Varian
return false;
}
-void ControlEditorToolbar::_set_anchors_and_offsets_preset(Control::LayoutPreset p_preset) {
+// Toolbars controls.
+
+Size2 ControlEditorPopupButton::get_minimum_size() const {
+ Vector2 base_size = Vector2(26, 26) * EDSCALE;
+
+ if (arrow_icon.is_null()) {
+ return base_size;
+ }
+
+ Vector2 final_size;
+ final_size.x = base_size.x + arrow_icon->get_width();
+ final_size.y = MAX(base_size.y, arrow_icon->get_height());
+
+ return final_size;
+}
+
+void ControlEditorPopupButton::toggled(bool p_pressed) {
+ if (!p_pressed) {
+ return;
+ }
+
+ Size2 size = get_size() * get_viewport()->get_canvas_transform().get_scale();
+
+ popup_panel->set_size(Size2(size.width, 0));
+ Point2 gp = get_screen_position();
+ gp.y += size.y;
+ if (is_layout_rtl()) {
+ gp.x += size.width - popup_panel->get_size().width;
+ }
+ popup_panel->set_position(gp);
+
+ popup_panel->popup();
+}
+
+void ControlEditorPopupButton::_popup_visibility_changed(bool p_visible) {
+ set_pressed(p_visible);
+}
+
+void ControlEditorPopupButton::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ arrow_icon = get_theme_icon("select_arrow", "Tree");
+ } break;
+
+ case NOTIFICATION_DRAW: {
+ if (arrow_icon.is_valid()) {
+ Vector2 arrow_pos = Point2(26, 0) * EDSCALE;
+ arrow_pos.y = get_size().y / 2 - arrow_icon->get_height() / 2;
+ draw_texture(arrow_icon, arrow_pos);
+ }
+ } break;
+
+ case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
+ popup_panel->set_layout_direction((Window::LayoutDirection)get_layout_direction());
+ } break;
+
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ if (!is_visible_in_tree()) {
+ popup_panel->hide();
+ }
+ } break;
+ }
+}
+
+ControlEditorPopupButton::ControlEditorPopupButton() {
+ set_flat(true);
+ set_toggle_mode(true);
+ set_focus_mode(FOCUS_NONE);
+
+ popup_panel = memnew(PopupPanel);
+ popup_panel->set_theme_type_variation("ControlEditorPopupPanel");
+ add_child(popup_panel);
+ popup_panel->connect("about_to_popup", callable_mp(this, &ControlEditorPopupButton::_popup_visibility_changed).bind(true));
+ popup_panel->connect("popup_hide", callable_mp(this, &ControlEditorPopupButton::_popup_visibility_changed).bind(false));
+
+ popup_vbox = memnew(VBoxContainer);
+ popup_panel->add_child(popup_vbox);
+}
+
+void ControlEditorPresetPicker::_add_row_button(HBoxContainer *p_row, const int p_preset, const String &p_name) {
+ ERR_FAIL_COND(preset_buttons.has(p_preset));
+
+ Button *b = memnew(Button);
+ b->set_custom_minimum_size(Size2i(36, 36) * EDSCALE);
+ b->set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER);
+ b->set_tooltip_text(p_name);
+ b->set_flat(true);
+ p_row->add_child(b);
+ b->connect("pressed", callable_mp(this, &ControlEditorPresetPicker::_preset_button_pressed).bind(p_preset));
+
+ preset_buttons[p_preset] = b;
+}
+
+void ControlEditorPresetPicker::_add_separator(BoxContainer *p_box, Separator *p_separator) {
+ p_separator->add_theme_constant_override("separation", grid_separation);
+ p_separator->set_custom_minimum_size(Size2i(1, 1));
+ p_box->add_child(p_separator);
+}
+
+void AnchorPresetPicker::_preset_button_pressed(const int p_preset) {
+ emit_signal("anchors_preset_selected", p_preset);
+}
+
+void AnchorPresetPicker::_notification(int p_notification) {
+ switch (p_notification) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ preset_buttons[PRESET_TOP_LEFT]->set_icon(get_theme_icon(SNAME("ControlAlignTopLeft"), SNAME("EditorIcons")));
+ preset_buttons[PRESET_CENTER_TOP]->set_icon(get_theme_icon(SNAME("ControlAlignCenterTop"), SNAME("EditorIcons")));
+ preset_buttons[PRESET_TOP_RIGHT]->set_icon(get_theme_icon(SNAME("ControlAlignTopRight"), SNAME("EditorIcons")));
+
+ preset_buttons[PRESET_CENTER_LEFT]->set_icon(get_theme_icon(SNAME("ControlAlignCenterLeft"), SNAME("EditorIcons")));
+ preset_buttons[PRESET_CENTER]->set_icon(get_theme_icon(SNAME("ControlAlignCenter"), SNAME("EditorIcons")));
+ preset_buttons[PRESET_CENTER_RIGHT]->set_icon(get_theme_icon(SNAME("ControlAlignCenterRight"), SNAME("EditorIcons")));
+
+ preset_buttons[PRESET_BOTTOM_LEFT]->set_icon(get_theme_icon(SNAME("ControlAlignBottomLeft"), SNAME("EditorIcons")));
+ preset_buttons[PRESET_CENTER_BOTTOM]->set_icon(get_theme_icon(SNAME("ControlAlignCenterBottom"), SNAME("EditorIcons")));
+ preset_buttons[PRESET_BOTTOM_RIGHT]->set_icon(get_theme_icon(SNAME("ControlAlignBottomRight"), SNAME("EditorIcons")));
+
+ preset_buttons[PRESET_TOP_WIDE]->set_icon(get_theme_icon(SNAME("ControlAlignTopWide"), SNAME("EditorIcons")));
+ preset_buttons[PRESET_HCENTER_WIDE]->set_icon(get_theme_icon(SNAME("ControlAlignHCenterWide"), SNAME("EditorIcons")));
+ preset_buttons[PRESET_BOTTOM_WIDE]->set_icon(get_theme_icon(SNAME("ControlAlignBottomWide"), SNAME("EditorIcons")));
+
+ preset_buttons[PRESET_LEFT_WIDE]->set_icon(get_theme_icon(SNAME("ControlAlignLeftWide"), SNAME("EditorIcons")));
+ preset_buttons[PRESET_VCENTER_WIDE]->set_icon(get_theme_icon(SNAME("ControlAlignVCenterWide"), SNAME("EditorIcons")));
+ preset_buttons[PRESET_RIGHT_WIDE]->set_icon(get_theme_icon(SNAME("ControlAlignRightWide"), SNAME("EditorIcons")));
+
+ preset_buttons[PRESET_FULL_RECT]->set_icon(get_theme_icon(SNAME("ControlAlignFullRect"), SNAME("EditorIcons")));
+ } break;
+ }
+}
+
+void AnchorPresetPicker::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("anchors_preset_selected", PropertyInfo(Variant::INT, "preset")));
+}
+
+AnchorPresetPicker::AnchorPresetPicker() {
+ VBoxContainer *main_vb = memnew(VBoxContainer);
+ main_vb->add_theme_constant_override("separation", grid_separation);
+ add_child(main_vb);
+
+ HBoxContainer *top_row = memnew(HBoxContainer);
+ top_row->set_alignment(BoxContainer::ALIGNMENT_CENTER);
+ top_row->add_theme_constant_override("separation", grid_separation);
+ main_vb->add_child(top_row);
+
+ _add_row_button(top_row, PRESET_TOP_LEFT, TTR("Top Left"));
+ _add_row_button(top_row, PRESET_CENTER_TOP, TTR("Center Top"));
+ _add_row_button(top_row, PRESET_TOP_RIGHT, TTR("Top Right"));
+ _add_separator(top_row, memnew(VSeparator));
+ _add_row_button(top_row, PRESET_TOP_WIDE, TTR("Top Wide"));
+
+ HBoxContainer *mid_row = memnew(HBoxContainer);
+ mid_row->set_alignment(BoxContainer::ALIGNMENT_CENTER);
+ mid_row->add_theme_constant_override("separation", grid_separation);
+ main_vb->add_child(mid_row);
+
+ _add_row_button(mid_row, PRESET_CENTER_LEFT, TTR("Center Left"));
+ _add_row_button(mid_row, PRESET_CENTER, TTR("Center"));
+ _add_row_button(mid_row, PRESET_CENTER_RIGHT, TTR("Center Right"));
+ _add_separator(mid_row, memnew(VSeparator));
+ _add_row_button(mid_row, PRESET_HCENTER_WIDE, TTR("HCenter Wide"));
+
+ HBoxContainer *bot_row = memnew(HBoxContainer);
+ bot_row->set_alignment(BoxContainer::ALIGNMENT_CENTER);
+ bot_row->add_theme_constant_override("separation", grid_separation);
+ main_vb->add_child(bot_row);
+
+ _add_row_button(bot_row, PRESET_BOTTOM_LEFT, TTR("Bottom Left"));
+ _add_row_button(bot_row, PRESET_CENTER_BOTTOM, TTR("Center Bottom"));
+ _add_row_button(bot_row, PRESET_BOTTOM_RIGHT, TTR("Bottom Right"));
+ _add_separator(bot_row, memnew(VSeparator));
+ _add_row_button(bot_row, PRESET_BOTTOM_WIDE, TTR("Bottom Wide"));
+
+ _add_separator(main_vb, memnew(HSeparator));
+
+ HBoxContainer *extra_row = memnew(HBoxContainer);
+ extra_row->set_alignment(BoxContainer::ALIGNMENT_CENTER);
+ extra_row->add_theme_constant_override("separation", grid_separation);
+ main_vb->add_child(extra_row);
+
+ _add_row_button(extra_row, PRESET_LEFT_WIDE, TTR("Left Wide"));
+ _add_row_button(extra_row, PRESET_VCENTER_WIDE, TTR("VCenter Wide"));
+ _add_row_button(extra_row, PRESET_RIGHT_WIDE, TTR("Right Wide"));
+ _add_separator(extra_row, memnew(VSeparator));
+ _add_row_button(extra_row, PRESET_FULL_RECT, TTR("Full Rect"));
+}
+
+void SizeFlagPresetPicker::_preset_button_pressed(const int p_preset) {
+ int flags = (SizeFlags)p_preset;
+ if (expand_button->is_pressed()) {
+ flags |= SIZE_EXPAND;
+ }
+
+ emit_signal("size_flags_selected", flags);
+}
+
+void SizeFlagPresetPicker::set_allowed_flags(Vector<SizeFlags> &p_flags) {
+ preset_buttons[SIZE_SHRINK_BEGIN]->set_disabled(!p_flags.has(SIZE_SHRINK_BEGIN));
+ preset_buttons[SIZE_SHRINK_CENTER]->set_disabled(!p_flags.has(SIZE_SHRINK_CENTER));
+ preset_buttons[SIZE_SHRINK_END]->set_disabled(!p_flags.has(SIZE_SHRINK_END));
+ preset_buttons[SIZE_FILL]->set_disabled(!p_flags.has(SIZE_FILL));
+
+ expand_button->set_disabled(!p_flags.has(SIZE_EXPAND));
+ if (p_flags.has(SIZE_EXPAND)) {
+ expand_button->set_tooltip_text(TTR("Enable to also set the Expand flag.\nDisable to only set Shrink/Fill flags."));
+ } else {
+ expand_button->set_pressed(false);
+ expand_button->set_tooltip_text(TTR("Some parents of the selected nodes do not support the Expand flag."));
+ }
+}
+
+void SizeFlagPresetPicker::_notification(int p_notification) {
+ switch (p_notification) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ if (vertical) {
+ preset_buttons[SIZE_SHRINK_BEGIN]->set_icon(get_theme_icon(SNAME("ControlAlignCenterTop"), SNAME("EditorIcons")));
+ preset_buttons[SIZE_SHRINK_CENTER]->set_icon(get_theme_icon(SNAME("ControlAlignCenter"), SNAME("EditorIcons")));
+ preset_buttons[SIZE_SHRINK_END]->set_icon(get_theme_icon(SNAME("ControlAlignCenterBottom"), SNAME("EditorIcons")));
+
+ preset_buttons[SIZE_FILL]->set_icon(get_theme_icon(SNAME("ControlAlignVCenterWide"), SNAME("EditorIcons")));
+ } else {
+ preset_buttons[SIZE_SHRINK_BEGIN]->set_icon(get_theme_icon(SNAME("ControlAlignCenterLeft"), SNAME("EditorIcons")));
+ preset_buttons[SIZE_SHRINK_CENTER]->set_icon(get_theme_icon(SNAME("ControlAlignCenter"), SNAME("EditorIcons")));
+ preset_buttons[SIZE_SHRINK_END]->set_icon(get_theme_icon(SNAME("ControlAlignCenterRight"), SNAME("EditorIcons")));
+
+ preset_buttons[SIZE_FILL]->set_icon(get_theme_icon(SNAME("ControlAlignHCenterWide"), SNAME("EditorIcons")));
+ }
+ } break;
+ }
+}
+
+void SizeFlagPresetPicker::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("size_flags_selected", PropertyInfo(Variant::INT, "size_flags")));
+}
+
+SizeFlagPresetPicker::SizeFlagPresetPicker(bool p_vertical) {
+ vertical = p_vertical;
+
+ VBoxContainer *main_vb = memnew(VBoxContainer);
+ add_child(main_vb);
+
+ HBoxContainer *main_row = memnew(HBoxContainer);
+ main_row->set_alignment(BoxContainer::ALIGNMENT_CENTER);
+ main_row->add_theme_constant_override("separation", grid_separation);
+ main_vb->add_child(main_row);
+
+ _add_row_button(main_row, SIZE_SHRINK_BEGIN, TTR("Shrink Begin"));
+ _add_row_button(main_row, SIZE_SHRINK_CENTER, TTR("Shrink Center"));
+ _add_row_button(main_row, SIZE_SHRINK_END, TTR("Shrink End"));
+ _add_separator(main_row, memnew(VSeparator));
+ _add_row_button(main_row, SIZE_FILL, TTR("Fill"));
+
+ expand_button = memnew(CheckBox);
+ expand_button->set_flat(true);
+ expand_button->set_text(TTR("Align with Expand"));
+ expand_button->set_tooltip_text(TTR("Enable to also set the Expand flag.\nDisable to only set Shrink/Fill flags."));
+ main_vb->add_child(expand_button);
+}
+
+// Toolbar.
+
+void ControlEditorToolbar::_anchors_preset_selected(int p_preset) {
+ LayoutPreset preset = (LayoutPreset)p_preset;
List<Node *> selection = editor_selection->get_selected_node_list();
- undo_redo->create_action(TTR("Change Anchors and Offsets"));
+ undo_redo->create_action(TTR("Change Anchors, Offsets, Grow Direction"));
for (Node *E : selection) {
Control *control = Object::cast_to<Control>(E);
if (control) {
- undo_redo->add_do_method(control, "set_anchors_preset", p_preset);
- switch (p_preset) {
- case PRESET_TOP_LEFT:
- case PRESET_TOP_RIGHT:
- case PRESET_BOTTOM_LEFT:
- case PRESET_BOTTOM_RIGHT:
- case PRESET_CENTER_LEFT:
- case PRESET_CENTER_TOP:
- case PRESET_CENTER_RIGHT:
- case PRESET_CENTER_BOTTOM:
- case PRESET_CENTER:
- undo_redo->add_do_method(control, "set_offsets_preset", p_preset, Control::PRESET_MODE_KEEP_SIZE);
- break;
- case PRESET_LEFT_WIDE:
- case PRESET_TOP_WIDE:
- case PRESET_RIGHT_WIDE:
- case PRESET_BOTTOM_WIDE:
- case PRESET_VCENTER_WIDE:
- case PRESET_HCENTER_WIDE:
- case PRESET_FULL_RECT:
- undo_redo->add_do_method(control, "set_offsets_preset", p_preset, Control::PRESET_MODE_MINSIZE);
- break;
- }
+ undo_redo->add_do_property(control, "anchors_preset", preset);
undo_redo->add_undo_method(control, "_edit_set_state", control->_edit_get_state());
}
}
@@ -489,10 +736,10 @@ void ControlEditorToolbar::_set_anchors_and_offsets_preset(Control::LayoutPreset
anchor_mode_button->set_pressed(anchors_mode);
}
-void ControlEditorToolbar::_set_anchors_and_offsets_to_keep_ratio() {
+void ControlEditorToolbar::_anchors_to_current_ratio() {
List<Node *> selection = editor_selection->get_selected_node_list();
- undo_redo->create_action(TTR("Change Anchors and Offsets"));
+ undo_redo->create_action(TTR("Change Anchors, Offsets (Keep Ratio)"));
for (Node *E : selection) {
Control *control = Object::cast_to<Control>(E);
@@ -521,44 +768,41 @@ void ControlEditorToolbar::_set_anchors_and_offsets_to_keep_ratio() {
undo_redo->commit_action();
}
-void ControlEditorToolbar::_set_anchors_preset(Control::LayoutPreset p_preset) {
- List<Node *> selection = editor_selection->get_selected_node_list();
+void ControlEditorToolbar::_anchor_mode_toggled(bool p_status) {
+ List<Control *> selection = _get_edited_controls();
+ for (Control *E : selection) {
+ if (Object::cast_to<Container>(E->get_parent())) {
+ continue;
+ }
- undo_redo->create_action(TTR("Change Anchors"));
- for (Node *E : selection) {
- Control *control = Object::cast_to<Control>(E);
- if (control) {
- undo_redo->add_do_method(control, "set_anchors_preset", p_preset);
- undo_redo->add_undo_method(control, "_edit_set_state", control->_edit_get_state());
+ if (p_status) {
+ E->set_meta("_edit_use_anchors_", true);
+ } else {
+ E->remove_meta("_edit_use_anchors_");
}
}
- undo_redo->commit_action();
+ anchors_mode = p_status;
+ CanvasItemEditor::get_singleton()->update_viewport();
}
-void ControlEditorToolbar::_set_container_h_preset(Control::SizeFlags p_preset) {
+void ControlEditorToolbar::_container_flags_selected(int p_flags, bool p_vertical) {
List<Node *> selection = editor_selection->get_selected_node_list();
- undo_redo->create_action(TTR("Change Horizontal Size Flags"));
- for (Node *E : selection) {
- Control *control = Object::cast_to<Control>(E);
- if (control) {
- undo_redo->add_do_method(control, "set_h_size_flags", p_preset);
- undo_redo->add_undo_method(control, "_edit_set_state", control->_edit_get_state());
- }
+ if (p_vertical) {
+ undo_redo->create_action(TTR("Change Vertical Size Flags"));
+ } else {
+ undo_redo->create_action(TTR("Change Horizontal Size Flags"));
}
- undo_redo->commit_action();
-}
-
-void ControlEditorToolbar::_set_container_v_preset(Control::SizeFlags p_preset) {
- List<Node *> selection = editor_selection->get_selected_node_list();
-
- undo_redo->create_action(TTR("Change Horizontal Size Flags"));
for (Node *E : selection) {
Control *control = Object::cast_to<Control>(E);
if (control) {
- undo_redo->add_do_method(control, "set_v_size_flags", p_preset);
+ if (p_vertical) {
+ undo_redo->add_do_method(control, "set_v_size_flags", p_flags);
+ } else {
+ undo_redo->add_do_method(control, "set_h_size_flags", p_flags);
+ }
undo_redo->add_undo_method(control, "_edit_set_state", control->_edit_get_state());
}
}
@@ -594,400 +838,205 @@ Vector2 ControlEditorToolbar::_position_to_anchor(const Control *p_control, Vect
return output;
}
-void ControlEditorToolbar::_button_toggle_anchor_mode(bool p_status) {
- List<Control *> selection = _get_edited_controls(false, false);
- for (Control *E : selection) {
- if (Object::cast_to<Container>(E->get_parent())) {
- continue;
- }
-
- if (p_status) {
- E->set_meta("_edit_use_anchors_", true);
- } else {
- E->remove_meta("_edit_use_anchors_");
- }
- }
-
- anchors_mode = p_status;
- CanvasItemEditor::get_singleton()->update_viewport();
-}
-
bool ControlEditorToolbar::_is_node_locked(const Node *p_node) {
return p_node->get_meta("_edit_lock_", false);
}
-List<Control *> ControlEditorToolbar::_get_edited_controls(bool retrieve_locked, bool remove_controls_if_parent_in_selection) {
+List<Control *> ControlEditorToolbar::_get_edited_controls() {
List<Control *> selection;
for (const KeyValue<Node *, Object *> &E : editor_selection->get_selection()) {
Control *control = Object::cast_to<Control>(E.key);
- if (control && control->is_visible_in_tree() && control->get_viewport() == EditorNode::get_singleton()->get_scene_root() && (retrieve_locked || !_is_node_locked(control))) {
+ if (control && control->is_visible_in_tree() && control->get_viewport() == EditorNode::get_singleton()->get_scene_root() && !_is_node_locked(control)) {
selection.push_back(control);
}
}
- if (remove_controls_if_parent_in_selection) {
- List<Control *> filtered_selection;
- for (Control *E : selection) {
- if (!selection.find(E->get_parent())) {
- filtered_selection.push_back(E);
- }
- }
- return filtered_selection;
- }
-
return selection;
}
-void ControlEditorToolbar::_popup_callback(int p_op) {
- switch (p_op) {
- case ANCHORS_AND_OFFSETS_PRESET_TOP_LEFT: {
- _set_anchors_and_offsets_preset(PRESET_TOP_LEFT);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_TOP_RIGHT: {
- _set_anchors_and_offsets_preset(PRESET_TOP_RIGHT);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_BOTTOM_LEFT: {
- _set_anchors_and_offsets_preset(PRESET_BOTTOM_LEFT);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_BOTTOM_RIGHT: {
- _set_anchors_and_offsets_preset(PRESET_BOTTOM_RIGHT);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_CENTER_LEFT: {
- _set_anchors_and_offsets_preset(PRESET_CENTER_LEFT);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_CENTER_RIGHT: {
- _set_anchors_and_offsets_preset(PRESET_CENTER_RIGHT);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_CENTER_TOP: {
- _set_anchors_and_offsets_preset(PRESET_CENTER_TOP);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_CENTER_BOTTOM: {
- _set_anchors_and_offsets_preset(PRESET_CENTER_BOTTOM);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_CENTER: {
- _set_anchors_and_offsets_preset(PRESET_CENTER);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_TOP_WIDE: {
- _set_anchors_and_offsets_preset(PRESET_TOP_WIDE);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_LEFT_WIDE: {
- _set_anchors_and_offsets_preset(PRESET_LEFT_WIDE);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_RIGHT_WIDE: {
- _set_anchors_and_offsets_preset(PRESET_RIGHT_WIDE);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_BOTTOM_WIDE: {
- _set_anchors_and_offsets_preset(PRESET_BOTTOM_WIDE);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_VCENTER_WIDE: {
- _set_anchors_and_offsets_preset(PRESET_VCENTER_WIDE);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_HCENTER_WIDE: {
- _set_anchors_and_offsets_preset(PRESET_HCENTER_WIDE);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_FULL_RECT: {
- _set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
- } break;
- case ANCHORS_AND_OFFSETS_PRESET_KEEP_RATIO: {
- _set_anchors_and_offsets_to_keep_ratio();
- } break;
-
- case ANCHORS_PRESET_TOP_LEFT: {
- _set_anchors_preset(PRESET_TOP_LEFT);
- } break;
- case ANCHORS_PRESET_TOP_RIGHT: {
- _set_anchors_preset(PRESET_TOP_RIGHT);
- } break;
- case ANCHORS_PRESET_BOTTOM_LEFT: {
- _set_anchors_preset(PRESET_BOTTOM_LEFT);
- } break;
- case ANCHORS_PRESET_BOTTOM_RIGHT: {
- _set_anchors_preset(PRESET_BOTTOM_RIGHT);
- } break;
- case ANCHORS_PRESET_CENTER_LEFT: {
- _set_anchors_preset(PRESET_CENTER_LEFT);
- } break;
- case ANCHORS_PRESET_CENTER_RIGHT: {
- _set_anchors_preset(PRESET_CENTER_RIGHT);
- } break;
- case ANCHORS_PRESET_CENTER_TOP: {
- _set_anchors_preset(PRESET_CENTER_TOP);
- } break;
- case ANCHORS_PRESET_CENTER_BOTTOM: {
- _set_anchors_preset(PRESET_CENTER_BOTTOM);
- } break;
- case ANCHORS_PRESET_CENTER: {
- _set_anchors_preset(PRESET_CENTER);
- } break;
- case ANCHORS_PRESET_TOP_WIDE: {
- _set_anchors_preset(PRESET_TOP_WIDE);
- } break;
- case ANCHORS_PRESET_LEFT_WIDE: {
- _set_anchors_preset(PRESET_LEFT_WIDE);
- } break;
- case ANCHORS_PRESET_RIGHT_WIDE: {
- _set_anchors_preset(PRESET_RIGHT_WIDE);
- } break;
- case ANCHORS_PRESET_BOTTOM_WIDE: {
- _set_anchors_preset(PRESET_BOTTOM_WIDE);
- } break;
- case ANCHORS_PRESET_VCENTER_WIDE: {
- _set_anchors_preset(PRESET_VCENTER_WIDE);
- } break;
- case ANCHORS_PRESET_HCENTER_WIDE: {
- _set_anchors_preset(PRESET_HCENTER_WIDE);
- } break;
- case ANCHORS_PRESET_FULL_RECT: {
- _set_anchors_preset(Control::PRESET_FULL_RECT);
- } break;
-
- case CONTAINERS_H_PRESET_FILL: {
- _set_container_h_preset(Control::SIZE_FILL);
- } break;
- case CONTAINERS_H_PRESET_FILL_EXPAND: {
- _set_container_h_preset(Control::SIZE_EXPAND_FILL);
- } break;
- case CONTAINERS_H_PRESET_SHRINK_BEGIN: {
- _set_container_h_preset(Control::SIZE_SHRINK_BEGIN);
- } break;
- case CONTAINERS_H_PRESET_SHRINK_CENTER: {
- _set_container_h_preset(Control::SIZE_SHRINK_CENTER);
- } break;
- case CONTAINERS_H_PRESET_SHRINK_END: {
- _set_container_h_preset(Control::SIZE_SHRINK_END);
- } break;
-
- case CONTAINERS_V_PRESET_FILL: {
- _set_container_v_preset(Control::SIZE_FILL);
- } break;
- case CONTAINERS_V_PRESET_FILL_EXPAND: {
- _set_container_v_preset(Control::SIZE_EXPAND_FILL);
- } break;
- case CONTAINERS_V_PRESET_SHRINK_BEGIN: {
- _set_container_v_preset(Control::SIZE_SHRINK_BEGIN);
- } break;
- case CONTAINERS_V_PRESET_SHRINK_CENTER: {
- _set_container_v_preset(Control::SIZE_SHRINK_CENTER);
- } break;
- case CONTAINERS_V_PRESET_SHRINK_END: {
- _set_container_v_preset(Control::SIZE_SHRINK_END);
- } break;
- }
-}
-
void ControlEditorToolbar::_selection_changed() {
- // Update the anchors_mode.
- int nb_controls = 0;
- int nb_valid_controls = 0;
- int nb_anchors_mode = 0;
+ // Update toolbar visibility.
+ bool has_controls = false;
+ bool has_control_parents = false;
+ bool has_container_parents = false;
+
+ // Also update which size flags can be configured for the selected nodes.
+ Vector<SizeFlags> allowed_h_flags = {
+ SIZE_SHRINK_BEGIN,
+ SIZE_SHRINK_CENTER,
+ SIZE_SHRINK_END,
+ SIZE_FILL,
+ SIZE_EXPAND,
+ };
+ Vector<SizeFlags> allowed_v_flags = {
+ SIZE_SHRINK_BEGIN,
+ SIZE_SHRINK_CENTER,
+ SIZE_SHRINK_END,
+ SIZE_FILL,
+ SIZE_EXPAND,
+ };
- List<Node *> selection = editor_selection->get_selected_node_list();
- for (Node *E : selection) {
- Control *control = Object::cast_to<Control>(E);
+ for (const KeyValue<Node *, Object *> &E : editor_selection->get_selection()) {
+ Control *control = Object::cast_to<Control>(E.key);
if (!control) {
continue;
}
+ has_controls = true;
- nb_controls++;
+ if (Object::cast_to<Control>(control->get_parent())) {
+ has_control_parents = true;
+ }
if (Object::cast_to<Container>(control->get_parent())) {
- continue;
+ has_container_parents = true;
+
+ Container *parent_container = Object::cast_to<Container>(control->get_parent());
+
+ Vector<int> container_h_flags = parent_container->get_allowed_size_flags_horizontal();
+ Vector<SizeFlags> tmp_flags = allowed_h_flags.duplicate();
+ for (int i = 0; i < allowed_h_flags.size(); i++) {
+ if (!container_h_flags.has((int)allowed_h_flags[i])) {
+ tmp_flags.erase(allowed_h_flags[i]);
+ }
+ }
+ allowed_h_flags = tmp_flags;
+
+ Vector<int> container_v_flags = parent_container->get_allowed_size_flags_vertical();
+ tmp_flags = allowed_v_flags.duplicate();
+ for (int i = 0; i < allowed_v_flags.size(); i++) {
+ if (!container_v_flags.has((int)allowed_v_flags[i])) {
+ tmp_flags.erase(allowed_v_flags[i]);
+ }
+ }
+ allowed_v_flags = tmp_flags;
}
+ }
+
+ // Set general toolbar visibility.
+ set_visible(has_controls);
+
+ // Set anchor tools visibility.
+ if (has_controls && (!has_control_parents || !has_container_parents)) {
+ anchors_button->set_visible(true);
+ anchor_mode_button->set_visible(true);
+
+ // Update anchor mode.
+ int nb_valid_controls = 0;
+ int nb_anchors_mode = 0;
- nb_valid_controls++;
- if (control->get_meta("_edit_use_anchors_", false)) {
- nb_anchors_mode++;
+ List<Node *> selection = editor_selection->get_selected_node_list();
+ for (Node *E : selection) {
+ Control *control = Object::cast_to<Control>(E);
+ if (!control) {
+ continue;
+ }
+ if (Object::cast_to<Container>(control->get_parent())) {
+ continue;
+ }
+
+ nb_valid_controls++;
+ if (control->get_meta("_edit_use_anchors_", false)) {
+ nb_anchors_mode++;
+ }
}
+
+ anchors_mode = (nb_valid_controls == nb_anchors_mode);
+ anchor_mode_button->set_pressed(anchors_mode);
+ } else {
+ anchors_button->set_visible(false);
+ anchor_mode_button->set_visible(false);
+ anchor_mode_button->set_pressed(false);
}
- anchors_mode = (nb_valid_controls == nb_anchors_mode);
- anchor_mode_button->set_pressed(anchors_mode);
+ // Set container tools visibility.
+ if (has_controls && (!has_control_parents || has_container_parents)) {
+ containers_button->set_visible(true);
- if (nb_controls > 0) {
- set_physics_process(true);
+ // Update allowed size flags.
+ if (has_container_parents) {
+ container_h_picker->set_allowed_flags(allowed_h_flags);
+ container_v_picker->set_allowed_flags(allowed_v_flags);
+ } else {
+ Vector<SizeFlags> allowed_all_flags = {
+ SIZE_SHRINK_BEGIN,
+ SIZE_SHRINK_CENTER,
+ SIZE_SHRINK_END,
+ SIZE_FILL,
+ SIZE_EXPAND,
+ };
+
+ container_h_picker->set_allowed_flags(allowed_all_flags);
+ container_v_picker->set_allowed_flags(allowed_all_flags);
+ }
} else {
- set_physics_process(false);
- set_visible(false);
+ containers_button->set_visible(false);
}
}
void ControlEditorToolbar::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
- case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- anchor_presets_menu->set_icon(get_theme_icon(SNAME("ControlLayout"), SNAME("EditorIcons")));
-
- PopupMenu *p = anchor_presets_menu->get_popup();
- p->clear();
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignTopLeft"), SNAME("EditorIcons")), TTR("Top Left"), ANCHORS_AND_OFFSETS_PRESET_TOP_LEFT);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignTopRight"), SNAME("EditorIcons")), TTR("Top Right"), ANCHORS_AND_OFFSETS_PRESET_TOP_RIGHT);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignBottomRight"), SNAME("EditorIcons")), TTR("Bottom Right"), ANCHORS_AND_OFFSETS_PRESET_BOTTOM_RIGHT);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignBottomLeft"), SNAME("EditorIcons")), TTR("Bottom Left"), ANCHORS_AND_OFFSETS_PRESET_BOTTOM_LEFT);
- p->add_separator();
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterLeft"), SNAME("EditorIcons")), TTR("Center Left"), ANCHORS_AND_OFFSETS_PRESET_CENTER_LEFT);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterTop"), SNAME("EditorIcons")), TTR("Center Top"), ANCHORS_AND_OFFSETS_PRESET_CENTER_TOP);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterRight"), SNAME("EditorIcons")), TTR("Center Right"), ANCHORS_AND_OFFSETS_PRESET_CENTER_RIGHT);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterBottom"), SNAME("EditorIcons")), TTR("Center Bottom"), ANCHORS_AND_OFFSETS_PRESET_CENTER_BOTTOM);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenter"), SNAME("EditorIcons")), TTR("Center"), ANCHORS_AND_OFFSETS_PRESET_CENTER);
- p->add_separator();
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignLeftWide"), SNAME("EditorIcons")), TTR("Left Wide"), ANCHORS_AND_OFFSETS_PRESET_LEFT_WIDE);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignTopWide"), SNAME("EditorIcons")), TTR("Top Wide"), ANCHORS_AND_OFFSETS_PRESET_TOP_WIDE);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignRightWide"), SNAME("EditorIcons")), TTR("Right Wide"), ANCHORS_AND_OFFSETS_PRESET_RIGHT_WIDE);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignBottomWide"), SNAME("EditorIcons")), TTR("Bottom Wide"), ANCHORS_AND_OFFSETS_PRESET_BOTTOM_WIDE);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignVCenterWide"), SNAME("EditorIcons")), TTR("VCenter Wide"), ANCHORS_AND_OFFSETS_PRESET_VCENTER_WIDE);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignHCenterWide"), SNAME("EditorIcons")), TTR("HCenter Wide"), ANCHORS_AND_OFFSETS_PRESET_HCENTER_WIDE);
- p->add_separator();
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignFullRect"), SNAME("EditorIcons")), TTR("Full Rect"), ANCHORS_AND_OFFSETS_PRESET_FULL_RECT);
- p->add_icon_item(get_theme_icon(SNAME("Anchor"), SNAME("EditorIcons")), TTR("Keep Current Ratio"), ANCHORS_AND_OFFSETS_PRESET_KEEP_RATIO);
- p->set_item_tooltip(19, TTR("Adjust anchors and offsets to match the current rect size."));
-
- p->add_separator();
- p->add_submenu_item(TTR("Anchors only"), "Anchors");
- p->set_item_icon(21, get_theme_icon(SNAME("Anchor"), SNAME("EditorIcons")));
-
- anchors_popup->clear();
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignTopLeft"), SNAME("EditorIcons")), TTR("Top Left"), ANCHORS_PRESET_TOP_LEFT);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignTopRight"), SNAME("EditorIcons")), TTR("Top Right"), ANCHORS_PRESET_TOP_RIGHT);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignBottomRight"), SNAME("EditorIcons")), TTR("Bottom Right"), ANCHORS_PRESET_BOTTOM_RIGHT);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignBottomLeft"), SNAME("EditorIcons")), TTR("Bottom Left"), ANCHORS_PRESET_BOTTOM_LEFT);
- anchors_popup->add_separator();
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterLeft"), SNAME("EditorIcons")), TTR("Center Left"), ANCHORS_PRESET_CENTER_LEFT);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterTop"), SNAME("EditorIcons")), TTR("Center Top"), ANCHORS_PRESET_CENTER_TOP);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterRight"), SNAME("EditorIcons")), TTR("Center Right"), ANCHORS_PRESET_CENTER_RIGHT);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterBottom"), SNAME("EditorIcons")), TTR("Center Bottom"), ANCHORS_PRESET_CENTER_BOTTOM);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignCenter"), SNAME("EditorIcons")), TTR("Center"), ANCHORS_PRESET_CENTER);
- anchors_popup->add_separator();
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignLeftWide"), SNAME("EditorIcons")), TTR("Left Wide"), ANCHORS_PRESET_LEFT_WIDE);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignTopWide"), SNAME("EditorIcons")), TTR("Top Wide"), ANCHORS_PRESET_TOP_WIDE);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignRightWide"), SNAME("EditorIcons")), TTR("Right Wide"), ANCHORS_PRESET_RIGHT_WIDE);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignBottomWide"), SNAME("EditorIcons")), TTR("Bottom Wide"), ANCHORS_PRESET_BOTTOM_WIDE);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignVCenterWide"), SNAME("EditorIcons")), TTR("VCenter Wide"), ANCHORS_PRESET_VCENTER_WIDE);
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignHCenterWide"), SNAME("EditorIcons")), TTR("HCenter Wide"), ANCHORS_PRESET_HCENTER_WIDE);
- anchors_popup->add_separator();
- anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignFullRect"), SNAME("EditorIcons")), TTR("Full Rect"), ANCHORS_PRESET_FULL_RECT);
-
+ case NOTIFICATION_THEME_CHANGED: {
+ anchors_button->set_icon(get_theme_icon(SNAME("ControlLayout"), SNAME("EditorIcons")));
anchor_mode_button->set_icon(get_theme_icon(SNAME("Anchor"), SNAME("EditorIcons")));
-
- container_h_presets_menu->set_icon(get_theme_icon(SNAME("Container"), SNAME("EditorIcons")));
- container_v_presets_menu->set_icon(get_theme_icon(SNAME("Container"), SNAME("EditorIcons")));
-
- p = container_h_presets_menu->get_popup();
- p->clear();
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignHCenterWide"), SNAME("EditorIcons")), TTR("Fill"), CONTAINERS_H_PRESET_FILL);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignHCenterWide"), SNAME("EditorIcons")), TTR("Fill & Expand"), CONTAINERS_H_PRESET_FILL_EXPAND);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterLeft"), SNAME("EditorIcons")), TTR("Shrink Begin"), CONTAINERS_H_PRESET_SHRINK_BEGIN);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenter"), SNAME("EditorIcons")), TTR("Shrink Center"), CONTAINERS_H_PRESET_SHRINK_CENTER);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterRight"), SNAME("EditorIcons")), TTR("Shrink End"), CONTAINERS_H_PRESET_SHRINK_END);
-
- p = container_v_presets_menu->get_popup();
- p->clear();
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignVCenterWide"), SNAME("EditorIcons")), TTR("Fill"), CONTAINERS_V_PRESET_FILL);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignVCenterWide"), SNAME("EditorIcons")), TTR("Fill & Expand"), CONTAINERS_V_PRESET_FILL_EXPAND);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterTop"), SNAME("EditorIcons")), TTR("Shrink Begin"), CONTAINERS_V_PRESET_SHRINK_BEGIN);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenter"), SNAME("EditorIcons")), TTR("Shrink Center"), CONTAINERS_V_PRESET_SHRINK_CENTER);
- p->add_icon_item(get_theme_icon(SNAME("ControlAlignCenterBottom"), SNAME("EditorIcons")), TTR("Shrink End"), CONTAINERS_V_PRESET_SHRINK_END);
- } break;
-
- case NOTIFICATION_PHYSICS_PROCESS: {
- bool has_control_parents = false;
- bool has_container_parents = false;
-
- // Update the viewport if the canvas_item changes
- List<Control *> selection = _get_edited_controls(true);
- for (Control *control : selection) {
- if (Object::cast_to<Control>(control->get_parent())) {
- has_control_parents = true;
- }
- if (Object::cast_to<Container>(control->get_parent())) {
- has_container_parents = true;
- }
- }
-
- // Show / Hide the control layout buttons.
- if (selection.size() > 0) {
- set_visible(true);
-
- // Toggle anchor and container layout buttons depending on parents of the selected nodes.
- // - If there are no control parents, enable everything.
- // - If there are container parents, then enable only container buttons.
- // - If there are NO container parents, then enable only anchor buttons.
- bool enable_anchors = false;
- bool enable_containers = false;
- if (!has_control_parents) {
- enable_anchors = true;
- enable_containers = true;
- } else if (has_container_parents) {
- enable_containers = true;
- } else {
- enable_anchors = true;
- }
-
- if (enable_anchors) {
- anchor_presets_menu->set_visible(true);
- anchor_mode_button->set_visible(true);
- } else {
- anchor_presets_menu->set_visible(false);
- anchor_mode_button->set_visible(false);
- }
-
- if (enable_containers) {
- container_h_presets_menu->set_visible(true);
- container_v_presets_menu->set_visible(true);
- } else {
- container_h_presets_menu->set_visible(false);
- container_v_presets_menu->set_visible(false);
- }
- } else {
- set_visible(false);
- }
+ containers_button->set_icon(get_theme_icon(SNAME("ContainerLayout"), SNAME("EditorIcons")));
} break;
}
}
ControlEditorToolbar::ControlEditorToolbar() {
- anchor_presets_menu = memnew(MenuButton);
- anchor_presets_menu->set_shortcut_context(this);
- anchor_presets_menu->set_text(TTR("Anchors"));
- anchor_presets_menu->set_tooltip(TTR("Presets for the anchor and offset values of a Control node."));
- add_child(anchor_presets_menu);
- anchor_presets_menu->set_switch_on_hover(true);
+ add_child(memnew(VSeparator));
- PopupMenu *p = anchor_presets_menu->get_popup();
- p->connect("id_pressed", callable_mp(this, &ControlEditorToolbar::_popup_callback));
+ // Anchor and offset tools.
+ anchors_button = memnew(ControlEditorPopupButton);
+ anchors_button->set_tooltip_text(TTR("Presets for the anchor and offset values of a Control node."));
+ add_child(anchors_button);
- anchors_popup = memnew(PopupMenu);
- p->add_child(anchors_popup);
- anchors_popup->set_name("Anchors");
- anchors_popup->connect("id_pressed", callable_mp(this, &ControlEditorToolbar::_popup_callback));
+ Label *anchors_label = memnew(Label);
+ anchors_label->set_text(TTR("Anchor preset"));
+ anchors_button->get_popup_hbox()->add_child(anchors_label);
+ AnchorPresetPicker *anchors_picker = memnew(AnchorPresetPicker);
+ anchors_picker->set_h_size_flags(SIZE_SHRINK_CENTER);
+ anchors_button->get_popup_hbox()->add_child(anchors_picker);
+ anchors_picker->connect("anchors_preset_selected", callable_mp(this, &ControlEditorToolbar::_anchors_preset_selected));
+
+ anchors_button->get_popup_hbox()->add_child(memnew(HSeparator));
+
+ Button *keep_ratio_button = memnew(Button);
+ keep_ratio_button->set_text_alignment(HORIZONTAL_ALIGNMENT_LEFT);
+ keep_ratio_button->set_text(TTR("Set to Current Ratio"));
+ keep_ratio_button->set_tooltip_text(TTR("Adjust anchors and offsets to match the current rect size."));
+ anchors_button->get_popup_hbox()->add_child(keep_ratio_button);
+ keep_ratio_button->connect("pressed", callable_mp(this, &ControlEditorToolbar::_anchors_to_current_ratio));
anchor_mode_button = memnew(Button);
anchor_mode_button->set_flat(true);
anchor_mode_button->set_toggle_mode(true);
- anchor_mode_button->set_tooltip(TTR("When active, moving Control nodes changes their anchors instead of their offsets."));
+ anchor_mode_button->set_tooltip_text(TTR("When active, moving Control nodes changes their anchors instead of their offsets."));
add_child(anchor_mode_button);
- anchor_mode_button->connect("toggled", callable_mp(this, &ControlEditorToolbar::_button_toggle_anchor_mode));
-
- add_child(memnew(VSeparator));
-
- container_h_presets_menu = memnew(MenuButton);
- container_h_presets_menu->set_shortcut_context(this);
- container_h_presets_menu->set_text(TTR("Horizontal"));
- container_h_presets_menu->set_tooltip(TTR("Horizontal sizing setting for children of a Container node."));
- add_child(container_h_presets_menu);
- container_h_presets_menu->set_switch_on_hover(true);
-
- p = container_h_presets_menu->get_popup();
- p->connect("id_pressed", callable_mp(this, &ControlEditorToolbar::_popup_callback));
-
- container_v_presets_menu = memnew(MenuButton);
- container_v_presets_menu->set_shortcut_context(this);
- container_v_presets_menu->set_text(TTR("Vertical"));
- container_v_presets_menu->set_tooltip(TTR("Vertical sizing setting for children of a Container node."));
- add_child(container_v_presets_menu);
- container_v_presets_menu->set_switch_on_hover(true);
-
- p = container_v_presets_menu->get_popup();
- p->connect("id_pressed", callable_mp(this, &ControlEditorToolbar::_popup_callback));
-
+ anchor_mode_button->connect("toggled", callable_mp(this, &ControlEditorToolbar::_anchor_mode_toggled));
+
+ // Container tools.
+ containers_button = memnew(ControlEditorPopupButton);
+ containers_button->set_tooltip_text(TTR("Sizing settings for children of a Container node."));
+ add_child(containers_button);
+
+ Label *container_h_label = memnew(Label);
+ container_h_label->set_text(TTR("Horizontal alignment"));
+ containers_button->get_popup_hbox()->add_child(container_h_label);
+ container_h_picker = memnew(SizeFlagPresetPicker(false));
+ containers_button->get_popup_hbox()->add_child(container_h_picker);
+ container_h_picker->connect("size_flags_selected", callable_mp(this, &ControlEditorToolbar::_container_flags_selected).bind(false));
+
+ containers_button->get_popup_hbox()->add_child(memnew(HSeparator));
+
+ Label *container_v_label = memnew(Label);
+ container_v_label->set_text(TTR("Vertical alignment"));
+ containers_button->get_popup_hbox()->add_child(container_v_label);
+ container_v_picker = memnew(SizeFlagPresetPicker(true));
+ containers_button->get_popup_hbox()->add_child(container_v_picker);
+ container_v_picker->connect("size_flags_selected", callable_mp(this, &ControlEditorToolbar::_container_flags_selected).bind(true));
+
+ // Editor connections.
undo_redo = EditorNode::get_singleton()->get_undo_redo();
editor_selection = EditorNode::get_singleton()->get_editor_selection();
editor_selection->add_editor_plugin(this);
@@ -998,6 +1047,8 @@ ControlEditorToolbar::ControlEditorToolbar() {
ControlEditorToolbar *ControlEditorToolbar::singleton = nullptr;
+// Editor plugin.
+
ControlEditorPlugin::ControlEditorPlugin() {
toolbar = memnew(ControlEditorToolbar);
toolbar->hide();
diff --git a/editor/plugins/control_editor_plugin.h b/editor/plugins/control_editor_plugin.h
index 11389bc095..584d05aab0 100644
--- a/editor/plugins/control_editor_plugin.h
+++ b/editor/plugins/control_editor_plugin.h
@@ -33,14 +33,20 @@
#include "editor/editor_plugin.h"
#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
#include "scene/gui/check_box.h"
#include "scene/gui/control.h"
#include "scene/gui/label.h"
#include "scene/gui/margin_container.h"
#include "scene/gui/option_button.h"
#include "scene/gui/panel_container.h"
+#include "scene/gui/popup.h"
+#include "scene/gui/separator.h"
#include "scene/gui/texture_rect.h"
+class EditorUndoRedoManager;
+
+// Inspector controls.
class ControlPositioningWarning : public MarginContainer {
GDCLASS(ControlPositioningWarning, MarginContainer);
@@ -125,102 +131,101 @@ public:
virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override;
};
+// Toolbar controls.
+class ControlEditorPopupButton : public Button {
+ GDCLASS(ControlEditorPopupButton, Button);
+
+ Ref<Texture2D> arrow_icon;
+
+ PopupPanel *popup_panel = nullptr;
+ VBoxContainer *popup_vbox = nullptr;
+
+ void _popup_visibility_changed(bool p_visible);
+
+protected:
+ void _notification(int p_what);
+
+public:
+ virtual Size2 get_minimum_size() const override;
+ virtual void toggled(bool p_pressed) override;
+
+ VBoxContainer *get_popup_hbox() const { return popup_vbox; }
+
+ ControlEditorPopupButton();
+};
+
+class ControlEditorPresetPicker : public MarginContainer {
+ GDCLASS(ControlEditorPresetPicker, MarginContainer);
+
+ virtual void _preset_button_pressed(const int p_preset) {}
+
+protected:
+ static constexpr int grid_separation = 0;
+ HashMap<int, Button *> preset_buttons;
+
+ void _add_row_button(HBoxContainer *p_row, const int p_preset, const String &p_name);
+ void _add_separator(BoxContainer *p_box, Separator *p_separator);
+
+public:
+ ControlEditorPresetPicker() {}
+};
+
+class AnchorPresetPicker : public ControlEditorPresetPicker {
+ GDCLASS(AnchorPresetPicker, ControlEditorPresetPicker);
+
+ virtual void _preset_button_pressed(const int p_preset) override;
+
+protected:
+ void _notification(int p_notification);
+ static void _bind_methods();
+
+public:
+ AnchorPresetPicker();
+};
+
+class SizeFlagPresetPicker : public ControlEditorPresetPicker {
+ GDCLASS(SizeFlagPresetPicker, ControlEditorPresetPicker);
+
+ CheckBox *expand_button;
+
+ bool vertical = false;
+
+ virtual void _preset_button_pressed(const int p_preset) override;
+
+protected:
+ void _notification(int p_notification);
+ static void _bind_methods();
+
+public:
+ void set_allowed_flags(Vector<SizeFlags> &p_flags);
+
+ SizeFlagPresetPicker(bool p_vertical);
+};
+
class ControlEditorToolbar : public HBoxContainer {
GDCLASS(ControlEditorToolbar, HBoxContainer);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
EditorSelection *editor_selection = nullptr;
- enum MenuOption {
- ANCHORS_AND_OFFSETS_PRESET_TOP_LEFT,
- ANCHORS_AND_OFFSETS_PRESET_TOP_RIGHT,
- ANCHORS_AND_OFFSETS_PRESET_BOTTOM_LEFT,
- ANCHORS_AND_OFFSETS_PRESET_BOTTOM_RIGHT,
- ANCHORS_AND_OFFSETS_PRESET_CENTER_LEFT,
- ANCHORS_AND_OFFSETS_PRESET_CENTER_RIGHT,
- ANCHORS_AND_OFFSETS_PRESET_CENTER_TOP,
- ANCHORS_AND_OFFSETS_PRESET_CENTER_BOTTOM,
- ANCHORS_AND_OFFSETS_PRESET_CENTER,
- ANCHORS_AND_OFFSETS_PRESET_TOP_WIDE,
- ANCHORS_AND_OFFSETS_PRESET_LEFT_WIDE,
- ANCHORS_AND_OFFSETS_PRESET_RIGHT_WIDE,
- ANCHORS_AND_OFFSETS_PRESET_BOTTOM_WIDE,
- ANCHORS_AND_OFFSETS_PRESET_VCENTER_WIDE,
- ANCHORS_AND_OFFSETS_PRESET_HCENTER_WIDE,
- ANCHORS_AND_OFFSETS_PRESET_FULL_RECT,
-
- ANCHORS_AND_OFFSETS_PRESET_KEEP_RATIO,
-
- ANCHORS_PRESET_TOP_LEFT,
- ANCHORS_PRESET_TOP_RIGHT,
- ANCHORS_PRESET_BOTTOM_LEFT,
- ANCHORS_PRESET_BOTTOM_RIGHT,
- ANCHORS_PRESET_CENTER_LEFT,
- ANCHORS_PRESET_CENTER_RIGHT,
- ANCHORS_PRESET_CENTER_TOP,
- ANCHORS_PRESET_CENTER_BOTTOM,
- ANCHORS_PRESET_CENTER,
- ANCHORS_PRESET_TOP_WIDE,
- ANCHORS_PRESET_LEFT_WIDE,
- ANCHORS_PRESET_RIGHT_WIDE,
- ANCHORS_PRESET_BOTTOM_WIDE,
- ANCHORS_PRESET_VCENTER_WIDE,
- ANCHORS_PRESET_HCENTER_WIDE,
- ANCHORS_PRESET_FULL_RECT,
-
- // Offsets Presets are not currently in use.
- OFFSETS_PRESET_TOP_LEFT,
- OFFSETS_PRESET_TOP_RIGHT,
- OFFSETS_PRESET_BOTTOM_LEFT,
- OFFSETS_PRESET_BOTTOM_RIGHT,
- OFFSETS_PRESET_CENTER_LEFT,
- OFFSETS_PRESET_CENTER_RIGHT,
- OFFSETS_PRESET_CENTER_TOP,
- OFFSETS_PRESET_CENTER_BOTTOM,
- OFFSETS_PRESET_CENTER,
- OFFSETS_PRESET_TOP_WIDE,
- OFFSETS_PRESET_LEFT_WIDE,
- OFFSETS_PRESET_RIGHT_WIDE,
- OFFSETS_PRESET_BOTTOM_WIDE,
- OFFSETS_PRESET_VCENTER_WIDE,
- OFFSETS_PRESET_HCENTER_WIDE,
- OFFSETS_PRESET_FULL_RECT,
-
- CONTAINERS_H_PRESET_FILL,
- CONTAINERS_H_PRESET_FILL_EXPAND,
- CONTAINERS_H_PRESET_SHRINK_BEGIN,
- CONTAINERS_H_PRESET_SHRINK_CENTER,
- CONTAINERS_H_PRESET_SHRINK_END,
- CONTAINERS_V_PRESET_FILL,
- CONTAINERS_V_PRESET_FILL_EXPAND,
- CONTAINERS_V_PRESET_SHRINK_BEGIN,
- CONTAINERS_V_PRESET_SHRINK_CENTER,
- CONTAINERS_V_PRESET_SHRINK_END,
- };
-
- MenuButton *anchor_presets_menu = nullptr;
- PopupMenu *anchors_popup = nullptr;
- MenuButton *container_h_presets_menu = nullptr;
- MenuButton *container_v_presets_menu = nullptr;
-
+ ControlEditorPopupButton *anchors_button = nullptr;
+ ControlEditorPopupButton *containers_button = nullptr;
Button *anchor_mode_button = nullptr;
+ SizeFlagPresetPicker *container_h_picker = nullptr;
+ SizeFlagPresetPicker *container_v_picker = nullptr;
+
bool anchors_mode = false;
- void _set_anchors_preset(Control::LayoutPreset p_preset);
- void _set_anchors_and_offsets_preset(Control::LayoutPreset p_preset);
- void _set_anchors_and_offsets_to_keep_ratio();
- void _set_container_h_preset(Control::SizeFlags p_preset);
- void _set_container_v_preset(Control::SizeFlags p_preset);
+ void _anchors_preset_selected(int p_preset);
+ void _anchors_to_current_ratio();
+ void _anchor_mode_toggled(bool p_status);
+ void _container_flags_selected(int p_flags, bool p_vertical);
Vector2 _anchor_to_position(const Control *p_control, Vector2 anchor);
Vector2 _position_to_anchor(const Control *p_control, Vector2 position);
-
- void _button_toggle_anchor_mode(bool p_status);
-
bool _is_node_locked(const Node *p_node);
- List<Control *> _get_edited_controls(bool retrieve_locked = false, bool remove_controls_if_parent_in_selection = true);
- void _popup_callback(int p_op);
+ List<Control *> _get_edited_controls();
void _selection_changed();
protected:
@@ -236,6 +241,7 @@ public:
ControlEditorToolbar();
};
+// Editor plugin.
class ControlEditorPlugin : public EditorPlugin {
GDCLASS(ControlEditorPlugin, EditorPlugin);
diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
index a7c3c32120..e56fd5dfe3 100644
--- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
@@ -34,9 +34,10 @@
#include "core/io/image_loader.h"
#include "editor/editor_file_dialog.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/2d/cpu_particles_2d.h"
#include "scene/gui/separator.h"
-#include "scene/resources/particles_material.h"
+#include "scene/resources/particle_process_material.h"
void CPUParticles2DEditorPlugin::edit(Object *p_object) {
particles = Object::cast_to<CPUParticles2D>(p_object);
diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.h b/editor/plugins/cpu_particles_2d_editor_plugin.h
index cc59bc924f..06ca208463 100644
--- a/editor/plugins/cpu_particles_2d_editor_plugin.h
+++ b/editor/plugins/cpu_particles_2d_editor_plugin.h
@@ -39,6 +39,7 @@
class EditorPlugin;
class SpinBox;
class EditorFileDialog;
+class EditorUndoRedoManager;
class CPUParticles2DEditorPlugin : public EditorPlugin {
GDCLASS(CPUParticles2DEditorPlugin, EditorPlugin);
@@ -70,7 +71,7 @@ class CPUParticles2DEditorPlugin : public EditorPlugin {
String source_emission_file;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
void _file_selected(const String &p_file);
void _menu_callback(int p_idx);
void _generate_emission_mask();
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index 8aeab684e3..013a9f10a4 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -139,14 +139,14 @@ void CurveEditor::gui_input(const Ref<InputEvent> &p_event) {
if (!mb.is_pressed() && _dragging && mb.get_button_index() == MouseButton::LEFT) {
_dragging = false;
if (_has_undo_data) {
- UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
- ur.create_action(_selected_tangent == TANGENT_NONE ? TTR("Modify Curve Point") : TTR("Modify Curve Tangent"));
- ur.add_do_method(*_curve_ref, "_set_data", _curve_ref->get_data());
- ur.add_undo_method(*_curve_ref, "_set_data", _undo_data);
+ ur->create_action(_selected_tangent == TANGENT_NONE ? TTR("Modify Curve Point") : TTR("Modify Curve Tangent"));
+ ur->add_do_method(*_curve_ref, "_set_data", _curve_ref->get_data());
+ ur->add_undo_method(*_curve_ref, "_set_data", _undo_data);
// Note: this will trigger one more "changed" signal even if nothing changes,
// but it's ok since it would have fired every frame during the drag anyways
- ur.commit_action();
+ ur->commit_action();
_has_undo_data = false;
}
@@ -301,13 +301,13 @@ void CurveEditor::on_preset_item_selected(int preset_id) {
break;
}
- UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo();
- ur.create_action(TTR("Load Curve Preset"));
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ ur->create_action(TTR("Load Curve Preset"));
- ur.add_do_method(&curve, "_set_data", curve.get_data());
- ur.add_undo_method(&curve, "_set_data", previous_data);
+ ur->add_do_method(&curve, "_set_data", curve.get_data());
+ ur->add_undo_method(&curve, "_set_data", previous_data);
- ur.commit_action();
+ ur->commit_action();
}
void CurveEditor::_curve_changed() {
@@ -435,8 +435,8 @@ CurveEditor::TangentIndex CurveEditor::get_tangent_at(Vector2 pos) const {
void CurveEditor::add_point(Vector2 pos) {
ERR_FAIL_COND(_curve_ref.is_null());
- UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo();
- ur.create_action(TTR("Remove Curve Point"));
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ ur->create_action(TTR("Remove Curve Point"));
Vector2 point_pos = get_world_pos(pos);
if (point_pos.y < 0.0) {
@@ -449,22 +449,22 @@ void CurveEditor::add_point(Vector2 pos) {
int i = _curve_ref->add_point(point_pos);
_curve_ref->remove_point(i);
- ur.add_do_method(*_curve_ref, "add_point", point_pos);
- ur.add_undo_method(*_curve_ref, "remove_point", i);
+ ur->add_do_method(*_curve_ref, "add_point", point_pos);
+ ur->add_undo_method(*_curve_ref, "remove_point", i);
- ur.commit_action();
+ ur->commit_action();
}
void CurveEditor::remove_point(int index) {
ERR_FAIL_COND(_curve_ref.is_null());
- UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo();
- ur.create_action(TTR("Remove Curve Point"));
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ ur->create_action(TTR("Remove Curve Point"));
Curve::Point p = _curve_ref->get_point(index);
- ur.add_do_method(*_curve_ref, "remove_point", index);
- ur.add_undo_method(*_curve_ref, "add_point", p.position, p.left_tangent, p.right_tangent, p.left_mode, p.right_mode);
+ ur->add_do_method(*_curve_ref, "remove_point", index);
+ ur->add_undo_method(*_curve_ref, "add_point", p.position, p.left_tangent, p.right_tangent, p.left_mode, p.right_mode);
if (index == _selected_point) {
set_selected_point(-1);
@@ -474,14 +474,14 @@ void CurveEditor::remove_point(int index) {
set_hover_point_index(-1);
}
- ur.commit_action();
+ ur->commit_action();
}
void CurveEditor::toggle_linear(TangentIndex tangent) {
ERR_FAIL_COND(_curve_ref.is_null());
- UndoRedo &ur = *EditorNode::get_singleton()->get_undo_redo();
- ur.create_action(TTR("Toggle Curve Linear Tangent"));
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ ur->create_action(TTR("Toggle Curve Linear Tangent"));
if (tangent == TANGENT_NONE) {
tangent = _selected_tangent;
@@ -493,8 +493,8 @@ void CurveEditor::toggle_linear(TangentIndex tangent) {
Curve::TangentMode prev_mode = _curve_ref->get_point_left_mode(_selected_point);
Curve::TangentMode mode = is_linear ? Curve::TANGENT_FREE : Curve::TANGENT_LINEAR;
- ur.add_do_method(*_curve_ref, "set_point_left_mode", _selected_point, mode);
- ur.add_undo_method(*_curve_ref, "set_point_left_mode", _selected_point, prev_mode);
+ ur->add_do_method(*_curve_ref, "set_point_left_mode", _selected_point, mode);
+ ur->add_undo_method(*_curve_ref, "set_point_left_mode", _selected_point, prev_mode);
} else {
bool is_linear = _curve_ref->get_point_right_mode(_selected_point) == Curve::TANGENT_LINEAR;
@@ -502,11 +502,11 @@ void CurveEditor::toggle_linear(TangentIndex tangent) {
Curve::TangentMode prev_mode = _curve_ref->get_point_right_mode(_selected_point);
Curve::TangentMode mode = is_linear ? Curve::TANGENT_FREE : Curve::TANGENT_LINEAR;
- ur.add_do_method(*_curve_ref, "set_point_right_mode", _selected_point, mode);
- ur.add_undo_method(*_curve_ref, "set_point_right_mode", _selected_point, prev_mode);
+ ur->add_do_method(*_curve_ref, "set_point_right_mode", _selected_point, mode);
+ ur->add_undo_method(*_curve_ref, "set_point_right_mode", _selected_point, prev_mode);
}
- ur.commit_action();
+ ur->commit_action();
}
void CurveEditor::set_selected_point(int index) {
diff --git a/editor/plugins/debugger_editor_plugin.cpp b/editor/plugins/debugger_editor_plugin.cpp
index c572b5b7fe..40e7dfead2 100644
--- a/editor/plugins/debugger_editor_plugin.cpp
+++ b/editor/plugins/debugger_editor_plugin.cpp
@@ -40,7 +40,7 @@
#include "editor/plugins/script_editor_plugin.h"
#include "scene/gui/menu_button.h"
-DebuggerEditorPlugin::DebuggerEditorPlugin(MenuButton *p_debug_menu) {
+DebuggerEditorPlugin::DebuggerEditorPlugin(PopupMenu *p_debug_menu) {
EditorDebuggerServer::initialize();
ED_SHORTCUT("debugger/step_into", TTR("Step Into"), Key::F11);
@@ -61,30 +61,29 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(MenuButton *p_debug_menu) {
// Main editor debug menu.
debug_menu = p_debug_menu;
- 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(-1,
+ debug_menu->set_hide_on_checkable_item_selection(false);
+ debug_menu->add_check_shortcut(ED_SHORTCUT("editor/deploy_with_remote_debug", TTR("Deploy with Remote Debug")), RUN_DEPLOY_REMOTE_DEBUG);
+ debug_menu->set_item_tooltip(-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(-1,
+ debug_menu->add_check_shortcut(ED_SHORTCUT("editor/small_deploy_with_network_fs", TTR("Small Deploy with Network Filesystem")), RUN_FILE_SERVER);
+ debug_menu->set_item_tooltip(-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(-1,
+ debug_menu->add_separator();
+ debug_menu->add_check_shortcut(ED_SHORTCUT("editor/visible_collision_shapes", TTR("Visible Collision Shapes")), RUN_DEBUG_COLLISONS);
+ debug_menu->set_item_tooltip(-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_paths", TTR("Visible Paths")), RUN_DEBUG_PATHS);
- p->set_item_tooltip(-1,
+ debug_menu->add_check_shortcut(ED_SHORTCUT("editor/visible_paths", TTR("Visible Paths")), RUN_DEBUG_PATHS);
+ debug_menu->set_item_tooltip(-1,
TTR("When this option is enabled, curve resources used by path nodes 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(-1,
+ debug_menu->add_check_shortcut(ED_SHORTCUT("editor/visible_navigation", TTR("Visible Navigation")), RUN_DEBUG_NAVIGATION);
+ debug_menu->set_item_tooltip(-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("Synchronize Scene Changes")), RUN_LIVE_DEBUG);
- p->set_item_tooltip(-1,
+ debug_menu->add_separator();
+ debug_menu->add_check_shortcut(ED_SHORTCUT("editor/sync_scene_changes", TTR("Synchronize Scene Changes")), RUN_LIVE_DEBUG);
+ debug_menu->set_item_tooltip(-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(-1,
+ debug_menu->add_check_shortcut(ED_SHORTCUT("editor/sync_script_changes", TTR("Synchronize Script Changes")), RUN_RELOAD_SCRIPTS);
+ debug_menu->set_item_tooltip(-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
@@ -92,9 +91,9 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(MenuButton *p_debug_menu) {
instances_menu->set_name("run_instances");
instances_menu->set_hide_on_checkable_item_selection(false);
- p->add_child(instances_menu);
- p->add_separator();
- p->add_submenu_item(TTR("Run Multiple Instances"), "run_instances");
+ debug_menu->add_child(instances_menu);
+ debug_menu->add_separator();
+ debug_menu->add_submenu_item(TTR("Run Multiple Instances"), "run_instances");
instances_menu->add_radio_check_item(TTR("Run 1 Instance"));
instances_menu->set_item_metadata(0, 1);
@@ -106,7 +105,7 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(MenuButton *p_debug_menu) {
instances_menu->set_item_metadata(3, 4);
instances_menu->set_item_checked(0, true);
instances_menu->connect("index_pressed", callable_mp(this, &DebuggerEditorPlugin::_select_run_count));
- p->connect("id_pressed", callable_mp(this, &DebuggerEditorPlugin::_menu_option));
+ debug_menu->connect("id_pressed", callable_mp(this, &DebuggerEditorPlugin::_menu_option));
}
DebuggerEditorPlugin::~DebuggerEditorPlugin() {
@@ -125,7 +124,7 @@ void DebuggerEditorPlugin::_select_run_count(int p_index) {
void DebuggerEditorPlugin::_menu_option(int p_option) {
switch (p_option) {
case RUN_FILE_SERVER: {
- bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_FILE_SERVER));
+ bool ischecked = debug_menu->is_item_checked(debug_menu->get_item_index(RUN_FILE_SERVER));
if (ischecked) {
file_server->stop();
@@ -133,45 +132,45 @@ void DebuggerEditorPlugin::_menu_option(int p_option) {
file_server->start();
}
- debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_FILE_SERVER), !ischecked);
+ debug_menu->set_item_checked(debug_menu->get_item_index(RUN_FILE_SERVER), !ischecked);
EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_file_server", !ischecked);
} break;
case RUN_LIVE_DEBUG: {
- bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_LIVE_DEBUG));
+ bool ischecked = debug_menu->is_item_checked(debug_menu->get_item_index(RUN_LIVE_DEBUG));
- debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_LIVE_DEBUG), !ischecked);
+ debug_menu->set_item_checked(debug_menu->get_item_index(RUN_LIVE_DEBUG), !ischecked);
EditorDebuggerNode::get_singleton()->set_live_debugging(!ischecked);
EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_live_debug", !ischecked);
} break;
case RUN_DEPLOY_REMOTE_DEBUG: {
- bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEPLOY_REMOTE_DEBUG));
- debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEPLOY_REMOTE_DEBUG), !ischecked);
+ bool ischecked = debug_menu->is_item_checked(debug_menu->get_item_index(RUN_DEPLOY_REMOTE_DEBUG));
+ debug_menu->set_item_checked(debug_menu->get_item_index(RUN_DEPLOY_REMOTE_DEBUG), !ischecked);
EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_deploy_remote_debug", !ischecked);
} break;
case RUN_DEBUG_COLLISONS: {
- bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEBUG_COLLISONS));
- debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEBUG_COLLISONS), !ischecked);
+ bool ischecked = debug_menu->is_item_checked(debug_menu->get_item_index(RUN_DEBUG_COLLISONS));
+ debug_menu->set_item_checked(debug_menu->get_item_index(RUN_DEBUG_COLLISONS), !ischecked);
EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_debug_collisons", !ischecked);
} break;
case RUN_DEBUG_PATHS: {
- bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEBUG_PATHS));
- debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEBUG_PATHS), !ischecked);
+ bool ischecked = debug_menu->is_item_checked(debug_menu->get_item_index(RUN_DEBUG_PATHS));
+ debug_menu->set_item_checked(debug_menu->get_item_index(RUN_DEBUG_PATHS), !ischecked);
EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_debug_paths", !ischecked);
} break;
case RUN_DEBUG_NAVIGATION: {
- bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEBUG_NAVIGATION));
- debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEBUG_NAVIGATION), !ischecked);
+ bool ischecked = debug_menu->is_item_checked(debug_menu->get_item_index(RUN_DEBUG_NAVIGATION));
+ debug_menu->set_item_checked(debug_menu->get_item_index(RUN_DEBUG_NAVIGATION), !ischecked);
EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_debug_navigation", !ischecked);
} break;
case RUN_RELOAD_SCRIPTS: {
- bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_RELOAD_SCRIPTS));
- debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_RELOAD_SCRIPTS), !ischecked);
+ bool ischecked = debug_menu->is_item_checked(debug_menu->get_item_index(RUN_RELOAD_SCRIPTS));
+ debug_menu->set_item_checked(debug_menu->get_item_index(RUN_RELOAD_SCRIPTS), !ischecked);
ScriptEditor::get_singleton()->set_live_auto_reload_running_scripts(!ischecked);
EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_reload_scripts", !ischecked);
diff --git a/editor/plugins/debugger_editor_plugin.h b/editor/plugins/debugger_editor_plugin.h
index fb963385cd..d8871128c3 100644
--- a/editor/plugins/debugger_editor_plugin.h
+++ b/editor/plugins/debugger_editor_plugin.h
@@ -41,7 +41,7 @@ class DebuggerEditorPlugin : public EditorPlugin {
GDCLASS(DebuggerEditorPlugin, EditorPlugin);
private:
- MenuButton *debug_menu = nullptr;
+ PopupMenu *debug_menu = nullptr;
EditorFileServer *file_server = nullptr;
PopupMenu *instances_menu = nullptr;
@@ -64,7 +64,7 @@ public:
virtual String get_name() const override { return "Debugger"; }
bool has_main_screen() const override { return false; }
- DebuggerEditorPlugin(MenuButton *p_menu);
+ DebuggerEditorPlugin(PopupMenu *p_menu);
~DebuggerEditorPlugin();
};
diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp
index 0196214ceb..f4a718119e 100644
--- a/editor/plugins/editor_preview_plugins.cpp
+++ b/editor/plugins/editor_preview_plugins.cpp
@@ -255,7 +255,7 @@ Ref<Texture2D> EditorPackedScenePreviewPlugin::generate(const Ref<Resource> &p_f
Ref<Texture2D> EditorPackedScenePreviewPlugin::generate_from_path(const String &p_path, const Size2 &p_size) const {
String temp_path = EditorPaths::get_singleton()->get_cache_dir();
String cache_base = ProjectSettings::get_singleton()->globalize_path(p_path).md5_text();
- cache_base = temp_path.plus_file("resthumb-" + cache_base);
+ cache_base = temp_path.path_join("resthumb-" + cache_base);
//does not have it, try to load a cached thumbnail
diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp
index cadb974345..935b0a5501 100644
--- a/editor/plugins/font_config_plugin.cpp
+++ b/editor/plugins/font_config_plugin.cpp
@@ -100,11 +100,6 @@ bool EditorPropertyFontOTObject::_get(const StringName &p_name, Variant &r_ret)
return false;
}
-void EditorPropertyFontOTObject::_bind_methods() {
- ClassDB::bind_method(D_METHOD("property_can_revert", "name"), &EditorPropertyFontOTObject::property_can_revert);
- ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &EditorPropertyFontOTObject::property_get_revert);
-}
-
void EditorPropertyFontOTObject::set_dict(const Dictionary &p_dict) {
dict = p_dict;
}
@@ -121,7 +116,7 @@ Dictionary EditorPropertyFontOTObject::get_defaults() {
return defaults_dict;
}
-bool EditorPropertyFontOTObject::property_can_revert(const String &p_name) {
+bool EditorPropertyFontOTObject::_property_can_revert(const StringName &p_name) const {
String name = p_name;
if (name.begins_with("keys")) {
@@ -136,18 +131,19 @@ bool EditorPropertyFontOTObject::property_can_revert(const String &p_name) {
return false;
}
-Variant EditorPropertyFontOTObject::property_get_revert(const String &p_name) {
+bool EditorPropertyFontOTObject::_property_get_revert(const StringName &p_name, Variant &r_property) const {
String name = p_name;
if (name.begins_with("keys")) {
int key = name.get_slicec('/', 1).to_int();
if (defaults_dict.has(key)) {
Vector3i range = defaults_dict[key];
- return range.z;
+ r_property = range.z;
+ return true;
}
}
- return Variant();
+ return false;
}
/*************************************************************************/
@@ -294,7 +290,7 @@ void EditorPropertyFontMetaOverride::update_property() {
} else {
prop->set_label(TranslationServer::get_singleton()->get_locale_name(name));
}
- prop->set_tooltip(name);
+ prop->set_tooltip_text(name);
prop->set_selectable(false);
prop->connect("property_changed", callable_mp(this, &EditorPropertyFontMetaOverride::_property_changed));
@@ -491,7 +487,7 @@ void EditorPropertyOTVariation::update_property() {
String name = TS->tag_to_name(name_tag);
prop->set_label(name.capitalize());
- prop->set_tooltip(name);
+ prop->set_tooltip_text(name);
prop->set_selectable(false);
prop->connect("property_changed", callable_mp(this, &EditorPropertyOTVariation::_property_changed));
@@ -770,7 +766,7 @@ void EditorPropertyOTFeatures::update_property() {
disp_name = vformat("%s (%s)", disp_name, info["label"].operator String());
}
prop->set_label(disp_name);
- prop->set_tooltip(name);
+ prop->set_tooltip_text(name);
prop->set_selectable(false);
prop->connect("property_changed", callable_mp(this, &EditorPropertyOTFeatures::_property_changed));
diff --git a/editor/plugins/font_config_plugin.h b/editor/plugins/font_config_plugin.h
index 3eaa2fdc17..41dde3cc59 100644
--- a/editor/plugins/font_config_plugin.h
+++ b/editor/plugins/font_config_plugin.h
@@ -66,7 +66,8 @@ class EditorPropertyFontOTObject : public RefCounted {
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
- static void _bind_methods();
+ bool _property_can_revert(const StringName &p_name) const;
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
public:
void set_dict(const Dictionary &p_dict);
@@ -75,9 +76,6 @@ public:
void set_defaults(const Dictionary &p_dict);
Dictionary get_defaults();
- bool property_can_revert(const String &p_name);
- Variant property_get_revert(const String &p_name);
-
EditorPropertyFontOTObject(){};
};
diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
index 8e6687c836..e2d19c34e6 100644
--- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
@@ -34,10 +34,11 @@
#include "core/io/image_loader.h"
#include "editor/editor_file_dialog.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/scene_tree_dock.h"
#include "scene/2d/cpu_particles_2d.h"
#include "scene/gui/separator.h"
-#include "scene/resources/particles_material.h"
+#include "scene/resources/particle_process_material.h"
void GPUParticles2DEditorPlugin::edit(Object *p_object) {
particles = Object::cast_to<GPUParticles2D>(p_object);
@@ -111,7 +112,7 @@ void GPUParticles2DEditorPlugin::_menu_callback(int p_idx) {
cpu_particles->set_process_mode(particles->get_process_mode());
cpu_particles->set_z_index(particles->get_z_index());
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Convert to CPUParticles2D"));
ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", particles, cpu_particles, true, false);
ur->add_do_reference(cpu_particles);
@@ -166,9 +167,9 @@ void GPUParticles2DEditorPlugin::_generate_visibility_rect() {
}
void GPUParticles2DEditorPlugin::_generate_emission_mask() {
- Ref<ParticlesMaterial> pm = particles->get_process_material();
+ Ref<ParticleProcessMaterial> pm = particles->get_process_material();
if (!pm.is_valid()) {
- EditorNode::get_singleton()->show_warning(TTR("Can only set point into a ParticlesMaterial process material"));
+ EditorNode::get_singleton()->show_warning(TTR("Can only set point into a ParticleProcessMaterial process material"));
return;
}
@@ -319,7 +320,7 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() {
}
if (valid_normals.size()) {
- pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_DIRECTED_POINTS);
+ pm->set_emission_shape(ParticleProcessMaterial::EMISSION_SHAPE_DIRECTED_POINTS);
Vector<uint8_t> normdata;
normdata.resize(w * h * 2 * sizeof(float)); //use RG texture
@@ -338,7 +339,7 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() {
pm->set_emission_normal_texture(ImageTexture::create_from_image(img));
} else {
- pm->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS);
+ pm->set_emission_shape(ParticleProcessMaterial::EMISSION_SHAPE_POINTS);
}
}
diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.h b/editor/plugins/gpu_particles_2d_editor_plugin.h
index bf49a82166..0229b57c10 100644
--- a/editor/plugins/gpu_particles_2d_editor_plugin.h
+++ b/editor/plugins/gpu_particles_2d_editor_plugin.h
@@ -38,6 +38,7 @@
#include "scene/gui/spin_box.h"
class EditorFileDialog;
+class EditorUndoRedoManager;
class GPUParticles2DEditorPlugin : public EditorPlugin {
GDCLASS(GPUParticles2DEditorPlugin, EditorPlugin);
@@ -75,7 +76,7 @@ class GPUParticles2DEditorPlugin : public EditorPlugin {
String source_emission_file;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
void _file_selected(const String &p_file);
void _menu_callback(int p_idx);
void _generate_visibility_rect();
diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
index 6750f1aa9c..ebc92bf531 100644
--- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
@@ -32,10 +32,11 @@
#include "core/io/resource_loader.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "editor/scene_tree_dock.h"
#include "scene/3d/cpu_particles_3d.h"
-#include "scene/resources/particles_material.h"
+#include "scene/resources/particle_process_material.h"
bool GPUParticles3DEditorBase::_generate(Vector<Vector3> &points, Vector<Vector3> &normals) {
bool use_normals = emission_fill->get_selected() == 1;
@@ -254,9 +255,9 @@ void GPUParticles3DEditor::_menu_option(int p_option) {
}
} break;
case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE: {
- Ref<ParticlesMaterial> material = node->get_process_material();
+ Ref<ParticleProcessMaterial> material = node->get_process_material();
if (material.is_null()) {
- EditorNode::get_singleton()->show_warning(TTR("A processor material of type 'ParticlesMaterial' is required."));
+ EditorNode::get_singleton()->show_warning(TTR("A processor material of type 'ParticleProcessMaterial' is required."));
return;
}
@@ -271,7 +272,7 @@ void GPUParticles3DEditor::_menu_option(int p_option) {
cpu_particles->set_visible(node->is_visible());
cpu_particles->set_process_mode(node->get_process_mode());
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Convert to CPUParticles3D"));
ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", node, cpu_particles, true, false);
ur->add_do_reference(cpu_particles);
@@ -321,7 +322,7 @@ void GPUParticles3DEditor::_generate_aabb() {
node->set_emitting(false);
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Generate Visibility AABB"));
ur->add_do_method(node, "set_visibility_aabb", rect);
ur->add_undo_method(node, "set_visibility_aabb", node->get_visibility_aabb());
@@ -365,11 +366,11 @@ void GPUParticles3DEditor::_generate_emission_points() {
Ref<Image> image = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img));
Ref<ImageTexture> tex = ImageTexture::create_from_image(image);
- Ref<ParticlesMaterial> material = node->get_process_material();
+ Ref<ParticleProcessMaterial> material = node->get_process_material();
ERR_FAIL_COND(material.is_null());
if (normals.size() > 0) {
- material->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_DIRECTED_POINTS);
+ material->set_emission_shape(ParticleProcessMaterial::EMISSION_SHAPE_DIRECTED_POINTS);
material->set_emission_point_count(point_count);
material->set_emission_point_texture(tex);
@@ -391,7 +392,7 @@ void GPUParticles3DEditor::_generate_emission_points() {
Ref<Image> image2 = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img2));
material->set_emission_normal_texture(ImageTexture::create_from_image(image2));
} else {
- material->set_emission_shape(ParticlesMaterial::EMISSION_SHAPE_POINTS);
+ material->set_emission_shape(ParticleProcessMaterial::EMISSION_SHAPE_POINTS);
material->set_emission_point_count(point_count);
material->set_emission_point_texture(tex);
}
diff --git a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp
index 643a470425..59d665342f 100644
--- a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp
@@ -101,7 +101,7 @@ void GPUParticlesCollisionSDF3DEditorPlugin::_notification(int p_what) {
return;
}
- bake->set_tooltip(text);
+ bake->set_tooltip_text(text);
} break;
}
}
@@ -140,7 +140,7 @@ void GPUParticlesCollisionSDF3DEditorPlugin::_sdf_save_path_and_bake(const Strin
if (col_sdf) {
Ref<Image> bake_img = col_sdf->bake();
if (bake_img.is_null()) {
- EditorNode::get_singleton()->show_warning(TTR("Bake Error."));
+ EditorNode::get_singleton()->show_warning(TTR("No faces detected during GPUParticlesCollisionSDF3D bake.\nCheck whether there are visible meshes matching the bake mask within its extents."));
return;
}
diff --git a/editor/plugins/gradient_editor_plugin.cpp b/editor/plugins/gradient_editor_plugin.cpp
index 542aee879b..f368d5bea1 100644
--- a/editor/plugins/gradient_editor_plugin.cpp
+++ b/editor/plugins/gradient_editor_plugin.cpp
@@ -34,6 +34,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "node_3d_editor_plugin.h"
Size2 GradientEditor::get_minimum_size() const {
@@ -55,7 +56,7 @@ void GradientEditor::_gradient_changed() {
void GradientEditor::_ramp_changed() {
editing = true;
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
undo_redo->create_action(TTR("Gradient Edited"), UndoRedo::MERGE_ENDS);
undo_redo->add_do_method(gradient.ptr(), "set_offsets", get_offsets());
undo_redo->add_do_method(gradient.ptr(), "set_colors", get_colors());
@@ -134,7 +135,7 @@ void EditorInspectorPluginGradient::parse_begin(Object *p_object) {
add_custom_control(gradient_tools_hbox);
reverse_btn->connect("pressed", callable_mp(this, &EditorInspectorPluginGradient::_reverse_button_pressed));
- reverse_btn->set_tooltip(TTR("Reverse/mirror gradient."));
+ reverse_btn->set_tooltip_text(TTR("Reverse/mirror gradient."));
}
void EditorInspectorPluginGradient::_reverse_button_pressed() {
diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.cpp b/editor/plugins/gradient_texture_2d_editor_plugin.cpp
index df45d6c290..5aaf450d3f 100644
--- a/editor/plugins/gradient_texture_2d_editor_plugin.cpp
+++ b/editor/plugins/gradient_texture_2d_editor_plugin.cpp
@@ -32,6 +32,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/box_container.h"
#include "scene/gui/flow_container.h"
#include "scene/gui/separator.h"
@@ -175,7 +176,7 @@ void GradientTexture2DEditorRect::_notification(int p_what) {
}
GradientTexture2DEditorRect::GradientTexture2DEditorRect() {
- undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ undo_redo = EditorNode::get_undo_redo();
checkerboard = memnew(TextureRect);
checkerboard->set_stretch_mode(TextureRect::STRETCH_TILE);
@@ -222,20 +223,20 @@ void GradientTexture2DEditor::_notification(int p_what) {
}
GradientTexture2DEditor::GradientTexture2DEditor() {
- undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ undo_redo = EditorNode::get_undo_redo();
HFlowContainer *toolbar = memnew(HFlowContainer);
add_child(toolbar);
reverse_button = memnew(Button);
- reverse_button->set_tooltip(TTR("Swap Gradient Fill Points"));
+ reverse_button->set_tooltip_text(TTR("Swap Gradient Fill Points"));
toolbar->add_child(reverse_button);
reverse_button->connect("pressed", callable_mp(this, &GradientTexture2DEditor::_reverse_button_pressed));
toolbar->add_child(memnew(VSeparator));
snap_button = memnew(Button);
- snap_button->set_tooltip(TTR("Toggle Grid Snap"));
+ snap_button->set_tooltip_text(TTR("Toggle Grid Snap"));
snap_button->set_toggle_mode(true);
toolbar->add_child(snap_button);
snap_button->connect("toggled", callable_mp(this, &GradientTexture2DEditor::_set_snap_enabled));
diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.h b/editor/plugins/gradient_texture_2d_editor_plugin.h
index 93c49b1e6f..9faf33152a 100644
--- a/editor/plugins/gradient_texture_2d_editor_plugin.h
+++ b/editor/plugins/gradient_texture_2d_editor_plugin.h
@@ -34,6 +34,8 @@
#include "editor/editor_plugin.h"
#include "editor/editor_spin_slider.h"
+class EditorUndoRedoManager;
+
class GradientTexture2DEditorRect : public Control {
GDCLASS(GradientTexture2DEditorRect, Control);
@@ -44,7 +46,7 @@ class GradientTexture2DEditorRect : public Control {
};
Ref<GradientTexture2D> texture;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
bool snap_enabled = false;
float snap_size = 0;
@@ -74,7 +76,7 @@ class GradientTexture2DEditor : public VBoxContainer {
GDCLASS(GradientTexture2DEditor, VBoxContainer);
Ref<GradientTexture2D> texture;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
Button *reverse_button = nullptr;
Button *snap_button = nullptr;
diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp
index 00fc8cc7d6..74a6e90a6d 100644
--- a/editor/plugins/material_editor_plugin.cpp
+++ b/editor/plugins/material_editor_plugin.cpp
@@ -33,9 +33,10 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/subviewport_container.h"
#include "scene/resources/fog_material.h"
-#include "scene/resources/particles_material.h"
+#include "scene/resources/particle_process_material.h"
#include "scene/resources/sky_material.h"
void MaterialEditor::_notification(int p_what) {
@@ -178,8 +179,8 @@ MaterialEditor::MaterialEditor() {
viewport->add_child(box_instance);
Transform3D box_xform;
- box_xform.basis.rotate(Vector3(1, 0, 0), Math::deg2rad(25.0));
- box_xform.basis = box_xform.basis * Basis().rotated(Vector3(0, 1, 0), Math::deg2rad(-25.0));
+ box_xform.basis.rotate(Vector3(1, 0, 0), Math::deg_to_rad(25.0));
+ box_xform.basis = box_xform.basis * Basis().rotated(Vector3(0, 1, 0), Math::deg_to_rad(-25.0));
box_xform.basis.scale(Vector3(0.7, 0.7, 0.7));
box_xform.origin.y = 0.05;
box_instance->set_transform(box_xform);
@@ -261,10 +262,8 @@ void EditorInspectorPluginMaterial::parse_begin(Object *p_object) {
}
void EditorInspectorPluginMaterial::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) {
- UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo);
- if (!undo_redo) {
- return;
- }
+ Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_COND(!undo_redo.is_valid());
// For BaseMaterial3D, if a roughness or metallic textures is being assigned to an empty slot,
// set the respective metallic or roughness factor to 1.0 as a convenience feature
@@ -340,17 +339,17 @@ Ref<Resource> StandardMaterial3DConversionPlugin::convert(const Ref<Resource> &p
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
for (const PropertyInfo &E : params) {
// Texture parameter has to be treated specially since StandardMaterial3D saved it
// as RID but ShaderMaterial needs Texture itself
Ref<Texture2D> texture = mat->get_texture_by_name(E.name);
if (texture.is_valid()) {
- smat->set_shader_param(E.name, texture);
+ smat->set_shader_uniform(E.name, texture);
} else {
Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
- smat->set_shader_param(E.name, value);
+ smat->set_shader_uniform(E.name, value);
}
}
@@ -386,17 +385,17 @@ Ref<Resource> ORMMaterial3DConversionPlugin::convert(const Ref<Resource> &p_reso
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
for (const PropertyInfo &E : params) {
// Texture parameter has to be treated specially since ORMMaterial3D saved it
// as RID but ShaderMaterial needs Texture itself
Ref<Texture2D> texture = mat->get_texture_by_name(E.name);
if (texture.is_valid()) {
- smat->set_shader_param(E.name, texture);
+ smat->set_shader_uniform(E.name, texture);
} else {
Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
- smat->set_shader_param(E.name, value);
+ smat->set_shader_uniform(E.name, value);
}
}
@@ -406,17 +405,17 @@ Ref<Resource> ORMMaterial3DConversionPlugin::convert(const Ref<Resource> &p_reso
return smat;
}
-String ParticlesMaterialConversionPlugin::converts_to() const {
+String ParticleProcessMaterialConversionPlugin::converts_to() const {
return "ShaderMaterial";
}
-bool ParticlesMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const {
- Ref<ParticlesMaterial> mat = p_resource;
+bool ParticleProcessMaterialConversionPlugin::handles(const Ref<Resource> &p_resource) const {
+ Ref<ParticleProcessMaterial> mat = p_resource;
return mat.is_valid();
}
-Ref<Resource> ParticlesMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const {
- Ref<ParticlesMaterial> mat = p_resource;
+Ref<Resource> ParticleProcessMaterialConversionPlugin::convert(const Ref<Resource> &p_resource) const {
+ Ref<ParticleProcessMaterial> mat = p_resource;
ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>());
Ref<ShaderMaterial> smat;
@@ -432,11 +431,11 @@ Ref<Resource> ParticlesMaterialConversionPlugin::convert(const Ref<Resource> &p_
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
for (const PropertyInfo &E : params) {
Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
- smat->set_shader_param(E.name, value);
+ smat->set_shader_uniform(E.name, value);
}
smat->set_render_priority(mat->get_render_priority());
@@ -471,11 +470,11 @@ Ref<Resource> CanvasItemMaterialConversionPlugin::convert(const Ref<Resource> &p
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
for (const PropertyInfo &E : params) {
Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
- smat->set_shader_param(E.name, value);
+ smat->set_shader_uniform(E.name, value);
}
smat->set_render_priority(mat->get_render_priority());
@@ -510,11 +509,11 @@ Ref<Resource> ProceduralSkyMaterialConversionPlugin::convert(const Ref<Resource>
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
for (const PropertyInfo &E : params) {
Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
- smat->set_shader_param(E.name, value);
+ smat->set_shader_uniform(E.name, value);
}
smat->set_render_priority(mat->get_render_priority());
@@ -549,11 +548,11 @@ Ref<Resource> PanoramaSkyMaterialConversionPlugin::convert(const Ref<Resource> &
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
for (const PropertyInfo &E : params) {
Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
- smat->set_shader_param(E.name, value);
+ smat->set_shader_uniform(E.name, value);
}
smat->set_render_priority(mat->get_render_priority());
@@ -588,11 +587,11 @@ Ref<Resource> PhysicalSkyMaterialConversionPlugin::convert(const Ref<Resource> &
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
for (const PropertyInfo &E : params) {
Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
- smat->set_shader_param(E.name, value);
+ smat->set_shader_uniform(E.name, value);
}
smat->set_render_priority(mat->get_render_priority());
@@ -627,11 +626,11 @@ Ref<Resource> FogMaterialConversionPlugin::convert(const Ref<Resource> &p_resour
smat->set_shader(shader);
List<PropertyInfo> params;
- RS::get_singleton()->shader_get_param_list(mat->get_shader_rid(), &params);
+ RS::get_singleton()->shader_get_shader_uniform_list(mat->get_shader_rid(), &params);
for (const PropertyInfo &E : params) {
Variant value = RS::get_singleton()->material_get_param(mat->get_rid(), E.name);
- smat->set_shader_param(E.name, value);
+ smat->set_shader_uniform(E.name, value);
}
smat->set_render_priority(mat->get_render_priority());
diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h
index fc3da5fd9f..06ae43e6d7 100644
--- a/editor/plugins/material_editor_plugin.h
+++ b/editor/plugins/material_editor_plugin.h
@@ -122,8 +122,8 @@ public:
virtual Ref<Resource> convert(const Ref<Resource> &p_resource) const override;
};
-class ParticlesMaterialConversionPlugin : public EditorResourceConversionPlugin {
- GDCLASS(ParticlesMaterialConversionPlugin, EditorResourceConversionPlugin);
+class ParticleProcessMaterialConversionPlugin : public EditorResourceConversionPlugin {
+ GDCLASS(ParticleProcessMaterialConversionPlugin, EditorResourceConversionPlugin);
public:
virtual String converts_to() const override;
diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp
index 31c9f1e387..980d2974a0 100644
--- a/editor/plugins/mesh_editor_plugin.cpp
+++ b/editor/plugins/mesh_editor_plugin.cpp
@@ -77,8 +77,8 @@ void MeshEditor::edit(Ref<Mesh> p_mesh) {
mesh = p_mesh;
mesh_instance->set_mesh(mesh);
- rot_x = Math::deg2rad(-15.0);
- rot_y = Math::deg2rad(30.0);
+ rot_x = Math::deg_to_rad(-15.0);
+ rot_y = Math::deg_to_rad(30.0);
_update_rotation();
AABB aabb = mesh->get_aabb();
diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
index 5fb885ad1f..7bd406b869 100644
--- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp
+++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
@@ -32,6 +32,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "node_3d_editor_plugin.h"
#include "scene/3d/collision_shape_3d.h"
#include "scene/3d/navigation_region_3d.h"
@@ -60,7 +61,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
switch (p_option) {
case MENU_OPTION_CREATE_STATIC_TRIMESH_BODY: {
EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
List<Node *> selection = editor_selection->get_selected_node_list();
@@ -147,7 +148,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
Node *owner = get_tree()->get_edited_scene_root();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Create Trimesh Static Shape"));
@@ -177,7 +178,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
err_dialog->popup_centered();
return;
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
if (simplify) {
ur->create_action(TTR("Create Simplified Convex Shape"));
@@ -217,7 +218,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
err_dialog->popup_centered();
return;
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Create Multiple Convex Shapes"));
@@ -254,7 +255,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
Node *owner = get_tree()->get_edited_scene_root();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Create Navigation Mesh"));
ur->add_do_method(node, "add_child", nmi, true);
@@ -311,7 +312,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
return;
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Unwrap UV2"));
ur->add_do_method(node, "set_mesh", unwrapped_mesh);
@@ -470,7 +471,7 @@ void MeshInstance3DEditor::_create_outline_mesh() {
mi->set_mesh(mesho);
Node *owner = get_tree()->get_edited_scene_root();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Create Outline"));
diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp
index 0070226d40..878f8c9a95 100644
--- a/editor/plugins/node_3d_editor_gizmos.cpp
+++ b/editor/plugins/node_3d_editor_gizmos.cpp
@@ -35,6 +35,7 @@
#include "core/math/geometry_3d.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/audio_listener_3d.h"
#include "scene/3d/audio_stream_player_3d.h"
@@ -51,14 +52,14 @@
#include "scene/3d/light_3d.h"
#include "scene/3d/lightmap_gi.h"
#include "scene/3d/lightmap_probe.h"
+#include "scene/3d/marker_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/navigation_region_3d.h"
#include "scene/3d/occluder_instance_3d.h"
-#include "scene/3d/position_3d.h"
#include "scene/3d/ray_cast_3d.h"
#include "scene/3d/reflection_probe.h"
#include "scene/3d/shape_cast_3d.h"
-#include "scene/3d/soft_dynamic_body_3d.h"
+#include "scene/3d/soft_body_3d.h"
#include "scene/3d/spring_arm_3d.h"
#include "scene/3d/sprite_3d.h"
#include "scene/3d/vehicle_body_3d.h"
@@ -1294,7 +1295,7 @@ static float _find_closest_angle_to_half_pi_arc(const Vector3 &p_from, const Vec
//min_p = p_arc_xform.affine_inverse().xform(min_p);
float a = (Math_PI * 0.5) - Vector2(min_p.x, -min_p.z).angle();
- return Math::rad2deg(a);
+ return Math::rad_to_deg(a);
}
void Light3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
@@ -1347,13 +1348,13 @@ void Light3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_i
light->set_param(p_id == 0 ? Light3D::PARAM_RANGE : Light3D::PARAM_SPOT_ANGLE, p_restore);
} else if (p_id == 0) {
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Light Radius"));
ur->add_do_method(light, "set_param", Light3D::PARAM_RANGE, light->get_param(Light3D::PARAM_RANGE));
ur->add_undo_method(light, "set_param", Light3D::PARAM_RANGE, p_restore);
ur->commit_action();
} else if (p_id == 1) {
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Light Radius"));
ur->add_do_method(light, "set_param", Light3D::PARAM_SPOT_ANGLE, light->get_param(Light3D::PARAM_SPOT_ANGLE));
ur->add_undo_method(light, "set_param", Light3D::PARAM_SPOT_ANGLE, p_restore);
@@ -1420,8 +1421,8 @@ void Light3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
for (int i = 0; i < 120; i++) {
// Create a circle
- const float ra = Math::deg2rad((float)(i * 3));
- const float rb = Math::deg2rad((float)((i + 1) * 3));
+ const float ra = Math::deg_to_rad((float)(i * 3));
+ const float rb = Math::deg_to_rad((float)((i + 1) * 3));
const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
@@ -1457,13 +1458,13 @@ void Light3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
SpotLight3D *sl = Object::cast_to<SpotLight3D>(light);
float r = sl->get_param(Light3D::PARAM_RANGE);
- float w = r * Math::sin(Math::deg2rad(sl->get_param(Light3D::PARAM_SPOT_ANGLE)));
- float d = r * Math::cos(Math::deg2rad(sl->get_param(Light3D::PARAM_SPOT_ANGLE)));
+ float w = r * Math::sin(Math::deg_to_rad(sl->get_param(Light3D::PARAM_SPOT_ANGLE)));
+ float d = r * Math::cos(Math::deg_to_rad(sl->get_param(Light3D::PARAM_SPOT_ANGLE)));
for (int i = 0; i < 120; i++) {
// Draw a circle
- const float ra = Math::deg2rad((float)(i * 3));
- const float rb = Math::deg2rad((float)((i + 1) * 3));
+ const float ra = Math::deg_to_rad((float)(i * 3));
+ const float rb = Math::deg_to_rad((float)((i + 1) * 3));
const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w;
const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w;
@@ -1544,8 +1545,8 @@ void AudioStreamPlayer3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo
float closest_angle = 1e20;
for (int i = 0; i < 180; i++) {
- float a = Math::deg2rad((float)i);
- float an = Math::deg2rad((float)(i + 1));
+ float a = Math::deg_to_rad((float)i);
+ float an = Math::deg_to_rad((float)(i + 1));
Vector3 from(Math::sin(a), 0, -Math::cos(a));
Vector3 to(Math::sin(an), 0, -Math::cos(an));
@@ -1571,7 +1572,7 @@ void AudioStreamPlayer3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gi
player->set_emission_angle(p_restore);
} else {
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change AudioStreamPlayer3D Emission Angle"));
ur->add_do_method(player, "set_emission_angle", player->get_emission_angle());
ur->add_undo_method(player, "set_emission_angle", p_restore);
@@ -1627,8 +1628,8 @@ void AudioStreamPlayer3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
for (int i = 0; i < 120; i++) {
// Create a circle.
- const float ra = Math::deg2rad((float)(i * 3));
- const float rb = Math::deg2rad((float)((i + 1) * 3));
+ const float ra = Math::deg_to_rad((float)(i * 3));
+ const float rb = Math::deg_to_rad((float)((i + 1) * 3));
const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
@@ -1670,8 +1671,8 @@ void AudioStreamPlayer3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
if (player->is_emission_angle_enabled()) {
const float pc = player->get_emission_angle();
- const float ofs = -Math::cos(Math::deg2rad(pc));
- const float radius = Math::sin(Math::deg2rad(pc));
+ const float ofs = -Math::cos(Math::deg_to_rad(pc));
+ const float radius = Math::sin(Math::deg_to_rad(pc));
Vector<Vector3> points_primary;
points_primary.resize(200);
@@ -1706,7 +1707,7 @@ void AudioStreamPlayer3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_lines(points_secondary, material_secondary);
Vector<Vector3> handles;
- const float ha = Math::deg2rad(player->get_emission_angle());
+ const float ha = Math::deg_to_rad(player->get_emission_angle());
handles.push_back(Vector3(Math::sin(ha), 0, -Math::cos(ha)));
p_gizmo->add_handles(handles, get_material("handles"));
}
@@ -1814,7 +1815,7 @@ void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_
if (p_cancel) {
camera->set("fov", p_restore);
} else {
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Camera FOV"));
ur->add_do_property(camera, "fov", camera->get_fov());
ur->add_undo_property(camera, "fov", p_restore);
@@ -1825,7 +1826,7 @@ void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_
if (p_cancel) {
camera->set("size", p_restore);
} else {
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Camera Size"));
ur->add_do_property(camera, "size", camera->get_size());
ur->add_undo_property(camera, "size", p_restore);
@@ -1871,7 +1872,7 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
// The real FOV is halved for accurate representation
float fov = camera->get_fov() / 2.0;
- Vector3 side = Vector3(Math::sin(Math::deg2rad(fov)), 0, -Math::cos(Math::deg2rad(fov)));
+ Vector3 side = Vector3(Math::sin(Math::deg_to_rad(fov)), 0, -Math::cos(Math::deg_to_rad(fov)));
Vector3 nside = side;
nside.x = -nside.x;
Vector3 up = Vector3(0, side.x, 0);
@@ -1943,7 +1944,7 @@ MeshInstance3DGizmoPlugin::MeshInstance3DGizmoPlugin() {
}
bool MeshInstance3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
- return Object::cast_to<MeshInstance3D>(p_spatial) != nullptr && Object::cast_to<SoftDynamicBody3D>(p_spatial) == nullptr;
+ return Object::cast_to<MeshInstance3D>(p_spatial) != nullptr && Object::cast_to<SoftBody3D>(p_spatial) == nullptr;
}
String MeshInstance3DGizmoPlugin::get_gizmo_name() const {
@@ -2141,7 +2142,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Sphere Shape Radius"));
ur->add_do_method(so.ptr(), "set_radius", so->get_radius());
ur->add_undo_method(so.ptr(), "set_radius", p_restore);
@@ -2155,7 +2156,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Box Shape Size"));
ur->add_do_method(bo.ptr(), "set_size", bo->get_size());
ur->add_undo_method(bo.ptr(), "set_size", p_restore);
@@ -2169,7 +2170,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Box Shape Size"));
ur->add_do_method(qo.ptr(), "set_size", qo->get_size());
ur->add_undo_method(qo.ptr(), "set_size", p_restore);
@@ -2291,7 +2292,7 @@ void Label3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
///
-Position3DGizmoPlugin::Position3DGizmoPlugin() {
+Marker3DGizmoPlugin::Marker3DGizmoPlugin() {
pos3d_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
cursor_points = Vector<Vector3>();
@@ -2315,7 +2316,7 @@ Position3DGizmoPlugin::Position3DGizmoPlugin() {
// Use the axis color which is brighter for the positive axis.
// Use a darkened axis color for the negative axis.
- // This makes it possible to see in which direction the Position3D node is rotated
+ // This makes it possible to see in which direction the Marker3D node is rotated
// (which can be important depending on how it's used).
const Color color_x = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("axis_x_color"), SNAME("Editor"));
cursor_colors.push_back(color_x);
@@ -2351,19 +2352,19 @@ Position3DGizmoPlugin::Position3DGizmoPlugin() {
pos3d_mesh->surface_set_material(0, mat);
}
-bool Position3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
- return Object::cast_to<Position3D>(p_spatial) != nullptr;
+bool Marker3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<Marker3D>(p_spatial) != nullptr;
}
-String Position3DGizmoPlugin::get_gizmo_name() const {
- return "Position3D";
+String Marker3DGizmoPlugin::get_gizmo_name() const {
+ return "Marker3D";
}
-int Position3DGizmoPlugin::get_priority() const {
+int Marker3DGizmoPlugin::get_priority() const {
return -1;
}
-void Position3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+void Marker3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->clear();
p_gizmo->add_mesh(pos3d_mesh);
p_gizmo->add_collision_segments(cursor_points);
@@ -2642,8 +2643,8 @@ void VehicleWheel3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
float r = car_wheel->get_radius();
const int skip = 10;
for (int i = 0; i <= 360; i += skip) {
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + skip);
+ float ra = Math::deg_to_rad((float)i);
+ float rb = Math::deg_to_rad((float)i + skip);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
@@ -2686,30 +2687,30 @@ void VehicleWheel3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
///////////
-SoftDynamicBody3DGizmoPlugin::SoftDynamicBody3DGizmoPlugin() {
+SoftBody3DGizmoPlugin::SoftBody3DGizmoPlugin() {
Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape");
create_material("shape_material", gizmo_color);
create_handle_material("handles");
}
-bool SoftDynamicBody3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
- return Object::cast_to<SoftDynamicBody3D>(p_spatial) != nullptr;
+bool SoftBody3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
+ return Object::cast_to<SoftBody3D>(p_spatial) != nullptr;
}
-String SoftDynamicBody3DGizmoPlugin::get_gizmo_name() const {
- return "SoftDynamicBody3D";
+String SoftBody3DGizmoPlugin::get_gizmo_name() const {
+ return "SoftBody3D";
}
-int SoftDynamicBody3DGizmoPlugin::get_priority() const {
+int SoftBody3DGizmoPlugin::get_priority() const {
return -1;
}
-bool SoftDynamicBody3DGizmoPlugin::is_selectable_when_hidden() const {
+bool SoftBody3DGizmoPlugin::is_selectable_when_hidden() const {
return true;
}
-void SoftDynamicBody3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- SoftDynamicBody3D *soft_body = Object::cast_to<SoftDynamicBody3D>(p_gizmo->get_spatial_node());
+void SoftBody3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
+ SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_spatial_node());
p_gizmo->clear();
@@ -2745,22 +2746,22 @@ void SoftDynamicBody3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_collision_triangles(tm);
}
-String SoftDynamicBody3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- return "SoftDynamicBody3D pin point";
+String SoftBody3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
+ return "SoftBody3D pin point";
}
-Variant SoftDynamicBody3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- SoftDynamicBody3D *soft_body = Object::cast_to<SoftDynamicBody3D>(p_gizmo->get_spatial_node());
+Variant SoftBody3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
+ SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_spatial_node());
return Variant(soft_body->is_point_pinned(p_id));
}
-void SoftDynamicBody3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
- SoftDynamicBody3D *soft_body = Object::cast_to<SoftDynamicBody3D>(p_gizmo->get_spatial_node());
+void SoftBody3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
+ SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_spatial_node());
soft_body->pin_point_toggle(p_id);
}
-bool SoftDynamicBody3DGizmoPlugin::is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- SoftDynamicBody3D *soft_body = Object::cast_to<SoftDynamicBody3D>(p_gizmo->get_spatial_node());
+bool SoftBody3DGizmoPlugin::is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
+ SoftBody3D *soft_body = Object::cast_to<SoftBody3D>(p_gizmo->get_spatial_node());
return soft_body->is_point_pinned(p_id);
}
@@ -2870,7 +2871,7 @@ void VisibleOnScreenNotifier3DGizmoPlugin::commit_handle(const EditorNode3DGizmo
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Notifier AABB"));
ur->add_do_method(notifier, "set_aabb", notifier->get_aabb());
ur->add_undo_method(notifier, "set_aabb", p_restore);
@@ -3061,7 +3062,7 @@ void GPUParticles3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo,
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Particles AABB"));
ur->add_do_method(particles, "set_visibility_aabb", particles->get_visibility_aabb());
ur->add_undo_method(particles, "set_visibility_aabb", p_restore);
@@ -3227,7 +3228,7 @@ void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Radius"));
ur->add_do_method(sn, "set_radius", sn->call("get_radius"));
ur->add_undo_method(sn, "set_radius", p_restore);
@@ -3240,7 +3241,7 @@ void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Box Shape Extents"));
ur->add_do_method(sn, "set_extents", sn->call("get_extents"));
ur->add_undo_method(sn, "set_extents", p_restore);
@@ -3271,8 +3272,8 @@ void GPUParticlesCollision3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Vector<Vector3> points;
for (int i = 0; i <= 360; i++) {
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 1);
+ float ra = Math::deg_to_rad((float)i);
+ float rb = Math::deg_to_rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
@@ -3499,7 +3500,7 @@ void ReflectionProbeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo,
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Probe Extents"));
ur->add_do_method(probe, "set_extents", probe->get_extents());
ur->add_do_method(probe, "set_origin_offset", probe->get_origin_offset());
@@ -3651,7 +3652,7 @@ void DecalGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id,
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Decal Extents"));
ur->add_do_method(decal, "set_extents", decal->get_extents());
ur->add_undo_method(decal, "set_extents", restore);
@@ -3791,7 +3792,7 @@ void VoxelGIGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_i
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Probe Extents"));
ur->add_do_method(probe, "set_extents", probe->get_extents());
ur->add_undo_method(probe, "set_extents", restore);
@@ -4406,7 +4407,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Sphere Shape Radius"));
ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
ur->add_undo_method(ss.ptr(), "set_radius", p_restore);
@@ -4420,7 +4421,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Box Shape Size"));
ur->add_do_method(ss.ptr(), "set_size", ss->get_size());
ur->add_undo_method(ss.ptr(), "set_size", p_restore);
@@ -4437,7 +4438,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
if (p_id == 0) {
ur->create_action(TTR("Change Capsule Shape Radius"));
ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
@@ -4462,7 +4463,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
if (p_id == 0) {
ur->create_action(TTR("Change Cylinder Shape Radius"));
ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
@@ -4487,7 +4488,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Separation Ray Shape Length"));
ur->add_do_method(ss.ptr(), "set_length", ss->get_length());
ur->add_undo_method(ss.ptr(), "set_length", p_restore);
@@ -4516,8 +4517,8 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Vector<Vector3> points;
for (int i = 0; i <= 360; i++) {
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 1);
+ float ra = Math::deg_to_rad((float)i);
+ float rb = Math::deg_to_rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
@@ -4588,8 +4589,8 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Vector3 d(0, height * 0.5 - radius, 0);
for (int i = 0; i < 360; i++) {
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 1);
+ float ra = Math::deg_to_rad((float)i);
+ float rb = Math::deg_to_rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
@@ -4659,8 +4660,8 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
Vector3 d(0, height * 0.5, 0);
for (int i = 0; i < 360; i++) {
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 1);
+ float ra = Math::deg_to_rad((float)i);
+ float rb = Math::deg_to_rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
@@ -4839,6 +4840,10 @@ void CollisionPolygon3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
////
NavigationRegion3DGizmoPlugin::NavigationRegion3DGizmoPlugin() {
+ create_material("face_material", NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color(), false, false, true);
+ create_material("face_material_disabled", NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_disabled_color(), false, false, true);
+ create_material("edge_material", NavigationServer3D::get_singleton()->get_debug_navigation_geometry_edge_color());
+ create_material("edge_material_disabled", NavigationServer3D::get_singleton()->get_debug_navigation_geometry_edge_disabled_color());
}
bool NavigationRegion3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
@@ -4924,6 +4929,7 @@ void NavigationRegion3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
tmesh->create(tmeshfaces);
p_gizmo->add_collision_triangles(tmesh);
+ p_gizmo->add_collision_segments(lines);
Ref<ArrayMesh> debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
int polygon_count = navigationmesh->get_polygon_count();
@@ -4945,6 +4951,7 @@ void NavigationRegion3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
face_mesh_array[Mesh::ARRAY_VERTEX] = face_vertex_array;
// if enabled add vertex colors to colorize each face individually
+ RandomPCG rand;
bool enabled_geometry_face_random_color = NavigationServer3D::get_singleton()->get_debug_navigation_enable_geometry_face_random_color();
if (enabled_geometry_face_random_color) {
Color debug_navigation_geometry_face_color = NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color();
@@ -4954,7 +4961,9 @@ void NavigationRegion3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
face_color_array.resize(polygon_count * 3);
for (int i = 0; i < polygon_count; i++) {
- polygon_color = debug_navigation_geometry_face_color * (Color(Math::randf(), Math::randf(), Math::randf()));
+ // Generate the polygon color, slightly randomly modified from the settings one.
+ polygon_color.set_hsv(debug_navigation_geometry_face_color.get_h() + rand.random(-1.0, 1.0) * 0.1, debug_navigation_geometry_face_color.get_s(), debug_navigation_geometry_face_color.get_v() + rand.random(-1.0, 1.0) * 0.2);
+ polygon_color.a = debug_navigation_geometry_face_color.a;
Vector<int> polygon = navigationmesh->get_polygon(i);
@@ -4966,12 +4975,10 @@ void NavigationRegion3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, face_mesh_array);
- Ref<StandardMaterial3D> debug_geometry_face_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_face_material();
- debug_mesh->surface_set_material(0, debug_geometry_face_material);
+ p_gizmo->add_mesh(debug_mesh, navigationregion->is_enabled() ? get_material("face_material", p_gizmo) : get_material("face_material_disabled", p_gizmo));
// if enabled build geometry edge line surface
bool enabled_edge_lines = NavigationServer3D::get_singleton()->get_debug_navigation_enable_edge_lines();
-
if (enabled_edge_lines) {
Vector<Vector3> line_vertex_array;
line_vertex_array.resize(polygon_count * 6);
@@ -4987,27 +4994,8 @@ void NavigationRegion3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
line_vertex_array.push_back(vertices[polygon[0]]);
}
- Array line_mesh_array;
- line_mesh_array.resize(Mesh::ARRAY_MAX);
- line_mesh_array[Mesh::ARRAY_VERTEX] = line_vertex_array;
- debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, line_mesh_array);
- Ref<StandardMaterial3D> debug_geometry_edge_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_edge_material();
- debug_mesh->surface_set_material(1, debug_geometry_edge_material);
+ p_gizmo->add_lines(line_vertex_array, navigationregion->is_enabled() ? get_material("edge_material", p_gizmo) : get_material("edge_material_disabled", p_gizmo));
}
-
- if (!navigationregion->is_enabled()) {
- if (debug_mesh.is_valid()) {
- if (debug_mesh->get_surface_count() > 0) {
- debug_mesh->surface_set_material(0, NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_face_disabled_material());
- }
- if (debug_mesh->get_surface_count() > 1) {
- debug_mesh->surface_set_material(1, NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_edge_disabled_material());
- }
- }
- }
-
- p_gizmo->add_mesh(debug_mesh);
- p_gizmo->add_collision_segments(lines);
}
//////
@@ -5215,8 +5203,8 @@ void JointGizmosDrawer::draw_cone(const Transform3D &p_offset, const Basis &p_ba
//swing
for (int i = 0; i < 360; i += 10) {
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 10);
+ float ra = Math::deg_to_rad((float)i);
+ float rb = Math::deg_to_rad((float)i + 10);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w;
@@ -5233,12 +5221,12 @@ void JointGizmosDrawer::draw_cone(const Transform3D &p_offset, const Basis &p_ba
r_points.push_back(p_offset.translated_local(p_base.xform(Vector3(1, 0, 0))).origin);
/// Twist
- float ts = Math::rad2deg(p_twist);
+ float ts = Math::rad_to_deg(p_twist);
ts = MIN(ts, 720);
for (int i = 0; i < int(ts); i += 5) {
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 5);
+ float ra = Math::deg_to_rad((float)i);
+ float rb = Math::deg_to_rad((float)i + 5);
float c = i / 720.0;
float cn = (i + 5) / 720.0;
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w * c;
@@ -5758,7 +5746,7 @@ void FogVolumeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Fog Volume Extents"));
ur->add_do_method(sn, "set_extents", sn->call("get_extents"));
ur->add_undo_method(sn, "set_extents", p_restore);
diff --git a/editor/plugins/node_3d_editor_gizmos.h b/editor/plugins/node_3d_editor_gizmos.h
index 739bf1b929..1b6485ac4e 100644
--- a/editor/plugins/node_3d_editor_gizmos.h
+++ b/editor/plugins/node_3d_editor_gizmos.h
@@ -334,8 +334,8 @@ public:
Label3DGizmoPlugin();
};
-class Position3DGizmoPlugin : public EditorNode3DGizmoPlugin {
- GDCLASS(Position3DGizmoPlugin, EditorNode3DGizmoPlugin);
+class Marker3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+ GDCLASS(Marker3DGizmoPlugin, EditorNode3DGizmoPlugin);
Ref<ArrayMesh> pos3d_mesh;
Vector<Vector3> cursor_points;
@@ -346,7 +346,7 @@ public:
int get_priority() const override;
void redraw(EditorNode3DGizmo *p_gizmo) override;
- Position3DGizmoPlugin();
+ Marker3DGizmoPlugin();
};
class PhysicalBone3DGizmoPlugin : public EditorNode3DGizmoPlugin {
@@ -409,8 +409,8 @@ public:
VehicleWheel3DGizmoPlugin();
};
-class SoftDynamicBody3DGizmoPlugin : public EditorNode3DGizmoPlugin {
- GDCLASS(SoftDynamicBody3DGizmoPlugin, EditorNode3DGizmoPlugin);
+class SoftBody3DGizmoPlugin : public EditorNode3DGizmoPlugin {
+ GDCLASS(SoftBody3DGizmoPlugin, EditorNode3DGizmoPlugin);
public:
bool has_gizmo(Node3D *p_spatial) override;
@@ -424,7 +424,7 @@ public:
void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
bool is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
- SoftDynamicBody3DGizmoPlugin();
+ SoftBody3DGizmoPlugin();
};
class VisibleOnScreenNotifier3DGizmoPlugin : public EditorNode3DGizmoPlugin {
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 7628a95310..f165b83999 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -46,6 +46,7 @@
#include "editor/scene_tree_dock.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/collision_shape_3d.h"
+#include "scene/3d/decal.h"
#include "scene/3d/light_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/physics_body_3d.h"
@@ -341,7 +342,7 @@ void Node3DEditorViewport::_update_camera(real_t p_interp_delta) {
camera->set_global_transform(to_camera_transform(camera_cursor));
if (orthogonal) {
- float half_fov = Math::deg2rad(get_fov()) / 2.0;
+ float half_fov = Math::deg_to_rad(get_fov()) / 2.0;
float height = 2.0 * cursor.distance * Math::tan(half_fov);
camera->set_orthogonal(height, get_znear(), get_zfar());
} else {
@@ -1386,25 +1387,17 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
const real_t zoom_factor = 1 + (ZOOM_FREELOOK_MULTIPLIER - 1) * b->get_factor();
switch (b->get_button_index()) {
case MouseButton::WHEEL_UP: {
- if (b->is_alt_pressed()) {
- scale_fov(-0.05);
+ if (is_freelook_active()) {
+ scale_freelook_speed(zoom_factor);
} else {
- if (is_freelook_active()) {
- scale_freelook_speed(zoom_factor);
- } else {
- scale_cursor_distance(1.0 / zoom_factor);
- }
+ scale_cursor_distance(1.0 / zoom_factor);
}
} break;
case MouseButton::WHEEL_DOWN: {
- if (b->is_alt_pressed()) {
- scale_fov(0.05);
+ if (is_freelook_active()) {
+ scale_freelook_speed(1.0 / zoom_factor);
} else {
- if (is_freelook_active()) {
- scale_freelook_speed(1.0 / zoom_factor);
- } else {
- scale_cursor_distance(zoom_factor);
- }
+ scale_cursor_distance(zoom_factor);
}
} break;
case MouseButton::RIGHT: {
@@ -2151,7 +2144,7 @@ void Node3DEditorViewport::_nav_orbit(Ref<InputEventWithModifiers> p_event, cons
}
const real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
- const real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
+ const real_t radians_per_pixel = Math::deg_to_rad(degrees_per_pixel);
const bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis");
const bool invert_x_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_x_axis");
@@ -2184,7 +2177,7 @@ void Node3DEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, const
// Scale mouse sensitivity with camera FOV scale when zoomed in to make it easier to point at things.
const real_t degrees_per_pixel = real_t(EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_sensitivity")) * MIN(1.0, cursor.fov_scale);
- const real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
+ const real_t radians_per_pixel = Math::deg_to_rad(degrees_per_pixel);
const bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis");
// Note: do NOT assume the camera has the "current" transform, because it is interpolated and may have "lag".
@@ -2980,6 +2973,13 @@ void Node3DEditorViewport::_menu_option(int p_option) {
xform.scale_basis(sp->get_scale());
}
+ if (Object::cast_to<Decal>(E)) {
+ // Adjust rotation to match Decal's default orientation.
+ // This makes the decal "look" in the same direction as the camera,
+ // rather than pointing down relative to the camera orientation.
+ xform.basis.rotate_local(Vector3(1, 0, 0), Math_TAU * 0.25);
+ }
+
undo_redo->add_do_method(sp, "set_global_transform", xform);
undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_gizmo_transform());
}
@@ -3007,7 +3007,16 @@ void Node3DEditorViewport::_menu_option(int p_option) {
continue;
}
- undo_redo->add_do_method(sp, "set_rotation", camera_transform.basis.get_euler_normalized());
+ Basis basis = camera_transform.basis;
+
+ if (Object::cast_to<Decal>(E)) {
+ // Adjust rotation to match Decal's default orientation.
+ // This makes the decal "look" in the same direction as the camera,
+ // rather than pointing down relative to the camera orientation.
+ basis.rotate_local(Vector3(1, 0, 0), Math_TAU * 0.25);
+ }
+
+ undo_redo->add_do_method(sp, "set_rotation", basis.get_euler_normalized());
undo_redo->add_undo_method(sp, "set_rotation", sp->get_rotation());
}
undo_redo->commit_action();
@@ -3972,19 +3981,7 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
// Adjust casing according to project setting. The file name is expected to be in snake_case, but will work for others.
String name = path.get_file().get_basename();
- switch (ProjectSettings::get_singleton()->get("editor/node_naming/name_casing").operator int()) {
- case NAME_CASING_PASCAL_CASE:
- name = name.capitalize().replace(" ", "");
- break;
- case NAME_CASING_CAMEL_CASE:
- name = name.capitalize().replace(" ", "");
- name[0] = name.to_lower()[0];
- break;
- case NAME_CASING_SNAKE_CASE:
- name = name.capitalize().replace(" ", "_").to_lower();
- break;
- }
- mesh_instance->set_name(name);
+ mesh_instance->set_name(Node::adjust_name_casing(name));
instantiated_scene = mesh_instance;
} else {
@@ -4011,15 +4008,15 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(path));
}
- editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene, true);
- editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_owner", EditorNode::get_singleton()->get_edited_scene());
- editor_data->get_undo_redo().add_do_reference(instantiated_scene);
- editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instantiated_scene);
+ editor_data->get_undo_redo()->add_do_method(parent, "add_child", instantiated_scene, true);
+ editor_data->get_undo_redo()->add_do_method(instantiated_scene, "set_owner", EditorNode::get_singleton()->get_edited_scene());
+ editor_data->get_undo_redo()->add_do_reference(instantiated_scene);
+ editor_data->get_undo_redo()->add_undo_method(parent, "remove_child", instantiated_scene);
String new_name = parent->validate_child_name(instantiated_scene);
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
- editor_data->get_undo_redo().add_do_method(ed, "live_debug_instance_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent), path, new_name);
- editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent)) + "/" + new_name));
+ editor_data->get_undo_redo()->add_do_method(ed, "live_debug_instance_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent), path, new_name);
+ editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent)) + "/" + new_name));
Node3D *node3d = Object::cast_to<Node3D>(instantiated_scene);
if (node3d) {
@@ -4032,7 +4029,7 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
global_transform.origin = spatial_editor->snap_point(_get_instance_position(p_point));
global_transform.basis *= node3d->get_transform().basis;
- editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_global_transform", global_transform);
+ editor_data->get_undo_redo()->add_do_method(instantiated_scene, "set_global_transform", global_transform);
}
return true;
@@ -4043,15 +4040,15 @@ void Node3DEditorViewport::_perform_drop_data() {
GeometryInstance3D *geometry_instance = Object::cast_to<GeometryInstance3D>(ObjectDB::get_instance(spatial_editor->get_preview_material_target()));
MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(ObjectDB::get_instance(spatial_editor->get_preview_material_target()));
if (mesh_instance && spatial_editor->get_preview_material_surface() != -1) {
- editor_data->get_undo_redo().create_action(vformat(TTR("Set Surface %d Override Material"), spatial_editor->get_preview_material_surface()));
- editor_data->get_undo_redo().add_do_method(geometry_instance, "set_surface_override_material", spatial_editor->get_preview_material_surface(), spatial_editor->get_preview_material());
- editor_data->get_undo_redo().add_undo_method(geometry_instance, "set_surface_override_material", spatial_editor->get_preview_material_surface(), spatial_editor->get_preview_reset_material());
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->create_action(vformat(TTR("Set Surface %d Override Material"), spatial_editor->get_preview_material_surface()));
+ editor_data->get_undo_redo()->add_do_method(geometry_instance, "set_surface_override_material", spatial_editor->get_preview_material_surface(), spatial_editor->get_preview_material());
+ editor_data->get_undo_redo()->add_undo_method(geometry_instance, "set_surface_override_material", spatial_editor->get_preview_material_surface(), spatial_editor->get_preview_reset_material());
+ editor_data->get_undo_redo()->commit_action();
} else if (geometry_instance) {
- editor_data->get_undo_redo().create_action(TTR("Set Material Override"));
- editor_data->get_undo_redo().add_do_method(geometry_instance, "set_material_override", spatial_editor->get_preview_material());
- editor_data->get_undo_redo().add_undo_method(geometry_instance, "set_material_override", spatial_editor->get_preview_reset_material());
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->create_action(TTR("Set Material Override"));
+ editor_data->get_undo_redo()->add_do_method(geometry_instance, "set_material_override", spatial_editor->get_preview_material());
+ editor_data->get_undo_redo()->add_undo_method(geometry_instance, "set_material_override", spatial_editor->get_preview_reset_material());
+ editor_data->get_undo_redo()->commit_action();
}
_remove_preview_material();
@@ -4062,7 +4059,7 @@ void Node3DEditorViewport::_perform_drop_data() {
Vector<String> error_files;
- editor_data->get_undo_redo().create_action(TTR("Create Node"));
+ editor_data->get_undo_redo()->create_action(TTR("Create Node"));
for (int i = 0; i < selected_files.size(); i++) {
String path = selected_files[i];
@@ -4080,7 +4077,7 @@ void Node3DEditorViewport::_perform_drop_data() {
}
}
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->commit_action();
if (error_files.size() > 0) {
String files_str;
@@ -4121,6 +4118,7 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant
continue;
}
Ref<PackedScene> scn = res;
+ Ref<Mesh> mesh = res;
Ref<Material> mat = res;
Ref<Texture2D> tex = res;
if (scn.is_valid()) {
@@ -4139,6 +4137,8 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant
spatial_editor->set_preview_material(mat);
break;
+ } else if (mesh.is_valid()) {
+ // Let the mesh pass.
} else if (tex.is_valid()) {
Ref<StandardMaterial3D> new_mat = memnew(StandardMaterial3D);
new_mat->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, tex);
@@ -4534,7 +4534,7 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) {
break;
}
- static const float orthogonal_threshold = Math::cos(Math::deg2rad(87.0f));
+ static const float orthogonal_threshold = Math::cos(Math::deg_to_rad(87.0f));
bool axis_is_orthogonal = ABS(plane.normal.dot(global_axis)) < orthogonal_threshold;
double angle = 0.0f;
@@ -4554,10 +4554,10 @@ void Node3DEditorViewport::update_transform(Point2 p_mousepos, bool p_shift) {
if (_edit.snap || spatial_editor->is_snap_enabled()) {
snap = spatial_editor->get_rotate_snap();
}
- angle = Math::rad2deg(angle) + snap * 0.5; //else it won't reach +180
+ angle = Math::rad_to_deg(angle) + snap * 0.5; //else it won't reach +180
angle -= Math::fmod(angle, snap);
set_message(vformat(TTR("Rotating %s degrees."), String::num(angle, snap_step_decimals)));
- angle = Math::deg2rad(angle);
+ angle = Math::deg_to_rad(angle);
bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW); // Disable local transformation for TRANSFORM_VIEW
@@ -5725,7 +5725,7 @@ void Node3DEditor::_xform_dialog_action() {
for (int i = 0; i < 3; i++) {
translate[i] = xform_translate[i]->get_text().to_float();
- rotate[i] = Math::deg2rad(xform_rotate[i]->get_text().to_float());
+ rotate[i] = Math::deg_to_rad(xform_rotate[i]->get_text().to_float());
scale[i] = xform_scale[i]->get_text().to_float();
}
@@ -5818,11 +5818,11 @@ void Node3DEditor::_update_camera_override_button(bool p_game_running) {
if (p_game_running) {
button->set_disabled(false);
- button->set_tooltip(TTR("Project Camera Override\nOverrides the running project's camera with the editor viewport camera."));
+ button->set_tooltip_text(TTR("Project Camera Override\nOverrides the running project's camera with the editor viewport camera."));
} else {
button->set_disabled(true);
button->set_pressed(false);
- button->set_tooltip(TTR("Project Camera Override\nNo project instance running. Run the project from the editor to use this feature."));
+ button->set_tooltip_text(TTR("Project Camera Override\nNo project instance running. Run the project from the editor to use this feature."));
}
}
@@ -6408,7 +6408,7 @@ void fragment() {
Ref<ShaderMaterial> rotate_mat = memnew(ShaderMaterial);
rotate_mat->set_render_priority(Material::RENDER_PRIORITY_MAX);
rotate_mat->set_shader(rotate_shader);
- rotate_mat->set_shader_param("albedo", col);
+ rotate_mat->set_shader_uniform("albedo", col);
rotate_gizmo_color[i] = rotate_mat;
Array arrays = surftool->commit_to_arrays();
@@ -6416,7 +6416,7 @@ void fragment() {
rotate_gizmo[i]->surface_set_material(0, rotate_mat);
Ref<ShaderMaterial> rotate_mat_hl = rotate_mat->duplicate();
- rotate_mat_hl->set_shader_param("albedo", albedo);
+ rotate_mat_hl->set_shader_uniform("albedo", albedo);
rotate_gizmo_color_hl[i] = rotate_mat_hl;
if (i == 2) { // Rotation white outline
@@ -6457,7 +6457,7 @@ void fragment() {
)");
border_mat->set_shader(border_shader);
- border_mat->set_shader_param("albedo", Color(0.75, 0.75, 0.75, col.a / 3.0));
+ border_mat->set_shader_uniform("albedo", Color(0.75, 0.75, 0.75, col.a / 3.0));
rotate_gizmo[3] = Ref<ArrayMesh>(memnew(ArrayMesh));
rotate_gizmo[3]->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays);
@@ -6710,8 +6710,8 @@ void Node3DEditor::_init_grid() {
fade_size = CLAMP(fade_size, min_fade_size, max_fade_size);
real_t grid_fade_size = (grid_size - primary_grid_steps) * fade_size;
- grid_mat[c]->set_shader_param("grid_size", grid_fade_size);
- grid_mat[c]->set_shader_param("orthogonal", orthogonal);
+ grid_mat[c]->set_shader_uniform("grid_size", grid_fade_size);
+ grid_mat[c]->set_shader_uniform("orthogonal", orthogonal);
// Cache these so we don't have to re-access memory.
Vector<Vector3> &ref_grid = grid_points[c];
@@ -7255,6 +7255,14 @@ Vector<int> Node3DEditor::get_subgizmo_selection() {
return ret;
}
+void Node3DEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
+ undo_redo = p_undo_redo;
+}
+
+Ref<EditorUndoRedoManager> Node3DEditor::get_undo_redo() {
+ return undo_redo;
+}
+
void Node3DEditor::add_control_to_menu_panel(Control *p_control) {
context_menu_hbox->add_child(p_control);
}
@@ -7492,10 +7500,10 @@ void Node3DEditor::_register_all_gizmos() {
add_gizmo_plugin(Ref<AudioListener3DGizmoPlugin>(memnew(AudioListener3DGizmoPlugin)));
add_gizmo_plugin(Ref<MeshInstance3DGizmoPlugin>(memnew(MeshInstance3DGizmoPlugin)));
add_gizmo_plugin(Ref<OccluderInstance3DGizmoPlugin>(memnew(OccluderInstance3DGizmoPlugin)));
- add_gizmo_plugin(Ref<SoftDynamicBody3DGizmoPlugin>(memnew(SoftDynamicBody3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<SoftBody3DGizmoPlugin>(memnew(SoftBody3DGizmoPlugin)));
add_gizmo_plugin(Ref<Sprite3DGizmoPlugin>(memnew(Sprite3DGizmoPlugin)));
add_gizmo_plugin(Ref<Label3DGizmoPlugin>(memnew(Label3DGizmoPlugin)));
- add_gizmo_plugin(Ref<Position3DGizmoPlugin>(memnew(Position3DGizmoPlugin)));
+ add_gizmo_plugin(Ref<Marker3DGizmoPlugin>(memnew(Marker3DGizmoPlugin)));
add_gizmo_plugin(Ref<RayCast3DGizmoPlugin>(memnew(RayCast3DGizmoPlugin)));
add_gizmo_plugin(Ref<ShapeCast3DGizmoPlugin>(memnew(ShapeCast3DGizmoPlugin)));
add_gizmo_plugin(Ref<SpringArm3DGizmoPlugin>(memnew(SpringArm3DGizmoPlugin)));
@@ -7559,9 +7567,9 @@ void Node3DEditor::_sun_direction_draw() {
sun_direction->draw_rect(Rect2(Vector2(), sun_direction->get_size()), Color(1, 1, 1, 1));
Vector3 z_axis = preview_sun->get_transform().basis.get_column(Vector3::AXIS_Z);
z_axis = get_editor_viewport(0)->camera->get_camera_transform().basis.xform_inv(z_axis);
- sun_direction_material->set_shader_param("sun_direction", Vector3(z_axis.x, -z_axis.y, z_axis.z));
+ sun_direction_material->set_shader_uniform("sun_direction", Vector3(z_axis.x, -z_axis.y, z_axis.z));
Color color = sun_color->get_pick_color() * sun_energy->get_value();
- sun_direction_material->set_shader_param("sun_color", Vector3(color.r, color.g, color.b));
+ sun_direction_material->set_shader_uniform("sun_color", Vector3(color.r, color.g, color.b));
}
void Node3DEditor::_preview_settings_changed() {
@@ -7603,10 +7611,10 @@ void Node3DEditor::_load_default_preview_settings() {
// On any not-tidally-locked planet, a sun would have an angular altitude
// of 60 degrees as the average of all points on the sphere at noon.
// The azimuth choice is arbitrary, but ideally shouldn't be on an axis.
- sun_rotation = Vector2(-Math::deg2rad(60.0), Math::deg2rad(150.0));
+ sun_rotation = Vector2(-Math::deg_to_rad(60.0), Math::deg_to_rad(150.0));
- sun_angle_altitude->set_value(-Math::rad2deg(sun_rotation.x));
- sun_angle_azimuth->set_value(180.0 - Math::rad2deg(sun_rotation.y));
+ sun_angle_altitude->set_value(-Math::rad_to_deg(sun_rotation.x));
+ sun_angle_azimuth->set_value(180.0 - Math::rad_to_deg(sun_rotation.y));
sun_direction->update();
environ_sky_color->set_pick_color(Color(0.385, 0.454, 0.55));
environ_ground_color->set_pick_color(Color(0.2, 0.169, 0.133));
@@ -7615,7 +7623,7 @@ void Node3DEditor::_load_default_preview_settings() {
environ_tonemap_button->set_pressed(true);
environ_ao_button->set_pressed(false);
environ_gi_button->set_pressed(false);
- sun_max_distance->set_value(250);
+ sun_max_distance->set_value(100);
sun_color->set_pick_color(Color(1, 1, 1));
sun_energy->set_value(1.0);
@@ -7649,8 +7657,8 @@ void Node3DEditor::_update_preview_environment() {
}
}
- sun_angle_altitude->set_value(-Math::rad2deg(sun_rotation.x));
- sun_angle_azimuth->set_value(180.0 - Math::rad2deg(sun_rotation.y));
+ sun_angle_altitude->set_value(-Math::rad_to_deg(sun_rotation.x));
+ sun_angle_azimuth->set_value(180.0 - Math::rad_to_deg(sun_rotation.y));
bool disable_env = world_env_count > 0 || environ_button->is_pressed();
@@ -7683,15 +7691,15 @@ void Node3DEditor::_sun_direction_input(const Ref<InputEvent> &p_event) {
sun_rotation.x += mm->get_relative().y * (0.02 * EDSCALE);
sun_rotation.y -= mm->get_relative().x * (0.02 * EDSCALE);
sun_rotation.x = CLAMP(sun_rotation.x, -Math_TAU / 4, Math_TAU / 4);
- sun_angle_altitude->set_value(-Math::rad2deg(sun_rotation.x));
- sun_angle_azimuth->set_value(180.0 - Math::rad2deg(sun_rotation.y));
+ sun_angle_altitude->set_value(-Math::rad_to_deg(sun_rotation.x));
+ sun_angle_azimuth->set_value(180.0 - Math::rad_to_deg(sun_rotation.y));
_preview_settings_changed();
}
}
void Node3DEditor::_sun_direction_angle_set() {
- sun_rotation.x = Math::deg2rad(-sun_angle_altitude->get_value());
- sun_rotation.y = Math::deg2rad(180.0 - sun_angle_azimuth->get_value());
+ sun_rotation.x = Math::deg_to_rad(-sun_angle_altitude->get_value());
+ sun_rotation.y = Math::deg_to_rad(180.0 - sun_angle_azimuth->get_value());
_preview_settings_changed();
}
@@ -7739,7 +7747,7 @@ Node3DEditor::Node3DEditor() {
tool_button[TOOL_MODE_SELECT]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_TOOL_SELECT));
tool_button[TOOL_MODE_SELECT]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_select", TTR("Select Mode"), Key::Q));
tool_button[TOOL_MODE_SELECT]->set_shortcut_context(this);
- tool_button[TOOL_MODE_SELECT]->set_tooltip(keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Drag: Rotate selected node around pivot.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked."));
+ tool_button[TOOL_MODE_SELECT]->set_tooltip_text(keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Drag: Rotate selected node around pivot.") + "\n" + TTR("Alt+RMB: Show list of all nodes at position clicked, including locked."));
main_menu_hbox->add_child(memnew(VSeparator));
tool_button[TOOL_MODE_MOVE] = memnew(Button);
@@ -7774,13 +7782,13 @@ Node3DEditor::Node3DEditor() {
tool_button[TOOL_MODE_LIST_SELECT]->set_toggle_mode(true);
tool_button[TOOL_MODE_LIST_SELECT]->set_flat(true);
tool_button[TOOL_MODE_LIST_SELECT]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_TOOL_LIST_SELECT));
- tool_button[TOOL_MODE_LIST_SELECT]->set_tooltip(TTR("Show list of selectable nodes at position clicked."));
+ tool_button[TOOL_MODE_LIST_SELECT]->set_tooltip_text(TTR("Show list of selectable nodes at position clicked."));
tool_button[TOOL_LOCK_SELECTED] = memnew(Button);
main_menu_hbox->add_child(tool_button[TOOL_LOCK_SELECTED]);
tool_button[TOOL_LOCK_SELECTED]->set_flat(true);
tool_button[TOOL_LOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_LOCK_SELECTED));
- tool_button[TOOL_LOCK_SELECTED]->set_tooltip(TTR("Lock selected node, preventing selection and movement."));
+ tool_button[TOOL_LOCK_SELECTED]->set_tooltip_text(TTR("Lock selected node, preventing selection and movement."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
tool_button[TOOL_LOCK_SELECTED]->set_shortcut(ED_SHORTCUT("editor/lock_selected_nodes", TTR("Lock Selected Node(s)"), KeyModifierMask::CMD | Key::L));
@@ -7788,7 +7796,7 @@ Node3DEditor::Node3DEditor() {
main_menu_hbox->add_child(tool_button[TOOL_UNLOCK_SELECTED]);
tool_button[TOOL_UNLOCK_SELECTED]->set_flat(true);
tool_button[TOOL_UNLOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_UNLOCK_SELECTED));
- tool_button[TOOL_UNLOCK_SELECTED]->set_tooltip(TTR("Unlock selected node, allowing selection and movement."));
+ tool_button[TOOL_UNLOCK_SELECTED]->set_tooltip_text(TTR("Unlock selected node, allowing selection and movement."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
tool_button[TOOL_UNLOCK_SELECTED]->set_shortcut(ED_SHORTCUT("editor/unlock_selected_nodes", TTR("Unlock Selected Node(s)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::L));
@@ -7796,7 +7804,7 @@ Node3DEditor::Node3DEditor() {
main_menu_hbox->add_child(tool_button[TOOL_GROUP_SELECTED]);
tool_button[TOOL_GROUP_SELECTED]->set_flat(true);
tool_button[TOOL_GROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_GROUP_SELECTED));
- tool_button[TOOL_GROUP_SELECTED]->set_tooltip(TTR("Makes sure the object's children are not selectable."));
+ tool_button[TOOL_GROUP_SELECTED]->set_tooltip_text(TTR("Make selected node's children not selectable."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
tool_button[TOOL_GROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KeyModifierMask::CMD | Key::G));
@@ -7804,7 +7812,7 @@ Node3DEditor::Node3DEditor() {
main_menu_hbox->add_child(tool_button[TOOL_UNGROUP_SELECTED]);
tool_button[TOOL_UNGROUP_SELECTED]->set_flat(true);
tool_button[TOOL_UNGROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_UNGROUP_SELECTED));
- tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip(TTR("Restores the object's children's ability to be selected."));
+ tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip_text(TTR("Make selected node's children selectable."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
tool_button[TOOL_UNGROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::G));
@@ -7838,7 +7846,7 @@ Node3DEditor::Node3DEditor() {
main_menu_hbox->add_child(memnew(VSeparator));
sun_button = memnew(Button);
- sun_button->set_tooltip(TTR("Toggle preview sunlight.\nIf a DirectionalLight3D node is added to the scene, preview sunlight is disabled."));
+ sun_button->set_tooltip_text(TTR("Toggle preview sunlight.\nIf a DirectionalLight3D node is added to the scene, preview sunlight is disabled."));
sun_button->set_toggle_mode(true);
sun_button->set_flat(true);
sun_button->connect("pressed", callable_mp(this, &Node3DEditor::_update_preview_environment), CONNECT_DEFERRED);
@@ -7847,7 +7855,7 @@ Node3DEditor::Node3DEditor() {
main_menu_hbox->add_child(sun_button);
environ_button = memnew(Button);
- environ_button->set_tooltip(TTR("Toggle preview environment.\nIf a WorldEnvironment node is added to the scene, preview environment is disabled."));
+ environ_button->set_tooltip_text(TTR("Toggle preview environment.\nIf a WorldEnvironment node is added to the scene, preview environment is disabled."));
environ_button->set_toggle_mode(true);
environ_button->set_flat(true);
environ_button->connect("pressed", callable_mp(this, &Node3DEditor::_update_preview_environment), CONNECT_DEFERRED);
@@ -7856,7 +7864,7 @@ Node3DEditor::Node3DEditor() {
main_menu_hbox->add_child(environ_button);
sun_environ_settings = memnew(Button);
- sun_environ_settings->set_tooltip(TTR("Edit Sun and Environment settings."));
+ sun_environ_settings->set_tooltip_text(TTR("Edit Sun and Environment settings."));
sun_environ_settings->set_flat(true);
sun_environ_settings->connect("pressed", callable_mp(this, &Node3DEditor::_sun_environ_settings_pressed));
@@ -8162,8 +8170,8 @@ void fragment() {
)");
sun_direction_material.instantiate();
sun_direction_material->set_shader(sun_direction_shader);
- sun_direction_material->set_shader_param("sun_direction", Vector3(0, 0, 1));
- sun_direction_material->set_shader_param("sun_color", Vector3(1, 1, 1));
+ sun_direction_material->set_shader_uniform("sun_direction", Vector3(0, 0, 1));
+ sun_direction_material->set_shader_uniform("sun_color", Vector3(1, 1, 1));
sun_direction->set_material(sun_direction_material);
HBoxContainer *sun_angle_hbox = memnew(HBoxContainer);
@@ -8214,7 +8222,7 @@ void fragment() {
sun_add_to_scene = memnew(Button);
sun_add_to_scene->set_text(TTR("Add Sun to Scene"));
- sun_add_to_scene->set_tooltip(TTR("Adds a DirectionalLight3D node matching the preview sun settings to the current scene.\nHold Shift while clicking to also add the preview environment to the current scene."));
+ sun_add_to_scene->set_tooltip_text(TTR("Adds a DirectionalLight3D node matching the preview sun settings to the current scene.\nHold Shift while clicking to also add the preview environment to the current scene."));
sun_add_to_scene->connect("pressed", callable_mp(this, &Node3DEditor::_add_sun_to_scene).bind(false));
sun_vb->add_spacer();
sun_vb->add_child(sun_add_to_scene);
@@ -8283,7 +8291,7 @@ void fragment() {
environ_add_to_scene = memnew(Button);
environ_add_to_scene->set_text(TTR("Add Environment to Scene"));
- environ_add_to_scene->set_tooltip(TTR("Adds a WorldEnvironment node matching the preview environment settings to the current scene.\nHold Shift while clicking to also add the preview sun to the current scene."));
+ environ_add_to_scene->set_tooltip_text(TTR("Adds a WorldEnvironment node matching the preview environment settings to the current scene.\nHold Shift while clicking to also add the preview sun to the current scene."));
environ_add_to_scene->connect("pressed", callable_mp(this, &Node3DEditor::_add_environment_to_scene).bind(false));
environ_vb->add_spacer();
environ_vb->add_child(environ_add_to_scene);
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 4469271a38..e0298ebd5f 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -53,6 +53,7 @@ class Node3DEditorViewport;
class SubViewportContainer;
class DirectionalLight3D;
class WorldEnvironment;
+class EditorUndoRedoManager;
class ViewportRotationControl : public Control {
GDCLASS(ViewportRotationControl, Control);
@@ -201,7 +202,7 @@ private:
EditorData *editor_data = nullptr;
EditorSelection *editor_selection = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
CheckBox *preview_camera = nullptr;
SubViewportContainer *subviewport_container = nullptr;
@@ -682,7 +683,7 @@ private:
HBoxContainer *context_menu_hbox = nullptr;
void _generate_selection_boxes();
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
int camera_override_viewport_id;
@@ -820,13 +821,13 @@ public:
void select_gizmo_highlight_axis(int p_axis);
void set_custom_camera(Node *p_camera) { custom_camera = p_camera; }
- void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; }
Dictionary get_state() const;
void set_state(const Dictionary &p_state);
Ref<Environment> get_viewport_environment() { return viewport_environment; }
- UndoRedo *get_undo_redo() { return undo_redo; }
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
+ Ref<EditorUndoRedoManager> get_undo_redo();
void add_control_to_menu_panel(Control *p_control);
void remove_control_from_menu_panel(Control *p_control);
diff --git a/editor/plugins/packed_scene_translation_parser_plugin.cpp b/editor/plugins/packed_scene_translation_parser_plugin.cpp
index 8d083d28b2..2f4ae734d1 100644
--- a/editor/plugins/packed_scene_translation_parser_plugin.cpp
+++ b/editor/plugins/packed_scene_translation_parser_plugin.cpp
@@ -123,7 +123,7 @@ Error PackedSceneEditorTranslationParserPlugin::parse_file(const String &p_path,
PackedSceneEditorTranslationParserPlugin::PackedSceneEditorTranslationParserPlugin() {
// Scene Node's properties containing strings that will be fetched for translation.
lookup_properties.insert("text");
- lookup_properties.insert("hint_tooltip");
+ lookup_properties.insert("tooltip_text");
lookup_properties.insert("placeholder_text");
lookup_properties.insert("items");
lookup_properties.insert("title");
diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp
index fd331c4127..dc6dfd81c2 100644
--- a/editor/plugins/path_2d_editor_plugin.cpp
+++ b/editor/plugins/path_2d_editor_plugin.cpp
@@ -36,6 +36,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
void Path2DEditor::_notification(int p_what) {
switch (p_what) {
@@ -536,7 +537,7 @@ Path2DEditor::Path2DEditor() {
curve_edit->set_flat(true);
curve_edit->set_toggle_mode(true);
curve_edit->set_focus_mode(Control::FOCUS_NONE);
- curve_edit->set_tooltip(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Click: Add Point") + "\n" + TTR("Left Click: Split Segment (in curve)") + "\n" + TTR("Right Click: Delete Point"));
+ curve_edit->set_tooltip_text(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Click: Add Point") + "\n" + TTR("Left Click: Split Segment (in curve)") + "\n" + TTR("Right Click: Delete Point"));
curve_edit->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(MODE_EDIT));
base_hb->add_child(curve_edit);
@@ -544,7 +545,7 @@ Path2DEditor::Path2DEditor() {
curve_edit_curve->set_flat(true);
curve_edit_curve->set_toggle_mode(true);
curve_edit_curve->set_focus_mode(Control::FOCUS_NONE);
- curve_edit_curve->set_tooltip(TTR("Select Control Points (Shift+Drag)"));
+ curve_edit_curve->set_tooltip_text(TTR("Select Control Points (Shift+Drag)"));
curve_edit_curve->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(MODE_EDIT_CURVE));
base_hb->add_child(curve_edit_curve);
@@ -552,7 +553,7 @@ Path2DEditor::Path2DEditor() {
curve_create->set_flat(true);
curve_create->set_toggle_mode(true);
curve_create->set_focus_mode(Control::FOCUS_NONE);
- curve_create->set_tooltip(TTR("Add Point (in empty space)"));
+ curve_create->set_tooltip_text(TTR("Add Point (in empty space)"));
curve_create->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(MODE_CREATE));
base_hb->add_child(curve_create);
@@ -560,14 +561,14 @@ Path2DEditor::Path2DEditor() {
curve_del->set_flat(true);
curve_del->set_toggle_mode(true);
curve_del->set_focus_mode(Control::FOCUS_NONE);
- curve_del->set_tooltip(TTR("Delete Point"));
+ curve_del->set_tooltip_text(TTR("Delete Point"));
curve_del->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(MODE_DELETE));
base_hb->add_child(curve_del);
curve_close = memnew(Button);
curve_close->set_flat(true);
curve_close->set_focus_mode(Control::FOCUS_NONE);
- curve_close->set_tooltip(TTR("Close Curve"));
+ curve_close->set_tooltip_text(TTR("Close Curve"));
curve_close->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(ACTION_CLOSE));
base_hb->add_child(curve_close);
diff --git a/editor/plugins/path_2d_editor_plugin.h b/editor/plugins/path_2d_editor_plugin.h
index 720f5c090f..13eca79010 100644
--- a/editor/plugins/path_2d_editor_plugin.h
+++ b/editor/plugins/path_2d_editor_plugin.h
@@ -36,11 +36,12 @@
#include "scene/gui/separator.h"
class CanvasItemEditor;
+class EditorUndoRedoManager;
class Path2DEditor : public HBoxContainer {
GDCLASS(Path2DEditor, HBoxContainer);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
CanvasItemEditor *canvas_item_editor = nullptr;
Panel *panel = nullptr;
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index 65b15a6001..1029b06638 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -35,6 +35,7 @@
#include "core/os/keyboard.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "node_3d_editor_plugin.h"
#include "scene/resources/curve.h"
@@ -172,7 +173,7 @@ void Path3DGizmo::commit_handle(int p_id, bool p_secondary, const Variant &p_res
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
if (!p_secondary) {
if (p_cancel) {
@@ -385,7 +386,7 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_spatial_gui_input(Camera
}
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
if (closest_seg != -1) {
//subdivide
@@ -427,21 +428,21 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_spatial_gui_input(Camera
// Find the offset and point index of the place to break up.
// Also check for the control points.
if (dist_to_p < click_dist) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Remove Path Point"));
ur->add_do_method(c.ptr(), "remove_point", i);
ur->add_undo_method(c.ptr(), "add_point", c->get_point_position(i), c->get_point_in(i), c->get_point_out(i), i);
ur->commit_action();
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else if (dist_to_p_out < click_dist) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Remove Out-Control Point"));
ur->add_do_method(c.ptr(), "set_point_out", i, Vector3());
ur->add_undo_method(c.ptr(), "set_point_out", i, c->get_point_out(i));
ur->commit_action();
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else if (dist_to_p_in < click_dist) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Remove In-Control Point"));
ur->add_do_method(c.ptr(), "set_point_in", i, Vector3());
ur->add_undo_method(c.ptr(), "set_point_in", i, c->get_point_in(i));
@@ -520,7 +521,7 @@ void Path3DEditorPlugin::_close_curve() {
if (c->get_point_position(0) == c->get_point_position(c->get_point_count() - 1)) {
return;
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Close Curve"));
ur->add_do_method(c.ptr(), "add_point", c->get_point_position(0), c->get_point_in(0), c->get_point_out(0), -1);
ur->add_undo_method(c.ptr(), "remove_point", c->get_point_count());
@@ -596,7 +597,7 @@ Path3DEditorPlugin::Path3DEditorPlugin() {
curve_edit->set_toggle_mode(true);
curve_edit->hide();
curve_edit->set_focus_mode(Control::FOCUS_NONE);
- curve_edit->set_tooltip(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Click: Add Point") + "\n" + TTR("Right Click: Delete Point"));
+ curve_edit->set_tooltip_text(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD) + TTR("Click: Add Point") + "\n" + TTR("Right Click: Delete Point"));
Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_edit);
curve_create = memnew(Button);
@@ -604,7 +605,7 @@ Path3DEditorPlugin::Path3DEditorPlugin() {
curve_create->set_toggle_mode(true);
curve_create->hide();
curve_create->set_focus_mode(Control::FOCUS_NONE);
- curve_create->set_tooltip(TTR("Add Point (in empty space)") + "\n" + TTR("Split Segment (in curve)"));
+ curve_create->set_tooltip_text(TTR("Add Point (in empty space)") + "\n" + TTR("Split Segment (in curve)"));
Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_create);
curve_del = memnew(Button);
@@ -612,14 +613,14 @@ Path3DEditorPlugin::Path3DEditorPlugin() {
curve_del->set_toggle_mode(true);
curve_del->hide();
curve_del->set_focus_mode(Control::FOCUS_NONE);
- curve_del->set_tooltip(TTR("Delete Point"));
+ curve_del->set_tooltip_text(TTR("Delete Point"));
Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_del);
curve_close = memnew(Button);
curve_close->set_flat(true);
curve_close->hide();
curve_close->set_focus_mode(Control::FOCUS_NONE);
- curve_close->set_tooltip(TTR("Close Curve"));
+ curve_close->set_tooltip_text(TTR("Close Curve"));
Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_close);
PopupMenu *menu;
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 4f46c99a04..b71cee8882 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -1237,7 +1237,7 @@ Polygon2DEditor::Polygon2DEditor() {
button_uv = memnew(Button);
button_uv->set_flat(true);
add_child(button_uv);
- button_uv->set_tooltip(TTR("Open Polygon 2D UV editor."));
+ button_uv->set_tooltip_text(TTR("Open Polygon 2D UV editor."));
button_uv->connect("pressed", callable_mp(this, &Polygon2DEditor::_menu_option).bind(MODE_EDIT_UV));
uv_mode = UV_MODE_EDIT_POINT;
@@ -1293,17 +1293,17 @@ Polygon2DEditor::Polygon2DEditor() {
uv_button[i]->set_focus_mode(FOCUS_NONE);
}
- uv_button[UV_MODE_CREATE]->set_tooltip(TTR("Create Polygon"));
- uv_button[UV_MODE_CREATE_INTERNAL]->set_tooltip(TTR("Create Internal Vertex"));
- uv_button[UV_MODE_REMOVE_INTERNAL]->set_tooltip(TTR("Remove Internal Vertex"));
- uv_button[UV_MODE_EDIT_POINT]->set_tooltip(TTR("Move Points") + "\n" + TTR("Ctrl: Rotate") + "\n" + TTR("Shift: Move All") + "\n" + TTR("Shift+Ctrl: Scale"));
- uv_button[UV_MODE_MOVE]->set_tooltip(TTR("Move Polygon"));
- uv_button[UV_MODE_ROTATE]->set_tooltip(TTR("Rotate Polygon"));
- uv_button[UV_MODE_SCALE]->set_tooltip(TTR("Scale Polygon"));
- uv_button[UV_MODE_ADD_POLYGON]->set_tooltip(TTR("Create a custom polygon. Enables custom polygon rendering."));
- uv_button[UV_MODE_REMOVE_POLYGON]->set_tooltip(TTR("Remove a custom polygon. If none remain, custom polygon rendering is disabled."));
- uv_button[UV_MODE_PAINT_WEIGHT]->set_tooltip(TTR("Paint weights with specified intensity."));
- uv_button[UV_MODE_CLEAR_WEIGHT]->set_tooltip(TTR("Unpaint weights with specified intensity."));
+ uv_button[UV_MODE_CREATE]->set_tooltip_text(TTR("Create Polygon"));
+ uv_button[UV_MODE_CREATE_INTERNAL]->set_tooltip_text(TTR("Create Internal Vertex"));
+ uv_button[UV_MODE_REMOVE_INTERNAL]->set_tooltip_text(TTR("Remove Internal Vertex"));
+ uv_button[UV_MODE_EDIT_POINT]->set_tooltip_text(TTR("Move Points") + "\n" + TTR("Ctrl: Rotate") + "\n" + TTR("Shift: Move All") + "\n" + TTR("Shift+Ctrl: Scale"));
+ uv_button[UV_MODE_MOVE]->set_tooltip_text(TTR("Move Polygon"));
+ uv_button[UV_MODE_ROTATE]->set_tooltip_text(TTR("Rotate Polygon"));
+ uv_button[UV_MODE_SCALE]->set_tooltip_text(TTR("Scale Polygon"));
+ uv_button[UV_MODE_ADD_POLYGON]->set_tooltip_text(TTR("Create a custom polygon. Enables custom polygon rendering."));
+ uv_button[UV_MODE_REMOVE_POLYGON]->set_tooltip_text(TTR("Remove a custom polygon. If none remain, custom polygon rendering is disabled."));
+ uv_button[UV_MODE_PAINT_WEIGHT]->set_tooltip_text(TTR("Paint weights with specified intensity."));
+ uv_button[UV_MODE_CLEAR_WEIGHT]->set_tooltip_text(TTR("Unpaint weights with specified intensity."));
uv_button[UV_MODE_CREATE]->hide();
uv_button[UV_MODE_CREATE_INTERNAL]->hide();
@@ -1368,7 +1368,7 @@ Polygon2DEditor::Polygon2DEditor() {
b_snap_enable->set_focus_mode(FOCUS_NONE);
b_snap_enable->set_toggle_mode(true);
b_snap_enable->set_pressed(use_snap);
- b_snap_enable->set_tooltip(TTR("Enable Snap"));
+ b_snap_enable->set_tooltip_text(TTR("Enable Snap"));
b_snap_enable->connect("toggled", callable_mp(this, &Polygon2DEditor::_set_use_snap));
b_snap_grid = memnew(Button);
@@ -1378,7 +1378,7 @@ Polygon2DEditor::Polygon2DEditor() {
b_snap_grid->set_focus_mode(FOCUS_NONE);
b_snap_grid->set_toggle_mode(true);
b_snap_grid->set_pressed(snap_show_grid);
- b_snap_grid->set_tooltip(TTR("Show Grid"));
+ b_snap_grid->set_tooltip_text(TTR("Show Grid"));
b_snap_grid->connect("toggled", callable_mp(this, &Polygon2DEditor::_set_show_grid));
grid_settings = memnew(AcceptDialog);
diff --git a/editor/plugins/polygon_3d_editor_plugin.cpp b/editor/plugins/polygon_3d_editor_plugin.cpp
index 83092f990f..2b3a5c3e23 100644
--- a/editor/plugins/polygon_3d_editor_plugin.cpp
+++ b/editor/plugins/polygon_3d_editor_plugin.cpp
@@ -38,6 +38,7 @@
#include "core/os/keyboard.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "node_3d_editor_plugin.h"
#include "scene/3d/camera_3d.h"
diff --git a/editor/plugins/polygon_3d_editor_plugin.h b/editor/plugins/polygon_3d_editor_plugin.h
index e1e1261250..0eb02a39e2 100644
--- a/editor/plugins/polygon_3d_editor_plugin.h
+++ b/editor/plugins/polygon_3d_editor_plugin.h
@@ -37,11 +37,12 @@
#include "scene/resources/immediate_mesh.h"
class CanvasItemEditor;
+class EditorUndoRedoManager;
class Polygon3DEditor : public HBoxContainer {
GDCLASS(Polygon3DEditor, HBoxContainer);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
enum Mode {
MODE_CREATE,
MODE_EDIT,
diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp
index 4e528ef066..80566419b1 100644
--- a/editor/plugins/resource_preloader_editor_plugin.cpp
+++ b/editor/plugins/resource_preloader_editor_plugin.cpp
@@ -234,6 +234,10 @@ void ResourcePreloaderEditor::_cell_button_pressed(Object *p_item, int p_column,
}
}
+void ResourcePreloaderEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
+ undo_redo = p_undo_redo;
+}
+
void ResourcePreloaderEditor::edit(ResourcePreloader *p_preloader) {
preloader = p_preloader;
@@ -352,7 +356,7 @@ ResourcePreloaderEditor::ResourcePreloaderEditor() {
vbc->add_child(hbc);
load = memnew(Button);
- load->set_tooltip(TTR("Load Resource"));
+ load->set_tooltip_text(TTR("Load Resource"));
hbc->add_child(load);
paste = memnew(Button);
@@ -387,7 +391,7 @@ ResourcePreloaderEditor::ResourcePreloaderEditor() {
}
void ResourcePreloaderEditorPlugin::edit(Object *p_object) {
- preloader_editor->set_undo_redo(&get_undo_redo());
+ preloader_editor->set_undo_redo(EditorNode::get_undo_redo());
ResourcePreloader *s = Object::cast_to<ResourcePreloader>(p_object);
if (!s) {
return;
diff --git a/editor/plugins/resource_preloader_editor_plugin.h b/editor/plugins/resource_preloader_editor_plugin.h
index 96cef3de21..ef80283dae 100644
--- a/editor/plugins/resource_preloader_editor_plugin.h
+++ b/editor/plugins/resource_preloader_editor_plugin.h
@@ -37,6 +37,7 @@
#include "scene/main/resource_preloader.h"
class EditorFileDialog;
+class EditorUndoRedoManager;
class ResourcePreloaderEditor : public PanelContainer {
GDCLASS(ResourcePreloaderEditor, PanelContainer);
@@ -66,7 +67,7 @@ class ResourcePreloaderEditor : public PanelContainer {
void _cell_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button);
void _item_edited();
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
@@ -78,7 +79,7 @@ protected:
static void _bind_methods();
public:
- void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; }
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void edit(ResourcePreloader *p_preloader);
ResourcePreloaderEditor();
diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp
index 681dd476e3..de30c4100d 100644
--- a/editor/plugins/root_motion_editor_plugin.cpp
+++ b/editor/plugins/root_motion_editor_plugin.cpp
@@ -198,7 +198,7 @@ void EditorPropertyRootMotion::_node_clear() {
void EditorPropertyRootMotion::update_property() {
NodePath p = get_edited_object()->get(get_edited_property());
- assign->set_tooltip(p);
+ assign->set_tooltip_text(p);
if (p == NodePath()) {
assign->set_icon(Ref<Texture2D>());
assign->set_text(TTR("Assign..."));
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index bbf5ffa462..aa1d630372 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -49,7 +49,6 @@
#include "editor/find_in_files.h"
#include "editor/node_dock.h"
#include "editor/plugins/shader_editor_plugin.h"
-#include "modules/visual_script/editor/visual_script_editor.h"
#include "scene/main/window.h"
#include "scene/scene_string_names.h"
#include "script_text_editor.h"
@@ -66,12 +65,12 @@ String EditorSyntaxHighlighter::_get_name() const {
return "Unnamed";
}
-Array EditorSyntaxHighlighter::_get_supported_languages() const {
- Array ret;
+PackedStringArray EditorSyntaxHighlighter::_get_supported_languages() const {
+ PackedStringArray ret;
if (GDVIRTUAL_CALL(_get_supported_languages, ret)) {
return ret;
}
- return Array();
+ return PackedStringArray();
}
Ref<EditorSyntaxHighlighter> EditorSyntaxHighlighter::_create() const {
@@ -1156,8 +1155,8 @@ Ref<Script> ScriptEditor::_get_current_script() {
}
}
-Array ScriptEditor::_get_open_scripts() const {
- Array ret;
+TypedArray<Script> ScriptEditor::_get_open_scripts() const {
+ TypedArray<Script> ret;
Vector<Ref<Script>> scripts = get_open_scripts();
int scrits_amount = scripts.size();
for (int idx_script = 0; idx_script < scrits_amount; idx_script++) {
@@ -1408,8 +1407,6 @@ void ScriptEditor::_menu_option(int p_option) {
es->set_editor(EditorNode::get_singleton());
es->_run();
-
- EditorNode::get_undo_redo()->clear_history();
} break;
case FILE_CLOSE: {
if (current->is_unsaved()) {
@@ -1543,7 +1540,7 @@ void ScriptEditor::_show_save_theme_as_dialog() {
file_dialog_option = THEME_SAVE_AS;
file_dialog->clear_filters();
file_dialog->add_filter("*.tet");
- file_dialog->set_current_path(EditorPaths::get_singleton()->get_text_editor_themes_dir().plus_file(EditorSettings::get_singleton()->get("text_editor/theme/color_theme")));
+ file_dialog->set_current_path(EditorPaths::get_singleton()->get_text_editor_themes_dir().path_join(EditorSettings::get_singleton()->get("text_editor/theme/color_theme")));
file_dialog->popup_file_dialog();
file_dialog->set_title(TTR("Save Theme As..."));
}
@@ -1734,7 +1731,7 @@ void ScriptEditor::get_breakpoints(List<String> *p_breakpoints) {
continue;
}
- Array bpoints = se->get_breakpoints();
+ PackedInt32Array bpoints = se->get_breakpoints();
for (int j = 0; j < bpoints.size(); j++) {
p_breakpoints->push_back(base + ":" + itos((int)bpoints[j] + 1));
}
@@ -1853,10 +1850,12 @@ void ScriptEditor::_update_members_overview_visibility() {
if (members_overview_enabled && se->show_members_overview()) {
members_overview_alphabeta_sort_button->set_visible(true);
+ filter_methods->set_visible(true);
members_overview->set_visible(true);
overview_vbox->set_visible(true);
} else {
members_overview_alphabeta_sort_button->set_visible(false);
+ filter_methods->set_visible(false);
members_overview->set_visible(false);
overview_vbox->set_visible(false);
}
@@ -1911,6 +1910,7 @@ void ScriptEditor::_update_help_overview_visibility() {
if (help_overview_enabled) {
members_overview_alphabeta_sort_button->set_visible(false);
+ filter_methods->set_visible(false);
help_overview->set_visible(true);
overview_vbox->set_visible(true);
filename->set_text(se->get_name());
@@ -2038,7 +2038,7 @@ void ScriptEditor::_update_script_names() {
} break;
case DISPLAY_DIR_AND_NAME: {
if (!path.get_base_dir().get_file().is_empty()) {
- sd.name = path.get_base_dir().get_file().plus_file(name);
+ sd.name = path.get_base_dir().get_file().path_join(name);
} else {
sd.name = name;
}
@@ -2064,7 +2064,7 @@ void ScriptEditor::_update_script_names() {
name = name.get_file();
} break;
case DISPLAY_DIR_AND_NAME: {
- name = name.get_base_dir().get_file().plus_file(name.get_file());
+ name = name.get_base_dir().get_file().path_join(name.get_file());
} break;
default:
break;
@@ -2379,8 +2379,8 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
se->add_syntax_highlighter(highlighter);
if (script != nullptr && !highlighter_set) {
- Array languages = highlighter->_get_supported_languages();
- if (languages.find(script->get_language()->get_name()) > -1) {
+ PackedStringArray languages = highlighter->_get_supported_languages();
+ if (languages.has(script->get_language()->get_name())) {
se->set_syntax_highlighter(highlighter);
highlighter_set = true;
}
@@ -3267,7 +3267,7 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) {
p_layout->set_value("ScriptEditor", "list_split_offset", list_split->get_split_offset());
// Save the cache.
- script_editor_cache->save(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("script_editor_cache.cfg"));
+ script_editor_cache->save(EditorPaths::get_singleton()->get_project_settings_dir().path_join("script_editor_cache.cfg"));
}
void ScriptEditor::_help_class_open(const String &p_class) {
@@ -3445,8 +3445,8 @@ Vector<Ref<Script>> ScriptEditor::get_open_scripts() const {
return out_scripts;
}
-Array ScriptEditor::_get_open_script_editors() const {
- Array script_editors;
+TypedArray<ScriptEditorBase> ScriptEditor::_get_open_script_editors() const {
+ TypedArray<ScriptEditorBase> script_editors;
for (int i = 0; i < tab_container->get_tab_count(); i++) {
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
if (!se) {
@@ -3648,7 +3648,7 @@ ScriptEditor::ScriptEditor() {
current_theme = "";
script_editor_cache.instantiate();
- script_editor_cache->load(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("script_editor_cache.cfg"));
+ script_editor_cache->load(EditorPaths::get_singleton()->get_project_settings_dir().path_join("script_editor_cache.cfg"));
completion_cache = memnew(EditorScriptCodeCompletionCache);
restoring_layout = false;
@@ -3712,7 +3712,7 @@ ScriptEditor::ScriptEditor() {
members_overview_alphabeta_sort_button = memnew(Button);
members_overview_alphabeta_sort_button->set_flat(true);
- members_overview_alphabeta_sort_button->set_tooltip(TTR("Toggle alphabetical sorting of the method list."));
+ members_overview_alphabeta_sort_button->set_tooltip_text(TTR("Toggle alphabetical sorting of the method list."));
members_overview_alphabeta_sort_button->set_toggle_mode(true);
members_overview_alphabeta_sort_button->set_pressed(EditorSettings::get_singleton()->get("text_editor/script_list/sort_members_outline_alphabetically"));
members_overview_alphabeta_sort_button->connect("toggled", callable_mp(this, &ScriptEditor::_toggle_members_overview_alpha_sort));
@@ -3858,14 +3858,14 @@ ScriptEditor::ScriptEditor() {
site_search->set_text(TTR("Online Docs"));
site_search->connect("pressed", callable_mp(this, &ScriptEditor::_menu_option).bind(SEARCH_WEBSITE));
menu_hb->add_child(site_search);
- site_search->set_tooltip(TTR("Open Godot online documentation."));
+ site_search->set_tooltip_text(TTR("Open Godot online documentation."));
help_search = memnew(Button);
help_search->set_flat(true);
help_search->set_text(TTR("Search Help"));
help_search->connect("pressed", callable_mp(this, &ScriptEditor::_menu_option).bind(SEARCH_HELP));
menu_hb->add_child(help_search);
- help_search->set_tooltip(TTR("Search the reference documentation."));
+ help_search->set_tooltip_text(TTR("Search the reference documentation."));
menu_hb->add_child(memnew(VSeparator));
@@ -3874,14 +3874,14 @@ ScriptEditor::ScriptEditor() {
script_back->connect("pressed", callable_mp(this, &ScriptEditor::_history_back));
menu_hb->add_child(script_back);
script_back->set_disabled(true);
- script_back->set_tooltip(TTR("Go to previous edited document."));
+ script_back->set_tooltip_text(TTR("Go to previous edited document."));
script_forward = memnew(Button);
script_forward->set_flat(true);
script_forward->connect("pressed", callable_mp(this, &ScriptEditor::_history_forward));
menu_hb->add_child(script_forward);
script_forward->set_disabled(true);
- script_forward->set_tooltip(TTR("Go to next edited document."));
+ script_forward->set_tooltip_text(TTR("Go to next edited document."));
tab_container->connect("tab_changed", callable_mp(this, &ScriptEditor::_tab_changed));
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index 9f088aac49..d1898efb69 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -59,11 +59,11 @@ protected:
static void _bind_methods();
GDVIRTUAL0RC(String, _get_name)
- GDVIRTUAL0RC(Array, _get_supported_languages)
+ GDVIRTUAL0RC(PackedStringArray, _get_supported_languages)
public:
virtual String _get_name() const;
- virtual Array _get_supported_languages() const;
+ virtual PackedStringArray _get_supported_languages() const;
void _set_edited_resource(const Ref<Resource> &p_res) { edited_resourse = p_res; }
Ref<RefCounted> _get_edited_resource() { return edited_resourse; }
@@ -156,7 +156,7 @@ public:
virtual void ensure_focus() = 0;
virtual void tag_saved_version() = 0;
virtual void reload(bool p_soft) {}
- virtual Array get_breakpoints() = 0;
+ virtual PackedInt32Array get_breakpoints() = 0;
virtual void set_breakpoint(int p_line, bool p_enabled) = 0;
virtual void clear_breakpoints() = 0;
virtual void add_callback(const String &p_function, PackedStringArray p_args) = 0;
@@ -386,7 +386,7 @@ class ScriptEditor : public PanelContainer {
Array _get_cached_breakpoints_for_script(const String &p_path) const;
ScriptEditorBase *_get_current_editor() const;
- Array _get_open_script_editors() const;
+ TypedArray<ScriptEditorBase> _get_open_script_editors() const;
Ref<ConfigFile> script_editor_cache;
void _save_editor_state(ScriptEditorBase *p_editor);
@@ -452,7 +452,7 @@ class ScriptEditor : public PanelContainer {
void _file_dialog_action(String p_file);
Ref<Script> _get_current_script();
- Array _get_open_scripts() const;
+ TypedArray<Script> _get_open_scripts() const;
HashSet<String> textfile_extensions;
Ref<TextFile> _load_text_file(const String &p_path, Error *r_error) const;
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 5d5f452390..85e53011d6 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -596,7 +596,7 @@ void ScriptTextEditor::_update_bookmark_list() {
bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_bookmark"), BOOKMARK_GOTO_NEXT);
bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_bookmark"), BOOKMARK_GOTO_PREV);
- Array bookmark_list = code_editor->get_text_editor()->get_bookmarked_lines();
+ PackedInt32Array bookmark_list = code_editor->get_text_editor()->get_bookmarked_lines();
if (bookmark_list.size() == 0) {
return;
}
@@ -751,7 +751,7 @@ void ScriptTextEditor::_update_breakpoint_list() {
breakpoints_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_breakpoint"), DEBUG_GOTO_NEXT_BREAKPOINT);
breakpoints_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_breakpoint"), DEBUG_GOTO_PREV_BREAKPOINT);
- Array breakpoint_list = code_editor->get_text_editor()->get_breakpointed_lines();
+ PackedInt32Array breakpoint_list = code_editor->get_text_editor()->get_breakpointed_lines();
if (breakpoint_list.size() == 0) {
return;
}
@@ -942,7 +942,7 @@ void ScriptTextEditor::_validate_symbol(const String &p_symbol) {
String ScriptTextEditor::_get_absolute_path(const String &rel_path) {
String base_path = script->get_path().get_base_dir();
- String path = base_path.plus_file(rel_path);
+ String path = base_path.path_join(rel_path);
return path.replace("///", "//").simplify_path();
}
@@ -1264,7 +1264,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
EditorDebuggerNode::get_singleton()->set_breakpoint(script->get_path(), line + 1, dobreak);
} break;
case DEBUG_REMOVE_ALL_BREAKPOINTS: {
- Array bpoints = tx->get_breakpointed_lines();
+ PackedInt32Array bpoints = tx->get_breakpointed_lines();
for (int i = 0; i < bpoints.size(); i++) {
int line = bpoints[i];
@@ -1274,7 +1274,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
}
} break;
case DEBUG_GOTO_NEXT_BREAKPOINT: {
- Array bpoints = tx->get_breakpointed_lines();
+ PackedInt32Array bpoints = tx->get_breakpointed_lines();
if (bpoints.size() <= 0) {
return;
}
@@ -1300,7 +1300,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
} break;
case DEBUG_GOTO_PREV_BREAKPOINT: {
- Array bpoints = tx->get_breakpointed_lines();
+ PackedInt32Array bpoints = tx->get_breakpointed_lines();
if (bpoints.size() <= 0) {
return;
}
@@ -1441,7 +1441,7 @@ void ScriptTextEditor::reload(bool p_soft) {
scr->get_language()->reload_tool_script(scr, soft);
}
-Array ScriptTextEditor::get_breakpoints() {
+PackedInt32Array ScriptTextEditor::get_breakpoints() {
return code_editor->get_text_editor()->get_breakpointed_lines();
}
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index fc87c84a2c..8d2fb98721 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -229,7 +229,7 @@ public:
virtual void clear_executing_line() override;
virtual void reload(bool p_soft) override;
- virtual Array get_breakpoints() override;
+ virtual PackedInt32Array get_breakpoints() override;
virtual void set_breakpoint(int p_line, bool p_enabled) override;
virtual void clear_breakpoints() override;
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index e700412188..6674d15268 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -47,6 +47,50 @@
#include "servers/rendering/shader_preprocessor.h"
#include "servers/rendering/shader_types.h"
+/*** SHADER SYNTAX HIGHLIGHTER ****/
+
+Dictionary GDShaderSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_line) {
+ Dictionary color_map;
+
+ for (const Point2i &region : disabled_branch_regions) {
+ if (p_line >= region.x && p_line <= region.y) {
+ Dictionary highlighter_info;
+ highlighter_info["color"] = disabled_branch_color;
+
+ color_map[0] = highlighter_info;
+ return color_map;
+ }
+ }
+
+ return CodeHighlighter::_get_line_syntax_highlighting_impl(p_line);
+}
+
+void GDShaderSyntaxHighlighter::add_disabled_branch_region(const Point2i &p_region) {
+ ERR_FAIL_COND(p_region.x < 0);
+ ERR_FAIL_COND(p_region.y < 0);
+
+ for (int i = 0; i < disabled_branch_regions.size(); i++) {
+ ERR_FAIL_COND_MSG(disabled_branch_regions[i].x == p_region.x, "Branch region with a start line '" + itos(p_region.x) + "' already exists.");
+ }
+
+ Point2i disabled_branch_region;
+ disabled_branch_region.x = p_region.x;
+ disabled_branch_region.y = p_region.y;
+ disabled_branch_regions.push_back(disabled_branch_region);
+
+ clear_highlighting_cache();
+}
+
+void GDShaderSyntaxHighlighter::clear_disabled_branch_regions() {
+ disabled_branch_regions.clear();
+ clear_highlighting_cache();
+}
+
+void GDShaderSyntaxHighlighter::set_disabled_branch_color(const Color &p_color) {
+ disabled_branch_color = p_color;
+ clear_highlighting_cache();
+}
+
/*** SHADER SCRIPT EDITOR ****/
static bool saved_warnings_enabled = false;
@@ -134,6 +178,7 @@ void ShaderTextEditor::set_edited_code(const String &p_code) {
get_text_editor()->clear_undo_history();
get_text_editor()->call_deferred(SNAME("set_h_scroll"), 0);
get_text_editor()->call_deferred(SNAME("set_v_scroll"), 0);
+ get_text_editor()->tag_saved_version();
_validate_script();
_line_col_changed();
@@ -263,6 +308,7 @@ void ShaderTextEditor::_load_theme_settings() {
syntax_highlighter->clear_color_regions();
syntax_highlighter->add_color_region("/*", "*/", comment_color, false);
syntax_highlighter->add_color_region("//", "", comment_color, true);
+ syntax_highlighter->set_disabled_branch_color(comment_color);
text_editor->clear_comment_delimiters();
text_editor->add_comment_delimiter("/*", "*/", false);
@@ -345,7 +391,7 @@ void ShaderTextEditor::_code_complete_script(const String &p_code, List<ScriptLa
if (!complete_from_path.ends_with("/")) {
complete_from_path += "/";
}
- preprocessor.preprocess(p_code, code, nullptr, nullptr, nullptr, &pp_options, _complete_include_paths);
+ preprocessor.preprocess(p_code, "", code, nullptr, nullptr, nullptr, nullptr, &pp_options, _complete_include_paths);
complete_from_path = String();
if (pp_options.size()) {
for (const ScriptLanguage::CodeCompletionOption &E : pp_options) {
@@ -391,11 +437,29 @@ void ShaderTextEditor::_validate_script() {
String code_pp;
String error_pp;
List<ShaderPreprocessor::FilePosition> err_positions;
- last_compile_result = preprocessor.preprocess(code, code_pp, &error_pp, &err_positions);
+ List<ShaderPreprocessor::Region> regions;
+ String filename;
+ if (shader.is_valid()) {
+ filename = shader->get_path();
+ } else if (shader_inc.is_valid()) {
+ filename = shader_inc->get_path();
+ }
+ last_compile_result = preprocessor.preprocess(code, filename, code_pp, &error_pp, &err_positions, &regions);
for (int i = 0; i < get_text_editor()->get_line_count(); i++) {
get_text_editor()->set_line_background_color(i, Color(0, 0, 0, 0));
}
+
+ syntax_highlighter->clear_disabled_branch_regions();
+ for (const ShaderPreprocessor::Region &region : regions) {
+ if (!region.enabled) {
+ if (filename != region.file) {
+ continue;
+ }
+ syntax_highlighter->add_disabled_branch_region(Point2i(region.from_line, region.to_line));
+ }
+ }
+
set_error("");
set_error_count(0);
@@ -843,6 +907,7 @@ void ShaderEditor::save_external_data(const String &p_str) {
if (shader_inc.is_valid() && shader_inc != edited_shader_inc) {
ResourceSaver::save(shader_inc);
}
+ shader_editor->get_text_editor()->tag_saved_version();
disk_changed->hide();
}
@@ -851,6 +916,10 @@ void ShaderEditor::validate_script() {
shader_editor->_validate_script();
}
+bool ShaderEditor::is_unsaved() const {
+ return shader_editor->get_text_editor()->get_saved_version() != shader_editor->get_text_editor()->get_version();
+}
+
void ShaderEditor::apply_shaders() {
String editor_code = shader_editor->get_text_editor()->get_text();
if (shader.is_valid()) {
@@ -925,7 +994,7 @@ void ShaderEditor::_update_bookmark_list() {
bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_bookmark"), BOOKMARK_GOTO_NEXT);
bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_bookmark"), BOOKMARK_GOTO_PREV);
- Array bookmark_list = shader_editor->get_text_editor()->get_bookmarked_lines();
+ PackedInt32Array bookmark_list = shader_editor->get_text_editor()->get_bookmarked_lines();
if (bookmark_list.size() == 0) {
return;
}
@@ -1127,36 +1196,34 @@ ShaderEditor::ShaderEditor() {
void ShaderEditorPlugin::_update_shader_list() {
shader_list->clear();
for (uint32_t i = 0; i < edited_shaders.size(); i++) {
- String text;
- String path;
- String _class;
- String shader_name;
- if (edited_shaders[i].shader.is_valid()) {
- Ref<Shader> shader = edited_shaders[i].shader;
-
- path = shader->get_path();
- _class = shader->get_class();
- shader_name = shader->get_name();
- } else {
- Ref<ShaderInclude> shader_inc = edited_shaders[i].shader_inc;
-
- path = shader_inc->get_path();
- _class = shader_inc->get_class();
- shader_name = shader_inc->get_name();
+ Ref<Resource> shader = edited_shaders[i].shader;
+ if (shader.is_null()) {
+ shader = edited_shaders[i].shader_inc;
}
- if (path.is_resource_file()) {
- text = path.get_file();
- } else if (shader_name != "") {
- text = shader_name;
- } else {
- if (edited_shaders[i].shader.is_valid()) {
- text = _class + ":" + itos(edited_shaders[i].shader->get_instance_id());
- } else {
- text = _class + ":" + itos(edited_shaders[i].shader_inc->get_instance_id());
+ String path = shader->get_path();
+ String text = path.get_file();
+ if (text.is_empty()) {
+ // This appears for newly created built-in shaders before saving the scene.
+ text = TTR("[unsaved]");
+ } else if (shader->is_built_in()) {
+ const String &shader_name = shader->get_name();
+ if (!shader_name.is_empty()) {
+ text = vformat("%s (%s)", shader_name, text.get_slice("::", 0));
}
}
+ bool unsaved = false;
+ if (edited_shaders[i].shader_editor) {
+ unsaved = edited_shaders[i].shader_editor->is_unsaved();
+ }
+ // TODO: Handle visual shaders too.
+
+ if (unsaved) {
+ text += "(*)";
+ }
+
+ String _class = shader->get_class();
if (!shader_list->has_theme_icon(_class, SNAME("EditorIcons"))) {
_class = "TextFile";
}
@@ -1190,6 +1257,17 @@ void ShaderEditorPlugin::_update_shader_list_status() {
}
}
+void ShaderEditorPlugin::_move_shader_tab(int p_from, int p_to) {
+ if (p_from == p_to) {
+ return;
+ }
+ EditedShader es = edited_shaders[p_from];
+ edited_shaders.remove_at(p_from);
+ edited_shaders.insert(p_to, es);
+ shader_tabs->move_child(shader_tabs->get_tab_control(p_from), p_to);
+ _update_shader_list();
+}
+
void ShaderEditorPlugin::edit(Object *p_object) {
EditedShader es;
@@ -1206,7 +1284,7 @@ void ShaderEditorPlugin::edit(Object *p_object) {
es.shader_editor = memnew(ShaderEditor);
es.shader_editor->edit(si);
shader_tabs->add_child(es.shader_editor);
- es.shader_editor->connect("validation_changed", callable_mp(this, &ShaderEditorPlugin::_update_shader_list_status));
+ es.shader_editor->connect("validation_changed", callable_mp(this, &ShaderEditorPlugin::_update_shader_list));
} else {
Shader *s = Object::cast_to<Shader>(p_object);
for (uint32_t i = 0; i < edited_shaders.size(); i++) {
@@ -1226,7 +1304,7 @@ void ShaderEditorPlugin::edit(Object *p_object) {
es.shader_editor = memnew(ShaderEditor);
shader_tabs->add_child(es.shader_editor);
es.shader_editor->edit(s);
- es.shader_editor->connect("validation_changed", callable_mp(this, &ShaderEditorPlugin::_update_shader_list_status));
+ es.shader_editor->connect("validation_changed", callable_mp(this, &ShaderEditorPlugin::_update_shader_list));
}
}
@@ -1272,6 +1350,7 @@ void ShaderEditorPlugin::save_external_data() {
edited_shaders[i].shader_editor->save_external_data();
}
}
+ _update_shader_list();
}
void ShaderEditorPlugin::apply_changes() {
@@ -1289,6 +1368,12 @@ void ShaderEditorPlugin::_shader_selected(int p_index) {
shader_tabs->set_current_tab(p_index);
}
+void ShaderEditorPlugin::_shader_list_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index) {
+ if (p_mouse_button_index == MouseButton::MIDDLE) {
+ _close_shader(p_item);
+ }
+}
+
void ShaderEditorPlugin::_close_shader(int p_index) {
int index = shader_tabs->get_current_tab();
ERR_FAIL_INDEX(index, shader_tabs->get_tab_count());
@@ -1313,12 +1398,12 @@ void ShaderEditorPlugin::_menu_item_pressed(int p_index) {
switch (p_index) {
case FILE_NEW: {
String base_path = FileSystemDock::get_singleton()->get_current_path().get_base_dir();
- shader_create_dialog->config(base_path.plus_file("new_shader"), false, false, 0);
+ shader_create_dialog->config(base_path.path_join("new_shader"), false, false, 0);
shader_create_dialog->popup_centered();
} break;
case FILE_NEW_INCLUDE: {
String base_path = FileSystemDock::get_singleton()->get_current_path().get_base_dir();
- shader_create_dialog->config(base_path.plus_file("new_shader"), false, false, 2);
+ shader_create_dialog->config(base_path.path_join("new_shader"), false, false, 2);
shader_create_dialog->popup_centered();
} break;
case FILE_OPEN: {
@@ -1377,6 +1462,109 @@ void ShaderEditorPlugin::_shader_include_created(Ref<ShaderInclude> p_shader_inc
EditorNode::get_singleton()->push_item(p_shader_inc.ptr());
}
+Variant ShaderEditorPlugin::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
+ if (shader_list->get_item_count() == 0) {
+ return Variant();
+ }
+
+ int idx = shader_list->get_item_at_position(p_point);
+ if (idx < 0) {
+ return Variant();
+ }
+
+ HBoxContainer *drag_preview = memnew(HBoxContainer);
+ String preview_name = shader_list->get_item_text(idx);
+ Ref<Texture2D> preview_icon = shader_list->get_item_icon(idx);
+
+ if (!preview_icon.is_null()) {
+ TextureRect *tf = memnew(TextureRect);
+ tf->set_texture(preview_icon);
+ tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
+ drag_preview->add_child(tf);
+ }
+ Label *label = memnew(Label(preview_name));
+ drag_preview->add_child(label);
+ main_split->set_drag_preview(drag_preview);
+
+ Dictionary drag_data;
+ drag_data["type"] = "shader_list_element";
+ drag_data["shader_list_element"] = idx;
+
+ return drag_data;
+}
+
+bool ShaderEditorPlugin::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+ Dictionary d = p_data;
+ if (!d.has("type")) {
+ return false;
+ }
+
+ if (String(d["type"]) == "shader_list_element") {
+ return true;
+ }
+
+ if (String(d["type"]) == "files") {
+ Vector<String> files = d["files"];
+
+ if (files.size() == 0) {
+ return false;
+ }
+
+ for (int i = 0; i < files.size(); i++) {
+ String file = files[i];
+ if (ResourceLoader::exists(file, "Shader")) {
+ Ref<Shader> shader = ResourceLoader::load(file);
+ if (shader.is_valid()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ return false;
+}
+
+void ShaderEditorPlugin::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
+ if (!can_drop_data_fw(p_point, p_data, p_from)) {
+ return;
+ }
+
+ Dictionary d = p_data;
+ if (!d.has("type")) {
+ return;
+ }
+
+ if (String(d["type"]) == "shader_list_element") {
+ int idx = d["shader_list_element"];
+ int new_idx = shader_list->get_item_at_position(p_point);
+ _move_shader_tab(idx, new_idx);
+ return;
+ }
+
+ if (String(d["type"]) == "files") {
+ Vector<String> files = d["files"];
+
+ for (int i = 0; i < files.size(); i++) {
+ String file = files[i];
+ if (!ResourceLoader::exists(file, "Shader")) {
+ continue;
+ }
+
+ Ref<Resource> res = ResourceLoader::load(file);
+ if (res.is_valid()) {
+ edit(res.ptr());
+ }
+ }
+ }
+}
+
+void ShaderEditorPlugin::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_get_drag_data_fw", "point", "from"), &ShaderEditorPlugin::get_drag_data_fw);
+ ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "point", "data", "from"), &ShaderEditorPlugin::can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_drop_data_fw", "point", "data", "from"), &ShaderEditorPlugin::drop_data_fw);
+}
+
ShaderEditorPlugin::ShaderEditorPlugin() {
main_split = memnew(HSplitContainer);
@@ -1408,6 +1596,8 @@ ShaderEditorPlugin::ShaderEditorPlugin() {
shader_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
vb->add_child(shader_list);
shader_list->connect("item_selected", callable_mp(this, &ShaderEditorPlugin::_shader_selected));
+ shader_list->connect("item_clicked", callable_mp(this, &ShaderEditorPlugin::_shader_list_clicked));
+ shader_list->set_drag_forwarding(this);
main_split->add_child(vb);
vb->set_custom_minimum_size(Size2(200, 300) * EDSCALE);
diff --git a/editor/plugins/shader_editor_plugin.h b/editor/plugins/shader_editor_plugin.h
index 907de6ea87..afd38ef71a 100644
--- a/editor/plugins/shader_editor_plugin.h
+++ b/editor/plugins/shader_editor_plugin.h
@@ -48,6 +48,21 @@ class VisualShaderEditor;
class HSplitContainer;
class ShaderCreateDialog;
+class GDShaderSyntaxHighlighter : public CodeHighlighter {
+ GDCLASS(GDShaderSyntaxHighlighter, CodeHighlighter)
+
+private:
+ Vector<Point2i> disabled_branch_regions;
+ Color disabled_branch_color;
+
+public:
+ virtual Dictionary _get_line_syntax_highlighting_impl(int p_line) override;
+
+ void add_disabled_branch_region(const Point2i &p_region);
+ void clear_disabled_branch_regions();
+ void set_disabled_branch_color(const Color &p_color);
+};
+
class ShaderTextEditor : public CodeTextEditor {
GDCLASS(ShaderTextEditor, CodeTextEditor);
@@ -57,7 +72,7 @@ class ShaderTextEditor : public CodeTextEditor {
_ALWAYS_INLINE_ bool operator()(const ShaderWarning &p_a, const ShaderWarning &p_b) const { return (p_a.get_line() < p_b.get_line()); }
};
- Ref<CodeHighlighter> syntax_highlighter;
+ Ref<GDShaderSyntaxHighlighter> syntax_highlighter;
RichTextLabel *warnings_panel = nullptr;
Ref<Shader> shader;
Ref<ShaderInclude> shader_inc;
@@ -185,6 +200,7 @@ public:
void goto_line_selection(int p_line, int p_begin, int p_end);
void save_external_data(const String &p_str = "");
void validate_script();
+ bool is_unsaved() const;
virtual Size2 get_minimum_size() const override { return Size2(0, 200); }
@@ -226,6 +242,7 @@ class ShaderEditorPlugin : public EditorPlugin {
void _update_shader_list();
void _shader_selected(int p_index);
+ void _shader_list_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index);
void _menu_item_pressed(int p_index);
void _resource_saved(Object *obj);
void _close_shader(int p_index);
@@ -233,10 +250,16 @@ class ShaderEditorPlugin : public EditorPlugin {
void _shader_created(Ref<Shader> p_shader);
void _shader_include_created(Ref<ShaderInclude> p_shader_inc);
void _update_shader_list_status();
+ void _move_shader_tab(int p_from, int p_to);
+
+ Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
+ bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
+ void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
+
+protected:
+ static void _bind_methods();
public:
- virtual String get_name() const override { return "Shader"; }
- bool has_main_screen() const override { return false; }
virtual void edit(Object *p_object) override;
virtual bool handles(Object *p_object) const override;
virtual void make_visible(bool p_visible) override;
diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp
index 5a1505c232..3dc068a72a 100644
--- a/editor/plugins/skeleton_2d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_2d_editor_plugin.cpp
@@ -32,6 +32,7 @@
#include "canvas_item_editor_plugin.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/2d/mesh_instance_2d.h"
#include "scene/gui/box_container.h"
#include "thirdparty/misc/clipper.hpp"
@@ -59,7 +60,7 @@ void Skeleton2DEditor::_menu_option(int p_option) {
err_dialog->popup_centered();
return;
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Set Rest Pose to Bones"));
for (int i = 0; i < node->get_bone_count(); i++) {
Bone2D *bone = node->get_bone(i);
@@ -75,7 +76,7 @@ void Skeleton2DEditor::_menu_option(int p_option) {
err_dialog->popup_centered();
return;
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Create Rest Pose from Bones"));
for (int i = 0; i < node->get_bone_count(); i++) {
Bone2D *bone = node->get_bone(i);
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index ed0d14efb7..eac075c139 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -31,10 +31,10 @@
#include "skeleton_3d_editor_plugin.h"
#include "core/io/resource_saver.h"
-#include "editor/editor_file_dialog.h"
#include "editor/editor_node.h"
#include "editor/editor_properties.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/animation_player_editor_plugin.h"
#include "node_3d_editor_plugin.h"
#include "scene/3d/collision_shape_3d.h"
@@ -221,7 +221,7 @@ void Skeleton3DEditor::set_keyable(const bool p_keyable) {
};
void Skeleton3DEditor::set_bone_options_enabled(const bool p_bone_options_enabled) {
- skeleton_options->get_popup()->set_item_disabled(SKELETON_OPTION_INIT_SELECTED_POSES, !p_bone_options_enabled);
+ skeleton_options->get_popup()->set_item_disabled(SKELETON_OPTION_RESET_SELECTED_POSES, !p_bone_options_enabled);
skeleton_options->get_popup()->set_item_disabled(SKELETON_OPTION_SELECTED_POSES_TO_RESTS, !p_bone_options_enabled);
};
@@ -231,12 +231,12 @@ void Skeleton3DEditor::_on_click_skeleton_option(int p_skeleton_option) {
}
switch (p_skeleton_option) {
- case SKELETON_OPTION_INIT_ALL_POSES: {
- init_pose(true);
+ case SKELETON_OPTION_RESET_ALL_POSES: {
+ reset_pose(true);
break;
}
- case SKELETON_OPTION_INIT_SELECTED_POSES: {
- init_pose(false);
+ case SKELETON_OPTION_RESET_SELECTED_POSES: {
+ reset_pose(false);
break;
}
case SKELETON_OPTION_ALL_POSES_TO_RESTS: {
@@ -258,7 +258,7 @@ void Skeleton3DEditor::_on_click_skeleton_option(int p_skeleton_option) {
}
}
-void Skeleton3DEditor::init_pose(const bool p_all_bones) {
+void Skeleton3DEditor::reset_pose(const bool p_all_bones) {
if (!skeleton) {
return;
}
@@ -267,31 +267,25 @@ void Skeleton3DEditor::init_pose(const bool p_all_bones) {
return;
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS);
if (p_all_bones) {
for (int i = 0; i < bone_len; i++) {
- Transform3D rest = skeleton->get_bone_rest(i);
- ur->add_do_method(skeleton, "set_bone_pose_position", i, rest.origin);
- ur->add_do_method(skeleton, "set_bone_pose_rotation", i, rest.basis.get_rotation_quaternion());
- ur->add_do_method(skeleton, "set_bone_pose_scale", i, rest.basis.get_scale());
ur->add_undo_method(skeleton, "set_bone_pose_position", i, skeleton->get_bone_pose_position(i));
ur->add_undo_method(skeleton, "set_bone_pose_rotation", i, skeleton->get_bone_pose_rotation(i));
ur->add_undo_method(skeleton, "set_bone_pose_scale", i, skeleton->get_bone_pose_scale(i));
}
+ ur->add_do_method(skeleton, "reset_bone_poses");
} else {
// Todo: Do method with multiple bone selection.
if (selected_bone == -1) {
ur->commit_action();
return;
}
- Transform3D rest = skeleton->get_bone_rest(selected_bone);
- ur->add_do_method(skeleton, "set_bone_pose_position", selected_bone, rest.origin);
- ur->add_do_method(skeleton, "set_bone_pose_rotation", selected_bone, rest.basis.get_rotation_quaternion());
- ur->add_do_method(skeleton, "set_bone_pose_scale", selected_bone, rest.basis.get_scale());
ur->add_undo_method(skeleton, "set_bone_pose_position", selected_bone, skeleton->get_bone_pose_position(selected_bone));
ur->add_undo_method(skeleton, "set_bone_pose_rotation", selected_bone, skeleton->get_bone_pose_rotation(selected_bone));
ur->add_undo_method(skeleton, "set_bone_pose_scale", selected_bone, skeleton->get_bone_pose_scale(selected_bone));
+ ur->add_do_method(skeleton, "reset_bone_pose", selected_bone);
}
ur->commit_action();
}
@@ -340,7 +334,7 @@ void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) {
return;
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Set Bone Rest"), UndoRedo::MERGE_ENDS);
if (p_all_bones) {
for (int i = 0; i < bone_len; i++) {
@@ -360,7 +354,7 @@ void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) {
}
void Skeleton3DEditor::create_physical_skeleton() {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ERR_FAIL_COND(!get_tree());
Node *owner = get_tree()->get_edited_scene_root();
@@ -593,7 +587,7 @@ void Skeleton3DEditor::move_skeleton_bone(NodePath p_skeleton_path, int32_t p_se
Node *node = get_node_or_null(p_skeleton_path);
Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node);
ERR_FAIL_NULL(skeleton);
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Set Bone Parentage"));
// If the target is a child of ourselves, we move only *us* and not our children.
if (skeleton->is_bone_parent_of(p_target_boneidx, p_selected_boneidx)) {
@@ -696,8 +690,6 @@ void Skeleton3DEditor::update_editors() {
void Skeleton3DEditor::create_editors() {
set_h_size_flags(SIZE_EXPAND_FILL);
- add_theme_constant_override("separation", 0);
-
set_focus_mode(FOCUS_ALL);
Node3DEditor *ne = Node3DEditor::get_singleton();
@@ -721,8 +713,8 @@ void Skeleton3DEditor::create_editors() {
// Skeleton options.
PopupMenu *p = skeleton_options->get_popup();
- p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/init_all_poses", TTR("Init all Poses")), SKELETON_OPTION_INIT_ALL_POSES);
- p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/init_selected_poses", TTR("Init selected Poses")), SKELETON_OPTION_INIT_SELECTED_POSES);
+ p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/reset_all_poses", TTR("Reset all bone Poses")), SKELETON_OPTION_RESET_ALL_POSES);
+ p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/reset_selected_poses", TTR("Reset selected Poses")), SKELETON_OPTION_RESET_SELECTED_POSES);
p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/all_poses_to_rests", TTR("Apply all poses to rests")), SKELETON_OPTION_ALL_POSES_TO_RESTS);
p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/selected_poses_to_rests", TTR("Apply selected poses to rests")), SKELETON_OPTION_SELECTED_POSES_TO_RESTS);
p->add_item(TTR("Create physical skeleton"), SKELETON_OPTION_CREATE_PHYSICAL_SKELETON);
@@ -739,7 +731,7 @@ void Skeleton3DEditor::create_editors() {
edit_mode_button->set_flat(true);
edit_mode_button->set_toggle_mode(true);
edit_mode_button->set_focus_mode(FOCUS_NONE);
- edit_mode_button->set_tooltip(TTR("Edit Mode\nShow buttons on joints."));
+ edit_mode_button->set_tooltip_text(TTR("Edit Mode\nShow buttons on joints."));
edit_mode_button->connect("toggled", callable_mp(this, &Skeleton3DEditor::edit_mode_toggled));
edit_mode = false;
@@ -760,7 +752,7 @@ void Skeleton3DEditor::create_editors() {
key_loc_button->set_toggle_mode(true);
key_loc_button->set_pressed(false);
key_loc_button->set_focus_mode(FOCUS_NONE);
- key_loc_button->set_tooltip(TTR("Translation mask for inserting keys."));
+ key_loc_button->set_tooltip_text(TTR("Translation mask for inserting keys."));
animation_hb->add_child(key_loc_button);
key_rot_button = memnew(Button);
@@ -768,7 +760,7 @@ void Skeleton3DEditor::create_editors() {
key_rot_button->set_toggle_mode(true);
key_rot_button->set_pressed(true);
key_rot_button->set_focus_mode(FOCUS_NONE);
- key_rot_button->set_tooltip(TTR("Rotation mask for inserting keys."));
+ key_rot_button->set_tooltip_text(TTR("Rotation mask for inserting keys."));
animation_hb->add_child(key_rot_button);
key_scale_button = memnew(Button);
@@ -776,14 +768,14 @@ void Skeleton3DEditor::create_editors() {
key_scale_button->set_toggle_mode(true);
key_scale_button->set_pressed(false);
key_scale_button->set_focus_mode(FOCUS_NONE);
- key_scale_button->set_tooltip(TTR("Scale mask for inserting keys."));
+ key_scale_button->set_tooltip_text(TTR("Scale mask for inserting keys."));
animation_hb->add_child(key_scale_button);
key_insert_button = memnew(Button);
key_insert_button->set_flat(true);
key_insert_button->set_focus_mode(FOCUS_NONE);
key_insert_button->connect("pressed", callable_mp(this, &Skeleton3DEditor::insert_keys).bind(false));
- key_insert_button->set_tooltip(TTR("Insert key of bone poses already exist track."));
+ key_insert_button->set_tooltip_text(TTR("Insert key of bone poses already exist track."));
key_insert_button->set_shortcut(ED_SHORTCUT("skeleton_3d_editor/insert_key_to_existing_tracks", TTR("Insert Key (Existing Tracks)"), Key::INSERT));
animation_hb->add_child(key_insert_button);
@@ -791,7 +783,7 @@ void Skeleton3DEditor::create_editors() {
key_insert_all_button->set_flat(true);
key_insert_all_button->set_focus_mode(FOCUS_NONE);
key_insert_all_button->connect("pressed", callable_mp(this, &Skeleton3DEditor::insert_keys).bind(true));
- key_insert_all_button->set_tooltip(TTR("Insert key of all bone poses."));
+ key_insert_all_button->set_tooltip_text(TTR("Insert key of all bone poses."));
key_insert_all_button->set_shortcut(ED_SHORTCUT("skeleton_3d_editor/insert_key_of_all_bones", TTR("Insert Key (All Bones)"), KeyModifierMask::CMD + Key::INSERT));
animation_hb->add_child(key_insert_all_button);
@@ -829,20 +821,11 @@ void Skeleton3DEditor::create_editors() {
void Skeleton3DEditor::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_READY: {
- edit_mode_button->set_icon(get_theme_icon(SNAME("ToolBoneSelect"), SNAME("EditorIcons")));
- key_loc_button->set_icon(get_theme_icon(SNAME("KeyPosition"), SNAME("EditorIcons")));
- key_rot_button->set_icon(get_theme_icon(SNAME("KeyRotation"), SNAME("EditorIcons")));
- key_scale_button->set_icon(get_theme_icon(SNAME("KeyScale"), SNAME("EditorIcons")));
- key_insert_button->set_icon(get_theme_icon(SNAME("Key"), SNAME("EditorIcons")));
- key_insert_all_button->set_icon(get_theme_icon(SNAME("NewKey"), SNAME("EditorIcons")));
- get_tree()->connect("node_removed", callable_mp(this, &Skeleton3DEditor::_node_removed), Object::CONNECT_ONESHOT);
- break;
- }
case NOTIFICATION_ENTER_TREE: {
create_editors();
update_joint_tree();
update_editors();
+
joint_tree->connect("item_selected", callable_mp(this, &Skeleton3DEditor::_joint_tree_selection_changed));
joint_tree->connect("item_mouse_selected", callable_mp(this, &Skeleton3DEditor::_joint_tree_rmb_select));
#ifdef TOOLS_ENABLED
@@ -851,8 +834,23 @@ void Skeleton3DEditor::_notification(int p_what) {
skeleton->connect("bone_enabled_changed", callable_mp(this, &Skeleton3DEditor::_bone_enabled_changed));
skeleton->connect("show_rest_only_changed", callable_mp(this, &Skeleton3DEditor::_update_gizmo_visible));
#endif
- break;
- }
+
+ get_tree()->connect("node_removed", callable_mp(this, &Skeleton3DEditor::_node_removed), Object::CONNECT_ONESHOT);
+ } break;
+ case NOTIFICATION_READY: {
+ // Will trigger NOTIFICATION_THEME_CHANGED, but won't cause any loops if called here.
+ add_theme_constant_override("separation", 0);
+ } break;
+ case NOTIFICATION_THEME_CHANGED: {
+ edit_mode_button->set_icon(get_theme_icon(SNAME("ToolBoneSelect"), SNAME("EditorIcons")));
+ key_loc_button->set_icon(get_theme_icon(SNAME("KeyPosition"), SNAME("EditorIcons")));
+ key_rot_button->set_icon(get_theme_icon(SNAME("KeyRotation"), SNAME("EditorIcons")));
+ key_scale_button->set_icon(get_theme_icon(SNAME("KeyScale"), SNAME("EditorIcons")));
+ key_insert_button->set_icon(get_theme_icon(SNAME("Key"), SNAME("EditorIcons")));
+ key_insert_all_button->set_icon(get_theme_icon(SNAME("NewKey"), SNAME("EditorIcons")));
+
+ update_joint_tree();
+ } break;
}
}
@@ -921,8 +919,8 @@ void fragment() {
)");
handle_material->set_shader(handle_shader);
Ref<Texture2D> handle = EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("EditorBoneHandle"), SNAME("EditorIcons"));
- handle_material->set_shader_param("point_size", handle->get_width());
- handle_material->set_shader_param("texture_albedo", handle);
+ handle_material->set_shader_uniform("point_size", handle->get_width());
+ handle_material->set_shader_uniform("texture_albedo", handle);
handles_mesh_instance = memnew(MeshInstance3D);
handles_mesh_instance->set_cast_shadows_setting(GeometryInstance3D::SHADOW_CASTING_SETTING_OFF);
@@ -1315,7 +1313,7 @@ void Skeleton3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *p_gizmo, c
Skeleton3DEditor *se = Skeleton3DEditor::get_singleton();
Node3DEditor *ne = Node3DEditor::get_singleton();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Set Bone Transform"));
if (ne->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || ne->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) {
for (int i = 0; i < p_ids.size(); i++) {
diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h
index 975b54fa77..9747ed8374 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.h
+++ b/editor/plugins/skeleton_3d_editor_plugin.h
@@ -31,6 +31,7 @@
#ifndef SKELETON_3D_EDITOR_PLUGIN_H
#define SKELETON_3D_EDITOR_PLUGIN_H
+#include "editor/editor_file_dialog.h"
#include "editor/editor_plugin.h"
#include "editor/editor_properties.h"
#include "node_3d_editor_plugin.h"
@@ -40,6 +41,7 @@
#include "scene/resources/immediate_mesh.h"
class EditorInspectorPluginSkeleton;
+class EditorUndoRedoManager;
class Joint;
class PhysicalBone3D;
class Skeleton3DEditorPlugin;
@@ -63,7 +65,7 @@ class BoneTransformEditor : public VBoxContainer {
Skeleton3D *skeleton = nullptr;
// String property;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
bool toggle_enabled = false;
bool updating = false;
@@ -96,8 +98,8 @@ class Skeleton3DEditor : public VBoxContainer {
friend class Skeleton3DEditorPlugin;
enum SkeletonOption {
- SKELETON_OPTION_INIT_ALL_POSES,
- SKELETON_OPTION_INIT_SELECTED_POSES,
+ SKELETON_OPTION_RESET_ALL_POSES,
+ SKELETON_OPTION_RESET_SELECTED_POSES,
SKELETON_OPTION_ALL_POSES_TO_RESTS,
SKELETON_OPTION_SELECTED_POSES_TO_RESTS,
SKELETON_OPTION_CREATE_PHYSICAL_SKELETON,
@@ -148,7 +150,7 @@ class Skeleton3DEditor : public VBoxContainer {
void create_editors();
- void init_pose(const bool p_all_bones);
+ void reset_pose(const bool p_all_bones);
void pose_to_rest(const bool p_all_bones);
void insert_keys(const bool p_all_bones);
diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp
index 3323d865c2..e45c907e86 100644
--- a/editor/plugins/sprite_2d_editor_plugin.cpp
+++ b/editor/plugins/sprite_2d_editor_plugin.cpp
@@ -34,6 +34,7 @@
#include "core/math/geometry_2d.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/scene_tree_dock.h"
#include "scene/2d/collision_polygon_2d.h"
#include "scene/2d/light_occluder_2d.h"
@@ -160,6 +161,11 @@ void Sprite2DEditor::_menu_option(int p_option) {
}
void Sprite2DEditor::_update_mesh_data() {
+ if (node->get_owner() != get_tree()->get_edited_scene_root()) {
+ err_dialog->set_text(TTR("Can't convert a Sprite2D from a foreign scene."));
+ err_dialog->popup_centered();
+ }
+
Ref<Texture2D> texture = node->get_texture();
if (texture.is_null()) {
err_dialog->set_text(TTR("Sprite2D is empty!"));
@@ -337,7 +343,7 @@ void Sprite2DEditor::_convert_to_mesh_2d_node() {
MeshInstance2D *mesh_instance = memnew(MeshInstance2D);
mesh_instance->set_mesh(mesh);
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Convert to MeshInstance2D"));
ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", node, mesh_instance, true, false);
ur->add_do_reference(mesh_instance);
@@ -395,7 +401,7 @@ void Sprite2DEditor::_convert_to_polygon_2d_node() {
polygon_2d_instance->set_polygon(polygon);
polygon_2d_instance->set_polygons(polys);
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Convert to Polygon2D"));
ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", node, polygon_2d_instance, true, false);
ur->add_do_reference(polygon_2d_instance);
@@ -417,7 +423,7 @@ void Sprite2DEditor::_create_collision_polygon_2d_node() {
CollisionPolygon2D *collision_polygon_2d_instance = memnew(CollisionPolygon2D);
collision_polygon_2d_instance->set_polygon(outline);
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Create CollisionPolygon2D Sibling"));
ur->add_do_method(this, "_add_as_sibling_or_child", node, collision_polygon_2d_instance);
ur->add_do_reference(collision_polygon_2d_instance);
@@ -450,7 +456,7 @@ void Sprite2DEditor::_create_light_occluder_2d_node() {
LightOccluder2D *light_occluder_2d_instance = memnew(LightOccluder2D);
light_occluder_2d_instance->set_occluder_polygon(polygon);
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Create LightOccluder2D Sibling"));
ur->add_do_method(this, "_add_as_sibling_or_child", node, light_occluder_2d_instance);
ur->add_do_reference(light_occluder_2d_instance);
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index a39d24a167..87f0fc4ad0 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -37,6 +37,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/scene_tree_dock.h"
#include "scene/3d/sprite_3d.h"
#include "scene/gui/center_container.h"
@@ -1010,6 +1011,10 @@ void SpriteFramesEditor::edit(SpriteFrames *p_frames) {
}
}
+void SpriteFramesEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
+ undo_redo = p_undo_redo;
+}
+
Variant SpriteFramesEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
if (!frames->has_animation(edited_anim)) {
return false;
@@ -1156,13 +1161,13 @@ SpriteFramesEditor::SpriteFramesEditor() {
new_anim = memnew(Button);
new_anim->set_flat(true);
- new_anim->set_tooltip(TTR("New Animation"));
+ new_anim->set_tooltip_text(TTR("New Animation"));
hbc_animlist->add_child(new_anim);
new_anim->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_add));
remove_anim = memnew(Button);
remove_anim->set_flat(true);
- remove_anim->set_tooltip(TTR("Remove Animation"));
+ remove_anim->set_tooltip_text(TTR("Remove Animation"));
hbc_animlist->add_child(remove_anim);
remove_anim->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_remove));
@@ -1210,53 +1215,53 @@ SpriteFramesEditor::SpriteFramesEditor() {
load = memnew(Button);
load->set_flat(true);
- load->set_tooltip(TTR("Add a Texture from File"));
+ load->set_tooltip_text(TTR("Add a Texture from File"));
hbc->add_child(load);
load_sheet = memnew(Button);
load_sheet->set_flat(true);
- load_sheet->set_tooltip(TTR("Add Frames from a Sprite Sheet"));
+ load_sheet->set_tooltip_text(TTR("Add Frames from a Sprite Sheet"));
hbc->add_child(load_sheet);
hbc->add_child(memnew(VSeparator));
copy = memnew(Button);
copy->set_flat(true);
- copy->set_tooltip(TTR("Copy"));
+ copy->set_tooltip_text(TTR("Copy"));
hbc->add_child(copy);
paste = memnew(Button);
paste->set_flat(true);
- paste->set_tooltip(TTR("Paste"));
+ paste->set_tooltip_text(TTR("Paste"));
hbc->add_child(paste);
hbc->add_child(memnew(VSeparator));
empty = memnew(Button);
empty->set_flat(true);
- empty->set_tooltip(TTR("Insert Empty (Before)"));
+ empty->set_tooltip_text(TTR("Insert Empty (Before)"));
hbc->add_child(empty);
empty2 = memnew(Button);
empty2->set_flat(true);
- empty2->set_tooltip(TTR("Insert Empty (After)"));
+ empty2->set_tooltip_text(TTR("Insert Empty (After)"));
hbc->add_child(empty2);
hbc->add_child(memnew(VSeparator));
move_up = memnew(Button);
move_up->set_flat(true);
- move_up->set_tooltip(TTR("Move (Before)"));
+ move_up->set_tooltip_text(TTR("Move (Before)"));
hbc->add_child(move_up);
move_down = memnew(Button);
move_down->set_flat(true);
- move_down->set_tooltip(TTR("Move (After)"));
+ move_down->set_tooltip_text(TTR("Move (After)"));
hbc->add_child(move_down);
_delete = memnew(Button);
_delete->set_flat(true);
- _delete->set_tooltip(TTR("Delete"));
+ _delete->set_tooltip_text(TTR("Delete"));
hbc->add_child(_delete);
hbc->add_spacer();
@@ -1264,19 +1269,19 @@ SpriteFramesEditor::SpriteFramesEditor() {
zoom_out = memnew(Button);
zoom_out->connect("pressed", callable_mp(this, &SpriteFramesEditor::_zoom_out));
zoom_out->set_flat(true);
- zoom_out->set_tooltip(TTR("Zoom Out"));
+ zoom_out->set_tooltip_text(TTR("Zoom Out"));
hbc->add_child(zoom_out);
zoom_reset = memnew(Button);
zoom_reset->connect("pressed", callable_mp(this, &SpriteFramesEditor::_zoom_reset));
zoom_reset->set_flat(true);
- zoom_reset->set_tooltip(TTR("Zoom Reset"));
+ zoom_reset->set_tooltip_text(TTR("Zoom Reset"));
hbc->add_child(zoom_reset);
zoom_in = memnew(Button);
zoom_in->connect("pressed", callable_mp(this, &SpriteFramesEditor::_zoom_in));
zoom_in->set_flat(true);
- zoom_in->set_tooltip(TTR("Zoom In"));
+ zoom_in->set_tooltip_text(TTR("Zoom In"));
hbc->add_child(zoom_in);
file = memnew(EditorFileDialog);
@@ -1429,21 +1434,21 @@ SpriteFramesEditor::SpriteFramesEditor() {
split_sheet_zoom_out = memnew(Button);
split_sheet_zoom_out->set_flat(true);
split_sheet_zoom_out->set_focus_mode(FOCUS_NONE);
- split_sheet_zoom_out->set_tooltip(TTR("Zoom Out"));
+ split_sheet_zoom_out->set_tooltip_text(TTR("Zoom Out"));
split_sheet_zoom_out->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_zoom_out));
split_sheet_zoom_hb->add_child(split_sheet_zoom_out);
split_sheet_zoom_reset = memnew(Button);
split_sheet_zoom_reset->set_flat(true);
split_sheet_zoom_reset->set_focus_mode(FOCUS_NONE);
- split_sheet_zoom_reset->set_tooltip(TTR("Zoom Reset"));
+ split_sheet_zoom_reset->set_tooltip_text(TTR("Zoom Reset"));
split_sheet_zoom_reset->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_zoom_reset));
split_sheet_zoom_hb->add_child(split_sheet_zoom_reset);
split_sheet_zoom_in = memnew(Button);
split_sheet_zoom_in->set_flat(true);
split_sheet_zoom_in->set_focus_mode(FOCUS_NONE);
- split_sheet_zoom_in->set_tooltip(TTR("Zoom In"));
+ split_sheet_zoom_in->set_tooltip_text(TTR("Zoom In"));
split_sheet_zoom_in->connect("pressed", callable_mp(this, &SpriteFramesEditor::_sheet_zoom_in));
split_sheet_zoom_hb->add_child(split_sheet_zoom_in);
@@ -1471,7 +1476,7 @@ SpriteFramesEditor::SpriteFramesEditor() {
}
void SpriteFramesEditorPlugin::edit(Object *p_object) {
- frames_editor->set_undo_redo(&get_undo_redo());
+ frames_editor->set_undo_redo(get_undo_redo());
SpriteFrames *s;
AnimatedSprite2D *animated_sprite = Object::cast_to<AnimatedSprite2D>(p_object);
diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h
index 6352259b73..f2530b732f 100644
--- a/editor/plugins/sprite_frames_editor_plugin.h
+++ b/editor/plugins/sprite_frames_editor_plugin.h
@@ -45,6 +45,7 @@
#include "scene/gui/tree.h"
class EditorFileDialog;
+class EditorUndoRedoManager;
class SpriteFramesEditor : public HSplitContainer {
GDCLASS(SpriteFramesEditor, HSplitContainer);
@@ -151,7 +152,7 @@ class SpriteFramesEditor : public HSplitContainer {
bool updating;
bool updating_split_settings = false; // Skip SpinBox/Range callback when setting value by code.
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
@@ -176,7 +177,7 @@ protected:
static void _bind_methods();
public:
- void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; }
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void edit(SpriteFrames *p_frames);
SpriteFramesEditor();
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index 196d87da36..0900415b04 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -128,8 +128,8 @@ Control *TextEditor::get_base_editor() const {
return code_editor->get_text_editor();
}
-Array TextEditor::get_breakpoints() {
- return Array();
+PackedInt32Array TextEditor::get_breakpoints() {
+ return PackedInt32Array();
}
void TextEditor::reload_text() {
@@ -165,7 +165,7 @@ void TextEditor::_update_bookmark_list() {
bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_bookmark"), BOOKMARK_GOTO_NEXT);
bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_bookmark"), BOOKMARK_GOTO_PREV);
- Array bookmark_list = code_editor->get_text_editor()->get_bookmarked_lines();
+ PackedInt32Array bookmark_list = code_editor->get_text_editor()->get_bookmarked_lines();
if (bookmark_list.size() == 0) {
return;
}
diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h
index 4f0121da52..15f7c45653 100644
--- a/editor/plugins/text_editor.h
+++ b/editor/plugins/text_editor.h
@@ -118,7 +118,7 @@ public:
virtual Variant get_edit_state() override;
virtual void set_edit_state(const Variant &p_state) override;
virtual Vector<String> get_functions() override;
- virtual Array get_breakpoints() override;
+ virtual PackedInt32Array get_breakpoints() override;
virtual void set_breakpoint(int p_line, bool p_enabled) override{};
virtual void clear_breakpoints() override{};
virtual void goto_line(int p_line, bool p_with_error = false) override;
diff --git a/editor/plugins/texture_3d_editor_plugin.cpp b/editor/plugins/texture_3d_editor_plugin.cpp
index 0fc7079a24..64cafa17f3 100644
--- a/editor/plugins/texture_3d_editor_plugin.cpp
+++ b/editor/plugins/texture_3d_editor_plugin.cpp
@@ -57,8 +57,8 @@ void Texture3DEditor::_texture_changed() {
}
void Texture3DEditor::_update_material() {
- material->set_shader_param("layer", (layer->get_value() + 0.5) / texture->get_depth());
- material->set_shader_param("tex", texture->get_rid());
+ material->set_shader_uniform("layer", (layer->get_value() + 0.5) / texture->get_depth());
+ material->set_shader_uniform("tex", texture->get_rid());
String format = Image::get_format_name(texture->get_format());
diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp
index f6b02d5f80..be382759f5 100644
--- a/editor/plugins/texture_editor_plugin.cpp
+++ b/editor/plugins/texture_editor_plugin.cpp
@@ -137,7 +137,7 @@ TexturePreview::TexturePreview(Ref<Texture2D> p_texture, bool p_show_metadata) {
// It's okay that these colors are static since the grid color is static too.
metadata_label->add_theme_color_override("font_color", Color::named("white"));
- metadata_label->add_theme_color_override("font_color_shadow", Color::named("black"));
+ metadata_label->add_theme_color_override("font_shadow_color", Color::named("black"));
metadata_label->add_theme_font_size_override("font_size", 14 * EDSCALE);
metadata_label->add_theme_color_override("font_outline_color", Color::named("black"));
diff --git a/editor/plugins/texture_layered_editor_plugin.cpp b/editor/plugins/texture_layered_editor_plugin.cpp
index cb146fd342..2c6f70463d 100644
--- a/editor/plugins/texture_layered_editor_plugin.cpp
+++ b/editor/plugins/texture_layered_editor_plugin.cpp
@@ -68,9 +68,9 @@ void TextureLayeredEditor::_texture_changed() {
}
void TextureLayeredEditor::_update_material() {
- materials[0]->set_shader_param("layer", layer->get_value());
- materials[2]->set_shader_param("layer", layer->get_value());
- materials[texture->get_layered_type()]->set_shader_param("tex", texture->get_rid());
+ materials[0]->set_shader_uniform("layer", layer->get_value());
+ materials[2]->set_shader_uniform("layer", layer->get_value());
+ materials[texture->get_layered_type()]->set_shader_uniform("tex", texture->get_rid());
Vector3 v(1, 1, 1);
v.normalize();
@@ -79,10 +79,10 @@ void TextureLayeredEditor::_update_material() {
b.rotate(Vector3(1, 0, 0), x_rot);
b.rotate(Vector3(0, 1, 0), y_rot);
- materials[1]->set_shader_param("normal", v);
- materials[1]->set_shader_param("rot", b);
- materials[2]->set_shader_param("normal", v);
- materials[2]->set_shader_param("rot", b);
+ materials[1]->set_shader_uniform("normal", v);
+ materials[1]->set_shader_uniform("rot", b);
+ materials[2]->set_shader_uniform("normal", v);
+ materials[2]->set_shader_uniform("rot", b);
String format = Image::get_format_name(texture->get_format());
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 0bd8a8a484..50a7dc7f96 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -36,6 +36,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/check_box.h"
#include "scene/gui/separator.h"
#include "scene/gui/view_panner.h"
@@ -1109,19 +1110,19 @@ TextureRegionEditor::TextureRegionEditor() {
zoom_out = memnew(Button);
zoom_out->set_flat(true);
- zoom_out->set_tooltip(TTR("Zoom Out"));
+ zoom_out->set_tooltip_text(TTR("Zoom Out"));
zoom_out->connect("pressed", callable_mp(this, &TextureRegionEditor::_zoom_out));
zoom_hb->add_child(zoom_out);
zoom_reset = memnew(Button);
zoom_reset->set_flat(true);
- zoom_reset->set_tooltip(TTR("Zoom Reset"));
+ zoom_reset->set_tooltip_text(TTR("Zoom Reset"));
zoom_reset->connect("pressed", callable_mp(this, &TextureRegionEditor::_zoom_reset));
zoom_hb->add_child(zoom_reset);
zoom_in = memnew(Button);
zoom_in->set_flat(true);
- zoom_in->set_tooltip(TTR("Zoom In"));
+ zoom_in->set_tooltip_text(TTR("Zoom In"));
zoom_in->connect("pressed", callable_mp(this, &TextureRegionEditor::_zoom_in));
zoom_hb->add_child(zoom_in);
diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h
index a18c87f153..e3bbaf49fc 100644
--- a/editor/plugins/texture_region_editor_plugin.h
+++ b/editor/plugins/texture_region_editor_plugin.h
@@ -40,6 +40,7 @@
#include "scene/resources/texture.h"
class ViewPanner;
+class EditorUndoRedoManager;
class TextureRegionEditor : public AcceptDialog {
GDCLASS(TextureRegionEditor, AcceptDialog);
@@ -68,7 +69,7 @@ class TextureRegionEditor : public AcceptDialog {
VScrollBar *vscroll = nullptr;
HScrollBar *hscroll = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
Vector2 draw_ofs;
float draw_zoom = 0.0;
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index 2a61ea0baa..f6acd8ceda 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -35,8 +35,10 @@
#include "editor/editor_node.h"
#include "editor/editor_resource_picker.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/progress_dialog.h"
#include "scene/gui/color_picker.h"
+#include "scene/theme/theme_db.h"
void ThemeItemImportTree::_update_items_tree() {
import_items_tree->clear();
@@ -796,7 +798,7 @@ void ThemeItemImportTree::_import_selected() {
ProgressDialog::get_singleton()->end_task("import_theme_items");
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Import Theme Items"));
ur->add_do_method(*edited_theme, "clear");
@@ -1102,15 +1104,15 @@ ThemeItemImportTree::ThemeItemImportTree() {
button_set->set_alignment(BoxContainer::ALIGNMENT_END);
all_set->add_child(button_set);
select_all_items_button->set_flat(true);
- select_all_items_button->set_tooltip(select_all_items_tooltip);
+ select_all_items_button->set_tooltip_text(select_all_items_tooltip);
button_set->add_child(select_all_items_button);
select_all_items_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_select_all_data_type_pressed).bind(i));
select_full_items_button->set_flat(true);
- select_full_items_button->set_tooltip(select_full_items_tooltip);
+ select_full_items_button->set_tooltip_text(select_full_items_tooltip);
button_set->add_child(select_full_items_button);
select_full_items_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_select_full_data_type_pressed).bind(i));
deselect_all_items_button->set_flat(true);
- deselect_all_items_button->set_tooltip(deselect_all_items_tooltip);
+ deselect_all_items_button->set_tooltip_text(deselect_all_items_tooltip);
button_set->add_child(deselect_all_items_button);
deselect_all_items_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_deselect_all_data_type_pressed).bind(i));
@@ -1141,12 +1143,12 @@ ThemeItemImportTree::ThemeItemImportTree() {
import_collapse_types_button = memnew(Button);
import_collapse_types_button->set_flat(true);
- import_collapse_types_button->set_tooltip(TTR("Collapse types."));
+ import_collapse_types_button->set_tooltip_text(TTR("Collapse types."));
import_buttons->add_child(import_collapse_types_button);
import_collapse_types_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_toggle_type_items).bind(true));
import_expand_types_button = memnew(Button);
import_expand_types_button->set_flat(true);
- import_expand_types_button->set_tooltip(TTR("Expand types."));
+ import_expand_types_button->set_tooltip_text(TTR("Expand types."));
import_buttons->add_child(import_expand_types_button);
import_expand_types_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_toggle_type_items).bind(false));
@@ -1155,19 +1157,19 @@ ThemeItemImportTree::ThemeItemImportTree() {
import_select_all_button = memnew(Button);
import_select_all_button->set_flat(true);
import_select_all_button->set_text(TTR("Select All"));
- import_select_all_button->set_tooltip(TTR("Select all Theme items."));
+ import_select_all_button->set_tooltip_text(TTR("Select all Theme items."));
import_buttons->add_child(import_select_all_button);
import_select_all_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_select_all_items_pressed));
import_select_full_button = memnew(Button);
import_select_full_button->set_flat(true);
import_select_full_button->set_text(TTR("Select With Data"));
- import_select_full_button->set_tooltip(TTR("Select all Theme items with item data."));
+ import_select_full_button->set_tooltip_text(TTR("Select all Theme items with item data."));
import_buttons->add_child(import_select_full_button);
import_select_full_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_select_full_items_pressed));
import_deselect_all_button = memnew(Button);
import_deselect_all_button->set_flat(true);
import_deselect_all_button->set_text(TTR("Deselect All"));
- import_deselect_all_button->set_tooltip(TTR("Deselect all Theme items."));
+ import_deselect_all_button->set_tooltip_text(TTR("Deselect all Theme items."));
import_buttons->add_child(import_deselect_all_button);
import_deselect_all_button->connect("pressed", callable_mp(this, &ThemeItemImportTree::_deselect_all_items_pressed));
@@ -1201,7 +1203,7 @@ void ThemeItemEditorDialog::_dialog_about_to_show() {
_update_edit_types();
import_default_theme_items->set_edited_theme(edited_theme);
- import_default_theme_items->set_base_theme(Theme::get_default());
+ import_default_theme_items->set_base_theme(ThemeDB::get_singleton()->get_default_theme());
import_default_theme_items->reset_item_tree();
import_editor_theme_items->set_edited_theme(edited_theme);
@@ -1213,7 +1215,7 @@ void ThemeItemEditorDialog::_dialog_about_to_show() {
}
void ThemeItemEditorDialog::_update_edit_types() {
- Ref<Theme> base_theme = Theme::get_default();
+ Ref<Theme> base_theme = ThemeDB::get_singleton()->get_default_theme();
List<StringName> theme_types;
edited_theme->get_type_list(&theme_types);
@@ -1494,7 +1496,7 @@ void ThemeItemEditorDialog::_item_tree_button_pressed(Object *p_item, int p_colu
String item_name = item->get_text(0);
int data_type = item->get_parent()->get_metadata(0);
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Remove Theme Item"));
ur->add_do_method(*edited_theme, "clear_theme_item", (Theme::DataType)data_type, item_name, edited_item_type);
ur->add_undo_method(*edited_theme, "set_theme_item", (Theme::DataType)data_type, item_name, edited_item_type, edited_theme->get_theme_item((Theme::DataType)data_type, item_name, edited_item_type));
@@ -1513,7 +1515,7 @@ void ThemeItemEditorDialog::_add_theme_type(const String &p_new_text) {
const String new_type = edit_add_type_value->get_text().strip_edges();
edit_add_type_value->clear();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Add Theme Type"));
ur->add_do_method(*edited_theme, "add_type", new_type);
@@ -1525,7 +1527,7 @@ void ThemeItemEditorDialog::_add_theme_type(const String &p_new_text) {
}
void ThemeItemEditorDialog::_add_theme_item(Theme::DataType p_data_type, String p_item_name, String p_item_type) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Create Theme Item"));
switch (p_data_type) {
@@ -1570,7 +1572,7 @@ void ThemeItemEditorDialog::_remove_theme_type(const String &p_theme_type) {
Ref<Theme> old_snapshot = edited_theme->duplicate();
Ref<Theme> new_snapshot = edited_theme->duplicate();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Remove Theme Type"));
new_snapshot->remove_type(p_theme_type);
@@ -1593,7 +1595,7 @@ void ThemeItemEditorDialog::_remove_data_type_items(Theme::DataType p_data_type,
Ref<Theme> old_snapshot = edited_theme->duplicate();
Ref<Theme> new_snapshot = edited_theme->duplicate();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Remove Data Type Items From Theme"));
new_snapshot->get_theme_item_list(p_data_type, p_item_type, &names);
@@ -1622,14 +1624,14 @@ void ThemeItemEditorDialog::_remove_class_items() {
Ref<Theme> old_snapshot = edited_theme->duplicate();
Ref<Theme> new_snapshot = edited_theme->duplicate();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Remove Class Items From Theme"));
for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
Theme::DataType data_type = (Theme::DataType)dt;
names.clear();
- Theme::get_default()->get_theme_item_list(data_type, edited_item_type, &names);
+ ThemeDB::get_singleton()->get_default_theme()->get_theme_item_list(data_type, edited_item_type, &names);
for (const StringName &E : names) {
if (new_snapshot->has_theme_item_nocheck(data_type, E, edited_item_type)) {
new_snapshot->clear_theme_item(data_type, E, edited_item_type);
@@ -1658,7 +1660,7 @@ void ThemeItemEditorDialog::_remove_custom_items() {
Ref<Theme> old_snapshot = edited_theme->duplicate();
Ref<Theme> new_snapshot = edited_theme->duplicate();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Remove Custom Items From Theme"));
for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
@@ -1667,7 +1669,7 @@ void ThemeItemEditorDialog::_remove_custom_items() {
names.clear();
new_snapshot->get_theme_item_list(data_type, edited_item_type, &names);
for (const StringName &E : names) {
- if (!Theme::get_default()->has_theme_item_nocheck(data_type, E, edited_item_type)) {
+ if (!ThemeDB::get_singleton()->get_default_theme()->has_theme_item_nocheck(data_type, E, edited_item_type)) {
new_snapshot->clear_theme_item(data_type, E, edited_item_type);
if (dt == Theme::DATA_TYPE_STYLEBOX && theme_type_editor->is_stylebox_pinned(edited_theme->get_stylebox(E, edited_item_type))) {
@@ -1694,7 +1696,7 @@ void ThemeItemEditorDialog::_remove_all_items() {
Ref<Theme> old_snapshot = edited_theme->duplicate();
Ref<Theme> new_snapshot = edited_theme->duplicate();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Remove All Items From Theme"));
for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
@@ -1798,7 +1800,7 @@ void ThemeItemEditorDialog::_confirm_edit_theme_item() {
if (item_popup_mode == CREATE_THEME_ITEM) {
_add_theme_item(edit_item_data_type, theme_item_name->get_text(), edited_item_type);
} else if (item_popup_mode == RENAME_THEME_ITEM) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Rename Theme Item"));
ur->add_do_method(*edited_theme, "rename_theme_item", edit_item_data_type, edit_item_old_name, theme_item_name->get_text(), edited_item_type);
@@ -1953,42 +1955,42 @@ ThemeItemEditorDialog::ThemeItemEditorDialog(ThemeTypeEditor *p_theme_type_edito
edit_items_toolbar->add_child(edit_items_toolbar_add_label);
edit_items_add_color = memnew(Button);
- edit_items_add_color->set_tooltip(TTR("Add Color Item"));
+ edit_items_add_color->set_tooltip_text(TTR("Add Color Item"));
edit_items_add_color->set_flat(true);
edit_items_add_color->set_disabled(true);
edit_items_toolbar->add_child(edit_items_add_color);
edit_items_add_color->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_COLOR));
edit_items_add_constant = memnew(Button);
- edit_items_add_constant->set_tooltip(TTR("Add Constant Item"));
+ edit_items_add_constant->set_tooltip_text(TTR("Add Constant Item"));
edit_items_add_constant->set_flat(true);
edit_items_add_constant->set_disabled(true);
edit_items_toolbar->add_child(edit_items_add_constant);
edit_items_add_constant->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_CONSTANT));
edit_items_add_font = memnew(Button);
- edit_items_add_font->set_tooltip(TTR("Add Font Item"));
+ edit_items_add_font->set_tooltip_text(TTR("Add Font Item"));
edit_items_add_font->set_flat(true);
edit_items_add_font->set_disabled(true);
edit_items_toolbar->add_child(edit_items_add_font);
edit_items_add_font->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_FONT));
edit_items_add_font_size = memnew(Button);
- edit_items_add_font_size->set_tooltip(TTR("Add Font Size Item"));
+ edit_items_add_font_size->set_tooltip_text(TTR("Add Font Size Item"));
edit_items_add_font_size->set_flat(true);
edit_items_add_font_size->set_disabled(true);
edit_items_toolbar->add_child(edit_items_add_font_size);
edit_items_add_font_size->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_FONT_SIZE));
edit_items_add_icon = memnew(Button);
- edit_items_add_icon->set_tooltip(TTR("Add Icon Item"));
+ edit_items_add_icon->set_tooltip_text(TTR("Add Icon Item"));
edit_items_add_icon->set_flat(true);
edit_items_add_icon->set_disabled(true);
edit_items_toolbar->add_child(edit_items_add_icon);
edit_items_add_icon->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_open_add_theme_item_dialog).bind(Theme::DATA_TYPE_ICON));
edit_items_add_stylebox = memnew(Button);
- edit_items_add_stylebox->set_tooltip(TTR("Add StyleBox Item"));
+ edit_items_add_stylebox->set_tooltip_text(TTR("Add StyleBox Item"));
edit_items_add_stylebox->set_flat(true);
edit_items_add_stylebox->set_disabled(true);
edit_items_toolbar->add_child(edit_items_add_stylebox);
@@ -2001,21 +2003,21 @@ ThemeItemEditorDialog::ThemeItemEditorDialog(ThemeTypeEditor *p_theme_type_edito
edit_items_toolbar->add_child(edit_items_toolbar_remove_label);
edit_items_remove_class = memnew(Button);
- edit_items_remove_class->set_tooltip(TTR("Remove Class Items"));
+ edit_items_remove_class->set_tooltip_text(TTR("Remove Class Items"));
edit_items_remove_class->set_flat(true);
edit_items_remove_class->set_disabled(true);
edit_items_toolbar->add_child(edit_items_remove_class);
edit_items_remove_class->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_remove_class_items));
edit_items_remove_custom = memnew(Button);
- edit_items_remove_custom->set_tooltip(TTR("Remove Custom Items"));
+ edit_items_remove_custom->set_tooltip_text(TTR("Remove Custom Items"));
edit_items_remove_custom->set_flat(true);
edit_items_remove_custom->set_disabled(true);
edit_items_toolbar->add_child(edit_items_remove_custom);
edit_items_remove_custom->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_remove_custom_items));
edit_items_remove_all = memnew(Button);
- edit_items_remove_all->set_tooltip(TTR("Remove All Items"));
+ edit_items_remove_all->set_tooltip_text(TTR("Remove All Items"));
edit_items_remove_all->set_flat(true);
edit_items_remove_all->set_disabled(true);
edit_items_toolbar->add_child(edit_items_remove_all);
@@ -2128,7 +2130,7 @@ void ThemeTypeDialog::_update_add_type_options(const String &p_filter) {
add_type_options->clear();
List<StringName> names;
- Theme::get_default()->get_type_list(&names);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_list(&names);
if (include_own_types) {
edited_theme->get_type_list(&names);
}
@@ -2369,7 +2371,7 @@ HashMap<StringName, bool> ThemeTypeEditor::_get_type_items(String p_type_name, v
default_type = edited_theme->get_type_variation_base(p_type_name);
}
- (Theme::get_default().operator->()->*get_list_func)(default_type, &names);
+ (ThemeDB::get_singleton()->get_default_theme().operator->()->*get_list_func)(default_type, &names);
names.sort_custom<StringName::AlphCompare>();
for (const StringName &E : names) {
items[E] = false;
@@ -2411,7 +2413,7 @@ HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_
item_name->set_h_size_flags(SIZE_EXPAND_FILL);
item_name->set_clip_text(true);
item_name->set_text(p_item_name);
- item_name->set_tooltip(p_item_name);
+ item_name->set_tooltip_text(p_item_name);
item_name_container->add_child(item_name);
if (p_editable) {
@@ -2424,21 +2426,21 @@ HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_
Button *item_rename_button = memnew(Button);
item_rename_button->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
- item_rename_button->set_tooltip(TTR("Rename Item"));
+ item_rename_button->set_tooltip_text(TTR("Rename Item"));
item_rename_button->set_flat(true);
item_name_container->add_child(item_rename_button);
item_rename_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_rename_cbk).bind(p_data_type, p_item_name, item_name_container));
Button *item_remove_button = memnew(Button);
item_remove_button->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
- item_remove_button->set_tooltip(TTR("Remove Item"));
+ item_remove_button->set_tooltip_text(TTR("Remove Item"));
item_remove_button->set_flat(true);
item_name_container->add_child(item_remove_button);
item_remove_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_remove_cbk).bind(p_data_type, p_item_name));
Button *item_rename_confirm_button = memnew(Button);
item_rename_confirm_button->set_icon(get_theme_icon(SNAME("ImportCheck"), SNAME("EditorIcons")));
- item_rename_confirm_button->set_tooltip(TTR("Confirm Item Rename"));
+ item_rename_confirm_button->set_tooltip_text(TTR("Confirm Item Rename"));
item_rename_confirm_button->set_flat(true);
item_name_container->add_child(item_rename_confirm_button);
item_rename_confirm_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_rename_confirmed).bind(p_data_type, p_item_name, item_name_container));
@@ -2446,7 +2448,7 @@ HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_
Button *item_rename_cancel_button = memnew(Button);
item_rename_cancel_button->set_icon(get_theme_icon(SNAME("ImportFail"), SNAME("EditorIcons")));
- item_rename_cancel_button->set_tooltip(TTR("Cancel Item Rename"));
+ item_rename_cancel_button->set_tooltip_text(TTR("Cancel Item Rename"));
item_rename_cancel_button->set_flat(true);
item_name_container->add_child(item_rename_cancel_button);
item_rename_cancel_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_rename_canceled).bind(p_data_type, p_item_name, item_name_container));
@@ -2456,7 +2458,7 @@ HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_
Button *item_override_button = memnew(Button);
item_override_button->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
- item_override_button->set_tooltip(TTR("Override Item"));
+ item_override_button->set_tooltip_text(TTR("Override Item"));
item_override_button->set_flat(true);
item_name_container->add_child(item_override_button);
item_override_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_override_cbk).bind(p_data_type, p_item_name));
@@ -2495,7 +2497,7 @@ void ThemeTypeEditor::_update_type_items() {
item_editor->connect("color_changed", callable_mp(this, &ThemeTypeEditor::_color_item_changed).bind(E.key));
item_editor->get_popup()->connect("about_to_popup", callable_mp(EditorNode::get_singleton(), &EditorNode::setup_color_picker).bind(item_editor->get_picker()));
} else {
- item_editor->set_pick_color(Theme::get_default()->get_color(E.key, edited_type));
+ item_editor->set_pick_color(ThemeDB::get_singleton()->get_default_theme()->get_color(E.key, edited_type));
item_editor->set_disabled(true);
}
@@ -2528,7 +2530,7 @@ void ThemeTypeEditor::_update_type_items() {
item_editor->set_value(edited_theme->get_constant(E.key, edited_type));
item_editor->connect("value_changed", callable_mp(this, &ThemeTypeEditor::_constant_item_changed).bind(E.key));
} else {
- item_editor->set_value(Theme::get_default()->get_constant(E.key, edited_type));
+ item_editor->set_value(ThemeDB::get_singleton()->get_default_theme()->get_constant(E.key, edited_type));
item_editor->set_editable(false);
}
@@ -2562,8 +2564,8 @@ void ThemeTypeEditor::_update_type_items() {
item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item));
item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_font_item_changed).bind(E.key));
} else {
- if (Theme::get_default()->has_font(E.key, edited_type)) {
- item_editor->set_edited_resource(Theme::get_default()->get_font(E.key, edited_type));
+ if (ThemeDB::get_singleton()->get_default_theme()->has_font(E.key, edited_type)) {
+ item_editor->set_edited_resource(ThemeDB::get_singleton()->get_default_theme()->get_font(E.key, edited_type));
} else {
item_editor->set_edited_resource(Ref<Resource>());
}
@@ -2599,7 +2601,7 @@ void ThemeTypeEditor::_update_type_items() {
item_editor->set_value(edited_theme->get_font_size(E.key, edited_type));
item_editor->connect("value_changed", callable_mp(this, &ThemeTypeEditor::_font_size_item_changed).bind(E.key));
} else {
- item_editor->set_value(Theme::get_default()->get_font_size(E.key, edited_type));
+ item_editor->set_value(ThemeDB::get_singleton()->get_default_theme()->get_font_size(E.key, edited_type));
item_editor->set_editable(false);
}
@@ -2633,8 +2635,8 @@ void ThemeTypeEditor::_update_type_items() {
item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item));
item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_icon_item_changed).bind(E.key));
} else {
- if (Theme::get_default()->has_icon(E.key, edited_type)) {
- item_editor->set_edited_resource(Theme::get_default()->get_icon(E.key, edited_type));
+ if (ThemeDB::get_singleton()->get_default_theme()->has_icon(E.key, edited_type)) {
+ item_editor->set_edited_resource(ThemeDB::get_singleton()->get_default_theme()->get_icon(E.key, edited_type));
} else {
item_editor->set_edited_resource(Ref<Resource>());
}
@@ -2666,7 +2668,7 @@ void ThemeTypeEditor::_update_type_items() {
pin_leader_button->set_toggle_mode(true);
pin_leader_button->set_pressed(true);
pin_leader_button->set_icon(get_theme_icon(SNAME("Pin"), SNAME("EditorIcons")));
- pin_leader_button->set_tooltip(TTR("Unpin this StyleBox as a main style."));
+ pin_leader_button->set_tooltip_text(TTR("Unpin this StyleBox as a main style."));
item_control->add_child(pin_leader_button);
pin_leader_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_on_unpin_leader_button_pressed));
@@ -2709,12 +2711,12 @@ void ThemeTypeEditor::_update_type_items() {
pin_leader_button->set_flat(true);
pin_leader_button->set_toggle_mode(true);
pin_leader_button->set_icon(get_theme_icon(SNAME("Pin"), SNAME("EditorIcons")));
- pin_leader_button->set_tooltip(TTR("Pin this StyleBox as a main style. Editing its properties will update the same properties in all other StyleBoxes of this type."));
+ pin_leader_button->set_tooltip_text(TTR("Pin this StyleBox as a main style. Editing its properties will update the same properties in all other StyleBoxes of this type."));
item_control->add_child(pin_leader_button);
pin_leader_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_on_pin_leader_button_pressed).bind(item_editor, E.key));
} else {
- if (Theme::get_default()->has_stylebox(E.key, edited_type)) {
- item_editor->set_edited_resource(Theme::get_default()->get_stylebox(E.key, edited_type));
+ if (ThemeDB::get_singleton()->get_default_theme()->has_stylebox(E.key, edited_type)) {
+ item_editor->set_edited_resource(ThemeDB::get_singleton()->get_default_theme()->get_stylebox(E.key, edited_type));
} else {
item_editor->set_edited_resource(Ref<Resource>());
}
@@ -2769,62 +2771,62 @@ void ThemeTypeEditor::_add_default_type_items() {
{
names.clear();
- Theme::get_default()->get_icon_list(default_type, &names);
+ ThemeDB::get_singleton()->get_default_theme()->get_icon_list(default_type, &names);
for (const StringName &E : names) {
if (!new_snapshot->has_icon(E, edited_type)) {
- new_snapshot->set_icon(E, edited_type, Theme::get_default()->get_icon(E, edited_type));
+ new_snapshot->set_icon(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_icon(E, edited_type));
}
}
}
{
names.clear();
- Theme::get_default()->get_stylebox_list(default_type, &names);
+ ThemeDB::get_singleton()->get_default_theme()->get_stylebox_list(default_type, &names);
for (const StringName &E : names) {
if (!new_snapshot->has_stylebox(E, edited_type)) {
- new_snapshot->set_stylebox(E, edited_type, Theme::get_default()->get_stylebox(E, edited_type));
+ new_snapshot->set_stylebox(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_stylebox(E, edited_type));
}
}
}
{
names.clear();
- Theme::get_default()->get_font_list(default_type, &names);
+ ThemeDB::get_singleton()->get_default_theme()->get_font_list(default_type, &names);
for (const StringName &E : names) {
if (!new_snapshot->has_font(E, edited_type)) {
- new_snapshot->set_font(E, edited_type, Theme::get_default()->get_font(E, edited_type));
+ new_snapshot->set_font(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_font(E, edited_type));
}
}
}
{
names.clear();
- Theme::get_default()->get_font_size_list(default_type, &names);
+ ThemeDB::get_singleton()->get_default_theme()->get_font_size_list(default_type, &names);
for (const StringName &E : names) {
if (!new_snapshot->has_font_size(E, edited_type)) {
- new_snapshot->set_font_size(E, edited_type, Theme::get_default()->get_font_size(E, edited_type));
+ new_snapshot->set_font_size(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_font_size(E, edited_type));
}
}
}
{
names.clear();
- Theme::get_default()->get_color_list(default_type, &names);
+ ThemeDB::get_singleton()->get_default_theme()->get_color_list(default_type, &names);
for (const StringName &E : names) {
if (!new_snapshot->has_color(E, edited_type)) {
- new_snapshot->set_color(E, edited_type, Theme::get_default()->get_color(E, edited_type));
+ new_snapshot->set_color(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_color(E, edited_type));
}
}
}
{
names.clear();
- Theme::get_default()->get_constant_list(default_type, &names);
+ ThemeDB::get_singleton()->get_default_theme()->get_constant_list(default_type, &names);
for (const StringName &E : names) {
if (!new_snapshot->has_constant(E, edited_type)) {
- new_snapshot->set_constant(E, edited_type, Theme::get_default()->get_constant(E, edited_type));
+ new_snapshot->set_constant(E, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_constant(E, edited_type));
}
}
}
updating = false;
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Override All Default Theme Items"));
ur->add_do_method(*edited_theme, "merge_with", new_snapshot);
@@ -2844,7 +2846,7 @@ void ThemeTypeEditor::_item_add_cbk(int p_data_type, Control *p_control) {
}
String item_name = le->get_text().strip_edges();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Add Theme Item"));
switch (p_data_type) {
@@ -2889,16 +2891,16 @@ void ThemeTypeEditor::_item_add_lineedit_cbk(String p_value, int p_data_type, Co
}
void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Override Theme Item"));
switch (p_data_type) {
case Theme::DATA_TYPE_COLOR: {
- ur->add_do_method(*edited_theme, "set_color", p_item_name, edited_type, Theme::get_default()->get_color(p_item_name, edited_type));
+ ur->add_do_method(*edited_theme, "set_color", p_item_name, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_color(p_item_name, edited_type));
ur->add_undo_method(*edited_theme, "clear_color", p_item_name, edited_type);
} break;
case Theme::DATA_TYPE_CONSTANT: {
- ur->add_do_method(*edited_theme, "set_constant", p_item_name, edited_type, Theme::get_default()->get_constant(p_item_name, edited_type));
+ ur->add_do_method(*edited_theme, "set_constant", p_item_name, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_constant(p_item_name, edited_type));
ur->add_undo_method(*edited_theme, "clear_constant", p_item_name, edited_type);
} break;
case Theme::DATA_TYPE_FONT: {
@@ -2906,7 +2908,7 @@ void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) {
ur->add_undo_method(*edited_theme, "clear_font", p_item_name, edited_type);
} break;
case Theme::DATA_TYPE_FONT_SIZE: {
- ur->add_do_method(*edited_theme, "set_font_size", p_item_name, edited_type, Theme::get_default()->get_font_size(p_item_name, edited_type));
+ ur->add_do_method(*edited_theme, "set_font_size", p_item_name, edited_type, ThemeDB::get_singleton()->get_default_theme()->get_font_size(p_item_name, edited_type));
ur->add_undo_method(*edited_theme, "clear_font_size", p_item_name, edited_type);
} break;
case Theme::DATA_TYPE_ICON: {
@@ -2928,7 +2930,7 @@ void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) {
}
void ThemeTypeEditor::_item_remove_cbk(int p_data_type, String p_item_name) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Remove Theme Item"));
switch (p_data_type) {
@@ -3002,7 +3004,7 @@ void ThemeTypeEditor::_item_rename_confirmed(int p_data_type, String p_item_name
return;
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Rename Theme Item"));
switch (p_data_type) {
@@ -3058,7 +3060,7 @@ void ThemeTypeEditor::_item_rename_canceled(int p_data_type, String p_item_name,
}
void ThemeTypeEditor::_color_item_changed(Color p_value, String p_item_name) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Set Color Item in Theme"), UndoRedo::MERGE_ENDS);
ur->add_do_method(*edited_theme, "set_color", p_item_name, edited_type, p_value);
ur->add_undo_method(*edited_theme, "set_color", p_item_name, edited_type, edited_theme->get_color(p_item_name, edited_type));
@@ -3066,7 +3068,7 @@ void ThemeTypeEditor::_color_item_changed(Color p_value, String p_item_name) {
}
void ThemeTypeEditor::_constant_item_changed(float p_value, String p_item_name) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Set Constant Item in Theme"));
ur->add_do_method(*edited_theme, "set_constant", p_item_name, edited_type, p_value);
ur->add_undo_method(*edited_theme, "set_constant", p_item_name, edited_type, edited_theme->get_constant(p_item_name, edited_type));
@@ -3074,7 +3076,7 @@ void ThemeTypeEditor::_constant_item_changed(float p_value, String p_item_name)
}
void ThemeTypeEditor::_font_size_item_changed(float p_value, String p_item_name) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Set Font Size Item in Theme"));
ur->add_do_method(*edited_theme, "set_font_size", p_item_name, edited_type, p_value);
ur->add_undo_method(*edited_theme, "set_font_size", p_item_name, edited_type, edited_theme->get_font_size(p_item_name, edited_type));
@@ -3086,7 +3088,7 @@ void ThemeTypeEditor::_edit_resource_item(Ref<Resource> p_resource, bool p_edit)
}
void ThemeTypeEditor::_font_item_changed(Ref<Font> p_value, String p_item_name) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Set Font Item in Theme"));
ur->add_do_method(*edited_theme, "set_font", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<Font>());
@@ -3103,7 +3105,7 @@ void ThemeTypeEditor::_font_item_changed(Ref<Font> p_value, String p_item_name)
}
void ThemeTypeEditor::_icon_item_changed(Ref<Texture2D> p_value, String p_item_name) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Set Icon Item in Theme"));
ur->add_do_method(*edited_theme, "set_icon", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<Texture2D>());
@@ -3120,7 +3122,7 @@ void ThemeTypeEditor::_icon_item_changed(Ref<Texture2D> p_value, String p_item_n
}
void ThemeTypeEditor::_stylebox_item_changed(Ref<StyleBox> p_value, String p_item_name) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Set Stylebox Item in Theme"));
ur->add_do_method(*edited_theme, "set_stylebox", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<StyleBox>());
@@ -3163,7 +3165,7 @@ void ThemeTypeEditor::_on_pin_leader_button_pressed(Control *p_editor, String p_
stylebox = Object::cast_to<EditorResourcePicker>(p_editor)->get_edited_resource();
}
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Pin Stylebox"));
ur->add_do_method(this, "_pin_leading_stylebox", p_item_name, stylebox);
@@ -3196,7 +3198,7 @@ void ThemeTypeEditor::_pin_leading_stylebox(String p_item_name, Ref<StyleBox> p_
}
void ThemeTypeEditor::_on_unpin_leader_button_pressed() {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Unpin Stylebox"));
ur->add_do_method(this, "_unpin_leading_stylebox");
ur->add_undo_method(this, "_pin_leading_stylebox", leading_stylebox.item_name, leading_stylebox.stylebox);
@@ -3265,7 +3267,7 @@ void ThemeTypeEditor::_update_stylebox_from_leading() {
}
void ThemeTypeEditor::_type_variation_changed(const String p_value) {
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Set Theme Type Variation"));
if (p_value.is_empty()) {
@@ -3381,11 +3383,12 @@ ThemeTypeEditor::ThemeTypeEditor() {
theme_type_list = memnew(OptionButton);
theme_type_list->set_h_size_flags(SIZE_EXPAND_FILL);
+ theme_type_list->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
type_list_hb->add_child(theme_type_list);
theme_type_list->connect("item_selected", callable_mp(this, &ThemeTypeEditor::_list_type_selected));
add_type_button = memnew(Button);
- add_type_button->set_tooltip(TTR("Add a type from a list of available types or create a new one."));
+ add_type_button->set_tooltip_text(TTR("Add a type from a list of available types or create a new one."));
type_list_hb->add_child(add_type_button);
add_type_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_add_type_button_cbk));
@@ -3395,7 +3398,7 @@ ThemeTypeEditor::ThemeTypeEditor() {
show_default_items_button = memnew(CheckButton);
show_default_items_button->set_h_size_flags(SIZE_EXPAND_FILL);
show_default_items_button->set_text(TTR("Show Default"));
- show_default_items_button->set_tooltip(TTR("Show default type items alongside items that have been overridden."));
+ show_default_items_button->set_tooltip_text(TTR("Show default type items alongside items that have been overridden."));
show_default_items_button->set_pressed(true);
type_controls->add_child(show_default_items_button);
show_default_items_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_update_type_items));
@@ -3403,7 +3406,7 @@ ThemeTypeEditor::ThemeTypeEditor() {
Button *add_default_items_button = memnew(Button);
add_default_items_button->set_h_size_flags(SIZE_EXPAND_FILL);
add_default_items_button->set_text(TTR("Override All"));
- add_default_items_button->set_tooltip(TTR("Override all default type items."));
+ add_default_items_button->set_tooltip_text(TTR("Override all default type items."));
type_controls->add_child(add_default_items_button);
add_default_items_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_add_default_type_items));
@@ -3450,7 +3453,7 @@ ThemeTypeEditor::ThemeTypeEditor() {
type_variation_edit->connect("focus_exited", callable_mp(this, &ThemeTypeEditor::_update_type_items));
type_variation_button = memnew(Button);
type_variation_hb->add_child(type_variation_button);
- type_variation_button->set_tooltip(TTR("Select the variation base type from a list of available types."));
+ type_variation_button->set_tooltip_text(TTR("Select the variation base type from a list of available types."));
type_variation_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_add_type_variation_cbk));
type_variation_locked = memnew(Label);
@@ -3631,7 +3634,7 @@ ThemeEditor::ThemeEditor() {
Button *theme_edit_button = memnew(Button);
theme_edit_button->set_text(TTR("Manage Items..."));
- theme_edit_button->set_tooltip(TTR("Add, remove, organize and import Theme items."));
+ theme_edit_button->set_tooltip_text(TTR("Add, remove, organize and import Theme items."));
theme_edit_button->set_flat(true);
theme_edit_button->connect("pressed", callable_mp(this, &ThemeEditor::_theme_edit_button_cbk));
top_menu->add_child(theme_edit_button);
diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp
index b5c6c6d651..ea8da1e86d 100644
--- a/editor/plugins/theme_editor_preview.cpp
+++ b/editor/plugins/theme_editor_preview.cpp
@@ -40,6 +40,7 @@
#include "scene/gui/color_picker.h"
#include "scene/gui/progress_bar.h"
#include "scene/resources/packed_scene.h"
+#include "scene/theme/theme_db.h"
constexpr double REFRESH_TIMER = 1.5;
@@ -227,7 +228,7 @@ ThemeEditorPreview::ThemeEditorPreview() {
preview_toolbar->add_child(picker_button);
picker_button->set_flat(true);
picker_button->set_toggle_mode(true);
- picker_button->set_tooltip(TTR("Toggle the control picker, allowing to visually select control types for edit."));
+ picker_button->set_tooltip_text(TTR("Toggle the control picker, allowing to visually select control types for edit."));
picker_button->connect("pressed", callable_mp(this, &ThemeEditorPreview::_picker_button_cbk));
MarginContainer *preview_body = memnew(MarginContainer);
@@ -240,7 +241,7 @@ ThemeEditorPreview::ThemeEditorPreview() {
MarginContainer *preview_root = memnew(MarginContainer);
preview_container->add_child(preview_root);
- preview_root->set_theme(Theme::get_default());
+ preview_root->set_theme(ThemeDB::get_singleton()->get_default_theme());
preview_root->set_clip_contents(true);
preview_root->set_custom_minimum_size(Size2(450, 0) * EDSCALE);
preview_root->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -517,7 +518,7 @@ SceneThemeEditorPreview::SceneThemeEditorPreview() {
reload_scene_button = memnew(Button);
reload_scene_button->set_flat(true);
- reload_scene_button->set_tooltip(TTR("Reload the scene to reflect its most actual state."));
+ reload_scene_button->set_tooltip_text(TTR("Reload the scene to reflect its most actual state."));
preview_toolbar->add_child(reload_scene_button);
reload_scene_button->connect("pressed", callable_mp(this, &SceneThemeEditorPreview::_reload_scene));
}
diff --git a/editor/plugins/tiles/atlas_merging_dialog.cpp b/editor/plugins/tiles/atlas_merging_dialog.cpp
index 3fe6778f48..de4f3f7989 100644
--- a/editor/plugins/tiles/atlas_merging_dialog.cpp
+++ b/editor/plugins/tiles/atlas_merging_dialog.cpp
@@ -33,6 +33,7 @@
#include "editor/editor_file_dialog.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/control.h"
#include "scene/gui/split_container.h"
diff --git a/editor/plugins/tiles/atlas_merging_dialog.h b/editor/plugins/tiles/atlas_merging_dialog.h
index c54e259594..c7e4635d16 100644
--- a/editor/plugins/tiles/atlas_merging_dialog.h
+++ b/editor/plugins/tiles/atlas_merging_dialog.h
@@ -38,6 +38,7 @@
#include "scene/resources/tile_set.h"
class EditorFileDialog;
+class EditorUndoRedoManager;
class AtlasMergingDialog : public ConfirmationDialog {
GDCLASS(AtlasMergingDialog, ConfirmationDialog);
@@ -49,7 +50,7 @@ private:
LocalVector<HashMap<Vector2i, Vector2i>> merged_mapping;
Ref<TileSet> tile_set;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
// Settings.
int next_line_after_column = 30;
diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp
index f119ada810..8d2b150d6d 100644
--- a/editor/plugins/tiles/tile_atlas_view.cpp
+++ b/editor/plugins/tiles/tile_atlas_view.cpp
@@ -127,8 +127,8 @@ void TileAtlasView::_update_zoom_and_panning(bool p_zoom_on_mouse_pos) {
}
// Update the backgrounds.
- background_left->update();
- background_right->update();
+ background_left->set_size(base_tiles_root_control->get_custom_minimum_size());
+ background_right->set_size(alternative_tiles_root_control->get_custom_minimum_size());
// Zoom on the position.
if (p_zoom_on_mouse_pos) {
@@ -160,7 +160,7 @@ void TileAtlasView::_center_view() {
}
void TileAtlasView::_base_tiles_root_control_gui_input(const Ref<InputEvent> &p_event) {
- base_tiles_root_control->set_tooltip("");
+ base_tiles_root_control->set_tooltip_text("");
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
@@ -169,7 +169,7 @@ void TileAtlasView::_base_tiles_root_control_gui_input(const Ref<InputEvent> &p_
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
coords = tile_set_atlas_source->get_tile_at_coords(coords);
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
- base_tiles_root_control->set_tooltip(vformat(TTR("Source: %d\nAtlas coordinates: %s\nAlternative: 0"), source_id, coords));
+ base_tiles_root_control->set_tooltip_text(vformat(TTR("Source: %d\nAtlas coordinates: %s\nAlternative: 0"), source_id, coords));
}
}
}
@@ -319,7 +319,7 @@ void TileAtlasView::_draw_base_tiles_shape_grid() {
}
void TileAtlasView::_alternative_tiles_root_control_gui_input(const Ref<InputEvent> &p_event) {
- alternative_tiles_root_control->set_tooltip("");
+ alternative_tiles_root_control->set_tooltip_text("");
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
@@ -328,7 +328,7 @@ void TileAtlasView::_alternative_tiles_root_control_gui_input(const Ref<InputEve
Vector2i coords = Vector2i(coords3.x, coords3.y);
int alternative_id = coords3.z;
if (coords != TileSetSource::INVALID_ATLAS_COORDS && alternative_id != TileSetSource::INVALID_TILE_ALTERNATIVE) {
- alternative_tiles_root_control->set_tooltip(vformat(TTR("Source: %d\nAtlas coordinates: %s\nAlternative: %d"), source_id, coords, alternative_id));
+ alternative_tiles_root_control->set_tooltip_text(vformat(TTR("Source: %d\nAtlas coordinates: %s\nAlternative: %d"), source_id, coords, alternative_id));
}
}
}
@@ -374,13 +374,11 @@ void TileAtlasView::_draw_alternatives() {
void TileAtlasView::_draw_background_left() {
Ref<Texture2D> texture = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons"));
- background_left->set_size(base_tiles_root_control->get_custom_minimum_size());
background_left->draw_texture_rect(texture, Rect2(Vector2(), background_left->get_size()), true);
}
void TileAtlasView::_draw_background_right() {
Ref<Texture2D> texture = get_theme_icon(SNAME("Checkerboard"), SNAME("EditorIcons"));
- background_right->set_size(alternative_tiles_root_control->get_custom_minimum_size());
background_right->draw_texture_rect(texture, Rect2(Vector2(), background_right->get_size()), true);
}
@@ -405,23 +403,6 @@ void TileAtlasView::set_atlas_source(TileSet *p_tile_set, TileSetAtlasSource *p_
// Update everything.
_update_zoom_and_panning();
- // Change children control size.
- Size2i base_tiles_control_size = _compute_base_tiles_control_size();
- for (int i = 0; i < base_tiles_drawing_root->get_child_count(); i++) {
- Control *control = Object::cast_to<Control>(base_tiles_drawing_root->get_child(i));
- if (control) {
- control->set_size(base_tiles_control_size);
- }
- }
-
- Size2i alternative_control_size = _compute_alternative_tiles_control_size();
- for (int i = 0; i < alternative_tiles_drawing_root->get_child_count(); i++) {
- Control *control = Object::cast_to<Control>(alternative_tiles_drawing_root->get_child(i));
- if (control) {
- control->set_size(alternative_control_size);
- }
- }
-
// Update.
base_tiles_draw->update();
base_tiles_texture_grid->update();
@@ -561,7 +542,7 @@ TileAtlasView::TileAtlasView() {
button_center_view->connect("pressed", callable_mp(this, &TileAtlasView::_center_view));
button_center_view->set_flat(true);
button_center_view->set_disabled(true);
- button_center_view->set_tooltip(TTR("Center View"));
+ button_center_view->set_tooltip_text(TTR("Center View"));
add_child(button_center_view);
panner.instantiate();
@@ -613,7 +594,7 @@ TileAtlasView::TileAtlasView() {
background_left = memnew(Control);
background_left->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
- background_left->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
+ background_left->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT);
background_left->set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED);
background_left->connect("draw", callable_mp(this, &TileAtlasView::_draw_background_left));
base_tiles_root_control->add_child(background_left);
@@ -651,23 +632,26 @@ TileAtlasView::TileAtlasView() {
alternative_tiles_root_control = memnew(Control);
alternative_tiles_root_control->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ alternative_tiles_root_control->set_v_size_flags(Control::SIZE_EXPAND_FILL);
alternative_tiles_root_control->connect("gui_input", callable_mp(this, &TileAtlasView::_alternative_tiles_root_control_gui_input));
right_vbox->add_child(alternative_tiles_root_control);
background_right = memnew(Control);
background_right->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ background_right->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT);
background_right->set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED);
background_right->connect("draw", callable_mp(this, &TileAtlasView::_draw_background_right));
-
alternative_tiles_root_control->add_child(background_right);
alternative_tiles_drawing_root = memnew(Control);
alternative_tiles_drawing_root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ alternative_tiles_drawing_root->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
alternative_tiles_drawing_root->set_texture_filter(TEXTURE_FILTER_NEAREST);
alternative_tiles_root_control->add_child(alternative_tiles_drawing_root);
alternatives_draw = memnew(Control);
alternatives_draw->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
+ alternatives_draw->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
alternatives_draw->connect("draw", callable_mp(this, &TileAtlasView::_draw_alternatives));
alternative_tiles_drawing_root->add_child(alternatives_draw);
}
diff --git a/editor/plugins/tiles/tile_atlas_view.h b/editor/plugins/tiles/tile_atlas_view.h
index 196a642283..1c0b622bb1 100644
--- a/editor/plugins/tiles/tile_atlas_view.h
+++ b/editor/plugins/tiles/tile_atlas_view.h
@@ -136,6 +136,7 @@ public:
} else {
base_tiles_root_control->add_child(p_control);
}
+ p_control->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
p_control->set_mouse_filter(Control::MOUSE_FILTER_PASS);
};
@@ -149,6 +150,7 @@ public:
} else {
alternative_tiles_root_control->add_child(p_control);
}
+ p_control->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
p_control->set_mouse_filter(Control::MOUSE_FILTER_PASS);
};
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index a00e1ed9e8..73e07e6647 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -38,6 +38,7 @@
#include "editor/editor_node.h"
#include "editor/editor_properties.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
void TileDataEditor::_tile_set_changed_plan_update() {
_tile_set_changed_update_needed = true;
@@ -248,7 +249,14 @@ void GenericTilePolygonEditor::_zoom_changed() {
}
void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) {
- UndoRedo *undo_redo = use_undo_redo ? editor_undo_redo : memnew(UndoRedo);
+ Ref<EditorUndoRedoManager> undo_redo;
+ if (use_undo_redo) {
+ undo_redo = editor_undo_redo;
+ } else {
+ // This nice hack allows for discarding undo actions without making code too complex.
+ undo_redo.instantiate();
+ }
+
switch (p_item_pressed) {
case RESET_TO_DEFAULT_TILE: {
undo_redo->create_action(TTR("Reset Polygons"));
@@ -322,9 +330,6 @@ void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) {
default:
break;
}
- if (!use_undo_redo) {
- memdelete(undo_redo);
- }
}
void GenericTilePolygonEditor::_grab_polygon_point(Vector2 p_pos, const Transform2D &p_polygon_xform, int &r_polygon_index, int &r_point_index) {
@@ -409,7 +414,14 @@ void GenericTilePolygonEditor::_snap_to_half_pixel(Point2 &r_point) {
}
void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event) {
- UndoRedo *undo_redo = use_undo_redo ? editor_undo_redo : memnew(UndoRedo);
+ Ref<EditorUndoRedoManager> undo_redo;
+ if (use_undo_redo) {
+ undo_redo = editor_undo_redo;
+ } else {
+ // This nice hack allows for discarding undo actions without making code too complex.
+ undo_redo.instantiate();
+ }
+
real_t grab_threshold = EDITOR_GET("editors/polygon_editor/point_grab_radius");
hovered_polygon_index = -1;
@@ -600,10 +612,6 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
}
base_control->update();
-
- if (!use_undo_redo) {
- memdelete(undo_redo);
- }
}
void GenericTilePolygonEditor::set_use_undo_redo(bool p_use_undo_redo) {
@@ -756,21 +764,21 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() {
button_create->set_toggle_mode(true);
button_create->set_button_group(tools_button_group);
button_create->set_pressed(true);
- button_create->set_tooltip(TTR("Add polygon tool"));
+ button_create->set_tooltip_text(TTR("Add polygon tool"));
toolbar->add_child(button_create);
button_edit = memnew(Button);
button_edit->set_flat(true);
button_edit->set_toggle_mode(true);
button_edit->set_button_group(tools_button_group);
- button_edit->set_tooltip(TTR("Edit points tool"));
+ button_edit->set_tooltip_text(TTR("Edit points tool"));
toolbar->add_child(button_edit);
button_delete = memnew(Button);
button_delete->set_flat(true);
button_delete->set_toggle_mode(true);
button_delete->set_button_group(tools_button_group);
- button_delete->set_tooltip(TTR("Delete points tool"));
+ button_delete->set_tooltip_text(TTR("Delete points tool"));
toolbar->add_child(button_delete);
button_advanced_menu = memnew(MenuButton);
@@ -793,7 +801,7 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() {
button_pixel_snap->set_flat(true);
button_pixel_snap->set_toggle_mode(true);
button_pixel_snap->set_pressed(true);
- button_pixel_snap->set_tooltip(TTR("Snap to half-pixel"));
+ button_pixel_snap->set_tooltip_text(TTR("Snap to half-pixel"));
toolbar->add_child(button_pixel_snap);
Control *root = memnew(Control);
@@ -1153,7 +1161,7 @@ void TileDataDefaultEditor::setup_property_editor(Variant::Type p_type, String p
property_editor->set_label(p_label);
}
property_editor->connect("property_changed", callable_mp(this, &TileDataDefaultEditor::_property_value_changed).unbind(1));
- property_editor->set_tooltip(p_property);
+ property_editor->set_tooltip_text(p_property);
property_editor->update_property();
add_child(property_editor);
}
@@ -1363,7 +1371,7 @@ void TileDataCollisionEditor::_polygons_changed() {
one_way_property_editor->set_label(one_way_property);
one_way_property_editor->connect("property_changed", callable_mp(this, &TileDataCollisionEditor::_property_value_changed).unbind(1));
one_way_property_editor->connect("selected", callable_mp(this, &TileDataCollisionEditor::_property_selected));
- one_way_property_editor->set_tooltip(one_way_property_editor->get_edited_property());
+ one_way_property_editor->set_tooltip_text(one_way_property_editor->get_edited_property());
one_way_property_editor->update_property();
add_child(one_way_property_editor);
property_editors[one_way_property] = one_way_property_editor;
@@ -1375,7 +1383,7 @@ void TileDataCollisionEditor::_polygons_changed() {
one_way_margin_property_editor->set_label(one_way_margin_property);
one_way_margin_property_editor->connect("property_changed", callable_mp(this, &TileDataCollisionEditor::_property_value_changed).unbind(1));
one_way_margin_property_editor->connect("selected", callable_mp(this, &TileDataCollisionEditor::_property_selected));
- one_way_margin_property_editor->set_tooltip(one_way_margin_property_editor->get_edited_property());
+ one_way_margin_property_editor->set_tooltip_text(one_way_margin_property_editor->get_edited_property());
one_way_margin_property_editor->update_property();
add_child(one_way_margin_property_editor);
property_editors[one_way_margin_property] = one_way_margin_property_editor;
@@ -1536,7 +1544,7 @@ TileDataCollisionEditor::TileDataCollisionEditor() {
linear_velocity_editor->set_label("linear_velocity");
linear_velocity_editor->connect("property_changed", callable_mp(this, &TileDataCollisionEditor::_property_value_changed).unbind(1));
linear_velocity_editor->connect("selected", callable_mp(this, &TileDataCollisionEditor::_property_selected));
- linear_velocity_editor->set_tooltip(linear_velocity_editor->get_edited_property());
+ linear_velocity_editor->set_tooltip_text(linear_velocity_editor->get_edited_property());
linear_velocity_editor->update_property();
add_child(linear_velocity_editor);
property_editors["linear_velocity"] = linear_velocity_editor;
@@ -1546,7 +1554,7 @@ TileDataCollisionEditor::TileDataCollisionEditor() {
angular_velocity_editor->set_label("angular_velocity");
angular_velocity_editor->connect("property_changed", callable_mp(this, &TileDataCollisionEditor::_property_value_changed).unbind(1));
angular_velocity_editor->connect("selected", callable_mp(this, &TileDataCollisionEditor::_property_selected));
- angular_velocity_editor->set_tooltip(angular_velocity_editor->get_edited_property());
+ angular_velocity_editor->set_tooltip_text(angular_velocity_editor->get_edited_property());
angular_velocity_editor->update_property();
add_child(angular_velocity_editor);
property_editors["angular_velocity"] = angular_velocity_editor;
@@ -2594,7 +2602,7 @@ TileDataTerrainsEditor::TileDataTerrainsEditor() {
terrain_set_property_editor->set_object_and_property(dummy_object, "terrain_set");
terrain_set_property_editor->set_label("Terrain Set");
terrain_set_property_editor->connect("property_changed", callable_mp(this, &TileDataTerrainsEditor::_property_value_changed).unbind(1));
- terrain_set_property_editor->set_tooltip(terrain_set_property_editor->get_edited_property());
+ terrain_set_property_editor->set_tooltip_text(terrain_set_property_editor->get_edited_property());
add_child(terrain_set_property_editor);
terrain_property_editor = memnew(EditorPropertyEnum);
diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h
index f9b8948d0a..c1560138b2 100644
--- a/editor/plugins/tiles/tile_data_editors.h
+++ b/editor/plugins/tiles/tile_data_editors.h
@@ -39,6 +39,8 @@
#include "scene/gui/control.h"
#include "scene/gui/label.h"
+class EditorUndoRedoManager;
+
class TileDataEditor : public VBoxContainer {
GDCLASS(TileDataEditor, VBoxContainer);
@@ -93,7 +95,7 @@ private:
bool multiple_polygon_mode = false;
bool use_undo_redo = true;
- UndoRedo *editor_undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> editor_undo_redo;
// UI
int hovered_polygon_index = -1;
@@ -214,7 +216,7 @@ private:
protected:
DummyObject *dummy_object = memnew(DummyObject);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
StringName type;
String property;
@@ -279,7 +281,7 @@ private:
virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) override;
protected:
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
virtual void _tile_set_changed() override;
@@ -314,7 +316,7 @@ class TileDataCollisionEditor : public TileDataDefaultEditor {
virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) override;
protected:
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
virtual void _tile_set_changed() override;
@@ -366,7 +368,7 @@ protected:
void _notification(int p_what);
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
public:
virtual Control *get_toolbar() override { return toolbar; };
@@ -399,7 +401,7 @@ private:
virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) override;
protected:
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
virtual void _tile_set_changed() override;
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index 1bf24a7393..556788f50c 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -35,6 +35,7 @@
#include "editor/editor_node.h"
#include "editor/editor_resource_preview.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "scene/2d/camera_2d.h"
@@ -2049,7 +2050,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
paint_tool_button->set_toggle_mode(true);
paint_tool_button->set_button_group(tool_buttons_group);
paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", "Paint", Key::D));
- paint_tool_button->set_tooltip(TTR("Shift: Draw line.") + "\n" + TTR("Shift+Ctrl: Draw rectangle."));
+ paint_tool_button->set_tooltip_text(TTR("Shift: Draw line.") + "\n" + TTR("Shift+Ctrl: Draw rectangle."));
paint_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(paint_tool_button);
@@ -2090,7 +2091,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
picker_button->set_flat(true);
picker_button->set_toggle_mode(true);
picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", "Picker", Key::P));
- picker_button->set_tooltip(TTR("Alternatively hold Ctrl with other tools to pick tile."));
+ picker_button->set_tooltip_text(TTR("Alternatively hold Ctrl with other tools to pick tile."));
picker_button->connect("pressed", callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
tools_settings->add_child(picker_button);
@@ -2099,7 +2100,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
erase_button->set_flat(true);
erase_button->set_toggle_mode(true);
erase_button->set_shortcut(ED_SHORTCUT("tiles_editor/eraser", "Eraser", Key::E));
- erase_button->set_tooltip(TTR("Alternatively use RMB to erase tiles."));
+ erase_button->set_tooltip_text(TTR("Alternatively use RMB to erase tiles."));
erase_button->connect("pressed", callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
tools_settings->add_child(erase_button);
@@ -2118,13 +2119,13 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
random_tile_toggle = memnew(Button);
random_tile_toggle->set_flat(true);
random_tile_toggle->set_toggle_mode(true);
- random_tile_toggle->set_tooltip(TTR("Place Random Tile"));
+ random_tile_toggle->set_tooltip_text(TTR("Place Random Tile"));
random_tile_toggle->connect("toggled", callable_mp(this, &TileMapEditorTilesPlugin::_on_random_tile_checkbox_toggled));
tools_settings->add_child(random_tile_toggle);
// Random tile scattering.
scatter_label = memnew(Label);
- scatter_label->set_tooltip(TTR("Defines the probability of painting nothing instead of a randomly selected tile."));
+ scatter_label->set_tooltip_text(TTR("Defines the probability of painting nothing instead of a randomly selected tile."));
scatter_label->set_text(TTR("Scattering:"));
tools_settings->add_child(scatter_label);
@@ -2132,7 +2133,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
scatter_spinbox->set_min(0.0);
scatter_spinbox->set_max(1000);
scatter_spinbox->set_step(0.001);
- scatter_spinbox->set_tooltip(TTR("Defines the probability of painting nothing instead of a randomly selected tile."));
+ scatter_spinbox->set_tooltip_text(TTR("Defines the probability of painting nothing instead of a randomly selected tile."));
scatter_spinbox->get_line_edit()->add_theme_constant_override("minimum_character_width", 4);
scatter_spinbox->connect("value_changed", callable_mp(this, &TileMapEditorTilesPlugin::_on_scattering_spinbox_changed));
tools_settings->add_child(scatter_spinbox);
@@ -2177,7 +2178,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
source_sort_button = memnew(MenuButton);
source_sort_button->set_flat(true);
- source_sort_button->set_tooltip(TTR("Sort sources"));
+ source_sort_button->set_tooltip_text(TTR("Sort sources"));
PopupMenu *p = source_sort_button->get_popup();
p->connect("id_pressed", callable_mp(this, &TileMapEditorTilesPlugin::_set_source_sort));
@@ -3697,8 +3698,8 @@ void TileMapEditor::_update_layers_selection() {
}
void TileMapEditor::_move_tile_map_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) {
- UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo);
- ERR_FAIL_COND(!undo_redo);
+ Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_COND(undo_redo.is_null());
TileMap *tile_map = Object::cast_to<TileMap>(p_edited);
if (!tile_map) {
@@ -4002,7 +4003,7 @@ TileMapEditor::TileMapEditor() {
layers_selection_button = memnew(OptionButton);
layers_selection_button->set_custom_minimum_size(Size2(200, 0));
layers_selection_button->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
- layers_selection_button->set_tooltip(TTR("TileMap Layers"));
+ layers_selection_button->set_tooltip_text(TTR("TileMap Layers"));
layers_selection_button->connect("item_selected", callable_mp(this, &TileMapEditor::_layers_selection_item_selected));
tile_map_toolbar->add_child(layers_selection_button);
@@ -4011,7 +4012,7 @@ TileMapEditor::TileMapEditor() {
toggle_highlight_selected_layer_button->set_toggle_mode(true);
toggle_highlight_selected_layer_button->set_pressed(true);
toggle_highlight_selected_layer_button->connect("pressed", callable_mp(this, &TileMapEditor::_update_layers_selection));
- toggle_highlight_selected_layer_button->set_tooltip(TTR("Highlight Selected TileMap Layer"));
+ toggle_highlight_selected_layer_button->set_tooltip_text(TTR("Highlight Selected TileMap Layer"));
tile_map_toolbar->add_child(toggle_highlight_selected_layer_button);
tile_map_toolbar->add_child(memnew(VSeparator));
@@ -4020,7 +4021,7 @@ TileMapEditor::TileMapEditor() {
toggle_grid_button = memnew(Button);
toggle_grid_button->set_flat(true);
toggle_grid_button->set_toggle_mode(true);
- toggle_grid_button->set_tooltip(TTR("Toggle grid visibility."));
+ toggle_grid_button->set_tooltip_text(TTR("Toggle grid visibility."));
toggle_grid_button->connect("toggled", callable_mp(this, &TileMapEditor::_on_grid_toggled));
tile_map_toolbar->add_child(toggle_grid_button);
diff --git a/editor/plugins/tiles/tile_map_editor.h b/editor/plugins/tiles/tile_map_editor.h
index 605fbe4823..9a47d8bbc4 100644
--- a/editor/plugins/tiles/tile_map_editor.h
+++ b/editor/plugins/tiles/tile_map_editor.h
@@ -47,7 +47,7 @@
#include "scene/gui/tab_bar.h"
#include "scene/gui/tree.h"
-class UndoRedo;
+class EditorUndoRedoManager;
class TileMapEditorPlugin : public Object {
public:
@@ -70,7 +70,7 @@ class TileMapEditorTilesPlugin : public TileMapEditorPlugin {
GDCLASS(TileMapEditorTilesPlugin, TileMapEditorPlugin);
private:
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
ObjectID tile_map_id;
int tile_map_layer = -1;
virtual void edit(ObjectID p_tile_map_id, int p_tile_map_layer) override;
@@ -223,7 +223,7 @@ class TileMapEditorTerrainsPlugin : public TileMapEditorPlugin {
GDCLASS(TileMapEditorTerrainsPlugin, TileMapEditorPlugin);
private:
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
ObjectID tile_map_id;
int tile_map_layer = -1;
virtual void edit(ObjectID p_tile_map_id, int p_tile_map_layer) override;
@@ -317,7 +317,7 @@ class TileMapEditor : public VBoxContainer {
GDCLASS(TileMapEditor, VBoxContainer);
private:
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
bool tileset_changed_needs_update = false;
ObjectID tile_map_id;
int tile_map_layer = -1;
diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
index 12e1615484..9e4c29fa79 100644
--- a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
+++ b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
@@ -32,6 +32,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
void TileProxiesManagerDialog::_right_clicked(int p_item, Vector2 p_local_mouse_pos, Object *p_item_list, MouseButton p_mouse_button_index) {
if (p_mouse_button_index != MouseButton::RIGHT) {
diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.h b/editor/plugins/tiles/tile_proxies_manager_dialog.h
index 44de708898..511e442a10 100644
--- a/editor/plugins/tiles/tile_proxies_manager_dialog.h
+++ b/editor/plugins/tiles/tile_proxies_manager_dialog.h
@@ -43,7 +43,7 @@ private:
int commited_actions_count = 0;
Ref<TileSet> tile_set;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
TileMapCell from;
TileMapCell to;
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index 6950f57a00..46093469e3 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -527,7 +527,7 @@ void TileSetAtlasSourceEditor::_update_tile_id_label() {
if (selection.size() == 1) {
TileSelection selected = selection.front()->get();
tool_tile_id_label->set_text(vformat("%d, %s, %d", tile_set_atlas_source_id, selected.tile, selected.alternative));
- tool_tile_id_label->set_tooltip(vformat(TTR("Selected tile:\nSource: %d\nAtlas coordinates: %s\nAlternative: %d"), tile_set_atlas_source_id, selected.tile, selected.alternative));
+ tool_tile_id_label->set_tooltip_text(vformat(TTR("Selected tile:\nSource: %d\nAtlas coordinates: %s\nAlternative: %d"), tile_set_atlas_source_id, selected.tile, selected.alternative));
tool_tile_id_label->show();
} else {
tool_tile_id_label->hide();
@@ -1888,7 +1888,7 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<In
alternative_tiles_control_unscaled->update();
if (drag_type == DRAG_TYPE_MAY_POPUP_MENU) {
- if (Vector2(drag_start_mouse_pos).distance_to(tile_atlas_control->get_local_mouse_position()) > 5.0 * EDSCALE) {
+ if (Vector2(drag_start_mouse_pos).distance_to(alternative_tiles_control->get_local_mouse_position()) > 5.0 * EDSCALE) {
drag_type = DRAG_TYPE_NONE;
}
}
@@ -1896,8 +1896,6 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<In
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- drag_type = DRAG_TYPE_NONE;
-
Vector2 mouse_local_pos = alternative_tiles_control->get_local_mouse_position();
if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
@@ -1919,25 +1917,29 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<In
if (mb->is_pressed()) {
drag_type = DRAG_TYPE_MAY_POPUP_MENU;
drag_start_mouse_pos = alternative_tiles_control->get_local_mouse_position();
- } else if (drag_type == DRAG_TYPE_MAY_POPUP_MENU) {
- // Right click released and wasn't dragged too far
- Vector3 tile = tile_atlas_view->get_alternative_tile_at_pos(mouse_local_pos);
+ } else {
+ if (drag_type == DRAG_TYPE_MAY_POPUP_MENU) {
+ // Right click released and wasn't dragged too far
+ Vector3 tile = tile_atlas_view->get_alternative_tile_at_pos(mouse_local_pos);
- selection.clear();
- TileSelection selected = { Vector2i(tile.x, tile.y), int(tile.z) };
- if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) {
- selection.insert(selected);
- }
+ selection.clear();
+ TileSelection selected = { Vector2i(tile.x, tile.y), int(tile.z) };
+ if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) {
+ selection.insert(selected);
+ }
- _update_tile_inspector();
- _update_tile_id_label();
+ _update_tile_inspector();
+ _update_tile_id_label();
- if (selection.size() == 1) {
- selected = selection.front()->get();
- menu_option_coords = selected.tile;
- menu_option_alternative = selected.alternative;
- alternative_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i()));
+ if (selection.size() == 1) {
+ selected = selection.front()->get();
+ menu_option_coords = selected.tile;
+ menu_option_alternative = selected.alternative;
+ alternative_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i()));
+ }
}
+
+ drag_type = DRAG_TYPE_NONE;
}
}
tile_atlas_control->update();
@@ -2058,14 +2060,16 @@ void TileSetAtlasSourceEditor::_atlas_source_proxy_object_changed(String p_what)
}
void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) {
- UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo);
- ERR_FAIL_COND(!undo_redo);
+ Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_COND(!undo_redo.is_valid());
#define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, obj->get(property));
- undo_redo->start_force_keep_in_merge_ends();
AtlasTileProxyObject *tile_data_proxy = Object::cast_to<AtlasTileProxyObject>(p_edited);
if (tile_data_proxy) {
+ UndoRedo *internal_undo_redo = undo_redo->get_history_for_object(tile_data_proxy).undo_redo;
+ internal_undo_redo->start_force_keep_in_merge_ends();
+
Vector<String> components = String(p_property).split("/", true, 2);
if (components.size() == 2 && components[1] == "polygons_count") {
int layer_index = components[0].trim_prefix("physics_layer_").to_int();
@@ -2088,6 +2092,7 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo
}
}
}
+ internal_undo_redo->end_force_keep_in_merge_ends();
}
TileSetAtlasSourceProxyObject *atlas_source_proxy = Object::cast_to<TileSetAtlasSourceProxyObject>(p_edited);
@@ -2095,6 +2100,9 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo
TileSetAtlasSource *atlas_source = atlas_source_proxy->get_edited();
ERR_FAIL_COND(!atlas_source);
+ UndoRedo *internal_undo_redo = undo_redo->get_history_for_object(atlas_source).undo_redo;
+ internal_undo_redo->start_force_keep_in_merge_ends();
+
PackedVector2Array arr;
if (p_property == "texture") {
arr = atlas_source->get_tiles_to_be_removed_on_change(p_new_value, atlas_source->get_margins(), atlas_source->get_separation(), atlas_source->get_texture_region_size());
@@ -2121,8 +2129,8 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo
}
}
}
+ internal_undo_redo->end_force_keep_in_merge_ends();
}
- undo_redo->end_force_keep_in_merge_ends();
#undef ADD_UNDO
}
@@ -2438,7 +2446,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tool_setup_atlas_source_button->set_toggle_mode(true);
tool_setup_atlas_source_button->set_pressed(true);
tool_setup_atlas_source_button->set_button_group(tools_button_group);
- tool_setup_atlas_source_button->set_tooltip(TTR("Atlas setup. Add/Remove tiles tool (use the shift key to create big tiles, control for rectangle editing)."));
+ tool_setup_atlas_source_button->set_tooltip_text(TTR("Atlas setup. Add/Remove tiles tool (use the shift key to create big tiles, control for rectangle editing)."));
toolbox->add_child(tool_setup_atlas_source_button);
tool_select_button = memnew(Button);
@@ -2446,14 +2454,14 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tool_select_button->set_toggle_mode(true);
tool_select_button->set_pressed(false);
tool_select_button->set_button_group(tools_button_group);
- tool_select_button->set_tooltip(TTR("Select tiles."));
+ tool_select_button->set_tooltip_text(TTR("Select tiles."));
toolbox->add_child(tool_select_button);
tool_paint_button = memnew(Button);
tool_paint_button->set_flat(true);
tool_paint_button->set_toggle_mode(true);
tool_paint_button->set_button_group(tools_button_group);
- tool_paint_button->set_tooltip(TTR("Paint properties."));
+ tool_paint_button->set_tooltip_text(TTR("Paint properties."));
toolbox->add_child(tool_paint_button);
// Tool settings.
@@ -2518,7 +2526,6 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tile_atlas_view->add_control_over_atlas_tiles(tile_atlas_control);
tile_atlas_control_unscaled = memnew(Control);
- tile_atlas_control_unscaled->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
tile_atlas_control_unscaled->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_atlas_control_unscaled_draw));
tile_atlas_view->add_control_over_atlas_tiles(tile_atlas_control_unscaled, false);
tile_atlas_control_unscaled->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
@@ -2535,7 +2542,6 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tile_atlas_view->add_control_over_alternative_tiles(alternative_tiles_control);
alternative_tiles_control_unscaled = memnew(Control);
- alternative_tiles_control_unscaled->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
alternative_tiles_control_unscaled->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw));
tile_atlas_view->add_control_over_alternative_tiles(alternative_tiles_control_unscaled, false);
alternative_tiles_control_unscaled->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h
index 738fe1044d..badb702e29 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.h
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h
@@ -114,7 +114,7 @@ private:
TileSetAtlasSource *tile_set_atlas_source = nullptr;
int tile_set_atlas_source_id = TileSet::INVALID_SOURCE;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
bool tile_set_changed_needs_update = false;
diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp
index 81804710b4..dca17475e0 100644
--- a/editor/plugins/tiles/tile_set_editor.cpp
+++ b/editor/plugins/tiles/tile_set_editor.cpp
@@ -36,6 +36,7 @@
#include "editor/editor_file_system.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/box_container.h"
#include "scene/gui/control.h"
@@ -405,8 +406,8 @@ void TileSetEditor::_tab_changed(int p_tab_changed) {
}
void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) {
- UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo);
- ERR_FAIL_COND(!undo_redo);
+ Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_COND(undo_redo.is_null());
TileSet *tile_set = Object::cast_to<TileSet>(p_edited);
if (!tile_set) {
@@ -586,8 +587,8 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_
}
void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) {
- UndoRedo *undo_redo = Object::cast_to<UndoRedo>(p_undo_redo);
- ERR_FAIL_COND(!undo_redo);
+ Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_COND(undo_redo.is_null());
#define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, obj->get(property));
TileSet *tile_set = Object::cast_to<TileSet>(p_edited);
@@ -694,7 +695,7 @@ TileSetEditor::TileSetEditor() {
source_sort_button = memnew(MenuButton);
source_sort_button->set_flat(true);
- source_sort_button->set_tooltip(TTR("Sort sources"));
+ source_sort_button->set_tooltip_text(TTR("Sort sources"));
PopupMenu *p = source_sort_button->get_popup();
p->connect("id_pressed", callable_mp(this, &TileSetEditor::_set_source_sort));
diff --git a/editor/plugins/tiles/tile_set_editor.h b/editor/plugins/tiles/tile_set_editor.h
index c45240043e..3b9b80dac4 100644
--- a/editor/plugins/tiles/tile_set_editor.h
+++ b/editor/plugins/tiles/tile_set_editor.h
@@ -39,6 +39,8 @@
#include "tile_set_atlas_source_editor.h"
#include "tile_set_scenes_collection_source_editor.h"
+class EditorUndoRedoManager;
+
class TileSetEditor : public VBoxContainer {
GDCLASS(TileSetEditor, VBoxContainer);
@@ -58,7 +60,7 @@ private:
TileSetAtlasSourceEditor *tile_set_atlas_source_editor = nullptr;
TileSetScenesCollectionSourceEditor *tile_set_scenes_collection_source_editor = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
void _drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
bool _can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h
index 77a583e522..0284b45c0f 100644
--- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h
+++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.h
@@ -97,7 +97,7 @@ private:
TileSetScenesCollectionSource *tile_set_scenes_collection_source = nullptr;
int tile_set_source_id = -1;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
bool tile_set_scenes_collection_source_changed_needs_update = false;
diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index cf55465417..2b55ba64c3 100644
--- a/editor/plugins/version_control_editor_plugin.cpp
+++ b/editor/plugins/version_control_editor_plugin.cpp
@@ -242,7 +242,7 @@ void VersionControlEditorPlugin::_view_file_diff() {
}
void VersionControlEditorPlugin::_display_file_diff(String p_file_path) {
- Array diff_content = EditorVCSInterface::get_singleton()->get_file_diff(p_file_path);
+ TypedArray<Dictionary> diff_content = EditorVCSInterface::get_singleton()->get_file_diff(p_file_path);
diff_file_name->set_text(p_file_path);
@@ -464,7 +464,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
stage_tools->add_child(staging_area_label);
refresh_button = memnew(Button);
- refresh_button->set_tooltip(TTR("Detect new changes"));
+ refresh_button->set_tooltip_text(TTR("Detect new changes"));
refresh_button->set_text(TTR("Refresh"));
refresh_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
refresh_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area));
@@ -551,7 +551,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
diff_heading = memnew(Label);
diff_heading->set_text(TTR("Status"));
- diff_heading->set_tooltip(TTR("View file diffs before committing them to the latest version"));
+ diff_heading->set_tooltip_text(TTR("View file diffs before committing them to the latest version"));
diff_hbc->add_child(diff_heading);
diff_file_name = memnew(Label);
@@ -561,7 +561,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
diff_hbc->add_child(diff_file_name);
diff_refresh_button = memnew(Button);
- diff_refresh_button->set_tooltip(TTR("Detect changes in file diff"));
+ diff_refresh_button->set_tooltip_text(TTR("Detect changes in file diff"));
diff_refresh_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
diff_refresh_button->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_refresh_file_diff));
diff_hbc->add_child(diff_refresh_button);
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 626071aa72..83341b3016 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -40,10 +40,18 @@
#include "editor/editor_node.h"
#include "editor/editor_properties.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
+#include "editor/plugins/curve_editor_plugin.h"
#include "editor/plugins/shader_editor_plugin.h"
#include "scene/animation/animation_player.h"
+#include "scene/gui/button.h"
+#include "scene/gui/code_edit.h"
+#include "scene/gui/graph_edit.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
+#include "scene/gui/popup.h"
+#include "scene/gui/rich_text_label.h"
+#include "scene/gui/tree.h"
#include "scene/gui/view_panner.h"
#include "scene/main/window.h"
#include "scene/resources/visual_shader_nodes.h"
@@ -91,17 +99,6 @@ void VisualShaderNodePlugin::_bind_methods() {
///////////////////
-static Ref<StyleBoxEmpty> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) {
- Ref<StyleBoxEmpty> style(memnew(StyleBoxEmpty));
- style->set_default_margin(SIDE_LEFT, p_margin_left * EDSCALE);
- style->set_default_margin(SIDE_RIGHT, p_margin_right * EDSCALE);
- style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * EDSCALE);
- style->set_default_margin(SIDE_TOP, p_margin_top * EDSCALE);
- return style;
-}
-
-///////////////////
-
VisualShaderGraphPlugin::VisualShaderGraphPlugin() {
}
@@ -364,8 +361,6 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
Control *offset;
- static Ref<StyleBoxEmpty> label_style = make_empty_stylebox(2, 1, 2, 1);
-
static const Color type_color[] = {
Color(0.38, 0.85, 0.96), // scalar (float)
Color(0.49, 0.78, 0.94), // scalar (int)
@@ -759,20 +754,20 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
Button *remove_btn = memnew(Button);
remove_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
- remove_btn->set_tooltip(TTR("Remove") + " " + name_left);
+ remove_btn->set_tooltip_text(TTR("Remove") + " " + name_left);
remove_btn->connect("pressed", callable_mp(editor, &VisualShaderEditor::_remove_input_port).bind(p_id, i), CONNECT_DEFERRED);
hb->add_child(remove_btn);
} else {
Label *label = memnew(Label);
label->set_text(name_left);
- label->add_theme_style_override("normal", label_style); //more compact
+ label->add_theme_style_override("normal", editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor"))); //more compact
hb->add_child(label);
if (vsnode->is_input_port_default(i, mode) && !port_left_used) {
Label *hint_label = memnew(Label);
hint_label->set_text(TTR("[default]"));
hint_label->add_theme_color_override("font_color", editor->get_theme_color(SNAME("font_readonly_color"), SNAME("TextEdit")));
- hint_label->add_theme_style_override("normal", label_style);
+ hint_label->add_theme_style_override("normal", editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor")));
hb->add_child(hint_label);
}
}
@@ -786,7 +781,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
if (is_group) {
Button *remove_btn = memnew(Button);
remove_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
- remove_btn->set_tooltip(TTR("Remove") + " " + name_left);
+ remove_btn->set_tooltip_text(TTR("Remove") + " " + name_left);
remove_btn->connect("pressed", callable_mp(editor, &VisualShaderEditor::_remove_output_port).bind(p_id, i), CONNECT_DEFERRED);
hb->add_child(remove_btn);
@@ -813,7 +808,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
} else {
Label *label = memnew(Label);
label->set_text(name_right);
- label->add_theme_style_override("normal", label_style); //more compact
+ label->add_theme_style_override("normal", editor->get_theme_stylebox(SNAME("label_style"), SNAME("VShaderEditor"))); //more compact
hb->add_child(label);
}
}
@@ -1080,6 +1075,23 @@ VisualShaderGraphPlugin::~VisualShaderGraphPlugin() {
/////////////////
+void VisualShaderEditedProperty::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_edited_property", "value"), &VisualShaderEditedProperty::set_edited_property);
+ ClassDB::bind_method(D_METHOD("get_edited_property"), &VisualShaderEditedProperty::get_edited_property);
+
+ ADD_PROPERTY(PropertyInfo(Variant::NIL, "edited_property", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_edited_property", "get_edited_property");
+}
+
+void VisualShaderEditedProperty::set_edited_property(Variant p_variant) {
+ edited_property = p_variant;
+}
+
+Variant VisualShaderEditedProperty::get_edited_property() const {
+ return edited_property;
+}
+
+/////////////////
+
Vector2 VisualShaderEditor::selection_center;
List<VisualShaderEditor::CopyItem> VisualShaderEditor::copy_items_buffer;
List<VisualShader::Connection> VisualShaderEditor::copy_connections_buffer;
@@ -2287,10 +2299,8 @@ void VisualShaderEditor::_port_name_focus_out(Object *line_edit, int p_node_id,
}
}
-void VisualShaderEditor::_port_edited() {
+void VisualShaderEditor::_port_edited(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing) {
VisualShader::Type type = get_current_shader_type();
-
- Variant value = property_editor->get_variant();
Ref<VisualShaderNode> vsn = visual_shader->get_node(type, editing_node);
ERR_FAIL_COND(!vsn.is_valid());
@@ -2298,30 +2308,51 @@ void VisualShaderEditor::_port_edited() {
Ref<VisualShaderNodeCustom> custom = Object::cast_to<VisualShaderNodeCustom>(vsn.ptr());
if (custom.is_valid()) {
- undo_redo->add_do_method(custom.ptr(), "_set_input_port_default_value", editing_port, value);
+ undo_redo->add_do_method(custom.ptr(), "_set_input_port_default_value", editing_port, p_value);
undo_redo->add_undo_method(custom.ptr(), "_set_input_port_default_value", editing_port, vsn->get_input_port_default_value(editing_port));
} else {
- undo_redo->add_do_method(vsn.ptr(), "set_input_port_default_value", editing_port, value);
+ undo_redo->add_do_method(vsn.ptr(), "set_input_port_default_value", editing_port, p_value);
undo_redo->add_undo_method(vsn.ptr(), "set_input_port_default_value", editing_port, vsn->get_input_port_default_value(editing_port));
}
- undo_redo->add_do_method(graph_plugin.ptr(), "set_input_port_default_value", type, editing_node, editing_port, value);
+ undo_redo->add_do_method(graph_plugin.ptr(), "set_input_port_default_value", type, editing_node, editing_port, p_value);
undo_redo->add_undo_method(graph_plugin.ptr(), "set_input_port_default_value", type, editing_node, editing_port, vsn->get_input_port_default_value(editing_port));
undo_redo->commit_action();
-
- property_editor->hide();
}
void VisualShaderEditor::_edit_port_default_input(Object *p_button, int p_node, int p_port) {
VisualShader::Type type = get_current_shader_type();
+ Ref<VisualShaderNode> vs_node = visual_shader->get_node(type, p_node);
+ Variant value = vs_node->get_input_port_default_value(p_port);
- Ref<VisualShaderNode> vsn = visual_shader->get_node(type, p_node);
+ edited_property_holder->set_edited_property(value);
+
+ if (property_editor) {
+ property_editor->disconnect("property_changed", callable_mp(this, &VisualShaderEditor::_port_edited));
+ property_editor_popup->remove_child(property_editor);
+ }
+
+ // TODO: Define these properties with actual PropertyInfo and feed it to the property editor widget.
+ property_editor = EditorInspector::instantiate_property_editor(edited_property_holder.ptr(), value.get_type(), "edited_property", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE);
+ if (property_editor) {
+ property_editor->set_object_and_property(edited_property_holder.ptr(), "edited_property");
+ property_editor->update_property();
+ property_editor->set_name_split_ratio(0);
+ property_editor_popup->add_child(property_editor);
+
+ property_editor->connect("property_changed", callable_mp(this, &VisualShaderEditor::_port_edited));
+
+ Button *button = Object::cast_to<Button>(p_button);
+ if (button) {
+ property_editor_popup->set_position(button->get_screen_position() + Vector2(0, button->get_size().height) * graph->get_zoom());
+ }
+ property_editor_popup->reset_size();
+ if (button) {
+ property_editor_popup->popup();
+ } else {
+ property_editor_popup->popup_centered_ratio();
+ }
+ }
- Button *button = Object::cast_to<Button>(p_button);
- ERR_FAIL_COND(!button);
- Variant value = vsn->get_input_port_default_value(p_port);
- property_editor->set_position(button->get_screen_position() + Vector2(0, button->get_size().height));
- property_editor->edit(nullptr, "", value.get_type(), value, 0, "");
- property_editor->popup();
editing_node = p_node;
editing_port = p_port;
}
@@ -4033,7 +4064,7 @@ void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input,
bool type_changed = next_input_type != prev_input_type;
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
undo_redo->create_action(TTR("Visual Shader Input Type Changed"));
undo_redo->add_do_method(p_input.ptr(), "set_input_name", p_name);
@@ -4102,7 +4133,7 @@ void VisualShaderEditor::_uniform_select_item(Ref<VisualShaderNodeUniformRef> p_
bool type_changed = p_uniform_ref->get_uniform_type_by_name(p_name) != p_uniform_ref->get_uniform_type_by_name(prev_name);
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
undo_redo->create_action(TTR("UniformRef Name Changed"));
undo_redo->add_do_method(p_uniform_ref.ptr(), "set_uniform_name", p_name);
@@ -4146,7 +4177,7 @@ void VisualShaderEditor::_varying_select_item(Ref<VisualShaderNodeVarying> p_var
bool is_getter = Ref<VisualShaderNodeVaryingGetter>(p_varying.ptr()).is_valid();
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
undo_redo->create_action(TTR("Varying Name Changed"));
undo_redo->add_do_method(p_varying.ptr(), "set_varying_name", p_name);
@@ -4281,6 +4312,9 @@ void VisualShaderEditor::_update_varying_tree() {
case VisualShader::VARYING_TYPE_FLOAT:
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("float"), SNAME("EditorIcons")));
break;
+ case VisualShader::VARYING_TYPE_INT:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("int"), SNAME("EditorIcons")));
+ break;
case VisualShader::VARYING_TYPE_VECTOR_2D:
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector2"), SNAME("EditorIcons")));
break;
@@ -4290,8 +4324,8 @@ void VisualShaderEditor::_update_varying_tree() {
case VisualShader::VARYING_TYPE_VECTOR_4D:
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector4"), SNAME("EditorIcons")));
break;
- case VisualShader::VARYING_TYPE_COLOR:
- item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Color"), SNAME("EditorIcons")));
+ case VisualShader::VARYING_TYPE_BOOLEAN:
+ item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("bool"), SNAME("EditorIcons")));
break;
case VisualShader::VARYING_TYPE_TRANSFORM:
item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Transform3D"), SNAME("EditorIcons")));
@@ -4792,7 +4826,7 @@ VisualShaderEditor::VisualShaderEditor() {
preview_shader = memnew(Button);
preview_shader->set_flat(true);
preview_shader->set_toggle_mode(true);
- preview_shader->set_tooltip(TTR("Show generated shader code."));
+ preview_shader->set_tooltip_text(TTR("Show generated shader code."));
graph->get_zoom_hbox()->add_child(preview_shader);
preview_shader->connect("pressed", callable_mp(this, &VisualShaderEditor::_show_preview_text));
@@ -4862,7 +4896,7 @@ VisualShaderEditor::VisualShaderEditor() {
tools = memnew(MenuButton);
filter_hb->add_child(tools);
- tools->set_tooltip(TTR("Options"));
+ tools->set_tooltip_text(TTR("Options"));
tools->get_popup()->connect("id_pressed", callable_mp(this, &VisualShaderEditor::_tools_menu_option));
tools->get_popup()->add_item(TTR("Expand All"), EXPAND_ALL);
tools->get_popup()->add_item(TTR("Collapse All"), COLLAPSE_ALL);
@@ -4894,7 +4928,7 @@ VisualShaderEditor::VisualShaderEditor() {
highend_label->set_visible(false);
highend_label->set_text("Vulkan");
highend_label->set_mouse_filter(Control::MOUSE_FILTER_STOP);
- highend_label->set_tooltip(TTR("High-end node"));
+ highend_label->set_tooltip_text(TTR("High-end node"));
node_desc = memnew(RichTextLabel);
members_vb->add_child(node_desc);
@@ -4932,10 +4966,11 @@ VisualShaderEditor::VisualShaderEditor() {
varying_type = memnew(OptionButton);
hb->add_child(varying_type);
varying_type->add_item("Float");
+ varying_type->add_item("Int");
varying_type->add_item("Vector2");
varying_type->add_item("Vector3");
varying_type->add_item("Vector4");
- varying_type->add_item("Color");
+ varying_type->add_item("Boolean");
varying_type->add_item("Transform");
varying_name = memnew(LineEdit);
@@ -5147,6 +5182,10 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("ViewIndex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_index", "VIEW_INDEX"), { "view_index" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("ViewMonoLeft", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_mono_left", "VIEW_MONO_LEFT"), { "view_mono_left" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("ViewRight", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_right", "VIEW_RIGHT"), { "view_right" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("NodePositionWorld", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_world", "NODE_POSITION_WORLD"), { "node_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("CameraPositionWorld", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_position_world", "CAMERA_POSITION_WORLD"), { "camera_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("CameraDirectionWorld", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_direction_world", "CAMERA_DIRECTION_WORLD"), { "camera_direction_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("NodePositionView", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_view", "NODE_POSITION_VIEW"), { "node_position_view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Binormal", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal", "BINORMAL"), { "binormal" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, 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"), { "color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
@@ -5162,6 +5201,10 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("ViewIndex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_index", "VIEW_INDEX"), { "view_index" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("ViewMonoLeft", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_mono_left", "VIEW_MONO_LEFT"), { "view_mono_left" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("ViewRight", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "view_right", "VIEW_RIGHT"), { "view_right" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("NodePositionWorld", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_world", "NODE_POSITION_WORLD"), { "node_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("CameraPositionWorld", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_position_world", "CAMERA_POSITION_WORLD"), { "camera_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("CameraDirectionWorld", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_direction_world", "CAMERA_DIRECTION_WORLD"), { "camera_direction_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("NodePositionView", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_view", "NODE_POSITION_VIEW"), { "node_position_view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Albedo", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "albedo", "ALBEDO"), { "albedo" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Attenuation", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "attenuation", "ATTENUATION"), { "attenuation" }, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL));
@@ -5368,6 +5411,7 @@ VisualShaderEditor::VisualShaderEditor() {
// TEXTURES
add_options.push_back(AddOption("UVFunc", "Textures", "Common", "VisualShaderNodeUVFunc", TTR("Function to be applied on texture coordinates."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
+ add_options.push_back(AddOption("UVPolarCoord", "Textures", "Common", "VisualShaderNodeUVPolarCoord", TTR("Polar coordinates conversion applied on texture coordinates."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
cubemap_node_option_idx = add_options.size();
add_options.push_back(AddOption("CubeMap", "Textures", "Functions", "VisualShaderNodeCubemap", TTR("Perform the cubic texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
@@ -5375,6 +5419,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("CurveTexture", "Textures", "Functions", "VisualShaderNodeCurveTexture", TTR("Perform the curve texture lookup."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
curve_xyz_node_option_idx = add_options.size();
add_options.push_back(AddOption("CurveXYZTexture", "Textures", "Functions", "VisualShaderNodeCurveXYZTexture", TTR("Perform the three components curve texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("LinearSceneDepth", "Textures", "Functions", "VisualShaderNodeLinearSceneDepth", TTR("Returns the depth value of the DEPTH_TEXTURE node in a linear space."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
texture2d_node_option_idx = add_options.size();
add_options.push_back(AddOption("Texture2D", "Textures", "Functions", "VisualShaderNodeTexture", TTR("Perform the 2D texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
texture2d_array_node_option_idx = add_options.size();
@@ -5414,6 +5459,13 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("TransformConstant", "Transform", "Variables", "VisualShaderNodeTransformConstant", TTR("Transform constant."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));
add_options.push_back(AddOption("TransformUniform", "Transform", "Variables", "VisualShaderNodeTransformUniform", TTR("Transform uniform."), {}, VisualShaderNode::PORT_TYPE_TRANSFORM));
+ // UTILITY
+
+ add_options.push_back(AddOption("DistanceFade", "Utility", "", "VisualShaderNodeDistanceFade", TTR("The distance fade effect fades out each pixel based on its distance to another object."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("ProximityFade", "Utility", "", "VisualShaderNodeProximityFade", TTR("The proximity fade effect fades out each pixel based on its distance to another object."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("RandomRange", "Utility", "", "VisualShaderNodeRandomRange", TTR("Returns a random value between the minimum and maximum input values."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
+ add_options.push_back(AddOption("Remap", "Utility", "", "VisualShaderNodeRemap", TTR("Remaps a given input from the input range to the output range."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
+
// VECTOR
add_options.push_back(AddOption("VectorFunc", "Vector", "Common", "VisualShaderNodeVectorFunc", TTR("Vector function."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
@@ -5539,8 +5591,12 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Reciprocal", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("1.0 / vector"), { VisualShaderNodeVectorFunc::FUNC_RECIPROCAL, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
add_options.push_back(AddOption("Reciprocal", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("1.0 / vector"), { VisualShaderNodeVectorFunc::FUNC_RECIPROCAL, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("Reciprocal", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("1.0 / vector"), { VisualShaderNodeVectorFunc::FUNC_RECIPROCAL, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Reflect", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the vector that points in the direction of reflection ( a : incident vector, b : normal vector )."), { VisualShaderNodeVectorOp::OP_REFLECT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
add_options.push_back(AddOption("Reflect", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the vector that points in the direction of reflection ( a : incident vector, b : normal vector )."), { VisualShaderNodeVectorOp::OP_REFLECT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Reflect", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Returns the vector that points in the direction of reflection ( a : incident vector, b : normal vector )."), { VisualShaderNodeVectorOp::OP_REFLECT, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
+ add_options.push_back(AddOption("Refract", "Vector", "Functions", "VisualShaderNodeVectorRefract", TTR("Returns the vector that points in the direction of refraction."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D));
add_options.push_back(AddOption("Refract", "Vector", "Functions", "VisualShaderNodeVectorRefract", TTR("Returns the vector that points in the direction of refraction."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
+ add_options.push_back(AddOption("Refract", "Vector", "Functions", "VisualShaderNodeVectorRefract", TTR("Returns the vector that points in the direction of refraction."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
add_options.push_back(AddOption("Round", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer to the parameter."), { VisualShaderNodeVectorFunc::FUNC_ROUND, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D));
add_options.push_back(AddOption("Round", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer to the parameter."), { VisualShaderNodeVectorFunc::FUNC_ROUND, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D));
add_options.push_back(AddOption("Round", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer to the parameter."), { VisualShaderNodeVectorFunc::FUNC_ROUND, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D));
@@ -5626,7 +5682,7 @@ VisualShaderEditor::VisualShaderEditor() {
_update_options_menu();
- undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ undo_redo = EditorNode::get_undo_redo();
Ref<VisualShaderNodePluginDefault> default_plugin;
default_plugin.instantiate();
@@ -5636,10 +5692,11 @@ VisualShaderEditor::VisualShaderEditor() {
graph_plugin.instantiate();
graph_plugin->set_editor(this);
- property_editor = memnew(CustomPropertyEditor);
- add_child(property_editor);
+ property_editor_popup = memnew(PopupPanel);
+ property_editor_popup->set_min_size(Size2i(180, 0) * EDSCALE);
+ add_child(property_editor_popup);
- property_editor->connect("variant_changed", callable_mp(this, &VisualShaderEditor::_port_edited));
+ edited_property_holder.instantiate();
}
class VisualShaderNodePluginInputEditor : public OptionButton {
@@ -5715,10 +5772,11 @@ public:
Ref<Texture2D> type_icon[] = {
EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("float"), SNAME("EditorIcons")),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("int"), SNAME("EditorIcons")),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector2"), SNAME("EditorIcons")),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector3"), SNAME("EditorIcons")),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Vector4"), SNAME("EditorIcons")),
- EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Color"), SNAME("EditorIcons")),
+ EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("bool"), SNAME("EditorIcons")),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Transform3D"), SNAME("EditorIcons")),
};
@@ -5833,7 +5891,7 @@ public:
return;
}
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
updating = true;
undo_redo->create_action(TTR("Edit Visual Property:") + " " + p_property, UndoRedo::MERGE_ENDS);
@@ -6020,7 +6078,7 @@ Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_par
return editor;
}
-void EditorPropertyShaderMode::_option_selected(int p_which) {
+void EditorPropertyVisualShaderMode::_option_selected(int p_which) {
Ref<VisualShader> visual_shader(Object::cast_to<VisualShader>(get_edited_object()));
if (visual_shader->get_mode() == p_which) {
return;
@@ -6035,7 +6093,7 @@ void EditorPropertyShaderMode::_option_selected(int p_which) {
return;
}
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
undo_redo->create_action(TTR("Visual Shader Mode Changed"));
//do is easy
undo_redo->add_do_method(visual_shader.ptr(), "set_mode", p_which);
@@ -6106,39 +6164,39 @@ void EditorPropertyShaderMode::_option_selected(int p_which) {
undo_redo->commit_action();
}
-void EditorPropertyShaderMode::update_property() {
+void EditorPropertyVisualShaderMode::update_property() {
int which = get_edited_object()->get(get_edited_property());
options->select(which);
}
-void EditorPropertyShaderMode::setup(const Vector<String> &p_options) {
+void EditorPropertyVisualShaderMode::setup(const Vector<String> &p_options) {
for (int i = 0; i < p_options.size(); i++) {
options->add_item(p_options[i], i);
}
}
-void EditorPropertyShaderMode::set_option_button_clip(bool p_enable) {
+void EditorPropertyVisualShaderMode::set_option_button_clip(bool p_enable) {
options->set_clip_text(p_enable);
}
-void EditorPropertyShaderMode::_bind_methods() {
+void EditorPropertyVisualShaderMode::_bind_methods() {
}
-EditorPropertyShaderMode::EditorPropertyShaderMode() {
+EditorPropertyVisualShaderMode::EditorPropertyVisualShaderMode() {
options = memnew(OptionButton);
options->set_clip_text(true);
add_child(options);
add_focusable(options);
- options->connect("item_selected", callable_mp(this, &EditorPropertyShaderMode::_option_selected));
+ options->connect("item_selected", callable_mp(this, &EditorPropertyVisualShaderMode::_option_selected));
}
-bool EditorInspectorShaderModePlugin::can_handle(Object *p_object) {
+bool EditorInspectorVisualShaderModePlugin::can_handle(Object *p_object) {
return true; // Can handle everything.
}
-bool EditorInspectorShaderModePlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
+bool EditorInspectorVisualShaderModePlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
if (p_path == "mode" && p_object->is_class("VisualShader") && p_type == Variant::INT) {
- EditorPropertyShaderMode *mode_editor = memnew(EditorPropertyShaderMode);
+ EditorPropertyVisualShaderMode *mode_editor = memnew(EditorPropertyVisualShaderMode);
Vector<String> options = p_hint_text.split(",");
mode_editor->setup(options);
add_property_editor(p_path, mode_editor);
@@ -6189,7 +6247,7 @@ void VisualShaderNodePortPreview::_shader_changed() {
}
if (src_mat && src_mat->get_shader().is_valid()) {
List<PropertyInfo> params;
- src_mat->get_shader()->get_param_list(&params);
+ src_mat->get_shader()->get_shader_uniform_list(&params);
for (const PropertyInfo &E : params) {
material->set(E.name, src_mat->get(E.name));
}
@@ -6210,7 +6268,7 @@ void VisualShaderNodePortPreview::setup(const Ref<VisualShader> &p_shader, Visua
}
Size2 VisualShaderNodePortPreview::get_minimum_size() const {
- int port_preview_size = EditorSettings::get_singleton()->get("editors/visual_editors/visualshader/port_preview_size");
+ int port_preview_size = EditorSettings::get_singleton()->get("editors/visual_editors/visual_shader/port_preview_size");
return Size2(port_preview_size, port_preview_size) * EDSCALE;
}
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index ecaad1e540..ede6513b83 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -32,18 +32,23 @@
#define VISUAL_SHADER_EDITOR_PLUGIN_H
#include "editor/editor_plugin.h"
-#include "editor/plugins/curve_editor_plugin.h"
#include "editor/plugins/editor_resource_conversion_plugin.h"
-#include "editor/property_editor.h"
-#include "scene/gui/button.h"
-#include "scene/gui/code_edit.h"
-#include "scene/gui/graph_edit.h"
-#include "scene/gui/popup.h"
-#include "scene/gui/rich_text_label.h"
-#include "scene/gui/tree.h"
#include "scene/resources/visual_shader.h"
+class Button;
+class CodeEdit;
+class CodeHighlighter;
+class CurveEditor;
+class GraphEdit;
+class GraphNode;
+class PopupMenu;
+class PopupPanel;
+class RichTextLabel;
+class TextEdit;
+class Tree;
+
class VisualShaderEditor;
+class EditorUndoRedoManager;
class VisualShaderNodePlugin : public RefCounted {
GDCLASS(VisualShaderNodePlugin, RefCounted);
@@ -138,13 +143,31 @@ public:
~VisualShaderGraphPlugin();
};
+class VisualShaderEditedProperty : public RefCounted {
+ GDCLASS(VisualShaderEditedProperty, RefCounted);
+
+private:
+ Variant edited_property;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_edited_property(Variant p_variant);
+ Variant get_edited_property() const;
+
+ VisualShaderEditedProperty() {}
+};
+
class VisualShaderEditor : public VBoxContainer {
GDCLASS(VisualShaderEditor, VBoxContainer);
friend class VisualShaderGraphPlugin;
- CustomPropertyEditor *property_editor = nullptr;
+ PopupPanel *property_editor_popup = nullptr;
+ EditorProperty *property_editor = nullptr;
int editing_node = -1;
int editing_port = -1;
+ Ref<VisualShaderEditedProperty> edited_property_holder;
Ref<VisualShader> visual_shader;
GraphEdit *graph = nullptr;
@@ -170,7 +193,7 @@ class VisualShaderEditor : public VBoxContainer {
PanelContainer *error_panel = nullptr;
Label *error_label = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
Point2 saved_node_pos;
bool saved_node_pos_dirty = false;
@@ -359,7 +382,7 @@ class VisualShaderEditor : public VBoxContainer {
void _node_changed(int p_id);
void _edit_port_default_input(Object *p_button, int p_node, int p_port);
- void _port_edited();
+ void _port_edited(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing);
int to_node = -1;
int to_slot = -1;
@@ -507,8 +530,8 @@ public:
virtual Control *create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node) override;
};
-class EditorPropertyShaderMode : public EditorProperty {
- GDCLASS(EditorPropertyShaderMode, EditorProperty);
+class EditorPropertyVisualShaderMode : public EditorProperty {
+ GDCLASS(EditorPropertyVisualShaderMode, EditorProperty);
OptionButton *options = nullptr;
void _option_selected(int p_which);
@@ -520,11 +543,11 @@ public:
void setup(const Vector<String> &p_options);
virtual void update_property() override;
void set_option_button_clip(bool p_enable);
- EditorPropertyShaderMode();
+ EditorPropertyVisualShaderMode();
};
-class EditorInspectorShaderModePlugin : public EditorInspectorPlugin {
- GDCLASS(EditorInspectorShaderModePlugin, EditorInspectorPlugin);
+class EditorInspectorVisualShaderModePlugin : public EditorInspectorPlugin {
+ GDCLASS(EditorInspectorVisualShaderModePlugin, EditorInspectorPlugin);
public:
virtual bool can_handle(Object *p_object) override;
diff --git a/editor/plugins/voxel_gi_editor_plugin.cpp b/editor/plugins/voxel_gi_editor_plugin.cpp
index e3b2be33df..713c90c075 100644
--- a/editor/plugins/voxel_gi_editor_plugin.cpp
+++ b/editor/plugins/voxel_gi_editor_plugin.cpp
@@ -100,7 +100,7 @@ void VoxelGIEditorPlugin::_notification(int p_what) {
return;
}
- bake->set_tooltip(text);
+ bake->set_tooltip_text(text);
} break;
}
}
diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp
index 658258d98b..83275a2a7b 100644
--- a/editor/project_converter_3_to_4.cpp
+++ b/editor/project_converter_3_to_4.cpp
@@ -41,8 +41,7 @@ const int ERROR_CODE = 77;
#include "core/os/time.h"
#include "core/templates/hash_map.h"
#include "core/templates/list.h"
-
-const int CONVERSION_MAX_FILE_SIZE = 1024 * 1024 * 4; // 4 MB
+#include "core/templates/local_vector.h"
static const char *enum_renames[][2] = {
//// constants
@@ -75,8 +74,7 @@ static const char *enum_renames[][2] = {
{ "ARVR_STEREO", "XR_STEREO" }, // XRInterface
{ "ARVR_UNKNOWN_TRACKING", "XR_UNKNOWN_TRACKING" }, // XRInterface
{ "BAKE_ERROR_INVALID_MESH", "BAKE_ERROR_MESHES_INVALID" }, // LightmapGI
- { "BODY_MODE_CHARACTER", "BODY_MODE_DYNAMIC" }, // PhysicsServer2D
- { "BODY_MODE_DYNAMIC_LOCKED", "BODY_MODE_DYNAMIC_LINEAR" }, // PhysicsServer3D
+ { "BODY_MODE_CHARACTER", "BODY_MODE_RIGID_LINEAR" }, // PhysicsServer
{ "BUTTON_LEFT", "MOUSE_BUTTON_LEFT" }, // Globals
{ "BUTTON_MASK_LEFT", "MOUSE_BUTTON_MASK_LEFT" }, // Globals
{ "BUTTON_MASK_MIDDLE", "MOUSE_BUTTON_MASK_MIDDLE" }, // Globals
@@ -124,15 +122,13 @@ static const char *enum_renames[][2] = {
{ "MATH_RAND", "MATH_RANDF_RANGE" }, // VisualScriptBuiltinFunc
{ "MATH_RANDOM", "MATH_RANDI_RANGE" }, // VisualScriptBuiltinFunc
{ "MATH_STEPIFY", "MATH_STEP_DECIMALS" }, // VisualScriptBuiltinFunc
- { "MODE_CHARACTER", "MODE_DYNAMIC_LOCKED" }, // RigidBody2D, RigidBody3D
- { "MODE_KINEMATIC", "FREEZE_MODE_KINEMATIC" }, // RigidDynamicBody
+ { "MODE_KINEMATIC", "FREEZE_MODE_KINEMATIC" }, // RigidBody
{ "MODE_OPEN_ANY", "FILE_MODE_OPEN_ANY" }, // FileDialog
{ "MODE_OPEN_DIR", "FILE_MODE_OPEN_DIR" }, // FileDialog
{ "MODE_OPEN_FILE", "FILE_MODE_OPEN_FILE" }, // FileDialog
{ "MODE_OPEN_FILES", "FILE_MODE_OPEN_FILES" }, // FileDialog
- { "MODE_RIGID", "MODE_DYNAMIC" }, // RigidBody2D, RigidBody3D
{ "MODE_SAVE_FILE", "FILE_MODE_SAVE_FILE" }, // FileDialog
- { "MODE_STATIC", "FREEZE_MODE_STATIC" }, // RigidDynamicBody
+ { "MODE_STATIC", "FREEZE_MODE_STATIC" }, // RigidBody
{ "NOTIFICATION_APP_PAUSED", "NOTIFICATION_APPLICATION_PAUSED" }, // MainLoop
{ "NOTIFICATION_APP_RESUMED", "NOTIFICATION_APPLICATION_RESUMED" }, // MainLoop
{ "NOTIFICATION_PATH_CHANGED", "NOTIFICATION_PATH_RENAMED" }, //Node
@@ -200,13 +196,15 @@ static const char *gdscript_function_renames[][2] = {
// { "set_color", "surface_set_color"}, // ImmediateMesh broke Light2D, Theme, SurfaceTool
// { "set_event", "set_shortcut" }, // BaseButton - Cyclic Rename
// { "set_extents", "set_size"}, // BoxShape, RectangleShape broke ReflectionProbe
- // { "set_flag", "set_particle_flag"}, // ParticlesMaterial broke Window, HingeJoint3D
+ // { "set_flag", "set_particle_flag"}, // ParticleProcessMaterial broke Window, HingeJoint3D
// { "set_h_offset", "set_drag_horizontal_offset" }, // Camera2D broke Camera3D, PathFollow3D, PathFollow2D
// { "set_margin", "set_offset" }, // Control broke Shape3D, AtlasTexture
// { "set_mode", "set_mode_file_mode" }, // FileDialog broke Panel, Shader, CSGPolygon, Tilemap
// { "set_normal", "surface_set_normal"}, // ImmediateGeometry broke SurfaceTool, WorldMarginShape2D
+ // { "set_offset", "set_progress" }, // PathFollow2D, PathFollow3D - Too common
// { "set_process_mode", "set_process_callback" }, // AnimationTree broke Node, Tween, Sky
// { "set_refuse_new_network_connections", "set_refuse_new_connections"}, // MultiplayerAPI broke SceneTree
+ // { "set_tooltip", "set_tooltip_text" }, // Control, breaks TreeItem, at least for now.
// { "set_uv", "surface_set_uv" }, // ImmediateMesh broke Polygon2D
// { "set_v_offset", "set_drag_vertical_offset" }, // Camera2D broke Camera3D, PathFollow3D, PathFollow2D
// {"get_points","get_points_id"},// Astar, broke Line2D, Convexpolygonshape
@@ -219,18 +217,17 @@ static const char *gdscript_function_renames[][2] = {
{ "_update_wrap_at", "_update_wrap_at_column" }, // TextEdit
{ "add_animation", "add_animation_library" }, // AnimationPlayer
{ "add_cancel", "add_cancel_button" }, // AcceptDialog
- { "add_central_force", "apply_central_force" }, //RigidDynamicBody2D
+ { "add_central_force", "apply_central_force" }, //RigidBody2D
{ "add_child_below_node", "add_sibling" }, // Node
{ "add_color_override", "add_theme_color_override" }, // Control
{ "add_constant_override", "add_theme_constant_override" }, // Control
{ "add_font_override", "add_theme_font_override" }, // Control
- { "add_force", "apply_force" }, //RigidDynamicBody2D
+ { "add_force", "apply_force" }, //RigidBody2D
{ "add_icon_override", "add_theme_icon_override" }, // Control
{ "add_scene_import_plugin", "add_scene_format_importer_plugin" }, //EditorPlugin
{ "add_stylebox_override", "add_theme_stylebox_override" }, // Control
- { "add_torque", "apply_torque" }, //RigidDynamicBody2D
+ { "add_torque", "apply_torque" }, //RigidBody2D
{ "apply_changes", "_apply_changes" }, // EditorPlugin
- { "bind_child_node_to_bone", "set_bone_children" }, // Skeleton3D
{ "body_add_force", "body_apply_force" }, // PhysicsServer2D
{ "body_add_torque", "body_apply_torque" }, // PhysicsServer2D
{ "bumpmap_to_normalmap", "bump_map_to_normal_map" }, // Image
@@ -255,6 +252,7 @@ static const char *gdscript_function_renames[][2] = {
{ "damped_spring_joint_create", "joint_make_damped_spring" }, // PhysicsServer2D
{ "damped_string_joint_get_param", "damped_spring_joint_get_param" }, // PhysicsServer2D
{ "damped_string_joint_set_param", "damped_spring_joint_set_param" }, // PhysicsServer2D
+ { "dectime", "move_toward" }, // GDScript, Math functions
{ "delete_char_at_cursor", "delete_char_at_caret" }, // LineEdit
{ "deselect_items", "deselect_all" }, // FileDialog
{ "disable_plugin", "_disable_plugin" }, // EditorPlugin
@@ -273,8 +271,8 @@ static const char *gdscript_function_renames[][2] = {
{ "get_action_list", "action_get_events" }, // InputMap
{ "get_alt", "is_alt_pressed" }, // InputEventWithModifiers
{ "get_animation_process_mode", "get_process_callback" }, // AnimationPlayer
- { "get_applied_force", "get_constant_force" }, //RigidDynamicBody2D
- { "get_applied_torque", "get_constant_torque" }, //RigidDynamicBody2D
+ { "get_applied_force", "get_constant_force" }, //RigidBody2D
+ { "get_applied_torque", "get_constant_torque" }, //RigidBody2D
{ "get_audio_bus", "get_audio_bus_name" }, // Area3D
{ "get_bound_child_nodes_to_bone", "get_bone_children" }, // Skeleton3D
{ "get_camera", "get_camera_3d" }, // Viewport -> this is also convertable to get_camera_2d, broke GLTFNode
@@ -297,11 +295,11 @@ static const char *gdscript_function_renames[][2] = {
{ "get_d", "get_distance" }, // LineShape2D
{ "get_drag_data", "_get_drag_data" }, // Control
{ "get_drag_data_fw", "_get_drag_data_fw" }, // ScriptEditor
- { "get_editor_description", "_get_editor_description" }, // Node
{ "get_editor_viewport", "get_viewport" }, // EditorPlugin
{ "get_enabled_focus_mode", "get_focus_mode" }, // BaseButton
{ "get_endian_swap", "is_big_endian" }, // File
{ "get_error_string", "get_error_message" }, // JSON
+ { "get_filename", "get_scene_file_path" }, // Node, WARNING, this may be used in a lot of other places
{ "get_focus_neighbour", "get_focus_neighbor" }, // Control
{ "get_font_types", "get_font_type_list" }, // Theme
{ "get_frame_color", "get_color" }, // ColorRect
@@ -356,6 +354,7 @@ static const char *gdscript_function_renames[][2] = {
{ "get_scancode_with_modifiers", "get_keycode_with_modifiers" }, // InputEventKey
{ "get_shift", "is_shift_pressed" }, // InputEventWithModifiers
{ "get_size_override", "get_size_2d_override" }, // SubViewport
+ { "get_slide_count", "get_slide_collision_count" }, // CharacterBody2D, CharacterBody3D
{ "get_slips_on_slope", "get_slide_on_slope" }, // SeparationRayShape2D, SeparationRayShape3D
{ "get_space_override_mode", "get_gravity_space_override_mode" }, // Area2D
{ "get_speed", "get_velocity" }, // InputEventMouseMotion
@@ -368,6 +367,7 @@ static const char *gdscript_function_renames[][2] = {
{ "get_theme_item_types", "get_theme_item_type_list" }, // Theme
{ "get_timer_process_mode", "get_timer_process_callback" }, // Timer
{ "get_translation", "get_position" }, // Node3D broke GLTFNode which is used rarely
+ { "get_unit_offset", "get_progress_ratio" }, // PathFollow2D, PathFollow3D
{ "get_use_in_baked_light", "is_baking_navigation" }, // GridMap
{ "get_used_cells_by_id", "get_used_cells" }, // TileMap
{ "get_v_scrollbar", "get_v_scroll_bar" }, //ScrollContainer
@@ -395,7 +395,6 @@ static const char *gdscript_function_renames[][2] = {
{ "has_stylebox_override", "has_theme_stylebox_override" }, // Control
{ "http_escape", "uri_encode" }, // String
{ "http_unescape", "uri_decode" }, // String
- { "import_animation_from_other_importer", "_import_animation" }, //EditorSceneFormatImporter
{ "import_scene_from_other_importer", "_import_scene" }, //EditorSceneFormatImporter
{ "instance_set_surface_material", "instance_set_surface_override_material" }, // RenderingServer
{ "intersect_polygons_2d", "intersect_polygons" }, // Geometry2D
@@ -427,6 +426,7 @@ static const char *gdscript_function_renames[][2] = {
{ "joint_create_slider", "joint_make_slider" }, // PhysicsServer3D
{ "line_intersects_line_2d", "line_intersects_line" }, // Geometry2D
{ "load_from_globals", "load_from_project_settings" }, // InputMap
+ { "load_interactive", "load_threaded_request" }, // ResourceLoader - load_threaded_request is alternative, but is used differently
{ "make_convex_from_brothers", "make_convex_from_siblings" }, // CollisionShape3D
{ "make_visible", "_make_visible" }, // EditorPlugin
{ "merge_polygons_2d", "merge_polygons" }, // Geometry2D
@@ -484,6 +484,7 @@ static const char *gdscript_function_renames[][2] = {
{ "set_enabled_focus_mode", "set_focus_mode" }, // BaseButton
{ "set_endian_swap", "set_big_endian" }, // File
{ "set_expand_to_text_length", "set_expand_to_text_length_enabled" }, // LineEdit
+ { "set_filename", "set_scene_file_path" }, // Node, WARNING, this may be used in a lot of other places
{ "set_focus_neighbour", "set_focus_neighbor" }, // Control
{ "set_frame_color", "set_color" }, // ColorRect
{ "set_global_rate_scale", "set_playback_speed_scale" }, // AudioServer
@@ -511,6 +512,7 @@ static const char *gdscript_function_renames[][2] = {
{ "set_region_filter_clip", "set_region_filter_clip_enabled" }, // Sprite2D
{ "set_rotate", "set_rotates" }, // PathFollow2D
{ "set_scancode", "set_keycode" }, // InputEventKey
+ { "set_shader_param", "set_shader_uniform" }, // ShaderMaterial
{ "set_shift", "set_shift_pressed" }, // InputEventWithModifiers
{ "set_size_override", "set_size_2d_override" }, // SubViewport broke ImageTexture
{ "set_size_override_stretch", "set_size_2d_override_stretch" }, // SubViewport
@@ -526,6 +528,7 @@ static const char *gdscript_function_renames[][2] = {
{ "set_timer_process_mode", "set_timer_process_callback" }, // Timer
{ "set_tonemap_auto_exposure", "set_tonemap_auto_exposure_enabled" }, // Environment
{ "set_translation", "set_position" }, // Node3D - this broke GLTFNode which is used rarely
+ { "set_unit_offset", "set_progress_ratio" }, // PathFollow2D, PathFollow3D
{ "set_uv2", "surface_set_uv2" }, // ImmediateMesh broke Surffacetool
{ "set_v_drag_enabled", "set_drag_vertical_enabled" }, // Camera2D
{ "set_valign", "set_vertical_alignment" }, // Label
@@ -539,7 +542,6 @@ static const char *gdscript_function_renames[][2] = {
{ "targeting_property", "tween_property" }, // Tween
{ "track_remove_key_at_position", "track_remove_key_at_time" }, // Animation
{ "triangulate_delaunay_2d", "triangulate_delaunay" }, // Geometry2D
- { "unbind_child_node_from_bone", "remove_bone_child" }, // Skeleton3D
{ "unselect", "deselect" }, // ItemList
{ "unselect_all", "deselect_all" }, // ItemList
{ "update_configuration_warning", "update_configuration_warnings" }, // Node
@@ -548,6 +550,7 @@ static const char *gdscript_function_renames[][2] = {
{ "warp_mouse_position", "warp_mouse" }, // Input
// Builtin types
+ // Remember to add them to builtin_types_excluded_functions variable, because for now this functions cannot be listed
// { "empty", "is_empty" }, // Array - Used as custom rule // Be careful, this will be used everywhere
{ "clamped", "clamp" }, // Vector2 // Be careful, this will be used everywhere
{ "get_rotation_quat", "get_rotation_quaternion" }, // Basis
@@ -560,9 +563,25 @@ static const char *gdscript_function_renames[][2] = {
{ "to_utf8", "to_utf8_buffer" }, // String
{ "to_wchar", "to_utf32_buffer" }, // String // TODO - utf32 or utf16?
- // Globals
+ // @GlobalScope
+ // Remember to add them to builtin_types_excluded_functions variable, because for now this functions cannot be listed
+ { "bytes2var", "bytes_to_var" },
+ { "bytes2var_with_objects", "bytes_to_var_with_objects" },
+ { "db2linear", "db_to_linear" },
+ { "deg2rad", "deg_to_rad" },
+ { "linear2db", "linear_to_db" },
+ { "rad2deg", "rad_to_deg" },
{ "rand_range", "randf_range" },
{ "stepify", "snapped" },
+ { "str2var", "str_to_var" },
+ { "var2str", "var_to_str" },
+ { "var2bytes", "var_to_bytes" },
+ { "var2bytes_with_objects", "var_to_bytes_with_objects" },
+
+ // @GDScript
+ // Remember to add them to builtin_types_excluded_functions variable, because for now this functions cannot be listed
+ { "dict2inst", "dict_to_inst" },
+ { "inst2dict", "inst_to_dict" },
{ nullptr, nullptr },
};
@@ -601,13 +620,15 @@ static const char *csharp_function_renames[][2] = {
// { "SetColor", "SurfaceSetColor"}, // ImmediateMesh broke Light2D, Theme, SurfaceTool
// { "SetEvent", "SetShortcut" }, // BaseButton - Cyclic Rename
// { "SetExtents", "SetSize"}, // BoxShape, RectangleShape broke ReflectionProbe
- // { "SetFlag", "SetParticleFlag"}, // ParticlesMaterial broke Window, HingeJoint3D
+ // { "SetFlag", "SetParticleFlag"}, // ParticleProcessMaterial broke Window, HingeJoint3D
// { "SetHOffset", "SetDragHorizontalOffset" }, // Camera2D broke Camera3D, PathFollow3D, PathFollow2D
// { "SetMargin", "SetOffset" }, // Control broke Shape3D, AtlasTexture
// { "SetMode", "SetModeFileMode" }, // FileDialog broke Panel, Shader, CSGPolygon, Tilemap
// { "SetNormal", "SurfaceSetNormal"}, // ImmediateGeometry broke SurfaceTool, WorldMarginShape2D
+ // { "SetOffset", "SetProgress" }, // PathFollow2D, PathFollow3D - Too common
// { "SetProcessMode", "SetProcessCallback" }, // AnimationTree broke Node, Tween, Sky
// { "SetRefuseNewNetworkConnections", "SetRefuseNewConnections"}, // MultiplayerAPI broke SceneTree
+ // { "SetTooltip", "SetTooltipText" }, // Control, breaks TreeItem, at least for now.
// { "SetUv", "SurfaceSetUv" }, // ImmediateMesh broke Polygon2D
// { "SetVOffset", "SetDragVerticalOffset" }, // Camera2D broke Camera3D, PathFollow3D, PathFollow2D
// {"GetPoints","GetPointsId"},// Astar, broke Line2D, Convexpolygonshape
@@ -621,16 +642,16 @@ static const char *csharp_function_renames[][2] = {
{ "_UpdateWrapAt", "_UpdateWrapAtColumn" }, // TextEdit
{ "AddAnimation", "AddAnimationLibrary" }, // AnimationPlayer
{ "AddCancel", "AddCancelButton" }, // AcceptDialog
- { "AddCentralForce", "AddConstantCentralForce" }, //RigidDynamicBody2D
+ { "AddCentralForce", "AddConstantCentralForce" }, //RigidBody2D
{ "AddChildBelowNode", "AddSibling" }, // Node
{ "AddColorOverride", "AddThemeColorOverride" }, // Control
{ "AddConstantOverride", "AddThemeConstantOverride" }, // Control
{ "AddFontOverride", "AddThemeFontOverride" }, // Control
- { "AddForce", "AddConstantForce" }, //RigidDynamicBody2D
+ { "AddForce", "AddConstantForce" }, //RigidBody2D
{ "AddIconOverride", "AddThemeIconOverride" }, // Control
{ "AddSceneImportPlugin", "AddSceneFormatImporterPlugin" }, //EditorPlugin
{ "AddStyleboxOverride", "AddThemeStyleboxOverride" }, // Control
- { "AddTorque", "AddConstantTorque" }, //RigidDynamicBody2D
+ { "AddTorque", "AddConstantTorque" }, //RigidBody2D
{ "BindChildNodeToBone", "SetBoneChildren" }, // Skeleton3D
{ "BumpmapToNormalmap", "BumpMapToNormalMap" }, // Image
{ "CanBeHidden", "_CanBeHidden" }, // EditorNode3DGizmoPlugin
@@ -669,8 +690,8 @@ static const char *csharp_function_renames[][2] = {
{ "GetActionList", "ActionGetEvents" }, // InputMap
{ "GetAlt", "IsAltPressed" }, // InputEventWithModifiers
{ "GetAnimationProcessMode", "GetProcessCallback" }, // AnimationPlayer
- { "GetAppliedForce", "GetConstantForce" }, //RigidDynamicBody2D
- { "GetAppliedTorque", "GetConstantTorque" }, //RigidDynamicBody2D
+ { "GetAppliedForce", "GetConstantForce" }, //RigidBody2D
+ { "GetAppliedTorque", "GetConstantTorque" }, //RigidBody2D
{ "GetAudioBus", "GetAudioBusName" }, // Area3D
{ "GetBoundChildNodesToBone", "GetBoneChildren" }, // Skeleton3D
{ "GetCamera", "GetCamera3d" }, // Viewport -> this is also convertable to getCamera2d, broke GLTFNode
@@ -761,6 +782,7 @@ static const char *csharp_function_renames[][2] = {
{ "GetThemeItemTypes", "GetThemeItemTypeList" }, // Theme
{ "GetTimerProcessMode", "GetTimerProcessCallback" }, // Timer
{ "GetTranslation", "GetPosition" }, // Node3D broke GLTFNode which is used rarely
+ { "GetUnitOffset", "GetProgressRatio" }, // PathFollow2D, PathFollow3D
{ "GetUseInBakedLight", "IsBakingNavigation" }, // GridMap
{ "GetUsedCellsById", "GetUsedCells" }, // TileMap
{ "GetVScrollbar", "GetVScrollBar" }, //ScrollContainer
@@ -912,6 +934,7 @@ static const char *csharp_function_renames[][2] = {
{ "SetTimerProcessMode", "SetTimerProcessCallback" }, // Timer
{ "SetTonemapAutoExposure", "SetTonemapAutoExposureEnabled" }, // Environment
{ "SetTranslation", "SetPosition" }, // Node3D - this broke GLTFNode which is used rarely
+ { "SetUnitOffset", "SetProgressRatio" }, // PathFollow2D, PathFollow3D
{ "SetUv2", "SurfaceSetUv2" }, // ImmediateMesh broke Surffacetool
{ "SetVDragEnabled", "SetDragVerticalEnabled" }, // Camera2D
{ "SetValign", "SetVerticalAlignment" }, // Label
@@ -946,9 +969,23 @@ static const char *csharp_function_renames[][2] = {
{ "ToUtf8", "ToUtf8Buffer" }, // String
{ "ToWchar", "ToUtf32Buffer" }, // String // TODO - utf32 or utf16?
- // Globals
+ // @GlobalScope
+ { "Bytes2Var", "BytesToVar" },
+ { "Bytes2VarWithObjects", "BytesToVarWithObjects" },
+ { "Db2Linear", "DbToLinear" },
+ { "Deg2Rad", "DegToRad" },
+ { "Linear2Db", "LinearToDb" },
+ { "Rad2Deg", "RadToDeg" },
{ "RandRange", "RandfRange" },
{ "Stepify", "Snapped" },
+ { "Str2Var", "StrToVar" },
+ { "Var2Str", "VarToStr" },
+ { "Var2Bytes", "VarToBytes" },
+ { "Var2BytesWithObjects", "VarToBytesWithObjects" },
+
+ // @GDScript
+ { "Dict2Inst", "DictToInst" },
+ { "Inst2Dict", "InstToDict" },
{ nullptr, nullptr },
};
@@ -963,6 +1000,7 @@ static const char *gdscript_properties_renames[][2] = {
// // {"meta","meta_pressed"},// This may broke a lot of comments and user variables
// // {"pause_mode","process_mode"}, // Node - Cyclic rename, look for others
// // {"rotate","rotates"}, // PathFollow2D - probably function exists with same name
+ // // {"offset","progress"}, // PathFollow2D, PathFollow3D - Name is way too vague
// // {"shift","shift_pressed"},// This may broke a lot of comments and user variables
// { "autowrap", "autowrap_mode" }, // Label
// { "cast_to", "target_position" }, // RayCast2D, RayCast3D
@@ -975,6 +1013,7 @@ static const char *gdscript_properties_renames[][2] = {
// { "wrap_enabled", "wrap_mode" }, // TextEdit
// { "zfar", "far" }, // Camera3D
// { "znear", "near" }, // Camera3D
+ // { "filename", "scene_file_path" }, // Node
{ "as_normalmap", "as_normal_map" }, // NoiseTexture
{ "bbcode_text", "text" }, // RichTextLabel
{ "caret_moving_by_right_click", "caret_move_on_right_click" }, // TextEdit
@@ -983,6 +1022,7 @@ static const char *gdscript_properties_renames[][2] = {
{ "close_h_ofs", "close_h_offset" }, // Theme
{ "close_v_ofs", "close_v_offset" }, // Theme
{ "commentfocus", "comment_focus" }, // Theme
+ { "contacts_reported", "max_contacts_reported" }, // RigidBody
{ "drag_margin_bottom", "drag_bottom_margin" }, // Camera2D
{ "drag_margin_h_enabled", "drag_horizontal_enabled" }, // Camera2D
{ "drag_margin_left", "drag_left_margin" }, // Camera2D
@@ -999,8 +1039,10 @@ static const char *gdscript_properties_renames[][2] = {
{ "global_rate_scale", "playback_speed_scale" }, // AudioServer
{ "gravity_distance_scale", "gravity_point_distance_scale" }, // Area2D
{ "gravity_vec", "gravity_direction" }, // Area2D
+ { "hint_tooltip", "tooltip_text" }, // Control
{ "hseparation", "h_separation" }, // Theme
{ "iterations_per_second", "physics_ticks_per_second" }, // Engine
+ { "invert_enable", "invert_enabled" }, // Polygon2D
{ "margin_bottom", "offset_bottom" }, // Control broke NinePatchRect, StyleBox
{ "margin_left", "offset_left" }, // Control broke NinePatchRect, StyleBox
{ "margin_right", "offset_right" }, // Control broke NinePatchRect, StyleBox
@@ -1013,6 +1055,14 @@ static const char *gdscript_properties_renames[][2] = {
{ "pause_mode", "process_mode" }, // Node
{ "physical_scancode", "physical_keycode" }, // InputEventKey
{ "popup_exclusive", "exclusive" }, // Window
+ { "rect_position", "position" }, // Control
+ { "rect_global_position", "global_position" }, // Control
+ { "rect_size", "size" }, // Control
+ { "rect_min_size", "minimum_size" }, // Control
+ { "rect_rotation", "rotation" }, // Control
+ { "rect_scale", "scale" }, // Control
+ { "rect_pivot_offset", "pivot_offset" }, // Control
+ { "rect_clip_content", "clip_contents" }, // Control
{ "refuse_new_network_connections", "refuse_new_connections" }, // MultiplayerAPI
{ "region_filter_clip", "region_filter_clip_enabled" }, // Sprite2D
{ "selectedframe", "selected_frame" }, // Theme
@@ -1029,6 +1079,7 @@ static const char *gdscript_properties_renames[][2] = {
{ "table_hseparation", "table_h_separation" }, // Theme
{ "table_vseparation", "table_v_separation" }, // Theme
{ "translation", "position" }, // Node3D - broke GLTFNode
+ { "unit_offset", "progress_ratio" }, // PathFollow2D, PathFollow3D
{ "vseparation", "v_separation" }, // Theme
{ nullptr, nullptr },
@@ -1044,6 +1095,7 @@ static const char *csharp_properties_renames[][2] = {
// // {"Meta","MetaPressed"},// This may broke a lot of comments and user variables
// // {"PauseMode","ProcessMode"}, // Node - Cyclic rename, look for others
// // {"Rotate","Rotates"}, // PathFollow2D - probably function exists with same name
+ // // {"Offset","Progress"}, // PathFollow2D, PathFollow3D - Name is way too vague
// // {"Shift","ShiftPressed"},// This may broke a lot of comments and user variables
// { "Autowrap", "AutowrapMode" }, // Label
// { "CastTo", "TargetPosition" }, // RayCast2D, RayCast3D
@@ -1080,8 +1132,10 @@ static const char *csharp_properties_renames[][2] = {
{ "GlobalRateScale", "PlaybackSpeedScale" }, // AudioServer
{ "GravityDistanceScale", "GravityPointDistanceScale" }, // Area2D
{ "GravityVec", "GravityDirection" }, // Area2D
+ { "HintTooltip", "TooltipText" }, // Control
{ "Hseparation", "HSeparation" }, // Theme
{ "IterationsPerSecond", "PhysicsTicksPerSecond" }, // Engine
+ { "InvertEnable", "InvertEnabled" }, // Polygon2D
{ "MarginBottom", "OffsetBottom" }, // Control broke NinePatchRect, StyleBox
{ "MarginLeft", "OffsetLeft" }, // Control broke NinePatchRect, StyleBox
{ "MarginRight", "OffsetRight" }, // Control broke NinePatchRect, StyleBox
@@ -1110,6 +1164,7 @@ static const char *csharp_properties_renames[][2] = {
{ "TableHseparation", "TableHSeparation" }, // Theme
{ "TableVseparation", "TableVSeparation" }, // Theme
{ "Translation", "Position" }, // Node3D - broke GLTFNode
+ { "UnitOffset", "ProgressRatio" }, // PathFollow2D, PathFollow3D
{ "Vseparation", "VSeparation" }, // Theme
{ nullptr, nullptr },
@@ -1222,9 +1277,19 @@ static const char *builtin_types_renames[][2] = {
static const char *shaders_renames[][2] = {
{ "ALPHA_SCISSOR", "ALPHA_SCISSOR_THRESHOLD" },
+ { "CAMERA_MATRIX", "INV_VIEW_MATRIX" },
+ { "INV_CAMERA_MATRIX", "VIEW_MATRIX" },
{ "NORMALMAP", "NORMAL_MAP" },
{ "NORMALMAP_DEPTH", "NORMAL_MAP_DEPTH" },
- { "TRANSMISSION", "SSS_TRANSMITTANCE_COLOR" },
+ { "TRANSMISSION", "BACKLIGHT" },
+ { "WORLD_MATRIX", "MODEL_MATRIX" },
+ { "depth_draw_alpha_prepass", "depth_draw_opaque" },
+ { "hint_albedo", "source_color" },
+ { "hint_aniso", "hint_anisotropy" },
+ { "hint_black", "hint_default_black" },
+ { "hint_black_albedo", "hint_default_black" },
+ { "hint_color", "source_color" },
+ { "hint_white", "hint_default_white" },
{ nullptr, nullptr },
};
@@ -1337,6 +1402,7 @@ static const char *class_renames[][2] = {
{ "PanoramaSky", "Sky" },
{ "Particles", "GPUParticles3D" }, // Be careful, this will be used everywhere
{ "Particles2D", "GPUParticles2D" },
+ { "ParticlesMaterial", "ParticleProcessMaterial" },
{ "Path", "Path3D" }, // Be careful, this will be used everywhere
{ "PathFollow", "PathFollow3D" },
{ "PhysicalBone", "PhysicalBone3D" },
@@ -1355,6 +1421,8 @@ static const char *class_renames[][2] = {
{ "PinJoint", "PinJoint3D" },
{ "PlaneShape", "WorldBoundaryShape3D" },
{ "PopupDialog", "Popup" },
+ { "Position2D", "Marker2D" },
+ { "Position3D", "Marker3D" },
{ "ProceduralSky", "Sky" },
{ "RayCast", "RayCast3D" },
{ "RayShape", "SeparationRayShape3D" },
@@ -1362,19 +1430,17 @@ static const char *class_renames[][2] = {
{ "Reference", "RefCounted" }, // Be careful, this will be used everywhere
{ "RemoteTransform", "RemoteTransform3D" },
{ "ResourceInteractiveLoader", "ResourceLoader" },
- { "RigidBody", "RigidDynamicBody3D" },
- { "RigidBody2D", "RigidDynamicBody2D" },
+ { "RigidBody", "RigidBody3D" },
{ "SceneTreeTween", "Tween" },
{ "Shape", "Shape3D" }, // Be careful, this will be used everywhere
{ "ShortCut", "Shortcut" },
{ "Skeleton", "Skeleton3D" },
{ "SkeletonIK", "SkeletonIK3D" },
{ "SliderJoint", "SliderJoint3D" },
- { "SoftBody", "SoftDynamicBody3D" },
+ { "SoftBody", "SoftBody3D" },
{ "Spatial", "Node3D" },
{ "SpatialGizmo", "Node3DGizmo" },
{ "SpatialMaterial", "StandardMaterial3D" },
- { "SpatialVelocityTracker", "VelocityTracker3D" },
{ "SphereShape", "SphereShape3D" },
{ "SpotLight", "SpotLight3D" },
{ "SpringArm", "SpringArm3D" },
@@ -1444,7 +1510,7 @@ static const char *class_renames[][2] = {
};
// TODO - this colors needs to be validated(not all are valid)
-static const char *colors_renames[][2] = {
+static const char *color_renames[][2] = {
{ "aliceblue", "ALICE_BLUE" },
{ "antiquewhite", "ANTIQUE_WHITE" },
{ "aqua", "AQUA" },
@@ -1595,15 +1661,210 @@ static const char *colors_renames[][2] = {
{ nullptr, nullptr },
};
+class ProjectConverter3To4::RegExContainer {
+public:
+ // Custom GDScript
+ RegEx reg_is_empty = RegEx("\\bempty\\(");
+ RegEx reg_super = RegEx("([\t ])\\.([a-zA-Z_])");
+ RegEx reg_json_to = RegEx("\\bto_json\\b");
+ RegEx reg_json_parse = RegEx("([\t ]{0,})([^\n]+)parse_json\\(([^\n]+)");
+ RegEx reg_json_non_new = RegEx("([\t ]{0,})([^\n]+)JSON\\.parse\\(([^\n]+)");
+ RegEx reg_export = RegEx("export\\(([a-zA-Z0-9_]+)\\)[ ]+var[ ]+([a-zA-Z0-9_]+)");
+ RegEx reg_export_advanced = RegEx("export\\(([^)^\n]+)\\)[ ]+var[ ]+([a-zA-Z0-9_]+)([^\n]+)");
+ RegEx reg_setget_setget = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+([a-zA-Z0-9_]+)[ \t]*,[ \t]*([a-zA-Z0-9_]+)");
+ RegEx reg_setget_set = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+([a-zA-Z0-9_]+)[ \t]*[,]*[^a-z^A-Z^0-9^_]*$");
+ RegEx reg_setget_get = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+,[ \t]*([a-zA-Z0-9_]+)[ \t]*$");
+ RegEx reg_join = RegEx("([\\(\\)a-zA-Z0-9_]+)\\.join\\(([^\n^\\)]+)\\)");
+ RegEx reg_image_lock = RegEx("([a-zA-Z0-9_\\.]+)\\.lock\\(\\)");
+ RegEx reg_image_unlock = RegEx("([a-zA-Z0-9_\\.]+)\\.unlock\\(\\)");
+ RegEx reg_os_fullscreen = RegEx("OS.window_fullscreen[= ]+([^#^\n]+)");
+ RegEx reg_instantiate = RegEx("\\.instance\\(([^\\)]*)\\)");
+
+ // GDScript keywords
+ RegEx keyword_gdscript_tool = RegEx("^tool");
+ RegEx keyword_gdscript_export_single = RegEx("^export");
+ RegEx keyword_gdscript_export_mutli = RegEx("([\t]+)export\\b");
+ RegEx keyword_gdscript_onready = RegEx("^onready");
+ RegEx keyword_gdscript_remote = RegEx("^remote func");
+ RegEx keyword_gdscript_remotesync = RegEx("^remotesync func");
+ RegEx keyword_gdscript_sync = RegEx("^sync func");
+ RegEx keyword_gdscript_slave = RegEx("^slave func");
+ RegEx keyword_gdscript_puppet = RegEx("^puppet func");
+ RegEx keyword_gdscript_puppetsync = RegEx("^puppetsync func");
+ RegEx keyword_gdscript_master = RegEx("^master func");
+ RegEx keyword_gdscript_mastersync = RegEx("^mastersync func");
+
+ // CSharp keywords
+ RegEx keyword_csharp_remote = RegEx("\\[Remote(Attribute)?(\\(\\))?\\]");
+ RegEx keyword_csharp_remotesync = RegEx("\\[(Remote)?Sync(Attribute)?(\\(\\))?\\]");
+ RegEx keyword_csharp_puppet = RegEx("\\[(Puppet|Slave)(Attribute)?(\\(\\))?\\]");
+ RegEx keyword_csharp_puppetsync = RegEx("\\[PuppetSync(Attribute)?(\\(\\))?\\]");
+ RegEx keyword_csharp_master = RegEx("\\[Master(Attribute)?(\\(\\))?\\]");
+ RegEx keyword_csharp_mastersync = RegEx("\\[MasterSync(Attribute)?(\\(\\))?\\]");
+
+ // Colors
+ LocalVector<RegEx *> color_regexes;
+ LocalVector<String> color_renamed;
+
+ // Classes
+ LocalVector<RegEx *> class_tscn_regexes;
+ LocalVector<RegEx *> class_gd_regexes;
+ LocalVector<RegEx *> class_shader_regexes;
+
+ LocalVector<RegEx *> class_regexes;
+
+ RegEx class_temp_tscn = RegEx("\\bTEMP_RENAMED_CLASS.tscn\\b");
+ RegEx class_temp_gd = RegEx("\\bTEMP_RENAMED_CLASS.gd\\b");
+ RegEx class_temp_shader = RegEx("\\bTEMP_RENAMED_CLASS.shader\\b");
+
+ LocalVector<String> class_temp_tscn_renames;
+ LocalVector<String> class_temp_gd_renames;
+ LocalVector<String> class_temp_shader_renames;
+
+ // Common
+ LocalVector<RegEx *> enum_regexes;
+ LocalVector<RegEx *> gdscript_function_regexes;
+ LocalVector<RegEx *> project_settings_regexes;
+ LocalVector<RegEx *> gdscript_properties_regexes;
+ LocalVector<RegEx *> gdscript_signals_regexes;
+ LocalVector<RegEx *> shaders_regexes;
+ LocalVector<RegEx *> builtin_types_regexes;
+ LocalVector<RegEx *> csharp_function_regexes;
+ LocalVector<RegEx *> csharp_properties_regexes;
+ LocalVector<RegEx *> csharp_signal_regexes;
+
+ RegExContainer() {
+ // Common
+ {
+ // Enum
+ for (unsigned int current_index = 0; enum_renames[current_index][0]; current_index++) {
+ enum_regexes.push_back(memnew(RegEx(String("\\b") + enum_renames[current_index][0] + "\\b")));
+ }
+ // GDScript functions
+ for (unsigned int current_index = 0; gdscript_function_renames[current_index][0]; current_index++) {
+ gdscript_function_regexes.push_back(memnew(RegEx(String("\\b") + gdscript_function_renames[current_index][0] + "\\b")));
+ }
+ // Project Settings
+ for (unsigned int current_index = 0; project_settings_renames[current_index][0]; current_index++) {
+ project_settings_regexes.push_back(memnew(RegEx(String("\\b") + project_settings_renames[current_index][0] + "\\b")));
+ }
+ // GDScript properties
+ for (unsigned int current_index = 0; gdscript_properties_renames[current_index][0]; current_index++) {
+ gdscript_properties_regexes.push_back(memnew(RegEx(String("\\b") + gdscript_properties_renames[current_index][0] + "\\b")));
+ }
+ // GDScript Signals
+ for (unsigned int current_index = 0; gdscript_signals_renames[current_index][0]; current_index++) {
+ gdscript_signals_regexes.push_back(memnew(RegEx(String("\\b") + gdscript_signals_renames[current_index][0] + "\\b")));
+ }
+ // Shaders
+ for (unsigned int current_index = 0; shaders_renames[current_index][0]; current_index++) {
+ shaders_regexes.push_back(memnew(RegEx(String("\\b") + shaders_renames[current_index][0] + "\\b")));
+ }
+ // Builtin types
+ for (unsigned int current_index = 0; builtin_types_renames[current_index][0]; current_index++) {
+ builtin_types_regexes.push_back(memnew(RegEx(String("\\b") + builtin_types_renames[current_index][0] + "\\b")));
+ }
+ // CSharp function renames
+ for (unsigned int current_index = 0; csharp_function_renames[current_index][0]; current_index++) {
+ csharp_function_regexes.push_back(memnew(RegEx(String("\\b") + csharp_function_renames[current_index][0] + "\\b")));
+ }
+ // CSharp properties renames
+ for (unsigned int current_index = 0; csharp_properties_renames[current_index][0]; current_index++) {
+ csharp_properties_regexes.push_back(memnew(RegEx(String("\\b") + csharp_properties_renames[current_index][0] + "\\b")));
+ }
+ // CSharp signals renames
+ for (unsigned int current_index = 0; csharp_signals_renames[current_index][0]; current_index++) {
+ csharp_signal_regexes.push_back(memnew(RegEx(String("\\b") + csharp_signals_renames[current_index][0] + "\\b")));
+ }
+ }
+
+ // Colors
+ {
+ for (unsigned int current_index = 0; color_renames[current_index][0]; current_index++) {
+ color_regexes.push_back(memnew(RegEx(String("\\bColor.") + color_renames[current_index][0] + "\\b")));
+ color_renamed.push_back(String("Color.") + color_renames[current_index][1]);
+ }
+ }
+ // Classes
+ {
+ for (unsigned int current_index = 0; class_renames[current_index][0]; current_index++) {
+ class_tscn_regexes.push_back(memnew(RegEx(String("\\b") + class_renames[current_index][0] + ".tscn\\b")));
+ class_gd_regexes.push_back(memnew(RegEx(String("\\b") + class_renames[current_index][0] + ".gd\\b")));
+ class_shader_regexes.push_back(memnew(RegEx(String("\\b") + class_renames[current_index][0] + ".shader\\b")));
+
+ class_regexes.push_back(memnew(RegEx(String("\\b") + class_renames[current_index][0] + "\\b")));
+
+ class_temp_tscn_renames.push_back(String(class_renames[current_index][0]) + ".tscn");
+ class_temp_gd_renames.push_back(String(class_renames[current_index][0]) + ".gd");
+ class_temp_shader_renames.push_back(String(class_renames[current_index][0]) + ".shader");
+ }
+ }
+ }
+ ~RegExContainer() {
+ for (unsigned int i = 0; i < color_regexes.size(); i++) {
+ memdelete(color_regexes[i]);
+ }
+ for (unsigned int i = 0; i < class_tscn_regexes.size(); i++) {
+ memdelete(class_tscn_regexes[i]);
+ memdelete(class_gd_regexes[i]);
+ memdelete(class_shader_regexes[i]);
+ memdelete(class_regexes[i]);
+ }
+ for (unsigned int i = 0; i < enum_regexes.size(); i++) {
+ memdelete(enum_regexes[i]);
+ }
+ for (unsigned int i = 0; i < gdscript_function_regexes.size(); i++) {
+ memdelete(gdscript_function_regexes[i]);
+ }
+ for (unsigned int i = 0; i < project_settings_regexes.size(); i++) {
+ memdelete(project_settings_regexes[i]);
+ }
+ for (unsigned int i = 0; i < gdscript_properties_regexes.size(); i++) {
+ memdelete(gdscript_properties_regexes[i]);
+ }
+ for (unsigned int i = 0; i < gdscript_signals_regexes.size(); i++) {
+ memdelete(gdscript_signals_regexes[i]);
+ }
+ for (unsigned int i = 0; i < shaders_regexes.size(); i++) {
+ memdelete(shaders_regexes[i]);
+ }
+ for (unsigned int i = 0; i < builtin_types_regexes.size(); i++) {
+ memdelete(builtin_types_regexes[i]);
+ }
+ for (unsigned int i = 0; i < csharp_function_regexes.size(); i++) {
+ memdelete(csharp_function_regexes[i]);
+ }
+ for (unsigned int i = 0; i < csharp_properties_regexes.size(); i++) {
+ memdelete(csharp_properties_regexes[i]);
+ }
+ for (unsigned int i = 0; i < csharp_signal_regexes.size(); i++) {
+ memdelete(csharp_signal_regexes[i]);
+ }
+ }
+};
+
+ProjectConverter3To4::ProjectConverter3To4(int maximum_file_size_kb, int maximum_line_length) {
+ this->maximum_file_size = maximum_file_size_kb * 1024;
+ this->maximum_line_length = maximum_line_length;
+}
+
// Function responsible for converting project
int ProjectConverter3To4::convert() {
print_line("Starting conversion.");
+ uint64_t conversion_start_time = Time::get_singleton()->get_ticks_msec();
+
+ RegExContainer reg_container = RegExContainer();
+
+ int cached_maximum_line_length = maximum_line_length;
+ maximum_line_length = 10000; // Use only for tests bigger value, to not break them
ERR_FAIL_COND_V_MSG(!test_array_names(), ERROR_CODE, "Cannot start converting due to problems with data in arrays.");
- ERR_FAIL_COND_V_MSG(!test_conversion(), ERROR_CODE, "Cannot start converting due to problems with converting arrays.");
+ ERR_FAIL_COND_V_MSG(!test_conversion(reg_container), ERROR_CODE, "Cannot start converting due to problems with converting arrays.");
+
+ maximum_line_length = cached_maximum_line_length;
// Checking if folder contains valid Godot 3 project.
- // Project cannot be converted 2 times
+ // Project should not be converted more than 1 times
{
String conventer_text = "; Project was converted by built-in tool to Godot 4.0";
@@ -1613,7 +1874,7 @@ int ProjectConverter3To4::convert() {
String project_godot_content = FileAccess::get_file_as_string("project.godot", &err);
ERR_FAIL_COND_V_MSG(err != OK, ERROR_CODE, "Failed to read content of \"project.godot\" file.");
- ERR_FAIL_COND_V_MSG(project_godot_content.find(conventer_text) != -1, ERROR_CODE, "Project already was converted with this tool.");
+ ERR_FAIL_COND_V_MSG(project_godot_content.contains(conventer_text), ERROR_CODE, "Project already was converted with this tool.");
Ref<FileAccess> file = FileAccess::open("project.godot", FileAccess::WRITE);
ERR_FAIL_COND_V_MSG(file.is_null(), ERROR_CODE, "Failed to open project.godot file.");
@@ -1628,11 +1889,19 @@ int ProjectConverter3To4::convert() {
// Check file by file
for (int i = 0; i < collected_files.size(); i++) {
String file_name = collected_files[i];
- Error err = OK;
- String file_content = FileAccess::get_file_as_string(file_name, &err);
- ERR_CONTINUE_MSG(err != OK, "Failed to read content of \"" + file_name + "\".");
- uint64_t hash_before = file_content.hash64();
- uint64_t file_size = file_content.size();
+ Vector<String> lines;
+ uint32_t ignored_lines = 0;
+ {
+ Ref<FileAccess> file = FileAccess::open(file_name, FileAccess::READ);
+ ERR_CONTINUE_MSG(file.is_null(), "Failed to read content of \"" + file_name + "\".");
+ while (!file->eof_reached()) {
+ String line = file->get_line();
+ lines.append(line);
+ }
+ }
+ String file_content_before = collect_string_from_vector(lines);
+ uint64_t hash_before = file_content_before.hash();
+ uint64_t file_size = file_content_before.size();
print_line("Trying to convert\t" + itos(i + 1) + "/" + itos(collected_files.size()) + " file - \"" + file_name.trim_prefix("res://") + "\" with size - " + itos(file_size / 1024) + " KB");
Vector<String> reason;
@@ -1640,94 +1909,106 @@ int ProjectConverter3To4::convert() {
uint64_t start_time = Time::get_singleton()->get_ticks_msec();
if (file_name.ends_with(".shader")) {
- DirAccess::remove_file_or_error(file_name);
+ DirAccess::remove_file_or_error(file_name.trim_prefix("res://"));
file_name = file_name.replace(".shader", ".gdshader");
}
- if (file_size < CONVERSION_MAX_FILE_SIZE) {
+ if (file_size < uint64_t(maximum_file_size)) {
// TSCN must be the same work exactly same as .gd file because it may contains builtin script
if (file_name.ends_with(".gd")) {
- rename_classes(file_content); // Using only specialized function
+ rename_classes(lines, reg_container); // Using only specialized function
- rename_common(enum_renames, file_content);
- rename_enums(file_content); // Require to additional rename
+ rename_common(enum_renames, reg_container.enum_regexes, lines);
+ rename_colors(lines, reg_container); // Require to additional rename
- rename_common(gdscript_function_renames, file_content);
- rename_gdscript_functions(file_content); // Require to additional rename
+ rename_common(gdscript_function_renames, reg_container.gdscript_function_regexes, lines);
+ rename_gdscript_functions(lines, reg_container, false); // Require to additional rename
- rename_common(project_settings_renames, file_content);
- rename_gdscript_keywords(file_content);
- rename_common(gdscript_properties_renames, file_content);
- rename_common(gdscript_signals_renames, file_content);
- rename_common(shaders_renames, file_content);
- rename_common(builtin_types_renames, file_content);
+ rename_common(project_settings_renames, reg_container.project_settings_regexes, lines);
+ rename_gdscript_keywords(lines, reg_container);
+ rename_common(gdscript_properties_renames, reg_container.gdscript_properties_regexes, lines);
+ rename_common(gdscript_signals_renames, reg_container.gdscript_signals_regexes, lines);
+ rename_common(shaders_renames, reg_container.shaders_regexes, lines);
+ rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines);
- custom_rename(file_content, "\\.shader", ".gdshader");
- custom_rename(file_content, "instance", "instantiate");
+ custom_rename(lines, "\\.shader", ".gdshader");
} else if (file_name.ends_with(".tscn")) {
- rename_classes(file_content); // Using only specialized function
+ rename_classes(lines, reg_container); // Using only specialized function
- rename_common(enum_renames, file_content);
- rename_enums(file_content); // Require to additional rename
+ rename_common(enum_renames, reg_container.enum_regexes, lines);
+ rename_colors(lines, reg_container); // Require to additional rename
- rename_common(gdscript_function_renames, file_content);
- rename_gdscript_functions(file_content); // Require to additional rename
+ rename_common(gdscript_function_renames, reg_container.gdscript_function_regexes, lines);
+ rename_gdscript_functions(lines, reg_container, true); // Require to additional rename
- rename_common(project_settings_renames, file_content);
- rename_gdscript_keywords(file_content);
- rename_common(gdscript_properties_renames, file_content);
- rename_common(gdscript_signals_renames, file_content);
- rename_common(shaders_renames, file_content);
- rename_common(builtin_types_renames, file_content);
+ rename_common(project_settings_renames, reg_container.project_settings_regexes, lines);
+ rename_gdscript_keywords(lines, reg_container);
+ rename_common(gdscript_properties_renames, reg_container.gdscript_properties_regexes, lines);
+ rename_common(gdscript_signals_renames, reg_container.gdscript_signals_regexes, lines);
+ rename_common(shaders_renames, reg_container.shaders_regexes, lines);
+ rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines);
- custom_rename(file_content, "\\.shader", ".gdshader");
+ custom_rename(lines, "\\.shader", ".gdshader");
} else if (file_name.ends_with(".cs")) { // TODO, C# should use different methods
- rename_classes(file_content); // Using only specialized function
- rename_common(csharp_function_renames, file_content);
- rename_common(builtin_types_renames, file_content);
- rename_common(csharp_properties_renames, file_content);
- rename_common(csharp_signals_renames, file_content);
- rename_csharp_functions(file_content);
- custom_rename(file_content, "public class ", "public partial class ");
+ rename_classes(lines, reg_container); // Using only specialized function
+ rename_common(csharp_function_renames, reg_container.csharp_function_regexes, lines);
+ rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines);
+ rename_common(csharp_properties_renames, reg_container.csharp_properties_regexes, lines);
+ rename_common(csharp_signals_renames, reg_container.csharp_signal_regexes, lines);
+ rename_csharp_functions(lines, reg_container);
+ rename_csharp_attributes(lines, reg_container);
+ custom_rename(lines, "public class ", "public partial class ");
} else if (file_name.ends_with(".gdshader") || file_name.ends_with(".shader")) {
- rename_common(shaders_renames, file_content);
+ rename_common(shaders_renames, reg_container.shaders_regexes, lines);
} else if (file_name.ends_with("tres")) {
- rename_classes(file_content); // Using only specialized function
+ rename_classes(lines, reg_container); // Using only specialized function
- rename_common(shaders_renames, file_content);
- rename_common(builtin_types_renames, file_content);
+ rename_common(shaders_renames, reg_container.shaders_regexes, lines);
+ rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines);
- custom_rename(file_content, "\\.shader", ".gdshader");
+ custom_rename(lines, "\\.shader", ".gdshader");
} else if (file_name.ends_with("project.godot")) {
- rename_common(project_settings_renames, file_content);
- rename_common(builtin_types_renames, file_content);
+ rename_common(project_settings_renames, reg_container.project_settings_regexes, lines);
+ rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines);
} else if (file_name.ends_with(".csproj")) {
// TODO
} else {
ERR_PRINT(file_name + " is not supported!");
continue;
}
+
+ for (String &line : lines) {
+ if (uint64_t(line.length()) > maximum_line_length) {
+ ignored_lines += 1;
+ }
+ }
} else {
- reason.append(" ERROR: File has exceeded the maximum size allowed - 500 KB");
+ reason.append(" ERROR: File has exceeded the maximum size allowed - " + itos(maximum_file_size / 1024) + " KB");
is_ignored = true;
}
uint64_t end_time = Time::get_singleton()->get_ticks_msec();
-
- if (!is_ignored) {
- uint64_t hash_after = file_content.hash64();
+ if (is_ignored) {
+ String end_message = " Checking file took " + itos(end_time - start_time) + " ms.";
+ print_line(end_message);
+ } else {
+ String file_content_after = collect_string_from_vector(lines);
+ uint64_t hash_after = file_content_after.hash64();
// Don't need to save file without any changes
// Save if this is a shader, because it was renamed
- if (hash_before != hash_after || file_name.find(".gdshader") != -1) {
+ if (hash_before != hash_after || file_name.ends_with(".gdshader")) {
converted_files++;
Ref<FileAccess> file = FileAccess::open(file_name, FileAccess::WRITE);
ERR_CONTINUE_MSG(file.is_null(), "Failed to open \"" + file_name + "\" to save data to file.");
- file->store_string(file_content);
+ file->store_string(file_content_after);
reason.append(" File was changed, conversion took " + itos(end_time - start_time) + " ms.");
} else {
reason.append(" File was not changed, checking took " + itos(end_time - start_time) + " ms.");
}
+ if (ignored_lines != 0) {
+ reason.append(" Ignored " + itos(ignored_lines) + " lines, because their length exceeds maximum allowed characters - " + itos(maximum_line_length));
+ }
}
for (int k = 0; k < reason.size(); k++) {
print_line(reason[k]);
@@ -1735,18 +2016,28 @@ int ProjectConverter3To4::convert() {
}
print_line("Conversion ended - all files(" + itos(collected_files.size()) + "), converted files(" + itos(converted_files) + "), not converted files(" + itos(collected_files.size() - converted_files) + ").");
+ uint64_t conversion_end_time = Time::get_singleton()->get_ticks_msec();
+ print_line("Conversion of all files took " + itos(conversion_end_time - conversion_start_time) + " ms.");
return 0;
};
// Function responsible for validating project conversion.
int ProjectConverter3To4::validate_conversion() {
print_line("Starting checking if project conversion can be done.");
+ uint64_t conversion_start_time = Time::get_singleton()->get_ticks_msec();
+
+ RegExContainer reg_container = RegExContainer();
+
+ int cached_maximum_line_length = maximum_line_length;
+ maximum_line_length = 10000; // Use only for tests bigger value, to not break them
ERR_FAIL_COND_V_MSG(!test_array_names(), ERROR_CODE, "Cannot start converting due to problems with data in arrays.");
- ERR_FAIL_COND_V_MSG(!test_conversion(), ERROR_CODE, "Cannot start converting due to problems with converting arrays.");
+ ERR_FAIL_COND_V_MSG(!test_conversion(reg_container), ERROR_CODE, "Cannot start converting due to problems with converting arrays.");
+
+ maximum_line_length = cached_maximum_line_length;
// Checking if folder contains valid Godot 3 project.
- // Project cannot be converted 2 times
+ // Project should not be converted more than 1 times
{
String conventer_text = "; Project was converted by built-in tool to Godot 4.0";
@@ -1756,7 +2047,7 @@ int ProjectConverter3To4::validate_conversion() {
String project_godot_content = FileAccess::get_file_as_string("project.godot", &err);
ERR_FAIL_COND_V_MSG(err != OK, ERROR_CODE, "Failed to read content of \"project.godot\" file.");
- ERR_FAIL_COND_V_MSG(project_godot_content.find(conventer_text) != -1, ERROR_CODE, "Project already was converted with this tool.");
+ ERR_FAIL_COND_V_MSG(project_godot_content.contains(conventer_text), ERROR_CODE, "Project already was converted with this tool.");
}
Vector<String> collected_files = check_for_files();
@@ -1766,7 +2057,8 @@ int ProjectConverter3To4::validate_conversion() {
// Check file by file
for (int i = 0; i < collected_files.size(); i++) {
String file_name = collected_files[i];
- Vector<String> file_content;
+ Vector<String> lines;
+ uint32_t ignored_lines = 0;
uint64_t file_size = 0;
{
Ref<FileAccess> file = FileAccess::open(file_name, FileAccess::READ);
@@ -1774,7 +2066,7 @@ int ProjectConverter3To4::validate_conversion() {
while (!file->eof_reached()) {
String line = file->get_line();
file_size += line.size();
- file_content.append(line);
+ lines.append(line);
}
}
print_line("Checking for conversion - " + itos(i + 1) + "/" + itos(collected_files.size()) + " file - \"" + file_name.trim_prefix("res://") + "\" with size - " + itos(file_size / 1024) + " KB");
@@ -1784,79 +2076,89 @@ int ProjectConverter3To4::validate_conversion() {
bool is_ignored = false;
uint64_t start_time = Time::get_singleton()->get_ticks_msec();
- if (file_name.ends_with(".sader")) {
+ if (file_name.ends_with(".shader")) {
reason.append("\tFile extension will be renamed from `shader` to `gdshader`.");
}
- if (file_size < CONVERSION_MAX_FILE_SIZE) {
+ if (file_size < uint64_t(maximum_file_size)) {
if (file_name.ends_with(".gd")) {
- changed_elements.append_array(check_for_rename_classes(file_content));
+ changed_elements.append_array(check_for_rename_classes(lines, reg_container));
- changed_elements.append_array(check_for_rename_common(enum_renames, file_content));
- changed_elements.append_array(check_for_rename_enums(file_content));
+ changed_elements.append_array(check_for_rename_common(enum_renames, reg_container.enum_regexes, lines));
+ changed_elements.append_array(check_for_rename_colors(lines, reg_container));
- changed_elements.append_array(check_for_rename_common(gdscript_function_renames, file_content));
- changed_elements.append_array(check_for_rename_gdscript_functions(file_content));
+ changed_elements.append_array(check_for_rename_common(gdscript_function_renames, reg_container.gdscript_function_regexes, lines));
+ changed_elements.append_array(check_for_rename_gdscript_functions(lines, reg_container, false));
- changed_elements.append_array(check_for_rename_common(project_settings_renames, file_content));
- changed_elements.append_array(check_for_rename_gdscript_keywords(file_content));
- changed_elements.append_array(check_for_rename_common(gdscript_properties_renames, file_content));
- changed_elements.append_array(check_for_rename_common(gdscript_signals_renames, file_content));
- changed_elements.append_array(check_for_rename_common(shaders_renames, file_content));
- changed_elements.append_array(check_for_rename_common(builtin_types_renames, file_content));
+ changed_elements.append_array(check_for_rename_common(project_settings_renames, reg_container.project_settings_regexes, lines));
+ changed_elements.append_array(check_for_rename_gdscript_keywords(lines, reg_container));
+ changed_elements.append_array(check_for_rename_common(gdscript_properties_renames, reg_container.gdscript_properties_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(gdscript_signals_renames, reg_container.gdscript_signals_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(shaders_renames, reg_container.shaders_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines));
- changed_elements.append_array(check_for_custom_rename(file_content, "instance", "instantiate"));
- changed_elements.append_array(check_for_custom_rename(file_content, "\\.shader", ".gdshader"));
+ changed_elements.append_array(check_for_custom_rename(lines, "\\.shader", ".gdshader"));
} else if (file_name.ends_with(".tscn")) {
- changed_elements.append_array(check_for_rename_classes(file_content));
+ changed_elements.append_array(check_for_rename_classes(lines, reg_container));
- changed_elements.append_array(check_for_rename_common(enum_renames, file_content));
- changed_elements.append_array(check_for_rename_enums(file_content));
+ changed_elements.append_array(check_for_rename_common(enum_renames, reg_container.enum_regexes, lines));
+ changed_elements.append_array(check_for_rename_colors(lines, reg_container));
- changed_elements.append_array(check_for_rename_common(gdscript_function_renames, file_content));
- changed_elements.append_array(check_for_rename_gdscript_functions(file_content));
+ changed_elements.append_array(check_for_rename_common(gdscript_function_renames, reg_container.gdscript_function_regexes, lines));
+ changed_elements.append_array(check_for_rename_gdscript_functions(lines, reg_container, true));
- changed_elements.append_array(check_for_rename_common(project_settings_renames, file_content));
- changed_elements.append_array(check_for_rename_gdscript_keywords(file_content));
- changed_elements.append_array(check_for_rename_common(gdscript_properties_renames, file_content));
- changed_elements.append_array(check_for_rename_common(gdscript_signals_renames, file_content));
- changed_elements.append_array(check_for_rename_common(shaders_renames, file_content));
- changed_elements.append_array(check_for_rename_common(builtin_types_renames, file_content));
+ changed_elements.append_array(check_for_rename_common(project_settings_renames, reg_container.project_settings_regexes, lines));
+ changed_elements.append_array(check_for_rename_gdscript_keywords(lines, reg_container));
+ changed_elements.append_array(check_for_rename_common(gdscript_properties_renames, reg_container.gdscript_properties_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(gdscript_signals_renames, reg_container.gdscript_signals_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(shaders_renames, reg_container.shaders_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines));
- changed_elements.append_array(check_for_custom_rename(file_content, "\\.shader", ".gdshader"));
+ changed_elements.append_array(check_for_custom_rename(lines, "\\.shader", ".gdshader"));
} else if (file_name.ends_with(".cs")) {
- changed_elements.append_array(check_for_rename_common(class_renames, file_content));
- changed_elements.append_array(check_for_rename_common(csharp_function_renames, file_content));
- changed_elements.append_array(check_for_rename_common(builtin_types_renames, file_content));
- changed_elements.append_array(check_for_rename_common(csharp_properties_renames, file_content));
- changed_elements.append_array(check_for_rename_common(csharp_signals_renames, file_content));
- changed_elements.append_array(check_for_rename_csharp_functions(file_content));
- changed_elements.append_array(check_for_custom_rename(file_content, "public class ", "public partial class "));
+ changed_elements.append_array(check_for_rename_classes(lines, reg_container));
+ changed_elements.append_array(check_for_rename_common(csharp_function_renames, reg_container.csharp_function_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(csharp_properties_renames, reg_container.csharp_properties_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(csharp_signals_renames, reg_container.csharp_signal_regexes, lines));
+ changed_elements.append_array(check_for_rename_csharp_functions(lines, reg_container));
+ changed_elements.append_array(check_for_rename_csharp_attributes(lines, reg_container));
+ changed_elements.append_array(check_for_custom_rename(lines, "public class ", "public partial class "));
} else if (file_name.ends_with(".gdshader") || file_name.ends_with(".shader")) {
- changed_elements.append_array(check_for_rename_common(shaders_renames, file_content));
+ changed_elements.append_array(check_for_rename_common(shaders_renames, reg_container.shaders_regexes, lines));
} else if (file_name.ends_with("tres")) {
- changed_elements.append_array(check_for_rename_classes(file_content));
+ changed_elements.append_array(check_for_rename_classes(lines, reg_container));
- changed_elements.append_array(check_for_rename_common(shaders_renames, file_content));
- changed_elements.append_array(check_for_rename_common(builtin_types_renames, file_content));
+ changed_elements.append_array(check_for_rename_common(shaders_renames, reg_container.shaders_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines));
- changed_elements.append_array(check_for_custom_rename(file_content, "\\.shader", ".gdshader"));
+ changed_elements.append_array(check_for_custom_rename(lines, "\\.shader", ".gdshader"));
} else if (file_name.ends_with("project.godot")) {
- changed_elements.append_array(check_for_rename_common(project_settings_renames, file_content));
- changed_elements.append_array(check_for_rename_common(builtin_types_renames, file_content));
+ changed_elements.append_array(check_for_rename_common(project_settings_renames, reg_container.project_settings_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines));
} else if (file_name.ends_with(".csproj")) {
// TODO
} else {
ERR_PRINT(file_name + " is not supported!");
continue;
}
+
+ for (String &line : lines) {
+ if (uint64_t(line.length()) > maximum_line_length) {
+ ignored_lines += 1;
+ }
+ }
} else {
- reason.append("\tERROR: File has exceeded the maximum size allowed - 500 KB");
+ reason.append("\tERROR: File has exceeded the maximum size allowed - " + itos(maximum_file_size / 1024) + " KB");
is_ignored = true;
}
uint64_t end_time = Time::get_singleton()->get_ticks_msec();
- print_line(" Checking file took " + itos(end_time - start_time) + " ms.");
+ String end_message = " Checking file took " + itos(end_time - start_time) + " ms.";
+ if (ignored_lines != 0) {
+ end_message += " Ignored " + itos(ignored_lines) + " lines, because their length exceeds maximum allowed characters - " + itos(maximum_line_length);
+ }
+ print_line(end_message);
for (int k = 0; k < reason.size(); k++) {
print_line(reason[k]);
@@ -1872,6 +2174,8 @@ int ProjectConverter3To4::validate_conversion() {
}
print_line("Checking for valid conversion ended - all files(" + itos(collected_files.size()) + "), files which would be converted(" + itos(converted_files) + "), files which would not be converted(" + itos(collected_files.size() - converted_files) + ").");
+ uint64_t conversion_end_time = Time::get_singleton()->get_ticks_msec();
+ print_line("Conversion of all files took " + itos(conversion_end_time - conversion_start_time) + " ms.");
return 0;
}
@@ -1898,14 +2202,14 @@ Vector<String> ProjectConverter3To4::check_for_files() {
continue;
}
if (dir.current_is_dir()) {
- directories_to_check.append(current_dir.plus_file(file_name) + "/");
+ directories_to_check.append(current_dir.path_join(file_name) + "/");
} else {
bool proper_extension = false;
if (file_name.ends_with(".gd") || file_name.ends_with(".shader") || file_name.ends_with(".tscn") || file_name.ends_with(".tres") || file_name.ends_with(".godot") || file_name.ends_with(".cs") || file_name.ends_with(".csproj"))
proper_extension = true;
if (proper_extension) {
- collected_files.append(current_dir.plus_file(file_name));
+ collected_files.append(current_dir.path_join(file_name));
}
}
file_name = dir.get_next();
@@ -1917,182 +2221,230 @@ Vector<String> ProjectConverter3To4::check_for_files() {
return collected_files;
}
-bool ProjectConverter3To4::test_conversion_single_additional(String name, String expected, void (ProjectConverter3To4::*func)(String &), String what) {
- String got = name;
- (this->*func)(got);
- if (expected != got) {
- ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got + "`");
+// Test expected results of gdscript
+bool ProjectConverter3To4::test_conversion_gdscript_builtin(String name, String expected, void (ProjectConverter3To4::*func)(Vector<String> &, const RegExContainer &, bool), String what, const RegExContainer &reg_container, bool builtin_script) {
+ Vector<String> got = name.split("\n");
+ (this->*func)(got, reg_container, builtin_script);
+ String got_str = collect_string_from_vector(got);
+ if (expected != got_str) {
+ ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got_str + "`");
+ return false;
+ }
+
+ return true;
+}
+
+bool ProjectConverter3To4::test_conversion_with_regex(String name, String expected, void (ProjectConverter3To4::*func)(Vector<String> &, const RegExContainer &), String what, const RegExContainer &reg_container) {
+ Vector<String> got = name.split("\n");
+ (this->*func)(got, reg_container);
+ String got_str = collect_string_from_vector(got);
+ if (expected != got_str) {
+ ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got_str + "`");
return false;
}
return true;
}
-bool ProjectConverter3To4::test_conversion_single_normal(String name, String expected, const char *array[][2], String what) {
- String got = name;
- rename_common(array, got);
- if (expected != got) {
- ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got + "`");
+bool ProjectConverter3To4::test_conversion_basic(String name, String expected, const char *array[][2], LocalVector<RegEx *> &regex_cache, String what) {
+ Vector<String> got = name.split("\n");
+ rename_common(array, regex_cache, got);
+ String got_str = collect_string_from_vector(got);
+ if (expected != got_str) {
+ ERR_PRINT("Failed to convert " + what + " `" + name + "` to `" + expected + "`, got instead `" + got_str + "`");
return false;
}
return true;
}
// Validate if conversions are proper
-bool ProjectConverter3To4::test_conversion() {
+bool ProjectConverter3To4::test_conversion(RegExContainer &reg_container) {
bool valid = true;
- valid = valid & test_conversion_single_normal("Spatial", "Node3D", class_renames, "class");
-
- valid = valid & test_conversion_single_normal("TYPE_REAL", "TYPE_FLOAT", enum_renames, "enum");
+ valid = valid & test_conversion_basic("TYPE_REAL", "TYPE_FLOAT", enum_renames, reg_container.enum_regexes, "enum");
- valid = valid & test_conversion_single_normal("can_instance", "can_instantiate", gdscript_function_renames, "gdscript function");
+ valid = valid & test_conversion_basic("can_instance", "can_instantiate", gdscript_function_renames, reg_container.gdscript_function_regexes, "gdscript function");
- valid = valid & test_conversion_single_normal("CanInstance", "CanInstantiate", csharp_function_renames, "csharp function");
+ valid = valid & test_conversion_basic("CanInstance", "CanInstantiate", csharp_function_renames, reg_container.csharp_function_regexes, "csharp function");
- valid = valid & test_conversion_single_normal("translation", "position", gdscript_properties_renames, "gdscript property");
+ valid = valid & test_conversion_basic("translation", "position", gdscript_properties_renames, reg_container.gdscript_properties_regexes, "gdscript property");
- valid = valid & test_conversion_single_normal("Translation", "Position", csharp_properties_renames, "csharp property");
+ valid = valid & test_conversion_basic("Translation", "Position", csharp_properties_renames, reg_container.csharp_properties_regexes, "csharp property");
- valid = valid & test_conversion_single_normal("NORMALMAP", "NORMAL_MAP", shaders_renames, "shader");
+ valid = valid & test_conversion_basic("NORMALMAP", "NORMAL_MAP", shaders_renames, reg_container.shaders_regexes, "shader");
- valid = valid & test_conversion_single_normal("text_entered", "text_submitted", gdscript_signals_renames, "gdscript signal");
+ valid = valid & test_conversion_basic("text_entered", "text_submitted", gdscript_signals_renames, reg_container.gdscript_signals_regexes, "gdscript signal");
- valid = valid & test_conversion_single_normal("TextEntered", "TextSubmitted", csharp_signals_renames, "csharp signal");
+ valid = valid & test_conversion_basic("TextEntered", "TextSubmitted", csharp_signals_renames, reg_container.csharp_signal_regexes, "csharp signal");
- valid = valid & test_conversion_single_normal("audio/channel_disable_threshold_db", "audio/buses/channel_disable_threshold_db", project_settings_renames, "project setting");
+ valid = valid & test_conversion_basic("audio/channel_disable_threshold_db", "audio/buses/channel_disable_threshold_db", project_settings_renames, reg_container.project_settings_regexes, "project setting");
- valid = valid & test_conversion_single_normal("Transform", "Transform3D", builtin_types_renames, "builtin type");
+ valid = valid & test_conversion_basic("Transform", "Transform3D", builtin_types_renames, reg_container.builtin_types_regexes, "builtin type");
// Custom Renames
- valid = valid & test_conversion_single_additional("(Connect(A,B,C,D,E,F,G) != OK):", "(Connect(A,new Callable(B,C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp");
- valid = valid & test_conversion_single_additional("(Disconnect(A,B,C) != OK):", "(Disconnect(A,new Callable(B,C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp");
- valid = valid & test_conversion_single_additional("(IsConnected(A,B,C) != OK):", "(IsConnected(A,new Callable(B,C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\"display/window/size/fullscreen\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("\tvar aa = roman(r.move_and_slide( a, b, c, d, e, f )) # Roman", "\tr.set_motion_velocity(a)\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tvar aa = roman(r.move_and_slide()) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("\tvar aa = roman(r.move_and_slide_with_snap( a, g, b, c, d, e, f )) # Roman", "\tr.set_motion_velocity(a)\n\t# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `g`\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tvar aa = roman(r.move_and_slide()) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("list_dir_begin( a , b )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("list_dir_begin( a )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("list_dir_begin( )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("sort_custom( a , b )", "sort_custom(Callable(a,b))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("func c(var a, var b)", "func c(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("draw_line(1, 2, 3, 4, 5)", "draw_line(1,2,3,4)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("\timage.lock()", "\tfalse # image.lock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("\timage.unlock()", "\tfalse # image.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("\troman.image.unlock()", "\tfalse # roman.image.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("\tmtx.lock()", "\tmtx.lock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("\tmutex.unlock()", "\tmutex.unlock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("\nonready", "\n@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("onready", "@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional(" onready", " onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\nexport", "\n@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\texport", "\t@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\texport_dialog", "\texport_dialog", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("export", "@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional(" export", " export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("tool", "@tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n tool", "\n tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\ntool", "\n\n@tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\nmaster func", "\n\n@rpc(any) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\npuppet func", "\n\n@rpc(auth) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\nremote func", "\n\n@rpc(any) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\nremotesync func", "\n\n@rpc(any,sync) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\nsync func", "\n\n@rpc(any,sync) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\npuppetsync func", "\n\n@rpc(auth,sync) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
- valid = valid & test_conversion_single_additional("\n\nmastersync func", "\n\n@rpc(any,sync) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword");
-
- valid = valid & test_conversion_single_additional("var size : Vector2 = Vector2() setget set_function , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function\n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("var size : Vector2 = Vector2() setget set_function , ", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("var size : Vector2 = Vector2() setget set_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("var size : Vector2 = Vector2() setget , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function \n set(mod_value):\n mod_value # TODOConverter40 Non existent set function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("get_node(@", "get_node(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("yield(this, \"timeout\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional(" Transform.xform(Vector3(a,b,c)) ", " Transform * Vector3(a,b,c) ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional(" Transform.xform_inv(Vector3(a,b,c)) ", " Vector3(a,b,c) * Transform ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("export(float) var lifetime = 3.0", "export var lifetime: float = 3.0", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro'", "export var _font_name = 'AnonymousPro' # (String, 'AnonymousPro', 'CourierPrime')", &ProjectConverter3To4::rename_gdscript_functions, "custom rename"); // TODO, this is only a workaround
- valid = valid & test_conversion_single_additional("export(PackedScene) var mob_scene", "export var mob_scene: PackedScene", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("var d = parse_json(roman(sfs))", "var test_json_conv = JSON.new()\ntest_json_conv.parse(roman(sfs))\nvar d = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("to_json( AA ) szon", "JSON.new().stringify( AA ) szon", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("s to_json", "s JSON.new().stringify", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("AF to_json2", "AF to_json2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("var rr = JSON.parse(a)", "var test_json_conv = JSON.new()\ntest_json_conv.parse(a)\nvar rr = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("empty()", "is_empty()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional(".empty", ".empty", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional(").roman(", ").roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("\t.roman(", "\tsuper.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional(" .roman(", " super.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional(".1", ".1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional(" .1", " .1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("'.'", "'.'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("'.a'", "'.a'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("\t._input(_event)", "\tsuper._input(_event)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("(start(A,B,C,D,E,F,G) != OK):", "(start(A,Callable(B,C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("(connect(A,B,C,D,E,F,G) != OK):", "(connect(A,Callable(B,C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("(connect(A,B,C) != OK):", "(connect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("disconnect(A,B,C) != OK):", "disconnect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("is_connected(A,B,C) != OK):", "is_connected(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("is_connected(A,B,C))", "is_connected(A,Callable(B,C)))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("func _init(p_x:int)->void:", "func _init(p_x:int):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("q_PackedDataContainer._iter_init(variable1)", "q_PackedDataContainer._iter_init(variable1)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("assert(speed < 20, str(randi()%10))", "assert(speed < 20) #,str(randi()%10))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("assert(speed < 2)", "assert(speed < 2)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("assert(false, \"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", "assert(false) #,\"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("create_from_image(aa, bb)", "create_from_image(aa) #,bb", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("q_ImageTexture.create_from_image(variable1, variable2)", "q_ImageTexture.create_from_image(variable1) #,variable2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("set_cell_item(a, b, c, d ,e) # AA", "set_cell_item( Vector3(a,b,c) ,d,e) # AA", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("set_cell_item(a, b)", "set_cell_item(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("get_cell_item_orientation(a, b,c)", "get_cell_item_orientation(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("get_cell_item(a, b,c)", "get_cell_item(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("map_to_world(a, b,c)", "map_to_world(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("PackedStringArray(req_godot).join('.')", "'.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("=PackedStringArray(req_godot).join('.')", "='.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional(" aa", " aa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("\taa", "\taa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("\t aa", "\taa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional(" \taa", " \taa", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("apply_force(position, impulse)", "apply_force(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
- valid = valid & test_conversion_single_additional("apply_impulse(position, impulse)", "apply_impulse(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename");
-
- valid = valid & test_conversion_single_additional("AAA Color.white AF", "AAA Color.WHITE AF", &ProjectConverter3To4::rename_enums, "custom rename");
+ valid = valid & test_conversion_with_regex("(Connect(A,B,C,D,E,F,G) != OK):", "(Connect(A,new Callable(B,C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp", reg_container);
+ valid = valid & test_conversion_with_regex("(Disconnect(A,B,C) != OK):", "(Disconnect(A,new Callable(B,C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename csharp", reg_container);
+ valid = valid & test_conversion_with_regex("(IsConnected(A,B,C) != OK):", "(IsConnected(A,new Callable(B,C)) != OK):", &ProjectConverter3To4::rename_csharp_functions, "custom rename", reg_container);
+
+ valid = valid & test_conversion_with_regex("[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
+ valid = valid & test_conversion_with_regex("[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
+ valid = valid & test_conversion_with_regex("[Sync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
+ valid = valid & test_conversion_with_regex("[Slave]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
+ valid = valid & test_conversion_with_regex("[Puppet]", "[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
+ valid = valid & test_conversion_with_regex("[PuppetSync]", "[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
+ valid = valid & test_conversion_with_regex("[Master]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
+ valid = valid & test_conversion_with_regex("[MasterSync]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
+
+ valid = valid & test_conversion_gdscript_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\"display/window/size/fullscreen\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("OS.window_fullscreen = Settings.fullscreen", "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", Settings.fullscreen)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true);
+ valid = valid & test_conversion_gdscript_builtin("OS.get_window_safe_area()", "DisplayServer.get_display_safe_area()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide( a, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide_with_snap( a, g, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\t# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `g`\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin("list_dir_begin( a , b )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("list_dir_begin( a )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("list_dir_begin( )", "list_dir_begin() # TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin("sort_custom( a , b )", "sort_custom(Callable(a,b))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin("func c(var a, var b)", "func c(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin("draw_line(1, 2, 3, 4, 5)", "draw_line(1,2,3,4)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin("\timage.lock()", "\tfalse # image.lock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("\timage.unlock()", "\tfalse # image.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("\troman.image.unlock()", "\tfalse # roman.image.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("\tmtx.lock()", "\tmtx.lock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("\tmutex.unlock()", "\tmutex.unlock()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_with_regex("extends CSGBox", "extends CSGBox3D", &ProjectConverter3To4::rename_classes, "classes", reg_container);
+ valid = valid & test_conversion_with_regex("CSGBox", "CSGBox3D", &ProjectConverter3To4::rename_classes, "classes", reg_container);
+ valid = valid & test_conversion_with_regex("Spatial", "Node3D", &ProjectConverter3To4::rename_classes, "classes", reg_container);
+ valid = valid & test_conversion_with_regex("Spatial.tscn", "Spatial.tscn", &ProjectConverter3To4::rename_classes, "classes", reg_container);
+ valid = valid & test_conversion_with_regex("Spatial.gd", "Spatial.gd", &ProjectConverter3To4::rename_classes, "classes", reg_container);
+ valid = valid & test_conversion_with_regex("Spatial.shader", "Spatial.shader", &ProjectConverter3To4::rename_classes, "classes", reg_container);
+ valid = valid & test_conversion_with_regex("Spatial.other", "Node3D.other", &ProjectConverter3To4::rename_classes, "classes", reg_container);
+
+ valid = valid & test_conversion_with_regex("\nonready", "\n@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid & test_conversion_with_regex("onready", "@onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid & test_conversion_with_regex(" onready", " onready", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid & test_conversion_with_regex("\nexport", "\n@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid & test_conversion_with_regex("\texport", "\t@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid & test_conversion_with_regex("\texport_dialog", "\texport_dialog", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid & test_conversion_with_regex("export", "@export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid & test_conversion_with_regex(" export", " export", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid & test_conversion_with_regex("tool", "@tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid & test_conversion_with_regex("\n tool", "\n tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid & test_conversion_with_regex("\n\ntool", "\n\n@tool", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid & test_conversion_with_regex("\n\nremote func", "\n\n@rpc(any_peer) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid & test_conversion_with_regex("\n\nremotesync func", "\n\n@rpc(any_peer, call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid & test_conversion_with_regex("\n\nsync func", "\n\n@rpc(any_peer, call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid & test_conversion_with_regex("\n\nslave func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid & test_conversion_with_regex("\n\npuppet func", "\n\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid & test_conversion_with_regex("\n\npuppetsync func", "\n\n@rpc(call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid & test_conversion_with_regex("\n\nmaster func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+ valid = valid & test_conversion_with_regex("\n\nmastersync func", "\n\nThe master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n@rpc(call_local) func", &ProjectConverter3To4::rename_gdscript_keywords, "gdscript keyword", reg_container);
+
+ valid = valid & test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget set_function , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function\n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget set_function , ", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget set_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Non existent get function \n set(mod_value):\n mod_value # TODOConverter40 Copy here content of set_function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("var size : Vector2 = Vector2() setget , get_function", "var size : Vector2 = Vector2() :\n get:\n return size # TODOConverter40 Copy here content of get_function \n set(mod_value):\n mod_value # TODOConverter40 Non existent set function", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin("get_node(@", "get_node(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin("yield(this, \"timeout\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("yield(this, \\\"timeout\\\")", "await this.timeout", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, true);
+
+ valid = valid & test_conversion_gdscript_builtin(" Transform.xform(Vector3(a,b,c)) ", " Transform * Vector3(a,b,c) ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin(" Transform.xform_inv(Vector3(a,b,c)) ", " Vector3(a,b,c) * Transform ", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin("export(float) var lifetime = 3.0", "export var lifetime: float = 3.0", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro'", "export var _font_name = 'AnonymousPro' # (String, 'AnonymousPro', 'CourierPrime')", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false); // TODO, this is only a workaround
+ valid = valid & test_conversion_gdscript_builtin("export(PackedScene) var mob_scene", "export var mob_scene: PackedScene", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin("var d = parse_json(roman(sfs))", "var test_json_conv = JSON.new()\ntest_json_conv.parse(roman(sfs))\nvar d = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin("to_json( AA ) szon", "JSON.new().stringify( AA ) szon", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("s to_json", "s JSON.new().stringify", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("AF to_json2", "AF to_json2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("var rr = JSON.parse(a)", "var test_json_conv = JSON.new()\ntest_json_conv.parse(a)\nvar rr = test_json_conv.get_data()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin("empty()", "is_empty()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin(".empty", ".empty", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin(").roman(", ").roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("\t.roman(", "\tsuper.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin(" .roman(", " super.roman(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin(".1", ".1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin(" .1", " .1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("'.'", "'.'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("'.a'", "'.a'", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("\t._input(_event)", "\tsuper._input(_event)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin("(connect(A,B,C) != OK):", "(connect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("(connect(A,B,C,D) != OK):", "(connect(A,Callable(B,C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("(connect(A,B,C,[D]) != OK):", "(connect(A,Callable(B,C).bind(D)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("(connect(A,B,C,[D,E]) != OK):", "(connect(A,Callable(B,C).bind(D,E)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("(connect(A,B,C,[D,E],F) != OK):", "(connect(A,Callable(B,C).bind(D,E),F) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("(connect(A,B,C,D,E) != OK):", "(connect(A,Callable(B,C).bind(D),E) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin("(start(A,B) != OK):", "(start(Callable(A,B)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("func start(A,B):", "func start(A,B):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("(start(A,B,C,D,E,F,G) != OK):", "(start(Callable(A,B).bind(C),D,E,F,G) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("disconnect(A,B,C) != OK):", "disconnect(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("is_connected(A,B,C) != OK):", "is_connected(A,Callable(B,C)) != OK):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("is_connected(A,B,C))", "is_connected(A,Callable(B,C)))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin("(tween_method(A,B,C,D,E).foo())", "(tween_method(Callable(A,B),C,D,E).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("(tween_method(A,B,C,D,E,[F,G]).foo())", "(tween_method(Callable(A,B).bind(F,G),C,D,E).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("(tween_callback(A,B).foo())", "(tween_callback(Callable(A,B)).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("(tween_callback(A,B,[C,D]).foo())", "(tween_callback(Callable(A,B).bind(C,D)).foo())", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin("func _init(", "func _init(", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("func _init(p_x:int)->void:", "func _init(p_x:int):", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("q_PackedDataContainer._iter_init(variable1)", "q_PackedDataContainer._iter_init(variable1)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin("assert(speed < 20, str(randi()%10))", "assert(speed < 20) #,str(randi()%10))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("assert(speed < 2)", "assert(speed < 2)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("assert(false, \"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", "assert(false) #,\"Missing type --\" + str(argument.type) + \"--, needs to be added to project\")", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin("create_from_image(aa, bb)", "create_from_image(aa) #,bb", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("q_ImageTexture.create_from_image(variable1, variable2)", "q_ImageTexture.create_from_image(variable1) #,variable2", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin("set_cell_item(a, b, c, d ,e) # AA", "set_cell_item( Vector3(a,b,c) ,d,e) # AA", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("set_cell_item(a, b)", "set_cell_item(a, b)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("get_cell_item_orientation(a, b,c)", "get_cell_item_orientation(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("get_cell_item(a, b,c)", "get_cell_item(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("map_to_world(a, b,c)", "map_to_world(Vector3i(a,b,c))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin("PackedStringArray(req_godot).join('.')", "'.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("=PackedStringArray(req_godot).join('.')", "='.'.join(PackedStringArray(req_godot))", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_gdscript_builtin("apply_force(position, impulse)", "apply_force(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("apply_impulse(position, impulse)", "apply_impulse(impulse, position)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("draw_rect(a,b,c,d,e).abc", "draw_rect(a,b,c,d).abc# e) TODOGODOT4 Antialiasing argument is missing", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("get_focus_owner()", "get_viewport().gui_get_focus_owner()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("button.pressed = 1", "button.button_pressed = 1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("button.pressed=1", "button.button_pressed=1", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid & test_conversion_gdscript_builtin("button.pressed SF", "button.pressed SF", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid & test_conversion_with_regex("AAA Color.white AF", "AAA Color.WHITE AF", &ProjectConverter3To4::rename_colors, "custom rename", reg_container);
// Custom rule conversion
{
String from = "instance";
String to = "instantiate";
String name = "AA.instance()";
- String got = "AA.instance()";
+ Vector<String> got = String("AA.instance()").split("\n");
String expected = "AA.instantiate()";
custom_rename(got, from, to);
- if (got != expected) {
- ERR_PRINT("Failed to convert custom rename `" + name + "` to `" + expected + "`, got instead `" + got + "`");
+ String got_str = collect_string_from_vector(got);
+ if (got_str != expected) {
+ ERR_PRINT("Failed to convert custom rename `" + name + "` to `" + expected + "`, got instead `" + got_str + "`");
}
- valid = valid & (got == expected);
+ valid = valid & (got_str == expected);
}
// get_object_of_execution
@@ -2123,6 +2475,15 @@ bool ProjectConverter3To4::test_conversion() {
}
valid = valid & (got == expected);
}
+{
+ String base = "var node = $world/ukraine/lviv.";
+ String expected = "$world/ukraine/lviv.";
+ String got = get_object_of_execution(base);
+ if (got != expected) {
+ ERR_PRINT("Failed to get proper data from get_object_of_execution `" + base + "` should return `" + expected + "`(" + itos(expected.size()) + "), got instead `" + got + "`(" + itos(got.size()) + ")");
+ }
+ valid = valid & (got == expected);
+}
}
// get_starting_space
{
@@ -2198,8 +2559,7 @@ bool ProjectConverter3To4::test_array_names() {
// Validate if all classes are valid
{
- int current_index = 0;
- while (class_renames[current_index][0]) {
+ for (unsigned int current_index = 0; class_renames[current_index][0]; current_index++) {
const String old_class = class_renames[current_index][0];
const String new_class = class_renames[current_index][1];
@@ -2214,84 +2574,65 @@ bool ProjectConverter3To4::test_array_names() {
ERR_PRINT(String("Class `") + new_class + "` doesn't exists in Godot 4.0, so cannot be used in conversion.");
valid = false; // This probably should be only a warning, but not 100% sure - this would need to be added to CI
}
- current_index++;
- }
- }
-
- // // TODO To be able to fully work, it needs https://github.com/godotengine/godot/pull/49053
- // // TODO this needs to be changed to hashset when available https://github.com/godotengine/godot-proposals/issues/867, to speedup searchng
- // {
- // OrderedHashMap<String, bool> all_functions;
-
- // List<StringName> classes_list;
- // ClassDB::get_class_list(&classes_list);
- // for (StringName &name_of_class : classes_list) {
- // List<MethodInfo> method_list;
- // ClassDB::get_method_list(name_of_class, &method_list, true);
- // for (MethodInfo &function_data : method_list) {
- // if (!all_functions.has(function_data.name)) {
- // all_functions.insert(function_data.name, false);
- // }
- // }
- // }
-
- // for (int type = Variant::Type::NIL + 1; type < Variant::Type::VARIANT_MAX; type++) {
- // List<MethodInfo> method_list;
- // Variant::get_method_list_by_type(&method_list, Variant::Type(type));
- // for (MethodInfo &function_data : method_list) {
- // if (!all_functions.has(function_data.name)) {
- // all_functions.insert(function_data.name, false);
- // }
- // }
- // }
-
- // int current_element = 0;
- // while (gdscript_function_renames[current_element][0] != nullptr) {
- // if (!all_functions.has(gdscript_function_renames[current_element][1])) {
- // ERR_PRINT(String("Missing gdscript function in pair (") + gdscript_function_renames[current_element][0] + " - ===> " + gdscript_function_renames[current_element][1] + " <===)");
- // valid = false;
- // }
- // // // DEBUG, disable below after tests
- // // if (all_functions.has(gdscript_function_renames[current_element][0])) {
- // // String used_in_classes = "";
- // //
- // // for (StringName &name_of_class : classes_list) {
- // // List<MethodInfo> method_list;
- // // ClassDB::get_method_list(name_of_class, &method_list, true);
- // // for (MethodInfo &function_data : method_list) {
- // // if (function_data.name == gdscript_function_renames[current_element][0]) {
- // // used_in_classes += String(name_of_class) + ", ";
- // // }
- // // }
- // // }
- // // for (int type = Variant::Type::NIL + 1; type < Variant::Type::VARIANT_MAX; type++) {
- // // List<MethodInfo> method_list;
- // // Variant::get_method_list_by_type(&method_list, Variant::Type(type));
- // // for (MethodInfo &function_data : method_list) {
- // // if (function_data.name == gdscript_function_renames[current_element][0]) {
- // // used_in_classes += Variant::get_type_name(Variant::Type(type)) + ", ";
- // // }
- // // }
- // // }
- // // used_in_classes = used_in_classes.trim_suffix(", ");
- // //
- // // WARN_PRINT(String("Godot contains function which will be renamed in pair ( ===> ") + gdscript_function_renames[current_element][0] + " <=== - " + gdscript_function_renames[current_element][1] + ") in class " + used_in_classes + " - check for possible invalid rule.");
- // // }
- // current_element++;
- // }
- // }
+ }
+ }
+
+ {
+ HashSet<String> all_functions;
+
+ // List of excluded functions from builtin types and global namespace, because currently it is not possible to get list of functions from them
+ // This will be available when https://github.com/godotengine/godot/pull/49053 or similar will be included into Godot
+ static const char *builtin_types_excluded_functions[] = { "dict_to_inst", "inst_to_dict", "bytes_to_var", "bytes_to_var_with_objects", "db_to_linear", "deg_to_rad", "linear_to_db", "rad_to_deg", "randf_range", "snapped", "str_to_var", "var_to_str", "var_to_bytes", "var_to_bytes_with_objects", "move_toward", "uri_encode", "uri_decode", "remove_at", "get_rotation_quaternion", "clamp", "grow_side", "is_absolute_path", "is_valid_int", "lerp", "to_ascii_buffer", "to_utf8_buffer", "to_utf32_buffer", "snapped", nullptr };
+ for (int current_index = 0; builtin_types_excluded_functions[current_index]; current_index++) {
+ all_functions.insert(builtin_types_excluded_functions[current_index]);
+ }
+
+ // for (int type = Variant::Type::NIL + 1; type < Variant::Type::VARIANT_MAX; type++) {
+ // List<MethodInfo> method_list;
+ // Variant::get_method_list_by_type(&method_list, Variant::Type(type));
+ // for (MethodInfo &function_data : method_list) {
+ // if (!all_functions.has(function_data.name)) {
+ // all_functions.insert(function_data.name);
+ // }
+ // }
+ // }
+
+ List<StringName> classes_list;
+ ClassDB::get_class_list(&classes_list);
+ for (StringName &name_of_class : classes_list) {
+ List<MethodInfo> method_list;
+ ClassDB::get_method_list(name_of_class, &method_list, true);
+ for (MethodInfo &function_data : method_list) {
+ if (!all_functions.has(function_data.name)) {
+ all_functions.insert(function_data.name);
+ }
+ }
+ }
+
+ int current_element = 0;
+ while (gdscript_function_renames[current_element][0] != nullptr) {
+ if (!all_functions.has(gdscript_function_renames[current_element][1])) {
+ ERR_PRINT(String("Missing gdscript function in pair (") + gdscript_function_renames[current_element][0] + " - ===> " + gdscript_function_renames[current_element][1] + " <===)");
+ valid = false;
+ }
+ current_element++;
+ }
+ }
+ if (!valid) {
+ ERR_PRINT("Found function which is used in converter, but cannot be found in Godot 4. Rename this element to new name or remove entire rule about it if is obsolete.");
+ }
valid = valid & test_single_array(enum_renames);
valid = valid & test_single_array(class_renames, true);
valid = valid & test_single_array(gdscript_function_renames, true);
valid = valid & test_single_array(csharp_function_renames, true);
- valid = valid & test_single_array(gdscript_properties_renames);
+ valid = valid & test_single_array(gdscript_properties_renames, true);
valid = valid & test_single_array(csharp_properties_renames);
- valid = valid & test_single_array(shaders_renames);
+ valid = valid & test_single_array(shaders_renames, true);
valid = valid & test_single_array(gdscript_signals_renames);
valid = valid & test_single_array(project_settings_renames);
valid = valid & test_single_array(builtin_types_renames);
- valid = valid & test_single_array(colors_renames);
+ valid = valid & test_single_array(color_renames);
return valid;
}
@@ -2300,10 +2641,9 @@ bool ProjectConverter3To4::test_array_names() {
// Also checks if in name contains spaces at the end or beginning
bool ProjectConverter3To4::test_single_array(const char *array[][2], bool ignore_second_check) {
bool valid = true;
- int current_index = 0;
Vector<String> names = Vector<String>();
- while (array[current_index][0]) {
+ for (unsigned int current_index = 0; array[current_index][0]; current_index++) {
if (String(array[current_index][0]).begins_with(" ") || String(array[current_index][0]).ends_with(" ")) {
{
ERR_PRINT(String("Entry \"") + array[current_index][0] + "\" ends or stars with space.");
@@ -2329,7 +2669,6 @@ bool ProjectConverter3To4::test_single_array(const char *array[][2], bool ignore
if (!ignore_second_check) {
names.append(array[current_index][1]);
}
- current_index++;
}
return valid;
};
@@ -2339,18 +2678,17 @@ bool ProjectConverter3To4::test_single_array(const char *array[][2], bool ignore
Vector<String> ProjectConverter3To4::parse_arguments(const String &line) {
Vector<String> parts;
int string_size = line.length();
- int current_index = 0;
int start_part = 0; // Index of beginning of start par
int parts_counter = 0;
char32_t previous_character = '\0';
bool is_inside_string = false; // if true, it ignore this 3 characters ( , ) inside string
if (line.count("(") != line.count(")")) {
- ERR_PRINT("Bug: substring should have equal number of open and close parenthess - `" + line + "`");
+ ERR_PRINT("Converter internal bug: substring should have equal number of open and close parenthess in line - `" + line + "`");
return parts;
}
- while (current_index < string_size) {
+ for (int current_index = 0; current_index < string_size; current_index++) {
char32_t character = line.get(current_index);
switch (character) {
case '(': {
@@ -2368,6 +2706,21 @@ Vector<String> ProjectConverter3To4::parse_arguments(const String &line) {
}
break;
};
+ case '[': {
+ parts_counter++;
+ if (parts_counter == 1 && !is_inside_string) {
+ start_part = current_index;
+ }
+ break;
+ };
+ case ']': {
+ parts_counter--;
+ if (parts_counter == 0 && !is_inside_string) {
+ parts.append(line.substr(start_part, current_index - start_part));
+ start_part = current_index;
+ }
+ break;
+ };
case ',': {
if (parts_counter == 1 && !is_inside_string) {
parts.append(line.substr(start_part + 1, current_index - start_part - 1));
@@ -2380,7 +2733,6 @@ Vector<String> ProjectConverter3To4::parse_arguments(const String &line) {
is_inside_string = !is_inside_string;
}
}
- current_index++;
previous_character = character;
}
@@ -2398,9 +2750,8 @@ Vector<String> ProjectConverter3To4::parse_arguments(const String &line) {
// Finds latest parenthess owned by function
// `function(abc(a,b),DD)):` finds this parenthess `function(abc(a,b),DD => ) <= ):`
int ProjectConverter3To4::get_end_parenthess(const String &line) const {
- int current_index = 0;
int current_state = 0;
- while (line.length() > current_index) {
+ for (int current_index = 0; line.length() > current_index; current_index++) {
char32_t character = line.get(current_index);
if (character == '(') {
current_state++;
@@ -2411,7 +2762,6 @@ int ProjectConverter3To4::get_end_parenthess(const String &line) const {
return current_index;
}
}
- current_index++;
}
return -1;
}
@@ -2474,1385 +2824,1049 @@ String ProjectConverter3To4::get_starting_space(const String &line) const {
// so it is `var roman = kieliszek.` and this function return `kieliszek.`
String ProjectConverter3To4::get_object_of_execution(const String &line) const {
int end = line.size() - 1; // Last one is \0
+ int variable_start = end - 1;
int start = end - 1;
+ bool is_possibly_nodepath = false;
+ bool is_valid_nodepath = false;
+
while (start >= 0) {
char32_t character = line[start];
- if ((character >= 'A' && character <= 'Z') || (character >= 'a' && character <= 'z') || character == '.' || character == '_') {
+ bool is_variable_char = (character >= 'A' && character <= 'Z') || (character >= 'a' && character <= 'z') || character == '.' || character == '_';
+ bool is_nodepath_start = character == '$';
+ bool is_nodepath_sep = character == '/';
+ if (is_variable_char || is_nodepath_start || is_nodepath_sep) {
if (start == 0) {
break;
+ } else if (is_nodepath_sep) {
+ // Freeze variable_start, try to fetch more chars since this might be node path literal
+ is_possibly_nodepath = true;
+ } else if (is_nodepath_start) {
+ // Found $, this is a node path literal
+ is_valid_nodepath = true;
+ break;
+ }
+ if (!is_possibly_nodepath) {
+ variable_start--;
}
start--;
continue;
} else {
- start++; // Found invalid character, needs to be ignored
+ // Abandon all hope, this is neither a variable nor a node path literal
+ variable_start++; // Found invalid character, needs to be ignored
break;
}
}
- return line.substr(start, (end - start));
+ if (is_valid_nodepath) {
+ variable_start = start;
+ }
+ return line.substr(variable_start, (end - variable_start));
}
-void ProjectConverter3To4::rename_enums(String &file_content) {
- int current_index = 0;
-
- // Rename colors
- if (file_content.find("Color.") != -1) {
- while (colors_renames[current_index][0]) {
- RegEx reg = RegEx(String("\\bColor.") + colors_renames[current_index][0] + "\\b");
- CRASH_COND(!reg.is_valid());
- file_content = reg.sub(file_content, String("Color.") + colors_renames[current_index][1], true);
- current_index++;
+void ProjectConverter3To4::rename_colors(Vector<String> &lines, const RegExContainer &reg_container) {
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ if (line.contains("Color.")) {
+ for (unsigned int current_index = 0; color_renames[current_index][0]; current_index++) {
+ line = reg_container.color_regexes[current_index]->sub(line, reg_container.color_renamed[current_index], true);
+ }
+ }
}
}
};
-Vector<String> ProjectConverter3To4::check_for_rename_enums(Vector<String> &file_content) {
- int current_index = 0;
-
- Vector<String> found_things;
+Vector<String> ProjectConverter3To4::check_for_rename_colors(Vector<String> &lines, const RegExContainer &reg_container) {
+ Vector<String> found_renames;
- // Rename colors
- if (file_content.find("Color.") != -1) {
- while (colors_renames[current_index][0]) {
- RegEx reg = RegEx(String("\\bColor.") + colors_renames[current_index][0] + "\\b");
- CRASH_COND(!reg.is_valid());
-
- int current_line = 1;
- for (String &line : file_content) {
- Array reg_match = reg.search_all(line);
- if (reg_match.size() > 0) {
- found_things.append(line_formatter(current_line, colors_renames[current_index][0], colors_renames[current_index][1], line));
+ int current_line = 1;
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ if (line.contains("Color.")) {
+ for (unsigned int current_index = 0; color_renames[current_index][0]; current_index++) {
+ TypedArray<RegExMatch> reg_match = reg_container.color_regexes[current_index]->search_all(line);
+ if (reg_match.size() > 0) {
+ found_renames.append(line_formatter(current_line, color_renames[current_index][0], color_renames[current_index][1], line));
+ }
}
- current_line++;
}
- current_index++;
}
+ current_line++;
}
- return found_things;
+ return found_renames;
}
-void ProjectConverter3To4::rename_classes(String &file_content) {
- int current_index = 0;
-
- // TODO Maybe it is better way to not rename gd, tscn and other files which are named are classes
- while (class_renames[current_index][0]) {
- // Begin renaming workaround `Resource.gd` -> `RefCounter.gd`
- RegEx reg_before = RegEx(String("\\b") + class_renames[current_index][0] + ".tscn\\b");
- CRASH_COND(!reg_before.is_valid());
- file_content = reg_before.sub(file_content, "TEMP_RENAMED_CLASS.tscn", true);
- RegEx reg_before2 = RegEx(String("\\b") + class_renames[current_index][0] + ".gd\\b");
- CRASH_COND(!reg_before2.is_valid());
- file_content = reg_before2.sub(file_content, "TEMP_RENAMED_CLASS.gd", true);
- RegEx reg_before3 = RegEx(String("\\b") + class_renames[current_index][0] + ".shader\\b");
- CRASH_COND(!reg_before3.is_valid());
- file_content = reg_before3.sub(file_content, "TEMP_RENAMED_CLASS.gd", true);
- // End
-
- RegEx reg = RegEx(String("\\b") + class_renames[current_index][0] + "\\b");
- CRASH_COND(!reg.is_valid());
- file_content = reg.sub(file_content, class_renames[current_index][1], true);
-
- // Begin renaming workaround `Resource.gd` -> `RefCounter.gd`
- RegEx reg_after = RegEx("\\bTEMP_RENAMED_CLASS.tscn\\b");
- CRASH_COND(!reg_after.is_valid());
- file_content = reg_after.sub(file_content, String(class_renames[current_index][0]) + ".tscn", true);
- RegEx reg_after2 = RegEx("\\bTEMP_RENAMED_CLASS.gd\\b");
- CRASH_COND(!reg_after2.is_valid());
- file_content = reg_after2.sub(file_content, String(class_renames[current_index][0]) + ".gd", true);
- RegEx reg_after3 = RegEx("\\bTEMP_RENAMED_CLASS.gd\\b");
- CRASH_COND(!reg_after3.is_valid());
- file_content = reg_after3.sub(file_content, String(class_renames[current_index][0]) + ".shader", true);
- // End
-
- current_index++;
- }
-
- // OS.get_ticks_msec -> Time.get_ticks_msec
- RegEx reg_time1 = RegEx("OS.get_ticks_msec");
- CRASH_COND(!reg_time1.is_valid());
- file_content = reg_time1.sub(file_content, "Time.get_ticks_msec", true);
- RegEx reg_time2 = RegEx("OS.get_ticks_usec");
- CRASH_COND(!reg_time2.is_valid());
- file_content = reg_time2.sub(file_content, "Time.get_ticks_usec", true);
-};
-
-Vector<String> ProjectConverter3To4::check_for_rename_classes(Vector<String> &file_content) {
- int current_index = 0;
-
- Vector<String> found_things;
-
- while (class_renames[current_index][0]) {
- RegEx reg_before = RegEx(String("\\b") + class_renames[current_index][0] + ".tscn\\b");
- CRASH_COND(!reg_before.is_valid());
- RegEx reg_before2 = RegEx(String("\\b") + class_renames[current_index][0] + ".gd\\b");
- CRASH_COND(!reg_before2.is_valid());
-
- RegEx reg = RegEx(String("\\b") + class_renames[current_index][0] + "\\b");
- CRASH_COND(!reg.is_valid());
+void ProjectConverter3To4::rename_classes(Vector<String> &lines, const RegExContainer &reg_container) {
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ for (unsigned int current_index = 0; class_renames[current_index][0]; current_index++) {
+ if (line.contains(class_renames[current_index][0])) {
+ bool found_ignored_items = false;
+ // Renaming Spatial.tscn to TEMP_RENAMED_CLASS.tscn
+ if (line.contains(String(class_renames[current_index][0]) + ".")) {
+ found_ignored_items = true;
+ line = reg_container.class_tscn_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.tscn", true);
+ line = reg_container.class_gd_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.gd", true);
+ line = reg_container.class_shader_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.shader", true);
+ }
- int current_line = 1;
- for (String &line : file_content) {
- line = reg_before.sub(line, "TEMP_RENAMED_CLASS.tscn", true);
- line = reg_before2.sub(line, "TEMP_RENAMED_CLASS.gd", true);
+ // Causal renaming Spatial -> Node3D
+ line = reg_container.class_regexes[current_index]->sub(line, class_renames[current_index][1], true);
- Array reg_match = reg.search_all(line);
- if (reg_match.size() > 0) {
- found_things.append(line_formatter(current_line, class_renames[current_index][0], class_renames[current_index][1], line));
+ // Restore Spatial.tscn from TEMP_RENAMED_CLASS.tscn
+ if (found_ignored_items) {
+ line = reg_container.class_temp_tscn.sub(line, reg_container.class_temp_tscn_renames[current_index], true);
+ line = reg_container.class_temp_gd.sub(line, reg_container.class_temp_gd_renames[current_index], true);
+ line = reg_container.class_temp_shader.sub(line, reg_container.class_temp_shader_renames[current_index], true);
+ }
+ }
}
- current_line++;
}
- current_index++;
}
+};
+
+Vector<String> ProjectConverter3To4::check_for_rename_classes(Vector<String> &lines, const RegExContainer &reg_container) {
+ Vector<String> found_renames;
- // TODO OS -> TIME
int current_line = 1;
- RegEx reg_time1 = RegEx("OS.get_ticks_msec");
- CRASH_COND(!reg_time1.is_valid());
- RegEx reg_time2 = RegEx("OS.get_ticks_usec");
- CRASH_COND(!reg_time2.is_valid());
- for (String &line : file_content) {
- String old = line;
- line = reg_time1.sub(line, "Time.get_ticks_msec", true);
- line = reg_time2.sub(line, "Time.get_ticks_usec", true);
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ for (unsigned int current_index = 0; class_renames[current_index][0]; current_index++) {
+ if (line.contains(class_renames[current_index][0])) {
+ String old_line = line;
+ bool found_ignored_items = false;
+ // Renaming Spatial.tscn to TEMP_RENAMED_CLASS.tscn
+ if (line.contains(String(class_renames[current_index][0]) + ".")) {
+ found_ignored_items = true;
+ line = reg_container.class_tscn_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.tscn", true);
+ line = reg_container.class_gd_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.gd", true);
+ line = reg_container.class_shader_regexes[current_index]->sub(line, "TEMP_RENAMED_CLASS.shader", true);
+ }
+
+ // Causal renaming Spatial -> Node3D
+ TypedArray<RegExMatch> reg_match = reg_container.class_regexes[current_index]->search_all(line);
+ if (reg_match.size() > 0) {
+ found_renames.append(line_formatter(current_line, class_renames[current_index][0], class_renames[current_index][1], old_line));
+ }
- if (old != line) {
- found_things.append(simple_line_formatter(current_line, old, line));
+ // Restore Spatial.tscn from TEMP_RENAMED_CLASS.tscn
+ if (found_ignored_items) {
+ line = reg_container.class_temp_tscn.sub(line, reg_container.class_temp_tscn_renames[current_index], true);
+ line = reg_container.class_temp_gd.sub(line, reg_container.class_temp_gd_renames[current_index], true);
+ line = reg_container.class_temp_shader.sub(line, reg_container.class_temp_shader_renames[current_index], true);
+ }
+ }
+ }
}
current_line++;
}
- return found_things;
+ return found_renames;
}
-void ProjectConverter3To4::rename_gdscript_functions(String &file_content) {
- // Custom renaming, each rule needs to be set manually
- // Don't forget to put validate each rule in validate_conversion function
- Vector<String> lines = file_content.split("\n");
+void ProjectConverter3To4::rename_gdscript_functions(Vector<String> &lines, const RegExContainer &reg_container, bool builtin) {
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ process_gdscript_line(line, reg_container, builtin);
+ }
+ }
+};
- RegEx reg_is_empty = RegEx("\\bempty\\(");
- RegEx reg_super = RegEx("([\t ])\\.([a-zA-Z_])");
- RegEx reg_json_to = RegEx("\\bto_json\\b");
- RegEx reg_json_parse = RegEx("([\t]{0,})([^\n]+)parse_json\\(([^\n]+)");
- RegEx reg_json_non_new = RegEx("([\t]{0,})([^\n]+)JSON\\.parse\\(([^\n]+)");
- RegEx reg_export = RegEx("export\\(([a-zA-Z0-9_]+)\\)[ ]+var[ ]+([a-zA-Z0-9_]+)");
- RegEx reg_export_advanced = RegEx("export\\(([^)^\n]+)\\)[ ]+var[ ]+([a-zA-Z0-9_]+)([^\n]+)");
- RegEx reg_setget_setget = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+([a-zA-Z0-9_]+)[ \t]*,[ \t]*([a-zA-Z0-9_]+)");
- RegEx reg_setget_set = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+([a-zA-Z0-9_]+)[ \t]*[,]*[^a-z^A-Z^0-9^_]*$");
- RegEx reg_setget_get = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+,[ \t]*([a-zA-Z0-9_]+)[ \t]*$");
- RegEx reg_join = RegEx("([\\(\\)a-zA-Z0-9_]+)\\.join\\(([^\n^\\)]+)\\)");
- RegEx reg_mixed_tab_space = RegEx("([\t]+)([ ]+)");
- RegEx reg_image_lock = RegEx("([a-zA-Z0-9_\\.]+)\\.lock\\(\\)");
- RegEx reg_image_unlock = RegEx("([a-zA-Z0-9_\\.]+)\\.unlock\\(\\)");
- RegEx reg_os_fullscreen = RegEx("OS.window_fullscreen[= ]+([^#^\n]+)");
+Vector<String> ProjectConverter3To4::check_for_rename_gdscript_functions(Vector<String> &lines, const RegExContainer &reg_container, bool builtin) {
+ int current_line = 1;
- CRASH_COND(!reg_is_empty.is_valid());
- CRASH_COND(!reg_super.is_valid());
- CRASH_COND(!reg_json_to.is_valid());
- CRASH_COND(!reg_json_parse.is_valid());
- CRASH_COND(!reg_json_non_new.is_valid());
- CRASH_COND(!reg_export.is_valid());
- CRASH_COND(!reg_export_advanced.is_valid());
- CRASH_COND(!reg_setget_setget.is_valid());
- CRASH_COND(!reg_setget_set.is_valid());
- CRASH_COND(!reg_setget_get.is_valid());
- CRASH_COND(!reg_join.is_valid());
- CRASH_COND(!reg_mixed_tab_space.is_valid());
- CRASH_COND(!reg_image_lock.is_valid());
- CRASH_COND(!reg_image_unlock.is_valid());
- CRASH_COND(!reg_os_fullscreen.is_valid());
+ Vector<String> found_renames;
for (String &line : lines) {
- if (line.find("mtx") == -1 && line.find("mutex") == -1 && line.find("Mutex") == -1) {
- line = reg_image_lock.sub(line, "false # $1.lock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", true);
- line = reg_image_unlock.sub(line, "false # $1.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", true);
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ String old_line = line;
+ process_gdscript_line(line, reg_container, builtin);
+ if (old_line != line) {
+ found_renames.append(simple_line_formatter(current_line, old_line, line));
+ }
}
+ }
+
+ return found_renames;
+}
- // Mixed use of spaces and tabs - tabs as first - TODO, this probably is problem problem, but not sure
- line = reg_mixed_tab_space.sub(line, "$1", true);
+// TODO, this function should run only on all .gd files and also on lines in tscn files which
+void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContainer &reg_container, bool builtin) {
+ // In this and other functions, reg.sub are used only after checking line with str.contains function which is sometimes few times faster with bigger line lengths
- // PackedStringArray(req_godot).join('.') -> '.'.join(PackedStringArray(req_godot)) PoolStringArray
- line = reg_join.sub(line, "$2.join($1)", true);
+ if ((line.contains(".lock") || line.contains(".unlock")) && !line.contains("mtx") && !line.contains("mutex") && !line.contains("Mutex")) {
+ line = reg_container.reg_image_lock.sub(line, "false # $1.lock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", true);
+ line = reg_container.reg_image_unlock.sub(line, "false # $1.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", true);
+ }
- // -- empty() -> is_empty() Pool*Array
- line = reg_is_empty.sub(line, "is_empty(", true);
+ // PackedStringArray(req_godot).join('.') -> '.'.join(PackedStringArray(req_godot)) PoolStringArray
+ if (line.contains(".join")) {
+ line = reg_container.reg_join.sub(line, "$2.join($1)", true);
+ }
- // -- \t.func() -> \tsuper.func() Object
- line = reg_super.sub(line, "$1super.$2", true); // TODO, not sure if possible, but for now this brake String text e.g. "Choosen .gitignore" -> "Choosen super.gitignore"
+ // -- empty() -> is_empty() Pool*Array
+ if (line.contains("empty")) {
+ line = reg_container.reg_is_empty.sub(line, "is_empty(", true);
+ }
- // -- JSON.parse(a) -> JSON.new().parse(a) etc. JSON
- line = reg_json_non_new.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true);
+ // -- \t.func() -> \tsuper.func() Object
+ if (line.contains("(") && line.contains(".")) {
+ line = reg_container.reg_super.sub(line, "$1super.$2", true); // TODO, not sure if possible, but for now this broke String text e.g. "Choosen .gitignore" -> "Choosen super.gitignore"
+ }
- // -- to_json(a) -> JSON.new().stringify(a) Object
- line = reg_json_to.sub(line, "JSON.new().stringify", true);
+ // -- JSON.parse(a) -> JSON.new().parse(a) etc. JSON
+ if (line.contains("parse")) {
+ line = reg_container.reg_json_non_new.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true);
+ }
- // -- parse_json(a) -> JSON.get_data() etc. Object
- line = reg_json_parse.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true);
+ // -- to_json(a) -> JSON.new().stringify(a) Object
+ if (line.contains("to_json")) {
+ line = reg_container.reg_json_to.sub(line, "JSON.new().stringify", true);
+ }
+ // -- parse_json(a) -> JSON.get_data() etc. Object
+ if (line.contains("parse_json")) {
+ line = reg_container.reg_json_parse.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true);
+ }
- // -- get_node(@ -> get_node( Node
+ // -- get_node(@ -> get_node( Node
+ if (line.contains("get_node")) {
line = line.replace("get_node(@", "get_node(");
+ }
- // export(float) var lifetime = 3.0 -> export var lifetime: float = 3.0 GDScript
- line = reg_export.sub(line, "export var $2: $1");
+ // export(float) var lifetime = 3.0 -> export var lifetime: float = 3.0 GDScript
+ if (line.contains("export")) {
+ line = reg_container.reg_export.sub(line, "export var $2: $1");
+ }
- // export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro' -> export var _font_name = 'AnonymousPro' #(String, 'AnonymousPro', 'CourierPrime') GDScript
- line = reg_export_advanced.sub(line, "export var $2$3 # ($1)");
+ // export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro' -> export var _font_name = 'AnonymousPro' #(String, 'AnonymousPro', 'CourierPrime') GDScript
+ if (line.contains("export")) {
+ line = reg_container.reg_export_advanced.sub(line, "export var $2$3 # ($1)");
+ }
- // Setget Setget
- line = reg_setget_setget.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $4\n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true);
+ // Setget Setget
+ if (line.contains("setget")) {
+ line = reg_container.reg_setget_setget.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $4\n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true);
+ }
- // Setget set
- line = reg_setget_set.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Non existent get function \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true);
+ // Setget set
+ if (line.contains("setget")) {
+ line = reg_container.reg_setget_set.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Non existent get function \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true);
+ }
- // Setget get
- line = reg_setget_get.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $3 \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Non existent set function", true);
+ // Setget get
+ if (line.contains("setget")) {
+ line = reg_container.reg_setget_get.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $3 \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Non existent set function", true);
+ }
- // OS.window_fullscreen = true -> ProjectSettings.set("display/window/size/fullscreen",true)
- line = reg_os_fullscreen.sub(line, "ProjectSettings.set(\"display/window/size/fullscreen\", $1)", true);
+ // OS.window_fullscreen = true -> ProjectSettings.set("display/window/size/fullscreen",true)
+ if (line.contains("window_fullscreen")) {
+ if (builtin) {
+ line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\\\"display/window/size/fullscreen\\\", $1)", true);
+ } else {
+ line = reg_container.reg_os_fullscreen.sub(line, "ProjectSettings.set(\"display/window/size/fullscreen\", $1)", true);
+ }
+ }
- // -- r.move_and_slide( a, b, c, d, e ) -> r.set_motion_velocity(a) ... r.move_and_slide() KinematicBody
- if (line.find("move_and_slide(") != -1) {
- int start = line.find("move_and_slide(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- String base_obj = get_object_of_execution(line.substr(0, start));
- String starting_space = get_starting_space(line);
+ // Instantiate
+ if (line.contains("instance")) {
+ line = reg_container.reg_instantiate.sub(line, ".instantiate($1)", true);
+ }
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() >= 1) {
- String line_new;
+ // -- r.move_and_slide( a, b, c, d, e ) -> r.set_velocity(a) ... r.move_and_slide() KinematicBody
+ if (line.contains(("move_and_slide("))) {
+ int start = line.find("move_and_slide(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ String base_obj = get_object_of_execution(line.substr(0, start));
+ String starting_space = get_starting_space(line);
- // motion_velocity
- line_new += starting_space + base_obj + "set_motion_velocity(" + parts[0] + ")\n";
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() >= 1) {
+ String line_new;
- // up_direction
- if (parts.size() >= 2) {
- line_new += starting_space + base_obj + "set_up_direction(" + parts[1] + ")\n";
- }
+ // motion_velocity
+ line_new += starting_space + base_obj + "set_velocity(" + parts[0] + ")\n";
- // stop_on_slope
- if (parts.size() >= 3) {
- line_new += starting_space + base_obj + "set_floor_stop_on_slope_enabled(" + parts[2] + ")\n";
- }
+ // up_direction
+ if (parts.size() >= 2) {
+ line_new += starting_space + base_obj + "set_up_direction(" + parts[1] + ")\n";
+ }
- // max_slides
- if (parts.size() >= 4) {
- line_new += starting_space + base_obj + "set_max_slides(" + parts[3] + ")\n";
- }
+ // stop_on_slope
+ if (parts.size() >= 3) {
+ line_new += starting_space + base_obj + "set_floor_stop_on_slope_enabled(" + parts[2] + ")\n";
+ }
- // floor_max_angle
- if (parts.size() >= 5) {
- line_new += starting_space + base_obj + "set_floor_max_angle(" + parts[4] + ")\n";
- }
+ // max_slides
+ if (parts.size() >= 4) {
+ line_new += starting_space + base_obj + "set_max_slides(" + parts[3] + ")\n";
+ }
- // infiinite_interia
- if (parts.size() >= 6) {
- line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[5] + "`\n";
- }
+ // floor_max_angle
+ if (parts.size() >= 5) {
+ line_new += starting_space + base_obj + "set_floor_max_angle(" + parts[4] + ")\n";
+ }
- line = line_new + line.substr(0, start) + "move_and_slide()" + line.substr(end + start);
+ // infiinite_interia
+ if (parts.size() >= 6) {
+ line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[5] + "`\n";
}
+
+ line_new += starting_space + base_obj + "move_and_slide()\n";
+ line = line_new + line.substr(0, start) + "velocity" + line.substr(end + start);
}
}
+ }
- // -- r.move_and_slide_with_snap( a, b, c, d, e ) -> r.set_motion_velocity(a) ... r.move_and_slide() KinematicBody
- if (line.find("move_and_slide_with_snap(") != -1) {
- int start = line.find("move_and_slide_with_snap(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- String base_obj = get_object_of_execution(line.substr(0, start));
- String starting_space = get_starting_space(line);
-
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() >= 1) {
- String line_new;
+ // -- r.move_and_slide_with_snap( a, b, c, d, e ) -> r.set_velocity(a) ... r.move_and_slide() KinematicBody
+ if (line.contains("move_and_slide_with_snap(")) {
+ int start = line.find("move_and_slide_with_snap(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ String base_obj = get_object_of_execution(line.substr(0, start));
+ String starting_space = get_starting_space(line);
- // motion_velocity
- line_new += starting_space + base_obj + "set_motion_velocity(" + parts[0] + ")\n";
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() >= 1) {
+ String line_new;
- // snap
- if (parts.size() >= 2) {
- line_new += starting_space + "# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `" + parts[1] + "`\n";
- }
+ // motion_velocity
+ line_new += starting_space + base_obj + "set_velocity(" + parts[0] + ")\n";
- // up_direction
- if (parts.size() >= 3) {
- line_new += starting_space + base_obj + "set_up_direction(" + parts[2] + ")\n";
- }
+ // snap
+ if (parts.size() >= 2) {
+ line_new += starting_space + "# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `" + parts[1] + "`\n";
+ }
- // stop_on_slope
- if (parts.size() >= 4) {
- line_new += starting_space + base_obj + "set_floor_stop_on_slope_enabled(" + parts[3] + ")\n";
- }
+ // up_direction
+ if (parts.size() >= 3) {
+ line_new += starting_space + base_obj + "set_up_direction(" + parts[2] + ")\n";
+ }
- // max_slides
- if (parts.size() >= 5) {
- line_new += starting_space + base_obj + "set_max_slides(" + parts[4] + ")\n";
- }
+ // stop_on_slope
+ if (parts.size() >= 4) {
+ line_new += starting_space + base_obj + "set_floor_stop_on_slope_enabled(" + parts[3] + ")\n";
+ }
- // floor_max_angle
- if (parts.size() >= 6) {
- line_new += starting_space + base_obj + "set_floor_max_angle(" + parts[5] + ")\n";
- }
+ // max_slides
+ if (parts.size() >= 5) {
+ line_new += starting_space + base_obj + "set_max_slides(" + parts[4] + ")\n";
+ }
- // infiinite_interia
- if (parts.size() >= 7) {
- line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[6] + "`\n";
- }
+ // floor_max_angle
+ if (parts.size() >= 6) {
+ line_new += starting_space + base_obj + "set_floor_max_angle(" + parts[5] + ")\n";
+ }
- line = line_new + line.substr(0, start) + "move_and_slide()" + line.substr(end + start);
+ // infiinite_interia
+ if (parts.size() >= 7) {
+ line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[6] + "`\n";
}
+
+ line_new += starting_space + base_obj + "move_and_slide()\n";
+ line = line_new + line.substr(0, start) + "velocity" + line.substr(end + start); // move_and_slide used to return velocity
}
}
+ }
- // -- sort_custom( a , b ) -> sort_custom(Callable( a , b )) Object
- if (line.find("sort_custom(") != -1) {
- int start = line.find("sort_custom(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 2) {
- line = line.substr(0, start) + "sort_custom(Callable(" + parts[0] + "," + parts[1] + "))" + line.substr(end + start);
- }
+ // -- sort_custom( a , b ) -> sort_custom(Callable( a , b )) Object
+ if (line.contains("sort_custom(")) {
+ int start = line.find("sort_custom(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 2) {
+ line = line.substr(0, start) + "sort_custom(Callable(" + parts[0] + "," + parts[1] + "))" + line.substr(end + start);
}
}
+ }
- // -- list_dir_begin( ) -> list_dir_begin() Object
- if (line.find("list_dir_begin(") != -1) {
- int start = line.find("list_dir_begin(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- line = line.substr(0, start) + "list_dir_begin() " + line.substr(end + start) + "# TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547";
- }
+ // -- list_dir_begin( ) -> list_dir_begin() Object
+ if (line.contains("list_dir_begin(")) {
+ int start = line.find("list_dir_begin(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ line = line.substr(0, start) + "list_dir_begin() " + line.substr(end + start) + "# TODOGODOT4 fill missing arguments https://github.com/godotengine/godot/pull/40547";
}
+ }
- // -- draw_line(1,2,3,4,5) -> draw_line(1,2,3,4) CanvasItem
- if (line.find("draw_line(") != -1) {
- int start = line.find("draw_line(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 5) {
- line = line.substr(0, start) + "draw_line(" + parts[0] + "," + parts[1] + "," + parts[2] + "," + parts[3] + ")" + line.substr(end + start);
- }
+ // -- draw_line(1,2,3,4,5) -> draw_line(1,2,3,4) CanvasItem
+ if (line.contains("draw_line(")) {
+ int start = line.find("draw_line(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 5) {
+ line = line.substr(0, start) + "draw_line(" + parts[0] + "," + parts[1] + "," + parts[2] + "," + parts[3] + ")" + line.substr(end + start);
}
}
+ }
- // -- func c(var a, var b) -> func c(a, b)
- if (line.find("func ") != -1 && line.find("var ") != -1) {
- int start = line.find("func ");
- start = line.substr(start).find("(") + start;
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
-
- String start_string = line.substr(0, start) + "(";
- for (int i = 0; i < parts.size(); i++) {
- start_string += parts[i].strip_edges().trim_prefix("var ");
- if (i != parts.size() - 1) {
- start_string += ", ";
- }
+ // -- func c(var a, var b) -> func c(a, b)
+ if (line.contains("func ") && line.contains("var ")) {
+ int start = line.find("func ");
+ start = line.substr(start).find("(") + start;
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+
+ String start_string = line.substr(0, start) + "(";
+ for (int i = 0; i < parts.size(); i++) {
+ start_string += parts[i].strip_edges().trim_prefix("var ");
+ if (i != parts.size() - 1) {
+ start_string += ", ";
}
- line = start_string + ")" + line.substr(end + start);
}
+ line = start_string + ")" + line.substr(end + start);
}
+ }
- // -- yield(this, \"timeout\") -> await this.timeout GDScript
- if (line.find("yield(") != -1) {
- int start = line.find("yield(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 2) {
+ // -- yield(this, \"timeout\") -> await this.timeout GDScript
+ if (line.contains("yield(")) {
+ int start = line.find("yield(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 2) {
+ if (builtin) {
+ line = line.substr(0, start) + "await " + parts[0] + "." + parts[1].replace("\\\"", "").replace("\\'", "").replace(" ", "") + line.substr(end + start);
+ } else {
line = line.substr(0, start) + "await " + parts[0] + "." + parts[1].replace("\"", "").replace("\'", "").replace(" ", "") + line.substr(end + start);
}
}
}
+ }
- // -- parse_json( AA ) -> TODO Object
- if (line.find("parse_json(") != -1) {
- int start = line.find("parse_json(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- line = line.substr(0, start) + "JSON.new().stringify(" + connect_arguments(parts, 0) + ")" + line.substr(end + start);
+ // -- parse_json( AA ) -> TODO Object
+ if (line.contains("parse_json(")) {
+ int start = line.find("parse_json(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ line = line.substr(0, start) + "JSON.new().stringify(" + connect_arguments(parts, 0) + ")" + line.substr(end + start);
+ }
+ }
+
+ // -- .xform(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform
+ if (line.contains(".xform(")) {
+ int start = line.find(".xform(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 1) {
+ line = line.substr(0, start) + " * " + parts[0] + line.substr(end + start);
}
}
+ }
- // -- .xform(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform
- if (line.find(".xform(") != -1) {
- int start = line.find(".xform(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
+ // -- .xform_inv(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform
+ if (line.contains(".xform_inv(")) {
+ int start = line.find(".xform_inv(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ String object_exec = get_object_of_execution(line.substr(0, start));
+ if (line.contains(object_exec + ".xform")) {
+ int start2 = line.find(object_exec + ".xform");
Vector<String> parts = parse_arguments(line.substr(start, end));
if (parts.size() == 1) {
- line = line.substr(0, start) + " * " + parts[0] + line.substr(end + start);
+ line = line.substr(0, start2) + parts[0] + " * " + object_exec + line.substr(end + start);
}
}
}
+ }
- // -- .xform_inv(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform
- if (line.find(".xform_inv(") != -1) {
- int start = line.find(".xform_inv(");
+ // -- "(connect(A,B,C,D,E) != OK):", "(connect(A,Callable(B,C).bind(D),E) Object
+ if (line.contains("connect(")) {
+ int start = line.find("connect(");
+ // Protection from disconnect
+ if (start == 0 || line.get(start - 1) != 's') {
int end = get_end_parenthess(line.substr(start)) + 1;
if (end > -1) {
- String object_exec = get_object_of_execution(line.substr(0, start));
- if (line.find(object_exec + ".xform") != -1) {
- int start2 = line.find(object_exec + ".xform");
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 1) {
- line = line.substr(0, start2) + parts[0] + " * " + object_exec + line.substr(end + start);
- }
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 3) {
+ line = line.substr(0, start) + "connect(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
+ } else if (parts.size() >= 4) {
+ line = line.substr(0, start) + "connect(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + ").bind(" + parts[3].lstrip("[").rstrip("]") + ")" + connect_arguments(parts, 4) + ")" + line.substr(end + start);
}
}
}
-
- // -- connect(,,,things) -> connect(,Callable(,),things) Object
- if (line.find("connect(") != -1) {
- int start = line.find("connect(");
- // Protection from disconnect
- if (start == 0 || line.get(start - 1) != 's') {
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() >= 3) {
- line = line.substr(0, start) + "connect(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start);
- }
- }
+ }
+ // -- disconnect(a,b,c) -> disconnect(a,Callable(b,c)) Object
+ if (line.contains("disconnect(")) {
+ int start = line.find("disconnect(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 3) {
+ line = line.substr(0, start) + "disconnect(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
}
}
- // -- disconnect(a,b,c) -> disconnect(a,Callable(b,c)) Object
- if (line.find("disconnect(") != -1) {
- int start = line.find("disconnect(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 3) {
- line = line.substr(0, start) + "disconnect(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
- }
+ }
+ // -- is_connected(a,b,c) -> is_connected(a,Callable(b,c)) Object
+ if (line.contains("is_connected(")) {
+ int start = line.find("is_connected(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 3) {
+ line = line.substr(0, start) + "is_connected(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
}
}
- // -- is_connected(a,b,c) -> is_connected(a,Callable(b,c)) Object
- if (line.find("is_connected(") != -1) {
- int start = line.find("is_connected(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 3) {
- line = line.substr(0, start) + "is_connected(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
- }
+ }
+ // -- "(tween_method(A,B,C,D,E) != OK):", "(tween_method(Callable(A,B),C,D,E) Object
+ // -- "(tween_method(A,B,C,D,E,[F,G]) != OK):", "(tween_method(Callable(A,B).bind(F,G),C,D,E) Object
+ if (line.contains("tween_method(")) {
+ int start = line.find("tween_method(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 5) {
+ line = line.substr(0, start) + "tween_method(Callable(" + parts[0] + "," + parts[1] + ")," + parts[2] + "," + parts[3] + "," + parts[4] + ")" + line.substr(end + start);
+ } else if (parts.size() >= 6) {
+ line = line.substr(0, start) + "tween_method(Callable(" + parts[0] + "," + parts[1] + ").bind(" + connect_arguments(parts, 5).substr(1).lstrip("[").rstrip("]") + ")," + parts[2] + "," + parts[3] + "," + parts[4] + ")" + line.substr(end + start);
}
}
- // -- start(a,b,c) -> start(a,Callable(b,c)) Thread
- if (line.find("start(") != -1) {
- int start = line.find("start(");
- int end = get_end_parenthess(line.substr(start)) + 1;
+ }
+ // -- "(tween_callback(A,B,[C,D]) != OK):", "(connect(Callable(A,B).bind(C,D)) Object
+ if (line.contains("tween_callback(")) {
+ int start = line.find("tween_callback(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 2) {
+ line = line.substr(0, start) + "tween_callback(Callable(" + parts[0] + "," + parts[1] + "))" + line.substr(end + start);
+ } else if (parts.size() >= 3) {
+ line = line.substr(0, start) + "tween_callback(Callable(" + parts[0] + "," + parts[1] + ").bind(" + connect_arguments(parts, 2).substr(1).lstrip("[").rstrip("]") + "))" + line.substr(end + start);
+ }
+ }
+ }
+ // -- start(a,b) -> start(Callable(a,b)) Thread
+ // -- start(a,b,c,d) -> start(Callable(a,b).bind(c),d) Thread
+ if (line.contains("start(")) {
+ int start = line.find("start(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ // Protection from 'func start'
+ if (!line.begins_with("func ")) {
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() >= 3) {
- line = line.substr(0, start) + "start(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start);
+ if (parts.size() == 2) {
+ line = line.substr(0, start) + "start(Callable(" + parts[0] + "," + parts[1] + "))" + line.substr(end + start);
+ } else if (parts.size() >= 3) {
+ line = line.substr(0, start) + "start(Callable(" + parts[0] + "," + parts[1] + ").bind(" + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start);
}
}
}
- // -- func _init(p_x:int)->void: -> func _init(p_x:int): Object # https://github.com/godotengine/godot/issues/50589
- if (line.find(" _init(") != -1) {
- int start = line.find(" _init(");
+ }
+ // -- func _init(p_x:int)->void: -> func _init(p_x:int): Object # https://github.com/godotengine/godot/issues/50589
+ if (line.contains(" _init(")) {
+ int start = line.find(" _init(");
+ if (line.contains(":")) {
int end = line.rfind(":") + 1;
if (end > -1) {
Vector<String> parts = parse_arguments(line.substr(start, end));
line = line.substr(0, start) + " _init(" + connect_arguments(parts, 0) + "):" + line.substr(end + start);
}
}
- // assert(speed < 20, str(randi()%10)) -> assert(speed < 20) #,str(randi()%10)) GDScript - GDScript bug constant message
- if (line.find("assert(") != -1) {
- int start = line.find("assert(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 2) {
- line = line.substr(0, start) + "assert(" + parts[0] + ") " + line.substr(end + start) + "#," + parts[1] + ")";
- }
+ }
+ // assert(speed < 20, str(randi()%10)) -> assert(speed < 20) #,str(randi()%10)) GDScript - GDScript bug constant message
+ if (line.contains("assert(")) {
+ int start = line.find("assert(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 2) {
+ line = line.substr(0, start) + "assert(" + parts[0] + ") " + line.substr(end + start) + "#," + parts[1] + ")";
}
}
- // create_from_image(aa, bb) -> create_from_image(aa) #, bb ImageTexture
- if (line.find("create_from_image(") != -1) {
- int start = line.find("create_from_image(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 2) {
- line = line.substr(0, start) + "create_from_image(" + parts[0] + ") " + "#," + parts[1] + line.substr(end + start);
- }
+ }
+ // create_from_image(aa, bb) -> create_from_image(aa) #, bb ImageTexture
+ if (line.contains("create_from_image(")) {
+ int start = line.find("create_from_image(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 2) {
+ line = line.substr(0, start) + "create_from_image(" + parts[0] + ") " + "#," + parts[1] + line.substr(end + start);
}
}
- // set_cell_item(a, b, c, d ,e) -> set_cell_item(Vector3(a, b, c), d ,e)
- if (line.find("set_cell_item(") != -1) {
- int start = line.find("set_cell_item(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() > 2) {
- line = line.substr(0, start) + "set_cell_item( Vector3(" + parts[0] + "," + parts[1] + "," + parts[2] + ") " + connect_arguments(parts, 3) + ")" + line.substr(end + start);
- }
+ }
+ // set_cell_item(a, b, c, d ,e) -> set_cell_item(Vector3(a, b, c), d ,e)
+ if (line.contains("set_cell_item(")) {
+ int start = line.find("set_cell_item(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() > 2) {
+ line = line.substr(0, start) + "set_cell_item( Vector3(" + parts[0] + "," + parts[1] + "," + parts[2] + ") " + connect_arguments(parts, 3) + ")" + line.substr(end + start);
}
}
- // get_cell_item(a, b, c) -> get_cell_item(Vector3i(a, b, c))
- if (line.find("get_cell_item(") != -1) {
- int start = line.find("get_cell_item(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 3) {
- line = line.substr(0, start) + "get_cell_item(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
- }
+ }
+ // get_cell_item(a, b, c) -> get_cell_item(Vector3i(a, b, c))
+ if (line.contains("get_cell_item(")) {
+ int start = line.find("get_cell_item(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 3) {
+ line = line.substr(0, start) + "get_cell_item(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
}
}
- // get_cell_item_orientation(a, b, c) -> get_cell_item_orientation(Vector3i(a, b, c))
- if (line.find("get_cell_item_orientation(") != -1) {
- int start = line.find("get_cell_item_orientation(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 3) {
- line = line.substr(0, start) + "get_cell_item_orientation(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
- }
+ }
+ // get_cell_item_orientation(a, b, c) -> get_cell_item_orientation(Vector3i(a, b, c))
+ if (line.contains("get_cell_item_orientation(")) {
+ int start = line.find("get_cell_item_orientation(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 3) {
+ line = line.substr(0, start) + "get_cell_item_orientation(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
}
}
- // apply_impulse(A, B) -> apply_impulse(B, A)
- if (line.find("apply_impulse(") != -1) {
- int start = line.find("apply_impulse(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 2) {
- line = line.substr(0, start) + "apply_impulse(" + parts[1] + ", " + parts[0] + ")" + line.substr(end + start);
- }
+ }
+ // apply_impulse(A, B) -> apply_impulse(B, A)
+ if (line.contains("apply_impulse(")) {
+ int start = line.find("apply_impulse(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 2) {
+ line = line.substr(0, start) + "apply_impulse(" + parts[1] + ", " + parts[0] + ")" + line.substr(end + start);
}
}
- // apply_force(A, B) -> apply_force(B, A)
- if (line.find("apply_force(") != -1) {
- int start = line.find("apply_force(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 2) {
- line = line.substr(0, start) + "apply_force(" + parts[1] + ", " + parts[0] + ")" + line.substr(end + start);
- }
+ }
+ // apply_force(A, B) -> apply_force(B, A)
+ if (line.contains("apply_force(")) {
+ int start = line.find("apply_force(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 2) {
+ line = line.substr(0, start) + "apply_force(" + parts[1] + ", " + parts[0] + ")" + line.substr(end + start);
}
}
- // map_to_world(a, b, c) -> map_to_world(Vector3i(a, b, c))
- if (line.find("map_to_world(") != -1) {
- int start = line.find("map_to_world(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 3) {
- line = line.substr(0, start) + "map_to_world(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
- }
+ }
+ // map_to_world(a, b, c) -> map_to_world(Vector3i(a, b, c))
+ if (line.contains("map_to_world(")) {
+ int start = line.find("map_to_world(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 3) {
+ line = line.substr(0, start) + "map_to_world(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
}
}
}
-
- // Collect vector to string
- file_content = "";
- for (int i = 0; i < lines.size(); i++) {
- file_content += lines[i];
-
- if (i != lines.size() - 1) {
- file_content += "\n";
+ // OS.get_window_safe_area() -> DisplayServer.get_display_safe_area()
+ if (line.contains("OS.get_window_safe_area(")) {
+ int start = line.find("OS.get_window_safe_area(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 0) {
+ line = line.substr(0, start) + "DisplayServer.get_display_safe_area()" + line.substr(end + start);
+ }
}
}
-};
-
-// This is almost 1:1 copy of function which rename gdscript functions
-Vector<String> ProjectConverter3To4::check_for_rename_gdscript_functions(Vector<String> &file_content) {
- int current_line = 1;
-
- Vector<String> found_things;
-
- RegEx reg_is_empty = RegEx("\\bempty\\(");
- RegEx reg_super = RegEx("([\t ])\\.([a-zA-Z_])");
- RegEx reg_json_to = RegEx("\\bto_json\\b");
- RegEx reg_json_parse = RegEx("([\t]{0,})([^\n]+)parse_json\\(([^\n]+)");
- RegEx reg_json_non_new = RegEx("([\t]{0,})([^\n]+)JSON\\.parse\\(([^\n]+)");
- RegEx reg_export = RegEx("export\\(([a-zA-Z0-9_]+)\\)[ ]+var[ ]+([a-zA-Z0-9_]+)");
- RegEx reg_export_advanced = RegEx("export\\(([^)^\n]+)\\)[ ]+var[ ]+([a-zA-Z0-9_]+)([^\n]+)");
- RegEx reg_setget_setget = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+([a-zA-Z0-9_]+)[ \t]*,[ \t]*([a-zA-Z0-9_]+)");
- RegEx reg_setget_set = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+([a-zA-Z0-9_]+)[ \t]*[,]*[^a-z^A-Z^0-9^_]*$");
- RegEx reg_setget_get = RegEx("var[ ]+([a-zA-Z0-9_]+)([^\n]+)setget[ \t]+,[ \t]*([a-zA-Z0-9_]+)[ \t]*$");
- RegEx reg_join = RegEx("([\\(\\)a-zA-Z0-9_]+)\\.join\\(([^\n^\\)]+)\\)");
- RegEx reg_mixed_tab_space = RegEx("([\t]+)([ ]+)");
- RegEx reg_image_lock = RegEx("([a-zA-Z0-9_\\.]+)\\.lock\\(\\)");
- RegEx reg_image_unlock = RegEx("([a-zA-Z0-9_\\.]+)\\.unlock\\(\\)");
- RegEx reg_os_fullscreen = RegEx("OS.window_fullscreen[= ]+([^#^\n]+)");
-
- CRASH_COND(!reg_is_empty.is_valid());
- CRASH_COND(!reg_super.is_valid());
- CRASH_COND(!reg_json_to.is_valid());
- CRASH_COND(!reg_json_parse.is_valid());
- CRASH_COND(!reg_json_non_new.is_valid());
- CRASH_COND(!reg_export.is_valid());
- CRASH_COND(!reg_export_advanced.is_valid());
- CRASH_COND(!reg_setget_setget.is_valid());
- CRASH_COND(!reg_setget_set.is_valid());
- CRASH_COND(!reg_setget_get.is_valid());
- CRASH_COND(!reg_join.is_valid());
- CRASH_COND(!reg_mixed_tab_space.is_valid());
- CRASH_COND(!reg_image_lock.is_valid());
- CRASH_COND(!reg_image_unlock.is_valid());
- CRASH_COND(!reg_os_fullscreen.is_valid());
-
- for (String &line : file_content) {
- String old_line = line;
-
- if (line.find("mtx") == -1 && line.find("mutex") == -1 && line.find("Mutex") == -1) {
- line = reg_image_lock.sub(line, "false # $1.lock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", true);
- line = reg_image_unlock.sub(line, "false # $1.unlock() # TODOConverter40, image no longer require locking, `false` helps to not broke one line if/else, so can be freely removed", true);
+ // draw_rect(a,b,c,d,e) -> draw_rect(a,b,c,d)#e) TODOGODOT4 Antialiasing argument is missing
+ if (line.contains("draw_rect(")) {
+ int start = line.find("draw_rect(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 5) {
+ line = line.substr(0, start) + "draw_rect(" + parts[0] + "," + parts[1] + "," + parts[2] + "," + parts[3] + ")" + line.substr(end + start) + "# " + parts[4] + ") TODOGODOT4 Antialiasing argument is missing";
+ }
}
+ }
+ // get_focus_owner() -> get_viewport().gui_get_focus_owner()
+ if (line.contains("get_focus_owner()")) {
+ line = line.replace("get_focus_owner()", "get_viewport().gui_get_focus_owner()");
+ }
- // Mixed use of spaces and tabs - tabs as first - TODO, this probably is problem problem, but not sure
- line = reg_mixed_tab_space.sub(line, "$1", true);
-
- // PackedStringArray(req_godot).join('.') -> '.'.join(PackedStringArray(req_godot)) PoolStringArray
- line = reg_join.sub(line, "$2.join($1)", true);
-
- // -- empty() -> is_empty() Pool*Array
- line = reg_is_empty.sub(line, "is_empty(", true);
-
- // -- \t.func() -> \tsuper.func() Object
- line = reg_super.sub(line, "$1super.$2", true); // TODO, not sure if possible, but for now this brake String text e.g. "Choosen .gitignore" -> "Choosen super.gitignore"
-
- // -- JSON.parse(a) -> JSON.new().parse(a) etc. JSON
- line = reg_json_non_new.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true);
-
- // -- to_json(a) -> JSON.new().stringify(a) Object
- line = reg_json_to.sub(line, "JSON.new().stringify", true);
-
- // -- parse_json(a) -> JSON.get_data() etc. Object
- line = reg_json_parse.sub(line, "$1var test_json_conv = JSON.new()\n$1test_json_conv.parse($3\n$1$2test_json_conv.get_data()", true);
-
- // -- get_node(@ -> get_node( Node
- line = line.replace("get_node(@", "get_node(");
-
- // export(float) var lifetime = 3.0 -> export var lifetime: float = 3.0 GDScript
- line = reg_export.sub(line, "export var $2: $1");
-
- // export(String, 'AnonymousPro', 'CourierPrime') var _font_name = 'AnonymousPro' -> export var _font_name = 'AnonymousPro' #(String, 'AnonymousPro', 'CourierPrime') GDScript
- line = reg_export_advanced.sub(line, "export var $2$3 # ($1)");
-
- // Setget Setget
- line = reg_setget_setget.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $4\n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true);
-
- // Setget set
- line = reg_setget_set.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Non existent get function \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Copy here content of $3", true);
+ // button.pressed = 1 -> button.button_pressed = 1
+ if (line.contains(".pressed")) {
+ int start = line.find(".pressed");
+ bool foundNextEqual = false;
+ String line_to_check = line.substr(start + String(".pressed").length());
+ for (int current_index = 0; line_to_check.length() > current_index; current_index++) {
+ char32_t chr = line_to_check.get(current_index);
+ if (chr == '\t' || chr == ' ') {
+ continue;
+ } else if (chr == '=') {
+ foundNextEqual = true;
+ } else {
+ break;
+ }
+ }
+ if (foundNextEqual) {
+ line = line.substr(0, start) + ".button_pressed" + line.substr(start + String(".pressed").length());
+ }
+ }
- // Setget get
- line = reg_setget_get.sub(line, "var $1$2:\n\tget:\n\t\treturn $1 # TODOConverter40 Copy here content of $3 \n\tset(mod_value):\n\t\tmod_value # TODOConverter40 Non existent set function", true);
+ // OS -> Time functions
+ if (line.contains("OS.get_ticks_msec")) {
+ line = line.replace("OS.get_ticks_msec", "Time.get_ticks_msec");
+ }
+ if (line.contains("OS.get_ticks_usec")) {
+ line = line.replace("OS.get_ticks_usec", "Time.get_ticks_usec");
+ }
+ if (line.contains("OS.get_unix_time")) {
+ line = line.replace("OS.get_unix_time", "Time.get_unix_time_from_system");
+ }
+}
- // OS.window_fullscreen = true -> ProjectSettings.set("display/window/size/fullscreen",true)
- line = reg_os_fullscreen.sub(line, "ProjectSettings.set(\"display/window/size/fullscreen\", $1)", true);
+void ProjectConverter3To4::process_csharp_line(String &line, const RegExContainer &reg_container) {
+ line = line.replace("OS.GetWindowSafeArea()", "DisplayServer.ScreenGetUsableRect()");
- // -- r.move_and_slide( a, b, c, d, e ) -> r.set_motion_velocity(a) ... r.move_and_slide() KinematicBody
- if (line.find("move_and_slide(") != -1) {
- int start = line.find("move_and_slide(");
+ // -- Connect(,,,things) -> Connect(,Callable(,),things) Object
+ if (line.contains("Connect(")) {
+ int start = line.find("Connect(");
+ // Protection from disconnect
+ if (start == 0 || line.get(start - 1) != 's') {
int end = get_end_parenthess(line.substr(start)) + 1;
if (end > -1) {
- String base_obj = get_object_of_execution(line.substr(0, start));
- String starting_space = get_starting_space(line);
-
Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() >= 1) {
- String line_new;
-
- // motion_velocity
- line_new += starting_space + base_obj + "set_motion_velocity(" + parts[0] + ")\n";
-
- // up_direction
- if (parts.size() >= 2) {
- line_new += starting_space + base_obj + "set_up_direction(" + parts[1] + ")\n";
- }
-
- // stop_on_slope
- if (parts.size() >= 3) {
- line_new += starting_space + base_obj + "set_floor_stop_on_slope_enabled(" + parts[2] + ")\n";
- }
-
- // max_slides
- if (parts.size() >= 4) {
- line_new += starting_space + base_obj + "set_max_slides(" + parts[3] + ")\n";
- }
-
- // floor_max_angle
- if (parts.size() >= 5) {
- line_new += starting_space + base_obj + "set_floor_max_angle(" + parts[4] + ")\n";
- }
-
- // infiinite_interia
- if (parts.size() >= 6) {
- line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[5] + "`\n";
- }
-
- line = line_new + line.substr(0, start) + "move_and_slide()" + line.substr(end + start);
+ if (parts.size() >= 3) {
+ line = line.substr(0, start) + "Connect(" + parts[0] + ",new Callable(" + parts[1] + "," + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start);
}
}
}
+ }
+ // -- Disconnect(a,b,c) -> Disconnect(a,Callable(b,c)) Object
+ if (line.contains("Disconnect(")) {
+ int start = line.find("Disconnect(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 3) {
+ line = line.substr(0, start) + "Disconnect(" + parts[0] + ",new Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
+ }
+ }
+ }
+ // -- IsConnected(a,b,c) -> IsConnected(a,Callable(b,c)) Object
+ if (line.contains("IsConnected(")) {
+ int start = line.find("IsConnected(");
+ int end = get_end_parenthess(line.substr(start)) + 1;
+ if (end > -1) {
+ Vector<String> parts = parse_arguments(line.substr(start, end));
+ if (parts.size() == 3) {
+ line = line.substr(0, start) + "IsConnected(" + parts[0] + ",new Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
+ }
+ }
+ }
+}
- // -- r.move_and_slide_with_snap( a, b, c, d, e ) -> r.set_motion_velocity(a) ... r.move_and_slide() KinematicBody
- if (line.find("move_and_slide_with_snap(") != -1) {
- int start = line.find("move_and_slide_with_snap(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- String base_obj = get_object_of_execution(line.substr(0, start));
- String starting_space = get_starting_space(line);
+void ProjectConverter3To4::rename_csharp_functions(Vector<String> &lines, const RegExContainer &reg_container) {
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ process_csharp_line(line, reg_container);
+ }
+ }
+};
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() >= 1) {
- String line_new;
+Vector<String> ProjectConverter3To4::check_for_rename_csharp_functions(Vector<String> &lines, const RegExContainer &reg_container) {
+ int current_line = 1;
- // motion_velocity
- line_new += starting_space + base_obj + "set_motion_velocity(" + parts[0] + ")\n";
+ Vector<String> found_renames;
- // snap
- if (parts.size() >= 2) {
- line_new += starting_space + "# TODOConverter40 looks that snap in Godot 4.0 is float, not vector like in Godot 3 - previous value `" + parts[1] + "`\n";
- }
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ String old_line = line;
+ process_csharp_line(line, reg_container);
+ if (old_line != line) {
+ found_renames.append(simple_line_formatter(current_line, old_line, line));
+ }
+ }
+ }
- // up_direction
- if (parts.size() >= 3) {
- line_new += starting_space + base_obj + "set_up_direction(" + parts[2] + ")\n";
- }
+ return found_renames;
+}
- // stop_on_slope
- if (parts.size() >= 4) {
- line_new += starting_space + base_obj + "set_floor_stop_on_slope_enabled(" + parts[3] + ")\n";
- }
+void ProjectConverter3To4::rename_csharp_attributes(Vector<String> &lines, const RegExContainer &reg_container) {
+ static String error_message = "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n";
- // max_slides
- if (parts.size() >= 5) {
- line_new += starting_space + base_obj + "set_max_slides(" + parts[4] + ")\n";
- }
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ line = reg_container.keyword_csharp_remote.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true);
+ line = reg_container.keyword_csharp_remotesync.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true);
+ line = reg_container.keyword_csharp_puppet.sub(line, "[RPC]", true);
+ line = reg_container.keyword_csharp_puppetsync.sub(line, "[RPC(CallLocal = true)]", true);
+ line = reg_container.keyword_csharp_master.sub(line, error_message + "[RPC]", true);
+ line = reg_container.keyword_csharp_mastersync.sub(line, error_message + "[RPC(CallLocal = true)]", true);
+ }
+ }
+}
- // floor_max_angle
- if (parts.size() >= 6) {
- line_new += starting_space + base_obj + "set_floor_max_angle(" + parts[5] + ")\n";
- }
+Vector<String> ProjectConverter3To4::check_for_rename_csharp_attributes(Vector<String> &lines, const RegExContainer &reg_container) {
+ int current_line = 1;
- // infiinite_interia
- if (parts.size() >= 7) {
- line_new += starting_space + "# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `" + parts[6] + "`\n";
- }
+ Vector<String> found_renames;
- line = line_new + line.substr(0, start) + "move_and_slide()" + line.substr(end + start);
- }
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ String old;
+ old = line;
+ line = reg_container.keyword_csharp_remote.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "[Remote]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer)]", line));
}
- }
- // -- sort_custom( a , b ) -> sort_custom(Callable( a , b )) Object
- if (line.find("sort_custom(") != -1) {
- int start = line.find("sort_custom(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 2) {
- line = line.substr(0, start) + "sort_custom(Callable(" + parts[0] + "," + parts[1] + "))" + line.substr(end + start);
- }
+ old = line;
+ line = reg_container.keyword_csharp_remotesync.sub(line, "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "[RemoteSync]", "[RPC(MultiplayerAPI.RPCMode.AnyPeer, CallLocal = true)]", line));
}
- }
- // -- draw_line(1,2,3,4,5) -> draw_line(1,2,3,4) CanvasItem
- if (line.find("draw_line(") != -1) {
- int start = line.find("draw_line(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 5) {
- line = line.substr(0, start) + "draw_line(" + parts[0] + "," + parts[1] + "," + parts[2] + "," + parts[3] + ")" + line.substr(end + start);
- }
+ old = line;
+ line = reg_container.keyword_csharp_puppet.sub(line, "[RPC]", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "[Puppet]", "[RPC]", line));
}
- }
- // -- func c(var a, var b) -> func c(a, b)
- if (line.find("func ") != -1 && line.find("var ") != -1) {
- int start = line.find("func ");
- start = line.substr(start).find("(") + start;
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
-
- String start_string = line.substr(0, start) + "(";
- for (int i = 0; i < parts.size(); i++) {
- start_string += parts[i].strip_edges().trim_prefix("var ");
- if (i != parts.size() - 1) {
- start_string += ", ";
- }
- }
- line = start_string + ")" + line.substr(end + start);
+ old = line;
+ line = reg_container.keyword_csharp_puppetsync.sub(line, "[RPC(CallLocal = true)]", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "[PuppetSync]", "[RPC(CallLocal = true)]", line));
}
- }
- // -- yield(this, \"timeout\") -> await this.timeout GDScript
- if (line.find("yield(") != -1) {
- int start = line.find("yield(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 2) {
- line = line.substr(0, start) + "await " + parts[0] + "." + parts[1].replace("\"", "").replace("\'", "").replace(" ", "") + line.substr(end + start);
- }
+ old = line;
+ line = reg_container.keyword_csharp_master.sub(line, "[RPC]", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "[Master]", "[RPC]", line));
}
- }
- // -- parse_json( AA ) -> TODO Object
- if (line.find("parse_json(") != -1) {
- int start = line.find("parse_json(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- line = line.substr(0, start) + "JSON.new().stringify(" + connect_arguments(parts, 0) + ")" + line.substr(end + start);
+ old = line;
+ line = reg_container.keyword_csharp_mastersync.sub(line, "[RPC(CallLocal = true)]", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "[MasterSync]", "[RPC(CallLocal = true)]", line));
}
}
+ current_line++;
+ }
- // -- .xform(Vector3(a,b,c)) -> * Vector3(a,b,c) Transform
- if (line.find(".xform(") != -1) {
- int start = line.find(".xform(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 1) {
- line = line.substr(0, start) + " * " + parts[0] + line.substr(end + start);
- }
- }
- }
+ return found_renames;
+}
- // -- .xform_inv(Vector3(a,b,c)) -> / Vector3(a,b,c) Transform
- if (line.find(".xform_inv(") != -1) {
- int start = line.find(".xform_inv(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 1) {
- line = line.substr(0, start) + " / " + parts[0] + line.substr(end + start);
- }
- }
- }
+void ProjectConverter3To4::rename_gdscript_keywords(Vector<String> &lines, const RegExContainer &reg_container) {
+ static String error_message = "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using get_multiplayer().get_remote_sender_id()\n";
- // -- connect(,,,things) -> connect(,Callable(,),things) Object
- if (line.find("connect(") != -1) {
- int start = line.find("connect(");
- // Protection from disconnect
- if (start == 0 || line.get(start - 1) != 's') {
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() >= 3) {
- line = line.substr(0, start) + "connect(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start);
- }
- }
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ if (line.contains("tool")) {
+ line = reg_container.keyword_gdscript_tool.sub(line, "@tool", true);
}
- }
- // -- disconnect(a,b,c) -> disconnect(a,Callable(b,c)) Object
- if (line.find("disconnect(") != -1) {
- int start = line.find("disconnect(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 3) {
- line = line.substr(0, start) + "disconnect(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
- }
+ if (line.contains("export")) {
+ line = reg_container.keyword_gdscript_export_single.sub(line, "@export", true);
}
- }
- // -- is_connected(a,b,c) -> is_connected(a,Callable(b,c)) Object
- if (line.find("is_connected(") != -1) {
- int start = line.find("is_connected(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 3) {
- line = line.substr(0, start) + "is_connected(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
- }
+ if (line.contains("export")) {
+ line = reg_container.keyword_gdscript_export_mutli.sub(line, "$1@export", true);
}
- }
- // -- start(a,b,c) -> start(a,Callable(b,c)) Thread
- if (line.find("start(") != -1) {
- int start = line.find("start(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() >= 3) {
- line = line.substr(0, start) + "start(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start);
- }
+ if (line.contains("onready")) {
+ line = reg_container.keyword_gdscript_onready.sub(line, "@onready", true);
}
- }
- // -- func _init(p_x:int)->void: -> func _init(p_x:int): Object # https://github.com/godotengine/godot/issues/50589
- if (line.find(" _init(") != -1) {
- int start = line.find(" _init(");
- int end = line.rfind(":") + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- line = line.substr(0, start) + " _init(" + connect_arguments(parts, 0) + "):" + line.substr(end + start);
+ if (line.contains("remote")) {
+ line = reg_container.keyword_gdscript_remote.sub(line, "@rpc(any_peer) func", true);
}
- }
- // assert(speed < 20, str(randi()%10)) -> assert(speed < 20) #,str(randi()%10)) GDScript - GDScript bug constant message
- if (line.find("assert(") != -1) {
- int start = line.find("assert(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 2) {
- line = line.substr(0, start) + "assert(" + parts[0] + ") " + line.substr(end + start) + "#," + parts[1] + ")";
- }
+ if (line.contains("remote")) {
+ line = reg_container.keyword_gdscript_remotesync.sub(line, "@rpc(any_peer, call_local) func", true);
}
- }
- // create_from_image(aa, bb) -> create_from_image(aa) #, bb ImageTexture
- if (line.find("create_from_image(") != -1) {
- int start = line.find("create_from_image(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 2) {
- line = line.substr(0, start) + "create_from_image(" + parts[0] + ") " + "#," + parts[1] + line.substr(end + start);
- }
+ if (line.contains("sync")) {
+ line = reg_container.keyword_gdscript_sync.sub(line, "@rpc(any_peer, call_local) func", true);
}
- }
- // set_cell_item(a, b, c, d ,e) -> set_cell_item(Vector3(a, b, c), d ,e)
- if (line.find("set_cell_item(") != -1) {
- int start = line.find("set_cell_item(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() > 2) {
- line = line.substr(0, start) + "set_cell_item( Vector3(" + parts[0] + "," + parts[1] + "," + parts[2] + ") " + connect_arguments(parts, 3) + ")" + line.substr(end + start);
- }
+ if (line.contains("slave")) {
+ line = reg_container.keyword_gdscript_slave.sub(line, "@rpc func", true);
}
- }
- // get_cell_item(a, b, c) -> get_cell_item(Vector3i(a, b, c))
- if (line.find("get_cell_item(") != -1) {
- int start = line.find("get_cell_item(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 3) {
- line = line.substr(0, start) + "get_cell_item(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
- }
+ if (line.contains("puppet")) {
+ line = reg_container.keyword_gdscript_puppet.sub(line, "@rpc func", true);
}
- }
- // get_cell_item_orientation(a, b, c) -> get_cell_item_orientation(Vector3i(a, b, c))
- if (line.find("get_cell_item_orientation(") != -1) {
- int start = line.find("get_cell_item_orientation(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 3) {
- line = line.substr(0, start) + "get_cell_item_orientation(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
- }
+ if (line.contains("puppet")) {
+ line = reg_container.keyword_gdscript_puppetsync.sub(line, "@rpc(call_local) func", true);
}
- }
-
- // apply_impulse(A, B) -> apply_impulse(B, A)
- if (line.find("apply_impulse(") != -1) {
- int start = line.find("apply_impulse(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 2) {
- line = line.substr(0, start) + "apply_impulse(" + parts[1] + ", " + parts[0] + ")" + line.substr(end + start);
- }
+ if (line.contains("master")) {
+ line = reg_container.keyword_gdscript_master.sub(line, error_message + "@rpc func", true);
}
- }
- // apply_force(A, B) -> apply_force(B, A)
- if (line.find("apply_force(") != -1) {
- int start = line.find("apply_force(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 2) {
- line = line.substr(0, start) + "apply_force(" + parts[1] + ", " + parts[0] + ")" + line.substr(end + start);
- }
+ if (line.contains("master")) {
+ line = reg_container.keyword_gdscript_mastersync.sub(line, error_message + "@rpc(call_local) func", true);
}
}
- // map_to_world(a, b, c) -> map_to_world(Vector3i(a, b, c))
- if (line.find("map_to_world(") != -1) {
- int start = line.find("get_cell_item_orientation(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 3) {
- line = line.substr(0, start) + "map_to_world(Vector3i(" + parts[0] + "," + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
- }
- }
- }
-
- if (old_line != line) {
- found_things.append(simple_line_formatter(current_line, old_line, line));
- }
}
-
- return found_things;
}
-void ProjectConverter3To4::rename_csharp_functions(String &file_content) {
- // Custom renaming, each rule needs to be set manually
- // Don't forget to put validate each rule in validate_conversion function
- Vector<String> lines = file_content.split("\n");
+Vector<String> ProjectConverter3To4::check_for_rename_gdscript_keywords(Vector<String> &lines, const RegExContainer &reg_container) {
+ Vector<String> found_renames;
+ int current_line = 1;
for (String &line : lines) {
- // TODO maybe this can be changed to normal rule
- line = line.replace("OS.GetWindowSafeArea()", "DisplayServer.ScreenGetUsableRect()");
-
- // -- Connect(,,,things) -> Connect(,Callable(,),things) Object
- if (line.find("Connect(") != -1) {
- int start = line.find("Connect(");
- // Protection from disconnect
- if (start == 0 || line.get(start - 1) != 's') {
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() >= 3) {
- line = line.substr(0, start) + "Connect(" + parts[0] + ",new Callable(" + parts[1] + "," + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start);
- }
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ String old;
+
+ if (line.contains("tool")) {
+ old = line;
+ line = reg_container.keyword_gdscript_tool.sub(line, "@tool", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "tool", "@tool", line));
}
}
- }
- // -- Disconnect(a,b,c) -> Disconnect(a,Callable(b,c)) Object
- if (line.find("Disconnect(") != -1) {
- int start = line.find("Disconnect(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 3) {
- line = line.substr(0, start) + "Disconnect(" + parts[0] + ",new Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
+
+ if (line.contains("export")) {
+ old = line;
+ line = reg_container.keyword_gdscript_export_single.sub(line, "$1@export", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "export", "@export", line));
}
}
- }
- // -- IsConnected(a,b,c) -> IsConnected(a,Callable(b,c)) Object
- if (line.find("IsConnected(") != -1) {
- int start = line.find("IsConnected(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 3) {
- line = line.substr(0, start) + "IsConnected(" + parts[0] + ",new Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
+
+ if (line.contains("export")) {
+ old = line;
+ line = reg_container.keyword_gdscript_export_mutli.sub(line, "@export", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "export", "@export", line));
}
}
- }
- }
-
- // Collect vector to string
- file_content = "";
- for (int i = 0; i < lines.size(); i++) {
- file_content += lines[i];
-
- if (i != lines.size() - 1) {
- file_content += "\n";
- }
- }
-};
-
-// This is almost 1:1 copy of function which rename gdscript functions
-Vector<String> ProjectConverter3To4::check_for_rename_csharp_functions(Vector<String> &file_content) {
- int current_line = 1;
- Vector<String> found_things;
-
- for (String &line : file_content) {
- String old_line = line;
-
- // TODO maybe this can be changed to normal rule
- line = line.replace("OS.GetWindowSafeArea()", "DisplayServer.ScreenGetUsableRect()");
-
- // -- Connect(,,,things) -> connect(,Callable(,),things) Object
- if (line.find("Connect(") != -1) {
- int start = line.find("Connect(");
- // Protection from disconnect
- if (start == 0 || line.get(start - 1) != 's') {
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() >= 3) {
- line = line.substr(0, start) + "Connect(" + parts[0] + ",new Callable(" + parts[1] + "," + parts[2] + ")" + connect_arguments(parts, 3) + ")" + line.substr(end + start);
- }
+ if (line.contains("onready")) {
+ old = line;
+ line = reg_container.keyword_gdscript_tool.sub(line, "@onready", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "onready", "@onready", line));
}
}
- }
- // -- Disconnect(a,b,c) -> Disconnect(a,Callable(b,c)) Object
- if (line.find("Disconnect(") != -1) {
- int start = line.find("Disconnect(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 3) {
- line = line.substr(0, start) + "Disconnect(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
+
+ if (line.contains("remote")) {
+ old = line;
+ line = reg_container.keyword_gdscript_remote.sub(line, "@rpc(any_peer) func", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "remote func", "@rpc(any_peer) func", line));
}
}
- }
- // -- IsConnected(a,b,c) -> IsConnected(a,Callable(b,c)) Object
- if (line.find("IsConnected(") != -1) {
- int start = line.find("IsConnected(");
- int end = get_end_parenthess(line.substr(start)) + 1;
- if (end > -1) {
- Vector<String> parts = parse_arguments(line.substr(start, end));
- if (parts.size() == 3) {
- line = line.substr(0, start) + "IsConnected(" + parts[0] + ",Callable(" + parts[1] + "," + parts[2] + "))" + line.substr(end + start);
+
+ if (line.contains("remote")) {
+ old = line;
+ line = reg_container.keyword_gdscript_remotesync.sub(line, "@rpc(any_peer, call_local)) func", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "remotesync func", "@rpc(any_peer, call_local)) func", line));
}
}
- }
- if (old_line != line) {
- found_things.append(simple_line_formatter(current_line, old_line, line));
- }
- }
+ if (line.contains("sync")) {
+ old = line;
+ line = reg_container.keyword_gdscript_sync.sub(line, "@rpc(any_peer, call_local)) func", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "sync func", "@rpc(any_peer, call_local)) func", line));
+ }
+ }
- return found_things;
-}
+ if (line.contains("slave")) {
+ old = line;
+ line = reg_container.keyword_gdscript_slave.sub(line, "@rpc func", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "slave func", "@rpc func", line));
+ }
+ }
-void ProjectConverter3To4::rename_gdscript_keywords(String &file_content){
- { RegEx reg_tool = RegEx("([\n]+)tool");
-CRASH_COND(!reg_tool.is_valid());
-file_content = reg_tool.sub(file_content, "$1@tool", true);
-RegEx reg_tool2 = RegEx("^tool");
-CRASH_COND(!reg_tool2.is_valid());
-file_content = reg_tool2.sub(file_content, "@tool", true);
-}
-{
- RegEx reg_export = RegEx("([\n\t]+)export\\b");
- CRASH_COND(!reg_export.is_valid());
- file_content = reg_export.sub(file_content, "$1@export", true);
- RegEx reg_export2 = RegEx("^export");
- CRASH_COND(!reg_export2.is_valid());
- file_content = reg_export2.sub(file_content, "@export", true);
-}
-{
- RegEx reg_onready = RegEx("([\n]+)onready");
- CRASH_COND(!reg_onready.is_valid());
- file_content = reg_onready.sub(file_content, "$1@onready", true);
- RegEx reg_onready2 = RegEx("^onready");
- CRASH_COND(!reg_onready2.is_valid());
- file_content = reg_onready2.sub(file_content, "@onready", true);
-}
-{
- RegEx reg_master = RegEx("([\n]+)master func");
- CRASH_COND(!reg_master.is_valid());
- file_content = reg_master.sub(file_content, "$1@rpc(any) func", true);
- RegEx reg_master2 = RegEx("^master func");
- CRASH_COND(!reg_master2.is_valid());
- file_content = reg_master2.sub(file_content, "@rpc(any) func", true);
-}
-{
- RegEx reg_puppet = RegEx("([\n]+)puppet func");
- CRASH_COND(!reg_puppet.is_valid());
- file_content = reg_puppet.sub(file_content, "$1@rpc(auth) func", true);
- RegEx reg_puppet2 = RegEx("^puppet func");
- CRASH_COND(!reg_puppet2.is_valid());
- file_content = reg_puppet2.sub(file_content, "@rpc(auth) func", true);
-}
-{
- RegEx reg_remote = RegEx("([\n]+)remote func");
- CRASH_COND(!reg_remote.is_valid());
- file_content = reg_remote.sub(file_content, "$1@rpc(any) func", true);
- RegEx reg_remote2 = RegEx("^remote func");
- CRASH_COND(!reg_remote2.is_valid());
- file_content = reg_remote2.sub(file_content, "@rpc(any) func", true);
-}
-{
- RegEx reg_remotesync = RegEx("([\n]+)remotesync func");
- CRASH_COND(!reg_remotesync.is_valid());
- file_content = reg_remotesync.sub(file_content, "$1@rpc(any,sync) func", true);
- RegEx reg_remotesync2 = RegEx("^remotesync func");
- CRASH_COND(!reg_remotesync2.is_valid());
- file_content = reg_remotesync2.sub(file_content, "@rpc(any,sync) func", true);
-}
-{
- RegEx reg_sync = RegEx("([\n]+)sync func");
- CRASH_COND(!reg_sync.is_valid());
- file_content = reg_sync.sub(file_content, "$1@rpc(any,sync) func", true);
- RegEx reg_sync2 = RegEx("^sync func");
- CRASH_COND(!reg_sync2.is_valid());
- file_content = reg_sync2.sub(file_content, "@rpc(any,sync) func", true);
-}
-{
- RegEx reg_puppetsync = RegEx("([\n]+)puppetsync func");
- CRASH_COND(!reg_puppetsync.is_valid());
- file_content = reg_puppetsync.sub(file_content, "$1@rpc(auth,sync) func", true);
- RegEx reg_puppetsync2 = RegEx("^puppetsync func");
- CRASH_COND(!reg_puppetsync2.is_valid());
- file_content = reg_puppetsync2.sub(file_content, "@rpc(auth,sync) func", true);
-}
-{
- RegEx reg_mastersync = RegEx("([\n]+)mastersync func");
- CRASH_COND(!reg_mastersync.is_valid());
- file_content = reg_mastersync.sub(file_content, "$1@rpc(any,sync) func", true);
- RegEx reg_mastersync2 = RegEx("^mastersync func");
- CRASH_COND(!reg_mastersync2.is_valid());
- file_content = reg_mastersync2.sub(file_content, "@rpc(any,sync) func", true);
-}
-}
-;
+ if (line.contains("puppet")) {
+ old = line;
+ line = reg_container.keyword_gdscript_puppet.sub(line, "@rpc func", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "puppet func", "@rpc func", line));
+ }
+ }
-Vector<String> ProjectConverter3To4::check_for_rename_gdscript_keywords(Vector<String> &file_content) {
- Vector<String> found_things;
+ if (line.contains("puppet")) {
+ old = line;
+ line = reg_container.keyword_gdscript_puppetsync.sub(line, "@rpc(call_local) func", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "puppetsync func", "@rpc(call_local) func", line));
+ }
+ }
- int current_line = 1;
+ if (line.contains("master")) {
+ old = line;
+ line = reg_container.keyword_gdscript_master.sub(line, "@rpc func", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "master func", "@rpc func", line));
+ }
+ }
- for (String &line : file_content) {
- String old;
- old = line;
- {
- RegEx reg_tool2 = RegEx("^tool");
- CRASH_COND(!reg_tool2.is_valid());
- line = reg_tool2.sub(line, "@tool", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "tool", "@tool", line));
- }
- old = line;
- {
- RegEx reg_export = RegEx("([\t]+)export\\b");
- CRASH_COND(!reg_export.is_valid());
- line = reg_export.sub(line, "$1@export", true);
- RegEx reg_export2 = RegEx("^export");
- CRASH_COND(!reg_export2.is_valid());
- line = reg_export2.sub(line, "@export", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "export", "@export", line));
- }
- old = line;
- {
- RegEx reg_onready2 = RegEx("^onready");
- CRASH_COND(!reg_onready2.is_valid());
- line = reg_onready2.sub(line, "@onready", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "onready", "@onready", line));
- }
- old = line;
- {
- RegEx reg_master2 = RegEx("^master func");
- CRASH_COND(!reg_master2.is_valid());
- line = reg_master2.sub(line, "@rpc(any) func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "master func", "@rpc(any) func", line));
- }
- old = line;
- {
- RegEx reg_puppet2 = RegEx("^puppet func");
- CRASH_COND(!reg_puppet2.is_valid());
- line = reg_puppet2.sub(line, "@rpc(auth) func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "puppet func", "@rpc(auth) func", line));
- }
- old = line;
- {
- RegEx reg_remote2 = RegEx("^remote func");
- CRASH_COND(!reg_remote2.is_valid());
- line = reg_remote2.sub(line, "@rpc(any) func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "remote func", "@rpc(any) func", line));
- }
- old = line;
- {
- RegEx reg_remotesync2 = RegEx("^remotesync func");
- CRASH_COND(!reg_remotesync2.is_valid());
- line = reg_remotesync2.sub(line, "@rpc(any,sync) func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "remotesync func", "@rpc(any,sync) func", line));
- }
- old = line;
- {
- RegEx reg_sync2 = RegEx("^sync func");
- CRASH_COND(!reg_sync2.is_valid());
- line = reg_sync2.sub(line, "@rpc(any,sync) func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "sync func", "@rpc(any,sync) func", line));
- }
- old = line;
- {
- RegEx reg_puppetsync2 = RegEx("^puppetsync func");
- CRASH_COND(!reg_puppetsync2.is_valid());
- line = reg_puppetsync2.sub(line, "@rpc(auth,sync) func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "puppetsync func", "@rpc(any,sync) func", line));
- }
- old = line;
- {
- RegEx reg_mastersync2 = RegEx("^mastersync func");
- CRASH_COND(!reg_mastersync2.is_valid());
- line = reg_mastersync2.sub(line, "@rpc(any,sync) func", true);
- }
- if (old != line) {
- found_things.append(line_formatter(current_line, "mastersync", "@rpc(any,sync) func", line));
+ if (line.contains("master")) {
+ old = line;
+ line = reg_container.keyword_gdscript_master.sub(line, "@rpc(call_local) func", true);
+ if (old != line) {
+ found_renames.append(line_formatter(current_line, "mastersync func", "@rpc(call_local) func", line));
+ }
+ }
}
- old = line;
-
current_line++;
}
- return found_things;
+ return found_renames;
}
-void ProjectConverter3To4::custom_rename(String &file_content, String from, String to) {
+void ProjectConverter3To4::custom_rename(Vector<String> &lines, String from, String to) {
RegEx reg = RegEx(String("\\b") + from + "\\b");
CRASH_COND(!reg.is_valid());
- file_content = reg.sub(file_content, to, true);
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ line = reg.sub(line, to, true);
+ }
+ }
};
-Vector<String> ProjectConverter3To4::check_for_custom_rename(Vector<String> &file_content, String from, String to) {
- Vector<String> found_things;
+Vector<String> ProjectConverter3To4::check_for_custom_rename(Vector<String> &lines, String from, String to) {
+ Vector<String> found_renames;
RegEx reg = RegEx(String("\\b") + from + "\\b");
CRASH_COND(!reg.is_valid());
int current_line = 1;
- for (String &line : file_content) {
- Array reg_match = reg.search_all(line);
- if (reg_match.size() > 0) {
- found_things.append(line_formatter(current_line, from.replace("\\.", "."), to, line)); // Without replacing it will print "\.shader" instead ".shader"
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ TypedArray<RegExMatch> reg_match = reg.search_all(line);
+ if (reg_match.size() > 0) {
+ found_renames.append(line_formatter(current_line, from.replace("\\.", "."), to, line)); // Without replacing it will print "\.shader" instead ".shader"
+ }
}
current_line++;
}
- return found_things;
+ return found_renames;
}
-void ProjectConverter3To4::rename_common(const char *array[][2], String &file_content) {
- int current_index = 0;
- while (array[current_index][0]) {
- RegEx reg = RegEx(String("\\b") + array[current_index][0] + "\\b");
- CRASH_COND(!reg.is_valid());
- file_content = reg.sub(file_content, array[current_index][1], true);
- current_index++;
+void ProjectConverter3To4::rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<String> &lines) {
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ for (unsigned int current_index = 0; current_index < cached_regexes.size(); current_index++) {
+ if (line.contains(array[current_index][0])) {
+ line = cached_regexes[current_index]->sub(line, array[current_index][1], true);
+ }
+ }
+ }
}
}
-// Common renaming,
-Vector<String> ProjectConverter3To4::check_for_rename_common(const char *array[][2], Vector<String> &file_content) {
- int current_index = 0;
-
- Vector<String> found_things;
+Vector<String> ProjectConverter3To4::check_for_rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<String> &lines) {
+ Vector<String> found_renames;
- while (array[current_index][0]) {
- RegEx reg = RegEx(String("\\b") + array[current_index][0] + "\\b");
- CRASH_COND(!reg.is_valid());
+ int current_line = 1;
- int current_line = 1;
- for (String &line : file_content) {
- Array reg_match = reg.search_all(line);
- if (reg_match.size() > 0) {
- found_things.append(line_formatter(current_line, array[current_index][0], array[current_index][1], line));
+ for (String &line : lines) {
+ if (uint64_t(line.length()) <= maximum_line_length) {
+ for (unsigned int current_index = 0; current_index < cached_regexes.size(); current_index++) {
+ if (line.contains(array[current_index][0])) {
+ TypedArray<RegExMatch> reg_match = cached_regexes[current_index]->search_all(line);
+ if (reg_match.size() > 0) {
+ found_renames.append(line_formatter(current_line, array[current_index][0], array[current_index][1], line));
+ }
+ }
}
- current_line++;
}
- current_index++;
+ current_line++;
}
- return found_things;
+
+ return found_renames;
}
-// Formats data to print them into user console when trying to convert data
+// Prints full info about renamed things e.g.:
+// Line (67) remove -> remove_at - LINE """ doubler._blacklist.remove(0) """
String ProjectConverter3To4::line_formatter(int current_line, String from, String to, String line) {
if (from.size() > 200) {
from = from.substr(0, 197) + "...";
@@ -3866,6 +3880,8 @@ String ProjectConverter3To4::line_formatter(int current_line, String from, Strin
return String("Line (") + itos(current_line) + ") " + from.replace("\r", "").replace("\n", "") + " -> " + to.replace("\r", "").replace("\n", "") + " - LINE \"\"\" " + line.replace("\r", "").replace("\n", "").strip_edges() + " \"\"\"";
}
+// Prints only full lines e.g.:
+// Line (1) - FULL LINES - """yield(get_tree().create_timer(3), 'timeout')""" =====> """ await get_tree().create_timer(3).timeout """
String ProjectConverter3To4::simple_line_formatter(int current_line, String old_line, String line) {
if (old_line.size() > 1000) {
old_line = old_line.substr(0, 997) + "...";
@@ -3876,6 +3892,19 @@ String ProjectConverter3To4::simple_line_formatter(int current_line, String old_
return String("Line (") + itos(current_line) + ") - FULL LINES - \"\"\"" + old_line.replace("\r", "").replace("\n", "").strip_edges() + "\"\"\" =====> \"\"\" " + line.replace("\r", "").replace("\n", "").strip_edges() + " \"\"\"";
}
+// Collects string from vector strings
+String ProjectConverter3To4::collect_string_from_vector(Vector<String> &vector) {
+ String string = "";
+ for (int i = 0; i < vector.size(); i++) {
+ string += vector[i];
+
+ if (i != vector.size() - 1) {
+ string += "\n";
+ }
+ }
+ return string;
+}
+
#else // No regex.
int ProjectConverter3To4::convert() {
diff --git a/editor/project_converter_3_to_4.h b/editor/project_converter_3_to_4.h
index 95239666e0..fc6d66c9a8 100644
--- a/editor/project_converter_3_to_4.h
+++ b/editor/project_converter_3_to_4.h
@@ -35,28 +35,43 @@
#include "core/io/file_access.h"
#include "core/object/ref_counted.h"
#include "core/string/ustring.h"
+#include "core/templates/local_vector.h"
+
+class RegEx;
class ProjectConverter3To4 {
- void rename_enums(String &file_content);
- Vector<String> check_for_rename_enums(Vector<String> &file_content);
+public:
+ class RegExContainer;
+
+private:
+ uint64_t maximum_file_size;
+ uint64_t maximum_line_length;
+
+ void rename_colors(Vector<String> &lines, const RegExContainer &reg_container);
+ Vector<String> check_for_rename_colors(Vector<String> &lines, const RegExContainer &reg_container);
+
+ void rename_classes(Vector<String> &lines, const RegExContainer &reg_container);
+ Vector<String> check_for_rename_classes(Vector<String> &lines, const RegExContainer &reg_container);
- void rename_classes(String &file_content);
- Vector<String> check_for_rename_classes(Vector<String> &file_content);
+ void rename_gdscript_functions(Vector<String> &lines, const RegExContainer &reg_container, bool builtin);
+ Vector<String> check_for_rename_gdscript_functions(Vector<String> &lines, const RegExContainer &reg_container, bool builtin);
+ void process_gdscript_line(String &line, const RegExContainer &reg_container, bool builtin);
- void rename_gdscript_functions(String &file_content);
- Vector<String> check_for_rename_gdscript_functions(Vector<String> &file_content);
+ void rename_csharp_functions(Vector<String> &lines, const RegExContainer &reg_container);
+ Vector<String> check_for_rename_csharp_functions(Vector<String> &lines, const RegExContainer &reg_container);
+ void process_csharp_line(String &line, const RegExContainer &reg_container);
- void rename_csharp_functions(String &file_content);
- Vector<String> check_for_rename_csharp_functions(Vector<String> &file_content);
+ void rename_csharp_attributes(Vector<String> &lines, const RegExContainer &reg_container);
+ Vector<String> check_for_rename_csharp_attributes(Vector<String> &lines, const RegExContainer &reg_container);
- void rename_gdscript_keywords(String &file_content);
- Vector<String> check_for_rename_gdscript_keywords(Vector<String> &file_content);
+ void rename_gdscript_keywords(Vector<String> &lines, const RegExContainer &reg_container);
+ Vector<String> check_for_rename_gdscript_keywords(Vector<String> &lines, const RegExContainer &reg_container);
- void custom_rename(String &file_content, String from, String to);
- Vector<String> check_for_custom_rename(Vector<String> &file_content, String from, String to);
+ void custom_rename(Vector<String> &lines, String from, String to);
+ Vector<String> check_for_custom_rename(Vector<String> &lines, String from, String to);
- void rename_common(const char *array[][2], String &file_content);
- Vector<String> check_for_rename_common(const char *array[][2], Vector<String> &file_content);
+ void rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<String> &lines);
+ Vector<String> check_for_rename_common(const char *array[][2], LocalVector<RegEx *> &cached_regexes, Vector<String> &lines);
Vector<String> check_for_files();
@@ -68,14 +83,17 @@ class ProjectConverter3To4 {
String line_formatter(int current_line, String from, String to, String line);
String simple_line_formatter(int current_line, String old_line, String line);
+ String collect_string_from_vector(Vector<String> &vector);
bool test_single_array(const char *array[][2], bool ignore_second_check = false);
- bool test_conversion_single_additional(String name, String expected, void (ProjectConverter3To4::*func)(String &), String what);
- bool test_conversion_single_normal(String name, String expected, const char *array[][2], String what);
+ bool test_conversion_gdscript_builtin(String name, String expected, void (ProjectConverter3To4::*func)(Vector<String> &, const RegExContainer &, bool), String what, const RegExContainer &reg_container, bool builtin);
+ bool test_conversion_with_regex(String name, String expected, void (ProjectConverter3To4::*func)(Vector<String> &, const RegExContainer &), String what, const RegExContainer &reg_container);
+ bool test_conversion_basic(String name, String expected, const char *array[][2], LocalVector<RegEx *> &regex_cache, String what);
bool test_array_names();
- bool test_conversion();
+ bool test_conversion(RegExContainer &reg_container);
public:
+ ProjectConverter3To4(int, int);
int validate_conversion();
int convert();
};
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 8395fa996a..9779ce398b 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -42,10 +42,12 @@
#include "core/string/translation.h"
#include "core/version.h"
#include "editor/editor_file_dialog.h"
+#include "editor/editor_paths.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/editor_themes.h"
#include "editor/editor_vcs_interface.h"
+#include "main/main.h"
#include "scene/gui/center_container.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/margin_container.h"
@@ -57,10 +59,6 @@
#include "servers/navigation_server_3d.h"
#include "servers/physics_server_2d.h"
-static inline String get_project_key_from_path(const String &dir) {
- return dir.replace("/", "::");
-}
-
class ProjectDialog : public ConfirmationDialog {
GDCLASS(ProjectDialog, ConfirmationDialog);
@@ -440,7 +438,7 @@ private:
ProjectSettings::CustomMap edited_settings;
edited_settings["application/config/name"] = project_name->get_text().strip_edges();
- if (current->save_custom(dir2.plus_file("project.godot"), edited_settings, Vector<String>(), true) != OK) {
+ if (current->save_custom(dir2.path_join("project.godot"), edited_settings, Vector<String>(), true) != OK) {
set_message(TTR("Couldn't edit project.godot in project path."), MESSAGE_ERROR);
}
}
@@ -486,12 +484,20 @@ private:
project_features.sort();
initial_settings["application/config/features"] = project_features;
initial_settings["application/config/name"] = project_name->get_text().strip_edges();
- initial_settings["application/config/icon"] = "res://icon.png";
+ initial_settings["application/config/icon"] = "res://icon.svg";
- if (ProjectSettings::get_singleton()->save_custom(dir.plus_file("project.godot"), initial_settings, Vector<String>(), false) != OK) {
+ if (ProjectSettings::get_singleton()->save_custom(dir.path_join("project.godot"), initial_settings, Vector<String>(), false) != OK) {
set_message(TTR("Couldn't create project.godot in project path."), MESSAGE_ERROR);
} else {
- ResourceSaver::save(create_unscaled_default_project_icon(), dir.plus_file("icon.png"));
+ // Store default project icon in SVG format.
+ Error err;
+ Ref<FileAccess> fa_icon = FileAccess::open(dir.path_join("icon.svg"), FileAccess::WRITE, &err);
+ fa_icon->store_string(get_default_project_icon());
+
+ if (err != OK) {
+ set_message(TTR("Couldn't create icon.svg in project path."), MESSAGE_ERROR);
+ }
+
EditorVCSInterface::create_vcs_metadata_files(EditorVCSInterface::VCSMetadata(vcs_metadata_selection->get_selected()), dir);
}
} else if (mode == MODE_INSTALL) {
@@ -550,7 +556,7 @@ private:
String rel_path = path.substr(zip_root.length());
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- da->make_dir(dir.plus_file(rel_path));
+ da->make_dir(dir.path_join(rel_path));
} else {
Vector<uint8_t> data;
data.resize(info.uncompressed_size);
@@ -562,7 +568,7 @@ private:
ERR_BREAK_MSG(ret < 0, vformat("An error occurred while attempting to read from file: %s. This file will not be used.", rel_path));
unzCloseCurrentFile(pkg);
- Ref<FileAccess> f = FileAccess::open(dir.plus_file(rel_path), FileAccess::WRITE);
+ Ref<FileAccess> f = FileAccess::open(dir.path_join(rel_path), FileAccess::WRITE);
if (f.is_valid()) {
f->store_buffer(data.ptr(), data.size());
} else {
@@ -600,9 +606,6 @@ private:
if (dir.ends_with("/")) {
dir = dir.substr(0, dir.length() - 1);
}
- String proj = get_project_key_from_path(dir);
- EditorSettings::get_singleton()->set("projects/" + proj, dir);
- EditorSettings::get_singleton()->save();
hide();
emit_signal(SNAME("project_created"), dir);
@@ -989,7 +992,6 @@ public:
// Can often be passed by copy
struct Item {
- String project_key;
String project_name;
String description;
String path;
@@ -1006,8 +1008,7 @@ public:
Item() {}
- Item(const String &p_project,
- const String &p_name,
+ Item(const String &p_name,
const String &p_description,
const String &p_path,
const String &p_icon,
@@ -1018,7 +1019,6 @@ public:
bool p_grayed,
bool p_missing,
int p_version) {
- project_key = p_project;
project_name = p_name;
description = p_description;
path = p_path;
@@ -1034,7 +1034,7 @@ public:
}
_FORCE_INLINE_ bool operator==(const Item &l) const {
- return project_key == l.project_key;
+ return path == l.path;
}
};
@@ -1047,6 +1047,7 @@ public:
void _global_menu_open_project(const Variant &p_tag);
void update_dock_menu();
+ void migrate_config();
void load_projects();
void set_search_term(String p_search_term);
void set_order_option(int p_option);
@@ -1062,6 +1063,8 @@ public:
bool is_any_project_missing() const;
void erase_missing_projects();
int refresh_project(const String &dir_path);
+ void add_project(const String &dir_path, bool favorite);
+ void save_config();
private:
static void _bind_methods();
@@ -1082,12 +1085,15 @@ private:
String _search_term;
FilterOption _order_option;
- HashSet<String> _selected_project_keys;
+ HashSet<String> _selected_project_paths;
String _last_clicked; // Project key
VBoxContainer *_scroll_children;
int _icon_load_index;
Vector<Item> _projects;
+
+ ConfigFile _config;
+ String _config_path;
};
struct ProjectListComparator {
@@ -1103,7 +1109,7 @@ struct ProjectListComparator {
}
switch (order_option) {
case PATH:
- return a.project_key < b.project_key;
+ return a.path < b.path;
case EDIT_DATE:
return a.last_edited > b.last_edited;
default:
@@ -1120,6 +1126,7 @@ ProjectList::ProjectList() {
_icon_load_index = 0;
project_opening_initiated = false;
+ _config_path = EditorPaths::get_singleton()->get_data_dir().path_join("projects.cfg");
}
ProjectList::~ProjectList() {
@@ -1166,14 +1173,19 @@ void ProjectList::load_project_icon(int p_index) {
icon = default_icon;
}
+ // The default project icon is 128×128 to look crisp on hiDPI displays,
+ // but we want the actual displayed size to be 64×64 on loDPI displays.
+ item.control->icon->set_ignore_texture_size(true);
+ item.control->icon->set_custom_minimum_size(Size2(64, 64) * EDSCALE);
+ item.control->icon->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
+
item.control->icon->set_texture(icon);
item.control->icon_needs_reload = false;
}
// Load project data from p_property_key and return it in a ProjectList::Item. p_favorite is passed directly into the Item.
-ProjectList::Item ProjectList::load_project_data(const String &p_property_key, bool p_favorite) {
- String path = EditorSettings::get_singleton()->get(p_property_key);
- String conf = path.plus_file("project.godot");
+ProjectList::Item ProjectList::load_project_data(const String &p_path, bool p_favorite) {
+ String conf = p_path.path_join("project.godot");
bool grayed = false;
bool missing = false;
@@ -1209,7 +1221,7 @@ ProjectList::Item ProjectList::load_project_data(const String &p_property_key, b
// when editing a project (but not when running it).
last_edited = FileAccess::get_modified_time(conf);
- String fscache = path.plus_file(".fscache");
+ String fscache = p_path.path_join(".fscache");
if (FileAccess::exists(fscache)) {
uint64_t cache_modified = FileAccess::get_modified_time(fscache);
if (cache_modified > last_edited) {
@@ -1222,9 +1234,38 @@ ProjectList::Item ProjectList::load_project_data(const String &p_property_key, b
print_line("Project is missing: " + conf);
}
- const String project_key = p_property_key.get_slice("/", 1);
+ return Item(project_name, description, p_path, icon, main_scene, unsupported_features, last_edited, p_favorite, grayed, missing, config_version);
+}
+
+void ProjectList::migrate_config() {
+ // Proposal #1637 moved the project list from editor settings to a separate config file
+ // If the new config file doesn't exist, populate it from EditorSettings
+ if (FileAccess::exists(_config_path)) {
+ return;
+ }
+ print_line("Migrating legacy project list");
+
+ List<PropertyInfo> properties;
+ EditorSettings::get_singleton()->get_property_list(&properties);
+
+ for (const PropertyInfo &E : properties) {
+ // This is actually something like "projects/C:::Documents::Godot::Projects::MyGame"
+ String property_key = E.name;
+ if (!property_key.begins_with("projects/")) {
+ continue;
+ }
+
+ String path = EditorSettings::get_singleton()->get(property_key);
+ String favoriteKey = "favorite_projects/" + property_key.get_slice("/", 1);
+ bool favorite = EditorSettings::get_singleton()->has_setting(favoriteKey);
+ add_project(path, favorite);
+ if (favorite) {
+ EditorSettings::get_singleton()->erase(favoriteKey);
+ }
+ EditorSettings::get_singleton()->erase(property_key);
+ }
- return Item(project_key, project_name, description, path, icon, main_scene, unsupported_features, last_edited, p_favorite, grayed, missing, config_version);
+ save_config();
}
void ProjectList::load_projects() {
@@ -1239,37 +1280,15 @@ void ProjectList::load_projects() {
}
_projects.clear();
_last_clicked = "";
- _selected_project_keys.clear();
-
- // Load data
- // TODO Would be nice to change how projects and favourites are stored... it complicates things a bit.
- // Use a dictionary associating project path to metadata (like is_favorite).
-
- List<PropertyInfo> properties;
- EditorSettings::get_singleton()->get_property_list(&properties);
-
- HashSet<String> favorites;
- // Find favourites...
- for (const PropertyInfo &E : properties) {
- String property_key = E.name;
- if (property_key.begins_with("favorite_projects/")) {
- favorites.insert(property_key);
- }
- }
-
- for (const PropertyInfo &E : properties) {
- // This is actually something like "projects/C:::Documents::Godot::Projects::MyGame"
- String property_key = E.name;
- if (!property_key.begins_with("projects/")) {
- continue;
- }
+ _selected_project_paths.clear();
- String project_key = property_key.get_slice("/", 1);
- bool favorite = favorites.has("favorite_projects/" + project_key);
+ List<String> sections;
+ _config.load(_config_path);
+ _config.get_sections(&sections);
- Item item = load_project_data(property_key, favorite);
-
- _projects.push_back(item);
+ for (const String &path : sections) {
+ bool favorite = _config.get_value(path, "favorite", false);
+ _projects.push_back(load_project_data(path, favorite));
}
// Create controls
@@ -1322,7 +1341,7 @@ void ProjectList::_global_menu_open_project(const Variant &p_tag) {
int idx = (int)p_tag;
if (idx >= 0 && idx < _projects.size()) {
- String conf = _projects[idx].path.plus_file("project.godot");
+ String conf = _projects[idx].path.path_join("project.godot");
List<String> args;
args.push_back(conf);
OS::get_singleton()->create_instance(args);
@@ -1343,7 +1362,7 @@ void ProjectList::create_project_item_control(int p_index) {
hb->connect("draw", callable_mp(this, &ProjectList::_panel_draw).bind(hb));
hb->connect("gui_input", callable_mp(this, &ProjectList::_panel_input).bind(hb));
hb->add_theme_constant_override("separation", 10 * EDSCALE);
- hb->set_tooltip(item.description);
+ hb->set_tooltip_text(item.description);
VBoxContainer *favorite_box = memnew(VBoxContainer);
favorite_box->set_name("FavoriteBox");
@@ -1426,9 +1445,9 @@ void ProjectList::create_project_item_control(int p_index) {
if (!item.missing) {
show->connect("pressed", callable_mp(this, &ProjectList::_show_project).bind(item.path));
- show->set_tooltip(TTR("Show in File Manager"));
+ show->set_tooltip_text(TTR("Show in File Manager"));
} else {
- show->set_tooltip(TTR("Error: Project is missing on the filesystem."));
+ show->set_tooltip_text(TTR("Error: Project is missing on the filesystem."));
}
Label *fpath = memnew(Label(item.path));
@@ -1496,19 +1515,19 @@ void ProjectList::sort_projects() {
const HashSet<String> &ProjectList::get_selected_project_keys() const {
// Faster if that's all you need
- return _selected_project_keys;
+ return _selected_project_paths;
}
Vector<ProjectList::Item> ProjectList::get_selected_projects() const {
Vector<Item> items;
- if (_selected_project_keys.size() == 0) {
+ if (_selected_project_paths.size() == 0) {
return items;
}
- items.resize(_selected_project_keys.size());
+ items.resize(_selected_project_paths.size());
int j = 0;
for (int i = 0; i < _projects.size(); ++i) {
const Item &item = _projects[i];
- if (_selected_project_keys.has(item.project_key)) {
+ if (_selected_project_paths.has(item.path)) {
items.write[j++] = item;
}
}
@@ -1522,41 +1541,40 @@ void ProjectList::ensure_project_visible(int p_index) {
}
int ProjectList::get_single_selected_index() const {
- if (_selected_project_keys.size() == 0) {
+ if (_selected_project_paths.size() == 0) {
// Default selection
return 0;
}
String key;
- if (_selected_project_keys.size() == 1) {
+ if (_selected_project_paths.size() == 1) {
// Only one selected
- key = *_selected_project_keys.begin();
+ key = *_selected_project_paths.begin();
} else {
// Multiple selected, consider the last clicked one as "main"
key = _last_clicked;
}
for (int i = 0; i < _projects.size(); ++i) {
- if (_projects[i].project_key == key) {
+ if (_projects[i].path == key) {
return i;
}
}
return 0;
}
-void ProjectList::remove_project(int p_index, bool p_update_settings) {
+void ProjectList::remove_project(int p_index, bool p_update_config) {
const Item item = _projects[p_index]; // Take a copy
- _selected_project_keys.erase(item.project_key);
+ _selected_project_paths.erase(item.path);
- if (_last_clicked == item.project_key) {
+ if (_last_clicked == item.path) {
_last_clicked = "";
}
memdelete(item.control);
_projects.remove_at(p_index);
- if (p_update_settings) {
- EditorSettings::get_singleton()->erase("projects/" + item.project_key);
- EditorSettings::get_singleton()->erase("favorite_projects/" + item.project_key);
+ if (p_update_config) {
+ _config.erase_section(item.path);
// Not actually saving the file, in case you are doing more changes to settings
}
@@ -1594,41 +1612,19 @@ void ProjectList::erase_missing_projects() {
}
print_line("Removed " + itos(deleted_count) + " projects from the list, remaining " + itos(remaining_count) + " projects");
-
- EditorSettings::get_singleton()->save();
+ save_config();
}
int ProjectList::refresh_project(const String &dir_path) {
- // Reads editor settings and reloads information about a specific project.
+ // Reloads information about a specific project.
// If it wasn't loaded and should be in the list, it is added (i.e new project).
// If it isn't in the list anymore, it is removed.
// If it is in the list but doesn't exist anymore, it is marked as missing.
- String project_key = get_project_key_from_path(dir_path);
-
- // Read project manager settings
- bool is_favourite = false;
- bool should_be_in_list = false;
- String property_key = "projects/" + project_key;
- {
- List<PropertyInfo> properties;
- EditorSettings::get_singleton()->get_property_list(&properties);
- String favorite_property_key = "favorite_projects/" + project_key;
-
- bool found = false;
- for (const PropertyInfo &E : properties) {
- String prop = E.name;
- if (!found && prop == property_key) {
- found = true;
- } else if (!is_favourite && prop == favorite_property_key) {
- is_favourite = true;
- }
- }
-
- should_be_in_list = found;
- }
+ bool should_be_in_list = _config.has_section(dir_path);
+ bool is_favourite = _config.get_value(dir_path, "favorite", false);
- bool was_selected = _selected_project_keys.has(project_key);
+ bool was_selected = _selected_project_paths.has(dir_path);
// Remove item in any case
for (int i = 0; i < _projects.size(); ++i) {
@@ -1643,7 +1639,7 @@ int ProjectList::refresh_project(const String &dir_path) {
if (should_be_in_list) {
// Recreate it with updated info
- Item item = load_project_data(property_key, is_favourite);
+ Item item = load_project_data(dir_path, is_favourite);
_projects.push_back(item);
create_project_item_control(_projects.size() - 1);
@@ -1651,7 +1647,7 @@ int ProjectList::refresh_project(const String &dir_path) {
sort_projects();
for (int i = 0; i < _projects.size(); ++i) {
- if (_projects[i].project_key == project_key) {
+ if (_projects[i].path == dir_path) {
if (was_selected) {
select_project(i);
ensure_project_visible(i);
@@ -1667,13 +1663,23 @@ int ProjectList::refresh_project(const String &dir_path) {
return index;
}
+void ProjectList::add_project(const String &dir_path, bool favorite) {
+ if (!_config.has_section(dir_path)) {
+ _config.set_value(dir_path, "favorite", favorite);
+ }
+}
+
+void ProjectList::save_config() {
+ _config.save(_config_path);
+}
+
int ProjectList::get_project_count() const {
return _projects.size();
}
void ProjectList::select_project(int p_index) {
Vector<Item> previous_selected_items = get_selected_projects();
- _selected_project_keys.clear();
+ _selected_project_paths.clear();
for (int i = 0; i < previous_selected_items.size(); ++i) {
previous_selected_items[i].control->update();
@@ -1695,7 +1701,7 @@ void ProjectList::select_first_visible_project() {
if (!found) {
// Deselect all projects if there are no visible projects in the list.
- _selected_project_keys.clear();
+ _selected_project_paths.clear();
}
}
@@ -1717,24 +1723,23 @@ void ProjectList::select_range(int p_begin, int p_end) {
void ProjectList::toggle_select(int p_index) {
Item &item = _projects.write[p_index];
- if (_selected_project_keys.has(item.project_key)) {
- _selected_project_keys.erase(item.project_key);
+ if (_selected_project_paths.has(item.path)) {
+ _selected_project_paths.erase(item.path);
} else {
- _selected_project_keys.insert(item.project_key);
+ _selected_project_paths.insert(item.path);
}
item.control->update();
}
void ProjectList::erase_selected_projects(bool p_delete_project_contents) {
- if (_selected_project_keys.size() == 0) {
+ if (_selected_project_paths.size() == 0) {
return;
}
for (int i = 0; i < _projects.size(); ++i) {
Item &item = _projects.write[i];
- if (_selected_project_keys.has(item.project_key) && item.control->is_visible()) {
- EditorSettings::get_singleton()->erase("projects/" + item.project_key);
- EditorSettings::get_singleton()->erase("favorite_projects/" + item.project_key);
+ if (_selected_project_paths.has(item.path) && item.control->is_visible()) {
+ _config.erase_section(item.path);
if (p_delete_project_contents) {
OS::get_singleton()->move_to_trash(item.path);
@@ -1746,9 +1751,8 @@ void ProjectList::erase_selected_projects(bool p_delete_project_contents) {
}
}
- EditorSettings::get_singleton()->save();
-
- _selected_project_keys.clear();
+ save_config();
+ _selected_project_paths.clear();
_last_clicked = "";
update_dock_menu();
@@ -1764,9 +1768,9 @@ void ProjectList::_panel_draw(Node *p_hb) {
hb->draw_line(Point2(0, hb->get_size().y + 1), Point2(hb->get_size().x, hb->get_size().y + 1), get_theme_color(SNAME("guide_color"), SNAME("Tree")));
}
- String key = _projects[p_hb->get_index()].project_key;
+ String key = _projects[p_hb->get_index()].path;
- if (_selected_project_keys.has(key)) {
+ if (_selected_project_paths.has(key)) {
hb->draw_style_box(get_theme_stylebox(SNAME("selected"), SNAME("Tree")), Rect2(Point2(), hb->get_size()));
}
}
@@ -1778,11 +1782,11 @@ void ProjectList::_panel_input(const Ref<InputEvent> &p_ev, Node *p_hb) {
const Item &clicked_project = _projects[clicked_index];
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
- if (mb->is_shift_pressed() && _selected_project_keys.size() > 0 && !_last_clicked.is_empty() && clicked_project.project_key != _last_clicked) {
+ if (mb->is_shift_pressed() && _selected_project_paths.size() > 0 && !_last_clicked.is_empty() && clicked_project.path != _last_clicked) {
int anchor_index = -1;
for (int i = 0; i < _projects.size(); ++i) {
const Item &p = _projects[i];
- if (p.project_key == _last_clicked) {
+ if (p.path == _last_clicked) {
anchor_index = p.control->get_index();
break;
}
@@ -1794,7 +1798,7 @@ void ProjectList::_panel_input(const Ref<InputEvent> &p_ev, Node *p_hb) {
toggle_select(clicked_index);
} else {
- _last_clicked = clicked_project.project_key;
+ _last_clicked = clicked_project.path;
select_project(clicked_index);
}
@@ -1816,12 +1820,8 @@ void ProjectList::_favorite_pressed(Node *p_hb) {
item.favorite = !item.favorite;
- if (item.favorite) {
- EditorSettings::get_singleton()->set("favorite_projects/" + item.project_key, item.path);
- } else {
- EditorSettings::get_singleton()->erase("favorite_projects/" + item.project_key);
- }
- EditorSettings::get_singleton()->save();
+ _config.set_value(item.path, "favorite", item.favorite);
+ save_config();
_projects.write[index] = item;
@@ -1831,7 +1831,7 @@ void ProjectList::_favorite_pressed(Node *p_hb) {
if (item.favorite) {
for (int i = 0; i < _projects.size(); ++i) {
- if (_projects[i].project_key == item.project_key) {
+ if (_projects[i].path == item.path) {
ensure_project_visible(i);
break;
}
@@ -2089,6 +2089,8 @@ void ProjectManager::_on_projects_updated() {
}
void ProjectManager::_on_project_created(const String &dir) {
+ _project_list->add_project(dir, false);
+ _project_list->save_config();
search_box->clear();
int i = _project_list->refresh_project(dir);
_project_list->select_project(i);
@@ -2104,15 +2106,13 @@ void ProjectManager::_confirm_update_settings() {
void ProjectManager::_open_selected_projects() {
// Show loading text to tell the user that the project manager is busy loading.
- // This is especially important for the HTML5 project manager.
+ // This is especially important for the Web project manager.
loading_label->show();
const HashSet<String> &selected_list = _project_list->get_selected_project_keys();
- for (const String &E : selected_list) {
- const String &selected = E;
- String path = EditorSettings::get_singleton()->get("projects/" + selected);
- String conf = path.plus_file("project.godot");
+ for (const String &path : selected_list) {
+ String conf = path.path_join("project.godot");
if (!FileAccess::exists(conf)) {
dialog_error->set_text(vformat(TTR("Can't open project at '%s'."), path));
@@ -2120,31 +2120,19 @@ void ProjectManager::_open_selected_projects() {
return;
}
- print_line("Editing project: " + path + " (" + selected + ")");
+ print_line("Editing project: " + path);
List<String> args;
+ for (const String &a : Main::get_forwardable_cli_arguments(Main::CLI_SCOPE_TOOL)) {
+ args.push_back(a);
+ }
+
args.push_back("--path");
args.push_back(path);
args.push_back("--editor");
- if (OS::get_singleton()->is_stdout_debug_enabled()) {
- args.push_back("--debug");
- }
-
- if (OS::get_singleton()->is_stdout_verbose()) {
- args.push_back("--verbose");
- }
-
- if (OS::get_singleton()->is_disable_crash_handler()) {
- args.push_back("--disable-crash-handler");
- }
-
- if (OS::get_singleton()->is_single_window()) {
- args.push_back("--single-window");
- }
-
Error err = OS::get_singleton()->create_instance(args);
ERR_FAIL_COND(err);
}
@@ -2174,7 +2162,7 @@ void ProjectManager::_open_selected_projects_ask() {
}
// Update the project settings or don't open
- const String conf = project.path.plus_file("project.godot");
+ const String conf = project.path.path_join("project.godot");
const int config_version = project.version;
PackedStringArray unsupported_features = project.unsupported_features;
@@ -2244,27 +2232,26 @@ void ProjectManager::_run_project_confirm() {
continue;
}
- const String &selected = selected_list[i].project_key;
- String path = EditorSettings::get_singleton()->get("projects/" + selected);
+ const String &path = selected_list[i].path;
// `.substr(6)` on `ProjectSettings::get_singleton()->get_imported_files_path()` strips away the leading "res://".
- if (!DirAccess::exists(path.plus_file(ProjectSettings::get_singleton()->get_imported_files_path().substr(6)))) {
+ if (!DirAccess::exists(path.path_join(ProjectSettings::get_singleton()->get_imported_files_path().substr(6)))) {
run_error_diag->set_text(TTR("Can't run project: Assets need to be imported.\nPlease edit the project to trigger the initial import."));
run_error_diag->popup_centered();
continue;
}
- print_line("Running project: " + path + " (" + selected + ")");
+ print_line("Running project: " + path);
List<String> args;
+ for (const String &a : Main::get_forwardable_cli_arguments(Main::CLI_SCOPE_PROJECT)) {
+ args.push_back(a);
+ }
+
args.push_back("--path");
args.push_back(path);
- if (OS::get_singleton()->is_disable_crash_handler()) {
- args.push_back("--disable-crash-handler");
- }
-
Error err = OS::get_singleton()->create_instance(args);
ERR_FAIL_COND(err);
}
@@ -2285,7 +2272,7 @@ void ProjectManager::_run_project() {
}
}
-void ProjectManager::_scan_dir(const String &path, List<String> *r_projects) {
+void ProjectManager::_scan_dir(const String &path) {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
Error error = da->change_dir(path);
ERR_FAIL_COND_MSG(error != OK, "Could not scan directory at: " + path);
@@ -2293,26 +2280,18 @@ void ProjectManager::_scan_dir(const String &path, List<String> *r_projects) {
String n = da->get_next();
while (!n.is_empty()) {
if (da->current_is_dir() && !n.begins_with(".")) {
- _scan_dir(da->get_current_dir().plus_file(n), r_projects);
+ _scan_dir(da->get_current_dir().path_join(n));
} else if (n == "project.godot") {
- r_projects->push_back(da->get_current_dir());
+ _project_list->add_project(da->get_current_dir(), false);
}
n = da->get_next();
}
da->list_dir_end();
}
-
void ProjectManager::_scan_begin(const String &p_base) {
print_line("Scanning projects at: " + p_base);
- List<String> projects;
- _scan_dir(p_base, &projects);
- print_line("Found " + itos(projects.size()) + " projects.");
-
- for (const String &E : projects) {
- String proj = get_project_key_from_path(E);
- EditorSettings::get_singleton()->set("projects/" + proj, E);
- }
- EditorSettings::get_singleton()->save();
+ _scan_dir(p_base);
+ _project_list->save_config();
_load_recent_projects();
}
@@ -2338,9 +2317,7 @@ void ProjectManager::_rename_project() {
}
for (const String &E : selected_list) {
- const String &selected = E;
- String path = EditorSettings::get_singleton()->get("projects/" + selected);
- npdialog->set_project_path(path);
+ npdialog->set_project_path(E);
npdialog->set_mode(ProjectDialog::MODE_RENAME);
npdialog->show_dialog();
}
@@ -2593,7 +2570,7 @@ ProjectManager::ProjectManager() {
search_box = memnew(LineEdit);
search_box->set_placeholder(TTR("Filter Projects"));
- search_box->set_tooltip(TTR("This field 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->set_tooltip_text(TTR("This field 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);
@@ -2733,7 +2710,7 @@ ProjectManager::ProjectManager() {
// Fade the version label to be less prominent, but still readable.
version_btn->set_self_modulate(Color(1, 1, 1, 0.6));
version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER);
- version_btn->set_tooltip(TTR("Click to copy."));
+ version_btn->set_tooltip_text(TTR("Click to copy."));
version_btn->connect("pressed", callable_mp(this, &ProjectManager::_version_button_pressed));
spacer_vb->add_child(version_btn);
@@ -2871,6 +2848,7 @@ ProjectManager::ProjectManager() {
_build_icon_type_cache(get_theme());
}
+ _project_list->migrate_config();
_load_recent_projects();
Ref<DirAccess> dir_access = DirAccess::create(DirAccess::AccessType::ACCESS_FILESYSTEM);
diff --git a/editor/project_manager.h b/editor/project_manager.h
index 28383e4142..10bf25c048 100644
--- a/editor/project_manager.h
+++ b/editor/project_manager.h
@@ -125,7 +125,7 @@ class ProjectManager : public Control {
void _on_projects_updated();
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 _scan_dir(const String &path);
void _install_project(const String &p_zip_path, const String &p_title);
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index fba8c5c522..581315d512 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -35,10 +35,15 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "servers/movie_writer/movie_writer.h"
ProjectSettingsEditor *ProjectSettingsEditor::singleton = nullptr;
+void ProjectSettingsEditor::connect_filesystem_dock_signals(FileSystemDock *p_fs_dock) {
+ localization_editor->connect_filesystem_dock_signals(p_fs_dock);
+}
+
void ProjectSettingsEditor::popup_project_settings() {
// Restore valid window bounds or pop up at default size.
Rect2 saved_size = EditorSettings::get_singleton()->get_project_metadata("dialog_bounds", "project_settings", Rect2());
@@ -562,7 +567,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
set_title(TTR("Project Settings (project.godot)"));
ps = ProjectSettings::get_singleton();
- undo_redo = &p_data->get_undo_redo();
+ undo_redo = p_data->get_undo_redo();
data = p_data;
tab_container = memnew(TabContainer);
@@ -621,7 +626,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
custom_properties->add_child(del_button);
general_settings_inspector = memnew(SectionedInspector);
- general_settings_inspector->get_inspector()->set_undo_redo(EditorNode::get_singleton()->get_undo_redo());
+ general_settings_inspector->get_inspector()->set_undo_redo(EditorNode::get_undo_redo());
general_settings_inspector->set_v_size_flags(Control::SIZE_EXPAND_FILL);
general_settings_inspector->register_search_box(search_box);
general_settings_inspector->get_inspector()->set_use_filter(true);
diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h
index 849c50b9ba..040d992e40 100644
--- a/editor/project_settings_editor.h
+++ b/editor/project_settings_editor.h
@@ -32,7 +32,6 @@
#define PROJECT_SETTINGS_EDITOR_H
#include "core/config/project_settings.h"
-#include "core/object/undo_redo.h"
#include "editor/action_map_editor.h"
#include "editor/editor_autoload_settings.h"
#include "editor/editor_data.h"
@@ -43,6 +42,9 @@
#include "editor/shader_globals_editor.h"
#include "scene/gui/tab_container.h"
+class EditorUndoRedoManager;
+class FileSystemDock;
+
class ProjectSettingsEditor : public AcceptDialog {
GDCLASS(ProjectSettingsEditor, AcceptDialog);
@@ -75,7 +77,7 @@ class ProjectSettingsEditor : public AcceptDialog {
ImportDefaultsEditor *import_defaults_editor = nullptr;
EditorData *data = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
void _advanced_toggled(bool p_button_pressed);
void _update_advanced(bool p_is_advanced);
@@ -120,6 +122,7 @@ public:
TabContainer *get_tabs() { return tab_container; }
void queue_save();
+ void connect_filesystem_dock_signals(FileSystemDock *p_fs_dock);
ProjectSettingsEditor(EditorData *p_data);
};
diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp
deleted file mode 100644
index 4092cc47e3..0000000000
--- a/editor/property_editor.cpp
+++ /dev/null
@@ -1,1866 +0,0 @@
-/*************************************************************************/
-/* property_editor.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "property_editor.h"
-
-#include "core/config/project_settings.h"
-#include "core/input/input.h"
-#include "core/io/image_loader.h"
-#include "core/io/marshalls.h"
-#include "core/io/resource_loader.h"
-#include "core/math/expression.h"
-#include "core/object/class_db.h"
-#include "core/os/keyboard.h"
-#include "core/string/print_string.h"
-#include "core/templates/pair.h"
-#include "editor/array_property_edit.h"
-#include "editor/create_dialog.h"
-#include "editor/dictionary_property_edit.h"
-#include "editor/editor_file_dialog.h"
-#include "editor/editor_file_system.h"
-#include "editor/editor_help.h"
-#include "editor/editor_node.h"
-#include "editor/editor_scale.h"
-#include "editor/editor_settings.h"
-#include "editor/filesystem_dock.h"
-#include "editor/multi_node_edit.h"
-#include "editor/plugins/editor_resource_conversion_plugin.h"
-#include "editor/property_selector.h"
-#include "editor/scene_tree_dock.h"
-#include "scene/gui/label.h"
-#include "scene/main/window.h"
-#include "scene/resources/font.h"
-#include "scene/resources/packed_scene.h"
-#include "scene/scene_string_names.h"
-
-void CustomPropertyEditor::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_WM_CLOSE_REQUEST: {
- hide();
- } break;
- }
-}
-
-void CustomPropertyEditor::_menu_option(int p_which) {
- switch (type) {
- case Variant::INT: {
- if (hint == PROPERTY_HINT_FLAGS) {
- int idx = menu->get_item_index(p_which);
- uint32_t item_value = menu->get_item_metadata(idx);
- uint32_t value = v;
- // If the item wasn't previously checked it means it was pressed,
- // otherwise it was unpressed.
- if (!menu->is_item_checked(idx)) {
- v = value | item_value;
- } else {
- v = value & ~item_value;
- }
- emit_signal(SNAME("variant_changed"));
- } else if (hint == PROPERTY_HINT_ENUM) {
- v = menu->get_item_metadata(p_which);
- emit_signal(SNAME("variant_changed"));
- }
- } break;
- case Variant::STRING: {
- if (hint == PROPERTY_HINT_ENUM) {
- v = hint_text.get_slice(",", p_which);
- emit_signal(SNAME("variant_changed"));
- }
- } break;
- case Variant::OBJECT: {
- switch (p_which) {
- case OBJ_MENU_LOAD: {
- file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
- String type = (hint == PROPERTY_HINT_RESOURCE_TYPE) ? hint_text : String();
-
- List<String> extensions;
- for (int i = 0; i < type.get_slice_count(","); i++) {
- ResourceLoader::get_recognized_extensions_for_type(type.get_slice(",", i), &extensions);
- }
-
- HashSet<String> valid_extensions;
- for (const String &E : extensions) {
- valid_extensions.insert(E);
- }
-
- file->clear_filters();
- for (const String &E : valid_extensions) {
- file->add_filter("*." + E, E.to_upper());
- }
-
- file->popup_file_dialog();
- } break;
-
- case OBJ_MENU_EDIT: {
- Ref<RefCounted> r = v;
-
- if (!r.is_null()) {
- emit_signal(SNAME("resource_edit_request"));
- hide();
- }
- } break;
- case OBJ_MENU_CLEAR: {
- v = Variant();
- emit_signal(SNAME("variant_changed"));
- hide();
- } break;
-
- case OBJ_MENU_MAKE_UNIQUE: {
- Ref<Resource> res_orig = v;
- if (res_orig.is_null()) {
- return;
- }
-
- List<PropertyInfo> property_list;
- res_orig->get_property_list(&property_list);
- List<Pair<String, Variant>> propvalues;
-
- for (const PropertyInfo &pi : property_list) {
- Pair<String, Variant> p;
- if (pi.usage & PROPERTY_USAGE_STORAGE) {
- p.first = pi.name;
- p.second = res_orig->get(pi.name);
- }
-
- propvalues.push_back(p);
- }
-
- String orig_type = res_orig->get_class();
-
- Object *inst = ClassDB::instantiate(orig_type);
-
- Ref<Resource> res = Ref<Resource>(Object::cast_to<Resource>(inst));
-
- ERR_FAIL_COND(res.is_null());
-
- for (const Pair<String, Variant> &p : propvalues) {
- res->set(p.first, p.second);
- }
-
- v = res;
- emit_signal(SNAME("variant_changed"));
- hide();
- } break;
-
- case OBJ_MENU_COPY: {
- EditorSettings::get_singleton()->set_resource_clipboard(v);
-
- } break;
- case OBJ_MENU_PASTE: {
- v = EditorSettings::get_singleton()->get_resource_clipboard();
- emit_signal(SNAME("variant_changed"));
-
- } break;
- case OBJ_MENU_NEW_SCRIPT: {
- if (Object::cast_to<Node>(owner)) {
- SceneTreeDock::get_singleton()->open_script_dialog(Object::cast_to<Node>(owner), false);
- }
-
- } break;
- case OBJ_MENU_EXTEND_SCRIPT: {
- if (Object::cast_to<Node>(owner)) {
- SceneTreeDock::get_singleton()->open_script_dialog(Object::cast_to<Node>(owner), true);
- }
-
- } break;
- case OBJ_MENU_SHOW_IN_FILE_SYSTEM: {
- Ref<Resource> r = v;
- FileSystemDock *file_system_dock = FileSystemDock::get_singleton();
- file_system_dock->navigate_to_path(r->get_path());
- // Ensure that the FileSystem dock is visible.
- TabContainer *tab_container = (TabContainer *)file_system_dock->get_parent_control();
- tab_container->set_current_tab(tab_container->get_tab_idx_from_control(file_system_dock));
- } break;
- default: {
- if (p_which >= CONVERT_BASE_ID) {
- int to_type = p_which - CONVERT_BASE_ID;
-
- Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(Ref<Resource>(v));
-
- ERR_FAIL_INDEX(to_type, conversions.size());
-
- Ref<Resource> new_res = conversions[to_type]->convert(v);
-
- v = new_res;
- emit_signal(SNAME("variant_changed"));
- break;
- }
- ERR_FAIL_COND(inheritors_array.is_empty());
-
- String intype = inheritors_array[p_which - TYPE_BASE_ID];
-
- if (intype == "ViewportTexture") {
- scene_tree->set_title(TTR("Pick a Viewport"));
- scene_tree->popup_scenetree_dialog();
- picking_viewport = true;
- return;
- }
-
- Variant obj = ClassDB::instantiate(intype);
-
- if (!obj) {
- if (ScriptServer::is_global_class(intype)) {
- obj = EditorNode::get_editor_data().script_class_instance(intype);
- } else {
- obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource");
- }
- }
-
- ERR_BREAK(!obj);
- Resource *res = Object::cast_to<Resource>(obj);
- ERR_BREAK(!res);
- if (owner && hint == PROPERTY_HINT_RESOURCE_TYPE && hint_text == "Script") {
- //make visual script the right type
- res->call("set_instance_base_type", owner->get_class());
- }
-
- EditorNode::get_editor_data().instantiate_object_properties(obj);
- v = obj;
-
- emit_signal(SNAME("variant_changed"));
-
- } break;
- }
-
- } break;
- default: {
- }
- }
-}
-
-void CustomPropertyEditor::hide_menu() {
- menu->hide();
-}
-
-Variant CustomPropertyEditor::get_variant() const {
- return v;
-}
-
-String CustomPropertyEditor::get_name() const {
- return name;
-}
-
-bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::Type p_type, const Variant &p_variant, int p_hint, String p_hint_text) {
- owner = p_owner;
- updating = true;
- name = p_name;
- v = p_variant;
- field_names.clear();
- hint = p_hint;
- hint_text = p_hint_text;
- type_button->hide();
- if (color_picker) {
- color_picker->hide();
- }
- texture_preview->hide();
- inheritors_array.clear();
- text_edit->hide();
- easing_draw->hide();
- spinbox->hide();
- slider->hide();
- menu->clear();
- menu->reset_size();
-
- for (int i = 0; i < MAX_VALUE_EDITORS; i++) {
- if (i < MAX_VALUE_EDITORS / 4) {
- value_hboxes[i]->hide();
- }
- value_editor[i]->hide();
- value_label[i]->hide();
- if (i < 4) {
- scroll[i]->hide();
- }
- }
-
- for (int i = 0; i < MAX_ACTION_BUTTONS; i++) {
- action_buttons[i]->hide();
- }
-
- checks20gc->hide();
- for (int i = 0; i < 20; i++) {
- checks20[i]->hide();
- }
-
- type = (p_variant.get_type() != Variant::NIL && p_variant.get_type() != Variant::RID && p_type != Variant::OBJECT) ? p_variant.get_type() : p_type;
-
- switch (type) {
- case Variant::BOOL: {
- checks20gc->show();
-
- CheckBox *c = checks20[0];
- c->set_text("True");
- checks20gc->set_position(Vector2(4, 4) * EDSCALE);
- c->set_pressed(v);
- c->show();
-
- checks20gc->set_size(checks20gc->get_minimum_size());
- set_size(checks20gc->get_position() + checks20gc->get_size() + c->get_size() + Vector2(4, 4) * EDSCALE);
-
- } break;
- case Variant::INT:
- case Variant::FLOAT: {
- if (hint == PROPERTY_HINT_RANGE) {
- int c = hint_text.get_slice_count(",");
- float min = 0, max = 100, step = type == Variant::FLOAT ? .01 : 1;
- if (c >= 1) {
- if (!hint_text.get_slice(",", 0).is_empty()) {
- min = hint_text.get_slice(",", 0).to_float();
- }
- }
- if (c >= 2) {
- if (!hint_text.get_slice(",", 1).is_empty()) {
- max = hint_text.get_slice(",", 1).to_float();
- }
- }
-
- if (c >= 3) {
- if (!hint_text.get_slice(",", 2).is_empty()) {
- step = hint_text.get_slice(",", 2).to_float();
- }
- }
-
- if (c >= 4 && hint_text.get_slice(",", 3) == "slider") {
- slider->set_min(min);
- slider->set_max(max);
- slider->set_step(step);
- slider->set_value(v);
- slider->show();
- set_size(Size2(110, 30) * EDSCALE);
- } else {
- spinbox->set_min(min);
- spinbox->set_max(max);
- spinbox->set_step(step);
- spinbox->set_value(v);
- spinbox->show();
- set_size(Size2(70, 35) * EDSCALE);
- }
-
- } else if (hint == PROPERTY_HINT_ENUM) {
- Vector<String> options = hint_text.split(",");
- int current_val = 0;
- for (int i = 0; i < options.size(); i++) {
- Vector<String> text_split = options[i].split(":");
- if (text_split.size() != 1) {
- current_val = text_split[1].to_int();
- }
- menu->add_item(text_split[0]);
- menu->set_item_metadata(i, current_val);
- current_val += 1;
- }
- menu->set_position(get_position());
- menu->popup();
- hide();
- updating = false;
- return false;
-
- } else if (hint == PROPERTY_HINT_LAYERS_2D_PHYSICS ||
- hint == PROPERTY_HINT_LAYERS_2D_RENDER ||
- hint == PROPERTY_HINT_LAYERS_2D_NAVIGATION ||
- hint == PROPERTY_HINT_LAYERS_3D_PHYSICS ||
- hint == PROPERTY_HINT_LAYERS_3D_RENDER ||
- hint == PROPERTY_HINT_LAYERS_3D_NAVIGATION) {
- String basename;
- switch (hint) {
- case PROPERTY_HINT_LAYERS_2D_RENDER:
- basename = "layer_names/2d_render";
- break;
- case PROPERTY_HINT_LAYERS_2D_PHYSICS:
- basename = "layer_names/2d_physics";
- break;
- case PROPERTY_HINT_LAYERS_2D_NAVIGATION:
- basename = "layer_names/2d_navigation";
- break;
- case PROPERTY_HINT_LAYERS_3D_RENDER:
- basename = "layer_names/3d_render";
- break;
- case PROPERTY_HINT_LAYERS_3D_PHYSICS:
- basename = "layer_names/3d_physics";
- break;
- case PROPERTY_HINT_LAYERS_3D_NAVIGATION:
- basename = "layer_names/3d_navigation";
- break;
- }
-
- checks20gc->show();
- uint32_t flgs = v;
- for (int i = 0; i < 2; i++) {
- Point2 ofs(4, 4);
- ofs.y += 22 * i;
- for (int j = 0; j < 10; j++) {
- int idx = i * 10 + j;
- CheckBox *c = checks20[idx];
- c->set_text(ProjectSettings::get_singleton()->get(basename + "/layer_" + itos(idx + 1)));
- c->set_pressed(flgs & (1 << (i * 10 + j)));
- c->show();
- }
- }
-
- show();
-
- checks20gc->set_position(Vector2(4, 4) * EDSCALE);
- checks20gc->set_size(checks20gc->get_minimum_size());
-
- set_size(Vector2(4, 4) * EDSCALE + checks20gc->get_position() + checks20gc->get_size());
-
- } else if (hint == PROPERTY_HINT_EXP_EASING) {
- easing_draw->set_anchor_and_offset(SIDE_LEFT, Control::ANCHOR_BEGIN, 5 * EDSCALE);
- easing_draw->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, -5 * EDSCALE);
- easing_draw->set_anchor_and_offset(SIDE_TOP, Control::ANCHOR_BEGIN, 5 * EDSCALE);
- easing_draw->set_anchor_and_offset(SIDE_BOTTOM, Control::ANCHOR_END, -30 * EDSCALE);
- type_button->set_anchor_and_offset(SIDE_LEFT, Control::ANCHOR_BEGIN, 3 * EDSCALE);
- type_button->set_anchor_and_offset(SIDE_RIGHT, Control::ANCHOR_END, -3 * EDSCALE);
- type_button->set_anchor_and_offset(SIDE_TOP, Control::ANCHOR_END, -25 * EDSCALE);
- type_button->set_anchor_and_offset(SIDE_BOTTOM, Control::ANCHOR_END, -7 * EDSCALE);
- type_button->set_text(TTR("Preset..."));
- type_button->get_popup()->clear();
- type_button->get_popup()->add_item(TTR("Linear"), EASING_LINEAR);
- type_button->get_popup()->add_item(TTR("Ease In"), EASING_EASE_IN);
- type_button->get_popup()->add_item(TTR("Ease Out"), EASING_EASE_OUT);
- if (hint_text != "attenuation") {
- type_button->get_popup()->add_item(TTR("Zero"), EASING_ZERO);
- type_button->get_popup()->add_item(TTR("Easing In-Out"), EASING_IN_OUT);
- type_button->get_popup()->add_item(TTR("Easing Out-In"), EASING_OUT_IN);
- }
-
- type_button->show();
- easing_draw->show();
- set_size(Size2(200, 150) * EDSCALE);
- } else if (hint == PROPERTY_HINT_FLAGS) {
- Vector<String> flags = hint_text.split(",");
- uint32_t value = v;
- for (int i = 0; i < flags.size(); i++) {
- uint32_t current_val;
- Vector<String> text_split = flags[i].split(":");
- if (text_split.size() != 1) {
- current_val = text_split[1].to_int();
- } else {
- current_val = 1 << i;
- }
- menu->add_check_item(text_split[0], current_val);
- menu->set_item_metadata(i, current_val);
- if ((value & current_val) == current_val) {
- menu->set_item_checked(menu->get_item_index(current_val), true);
- }
- }
- menu->set_position(get_position());
- menu->popup();
- hide();
- updating = false;
- return false;
-
- } else {
- List<String> names;
- names.push_back("value:");
- config_value_editors(1, 1, 50, names);
- value_editor[0]->set_text(TS->format_number(String::num(v)));
- }
-
- } break;
- case Variant::STRING: {
- if (hint == PROPERTY_HINT_LOCALE_ID) {
- List<String> names;
- names.push_back(TTR("Locale..."));
- names.push_back(TTR("Clear"));
- config_action_buttons(names);
- } else if (hint == PROPERTY_HINT_FILE || hint == PROPERTY_HINT_GLOBAL_FILE) {
- List<String> names;
- names.push_back(TTR("File..."));
- names.push_back(TTR("Clear"));
- config_action_buttons(names);
- } else if (hint == PROPERTY_HINT_DIR || hint == PROPERTY_HINT_GLOBAL_DIR) {
- List<String> names;
- names.push_back(TTR("Dir..."));
- names.push_back(TTR("Clear"));
- config_action_buttons(names);
- } else if (hint == PROPERTY_HINT_ENUM) {
- Vector<String> options = hint_text.split(",");
- for (int i = 0; i < options.size(); i++) {
- menu->add_item(options[i], i);
- }
- menu->set_position(get_position());
- menu->popup();
- hide();
- updating = false;
- return false;
-
- } else if (hint == PROPERTY_HINT_MULTILINE_TEXT) {
- text_edit->show();
- text_edit->set_text(v);
- text_edit->deselect();
-
- int button_margin = text_edit->get_theme_constant(SNAME("button_margin"), SNAME("Dialogs"));
- int margin = text_edit->get_theme_constant(SNAME("margin"), SNAME("Dialogs"));
-
- action_buttons[0]->set_anchor(SIDE_LEFT, Control::ANCHOR_END);
- action_buttons[0]->set_anchor(SIDE_TOP, Control::ANCHOR_END);
- action_buttons[0]->set_anchor(SIDE_RIGHT, Control::ANCHOR_END);
- action_buttons[0]->set_anchor(SIDE_BOTTOM, Control::ANCHOR_END);
- action_buttons[0]->set_begin(Point2(-70 * EDSCALE, -button_margin + 5 * EDSCALE));
- action_buttons[0]->set_end(Point2(-margin, -margin));
- action_buttons[0]->set_text(TTR("Close"));
- action_buttons[0]->show();
-
- } else if (hint == PROPERTY_HINT_TYPE_STRING) {
- if (!create_dialog) {
- create_dialog = memnew(CreateDialog);
- create_dialog->connect("create", callable_mp(this, &CustomPropertyEditor::_create_dialog_callback));
- add_child(create_dialog);
- }
-
- if (!hint_text.is_empty()) {
- create_dialog->set_base_type(hint_text);
- } else {
- create_dialog->set_base_type("Object");
- }
-
- create_dialog->popup_create(false);
- hide();
- updating = false;
- return false;
-
- } else if (hint == PROPERTY_HINT_METHOD_OF_VARIANT_TYPE) {
-#define MAKE_PROPSELECT \
- if (!property_select) { \
- property_select = memnew(PropertySelector); \
- property_select->connect("selected", callable_mp(this, &CustomPropertyEditor::_create_selected_property)); \
- add_child(property_select); \
- } \
- hide();
-
- MAKE_PROPSELECT;
-
- Variant::Type type = Variant::NIL;
- for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- if (hint_text == Variant::get_type_name(Variant::Type(i))) {
- type = Variant::Type(i);
- }
- }
- if (type != Variant::NIL) {
- property_select->select_method_from_basic_type(type, v);
- }
- updating = false;
- return false;
-
- } else if (hint == PROPERTY_HINT_METHOD_OF_BASE_TYPE) {
- MAKE_PROPSELECT
-
- property_select->select_method_from_base_type(hint_text, v);
-
- updating = false;
- return false;
-
- } else if (hint == PROPERTY_HINT_METHOD_OF_INSTANCE) {
- MAKE_PROPSELECT
-
- Object *instance = ObjectDB::get_instance(ObjectID(hint_text.to_int()));
- if (instance) {
- property_select->select_method_from_instance(instance, v);
- }
- updating = false;
- return false;
-
- } else if (hint == PROPERTY_HINT_METHOD_OF_SCRIPT) {
- MAKE_PROPSELECT
-
- Object *obj = ObjectDB::get_instance(ObjectID(hint_text.to_int()));
- if (Object::cast_to<Script>(obj)) {
- property_select->select_method_from_script(Object::cast_to<Script>(obj), v);
- }
-
- updating = false;
- return false;
-
- } else if (hint == PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE) {
- MAKE_PROPSELECT
- Variant::Type type = Variant::NIL;
- String tname = hint_text;
- if (tname.contains(".")) {
- tname = tname.get_slice(".", 0);
- }
- for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- if (tname == Variant::get_type_name(Variant::Type(i))) {
- type = Variant::Type(Variant::Type(i));
- }
- }
-
- if (type != Variant::NIL) {
- property_select->select_property_from_basic_type(type, v);
- }
-
- updating = false;
- return false;
-
- } else if (hint == PROPERTY_HINT_PROPERTY_OF_BASE_TYPE) {
- MAKE_PROPSELECT
-
- property_select->select_property_from_base_type(hint_text, v);
-
- updating = false;
- return false;
-
- } else if (hint == PROPERTY_HINT_PROPERTY_OF_INSTANCE) {
- MAKE_PROPSELECT
-
- Object *instance = ObjectDB::get_instance(ObjectID(hint_text.to_int()));
- if (instance) {
- property_select->select_property_from_instance(instance, v);
- }
-
- updating = false;
- return false;
-
- } else if (hint == PROPERTY_HINT_PROPERTY_OF_SCRIPT) {
- MAKE_PROPSELECT
-
- Object *obj = ObjectDB::get_instance(ObjectID(hint_text.to_int()));
- if (Object::cast_to<Script>(obj)) {
- property_select->select_property_from_script(Object::cast_to<Script>(obj), v);
- }
-
- updating = false;
- return false;
-
- } else {
- List<String> names;
- names.push_back("string:");
- config_value_editors(1, 1, 50, names);
- value_editor[0]->set_text(v);
- }
-
- } break;
- case Variant::VECTOR2: {
- field_names.push_back("x");
- field_names.push_back("y");
- config_value_editors(2, 2, 10, field_names);
- Vector2 vec = v;
- value_editor[0]->set_text(String::num(vec.x));
- value_editor[1]->set_text(String::num(vec.y));
- } break;
- case Variant::RECT2: {
- field_names.push_back("x");
- field_names.push_back("y");
- field_names.push_back("w");
- field_names.push_back("h");
- config_value_editors(4, 4, 10, field_names);
- Rect2 r = v;
- value_editor[0]->set_text(String::num(r.position.x));
- value_editor[1]->set_text(String::num(r.position.y));
- value_editor[2]->set_text(String::num(r.size.x));
- value_editor[3]->set_text(String::num(r.size.y));
- } break;
- case Variant::VECTOR3: {
- field_names.push_back("x");
- field_names.push_back("y");
- field_names.push_back("z");
- config_value_editors(3, 3, 10, field_names);
- Vector3 vec = v;
- value_editor[0]->set_text(String::num(vec.x));
- value_editor[1]->set_text(String::num(vec.y));
- value_editor[2]->set_text(String::num(vec.z));
- } break;
- case Variant::PLANE: {
- field_names.push_back("x");
- field_names.push_back("y");
- field_names.push_back("z");
- field_names.push_back("d");
- config_value_editors(4, 4, 10, field_names);
- Plane plane = v;
- value_editor[0]->set_text(String::num(plane.normal.x));
- value_editor[1]->set_text(String::num(plane.normal.y));
- value_editor[2]->set_text(String::num(plane.normal.z));
- value_editor[3]->set_text(String::num(plane.d));
-
- } break;
- case Variant::QUATERNION: {
- field_names.push_back("x");
- field_names.push_back("y");
- field_names.push_back("z");
- field_names.push_back("w");
- config_value_editors(4, 4, 10, field_names);
- Quaternion q = v;
- value_editor[0]->set_text(String::num(q.x));
- value_editor[1]->set_text(String::num(q.y));
- value_editor[2]->set_text(String::num(q.z));
- value_editor[3]->set_text(String::num(q.w));
-
- } break;
- case Variant::AABB: {
- field_names.push_back("px");
- field_names.push_back("py");
- field_names.push_back("pz");
- field_names.push_back("sx");
- field_names.push_back("sy");
- field_names.push_back("sz");
- config_value_editors(6, 3, 16, field_names);
-
- AABB aabb = v;
- value_editor[0]->set_text(String::num(aabb.position.x));
- value_editor[1]->set_text(String::num(aabb.position.y));
- value_editor[2]->set_text(String::num(aabb.position.z));
- value_editor[3]->set_text(String::num(aabb.size.x));
- value_editor[4]->set_text(String::num(aabb.size.y));
- value_editor[5]->set_text(String::num(aabb.size.z));
-
- } break;
- case Variant::TRANSFORM2D: {
- field_names.push_back("xx");
- field_names.push_back("xy");
- field_names.push_back("yx");
- field_names.push_back("yy");
- field_names.push_back("ox");
- field_names.push_back("oy");
- config_value_editors(6, 2, 16, field_names);
-
- Transform2D basis = v;
- for (int i = 0; i < 6; i++) {
- value_editor[i]->set_text(String::num(basis.columns[i / 2][i % 2]));
- }
-
- } break;
- case Variant::BASIS: {
- field_names.push_back("xx");
- field_names.push_back("xy");
- field_names.push_back("xz");
- field_names.push_back("yx");
- field_names.push_back("yy");
- field_names.push_back("yz");
- field_names.push_back("zx");
- field_names.push_back("zy");
- field_names.push_back("zz");
- config_value_editors(9, 3, 16, field_names);
-
- Basis basis = v;
- for (int i = 0; i < 9; i++) {
- value_editor[i]->set_text(String::num(basis.rows[i / 3][i % 3]));
- }
-
- } break;
- case Variant::TRANSFORM3D: {
- field_names.push_back("xx");
- field_names.push_back("xy");
- field_names.push_back("xz");
- field_names.push_back("xo");
- field_names.push_back("yx");
- field_names.push_back("yy");
- field_names.push_back("yz");
- field_names.push_back("yo");
- field_names.push_back("zx");
- field_names.push_back("zy");
- field_names.push_back("zz");
- field_names.push_back("zo");
- config_value_editors(12, 4, 16, field_names);
-
- Transform3D tr = v;
- for (int i = 0; i < 9; i++) {
- value_editor[(i / 3) * 4 + i % 3]->set_text(String::num(tr.basis.rows[i / 3][i % 3]));
- }
-
- value_editor[3]->set_text(String::num(tr.origin.x));
- value_editor[7]->set_text(String::num(tr.origin.y));
- value_editor[11]->set_text(String::num(tr.origin.z));
-
- } break;
- case Variant::COLOR: {
- if (!color_picker) {
- //late init for performance
- color_picker = memnew(ColorPicker);
- color_picker->set_deferred_mode(true);
- value_vbox->add_child(color_picker);
- color_picker->hide();
- color_picker->connect("color_changed", callable_mp(this, &CustomPropertyEditor::_color_changed));
- color_picker->connect("show", callable_mp(EditorNode::get_singleton(), &EditorNode::setup_color_picker).bind(color_picker));
- }
-
- color_picker->show();
- color_picker->set_edit_alpha(hint != PROPERTY_HINT_COLOR_NO_ALPHA);
- color_picker->set_pick_color(v);
- color_picker->set_focus_on_line_edit();
-
- } break;
-
- case Variant::NODE_PATH: {
- List<String> names;
- names.push_back(TTR("Assign"));
- names.push_back(TTR("Clear"));
-
- if (owner && owner->is_class("Node") && (v.get_type() == Variant::NODE_PATH) && Object::cast_to<Node>(owner)->has_node(v)) {
- names.push_back(TTR("Select Node"));
- }
-
- config_action_buttons(names);
-
- } break;
- case Variant::OBJECT: {
- if (hint != PROPERTY_HINT_RESOURCE_TYPE) {
- break;
- }
-
- if (p_name == "script" && hint_text == "Script" && Object::cast_to<Node>(owner)) {
- menu->add_item(TTR("New Script"), OBJ_MENU_NEW_SCRIPT);
- menu->add_separator();
- } else if (!hint_text.is_empty()) {
- int idx = 0;
-
- Vector<EditorData::CustomType> custom_resources;
-
- if (EditorNode::get_editor_data().get_custom_types().has("Resource")) {
- custom_resources = EditorNode::get_editor_data().get_custom_types()["Resource"];
- }
-
- for (int i = 0; i < hint_text.get_slice_count(","); i++) {
- String base = hint_text.get_slice(",", i);
-
- HashSet<String> valid_inheritors;
- valid_inheritors.insert(base);
- List<StringName> inheritors;
- ClassDB::get_inheriters_from_class(base.strip_edges(), &inheritors);
-
- for (int j = 0; j < custom_resources.size(); j++) {
- inheritors.push_back(custom_resources[j].name);
- }
-
- List<StringName>::Element *E = inheritors.front();
- while (E) {
- valid_inheritors.insert(E->get());
- E = E->next();
- }
-
- for (const String &j : valid_inheritors) {
- const String &t = j;
-
- bool is_custom_resource = false;
- Ref<Texture2D> icon;
- if (!custom_resources.is_empty()) {
- for (int k = 0; k < custom_resources.size(); k++) {
- if (custom_resources[k].name == t) {
- is_custom_resource = true;
- if (custom_resources[k].icon.is_valid()) {
- icon = custom_resources[k].icon;
- }
- break;
- }
- }
- }
-
- if (!is_custom_resource && (!ClassDB::can_instantiate(t) || ClassDB::is_virtual(t))) {
- continue;
- }
-
- inheritors_array.push_back(t);
-
- int id = TYPE_BASE_ID + idx;
-
- menu->add_item(vformat(TTR("New %s"), t), id);
-
- idx++;
- }
- }
-
- if (menu->get_item_count()) {
- menu->add_separator();
- }
- }
-
- menu->add_item(TTR("Load"), OBJ_MENU_LOAD);
-
- if (!Ref<Resource>(v).is_null()) {
- menu->add_item(TTR("Edit"), OBJ_MENU_EDIT);
- menu->add_item(TTR("Clear"), OBJ_MENU_CLEAR);
- menu->add_item(TTR("Make Unique"), OBJ_MENU_MAKE_UNIQUE);
-
- Ref<Resource> r = v;
- if (r.is_valid() && r->get_path().is_resource_file()) {
- menu->add_separator();
- menu->add_item(TTR("Show in FileSystem"), OBJ_MENU_SHOW_IN_FILE_SYSTEM);
- }
- }
-
- Ref<Resource> cb = EditorSettings::get_singleton()->get_resource_clipboard();
- bool paste_valid = false;
- if (cb.is_valid()) {
- if (hint_text.is_empty()) {
- paste_valid = true;
- } else {
- for (int i = 0; i < hint_text.get_slice_count(","); i++) {
- if (ClassDB::is_parent_class(cb->get_class(), hint_text.get_slice(",", i))) {
- paste_valid = true;
- break;
- }
- }
- }
- }
-
- if (!Ref<Resource>(v).is_null() || paste_valid) {
- menu->add_separator();
-
- if (!Ref<Resource>(v).is_null()) {
- menu->add_item(TTR("Copy"), OBJ_MENU_COPY);
- }
-
- if (paste_valid) {
- menu->add_item(TTR("Paste"), OBJ_MENU_PASTE);
- }
- }
-
- if (!Ref<Resource>(v).is_null()) {
- Vector<Ref<EditorResourceConversionPlugin>> conversions = EditorNode::get_singleton()->find_resource_conversion_plugin(Ref<Resource>(v));
- if (conversions.size()) {
- menu->add_separator();
- }
- for (int i = 0; i < conversions.size(); i++) {
- String what = conversions[i]->converts_to();
- menu->add_item(vformat(TTR("Convert to %s"), what), CONVERT_BASE_ID + i);
- }
- }
-
- menu->set_position(get_position());
- menu->popup();
- hide();
- updating = false;
- return false;
- } break;
- case Variant::DICTIONARY: {
- } break;
- case Variant::PACKED_BYTE_ARRAY: {
- } break;
- case Variant::PACKED_INT32_ARRAY: {
- } break;
- case Variant::PACKED_FLOAT32_ARRAY: {
- } break;
- case Variant::PACKED_INT64_ARRAY: {
- } break;
- case Variant::PACKED_FLOAT64_ARRAY: {
- } break;
- case Variant::PACKED_STRING_ARRAY: {
- } break;
- case Variant::PACKED_VECTOR3_ARRAY: {
- } break;
- case Variant::PACKED_COLOR_ARRAY: {
- } break;
- default: {
- }
- }
-
- updating = false;
- return true;
-}
-
-void CustomPropertyEditor::_file_selected(String p_file) {
- switch (type) {
- case Variant::STRING: {
- if (hint == PROPERTY_HINT_FILE || hint == PROPERTY_HINT_DIR) {
- v = ProjectSettings::get_singleton()->localize_path(p_file);
- emit_signal(SNAME("variant_changed"));
- hide();
- }
-
- if (hint == PROPERTY_HINT_GLOBAL_FILE || hint == PROPERTY_HINT_GLOBAL_DIR) {
- v = p_file;
- emit_signal(SNAME("variant_changed"));
- hide();
- }
-
- } break;
- case Variant::OBJECT: {
- String type = (hint == PROPERTY_HINT_RESOURCE_TYPE) ? hint_text : String();
-
- Ref<Resource> res = ResourceLoader::load(p_file, type);
- if (res.is_null()) {
- error->set_text(TTR("Error loading file: Not a resource!"));
- error->popup_centered();
- break;
- }
- v = res;
- emit_signal(SNAME("variant_changed"));
- hide();
- } break;
- default: {
- }
- }
-}
-
-void CustomPropertyEditor::_locale_selected(String p_locale) {
- if (type == Variant::STRING && hint == PROPERTY_HINT_LOCALE_ID) {
- v = p_locale;
- emit_signal(SNAME("variant_changed"));
- hide();
- }
-}
-
-void CustomPropertyEditor::_type_create_selected(int p_idx) {
- if (type == Variant::INT || type == Variant::FLOAT) {
- float newval = 0;
- switch (p_idx) {
- case EASING_LINEAR: {
- newval = 1;
- } break;
- case EASING_EASE_IN: {
- newval = 2.0;
- } break;
- case EASING_EASE_OUT: {
- newval = 0.5;
- } break;
- case EASING_ZERO: {
- newval = 0;
- } break;
- case EASING_IN_OUT: {
- newval = -0.5;
- } break;
- case EASING_OUT_IN: {
- newval = -2.0;
- } break;
- }
-
- v = newval;
- emit_signal(SNAME("variant_changed"));
- easing_draw->update();
-
- } else if (type == Variant::OBJECT) {
- ERR_FAIL_INDEX(p_idx, inheritors_array.size());
-
- String intype = inheritors_array[p_idx];
-
- Variant obj = ClassDB::instantiate(intype);
-
- if (!obj) {
- if (ScriptServer::is_global_class(intype)) {
- obj = EditorNode::get_editor_data().script_class_instance(intype);
- } else {
- obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource");
- }
- }
-
- ERR_FAIL_COND(!obj);
- ERR_FAIL_COND(!Object::cast_to<Resource>(obj));
-
- EditorNode::get_editor_data().instantiate_object_properties(obj);
- v = obj;
-
- emit_signal(SNAME("variant_changed"));
- hide();
- }
-}
-
-void CustomPropertyEditor::_color_changed(const Color &p_color) {
- v = p_color;
- emit_signal(SNAME("variant_changed"));
-}
-
-void CustomPropertyEditor::_node_path_selected(NodePath p_path) {
- if (picking_viewport) {
- Node *to_node = get_node(p_path);
- if (!Object::cast_to<Viewport>(to_node)) {
- EditorNode::get_singleton()->show_warning(TTR("Selected node is not a Viewport!"));
- return;
- }
-
- Ref<ViewportTexture> vt;
- vt.instantiate();
- vt->set_viewport_path_in_scene(get_tree()->get_edited_scene_root()->get_path_to(to_node));
- vt->setup_local_to_scene();
- v = vt;
- emit_signal(SNAME("variant_changed"));
- return;
- }
-
- if (hint == PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE && !hint_text.is_empty()) {
- Node *node = get_node(hint_text);
- if (node) {
- Node *tonode = node->get_node(p_path);
- if (tonode) {
- p_path = node->get_path_to(tonode);
- }
- }
-
- } else if (owner) {
- Node *node = nullptr;
-
- if (owner->is_class("Node")) {
- node = Object::cast_to<Node>(owner);
- } else if (owner->is_class("ArrayPropertyEdit")) {
- node = Object::cast_to<ArrayPropertyEdit>(owner)->get_node();
- } else if (owner->is_class("DictionaryPropertyEdit")) {
- node = Object::cast_to<DictionaryPropertyEdit>(owner)->get_node();
- }
- if (!node) {
- v = p_path;
- emit_signal(SNAME("variant_changed"));
- call_deferred(SNAME("hide")); //to not mess with dialogs
- return;
- }
-
- Node *tonode = node->get_node(p_path);
- if (tonode) {
- p_path = node->get_path_to(tonode);
- }
- }
-
- v = p_path;
- emit_signal(SNAME("variant_changed"));
- call_deferred(SNAME("hide")); //to not mess with dialogs
-}
-
-void CustomPropertyEditor::_action_pressed(int p_which) {
- if (updating) {
- return;
- }
-
- switch (type) {
- case Variant::BOOL: {
- v = checks20[0]->is_pressed();
- emit_signal(SNAME("variant_changed"));
- } break;
- case Variant::INT: {
- if (hint == PROPERTY_HINT_LAYERS_2D_PHYSICS ||
- hint == PROPERTY_HINT_LAYERS_2D_RENDER ||
- hint == PROPERTY_HINT_LAYERS_2D_NAVIGATION ||
- hint == PROPERTY_HINT_LAYERS_3D_PHYSICS ||
- hint == PROPERTY_HINT_LAYERS_3D_RENDER ||
- hint == PROPERTY_HINT_LAYERS_3D_NAVIGATION) {
- uint32_t f = v;
- if (checks20[p_which]->is_pressed()) {
- f |= (1 << p_which);
- } else {
- f &= ~(1 << p_which);
- }
-
- v = f;
- emit_signal(SNAME("variant_changed"));
- }
-
- } break;
- case Variant::STRING: {
- if (hint == PROPERTY_HINT_MULTILINE_TEXT) {
- hide();
- } else if (hint == PROPERTY_HINT_LOCALE_ID) {
- locale->popup_locale_dialog();
- } else if (hint == PROPERTY_HINT_FILE || hint == PROPERTY_HINT_GLOBAL_FILE) {
- if (p_which == 0) {
- if (hint == PROPERTY_HINT_FILE) {
- file->set_access(EditorFileDialog::ACCESS_RESOURCES);
- } else {
- file->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
- }
-
- file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
- file->clear_filters();
-
- file->clear_filters();
-
- if (!hint_text.is_empty()) {
- Vector<String> extensions = hint_text.split(",");
- for (int i = 0; i < extensions.size(); i++) {
- String filter = extensions[i];
- if (filter.begins_with(".")) {
- filter = "*" + extensions[i];
- } else if (!filter.begins_with("*")) {
- filter = "*." + extensions[i];
- }
-
- file->add_filter(filter, extensions[i].to_upper());
- }
- }
- file->popup_file_dialog();
- } else {
- v = "";
- emit_signal(SNAME("variant_changed"));
- hide();
- }
-
- } else if (hint == PROPERTY_HINT_DIR || hint == PROPERTY_HINT_GLOBAL_DIR) {
- if (p_which == 0) {
- if (hint == PROPERTY_HINT_DIR) {
- file->set_access(EditorFileDialog::ACCESS_RESOURCES);
- } else {
- file->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
- }
- file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_DIR);
- file->clear_filters();
- file->popup_file_dialog();
- } else {
- v = "";
- emit_signal(SNAME("variant_changed"));
- hide();
- }
- }
-
- } break;
- case Variant::NODE_PATH: {
- if (p_which == 0) {
- picking_viewport = false;
- scene_tree->set_title(TTR("Pick a Node"));
- scene_tree->popup_scenetree_dialog();
-
- } else if (p_which == 1) {
- v = NodePath();
- emit_signal(SNAME("variant_changed"));
- hide();
- } else if (p_which == 2) {
- if (owner->is_class("Node") && (v.get_type() == Variant::NODE_PATH) && Object::cast_to<Node>(owner)->has_node(v)) {
- Node *target_node = Object::cast_to<Node>(owner)->get_node(v);
- EditorNode::get_singleton()->get_editor_selection()->clear();
- SceneTreeDock::get_singleton()->set_selected(target_node);
- }
-
- hide();
- }
-
- } break;
- case Variant::OBJECT: {
- if (p_which == 0) {
- ERR_FAIL_COND(inheritors_array.is_empty());
-
- String intype = inheritors_array[0];
-
- if (hint == PROPERTY_HINT_RESOURCE_TYPE) {
- Variant obj = ClassDB::instantiate(intype);
-
- if (!obj) {
- if (ScriptServer::is_global_class(intype)) {
- obj = EditorNode::get_editor_data().script_class_instance(intype);
- } else {
- obj = EditorNode::get_editor_data().instance_custom_type(intype, "Resource");
- }
- }
-
- ERR_BREAK(!obj);
- ERR_BREAK(!Object::cast_to<Resource>(obj));
-
- EditorNode::get_editor_data().instantiate_object_properties(obj);
- v = obj;
-
- emit_signal(SNAME("variant_changed"));
- hide();
- }
- } else if (p_which == 1) {
- file->set_access(EditorFileDialog::ACCESS_RESOURCES);
- file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
- List<String> extensions;
- String type = (hint == PROPERTY_HINT_RESOURCE_TYPE) ? hint_text : String();
-
- ResourceLoader::get_recognized_extensions_for_type(type, &extensions);
- file->clear_filters();
- for (const String &E : extensions) {
- file->add_filter("*." + E, E.to_upper());
- }
-
- file->popup_file_dialog();
-
- } else if (p_which == 2) {
- Ref<Resource> r = v;
-
- if (!r.is_null()) {
- emit_signal(SNAME("resource_edit_request"));
- hide();
- }
-
- } else if (p_which == 3) {
- v = Variant();
- emit_signal(SNAME("variant_changed"));
- hide();
- } else if (p_which == 4) {
- Ref<Resource> res_orig = v;
- if (res_orig.is_null()) {
- return;
- }
-
- List<PropertyInfo> property_list;
- res_orig->get_property_list(&property_list);
- List<Pair<String, Variant>> propvalues;
-
- for (const PropertyInfo &pi : property_list) {
- Pair<String, Variant> p;
- if (pi.usage & PROPERTY_USAGE_STORAGE) {
- p.first = pi.name;
- p.second = res_orig->get(pi.name);
- }
-
- propvalues.push_back(p);
- }
-
- Ref<Resource> res = Ref<Resource>(ClassDB::instantiate(res_orig->get_class()));
-
- ERR_FAIL_COND(res.is_null());
-
- for (const Pair<String, Variant> &p : propvalues) {
- res->set(p.first, p.second);
- }
-
- v = res;
- emit_signal(SNAME("variant_changed"));
- hide();
- }
-
- } break;
-
- default: {
- };
- }
-}
-
-void CustomPropertyEditor::_drag_easing(const Ref<InputEvent> &p_ev) {
- Ref<InputEventMouseMotion> mm = p_ev;
-
- if (mm.is_valid() && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE) {
- float rel = mm->get_relative().x;
- if (rel == 0) {
- return;
- }
-
- bool flip = hint_text == "attenuation";
-
- if (flip) {
- rel = -rel;
- }
-
- float val = v;
- if (val == 0) {
- return;
- }
- bool sg = val < 0;
- val = Math::absf(val);
-
- val = Math::log(val) / Math::log((float)2.0);
- //logspace
- val += rel * 0.05;
-
- val = Math::pow(2.0f, val);
- if (sg) {
- val = -val;
- }
-
- v = val;
- easing_draw->update();
- emit_signal(SNAME("variant_changed"));
- }
-}
-
-void CustomPropertyEditor::_draw_easing() {
- RID ci = easing_draw->get_canvas_item();
-
- Size2 s = easing_draw->get_size();
- Rect2 r(Point2(), s);
- r = r.grow(3);
- easing_draw->get_theme_stylebox(SNAME("normal"), SNAME("LineEdit"))->draw(ci, r);
-
- int points = 48;
-
- float prev = 1.0;
- float exp = v;
- bool flip = hint_text == "attenuation";
-
- Ref<Font> f = easing_draw->get_theme_font(SNAME("font"), SNAME("Label"));
- int font_size = easing_draw->get_theme_font_size(SNAME("font_size"), SNAME("Label"));
- Color color = easing_draw->get_theme_color(SNAME("font_color"), SNAME("Label"));
-
- for (int i = 1; i <= points; i++) {
- float ifl = i / float(points);
- float iflp = (i - 1) / float(points);
-
- float h = 1.0 - Math::ease(ifl, exp);
-
- if (flip) {
- ifl = 1.0 - ifl;
- iflp = 1.0 - iflp;
- }
-
- RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2(iflp * s.width, prev * s.height), Point2(ifl * s.width, h * s.height), color);
- prev = h;
- }
-
- f->draw_string(ci, Point2(10, 10 + f->get_ascent(font_size)), String::num(exp, 2), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, color);
-}
-
-void CustomPropertyEditor::_text_edit_changed() {
- v = text_edit->get_text();
- emit_signal(SNAME("variant_changed"));
-}
-
-void CustomPropertyEditor::_create_dialog_callback() {
- v = create_dialog->get_selected_type();
- emit_signal(SNAME("variant_changed"));
-}
-
-void CustomPropertyEditor::_create_selected_property(const String &p_prop) {
- v = p_prop;
- emit_signal(SNAME("variant_changed"));
-}
-
-void CustomPropertyEditor::_modified(String p_string) {
- if (updating) {
- return;
- }
-
- Variant prev_v = v;
-
- updating = true;
- switch (type) {
- case Variant::INT: {
- String text = TS->parse_number(value_editor[0]->get_text());
- Ref<Expression> expr;
- expr.instantiate();
- Error err = expr->parse(text);
- if (err != OK) {
- v = value_editor[0]->get_text().to_int();
- return;
- } else {
- v = expr->execute(Array(), nullptr, false, false);
- }
-
- if (v != prev_v) {
- emit_signal(SNAME("variant_changed"));
- }
- } break;
- case Variant::FLOAT: {
- if (hint != PROPERTY_HINT_EXP_EASING) {
- String text = TS->parse_number(value_editor[0]->get_text());
- v = _parse_real_expression(text);
- if (v != prev_v) {
- emit_signal(SNAME("variant_changed"));
- }
- }
-
- } break;
- case Variant::STRING: {
- v = value_editor[0]->get_text();
- emit_signal(SNAME("variant_changed"));
- } break;
- case Variant::VECTOR2: {
- Vector2 vec;
- vec.x = _parse_real_expression(value_editor[0]->get_text());
- vec.y = _parse_real_expression(value_editor[1]->get_text());
- v = vec;
- if (v != prev_v) {
- _emit_changed_whole_or_field();
- }
-
- } break;
- case Variant::RECT2: {
- Rect2 r2;
-
- r2.position.x = _parse_real_expression(value_editor[0]->get_text());
- r2.position.y = _parse_real_expression(value_editor[1]->get_text());
- r2.size.x = _parse_real_expression(value_editor[2]->get_text());
- r2.size.y = _parse_real_expression(value_editor[3]->get_text());
- v = r2;
- if (v != prev_v) {
- _emit_changed_whole_or_field();
- }
-
- } break;
-
- case Variant::VECTOR3: {
- Vector3 vec;
- vec.x = _parse_real_expression(value_editor[0]->get_text());
- vec.y = _parse_real_expression(value_editor[1]->get_text());
- vec.z = _parse_real_expression(value_editor[2]->get_text());
- v = vec;
- if (v != prev_v) {
- _emit_changed_whole_or_field();
- }
-
- } break;
- case Variant::PLANE: {
- Plane pl;
- pl.normal.x = _parse_real_expression(value_editor[0]->get_text());
- pl.normal.y = _parse_real_expression(value_editor[1]->get_text());
- pl.normal.z = _parse_real_expression(value_editor[2]->get_text());
- pl.d = _parse_real_expression(value_editor[3]->get_text());
- v = pl;
- if (v != prev_v) {
- _emit_changed_whole_or_field();
- }
-
- } break;
- case Variant::QUATERNION: {
- Quaternion q;
- q.x = _parse_real_expression(value_editor[0]->get_text());
- q.y = _parse_real_expression(value_editor[1]->get_text());
- q.z = _parse_real_expression(value_editor[2]->get_text());
- q.w = _parse_real_expression(value_editor[3]->get_text());
- v = q;
- if (v != prev_v) {
- _emit_changed_whole_or_field();
- }
-
- } break;
- case Variant::AABB: {
- Vector3 pos;
- Vector3 size;
-
- pos.x = _parse_real_expression(value_editor[0]->get_text());
- pos.y = _parse_real_expression(value_editor[1]->get_text());
- pos.z = _parse_real_expression(value_editor[2]->get_text());
- size.x = _parse_real_expression(value_editor[3]->get_text());
- size.y = _parse_real_expression(value_editor[4]->get_text());
- size.z = _parse_real_expression(value_editor[5]->get_text());
- v = AABB(pos, size);
- if (v != prev_v) {
- _emit_changed_whole_or_field();
- }
-
- } break;
- case Variant::TRANSFORM2D: {
- Transform2D m;
- for (int i = 0; i < 6; i++) {
- m.columns[i / 2][i % 2] = _parse_real_expression(value_editor[i]->get_text());
- }
-
- v = m;
- if (v != prev_v) {
- _emit_changed_whole_or_field();
- }
-
- } break;
- case Variant::BASIS: {
- Basis m;
- for (int i = 0; i < 9; i++) {
- m.rows[i / 3][i % 3] = _parse_real_expression(value_editor[i]->get_text());
- }
-
- v = m;
- if (v != prev_v) {
- _emit_changed_whole_or_field();
- }
-
- } break;
- case Variant::TRANSFORM3D: {
- Basis basis;
- for (int i = 0; i < 9; i++) {
- basis.rows[i / 3][i % 3] = _parse_real_expression(value_editor[(i / 3) * 4 + i % 3]->get_text());
- }
-
- Vector3 origin;
-
- origin.x = _parse_real_expression(value_editor[3]->get_text());
- origin.y = _parse_real_expression(value_editor[7]->get_text());
- origin.z = _parse_real_expression(value_editor[11]->get_text());
-
- v = Transform3D(basis, origin);
- if (v != prev_v) {
- _emit_changed_whole_or_field();
- }
-
- } break;
- case Variant::COLOR: {
- } break;
-
- case Variant::NODE_PATH: {
- v = NodePath(value_editor[0]->get_text());
- if (v != prev_v) {
- emit_signal(SNAME("variant_changed"));
- }
- } break;
- case Variant::DICTIONARY: {
- } break;
- case Variant::PACKED_BYTE_ARRAY: {
- } break;
- case Variant::PACKED_INT32_ARRAY: {
- } break;
- case Variant::PACKED_FLOAT32_ARRAY: {
- } break;
- case Variant::PACKED_STRING_ARRAY: {
- } break;
- case Variant::PACKED_VECTOR3_ARRAY: {
- } break;
- case Variant::PACKED_COLOR_ARRAY: {
- } break;
- default: {
- }
- }
-
- updating = false;
-}
-
-real_t CustomPropertyEditor::_parse_real_expression(String text) {
- Ref<Expression> expr;
- expr.instantiate();
- Error err = expr->parse(text);
- real_t out;
- if (err != OK) {
- out = value_editor[0]->get_text().to_float();
- } else {
- out = expr->execute(Array(), nullptr, false, true);
- }
- return out;
-}
-
-void CustomPropertyEditor::_emit_changed_whole_or_field() {
- if (!Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
- emit_signal(SNAME("variant_changed"));
- } else {
- emit_signal(SNAME("variant_field_changed"), field_names[focused_value_editor]);
- }
-}
-
-void CustomPropertyEditor::_range_modified(double p_value) {
- v = p_value;
- emit_signal(SNAME("variant_changed"));
-}
-
-void CustomPropertyEditor::_focus_enter() {
- switch (type) {
- case Variant::FLOAT:
- case Variant::STRING:
- case Variant::VECTOR2:
- case Variant::RECT2:
- case Variant::VECTOR3:
- case Variant::PLANE:
- case Variant::QUATERNION:
- case Variant::AABB:
- case Variant::TRANSFORM2D:
- case Variant::BASIS:
- case Variant::TRANSFORM3D: {
- for (int i = 0; i < MAX_VALUE_EDITORS; ++i) {
- if (value_editor[i]->has_focus()) {
- focused_value_editor = i;
- value_editor[i]->select_all();
- break;
- }
- }
- } break;
- default: {
- }
- }
-}
-
-void CustomPropertyEditor::_focus_exit() {
- _modified(String());
-}
-
-void CustomPropertyEditor::config_action_buttons(const List<String> &p_strings) {
- Ref<StyleBox> sb = action_buttons[0]->get_theme_stylebox(SNAME("button"));
- int margin_top = sb->get_margin(SIDE_TOP);
- int margin_left = sb->get_margin(SIDE_LEFT);
- int margin_bottom = sb->get_margin(SIDE_BOTTOM);
- int margin_right = sb->get_margin(SIDE_RIGHT);
-
- int max_width = 0;
- int height = 0;
-
- for (int i = 0; i < MAX_ACTION_BUTTONS; i++) {
- if (i < p_strings.size()) {
- action_buttons[i]->show();
- action_buttons[i]->set_text(p_strings[i]);
-
- Size2 btn_m_size = action_buttons[i]->get_minimum_size();
- if (btn_m_size.width > max_width) {
- max_width = btn_m_size.width;
- }
-
- } else {
- action_buttons[i]->hide();
- }
- }
-
- for (int i = 0; i < p_strings.size(); i++) {
- Size2 btn_m_size = action_buttons[i]->get_size();
- action_buttons[i]->set_position(Point2(0, height) + Point2(margin_left, margin_top));
- action_buttons[i]->set_size(Size2(max_width, btn_m_size.height));
-
- height += btn_m_size.height;
- }
- set_size(Size2(max_width, height) + Size2(margin_left + margin_right, margin_top + margin_bottom));
-}
-
-void CustomPropertyEditor::config_value_editors(int p_amount, int p_columns, int p_label_w, const List<String> &p_strings) {
- int cell_width = 95;
- int cell_height = 25;
- int cell_margin = 5;
- int rows = ((p_amount - 1) / p_columns) + 1;
-
- set_size(Size2(cell_margin + p_label_w + (cell_width + cell_margin + p_label_w) * p_columns, cell_margin + (cell_height + cell_margin) * rows) * EDSCALE);
-
- for (int i = 0; i < MAX_VALUE_EDITORS; i++) {
- value_label[i]->get_parent()->remove_child(value_label[i]);
- value_editor[i]->get_parent()->remove_child(value_editor[i]);
-
- int box_id = i / p_columns;
- value_hboxes[box_id]->add_child(value_label[i]);
- value_hboxes[box_id]->add_child(value_editor[i]);
-
- if (i < MAX_VALUE_EDITORS / 4) {
- if (i <= p_amount / 4) {
- value_hboxes[i]->show();
- } else {
- value_hboxes[i]->hide();
- }
- }
-
- if (i < p_amount) {
- value_editor[i]->show();
- value_label[i]->show();
- value_label[i]->set_text(i < p_strings.size() ? p_strings[i] : String(""));
- value_editor[i]->set_editable(!read_only);
- } else {
- value_editor[i]->hide();
- value_label[i]->hide();
- }
- }
-}
-
-void CustomPropertyEditor::_bind_methods() {
- ADD_SIGNAL(MethodInfo("variant_changed"));
- ADD_SIGNAL(MethodInfo("variant_field_changed", PropertyInfo(Variant::STRING, "field")));
- ADD_SIGNAL(MethodInfo("resource_edit_request"));
-}
-
-CustomPropertyEditor::CustomPropertyEditor() {
- value_vbox = memnew(VBoxContainer);
- add_child(value_vbox);
-
- for (int i = 0; i < MAX_VALUE_EDITORS; i++) {
- if (i < MAX_VALUE_EDITORS / 4) {
- value_hboxes[i] = memnew(HBoxContainer);
- value_vbox->add_child(value_hboxes[i]);
- value_hboxes[i]->hide();
- }
- int hbox_idx = i / 4;
- value_label[i] = memnew(Label);
- value_hboxes[hbox_idx]->add_child(value_label[i]);
- value_label[i]->hide();
- value_editor[i] = memnew(LineEdit);
- value_hboxes[hbox_idx]->add_child(value_editor[i]);
- value_editor[i]->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- value_editor[i]->hide();
- value_editor[i]->connect("text_submitted", callable_mp(this, &CustomPropertyEditor::_modified));
- value_editor[i]->connect("focus_entered", callable_mp(this, &CustomPropertyEditor::_focus_enter));
- value_editor[i]->connect("focus_exited", callable_mp(this, &CustomPropertyEditor::_focus_exit));
- }
- focused_value_editor = -1;
-
- for (int i = 0; i < 4; i++) {
- scroll[i] = memnew(HScrollBar);
- scroll[i]->hide();
- scroll[i]->set_min(0);
- scroll[i]->set_max(1.0);
- scroll[i]->set_step(0.01);
- add_child(scroll[i]);
- }
-
- checks20gc = memnew(GridContainer);
- add_child(checks20gc);
- checks20gc->set_columns(11);
-
- for (int i = 0; i < 20; i++) {
- if (i == 5 || i == 15) {
- Control *space = memnew(Control);
- space->set_custom_minimum_size(Size2(20, 0) * EDSCALE);
- checks20gc->add_child(space);
- }
-
- checks20[i] = memnew(CheckBox);
- checks20[i]->set_toggle_mode(true);
- checks20[i]->set_focus_mode(Control::FOCUS_NONE);
- checks20gc->add_child(checks20[i]);
- checks20[i]->hide();
- checks20[i]->connect("pressed", callable_mp(this, &CustomPropertyEditor::_action_pressed).bind(i));
- checks20[i]->set_tooltip(vformat(TTR("Bit %d, val %d."), i, 1 << i));
- }
-
- text_edit = memnew(TextEdit);
- value_vbox->add_child(text_edit);
- text_edit->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, 5);
- text_edit->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- text_edit->set_offset(SIDE_BOTTOM, -30);
-
- text_edit->hide();
- text_edit->connect("text_changed", callable_mp(this, &CustomPropertyEditor::_text_edit_changed));
-
- color_picker = nullptr;
-
- file = memnew(EditorFileDialog);
- value_vbox->add_child(file);
- file->hide();
-
- file->connect("file_selected", callable_mp(this, &CustomPropertyEditor::_file_selected));
- file->connect("dir_selected", callable_mp(this, &CustomPropertyEditor::_file_selected));
-
- locale = memnew(EditorLocaleDialog);
- value_vbox->add_child(locale);
- locale->hide();
-
- locale->connect("locale_selected", callable_mp(this, &CustomPropertyEditor::_locale_selected));
-
- error = memnew(ConfirmationDialog);
- error->set_title(TTR("Error!"));
- value_vbox->add_child(error);
-
- scene_tree = memnew(SceneTreeDialog);
- value_vbox->add_child(scene_tree);
- scene_tree->connect("selected", callable_mp(this, &CustomPropertyEditor::_node_path_selected));
- scene_tree->get_scene_tree()->set_show_enabled_subscene(true);
-
- texture_preview = memnew(TextureRect);
- value_vbox->add_child(texture_preview);
- texture_preview->hide();
-
- easing_draw = memnew(Control);
- value_vbox->add_child(easing_draw);
- easing_draw->hide();
- easing_draw->connect("draw", callable_mp(this, &CustomPropertyEditor::_draw_easing));
- easing_draw->connect("gui_input", callable_mp(this, &CustomPropertyEditor::_drag_easing));
- easing_draw->set_default_cursor_shape(Control::CURSOR_MOVE);
-
- type_button = memnew(MenuButton);
- value_vbox->add_child(type_button);
- type_button->hide();
- type_button->get_popup()->connect("id_pressed", callable_mp(this, &CustomPropertyEditor::_type_create_selected));
-
- menu = memnew(PopupMenu);
- // menu->set_pass_on_modal_close_click(false);
- value_vbox->add_child(menu);
- menu->connect("id_pressed", callable_mp(this, &CustomPropertyEditor::_menu_option));
-
- evaluator = nullptr;
-
- spinbox = memnew(SpinBox);
- value_vbox->add_child(spinbox);
- spinbox->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, 5);
- spinbox->connect("value_changed", callable_mp(this, &CustomPropertyEditor::_range_modified));
-
- slider = memnew(HSlider);
- value_vbox->add_child(slider);
- slider->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT, Control::PRESET_MODE_MINSIZE, 5);
- slider->connect("value_changed", callable_mp(this, &CustomPropertyEditor::_range_modified));
-
- action_hboxes = memnew(HBoxContainer);
- action_hboxes->set_alignment(BoxContainer::ALIGNMENT_CENTER);
- value_vbox->add_child(action_hboxes);
- for (int i = 0; i < MAX_ACTION_BUTTONS; i++) {
- action_buttons[i] = memnew(Button);
- action_buttons[i]->hide();
- action_hboxes->add_child(action_buttons[i]);
- action_buttons[i]->connect("pressed", callable_mp(this, &CustomPropertyEditor::_action_pressed).bind(i));
- }
-
- create_dialog = nullptr;
- property_select = nullptr;
-}
diff --git a/editor/property_editor.h b/editor/property_editor.h
deleted file mode 100644
index 195eb89b81..0000000000
--- a/editor/property_editor.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/*************************************************************************/
-/* property_editor.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef PROPERTY_EDITOR_H
-#define PROPERTY_EDITOR_H
-
-#include "editor/editor_locale_dialog.h"
-#include "editor/scene_tree_editor.h"
-#include "scene/gui/button.h"
-#include "scene/gui/check_box.h"
-#include "scene/gui/check_button.h"
-#include "scene/gui/color_picker.h"
-#include "scene/gui/dialogs.h"
-#include "scene/gui/grid_container.h"
-#include "scene/gui/label.h"
-#include "scene/gui/menu_button.h"
-#include "scene/gui/split_container.h"
-#include "scene/gui/text_edit.h"
-#include "scene/gui/texture_rect.h"
-#include "scene/gui/tree.h"
-
-class CreateDialog;
-class EditorFileDialog;
-class PropertyValueEvaluator;
-class PropertySelector;
-
-class CustomPropertyEditor : public PopupPanel {
- GDCLASS(CustomPropertyEditor, PopupPanel);
-
- enum {
- MAX_VALUE_EDITORS = 12,
- MAX_ACTION_BUTTONS = 5,
- OBJ_MENU_LOAD = 0,
- OBJ_MENU_EDIT = 1,
- OBJ_MENU_CLEAR = 2,
- OBJ_MENU_MAKE_UNIQUE = 3,
- OBJ_MENU_COPY = 4,
- OBJ_MENU_PASTE = 5,
- OBJ_MENU_NEW_SCRIPT = 6,
- OBJ_MENU_EXTEND_SCRIPT = 7,
- OBJ_MENU_SHOW_IN_FILE_SYSTEM = 8,
- TYPE_BASE_ID = 100,
- CONVERT_BASE_ID = 1000
- };
-
- enum {
- EASING_LINEAR,
- EASING_EASE_IN,
- EASING_EASE_OUT,
- EASING_ZERO,
- EASING_IN_OUT,
- EASING_OUT_IN
- };
-
- PopupMenu *menu = nullptr;
- SceneTreeDialog *scene_tree = nullptr;
- EditorFileDialog *file = nullptr;
- EditorLocaleDialog *locale = nullptr;
- ConfirmationDialog *error = nullptr;
- String name;
- Variant::Type type;
- Variant v;
- List<String> field_names;
- int hint = 0;
- String hint_text;
- HBoxContainer *value_hboxes[MAX_VALUE_EDITORS / 4];
- VBoxContainer *value_vbox = nullptr;
- LineEdit *value_editor[MAX_VALUE_EDITORS];
- int focused_value_editor;
- Label *value_label[MAX_VALUE_EDITORS];
- HScrollBar *scroll[4];
- HBoxContainer *action_hboxes = nullptr;
- Button *action_buttons[MAX_ACTION_BUTTONS];
- MenuButton *type_button = nullptr;
- Vector<String> inheritors_array;
- TextureRect *texture_preview = nullptr;
- ColorPicker *color_picker = nullptr;
- TextEdit *text_edit = nullptr;
- bool read_only = false;
- bool picking_viewport = false;
- GridContainer *checks20gc = nullptr;
- CheckBox *checks20[20];
- SpinBox *spinbox = nullptr;
- HSlider *slider = nullptr;
-
- Control *easing_draw = nullptr;
- CreateDialog *create_dialog = nullptr;
- PropertySelector *property_select = nullptr;
-
- Object *owner = nullptr;
-
- bool updating = false;
-
- PropertyValueEvaluator *evaluator = nullptr;
-
- void _text_edit_changed();
- void _file_selected(String p_file);
- void _locale_selected(String p_locale);
- void _modified(String p_string);
-
- real_t _parse_real_expression(String text);
-
- void _range_modified(double p_value);
- void _focus_enter();
- void _focus_exit();
- void _action_pressed(int p_which);
- void _type_create_selected(int p_idx);
- void _create_dialog_callback();
- void _create_selected_property(const String &p_prop);
-
- void _color_changed(const Color &p_color);
- void _draw_easing();
- void _menu_option(int p_which);
-
- void _drag_easing(const Ref<InputEvent> &p_ev);
-
- void _node_path_selected(NodePath p_path);
- void show_value_editors(int p_amount);
- void config_value_editors(int p_amount, int p_columns, int p_label_w, const List<String> &p_strings);
- void config_action_buttons(const List<String> &p_strings);
-
- void _emit_changed_whole_or_field();
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- void hide_menu();
-
- Variant get_variant() const;
- String get_name() const;
-
- void set_read_only(bool p_read_only) { read_only = p_read_only; }
-
- bool edit(Object *p_owner, const String &p_name, Variant::Type p_type, const Variant &p_variant, int p_hint, String p_hint_text);
-
- CustomPropertyEditor();
-};
-
-#endif // PROPERTY_EDITOR_H
diff --git a/editor/property_selector.cpp b/editor/property_selector.cpp
index 841c3ff3b1..1b17a740dd 100644
--- a/editor/property_selector.cpp
+++ b/editor/property_selector.cpp
@@ -32,8 +32,12 @@
#include "core/os/keyboard.h"
#include "editor/doc_tools.h"
+#include "editor/editor_help.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "scene/gui/line_edit.h"
+#include "scene/gui/rich_text_label.h"
+#include "scene/gui/tree.h"
void PropertySelector::_text_changed(const String &p_newtext) {
_update_search();
diff --git a/editor/property_selector.h b/editor/property_selector.h
index e2bf5c02b7..9f1af576dd 100644
--- a/editor/property_selector.h
+++ b/editor/property_selector.h
@@ -31,9 +31,11 @@
#ifndef PROPERTY_SELECTOR_H
#define PROPERTY_SELECTOR_H
-#include "editor/editor_help.h"
-#include "editor/property_editor.h"
-#include "scene/gui/rich_text_label.h"
+#include "scene/gui/dialogs.h"
+
+class EditorHelpBit;
+class LineEdit;
+class Tree;
class PropertySelector : public ConfirmationDialog {
GDCLASS(PropertySelector, ConfirmationDialog);
diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp
index 665aca6a37..7b4df696b7 100644
--- a/editor/rename_dialog.cpp
+++ b/editor/rename_dialog.cpp
@@ -38,6 +38,7 @@
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/editor_themes.h"
+#include "editor/editor_undo_redo_manager.h"
#include "modules/regex/regex.h"
#include "plugins/script_editor_plugin.h"
#include "scene/gui/control.h"
@@ -45,7 +46,7 @@
#include "scene/gui/separator.h"
#include "scene/gui/tab_container.h"
-RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_undo_redo) {
+RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoRedoManager> p_undo_redo) {
scene_tree_editor = p_scene_tree_editor;
undo_redo = p_undo_redo;
preview_node = nullptr;
@@ -138,7 +139,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
but_insert_name = memnew(Button);
but_insert_name->set_text("NAME");
- but_insert_name->set_tooltip(String("${NAME}\n") + TTR("Node name."));
+ but_insert_name->set_tooltip_text(String("${NAME}\n") + TTR("Node name."));
but_insert_name->set_focus_mode(Control::FOCUS_NONE);
but_insert_name->connect("pressed", callable_mp(this, &RenameDialog::_insert_text).bind("${NAME}"));
but_insert_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -148,7 +149,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
but_insert_parent = memnew(Button);
but_insert_parent->set_text("PARENT");
- but_insert_parent->set_tooltip(String("${PARENT}\n") + TTR("Node's parent name, if available."));
+ but_insert_parent->set_tooltip_text(String("${PARENT}\n") + TTR("Node's parent name, if available."));
but_insert_parent->set_focus_mode(Control::FOCUS_NONE);
but_insert_parent->connect("pressed", callable_mp(this, &RenameDialog::_insert_text).bind("${PARENT}"));
but_insert_parent->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -158,7 +159,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
but_insert_type = memnew(Button);
but_insert_type->set_text("TYPE");
- but_insert_type->set_tooltip(String("${TYPE}\n") + TTR("Node type."));
+ but_insert_type->set_tooltip_text(String("${TYPE}\n") + TTR("Node type."));
but_insert_type->set_focus_mode(Control::FOCUS_NONE);
but_insert_type->connect("pressed", callable_mp(this, &RenameDialog::_insert_text).bind("${TYPE}"));
but_insert_type->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -168,7 +169,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
but_insert_scene = memnew(Button);
but_insert_scene->set_text("SCENE");
- but_insert_scene->set_tooltip(String("${SCENE}\n") + TTR("Current scene name."));
+ but_insert_scene->set_tooltip_text(String("${SCENE}\n") + TTR("Current scene name."));
but_insert_scene->set_focus_mode(Control::FOCUS_NONE);
but_insert_scene->connect("pressed", callable_mp(this, &RenameDialog::_insert_text).bind("${SCENE}"));
but_insert_scene->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -178,7 +179,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
but_insert_root = memnew(Button);
but_insert_root->set_text("ROOT");
- but_insert_root->set_tooltip(String("${ROOT}\n") + TTR("Root node name."));
+ but_insert_root->set_tooltip_text(String("${ROOT}\n") + TTR("Root node name."));
but_insert_root->set_focus_mode(Control::FOCUS_NONE);
but_insert_root->connect("pressed", callable_mp(this, &RenameDialog::_insert_text).bind("${ROOT}"));
but_insert_root->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -188,7 +189,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
but_insert_count = memnew(Button);
but_insert_count->set_text("COUNTER");
- but_insert_count->set_tooltip(String("${COUNTER}\n") + TTR("Sequential integer counter.\nCompare counter options."));
+ but_insert_count->set_tooltip_text(String("${COUNTER}\n") + TTR("Sequential integer counter.\nCompare counter options."));
but_insert_count->set_focus_mode(Control::FOCUS_NONE);
but_insert_count->connect("pressed", callable_mp(this, &RenameDialog::_insert_text).bind("${COUNTER}"));
but_insert_count->set_h_size_flags(Control::SIZE_EXPAND_FILL);
@@ -196,7 +197,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
chk_per_level_counter = memnew(CheckBox);
chk_per_level_counter->set_text(TTR("Per-level Counter"));
- chk_per_level_counter->set_tooltip(TTR("If set, the counter restarts for each group of child nodes."));
+ chk_per_level_counter->set_tooltip_text(TTR("If set, the counter restarts for each group of child nodes."));
vbc_substitute->add_child(chk_per_level_counter);
HBoxContainer *hbc_count_options = memnew(HBoxContainer);
@@ -204,32 +205,32 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
Label *lbl_count_start = memnew(Label);
lbl_count_start->set_text(TTR("Start"));
- lbl_count_start->set_tooltip(TTR("Initial value for the counter."));
+ lbl_count_start->set_tooltip_text(TTR("Initial value for the counter."));
hbc_count_options->add_child(lbl_count_start);
spn_count_start = memnew(SpinBox);
- spn_count_start->set_tooltip(TTR("Initial value for the counter."));
+ spn_count_start->set_tooltip_text(TTR("Initial value for the counter."));
spn_count_start->set_step(1);
spn_count_start->set_min(0);
hbc_count_options->add_child(spn_count_start);
Label *lbl_count_step = memnew(Label);
lbl_count_step->set_text(TTR("Step"));
- lbl_count_step->set_tooltip(TTR("Amount by which counter is incremented for each node."));
+ lbl_count_step->set_tooltip_text(TTR("Amount by which counter is incremented for each node."));
hbc_count_options->add_child(lbl_count_step);
spn_count_step = memnew(SpinBox);
- spn_count_step->set_tooltip(TTR("Amount by which counter is incremented for each node."));
+ spn_count_step->set_tooltip_text(TTR("Amount by which counter is incremented for each node."));
spn_count_step->set_step(1);
hbc_count_options->add_child(spn_count_step);
Label *lbl_count_padding = memnew(Label);
lbl_count_padding->set_text(TTR("Padding"));
- lbl_count_padding->set_tooltip(TTR("Minimum number of digits for the counter.\nMissing digits are padded with leading zeros."));
+ lbl_count_padding->set_tooltip_text(TTR("Minimum number of digits for the counter.\nMissing digits are padded with leading zeros."));
hbc_count_options->add_child(lbl_count_padding);
spn_count_padding = memnew(SpinBox);
- spn_count_padding->set_tooltip(TTR("Minimum number of digits for the counter.\nMissing digits are padded with leading zeros."));
+ spn_count_padding->set_tooltip_text(TTR("Minimum number of digits for the counter.\nMissing digits are padded with leading zeros."));
spn_count_padding->set_step(1);
hbc_count_options->add_child(spn_count_padding);
@@ -581,7 +582,7 @@ void RenameDialog::rename() {
// Forward recursive as opposed to the actual renaming.
_iterate_scene(root_node, selected_node_list, &global_count);
- if (undo_redo && !to_rename.is_empty()) {
+ if (undo_redo.is_valid() && !to_rename.is_empty()) {
undo_redo->create_action(TTR("Batch Rename"));
// Make sure to iterate reversed so that child nodes will find parents.
diff --git a/editor/rename_dialog.h b/editor/rename_dialog.h
index f3a850045e..dac73b13b8 100644
--- a/editor/rename_dialog.h
+++ b/editor/rename_dialog.h
@@ -34,7 +34,6 @@
#include "modules/modules_enabled.gen.h" // For regex.
#ifdef MODULE_REGEX_ENABLED
-#include "core/object/undo_redo.h"
#include "editor/scene_tree_editor.h"
#include "scene/gui/check_box.h"
#include "scene/gui/check_button.h"
@@ -43,6 +42,8 @@
#include "scene/gui/spin_box.h"
#include "scene/gui/tab_container.h"
+class EditorUndoRedoManager;
+
class RenameDialog : public ConfirmationDialog {
GDCLASS(RenameDialog, ConfirmationDialog);
@@ -63,7 +64,7 @@ class RenameDialog : public ConfirmationDialog {
static void _error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, bool p_editor_notify, ErrorHandlerType p_type);
SceneTreeEditor *scene_tree_editor = nullptr;
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
int global_count = 0;
LineEdit *lne_search = nullptr;
@@ -109,7 +110,7 @@ public:
void reset();
void rename();
- RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_undo_redo = nullptr);
+ RenameDialog(SceneTreeEditor *p_scene_tree_editor, Ref<EditorUndoRedoManager> p_undo_redo = Ref<EditorUndoRedoManager>());
~RenameDialog() {}
};
diff --git a/editor/scene_create_dialog.cpp b/editor/scene_create_dialog.cpp
index 94a5c07709..9b8684b7b8 100644
--- a/editor/scene_create_dialog.cpp
+++ b/editor/scene_create_dialog.cpp
@@ -111,7 +111,7 @@ void SceneCreateDialog::update_dialog() {
}
if (is_valid) {
- scene_name = directory.plus_file(scene_name);
+ scene_name = directory.path_join(scene_name);
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
if (da->file_exists(scene_name)) {
update_error(file_error_label, MSG_ERROR, TTR("File already exists."));
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index d19a40599f..3e98c854c5 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -222,28 +222,28 @@ void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, N
return;
}
- editor_data->get_undo_redo().create_action(TTR("Instance Scene(s)"));
+ editor_data->get_undo_redo()->create_action(TTR("Instance Scene(s)"));
for (int i = 0; i < instances.size(); i++) {
Node *instantiated_scene = instances[i];
- editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene, true);
+ editor_data->get_undo_redo()->add_do_method(parent, "add_child", instantiated_scene, true);
if (p_pos >= 0) {
- editor_data->get_undo_redo().add_do_method(parent, "move_child", instantiated_scene, p_pos + i);
+ editor_data->get_undo_redo()->add_do_method(parent, "move_child", instantiated_scene, p_pos + i);
}
- editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_owner", edited_scene);
- editor_data->get_undo_redo().add_do_method(editor_selection, "clear");
- editor_data->get_undo_redo().add_do_method(editor_selection, "add_node", instantiated_scene);
- editor_data->get_undo_redo().add_do_reference(instantiated_scene);
- editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instantiated_scene);
+ editor_data->get_undo_redo()->add_do_method(instantiated_scene, "set_owner", edited_scene);
+ editor_data->get_undo_redo()->add_do_method(editor_selection, "clear");
+ editor_data->get_undo_redo()->add_do_method(editor_selection, "add_node", instantiated_scene);
+ editor_data->get_undo_redo()->add_do_reference(instantiated_scene);
+ editor_data->get_undo_redo()->add_undo_method(parent, "remove_child", instantiated_scene);
String new_name = parent->validate_child_name(instantiated_scene);
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
- editor_data->get_undo_redo().add_do_method(ed, "live_debug_instance_node", edited_scene->get_path_to(parent), p_files[i], new_name);
- editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(new_name)));
+ editor_data->get_undo_redo()->add_do_method(ed, "live_debug_instance_node", edited_scene->get_path_to(parent), p_files[i], new_name);
+ editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).path_join(new_name)));
}
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->commit_action();
_push_item(instances[instances.size() - 1]);
for (int i = 0; i < instances.size(); i++) {
emit_signal(SNAME("node_created"), instances[i]);
@@ -265,7 +265,7 @@ void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base)
return;
}
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
undo_redo->create_action(TTR("Replace with Branch Scene"));
Node *parent = base->get_parent();
@@ -510,9 +510,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
}
if (selected) {
- create_dialog->popup_create(false, true, selected->get_class());
+ create_dialog->popup_create(false, true, selected->get_class(), selected->get_name());
}
-
} break;
case TOOL_EXTEND_SCRIPT: {
attach_script_to_selected(true);
@@ -531,23 +530,23 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
return;
}
- editor_data->get_undo_redo().create_action(TTR("Detach Script"));
- editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "push_item", (Script *)nullptr);
+ editor_data->get_undo_redo()->create_action(TTR("Detach Script"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
+ editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "push_item", (Script *)nullptr);
for (int i = 0; i < selection.size(); i++) {
Node *n = Object::cast_to<Node>(selection[i]);
Ref<Script> existing = n->get_script();
Ref<Script> empty = EditorNode::get_singleton()->get_object_custom_type_base(n);
if (existing != empty) {
- editor_data->get_undo_redo().add_do_method(n, "set_script", empty);
- editor_data->get_undo_redo().add_undo_method(n, "set_script", existing);
+ editor_data->get_undo_redo()->add_do_method(n, "set_script", empty);
+ editor_data->get_undo_redo()->add_undo_method(n, "set_script", existing);
}
}
- editor_data->get_undo_redo().add_do_method(this, "_update_script_button");
- editor_data->get_undo_redo().add_undo_method(this, "_update_script_button");
+ editor_data->get_undo_redo()->add_do_method(this, "_update_script_button");
+ editor_data->get_undo_redo()->add_undo_method(this, "_update_script_button");
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->commit_action();
} break;
case TOOL_MOVE_UP:
case TOOL_MOVE_DOWN: {
@@ -602,10 +601,10 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
}
if (selection.size() == 1) {
- editor_data->get_undo_redo().create_action(TTR("Move Node In Parent"));
+ editor_data->get_undo_redo()->create_action(TTR("Move Node In Parent"));
}
if (selection.size() > 1) {
- editor_data->get_undo_redo().create_action(TTR("Move Nodes In Parent"));
+ editor_data->get_undo_redo()->create_action(TTR("Move Nodes In Parent"));
}
for (int i = 0; i < selection.size(); i++) {
@@ -618,11 +617,11 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
int bottom_node_pos = bottom_node->get_index();
int top_node_pos_next = top_node->get_index() + (MOVING_DOWN ? 1 : -1);
- editor_data->get_undo_redo().add_do_method(top_node->get_parent(), "move_child", top_node, top_node_pos_next);
- editor_data->get_undo_redo().add_undo_method(bottom_node->get_parent(), "move_child", bottom_node, bottom_node_pos);
+ editor_data->get_undo_redo()->add_do_method(top_node->get_parent(), "move_child", top_node, top_node_pos_next);
+ editor_data->get_undo_redo()->add_undo_method(bottom_node->get_parent(), "move_child", bottom_node, bottom_node_pos);
}
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->commit_action();
} break;
case TOOL_DUPLICATE: {
@@ -650,8 +649,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
- editor_data->get_undo_redo().create_action(TTR("Duplicate Node(s)"));
- editor_data->get_undo_redo().add_do_method(editor_selection, "clear");
+ editor_data->get_undo_redo()->create_action(TTR("Duplicate Node(s)"), UndoRedo::MERGE_DISABLE, selection.front()->get());
+ editor_data->get_undo_redo()->add_do_method(editor_selection, "clear");
Node *dupsingle = nullptr;
@@ -676,28 +675,28 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
dup->set_name(parent->validate_child_name(dup));
- editor_data->get_undo_redo().add_do_method(add_below_node, "add_sibling", dup, true);
+ editor_data->get_undo_redo()->add_do_method(add_below_node, "add_sibling", dup, true);
for (Node *F : owned) {
if (!duplimap.has(F)) {
continue;
}
Node *d = duplimap[F];
- editor_data->get_undo_redo().add_do_method(d, "set_owner", node->get_owner());
+ editor_data->get_undo_redo()->add_do_method(d, "set_owner", node->get_owner());
}
- editor_data->get_undo_redo().add_do_method(editor_selection, "add_node", dup);
- editor_data->get_undo_redo().add_undo_method(parent, "remove_child", dup);
- editor_data->get_undo_redo().add_do_reference(dup);
+ editor_data->get_undo_redo()->add_do_method(editor_selection, "add_node", dup);
+ editor_data->get_undo_redo()->add_undo_method(parent, "remove_child", dup);
+ editor_data->get_undo_redo()->add_do_reference(dup);
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
- editor_data->get_undo_redo().add_do_method(ed, "live_debug_duplicate_node", edited_scene->get_path_to(node), dup->get_name());
- editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(dup->get_name())));
+ editor_data->get_undo_redo()->add_do_method(ed, "live_debug_duplicate_node", edited_scene->get_path_to(node), dup->get_name());
+ editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).path_join(dup->get_name())));
add_below_node = dup;
}
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->commit_action();
if (dupsingle) {
_push_item(dupsingle);
@@ -766,29 +765,29 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
return;
}
- editor_data->get_undo_redo().create_action(TTR("Make node as Root"));
- editor_data->get_undo_redo().add_do_method(node->get_parent(), "remove_child", node);
- editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "set_edited_scene", node);
- editor_data->get_undo_redo().add_do_method(node, "add_child", root, true);
- editor_data->get_undo_redo().add_do_method(node, "set_scene_file_path", root->get_scene_file_path());
- editor_data->get_undo_redo().add_do_method(root, "set_scene_file_path", String());
- editor_data->get_undo_redo().add_do_method(node, "set_owner", (Object *)nullptr);
- editor_data->get_undo_redo().add_do_method(root, "set_owner", node);
+ editor_data->get_undo_redo()->create_action(TTR("Make node as Root"));
+ editor_data->get_undo_redo()->add_do_method(node->get_parent(), "remove_child", node);
+ editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "set_edited_scene", node);
+ editor_data->get_undo_redo()->add_do_method(node, "add_child", root, true);
+ editor_data->get_undo_redo()->add_do_method(node, "set_scene_file_path", root->get_scene_file_path());
+ editor_data->get_undo_redo()->add_do_method(root, "set_scene_file_path", String());
+ editor_data->get_undo_redo()->add_do_method(node, "set_owner", (Object *)nullptr);
+ editor_data->get_undo_redo()->add_do_method(root, "set_owner", node);
_node_replace_owner(root, root, node, MODE_DO);
- editor_data->get_undo_redo().add_undo_method(root, "set_scene_file_path", root->get_scene_file_path());
- editor_data->get_undo_redo().add_undo_method(node, "set_scene_file_path", String());
- editor_data->get_undo_redo().add_undo_method(node, "remove_child", root);
- editor_data->get_undo_redo().add_undo_method(EditorNode::get_singleton(), "set_edited_scene", root);
- editor_data->get_undo_redo().add_undo_method(node->get_parent(), "add_child", node, true);
- editor_data->get_undo_redo().add_undo_method(node->get_parent(), "move_child", node, node->get_index());
- editor_data->get_undo_redo().add_undo_method(root, "set_owner", (Object *)nullptr);
- editor_data->get_undo_redo().add_undo_method(node, "set_owner", root);
+ editor_data->get_undo_redo()->add_undo_method(root, "set_scene_file_path", root->get_scene_file_path());
+ editor_data->get_undo_redo()->add_undo_method(node, "set_scene_file_path", String());
+ editor_data->get_undo_redo()->add_undo_method(node, "remove_child", root);
+ editor_data->get_undo_redo()->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", root);
+ editor_data->get_undo_redo()->add_undo_method(node->get_parent(), "add_child", node, true);
+ editor_data->get_undo_redo()->add_undo_method(node->get_parent(), "move_child", node, node->get_index());
+ editor_data->get_undo_redo()->add_undo_method(root, "set_owner", (Object *)nullptr);
+ editor_data->get_undo_redo()->add_undo_method(node, "set_owner", root);
_node_replace_owner(root, root, root, MODE_UNDO);
- editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree");
- editor_data->get_undo_redo().add_undo_method(scene_tree, "update_tree");
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->add_do_method(scene_tree, "update_tree");
+ editor_data->get_undo_redo()->add_undo_method(scene_tree, "update_tree");
+ editor_data->get_undo_redo()->commit_action();
} break;
case TOOL_MULTI_EDIT: {
if (!profile_allow_editing) {
@@ -1009,7 +1008,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
Node *node = e->get();
if (node) {
Node *root = EditorNode::get_singleton()->get_edited_scene();
- UndoRedo *undo_redo = &editor_data->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = editor_data->get_undo_redo();
if (!root) {
break;
}
@@ -1069,24 +1068,61 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
}
} break;
case TOOL_TOGGLE_SCENE_UNIQUE_NAME: {
- List<Node *> selection = editor_selection->get_selected_node_list();
- List<Node *>::Element *e = selection.front();
- if (e) {
- UndoRedo *undo_redo = &editor_data->get_undo_redo();
- Node *node = e->get();
- bool enabled = node->is_unique_name_in_owner();
- if (!enabled && get_tree()->get_edited_scene_root()->get_node_or_null(UNIQUE_NODE_PREFIX + String(node->get_name())) != nullptr) {
- accept->set_text(TTR("Another node already uses this unique name in the scene."));
+ // Enabling/disabling based on the same node based on which the checkbox in the menu is checked/unchecked.
+ List<Node *>::Element *first_selected = editor_selection->get_selected_node_list().front();
+ if (first_selected == nullptr) {
+ return;
+ }
+ bool enabling = !first_selected->get()->is_unique_name_in_owner();
+
+ List<Node *> full_selection = editor_selection->get_full_selected_node_list();
+ Ref<EditorUndoRedoManager> undo_redo = editor_data->get_undo_redo();
+
+ if (enabling) {
+ Vector<Node *> new_unique_nodes;
+ Vector<StringName> new_unique_names;
+ Vector<StringName> cant_be_set_unique_names;
+
+ for (Node *node : full_selection) {
+ if (node->is_unique_name_in_owner()) {
+ continue;
+ }
+ StringName name = node->get_name();
+ if (new_unique_names.find(name) != -1 || get_tree()->get_edited_scene_root()->get_node_or_null(UNIQUE_NODE_PREFIX + String(name)) != nullptr) {
+ cant_be_set_unique_names.push_back(name);
+ } else {
+ new_unique_nodes.push_back(node);
+ new_unique_names.push_back(name);
+ }
+ }
+
+ if (new_unique_nodes.size()) {
+ undo_redo->create_action(TTR("Enable Scene Unique Name(s)"));
+ for (Node *node : new_unique_nodes) {
+ undo_redo->add_do_method(node, "set_unique_name_in_owner", true);
+ undo_redo->add_undo_method(node, "set_unique_name_in_owner", false);
+ }
+ undo_redo->commit_action();
+ }
+
+ if (cant_be_set_unique_names.size()) {
+ String popup_text = TTR("Unique names already used by another node in the scene:");
+ popup_text += "\n";
+ for (StringName name : cant_be_set_unique_names) {
+ popup_text += "\n" + String(name);
+ }
+ accept->set_text(popup_text);
accept->popup_centered();
- return;
}
- if (!enabled) {
- undo_redo->create_action(TTR("Enable Scene Unique Name"));
- } else {
- undo_redo->create_action(TTR("Disable Scene Unique Name"));
+ } else { // Disabling.
+ undo_redo->create_action(TTR("Disable Scene Unique Name(s)"));
+ for (Node *node : full_selection) {
+ if (!node->is_unique_name_in_owner()) {
+ continue;
+ }
+ undo_redo->add_do_method(node, "set_unique_name_in_owner", false);
+ undo_redo->add_undo_method(node, "set_unique_name_in_owner", true);
}
- undo_redo->add_do_method(node, "set_unique_name_in_owner", !enabled);
- undo_redo->add_undo_method(node, "set_unique_name_in_owner", enabled);
undo_redo->commit_action();
}
} break;
@@ -1161,19 +1197,19 @@ void SceneTreeDock::_property_selected(int p_idx) {
}
void SceneTreeDock::_perform_property_drop(Node *p_node, String p_property, Ref<Resource> p_res) {
- editor_data->get_undo_redo().create_action(vformat(TTR("Set %s"), p_property));
- editor_data->get_undo_redo().add_do_property(p_node, p_property, p_res);
- editor_data->get_undo_redo().add_undo_property(p_node, p_property, p_node->get(p_property));
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->create_action(vformat(TTR("Set %s"), p_property));
+ editor_data->get_undo_redo()->add_do_property(p_node, p_property, p_res);
+ editor_data->get_undo_redo()->add_undo_property(p_node, p_property, p_node->get(p_property));
+ editor_data->get_undo_redo()->commit_action();
}
void SceneTreeDock::add_root_node(Node *p_node) {
- editor_data->get_undo_redo().create_action(TTR("New Scene Root"));
- editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "set_edited_scene", p_node);
- editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree");
- editor_data->get_undo_redo().add_do_reference(p_node);
- editor_data->get_undo_redo().add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->create_action_for_history(TTR("New Scene Root"), editor_data->get_current_edited_scene_history_id());
+ editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "set_edited_scene", p_node);
+ editor_data->get_undo_redo()->add_do_method(scene_tree, "update_tree");
+ editor_data->get_undo_redo()->add_do_reference(p_node);
+ editor_data->get_undo_redo()->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
+ editor_data->get_undo_redo()->commit_action();
}
void SceneTreeDock::_node_collapsed(Object *p_obj) {
@@ -1231,7 +1267,7 @@ void SceneTreeDock::_notification(int p_what) {
node_shortcuts_toggle->set_name("NodeShortcutsToggle");
node_shortcuts_toggle->set_icon(get_theme_icon(SNAME("Favorites"), SNAME("EditorIcons")));
node_shortcuts_toggle->set_toggle_mode(true);
- node_shortcuts_toggle->set_tooltip(TTR("Switch to Favorite Nodes"));
+ node_shortcuts_toggle->set_tooltip_text(TTR("Switch to Favorite Nodes"));
node_shortcuts_toggle->set_pressed(EDITOR_GET("_use_favorites_root_selection"));
node_shortcuts_toggle->set_anchors_and_offsets_preset(Control::PRESET_CENTER_RIGHT);
node_shortcuts_toggle->connect("pressed", callable_mp(this, &SceneTreeDock::_update_create_root_dialog));
@@ -1335,7 +1371,7 @@ void SceneTreeDock::_notification(int p_what) {
void SceneTreeDock::_node_replace_owner(Node *p_base, Node *p_node, Node *p_root, ReplaceOwnerMode p_mode) {
if (p_node->get_owner() == p_base && p_node != p_root) {
- UndoRedo *undo_redo = &editor_data->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = editor_data->get_undo_redo();
switch (p_mode) {
case MODE_BIDI: {
bool disable_unique = p_node->is_unique_name_in_owner() && p_root->get_node_or_null(UNIQUE_NODE_PREFIX + String(p_node->get_name())) != nullptr;
@@ -1470,7 +1506,7 @@ bool SceneTreeDock::_update_node_path(Node *p_root_node, NodePath &r_node_path,
if (found_root_path) {
NodePath root_path_new = found_root_path->value;
if (!root_path_new.is_empty()) {
- NodePath old_abs_path = NodePath(String(p_root_node->get_path()).plus_file(r_node_path));
+ NodePath old_abs_path = NodePath(String(p_root_node->get_path()).path_join(r_node_path));
old_abs_path.simplify();
r_node_path = root_path_new.rel_path_to(old_abs_path);
}
@@ -1568,8 +1604,8 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath>
Variant old_variant = p_base->get(propertyname);
Variant updated_variant = old_variant;
if (_check_node_path_recursive(p_base, updated_variant, p_renames)) {
- editor_data->get_undo_redo().add_do_property(p_base, propertyname, updated_variant);
- editor_data->get_undo_redo().add_undo_property(p_base, propertyname, old_variant);
+ editor_data->get_undo_redo()->add_do_property(p_base, propertyname, updated_variant);
+ editor_data->get_undo_redo()->add_undo_property(p_base, propertyname, old_variant);
p_base->set(propertyname, updated_variant);
}
}
@@ -1627,12 +1663,12 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath>
ERR_FAIL_COND(!EI); //another bug
}
- editor_data->get_undo_redo().add_do_method(anim.ptr(), "remove_track", idx);
- editor_data->get_undo_redo().add_undo_method(anim.ptr(), "add_track", anim->track_get_type(i), idx);
- editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_set_path", idx, track_np);
- editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_set_interpolation_type", idx, anim->track_get_interpolation_type(i));
+ editor_data->get_undo_redo()->add_do_method(anim.ptr(), "remove_track", idx);
+ editor_data->get_undo_redo()->add_undo_method(anim.ptr(), "add_track", anim->track_get_type(i), idx);
+ editor_data->get_undo_redo()->add_undo_method(anim.ptr(), "track_set_path", idx, track_np);
+ editor_data->get_undo_redo()->add_undo_method(anim.ptr(), "track_set_interpolation_type", idx, anim->track_get_interpolation_type(i));
for (int j = 0; j < anim->track_get_key_count(i); j++) {
- editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_insert_key", idx, anim->track_get_key_time(i, j), anim->track_get_key_value(i, j), anim->track_get_key_transition(i, j));
+ editor_data->get_undo_redo()->add_undo_method(anim.ptr(), "track_insert_key", idx, anim->track_get_key_time(i, j), anim->track_get_key_value(i, j), anim->track_get_key_transition(i, j));
}
ran.erase(i); //byebye channel
@@ -1645,8 +1681,8 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath>
if (new_path == track_np) {
continue; //bleh
}
- editor_data->get_undo_redo().add_do_method(anim.ptr(), "track_set_path", i, new_path);
- editor_data->get_undo_redo().add_undo_method(anim.ptr(), "track_set_path", i, track_np);
+ editor_data->get_undo_redo()->add_do_method(anim.ptr(), "track_set_path", i, new_path);
+ editor_data->get_undo_redo()->add_undo_method(anim.ptr(), "track_set_path", i, track_np);
}
}
}
@@ -1780,7 +1816,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
// Sort by tree order, so re-adding is easy.
p_nodes.sort_custom<Node::Comparator>();
- editor_data->get_undo_redo().create_action(TTR("Reparent Node"));
+ editor_data->get_undo_redo()->create_action(TTR("Reparent Node"));
HashMap<Node *, NodePath> path_renames;
Vector<StringName> former_names;
@@ -1805,11 +1841,11 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
inc--; // If the child will generate a gap when moved, adjust.
}
- editor_data->get_undo_redo().add_do_method(node->get_parent(), "remove_child", node);
- editor_data->get_undo_redo().add_do_method(new_parent, "add_child", node, true);
+ editor_data->get_undo_redo()->add_do_method(node->get_parent(), "remove_child", node);
+ editor_data->get_undo_redo()->add_do_method(new_parent, "add_child", node, true);
if (p_position_in_parent >= 0) {
- editor_data->get_undo_redo().add_do_method(new_parent, "move_child", node, p_position_in_parent + inc);
+ editor_data->get_undo_redo()->add_do_method(new_parent, "move_child", node, p_position_in_parent + inc);
}
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
@@ -1839,29 +1875,29 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
}
}
- editor_data->get_undo_redo().add_do_method(ed, "live_debug_reparent_node", edited_scene->get_path_to(node), edited_scene->get_path_to(new_parent), new_name, p_position_in_parent + inc);
- editor_data->get_undo_redo().add_undo_method(ed, "live_debug_reparent_node", NodePath(String(edited_scene->get_path_to(new_parent)).plus_file(new_name)), edited_scene->get_path_to(node->get_parent()), node->get_name(), node->get_index());
+ editor_data->get_undo_redo()->add_do_method(ed, "live_debug_reparent_node", edited_scene->get_path_to(node), edited_scene->get_path_to(new_parent), new_name, p_position_in_parent + inc);
+ editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_reparent_node", NodePath(String(edited_scene->get_path_to(new_parent)).path_join(new_name)), edited_scene->get_path_to(node->get_parent()), node->get_name(), node->get_index());
if (p_keep_global_xform) {
if (Object::cast_to<Node2D>(node)) {
- editor_data->get_undo_redo().add_do_method(node, "set_global_transform", Object::cast_to<Node2D>(node)->get_global_transform());
+ editor_data->get_undo_redo()->add_do_method(node, "set_global_transform", Object::cast_to<Node2D>(node)->get_global_transform());
}
if (Object::cast_to<Node3D>(node)) {
- editor_data->get_undo_redo().add_do_method(node, "set_global_transform", Object::cast_to<Node3D>(node)->get_global_transform());
+ editor_data->get_undo_redo()->add_do_method(node, "set_global_transform", Object::cast_to<Node3D>(node)->get_global_transform());
}
if (Object::cast_to<Control>(node)) {
- editor_data->get_undo_redo().add_do_method(node, "set_global_position", Object::cast_to<Control>(node)->get_global_position());
+ editor_data->get_undo_redo()->add_do_method(node, "set_global_position", Object::cast_to<Control>(node)->get_global_position());
}
}
- editor_data->get_undo_redo().add_do_method(this, "_set_owners", edited_scene, owners);
+ editor_data->get_undo_redo()->add_do_method(this, "_set_owners", edited_scene, owners);
if (AnimationPlayerEditor::get_singleton()->get_track_editor()->get_root() == node) {
- editor_data->get_undo_redo().add_do_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node);
+ editor_data->get_undo_redo()->add_do_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node);
}
- editor_data->get_undo_redo().add_undo_method(new_parent, "remove_child", node);
- editor_data->get_undo_redo().add_undo_method(node, "set_name", former_names[ni]);
+ editor_data->get_undo_redo()->add_undo_method(new_parent, "remove_child", node);
+ editor_data->get_undo_redo()->add_undo_method(node, "set_name", former_names[ni]);
inc++;
}
@@ -1879,29 +1915,29 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
int child_pos = node->get_index();
- editor_data->get_undo_redo().add_undo_method(node->get_parent(), "add_child", node, true);
- editor_data->get_undo_redo().add_undo_method(node->get_parent(), "move_child", node, child_pos);
- editor_data->get_undo_redo().add_undo_method(this, "_set_owners", edited_scene, owners);
+ editor_data->get_undo_redo()->add_undo_method(node->get_parent(), "add_child", node, true);
+ editor_data->get_undo_redo()->add_undo_method(node->get_parent(), "move_child", node, child_pos);
+ editor_data->get_undo_redo()->add_undo_method(this, "_set_owners", edited_scene, owners);
if (AnimationPlayerEditor::get_singleton()->get_track_editor()->get_root() == node) {
- editor_data->get_undo_redo().add_undo_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node);
+ editor_data->get_undo_redo()->add_undo_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", node);
}
if (p_keep_global_xform) {
if (Object::cast_to<Node2D>(node)) {
- editor_data->get_undo_redo().add_undo_method(node, "set_transform", Object::cast_to<Node2D>(node)->get_transform());
+ editor_data->get_undo_redo()->add_undo_method(node, "set_transform", Object::cast_to<Node2D>(node)->get_transform());
}
if (Object::cast_to<Node3D>(node)) {
- editor_data->get_undo_redo().add_undo_method(node, "set_transform", Object::cast_to<Node3D>(node)->get_transform());
+ editor_data->get_undo_redo()->add_undo_method(node, "set_transform", Object::cast_to<Node3D>(node)->get_transform());
}
if (Object::cast_to<Control>(node)) {
- editor_data->get_undo_redo().add_undo_method(node, "set_position", Object::cast_to<Control>(node)->get_position());
+ editor_data->get_undo_redo()->add_undo_method(node, "set_position", Object::cast_to<Control>(node)->get_position());
}
}
}
perform_node_renames(nullptr, &path_renames);
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->commit_action();
}
bool SceneTreeDock::_is_collapsed_recursive(TreeItem *p_item) const {
@@ -1957,30 +1993,30 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) {
Node *node = selected.front()->get();
Ref<Script> existing = node->get_script();
- editor_data->get_undo_redo().create_action(TTR("Attach Script"));
- editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "store_script_properties", node);
- editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "store_script_properties", node);
- editor_data->get_undo_redo().add_do_method(node, "set_script", p_script);
- editor_data->get_undo_redo().add_undo_method(node, "set_script", existing);
- editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "apply_script_properties", node);
- editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", node);
- editor_data->get_undo_redo().add_do_method(this, "_update_script_button");
- editor_data->get_undo_redo().add_undo_method(this, "_update_script_button");
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->create_action(TTR("Attach Script"));
+ editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "store_script_properties", node);
+ editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "store_script_properties", node);
+ editor_data->get_undo_redo()->add_do_method(node, "set_script", p_script);
+ editor_data->get_undo_redo()->add_undo_method(node, "set_script", existing);
+ editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "apply_script_properties", node);
+ editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", node);
+ editor_data->get_undo_redo()->add_do_method(this, "_update_script_button");
+ editor_data->get_undo_redo()->add_undo_method(this, "_update_script_button");
+ editor_data->get_undo_redo()->commit_action();
} else {
- editor_data->get_undo_redo().create_action(TTR("Attach Script"));
- for (List<Node *>::Element *E = selected.front(); E; E = E->next()) {
- Ref<Script> existing = E->get()->get_script();
- editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "store_script_properties", E->get());
- editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "store_script_properties", E->get());
- editor_data->get_undo_redo().add_do_method(E->get(), "set_script", p_script);
- editor_data->get_undo_redo().add_undo_method(E->get(), "set_script", existing);
- editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "apply_script_properties", E->get());
- editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", E->get());
- editor_data->get_undo_redo().add_do_method(this, "_update_script_button");
- editor_data->get_undo_redo().add_undo_method(this, "_update_script_button");
+ editor_data->get_undo_redo()->create_action(TTR("Attach Script"));
+ for (Node *E : selected) {
+ Ref<Script> existing = E->get_script();
+ editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "store_script_properties", E);
+ editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "store_script_properties", E);
+ editor_data->get_undo_redo()->add_do_method(E, "set_script", p_script);
+ editor_data->get_undo_redo()->add_undo_method(E, "set_script", existing);
+ editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "apply_script_properties", E);
+ editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", E);
+ editor_data->get_undo_redo()->add_do_method(this, "_update_script_button");
+ editor_data->get_undo_redo()->add_undo_method(this, "_update_script_button");
}
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->commit_action();
}
_push_item(p_script.operator->());
@@ -1994,10 +2030,10 @@ void SceneTreeDock::_shader_created(Ref<Shader> p_shader) {
Ref<Shader> existing = selected_shader_material->get_shader();
- editor_data->get_undo_redo().create_action(TTR("Set Shader"));
- editor_data->get_undo_redo().add_do_method(selected_shader_material.ptr(), "set_shader", p_shader);
- editor_data->get_undo_redo().add_undo_method(selected_shader_material.ptr(), "set_shader", existing);
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->create_action(TTR("Set Shader"));
+ editor_data->get_undo_redo()->add_do_method(selected_shader_material.ptr(), "set_shader", p_shader);
+ editor_data->get_undo_redo()->add_undo_method(selected_shader_material.ptr(), "set_shader", existing);
+ editor_data->get_undo_redo()->commit_action();
}
void SceneTreeDock::_script_creation_closed() {
@@ -2063,9 +2099,9 @@ void SceneTreeDock::_delete_confirm(bool p_cut) {
EditorNode::get_singleton()->get_editor_plugins_over()->make_visible(false);
if (p_cut) {
- editor_data->get_undo_redo().create_action(TTR("Cut Node(s)"));
+ editor_data->get_undo_redo()->create_action(TTR("Cut Node(s)"));
} else {
- editor_data->get_undo_redo().create_action(TTR("Remove Node(s)"));
+ editor_data->get_undo_redo()->create_action(TTR("Remove Node(s)"));
}
bool entire_scene = false;
@@ -2077,11 +2113,11 @@ void SceneTreeDock::_delete_confirm(bool p_cut) {
}
if (entire_scene) {
- editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
- editor_data->get_undo_redo().add_undo_method(EditorNode::get_singleton(), "set_edited_scene", edited_scene);
- editor_data->get_undo_redo().add_undo_method(edited_scene, "set_owner", edited_scene->get_owner());
- editor_data->get_undo_redo().add_undo_method(scene_tree, "update_tree");
- editor_data->get_undo_redo().add_undo_reference(edited_scene);
+ editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
+ editor_data->get_undo_redo()->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", edited_scene);
+ editor_data->get_undo_redo()->add_undo_method(edited_scene, "set_owner", edited_scene->get_owner());
+ editor_data->get_undo_redo()->add_undo_method(scene_tree, "update_tree");
+ editor_data->get_undo_redo()->add_undo_reference(edited_scene);
} else {
remove_list.sort_custom<Node::Comparator>(); //sort nodes to keep positions
@@ -2110,21 +2146,21 @@ void SceneTreeDock::_delete_confirm(bool p_cut) {
owners.push_back(F);
}
- editor_data->get_undo_redo().add_do_method(n->get_parent(), "remove_child", n);
- editor_data->get_undo_redo().add_undo_method(n->get_parent(), "add_child", n, true);
- editor_data->get_undo_redo().add_undo_method(n->get_parent(), "move_child", n, n->get_index());
+ editor_data->get_undo_redo()->add_do_method(n->get_parent(), "remove_child", n);
+ editor_data->get_undo_redo()->add_undo_method(n->get_parent(), "add_child", n, true);
+ editor_data->get_undo_redo()->add_undo_method(n->get_parent(), "move_child", n, n->get_index());
if (AnimationPlayerEditor::get_singleton()->get_track_editor()->get_root() == n) {
- editor_data->get_undo_redo().add_undo_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", n);
+ editor_data->get_undo_redo()->add_undo_method(AnimationPlayerEditor::get_singleton()->get_track_editor(), "set_root", n);
}
- editor_data->get_undo_redo().add_undo_method(this, "_set_owners", edited_scene, owners);
- editor_data->get_undo_redo().add_undo_reference(n);
+ editor_data->get_undo_redo()->add_undo_method(this, "_set_owners", edited_scene, owners);
+ editor_data->get_undo_redo()->add_undo_reference(n);
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
- editor_data->get_undo_redo().add_do_method(ed, "live_debug_remove_and_keep_node", edited_scene->get_path_to(n), n->get_instance_id());
- editor_data->get_undo_redo().add_undo_method(ed, "live_debug_restore_node", n->get_instance_id(), edited_scene->get_path_to(n->get_parent()), n->get_index());
+ editor_data->get_undo_redo()->add_do_method(ed, "live_debug_remove_and_keep_node", edited_scene->get_path_to(n), n->get_instance_id());
+ editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_restore_node", n->get_instance_id(), edited_scene->get_path_to(n->get_parent()), n->get_index());
}
}
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->commit_action();
// hack, force 2d editor viewport to refresh after deletion
if (CanvasItemEditor *editor = CanvasItemEditor::get_singleton()) {
@@ -2190,29 +2226,29 @@ void SceneTreeDock::_do_create(Node *p_parent) {
Node *child = Object::cast_to<Node>(c);
ERR_FAIL_COND(!child);
- editor_data->get_undo_redo().create_action(TTR("Create Node"));
+ editor_data->get_undo_redo()->create_action(TTR("Create Node"));
if (edited_scene) {
- editor_data->get_undo_redo().add_do_method(p_parent, "add_child", child, true);
- editor_data->get_undo_redo().add_do_method(child, "set_owner", edited_scene);
- editor_data->get_undo_redo().add_do_method(editor_selection, "clear");
- editor_data->get_undo_redo().add_do_method(editor_selection, "add_node", child);
- editor_data->get_undo_redo().add_do_reference(child);
- editor_data->get_undo_redo().add_undo_method(p_parent, "remove_child", child);
+ editor_data->get_undo_redo()->add_do_method(p_parent, "add_child", child, true);
+ editor_data->get_undo_redo()->add_do_method(child, "set_owner", edited_scene);
+ editor_data->get_undo_redo()->add_do_method(editor_selection, "clear");
+ editor_data->get_undo_redo()->add_do_method(editor_selection, "add_node", child);
+ editor_data->get_undo_redo()->add_do_reference(child);
+ editor_data->get_undo_redo()->add_undo_method(p_parent, "remove_child", child);
String new_name = p_parent->validate_child_name(child);
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
- editor_data->get_undo_redo().add_do_method(ed, "live_debug_create_node", edited_scene->get_path_to(p_parent), child->get_class(), new_name);
- editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)).plus_file(new_name)));
+ editor_data->get_undo_redo()->add_do_method(ed, "live_debug_create_node", edited_scene->get_path_to(p_parent), child->get_class(), new_name);
+ editor_data->get_undo_redo()->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)).path_join(new_name)));
} else {
- editor_data->get_undo_redo().add_do_method(EditorNode::get_singleton(), "set_edited_scene", child);
- editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree");
- editor_data->get_undo_redo().add_do_reference(child);
- editor_data->get_undo_redo().add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
+ editor_data->get_undo_redo()->add_do_method(EditorNode::get_singleton(), "set_edited_scene", child);
+ editor_data->get_undo_redo()->add_do_method(scene_tree, "update_tree");
+ editor_data->get_undo_redo()->add_do_reference(child);
+ editor_data->get_undo_redo()->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
}
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->commit_action();
_push_item(c);
editor_selection->clear();
editor_selection->add_node(child);
@@ -2259,8 +2295,8 @@ void SceneTreeDock::_create() {
List<Node *> selection = editor_selection->get_selected_node_list();
ERR_FAIL_COND(selection.size() <= 0);
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
- ur->create_action(TTR("Change type of node(s)"));
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ ur->create_action(TTR("Change type of node(s)"), UndoRedo::MERGE_DISABLE, selection.front()->get());
for (Node *n : selection) {
ERR_FAIL_COND(!n);
@@ -2393,7 +2429,7 @@ void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node, bool p_keep_prop
}
//p_remove_old was added to support undo
if (p_remove_old) {
- editor_data->get_undo_redo().clear_history();
+ editor_data->get_undo_redo()->clear_history();
}
newnode->set_name(newname);
@@ -2607,16 +2643,16 @@ void SceneTreeDock::_script_dropped(String p_file, NodePath p_to) {
Ref<Script> scr = ResourceLoader::load(p_file);
ERR_FAIL_COND(!scr.is_valid());
if (Node *n = get_node(p_to)) {
- editor_data->get_undo_redo().create_action(TTR("Attach Script"));
- editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "store_script_properties", n);
- editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "store_script_properties", n);
- editor_data->get_undo_redo().add_do_method(n, "set_script", scr);
- editor_data->get_undo_redo().add_undo_method(n, "set_script", n->get_script());
- editor_data->get_undo_redo().add_do_method(InspectorDock::get_singleton(), "apply_script_properties", n);
- editor_data->get_undo_redo().add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", n);
- editor_data->get_undo_redo().add_do_method(this, "_update_script_button");
- editor_data->get_undo_redo().add_undo_method(this, "_update_script_button");
- editor_data->get_undo_redo().commit_action();
+ editor_data->get_undo_redo()->create_action(TTR("Attach Script"));
+ editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "store_script_properties", n);
+ editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "store_script_properties", n);
+ editor_data->get_undo_redo()->add_do_method(n, "set_script", scr);
+ editor_data->get_undo_redo()->add_undo_method(n, "set_script", n->get_script());
+ editor_data->get_undo_redo()->add_do_method(InspectorDock::get_singleton(), "apply_script_properties", n);
+ editor_data->get_undo_redo()->add_undo_method(InspectorDock::get_singleton(), "apply_script_properties", n);
+ editor_data->get_undo_redo()->add_do_method(this, "_update_script_button");
+ editor_data->get_undo_redo()->add_undo_method(this, "_update_script_button");
+ editor_data->get_undo_redo()->commit_action();
}
}
@@ -2678,7 +2714,7 @@ void SceneTreeDock::_add_children_to_popup(Object *p_obj, int p_depth) {
}
int index = menu_subresources->get_item_count();
menu_subresources->add_icon_item(icon, E.name.capitalize(), EDIT_SUBRESOURCE_BASE + subresources.size());
- menu_subresources->set_item_horizontal_offset(index, p_depth * 10 * EDSCALE);
+ menu_subresources->set_item_indent(index, p_depth);
subresources.push_back(obj->get_instance_id());
_add_children_to_popup(obj, p_depth + 1);
@@ -2822,14 +2858,26 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
menu->add_separator();
menu->add_icon_shortcut(get_theme_icon(SNAME("CopyNodePath"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/copy_node_path"), TOOL_COPY_NODE_PATH);
}
+ }
- if (selection[0]->get_owner() == EditorNode::get_singleton()->get_edited_scene()) {
- // Only for nodes owned by the edited scene root.
+ if (profile_allow_editing) {
+ // Allow multi-toggling scene unique names but only if all selected nodes are owned by the edited scene root.
+ bool all_owned = true;
+ for (Node *node : full_selection) {
+ if (node->get_owner() != EditorNode::get_singleton()->get_edited_scene()) {
+ all_owned = false;
+ break;
+ }
+ }
+ if (all_owned) {
menu->add_separator();
menu->add_icon_check_item(get_theme_icon(SNAME("SceneUniqueName"), SNAME("EditorIcons")), TTR("Access as Scene Unique Name"), TOOL_TOGGLE_SCENE_UNIQUE_NAME);
+ // Checked based on `selection[0]` because `full_selection` has undesired ordering.
menu->set_item_checked(menu->get_item_index(TOOL_TOGGLE_SCENE_UNIQUE_NAME), selection[0]->is_unique_name_in_owner());
}
+ }
+ if (selection.size() == 1) {
bool is_external = (!selection[0]->get_scene_file_path().is_empty());
if (is_external) {
bool is_inherited = selection[0]->get_scene_inherited_state() != nullptr;
@@ -2939,9 +2987,9 @@ void SceneTreeDock::attach_script_to_selected(bool p_extend) {
if (path.is_empty()) {
String root_path = editor_data->get_edited_scene_root()->get_scene_file_path();
if (root_path.is_empty()) {
- path = String("res://").plus_file(selected->get_name());
+ path = String("res://").path_join(selected->get_name());
} else {
- path = root_path.get_base_dir().plus_file(selected->get_name());
+ path = root_path.get_base_dir().path_join(selected->get_name());
}
}
@@ -2998,9 +3046,9 @@ void SceneTreeDock::attach_shader_to_selected(int p_preferred_mode) {
shader_name = selected_shader_material->get_name();
}
if (root_path.is_empty()) {
- path = String("res://").plus_file(shader_name);
+ path = String("res://").path_join(shader_name);
} else {
- path = root_path.get_base_dir().plus_file(shader_name);
+ path = root_path.get_base_dir().path_join(shader_name);
}
}
@@ -3064,9 +3112,9 @@ List<Node *> SceneTreeDock::paste_nodes() {
owner = paste_parent;
}
- UndoRedo &ur = editor_data->get_undo_redo();
- ur.create_action(TTR("Paste Node(s)"));
- ur.add_do_method(editor_selection, "clear");
+ Ref<EditorUndoRedoManager> &ur = editor_data->get_undo_redo();
+ ur->create_action(TTR("Paste Node(s)"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
+ ur->add_do_method(editor_selection, "clear");
HashMap<Ref<Resource>, Ref<Resource>> resource_remap;
String target_scene;
@@ -3095,36 +3143,36 @@ List<Node *> SceneTreeDock::paste_nodes() {
if (!paste_parent) {
paste_parent = dup;
owner = dup;
- ur.add_do_method(EditorNode::get_singleton(), "set_edited_scene", dup);
+ ur->add_do_method(EditorNode::get_singleton(), "set_edited_scene", dup);
} else {
- ur.add_do_method(paste_parent, "add_child", dup, true);
+ ur->add_do_method(paste_parent, "add_child", dup, true);
}
for (KeyValue<const Node *, Node *> &E2 : duplimap) {
Node *d = E2.value;
if (d != dup) {
- ur.add_do_method(d, "set_owner", owner);
+ ur->add_do_method(d, "set_owner", owner);
}
}
if (dup != owner) {
- ur.add_do_method(dup, "set_owner", owner);
+ ur->add_do_method(dup, "set_owner", owner);
}
- ur.add_do_method(editor_selection, "add_node", dup);
+ ur->add_do_method(editor_selection, "add_node", dup);
if (dup == paste_parent) {
- ur.add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
+ ur->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
} else {
- ur.add_undo_method(paste_parent, "remove_child", dup);
+ ur->add_undo_method(paste_parent, "remove_child", dup);
}
- ur.add_do_reference(dup);
+ ur->add_do_reference(dup);
if (node_clipboard.size() == 1) {
- ur.add_do_method(EditorNode::get_singleton(), "push_item", dup);
+ ur->add_do_method(EditorNode::get_singleton(), "push_item", dup);
}
}
- ur.commit_action();
+ ur->commit_action();
return pasted_nodes;
}
@@ -3200,7 +3248,7 @@ void SceneTreeDock::_update_create_root_dialog() {
favorite_nodes->get_child(i)->queue_delete();
}
- Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().plus_file("favorites.Node"), FileAccess::READ);
+ Ref<FileAccess> f = FileAccess::open(EditorPaths::get_singleton()->get_project_settings_dir().path_join("favorites.Node"), FileAccess::READ);
if (f.is_valid()) {
while (!f->eof_reached()) {
String l = f->get_line().strip_edges();
@@ -3398,14 +3446,14 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
button_add = memnew(Button);
button_add->set_flat(true);
button_add->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_NEW, false));
- button_add->set_tooltip(TTR("Add/Create a New Node."));
+ button_add->set_tooltip_text(TTR("Add/Create a New Node."));
button_add->set_shortcut(ED_GET_SHORTCUT("scene_tree/add_child_node"));
filter_hbc->add_child(button_add);
button_instance = memnew(Button);
button_instance->set_flat(true);
button_instance->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_INSTANTIATE, false));
- button_instance->set_tooltip(TTR("Instantiate a scene file as a Node. Creates an inherited scene if no root node exists."));
+ button_instance->set_tooltip_text(TTR("Instantiate a scene file as a Node. Creates an inherited scene if no root node exists."));
button_instance->set_shortcut(ED_GET_SHORTCUT("scene_tree/instance_scene"));
filter_hbc->add_child(button_instance);
@@ -3420,7 +3468,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
button_create_script = memnew(Button);
button_create_script->set_flat(true);
button_create_script->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_ATTACH_SCRIPT, false));
- button_create_script->set_tooltip(TTR("Attach a new or existing script to the selected node."));
+ button_create_script->set_tooltip_text(TTR("Attach a new or existing script to the selected node."));
button_create_script->set_shortcut(ED_GET_SHORTCUT("scene_tree/attach_script"));
filter_hbc->add_child(button_create_script);
button_create_script->hide();
@@ -3428,7 +3476,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
button_detach_script = memnew(Button);
button_detach_script->set_flat(true);
button_detach_script->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected).bind(TOOL_DETACH_SCRIPT, false));
- button_detach_script->set_tooltip(TTR("Detach the script from the selected node."));
+ button_detach_script->set_tooltip_text(TTR("Detach the script from the selected node."));
button_detach_script->set_shortcut(ED_GET_SHORTCUT("scene_tree/detach_script"));
filter_hbc->add_child(button_detach_script);
button_detach_script->hide();
@@ -3451,7 +3499,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
edit_remote->set_h_size_flags(SIZE_EXPAND_FILL);
edit_remote->set_text(TTR("Remote"));
edit_remote->set_toggle_mode(true);
- edit_remote->set_tooltip(TTR("If selected, the Remote scene tree dock will cause the project to stutter every time it updates.\nSwitch back to the Local scene tree dock to improve performance."));
+ edit_remote->set_tooltip_text(TTR("If selected, the Remote scene tree dock will cause the project to stutter every time it updates.\nSwitch back to the Local scene tree dock to improve performance."));
edit_remote->connect("pressed", callable_mp(this, &SceneTreeDock::_remote_tree_selected));
edit_local = memnew(Button);
@@ -3492,7 +3540,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
editor_selection->connect("selection_changed", callable_mp(this, &SceneTreeDock::_selection_changed));
- scene_tree->set_undo_redo(&editor_data->get_undo_redo());
+ scene_tree->set_undo_redo(editor_data->get_undo_redo());
scene_tree->set_editor_selection(editor_selection);
create_dialog = memnew(CreateDialog);
@@ -3502,7 +3550,7 @@ SceneTreeDock::SceneTreeDock(Node *p_scene_root, EditorSelection *p_editor_selec
create_dialog->connect("favorites_updated", callable_mp(this, &SceneTreeDock::_update_create_root_dialog));
#ifdef MODULE_REGEX_ENABLED
- rename_dialog = memnew(RenameDialog(scene_tree, &editor_data->get_undo_redo()));
+ rename_dialog = memnew(RenameDialog(scene_tree, editor_data->get_undo_redo()));
add_child(rename_dialog);
#endif // MODULE_REGEX_ENABLED
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index c74a4c884d..00fd0c3aac 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -35,6 +35,7 @@
#include "editor/editor_file_system.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/node_dock.h"
#include "editor/plugins/animation_player_editor_plugin.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
@@ -268,7 +269,29 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
String warning = p_node->get_configuration_warnings_as_string();
if (!warning.is_empty()) {
- item->add_button(0, get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons")), BUTTON_WARNING, false, TTR("Node configuration warning:") + "\n" + warning);
+ const int num_warnings = p_node->get_configuration_warnings().size();
+ String warning_icon;
+ if (num_warnings == 1) {
+ warning_icon = SNAME("NodeWarning");
+ } else if (num_warnings <= 3) {
+ warning_icon = vformat("NodeWarnings%d", num_warnings);
+ } else {
+ warning_icon = SNAME("NodeWarnings4Plus");
+ }
+
+ // Improve looks on tooltip, extra spacing on non-bullet point newlines.
+ const String bullet_point = String::utf8("• ");
+ int next_newline = 0;
+ while (next_newline != -1) {
+ next_newline = warning.find("\n", next_newline + 2);
+ if (warning.substr(next_newline + 1, bullet_point.length()) != bullet_point) {
+ warning = warning.insert(next_newline + 1, " ");
+ }
+ }
+
+ String newline = (num_warnings == 1 ? "\n" : "\n\n");
+
+ item->add_button(0, get_theme_icon(warning_icon, SNAME("EditorIcons")), BUTTON_WARNING, false, TTR("Node configuration warning:") + newline + warning);
}
if (p_node->is_unique_name_in_owner()) {
@@ -355,7 +378,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
item->set_tooltip(0, tooltip);
}
- if (can_open_instance && undo_redo) { //Show buttons only when necessary(SceneTreeDock) to avoid crashes
+ if (can_open_instance && undo_redo.is_valid()) { //Show buttons only when necessary(SceneTreeDock) to avoid crashes
if (!p_node->is_connected("script_changed", callable_mp(this, &SceneTreeEditor::_node_script_changed))) {
p_node->connect("script_changed", callable_mp(this, &SceneTreeEditor::_node_script_changed).bind(p_node));
@@ -375,7 +398,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
}
if (p_node->has_meta("_edit_group_")) {
- item->add_button(0, get_theme_icon(SNAME("Group"), SNAME("EditorIcons")), BUTTON_GROUP, false, TTR("Children are not selectable.\nClick to make selectable."));
+ item->add_button(0, get_theme_icon(SNAME("Group"), SNAME("EditorIcons")), BUTTON_GROUP, false, TTR("Children are not selectable.\nClick to make them selectable."));
}
bool v = p_node->call("is_visible");
@@ -390,7 +413,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
}
_update_visibility_color(p_node, item);
- } else if (p_node->is_class("CanvasLayer")) {
+ } else if (p_node->is_class("CanvasLayer") || p_node->is_class("Window")) {
bool v = p_node->call("is_visible");
if (v) {
item->add_button(0, get_theme_icon(SNAME("GuiVisibilityVisible"), SNAME("EditorIcons")), BUTTON_VISIBILITY, false, TTR("Toggle Visibility"));
@@ -407,7 +430,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) {
}
if (p_node->has_meta("_edit_group_")) {
- item->add_button(0, get_theme_icon(SNAME("Group"), SNAME("EditorIcons")), BUTTON_GROUP, false, TTR("Children are not selectable.\nClick to make selectable."));
+ item->add_button(0, get_theme_icon(SNAME("Group"), SNAME("EditorIcons")), BUTTON_GROUP, false, TTR("Children are not selectable.\nClick to make them selectable."));
}
bool v = p_node->call("is_visible");
@@ -480,10 +503,7 @@ void SceneTreeEditor::_node_visibility_changed(Node *p_node) {
bool visible = false;
- if (p_node->is_class("CanvasItem")) {
- visible = p_node->call("is_visible");
- CanvasItemEditor::get_singleton()->get_viewport_control()->update();
- } else if (p_node->is_class("CanvasLayer")) {
+ if (p_node->is_class("CanvasItem") || p_node->is_class("CanvasLayer") || p_node->is_class("Window")) {
visible = p_node->call("is_visible");
CanvasItemEditor::get_singleton()->get_viewport_control()->update();
} else if (p_node->is_class("Node3D")) {
@@ -529,7 +549,7 @@ void SceneTreeEditor::_node_removed(Node *p_node) {
p_node->disconnect("script_changed", callable_mp(this, &SceneTreeEditor::_node_script_changed));
}
- if (p_node->is_class("Node3D") || p_node->is_class("CanvasItem") || p_node->is_class("CanvasLayer")) {
+ if (p_node->is_class("Node3D") || p_node->is_class("CanvasItem") || p_node->is_class("CanvasLayer") || p_node->is_class("Window")) {
if (p_node->is_connected("visibility_changed", callable_mp(this, &SceneTreeEditor::_node_visibility_changed))) {
p_node->disconnect("visibility_changed", callable_mp(this, &SceneTreeEditor::_node_visibility_changed));
}
@@ -595,7 +615,9 @@ bool SceneTreeEditor::_update_filter(TreeItem *p_parent, bool p_scroll_to_select
}
if (!keep) {
- keep = filter.is_subsequence_ofn(p_parent->get_text(0));
+ StringName node_type = get_node(p_parent->get_metadata(0))->get_class();
+ bool is_kept_by_type = (filter.begins_with("type:") && filter.trim_prefix("type:").is_subsequence_ofn(node_type)) || (filter.begins_with("t:") && filter.trim_prefix("t:").is_subsequence_ofn(node_type));
+ keep = (filter.is_subsequence_ofn(p_parent->get_text(0)) || is_kept_by_type);
}
p_parent->set_visible(keep);
@@ -876,7 +898,7 @@ void SceneTreeEditor::_renamed() {
return;
}
- if (!undo_redo) {
+ if (!undo_redo.is_valid()) {
n->set_name(new_name);
which->set_metadata(0, n->get_path());
emit_signal(SNAME("node_renamed"));
@@ -920,6 +942,10 @@ String SceneTreeEditor::get_filter() const {
return filter;
}
+void SceneTreeEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
+ undo_redo = p_undo_redo;
+}
+
void SceneTreeEditor::set_display_foreign_nodes(bool p_display) {
display_foreign = p_display;
_update_tree();
@@ -1251,7 +1277,6 @@ void SceneTreeEditor::_bind_methods() {
}
SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_open_instance) {
- undo_redo = nullptr;
selected = nullptr;
can_rename = p_can_rename;
diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h
index 31772e55b5..0c13ad96cd 100644
--- a/editor/scene_tree_editor.h
+++ b/editor/scene_tree_editor.h
@@ -31,13 +31,14 @@
#ifndef SCENE_TREE_EDITOR_H
#define SCENE_TREE_EDITOR_H
-#include "core/object/undo_redo.h"
#include "editor/editor_data.h"
#include "editor/editor_settings.h"
#include "scene/gui/button.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/tree.h"
+class EditorUndoRedoManager;
+
class SceneTreeEditor : public Control {
GDCLASS(SceneTreeEditor, Control);
@@ -98,7 +99,7 @@ class SceneTreeEditor : public Control {
bool show_enabled_subscene = false;
void _renamed();
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
HashSet<Node *> marked;
bool marked_selectable = false;
@@ -139,7 +140,7 @@ public:
void set_filter(const String &p_filter);
String get_filter() const;
- void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; };
+ void set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo);
void set_display_foreign_nodes(bool p_display);
void set_marked(const HashSet<Node *> &p_marked, bool p_selectable = false, bool p_children_selectable = true);
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index 77e0321f83..e09862263c 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -166,6 +166,7 @@ void ScriptCreateDialog::config(const String &p_base_name, const String &p_base_
class_name->deselect();
parent_name->set_text(p_base_name);
parent_name->deselect();
+ internal_name->set_text("");
if (!p_base_path.is_empty()) {
initial_bp = p_base_path.get_basename();
@@ -823,7 +824,7 @@ Vector<ScriptLanguage::ScriptTemplate> ScriptCreateDialog::_get_user_templates(c
Vector<ScriptLanguage::ScriptTemplate> user_templates;
String extension = language->get_extension();
- String dir_path = p_dir.plus_file(p_object);
+ String dir_path = p_dir.path_join(p_object);
Ref<DirAccess> d = DirAccess::open(dir_path);
if (d.is_valid()) {
@@ -859,7 +860,7 @@ ScriptLanguage::ScriptTemplate ScriptCreateDialog::_parse_template(const ScriptL
// Parse file for meta-information and script content
Error err;
- Ref<FileAccess> file = FileAccess::open(p_path.plus_file(p_filename), FileAccess::READ, &err);
+ Ref<FileAccess> file = FileAccess::open(p_path.path_join(p_filename), FileAccess::READ, &err);
if (!err) {
while (!file->eof_reached()) {
String line = file->get_line();
diff --git a/editor/shader_create_dialog.cpp b/editor/shader_create_dialog.cpp
index bd1f2529ca..8c4a231e8a 100644
--- a/editor/shader_create_dialog.cpp
+++ b/editor/shader_create_dialog.cpp
@@ -37,6 +37,13 @@
#include "scene/resources/visual_shader.h"
#include "servers/rendering/shader_types.h"
+enum ShaderType {
+ SHADER_TYPE_TEXT,
+ SHADER_TYPE_VISUAL,
+ SHADER_TYPE_INC,
+ SHADER_TYPE_MAX,
+};
+
void ShaderCreateDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
diff --git a/editor/shader_create_dialog.h b/editor/shader_create_dialog.h
index bf031c3601..9ba655369b 100644
--- a/editor/shader_create_dialog.h
+++ b/editor/shader_create_dialog.h
@@ -44,13 +44,6 @@ class EditorFileDialog;
class ShaderCreateDialog : public ConfirmationDialog {
GDCLASS(ShaderCreateDialog, ConfirmationDialog);
- enum ShaderType {
- SHADER_TYPE_TEXT,
- SHADER_TYPE_VISUAL,
- SHADER_TYPE_INC,
- SHADER_TYPE_MAX,
- };
-
struct ShaderTypeData {
List<String> extensions;
String default_extension;
diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp
index 1cd1b4ea00..9058596830 100644
--- a/editor/shader_globals_editor.cpp
+++ b/editor/shader_globals_editor.cpp
@@ -32,6 +32,7 @@
#include "core/config/project_settings.h"
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
#include "servers/rendering/shader_language.h"
static const char *global_var_type_names[RS::GLOBAL_VAR_TYPE_MAX] = {
@@ -85,7 +86,7 @@ protected:
return false;
}
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
undo_redo->create_action(TTR("Set Shader Global Variable"));
undo_redo->add_do_method(RS::get_singleton(), "global_shader_uniform_set", p_name, p_value);
@@ -393,7 +394,7 @@ void ShaderGlobalsEditor::_variable_added() {
return;
}
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo();
Variant value = create_var(RS::GlobalShaderUniformType(variable_type->get_selected()));
@@ -412,7 +413,7 @@ void ShaderGlobalsEditor::_variable_added() {
}
void ShaderGlobalsEditor::_variable_deleted(const String &p_variable) {
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo();
undo_redo->create_action(TTR("Add Shader Global Uniform"));
undo_redo->add_do_method(RS::get_singleton(), "global_shader_uniform_remove", p_variable);
diff --git a/editor/shader_globals_editor.h b/editor/shader_globals_editor.h
index d29052eaee..1e2f1dd828 100644
--- a/editor/shader_globals_editor.h
+++ b/editor/shader_globals_editor.h
@@ -31,7 +31,6 @@
#ifndef SHADER_GLOBALS_EDITOR_H
#define SHADER_GLOBALS_EDITOR_H
-#include "core/object/undo_redo.h"
#include "editor/editor_autoload_settings.h"
#include "editor/editor_data.h"
#include "editor/editor_plugin_settings.h"
diff --git a/editor/translations/af.po b/editor/translations/af.po
index 55fe58e1b0..f2e389b6f5 100644
--- a/editor/translations/af.po
+++ b/editor/translations/af.po
@@ -2856,8 +2856,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "Verwyder Seleksie"
#: editor/editor_export.cpp
#, fuzzy
@@ -20423,15 +20424,15 @@ msgstr "Kon nie vouer skep nie."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Moet 'n geldige uitbreiding gebruik."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20455,15 +20456,15 @@ msgstr "Ongeldige naam."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Moet 'n geldige uitbreiding gebruik."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/ar.po b/editor/translations/ar.po
index 36e71f130e..cda76c44c8 100644
--- a/editor/translations/ar.po
+++ b/editor/translations/ar.po
@@ -2820,7 +2820,7 @@ msgstr "تصدير المشروع لمنصة:"
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "نسخ مسار العÙقدة"
#: editor/editor_export.cpp
@@ -20570,15 +20570,15 @@ msgstr "لا يمكن العثور على Ù…ÙØªØ§Ø­ المتجر، لا يمكÙ
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "صيغة غير صالحة."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20602,15 +20602,15 @@ msgstr "اسم غير صالح."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "صيغة غير صالحة."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/az.po b/editor/translations/az.po
index 3a59e8aa41..af28a85240 100644
--- a/editor/translations/az.po
+++ b/editor/translations/az.po
@@ -5,49 +5,49 @@
#
# Jafar Tarverdiyev <cefertarverdiyevv@gmail.com>, 2021.
# Lucifer25x <umudyt2006@gmail.com>, 2021.
+# Ümid Quliyev <lucifer25x@protonmail.com>, 2022.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
-"PO-Revision-Date: 2021-09-16 14:36+0000\n"
-"Last-Translator: Lucifer25x <umudyt2006@gmail.com>\n"
+"PO-Revision-Date: 2022-08-05 01:04+0000\n"
+"Last-Translator: Ümid Quliyev <lucifer25x@protonmail.com>\n"
"Language-Team: Azerbaijani <https://hosted.weblate.org/projects/godot-engine/"
"godot/az/>\n"
"Language: az\n"
"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.9-dev\n"
+"X-Generator: Weblate 4.14-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
+#, fuzzy
msgid "Tablet Driver"
-msgstr ""
+msgstr "Planşet sürücü"
#: core/bind/core_bind.cpp
-#, fuzzy
msgid "Clipboard"
-msgstr "Pano boÅŸdur!"
+msgstr "Pano"
#: core/bind/core_bind.cpp
-#, fuzzy
msgid "Current Screen"
-msgstr "Animasiya xüsusiyyətləri."
+msgstr "Aktiv Ekran"
#: core/bind/core_bind.cpp
msgid "Exit Code"
-msgstr ""
+msgstr "Çıxış Kodu"
#: core/bind/core_bind.cpp
msgid "V-Sync Enabled"
-msgstr ""
+msgstr "V-Sync Aktivdir"
#: core/bind/core_bind.cpp main/main.cpp
msgid "V-Sync Via Compositor"
-msgstr ""
+msgstr "V-Sync Kompozitor Vasitəsilə"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Delta Smoothing"
-msgstr ""
+msgstr "Delta hamarlanması"
#: core/bind/core_bind.cpp
msgid "Low Processor Usage Mode"
@@ -59,28 +59,28 @@ msgstr ""
#: core/bind/core_bind.cpp main/main.cpp platform/uwp/os_uwp.cpp
msgid "Keep Screen On"
-msgstr ""
+msgstr "Ekranı Açıq Tut"
#: core/bind/core_bind.cpp
msgid "Min Window Size"
-msgstr ""
+msgstr "Minimum Pəncərə Ölçüsü"
#: core/bind/core_bind.cpp
msgid "Max Window Size"
-msgstr ""
+msgstr "Maksimum Pəncərə Ölçüsü"
#: core/bind/core_bind.cpp
msgid "Screen Orientation"
-msgstr ""
+msgstr "Pəncərə Nisbəti"
#: core/bind/core_bind.cpp core/project_settings.cpp main/main.cpp
#: platform/uwp/os_uwp.cpp
msgid "Window"
-msgstr ""
+msgstr "Pəncərə"
#: core/bind/core_bind.cpp core/project_settings.cpp
msgid "Borderless"
-msgstr ""
+msgstr "Kənarsız"
#: core/bind/core_bind.cpp
msgid "Per Pixel Transparency Enabled"
@@ -88,29 +88,28 @@ msgstr ""
#: core/bind/core_bind.cpp core/project_settings.cpp
msgid "Fullscreen"
-msgstr ""
+msgstr "Bütün Ekran"
#: core/bind/core_bind.cpp
msgid "Maximized"
-msgstr ""
+msgstr "Böyüdülmüş"
#: core/bind/core_bind.cpp
msgid "Minimized"
-msgstr ""
+msgstr "Kiçildilmiş"
#: core/bind/core_bind.cpp core/project_settings.cpp scene/gui/dialogs.cpp
#: scene/gui/graph_node.cpp
msgid "Resizable"
-msgstr ""
+msgstr "Ölçüsü Dəyişdirilə Bilər"
#: core/bind/core_bind.cpp core/os/input_event.cpp scene/2d/node_2d.cpp
#: scene/2d/physics_body_2d.cpp scene/2d/remote_transform_2d.cpp
#: scene/3d/physics_body.cpp scene/3d/remote_transform.cpp
#: scene/gui/control.cpp scene/gui/line_edit.cpp
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Position"
-msgstr "Animasiyanı Təmizləmə"
+msgstr "Pozisiya"
#: core/bind/core_bind.cpp core/project_settings.cpp editor/editor_settings.cpp
#: main/main.cpp modules/gridmap/grid_map.cpp
@@ -122,7 +121,7 @@ msgstr "Animasiyanı Təmizləmə"
#: scene/resources/style_box.cpp scene/resources/texture.cpp
#: scene/resources/visual_shader.cpp servers/visual_server.cpp
msgid "Size"
-msgstr ""
+msgstr "Ölçü"
#: core/bind/core_bind.cpp
msgid "Endian Swap"
@@ -131,25 +130,23 @@ msgstr ""
#: core/bind/core_bind.cpp
#, fuzzy
msgid "Editor Hint"
-msgstr "RedaktÉ™ et"
+msgstr "Editor İpucu"
#: core/bind/core_bind.cpp
msgid "Print Error Messages"
-msgstr ""
+msgstr "Xəta Mesajlarını Yazdır"
#: core/bind/core_bind.cpp
-#, fuzzy
msgid "Iterations Per Second"
-msgstr "İnterpolasiya rejimi"
+msgstr "Hər Saniyədə İterasiya Sayı"
#: core/bind/core_bind.cpp
msgid "Target FPS"
-msgstr ""
+msgstr "Hədəf FPS"
#: core/bind/core_bind.cpp
-#, fuzzy
msgid "Time Scale"
-msgstr "Animasya Açarlarını Ölçülə"
+msgstr "Zaman Ölçəyi"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Physics Jitter Fix"
@@ -157,25 +154,23 @@ msgstr ""
#: core/bind/core_bind.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "Error"
-msgstr ""
+msgstr "Xəta"
#: core/bind/core_bind.cpp
-#, fuzzy
msgid "Error String"
-msgstr "Yükləmə xətası:"
+msgstr "Xəta Yazısı"
#: core/bind/core_bind.cpp
-#, fuzzy
msgid "Error Line"
-msgstr "Yükləmə xətası:"
+msgstr "Xəta Sətiri"
#: core/bind/core_bind.cpp
msgid "Result"
-msgstr ""
+msgstr "Nəticə"
#: core/command_queue_mt.cpp core/message_queue.cpp main/main.cpp
msgid "Memory"
-msgstr ""
+msgstr "YaddaÅŸ"
#: core/command_queue_mt.cpp core/message_queue.cpp
#: core/register_core_types.cpp drivers/gles2/rasterizer_canvas_base_gles2.cpp
@@ -186,11 +181,11 @@ msgstr ""
#: modules/webrtc/webrtc_data_channel.h modules/websocket/websocket_macros.h
#: servers/visual_server.cpp
msgid "Limits"
-msgstr ""
+msgstr "Limitlər"
#: core/command_queue_mt.cpp
msgid "Command Queue"
-msgstr ""
+msgstr "Æmr NövbÉ™si"
#: core/command_queue_mt.cpp
msgid "Multithreading Queue Size (KB)"
@@ -200,14 +195,13 @@ msgstr ""
#: modules/visual_script/visual_script_func_nodes.cpp
#: modules/visual_script/visual_script_nodes.cpp
#: scene/resources/visual_shader_nodes.cpp
-#, fuzzy
msgid "Function"
-msgstr "Funksiyalar:"
+msgstr "Funksiya"
#: core/image.cpp core/packed_data_container.cpp scene/2d/polygon_2d.cpp
#: scene/3d/baked_lightmap.cpp scene/3d/gi_probe.cpp
msgid "Data"
-msgstr ""
+msgstr "Məlumat"
#: core/io/file_access_network.cpp core/register_core_types.cpp
#: editor/editor_file_dialog.cpp editor/editor_settings.cpp main/main.cpp
@@ -215,16 +209,15 @@ msgstr ""
#: modules/webrtc/webrtc_data_channel.h modules/websocket/websocket_macros.h
#: scene/gui/file_dialog.cpp
msgid "Network"
-msgstr ""
+msgstr "Şəbəkə"
#: core/io/file_access_network.cpp
-#, fuzzy
msgid "Remote FS"
-msgstr "Sil"
+msgstr "Uzaqdan FS"
#: core/io/file_access_network.cpp
msgid "Page Size"
-msgstr ""
+msgstr "Səhifə Ölçüsü"
#: core/io/file_access_network.cpp
msgid "Page Read Ahead"
@@ -232,12 +225,11 @@ msgstr ""
#: core/io/http_client.cpp
msgid "Blocking Mode Enabled"
-msgstr ""
+msgstr "Bloklama Modu Aktivdir"
#: core/io/http_client.cpp
-#, fuzzy
msgid "Connection"
-msgstr "QoÅŸ"
+msgstr "ÆlaqÉ™"
#: core/io/http_client.cpp
msgid "Read Chunk Size"
@@ -245,15 +237,15 @@ msgstr ""
#: core/io/marshalls.cpp
msgid "Object ID"
-msgstr ""
+msgstr "Obyekt ID"
#: core/io/multiplayer_api.cpp core/io/packet_peer.cpp
msgid "Allow Object Decoding"
-msgstr ""
+msgstr "Obyekt Deşifrəsinə İzn Verin"
#: core/io/multiplayer_api.cpp scene/main/scene_tree.cpp
msgid "Refuse New Network Connections"
-msgstr ""
+msgstr "Yeni ŞəbÉ™kÉ™ ÆlaqÉ™lÉ™rindÉ™n İmtina Et"
#: core/io/multiplayer_api.cpp scene/main/scene_tree.cpp
msgid "Network Peer"
@@ -261,16 +253,15 @@ msgstr ""
#: core/io/multiplayer_api.cpp scene/animation/animation_player.cpp
msgid "Root Node"
-msgstr ""
+msgstr "Kök Düyün"
#: core/io/networked_multiplayer_peer.cpp
-#, fuzzy
msgid "Refuse New Connections"
-msgstr "QoÅŸ"
+msgstr "Yeni ÆlaqÉ™lÉ™rdÉ™n İmtina Et"
#: core/io/networked_multiplayer_peer.cpp
msgid "Transfer Mode"
-msgstr ""
+msgstr "Transfer Modu"
#: core/io/packet_peer.cpp
msgid "Encode Buffer Max Size"
@@ -294,16 +285,15 @@ msgstr ""
#: core/io/stream_peer.cpp
msgid "Data Array"
-msgstr ""
+msgstr "Məlumat Siyahısı"
#: core/io/stream_peer_ssl.cpp
msgid "Blocking Handshake"
-msgstr ""
+msgstr "Æl Sıxmağın Qarşısının Alınması"
#: core/io/udp_server.cpp
-#, fuzzy
msgid "Max Pending Connections"
-msgstr "ÆlaqÉ™ni redaktÉ™ edin:"
+msgstr "GözlÉ™nilÉ™n Maksimum ÆlaqÉ™lÉ™r"
#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp
#: modules/visual_script/visual_script_builtin_funcs.cpp
@@ -325,7 +315,6 @@ msgstr ""
"format."
#: core/math/expression.cpp
-#, fuzzy
msgid "Invalid input %d (not passed) in expression"
msgstr "İfadədə uyğunsuz giriş %d (ötürülmədi)"
@@ -2810,8 +2799,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "Animasiyanı Təmizləmə"
#: editor/editor_export.cpp
msgid "Completed successfully."
@@ -19641,14 +19631,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
+msgid "rcedit failed to modify executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
@@ -19670,14 +19659,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
+msgid "Signtool failed to sign executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
diff --git a/editor/translations/bg.po b/editor/translations/bg.po
index 877823c869..d2d7a56dc3 100644
--- a/editor/translations/bg.po
+++ b/editor/translations/bg.po
@@ -2814,8 +2814,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "Копиране на избраното"
#: editor/editor_export.cpp
msgid "Completed successfully."
@@ -20110,15 +20111,15 @@ msgstr "Ðе е намерено хранилище за ключове. ИзнÐ
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Ðеправилно разширение."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20142,15 +20143,15 @@ msgstr "Ðеправилно име."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Ðеправилно разширение."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/bn.po b/editor/translations/bn.po
index 8379e2de5b..6f1e8f945d 100644
--- a/editor/translations/bn.po
+++ b/editor/translations/bn.po
@@ -2904,7 +2904,7 @@ msgstr ""
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "পথ পà§à¦°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿/কপি করà§à¦¨"
#: editor/editor_export.cpp
@@ -21539,15 +21539,15 @@ msgstr "ফোলà§à¦¡à¦¾à¦° তৈরী করা সমà§à¦­à¦¬ হয়নà¦
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "অগà§à¦°à¦¹à¦£à¦¯à§‹à¦—à§à¦¯ à¦à¦•à§à¦¸à¦Ÿà§‡à¦¨à¦¶à¦¨"
#: platform/windows/export/export.cpp
#, fuzzy
@@ -21571,15 +21571,15 @@ msgstr "অগà§à¦°à¦¹à¦¨à¦¯à§‹à¦—à§à¦¯ নাম।"
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "অগà§à¦°à¦¹à¦£à¦¯à§‹à¦—à§à¦¯ à¦à¦•à§à¦¸à¦Ÿà§‡à¦¨à¦¶à¦¨"
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/br.po b/editor/translations/br.po
index f86b01cc44..823490a280 100644
--- a/editor/translations/br.po
+++ b/editor/translations/br.po
@@ -2732,8 +2732,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "Tro Fiñvskeudenn"
#: editor/editor_export.cpp
msgid "Completed successfully."
@@ -19433,14 +19434,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
+msgid "rcedit failed to modify executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
@@ -19462,14 +19462,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
+msgid "Signtool failed to sign executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
diff --git a/editor/translations/ca.po b/editor/translations/ca.po
index b1ee6245f6..04c9b7761c 100644
--- a/editor/translations/ca.po
+++ b/editor/translations/ca.po
@@ -2790,7 +2790,8 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
+#, fuzzy
+msgid "Completed with warnings."
msgstr "Completat amb errors."
#: editor/editor_export.cpp
@@ -20973,15 +20974,15 @@ msgstr "No es pot obrir la plantilla per exportar."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "L'extensió no és vàlida."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -21005,15 +21006,15 @@ msgstr "Nom no vàlid."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "L'extensió no és vàlida."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/cs.po b/editor/translations/cs.po
index c27334b374..1e92a92ae7 100644
--- a/editor/translations/cs.po
+++ b/editor/translations/cs.po
@@ -2882,7 +2882,7 @@ msgstr ""
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "Kopírovat cestu k uzlu"
#: editor/editor_export.cpp
@@ -20734,15 +20734,15 @@ msgstr "NepodaÅ™ilo se najít úložiÅ¡tÄ› klíÄů, nelze exportovat."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Neplatná přípona."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20766,15 +20766,15 @@ msgstr "Neplatný název."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Neplatná přípona."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/da.po b/editor/translations/da.po
index 3dc6f52da1..1bb05be6f9 100644
--- a/editor/translations/da.po
+++ b/editor/translations/da.po
@@ -2895,8 +2895,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "Fjern Markering"
#: editor/editor_export.cpp
#, fuzzy
@@ -20911,15 +20912,15 @@ msgstr "Kan ikke åbne skabelon til eksport:\n"
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Du skal bruge en gyldig udvidelse."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20943,15 +20944,15 @@ msgstr "Ugyldigt navn."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Du skal bruge en gyldig udvidelse."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/de.po b/editor/translations/de.po
index 5035a7aa5d..aa92914ada 100644
--- a/editor/translations/de.po
+++ b/editor/translations/de.po
@@ -82,13 +82,14 @@
# Christian Packenius <christian@packenius.com>, 2022.
# Sajeg <jfx@posteo.de>, 2022.
# Tobias Jacobs <tobi@jacobs.rocks>, 2022.
+# JeremyStarTM <jeremystartm@tuta.io>, 2022.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-07-23 03:57+0000\n"
-"Last-Translator: So Wieso <sowieso@dukun.de>\n"
+"PO-Revision-Date: 2022-07-31 18:34+0000\n"
+"Last-Translator: JeremyStarTM <jeremystartm@tuta.io>\n"
"Language-Team: German <https://hosted.weblate.org/projects/godot-engine/"
"godot/de/>\n"
"Language: de\n"
@@ -1632,7 +1633,7 @@ msgstr "Methodenaufrufsspurschlüssel hinzufügen"
#: editor/animation_track_editor.cpp
msgid "Method not found in object:"
-msgstr "Methode nicht in Objekt gefunden:"
+msgstr "Methode im Objekt nicht gefunden:"
#: editor/animation_track_editor.cpp
msgid "Anim Move Keys"
@@ -2814,7 +2815,8 @@ msgid "Project export for platform:"
msgstr "Projektexport für Plattform:"
#: editor/editor_export.cpp
-msgid "Completed with errors."
+#, fuzzy
+msgid "Completed with warnings."
msgstr "Fertiggestellt mit Fehlern."
#: editor/editor_export.cpp
@@ -5569,7 +5571,7 @@ msgstr "Auswahl ziehen und fallen lassen"
#: editor/editor_settings.cpp
msgid "Stay In Script Editor On Node Selected"
-msgstr ""
+msgstr "Im Skript Editor bei ausgewähltem Node bleiben"
#: editor/editor_settings.cpp
msgid "Appearance"
@@ -11697,9 +11699,8 @@ msgid "New Animation"
msgstr "Neue Animation"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Filter animations"
-msgstr "Methoden filtern"
+msgstr "Animationen filtern"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Speed:"
@@ -18151,7 +18152,7 @@ msgstr "Ungültiges Argument vom Typ:"
#: modules/visual_script/visual_script_nodes.cpp
msgid "Invalid arguments:"
-msgstr "Ungültige Argumente:"
+msgstr "Ungültige Parameter:"
#: modules/visual_script/visual_script_nodes.cpp
msgid "a if cond, else b"
@@ -19652,8 +19653,8 @@ msgid ""
"Could not start codesign executable, make sure Xcode command line tools are "
"installed."
msgstr ""
-"Codesign-Anwendung konnte nicht gestartet werden. Wurden die Xcode-"
-"Kommandozeilen-Hilfsprogramme installiert?"
+"Codesign-Anwendung konnte nicht gestartet werden, stelle sicher dass die "
+"Xcode-Kommandozeilen-Tools installiert sind."
#: platform/osx/export/export.cpp platform/windows/export/export.cpp
msgid "No identity found."
@@ -20145,17 +20146,18 @@ msgid "Could not find wine executable at \"%s\"."
msgstr "Anwendung wine konnte nicht gefunden werden in „%s“."
#: platform/windows/export/export.cpp
+#, fuzzy
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
"Anwendung rcedit konnte nicht gestartet werden. Bitte rcedit-Pfad in "
"Editoreinstellungen festlegen (Export > Windows > Rcedit)."
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
msgstr ""
"Modifikation der Anwendung durch rcedit fehlgeschlagen:\n"
"%s"
@@ -20177,17 +20179,18 @@ msgid "Invalid timestamp server."
msgstr "Ungültiger Zeitstempelserver."
#: platform/windows/export/export.cpp
+#, fuzzy
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
"Anwendung signtool konnte nicht gestartet werden. Bitte signtool-Pfad in "
"Editoreinstellungen festlegen (Export > Windows > Signtool)."
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
msgstr ""
"Signieren der Anwendung durch Signtool ist fehlgeschlagen:\n"
"%s"
diff --git a/editor/translations/editor.pot b/editor/translations/editor.pot
index c207124fcb..23c58c5ffb 100644
--- a/editor/translations/editor.pot
+++ b/editor/translations/editor.pot
@@ -2684,7 +2684,7 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr ""
#: editor/editor_export.cpp
@@ -19258,14 +19258,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
+msgid "rcedit failed to modify executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
@@ -19286,14 +19285,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
+msgid "Signtool failed to sign executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
diff --git a/editor/translations/el.po b/editor/translations/el.po
index 85005d903a..4b71ed8528 100644
--- a/editor/translations/el.po
+++ b/editor/translations/el.po
@@ -2841,7 +2841,7 @@ msgstr ""
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "ΑντιγÏαφή διαδÏομής κόμβου"
#: editor/editor_export.cpp
@@ -20907,15 +20907,15 @@ msgstr "Σφάλμα κατά το άνοιγμα Ï€ÏοτÏπου για εξα
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "ΆκυÏη επέκταση."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20939,15 +20939,15 @@ msgstr "Μη έγκυÏο όνομα."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "ΆκυÏη επέκταση."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/en_Shaw.po b/editor/translations/en_Shaw.po
index 45d0549a81..361c10ce1a 100644
--- a/editor/translations/en_Shaw.po
+++ b/editor/translations/en_Shaw.po
@@ -2707,8 +2707,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "ð‘“ð‘³ð‘™ð‘’ð‘–ð‘©ð‘¯ð‘Ÿ:"
#: editor/editor_export.cpp
msgid "Completed successfully."
@@ -19353,14 +19354,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
+msgid "rcedit failed to modify executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
@@ -19382,14 +19382,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
+msgid "Signtool failed to sign executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
diff --git a/editor/translations/eo.po b/editor/translations/eo.po
index 5a251ba489..0139382972 100644
--- a/editor/translations/eo.po
+++ b/editor/translations/eo.po
@@ -2852,8 +2852,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "Kopii elektaron"
#: editor/editor_export.cpp
#, fuzzy
@@ -20555,15 +20556,15 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Nevalida kromprogramo."
#: platform/windows/export/export.cpp
msgid "Could not find signtool executable at \"%s\"."
@@ -20585,15 +20586,15 @@ msgstr "Malvalida nomo."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Nevalida kromprogramo."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/es.po b/editor/translations/es.po
index 872fedfdac..173b195cc4 100644
--- a/editor/translations/es.po
+++ b/editor/translations/es.po
@@ -81,12 +81,16 @@
# David Martínez <goddrinksjava@gmail.com>, 2022.
# Nagamine-j <jimmy.kochi@unmsm.edu.pe>, 2022.
# Esdras Caleb Oliveira Silva <acheicaleb@gmail.com>, 2022.
+# Luis Ortiz <luisortiz66@hotmail.com>, 2022.
+# Angel Andrade <aandradeb99@gmail.com>, 2022.
+# Juan Felipe Gómez López <juanfgomez0912@gmail.com>, 2022.
+# Pineappletooth <yochank003@gmail.com>, 2022.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-07-27 13:26+0000\n"
+"PO-Revision-Date: 2022-08-05 01:04+0000\n"
"Last-Translator: Javier Ocampos <xavier.ocampos@gmail.com>\n"
"Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/"
"godot/es/>\n"
@@ -225,7 +229,7 @@ msgstr "Escala de Tiempo"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Physics Jitter Fix"
-msgstr "Arreglo de las Fluctuaciones Físicas"
+msgstr "Corrección de Fluctuaciones de Física"
#: core/bind/core_bind.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "Error"
@@ -2813,7 +2817,8 @@ msgid "Project export for platform:"
msgstr "Exportar proyecto para la plataforma:"
#: editor/editor_export.cpp
-msgid "Completed with errors."
+#, fuzzy
+msgid "Completed with warnings."
msgstr "Completado con errores."
#: editor/editor_export.cpp
@@ -5563,7 +5568,7 @@ msgstr "Arrastrar y Soltar la Selección"
#: editor/editor_settings.cpp
msgid "Stay In Script Editor On Node Selected"
-msgstr ""
+msgstr "Permanecer En Editor de Scripts En Nodo Seleccionado"
#: editor/editor_settings.cpp
msgid "Appearance"
@@ -5693,11 +5698,11 @@ msgstr "Espera de Completado de Código"
#: editor/editor_settings.cpp
msgid "Put Callhint Tooltip Below Current Line"
-msgstr "Colocar la Información Sobre la Llamada Debajo de la Línea Actual"
+msgstr "Colocar Tooltip de Llamada Debajo de la Línea Actual"
#: editor/editor_settings.cpp
msgid "Callhint Tooltip Offset"
-msgstr "Desplazamiento de la Información Sobre la Llamada"
+msgstr "Desplazamiento del Tooltip de Llamada"
#: editor/editor_settings.cpp
msgid "Complete File Paths"
@@ -6155,7 +6160,7 @@ msgstr "Color de Número de Línea Seguro"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Caret Color"
-msgstr ""
+msgstr "Color del Caret"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Caret Background Color"
@@ -6187,7 +6192,7 @@ msgstr "Color de la Palabra Resaltada"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Number Color"
-msgstr ""
+msgstr "Número del Color"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Function Color"
@@ -6211,7 +6216,7 @@ msgstr "Puntos de Interrupción"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Executing Line Color"
-msgstr ""
+msgstr "Color de la línea de ejecución"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Code Folding Color"
@@ -10144,7 +10149,7 @@ msgid ""
"viewport."
msgstr ""
"El polígono 2D tiene vértices internos, por lo que ya no se puede editar en "
-"la ventanilla."
+"el viewport."
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Create Polygon & UV"
@@ -11410,27 +11415,27 @@ msgstr "Dialogo de Transformación..."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "1 Viewport"
-msgstr "1 Ventana"
+msgstr "1 Viewport"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "2 Viewports"
-msgstr "2 Ventanas"
+msgstr "2 Viewports"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "2 Viewports (Alt)"
-msgstr "2 Ventanas (Alt)"
+msgstr "2 Viewports (Alt)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "3 Viewports"
-msgstr "3 Ventanas"
+msgstr "3 Viewports"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "3 Viewports (Alt)"
-msgstr "3 Ventanas (Alt)"
+msgstr "3 Viewports (Alt)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "4 Viewports"
-msgstr "4 Ventanas"
+msgstr "4 Viewports"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Gizmos"
@@ -11475,7 +11480,7 @@ msgstr "Ajuste de Escala (%):"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Viewport Settings"
-msgstr "Configuración de ventanilla"
+msgstr "Configuración del Viewport"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Perspective FOV (deg.):"
@@ -11683,9 +11688,8 @@ msgid "New Animation"
msgstr "Nueva Animación"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Filter animations"
-msgstr "Filtrar métodos"
+msgstr "Filtrar animaciones"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Speed:"
@@ -16430,7 +16434,7 @@ msgstr ""
#: main/main.cpp
msgid "Tooltip Position Offset"
-msgstr "Offset de la Posición del Tooltip"
+msgstr "Desplazamiento de Posición del Tooltip"
#: main/main.cpp modules/mono/mono_gd/gd_mono.cpp
msgid "Debugger Agent"
@@ -20127,18 +20131,19 @@ msgid "Could not find wine executable at \"%s\"."
msgstr "No se pudo encontrar el ejecutable de wine en \"%s\"."
#: platform/windows/export/export.cpp
+#, fuzzy
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
"No se ha podido iniciar el ejecutable rcedit, configura la ruta de rcedit en "
"la configuración del editor (Exportar > Windows > Rcedit)."
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Fallo al abrir el archivo ejecutable \"%s\"."
#: platform/windows/export/export.cpp
msgid "Could not find signtool executable at \"%s\"."
@@ -20157,18 +20162,19 @@ msgid "Invalid timestamp server."
msgstr "Servidor de marcas de tiempo inválido."
#: platform/windows/export/export.cpp
+#, fuzzy
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
"No se ha podido iniciar el ejecutable de signtool, configura la ruta de "
"signtool en la configuración del editor (Exportar > Windows > Signtool)."
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Fallo al abrir el archivo ejecutable \"%s\"."
#: platform/windows/export/export.cpp
msgid "Failed to remove temporary file \"%s\"."
@@ -20382,7 +20388,7 @@ msgstr "Zoom"
#: scene/2d/camera_2d.cpp scene/main/canvas_layer.cpp
msgid "Custom Viewport"
-msgstr "Vista Personalizada"
+msgstr "Viewport Personalizado"
#: scene/2d/camera_2d.cpp scene/3d/camera.cpp scene/3d/interpolated_camera.cpp
#: scene/animation/animation_player.cpp scene/animation/animation_tree.cpp
@@ -22922,9 +22928,8 @@ msgid "Show Margins"
msgstr "Mostrar Márgenes"
#: scene/3d/room_manager.cpp
-#, fuzzy
msgid "Debug Sprawl"
-msgstr "Depurar Desorden"
+msgstr "Depurar Extensión"
#: scene/3d/room_manager.cpp
msgid "Overlap Warning Threshold"
@@ -22939,14 +22944,12 @@ msgid "Portal Depth Limit"
msgstr ""
#: scene/3d/room_manager.cpp
-#, fuzzy
msgid "Default Portal Margin"
-msgstr "Asignar Margen"
+msgstr "Margen del Portal por Defecto"
#: scene/3d/room_manager.cpp
-#, fuzzy
msgid "Roaming Expansion Margin"
-msgstr "Expandir Todo"
+msgstr "Margen de Expansión del Roaming"
#: scene/3d/room_manager.cpp
msgid ""
@@ -22999,43 +23002,36 @@ msgstr ""
"Asegúrate de que todas las rooms contienen geometría o límites manuales."
#: scene/3d/skeleton.cpp scene/resources/skin.cpp
-#, fuzzy
msgid "Pose"
-msgstr "Copiar Pose"
+msgstr "Pose"
#: scene/3d/skeleton.cpp
-#, fuzzy
msgid "Bound Children"
-msgstr "Hijos Editables"
+msgstr "Hijos Vinculados"
#: scene/3d/soft_body.cpp
-#, fuzzy
msgid "Pinned Points"
-msgstr "Fijado %s"
+msgstr "Puntos de Anclaje"
#: scene/3d/soft_body.cpp
-#, fuzzy
msgid "Attachments"
-msgstr "Gizmos"
+msgstr "Adjuntos"
#: scene/3d/soft_body.cpp
-#, fuzzy
msgid "Point Index"
-msgstr "Obtener Ãndice"
+msgstr "Ãndice de Puntos"
#: scene/3d/soft_body.cpp
msgid "Spatial Attachment Path"
msgstr ""
#: scene/3d/soft_body.cpp
-#, fuzzy
msgid "Physics Enabled"
-msgstr "Fotogramas de Física %"
+msgstr "Física Activada"
#: scene/3d/soft_body.cpp
-#, fuzzy
msgid "Parent Collision Ignore"
-msgstr "Crear Polígono de Colisión"
+msgstr "Ignorar Colisión de los Padres"
#: scene/3d/soft_body.cpp
msgid "Simulation Precision"
@@ -23100,9 +23096,8 @@ msgid "Gizmo"
msgstr "Gizmo"
#: scene/3d/spatial_velocity_tracker.cpp
-#, fuzzy
msgid "Track Physics Step"
-msgstr "Fotogramas de Física %"
+msgstr "Paso de Física de Pistas"
#: scene/3d/spring_arm.cpp
msgid "Spring Length"
@@ -23113,9 +23108,8 @@ msgid "Opacity"
msgstr ""
#: scene/3d/sprite_3d.cpp scene/resources/material.cpp
-#, fuzzy
msgid "Transparent"
-msgstr "Transponer"
+msgstr "Transparente"
#: scene/3d/sprite_3d.cpp
msgid ""
@@ -23134,14 +23128,12 @@ msgstr ""
"Por favor, úselo como hijo de un VehicleBody."
#: scene/3d/vehicle_body.cpp
-#, fuzzy
msgid "Per-Wheel Motion"
-msgstr "Botón Bajar la Rueda"
+msgstr "Movimiento por Rueda"
#: scene/3d/vehicle_body.cpp
-#, fuzzy
msgid "Engine Force"
-msgstr "Documentación Online"
+msgstr "Fuerza del Motor"
#: scene/3d/vehicle_body.cpp
msgid "Brake"
@@ -23172,19 +23164,16 @@ msgid "Roll Influence"
msgstr ""
#: scene/3d/vehicle_body.cpp
-#, fuzzy
msgid "Friction Slip"
-msgstr "Función"
+msgstr "Deslizamiento por Fricción"
#: scene/3d/vehicle_body.cpp
-#, fuzzy
msgid "Suspension"
-msgstr "Expresión"
+msgstr "Suspensión"
#: scene/3d/vehicle_body.cpp
-#, fuzzy
msgid "Max Force"
-msgstr "Error"
+msgstr "Fuerza Máxima"
#: scene/3d/visibility_notifier.cpp
msgid "AABB"
@@ -23211,14 +23200,12 @@ msgid "Extra Cull Margin"
msgstr "Margen de Sacrificio Extra"
#: scene/3d/visual_instance.cpp
-#, fuzzy
msgid "Baked Light"
-msgstr "Calcular Lightmaps"
+msgstr "Bakear Luces"
#: scene/3d/visual_instance.cpp
-#, fuzzy
msgid "Generate Lightmap"
-msgstr "Generando Lightmaps"
+msgstr "Generar Lightmap"
#: scene/3d/visual_instance.cpp
msgid "Lightmap Scale"
@@ -23274,9 +23261,8 @@ msgid "Animation not found: '%s'"
msgstr "No se encontró la animación: '%s'"
#: scene/animation/animation_blend_tree.cpp
-#, fuzzy
msgid "Mix Mode"
-msgstr "Nodo Mix"
+msgstr "Modo Mix"
#: scene/animation/animation_blend_tree.cpp
msgid "Fadein Time"
@@ -23303,24 +23289,20 @@ msgid "Random Delay"
msgstr "Retraso Aleatorio"
#: scene/animation/animation_blend_tree.cpp
-#, fuzzy
msgid "Add Amount"
-msgstr "Cantidad"
+msgstr "Añadir Cantidad"
#: scene/animation/animation_blend_tree.cpp
-#, fuzzy
msgid "Blend Amount"
-msgstr "Cantidad de Escala"
+msgstr "Cantidad de Mezcla"
#: scene/animation/animation_blend_tree.cpp
-#, fuzzy
msgid "Seek Position"
-msgstr "Establecer Posición de Entrada de Curva"
+msgstr "Buscar Posición"
#: scene/animation/animation_blend_tree.cpp
-#, fuzzy
msgid "Input Count"
-msgstr "Añadir Puerto de Entrada"
+msgstr "Conteo de Entradas"
#: scene/animation/animation_blend_tree.cpp
#: scene/animation/animation_node_state_machine.cpp
@@ -23328,56 +23310,48 @@ msgid "Xfade Time"
msgstr "Tiempo de Fundido Cruzado"
#: scene/animation/animation_node_state_machine.cpp
-#, fuzzy
msgid "Switch Mode"
-msgstr "Cambiar"
+msgstr "Modo de Conmutación"
#: scene/animation/animation_node_state_machine.cpp
-#, fuzzy
msgid "Auto Advance"
-msgstr "Establecer avance automático"
+msgstr "Auto Avance"
#: scene/animation/animation_node_state_machine.cpp
-#, fuzzy
msgid "Advance Condition"
-msgstr "Opciones Avanzadas"
+msgstr "Condición de Avance"
#: scene/animation/animation_player.cpp
msgid "Anim Apply Reset"
msgstr "Aplicar Reset de la Animación"
#: scene/animation/animation_player.cpp
-#, fuzzy
msgid "Current Animation"
-msgstr "Establecer Animación"
+msgstr "Animación Actual"
#: scene/animation/animation_player.cpp
-#, fuzzy
msgid "Assigned Animation"
-msgstr "Añadir Animación"
+msgstr "Animación Asignada"
#: scene/animation/animation_player.cpp
msgid "Reset On Save"
msgstr ""
#: scene/animation/animation_player.cpp
-#, fuzzy
msgid "Current Animation Length"
-msgstr "Cambiar Duración de la Animación"
+msgstr "Duración Actual de la Animación"
#: scene/animation/animation_player.cpp
-#, fuzzy
msgid "Current Animation Position"
-msgstr "Añadir Punto de Animación"
+msgstr "Posición Actual de la Animación"
#: scene/animation/animation_player.cpp
msgid "Playback Options"
msgstr "Opciones de Reproducción"
#: scene/animation/animation_player.cpp
-#, fuzzy
msgid "Default Blend Time"
-msgstr "Theme Predeterminado"
+msgstr "Tiempo de Mezcla por Defecto"
#: scene/animation/animation_player.cpp
msgid "Method Call Mode"
@@ -23418,67 +23392,56 @@ msgid "Tree Root"
msgstr "Raíz del Ãrbol"
#: scene/animation/animation_tree.cpp
-#, fuzzy
msgid "Anim Player"
-msgstr "Fijar AnimationPlayer"
+msgstr "Reproductor de Animación"
#: scene/animation/animation_tree.cpp
msgid "Root Motion"
msgstr ""
#: scene/animation/animation_tree.cpp
-#, fuzzy
msgid "Track"
-msgstr "Agregar Pista"
+msgstr "Pista"
#: scene/animation/animation_tree_player.cpp
msgid "This node has been deprecated. Use AnimationTree instead."
msgstr "Este nodo ha quedado obsoleto. Usa AnimationTree en su lugar."
#: scene/animation/animation_tree_player.cpp
-#, fuzzy
msgid "Playback"
msgstr "Reproducir"
#: scene/animation/animation_tree_player.cpp
-#, fuzzy
msgid "Master Player"
-msgstr "Pegar Parámetros"
+msgstr "Reproductor Principal"
#: scene/animation/animation_tree_player.cpp
-#, fuzzy
msgid "Base Path"
-msgstr "Ruta de Exportación"
+msgstr "Ruta Base"
#: scene/animation/root_motion_view.cpp
-#, fuzzy
msgid "Animation Path"
-msgstr "Animación"
+msgstr "Ruta de la Animación"
#: scene/animation/root_motion_view.cpp
-#, fuzzy
msgid "Zero Y"
-msgstr "Cero"
+msgstr "Cero Y"
#: scene/animation/skeleton_ik.cpp
-#, fuzzy
msgid "Root Bone"
-msgstr "Nombre del nodo raíz"
+msgstr "Hueso Raíz"
#: scene/animation/skeleton_ik.cpp
-#, fuzzy
msgid "Tip Bone"
-msgstr "Huesos"
+msgstr "Punta del Hueso"
#: scene/animation/skeleton_ik.cpp
-#, fuzzy
msgid "Interpolation"
-msgstr "Modo de Interpolación"
+msgstr "Interpolación"
#: scene/animation/skeleton_ik.cpp
-#, fuzzy
msgid "Override Tip Basis"
-msgstr "Anulaciones"
+msgstr "Anular Base de la Punta"
#: scene/animation/skeleton_ik.cpp
msgid "Use Magnet"
@@ -23489,54 +23452,46 @@ msgid "Magnet"
msgstr ""
#: scene/animation/skeleton_ik.cpp
-#, fuzzy
msgid "Target Node"
-msgstr "Reemparentar nodo"
+msgstr "Nodo Objetivo"
#: scene/animation/skeleton_ik.cpp
-#, fuzzy
msgid "Max Iterations"
-msgstr "Crear Función"
+msgstr "Iteraciones Máximas"
#: scene/animation/tween.cpp
msgid "Playback Process Mode"
msgstr ""
#: scene/animation/tween.cpp
-#, fuzzy
msgid "Playback Speed"
-msgstr "Reproducir Escena"
+msgstr "Velocidad de Reproducción"
#: scene/audio/audio_stream_player.cpp
-#, fuzzy
msgid "Mix Target"
-msgstr "Objetivo"
+msgstr "Objetivo de la Mezcla"
#: scene/gui/aspect_ratio_container.cpp scene/gui/range.cpp
#: servers/audio/effects/audio_effect_compressor.cpp
-#, fuzzy
msgid "Ratio"
-msgstr "Mantener Proporciones"
+msgstr "Proporción"
#: scene/gui/aspect_ratio_container.cpp scene/gui/texture_button.cpp
#: scene/gui/texture_rect.cpp
-#, fuzzy
msgid "Stretch Mode"
-msgstr "Modo de Selección"
+msgstr "Modo de Estiramiento"
#: scene/gui/aspect_ratio_container.cpp scene/gui/box_container.cpp
msgid "Alignment"
msgstr ""
#: scene/gui/base_button.cpp
-#, fuzzy
msgid "Shortcut In Tooltip"
-msgstr "Mostrar Origen"
+msgstr "Atajo en el Tooltip"
#: scene/gui/base_button.cpp
-#, fuzzy
msgid "Action Mode"
-msgstr "Modo de Icono"
+msgstr "Modo de Acción"
#: scene/gui/base_button.cpp
msgid "Enabled Focus Mode"
@@ -23547,38 +23502,33 @@ msgid "Keep Pressed Outside"
msgstr ""
#: scene/gui/base_button.cpp scene/gui/shortcut.cpp
-#, fuzzy
msgid "Shortcut"
-msgstr "Atajos"
+msgstr "Atajo"
#: scene/gui/base_button.cpp
-#, fuzzy
msgid "Group"
-msgstr "Grupos"
+msgstr "Grupo"
#: scene/gui/button.cpp scene/gui/label.cpp
-#, fuzzy
msgid "Clip Text"
-msgstr "Copiar Texto"
+msgstr "Texto del Clip"
#: scene/gui/button.cpp scene/gui/label.cpp scene/gui/line_edit.cpp
#: scene/gui/spin_box.cpp
msgid "Align"
-msgstr ""
+msgstr "Alinear"
#: scene/gui/button.cpp
msgid "Icon Align"
-msgstr ""
+msgstr "Alinear Icono"
#: scene/gui/button.cpp
-#, fuzzy
msgid "Expand Icon"
-msgstr "Expandir Todo"
+msgstr "Expandir Icono"
#: scene/gui/center_container.cpp
-#, fuzzy
msgid "Use Top Left"
-msgstr "Superior Izquierda"
+msgstr "Usar Superior Izquierda"
#: scene/gui/color_picker.cpp
msgid ""
@@ -23591,34 +23541,28 @@ msgstr ""
"Clic der: Borrar configuración predeterminada"
#: scene/gui/color_picker.cpp
-#, fuzzy
msgid "Edit Alpha"
-msgstr "Editar Polígono"
+msgstr "Editar Alfa"
#: scene/gui/color_picker.cpp
-#, fuzzy
msgid "HSV Mode"
-msgstr "Modo de Selección"
+msgstr "Modo HSV"
#: scene/gui/color_picker.cpp
-#, fuzzy
msgid "Raw Mode"
-msgstr "Modo desplazamiento lateral"
+msgstr "Modo Raw"
#: scene/gui/color_picker.cpp
-#, fuzzy
msgid "Deferred Mode"
-msgstr "Diferido"
+msgstr "Modo Diferido"
#: scene/gui/color_picker.cpp
-#, fuzzy
msgid "Presets Enabled"
-msgstr "Ajustes preestablecidos"
+msgstr "Preajustes Activados"
#: scene/gui/color_picker.cpp
-#, fuzzy
msgid "Presets Visible"
-msgstr "Act./Desact. Visible"
+msgstr "Preajustes Visibles"
#: scene/gui/color_picker.cpp
msgid "Pick a color from the editor window."
@@ -23648,9 +23592,8 @@ msgstr ""
"sencillo."
#: scene/gui/control.cpp
-#, fuzzy
msgid "Theme Overrides"
-msgstr "Anulaciones"
+msgstr "Anulación de Temas"
#: scene/gui/control.cpp
msgid ""
@@ -23662,14 +23605,12 @@ msgstr ""
"Filtro del Ratón en \"Stop\" o \"Pass\"."
#: scene/gui/control.cpp
-#, fuzzy
msgid "Anchor"
-msgstr "Sólo anclado"
+msgstr "Anclaje"
#: scene/gui/control.cpp
-#, fuzzy
msgid "Grow Direction"
-msgstr "Direcciones"
+msgstr "Dirección de Crecimiento"
#: scene/gui/control.cpp scene/resources/navigation_mesh.cpp
msgid "Min Size"
@@ -23680,40 +23621,36 @@ msgid "Pivot Offset"
msgstr "Pivote de Desplazamiento"
#: scene/gui/control.cpp
-#, fuzzy
msgid "Clip Content"
-msgstr "Constante de Clase"
+msgstr "Contenido del Clip"
#: scene/gui/control.cpp scene/resources/visual_shader_nodes.cpp
msgid "Hint"
msgstr ""
#: scene/gui/control.cpp
-#, fuzzy
msgid "Tooltip"
-msgstr "Herramientas"
+msgstr "Tooltip"
#: scene/gui/control.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Focus"
-msgstr "Foco en Ruta"
+msgstr "Foco"
#: scene/gui/control.cpp
msgid "Neighbour Left"
-msgstr ""
+msgstr "Vecino Izquierda"
#: scene/gui/control.cpp
msgid "Neighbour Top"
-msgstr ""
+msgstr "Vecino Superior"
#: scene/gui/control.cpp
msgid "Neighbour Right"
-msgstr ""
+msgstr "Vecino Derecha"
#: scene/gui/control.cpp
-#, fuzzy
msgid "Neighbour Bottom"
-msgstr "Centro Inferior"
+msgstr "Vecino Inferior"
#: scene/gui/control.cpp
msgid "Next"
@@ -23740,23 +23677,20 @@ msgid "Size Flags"
msgstr "Tamaño de los Indicadores"
#: scene/gui/control.cpp
-#, fuzzy
msgid "Stretch Ratio"
-msgstr "Modo de Selección"
+msgstr "Relación de Estiramiento"
#: scene/gui/control.cpp
-#, fuzzy
msgid "Theme Type Variation"
-msgstr "Propiedades del Theme"
+msgstr "Propiedades del Tema"
#: scene/gui/dialogs.cpp
msgid "Window Title"
msgstr ""
#: scene/gui/dialogs.cpp
-#, fuzzy
msgid "Dialog"
-msgstr "Diálogo XForm"
+msgstr "Diálogo"
#: scene/gui/dialogs.cpp
msgid "Hide On OK"
@@ -23771,18 +23705,16 @@ msgid "Please Confirm..."
msgstr "Por favor, Confirma..."
#: scene/gui/file_dialog.cpp
-#, fuzzy
msgid "Mode Overrides Title"
-msgstr "Elemento de Anulación"
+msgstr "Sobreescritura"
#: scene/gui/file_dialog.cpp
msgid "Must use a valid extension."
msgstr "Debe tener una extensión válida."
#: scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Right Disconnects"
-msgstr "Desconectar"
+msgstr "Desconexión Correcta"
#: scene/gui/graph_edit.cpp
msgid "Scroll Offset"
@@ -23793,24 +23725,20 @@ msgid "Snap Distance"
msgstr "Ajustar Distancia"
#: scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Zoom Min"
-msgstr "Acercar Zoom"
+msgstr "Zoom Mínimo"
#: scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Zoom Max"
-msgstr "Acercar Zoom"
+msgstr "Zoom Máximo"
#: scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Zoom Step"
-msgstr "Alejar Zoom"
+msgstr "Paso Zoom"
#: scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Show Zoom Label"
-msgstr "Mostrar Huesos"
+msgstr "Mostrar Etiqueta Zoom"
#: scene/gui/graph_edit.cpp scene/gui/text_edit.cpp
#: scene/resources/default_theme/default_theme.cpp
@@ -23822,58 +23750,50 @@ msgid "Enable grid minimap."
msgstr "Activar minimapa de cuadrícula."
#: scene/gui/graph_node.cpp
-#, fuzzy
msgid "Show Close"
-msgstr "Mostrar Huesos"
+msgstr "Mostrar Cerrar"
#: scene/gui/graph_node.cpp scene/gui/option_button.cpp
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Selected"
-msgstr "Seleccionar"
+msgstr "Seleccionado"
#: scene/gui/graph_node.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Comment"
-msgstr "Confirmar"
+msgstr "Comentario"
#: scene/gui/graph_node.cpp
msgid "Overlay"
msgstr ""
#: scene/gui/grid_container.cpp scene/gui/item_list.cpp scene/gui/tree.cpp
-#, fuzzy
msgid "Columns"
-msgstr "Volumen"
+msgstr "Columnas"
#: scene/gui/item_list.cpp scene/gui/popup_menu.cpp scene/gui/text_edit.cpp
#: scene/gui/tree.cpp scene/main/viewport.cpp
-#, fuzzy
msgid "Timers"
-msgstr "Tiempo"
+msgstr "Temporizadores"
#: scene/gui/item_list.cpp scene/gui/popup_menu.cpp scene/gui/tree.cpp
msgid "Incremental Search Max Interval Msec"
msgstr ""
#: scene/gui/item_list.cpp scene/gui/tree.cpp
-#, fuzzy
msgid "Allow Reselect"
-msgstr "Aplicar Restablecer"
+msgstr "Permitir Volver A Seleccionar"
#: scene/gui/item_list.cpp scene/gui/tree.cpp
-#, fuzzy
msgid "Allow RMB Select"
-msgstr "Rellenar Selección"
+msgstr "Permitir Selección Con Botón Derecho Del Ratón"
#: scene/gui/item_list.cpp
msgid "Max Text Lines"
msgstr ""
#: scene/gui/item_list.cpp
-#, fuzzy
msgid "Auto Height"
-msgstr "Prueba"
+msgstr "Altura Automática"
#: scene/gui/item_list.cpp
msgid "Max Columns"
@@ -23892,23 +23812,20 @@ msgid "Icon Scale"
msgstr "Escala de Icono"
#: scene/gui/item_list.cpp
-#, fuzzy
msgid "Fixed Icon Size"
-msgstr "Vista Frontal"
+msgstr "Tamaño Fijo de Icono"
#: scene/gui/label.cpp
-#, fuzzy
msgid "V Align"
-msgstr "Asignar"
+msgstr "Alineamiento V"
#: scene/gui/label.cpp scene/gui/rich_text_label.cpp
msgid "Visible Characters"
msgstr "Caracteres Visibles"
#: scene/gui/label.cpp scene/gui/rich_text_label.cpp
-#, fuzzy
msgid "Percent Visible"
-msgstr "Act./Desact. Visible"
+msgstr "Porcentaje Visible"
#: scene/gui/label.cpp
msgid "Lines Skipped"
@@ -23935,34 +23852,28 @@ msgid "Expand To Text Length"
msgstr ""
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
-#, fuzzy
msgid "Context Menu Enabled"
-msgstr "Ayuda Contextual"
+msgstr "Menú Contextual Activado"
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
-#, fuzzy
msgid "Virtual Keyboard Enabled"
-msgstr "Filtrar señales"
+msgstr "Teclado Virtual Activado"
#: scene/gui/line_edit.cpp
-#, fuzzy
msgid "Clear Button Enabled"
-msgstr "Filtrar señales"
+msgstr "Botón de Borrado Activado"
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
-#, fuzzy
msgid "Shortcut Keys Enabled"
-msgstr "Atajos"
+msgstr "Atajos Activados"
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
-#, fuzzy
msgid "Middle Mouse Paste Enabled"
-msgstr "Filtrar señales"
+msgstr "Pegar Con Botón Intermedio Ratón Activado"
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
-#, fuzzy
msgid "Selecting Enabled"
-msgstr "Sólo selección"
+msgstr "Selección Activada"
#: scene/gui/line_edit.cpp scene/gui/rich_text_label.cpp
#: scene/gui/text_edit.cpp
@@ -23970,14 +23881,12 @@ msgid "Deselect On Focus Loss Enabled"
msgstr ""
#: scene/gui/line_edit.cpp
-#, fuzzy
msgid "Right Icon"
-msgstr "Botón Derecho"
+msgstr "Icono Derecho"
#: scene/gui/line_edit.cpp
-#, fuzzy
msgid "Placeholder"
-msgstr "Cargar Como Placeholder"
+msgstr "Marcador"
#: scene/gui/line_edit.cpp
msgid "Alpha"
@@ -24000,24 +23909,20 @@ msgid "Underline"
msgstr ""
#: scene/gui/menu_button.cpp
-#, fuzzy
msgid "Switch On Hover"
-msgstr "Cambiar"
+msgstr "Cambiar Al Pasar Por Encima"
#: scene/gui/nine_patch_rect.cpp scene/resources/style_box.cpp
-#, fuzzy
msgid "Draw Center"
-msgstr "Centro"
+msgstr "Dibujar al Centro"
#: scene/gui/nine_patch_rect.cpp scene/resources/style_box.cpp
-#, fuzzy
msgid "Region Rect"
-msgstr "Establecer Region Rect"
+msgstr "Región Rectángulo"
#: scene/gui/nine_patch_rect.cpp
-#, fuzzy
msgid "Patch Margin"
-msgstr "Asignar Margen"
+msgstr "Parche de Margen"
#: scene/gui/nine_patch_rect.cpp scene/resources/style_box.cpp
msgid "Axis Stretch"
@@ -24036,14 +23941,12 @@ msgstr ""
"como Stretch en su lugar."
#: scene/gui/popup.cpp
-#, fuzzy
msgid "Popup"
-msgstr "Rellenar"
+msgstr "Popup"
#: scene/gui/popup.cpp
-#, fuzzy
msgid "Exclusive"
-msgstr "Inclusivo"
+msgstr "Exclusivo"
#: scene/gui/popup.cpp
msgid ""
@@ -24056,28 +23959,24 @@ msgstr ""
"edición, pero se esconderán al iniciar."
#: scene/gui/popup_menu.cpp
-#, fuzzy
msgid "Hide On Item Selection"
-msgstr "Centrar Selección"
+msgstr "Ocultar Al Seleccionar Elemento"
#: scene/gui/popup_menu.cpp
-#, fuzzy
msgid "Hide On Checkable Item Selection"
-msgstr "Eliminar Selección de GridMap"
+msgstr "Ocultar Al Seleccionar Elemento Activable"
#: scene/gui/popup_menu.cpp
-#, fuzzy
msgid "Hide On State Item Selection"
-msgstr "Eliminar Selección"
+msgstr "Ocultar Al Seleccionar Elemento de Estado"
#: scene/gui/popup_menu.cpp
msgid "Submenu Popup Delay"
msgstr ""
#: scene/gui/popup_menu.cpp
-#, fuzzy
msgid "Allow Search"
-msgstr "Buscar"
+msgstr "Permitir Búsqueda"
#: scene/gui/progress_bar.cpp
msgid "Percent"
@@ -24088,28 +23987,24 @@ msgid "If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."
msgstr "Si \"Exp Edit\" está activado, \"Min Value\" debe ser mayor que 0."
#: scene/gui/range.cpp scene/resources/curve.cpp
-#, fuzzy
msgid "Min Value"
-msgstr "Fijar Valor"
+msgstr "Valor Mínimo"
#: scene/gui/range.cpp scene/resources/curve.cpp
-#, fuzzy
msgid "Max Value"
-msgstr "Valor"
+msgstr "Valor Máximo"
#: scene/gui/range.cpp
msgid "Page"
msgstr "Página"
#: scene/gui/range.cpp
-#, fuzzy
msgid "Exp Edit"
-msgstr "Editar"
+msgstr "Editar Exp"
#: scene/gui/range.cpp
-#, fuzzy
msgid "Rounded"
-msgstr "Agrupado"
+msgstr "Redondeado"
#: scene/gui/range.cpp
msgid "Allow Greater"
@@ -24120,24 +24015,20 @@ msgid "Allow Lesser"
msgstr ""
#: scene/gui/reference_rect.cpp
-#, fuzzy
msgid "Border Color"
-msgstr "Cambiar Nombre del Elemento Color"
+msgstr "Color Del Borde"
#: scene/gui/reference_rect.cpp scene/resources/style_box.cpp
-#, fuzzy
msgid "Border Width"
-msgstr "Píxeles del Borde"
+msgstr "Anchura Del Borde"
#: scene/gui/rich_text_effect.cpp
-#, fuzzy
msgid "Relative Index"
-msgstr "Obtener Ãndice"
+msgstr "Ãndice Relativo"
#: scene/gui/rich_text_effect.cpp
-#, fuzzy
msgid "Absolute Index"
-msgstr "Auto Sangría"
+msgstr "Ãndice Absoluto"
#: scene/gui/rich_text_effect.cpp
msgid "Elapsed Time"
@@ -24146,7 +24037,7 @@ msgstr "Tiempo Transcurrido"
#: scene/gui/rich_text_effect.cpp
#, fuzzy
msgid "Env"
-msgstr "Fin"
+msgstr "Env"
#: scene/gui/rich_text_effect.cpp
msgid "Character"
@@ -24165,9 +24056,8 @@ msgid "Tab Size"
msgstr "Tamaño de Tabulación"
#: scene/gui/rich_text_label.cpp
-#, fuzzy
msgid "Fit Content Height"
-msgstr "Pintar Peso de Huesos"
+msgstr "Ajustar Altura Del Contenido"
#: scene/gui/rich_text_label.cpp
msgid "Scroll Active"
@@ -24178,23 +24068,20 @@ msgid "Scroll Following"
msgstr ""
#: scene/gui/rich_text_label.cpp
-#, fuzzy
msgid "Selection Enabled"
-msgstr "Sólo selección"
+msgstr "Selección Activada"
#: scene/gui/rich_text_label.cpp scene/gui/text_edit.cpp
msgid "Override Selected Font Color"
msgstr "Sobrescribir Color de Fuente Seleccionada"
#: scene/gui/rich_text_label.cpp
-#, fuzzy
msgid "Custom Effects"
-msgstr "Mover Efecto de Bus"
+msgstr "Efectos Personalizados"
#: scene/gui/scroll_bar.cpp
-#, fuzzy
msgid "Custom Step"
-msgstr "CustomNode"
+msgstr "Paso Personalizado"
#: scene/gui/scroll_container.cpp
msgid ""
@@ -24207,18 +24094,16 @@ msgstr ""
"manualmente el tamaño mínimo personalizado."
#: scene/gui/scroll_container.cpp
-#, fuzzy
msgid "Follow Focus"
-msgstr "Llenar superficie"
+msgstr "Seguir Focus"
#: scene/gui/scroll_container.cpp
msgid "Horizontal Enabled"
msgstr "Horizontal Activado"
#: scene/gui/scroll_container.cpp
-#, fuzzy
msgid "Vertical Enabled"
-msgstr "Filtrar señales"
+msgstr "Vertical Activada"
#: scene/gui/scroll_container.cpp
msgid "Default Scroll Deadzone"
@@ -24229,9 +24114,8 @@ msgid "Scrollable"
msgstr ""
#: scene/gui/slider.cpp
-#, fuzzy
msgid "Tick Count"
-msgstr "Seleccionar Color"
+msgstr "Cantidad De Marcas"
#: scene/gui/slider.cpp
msgid "Ticks On Borders"
@@ -24250,14 +24134,12 @@ msgid "Split Offset"
msgstr "Desplazamiento de División"
#: scene/gui/split_container.cpp scene/gui/tree.cpp
-#, fuzzy
msgid "Collapsed"
-msgstr "Colapsar Todo"
+msgstr "Colapsado"
#: scene/gui/split_container.cpp
-#, fuzzy
msgid "Dragger Visibility"
-msgstr "Cambiar Visibilidad"
+msgstr "Visibilidad de los Arrastradores"
#: scene/gui/tab_container.cpp scene/gui/tabs.cpp
msgid "Tab Align"
@@ -24268,9 +24150,8 @@ msgid "Current Tab"
msgstr "Pestaña Actual"
#: scene/gui/tab_container.cpp
-#, fuzzy
msgid "Tabs Visible"
-msgstr "Act./Desact. Visible"
+msgstr "Pestañas Visibles"
#: scene/gui/tab_container.cpp
msgid "All Tabs In Front"
@@ -24297,18 +24178,16 @@ msgid "Readonly"
msgstr ""
#: scene/gui/text_edit.cpp
-#, fuzzy
msgid "Bookmark Gutter"
-msgstr "Marcadores"
+msgstr "Canalón de Marcadores"
#: scene/gui/text_edit.cpp
-#, fuzzy
msgid "Breakpoint Gutter"
-msgstr "Saltar Breakpoints"
+msgstr "Canalón de Puntos de Ruptura"
#: scene/gui/text_edit.cpp
msgid "Fold Gutter"
-msgstr "Plegar Gutter"
+msgstr "Canalón Plegable"
#: scene/gui/text_edit.cpp
msgid "Drag And Drop Selection Enabled"
@@ -24335,9 +24214,8 @@ msgid "Draw"
msgstr "Dibujar"
#: scene/gui/text_edit.cpp
-#, fuzzy
msgid "Block Mode"
-msgstr "Desbloquear Nodo"
+msgstr "Modo Bloque"
#: scene/gui/text_edit.cpp
msgid "Moving By Right Click"
@@ -24356,34 +24234,29 @@ msgid "Hover"
msgstr ""
#: scene/gui/texture_button.cpp
-#, fuzzy
msgid "Focused"
-msgstr "Foco en Ruta"
+msgstr "Enfocado"
#: scene/gui/texture_button.cpp
-#, fuzzy
msgid "Click Mask"
-msgstr "Modo de Colisión"
+msgstr "Máscara de Clic"
#: scene/gui/texture_button.cpp scene/gui/texture_rect.cpp
#: scene/gui/video_player.cpp
-#, fuzzy
msgid "Expand"
-msgstr "Expandir Todo"
+msgstr "Expandir"
#: scene/gui/texture_progress.cpp
msgid "Under"
msgstr ""
#: scene/gui/texture_progress.cpp
-#, fuzzy
msgid "Over"
-msgstr "Sobreescribir"
+msgstr "Sobre"
#: scene/gui/texture_progress.cpp
-#, fuzzy
msgid "Progress"
-msgstr "Propiedades del Theme"
+msgstr "Progreso"
#: scene/gui/texture_progress.cpp
msgid "Progress Offset"
@@ -24402,43 +24275,36 @@ msgid "Radial Fill"
msgstr ""
#: scene/gui/texture_progress.cpp
-#, fuzzy
msgid "Initial Angle"
-msgstr "Inicializar"
+msgstr "Ãngulo Inicial"
#: scene/gui/texture_progress.cpp
msgid "Fill Degrees"
msgstr "Completar Grados"
#: scene/gui/texture_progress.cpp scene/resources/primitive_meshes.cpp
-#, fuzzy
msgid "Center Offset"
-msgstr "Centro Izquierda"
+msgstr "Desplazamiento Central"
#: scene/gui/texture_progress.cpp
-#, fuzzy
msgid "Nine Patch Stretch"
-msgstr "Modo de Interpolación"
+msgstr "Estiramiento de Nine Patch"
#: scene/gui/texture_progress.cpp
-#, fuzzy
msgid "Stretch Margin Left"
-msgstr "Asignar Margen"
+msgstr "Estiramiento de Margen Izquierdo"
#: scene/gui/texture_progress.cpp
-#, fuzzy
msgid "Stretch Margin Top"
-msgstr "Asignar Margen"
+msgstr "Estiramiento de Margen Superior"
#: scene/gui/texture_progress.cpp
-#, fuzzy
msgid "Stretch Margin Right"
-msgstr "Asignar Margen"
+msgstr "Estiramiento de Margen Derecho"
#: scene/gui/texture_progress.cpp
-#, fuzzy
msgid "Stretch Margin Bottom"
-msgstr "Modo de Selección"
+msgstr "Estiramiento de Margen Inferior"
#: scene/gui/tree.cpp
msgid "Custom Minimum Height"
@@ -24449,14 +24315,12 @@ msgid "(Other)"
msgstr "(Otros)"
#: scene/gui/tree.cpp
-#, fuzzy
msgid "Column Titles Visible"
-msgstr "Act./Desact. Visible"
+msgstr "Títulos de Columnas Visibles"
#: scene/gui/tree.cpp
-#, fuzzy
msgid "Hide Folding"
-msgstr "Botón Desactivado"
+msgstr "Plegado de Pieles"
#: scene/gui/tree.cpp
msgid "Hide Root"
@@ -24467,43 +24331,36 @@ msgid "Drop Mode Flags"
msgstr ""
#: scene/gui/video_player.cpp
-#, fuzzy
msgid "Audio Track"
-msgstr "Agregar Pista"
+msgstr "Pista de Audio"
#: scene/gui/video_player.cpp scene/main/scene_tree.cpp scene/main/timer.cpp
msgid "Paused"
-msgstr ""
+msgstr "Pausado"
#: scene/gui/video_player.cpp
-#, fuzzy
msgid "Buffering Msec"
-msgstr "Vista Trasera"
+msgstr "Buffering Msec"
#: scene/gui/video_player.cpp
-#, fuzzy
msgid "Stream Position"
-msgstr "Establecer Posición de Entrada de Curva"
+msgstr "Posición del Stream"
#: scene/gui/viewport_container.cpp
-#, fuzzy
msgid "Stretch Shrink"
-msgstr "Buscar"
+msgstr "Encogimiento por Estiramiento"
#: scene/main/canvas_layer.cpp
-#, fuzzy
msgid "Follow Viewport"
-msgstr "Mostrar Viewport"
+msgstr "Seguir el Viewport"
#: scene/main/http_request.cpp
-#, fuzzy
msgid "Download File"
-msgstr "Descargar"
+msgstr "Descargar Archivo"
#: scene/main/http_request.cpp
-#, fuzzy
msgid "Download Chunk Size"
-msgstr "Descargando"
+msgstr "Descargar Tamaño del Fragmento"
#: scene/main/http_request.cpp
msgid "Body Size Limit"
@@ -24524,89 +24381,76 @@ msgid ""
msgstr ""
#: scene/main/node.cpp
-#, fuzzy
msgid "Name Num Separator"
-msgstr "Separador con nombre"
+msgstr "Separador Numérico del Nombre"
#: scene/main/node.cpp
msgid "Name Casing"
msgstr ""
#: scene/main/node.cpp
-#, fuzzy
msgid "Editor Description"
-msgstr "Descripción"
+msgstr "Descripción del Editor"
#: scene/main/node.cpp
-#, fuzzy
msgid "Pause Mode"
-msgstr "Modo desplazamiento lateral"
+msgstr "Modo Pausa"
#: scene/main/node.cpp
-#, fuzzy
msgid "Physics Interpolation Mode"
-msgstr "Modo de Interpolación"
+msgstr "Modo de Interpolación Física"
#: scene/main/node.cpp
-#, fuzzy
msgid "Display Folded"
-msgstr "Mostrar Sin Sombreado"
+msgstr "Vista Plegada"
#: scene/main/node.cpp
-#, fuzzy
msgid "Filename"
-msgstr "Renombrar"
+msgstr "Nombre del Archivo"
#: scene/main/node.cpp
msgid "Owner"
msgstr "Propietario"
#: scene/main/node.cpp scene/main/scene_tree.cpp
-#, fuzzy
msgid "Multiplayer"
-msgstr "Multiplicar %s"
+msgstr "Multijugador"
#: scene/main/node.cpp
msgid "Custom Multiplayer"
msgstr "Multijugador Personalizado"
#: scene/main/node.cpp
-#, fuzzy
msgid "Process Priority"
-msgstr "Activar Prioridad"
+msgstr "Prioridad del Proceso"
#: scene/main/scene_tree.cpp scene/main/timer.cpp
-#, fuzzy
msgid "Time Left"
-msgstr "Superior Izquierda"
+msgstr "Tiempo Restante"
#: scene/main/scene_tree.cpp
-#, fuzzy
msgid "Debug Collisions Hint"
-msgstr "Modo de Colisión"
+msgstr "Sugerencia de Depuración de Colisiones"
#: scene/main/scene_tree.cpp
-#, fuzzy
msgid "Debug Navigation Hint"
-msgstr "Modo de Navegación"
+msgstr "Sugerencia de Depuración de Navegación"
#: scene/main/scene_tree.cpp
msgid "Use Font Oversampling"
msgstr ""
#: scene/main/scene_tree.cpp
-#, fuzzy
msgid "Edited Scene Root"
-msgstr "Nueva Raíz de Escena"
+msgstr "Escena Raíz Editada"
#: scene/main/scene_tree.cpp
msgid "Root"
msgstr ""
#: scene/main/scene_tree.cpp
-#, fuzzy
msgid "Multiplayer Poll"
-msgstr "Multiplicar %s"
+msgstr "Encuesta Multijugador"
#: scene/main/scene_tree.cpp scene/resources/mesh_library.cpp
#: scene/resources/shape_2d.cpp
@@ -24618,32 +24462,28 @@ msgid "Shape Color"
msgstr ""
#: scene/main/scene_tree.cpp
-#, fuzzy
msgid "Contact Color"
-msgstr "Seleccionar Color"
+msgstr "Color de Contacto"
#: scene/main/scene_tree.cpp
msgid "Geometry Color"
msgstr ""
#: scene/main/scene_tree.cpp
-#, fuzzy
msgid "Disabled Geometry Color"
-msgstr "Desactivar Elemento"
+msgstr "Color de la Geometría Desactivada"
#: scene/main/scene_tree.cpp
msgid "Max Contacts Displayed"
msgstr ""
#: scene/main/scene_tree.cpp scene/resources/shape_2d.cpp
-#, fuzzy
msgid "Draw 2D Outlines"
-msgstr "Crear Outline"
+msgstr "Dibujar Contornos 2D"
#: scene/main/scene_tree.cpp servers/visual_server.cpp
-#, fuzzy
msgid "Reflections"
-msgstr "Direcciones"
+msgstr "Reflexiones"
#: scene/main/scene_tree.cpp
msgid "Atlas Size"
@@ -24674,9 +24514,8 @@ msgid "Use 32 BPC Depth"
msgstr ""
#: scene/main/scene_tree.cpp
-#, fuzzy
msgid "Default Environment"
-msgstr "Ver Entorno"
+msgstr "Entorno por Defecto"
#: scene/main/scene_tree.cpp
msgid ""
@@ -24687,9 +24526,8 @@ msgstr ""
"(Rendering -> Environment -> Default Environment) no se ha podido cargar."
#: scene/main/scene_tree.cpp
-#, fuzzy
msgid "Enable Object Picking"
-msgstr "Activar Papel Cebolla"
+msgstr "Activar Selección de Objetos"
#: scene/main/timer.cpp
msgid ""
@@ -24709,9 +24547,8 @@ msgid "Autostart"
msgstr "Inicio Automático"
#: scene/main/viewport.cpp
-#, fuzzy
msgid "Viewport Path"
-msgstr "Ruta de Exportación"
+msgstr "Ruta del Viewport"
#: scene/main/viewport.cpp
msgid ""
@@ -24785,9 +24622,8 @@ msgid "Render Direct To Screen"
msgstr "Renderización Directa en Pantalla"
#: scene/main/viewport.cpp
-#, fuzzy
msgid "Debug Draw"
-msgstr "Depurar"
+msgstr "Depurar Dibujo"
#: scene/main/viewport.cpp
msgid "Render Target"
@@ -24798,34 +24634,28 @@ msgid "V Flip"
msgstr ""
#: scene/main/viewport.cpp
-#, fuzzy
msgid "Clear Mode"
-msgstr "Modo de Regla"
+msgstr "Modo de Limpieza"
#: scene/main/viewport.cpp
-#, fuzzy
msgid "Enable 2D"
-msgstr "Activar"
+msgstr "Activar 2D"
#: scene/main/viewport.cpp
-#, fuzzy
msgid "Enable 3D"
-msgstr "Activar"
+msgstr "Activar 3D"
#: scene/main/viewport.cpp
-#, fuzzy
msgid "Object Picking"
-msgstr "Activar Papel Cebolla"
+msgstr "Selección de Objetos"
#: scene/main/viewport.cpp
-#, fuzzy
msgid "Disable Input"
-msgstr "Desactivar Elemento"
+msgstr "Desactivar Entrada"
#: scene/main/viewport.cpp servers/visual_server.cpp
-#, fuzzy
msgid "Shadow Atlas"
-msgstr "Nuevo Atlas"
+msgstr "Sombra del Atlas"
#: scene/main/viewport.cpp
msgid "Quad 0"
@@ -24844,78 +24674,66 @@ msgid "Quad 3"
msgstr ""
#: scene/main/viewport.cpp
-#, fuzzy
msgid "Canvas Transform"
-msgstr "Reestablecer Transformación"
+msgstr "Transformación del Canvas"
#: scene/main/viewport.cpp
-#, fuzzy
msgid "Global Canvas Transform"
-msgstr "Mantener transformación global"
+msgstr "Transformación Global del Canvas"
#: scene/main/viewport.cpp
msgid "Tooltip Delay (sec)"
-msgstr ""
+msgstr "Retraso del Tooltip (sec)"
#: scene/register_scene_types.cpp
#, fuzzy
msgid "Swap OK Cancel"
-msgstr "Cancelar UI"
+msgstr "Intercambio OK Cancelar"
#: scene/register_scene_types.cpp
-#, fuzzy
msgid "Layer Names"
-msgstr "Nombre"
+msgstr "Nombres de las Capas"
#: scene/register_scene_types.cpp
-#, fuzzy
msgid "2D Render"
-msgstr "Renderización"
+msgstr "Renderización 2D"
#: scene/register_scene_types.cpp
-#, fuzzy
msgid "3D Render"
-msgstr "Renderización"
+msgstr "Renderización 3D"
#: scene/register_scene_types.cpp
-#, fuzzy
msgid "2D Physics"
-msgstr "Física"
+msgstr "Física 2D"
#: scene/register_scene_types.cpp
-#, fuzzy
msgid "3D Physics"
-msgstr "Física"
+msgstr "Física 3D"
#: scene/register_scene_types.cpp
-#, fuzzy
msgid "2D Navigation"
-msgstr "Navegación"
+msgstr "Navegación 2D"
#: scene/register_scene_types.cpp
-#, fuzzy
msgid "3D Navigation"
-msgstr "Navegación"
+msgstr "Navegación 3D"
#: scene/register_scene_types.cpp
msgid "Use hiDPI"
msgstr ""
#: scene/register_scene_types.cpp
-#, fuzzy
msgid "Custom"
-msgstr "CustomNode"
+msgstr "Personalizado"
#: scene/register_scene_types.cpp
-#, fuzzy
msgid "Custom Font"
-msgstr "CustomNode"
+msgstr "Fuente Personalizada"
#: scene/resources/audio_stream_sample.cpp
#: servers/audio/effects/audio_stream_generator.cpp servers/audio_server.cpp
-#, fuzzy
msgid "Mix Rate"
-msgstr "Nodo Mix"
+msgstr "Tasa de Mezcla"
#: scene/resources/audio_stream_sample.cpp
msgid "Stereo"
@@ -24926,9 +24744,8 @@ msgid "Segments"
msgstr "Segmentos"
#: scene/resources/curve.cpp
-#, fuzzy
msgid "Bake Resolution"
-msgstr "Media Resolución"
+msgstr "Bakear Resolución"
#: scene/resources/curve.cpp
msgid "Bake Interval"
@@ -24939,77 +24756,64 @@ msgid "Panel"
msgstr ""
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Font Color"
-msgstr "Seleccionar Color"
+msgstr "Color de la Fuente"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Font Color Pressed"
-msgstr "Color Hueso 1"
+msgstr "Color de la Fuente Presionada"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Font Color Hover"
-msgstr "Color Hueso 1"
+msgstr "Color de la Fuente por Encima"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Font Color Focus"
-msgstr "Llenar superficie"
+msgstr "Color de la Fuente Enfocada"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Font Color Disabled"
-msgstr "Clip Deshabilitado"
+msgstr "Color de la Fuente Desactivada"
#: scene/resources/default_theme/default_theme.cpp
msgid "H Separation"
msgstr "Separación en H"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Underline Spacing"
-msgstr "Espaciado de Línea"
+msgstr "Espaciado del Subrayado"
#: scene/resources/default_theme/default_theme.cpp
msgid "Arrow"
msgstr ""
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Arrow Margin"
-msgstr "Asignar Margen"
+msgstr "Margen de la Flecha"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Hover Pressed"
-msgstr "Preset"
+msgstr "Presionado por Encima"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Checked Disabled"
-msgstr "Chequeable"
+msgstr "Marcado Desactivado"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Unchecked"
-msgstr "Chequeado"
+msgstr "Sin marcar"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Unchecked Disabled"
-msgstr "Desactivar Elemento"
+msgstr "Sin marcar Desactivado"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Radio Checked"
-msgstr "Chequeado"
+msgstr "Radio Marcado"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Radio Checked Disabled"
-msgstr "(Editor Desactivado)"
+msgstr "Radio Marcado Desactivado"
#: scene/resources/default_theme/default_theme.cpp
msgid "Radio Unchecked"
@@ -25030,27 +24834,23 @@ msgstr ""
#: scene/resources/default_theme/default_theme.cpp
#, fuzzy
msgid "On Disabled"
-msgstr "Desactivar Elemento"
+msgstr "Desactivado"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Off"
-msgstr "Desplazamiento"
+msgstr "Apagado"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Off Disabled"
-msgstr "Desactivar Elemento"
+msgstr "Apagado Desactivado"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Font Color Shadow"
-msgstr "Color Hueso 1"
+msgstr "Color de la Sombra de la Fuente"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Font Outline Modulate"
-msgstr "Forzar Modulación en Blanco"
+msgstr "Modulación del Contorno de la Fuente"
#: scene/resources/default_theme/default_theme.cpp
msgid "Shadow Offset X"
@@ -25061,59 +24861,50 @@ msgid "Shadow Offset Y"
msgstr "Desplazamiento de la Sombra en Y"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Shadow As Outline"
-msgstr "Mostrar Contorno Anterior"
+msgstr "Sombra como Contorno"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Font Color Selected"
-msgstr "Desbloquear Seleccionado"
+msgstr "Color de Fuente Seleccionada"
#: scene/resources/default_theme/default_theme.cpp
msgid "Font Color Uneditable"
msgstr ""
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Cursor Color"
-msgstr "CustomNode"
+msgstr "Color del Cursor"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Clear Button Color"
-msgstr "Filtrar señales"
+msgstr "Limpiar Color del Botón"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Clear Button Color Pressed"
-msgstr "Filtrar señales"
+msgstr "Limpiar Color del Botón Presionado"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Minimum Spaces"
-msgstr "Escena Principal"
+msgstr "Espacios Mínimos"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "BG"
-msgstr "B"
+msgstr "BG"
#: scene/resources/default_theme/default_theme.cpp
msgid "FG"
msgstr ""
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Tab"
-msgstr "Tab 1"
+msgstr "Tab"
#: scene/resources/default_theme/default_theme.cpp
#: scene/resources/dynamic_font.cpp scene/resources/world.cpp
#: scene/resources/world_2d.cpp
-#, fuzzy
msgid "Space"
-msgstr "Escena Principal"
+msgstr "Espacio"
#: scene/resources/default_theme/default_theme.cpp
msgid "Folded"
@@ -25128,9 +24919,8 @@ msgid "Font Color Readonly"
msgstr ""
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Completion Lines"
-msgstr "Completar"
+msgstr "Finalización de Líneas"
#: scene/resources/default_theme/default_theme.cpp
#, fuzzy
@@ -26907,7 +26697,7 @@ msgstr "Margen de Conexión de Bordes"
#: scene/resources/world_2d.cpp
msgid "Canvas"
-msgstr ""
+msgstr "Lienzo"
#: servers/arvr/arvr_interface.cpp
msgid "Is Primary"
diff --git a/editor/translations/es_AR.po b/editor/translations/es_AR.po
index b37d9dcfd8..10a562d0b8 100644
--- a/editor/translations/es_AR.po
+++ b/editor/translations/es_AR.po
@@ -2800,7 +2800,7 @@ msgstr ""
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "Copiar Ruta del Nodo"
#: editor/editor_export.cpp
@@ -20742,15 +20742,15 @@ msgstr "No se pudo encontrar la keystore, no se puedo exportar."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Archivo ejecutable no válido."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20774,15 +20774,15 @@ msgstr "Nombre inválido."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Archivo ejecutable no válido."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/et.po b/editor/translations/et.po
index 1f3fe075df..3976c9f0bd 100644
--- a/editor/translations/et.po
+++ b/editor/translations/et.po
@@ -2789,7 +2789,7 @@ msgstr ""
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "Kopeeri sõlme tee"
#: editor/editor_export.cpp
@@ -20013,15 +20013,15 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Vigane nimi."
#: platform/windows/export/export.cpp
msgid "Could not find signtool executable at \"%s\"."
@@ -20043,15 +20043,15 @@ msgstr "Vigane nimi."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Vigane nimi."
#: platform/windows/export/export.cpp
msgid "Failed to remove temporary file \"%s\"."
diff --git a/editor/translations/eu.po b/editor/translations/eu.po
index 2555dfa8d3..3e69f3c4b9 100644
--- a/editor/translations/eu.po
+++ b/editor/translations/eu.po
@@ -2756,8 +2756,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "Kargatu animazioa"
#: editor/editor_export.cpp
#, fuzzy
@@ -19815,15 +19816,15 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Animazio izen baliogabea!"
#: platform/windows/export/export.cpp
msgid "Could not find signtool executable at \"%s\"."
@@ -19845,15 +19846,15 @@ msgstr "Animazio izen baliogabea!"
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Animazio izen baliogabea!"
#: platform/windows/export/export.cpp
msgid "Failed to remove temporary file \"%s\"."
diff --git a/editor/translations/fa.po b/editor/translations/fa.po
index a0202d3254..86b847e530 100644
--- a/editor/translations/fa.po
+++ b/editor/translations/fa.po
@@ -2840,7 +2840,7 @@ msgstr ""
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "کپی کردن مسیر node"
#: editor/editor_export.cpp
@@ -20752,15 +20752,15 @@ msgstr "نمی‌تواند یک پوشه ایجاد شود."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "باید از یک پسوند معتبر Ø§Ø³ØªÙØ§Ø¯Ù‡ شود."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20784,15 +20784,15 @@ msgstr "نام نامعتبر."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "باید از یک پسوند معتبر Ø§Ø³ØªÙØ§Ø¯Ù‡ شود."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/fi.po b/editor/translations/fi.po
index 28b4581d60..db841ef48a 100644
--- a/editor/translations/fi.po
+++ b/editor/translations/fi.po
@@ -2864,7 +2864,7 @@ msgstr ""
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "Kopioi solmun polku"
#: editor/editor_export.cpp
@@ -20756,17 +20756,17 @@ msgstr "Keystorea ei löytynyt, ei voida viedä."
#: platform/windows/export/export.cpp
#, fuzzy
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
"rcedit-työkalu täytyy olla konfiguroituna editorin asetuksissa (Export > "
"Windows > Rcedit) ikonin tai sovelluksen tietojen muuttamiseksi."
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Virheellinen käynnistystiedosto."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20791,17 +20791,17 @@ msgstr "Virheellinen nimi."
#: platform/windows/export/export.cpp
#, fuzzy
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
"rcedit-työkalu täytyy olla konfiguroituna editorin asetuksissa (Export > "
"Windows > Rcedit) ikonin tai sovelluksen tietojen muuttamiseksi."
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Virheellinen käynnistystiedosto."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/fil.po b/editor/translations/fil.po
index 4671a2aeaf..0a154fd6ae 100644
--- a/editor/translations/fil.po
+++ b/editor/translations/fil.po
@@ -2712,8 +2712,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "Pagulit ng Animation"
#: editor/editor_export.cpp
msgid "Completed successfully."
@@ -19501,14 +19502,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
+msgid "rcedit failed to modify executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
@@ -19530,14 +19530,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
+msgid "Signtool failed to sign executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
diff --git a/editor/translations/fr.po b/editor/translations/fr.po
index 85a3e54c1d..88c4966b54 100644
--- a/editor/translations/fr.po
+++ b/editor/translations/fr.po
@@ -101,13 +101,14 @@
# Arnaud Lier <arnaud@ric-rac.org>, 2022.
# Jérémie Guegain <mirejai@orange.fr>, 2022.
# cwulveryck <cwulveryck@online.fr>, 2022.
+# Helix Sir <vincentbarkmann@gmail.com>, 2022.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-07-16 06:20+0000\n"
-"Last-Translator: cwulveryck <cwulveryck@online.fr>\n"
+"PO-Revision-Date: 2022-08-05 01:04+0000\n"
+"Last-Translator: Helix Sir <vincentbarkmann@gmail.com>\n"
"Language-Team: French <https://hosted.weblate.org/projects/godot-engine/"
"godot/fr/>\n"
"Language: fr\n"
@@ -147,11 +148,11 @@ msgstr "Lissage de Delta"
#: core/bind/core_bind.cpp
msgid "Low Processor Usage Mode"
-msgstr "Mode d'Utilisation Faible du Processeur"
+msgstr "Mode d'utilisation faible du processeur"
#: core/bind/core_bind.cpp
msgid "Low Processor Usage Mode Sleep (µsec)"
-msgstr "Mode d'Utilisation Faible du Processeur (µs)"
+msgstr "Mode d'utilisation faible du processeur Veille (µsec)"
#: core/bind/core_bind.cpp main/main.cpp platform/uwp/os_uwp.cpp
msgid "Keep Screen On"
@@ -244,9 +245,8 @@ msgid "Time Scale"
msgstr "Echelle de temps"
#: core/bind/core_bind.cpp main/main.cpp
-#, fuzzy
msgid "Physics Jitter Fix"
-msgstr "Correction de la physique gigue"
+msgstr "Correction des sursauts de physique"
#: core/bind/core_bind.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "Error"
@@ -316,9 +316,8 @@ msgid "Page Size"
msgstr "Taille de page"
#: core/io/file_access_network.cpp
-#, fuzzy
msgid "Page Read Ahead"
-msgstr "Page lue devant"
+msgstr "Pré-lecture de page"
#: core/io/http_client.cpp
msgid "Blocking Mode Enabled"
@@ -329,9 +328,8 @@ msgid "Connection"
msgstr "Connexion"
#: core/io/http_client.cpp
-#, fuzzy
msgid "Read Chunk Size"
-msgstr "Lire la taille du tronçon"
+msgstr "Taile des tronçons de lecture"
#: core/io/marshalls.cpp
msgid "Object ID"
@@ -375,7 +373,7 @@ msgstr "Taille maximale du tampon de sortie"
#: core/io/packet_peer.cpp
msgid "Stream Peer"
-msgstr ""
+msgstr "Pair de flux"
#: core/io/stream_peer.cpp
msgid "Big Endian"
@@ -488,9 +486,8 @@ msgid "Command"
msgstr "Commande"
#: core/os/input_event.cpp
-#, fuzzy
msgid "Physical"
-msgstr " (physique)"
+msgstr "Physique"
#: core/os/input_event.cpp scene/2d/touch_screen_button.cpp
#: scene/gui/base_button.cpp scene/gui/texture_button.cpp
@@ -500,7 +497,7 @@ msgstr "Pressé"
#: core/os/input_event.cpp
msgid "Scancode"
-msgstr "Scancode"
+msgstr "Code de scan"
#: core/os/input_event.cpp
msgid "Physical Scancode"
@@ -543,9 +540,8 @@ msgid "Pressure"
msgstr "Pression"
#: core/os/input_event.cpp
-#, fuzzy
msgid "Pen Inverted"
-msgstr "Inverser"
+msgstr "Stylo Inversé"
#: core/os/input_event.cpp
msgid "Relative"
@@ -624,7 +620,7 @@ msgstr "Application"
#: core/project_settings.cpp main/main.cpp
msgid "Config"
-msgstr "Config"
+msgstr "Configuration"
#: core/project_settings.cpp
msgid "Project Settings Override"
@@ -731,9 +727,8 @@ msgid "Editor"
msgstr "Éditeur"
#: core/project_settings.cpp
-#, fuzzy
msgid "Main Run Args"
-msgstr "Arguments de la scène principale :"
+msgstr "Paramètres d'exécution du programme principal"
#: core/project_settings.cpp
msgid "Scene Naming"
@@ -797,9 +792,8 @@ msgid "UI Down"
msgstr "Bas"
#: core/project_settings.cpp
-#, fuzzy
msgid "UI Page Up"
-msgstr "Page Haut"
+msgstr "Page Haut (Interface)"
#: core/project_settings.cpp
msgid "UI Page Down"
@@ -835,9 +829,8 @@ msgid "3D"
msgstr "3D"
#: core/project_settings.cpp
-#, fuzzy
msgid "Smooth Trimesh Collision"
-msgstr "Collision Lisse Trimesh"
+msgstr "Lissage de Collision Trimesh"
#: core/project_settings.cpp drivers/gles2/rasterizer_canvas_base_gles2.cpp
#: drivers/gles2/rasterizer_scene_gles2.cpp
@@ -918,9 +911,8 @@ msgid "Compression Level"
msgstr "Niveau de Compression"
#: core/project_settings.cpp
-#, fuzzy
msgid "Window Log Size"
-msgstr "Taille de la fenêtre du journal"
+msgstr "Taille du journal de la fenêtre"
#: core/project_settings.cpp
msgid "Zlib"
@@ -948,10 +940,9 @@ msgstr "Délai d'expiration de la connexion en secondes"
#: core/register_core_types.cpp
msgid "Packet Peer Stream"
-msgstr ""
+msgstr "Flux de pair de paquet"
#: core/register_core_types.cpp
-#, fuzzy
msgid "Max Buffer (Power of 2)"
msgstr "Tampon Max (puissance de 2)"
@@ -993,7 +984,6 @@ msgid "Test"
msgstr "Test"
#: core/translation.cpp scene/resources/font.cpp
-#, fuzzy
msgid "Fallback"
msgstr "Repli"
@@ -1036,12 +1026,12 @@ msgstr "Tampons"
#: drivers/gles2/rasterizer_canvas_base_gles2.cpp
#: drivers/gles3/rasterizer_canvas_base_gles3.cpp
msgid "Canvas Polygon Buffer Size (KB)"
-msgstr ""
+msgstr "Taille du tampon des polygones du canevas (Ko)"
#: drivers/gles2/rasterizer_canvas_base_gles2.cpp
#: drivers/gles3/rasterizer_canvas_base_gles3.cpp
msgid "Canvas Polygon Index Buffer Size (KB)"
-msgstr ""
+msgstr "Taille de l'index des polygones du canevas (Ko)"
#: drivers/gles2/rasterizer_canvas_base_gles2.cpp
#: drivers/gles3/rasterizer_canvas_base_gles3.cpp editor/editor_settings.cpp
@@ -1057,15 +1047,13 @@ msgstr "2D"
#: drivers/gles2/rasterizer_canvas_base_gles2.cpp
#: drivers/gles3/rasterizer_canvas_base_gles3.cpp
-#, fuzzy
msgid "Snapping"
-msgstr "Magnétisme intelligent"
+msgstr "Magnétisme"
#: drivers/gles2/rasterizer_canvas_base_gles2.cpp
#: drivers/gles3/rasterizer_canvas_base_gles3.cpp
-#, fuzzy
msgid "Use GPU Pixel Snap"
-msgstr "Aligner au pixel près"
+msgstr "Arrondissement GPU au pixel le plus proche"
#: drivers/gles2/rasterizer_scene_gles2.cpp
#: drivers/gles3/rasterizer_scene_gles3.cpp
@@ -1074,9 +1062,8 @@ msgstr "Taille du tampon immédiat (Ko)"
#: drivers/gles2/rasterizer_storage_gles2.cpp
#: drivers/gles3/rasterizer_storage_gles3.cpp
-#, fuzzy
msgid "Lightmapping"
-msgstr "Précalculer les lightmaps"
+msgstr "Cartographie des lumières"
#: drivers/gles2/rasterizer_storage_gles2.cpp
#: drivers/gles3/rasterizer_storage_gles3.cpp
@@ -1100,7 +1087,6 @@ msgid "Max Lights Per Object"
msgstr "Maximum de lumières par objet"
#: drivers/gles3/rasterizer_scene_gles3.cpp
-#, fuzzy
msgid "Subsurface Scattering"
msgstr "Transluminescence"
@@ -1122,13 +1108,12 @@ msgid "Follow Surface"
msgstr "Suivre la surface"
#: drivers/gles3/rasterizer_scene_gles3.cpp
-#, fuzzy
msgid "Weight Samples"
msgstr "Échantillons de poids"
#: drivers/gles3/rasterizer_scene_gles3.cpp
msgid "Voxel Cone Tracing"
-msgstr ""
+msgstr "Traçage de cone voxel"
#: drivers/gles3/rasterizer_scene_gles3.cpp scene/resources/environment.cpp
msgid "High Quality"
@@ -1136,7 +1121,7 @@ msgstr "Haute Qualité"
#: drivers/gles3/rasterizer_storage_gles3.cpp
msgid "Blend Shape Max Buffer Size (KB)"
-msgstr ""
+msgstr "Taille max du tampon de mélange de formes"
#. TRANSLATORS: Adjective, refers to the mode for Bezier handles (Free, Balanced, Mirror).
#: editor/animation_bezier_editor.cpp
@@ -1193,7 +1178,7 @@ msgstr "Modifier le temps de l’image-clé"
#: editor/animation_track_editor.cpp
msgid "Anim Change Transition"
-msgstr "Changer la transition de l’animation"
+msgstr "Transition de changement de l’animation"
#: editor/animation_track_editor.cpp
msgid "Anim Change Transform"
@@ -1253,14 +1238,12 @@ msgid "Type"
msgstr "Type"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "In Handle"
-msgstr "Définir la poignée"
+msgstr "Poignée d'entrée"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Out Handle"
-msgstr "Définir la poignée"
+msgstr "Poignée de sortie"
#: editor/animation_track_editor.cpp
#: editor/import/resource_importer_texture.cpp
@@ -1274,7 +1257,6 @@ msgid "Start Offset"
msgstr "Décalage du Départ"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "End Offset"
msgstr "Décalage à la fin"
@@ -1289,9 +1271,8 @@ msgid "Animation"
msgstr "Animation"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Easing"
-msgstr "Ease in-out"
+msgstr "Transition entrée-sortie"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Keyframe Time"
@@ -1430,38 +1411,32 @@ msgid "(Invalid, expected type: %s)"
msgstr "(Invalide, type attendu : %s)"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Easing:"
-msgstr "Ease in-out"
+msgstr "Transition entrée-sortie :"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "In-Handle:"
-msgstr "Définir la poignée"
+msgstr "Poignée d'entrée :"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Out-Handle:"
-msgstr "Définir la poignée"
+msgstr "Poignée de sortie :"
#: editor/animation_track_editor.cpp
msgid "Stream:"
msgstr "Flux :"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Start (s):"
-msgstr "Redémarrer (s) :"
+msgstr "Début (s) :"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "End (s):"
-msgstr "Fondu entrant (s) :"
+msgstr "Fin (s) :"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Animation Clip:"
-msgstr "Animations :"
+msgstr "Clip d'animation :"
#: editor/animation_track_editor.cpp
msgid "Toggle Track Enabled"
@@ -1549,9 +1524,8 @@ msgid "Editors"
msgstr "Éditeurs"
#: editor/animation_track_editor.cpp editor/editor_settings.cpp
-#, fuzzy
msgid "Confirm Insert Track"
-msgstr "Insérer une piste et clé d’animation"
+msgstr "Confirmer l'ajout de piste"
#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
@@ -2867,8 +2841,8 @@ msgid "Project export for platform:"
msgstr "Exportation du projet pour la plateforme :"
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr "Terminé avec des erreurs."
+msgid "Completed with warnings."
+msgstr "Terminé avec des avertissements."
#: editor/editor_export.cpp
msgid "Completed successfully."
@@ -2988,9 +2962,8 @@ msgid "64 Bits"
msgstr "64 Bits"
#: editor/editor_export.cpp
-#, fuzzy
msgid "Embed PCK"
-msgstr "PCK Intégré"
+msgstr "Intégrer PCK"
#: editor/editor_export.cpp platform/osx/export/export.cpp
msgid "Texture Format"
@@ -3029,9 +3002,8 @@ msgid "Custom release template not found."
msgstr "Modèle de version personnalisée introuvable."
#: editor/editor_export.cpp
-#, fuzzy
msgid "Prepare Template"
-msgstr "Gérer les modèles"
+msgstr "Préparer le modèle type"
#: editor/editor_export.cpp platform/osx/export/export.cpp
msgid "The given export path doesn't exist."
@@ -3047,9 +3019,8 @@ msgstr "La copie du modèle d'exportation a échoué."
#: editor/editor_export.cpp platform/windows/export/export.cpp
#: platform/x11/export/export.cpp
-#, fuzzy
msgid "PCK Embedding"
-msgstr "Intégration du PCK"
+msgstr "Intégration PCK"
#: editor/editor_export.cpp
msgid "On 32-bit exports the embedded PCK cannot be bigger than 4 GiB."
@@ -3270,9 +3241,8 @@ msgid "Manage Editor Feature Profiles"
msgstr "Gérer les profils de fonctionnalités de l'éditeur"
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "Default Feature Profile"
-msgstr "Profil des fonctionnalités de Godot"
+msgstr "Profil de fonctionalités par défaut"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
msgid "Select Current Folder"
@@ -3383,7 +3353,6 @@ msgid "Show Hidden Files"
msgstr "Afficher les fichiers cachés"
#: editor/editor_file_dialog.cpp
-#, fuzzy
msgid "Disable Overwrite Warning"
msgstr "Désactiver l'avertissement de réécriture"
@@ -3688,25 +3657,21 @@ msgid "Read Only"
msgstr "Lecture Seule"
#: editor/editor_inspector.cpp editor/plugins/item_list_editor_plugin.cpp
-#, fuzzy
msgid "Checkable"
-msgstr "Item à cocher"
+msgstr "Cochable"
#: editor/editor_inspector.cpp editor/plugins/item_list_editor_plugin.cpp
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Checked"
-msgstr "Item coché"
+msgstr "Coché"
#: editor/editor_inspector.cpp
-#, fuzzy
msgid "Draw Red"
-msgstr "Appels de dessin :"
+msgstr "Dessiner en rouge"
#: editor/editor_inspector.cpp
-#, fuzzy
msgid "Keying"
-msgstr "Jouer"
+msgstr "En train de taper"
#: editor/editor_inspector.cpp
msgid "Pin value"
@@ -4080,10 +4045,8 @@ msgid "Save & Reload"
msgstr "Sauvegarder & Recharger"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Save changes to '%s' before reloading?"
-msgstr ""
-"Sauvegarder les modifications effectuées dans « %s » avant de recharger ?"
+msgstr "Sauvegarder les modifications dans '%s' avant de recharger ?"
#: editor/editor_node.cpp
msgid "Save & Close"
@@ -4202,11 +4165,9 @@ msgid "Open Project Manager?"
msgstr "Ouvrir le gestionnaire de projets ?"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Save changes to the following scene(s) before reloading?"
msgstr ""
-"Sauvegarder les modifications sur la (les) scène(s) suivante(s) avant de "
-"quitter ?"
+"Sauvegarder les modifications de scène(s) suivante(s) avant de recharger ?"
#: editor/editor_node.cpp
msgid "Save & Quit"
@@ -4411,9 +4372,8 @@ msgid "Interface"
msgstr "Interface"
#: editor/editor_node.cpp editor/editor_settings.cpp
-#, fuzzy
msgid "Scene Tabs"
-msgstr "Basculer entre onglets de scène"
+msgstr "Onglets de scène"
#: editor/editor_node.cpp
msgid "Always Show Close Button"
@@ -4448,7 +4408,6 @@ msgid "Save On Focus Loss"
msgstr "Enregistrer lorsque le focus est perdu"
#: editor/editor_node.cpp editor/editor_settings.cpp
-#, fuzzy
msgid "Save Each Scene On Quit"
msgstr "Enregistrer toutes les scènes à la fermeture"
@@ -4470,12 +4429,10 @@ msgid "Update Vital Only"
msgstr "Changements de matériau"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Localize Settings"
-msgstr "Localisation"
+msgstr "Traduction des réglages"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Restore Scenes On Load"
msgstr "Restaurer les scènes au chargement"
@@ -4488,7 +4445,6 @@ msgid "Inspector"
msgstr "Inspecteur"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Default Property Name Style"
msgstr "Style par défaut des noms de propriétés"
@@ -4497,12 +4453,10 @@ msgid "Default Float Step"
msgstr "Pas par défaut des flottant"
#: editor/editor_node.cpp scene/gui/tree.cpp
-#, fuzzy
msgid "Disable Folding"
-msgstr "Bouton désactivé"
+msgstr "Désactiver le repliage"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Auto Unfold Foreign Scenes"
msgstr "Déplier automatiquement les scènes étrangères"
@@ -4511,7 +4465,6 @@ msgid "Horizontal Vector2 Editing"
msgstr "Édition horizontale de Vector2"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Horizontal Vector Types Editing"
msgstr "Édition de Types de Vecteur Horizontal"
@@ -4520,12 +4473,10 @@ msgid "Open Resources In Current Inspector"
msgstr "Ouvrir les ressources dans l'inspecteur actuel"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Resources To Open In New Inspector"
msgstr "Ressources à ouvrir dans un nouvel inspecteur"
#: editor/editor_node.cpp
-#, fuzzy
msgid "Default Color Picker Mode"
msgstr "Mode par défaut du sélectionneur de couleur"
@@ -5187,14 +5138,12 @@ msgid "Debugger"
msgstr "Débogueur"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Profiler Frame History Size"
msgstr "Taille de l'historique de la trame du profileur"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Profiler Frame Max Functions"
-msgstr "Renommer la fonction"
+msgstr "Nombre maximum de fonctions par trame de profileur"
#: editor/editor_properties.cpp
msgid "Edit Text:"
@@ -5409,12 +5358,10 @@ msgid "Code Font Size"
msgstr "Taille de la police du code"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Font Antialiased"
-msgstr "Anticrénelage appliqué sur la police"
+msgstr "Police anticrénelée"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Font Hinting"
msgstr "Indication de police"
@@ -5435,18 +5382,16 @@ msgid "Dim Editor On Dialog Popup"
msgstr "Assombrir l'éditeur à l'ouverture d'un dialogue"
#: editor/editor_settings.cpp main/main.cpp
-#, fuzzy
msgid "Low Processor Mode Sleep (µsec)"
-msgstr "Mode de faible latence Processeur"
+msgstr "Veille du Mode faible latence Processeur (µsec)"
#: editor/editor_settings.cpp
msgid "Unfocused Low Processor Mode Sleep (µsec)"
-msgstr ""
+msgstr "Veille du mode d'utilisation faible du processeur quand inactif (µsec)"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Separate Distraction Mode"
-msgstr "Mode Sans Distraction"
+msgstr "Mode distraction séparée"
#: editor/editor_settings.cpp
msgid "Automatically Open Screenshots"
@@ -5454,7 +5399,7 @@ msgstr "Ouvrir automatiquement les captures d'écran"
#: editor/editor_settings.cpp
msgid "Max Array Dictionary Items Per Page"
-msgstr ""
+msgstr "Nombre maximum d'articles tableau de dictionnaire par page"
#: editor/editor_settings.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp scene/gui/control.cpp
@@ -5475,9 +5420,8 @@ msgid "Base Color"
msgstr "Couleur de Base"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Accent Color"
-msgstr "Prélever une couleur"
+msgstr "Couleur d'accentuation"
#: editor/editor_settings.cpp scene/resources/environment.cpp
msgid "Contrast"
@@ -5485,69 +5429,59 @@ msgstr "Contraste"
#: editor/editor_settings.cpp
msgid "Relationship Line Opacity"
-msgstr ""
+msgstr "Opacité des lignes de relation"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Highlight Tabs"
-msgstr "Enregistrement des lightmaps"
+msgstr "Surligner les onglets"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Border Size"
-msgstr "Pixels de bordure"
+msgstr "Taille de bordure"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Use Graph Node Headers"
-msgstr "Utiliser les en-tête de noeud Graph"
+msgstr "Utiliser les en-têtes de graphes des nœuds"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Additional Spacing"
-msgstr "Bouclage de l’animation"
+msgstr "Espacement supplémentaire"
#: editor/editor_settings.cpp
msgid "Custom Theme"
msgstr "Thème Personnalisé"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Show Script Button"
-msgstr "Molette bouton droit"
+msgstr "Afficher le bouton script"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Directories"
-msgstr "Directions"
+msgstr "Dossiers"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Autoscan Project Path"
-msgstr "Chemin du projet :"
+msgstr "Scan auto du chemin du projet"
#: editor/editor_settings.cpp
msgid "Default Project Path"
msgstr "Chemin du Projet par Défaut"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "On Save"
-msgstr "Enregistrer"
+msgstr "À l'enregistrement"
#: editor/editor_settings.cpp
msgid "Compress Binary Resources"
msgstr "Compresser les ressources binaires"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Safe Save On Backup Then Rename"
-msgstr "Sauvegarde sécurisée lors de l'archivage puis renommer"
+msgstr "Sauvegarde sécurisée lors de l'archivage avant de renommer"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "File Dialog"
-msgstr "Dialogue XForm"
+msgstr "Fenêtre de sélection de fichiers"
#: editor/editor_settings.cpp
msgid "Thumbnail Size"
@@ -5555,21 +5489,19 @@ msgstr "Taille de la vignette"
#: editor/editor_settings.cpp
msgid "Docks"
-msgstr ""
+msgstr "S'attache"
#: editor/editor_settings.cpp
msgid "Scene Tree"
msgstr "une arborescence, arbre des scènes"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Start Create Dialog Fully Expanded"
-msgstr "Lancer le dialogue de Création totalement expandu"
+msgstr "Lancer le dialogue de création complètement déplié"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Always Show Folders"
-msgstr "Toujours afficher la grille"
+msgstr "Toujours afficher les dossiers"
#: editor/editor_settings.cpp
msgid "Property Editor"
@@ -5580,29 +5512,24 @@ msgid "Auto Refresh Interval"
msgstr "Intervalle d’autorafraîchissement"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Subresource Hue Tint"
-msgstr "Ressources secondaires"
+msgstr "Teinte des sous-ressources"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Color Theme"
-msgstr "Thème de l'éditeur"
+msgstr "Thème de couleurs"
#: editor/editor_settings.cpp scene/3d/label_3d.cpp
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Line Spacing"
msgstr "Espace entre les lignes"
#: editor/editor_settings.cpp editor/plugins/script_text_editor.cpp
#: modules/gdscript/editor/gdscript_highlighter.cpp
-#, fuzzy
msgid "Highlighting"
-msgstr "Éclairage direct"
+msgstr "Surlignage"
#: editor/editor_settings.cpp scene/gui/text_edit.cpp
-#, fuzzy
msgid "Syntax Highlighting"
msgstr "Coloration syntaxique"
@@ -5615,32 +5542,28 @@ msgid "Highlight Current Line"
msgstr "Mettre en évidence la ligne actuelle"
#: editor/editor_settings.cpp editor/plugins/script_text_editor.cpp
-#, fuzzy
msgid "Highlight Type Safe Lines"
-msgstr "Surligner les lignes Typées"
+msgstr "Surligner les lignes à types sûrs"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Indent"
-msgstr "Indenter vers la gauche"
+msgstr "Indenter"
#: editor/editor_settings.cpp editor/plugins/script_text_editor.cpp
msgid "Auto Indent"
msgstr "Indentation automatique"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Convert Indent On Save"
-msgstr "Convertir indentations en espaces"
+msgstr "Convertir les indentations à l'enregistrement"
#: editor/editor_settings.cpp scene/gui/text_edit.cpp
msgid "Draw Tabs"
msgstr "Montrer les tabulations"
#: editor/editor_settings.cpp scene/gui/text_edit.cpp
-#, fuzzy
msgid "Draw Spaces"
-msgstr "Appels de dessin :"
+msgstr "Afficher les espaces"
#: editor/editor_settings.cpp editor/plugins/spatial_editor_plugin.cpp
#: editor/plugins/tile_set_editor_plugin.cpp scene/2d/tile_map.cpp
@@ -5658,9 +5581,8 @@ msgid "V Scroll Speed"
msgstr "Vitesse du défilement vertical"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Show Minimap"
-msgstr "Afficher l'origine"
+msgstr "Afficher la minimap"
#: editor/editor_settings.cpp
msgid "Minimap Width"
@@ -5668,16 +5590,15 @@ msgstr "Largeur de la mini-carte"
#: editor/editor_settings.cpp
msgid "Mouse Extra Buttons Navigate History"
-msgstr ""
+msgstr "Boutons additionnels de la souris déplacent dans l'historique"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Drag And Drop Selection"
-msgstr "Sélection de la GridMap"
+msgstr "Sélection glisser/déposer"
#: editor/editor_settings.cpp
msgid "Stay In Script Editor On Node Selected"
-msgstr ""
+msgstr "Rester sur l’éditeur de script en sélectionnant un nœud"
#: editor/editor_settings.cpp
msgid "Appearance"
@@ -5688,21 +5609,18 @@ msgid "Show Line Numbers"
msgstr "Afficher les Numéros de Ligne"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Line Numbers Zero Padded"
-msgstr "Numéro de ligne :"
+msgstr "Numéros de lignes avec remplissage en zéros"
#: editor/editor_settings.cpp
msgid "Show Bookmark Gutter"
msgstr "Montrer le bandeau de marque-page"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Show Breakpoint Gutter"
-msgstr "Passer les points d'arrêt"
+msgstr "Afficher le bandeau de points d’arrêt"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Show Info Gutter"
msgstr "Montrer le bandeau d'information"
@@ -5712,26 +5630,25 @@ msgstr "Rétrécir le code"
#: editor/editor_settings.cpp
msgid "Word Wrap"
-msgstr ""
+msgstr "Retour à la ligne des mots"
#: editor/editor_settings.cpp
msgid "Show Line Length Guidelines"
-msgstr ""
+msgstr "Montrer les guides de longueur de ligne"
#: editor/editor_settings.cpp
msgid "Line Length Guideline Soft Column"
-msgstr ""
+msgstr "Colonne douce des guides de longueur de ligne"
#: editor/editor_settings.cpp
msgid "Line Length Guideline Hard Column"
-msgstr ""
+msgstr "Colonne dure des guides de longueur de ligne"
#: editor/editor_settings.cpp editor/plugins/script_editor_plugin.cpp
msgid "Script List"
msgstr "Liste des Scripts"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Show Members Overview"
msgstr "Montrer l'ensemble des Membres"
@@ -5740,19 +5657,16 @@ msgid "Files"
msgstr "Fichiers"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Trim Trailing Whitespace On Save"
-msgstr "Supprimer les espaces de fin de ligne"
+msgstr "Retirer les espaces de fin de ligne à l'enregistrement"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Autosave Interval Secs"
-msgstr "Intervalle entre les auto-sauvegarde (en secondes)"
+msgstr "Intervalle entre les sauvegardes automatiques (en secondes)"
#: editor/editor_settings.cpp editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Restore Scripts On Load"
-msgstr "Restaurer les scripts lors du chargement"
+msgstr "Restaurer les scripts au chargement"
#: editor/editor_settings.cpp
msgid "Auto Reload And Parse Scripts On Save"
@@ -5761,16 +5675,15 @@ msgstr ""
#: editor/editor_settings.cpp
msgid "Auto Reload Scripts On External Change"
-msgstr ""
+msgstr "Recharger automatiquement les scripts sur changement externe"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Create Signal Callbacks"
-msgstr "Forcer les replis du shader"
+msgstr "Créer des rappels de signaux"
#: editor/editor_settings.cpp
msgid "Sort Members Outline Alphabetically"
-msgstr ""
+msgstr "Trier le contour des membres alphabétiquement"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Cursor"
@@ -5793,9 +5706,8 @@ msgid "Caret Blink Speed"
msgstr "Vitesse du clignotement du caret"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Right Click Moves Caret"
-msgstr "Clic droit pour ajouter un point"
+msgstr "Clic droit déplace le caret"
#: editor/editor_settings.cpp modules/gdscript/gdscript.cpp
#: modules/gdscript/gdscript_editor.cpp
@@ -5817,31 +5729,27 @@ msgstr "Délai d'auto-complétion du code"
#: editor/editor_settings.cpp
msgid "Put Callhint Tooltip Below Current Line"
-msgstr ""
+msgstr "Placer l'info-bulle d'appel sous la ligne actuelle"
#: editor/editor_settings.cpp
msgid "Callhint Tooltip Offset"
-msgstr ""
+msgstr "Décalage des info-bulles d'appel"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Complete File Paths"
-msgstr "Copier le chemin du nœud"
+msgstr "Compléter les chemins de fichiers"
#: editor/editor_settings.cpp modules/gdscript/gdscript_editor.cpp
-#, fuzzy
msgid "Add Type Hints"
-msgstr "Ajouter un type"
+msgstr "Ajouter des indices de type"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Use Single Quotes"
-msgstr "Nouvelle Simple Tuile"
+msgstr "Utiliser des simples guillemets"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Show Help Index"
-msgstr "Afficher les aides"
+msgstr "Afficher l'index d'aide"
#: editor/editor_settings.cpp
msgid "Help Font Size"
@@ -5852,7 +5760,6 @@ msgid "Help Source Font Size"
msgstr "Taille de la police de l'aide de la source"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Help Title Font Size"
msgstr "Taille de la police du titre Aide"
@@ -5861,9 +5768,8 @@ msgid "Grid Map"
msgstr "Grille"
#: editor/editor_settings.cpp modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "Pick Distance"
-msgstr "Choisissez distance :"
+msgstr "Choisissez la distance"
#: editor/editor_settings.cpp editor/plugins/tile_map_editor_plugin.cpp
msgid "Preview Size"
@@ -5878,32 +5784,27 @@ msgid "Secondary Grid Color"
msgstr "Couleur de la grille secondaire"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Selection Box Color"
-msgstr "Sélection uniquement"
+msgstr "Couleur de la boîte de sélection"
#: editor/editor_settings.cpp editor/plugins/path_editor_plugin.cpp
#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
-#, fuzzy
msgid "3D Gizmos"
-msgstr "Gadgets"
+msgstr "Manipulateurs 3D"
#: editor/editor_settings.cpp editor/plugins/path_editor_plugin.cpp
#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
-#, fuzzy
msgid "Gizmo Colors"
-msgstr "Couleurs d'émission"
+msgstr "Couleurs des manipulateurs"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Instanced"
-msgstr "Instance"
+msgstr "Instancié"
#: editor/editor_settings.cpp modules/gltf/gltf_node.cpp
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Joint"
-msgstr "Point"
+msgstr "Jointure"
#: editor/editor_settings.cpp scene/2d/collision_shape_2d.cpp
#: scene/2d/cpu_particles_2d.cpp scene/2d/touch_screen_button.cpp
@@ -5915,9 +5816,8 @@ msgid "Shape"
msgstr "Forme"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Primary Grid Steps"
-msgstr "Pas de la grille :"
+msgstr "Pas de la grille principale"
#: editor/editor_settings.cpp
msgid "Grid Size"
@@ -5933,55 +5833,47 @@ msgstr "Niveau minimal de division de la grille"
#: editor/editor_settings.cpp
msgid "Grid Division Level Bias"
-msgstr ""
+msgstr "Niveau de biais de la division de grille"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Grid XZ Plane"
-msgstr "Peinture GridMap"
+msgstr "Plan XZ de la grille"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Grid XY Plane"
-msgstr "Peinture GridMap"
+msgstr "Plan XY de la grille"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Grid YZ Plane"
-msgstr "Peinture GridMap"
+msgstr "Plan YZ de la grille"
#: editor/editor_settings.cpp
msgid "Default FOV"
msgstr "FOV par défaut"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Default Z Near"
-msgstr "Thème par défaut"
+msgstr "Z proche par défaut"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Default Z Far"
-msgstr "Défaut"
+msgstr "Z distant par défaut"
#: editor/editor_settings.cpp
msgid "Lightmap Baking Number Of CPU Threads"
msgstr "Nombre de fils CPU pour calculer les cartes de lumières"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Navigation Scheme"
-msgstr "Mode Navigation"
+msgstr "Schéma de navigation"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Invert Y Axis"
-msgstr "Modifier l'axe Y"
+msgstr "Inverser l'axe Y"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Invert X Axis"
-msgstr "Modifier l'axe X"
+msgstr "Inverser l'axe X"
#: editor/editor_settings.cpp
msgid "Zoom Style"
@@ -5996,14 +5888,12 @@ msgid "Emulate 3 Button Mouse"
msgstr "Émuler souris à 3 boutons"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Orbit Modifier"
-msgstr "Trier par date de modification (moins récent au plus récent)"
+msgstr "Modificateur d'orbite"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Pan Modifier"
-msgstr "Mode navigation"
+msgstr "Modificateur panoramique"
#: editor/editor_settings.cpp
msgid "Zoom Modifier"
@@ -6020,11 +5910,11 @@ msgstr "Mode Navigation"
#: editor/editor_settings.cpp
msgid "Orbit Sensitivity"
-msgstr ""
+msgstr "Sensibilité de l'orbite"
#: editor/editor_settings.cpp
msgid "Orbit Inertia"
-msgstr ""
+msgstr "Inertie de l'orbite"
#: editor/editor_settings.cpp
msgid "Translation Inertia"
@@ -6035,152 +5925,128 @@ msgid "Zoom Inertia"
msgstr "Inertie du Zoom"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook"
-msgstr "Vue libre haut"
+msgstr "Vue libre"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook Navigation Scheme"
-msgstr "Créer un maillage de navigation"
+msgstr "Schéma de navigation en vue libre"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook Sensitivity"
-msgstr "Vue libre gauche"
+msgstr "Sensibilité de la vue libre"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook Inertia"
-msgstr "Vue libre gauche"
+msgstr "Inertie de la vue libre"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook Base Speed"
-msgstr "Modificateur de vitesse de la vue libre"
+msgstr "Vitesse de base de la vue libre"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook Activation Modifier"
-msgstr "Ralentissement de la vue libre"
+msgstr "Modificateur d'activation de la vue libre"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook Speed Zoom Link"
-msgstr "Modificateur de vitesse de la vue libre"
+msgstr "Lien de zoom rapide de la vue libre"
#: editor/editor_settings.cpp editor/plugins/tile_map_editor_plugin.cpp
msgid "Grid Color"
msgstr "Couleur de la Grille"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Guides Color"
-msgstr "Prélever une couleur"
+msgstr "Couleur des guides"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Smart Snapping Line Color"
-msgstr "Magnétisme intelligent"
+msgstr "Couleur de ligne du magnétisme intelligent"
#: editor/editor_settings.cpp
msgid "Bone Width"
msgstr "Largeur des os"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Bone Color 1"
-msgstr "Renommer l'item de couleur"
+msgstr "Couleur d'os 1"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Bone Color 2"
-msgstr "Renommer l'item de couleur"
+msgstr "Couleur d'os 2"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Bone Selected Color"
-msgstr "Configurer le profil sélectionné :"
+msgstr "Couleur de l'os sélectionnée"
#: editor/editor_settings.cpp
msgid "Bone IK Color"
-msgstr ""
+msgstr "Couleur de cinématique inverse d'os"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Bone Outline Color"
-msgstr "Couleur de bordure de l'Os"
+msgstr "Couleur de contour d'os"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Bone Outline Size"
-msgstr "Taille du contour :"
+msgstr "Taille du contour de l'os"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Viewport Border Color"
msgstr "Couleur de bordure de la fenêtre d'affichage"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Constrain Editor View"
msgstr "Restreindre la fenêtre d'Éditeur"
#: editor/editor_settings.cpp
msgid "Simple Panning"
-msgstr ""
+msgstr "Panoramique simple"
#: editor/editor_settings.cpp
msgid "Scroll To Pan"
-msgstr ""
+msgstr "Panoramique au défilement"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Pan Speed"
msgstr "Vitesse Panoramique"
#: editor/editor_settings.cpp editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Poly Editor"
-msgstr "Éditeur UV de polygones 2D"
+msgstr "Éditeur de polygones"
#: editor/editor_settings.cpp
msgid "Point Grab Radius"
-msgstr ""
+msgstr "Rayon de saisie par point"
#: editor/editor_settings.cpp editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Show Previous Outline"
-msgstr "Plan précédent"
+msgstr "Montrer le contour précédent"
#: editor/editor_settings.cpp editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Autorename Animation Tracks"
-msgstr "Renommer l'animation"
+msgstr "Renommer les pistes d'animation automatiquement"
#: editor/editor_settings.cpp
msgid "Default Create Bezier Tracks"
-msgstr ""
+msgstr "Créer pistes de Bézier par défaut"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Default Create Reset Tracks"
-msgstr "Créer des pistes RESET"
+msgstr "Créer pistes de réinitialisation par défaut"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Onion Layers Past Color"
-msgstr "Couleur de couche Oignon précedente"
+msgstr "Couleur des couches d'oignon précedentes"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Onion Layers Future Color"
-msgstr "Couleur de la couche d'Oignon suivante"
+msgstr "Couleur des couches d'oignon suivantes"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Visual Editors"
-msgstr "Editeur de groupe"
+msgstr "Éditeurs visuels"
#: editor/editor_settings.cpp
msgid "Minimap Opacity"
@@ -6197,18 +6063,16 @@ msgid "Rect"
msgstr "Rect"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Rect Custom Position"
-msgstr "Définir la position de sortie de la courbe"
+msgstr "Position du Rect personnalisée"
#: editor/editor_settings.cpp platform/android/export/export_plugin.cpp
msgid "Screen"
msgstr "Écran"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Auto Save"
-msgstr "Coupe automatique"
+msgstr "Sauvegarde auto"
#: editor/editor_settings.cpp
msgid "Save Before Running"
@@ -6225,14 +6089,12 @@ msgstr "Hôte distant"
#: editor/editor_settings.cpp
#: modules/gdscript/language_server/gdscript_language_server.cpp
-#, fuzzy
msgid "Remote Port"
-msgstr "Supprimer un point"
+msgstr "Port distant"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Editor SSL Certificates"
-msgstr "Paramètres de l'éditeur"
+msgstr "Certificats SSL de l’éditeur"
#: editor/editor_settings.cpp
msgid "HTTP Proxy"
@@ -6260,7 +6122,7 @@ msgstr "Ordre de Tri"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Symbol Color"
-msgstr ""
+msgstr "Couleur de symbole"
#: editor/editor_settings.cpp
msgid "Keyword Color"
@@ -6268,29 +6130,27 @@ msgstr "Couleur des mots-clés"
#: editor/editor_settings.cpp
msgid "Control Flow Keyword Color"
-msgstr ""
+msgstr "Couleur de mot clé de contrôle de flux"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Base Type Color"
-msgstr "Changer le type de base"
+msgstr "Couleur de base des types"
#: editor/editor_settings.cpp
msgid "Engine Type Color"
-msgstr ""
+msgstr "Couleur de type du moteur"
#: editor/editor_settings.cpp
msgid "User Type Color"
-msgstr ""
+msgstr "Couleur de type utilisateur"
#: editor/editor_settings.cpp
msgid "Comment Color"
msgstr "Couleur des commentaires"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "String Color"
-msgstr "Stockage du fichier :"
+msgstr "Couleur des chaînes de caractères"
#: editor/editor_settings.cpp platform/javascript/export/export.cpp
#: platform/uwp/export/export.cpp
@@ -6299,9 +6159,8 @@ msgid "Background Color"
msgstr "Couleur d’Arrière-Plan"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Completion Background Color"
-msgstr "Couleur de fond invalide."
+msgstr "Couleur d'arrière-plan de complétion"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
#, fuzzy
@@ -6329,23 +6188,20 @@ msgid "Line Number Color"
msgstr "Couleur du Numéro de Ligne"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Safe Line Number Color"
-msgstr "Numéro de ligne :"
+msgstr "Couleur des nombres des lignes sûres"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Caret Color"
msgstr "Couleur du caret"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Caret Background Color"
-msgstr "Couleur de fond invalide."
+msgstr "Couleur d'arrière-plan de caret"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Text Selected Color"
-msgstr "Supprimer la selection"
+msgstr "Couleur de texte sélectionné"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Selection Color"
@@ -6353,7 +6209,7 @@ msgstr "Couleur de la Sélection"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Brace Mismatch Color"
-msgstr ""
+msgstr "Couleur des erreur de fermeture d'accolades"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Current Line Color"
@@ -6361,26 +6217,23 @@ msgstr "Couleur de la Ligne Actuelle"
#: editor/editor_settings.cpp
msgid "Line Length Guideline Color"
-msgstr ""
+msgstr "Couleur du guide de longueur de ligne"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Word Highlighted Color"
-msgstr "Coloration syntaxique"
+msgstr "Couleur de surlignage des mots"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Number Color"
msgstr "Couleur des nombres"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Function Color"
-msgstr "Fonction"
+msgstr "Couleur des fonctions"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Member Variable Color"
-msgstr "Renommer la variable"
+msgstr "Couleur des variables de membres"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
#, fuzzy
@@ -6388,33 +6241,28 @@ msgid "Mark Color"
msgstr "Prélever une couleur"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Bookmark Color"
-msgstr "Signets"
+msgstr "Couleur des signets"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Breakpoint Color"
-msgstr "Point d'arrêts"
+msgstr "Couleur des point d'arrêts"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Executing Line Color"
msgstr "Couleur de la ligne d’exécution"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Code Folding Color"
-msgstr ""
+msgstr "Couleur du repliage de code"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Search Result Color"
-msgstr "Résultats de recherche"
+msgstr "Couleur des résultats de recherche"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Search Result Border Color"
-msgstr "Résultats de recherche"
+msgstr "Couleur de bordure des résultats de recherche"
#: editor/editor_spin_slider.cpp
msgid "Hold %s to round to integers. Hold Shift for more precise changes."
@@ -6427,9 +6275,8 @@ msgid "Flat"
msgstr "Plat"
#: editor/editor_spin_slider.cpp
-#, fuzzy
msgid "Hide Slider"
-msgstr "Mode collision"
+msgstr "Cacher la barre de défilement"
#: editor/editor_sub_scene.cpp
msgid "Select Node(s) to Import"
@@ -6727,7 +6574,6 @@ msgstr ""
"téléchargement est terminé."
#: editor/fileserver/editor_file_server.cpp
-#, fuzzy
msgid "File Server"
msgstr "Serveur de fichiers"
@@ -7106,7 +6952,7 @@ msgstr "Collada"
#: editor/import/editor_import_collada.cpp
msgid "Use Ambient"
-msgstr ""
+msgstr "Utiliser ambiant"
#: editor/import/resource_importer_bitmask.cpp
msgid "Create From"
@@ -7115,7 +6961,7 @@ msgstr "Créer à Partir de"
#: editor/import/resource_importer_bitmask.cpp
#: servers/audio/effects/audio_effect_compressor.cpp
msgid "Threshold"
-msgstr ""
+msgstr "Seuil"
#: editor/import/resource_importer_csv_translation.cpp
#: editor/import/resource_importer_layered_texture.cpp
@@ -7127,7 +6973,7 @@ msgstr "Compresser"
#: editor/import/resource_importer_csv_translation.cpp
msgid "Delimiter"
-msgstr ""
+msgstr "Délimiteur"
#: editor/import/resource_importer_layered_texture.cpp
#, fuzzy
@@ -7165,9 +7011,8 @@ msgstr "Mipmaps"
#: editor/import/resource_importer_layered_texture.cpp
#: editor/import/resource_importer_texture.cpp
-#, fuzzy
msgid "Anisotropic"
-msgstr "Anisotropie"
+msgstr "Anisotrope"
#: editor/import/resource_importer_layered_texture.cpp
#: editor/import/resource_importer_texture.cpp
@@ -7175,9 +7020,8 @@ msgid "sRGB"
msgstr "sRGB"
#: editor/import/resource_importer_layered_texture.cpp
-#, fuzzy
msgid "Slices"
-msgstr "Coupures"
+msgstr "Tranches"
#: editor/import/resource_importer_layered_texture.cpp
#: scene/gui/aspect_ratio_container.cpp scene/gui/control.cpp
@@ -7207,7 +7051,6 @@ msgstr "Décalage du maillage"
#: editor/import/resource_importer_obj.cpp
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Octahedral Compression"
msgstr "Compression Octaédrique"
@@ -7281,9 +7124,8 @@ msgid "Storage"
msgstr "Stockage"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Use Legacy Names"
-msgstr "Utiliser des noms classiques"
+msgstr "Utiliser les noms hérités"
#: editor/import/resource_importer_scene.cpp modules/gltf/gltf_state.cpp
msgid "Materials"
@@ -7303,9 +7145,8 @@ msgid "Ensure Tangents"
msgstr "Modifier la tangente de courbes"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Light Baking"
-msgstr "Pré-calculer les cartes de lumières"
+msgstr "Pré-calculer les lumières"
#: editor/import/resource_importer_scene.cpp
msgid "Lightmap Texel Size"
@@ -7313,24 +7154,21 @@ msgstr "Taille des Texels dans la carte de lumières"
#: editor/import/resource_importer_scene.cpp modules/gltf/gltf_state.cpp
msgid "Skins"
-msgstr ""
+msgstr "Enveloppes"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Use Named Skins"
-msgstr "Utiliser le magnétisme d'échelle"
+msgstr "Utiliser les enveloppes nommées"
#: editor/import/resource_importer_scene.cpp
msgid "External Files"
msgstr "Fichiers externes"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Store In Subdir"
msgstr "Stocker dans un sous-dossier"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Filter Script"
msgstr "Filtrer les scripts"
@@ -7366,17 +7204,14 @@ msgid "Max Angular Error"
msgstr "Erreur Angulaire Max"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Max Angle"
-msgstr "Valeur"
+msgstr "Angle maximal"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Remove Unused Tracks"
-msgstr "Supprimer la piste d’animation"
+msgstr "Retirer les pistes inutilisées"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Clips"
msgstr "Clips d'animation"
@@ -7464,7 +7299,7 @@ msgstr "Mode HDR"
#: editor/import/resource_importer_texture.cpp
msgid "BPTC LDR"
-msgstr ""
+msgstr "BPTC LDR"
#: editor/import/resource_importer_texture.cpp
#: editor/plugins/tile_set_editor_plugin.cpp scene/2d/cpu_particles_2d.cpp
@@ -7482,9 +7317,8 @@ msgid "Fix Alpha Border"
msgstr "Corriger la bordure alpha"
#: editor/import/resource_importer_texture.cpp
-#, fuzzy
msgid "Premult Alpha"
-msgstr "Modifier le polygone"
+msgstr "Alpha pré-multiplié"
#: editor/import/resource_importer_texture.cpp
msgid "Hdr As Srgb"
@@ -7528,13 +7362,12 @@ msgid "Import Mode"
msgstr "Mode d'Importation"
#: editor/import/resource_importer_texture_atlas.cpp
-#, fuzzy
msgid "Crop To Region"
-msgstr "Définir la région de la tuile"
+msgstr "Rogner vers la région"
#: editor/import/resource_importer_texture_atlas.cpp
msgid "Trim Alpha Border From Region"
-msgstr ""
+msgstr "Rogner les bordures alpha de la région"
#: editor/import/resource_importer_wav.cpp scene/2d/physics_body_2d.cpp
msgid "Force"
@@ -7559,7 +7392,7 @@ msgstr "Taux maximal en Hz"
#: editor/import/resource_importer_wav.cpp
msgid "Trim"
-msgstr ""
+msgstr "Rogner"
#: editor/import/resource_importer_wav.cpp
msgid "Normalize"
@@ -7667,7 +7500,6 @@ msgid "Raw"
msgstr "Brut"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Capitalized"
msgstr "Majuscule à chaque mot"
@@ -8481,7 +8313,7 @@ msgstr "Mélange 1 :"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
msgid "X-Fade Time (s):"
-msgstr "Durée du fondu (s) :"
+msgstr "Durée du fondu croisé (s) :"
#: editor/plugins/animation_tree_player_editor_plugin.cpp
#: editor/plugins/visual_shader_editor_plugin.cpp
@@ -9722,7 +9554,6 @@ msgid "Swap GradientTexture2D Fill Points"
msgstr "Échanger les points de remplissage du GradientTexture2D"
#: editor/plugins/gradient_texture_2d_editor_plugin.cpp
-#, fuzzy
msgid "Swap Gradient Fill Points"
msgstr "Échanger les points de remplissage du dégradé"
@@ -10020,14 +9851,12 @@ msgid "Update from Scene"
msgstr "Mettre à jour depuis la scène"
#: editor/plugins/mesh_library_editor_plugin.cpp
-#, fuzzy
msgid "Apply without Transforms"
-msgstr "Appliquer la transformation du MeshInstance"
+msgstr "Appliquer sans transformations"
#: editor/plugins/mesh_library_editor_plugin.cpp
-#, fuzzy
msgid "Apply with Transforms"
-msgstr "Appliquer la transformation du MeshInstance"
+msgstr "Appliquer avec transformations"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "No mesh source specified (and no MultiMesh set in node)."
@@ -10904,9 +10733,8 @@ msgid "Exec Path"
msgstr "Chemin d'exécution"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Script Temperature Enabled"
-msgstr "Sélectionner le fichier de modèles"
+msgstr "Température de script activée"
#: editor/plugins/script_editor_plugin.cpp
msgid "Highlight Current Script"
@@ -10914,16 +10742,15 @@ msgstr "Mettre en évidence le script actuel"
#: editor/plugins/script_editor_plugin.cpp
msgid "Script Temperature History Size"
-msgstr ""
+msgstr "Taille de l'historique des températures de script"
#: editor/plugins/script_editor_plugin.cpp
msgid "Current Script Background Color"
msgstr "Couleur d'Arrière-Plan du Script Actuel"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Group Help Pages"
-msgstr "Groupe sélectionné"
+msgstr "Pages d'aide de groupe"
#: editor/plugins/script_editor_plugin.cpp
msgid "Sort Scripts By"
@@ -11756,11 +11583,11 @@ msgstr "Post"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Manipulator Gizmo Size"
-msgstr ""
+msgstr "Taille des manipulateurs"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Manipulator Gizmo Opacity"
-msgstr ""
+msgstr "Opacité des manipulateurs"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Show Viewport Rotation Gizmo"
@@ -11921,9 +11748,8 @@ msgid "New Animation"
msgstr "Nouvelle animation"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Filter animations"
-msgstr "Filtrer les méthodes"
+msgstr "Filtrer les animations"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Speed:"
@@ -12395,9 +12221,8 @@ msgid "Select Another Theme Resource:"
msgstr "Sélectionnez une autre ressource Theme :"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Theme Resource"
-msgstr "Ressource de Thème"
+msgstr "Ressource de thème"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Another Theme"
@@ -12453,9 +12278,8 @@ msgid "Add Item Type"
msgstr "Ajouter un item de type"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Set Variation Base Type"
-msgstr "Définir type de variable"
+msgstr "Définir le type parent de la variation"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Set Base Type"
@@ -12481,15 +12305,16 @@ msgstr "Surcharge tous les items de type par défaut."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select the variation base type from a list of available types."
msgstr ""
+"Choisissez le type parent de la variation depuis la liste des types "
+"disponibles."
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid ""
"A type associated with a built-in class cannot be marked as a variation of "
"another type."
msgstr ""
-"Un type affilié à une classe intégré ne peut pas être marqué comme une "
-"variante d'un autre type."
+"Un type affilié à une classe intégrée ne peut pas être marqué comme variante "
+"d'un autre type."
#: editor/plugins/theme_editor_plugin.cpp
msgid "Theme:"
@@ -12756,9 +12581,8 @@ msgid "Sort Tiles By Name"
msgstr "Trier les tuiles par nom"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Bucket Fill Preview"
-msgstr "Remplissage du seau"
+msgstr "Aperçu du remplissage"
#: editor/plugins/tile_map_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
@@ -13152,9 +12976,8 @@ msgid "Texture"
msgstr "Texture"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Tex Offset"
-msgstr "Décalage d’Octet"
+msgstr "Décalage de texture"
#: editor/plugins/tile_set_editor_plugin.cpp modules/csg/csg_shape.cpp
#: scene/2d/canvas_item.cpp scene/2d/particles_2d.cpp
@@ -13168,14 +12991,12 @@ msgid "Modulate"
msgstr "Moduler"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Tile Mode"
-msgstr "Basculer le mode"
+msgstr "Mode de tuile"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Autotile Bitmask Mode"
-msgstr "Mode Bitmask"
+msgstr "Mode de masque d'octet de tuile auto"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Subtile Size"
@@ -13206,28 +13027,24 @@ msgid "Selected Collision"
msgstr "Collision sélectionné"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Selected Collision One Way"
-msgstr "Sélection uniquement"
+msgstr "Collision à sens unique de la sélection"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Selected Collision One Way Margin"
-msgstr "Mode collision"
+msgstr "Marge de collision à sens unique de la sélection"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Selected Navigation"
msgstr "Navigation sélectionnée"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Selected Occlusion"
-msgstr "Sélectionner"
+msgstr "Occultation de la sélection"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Tileset Script"
-msgstr "Filtrer les scripts"
+msgstr "Script de palette de tuiles"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "TileSet"
@@ -14450,7 +14267,7 @@ msgstr "Plus d'informations..."
#: editor/project_export.cpp
msgid "Export PCK/Zip..."
-msgstr "Exporter le PCK/ZIP"
+msgstr "Exporter le PCK/ZIP..."
#: editor/project_export.cpp
msgid "Export Project..."
@@ -15516,7 +15333,7 @@ msgstr "Supprimer le nœud \"%s\" et ses enfants ?"
#: editor/scene_tree_dock.cpp
msgid "Delete node \"%s\"?"
-msgstr "Supprimer le noeud \"%s\" ?"
+msgstr "Supprimer le nœud \"%s\" ?"
#: editor/scene_tree_dock.cpp
msgid ""
@@ -15693,7 +15510,7 @@ msgstr "Ressources secondaires"
#: editor/scene_tree_dock.cpp
msgid "Access as Scene Unique Name"
-msgstr ""
+msgstr "Accéder en tant que nom unique de scène"
#: editor/scene_tree_dock.cpp
msgid "Clear Inheritance"
@@ -15793,18 +15610,16 @@ msgid "Clear Inheritance? (No Undo!)"
msgstr "Effacer l'héritage ? (Pas de retour en arrière !)"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Show Scene Tree Root Selection"
-msgstr "Afficher la sélection de la racine de l'arborescence"
+msgstr "Afficher la sélection de la racine de la hiérarchie de la scène"
#: editor/scene_tree_dock.cpp
msgid "Derive Script Globals By Name"
-msgstr ""
+msgstr "Dériver les Globals de scripts par nom"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Use Favorites Root Selection"
-msgstr "Encadrer la sélection"
+msgstr "Utiliser la sélection racine des favoris"
#: editor/scene_tree_editor.cpp
msgid "Toggle Visible"
@@ -16126,7 +15941,7 @@ msgstr "Filtrer les variables de la pile"
#: editor/script_editor_debugger.cpp
msgid "Auto Switch To Remote Scene Tree"
-msgstr ""
+msgstr "Basculer automatiquement vers l'arborescence de scène distante"
#: editor/script_editor_debugger.cpp
msgid "Remote Scene Tree Refresh Interval"
@@ -16134,7 +15949,7 @@ msgstr "Intervalle de rafraîchissement de l'arborescence distante"
#: editor/script_editor_debugger.cpp
msgid "Remote Inspect Refresh Interval"
-msgstr ""
+msgstr "Intervalle de rafraîchissement d'inspection distante"
#: editor/script_editor_debugger.cpp
msgid "Network Profiler"
@@ -16232,9 +16047,8 @@ msgid "Change Light Radius"
msgstr "Changer le rayon d'une lumière"
#: editor/spatial_editor_gizmos.cpp
-#, fuzzy
msgid "Stream Player 3D"
-msgstr "Émetteur de flux sonore 3D"
+msgstr "Émetteur de flux 3D"
#: editor/spatial_editor_gizmos.cpp
msgid "Change AudioStreamPlayer3D Emission Angle"
@@ -16279,9 +16093,8 @@ msgid "GI Probe"
msgstr "Sonde GI"
#: editor/spatial_editor_gizmos.cpp
-#, fuzzy
msgid "Baked Indirect Light"
-msgstr "Éclairage indirect"
+msgstr "Éclairage indirect pré-calculé"
#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
msgid "Change Sphere Shape Radius"
@@ -16320,22 +16133,20 @@ msgid "Navigation Edge Disabled"
msgstr "Bord de la Navigation Désactivé"
#: editor/spatial_editor_gizmos.cpp
-#, fuzzy
msgid "Navigation Solid"
-msgstr "Mode Navigation"
+msgstr "Solide de navigation"
#: editor/spatial_editor_gizmos.cpp
-#, fuzzy
msgid "Navigation Solid Disabled"
-msgstr "Mode Navigation"
+msgstr "Solide de navigation désactivé"
#: editor/spatial_editor_gizmos.cpp
msgid "Joint Body A"
-msgstr ""
+msgstr "Jointure Corps A"
#: editor/spatial_editor_gizmos.cpp
msgid "Joint Body B"
-msgstr ""
+msgstr "Jointure Corps B"
#: editor/spatial_editor_gizmos.cpp
msgid "Room Edge"
@@ -16343,7 +16154,7 @@ msgstr "Bord de la pièce"
#: editor/spatial_editor_gizmos.cpp
msgid "Room Overlap"
-msgstr ""
+msgstr "Chevauchement de salle"
#: editor/spatial_editor_gizmos.cpp
msgid "Set Room Point Position"
@@ -16359,7 +16170,7 @@ msgstr "Bords du portail"
#: editor/spatial_editor_gizmos.cpp
msgid "Portal Arrow"
-msgstr ""
+msgstr "Flèche de portail"
#: editor/spatial_editor_gizmos.cpp
msgid "Set Portal Point Position"
@@ -16387,44 +16198,38 @@ msgid "Set Occluder Sphere Position"
msgstr "Définir la position de la sphère de l'occulteur"
#: editor/spatial_editor_gizmos.cpp
-#, fuzzy
msgid "Set Occluder Polygon Point Position"
-msgstr "Définir la position du point du Portal"
+msgstr "Définir la position ponctuelle du polygone occulteur"
#: editor/spatial_editor_gizmos.cpp
-#, fuzzy
msgid "Set Occluder Hole Point Position"
-msgstr "Définir la position du point de la courbe"
+msgstr "Définir la position ponctuelle du trou occulteur"
#: editor/spatial_editor_gizmos.cpp
-#, fuzzy
msgid "Occluder Polygon Front"
-msgstr "Créer un polygone occulteur"
+msgstr "Avant du polygone occulteur"
#: editor/spatial_editor_gizmos.cpp
-#, fuzzy
msgid "Occluder Polygon Back"
-msgstr "Créer un polygone occulteur"
+msgstr "Arrière du polygone occulteur"
#: editor/spatial_editor_gizmos.cpp
-#, fuzzy
msgid "Occluder Hole"
-msgstr "Créer un polygone occulteur"
+msgstr "Trou occulteur"
#: main/main.cpp
msgid "Godot Physics"
-msgstr ""
+msgstr "Calculs de physique de Godot"
#: main/main.cpp servers/physics_2d/physics_2d_server_sw.cpp
#: servers/visual/visual_server_scene.cpp
msgid "Use BVH"
-msgstr ""
+msgstr "Utiliser BVH"
#: main/main.cpp servers/physics_2d/physics_2d_server_sw.cpp
#: servers/visual/visual_server_scene.cpp
-#, fuzzy
msgid "BVH Collision Margin"
-msgstr "Mode collision"
+msgstr "Marge de collision BVH"
#: main/main.cpp
msgid "Crash Handler"
@@ -16460,7 +16265,7 @@ msgstr "Maximum d'avertissements par secondes"
#: main/main.cpp
msgid "Flush stdout On Print"
-msgstr ""
+msgstr "Vider stdout à l'impression"
#: main/main.cpp servers/visual_server.cpp
msgid "Logging"
@@ -16500,11 +16305,11 @@ msgstr ""
#: main/main.cpp
msgid "DPI"
-msgstr ""
+msgstr "PPP"
#: main/main.cpp
msgid "Allow hiDPI"
-msgstr ""
+msgstr "Autoriser PPP élevé"
#: main/main.cpp
msgid "V-Sync"
@@ -16548,7 +16353,7 @@ msgstr ""
#: main/main.cpp
msgid "Handheld"
-msgstr ""
+msgstr "Portable"
#: main/main.cpp platform/javascript/export/export.cpp
#: platform/uwp/export/export.cpp
@@ -16588,7 +16393,7 @@ msgstr "Sortie Standard"
#: main/main.cpp
msgid "Print FPS"
-msgstr ""
+msgstr "Afficher les FPS"
#: main/main.cpp
msgid "Verbose stdout"
@@ -16632,7 +16437,7 @@ msgstr "Pointage"
#: main/main.cpp
msgid "Touch Delay"
-msgstr ""
+msgstr "Retard d'appui"
#: main/main.cpp servers/visual_server.cpp
msgid "GLES3"
@@ -16643,9 +16448,8 @@ msgid "Shaders"
msgstr "Shaders"
#: main/main.cpp
-#, fuzzy
msgid "Debug Shader Fallbacks"
-msgstr "Forcer les replis du shader"
+msgstr "Valeurs de repli du shader de débogage"
#: main/main.cpp scene/3d/baked_lightmap.cpp scene/3d/camera.cpp
#: scene/3d/world_environment.cpp scene/main/scene_tree.cpp
@@ -16691,7 +16495,7 @@ msgstr "Icône native de Windows"
#: main/main.cpp
msgid "Buffering"
-msgstr ""
+msgstr "Mise en mémoire tampon"
#: main/main.cpp
msgid "Agile Event Flushing"
@@ -16722,9 +16526,8 @@ msgid "Tooltip Position Offset"
msgstr "Décalage de la position des info-bulles"
#: main/main.cpp modules/mono/mono_gd/gd_mono.cpp
-#, fuzzy
msgid "Debugger Agent"
-msgstr "Débogueur"
+msgstr "Agent du débogueur"
#: main/main.cpp modules/mono/mono_gd/gd_mono.cpp
msgid "Wait For Debugger"
@@ -16736,11 +16539,11 @@ msgstr "Délai d'Attente"
#: main/main.cpp
msgid "Runtime"
-msgstr ""
+msgstr "Exécution"
#: main/main.cpp
msgid "Unhandled Exception Policy"
-msgstr ""
+msgstr "Politique d'exceptions non gérées"
#: main/main.cpp
msgid "Main Loop Type"
@@ -16764,14 +16567,12 @@ msgid "Auto Accept Quit"
msgstr "Accepter automatiquement la fermeture"
#: main/main.cpp scene/main/scene_tree.cpp
-#, fuzzy
msgid "Quit On Go Back"
-msgstr "Retourner"
+msgstr "Quitter au retour"
#: main/main.cpp scene/main/viewport.cpp
-#, fuzzy
msgid "Snap Controls To Pixels"
-msgstr "Aimanter aux flancs du nœud"
+msgstr "Aimanter les contrôles aux pixels"
#: main/main.cpp
msgid "Dynamic Fonts"
@@ -16779,7 +16580,7 @@ msgstr "Polices Dynamiques"
#: main/main.cpp
msgid "Use Oversampling"
-msgstr ""
+msgstr "Utiliser le suréchantillonnage"
#: modules/bullet/register_types.cpp modules/bullet/space_bullet.cpp
msgid "Active Soft World"
@@ -16806,35 +16607,30 @@ msgid "Change Torus Outer Radius"
msgstr "Changer le rayon extérieur de la tour"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Operation"
-msgstr "Options"
+msgstr "Opération"
#: modules/csg/csg_shape.cpp
msgid "Calculate Tangents"
msgstr "Calculer les Tangentes"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Use Collision"
-msgstr "Collision"
+msgstr "Utiliser les collisions"
#: modules/csg/csg_shape.cpp servers/physics_2d_server.cpp
-#, fuzzy
msgid "Collision Layer"
-msgstr "Mode collision"
+msgstr "Couche des collisions"
#: modules/csg/csg_shape.cpp scene/2d/ray_cast_2d.cpp scene/3d/camera.cpp
#: scene/3d/ray_cast.cpp scene/3d/spring_arm.cpp
#: scene/resources/navigation_mesh.cpp servers/physics_server.cpp
-#, fuzzy
msgid "Collision Mask"
-msgstr "Mode collision"
+msgstr "Masque de collisions"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Invert Faces"
-msgstr "Modifier la casse"
+msgstr "Inverses les faces"
#: modules/csg/csg_shape.cpp scene/2d/navigation_agent_2d.cpp
#: scene/2d/navigation_obstacle_2d.cpp scene/3d/navigation_agent.cpp
@@ -16852,57 +16648,50 @@ msgid "Radial Segments"
msgstr "Segments radiaux"
#: modules/csg/csg_shape.cpp scene/resources/primitive_meshes.cpp
-#, fuzzy
msgid "Rings"
-msgstr "Avertissements"
+msgstr "Anneaux"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Smooth Faces"
-msgstr "Progression douce"
+msgstr "Adoucir les faces"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Sides"
-msgstr "Afficher les guides"
+msgstr "Côtés"
#: modules/csg/csg_shape.cpp
msgid "Cone"
-msgstr ""
+msgstr "Cone"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Inner Radius"
-msgstr "Changer le rayon intérieur de la tour"
+msgstr "Rayon intérieur"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Outer Radius"
-msgstr "Changer le rayon extérieur de la tour"
+msgstr "Rayon extérieur"
#: modules/csg/csg_shape.cpp
msgid "Ring Sides"
-msgstr ""
+msgstr "Côtés de l'anneau"
#: modules/csg/csg_shape.cpp scene/2d/collision_polygon_2d.cpp
#: scene/2d/light_occluder_2d.cpp scene/2d/polygon_2d.cpp
#: scene/3d/collision_polygon.cpp
-#, fuzzy
msgid "Polygon"
-msgstr "Polygones"
+msgstr "Polygone"
#: modules/csg/csg_shape.cpp
msgid "Spin Degrees"
-msgstr ""
+msgstr "Degrés de tour"
#: modules/csg/csg_shape.cpp
msgid "Spin Sides"
-msgstr ""
+msgstr "Côtés du tour"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Path Node"
-msgstr "Coller les nœuds"
+msgstr "Noeud de chemin"
#: modules/csg/csg_shape.cpp
#, fuzzy
@@ -16911,35 +16700,31 @@ msgstr "Créer un vertex interne"
#: modules/csg/csg_shape.cpp
msgid "Path Interval"
-msgstr ""
+msgstr "Intervalle de chemin"
#: modules/csg/csg_shape.cpp
msgid "Path Simplify Angle"
-msgstr ""
+msgstr "Simplification d'angle de chemin"
#: modules/csg/csg_shape.cpp
msgid "Path Rotation"
msgstr "Rotation du chemin"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Path Local"
-msgstr "Rendre local"
+msgstr "Chemin local"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Path Continuous U"
-msgstr "Continu"
+msgstr "Chemin Continu U"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Path U Distance"
-msgstr "Choisissez distance :"
+msgstr "Distance du chemin U"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Path Joined"
-msgstr "Rotation aléatoire :"
+msgstr "Chemin joint"
#: modules/enet/networked_multiplayer_enet.cpp
msgid "Compression Mode"
@@ -16959,7 +16744,7 @@ msgstr "Toujours ordonnée"
#: modules/enet/networked_multiplayer_enet.cpp
msgid "Server Relay"
-msgstr ""
+msgstr "Relais serveur"
#: modules/enet/networked_multiplayer_enet.cpp
msgid "DTLS Verify"
@@ -16986,9 +16771,8 @@ msgid "Config File"
msgstr "Fichier de Configuration"
#: modules/gdnative/gdnative.cpp
-#, fuzzy
msgid "Load Once"
-msgstr "Charger une ressource"
+msgstr "Charger une fois"
#: modules/gdnative/gdnative.cpp
#: modules/visual_script/visual_script_func_nodes.cpp
@@ -17208,9 +16992,8 @@ msgid "Sparse Indices Byte Offset"
msgstr ""
#: modules/gltf/gltf_accessor.cpp
-#, fuzzy
msgid "Sparse Indices Component Type"
-msgstr "Analyse de la géométrie..."
+msgstr "Type de composant d'indices épars"
#: modules/gltf/gltf_accessor.cpp
msgid "Sparse Values Buffer View"
@@ -17284,9 +17067,8 @@ msgid "Blend Weights"
msgstr "Précalculer les lightmaps"
#: modules/gltf/gltf_mesh.cpp
-#, fuzzy
msgid "Instance Materials"
-msgstr "Changements de matériau :"
+msgstr "Matériaux d'instances"
#: modules/gltf/gltf_node.cpp scene/3d/skeleton.cpp
msgid "Parent"
@@ -17299,25 +17081,21 @@ msgstr "Plateforme"
#: modules/gltf/gltf_node.cpp scene/3d/mesh_instance.cpp
msgid "Skin"
-msgstr ""
+msgstr "Enveloppe"
#: modules/gltf/gltf_node.cpp scene/3d/spatial.cpp
-#, fuzzy
msgid "Translation"
-msgstr "Traductions"
+msgstr "Translation"
#: modules/gltf/gltf_node.cpp
-#, fuzzy
msgid "Children"
-msgstr "Enfants modifiables"
+msgstr "Enfants"
#: modules/gltf/gltf_skeleton.cpp modules/gltf/gltf_skin.cpp
-#, fuzzy
msgid "Joints"
-msgstr "Point"
+msgstr "Jointures"
#: modules/gltf/gltf_skeleton.cpp modules/gltf/gltf_skin.cpp
-#, fuzzy
msgid "Roots"
msgstr "Racines"
@@ -17326,48 +17104,42 @@ msgid "Unique Names"
msgstr "Noms Uniques"
#: modules/gltf/gltf_skeleton.cpp
-#, fuzzy
msgid "Godot Bone Node"
-msgstr "Le nœud de la scène"
+msgstr "Nœud d'os de Godot"
#: modules/gltf/gltf_skin.cpp
-#, fuzzy
msgid "Skin Root"
-msgstr "Nouvelle racine de scène"
+msgstr "Racine de l'enveloppe"
#: modules/gltf/gltf_skin.cpp
-#, fuzzy
msgid "Joints Original"
-msgstr "Focaliser l'origine"
+msgstr "Jointure à l'original"
#: modules/gltf/gltf_skin.cpp
msgid "Inverse Binds"
-msgstr ""
+msgstr "Inverser les liens"
#: modules/gltf/gltf_skin.cpp
-#, fuzzy
msgid "Non Joints"
-msgstr "Déplacer la jointure"
+msgstr "Non jointures"
#: modules/gltf/gltf_skin.cpp
msgid "Joint I To Bone I"
-msgstr ""
+msgstr "Jointure I à os I"
#: modules/gltf/gltf_skin.cpp
msgid "Joint I To Name"
-msgstr ""
+msgstr "Jointure I à nom"
#: modules/gltf/gltf_skin.cpp
msgid "Godot Skin"
-msgstr ""
+msgstr "Enveloppe Godot"
#: modules/gltf/gltf_spec_gloss.cpp
-#, fuzzy
msgid "Diffuse Img"
msgstr "Image Diffuse"
#: modules/gltf/gltf_spec_gloss.cpp
-#, fuzzy
msgid "Diffuse Factor"
msgstr "Facteur de diffusion"
@@ -17385,50 +17157,44 @@ msgstr ""
#: modules/gltf/gltf_state.cpp
msgid "Json"
-msgstr ""
+msgstr "Json"
#: modules/gltf/gltf_state.cpp
-#, fuzzy
msgid "Major Version"
-msgstr "Version"
+msgstr "Version majeure"
#: modules/gltf/gltf_state.cpp
-#, fuzzy
msgid "Minor Version"
-msgstr "Version"
+msgstr "Version mineure"
#: modules/gltf/gltf_state.cpp
-#, fuzzy
msgid "GLB Data"
-msgstr "Avec données"
+msgstr "Données GLB"
#: modules/gltf/gltf_state.cpp
msgid "Use Named Skin Binds"
-msgstr ""
+msgstr "Utiliser les liens d'enveloppe par nom"
#: modules/gltf/gltf_state.cpp
-#, fuzzy
msgid "Buffer Views"
-msgstr "Vue de derrière"
+msgstr "Vues tampon"
#: modules/gltf/gltf_state.cpp
msgid "Accessors"
-msgstr ""
+msgstr "Accesseurs"
#: modules/gltf/gltf_state.cpp
msgid "Scene Name"
msgstr "Nom de la Scène"
#: modules/gltf/gltf_state.cpp
-#, fuzzy
msgid "Root Nodes"
-msgstr "Nom de nœud racine"
+msgstr "Nœuds racines"
#: modules/gltf/gltf_state.cpp scene/2d/particles_2d.cpp
#: scene/gui/texture_button.cpp scene/gui/texture_progress.cpp
-#, fuzzy
msgid "Textures"
-msgstr "Fonctionnalités"
+msgstr "Textures"
#: modules/gltf/gltf_state.cpp platform/uwp/export/export.cpp
msgid "Images"
@@ -17439,42 +17205,36 @@ msgid "Cameras"
msgstr "Caméras"
#: modules/gltf/gltf_state.cpp servers/visual_server.cpp
-#, fuzzy
msgid "Lights"
-msgstr "Lumière"
+msgstr "Lumières"
#: modules/gltf/gltf_state.cpp
-#, fuzzy
msgid "Unique Animation Names"
-msgstr "Nom de la nouvelle animation :"
+msgstr "Noms d'animations uniques"
#: modules/gltf/gltf_state.cpp
-#, fuzzy
msgid "Skeletons"
-msgstr "Squelette"
+msgstr "Squelettes"
#: modules/gltf/gltf_state.cpp
-#, fuzzy
msgid "Skeleton To Node"
-msgstr "Sélectionner un nœud"
+msgstr "Squelette vers nœud"
#: modules/gltf/gltf_state.cpp
msgid "Animations"
msgstr "Animations"
#: modules/gltf/gltf_texture.cpp
-#, fuzzy
msgid "Src Image"
-msgstr "Afficher les os"
+msgstr "Image source"
#: modules/gridmap/grid_map.cpp
msgid "Mesh Library"
msgstr "Librairie de maillages"
#: modules/gridmap/grid_map.cpp
-#, fuzzy
msgid "Physics Material"
-msgstr "Image physique %"
+msgstr "Matériau physique"
#: modules/gridmap/grid_map.cpp scene/3d/visual_instance.cpp
#, fuzzy
@@ -17486,24 +17246,20 @@ msgid "Cell"
msgstr "Cellule"
#: modules/gridmap/grid_map.cpp
-#, fuzzy
msgid "Octant Size"
-msgstr "Vue de devant"
+msgstr "Taille d'octant"
#: modules/gridmap/grid_map.cpp
-#, fuzzy
msgid "Center X"
-msgstr "Centre"
+msgstr "X du centre"
#: modules/gridmap/grid_map.cpp
-#, fuzzy
msgid "Center Y"
-msgstr "Centre"
+msgstr "Y du centre"
#: modules/gridmap/grid_map.cpp
-#, fuzzy
msgid "Center Z"
-msgstr "Centre"
+msgstr "Z du centre"
#: modules/gridmap/grid_map.cpp scene/2d/collision_object_2d.cpp
#: scene/2d/tile_map.cpp scene/3d/collision_object.cpp scene/3d/soft_body.cpp
@@ -17512,17 +17268,15 @@ msgid "Mask"
msgstr "Masque"
#: modules/gridmap/grid_map.cpp scene/2d/tile_map.cpp
-#, fuzzy
msgid "Bake Navigation"
-msgstr "Navigation"
+msgstr "Pré-calculer la navigation"
#: modules/gridmap/grid_map.cpp scene/2d/navigation_2d.cpp
#: scene/2d/navigation_agent_2d.cpp scene/2d/navigation_polygon.cpp
#: scene/2d/tile_map.cpp scene/3d/navigation.cpp scene/3d/navigation_agent.cpp
#: scene/3d/navigation_mesh_instance.cpp
-#, fuzzy
msgid "Navigation Layers"
-msgstr "Mode Navigation"
+msgstr "Calques de navigation"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Next Plane"
@@ -17710,7 +17464,6 @@ msgid "Loop Offset"
msgstr "Décalage de Boucle"
#: modules/mobile_vr/mobile_vr_interface.cpp
-#, fuzzy
msgid "Eye Height"
msgstr "Hauteur de l’œil"
@@ -17729,15 +17482,15 @@ msgstr "Afficher sans ombrage"
#: modules/mobile_vr/mobile_vr_interface.cpp
msgid "Oversample"
-msgstr ""
+msgstr "Suréchantillonner"
#: modules/mobile_vr/mobile_vr_interface.cpp
msgid "K1"
-msgstr ""
+msgstr "K1"
#: modules/mobile_vr/mobile_vr_interface.cpp
msgid "K2"
-msgstr ""
+msgstr "K2"
#: modules/mono/csharp_script.cpp
msgid "Class name can't be a reserved keyword"
@@ -17824,14 +17577,13 @@ msgstr "C'est fait !"
#: modules/opensimplex/noise_texture.cpp
msgid "Seamless"
-msgstr ""
+msgstr "Sans bord"
#: modules/opensimplex/noise_texture.cpp
msgid "As Normal Map"
msgstr "En tant que carte de normales"
#: modules/opensimplex/noise_texture.cpp
-#, fuzzy
msgid "Bump Strength"
msgstr "Force du bossage"
@@ -17840,12 +17592,10 @@ msgid "Noise"
msgstr "Bruit"
#: modules/opensimplex/noise_texture.cpp
-#, fuzzy
msgid "Noise Offset"
-msgstr "Décalage de la grille :"
+msgstr "Décalage du bruit"
#: modules/opensimplex/open_simplex_noise.cpp
-#, fuzzy
msgid "Octaves"
msgstr "Octaves"
@@ -17854,28 +17604,24 @@ msgid "Period"
msgstr "Période"
#: modules/opensimplex/open_simplex_noise.cpp
-#, fuzzy
msgid "Persistence"
-msgstr "Perspective"
+msgstr "Persistance"
#: modules/opensimplex/open_simplex_noise.cpp
msgid "Lacunarity"
-msgstr ""
+msgstr "Lacunarité"
#: modules/regex/regex.cpp
-#, fuzzy
msgid "Subject"
msgstr "Sujet"
#: modules/regex/regex.cpp
-#, fuzzy
msgid "Names"
-msgstr "Nom"
+msgstr "Noms"
#: modules/regex/regex.cpp
-#, fuzzy
msgid "Strings"
-msgstr "Paramètres :"
+msgstr "Paramètres"
#: modules/upnp/upnp.cpp
msgid "Discover Multicast If"
@@ -17883,39 +17629,35 @@ msgstr ""
#: modules/upnp/upnp.cpp
msgid "Discover Local Port"
-msgstr ""
+msgstr "Révéler le port local"
#: modules/upnp/upnp.cpp
msgid "Discover IPv6"
msgstr "Découvrir IPv6"
#: modules/upnp/upnp_device.cpp
-#, fuzzy
msgid "Description URL"
-msgstr "Description"
+msgstr "URL de description"
#: modules/upnp/upnp_device.cpp
-#, fuzzy
msgid "Service Type"
-msgstr "Définir type de variable"
+msgstr "Type du service"
#: modules/upnp/upnp_device.cpp
msgid "IGD Control URL"
-msgstr ""
+msgstr "URL de contrôle IGD"
#: modules/upnp/upnp_device.cpp
-#, fuzzy
msgid "IGD Service Type"
-msgstr "Définir type de variable"
+msgstr "Type de service IGD"
#: modules/upnp/upnp_device.cpp
msgid "IGD Our Addr"
msgstr ""
#: modules/upnp/upnp_device.cpp
-#, fuzzy
msgid "IGD Status"
-msgstr "État"
+msgstr "État IGD"
#: modules/visual_script/visual_script.cpp
msgid ""
@@ -17956,9 +17698,8 @@ msgid "Stack overflow with stack depth:"
msgstr "Débordement de pile avec profondeur de pile :"
#: modules/visual_script/visual_script.cpp
-#, fuzzy
msgid "Visual Script"
-msgstr "Rechercher VisualScript"
+msgstr "Script graphique"
#: modules/visual_script/visual_script_editor.cpp
msgid "Change Signal Arguments"
@@ -18294,9 +18035,8 @@ msgid "Return Enabled"
msgstr "Exécutable"
#: modules/visual_script/visual_script_flow_control.cpp
-#, fuzzy
msgid "Return Type"
-msgstr "Retour"
+msgstr "Type de retour"
#: modules/visual_script/visual_script_flow_control.cpp
#: scene/resources/visual_shader_nodes.cpp
@@ -18344,7 +18084,6 @@ msgid "in order:"
msgstr "dans l'ordre :"
#: modules/visual_script/visual_script_flow_control.cpp
-#, fuzzy
msgid "Steps"
msgstr "Pas"
@@ -18366,9 +18105,8 @@ msgstr "Est-ce %s ?"
#: modules/visual_script/visual_script_flow_control.cpp
#: modules/visual_script/visual_script_func_nodes.cpp
-#, fuzzy
msgid "Base Script"
-msgstr "Nouveau script"
+msgstr "Script de base"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "On %s"
@@ -18380,36 +18118,31 @@ msgstr "On Self"
#: modules/visual_script/visual_script_func_nodes.cpp
#: modules/visual_script/visual_script_yield_nodes.cpp
-#, fuzzy
msgid "Call Mode"
-msgstr "Mode mise à l'échelle"
+msgstr "Mode d'appel"
#: modules/visual_script/visual_script_func_nodes.cpp
#: modules/visual_script/visual_script_nodes.cpp
-#, fuzzy
msgid "Basic Type"
-msgstr "Changer le type de base"
+msgstr "Type simple"
#: modules/visual_script/visual_script_func_nodes.cpp
#: modules/visual_script/visual_script_nodes.cpp
#: modules/visual_script/visual_script_yield_nodes.cpp
-#, fuzzy
msgid "Node Path"
-msgstr "Copier le chemin du nœud"
+msgstr "Chemin de nœud"
#: modules/visual_script/visual_script_func_nodes.cpp
-#, fuzzy
msgid "Use Default Args"
-msgstr "Réinitialiser"
+msgstr "Utiliser les valeurs d'arguments par défaut"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "Validate"
msgstr "Valider"
#: modules/visual_script/visual_script_func_nodes.cpp
-#, fuzzy
msgid "RPC Call Mode"
-msgstr "Mode mise à l'échelle"
+msgstr "Mode d'appel RPC"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "Subtract %s"
@@ -18448,14 +18181,12 @@ msgid "BitXor %s"
msgstr "Ou-exclusif par bit %s"
#: modules/visual_script/visual_script_func_nodes.cpp
-#, fuzzy
msgid "Set Mode"
-msgstr "Mode sélection"
+msgstr "Définir le mode"
#: modules/visual_script/visual_script_func_nodes.cpp
-#, fuzzy
msgid "Assign Op"
-msgstr "Assigner"
+msgstr "Opérateur d'assignation"
#: modules/visual_script/visual_script_func_nodes.cpp
#: modules/visual_script/visual_script_nodes.cpp
@@ -18472,9 +18203,8 @@ msgid "Base object is not a Node!"
msgstr "L'objet de base n'est pas un nœud !"
#: modules/visual_script/visual_script_func_nodes.cpp
-#, fuzzy
msgid "Path does not lead to Node!"
-msgstr "Le chemin ne mène pas au nœud !"
+msgstr "Le chemin ne mène pas vers un nœud !"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "Invalid index property name '%s' in node %s."
@@ -18490,9 +18220,8 @@ msgstr "Composer le tableau"
#: modules/visual_script/visual_script_nodes.cpp scene/resources/material.cpp
#: scene/resources/visual_shader_nodes.cpp
-#, fuzzy
msgid "Operator"
-msgstr "Itérateur"
+msgstr "Opérateur"
#: modules/visual_script/visual_script_nodes.cpp
msgid "Invalid argument of type:"
@@ -18507,9 +18236,8 @@ msgid "a if cond, else b"
msgstr "a if cond, else b"
#: modules/visual_script/visual_script_nodes.cpp
-#, fuzzy
msgid "Var Name"
-msgstr "Nom"
+msgstr "Nom de variable"
#: modules/visual_script/visual_script_nodes.cpp
msgid "VariableGet not found in script:"
@@ -18634,9 +18362,8 @@ msgid "%s sec(s)"
msgstr "%s seconde(s)"
#: modules/visual_script/visual_script_yield_nodes.cpp scene/main/timer.cpp
-#, fuzzy
msgid "Wait Time"
-msgstr "Peindre la tuile"
+msgstr "Temps d'attente"
#: modules/visual_script/visual_script_yield_nodes.cpp
msgid "WaitSignal"
@@ -18651,16 +18378,14 @@ msgid "WaitInstanceSignal"
msgstr "WaitInstanceSignal"
#: modules/webrtc/webrtc_data_channel.cpp
-#, fuzzy
msgid "Write Mode"
-msgstr "Mode prioritaire"
+msgstr "Mode écriture"
#: modules/webrtc/webrtc_data_channel.h
msgid "WebRTC"
msgstr "WebRTC"
#: modules/webrtc/webrtc_data_channel.h
-#, fuzzy
msgid "Max Channel In Buffer (KB)"
msgstr "Maximum de canal dans le tampon (Ko)"
@@ -18673,61 +18398,52 @@ msgid "Trusted SSL Certificate"
msgstr "Certificat SSL Fiable"
#: modules/websocket/websocket_macros.h
-#, fuzzy
msgid "WebSocket Client"
-msgstr "Profileur réseau"
+msgstr "Client WebSocket"
#: modules/websocket/websocket_macros.h
-#, fuzzy
msgid "Max In Buffer (KB)"
-msgstr "Taille Maximale (KB)"
+msgstr "Maximum tampon entrant (KB)"
#: modules/websocket/websocket_macros.h
-#, fuzzy
msgid "Max In Packets"
-msgstr "Maximum par paquet"
+msgstr "Maximum de paquets entrant"
#: modules/websocket/websocket_macros.h
-#, fuzzy
msgid "Max Out Buffer (KB)"
-msgstr "Taille Maximale (KB)"
+msgstr "Maximum tampon sortant (KB)"
#: modules/websocket/websocket_macros.h
msgid "Max Out Packets"
-msgstr ""
+msgstr "Maximum de paquets sortant"
#: modules/websocket/websocket_macros.h
-#, fuzzy
msgid "WebSocket Server"
-msgstr "Profileur réseau"
+msgstr "Server WebSocket"
#: modules/websocket/websocket_server.cpp
msgid "Bind IP"
-msgstr ""
+msgstr "Lier IP"
#: modules/websocket/websocket_server.cpp
-#, fuzzy
msgid "Private Key"
-msgstr "Chemin de la clé privée SSH"
+msgstr "Clé privée"
#: modules/websocket/websocket_server.cpp platform/javascript/export/export.cpp
msgid "SSL Certificate"
msgstr "Certificat SSL"
#: modules/websocket/websocket_server.cpp
-#, fuzzy
msgid "CA Chain"
-msgstr "Effacer la chaîne IK"
+msgstr "Chaîne d’autorité de certificat (CA)"
#: modules/websocket/websocket_server.cpp
-#, fuzzy
msgid "Handshake Timeout"
-msgstr "Délai dépassé."
+msgstr "Délai de poignée de main expiré"
#: modules/webxr/webxr_interface.cpp
-#, fuzzy
msgid "Session Mode"
-msgstr "Mode Région"
+msgstr "Mode de session"
#: modules/webxr/webxr_interface.cpp
msgid "Required Features"
@@ -18742,18 +18458,17 @@ msgid "Requested Reference Space Types"
msgstr ""
#: modules/webxr/webxr_interface.cpp
+#, fuzzy
msgid "Reference Space Type"
-msgstr ""
+msgstr "Type de référentiel spatial"
#: modules/webxr/webxr_interface.cpp
-#, fuzzy
msgid "Visibility State"
-msgstr "Basculer la visibilité"
+msgstr "État de la visibilité"
#: modules/webxr/webxr_interface.cpp
-#, fuzzy
msgid "Bounds Geometry"
-msgstr "Réessayer"
+msgstr "Géométrie des limites"
#: modules/webxr/webxr_interface.cpp
#, fuzzy
@@ -18779,14 +18494,13 @@ msgstr ""
#: platform/android/export/export.cpp
msgid "Force System User"
-msgstr ""
+msgstr "Forcer l'utilisateur système"
#: platform/android/export/export.cpp
msgid "Shutdown ADB On Exit"
-msgstr ""
+msgstr "Fermer ADB à la sortie"
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "Launcher Icons"
msgstr "Icônes du lanceur"
@@ -18861,27 +18575,22 @@ msgid "Keystore"
msgstr "Débogueur"
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "Debug User"
-msgstr "Débogueur"
+msgstr "Utilisateur de débogage"
#: platform/android/export/export_plugin.cpp platform/uwp/export/export.cpp
-#, fuzzy
msgid "Debug Password"
-msgstr "Mot de passe"
+msgstr "Mot de passe de débogage"
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "Release User"
-msgstr "Publication (release)"
+msgstr "Utilisateur de publication (release)"
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "Release Password"
-msgstr "Mot de passe"
+msgstr "Mot de passe de publication"
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "One Click Deploy"
msgstr "Déploiement en un clic"
@@ -18894,18 +18603,16 @@ msgid "Code"
msgstr "Code"
#: platform/android/export/export_plugin.cpp platform/uwp/export/export.cpp
-#, fuzzy
msgid "Package"
-msgstr "Empaquetage"
+msgstr "Paquetage"
#: platform/android/export/export_plugin.cpp platform/uwp/export/export.cpp
msgid "Unique Name"
msgstr "Nom unique"
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "Signed"
-msgstr "Signaux"
+msgstr "Signé"
#: platform/android/export/export_plugin.cpp
msgid "Classify As Game"
@@ -18916,9 +18623,8 @@ msgid "Retain Data On Uninstall"
msgstr "Conserver les données lors de la désinstallation"
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "Exclude From Recents"
-msgstr "Supprimer des nœuds"
+msgstr "Exclure des récents"
#: platform/android/export/export_plugin.cpp
msgid "Graphics"
@@ -18937,17 +18643,16 @@ msgid "XR Mode"
msgstr "Mode XR"
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "Hand Tracking"
-msgstr "Empaquetage"
+msgstr "Suivi des mains"
#: platform/android/export/export_plugin.cpp
msgid "Hand Tracking Frequency"
-msgstr ""
+msgstr "Fréquence de suivi des mains"
#: platform/android/export/export_plugin.cpp
msgid "Passthrough"
-msgstr ""
+msgstr "Relais"
#: platform/android/export/export_plugin.cpp
msgid "Immersive Mode"
@@ -18974,9 +18679,8 @@ msgid "Support Xlarge"
msgstr "Support"
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "User Data Backup"
-msgstr "Interface utilisateur"
+msgstr "Sauvegarde(backup) des données utilisateur"
#: platform/android/export/export_plugin.cpp
msgid "Allow"
@@ -19209,20 +18913,17 @@ msgstr ""
#: platform/android/export/export_plugin.cpp platform/osx/export/export.cpp
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Code Signing"
-msgstr "Signaux"
+msgstr "Signature du code"
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid ""
"'apksigner' could not be found. Please check that the command is available "
"in the Android SDK build-tools directory. The resulting %s is unsigned."
msgstr ""
-"Impossible de trouver 'apksigner'.\n"
-"Veuillez vérifier que la commande est disponible dans le dossier build-tools "
-"du SDK Android.\n"
-"Le paquet sortant %s est non signé."
+"Impossible de trouver 'apksigner'. Veuillez vérifier que la commande est "
+"disponible dans le dossier build-tools du SDK Android. Le %s resultant n'est "
+"pas signé."
#: platform/android/export/export_plugin.cpp
msgid "Signing debug %s..."
@@ -19237,9 +18938,8 @@ msgid "Could not find keystore, unable to export."
msgstr "Impossible de trouver le keystore, impossible d'exporter."
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "Could not start apksigner executable."
-msgstr "Impossible de démarrer le sous-processus !"
+msgstr "Impossible de le programme apksigner."
#: platform/android/export/export_plugin.cpp
msgid "'apksigner' returned with error #%d"
@@ -19276,9 +18976,8 @@ msgstr ""
"*.apk."
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "Unsupported export format!"
-msgstr "Format d'export non supporté !\n"
+msgstr "Format d'export non supporté !"
#: platform/android/export/export_plugin.cpp
msgid ""
@@ -19290,28 +18989,24 @@ msgstr ""
"menu 'Projet'."
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid ""
"Android build version mismatch: Template installed: %s, Godot version: %s. "
"Please reinstall Android build template from 'Project' menu."
msgstr ""
-"La version d'Android ne correspond pas :\n"
-" Modèle installé : %s\n"
-" Version Godot : %s\n"
-"Veuillez réinstaller la version d'Android depuis le menu 'Projet'."
+"La version compilée d'Android ne correspond pas : Modèle type installé : %s, "
+"Version de Godot : %s. Veuillez réinstaller le modèle type de compilation "
+"d'Android depuis le menu 'Projet'."
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid ""
"Unable to overwrite res://android/build/res/*.xml files with project name."
msgstr ""
"Impossible d'écraser les fichiers res://android/build/res/*.xml avec le nom "
-"du projet"
+"du projet."
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "Could not export project files to gradle project."
-msgstr "Impossible d'exporter les fichiers du projet vers le projet gradle\n"
+msgstr "Impossible d'exporter les fichiers du projet vers le projet gradle."
#: platform/android/export/export_plugin.cpp
msgid "Could not write expansion package file!"
@@ -19322,15 +19017,13 @@ msgid "Building Android Project (gradle)"
msgstr "Construire le Project Android (gradle)"
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid ""
"Building of Android project failed, check output for the error. "
"Alternatively visit docs.godotengine.org for Android build documentation."
msgstr ""
"La construction du projet Android a échoué, vérifiez la sortie pour "
-"l'erreur.\n"
-"Sinon, visitez docs.godotengine.org pour la documentation de construction "
-"Android."
+"l'erreur. Sinon, visitez docs.godotengine.org pour la documentation de "
+"construction Android."
#: platform/android/export/export_plugin.cpp
msgid "Moving output"
@@ -19345,41 +19038,38 @@ msgstr ""
"du projet gradle pour les journaux."
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "Package not found: \"%s\"."
-msgstr "Paquet non trouvé : %s"
+msgstr "Paquet non trouvé : \"%s\"."
#: platform/android/export/export_plugin.cpp
msgid "Creating APK..."
msgstr "Création de l'APK..."
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "Could not find template APK to export: \"%s\"."
msgstr ""
-"Impossible de trouver le modèle de l'APK à exporter :\n"
-"%s"
+"La construction du projet Android a échoué, vérifiez la sortie pour "
+"l'erreur. Sinon, visitez docs.godotengine.org pour la documentation de "
+"construction Android."
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid ""
"Missing libraries in the export template for the selected architectures: %s. "
"Please build a template with all required libraries, or uncheck the missing "
"architectures in the export preset."
msgstr ""
"Bibliothèques manquantes dans le modèle d'exportation pour les architectures "
-"sélectionnées : %s.\n"
-"Veuillez construire un modèle avec toutes les bibliothèques requises, ou "
-"désélectionner les architectures manquantes dans le préréglage d'exportation."
+"sélectionnées : %s. Veuillez construire un modèle avec toutes les "
+"bibliothèques requises, ou désélectionner les architectures manquantes dans "
+"le préréglage d'exportation."
#: platform/android/export/export_plugin.cpp
msgid "Adding files..."
msgstr "Ajout de fichiers..."
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "Could not export project files."
-msgstr "Impossible d'exporter les fichiers du projet"
+msgstr "Impossible d'exporter les fichiers du projet."
#: platform/android/export/export_plugin.cpp
msgid "Aligning APK..."
@@ -19419,7 +19109,7 @@ msgstr "iPad 2048 X 1536"
#: platform/iphone/export/export.cpp
msgid "Portrait Launch Screens"
-msgstr ""
+msgstr "Écrans de lancement en mode portrait"
#: platform/iphone/export/export.cpp
msgid "iPhone 640 X 960"
@@ -19451,38 +19141,35 @@ msgstr "iPhone 1242 X 2208"
#: platform/iphone/export/export.cpp
msgid "App Store Team ID"
-msgstr ""
+msgstr "ID de groupe de l'App Store"
#: platform/iphone/export/export.cpp
msgid "Provisioning Profile UUID Debug"
-msgstr ""
+msgstr "UUID de provisionnement de profils en débogage"
#: platform/iphone/export/export.cpp
msgid "Code Sign Identity Debug"
-msgstr ""
+msgstr "Identité de signature de code en débogage"
#: platform/iphone/export/export.cpp
-#, fuzzy
msgid "Export Method Debug"
-msgstr "Exporter avec debug"
+msgstr "Méthode d'exportation en débogage"
#: platform/iphone/export/export.cpp
msgid "Provisioning Profile UUID Release"
-msgstr ""
+msgstr "UUID de provisionnement de profils en publication"
#: platform/iphone/export/export.cpp
msgid "Code Sign Identity Release"
-msgstr ""
+msgstr "Identité de signature de code en publication"
#: platform/iphone/export/export.cpp
-#, fuzzy
msgid "Export Method Release"
-msgstr "Mode d'exportation :"
+msgstr "Méthode d'exportation en publication"
#: platform/iphone/export/export.cpp
-#, fuzzy
msgid "Targeted Device Family"
-msgstr "Famille de système cible"
+msgstr "Famille de système ciblée"
#: platform/iphone/export/export.cpp platform/osx/export/export.cpp
msgid "Info"
@@ -19514,9 +19201,8 @@ msgid "Access Wi-Fi"
msgstr "Accès Wi-Fi"
#: platform/iphone/export/export.cpp
-#, fuzzy
msgid "Push Notifications"
-msgstr "Rotation aléatoire :"
+msgstr "Notifications Push"
#: platform/iphone/export/export.cpp
msgid "User Data"
@@ -19524,33 +19210,29 @@ msgstr "Données Utilisateur"
#: platform/iphone/export/export.cpp
msgid "Accessible From Files App"
-msgstr ""
+msgstr "Accessible depuis l'application Files"
#: platform/iphone/export/export.cpp
msgid "Accessible From iTunes Sharing"
-msgstr ""
+msgstr "Accessible depuis le partage iTunes"
#: platform/iphone/export/export.cpp platform/osx/export/export.cpp
msgid "Privacy"
msgstr "Confidentialité"
#: platform/iphone/export/export.cpp platform/osx/export/export.cpp
-#, fuzzy
msgid "Camera Usage Description"
-msgstr "Description"
+msgstr "Description d'utilisation de la caméra"
#: platform/iphone/export/export.cpp platform/osx/export/export.cpp
-#, fuzzy
msgid "Microphone Usage Description"
-msgstr "Description des propriétés"
+msgstr "Description d'utilisation du microphone"
#: platform/iphone/export/export.cpp
-#, fuzzy
msgid "Photolibrary Usage Description"
-msgstr "Description des propriétés"
+msgstr "Description d'utilisation de la bibliothèque d'image"
#: platform/iphone/export/export.cpp
-#, fuzzy
msgid "iPhone 120 X 120"
msgstr "iPhone 120 X 120"
@@ -19568,19 +19250,19 @@ msgstr "iPad 152 X 152"
#: platform/iphone/export/export.cpp
msgid "iPad 167 X 167"
-msgstr ""
+msgstr "iPad 167 X 167"
#: platform/iphone/export/export.cpp
msgid "App Store 1024 X 1024"
-msgstr ""
+msgstr "App Store 1024 X 1024"
#: platform/iphone/export/export.cpp
msgid "Spotlight 40 X 40"
-msgstr ""
+msgstr "Projecteur 40 X 40"
#: platform/iphone/export/export.cpp
msgid "Spotlight 80 X 80"
-msgstr ""
+msgstr "Projecteur 80 X 80"
#: platform/iphone/export/export.cpp
msgid "Storyboard"
@@ -19591,19 +19273,16 @@ msgid "Use Launch Screen Storyboard"
msgstr ""
#: platform/iphone/export/export.cpp
-#, fuzzy
msgid "Image Scale Mode"
-msgstr "Mode mise à l'échelle"
+msgstr "Mode de mise à l'échelle d'image"
#: platform/iphone/export/export.cpp
-#, fuzzy
msgid "Custom Image @2x"
-msgstr "Nœud Personnalisé"
+msgstr "Image personnalisée @2x"
#: platform/iphone/export/export.cpp
-#, fuzzy
msgid "Custom Image @3x"
-msgstr "Nœud Personnalisé"
+msgstr "Image personnalisée @3x"
#: platform/iphone/export/export.cpp
msgid "Use Custom BG Color"
@@ -19704,7 +19383,7 @@ msgstr ""
#: platform/javascript/export/export.cpp
msgid "Canvas Resize Policy"
-msgstr ""
+msgstr "Politique de redimensionnement du canevas"
#: platform/javascript/export/export.cpp
msgid "Focus Canvas On Start"
@@ -19803,18 +19482,16 @@ msgid "Already signed!"
msgstr "Déjà signé !"
#: platform/osx/export/codesign.cpp
-#, fuzzy
msgid "Failed to process nested resources."
-msgstr "Impossible de charger la ressource."
+msgstr "Le traitement des ressources imbriquées a échoué."
#: platform/osx/export/codesign.cpp
msgid "Failed to create _CodeSignature subfolder."
msgstr "Échec lors de la création du sous-dossier _CodeSignature."
#: platform/osx/export/codesign.cpp
-#, fuzzy
msgid "Failed to get CodeResources hash."
-msgstr "Impossible de charger la ressource."
+msgstr "La récupération du hachage de CodeResources a échouée."
#: platform/osx/export/codesign.cpp platform/osx/export/export.cpp
#, fuzzy
@@ -19826,7 +19503,6 @@ msgid "Invalid executable file."
msgstr "Fichier exécutable invalide."
#: platform/osx/export/codesign.cpp
-#, fuzzy
msgid "Can't resize signature load command."
msgstr "Impossible de redimensionner la commande de chargement des signatures."
@@ -19847,75 +19523,65 @@ msgid "App Category"
msgstr "Catégorie de l'application"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "High Res"
msgstr "Haute Résolution"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Location Usage Description"
-msgstr "Description"
+msgstr "Description d'utilisation de la géolocalisation"
#: platform/osx/export/export.cpp
msgid "Address Book Usage Description"
-msgstr ""
+msgstr "Description d'utilisation du carnet d'adresse"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Calendar Usage Description"
-msgstr "Description"
+msgstr "Description d'utilisation du calendrier"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Photos Library Usage Description"
-msgstr "Description des propriétés"
+msgstr "Description d'utilisation de la bibliothèque photo"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Desktop Folder Usage Description"
-msgstr "Descriptions des méthodes"
+msgstr "Description d'utilisation du dossier Bureau"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Documents Folder Usage Description"
-msgstr "Descriptions des méthodes"
+msgstr "Description d'utilisation du dossier Documents"
#: platform/osx/export/export.cpp
msgid "Downloads Folder Usage Description"
-msgstr ""
+msgstr "Description d'utilisation du dossier Téléchargements"
#: platform/osx/export/export.cpp
msgid "Network Volumes Usage Description"
-msgstr ""
+msgstr "Description d'utilisation des disques réseau"
#: platform/osx/export/export.cpp
msgid "Removable Volumes Usage Description"
-msgstr ""
+msgstr "Description d'utilisation des disques amovibles"
#: platform/osx/export/export.cpp platform/windows/export/export.cpp
-#, fuzzy
msgid "Codesign"
-msgstr "Nœud"
+msgstr "Signature du code"
#: platform/osx/export/export.cpp platform/uwp/export/export.cpp
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Identity"
-msgstr "Indenter vers la gauche"
+msgstr "Identité"
#: platform/osx/export/export.cpp platform/windows/export/export.cpp
-#, fuzzy
msgid "Timestamp"
-msgstr "Temps"
+msgstr "Horodatage"
#: platform/osx/export/export.cpp
msgid "Hardened Runtime"
msgstr ""
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Replace Existing Signature"
-msgstr "Remplacer dans les fichiers"
+msgstr "Remplacer la signature existante"
#: platform/osx/export/export.cpp
#, fuzzy
@@ -19923,9 +19589,8 @@ msgid "Entitlements"
msgstr "Gadgets"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Custom File"
-msgstr "Nœud Personnalisé"
+msgstr "Fichier personnalisé"
#: platform/osx/export/export.cpp
msgid "Allow JIT Code Execution"
@@ -19960,43 +19625,37 @@ msgid "Photos Library"
msgstr "Bibliothèque de photos"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Apple Events"
-msgstr "Ajouter évènement"
+msgstr "Événements Apple"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Debugging"
msgstr "Débogage"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "App Sandbox"
msgstr "Bac à sable de l'application"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Network Server"
-msgstr "Profileur réseau"
+msgstr "Serveur réseau"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Network Client"
-msgstr "Profileur réseau"
+msgstr "Client réseau"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Device USB"
-msgstr "Périphérique"
+msgstr "Périphérique USB"
#: platform/osx/export/export.cpp
msgid "Device Bluetooth"
-msgstr ""
+msgstr "Périphérique Bluetooth"
#: platform/osx/export/export.cpp
#, fuzzy
msgid "Files Downloads"
-msgstr "Télécharger"
+msgstr "Téléchargement de fichiers"
#: platform/osx/export/export.cpp
#, fuzzy
@@ -20014,9 +19673,8 @@ msgid "Files Movies"
msgstr "Filtrer les tuiles"
#: platform/osx/export/export.cpp platform/windows/export/export.cpp
-#, fuzzy
msgid "Custom Options"
-msgstr "Options de bus"
+msgstr "Options personnalisées"
#: platform/osx/export/export.cpp
#, fuzzy
@@ -20025,31 +19683,27 @@ msgstr "Localisation"
#: platform/osx/export/export.cpp
msgid "Apple ID Name"
-msgstr ""
+msgstr "Nom Apple ID"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Apple ID Password"
-msgstr "Mot de passe"
+msgstr "Mot de passe Apple ID"
#: platform/osx/export/export.cpp
msgid "Apple Team ID"
msgstr "Apple Team ID"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Could not open icon file \"%s\"."
-msgstr "Impossible d'exporter les fichiers du projet"
+msgstr "Impossible d'ouvrir le fichier d'icône \"%s\"."
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Could not start xcrun executable."
-msgstr "Impossible de démarrer le sous-processus !"
+msgstr "Impossible de démarrer le sous-processus."
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Notarization failed."
-msgstr "Localisation"
+msgstr "Notarisation échouée."
#: platform/osx/export/export.cpp
msgid "Notarization request UUID: \"%s\""
@@ -20082,6 +19736,8 @@ msgstr ""
#: platform/osx/export/export.cpp
msgid "Timestamping is not compatible with ad-hoc signature, and was disabled!"
msgstr ""
+"L'horodatage n'est pas compatible avec la signature ad-hoc et a été "
+"désactivé !"
#: platform/osx/export/export.cpp
msgid ""
@@ -20094,7 +19750,7 @@ msgstr ""
#: platform/osx/export/export.cpp
msgid "Built-in CodeSign require regex module."
-msgstr ""
+msgstr "CodeSign intégré nécessite le module regex."
#: platform/osx/export/export.cpp
msgid ""
@@ -20109,9 +19765,8 @@ msgid "No identity found."
msgstr "Aucune identité trouvée."
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Cannot sign file %s."
-msgstr "Erreur lors de l'enregistrement du fichier : %s"
+msgstr "Impossible de signer le fichier %s."
#: platform/osx/export/export.cpp
msgid "Relative symlinks are not supported, exported \"%s\" might be broken!"
@@ -20120,17 +19775,14 @@ msgstr ""
"cassé !"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "DMG Creation"
-msgstr "Directions"
+msgstr "Création du DMG"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Could not start hdiutil executable."
-msgstr "Impossible de démarrer le sous-processus !"
+msgstr "Impossible de démarrer le programme hdiutil."
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "`hdiutil create` failed - file exists."
msgstr "`hdiutil create` a échoué - le fichier existe."
@@ -20139,19 +19791,16 @@ msgid "`hdiutil create` failed."
msgstr "`hdiutil create` a échoué."
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Creating app bundle"
-msgstr "Création de l'aperçu"
+msgstr "Création du paquet d'application"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Could not find template app to export: \"%s\"."
-msgstr "Impossible de trouver le modèle de l'application à exporter :"
+msgstr "Impossible de trouver le modèle de l'application à exporter : \"%s\"."
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Invalid export format."
-msgstr "Modèle d'exportation non valide :"
+msgstr "Format d'export invalide."
#: platform/osx/export/export.cpp
msgid ""
@@ -20178,10 +19827,13 @@ msgid ""
"Ad-hoc signed applications require the 'Disable Library Validation' "
"entitlement to load dynamic libraries."
msgstr ""
+"La signature d'applications ad-hoc nécessite la permission \"Désactiver la "
+"validation de bibliothèque\" pour pouvoir charger dynamiquement les "
+"bibliothèques."
#: platform/osx/export/export.cpp
msgid "Code signing bundle"
-msgstr ""
+msgstr "Paquet de signature du code"
#: platform/osx/export/export.cpp
msgid "Making DMG"
@@ -20189,7 +19841,7 @@ msgstr "Création du DMG"
#: platform/osx/export/export.cpp
msgid "Code signing DMG"
-msgstr ""
+msgstr "DMG de signature du code"
#: platform/osx/export/export.cpp
msgid "Making ZIP"
@@ -20208,14 +19860,12 @@ msgid "Sending archive for notarization"
msgstr "Envoi de l'archive pour la certification"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "ZIP Creation"
-msgstr "Projet"
+msgstr "Création ZIP"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Could not open file to read from path \"%s\"."
-msgstr "Impossible d'exporter les fichiers du projet vers le projet gradle\n"
+msgstr "Impossible d'ouvrir le fichier à lire au chemin \"%s\"."
#: platform/osx/export/export.cpp
msgid "Invalid bundle identifier:"
@@ -20245,14 +19895,13 @@ msgstr ""
"supporté."
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Notarization: Code signing is required for notarization."
-msgstr "Certification : signature du code requise."
+msgstr ""
+"Notarisation : La signature du code est nécessaire pour la notarisation."
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Notarization: Hardened runtime is required for notarization."
-msgstr "Certification : exécution renforcée requise."
+msgstr "Notarisation : exécution renforcée nécessaire pour la notarisation."
#: platform/osx/export/export.cpp
#, fuzzy
@@ -20294,6 +19943,8 @@ msgstr ""
msgid ""
"Timestamping is not compatible with ad-hoc signature, and will be disabled!"
msgstr ""
+"L'horodatage n'est pas compatible avec la signature ad-hoc et a été "
+"désactivé !"
#: platform/osx/export/export.cpp
msgid ""
@@ -20356,17 +20007,15 @@ msgstr "macOS"
#: platform/osx/export/export.cpp
msgid "Force Builtin Codesign"
-msgstr ""
+msgstr "Forcer CodeSign intégré"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Architecture"
-msgstr "Ajouter une entrée architecture"
+msgstr "Architecture"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Display Name"
-msgstr "Tout afficher"
+msgstr "Afficher le nom"
#: platform/uwp/export/export.cpp
msgid "Short Name"
@@ -20374,36 +20023,31 @@ msgstr "Nom Abrégé"
#: platform/uwp/export/export.cpp
msgid "Publisher"
-msgstr ""
+msgstr "Publicateur"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Publisher Display Name"
-msgstr "Nom d'affichage d'éditeur du paquet invalide."
+msgstr "Nom d'affichage de l'éditeur du paquet"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Product GUID"
-msgstr "GUID produit invalide."
+msgstr "GUID du produit"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Publisher GUID"
-msgstr "Effacé Guides"
+msgstr "GUID du publicateur"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Signing"
-msgstr "Signaux"
+msgstr "Signature"
#: platform/uwp/export/export.cpp
msgid "Certificate"
msgstr "Certificat"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Algorithm"
-msgstr "Débogueur"
+msgstr "Algorithme"
#: platform/uwp/export/export.cpp
msgid "Major"
@@ -20414,23 +20058,20 @@ msgid "Minor"
msgstr "Mineur"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Build"
-msgstr "Mode Règle"
+msgstr "Build"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Revision"
-msgstr "Expression"
+msgstr "Révision"
#: platform/uwp/export/export.cpp
msgid "Landscape"
msgstr "Paysage"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Portrait"
-msgstr "Retourner les Portals"
+msgstr "Portrait"
#: platform/uwp/export/export.cpp
msgid "Landscape Flipped"
@@ -20441,9 +20082,8 @@ msgid "Portrait Flipped"
msgstr "Portrait Inversé"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Store Logo"
-msgstr "Mode mise à l'échelle"
+msgstr "Logo du magasin"
#: platform/uwp/export/export.cpp
msgid "Square 44 X 44 Logo"
@@ -20466,14 +20106,12 @@ msgid "Wide 310 X 150 Logo"
msgstr "Logo 310 X 150 Large"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Splash Screen"
-msgstr "Appels de dessin :"
+msgstr "Écran de chargement"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Tiles"
-msgstr "Fichier"
+msgstr "Tuiles"
#: platform/uwp/export/export.cpp
msgid "Show Name On Square 150 X 150"
@@ -20557,32 +20195,28 @@ msgid "UWP"
msgstr "UWP"
#: platform/uwp/export/export.cpp platform/windows/export/export.cpp
-#, fuzzy
msgid "Signtool"
-msgstr "Signaux"
+msgstr "Signtool"
#: platform/uwp/export/export.cpp
msgid "Debug Certificate"
msgstr "Certificat de Débogage"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Debug Algorithm"
-msgstr "Débogueur"
+msgstr "Algorithme de débogage"
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Failed to rename temporary file \"%s\"."
-msgstr "Impossible de supprimer le fichier temporaire :"
+msgstr "Impossible de renommer le fichier temporaire \"%s\"."
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Identity Type"
msgstr "Type d'identité"
#: platform/windows/export/export.cpp
msgid "Timestamp Server URL"
-msgstr ""
+msgstr "URL du serveur d'horodatage"
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20590,14 +20224,12 @@ msgid "Digest Algorithm"
msgstr "Débogueur"
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Modify Resources"
-msgstr "Copier la ressource"
+msgstr "Modifier les ressources"
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "File Version"
-msgstr "Version"
+msgstr "Version de fichier"
#: platform/windows/export/export.cpp
msgid "Product Version"
@@ -20612,18 +20244,16 @@ msgid "Product Name"
msgstr "Nom du produit"
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "File Description"
-msgstr "Description"
+msgstr "Description de fichier"
#: platform/windows/export/export.cpp
msgid "Trademarks"
msgstr "Marques Déposées"
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Resources Modification"
-msgstr "Rotation aléatoire :"
+msgstr "Modification de ressources"
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20638,61 +20268,52 @@ msgstr "Impossible de trouver le keystore, impossible d'exporter."
#: platform/windows/export/export.cpp
#, fuzzy
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
"L'outil « rcedit » doit être configuré dans les préférences de l'éditeur "
"(Exporter > Windows > Rcedit) for modifier l'icône ou les informations de "
"l'application."
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
-"rcedit n'a pas réussi à modifier l'exécutable :\n"
-"%s"
+msgid "rcedit failed to modify executable: %s."
+msgstr "rcedit n'a pas réussi à modifier l'exécutable : %s."
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Could not find signtool executable at \"%s\"."
-msgstr "Impossible de trouver le keystore, impossible d'exporter."
+msgstr "Impossible de trouver l’exécutable signtool à \"%s\"."
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Could not find osslsigncode executable at \"%s\"."
-msgstr "Impossible de trouver le keystore, impossible d'exporter."
+msgstr "Impossible de trouver l’exécutable osslsigncode à \"%s\"."
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Invalid identity type."
-msgstr "Identifiant invalide :"
+msgstr "Type d'identité invalide."
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Invalid timestamp server."
-msgstr "Nom invalide."
+msgstr "Server d'horodatage invalide."
#: platform/windows/export/export.cpp
#, fuzzy
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
"L'outil « rcedit » doit être configuré dans les préférences de l'éditeur "
"(Exporter > Windows > Rcedit) for modifier l'icône ou les informations de "
"l'application."
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+msgid "Signtool failed to sign executable: %s."
+msgstr "La signature de l’exécutable avec Signtool a échoué : %s."
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Failed to remove temporary file \"%s\"."
-msgstr "Impossible de supprimer le fichier temporaire :"
+msgstr "Impossible de supprimer le fichier temporaire \"%s\"."
#: platform/windows/export/export.cpp
msgid ""
@@ -20717,7 +20338,7 @@ msgstr "Version du produit invalide :"
#: platform/windows/export/export.cpp
msgid "Windows executables cannot be >= 4 GiB."
-msgstr ""
+msgstr "Les exécutables Windows ne peuvent pas peser >= 4Gio."
#: platform/windows/export/export.cpp platform/x11/export/export.cpp
#, fuzzy
@@ -20726,38 +20347,37 @@ msgstr "Fichier exécutable invalide."
#: platform/windows/export/export.cpp platform/x11/export/export.cpp
msgid "Executable file header corrupted."
-msgstr ""
+msgstr "Entête du fichier exécutable corrompue."
#: platform/windows/export/export.cpp platform/x11/export/export.cpp
msgid "Executable \"pck\" section not found."
-msgstr ""
+msgstr "Section \"pck\" de l’exécutable non trouvée."
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Windows"
-msgstr "Nouvelle Fenêtre"
+msgstr "Windows"
#: platform/windows/export/export.cpp
msgid "Rcedit"
-msgstr ""
+msgstr "Rcedit"
#: platform/windows/export/export.cpp
msgid "Osslsigncode"
-msgstr ""
+msgstr "Osslsigncode"
#: platform/windows/export/export.cpp
msgid "Wine"
-msgstr ""
+msgstr "Wine"
#: platform/x11/export/export.cpp
msgid "32-bit executables cannot have embedded data >= 4 GiB."
msgstr ""
+"les exécutables 32 bits ne peuvent pas contenir de données pesant >= 4Gio."
#: scene/2d/animated_sprite.cpp scene/3d/sprite_3d.cpp
#: scene/resources/texture.cpp
-#, fuzzy
msgid "Frames"
-msgstr "Image %"
+msgstr "Trames"
#: scene/2d/animated_sprite.cpp
msgid ""
@@ -20769,71 +20389,61 @@ msgstr ""
#: scene/2d/animated_sprite.cpp scene/2d/cpu_particles_2d.cpp
#: scene/2d/particles_2d.cpp scene/3d/cpu_particles.cpp scene/3d/particles.cpp
-#, fuzzy
msgid "Speed Scale"
-msgstr "Mode mise à l'échelle"
+msgstr "Échelle de vitesse"
#: scene/2d/animated_sprite.cpp scene/2d/audio_stream_player_2d.cpp
#: scene/3d/audio_stream_player_3d.cpp scene/3d/sprite_3d.cpp
#: scene/audio/audio_stream_player.cpp
-#, fuzzy
msgid "Playing"
-msgstr "Jouer"
+msgstr "En train de jouer"
#: scene/2d/animated_sprite.cpp scene/2d/sprite.cpp scene/3d/sprite_3d.cpp
-#, fuzzy
msgid "Centered"
-msgstr "Centre"
+msgstr "Centré"
#: scene/2d/animated_sprite.cpp scene/2d/sprite.cpp scene/3d/sprite_3d.cpp
#: scene/gui/texture_button.cpp scene/gui/texture_rect.cpp
msgid "Flip H"
-msgstr ""
+msgstr "Miroir H"
#: scene/2d/animated_sprite.cpp scene/2d/sprite.cpp scene/3d/sprite_3d.cpp
#: scene/gui/texture_button.cpp scene/gui/texture_rect.cpp
msgid "Flip V"
-msgstr ""
+msgstr "Miroir V"
#: scene/2d/area_2d.cpp scene/3d/area.cpp
-#, fuzzy
msgid "Monitoring"
-msgstr "Moniteur"
+msgstr "Observation"
#: scene/2d/area_2d.cpp scene/3d/area.cpp
-#, fuzzy
msgid "Monitorable"
-msgstr "Moniteur"
+msgstr "Observable"
#: scene/2d/area_2d.cpp scene/3d/area.cpp
-#, fuzzy
msgid "Physics Overrides"
-msgstr "Redéfinition"
+msgstr "Redéfinitions de physique"
#: scene/2d/area_2d.cpp scene/3d/area.cpp
-#, fuzzy
msgid "Space Override"
-msgstr "Redéfinition"
+msgstr "Redéfinition d'espace"
#: scene/2d/area_2d.cpp scene/3d/area.cpp
-#, fuzzy
msgid "Gravity Point"
-msgstr "Générer des points"
+msgstr "Gravité ponctuelle"
#: scene/2d/area_2d.cpp scene/3d/area.cpp
-#, fuzzy
msgid "Gravity Distance Scale"
-msgstr "WaitInstanceSignal"
+msgstr "Échelle de distance de gravité"
#: scene/2d/area_2d.cpp scene/3d/area.cpp
-#, fuzzy
msgid "Gravity Vec"
-msgstr "Aperçu par défaut"
+msgstr "Vecteur de gravité"
#: scene/2d/area_2d.cpp scene/2d/cpu_particles_2d.cpp scene/3d/area.cpp
#: scene/3d/cpu_particles.cpp scene/resources/particles_material.cpp
msgid "Gravity"
-msgstr ""
+msgstr "Gravité"
#: scene/2d/area_2d.cpp scene/3d/area.cpp
#, fuzzy
@@ -20845,38 +20455,33 @@ msgid "Angular Damp"
msgstr ""
#: scene/2d/area_2d.cpp scene/3d/area.cpp
-#, fuzzy
msgid "Audio Bus"
-msgstr "Ajouter un bus audio"
+msgstr "Bus audio"
#: scene/2d/area_2d.cpp scene/3d/area.cpp
-#, fuzzy
msgid "Override"
msgstr "Redéfinition"
#: scene/2d/audio_stream_player_2d.cpp scene/audio/audio_stream_player.cpp
#: scene/gui/video_player.cpp servers/audio/effects/audio_effect_amplify.cpp
-#, fuzzy
msgid "Volume dB"
-msgstr "Volume"
+msgstr "Volume (dB)"
#: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp
#: scene/audio/audio_stream_player.cpp
#: servers/audio/effects/audio_effect_pitch_shift.cpp
-#, fuzzy
msgid "Pitch Scale"
-msgstr "Mode mise à l'échelle"
+msgstr "Échelle de pitch"
#: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp
#: scene/audio/audio_stream_player.cpp scene/gui/video_player.cpp
-#, fuzzy
msgid "Autoplay"
-msgstr "Activer/désactiver la lecture automatique"
+msgstr "Lecture automatique"
#: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp
#: scene/audio/audio_stream_player.cpp
msgid "Stream Paused"
-msgstr ""
+msgstr "Diffusion en pause"
#: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp
#: scene/3d/light.cpp scene/3d/reflection_probe.cpp
@@ -20886,34 +20491,29 @@ msgid "Max Distance"
msgstr "Distance Maximale"
#: scene/2d/audio_stream_player_2d.cpp scene/3d/light.cpp
-#, fuzzy
msgid "Attenuation"
-msgstr "Animation"
+msgstr "Atténuation"
#: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp
#: scene/audio/audio_stream_player.cpp scene/gui/video_player.cpp
-#, fuzzy
msgid "Bus"
-msgstr "Ajouter un bus"
+msgstr "Bus"
#: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp
msgid "Area Mask"
-msgstr ""
+msgstr "Masque de zone"
#: scene/2d/back_buffer_copy.cpp
-#, fuzzy
msgid "Copy Mode"
-msgstr "Copier les nœuds"
+msgstr "Mode copie"
#: scene/2d/camera_2d.cpp
-#, fuzzy
msgid "Anchor Mode"
-msgstr "Mode Icône"
+msgstr "Mode ancre"
#: scene/2d/camera_2d.cpp
-#, fuzzy
msgid "Rotating"
-msgstr "Pas de la rotation :"
+msgstr "En rotation"
#: scene/2d/camera_2d.cpp scene/2d/listener_2d.cpp scene/3d/camera.cpp
#: scene/3d/listener.cpp scene/animation/animation_blend_tree.cpp
@@ -20921,14 +20521,12 @@ msgid "Current"
msgstr "Actuel"
#: scene/2d/camera_2d.cpp scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Zoom"
msgstr "Zoomer"
#: scene/2d/camera_2d.cpp scene/main/canvas_layer.cpp
-#, fuzzy
msgid "Custom Viewport"
-msgstr "1 vue"
+msgstr "Vue personnalisée"
#: scene/2d/camera_2d.cpp scene/3d/camera.cpp scene/3d/interpolated_camera.cpp
#: scene/animation/animation_player.cpp scene/animation/animation_tree.cpp
@@ -20939,26 +20537,23 @@ msgstr "Mode déplacement"
#: scene/2d/camera_2d.cpp
msgid "Limit"
-msgstr ""
+msgstr "Limite"
#: scene/2d/camera_2d.cpp scene/gui/control.cpp scene/gui/nine_patch_rect.cpp
#: scene/resources/style_box.cpp scene/resources/texture.cpp
-#, fuzzy
msgid "Left"
-msgstr "En haut à gauche"
+msgstr "Gauche"
#: scene/2d/camera_2d.cpp scene/gui/control.cpp scene/gui/nine_patch_rect.cpp
#: scene/resources/style_box.cpp scene/resources/texture.cpp
-#, fuzzy
msgid "Right"
-msgstr "Lumière"
+msgstr "Droite"
#: scene/2d/camera_2d.cpp scene/gui/control.cpp scene/gui/nine_patch_rect.cpp
#: scene/resources/dynamic_font.cpp scene/resources/style_box.cpp
#: scene/resources/texture.cpp
-#, fuzzy
msgid "Bottom"
-msgstr "En bas à gauche"
+msgstr "Bas"
#: scene/2d/camera_2d.cpp
#, fuzzy
@@ -20966,9 +20561,8 @@ msgid "Smoothed"
msgstr "Progression douce"
#: scene/2d/camera_2d.cpp
-#, fuzzy
msgid "Draw Margin"
-msgstr "Définir la marge"
+msgstr "Afficher les marges"
#: scene/2d/camera_2d.cpp
#, fuzzy
@@ -20987,27 +20581,24 @@ msgstr "Progression douce"
#: scene/2d/camera_2d.cpp
msgid "H"
-msgstr ""
+msgstr "H"
#: scene/2d/camera_2d.cpp
-#, fuzzy
msgid "V"
-msgstr "UV"
+msgstr "V"
#: scene/2d/camera_2d.cpp
#, fuzzy
msgid "Drag Margin"
-msgstr "Définir la marge"
+msgstr "Tirer la marge"
#: scene/2d/camera_2d.cpp
-#, fuzzy
msgid "Draw Screen"
-msgstr "Appels de dessin :"
+msgstr "Afficher l'écran"
#: scene/2d/camera_2d.cpp
-#, fuzzy
msgid "Draw Limits"
-msgstr "Appels de dessin :"
+msgstr "Afficher les limites"
#: scene/2d/camera_2d.cpp
#, fuzzy
@@ -21016,43 +20607,37 @@ msgstr "Définir la marge"
#: scene/2d/canvas_item.cpp scene/resources/environment.cpp
#: scene/resources/material.cpp
-#, fuzzy
msgid "Blend Mode"
-msgstr "Nœud Blend2"
+msgstr "Mode mélange"
#: scene/2d/canvas_item.cpp
-#, fuzzy
msgid "Light Mode"
-msgstr "Étendu à Droite"
+msgstr "Mode de lumière"
#: scene/2d/canvas_item.cpp
-#, fuzzy
msgid "Particles Animation"
-msgstr "Particules"
+msgstr "Animation de particules"
#: scene/2d/canvas_item.cpp
msgid "Particles Anim H Frames"
-msgstr ""
+msgstr "Trames d'animation H de particules"
#: scene/2d/canvas_item.cpp
msgid "Particles Anim V Frames"
-msgstr ""
+msgstr "Trames d'animation V de particules"
#: scene/2d/canvas_item.cpp
-#, fuzzy
msgid "Particles Anim Loop"
-msgstr "Particules"
+msgstr "Boucle d'animation de particules"
#: scene/2d/canvas_item.cpp scene/3d/spatial.cpp
-#, fuzzy
msgid "Visibility"
-msgstr "Basculer la visibilité"
+msgstr "Visibilité"
#: scene/2d/canvas_item.cpp scene/3d/spatial.cpp scene/gui/progress_bar.cpp
#: scene/gui/rich_text_effect.cpp scene/main/canvas_layer.cpp
-#, fuzzy
msgid "Visible"
-msgstr "Basculer la visibilité"
+msgstr "Visible"
#: scene/2d/canvas_item.cpp
#, fuzzy
@@ -21061,22 +20646,20 @@ msgstr "Peupler"
#: scene/2d/canvas_item.cpp
msgid "Show Behind Parent"
-msgstr ""
+msgstr "Montrer derrière le parent"
#: scene/2d/canvas_item.cpp
-#, fuzzy
msgid "Show On Top"
-msgstr "Afficher l'origine"
+msgstr "Montrer au dessus"
#: scene/2d/canvas_item.cpp scene/2d/light_occluder_2d.cpp
#: scene/2d/tile_map.cpp
-#, fuzzy
msgid "Light Mask"
-msgstr "LightMap Bake"
+msgstr "Masque de lumières"
#: scene/2d/canvas_item.cpp
msgid "Use Parent Material"
-msgstr ""
+msgstr "Utiliser le matériau du parent"
#: scene/2d/canvas_modulate.cpp
msgid ""
@@ -21098,9 +20681,8 @@ msgstr ""
"qu'enfant pour définir sa forme."
#: scene/2d/collision_object_2d.cpp
-#, fuzzy
msgid "Pickable"
-msgstr "Sélectionner une tuile"
+msgstr "Déplaçable"
#: scene/2d/collision_polygon_2d.cpp
msgid ""
@@ -21132,29 +20714,27 @@ msgstr ""
msgid ""
"The One Way Collision property will be ignored when the parent is an Area2D."
msgstr ""
+"La propriété Collision à sens unique est ignorée lorsque le parent est un "
+"Area2D."
#: scene/2d/collision_polygon_2d.cpp
-#, fuzzy
msgid "Build Mode"
-msgstr "Mode Règle"
+msgstr "Mode construction"
#: scene/2d/collision_polygon_2d.cpp scene/2d/collision_shape_2d.cpp
#: scene/3d/collision_polygon.cpp scene/3d/collision_shape.cpp
#: scene/animation/animation_node_state_machine.cpp scene/gui/base_button.cpp
#: scene/gui/texture_button.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Disabled"
-msgstr "Item désactivé"
+msgstr "Désactivé"
#: scene/2d/collision_polygon_2d.cpp scene/2d/collision_shape_2d.cpp
-#, fuzzy
msgid "One Way Collision"
-msgstr "Créer le polygone de collision"
+msgstr "Collision à sens unique"
#: scene/2d/collision_polygon_2d.cpp scene/2d/collision_shape_2d.cpp
-#, fuzzy
msgid "One Way Collision Margin"
-msgstr "Créer le polygone de collision"
+msgstr "marge de collision à sens unique"
#: scene/2d/collision_shape_2d.cpp
msgid ""
@@ -21193,31 +20773,28 @@ msgstr ""
#: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/particles.cpp
-#, fuzzy
msgid "Emitting"
-msgstr "Paramètres :"
+msgstr "Émet"
#: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/particles.cpp
msgid "Lifetime"
-msgstr ""
+msgstr "Durée de vie"
#: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/particles.cpp scene/main/timer.cpp
-#, fuzzy
msgid "One Shot"
-msgstr "Nœud one-shot"
+msgstr "Jouer une fois"
#: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/particles.cpp
-#, fuzzy
msgid "Preprocess"
-msgstr "Post-traitement"
+msgstr "Pré-traitement"
#: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/particles.cpp
msgid "Explosiveness"
-msgstr ""
+msgstr "Explovisité"
#: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/particles.cpp
@@ -21227,13 +20804,12 @@ msgstr "Aléatoire"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
msgid "Lifetime Randomness"
-msgstr ""
+msgstr "Aléatoire de durée de vie"
#: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/particles.cpp
-#, fuzzy
msgid "Fixed FPS"
-msgstr "Voir Images par secondes"
+msgstr "FPS fixes"
#: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/particles.cpp
@@ -21247,20 +20823,18 @@ msgstr ""
#: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/particles.cpp
-#, fuzzy
msgid "Local Coords"
-msgstr "Projets locaux"
+msgstr "Coordonnées locales"
#: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/particles.cpp
msgid "Draw Order"
-msgstr ""
+msgstr "Ordre de rendu"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Emission Shape"
-msgstr "Masque d'émission"
+msgstr "Forme d'émission"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
@@ -21273,63 +20847,55 @@ msgid "Rect Extents"
msgstr "Gadgets"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
-#, fuzzy
msgid "Normals"
-msgstr "Format"
+msgstr "Normales"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Align Y"
-msgstr "Assigner"
+msgstr "Aligner axe Y"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Direction"
-msgstr "Directions"
+msgstr "Direction"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
#: servers/audio/effects/audio_effect_reverb.cpp
msgid "Spread"
-msgstr ""
+msgstr "Propagation"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Initial Velocity"
-msgstr "Initialiser"
+msgstr "Vélocité initiale"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Velocity Random"
-msgstr "Vue de l'orbite vers la droite"
+msgstr "Vélocité aléatoire"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp servers/physics_2d_server.cpp
#: servers/physics_server.cpp
msgid "Angular Velocity"
-msgstr ""
+msgstr "Vélocité angulaire"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Velocity Curve"
-msgstr "Vue de l'orbite vers la droite"
+msgstr "Courbe de vélocité"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Orbit Velocity"
-msgstr "Vue de l'orbite vers la droite"
+msgstr "Vélocité d'orbite"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Linear Accel"
-msgstr "Linéaire"
+msgstr "Accélération linéaire"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
@@ -21339,23 +20905,22 @@ msgstr "Accel"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
msgid "Accel Random"
-msgstr ""
+msgstr "Accélération aléatoire"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Accel Curve"
-msgstr "Scinder la courbe"
+msgstr "Courbe d’accélération"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
msgid "Radial Accel"
-msgstr ""
+msgstr "Accélération radiale"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
msgid "Tangential Accel"
-msgstr ""
+msgstr "Accélération tangentielle"
#: scene/2d/cpu_particles_2d.cpp scene/2d/joints_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/physics_body.cpp
@@ -21363,39 +20928,37 @@ msgstr ""
#: scene/resources/particles_material.cpp
#: servers/audio/effects/audio_effect_reverb.cpp
msgid "Damping"
-msgstr ""
+msgstr "Amortissement"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
msgid "Damping Random"
-msgstr ""
+msgstr "Amortissement aléatoire"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Damping Curve"
-msgstr "Scinder la courbe"
+msgstr "Courbe d'amortissement"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp scene/3d/light.cpp
#: scene/resources/particles_material.cpp
msgid "Angle"
-msgstr ""
+msgstr "Angle"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
msgid "Angle Random"
-msgstr ""
+msgstr "Angle aléatoire"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Angle Curve"
-msgstr "Fermer la courbe"
+msgstr "Courbe d'angle"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#, fuzzy
msgid "Scale Amount"
-msgstr "Quantité :"
+msgstr "Valeur d'échelle"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
msgid "Scale Amount Random"
@@ -21408,14 +20971,13 @@ msgstr "Agrandir/Rétrécir à partir du curseur"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Color Ramp"
-msgstr "Couleurs"
+msgstr "Dégradé de couleurs"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
msgid "Color Initial Ramp"
-msgstr ""
+msgstr "Dégradé de couleurs initial"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
@@ -21434,33 +20996,28 @@ msgstr "Variation aléatoire"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Variation Curve"
-msgstr "Séparation :"
+msgstr "Courbe de variation"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Speed Random"
-msgstr "Mode mise à l'échelle"
+msgstr "Vitesse aléatoire"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Speed Curve"
-msgstr "Scinder la courbe"
+msgstr "Courbe de vitesse"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Offset Random"
-msgstr "Décalage :"
+msgstr "Décalage de l'aléatoire"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Offset Curve"
-msgstr "Fermer la courbe"
+msgstr "Courbe de décalage"
#: scene/2d/joints_2d.cpp
msgid "Node A and Node B must be PhysicsBody2Ds"
@@ -21483,25 +21040,22 @@ msgid "Node A and Node B must be different PhysicsBody2Ds"
msgstr "Node A et Node B doivent être des PhysicsBody2D différents"
#: scene/2d/joints_2d.cpp scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Node A"
-msgstr "Nœud"
+msgstr "Nœud A"
#: scene/2d/joints_2d.cpp scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Node B"
-msgstr "Nœud"
+msgstr "Nœud B"
#: scene/2d/joints_2d.cpp scene/3d/baked_lightmap.cpp scene/3d/gi_probe.cpp
#: scene/3d/light.cpp scene/3d/physics_body.cpp scene/3d/physics_joint.cpp
#: scene/resources/environment.cpp
msgid "Bias"
-msgstr ""
+msgstr "Biais"
#: scene/2d/joints_2d.cpp
-#, fuzzy
msgid "Disable Collision"
-msgstr "Bouton désactivé"
+msgstr "Désactiver les collisions"
#: scene/2d/joints_2d.cpp scene/3d/physics_body.cpp scene/3d/physics_joint.cpp
msgid "Softness"
@@ -21513,9 +21067,8 @@ msgid "Length"
msgstr "Longueur"
#: scene/2d/joints_2d.cpp
-#, fuzzy
msgid "Initial Offset"
-msgstr "Initialiser"
+msgstr "Décalage initial"
#: scene/2d/joints_2d.cpp scene/3d/vehicle_body.cpp
msgid "Rest Length"
@@ -21534,14 +21087,12 @@ msgstr ""
"« Texture »."
#: scene/2d/light_2d.cpp scene/3d/light.cpp scene/gui/reference_rect.cpp
-#, fuzzy
msgid "Editor Only"
-msgstr "Éditeur"
+msgstr "Éditeur seulement"
#: scene/2d/light_2d.cpp
-#, fuzzy
msgid "Texture Scale"
-msgstr "RegionDeTexture"
+msgstr "Échelle de texture"
#: scene/2d/light_2d.cpp scene/3d/baked_lightmap.cpp scene/3d/gi_probe.cpp
#: scene/3d/light.cpp scene/resources/environment.cpp
@@ -21558,33 +21109,28 @@ msgid "Z Max"
msgstr "Maximum Z"
#: scene/2d/light_2d.cpp
-#, fuzzy
msgid "Layer Min"
-msgstr "Changer la taille d'une caméra"
+msgstr "Calque min"
#: scene/2d/light_2d.cpp
-#, fuzzy
msgid "Layer Max"
-msgstr "Calque"
+msgstr "Calque max"
#: scene/2d/light_2d.cpp
msgid "Item Cull Mask"
msgstr ""
#: scene/2d/light_2d.cpp scene/3d/light.cpp scene/resources/style_box.cpp
-#, fuzzy
msgid "Shadow"
-msgstr "Ombrage"
+msgstr "Ombre"
#: scene/2d/light_2d.cpp
-#, fuzzy
msgid "Buffer Size"
-msgstr "Vue de derrière"
+msgstr "Taille de tampon"
#: scene/2d/light_2d.cpp
-#, fuzzy
msgid "Gradient Length"
-msgstr "Dégradé édité"
+msgstr "Longueur du dégradé"
#: scene/2d/light_2d.cpp
#, fuzzy
@@ -21592,9 +21138,8 @@ msgid "Filter Smooth"
msgstr "Filtrer les méthodes"
#: scene/2d/light_occluder_2d.cpp
-#, fuzzy
msgid "Closed"
-msgstr "Fermer"
+msgstr "Fermé"
#: scene/2d/light_occluder_2d.cpp scene/resources/material.cpp
#, fuzzy
@@ -21615,38 +21160,32 @@ msgstr ""
"polygone."
#: scene/2d/line_2d.cpp
-#, fuzzy
msgid "Width Curve"
-msgstr "Scinder la courbe"
+msgstr "Courbe de largeur"
#: scene/2d/line_2d.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Default Color"
-msgstr "Défaut"
+msgstr "Couleur par défaut"
#: scene/2d/line_2d.cpp scene/resources/texture.cpp
msgid "Fill"
msgstr "Remplissage"
#: scene/2d/line_2d.cpp scene/resources/texture.cpp
-#, fuzzy
msgid "Gradient"
-msgstr "Dégradé édité"
+msgstr "Dégradé"
#: scene/2d/line_2d.cpp
-#, fuzzy
msgid "Texture Mode"
-msgstr "RegionDeTexture"
+msgstr "Mode de texture"
#: scene/2d/line_2d.cpp
-#, fuzzy
msgid "Capping"
-msgstr "Recouvrement"
+msgstr "Capuchonnement"
#: scene/2d/line_2d.cpp
-#, fuzzy
msgid "Joint Mode"
-msgstr "Mode Icône"
+msgstr "Mode de jointure"
#: scene/2d/line_2d.cpp
#, fuzzy
@@ -21654,14 +21193,12 @@ msgid "Begin Cap Mode"
msgstr "Mode Région"
#: scene/2d/line_2d.cpp
-#, fuzzy
msgid "End Cap Mode"
-msgstr "Mode d'aimantation :"
+msgstr "Mode du capuchon de fin"
#: scene/2d/line_2d.cpp scene/2d/polygon_2d.cpp scene/resources/style_box.cpp
-#, fuzzy
msgid "Border"
-msgstr "dans l'ordre :"
+msgstr "Bordure"
#: scene/2d/line_2d.cpp
msgid "Sharp Limit"
@@ -21673,9 +21210,8 @@ msgstr "Précision de l’arrondissement"
#: scene/2d/line_2d.cpp scene/2d/polygon_2d.cpp
#: scene/resources/dynamic_font.cpp
-#, fuzzy
msgid "Antialiased"
-msgstr "Initialiser"
+msgstr "Anticrénelé"
#: scene/2d/multimesh_instance_2d.cpp scene/3d/multimesh_instance.cpp
#, fuzzy
@@ -21689,9 +21225,8 @@ msgid "Cell Size"
msgstr "Taille des Cellules"
#: scene/2d/navigation_2d.cpp scene/3d/navigation.cpp
-#, fuzzy
msgid "Edge Connection Margin"
-msgstr "Modifier la connexion :"
+msgstr "Marge de connexion des bords"
#: scene/2d/navigation_2d.cpp
msgid ""
@@ -21706,31 +21241,27 @@ msgstr ""
#: scene/2d/navigation_agent_2d.cpp scene/3d/navigation_agent.cpp
#, fuzzy
msgid "Pathfinding"
-msgstr "Liaison"
+msgstr "Pathfinding"
#: scene/2d/navigation_agent_2d.cpp scene/3d/navigation_agent.cpp
-#, fuzzy
msgid "Path Desired Distance"
-msgstr "Choisissez distance :"
+msgstr "Distance souhaitée du chemin"
#: scene/2d/navigation_agent_2d.cpp scene/3d/navigation_agent.cpp
msgid "Target Desired Distance"
msgstr "Distance Désirée de la Cible"
#: scene/2d/navigation_agent_2d.cpp scene/3d/navigation_agent.cpp
-#, fuzzy
msgid "Path Max Distance"
-msgstr "Choisissez distance :"
+msgstr "Distance maximale du chemin"
#: scene/2d/navigation_agent_2d.cpp scene/3d/navigation_agent.cpp
-#, fuzzy
msgid "Avoidance"
-msgstr "Options avancées"
+msgstr "Évitement"
#: scene/2d/navigation_agent_2d.cpp scene/3d/navigation_agent.cpp
-#, fuzzy
msgid "Avoidance Enabled"
-msgstr "Activer"
+msgstr "Évitement activé"
#: scene/2d/navigation_agent_2d.cpp scene/3d/navigation_agent.cpp
msgid "Neighbor Dist"
@@ -21750,10 +21281,11 @@ msgid "Max Speed"
msgstr "Vitesse Max"
#: scene/2d/navigation_agent_2d.cpp
-#, fuzzy
msgid ""
"The NavigationAgent2D can be used only under a Node2D inheriting parent node."
-msgstr "Le NavigationAgent2D ne peut être utilisé que sous un nœud Node2D."
+msgstr ""
+"Le NavigationAgent2D ne peut être utilisé que sous un nœud dont le parent "
+"hérite de Node2D."
#: scene/2d/navigation_obstacle_2d.cpp scene/3d/navigation_obstacle.cpp
msgid "Estimate Radius"
@@ -21778,17 +21310,15 @@ msgstr ""
#: scene/2d/navigation_polygon.cpp
msgid "Navpoly"
-msgstr ""
+msgstr "Polygone de navigation"
#: scene/2d/navigation_polygon.cpp scene/3d/navigation_mesh_instance.cpp
-#, fuzzy
msgid "Enter Cost"
-msgstr "Centrée en bas"
+msgstr "Coût d’entrée"
#: scene/2d/navigation_polygon.cpp scene/3d/navigation_mesh_instance.cpp
-#, fuzzy
msgid "Travel Cost"
-msgstr "Se déplacer"
+msgstr "Coût de déplacement"
#: scene/2d/node_2d.cpp scene/2d/polygon_2d.cpp scene/3d/spatial.cpp
#: scene/main/canvas_layer.cpp
@@ -21854,9 +21384,8 @@ msgid "Motion"
msgstr "Déplacement"
#: scene/2d/parallax_layer.cpp
-#, fuzzy
msgid "Mirroring"
-msgstr "Miroir"
+msgstr "Effet de miroir"
#: scene/2d/particles_2d.cpp
msgid ""
@@ -21919,9 +21448,8 @@ msgstr ""
"d'un nœud de type Path2D."
#: scene/2d/path_2d.cpp scene/3d/path.cpp
-#, fuzzy
msgid "Unit Offset"
-msgstr "Décalage de la grille :"
+msgstr "Décalage d'unité"
#: scene/2d/path_2d.cpp scene/3d/camera.cpp scene/3d/path.cpp
msgid "H Offset"
@@ -21937,7 +21465,7 @@ msgstr "Interpolation Cubique"
#: scene/2d/path_2d.cpp
msgid "Lookahead"
-msgstr ""
+msgstr "Anticipation"
#: scene/2d/physics_body_2d.cpp scene/3d/visual_instance.cpp
msgid "Layers"
@@ -21997,14 +21525,12 @@ msgid "Gravity Scale"
msgstr "Échelle de la Gravité"
#: scene/2d/physics_body_2d.cpp scene/3d/physics_body.cpp
-#, fuzzy
msgid "Custom Integrator"
-msgstr "Nœud Personnalisé"
+msgstr "Intégrateur personnalisé"
#: scene/2d/physics_body_2d.cpp scene/3d/physics_body.cpp
-#, fuzzy
msgid "Continuous CD"
-msgstr "Continu"
+msgstr "Détection de collision continue"
#: scene/2d/physics_body_2d.cpp scene/3d/physics_body.cpp
msgid "Contacts Reported"
@@ -22037,7 +21563,7 @@ msgstr "Forces Appliquées"
#: scene/2d/physics_body_2d.cpp
msgid "Torque"
-msgstr ""
+msgstr "Torque"
#: scene/2d/physics_body_2d.cpp scene/3d/physics_body.cpp
msgid "Safe Margin"
@@ -22048,9 +21574,8 @@ msgid "Sync To Physics"
msgstr "Synchroniser Avec La Physique"
#: scene/2d/physics_body_2d.cpp scene/3d/physics_body.cpp
-#, fuzzy
msgid "Moving Platform"
-msgstr "Déplacement du résultat"
+msgstr "Plateforme mobile"
#: scene/2d/physics_body_2d.cpp scene/3d/physics_body.cpp
msgid "Apply Velocity On Leave"
@@ -22064,9 +21589,8 @@ msgid "Normal"
msgstr "Normale"
#: scene/2d/physics_body_2d.cpp scene/3d/physics_body.cpp
-#, fuzzy
msgid "Remainder"
-msgstr "Moteur de rendu :"
+msgstr "Reste"
#: scene/2d/physics_body_2d.cpp scene/3d/physics_body.cpp
msgid "Local Shape"
@@ -22127,9 +21651,8 @@ msgid "Exclude Parent"
msgstr "Exclure Le Parent"
#: scene/2d/ray_cast_2d.cpp scene/3d/ray_cast.cpp
-#, fuzzy
msgid "Cast To"
-msgstr "Créer un nœud Shader"
+msgstr "Lancer vers"
#: scene/2d/ray_cast_2d.cpp scene/3d/ray_cast.cpp
msgid "Collide With"
@@ -22137,7 +21660,7 @@ msgstr "Collisionne Avec"
#: scene/2d/ray_cast_2d.cpp scene/3d/camera.cpp scene/3d/ray_cast.cpp
msgid "Areas"
-msgstr ""
+msgstr "Zones"
#: scene/2d/ray_cast_2d.cpp scene/3d/camera.cpp scene/3d/ray_cast.cpp
msgid "Bodies"
@@ -22150,24 +21673,20 @@ msgstr ""
"fonctionner."
#: scene/2d/remote_transform_2d.cpp scene/3d/remote_transform.cpp
-#, fuzzy
msgid "Remote Path"
-msgstr "Supprimer un point"
+msgstr "Chemin distant"
#: scene/2d/remote_transform_2d.cpp scene/3d/remote_transform.cpp
-#, fuzzy
msgid "Use Global Coordinates"
-msgstr "Coordonnée suivante"
+msgstr "Utiliser les coordonnées globales"
#: scene/2d/skeleton_2d.cpp scene/3d/skeleton.cpp
-#, fuzzy
msgid "Rest"
-msgstr "Redémarrer"
+msgstr "Repos"
#: scene/2d/skeleton_2d.cpp
-#, fuzzy
msgid "Default Length"
-msgstr "Thème par défaut"
+msgstr "Longueur par défaut"
#: scene/2d/skeleton_2d.cpp
msgid "This Bone2D chain should end at a Skeleton2D node."
@@ -22188,16 +21707,15 @@ msgstr ""
#: scene/2d/sprite.cpp scene/3d/sprite_3d.cpp
msgid "Hframes"
-msgstr ""
+msgstr "Trames H"
#: scene/2d/sprite.cpp scene/3d/sprite_3d.cpp
msgid "Vframes"
-msgstr ""
+msgstr "Trames V"
#: scene/2d/sprite.cpp scene/3d/sprite_3d.cpp
-#, fuzzy
msgid "Frame Coords"
-msgstr "Image %"
+msgstr "Coordonnées de trame"
#: scene/2d/sprite.cpp scene/resources/texture.cpp
#, fuzzy
@@ -22215,14 +21733,12 @@ msgstr ""
"etc."
#: scene/2d/tile_map.cpp
-#, fuzzy
msgid "Tile Set"
-msgstr "TileSet"
+msgstr "Palette de tuiles"
#: scene/2d/tile_map.cpp
-#, fuzzy
msgid "Quadrant Size"
-msgstr "Changer la taille d'une caméra"
+msgstr "Taille de quadrant"
#: scene/2d/tile_map.cpp
#, fuzzy
@@ -22230,19 +21746,16 @@ msgid "Custom Transform"
msgstr "Transformation"
#: scene/2d/tile_map.cpp
-#, fuzzy
msgid "Half Offset"
-msgstr "Initialiser"
+msgstr "Décalage de moitié"
#: scene/2d/tile_map.cpp
-#, fuzzy
msgid "Tile Origin"
-msgstr "Afficher l'origine"
+msgstr "Origine de la tuile"
#: scene/2d/tile_map.cpp
-#, fuzzy
msgid "Y Sort"
-msgstr "Trier"
+msgstr "Trier par Y"
#: scene/2d/tile_map.cpp
msgid "Show Collision"
@@ -22293,23 +21806,20 @@ msgstr ""
"nœud racine de la scène éditée."
#: scene/2d/visibility_notifier_2d.cpp scene/3d/visibility_notifier.cpp
-#, fuzzy
msgid "Pause Animations"
-msgstr "Coller l'animation"
+msgstr "Mettre les animations en pause"
#: scene/2d/visibility_notifier_2d.cpp scene/3d/visibility_notifier.cpp
msgid "Freeze Bodies"
msgstr "Geler les corps"
#: scene/2d/visibility_notifier_2d.cpp
-#, fuzzy
msgid "Pause Particles"
-msgstr "Particules"
+msgstr "Mettre les particules en pause"
#: scene/2d/visibility_notifier_2d.cpp
-#, fuzzy
msgid "Pause Animated Sprites"
-msgstr "Coller l'animation"
+msgstr "Mettre les Sprites animés en pause"
#: scene/2d/visibility_notifier_2d.cpp
msgid "Process Parent"
@@ -22337,7 +21847,7 @@ msgstr "ID Du Contrôleur"
#: scene/3d/arvr_nodes.cpp servers/arvr/arvr_positional_tracker.cpp
msgid "Rumble"
-msgstr ""
+msgstr "Vibration"
#: scene/3d/arvr_nodes.cpp
msgid "ARVRController must have an ARVROrigin node as its parent."
@@ -22377,43 +21887,40 @@ msgid "World Scale"
msgstr "Échelle du Monde"
#: scene/3d/audio_stream_player_3d.cpp
-#, fuzzy
msgid "Attenuation Model"
-msgstr "Nœud d'animation"
+msgstr "Modèle d’atténuation"
#: scene/3d/audio_stream_player_3d.cpp
msgid "Unit dB"
-msgstr ""
+msgstr "Unité (dB)"
#: scene/3d/audio_stream_player_3d.cpp
msgid "Unit Size"
-msgstr ""
+msgstr "Taille d’unité"
#: scene/3d/audio_stream_player_3d.cpp
msgid "Max dB"
-msgstr ""
+msgstr "Max (dB)"
#: scene/3d/audio_stream_player_3d.cpp
msgid "Out Of Range Mode"
msgstr ""
#: scene/3d/audio_stream_player_3d.cpp
-#, fuzzy
msgid "Emission Angle"
-msgstr "Couleurs d'émission"
+msgstr "Angle d’émission"
#: scene/3d/audio_stream_player_3d.cpp
msgid "Degrees"
msgstr "Degrés"
#: scene/3d/audio_stream_player_3d.cpp
-#, fuzzy
msgid "Filter Attenuation dB"
-msgstr "Animation"
+msgstr "Filtre d’atténuation (dB)"
#: scene/3d/audio_stream_player_3d.cpp
msgid "Attenuation Filter"
-msgstr ""
+msgstr "Filtre d’atténuation"
#: scene/3d/audio_stream_player_3d.cpp
#: servers/audio/effects/audio_effect_chorus.cpp
@@ -22423,14 +21930,12 @@ msgstr ""
#: scene/3d/audio_stream_player_3d.cpp
#: servers/audio/effects/audio_effect_filter.cpp
-#, fuzzy
msgid "dB"
-msgstr "o"
+msgstr "dB"
#: scene/3d/audio_stream_player_3d.cpp
-#, fuzzy
msgid "Doppler"
-msgstr "Activer l'effet Doppler"
+msgstr "Doppler"
#: scene/3d/audio_stream_player_3d.cpp
#, fuzzy
@@ -22440,7 +21945,7 @@ msgstr "Empaquetage"
#: scene/3d/baked_lightmap.cpp scene/3d/gi_probe.cpp
#: scene/3d/reflection_probe.cpp
msgid "Interior"
-msgstr ""
+msgstr "Intérieur"
#: scene/3d/baked_lightmap.cpp
msgid "Finding meshes and lights"
@@ -22475,69 +21980,59 @@ msgstr "Gadgets"
#: scene/3d/baked_lightmap.cpp
msgid "Tweaks"
-msgstr ""
+msgstr "Ajustements"
#: scene/3d/baked_lightmap.cpp
msgid "Bounces"
-msgstr ""
+msgstr "Rebonds"
#: scene/3d/baked_lightmap.cpp
msgid "Bounce Indirect Energy"
-msgstr ""
+msgstr "Énergie indirecte de rebond"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Use Denoiser"
-msgstr "Filtre :"
+msgstr "Utiliser un filtre anti-bruit"
#: scene/3d/baked_lightmap.cpp scene/resources/texture.cpp
msgid "Use HDR"
-msgstr ""
+msgstr "Utiliser HDR"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Use Color"
-msgstr "Couleurs"
+msgstr "Utiliser la couleur"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Default Texels Per Unit"
-msgstr "Thème par défaut"
+msgstr "Texels par unité par défaut"
#: scene/3d/baked_lightmap.cpp scene/resources/texture.cpp
-#, fuzzy
msgid "Atlas"
-msgstr "Nouvel Atlas"
+msgstr "Atlas"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Generate"
-msgstr "Général"
+msgstr "Générer"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Max Size"
-msgstr "Taille :"
+msgstr "Taille maximale"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Custom Sky"
-msgstr "Nœud Personnalisé"
+msgstr "Ciel personnalisé"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Custom Sky Rotation Degrees"
-msgstr "Rotation de %s degrés."
+msgstr "Degrés de rotation du ciel personnalisé"
#: scene/3d/baked_lightmap.cpp scene/3d/ray_cast.cpp
-#, fuzzy
msgid "Custom Color"
-msgstr "Nœud Personnalisé"
+msgstr "Couleur personnalisée"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Custom Energy"
-msgstr "Déplacer effet de transport"
+msgstr "Énergie personnalisée"
#: scene/3d/baked_lightmap.cpp
#, fuzzy
@@ -22545,27 +22040,24 @@ msgid "Min Light"
msgstr "Indenter vers la droite"
#: scene/3d/baked_lightmap.cpp scene/3d/gi_probe.cpp
-#, fuzzy
msgid "Propagation"
-msgstr "Navigation"
+msgstr "Propagation"
#: scene/3d/baked_lightmap.cpp
msgid "Image Path"
-msgstr ""
+msgstr "Chemin de l'image"
#: scene/3d/baked_lightmap.cpp
-#, fuzzy
msgid "Light Data"
-msgstr "Avec données"
+msgstr "Données de lumière"
#: scene/3d/bone_attachment.cpp scene/3d/physics_body.cpp
-#, fuzzy
msgid "Bone Name"
-msgstr "Nom de nœud :"
+msgstr "Nom de l'os"
#: scene/3d/camera.cpp
msgid "Keep Aspect"
-msgstr ""
+msgstr "Garder l'aspect"
#: scene/3d/camera.cpp scene/3d/light.cpp scene/3d/reflection_probe.cpp
msgid "Cull Mask"
@@ -22577,36 +22069,32 @@ msgid "Doppler Tracking"
msgstr "Piste de propriété"
#: scene/3d/camera.cpp
-#, fuzzy
msgid "Projection"
-msgstr "Projet"
+msgstr "Projection"
#: scene/3d/camera.cpp
msgid "FOV"
-msgstr ""
+msgstr "Champ de vision"
#: scene/3d/camera.cpp
-#, fuzzy
msgid "Frustum Offset"
-msgstr "Décalage de la grille :"
+msgstr "Décalage du Tronc"
#: scene/3d/camera.cpp
-#, fuzzy
msgid "Near"
-msgstr "Au plus proche"
+msgstr "Plan proche"
#: scene/3d/camera.cpp
msgid "Far"
-msgstr ""
+msgstr "Plan éloigné"
#: scene/3d/camera.cpp scene/3d/collision_polygon.cpp scene/3d/spring_arm.cpp
#: scene/gui/control.cpp scene/resources/default_theme/default_theme.cpp
#: scene/resources/shape.cpp scene/resources/style_box.cpp
#: scene/resources/texture.cpp servers/physics_2d_server.cpp
#: servers/physics_server.cpp
-#, fuzzy
msgid "Margin"
-msgstr "Définir la marge"
+msgstr "Marge"
#: scene/3d/camera.cpp
#, fuzzy
@@ -22696,48 +22184,40 @@ msgid "Box Extents"
msgstr "Gadgets"
#: scene/3d/cpu_particles.cpp scene/resources/particles_material.cpp
-#, fuzzy
msgid "Ring Radius"
-msgstr "Masque d'émission"
+msgstr "Rayon de l'anneau"
#: scene/3d/cpu_particles.cpp scene/resources/particles_material.cpp
-#, fuzzy
msgid "Ring Inner Radius"
-msgstr "Changer le rayon intérieur de la tour"
+msgstr "Rayon intérieur de l'anneau"
#: scene/3d/cpu_particles.cpp scene/resources/particles_material.cpp
-#, fuzzy
msgid "Ring Height"
-msgstr "Rotation vers la droite"
+msgstr "Hauteur de l'anneau"
#: scene/3d/cpu_particles.cpp scene/resources/particles_material.cpp
-#, fuzzy
msgid "Ring Axis"
-msgstr "Avertissements"
+msgstr "Axe de l'anneau"
#: scene/3d/cpu_particles.cpp scene/resources/particles_material.cpp
-#, fuzzy
msgid "Rotate Y"
-msgstr "Rotation"
+msgstr "Rotation Y"
#: scene/3d/cpu_particles.cpp scene/resources/particles_material.cpp
-#, fuzzy
msgid "Disable Z"
-msgstr "Item désactivé"
+msgstr "Désactiver axe Z"
#: scene/3d/cpu_particles.cpp scene/resources/particles_material.cpp
msgid "Flatness"
-msgstr ""
+msgstr "Platitude"
#: scene/3d/cull_instance.cpp servers/visual_server.cpp
-#, fuzzy
msgid "Portals"
-msgstr "Retourner les Portals"
+msgstr "Portails"
#: scene/3d/cull_instance.cpp
-#, fuzzy
msgid "Portal Mode"
-msgstr "Mode prioritaire"
+msgstr "Mode portail"
#: scene/3d/cull_instance.cpp
msgid "Include In Bound"
@@ -22748,9 +22228,8 @@ msgid "Allow Merging"
msgstr ""
#: scene/3d/cull_instance.cpp
-#, fuzzy
msgid "Autoplace Priority"
-msgstr "Activer la priorité"
+msgstr "Priorité d’auto-placement"
#: scene/3d/gi_probe.cpp
msgid "Plotting Meshes"
@@ -22781,114 +22260,98 @@ msgstr ""
#: scene/3d/gi_probe.cpp
msgid "Subdiv"
-msgstr ""
+msgstr "Subdivision"
#: scene/3d/gi_probe.cpp
-#, fuzzy
msgid "Dynamic Range"
-msgstr "Bibliothèque dynamique"
+msgstr "Plage dynamique"
#: scene/3d/gi_probe.cpp scene/3d/light.cpp
msgid "Normal Bias"
-msgstr ""
+msgstr "Biais normal"
#: scene/3d/label_3d.cpp scene/3d/sprite_3d.cpp
#: scene/resources/primitive_meshes.cpp
-#, fuzzy
msgid "Pixel Size"
-msgstr "Aimanter au pixel"
+msgstr "Taille de pixel"
#: scene/3d/label_3d.cpp scene/3d/sprite_3d.cpp
msgid "Billboard"
-msgstr "Billboard"
+msgstr "Panneau(Billboard)"
#: scene/3d/label_3d.cpp scene/3d/sprite_3d.cpp
-#, fuzzy
msgid "Shaded"
-msgstr "Ombrage"
+msgstr "Ombré"
#: scene/3d/label_3d.cpp scene/3d/sprite_3d.cpp
msgid "Double Sided"
-msgstr ""
+msgstr "Double face"
#: scene/3d/label_3d.cpp scene/3d/sprite_3d.cpp scene/resources/material.cpp
msgid "No Depth Test"
-msgstr ""
+msgstr "Pas de test de profondeur"
#: scene/3d/label_3d.cpp scene/3d/sprite_3d.cpp scene/resources/material.cpp
-#, fuzzy
msgid "Fixed Size"
-msgstr "Vue de devant"
+msgstr "Taille fixe"
#: scene/3d/label_3d.cpp scene/3d/sprite_3d.cpp
msgid "Alpha Cut"
-msgstr ""
+msgstr "Coupe alpha"
#: scene/3d/label_3d.cpp scene/resources/material.cpp
msgid "Alpha Scissor Threshold"
-msgstr ""
+msgstr "Seuil des ciseaux d'alpha"
#: scene/3d/label_3d.cpp scene/3d/sprite_3d.cpp scene/resources/material.cpp
-#, fuzzy
msgid "Render Priority"
-msgstr "Activer la priorité"
+msgstr "Priorité de rendu"
#: scene/3d/label_3d.cpp
-#, fuzzy
msgid "Outline Render Priority"
-msgstr "Activer la priorité"
+msgstr "Priorité de rendu du contour"
#: scene/3d/label_3d.cpp
-#, fuzzy
msgid "Outline Modulate"
-msgstr "Forcer la modulation blanche"
+msgstr "Moduler le contour"
#: scene/3d/label_3d.cpp scene/resources/default_theme/default_theme.cpp
#: scene/resources/dynamic_font.cpp scene/resources/primitive_meshes.cpp
-#, fuzzy
msgid "Font"
-msgstr "Polices"
+msgstr "Police"
#: scene/3d/label_3d.cpp scene/resources/primitive_meshes.cpp
-#, fuzzy
msgid "Horizontal Alignment"
-msgstr "Horizontal Activé"
+msgstr "Alignement horizontal"
#: scene/3d/label_3d.cpp
-#, fuzzy
msgid "Vertical Alignment"
-msgstr "Filtrer les signaux"
+msgstr "Alignement vertical"
#: scene/3d/label_3d.cpp scene/gui/dialogs.cpp scene/gui/label.cpp
-#, fuzzy
msgid "Autowrap"
-msgstr "AutoLoad"
+msgstr "Retour à la ligne automatique"
#: scene/3d/light.cpp
-#, fuzzy
msgid "Indirect Energy"
-msgstr "Couleurs d'émission"
+msgstr "Énergie indirecte"
#: scene/3d/light.cpp
-#, fuzzy
msgid "Negative"
-msgstr "GDNative"
+msgstr "Négative"
#: scene/3d/light.cpp scene/resources/material.cpp
#: scene/resources/visual_shader.cpp
-#, fuzzy
msgid "Specular"
-msgstr "Mode Règle"
+msgstr "Spéculaire"
#: scene/3d/light.cpp
-#, fuzzy
msgid "Bake Mode"
-msgstr "Mode Bitmask"
+msgstr "Mode de pré-calcul"
#: scene/3d/light.cpp
-#, fuzzy
msgid "Contact"
-msgstr "Prélever une couleur"
+msgstr "Contact"
#: scene/3d/light.cpp
#, fuzzy
@@ -22896,9 +22359,8 @@ msgid "Reverse Cull Face"
msgstr "Réinitialiser le volume de bus"
#: scene/3d/light.cpp servers/visual_server.cpp
-#, fuzzy
msgid "Directional Shadow"
-msgstr "Directions"
+msgstr "Ombre directionnelle"
#: scene/3d/light.cpp
#, fuzzy
@@ -22916,9 +22378,8 @@ msgid "Split 3"
msgstr "Divisé"
#: scene/3d/light.cpp
-#, fuzzy
msgid "Blend Splits"
-msgstr "Temps de mélange :"
+msgstr "Mélanger les écarts"
#: scene/3d/light.cpp
#, fuzzy
@@ -22926,23 +22387,20 @@ msgid "Bias Split Scale"
msgstr "Utiliser le magnétisme d'échelle"
#: scene/3d/light.cpp
-#, fuzzy
msgid "Depth Range"
-msgstr "Profondeur"
+msgstr "Plage de profondeur"
#: scene/3d/light.cpp
msgid "Omni"
-msgstr ""
+msgstr "Omnidirectionnelle"
#: scene/3d/light.cpp
-#, fuzzy
msgid "Shadow Mode"
-msgstr "Ombrage"
+msgstr "Mode ombre"
#: scene/3d/light.cpp
-#, fuzzy
msgid "Shadow Detail"
-msgstr "Afficher par défaut"
+msgstr "Détails d'ombre"
#: scene/3d/light.cpp
msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows."
@@ -22952,21 +22410,19 @@ msgstr ""
#: scene/3d/light.cpp
msgid "Spot"
-msgstr ""
+msgstr "Spot"
#: scene/3d/light.cpp
-#, fuzzy
msgid "Angle Attenuation"
-msgstr "Animation"
+msgstr "Atténuation d'angle"
#: scene/3d/mesh_instance.cpp
msgid "Software Skinning"
msgstr ""
#: scene/3d/mesh_instance.cpp
-#, fuzzy
msgid "Transform Normals"
-msgstr "Transformation annulée."
+msgstr "Transformer les normales"
#: scene/3d/navigation.cpp
msgid ""
@@ -22974,45 +22430,44 @@ msgid ""
"be removed in a future version. Use 'NavigationServer.map_get_path()' "
"instead."
msgstr ""
+"Le nœud \"Navigation\" et \"Navigation.get_simple_path()\" sont obsolètes et "
+"seront retires dans une version ultérieure. Utilisez plutôt "
+"\"NavigationServer.map_get_path()\"."
#: scene/3d/navigation.cpp scene/resources/curve.cpp
-#, fuzzy
msgid "Up Vector"
-msgstr "Vecteur"
+msgstr "Vecteur Haut"
#: scene/3d/navigation.cpp
-#, fuzzy
msgid "Cell Height"
-msgstr "En période de test"
+msgstr "Hauteur de cellule"
#: scene/3d/navigation_agent.cpp
msgid "Agent Height Offset"
-msgstr ""
+msgstr "Décalage de hauteur de l'agent"
#: scene/3d/navigation_agent.cpp
-#, fuzzy
msgid "Ignore Y"
-msgstr "[Ignorer]"
+msgstr "Ignorer Y"
#: scene/3d/navigation_agent.cpp
-#, fuzzy
msgid ""
"The NavigationAgent can be used only under a Spatial inheriting parent node."
-msgstr "Le NavigationAgent ne peut être utilisé que sous un nœud spatial."
+msgstr ""
+"Le NavigationAgent ne peut être utilisé que sous un nœud parent héritant de "
+"Spatial."
#: scene/3d/navigation_mesh_instance.cpp scene/resources/mesh_library.cpp
-#, fuzzy
msgid "NavMesh"
-msgstr "Calculer le NavMesh"
+msgstr "NavMesh"
#: scene/3d/navigation_obstacle.cpp
-#, fuzzy
msgid ""
"The NavigationObstacle only serves to provide collision avoidance to a "
"Spatial inheriting parent object."
msgstr ""
-"Un NavigationObstacle ne peut éviter les collisions qu'avec les nœuds "
-"Spatial."
+"Le NavigationObstacle ne sert qu'à fournir l’évitement de collision qu'aux "
+"objets dont les parents héritent de Spatial."
#: scene/3d/occluder.cpp
msgid "No shape is set."
@@ -23063,19 +22518,16 @@ msgstr ""
"Particles » activé."
#: scene/3d/particles.cpp
-#, fuzzy
msgid "Visibility AABB"
-msgstr "Basculer la visibilité"
+msgstr "Visibilité AABB"
#: scene/3d/particles.cpp
-#, fuzzy
msgid "Draw Passes"
-msgstr "Appels de dessin :"
+msgstr "Afficher les passes"
#: scene/3d/particles.cpp
-#, fuzzy
msgid "Passes"
-msgstr "Appels de dessin :"
+msgstr "Passes"
#: scene/3d/path.cpp
msgid "PathFollow only works when set as a child of a Path node."
@@ -23092,7 +22544,6 @@ msgstr ""
"Vector » dans la ressource Curve de son parent Path."
#: scene/3d/path.cpp
-#, fuzzy
msgid "Rotation Mode"
msgstr "Mode rotation"
@@ -23107,223 +22558,189 @@ msgstr ""
"Modifiez la taille dans les formes de collision enfant à la place."
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Axis Lock"
-msgstr "Axe"
+msgstr "Verrouiller l'axe"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Linear X"
-msgstr "Linéaire"
+msgstr "X linéaire"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Linear Y"
-msgstr "Linéaire"
+msgstr "Y linéaire"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Linear Z"
-msgstr "Linéaire"
+msgstr "Z linéaire"
#: scene/3d/physics_body.cpp
msgid "Angular X"
-msgstr ""
+msgstr "X angulaire"
#: scene/3d/physics_body.cpp
msgid "Angular Y"
-msgstr ""
+msgstr "Y angulaire"
#: scene/3d/physics_body.cpp
msgid "Angular Z"
-msgstr ""
+msgstr "Z angulaire"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Motion X"
-msgstr "Action"
+msgstr "X mouvement"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Motion Y"
-msgstr "Action"
+msgstr "Y mouvement"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Motion Z"
-msgstr "Action"
+msgstr "Z mouvement"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Joint Constraints"
-msgstr "Constantes"
+msgstr "Restrictions de jointure"
#: scene/3d/physics_body.cpp scene/3d/physics_joint.cpp
msgid "Impulse Clamp"
-msgstr ""
+msgstr "Borner l'impulsion"
#: scene/3d/physics_body.cpp scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Swing Span"
-msgstr "Enregistrement de la scène"
+msgstr "Ampleur de balancement"
#: scene/3d/physics_body.cpp scene/3d/physics_joint.cpp
msgid "Twist Span"
-msgstr ""
+msgstr "Ampleur de torsion"
#: scene/3d/physics_body.cpp scene/3d/physics_joint.cpp
#: scene/3d/vehicle_body.cpp
-#, fuzzy
msgid "Relaxation"
-msgstr "Séparation :"
+msgstr "Relaxation"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Angular Limit Enabled"
-msgstr "Filtrer les signaux"
+msgstr "Limite angulaire activée"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Angular Limit Upper"
-msgstr "Linéaire"
+msgstr "Limite angulaire haute"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Angular Limit Lower"
-msgstr "Erreur angulaire max. :"
+msgstr "Limite angulaire basse"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Angular Limit Bias"
-msgstr "Linéaire"
+msgstr "Biais de limite angulaire"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Angular Limit Softness"
-msgstr "Animation"
+msgstr "Douceur de limite angulaire"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Angular Limit Relaxation"
-msgstr "Animation"
+msgstr "Relaxation de limite angulaire"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Linear Limit Upper"
-msgstr "Linéaire"
+msgstr "Limite linéaire haute"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Linear Limit Lower"
-msgstr "Linéaire"
+msgstr "Limite linéaire basse"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Linear Limit Softness"
-msgstr "Linéaire"
+msgstr "Douceur de limite linéaire"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Linear Limit Restitution"
-msgstr "Linéaire"
+msgstr "Restitution de limite linéaire"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Linear Limit Damping"
-msgstr "Linéaire"
+msgstr "Amortissement de limite linéaire"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Angular Limit Restitution"
-msgstr "Animation"
+msgstr "Restitution de limite angulaire"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Angular Limit Damping"
-msgstr "Animation"
+msgstr "Amortissement de limite angulaire"
#: scene/3d/physics_body.cpp
msgid "X"
-msgstr ""
+msgstr "X"
#: scene/3d/physics_body.cpp
msgid "Y"
-msgstr ""
+msgstr "Y"
#: scene/3d/physics_body.cpp
msgid "Z"
-msgstr ""
+msgstr "Z"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Linear Limit Enabled"
-msgstr "Linéaire"
+msgstr "Limite linéaire active"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Linear Spring Enabled"
-msgstr "Linéaire"
+msgstr "Ressort linéaire actif"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Linear Spring Stiffness"
-msgstr "Linéaire"
+msgstr "Raideur du ressort linéaire"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Linear Spring Damping"
-msgstr "Linéaire"
+msgstr "Amortissement de ressort linéaire"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Linear Equilibrium Point"
-msgstr "Linéaire"
+msgstr "Point d’équilibre linéaire"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Linear Restitution"
-msgstr "Description"
+msgstr "Restitution linéaire"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Linear Damping"
-msgstr "Linéaire"
+msgstr "Amortissement linéaire"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Angular Restitution"
-msgstr "Description"
+msgstr "Restitution angulaire"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Angular Damping"
-msgstr "Animation"
+msgstr "Amortissement angulaire"
#: scene/3d/physics_body.cpp scene/3d/physics_joint.cpp
msgid "ERP"
msgstr ""
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Angular Spring Enabled"
-msgstr "Filtrer les signaux"
+msgstr "Ressort angulaire actif"
#: scene/3d/physics_body.cpp
msgid "Angular Spring Stiffness"
-msgstr ""
+msgstr "Raideur de ressort angulaire"
#: scene/3d/physics_body.cpp
msgid "Angular Spring Damping"
-msgstr ""
+msgstr "Amortissement de ressort angulaire"
#: scene/3d/physics_body.cpp
msgid "Angular Equilibrium Point"
-msgstr ""
+msgstr "Point d’équilibre angulaire"
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Body Offset"
-msgstr "Décalage :"
+msgstr "Décalage du corps"
#: scene/3d/physics_joint.cpp
msgid "Node A and Node B must be PhysicsBodies"
@@ -23347,183 +22764,159 @@ msgstr "Node A et Node B doivent être des PhysicsBody différents"
#: scene/3d/physics_joint.cpp
msgid "Solver"
-msgstr ""
+msgstr "Résolveur"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Exclude Nodes"
-msgstr "Supprimer des nœuds"
+msgstr "Exclure les nœuds"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Params"
-msgstr "Paramètre modifié :"
+msgstr "Paramètres"
#: scene/3d/physics_joint.cpp
msgid "Angular Limit"
-msgstr ""
+msgstr "Limite angulaire"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Upper"
-msgstr "Tout en majuscule"
+msgstr "Haute"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Lower"
-msgstr "Tout en minuscule"
+msgstr "Basse"
#: scene/3d/physics_joint.cpp
msgid "Motor"
-msgstr ""
+msgstr "Moteur"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Target Velocity"
-msgstr "Vue de l'orbite vers la droite"
+msgstr "Vélocité cible"
#: scene/3d/physics_joint.cpp
msgid "Max Impulse"
msgstr "Impulsion Maximale"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Linear Limit"
-msgstr "Linéaire"
+msgstr "Limite linéaire"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Upper Distance"
-msgstr "Choisissez distance :"
+msgstr "Distance haute"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Lower Distance"
-msgstr "Choisissez distance :"
+msgstr "Distance basse"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Restitution"
-msgstr "Description"
+msgstr "Restitution"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Linear Motion"
-msgstr "Initialiser"
+msgstr "Mouvement linéaire"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Linear Ortho"
-msgstr "Orthogonale arrière"
+msgstr "Ortho linéaire"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Upper Angle"
-msgstr "Tout en majuscule"
+msgstr "Angle supérieur"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Lower Angle"
-msgstr "Tout en minuscule"
+msgstr "Angle inférieur"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Angular Motion"
-msgstr "Animation"
+msgstr "Mouvement angulaire"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Angular Ortho"
-msgstr "Erreur angulaire max. :"
+msgstr "Ortho angulaire"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Linear Limit X"
-msgstr "Linéaire"
+msgstr "X de la limite linéaire"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Linear Motor X"
-msgstr "Initialiser"
+msgstr "X du moteur linéaire"
#: scene/3d/physics_joint.cpp
msgid "Force Limit"
msgstr "Limite de Force"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Linear Spring X"
-msgstr "Linéaire"
+msgstr "X du ressort linéaire"
#: scene/3d/physics_joint.cpp
msgid "Equilibrium Point"
-msgstr ""
+msgstr "Point d’équilibre"
#: scene/3d/physics_joint.cpp
msgid "Angular Limit X"
-msgstr ""
+msgstr "X de la limite angulaire"
#: scene/3d/physics_joint.cpp
msgid "Angular Motor X"
-msgstr ""
+msgstr "X du moteur angulaire"
#: scene/3d/physics_joint.cpp
msgid "Angular Spring X"
-msgstr ""
+msgstr "X du ressort angulaire"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Linear Limit Y"
-msgstr "Linéaire"
+msgstr "Y de la limite linéaire"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Linear Motor Y"
-msgstr "Initialiser"
+msgstr "Y du moteur linéaire"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Linear Spring Y"
-msgstr "Linéaire"
+msgstr "Y du ressort linéaire"
#: scene/3d/physics_joint.cpp
msgid "Angular Limit Y"
-msgstr ""
+msgstr "Y de la limite angulaire"
#: scene/3d/physics_joint.cpp
msgid "Angular Motor Y"
-msgstr ""
+msgstr "Y du moteur angulaire"
#: scene/3d/physics_joint.cpp
msgid "Angular Spring Y"
-msgstr ""
+msgstr "Y du ressort angulaire"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Linear Limit Z"
-msgstr "Linéaire"
+msgstr "Z de la limite linéaire"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Linear Motor Z"
-msgstr "Initialiser"
+msgstr "Z du moteur linéaire"
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Linear Spring Z"
-msgstr "Linéaire"
+msgstr "Z du ressort linéaire"
#: scene/3d/physics_joint.cpp
msgid "Angular Limit Z"
-msgstr ""
+msgstr "Z de la limite angulaire"
#: scene/3d/physics_joint.cpp
msgid "Angular Motor Z"
-msgstr ""
+msgstr "Z du moteur angulaire"
#: scene/3d/physics_joint.cpp
msgid "Angular Spring Z"
-msgstr ""
+msgstr "Z du ressort angulaire"
#: scene/3d/portal.cpp
msgid "The RoomManager should not be a child or grandchild of a Portal."
@@ -23543,21 +22936,19 @@ msgstr "Portail actif"
#: scene/3d/portal.cpp scene/resources/occluder_shape_polygon.cpp
msgid "Two Way"
-msgstr ""
+msgstr "Double sens"
#: scene/3d/portal.cpp
msgid "Linked Room"
msgstr "Salle liée"
#: scene/3d/portal.cpp
-#, fuzzy
msgid "Use Default Margin"
-msgstr "Défaut"
+msgstr "Utiliser les marges par défaut"
#: scene/3d/proximity_group.cpp
-#, fuzzy
msgid "Group Name"
-msgstr "Groupé"
+msgstr "Nom de groupe"
#: scene/3d/proximity_group.cpp
msgid "Dispatch Mode"
@@ -23568,42 +22959,36 @@ msgid "Grid Radius"
msgstr "Rayon de la Grille"
#: scene/3d/ray_cast.cpp
-#, fuzzy
msgid "Debug Shape"
-msgstr "Débogueur"
+msgstr "Forme de débogage"
#: scene/3d/ray_cast.cpp scene/resources/style_box.cpp
msgid "Thickness"
-msgstr ""
+msgstr "Épaisseur"
#: scene/3d/reflection_probe.cpp scene/main/viewport.cpp
-#, fuzzy
msgid "Update Mode"
-msgstr "Mode rotation"
+msgstr "Mode de mise à jour"
#: scene/3d/reflection_probe.cpp
msgid "Origin Offset"
msgstr "Décalage de la Grille"
#: scene/3d/reflection_probe.cpp
-#, fuzzy
msgid "Box Projection"
-msgstr "Projet"
+msgstr "Projection boîte"
#: scene/3d/reflection_probe.cpp
-#, fuzzy
msgid "Enable Shadows"
-msgstr "Activer l'alignement"
+msgstr "Activer les ombres"
#: scene/3d/reflection_probe.cpp
-#, fuzzy
msgid "Ambient Color"
-msgstr "Prélever une couleur"
+msgstr "Couleur ambiante"
#: scene/3d/reflection_probe.cpp
-#, fuzzy
msgid "Ambient Energy"
-msgstr "Couleurs d'émission"
+msgstr "Énergie ambiante"
#: scene/3d/reflection_probe.cpp
#, fuzzy
@@ -23984,9 +23369,8 @@ msgid "Use As Steering"
msgstr ""
#: scene/3d/vehicle_body.cpp
-#, fuzzy
msgid "Wheel"
-msgstr "Molette vers le haut."
+msgstr "Molette"
#: scene/3d/vehicle_body.cpp
msgid "Roll Influence"
@@ -24022,9 +23406,8 @@ msgid "Material Override"
msgstr "Redéfinition"
#: scene/3d/visual_instance.cpp
-#, fuzzy
msgid "Material Overlay"
-msgstr "Changements de matériau :"
+msgstr "Superposition de Matériau"
#: scene/3d/visual_instance.cpp
#, fuzzy
@@ -24032,9 +23415,8 @@ msgid "Cast Shadow"
msgstr "Créer un nœud Shader"
#: scene/3d/visual_instance.cpp
-#, fuzzy
msgid "Extra Cull Margin"
-msgstr "Arguments supplémentaires :"
+msgstr "Marge supplémentaire de détermination des faces cachées"
#: scene/3d/visual_instance.cpp
#, fuzzy
@@ -24106,14 +23488,12 @@ msgid "Mix Mode"
msgstr "Mélanger le nœud"
#: scene/animation/animation_blend_tree.cpp
-#, fuzzy
msgid "Fadein Time"
-msgstr "Durée du fondu (s) :"
+msgstr "Durée du fondu entrant"
#: scene/animation/animation_blend_tree.cpp
-#, fuzzy
msgid "Fadeout Time"
-msgstr "Durée du fondu (s) :"
+msgstr "Durée du fondu sortant"
#: scene/animation/animation_blend_tree.cpp
msgid "Auto Restart"
@@ -24128,9 +23508,8 @@ msgid "Delay"
msgstr ""
#: scene/animation/animation_blend_tree.cpp
-#, fuzzy
msgid "Random Delay"
-msgstr "Inclinaison aléatoire :"
+msgstr "Retard aléatoire"
#: scene/animation/animation_blend_tree.cpp
#, fuzzy
@@ -24138,9 +23517,8 @@ msgid "Add Amount"
msgstr "Quantité"
#: scene/animation/animation_blend_tree.cpp
-#, fuzzy
msgid "Blend Amount"
-msgstr "Quantité :"
+msgstr "Quantité de mélange"
#: scene/animation/animation_blend_tree.cpp
#, fuzzy
@@ -24154,9 +23532,8 @@ msgstr "Ajouter un port d'entrée"
#: scene/animation/animation_blend_tree.cpp
#: scene/animation/animation_node_state_machine.cpp
-#, fuzzy
msgid "Xfade Time"
-msgstr "Durée du fondu (s) :"
+msgstr "Durée du fondu croisé"
#: scene/animation/animation_node_state_machine.cpp
#, fuzzy
@@ -24568,9 +23945,8 @@ msgid "Pass On Modal Close Click"
msgstr ""
#: scene/gui/control.cpp
-#, fuzzy
msgid "Size Flags"
-msgstr "Taille :"
+msgstr "Drapeaux de Taille"
#: scene/gui/control.cpp
#, fuzzy
@@ -24622,9 +23998,8 @@ msgid "Scroll Offset"
msgstr "Décalage du Défilement"
#: scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Snap Distance"
-msgstr "Choisissez distance :"
+msgstr "Distance d'arrondissage"
#: scene/gui/graph_edit.cpp
#, fuzzy
@@ -24761,9 +24136,8 @@ msgid "Secret"
msgstr ""
#: scene/gui/line_edit.cpp
-#, fuzzy
msgid "Secret Character"
-msgstr "Caractères valides :"
+msgstr "Caractère secret"
#: scene/gui/line_edit.cpp
msgid "Expand To Text Length"
@@ -24820,7 +24194,7 @@ msgstr ""
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Caret"
-msgstr ""
+msgstr "Caret"
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Blink"
@@ -24997,9 +24371,8 @@ msgid "Meta Underlined"
msgstr ""
#: scene/gui/rich_text_label.cpp
-#, fuzzy
msgid "Tab Size"
-msgstr "Taille :"
+msgstr "Taille de tabulation"
#: scene/gui/rich_text_label.cpp
#, fuzzy
@@ -25020,9 +24393,8 @@ msgid "Selection Enabled"
msgstr "Sélection uniquement"
#: scene/gui/rich_text_label.cpp scene/gui/text_edit.cpp
-#, fuzzy
msgid "Override Selected Font Color"
-msgstr "Configurer le profil sélectionné :"
+msgstr "Remplacer la couleur de police sélectionnée"
#: scene/gui/rich_text_label.cpp
#, fuzzy
@@ -25073,9 +24445,8 @@ msgid "Tick Count"
msgstr "Prélever une couleur"
#: scene/gui/slider.cpp
-#, fuzzy
msgid "Ticks On Borders"
-msgstr "dans l'ordre :"
+msgstr "Encoches aux bordures"
#: scene/gui/spin_box.cpp
msgid "Prefix"
@@ -25086,9 +24457,8 @@ msgid "Suffix"
msgstr "Suffixe"
#: scene/gui/split_container.cpp
-#, fuzzy
msgid "Split Offset"
-msgstr "Décalage de la grille :"
+msgstr "Décalage des écarts"
#: scene/gui/split_container.cpp scene/gui/tree.cpp
#, fuzzy
@@ -25105,9 +24475,8 @@ msgid "Tab Align"
msgstr ""
#: scene/gui/tab_container.cpp scene/gui/tabs.cpp
-#, fuzzy
msgid "Current Tab"
-msgstr "Actuel :"
+msgstr "Onglet actuel"
#: scene/gui/tab_container.cpp
#, fuzzy
@@ -25149,9 +24518,8 @@ msgid "Breakpoint Gutter"
msgstr "Passer les points d'arrêt"
#: scene/gui/text_edit.cpp
-#, fuzzy
msgid "Fold Gutter"
-msgstr "Dossier :"
+msgstr "Replier le bandeau"
#: scene/gui/text_edit.cpp
#, fuzzy
@@ -25253,9 +24621,8 @@ msgid "Initial Angle"
msgstr "Initialiser"
#: scene/gui/texture_progress.cpp
-#, fuzzy
msgid "Fill Degrees"
-msgstr "Rotation de %s degrés."
+msgstr "Degrés remplis"
#: scene/gui/texture_progress.cpp scene/resources/primitive_meshes.cpp
#, fuzzy
@@ -25361,9 +24728,8 @@ msgid "Max Redirects"
msgstr ""
#: scene/main/http_request.cpp
-#, fuzzy
msgid "Timeout"
-msgstr "Délai dépassé."
+msgstr "Délai dépassé"
#: scene/main/node.cpp
msgid ""
@@ -25636,9 +25002,8 @@ msgid "Debug Draw"
msgstr "Débogage"
#: scene/main/viewport.cpp
-#, fuzzy
msgid "Render Target"
-msgstr "Moteur de rendu :"
+msgstr "Rendre la cible"
#: scene/main/viewport.cpp
msgid "V Flip"
@@ -25811,9 +25176,8 @@ msgid "Font Color Disabled"
msgstr "Âgrafe désactivée"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "H Separation"
-msgstr "Séparation :"
+msgstr "Séparation H"
#: scene/resources/default_theme/default_theme.cpp
#, fuzzy
@@ -25901,14 +25265,12 @@ msgid "Font Outline Modulate"
msgstr "Forcer la modulation blanche"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Shadow Offset X"
-msgstr "Décalage X de la grille :"
+msgstr "Décalage X de l'ombre"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Shadow Offset Y"
-msgstr "Décalage Y de la grille :"
+msgstr "Décalage Y de l'ombre"
#: scene/resources/default_theme/default_theme.cpp
#, fuzzy
@@ -25966,14 +25328,12 @@ msgid "Space"
msgstr "Scène principale"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Folded"
-msgstr "Dossier :"
+msgstr "Replié"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Fold"
-msgstr "Dossier :"
+msgstr "Replier"
#: scene/resources/default_theme/default_theme.cpp
msgid "Font Color Readonly"
@@ -26092,14 +25452,12 @@ msgid "Close Highlight"
msgstr "Éclairage direct"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Close H Offset"
-msgstr "Décalage de la grille :"
+msgstr "Fermer décalage H"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Close V Offset"
-msgstr "Décalage de la grille :"
+msgstr "Fermer décalage V"
#: scene/resources/default_theme/default_theme.cpp
#, fuzzy
@@ -26127,9 +25485,8 @@ msgid "Labeled Separator Right"
msgstr "Séparateur nommé"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Font Separator"
-msgstr "Opérateur de couleur."
+msgstr "Séparateur de police"
#: scene/resources/default_theme/default_theme.cpp
#, fuzzy
@@ -26137,14 +25494,12 @@ msgid "Font Color Accel"
msgstr "Renommer l'item de couleur"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Font Color Separator"
-msgstr "Opérateur de couleur."
+msgstr "Séparateur de couleur de police"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "V Separation"
-msgstr "Séparation :"
+msgstr "Séparation V"
#: scene/resources/default_theme/default_theme.cpp
#, fuzzy
@@ -26192,9 +25547,8 @@ msgid "Title Offset"
msgstr "Décalage d’Octet"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Close Offset"
-msgstr "Décalage de la grille :"
+msgstr "Fermer de décalage"
#: scene/resources/default_theme/default_theme.cpp
#, fuzzy
@@ -26324,9 +25678,8 @@ msgid "Icon Margin"
msgstr "Définir la marge"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Line Separation"
-msgstr "Séparation :"
+msgstr "Séparation de line"
#: scene/resources/default_theme/default_theme.cpp
#, fuzzy
@@ -26386,9 +25739,8 @@ msgid "Large"
msgstr "Cible"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Folder"
-msgstr "Dossier :"
+msgstr "Dossier"
#: scene/resources/default_theme/default_theme.cpp
#, fuzzy
@@ -26426,9 +25778,8 @@ msgid "Label Width"
msgstr "Étendu à Gauche"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Screen Picker"
-msgstr "Opérateur d'écran."
+msgstr "Sélecteur d'écran"
#: scene/resources/default_theme/default_theme.cpp
#, fuzzy
@@ -26489,14 +25840,12 @@ msgid "Mono Font"
msgstr "Police Principale"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Table H Separation"
-msgstr "Séparation :"
+msgstr "Séparation H de table"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Table V Separation"
-msgstr "Séparation :"
+msgstr "Séparation V de table"
#: scene/resources/default_theme/default_theme.cpp
#, fuzzy
@@ -26661,7 +26010,7 @@ msgstr "Condition"
#: scene/resources/environment.cpp
msgid "Fog"
-msgstr ""
+msgstr "Brouillard"
#: scene/resources/environment.cpp
msgid "Sun Color"
@@ -26757,14 +26106,12 @@ msgid "Max Steps"
msgstr "Pas"
#: scene/resources/environment.cpp
-#, fuzzy
msgid "Fade In"
-msgstr "Fondu entrant (s) :"
+msgstr "Fondu entrant"
#: scene/resources/environment.cpp
-#, fuzzy
msgid "Fade Out"
-msgstr "Fondu sortant (s) :"
+msgstr "Fondu sortant"
#: scene/resources/environment.cpp
#, fuzzy
@@ -26843,54 +26190,52 @@ msgstr "2"
#: scene/resources/environment.cpp
#: servers/audio/effects/audio_effect_chorus.cpp
msgid "3"
-msgstr ""
+msgstr "3"
#: scene/resources/environment.cpp
#: servers/audio/effects/audio_effect_chorus.cpp
msgid "4"
-msgstr ""
+msgstr "4"
#: scene/resources/environment.cpp
msgid "5"
-msgstr ""
+msgstr "5"
#: scene/resources/environment.cpp
msgid "6"
-msgstr ""
+msgstr "6"
#: scene/resources/environment.cpp
msgid "7"
-msgstr ""
+msgstr "7"
#: scene/resources/environment.cpp
msgid "Bloom"
-msgstr ""
+msgstr "Flou lumineux"
#: scene/resources/environment.cpp
msgid "HDR Threshold"
-msgstr ""
+msgstr "Seuil HDR"
#: scene/resources/environment.cpp
msgid "HDR Luminance Cap"
-msgstr ""
+msgstr "Limite de luminance HDR"
#: scene/resources/environment.cpp
-#, fuzzy
msgid "HDR Scale"
-msgstr "Mode mise à l'échelle"
+msgstr "Échelle HDR"
#: scene/resources/environment.cpp
msgid "Bicubic Upscale"
-msgstr ""
+msgstr "Redimensionnement Bicubique"
#: scene/resources/environment.cpp
msgid "Adjustments"
-msgstr ""
+msgstr "Ajustements"
#: scene/resources/environment.cpp
-#, fuzzy
msgid "Brightness"
-msgstr "Lumière"
+msgstr "Luminosité"
#: scene/resources/environment.cpp
msgid "Saturation"
@@ -26898,22 +26243,19 @@ msgstr "Saturation"
#: scene/resources/environment.cpp
msgid "Color Correction"
-msgstr "Correction de Couleur"
+msgstr "Correction des couleurs"
#: scene/resources/font.cpp
-#, fuzzy
msgid "Ascent"
-msgstr "Récents :"
+msgstr "Inclinaison"
#: scene/resources/font.cpp
-#, fuzzy
msgid "Distance Field"
-msgstr "Mode Sans Distraction"
+msgstr "Champ de distance"
#: scene/resources/gradient.cpp
-#, fuzzy
msgid "Raw Data"
-msgstr "Profondeur"
+msgstr "Données brutes"
#: scene/resources/gradient.cpp
msgid "Offsets"
@@ -26921,62 +26263,55 @@ msgstr "Décalages"
#: scene/resources/height_map_shape.cpp
msgid "Map Width"
-msgstr ""
+msgstr "Largeur de la carte"
#: scene/resources/height_map_shape.cpp
-#, fuzzy
msgid "Map Depth"
-msgstr "Profondeur"
+msgstr "Profondeur de la carte"
#: scene/resources/height_map_shape.cpp
-#, fuzzy
msgid "Map Data"
-msgstr "Profondeur"
+msgstr "Données de la carte"
#: scene/resources/line_shape_2d.cpp
msgid "D"
-msgstr ""
+msgstr "D"
#: scene/resources/material.cpp
-#, fuzzy
msgid "Next Pass"
-msgstr "Plan suivant"
+msgstr "Passe suivante"
#: scene/resources/material.cpp
msgid "Use Shadow To Opacity"
msgstr ""
#: scene/resources/material.cpp
-#, fuzzy
msgid "Unshaded"
-msgstr "Afficher sans ombrage"
+msgstr "Sans ombrage"
#: scene/resources/material.cpp
-#, fuzzy
msgid "Vertex Lighting"
-msgstr "Éclairage direct"
+msgstr "Éclairage de sommet"
#: scene/resources/material.cpp
-#, fuzzy
msgid "Use Point Size"
-msgstr "Vue de devant"
+msgstr "Utiliser la taille de point"
#: scene/resources/material.cpp
msgid "World Triplanar"
-msgstr ""
+msgstr "Monde Triplanaire"
#: scene/resources/material.cpp
msgid "Albedo Tex Force sRGB"
-msgstr ""
+msgstr "Forcer sRGB dans la texture d'albédo"
#: scene/resources/material.cpp
msgid "Do Not Receive Shadows"
-msgstr ""
+msgstr "Ne pas recevoir d'ombres"
#: scene/resources/material.cpp
-#, fuzzy
msgid "Disable Ambient Light"
-msgstr "Indenter vers la droite"
+msgstr "Désactiver la lumière ambiante"
#: scene/resources/material.cpp
msgid "Ensure Correct Normals"
@@ -26984,70 +26319,63 @@ msgstr "Assurer des Normales Correctes"
#: scene/resources/material.cpp
msgid "Albedo Tex MSDF"
-msgstr ""
+msgstr "Texture d'albédo MSDF"
#: scene/resources/material.cpp
-#, fuzzy
msgid "Vertex Color"
-msgstr "Vertex"
+msgstr "Couleur de sommet"
#: scene/resources/material.cpp
msgid "Use As Albedo"
-msgstr ""
+msgstr "Utiliser comme albédo"
#: scene/resources/material.cpp
msgid "Is sRGB"
-msgstr ""
+msgstr "Est sRGB"
#: scene/resources/material.cpp servers/visual_server.cpp
msgid "Parameters"
msgstr "Paramètres"
#: scene/resources/material.cpp
-#, fuzzy
msgid "Diffuse Mode"
-msgstr "Mode navigation"
+msgstr "Mode diffus"
#: scene/resources/material.cpp
-#, fuzzy
msgid "Specular Mode"
-msgstr "Mode Règle"
+msgstr "Mode spéculaire"
#: scene/resources/material.cpp
-#, fuzzy
msgid "Depth Draw Mode"
-msgstr "Mode d’interpolation"
+msgstr "Mode de dessin en profondeur"
#: scene/resources/material.cpp
-#, fuzzy
msgid "Line Width"
-msgstr "Étendu à Gauche"
+msgstr "Largeur de ligne"
#: scene/resources/material.cpp
-#, fuzzy
msgid "Point Size"
-msgstr "Vue de devant"
+msgstr "Taille de point"
#: scene/resources/material.cpp
msgid "Billboard Mode"
-msgstr "Mode billboard"
+msgstr "Mode Billboard"
#: scene/resources/material.cpp
msgid "Billboard Keep Scale"
-msgstr "Garder l'échelle du billboard"
+msgstr "Garder l'échelle du Billboard"
#: scene/resources/material.cpp
msgid "Grow"
-msgstr ""
+msgstr "Croître"
#: scene/resources/material.cpp
-#, fuzzy
msgid "Grow Amount"
-msgstr "Quantité :"
+msgstr "Quantité de croissance"
#: scene/resources/material.cpp
msgid "Use Alpha Scissor"
-msgstr ""
+msgstr "Utiliser la découpe alpha"
#: scene/resources/material.cpp
#, fuzzy
@@ -27066,7 +26394,7 @@ msgstr "Image %"
#: scene/resources/material.cpp
msgid "Albedo"
-msgstr ""
+msgstr "Albédo"
#: scene/resources/material.cpp
msgid "Metallic"
@@ -27092,7 +26420,7 @@ msgstr ""
#: scene/resources/material.cpp
msgid "Rim"
-msgstr "Bordure"
+msgstr "Bord"
#: scene/resources/material.cpp
#, fuzzy
@@ -27216,9 +26544,8 @@ msgid "Color Format"
msgstr "Format de Couleur"
#: scene/resources/multimesh.cpp
-#, fuzzy
msgid "Transform Format"
-msgstr "Transformation annulée."
+msgstr "Format de transformation"
#: scene/resources/multimesh.cpp
msgid "Custom Data Format"
@@ -27234,9 +26561,8 @@ msgid "Visible Instance Count"
msgstr ""
#: scene/resources/navigation_mesh.cpp
-#, fuzzy
msgid "Sampling"
-msgstr "Mise à l'échelle :"
+msgstr "Échantillonnage"
#: scene/resources/navigation_mesh.cpp
#, fuzzy
@@ -27244,9 +26570,8 @@ msgid "Partition Type"
msgstr "Définir type de variable"
#: scene/resources/navigation_mesh.cpp
-#, fuzzy
msgid "Parsed Geometry Type"
-msgstr "Analyse de la géométrie..."
+msgstr "Type de la géométrie analysée"
#: scene/resources/navigation_mesh.cpp
msgid "Source Geometry Mode"
@@ -27303,9 +26628,8 @@ msgid "Details"
msgstr "Afficher par défaut"
#: scene/resources/navigation_mesh.cpp
-#, fuzzy
msgid "Sample Distance"
-msgstr "Choisissez distance :"
+msgstr "Échantillonner la distance"
#: scene/resources/navigation_mesh.cpp
#, fuzzy
@@ -27376,12 +26700,10 @@ msgid "Color Modifier"
msgstr "Ralentissement de la vue libre"
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Point Texture"
-msgstr "Points d'Émission :"
+msgstr "Texture ponctuelle"
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Normal Texture"
msgstr "Texture Normale"
@@ -27413,9 +26735,8 @@ msgid "Absorbent"
msgstr ""
#: scene/resources/plane_shape.cpp
-#, fuzzy
msgid "Plane"
-msgstr "Plan :"
+msgstr "Plan"
#: scene/resources/primitive_meshes.cpp
#, fuzzy
@@ -27489,9 +26810,8 @@ msgid "Bone"
msgstr "Os"
#: scene/resources/sky.cpp
-#, fuzzy
msgid "Radiance Size"
-msgstr "Taille du contour :"
+msgstr "Taille du rayonnement"
#: scene/resources/sky.cpp
msgid "Panorama"
@@ -27783,9 +27103,8 @@ msgid "Default Cell Height"
msgstr "En période de test"
#: scene/resources/world.cpp scene/resources/world_2d.cpp
-#, fuzzy
msgid "Default Edge Connection Margin"
-msgstr "Modifier la connexion :"
+msgstr "Marge de connexion des bords par défaut"
#: scene/resources/world_2d.cpp
msgid "Canvas"
@@ -27939,11 +27258,11 @@ msgstr "Ressource"
#: servers/audio/effects/audio_effect_limiter.cpp
msgid "Ceiling dB"
-msgstr ""
+msgstr "Plafond de dB"
#: servers/audio/effects/audio_effect_limiter.cpp
msgid "Threshold dB"
-msgstr ""
+msgstr "Seuil de dB"
#: servers/audio/effects/audio_effect_limiter.cpp
msgid "Soft Clip dB"
@@ -27955,37 +27274,36 @@ msgstr ""
#: servers/audio/effects/audio_effect_phaser.cpp
msgid "Range Min Hz"
-msgstr ""
+msgstr "Borne inférieure de la plage (Hz)"
#: servers/audio/effects/audio_effect_phaser.cpp
msgid "Range Max Hz"
-msgstr ""
+msgstr "Borne supérieure de la plage (Hz)"
#: servers/audio/effects/audio_effect_pitch_shift.cpp
msgid "Oversampling"
-msgstr ""
+msgstr "Suréchantillonnage"
#: servers/audio/effects/audio_effect_pitch_shift.cpp
#: servers/audio/effects/audio_effect_spectrum_analyzer.cpp
msgid "FFT Size"
-msgstr "Taille FFT"
+msgstr "Taille des FFTs"
#: servers/audio/effects/audio_effect_reverb.cpp
msgid "Predelay"
-msgstr ""
+msgstr "Pré-retarder"
#: servers/audio/effects/audio_effect_reverb.cpp
msgid "Msec"
-msgstr ""
+msgstr "Millisec"
#: servers/audio/effects/audio_effect_reverb.cpp
msgid "Room Size"
-msgstr ""
+msgstr "Taille de la salle"
#: servers/audio/effects/audio_effect_reverb.cpp
-#, fuzzy
msgid "High-pass"
-msgstr "Contourner"
+msgstr "Passe-haut"
#: servers/audio/effects/audio_effect_spectrum_analyzer.cpp
msgid "Tap Back Pos"
@@ -27996,27 +27314,24 @@ msgid "Pan Pullout"
msgstr ""
#: servers/audio/effects/audio_effect_stereo_enhance.cpp
-#, fuzzy
msgid "Time Pullout (ms)"
-msgstr "Délai dépassé."
+msgstr "Temps de retrait (ms)"
#: servers/audio/effects/audio_effect_stereo_enhance.cpp
msgid "Surround"
-msgstr ""
+msgstr "Surround"
#: servers/audio_server.cpp
-#, fuzzy
msgid "Enable Audio Input"
-msgstr "Renommer le bus audio"
+msgstr "Activer l’entrée audio"
#: servers/audio_server.cpp
-#, fuzzy
msgid "Output Latency"
-msgstr "Sortie"
+msgstr "Latence de sortie"
#: servers/audio_server.cpp
msgid "Channel Disable Threshold dB"
-msgstr ""
+msgstr "Désactiver le seuil de dB du canal"
#: servers/audio_server.cpp
#, fuzzy
@@ -28025,43 +27340,39 @@ msgstr "Changer le temps de mélange"
#: servers/audio_server.cpp
msgid "Video Delay Compensation (ms)"
-msgstr ""
+msgstr "Compensation de retard vidéo (ms)"
#: servers/audio_server.cpp
-#, fuzzy
msgid "Bus Count"
-msgstr "Ajouter un port d'entrée"
+msgstr "Nombre de ports"
#: servers/audio_server.cpp
-#, fuzzy
msgid "Capture Device"
-msgstr "Capturer depuis Pixel"
+msgstr "Périphérique de capture"
#: servers/audio_server.cpp
-#, fuzzy
msgid "Global Rate Scale"
-msgstr "Variable globale"
+msgstr "Echelle de débit global"
#: servers/camera/camera_feed.cpp
msgid "Feed"
-msgstr ""
+msgstr "Flux"
#: servers/camera/camera_feed.cpp
-#, fuzzy
msgid "Is Active"
-msgstr "Perspective"
+msgstr "Est active"
#: servers/physics/space_sw.cpp servers/physics_2d/space_2d_sw.cpp
msgid "Sleep Threshold Linear"
-msgstr ""
+msgstr "Seuil linéaire de veille"
#: servers/physics/space_sw.cpp servers/physics_2d/space_2d_sw.cpp
msgid "Sleep Threshold Angular"
-msgstr ""
+msgstr "Seuil angulaire de veille"
#: servers/physics/space_sw.cpp servers/physics_2d/space_2d_sw.cpp
msgid "Time Before Sleep"
-msgstr ""
+msgstr "Temps avant veille"
#: servers/physics_2d/physics_2d_server_sw.cpp
msgid "BP Hash Table Size"
@@ -28073,48 +27384,43 @@ msgstr ""
#: servers/physics_2d_server.cpp servers/physics_server.cpp
msgid "Inverse Mass"
-msgstr ""
+msgstr "Masse inverse"
#: servers/physics_2d_server.cpp servers/physics_server.cpp
-#, fuzzy
msgid "Inverse Inertia"
-msgstr "Vue libre gauche"
+msgstr "Inertie inverse"
#: servers/physics_2d_server.cpp servers/physics_server.cpp
msgid "Total Angular Damp"
-msgstr ""
+msgstr "Amortissage angulaire total"
#: servers/physics_2d_server.cpp servers/physics_server.cpp
-#, fuzzy
msgid "Total Linear Damp"
-msgstr "Linéaire"
+msgstr "Amortissage linéaire total"
#: servers/physics_2d_server.cpp servers/physics_server.cpp
-#, fuzzy
msgid "Total Gravity"
-msgstr "Aperçu par défaut"
+msgstr "Gravité totale"
#: servers/physics_2d_server.cpp servers/physics_server.cpp
-#, fuzzy
msgid "Linear Velocity"
-msgstr "Initialiser"
+msgstr "Vélocité linéaire"
#: servers/physics_2d_server.cpp servers/physics_server.cpp
msgid "Exclude"
-msgstr ""
+msgstr "Exclure"
#: servers/physics_2d_server.cpp servers/physics_server.cpp
msgid "Shape RID"
-msgstr ""
+msgstr "RID de forme"
#: servers/physics_2d_server.cpp servers/physics_server.cpp
-#, fuzzy
msgid "Collide With Bodies"
-msgstr "Mode collision"
+msgstr "Collisions avec les corps"
#: servers/physics_2d_server.cpp servers/physics_server.cpp
msgid "Collide With Areas"
-msgstr ""
+msgstr "Collisions avec les zones"
#: servers/physics_2d_server.cpp servers/physics_server.cpp
msgid "Motion Remainder"
@@ -28356,14 +27662,12 @@ msgid "Use Software Skinning"
msgstr ""
#: servers/visual_server.cpp
-#, fuzzy
msgid "Ninepatch Mode"
-msgstr "Mode d’interpolation"
+msgstr "Mode Ninepatch"
#: servers/visual_server.cpp
-#, fuzzy
msgid "OpenGL"
-msgstr "Ouvrir"
+msgstr "OpenGL"
#: servers/visual_server.cpp
msgid "Batching Send Null"
@@ -28388,12 +27692,11 @@ msgstr "Traitement en lot"
#: servers/visual_server.cpp
msgid "Use Batching"
-msgstr ""
+msgstr "Utiliser le traitement en lot"
#: servers/visual_server.cpp
-#, fuzzy
msgid "Use Batching In Editor"
-msgstr "Mise à jour de l'éditeur"
+msgstr "Utiliser le traitement en lot dans l'éditeur"
#: servers/visual_server.cpp
msgid "Single Rect Fallback"
@@ -28417,7 +27720,7 @@ msgstr "Nombre Maximal d'Éléments Joints"
#: servers/visual_server.cpp
msgid "Batch Buffer Size"
-msgstr ""
+msgstr "Taille de tampon des lots"
#: servers/visual_server.cpp
msgid "Item Reordering Lookahead"
@@ -28428,21 +27731,20 @@ msgid "Flash Batching"
msgstr ""
#: servers/visual_server.cpp
-#, fuzzy
msgid "Diagnose Frame"
-msgstr "Coller une image"
+msgstr "Diagnostiquer la trame"
#: servers/visual_server.cpp
msgid "GLES2"
-msgstr ""
+msgstr "GLES2"
#: servers/visual_server.cpp
msgid "Compatibility"
-msgstr ""
+msgstr "Compatibilité"
#: servers/visual_server.cpp
msgid "Disable Half Float"
-msgstr ""
+msgstr "Désactiver les demi Float"
#: servers/visual_server.cpp
#, fuzzy
@@ -28450,31 +27752,28 @@ msgid "Enable High Float"
msgstr "Activer la priorité"
#: servers/visual_server.cpp
-#, fuzzy
msgid "Precision"
-msgstr "Expression"
+msgstr "Précision"
#: servers/visual_server.cpp
msgid "UV Contract"
-msgstr ""
+msgstr "Contraction UV"
#: servers/visual_server.cpp
msgid "UV Contract Amount"
-msgstr ""
+msgstr "Quantité de contraction UV"
#: servers/visual_server.cpp
-#, fuzzy
msgid "Use Simple PVS"
-msgstr "Utiliser le magnétisme d'échelle"
+msgstr "Utiliser PVS simple"
#: servers/visual_server.cpp
msgid "PVS Logging"
-msgstr ""
+msgstr "Journal PVS"
#: servers/visual_server.cpp
-#, fuzzy
msgid "Use Signals"
-msgstr "Signaux"
+msgstr "Utiliser les signaux"
#: servers/visual_server.cpp
#, fuzzy
@@ -28493,27 +27792,24 @@ msgstr "Voir la suppression de l'occlusion"
#: servers/visual_server.cpp
msgid "Max Active Spheres"
-msgstr ""
+msgstr "Nombre maximum de sphères actives"
#: servers/visual_server.cpp
-#, fuzzy
msgid "Max Active Polygons"
-msgstr "Déplacer le polygone"
+msgstr "Nombre maximum de polygones actifs"
#: servers/visual_server.cpp
-#, fuzzy
msgid "Shader Compilation Mode"
-msgstr "Mode d’interpolation"
+msgstr "Mode de compilation des shaders"
#: servers/visual_server.cpp
msgid "Max Simultaneous Compiles"
-msgstr ""
+msgstr "Nombre de compilations simultanées"
#: servers/visual_server.cpp
msgid "Log Active Async Compiles Count"
msgstr ""
#: servers/visual_server.cpp
-#, fuzzy
msgid "Shader Cache Size (MB)"
-msgstr "Changer la taille d'une caméra"
+msgstr "Taille du cache de shader (Mo)"
diff --git a/editor/translations/ga.po b/editor/translations/ga.po
index 17fc0b03fa..87e005f5f3 100644
--- a/editor/translations/ga.po
+++ b/editor/translations/ga.po
@@ -2720,8 +2720,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "CrannBeochan"
#: editor/editor_export.cpp
msgid "Completed successfully."
@@ -19452,14 +19453,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
+msgid "rcedit failed to modify executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
@@ -19480,14 +19480,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
+msgid "Signtool failed to sign executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
diff --git a/editor/translations/gl.po b/editor/translations/gl.po
index 191093a45d..29db0e8063 100644
--- a/editor/translations/gl.po
+++ b/editor/translations/gl.po
@@ -2851,7 +2851,7 @@ msgstr ""
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "Copiar Ruta do Nodo"
#: editor/editor_export.cpp
@@ -20550,15 +20550,15 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Extensión inválida."
#: platform/windows/export/export.cpp
msgid "Could not find signtool executable at \"%s\"."
@@ -20580,15 +20580,15 @@ msgstr "Nome inválido."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Extensión inválida."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/he.po b/editor/translations/he.po
index 2003351f93..abaada7880 100644
--- a/editor/translations/he.po
+++ b/editor/translations/he.po
@@ -2807,7 +2807,7 @@ msgstr ""
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "העתקת נתיב המפרק"
#: editor/editor_export.cpp
@@ -20707,15 +20707,15 @@ msgstr "×œ× × ×™×ª×Ÿ לפתוח תבנית לייצו×:"
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "סיומת ×œ× ×—×•×§×™×ª."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20739,15 +20739,15 @@ msgstr "×©× ×©×’×•×™."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "סיומת ×œ× ×—×•×§×™×ª."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/hi.po b/editor/translations/hi.po
index 7faa61ab12..e5a41404d0 100644
--- a/editor/translations/hi.po
+++ b/editor/translations/hi.po
@@ -2804,8 +2804,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "खंड कौपी कीजिये"
#: editor/editor_export.cpp
#, fuzzy
@@ -20309,15 +20310,15 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "गलत फॉणà¥à¤Ÿ का आकार |"
#: platform/windows/export/export.cpp
msgid "Could not find signtool executable at \"%s\"."
@@ -20339,15 +20340,15 @@ msgstr "अमानà¥à¤¯ नाम."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "गलत फॉणà¥à¤Ÿ का आकार |"
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/hr.po b/editor/translations/hr.po
index 6d2b3b07da..e473c6556c 100644
--- a/editor/translations/hr.po
+++ b/editor/translations/hr.po
@@ -2773,8 +2773,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "Animacija"
#: editor/editor_export.cpp
#, fuzzy
@@ -19817,15 +19818,15 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Nevažeće ime."
#: platform/windows/export/export.cpp
msgid "Could not find signtool executable at \"%s\"."
@@ -19847,15 +19848,15 @@ msgstr "Nevažeće ime."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Nevažeće ime."
#: platform/windows/export/export.cpp
msgid "Failed to remove temporary file \"%s\"."
diff --git a/editor/translations/hu.po b/editor/translations/hu.po
index cc7024a260..b35be76368 100644
--- a/editor/translations/hu.po
+++ b/editor/translations/hu.po
@@ -2872,7 +2872,7 @@ msgstr ""
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "Node Útvonal Másolása"
#: editor/editor_export.cpp
@@ -20510,15 +20510,15 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Érvénytelen kiterjesztés."
#: platform/windows/export/export.cpp
msgid "Could not find signtool executable at \"%s\"."
@@ -20540,15 +20540,15 @@ msgstr "Érvénytelen név."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Érvénytelen kiterjesztés."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/id.po b/editor/translations/id.po
index 8c447326e3..7d839357cd 100644
--- a/editor/translations/id.po
+++ b/editor/translations/id.po
@@ -45,8 +45,8 @@ msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-07-23 03:57+0000\n"
-"Last-Translator: FellowMustard <rachmawanng33@gmail.com>\n"
+"PO-Revision-Date: 2022-07-31 18:34+0000\n"
+"Last-Translator: ProgrammerIndonesia 44 <elo.jhy@gmail.com>\n"
"Language-Team: Indonesian <https://hosted.weblate.org/projects/godot-engine/"
"godot/id/>\n"
"Language: id\n"
@@ -427,9 +427,8 @@ msgid "Command"
msgstr "Perintah"
#: core/os/input_event.cpp
-#, fuzzy
msgid "Physical"
-msgstr " (Secara fisik)"
+msgstr "(Secara fisik)"
#: core/os/input_event.cpp scene/2d/touch_screen_button.cpp
#: scene/gui/base_button.cpp scene/gui/texture_button.cpp
@@ -2805,13 +2804,12 @@ msgstr ""
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "Salin Lokasi Node"
#: editor/editor_export.cpp
-#, fuzzy
msgid "Completed successfully."
-msgstr "Paket Sukses Terpasang!"
+msgstr "Sukses."
#: editor/editor_export.cpp
#, fuzzy
@@ -3290,9 +3288,8 @@ msgid "Save a File"
msgstr "Simpan sebuah File"
#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp
-#, fuzzy
msgid "Access"
-msgstr "Sukses!"
+msgstr "Akses"
#: editor/editor_file_dialog.cpp editor/editor_settings.cpp
#, fuzzy
@@ -12382,9 +12379,8 @@ msgid "Available Node-based types:"
msgstr "Profil yang Tersedia:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Type name is empty!"
-msgstr "Nama berkas kosong."
+msgstr "Nama tipe kosong!"
#: editor/plugins/theme_editor_plugin.cpp
#, fuzzy
@@ -19289,9 +19285,8 @@ msgid "Could not find keystore, unable to export."
msgstr "Tidak dapat menemukan keystore, tidak bisa ekspor."
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "Could not start apksigner executable."
-msgstr "Tidak dapat memulai subproses!"
+msgstr "Tidak dapat memulai apksigner."
#: platform/android/export/export_plugin.cpp
msgid "'apksigner' returned with error #%d"
@@ -19324,9 +19319,8 @@ msgid "Invalid filename! Android APK requires the *.apk extension."
msgstr "Nama berkas tidak valid! APK Android memerlukan ekstensi *.apk ."
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "Unsupported export format!"
-msgstr "Format ekspor tidak didukung!\n"
+msgstr "Format ekspor tidak didukung!"
#: platform/android/export/export_plugin.cpp
msgid ""
@@ -19337,15 +19331,12 @@ msgstr ""
"versinya. Silakan pasang ulang dari menu 'Proyek'."
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid ""
"Android build version mismatch: Template installed: %s, Godot version: %s. "
"Please reinstall Android build template from 'Project' menu."
msgstr ""
-"Versi build Android tidak cocok:\n"
-" Templat terpasang: %s\n"
-" Versi Godot: %s\n"
-"Silakan pasang ulang templat build Android dari menu 'Project'."
+"Versi build Android tidak cocok: Templat terpasang: %s, Versi Godot: %s. "
+"Silakan pasang ulang templat build Android dari menu 'Proyek'."
#: platform/android/export/export_plugin.cpp
msgid ""
@@ -19353,9 +19344,8 @@ msgid ""
msgstr ""
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "Could not export project files to gradle project."
-msgstr "Tidak dapat menyunting proyek gradle dalam lokasi proyek\n"
+msgstr "Tidak dapat mengekspor file proyek ke dalam lokasi proyek gradle."
#: platform/android/export/export_plugin.cpp
msgid "Could not write expansion package file!"
@@ -19366,13 +19356,12 @@ msgid "Building Android Project (gradle)"
msgstr "Membangun Proyek Android (gradle)"
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid ""
"Building of Android project failed, check output for the error. "
"Alternatively visit docs.godotengine.org for Android build documentation."
msgstr ""
-"Pembangunan proyek Android gagal, periksa output untuk galatnya.\n"
-"Atau kunjungi docs.godotengine.org untuk dokumentasi build Android."
+"Pembangunan proyek Android gagal, periksa output untuk galatnya. Atau "
+"kunjungi docs.godotengine.org untuk dokumentasi build Android."
#: platform/android/export/export_plugin.cpp
msgid "Moving output"
@@ -19397,11 +19386,8 @@ msgid "Creating APK..."
msgstr "Membuat kontur..."
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "Could not find template APK to export: \"%s\"."
-msgstr ""
-"Tidak dapat menemukan contoh APK untuk ekspor:\n"
-"%s"
+msgstr "Tidak dapat menemukan contoh APK untuk ekspor: \"%s\""
#: platform/android/export/export_plugin.cpp
msgid ""
@@ -19560,9 +19546,8 @@ msgid "Capabilities"
msgstr "Kapabilitas"
#: platform/iphone/export/export.cpp
-#, fuzzy
msgid "Access Wi-Fi"
-msgstr "Sukses!"
+msgstr "Akses Wi-Fi"
#: platform/iphone/export/export.cpp
#, fuzzy
@@ -20110,9 +20095,8 @@ msgid "Could not open icon file \"%s\"."
msgstr "Tidak dapat ekspor berkas proyek"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Could not start xcrun executable."
-msgstr "Tidak dapat memulai subproses!"
+msgstr "Tidak dapat memulai subproses xcrun."
#: platform/osx/export/export.cpp
#, fuzzy
@@ -20190,9 +20174,8 @@ msgid "DMG Creation"
msgstr "Arah"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Could not start hdiutil executable."
-msgstr "Tidak dapat memulai subproses!"
+msgstr "Tidak dapat memulai subproses hdiutil."
#: platform/osx/export/export.cpp
msgid "`hdiutil create` failed - file exists."
@@ -20274,7 +20257,7 @@ msgstr "Proyeksi"
#: platform/osx/export/export.cpp
#, fuzzy
msgid "Could not open file to read from path \"%s\"."
-msgstr "Tidak dapat menyunting proyek gradle dalam lokasi proyek\n"
+msgstr "Tidak dapat membuka file untuk membaca dari jalur \"%s\"."
#: platform/osx/export/export.cpp
msgid "Invalid bundle identifier:"
@@ -20659,15 +20642,15 @@ msgstr "Tidak dapat menemukan keystore, tidak bisa ekspor."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Ekstensi tidak valid."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20691,15 +20674,15 @@ msgstr "Nama tidak sah."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Ekstensi tidak valid."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -25445,9 +25428,8 @@ msgid "Draw 2D Outlines"
msgstr "Buat Garis Tepi"
#: scene/main/scene_tree.cpp servers/visual_server.cpp
-#, fuzzy
msgid "Reflections"
-msgstr "Arah"
+msgstr "Refleksi"
#: scene/main/scene_tree.cpp
#, fuzzy
@@ -26803,9 +26785,8 @@ msgstr ""
#: scene/resources/environment.cpp
#: servers/audio/effects/audio_effect_chorus.cpp
-#, fuzzy
msgid "2"
-msgstr "2D"
+msgstr "2"
#: scene/resources/environment.cpp
#: servers/audio/effects/audio_effect_chorus.cpp
diff --git a/editor/translations/is.po b/editor/translations/is.po
index 7a990ebd6b..512c660eef 100644
--- a/editor/translations/is.po
+++ b/editor/translations/is.po
@@ -2767,8 +2767,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "Fjarlægja val"
#: editor/editor_export.cpp
msgid "Completed successfully."
@@ -19724,14 +19725,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
+msgid "rcedit failed to modify executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
@@ -19752,14 +19752,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
+msgid "Signtool failed to sign executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
diff --git a/editor/translations/it.po b/editor/translations/it.po
index 1d89d28a99..2c9f7eb6fe 100644
--- a/editor/translations/it.po
+++ b/editor/translations/it.po
@@ -76,8 +76,8 @@ msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-07-23 03:57+0000\n"
-"Last-Translator: ale piccia <picciatialessio2@gmail.com>\n"
+"PO-Revision-Date: 2022-07-31 18:34+0000\n"
+"Last-Translator: Mirko <miknsop@gmail.com>\n"
"Language-Team: Italian <https://hosted.weblate.org/projects/godot-engine/"
"godot/it/>\n"
"Language: it\n"
@@ -473,6 +473,7 @@ msgid "Physical Scancode"
msgstr "Scancode Fisico"
#: core/os/input_event.cpp
+#, fuzzy
msgid "Unicode"
msgstr "Unicode"
@@ -900,6 +901,7 @@ msgid "Modules"
msgstr "Moduli"
#: core/register_core_types.cpp
+#, fuzzy
msgid "TCP"
msgstr "TCP"
@@ -2113,6 +2115,7 @@ msgid "Are you sure you want to remove all connections from the \"%s\" signal?"
msgstr "Sei sicuro di voler rimuovere tutte le connessioni dal segnale \"%s\"?"
#: editor/connections_dialog.cpp editor/editor_help.cpp editor/node_dock.cpp
+#, fuzzy
msgid "Signals"
msgstr "Segnali"
@@ -2811,7 +2814,7 @@ msgstr "Esportazione del progetto per la piattaforma:"
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "Completato con errori."
#: editor/editor_export.cpp
@@ -6995,6 +6998,7 @@ msgstr "Anisotropico"
#: editor/import/resource_importer_layered_texture.cpp
#: editor/import/resource_importer_texture.cpp
+#, fuzzy
msgid "sRGB"
msgstr "sRGB"
@@ -18020,7 +18024,6 @@ msgid "Expression"
msgstr "Espressione"
#: modules/visual_script/visual_script_flow_control.cpp
-#, fuzzy
msgid "Return"
msgstr "Ritorno"
@@ -18680,7 +18683,6 @@ msgid "Hand Tracking Frequency"
msgstr ""
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "Passthrough"
msgstr "Passthrough"
@@ -20336,15 +20338,15 @@ msgstr "Non è stato possibile trovare keystore, impossible esportare."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Estensione non valida."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20368,15 +20370,15 @@ msgstr "Nome non valido."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Estensione non valida."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20924,9 +20926,8 @@ msgstr ""
#: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/particles.cpp
-#, fuzzy
msgid "Fixed FPS"
-msgstr "Vedi FPS"
+msgstr "FPS fisso"
#: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/particles.cpp
@@ -26411,7 +26412,6 @@ msgid "Sky Contribution"
msgstr "Condizione"
#: scene/resources/environment.cpp
-#, fuzzy
msgid "Fog"
msgstr "Nebbia"
@@ -26758,7 +26758,7 @@ msgstr ""
#: scene/resources/material.cpp
msgid "Is sRGB"
-msgstr ""
+msgstr "È sRGB"
#: scene/resources/material.cpp servers/visual_server.cpp
#, fuzzy
@@ -26876,9 +26876,8 @@ msgid "Flowmap"
msgstr ""
#: scene/resources/material.cpp
-#, fuzzy
msgid "Ambient Occlusion"
-msgstr "Occlusione"
+msgstr "Occlusione ambientale"
#: scene/resources/material.cpp
msgid "Deep Parallax"
diff --git a/editor/translations/ja.po b/editor/translations/ja.po
index a40939f777..60458e89df 100644
--- a/editor/translations/ja.po
+++ b/editor/translations/ja.po
@@ -2822,7 +2822,7 @@ msgstr ""
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "ノードã®ãƒ‘スをコピー"
#: editor/editor_export.cpp
@@ -20462,15 +20462,15 @@ msgstr "キーストアãŒè¦‹ã¤ã‹ã‚‰ãªã„ãŸã‚ã€ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã§ãã¾
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "無効ãªå®Ÿè¡Œå¯èƒ½ãƒ•ァイルã§ã™ã€‚"
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20494,15 +20494,15 @@ msgstr "無効ãªåå‰ã§ã™ã€‚"
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "無効ãªå®Ÿè¡Œå¯èƒ½ãƒ•ァイルã§ã™ã€‚"
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/ka.po b/editor/translations/ka.po
index ae98d76c31..2e6e0e70e7 100644
--- a/editor/translations/ka.po
+++ b/editor/translations/ka.po
@@ -2847,8 +2847,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "მáƒáƒœáƒ˜áƒ¨áƒ•ნის მáƒáƒ¨áƒáƒ áƒ”ბáƒ"
#: editor/editor_export.cpp
#, fuzzy
@@ -20194,15 +20195,15 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜ ფáƒáƒœáƒ¢áƒ˜áƒ¡ ზáƒáƒ›áƒ."
#: platform/windows/export/export.cpp
msgid "Could not find signtool executable at \"%s\"."
@@ -20224,15 +20225,15 @@ msgstr "áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜ ფáƒáƒœáƒ¢áƒ˜áƒ¡ ზáƒáƒ›áƒ."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "áƒáƒ áƒáƒ¡áƒ¬áƒáƒ áƒ˜ ფáƒáƒœáƒ¢áƒ˜áƒ¡ ზáƒáƒ›áƒ."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/km.po b/editor/translations/km.po
index 4141c021e2..522cb30363 100644
--- a/editor/translations/km.po
+++ b/editor/translations/km.po
@@ -2695,8 +2695,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "Anim ផ្លាស់ប្ážáž¼ážš Transform"
#: editor/editor_export.cpp
msgid "Completed successfully."
@@ -19318,14 +19319,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
+msgid "rcedit failed to modify executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
@@ -19347,14 +19347,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
+msgid "Signtool failed to sign executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
diff --git a/editor/translations/ko.po b/editor/translations/ko.po
index af0b7e99a5..a91450dd41 100644
--- a/editor/translations/ko.po
+++ b/editor/translations/ko.po
@@ -2761,7 +2761,7 @@ msgstr ""
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "íŒŒì¼ ê²½ë¡œ 완성"
#: editor/editor_export.cpp
@@ -20420,15 +20420,15 @@ msgstr "keystore를 ì°¾ì„ ìˆ˜ 없어, 내보낼 수 없었습니다."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "ìž˜ëª»ëœ í™•ìž¥ìž."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20452,15 +20452,15 @@ msgstr "올바르지 ì•Šì€ ì´ë¦„입니다."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "ìž˜ëª»ëœ í™•ìž¥ìž."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/lt.po b/editor/translations/lt.po
index 3b1140192a..66891e3f0e 100644
--- a/editor/translations/lt.po
+++ b/editor/translations/lt.po
@@ -2806,8 +2806,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "Panaikinti pasirinkimÄ…"
#: editor/editor_export.cpp
msgid "Completed successfully."
@@ -20215,15 +20216,15 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Netinkamas šrifto dydis."
#: platform/windows/export/export.cpp
msgid "Could not find signtool executable at \"%s\"."
@@ -20245,15 +20246,15 @@ msgstr "Netinkamas šrifto dydis."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Netinkamas šrifto dydis."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/lv.po b/editor/translations/lv.po
index f134fd5b48..c00e8d1a44 100644
--- a/editor/translations/lv.po
+++ b/editor/translations/lv.po
@@ -2819,7 +2819,7 @@ msgstr ""
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "Kopēt mezgla ceļu"
#: editor/editor_export.cpp
@@ -20022,15 +20022,15 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "NederÄ«gs paplaÅ¡inÄjums."
#: platform/windows/export/export.cpp
msgid "Could not find signtool executable at \"%s\"."
@@ -20052,15 +20052,15 @@ msgstr "Nederīgs nosaukums."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "NederÄ«gs paplaÅ¡inÄjums."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/mk.po b/editor/translations/mk.po
index a3390bd895..2d183ec609 100644
--- a/editor/translations/mk.po
+++ b/editor/translations/mk.po
@@ -2704,7 +2704,7 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr ""
#: editor/editor_export.cpp
@@ -19363,14 +19363,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
+msgid "rcedit failed to modify executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
@@ -19392,14 +19391,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
+msgid "Signtool failed to sign executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
diff --git a/editor/translations/ml.po b/editor/translations/ml.po
index 4cb867c040..7568bc881e 100644
--- a/editor/translations/ml.po
+++ b/editor/translations/ml.po
@@ -2715,8 +2715,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "ചലനം à´šàµà´±àµà´±àµ½"
#: editor/editor_export.cpp
msgid "Completed successfully."
@@ -19402,14 +19403,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
+msgid "rcedit failed to modify executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
@@ -19431,14 +19431,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
+msgid "Signtool failed to sign executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
diff --git a/editor/translations/mr.po b/editor/translations/mr.po
index 47b8bd3f86..4bdf5ba4fb 100644
--- a/editor/translations/mr.po
+++ b/editor/translations/mr.po
@@ -2715,8 +2715,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "अâ€à¥…निमेशन टà¥à¤°à¥€"
#: editor/editor_export.cpp
msgid "Completed successfully."
@@ -19403,14 +19404,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
+msgid "rcedit failed to modify executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
@@ -19432,14 +19432,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
+msgid "Signtool failed to sign executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
diff --git a/editor/translations/ms.po b/editor/translations/ms.po
index 055e18e0bc..61a60ad8fe 100644
--- a/editor/translations/ms.po
+++ b/editor/translations/ms.po
@@ -2745,8 +2745,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "Salin Pilihan"
#: editor/editor_export.cpp
#, fuzzy
@@ -20226,15 +20227,15 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Nama kumpulan tidak sah."
#: platform/windows/export/export.cpp
msgid "Could not find signtool executable at \"%s\"."
@@ -20256,15 +20257,15 @@ msgstr "Nama tidak sah."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Nama kumpulan tidak sah."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/nb.po b/editor/translations/nb.po
index dac373fdc7..542d5987ca 100644
--- a/editor/translations/nb.po
+++ b/editor/translations/nb.po
@@ -2876,7 +2876,7 @@ msgstr ""
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "Kopier Node-bane"
#: editor/editor_export.cpp
@@ -21049,15 +21049,15 @@ msgstr "Kunne ikke opprette mappe."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "MÃ¥ ha en gyldig filutvidelse."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -21081,15 +21081,15 @@ msgstr "Ugyldig navn."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "MÃ¥ ha en gyldig filutvidelse."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/nl.po b/editor/translations/nl.po
index 40e0ddfb78..aaa0f38a1d 100644
--- a/editor/translations/nl.po
+++ b/editor/translations/nl.po
@@ -2916,7 +2916,7 @@ msgstr ""
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "Knooppad kopiëren"
#: editor/editor_export.cpp
@@ -20936,15 +20936,15 @@ msgstr "Kon template niet openen voor export:"
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Ongeldige extentie."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20968,15 +20968,15 @@ msgstr "Ongeldige naam."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Ongeldige extentie."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/pl.po b/editor/translations/pl.po
index 180abba988..3e4664c317 100644
--- a/editor/translations/pl.po
+++ b/editor/translations/pl.po
@@ -62,13 +62,14 @@
# Pixel Zone - Godot Engine Tutorials <karoltomaszewskimusic@gmail.com>, 2022.
# DK0492 <doriankaczmarek28@gmail.com>, 2022.
# Dawid Skubij <davidsd@tlen.pl>, 2022.
+# kingofsponges <q.patex.q@gmail.com>, 2022.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-07-10 14:38+0000\n"
-"Last-Translator: Dawid Skubij <davidsd@tlen.pl>\n"
+"PO-Revision-Date: 2022-08-04 06:38+0000\n"
+"Last-Translator: kingofsponges <q.patex.q@gmail.com>\n"
"Language-Team: Polish <https://hosted.weblate.org/projects/godot-engine/"
"godot/pl/>\n"
"Language: pl\n"
@@ -77,7 +78,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.13.1-dev\n"
+"X-Generator: Weblate 4.14-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -338,7 +339,7 @@ msgstr "Członek transmisji"
#: core/io/stream_peer.cpp
msgid "Big Endian"
-msgstr ""
+msgstr "Big endian"
#: core/io/stream_peer.cpp
msgid "Data Array"
@@ -368,9 +369,8 @@ msgid "Not enough bytes for decoding bytes, or invalid format."
msgstr "Niewystarczająca ilość bajtów dla bajtów dekodujących lub zły format."
#: core/math/expression.cpp
-#, fuzzy
msgid "Invalid input %d (not passed) in expression"
-msgstr "Niewłaściwe dane %i (nie przekazane) w wyrażeniu"
+msgstr "Niewłaściwe dane %d (nie przekazane) w wyrażeniu"
#: core/math/expression.cpp
msgid "self can't be used because instance is null (not passed)"
@@ -415,14 +415,12 @@ msgid "Max Size (KB)"
msgstr "Maks. rozmiar (KB)"
#: core/os/input.cpp
-#, fuzzy
msgid "Mouse Mode"
-msgstr "Tryb przesuwania"
+msgstr "Tryb myszki"
#: core/os/input.cpp
-#, fuzzy
msgid "Use Accumulated Input"
-msgstr "Usuń Wejście"
+msgstr "Użyj skumulowanego wejścia"
#: core/os/input_event.cpp editor/project_settings_editor.cpp
#: servers/audio_server.cpp
@@ -501,15 +499,15 @@ msgstr "Pochylenie"
#: core/os/input_event.cpp
msgid "Pressure"
-msgstr "Ciśnienie"
+msgstr "Nacisk"
#: core/os/input_event.cpp
msgid "Pen Inverted"
-msgstr ""
+msgstr "Odwrócone pióro"
#: core/os/input_event.cpp
msgid "Relative"
-msgstr "Relatywny"
+msgstr "Względny"
#: core/os/input_event.cpp scene/2d/camera_2d.cpp scene/2d/cpu_particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/interpolated_camera.cpp
@@ -644,9 +642,8 @@ msgstr "Własna nazwa katalogu użytkownika"
#: core/project_settings.cpp main/main.cpp
#: platform/javascript/export/export.cpp platform/osx/export/export.cpp
#: platform/uwp/os_uwp.cpp
-#, fuzzy
msgid "Display"
-msgstr "Pokaż wszystko"
+msgstr "Wyświetlanie"
#: core/project_settings.cpp main/main.cpp modules/csg/csg_shape.cpp
#: modules/opensimplex/noise_texture.cpp scene/2d/line_2d.cpp
@@ -660,23 +657,20 @@ msgstr "Szerokość"
#: scene/resources/capsule_shape_2d.cpp scene/resources/cylinder_shape.cpp
#: scene/resources/font.cpp scene/resources/navigation_mesh.cpp
#: scene/resources/primitive_meshes.cpp scene/resources/texture.cpp
-#, fuzzy
msgid "Height"
-msgstr "Światło"
+msgstr "Wysokość"
#: core/project_settings.cpp
msgid "Always On Top"
msgstr "Zawsze na wierzchu"
#: core/project_settings.cpp
-#, fuzzy
msgid "Test Width"
-msgstr "RozciÄ…gnij po lewej"
+msgstr "Szerokość testowa"
#: core/project_settings.cpp
-#, fuzzy
msgid "Test Height"
-msgstr "Testowanie"
+msgstr "Wysokość testowa"
#: core/project_settings.cpp editor/animation_track_editor.cpp
#: editor/editor_audio_buses.cpp main/main.cpp servers/audio_server.cpp
@@ -699,9 +693,8 @@ msgid "Main Run Args"
msgstr "Główne argumenty włączania"
#: core/project_settings.cpp
-#, fuzzy
msgid "Scene Naming"
-msgstr "Ścieżka sceny:"
+msgstr "Nazywanie scen"
#: core/project_settings.cpp
msgid "Search In File Extensions"
@@ -712,14 +705,12 @@ msgid "Script Templates Search Path"
msgstr "Ścieżka wyszukiwania szablonów skryptów"
#: core/project_settings.cpp
-#, fuzzy
msgid "Version Control Autoload On Startup"
-msgstr "Automatyczne ładowanie podczas uruchamiania"
+msgstr "Automatyczne ładowanie kontroli wersji podczas uruchamiania"
#: core/project_settings.cpp
-#, fuzzy
msgid "Version Control Plugin Name"
-msgstr "Kontrola wersji"
+msgstr "Nazwa wtyczki kontroli wersji"
#: core/project_settings.cpp scene/2d/collision_object_2d.cpp
#: scene/3d/collision_object.cpp scene/gui/control.cpp
@@ -1204,7 +1195,7 @@ msgstr "Ilośc:"
#: editor/animation_track_editor.cpp main/main.cpp
#: modules/mono/mono_gd/gd_mono.cpp
msgid "Args"
-msgstr ""
+msgstr "Argumenty"
#: editor/animation_track_editor.cpp editor/editor_settings.cpp
#: editor/script_editor_debugger.cpp modules/gltf/gltf_accessor.cpp
@@ -1228,7 +1219,7 @@ msgstr "Ustaw uchwyt"
#: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp
#: scene/audio/audio_stream_player.cpp scene/gui/video_player.cpp
msgid "Stream"
-msgstr ""
+msgstr "Strumień"
#: editor/animation_track_editor.cpp
#, fuzzy
@@ -2254,7 +2245,7 @@ msgstr "Otwórz"
#: editor/dependency_editor.cpp
msgid "Owners of: %s (Total: %d)"
-msgstr ""
+msgstr "Właściciele: %s (Suma: %d)"
#: editor/dependency_editor.cpp
msgid ""
@@ -2814,11 +2805,11 @@ msgstr "Wybierz"
#: editor/editor_export.cpp
msgid "Project export for platform:"
-msgstr ""
+msgstr "Eksportowanie projektu dla platformy:"
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "Skopiuj ścieżkę węzła"
#: editor/editor_export.cpp
@@ -2844,14 +2835,12 @@ msgid "Packing"
msgstr "Pakowanie"
#: editor/editor_export.cpp
-#, fuzzy
msgid "Save PCK"
-msgstr "Zapisz jako"
+msgstr "Zapisz plik PCK"
#: editor/editor_export.cpp
-#, fuzzy
msgid "Cannot create file \"%s\"."
-msgstr "Nie można utworzyć katalogu."
+msgstr "Nie można utworzyć pliku \"%s\"."
#: editor/editor_export.cpp
#, fuzzy
@@ -20698,17 +20687,17 @@ msgstr "Nie udało się znaleźć keystore, nie można eksportować."
#: platform/windows/export/export.cpp
#, fuzzy
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
"Narzędzie rcedit musi być skonfigurowane w Ustawieniach edytora (Eksport > "
"Windows > Rcedit), aby zmienić ikonę lub dane informacji o aplikacji."
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Niepoprawny plik wykonywalny."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20733,17 +20722,17 @@ msgstr "Niewłaściwa nazwa."
#: platform/windows/export/export.cpp
#, fuzzy
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
"Narzędzie rcedit musi być skonfigurowane w Ustawieniach edytora (Eksport > "
"Windows > Rcedit), aby zmienić ikonę lub dane informacji o aplikacji."
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Niepoprawny plik wykonywalny."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/pr.po b/editor/translations/pr.po
index 337e5af5c0..4c073f8542 100644
--- a/editor/translations/pr.po
+++ b/editor/translations/pr.po
@@ -2799,7 +2799,7 @@ msgstr ""
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "Forge yer Node!"
#: editor/editor_export.cpp
@@ -20263,15 +20263,15 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Yer Calligraphy be wrongly sized."
#: platform/windows/export/export.cpp
msgid "Could not find signtool executable at \"%s\"."
@@ -20293,15 +20293,15 @@ msgstr "Yer Calligraphy be wrongly sized."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Yer Calligraphy be wrongly sized."
#: platform/windows/export/export.cpp
msgid "Failed to remove temporary file \"%s\"."
diff --git a/editor/translations/pt.po b/editor/translations/pt.po
index db7171b3c6..f284e0ece8 100644
--- a/editor/translations/pt.po
+++ b/editor/translations/pt.po
@@ -2754,7 +2754,8 @@ msgid "Project export for platform:"
msgstr "Exportação do projeto para plataforma:"
#: editor/editor_export.cpp
-msgid "Completed with errors."
+#, fuzzy
+msgid "Completed with warnings."
msgstr "Concluído com erros."
#: editor/editor_export.cpp
@@ -20408,15 +20409,15 @@ msgstr "Incapaz de encontrar keystore e exportar."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Extensão inválida."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20440,15 +20441,15 @@ msgstr "Nome inválido."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Extensão inválida."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/pt_BR.po b/editor/translations/pt_BR.po
index 5d2b642352..84a5ac45c3 100644
--- a/editor/translations/pt_BR.po
+++ b/editor/translations/pt_BR.po
@@ -149,7 +149,7 @@ msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: 2016-05-30\n"
-"PO-Revision-Date: 2022-07-27 13:26+0000\n"
+"PO-Revision-Date: 2022-08-04 06:38+0000\n"
"Last-Translator: Felipe Kinoshita <kinofhek@gmail.com>\n"
"Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/"
"godot-engine/godot/pt_BR/>\n"
@@ -2868,7 +2868,8 @@ msgid "Project export for platform:"
msgstr "Exportação do projeto para plataforma:"
#: editor/editor_export.cpp
-msgid "Completed with errors."
+#, fuzzy
+msgid "Completed with warnings."
msgstr "Concluído com erros."
#: editor/editor_export.cpp
@@ -5495,7 +5496,7 @@ msgstr "Tamanho da Miniatura"
#: editor/editor_settings.cpp
msgid "Docks"
-msgstr "Docas"
+msgstr "Docks"
#: editor/editor_settings.cpp
msgid "Scene Tree"
@@ -16364,7 +16365,7 @@ msgstr "stdout"
#: main/main.cpp
msgid "Print FPS"
-msgstr ""
+msgstr "Mostrar FPS"
#: main/main.cpp
msgid "Verbose stdout"
@@ -20360,15 +20361,15 @@ msgstr "O keystore não foi encontrado, não foi possível exportar."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Extensão inválida."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20391,15 +20392,15 @@ msgstr "Nome Inválido."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Extensão inválida."
#: platform/windows/export/export.cpp
msgid "Failed to remove temporary file \"%s\"."
@@ -24458,7 +24459,7 @@ msgstr ""
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Caret"
-msgstr ""
+msgstr "Circunflexo"
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Blink"
diff --git a/editor/translations/ro.po b/editor/translations/ro.po
index aaa6e1cbcb..a78712c6ba 100644
--- a/editor/translations/ro.po
+++ b/editor/translations/ro.po
@@ -2836,8 +2836,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "Copiază Selecția"
#: editor/editor_export.cpp
#, fuzzy
@@ -20739,15 +20740,15 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Trebuie să utilizaţi o extensie valida."
#: platform/windows/export/export.cpp
msgid "Could not find signtool executable at \"%s\"."
@@ -20769,15 +20770,15 @@ msgstr "Nume nevalid."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Trebuie să utilizaţi o extensie valida."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/ru.po b/editor/translations/ru.po
index c50dce8e01..1df1d87308 100644
--- a/editor/translations/ru.po
+++ b/editor/translations/ru.po
@@ -2852,7 +2852,8 @@ msgid "Project export for platform:"
msgstr "ЭкÑпорт проекта Ð´Ð»Ñ Ð¿Ð»Ð°Ñ‚Ñ„Ð¾Ñ€Ð¼Ñ‹:"
#: editor/editor_export.cpp
-msgid "Completed with errors."
+#, fuzzy
+msgid "Completed with warnings."
msgstr "Завершено Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°Ð¼Ð¸."
#: editor/editor_export.cpp
@@ -20280,17 +20281,17 @@ msgstr "Ðе удалоÑÑŒ найти хранилище ключей, нево
#: platform/windows/export/export.cpp
#, fuzzy
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
"ИнÑтрумент rcedit должен быть наÑтроен в ÐаÑтройках редактора (Export > "
"Windows > Rcedit) Ð´Ð»Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð·Ð½Ð°Ñ‡ÐºÐ° или информационных данных приложениÑ."
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "ÐедопуÑтимый иÑполнÑемый файл."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20315,17 +20316,17 @@ msgstr "ÐедопуÑтимое имÑ."
#: platform/windows/export/export.cpp
#, fuzzy
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
"ИнÑтрумент rcedit должен быть наÑтроен в ÐаÑтройках редактора (Export > "
"Windows > Rcedit) Ð´Ð»Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð·Ð½Ð°Ñ‡ÐºÐ° или информационных данных приложениÑ."
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "ÐедопуÑтимый иÑполнÑемый файл."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/si.po b/editor/translations/si.po
index e30d6c27ab..8ce2d1d628 100644
--- a/editor/translations/si.po
+++ b/editor/translations/si.po
@@ -2745,8 +2745,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "à·à·Šâ€à¶»à·’à¶­:"
#: editor/editor_export.cpp
msgid "Completed successfully."
@@ -19620,14 +19621,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
+msgid "rcedit failed to modify executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
@@ -19649,14 +19649,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
+msgid "Signtool failed to sign executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
diff --git a/editor/translations/sk.po b/editor/translations/sk.po
index c3a64ecc2f..7cba3886ba 100644
--- a/editor/translations/sk.po
+++ b/editor/translations/sk.po
@@ -2854,8 +2854,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "Skopírovať Výber"
#: editor/editor_export.cpp
#, fuzzy
@@ -20662,15 +20663,15 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Nesprávna veľkosť písma."
#: platform/windows/export/export.cpp
msgid "Could not find signtool executable at \"%s\"."
@@ -20692,15 +20693,15 @@ msgstr "Neplatný Názov."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Nesprávna veľkosť písma."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/sl.po b/editor/translations/sl.po
index 4f7f11baa3..ceb21aa750 100644
--- a/editor/translations/sl.po
+++ b/editor/translations/sl.po
@@ -2887,8 +2887,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "Odstrani izbrano"
#: editor/editor_export.cpp
#, fuzzy
@@ -20961,15 +20962,15 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Uporabiti moraš valjavno razširitev."
#: platform/windows/export/export.cpp
msgid "Could not find signtool executable at \"%s\"."
@@ -20991,15 +20992,15 @@ msgstr "Neveljavno ime."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Uporabiti moraš valjavno razširitev."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/sq.po b/editor/translations/sq.po
index d011c34407..af72b686b9 100644
--- a/editor/translations/sq.po
+++ b/editor/translations/sq.po
@@ -2824,8 +2824,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "Animacionet:"
#: editor/editor_export.cpp
#, fuzzy
@@ -20432,15 +20433,15 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Duhet të perdorësh një shtesë të lejuar."
#: platform/windows/export/export.cpp
msgid "Could not find signtool executable at \"%s\"."
@@ -20462,15 +20463,15 @@ msgstr "Emër i palejuar."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Duhet të perdorësh një shtesë të lejuar."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/sr_Cyrl.po b/editor/translations/sr_Cyrl.po
index 4a9d933004..4231d62c6b 100644
--- a/editor/translations/sr_Cyrl.po
+++ b/editor/translations/sr_Cyrl.po
@@ -3003,7 +3003,7 @@ msgstr ""
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "Копирај Путању Чвора"
#: editor/editor_export.cpp
@@ -22362,15 +22362,15 @@ msgstr "ÐеуÑпешно отварање нацрта за извоз:"
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Мора Ñе кориÑтити важећа екÑтензија."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -22394,15 +22394,15 @@ msgstr "Ðеважеће име."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Мора Ñе кориÑтити важећа екÑтензија."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/sr_Latn.po b/editor/translations/sr_Latn.po
index 41b23339de..b898108402 100644
--- a/editor/translations/sr_Latn.po
+++ b/editor/translations/sr_Latn.po
@@ -2769,8 +2769,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "Kopiraj OznaÄeno"
#: editor/editor_export.cpp
msgid "Completed successfully."
@@ -19709,14 +19710,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
+msgid "rcedit failed to modify executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
@@ -19738,14 +19738,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
+msgid "Signtool failed to sign executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
diff --git a/editor/translations/sv.po b/editor/translations/sv.po
index 3baefa6356..9fd6b9bf67 100644
--- a/editor/translations/sv.po
+++ b/editor/translations/sv.po
@@ -2852,7 +2852,7 @@ msgstr "Projektexport för plattformen:"
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "Kopiera Nod-Sökväg"
#: editor/editor_export.cpp
@@ -20723,15 +20723,15 @@ msgstr "Det gick inte att hitta nyckellager, det gick inte att exportera."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Måste använda en giltigt filändelse."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20755,15 +20755,15 @@ msgstr "Ogiltigt namn."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Måste använda en giltigt filändelse."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/te.po b/editor/translations/te.po
index 03919233f7..af4c65f062 100644
--- a/editor/translations/te.po
+++ b/editor/translations/te.po
@@ -2698,8 +2698,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "సంఘం"
#: editor/editor_export.cpp
msgid "Completed successfully."
@@ -19324,14 +19325,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
+msgid "rcedit failed to modify executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
@@ -19352,14 +19352,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
+msgid "Signtool failed to sign executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
diff --git a/editor/translations/th.po b/editor/translations/th.po
index 1690916a54..f1eb8b716f 100644
--- a/editor/translations/th.po
+++ b/editor/translations/th.po
@@ -2875,7 +2875,7 @@ msgstr ""
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "คัดลอà¸à¸•ำà¹à¸«à¸™à¹ˆà¸‡à¹‚หนด"
#: editor/editor_export.cpp
@@ -20710,15 +20710,15 @@ msgstr "เปิดเทมเพลตเพื่อส่งออà¸à¹„ม
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "นามสà¸à¸¸à¸¥à¹„ม่ถูà¸à¸•้อง"
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20742,15 +20742,15 @@ msgstr "ชื่อผิดพลาด"
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "นามสà¸à¸¸à¸¥à¹„ม่ถูà¸à¸•้อง"
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/tl.po b/editor/translations/tl.po
index cc20958dd1..fec7766383 100644
--- a/editor/translations/tl.po
+++ b/editor/translations/tl.po
@@ -2814,8 +2814,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr "Kopyahin Ang Pinagpipilian"
#: editor/editor_export.cpp
msgid "Completed successfully."
@@ -19980,14 +19981,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
+msgid "rcedit failed to modify executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
@@ -20010,14 +20010,13 @@ msgstr "Di-wastong pangalan."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
+msgid "Signtool failed to sign executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
diff --git a/editor/translations/tr.po b/editor/translations/tr.po
index 4980240671..ab58a87c36 100644
--- a/editor/translations/tr.po
+++ b/editor/translations/tr.po
@@ -77,13 +77,14 @@
# Deleted User <noreply+46833@weblate.org>, 2022.
# Emre <mr.inkaya@gmail.com>, 2022.
# Deleted User <noreply+46858@weblate.org>, 2022.
+# Ümid Quliyev <lucifer25x@protonmail.com>, 2022.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-07-23 03:57+0000\n"
-"Last-Translator: Deleted User <noreply+46858@weblate.org>\n"
+"PO-Revision-Date: 2022-08-05 01:04+0000\n"
+"Last-Translator: Ümid Quliyev <lucifer25x@protonmail.com>\n"
"Language-Team: Turkish <https://hosted.weblate.org/projects/godot-engine/"
"godot/tr/>\n"
"Language: tr\n"
@@ -360,7 +361,7 @@ msgstr "Veri Dizisi"
#: core/io/stream_peer_ssl.cpp
msgid "Blocking Handshake"
-msgstr ""
+msgstr "Tokalaşmayı blokla"
#: core/io/udp_server.cpp
msgid "Max Pending Connections"
@@ -411,7 +412,6 @@ msgstr "'%s' çağrıldığında:"
#: core/math/random_number_generator.cpp
#: modules/opensimplex/open_simplex_noise.cpp
-#, fuzzy
msgid "Seed"
msgstr "Tohum"
@@ -449,7 +449,6 @@ msgid "Shift"
msgstr "Shift"
#: core/os/input_event.cpp
-#, fuzzy
msgid "Control"
msgstr "Kontrol TuÅŸu"
@@ -2833,7 +2832,7 @@ msgstr "Platform için proje dışa aktarımı:"
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "Hatalarla tamamlandı."
#: editor/editor_export.cpp
@@ -4459,8 +4458,9 @@ msgid "Restore Scenes On Load"
msgstr "Sahne Düğümünü Al"
#: editor/editor_node.cpp editor/editor_settings.cpp
+#, fuzzy
msgid "Show Thumbnail On Hover"
-msgstr ""
+msgstr "Fareyle üzerine gelindiğinde  küçük resmi  göster"
#: editor/editor_node.cpp editor/editor_settings.cpp
msgid "Inspector"
@@ -4486,11 +4486,11 @@ msgstr ""
#: editor/editor_node.cpp
msgid "Horizontal Vector2 Editing"
-msgstr ""
+msgstr "Yatay Vector2 Düzenleme"
#: editor/editor_node.cpp
msgid "Horizontal Vector Types Editing"
-msgstr ""
+msgstr "Yatay Vector tipleri düzenleme"
#: editor/editor_node.cpp
#, fuzzy
@@ -4503,8 +4503,9 @@ msgid "Resources To Open In New Inspector"
msgstr "Gözetmen Bölümünde Aç"
#: editor/editor_node.cpp
+#, fuzzy
msgid "Default Color Picker Mode"
-msgstr ""
+msgstr "Varsayılan renk seçme modu"
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "Version Control"
@@ -5380,19 +5381,19 @@ msgstr "Hepsini Görüntüle"
#: editor/editor_settings.cpp
msgid "Custom Display Scale"
-msgstr ""
+msgstr "Özel Ekran Ölçeği"
#: editor/editor_settings.cpp
msgid "Main Font Size"
-msgstr ""
+msgstr "Ana font ölçüsü"
#: editor/editor_settings.cpp
msgid "Code Font Size"
-msgstr ""
+msgstr "Kod font'u ölçüsü"
#: editor/editor_settings.cpp
msgid "Font Antialiased"
-msgstr ""
+msgstr "Kenarı yumuşatılmış font"
#: editor/editor_settings.cpp
msgid "Font Hinting"
@@ -5405,7 +5406,7 @@ msgstr "Ana Sahne"
#: editor/editor_settings.cpp
msgid "Main Font Bold"
-msgstr ""
+msgstr "Ana font kalınlığı"
#: editor/editor_settings.cpp
#, fuzzy
@@ -5413,8 +5414,9 @@ msgid "Code Font"
msgstr "Düğüm Noktası Ekle"
#: editor/editor_settings.cpp
+#, fuzzy
msgid "Dim Editor On Dialog Popup"
-msgstr ""
+msgstr "İletişim penceresinde Dim Editörü"
#: editor/editor_settings.cpp main/main.cpp
msgid "Low Processor Mode Sleep (µsec)"
@@ -5431,11 +5433,12 @@ msgstr "Dikkat Dağıtmayan Kip"
#: editor/editor_settings.cpp
msgid "Automatically Open Screenshots"
-msgstr ""
+msgstr "Otomatik olarak ekran görüntülerini aç"
#: editor/editor_settings.cpp
+#, fuzzy
msgid "Max Array Dictionary Items Per Page"
-msgstr ""
+msgstr "Her sayfada maks dizi sözlüğü öğesi"
#: editor/editor_settings.cpp editor/plugins/script_editor_plugin.cpp
#: editor/plugins/theme_editor_plugin.cpp scene/gui/control.cpp
@@ -5449,7 +5452,7 @@ msgstr "Ön ayar"
#: editor/editor_settings.cpp
msgid "Icon And Font Color"
-msgstr ""
+msgstr "Simge ve Font rengi"
#: editor/editor_settings.cpp
#, fuzzy
@@ -5463,7 +5466,7 @@ msgstr "Renk Seç"
#: editor/editor_settings.cpp scene/resources/environment.cpp
msgid "Contrast"
-msgstr ""
+msgstr "Kontrast"
#: editor/editor_settings.cpp
msgid "Relationship Line Opacity"
@@ -5561,8 +5564,9 @@ msgid "Property Editor"
msgstr "Grup Düzenleyici"
#: editor/editor_settings.cpp
+#, fuzzy
msgid "Auto Refresh Interval"
-msgstr ""
+msgstr "Otomatik yenileme intervalı"
#: editor/editor_settings.cpp
#, fuzzy
@@ -5577,7 +5581,7 @@ msgstr "Editör Teması"
#: editor/editor_settings.cpp scene/3d/label_3d.cpp
#: scene/resources/default_theme/default_theme.cpp
msgid "Line Spacing"
-msgstr ""
+msgstr "Satır aralığı"
#: editor/editor_settings.cpp editor/plugins/script_text_editor.cpp
#: modules/gdscript/editor/gdscript_highlighter.cpp
@@ -5596,7 +5600,7 @@ msgstr ""
#: editor/editor_settings.cpp scene/gui/text_edit.cpp
msgid "Highlight Current Line"
-msgstr ""
+msgstr "Geçerli satırı vurgula"
#: editor/editor_settings.cpp editor/plugins/script_text_editor.cpp
msgid "Highlight Type Safe Lines"
@@ -5635,11 +5639,11 @@ msgstr "Gezinim"
#: editor/editor_settings.cpp scene/gui/text_edit.cpp
msgid "Smooth Scrolling"
-msgstr ""
+msgstr "Pürüzsüz kaydırma"
#: editor/editor_settings.cpp scene/gui/text_edit.cpp
msgid "V Scroll Speed"
-msgstr ""
+msgstr "V kaydırma hızı"
#: editor/editor_settings.cpp
#, fuzzy
@@ -5648,7 +5652,7 @@ msgstr "Başlatımı Göster"
#: editor/editor_settings.cpp
msgid "Minimap Width"
-msgstr ""
+msgstr "Küçük Harita Genişliği"
#: editor/editor_settings.cpp
msgid "Mouse Extra Buttons Navigate History"
@@ -5660,12 +5664,13 @@ msgid "Drag And Drop Selection"
msgstr "GridMap Seçimi"
#: editor/editor_settings.cpp
+#, fuzzy
msgid "Stay In Script Editor On Node Selected"
-msgstr ""
+msgstr "Seçilmiş Düğümde Script Editöründe Kal"
#: editor/editor_settings.cpp
msgid "Appearance"
-msgstr ""
+msgstr "Dış görünüş"
#: editor/editor_settings.cpp scene/gui/text_edit.cpp
#, fuzzy
@@ -5691,12 +5696,14 @@ msgid "Show Info Gutter"
msgstr ""
#: editor/editor_settings.cpp
+#, fuzzy
msgid "Code Folding"
-msgstr ""
+msgstr "Kod katlama"
#: editor/editor_settings.cpp
+#, fuzzy
msgid "Word Wrap"
-msgstr ""
+msgstr "Kelime Paketle"
#: editor/editor_settings.cpp
msgid "Show Line Length Guidelines"
@@ -5717,7 +5724,7 @@ msgstr "Kod Düzenleyici"
#: editor/editor_settings.cpp
msgid "Show Members Overview"
-msgstr ""
+msgstr "Üyelerin Genel Bakışını Göster"
#: editor/editor_settings.cpp editor/plugins/script_editor_plugin.cpp
#, fuzzy
@@ -5734,16 +5741,19 @@ msgid "Autosave Interval Secs"
msgstr ""
#: editor/editor_settings.cpp editor/plugins/script_editor_plugin.cpp
+#, fuzzy
msgid "Restore Scripts On Load"
-msgstr ""
+msgstr "Script'leri Yüklemede Eski Haline Getir"
#: editor/editor_settings.cpp
+#, fuzzy
msgid "Auto Reload And Parse Scripts On Save"
-msgstr ""
+msgstr "Kaydederken Script'leri Otomatik Tekrar yükle ve Ayrıştır"
#: editor/editor_settings.cpp
+#, fuzzy
msgid "Auto Reload Scripts On External Change"
-msgstr ""
+msgstr "Dış Değişiklikte Otomatik Olarak Script'i Geri Yükle"
#: editor/editor_settings.cpp
#, fuzzy
@@ -5756,11 +5766,11 @@ msgstr ""
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Cursor"
-msgstr ""
+msgstr "İmleç"
#: editor/editor_settings.cpp
msgid "Scroll Past End Of File"
-msgstr ""
+msgstr "Dosyanın Sonunu Kaydır"
#: editor/editor_settings.cpp
msgid "Block Caret"
@@ -5796,7 +5806,7 @@ msgstr ""
#: editor/editor_settings.cpp
msgid "Code Complete Delay"
-msgstr ""
+msgstr "Kod Tamamlama Gecikme Süresi"
#: editor/editor_settings.cpp
msgid "Put Callhint Tooltip Below Current Line"
@@ -5853,12 +5863,14 @@ msgid "Preview Size"
msgstr "Önizleme"
#: editor/editor_settings.cpp
+#, fuzzy
msgid "Primary Grid Color"
-msgstr ""
+msgstr "Birincil Izgara Rengi"
#: editor/editor_settings.cpp
+#, fuzzy
msgid "Secondary Grid Color"
-msgstr ""
+msgstr "İkincil Izgara Rengi"
#: editor/editor_settings.cpp
#, fuzzy
@@ -5895,7 +5907,7 @@ msgstr "Nokta"
#: scene/resources/particles_material.cpp servers/physics_2d_server.cpp
#: servers/physics_server.cpp
msgid "Shape"
-msgstr ""
+msgstr "Åžekil"
#: editor/editor_settings.cpp
#, fuzzy
@@ -6007,7 +6019,7 @@ msgstr "Gezinim Kipi"
#: editor/editor_settings.cpp
msgid "Orbit Sensitivity"
-msgstr ""
+msgstr "Yörünge Hassasiyeti"
#: editor/editor_settings.cpp
msgid "Orbit Inertia"
@@ -20660,15 +20672,15 @@ msgstr "Anahtar deposu bulunamadı, dışa aktarılamadı."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Geçersiz uzantı."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20692,15 +20704,15 @@ msgstr "Geçersiz ad."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Geçersiz uzantı."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/uk.po b/editor/translations/uk.po
index 0feae1a849..d87aa168d7 100644
--- a/editor/translations/uk.po
+++ b/editor/translations/uk.po
@@ -2757,7 +2757,8 @@ msgid "Project export for platform:"
msgstr "ЕкÑÐ¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ Ð´Ð»Ñ Ð¿Ð»Ð°Ñ‚Ñ„Ð¾Ñ€Ð¼Ð¸:"
#: editor/editor_export.cpp
-msgid "Completed with errors."
+#, fuzzy
+msgid "Completed with warnings."
msgstr "Завершено з помилками."
#: editor/editor_export.cpp
@@ -20123,18 +20124,18 @@ msgstr "Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ Ñховище ключів. Ðемож
#: platform/windows/export/export.cpp
#, fuzzy
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
"Щоб мати змогу змінювати піктограму або дані щодо програми, має бути "
"налаштовано інÑтрумент rcedit у параметрах редактора (ЕкÑпорт > Windows > "
"Rcedit)."
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Ðекоректний виконуваний файл."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20159,18 +20160,18 @@ msgstr "Ðекоректна назва."
#: platform/windows/export/export.cpp
#, fuzzy
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
"Щоб мати змогу змінювати піктограму або дані щодо програми, має бути "
"налаштовано інÑтрумент rcedit у параметрах редактора (ЕкÑпорт > Windows > "
"Rcedit)."
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Ðекоректний виконуваний файл."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/ur_PK.po b/editor/translations/ur_PK.po
index 9cb56f3c21..a428250cc7 100644
--- a/editor/translations/ur_PK.po
+++ b/editor/translations/ur_PK.po
@@ -2764,8 +2764,9 @@ msgid "Project export for platform:"
msgstr ""
#: editor/editor_export.cpp
-msgid "Completed with errors."
-msgstr ""
+#, fuzzy
+msgid "Completed with warnings."
+msgstr ".تمام کا انتخاب"
#: editor/editor_export.cpp
msgid "Completed successfully."
@@ -20062,14 +20063,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
+msgid "rcedit failed to modify executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
@@ -20091,14 +20091,13 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
+msgid "Signtool failed to sign executable: %s."
msgstr ""
#: platform/windows/export/export.cpp
diff --git a/editor/translations/vi.po b/editor/translations/vi.po
index 4a6164f7e1..0a6885872f 100644
--- a/editor/translations/vi.po
+++ b/editor/translations/vi.po
@@ -2797,7 +2797,7 @@ msgstr ""
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "Sao chép đưá»ng dẫn nút"
#: editor/editor_export.cpp
@@ -20574,15 +20574,15 @@ msgstr "Không thể mở bản mẫu để xuất:"
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "Tên đuôi không hợp lệ."
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20606,15 +20606,15 @@ msgstr "Tên không hợp lệ."
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "Tên đuôi không hợp lệ."
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/zh_CN.po b/editor/translations/zh_CN.po
index bd012a4c76..f25a372128 100644
--- a/editor/translations/zh_CN.po
+++ b/editor/translations/zh_CN.po
@@ -89,7 +89,7 @@ msgstr ""
"Project-Id-Version: Chinese (Simplified) (Godot Engine)\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: 2018-01-20 12:15+0200\n"
-"PO-Revision-Date: 2022-07-19 16:26+0000\n"
+"PO-Revision-Date: 2022-07-29 01:36+0000\n"
"Last-Translator: Haoyu Qiu <timothyqiu32@gmail.com>\n"
"Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/"
"godot-engine/godot/zh_Hans/>\n"
@@ -2791,7 +2791,8 @@ msgid "Project export for platform:"
msgstr "针对平å°å¯¼å‡ºé¡¹ç›®ï¼š"
#: editor/editor_export.cpp
-msgid "Completed with errors."
+#, fuzzy
+msgid "Completed with warnings."
msgstr "已完æˆï¼Œå­˜åœ¨é”™è¯¯ã€‚"
#: editor/editor_export.cpp
@@ -5445,7 +5446,7 @@ msgstr "拖放选中内容"
#: editor/editor_settings.cpp
msgid "Stay In Script Editor On Node Selected"
-msgstr ""
+msgstr "é€‰ä¸­èŠ‚ç‚¹æ—¶ä¿æŒè„šæœ¬ç¼–è¾‘å™¨"
#: editor/editor_settings.cpp
msgid "Appearance"
@@ -11470,9 +11471,8 @@ msgid "New Animation"
msgstr "新建动画"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Filter animations"
-msgstr "筛选方法"
+msgstr "筛选动画"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Speed:"
@@ -19681,17 +19681,18 @@ msgid "Could not find wine executable at \"%s\"."
msgstr "无法在“%sâ€æ‰¾åˆ° wine 坿‰§è¡Œæ–‡ä»¶ã€‚"
#: platform/windows/export/export.cpp
+#, fuzzy
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
"无法å¯åЍ rcedit 坿‰§è¡Œæ–‡ä»¶ï¼Œè¯·åœ¨ç¼–辑器设置中é…ç½® rcedit 路径(导出 > Windows "
"> Rcedit)。"
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
msgstr ""
"rcedit ä¿®æ”¹å¯æ‰§è¡Œæ–‡ä»¶å¤±è´¥ï¼š\n"
"%s"
@@ -19713,17 +19714,18 @@ msgid "Invalid timestamp server."
msgstr "时间戳æœåŠ¡å™¨æ— æ•ˆã€‚"
#: platform/windows/export/export.cpp
+#, fuzzy
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
"无法å¯åЍ signtool 坿‰§è¡Œæ–‡ä»¶ï¼Œè¯·åœ¨ç¼–辑器设置中é…ç½® signtool 路径(导出 > "
"Windows > Signtool)。"
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
msgstr ""
"Signtool ç­¾å坿‰§è¡Œæ–‡ä»¶å¤±è´¥ï¼š\n"
"%s"
diff --git a/editor/translations/zh_HK.po b/editor/translations/zh_HK.po
index 424752a849..79760d0de7 100644
--- a/editor/translations/zh_HK.po
+++ b/editor/translations/zh_HK.po
@@ -2891,7 +2891,7 @@ msgstr ""
#: editor/editor_export.cpp
#, fuzzy
-msgid "Completed with errors."
+msgid "Completed with warnings."
msgstr "複製路徑"
#: editor/editor_export.cpp
@@ -20867,15 +20867,15 @@ msgstr "無法新增資料夾"
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "無效副檔å"
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20899,15 +20899,15 @@ msgstr "無效å稱。"
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "無效副檔å"
#: platform/windows/export/export.cpp
#, fuzzy
diff --git a/editor/translations/zh_TW.po b/editor/translations/zh_TW.po
index f5568c41b5..8ad86d4b2a 100644
--- a/editor/translations/zh_TW.po
+++ b/editor/translations/zh_TW.po
@@ -23,7 +23,7 @@
# binotaliu <binota@protonmail.ch>, 2020.
# Allen H. <w84miracle@gmail.com>, 2020.
# BinotaLIU <binota@protonmail.ch>, 2020.
-# BinotaLIU <me@binota.org>, 2020, 2021.
+# BinotaLIU <me@binota.org>, 2020, 2021, 2022.
# MintSoda <lionlxh@qq.com>, 2020.
# meowmeowmeowcat <meowmeowcat1211@gmail.com>, 2021.
# anthonychen <anton1554970211@126.com>, 2021.
@@ -41,8 +41,8 @@ msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-07-23 03:57+0000\n"
-"Last-Translator: è˜è˜ <rrt467778@gmail.com>\n"
+"PO-Revision-Date: 2022-07-31 18:34+0000\n"
+"Last-Translator: BinotaLIU <me@binota.org>\n"
"Language-Team: Chinese (Traditional) <https://hosted.weblate.org/projects/"
"godot-engine/godot/zh_Hant/>\n"
"Language: zh_TW\n"
@@ -474,7 +474,7 @@ msgstr "壓力"
#: core/os/input_event.cpp
msgid "Pen Inverted"
-msgstr ""
+msgstr "å轉筆觸"
#: core/os/input_event.cpp
msgid "Relative"
@@ -1171,14 +1171,12 @@ msgid "Type"
msgstr "型別"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "In Handle"
-msgstr "輸入把手"
+msgstr "進入控點"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Out Handle"
-msgstr "輸出把手"
+msgstr "離開控點"
#: editor/animation_track_editor.cpp
#: editor/import/resource_importer_texture.cpp
@@ -1350,14 +1348,12 @@ msgid "Easing:"
msgstr "緩入緩出:"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "In-Handle:"
-msgstr "設定處ç†ç¨‹å¼"
+msgstr "進入控點:"
#: editor/animation_track_editor.cpp
-#, fuzzy
msgid "Out-Handle:"
-msgstr "設定處ç†ç¨‹å¼"
+msgstr "離開控點:"
#: editor/animation_track_editor.cpp
msgid "Stream:"
@@ -2747,7 +2743,8 @@ msgid "Project export for platform:"
msgstr "專案匯出平å°ï¼š"
#: editor/editor_export.cpp
-msgid "Completed with errors."
+#, fuzzy
+msgid "Completed with warnings."
msgstr "已完æˆï¼Œå­˜åœ¨éŒ¯èª¤ã€‚"
#: editor/editor_export.cpp
@@ -5195,9 +5192,8 @@ msgid "Unfocused Low Processor Mode Sleep (µsec)"
msgstr "未èšç„¦ä½Žè™•ç†å™¨ç¡çœ æ¨¡å¼ï¼ˆå¾®ç§’)"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Separate Distraction Mode"
-msgstr "專注模å¼"
+msgstr "ç¨ç«‹å°ˆæ³¨æ¨¡å¼"
#: editor/editor_settings.cpp
msgid "Automatically Open Screenshots"
@@ -5404,7 +5400,7 @@ msgstr "æ‹–ç§»é¸æ“‡çš„æª”案"
#: editor/editor_settings.cpp
msgid "Stay In Script Editor On Node Selected"
-msgstr ""
+msgstr "鏿“‡ç¯€é»žæ™‚ä¿ç•™åœ¨è…³æœ¬ç·¨è¼¯å™¨ä¸­"
#: editor/editor_settings.cpp
msgid "Appearance"
@@ -5423,9 +5419,8 @@ msgid "Show Bookmark Gutter"
msgstr "顯示書籤欄"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Show Breakpoint Gutter"
-msgstr "è·³éŽä¸­æ–·é»ž"
+msgstr "顯示中斷點欄"
#: editor/editor_settings.cpp
msgid "Show Info Gutter"
@@ -5464,9 +5459,8 @@ msgid "Files"
msgstr "檔案"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Trim Trailing Whitespace On Save"
-msgstr "移除後方空白字元"
+msgstr "ä¿å­˜æ™‚移除後方空白字元"
#: editor/editor_settings.cpp
msgid "Autosave Interval Secs"
@@ -5513,9 +5507,8 @@ msgid "Caret Blink Speed"
msgstr "æ’入符閃çˆé€Ÿåº¦"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Right Click Moves Caret"
-msgstr "å³éµé»žæ“Šä»¥æ–°å¢žæŽ§åˆ¶é»ž"
+msgstr "按一下å³éµä¾†ç§»å‹•éŠæ¨™"
#: editor/editor_settings.cpp modules/gdscript/gdscript.cpp
#: modules/gdscript/gdscript_editor.cpp
@@ -5544,9 +5537,8 @@ msgid "Callhint Tooltip Offset"
msgstr "å‘¼å«æç¤ºå·¥å…·æç¤ºæ¡†åç§»é‡"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Complete File Paths"
-msgstr "複製節點路徑"
+msgstr "補全檔案路徑"
#: editor/editor_settings.cpp modules/gdscript/gdscript_editor.cpp
msgid "Add Type Hints"
@@ -5713,9 +5705,8 @@ msgid "Warped Mouse Panning"
msgstr "彎曲滑鼠平移"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Navigation Feel"
-msgstr "導航模å¼"
+msgstr "導航風格"
#: editor/editor_settings.cpp
msgid "Orbit Sensitivity"
@@ -5972,21 +5963,20 @@ msgid "Completion Background Color"
msgstr "自動補全背景é¡è‰²"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Completion Selected Color"
-msgstr "匯入所é¸"
+msgstr "自動補全所é¸é¡è‰²"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Completion Existing Color"
-msgstr "完æˆå­˜åœ¨ä¸­é¡è‰²"
+msgstr "è‡ªå‹•è£œå…¨ç¾æœ‰é¡è‰²"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Completion Scroll Color"
-msgstr "å®Œæˆæ»¾å‹•é¡è‰²"
+msgstr "自動補全æ²è»¸é¡è‰²"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Completion Font Color"
-msgstr "完æˆå­—åž‹é¡è‰²"
+msgstr "自動補全字型é¡è‰²"
#: editor/editor_settings.cpp
msgid "Text Color"
@@ -6739,7 +6729,7 @@ msgstr "使用環境通é“"
#: editor/import/resource_importer_bitmask.cpp
msgid "Create From"
-msgstr "從æŸè™•建立"
+msgstr "建立自"
#: editor/import/resource_importer_bitmask.cpp
#: servers/audio/effects/audio_effect_compressor.cpp
@@ -6751,9 +6741,8 @@ msgstr "臨界值"
#: editor/import/resource_importer_scene.cpp
#: editor/import/resource_importer_texture.cpp
#: editor/import/resource_importer_wav.cpp scene/3d/gi_probe.cpp
-#, fuzzy
msgid "Compress"
-msgstr "元件"
+msgstr "壓縮"
#: editor/import/resource_importer_csv_translation.cpp
msgid "Delimiter"
@@ -6803,9 +6792,8 @@ msgid "sRGB"
msgstr "sRGB"
#: editor/import/resource_importer_layered_texture.cpp
-#, fuzzy
msgid "Slices"
-msgstr "自動剪è£"
+msgstr "切片"
#: editor/import/resource_importer_layered_texture.cpp
#: scene/gui/aspect_ratio_container.cpp scene/gui/control.cpp
@@ -6822,9 +6810,8 @@ msgid "Vertical"
msgstr "垂直"
#: editor/import/resource_importer_obj.cpp
-#, fuzzy
msgid "Generate Tangents"
-msgstr "產生點"
+msgstr "產生切線"
#: editor/import/resource_importer_obj.cpp
msgid "Scale Mesh"
@@ -6836,9 +6823,8 @@ msgstr "Mesh åç§»"
#: editor/import/resource_importer_obj.cpp
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Octahedral Compression"
-msgstr "設定表示å¼"
+msgstr "å…«é¢é«”壓縮"
#: editor/import/resource_importer_obj.cpp
msgid "Optimize Mesh Flags"
@@ -6926,27 +6912,24 @@ msgid "Meshes"
msgstr "網格"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Ensure Tangents"
-msgstr "修改曲線切線"
+msgstr "確ä¿åˆ‡ç·š"
#: editor/import/resource_importer_scene.cpp
msgid "Light Baking"
msgstr "光照烘焙"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Lightmap Texel Size"
-msgstr "烘焙光照圖"
+msgstr "光照圖紋ç†å…ƒç´ å¤§å°"
#: editor/import/resource_importer_scene.cpp modules/gltf/gltf_state.cpp
msgid "Skins"
msgstr "Skin"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Use Named Skins"
-msgstr "使用縮放å¸é™„"
+msgstr "使用命å Skin"
#: editor/import/resource_importer_scene.cpp
msgid "External Files"
@@ -6961,9 +6944,8 @@ msgid "Filter Script"
msgstr "篩é¸è…³æœ¬"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Keep Custom Tracks"
-msgstr "變æ›"
+msgstr "ä¿ç•™è‡ªå®šè»Œé“"
#: editor/import/resource_importer_scene.cpp
msgid "Optimizer"
@@ -8769,7 +8751,7 @@ msgstr "縮放模å¼"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Shift: Scale proportionally."
-msgstr ""
+msgstr "Shift:按比例縮放。"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -9287,11 +9269,11 @@ msgstr "漸層編輯"
#: editor/plugins/gradient_texture_2d_editor_plugin.cpp
msgid "Swap GradientTexture2D Fill Points"
-msgstr ""
+msgstr "äº¤æ› GradientTexture2D 的填充點"
#: editor/plugins/gradient_texture_2d_editor_plugin.cpp
msgid "Swap Gradient Fill Points"
-msgstr ""
+msgstr "äº¤æ› Gradient 填充點"
#: editor/plugins/gradient_texture_2d_editor_plugin.cpp
msgid "Toggle Grid Snap"
@@ -10096,7 +10078,7 @@ msgstr "åŒæ­¥éª¨éª¼åˆ°å¤šé‚Šå½¢"
#: editor/plugins/ray_cast_2d_editor_plugin.cpp
msgid "Set cast_to"
-msgstr ""
+msgstr "設定 cast_to"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "ERROR: Couldn't load resource!"
@@ -10425,7 +10407,7 @@ msgstr "æœå°‹çµæžœ"
#: editor/plugins/script_editor_plugin.cpp
msgid "Open Dominant Script On Scene Change"
-msgstr ""
+msgstr "場景更改時開啟主腳本"
#: editor/plugins/script_editor_plugin.cpp
msgid "External"
@@ -10449,7 +10431,7 @@ msgstr "強調顯示目å‰çš„腳本"
#: editor/plugins/script_editor_plugin.cpp
msgid "Script Temperature History Size"
-msgstr ""
+msgstr "腳本溫度歷å²å¤§å°"
#: editor/plugins/script_editor_plugin.cpp
msgid "Current Script Background Color"
@@ -10469,7 +10451,7 @@ msgstr "將腳本å稱列為"
#: editor/plugins/script_editor_plugin.cpp
msgid "Exec Flags"
-msgstr ""
+msgstr "執行旗標"
#: editor/plugins/script_editor_plugin.cpp
msgid "Clear Recent Scripts"
@@ -10986,43 +10968,43 @@ msgstr "(ä¸åœ¨GLES2中)"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
"Debug draw modes are only available when using the GLES3 renderer, not GLES2."
-msgstr "除錯繪製模å¼åƒ…在使用 GLES3 算繪引擎時å¯ç”¨ï¼ŒGLES2 ä¸å¯ç”¨ã€‚"
+msgstr "除錯繪製模å¼åƒ…å¯åœ¨ GLES3 算繪引擎下使用,無法在 GLES2 下使用。"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Left"
-msgstr "自由視圖 左"
+msgstr "自由觀看 左"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Right"
-msgstr "自由視圖 å³"
+msgstr "自由觀看 å³"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Forward"
-msgstr "自由視圖 å‰"
+msgstr "自由觀看 å‰"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Backwards"
-msgstr "自由視圖 後"
+msgstr "自由觀看 後"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Up"
-msgstr "自由視圖 上"
+msgstr "自由觀看 上"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Down"
-msgstr "自由視圖 下"
+msgstr "自由觀看 下"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Speed Modifier"
-msgstr "加速自由視圖速度"
+msgstr "自由觀看速度調整"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Slow Modifier"
-msgstr "放慢自由視圖速度"
+msgstr "自由觀看減速調整"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Toggle Camera Preview"
-msgstr "切æ›ç›¸æ©Ÿé è¦½é–‹é—œ"
+msgstr "開啟ï¼é—œé–‰ç›¸æ©Ÿé è¦½"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "View Rotation Locked"
@@ -11031,7 +11013,7 @@ msgstr "視圖旋轉已鎖定"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
"To zoom further, change the camera's clipping planes (View -> Settings...)"
-msgstr "è‹¥è¦å†ç¹¼çºŒæ”¾å¤§ï¼Œè«‹è‡³ 檢視 -> 設定... 修改æ”影機的剪è£å¹³é¢"
+msgstr "è‹¥è¦å†ç¹¼çºŒæ”¾å¤§ï¼Œè«‹è‡³ [檢視] -> [設定...] 修改æ”影機的剪è£å¹³é¢"
#: editor/plugins/spatial_editor_plugin.cpp
msgid ""
@@ -11278,16 +11260,15 @@ msgstr "後置"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Manipulator Gizmo Size"
-msgstr ""
+msgstr "æ“縱器控制項大å°"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Manipulator Gizmo Opacity"
-msgstr ""
+msgstr "æ“縱器控制項ä¸é€æ˜Žåº¦"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Show Viewport Rotation Gizmo"
-msgstr "鎖定視角旋轉"
+msgstr "顯示檢視å€çš„æ—‹è½‰æŽ§åˆ¶å™¨"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Unnamed Gizmo"
@@ -11338,9 +11319,8 @@ msgid "Invalid geometry, can't replace by mesh."
msgstr "無效的幾何圖形,無法以網格å–代。"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Convert to MeshInstance2D"
-msgstr "轉æ›ç‚º Mesh2D"
+msgstr "轉æ›ç‚º MeshInstance2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Invalid geometry, can't create polygon."
@@ -11443,9 +11423,8 @@ msgid "New Animation"
msgstr "新增動畫"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Filter animations"
-msgstr "ç¯©é¸æ–¹æ³•"
+msgstr "篩é¸å‹•ç•«"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Speed:"
@@ -11742,9 +11721,8 @@ msgstr ""
"確定è¦é—œé–‰å—Žï¼Ÿ"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove Type"
-msgstr "移除圖塊"
+msgstr "移除型別"
#: editor/plugins/theme_editor_plugin.cpp
msgid ""
@@ -11787,14 +11765,12 @@ msgstr ""
"手動加入更多項目於其中或從å¦ä¸€å€‹ä¸»é¡ŒåŒ¯å…¥ã€‚"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Add Theme Type"
-msgstr "新增項目類型"
+msgstr "新增主題型別"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove Theme Type"
-msgstr "移除項目"
+msgstr "移除主題型別"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Add Color Item"
@@ -11909,9 +11885,8 @@ msgid "Select Another Theme Resource:"
msgstr "鏿“‡å…¶ä»–主題資æºï¼š"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Theme Resource"
-msgstr "釿–°å‘½å資æº"
+msgstr "主題資æº"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Another Theme"
@@ -11923,21 +11898,19 @@ msgstr "新增類別"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Filter the list of types or create a new custom type:"
-msgstr ""
+msgstr "篩é¸åž‹åˆ¥åˆ—表,或是建立新的自定型別:"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Available Node-based types:"
-msgstr "å¯ç”¨è¨­å®šæª”:"
+msgstr "å¯ç”¨ä¹‹åŸºæ–¼ç¯€é»žçš„型別:"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Type name is empty!"
msgstr "型別å稱為空ï¼"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Are you sure you want to create an empty type?"
-msgstr "ç¢ºå®šè¦æ‰“開多個專案嗎?"
+msgstr "確定è¦å»ºç«‹ç©ºåž‹åˆ¥å—Žï¼Ÿ"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Confirm Item Rename"
@@ -11967,14 +11940,12 @@ msgid "Add Item Type"
msgstr "新增項目類型"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Set Variation Base Type"
-msgstr "設定變數型別"
+msgstr "設定變化基礎型別"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Set Base Type"
-msgstr "更改基礎型別"
+msgstr "設定基礎型別"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Show Default"
@@ -11994,13 +11965,13 @@ msgstr "複寫所有é è¨­é¡žåˆ¥é …目。"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Select the variation base type from a list of available types."
-msgstr ""
+msgstr "從å¯ç”¨çš„åž‹åˆ¥åˆ—è¡¨ä¸­é¸æ“‡åŸºç¤Žåž‹åˆ¥çš„變化。"
#: editor/plugins/theme_editor_plugin.cpp
msgid ""
"A type associated with a built-in class cannot be marked as a variation of "
"another type."
-msgstr ""
+msgstr "與內建型別相關è¯çš„型別無法被標記為å¦ä¸€å€‹åž‹åˆ¥çš„變化。"
#: editor/plugins/theme_editor_plugin.cpp
msgid "Theme:"
@@ -12235,55 +12206,46 @@ msgid "Clear Transform"
msgstr "清除變æ›"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Tile Map"
-msgstr "繪製圖塊地圖"
+msgstr "圖塊地圖"
#: editor/plugins/tile_map_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Palette Min Width"
-msgstr ""
+msgstr "調色盤最å°å¯¬åº¦"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Palette Item H Separation"
-msgstr "帶å稱的分隔線"
+msgstr "調色盤項目的水平分隔線"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Show Tile Names"
-msgstr "顯示所有地å€"
+msgstr "顯示圖塊å稱"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Show Tile Ids"
-msgstr "顯示尺è¦"
+msgstr "顯示圖塊 ID"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Sort Tiles By Name"
-msgstr "檔案排åº"
+msgstr "以å稱排åºåœ–塊"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Bucket Fill Preview"
-msgstr "油漆桶填滿"
+msgstr "油漆桶填充é è¦½"
#: editor/plugins/tile_map_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "Editor Side"
-msgstr "編輯器"
+msgstr "ç·¨è¼¯å™¨å´æ¬„"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Display Grid"
-msgstr "顯示éŽåº¦ç¹ªåœ–"
+msgstr "顯示柵欄"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Axis Color"
-msgstr "鏿“‡é¡è‰²"
+msgstr "座標軸é¡è‰²"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Add Texture(s) to TileSet."
@@ -12616,7 +12578,6 @@ msgid "This property can't be changed."
msgstr "該屬性無法修改。"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Snap Options"
msgstr "å¸é™„é¸é …"
@@ -12645,9 +12606,8 @@ msgid "Separation"
msgstr "é–“è·"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Selected Tile"
-msgstr "鏿“‡"
+msgstr "所é¸åœ–塊"
#: editor/plugins/tile_set_editor_plugin.cpp scene/2d/cpu_particles_2d.cpp
#: scene/2d/light_2d.cpp scene/2d/line_2d.cpp scene/2d/mesh_instance_2d.cpp
@@ -12656,9 +12616,8 @@ msgstr "鏿“‡"
#: scene/gui/nine_patch_rect.cpp scene/gui/texture_rect.cpp
#: scene/resources/material.cpp scene/resources/sky.cpp
#: scene/resources/style_box.cpp scene/resources/visual_shader_nodes.cpp
-#, fuzzy
msgid "Texture"
-msgstr "純文字"
+msgstr "ç´‹ç†è²¼åœ–"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Tex Offset"
@@ -12672,86 +12631,72 @@ msgstr "æè³ª"
#: editor/plugins/tile_set_editor_plugin.cpp scene/2d/canvas_item.cpp
#: scene/3d/label_3d.cpp scene/3d/sprite_3d.cpp scene/resources/style_box.cpp
-#, fuzzy
msgid "Modulate"
-msgstr "å¡«å……"
+msgstr "調變"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Tile Mode"
-msgstr "åˆ‡æ›æ¨¡å¼"
+msgstr "圖塊模å¼"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Autotile Bitmask Mode"
-msgstr "優先模å¼"
+msgstr "自動圖塊的ä½å…ƒé®ç½©æ¨¡å¼"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Subtile Size"
msgstr "å­åœ–塊大å°"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Subtile Spacing"
-msgstr "行間è·"
+msgstr "自圖塊間è·"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Occluder Offset"
-msgstr "建立é®å…‰å¤šé‚Šå½¢"
+msgstr "é®å…‰åç§»"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Navigation Offset"
-msgstr "導航模å¼"
+msgstr "導航åç§»"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Shape Offset"
msgstr "形狀åç§»"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Shape Transform"
-msgstr "變æ›"
+msgstr "形狀變æ›"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Selected Collision"
-msgstr "碰撞"
+msgstr "所é¸ç¢°æ’ž"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Selected Collision One Way"
-msgstr "僅æœå°‹æ‰€é¸å€åŸŸ"
+msgstr "所é¸ç¢°æ’žå–®å‘"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Selected Collision One Way Margin"
-msgstr "碰撞模å¼"
+msgstr "所é¸ç¢°æ’žå–®å‘外邊è·"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Selected Navigation"
-msgstr "顯示導航"
+msgstr "所é¸å°Žèˆª"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Selected Occlusion"
-msgstr "鏿“‡"
+msgstr "所é¸é®æ“‹"
#: editor/plugins/tile_set_editor_plugin.cpp
-#, fuzzy
msgid "Tileset Script"
-msgstr "篩é¸è…³æœ¬"
+msgstr "圖塊集腳本"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "TileSet"
msgstr "圖塊集"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "No VCS plugins are available."
-msgstr "ç„¡å¯ç”¨çš„版本控制 (VCS) 擴充功能。"
+msgstr "ç„¡å¯ç”¨çš„版本控制 (VCS) 外掛。"
#: editor/plugins/version_control_editor_plugin.cpp
msgid ""
@@ -12759,9 +12704,8 @@ msgid ""
msgstr "é ç«¯è¨­å®šæ˜¯ç©ºçš„。使用網路的VCS功能æç„¡æ³•é‹ä½œã€‚"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "No commit message was provided."
-msgstr "未æä¾›å稱。"
+msgstr "未æä¾›èªå¯ (Commit) 訊æ¯ã€‚"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Commit"
@@ -12792,14 +12736,12 @@ msgid "Do you want to remove the %s branch?"
msgstr "你確定è¦ç§»é™¤ %s 分支?"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Do you want to remove the %s remote?"
-msgstr "ç¢ºå®šè¦æ‰“開多個專案嗎?"
+msgstr "確定è¦ç§»é™¤é ç«¯ã€Œ%sã€ï¼Ÿ"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Apply"
-msgstr "套用é‡è¨­"
+msgstr "套用"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Version Control System"
@@ -12810,9 +12752,8 @@ msgid "Initialize"
msgstr "åˆå§‹åŒ–"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Remote Login"
-msgstr "移除控制點"
+msgstr "é ç«¯ç™»å…¥"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Select SSH public key path"
@@ -12843,55 +12784,48 @@ msgid "Unstage all changes"
msgstr "撤銷暫存所有變更"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Commit Message"
-msgstr "æäº¤æ”¹å‹•"
+msgstr "èªå¯ (Commit) 訊æ¯"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Commit Changes"
msgstr "æäº¤æ”¹å‹•"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Commit List"
-msgstr "æäº¤"
+msgstr "èªå¯åˆ—表"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Commit list size"
-msgstr "簽入列表大å°"
+msgstr "èªå¯åˆ—表大å°"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Branches"
msgstr "分支"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Create New Branch"
-msgstr "建立新專案"
+msgstr "建立分支"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Remove Branch"
-msgstr "刪除動畫軌"
+msgstr "移除分支"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Branch Name"
msgstr "分支å稱"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Remotes"
msgstr "é ç«¯"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Create New Remote"
-msgstr "建立新專案"
+msgstr "建立é ç«¯"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Remove Remote"
-msgstr "移除項目"
+msgstr "移除é ç«¯"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Remote Name"
@@ -12903,15 +12837,15 @@ msgstr "é ç«¯ç¶²å€"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Fetch"
-msgstr "æå–"
+msgstr "æˆªå– (Fetch)"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Pull"
-msgstr "拉é€"
+msgstr "æå– (Pull)"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Push"
-msgstr "推é€"
+msgstr "æŽ¨é€ (Push)"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Force Push"
@@ -12919,7 +12853,7 @@ msgstr "強制推é€"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Modified"
-msgstr "已修改"
+msgstr "修改"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Renamed"
@@ -12927,11 +12861,11 @@ msgstr "釿–°å‘½å"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Deleted"
-msgstr "已刪除"
+msgstr "刪除"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Typechange"
-msgstr "æ ¼å¼æ›´æ”¹"
+msgstr "更改型別"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Unmerged"
@@ -12942,14 +12876,12 @@ msgid "View:"
msgstr "檢視:"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Split"
-msgstr "拆分路徑"
+msgstr "分割"
#: editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Unified"
-msgstr "已修改"
+msgstr "åˆä½µ"
#: editor/plugins/visual_shader_editor_plugin.cpp
msgid "(GLES3 only)"
@@ -13806,11 +13738,11 @@ msgstr "å¯åŸ·è¡Œ"
#: editor/project_export.cpp
msgid "Export the project for all the presets defined."
-msgstr ""
+msgstr "使用æ¯å€‹å·²å®šç¾©çš„é è¨­è¨­å®šä¾†åŒ¯å‡ºè©²å°ˆæ¡ˆã€‚"
#: editor/project_export.cpp
msgid "All presets must have an export path defined for Export All to work."
-msgstr ""
+msgstr "所有é è¨­è¨­å®šéƒ½å¿…須定義好匯出路徑,æ‰å¯ä½¿ç”¨ [匯出全部] 功能。"
#: editor/project_export.cpp
msgid "Delete preset '%s'?"
@@ -13921,11 +13853,12 @@ msgid ""
"Note: Encryption key needs to be stored in the binary,\n"
"you need to build the export templates from source."
msgstr ""
+"注æ„:加密金鑰必須以二進ä½å½¢å¼ä¿å­˜ï¼Œ\n"
+"必須從原始碼來編譯匯出樣æ¿ã€‚"
#: editor/project_export.cpp
-#, fuzzy
msgid "More Info..."
-msgstr "移動至..."
+msgstr "更多資訊..."
#: editor/project_export.cpp
msgid "Export PCK/Zip..."
@@ -13952,18 +13885,16 @@ msgid "ZIP File"
msgstr "ZIP 檔案"
#: editor/project_export.cpp
-#, fuzzy
msgid "Godot Project Pack"
-msgstr "Godot éŠæˆ²åŒ…"
+msgstr "Godot 專案包"
#: editor/project_export.cpp
msgid "Export templates for this platform are missing:"
msgstr "缺少匯出該平å°ç”¨çš„æ¨£æ¿ï¼š"
#: editor/project_export.cpp
-#, fuzzy
msgid "Project Export"
-msgstr "專案發起人"
+msgstr "專案匯出"
#: editor/project_export.cpp
msgid "Manage Export Templates"
@@ -14263,7 +14194,6 @@ msgstr ""
#. TRANSLATORS: This refers to the application where users manage their Godot projects.
#: editor/project_manager.cpp
-#, fuzzy
msgctxt "Application"
msgid "Project Manager"
msgstr "專案管ç†å“¡"
@@ -15007,6 +14937,9 @@ msgid ""
"To save this branch into its own scene, open the original scene, right click "
"on this branch, and select \"Save Branch as Scene\"."
msgstr ""
+"無法ä¿å­˜åˆ†æ”¯ï¼Œè©²åˆ†æ”¯æ˜¯å·²å¯¦é«”化場景的å­é …目。\n"
+"è‹¥è¦å°‡è©²åˆ†æ”¯ä¿å­˜é€²ç¨ç«‹çš„場景中,請開啟原始場景,並在該分支上點擊å³éµï¼Œç„¶å¾Œé¸"
+"擇 [將分支ä¿å­˜ç‚ºå ´æ™¯]。"
#: editor/scene_tree_dock.cpp
msgid ""
@@ -15014,6 +14947,9 @@ msgid ""
"To save this branch into its own scene, open the original scene, right click "
"on this branch, and select \"Save Branch as Scene\"."
msgstr ""
+"無法ä¿å­˜åˆ†æ”¯ï¼Œè©²åˆ†æ”¯æ˜¯ç¹¼æ‰¿å ´æ™¯çš„一部分。\n"
+"è‹¥è¦å°‡è©²åˆ†æ”¯ä¿å­˜ç‚ºç¨ç«‹çš„場景,請開啟原始場景,並在該分支上點擊å³éµï¼Œç„¶å¾Œé¸æ“‡ "
+"[將分支ä¿å­˜ç‚ºå ´æ™¯]。"
#: editor/scene_tree_dock.cpp
msgid "Save New Scene As..."
@@ -15039,7 +14975,7 @@ msgstr "轉為本地"
#: editor/scene_tree_dock.cpp editor/scene_tree_editor.cpp
msgid "Another node already uses this unique name in the scene."
-msgstr ""
+msgstr "å¦ä¸€å€‹ç¯€é»žå·²åœ¨è©²å ´æ™¯ä¸­ä½¿ç”¨äº†é€™å€‹ä¸å¯é‡è¤‡çš„å稱。"
#: editor/scene_tree_dock.cpp
msgid "Enable Scene Unique Name"
@@ -15121,7 +15057,7 @@ msgstr "å­è³‡æº"
#: editor/scene_tree_dock.cpp
msgid "Access as Scene Unique Name"
-msgstr ""
+msgstr "以ä¸é‡è¤‡çš„場景å稱來存å–"
#: editor/scene_tree_dock.cpp
msgid "Clear Inheritance"
@@ -15216,18 +15152,16 @@ msgid "Clear Inheritance? (No Undo!)"
msgstr "ç¢ºå®šè¦æ¸…除繼承嗎?(無法復原ï¼ï¼‰"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Show Scene Tree Root Selection"
-msgstr "置中所é¸"
+msgstr "é¡¯ç¤ºå ´æ™¯æ¨¹çš„æ ¹é¸æ“‡"
#: editor/scene_tree_dock.cpp
msgid "Derive Script Globals By Name"
-msgstr ""
+msgstr "ä¾ç…§å稱來推斷腳本的全域變數"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Use Favorites Root Selection"
-msgstr "完整顯示所é¸"
+msgstr "ä½¿ç”¨æˆ‘çš„æœ€æ„›æ ¹é¸æ“‡"
#: editor/scene_tree_editor.cpp
msgid "Toggle Visible"
@@ -15255,6 +15189,8 @@ msgid ""
"with the '%s' prefix in a node path.\n"
"Click to disable this."
msgstr ""
+"該節點å¯åœ¨æ­¤å ´æ™¯ä¸­çš„任何地方通éŽåœ¨ç¯€é»žè·¯å¾‘剿–¹åŠ ä¸Šã€Œ%sã€å‰ç½®è©žä¾†å­˜å–。\n"
+"點擊以ç¦ç”¨ã€‚"
#: editor/scene_tree_editor.cpp
msgid ""
@@ -15537,21 +15473,20 @@ msgid "Stack Frames"
msgstr "堆疊框"
#: editor/script_editor_debugger.cpp
-#, fuzzy
msgid "Filter stack variables"
-msgstr "篩é¸åœ–塊"
+msgstr "篩é¸å †ç–Šè®Šæ•¸"
#: editor/script_editor_debugger.cpp
msgid "Auto Switch To Remote Scene Tree"
-msgstr ""
+msgstr "自動切æ›è‡³é ç«¯å ´æ™¯æ¨¹"
#: editor/script_editor_debugger.cpp
msgid "Remote Scene Tree Refresh Interval"
-msgstr ""
+msgstr "é ç«¯å ´æ™¯æ¨¹é‡æ–°æ•´ç†é–“éš”"
#: editor/script_editor_debugger.cpp
msgid "Remote Inspect Refresh Interval"
-msgstr ""
+msgstr "é ç«¯æª¢æŸ¥é‡æ–°æ•´ç†é–“éš”"
#: editor/script_editor_debugger.cpp
msgid "Network Profiler"
@@ -15649,7 +15584,7 @@ msgstr "更改光照åŠå¾‘"
#: editor/spatial_editor_gizmos.cpp
msgid "Stream Player 3D"
-msgstr ""
+msgstr "StreamPlayer3D"
#: editor/spatial_editor_gizmos.cpp
msgid "Change AudioStreamPlayer3D Emission Angle"
@@ -15659,7 +15594,7 @@ msgstr "更改 AudioStreamPlayer3D 發射角"
#: platform/osx/export/export.cpp
#: scene/resources/default_theme/default_theme.cpp
msgid "Camera"
-msgstr ""
+msgstr "相機"
#: editor/spatial_editor_gizmos.cpp
msgid "Change Camera FOV"
@@ -15671,7 +15606,7 @@ msgstr "更改相機尺寸"
#: editor/spatial_editor_gizmos.cpp
msgid "Visibility Notifier"
-msgstr ""
+msgstr "VisibilityNotifier"
#: editor/spatial_editor_gizmos.cpp
msgid "Change Notifier AABB"
@@ -15682,23 +15617,20 @@ msgid "Change Particles AABB"
msgstr "æ›´æ”¹ç²’å­ AABB"
#: editor/spatial_editor_gizmos.cpp
-#, fuzzy
msgid "Reflection Probe"
-msgstr "鏿“‡å±¬æ€§"
+msgstr "å射探查"
#: editor/spatial_editor_gizmos.cpp
msgid "Change Probe Extents"
msgstr "更改探查範åœ"
#: editor/spatial_editor_gizmos.cpp
-#, fuzzy
msgid "GI Probe"
-msgstr "烘焙 GI 探查"
+msgstr "GI 探查"
#: editor/spatial_editor_gizmos.cpp
-#, fuzzy
msgid "Baked Indirect Light"
-msgstr "éžå‘性光照"
+msgstr "烘焙間接光照"
#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
msgid "Change Sphere Shape Radius"
@@ -15729,14 +15661,12 @@ msgid "Change Ray Shape Length"
msgstr "更改射線形長度"
#: editor/spatial_editor_gizmos.cpp
-#, fuzzy
msgid "Navigation Edge"
-msgstr "導航模å¼"
+msgstr "導航邊界"
#: editor/spatial_editor_gizmos.cpp
-#, fuzzy
msgid "Navigation Edge Disabled"
-msgstr "導航模å¼"
+msgstr "å·²ç¦ç”¨å°Žèˆªé‚Šç•Œ"
#: editor/spatial_editor_gizmos.cpp
#, fuzzy
@@ -19984,15 +19914,15 @@ msgstr "找ä¸åˆ°é‡‘鑰儲存å€ï¼Œç„¡æ³•匯出。"
#: platform/windows/export/export.cpp
msgid ""
-"Could not start rcedit executable, configure rcedit path in the Editor "
-"Settings (Export > Windows > Rcedit)."
+"Could not start rcedit executable. Configure rcedit path in the Editor "
+"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
+"Resources\" in the export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"rcedit failed to modify executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "rcedit failed to modify executable: %s."
+msgstr "無效的副檔å。"
#: platform/windows/export/export.cpp
#, fuzzy
@@ -20015,15 +19945,15 @@ msgstr "無效的å稱。"
#: platform/windows/export/export.cpp
msgid ""
-"Could not start signtool executable, configure signtool path in the Editor "
-"Settings (Export > Windows > Signtool)."
+"Could not start signtool executable. Configure signtool path in the Editor "
+"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
+"export preset."
msgstr ""
#: platform/windows/export/export.cpp
-msgid ""
-"Signtool failed to sign executable:\n"
-"%s"
-msgstr ""
+#, fuzzy
+msgid "Signtool failed to sign executable: %s."
+msgstr "無效的副檔å。"
#: platform/windows/export/export.cpp
msgid "Failed to remove temporary file \"%s\"."
@@ -26646,9 +26576,8 @@ msgid "Normal Texture"
msgstr "法線紋ç†è²¼åœ–"
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Color Texture"
-msgstr "編輯器主題"
+msgstr "é¡è‰²ç´‹ç†è²¼åœ–"
#: scene/resources/particles_material.cpp
#, fuzzy
diff --git a/gles3_builders.py b/gles3_builders.py
index a9fabd93ce..eafe503dd5 100644
--- a/gles3_builders.py
+++ b/gles3_builders.py
@@ -182,8 +182,8 @@ def include_file_in_gles3_header(filename, header_data, depth):
return header_data
-def build_gles3_header(filename, include, class_suffix, output_attribs):
- header_data = GLES3HeaderStruct()
+def build_gles3_header(filename, include, class_suffix, header_data=None):
+ header_data = header_data or GLES3HeaderStruct()
include_file_in_gles3_header(filename, header_data, 0)
out_file = filename + ".gen.h"
@@ -191,8 +191,6 @@ def build_gles3_header(filename, include, class_suffix, output_attribs):
defspec = 0
defvariant = ""
- enum_constants = []
-
fd.write("/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */\n")
out_file_base = out_file
@@ -552,7 +550,7 @@ def build_gles3_header(filename, include, class_suffix, output_attribs):
def build_gles3_headers(target, source, env):
for x in source:
- build_gles3_header(str(x), include="drivers/gles3/shader_gles3.h", class_suffix="GLES3", output_attribs=True)
+ build_gles3_header(str(x), include="drivers/gles3/shader_gles3.h", class_suffix="GLES3")
if __name__ == "__main__":
diff --git a/glsl_builders.py b/glsl_builders.py
index 0926212e50..8cb5807f21 100644
--- a/glsl_builders.py
+++ b/glsl_builders.py
@@ -3,9 +3,26 @@
All such functions are invoked in a subprocess on Windows to prevent build flakiness.
"""
+import os.path
from platform_methods import subprocess_main
+def generate_inline_code(input_lines, insert_newline=True):
+ """Take header data and generate inline code
+
+ :param: list input_lines: values for shared inline code
+ :return: str - generated inline value
+ """
+ output = []
+ for line in input_lines:
+ if line:
+ output.append(",".join(str(ord(c)) for c in line))
+ if insert_newline:
+ output.append("%s" % ord("\n"))
+ output.append("0")
+ return ",".join(output)
+
+
class RDHeaderStruct:
def __init__(self):
self.vertex_lines = []
@@ -57,10 +74,6 @@ def include_file_in_rd_header(filename, header_data, depth):
while line.find("#include ") != -1:
includeline = line.replace("#include ", "").strip()[1:-1]
- import os.path
-
- included_file = ""
-
if includeline.startswith("thirdparty/"):
included_file = os.path.relpath(includeline)
@@ -82,8 +95,7 @@ def include_file_in_rd_header(filename, header_data, depth):
line = fs.readline()
- line = line.replace("\r", "")
- line = line.replace("\n", "")
+ line = line.replace("\r", "").replace("\n", "")
if header_data.reading == "vertex":
header_data.vertex_lines += [line]
@@ -100,65 +112,53 @@ def include_file_in_rd_header(filename, header_data, depth):
return header_data
-def build_rd_header(filename):
- header_data = RDHeaderStruct()
+def build_rd_header(filename, header_data=None):
+ header_data = header_data or RDHeaderStruct()
include_file_in_rd_header(filename, header_data, 0)
out_file = filename + ".gen.h"
- fd = open(out_file, "w")
-
- fd.write("/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */\n")
-
out_file_base = out_file
out_file_base = out_file_base[out_file_base.rfind("/") + 1 :]
out_file_base = out_file_base[out_file_base.rfind("\\") + 1 :]
out_file_ifdef = out_file_base.replace(".", "_").upper()
- fd.write("#ifndef " + out_file_ifdef + "_RD\n")
- fd.write("#define " + out_file_ifdef + "_RD\n")
-
out_file_class = out_file_base.replace(".glsl.gen.h", "").title().replace("_", "").replace(".", "") + "ShaderRD"
- fd.write("\n")
- fd.write('#include "servers/rendering/renderer_rd/shader_rd.h"\n\n')
- fd.write("class " + out_file_class + " : public ShaderRD {\n\n")
- fd.write("public:\n\n")
- fd.write("\t" + out_file_class + "() {\n\n")
+ if header_data.compute_lines:
+ body_parts = [
+ "static const char _compute_code[] = {\n%s\n\t\t};" % generate_inline_code(header_data.compute_lines),
+ f'setup(nullptr, nullptr, _compute_code, "{out_file_class}");',
+ ]
+ else:
+ body_parts = [
+ "static const char _vertex_code[] = {\n%s\n\t\t};" % generate_inline_code(header_data.vertex_lines),
+ "static const char _fragment_code[] = {\n%s\n\t\t};" % generate_inline_code(header_data.fragment_lines),
+ f'setup(_vertex_code, _fragment_code, nullptr, "{out_file_class}");',
+ ]
- if len(header_data.compute_lines):
+ body_content = "\n\t\t".join(body_parts)
- fd.write("\t\tstatic const char _compute_code[] = {\n")
- for x in header_data.compute_lines:
- for c in x:
- fd.write(str(ord(c)) + ",")
- fd.write(str(ord("\n")) + ",")
- fd.write("\t\t0};\n\n")
+ # Intended curly brackets are doubled so f-string doesn't eat them up.
+ shader_template = f"""/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */
+#ifndef {out_file_ifdef}_RD
+#define {out_file_ifdef}_RD
- fd.write('\t\tsetup(nullptr, nullptr, _compute_code, "' + out_file_class + '");\n')
- fd.write("\t}\n")
+#include "servers/rendering/renderer_rd/shader_rd.h"
- else:
+class {out_file_class} : public ShaderRD {{
- fd.write("\t\tstatic const char _vertex_code[] = {\n")
- for x in header_data.vertex_lines:
- for c in x:
- fd.write(str(ord(c)) + ",")
- fd.write(str(ord("\n")) + ",")
- fd.write("\t\t0};\n\n")
+public:
- fd.write("\t\tstatic const char _fragment_code[]={\n")
- for x in header_data.fragment_lines:
- for c in x:
- fd.write(str(ord(c)) + ",")
- fd.write(str(ord("\n")) + ",")
- fd.write("\t\t0};\n\n")
+ {out_file_class}() {{
- fd.write('\t\tsetup(_vertex_code, _fragment_code, nullptr, "' + out_file_class + '");\n')
- fd.write("\t}\n")
+ {body_content}
+ }}
+}};
- fd.write("};\n\n")
+#endif
+"""
- fd.write("#endif\n")
- fd.close()
+ with open(out_file, "w") as fd:
+ fd.write(shader_template)
def build_rd_headers(target, source, env):
@@ -180,8 +180,6 @@ def include_file_in_raw_header(filename, header_data, depth):
while line.find("#include ") != -1:
includeline = line.replace("#include ", "").strip()[1:-1]
- import os.path
-
included_file = os.path.relpath(os.path.dirname(filename) + "/" + includeline)
include_file_in_raw_header(included_file, header_data, depth + 1)
@@ -193,28 +191,28 @@ def include_file_in_raw_header(filename, header_data, depth):
fs.close()
-def build_raw_header(filename):
- header_data = RAWHeaderStruct()
+def build_raw_header(filename, header_data=None):
+ header_data = header_data or RAWHeaderStruct()
include_file_in_raw_header(filename, header_data, 0)
out_file = filename + ".gen.h"
- fd = open(out_file, "w")
-
- fd.write("/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */\n")
-
out_file_base = out_file.replace(".glsl.gen.h", "_shader_glsl")
out_file_base = out_file_base[out_file_base.rfind("/") + 1 :]
out_file_base = out_file_base[out_file_base.rfind("\\") + 1 :]
out_file_ifdef = out_file_base.replace(".", "_").upper()
- fd.write("#ifndef " + out_file_ifdef + "_RAW_H\n")
- fd.write("#define " + out_file_ifdef + "_RAW_H\n")
- fd.write("\n")
- fd.write("static const char " + out_file_base + "[] = {\n")
- for c in header_data.code:
- fd.write(str(ord(c)) + ",")
- fd.write("\t\t0};\n\n")
- fd.write("#endif\n")
- fd.close()
+
+ shader_template = f"""/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */
+#ifndef {out_file_ifdef}_RAW_H
+#define {out_file_ifdef}_RAW_H
+
+static const char {out_file_base}[] = {{
+ {generate_inline_code(header_data.code, insert_newline=False)}
+}};
+#endif
+"""
+
+ with open(out_file, "w") as f:
+ f.write(shader_template)
def build_raw_headers(target, source, env):
diff --git a/main/main.cpp b/main/main.cpp
index 42a866317e..d0170d8093 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -31,6 +31,7 @@
#include "main.h"
#include "core/config/project_settings.h"
+#include "core/core_globals.h"
#include "core/core_string_names.h"
#include "core/crypto/crypto.h"
#include "core/debugger/engine_debugger.h"
@@ -62,6 +63,7 @@
#include "scene/main/window.h"
#include "scene/register_scene_types.h"
#include "scene/resources/packed_scene.h"
+#include "scene/theme/theme_db.h"
#include "servers/audio_server.h"
#include "servers/camera_server.h"
#include "servers/display_server.h"
@@ -128,6 +130,7 @@ static PhysicsServer3D *physics_server_3d = nullptr;
static PhysicsServer2D *physics_server_2d = nullptr;
static NavigationServer3D *navigation_server_3d = nullptr;
static NavigationServer2D *navigation_server_2d = nullptr;
+static ThemeDB *theme_db = nullptr;
// We error out if setup2() doesn't turn this true
static bool _start_success = false;
@@ -142,6 +145,7 @@ static int audio_driver_idx = -1;
// Engine config/tools
+static bool single_window = false;
static bool editor = false;
static bool project_manager = false;
static bool cmdline_tool = false;
@@ -152,7 +156,13 @@ static OS::ProcessID editor_pid = 0;
#ifdef TOOLS_ENABLED
static bool auto_build_solutions = false;
static String debug_server_uri;
+static int converter_max_kb_file = 4 * 1024; // 4MB
+static int converter_max_line_length = 100000;
+
+HashMap<Main::CLIScope, Vector<String>> forwardable_cli_arguments;
#endif
+bool use_startup_benchmark = false;
+String startup_benchmark_file;
// Display
@@ -160,7 +170,7 @@ static DisplayServer::WindowMode window_mode = DisplayServer::WINDOW_MODE_WINDOW
static DisplayServer::ScreenOrientation window_orientation = DisplayServer::SCREEN_LANDSCAPE;
static DisplayServer::VSyncMode window_vsync_mode = DisplayServer::VSYNC_ENABLED;
static uint32_t window_flags = 0;
-static Size2i window_size = Size2i(1024, 600);
+static Size2i window_size = Size2i(1152, 648);
static int init_screen = -1;
static bool init_fullscreen = false;
@@ -195,6 +205,12 @@ bool Main::is_cmdline_tool() {
return cmdline_tool;
}
+#ifdef TOOLS_ENABLED
+const Vector<String> &Main::get_forwardable_cli_arguments(Main::CLIScope p_scope) {
+ return forwardable_cli_arguments[p_scope];
+}
+#endif
+
static String unescape_cmdline(const String &p_str) {
return p_str.replace("%20", " ");
}
@@ -261,6 +277,16 @@ void finalize_navigation_server() {
navigation_server_2d = nullptr;
}
+void initialize_theme_db() {
+ theme_db = memnew(ThemeDB);
+ theme_db->initialize_theme();
+}
+
+void finalize_theme_db() {
+ memdelete(theme_db);
+ theme_db = nullptr;
+}
+
//#define DEBUG_INIT
#ifdef DEBUG_INIT
#define MAIN_PRINT(m_txt) print_line(m_txt)
@@ -285,6 +311,7 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print("\n");
OS::get_singleton()->print("Run options:\n");
+ OS::get_singleton()->print(" -- Separator for user-provided arguments. Following arguments are not used by the engine, but can be read from `OS.get_cmdline_user_args()`.\n");
#ifdef TOOLS_ENABLED
OS::get_singleton()->print(" -e, --editor Start the editor instead of running the scene.\n");
OS::get_singleton()->print(" -p, --project-manager Start the project manager, even if a project is auto-detected.\n");
@@ -378,12 +405,14 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print(" <path> should be absolute or relative to the project directory, and include the filename for the binary (e.g. 'builds/game.exe'). The target directory should exist.\n");
OS::get_singleton()->print(" --export-debug <preset> <path> Same as --export, but using the debug template.\n");
OS::get_singleton()->print(" --export-pack <preset> <path> Same as --export, but only export the game pack for the given preset. The <path> extension determines whether it will be in PCK or ZIP format.\n");
- OS::get_singleton()->print(" --convert-3to4 Converts project from Godot 3.x to Godot 4.x.\n");
- OS::get_singleton()->print(" --validate-conversion-3to4 Shows what elements will be renamed when converting project from Godot 3.x to Godot 4.x.\n");
+ OS::get_singleton()->print(" --convert-3to4 [<max_file_kb>] [<max_line_size>] Converts project from Godot 3.x to Godot 4.x.\n");
+ OS::get_singleton()->print(" --validate-conversion-3to4 [<max_file_kb>] [<max_line_size>] Shows what elements will be renamed when converting project from Godot 3.x to Godot 4.x.\n");
OS::get_singleton()->print(" --doctool [<path>] Dump the engine API reference to the given <path> (defaults to current dir) in XML format, merging if existing files are found.\n");
OS::get_singleton()->print(" --no-docbase Disallow dumping the base types (used with --doctool).\n");
OS::get_singleton()->print(" --build-solutions Build the scripting solutions (e.g. for C# projects). Implies --editor and requires a valid project to edit.\n");
OS::get_singleton()->print(" --dump-extension-api Generate JSON dump of the Godot API for GDExtension bindings named 'extension_api.json' in the current folder.\n");
+ OS::get_singleton()->print(" --startup-benchmark Benchmark the startup time and print it to console.\n");
+ OS::get_singleton()->print(" --startup-benchmark-file <path> Benchmark the startup time and save it to a given file in JSON format.\n");
#ifdef TESTS_ENABLED
OS::get_singleton()->print(" --test [--help] Run unit tests. Use --test --help for more information.\n");
#endif
@@ -429,6 +458,7 @@ Error Main::test_setup() {
/** INITIALIZE SERVERS **/
register_server_types();
+ XRServer::set_xr_mode(XRServer::XRMODE_OFF); // Skip in tests.
initialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
NativeExtensionManager::get_singleton()->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS);
@@ -459,7 +489,8 @@ Error Main::test_setup() {
register_platform_apis();
// Theme needs modules to be initialized so that sub-resources can be loaded.
- initialize_theme();
+ initialize_theme_db();
+ register_scene_singletons();
ERR_FAIL_COND_V(TextServerManager::get_singleton()->get_interface_count() == 0, ERR_CANT_CREATE);
@@ -510,6 +541,8 @@ void Main::test_cleanup() {
unregister_driver_types();
unregister_scene_types();
+ finalize_theme_db();
+
NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS);
uninitialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
unregister_server_types();
@@ -591,6 +624,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
engine = memnew(Engine);
MAIN_PRINT("Main: Initialize CORE");
+ engine->startup_begin();
+ engine->startup_benchmark_begin_measure("core");
register_core_types();
register_core_driver_types();
@@ -623,6 +658,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
/* argument parsing and main creation */
List<String> args;
List<String> main_args;
+ List<String> user_args;
+ bool adding_user_args = false;
List<String> platform_args = OS::get_singleton()->get_cmdline_platform_args();
// Add command line arguments.
@@ -695,9 +732,32 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
continue;
}
#endif
+
List<String>::Element *N = I->next();
- if (I->get() == "-h" || I->get() == "--help" || I->get() == "/?") { // display help
+#ifdef TOOLS_ENABLED
+ if (I->get() == "--debug" ||
+ I->get() == "--verbose" ||
+ I->get() == "--disable-crash-handler") {
+ forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(I->get());
+ forwardable_cli_arguments[CLI_SCOPE_PROJECT].push_back(I->get());
+ }
+ if (I->get() == "--single-window") {
+ forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(I->get());
+ }
+ if (I->get() == "--audio-driver" ||
+ I->get() == "--display-driver" ||
+ I->get() == "--rendering-driver") {
+ if (I->next()) {
+ forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(I->get());
+ forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(I->next()->get());
+ }
+ }
+#endif
+
+ if (adding_user_args) {
+ user_args.push_back(I->get());
+ } else if (I->get() == "-h" || I->get() == "--help" || I->get() == "/?") { // display help
show_help = true;
exit_code = ERR_HELP; // Hack to force an early exit in `main()` with a success code.
@@ -873,7 +933,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
} else if (I->get() == "--single-window") { // force single window
- OS::get_singleton()->_single_window = true;
+ single_window = true;
} else if (I->get() == "-t" || I->get() == "--always-on-top") { // force always-on-top window
init_always_on_top = true;
@@ -1028,10 +1088,32 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
// Actually handling is done in start().
cmdline_tool = true;
main_args.push_back(I->get());
+
+ if (I->next() && !I->next()->get().begins_with("-")) {
+ if (itos(I->next()->get().to_int()) == I->next()->get()) {
+ converter_max_kb_file = I->next()->get().to_int();
+ }
+ if (I->next()->next() && !I->next()->next()->get().begins_with("-")) {
+ if (itos(I->next()->next()->get().to_int()) == I->next()->next()->get()) {
+ converter_max_line_length = I->next()->next()->get().to_int();
+ }
+ }
+ }
} else if (I->get() == "--validate-conversion-3to4") {
// Actually handling is done in start().
cmdline_tool = true;
main_args.push_back(I->get());
+
+ if (I->next() && !I->next()->get().begins_with("-")) {
+ if (itos(I->next()->get().to_int()) == I->next()->get()) {
+ converter_max_kb_file = I->next()->get().to_int();
+ }
+ if (I->next()->next() && !I->next()->next()->get().begins_with("-")) {
+ if (itos(I->next()->next()->get().to_int()) == I->next()->next()->get()) {
+ converter_max_line_length = I->next()->next()->get().to_int();
+ }
+ }
+ }
} else if (I->get() == "--doctool") {
// Actually handling is done in start().
cmdline_tool = true;
@@ -1201,6 +1283,20 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
goto error;
}
+ } else if (I->get() == "--startup-benchmark") {
+ use_startup_benchmark = true;
+ } else if (I->get() == "--startup-benchmark-file") {
+ if (I->next()) {
+ use_startup_benchmark = true;
+ startup_benchmark_file = I->next()->get();
+ N = I->next()->next();
+ } else {
+ OS::get_singleton()->print("Missing <path> argument for --startup-benchmark-file <path>.\n");
+ goto error;
+ }
+
+ } else if (I->get() == "--") {
+ adding_user_args = true;
} else {
main_args.push_back(I->get());
}
@@ -1368,16 +1464,16 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
quiet_stdout = true;
}
if (bool(ProjectSettings::get_singleton()->get("application/run/disable_stderr"))) {
- _print_error_enabled = false;
+ CoreGlobals::print_error_enabled = false;
};
if (quiet_stdout) {
- _print_line_enabled = false;
+ CoreGlobals::print_line_enabled = false;
}
Logger::set_flush_stdout_on_print(ProjectSettings::get_singleton()->get("application/run/flush_stdout_on_print"));
- OS::get_singleton()->set_cmdline(execpath, main_args);
+ OS::get_singleton()->set_cmdline(execpath, main_args, user_args);
// possibly be worth changing the default from vulkan to something lower spec,
// for the project manager, depending on how smooth the fallback is.
@@ -1472,7 +1568,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->_allow_layered = false;
}
- OS::get_singleton()->_keep_screen_on = GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true);
if (rtm == -1) {
rtm = GLOBAL_DEF("rendering/driver/threads/thread_model", OS::RENDER_THREAD_SAFE);
}
@@ -1616,6 +1711,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
message_queue = memnew(MessageQueue);
+ engine->startup_benchmark_end_measure(); // core
+
if (p_second_phase) {
return setup2();
}
@@ -1670,6 +1767,7 @@ error:
unregister_core_types();
OS::get_singleton()->_cmdline.clear();
+ OS::get_singleton()->_user_args.clear();
if (message_queue) {
memdelete(message_queue);
@@ -1681,6 +1779,8 @@ error:
}
Error Main::setup2(Thread::ID p_main_tid_override) {
+ engine->startup_benchmark_begin_measure("servers");
+
tsman = memnew(TextServerManager);
if (tsman) {
@@ -1842,7 +1942,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
MAIN_PRINT("Main: Setup Logo");
-#if defined(JAVASCRIPT_ENABLED) || defined(ANDROID_ENABLED)
+#if defined(WEB_ENABLED) || defined(ANDROID_ENABLED)
bool show_logo = false;
#else
bool show_logo = true;
@@ -1988,10 +2088,16 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
GLOBAL_DEF_RST("internationalization/rendering/text_driver", "");
String text_driver_options;
for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
- if (i > 0) {
+ const String driver_name = TextServerManager::get_singleton()->get_interface(i)->get_name();
+ if (driver_name == "Dummy") {
+ // Dummy text driver cannot draw any text, making the editor unusable if selected.
+ continue;
+ }
+ if (!text_driver_options.is_empty() && text_driver_options.find(",") == -1) {
+ // Not the first option; add a comma before it as a separator for the property hint.
text_driver_options += ",";
}
- text_driver_options += TextServerManager::get_singleton()->get_interface(i)->get_name();
+ text_driver_options += driver_name;
}
ProjectSettings::get_singleton()->set_custom_property_info("internationalization/rendering/text_driver", PropertyInfo(Variant::STRING, "internationalization/rendering/text_driver", PROPERTY_HINT_ENUM, text_driver_options));
@@ -2032,8 +2138,12 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
ERR_FAIL_V_MSG(ERR_CANT_CREATE, "TextServer: Unable to create TextServer interface.");
}
+ engine->startup_benchmark_end_measure(); // servers
+
MAIN_PRINT("Main: Load Scene Types");
+ engine->startup_benchmark_begin_measure("scene");
+
register_scene_types();
register_driver_types();
@@ -2055,7 +2165,8 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
register_platform_apis();
// Theme needs modules to be initialized so that sub-resources can be loaded.
- initialize_theme();
+ initialize_theme_db();
+ register_scene_singletons();
GLOBAL_DEF_BASIC("display/mouse_cursor/custom_image", String());
GLOBAL_DEF_BASIC("display/mouse_cursor/custom_image_hotspot", Vector2());
@@ -2109,6 +2220,8 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
print_verbose("EDITOR API HASH: " + uitos(ClassDB::get_api_hash(ClassDB::API_EDITOR)));
MAIN_PRINT("Main: Done");
+ engine->startup_benchmark_end_measure(); // scene
+
return OK;
}
@@ -2240,18 +2353,6 @@ bool Main::start() {
ERR_FAIL_COND_V_MSG(da.is_null(), false, "Argument supplied to --doctool must be a valid directory path.");
}
-#ifndef MODULE_MONO_ENABLED
- // Hack to define Mono-specific project settings even on non-Mono builds,
- // so that we don't lose their descriptions and default values in DocData.
- // Default values should be synced with mono_gd/gd_mono.cpp.
- GLOBAL_DEF("mono/debugger_agent/port", 23685);
- GLOBAL_DEF("mono/debugger_agent/wait_for_debugger", false);
- GLOBAL_DEF("mono/debugger_agent/wait_timeout", 3000);
- GLOBAL_DEF("mono/profiler/args", "log:calls,alloc,sample,output=output.mlpd");
- GLOBAL_DEF("mono/profiler/enabled", false);
- GLOBAL_DEF("mono/runtime/unhandled_exception_policy", 0);
-#endif
-
Error err;
DocTools doc;
doc.generate(doc_base);
@@ -2265,7 +2366,7 @@ bool Main::start() {
// Custom modules are always located by absolute path.
String path = _doc_data_class_paths[i].path;
if (path.is_relative_path()) {
- path = doc_tool_path.plus_file(path);
+ path = doc_tool_path.path_join(path);
}
String name = _doc_data_class_paths[i].name;
doc_data_classes[name] = path;
@@ -2283,7 +2384,7 @@ bool Main::start() {
}
}
- String index_path = doc_tool_path.plus_file("doc/classes");
+ String index_path = doc_tool_path.path_join("doc/classes");
// Create the main documentation directory if it doesn't exist
Ref<DirAccess> da = DirAccess::create_for_path(index_path);
err = da->make_dir_recursive(index_path);
@@ -2317,12 +2418,12 @@ bool Main::start() {
}
if (converting_project) {
- int exit_code = ProjectConverter3To4().convert();
+ int exit_code = ProjectConverter3To4(converter_max_kb_file, converter_max_line_length).convert();
OS::get_singleton()->set_exit_code(exit_code);
return false;
}
if (validating_converting_project) {
- int exit_code = ProjectConverter3To4().validate_conversion();
+ int exit_code = ProjectConverter3To4(converter_max_kb_file, converter_max_line_length).validate_conversion();
OS::get_singleton()->set_exit_code(exit_code);
return false;
}
@@ -2437,7 +2538,7 @@ bool Main::start() {
bool embed_subwindows = GLOBAL_DEF("display/window/subwindows/embed_subwindows", true);
- if (OS::get_singleton()->is_single_window() || (!project_manager && !editor && embed_subwindows) || !DisplayServer::get_singleton()->has_feature(DisplayServer::Feature::FEATURE_SUBWINDOWS)) {
+ if (single_window || (!project_manager && !editor && embed_subwindows) || !DisplayServer::get_singleton()->has_feature(DisplayServer::Feature::FEATURE_SUBWINDOWS)) {
sml->get_root()->set_embedding_subwindows(true);
}
@@ -2447,6 +2548,7 @@ bool Main::start() {
if (!project_manager && !editor) { // game
if (!game_path.is_empty() || !script.is_empty()) {
//autoload
+ Engine::get_singleton()->startup_benchmark_begin_measure("load_autoloads");
HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
//first pass, add the constants so they exist before any script is loaded
@@ -2501,12 +2603,14 @@ bool Main::start() {
for (Node *E : to_add) {
sml->get_root()->add_child(E);
}
+ Engine::get_singleton()->startup_benchmark_end_measure(); // load autoloads
}
}
#ifdef TOOLS_ENABLED
EditorNode *editor_node = nullptr;
if (editor) {
+ Engine::get_singleton()->startup_benchmark_begin_measure("editor");
editor_node = memnew(EditorNode);
sml->get_root()->add_child(editor_node);
@@ -2514,6 +2618,13 @@ bool Main::start() {
editor_node->export_preset(_export_preset, positional_arg, export_debug, export_pack_only);
game_path = ""; // Do not load anything.
}
+
+ Engine::get_singleton()->startup_benchmark_end_measure();
+
+ editor_node->set_use_startup_benchmark(use_startup_benchmark, startup_benchmark_file);
+ // Editor takes over
+ use_startup_benchmark = false;
+ startup_benchmark_file = String();
}
#endif
@@ -2643,11 +2754,11 @@ bool Main::start() {
if (sep == -1) {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- local_game_path = da->get_current_dir().plus_file(local_game_path);
+ local_game_path = da->get_current_dir().path_join(local_game_path);
} else {
Ref<DirAccess> da = DirAccess::open(local_game_path.substr(0, sep));
if (da.is_valid()) {
- local_game_path = da->get_current_dir().plus_file(
+ local_game_path = da->get_current_dir().path_join(
local_game_path.substr(sep + 1, local_game_path.length()));
}
}
@@ -2678,6 +2789,8 @@ bool Main::start() {
if (!project_manager && !editor) { // game
+ Engine::get_singleton()->startup_benchmark_begin_measure("game_load");
+
// Load SSL Certificates from Project Settings (or builtin).
Crypto::load_default_certificates(GLOBAL_DEF("network/ssl/certificate_bundle_override", ""));
@@ -2717,16 +2830,20 @@ bool Main::start() {
}
}
}
+
+ Engine::get_singleton()->startup_benchmark_end_measure(); // game_load
}
#ifdef TOOLS_ENABLED
if (project_manager) {
+ Engine::get_singleton()->startup_benchmark_begin_measure("project_manager");
Engine::get_singleton()->set_editor_hint(true);
ProjectManager *pmanager = memnew(ProjectManager);
ProgressDialog *progress_dialog = memnew(ProgressDialog);
pmanager->add_child(progress_dialog);
sml->get_root()->add_child(pmanager);
DisplayServer::get_singleton()->set_context(DisplayServer::CONTEXT_PROJECTMAN);
+ Engine::get_singleton()->startup_benchmark_end_measure();
}
if (project_manager || editor) {
@@ -2756,6 +2873,11 @@ bool Main::start() {
}
}
+ if (use_startup_benchmark) {
+ Engine::get_singleton()->startup_dump(startup_benchmark_file);
+ startup_benchmark_file = String();
+ }
+
return true;
}
@@ -3001,6 +3123,7 @@ void Main::cleanup(bool p_force) {
OS::get_singleton()->delete_main_loop();
OS::get_singleton()->_cmdline.clear();
+ OS::get_singleton()->_user_args.clear();
OS::get_singleton()->_execpath = "";
OS::get_singleton()->_local_clipboard = "";
@@ -3037,6 +3160,8 @@ void Main::cleanup(bool p_force) {
unregister_driver_types();
unregister_scene_types();
+ finalize_theme_db();
+
NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS);
uninitialize_modules(MODULE_INITIALIZATION_LEVEL_SERVERS);
unregister_server_types();
diff --git a/main/main.h b/main/main.h
index d1870ab8df..f0bfe69b34 100644
--- a/main/main.h
+++ b/main/main.h
@@ -35,6 +35,9 @@
#include "core/os/thread.h"
#include "core/typedefs.h"
+template <class T>
+class Vector;
+
class Main {
static void print_help(const char *p_binary);
static uint64_t last_ticks;
@@ -47,6 +50,14 @@ class Main {
public:
static bool is_cmdline_tool();
+#ifdef TOOLS_ENABLED
+ enum CLIScope {
+ CLI_SCOPE_TOOL, // Editor and project manager.
+ CLI_SCOPE_PROJECT,
+ };
+ static const Vector<String> &get_forwardable_cli_arguments(CLIScope p_scope);
+#endif
+
static int test_entrypoint(int argc, char *argv[], bool &tests_need_run);
static Error setup(const char *execpath, int argc, char *argv[], bool p_second_phase = true);
static Error setup2(Thread::ID p_main_tid_override = 0);
diff --git a/main/performance.cpp b/main/performance.cpp
index 0de525134e..bdcd07a216 100644
--- a/main/performance.cpp
+++ b/main/performance.cpp
@@ -32,6 +32,7 @@
#include "core/object/message_queue.h"
#include "core/os/os.h"
+#include "core/variant/typed_array.h"
#include "scene/main/node.h"
#include "scene/main/scene_tree.h"
#include "servers/audio_server.h"
@@ -240,11 +241,11 @@ Variant Performance::get_custom_monitor(const StringName &p_id) {
return return_value;
}
-Array Performance::get_custom_monitor_names() {
+TypedArray<StringName> Performance::get_custom_monitor_names() {
if (!_monitor_map.size()) {
- return Array();
+ return TypedArray<StringName>();
}
- Array return_array;
+ TypedArray<StringName> return_array;
return_array.resize(_monitor_map.size());
int index = 0;
for (KeyValue<StringName, MonitorCall> i : _monitor_map) {
diff --git a/main/performance.h b/main/performance.h
index 2837d8f512..597666b57d 100644
--- a/main/performance.h
+++ b/main/performance.h
@@ -37,6 +37,9 @@
#define PERF_WARN_OFFLINE_FUNCTION
#define PERF_WARN_PROCESS_SYNC
+template <typename T>
+class TypedArray;
+
class Performance : public Object {
GDCLASS(Performance, Object);
@@ -85,7 +88,6 @@ public:
PHYSICS_3D_ACTIVE_OBJECTS,
PHYSICS_3D_COLLISION_PAIRS,
PHYSICS_3D_ISLAND_COUNT,
- //physics
AUDIO_OUTPUT_LATENCY,
MONITOR_MAX
};
@@ -108,7 +110,7 @@ public:
void remove_custom_monitor(const StringName &p_id);
bool has_custom_monitor(const StringName &p_id);
Variant get_custom_monitor(const StringName &p_id);
- Array get_custom_monitor_names();
+ TypedArray<StringName> get_custom_monitor_names();
uint64_t get_monitor_modification_time();
diff --git a/methods.py b/methods.py
index 571b134c8a..3a00aa12ca 100644
--- a/methods.py
+++ b/methods.py
@@ -1,5 +1,6 @@
import os
import re
+import sys
import glob
import subprocess
from collections import OrderedDict
@@ -336,7 +337,20 @@ def disable_module(self):
self.disabled_modules.append(self.current_module)
-def module_check_dependencies(self, module, dependencies, silent=False):
+def module_add_dependencies(self, module, dependencies, optional=False):
+ """
+ Adds dependencies for a given module.
+ Meant to be used in module `can_build` methods.
+ """
+ if module not in self.module_dependencies:
+ self.module_dependencies[module] = [[], []]
+ if optional:
+ self.module_dependencies[module][1].extend(dependencies)
+ else:
+ self.module_dependencies[module][0].extend(dependencies)
+
+
+def module_check_dependencies(self, module):
"""
Checks if module dependencies are enabled for a given module,
and prints a warning if they aren't.
@@ -344,23 +358,41 @@ def module_check_dependencies(self, module, dependencies, silent=False):
Returns a boolean (True if dependencies are satisfied).
"""
missing_deps = []
- for dep in dependencies:
+ required_deps = self.module_dependencies[module][0] if module in self.module_dependencies else []
+ for dep in required_deps:
opt = "module_{}_enabled".format(dep)
if not opt in self or not self[opt]:
missing_deps.append(dep)
if missing_deps != []:
- if not silent:
- print(
- "Disabling '{}' module as the following dependencies are not satisfied: {}".format(
- module, ", ".join(missing_deps)
- )
+ print(
+ "Disabling '{}' module as the following dependencies are not satisfied: {}".format(
+ module, ", ".join(missing_deps)
)
+ )
return False
else:
return True
+def sort_module_list(env):
+ out = OrderedDict()
+ deps = {k: v[0] + list(filter(lambda x: x in env.module_list, v[1])) for k, v in env.module_dependencies.items()}
+
+ frontier = list(env.module_list.keys())
+ explored = []
+ while len(frontier):
+ cur = frontier.pop()
+ deps_list = deps[cur] if cur in deps else []
+ if len(deps_list) and any([d not in explored for d in deps_list]):
+ # Will explore later, after its dependencies
+ frontier.insert(0, cur)
+ continue
+ explored.append(cur)
+ for k in explored:
+ env.module_list.move_to_end(k)
+
+
def use_windows_spawn_fix(self, platform=None):
if os.name != "nt":
@@ -388,6 +420,7 @@ def use_windows_spawn_fix(self, platform=None):
startupinfo=startupinfo,
shell=False,
env=env,
+ text=True,
)
_, err = proc.communicate()
rv = proc.wait()
@@ -507,7 +540,7 @@ def detect_visual_c_compiler_version(tools_env):
# and not scons setup environment (env)... so make sure you call the right environment on it or it will fail to detect
# the proper vc version that will be called
- # There is no flag to give to visual c compilers to set the architecture, i.e. scons bits argument (32,64,ARM etc)
+ # There is no flag to give to visual c compilers to set the architecture, i.e. scons arch argument (x86_32, x86_64, arm64, etc.).
# There are many different cl.exe files that are run, and each one compiles & links to a different architecture
# As far as I know, the only way to figure out what compiler will be run when Scons calls cl.exe via Program()
# is to check the PATH variable and figure out which one will be called first. Code below does that and returns:
@@ -607,8 +640,18 @@ def find_visual_c_batch_file(env):
find_batch_file,
)
+ # Syntax changed in SCons 4.4.0.
+ from SCons import __version__ as scons_raw_version
+
+ scons_ver = env._get_major_minor_revision(scons_raw_version)
+
version = get_default_version(env)
- (host_platform, target_platform, _) = get_host_target(env)
+
+ if scons_ver >= (4, 4, 0):
+ (host_platform, target_platform, _) = get_host_target(env, version)
+ else:
+ (host_platform, target_platform, _) = get_host_target(env)
+
return find_batch_file(env, version, host_platform, target_platform)[0]
@@ -662,7 +705,7 @@ def generate_vs_project(env, num_jobs):
# required for Visual Studio to understand that it needs to generate an NMAKE
# project. Do not modify without knowing what you are doing.
PLATFORMS = ["Win32", "x64"]
- PLATFORM_IDS = ["32", "64"]
+ PLATFORM_IDS = ["x86_32", "x86_64"]
CONFIGURATIONS = ["debug", "release", "release_debug"]
CONFIGURATION_IDS = ["tools", "opt", "opt.tools"]
@@ -775,18 +818,21 @@ def generate_vs_project(env, num_jobs):
module_configs = ModuleConfigs()
if env.get("module_mono_enabled"):
- import modules.mono.build_scripts.mono_reg_utils as mono_reg
+ import modules.mono.build_scripts.mono_configure as mono_configure
- mono_root = env.get("mono_prefix") or mono_reg.find_mono_root_dir(env["bits"])
- if mono_root:
+ app_host_dir = mono_configure.find_dotnet_app_host_dir(env)
+ if app_host_dir and os.path.isdir(app_host_dir):
+ mono_defines = [("NETHOST_USE_AS_STATIC",)]
+ if env["tools"]:
+ mono_defines += [("GD_MONO_HOT_RELOAD",)]
module_configs.add_mode(
"mono",
- includes=os.path.join(mono_root, "include", "mono-2.0"),
- cli_args="module_mono_enabled=yes mono_glue=yes",
- defines=[("MONO_GLUE_ENABLED",)],
+ includes=app_host_dir,
+ cli_args="module_mono_enabled=yes",
+ defines=mono_defines,
)
else:
- print("Mono installation directory not found. Generated project will not have build variants for Mono.")
+ print(".NET App Host directory not found. Generated project will not have build variants for .NET.")
env["MSVSBUILDCOM"] = module_configs.build_commandline("scons")
env["MSVSREBUILDCOM"] = module_configs.build_commandline("scons vsproj=yes")
diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
index 69899cbe8d..467aa3ce83 100644
--- a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
+++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
@@ -10,6 +10,7 @@
1F1575721F582BE20003B888 /* dylibs in Resources */ = {isa = PBXBuildFile; fileRef = 1F1575711F582BE20003B888 /* dylibs */; };
DEADBEEF2F582BE20003B888 /* $binary.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = DEADBEEF1F582BE20003B888 /* $binary.xcframework */; };
$modules_buildfile
+ $swift_runtime_buildfile
1FF8DBB11FBA9DE1009DE660 /* dummy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1FF8DBB01FBA9DE1009DE660 /* dummy.cpp */; };
D07CD44E1C5D589C00B7FB28 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D07CD44D1C5D589C00B7FB28 /* Images.xcassets */; };
9039D3BE24C093AC0020482C /* MoltenVK.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9039D3BD24C093AC0020482C /* MoltenVK.xcframework */; };
@@ -37,6 +38,7 @@
1F1575711F582BE20003B888 /* dylibs */ = {isa = PBXFileReference; lastKnownFileType = folder; name = dylibs; path = "$binary/dylibs"; sourceTree = "<group>"; };
DEADBEEF1F582BE20003B888 /* $binary.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = godot; path = "$binary.xcframework"; sourceTree = "<group>"; };
$modules_fileref
+ $swift_runtime_fileref
1FF4C1881F584E6300A41E41 /* $binary.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "$binary.entitlements"; sourceTree = "<group>"; };
1FF8DBB01FBA9DE1009DE660 /* dummy.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = dummy.cpp; sourceTree = "<group>"; };
9039D3BD24C093AC0020482C /* MoltenVK.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = MoltenVK; path = MoltenVK.xcframework; sourceTree = "<group>"; };
@@ -107,6 +109,7 @@
D07CD44D1C5D589C00B7FB28 /* Images.xcassets */,
D0BCFE4218AEBDA2004A7AAE /* Supporting Files */,
1FF8DBB01FBA9DE1009DE660 /* dummy.cpp */,
+ $swift_runtime_binary_files
);
path = "$binary";
sourceTree = "<group>";
@@ -152,6 +155,7 @@
TargetAttributes = {
D0BCFE3318AEBDA2004A7AAE = {
DevelopmentTeam = $team_id;
+ $swift_runtime_migration
ProvisioningStyle = Automatic;
SystemCapabilities = {
};
@@ -198,6 +202,7 @@
buildActionMask = 2147483647;
files = (
1FF8DBB11FBA9DE1009DE660 /* dummy.cpp in Sources */,
+ $swift_runtime_build_phase
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -329,6 +334,7 @@
TARGETED_DEVICE_FAMILY = "$targeted_device_family";
VALID_ARCHS = "arm64 x86_64";
WRAPPER_EXTENSION = app;
+ $swift_runtime_build_settings
};
name = Debug;
};
@@ -360,6 +366,7 @@
TARGETED_DEVICE_FAMILY = "$targeted_device_family";
VALID_ARCHS = "arm64 x86_64";
WRAPPER_EXTENSION = app;
+ $swift_runtime_build_settings
};
name = Release;
};
diff --git a/misc/dist/ios_xcode/godot_ios/dummy.h b/misc/dist/ios_xcode/godot_ios/dummy.h
new file mode 100644
index 0000000000..ea6c0f78e4
--- /dev/null
+++ b/misc/dist/ios_xcode/godot_ios/dummy.h
@@ -0,0 +1,31 @@
+/*************************************************************************/
+/* dummy.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+// #import <Foundation/Foundation.h>
diff --git a/misc/dist/ios_xcode/godot_ios/dummy.swift b/misc/dist/ios_xcode/godot_ios/dummy.swift
new file mode 100644
index 0000000000..86c76b64d3
--- /dev/null
+++ b/misc/dist/ios_xcode/godot_ios/dummy.swift
@@ -0,0 +1,31 @@
+/*************************************************************************/
+/* dummy.swift */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+import Foundation
diff --git a/misc/scripts/clang_format.sh b/misc/scripts/clang_format.sh
index 2b7179f5be..b7c577d5fb 100755
--- a/misc/scripts/clang_format.sh
+++ b/misc/scripts/clang_format.sh
@@ -7,7 +7,8 @@ set -uo pipefail
# Loops through all code files tracked by Git.
git ls-files -- '*.c' '*.h' '*.cpp' '*.hpp' '*.cc' '*.hh' '*.cxx' '*.m' '*.mm' '*.inc' '*.java' '*.glsl' \
- ':!:.git/*' ':!:thirdparty/*' ':!:platform/android/java/lib/src/com/google/*' ':!:*-so_wrap.*' |
+ ':!:.git/*' ':!:thirdparty/*' ':!:platform/android/java/lib/src/com/google/*' ':!:*-so_wrap.*' \
+ ':!:tests/python_build/*' |
while read -r f; do
# Run clang-format.
clang-format --Wno-error=unknown -i "$f"
diff --git a/misc/scripts/dotnet_format.sh b/misc/scripts/dotnet_format.sh
new file mode 100755
index 0000000000..645737f419
--- /dev/null
+++ b/misc/scripts/dotnet_format.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+
+# This script runs dotnet format on all relevant files in the repo.
+# This is the primary script responsible for fixing style violations in C# files.
+
+set -uo pipefail
+
+# Loops through all C# projects tracked by Git.
+git ls-files -- '*.csproj' \
+ ':!:.git/*' ':!:thirdparty/*' ':!:platform/android/java/lib/src/com/google/*' ':!:*-so_wrap.*' |
+while read -r f; do
+ # Run dotnet format.
+ dotnet format "$f"
+done
+
+diff=$(git diff --color)
+
+# If no diff has been generated all is OK, clean up, and exit.
+if [ -z "$diff" ] ; then
+ printf "Files in this commit comply with the dotnet format style rules.\n"
+ exit 0
+fi
+
+# A diff has been created, notify the user, clean up, and exit.
+printf "\n*** The following changes have been made to comply with the formatting rules:\n\n"
+echo "$diff"
+printf "\n*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\n"
+exit 1
diff --git a/misc/scripts/file_format.sh b/misc/scripts/file_format.sh
index c767d3f8a0..731b3ee005 100755
--- a/misc/scripts/file_format.sh
+++ b/misc/scripts/file_format.sh
@@ -37,6 +37,8 @@ while IFS= read -rd '' f; do
continue
elif [[ "$f" == *"-so_wrap."* ]]; then
continue
+ elif [[ "$f" == *".test.txt" ]]; then
+ continue
fi
# Ensure that files are UTF-8 formatted.
recode UTF-8 "$f" 2> /dev/null
diff --git a/misc/scripts/pytest_builders.sh b/misc/scripts/pytest_builders.sh
new file mode 100755
index 0000000000..eb2ddbcddc
--- /dev/null
+++ b/misc/scripts/pytest_builders.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+set -uo pipefail
+
+echo "Running Python checks for builder system"
+pytest ./tests/python_build
diff --git a/modules/bmp/SCsub b/modules/bmp/SCsub
index 4f3405ff28..9d317887c3 100644
--- a/modules/bmp/SCsub
+++ b/modules/bmp/SCsub
@@ -5,5 +5,5 @@ Import("env_modules")
env_bmp = env_modules.Clone()
-# Godot's own source files
+# Godot source files
env_bmp.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp
index 8813c3827a..ae03abca50 100644
--- a/modules/bmp/image_loader_bmp.cpp
+++ b/modules/bmp/image_loader_bmp.cpp
@@ -200,7 +200,7 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image,
return err;
}
-Error ImageLoaderBMP::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) {
+Error ImageLoaderBMP::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) {
bmp_header_s bmp_header;
Error err = ERR_INVALID_DATA;
diff --git a/modules/bmp/image_loader_bmp.h b/modules/bmp/image_loader_bmp.h
index 63dee0a969..cf8346ecad 100644
--- a/modules/bmp/image_loader_bmp.h
+++ b/modules/bmp/image_loader_bmp.h
@@ -83,7 +83,7 @@ protected:
const bmp_header_s &p_header);
public:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderBMP();
};
diff --git a/modules/csg/SCsub b/modules/csg/SCsub
index c7307ddefd..55f859db11 100644
--- a/modules/csg/SCsub
+++ b/modules/csg/SCsub
@@ -3,10 +3,9 @@
Import("env")
Import("env_modules")
-# Godot's own source files
env_csg = env_modules.Clone()
-# Godot's own source files
+# Godot source files
env_csg.add_source_files(env.modules_sources, "*.cpp")
if env["tools"]:
env_csg.add_source_files(env.modules_sources, "editor/*.cpp")
diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp
index 93533e1690..6b05c146e6 100644
--- a/modules/csg/csg.cpp
+++ b/modules/csg/csg.cpp
@@ -729,7 +729,7 @@ void CSGBrushOperation::MeshMerge::mark_inside_faces() {
}
}
-void CSGBrushOperation::MeshMerge::add_face(const Vector3 p_points[], const Vector2 p_uvs[], bool p_smooth, bool p_invert, const Ref<Material> &p_material, bool p_from_b) {
+void CSGBrushOperation::MeshMerge::add_face(const Vector3 p_points[3], const Vector2 p_uvs[3], bool p_smooth, bool p_invert, const Ref<Material> &p_material, bool p_from_b) {
int indices[3];
for (int i = 0; i < 3; i++) {
VertexKey vk;
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index 56be4e65f0..6294790132 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -53,6 +53,7 @@ void CSGShape3D::set_use_collision(bool p_enable) {
PhysicsServer3D::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id());
set_collision_layer(collision_layer);
set_collision_mask(collision_mask);
+ set_collision_priority(collision_priority);
_make_dirty(); //force update
} else {
PhysicsServer3D::get_singleton()->free(root_collision_instance);
@@ -124,6 +125,17 @@ bool CSGShape3D::get_collision_mask_value(int p_layer_number) const {
return get_collision_mask() & (1 << (p_layer_number - 1));
}
+void CSGShape3D::set_collision_priority(real_t p_priority) {
+ collision_priority = p_priority;
+ if (root_collision_instance.is_valid()) {
+ PhysicsServer3D::get_singleton()->body_set_collision_priority(root_collision_instance, p_priority);
+ }
+}
+
+real_t CSGShape3D::get_collision_priority() const {
+ return collision_priority;
+}
+
bool CSGShape3D::is_root_shape() const {
return !parent_shape;
}
@@ -545,6 +557,7 @@ void CSGShape3D::_notification(int p_what) {
PhysicsServer3D::get_singleton()->body_attach_object_instance_id(root_collision_instance, get_instance_id());
set_collision_layer(collision_layer);
set_collision_mask(collision_mask);
+ set_collision_priority(collision_priority);
_update_collision_faces();
}
} break;
@@ -584,15 +597,14 @@ bool CSGShape3D::is_calculating_tangents() const {
return calculate_tangents;
}
-void CSGShape3D::_validate_property(PropertyInfo &property) const {
- bool is_collision_prefixed = property.name.begins_with("collision_");
- if ((is_collision_prefixed || property.name.begins_with("use_collision")) && is_inside_tree() && !is_root_shape()) {
+void CSGShape3D::_validate_property(PropertyInfo &p_property) const {
+ bool is_collision_prefixed = p_property.name.begins_with("collision_");
+ if ((is_collision_prefixed || p_property.name.begins_with("use_collision")) && is_inside_tree() && !is_root_shape()) {
//hide collision if not root
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
} else if (is_collision_prefixed && !bool(get("use_collision"))) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- GeometryInstance3D::_validate_property(property);
}
Array CSGShape3D::get_meshes() const {
@@ -632,6 +644,9 @@ void CSGShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &CSGShape3D::set_collision_layer_value);
ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &CSGShape3D::get_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("set_collision_priority", "priority"), &CSGShape3D::set_collision_priority);
+ ClassDB::bind_method(D_METHOD("get_collision_priority"), &CSGShape3D::get_collision_priority);
+
ClassDB::bind_method(D_METHOD("set_calculate_tangents", "enabled"), &CSGShape3D::set_calculate_tangents);
ClassDB::bind_method(D_METHOD("is_calculating_tangents"), &CSGShape3D::is_calculating_tangents);
@@ -645,6 +660,7 @@ void CSGShape3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_collision"), "set_use_collision", "is_using_collision");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_priority"), "set_collision_priority", "get_collision_priority");
BIND_ENUM_CONSTANT(OPERATION_UNION);
BIND_ENUM_CONSTANT(OPERATION_INTERSECTION);
@@ -1822,7 +1838,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
u_step *= curve_length / path_u_distance;
}
double v_step = 1.0 / shape_sides;
- double spin_step = Math::deg2rad(spin_degrees / spin_sides);
+ double spin_step = Math::deg_to_rad(spin_degrees / spin_sides);
double extrusion_step = 1.0 / extrusions;
if (mode == MODE_PATH) {
if (path_joined) {
@@ -1886,7 +1902,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
}
}
- real_t angle_simplify_dot = Math::cos(Math::deg2rad(path_simplify_angle));
+ real_t angle_simplify_dot = Math::cos(Math::deg_to_rad(path_simplify_angle));
Vector3 previous_simplify_dir = Vector3(0, 0, 0);
int faces_combined = 0;
@@ -2058,18 +2074,16 @@ void CSGPolygon3D::_notification(int p_what) {
}
}
-void CSGPolygon3D::_validate_property(PropertyInfo &property) const {
- if (property.name.begins_with("spin") && mode != MODE_SPIN) {
- property.usage = PROPERTY_USAGE_NONE;
+void CSGPolygon3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name.begins_with("spin") && mode != MODE_SPIN) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("path") && mode != MODE_PATH) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("path") && mode != MODE_PATH) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "depth" && mode != MODE_DEPTH) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "depth" && mode != MODE_DEPTH) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
-
- CSGShape3D::_validate_property(property);
}
void CSGPolygon3D::_path_changed() {
diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h
index 0b49dc4609..7db5477b10 100644
--- a/modules/csg/csg_shape.h
+++ b/modules/csg/csg_shape.h
@@ -65,6 +65,7 @@ private:
bool use_collision = false;
uint32_t collision_layer = 1;
uint32_t collision_mask = 1;
+ real_t collision_priority = 1.0;
Ref<ConcavePolygonShape3D> root_collision_shape;
RID root_collision_instance;
@@ -117,7 +118,7 @@ protected:
friend class CSGCombiner3D;
CSGBrush *_get_brush();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
Array get_meshes() const;
@@ -144,6 +145,9 @@ public:
void set_collision_mask_value(int p_layer_number, bool p_value);
bool get_collision_mask_value(int p_layer_number) const;
+ void set_collision_priority(real_t p_priority);
+ real_t get_collision_priority() const;
+
void set_snap(float p_snap);
float get_snap() const;
@@ -383,7 +387,7 @@ private:
protected:
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
public:
diff --git a/modules/csg/doc_classes/CSGShape3D.xml b/modules/csg/doc_classes/CSGShape3D.xml
index f1cd28e00f..7e92d667b3 100644
--- a/modules/csg/doc_classes/CSGShape3D.xml
+++ b/modules/csg/doc_classes/CSGShape3D.xml
@@ -13,14 +13,14 @@
<methods>
<method name="get_collision_layer_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
Returns whether or not the specified layer of the [member collision_layer] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
@@ -39,16 +39,16 @@
</method>
<method name="set_collision_layer_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
Based on [code]value[/code], enables or disables the specified layer in the [member collision_layer], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="set_collision_mask_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
</description>
@@ -66,6 +66,8 @@
<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. See [url=$DOCS_URL/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
</member>
+ <member name="collision_priority" type="float" setter="set_collision_priority" getter="get_collision_priority" default="1.0">
+ </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.
</member>
diff --git a/modules/csg/editor/csg_gizmos.cpp b/modules/csg/editor/csg_gizmos.cpp
index 6442ff71fc..ba9b96db74 100644
--- a/modules/csg/editor/csg_gizmos.cpp
+++ b/modules/csg/editor/csg_gizmos.cpp
@@ -32,7 +32,9 @@
#ifdef TOOLS_ENABLED
+#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/camera_3d.h"
@@ -215,7 +217,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Sphere Shape Radius"));
ur->add_do_method(s, "set_radius", s->get_radius());
ur->add_undo_method(s, "set_radius", p_restore);
@@ -229,7 +231,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Change Box Shape Size"));
ur->add_do_method(s, "set_size", s->get_size());
ur->add_undo_method(s, "set_size", p_restore);
@@ -247,7 +249,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
if (p_id == 0) {
ur->create_action(TTR("Change Cylinder Radius"));
ur->add_do_method(s, "set_radius", s->get_radius());
@@ -272,7 +274,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int
return;
}
- UndoRedo *ur = Node3DEditor::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
if (p_id == 0) {
ur->create_action(TTR("Change Torus Inner Radius"));
ur->add_do_method(s, "set_inner_radius", s->get_inner_radius());
diff --git a/modules/denoise/config.py b/modules/denoise/config.py
index 521115dae5..20a5e1da2f 100644
--- a/modules/denoise/config.py
+++ b/modules/denoise/config.py
@@ -2,17 +2,10 @@ def can_build(env, platform):
# Thirdparty dependency OpenImage Denoise includes oneDNN library
# and the version we use only supports x86_64.
# It's also only relevant for tools build and desktop platforms,
- # as doing lightmap generation and denoising on Android or HTML5
+ # as doing lightmap generation and denoising on Android or Web
# would be a bit far-fetched.
desktop_platforms = ["linuxbsd", "macos", "windows"]
- supported_arch = env["bits"] == "64"
- if env["arch"] == "arm64":
- supported_arch = False
- if env["arch"].startswith("ppc"):
- supported_arch = False
- if env["arch"].startswith("rv"):
- supported_arch = False
- return env["tools"] and platform in desktop_platforms and supported_arch
+ return env["tools"] and platform in desktop_platforms and env["arch"] == "x86_64"
def configure(env):
diff --git a/modules/enet/doc_classes/ENetConnection.xml b/modules/enet/doc_classes/ENetConnection.xml
index 14aad0cb39..8c84fe87d7 100644
--- a/modules/enet/doc_classes/ENetConnection.xml
+++ b/modules/enet/doc_classes/ENetConnection.xml
@@ -12,31 +12,31 @@
<methods>
<method name="bandwidth_limit">
<return type="void" />
- <argument index="0" name="in_bandwidth" type="int" default="0" />
- <argument index="1" name="out_bandwidth" type="int" default="0" />
+ <param index="0" name="in_bandwidth" type="int" default="0" />
+ <param index="1" name="out_bandwidth" type="int" default="0" />
<description>
Adjusts the bandwidth limits of a host.
</description>
</method>
<method name="broadcast">
<return type="void" />
- <argument index="0" name="channel" type="int" />
- <argument index="1" name="packet" type="PackedByteArray" />
- <argument index="2" name="flags" type="int" />
+ <param index="0" name="channel" type="int" />
+ <param index="1" name="packet" type="PackedByteArray" />
+ <param index="2" name="flags" type="int" />
<description>
Queues a [code]packet[/code] to be sent to all peers associated with the host over the specified [code]channel[/code]. See [ENetPacketPeer] [code]FLAG_*[/code] constants for available packet flags.
</description>
</method>
<method name="channel_limit">
<return type="void" />
- <argument index="0" name="limit" type="int" />
+ <param index="0" name="limit" type="int" />
<description>
Limits the maximum allowed channels of future incoming connections.
</description>
</method>
<method name="compress">
<return type="void" />
- <argument index="0" name="mode" type="int" enum="ENetConnection.CompressionMode" />
+ <param index="0" name="mode" type="int" enum="ENetConnection.CompressionMode" />
<description>
Sets the compression method used for network packets. These have different tradeoffs of compression speed versus bandwidth, you may need to test which one works best for your use case if you use compression at all.
[b]Note:[/b] Most games' network design involve sending many small packets frequently (smaller than 4 KB each). If in doubt, it is recommended to keep the default compression algorithm as it works best on these small packets.
@@ -45,10 +45,10 @@
</method>
<method name="connect_to_host">
<return type="ENetPacketPeer" />
- <argument index="0" name="address" type="String" />
- <argument index="1" name="port" type="int" />
- <argument index="2" name="channels" type="int" default="0" />
- <argument index="3" name="data" type="int" default="0" />
+ <param index="0" name="address" type="String" />
+ <param index="1" name="port" type="int" />
+ <param index="2" name="channels" type="int" default="0" />
+ <param index="3" name="data" type="int" default="0" />
<description>
Initiates a connection to a foreign [code]address[/code] using the specified [code]port[/code] and allocating the requested [code]channels[/code]. Optional [code]data[/code] can be passed during connection in the form of a 32 bit integer.
[b]Note:[/b] You must call either [method create_host] or [method create_host_bound] before calling this method.
@@ -56,22 +56,22 @@
</method>
<method name="create_host">
<return type="int" enum="Error" />
- <argument index="0" name="max_peers" type="int" default="32" />
- <argument index="1" name="max_channels" type="int" default="0" />
- <argument index="2" name="in_bandwidth" type="int" default="0" />
- <argument index="3" name="out_bandwidth" type="int" default="0" />
+ <param index="0" name="max_peers" type="int" default="32" />
+ <param index="1" name="max_channels" type="int" default="0" />
+ <param index="2" name="in_bandwidth" type="int" default="0" />
+ <param index="3" name="out_bandwidth" type="int" default="0" />
<description>
Create an ENetHost that will allow up to [code]max_peers[/code] connected peers, each allocating up to [code]max_channels[/code] channels, optionally limiting bandwidth to [code]in_bandwidth[/code] and [code]out_bandwidth[/code].
</description>
</method>
<method name="create_host_bound">
<return type="int" enum="Error" />
- <argument index="0" name="bind_address" type="String" />
- <argument index="1" name="bind_port" type="int" />
- <argument index="2" name="max_peers" type="int" default="32" />
- <argument index="3" name="max_channels" type="int" default="0" />
- <argument index="4" name="in_bandwidth" type="int" default="0" />
- <argument index="5" name="out_bandwidth" type="int" default="0" />
+ <param index="0" name="bind_address" type="String" />
+ <param index="1" name="bind_port" type="int" />
+ <param index="2" name="max_peers" type="int" default="32" />
+ <param index="3" name="max_channels" type="int" default="0" />
+ <param index="4" name="in_bandwidth" type="int" default="0" />
+ <param index="5" name="out_bandwidth" type="int" default="0" />
<description>
Create an ENetHost like [method create_host] which is also bound to the given [code]bind_address[/code] and [code]bind_port[/code].
</description>
@@ -84,17 +84,17 @@
</method>
<method name="dtls_client_setup">
<return type="int" enum="Error" />
- <argument index="0" name="certificate" type="X509Certificate" />
- <argument index="1" name="hostname" type="String" />
- <argument index="2" name="verify" type="bool" default="true" />
+ <param index="0" name="certificate" type="X509Certificate" />
+ <param index="1" name="hostname" type="String" />
+ <param index="2" name="verify" type="bool" default="true" />
<description>
Configure this ENetHost to use the custom Godot extension allowing DTLS encryption for ENet clients. Call this before [method connect_to_host] to have ENet connect using DTLS with [code]certificate[/code] and [code]hostname[/code] verification. Verification can be optionally turned off via the [code]verify[/code] parameter.
</description>
</method>
<method name="dtls_server_setup">
<return type="int" enum="Error" />
- <argument index="0" name="key" type="CryptoKey" />
- <argument index="1" name="certificate" type="X509Certificate" />
+ <param index="0" name="key" type="CryptoKey" />
+ <param index="1" name="certificate" type="X509Certificate" />
<description>
Configure this ENetHost to use the custom Godot extension allowing DTLS encryption for ENet servers. Call this right after [method create_host_bound] to have ENet expect peers to connect using DTLS.
</description>
@@ -118,7 +118,7 @@
</description>
</method>
<method name="get_peers">
- <return type="Array" />
+ <return type="ENetPacketPeer[]" />
<description>
Returns the list of peers associated with this host.
[b]Note:[/b] This list might include some peers that are not fully connected or are still being disconnected.
@@ -126,14 +126,14 @@
</method>
<method name="pop_statistic">
<return type="float" />
- <argument index="0" name="statistic" type="int" enum="ENetConnection.HostStatistic" />
+ <param index="0" name="statistic" type="int" enum="ENetConnection.HostStatistic" />
<description>
Returns and resets host statistics. See [enum HostStatistic] for more info.
</description>
</method>
<method name="refuse_new_connections">
<return type="void" />
- <argument index="0" name="refuse" type="bool" />
+ <param index="0" name="refuse" type="bool" />
<description>
Configures the DTLS server to automatically drop new connections.
[b]Note:[/b] This method is only relevant after calling [method dtls_server_setup].
@@ -141,7 +141,7 @@
</method>
<method name="service">
<return type="Array" />
- <argument index="0" name="timeout" type="int" default="0" />
+ <param index="0" name="timeout" type="int" default="0" />
<description>
Waits for events on the host specified and shuttles packets between the host and its peers. The returned [Array] will have 4 elements. An [enum EventType], the [ENetPacketPeer] which generated the event, the event associated data (if any), the event associated channel (if any). If the generated event is [constant EVENT_RECEIVE], the received packet will be queued to the associated [ENetPacketPeer].
Call this function regularly to handle connections, disconnections, and to receive new packets.
diff --git a/modules/enet/doc_classes/ENetMultiplayerPeer.xml b/modules/enet/doc_classes/ENetMultiplayerPeer.xml
index 2ecf6b4122..5181ae76ce 100644
--- a/modules/enet/doc_classes/ENetMultiplayerPeer.xml
+++ b/modules/enet/doc_classes/ENetMultiplayerPeer.xml
@@ -14,8 +14,8 @@
<methods>
<method name="add_mesh_peer">
<return type="int" enum="Error" />
- <argument index="0" name="peer_id" type="int" />
- <argument index="1" name="host" type="ENetConnection" />
+ <param index="0" name="peer_id" type="int" />
+ <param index="1" name="host" type="ENetConnection" />
<description>
Add a new remote peer with the given [code]peer_id[/code] connected to the given [code]host[/code].
[b]Note:[/b] The [code]host[/code] must have exactly one peer in the [constant ENetPacketPeer.STATE_CONNECTED] state.
@@ -23,51 +23,51 @@
</method>
<method name="close_connection">
<return type="void" />
- <argument index="0" name="wait_usec" type="int" default="100" />
+ <param index="0" name="wait_usec" type="int" default="100" />
<description>
Closes the connection. Ignored if no connection is currently established. If this is a server it tries to notify all clients before forcibly disconnecting them. If this is a client it simply closes the connection to the server.
</description>
</method>
<method name="create_client">
<return type="int" enum="Error" />
- <argument index="0" name="address" type="String" />
- <argument index="1" name="port" type="int" />
- <argument index="2" name="channel_count" type="int" default="0" />
- <argument index="3" name="in_bandwidth" type="int" default="0" />
- <argument index="4" name="out_bandwidth" type="int" default="0" />
- <argument index="5" name="local_port" type="int" default="0" />
+ <param index="0" name="address" type="String" />
+ <param index="1" name="port" type="int" />
+ <param index="2" name="channel_count" type="int" default="0" />
+ <param index="3" name="in_bandwidth" type="int" default="0" />
+ <param index="4" name="out_bandwidth" type="int" default="0" />
+ <param index="5" name="local_port" type="int" default="0" />
<description>
Create client that connects to a server at [code]address[/code] using specified [code]port[/code]. The given address needs to be either a fully qualified domain name (e.g. [code]"www.example.com"[/code]) or an IP address in IPv4 or IPv6 format (e.g. [code]"192.168.1.1"[/code]). The [code]port[/code] is the port the server is listening on. The [code]channel_count[/code] parameter can be used to specify the number of ENet channels allocated for the connection. The [code]in_bandwidth[/code] and [code]out_bandwidth[/code] parameters can be used to limit the incoming and outgoing bandwidth to the given number of bytes per second. The default of 0 means unlimited bandwidth. Note that ENet will strategically drop packets on specific sides of a connection between peers to ensure the peer's bandwidth is not overwhelmed. The bandwidth parameters also determine the window size of a connection which limits the amount of reliable packets that may be in transit at any given time. Returns [constant OK] if a client was created, [constant ERR_ALREADY_IN_USE] if this ENetMultiplayerPeer instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the client could not be created. If [code]local_port[/code] is specified, the client will also listen to the given port; this is useful for some NAT traversal techniques.
</description>
</method>
<method name="create_mesh">
<return type="int" enum="Error" />
- <argument index="0" name="unique_id" type="int" />
+ <param index="0" name="unique_id" type="int" />
<description>
Initialize this [MultiplayerPeer] in mesh mode. The provided [code]unique_id[/code] will be used as the local peer network unique ID once assigned as the [member MultiplayerAPI.multiplayer_peer]. In the mesh configuration you will need to set up each new peer manually using [ENetConnection] before calling [method add_mesh_peer]. While this technique is more advanced, it allows for better control over the connection process (e.g. when dealing with NAT punch-through) and for better distribution of the network load (which would otherwise be more taxing on the server).
</description>
</method>
<method name="create_server">
<return type="int" enum="Error" />
- <argument index="0" name="port" type="int" />
- <argument index="1" name="max_clients" type="int" default="32" />
- <argument index="2" name="max_channels" type="int" default="0" />
- <argument index="3" name="in_bandwidth" type="int" default="0" />
- <argument index="4" name="out_bandwidth" type="int" default="0" />
+ <param index="0" name="port" type="int" />
+ <param index="1" name="max_clients" type="int" default="32" />
+ <param index="2" name="max_channels" type="int" default="0" />
+ <param index="3" name="in_bandwidth" type="int" default="0" />
+ <param index="4" name="out_bandwidth" type="int" default="0" />
<description>
Create server that listens to connections via [code]port[/code]. The port needs to be an available, unused port between 0 and 65535. Note that ports below 1024 are privileged and may require elevated permissions depending on the platform. To change the interface the server listens on, use [method set_bind_ip]. The default IP is the wildcard [code]"*"[/code], which listens on all available interfaces. [code]max_clients[/code] is the maximum number of clients that are allowed at once, any number up to 4095 may be used, although the achievable number of simultaneous clients may be far lower and depends on the application. For additional details on the bandwidth parameters, see [method create_client]. Returns [constant OK] if a server was created, [constant ERR_ALREADY_IN_USE] if this ENetMultiplayerPeer instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the server could not be created.
</description>
</method>
<method name="get_peer" qualifiers="const">
<return type="ENetPacketPeer" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Returns the [ENetPacketPeer] associated to the given [code]id[/code].
</description>
</method>
<method name="set_bind_ip">
<return type="void" />
- <argument index="0" name="ip" type="String" />
+ <param index="0" name="ip" type="String" />
<description>
The IP used when creating a server. This is set to the wildcard [code]"*"[/code] by default, which binds to all available interfaces. The given IP needs to be in IPv4 or IPv6 address format, for example: [code]"192.168.1.1"[/code].
</description>
diff --git a/modules/enet/doc_classes/ENetPacketPeer.xml b/modules/enet/doc_classes/ENetPacketPeer.xml
index 5de5a60853..67760ba5e8 100644
--- a/modules/enet/doc_classes/ENetPacketPeer.xml
+++ b/modules/enet/doc_classes/ENetPacketPeer.xml
@@ -18,6 +18,18 @@
Returns the number of channels allocated for communication with peer.
</description>
</method>
+ <method name="get_remote_address" qualifiers="const">
+ <return type="String" />
+ <description>
+ Returns the IP address of this peer.
+ </description>
+ </method>
+ <method name="get_remote_port" qualifiers="const">
+ <return type="int" />
+ <description>
+ Returns the remote port of this peer.
+ </description>
+ </method>
<method name="get_state" qualifiers="const">
<return type="int" enum="ENetPacketPeer.PeerState" />
<description>
@@ -26,7 +38,7 @@
</method>
<method name="get_statistic">
<return type="float" />
- <argument index="0" name="statistic" type="int" enum="ENetPacketPeer.PeerStatistic" />
+ <param index="0" name="statistic" type="int" enum="ENetPacketPeer.PeerStatistic" />
<description>
Returns the requested [code]statistic[/code] for this peer. See [enum PeerStatistic].
</description>
@@ -39,21 +51,21 @@
</method>
<method name="peer_disconnect">
<return type="void" />
- <argument index="0" name="data" type="int" default="0" />
+ <param index="0" name="data" type="int" default="0" />
<description>
Request a disconnection from a peer. An [constant ENetConnection.EVENT_DISCONNECT] will be generated during [method ENetConnection.service] once the disconnection is complete.
</description>
</method>
<method name="peer_disconnect_later">
<return type="void" />
- <argument index="0" name="data" type="int" default="0" />
+ <param index="0" name="data" type="int" default="0" />
<description>
Request a disconnection from a peer, but only after all queued outgoing packets are sent. An [constant ENetConnection.EVENT_DISCONNECT] will be generated during [method ENetConnection.service] once the disconnection is complete.
</description>
</method>
<method name="peer_disconnect_now">
<return type="void" />
- <argument index="0" name="data" type="int" default="0" />
+ <param index="0" name="data" type="int" default="0" />
<description>
Force an immediate disconnection from a peer. No [constant ENetConnection.EVENT_DISCONNECT] will be generated. The foreign peer is not guaranteed to receive the disconnect notification, and is reset immediately upon return from this function.
</description>
@@ -66,7 +78,7 @@
</method>
<method name="ping_interval">
<return type="void" />
- <argument index="0" name="ping_interval" type="int" />
+ <param index="0" name="ping_interval" type="int" />
<description>
Sets the [code]ping_interval[/code] in milliseconds at which pings will be sent to a peer. Pings are used both to monitor the liveness of the connection and also to dynamically adjust the throttle during periods of low traffic so that the throttle has reasonable responsiveness during traffic spikes.
</description>
@@ -79,18 +91,18 @@
</method>
<method name="send">
<return type="int" enum="Error" />
- <argument index="0" name="channel" type="int" />
- <argument index="1" name="packet" type="PackedByteArray" />
- <argument index="2" name="flags" type="int" />
+ <param index="0" name="channel" type="int" />
+ <param index="1" name="packet" type="PackedByteArray" />
+ <param index="2" name="flags" type="int" />
<description>
Queues a [code]packet[/code] to be sent over the specified [code]channel[/code]. See [code]FLAG_*[/code] constants for available packet flags.
</description>
</method>
<method name="set_timeout">
<return type="void" />
- <argument index="0" name="timeout" type="int" />
- <argument index="1" name="timeout_min" type="int" />
- <argument index="2" name="timeout_max" type="int" />
+ <param index="0" name="timeout" type="int" />
+ <param index="1" name="timeout_min" type="int" />
+ <param index="2" name="timeout_max" type="int" />
<description>
Sets the timeout parameters for a peer. The timeout parameters control how and when a peer will timeout from a failure to acknowledge reliable traffic. Timeout values are expressed in milliseconds.
The [code]timeout_limit[/code] is a factor that, multiplied by a value based on the average round trip time, will determine the timeout limit for a reliable packet. When that limit is reached, the timeout will be doubled, and the peer will be disconnected if that limit has reached [code]timeout_min[/code]. The [code]timeout_max[/code] parameter, on the other hand, defines a fixed timeout for which any packet must be acknowledged or the peer will be dropped.
@@ -98,9 +110,9 @@
</method>
<method name="throttle_configure">
<return type="void" />
- <argument index="0" name="interval" type="int" />
- <argument index="1" name="acceleration" type="int" />
- <argument index="2" name="deceleration" type="int" />
+ <param index="0" name="interval" type="int" />
+ <param index="1" name="acceleration" type="int" />
+ <param index="2" name="deceleration" type="int" />
<description>
Configures throttle parameter for a peer.
Unreliable packets are dropped by ENet in response to the varying conditions of the Internet connection to the peer. The throttle represents a probability that an unreliable packet should not be dropped and thus sent by ENet to the peer. By measuring fluctuations in round trip times of reliable packets over the specified [code]interval[/code], ENet will either increase the probably by the amount specified in the [code]acceleration[/code] parameter, or decrease it by the amount specified in the [code]deceleration[/code] parameter (both are ratios to [constant PACKET_THROTTLE_SCALE]).
diff --git a/modules/enet/enet_connection.cpp b/modules/enet/enet_connection.cpp
index 629974d7c7..6a4bbecf6a 100644
--- a/modules/enet/enet_connection.cpp
+++ b/modules/enet/enet_connection.cpp
@@ -34,6 +34,7 @@
#include "core/io/compression.h"
#include "core/io/ip.h"
+#include "core/variant/typed_array.h"
void ENetConnection::broadcast(enet_uint8 p_channel, ENetPacket *p_packet) {
ERR_FAIL_COND_MSG(!host, "The ENetConnection instance isn't currently active.");
@@ -263,9 +264,9 @@ void ENetConnection::get_peers(List<Ref<ENetPacketPeer>> &r_peers) {
}
}
-Array ENetConnection::_get_peers() {
+TypedArray<ENetPacketPeer> ENetConnection::_get_peers() {
ERR_FAIL_COND_V_MSG(!host, Array(), "The ENetConnection instance isn't currently active.");
- Array out;
+ TypedArray<ENetPacketPeer> out;
for (const Ref<ENetPacketPeer> &I : peers) {
out.push_back(I);
}
diff --git a/modules/enet/enet_connection.h b/modules/enet/enet_connection.h
index 0c873b6c55..5cd8f6be9a 100644
--- a/modules/enet/enet_connection.h
+++ b/modules/enet/enet_connection.h
@@ -38,6 +38,9 @@
#include <enet/enet.h>
+template <typename T>
+class TypedArray;
+
class ENetConnection : public RefCounted {
GDCLASS(ENetConnection, RefCounted);
@@ -83,7 +86,7 @@ private:
Error _create(ENetAddress *p_address, int p_max_peers, int p_max_channels, int p_in_bandwidth, int p_out_bandwidth);
Array _service(int p_timeout = 0);
void _broadcast(int p_channel, PackedByteArray p_packet, int p_flags);
- Array _get_peers();
+ TypedArray<ENetPacketPeer> _get_peers();
class Compressor {
private:
diff --git a/modules/enet/enet_packet_peer.cpp b/modules/enet/enet_packet_peer.cpp
index 62c0550edb..5a96f75c4f 100644
--- a/modules/enet/enet_packet_peer.cpp
+++ b/modules/enet/enet_packet_peer.cpp
@@ -206,6 +206,8 @@ void ENetPacketPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("send", "channel", "packet", "flags"), &ENetPacketPeer::_send);
ClassDB::bind_method(D_METHOD("throttle_configure", "interval", "acceleration", "deceleration"), &ENetPacketPeer::throttle_configure);
ClassDB::bind_method(D_METHOD("set_timeout", "timeout", "timeout_min", "timeout_max"), &ENetPacketPeer::set_timeout);
+ ClassDB::bind_method(D_METHOD("get_remote_address"), &ENetPacketPeer::get_remote_address);
+ ClassDB::bind_method(D_METHOD("get_remote_port"), &ENetPacketPeer::get_remote_port);
ClassDB::bind_method(D_METHOD("get_statistic", "statistic"), &ENetPacketPeer::get_statistic);
ClassDB::bind_method(D_METHOD("get_state"), &ENetPacketPeer::get_state);
ClassDB::bind_method(D_METHOD("get_channels"), &ENetPacketPeer::get_channels);
diff --git a/modules/freetype/SCsub b/modules/freetype/SCsub
index 4b2ea6faa5..2680479acc 100644
--- a/modules/freetype/SCsub
+++ b/modules/freetype/SCsub
@@ -58,22 +58,23 @@ if env["builtin_freetype"]:
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
- thirdparty_brotli_dir = "#thirdparty/brotli/"
- thirdparty_brotli_sources = [
- "common/constants.c",
- "common/context.c",
- "common/dictionary.c",
- "common/platform.c",
- "common/shared_dictionary.c",
- "common/transform.c",
- "dec/bit_reader.c",
- "dec/decode.c",
- "dec/huffman.c",
- "dec/state.c",
- ]
- thirdparty_sources += [thirdparty_brotli_dir + file for file in thirdparty_brotli_sources]
- env_freetype.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"])
- env_freetype.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"])
+ if env["brotli"]:
+ thirdparty_brotli_dir = "#thirdparty/brotli/"
+ thirdparty_brotli_sources = [
+ "common/constants.c",
+ "common/context.c",
+ "common/dictionary.c",
+ "common/platform.c",
+ "common/shared_dictionary.c",
+ "common/transform.c",
+ "dec/bit_reader.c",
+ "dec/decode.c",
+ "dec/huffman.c",
+ "dec/state.c",
+ ]
+ thirdparty_sources += [thirdparty_brotli_dir + file for file in thirdparty_brotli_sources]
+ env_freetype.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"])
+ env_freetype.Prepend(CPPPATH=[thirdparty_brotli_dir + "include"])
if env.get("use_ubsan") or env.get("use_asan") or env.get("use_tsan") or env.get("use_lsan") or env.get("use_msan"):
env_freetype.Append(CPPDEFINES=["BROTLI_BUILD_PORTABLE"])
@@ -98,7 +99,7 @@ if env["builtin_freetype"]:
sfnt = thirdparty_dir + "src/sfnt/sfnt.c"
# Must be done after all CPPDEFINES are being set so we can copy them.
- if env["platform"] == "javascript":
+ if env["platform"] == "web":
# Forcibly undefine this macro so SIMD is not used in this file,
# since currently unsupported in WASM
tmp_env = env_freetype.Clone()
diff --git a/modules/freetype/config.py b/modules/freetype/config.py
index d22f9454ed..c0586d5536 100644
--- a/modules/freetype/config.py
+++ b/modules/freetype/config.py
@@ -2,5 +2,13 @@ def can_build(env, platform):
return True
+def get_opts(platform):
+ from SCons.Variables import BoolVariable
+
+ return [
+ BoolVariable("brotli", "Enable Brotli decompressor for WOFF2 fonts support", True),
+ ]
+
+
def configure(env):
pass
diff --git a/modules/gdscript/config.py b/modules/gdscript/config.py
index 61ce6185a5..a7d5c406e9 100644
--- a/modules/gdscript/config.py
+++ b/modules/gdscript/config.py
@@ -1,4 +1,5 @@
def can_build(env, platform):
+ env.module_add_dependencies("gdscript", ["jsonrpc", "websocket"], True)
return True
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 10cf783e73..c2301c3e27 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -8,14 +8,15 @@
For the list of the global functions and constants see [@GlobalScope].
</description>
<tutorials>
+ <link title="GDScript exports">$DOCS_URL/tutorials/scripting/gdscript/gdscript_exports.html</link>
</tutorials>
<methods>
<method name="Color8">
<return type="Color" />
- <argument index="0" name="r8" type="int" />
- <argument index="1" name="g8" type="int" />
- <argument index="2" name="b8" type="int" />
- <argument index="3" name="a8" type="int" default="255" />
+ <param index="0" name="r8" type="int" />
+ <param index="1" name="g8" type="int" />
+ <param index="2" name="b8" type="int" />
+ <param index="3" name="a8" type="int" default="255" />
<description>
Returns a color constructed from integer red, green, blue, and alpha channels. Each channel should have 8 bits of information ranging from 0 to 255.
[code]r8[/code] red channel
@@ -29,8 +30,8 @@
</method>
<method name="assert">
<return type="void" />
- <argument index="0" name="condition" type="bool" />
- <argument index="1" name="message" type="String" default="&quot;&quot;" />
+ <param index="0" name="condition" type="bool" />
+ <param index="1" name="message" type="String" default="&quot;&quot;" />
<description>
Asserts that the [code]condition[/code] is [code]true[/code]. If the [code]condition[/code] is [code]false[/code], an error is generated. When running from the editor, the running project will also be paused until you resume it. This can be used as a stronger form of [method @GlobalScope.push_error] for reporting errors to project developers or add-on users.
[b]Note:[/b] For performance reasons, the code inside [method assert] is only executed in debug builds or when running the project from the editor. Don't include code that has side effects in an [method assert] call. Otherwise, the project will behave differently when exported in release mode.
@@ -47,7 +48,7 @@
</method>
<method name="char">
<return type="String" />
- <argument index="0" name="char" type="int" />
+ <param index="0" name="char" type="int" />
<description>
Returns a character as a String of the given Unicode code point (which is compatible with ASCII code).
[codeblock]
@@ -59,8 +60,8 @@
</method>
<method name="convert">
<return type="Variant" />
- <argument index="0" name="what" type="Variant" />
- <argument index="1" name="type" type="int" />
+ <param index="0" name="what" type="Variant" />
+ <param index="1" name="type" type="int" />
<description>
Converts from a type to another in the best way possible. The [code]type[/code] parameter uses the [enum Variant.Type] values.
[codeblock]
@@ -73,11 +74,11 @@
[/codeblock]
</description>
</method>
- <method name="dict2inst">
+ <method name="dict_to_inst">
<return type="Object" />
- <argument index="0" name="dictionary" type="Dictionary" />
+ <param index="0" name="dictionary" type="Dictionary" />
<description>
- Converts a dictionary (previously created with [method inst2dict]) back to an instance. Useful for deserializing.
+ Converts a [param dictionary] (previously created with [method inst_to_dict]) back to an Object instance. Useful for deserializing.
</description>
</method>
<method name="get_stack">
@@ -101,15 +102,15 @@
[b]Note:[/b] Not supported for calling from threads. Instead, this will return an empty array.
</description>
</method>
- <method name="inst2dict">
+ <method name="inst_to_dict">
<return type="Dictionary" />
- <argument index="0" name="instance" type="Object" />
+ <param index="0" name="instance" type="Object" />
<description>
- Returns the passed instance converted to a dictionary (useful for serializing).
+ Returns the passed [param instance] converted to a Dictionary (useful for serializing).
[codeblock]
var foo = "bar"
func _ready():
- var d = inst2dict(self)
+ var d = inst_to_dict(self)
print(d.keys())
print(d.values())
[/codeblock]
@@ -122,7 +123,7 @@
</method>
<method name="len">
<return type="int" />
- <argument index="0" name="var" type="Variant" />
+ <param index="0" name="var" type="Variant" />
<description>
Returns length of Variant [code]var[/code]. Length is the character count of String, element count of Array, size of Dictionary, etc.
[b]Note:[/b] Generates a fatal error if Variant can not provide a length.
@@ -134,7 +135,7 @@
</method>
<method name="load">
<return type="Resource" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Loads a resource from the filesystem located at [code]path[/code]. The resource is loaded on the method call (unless it's referenced already elsewhere, e.g. in another script or in the scene), which might cause slight delay, especially when loading scenes. To avoid unnecessary delays when loading something multiple times, either store the resource in a variable or use [method preload].
[b]Note:[/b] Resource paths can be obtained by right-clicking on a resource in the FileSystem dock and choosing "Copy Path" or by dragging the file from the FileSystem dock into the script.
@@ -149,7 +150,7 @@
</method>
<method name="preload">
<return type="Resource" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Returns a [Resource] from the filesystem located at [code]path[/code]. The resource is loaded during script parsing, i.e. is loaded with the script and [method preload] effectively acts as a reference to that resource. Note that the method requires a constant path. If you want to load a resource from a dynamic/variable path, use [method load].
[b]Note:[/b] Resource paths can be obtained by right clicking on a resource in the Assets Panel and choosing "Copy Path" or by dragging the file from the FileSystem dock into the script.
@@ -237,8 +238,13 @@
</method>
<method name="type_exists">
<return type="bool" />
- <argument index="0" name="type" type="StringName" />
+ <param index="0" name="type" type="StringName" />
<description>
+ Returns whether the given [Object]-derived class exists in [ClassDB]. Note that [Variant] data types are not registered in [ClassDB].
+ [codeblock]
+ type_exists("Sprite2D") # Returns true
+ type_exists("NonExistentClass") # Returns false
+ [/codeblock]
</description>
</method>
</methods>
@@ -262,157 +268,334 @@
<annotation name="@export">
<return type="void" />
<description>
+ Mark the following property as exported (editable in the Inspector dock and saved to disk). To control the type of the exported property use the type hint notation.
+ [codeblock]
+ @export var int_number = 5
+ @export var float_number: float = 5
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_category">
<return type="void" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
+ Define a new category for the following exported properties. This helps to organize properties in the Inspector dock.
+ See also [constant PROPERTY_USAGE_CATEGORY].
+ [codeblock]
+ @export_category("My Properties")
+ @export var number = 3
+ @export var string = ""
+ [/codeblock]
+ [b]Note:[/b] Categories in the property list are supposed to indicate different base types, so the use of this annotation is not encouraged. See [annotation @export_group] and [annotation @export_subgroup] instead.
</description>
</annotation>
<annotation name="@export_color_no_alpha">
<return type="void" />
<description>
+ Export a [Color] property without an alpha (fixed as [code]1.0[/code]).
+ See also [constant PROPERTY_HINT_COLOR_NO_ALPHA].
+ [codeblock]
+ @export_color_no_alpha var modulate_color: Color
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_dir">
<return type="void" />
<description>
+ Export a [String] property as a path to a directory. The path will be limited to the project folder and its subfolders. See [annotation @export_global_dir] to allow picking from the entire filesystem.
+ See also [constant PROPERTY_HINT_DIR].
+ [codeblock]
+ @export_dir var sprite_folder: String
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_enum" qualifiers="vararg">
<return type="void" />
- <argument index="0" name="names" type="String" />
+ <param index="0" name="names" type="String" />
<description>
+ Export a [String] or integer property as an enumerated list of options. If the property is an integer field, then the index of the value is stored, in the same order the values are provided. You can add specific identifiers for allowed values using a colon.
+ See also [constant PROPERTY_HINT_ENUM].
+ [codeblock]
+ @export_enum("Rebecca", "Mary", "Leah") var character_name: String
+ @export_enum("Warrior", "Magician", "Thief") var character_class: int
+ @export_enum("Walking:30", "Running:60", "Riding:200") var character_speed: int
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_exp_easing" qualifiers="vararg">
<return type="void" />
- <argument index="0" name="hints" type="String" default="&quot;&quot;" />
+ <param index="0" name="hints" type="String" default="&quot;&quot;" />
<description>
+ Export a floating-point property with an easing editor widget. Additional hints can be provided to adjust the behavior of the widget. [code]"attenuation"[/code] flips the curve, which makes it more intuitive for editing attenuation properties. [code]"positive_only"[/code] limits values to only be greater than or equal to zero.
+ See also [constant PROPERTY_HINT_EXP_EASING].
+ [codeblock]
+ @export_exp_easing var transition_speed
+ @export_exp_easing("attenuation") var fading_attenuation
+ @export_exp_easing("positive_only") var effect_power
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_file" qualifiers="vararg">
<return type="void" />
- <argument index="0" name="filter" type="String" default="&quot;&quot;" />
+ <param index="0" name="filter" type="String" default="&quot;&quot;" />
<description>
+ Export a [String] property as a path to a file. The path will be limited to the project folder and its subfolders. See [annotation @export_global_file] to allow picking from the entire filesystem.
+ If [param filter] is provided, only matching files will be available for picking.
+ See also [constant PROPERTY_HINT_FILE].
+ [codeblock]
+ @export_file var sound_effect_file: String
+ @export_file("*.txt") var notes_file: String
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_flags" qualifiers="vararg">
<return type="void" />
- <argument index="0" name="names" type="String" />
+ <param index="0" name="names" type="String" />
<description>
+ Export an integer property as a bit flag field. This allows to store several "checked" or [code]true[/code] values with one property, and comfortably select them from the Inspector dock.
+ See also [constant PROPERTY_HINT_FLAGS].
+ [codeblock]
+ @export_flags("Fire", "Water", "Earth", "Wind") var spell_elements = 0
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_flags_2d_navigation">
<return type="void" />
<description>
+ Export an integer property as a bit flag field for 2D navigation layers. The widget in the Inspector dock will use the layer names defined in [member ProjectSettings.layer_names/2d_navigation/layer_1].
+ See also [constant PROPERTY_HINT_LAYERS_2D_NAVIGATION].
+ [codeblock]
+ @export_flags_2d_navigation var navigation_layers: int
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_flags_2d_physics">
<return type="void" />
<description>
+ Export an integer property as a bit flag field for 2D physics layers. The widget in the Inspector dock will use the layer names defined in [member ProjectSettings.layer_names/2d_physics/layer_1].
+ See also [constant PROPERTY_HINT_LAYERS_2D_PHYSICS].
+ [codeblock]
+ @export_flags_2d_physics var physics_layers: int
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_flags_2d_render">
<return type="void" />
<description>
+ Export an integer property as a bit flag field for 2D render layers. The widget in the Inspector dock will use the layer names defined in [member ProjectSettings.layer_names/2d_render/layer_1].
+ See also [constant PROPERTY_HINT_LAYERS_2D_RENDER].
+ [codeblock]
+ @export_flags_2d_render var render_layers: int
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_flags_3d_navigation">
<return type="void" />
<description>
+ Export an integer property as a bit flag field for 3D navigation layers. The widget in the Inspector dock will use the layer names defined in [member ProjectSettings.layer_names/3d_navigation/layer_1].
+ See also [constant PROPERTY_HINT_LAYERS_3D_NAVIGATION].
+ [codeblock]
+ @export_flags_3d_navigation var navigation_layers: int
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_flags_3d_physics">
<return type="void" />
<description>
+ Export an integer property as a bit flag field for 3D physics layers. The widget in the Inspector dock will use the layer names defined in [member ProjectSettings.layer_names/3d_physics/layer_1].
+ See also [constant PROPERTY_HINT_LAYERS_3D_PHYSICS].
+ [codeblock]
+ @export_flags_3d_physics var physics_layers: int
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_flags_3d_render">
<return type="void" />
<description>
+ Export an integer property as a bit flag field for 3D render layers. The widget in the Inspector dock will use the layer names defined in [member ProjectSettings.layer_names/3d_render/layer_1].
+ See also [constant PROPERTY_HINT_LAYERS_3D_RENDER].
+ [codeblock]
+ @export_flags_3d_render var render_layers: int
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_global_dir">
<return type="void" />
<description>
+ Export a [String] property as a path to a directory. The path can be picked from the entire filesystem. See [annotation @export_dir] to limit it to the project folder and its subfolders.
+ See also [constant PROPERTY_HINT_GLOBAL_DIR].
+ [codeblock]
+ @export_global_dir var sprite_folder: String
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_global_file" qualifiers="vararg">
<return type="void" />
- <argument index="0" name="filter" type="String" default="&quot;&quot;" />
+ <param index="0" name="filter" type="String" default="&quot;&quot;" />
<description>
+ Export a [String] property as a path to a file. The path can be picked from the entire filesystem. See [annotation @export_file] to limit it to the project folder and its subfolders.
+ If [param filter] is provided, only matching files will be available for picking.
+ See also [constant PROPERTY_HINT_GLOBAL_FILE].
+ [codeblock]
+ @export_global_file var sound_effect_file: String
+ @export_global_file("*.txt") var notes_file: String
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_group">
<return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="prefix" type="String" default="&quot;&quot;" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="prefix" type="String" default="&quot;&quot;" />
<description>
+ Define a new group for the following exported properties. This helps to organize properties in the Inspector dock. Groups can be added with an optional [param prefix], which would make group to only consider properties that have this prefix. The grouping will break on the first property that doesn't have a prefix. The prefix is also removed from the property's name in the Inspector dock.
+ If no [param prefix] is provided, the every following property is added to the group. The group ends when then next group or category is defined. You can also force end a group by using this annotation with empty strings for paramters, [code]@export_group("", "")[/code].
+ Groups cannot be nested, use [annotation @export_subgroup] to add subgroups to your groups.
+ See also [constant PROPERTY_USAGE_GROUP].
+ [codeblock]
+ @export_group("My Properties")
+ @export var number = 3
+ @export var string = ""
+
+ @export_group("Prefixed Properties", "prefix_")
+ @export var prefix_number = 3
+ @export var prefix_string = ""
+
+ @export_group("", "")
+ @export var ungrouped_number = 3
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_multiline">
<return type="void" />
<description>
+ Export a [String] property with a large [TextEdit] widget instead of a [LineEdit]. This adds support for multiline content and makes it easier to edit large amount of text stored in the property.
+ See also [constant PROPERTY_HINT_MULTILINE_TEXT].
+ [codeblock]
+ @export_multiline var character_bio
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_node_path" qualifiers="vararg">
<return type="void" />
- <argument index="0" name="type" type="String" default="&quot;&quot;" />
+ <param index="0" name="type" type="String" default="&quot;&quot;" />
<description>
+ Export a [NodePath] property with a filter for allowed node types.
+ See also [constant PROPERTY_HINT_NODE_PATH_VALID_TYPES].
+ [codeblock]
+ @export_node_path(Button, TouchScreenButton) var some_button
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_placeholder">
<return type="void" />
+ <param index="0" name="placeholder" type="String" />
<description>
+ Export a [String] property with a placeholder text displayed in the editor widget when no value is present.
+ See also [constant PROPERTY_HINT_PLACEHOLDER_TEXT].
+ [codeblock]
+ @export_placeholder("Name in lowercase") var character_id: String
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_range" qualifiers="vararg">
<return type="void" />
- <argument index="0" name="min" type="float" />
- <argument index="1" name="max" type="float" />
- <argument index="2" name="step" type="float" default="1.0" />
- <argument index="3" name="extra_hints" type="String" default="&quot;&quot;" />
- <description>
+ <param index="0" name="min" type="float" />
+ <param index="1" name="max" type="float" />
+ <param index="2" name="step" type="float" default="1.0" />
+ <param index="3" name="extra_hints" type="String" default="&quot;&quot;" />
+ <description>
+ Export a numeric property as a range value. The range must be defined by [param min] and [param max], as well as an optional [param step] and a variety of extra hints. The [param step] defaults to [code]1[/code] for integer properties. For floating-point numbers this value depends on your [code]EditorSettings.interface/inspector/default_float_step[/code] setting.
+ If hints [code]"or_greater"[/code] and [code]"or_lesser"[/code] are provided, the editor widget will not cap the value at range boundaries. The [code]"exp"[/code] hint will make the edited values on range to change exponentially. The [code]"no_slider"[/code] hint will hide the slider element of the editor widget.
+ Hints also allow to indicate the units for the edited value. Using [code]"radians"[/code] you can specify that the actual value is in radians, but should be displayed in degrees in the Inspector dock. [code]"degrees"[/code] allows to add a degree sign as a unit suffix. Finally, a custom suffix can be provided using [code]"suffix:unit"[/code], where "unit" can be any string.
+ See also [constant PROPERTY_HINT_RANGE].
+ [codeblock]
+ @export_range(0, 20) var number
+ @export_range(-10, 20) var number
+ @export_range(-10, 20, 0.2) var number: float
+
+ @export_range(0, 100, 1, "or_greater") var power_percent
+ @export_range(0, 100, 1, "or_greater", "or_lesser") var health_delta
+
+ @export_range(-3.14, 3.14, 0.001, "radians") var angle_radians
+ @export_range(0, 360, 1, "degrees") var angle_degrees
+ @export_range(-8, 8, 2, "suffix:px") var target_offset
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_subgroup">
<return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="prefix" type="String" default="&quot;&quot;" />
+ <param index="0" name="name" type="String" />
+ <param index="1" name="prefix" type="String" default="&quot;&quot;" />
<description>
+ Define a new subgroup for the following exported properties. This helps to organize properties in the Inspector dock. Subgroups work exactly like groups, except they need a parent group to exist. See [annotation @export_group].
+ See also [constant PROPERTY_USAGE_SUBGROUP].
+ [codeblock]
+ @export_group("My Properties")
+ @export var number = 3
+ @export var string = ""
+
+ @export_subgroup("My Prefixed Properties", "prefix_")
+ @export var prefix_number = 3
+ @export var prefix_string = ""
+ [/codeblock]
+ [b]Note:[/b] Subgroups cannot be nested, they only provide one extra level of depth. Just like the next group ends the previous group, so do the subsequent subgroups.
</description>
</annotation>
<annotation name="@icon">
<return type="void" />
- <argument index="0" name="icon_path" type="String" />
+ <param index="0" name="icon_path" type="String" />
<description>
+ Add a custom icon to the current script. The icon is displayed in the Scene dock for every node that the script is attached to. For named classes the icon is also displayed in various editor dialogs.
+ [codeblock]
+ @icon("res://path/to/class/icon.svg")
+ [/codeblock]
+ [b]Note:[/b] Only the script can have a custom icon. Inner classes are not supported yet.
</description>
</annotation>
<annotation name="@onready">
<return type="void" />
<description>
+ Mark the following property as assigned on [Node]'s ready state change. Values for these properties are no assigned immediately upon the node's creation, and instead are computed and stored right before [method Node._ready].
+ [codeblock]
+ @onready var character_name: Label = $Label
+ [/codeblock]
</description>
</annotation>
<annotation name="@rpc" qualifiers="vararg">
<return type="void" />
- <argument index="0" name="mode" type="String" default="&quot;&quot;" />
- <argument index="1" name="sync" type="String" default="&quot;&quot;" />
- <argument index="2" name="transfer_mode" type="String" default="&quot;&quot;" />
- <argument index="3" name="transfer_channel" type="int" default="0" />
+ <param index="0" name="mode" type="String" default="&quot;&quot;" />
+ <param index="1" name="sync" type="String" default="&quot;&quot;" />
+ <param index="2" name="transfer_mode" type="String" default="&quot;&quot;" />
+ <param index="3" name="transfer_channel" type="int" default="0" />
<description>
+ Mark the following method for remote procedure calls. See [url=$DOCS_URL/tutorials/networking/high_level_multiplayer.html]High-level multiplayer[/url].
+ [codeblock]
+ @rpc()
+ [/codeblock]
</description>
</annotation>
<annotation name="@tool">
<return type="void" />
<description>
+ Mark the current script as a tool script, allowing it to be loaded and executed by the editor. See [url=$DOCS_URL/tutorials/plugins/running_code_in_the_editor.html]Running code in the editor[/url].
+ [codeblock]
+ @tool
+ extends Node
+ [/codeblock]
</description>
</annotation>
<annotation name="@warning_ignore" qualifiers="vararg">
<return type="void" />
- <argument index="0" name="warning" type="String" />
+ <param index="0" name="warning" type="String" />
<description>
+ Mark the following statement to ignore the specified warning. See [url=$DOCS_URL/tutorials/scripting/gdscript/warning_system.html]GDScript warning system[/url].
+ [codeblock]
+ func test():
+ print("hello")
+ return
+ @warning_ignore("unreachable_code")
+ print("unreachable")
+ [/codeblock]
</description>
</annotation>
</annotations>
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index a23f19de85..02922086f0 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -45,9 +45,11 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
int previous_column = 0;
bool prev_is_char = false;
- bool prev_is_number = false;
+ bool prev_is_digit = false;
+ bool prev_is_binary_op = false;
bool in_keyword = false;
bool in_word = false;
+ bool in_number = false;
bool in_function_name = false;
bool in_lambda = false;
bool in_variable_declaration = false;
@@ -84,16 +86,17 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
const int line_length = str.length();
Color prev_color;
- if (in_region != -1 && str.length() == 0) {
+ if (in_region != -1 && line_length == 0) {
color_region_cache[p_line] = in_region;
}
- for (int j = 0; j < str.length(); j++) {
+ for (int j = 0; j < line_length; j++) {
Dictionary highlighter_info;
color = font_color;
bool is_char = !is_symbol(str[j]);
bool is_a_symbol = is_symbol(str[j]);
- bool is_number = is_digit(str[j]);
+ bool is_a_digit = is_digit(str[j]);
+ bool is_binary_op = false;
/* color regions */
if (is_a_symbol || in_region != -1) {
@@ -231,67 +234,94 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
in_region = -1;
prev_is_char = false;
- prev_is_number = false;
+ prev_is_digit = false;
+ prev_is_binary_op = false;
continue;
}
}
}
+ // A bit of a hack, but couldn't come up with anything better.
+ if (j > 0 && (str[j] == '&' || str[j] == '^' || str[j] == '%' || str[j] == '+' || str[j] == '-' || str[j] == '~' || str[j] == '.')) {
+ if (!keywords.has(previous_text)) {
+ if (previous_text == "PI" || previous_text == "TAU" || previous_text == "INF" || previous_text == "NAN") {
+ is_binary_op = true;
+ } else {
+ int k = j - 1;
+ while (k > 0 && is_whitespace(str[k])) {
+ k--;
+ }
+ if (!is_symbol(str[k]) || str[k] == '"' || str[k] == '\'' || str[k] == ')' || str[k] == ']' || str[k] == '}') {
+ is_binary_op = true;
+ }
+ }
+ }
+ }
+
+ if (!is_char) {
+ in_keyword = false;
+ }
+
// allow ABCDEF in hex notation
- if (is_hex_notation && (is_hex_digit(str[j]) || is_number)) {
- is_number = true;
+ if (is_hex_notation && (is_hex_digit(str[j]) || is_a_digit)) {
+ is_a_digit = true;
} else {
is_hex_notation = false;
}
- // disallow anything not a 0 or 1
- if (is_bin_notation && (is_binary_digit(str[j]))) {
- is_number = true;
- } else if (is_bin_notation) {
- is_bin_notation = false;
- is_number = false;
- } else {
+ // disallow anything not a 0 or 1 in binary notation
+ if (is_bin_notation && !is_binary_digit(str[j])) {
+ is_a_digit = false;
is_bin_notation = false;
}
- // check for dot or underscore or 'x' for hex notation in floating point number or 'e' for scientific notation
- if ((str[j] == '.' || str[j] == 'x' || str[j] == 'b' || str[j] == '_' || str[j] == 'e') && !in_word && prev_is_number && !is_number) {
- is_number = true;
- is_a_symbol = false;
- is_char = false;
+ if (!in_number && !in_word && is_a_digit) {
+ in_number = true;
+ }
- if (str[j] == 'x' && str[j - 1] == '0') {
- is_hex_notation = true;
- } else if (str[j] == 'b' && str[j - 1] == '0') {
+ // Special cases for numbers
+ if (in_number && !is_a_digit) {
+ if (str[j] == 'b' && str[j - 1] == '0') {
is_bin_notation = true;
+ } else if (str[j] == 'x' && str[j - 1] == '0') {
+ is_hex_notation = true;
+ } else if (!((str[j] == '-' || str[j] == '+') && str[j - 1] == 'e' && !prev_is_digit) &&
+ !(str[j] == '_' && (prev_is_digit || str[j - 1] == 'b' || str[j - 1] == 'x' || str[j - 1] == '.')) &&
+ !((str[j] == 'e' || str[j] == '.') && (prev_is_digit || str[j - 1] == '_')) &&
+ !((str[j] == '-' || str[j] == '+' || str[j] == '~') && !prev_is_binary_op && str[j - 1] != 'e')) {
+ /* 1st row of condition: '+' or '-' after scientific notation;
+ 2nd row of condition: '_' as a numeric separator;
+ 3rd row of condition: Scientific notation 'e' and floating points;
+ 4th row of condition: Multiple unary operators. */
+ in_number = false;
}
+ } else if ((str[j] == '-' || str[j] == '+' || str[j] == '~' || (str[j] == '.' && str[j + 1] != '.' && (j == 0 || (j > 0 && str[j - 1] != '.')))) && !is_binary_op) {
+ // Start a number from unary mathematical operators and floating points, except for '..'
+ in_number = true;
}
- if (!in_word && (is_ascii_char(str[j]) || is_underscore(str[j])) && !is_number) {
+ if (!in_word && (is_ascii_char(str[j]) || is_underscore(str[j])) && !in_number) {
in_word = true;
}
- if ((in_keyword || in_word) && !is_hex_notation) {
- is_number = false;
- }
-
if (is_a_symbol && str[j] != '.' && in_word) {
in_word = false;
}
- if (!is_char) {
- in_keyword = false;
- }
-
if (!in_keyword && is_char && !prev_is_char) {
int to = j;
- while (to < str.length() && !is_symbol(str[to])) {
+ while (to < line_length && !is_symbol(str[to])) {
to++;
}
String word = str.substr(j, to - j);
Color col = Color();
- if (keywords.has(word)) {
+ if (global_functions.has(word)) {
+ // "assert" and "preload" are reserved, so highlight even if not followed by a bracket.
+ if (word == "assert" || word == "preload" || str[to] == '(') {
+ col = global_function_color;
+ }
+ } else if (keywords.has(word)) {
col = keywords[word];
} else if (member_keywords.has(word)) {
col = member_keywords[word];
@@ -300,12 +330,13 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
if (col != Color()) {
for (int k = j - 1; k >= 0; k--) {
if (str[k] == '.') {
- col = Color(); // keyword & member indexing not allowed
+ col = Color(); // keyword, member & global func indexing not allowed
break;
} else if (str[k] > 32) {
break;
}
}
+
if (col != Color()) {
in_keyword = true;
keyword_color = col;
@@ -318,12 +349,12 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
in_signal_declaration = true;
} else {
int k = j;
- while (k < str.length() && !is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') {
+ while (k < line_length && !is_symbol(str[k]) && !is_whitespace(str[k])) {
k++;
}
// check for space between name and bracket
- while (k < str.length() && (str[k] == '\t' || str[k] == ' ')) {
+ while (k < line_length && is_whitespace(str[k])) {
k++;
}
@@ -336,7 +367,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
// Check for lambda.
if (in_function_name && previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::FUNC)) {
k = j - 1;
- while (k > 0 && (str[k] == '\t' || str[k] == ' ')) {
+ while (k > 0 && is_whitespace(str[k])) {
k--;
}
@@ -347,9 +378,9 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
}
}
- if (!in_function_name && !in_member_variable && !in_keyword && !is_number && in_word) {
+ if (!in_function_name && !in_member_variable && !in_keyword && !in_number && in_word) {
int k = j;
- while (k > 0 && !is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') {
+ while (k > 0 && !is_symbol(str[k]) && !is_whitespace(str[k])) {
k--;
}
@@ -378,7 +409,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
if (in_variable_declaration || in_function_args) {
int k = j;
// Skip space
- while (k < str.length() && (str[k] == '\t' || str[k] == ' ')) {
+ while (k < line_length && is_whitespace(str[k])) {
k++;
}
@@ -395,13 +426,25 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
in_member_variable = false;
}
- if (!in_node_path && in_region == -1 && (str[j] == '^')) {
+ // Keep symbol color for binary '&&'. In the case of '&&&' use StringName color for the last ampersand
+ if (!in_string_name && in_region == -1 && str[j] == '&' && !is_binary_op) {
+ if (j >= 2 && str[j - 1] == '&' && str[j - 2] != '&' && prev_is_binary_op) {
+ is_binary_op = true;
+ } else if (j == 0 || (j > 0 && str[j - 1] != '&') || prev_is_binary_op) {
+ in_string_name = true;
+ }
+ } else if (in_region != -1 || is_a_symbol) {
+ in_string_name = false;
+ }
+
+ // '^^' has no special meaning, so unlike StringName, when binary, use NodePath color for the last caret
+ if (!in_node_path && in_region == -1 && str[j] == '^' && !is_binary_op && (j == 0 || (j > 0 && str[j - 1] != '^') || prev_is_binary_op)) {
in_node_path = true;
- } else if (in_region != -1 || (is_a_symbol && str[j] != '/' && str[j] != '%')) {
+ } else if (in_region != -1 || is_a_symbol) {
in_node_path = false;
}
- if (!in_node_ref && in_region == -1 && (str[j] == '$' || str[j] == '%')) {
+ if (!in_node_ref && in_region == -1 && (str[j] == '$' || (str[j] == '%' && !is_binary_op))) {
in_node_ref = true;
} else if (in_region != -1 || (is_a_symbol && str[j] != '/' && str[j] != '%')) {
in_node_ref = false;
@@ -413,16 +456,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
in_annotation = false;
}
- if (!in_string_name && in_region == -1 && str[j] == '&') {
- in_string_name = true;
- } else if (in_region != -1 || is_a_symbol) {
- in_string_name = false;
- }
-
- if (in_node_path) {
- next_type = NODE_PATH;
- color = node_path_color;
- } else if (in_node_ref) {
+ if (in_node_ref) {
next_type = NODE_REF;
color = node_ref_color;
} else if (in_annotation) {
@@ -431,6 +465,9 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
} else if (in_string_name) {
next_type = STRING_NAME;
color = string_name_color;
+ } else if (in_node_path) {
+ next_type = NODE_PATH;
+ color = node_path_color;
} else if (in_keyword) {
next_type = KEYWORD;
color = keyword_color;
@@ -449,12 +486,12 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
} else {
color = function_color;
}
+ } else if (in_number) {
+ next_type = NUMBER;
+ color = number_color;
} else if (is_a_symbol) {
next_type = SYMBOL;
color = symbol_color;
- } else if (is_number) {
- next_type = NUMBER;
- color = number_color;
} else if (expect_type) {
next_type = TYPE;
color = type_color;
@@ -486,7 +523,8 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
}
prev_is_char = is_char;
- prev_is_number = is_number;
+ prev_is_digit = is_a_digit;
+ prev_is_binary_op = is_binary_op;
if (color != prev_color) {
prev_color = color;
@@ -501,8 +539,8 @@ String GDScriptSyntaxHighlighter::_get_name() const {
return "GDScript";
}
-Array GDScriptSyntaxHighlighter::_get_supported_languages() const {
- Array languages;
+PackedStringArray GDScriptSyntaxHighlighter::_get_supported_languages() const {
+ PackedStringArray languages;
languages.push_back("GDScript");
return languages;
}
@@ -510,6 +548,7 @@ Array GDScriptSyntaxHighlighter::_get_supported_languages() const {
void GDScriptSyntaxHighlighter::_update_cache() {
keywords.clear();
member_keywords.clear();
+ global_functions.clear();
color_regions.clear();
color_region_cache.clear();
@@ -566,6 +605,17 @@ void GDScriptSyntaxHighlighter::_update_cache() {
}
}
+ /* Global functions. */
+ List<StringName> global_function_list;
+ GDScriptUtilityFunctions::get_function_list(&global_function_list);
+ Variant::get_utility_function_list(&global_function_list);
+ // "assert" and "preload" are not utility functions, but are global nonetheless, so insert them.
+ global_functions.insert(SNAME("assert"));
+ global_functions.insert(SNAME("preload"));
+ for (const StringName &E : global_function_list) {
+ global_functions.insert(E);
+ }
+
/* Comments */
const Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color");
List<String> comments;
@@ -618,19 +668,22 @@ void GDScriptSyntaxHighlighter::_update_cache() {
if (godot_2_theme || EditorSettings::get_singleton()->is_dark_theme()) {
function_definition_color = Color(0.4, 0.9, 1.0);
+ global_function_color = Color(0.6, 0.6, 0.9);
node_path_color = Color(0.72, 0.77, 0.49);
node_ref_color = Color(0.39, 0.76, 0.35);
annotation_color = Color(1.0, 0.7, 0.45);
- string_name_color = Color(1.0, 0.66, 0.72);
+ string_name_color = Color(1.0, 0.76, 0.65);
} else {
function_definition_color = Color(0, 0.6, 0.6);
+ global_function_color = Color(0.4, 0.2, 0.8);
node_path_color = Color(0.18, 0.55, 0);
node_ref_color = Color(0.0, 0.5, 0);
annotation_color = Color(0.8, 0.37, 0);
- string_name_color = Color(0.8, 0.46, 0.52);
+ string_name_color = Color(0.8, 0.56, 0.45);
}
EDITOR_DEF("text_editor/theme/highlighting/gdscript/function_definition_color", function_definition_color);
+ EDITOR_DEF("text_editor/theme/highlighting/gdscript/global_function_color", global_function_color);
EDITOR_DEF("text_editor/theme/highlighting/gdscript/node_path_color", node_path_color);
EDITOR_DEF("text_editor/theme/highlighting/gdscript/node_reference_color", node_ref_color);
EDITOR_DEF("text_editor/theme/highlighting/gdscript/annotation_color", annotation_color);
@@ -641,6 +694,10 @@ void GDScriptSyntaxHighlighter::_update_cache() {
function_definition_color,
true);
EditorSettings::get_singleton()->set_initial_value(
+ "text_editor/theme/highlighting/gdscript/global_function_color",
+ global_function_color,
+ true);
+ EditorSettings::get_singleton()->set_initial_value(
"text_editor/theme/highlighting/gdscript/node_path_color",
node_path_color,
true);
@@ -659,6 +716,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {
}
function_definition_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/function_definition_color");
+ global_function_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/global_function_color");
node_path_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/node_path_color");
node_ref_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/node_reference_color");
annotation_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/annotation_color");
diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h
index 7987582f07..60b5b092d4 100644
--- a/modules/gdscript/editor/gdscript_highlighter.h
+++ b/modules/gdscript/editor/gdscript_highlighter.h
@@ -49,6 +49,7 @@ private:
HashMap<StringName, Color> keywords;
HashMap<StringName, Color> member_keywords;
+ HashSet<StringName> global_functions;
enum Type {
NONE,
@@ -67,10 +68,11 @@ private:
TYPE,
};
- // colours
+ // Colors.
Color font_color;
Color symbol_color;
Color function_color;
+ Color global_function_color;
Color function_definition_color;
Color built_in_type_color;
Color number_color;
@@ -88,7 +90,7 @@ public:
virtual Dictionary _get_line_syntax_highlighting_impl(int p_line) override;
virtual String _get_name() const override;
- virtual Array _get_supported_languages() const override;
+ virtual PackedStringArray _get_supported_languages() const override;
virtual Ref<EditorSyntaxHighlighter> _create() const override;
};
diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
index 9b540b16f2..518d4bcb62 100644
--- a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
+++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
@@ -41,7 +41,7 @@ Error GDScriptEditorTranslationParserPlugin::parse_file(const String &p_path, Ve
// Extract all translatable strings using the parsed tree from GDSriptParser.
// The strategy is to find all ExpressionNode and AssignmentNode from the tree and extract strings if relevant, i.e
// Search strings in ExpressionNode -> CallNode -> tr(), set_text(), set_placeholder() etc.
- // Search strings in AssignmentNode -> text = "__", hint_tooltip = "__" etc.
+ // Search strings in AssignmentNode -> text = "__", tooltip_text = "__" etc.
Error err;
Ref<Resource> loaded_res = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
@@ -221,7 +221,7 @@ void GDScriptEditorTranslationParserPlugin::_assess_assignment(GDScriptParser::A
}
if (assignment_patterns.has(assignee_name) && p_assignment->assigned_value->type == GDScriptParser::Node::LITERAL) {
- // If the assignment is towards one of the extract patterns (text, hint_tooltip etc.), and the value is a string literal, we collect the string.
+ // If the assignment is towards one of the extract patterns (text, tooltip_text etc.), and the value is a string literal, we collect the string.
ids->push_back(static_cast<GDScriptParser::LiteralNode *>(p_assignment->assigned_value)->value);
} else if (assignee_name == fd_filters && p_assignment->assigned_value->type == GDScriptParser::Node::CALL) {
// FileDialog.filters accepts assignment in the form of PackedStringArray. For example,
@@ -330,10 +330,10 @@ void GDScriptEditorTranslationParserPlugin::_extract_fd_literals(GDScriptParser:
GDScriptEditorTranslationParserPlugin::GDScriptEditorTranslationParserPlugin() {
assignment_patterns.insert("text");
assignment_patterns.insert("placeholder_text");
- assignment_patterns.insert("hint_tooltip");
+ assignment_patterns.insert("tooltip_text");
first_arg_patterns.insert("set_text");
- first_arg_patterns.insert("set_tooltip");
+ first_arg_patterns.insert("set_tooltip_text");
first_arg_patterns.insert("set_placeholder");
first_arg_patterns.insert("add_tab");
first_arg_patterns.insert("add_check_item");
diff --git a/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd b/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd
index a379d915a9..b8fc8c75dc 100644
--- a/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd
+++ b/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd
@@ -6,7 +6,7 @@ extends _BASE_
const SPEED = 300.0
const JUMP_VELOCITY = -400.0
-# Get the gravity from the project settings to be synced with RigidDynamicBody nodes.
+# Get the gravity from the project settings to be synced with RigidBody nodes.
var gravity: int = ProjectSettings.get_setting("physics/2d/default_gravity")
diff --git a/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd b/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd
index 360b199e56..53bc606c9a 100644
--- a/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd
+++ b/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd
@@ -6,7 +6,7 @@ extends _BASE_
const SPEED = 5.0
const JUMP_VELOCITY = 4.5
-# Get the gravity from the project settings to be synced with RigidDynamicBody nodes.
+# Get the gravity from the project settings to be synced with RigidBody nodes.
var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity")
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index d752bef14f..10babad378 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -290,7 +290,9 @@ void GDScript::_get_script_method_list(List<MethodInfo> *r_list, bool p_include_
#endif
mi.arguments.push_back(arginfo);
}
-
+#ifdef TOOLS_ENABLED
+ mi.default_arguments.append_array(func->get_default_arg_values());
+#endif
mi.return_val = func->get_return_type();
r_list->push_back(mi);
}
@@ -325,16 +327,23 @@ void GDScript::_get_script_property_list(List<PropertyInfo> *r_list, bool p_incl
for (int i = 0; i < msort.size(); i++) {
props.push_front(sptr->member_info[msort[i].name]);
}
+
+#ifdef TOOLS_ENABLED
+ r_list->push_back(sptr->get_class_category());
+#endif // TOOLS_ENABLED
+
+ for (const PropertyInfo &E : props) {
+ r_list->push_back(E);
+ }
+
+ props.clear();
+
if (!p_include_base) {
break;
}
sptr = sptr->_base;
}
-
- for (const PropertyInfo &E : props) {
- r_list->push_back(E);
- }
}
void GDScript::get_script_property_list(List<PropertyInfo> *r_list) const {
@@ -434,10 +443,6 @@ void GDScript::set_source_code(const String &p_code) {
#ifdef TOOLS_ENABLED
void GDScript::_update_exports_values(HashMap<StringName, Variant> &values, List<PropertyInfo> &propnames) {
- if (base_cache.is_valid()) {
- base_cache->_update_exports_values(values, propnames);
- }
-
for (const KeyValue<StringName, Variant> &E : member_default_values_cache) {
values[E.key] = E.value;
}
@@ -445,6 +450,10 @@ void GDScript::_update_exports_values(HashMap<StringName, Variant> &values, List
for (const PropertyInfo &E : members_cache) {
propnames.push_back(E);
}
+
+ if (base_cache.is_valid()) {
+ base_cache->_update_exports_values(values, propnames);
+ }
}
void GDScript::_add_doc(const DocData::ClassDoc &p_inner_class) {
@@ -674,7 +683,7 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc
if (base.is_empty() || base.is_relative_path()) {
ERR_PRINT(("Could not resolve relative path for parent class: " + path).utf8().get_data());
} else {
- path = base.get_base_dir().plus_file(path);
+ path = base.get_base_dir().path_join(path);
}
}
} else if (c->extends.size() != 0) {
@@ -703,6 +712,8 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc
member_default_values_cache.clear();
_signals.clear();
+ members_cache.push_back(get_class_category());
+
for (int i = 0; i < c->members.size(); i++) {
const GDScriptParser::ClassNode::Member &member = c->members[i];
@@ -728,6 +739,9 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc
}
_signals[member.signal->identifier->name] = parameters_names;
} break;
+ case GDScriptParser::ClassNode::Member::GROUP: {
+ members_cache.push_back(member.annotation->export_info);
+ } break;
default:
break; // Nothing.
}
@@ -1510,12 +1524,59 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
props.push_front(sptr->member_info[msort[i].name]);
}
+#ifdef TOOLS_ENABLED
+ p_properties->push_back(sptr->get_class_category());
+#endif // TOOLS_ENABLED
+
+ for (const PropertyInfo &prop : props) {
+ p_properties->push_back(prop);
+ }
+
+ props.clear();
+
sptr = sptr->_base;
}
+}
- for (const PropertyInfo &E : props) {
- p_properties->push_back(E);
+bool GDScriptInstance::property_can_revert(const StringName &p_name) const {
+ Variant name = p_name;
+ const Variant *args[1] = { &name };
+
+ const GDScript *sptr = script.ptr();
+ while (sptr) {
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._property_can_revert);
+ if (E) {
+ Callable::CallError err;
+ Variant ret = E->value->call(const_cast<GDScriptInstance *>(this), args, 1, err);
+ if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) {
+ return true;
+ }
+ }
+ sptr = sptr->_base;
+ }
+
+ return false;
+}
+
+bool GDScriptInstance::property_get_revert(const StringName &p_name, Variant &r_ret) const {
+ Variant name = p_name;
+ const Variant *args[1] = { &name };
+
+ const GDScript *sptr = script.ptr();
+ while (sptr) {
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._property_get_revert);
+ if (E) {
+ Callable::CallError err;
+ Variant ret = E->value->call(const_cast<GDScriptInstance *>(this), args, 1, err);
+ if (err.error == Callable::CallError::CALL_OK && ret.get_type() != Variant::NIL) {
+ r_ret = ret;
+ return true;
+ }
+ }
+ sptr = sptr->_base;
}
+
+ return false;
}
void GDScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
@@ -2143,7 +2204,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
if (c->icon_path.is_empty() || c->icon_path.is_absolute_path()) {
*r_icon_path = c->icon_path;
} else if (c->icon_path.is_relative_path()) {
- *r_icon_path = p_path.get_base_dir().plus_file(c->icon_path).simplify_path();
+ *r_icon_path = p_path.get_base_dir().path_join(c->icon_path).simplify_path();
}
}
if (r_base_type) {
@@ -2171,7 +2232,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
}
String subpath = subclass->extends_path;
if (subpath.is_relative_path()) {
- subpath = path.get_base_dir().plus_file(subpath).simplify_path();
+ subpath = path.get_base_dir().path_join(subpath).simplify_path();
}
if (OK != subparser.parse(subsource, subpath, false)) {
@@ -2228,6 +2289,8 @@ GDScriptLanguage::GDScriptLanguage() {
strings._set = StaticCString::create("_set");
strings._get = StaticCString::create("_get");
strings._get_property_list = StaticCString::create("_get_property_list");
+ strings._property_can_revert = StaticCString::create("_property_can_revert");
+ strings._property_get_revert = StaticCString::create("_property_get_revert");
strings._script_source = StaticCString::create("script/source");
_debug_parse_err_line = -1;
_debug_parse_err_file = "";
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 5123cccddd..e4b12d4ddb 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -287,6 +287,9 @@ public:
virtual void get_property_list(List<PropertyInfo> *p_properties) const;
virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const;
+ virtual bool property_can_revert(const StringName &p_name) const;
+ virtual bool property_get_revert(const StringName &p_name, Variant &r_ret) const;
+
virtual void get_method_list(List<MethodInfo> *p_list) const;
virtual bool has_method(const StringName &p_method) const;
virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
@@ -423,6 +426,8 @@ public:
StringName _set;
StringName _get;
StringName _get_property_list;
+ StringName _property_can_revert;
+ StringName _property_get_revert;
StringName _script_source;
} strings;
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 7ed440929c..c8c876369f 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -260,7 +260,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
if (!p_class->extends_path.is_empty()) {
if (p_class->extends_path.is_relative_path()) {
- p_class->extends_path = class_type.script_path.get_base_dir().plus_file(p_class->extends_path).simplify_path();
+ p_class->extends_path = class_type.script_path.get_base_dir().path_join(p_class->extends_path).simplify_path();
}
Ref<GDScriptParserRef> parser = get_parser_for(p_class->extends_path);
if (parser.is_null()) {
@@ -3185,7 +3185,7 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) {
p_preload->resolved_path = p_preload->path->reduced_value;
// TODO: Save this as script dependency.
if (p_preload->resolved_path.is_relative_path()) {
- p_preload->resolved_path = parser->script_path.get_base_dir().plus_file(p_preload->resolved_path);
+ p_preload->resolved_path = parser->script_path.get_base_dir().path_join(p_preload->resolved_path);
}
p_preload->resolved_path = p_preload->resolved_path.simplify_path();
if (!FileAccess::exists(p_preload->resolved_path)) {
@@ -3238,12 +3238,12 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
Variant value = p_subscript->base->reduced_value.get_named(p_subscript->attribute->name, valid);
if (!valid) {
push_error(vformat(R"(Cannot get member "%s" from "%s".)", p_subscript->attribute->name, p_subscript->base->reduced_value), p_subscript->index);
+ result_type.kind = GDScriptParser::DataType::VARIANT;
} else {
p_subscript->is_constant = true;
p_subscript->reduced_value = value;
result_type = type_from_variant(value, p_subscript);
}
- result_type.kind = GDScriptParser::DataType::VARIANT;
} else {
GDScriptParser::DataType base_type = p_subscript->base->get_datatype();
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index d943974ce4..c18412bc63 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -660,7 +660,13 @@ static String _make_arguments_hint(const MethodInfo &p_info, int p_arg_idx, bool
}
static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_function, int p_arg_idx) {
- String arghint = p_function->get_datatype().to_string() + " " + p_function->identifier->name.operator String() + "(";
+ String arghint;
+
+ if (p_function->get_datatype().builtin_type == Variant::NIL) {
+ arghint = "void " + p_function->identifier->name.operator String() + "(";
+ } else {
+ arghint = p_function->get_datatype().to_string() + " " + p_function->identifier->name.operator String() + "(";
+ }
for (int i = 0; i < p_function->parameters.size(); i++) {
if (i > 0) {
@@ -671,7 +677,11 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio
arghint += String::chr(0xFFFF);
}
const GDScriptParser::ParameterNode *par = p_function->parameters[i];
- arghint += par->identifier->name.operator String() + ": " + par->get_datatype().to_string();
+ if (!par->get_datatype().is_hard_type()) {
+ arghint += par->identifier->name.operator String() + ": Variant";
+ } else {
+ arghint += par->identifier->name.operator String() + ": " + par->get_datatype().to_string();
+ }
if (par->default_value) {
String def_val = "<unknown>";
@@ -2517,39 +2527,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
GDScriptCompletionIdentifier connect_base;
- if (Variant::has_utility_function(call->function_name)) {
- MethodInfo info = Variant::get_utility_function_info(call->function_name);
- r_arghint = _make_arguments_hint(info, p_argidx);
- return;
- } else if (GDScriptUtilityFunctions::function_exists(call->function_name)) {
- MethodInfo info = GDScriptUtilityFunctions::get_function_info(call->function_name);
- r_arghint = _make_arguments_hint(info, p_argidx);
- return;
- } else if (GDScriptParser::get_builtin_type(call->function_name) < Variant::VARIANT_MAX) {
- // Complete constructor.
- List<MethodInfo> constructors;
- Variant::get_constructor_list(GDScriptParser::get_builtin_type(call->function_name), &constructors);
-
- int i = 0;
- for (const MethodInfo &E : constructors) {
- if (p_argidx >= E.arguments.size()) {
- continue;
- }
- if (i > 0) {
- r_arghint += "\n";
- }
- r_arghint += _make_arguments_hint(E, p_argidx);
- i++;
- }
- return;
- } else if (call->is_super || callee_type == GDScriptParser::Node::IDENTIFIER) {
- base = p_context.base;
-
- if (p_context.current_class) {
- base_type = p_context.current_class->get_datatype();
- _static = !p_context.current_function || p_context.current_function->is_static;
- }
- } else if (callee_type == GDScriptParser::Node::SUBSCRIPT) {
+ if (callee_type == GDScriptParser::Node::SUBSCRIPT) {
const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(call->callee);
if (subscript->base != nullptr && subscript->base->type == GDScriptParser::Node::IDENTIFIER) {
@@ -2589,6 +2567,38 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
_static = base_type.is_meta_type;
}
+ } else if (Variant::has_utility_function(call->function_name)) {
+ MethodInfo info = Variant::get_utility_function_info(call->function_name);
+ r_arghint = _make_arguments_hint(info, p_argidx);
+ return;
+ } else if (GDScriptUtilityFunctions::function_exists(call->function_name)) {
+ MethodInfo info = GDScriptUtilityFunctions::get_function_info(call->function_name);
+ r_arghint = _make_arguments_hint(info, p_argidx);
+ return;
+ } else if (GDScriptParser::get_builtin_type(call->function_name) < Variant::VARIANT_MAX) {
+ // Complete constructor.
+ List<MethodInfo> constructors;
+ Variant::get_constructor_list(GDScriptParser::get_builtin_type(call->function_name), &constructors);
+
+ int i = 0;
+ for (const MethodInfo &E : constructors) {
+ if (p_argidx >= E.arguments.size()) {
+ continue;
+ }
+ if (i > 0) {
+ r_arghint += "\n";
+ }
+ r_arghint += _make_arguments_hint(E, p_argidx);
+ i++;
+ }
+ return;
+ } else if (call->is_super || callee_type == GDScriptParser::Node::IDENTIFIER) {
+ base = p_context.base;
+
+ if (p_context.current_class) {
+ base_type = p_context.current_class->get_datatype();
+ _static = !p_context.current_function || p_context.current_function->is_static;
+ }
} else {
return;
}
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 6f5397e1a3..6b6ad427a7 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -127,7 +127,7 @@ GDScriptParser::GDScriptParser() {
register_annotation(MethodInfo("@export_global_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_FILE, Variant::STRING>, varray(""), true);
register_annotation(MethodInfo("@export_global_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_DIR, Variant::STRING>);
register_annotation(MethodInfo("@export_multiline"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_MULTILINE_TEXT, Variant::STRING>);
- register_annotation(MethodInfo("@export_placeholder"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_PLACEHOLDER_TEXT, Variant::STRING>);
+ register_annotation(MethodInfo("@export_placeholder", PropertyInfo(Variant::STRING, "placeholder")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_PLACEHOLDER_TEXT, Variant::STRING>);
register_annotation(MethodInfo("@export_range", PropertyInfo(Variant::FLOAT, "min"), PropertyInfo(Variant::FLOAT, "max"), PropertyInfo(Variant::FLOAT, "step"), PropertyInfo(Variant::STRING, "extra_hints")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_RANGE, Variant::FLOAT>, varray(1.0, ""), true);
register_annotation(MethodInfo("@export_exp_easing", PropertyInfo(Variant::STRING, "hints")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_EXP_EASING, Variant::FLOAT>, varray(""), true);
register_annotation(MethodInfo("@export_color_no_alpha"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_COLOR_NO_ALPHA, Variant::COLOR>);
diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp
index 4b97486cb3..bcbe8b8d2b 100644
--- a/modules/gdscript/gdscript_utility_functions.cpp
+++ b/modules/gdscript/gdscript_utility_functions.cpp
@@ -36,6 +36,7 @@
#include "core/object/object.h"
#include "core/templates/oa_hash_map.h"
#include "core/templates/vector.h"
+#include "core/variant/typed_array.h"
#include "gdscript.h"
#ifdef DEBUG_ENABLED
@@ -261,7 +262,7 @@ struct GDScriptUtilityFunctionsDefinitions {
}
}
- static inline void inst2dict(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ static inline void inst_to_dict(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
VALIDATE_ARG_COUNT(1);
if (p_args[0]->get_type() == Variant::NIL) {
@@ -328,7 +329,7 @@ struct GDScriptUtilityFunctionsDefinitions {
}
}
- static inline void dict2inst(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
+ static inline void dict_to_inst(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
VALIDATE_ARG_COUNT(1);
if (p_args[0]->get_type() != Variant::DICTIONARY) {
@@ -468,12 +469,12 @@ struct GDScriptUtilityFunctionsDefinitions {
static inline void get_stack(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
VALIDATE_ARG_COUNT(0);
if (Thread::get_caller_id() != Thread::get_main_id()) {
- *r_ret = Array();
+ *r_ret = TypedArray<Dictionary>();
return;
}
ScriptLanguage *script = GDScriptLanguage::get_singleton();
- Array ret;
+ TypedArray<Dictionary> ret;
for (int i = 0; i < script->debug_get_stack_level_count(); i++) {
Dictionary frame;
frame["source"] = script->debug_get_stack_level_source(i);
@@ -652,8 +653,8 @@ void GDScriptUtilityFunctions::register_functions() {
REGISTER_VARARG_FUNC(str, true, Variant::STRING);
REGISTER_VARARG_FUNC(range, false, Variant::ARRAY);
REGISTER_CLASS_FUNC(load, false, "Resource", ARG("path", Variant::STRING));
- REGISTER_FUNC(inst2dict, false, Variant::DICTIONARY, ARG("instance", Variant::OBJECT));
- REGISTER_FUNC(dict2inst, false, Variant::OBJECT, ARG("dictionary", Variant::DICTIONARY));
+ REGISTER_FUNC(inst_to_dict, false, Variant::DICTIONARY, ARG("instance", Variant::OBJECT));
+ REGISTER_FUNC(dict_to_inst, false, Variant::OBJECT, ARG("dictionary", Variant::DICTIONARY));
REGISTER_FUNC_DEF(Color8, true, 255, Variant::COLOR, ARG("r8", Variant::INT), ARG("g8", Variant::INT), ARG("b8", Variant::INT), ARG("a8", Variant::INT));
REGISTER_VARARG_FUNC(print_debug, false, Variant::NIL);
REGISTER_FUNC_NO_ARGS(print_stack, false, Variant::NIL);
diff --git a/modules/gdscript/gdscript_utility_functions.h b/modules/gdscript/gdscript_utility_functions.h
index 9ca7cf33d8..0f07db857f 100644
--- a/modules/gdscript/gdscript_utility_functions.h
+++ b/modules/gdscript/gdscript_utility_functions.h
@@ -34,6 +34,9 @@
#include "core/string/string_name.h"
#include "core/variant/variant.h"
+template <typename T>
+class TypedArray;
+
class GDScriptUtilityFunctions {
public:
typedef void (*FunctionPtr)(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error);
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp
index c0d5856be5..39f4c976a4 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.cpp
+++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp
@@ -184,7 +184,9 @@ Dictionary GDScriptLanguageProtocol::initialize(const Dictionary &p_params) {
if (root_uri.length() && is_same_workspace) {
workspace->root_uri = root_uri;
} else {
- workspace->root_uri = "file://" + workspace->root;
+ String r_root = workspace->root;
+ r_root = r_root.lstrip("/");
+ workspace->root_uri = "file:///" + r_root;
Dictionary params;
params["path"] = workspace->root;
diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp
index ded2a7b4d4..fd213e7b37 100644
--- a/modules/gdscript/language_server/gdscript_workspace.cpp
+++ b/modules/gdscript/language_server/gdscript_workspace.cpp
@@ -228,9 +228,9 @@ void GDScriptWorkspace::list_script_files(const String &p_root_dir, List<String>
String file_name = dir->get_next();
while (file_name.length()) {
if (dir->current_is_dir() && file_name != "." && file_name != ".." && file_name != "./") {
- list_script_files(p_root_dir.plus_file(file_name), r_files);
+ list_script_files(p_root_dir.path_join(file_name), r_files);
} else if (file_name.ends_with(".gd")) {
- String script_file = p_root_dir.plus_file(file_name);
+ String script_file = p_root_dir.path_join(file_name);
r_files.push_back(script_file);
}
file_name = dir->get_next();
@@ -500,10 +500,8 @@ Error GDScriptWorkspace::parse_local_script(const String &p_path) {
String GDScriptWorkspace::get_file_path(const String &p_uri) const {
String path = p_uri;
- path = path.replace("///", "//");
- path = path.replace("%3A", ":");
- path = path.replacen(root_uri + "/", "res://");
path = path.uri_decode();
+ path = path.replacen(root_uri + "/", "res://");
return path;
}
diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp
index ff4832bde0..6c346acb7e 100644
--- a/modules/gdscript/tests/gdscript_test_runner.cpp
+++ b/modules/gdscript/tests/gdscript_test_runner.cpp
@@ -36,6 +36,7 @@
#include "../gdscript_parser.h"
#include "core/config/project_settings.h"
+#include "core/core_globals.h"
#include "core/core_string_names.h"
#include "core/io/dir_access.h"
#include "core/io/file_access_pack.h"
@@ -142,8 +143,8 @@ GDScriptTestRunner::GDScriptTestRunner(const String &p_source_dir, bool p_init_l
#endif
// Enable printing to show results
- _print_line_enabled = true;
- _print_error_enabled = true;
+ CoreGlobals::print_line_enabled = true;
+ CoreGlobals::print_error_enabled = true;
}
GDScriptTestRunner::~GDScriptTestRunner() {
@@ -246,7 +247,7 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) {
next = dir->get_next();
continue;
}
- if (!make_tests_for_dir(current_dir.plus_file(next))) {
+ if (!make_tests_for_dir(current_dir.path_join(next))) {
return false;
}
} else {
@@ -254,7 +255,7 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) {
#ifndef DEBUG_ENABLED
// On release builds, skip tests marked as debug only.
Error open_err = OK;
- Ref<FileAccess> script_file(FileAccess::open(current_dir.plus_file(next), FileAccess::READ, &open_err));
+ Ref<FileAccess> script_file(FileAccess::open(current_dir.path_join(next), FileAccess::READ, &open_err));
if (open_err != OK) {
ERR_PRINT(vformat(R"(Couldn't open test file "%s".)", next));
next = dir->get_next();
@@ -271,7 +272,7 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) {
if (!is_generating && !dir->file_exists(out_file)) {
ERR_FAIL_V_MSG(false, "Could not find output file for " + next);
}
- GDScriptTest test(current_dir.plus_file(next), current_dir.plus_file(out_file), source_dir);
+ GDScriptTest test(current_dir.path_join(next), current_dir.path_join(out_file), source_dir);
tests.push_back(test);
}
}
diff --git a/modules/gdscript/tests/gdscript_test_runner_suite.h b/modules/gdscript/tests/gdscript_test_runner_suite.h
index 0722fb800e..90f6d7f7e8 100644
--- a/modules/gdscript/tests/gdscript_test_runner_suite.h
+++ b/modules/gdscript/tests/gdscript_test_runner_suite.h
@@ -69,6 +69,40 @@ func _init():
CHECK_MESSAGE(int(ref_counted->get_meta("result")) == 42, "The script should assign object metadata successfully.");
}
+TEST_CASE("[Modules][GDScript] Validate built-in API") {
+ GDScriptLanguage *lang = GDScriptLanguage::get_singleton();
+
+ // Validate methods.
+ List<MethodInfo> builtin_methods;
+ lang->get_public_functions(&builtin_methods);
+
+ SUBCASE("[Modules][GDScript] Validate built-in methods") {
+ for (const MethodInfo &mi : builtin_methods) {
+ for (int j = 0; j < mi.arguments.size(); j++) {
+ PropertyInfo arg = mi.arguments[j];
+
+ TEST_COND((arg.name.is_empty() || arg.name.begins_with("_unnamed_arg")),
+ vformat("Unnamed argument in position %d of built-in method '%s'.", j, mi.name));
+ }
+ }
+ }
+
+ // Validate annotations.
+ List<MethodInfo> builtin_annotations;
+ lang->get_public_annotations(&builtin_annotations);
+
+ SUBCASE("[Modules][GDScript] Validate built-in annotations") {
+ for (const MethodInfo &ai : builtin_annotations) {
+ for (int j = 0; j < ai.arguments.size(); j++) {
+ PropertyInfo arg = ai.arguments[j];
+
+ TEST_COND((arg.name.is_empty() || arg.name.begins_with("_unnamed_arg")),
+ vformat("Unnamed argument in position %d of built-in annotation '%s'.", j, ai.name));
+ }
+ }
+ }
+}
+
} // namespace GDScriptTests
#endif // GDSCRIPT_TEST_RUNNER_SUITE_H
diff --git a/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.gd b/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.gd
index fb0ace6a90..ea744e3027 100644
--- a/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.gd
+++ b/modules/gdscript/tests/scripts/analyzer/features/gdscript_to_preload.gd
@@ -1,3 +1,5 @@
+const A := 42
+
func test():
pass
diff --git a/modules/gdscript/tests/scripts/analyzer/features/preload_constant_types_are_inferred.gd b/modules/gdscript/tests/scripts/analyzer/features/preload_constant_types_are_inferred.gd
new file mode 100644
index 0000000000..276875dd5a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/preload_constant_types_are_inferred.gd
@@ -0,0 +1,6 @@
+const Constants = preload("gdscript_to_preload.gd")
+
+func test():
+ var a := Constants.A
+ print(a)
+
diff --git a/modules/gdscript/tests/scripts/analyzer/features/preload_constant_types_are_inferred.out b/modules/gdscript/tests/scripts/analyzer/features/preload_constant_types_are_inferred.out
new file mode 100644
index 0000000000..0982f3718c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/preload_constant_types_are_inferred.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+42
diff --git a/modules/gltf/SCsub b/modules/gltf/SCsub
index 6634d5df7b..71f3ba58d9 100644
--- a/modules/gltf/SCsub
+++ b/modules/gltf/SCsub
@@ -5,7 +5,7 @@ Import("env_modules")
env_gltf = env_modules.Clone()
-# Godot's own source files
+# Godot source files
env_gltf.add_source_files(env.modules_sources, "*.cpp")
env_gltf.add_source_files(env.modules_sources, "extensions/*.cpp")
env_gltf.add_source_files(env.modules_sources, "structures/*.cpp")
diff --git a/modules/gltf/doc_classes/GLTFCamera.xml b/modules/gltf/doc_classes/GLTFCamera.xml
index 9b9eff6141..49efaa1564 100644
--- a/modules/gltf/doc_classes/GLTFCamera.xml
+++ b/modules/gltf/doc_classes/GLTFCamera.xml
@@ -1,19 +1,58 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GLTFCamera" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
+ Represents a GLTF camera.
</brief_description>
<description>
+ Represents a camera as defined by the base GLTF spec.
</description>
<tutorials>
+ <link title="GLTF camera detailed specification">https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-camera</link>
+ <link title="GLTF camera spec and example file">https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_015_SimpleCameras.md</link>
</tutorials>
+ <methods>
+ <method name="from_dictionary" qualifiers="static">
+ <return type="GLTFCamera" />
+ <param index="0" name="dictionary" type="Dictionary" />
+ <description>
+ Creates a new GLTFCamera instance by parsing the given [Dictionary].
+ </description>
+ </method>
+ <method name="from_node" qualifiers="static">
+ <return type="GLTFCamera" />
+ <param index="0" name="camera_node" type="Camera3D" />
+ <description>
+ Create a new GLTFCamera instance from the given Godot [Camera3D] node.
+ </description>
+ </method>
+ <method name="to_dictionary" qualifiers="const">
+ <return type="Dictionary" />
+ <description>
+ Serializes this GLTFCamera instance into a [Dictionary].
+ </description>
+ </method>
+ <method name="to_node" qualifiers="const">
+ <return type="Camera3D" />
+ <description>
+ Converts this GLTFCamera instance into a Godot [Camera3D] node.
+ </description>
+ </method>
+ </methods>
<members>
<member name="depth_far" type="float" setter="set_depth_far" getter="get_depth_far" default="4000.0">
+ The distance to the far culling boundary for this camera relative to its local Z axis, in meters. This maps to GLTF's [code]zfar[/code] property.
</member>
<member name="depth_near" type="float" setter="set_depth_near" getter="get_depth_near" default="0.05">
+ The distance to the near culling boundary for this camera relative to its local Z axis, in meters. This maps to GLTF's [code]znear[/code] property.
</member>
- <member name="fov_size" type="float" setter="set_fov_size" getter="get_fov_size" default="75.0">
+ <member name="fov" type="float" setter="set_fov" getter="get_fov" default="1.309">
+ The FOV of the camera. This class and GLTF define the camera FOV in radians, while Godot uses degrees. This maps to GLTF's [code]yfov[/code] property. This value is only used for perspective cameras, when [member perspective] is true.
</member>
<member name="perspective" type="bool" setter="set_perspective" getter="get_perspective" default="true">
+ Whether or not the camera is in perspective mode. If false, the camera is in orthographic/orthogonal mode. This maps to GLTF's camera [code]type[/code] property. See [member Camera3D.projection] and the GLTF spec for more information.
+ </member>
+ <member name="size_mag" type="float" setter="set_size_mag" getter="get_size_mag" default="0.5">
+ The size of the camera. This class and GLTF define the camera size magnitude as a radius in meters, while Godot defines it as a diameter in meters. This maps to GLTF's [code]ymag[/code] property. This value is only used for orthographic/orthogonal cameras, when [member perspective] is false.
</member>
</members>
</class>
diff --git a/modules/gltf/doc_classes/GLTFDocument.xml b/modules/gltf/doc_classes/GLTFDocument.xml
index cb0e3b6754..3cd0f5c0f9 100644
--- a/modules/gltf/doc_classes/GLTFDocument.xml
+++ b/modules/gltf/doc_classes/GLTFDocument.xml
@@ -10,50 +10,50 @@
<methods>
<method name="append_from_buffer">
<return type="int" enum="Error" />
- <argument index="0" name="bytes" type="PackedByteArray" />
- <argument index="1" name="base_path" type="String" />
- <argument index="2" name="state" type="GLTFState" />
- <argument index="3" name="flags" type="int" default="0" />
- <argument index="4" name="bake_fps" type="int" default="30" />
+ <param index="0" name="bytes" type="PackedByteArray" />
+ <param index="1" name="base_path" type="String" />
+ <param index="2" name="state" type="GLTFState" />
+ <param index="3" name="flags" type="int" default="0" />
+ <param index="4" name="bake_fps" type="int" default="30" />
<description>
</description>
</method>
<method name="append_from_file">
<return type="int" enum="Error" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="state" type="GLTFState" />
- <argument index="2" name="flags" type="int" default="0" />
- <argument index="3" name="bake_fps" type="int" default="30" />
- <argument index="4" name="base_path" type="String" default="&quot;&quot;" />
+ <param index="0" name="path" type="String" />
+ <param index="1" name="state" type="GLTFState" />
+ <param index="2" name="flags" type="int" default="0" />
+ <param index="3" name="bake_fps" type="int" default="30" />
+ <param index="4" name="base_path" type="String" default="&quot;&quot;" />
<description>
</description>
</method>
<method name="append_from_scene">
<return type="int" enum="Error" />
- <argument index="0" name="node" type="Node" />
- <argument index="1" name="state" type="GLTFState" />
- <argument index="2" name="flags" type="int" default="0" />
- <argument index="3" name="bake_fps" type="int" default="30" />
+ <param index="0" name="node" type="Node" />
+ <param index="1" name="state" type="GLTFState" />
+ <param index="2" name="flags" type="int" default="0" />
+ <param index="3" name="bake_fps" type="int" default="30" />
<description>
</description>
</method>
<method name="generate_buffer">
<return type="PackedByteArray" />
- <argument index="0" name="state" type="GLTFState" />
+ <param index="0" name="state" type="GLTFState" />
<description>
</description>
</method>
<method name="generate_scene">
<return type="Node" />
- <argument index="0" name="state" type="GLTFState" />
- <argument index="1" name="bake_fps" type="int" default="30" />
+ <param index="0" name="state" type="GLTFState" />
+ <param index="1" name="bake_fps" type="int" default="30" />
<description>
</description>
</method>
<method name="write_to_filesystem">
<return type="int" enum="Error" />
- <argument index="0" name="state" type="GLTFState" />
- <argument index="1" name="path" type="String" />
+ <param index="0" name="state" type="GLTFState" />
+ <param index="1" name="path" type="String" />
<description>
</description>
</method>
diff --git a/modules/gltf/doc_classes/GLTFDocumentExtension.xml b/modules/gltf/doc_classes/GLTFDocumentExtension.xml
index 3c28546ad7..d2a9022445 100644
--- a/modules/gltf/doc_classes/GLTFDocumentExtension.xml
+++ b/modules/gltf/doc_classes/GLTFDocumentExtension.xml
@@ -9,50 +9,50 @@
<methods>
<method name="_export_node" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="state" type="GLTFState" />
- <argument index="1" name="gltf_node" type="GLTFNode" />
- <argument index="2" name="json" type="Dictionary" />
- <argument index="3" name="node" type="Node" />
+ <param index="0" name="state" type="GLTFState" />
+ <param index="1" name="gltf_node" type="GLTFNode" />
+ <param index="2" name="json" type="Dictionary" />
+ <param index="3" name="node" type="Node" />
<description>
</description>
</method>
<method name="_export_post" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="state" type="GLTFState" />
+ <param index="0" name="state" type="GLTFState" />
<description>
</description>
</method>
<method name="_export_preflight" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="root" type="Node" />
+ <param index="0" name="root" type="Node" />
<description>
</description>
</method>
<method name="_import_node" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="state" type="GLTFState" />
- <argument index="1" name="gltf_node" type="GLTFNode" />
- <argument index="2" name="json" type="Dictionary" />
- <argument index="3" name="node" type="Node" />
+ <param index="0" name="state" type="GLTFState" />
+ <param index="1" name="gltf_node" type="GLTFNode" />
+ <param index="2" name="json" type="Dictionary" />
+ <param index="3" name="node" type="Node" />
<description>
</description>
</method>
<method name="_import_post" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="state" type="GLTFState" />
- <argument index="1" name="root" type="Node" />
+ <param index="0" name="state" type="GLTFState" />
+ <param index="1" name="root" type="Node" />
<description>
</description>
</method>
<method name="_import_post_parse" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="state" type="GLTFState" />
+ <param index="0" name="state" type="GLTFState" />
<description>
</description>
</method>
<method name="_import_preflight" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="state" type="GLTFState" />
+ <param index="0" name="state" type="GLTFState" />
<description>
</description>
</method>
diff --git a/modules/gltf/doc_classes/GLTFLight.xml b/modules/gltf/doc_classes/GLTFLight.xml
index 354cd48a06..7fd59e14bc 100644
--- a/modules/gltf/doc_classes/GLTFLight.xml
+++ b/modules/gltf/doc_classes/GLTFLight.xml
@@ -1,11 +1,42 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GLTFLight" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
+ Represents a GLTF light.
</brief_description>
<description>
+ Represents a light as defined by the [code]KHR_lights_punctual[/code] GLTF extension.
</description>
<tutorials>
+ <link title="KHR_lights_punctual GLTF extension spec">https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_lights_punctual</link>
</tutorials>
+ <methods>
+ <method name="from_dictionary" qualifiers="static">
+ <return type="GLTFLight" />
+ <param index="0" name="dictionary" type="Dictionary" />
+ <description>
+ Creates a new GLTFLight instance by parsing the given [Dictionary].
+ </description>
+ </method>
+ <method name="from_node" qualifiers="static">
+ <return type="GLTFLight" />
+ <param index="0" name="light_node" type="Light3D" />
+ <description>
+ Create a new GLTFLight instance from the given Godot [Light3D] node.
+ </description>
+ </method>
+ <method name="to_dictionary" qualifiers="const">
+ <return type="Dictionary" />
+ <description>
+ Serializes this GLTFLight instance into a [Dictionary].
+ </description>
+ </method>
+ <method name="to_node" qualifiers="const">
+ <return type="Light3D" />
+ <description>
+ Converts this GLTFLight instance into a Godot [Light3D] node.
+ </description>
+ </method>
+ </methods>
<members>
<member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)">
The [Color] of the light. Defaults to white. A black color causes the light to have no effect.
diff --git a/modules/gltf/doc_classes/GLTFSkeleton.xml b/modules/gltf/doc_classes/GLTFSkeleton.xml
index dad985e886..d6ec09f113 100644
--- a/modules/gltf/doc_classes/GLTFSkeleton.xml
+++ b/modules/gltf/doc_classes/GLTFSkeleton.xml
@@ -9,7 +9,7 @@
<methods>
<method name="get_bone_attachment">
<return type="BoneAttachment3D" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
</description>
</method>
@@ -29,19 +29,19 @@
</description>
</method>
<method name="get_unique_names">
- <return type="Array" />
+ <return type="String[]" />
<description>
</description>
</method>
<method name="set_godot_bone_node">
<return type="void" />
- <argument index="0" name="godot_bone_node" type="Dictionary" />
+ <param index="0" name="godot_bone_node" type="Dictionary" />
<description>
</description>
</method>
<method name="set_unique_names">
<return type="void" />
- <argument index="0" name="unique_names" type="Array" />
+ <param index="0" name="unique_names" type="String[]" />
<description>
</description>
</method>
diff --git a/modules/gltf/doc_classes/GLTFSkin.xml b/modules/gltf/doc_classes/GLTFSkin.xml
index b6a2bdb957..4de32857b5 100644
--- a/modules/gltf/doc_classes/GLTFSkin.xml
+++ b/modules/gltf/doc_classes/GLTFSkin.xml
@@ -8,7 +8,7 @@
</tutorials>
<methods>
<method name="get_inverse_binds">
- <return type="Array" />
+ <return type="Transform3D[]" />
<description>
</description>
</method>
@@ -24,19 +24,19 @@
</method>
<method name="set_inverse_binds">
<return type="void" />
- <argument index="0" name="inverse_binds" type="Array" />
+ <param index="0" name="inverse_binds" type="Transform3D[]" />
<description>
</description>
</method>
<method name="set_joint_i_to_bone_i">
<return type="void" />
- <argument index="0" name="joint_i_to_bone_i" type="Dictionary" />
+ <param index="0" name="joint_i_to_bone_i" type="Dictionary" />
<description>
</description>
</method>
<method name="set_joint_i_to_name">
<return type="void" />
- <argument index="0" name="joint_i_to_name" type="Dictionary" />
+ <param index="0" name="joint_i_to_name" type="Dictionary" />
<description>
</description>
</method>
diff --git a/modules/gltf/doc_classes/GLTFSpecGloss.xml b/modules/gltf/doc_classes/GLTFSpecGloss.xml
index 8433cf8dd7..8882e48257 100644
--- a/modules/gltf/doc_classes/GLTFSpecGloss.xml
+++ b/modules/gltf/doc_classes/GLTFSpecGloss.xml
@@ -1,21 +1,29 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GLTFSpecGloss" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
+ Archived GLTF extension for specular/glossy materials.
</brief_description>
<description>
+ KHR_materials_pbrSpecularGlossiness is an archived GLTF extension. This means that it is deprecated and not recommended for new files. However, it is still supported for loading old files.
</description>
<tutorials>
+ <link title="KHR_materials_pbrSpecularGlossiness GLTF extension spec">https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Archived/KHR_materials_pbrSpecularGlossiness</link>
</tutorials>
<members>
<member name="diffuse_factor" type="Color" setter="set_diffuse_factor" getter="get_diffuse_factor" default="Color(1, 1, 1, 1)">
+ The reflected diffuse factor of the material.
</member>
<member name="diffuse_img" type="Image" setter="set_diffuse_img" getter="get_diffuse_img">
+ The diffuse texture.
</member>
<member name="gloss_factor" type="float" setter="set_gloss_factor" getter="get_gloss_factor" default="1.0">
+ The glossiness or smoothness of the material.
</member>
<member name="spec_gloss_img" type="Image" setter="set_spec_gloss_img" getter="get_spec_gloss_img">
+ The specular-glossiness texture.
</member>
<member name="specular_factor" type="Color" setter="set_specular_factor" getter="get_specular_factor" default="Color(1, 1, 1, 1)">
+ The specular RGB color of the material. The alpha channel is unused.
</member>
</members>
</class>
diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml
index 44a1723563..1dbd89aed8 100644
--- a/modules/gltf/doc_classes/GLTFState.xml
+++ b/modules/gltf/doc_classes/GLTFState.xml
@@ -8,65 +8,65 @@
</tutorials>
<methods>
<method name="get_accessors">
- <return type="Array" />
+ <return type="GLTFAccessor[]" />
<description>
</description>
</method>
<method name="get_animation_player">
<return type="AnimationPlayer" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
</description>
</method>
<method name="get_animation_players_count">
<return type="int" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
</description>
</method>
<method name="get_animations">
- <return type="Array" />
+ <return type="GLTFAnimation[]" />
<description>
</description>
</method>
<method name="get_buffer_views">
- <return type="Array" />
+ <return type="GLTFBufferView[]" />
<description>
</description>
</method>
<method name="get_cameras">
- <return type="Array" />
+ <return type="GLTFCamera[]" />
<description>
</description>
</method>
<method name="get_images">
- <return type="Array" />
+ <return type="Texture2D[]" />
<description>
</description>
</method>
<method name="get_lights">
- <return type="Array" />
+ <return type="GLTFLight[]" />
<description>
</description>
</method>
<method name="get_materials">
- <return type="Array" />
+ <return type="BaseMaterial3D[]" />
<description>
</description>
</method>
<method name="get_meshes">
- <return type="Array" />
+ <return type="GLTFMesh[]" />
<description>
</description>
</method>
<method name="get_nodes">
- <return type="Array" />
+ <return type="GLTFNode[]" />
<description>
</description>
</method>
<method name="get_scene_node">
<return type="Node" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
</description>
</method>
@@ -76,117 +76,117 @@
</description>
</method>
<method name="get_skeletons">
- <return type="Array" />
+ <return type="GLTFSkeleton[]" />
<description>
</description>
</method>
<method name="get_skins">
- <return type="Array" />
+ <return type="GLTFSkin[]" />
<description>
</description>
</method>
<method name="get_textures">
- <return type="Array" />
+ <return type="GLTFTexture[]" />
<description>
</description>
</method>
<method name="get_unique_animation_names">
- <return type="Array" />
+ <return type="String[]" />
<description>
</description>
</method>
<method name="get_unique_names">
- <return type="Array" />
+ <return type="String[]" />
<description>
</description>
</method>
<method name="set_accessors">
<return type="void" />
- <argument index="0" name="accessors" type="Array" />
+ <param index="0" name="accessors" type="GLTFAccessor[]" />
<description>
</description>
</method>
<method name="set_animations">
<return type="void" />
- <argument index="0" name="animations" type="Array" />
+ <param index="0" name="animations" type="GLTFAnimation[]" />
<description>
</description>
</method>
<method name="set_buffer_views">
<return type="void" />
- <argument index="0" name="buffer_views" type="Array" />
+ <param index="0" name="buffer_views" type="GLTFBufferView[]" />
<description>
</description>
</method>
<method name="set_cameras">
<return type="void" />
- <argument index="0" name="cameras" type="Array" />
+ <param index="0" name="cameras" type="GLTFCamera[]" />
<description>
</description>
</method>
<method name="set_images">
<return type="void" />
- <argument index="0" name="images" type="Array" />
+ <param index="0" name="images" type="Texture2D[]" />
<description>
</description>
</method>
<method name="set_lights">
<return type="void" />
- <argument index="0" name="lights" type="Array" />
+ <param index="0" name="lights" type="GLTFLight[]" />
<description>
</description>
</method>
<method name="set_materials">
<return type="void" />
- <argument index="0" name="materials" type="Array" />
+ <param index="0" name="materials" type="BaseMaterial3D[]" />
<description>
</description>
</method>
<method name="set_meshes">
<return type="void" />
- <argument index="0" name="meshes" type="Array" />
+ <param index="0" name="meshes" type="GLTFMesh[]" />
<description>
</description>
</method>
<method name="set_nodes">
<return type="void" />
- <argument index="0" name="nodes" type="Array" />
+ <param index="0" name="nodes" type="GLTFNode[]" />
<description>
</description>
</method>
<method name="set_skeleton_to_node">
<return type="void" />
- <argument index="0" name="skeleton_to_node" type="Dictionary" />
+ <param index="0" name="skeleton_to_node" type="Dictionary" />
<description>
</description>
</method>
<method name="set_skeletons">
<return type="void" />
- <argument index="0" name="skeletons" type="Array" />
+ <param index="0" name="skeletons" type="GLTFSkeleton[]" />
<description>
</description>
</method>
<method name="set_skins">
<return type="void" />
- <argument index="0" name="skins" type="Array" />
+ <param index="0" name="skins" type="GLTFSkin[]" />
<description>
</description>
</method>
<method name="set_textures">
<return type="void" />
- <argument index="0" name="textures" type="Array" />
+ <param index="0" name="textures" type="GLTFTexture[]" />
<description>
</description>
</method>
<method name="set_unique_animation_names">
<return type="void" />
- <argument index="0" name="unique_animation_names" type="Array" />
+ <param index="0" name="unique_animation_names" type="String[]" />
<description>
</description>
</method>
<method name="set_unique_names">
<return type="void" />
- <argument index="0" name="unique_names" type="Array" />
+ <param index="0" name="unique_names" type="String[]" />
<description>
</description>
</method>
@@ -194,7 +194,9 @@
<members>
<member name="base_path" type="String" setter="set_base_path" getter="get_base_path" default="&quot;&quot;">
</member>
- <member name="buffers" type="Array" setter="set_buffers" getter="get_buffers" default="[]">
+ <member name="buffers" type="PackedByteArray[]" setter="set_buffers" getter="get_buffers" default="[]">
+ </member>
+ <member name="create_animations" type="bool" setter="set_create_animations" getter="get_create_animations" default="true">
</member>
<member name="glb_data" type="PackedByteArray" setter="set_glb_data" getter="get_glb_data" default="PackedByteArray()">
</member>
@@ -204,7 +206,7 @@
</member>
<member name="minor_version" type="int" setter="set_minor_version" getter="get_minor_version" default="0">
</member>
- <member name="root_nodes" type="Array" setter="set_root_nodes" getter="get_root_nodes" default="[]">
+ <member name="root_nodes" type="PackedInt32Array" setter="set_root_nodes" getter="get_root_nodes" default="PackedInt32Array()">
</member>
<member name="scene_name" type="String" setter="set_scene_name" getter="get_scene_name" default="&quot;&quot;">
</member>
diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp
index 8002c185c7..ab52761e17 100644
--- a/modules/gltf/editor/editor_scene_importer_blend.cpp
+++ b/modules/gltf/editor/editor_scene_importer_blend.cpp
@@ -64,7 +64,7 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
// Escape paths to be valid Python strings to embed in the script.
const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path).c_escape();
- const String sink = ProjectSettings::get_singleton()->get_imported_files_path().plus_file(
+ const String sink = ProjectSettings::get_singleton()->get_imported_files_path().path_join(
vformat("%s-%s.gltf", p_path.get_file().get_basename(), p_path.md5_text()));
const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink).c_escape();
@@ -193,9 +193,9 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
String blender_path = EDITOR_GET("filesystem/import/blender/blender3_path");
#ifdef WINDOWS_ENABLED
- blender_path = blender_path.plus_file("blender.exe");
+ blender_path = blender_path.path_join("blender.exe");
#else
- blender_path = blender_path.plus_file("blender");
+ blender_path = blender_path.path_join("blender");
#endif
List<String> args;
@@ -287,14 +287,14 @@ void EditorSceneFormatImporterBlend::get_import_options(const String &p_path, Li
static bool _test_blender_path(const String &p_path, String *r_err = nullptr) {
String path = p_path;
#ifdef WINDOWS_ENABLED
- path = path.plus_file("blender.exe");
+ path = path.path_join("blender.exe");
#else
- path = path.plus_file("blender");
+ path = path.path_join("blender");
#endif
#if defined(MACOS_ENABLED)
if (!FileAccess::exists(path)) {
- path = path.plus_file("Blender");
+ path = path.path_join("Blender");
}
#endif
@@ -451,7 +451,7 @@ bool EditorFileSystemImportFormatSupportQueryBlend::query() {
configure_blender_dialog->set_ok_button_text(TTR("Confirm Path"));
configure_blender_dialog->set_cancel_button_text(TTR("Disable '.blend' Import"));
- configure_blender_dialog->get_cancel_button()->set_tooltip(TTR("Disables Blender '.blend' files import for this project. Can be re-enabled in Project Settings."));
+ configure_blender_dialog->get_cancel_button()->set_tooltip_text(TTR("Disables Blender '.blend' files import for this project. Can be re-enabled in Project Settings."));
configure_blender_dialog->connect("confirmed", callable_mp(this, &EditorFileSystemImportFormatSupportQueryBlend::_path_confirmed));
browse_dialog = memnew(EditorFileDialog);
@@ -485,7 +485,7 @@ bool EditorFileSystemImportFormatSupportQueryBlend::query() {
bool found = false;
for (const String &path : mdfind_paths) {
- found = _autodetect_path(path.plus_file("Contents/MacOS"));
+ found = _autodetect_path(path.path_join("Contents/MacOS"));
if (found) {
break;
}
diff --git a/modules/gltf/editor/editor_scene_importer_fbx.cpp b/modules/gltf/editor/editor_scene_importer_fbx.cpp
index faad2d315d..017a44cccf 100644
--- a/modules/gltf/editor/editor_scene_importer_fbx.cpp
+++ b/modules/gltf/editor/editor_scene_importer_fbx.cpp
@@ -57,7 +57,7 @@ Node *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t
// enclosed in double quotes by OS::execute(), so we only need to escape those.
// `c_escape_multiline()` seems to do this (escapes `\` and `"` only).
const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path).c_escape_multiline();
- const String sink = ProjectSettings::get_singleton()->get_imported_files_path().plus_file(
+ const String sink = ProjectSettings::get_singleton()->get_imported_files_path().path_join(
vformat("%s-%s.glb", p_path.get_file().get_basename(), p_path.md5_text()));
const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink).c_escape_multiline();
diff --git a/modules/gltf/editor/editor_scene_importer_gltf.cpp b/modules/gltf/editor/editor_scene_importer_gltf.cpp
index 3fadec5167..161808aade 100644
--- a/modules/gltf/editor/editor_scene_importer_gltf.cpp
+++ b/modules/gltf/editor/editor_scene_importer_gltf.cpp
@@ -60,6 +60,9 @@ Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t
}
return nullptr;
}
+ if (p_options.has("animation/import")) {
+ state->set_create_animations(bool(p_options["animation/import"]));
+ }
return doc->generate_scene(state, p_bake_fps);
}
diff --git a/modules/gltf/extensions/gltf_light.cpp b/modules/gltf/extensions/gltf_light.cpp
index af21a4e804..ab5a15c671 100644
--- a/modules/gltf/extensions/gltf_light.cpp
+++ b/modules/gltf/extensions/gltf_light.cpp
@@ -31,6 +31,12 @@
#include "gltf_light.h"
void GLTFLight::_bind_methods() {
+ ClassDB::bind_static_method("GLTFLight", D_METHOD("from_node", "light_node"), &GLTFLight::from_node);
+ ClassDB::bind_method(D_METHOD("to_node"), &GLTFLight::to_node);
+
+ ClassDB::bind_static_method("GLTFLight", D_METHOD("from_dictionary", "dictionary"), &GLTFLight::from_dictionary);
+ ClassDB::bind_method(D_METHOD("to_dictionary"), &GLTFLight::to_dictionary);
+
ClassDB::bind_method(D_METHOD("get_color"), &GLTFLight::get_color);
ClassDB::bind_method(D_METHOD("set_color", "color"), &GLTFLight::set_color);
ClassDB::bind_method(D_METHOD("get_intensity"), &GLTFLight::get_intensity);
@@ -99,3 +105,116 @@ float GLTFLight::get_outer_cone_angle() {
void GLTFLight::set_outer_cone_angle(float p_outer_cone_angle) {
outer_cone_angle = p_outer_cone_angle;
}
+
+Ref<GLTFLight> GLTFLight::from_node(const Light3D *p_light) {
+ Ref<GLTFLight> l;
+ l.instantiate();
+ l->color = p_light->get_color();
+ if (cast_to<DirectionalLight3D>(p_light)) {
+ l->light_type = "directional";
+ const DirectionalLight3D *light = cast_to<const DirectionalLight3D>(p_light);
+ l->intensity = light->get_param(DirectionalLight3D::PARAM_ENERGY);
+ l->range = FLT_MAX; // Range for directional lights is infinite in Godot.
+ } else if (cast_to<const OmniLight3D>(p_light)) {
+ l->light_type = "point";
+ const OmniLight3D *light = cast_to<const OmniLight3D>(p_light);
+ l->range = light->get_param(OmniLight3D::PARAM_RANGE);
+ l->intensity = light->get_param(OmniLight3D::PARAM_ENERGY);
+ } else if (cast_to<const SpotLight3D>(p_light)) {
+ l->light_type = "spot";
+ const SpotLight3D *light = cast_to<const SpotLight3D>(p_light);
+ l->range = light->get_param(SpotLight3D::PARAM_RANGE);
+ l->intensity = light->get_param(SpotLight3D::PARAM_ENERGY);
+ l->outer_cone_angle = Math::deg_to_rad(light->get_param(SpotLight3D::PARAM_SPOT_ANGLE));
+ // This equation is the inverse of the import equation (which has a desmos link).
+ float angle_ratio = 1 - (0.2 / (0.1 + light->get_param(SpotLight3D::PARAM_SPOT_ATTENUATION)));
+ angle_ratio = MAX(0, angle_ratio);
+ l->inner_cone_angle = l->outer_cone_angle * angle_ratio;
+ }
+ return l;
+}
+
+Light3D *GLTFLight::to_node() const {
+ if (light_type == "directional") {
+ DirectionalLight3D *light = memnew(DirectionalLight3D);
+ light->set_param(Light3D::PARAM_ENERGY, intensity);
+ light->set_color(color);
+ return light;
+ }
+ const float range = CLAMP(this->range, 0, 4096);
+ if (light_type == "point") {
+ OmniLight3D *light = memnew(OmniLight3D);
+ light->set_param(OmniLight3D::PARAM_ENERGY, intensity);
+ light->set_param(OmniLight3D::PARAM_RANGE, range);
+ light->set_color(color);
+ return light;
+ }
+ if (light_type == "spot") {
+ SpotLight3D *light = memnew(SpotLight3D);
+ light->set_param(SpotLight3D::PARAM_ENERGY, intensity);
+ light->set_param(SpotLight3D::PARAM_RANGE, range);
+ light->set_param(SpotLight3D::PARAM_SPOT_ANGLE, Math::rad_to_deg(outer_cone_angle));
+ light->set_color(color);
+ // Line of best fit derived from guessing, see https://www.desmos.com/calculator/biiflubp8b
+ // The points in desmos are not exact, except for (1, infinity).
+ float angle_ratio = inner_cone_angle / outer_cone_angle;
+ float angle_attenuation = 0.2 / (1 - angle_ratio) - 0.1;
+ light->set_param(SpotLight3D::PARAM_SPOT_ATTENUATION, angle_attenuation);
+ return light;
+ }
+ return memnew(Light3D);
+}
+
+Ref<GLTFLight> GLTFLight::from_dictionary(const Dictionary p_dictionary) {
+ ERR_FAIL_COND_V_MSG(!p_dictionary.has("type"), Ref<GLTFLight>(), "Failed to parse GLTF light, missing required field 'type'.");
+ Ref<GLTFLight> light;
+ light.instantiate();
+ const String &type = p_dictionary["type"];
+ light->light_type = type;
+
+ if (p_dictionary.has("color")) {
+ const Array &arr = p_dictionary["color"];
+ if (arr.size() == 3) {
+ light->color = Color(arr[0], arr[1], arr[2]).linear_to_srgb();
+ } else {
+ ERR_PRINT("Error parsing GLTF light: The color must have exactly 3 numbers.");
+ }
+ }
+ if (p_dictionary.has("intensity")) {
+ light->intensity = p_dictionary["intensity"];
+ }
+ if (p_dictionary.has("range")) {
+ light->range = p_dictionary["range"];
+ }
+ if (type == "spot") {
+ const Dictionary &spot = p_dictionary["spot"];
+ light->inner_cone_angle = spot["innerConeAngle"];
+ light->outer_cone_angle = spot["outerConeAngle"];
+ if (light->inner_cone_angle >= light->outer_cone_angle) {
+ ERR_PRINT("Error parsing GLTF light: The inner angle must be smaller than the outer angle.");
+ }
+ } else if (type != "point" && type != "directional") {
+ ERR_PRINT("Error parsing GLTF light: Light type '" + type + "' is unknown.");
+ }
+ return light;
+}
+
+Dictionary GLTFLight::to_dictionary() const {
+ Dictionary d;
+ Array color_array;
+ color_array.resize(3);
+ color_array[0] = color.r;
+ color_array[1] = color.g;
+ color_array[2] = color.b;
+ d["color"] = color_array;
+ d["type"] = light_type;
+ if (light_type == "spot") {
+ Dictionary spot_dict;
+ spot_dict["innerConeAngle"] = inner_cone_angle;
+ spot_dict["outerConeAngle"] = outer_cone_angle;
+ d["spot"] = spot_dict;
+ }
+ d["intensity"] = intensity;
+ d["range"] = range;
+ return d;
+}
diff --git a/modules/gltf/extensions/gltf_light.h b/modules/gltf/extensions/gltf_light.h
index 58fa299dfd..04980e144c 100644
--- a/modules/gltf/extensions/gltf_light.h
+++ b/modules/gltf/extensions/gltf_light.h
@@ -35,6 +35,8 @@
#include "core/io/resource.h"
#include "scene/3d/light_3d.h"
+// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_lights_punctual
+
class GLTFLight : public Resource {
GDCLASS(GLTFLight, Resource)
friend class GLTFDocument;
@@ -68,6 +70,12 @@ public:
float get_outer_cone_angle();
void set_outer_cone_angle(float p_outer_cone_angle);
+
+ static Ref<GLTFLight> from_node(const Light3D *p_light);
+ Light3D *to_node() const;
+
+ static Ref<GLTFLight> from_dictionary(const Dictionary p_dictionary);
+ Dictionary to_dictionary() const;
};
#endif // GLTF_LIGHT_H
diff --git a/modules/gltf/extensions/gltf_spec_gloss.h b/modules/gltf/extensions/gltf_spec_gloss.h
index a45fa4296c..2b4d3ee609 100644
--- a/modules/gltf/extensions/gltf_spec_gloss.h
+++ b/modules/gltf/extensions/gltf_spec_gloss.h
@@ -34,6 +34,11 @@
#include "core/io/image.h"
#include "core/io/resource.h"
+// KHR_materials_pbrSpecularGlossiness is an archived GLTF extension.
+// This means that it is deprecated and not recommended for new files.
+// However, it is still supported for loading old files.
+// https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Archived/KHR_materials_pbrSpecularGlossiness
+
class GLTFSpecGloss : public Resource {
GDCLASS(GLTFSpecGloss, Resource);
friend class GLTFDocument;
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 7e90f198f6..0ed212e21f 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -50,7 +50,6 @@
#include "core/version.h"
#include "drivers/png/png_driver_common.h"
#include "scene/2d/node_2d.h"
-#include "scene/3d/camera_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/multimesh_instance_3d.h"
#include "scene/3d/node_3d.h"
@@ -787,7 +786,7 @@ Error GLTFDocument::_parse_buffers(Ref<GLTFState> state, const String &p_base_pa
} else { // Relative path to an external image file.
ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER);
uri = uri.uri_decode();
- uri = p_base_path.plus_file(uri).replace("\\", "/"); // Fix for Windows.
+ uri = p_base_path.path_join(uri).replace("\\", "/"); // Fix for Windows.
buffer_data = FileAccess::get_file_as_array(uri);
ERR_FAIL_COND_V_MSG(buffer.size() == 0, ERR_PARSE_ERROR, "glTF: Couldn't load binary file as an array: " + uri);
}
@@ -3040,8 +3039,8 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path
if (!da->dir_exists(new_texture_dir)) {
da->make_dir(new_texture_dir);
}
- image->save_png(new_texture_dir.plus_file(name));
- d["uri"] = texture_dir.plus_file(name).uri_encode();
+ image->save_png(new_texture_dir.path_join(name));
+ d["uri"] = texture_dir.path_join(name).uri_encode();
}
images.push_back(d);
}
@@ -3119,7 +3118,7 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat
} else { // Relative path to an external image file.
ERR_FAIL_COND_V(p_base_path.is_empty(), ERR_INVALID_PARAMETER);
uri = uri.uri_decode();
- uri = p_base_path.plus_file(uri).replace("\\", "/"); // Fix for Windows.
+ uri = p_base_path.path_join(uri).replace("\\", "/"); // Fix for Windows.
// ResourceLoader will rely on the file extension to use the relevant loader.
// The spec says that if mimeType is defined, it should take precedence (e.g.
// there could be a `.png` image which is actually JPEG), but there's no easy
@@ -4535,28 +4534,7 @@ Error GLTFDocument::_serialize_lights(Ref<GLTFState> state) {
}
Array lights;
for (GLTFLightIndex i = 0; i < state->lights.size(); i++) {
- Dictionary d;
- Ref<GLTFLight> light = state->lights[i];
- Array color;
- color.resize(3);
- color[0] = light->color.r;
- color[1] = light->color.g;
- color[2] = light->color.b;
- d["color"] = color;
- d["type"] = light->light_type;
- if (light->light_type == "spot") {
- Dictionary s;
- float inner_cone_angle = light->inner_cone_angle;
- s["innerConeAngle"] = inner_cone_angle;
- float outer_cone_angle = light->outer_cone_angle;
- s["outerConeAngle"] = outer_cone_angle;
- d["spot"] = s;
- }
- float intensity = light->intensity;
- d["intensity"] = intensity;
- float range = light->range;
- d["range"] = range;
- lights.push_back(d);
+ lights.push_back(state->lights[i]->to_dictionary());
}
Dictionary extensions;
@@ -4578,28 +4556,7 @@ Error GLTFDocument::_serialize_cameras(Ref<GLTFState> state) {
Array cameras;
cameras.resize(state->cameras.size());
for (GLTFCameraIndex i = 0; i < state->cameras.size(); i++) {
- Dictionary d;
-
- Ref<GLTFCamera> camera = state->cameras[i];
-
- if (camera->get_perspective() == false) {
- Dictionary og;
- og["ymag"] = Math::deg2rad(camera->get_fov_size());
- og["xmag"] = Math::deg2rad(camera->get_fov_size());
- og["zfar"] = camera->get_depth_far();
- og["znear"] = camera->get_depth_near();
- d["orthographic"] = og;
- d["type"] = "orthographic";
- } else if (camera->get_perspective()) {
- Dictionary ppt;
- // GLTF spec is in radians, Godot's camera is in degrees.
- ppt["yfov"] = Math::deg2rad(camera->get_fov_size());
- ppt["zfar"] = camera->get_depth_far();
- ppt["znear"] = camera->get_depth_near();
- d["perspective"] = ppt;
- d["type"] = "perspective";
- }
- cameras[i] = d;
+ cameras[i] = state->cameras[i]->to_dictionary();
}
if (!state->cameras.size()) {
@@ -4629,35 +4586,10 @@ Error GLTFDocument::_parse_lights(Ref<GLTFState> state) {
const Array &lights = lights_punctual["lights"];
for (GLTFLightIndex light_i = 0; light_i < lights.size(); light_i++) {
- const Dictionary &d = lights[light_i];
-
- Ref<GLTFLight> light;
- light.instantiate();
- ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR);
- const String &type = d["type"];
- light->light_type = type;
-
- if (d.has("color")) {
- const Array &arr = d["color"];
- ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR);
- const Color c = Color(arr[0], arr[1], arr[2]).linear_to_srgb();
- light->color = c;
- }
- if (d.has("intensity")) {
- light->intensity = d["intensity"];
- }
- if (d.has("range")) {
- light->range = d["range"];
+ Ref<GLTFLight> light = GLTFLight::from_dictionary(lights[light_i]);
+ if (light.is_null()) {
+ return Error::ERR_PARSE_ERROR;
}
- if (type == "spot") {
- const Dictionary &spot = d["spot"];
- light->inner_cone_angle = spot["innerConeAngle"];
- light->outer_cone_angle = spot["outerConeAngle"];
- ERR_CONTINUE_MSG(light->inner_cone_angle >= light->outer_cone_angle, "The inner angle must be smaller than the outer angle.");
- } else if (type != "point" && type != "directional") {
- ERR_CONTINUE_MSG(true, "Light type is unknown.");
- }
-
state->lights.push_back(light);
}
@@ -4674,39 +4606,7 @@ Error GLTFDocument::_parse_cameras(Ref<GLTFState> state) {
const Array cameras = state->json["cameras"];
for (GLTFCameraIndex i = 0; i < cameras.size(); i++) {
- const Dictionary &d = cameras[i];
-
- Ref<GLTFCamera> camera;
- camera.instantiate();
- ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR);
- const String &type = d["type"];
- if (type == "orthographic") {
- camera->set_perspective(false);
- if (d.has("orthographic")) {
- const Dictionary &og = d["orthographic"];
- // GLTF spec is in radians, Godot's camera is in degrees.
- camera->set_fov_size(Math::rad2deg(real_t(og["ymag"])));
- camera->set_depth_far(og["zfar"]);
- camera->set_depth_near(og["znear"]);
- } else {
- camera->set_fov_size(10);
- }
- } else if (type == "perspective") {
- camera->set_perspective(true);
- if (d.has("perspective")) {
- const Dictionary &ppt = d["perspective"];
- // GLTF spec is in radians, Godot's camera is in degrees.
- camera->set_fov_size(Math::rad2deg(real_t(ppt["yfov"])));
- camera->set_depth_far(ppt["zfar"]);
- camera->set_depth_near(ppt["znear"]);
- } else {
- camera->set_fov_size(10);
- }
- } else {
- ERR_FAIL_V_MSG(ERR_PARSE_ERROR, "Camera3D should be in 'orthographic' or 'perspective'");
- }
-
- state->cameras.push_back(camera);
+ state->cameras.push_back(GLTFCamera::from_dictionary(cameras[i]));
}
print_verbose("glTF: Total cameras: " + itos(state->cameras.size()));
@@ -5154,45 +5054,7 @@ Node3D *GLTFDocument::_generate_light(Ref<GLTFState> state, const GLTFNodeIndex
print_verbose("glTF: Creating light for: " + gltf_node->get_name());
Ref<GLTFLight> l = state->lights[gltf_node->light];
-
- float intensity = l->intensity;
- if (intensity > 10) {
- // GLTF spec has the default around 1, but Blender defaults lights to 100.
- // The only sane way to handle this is to check where it came from and
- // handle it accordingly. If it's over 10, it probably came from Blender.
- intensity /= 100;
- }
-
- if (l->light_type == "directional") {
- DirectionalLight3D *light = memnew(DirectionalLight3D);
- light->set_param(Light3D::PARAM_ENERGY, intensity);
- light->set_color(l->color);
- return light;
- }
-
- const float range = CLAMP(l->range, 0, 4096);
- if (l->light_type == "point") {
- OmniLight3D *light = memnew(OmniLight3D);
- light->set_param(OmniLight3D::PARAM_ENERGY, intensity);
- light->set_param(OmniLight3D::PARAM_RANGE, range);
- light->set_color(l->color);
- return light;
- }
- if (l->light_type == "spot") {
- SpotLight3D *light = memnew(SpotLight3D);
- light->set_param(SpotLight3D::PARAM_ENERGY, intensity);
- light->set_param(SpotLight3D::PARAM_RANGE, range);
- light->set_param(SpotLight3D::PARAM_SPOT_ANGLE, Math::rad2deg(l->outer_cone_angle));
- light->set_color(l->color);
-
- // Line of best fit derived from guessing, see https://www.desmos.com/calculator/biiflubp8b
- // The points in desmos are not exact, except for (1, infinity).
- float angle_ratio = l->inner_cone_angle / l->outer_cone_angle;
- float angle_attenuation = 0.2 / (1 - angle_ratio) - 0.1;
- light->set_param(SpotLight3D::PARAM_SPOT_ATTENUATION, angle_attenuation);
- return light;
- }
- return memnew(Node3D);
+ return l->to_node();
}
Camera3D *GLTFDocument::_generate_camera(Ref<GLTFState> state, const GLTFNodeIndex node_index) {
@@ -5200,31 +5062,16 @@ Camera3D *GLTFDocument::_generate_camera(Ref<GLTFState> state, const GLTFNodeInd
ERR_FAIL_INDEX_V(gltf_node->camera, state->cameras.size(), nullptr);
- Camera3D *camera = memnew(Camera3D);
print_verbose("glTF: Creating camera for: " + gltf_node->get_name());
Ref<GLTFCamera> c = state->cameras[gltf_node->camera];
- if (c->get_perspective()) {
- camera->set_perspective(c->get_fov_size(), c->get_depth_near(), c->get_depth_far());
- } else {
- camera->set_orthogonal(c->get_fov_size(), c->get_depth_near(), c->get_depth_far());
- }
-
- return camera;
+ return c->to_node();
}
GLTFCameraIndex GLTFDocument::_convert_camera(Ref<GLTFState> state, Camera3D *p_camera) {
print_verbose("glTF: Converting camera: " + p_camera->get_name());
- Ref<GLTFCamera> c;
- c.instantiate();
-
- if (p_camera->get_projection() == Camera3D::ProjectionType::PROJECTION_PERSPECTIVE) {
- c->set_perspective(true);
- }
- c->set_fov_size(p_camera->get_fov());
- c->set_depth_far(p_camera->get_far());
- c->set_depth_near(p_camera->get_near());
+ Ref<GLTFCamera> c = GLTFCamera::from_node(p_camera);
GLTFCameraIndex camera_index = state->cameras.size();
state->cameras.push_back(c);
return camera_index;
@@ -5233,31 +5080,7 @@ GLTFCameraIndex GLTFDocument::_convert_camera(Ref<GLTFState> state, Camera3D *p_
GLTFLightIndex GLTFDocument::_convert_light(Ref<GLTFState> state, Light3D *p_light) {
print_verbose("glTF: Converting light: " + p_light->get_name());
- Ref<GLTFLight> l;
- l.instantiate();
- l->color = p_light->get_color();
- if (cast_to<DirectionalLight3D>(p_light)) {
- l->light_type = "directional";
- DirectionalLight3D *light = cast_to<DirectionalLight3D>(p_light);
- l->intensity = light->get_param(DirectionalLight3D::PARAM_ENERGY);
- l->range = FLT_MAX; // Range for directional lights is infinite in Godot.
- } else if (cast_to<OmniLight3D>(p_light)) {
- l->light_type = "point";
- OmniLight3D *light = cast_to<OmniLight3D>(p_light);
- l->range = light->get_param(OmniLight3D::PARAM_RANGE);
- l->intensity = light->get_param(OmniLight3D::PARAM_ENERGY);
- } else if (cast_to<SpotLight3D>(p_light)) {
- l->light_type = "spot";
- SpotLight3D *light = cast_to<SpotLight3D>(p_light);
- l->range = light->get_param(SpotLight3D::PARAM_RANGE);
- l->intensity = light->get_param(SpotLight3D::PARAM_ENERGY);
- l->outer_cone_angle = Math::deg2rad(light->get_param(SpotLight3D::PARAM_SPOT_ANGLE));
-
- // This equation is the inverse of the import equation (which has a desmos link).
- float angle_ratio = 1 - (0.2 / (0.1 + light->get_param(SpotLight3D::PARAM_SPOT_ATTENUATION)));
- angle_ratio = MAX(0, angle_ratio);
- l->inner_cone_angle = l->outer_cone_angle * angle_ratio;
- }
+ Ref<GLTFLight> l = GLTFLight::from_node(p_light);
GLTFLightIndex light_index = state->lights.size();
state->lights.push_back(l);
@@ -5442,7 +5265,7 @@ void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex
int32_t cell = p_grid_map->get_cell_item(
Vector3(cell_location.x, cell_location.y, cell_location.z));
Transform3D cell_xform;
- cell_xform.basis.set_orthogonal_index(
+ cell_xform.basis = p_grid_map->get_basis_with_orthogonal_index(
p_grid_map->get_cell_item_orientation(
Vector3(cell_location.x, cell_location.y, cell_location.z)));
cell_xform.basis.scale(Vector3(p_grid_map->get_cell_scale(),
@@ -6899,7 +6722,7 @@ Node *GLTFDocument::generate_scene(Ref<GLTFState> state, int32_t p_bake_fps) {
Node *root = gltf_root_node->get_parent();
ERR_FAIL_NULL_V(root, nullptr);
_process_mesh_instances(state, root);
- if (state->animations.size()) {
+ if (state->get_create_animations() && state->animations.size()) {
AnimationPlayer *ap = memnew(AnimationPlayer);
root->add_child(ap, true);
ap->set_owner(root);
diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp
index a5f7bcf9d6..85bac446cc 100644
--- a/modules/gltf/gltf_state.cpp
+++ b/modules/gltf/gltf_state.cpp
@@ -79,6 +79,8 @@ void GLTFState::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_skeletons", "skeletons"), &GLTFState::set_skeletons);
ClassDB::bind_method(D_METHOD("get_skeleton_to_node"), &GLTFState::get_skeleton_to_node);
ClassDB::bind_method(D_METHOD("set_skeleton_to_node", "skeleton_to_node"), &GLTFState::set_skeleton_to_node);
+ ClassDB::bind_method(D_METHOD("get_create_animations"), &GLTFState::get_create_animations);
+ ClassDB::bind_method(D_METHOD("set_create_animations", "create_animations"), &GLTFState::set_create_animations);
ClassDB::bind_method(D_METHOD("get_animations"), &GLTFState::get_animations);
ClassDB::bind_method(D_METHOD("set_animations", "animations"), &GLTFState::set_animations);
ClassDB::bind_method(D_METHOD("get_scene_node", "idx"), &GLTFState::get_scene_node);
@@ -106,6 +108,7 @@ void GLTFState::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "unique_animation_names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_unique_animation_names", "get_unique_animation_names"); // Set<String>
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "skeletons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skeletons", "get_skeletons"); // Vector<Ref<GLTFSkeleton>>
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "skeleton_to_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skeleton_to_node", "get_skeleton_to_node"); // RBMap<GLTFSkeletonIndex,
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "create_animations"), "set_create_animations", "get_create_animations"); // bool
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_animations", "get_animations"); // Vector<Ref<GLTFAnimation>>
}
@@ -149,51 +152,51 @@ void GLTFState::set_use_named_skin_binds(bool p_use_named_skin_binds) {
use_named_skin_binds = p_use_named_skin_binds;
}
-Array GLTFState::get_nodes() {
+TypedArray<GLTFNode> GLTFState::get_nodes() {
return GLTFTemplateConvert::to_array(nodes);
}
-void GLTFState::set_nodes(Array p_nodes) {
+void GLTFState::set_nodes(TypedArray<GLTFNode> p_nodes) {
GLTFTemplateConvert::set_from_array(nodes, p_nodes);
}
-Array GLTFState::get_buffers() {
+TypedArray<PackedByteArray> GLTFState::get_buffers() {
return GLTFTemplateConvert::to_array(buffers);
}
-void GLTFState::set_buffers(Array p_buffers) {
+void GLTFState::set_buffers(TypedArray<PackedByteArray> p_buffers) {
GLTFTemplateConvert::set_from_array(buffers, p_buffers);
}
-Array GLTFState::get_buffer_views() {
+TypedArray<GLTFBufferView> GLTFState::get_buffer_views() {
return GLTFTemplateConvert::to_array(buffer_views);
}
-void GLTFState::set_buffer_views(Array p_buffer_views) {
+void GLTFState::set_buffer_views(TypedArray<GLTFBufferView> p_buffer_views) {
GLTFTemplateConvert::set_from_array(buffer_views, p_buffer_views);
}
-Array GLTFState::get_accessors() {
+TypedArray<GLTFAccessor> GLTFState::get_accessors() {
return GLTFTemplateConvert::to_array(accessors);
}
-void GLTFState::set_accessors(Array p_accessors) {
+void GLTFState::set_accessors(TypedArray<GLTFAccessor> p_accessors) {
GLTFTemplateConvert::set_from_array(accessors, p_accessors);
}
-Array GLTFState::get_meshes() {
+TypedArray<GLTFMesh> GLTFState::get_meshes() {
return GLTFTemplateConvert::to_array(meshes);
}
-void GLTFState::set_meshes(Array p_meshes) {
+void GLTFState::set_meshes(TypedArray<GLTFMesh> p_meshes) {
GLTFTemplateConvert::set_from_array(meshes, p_meshes);
}
-Array GLTFState::get_materials() {
+TypedArray<BaseMaterial3D> GLTFState::get_materials() {
return GLTFTemplateConvert::to_array(materials);
}
-void GLTFState::set_materials(Array p_materials) {
+void GLTFState::set_materials(TypedArray<BaseMaterial3D> p_materials) {
GLTFTemplateConvert::set_from_array(materials, p_materials);
}
@@ -205,75 +208,75 @@ void GLTFState::set_scene_name(String p_scene_name) {
scene_name = p_scene_name;
}
-Array GLTFState::get_root_nodes() {
- return GLTFTemplateConvert::to_array(root_nodes);
+PackedInt32Array GLTFState::get_root_nodes() {
+ return root_nodes;
}
-void GLTFState::set_root_nodes(Array p_root_nodes) {
- GLTFTemplateConvert::set_from_array(root_nodes, p_root_nodes);
+void GLTFState::set_root_nodes(PackedInt32Array p_root_nodes) {
+ root_nodes = p_root_nodes;
}
-Array GLTFState::get_textures() {
+TypedArray<GLTFTexture> GLTFState::get_textures() {
return GLTFTemplateConvert::to_array(textures);
}
-void GLTFState::set_textures(Array p_textures) {
+void GLTFState::set_textures(TypedArray<GLTFTexture> p_textures) {
GLTFTemplateConvert::set_from_array(textures, p_textures);
}
-Array GLTFState::get_images() {
+TypedArray<Texture2D> GLTFState::get_images() {
return GLTFTemplateConvert::to_array(images);
}
-void GLTFState::set_images(Array p_images) {
+void GLTFState::set_images(TypedArray<Texture2D> p_images) {
GLTFTemplateConvert::set_from_array(images, p_images);
}
-Array GLTFState::get_skins() {
+TypedArray<GLTFSkin> GLTFState::get_skins() {
return GLTFTemplateConvert::to_array(skins);
}
-void GLTFState::set_skins(Array p_skins) {
+void GLTFState::set_skins(TypedArray<GLTFSkin> p_skins) {
GLTFTemplateConvert::set_from_array(skins, p_skins);
}
-Array GLTFState::get_cameras() {
+TypedArray<GLTFCamera> GLTFState::get_cameras() {
return GLTFTemplateConvert::to_array(cameras);
}
-void GLTFState::set_cameras(Array p_cameras) {
+void GLTFState::set_cameras(TypedArray<GLTFCamera> p_cameras) {
GLTFTemplateConvert::set_from_array(cameras, p_cameras);
}
-Array GLTFState::get_lights() {
+TypedArray<GLTFLight> GLTFState::get_lights() {
return GLTFTemplateConvert::to_array(lights);
}
-void GLTFState::set_lights(Array p_lights) {
+void GLTFState::set_lights(TypedArray<GLTFLight> p_lights) {
GLTFTemplateConvert::set_from_array(lights, p_lights);
}
-Array GLTFState::get_unique_names() {
+TypedArray<String> GLTFState::get_unique_names() {
return GLTFTemplateConvert::to_array(unique_names);
}
-void GLTFState::set_unique_names(Array p_unique_names) {
+void GLTFState::set_unique_names(TypedArray<String> p_unique_names) {
GLTFTemplateConvert::set_from_array(unique_names, p_unique_names);
}
-Array GLTFState::get_unique_animation_names() {
+TypedArray<String> GLTFState::get_unique_animation_names() {
return GLTFTemplateConvert::to_array(unique_animation_names);
}
-void GLTFState::set_unique_animation_names(Array p_unique_animation_names) {
+void GLTFState::set_unique_animation_names(TypedArray<String> p_unique_animation_names) {
GLTFTemplateConvert::set_from_array(unique_animation_names, p_unique_animation_names);
}
-Array GLTFState::get_skeletons() {
+TypedArray<GLTFSkeleton> GLTFState::get_skeletons() {
return GLTFTemplateConvert::to_array(skeletons);
}
-void GLTFState::set_skeletons(Array p_skeletons) {
+void GLTFState::set_skeletons(TypedArray<GLTFSkeleton> p_skeletons) {
GLTFTemplateConvert::set_from_array(skeletons, p_skeletons);
}
@@ -285,11 +288,19 @@ void GLTFState::set_skeleton_to_node(Dictionary p_skeleton_to_node) {
GLTFTemplateConvert::set_from_dict(skeleton_to_node, p_skeleton_to_node);
}
-Array GLTFState::get_animations() {
+bool GLTFState::get_create_animations() {
+ return create_animations;
+}
+
+void GLTFState::set_create_animations(bool p_create_animations) {
+ create_animations = p_create_animations;
+}
+
+TypedArray<GLTFAnimation> GLTFState::get_animations() {
return GLTFTemplateConvert::to_array(animations);
}
-void GLTFState::set_animations(Array p_animations) {
+void GLTFState::set_animations(TypedArray<GLTFAnimation> p_animations) {
GLTFTemplateConvert::set_from_array(animations, p_animations);
}
diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h
index d2a4948f06..6b2d1ca228 100644
--- a/modules/gltf/gltf_state.h
+++ b/modules/gltf/gltf_state.h
@@ -61,6 +61,7 @@ class GLTFState : public Resource {
bool use_named_skin_binds = false;
bool use_khr_texture_transform = false;
bool discard_meshes_and_materials = false;
+ bool create_animations = true;
Vector<Ref<GLTFNode>> nodes;
Vector<Vector<uint8_t>> buffers;
@@ -114,23 +115,23 @@ public:
bool get_discard_meshes_and_materials();
void set_discard_meshes_and_materials(bool p_discard_meshes_and_materials);
- Array get_nodes();
- void set_nodes(Array p_nodes);
+ TypedArray<GLTFNode> get_nodes();
+ void set_nodes(TypedArray<GLTFNode> p_nodes);
- Array get_buffers();
- void set_buffers(Array p_buffers);
+ TypedArray<PackedByteArray> get_buffers();
+ void set_buffers(TypedArray<PackedByteArray> p_buffers);
- Array get_buffer_views();
- void set_buffer_views(Array p_buffer_views);
+ TypedArray<GLTFBufferView> get_buffer_views();
+ void set_buffer_views(TypedArray<GLTFBufferView> p_buffer_views);
- Array get_accessors();
- void set_accessors(Array p_accessors);
+ TypedArray<GLTFAccessor> get_accessors();
+ void set_accessors(TypedArray<GLTFAccessor> p_accessors);
- Array get_meshes();
- void set_meshes(Array p_meshes);
+ TypedArray<GLTFMesh> get_meshes();
+ void set_meshes(TypedArray<GLTFMesh> p_meshes);
- Array get_materials();
- void set_materials(Array p_materials);
+ TypedArray<BaseMaterial3D> get_materials();
+ void set_materials(TypedArray<BaseMaterial3D> p_materials);
String get_scene_name();
void set_scene_name(String p_scene_name);
@@ -138,38 +139,41 @@ public:
String get_base_path();
void set_base_path(String p_base_path);
- Array get_root_nodes();
- void set_root_nodes(Array p_root_nodes);
+ PackedInt32Array get_root_nodes();
+ void set_root_nodes(PackedInt32Array p_root_nodes);
- Array get_textures();
- void set_textures(Array p_textures);
+ TypedArray<GLTFTexture> get_textures();
+ void set_textures(TypedArray<GLTFTexture> p_textures);
- Array get_images();
- void set_images(Array p_images);
+ TypedArray<Texture2D> get_images();
+ void set_images(TypedArray<Texture2D> p_images);
- Array get_skins();
- void set_skins(Array p_skins);
+ TypedArray<GLTFSkin> get_skins();
+ void set_skins(TypedArray<GLTFSkin> p_skins);
- Array get_cameras();
- void set_cameras(Array p_cameras);
+ TypedArray<GLTFCamera> get_cameras();
+ void set_cameras(TypedArray<GLTFCamera> p_cameras);
- Array get_lights();
- void set_lights(Array p_lights);
+ TypedArray<GLTFLight> get_lights();
+ void set_lights(TypedArray<GLTFLight> p_lights);
- Array get_unique_names();
- void set_unique_names(Array p_unique_names);
+ TypedArray<String> get_unique_names();
+ void set_unique_names(TypedArray<String> p_unique_names);
- Array get_unique_animation_names();
- void set_unique_animation_names(Array p_unique_names);
+ TypedArray<String> get_unique_animation_names();
+ void set_unique_animation_names(TypedArray<String> p_unique_names);
- Array get_skeletons();
- void set_skeletons(Array p_skeletons);
+ TypedArray<GLTFSkeleton> get_skeletons();
+ void set_skeletons(TypedArray<GLTFSkeleton> p_skeletons);
Dictionary get_skeleton_to_node();
void set_skeleton_to_node(Dictionary p_skeleton_to_node);
- Array get_animations();
- void set_animations(Array p_animations);
+ bool get_create_animations();
+ void set_create_animations(bool p_create_animations);
+
+ TypedArray<GLTFAnimation> get_animations();
+ void set_animations(TypedArray<GLTFAnimation> p_animations);
Node *get_scene_node(GLTFNodeIndex idx);
diff --git a/modules/gltf/gltf_template_convert.h b/modules/gltf/gltf_template_convert.h
index c915d3deb0..8a4b595c9f 100644
--- a/modules/gltf/gltf_template_convert.h
+++ b/modules/gltf/gltf_template_convert.h
@@ -46,8 +46,8 @@ static Array to_array(const Vector<T> &p_inp) {
}
template <class T>
-static Array to_array(const HashSet<T> &p_inp) {
- Array ret;
+static TypedArray<T> to_array(const HashSet<T> &p_inp) {
+ TypedArray<T> ret;
typename HashSet<T>::Iterator elem = p_inp.begin();
while (elem) {
ret.push_back(*elem);
@@ -65,7 +65,7 @@ static void set_from_array(Vector<T> &r_out, const Array &p_inp) {
}
template <class T>
-static void set_from_array(HashSet<T> &r_out, const Array &p_inp) {
+static void set_from_array(HashSet<T> &r_out, const TypedArray<T> &p_inp) {
r_out.clear();
for (int i = 0; i < p_inp.size(); i++) {
r_out.insert(p_inp[i]);
diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp
index 1e1204aa57..dbbccc9bcc 100644
--- a/modules/gltf/register_types.cpp
+++ b/modules/gltf/register_types.cpp
@@ -66,17 +66,24 @@ static void _editor_init() {
bool blend_enabled = GLOBAL_GET("filesystem/import/blender/enabled");
// Defined here because EditorSettings doesn't exist in `register_gltf_types` yet.
- EDITOR_DEF_RST("filesystem/import/blender/blender3_path", "");
+ String blender3_path = EDITOR_DEF_RST("filesystem/import/blender/blender3_path", "");
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,
"filesystem/import/blender/blender3_path", PROPERTY_HINT_GLOBAL_DIR));
if (blend_enabled) {
- Ref<EditorSceneFormatImporterBlend> importer;
- importer.instantiate();
- ResourceImporterScene::add_importer(importer);
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ if (blender3_path.is_empty()) {
+ WARN_PRINT("Blend file import is enabled in the project settings, but no Blender path is configured in the editor settings. Blend files will not be imported.");
+ } else if (!da->dir_exists(blender3_path)) {
+ WARN_PRINT("Blend file import is enabled, but the Blender path doesn't point to an accessible directory. Blend files will not be imported.");
+ } else {
+ Ref<EditorSceneFormatImporterBlend> importer;
+ importer.instantiate();
+ ResourceImporterScene::add_importer(importer);
- Ref<EditorFileSystemImportFormatSupportQueryBlend> blend_import_query;
- blend_import_query.instantiate();
- EditorFileSystem::get_singleton()->add_import_format_support_query(blend_import_query);
+ Ref<EditorFileSystemImportFormatSupportQueryBlend> blend_import_query;
+ blend_import_query.instantiate();
+ EditorFileSystem::get_singleton()->add_import_format_support_query(blend_import_query);
+ }
}
// FBX to glTF importer.
@@ -89,9 +96,9 @@ static void _editor_init() {
if (fbx_enabled) {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (fbx2gltf_path.is_empty()) {
- WARN_PRINT("FBX file import is enabled, but no FBX2glTF path is configured. FBX files will not be imported.");
+ WARN_PRINT("FBX file import is enabled in the project settings, but no FBX2glTF path is configured in the editor settings. FBX files will not be imported.");
} else if (!da->file_exists(fbx2gltf_path)) {
- WARN_PRINT("FBX file import is enabled, but the FBX2glTF path doesn't point to a valid FBX2glTF executable. FBX files will not be imported.");
+ WARN_PRINT("FBX file import is enabled, but the FBX2glTF path doesn't point to an accessible file. FBX files will not be imported.");
} else {
Ref<EditorSceneFormatImporterFBX> importer;
importer.instantiate();
diff --git a/modules/gltf/structures/gltf_camera.cpp b/modules/gltf/structures/gltf_camera.cpp
index f3ea6a1c4c..5069f39c4b 100644
--- a/modules/gltf/structures/gltf_camera.cpp
+++ b/modules/gltf/structures/gltf_camera.cpp
@@ -31,17 +31,101 @@
#include "gltf_camera.h"
void GLTFCamera::_bind_methods() {
+ ClassDB::bind_static_method("GLTFCamera", D_METHOD("from_node", "camera_node"), &GLTFCamera::from_node);
+ ClassDB::bind_method(D_METHOD("to_node"), &GLTFCamera::to_node);
+
+ ClassDB::bind_static_method("GLTFCamera", D_METHOD("from_dictionary", "dictionary"), &GLTFCamera::from_dictionary);
+ ClassDB::bind_method(D_METHOD("to_dictionary"), &GLTFCamera::to_dictionary);
+
ClassDB::bind_method(D_METHOD("get_perspective"), &GLTFCamera::get_perspective);
ClassDB::bind_method(D_METHOD("set_perspective", "perspective"), &GLTFCamera::set_perspective);
- ClassDB::bind_method(D_METHOD("get_fov_size"), &GLTFCamera::get_fov_size);
- ClassDB::bind_method(D_METHOD("set_fov_size", "fov_size"), &GLTFCamera::set_fov_size);
+ ClassDB::bind_method(D_METHOD("get_fov"), &GLTFCamera::get_fov);
+ ClassDB::bind_method(D_METHOD("set_fov", "fov"), &GLTFCamera::set_fov);
+ ClassDB::bind_method(D_METHOD("get_size_mag"), &GLTFCamera::get_size_mag);
+ ClassDB::bind_method(D_METHOD("set_size_mag", "size_mag"), &GLTFCamera::set_size_mag);
ClassDB::bind_method(D_METHOD("get_depth_far"), &GLTFCamera::get_depth_far);
ClassDB::bind_method(D_METHOD("set_depth_far", "zdepth_far"), &GLTFCamera::set_depth_far);
ClassDB::bind_method(D_METHOD("get_depth_near"), &GLTFCamera::get_depth_near);
ClassDB::bind_method(D_METHOD("set_depth_near", "zdepth_near"), &GLTFCamera::set_depth_near);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "perspective"), "set_perspective", "get_perspective"); // bool
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fov_size"), "set_fov_size", "get_fov_size"); // float
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth_far"), "set_depth_far", "get_depth_far"); // float
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth_near"), "set_depth_near", "get_depth_near"); // float
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "perspective"), "set_perspective", "get_perspective");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fov"), "set_fov", "get_fov");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size_mag"), "set_size_mag", "get_size_mag");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth_far"), "set_depth_far", "get_depth_far");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth_near"), "set_depth_near", "get_depth_near");
+}
+
+Ref<GLTFCamera> GLTFCamera::from_node(const Camera3D *p_camera) {
+ Ref<GLTFCamera> c;
+ c.instantiate();
+ c->set_perspective(p_camera->get_projection() == Camera3D::ProjectionType::PROJECTION_PERSPECTIVE);
+ // GLTF spec (yfov) is in radians, Godot's camera (fov) is in degrees.
+ c->set_fov(Math::deg_to_rad(p_camera->get_fov()));
+ // GLTF spec (xmag and ymag) is a radius in meters, Godot's camera (size) is a diameter in meters.
+ c->set_size_mag(p_camera->get_size() * 0.5f);
+ c->set_depth_far(p_camera->get_far());
+ c->set_depth_near(p_camera->get_near());
+ return c;
+}
+
+Camera3D *GLTFCamera::to_node() const {
+ Camera3D *camera = memnew(Camera3D);
+ camera->set_projection(perspective ? Camera3D::PROJECTION_PERSPECTIVE : Camera3D::PROJECTION_ORTHOGONAL);
+ // GLTF spec (yfov) is in radians, Godot's camera (fov) is in degrees.
+ camera->set_fov(Math::rad_to_deg(fov));
+ // GLTF spec (xmag and ymag) is a radius in meters, Godot's camera (size) is a diameter in meters.
+ camera->set_size(size_mag * 2.0f);
+ camera->set_near(depth_near);
+ camera->set_far(depth_far);
+ return camera;
+}
+
+Ref<GLTFCamera> GLTFCamera::from_dictionary(const Dictionary p_dictionary) {
+ ERR_FAIL_COND_V_MSG(!p_dictionary.has("type"), Ref<GLTFCamera>(), "Failed to parse GLTF camera, missing required field 'type'.");
+ Ref<GLTFCamera> camera;
+ camera.instantiate();
+ const String &type = p_dictionary["type"];
+ if (type == "perspective") {
+ camera->set_perspective(true);
+ if (p_dictionary.has("perspective")) {
+ const Dictionary &persp = p_dictionary["perspective"];
+ camera->set_fov(persp["yfov"]);
+ if (persp.has("zfar")) {
+ camera->set_depth_far(persp["zfar"]);
+ }
+ camera->set_depth_near(persp["znear"]);
+ }
+ } else if (type == "orthographic") {
+ camera->set_perspective(false);
+ if (p_dictionary.has("orthographic")) {
+ const Dictionary &ortho = p_dictionary["orthographic"];
+ camera->set_size_mag(ortho["ymag"]);
+ camera->set_depth_far(ortho["zfar"]);
+ camera->set_depth_near(ortho["znear"]);
+ }
+ } else {
+ ERR_PRINT("Error parsing GLTF camera: Camera type '" + type + "' is unknown, should be perspective or orthographic.");
+ }
+ return camera;
+}
+
+Dictionary GLTFCamera::to_dictionary() const {
+ Dictionary d;
+ if (perspective) {
+ Dictionary persp;
+ persp["yfov"] = fov;
+ persp["zfar"] = depth_far;
+ persp["znear"] = depth_near;
+ d["perspective"] = persp;
+ d["type"] = "perspective";
+ } else {
+ Dictionary ortho;
+ ortho["ymag"] = size_mag;
+ ortho["xmag"] = size_mag;
+ ortho["zfar"] = depth_far;
+ ortho["znear"] = depth_near;
+ d["orthographic"] = ortho;
+ d["type"] = "orthographic";
+ }
+ return d;
}
diff --git a/modules/gltf/structures/gltf_camera.h b/modules/gltf/structures/gltf_camera.h
index b7df741825..50ae10e17a 100644
--- a/modules/gltf/structures/gltf_camera.h
+++ b/modules/gltf/structures/gltf_camera.h
@@ -32,15 +32,22 @@
#define GLTF_CAMERA_H
#include "core/io/resource.h"
+#include "scene/3d/camera_3d.h"
+
+// Reference and test file:
+// https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_015_SimpleCameras.md
class GLTFCamera : public Resource {
GDCLASS(GLTFCamera, Resource);
private:
+ // GLTF has no default camera values, they should always be specified in
+ // the GLTF file. Here we default to Godot's default camera settings.
bool perspective = true;
- float fov_size = 75.0;
- float depth_far = 4000.0;
- float depth_near = 0.05;
+ real_t fov = Math::deg_to_rad(75.0);
+ real_t size_mag = 0.5;
+ real_t depth_far = 4000.0;
+ real_t depth_near = 0.05;
protected:
static void _bind_methods();
@@ -48,12 +55,20 @@ protected:
public:
bool get_perspective() const { return perspective; }
void set_perspective(bool p_val) { perspective = p_val; }
- float get_fov_size() const { return fov_size; }
- void set_fov_size(float p_val) { fov_size = p_val; }
- float get_depth_far() const { return depth_far; }
- void set_depth_far(float p_val) { depth_far = p_val; }
- float get_depth_near() const { return depth_near; }
- void set_depth_near(float p_val) { depth_near = p_val; }
+ real_t get_fov() const { return fov; }
+ void set_fov(real_t p_val) { fov = p_val; }
+ real_t get_size_mag() const { return size_mag; }
+ void set_size_mag(real_t p_val) { size_mag = p_val; }
+ real_t get_depth_far() const { return depth_far; }
+ void set_depth_far(real_t p_val) { depth_far = p_val; }
+ real_t get_depth_near() const { return depth_near; }
+ void set_depth_near(real_t p_val) { depth_near = p_val; }
+
+ static Ref<GLTFCamera> from_node(const Camera3D *p_light);
+ Camera3D *to_node() const;
+
+ static Ref<GLTFCamera> from_dictionary(const Dictionary p_dictionary);
+ Dictionary to_dictionary() const;
};
#endif // GLTF_CAMERA_H
diff --git a/modules/gltf/structures/gltf_skeleton.cpp b/modules/gltf/structures/gltf_skeleton.cpp
index 90a6b0f50f..0073357eda 100644
--- a/modules/gltf/structures/gltf_skeleton.cpp
+++ b/modules/gltf/structures/gltf_skeleton.cpp
@@ -72,11 +72,11 @@ Skeleton3D *GLTFSkeleton::get_godot_skeleton() {
return godot_skeleton;
}
-Array GLTFSkeleton::get_unique_names() {
+TypedArray<String> GLTFSkeleton::get_unique_names() {
return GLTFTemplateConvert::to_array(unique_names);
}
-void GLTFSkeleton::set_unique_names(Array p_unique_names) {
+void GLTFSkeleton::set_unique_names(TypedArray<String> p_unique_names) {
GLTFTemplateConvert::set_from_array(unique_names, p_unique_names);
}
diff --git a/modules/gltf/structures/gltf_skeleton.h b/modules/gltf/structures/gltf_skeleton.h
index db88623213..0f20b493b6 100644
--- a/modules/gltf/structures/gltf_skeleton.h
+++ b/modules/gltf/structures/gltf_skeleton.h
@@ -75,8 +75,8 @@ public:
// this->godot_skeleton = p_godot_skeleton;
// }
- Array get_unique_names();
- void set_unique_names(Array p_unique_names);
+ TypedArray<String> get_unique_names();
+ void set_unique_names(TypedArray<String> p_unique_names);
//RBMap<int32_t, GLTFNodeIndex> get_godot_bone_node() {
// return this->godot_bone_node;
diff --git a/modules/gltf/structures/gltf_skin.cpp b/modules/gltf/structures/gltf_skin.cpp
index 2e46ee3be2..9717a66048 100644
--- a/modules/gltf/structures/gltf_skin.cpp
+++ b/modules/gltf/structures/gltf_skin.cpp
@@ -31,6 +31,7 @@
#include "gltf_skin.h"
#include "../gltf_template_convert.h"
+#include "core/variant/typed_array.h"
#include "scene/resources/skin.h"
void GLTFSkin::_bind_methods() {
@@ -83,11 +84,11 @@ void GLTFSkin::set_joints_original(Vector<GLTFNodeIndex> p_joints_original) {
joints_original = p_joints_original;
}
-Array GLTFSkin::get_inverse_binds() {
+TypedArray<Transform3D> GLTFSkin::get_inverse_binds() {
return GLTFTemplateConvert::to_array(inverse_binds);
}
-void GLTFSkin::set_inverse_binds(Array p_inverse_binds) {
+void GLTFSkin::set_inverse_binds(TypedArray<Transform3D> p_inverse_binds) {
GLTFTemplateConvert::set_from_array(inverse_binds, p_inverse_binds);
}
diff --git a/modules/gltf/structures/gltf_skin.h b/modules/gltf/structures/gltf_skin.h
index 59b6a300ac..1a4d54b380 100644
--- a/modules/gltf/structures/gltf_skin.h
+++ b/modules/gltf/structures/gltf_skin.h
@@ -34,6 +34,9 @@
#include "../gltf_defines.h"
#include "core/io/resource.h"
+template <typename T>
+class TypedArray;
+
class GLTFSkin : public Resource {
GDCLASS(GLTFSkin, Resource);
friend class GLTFDocument;
@@ -82,8 +85,8 @@ public:
Vector<GLTFNodeIndex> get_joints_original();
void set_joints_original(Vector<GLTFNodeIndex> p_joints_original);
- Array get_inverse_binds();
- void set_inverse_binds(Array p_inverse_binds);
+ TypedArray<Transform3D> get_inverse_binds();
+ void set_inverse_binds(TypedArray<Transform3D> p_inverse_binds);
Vector<GLTFNodeIndex> get_joints();
void set_joints(Vector<GLTFNodeIndex> p_joints);
diff --git a/modules/gridmap/SCsub b/modules/gridmap/SCsub
index 52777235b8..da3f7d4dd9 100644
--- a/modules/gridmap/SCsub
+++ b/modules/gridmap/SCsub
@@ -5,7 +5,7 @@ Import("env_modules")
env_gridmap = env_modules.Clone()
-# Godot's own source files
+# Godot source files
env_gridmap.add_source_files(env.modules_sources, "*.cpp")
if env["tools"]:
env_gridmap.add_source_files(env.modules_sources, "editor/*.cpp")
diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml
index 499f54e3ba..6717f23057 100644
--- a/modules/gridmap/doc_classes/GridMap.xml
+++ b/modules/gridmap/doc_classes/GridMap.xml
@@ -29,7 +29,7 @@
</method>
<method name="get_bake_mesh_instance">
<return type="RID" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
</description>
</method>
@@ -39,30 +39,44 @@
Returns an array of [ArrayMesh]es and [Transform3D] references of all bake meshes that exist within the current GridMap.
</description>
</method>
+ <method name="get_basis_with_orthogonal_index" qualifiers="const">
+ <return type="Basis" />
+ <param index="0" name="index" type="int" />
+ <description>
+ Returns one of 24 possible rotations that lie along the vectors (x,y,z) with each component being either -1, 0, or 1. For further details, refer to the Godot source code.
+ </description>
+ </method>
<method name="get_cell_item" qualifiers="const">
<return type="int" />
- <argument index="0" name="position" type="Vector3i" />
+ <param index="0" name="position" type="Vector3i" />
<description>
The [MeshLibrary] item index located at the given grid coordinates. If the cell is empty, [constant INVALID_CELL_ITEM] will be returned.
</description>
</method>
+ <method name="get_cell_item_basis" qualifiers="const">
+ <return type="Basis" />
+ <param index="0" name="position" type="Vector3i" />
+ <description>
+ Returns the basis that gives the specificed cell its orientation.
+ </description>
+ </method>
<method name="get_cell_item_orientation" qualifiers="const">
<return type="int" />
- <argument index="0" name="position" type="Vector3i" />
+ <param index="0" name="position" type="Vector3i" />
<description>
The orientation of the cell at the given grid coordinates. [code]-1[/code] is returned if the cell is empty.
</description>
</method>
<method name="get_collision_layer_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
Returns whether or not the specified layer of the [member collision_layer] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="get_collision_mask_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
@@ -75,82 +89,89 @@
</method>
<method name="get_navigation_layer_value" qualifiers="const">
<return type="bool" />
- <argument index="0" name="layer_number" type="int" />
+ <param index="0" name="layer_number" type="int" />
<description>
Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
+ <method name="get_orthogonal_index_from_basis" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="basis" type="Basis" />
+ <description>
+ This function considers a discretization of rotations into 24 points on unit sphere, lying along the vectors (x,y,z) with each component being either -1, 0, or 1, and returns the index (in the range from 0 to 23) of the point best representing the orientation of the object. For further details, refer to the Godot source code.
+ </description>
+ </method>
<method name="get_used_cells" qualifiers="const">
- <return type="Array" />
+ <return type="Vector3i[]" />
<description>
Returns an array of [Vector3] with the non-empty cell coordinates in the grid map.
</description>
</method>
<method name="get_used_cells_by_item" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="item" type="int" />
+ <return type="Vector3i[]" />
+ <param index="0" name="item" type="int" />
<description>
Returns an array of all cells with the given item index specified in [code]item[/code].
</description>
</method>
<method name="make_baked_meshes">
<return type="void" />
- <argument index="0" name="gen_lightmap_uv" type="bool" default="false" />
- <argument index="1" name="lightmap_uv_texel_size" type="float" default="0.1" />
+ <param index="0" name="gen_lightmap_uv" type="bool" default="false" />
+ <param index="1" name="lightmap_uv_texel_size" type="float" default="0.1" />
<description>
</description>
</method>
<method name="map_to_world" qualifiers="const">
<return type="Vector3" />
- <argument index="0" name="map_position" type="Vector3i" />
+ <param index="0" name="map_position" type="Vector3i" />
<description>
Returns the position of a grid cell in the GridMap's local coordinate space.
</description>
</method>
<method name="resource_changed">
<return type="void" />
- <argument index="0" name="resource" type="Resource" />
+ <param index="0" name="resource" type="Resource" />
<description>
</description>
</method>
<method name="set_cell_item">
<return type="void" />
- <argument index="0" name="position" type="Vector3i" />
- <argument index="1" name="item" type="int" />
- <argument index="2" name="orientation" type="int" default="0" />
+ <param index="0" name="position" type="Vector3i" />
+ <param index="1" name="item" type="int" />
+ <param index="2" name="orientation" type="int" default="0" />
<description>
Sets the mesh index for the cell referenced by its grid coordinates.
A negative item index such as [constant INVALID_CELL_ITEM] will clear the cell.
- Optionally, the item's orientation can be passed. For valid orientation values, see [method Basis.get_orthogonal_index].
+ Optionally, the item's orientation can be passed. For valid orientation values, see [method get_orthogonal_index_from_basis].
</description>
</method>
<method name="set_collision_layer_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
Based on [code]value[/code], enables or disables the specified layer in the [member collision_layer], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="set_collision_mask_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="set_navigation_layer_value">
<return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
+ <param index="0" name="layer_number" type="int" />
+ <param index="1" name="value" type="bool" />
<description>
Based on [code]value[/code], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [code]layer_number[/code] between 1 and 32.
</description>
</method>
<method name="world_to_map" qualifiers="const">
<return type="Vector3i" />
- <argument index="0" name="world_position" type="Vector3" />
+ <param index="0" name="world_position" type="Vector3" />
<description>
Returns the coordinates of the grid cell containing the given point.
[code]pos[/code] should be in the GridMap's local coordinate space.
@@ -200,7 +221,7 @@
</members>
<signals>
<signal name="cell_size_changed">
- <argument index="0" name="cell_size" type="Vector3" />
+ <param index="0" name="cell_size" type="Vector3" />
<description>
Emitted when [member cell_size] changes.
</description>
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp
index 09f0ff32f0..17f9832096 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp
@@ -37,6 +37,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/camera_3d.h"
#include "scene/main/window.h"
@@ -94,91 +95,91 @@ void GridMapEditor::_menu_option(int p_option) {
case MENU_OPTION_CURSOR_ROTATE_Y: {
Basis r;
if (input_action == INPUT_PASTE) {
- r.set_orthogonal_index(paste_indicator.orientation);
+ r = node->get_basis_with_orthogonal_index(paste_indicator.orientation);
r.rotate(Vector3(0, 1, 0), -Math_PI / 2.0);
- paste_indicator.orientation = r.get_orthogonal_index();
+ paste_indicator.orientation = node->get_orthogonal_index_from_basis(r);
_update_paste_indicator();
break;
}
- r.set_orthogonal_index(cursor_rot);
+ r = node->get_basis_with_orthogonal_index(cursor_rot);
r.rotate(Vector3(0, 1, 0), -Math_PI / 2.0);
- cursor_rot = r.get_orthogonal_index();
+ cursor_rot = node->get_orthogonal_index_from_basis(r);
_update_cursor_transform();
} break;
case MENU_OPTION_CURSOR_ROTATE_X: {
Basis r;
if (input_action == INPUT_PASTE) {
- r.set_orthogonal_index(paste_indicator.orientation);
+ r = node->get_basis_with_orthogonal_index(paste_indicator.orientation);
r.rotate(Vector3(1, 0, 0), -Math_PI / 2.0);
- paste_indicator.orientation = r.get_orthogonal_index();
+ paste_indicator.orientation = node->get_orthogonal_index_from_basis(r);
_update_paste_indicator();
break;
}
- r.set_orthogonal_index(cursor_rot);
+ r = node->get_basis_with_orthogonal_index(cursor_rot);
r.rotate(Vector3(1, 0, 0), -Math_PI / 2.0);
- cursor_rot = r.get_orthogonal_index();
+ cursor_rot = node->get_orthogonal_index_from_basis(r);
_update_cursor_transform();
} break;
case MENU_OPTION_CURSOR_ROTATE_Z: {
Basis r;
if (input_action == INPUT_PASTE) {
- r.set_orthogonal_index(paste_indicator.orientation);
+ r = node->get_basis_with_orthogonal_index(paste_indicator.orientation);
r.rotate(Vector3(0, 0, 1), -Math_PI / 2.0);
- paste_indicator.orientation = r.get_orthogonal_index();
+ paste_indicator.orientation = node->get_orthogonal_index_from_basis(r);
_update_paste_indicator();
break;
}
- r.set_orthogonal_index(cursor_rot);
+ r = node->get_basis_with_orthogonal_index(cursor_rot);
r.rotate(Vector3(0, 0, 1), -Math_PI / 2.0);
- cursor_rot = r.get_orthogonal_index();
+ cursor_rot = node->get_orthogonal_index_from_basis(r);
_update_cursor_transform();
} break;
case MENU_OPTION_CURSOR_BACK_ROTATE_Y: {
Basis r;
if (input_action == INPUT_PASTE) {
- r.set_orthogonal_index(paste_indicator.orientation);
+ r = node->get_basis_with_orthogonal_index(paste_indicator.orientation);
r.rotate(Vector3(0, 1, 0), Math_PI / 2.0);
- paste_indicator.orientation = r.get_orthogonal_index();
+ paste_indicator.orientation = node->get_orthogonal_index_from_basis(r);
_update_paste_indicator();
break;
}
- r.set_orthogonal_index(cursor_rot);
+ r = node->get_basis_with_orthogonal_index(cursor_rot);
r.rotate(Vector3(0, 1, 0), Math_PI / 2.0);
- cursor_rot = r.get_orthogonal_index();
+ cursor_rot = node->get_orthogonal_index_from_basis(r);
_update_cursor_transform();
} break;
case MENU_OPTION_CURSOR_BACK_ROTATE_X: {
Basis r;
if (input_action == INPUT_PASTE) {
- r.set_orthogonal_index(paste_indicator.orientation);
+ r = node->get_basis_with_orthogonal_index(paste_indicator.orientation);
r.rotate(Vector3(1, 0, 0), Math_PI / 2.0);
- paste_indicator.orientation = r.get_orthogonal_index();
+ paste_indicator.orientation = node->get_orthogonal_index_from_basis(r);
_update_paste_indicator();
break;
}
- r.set_orthogonal_index(cursor_rot);
+ r = node->get_basis_with_orthogonal_index(cursor_rot);
r.rotate(Vector3(1, 0, 0), Math_PI / 2.0);
- cursor_rot = r.get_orthogonal_index();
+ cursor_rot = node->get_orthogonal_index_from_basis(r);
_update_cursor_transform();
} break;
case MENU_OPTION_CURSOR_BACK_ROTATE_Z: {
Basis r;
if (input_action == INPUT_PASTE) {
- r.set_orthogonal_index(paste_indicator.orientation);
+ r = node->get_basis_with_orthogonal_index(paste_indicator.orientation);
r.rotate(Vector3(0, 0, 1), Math_PI / 2.0);
- paste_indicator.orientation = r.get_orthogonal_index();
+ paste_indicator.orientation = node->get_orthogonal_index_from_basis(r);
_update_paste_indicator();
break;
}
- r.set_orthogonal_index(cursor_rot);
+ r = node->get_basis_with_orthogonal_index(cursor_rot);
r.rotate(Vector3(0, 0, 1), Math_PI / 2.0);
- cursor_rot = r.get_orthogonal_index();
+ cursor_rot = node->get_orthogonal_index_from_basis(r);
_update_cursor_transform();
} break;
case MENU_OPTION_CURSOR_CLEAR_ROTATION: {
@@ -242,7 +243,7 @@ void GridMapEditor::_menu_option(int p_option) {
void GridMapEditor::_update_cursor_transform() {
cursor_transform = Transform3D();
cursor_transform.origin = cursor_origin;
- cursor_transform.basis.set_orthogonal_index(cursor_rot);
+ cursor_transform.basis = node->get_basis_with_orthogonal_index(cursor_rot);
cursor_transform.basis *= node->get_cell_scale();
cursor_transform = node->get_global_transform() * cursor_transform;
@@ -543,7 +544,7 @@ void GridMapEditor::_update_paste_indicator() {
xf.scale(scale);
xf.origin = (paste_indicator.begin + (paste_indicator.current - paste_indicator.click) + center) * node->get_cell_size();
Basis rot;
- rot.set_orthogonal_index(paste_indicator.orientation);
+ rot = node->get_basis_with_orthogonal_index(paste_indicator.orientation);
xf.basis = rot * xf.basis;
xf.translate_local((-center * node->get_cell_size()) / scale);
@@ -556,7 +557,7 @@ void GridMapEditor::_update_paste_indicator() {
xf.translate_local(item.grid_offset * node->get_cell_size());
Basis item_rot;
- item_rot.set_orthogonal_index(item.orientation);
+ item_rot = node->get_basis_with_orthogonal_index(item.orientation);
xf.basis = item_rot * xf.basis * node->get_cell_scale();
RenderingServer::get_singleton()->instance_set_transform(item.instance, node->get_global_transform() * xf);
@@ -568,7 +569,7 @@ void GridMapEditor::_do_paste() {
bool reselect = options->get_popup()->is_item_checked(idx);
Basis rot;
- rot.set_orthogonal_index(paste_indicator.orientation);
+ rot = node->get_basis_with_orthogonal_index(paste_indicator.orientation);
Vector3 ofs = paste_indicator.current - paste_indicator.click;
undo_redo->create_action(TTR("GridMap Paste Selection"));
@@ -577,10 +578,10 @@ void GridMapEditor::_do_paste() {
Vector3 position = rot.xform(item.grid_offset) + paste_indicator.begin + ofs;
Basis orm;
- orm.set_orthogonal_index(item.orientation);
+ orm = node->get_basis_with_orthogonal_index(item.orientation);
orm = rot * orm;
- undo_redo->add_do_method(node, "set_cell_item", position, item.cell_item, orm.get_orthogonal_index());
+ undo_redo->add_do_method(node, "set_cell_item", position, item.cell_item, node->get_orthogonal_index_from_basis(orm));
undo_redo->add_undo_method(node, "set_cell_item", position, node->get_cell_item(position), node->get_cell_item_orientation(position));
}
@@ -896,10 +897,12 @@ void GridMapEditor::update_palette() {
}
if (selected != -1 && mesh_library_palette->get_item_count() > 0) {
- mesh_library_palette->select(selected);
+ // Make sure that this variable is set correctly.
+ selected_palette = MIN(selected, mesh_library_palette->get_item_count() - 1);
+ mesh_library_palette->select(selected_palette);
}
- last_mesh_library = mesh_library.operator->();
+ last_mesh_library = *mesh_library;
}
void GridMapEditor::edit(GridMap *p_gridmap) {
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.h b/modules/gridmap/editor/grid_map_editor_plugin.h
index 3b29397502..a64dc4a80b 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.h
+++ b/modules/gridmap/editor/grid_map_editor_plugin.h
@@ -39,6 +39,7 @@
#include "scene/gui/slider.h"
#include "scene/gui/spin_box.h"
+class EditorUndoRedoManager;
class Node3DEditorPlugin;
class GridMapEditor : public VBoxContainer {
@@ -62,7 +63,7 @@ class GridMapEditor : public VBoxContainer {
DISPLAY_LIST
};
- UndoRedo *undo_redo = nullptr;
+ Ref<EditorUndoRedoManager> undo_redo;
InputAction input_action = INPUT_NONE;
Panel *panel = nullptr;
MenuButton *options = nullptr;
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index 7d80cbef7c..f207d4a741 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -428,6 +428,75 @@ int GridMap::get_cell_item_orientation(const Vector3i &p_position) const {
return cell_map[key].rot;
}
+static const Basis _ortho_bases[24] = {
+ Basis(1, 0, 0, 0, 1, 0, 0, 0, 1),
+ Basis(0, -1, 0, 1, 0, 0, 0, 0, 1),
+ Basis(-1, 0, 0, 0, -1, 0, 0, 0, 1),
+ Basis(0, 1, 0, -1, 0, 0, 0, 0, 1),
+ Basis(1, 0, 0, 0, 0, -1, 0, 1, 0),
+ Basis(0, 0, 1, 1, 0, 0, 0, 1, 0),
+ Basis(-1, 0, 0, 0, 0, 1, 0, 1, 0),
+ Basis(0, 0, -1, -1, 0, 0, 0, 1, 0),
+ Basis(1, 0, 0, 0, -1, 0, 0, 0, -1),
+ Basis(0, 1, 0, 1, 0, 0, 0, 0, -1),
+ Basis(-1, 0, 0, 0, 1, 0, 0, 0, -1),
+ Basis(0, -1, 0, -1, 0, 0, 0, 0, -1),
+ Basis(1, 0, 0, 0, 0, 1, 0, -1, 0),
+ Basis(0, 0, -1, 1, 0, 0, 0, -1, 0),
+ Basis(-1, 0, 0, 0, 0, -1, 0, -1, 0),
+ Basis(0, 0, 1, -1, 0, 0, 0, -1, 0),
+ Basis(0, 0, 1, 0, 1, 0, -1, 0, 0),
+ Basis(0, -1, 0, 0, 0, 1, -1, 0, 0),
+ Basis(0, 0, -1, 0, -1, 0, -1, 0, 0),
+ Basis(0, 1, 0, 0, 0, -1, -1, 0, 0),
+ Basis(0, 0, 1, 0, -1, 0, 1, 0, 0),
+ Basis(0, 1, 0, 0, 0, 1, 1, 0, 0),
+ Basis(0, 0, -1, 0, 1, 0, 1, 0, 0),
+ Basis(0, -1, 0, 0, 0, -1, 1, 0, 0)
+};
+
+Basis GridMap::get_cell_item_basis(const Vector3i &p_position) const {
+ int orientation = get_cell_item_orientation(p_position);
+
+ if (orientation == -1) {
+ return Basis();
+ }
+
+ return get_basis_with_orthogonal_index(orientation);
+}
+
+Basis GridMap::get_basis_with_orthogonal_index(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, 24, Basis());
+
+ return _ortho_bases[p_index];
+}
+
+int GridMap::get_orthogonal_index_from_basis(const Basis &p_basis) const {
+ Basis orth = p_basis;
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ real_t v = orth[i][j];
+ if (v > 0.5) {
+ v = 1.0;
+ } else if (v < -0.5) {
+ v = -1.0;
+ } else {
+ v = 0;
+ }
+
+ orth[i][j] = v;
+ }
+ }
+
+ for (int i = 0; i < 24; i++) {
+ if (_ortho_bases[i] == orth) {
+ return i;
+ }
+ }
+
+ return 0;
+}
+
Vector3i GridMap::world_to_map(const Vector3 &p_world_position) const {
Vector3 map_position = (p_world_position / cell_size).floor();
return Vector3i(map_position);
@@ -529,7 +598,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
Transform3D xform;
- xform.basis.set_orthogonal_index(c.rot);
+ xform.basis = _ortho_bases[c.rot];
xform.set_origin(cellpos * cell_size + ofs);
xform.basis.scale(Vector3(cell_scale, cell_scale, cell_scale));
if (baked_meshes.size() == 0) {
@@ -921,6 +990,9 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_cell_item", "position", "item", "orientation"), &GridMap::set_cell_item, DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_cell_item", "position"), &GridMap::get_cell_item);
ClassDB::bind_method(D_METHOD("get_cell_item_orientation", "position"), &GridMap::get_cell_item_orientation);
+ ClassDB::bind_method(D_METHOD("get_cell_item_basis", "position"), &GridMap::get_cell_item_basis);
+ ClassDB::bind_method(D_METHOD("get_basis_with_orthogonal_index", "index"), &GridMap::get_basis_with_orthogonal_index);
+ ClassDB::bind_method(D_METHOD("get_orthogonal_index_from_basis", "basis"), &GridMap::get_orthogonal_index_from_basis);
ClassDB::bind_method(D_METHOD("world_to_map", "world_position"), &GridMap::world_to_map);
ClassDB::bind_method(D_METHOD("map_to_world", "map_position"), &GridMap::map_to_world);
@@ -977,23 +1049,23 @@ float GridMap::get_cell_scale() const {
return cell_scale;
}
-Array GridMap::get_used_cells() const {
- Array a;
+TypedArray<Vector3i> GridMap::get_used_cells() const {
+ TypedArray<Vector3i> a;
a.resize(cell_map.size());
int i = 0;
for (const KeyValue<IndexKey, Cell> &E : cell_map) {
- Vector3 p(E.key.x, E.key.y, E.key.z);
+ Vector3i p(E.key.x, E.key.y, E.key.z);
a[i++] = p;
}
return a;
}
-Array GridMap::get_used_cells_by_item(int p_item) const {
- Array a;
+TypedArray<Vector3i> GridMap::get_used_cells_by_item(int p_item) const {
+ TypedArray<Vector3i> a;
for (const KeyValue<IndexKey, Cell> &E : cell_map) {
if (E.value.item == p_item) {
- Vector3 p(E.key.x, E.key.y, E.key.z);
+ Vector3i p(E.key.x, E.key.y, E.key.z);
a.push_back(p);
}
}
@@ -1025,7 +1097,7 @@ Array GridMap::get_meshes() const {
Transform3D xform;
- xform.basis.set_orthogonal_index(E.value.rot);
+ xform.basis = _ortho_bases[E.value.rot];
xform.set_origin(cellpos * cell_size + ofs);
xform.basis.scale(Vector3(cell_scale, cell_scale, cell_scale));
@@ -1079,7 +1151,7 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe
Transform3D xform;
- xform.basis.set_orthogonal_index(E.value.rot);
+ xform.basis = _ortho_bases[E.value.rot];
xform.set_origin(cellpos * cell_size + ofs);
xform.basis.scale(Vector3(cell_scale, cell_scale, cell_scale));
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index 078a1d9de5..0ed4695fb9 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -263,6 +263,9 @@ public:
void set_cell_item(const Vector3i &p_position, int p_item, int p_rot = 0);
int get_cell_item(const Vector3i &p_position) const;
int get_cell_item_orientation(const Vector3i &p_position) const;
+ Basis get_cell_item_basis(const Vector3i &p_position) const;
+ Basis get_basis_with_orthogonal_index(int p_index) const;
+ int get_orthogonal_index_from_basis(const Basis &p_basis) const;
Vector3i world_to_map(const Vector3 &p_world_position) const;
Vector3 map_to_world(const Vector3i &p_map_position) const;
@@ -270,8 +273,8 @@ public:
void set_cell_scale(float p_scale);
float get_cell_scale() const;
- Array get_used_cells() const;
- Array get_used_cells_by_item(int p_item) const;
+ TypedArray<Vector3i> get_used_cells() const;
+ TypedArray<Vector3i> get_used_cells_by_item(int p_item) const;
Array get_meshes() const;
diff --git a/modules/hdr/SCsub b/modules/hdr/SCsub
index a709397c9a..10629bda3c 100644
--- a/modules/hdr/SCsub
+++ b/modules/hdr/SCsub
@@ -5,5 +5,5 @@ Import("env_modules")
env_hdr = env_modules.Clone()
-# Godot's own source files
+# Godot source files
env_hdr.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/hdr/image_loader_hdr.cpp b/modules/hdr/image_loader_hdr.cpp
index eca689e87a..e7c6fe592d 100644
--- a/modules/hdr/image_loader_hdr.cpp
+++ b/modules/hdr/image_loader_hdr.cpp
@@ -33,7 +33,7 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
-Error ImageLoaderHDR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) {
+Error ImageLoaderHDR::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) {
String header = f->get_token();
ERR_FAIL_COND_V_MSG(header != "#?RADIANCE" && header != "#?RGBE", ERR_FILE_UNRECOGNIZED, "Unsupported header information in HDR: " + header + ".");
@@ -131,7 +131,7 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_f
ptr[1] * exp / 255.0,
ptr[2] * exp / 255.0);
- if (p_force_linear) {
+ if (p_flags & FLAG_FORCE_LINEAR) {
c = c.srgb_to_linear();
}
diff --git a/modules/hdr/image_loader_hdr.h b/modules/hdr/image_loader_hdr.h
index 16c0816562..1bff05129b 100644
--- a/modules/hdr/image_loader_hdr.h
+++ b/modules/hdr/image_loader_hdr.h
@@ -35,7 +35,7 @@
class ImageLoaderHDR : public ImageFormatLoader {
public:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderHDR();
};
diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp
index 0e03fa65c8..3e138bf633 100644
--- a/modules/jpg/image_loader_jpegd.cpp
+++ b/modules/jpg/image_loader_jpegd.cpp
@@ -104,7 +104,7 @@ Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p
return OK;
}
-Error ImageLoaderJPG::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) {
+Error ImageLoaderJPG::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) {
Vector<uint8_t> src_image;
uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
diff --git a/modules/jpg/image_loader_jpegd.h b/modules/jpg/image_loader_jpegd.h
index 6d631446e7..caa0461d05 100644
--- a/modules/jpg/image_loader_jpegd.h
+++ b/modules/jpg/image_loader_jpegd.h
@@ -35,7 +35,7 @@
class ImageLoaderJPG : public ImageFormatLoader {
public:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderJPG();
};
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index 83ac478a97..2dcf644a06 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -62,7 +62,7 @@ void LightmapperRD::add_directional_light(bool p_static, const Vector3 &p_direct
l.color[2] = p_color.b;
l.energy = p_energy;
l.static_bake = p_static;
- l.size = Math::tan(Math::deg2rad(p_angular_distance));
+ l.size = Math::tan(Math::deg_to_rad(p_angular_distance));
l.shadow_blur = p_shadow_blur;
lights.push_back(l);
}
@@ -96,7 +96,7 @@ void LightmapperRD::add_spot_light(bool p_static, const Vector3 &p_position, con
l.direction[2] = p_direction.z;
l.range = p_range;
l.attenuation = p_attenuation;
- l.cos_spot_angle = Math::cos(Math::deg2rad(p_spot_angle));
+ l.cos_spot_angle = Math::cos(Math::deg_to_rad(p_spot_angle));
l.inv_spot_attenuation = 1.0f / p_spot_attenuation;
l.color[0] = p_color.r;
l.color[1] = p_color.g;
diff --git a/modules/lightmapper_rd/lightmapper_rd.h b/modules/lightmapper_rd/lightmapper_rd.h
index 88860ad0d4..bf6b4399ca 100644
--- a/modules/lightmapper_rd/lightmapper_rd.h
+++ b/modules/lightmapper_rd/lightmapper_rd.h
@@ -183,7 +183,7 @@ class LightmapperRD : public Lightmapper {
}
};
- void _plot_triangle_into_triangle_index_list(int p_size, const Vector3i &p_ofs, const AABB &p_bounds, const Vector3 p_points[], uint32_t p_triangle_index, LocalVector<TriangleSort> &triangles, uint32_t p_grid_size);
+ void _plot_triangle_into_triangle_index_list(int p_size, const Vector3i &p_ofs, const AABB &p_bounds, const Vector3 p_points[3], uint32_t p_triangle_index, LocalVector<TriangleSort> &triangles, uint32_t p_grid_size);
struct RasterPushConstant {
float atlas_size[2] = {};
diff --git a/modules/minimp3/SCsub b/modules/minimp3/SCsub
index f4d1605d55..20e3165f38 100644
--- a/modules/minimp3/SCsub
+++ b/modules/minimp3/SCsub
@@ -13,5 +13,5 @@ if not env.msvc:
else:
env_minimp3.Prepend(CPPPATH=[thirdparty_dir])
-# Godot's own source files
+# Godot source files
env_minimp3.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/mono/.editorconfig b/modules/mono/.editorconfig
index c9dcd7724e..9434d0693c 100644
--- a/modules/mono/.editorconfig
+++ b/modules/mono/.editorconfig
@@ -12,3 +12,32 @@ insert_final_newline = true
trim_trailing_whitespace = true
max_line_length = 120
csharp_indent_case_contents_when_block = false
+
+[*.cs]
+# CA1707: Identifiers should not contain underscores
+# TODO:
+# Maybe we could disable this selectively only
+# where it's not desired and for generated code.
+dotnet_diagnostic.CA1707.severity = none
+# CA1711: Identifiers should not have incorrect suffix
+# Disable warning for suffixes like EventHandler, Flags, Enum, etc.
+dotnet_diagnostic.CA1711.severity = none
+# CA1716: Identifiers should not match keywords
+# TODO: We should look into this.
+dotnet_diagnostic.CA1716.severity = warning
+# CA1720: Identifiers should not contain type names
+dotnet_diagnostic.CA1720.severity = none
+# CA1805: Do not initialize unnecessarily
+# Don't tell me what to do.
+dotnet_diagnostic.CA1805.severity = none
+# CA1304: Specify CultureInfo
+# TODO: We should look into this.
+dotnet_diagnostic.CA1304.severity = warning
+# CA1305: Specify IFormatProvider
+# TODO: We should look into this. Disabled for now because it's annoying.
+dotnet_diagnostic.CA1305.severity = none
+# CA1310: Specify StringComparison for correctness
+# TODO: We should look into this. Disabled for now because it's annoying.
+dotnet_diagnostic.CA1310.severity = none
+# Diagnostics to prevent defensive copies of `in` struct parameters
+resharper_possibly_impure_method_call_on_readonly_variable_highlighting = error
diff --git a/modules/mono/Directory.Build.props b/modules/mono/Directory.Build.props
index fbf864b11b..f7c8a825f9 100644
--- a/modules/mono/Directory.Build.props
+++ b/modules/mono/Directory.Build.props
@@ -1,3 +1,6 @@
<Project>
- <Import Project="$(MSBuildThisFileDirectory)\SdkPackageVersions.props" />
+ <PropertyGroup>
+ <GodotSdkPackageVersionsFilePath>$(MSBuildThisFileDirectory)\SdkPackageVersions.props</GodotSdkPackageVersionsFilePath>
+ </PropertyGroup>
+ <Import Project="$(GodotSdkPackageVersionsFilePath)" />
</Project>
diff --git a/modules/mono/Directory.Build.targets b/modules/mono/Directory.Build.targets
new file mode 100644
index 0000000000..98410b93ae
--- /dev/null
+++ b/modules/mono/Directory.Build.targets
@@ -0,0 +1,22 @@
+<Project>
+ <PropertyGroup>
+ <_HasNuGetPackage Condition=" '$(_HasNuGetPackage)' == '' And '$(PackageId)' != '' And '$(GeneratePackageOnBuild.ToLower())' == 'true' ">true</_HasNuGetPackage>
+ <_HasNuGetPackage Condition=" '$(_HasNuGetPackage)' == '' ">false</_HasNuGetPackage>
+ </PropertyGroup>
+ <Target Name="CopyNupkgToSConsOutputDir" AfterTargets="Pack"
+ Condition=" '$(_HasNuGetPackage)' == 'true' ">
+ <PropertyGroup>
+ <GodotSourceRootPath>$(MSBuildThisFileDirectory)\..\..\</GodotSourceRootPath>
+ <GodotOutputDataDir>$(GodotSourceRootPath)\bin\GodotSharp\</GodotOutputDataDir>
+ </PropertyGroup>
+ <Copy SourceFiles="$(PackageOutputPath)$(PackageId).$(PackageVersion).nupkg" DestinationFolder="$(GodotOutputDataDir)Tools\nupkgs\" />
+ </Target>
+ <Target Name="PushNuGetPackagesToLocalSource" BeforeTargets="Pack"
+ Condition=" '$(_HasNuGetPackage)' == 'true' And '$(PushNuGetToLocalSource)' != '' ">
+ <Copy SourceFiles="$(PackageOutputPath)$(PackageId).$(PackageVersion).nupkg" DestinationFolder="$(PushNuGetToLocalSource)\" />
+ </Target>
+ <Target Name="ClearNuGetLocalPackageCache" BeforeTargets="Pack"
+ Condition=" '$(_HasNuGetPackage)' == 'true' And '$(ClearNuGetLocalCache.ToLower())' == 'true' ">
+ <RemoveDir Directories="$(NugetPackageRoot)/$(PackageId.ToLower())/$(PackageVersion)"/>
+ </Target>
+</Project>
diff --git a/modules/mono/README.md b/modules/mono/README.md
new file mode 100644
index 0000000000..ebbc6b0f80
--- /dev/null
+++ b/modules/mono/README.md
@@ -0,0 +1,45 @@
+# How to build and run
+
+1. Build Godot with the module enabled: `module_mono_enabled=yes`.
+2. After building Godot, use it to generate the C# glue code:
+ ```sh
+ <godot_binary> --generate-mono-glue ./modules/mono/glue
+ ```
+3. Build the C# solutions:
+ ```sh
+ ./modules/mono/build_scripts/build_assemblies.py --godot-output-dir ./bin
+ ```
+
+The paths specified in these examples assume the command is being run from
+the Godot source root.
+
+# How to deal with NuGet packages
+
+We distribute the API assemblies, our source generators, and our custom
+MSBuild project SDK as NuGet packages. This is all transparent to the user,
+but it can make things complicated during development.
+
+In order to use Godot with a development of those packages, we must create
+a local NuGet source where MSBuild can find them. This can be done with
+the .NET CLI:
+
+```sh
+dotnet nuget add source ~/MyLocalNugetSource --name MyLocalNugetSource
+```
+
+The Godot NuGet packages must be added to that local source. Additionally,
+we must make sure there are no other versions of the package in the NuGet
+cache, as MSBuild may pick one of those instead.
+
+In order to simplify this process, the `build_assemblies.py` script provides
+the following `--push-nupkgs-local` option:
+
+```sh
+./modules/mono/build_scripts/build_assemblies.py --godot-output-dir ./bin \
+ --push-nupkgs-local ~/MyLocalNugetSource
+```
+
+This option ensures the packages will be added to the specified local NuGet
+source and that conflicting versions of the package are removed from the
+NuGet cache. It's recommended to always use this option when building the
+C# solutions during development to avoid mistakes.
diff --git a/modules/mono/SCsub b/modules/mono/SCsub
index d10ebc7b47..7764ba0b45 100644
--- a/modules/mono/SCsub
+++ b/modules/mono/SCsub
@@ -7,49 +7,14 @@ Import("env_modules")
env_mono = env_modules.Clone()
-if env_mono["tools"]:
- # NOTE: It is safe to generate this file here, since this is still executed serially
- import build_scripts.gen_cs_glue_version as gen_cs_glue_version
-
- gen_cs_glue_version.generate_header("glue/GodotSharp", "glue/cs_glue_version.gen.h")
-
-# Glue sources
-if env_mono["mono_glue"]:
- env_mono.Append(CPPDEFINES=["MONO_GLUE_ENABLED"])
-
- import os.path
-
- if not os.path.isfile("glue/mono_glue.gen.cpp"):
- raise RuntimeError("Mono glue sources not found. Did you forget to run '--generate-mono-glue'?")
-
-if env_mono["tools"] or env_mono["target"] != "release":
- env_mono.Append(CPPDEFINES=["GD_MONO_HOT_RELOAD"])
-
# Configure Mono
mono_configure.configure(env, env_mono)
-if env_mono["tools"] and env_mono["mono_glue"] and env_mono["build_cil"]:
- # Build Godot API solution
- import build_scripts.api_solution_build as api_solution_build
-
- api_sln_cmd = api_solution_build.build(env_mono)
-
- # Build GodotTools
- import build_scripts.godot_tools_build as godot_tools_build
-
- godot_tools_build.build(env_mono, api_sln_cmd)
-
- # Build Godot.NET.Sdk
- import build_scripts.godot_net_sdk_build as godot_net_sdk_build
-
- godot_net_sdk_build.build(env_mono)
-
# Add sources
env_mono.add_source_files(env.modules_sources, "*.cpp")
env_mono.add_source_files(env.modules_sources, "glue/*.cpp")
-env_mono.add_source_files(env.modules_sources, "glue/mono_glue.gen.cpp")
env_mono.add_source_files(env.modules_sources, "mono_gd/*.cpp")
env_mono.add_source_files(env.modules_sources, "utils/*.cpp")
diff --git a/modules/mono/SdkPackageVersions.props b/modules/mono/SdkPackageVersions.props
index bdec051625..65094aa34f 100644
--- a/modules/mono/SdkPackageVersions.props
+++ b/modules/mono/SdkPackageVersions.props
@@ -1,7 +1,8 @@
<Project>
<PropertyGroup>
<PackageFloatingVersion_Godot>4.0.*-*</PackageFloatingVersion_Godot>
- <PackageVersion_Godot_NET_Sdk>4.0.0-dev6</PackageVersion_Godot_NET_Sdk>
- <PackageVersion_Godot_SourceGenerators>4.0.0-dev3</PackageVersion_Godot_SourceGenerators>
+ <PackageVersion_GodotSharp>4.0.0-dev</PackageVersion_GodotSharp>
+ <PackageVersion_Godot_NET_Sdk>4.0.0-dev8</PackageVersion_Godot_NET_Sdk>
+ <PackageVersion_Godot_SourceGenerators>4.0.0-dev8</PackageVersion_Godot_SourceGenerators>
</PropertyGroup>
</Project>
diff --git a/modules/mono/build_scripts/api_solution_build.py b/modules/mono/build_scripts/api_solution_build.py
deleted file mode 100644
index 9abac22df6..0000000000
--- a/modules/mono/build_scripts/api_solution_build.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# Build the Godot API solution
-
-import os
-
-from SCons.Script import Dir
-
-
-def build_api_solution(source, target, env):
- # source and target elements are of type SCons.Node.FS.File, hence why we convert them to str
-
- module_dir = env["module_dir"]
-
- solution_path = os.path.join(module_dir, "glue/GodotSharp/GodotSharp.sln")
-
- build_config = env["solution_build_config"]
-
- extra_msbuild_args = ["/p:NoWarn=1591"] # Ignore missing documentation warnings
-
- from .solution_builder import build_solution
-
- build_solution(env, solution_path, build_config, extra_msbuild_args=extra_msbuild_args)
-
- # Copy targets
-
- core_src_dir = os.path.abspath(os.path.join(solution_path, os.pardir, "GodotSharp", "bin", build_config))
- editor_src_dir = os.path.abspath(os.path.join(solution_path, os.pardir, "GodotSharpEditor", "bin", build_config))
-
- dst_dir = os.path.abspath(os.path.join(str(target[0]), os.pardir))
-
- if not os.path.isdir(dst_dir):
- assert not os.path.isfile(dst_dir)
- os.makedirs(dst_dir)
-
- def copy_target(target_path):
- from shutil import copy
-
- filename = os.path.basename(target_path)
-
- src_path = os.path.join(core_src_dir, filename)
- if not os.path.isfile(src_path):
- src_path = os.path.join(editor_src_dir, filename)
-
- copy(src_path, target_path)
-
- for scons_target in target:
- copy_target(str(scons_target))
-
-
-def build(env_mono):
- assert env_mono["tools"]
-
- target_filenames = [
- "GodotSharp.dll",
- "GodotSharp.pdb",
- "GodotSharp.xml",
- "GodotSharpEditor.dll",
- "GodotSharpEditor.pdb",
- "GodotSharpEditor.xml",
- ]
-
- depend_cmd = []
-
- for build_config in ["Debug", "Release"]:
- output_dir = Dir("#bin").abspath
- editor_api_dir = os.path.join(output_dir, "GodotSharp", "Api", build_config)
-
- targets = [os.path.join(editor_api_dir, filename) for filename in target_filenames]
-
- cmd = env_mono.CommandNoCache(
- targets, depend_cmd, build_api_solution, module_dir=os.getcwd(), solution_build_config=build_config
- )
- env_mono.AlwaysBuild(cmd)
-
- # Make the Release build of the API solution depend on the Debug build.
- # We do this in order to prevent SCons from building them in parallel,
- # which can freak out MSBuild. In many cases, one of the builds would
- # hang indefinitely requiring a key to be pressed for it to continue.
- depend_cmd = cmd
-
- return depend_cmd
diff --git a/modules/mono/build_scripts/build_assemblies.py b/modules/mono/build_scripts/build_assemblies.py
new file mode 100755
index 0000000000..fa3be684bd
--- /dev/null
+++ b/modules/mono/build_scripts/build_assemblies.py
@@ -0,0 +1,329 @@
+#!/usr/bin/python3
+
+import os
+import os.path
+import shlex
+import subprocess
+from dataclasses import dataclass
+
+
+def find_dotnet_cli():
+ if os.name == "nt":
+ for hint_dir in os.environ["PATH"].split(os.pathsep):
+ hint_dir = hint_dir.strip('"')
+ hint_path = os.path.join(hint_dir, "dotnet")
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+ if os.path.isfile(hint_path + ".exe") and os.access(hint_path + ".exe", os.X_OK):
+ return hint_path + ".exe"
+ else:
+ for hint_dir in os.environ["PATH"].split(os.pathsep):
+ hint_dir = hint_dir.strip('"')
+ hint_path = os.path.join(hint_dir, "dotnet")
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+
+
+def find_msbuild_standalone_windows():
+ msbuild_tools_path = find_msbuild_tools_path_reg()
+
+ if msbuild_tools_path:
+ return os.path.join(msbuild_tools_path, "MSBuild.exe")
+
+ return None
+
+
+def find_msbuild_mono_windows(mono_prefix):
+ assert mono_prefix is not None
+
+ mono_bin_dir = os.path.join(mono_prefix, "bin")
+ msbuild_mono = os.path.join(mono_bin_dir, "msbuild.bat")
+
+ if os.path.isfile(msbuild_mono):
+ return msbuild_mono
+
+ return None
+
+
+def find_msbuild_mono_unix():
+ import sys
+
+ hint_dirs = []
+ if sys.platform == "darwin":
+ hint_dirs[:0] = [
+ "/Library/Frameworks/Mono.framework/Versions/Current/bin",
+ "/usr/local/var/homebrew/linked/mono/bin",
+ ]
+
+ for hint_dir in hint_dirs:
+ hint_path = os.path.join(hint_dir, "msbuild")
+ if os.path.isfile(hint_path):
+ return hint_path
+ elif os.path.isfile(hint_path + ".exe"):
+ return hint_path + ".exe"
+
+ for hint_dir in os.environ["PATH"].split(os.pathsep):
+ hint_dir = hint_dir.strip('"')
+ hint_path = os.path.join(hint_dir, "msbuild")
+ if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
+ return hint_path
+ if os.path.isfile(hint_path + ".exe") and os.access(hint_path + ".exe", os.X_OK):
+ return hint_path + ".exe"
+
+ return None
+
+
+def find_msbuild_tools_path_reg():
+ import subprocess
+
+ program_files = os.getenv("PROGRAMFILES(X86)")
+ if not program_files:
+ program_files = os.getenv("PROGRAMFILES")
+ vswhere = os.path.join(program_files, "Microsoft Visual Studio", "Installer", "vswhere.exe")
+
+ vswhere_args = ["-latest", "-products", "*", "-requires", "Microsoft.Component.MSBuild"]
+
+ try:
+ lines = subprocess.check_output([vswhere] + vswhere_args).splitlines()
+
+ for line in lines:
+ parts = line.decode("utf-8").split(":", 1)
+
+ if len(parts) < 2 or parts[0] != "installationPath":
+ continue
+
+ val = parts[1].strip()
+
+ if not val:
+ raise ValueError("Value of `installationPath` entry is empty")
+
+ # Since VS2019, the directory is simply named "Current"
+ msbuild_dir = os.path.join(val, "MSBuild", "Current", "Bin")
+ if os.path.isdir(msbuild_dir):
+ return msbuild_dir
+
+ # Directory name "15.0" is used in VS 2017
+ return os.path.join(val, "MSBuild", "15.0", "Bin")
+
+ raise ValueError("Cannot find `installationPath` entry")
+ except ValueError as e:
+ print("Error reading output from vswhere: " + str(e))
+ except OSError:
+ pass # Fine, vswhere not found
+ except (subprocess.CalledProcessError, OSError):
+ pass
+
+
+@dataclass
+class ToolsLocation:
+ dotnet_cli: str = ""
+ msbuild_standalone: str = ""
+ msbuild_mono: str = ""
+ mono_bin_dir: str = ""
+
+
+def find_any_msbuild_tool(mono_prefix):
+ # Preference order: dotnet CLI > Standalone MSBuild > Mono's MSBuild
+
+ # Find dotnet CLI
+ dotnet_cli = find_dotnet_cli()
+ if dotnet_cli:
+ return ToolsLocation(dotnet_cli=dotnet_cli)
+
+ # Find standalone MSBuild
+ if os.name == "nt":
+ msbuild_standalone = find_msbuild_standalone_windows()
+ if msbuild_standalone:
+ return ToolsLocation(msbuild_standalone=msbuild_standalone)
+
+ if mono_prefix:
+ # Find Mono's MSBuild
+ if os.name == "nt":
+ msbuild_mono = find_msbuild_mono_windows(mono_prefix)
+ if msbuild_mono:
+ return ToolsLocation(msbuild_mono=msbuild_mono)
+ else:
+ msbuild_mono = find_msbuild_mono_unix()
+ if msbuild_mono:
+ return ToolsLocation(msbuild_mono=msbuild_mono)
+
+ return None
+
+
+def run_msbuild(tools: ToolsLocation, sln: str, msbuild_args: [str] = None):
+ if msbuild_args is None:
+ msbuild_args = []
+
+ using_msbuild_mono = False
+
+ # Preference order: dotnet CLI > Standalone MSBuild > Mono's MSBuild
+ if tools.dotnet_cli:
+ args = [tools.dotnet_cli, "msbuild"]
+ elif tools.msbuild_standalone:
+ args = [tools.msbuild_standalone]
+ elif tools.msbuild_mono:
+ args = [tools.msbuild_mono]
+ using_msbuild_mono = True
+ else:
+ raise RuntimeError("Path to MSBuild or dotnet CLI not provided.")
+
+ args += [sln]
+
+ if len(msbuild_args) > 0:
+ args += msbuild_args
+
+ print("Running MSBuild: ", " ".join(shlex.quote(arg) for arg in args), flush=True)
+
+ msbuild_env = os.environ.copy()
+
+ # Needed when running from Developer Command Prompt for VS
+ if "PLATFORM" in msbuild_env:
+ del msbuild_env["PLATFORM"]
+
+ if using_msbuild_mono:
+ # The (Csc/Vbc/Fsc)ToolExe environment variables are required when
+ # building with Mono's MSBuild. They must point to the batch files
+ # in Mono's bin directory to make sure they are executed with Mono.
+ msbuild_env.update(
+ {
+ "CscToolExe": os.path.join(tools.mono_bin_dir, "csc.bat"),
+ "VbcToolExe": os.path.join(tools.mono_bin_dir, "vbc.bat"),
+ "FscToolExe": os.path.join(tools.mono_bin_dir, "fsharpc.bat"),
+ }
+ )
+
+ return subprocess.call(args, env=msbuild_env)
+
+
+def build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local):
+ target_filenames = [
+ "GodotSharp.dll",
+ "GodotSharp.pdb",
+ "GodotSharp.xml",
+ "GodotSharpEditor.dll",
+ "GodotSharpEditor.pdb",
+ "GodotSharpEditor.xml",
+ "GodotPlugins.dll",
+ "GodotPlugins.pdb",
+ "GodotPlugins.runtimeconfig.json",
+ ]
+
+ for build_config in ["Debug", "Release"]:
+ editor_api_dir = os.path.join(output_dir, "GodotSharp", "Api", build_config)
+
+ targets = [os.path.join(editor_api_dir, filename) for filename in target_filenames]
+
+ args = ["/restore", "/t:Build", "/p:Configuration=" + build_config, "/p:NoWarn=1591"]
+ if push_nupkgs_local:
+ args += ["/p:ClearNuGetLocalCache=true", "/p:PushNuGetToLocalSource=" + push_nupkgs_local]
+
+ sln = os.path.join(module_dir, "glue/GodotSharp/GodotSharp.sln")
+ exit_code = run_msbuild(
+ msbuild_tool,
+ sln=sln,
+ msbuild_args=args,
+ )
+ if exit_code != 0:
+ return exit_code
+
+ # Copy targets
+
+ core_src_dir = os.path.abspath(os.path.join(sln, os.pardir, "GodotSharp", "bin", build_config))
+ editor_src_dir = os.path.abspath(os.path.join(sln, os.pardir, "GodotSharpEditor", "bin", build_config))
+ plugins_src_dir = os.path.abspath(os.path.join(sln, os.pardir, "GodotPlugins", "bin", build_config, "net6.0"))
+
+ if not os.path.isdir(editor_api_dir):
+ assert not os.path.isfile(editor_api_dir)
+ os.makedirs(editor_api_dir)
+
+ def copy_target(target_path):
+ from shutil import copy
+
+ filename = os.path.basename(target_path)
+
+ src_path = os.path.join(core_src_dir, filename)
+ if not os.path.isfile(src_path):
+ src_path = os.path.join(editor_src_dir, filename)
+ if not os.path.isfile(src_path):
+ src_path = os.path.join(plugins_src_dir, filename)
+
+ print(f"Copying assembly to {target_path}...")
+ copy(src_path, target_path)
+
+ for scons_target in targets:
+ copy_target(scons_target)
+
+ return 0
+
+
+def build_all(msbuild_tool, module_dir, output_dir, godot_platform, dev_debug, push_nupkgs_local):
+ # Godot API
+ exit_code = build_godot_api(msbuild_tool, module_dir, output_dir, push_nupkgs_local)
+ if exit_code != 0:
+ return exit_code
+
+ # GodotTools
+ sln = os.path.join(module_dir, "editor/GodotTools/GodotTools.sln")
+ args = ["/restore", "/t:Build", "/p:Configuration=" + ("Debug" if dev_debug else "Release")] + (
+ ["/p:GodotPlatform=" + godot_platform] if godot_platform else []
+ )
+ if push_nupkgs_local:
+ args += ["/p:ClearNuGetLocalCache=true", "/p:PushNuGetToLocalSource=" + push_nupkgs_local]
+ exit_code = run_msbuild(msbuild_tool, sln=sln, msbuild_args=args)
+ if exit_code != 0:
+ return exit_code
+
+ # Godot.NET.Sdk
+ args = ["/restore", "/t:Build", "/p:Configuration=Release"]
+ if push_nupkgs_local:
+ args += ["/p:ClearNuGetLocalCache=true", "/p:PushNuGetToLocalSource=" + push_nupkgs_local]
+ sln = os.path.join(module_dir, "editor/Godot.NET.Sdk/Godot.NET.Sdk.sln")
+ exit_code = run_msbuild(msbuild_tool, sln=sln, msbuild_args=args)
+ if exit_code != 0:
+ return exit_code
+
+ return 0
+
+
+def main():
+ import argparse
+ import sys
+
+ parser = argparse.ArgumentParser(description="Builds all Godot .NET solutions")
+ parser.add_argument("--godot-output-dir", type=str, required=True)
+ parser.add_argument(
+ "--dev-debug",
+ action="store_true",
+ default=False,
+ help="Build GodotTools and Godot.NET.Sdk with 'Configuration=Debug'",
+ )
+ parser.add_argument("--godot-platform", type=str, default="")
+ parser.add_argument("--mono-prefix", type=str, default="")
+ parser.add_argument("--push-nupkgs-local", type=str, default="")
+
+ args = parser.parse_args()
+
+ this_script_dir = os.path.dirname(os.path.realpath(__file__))
+ module_dir = os.path.abspath(os.path.join(this_script_dir, os.pardir))
+
+ output_dir = os.path.abspath(args.godot_output_dir)
+
+ msbuild_tool = find_any_msbuild_tool(args.mono_prefix)
+
+ if msbuild_tool is None:
+ print("Unable to find MSBuild")
+ sys.exit(1)
+
+ exit_code = build_all(
+ msbuild_tool,
+ module_dir,
+ output_dir,
+ args.godot_platform,
+ args.dev_debug,
+ args.push_nupkgs_local,
+ )
+ sys.exit(exit_code)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/modules/mono/build_scripts/gen_cs_glue_version.py b/modules/mono/build_scripts/gen_cs_glue_version.py
deleted file mode 100644
index 98bbb4d9be..0000000000
--- a/modules/mono/build_scripts/gen_cs_glue_version.py
+++ /dev/null
@@ -1,20 +0,0 @@
-def generate_header(solution_dir, version_header_dst):
- import os
-
- latest_mtime = 0
- for root, dirs, files in os.walk(solution_dir, topdown=True):
- dirs[:] = [d for d in dirs if d not in ["Generated"]] # Ignored generated files
- files = [f for f in files if f.endswith(".cs")]
- for file in files:
- filepath = os.path.join(root, file)
- mtime = os.path.getmtime(filepath)
- latest_mtime = mtime if mtime > latest_mtime else latest_mtime
-
- glue_version = int(latest_mtime) # The latest modified time will do for now
-
- with open(version_header_dst, "w") as version_header:
- version_header.write("/* THIS FILE IS GENERATED DO NOT EDIT */\n")
- version_header.write("#ifndef CS_GLUE_VERSION_H\n")
- version_header.write("#define CS_GLUE_VERSION_H\n\n")
- version_header.write("#define CS_GLUE_VERSION UINT32_C(" + str(glue_version) + ")\n")
- version_header.write("\n#endif // CS_GLUE_VERSION_H\n")
diff --git a/modules/mono/build_scripts/godot_net_sdk_build.py b/modules/mono/build_scripts/godot_net_sdk_build.py
deleted file mode 100644
index 8c5a60d2db..0000000000
--- a/modules/mono/build_scripts/godot_net_sdk_build.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# Build Godot.NET.Sdk solution
-
-import os
-
-from SCons.Script import Dir
-
-
-def build_godot_net_sdk(source, target, env):
- # source and target elements are of type SCons.Node.FS.File, hence why we convert them to str
-
- module_dir = env["module_dir"]
-
- solution_path = os.path.join(module_dir, "editor/Godot.NET.Sdk/Godot.NET.Sdk.sln")
- build_config = "Release"
-
- from .solution_builder import build_solution
-
- extra_msbuild_args = ["/p:GodotPlatform=" + env["platform"]]
-
- build_solution(env, solution_path, build_config, extra_msbuild_args)
- # No need to copy targets. The Godot.NET.Sdk csproj takes care of copying them.
-
-
-def get_nupkgs_versions(props_file):
- import xml.etree.ElementTree as ET
-
- tree = ET.parse(props_file)
- root = tree.getroot()
-
- return {
- "Godot.NET.Sdk": root.find("./PropertyGroup/PackageVersion_Godot_NET_Sdk").text.strip(),
- "Godot.SourceGenerators": root.find("./PropertyGroup/PackageVersion_Godot_SourceGenerators").text.strip(),
- }
-
-
-def build(env_mono):
- assert env_mono["tools"]
-
- output_dir = Dir("#bin").abspath
- editor_tools_dir = os.path.join(output_dir, "GodotSharp", "Tools")
- nupkgs_dir = os.path.join(editor_tools_dir, "nupkgs")
-
- module_dir = os.getcwd()
-
- nupkgs_versions = get_nupkgs_versions(os.path.join(module_dir, "SdkPackageVersions.props"))
-
- target_filenames = [
- "Godot.NET.Sdk.%s.nupkg" % nupkgs_versions["Godot.NET.Sdk"],
- "Godot.SourceGenerators.%s.nupkg" % nupkgs_versions["Godot.SourceGenerators"],
- ]
-
- targets = [os.path.join(nupkgs_dir, filename) for filename in target_filenames]
-
- cmd = env_mono.CommandNoCache(targets, [], build_godot_net_sdk, module_dir=module_dir)
- env_mono.AlwaysBuild(cmd)
diff --git a/modules/mono/build_scripts/godot_tools_build.py b/modules/mono/build_scripts/godot_tools_build.py
deleted file mode 100644
index 3bbbf29d3b..0000000000
--- a/modules/mono/build_scripts/godot_tools_build.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# Build GodotTools solution
-
-import os
-
-from SCons.Script import Dir
-
-
-def build_godot_tools(source, target, env):
- # source and target elements are of type SCons.Node.FS.File, hence why we convert them to str
-
- module_dir = env["module_dir"]
-
- solution_path = os.path.join(module_dir, "editor/GodotTools/GodotTools.sln")
- build_config = "Debug" if env["target"] == "debug" else "Release"
-
- from .solution_builder import build_solution
-
- extra_msbuild_args = ["/p:GodotPlatform=" + env["platform"]]
-
- build_solution(env, solution_path, build_config, extra_msbuild_args)
- # No need to copy targets. The GodotTools csproj takes care of copying them.
-
-
-def build(env_mono, api_sln_cmd):
- assert env_mono["tools"]
-
- output_dir = Dir("#bin").abspath
- editor_tools_dir = os.path.join(output_dir, "GodotSharp", "Tools")
-
- target_filenames = ["GodotTools.dll"]
-
- if env_mono["target"] == "debug":
- target_filenames += ["GodotTools.pdb"]
-
- targets = [os.path.join(editor_tools_dir, filename) for filename in target_filenames]
-
- cmd = env_mono.CommandNoCache(targets, api_sln_cmd, build_godot_tools, module_dir=os.getcwd())
- env_mono.AlwaysBuild(cmd)
diff --git a/modules/mono/build_scripts/make_android_mono_config.py b/modules/mono/build_scripts/make_android_mono_config.py
deleted file mode 100644
index 3459244bc2..0000000000
--- a/modules/mono/build_scripts/make_android_mono_config.py
+++ /dev/null
@@ -1,55 +0,0 @@
-def generate_compressed_config(config_src, output_dir):
- import os.path
-
- # Source file
- with open(os.path.join(output_dir, "android_mono_config.gen.cpp"), "w") as cpp:
- with open(config_src, "rb") as f:
- buf = f.read()
- decompr_size = len(buf)
- import zlib
-
- # Use maximum zlib compression level to further reduce file size
- # (at the cost of initial build times).
- buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION)
- compr_size = len(buf)
-
- bytes_seq_str = ""
- for i, buf_idx in enumerate(range(compr_size)):
- if i > 0:
- bytes_seq_str += ", "
- bytes_seq_str += str(buf[buf_idx])
-
- cpp.write(
- """/* THIS FILE IS GENERATED DO NOT EDIT */
-#include "android_mono_config.h"
-
-#ifdef ANDROID_ENABLED
-
-#include "core/io/compression.h"
-
-
-namespace {
-
-// config
-static const int config_compressed_size = %d;
-static const int config_uncompressed_size = %d;
-static const unsigned char config_compressed_data[] = { %s };
-} // namespace
-
-String get_godot_android_mono_config() {
- Vector<uint8_t> data;
- data.resize(config_uncompressed_size);
- uint8_t* w = data.ptrw();
- Compression::decompress(w, config_uncompressed_size, config_compressed_data,
- config_compressed_size, Compression::MODE_DEFLATE);
- String s;
- if (s.parse_utf8((const char *)w, data.size()) != OK) {
- ERR_FAIL_V(String());
- }
- return s;
-}
-
-#endif // ANDROID_ENABLED
-"""
- % (compr_size, decompr_size, bytes_seq_str)
- )
diff --git a/modules/mono/build_scripts/mono_android_config.xml b/modules/mono/build_scripts/mono_android_config.xml
deleted file mode 100644
index e79670afd2..0000000000
--- a/modules/mono/build_scripts/mono_android_config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<configuration>
- <dllmap wordsize="32" dll="i:cygwin1.dll" target="/system/lib/libc.so" />
- <dllmap wordsize="64" dll="i:cygwin1.dll" target="/system/lib64/libc.so" />
- <dllmap wordsize="32" dll="libc" target="/system/lib/libc.so" />
- <dllmap wordsize="64" dll="libc" target="/system/lib64/libc.so" />
- <dllmap wordsize="32" dll="intl" target="/system/lib/libc.so" />
- <dllmap wordsize="64" dll="intl" target="/system/lib64/libc.so" />
- <dllmap wordsize="32" dll="libintl" target="/system/lib/libc.so" />
- <dllmap wordsize="64" dll="libintl" target="/system/lib64/libc.so" />
- <dllmap dll="MonoPosixHelper" target="libMonoPosixHelper.so" />
- <dllmap dll="System.Native" target="libmono-native.so" />
- <dllmap wordsize="32" dll="i:msvcrt" target="/system/lib/libc.so" />
- <dllmap wordsize="64" dll="i:msvcrt" target="/system/lib64/libc.so" />
- <dllmap wordsize="32" dll="i:msvcrt.dll" target="/system/lib/libc.so" />
- <dllmap wordsize="64" dll="i:msvcrt.dll" target="/system/lib64/libc.so" />
- <dllmap wordsize="32" dll="sqlite" target="/system/lib/libsqlite.so" />
- <dllmap wordsize="64" dll="sqlite" target="/system/lib64/libsqlite.so" />
- <dllmap wordsize="32" dll="sqlite3" target="/system/lib/libsqlite.so" />
- <dllmap wordsize="64" dll="sqlite3" target="/system/lib64/libsqlite.so" />
- <dllmap wordsize="32" dll="liblog" target="/system/lib/liblog.so" />
- <dllmap wordsize="64" dll="liblog" target="/system/lib64/liblog.so" />
- <dllmap dll="i:kernel32.dll">
- <dllentry dll="__Internal" name="CopyMemory" target="mono_win32_compat_CopyMemory"/>
- <dllentry dll="__Internal" name="FillMemory" target="mono_win32_compat_FillMemory"/>
- <dllentry dll="__Internal" name="MoveMemory" target="mono_win32_compat_MoveMemory"/>
- <dllentry dll="__Internal" name="ZeroMemory" target="mono_win32_compat_ZeroMemory"/>
- </dllmap>
-</configuration>
diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py
index e69904c54b..c2d5452837 100644
--- a/modules/mono/build_scripts/mono_configure.py
+++ b/modules/mono/build_scripts/mono_configure.py
@@ -1,574 +1,319 @@
import os
import os.path
-import subprocess
-
-from SCons.Script import Dir, Environment
-
-if os.name == "nt":
- from . import mono_reg_utils as monoreg
-
-
-android_arch_dirs = {
- "armv7": "armeabi-v7a",
- "arm64v8": "arm64-v8a",
- "x86": "x86",
- "x86_64": "x86_64",
-}
-
-
-def get_android_out_dir(env):
- return os.path.join(
- Dir("#platform/android/java/lib/libs").abspath,
- "release" if env["target"] == "release" else "debug",
- android_arch_dirs[env["android_arch"]],
- )
-
-
-def find_name_in_dir_files(directory, names, prefixes=[""], extensions=[""]):
- for extension in extensions:
- if extension and not extension.startswith("."):
- extension = "." + extension
- for prefix in prefixes:
- for curname in names:
- if os.path.isfile(os.path.join(directory, prefix + curname + extension)):
- return curname
- return ""
-
-
-def find_file_in_dir(directory, names, prefixes=[""], extensions=[""]):
- for extension in extensions:
- if extension and not extension.startswith("."):
- extension = "." + extension
- for prefix in prefixes:
- for curname in names:
- filename = prefix + curname + extension
- if os.path.isfile(os.path.join(directory, filename)):
- return filename
- return ""
-
-
-def copy_file(src_dir, dst_dir, src_name, dst_name=""):
- from shutil import copy
-
- src_path = os.path.join(Dir(src_dir).abspath, src_name)
- dst_dir = Dir(dst_dir).abspath
-
- if not os.path.isdir(dst_dir):
- os.makedirs(dst_dir)
-
- if dst_name:
- copy(src_path, os.path.join(dst_dir, dst_name))
- else:
- copy(src_path, dst_dir)
def is_desktop(platform):
- return platform in ["windows", "macos", "linuxbsd", "server", "uwp", "haiku"]
+ return platform in ["windows", "macos", "linuxbsd", "uwp", "haiku"]
def is_unix_like(platform):
- return platform in ["macos", "linuxbsd", "server", "android", "haiku", "ios"]
+ return platform in ["macos", "linuxbsd", "android", "haiku", "ios"]
def module_supports_tools_on(platform):
- return platform not in ["android", "javascript", "ios"]
-
-
-def find_wasm_src_dir(mono_root):
- hint_dirs = [
- os.path.join(mono_root, "src"),
- os.path.join(mono_root, "../src"),
- ]
- for hint_dir in hint_dirs:
- if os.path.isfile(os.path.join(hint_dir, "driver.c")):
- return hint_dir
- return ""
+ return is_desktop(platform)
def configure(env, env_mono):
- bits = env["bits"]
- is_android = env["platform"] == "android"
- is_javascript = env["platform"] == "javascript"
- is_ios = env["platform"] == "ios"
- is_ios_sim = is_ios and env["arch"] in ["x86", "x86_64"]
+ # is_android = env["platform"] == "android"
+ # is_web = env["platform"] == "web"
+ # is_ios = env["platform"] == "ios"
+ # is_ios_sim = is_ios and env["arch"] in ["x86_32", "x86_64"]
tools_enabled = env["tools"]
- mono_static = env["mono_static"]
- copy_mono_root = env["copy_mono_root"]
-
- mono_prefix = env["mono_prefix"]
- mono_bcl = env["mono_bcl"]
-
- mono_lib_names = ["mono-2.0-sgen", "monosgen-2.0"]
-
- if is_android and not env["android_arch"] in android_arch_dirs:
- raise RuntimeError("This module does not support the specified 'android_arch': " + env["android_arch"])
if tools_enabled and not module_supports_tools_on(env["platform"]):
- # TODO:
- # Android: We have to add the data directory to the apk, concretely the Api and Tools folders.
raise RuntimeError("This module does not currently support building for this platform with tools enabled")
- if is_android and mono_static:
- # FIXME: When static linking and doing something that requires libmono-native, we get a dlopen error as 'libmono-native'
- # seems to depend on 'libmonosgen-2.0'. Could be fixed by re-directing to '__Internal' with a dllmap or in the dlopen hook.
- raise RuntimeError("Statically linking Mono is not currently supported for this platform")
-
- if not mono_static and (is_javascript or is_ios):
- raise RuntimeError("Dynamically linking Mono is not currently supported for this platform")
-
- if not mono_prefix and (os.getenv("MONO32_PREFIX") or os.getenv("MONO64_PREFIX")):
- print(
- "WARNING: The environment variables 'MONO32_PREFIX' and 'MONO64_PREFIX' are deprecated; use the"
- " 'mono_prefix' SCons parameter instead"
- )
-
- # Although we don't support building with tools for any platform where we currently use static AOT,
- # if these are supported in the future, we won't be using static AOT for them as that would be
- # too restrictive for the editor. These builds would probably be made to only use the interpreter.
- mono_aot_static = (is_ios and not is_ios_sim) and not env["tools"]
-
- # Static AOT is only supported on the root domain
- mono_single_appdomain = mono_aot_static
-
- if mono_single_appdomain:
- env_mono.Append(CPPDEFINES=["GD_MONO_SINGLE_APPDOMAIN"])
-
- if (env["tools"] or env["target"] != "release") and not mono_single_appdomain:
+ if env["tools"]:
env_mono.Append(CPPDEFINES=["GD_MONO_HOT_RELOAD"])
- if env["platform"] == "windows":
- mono_root = mono_prefix
-
- if not mono_root and os.name == "nt":
- mono_root = monoreg.find_mono_root_dir(bits)
-
- if not mono_root:
- raise RuntimeError(
- "Mono installation directory not found; specify one manually with the 'mono_prefix' SCons parameter"
- )
-
- print("Found Mono root directory: " + mono_root)
+ app_host_dir = find_dotnet_app_host_dir(env)
- mono_lib_path = os.path.join(mono_root, "lib")
+ def check_app_host_file_exists(file):
+ file_path = os.path.join(app_host_dir, file)
+ if not os.path.isfile(file_path):
+ raise RuntimeError("File not found: " + file_path)
- env.Append(LIBPATH=mono_lib_path)
- env_mono.Prepend(CPPPATH=os.path.join(mono_root, "include", "mono-2.0"))
+ # TODO:
+ # All libnethost does for us is provide a function to find hostfxr.
+ # If we could handle that logic ourselves we could void linking it.
- lib_suffixes = [".lib"]
+ # nethost file names:
+ # static: libnethost.a/lib
+ # shared: libnethost.a/dylib and nethost.dll
+ check_app_host_file_exists("libnethost.lib" if os.name == "nt" else "libnethost.a")
+ check_app_host_file_exists("nethost.h")
+ check_app_host_file_exists("hostfxr.h")
+ check_app_host_file_exists("coreclr_delegates.h")
- if not env.msvc:
- # MingW supports both '.a' and '.lib'
- lib_suffixes.insert(0, ".a")
+ env_mono.Prepend(CPPPATH=app_host_dir)
- if mono_static:
- if env.msvc:
- mono_static_lib_name = "libmono-static-sgen"
- else:
- mono_static_lib_name = "libmonosgen-2.0"
+ env.Append(LIBPATH=[app_host_dir])
- mono_static_lib_file = find_file_in_dir(mono_lib_path, [mono_static_lib_name], extensions=lib_suffixes)
+ # Only the editor build links nethost, which is needed to find hostfxr.
+ # Exported games don't need this logic as hostfxr is bundled with them.
+ if tools_enabled:
+ libnethost_path = os.path.join(app_host_dir, "libnethost.lib" if os.name == "nt" else "libnethost.a")
- if not mono_static_lib_file:
- raise RuntimeError("Could not find static mono library in: " + mono_lib_path)
+ if env["platform"] == "windows":
+ env_mono.Append(CPPDEFINES=["NETHOST_USE_AS_STATIC"])
if env.msvc:
- env.Append(LINKFLAGS=mono_static_lib_file)
-
- env.Append(LINKFLAGS="Mincore.lib")
- env.Append(LINKFLAGS="msvcrt.lib")
- env.Append(LINKFLAGS="LIBCMT.lib")
- env.Append(LINKFLAGS="Psapi.lib")
+ env.Append(LINKFLAGS="libnethost.lib")
else:
- mono_static_lib_file_path = os.path.join(mono_lib_path, mono_static_lib_file)
- env.Append(LINKFLAGS=["-Wl,-whole-archive", mono_static_lib_file_path, "-Wl,-no-whole-archive"])
-
- env.Append(LIBS=["psapi"])
- env.Append(LIBS=["version"])
+ env.Append(LINKFLAGS=["-Wl,-whole-archive", libnethost_path, "-Wl,-no-whole-archive"])
else:
- mono_lib_file = find_file_in_dir(mono_lib_path, mono_lib_names, extensions=lib_suffixes)
+ is_apple = env["platform"] in ["macos", "ios"]
+ # is_macos = is_apple and not is_ios
- if not mono_lib_file:
- raise RuntimeError("Could not find mono library in: " + mono_lib_path)
+ # if is_ios and not is_ios_sim:
+ # env_mono.Append(CPPDEFINES=["IOS_DEVICE"])
- if env.msvc:
- env.Append(LINKFLAGS=mono_lib_file)
+ if is_apple:
+ env.Append(LINKFLAGS=["-Wl,-force_load," + libnethost_path])
else:
- mono_lib_file_path = os.path.join(mono_lib_path, mono_lib_file)
- env.Append(LINKFLAGS=mono_lib_file_path)
+ env.Append(LINKFLAGS=["-Wl,-whole-archive", libnethost_path, "-Wl,-no-whole-archive"])
- mono_bin_path = os.path.join(mono_root, "bin")
- mono_dll_file = find_file_in_dir(mono_bin_path, mono_lib_names, prefixes=["", "lib"], extensions=[".dll"])
+def find_dotnet_app_host_dir(env):
+ dotnet_version = "6.0"
- if not mono_dll_file:
- raise RuntimeError("Could not find mono shared library in: " + mono_bin_path)
+ dotnet_root = env["dotnet_root"]
- copy_file(mono_bin_path, "#bin", mono_dll_file)
- else:
- is_apple = env["platform"] in ["macos", "ios"]
- is_macos = is_apple and not is_ios
-
- sharedlib_ext = ".dylib" if is_apple else ".so"
-
- mono_root = mono_prefix
- mono_lib_path = ""
- mono_so_file = ""
-
- if not mono_root and (is_android or is_javascript or is_ios):
- raise RuntimeError(
- "Mono installation directory not found; specify one manually with the 'mono_prefix' SCons parameter"
- )
-
- if not mono_root and is_macos:
- # Try with some known directories under macOS
- hint_dirs = ["/Library/Frameworks/Mono.framework/Versions/Current", "/usr/local/var/homebrew/linked/mono"]
- for hint_dir in hint_dirs:
- if os.path.isdir(hint_dir):
- mono_root = hint_dir
- break
-
- # We can't use pkg-config to link mono statically,
- # but we can still use it to find the mono root directory
- if not mono_root and mono_static:
- mono_root = pkgconfig_try_find_mono_root(mono_lib_names, sharedlib_ext)
- if not mono_root:
- raise RuntimeError(
- "Building with mono_static=yes, but failed to find the mono prefix with pkg-config; "
- + "specify one manually with the 'mono_prefix' SCons parameter"
- )
-
- if is_ios and not is_ios_sim:
- env_mono.Append(CPPDEFINES=["IOS_DEVICE"])
-
- if mono_root:
- print("Found Mono root directory: " + mono_root)
-
- mono_lib_path = os.path.join(mono_root, "lib")
-
- env.Append(LIBPATH=[mono_lib_path])
- env_mono.Prepend(CPPPATH=os.path.join(mono_root, "include", "mono-2.0"))
-
- mono_lib = find_name_in_dir_files(mono_lib_path, mono_lib_names, prefixes=["lib"], extensions=[".a"])
-
- if not mono_lib:
- raise RuntimeError("Could not find mono library in: " + mono_lib_path)
-
- env_mono.Append(CPPDEFINES=["_REENTRANT"])
-
- if mono_static:
- if not is_javascript:
- env.Append(LINKFLAGS=["-rdynamic"])
-
- mono_lib_file = os.path.join(mono_lib_path, "lib" + mono_lib + ".a")
-
- if is_apple:
- if is_macos:
- env.Append(LINKFLAGS=["-Wl,-force_load," + mono_lib_file])
- else:
- arch = env["arch"]
-
- def copy_mono_lib(libname_wo_ext):
- copy_file(
- mono_lib_path, "#bin", libname_wo_ext + ".a", "%s.ios.%s.a" % (libname_wo_ext, arch)
- )
-
- # Copy Mono libraries to the output folder. These are meant to be bundled with
- # the export templates and added to the Xcode project when exporting a game.
- copy_mono_lib("lib" + mono_lib)
- copy_mono_lib("libmono-native")
- copy_mono_lib("libmono-profiler-log")
-
- if not is_ios_sim:
- copy_mono_lib("libmono-ee-interp")
- copy_mono_lib("libmono-icall-table")
- copy_mono_lib("libmono-ilgen")
- else:
- assert is_desktop(env["platform"]) or is_android or is_javascript
- env.Append(LINKFLAGS=["-Wl,-whole-archive", mono_lib_file, "-Wl,-no-whole-archive"])
-
- if is_javascript:
- env.Append(LIBS=["mono-icall-table", "mono-native", "mono-ilgen", "mono-ee-interp"])
-
- wasm_src_dir = os.path.join(mono_root, "src")
- if not os.path.isdir(wasm_src_dir):
- raise RuntimeError("Could not find mono wasm src directory")
-
- # Ideally this should be defined only for 'driver.c', but I can't fight scons for another 2 hours
- env_mono.Append(CPPDEFINES=["CORE_BINDINGS"])
-
- env_mono.add_source_files(
- env.modules_sources,
- [
- os.path.join(wasm_src_dir, "driver.c"),
- os.path.join(wasm_src_dir, "zlib-helper.c"),
- os.path.join(wasm_src_dir, "corebindings.c"),
- ],
- )
-
- env.Append(
- LINKFLAGS=[
- "--js-library",
- os.path.join(wasm_src_dir, "library_mono.js"),
- "--js-library",
- os.path.join(wasm_src_dir, "binding_support.js"),
- "--js-library",
- os.path.join(wasm_src_dir, "dotnet_support.js"),
- ]
- )
- else:
- env.Append(LIBS=[mono_lib])
-
- if is_macos:
- env.Append(LIBS=["iconv", "pthread"])
- elif is_android:
- pass # Nothing
- elif is_ios:
- pass # Nothing, linking is delegated to the exported Xcode project
- elif is_javascript:
- env.Append(LIBS=["m", "rt", "dl", "pthread"])
- else:
- env.Append(LIBS=["m", "rt", "dl", "pthread"])
+ if not dotnet_root:
+ dotnet_cmd = find_dotnet_executable(env["arch"])
+ if dotnet_cmd:
+ sdk_path = find_dotnet_sdk(dotnet_cmd, dotnet_version)
+ if sdk_path:
+ dotnet_root = os.path.abspath(os.path.join(sdk_path, os.pardir))
- if not mono_static:
- mono_so_file = find_file_in_dir(
- mono_lib_path, mono_lib_names, prefixes=["lib"], extensions=[sharedlib_ext]
- )
+ if not dotnet_root:
+ raise RuntimeError("Cannot find .NET Core Sdk")
- if not mono_so_file:
- raise RuntimeError("Could not find mono shared library in: " + mono_lib_path)
- else:
- assert not mono_static
+ print("Found .NET Core Sdk root directory: " + dotnet_root)
- # TODO: Add option to force using pkg-config
- print("Mono root directory not found. Using pkg-config instead")
+ dotnet_cmd = os.path.join(dotnet_root, "dotnet.exe" if os.name == "nt" else "dotnet")
- env.ParseConfig("pkg-config monosgen-2 --libs")
- env_mono.ParseConfig("pkg-config monosgen-2 --cflags")
+ runtime_identifier = determine_runtime_identifier(env)
- tmpenv = Environment()
- tmpenv.AppendENVPath("PKG_CONFIG_PATH", os.getenv("PKG_CONFIG_PATH"))
- tmpenv.ParseConfig("pkg-config monosgen-2 --libs-only-L")
+ # TODO: In the future, if it can't be found this way, we want to obtain it
+ # from the runtime.{runtime_identifier}.Microsoft.NETCore.DotNetAppHost NuGet package.
+ app_host_version = find_app_host_version(dotnet_cmd, dotnet_version)
+ if not app_host_version:
+ raise RuntimeError("Cannot find .NET app host for version: " + dotnet_version)
- for hint_dir in tmpenv["LIBPATH"]:
- file_found = find_file_in_dir(hint_dir, mono_lib_names, prefixes=["lib"], extensions=[sharedlib_ext])
- if file_found:
- mono_lib_path = hint_dir
- mono_so_file = file_found
- break
+ def get_runtime_path():
+ return os.path.join(
+ dotnet_root,
+ "packs",
+ "Microsoft.NETCore.App.Host." + runtime_identifier,
+ app_host_version,
+ "runtimes",
+ runtime_identifier,
+ "native",
+ )
- if not mono_so_file:
- raise RuntimeError("Could not find mono shared library in: " + str(tmpenv["LIBPATH"]))
+ app_host_dir = get_runtime_path()
+
+ # Some Linux distros use their distro name as the RID in these paths.
+ # If the initial generic path doesn't exist, try to get the RID from `dotnet --info`.
+ # The generic RID should still be the first choice. Some platforms like Windows 10
+ # define the RID as `win10-x64` but still use the generic `win-x64` for directory names.
+ if not app_host_dir or not os.path.isdir(app_host_dir):
+ runtime_identifier = find_dotnet_cli_rid(dotnet_cmd)
+ app_host_dir = get_runtime_path()
+
+ return app_host_dir
+
+
+def determine_runtime_identifier(env):
+ # The keys are Godot's names, the values are the Microsoft's names.
+ # List: https://docs.microsoft.com/en-us/dotnet/core/rid-catalog
+ names_map = {
+ "windows": "win",
+ "macos": "osx",
+ "linuxbsd": "linux",
+ }
+ arch_map = {
+ "x86_64": "x64",
+ "x86_32": "x86",
+ "arm64": "arm64",
+ "arm32": "arm",
+ }
+ platform = env["platform"]
+ if is_desktop(platform):
+ return "%s-%s" % (names_map[platform], arch_map[env["arch"]])
+ else:
+ raise NotImplementedError()
- if not mono_static:
- libs_output_dir = get_android_out_dir(env) if is_android else "#bin"
- copy_file(mono_lib_path, libs_output_dir, mono_so_file)
- if not tools_enabled:
- if is_desktop(env["platform"]):
- if not mono_root:
- mono_root = (
- subprocess.check_output(["pkg-config", "mono-2", "--variable=prefix"]).decode("utf8").strip()
- )
+def find_app_host_version(dotnet_cmd, search_version_str):
+ import subprocess
+ from distutils.version import LooseVersion
- make_template_dir(env, mono_root)
- elif is_android:
- # Compress Android Mono Config
- from . import make_android_mono_config
+ search_version = LooseVersion(search_version_str)
+ found_match = False
- module_dir = os.getcwd()
- config_file_path = os.path.join(module_dir, "build_scripts", "mono_android_config.xml")
- make_android_mono_config.generate_compressed_config(config_file_path, "mono_gd/")
+ try:
+ env = dict(os.environ, DOTNET_CLI_UI_LANGUAGE="en-US")
+ lines = subprocess.check_output([dotnet_cmd, "--list-runtimes"], env=env).splitlines()
- # Copy the required shared libraries
- copy_mono_shared_libs(env, mono_root, None)
- elif is_javascript:
- pass # No data directory for this platform
- elif is_ios:
- pass # No data directory for this platform
+ for line_bytes in lines:
+ line = line_bytes.decode("utf-8")
+ if not line.startswith("Microsoft.NETCore.App "):
+ continue
- if copy_mono_root:
- if not mono_root:
- mono_root = subprocess.check_output(["pkg-config", "mono-2", "--variable=prefix"]).decode("utf8").strip()
+ parts = line.split(" ", 2)
+ if len(parts) < 3:
+ continue
- if tools_enabled:
- # Only supported for editor builds.
- copy_mono_root_files(env, mono_root, mono_bcl)
+ version_str = parts[1]
+ version = LooseVersion(version_str)
-def make_template_dir(env, mono_root):
- from shutil import rmtree
+ if version >= search_version:
+ search_version = version
+ found_match = True
+ if found_match:
+ return str(search_version)
+ except (subprocess.CalledProcessError, OSError) as e:
+ import sys
- platform = env["platform"]
- target = env["target"]
+ print(e, file=sys.stderr)
- template_dir_name = ""
+ return ""
- assert is_desktop(platform)
- template_dir_name = "data.mono.%s.%s.%s" % (platform, env["bits"], target)
+def find_dotnet_arch(dotnet_cmd):
+ import subprocess
- output_dir = Dir("#bin").abspath
- template_dir = os.path.join(output_dir, template_dir_name)
+ try:
+ env = dict(os.environ, DOTNET_CLI_UI_LANGUAGE="en-US")
+ lines = subprocess.check_output([dotnet_cmd, "--info"], env=env).splitlines()
- template_mono_root_dir = os.path.join(template_dir, "Mono")
+ for line_bytes in lines:
+ line = line_bytes.decode("utf-8")
- if os.path.isdir(template_mono_root_dir):
- rmtree(template_mono_root_dir) # Clean first
+ parts = line.split(":", 1)
+ if len(parts) < 2:
+ continue
- # Copy etc/mono/
+ arch_str = parts[0].strip()
+ if arch_str != "Architecture":
+ continue
- template_mono_config_dir = os.path.join(template_mono_root_dir, "etc", "mono")
- copy_mono_etc_dir(mono_root, template_mono_config_dir, platform)
+ arch_value = parts[1].strip()
+ arch_map = {"x64": "x86_64", "x86": "x86_32", "arm64": "arm64", "arm32": "arm32"}
+ return arch_map[arch_value]
+ except (subprocess.CalledProcessError, OSError) as e:
+ import sys
- # Copy the required shared libraries
+ print(e, file=sys.stderr)
- copy_mono_shared_libs(env, mono_root, template_mono_root_dir)
+ return ""
-def copy_mono_root_files(env, mono_root, mono_bcl):
- from glob import glob
- from shutil import copy
- from shutil import rmtree
+def find_dotnet_sdk(dotnet_cmd, search_version_str):
+ import subprocess
+ from distutils.version import LooseVersion
- if not mono_root:
- raise RuntimeError("Mono installation directory not found")
+ search_version = LooseVersion(search_version_str)
- output_dir = Dir("#bin").abspath
- editor_mono_root_dir = os.path.join(output_dir, "GodotSharp", "Mono")
+ try:
+ env = dict(os.environ, DOTNET_CLI_UI_LANGUAGE="en-US")
+ lines = subprocess.check_output([dotnet_cmd, "--list-sdks"], env=env).splitlines()
- if os.path.isdir(editor_mono_root_dir):
- rmtree(editor_mono_root_dir) # Clean first
+ for line_bytes in lines:
+ line = line_bytes.decode("utf-8")
- # Copy etc/mono/
+ parts = line.split(" ", 1)
+ if len(parts) < 2:
+ continue
- editor_mono_config_dir = os.path.join(editor_mono_root_dir, "etc", "mono")
- copy_mono_etc_dir(mono_root, editor_mono_config_dir, env["platform"])
+ version_str = parts[0]
- # Copy the required shared libraries
+ version = LooseVersion(version_str)
- copy_mono_shared_libs(env, mono_root, editor_mono_root_dir)
+ if version < search_version:
+ continue
- # Copy framework assemblies
+ path_part = parts[1]
+ return path_part[1 : path_part.find("]")]
+ except (subprocess.CalledProcessError, OSError) as e:
+ import sys
- mono_framework_dir = mono_bcl or os.path.join(mono_root, "lib", "mono", "4.5")
- mono_framework_facades_dir = os.path.join(mono_framework_dir, "Facades")
+ print(e, file=sys.stderr)
- editor_mono_framework_dir = os.path.join(editor_mono_root_dir, "lib", "mono", "4.5")
- editor_mono_framework_facades_dir = os.path.join(editor_mono_framework_dir, "Facades")
+ return ""
- if not os.path.isdir(editor_mono_framework_dir):
- os.makedirs(editor_mono_framework_dir)
- if not os.path.isdir(editor_mono_framework_facades_dir):
- os.makedirs(editor_mono_framework_facades_dir)
- for assembly in glob(os.path.join(mono_framework_dir, "*.dll")):
- copy(assembly, editor_mono_framework_dir)
- for assembly in glob(os.path.join(mono_framework_facades_dir, "*.dll")):
- copy(assembly, editor_mono_framework_facades_dir)
+def find_dotnet_cli_rid(dotnet_cmd):
+ import subprocess
+ try:
+ env = dict(os.environ, DOTNET_CLI_UI_LANGUAGE="en-US")
+ lines = subprocess.check_output([dotnet_cmd, "--info"], env=env).splitlines()
-def copy_mono_etc_dir(mono_root, target_mono_config_dir, platform):
- from distutils.dir_util import copy_tree
- from glob import glob
- from shutil import copy
+ for line_bytes in lines:
+ line = line_bytes.decode("utf-8")
+ if not line.startswith(" RID:"):
+ continue
- if not os.path.isdir(target_mono_config_dir):
- os.makedirs(target_mono_config_dir)
+ parts = line.split()
+ if len(parts) < 2:
+ continue
- mono_etc_dir = os.path.join(mono_root, "etc", "mono")
- if not os.path.isdir(mono_etc_dir):
- mono_etc_dir = ""
- etc_hint_dirs = []
- if platform != "windows":
- etc_hint_dirs += ["/etc/mono", "/usr/local/etc/mono"]
- if "MONO_CFG_DIR" in os.environ:
- etc_hint_dirs += [os.path.join(os.environ["MONO_CFG_DIR"], "mono")]
- for etc_hint_dir in etc_hint_dirs:
- if os.path.isdir(etc_hint_dir):
- mono_etc_dir = etc_hint_dir
- break
- if not mono_etc_dir:
- raise RuntimeError("Mono installation etc directory not found")
+ return parts[1]
+ except (subprocess.CalledProcessError, OSError) as e:
+ import sys
- copy_tree(os.path.join(mono_etc_dir, "2.0"), os.path.join(target_mono_config_dir, "2.0"))
- copy_tree(os.path.join(mono_etc_dir, "4.0"), os.path.join(target_mono_config_dir, "4.0"))
- copy_tree(os.path.join(mono_etc_dir, "4.5"), os.path.join(target_mono_config_dir, "4.5"))
- if os.path.isdir(os.path.join(mono_etc_dir, "mconfig")):
- copy_tree(os.path.join(mono_etc_dir, "mconfig"), os.path.join(target_mono_config_dir, "mconfig"))
+ print(e, file=sys.stderr)
- for file in glob(os.path.join(mono_etc_dir, "*")):
- if os.path.isfile(file):
- copy(file, target_mono_config_dir)
+ return ""
-def copy_mono_shared_libs(env, mono_root, target_mono_root_dir):
- from shutil import copy
+ENV_PATH_SEP = ";" if os.name == "nt" else ":"
- def copy_if_exists(src, dst):
- if os.path.isfile(src):
- copy(src, dst)
- platform = env["platform"]
+def find_dotnet_executable(arch):
+ is_windows = os.name == "nt"
+ windows_exts = os.environ["PATHEXT"].split(ENV_PATH_SEP) if is_windows else None
+ path_dirs = os.environ["PATH"].split(ENV_PATH_SEP)
- if platform == "windows":
- src_mono_bin_dir = os.path.join(mono_root, "bin")
- target_mono_bin_dir = os.path.join(target_mono_root_dir, "bin")
+ search_dirs = path_dirs + [os.getcwd()] # cwd is last in the list
- if not os.path.isdir(target_mono_bin_dir):
- os.makedirs(target_mono_bin_dir)
+ for dir in path_dirs:
+ search_dirs += [
+ os.path.join(dir, "x64"),
+ os.path.join(dir, "x86"),
+ os.path.join(dir, "arm64"),
+ os.path.join(dir, "arm32"),
+ ] # search subfolders for cross compiling
- mono_posix_helper_file = find_file_in_dir(
- src_mono_bin_dir, ["MonoPosixHelper"], prefixes=["", "lib"], extensions=[".dll"]
- )
- copy(
- os.path.join(src_mono_bin_dir, mono_posix_helper_file),
- os.path.join(target_mono_bin_dir, "MonoPosixHelper.dll"),
- )
+ # `dotnet --info` may not specify architecture. In such cases,
+ # we fallback to the first one we find without architecture.
+ sdk_path_unknown_arch = ""
- # For newer versions
- btls_dll_path = os.path.join(src_mono_bin_dir, "libmono-btls-shared.dll")
- if os.path.isfile(btls_dll_path):
- copy(btls_dll_path, target_mono_bin_dir)
- else:
- target_mono_lib_dir = (
- get_android_out_dir(env) if platform == "android" else os.path.join(target_mono_root_dir, "lib")
- )
+ for dir in search_dirs:
+ path = os.path.join(dir, "dotnet")
- if not os.path.isdir(target_mono_lib_dir):
- os.makedirs(target_mono_lib_dir)
-
- lib_file_names = []
- if platform == "macos":
- lib_file_names = [
- lib_name + ".dylib"
- for lib_name in ["libmono-btls-shared", "libmono-native-compat", "libMonoPosixHelper"]
- ]
- elif is_unix_like(platform):
- lib_file_names = [
- lib_name + ".so"
- for lib_name in [
- "libmono-btls-shared",
- "libmono-ee-interp",
- "libmono-native",
- "libMonoPosixHelper",
- "libmono-profiler-aot",
- "libmono-profiler-coverage",
- "libmono-profiler-log",
- "libMonoSupportW",
- ]
- ]
-
- for lib_file_name in lib_file_names:
- copy_if_exists(os.path.join(mono_root, "lib", lib_file_name), target_mono_lib_dir)
-
-
-def pkgconfig_try_find_mono_root(mono_lib_names, sharedlib_ext):
- tmpenv = Environment()
- tmpenv.AppendENVPath("PKG_CONFIG_PATH", os.getenv("PKG_CONFIG_PATH"))
- tmpenv.ParseConfig("pkg-config monosgen-2 --libs-only-L")
- for hint_dir in tmpenv["LIBPATH"]:
- name_found = find_name_in_dir_files(hint_dir, mono_lib_names, prefixes=["lib"], extensions=[sharedlib_ext])
- if name_found and os.path.isdir(os.path.join(hint_dir, "..", "include", "mono-2.0")):
- return os.path.join(hint_dir, "..")
- return ""
+ if is_windows:
+ for extension in windows_exts:
+ path_with_ext = path + extension
+
+ if os.path.isfile(path_with_ext) and os.access(path_with_ext, os.X_OK):
+ sdk_arch = find_dotnet_arch(path_with_ext)
+ if sdk_arch == arch or arch == "":
+ return path_with_ext
+ elif sdk_arch == "":
+ sdk_path_unknown_arch = path_with_ext
+ else:
+ if os.path.isfile(path) and os.access(path, os.X_OK):
+ sdk_arch = find_dotnet_arch(path)
+ if sdk_arch == arch or arch == "":
+ return path
+ elif sdk_arch == "":
+ sdk_path_unknown_arch = path
+
+ return sdk_path_unknown_arch
diff --git a/modules/mono/build_scripts/mono_reg_utils.py b/modules/mono/build_scripts/mono_reg_utils.py
deleted file mode 100644
index 43c1ec8f8a..0000000000
--- a/modules/mono/build_scripts/mono_reg_utils.py
+++ /dev/null
@@ -1,112 +0,0 @@
-import os
-import platform
-
-if os.name == "nt":
- import winreg
-
-
-def _reg_open_key(key, subkey):
- try:
- return winreg.OpenKey(key, subkey)
- except OSError:
- if platform.architecture()[0] == "32bit":
- bitness_sam = winreg.KEY_WOW64_64KEY
- else:
- bitness_sam = winreg.KEY_WOW64_32KEY
- return winreg.OpenKey(key, subkey, 0, winreg.KEY_READ | bitness_sam)
-
-
-def _reg_open_key_bits(key, subkey, bits):
- sam = winreg.KEY_READ
-
- if platform.architecture()[0] == "32bit":
- if bits == "64":
- # Force 32bit process to search in 64bit registry
- sam |= winreg.KEY_WOW64_64KEY
- else:
- if bits == "32":
- # Force 64bit process to search in 32bit registry
- sam |= winreg.KEY_WOW64_32KEY
-
- return winreg.OpenKey(key, subkey, 0, sam)
-
-
-def _find_mono_in_reg(subkey, bits):
- try:
- with _reg_open_key_bits(winreg.HKEY_LOCAL_MACHINE, subkey, bits) as hKey:
- value = winreg.QueryValueEx(hKey, "SdkInstallRoot")[0]
- return value
- except OSError:
- return None
-
-
-def _find_mono_in_reg_old(subkey, bits):
- try:
- with _reg_open_key_bits(winreg.HKEY_LOCAL_MACHINE, subkey, bits) as hKey:
- default_clr = winreg.QueryValueEx(hKey, "DefaultCLR")[0]
- if default_clr:
- return _find_mono_in_reg(subkey + "\\" + default_clr, bits)
- return None
- except OSError:
- return None
-
-
-def find_mono_root_dir(bits):
- root_dir = _find_mono_in_reg(r"SOFTWARE\Mono", bits)
- if root_dir is not None:
- return str(root_dir)
- root_dir = _find_mono_in_reg_old(r"SOFTWARE\Novell\Mono", bits)
- if root_dir is not None:
- return str(root_dir)
- return ""
-
-
-def find_msbuild_tools_path_reg():
- import subprocess
-
- vswhere = os.getenv("PROGRAMFILES(X86)")
- if not vswhere:
- vswhere = os.getenv("PROGRAMFILES")
- vswhere += r"\Microsoft Visual Studio\Installer\vswhere.exe"
-
- vswhere_args = ["-latest", "-products", "*", "-requires", "Microsoft.Component.MSBuild"]
-
- try:
- lines = subprocess.check_output([vswhere] + vswhere_args).splitlines()
-
- for line in lines:
- parts = line.decode("utf-8").split(":", 1)
-
- if len(parts) < 2 or parts[0] != "installationPath":
- continue
-
- val = parts[1].strip()
-
- if not val:
- raise ValueError("Value of `installationPath` entry is empty")
-
- # Since VS2019, the directory is simply named "Current"
- msbuild_dir = os.path.join(val, "MSBuild\\Current\\Bin")
- if os.path.isdir(msbuild_dir):
- return msbuild_dir
-
- # Directory name "15.0" is used in VS 2017
- return os.path.join(val, "MSBuild\\15.0\\Bin")
-
- raise ValueError("Cannot find `installationPath` entry")
- except ValueError as e:
- print("Error reading output from vswhere: " + e.message)
- except subprocess.CalledProcessError as e:
- print(e.output)
- except OSError as e:
- print(e)
-
- # Try to find 14.0 in the Registry
-
- try:
- subkey = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0"
- with _reg_open_key(winreg.HKEY_LOCAL_MACHINE, subkey) as hKey:
- value = winreg.QueryValueEx(hKey, "MSBuildToolsPath")[0]
- return value
- except OSError:
- return ""
diff --git a/modules/mono/build_scripts/solution_builder.py b/modules/mono/build_scripts/solution_builder.py
deleted file mode 100644
index 6a621c3c8b..0000000000
--- a/modules/mono/build_scripts/solution_builder.py
+++ /dev/null
@@ -1,145 +0,0 @@
-import os
-
-
-verbose = False
-
-
-def find_dotnet_cli():
- import os.path
-
- if os.name == "nt":
- for hint_dir in os.environ["PATH"].split(os.pathsep):
- hint_dir = hint_dir.strip('"')
- hint_path = os.path.join(hint_dir, "dotnet")
- if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
- return hint_path
- if os.path.isfile(hint_path + ".exe") and os.access(hint_path + ".exe", os.X_OK):
- return hint_path + ".exe"
- else:
- for hint_dir in os.environ["PATH"].split(os.pathsep):
- hint_dir = hint_dir.strip('"')
- hint_path = os.path.join(hint_dir, "dotnet")
- if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
- return hint_path
-
-
-def find_msbuild_unix():
- import os.path
- import sys
-
- hint_dirs = []
- if sys.platform == "darwin":
- hint_dirs[:0] = [
- "/Library/Frameworks/Mono.framework/Versions/Current/bin",
- "/usr/local/var/homebrew/linked/mono/bin",
- ]
-
- for hint_dir in hint_dirs:
- hint_path = os.path.join(hint_dir, "msbuild")
- if os.path.isfile(hint_path):
- return hint_path
- elif os.path.isfile(hint_path + ".exe"):
- return hint_path + ".exe"
-
- for hint_dir in os.environ["PATH"].split(os.pathsep):
- hint_dir = hint_dir.strip('"')
- hint_path = os.path.join(hint_dir, "msbuild")
- if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
- return hint_path
- if os.path.isfile(hint_path + ".exe") and os.access(hint_path + ".exe", os.X_OK):
- return hint_path + ".exe"
-
- return None
-
-
-def find_msbuild_windows(env):
- from .mono_reg_utils import find_mono_root_dir, find_msbuild_tools_path_reg
-
- mono_root = env["mono_prefix"] or find_mono_root_dir(env["bits"])
-
- if not mono_root:
- raise RuntimeError("Cannot find mono root directory")
-
- mono_bin_dir = os.path.join(mono_root, "bin")
- msbuild_mono = os.path.join(mono_bin_dir, "msbuild.bat")
-
- msbuild_tools_path = find_msbuild_tools_path_reg()
-
- if msbuild_tools_path:
- return (os.path.join(msbuild_tools_path, "MSBuild.exe"), {})
-
- if os.path.isfile(msbuild_mono):
- # The (Csc/Vbc/Fsc)ToolExe environment variables are required when
- # building with Mono's MSBuild. They must point to the batch files
- # in Mono's bin directory to make sure they are executed with Mono.
- mono_msbuild_env = {
- "CscToolExe": os.path.join(mono_bin_dir, "csc.bat"),
- "VbcToolExe": os.path.join(mono_bin_dir, "vbc.bat"),
- "FscToolExe": os.path.join(mono_bin_dir, "fsharpc.bat"),
- }
- return (msbuild_mono, mono_msbuild_env)
-
- return None
-
-
-def run_command(command, args, env_override=None, name=None):
- def cmd_args_to_str(cmd_args):
- return " ".join([arg if not " " in arg else '"%s"' % arg for arg in cmd_args])
-
- args = [command] + args
-
- if name is None:
- name = os.path.basename(command)
-
- if verbose:
- print("Running '%s': %s" % (name, cmd_args_to_str(args)))
-
- import subprocess
-
- try:
- if env_override is None:
- subprocess.check_call(args)
- else:
- subprocess.check_call(args, env=env_override)
- except subprocess.CalledProcessError as e:
- raise RuntimeError("'%s' exited with error code: %s" % (name, e.returncode))
-
-
-def build_solution(env, solution_path, build_config, extra_msbuild_args=[]):
- global verbose
- verbose = env["verbose"]
-
- msbuild_env = os.environ.copy()
-
- # Needed when running from Developer Command Prompt for VS
- if "PLATFORM" in msbuild_env:
- del msbuild_env["PLATFORM"]
-
- msbuild_args = []
-
- dotnet_cli = find_dotnet_cli()
-
- if dotnet_cli:
- msbuild_path = dotnet_cli
- msbuild_args += ["msbuild"] # `dotnet msbuild` command
- else:
- # Find MSBuild
- if os.name == "nt":
- msbuild_info = find_msbuild_windows(env)
- if msbuild_info is None:
- raise RuntimeError("Cannot find MSBuild executable")
- msbuild_path = msbuild_info[0]
- msbuild_env.update(msbuild_info[1])
- else:
- msbuild_path = find_msbuild_unix()
- if msbuild_path is None:
- raise RuntimeError("Cannot find MSBuild executable")
-
- print("MSBuild path: " + msbuild_path)
-
- # Build solution
-
- msbuild_args += [solution_path, "/restore", "/t:Build", "/p:Configuration=" + build_config]
- msbuild_args += extra_msbuild_args
-
- run_command(msbuild_path, msbuild_args, env_override=msbuild_env, name="msbuild")
diff --git a/modules/mono/config.py b/modules/mono/config.py
index 3e6584590c..ad78c8c898 100644
--- a/modules/mono/config.py
+++ b/modules/mono/config.py
@@ -1,10 +1,28 @@
-supported_platforms = ["windows", "macos", "linuxbsd", "server", "android", "haiku", "javascript", "ios"]
+# Prior to .NET Core, we supported these: ["windows", "macos", "linuxbsd", "android", "haiku", "web", "ios"]
+# Eventually support for each them should be added back (except Haiku if not supported by .NET Core)
+supported_platforms = ["windows", "macos", "linuxbsd"]
def can_build(env, platform):
return not env["arch"].startswith("rv")
+def get_opts(platform):
+ from SCons.Variables import BoolVariable, PathVariable
+
+ default_mono_static = platform in ["ios", "web"]
+ default_mono_bundles_zlib = platform in ["web"]
+
+ return [
+ PathVariable(
+ "dotnet_root",
+ "Path to the .NET Sdk installation directory for the target platform and architecture",
+ "",
+ PathVariable.PathAccept,
+ ),
+ ]
+
+
def configure(env):
platform = env["platform"]
@@ -13,52 +31,6 @@ def configure(env):
env.add_module_version_string("mono")
- from SCons.Script import BoolVariable, PathVariable, Variables, Help
-
- default_mono_static = platform in ["ios", "javascript"]
- default_mono_bundles_zlib = platform in ["javascript"]
-
- envvars = Variables()
- envvars.Add(
- PathVariable(
- "mono_prefix",
- "Path to the Mono installation directory for the target platform and architecture",
- "",
- PathVariable.PathAccept,
- )
- )
- envvars.Add(
- PathVariable(
- "mono_bcl",
- "Path to a custom Mono BCL (Base Class Library) directory for the target platform",
- "",
- PathVariable.PathAccept,
- )
- )
- envvars.Add(BoolVariable("mono_static", "Statically link Mono", default_mono_static))
- envvars.Add(BoolVariable("mono_glue", "Build with the Mono glue sources", True))
- envvars.Add(BoolVariable("build_cil", "Build C# solutions", True))
- envvars.Add(
- BoolVariable("copy_mono_root", "Make a copy of the Mono installation directory to bundle with the editor", True)
- )
-
- # TODO: It would be great if this could be detected automatically instead
- envvars.Add(
- BoolVariable(
- "mono_bundles_zlib", "Specify if the Mono runtime was built with bundled zlib", default_mono_bundles_zlib
- )
- )
-
- envvars.Update(env)
- Help(envvars.GenerateHelpText(env))
-
- if env["mono_bundles_zlib"]:
- # Mono may come with zlib bundled for WASM or on newer version when built with MinGW.
- print("This Mono runtime comes with zlib bundled. Disabling 'builtin_zlib'...")
- env["builtin_zlib"] = False
- thirdparty_zlib_dir = "#thirdparty/zlib/"
- env.Prepend(CPPPATH=[thirdparty_zlib_dir])
-
def get_doc_classes():
return [
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index c7279be97f..2e59987fe6 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -30,8 +30,6 @@
#include "csharp_script.h"
-#include <mono/metadata/threads.h>
-#include <mono/metadata/tokentype.h>
#include <stdint.h>
#include "core/config/project_settings.h"
@@ -57,10 +55,8 @@
#endif
#include "godotsharp_dirs.h"
+#include "managed_callable.h"
#include "mono_gd/gd_mono_cache.h"
-#include "mono_gd/gd_mono_class.h"
-#include "mono_gd/gd_mono_marshal.h"
-#include "mono_gd/gd_mono_utils.h"
#include "signal_awaiter_utils.h"
#include "utils/macros.h"
#include "utils/string_utils.h"
@@ -69,17 +65,8 @@
#ifdef TOOLS_ENABLED
static bool _create_project_solution_if_needed() {
- String sln_path = GodotSharpDirs::get_project_sln_path();
- String csproj_path = GodotSharpDirs::get_project_csproj_path();
-
- if (!FileAccess::exists(sln_path) || !FileAccess::exists(csproj_path)) {
- // A solution does not yet exist, create a new one
-
- CRASH_COND(CSharpLanguage::get_singleton()->get_godotsharp_editor() == nullptr);
- return CSharpLanguage::get_singleton()->get_godotsharp_editor()->call("CreateProjectSolution");
- }
-
- return true;
+ CRASH_COND(CSharpLanguage::get_singleton()->get_godotsharp_editor() == nullptr);
+ return CSharpLanguage::get_singleton()->get_godotsharp_editor()->call("CreateProjectSolutionIfNeeded");
}
#endif
@@ -118,26 +105,21 @@ void CSharpLanguage::init() {
}
#endif
- gdmono = memnew(GDMono);
- gdmono->initialize();
-
#if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED)
- // Generate bindings here, before loading assemblies. 'initialize_load_assemblies' aborts
- // the applications if the api assemblies or the main tools assembly is missing, but this
- // is not a problem for BindingsGenerator as it only needs the tools project editor assembly.
+ // Generate the bindings here, before loading assemblies. The Godot assemblies
+ // may be missing if the glue wasn't generated yet in order to build them.
List<String> cmdline_args = OS::get_singleton()->get_cmdline_args();
BindingsGenerator::handle_cmdline_args(cmdline_args);
#endif
-#ifndef MONO_GLUE_ENABLED
- print_line("Run this binary with '--generate-mono-glue path/to/modules/mono/glue'");
-#endif
+ gdmono = memnew(GDMono);
+ gdmono->initialize();
+#ifdef TOOLS_ENABLED
if (gdmono->is_runtime_initialized()) {
gdmono->initialize_load_assemblies();
}
-#ifdef TOOLS_ENABLED
EditorNode::add_init_callback(&_editor_init_callback);
#endif
}
@@ -596,23 +578,19 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info()
return Vector<StackInfo>();
}
_recursion_flag_ = true;
- SCOPE_EXIT { _recursion_flag_ = false; };
-
- GD_MONO_SCOPE_THREAD_ATTACH;
+ SCOPE_EXIT {
+ _recursion_flag_ = false;
+ };
- if (!gdmono->is_runtime_initialized() || !GDMono::get_singleton()->get_core_api_assembly() || !GDMonoCache::cached_data.corlib_cache_updated) {
+ if (!gdmono->is_runtime_initialized()) {
return Vector<StackInfo>();
}
- MonoObject *stack_trace = mono_object_new(mono_domain_get(), CACHED_CLASS(System_Diagnostics_StackTrace)->get_mono_ptr());
-
- MonoBoolean need_file_info = true;
- void *ctor_args[1] = { &need_file_info };
-
- CACHED_METHOD(System_Diagnostics_StackTrace, ctor_bool)->invoke_raw(stack_trace, ctor_args);
-
Vector<StackInfo> si;
- si = stack_trace_get_info(stack_trace);
+
+ if (GDMonoCache::godot_api_cache_updated) {
+ GDMonoCache::managed_callbacks.DebuggingUtils_GetCurrentStackInfo(&si);
+ }
return si;
#else
@@ -620,63 +598,6 @@ Vector<ScriptLanguage::StackInfo> CSharpLanguage::debug_get_current_stack_info()
#endif
}
-#ifdef DEBUG_ENABLED
-Vector<ScriptLanguage::StackInfo> CSharpLanguage::stack_trace_get_info(MonoObject *p_stack_trace) {
- // Printing an error here will result in endless recursion, so we must be careful
- static thread_local bool _recursion_flag_ = false;
- if (_recursion_flag_) {
- return Vector<StackInfo>();
- }
- _recursion_flag_ = true;
- SCOPE_EXIT { _recursion_flag_ = false; };
-
- GD_MONO_SCOPE_THREAD_ATTACH;
-
- MonoException *exc = nullptr;
-
- MonoArray *frames = CACHED_METHOD_THUNK(System_Diagnostics_StackTrace, GetFrames).invoke(p_stack_trace, &exc);
-
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- return Vector<StackInfo>();
- }
-
- int frame_count = mono_array_length(frames);
-
- if (frame_count <= 0) {
- return Vector<StackInfo>();
- }
-
- Vector<StackInfo> si;
- si.resize(frame_count);
-
- for (int i = 0; i < frame_count; i++) {
- StackInfo &sif = si.write[i];
- MonoObject *frame = mono_array_get(frames, MonoObject *, i);
-
- MonoString *file_name;
- int file_line_num;
- MonoString *method_decl;
- CACHED_METHOD_THUNK(DebuggingUtils, GetStackFrameInfo).invoke(frame, &file_name, &file_line_num, &method_decl, &exc);
-
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- return Vector<StackInfo>();
- }
-
- // TODO
- // what if the StackFrame method is null (method_decl is empty). should we skip this frame?
- // can reproduce with a MissingMethodException on internal calls
-
- sif.file = GDMonoMarshal::mono_string_to_godot(file_name);
- sif.line = file_line_num;
- sif.func = GDMonoMarshal::mono_string_to_godot(method_decl);
- }
-
- return si;
-}
-#endif
-
void CSharpLanguage::post_unsafe_reference(Object *p_obj) {
#ifdef DEBUG_ENABLED
MutexLock lock(unsafe_object_references_lock);
@@ -698,48 +619,36 @@ void CSharpLanguage::pre_unsafe_unreference(Object *p_obj) {
}
void CSharpLanguage::frame() {
- if (gdmono && gdmono->is_runtime_initialized() && gdmono->get_core_api_assembly() != nullptr) {
- const Ref<MonoGCHandleRef> &task_scheduler_handle = GDMonoCache::cached_data.task_scheduler_handle;
-
- if (task_scheduler_handle.is_valid()) {
- MonoObject *task_scheduler = task_scheduler_handle->get_target();
-
- if (task_scheduler) {
- MonoException *exc = nullptr;
- CACHED_METHOD_THUNK(GodotTaskScheduler, Activate).invoke(task_scheduler, &exc);
-
- if (exc) {
- GDMonoUtils::debug_unhandled_exception(exc);
- }
- }
- }
+ if (gdmono && gdmono->is_runtime_initialized() && GDMonoCache::godot_api_cache_updated) {
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_FrameCallback();
}
}
struct CSharpScriptDepSort {
- // must support sorting so inheritance works properly (parent must be reloaded first)
+ // Must support sorting so inheritance works properly (parent must be reloaded first)
bool operator()(const Ref<CSharpScript> &A, const Ref<CSharpScript> &B) const {
if (A == B) {
- return false; // shouldn't happen but..
+ // Shouldn't happen but just in case...
+ return false;
}
- GDMonoClass *I = B->base;
+ const Script *I = B->get_base_script().ptr();
while (I) {
- if (I == A->script_class) {
+ if (I == A.ptr()) {
// A is a base of B
return true;
}
- I = I->get_parent_class();
+ I = I->get_base_script().ptr();
}
- return false; // not a base
+ // A isn't a base of B
+ return false;
}
};
void CSharpLanguage::reload_all_scripts() {
#ifdef GD_MONO_HOT_RELOAD
if (is_assembly_reloading_needed()) {
- GD_MONO_SCOPE_THREAD_ATTACH;
reload_assemblies(false);
}
#endif
@@ -756,7 +665,6 @@ void CSharpLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft
#ifdef GD_MONO_HOT_RELOAD
if (is_assembly_reloading_needed()) {
- GD_MONO_SCOPE_THREAD_ATTACH;
reload_assemblies(p_soft_reload);
}
#endif
@@ -768,28 +676,28 @@ bool CSharpLanguage::is_assembly_reloading_needed() {
return false;
}
- GDMonoAssembly *proj_assembly = gdmono->get_project_assembly();
+ String assembly_path = gdmono->get_project_assembly_path();
- String appname_safe = ProjectSettings::get_singleton()->get_safe_project_name();
-
- appname_safe += ".dll";
-
- if (proj_assembly) {
- String proj_asm_path = proj_assembly->get_path();
-
- if (!FileAccess::exists(proj_asm_path)) {
- // Maybe it wasn't loaded from the default path, so check this as well
- proj_asm_path = GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(appname_safe);
- if (!FileAccess::exists(proj_asm_path)) {
- return false; // No assembly to load
- }
+ if (!assembly_path.is_empty()) {
+ if (!FileAccess::exists(assembly_path)) {
+ return false; // No assembly to load
}
- if (FileAccess::get_modified_time(proj_asm_path) <= proj_assembly->get_modified_time()) {
+ if (FileAccess::get_modified_time(assembly_path) <= gdmono->get_project_assembly_modified_time()) {
return false; // Already up to date
}
} else {
- if (!FileAccess::exists(GodotSharpDirs::get_res_temp_assemblies_dir().plus_file(appname_safe))) {
+ String assembly_name = ProjectSettings::get_singleton()->get_setting("dotnet/project/assembly_name");
+
+ if (assembly_name.is_empty()) {
+ assembly_name = ProjectSettings::get_singleton()->get_safe_project_name();
+ }
+
+ assembly_path = GodotSharpDirs::get_res_temp_assemblies_dir()
+ .path_join(assembly_name + ".dll");
+ assembly_path = ProjectSettings::get_singleton()->globalize_path(assembly_path);
+
+ if (!FileAccess::exists(assembly_path)) {
return false; // No assembly to load
}
}
@@ -802,6 +710,12 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
return;
}
+ // TODO:
+ // Currently, this reloads all scripts, including those whose class is not part of the
+ // assembly load context being unloaded. As such, we unnecessarily reload GodotTools.
+
+ print_verbose(".NET: Reloading assemblies...");
+
// There is no soft reloading with Mono. It's always hard reloading.
List<Ref<CSharpScript>> scripts;
@@ -824,18 +738,12 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
for (SelfList<ManagedCallable> *elem = ManagedCallable::instances.first(); elem; elem = elem->next()) {
ManagedCallable *managed_callable = elem->self();
- MonoDelegate *delegate = (MonoDelegate *)managed_callable->delegate_handle.get_target();
+ ERR_CONTINUE(managed_callable->delegate_handle.value == nullptr);
Array serialized_data;
- MonoObject *managed_serialized_data = GDMonoMarshal::variant_to_mono_object(serialized_data);
-
- MonoException *exc = nullptr;
- bool success = (bool)CACHED_METHOD_THUNK(DelegateUtils, TrySerializeDelegate).invoke(delegate, managed_serialized_data, &exc);
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- continue;
- }
+ bool success = GDMonoCache::managed_callbacks.DelegateUtils_TrySerializeDelegateWithGCHandle(
+ managed_callable->delegate_handle, &serialized_data);
if (success) {
ManagedCallable::instances_pending_reload.insert(managed_callable, serialized_data);
@@ -864,17 +772,12 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
// If someone removes a script from a node, deletes the script, builds, adds a script to the
// same node, then builds again, the script might have no path and also no script_class. In
// that case, we can't (and don't need to) reload it.
- if (script->get_path().is_empty() && !script->script_class) {
+ if (script->get_path().is_empty() && !script->valid) {
continue;
}
to_reload.push_back(script);
- if (script->get_path().is_empty()) {
- script->tied_class_name_for_reload = script->script_class->get_name_for_lookup();
- script->tied_class_namespace_for_reload = script->script_class->get_namespace();
- }
-
// Script::instances are deleted during managed object disposal, which happens on domain finalize.
// Only placeholders are kept. Therefore we need to keep a copy before that happens.
@@ -907,17 +810,20 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
CSharpInstance *csi = static_cast<CSharpInstance *>(obj->get_script_instance());
- // Call OnBeforeSerialize
- if (csi->script->script_class->implements_interface(CACHED_CLASS(ISerializationListener))) {
- obj->get_script_instance()->call(string_names.on_before_serialize);
- }
+ // Call OnBeforeSerialize and save instance info
- // Save instance info
CSharpScript::StateBackup state;
- // TODO: Proper state backup (Not only variants, serialize managed state of scripts)
- csi->get_properties_state_for_reloading(state.properties);
- csi->get_event_signals_state_for_reloading(state.event_signals);
+ Dictionary properties;
+
+ GDMonoCache::managed_callbacks.CSharpInstanceBridge_SerializeState(
+ csi->get_gchandle_intptr(), &properties, &state.event_signals);
+
+ for (const Variant *s = properties.next(nullptr); s != nullptr; s = properties.next(s)) {
+ StringName name = *s;
+ Variant value = properties[*s];
+ state.properties.push_back(Pair<StringName, Variant>(name, value));
+ }
owners_map[obj->get_instance_id()] = state;
}
@@ -934,7 +840,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
}
// Do domain reload
- if (gdmono->reload_scripts_domain() != OK) {
+ if (gdmono->reload_project_assemblies() != OK) {
// Failed to reload the scripts domain
// Make sure to add the scripts back to their owners before returning
for (Ref<CSharpScript> &scr : to_reload) {
@@ -965,6 +871,9 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
scr->pending_reload_state.erase(obj_id);
}
+
+ scr->pending_reload_instances.clear();
+ scr->pending_reload_state.clear();
}
return;
@@ -976,53 +885,27 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
#ifdef TOOLS_ENABLED
script->exports_invalidated = true;
#endif
- script->signals_invalidated = true;
if (!script->get_path().is_empty()) {
script->reload(p_soft_reload);
if (!script->valid) {
script->pending_reload_instances.clear();
+ script->pending_reload_state.clear();
continue;
}
} else {
- const StringName &class_namespace = script->tied_class_namespace_for_reload;
- const StringName &class_name = script->tied_class_name_for_reload;
- GDMonoAssembly *project_assembly = gdmono->get_project_assembly();
-
- // Search in project and tools assemblies first as those are the most likely to have the class
- GDMonoClass *script_class = (project_assembly ? project_assembly->get_class(class_namespace, class_name) : nullptr);
-
-#ifdef TOOLS_ENABLED
- if (!script_class) {
- GDMonoAssembly *tools_assembly = gdmono->get_tools_assembly();
- script_class = (tools_assembly ? tools_assembly->get_class(class_namespace, class_name) : nullptr);
- }
-#endif
-
- if (!script_class) {
- script_class = gdmono->get_class(class_namespace, class_name);
- }
-
- if (!script_class) {
- // The class was removed, can't reload
- script->pending_reload_instances.clear();
- continue;
- }
+ bool success = GDMonoCache::managed_callbacks.ScriptManagerBridge_TryReloadRegisteredScriptWithClass(script.ptr());
- bool obj_type = CACHED_CLASS(GodotObject)->is_assignable_from(script_class);
- if (!obj_type) {
- // The class no longer inherits Godot.Object, can't reload
+ if (!success) {
+ // Couldn't reload
script->pending_reload_instances.clear();
+ script->pending_reload_state.clear();
continue;
}
-
- GDMonoClass *native = GDMonoUtils::get_class_native_base(script_class);
-
- CSharpScript::initialize_for_managed_type(script, script_class, native);
}
- StringName native_name = NATIVE_GDMONOCLASS_NAME(script->native);
+ StringName native_name = script->get_instance_base_type();
{
for (const ObjectID &obj_id : script->pending_reload_instances) {
@@ -1087,57 +970,25 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
ERR_CONTINUE(!obj->get_script_instance());
- // TODO: Restore serialized state
-
CSharpScript::StateBackup &state_backup = script->pending_reload_state[obj_id];
- for (const Pair<StringName, Variant> &G : state_backup.properties) {
- obj->get_script_instance()->set(G.first, G.second);
- }
-
CSharpInstance *csi = CAST_CSHARP_INSTANCE(obj->get_script_instance());
if (csi) {
- for (const Pair<StringName, Array> &G : state_backup.event_signals) {
- const StringName &name = G.first;
- const Array &serialized_data = G.second;
-
- HashMap<StringName, CSharpScript::EventSignal>::Iterator match = script->event_signals.find(name);
-
- if (!match) {
- // The event or its signal attribute were removed
- continue;
- }
-
- const CSharpScript::EventSignal &event_signal = match->value;
-
- MonoObject *managed_serialized_data = GDMonoMarshal::variant_to_mono_object(serialized_data);
- MonoDelegate *delegate = nullptr;
+ Dictionary properties;
- MonoException *exc = nullptr;
- bool success = (bool)CACHED_METHOD_THUNK(DelegateUtils, TryDeserializeDelegate).invoke(managed_serialized_data, &delegate, &exc);
-
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- continue;
- }
-
- if (success) {
- ERR_CONTINUE(delegate == nullptr);
- event_signal.field->set_value(csi->get_mono_object(), (MonoObject *)delegate);
- } else if (OS::get_singleton()->is_stdout_verbose()) {
- OS::get_singleton()->print("Failed to deserialize event signal delegate\n");
- }
+ for (const Pair<StringName, Variant> &G : state_backup.properties) {
+ properties[G.first] = G.second;
}
- // Call OnAfterDeserialization
- if (csi->script->script_class->implements_interface(CACHED_CLASS(ISerializationListener))) {
- obj->get_script_instance()->call(string_names.on_after_deserialize);
- }
+ // Restore serialized state and call OnAfterDeserialization
+ GDMonoCache::managed_callbacks.CSharpInstanceBridge_DeserializeState(
+ csi->get_gchandle_intptr(), &properties, &state_backup.event_signals);
}
}
script->pending_reload_instances.clear();
+ script->pending_reload_state.clear();
}
// Deserialize managed callables
@@ -1148,20 +999,14 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
ManagedCallable *managed_callable = elem.key;
const Array &serialized_data = elem.value;
- MonoObject *managed_serialized_data = GDMonoMarshal::variant_to_mono_object(serialized_data);
- MonoDelegate *delegate = nullptr;
-
- MonoException *exc = nullptr;
- bool success = (bool)CACHED_METHOD_THUNK(DelegateUtils, TryDeserializeDelegate).invoke(managed_serialized_data, &delegate, &exc);
+ GCHandleIntPtr delegate = { nullptr };
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- continue;
- }
+ bool success = GDMonoCache::managed_callbacks.DelegateUtils_TryDeserializeDelegateWithGCHandle(
+ &serialized_data, &delegate);
if (success) {
- ERR_CONTINUE(delegate == nullptr);
- managed_callable->set_delegate(delegate);
+ ERR_CONTINUE(delegate.value == nullptr);
+ managed_callable->delegate_handle = delegate;
} else if (OS::get_singleton()->is_stdout_verbose()) {
OS::get_singleton()->print("Failed to deserialize delegate\n");
}
@@ -1180,60 +1025,6 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
}
#endif
-void CSharpLanguage::lookup_script_for_class(GDMonoClass *p_class) {
- if (!p_class->has_attribute(CACHED_CLASS(ScriptPathAttribute))) {
- return;
- }
-
- MonoObject *attr = p_class->get_attribute(CACHED_CLASS(ScriptPathAttribute));
- String path = CACHED_FIELD(ScriptPathAttribute, path)->get_string_value(attr);
-
- dotnet_script_lookup_map[path] = DotNetScriptLookupInfo(
- p_class->get_namespace(), p_class->get_name(), p_class);
-}
-
-void CSharpLanguage::lookup_scripts_in_assembly(GDMonoAssembly *p_assembly) {
- if (p_assembly->has_attribute(CACHED_CLASS(AssemblyHasScriptsAttribute))) {
- MonoObject *attr = p_assembly->get_attribute(CACHED_CLASS(AssemblyHasScriptsAttribute));
- bool requires_lookup = CACHED_FIELD(AssemblyHasScriptsAttribute, requiresLookup)->get_bool_value(attr);
-
- if (requires_lookup) {
- // This is supported for scenarios where specifying all types would be cumbersome,
- // such as when disabling C# source generators (for whatever reason) or when using a
- // language other than C# that has nothing similar to source generators to automate it.
- MonoImage *image = p_assembly->get_image();
-
- int rows = mono_image_get_table_rows(image, MONO_TABLE_TYPEDEF);
-
- for (int i = 1; i < rows; i++) {
- // We don't search inner classes, only top-level.
- MonoClass *mono_class = mono_class_get(image, (i + 1) | MONO_TOKEN_TYPE_DEF);
-
- if (!mono_class_is_assignable_from(CACHED_CLASS_RAW(GodotObject), mono_class)) {
- continue;
- }
-
- GDMonoClass *current = p_assembly->get_class(mono_class);
- if (current) {
- lookup_script_for_class(current);
- }
- }
- } else {
- // This is the most likely scenario as we use C# source generators
- MonoArray *script_types = (MonoArray *)CACHED_FIELD(AssemblyHasScriptsAttribute, scriptTypes)->get_value(attr);
-
- int length = mono_array_length(script_types);
-
- for (int i = 0; i < length; i++) {
- MonoReflectionType *reftype = mono_array_get(script_types, MonoReflectionType *, i);
- ManagedType type = ManagedType::from_reftype(reftype);
- ERR_CONTINUE(!type.type_class);
- lookup_script_for_class(type.type_class);
- }
- }
- }
-}
-
void CSharpLanguage::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("cs");
}
@@ -1248,22 +1039,6 @@ bool CSharpLanguage::overrides_external_editor() {
}
#endif
-void CSharpLanguage::thread_enter() {
-#if 0
- if (gdmono->is_runtime_initialized()) {
- GDMonoUtils::attach_current_thread();
- }
-#endif
-}
-
-void CSharpLanguage::thread_exit() {
-#if 0
- if (gdmono->is_runtime_initialized()) {
- GDMonoUtils::detach_current_thread();
- }
-#endif
-}
-
bool CSharpLanguage::debug_break_parse(const String &p_file, int p_line, const String &p_error) {
// Not a parser error in our case, but it's still used for other type of errors
if (EngineDebugger::is_active() && Thread::get_caller_id() == Thread::get_main_id()) {
@@ -1289,49 +1064,35 @@ bool CSharpLanguage::debug_break(const String &p_error, bool p_allow_continue) {
}
}
-void CSharpLanguage::_on_scripts_domain_unloaded() {
- for (KeyValue<Object *, CSharpScriptBinding> &E : script_bindings) {
- CSharpScriptBinding &script_binding = E.value;
- script_binding.gchandle.release();
- script_binding.inited = false;
- }
-
+void CSharpLanguage::_on_scripts_domain_about_to_unload() {
#ifdef GD_MONO_HOT_RELOAD
{
MutexLock lock(ManagedCallable::instances_mutex);
for (SelfList<ManagedCallable> *elem = ManagedCallable::instances.first(); elem; elem = elem->next()) {
ManagedCallable *managed_callable = elem->self();
- managed_callable->delegate_handle.release();
- managed_callable->delegate_invoke = nullptr;
+ managed_callable->release_delegate_handle();
}
}
#endif
-
- dotnet_script_lookup_map.clear();
}
#ifdef TOOLS_ENABLED
void CSharpLanguage::_editor_init_callback() {
- register_editor_internal_calls();
-
- // Initialize GodotSharpEditor
-
- GDMonoClass *editor_klass = GDMono::get_singleton()->get_tools_assembly()->get_class("GodotTools", "GodotSharpEditor");
- CRASH_COND(editor_klass == nullptr);
+ // Load GodotTools and initialize GodotSharpEditor
- MonoObject *mono_object = mono_object_new(mono_domain_get(), editor_klass->get_mono_ptr());
- CRASH_COND(mono_object == nullptr);
+ int32_t interop_funcs_size = 0;
+ const void **interop_funcs = godotsharp::get_editor_interop_funcs(interop_funcs_size);
- MonoException *exc = nullptr;
- GDMonoUtils::runtime_object_init(mono_object, editor_klass, &exc);
- UNHANDLED_EXCEPTION(exc);
+ Object *editor_plugin_obj = GDMono::get_singleton()->get_plugin_callbacks().LoadToolsAssemblyCallback(
+ GodotSharpDirs::get_data_editor_tools_dir().path_join("GodotTools.dll").utf16(),
+ interop_funcs, interop_funcs_size);
+ CRASH_COND(editor_plugin_obj == nullptr);
- EditorPlugin *godotsharp_editor = Object::cast_to<EditorPlugin>(
- GDMonoMarshal::mono_object_to_variant(mono_object).operator Object *());
+ EditorPlugin *godotsharp_editor = Object::cast_to<EditorPlugin>(editor_plugin_obj);
CRASH_COND(godotsharp_editor == nullptr);
- // Enable it as a plugin
+ // Add plugin to EditorNode and enable it
EditorNode::add_editor_plugin(godotsharp_editor);
ED_SHORTCUT("mono/build_solution", TTR("Build Solution"), KeyModifierMask::ALT | Key::B);
godotsharp_editor->enable_plugin();
@@ -1352,24 +1113,24 @@ void CSharpLanguage::release_script_gchandle(MonoGCHandleData &p_gchandle) {
}
}
-void CSharpLanguage::release_script_gchandle(MonoObject *p_expected_obj, MonoGCHandleData &p_gchandle) {
- uint32_t pinned_gchandle = GDMonoUtils::new_strong_gchandle_pinned(p_expected_obj); // We might lock after this, so pin it
-
- if (!p_gchandle.is_released()) { // Do not lock unnecessarily
+void CSharpLanguage::release_script_gchandle_thread_safe(GCHandleIntPtr p_gchandle_to_free, MonoGCHandleData &r_gchandle) {
+ if (!r_gchandle.is_released() && r_gchandle.get_intptr() == p_gchandle_to_free) { // Do not lock unnecessarily
MutexLock lock(get_singleton()->script_gchandle_release_mutex);
-
- MonoObject *target = p_gchandle.get_target();
-
- // We release the gchandle if it points to the MonoObject* we expect (otherwise it was
- // already released and could have been replaced) or if we can't get its target MonoObject*
- // (which doesn't necessarily mean it was released, and we want it released in order to
- // avoid locking other threads unnecessarily).
- if (target == p_expected_obj || target == nullptr) {
- p_gchandle.release();
+ if (!r_gchandle.is_released() && r_gchandle.get_intptr() == p_gchandle_to_free) {
+ r_gchandle.release();
}
}
+}
- GDMonoUtils::free_gchandle(pinned_gchandle);
+void CSharpLanguage::release_binding_gchandle_thread_safe(GCHandleIntPtr p_gchandle_to_free, CSharpScriptBinding &r_script_binding) {
+ MonoGCHandleData &gchandle = r_script_binding.gchandle;
+ if (!gchandle.is_released() && gchandle.get_intptr() == p_gchandle_to_free) { // Do not lock unnecessarily
+ MutexLock lock(get_singleton()->script_gchandle_release_mutex);
+ if (!gchandle.is_released() && gchandle.get_intptr() == p_gchandle_to_free) {
+ gchandle.release();
+ r_script_binding.inited = false; // Here too, to be thread safe
+ }
+ }
}
CSharpLanguage::CSharpLanguage() {
@@ -1401,18 +1162,23 @@ bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_b
ERR_FAIL_NULL_V(classinfo, false);
type_name = classinfo->name;
- GDMonoClass *type_class = GDMonoUtils::type_get_proxy_class(type_name);
+ bool parent_is_object_class = ClassDB::is_parent_class(p_object->get_class_name(), type_name);
+ ERR_FAIL_COND_V_MSG(!parent_is_object_class, false,
+ "Type inherits from native type '" + type_name + "', so it can't be instantiated in object of type: '" + p_object->get_class() + "'.");
- ERR_FAIL_NULL_V(type_class, false);
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!r_script_binding.gchandle.is_released());
+#endif
- MonoObject *mono_object = GDMonoUtils::create_managed_for_godot_object(type_class, type_name, p_object);
+ GCHandleIntPtr strong_gchandle =
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_CreateManagedForGodotObjectBinding(
+ &type_name, p_object);
- ERR_FAIL_NULL_V(mono_object, false);
+ ERR_FAIL_NULL_V(strong_gchandle.value, false);
r_script_binding.inited = true;
r_script_binding.type_name = type_name;
- r_script_binding.wrapper_class = type_class; // cache
- r_script_binding.gchandle = MonoGCHandleData::new_strong_handle(mono_object);
+ r_script_binding.gchandle = MonoGCHandleData(strong_gchandle, gdmono::GCHandleType::STRONG_HANDLE);
r_script_binding.owner = p_object;
// Tie managed to unmanaged
@@ -1455,7 +1221,7 @@ void CSharpLanguage::_instance_binding_free_callback(void *, void *, void *p_bin
if (GDMono::get_singleton() == nullptr) {
#ifdef DEBUG_ENABLED
- CRASH_COND(!csharp_lang->script_bindings.is_empty());
+ CRASH_COND(csharp_lang && !csharp_lang->script_bindings.is_empty());
#endif
// Mono runtime finalized, all the gchandle bindings were already released
return;
@@ -1465,8 +1231,6 @@ void CSharpLanguage::_instance_binding_free_callback(void *, void *, void *p_bin
return; // inside CSharpLanguage::finish(), all the gchandle bindings are released there
}
- GD_MONO_ASSERT_THREAD_ATTACHED;
-
{
MutexLock lock(csharp_lang->language_bind_mutex);
@@ -1477,11 +1241,11 @@ void CSharpLanguage::_instance_binding_free_callback(void *, void *, void *p_bin
if (script_binding.inited) {
// Set the native instance field to IntPtr.Zero, if not yet garbage collected.
// This is done to avoid trying to dispose the native instance from Dispose(bool).
- MonoObject *mono_object = script_binding.gchandle.get_target();
- if (mono_object) {
- CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, nullptr);
- }
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_SetGodotObjectPtr(
+ script_binding.gchandle.get_intptr(), nullptr);
+
script_binding.gchandle.release();
+ script_binding.inited = false;
}
csharp_lang->script_bindings.erase(data);
@@ -1510,41 +1274,49 @@ GDNativeBool CSharpLanguage::_instance_binding_reference_callback(void *p_token,
if (p_reference) {
// Refcount incremented
if (refcount > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
- GD_MONO_SCOPE_THREAD_ATTACH;
-
// The reference count was increased after the managed side was the only one referencing our owner.
// This means the owner is being referenced again by the unmanaged side,
// so the owner must hold the managed side alive again to avoid it from being GCed.
- MonoObject *target = gchandle.get_target();
- if (!target) {
+ // Release the current weak handle and replace it with a strong handle.
+
+ GCHandleIntPtr old_gchandle = gchandle.get_intptr();
+ gchandle.handle = { nullptr }; // No longer owns the handle (released by swap function)
+
+ GCHandleIntPtr new_gchandle = { nullptr };
+ bool create_weak = false;
+ bool target_alive = GDMonoCache::managed_callbacks.ScriptManagerBridge_SwapGCHandleForType(
+ old_gchandle, &new_gchandle, create_weak);
+
+ if (!target_alive) {
return false; // Called after the managed side was collected, so nothing to do here
}
- // Release the current weak handle and replace it with a strong handle.
- MonoGCHandleData strong_gchandle = MonoGCHandleData::new_strong_handle(target);
- gchandle.release();
- gchandle = strong_gchandle;
+ gchandle = MonoGCHandleData(new_gchandle, gdmono::GCHandleType::STRONG_HANDLE);
}
return false;
} else {
// Refcount decremented
if (refcount == 1 && !gchandle.is_released() && !gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
- GD_MONO_SCOPE_THREAD_ATTACH;
-
// If owner owner is no longer referenced by the unmanaged side,
// the managed instance takes responsibility of deleting the owner when GCed.
- MonoObject *target = gchandle.get_target();
- if (!target) {
+ // Release the current strong handle and replace it with a weak handle.
+
+ GCHandleIntPtr old_gchandle = gchandle.get_intptr();
+ gchandle.handle = { nullptr }; // No longer owns the handle (released by swap function)
+
+ GCHandleIntPtr new_gchandle = { nullptr };
+ bool create_weak = true;
+ bool target_alive = GDMonoCache::managed_callbacks.ScriptManagerBridge_SwapGCHandleForType(
+ old_gchandle, &new_gchandle, create_weak);
+
+ if (!target_alive) {
return refcount == 0; // Called after the managed side was collected, so nothing to do here
}
- // Release the current strong handle and replace it with a weak handle.
- MonoGCHandleData weak_gchandle = MonoGCHandleData::new_weak_handle(target);
- gchandle.release();
- gchandle = weak_gchandle;
+ gchandle = MonoGCHandleData(new_gchandle, gdmono::GCHandleType::WEAK_HANDLE);
return false;
}
@@ -1589,250 +1361,189 @@ void CSharpLanguage::set_instance_binding(Object *p_object, void *p_binding) {
bool CSharpLanguage::has_instance_binding(Object *p_object) {
return p_object->has_instance_binding(get_singleton());
}
+void CSharpLanguage::tie_native_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, const StringName *p_native_name, bool p_ref_counted) {
+ // This method should not fail
-CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpScript *p_script, const MonoGCHandleData &p_gchandle) {
- CSharpInstance *instance = memnew(CSharpInstance(Ref<CSharpScript>(p_script)));
+ CRASH_COND(!p_unmanaged);
- RefCounted *rc = Object::cast_to<RefCounted>(p_owner);
+ // All mono objects created from the managed world (e.g.: 'new Player()')
+ // need to have a CSharpScript in order for their methods to be callable from the unmanaged side
- instance->base_ref_counted = rc != nullptr;
- instance->owner = p_owner;
- instance->gchandle = p_gchandle;
+ RefCounted *rc = Object::cast_to<RefCounted>(p_unmanaged);
- if (instance->base_ref_counted) {
- instance->_reference_owner_unsafe();
- }
+ CRASH_COND(p_ref_counted != (bool)rc);
- p_script->instances.insert(p_owner);
+ MonoGCHandleData gchandle = MonoGCHandleData(p_gchandle_intptr,
+ p_ref_counted ? gdmono::GCHandleType::WEAK_HANDLE : gdmono::GCHandleType::STRONG_HANDLE);
- return instance;
-}
+ // If it's just a wrapper Godot class and not a custom inheriting class, then attach a
+ // script binding instead. One of the advantages of this is that if a script is attached
+ // later and it's not a C# script, then the managed object won't have to be disposed.
+ // Another reason for doing this is that this instance could outlive CSharpLanguage, which would
+ // be problematic when using a script. See: https://github.com/godotengine/godot/issues/25621
-MonoObject *CSharpInstance::get_mono_object() const {
- ERR_FAIL_COND_V(gchandle.is_released(), nullptr);
- return gchandle.get_target();
-}
-
-Object *CSharpInstance::get_owner() {
- return owner;
-}
-
-bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) {
- ERR_FAIL_COND_V(!script.is_valid(), false);
-
- GD_MONO_SCOPE_THREAD_ATTACH;
-
- MonoObject *mono_object = get_mono_object();
- ERR_FAIL_NULL_V(mono_object, false);
-
- GDMonoClass *top = script->script_class;
-
- while (top && top != script->native) {
- GDMonoField *field = top->get_field(p_name);
+ CSharpScriptBinding script_binding;
- if (field) {
- field->set_value_from_variant(mono_object, p_value);
- return true;
- }
+ script_binding.inited = true;
+ script_binding.type_name = *p_native_name;
+ script_binding.gchandle = gchandle;
+ script_binding.owner = p_unmanaged;
- GDMonoProperty *property = top->get_property(p_name);
+ if (p_ref_counted) {
+ // Unsafe refcount increment. The managed instance also counts as a reference.
+ // This way if the unmanaged world has no references to our owner
+ // but the managed instance is alive, the refcount will be 1 instead of 0.
+ // See: godot_icall_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr)
- if (property) {
- property->set_value_from_variant(mono_object, p_value);
- return true;
+ // May not me referenced yet, so we must use init_ref() instead of reference()
+ if (rc->init_ref()) {
+ CSharpLanguage::get_singleton()->post_unsafe_reference(rc);
}
-
- top = top->get_parent_class();
}
- // Call _set
+ // The object was just created, no script instance binding should have been attached
+ CRASH_COND(CSharpLanguage::has_instance_binding(p_unmanaged));
- top = script->script_class;
+ void *data;
+ {
+ MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex());
+ data = (void *)CSharpLanguage::get_singleton()->insert_script_binding(p_unmanaged, script_binding);
+ }
- while (top && top != script->native) {
- GDMonoMethod *method = top->get_method(CACHED_STRING_NAME(_set), 2);
+ // Should be thread safe because the object was just created and nothing else should be referencing it
+ CSharpLanguage::set_instance_binding(p_unmanaged, data);
+}
- if (method) {
- Variant name = p_name;
- const Variant *args[2] = { &name, &p_value };
+void CSharpLanguage::tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, Ref<CSharpScript> *p_script, bool p_ref_counted) {
+ // This method should not fail
- MonoObject *ret = method->invoke(mono_object, args);
+ Ref<CSharpScript> script = *p_script;
+ // We take care of destructing this reference here, so the managed code won't need to do another P/Invoke call
+ p_script->~Ref();
- if (ret && GDMonoMarshal::unbox<MonoBoolean>(ret)) {
- return true;
- }
+ CRASH_COND(!p_unmanaged);
- break;
- }
+ // All mono objects created from the managed world (e.g.: 'new Player()')
+ // need to have a CSharpScript in order for their methods to be callable from the unmanaged side
- top = top->get_parent_class();
- }
+ RefCounted *rc = Object::cast_to<RefCounted>(p_unmanaged);
- return false;
-}
+ CRASH_COND(p_ref_counted != (bool)rc);
-bool CSharpInstance::get(const StringName &p_name, Variant &r_ret) const {
- ERR_FAIL_COND_V(!script.is_valid(), false);
+ MonoGCHandleData gchandle = MonoGCHandleData(p_gchandle_intptr,
+ p_ref_counted ? gdmono::GCHandleType::WEAK_HANDLE : gdmono::GCHandleType::STRONG_HANDLE);
- GD_MONO_SCOPE_THREAD_ATTACH;
+ CRASH_COND(script.is_null());
- MonoObject *mono_object = get_mono_object();
- ERR_FAIL_NULL_V(mono_object, false);
+ CSharpInstance *csharp_instance = CSharpInstance::create_for_managed_type(p_unmanaged, script.ptr(), gchandle);
- GDMonoClass *top = script->script_class;
+ p_unmanaged->set_script_and_instance(script, csharp_instance);
- while (top && top != script->native) {
- GDMonoField *field = top->get_field(p_name);
+ csharp_instance->connect_event_signals();
+}
- if (field) {
- MonoObject *value = field->get_value(mono_object);
- r_ret = GDMonoMarshal::mono_object_to_variant(value);
- return true;
- }
+void CSharpLanguage::tie_managed_to_unmanaged_with_pre_setup(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged) {
+ // This method should not fail
- GDMonoProperty *property = top->get_property(p_name);
+ CRASH_COND(!p_unmanaged);
- if (property) {
- MonoException *exc = nullptr;
- MonoObject *value = property->get_value(mono_object, &exc);
- if (exc) {
- r_ret = Variant();
- GDMonoUtils::set_pending_exception(exc);
- } else {
- r_ret = GDMonoMarshal::mono_object_to_variant(value);
- }
- return true;
- }
+ CSharpInstance *instance = CAST_CSHARP_INSTANCE(p_unmanaged->get_script_instance());
- top = top->get_parent_class();
+ if (!instance) {
+ // Native bindings don't need post-setup
+ return;
}
- // Call _get
-
- top = script->script_class;
-
- while (top && top != script->native) {
- GDMonoMethod *method = top->get_method(CACHED_STRING_NAME(_get), 1);
+ CRASH_COND(!instance->gchandle.is_released());
- if (method) {
- Variant name = p_name;
- const Variant *args[1] = { &name };
-
- MonoObject *ret = method->invoke(mono_object, args);
-
- if (ret) {
- r_ret = GDMonoMarshal::mono_object_to_variant(ret);
- return true;
- }
+ // Tie managed to unmanaged
+ instance->gchandle = MonoGCHandleData(p_gchandle_intptr, gdmono::GCHandleType::STRONG_HANDLE);
- break;
- }
+ if (instance->base_ref_counted) {
+ instance->_reference_owner_unsafe(); // Here, after assigning the gchandle (for the refcount_incremented callback)
+ }
- top = top->get_parent_class();
+ {
+ MutexLock lock(CSharpLanguage::get_singleton()->get_script_instances_mutex());
+ // instances is a set, so it's safe to insert multiple times (e.g.: from _internal_new_managed)
+ instance->script->instances.insert(instance->owner);
}
- return false;
+ instance->connect_event_signals();
}
-void CSharpInstance::get_properties_state_for_reloading(List<Pair<StringName, Variant>> &r_state) {
- List<PropertyInfo> property_list;
- get_property_list(&property_list);
-
- for (const PropertyInfo &prop_info : property_list) {
- Pair<StringName, Variant> state_pair;
- state_pair.first = prop_info.name;
+CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpScript *p_script, const MonoGCHandleData &p_gchandle) {
+ CSharpInstance *instance = memnew(CSharpInstance(Ref<CSharpScript>(p_script)));
- ManagedType managedType;
+ RefCounted *rc = Object::cast_to<RefCounted>(p_owner);
- GDMonoField *field = nullptr;
- GDMonoClass *top = script->script_class;
- while (top && top != script->native) {
- field = top->get_field(state_pair.first);
- if (field) {
- break;
- }
+ instance->base_ref_counted = rc != nullptr;
+ instance->owner = p_owner;
+ instance->gchandle = p_gchandle;
- top = top->get_parent_class();
- }
- if (!field) {
- continue; // Properties ignored. We get the property baking fields instead.
- }
+ if (instance->base_ref_counted) {
+ instance->_reference_owner_unsafe();
+ }
- managedType = field->get_type();
+ p_script->instances.insert(p_owner);
- if (GDMonoMarshal::managed_to_variant_type(managedType) != Variant::NIL) { // If we can marshal it
- if (get(state_pair.first, state_pair.second)) {
- r_state.push_back(state_pair);
- }
- }
- }
+ return instance;
}
-void CSharpInstance::get_event_signals_state_for_reloading(List<Pair<StringName, Array>> &r_state) {
- MonoObject *owner_managed = get_mono_object();
- ERR_FAIL_NULL(owner_managed);
+Object *CSharpInstance::get_owner() {
+ return owner;
+}
- for (const KeyValue<StringName, CSharpScript::EventSignal> &E : script->event_signals) {
- const CSharpScript::EventSignal &event_signal = E.value;
+bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) {
+ ERR_FAIL_COND_V(!script.is_valid(), false);
- MonoDelegate *delegate_field_value = (MonoDelegate *)event_signal.field->get_value(owner_managed);
- if (!delegate_field_value) {
- continue; // Empty
- }
+ return GDMonoCache::managed_callbacks.CSharpInstanceBridge_Set(
+ gchandle.get_intptr(), &p_name, &p_value);
+}
- Array serialized_data;
- MonoObject *managed_serialized_data = GDMonoMarshal::variant_to_mono_object(serialized_data);
+bool CSharpInstance::get(const StringName &p_name, Variant &r_ret) const {
+ ERR_FAIL_COND_V(!script.is_valid(), false);
- MonoException *exc = nullptr;
- bool success = (bool)CACHED_METHOD_THUNK(DelegateUtils, TrySerializeDelegate).invoke(delegate_field_value, managed_serialized_data, &exc);
+ Variant ret_value;
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- continue;
- }
+ bool ret = GDMonoCache::managed_callbacks.CSharpInstanceBridge_Get(
+ gchandle.get_intptr(), &p_name, &ret_value);
- if (success) {
- r_state.push_back(Pair<StringName, Array>(event_signal.field->get_name(), serialized_data));
- } else if (OS::get_singleton()->is_stdout_verbose()) {
- OS::get_singleton()->print("Failed to serialize event signal delegate\n");
- }
+ if (ret) {
+ r_ret = ret_value;
+ return true;
}
+
+ return false;
}
void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const {
List<PropertyInfo> props;
- for (const KeyValue<StringName, PropertyInfo> &E : script->member_info) {
- props.push_front(E.value);
- }
+ script->get_script_property_list(&props);
// Call _get_property_list
ERR_FAIL_COND(!script.is_valid());
- GD_MONO_SCOPE_THREAD_ATTACH;
-
- MonoObject *mono_object = get_mono_object();
- ERR_FAIL_NULL(mono_object);
-
- GDMonoClass *top = script->script_class;
-
- while (top && top != script->native) {
- GDMonoMethod *method = top->get_method(CACHED_STRING_NAME(_get_property_list), 0);
+ StringName method = SNAME("_get_property_list");
- if (method) {
- MonoObject *ret = method->invoke(mono_object);
+ Variant ret;
+ Callable::CallError call_error;
+ bool ok = GDMonoCache::managed_callbacks.CSharpInstanceBridge_Call(
+ gchandle.get_intptr(), &method, nullptr, 0, &call_error, &ret);
- if (ret) {
- Array array = Array(GDMonoMarshal::mono_object_to_variant(ret));
- for (int i = 0, size = array.size(); i < size; i++) {
- props.push_back(PropertyInfo::from_dict(array.get(i)));
- }
+ // CALL_ERROR_INVALID_METHOD would simply mean it was not overridden
+ if (call_error.error != Callable::CallError::CALL_ERROR_INVALID_METHOD) {
+ if (call_error.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT("Error calling '_get_property_list': " + Variant::get_call_error_text(method, nullptr, 0, call_error));
+ } else if (!ok) {
+ ERR_PRINT("Unexpected error calling '_get_property_list'");
+ } else {
+ Array array = ret;
+ for (int i = 0, size = array.size(); i < size; i++) {
+ p_properties->push_back(PropertyInfo::from_dict(array.get(i)));
}
-
- break;
}
-
- top = top->get_parent_class();
}
for (const PropertyInfo &prop : props) {
@@ -1855,84 +1566,79 @@ Variant::Type CSharpInstance::get_property_type(const StringName &p_name, bool *
return Variant::NIL;
}
-void CSharpInstance::get_method_list(List<MethodInfo> *p_list) const {
- if (!script->is_valid() || !script->script_class) {
- return;
- }
-
- GD_MONO_SCOPE_THREAD_ATTACH;
-
- // TODO: We're filtering out constructors but there may be other methods unsuitable for explicit calls.
- GDMonoClass *top = script->script_class;
+bool CSharpInstance::property_can_revert(const StringName &p_name) const {
+ ERR_FAIL_COND_V(!script.is_valid(), false);
- while (top && top != script->native) {
- const Vector<GDMonoMethod *> &methods = top->get_all_methods();
- for (int i = 0; i < methods.size(); ++i) {
- MethodInfo minfo = methods[i]->get_method_info();
- if (minfo.name != CACHED_STRING_NAME(dotctor)) {
- p_list->push_back(minfo);
- }
- }
+ Variant name_arg = p_name;
+ const Variant *args[1] = { &name_arg };
- top = top->get_parent_class();
- }
-}
+ Variant ret;
+ Callable::CallError call_error;
+ GDMonoCache::managed_callbacks.CSharpInstanceBridge_Call(
+ gchandle.get_intptr(), &CACHED_STRING_NAME(_property_can_revert), args, 1, &call_error, &ret);
-bool CSharpInstance::has_method(const StringName &p_method) const {
- if (!script.is_valid()) {
+ if (call_error.error != Callable::CallError::CALL_OK) {
return false;
}
- GD_MONO_SCOPE_THREAD_ATTACH;
+ return (bool)ret;
+}
+
+bool CSharpInstance::property_get_revert(const StringName &p_name, Variant &r_ret) const {
+ ERR_FAIL_COND_V(!script.is_valid(), false);
- GDMonoClass *top = script->script_class;
+ Variant name_arg = p_name;
+ const Variant *args[1] = { &name_arg };
- while (top && top != script->native) {
- if (top->has_fetched_method_unknown_params(p_method)) {
- return true;
- }
+ Variant ret;
+ Callable::CallError call_error;
+ GDMonoCache::managed_callbacks.CSharpInstanceBridge_Call(
+ gchandle.get_intptr(), &CACHED_STRING_NAME(_property_get_revert), args, 1, &call_error, &ret);
- top = top->get_parent_class();
+ if (call_error.error != Callable::CallError::CALL_OK) {
+ return false;
}
- return false;
+ r_ret = ret;
+ return true;
}
-Variant CSharpInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- ERR_FAIL_COND_V(!script.is_valid(), Variant());
-
- GD_MONO_SCOPE_THREAD_ATTACH;
-
- MonoObject *mono_object = get_mono_object();
-
- if (!mono_object) {
- r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
- ERR_FAIL_V(Variant());
+void CSharpInstance::get_method_list(List<MethodInfo> *p_list) const {
+ if (!script->is_valid() || !script->valid) {
+ return;
}
- GDMonoClass *top = script->script_class;
+ const CSharpScript *top = script.ptr();
+ while (top != nullptr) {
+ for (const CSharpScript::CSharpMethodInfo &E : top->methods) {
+ p_list->push_back(E.method_info);
+ }
- while (top && top != script->native) {
- GDMonoMethod *method = top->get_method(p_method, p_argcount);
+ top = top->base_script.ptr();
+ }
+}
- if (method) {
- MonoObject *return_value = method->invoke(mono_object, p_args);
+bool CSharpInstance::has_method(const StringName &p_method) const {
+ if (!script.is_valid()) {
+ return false;
+ }
- r_error.error = Callable::CallError::CALL_OK;
+ if (!GDMonoCache::godot_api_cache_updated) {
+ return false;
+ }
- if (return_value) {
- return GDMonoMarshal::mono_object_to_variant(return_value);
- } else {
- return Variant();
- }
- }
+ return GDMonoCache::managed_callbacks.CSharpInstanceBridge_HasMethodUnknownParams(
+ gchandle.get_intptr(), &p_method);
+}
- top = top->get_parent_class();
- }
+Variant CSharpInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ ERR_FAIL_COND_V(!script.is_valid(), Variant());
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ Variant ret;
+ GDMonoCache::managed_callbacks.CSharpInstanceBridge_Call(
+ gchandle.get_intptr(), &p_method, p_args, p_argcount, &r_error, &ret);
- return Variant();
+ return ret;
}
bool CSharpInstance::_reference_owner_unsafe() {
@@ -1978,48 +1684,29 @@ bool CSharpInstance::_unreference_owner_unsafe() {
return static_cast<RefCounted *>(owner)->unreference();
}
-MonoObject *CSharpInstance::_internal_new_managed() {
- // Search the constructor first, to fail with an error if it's not found before allocating anything else.
- GDMonoMethod *ctor = script->script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
- ERR_FAIL_NULL_V_MSG(ctor, nullptr,
- "Cannot create script instance because the class does not define a parameterless constructor: '" + script->get_path() + "'.");
-
+bool CSharpInstance::_internal_new_managed() {
CSharpLanguage::get_singleton()->release_script_gchandle(gchandle);
- ERR_FAIL_NULL_V(owner, nullptr);
- ERR_FAIL_COND_V(script.is_null(), nullptr);
+ ERR_FAIL_NULL_V(owner, false);
+ ERR_FAIL_COND_V(script.is_null(), false);
- MonoObject *mono_object = mono_object_new(mono_domain_get(), script->script_class->get_mono_ptr());
+ bool ok = GDMonoCache::managed_callbacks.ScriptManagerBridge_CreateManagedForGodotObjectScriptInstance(
+ script.ptr(), owner, nullptr, 0);
- if (!mono_object) {
+ if (!ok) {
// Important to clear this before destroying the script instance here
script = Ref<CSharpScript>();
-
- bool die = _unreference_owner_unsafe();
- // Not ok for the owner to die here. If there is a situation where this can happen, it will be considered a bug.
- CRASH_COND(die);
-
owner = nullptr;
- ERR_FAIL_V_MSG(nullptr, "Failed to allocate memory for the object.");
- }
-
- // Tie managed to unmanaged
- gchandle = MonoGCHandleData::new_strong_handle(mono_object);
-
- if (base_ref_counted) {
- _reference_owner_unsafe(); // Here, after assigning the gchandle (for the refcount_incremented callback)
+ return false;
}
- CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, owner);
-
- // Construct
- ctor->invoke_raw(mono_object, nullptr);
+ CRASH_COND(gchandle.is_released());
- return mono_object;
+ return true;
}
-void CSharpInstance::mono_object_disposed(MonoObject *p_obj) {
+void CSharpInstance::mono_object_disposed(GCHandleIntPtr p_gchandle_to_free) {
// Must make sure event signals are not left dangling
disconnect_event_signals();
@@ -2027,10 +1714,10 @@ void CSharpInstance::mono_object_disposed(MonoObject *p_obj) {
CRASH_COND(base_ref_counted);
CRASH_COND(gchandle.is_released());
#endif
- CSharpLanguage::get_singleton()->release_script_gchandle(p_obj, gchandle);
+ CSharpLanguage::get_singleton()->release_script_gchandle_thread_safe(p_gchandle_to_free, gchandle);
}
-void CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_delete_owner, bool &r_remove_script_instance) {
+void CSharpInstance::mono_object_disposed_baseref(GCHandleIntPtr p_gchandle_to_free, bool p_is_finalizer, bool &r_delete_owner, bool &r_remove_script_instance) {
#ifdef DEBUG_ENABLED
CRASH_COND(!base_ref_counted);
CRASH_COND(gchandle.is_released());
@@ -2046,20 +1733,20 @@ void CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_f
r_delete_owner = true;
} else {
r_delete_owner = false;
- CSharpLanguage::get_singleton()->release_script_gchandle(p_obj, gchandle);
+ CSharpLanguage::get_singleton()->release_script_gchandle_thread_safe(p_gchandle_to_free, gchandle);
if (!p_is_finalizer) {
// If the native instance is still alive and Dispose() was called
// (instead of the finalizer), then we remove the script instance.
r_remove_script_instance = true;
+ // TODO: Last usage of 'is_finalizing_scripts_domain'. It should be replaced with a check to determine if the load context is being unloaded.
} else if (!GDMono::get_singleton()->is_finalizing_scripts_domain()) {
// If the native instance is still alive and this is called from the finalizer,
// then it was referenced from another thread before the finalizer could
// unreference and delete it, so we want to keep it.
// GC.ReRegisterForFinalize(this) is not safe because the objects referenced by 'this'
// could have already been collected. Instead we will create a new managed instance here.
- MonoObject *new_managed = _internal_new_managed();
- if (!new_managed) {
+ if (!_internal_new_managed()) {
r_remove_script_instance = true;
}
}
@@ -2067,17 +1754,20 @@ void CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_f
}
void CSharpInstance::connect_event_signals() {
- for (const KeyValue<StringName, CSharpScript::EventSignal> &E : script->event_signals) {
- const CSharpScript::EventSignal &event_signal = E.value;
+ CSharpScript *top = script.ptr();
+ while (top != nullptr) {
+ for (CSharpScript::EventSignalInfo &signal : top->get_script_event_signals()) {
+ String signal_name = signal.name;
- StringName signal_name = event_signal.field->get_name();
+ // TODO: Use pooling for ManagedCallable instances.
+ EventSignalCallable *event_signal_callable = memnew(EventSignalCallable(owner, signal_name));
- // TODO: Use pooling for ManagedCallable instances.
- EventSignalCallable *event_signal_callable = memnew(EventSignalCallable(owner, &event_signal));
+ Callable callable(event_signal_callable);
+ connected_event_signals.push_back(callable);
+ owner->connect(signal_name, callable);
+ }
- Callable callable(event_signal_callable);
- connected_event_signals.push_back(callable);
- owner->connect(signal_name, callable);
+ top = top->base_script.ptr();
}
}
@@ -2099,16 +1789,25 @@ void CSharpInstance::refcount_incremented() {
RefCounted *rc_owner = Object::cast_to<RefCounted>(owner);
if (rc_owner->reference_get_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
- GD_MONO_SCOPE_THREAD_ATTACH;
-
// The reference count was increased after the managed side was the only one referencing our owner.
// This means the owner is being referenced again by the unmanaged side,
// so the owner must hold the managed side alive again to avoid it from being GCed.
// Release the current weak handle and replace it with a strong handle.
- MonoGCHandleData strong_gchandle = MonoGCHandleData::new_strong_handle(gchandle.get_target());
- gchandle.release();
- gchandle = strong_gchandle;
+
+ GCHandleIntPtr old_gchandle = gchandle.get_intptr();
+ gchandle.handle = { nullptr }; // No longer owns the handle (released by swap function)
+
+ GCHandleIntPtr new_gchandle = { nullptr };
+ bool create_weak = false;
+ bool target_alive = GDMonoCache::managed_callbacks.ScriptManagerBridge_SwapGCHandleForType(
+ old_gchandle, &new_gchandle, create_weak);
+
+ if (!target_alive) {
+ return; // Called after the managed side was collected, so nothing to do here
+ }
+
+ gchandle = MonoGCHandleData(new_gchandle, gdmono::GCHandleType::STRONG_HANDLE);
}
}
@@ -2123,15 +1822,24 @@ bool CSharpInstance::refcount_decremented() {
int refcount = rc_owner->reference_get_count();
if (refcount == 1 && !gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0
- GD_MONO_SCOPE_THREAD_ATTACH;
-
// If owner owner is no longer referenced by the unmanaged side,
// the managed instance takes responsibility of deleting the owner when GCed.
// Release the current strong handle and replace it with a weak handle.
- MonoGCHandleData weak_gchandle = MonoGCHandleData::new_weak_handle(gchandle.get_target());
- gchandle.release();
- gchandle = weak_gchandle;
+
+ GCHandleIntPtr old_gchandle = gchandle.get_intptr();
+ gchandle.handle = { nullptr }; // No longer owns the handle (released by swap function)
+
+ GCHandleIntPtr new_gchandle = { nullptr };
+ bool create_weak = true;
+ bool target_alive = GDMonoCache::managed_callbacks.ScriptManagerBridge_SwapGCHandleForType(
+ old_gchandle, &new_gchandle, create_weak);
+
+ if (!target_alive) {
+ return refcount == 0; // Called after the managed side was collected, so nothing to do here
+ }
+
+ gchandle = MonoGCHandleData(new_gchandle, gdmono::GCHandleType::WEAK_HANDLE);
return false;
}
@@ -2146,8 +1854,6 @@ const Variant CSharpInstance::get_rpc_config() const {
}
void CSharpInstance::notification(int p_notification) {
- GD_MONO_SCOPE_THREAD_ATTACH;
-
if (p_notification == Object::NOTIFICATION_PREDELETE) {
// When NOTIFICATION_PREDELETE is sent, we also take the chance to call Dispose().
// It's safe to call Dispose() multiple times and NOTIFICATION_PREDELETE is guaranteed
@@ -2167,15 +1873,8 @@ void CSharpInstance::notification(int p_notification) {
_call_notification(p_notification);
- MonoObject *mono_object = get_mono_object();
- ERR_FAIL_NULL(mono_object);
-
- MonoException *exc = nullptr;
- GDMonoUtils::dispose(mono_object, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- }
+ GDMonoCache::managed_callbacks.CSharpInstanceBridge_CallDispose(
+ gchandle.get_intptr(), /* okIfNull */ false);
return;
}
@@ -2184,62 +1883,29 @@ void CSharpInstance::notification(int p_notification) {
}
void CSharpInstance::_call_notification(int p_notification) {
- GD_MONO_ASSERT_THREAD_ATTACHED;
-
- MonoObject *mono_object = get_mono_object();
- ERR_FAIL_NULL(mono_object);
-
- // Custom version of _call_multilevel, optimized for _notification
+ Variant arg = p_notification;
+ const Variant *args[1] = { &arg };
+ StringName method_name = SNAME("_notification");
- int32_t arg = p_notification;
- void *args[1] = { &arg };
- StringName method_name = CACHED_STRING_NAME(_notification);
+ Callable::CallError call_error;
- GDMonoClass *top = script->script_class;
-
- while (top && top != script->native) {
- GDMonoMethod *method = top->get_method(method_name, 1);
-
- if (method) {
- method->invoke_raw(mono_object, args);
- return;
- }
-
- top = top->get_parent_class();
- }
+ Variant ret;
+ GDMonoCache::managed_callbacks.CSharpInstanceBridge_Call(
+ gchandle.get_intptr(), &method_name, args, 1, &call_error, &ret);
}
String CSharpInstance::to_string(bool *r_valid) {
- GD_MONO_SCOPE_THREAD_ATTACH;
+ String res;
+ bool valid;
- MonoObject *mono_object = get_mono_object();
+ GDMonoCache::managed_callbacks.CSharpInstanceBridge_CallToString(
+ gchandle.get_intptr(), &res, &valid);
- if (mono_object == nullptr) {
- if (r_valid) {
- *r_valid = false;
- }
- return String();
+ if (r_valid) {
+ *r_valid = valid;
}
- MonoException *exc = nullptr;
- MonoString *result = GDMonoUtils::object_to_string(mono_object, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- if (r_valid) {
- *r_valid = false;
- }
- return String();
- }
-
- if (result == nullptr) {
- if (r_valid) {
- *r_valid = false;
- }
- return String();
- }
-
- return GDMonoMarshal::mono_string_to_godot(result);
+ return res;
}
Ref<Script> CSharpInstance::get_script() const {
@@ -2255,8 +1921,6 @@ CSharpInstance::CSharpInstance(const Ref<CSharpScript> &p_script) :
}
CSharpInstance::~CSharpInstance() {
- GD_MONO_SCOPE_THREAD_ATTACH;
-
destructing_script_instance = true;
// Must make sure event signals are not left dangling
@@ -2270,16 +1934,8 @@ CSharpInstance::~CSharpInstance() {
// we must call Dispose here, because Dispose calls owner->set_script_instance(nullptr)
// and that would mess up with the new script instance if called later.
- MonoObject *mono_object = gchandle.get_target();
-
- if (mono_object) {
- MonoException *exc = nullptr;
- GDMonoUtils::dispose(mono_object, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- }
- }
+ GDMonoCache::managed_callbacks.CSharpInstanceBridge_CallDispose(
+ gchandle.get_intptr(), /* okIfNull */ true);
}
gchandle.release(); // Make sure the gchandle is released
@@ -2335,10 +1991,6 @@ void CSharpScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder)
#ifdef TOOLS_ENABLED
void CSharpScript::_update_exports_values(HashMap<StringName, Variant> &values, List<PropertyInfo> &propnames) {
- if (base_cache.is_valid()) {
- base_cache->_update_exports_values(values, propnames);
- }
-
for (const KeyValue<StringName, Variant> &E : exported_members_defval_cache) {
values[E.key] = E.value;
}
@@ -2346,52 +1998,9 @@ void CSharpScript::_update_exports_values(HashMap<StringName, Variant> &values,
for (const PropertyInfo &prop_info : exported_members_cache) {
propnames.push_back(prop_info);
}
-}
-
-void CSharpScript::_update_member_info_no_exports() {
- if (exports_invalidated) {
- GD_MONO_ASSERT_THREAD_ATTACHED;
-
- exports_invalidated = false;
-
- member_info.clear();
-
- GDMonoClass *top = script_class;
-
- while (top && top != native) {
- PropertyInfo prop_info;
- bool exported;
-
- const Vector<GDMonoField *> &fields = top->get_all_fields();
-
- for (int i = fields.size() - 1; i >= 0; i--) {
- GDMonoField *field = fields[i];
-
- if (_get_member_export(field, /* inspect export: */ false, prop_info, exported)) {
- StringName member_name = field->get_name();
- member_info[member_name] = prop_info;
- exported_members_cache.push_front(prop_info);
- exported_members_defval_cache[member_name] = Variant();
- }
- }
-
- const Vector<GDMonoProperty *> &properties = top->get_all_properties();
-
- for (int i = properties.size() - 1; i >= 0; i--) {
- GDMonoProperty *property = properties[i];
-
- if (_get_member_export(property, /* inspect export: */ false, prop_info, exported)) {
- StringName member_name = property->get_name();
-
- member_info[member_name] = prop_info;
- exported_members_cache.push_front(prop_info);
- exported_members_defval_cache[member_name] = Variant();
- }
- }
-
- top = top->get_parent_class();
- }
+ if (base_script.is_valid()) {
+ base_script->_update_exports_values(values, propnames);
}
}
#endif
@@ -2413,155 +2022,65 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda
if (exports_invalidated)
#endif
{
- GD_MONO_SCOPE_THREAD_ATTACH;
+#ifdef TOOLS_ENABLED
+ exports_invalidated = false;
+#endif
changed = true;
member_info.clear();
#ifdef TOOLS_ENABLED
- MonoObject *tmp_object = nullptr;
- Object *tmp_native = nullptr;
- uint32_t tmp_pinned_gchandle = 0;
-
- if (is_editor) {
- exports_invalidated = false;
-
- exported_members_cache.clear();
- exported_members_defval_cache.clear();
-
- // Here we create a temporary managed instance of the class to get the initial values
- tmp_object = mono_object_new(mono_domain_get(), script_class->get_mono_ptr());
-
- if (!tmp_object) {
- ERR_PRINT("Failed to allocate temporary MonoObject.");
- return false;
- }
-
- tmp_pinned_gchandle = GDMonoUtils::new_strong_gchandle_pinned(tmp_object); // pin it (not sure if needed)
-
- GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
-
- ERR_FAIL_NULL_V_MSG(ctor, false,
- "Cannot construct temporary MonoObject because the class does not define a parameterless constructor: '" + get_path() + "'.");
-
- MonoException *ctor_exc = nullptr;
- ctor->invoke(tmp_object, nullptr, &ctor_exc);
-
- tmp_native = GDMonoMarshal::unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(tmp_object));
-
- if (ctor_exc) {
- // TODO: Should we free 'tmp_native' if the exception was thrown after its creation?
-
- GDMonoUtils::free_gchandle(tmp_pinned_gchandle);
- tmp_object = nullptr;
-
- ERR_PRINT("Exception thrown from constructor of temporary MonoObject:");
- GDMonoUtils::debug_print_unhandled_exception(ctor_exc);
- return false;
- }
- }
+ exported_members_cache.clear();
+ exported_members_defval_cache.clear();
#endif
- GDMonoClass *top = script_class;
-
- while (top && top != native) {
- PropertyInfo prop_info;
- bool exported;
-
- const Vector<GDMonoField *> &fields = top->get_all_fields();
-
- for (int i = fields.size() - 1; i >= 0; i--) {
- GDMonoField *field = fields[i];
-
- if (_get_member_export(field, /* inspect export: */ true, prop_info, exported)) {
- StringName member_name = field->get_name();
-
- member_info[member_name] = prop_info;
-
- if (exported) {
+ if (GDMonoCache::godot_api_cache_updated) {
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_GetPropertyInfoList(this,
+ [](CSharpScript *p_script, const String *p_current_class_name, GDMonoCache::godotsharp_property_info *p_props, int32_t p_count) {
#ifdef TOOLS_ENABLED
- if (is_editor) {
- exported_members_cache.push_front(prop_info);
-
- if (tmp_object) {
- exported_members_defval_cache[member_name] = GDMonoMarshal::mono_object_to_variant(field->get_value(tmp_object));
- }
- }
+ p_script->exported_members_cache.push_back(PropertyInfo(
+ Variant::NIL, *p_current_class_name, PROPERTY_HINT_NONE,
+ p_script->get_path(), PROPERTY_USAGE_CATEGORY));
#endif
-#if defined(TOOLS_ENABLED) || defined(DEBUG_ENABLED)
- exported_members_names.insert(member_name);
-#endif
- }
- }
- }
+ for (int i = 0; i < p_count; i++) {
+ const GDMonoCache::godotsharp_property_info &prop = p_props[i];
- const Vector<GDMonoProperty *> &properties = top->get_all_properties();
+ StringName name = *reinterpret_cast<const StringName *>(&prop.name);
+ String hint_string = *reinterpret_cast<const String *>(&prop.hint_string);
- for (int i = properties.size() - 1; i >= 0; i--) {
- GDMonoProperty *property = properties[i];
+ PropertyInfo pinfo(prop.type, name, prop.hint, hint_string, prop.usage);
- if (_get_member_export(property, /* inspect export: */ true, prop_info, exported)) {
- StringName member_name = property->get_name();
+ p_script->member_info[name] = pinfo;
- member_info[member_name] = prop_info;
+ if (prop.exported) {
- if (exported) {
#ifdef TOOLS_ENABLED
- if (is_editor) {
- exported_members_cache.push_front(prop_info);
- if (tmp_object) {
- MonoException *exc = nullptr;
- MonoObject *ret = property->get_value(tmp_object, &exc);
- if (exc) {
- exported_members_defval_cache[member_name] = Variant();
- GDMonoUtils::debug_print_unhandled_exception(exc);
- } else {
- exported_members_defval_cache[member_name] = GDMonoMarshal::mono_object_to_variant(ret);
- }
- }
- }
+ p_script->exported_members_cache.push_back(pinfo);
#endif
#if defined(TOOLS_ENABLED) || defined(DEBUG_ENABLED)
- exported_members_names.insert(member_name);
+ p_script->exported_members_names.insert(name);
#endif
- }
- }
- }
-
- top = top->get_parent_class();
- }
+ }
+ }
+ });
#ifdef TOOLS_ENABLED
- if (is_editor) {
- // Need to check this here, before disposal
- bool base_ref_counted = Object::cast_to<RefCounted>(tmp_native) != nullptr;
-
- // Dispose the temporary managed instance
-
- MonoException *exc = nullptr;
- GDMonoUtils::dispose(tmp_object, &exc);
-
- if (exc) {
- ERR_PRINT("Exception thrown from method Dispose() of temporary MonoObject:");
- GDMonoUtils::debug_print_unhandled_exception(exc);
- }
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_GetPropertyDefaultValues(this,
+ [](CSharpScript *p_script, GDMonoCache::godotsharp_property_def_val_pair *p_def_vals, int32_t p_count) {
+ for (int i = 0; i < p_count; i++) {
+ const GDMonoCache::godotsharp_property_def_val_pair &def_val_pair = p_def_vals[i];
- GDMonoUtils::free_gchandle(tmp_pinned_gchandle);
- tmp_object = nullptr;
+ StringName name = *reinterpret_cast<const StringName *>(&def_val_pair.name);
+ Variant value = *reinterpret_cast<const Variant *>(&def_val_pair.value);
- if (tmp_native && !base_ref_counted) {
- Node *node = Object::cast_to<Node>(tmp_native);
- if (node && node->is_inside_tree()) {
- ERR_PRINT("Temporary instance was added to the scene tree.");
- } else {
- memdelete(tmp_native);
- }
- }
- }
+ p_script->exported_members_defval_cache[name] = value;
+ }
+ });
#endif
+ }
}
#ifdef TOOLS_ENABLED
@@ -2588,374 +2107,6 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda
return changed;
}
-void CSharpScript::load_script_signals(GDMonoClass *p_class, GDMonoClass *p_native_class) {
- // no need to load the script's signals more than once
- if (!signals_invalidated) {
- return;
- }
-
- // make sure this classes signals are empty when loading for the first time
- _signals.clear();
- event_signals.clear();
-
- GD_MONO_SCOPE_THREAD_ATTACH;
-
- GDMonoClass *top = p_class;
- while (top && top != p_native_class) {
- const Vector<GDMonoClass *> &delegates = top->get_all_delegates();
- for (int i = delegates.size() - 1; i >= 0; --i) {
- GDMonoClass *delegate = delegates[i];
-
- if (!delegate->has_attribute(CACHED_CLASS(SignalAttribute))) {
- continue;
- }
-
- // Arguments are accessibles as arguments of .Invoke method
- GDMonoMethod *invoke_method = delegate->get_method(mono_get_delegate_invoke(delegate->get_mono_ptr()));
-
- Vector<SignalParameter> parameters;
- if (_get_signal(top, invoke_method, parameters)) {
- _signals[delegate->get_name()] = parameters;
- }
- }
-
- List<StringName> found_event_signals;
-
- void *iter = nullptr;
- MonoEvent *raw_event = nullptr;
- while ((raw_event = mono_class_get_events(top->get_mono_ptr(), &iter)) != nullptr) {
- MonoCustomAttrInfo *event_attrs = mono_custom_attrs_from_event(top->get_mono_ptr(), raw_event);
- if (event_attrs) {
- if (mono_custom_attrs_has_attr(event_attrs, CACHED_CLASS(SignalAttribute)->get_mono_ptr())) {
- String event_name = String::utf8(mono_event_get_name(raw_event));
- found_event_signals.push_back(StringName(event_name));
- }
-
- mono_custom_attrs_free(event_attrs);
- }
- }
-
- const Vector<GDMonoField *> &fields = top->get_all_fields();
- for (int i = 0; i < fields.size(); i++) {
- GDMonoField *field = fields[i];
-
- GDMonoClass *field_class = field->get_type().type_class;
-
- if (!mono_class_is_delegate(field_class->get_mono_ptr())) {
- continue;
- }
-
- if (!found_event_signals.find(field->get_name())) {
- continue;
- }
-
- GDMonoMethod *invoke_method = field_class->get_method(mono_get_delegate_invoke(field_class->get_mono_ptr()));
-
- Vector<SignalParameter> parameters;
- if (_get_signal(top, invoke_method, parameters)) {
- event_signals[field->get_name()] = { field, invoke_method, parameters };
- }
- }
-
- top = top->get_parent_class();
- }
-
- signals_invalidated = false;
-}
-
-bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoMethod *p_delegate_invoke, Vector<SignalParameter> &params) {
- GD_MONO_ASSERT_THREAD_ATTACHED;
-
- Vector<StringName> names;
- Vector<ManagedType> types;
- p_delegate_invoke->get_parameter_names(names);
- p_delegate_invoke->get_parameter_types(types);
-
- for (int i = 0; i < names.size(); ++i) {
- SignalParameter arg;
- arg.name = names[i];
-
- bool nil_is_variant = false;
- arg.type = GDMonoMarshal::managed_to_variant_type(types[i], &nil_is_variant);
-
- if (arg.type == Variant::NIL) {
- if (nil_is_variant) {
- arg.nil_is_variant = true;
- } else {
- ERR_PRINT("Unknown type of signal parameter: '" + arg.name + "' in '" + p_class->get_full_name() + "'.");
- return false;
- }
- }
-
- params.push_back(arg);
- }
-
- return true;
-}
-
-/**
- * Returns false if there was an error, otherwise true.
- * If there was an error, r_prop_info and r_exported are not assigned any value.
- */
-bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect_export, PropertyInfo &r_prop_info, bool &r_exported) {
- GD_MONO_ASSERT_THREAD_ATTACHED;
-
- // Goddammit, C++. All I wanted was some nested functions.
-#define MEMBER_FULL_QUALIFIED_NAME(m_member) \
- (m_member->get_enclosing_class()->get_full_name() + "." + (String)m_member->get_name())
-
- if (p_member->is_static()) {
-#ifdef TOOLS_ENABLED
- if (p_member->has_attribute(CACHED_CLASS(ExportAttribute))) {
- ERR_PRINT("Cannot export member because it is static: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
- }
-#endif
- return false;
- }
-
- if (member_info.has(p_member->get_name())) {
- return false;
- }
-
- ManagedType type;
-
- if (p_member->get_member_type() == IMonoClassMember::MEMBER_TYPE_FIELD) {
- type = static_cast<GDMonoField *>(p_member)->get_type();
- } else if (p_member->get_member_type() == IMonoClassMember::MEMBER_TYPE_PROPERTY) {
- type = static_cast<GDMonoProperty *>(p_member)->get_type();
- } else {
- CRASH_NOW();
- }
-
- bool exported = p_member->has_attribute(CACHED_CLASS(ExportAttribute));
-
- if (p_member->get_member_type() == IMonoClassMember::MEMBER_TYPE_PROPERTY) {
- GDMonoProperty *property = static_cast<GDMonoProperty *>(p_member);
- if (!property->has_getter()) {
-#ifdef TOOLS_ENABLED
- if (exported) {
- ERR_PRINT("Cannot export a property without a getter: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
- }
-#endif
- return false;
- }
- if (!property->has_setter()) {
-#ifdef TOOLS_ENABLED
- if (exported) {
- ERR_PRINT("Cannot export a property without a setter: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
- }
-#endif
- return false;
- }
- }
-
- bool nil_is_variant = false;
- Variant::Type variant_type = GDMonoMarshal::managed_to_variant_type(type, &nil_is_variant);
-
- if (!p_inspect_export || !exported) {
- r_prop_info = PropertyInfo(variant_type, (String)p_member->get_name(), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_SCRIPT_VARIABLE);
- r_exported = false;
- return true;
- }
-
-#ifdef TOOLS_ENABLED
- MonoObject *attr = p_member->get_attribute(CACHED_CLASS(ExportAttribute));
-#endif
-
- PropertyHint hint = PROPERTY_HINT_NONE;
- String hint_string;
-
- if (variant_type == Variant::NIL && !nil_is_variant) {
-#ifdef TOOLS_ENABLED
- ERR_PRINT("Unknown exported member type: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
-#endif
- return false;
- }
-
-#ifdef TOOLS_ENABLED
- int hint_res = _try_get_member_export_hint(p_member, type, variant_type, /* allow_generics: */ true, hint, hint_string);
-
- ERR_FAIL_COND_V_MSG(hint_res == -1, false,
- "Error while trying to determine information about the exported member: '" +
- MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
-
- if (hint_res == 0) {
- hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr));
- hint_string = CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr);
- }
-#endif
-
- uint32_t prop_usage = PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE;
-
- if (variant_type == Variant::NIL) {
- // System.Object (Variant)
- prop_usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- }
-
- r_prop_info = PropertyInfo(variant_type, (String)p_member->get_name(), hint, hint_string, prop_usage);
- r_exported = true;
-
- return true;
-
-#undef MEMBER_FULL_QUALIFIED_NAME
-}
-
-#ifdef TOOLS_ENABLED
-int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, ManagedType p_type, Variant::Type p_variant_type, bool p_allow_generics, PropertyHint &r_hint, String &r_hint_string) {
- if (p_variant_type == Variant::NIL) {
- // System.Object (Variant)
- return 1;
- }
-
- GD_MONO_ASSERT_THREAD_ATTACHED;
-
- if (p_variant_type == Variant::INT && p_type.type_encoding == MONO_TYPE_VALUETYPE && mono_class_is_enum(p_type.type_class->get_mono_ptr())) {
- MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
- r_hint = GDMonoUtils::Marshal::type_has_flags_attribute(reftype) ? PROPERTY_HINT_FLAGS : PROPERTY_HINT_ENUM;
-
- Vector<MonoClassField *> fields = p_type.type_class->get_enum_fields();
-
- MonoType *enum_basetype = mono_class_enum_basetype(p_type.type_class->get_mono_ptr());
-
- String name_only_hint_string;
-
- // True: enum Foo { Bar, Baz, Quux }
- // True: enum Foo { Bar = 0, Baz = 1, Quux = 2 }
- // False: enum Foo { Bar = 0, Baz = 7, Quux = 5 }
- bool uses_default_values = true;
-
- for (int i = 0; i < fields.size(); i++) {
- MonoClassField *field = fields[i];
-
- if (i > 0) {
- r_hint_string += ",";
- name_only_hint_string += ",";
- }
-
- String enum_field_name = String::utf8(mono_field_get_name(field));
- r_hint_string += enum_field_name;
- name_only_hint_string += enum_field_name;
-
- // TODO:
- // Instead of using mono_field_get_value_object, we can do this without boxing. Check the
- // internal mono functions: ves_icall_System_Enum_GetEnumValuesAndNames and the get_enum_field.
-
- MonoObject *val_obj = mono_field_get_value_object(mono_domain_get(), field, nullptr);
-
- ERR_FAIL_NULL_V_MSG(val_obj, -1, "Failed to get '" + enum_field_name + "' constant enum value.");
-
- bool r_error;
- uint64_t val = GDMonoUtils::unbox_enum_value(val_obj, enum_basetype, r_error);
- ERR_FAIL_COND_V_MSG(r_error, -1, "Failed to unbox '" + enum_field_name + "' constant enum value.");
-
- unsigned int expected_val = r_hint == PROPERTY_HINT_FLAGS ? 1 << i : i;
- if (val != expected_val) {
- uses_default_values = false;
- }
-
- r_hint_string += ":";
- r_hint_string += String::num_uint64(val);
- }
-
- if (uses_default_values) {
- // If we use the format NAME:VAL, that's what the editor displays.
- // That's annoying if the user is not using custom values for the enum constants.
- // This may not be needed in the future if the editor is changed to not display values.
- r_hint_string = name_only_hint_string;
- }
- } else if (p_variant_type == Variant::OBJECT && CACHED_CLASS(GodotResource)->is_assignable_from(p_type.type_class)) {
- GDMonoClass *field_native_class = GDMonoUtils::get_class_native_base(p_type.type_class);
- CRASH_COND(field_native_class == nullptr);
-
- r_hint = PROPERTY_HINT_RESOURCE_TYPE;
- r_hint_string = String(NATIVE_GDMONOCLASS_NAME(field_native_class));
- } else if (p_variant_type == Variant::OBJECT && CACHED_CLASS(Node)->is_assignable_from(p_type.type_class)) {
- GDMonoClass *field_native_class = GDMonoUtils::get_class_native_base(p_type.type_class);
- CRASH_COND(field_native_class == nullptr);
-
- r_hint = PROPERTY_HINT_NODE_TYPE;
- r_hint_string = String(NATIVE_GDMONOCLASS_NAME(field_native_class));
- } else if (p_allow_generics && p_variant_type == Variant::ARRAY) {
- // Nested arrays are not supported in the inspector
-
- ManagedType elem_type;
-
- if (!GDMonoMarshal::try_get_array_element_type(p_type, elem_type)) {
- return 0;
- }
-
- Variant::Type elem_variant_type = GDMonoMarshal::managed_to_variant_type(elem_type);
-
- PropertyHint elem_hint = PROPERTY_HINT_NONE;
- String elem_hint_string;
-
- ERR_FAIL_COND_V_MSG(elem_variant_type == Variant::NIL, -1, "Unknown array element type.");
-
- bool preset_hint = false;
- if (elem_variant_type == Variant::STRING) {
- MonoObject *attr = p_member->get_attribute(CACHED_CLASS(ExportAttribute));
- if (PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr)) == PROPERTY_HINT_ENUM) {
- r_hint_string = itos(elem_variant_type) + "/" + itos(PROPERTY_HINT_ENUM) + ":" + CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr);
- preset_hint = true;
- }
- }
-
- if (!preset_hint) {
- int hint_res = _try_get_member_export_hint(p_member, elem_type, elem_variant_type, /* allow_generics: */ false, elem_hint, elem_hint_string);
-
- ERR_FAIL_COND_V_MSG(hint_res == -1, -1, "Error while trying to determine information about the array element type.");
-
- // Format: type/hint:hint_string
- r_hint_string = itos(elem_variant_type) + "/" + itos(elem_hint) + ":" + elem_hint_string;
- }
-
- r_hint = PROPERTY_HINT_TYPE_STRING;
-
- } else if (p_allow_generics && p_variant_type == Variant::DICTIONARY) {
- // TODO: Dictionaries are not supported in the inspector
- } else {
- return 0;
- }
-
- return 1;
-}
-#endif
-
-Variant CSharpScript::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- if (unlikely(GDMono::get_singleton() == nullptr)) {
- // Probably not the best error but eh.
- r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
- return Variant();
- }
-
- GD_MONO_SCOPE_THREAD_ATTACH;
-
- GDMonoClass *top = script_class;
-
- while (top && top != native) {
- GDMonoMethod *method = top->get_method(p_method, p_argcount);
-
- if (method && method->is_static()) {
- MonoObject *result = method->invoke(nullptr, p_args);
-
- if (result) {
- return GDMonoMarshal::mono_object_to_variant(result);
- } else {
- return Variant();
- }
- }
-
- top = top->get_parent_class();
- }
-
- // No static method found. Try regular instance calls
- return Script::callp(p_method, p_args, p_argcount, r_error);
-}
-
-void CSharpScript::_resource_path_changed() {
- _update_name();
-}
-
bool CSharpScript::_get(const StringName &p_name, Variant &r_ret) const {
if (p_name == CSharpLanguage::singleton->string_names._script_source) {
r_ret = get_source_code();
@@ -2983,107 +2134,107 @@ void CSharpScript::_bind_methods() {
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &CSharpScript::_new, MethodInfo("new"));
}
-Ref<CSharpScript> CSharpScript::create_for_managed_type(GDMonoClass *p_class, GDMonoClass *p_native) {
- // This method should not fail, only assertions allowed
-
- CRASH_COND(p_class == nullptr);
-
- // TODO OPTIMIZE: Cache the 'CSharpScript' associated with this 'p_class' instead of allocating a new one every time
- Ref<CSharpScript> script = memnew(CSharpScript);
-
- initialize_for_managed_type(script, p_class, p_native);
-
- return script;
-}
-
-void CSharpScript::initialize_for_managed_type(Ref<CSharpScript> p_script, GDMonoClass *p_class, GDMonoClass *p_native) {
- // This method should not fail, only assertions allowed
+void CSharpScript::reload_registered_script(Ref<CSharpScript> p_script) {
+ // IMPORTANT:
+ // This method must be called only after the CSharpScript and its associated type
+ // have been added to the script bridge map in the ScriptManagerBridge C# class.
+ // Other than that, it's the same as `CSharpScript::reload`.
- CRASH_COND(p_class == nullptr);
+ // This method should not fail, only assertions allowed.
- p_script->name = p_class->get_name();
- p_script->script_class = p_class;
- p_script->native = p_native;
-
- CRASH_COND(p_script->native == nullptr);
+ // Unlike `reload`, we print an error rather than silently returning,
+ // as we can assert this won't be called a second time until invalidated.
+ ERR_FAIL_COND(!p_script->reload_invalidated);
p_script->valid = true;
p_script->reload_invalidated = false;
update_script_class_info(p_script);
-#ifdef TOOLS_ENABLED
- p_script->_update_member_info_no_exports();
-#endif
+ p_script->_update_exports();
}
// Extract information about the script using the mono class.
void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
- GDMonoClass *base = p_script->script_class->get_parent_class();
+ bool tool = false;
- // `base` should only be set if the script is a user defined type.
- if (base != p_script->native) {
- p_script->base = base;
- }
+ // TODO: Use GDNative godot_dictionary
+ Array methods_array;
+ methods_array.~Array();
+ Dictionary rpc_functions_dict;
+ rpc_functions_dict.~Dictionary();
+ Dictionary signals_dict;
+ signals_dict.~Dictionary();
- p_script->tool = p_script->script_class->has_attribute(CACHED_CLASS(ToolAttribute));
+ Ref<CSharpScript> base_script;
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_UpdateScriptClassInfo(
+ p_script.ptr(), &tool, &methods_array, &rpc_functions_dict, &signals_dict, &base_script);
- if (!p_script->tool) {
- GDMonoClass *nesting_class = p_script->script_class->get_nesting_class();
- p_script->tool = nesting_class && nesting_class->has_attribute(CACHED_CLASS(ToolAttribute));
- }
+ p_script->tool = tool;
-#ifdef TOOLS_ENABLED
- if (!p_script->tool) {
- p_script->tool = p_script->script_class->get_assembly() == GDMono::get_singleton()->get_tools_assembly();
- }
-#endif
+ p_script->rpc_config.clear();
+ p_script->rpc_config = rpc_functions_dict;
-#ifdef DEBUG_ENABLED
- // For debug builds, we must fetch from all native base methods as well.
- // Native base methods must be fetched before the current class.
- // Not needed if the script class itself is a native class.
+ // Methods
- if (p_script->script_class != p_script->native) {
- GDMonoClass *native_top = p_script->native;
- while (native_top) {
- native_top->fetch_methods_with_godot_api_checks(p_script->native);
+ p_script->methods.clear();
- if (native_top == CACHED_CLASS(GodotObject)) {
- break;
- }
+ p_script->methods.resize(methods_array.size());
+ int push_index = 0;
+
+ for (int i = 0; i < methods_array.size(); i++) {
+ Dictionary method_info_dict = methods_array[i];
- native_top = native_top->get_parent_class();
+ StringName name = method_info_dict["name"];
+
+ MethodInfo mi;
+ mi.name = name;
+
+ Array params = method_info_dict["params"];
+
+ for (int j = 0; j < params.size(); j++) {
+ Dictionary param = params[j];
+
+ Variant::Type param_type = (Variant::Type)(int)param["type"];
+ PropertyInfo arg_info = PropertyInfo(param_type, (String)param["name"]);
+ arg_info.usage = (uint32_t)param["usage"];
+ mi.arguments.push_back(arg_info);
}
+
+ p_script->methods.set(push_index++, CSharpMethodInfo{ name, mi });
}
-#endif
- p_script->script_class->fetch_methods_with_godot_api_checks(p_script->native);
+ // Event signals
- p_script->rpc_config.clear();
+ // Performance is not critical here as this will be replaced with source generators.
- GDMonoClass *top = p_script->script_class;
- while (top && top != p_script->native) {
- // Fetch methods from base classes as well
- top->fetch_methods_with_godot_api_checks(p_script->native);
+ p_script->event_signals.clear();
- // Update RPC info
- {
- Vector<GDMonoMethod *> methods = top->get_all_methods();
- for (int i = 0; i < methods.size(); i++) {
- if (!methods[i]->is_static()) {
- const Variant rpc_config = p_script->_member_get_rpc_config(methods[i]);
- if (rpc_config.get_type() != Variant::NIL) {
- p_script->rpc_config[methods[i]->get_name()] = rpc_config;
- }
- }
- }
+ // Sigh... can't we just have capacity?
+ p_script->event_signals.resize(signals_dict.size());
+ push_index = 0;
+
+ for (const Variant *s = signals_dict.next(nullptr); s != nullptr; s = signals_dict.next(s)) {
+ StringName name = *s;
+
+ MethodInfo mi;
+ mi.name = name;
+
+ Array params = signals_dict[*s];
+
+ for (int i = 0; i < params.size(); i++) {
+ Dictionary param = params[i];
+
+ Variant::Type param_type = (Variant::Type)(int)param["type"];
+ PropertyInfo arg_info = PropertyInfo(param_type, (String)param["name"]);
+ arg_info.usage = (uint32_t)param["usage"];
+ mi.arguments.push_back(arg_info);
}
- top = top->get_parent_class();
+ p_script->event_signals.set(push_index++, EventSignalInfo{ name, mi });
}
- p_script->load_script_signals(p_script->script_class, p_script->native);
+ p_script->base_script = base_script;
}
bool CSharpScript::can_instantiate() const {
@@ -3096,43 +2247,22 @@ bool CSharpScript::can_instantiate() const {
// FIXME Need to think this through better.
// For tool scripts, this will never fire if the class is not found. That's because we
// don't know if it's a tool script if we can't find the class to access the attributes.
- if (extra_cond && !script_class) {
- if (GDMono::get_singleton()->get_project_assembly() == nullptr) {
- // The project assembly is not loaded
- ERR_FAIL_V_MSG(false, "Cannot instance script because the project assembly is not loaded. Script: '" + get_path() + "'.");
- } else {
- // The project assembly is loaded, but the class could not found
- ERR_FAIL_V_MSG(false, "Cannot instance script because the class '" + name + "' could not be found. Script: '" + get_path() + "'.");
- }
+ if (extra_cond && !valid) {
+ ERR_FAIL_V_MSG(false, "Cannot instance script because the associated class could not be found. Script: '" + get_path() + "'.");
}
return valid && extra_cond;
}
StringName CSharpScript::get_instance_base_type() const {
- if (native) {
- return native->get_name();
- } else {
- return StringName();
- }
+ StringName native_name;
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_GetScriptNativeName(this, &native_name);
+ return native_name;
}
CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error) {
- GD_MONO_ASSERT_THREAD_ATTACHED;
-
/* STEP 1, CREATE */
- // Search the constructor first, to fail with an error if it's not found before allocating anything else.
- GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), p_argcount);
- if (ctor == nullptr) {
- ERR_FAIL_COND_V_MSG(p_argcount == 0, nullptr,
- "Cannot create script instance. The class '" + script_class->get_full_name() +
- "' does not define a parameterless constructor." +
- (get_path().is_empty() ? String() : " Path: '" + get_path() + "'."));
-
- ERR_FAIL_V_MSG(nullptr, "Constructor not found.");
- }
-
Ref<RefCounted> ref;
if (p_is_ref_counted) {
// Hold it alive. Important if we have to dispose a script instance binding before creating the CSharpInstance.
@@ -3146,15 +2276,8 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
if (script_binding.inited && !script_binding.gchandle.is_released()) {
- MonoObject *mono_object = script_binding.gchandle.get_target();
- if (mono_object) {
- MonoException *exc = nullptr;
- GDMonoUtils::dispose(mono_object, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- }
- }
+ GDMonoCache::managed_callbacks.CSharpInstanceBridge_CallDispose(
+ script_binding.gchandle.get_intptr(), /* okIfNull */ true);
script_binding.gchandle.release(); // Just in case
script_binding.inited = false;
@@ -3168,38 +2291,19 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
/* STEP 2, INITIALIZE AND CONSTRUCT */
- MonoObject *mono_object = mono_object_new(mono_domain_get(), script_class->get_mono_ptr());
+ bool ok = GDMonoCache::managed_callbacks.ScriptManagerBridge_CreateManagedForGodotObjectScriptInstance(
+ this, p_owner, p_args, p_argcount);
- if (!mono_object) {
+ if (!ok) {
// Important to clear this before destroying the script instance here
instance->script = Ref<CSharpScript>();
instance->owner = nullptr;
-
- bool die = instance->_unreference_owner_unsafe();
- // Not ok for the owner to die here. If there is a situation where this can happen, it will be considered a bug.
- CRASH_COND(die);
-
p_owner->set_script_instance(nullptr);
- r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
- ERR_FAIL_V_MSG(nullptr, "Failed to allocate memory for the object.");
- }
-
- // Tie managed to unmanaged
- instance->gchandle = MonoGCHandleData::new_strong_handle(mono_object);
-
- if (instance->base_ref_counted) {
- instance->_reference_owner_unsafe(); // Here, after assigning the gchandle (for the refcount_incremented callback)
- }
- {
- MutexLock lock(CSharpLanguage::get_singleton()->script_instances_mutex);
- instances.insert(instance->owner);
+ return nullptr;
}
- CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, instance->owner);
-
- // Construct
- ctor->invoke(mono_object, p_args);
+ CRASH_COND(instance->gchandle.is_released());
/* STEP 3, PARTY */
@@ -3215,11 +2319,12 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Callable::Cal
r_error.error = Callable::CallError::CALL_OK;
- ERR_FAIL_NULL_V(native, Variant());
+ StringName native_name;
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_GetScriptNativeName(this, &native_name);
- GD_MONO_SCOPE_THREAD_ATTACH;
+ ERR_FAIL_COND_V(native_name == StringName(), Variant());
- Object *owner = ClassDB::instantiate(NATIVE_GDMONOCLASS_NAME(native));
+ Object *owner = ClassDB::instantiate(native_name);
Ref<RefCounted> ref;
RefCounted *r = Object::cast_to<RefCounted>(owner);
@@ -3247,18 +2352,18 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) {
CRASH_COND(!valid);
#endif
- GD_MONO_SCOPE_THREAD_ATTACH;
+ StringName native_name;
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_GetScriptNativeName(this, &native_name);
- if (native) {
- StringName native_name = NATIVE_GDMONOCLASS_NAME(native);
- if (!ClassDB::is_parent_class(p_this->get_class_name(), native_name)) {
- if (EngineDebugger::is_active()) {
- CSharpLanguage::get_singleton()->debug_break_parse(get_path(), 0,
- "Script inherits from native type '" + String(native_name) +
- "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'");
- }
- ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(native_name) + "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'.");
+ ERR_FAIL_COND_V(native_name == StringName(), nullptr);
+
+ if (!ClassDB::is_parent_class(p_this->get_class_name(), native_name)) {
+ if (EngineDebugger::is_active()) {
+ CSharpLanguage::get_singleton()->debug_break_parse(get_path(), 0,
+ "Script inherits from native type '" + String(native_name) +
+ "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'");
}
+ ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(native_name) + "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'.");
}
Callable::CallError unchecked_error;
@@ -3300,54 +2405,43 @@ void CSharpScript::set_source_code(const String &p_code) {
}
void CSharpScript::get_script_method_list(List<MethodInfo> *p_list) const {
- if (!script_class) {
+ if (!valid) {
return;
}
- GD_MONO_SCOPE_THREAD_ATTACH;
-
- // TODO: We're filtering out constructors but there may be other methods unsuitable for explicit calls.
- GDMonoClass *top = script_class;
-
- while (top && top != native) {
- const Vector<GDMonoMethod *> &methods = top->get_all_methods();
- for (int i = 0; i < methods.size(); ++i) {
- MethodInfo minfo = methods[i]->get_method_info();
- if (minfo.name != CACHED_STRING_NAME(dotctor)) {
- p_list->push_back(methods[i]->get_method_info());
- }
+ const CSharpScript *top = this;
+ while (top != nullptr) {
+ for (const CSharpMethodInfo &E : top->methods) {
+ p_list->push_back(E.method_info);
}
- top = top->get_parent_class();
+ top = top->base_script.ptr();
}
}
bool CSharpScript::has_method(const StringName &p_method) const {
- if (!script_class) {
+ if (!valid) {
return false;
}
- GD_MONO_SCOPE_THREAD_ATTACH;
+ for (const CSharpMethodInfo &E : methods) {
+ if (E.name == p_method) {
+ return true;
+ }
+ }
- return script_class->has_fetched_method_unknown_params(p_method);
+ return false;
}
MethodInfo CSharpScript::get_method_info(const StringName &p_method) const {
- if (!script_class) {
+ if (!valid) {
return MethodInfo();
}
- GD_MONO_SCOPE_THREAD_ATTACH;
-
- GDMonoClass *top = script_class;
-
- while (top && top != native) {
- GDMonoMethod *params = top->get_fetched_method_unknown_params(p_method);
- if (params) {
- return params->get_method_info();
+ for (const CSharpMethodInfo &E : methods) {
+ if (E.name == p_method) {
+ return E.method_info;
}
-
- top = top->get_parent_class();
}
return MethodInfo();
@@ -3362,30 +2456,15 @@ Error CSharpScript::reload(bool p_keep_state) {
// That's done separately via domain reloading.
reload_invalidated = false;
- GD_MONO_SCOPE_THREAD_ATTACH;
-
- const DotNetScriptLookupInfo *lookup_info =
- CSharpLanguage::get_singleton()->lookup_dotnet_script(get_path());
+ String script_path = get_path();
- if (lookup_info) {
- GDMonoClass *klass = lookup_info->script_class;
- if (klass) {
- ERR_FAIL_COND_V(!CACHED_CLASS(GodotObject)->is_assignable_from(klass), FAILED);
- script_class = klass;
- }
- }
-
- valid = script_class != nullptr;
+ valid = GDMonoCache::managed_callbacks.ScriptManagerBridge_AddScriptBridge(this, &script_path);
- if (script_class) {
+ if (valid) {
#ifdef DEBUG_ENABLED
- print_verbose("Found class " + script_class->get_full_name() + " for script " + get_path());
+ print_verbose("Found class for script " + get_path());
#endif
- native = GDMonoUtils::get_class_native_base(script_class);
-
- CRASH_COND(native == nullptr);
-
update_script_class_info(this);
_update_exports();
@@ -3407,8 +2486,8 @@ bool CSharpScript::get_property_default_value(const StringName &p_property, Vari
return true;
}
- if (base_cache.is_valid()) {
- return base_cache->get_property_default_value(p_property, r_value);
+ if (base_script.is_valid()) {
+ return base_script->get_property_default_value(p_property, r_value);
}
#endif
@@ -3422,48 +2501,39 @@ void CSharpScript::update_exports() {
}
bool CSharpScript::has_script_signal(const StringName &p_signal) const {
- return event_signals.has(p_signal) || _signals.has(p_signal);
-}
-
-void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
- for (const KeyValue<StringName, Vector<SignalParameter>> &E : _signals) {
- MethodInfo mi;
- mi.name = E.key;
-
- const Vector<SignalParameter> &params = E.value;
- for (int i = 0; i < params.size(); i++) {
- const SignalParameter &param = params[i];
+ if (!valid) {
+ return false;
+ }
- PropertyInfo arg_info = PropertyInfo(param.type, param.name);
- if (param.type == Variant::NIL && param.nil_is_variant) {
- arg_info.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- }
+ if (!GDMonoCache::godot_api_cache_updated) {
+ return false;
+ }
- mi.arguments.push_back(arg_info);
+ for (const EventSignalInfo &signal : event_signals) {
+ if (signal.name == p_signal) {
+ return true;
}
-
- r_signals->push_back(mi);
}
- for (const KeyValue<StringName, EventSignal> &E : event_signals) {
- MethodInfo mi;
- mi.name = E.key;
-
- const EventSignal &event_signal = E.value;
- const Vector<SignalParameter> &params = event_signal.parameters;
- for (int i = 0; i < params.size(); i++) {
- const SignalParameter &param = params[i];
+ return false;
+}
- PropertyInfo arg_info = PropertyInfo(param.type, param.name);
- if (param.type == Variant::NIL && param.nil_is_variant) {
- arg_info.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- }
+void CSharpScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
+ if (!valid) {
+ return;
+ }
- mi.arguments.push_back(arg_info);
- }
+ for (const EventSignalInfo &signal : get_script_event_signals()) {
+ r_signals->push_back(signal.method_info);
+ }
+}
- r_signals->push_back(mi);
+Vector<CSharpScript::EventSignalInfo> CSharpScript::get_script_event_signals() const {
+ if (!valid) {
+ return Vector<EventSignalInfo>();
}
+
+ return event_signals;
}
bool CSharpScript::inherits_script(const Ref<Script> &p_script) const {
@@ -3472,32 +2542,47 @@ bool CSharpScript::inherits_script(const Ref<Script> &p_script) const {
return false;
}
- if (script_class == nullptr || cs->script_class == nullptr) {
+ if (!valid || !cs->valid) {
return false;
}
- if (script_class == cs->script_class) {
- return true;
+ if (!GDMonoCache::godot_api_cache_updated) {
+ return false;
}
- return cs->script_class->is_assignable_from(script_class);
+ return GDMonoCache::managed_callbacks.ScriptManagerBridge_ScriptIsOrInherits(this, cs.ptr());
}
Ref<Script> CSharpScript::get_base_script() const {
- // TODO search in metadata file once we have it, not important any way?
- return Ref<Script>();
+ return base_script;
}
void CSharpScript::get_script_property_list(List<PropertyInfo> *r_list) const {
- List<PropertyInfo> props;
+#ifdef TOOLS_ENABLED
+ const CSharpScript *top = this;
+ while (top != nullptr) {
+ for (const PropertyInfo &E : top->exported_members_cache) {
+ r_list->push_back(E);
+ }
- for (const KeyValue<StringName, PropertyInfo> &E : member_info) {
- props.push_front(E.value);
+ top = top->base_script.ptr();
}
+#else
+ const CSharpScript *top = this;
+ while (top != nullptr) {
+ List<PropertyInfo> props;
- for (const PropertyInfo &prop : props) {
- r_list->push_back(prop);
+ for (const KeyValue<StringName, PropertyInfo> &E : top->member_info) {
+ props.push_front(E.value);
+ }
+
+ for (const PropertyInfo &prop : props) {
+ r_list->push_back(prop);
+ }
+
+ top = top->base_script.ptr();
}
+#endif
}
int CSharpScript::get_member_line(const StringName &p_member) const {
@@ -3505,22 +2590,6 @@ int CSharpScript::get_member_line(const StringName &p_member) const {
return -1;
}
-Variant CSharpScript::_member_get_rpc_config(IMonoClassMember *p_member) const {
- Variant out;
-
- MonoObject *rpc_attribute = p_member->get_attribute(CACHED_CLASS(RPCAttribute));
- if (rpc_attribute != nullptr) {
- Dictionary rpc_config;
- rpc_config["rpc_mode"] = CACHED_PROPERTY(RPCAttribute, Mode)->get_int_value(rpc_attribute);
- rpc_config["call_local"] = CACHED_PROPERTY(RPCAttribute, CallLocal)->get_bool_value(rpc_attribute);
- rpc_config["transfer_mode"] = CACHED_PROPERTY(RPCAttribute, TransferMode)->get_int_value(rpc_attribute);
- rpc_config["channel"] = CACHED_PROPERTY(RPCAttribute, TransferChannel)->get_int_value(rpc_attribute);
- out = rpc_config;
- }
-
- return out;
-}
-
const Variant CSharpScript::get_rpc_config() const {
return rpc_config;
}
@@ -3541,29 +2610,15 @@ Error CSharpScript::load_source_code(const String &p_path) {
return OK;
}
-void CSharpScript::_update_name() {
- String path = get_path();
-
- if (!path.is_empty()) {
- name = get_path().get_file().get_basename();
- }
-}
-
void CSharpScript::_clear() {
tool = false;
valid = false;
reload_invalidated = true;
-
- base = nullptr;
- native = nullptr;
- script_class = nullptr;
}
CSharpScript::CSharpScript() {
_clear();
- _update_name();
-
#ifdef DEBUG_ENABLED
{
MutexLock lock(CSharpLanguage::get_singleton()->script_instances_mutex);
@@ -3577,6 +2632,10 @@ CSharpScript::~CSharpScript() {
MutexLock lock(CSharpLanguage::get_singleton()->script_instances_mutex);
CSharpLanguage::get_singleton()->script_list.remove(&this->script_list);
#endif
+
+ if (GDMonoCache::godot_api_cache_updated) {
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_RemoveScriptBridge(this);
+ }
}
void CSharpScript::get_members(HashSet<StringName> *p_members) {
@@ -3598,9 +2657,13 @@ Ref<Resource> ResourceFormatLoaderCSharpScript::load(const String &p_path, const
// TODO ignore anything inside bin/ and obj/ in tools builds?
- CSharpScript *script = memnew(CSharpScript);
+ Ref<CSharpScript> script;
- Ref<CSharpScript> scriptres(script);
+ if (GDMonoCache::godot_api_cache_updated) {
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_GetOrCreateScriptBridgeForPath(&p_path, &script);
+ } else {
+ script = Ref<CSharpScript>(memnew(CSharpScript));
+ }
#if defined(DEBUG_ENABLED) || defined(TOOLS_ENABLED)
Error err = script->load_source_code(p_path);
@@ -3615,7 +2678,7 @@ Ref<Resource> ResourceFormatLoaderCSharpScript::load(const String &p_path, const
*r_error = OK;
}
- return scriptres;
+ return script;
}
void ResourceFormatLoaderCSharpScript::get_recognized_extensions(List<String> *p_extensions) const {
@@ -3678,14 +2741,7 @@ bool ResourceFormatSaverCSharpScript::recognize(const Ref<Resource> &p_resource)
}
CSharpLanguage::StringNameCache::StringNameCache() {
- _signal_callback = StaticCString::create("_signal_callback");
- _set = StaticCString::create("_set");
- _get = StaticCString::create("_get");
- _get_property_list = StaticCString::create("_get_property_list");
- _notification = StaticCString::create("_notification");
+ _property_can_revert = StaticCString::create("_property_can_revert");
+ _property_get_revert = StaticCString::create("_property_get_revert");
_script_source = StaticCString::create("script/source");
- on_before_serialize = StaticCString::create("OnBeforeSerialize");
- on_after_deserialize = StaticCString::create("OnAfterDeserialize");
- dotctor = StaticCString::create(".ctor");
- delegate_invoke_method_name = StaticCString::create("Invoke");
}
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 48129e69cb..3509a5c87d 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -39,8 +39,6 @@
#include "mono_gc_handle.h"
#include "mono_gd/gd_mono.h"
-#include "mono_gd/gd_mono_header.h"
-#include "mono_gd/gd_mono_internals.h"
#ifdef TOOLS_ENABLED
#include "editor/editor_plugin.h"
@@ -67,48 +65,17 @@ TScriptInstance *cast_script_instance(ScriptInstance *p_inst) {
#define CAST_CSHARP_INSTANCE(m_inst) (cast_script_instance<CSharpInstance, CSharpLanguage>(m_inst))
-struct DotNetScriptLookupInfo {
- String class_namespace;
- String class_name;
- GDMonoClass *script_class = nullptr;
-
- DotNetScriptLookupInfo() {} // Required by HashMap...
-
- DotNetScriptLookupInfo(const String &p_class_namespace, const String &p_class_name, GDMonoClass *p_script_class) :
- class_namespace(p_class_namespace), class_name(p_class_name), script_class(p_script_class) {
- }
-};
-
class CSharpScript : public Script {
GDCLASS(CSharpScript, Script);
-public:
- struct SignalParameter {
- String name;
- Variant::Type type;
- bool nil_is_variant = false;
- };
-
- struct EventSignal {
- GDMonoField *field = nullptr;
- GDMonoMethod *invoke_method = nullptr;
- Vector<SignalParameter> parameters;
- };
-
-private:
friend class CSharpInstance;
friend class CSharpLanguage;
- friend struct CSharpScriptDepSort;
bool tool = false;
bool valid = false;
bool reload_invalidated = false;
- GDMonoClass *base = nullptr;
- GDMonoClass *native = nullptr;
- GDMonoClass *script_class = nullptr;
-
- Ref<CSharpScript> base_cache; // TODO what's this for?
+ Ref<CSharpScript> base_script;
HashSet<Object *> instances;
@@ -118,26 +85,32 @@ private:
// Replace with buffer containing the serialized state of managed scripts.
// Keep variant state backup to use only with script instance placeholders.
List<Pair<StringName, Variant>> properties;
- List<Pair<StringName, Array>> event_signals;
+ Dictionary event_signals;
};
HashSet<ObjectID> pending_reload_instances;
RBMap<ObjectID, StateBackup> pending_reload_state;
- StringName tied_class_name_for_reload;
- StringName tied_class_namespace_for_reload;
#endif
String source;
- StringName name;
SelfList<CSharpScript> script_list = this;
- HashMap<StringName, Vector<SignalParameter>> _signals;
- HashMap<StringName, EventSignal> event_signals;
- bool signals_invalidated = true;
-
Dictionary rpc_config;
+ struct EventSignalInfo {
+ StringName name; // MethodInfo stores a string...
+ MethodInfo method_info;
+ };
+
+ struct CSharpMethodInfo {
+ StringName name; // MethodInfo stores a string...
+ MethodInfo method_info;
+ };
+
+ Vector<EventSignalInfo> event_signals;
+ Vector<CSharpMethodInfo> methods;
+
#ifdef TOOLS_ENABLED
List<PropertyInfo> exported_members_cache; // members_cache
HashMap<StringName, Variant> exported_members_defval_cache; // member_default_values_cache
@@ -146,7 +119,6 @@ private:
bool placeholder_fallback_enabled = false;
bool exports_invalidated = true;
void _update_exports_values(HashMap<StringName, Variant> &values, List<PropertyInfo> &propnames);
- void _update_member_info_no_exports();
void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override;
#endif
@@ -158,39 +130,24 @@ private:
void _clear();
- void _update_name();
-
- void load_script_signals(GDMonoClass *p_class, GDMonoClass *p_native_class);
- bool _get_signal(GDMonoClass *p_class, GDMonoMethod *p_delegate_invoke, Vector<SignalParameter> &params);
-
bool _update_exports(PlaceHolderScriptInstance *p_instance_to_update = nullptr);
- bool _get_member_export(IMonoClassMember *p_member, bool p_inspect_export, PropertyInfo &r_prop_info, bool &r_exported);
-#ifdef TOOLS_ENABLED
- static int _try_get_member_export_hint(IMonoClassMember *p_member, ManagedType p_type, Variant::Type p_variant_type, bool p_allow_generics, PropertyHint &r_hint, String &r_hint_string);
-#endif
-
CSharpInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error);
Variant _new(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
// Do not use unless you know what you are doing
- friend void GDMonoInternals::tie_managed_to_unmanaged(MonoObject *, Object *);
- static Ref<CSharpScript> create_for_managed_type(GDMonoClass *p_class, GDMonoClass *p_native);
static void update_script_class_info(Ref<CSharpScript> p_script);
- static void initialize_for_managed_type(Ref<CSharpScript> p_script, GDMonoClass *p_class, GDMonoClass *p_native);
-
- Variant _member_get_rpc_config(IMonoClassMember *p_member) const;
protected:
static void _bind_methods();
- Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override;
- void _resource_path_changed() override;
bool _get(const StringName &p_name, Variant &r_ret) const;
bool _set(const StringName &p_name, const Variant &p_value);
void _get_property_list(List<PropertyInfo> *p_properties) const;
public:
+ static void reload_registered_script(Ref<CSharpScript> p_script);
+
bool can_instantiate() const override;
StringName get_instance_base_type() const override;
ScriptInstance *instance_create(Object *p_this) override;
@@ -214,14 +171,20 @@ public:
bool has_script_signal(const StringName &p_signal) const override;
void get_script_signal_list(List<MethodInfo> *r_signals) const override;
+ Vector<EventSignalInfo> get_script_event_signals() const;
+
bool get_property_default_value(const StringName &p_property, Variant &r_value) const override;
void get_script_property_list(List<PropertyInfo> *r_list) const override;
void update_exports() override;
void get_members(HashSet<StringName> *p_members) override;
- bool is_tool() const override { return tool; }
- bool is_valid() const override { return valid; }
+ bool is_tool() const override {
+ return tool;
+ }
+ bool is_valid() const override {
+ return valid;
+ }
bool inherits_script(const Ref<Script> &p_script) const override;
@@ -237,7 +200,9 @@ public:
const Variant get_rpc_config() const override;
#ifdef TOOLS_ENABLED
- bool is_placeholder_fallback_enabled() const override { return placeholder_fallback_enabled; }
+ bool is_placeholder_fallback_enabled() const override {
+ return placeholder_fallback_enabled;
+ }
#endif
Error load_source_code(const String &p_path);
@@ -270,22 +235,18 @@ class CSharpInstance : public ScriptInstance {
bool _unreference_owner_unsafe();
/*
- * If nullptr is returned, the caller must destroy the script instance by removing it from its owner.
+ * If false is returned, the caller must destroy the script instance by removing it from its owner.
*/
- MonoObject *_internal_new_managed();
+ bool _internal_new_managed();
// Do not use unless you know what you are doing
- friend void GDMonoInternals::tie_managed_to_unmanaged(MonoObject *, Object *);
static CSharpInstance *create_for_managed_type(Object *p_owner, CSharpScript *p_script, const MonoGCHandleData &p_gchandle);
- void get_properties_state_for_reloading(List<Pair<StringName, Variant>> &r_state);
- void get_event_signals_state_for_reloading(List<Pair<StringName, Array>> &r_state);
-
public:
- MonoObject *get_mono_object() const;
-
_FORCE_INLINE_ bool is_destructing_script_instance() { return destructing_script_instance; }
+ _FORCE_INLINE_ GCHandleIntPtr get_gchandle_intptr() { return gchandle.get_intptr(); }
+
Object *get_owner() override;
bool set(const StringName &p_name, const Variant &p_value) override;
@@ -293,17 +254,20 @@ public:
void get_property_list(List<PropertyInfo> *p_properties) const override;
Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid) const override;
+ bool property_can_revert(const StringName &p_name) const override;
+ bool property_get_revert(const StringName &p_name, Variant &r_ret) const override;
+
void get_method_list(List<MethodInfo> *p_list) const override;
bool has_method(const StringName &p_method) const override;
Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override;
- void mono_object_disposed(MonoObject *p_obj);
+ void mono_object_disposed(GCHandleIntPtr p_gchandle_to_free);
/*
* If 'r_delete_owner' is set to true, the caller must memdelete the script instance's owner. Otherwise, if
* 'r_remove_script_instance' is set to true, the caller must destroy the script instance by removing it from its owner.
*/
- void mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_delete_owner, bool &r_remove_script_instance);
+ void mono_object_disposed_baseref(GCHandleIntPtr p_gchandle_to_free, bool p_is_finalizer, bool &r_delete_owner, bool &r_remove_script_instance);
void connect_event_signals();
void disconnect_event_signals();
@@ -329,7 +293,6 @@ public:
struct CSharpScriptBinding {
bool inited = false;
StringName type_name;
- GDMonoClass *wrapper_class = nullptr;
MonoGCHandleData gchandle;
Object *owner = nullptr;
@@ -367,33 +330,22 @@ class CSharpLanguage : public ScriptLanguage {
ManagedCallableMiddleman *managed_callable_middleman = memnew(ManagedCallableMiddleman);
struct StringNameCache {
- StringName _signal_callback;
- StringName _set;
- StringName _get;
- StringName _get_property_list;
- StringName _notification;
+ StringName _property_can_revert;
+ StringName _property_get_revert;
StringName _script_source;
- StringName dotctor; // .ctor
- StringName on_before_serialize; // OnBeforeSerialize
- StringName on_after_deserialize; // OnAfterDeserialize
- StringName delegate_invoke_method_name;
StringNameCache();
};
int lang_idx = -1;
- HashMap<String, DotNetScriptLookupInfo> dotnet_script_lookup_map;
-
- void lookup_script_for_class(GDMonoClass *p_class);
-
// For debug_break and debug_break_parse
int _debug_parse_err_line = -1;
String _debug_parse_err_file;
String _debug_error;
friend class GDMono;
- void _on_scripts_domain_unloaded();
+ void _on_scripts_domain_about_to_unload();
#ifdef TOOLS_ENABLED
EditorPlugin *godotsharp_editor = nullptr;
@@ -415,21 +367,35 @@ public:
StringNameCache string_names;
- const Mutex &get_language_bind_mutex() { return language_bind_mutex; }
+ const Mutex &get_language_bind_mutex() {
+ return language_bind_mutex;
+ }
+ const Mutex &get_script_instances_mutex() {
+ return script_instances_mutex;
+ }
- _FORCE_INLINE_ int get_language_index() { return lang_idx; }
+ _FORCE_INLINE_ int get_language_index() {
+ return lang_idx;
+ }
void set_language_index(int p_idx);
- _FORCE_INLINE_ const StringNameCache &get_string_names() { return string_names; }
+ _FORCE_INLINE_ const StringNameCache &get_string_names() {
+ return string_names;
+ }
- _FORCE_INLINE_ static CSharpLanguage *get_singleton() { return singleton; }
+ _FORCE_INLINE_ static CSharpLanguage *get_singleton() {
+ return singleton;
+ }
#ifdef TOOLS_ENABLED
- _FORCE_INLINE_ EditorPlugin *get_godotsharp_editor() const { return godotsharp_editor; }
+ _FORCE_INLINE_ EditorPlugin *get_godotsharp_editor() const {
+ return godotsharp_editor;
+ }
#endif
static void release_script_gchandle(MonoGCHandleData &p_gchandle);
- static void release_script_gchandle(MonoObject *p_expected_obj, MonoGCHandleData &p_gchandle);
+ static void release_script_gchandle_thread_safe(GCHandleIntPtr p_gchandle_to_free, MonoGCHandleData &r_gchandle);
+ static void release_binding_gchandle_thread_safe(GCHandleIntPtr p_gchandle_to_free, CSharpScriptBinding &r_script_binding);
bool debug_break(const String &p_error, bool p_allow_continue = true);
bool debug_break_parse(const String &p_file, int p_line, const String &p_error);
@@ -439,12 +405,8 @@ public:
void reload_assemblies(bool p_soft_reload);
#endif
- _FORCE_INLINE_ ManagedCallableMiddleman *get_managed_callable_middleman() const { return managed_callable_middleman; }
-
- void lookup_scripts_in_assembly(GDMonoAssembly *p_assembly);
-
- const DotNetScriptLookupInfo *lookup_dotnet_script(const String &p_script_path) const {
- return dotnet_script_lookup_map.getptr(p_script_path);
+ _FORCE_INLINE_ ManagedCallableMiddleman *get_managed_callable_middleman() const {
+ return managed_callable_middleman;
}
String get_name() const override;
@@ -474,7 +436,9 @@ public:
Script *create_script() const override;
bool has_named_classes() const override;
bool supports_builtin_mode() const override;
- /* TODO? */ int find_function(const String &p_function, const String &p_code) const override { return -1; }
+ /* TODO? */ int find_function(const String &p_function, const String &p_code) const override {
+ return -1;
+ }
String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const override;
virtual String _get_indentation() const;
/* TODO? */ void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const override {}
@@ -489,14 +453,20 @@ public:
/* TODO */ void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) override {}
/* TODO */ void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) override {}
/* TODO */ void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) override {}
- /* TODO */ String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) override { return ""; }
+ /* TODO */ String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) override {
+ return "";
+ }
Vector<StackInfo> debug_get_current_stack_info() override;
/* PROFILING FUNCTIONS */
/* TODO */ void profiling_start() override {}
/* TODO */ void profiling_stop() override {}
- /* TODO */ int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) override { return 0; }
- /* TODO */ int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) override { return 0; }
+ /* TODO */ int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) override {
+ return 0;
+ }
+ /* TODO */ int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) override {
+ return 0;
+ }
void frame() override;
@@ -515,16 +485,12 @@ public:
bool overrides_external_editor() override;
#endif
- /* THREAD ATTACHING */
- void thread_enter() override;
- void thread_exit() override;
-
RBMap<Object *, CSharpScriptBinding>::Element *insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding);
bool setup_csharp_script_binding(CSharpScriptBinding &r_script_binding, Object *p_object);
-#ifdef DEBUG_ENABLED
- Vector<StackInfo> stack_trace_get_info(MonoObject *p_stack_trace);
-#endif
+ static void tie_native_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, const StringName *p_native_name, bool p_ref_counted);
+ static void tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, Ref<CSharpScript> *p_script, bool p_ref_counted);
+ static void tie_managed_to_unmanaged_with_pre_setup(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged);
void post_unsafe_reference(Object *p_obj);
void pre_unsafe_unreference(Object *p_obj);
diff --git a/modules/mono/doc_classes/GodotSharp.xml b/modules/mono/doc_classes/GodotSharp.xml
index 9de6b48e9e..faf3512da7 100644
--- a/modules/mono/doc_classes/GodotSharp.xml
+++ b/modules/mono/doc_classes/GodotSharp.xml
@@ -10,55 +10,10 @@
<tutorials>
</tutorials>
<methods>
- <method name="attach_thread">
- <return type="void" />
- <description>
- Attaches the current thread to the Mono runtime.
- </description>
- </method>
- <method name="detach_thread">
- <return type="void" />
- <description>
- Detaches the current thread from the Mono runtime.
- </description>
- </method>
- <method name="get_domain_id">
- <return type="int" />
- <description>
- Returns the current MonoDomain ID.
- [b]Note:[/b] The Mono runtime must be initialized for this method to work (use [method is_runtime_initialized] to check). If the Mono runtime isn't initialized at the time this method is called, the engine will crash.
- </description>
- </method>
- <method name="get_scripts_domain_id">
- <return type="int" />
- <description>
- Returns the scripts MonoDomain's ID. This will be the same MonoDomain ID as [method get_domain_id], unless the scripts domain isn't loaded.
- [b]Note:[/b] The Mono runtime must be initialized for this method to work (use [method is_runtime_initialized] to check). If the Mono runtime isn't initialized at the time this method is called, the engine will crash.
- </description>
- </method>
- <method name="is_domain_finalizing_for_unload">
- <return type="bool" />
- <argument index="0" name="domain_id" type="int" />
- <description>
- Returns [code]true[/code] if the domain is being finalized, [code]false[/code] otherwise.
- </description>
- </method>
<method name="is_runtime_initialized">
<return type="bool" />
<description>
- Returns [code]true[/code] if the Mono runtime is initialized, [code]false[/code] otherwise.
- </description>
- </method>
- <method name="is_runtime_shutting_down">
- <return type="bool" />
- <description>
- Returns [code]true[/code] if the Mono runtime is shutting down, [code]false[/code] otherwise.
- </description>
- </method>
- <method name="is_scripts_domain_loaded">
- <return type="bool" />
- <description>
- Returns [code]true[/code] if the scripts domain is loaded, [code]false[/code] otherwise.
+ Returns [code]true[/code] if the .NET runtime is initialized, [code]false[/code] otherwise.
</description>
</method>
</methods>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln
index d1868f52ef..03a7dc453c 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk.sln
@@ -1,4 +1,4 @@
-
+
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot.NET.Sdk", "Godot.NET.Sdk\Godot.NET.Sdk.csproj", "{31B00BFA-DEA1-42FA-A472-9E54A92A8A5F}"
EndProject
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj
index 4e9e7184da..013b210ff4 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Godot.NET.Sdk.csproj
@@ -26,16 +26,8 @@
<None Include="Sdk\Sdk.props" Pack="true" PackagePath="Sdk" />
<None Include="Sdk\Sdk.targets" Pack="true" PackagePath="Sdk" />
<!-- SdkPackageVersions.props -->
- <None Include="..\..\..\SdkPackageVersions.props" Pack="true" PackagePath="Sdk">
+ <None Include="$(GodotSdkPackageVersionsFilePath)" Pack="true" PackagePath="Sdk">
<Link>Sdk\SdkPackageVersions.props</Link>
</None>
</ItemGroup>
-
- <Target Name="CopyNupkgToSConsOutputDir" AfterTargets="Pack">
- <PropertyGroup>
- <GodotSourceRootPath>$(SolutionDir)\..\..\..\..\</GodotSourceRootPath>
- <GodotOutputDataDir>$(GodotSourceRootPath)\bin\GodotSharp\</GodotOutputDataDir>
- </PropertyGroup>
- <Copy SourceFiles="$(PackageOutputPath)$(PackageId).$(PackageVersion).nupkg" DestinationFolder="$(GodotOutputDataDir)Tools\nupkgs\" />
- </Target>
</Project>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
index 5a499742e9..59ce1da17b 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props
@@ -77,12 +77,11 @@
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'windows' ">GODOT_WINDOWS;GODOT_PC</GodotPlatformConstants>
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'linuxbsd' ">GODOT_LINUXBSD;GODOT_PC</GodotPlatformConstants>
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'macos' ">GODOT_OSX;GODOT_MACOS;GODOT_PC</GodotPlatformConstants>
- <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'server' ">GODOT_SERVER;GODOT_PC</GodotPlatformConstants>
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'uwp' ">GODOT_UWP;GODOT_PC</GodotPlatformConstants>
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'haiku' ">GODOT_HAIKU;GODOT_PC</GodotPlatformConstants>
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'android' ">GODOT_ANDROID;GODOT_MOBILE</GodotPlatformConstants>
<GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'ios' ">GODOT_IPHONE;GODOT_IOS;GODOT_MOBILE</GodotPlatformConstants>
- <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'javascript' ">GODOT_JAVASCRIPT;GODOT_HTML5;GODOT_WASM;GODOT_WEB</GodotPlatformConstants>
+ <GodotPlatformConstants Condition=" '$(GodotTargetPlatform)' == 'web' ">GODOT_JAVASCRIPT;GODOT_HTML5;GODOT_WASM;GODOT_WEB</GodotPlatformConstants>
<GodotDefineConstants>$(GodotDefineConstants);$(GodotPlatformConstants)</GodotDefineConstants>
</PropertyGroup>
@@ -95,21 +94,4 @@
<DefineConstants>$(GodotDefineConstants);$(DefineConstants)</DefineConstants>
</PropertyGroup>
-
- <!-- Godot API references -->
- <ItemGroup>
- <!--
- TODO:
- We should consider a nuget package for reference assemblies. This is difficult because the
- Godot scripting API is continuaslly breaking backwards compatibility even in patch releases.
- -->
- <Reference Include="GodotSharp">
- <Private>false</Private>
- <HintPath>$(GodotProjectDir).godot\mono\assemblies\$(GodotApiConfiguration)\GodotSharp.dll</HintPath>
- </Reference>
- <Reference Include="GodotSharpEditor" Condition=" '$(Configuration)' == 'Debug' ">
- <Private>false</Private>
- <HintPath>$(GodotProjectDir).godot\mono\assemblies\$(GodotApiConfiguration)\GodotSharpEditor.dll</HintPath>
- </Reference>
- </ItemGroup>
</Project>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets
index 397ede9644..aad4ea4553 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets
@@ -19,4 +19,10 @@
<ItemGroup Condition=" '$(DisableImplicitGodotGeneratorReferences)' != 'true' ">
<PackageReference Include="Godot.SourceGenerators" Version="$(PackageFloatingVersion_Godot)" />
</ItemGroup>
+
+ <!-- Godot API references -->
+ <ItemGroup Condition=" '$(DisableImplicitGodotSharpReferences)' != 'true' ">
+ <PackageReference Include="GodotSharp" Version="$(PackageVersion_GodotSharp)" />
+ <PackageReference Include="GodotSharpEditor" Version="$(PackageVersion_GodotSharp)" Condition=" '$(Configuration)' == 'Debug' " />
+ </ItemGroup>
</Project>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/EventSignals.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/EventSignals.cs
new file mode 100644
index 0000000000..764ba8f121
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/EventSignals.cs
@@ -0,0 +1,7 @@
+namespace Godot.SourceGenerators.Sample;
+
+public partial class EventSignals : Godot.Object
+{
+ [Signal]
+ public delegate void MySignalEventHandler(string str, int num);
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs
new file mode 100644
index 0000000000..ac8d6473a6
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedFields.cs
@@ -0,0 +1,113 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+
+#pragma warning disable CS0169
+#pragma warning disable CS0414
+
+namespace Godot.SourceGenerators.Sample
+{
+ [SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")]
+ [SuppressMessage("ReSharper", "RedundantNameQualifier")]
+ [SuppressMessage("ReSharper", "ArrangeObjectCreationWhenTypeEvident")]
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ public partial class ExportedFields : Godot.Object
+ {
+ [Export] private Boolean field_Boolean = true;
+ [Export] private Char field_Char = 'f';
+ [Export] private SByte field_SByte = 10;
+ [Export] private Int16 field_Int16 = 10;
+ [Export] private Int32 field_Int32 = 10;
+ [Export] private Int64 field_Int64 = 10;
+ [Export] private Byte field_Byte = 10;
+ [Export] private UInt16 field_UInt16 = 10;
+ [Export] private UInt32 field_UInt32 = 10;
+ [Export] private UInt64 field_UInt64 = 10;
+ [Export] private Single field_Single = 10;
+ [Export] private Double field_Double = 10;
+ [Export] private String field_String = "foo";
+
+ // Godot structs
+ [Export] private Vector2 field_Vector2 = new(10f, 10f);
+ [Export] private Vector2i field_Vector2i = Vector2i.Up;
+ [Export] private Rect2 field_Rect2 = new(new Vector2(10f, 10f), new Vector2(10f, 10f));
+ [Export] private Rect2i field_Rect2i = new(new Vector2i(10, 10), new Vector2i(10, 10));
+ [Export] private Transform2D field_Transform2D = Transform2D.Identity;
+ [Export] private Vector3 field_Vector3 = new(10f, 10f, 10f);
+ [Export] private Vector3i field_Vector3i = Vector3i.Back;
+ [Export] private Basis field_Basis = new Basis(Quaternion.Identity);
+ [Export] private Quaternion field_Quaternion = new Quaternion(Basis.Identity);
+ [Export] private Transform3D field_Transform3D = Transform3D.Identity;
+ [Export] private Vector4 field_Vector4 = new(10f, 10f, 10f, 10f);
+ [Export] private Vector4i field_Vector4i = Vector4i.One;
+ [Export] private Projection field_Projection = Projection.Identity;
+ [Export] private AABB field_AABB = new AABB(10f, 10f, 10f, new Vector3(1f, 1f, 1f));
+ [Export] private Color field_Color = Colors.Aquamarine;
+ [Export] private Plane field_Plane = Plane.PlaneXZ;
+ [Export] private Callable field_Callable = new Callable(Engine.GetMainLoop(), "_process");
+ [Export] private SignalInfo field_SignalInfo = new SignalInfo(Engine.GetMainLoop(), "property_list_changed");
+
+ // Enums
+ [SuppressMessage("ReSharper", "UnusedMember.Local")]
+ enum MyEnum
+ {
+ A,
+ B,
+ C
+ }
+
+ [Export] private MyEnum field_Enum = MyEnum.C;
+
+ [Flags]
+ [SuppressMessage("ReSharper", "UnusedMember.Local")]
+ enum MyFlagsEnum
+ {
+ A,
+ B,
+ C
+ }
+
+ [Export] private MyFlagsEnum field_FlagsEnum = MyFlagsEnum.C;
+
+ // Arrays
+ [Export] private Byte[] field_ByteArray = { 0, 1, 2, 3, 4, 5, 6 };
+ [Export] private Int32[] field_Int32Array = { 0, 1, 2, 3, 4, 5, 6 };
+ [Export] private Int64[] field_Int64Array = { 0, 1, 2, 3, 4, 5, 6 };
+ [Export] private Single[] field_SingleArray = { 0f, 1f, 2f, 3f, 4f, 5f, 6f };
+ [Export] private Double[] field_DoubleArray = { 0d, 1d, 2d, 3d, 4d, 5d, 6d };
+ [Export] private String[] field_StringArray = { "foo", "bar" };
+ [Export(PropertyHint.Enum, "A,B,C")] private String[] field_StringArrayEnum = { "foo", "bar" };
+ [Export] private Vector2[] field_Vector2Array = { Vector2.Up, Vector2.Down, Vector2.Left, Vector2.Right };
+ [Export] private Vector3[] field_Vector3Array = { Vector3.Up, Vector3.Down, Vector3.Left, Vector3.Right };
+ [Export] private Color[] field_ColorArray = { Colors.Aqua, Colors.Aquamarine, Colors.Azure, Colors.Beige };
+ [Export] private Godot.Object[] field_GodotObjectOrDerivedArray = { null };
+ [Export] private StringName[] field_StringNameArray = { "foo", "bar" };
+ [Export] private NodePath[] field_NodePathArray = { "foo", "bar" };
+ [Export] private RID[] field_RIDArray = { default, default, default };
+
+ // Variant
+ [Export] private Variant field_Variant = "foo";
+
+ // Classes
+ [Export] private Godot.Object field_GodotObjectOrDerived;
+ [Export] private Godot.Texture field_GodotResourceTexture;
+ [Export] private StringName field_StringName = new StringName("foo");
+ [Export] private NodePath field_NodePath = new NodePath("foo");
+ [Export] private RID field_RID;
+
+ [Export]
+ private Godot.Collections.Dictionary field_GodotDictionary =
+ new() { { "foo", 10 }, { Vector2.Up, Colors.Chocolate } };
+
+ [Export]
+ private Godot.Collections.Array field_GodotArray =
+ new() { "foo", 10, Vector2.Up, Colors.Chocolate };
+
+ [Export]
+ private Godot.Collections.Dictionary<string, bool> field_GodotGenericDictionary =
+ new() { { "foo", true }, { "bar", false } };
+
+ [Export]
+ private Godot.Collections.Array<int> field_GodotGenericArray =
+ new() { 0, 1, 2, 3, 4, 5, 6 };
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs
new file mode 100644
index 0000000000..3020cfbc50
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ExportedProperties.cs
@@ -0,0 +1,113 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+
+#pragma warning disable CS0169
+#pragma warning disable CS0414
+
+namespace Godot.SourceGenerators.Sample
+{
+ [SuppressMessage("ReSharper", "BuiltInTypeReferenceStyle")]
+ [SuppressMessage("ReSharper", "RedundantNameQualifier")]
+ [SuppressMessage("ReSharper", "ArrangeObjectCreationWhenTypeEvident")]
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ public partial class ExportedProperties : Godot.Object
+ {
+ [Export] private Boolean property_Boolean { get; set; } = true;
+ [Export] private Char property_Char { get; set; } = 'f';
+ [Export] private SByte property_SByte { get; set; } = 10;
+ [Export] private Int16 property_Int16 { get; set; } = 10;
+ [Export] private Int32 property_Int32 { get; set; } = 10;
+ [Export] private Int64 property_Int64 { get; set; } = 10;
+ [Export] private Byte property_Byte { get; set; } = 10;
+ [Export] private UInt16 property_UInt16 { get; set; } = 10;
+ [Export] private UInt32 property_UInt32 { get; set; } = 10;
+ [Export] private UInt64 property_UInt64 { get; set; } = 10;
+ [Export] private Single property_Single { get; set; } = 10;
+ [Export] private Double property_Double { get; set; } = 10;
+ [Export] private String property_String { get; set; } = "foo";
+
+ // Godot structs
+ [Export] private Vector2 property_Vector2 { get; set; } = new(10f, 10f);
+ [Export] private Vector2i property_Vector2i { get; set; } = Vector2i.Up;
+ [Export] private Rect2 property_Rect2 { get; set; } = new(new Vector2(10f, 10f), new Vector2(10f, 10f));
+ [Export] private Rect2i property_Rect2i { get; set; } = new(new Vector2i(10, 10), new Vector2i(10, 10));
+ [Export] private Transform2D property_Transform2D { get; set; } = Transform2D.Identity;
+ [Export] private Vector3 property_Vector3 { get; set; } = new(10f, 10f, 10f);
+ [Export] private Vector3i property_Vector3i { get; set; } = Vector3i.Back;
+ [Export] private Basis property_Basis { get; set; } = new Basis(Quaternion.Identity);
+ [Export] private Quaternion property_Quaternion { get; set; } = new Quaternion(Basis.Identity);
+ [Export] private Transform3D property_Transform3D { get; set; } = Transform3D.Identity;
+ [Export] private Vector4 property_Vector4 { get; set; } = new(10f, 10f, 10f, 10f);
+ [Export] private Vector4i property_Vector4i { get; set; } = Vector4i.One;
+ [Export] private Projection property_Projection { get; set; } = Projection.Identity;
+ [Export] private AABB property_AABB { get; set; } = new AABB(10f, 10f, 10f, new Vector3(1f, 1f, 1f));
+ [Export] private Color property_Color { get; set; } = Colors.Aquamarine;
+ [Export] private Plane property_Plane { get; set; } = Plane.PlaneXZ;
+ [Export] private Callable property_Callable { get; set; } = new Callable(Engine.GetMainLoop(), "_process");
+ [Export] private SignalInfo property_SignalInfo { get; set; } = new SignalInfo(Engine.GetMainLoop(), "property_list_changed");
+
+ // Enums
+ [SuppressMessage("ReSharper", "UnusedMember.Local")]
+ enum MyEnum
+ {
+ A,
+ B,
+ C
+ }
+
+ [Export] private MyEnum property_Enum { get; set; } = MyEnum.C;
+
+ [Flags]
+ [SuppressMessage("ReSharper", "UnusedMember.Local")]
+ enum MyFlagsEnum
+ {
+ A,
+ B,
+ C
+ }
+
+ [Export] private MyFlagsEnum property_FlagsEnum { get; set; } = MyFlagsEnum.C;
+
+ // Arrays
+ [Export] private Byte[] property_ByteArray { get; set; } = { 0, 1, 2, 3, 4, 5, 6 };
+ [Export] private Int32[] property_Int32Array { get; set; } = { 0, 1, 2, 3, 4, 5, 6 };
+ [Export] private Int64[] property_Int64Array { get; set; } = { 0, 1, 2, 3, 4, 5, 6 };
+ [Export] private Single[] property_SingleArray { get; set; } = { 0f, 1f, 2f, 3f, 4f, 5f, 6f };
+ [Export] private Double[] property_DoubleArray { get; set; } = { 0d, 1d, 2d, 3d, 4d, 5d, 6d };
+ [Export] private String[] property_StringArray { get; set; } = { "foo", "bar" };
+ [Export(PropertyHint.Enum, "A,B,C")] private String[] property_StringArrayEnum { get; set; } = { "foo", "bar" };
+ [Export] private Vector2[] property_Vector2Array { get; set; } = { Vector2.Up, Vector2.Down, Vector2.Left, Vector2.Right };
+ [Export] private Vector3[] property_Vector3Array { get; set; } = { Vector3.Up, Vector3.Down, Vector3.Left, Vector3.Right };
+ [Export] private Color[] property_ColorArray { get; set; } = { Colors.Aqua, Colors.Aquamarine, Colors.Azure, Colors.Beige };
+ [Export] private Godot.Object[] property_GodotObjectOrDerivedArray { get; set; } = { null };
+ [Export] private StringName[] field_StringNameArray { get; set; } = { "foo", "bar" };
+ [Export] private NodePath[] field_NodePathArray { get; set; } = { "foo", "bar" };
+ [Export] private RID[] field_RIDArray { get; set; } = { default, default, default };
+
+ // Variant
+ [Export] private Variant property_Variant { get; set; } = "foo";
+
+ // Classes
+ [Export] private Godot.Object property_GodotObjectOrDerived { get; set; }
+ [Export] private Godot.Texture property_GodotResourceTexture { get; set; }
+ [Export] private StringName property_StringName { get; set; } = new StringName("foo");
+ [Export] private NodePath property_NodePath { get; set; } = new NodePath("foo");
+ [Export] private RID property_RID { get; set; }
+
+ [Export]
+ private Godot.Collections.Dictionary property_GodotDictionary { get; set; } =
+ new() { { "foo", 10 }, { Vector2.Up, Colors.Chocolate } };
+
+ [Export]
+ private Godot.Collections.Array property_GodotArray { get; set; } =
+ new() { "foo", 10, Vector2.Up, Colors.Chocolate };
+
+ [Export]
+ private Godot.Collections.Dictionary<string, bool> property_GodotGenericDictionary { get; set; } =
+ new() { { "foo", true }, { "bar", false } };
+
+ [Export]
+ private Godot.Collections.Array<int> property_GodotGenericArray { get; set; } =
+ new() { 0, 1, 2, 3, 4, 5, 6 };
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic.cs
index 2ddb8880c2..b21b035b4d 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Generic.cs
@@ -1,16 +1,21 @@
+#pragma warning disable CS0169
+
namespace Godot.SourceGenerators.Sample
{
partial class Generic<T> : Godot.Object
{
+ private int _field;
}
// Generic again but different generic parameters
partial class Generic<T, R> : Godot.Object
{
+ private int _field;
}
// Generic again but without generic parameters
partial class Generic : Godot.Object
{
+ private int _field;
}
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj
index 24f7909861..8e78e0385d 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Godot.SourceGenerators.Sample.csproj
@@ -1,12 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
- <TargetFramework>netstandard2.1</TargetFramework>
+ <TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<!-- $(GodotProjectDir) would normally be defined by the Godot.NET.Sdk -->
<GodotProjectDir>$(MSBuildProjectDirectory)</GodotProjectDir>
+ <!-- For compiling GetGodotPropertyDefaultValues. -->
+ <DefineConstants>$(DefineConstants);TOOLS</DefineConstants>
</PropertyGroup>
<PropertyGroup>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Methods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Methods.cs
new file mode 100644
index 0000000000..618ba24abc
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/Methods.cs
@@ -0,0 +1,31 @@
+using System.Diagnostics.CodeAnalysis;
+
+namespace Godot.SourceGenerators.Sample;
+
+[SuppressMessage("ReSharper", "RedundantNameQualifier")]
+public partial class Methods : Godot.Object
+{
+ private void MethodWithOverload()
+ {
+ }
+
+ private void MethodWithOverload(int a)
+ {
+ }
+
+ private void MethodWithOverload(int a, int b)
+ {
+ }
+
+ // Should be ignored. The previous one is picked.
+ // ReSharper disable once UnusedMember.Local
+ private void MethodWithOverload(float a, float b)
+ {
+ }
+
+ // Generic methods should be ignored.
+ // ReSharper disable once UnusedMember.Local
+ private void GenericMethod<T>(T t)
+ {
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ScriptBoilerplate.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ScriptBoilerplate.cs
new file mode 100644
index 0000000000..a1667dbb8f
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators.Sample/ScriptBoilerplate.cs
@@ -0,0 +1,36 @@
+#pragma warning disable CS0169
+
+namespace Godot.SourceGenerators.Sample
+{
+ public partial class ScriptBoilerplate : Node
+ {
+ private NodePath _nodePath;
+ private int _velocity;
+
+ public override void _Process(float delta)
+ {
+ _ = delta;
+
+ base._Process(delta);
+ }
+
+ public int Bazz(StringName name)
+ {
+ _ = name;
+ return 1;
+ }
+
+ public void IgnoreThisMethodWithByRefParams(ref int a)
+ {
+ _ = a;
+ }
+ }
+
+ partial struct OuterClass
+ {
+ public partial class NesterClass : RefCounted
+ {
+ public override Variant _Get(StringName property) => default;
+ }
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
index 4867c986e6..e28788ec0b 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Common.cs
@@ -1,5 +1,7 @@
+using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
namespace Godot.SourceGenerators
{
@@ -14,12 +16,11 @@ namespace Godot.SourceGenerators
"Missing partial modifier on declaration of type '" +
$"{symbol.FullQualifiedName()}' which is a subclass of '{GodotClasses.Object}'";
- string description = $"{message}. Subclasses of '{GodotClasses.Object}' must be " +
- "declared with the partial modifier or annotated with the " +
- $"attribute '{GodotClasses.DisableGodotGeneratorsAttr}'.";
+ string description = $"{message}. Subclasses of '{GodotClasses.Object}' " +
+ "must be declared with the partial modifier.";
context.ReportDiagnostic(Diagnostic.Create(
- new DiagnosticDescriptor(id: "GODOT-G0001",
+ new DiagnosticDescriptor(id: "GD0001",
title: message,
messageFormat: message,
category: "Usage",
@@ -29,5 +30,333 @@ namespace Godot.SourceGenerators
cds.GetLocation(),
cds.SyntaxTree.FilePath));
}
+
+ public static void ReportNonPartialGodotScriptOuterClass(
+ GeneratorExecutionContext context,
+ TypeDeclarationSyntax outerTypeDeclSyntax
+ )
+ {
+ var outerSymbol = context.Compilation
+ .GetSemanticModel(outerTypeDeclSyntax.SyntaxTree)
+ .GetDeclaredSymbol(outerTypeDeclSyntax);
+
+ string fullQualifiedName = outerSymbol is INamedTypeSymbol namedTypeSymbol ?
+ namedTypeSymbol.FullQualifiedName() :
+ "type not found";
+
+ string message =
+ $"Missing partial modifier on declaration of type '{fullQualifiedName}', " +
+ $"which contains one or more subclasses of '{GodotClasses.Object}'";
+
+ string description = $"{message}. Subclasses of '{GodotClasses.Object}' and their " +
+ "containing types must be declared with the partial modifier.";
+
+ context.ReportDiagnostic(Diagnostic.Create(
+ new DiagnosticDescriptor(id: "GD0002",
+ title: message,
+ messageFormat: message,
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description),
+ outerTypeDeclSyntax.GetLocation(),
+ outerTypeDeclSyntax.SyntaxTree.FilePath));
+ }
+
+ public static void ReportExportedMemberIsStatic(
+ GeneratorExecutionContext context,
+ ISymbol exportedMemberSymbol
+ )
+ {
+ var locations = exportedMemberSymbol.Locations;
+ var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault();
+ bool isField = exportedMemberSymbol is IFieldSymbol;
+
+ string message = $"Attempted to export static {(isField ? "field" : "property")}: " +
+ $"'{exportedMemberSymbol.ToDisplayString()}'";
+
+ string description = $"{message}. Only instance fields and properties can be exported." +
+ " Remove the 'static' modifier or the '[Export]' attribute.";
+
+ context.ReportDiagnostic(Diagnostic.Create(
+ new DiagnosticDescriptor(id: "GD0101",
+ title: message,
+ messageFormat: message,
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description),
+ location,
+ location?.SourceTree?.FilePath));
+ }
+
+ public static void ReportExportedMemberTypeNotSupported(
+ GeneratorExecutionContext context,
+ ISymbol exportedMemberSymbol
+ )
+ {
+ var locations = exportedMemberSymbol.Locations;
+ var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault();
+ bool isField = exportedMemberSymbol is IFieldSymbol;
+
+ string message = $"The type of the exported {(isField ? "field" : "property")} " +
+ $"is not supported: '{exportedMemberSymbol.ToDisplayString()}'";
+
+ string description = $"{message}. Use a supported type or remove the '[Export]' attribute.";
+
+ context.ReportDiagnostic(Diagnostic.Create(
+ new DiagnosticDescriptor(id: "GD0102",
+ title: message,
+ messageFormat: message,
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description),
+ location,
+ location?.SourceTree?.FilePath));
+ }
+
+ public static void ReportExportedMemberIsReadOnly(
+ GeneratorExecutionContext context,
+ ISymbol exportedMemberSymbol
+ )
+ {
+ var locations = exportedMemberSymbol.Locations;
+ var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault();
+ bool isField = exportedMemberSymbol is IFieldSymbol;
+
+ string message = $"The exported {(isField ? "field" : "property")} " +
+ $"is read-only: '{exportedMemberSymbol.ToDisplayString()}'";
+
+ string description = isField ?
+ $"{message}. Exported fields cannot be read-only." :
+ $"{message}. Exported properties must be writable.";
+
+ context.ReportDiagnostic(Diagnostic.Create(
+ new DiagnosticDescriptor(id: "GD0103",
+ title: message,
+ messageFormat: message,
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description),
+ location,
+ location?.SourceTree?.FilePath));
+ }
+
+ public static void ReportExportedMemberIsWriteOnly(
+ GeneratorExecutionContext context,
+ ISymbol exportedMemberSymbol
+ )
+ {
+ var locations = exportedMemberSymbol.Locations;
+ var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault();
+
+ string message = $"The exported property is write-only: '{exportedMemberSymbol.ToDisplayString()}'";
+
+ string description = $"{message}. Exported properties must be readable.";
+
+ context.ReportDiagnostic(Diagnostic.Create(
+ new DiagnosticDescriptor(id: "GD0104",
+ title: message,
+ messageFormat: message,
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description),
+ location,
+ location?.SourceTree?.FilePath));
+ }
+
+ public static void ReportExportedMemberIsIndexer(
+ GeneratorExecutionContext context,
+ ISymbol exportedMemberSymbol
+ )
+ {
+ var locations = exportedMemberSymbol.Locations;
+ var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault();
+
+ string message = $"Attempted to export indexer property: " +
+ $"'{exportedMemberSymbol.ToDisplayString()}'";
+
+ string description = $"{message}. Indexer properties can't be exported." +
+ " Remove the '[Export]' attribute.";
+
+ context.ReportDiagnostic(Diagnostic.Create(
+ new DiagnosticDescriptor(id: "GD0105",
+ title: message,
+ messageFormat: message,
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description),
+ location,
+ location?.SourceTree?.FilePath));
+ }
+
+ public static void ReportSignalDelegateMissingSuffix(
+ GeneratorExecutionContext context,
+ INamedTypeSymbol delegateSymbol)
+ {
+ var locations = delegateSymbol.Locations;
+ var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault();
+
+ string message = "The name of the delegate must end with 'EventHandler': " +
+ delegateSymbol.ToDisplayString() +
+ $". Did you mean '{delegateSymbol.Name}EventHandler'?";
+
+ string description = $"{message}. Rename the delegate accordingly or remove the '[Signal]' attribute.";
+
+ context.ReportDiagnostic(Diagnostic.Create(
+ new DiagnosticDescriptor(id: "GD0201",
+ title: message,
+ messageFormat: message,
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description),
+ location,
+ location?.SourceTree?.FilePath));
+ }
+
+ public static void ReportSignalParameterTypeNotSupported(
+ GeneratorExecutionContext context,
+ IParameterSymbol parameterSymbol)
+ {
+ var locations = parameterSymbol.Locations;
+ var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault();
+
+ string message = "The parameter of the delegate signature of the signal " +
+ $"is not supported: '{parameterSymbol.ToDisplayString()}'";
+
+ string description = $"{message}. Use supported types only or remove the '[Signal]' attribute.";
+
+ context.ReportDiagnostic(Diagnostic.Create(
+ new DiagnosticDescriptor(id: "GD0202",
+ title: message,
+ messageFormat: message,
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description),
+ location,
+ location?.SourceTree?.FilePath));
+ }
+
+ public static void ReportSignalDelegateSignatureMustReturnVoid(
+ GeneratorExecutionContext context,
+ INamedTypeSymbol delegateSymbol)
+ {
+ var locations = delegateSymbol.Locations;
+ var location = locations.FirstOrDefault(l => l.SourceTree != null) ?? locations.FirstOrDefault();
+
+ string message = "The delegate signature of the signal " +
+ $"must return void: '{delegateSymbol.ToDisplayString()}'";
+
+ string description = $"{message}. Return void or remove the '[Signal]' attribute.";
+
+ context.ReportDiagnostic(Diagnostic.Create(
+ new DiagnosticDescriptor(id: "GD0203",
+ title: message,
+ messageFormat: message,
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description),
+ location,
+ location?.SourceTree?.FilePath));
+ }
+
+ public static readonly DiagnosticDescriptor GenericTypeArgumentMustBeVariantRule =
+ new DiagnosticDescriptor(id: "GD0301",
+ title: "The generic type argument must be a Variant compatible type",
+ messageFormat: "The generic type argument must be a Variant compatible type: {0}",
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ "The generic type argument must be a Variant compatible type. Use a Variant compatible type as the generic type argument.");
+
+ public static void ReportGenericTypeArgumentMustBeVariant(
+ SyntaxNodeAnalysisContext context,
+ SyntaxNode typeArgumentSyntax,
+ ISymbol typeArgumentSymbol)
+ {
+ string message = "The generic type argument " +
+ $"must be a Variant compatible type: '{typeArgumentSymbol.ToDisplayString()}'";
+
+ string description = $"{message}. Use a Variant compatible type as the generic type argument.";
+
+ context.ReportDiagnostic(Diagnostic.Create(
+ new DiagnosticDescriptor(id: "GD0301",
+ title: message,
+ messageFormat: message,
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description),
+ typeArgumentSyntax.GetLocation(),
+ typeArgumentSyntax.SyntaxTree.FilePath));
+ }
+
+ public static readonly DiagnosticDescriptor GenericTypeParameterMustBeVariantAnnotatedRule =
+ new DiagnosticDescriptor(id: "GD0302",
+ title: "The generic type parameter must be annotated with the MustBeVariant attribute",
+ messageFormat: "The generic type argument must be a Variant type: {0}",
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ "The generic type argument must be a Variant type. Use a Variant type as the generic type argument.");
+
+ public static void ReportGenericTypeParameterMustBeVariantAnnotated(
+ SyntaxNodeAnalysisContext context,
+ SyntaxNode typeArgumentSyntax,
+ ISymbol typeArgumentSymbol)
+ {
+ string message = "The generic type parameter must be annotated with the MustBeVariant attribute";
+
+ string description = $"{message}. Add the MustBeVariant attribute to the generic type parameter.";
+
+ context.ReportDiagnostic(Diagnostic.Create(
+ new DiagnosticDescriptor(id: "GD0302",
+ title: message,
+ messageFormat: message,
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description),
+ typeArgumentSyntax.GetLocation(),
+ typeArgumentSyntax.SyntaxTree.FilePath));
+ }
+
+ public static readonly DiagnosticDescriptor TypeArgumentParentSymbolUnhandledRule =
+ new DiagnosticDescriptor(id: "GD0303",
+ title: "The generic type parameter must be annotated with the MustBeVariant attribute",
+ messageFormat: "The generic type argument must be a Variant type: {0}",
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ "The generic type argument must be a Variant type. Use a Variant type as the generic type argument.");
+
+ public static void ReportTypeArgumentParentSymbolUnhandled(
+ SyntaxNodeAnalysisContext context,
+ SyntaxNode typeArgumentSyntax,
+ ISymbol parentSymbol)
+ {
+ string message = $"Symbol '{parentSymbol.ToDisplayString()}' parent of a type argument " +
+ "that must be Variant compatible was not handled.";
+
+ string description = $"{message}. Handle type arguments that are children of the unhandled symbol type.";
+
+ context.ReportDiagnostic(Diagnostic.Create(
+ new DiagnosticDescriptor(id: "GD0303",
+ title: message,
+ messageFormat: message,
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description),
+ typeArgumentSyntax.GetLocation(),
+ typeArgumentSyntax.SyntaxTree.FilePath));
+ }
}
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
index e16f72f43a..de3b6c862a 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ExtensionMethods.cs
@@ -1,4 +1,6 @@
+using System;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
@@ -13,30 +15,65 @@ namespace Godot.SourceGenerators
) => context.AnalyzerConfigOptions.GlobalOptions
.TryGetValue("build_property." + property, out value);
- private static bool InheritsFrom(this INamedTypeSymbol? symbol, string baseName)
- {
- if (symbol == null)
- return false;
+ public static bool AreGodotSourceGeneratorsDisabled(this GeneratorExecutionContext context)
+ => context.TryGetGlobalAnalyzerProperty("GodotSourceGenerators", out string? toggle) &&
+ toggle != null &&
+ toggle.Equals("disabled", StringComparison.OrdinalIgnoreCase);
+
+ public static bool IsGodotToolsProject(this GeneratorExecutionContext context)
+ => context.TryGetGlobalAnalyzerProperty("IsGodotToolsProject", out string? toggle) &&
+ toggle != null &&
+ toggle.Equals("true", StringComparison.OrdinalIgnoreCase);
- while (true)
+ public static bool InheritsFrom(this INamedTypeSymbol? symbol, string assemblyName, string typeFullName)
+ {
+ while (symbol != null)
{
- if (symbol.ToString() == baseName)
+ if (symbol.ContainingAssembly.Name == assemblyName &&
+ symbol.ToString() == typeFullName)
{
return true;
}
- if (symbol.BaseType != null)
- {
- symbol = symbol.BaseType;
- continue;
- }
-
- break;
+ symbol = symbol.BaseType;
}
return false;
}
+ public static INamedTypeSymbol? GetGodotScriptNativeClass(this INamedTypeSymbol classTypeSymbol)
+ {
+ var symbol = classTypeSymbol;
+
+ while (symbol != null)
+ {
+ if (symbol.ContainingAssembly.Name == "GodotSharp")
+ return symbol;
+
+ symbol = symbol.BaseType;
+ }
+
+ return null;
+ }
+
+ public static string? GetGodotScriptNativeClassName(this INamedTypeSymbol classTypeSymbol)
+ {
+ var nativeType = classTypeSymbol.GetGodotScriptNativeClass();
+
+ if (nativeType == null)
+ return null;
+
+ var godotClassNameAttr = nativeType.GetAttributes()
+ .FirstOrDefault(a => a.AttributeClass?.IsGodotClassNameAttribute() ?? false);
+
+ string? godotClassName = null;
+
+ if (godotClassNameAttr is { ConstructorArguments: { Length: > 0 } })
+ godotClassName = godotClassNameAttr.ConstructorArguments[0].Value?.ToString();
+
+ return godotClassName ?? nativeType.Name;
+ }
+
private static bool IsGodotScriptClass(
this ClassDeclarationSyntax cds, Compilation compilation,
out INamedTypeSymbol? symbol
@@ -47,7 +84,7 @@ namespace Godot.SourceGenerators
var classTypeSymbol = sm.GetDeclaredSymbol(cds);
if (classTypeSymbol?.BaseType == null
- || !classTypeSymbol.BaseType.InheritsFrom(GodotClasses.Object))
+ || !classTypeSymbol.BaseType.InheritsFrom("GodotSharp", GodotClasses.Object))
{
symbol = null;
return false;
@@ -69,21 +106,182 @@ namespace Godot.SourceGenerators
}
}
- public static bool IsPartial(this ClassDeclarationSyntax cds)
+ public static bool IsNested(this TypeDeclarationSyntax cds)
+ => cds.Parent is TypeDeclarationSyntax;
+
+ public static bool IsPartial(this TypeDeclarationSyntax cds)
=> cds.Modifiers.Any(SyntaxKind.PartialKeyword);
- public static bool HasDisableGeneratorsAttribute(this INamedTypeSymbol symbol)
- => symbol.GetAttributes().Any(attr =>
- attr.AttributeClass?.ToString() == GodotClasses.DisableGodotGeneratorsAttr);
+ public static bool AreAllOuterTypesPartial(
+ this TypeDeclarationSyntax cds,
+ out TypeDeclarationSyntax? typeMissingPartial
+ )
+ {
+ SyntaxNode? outerSyntaxNode = cds.Parent;
+
+ while (outerSyntaxNode is TypeDeclarationSyntax outerTypeDeclSyntax)
+ {
+ if (!outerTypeDeclSyntax.IsPartial())
+ {
+ typeMissingPartial = outerTypeDeclSyntax;
+ return false;
+ }
+
+ outerSyntaxNode = outerSyntaxNode.Parent;
+ }
+
+ typeMissingPartial = null;
+ return true;
+ }
+
+ public static string GetDeclarationKeyword(this INamedTypeSymbol namedTypeSymbol)
+ {
+ string? keyword = namedTypeSymbol.DeclaringSyntaxReferences
+ .OfType<TypeDeclarationSyntax>().FirstOrDefault()?
+ .Keyword.Text;
+
+ return keyword ?? namedTypeSymbol.TypeKind switch
+ {
+ TypeKind.Interface => "interface",
+ TypeKind.Struct => "struct",
+ _ => "class"
+ };
+ }
private static SymbolDisplayFormat FullyQualifiedFormatOmitGlobal { get; } =
SymbolDisplayFormat.FullyQualifiedFormat
.WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted);
- public static string FullQualifiedName(this INamedTypeSymbol symbol)
+ public static string FullQualifiedName(this ITypeSymbol symbol)
=> symbol.ToDisplayString(NullableFlowState.NotNull, FullyQualifiedFormatOmitGlobal);
+ public static string NameWithTypeParameters(this INamedTypeSymbol symbol)
+ {
+ return symbol.IsGenericType ?
+ string.Concat(symbol.Name, "<", string.Join(", ", symbol.TypeParameters), ">") :
+ symbol.Name;
+ }
+
public static string FullQualifiedName(this INamespaceSymbol namespaceSymbol)
=> namespaceSymbol.ToDisplayString(FullyQualifiedFormatOmitGlobal);
+
+ public static string SanitizeQualifiedNameForUniqueHint(this string qualifiedName)
+ => qualifiedName
+ // AddSource() doesn't support angle brackets
+ .Replace("<", "(Of ")
+ .Replace(">", ")");
+
+ public static bool IsGodotExportAttribute(this INamedTypeSymbol symbol)
+ => symbol.ToString() == GodotClasses.ExportAttr;
+
+ public static bool IsGodotSignalAttribute(this INamedTypeSymbol symbol)
+ => symbol.ToString() == GodotClasses.SignalAttr;
+
+ public static bool IsGodotMustBeVariantAttribute(this INamedTypeSymbol symbol)
+ => symbol.ToString() == GodotClasses.MustBeVariantAttr;
+
+ public static bool IsGodotClassNameAttribute(this INamedTypeSymbol symbol)
+ => symbol.ToString() == GodotClasses.GodotClassNameAttr;
+
+ public static bool IsSystemFlagsAttribute(this INamedTypeSymbol symbol)
+ => symbol.ToString() == GodotClasses.SystemFlagsAttr;
+
+ public static GodotMethodData? HasGodotCompatibleSignature(
+ this IMethodSymbol method,
+ MarshalUtils.TypeCache typeCache
+ )
+ {
+ if (method.IsGenericMethod)
+ return null;
+
+ var retSymbol = method.ReturnType;
+ var retType = method.ReturnsVoid ?
+ null :
+ MarshalUtils.ConvertManagedTypeToMarshalType(method.ReturnType, typeCache);
+
+ if (retType == null && !method.ReturnsVoid)
+ return null;
+
+ var parameters = method.Parameters;
+
+ var paramTypes = parameters
+ // Currently we don't support `ref`, `out`, `in`, `ref readonly` parameters (and we never may)
+ .Where(p => p.RefKind == RefKind.None)
+ // Attempt to determine the variant type
+ .Select(p => MarshalUtils.ConvertManagedTypeToMarshalType(p.Type, typeCache))
+ // Discard parameter types that couldn't be determined (null entries)
+ .Where(t => t != null).Cast<MarshalType>().ToImmutableArray();
+
+ // If any parameter type was incompatible, it was discarded so the length won't match
+ if (parameters.Length > paramTypes.Length)
+ return null; // Ignore incompatible method
+
+ return new GodotMethodData(method, paramTypes, parameters
+ .Select(p => p.Type).ToImmutableArray(), retType, retSymbol);
+ }
+
+ public static IEnumerable<GodotMethodData> WhereHasGodotCompatibleSignature(
+ this IEnumerable<IMethodSymbol> methods,
+ MarshalUtils.TypeCache typeCache
+ )
+ {
+ foreach (var method in methods)
+ {
+ var methodData = HasGodotCompatibleSignature(method, typeCache);
+
+ if (methodData != null)
+ yield return methodData.Value;
+ }
+ }
+
+ public static IEnumerable<GodotPropertyData> WhereIsGodotCompatibleType(
+ this IEnumerable<IPropertySymbol> properties,
+ MarshalUtils.TypeCache typeCache
+ )
+ {
+ foreach (var property in properties)
+ {
+ // TODO: We should still restore read-only properties after reloading assembly. Two possible ways: reflection or turn RestoreGodotObjectData into a constructor overload.
+ // Ignore properties without a getter or without a setter. Godot properties must be both readable and writable.
+ if (property.IsWriteOnly || property.IsReadOnly)
+ continue;
+
+ var marshalType = MarshalUtils.ConvertManagedTypeToMarshalType(property.Type, typeCache);
+
+ if (marshalType == null)
+ continue;
+
+ yield return new GodotPropertyData(property, marshalType.Value);
+ }
+ }
+
+ public static IEnumerable<GodotFieldData> WhereIsGodotCompatibleType(
+ this IEnumerable<IFieldSymbol> fields,
+ MarshalUtils.TypeCache typeCache
+ )
+ {
+ foreach (var field in fields)
+ {
+ // TODO: We should still restore read-only fields after reloading assembly. Two possible ways: reflection or turn RestoreGodotObjectData into a constructor overload.
+ // Ignore properties without a getter or without a setter. Godot properties must be both readable and writable.
+ if (field.IsReadOnly)
+ continue;
+
+ var marshalType = MarshalUtils.ConvertManagedTypeToMarshalType(field.Type, typeCache);
+
+ if (marshalType == null)
+ continue;
+
+ yield return new GodotFieldData(field, marshalType.Value);
+ }
+ }
+
+ public static string Path(this Location location)
+ => location.SourceTree?.GetLineSpan(location.SourceSpan).Path
+ ?? location.GetLineSpan().Path;
+
+ public static int StartLine(this Location location)
+ => location.SourceTree?.GetLineSpan(location.SourceSpan).StartLinePosition.Line
+ ?? location.GetLineSpan().StartLinePosition.Line;
}
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj
index 11d8e0f72b..f51b5970c3 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.csproj
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
- <LangVersion>8.0</LangVersion>
+ <LangVersion>9.0</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
@@ -21,21 +21,13 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0" PrivateAssets="all" />
- <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.1" PrivateAssets="all" />
+ <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<!-- Package the generator in the analyzer directory of the nuget package -->
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
<!-- Package the props file -->
- <None Include="Godot.SourceGenerators.props" Pack="true" PackagePath="build" Visible="false" />
+ <None Include="Godot.SourceGenerators.props" Pack="true" PackagePath="build" Visible="true" />
</ItemGroup>
-
- <Target Name="CopyNupkgToSConsOutputDir" AfterTargets="Pack">
- <PropertyGroup>
- <GodotSourceRootPath>$(SolutionDir)\..\..\..\..\</GodotSourceRootPath>
- <GodotOutputDataDir>$(GodotSourceRootPath)\bin\GodotSharp\</GodotOutputDataDir>
- </PropertyGroup>
- <Copy SourceFiles="$(PackageOutputPath)$(PackageId).$(PackageVersion).nupkg" DestinationFolder="$(GodotOutputDataDir)Tools\nupkgs\" />
- </Target>
</Project>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.props b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.props
index f9b47ad5b1..7881ed0a8c 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.props
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/Godot.SourceGenerators.props
@@ -2,6 +2,7 @@
<ItemGroup>
<!-- $(GodotProjectDir) is defined by Godot.NET.Sdk -->
<CompilerVisibleProperty Include="GodotProjectDir" />
- <CompilerVisibleProperty Include="GodotScriptPathAttributeGenerator" />
+ <CompilerVisibleProperty Include="GodotSourceGenerators" />
+ <CompilerVisibleProperty Include="IsGodotToolsProject" />
</ItemGroup>
</Project>
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs
index 29e41d155a..1d8ddbabf2 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotClasses.cs
@@ -3,7 +3,14 @@ namespace Godot.SourceGenerators
public static class GodotClasses
{
public const string Object = "Godot.Object";
- public const string DisableGodotGeneratorsAttr = "Godot.DisableGodotGeneratorsAttribute";
public const string AssemblyHasScriptsAttr = "Godot.AssemblyHasScriptsAttribute";
+ public const string ExportAttr = "Godot.ExportAttribute";
+ public const string ExportCategoryAttr = "Godot.ExportCategoryAttribute";
+ public const string ExportGroupAttr = "Godot.ExportGroupAttribute";
+ public const string ExportSubgroupAttr = "Godot.ExportSubgroupAttribute";
+ public const string SignalAttr = "Godot.SignalAttribute";
+ public const string MustBeVariantAttr = "Godot.MustBeVariantAttribute";
+ public const string GodotClassNameAttr = "Godot.GodotClassName";
+ public const string SystemFlagsAttr = "System.FlagsAttribute";
}
}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs
new file mode 100644
index 0000000000..1a25d684a0
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotEnums.cs
@@ -0,0 +1,148 @@
+using System;
+
+namespace Godot.SourceGenerators
+{
+ // TODO: May need to think about compatibility here. Could Godot change these values between minor versions?
+
+ internal enum VariantType
+ {
+ Nil = 0,
+ Bool = 1,
+ Int = 2,
+ Float = 3,
+ String = 4,
+ Vector2 = 5,
+ Vector2i = 6,
+ Rect2 = 7,
+ Rect2i = 8,
+ Vector3 = 9,
+ Vector3i = 10,
+ Transform2d = 11,
+ Vector4 = 12,
+ Vector4i = 13,
+ Plane = 14,
+ Quaternion = 15,
+ Aabb = 16,
+ Basis = 17,
+ Transform3d = 18,
+ Projection = 19,
+ Color = 20,
+ StringName = 21,
+ NodePath = 22,
+ Rid = 23,
+ Object = 24,
+ Callable = 25,
+ Signal = 26,
+ Dictionary = 27,
+ Array = 28,
+ PackedByteArray = 29,
+ PackedInt32Array = 30,
+ PackedInt64Array = 31,
+ PackedFloat32Array = 32,
+ PackedFloat64Array = 33,
+ PackedStringArray = 34,
+ PackedVector2Array = 35,
+ PackedVector3Array = 36,
+ PackedColorArray = 37,
+ Max = 38
+ }
+
+ internal enum PropertyHint
+ {
+ None = 0,
+ Range = 1,
+ Enum = 2,
+ EnumSuggestion = 3,
+ ExpEasing = 4,
+ Link = 5,
+ Flags = 6,
+ Layers2dRender = 7,
+ Layers2dPhysics = 8,
+ Layers2dNavigation = 9,
+ Layers3dRender = 10,
+ Layers3dPhysics = 11,
+ Layers3dNavigation = 12,
+ File = 13,
+ Dir = 14,
+ GlobalFile = 15,
+ GlobalDir = 16,
+ ResourceType = 17,
+ MultilineText = 18,
+ Expression = 19,
+ PlaceholderText = 20,
+ ColorNoAlpha = 21,
+ ImageCompressLossy = 22,
+ ImageCompressLossless = 23,
+ ObjectId = 24,
+ TypeString = 25,
+ NodePathToEditedNode = 26,
+ MethodOfVariantType = 27,
+ MethodOfBaseType = 28,
+ MethodOfInstance = 29,
+ MethodOfScript = 30,
+ PropertyOfVariantType = 31,
+ PropertyOfBaseType = 32,
+ PropertyOfInstance = 33,
+ PropertyOfScript = 34,
+ ObjectTooBig = 35,
+ NodePathValidTypes = 36,
+ SaveFile = 37,
+ GlobalSaveFile = 38,
+ IntIsObjectid = 39,
+ IntIsPointer = 41,
+ ArrayType = 40,
+ LocaleId = 42,
+ LocalizableString = 43,
+ NodeType = 44,
+ Max = 45
+ }
+
+ [Flags]
+ internal enum PropertyUsageFlags
+ {
+ None = 0,
+ Storage = 2,
+ Editor = 4,
+ Checkable = 8,
+ Checked = 16,
+ Internationalized = 32,
+ Group = 64,
+ Category = 128,
+ Subgroup = 256,
+ ClassIsBitfield = 512,
+ NoInstanceState = 1024,
+ RestartIfChanged = 2048,
+ ScriptVariable = 4096,
+ StoreIfNull = 8192,
+ AnimateAsTrigger = 16384,
+ UpdateAllIfModified = 32768,
+ ScriptDefaultValue = 65536,
+ ClassIsEnum = 131072,
+ NilIsVariant = 262144,
+ Internal = 524288,
+ DoNotShareOnDuplicate = 1048576,
+ HighEndGfx = 2097152,
+ NodePathFromSceneRoot = 4194304,
+ ResourceNotPersistent = 8388608,
+ KeyingIncrements = 16777216,
+ DeferredSetResource = 33554432,
+ EditorInstantiateObject = 67108864,
+ EditorBasicSetting = 134217728,
+ Array = 536870912,
+ Default = 6,
+ DefaultIntl = 38,
+ NoEditor = 2
+ }
+
+ public enum MethodFlags
+ {
+ Normal = 1,
+ Editor = 2,
+ Const = 4,
+ Virtual = 8,
+ Vararg = 16,
+ Static = 32,
+ ObjectCore = 64,
+ Default = 1
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs
new file mode 100644
index 0000000000..db395e21cb
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotMemberData.cs
@@ -0,0 +1,84 @@
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+
+namespace Godot.SourceGenerators
+{
+ public struct GodotMethodData
+ {
+ public GodotMethodData(IMethodSymbol method, ImmutableArray<MarshalType> paramTypes,
+ ImmutableArray<ITypeSymbol> paramTypeSymbols, MarshalType? retType, ITypeSymbol? retSymbol)
+ {
+ Method = method;
+ ParamTypes = paramTypes;
+ ParamTypeSymbols = paramTypeSymbols;
+ RetType = retType;
+ RetSymbol = retSymbol;
+ }
+
+ public IMethodSymbol Method { get; }
+ public ImmutableArray<MarshalType> ParamTypes { get; }
+ public ImmutableArray<ITypeSymbol> ParamTypeSymbols { get; }
+ public MarshalType? RetType { get; }
+ public ITypeSymbol? RetSymbol { get; }
+ }
+
+ public struct GodotSignalDelegateData
+ {
+ public GodotSignalDelegateData(string name, INamedTypeSymbol delegateSymbol, GodotMethodData invokeMethodData)
+ {
+ Name = name;
+ DelegateSymbol = delegateSymbol;
+ InvokeMethodData = invokeMethodData;
+ }
+
+ public string Name { get; }
+ public INamedTypeSymbol DelegateSymbol { get; }
+ public GodotMethodData InvokeMethodData { get; }
+ }
+
+ public struct GodotPropertyData
+ {
+ public GodotPropertyData(IPropertySymbol propertySymbol, MarshalType type)
+ {
+ PropertySymbol = propertySymbol;
+ Type = type;
+ }
+
+ public IPropertySymbol PropertySymbol { get; }
+ public MarshalType Type { get; }
+ }
+
+ public struct GodotFieldData
+ {
+ public GodotFieldData(IFieldSymbol fieldSymbol, MarshalType type)
+ {
+ FieldSymbol = fieldSymbol;
+ Type = type;
+ }
+
+ public IFieldSymbol FieldSymbol { get; }
+ public MarshalType Type { get; }
+ }
+
+ public struct GodotPropertyOrFieldData
+ {
+ public GodotPropertyOrFieldData(ISymbol symbol, MarshalType type)
+ {
+ Symbol = symbol;
+ Type = type;
+ }
+
+ public GodotPropertyOrFieldData(GodotPropertyData propertyData)
+ : this(propertyData.PropertySymbol, propertyData.Type)
+ {
+ }
+
+ public GodotPropertyOrFieldData(GodotFieldData fieldData)
+ : this(fieldData.FieldSymbol, fieldData.Type)
+ {
+ }
+
+ public ISymbol Symbol { get; }
+ public MarshalType Type { get; }
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs
new file mode 100644
index 0000000000..7ec3f88e5d
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/GodotPluginsInitializerGenerator.cs
@@ -0,0 +1,63 @@
+using System.Text;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Godot.SourceGenerators
+{
+ [Generator]
+ public class GodotPluginsInitializerGenerator : ISourceGenerator
+ {
+ public void Initialize(GeneratorInitializationContext context)
+ {
+ }
+
+ public void Execute(GeneratorExecutionContext context)
+ {
+ if (context.IsGodotToolsProject())
+ return;
+
+ string source =
+ @"using System;
+using System.Runtime.InteropServices;
+using Godot.Bridge;
+using Godot.NativeInterop;
+
+namespace GodotPlugins.Game
+{
+ internal static partial class Main
+ {
+ [UnmanagedCallersOnly(EntryPoint = ""godotsharp_game_main_init"")]
+ private static godot_bool InitializeFromGameProject(IntPtr godotDllHandle, IntPtr outManagedCallbacks,
+ IntPtr unmanagedCallbacks, int unmanagedCallbacksSize)
+ {
+ try
+ {
+ DllImportResolver dllImportResolver = new GodotDllImportResolver(godotDllHandle).OnResolveDllImport;
+
+ var coreApiAssembly = typeof(Godot.Object).Assembly;
+
+ NativeLibrary.SetDllImportResolver(coreApiAssembly, dllImportResolver);
+
+ NativeFuncs.Initialize(unmanagedCallbacks, unmanagedCallbacksSize);
+
+ ManagedCallbacks.Create(outManagedCallbacks);
+
+ ScriptManagerBridge.LookupScriptsInAssembly(typeof(GodotPlugins.Game.Main).Assembly);
+
+ return godot_bool.True;
+ }
+ catch (Exception e)
+ {
+ Console.Error.WriteLine(e);
+ return false.ToGodotBool();
+ }
+ }
+ }
+}
+";
+
+ context.AddSource("GodotPlugins.Game_Generated",
+ SourceText.From(source, Encoding.UTF8));
+ }
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs
new file mode 100644
index 0000000000..15f5803bf0
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalType.cs
@@ -0,0 +1,73 @@
+using System.Diagnostics.CodeAnalysis;
+
+namespace Godot.SourceGenerators
+{
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ public enum MarshalType
+ {
+ Boolean,
+ Char,
+ SByte,
+ Int16,
+ Int32,
+ Int64,
+ Byte,
+ UInt16,
+ UInt32,
+ UInt64,
+ Single,
+ Double,
+ String,
+
+ // Godot structs
+ Vector2,
+ Vector2i,
+ Rect2,
+ Rect2i,
+ Transform2D,
+ Vector3,
+ Vector3i,
+ Basis,
+ Quaternion,
+ Transform3D,
+ Vector4,
+ Vector4i,
+ Projection,
+ AABB,
+ Color,
+ Plane,
+ Callable,
+ SignalInfo,
+
+ // Enums
+ Enum,
+
+ // Arrays
+ ByteArray,
+ Int32Array,
+ Int64Array,
+ Float32Array,
+ Float64Array,
+ StringArray,
+ Vector2Array,
+ Vector3Array,
+ ColorArray,
+ GodotObjectOrDerivedArray,
+ SystemArrayOfStringName,
+ SystemArrayOfNodePath,
+ SystemArrayOfRID,
+
+ // Variant
+ Variant,
+
+ // Classes
+ GodotObjectOrDerived,
+ StringName,
+ NodePath,
+ RID,
+ GodotDictionary,
+ GodotArray,
+ GodotGenericDictionary,
+ GodotGenericArray,
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
new file mode 100644
index 0000000000..efdd50098e
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MarshalUtils.cs
@@ -0,0 +1,678 @@
+using System;
+using System.Linq;
+using System.Text;
+using Microsoft.CodeAnalysis;
+
+namespace Godot.SourceGenerators
+{
+ internal static class MarshalUtils
+ {
+ public class TypeCache
+ {
+ public INamedTypeSymbol GodotObjectType { get; }
+
+ public TypeCache(Compilation compilation)
+ {
+ INamedTypeSymbol GetTypeByMetadataNameOrThrow(string fullyQualifiedMetadataName)
+ {
+ return compilation.GetTypeByMetadataName(fullyQualifiedMetadataName) ??
+ throw new InvalidOperationException($"Type not found: '{fullyQualifiedMetadataName}'.");
+ }
+
+ GodotObjectType = GetTypeByMetadataNameOrThrow("Godot.Object");
+ }
+ }
+
+ public static VariantType? ConvertMarshalTypeToVariantType(MarshalType marshalType)
+ => marshalType switch
+ {
+ MarshalType.Boolean => VariantType.Bool,
+ MarshalType.Char => VariantType.Int,
+ MarshalType.SByte => VariantType.Int,
+ MarshalType.Int16 => VariantType.Int,
+ MarshalType.Int32 => VariantType.Int,
+ MarshalType.Int64 => VariantType.Int,
+ MarshalType.Byte => VariantType.Int,
+ MarshalType.UInt16 => VariantType.Int,
+ MarshalType.UInt32 => VariantType.Int,
+ MarshalType.UInt64 => VariantType.Int,
+ MarshalType.Single => VariantType.Float,
+ MarshalType.Double => VariantType.Float,
+ MarshalType.String => VariantType.String,
+ MarshalType.Vector2 => VariantType.Vector2,
+ MarshalType.Vector2i => VariantType.Vector2i,
+ MarshalType.Rect2 => VariantType.Rect2,
+ MarshalType.Rect2i => VariantType.Rect2i,
+ MarshalType.Transform2D => VariantType.Transform2d,
+ MarshalType.Vector3 => VariantType.Vector3,
+ MarshalType.Vector3i => VariantType.Vector3i,
+ MarshalType.Basis => VariantType.Basis,
+ MarshalType.Quaternion => VariantType.Quaternion,
+ MarshalType.Transform3D => VariantType.Transform3d,
+ MarshalType.Vector4 => VariantType.Vector4,
+ MarshalType.Vector4i => VariantType.Vector4i,
+ MarshalType.Projection => VariantType.Projection,
+ MarshalType.AABB => VariantType.Aabb,
+ MarshalType.Color => VariantType.Color,
+ MarshalType.Plane => VariantType.Plane,
+ MarshalType.Callable => VariantType.Callable,
+ MarshalType.SignalInfo => VariantType.Signal,
+ MarshalType.Enum => VariantType.Int,
+ MarshalType.ByteArray => VariantType.PackedByteArray,
+ MarshalType.Int32Array => VariantType.PackedInt32Array,
+ MarshalType.Int64Array => VariantType.PackedInt64Array,
+ MarshalType.Float32Array => VariantType.PackedFloat32Array,
+ MarshalType.Float64Array => VariantType.PackedFloat64Array,
+ MarshalType.StringArray => VariantType.PackedStringArray,
+ MarshalType.Vector2Array => VariantType.PackedVector2Array,
+ MarshalType.Vector3Array => VariantType.PackedVector3Array,
+ MarshalType.ColorArray => VariantType.PackedColorArray,
+ MarshalType.GodotObjectOrDerivedArray => VariantType.Array,
+ MarshalType.SystemArrayOfStringName => VariantType.Array,
+ MarshalType.SystemArrayOfNodePath => VariantType.Array,
+ MarshalType.SystemArrayOfRID => VariantType.Array,
+ MarshalType.Variant => VariantType.Nil,
+ MarshalType.GodotObjectOrDerived => VariantType.Object,
+ MarshalType.StringName => VariantType.StringName,
+ MarshalType.NodePath => VariantType.NodePath,
+ MarshalType.RID => VariantType.Rid,
+ MarshalType.GodotDictionary => VariantType.Dictionary,
+ MarshalType.GodotArray => VariantType.Array,
+ MarshalType.GodotGenericDictionary => VariantType.Dictionary,
+ MarshalType.GodotGenericArray => VariantType.Array,
+ _ => null
+ };
+
+ public static MarshalType? ConvertManagedTypeToMarshalType(ITypeSymbol type, TypeCache typeCache)
+ {
+ var specialType = type.SpecialType;
+
+ switch (specialType)
+ {
+ case SpecialType.System_Boolean:
+ return MarshalType.Boolean;
+ case SpecialType.System_Char:
+ return MarshalType.Char;
+ case SpecialType.System_SByte:
+ return MarshalType.SByte;
+ case SpecialType.System_Int16:
+ return MarshalType.Int16;
+ case SpecialType.System_Int32:
+ return MarshalType.Int32;
+ case SpecialType.System_Int64:
+ return MarshalType.Int64;
+ case SpecialType.System_Byte:
+ return MarshalType.Byte;
+ case SpecialType.System_UInt16:
+ return MarshalType.UInt16;
+ case SpecialType.System_UInt32:
+ return MarshalType.UInt32;
+ case SpecialType.System_UInt64:
+ return MarshalType.UInt64;
+ case SpecialType.System_Single:
+ return MarshalType.Single;
+ case SpecialType.System_Double:
+ return MarshalType.Double;
+ case SpecialType.System_String:
+ return MarshalType.String;
+ default:
+ {
+ var typeKind = type.TypeKind;
+
+ if (typeKind == TypeKind.Enum)
+ return MarshalType.Enum;
+
+ if (typeKind == TypeKind.Struct)
+ {
+ if (type.ContainingAssembly.Name == "GodotSharp" &&
+ type.ContainingNamespace.Name == "Godot")
+ {
+ return type switch
+ {
+ { Name: "Vector2" } => MarshalType.Vector2,
+ { Name: "Vector2i" } => MarshalType.Vector2i,
+ { Name: "Rect2" } => MarshalType.Rect2,
+ { Name: "Rect2i" } => MarshalType.Rect2i,
+ { Name: "Transform2D" } => MarshalType.Transform2D,
+ { Name: "Vector3" } => MarshalType.Vector3,
+ { Name: "Vector3i" } => MarshalType.Vector3i,
+ { Name: "Basis" } => MarshalType.Basis,
+ { Name: "Quaternion" } => MarshalType.Quaternion,
+ { Name: "Transform3D" } => MarshalType.Transform3D,
+ { Name: "Vector4" } => MarshalType.Vector4,
+ { Name: "Vector4i" } => MarshalType.Vector4i,
+ { Name: "Projection" } => MarshalType.Projection,
+ { Name: "AABB" } => MarshalType.AABB,
+ { Name: "Color" } => MarshalType.Color,
+ { Name: "Plane" } => MarshalType.Plane,
+ { Name: "RID" } => MarshalType.RID,
+ { Name: "Callable" } => MarshalType.Callable,
+ { Name: "SignalInfo" } => MarshalType.SignalInfo,
+ { Name: "Variant" } => MarshalType.Variant,
+ _ => null
+ };
+ }
+ }
+ else if (typeKind == TypeKind.Array)
+ {
+ var arrayType = (IArrayTypeSymbol)type;
+ var elementType = arrayType.ElementType;
+
+ switch (elementType.SpecialType)
+ {
+ case SpecialType.System_Byte:
+ return MarshalType.ByteArray;
+ case SpecialType.System_Int32:
+ return MarshalType.Int32Array;
+ case SpecialType.System_Int64:
+ return MarshalType.Int64Array;
+ case SpecialType.System_Single:
+ return MarshalType.Float32Array;
+ case SpecialType.System_Double:
+ return MarshalType.Float64Array;
+ case SpecialType.System_String:
+ return MarshalType.StringArray;
+ }
+
+ if (elementType.SimpleDerivesFrom(typeCache.GodotObjectType))
+ return MarshalType.GodotObjectOrDerivedArray;
+
+ if (elementType.ContainingAssembly.Name == "GodotSharp" &&
+ elementType.ContainingNamespace.Name == "Godot")
+ {
+ switch (elementType)
+ {
+ case { Name: "Vector2" }:
+ return MarshalType.Vector2Array;
+ case { Name: "Vector3" }:
+ return MarshalType.Vector3Array;
+ case { Name: "Color" }:
+ return MarshalType.ColorArray;
+ case { Name: "StringName" }:
+ return MarshalType.SystemArrayOfStringName;
+ case { Name: "NodePath" }:
+ return MarshalType.SystemArrayOfNodePath;
+ case { Name: "RID" }:
+ return MarshalType.SystemArrayOfRID;
+ }
+ }
+
+ return null;
+ }
+ else
+ {
+ if (type.SimpleDerivesFrom(typeCache.GodotObjectType))
+ return MarshalType.GodotObjectOrDerived;
+
+ if (type.ContainingAssembly.Name == "GodotSharp")
+ {
+ switch (type.ContainingNamespace.Name)
+ {
+ case "Godot":
+ return type switch
+ {
+ { Name: "StringName" } => MarshalType.StringName,
+ { Name: "NodePath" } => MarshalType.NodePath,
+ _ => null
+ };
+ case "Collections"
+ when type.ContainingNamespace.FullQualifiedName() == "Godot.Collections":
+ return type switch
+ {
+ { Name: "Dictionary" } =>
+ type is INamedTypeSymbol { IsGenericType: false } ?
+ MarshalType.GodotDictionary :
+ MarshalType.GodotGenericDictionary,
+ { Name: "Array" } =>
+ type is INamedTypeSymbol { IsGenericType: false } ?
+ MarshalType.GodotArray :
+ MarshalType.GodotGenericArray,
+ _ => null
+ };
+ }
+ }
+ }
+
+ break;
+ }
+ }
+
+ return null;
+ }
+
+ private static bool SimpleDerivesFrom(this ITypeSymbol? type, ITypeSymbol candidateBaseType)
+ {
+ while (type != null)
+ {
+ if (SymbolEqualityComparer.Default.Equals(type, candidateBaseType))
+ return true;
+
+ type = type.BaseType;
+ }
+
+ return false;
+ }
+
+ public static ITypeSymbol? GetArrayElementType(ITypeSymbol typeSymbol)
+ {
+ if (typeSymbol.TypeKind == TypeKind.Array)
+ {
+ var arrayType = (IArrayTypeSymbol)typeSymbol;
+ return arrayType.ElementType;
+ }
+
+ if (typeSymbol is INamedTypeSymbol { IsGenericType: true } genericType)
+ return genericType.TypeArguments.FirstOrDefault();
+
+ return null;
+ }
+
+ private static StringBuilder Append(this StringBuilder source, string a, string b)
+ => source.Append(a).Append(b);
+
+ private static StringBuilder Append(this StringBuilder source, string a, string b, string c)
+ => source.Append(a).Append(b).Append(c);
+
+ private static StringBuilder Append(this StringBuilder source, string a, string b,
+ string c, string d)
+ => source.Append(a).Append(b).Append(c).Append(d);
+
+ private static StringBuilder Append(this StringBuilder source, string a, string b,
+ string c, string d, string e)
+ => source.Append(a).Append(b).Append(c).Append(d).Append(e);
+
+ private static StringBuilder Append(this StringBuilder source, string a, string b,
+ string c, string d, string e, string f)
+ => source.Append(a).Append(b).Append(c).Append(d).Append(e).Append(f);
+
+ private static StringBuilder Append(this StringBuilder source, string a, string b,
+ string c, string d, string e, string f, string g)
+ => source.Append(a).Append(b).Append(c).Append(d).Append(e).Append(f).Append(g);
+
+ private static StringBuilder Append(this StringBuilder source, string a, string b,
+ string c, string d, string e, string f, string g, string h)
+ => source.Append(a).Append(b).Append(c).Append(d).Append(e).Append(f).Append(g).Append(h);
+
+ private const string VariantUtils = "global::Godot.NativeInterop.VariantUtils";
+
+ public static StringBuilder AppendNativeVariantToManagedExpr(this StringBuilder source,
+ string inputExpr, ITypeSymbol typeSymbol, MarshalType marshalType)
+ {
+ return marshalType switch
+ {
+ MarshalType.Boolean =>
+ source.Append(VariantUtils, ".ConvertToBool(", inputExpr, ")"),
+ MarshalType.Char =>
+ source.Append("(char)", VariantUtils, ".ConvertToUInt16(", inputExpr, ")"),
+ MarshalType.SByte =>
+ source.Append(VariantUtils, ".ConvertToInt8(", inputExpr, ")"),
+ MarshalType.Int16 =>
+ source.Append(VariantUtils, ".ConvertToInt16(", inputExpr, ")"),
+ MarshalType.Int32 =>
+ source.Append(VariantUtils, ".ConvertToInt32(", inputExpr, ")"),
+ MarshalType.Int64 =>
+ source.Append(VariantUtils, ".ConvertToInt64(", inputExpr, ")"),
+ MarshalType.Byte =>
+ source.Append(VariantUtils, ".ConvertToUInt8(", inputExpr, ")"),
+ MarshalType.UInt16 =>
+ source.Append(VariantUtils, ".ConvertToUInt16(", inputExpr, ")"),
+ MarshalType.UInt32 =>
+ source.Append(VariantUtils, ".ConvertToUInt32(", inputExpr, ")"),
+ MarshalType.UInt64 =>
+ source.Append(VariantUtils, ".ConvertToUInt64(", inputExpr, ")"),
+ MarshalType.Single =>
+ source.Append(VariantUtils, ".ConvertToFloat32(", inputExpr, ")"),
+ MarshalType.Double =>
+ source.Append(VariantUtils, ".ConvertToFloat64(", inputExpr, ")"),
+ MarshalType.String =>
+ source.Append(VariantUtils, ".ConvertToStringObject(", inputExpr, ")"),
+ MarshalType.Vector2 =>
+ source.Append(VariantUtils, ".ConvertToVector2(", inputExpr, ")"),
+ MarshalType.Vector2i =>
+ source.Append(VariantUtils, ".ConvertToVector2i(", inputExpr, ")"),
+ MarshalType.Rect2 =>
+ source.Append(VariantUtils, ".ConvertToRect2(", inputExpr, ")"),
+ MarshalType.Rect2i =>
+ source.Append(VariantUtils, ".ConvertToRect2i(", inputExpr, ")"),
+ MarshalType.Transform2D =>
+ source.Append(VariantUtils, ".ConvertToTransform2D(", inputExpr, ")"),
+ MarshalType.Vector3 =>
+ source.Append(VariantUtils, ".ConvertToVector3(", inputExpr, ")"),
+ MarshalType.Vector3i =>
+ source.Append(VariantUtils, ".ConvertToVector3i(", inputExpr, ")"),
+ MarshalType.Basis =>
+ source.Append(VariantUtils, ".ConvertToBasis(", inputExpr, ")"),
+ MarshalType.Quaternion =>
+ source.Append(VariantUtils, ".ConvertToQuaternion(", inputExpr, ")"),
+ MarshalType.Transform3D =>
+ source.Append(VariantUtils, ".ConvertToTransform3D(", inputExpr, ")"),
+ MarshalType.Vector4 =>
+ source.Append(VariantUtils, ".ConvertToVector4(", inputExpr, ")"),
+ MarshalType.Vector4i =>
+ source.Append(VariantUtils, ".ConvertToVector4i(", inputExpr, ")"),
+ MarshalType.Projection =>
+ source.Append(VariantUtils, ".ConvertToProjection(", inputExpr, ")"),
+ MarshalType.AABB =>
+ source.Append(VariantUtils, ".ConvertToAABB(", inputExpr, ")"),
+ MarshalType.Color =>
+ source.Append(VariantUtils, ".ConvertToColor(", inputExpr, ")"),
+ MarshalType.Plane =>
+ source.Append(VariantUtils, ".ConvertToPlane(", inputExpr, ")"),
+ MarshalType.Callable =>
+ source.Append(VariantUtils, ".ConvertToCallableManaged(", inputExpr, ")"),
+ MarshalType.SignalInfo =>
+ source.Append(VariantUtils, ".ConvertToSignalInfo(", inputExpr, ")"),
+ MarshalType.Enum =>
+ source.Append("(", typeSymbol.FullQualifiedName(),
+ ")", VariantUtils, ".ConvertToInt32(", inputExpr, ")"),
+ MarshalType.ByteArray =>
+ source.Append(VariantUtils, ".ConvertAsPackedByteArrayToSystemArray(", inputExpr, ")"),
+ MarshalType.Int32Array =>
+ source.Append(VariantUtils, ".ConvertAsPackedInt32ArrayToSystemArray(", inputExpr, ")"),
+ MarshalType.Int64Array =>
+ source.Append(VariantUtils, ".ConvertAsPackedInt64ArrayToSystemArray(", inputExpr, ")"),
+ MarshalType.Float32Array =>
+ source.Append(VariantUtils, ".ConvertAsPackedFloat32ArrayToSystemArray(", inputExpr, ")"),
+ MarshalType.Float64Array =>
+ source.Append(VariantUtils, ".ConvertAsPackedFloat64ArrayToSystemArray(", inputExpr, ")"),
+ MarshalType.StringArray =>
+ source.Append(VariantUtils, ".ConvertAsPackedStringArrayToSystemArray(", inputExpr, ")"),
+ MarshalType.Vector2Array =>
+ source.Append(VariantUtils, ".ConvertAsPackedVector2ArrayToSystemArray(", inputExpr, ")"),
+ MarshalType.Vector3Array =>
+ source.Append(VariantUtils, ".ConvertAsPackedVector3ArrayToSystemArray(", inputExpr, ")"),
+ MarshalType.ColorArray =>
+ source.Append(VariantUtils, ".ConvertAsPackedColorArrayToSystemArray(", inputExpr, ")"),
+ MarshalType.GodotObjectOrDerivedArray =>
+ source.Append(VariantUtils, ".ConvertToSystemArrayOfGodotObject<",
+ ((IArrayTypeSymbol)typeSymbol).ElementType.FullQualifiedName(), ">(", inputExpr, ")"),
+ MarshalType.SystemArrayOfStringName =>
+ source.Append(VariantUtils, ".ConvertToSystemArrayOfStringName(", inputExpr, ")"),
+ MarshalType.SystemArrayOfNodePath =>
+ source.Append(VariantUtils, ".ConvertToSystemArrayOfNodePath(", inputExpr, ")"),
+ MarshalType.SystemArrayOfRID =>
+ source.Append(VariantUtils, ".ConvertToSystemArrayOfRID(", inputExpr, ")"),
+ MarshalType.Variant =>
+ source.Append("global::Godot.Variant.CreateCopyingBorrowed(", inputExpr, ")"),
+ MarshalType.GodotObjectOrDerived =>
+ source.Append("(", typeSymbol.FullQualifiedName(),
+ ")", VariantUtils, ".ConvertToGodotObject(", inputExpr, ")"),
+ MarshalType.StringName =>
+ source.Append(VariantUtils, ".ConvertToStringNameObject(", inputExpr, ")"),
+ MarshalType.NodePath =>
+ source.Append(VariantUtils, ".ConvertToNodePathObject(", inputExpr, ")"),
+ MarshalType.RID =>
+ source.Append(VariantUtils, ".ConvertToRID(", inputExpr, ")"),
+ MarshalType.GodotDictionary =>
+ source.Append(VariantUtils, ".ConvertToDictionaryObject(", inputExpr, ")"),
+ MarshalType.GodotArray =>
+ source.Append(VariantUtils, ".ConvertToArrayObject(", inputExpr, ")"),
+ MarshalType.GodotGenericDictionary =>
+ source.Append(VariantUtils, ".ConvertToDictionaryObject<",
+ ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedName(), ", ",
+ ((INamedTypeSymbol)typeSymbol).TypeArguments[1].FullQualifiedName(), ">(", inputExpr, ")"),
+ MarshalType.GodotGenericArray =>
+ source.Append(VariantUtils, ".ConvertToArrayObject<",
+ ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedName(), ">(", inputExpr, ")"),
+ _ => throw new ArgumentOutOfRangeException(nameof(marshalType), marshalType,
+ "Received unexpected marshal type")
+ };
+ }
+
+ public static StringBuilder AppendManagedToNativeVariantExpr(
+ this StringBuilder source, string inputExpr, MarshalType marshalType)
+ {
+ return marshalType switch
+ {
+ MarshalType.Boolean =>
+ source.Append(VariantUtils, ".CreateFromBool(", inputExpr, ")"),
+ MarshalType.Char =>
+ source.Append(VariantUtils, ".CreateFromInt((ushort)", inputExpr, ")"),
+ MarshalType.SByte =>
+ source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"),
+ MarshalType.Int16 =>
+ source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"),
+ MarshalType.Int32 =>
+ source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"),
+ MarshalType.Int64 =>
+ source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"),
+ MarshalType.Byte =>
+ source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"),
+ MarshalType.UInt16 =>
+ source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"),
+ MarshalType.UInt32 =>
+ source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"),
+ MarshalType.UInt64 =>
+ source.Append(VariantUtils, ".CreateFromInt(", inputExpr, ")"),
+ MarshalType.Single =>
+ source.Append(VariantUtils, ".CreateFromFloat(", inputExpr, ")"),
+ MarshalType.Double =>
+ source.Append(VariantUtils, ".CreateFromFloat(", inputExpr, ")"),
+ MarshalType.String =>
+ source.Append(VariantUtils, ".CreateFromString(", inputExpr, ")"),
+ MarshalType.Vector2 =>
+ source.Append(VariantUtils, ".CreateFromVector2(", inputExpr, ")"),
+ MarshalType.Vector2i =>
+ source.Append(VariantUtils, ".CreateFromVector2i(", inputExpr, ")"),
+ MarshalType.Rect2 =>
+ source.Append(VariantUtils, ".CreateFromRect2(", inputExpr, ")"),
+ MarshalType.Rect2i =>
+ source.Append(VariantUtils, ".CreateFromRect2i(", inputExpr, ")"),
+ MarshalType.Transform2D =>
+ source.Append(VariantUtils, ".CreateFromTransform2D(", inputExpr, ")"),
+ MarshalType.Vector3 =>
+ source.Append(VariantUtils, ".CreateFromVector3(", inputExpr, ")"),
+ MarshalType.Vector3i =>
+ source.Append(VariantUtils, ".CreateFromVector3i(", inputExpr, ")"),
+ MarshalType.Basis =>
+ source.Append(VariantUtils, ".CreateFromBasis(", inputExpr, ")"),
+ MarshalType.Quaternion =>
+ source.Append(VariantUtils, ".CreateFromQuaternion(", inputExpr, ")"),
+ MarshalType.Transform3D =>
+ source.Append(VariantUtils, ".CreateFromTransform3D(", inputExpr, ")"),
+ MarshalType.Vector4 =>
+ source.Append(VariantUtils, ".CreateFromVector4(", inputExpr, ")"),
+ MarshalType.Vector4i =>
+ source.Append(VariantUtils, ".CreateFromVector4i(", inputExpr, ")"),
+ MarshalType.Projection =>
+ source.Append(VariantUtils, ".CreateFromProjection(", inputExpr, ")"),
+ MarshalType.AABB =>
+ source.Append(VariantUtils, ".CreateFromAABB(", inputExpr, ")"),
+ MarshalType.Color =>
+ source.Append(VariantUtils, ".CreateFromColor(", inputExpr, ")"),
+ MarshalType.Plane =>
+ source.Append(VariantUtils, ".CreateFromPlane(", inputExpr, ")"),
+ MarshalType.Callable =>
+ source.Append(VariantUtils, ".CreateFromCallable(", inputExpr, ")"),
+ MarshalType.SignalInfo =>
+ source.Append(VariantUtils, ".CreateFromSignalInfo(", inputExpr, ")"),
+ MarshalType.Enum =>
+ source.Append(VariantUtils, ".CreateFromInt((int)", inputExpr, ")"),
+ MarshalType.ByteArray =>
+ source.Append(VariantUtils, ".CreateFromPackedByteArray(", inputExpr, ")"),
+ MarshalType.Int32Array =>
+ source.Append(VariantUtils, ".CreateFromPackedInt32Array(", inputExpr, ")"),
+ MarshalType.Int64Array =>
+ source.Append(VariantUtils, ".CreateFromPackedInt64Array(", inputExpr, ")"),
+ MarshalType.Float32Array =>
+ source.Append(VariantUtils, ".CreateFromPackedFloat32Array(", inputExpr, ")"),
+ MarshalType.Float64Array =>
+ source.Append(VariantUtils, ".CreateFromPackedFloat64Array(", inputExpr, ")"),
+ MarshalType.StringArray =>
+ source.Append(VariantUtils, ".CreateFromPackedStringArray(", inputExpr, ")"),
+ MarshalType.Vector2Array =>
+ source.Append(VariantUtils, ".CreateFromPackedVector2Array(", inputExpr, ")"),
+ MarshalType.Vector3Array =>
+ source.Append(VariantUtils, ".CreateFromPackedVector3Array(", inputExpr, ")"),
+ MarshalType.ColorArray =>
+ source.Append(VariantUtils, ".CreateFromPackedColorArray(", inputExpr, ")"),
+ MarshalType.GodotObjectOrDerivedArray =>
+ source.Append(VariantUtils, ".CreateFromSystemArrayOfGodotObject(", inputExpr, ")"),
+ MarshalType.SystemArrayOfStringName =>
+ source.Append(VariantUtils, ".CreateFromSystemArrayOfStringName(", inputExpr, ")"),
+ MarshalType.SystemArrayOfNodePath =>
+ source.Append(VariantUtils, ".CreateFromSystemArrayOfNodePath(", inputExpr, ")"),
+ MarshalType.SystemArrayOfRID =>
+ source.Append(VariantUtils, ".CreateFromSystemArrayOfRID(", inputExpr, ")"),
+ MarshalType.Variant =>
+ source.Append(inputExpr, ".CopyNativeVariant()"),
+ MarshalType.GodotObjectOrDerived =>
+ source.Append(VariantUtils, ".CreateFromGodotObject(", inputExpr, ")"),
+ MarshalType.StringName =>
+ source.Append(VariantUtils, ".CreateFromStringName(", inputExpr, ")"),
+ MarshalType.NodePath =>
+ source.Append(VariantUtils, ".CreateFromNodePath(", inputExpr, ")"),
+ MarshalType.RID =>
+ source.Append(VariantUtils, ".CreateFromRID(", inputExpr, ")"),
+ MarshalType.GodotDictionary =>
+ source.Append(VariantUtils, ".CreateFromDictionary(", inputExpr, ")"),
+ MarshalType.GodotArray =>
+ source.Append(VariantUtils, ".CreateFromArray(", inputExpr, ")"),
+ MarshalType.GodotGenericDictionary =>
+ source.Append(VariantUtils, ".CreateFromDictionary(", inputExpr, ")"),
+ MarshalType.GodotGenericArray =>
+ source.Append(VariantUtils, ".CreateFromArray(", inputExpr, ")"),
+ _ => throw new ArgumentOutOfRangeException(nameof(marshalType), marshalType,
+ "Received unexpected marshal type")
+ };
+ }
+
+ public static StringBuilder AppendVariantToManagedExpr(this StringBuilder source,
+ string inputExpr, ITypeSymbol typeSymbol, MarshalType marshalType)
+ {
+ return marshalType switch
+ {
+ MarshalType.Boolean => source.Append(inputExpr, ".AsBool()"),
+ MarshalType.Char => source.Append(inputExpr, ".AsChar()"),
+ MarshalType.SByte => source.Append(inputExpr, ".AsSByte()"),
+ MarshalType.Int16 => source.Append(inputExpr, ".AsInt16()"),
+ MarshalType.Int32 => source.Append(inputExpr, ".AsInt32()"),
+ MarshalType.Int64 => source.Append(inputExpr, ".AsInt64()"),
+ MarshalType.Byte => source.Append(inputExpr, ".AsByte()"),
+ MarshalType.UInt16 => source.Append(inputExpr, ".AsUInt16()"),
+ MarshalType.UInt32 => source.Append(inputExpr, ".AsUInt32()"),
+ MarshalType.UInt64 => source.Append(inputExpr, ".AsUInt64()"),
+ MarshalType.Single => source.Append(inputExpr, ".AsSingle()"),
+ MarshalType.Double => source.Append(inputExpr, ".AsDouble()"),
+ MarshalType.String => source.Append(inputExpr, ".AsString()"),
+ MarshalType.Vector2 => source.Append(inputExpr, ".AsVector2()"),
+ MarshalType.Vector2i => source.Append(inputExpr, ".AsVector2i()"),
+ MarshalType.Rect2 => source.Append(inputExpr, ".AsRect2()"),
+ MarshalType.Rect2i => source.Append(inputExpr, ".AsRect2i()"),
+ MarshalType.Transform2D => source.Append(inputExpr, ".AsTransform2D()"),
+ MarshalType.Vector3 => source.Append(inputExpr, ".AsVector3()"),
+ MarshalType.Vector3i => source.Append(inputExpr, ".AsVector3i()"),
+ MarshalType.Basis => source.Append(inputExpr, ".AsBasis()"),
+ MarshalType.Quaternion => source.Append(inputExpr, ".AsQuaternion()"),
+ MarshalType.Transform3D => source.Append(inputExpr, ".AsTransform3D()"),
+ MarshalType.Vector4 => source.Append(inputExpr, ".AsVector4()"),
+ MarshalType.Vector4i => source.Append(inputExpr, ".AsVector4i()"),
+ MarshalType.Projection => source.Append(inputExpr, ".AsProjection()"),
+ MarshalType.AABB => source.Append(inputExpr, ".AsAABB()"),
+ MarshalType.Color => source.Append(inputExpr, ".AsColor()"),
+ MarshalType.Plane => source.Append(inputExpr, ".AsPlane()"),
+ MarshalType.Callable => source.Append(inputExpr, ".AsCallable()"),
+ MarshalType.SignalInfo => source.Append(inputExpr, ".AsSignalInfo()"),
+ MarshalType.Enum =>
+ source.Append("(", typeSymbol.FullQualifiedName(), ")", inputExpr, ".AsInt64()"),
+ MarshalType.ByteArray => source.Append(inputExpr, ".AsByteArray()"),
+ MarshalType.Int32Array => source.Append(inputExpr, ".AsInt32Array()"),
+ MarshalType.Int64Array => source.Append(inputExpr, ".AsInt64Array()"),
+ MarshalType.Float32Array => source.Append(inputExpr, ".AsFloat32Array()"),
+ MarshalType.Float64Array => source.Append(inputExpr, ".AsFloat64Array()"),
+ MarshalType.StringArray => source.Append(inputExpr, ".AsStringArray()"),
+ MarshalType.Vector2Array => source.Append(inputExpr, ".AsVector2Array()"),
+ MarshalType.Vector3Array => source.Append(inputExpr, ".AsVector3Array()"),
+ MarshalType.ColorArray => source.Append(inputExpr, ".AsColorArray()"),
+ MarshalType.GodotObjectOrDerivedArray => source.Append(inputExpr, ".AsGodotObjectArray<",
+ ((IArrayTypeSymbol)typeSymbol).ElementType.FullQualifiedName(), ">()"),
+ MarshalType.SystemArrayOfStringName => source.Append(inputExpr, ".AsSystemArrayOfStringName()"),
+ MarshalType.SystemArrayOfNodePath => source.Append(inputExpr, ".AsSystemArrayOfNodePath()"),
+ MarshalType.SystemArrayOfRID => source.Append(inputExpr, ".AsSystemArrayOfRID()"),
+ MarshalType.Variant => source.Append(inputExpr),
+ MarshalType.GodotObjectOrDerived => source.Append("(",
+ typeSymbol.FullQualifiedName(), ")", inputExpr, ".AsGodotObject()"),
+ MarshalType.StringName => source.Append(inputExpr, ".AsStringName()"),
+ MarshalType.NodePath => source.Append(inputExpr, ".AsNodePath()"),
+ MarshalType.RID => source.Append(inputExpr, ".AsRID()"),
+ MarshalType.GodotDictionary => source.Append(inputExpr, ".AsGodotDictionary()"),
+ MarshalType.GodotArray => source.Append(inputExpr, ".AsGodotArray()"),
+ MarshalType.GodotGenericDictionary => source.Append(inputExpr, ".AsGodotDictionary<",
+ ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedName(), ", ",
+ ((INamedTypeSymbol)typeSymbol).TypeArguments[1].FullQualifiedName(), ">()"),
+ MarshalType.GodotGenericArray => source.Append(inputExpr, ".AsGodotArray<",
+ ((INamedTypeSymbol)typeSymbol).TypeArguments[0].FullQualifiedName(), ">()"),
+ _ => throw new ArgumentOutOfRangeException(nameof(marshalType), marshalType,
+ "Received unexpected marshal type")
+ };
+ }
+
+ public static StringBuilder AppendManagedToVariantExpr(this StringBuilder source,
+ string inputExpr, MarshalType marshalType)
+ {
+ switch (marshalType)
+ {
+ case MarshalType.Boolean:
+ case MarshalType.Char:
+ case MarshalType.SByte:
+ case MarshalType.Int16:
+ case MarshalType.Int32:
+ case MarshalType.Int64:
+ case MarshalType.Byte:
+ case MarshalType.UInt16:
+ case MarshalType.UInt32:
+ case MarshalType.UInt64:
+ case MarshalType.Single:
+ case MarshalType.Double:
+ case MarshalType.String:
+ case MarshalType.Vector2:
+ case MarshalType.Vector2i:
+ case MarshalType.Rect2:
+ case MarshalType.Rect2i:
+ case MarshalType.Transform2D:
+ case MarshalType.Vector3:
+ case MarshalType.Vector3i:
+ case MarshalType.Basis:
+ case MarshalType.Quaternion:
+ case MarshalType.Transform3D:
+ case MarshalType.Vector4:
+ case MarshalType.Vector4i:
+ case MarshalType.Projection:
+ case MarshalType.AABB:
+ case MarshalType.Color:
+ case MarshalType.Plane:
+ case MarshalType.Callable:
+ case MarshalType.SignalInfo:
+ case MarshalType.ByteArray:
+ case MarshalType.Int32Array:
+ case MarshalType.Int64Array:
+ case MarshalType.Float32Array:
+ case MarshalType.Float64Array:
+ case MarshalType.StringArray:
+ case MarshalType.Vector2Array:
+ case MarshalType.Vector3Array:
+ case MarshalType.ColorArray:
+ case MarshalType.GodotObjectOrDerivedArray:
+ case MarshalType.SystemArrayOfStringName:
+ case MarshalType.SystemArrayOfNodePath:
+ case MarshalType.SystemArrayOfRID:
+ case MarshalType.GodotObjectOrDerived:
+ case MarshalType.StringName:
+ case MarshalType.NodePath:
+ case MarshalType.RID:
+ case MarshalType.GodotDictionary:
+ case MarshalType.GodotArray:
+ case MarshalType.GodotGenericDictionary:
+ case MarshalType.GodotGenericArray:
+ return source.Append("Variant.CreateFrom(", inputExpr, ")");
+ case MarshalType.Enum:
+ return source.Append("Variant.CreateFrom((long)", inputExpr, ")");
+ case MarshalType.Variant:
+ return source.Append(inputExpr);
+ default:
+ throw new ArgumentOutOfRangeException(nameof(marshalType), marshalType,
+ "Received unexpected marshal type");
+ }
+ }
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MethodInfo.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MethodInfo.cs
new file mode 100644
index 0000000000..81c6f2b7d5
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MethodInfo.cs
@@ -0,0 +1,24 @@
+using System.Collections.Generic;
+
+namespace Godot.SourceGenerators
+{
+ internal struct MethodInfo
+ {
+ public MethodInfo(string name, PropertyInfo returnVal, MethodFlags flags,
+ List<PropertyInfo>? arguments,
+ List<string?>? defaultArguments)
+ {
+ Name = name;
+ ReturnVal = returnVal;
+ Flags = flags;
+ Arguments = arguments;
+ DefaultArguments = defaultArguments;
+ }
+
+ public string Name { get; }
+ public PropertyInfo ReturnVal { get; }
+ public MethodFlags Flags { get; }
+ public List<PropertyInfo>? Arguments { get; }
+ public List<string?>? DefaultArguments { get; }
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs
new file mode 100644
index 0000000000..7aaadb27be
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/MustBeVariantAnalyzer.cs
@@ -0,0 +1,100 @@
+using System.Collections.Immutable;
+using System.Diagnostics;
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace Godot.SourceGenerators
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ public class MustBeVariantAnalyzer : DiagnosticAnalyzer
+ {
+ public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
+ => ImmutableArray.Create(
+ Common.GenericTypeArgumentMustBeVariantRule,
+ Common.GenericTypeParameterMustBeVariantAnnotatedRule,
+ Common.TypeArgumentParentSymbolUnhandledRule);
+
+ public override void Initialize(AnalysisContext context)
+ {
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
+ context.EnableConcurrentExecution();
+ context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.TypeArgumentList);
+ }
+
+ private void AnalyzeNode(SyntaxNodeAnalysisContext context)
+ {
+ var typeArgListSyntax = (TypeArgumentListSyntax)context.Node;
+
+ // Method invocation or variable declaration that contained the type arguments
+ var parentSyntax = context.Node.Parent;
+ Debug.Assert(parentSyntax != null);
+
+ var sm = context.SemanticModel;
+
+ var typeCache = new MarshalUtils.TypeCache(context.Compilation);
+
+ for (int i = 0; i < typeArgListSyntax.Arguments.Count; i++)
+ {
+ var typeSyntax = typeArgListSyntax.Arguments[i];
+ var typeSymbol = sm.GetSymbolInfo(typeSyntax).Symbol as ITypeSymbol;
+ Debug.Assert(typeSymbol != null);
+
+ var parentSymbol = sm.GetSymbolInfo(parentSyntax).Symbol;
+
+ if (!ShouldCheckTypeArgument(context, parentSyntax, parentSymbol, typeSyntax, typeSymbol, i))
+ {
+ return;
+ }
+
+ if (typeSymbol is ITypeParameterSymbol typeParamSymbol)
+ {
+ if (!typeParamSymbol.GetAttributes().Any(a => a.AttributeClass?.IsGodotMustBeVariantAttribute() ?? false))
+ {
+ Common.ReportGenericTypeParameterMustBeVariantAnnotated(context, typeSyntax, typeSymbol);
+ }
+ continue;
+ }
+
+ var marshalType = MarshalUtils.ConvertManagedTypeToMarshalType(typeSymbol, typeCache);
+
+ if (marshalType == null)
+ {
+ Common.ReportGenericTypeArgumentMustBeVariant(context, typeSyntax, typeSymbol);
+ continue;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Check if the given type argument is being used in a type parameter that contains
+ /// the <c>MustBeVariantAttribute</c>; otherwise, we ignore the attribute.
+ /// </summary>
+ /// <param name="context">Context for a syntax node action.</param>
+ /// <param name="parentSyntax">The parent node syntax that contains the type node syntax.</param>
+ /// <param name="parentSymbol">The symbol retrieved for the parent node syntax.</param>
+ /// <param name="typeArgumentSyntax">The type node syntax of the argument type to check.</param>
+ /// <param name="typeArgumentSymbol">The symbol retrieved for the type node syntax.</param>
+ /// <returns><see langword="true"/> if the type must be variant and must be analyzed.</returns>
+ private bool ShouldCheckTypeArgument(SyntaxNodeAnalysisContext context, SyntaxNode parentSyntax, ISymbol parentSymbol, TypeSyntax typeArgumentSyntax, ITypeSymbol typeArgumentSymbol, int typeArgumentIndex)
+ {
+ var typeParamSymbol = parentSymbol switch
+ {
+ IMethodSymbol methodSymbol => methodSymbol.TypeParameters[typeArgumentIndex],
+ INamedTypeSymbol typeSymbol => typeSymbol.TypeParameters[typeArgumentIndex],
+ _ => null,
+ };
+
+ if (typeParamSymbol == null)
+ {
+ Common.ReportTypeArgumentParentSymbolUnhandled(context, typeArgumentSyntax, parentSymbol);
+ return false;
+ }
+
+ return typeParamSymbol.GetAttributes()
+ .Any(a => a.AttributeClass?.IsGodotMustBeVariantAttribute() ?? false);
+ }
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/PropertyInfo.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/PropertyInfo.cs
new file mode 100644
index 0000000000..b345f5f84d
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/PropertyInfo.cs
@@ -0,0 +1,23 @@
+namespace Godot.SourceGenerators
+{
+ internal struct PropertyInfo
+ {
+ public PropertyInfo(VariantType type, string name, PropertyHint hint,
+ string? hintString, PropertyUsageFlags usage, bool exported)
+ {
+ Type = type;
+ Name = name;
+ Hint = hint;
+ HintString = hintString;
+ Usage = usage;
+ Exported = exported;
+ }
+
+ public VariantType Type { get; }
+ public string Name { get; }
+ public PropertyHint Hint { get; }
+ public string? HintString { get; }
+ public PropertyUsageFlags Usage { get; }
+ public bool Exported { get; }
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
new file mode 100644
index 0000000000..5ac4f4a47e
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
@@ -0,0 +1,408 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Godot.SourceGenerators
+{
+ [Generator]
+ public class ScriptMethodsGenerator : ISourceGenerator
+ {
+ public void Initialize(GeneratorInitializationContext context)
+ {
+ }
+
+ public void Execute(GeneratorExecutionContext context)
+ {
+ if (context.AreGodotSourceGeneratorsDisabled())
+ return;
+
+ INamedTypeSymbol[] godotClasses = context
+ .Compilation.SyntaxTrees
+ .SelectMany(tree =>
+ tree.GetRoot().DescendantNodes()
+ .OfType<ClassDeclarationSyntax>()
+ .SelectGodotScriptClasses(context.Compilation)
+ // Report and skip non-partial classes
+ .Where(x =>
+ {
+ if (x.cds.IsPartial())
+ {
+ if (x.cds.IsNested() && !x.cds.AreAllOuterTypesPartial(out var typeMissingPartial))
+ {
+ Common.ReportNonPartialGodotScriptOuterClass(context, typeMissingPartial!);
+ return false;
+ }
+
+ return true;
+ }
+
+ Common.ReportNonPartialGodotScriptClass(context, x.cds, x.symbol);
+ return false;
+ })
+ .Select(x => x.symbol)
+ )
+ .Distinct<INamedTypeSymbol>(SymbolEqualityComparer.Default)
+ .ToArray();
+
+ if (godotClasses.Length > 0)
+ {
+ var typeCache = new MarshalUtils.TypeCache(context.Compilation);
+
+ foreach (var godotClass in godotClasses)
+ {
+ VisitGodotScriptClass(context, typeCache, godotClass);
+ }
+ }
+ }
+
+ private class MethodOverloadEqualityComparer : IEqualityComparer<GodotMethodData>
+ {
+ public bool Equals(GodotMethodData x, GodotMethodData y)
+ => x.ParamTypes.Length == y.ParamTypes.Length && x.Method.Name == y.Method.Name;
+
+ public int GetHashCode(GodotMethodData obj)
+ {
+ unchecked
+ {
+ return (obj.ParamTypes.Length.GetHashCode() * 397) ^ obj.Method.Name.GetHashCode();
+ }
+ }
+ }
+
+ private static void VisitGodotScriptClass(
+ GeneratorExecutionContext context,
+ MarshalUtils.TypeCache typeCache,
+ INamedTypeSymbol symbol
+ )
+ {
+ INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace;
+ string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ?
+ namespaceSymbol.FullQualifiedName() :
+ string.Empty;
+ bool hasNamespace = classNs.Length != 0;
+
+ bool isInnerClass = symbol.ContainingType != null;
+
+ string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
+ + "_ScriptMethods_Generated";
+
+ var source = new StringBuilder();
+
+ source.Append("using Godot;\n");
+ source.Append("using Godot.NativeInterop;\n");
+ source.Append("\n");
+
+ if (hasNamespace)
+ {
+ source.Append("namespace ");
+ source.Append(classNs);
+ source.Append(" {\n\n");
+ }
+
+ if (isInnerClass)
+ {
+ var containingType = symbol.ContainingType;
+
+ while (containingType != null)
+ {
+ source.Append("partial ");
+ source.Append(containingType.GetDeclarationKeyword());
+ source.Append(" ");
+ source.Append(containingType.NameWithTypeParameters());
+ source.Append("\n{\n");
+
+ containingType = containingType.ContainingType;
+ }
+ }
+
+ source.Append("partial class ");
+ source.Append(symbol.NameWithTypeParameters());
+ source.Append("\n{\n");
+
+ var members = symbol.GetMembers();
+
+ var methodSymbols = members
+ .Where(s => !s.IsStatic && s.Kind == SymbolKind.Method && !s.IsImplicitlyDeclared)
+ .Cast<IMethodSymbol>()
+ .Where(m => m.MethodKind == MethodKind.Ordinary);
+
+ var godotClassMethods = methodSymbols.WhereHasGodotCompatibleSignature(typeCache)
+ .Distinct(new MethodOverloadEqualityComparer())
+ .ToArray();
+
+ source.Append(" private partial class GodotInternal {\n");
+
+ // Generate cached StringNames for methods and properties, for fast lookup
+
+ var distinctMethodNames = godotClassMethods
+ .Select(m => m.Method.Name)
+ .Distinct()
+ .ToArray();
+
+ foreach (string methodName in distinctMethodNames)
+ {
+ source.Append(" public static readonly StringName MethodName_");
+ source.Append(methodName);
+ source.Append(" = \"");
+ source.Append(methodName);
+ source.Append("\";\n");
+ }
+
+ source.Append(" }\n"); // class GodotInternal
+
+ // Generate GetGodotMethodList
+
+ if (godotClassMethods.Length > 0)
+ {
+ source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
+
+ const string listType = "System.Collections.Generic.List<global::Godot.Bridge.MethodInfo>";
+
+ source.Append(" internal new static ")
+ .Append(listType)
+ .Append(" GetGodotMethodList()\n {\n");
+
+ source.Append(" var methods = new ")
+ .Append(listType)
+ .Append("(")
+ .Append(godotClassMethods.Length)
+ .Append(");\n");
+
+ foreach (var method in godotClassMethods)
+ {
+ var methodInfo = DetermineMethodInfo(method);
+ AppendMethodInfo(source, methodInfo);
+ }
+
+ source.Append(" return methods;\n");
+ source.Append(" }\n");
+
+ source.Append("#pragma warning restore CS0109\n");
+ }
+
+ // Generate InvokeGodotClassMethod
+
+ if (godotClassMethods.Length > 0)
+ {
+ source.Append(" protected override bool InvokeGodotClassMethod(in godot_string_name method, ");
+ source.Append("NativeVariantPtrArgs args, int argCount, out godot_variant ret)\n {\n");
+
+ foreach (var method in godotClassMethods)
+ {
+ GenerateMethodInvoker(method, source);
+ }
+
+ source.Append(" return base.InvokeGodotClassMethod(method, args, argCount, out ret);\n");
+
+ source.Append(" }\n");
+ }
+
+ // Generate HasGodotClassMethod
+
+ if (distinctMethodNames.Length > 0)
+ {
+ source.Append(" protected override bool HasGodotClassMethod(in godot_string_name method)\n {\n");
+
+ bool isFirstEntry = true;
+ foreach (string methodName in distinctMethodNames)
+ {
+ GenerateHasMethodEntry(methodName, source, isFirstEntry);
+ isFirstEntry = false;
+ }
+
+ source.Append(" return base.HasGodotClassMethod(method);\n");
+
+ source.Append(" }\n");
+ }
+
+ source.Append("}\n"); // partial class
+
+ if (isInnerClass)
+ {
+ var containingType = symbol.ContainingType;
+
+ while (containingType != null)
+ {
+ source.Append("}\n"); // outer class
+
+ containingType = containingType.ContainingType;
+ }
+ }
+
+ if (hasNamespace)
+ {
+ source.Append("\n}\n");
+ }
+
+ context.AddSource(uniqueHint, SourceText.From(source.ToString(), Encoding.UTF8));
+ }
+
+ private static void AppendMethodInfo(StringBuilder source, MethodInfo methodInfo)
+ {
+ source.Append(" methods.Add(new(name: GodotInternal.MethodName_")
+ .Append(methodInfo.Name)
+ .Append(", returnVal: ");
+
+ AppendPropertyInfo(source, methodInfo.ReturnVal);
+
+ source.Append(", flags: (Godot.MethodFlags)")
+ .Append((int)methodInfo.Flags)
+ .Append(", arguments: ");
+
+ if (methodInfo.Arguments is { Count: > 0 })
+ {
+ source.Append("new() { ");
+
+ foreach (var param in methodInfo.Arguments)
+ {
+ AppendPropertyInfo(source, param);
+
+ // C# allows colon after the last element
+ source.Append(", ");
+ }
+
+ source.Append(" }");
+ }
+ else
+ {
+ source.Append("null");
+ }
+
+ source.Append(", defaultArguments: null));\n");
+ }
+
+ private static void AppendPropertyInfo(StringBuilder source, PropertyInfo propertyInfo)
+ {
+ source.Append("new(type: (Godot.Variant.Type)")
+ .Append((int)propertyInfo.Type)
+ .Append(", name: \"")
+ .Append(propertyInfo.Name)
+ .Append("\", hint: (Godot.PropertyHint)")
+ .Append((int)propertyInfo.Hint)
+ .Append(", hintString: \"")
+ .Append(propertyInfo.HintString)
+ .Append("\", usage: (Godot.PropertyUsageFlags)")
+ .Append((int)propertyInfo.Usage)
+ .Append(", exported: ")
+ .Append(propertyInfo.Exported ? "true" : "false")
+ .Append(")");
+ }
+
+ private static MethodInfo DetermineMethodInfo(GodotMethodData method)
+ {
+ PropertyInfo returnVal;
+
+ if (method.RetType != null)
+ {
+ returnVal = DeterminePropertyInfo(method.RetType.Value, name: string.Empty);
+ }
+ else
+ {
+ returnVal = new PropertyInfo(VariantType.Nil, string.Empty, PropertyHint.None,
+ hintString: null, PropertyUsageFlags.Default, exported: false);
+ }
+
+ int paramCount = method.ParamTypes.Length;
+
+ List<PropertyInfo>? arguments;
+
+ if (paramCount > 0)
+ {
+ arguments = new(capacity: paramCount);
+
+ for (int i = 0; i < paramCount; i++)
+ {
+ arguments.Add(DeterminePropertyInfo(method.ParamTypes[i],
+ name: method.Method.Parameters[i].Name));
+ }
+ }
+ else
+ {
+ arguments = null;
+ }
+
+ return new MethodInfo(method.Method.Name, returnVal, MethodFlags.Default, arguments,
+ defaultArguments: null);
+ }
+
+ private static PropertyInfo DeterminePropertyInfo(MarshalType marshalType, string name)
+ {
+ var memberVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(marshalType)!.Value;
+
+ var propUsage = PropertyUsageFlags.Default;
+
+ if (memberVariantType == VariantType.Nil)
+ propUsage |= PropertyUsageFlags.NilIsVariant;
+
+ return new PropertyInfo(memberVariantType, name,
+ PropertyHint.None, string.Empty, propUsage, exported: false);
+ }
+
+ private static void GenerateHasMethodEntry(
+ string methodName,
+ StringBuilder source,
+ bool isFirstEntry
+ )
+ {
+ source.Append(" ");
+ if (!isFirstEntry)
+ source.Append("else ");
+ source.Append("if (method == GodotInternal.MethodName_");
+ source.Append(methodName);
+ source.Append(") {\n return true;\n }\n");
+ }
+
+ private static void GenerateMethodInvoker(
+ GodotMethodData method,
+ StringBuilder source
+ )
+ {
+ string methodName = method.Method.Name;
+
+ source.Append(" if (method == GodotInternal.MethodName_");
+ source.Append(methodName);
+ source.Append(" && argCount == ");
+ source.Append(method.ParamTypes.Length);
+ source.Append(") {\n");
+
+ if (method.RetType != null)
+ source.Append(" var callRet = ");
+ else
+ source.Append(" ");
+
+ source.Append(methodName);
+ source.Append("(");
+
+ for (int i = 0; i < method.ParamTypes.Length; i++)
+ {
+ if (i != 0)
+ source.Append(", ");
+
+ source.AppendNativeVariantToManagedExpr(string.Concat("args[", i.ToString(), "]"),
+ method.ParamTypeSymbols[i], method.ParamTypes[i]);
+ }
+
+ source.Append(");\n");
+
+ if (method.RetType != null)
+ {
+ source.Append(" ret = ");
+
+ source.AppendManagedToNativeVariantExpr("callRet", method.RetType.Value);
+ source.Append(";\n");
+
+ source.Append(" return true;\n");
+ }
+ else
+ {
+ source.Append(" ret = default;\n");
+ source.Append(" return true;\n");
+ }
+
+ source.Append(" }\n");
+ }
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
index fa65595290..e8a9e28d0c 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPathAttributeGenerator.cs
@@ -14,13 +14,13 @@ namespace Godot.SourceGenerators
{
public void Execute(GeneratorExecutionContext context)
{
- if (context.TryGetGlobalAnalyzerProperty("GodotScriptPathAttributeGenerator", out string? toggle)
- && toggle == "disabled")
- {
+ if (context.AreGodotSourceGeneratorsDisabled())
+ return;
+
+ if (context.IsGodotToolsProject())
return;
- }
- // NOTE: IsNullOrEmpty doesn't work well with nullable checks
+ // NOTE: NotNullWhen diagnostics don't work on projects targeting .NET Standard 2.0
// ReSharper disable once ReplaceWithStringIsNullOrEmpty
if (!context.TryGetGlobalAnalyzerProperty("GodotProjectDir", out string? godotProjectDir)
|| godotProjectDir!.Length == 0)
@@ -28,17 +28,18 @@ namespace Godot.SourceGenerators
throw new InvalidOperationException("Property 'GodotProjectDir' is null or empty.");
}
- var godotClasses = context.Compilation.SyntaxTrees
+ Dictionary<INamedTypeSymbol, IEnumerable<ClassDeclarationSyntax>> godotClasses = context
+ .Compilation.SyntaxTrees
.SelectMany(tree =>
tree.GetRoot().DescendantNodes()
.OfType<ClassDeclarationSyntax>()
// Ignore inner classes
- .Where(cds => !(cds.Parent is ClassDeclarationSyntax))
+ .Where(cds => !cds.IsNested())
.SelectGodotScriptClasses(context.Compilation)
// Report and skip non-partial classes
.Where(x =>
{
- if (x.cds.IsPartial() || x.symbol.HasDisableGeneratorsAttribute())
+ if (x.cds.IsPartial())
return true;
Common.ReportNonPartialGodotScriptClass(context, x.cds, x.symbol);
return false;
@@ -89,21 +90,14 @@ namespace Godot.SourceGenerators
attributes.Append(@""")]");
}
- string className = symbol.Name;
-
INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace;
string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ?
namespaceSymbol.FullQualifiedName() :
string.Empty;
bool hasNamespace = classNs.Length != 0;
- var uniqueName = new StringBuilder();
- if (hasNamespace)
- uniqueName.Append($"{classNs}.");
- uniqueName.Append(className);
- if (symbol.IsGenericType)
- uniqueName.Append($"Of{string.Join(string.Empty, symbol.TypeParameters)}");
- uniqueName.Append("_ScriptPath_Generated");
+ var uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
+ + "_ScriptPath_Generated";
var source = new StringBuilder();
@@ -123,10 +117,8 @@ namespace Godot.SourceGenerators
}
source.Append(attributes);
- source.Append("\n partial class ");
- source.Append(className);
- if (symbol.IsGenericType)
- source.Append($"<{string.Join(", ", symbol.TypeParameters)}>");
+ source.Append("\npartial class ");
+ source.Append(symbol.NameWithTypeParameters());
source.Append("\n{\n}\n");
if (hasNamespace)
@@ -134,7 +126,7 @@ namespace Godot.SourceGenerators
source.Append("\n}\n");
}
- context.AddSource(uniqueName.ToString(), SourceText.From(source.ToString(), Encoding.UTF8));
+ context.AddSource(uniqueHint.ToString(), SourceText.From(source.ToString(), Encoding.UTF8));
}
private static void AddScriptTypesAssemblyAttr(GeneratorExecutionContext context,
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
new file mode 100644
index 0000000000..fc46d82dff
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertiesGenerator.cs
@@ -0,0 +1,658 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Godot.SourceGenerators
+{
+ [Generator]
+ public class ScriptPropertiesGenerator : ISourceGenerator
+ {
+ public void Initialize(GeneratorInitializationContext context)
+ {
+ }
+
+ public void Execute(GeneratorExecutionContext context)
+ {
+ if (context.AreGodotSourceGeneratorsDisabled())
+ return;
+
+ INamedTypeSymbol[] godotClasses = context
+ .Compilation.SyntaxTrees
+ .SelectMany(tree =>
+ tree.GetRoot().DescendantNodes()
+ .OfType<ClassDeclarationSyntax>()
+ .SelectGodotScriptClasses(context.Compilation)
+ // Report and skip non-partial classes
+ .Where(x =>
+ {
+ if (x.cds.IsPartial())
+ {
+ if (x.cds.IsNested() && !x.cds.AreAllOuterTypesPartial(out var typeMissingPartial))
+ {
+ Common.ReportNonPartialGodotScriptOuterClass(context, typeMissingPartial!);
+ return false;
+ }
+
+ return true;
+ }
+
+ Common.ReportNonPartialGodotScriptClass(context, x.cds, x.symbol);
+ return false;
+ })
+ .Select(x => x.symbol)
+ )
+ .Distinct<INamedTypeSymbol>(SymbolEqualityComparer.Default)
+ .ToArray();
+
+ if (godotClasses.Length > 0)
+ {
+ var typeCache = new MarshalUtils.TypeCache(context.Compilation);
+
+ foreach (var godotClass in godotClasses)
+ {
+ VisitGodotScriptClass(context, typeCache, godotClass);
+ }
+ }
+ }
+
+ private static void VisitGodotScriptClass(
+ GeneratorExecutionContext context,
+ MarshalUtils.TypeCache typeCache,
+ INamedTypeSymbol symbol
+ )
+ {
+ INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace;
+ string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ?
+ namespaceSymbol.FullQualifiedName() :
+ string.Empty;
+ bool hasNamespace = classNs.Length != 0;
+
+ bool isInnerClass = symbol.ContainingType != null;
+
+ string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
+ + "_ScriptProperties_Generated";
+
+ var source = new StringBuilder();
+
+ source.Append("using Godot;\n");
+ source.Append("using Godot.NativeInterop;\n");
+ source.Append("\n");
+
+ if (hasNamespace)
+ {
+ source.Append("namespace ");
+ source.Append(classNs);
+ source.Append(" {\n\n");
+ }
+
+ if (isInnerClass)
+ {
+ var containingType = symbol.ContainingType;
+
+ while (containingType != null)
+ {
+ source.Append("partial ");
+ source.Append(containingType.GetDeclarationKeyword());
+ source.Append(" ");
+ source.Append(containingType.NameWithTypeParameters());
+ source.Append("\n{\n");
+
+ containingType = containingType.ContainingType;
+ }
+ }
+
+ source.Append("partial class ");
+ source.Append(symbol.NameWithTypeParameters());
+ source.Append("\n{\n");
+
+ var members = symbol.GetMembers();
+
+ var propertySymbols = members
+ .Where(s => !s.IsStatic && s.Kind == SymbolKind.Property)
+ .Cast<IPropertySymbol>()
+ .Where(s => !s.IsIndexer);
+
+ var fieldSymbols = members
+ .Where(s => !s.IsStatic && s.Kind == SymbolKind.Field && !s.IsImplicitlyDeclared)
+ .Cast<IFieldSymbol>();
+
+ var godotClassProperties = propertySymbols.WhereIsGodotCompatibleType(typeCache).ToArray();
+ var godotClassFields = fieldSymbols.WhereIsGodotCompatibleType(typeCache).ToArray();
+
+ source.Append(" private partial class GodotInternal {\n");
+
+ // Generate cached StringNames for methods and properties, for fast lookup
+
+ foreach (var property in godotClassProperties)
+ {
+ string propertyName = property.PropertySymbol.Name;
+ source.Append(" public static readonly StringName PropName_");
+ source.Append(propertyName);
+ source.Append(" = \"");
+ source.Append(propertyName);
+ source.Append("\";\n");
+ }
+
+ foreach (var field in godotClassFields)
+ {
+ string fieldName = field.FieldSymbol.Name;
+ source.Append(" public static readonly StringName PropName_");
+ source.Append(fieldName);
+ source.Append(" = \"");
+ source.Append(fieldName);
+ source.Append("\";\n");
+ }
+
+ source.Append(" }\n"); // class GodotInternal
+
+ if (godotClassProperties.Length > 0 || godotClassFields.Length > 0)
+ {
+ bool isFirstEntry;
+
+ // Generate SetGodotClassPropertyValue
+
+ bool allPropertiesAreReadOnly = godotClassFields.All(fi => fi.FieldSymbol.IsReadOnly) &&
+ godotClassProperties.All(pi => pi.PropertySymbol.IsReadOnly);
+
+ if (!allPropertiesAreReadOnly)
+ {
+ source.Append(" protected override bool SetGodotClassPropertyValue(in godot_string_name name, ");
+ source.Append("in godot_variant value)\n {\n");
+
+ isFirstEntry = true;
+ foreach (var property in godotClassProperties)
+ {
+ if (property.PropertySymbol.IsReadOnly)
+ continue;
+
+ GeneratePropertySetter(property.PropertySymbol.Name,
+ property.PropertySymbol.Type, property.Type, source, isFirstEntry);
+ isFirstEntry = false;
+ }
+
+ foreach (var field in godotClassFields)
+ {
+ if (field.FieldSymbol.IsReadOnly)
+ continue;
+
+ GeneratePropertySetter(field.FieldSymbol.Name,
+ field.FieldSymbol.Type, field.Type, source, isFirstEntry);
+ isFirstEntry = false;
+ }
+
+ source.Append(" return base.SetGodotClassPropertyValue(name, value);\n");
+
+ source.Append(" }\n");
+ }
+
+ // Generate GetGodotClassPropertyValue
+
+ source.Append(" protected override bool GetGodotClassPropertyValue(in godot_string_name name, ");
+ source.Append("out godot_variant value)\n {\n");
+
+ isFirstEntry = true;
+ foreach (var property in godotClassProperties)
+ {
+ GeneratePropertyGetter(property.PropertySymbol.Name,
+ property.Type, source, isFirstEntry);
+ isFirstEntry = false;
+ }
+
+ foreach (var field in godotClassFields)
+ {
+ GeneratePropertyGetter(field.FieldSymbol.Name,
+ field.Type, source, isFirstEntry);
+ isFirstEntry = false;
+ }
+
+ source.Append(" return base.GetGodotClassPropertyValue(name, out value);\n");
+
+ source.Append(" }\n");
+
+ // Generate GetGodotPropertyList
+
+ source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
+
+ string dictionaryType = "System.Collections.Generic.List<global::Godot.Bridge.PropertyInfo>";
+
+ source.Append(" internal new static ")
+ .Append(dictionaryType)
+ .Append(" GetGodotPropertyList()\n {\n");
+
+ source.Append(" var properties = new ")
+ .Append(dictionaryType)
+ .Append("();\n");
+
+ // To retain the definition order (and display categories correctly), we want to
+ // iterate over fields and properties at the same time, sorted by line number.
+ var godotClassPropertiesAndFields = Enumerable.Empty<GodotPropertyOrFieldData>()
+ .Concat(godotClassProperties.Select(propertyData => new GodotPropertyOrFieldData(propertyData)))
+ .Concat(godotClassFields.Select(fieldData => new GodotPropertyOrFieldData(fieldData)))
+ .OrderBy(data => data.Symbol.Locations[0].Path())
+ .ThenBy(data => data.Symbol.Locations[0].StartLine());
+
+ foreach (var member in godotClassPropertiesAndFields)
+ {
+ foreach (var groupingInfo in DetermineGroupingPropertyInfo(member.Symbol))
+ AppendGroupingPropertyInfo(source, groupingInfo);
+
+ var propertyInfo = DeterminePropertyInfo(context, typeCache,
+ member.Symbol, member.Type);
+
+ if (propertyInfo == null)
+ continue;
+
+ AppendPropertyInfo(source, propertyInfo.Value);
+ }
+
+ source.Append(" return properties;\n");
+ source.Append(" }\n");
+
+ source.Append("#pragma warning restore CS0109\n");
+ }
+
+ source.Append("}\n"); // partial class
+
+ if (isInnerClass)
+ {
+ var containingType = symbol.ContainingType;
+
+ while (containingType != null)
+ {
+ source.Append("}\n"); // outer class
+
+ containingType = containingType.ContainingType;
+ }
+ }
+
+ if (hasNamespace)
+ {
+ source.Append("\n}\n");
+ }
+
+ context.AddSource(uniqueHint, SourceText.From(source.ToString(), Encoding.UTF8));
+ }
+
+ private static void GeneratePropertySetter(
+ string propertyMemberName,
+ ITypeSymbol propertyTypeSymbol,
+ MarshalType propertyMarshalType,
+ StringBuilder source,
+ bool isFirstEntry
+ )
+ {
+ source.Append(" ");
+
+ if (!isFirstEntry)
+ source.Append("else ");
+
+ source.Append("if (name == GodotInternal.PropName_")
+ .Append(propertyMemberName)
+ .Append(") {\n")
+ .Append(" ")
+ .Append(propertyMemberName)
+ .Append(" = ")
+ .AppendNativeVariantToManagedExpr("value", propertyTypeSymbol, propertyMarshalType)
+ .Append(";\n")
+ .Append(" return true;\n")
+ .Append(" }\n");
+ }
+
+ private static void GeneratePropertyGetter(
+ string propertyMemberName,
+ MarshalType propertyMarshalType,
+ StringBuilder source,
+ bool isFirstEntry
+ )
+ {
+ source.Append(" ");
+
+ if (!isFirstEntry)
+ source.Append("else ");
+
+ source.Append("if (name == GodotInternal.PropName_")
+ .Append(propertyMemberName)
+ .Append(") {\n")
+ .Append(" value = ")
+ .AppendManagedToNativeVariantExpr(propertyMemberName, propertyMarshalType)
+ .Append(";\n")
+ .Append(" return true;\n")
+ .Append(" }\n");
+ }
+
+ private static void AppendGroupingPropertyInfo(StringBuilder source, PropertyInfo propertyInfo)
+ {
+ source.Append(" properties.Add(new(type: (Godot.Variant.Type)")
+ .Append((int)VariantType.Nil)
+ .Append(", name: \"")
+ .Append(propertyInfo.Name)
+ .Append("\", hint: (Godot.PropertyHint)")
+ .Append((int)PropertyHint.None)
+ .Append(", hintString: \"")
+ .Append(propertyInfo.HintString)
+ .Append("\", usage: (Godot.PropertyUsageFlags)")
+ .Append((int)propertyInfo.Usage)
+ .Append(", exported: true));\n");
+ }
+
+ private static void AppendPropertyInfo(StringBuilder source, PropertyInfo propertyInfo)
+ {
+ source.Append(" properties.Add(new(type: (Godot.Variant.Type)")
+ .Append((int)propertyInfo.Type)
+ .Append(", name: GodotInternal.PropName_")
+ .Append(propertyInfo.Name)
+ .Append(", hint: (Godot.PropertyHint)")
+ .Append((int)propertyInfo.Hint)
+ .Append(", hintString: \"")
+ .Append(propertyInfo.HintString)
+ .Append("\", usage: (Godot.PropertyUsageFlags)")
+ .Append((int)propertyInfo.Usage)
+ .Append(", exported: ")
+ .Append(propertyInfo.Exported ? "true" : "false")
+ .Append("));\n");
+ }
+
+ private static IEnumerable<PropertyInfo> DetermineGroupingPropertyInfo(ISymbol memberSymbol)
+ {
+ foreach (var attr in memberSymbol.GetAttributes())
+ {
+ PropertyUsageFlags? propertyUsage = attr.AttributeClass?.ToString() switch
+ {
+ GodotClasses.ExportCategoryAttr => PropertyUsageFlags.Category,
+ GodotClasses.ExportGroupAttr => PropertyUsageFlags.Group,
+ GodotClasses.ExportSubgroupAttr => PropertyUsageFlags.Subgroup,
+ _ => null
+ };
+
+ if (propertyUsage is null)
+ continue;
+
+ if (attr.ConstructorArguments.Length > 0 && attr.ConstructorArguments[0].Value is string name)
+ {
+ string? hintString = null;
+ if (propertyUsage != PropertyUsageFlags.Category && attr.ConstructorArguments.Length > 1)
+ hintString = attr.ConstructorArguments[1].Value?.ToString();
+
+ yield return new PropertyInfo(VariantType.Nil, name, PropertyHint.None, hintString, propertyUsage.Value, true);
+ }
+ }
+ }
+
+ private static PropertyInfo? DeterminePropertyInfo(
+ GeneratorExecutionContext context,
+ MarshalUtils.TypeCache typeCache,
+ ISymbol memberSymbol,
+ MarshalType marshalType
+ )
+ {
+ var exportAttr = memberSymbol.GetAttributes()
+ .FirstOrDefault(a => a.AttributeClass?.IsGodotExportAttribute() ?? false);
+
+ var propertySymbol = memberSymbol as IPropertySymbol;
+ var fieldSymbol = memberSymbol as IFieldSymbol;
+
+ if (exportAttr != null && propertySymbol != null)
+ {
+ if (propertySymbol.GetMethod == null)
+ {
+ // This should never happen, as we filtered WriteOnly properties, but just in case.
+ Common.ReportExportedMemberIsWriteOnly(context, propertySymbol);
+ return null;
+ }
+
+ if (propertySymbol.SetMethod == null)
+ {
+ // This should never happen, as we filtered ReadOnly properties, but just in case.
+ Common.ReportExportedMemberIsReadOnly(context, propertySymbol);
+ return null;
+ }
+ }
+
+ var memberType = propertySymbol?.Type ?? fieldSymbol!.Type;
+
+ var memberVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(marshalType)!.Value;
+ string memberName = memberSymbol.Name;
+
+ if (exportAttr == null)
+ {
+ return new PropertyInfo(memberVariantType, memberName, PropertyHint.None,
+ hintString: null, PropertyUsageFlags.ScriptVariable, exported: false);
+ }
+
+ if (!TryGetMemberExportHint(typeCache, memberType, exportAttr, memberVariantType,
+ isTypeArgument: false, out var hint, out var hintString))
+ {
+ var constructorArguments = exportAttr.ConstructorArguments;
+
+ if (constructorArguments.Length > 0)
+ {
+ var hintValue = exportAttr.ConstructorArguments[0].Value;
+
+ hint = hintValue switch
+ {
+ null => PropertyHint.None,
+ int intValue => (PropertyHint)intValue,
+ _ => (PropertyHint)(long)hintValue
+ };
+
+ hintString = constructorArguments.Length > 1 ?
+ exportAttr.ConstructorArguments[1].Value?.ToString() :
+ null;
+ }
+ else
+ {
+ hint = PropertyHint.None;
+ }
+ }
+
+ var propUsage = PropertyUsageFlags.Default | PropertyUsageFlags.ScriptVariable;
+
+ if (memberVariantType == VariantType.Nil)
+ propUsage |= PropertyUsageFlags.NilIsVariant;
+
+ return new PropertyInfo(memberVariantType, memberName,
+ hint, hintString, propUsage, exported: true);
+ }
+
+ private static bool TryGetMemberExportHint(
+ MarshalUtils.TypeCache typeCache,
+ ITypeSymbol type, AttributeData exportAttr,
+ VariantType variantType, bool isTypeArgument,
+ out PropertyHint hint, out string? hintString
+ )
+ {
+ hint = PropertyHint.None;
+ hintString = null;
+
+ if (variantType == VariantType.Nil)
+ return true; // Variant, no export hint
+
+ if (variantType == VariantType.Int &&
+ type.IsValueType && type.TypeKind == TypeKind.Enum)
+ {
+ bool hasFlagsAttr = type.GetAttributes()
+ .Any(a => a.AttributeClass?.IsSystemFlagsAttribute() ?? false);
+
+ hint = hasFlagsAttr ? PropertyHint.Flags : PropertyHint.Enum;
+
+ var members = type.GetMembers();
+
+ var enumFields = members
+ .Where(s => s.Kind == SymbolKind.Field && s.IsStatic &&
+ s.DeclaredAccessibility == Accessibility.Public &&
+ !s.IsImplicitlyDeclared)
+ .Cast<IFieldSymbol>().ToArray();
+
+ var hintStringBuilder = new StringBuilder();
+ var nameOnlyHintStringBuilder = new StringBuilder();
+
+ // True: enum Foo { Bar, Baz, Qux }
+ // True: enum Foo { Bar = 0, Baz = 1, Qux = 2 }
+ // False: enum Foo { Bar = 0, Baz = 7, Qux = 5 }
+ bool usesDefaultValues = true;
+
+ for (int i = 0; i < enumFields.Length; i++)
+ {
+ var enumField = enumFields[i];
+
+ if (i > 0)
+ {
+ hintStringBuilder.Append(",");
+ nameOnlyHintStringBuilder.Append(",");
+ }
+
+ string enumFieldName = enumField.Name;
+ hintStringBuilder.Append(enumFieldName);
+ nameOnlyHintStringBuilder.Append(enumFieldName);
+
+ long val = enumField.ConstantValue switch
+ {
+ sbyte v => v,
+ short v => v,
+ int v => v,
+ long v => v,
+ byte v => v,
+ ushort v => v,
+ uint v => v,
+ ulong v => (long)v,
+ _ => 0
+ };
+
+ uint expectedVal = (uint)(hint == PropertyHint.Flags ? 1 << i : i);
+ if (val != expectedVal)
+ usesDefaultValues = false;
+
+ hintStringBuilder.Append(":");
+ hintStringBuilder.Append(val);
+ }
+
+ hintString = !usesDefaultValues ?
+ hintStringBuilder.ToString() :
+ // If we use the format NAME:VAL, that's what the editor displays.
+ // That's annoying if the user is not using custom values for the enum constants.
+ // This may not be needed in the future if the editor is changed to not display values.
+ nameOnlyHintStringBuilder.ToString();
+
+ return true;
+ }
+
+ if (variantType == VariantType.Object && type is INamedTypeSymbol memberNamedType)
+ {
+ if (memberNamedType.InheritsFrom("GodotSharp", "Godot.Resource"))
+ {
+ string nativeTypeName = memberNamedType.GetGodotScriptNativeClassName()!;
+
+ hint = PropertyHint.ResourceType;
+ hintString = nativeTypeName;
+
+ return true;
+ }
+
+ if (memberNamedType.InheritsFrom("GodotSharp", "Godot.Node"))
+ {
+ string nativeTypeName = memberNamedType.GetGodotScriptNativeClassName()!;
+
+ hint = PropertyHint.NodeType;
+ hintString = nativeTypeName;
+
+ return true;
+ }
+ }
+
+ static bool GetStringArrayEnumHint(VariantType elementVariantType,
+ AttributeData exportAttr, out string? hintString)
+ {
+ var constructorArguments = exportAttr.ConstructorArguments;
+
+ if (constructorArguments.Length > 0)
+ {
+ var presetHintValue = exportAttr.ConstructorArguments[0].Value;
+
+ PropertyHint presetHint = presetHintValue switch
+ {
+ null => PropertyHint.None,
+ int intValue => (PropertyHint)intValue,
+ _ => (PropertyHint)(long)presetHintValue
+ };
+
+ if (presetHint == PropertyHint.Enum)
+ {
+ string? presetHintString = constructorArguments.Length > 1 ?
+ exportAttr.ConstructorArguments[1].Value?.ToString() :
+ null;
+
+ hintString = (int)elementVariantType + "/" + (int)PropertyHint.Enum + ":";
+
+ if (presetHintString != null)
+ hintString += presetHintString;
+
+ return true;
+ }
+ }
+
+ hintString = null;
+ return false;
+ }
+
+ if (!isTypeArgument && variantType == VariantType.Array)
+ {
+ var elementType = MarshalUtils.GetArrayElementType(type);
+
+ if (elementType == null)
+ return false; // Non-generic Array, so there's no hint to add
+
+ var elementMarshalType = MarshalUtils.ConvertManagedTypeToMarshalType(elementType, typeCache)!.Value;
+ var elementVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(elementMarshalType)!.Value;
+
+ bool isPresetHint = false;
+
+ if (elementVariantType == VariantType.String)
+ isPresetHint = GetStringArrayEnumHint(elementVariantType, exportAttr, out hintString);
+
+ if (!isPresetHint)
+ {
+ bool hintRes = TryGetMemberExportHint(typeCache, elementType,
+ exportAttr, elementVariantType, isTypeArgument: true,
+ out var elementHint, out var elementHintString);
+
+ // Format: type/hint:hint_string
+ if (hintRes)
+ {
+ hintString = (int)elementVariantType + "/" + (int)elementHint + ":";
+
+ if (elementHintString != null)
+ hintString += elementHintString;
+ }
+ else
+ {
+ hintString = (int)elementVariantType + "/" + (int)PropertyHint.None + ":";
+ }
+ }
+
+ hint = PropertyHint.TypeString;
+
+ return hintString != null;
+ }
+
+ if (!isTypeArgument && variantType == VariantType.PackedStringArray)
+ {
+ if (GetStringArrayEnumHint(VariantType.String, exportAttr, out hintString))
+ {
+ hint = PropertyHint.TypeString;
+ return true;
+ }
+ }
+
+ if (!isTypeArgument && variantType == VariantType.Dictionary)
+ {
+ // TODO: Dictionaries are not supported in the inspector
+ return false;
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
new file mode 100644
index 0000000000..c7745391d0
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptPropertyDefValGenerator.cs
@@ -0,0 +1,298 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Godot.SourceGenerators
+{
+ [Generator]
+ public class ScriptPropertyDefValGenerator : ISourceGenerator
+ {
+ public void Initialize(GeneratorInitializationContext context)
+ {
+ }
+
+ public void Execute(GeneratorExecutionContext context)
+ {
+ if (context.AreGodotSourceGeneratorsDisabled())
+ return;
+
+ INamedTypeSymbol[] godotClasses = context
+ .Compilation.SyntaxTrees
+ .SelectMany(tree =>
+ tree.GetRoot().DescendantNodes()
+ .OfType<ClassDeclarationSyntax>()
+ .SelectGodotScriptClasses(context.Compilation)
+ // Report and skip non-partial classes
+ .Where(x =>
+ {
+ if (x.cds.IsPartial())
+ {
+ if (x.cds.IsNested() && !x.cds.AreAllOuterTypesPartial(out var typeMissingPartial))
+ {
+ Common.ReportNonPartialGodotScriptOuterClass(context, typeMissingPartial!);
+ return false;
+ }
+
+ return true;
+ }
+
+ Common.ReportNonPartialGodotScriptClass(context, x.cds, x.symbol);
+ return false;
+ })
+ .Select(x => x.symbol)
+ )
+ .Distinct<INamedTypeSymbol>(SymbolEqualityComparer.Default)
+ .ToArray();
+
+ if (godotClasses.Length > 0)
+ {
+ var typeCache = new MarshalUtils.TypeCache(context.Compilation);
+
+ foreach (var godotClass in godotClasses)
+ {
+ VisitGodotScriptClass(context, typeCache, godotClass);
+ }
+ }
+ }
+
+ private static void VisitGodotScriptClass(
+ GeneratorExecutionContext context,
+ MarshalUtils.TypeCache typeCache,
+ INamedTypeSymbol symbol
+ )
+ {
+ INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace;
+ string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ?
+ namespaceSymbol.FullQualifiedName() :
+ string.Empty;
+ bool hasNamespace = classNs.Length != 0;
+
+ bool isInnerClass = symbol.ContainingType != null;
+
+ string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
+ + "_ScriptPropertyDefVal_Generated";
+
+ var source = new StringBuilder();
+
+ source.Append("using Godot;\n");
+ source.Append("using Godot.NativeInterop;\n");
+ source.Append("\n");
+
+ if (hasNamespace)
+ {
+ source.Append("namespace ");
+ source.Append(classNs);
+ source.Append(" {\n\n");
+ }
+
+ if (isInnerClass)
+ {
+ var containingType = symbol.ContainingType;
+
+ while (containingType != null)
+ {
+ source.Append("partial ");
+ source.Append(containingType.GetDeclarationKeyword());
+ source.Append(" ");
+ source.Append(containingType.NameWithTypeParameters());
+ source.Append("\n{\n");
+
+ containingType = containingType.ContainingType;
+ }
+ }
+
+ source.Append("partial class ");
+ source.Append(symbol.NameWithTypeParameters());
+ source.Append("\n{\n");
+
+ var exportedMembers = new List<ExportedPropertyMetadata>();
+
+ var members = symbol.GetMembers();
+
+ var exportedProperties = members
+ .Where(s => !s.IsStatic && s.Kind == SymbolKind.Property)
+ .Cast<IPropertySymbol>()
+ .Where(s => s.GetAttributes()
+ .Any(a => a.AttributeClass?.IsGodotExportAttribute() ?? false))
+ .ToArray();
+
+ var exportedFields = members
+ .Where(s => !s.IsStatic && s.Kind == SymbolKind.Field && !s.IsImplicitlyDeclared)
+ .Cast<IFieldSymbol>()
+ .Where(s => s.GetAttributes()
+ .Any(a => a.AttributeClass?.IsGodotExportAttribute() ?? false))
+ .ToArray();
+
+ foreach (var property in exportedProperties)
+ {
+ if (property.IsStatic)
+ {
+ Common.ReportExportedMemberIsStatic(context, property);
+ continue;
+ }
+
+ if (property.IsIndexer)
+ {
+ Common.ReportExportedMemberIsIndexer(context, property);
+ continue;
+ }
+
+ // TODO: We should still restore read-only properties after reloading assembly. Two possible ways: reflection or turn RestoreGodotObjectData into a constructor overload.
+ // Ignore properties without a getter or without a setter. Godot properties must be both readable and writable.
+ if (property.IsWriteOnly)
+ {
+ Common.ReportExportedMemberIsWriteOnly(context, property);
+ continue;
+ }
+
+ if (property.IsReadOnly)
+ {
+ Common.ReportExportedMemberIsReadOnly(context, property);
+ continue;
+ }
+
+ var propertyType = property.Type;
+ var marshalType = MarshalUtils.ConvertManagedTypeToMarshalType(propertyType, typeCache);
+
+ if (marshalType == null)
+ {
+ Common.ReportExportedMemberTypeNotSupported(context, property);
+ continue;
+ }
+
+ // TODO: Detect default value from simple property getters (currently we only detect from initializers)
+
+ EqualsValueClauseSyntax? initializer = property.DeclaringSyntaxReferences
+ .Select(r => r.GetSyntax() as PropertyDeclarationSyntax)
+ .Select(s => s?.Initializer ?? null)
+ .FirstOrDefault();
+
+ string? value = initializer?.Value.ToString();
+
+ exportedMembers.Add(new ExportedPropertyMetadata(
+ property.Name, marshalType.Value, propertyType, value));
+ }
+
+ foreach (var field in exportedFields)
+ {
+ if (field.IsStatic)
+ {
+ Common.ReportExportedMemberIsStatic(context, field);
+ continue;
+ }
+
+ // TODO: We should still restore read-only fields after reloading assembly. Two possible ways: reflection or turn RestoreGodotObjectData into a constructor overload.
+ // Ignore properties without a getter or without a setter. Godot properties must be both readable and writable.
+ if (field.IsReadOnly)
+ {
+ Common.ReportExportedMemberIsReadOnly(context, field);
+ continue;
+ }
+
+ var fieldType = field.Type;
+ var marshalType = MarshalUtils.ConvertManagedTypeToMarshalType(fieldType, typeCache);
+
+ if (marshalType == null)
+ {
+ Common.ReportExportedMemberTypeNotSupported(context, field);
+ continue;
+ }
+
+ EqualsValueClauseSyntax? initializer = field.DeclaringSyntaxReferences
+ .Select(r => r.GetSyntax())
+ .OfType<VariableDeclaratorSyntax>()
+ .Select(s => s.Initializer)
+ .FirstOrDefault(i => i != null);
+
+ string? value = initializer?.Value.ToString();
+
+ exportedMembers.Add(new ExportedPropertyMetadata(
+ field.Name, marshalType.Value, fieldType, value));
+ }
+
+ // Generate GetGodotExportedProperties
+
+ if (exportedMembers.Count > 0)
+ {
+ source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
+
+ string dictionaryType = "System.Collections.Generic.Dictionary<StringName, object>";
+
+ source.Append("#if TOOLS\n");
+ source.Append(" internal new static ");
+ source.Append(dictionaryType);
+ source.Append(" GetGodotPropertyDefaultValues()\n {\n");
+
+ source.Append(" var values = new ");
+ source.Append(dictionaryType);
+ source.Append("(");
+ source.Append(exportedMembers.Count);
+ source.Append(");\n");
+
+ foreach (var exportedMember in exportedMembers)
+ {
+ string defaultValueLocalName = string.Concat("__", exportedMember.Name, "_default_value");
+
+ source.Append(" ");
+ source.Append(exportedMember.TypeSymbol.FullQualifiedName());
+ source.Append(" ");
+ source.Append(defaultValueLocalName);
+ source.Append(" = ");
+ source.Append(exportedMember.Value ?? "default");
+ source.Append(";\n");
+ source.Append(" values.Add(GodotInternal.PropName_");
+ source.Append(exportedMember.Name);
+ source.Append(", ");
+ source.Append(defaultValueLocalName);
+ source.Append(");\n");
+ }
+
+ source.Append(" return values;\n");
+ source.Append(" }\n");
+ source.Append("#endif\n");
+
+ source.Append("#pragma warning restore CS0109\n");
+ }
+
+ source.Append("}\n"); // partial class
+
+ if (isInnerClass)
+ {
+ var containingType = symbol.ContainingType;
+
+ while (containingType != null)
+ {
+ source.Append("}\n"); // outer class
+
+ containingType = containingType.ContainingType;
+ }
+ }
+
+ if (hasNamespace)
+ {
+ source.Append("\n}\n");
+ }
+
+ context.AddSource(uniqueHint, SourceText.From(source.ToString(), Encoding.UTF8));
+ }
+
+ private struct ExportedPropertyMetadata
+ {
+ public ExportedPropertyMetadata(string name, MarshalType type, ITypeSymbol typeSymbol, string? value)
+ {
+ Name = name;
+ Type = type;
+ TypeSymbol = typeSymbol;
+ Value = value;
+ }
+
+ public string Name { get; }
+ public MarshalType Type { get; }
+ public ITypeSymbol TypeSymbol { get; }
+ public string? Value { get; }
+ }
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptRegistrarGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptRegistrarGenerator.cs
new file mode 100644
index 0000000000..ec04a319e2
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptRegistrarGenerator.cs
@@ -0,0 +1,19 @@
+using Microsoft.CodeAnalysis;
+
+namespace Godot.SourceGenerators
+{
+ // Placeholder. Once we switch to native extensions this will act as the registrar for all
+ // user Godot classes in the assembly. Think of it as something similar to `register_types`.
+ public class ScriptRegistrarGenerator : ISourceGenerator
+ {
+ public void Initialize(GeneratorInitializationContext context)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public void Execute(GeneratorExecutionContext context)
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
new file mode 100644
index 0000000000..39a99ff8ba
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSerializationGenerator.cs
@@ -0,0 +1,284 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Text;
+
+namespace Godot.SourceGenerators
+{
+ [Generator]
+ public class ScriptSerializationGenerator : ISourceGenerator
+ {
+ public void Initialize(GeneratorInitializationContext context)
+ {
+ }
+
+ public void Execute(GeneratorExecutionContext context)
+ {
+ if (context.AreGodotSourceGeneratorsDisabled())
+ return;
+
+ INamedTypeSymbol[] godotClasses = context
+ .Compilation.SyntaxTrees
+ .SelectMany(tree =>
+ tree.GetRoot().DescendantNodes()
+ .OfType<ClassDeclarationSyntax>()
+ .SelectGodotScriptClasses(context.Compilation)
+ // Report and skip non-partial classes
+ .Where(x =>
+ {
+ if (x.cds.IsPartial())
+ {
+ if (x.cds.IsNested() && !x.cds.AreAllOuterTypesPartial(out var typeMissingPartial))
+ {
+ Common.ReportNonPartialGodotScriptOuterClass(context, typeMissingPartial!);
+ return false;
+ }
+
+ return true;
+ }
+
+ Common.ReportNonPartialGodotScriptClass(context, x.cds, x.symbol);
+ return false;
+ })
+ .Select(x => x.symbol)
+ )
+ .Distinct<INamedTypeSymbol>(SymbolEqualityComparer.Default)
+ .ToArray();
+
+ if (godotClasses.Length > 0)
+ {
+ var typeCache = new MarshalUtils.TypeCache(context.Compilation);
+
+ foreach (var godotClass in godotClasses)
+ {
+ VisitGodotScriptClass(context, typeCache, godotClass);
+ }
+ }
+ }
+
+ private static void VisitGodotScriptClass(
+ GeneratorExecutionContext context,
+ MarshalUtils.TypeCache typeCache,
+ INamedTypeSymbol symbol
+ )
+ {
+ INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace;
+ string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ?
+ namespaceSymbol.FullQualifiedName() :
+ string.Empty;
+ bool hasNamespace = classNs.Length != 0;
+
+ bool isInnerClass = symbol.ContainingType != null;
+
+ string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
+ + "_ScriptSerialization_Generated";
+
+ var source = new StringBuilder();
+
+ source.Append("using Godot;\n");
+ source.Append("using Godot.NativeInterop;\n");
+ source.Append("\n");
+
+ if (hasNamespace)
+ {
+ source.Append("namespace ");
+ source.Append(classNs);
+ source.Append(" {\n\n");
+ }
+
+ if (isInnerClass)
+ {
+ var containingType = symbol.ContainingType;
+
+ while (containingType != null)
+ {
+ source.Append("partial ");
+ source.Append(containingType.GetDeclarationKeyword());
+ source.Append(" ");
+ source.Append(containingType.NameWithTypeParameters());
+ source.Append("\n{\n");
+
+ containingType = containingType.ContainingType;
+ }
+ }
+
+ source.Append("partial class ");
+ source.Append(symbol.NameWithTypeParameters());
+ source.Append("\n{\n");
+
+ var members = symbol.GetMembers();
+
+ var propertySymbols = members
+ .Where(s => !s.IsStatic && s.Kind == SymbolKind.Property)
+ .Cast<IPropertySymbol>()
+ .Where(s => !s.IsIndexer);
+
+ var fieldSymbols = members
+ .Where(s => !s.IsStatic && s.Kind == SymbolKind.Field && !s.IsImplicitlyDeclared)
+ .Cast<IFieldSymbol>();
+
+ var godotClassProperties = propertySymbols.WhereIsGodotCompatibleType(typeCache).ToArray();
+ var godotClassFields = fieldSymbols.WhereIsGodotCompatibleType(typeCache).ToArray();
+
+ var signalDelegateSymbols = members
+ .Where(s => s.Kind == SymbolKind.NamedType)
+ .Cast<INamedTypeSymbol>()
+ .Where(namedTypeSymbol => namedTypeSymbol.TypeKind == TypeKind.Delegate)
+ .Where(s => s.GetAttributes()
+ .Any(a => a.AttributeClass?.IsGodotSignalAttribute() ?? false));
+
+ List<GodotSignalDelegateData> godotSignalDelegates = new();
+
+ foreach (var signalDelegateSymbol in signalDelegateSymbols)
+ {
+ if (!signalDelegateSymbol.Name.EndsWith(ScriptSignalsGenerator.SignalDelegateSuffix))
+ continue;
+
+ string signalName = signalDelegateSymbol.Name;
+ signalName = signalName.Substring(0,
+ signalName.Length - ScriptSignalsGenerator.SignalDelegateSuffix.Length);
+
+ var invokeMethodData = signalDelegateSymbol
+ .DelegateInvokeMethod?.HasGodotCompatibleSignature(typeCache);
+
+ if (invokeMethodData == null)
+ continue;
+
+ godotSignalDelegates.Add(new(signalName, signalDelegateSymbol, invokeMethodData.Value));
+ }
+
+ source.Append(
+ " protected override void SaveGodotObjectData(global::Godot.Bridge.GodotSerializationInfo info)\n {\n");
+ source.Append(" base.SaveGodotObjectData(info);\n");
+
+ // Save properties
+
+ foreach (var property in godotClassProperties)
+ {
+ string propertyName = property.PropertySymbol.Name;
+
+ source.Append(" info.AddProperty(GodotInternal.PropName_")
+ .Append(propertyName)
+ .Append(", ")
+ .AppendManagedToVariantExpr(string.Concat("this.", propertyName), property.Type)
+ .Append(");\n");
+ }
+
+ // Save fields
+
+ foreach (var field in godotClassFields)
+ {
+ string fieldName = field.FieldSymbol.Name;
+
+ source.Append(" info.AddProperty(GodotInternal.PropName_")
+ .Append(fieldName)
+ .Append(", ")
+ .AppendManagedToVariantExpr(string.Concat("this.", fieldName), field.Type)
+ .Append(");\n");
+ }
+
+ // Save signal events
+
+ foreach (var signalDelegate in godotSignalDelegates)
+ {
+ string signalName = signalDelegate.Name;
+
+ source.Append(" info.AddSignalEventDelegate(GodotInternal.SignalName_")
+ .Append(signalName)
+ .Append(", this.backing_")
+ .Append(signalName)
+ .Append(");\n");
+ }
+
+ source.Append(" }\n");
+
+ source.Append(
+ " protected override void RestoreGodotObjectData(global::Godot.Bridge.GodotSerializationInfo info)\n {\n");
+ source.Append(" base.RestoreGodotObjectData(info);\n");
+
+ // Restore properties
+
+ foreach (var property in godotClassProperties)
+ {
+ string propertyName = property.PropertySymbol.Name;
+
+ source.Append(" if (info.TryGetProperty(GodotInternal.PropName_")
+ .Append(propertyName)
+ .Append(", out var _value_")
+ .Append(propertyName)
+ .Append("))\n")
+ .Append(" this.")
+ .Append(propertyName)
+ .Append(" = ")
+ .AppendVariantToManagedExpr(string.Concat("_value_", propertyName),
+ property.PropertySymbol.Type, property.Type)
+ .Append(";\n");
+ }
+
+ // Restore fields
+
+ foreach (var field in godotClassFields)
+ {
+ string fieldName = field.FieldSymbol.Name;
+
+ source.Append(" if (info.TryGetProperty(GodotInternal.PropName_")
+ .Append(fieldName)
+ .Append(", out var _value_")
+ .Append(fieldName)
+ .Append("))\n")
+ .Append(" this.")
+ .Append(fieldName)
+ .Append(" = ")
+ .AppendVariantToManagedExpr(string.Concat("_value_", fieldName),
+ field.FieldSymbol.Type, field.Type)
+ .Append(";\n");
+ }
+
+ // Restore signal events
+
+ foreach (var signalDelegate in godotSignalDelegates)
+ {
+ string signalName = signalDelegate.Name;
+ string signalDelegateQualifiedName = signalDelegate.DelegateSymbol.FullQualifiedName();
+
+ source.Append(" if (info.TryGetSignalEventDelegate<")
+ .Append(signalDelegateQualifiedName)
+ .Append(">(GodotInternal.SignalName_")
+ .Append(signalName)
+ .Append(", out var _value_")
+ .Append(signalName)
+ .Append("))\n")
+ .Append(" this.backing_")
+ .Append(signalName)
+ .Append(" = _value_")
+ .Append(signalName)
+ .Append(";\n");
+ }
+
+ source.Append(" }\n");
+
+ source.Append("}\n"); // partial class
+
+ if (isInnerClass)
+ {
+ var containingType = symbol.ContainingType;
+
+ while (containingType != null)
+ {
+ source.Append("}\n"); // outer class
+
+ containingType = containingType.ContainingType;
+ }
+ }
+
+ if (hasNamespace)
+ {
+ source.Append("\n}\n");
+ }
+
+ context.AddSource(uniqueHint, SourceText.From(source.ToString(), Encoding.UTF8));
+ }
+ }
+}
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
new file mode 100644
index 0000000000..6b06f10db1
--- /dev/null
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptSignalsGenerator.cs
@@ -0,0 +1,428 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Text;
+
+// TODO:
+// Determine a proper way to emit the signal.
+// 'Emit(nameof(TheEvent))' creates a StringName everytime and has the overhead of string marshaling.
+// I haven't decided on the best option yet. Some possibilities:
+// - Expose the generated StringName fields to the user, for use with 'Emit(...)'.
+// - Generate a 'EmitSignalName' method for each event signal.
+
+namespace Godot.SourceGenerators
+{
+ [Generator]
+ public class ScriptSignalsGenerator : ISourceGenerator
+ {
+ public void Initialize(GeneratorInitializationContext context)
+ {
+ }
+
+ public void Execute(GeneratorExecutionContext context)
+ {
+ if (context.AreGodotSourceGeneratorsDisabled())
+ return;
+
+ INamedTypeSymbol[] godotClasses = context
+ .Compilation.SyntaxTrees
+ .SelectMany(tree =>
+ tree.GetRoot().DescendantNodes()
+ .OfType<ClassDeclarationSyntax>()
+ .SelectGodotScriptClasses(context.Compilation)
+ // Report and skip non-partial classes
+ .Where(x =>
+ {
+ if (x.cds.IsPartial())
+ {
+ if (x.cds.IsNested() && !x.cds.AreAllOuterTypesPartial(out var typeMissingPartial))
+ {
+ Common.ReportNonPartialGodotScriptOuterClass(context, typeMissingPartial!);
+ return false;
+ }
+
+ return true;
+ }
+
+ Common.ReportNonPartialGodotScriptClass(context, x.cds, x.symbol);
+ return false;
+ })
+ .Select(x => x.symbol)
+ )
+ .Distinct<INamedTypeSymbol>(SymbolEqualityComparer.Default)
+ .ToArray();
+
+ if (godotClasses.Length > 0)
+ {
+ var typeCache = new MarshalUtils.TypeCache(context.Compilation);
+
+ foreach (var godotClass in godotClasses)
+ {
+ VisitGodotScriptClass(context, typeCache, godotClass);
+ }
+ }
+ }
+
+ internal static string SignalDelegateSuffix = "EventHandler";
+
+ private static void VisitGodotScriptClass(
+ GeneratorExecutionContext context,
+ MarshalUtils.TypeCache typeCache,
+ INamedTypeSymbol symbol
+ )
+ {
+ INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace;
+ string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ?
+ namespaceSymbol.FullQualifiedName() :
+ string.Empty;
+ bool hasNamespace = classNs.Length != 0;
+
+ bool isInnerClass = symbol.ContainingType != null;
+
+ string uniqueHint = symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()
+ + "_ScriptSignals_Generated";
+
+ var source = new StringBuilder();
+
+ source.Append("using Godot;\n");
+ source.Append("using Godot.NativeInterop;\n");
+ source.Append("\n");
+
+ if (hasNamespace)
+ {
+ source.Append("namespace ");
+ source.Append(classNs);
+ source.Append(" {\n\n");
+ }
+
+ if (isInnerClass)
+ {
+ var containingType = symbol.ContainingType;
+
+ while (containingType != null)
+ {
+ source.Append("partial ");
+ source.Append(containingType.GetDeclarationKeyword());
+ source.Append(" ");
+ source.Append(containingType.NameWithTypeParameters());
+ source.Append("\n{\n");
+
+ containingType = containingType.ContainingType;
+ }
+ }
+
+ source.Append("partial class ");
+ source.Append(symbol.NameWithTypeParameters());
+ source.Append("\n{\n");
+
+ var members = symbol.GetMembers();
+
+ var signalDelegateSymbols = members
+ .Where(s => s.Kind == SymbolKind.NamedType)
+ .Cast<INamedTypeSymbol>()
+ .Where(namedTypeSymbol => namedTypeSymbol.TypeKind == TypeKind.Delegate)
+ .Where(s => s.GetAttributes()
+ .Any(a => a.AttributeClass?.IsGodotSignalAttribute() ?? false));
+
+ List<GodotSignalDelegateData> godotSignalDelegates = new();
+
+ foreach (var signalDelegateSymbol in signalDelegateSymbols)
+ {
+ if (!signalDelegateSymbol.Name.EndsWith(SignalDelegateSuffix))
+ {
+ Common.ReportSignalDelegateMissingSuffix(context, signalDelegateSymbol);
+ continue;
+ }
+
+ string signalName = signalDelegateSymbol.Name;
+ signalName = signalName.Substring(0, signalName.Length - SignalDelegateSuffix.Length);
+
+ var invokeMethodData = signalDelegateSymbol
+ .DelegateInvokeMethod?.HasGodotCompatibleSignature(typeCache);
+
+ if (invokeMethodData == null)
+ {
+ if (signalDelegateSymbol.DelegateInvokeMethod is IMethodSymbol methodSymbol)
+ {
+ foreach (var parameter in methodSymbol.Parameters)
+ {
+ if (parameter.RefKind != RefKind.None)
+ {
+ Common.ReportSignalParameterTypeNotSupported(context, parameter);
+ continue;
+ }
+
+ var marshalType = MarshalUtils.ConvertManagedTypeToMarshalType(parameter.Type, typeCache);
+
+ if (marshalType == null)
+ {
+ Common.ReportSignalParameterTypeNotSupported(context, parameter);
+ }
+ }
+
+ if (!methodSymbol.ReturnsVoid)
+ {
+ Common.ReportSignalDelegateSignatureMustReturnVoid(context, signalDelegateSymbol);
+ }
+ }
+ continue;
+ }
+
+ godotSignalDelegates.Add(new(signalName, signalDelegateSymbol, invokeMethodData.Value));
+ }
+
+ source.Append(" private partial class GodotInternal {\n");
+
+ // Generate cached StringNames for methods and properties, for fast lookup
+
+ foreach (var signalDelegate in godotSignalDelegates)
+ {
+ string signalName = signalDelegate.Name;
+ source.Append(" public static readonly StringName SignalName_");
+ source.Append(signalName);
+ source.Append(" = \"");
+ source.Append(signalName);
+ source.Append("\";\n");
+ }
+
+ source.Append(" }\n"); // class GodotInternal
+
+ // Generate GetGodotSignalList
+
+ if (godotSignalDelegates.Count > 0)
+ {
+ source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
+
+ const string listType = "System.Collections.Generic.List<global::Godot.Bridge.MethodInfo>";
+
+ source.Append(" internal new static ")
+ .Append(listType)
+ .Append(" GetGodotSignalList()\n {\n");
+
+ source.Append(" var signals = new ")
+ .Append(listType)
+ .Append("(")
+ .Append(godotSignalDelegates.Count)
+ .Append(");\n");
+
+ foreach (var signalDelegateData in godotSignalDelegates)
+ {
+ var methodInfo = DetermineMethodInfo(signalDelegateData);
+ AppendMethodInfo(source, methodInfo);
+ }
+
+ source.Append(" return signals;\n");
+ source.Append(" }\n");
+
+ source.Append("#pragma warning restore CS0109\n");
+ }
+
+ // Generate signal event
+
+ foreach (var signalDelegate in godotSignalDelegates)
+ {
+ string signalName = signalDelegate.Name;
+
+ // TODO: Hide backing event from code-completion and debugger
+ // The reason we have a backing field is to hide the invoke method from the event,
+ // as it doesn't emit the signal, only the event delegates. This can confuse users.
+ // Maybe we should directly connect the delegates, as we do with native signals?
+ source.Append(" private ")
+ .Append(signalDelegate.DelegateSymbol.FullQualifiedName())
+ .Append(" backing_")
+ .Append(signalName)
+ .Append(";\n");
+
+ source.Append(" public event ")
+ .Append(signalDelegate.DelegateSymbol.FullQualifiedName())
+ .Append(" ")
+ .Append(signalName)
+ .Append(" {\n")
+ .Append(" add => backing_")
+ .Append(signalName)
+ .Append(" += value;\n")
+ .Append(" remove => backing_")
+ .Append(signalName)
+ .Append(" -= value;\n")
+ .Append("}\n");
+ }
+
+ // Generate RaiseGodotClassSignalCallbacks
+
+ if (godotSignalDelegates.Count > 0)
+ {
+ source.Append(
+ " protected override void RaiseGodotClassSignalCallbacks(in godot_string_name signal, ");
+ source.Append("NativeVariantPtrArgs args, int argCount)\n {\n");
+
+ foreach (var signal in godotSignalDelegates)
+ {
+ GenerateSignalEventInvoker(signal, source);
+ }
+
+ source.Append(" base.RaiseGodotClassSignalCallbacks(signal, args, argCount);\n");
+
+ source.Append(" }\n");
+ }
+
+ source.Append("}\n"); // partial class
+
+ if (isInnerClass)
+ {
+ var containingType = symbol.ContainingType;
+
+ while (containingType != null)
+ {
+ source.Append("}\n"); // outer class
+
+ containingType = containingType.ContainingType;
+ }
+ }
+
+ if (hasNamespace)
+ {
+ source.Append("\n}\n");
+ }
+
+ context.AddSource(uniqueHint, SourceText.From(source.ToString(), Encoding.UTF8));
+ }
+
+ private static void AppendMethodInfo(StringBuilder source, MethodInfo methodInfo)
+ {
+ source.Append(" signals.Add(new(name: GodotInternal.SignalName_")
+ .Append(methodInfo.Name)
+ .Append(", returnVal: ");
+
+ AppendPropertyInfo(source, methodInfo.ReturnVal);
+
+ source.Append(", flags: (Godot.MethodFlags)")
+ .Append((int)methodInfo.Flags)
+ .Append(", arguments: ");
+
+ if (methodInfo.Arguments is { Count: > 0 })
+ {
+ source.Append("new() { ");
+
+ foreach (var param in methodInfo.Arguments)
+ {
+ AppendPropertyInfo(source, param);
+
+ // C# allows colon after the last element
+ source.Append(", ");
+ }
+
+ source.Append(" }");
+ }
+ else
+ {
+ source.Append("null");
+ }
+
+ source.Append(", defaultArguments: null));\n");
+ }
+
+ private static void AppendPropertyInfo(StringBuilder source, PropertyInfo propertyInfo)
+ {
+ source.Append("new(type: (Godot.Variant.Type)")
+ .Append((int)propertyInfo.Type)
+ .Append(", name: \"")
+ .Append(propertyInfo.Name)
+ .Append("\", hint: (Godot.PropertyHint)")
+ .Append((int)propertyInfo.Hint)
+ .Append(", hintString: \"")
+ .Append(propertyInfo.HintString)
+ .Append("\", usage: (Godot.PropertyUsageFlags)")
+ .Append((int)propertyInfo.Usage)
+ .Append(", exported: ")
+ .Append(propertyInfo.Exported ? "true" : "false")
+ .Append(")");
+ }
+
+ private static MethodInfo DetermineMethodInfo(GodotSignalDelegateData signalDelegateData)
+ {
+ var invokeMethodData = signalDelegateData.InvokeMethodData;
+
+ PropertyInfo returnVal;
+
+ if (invokeMethodData.RetType != null)
+ {
+ returnVal = DeterminePropertyInfo(invokeMethodData.RetType.Value, name: string.Empty);
+ }
+ else
+ {
+ returnVal = new PropertyInfo(VariantType.Nil, string.Empty, PropertyHint.None,
+ hintString: null, PropertyUsageFlags.Default, exported: false);
+ }
+
+ int paramCount = invokeMethodData.ParamTypes.Length;
+
+ List<PropertyInfo>? arguments;
+
+ if (paramCount > 0)
+ {
+ arguments = new(capacity: paramCount);
+
+ for (int i = 0; i < paramCount; i++)
+ {
+ arguments.Add(DeterminePropertyInfo(invokeMethodData.ParamTypes[i],
+ name: invokeMethodData.Method.Parameters[i].Name));
+ }
+ }
+ else
+ {
+ arguments = null;
+ }
+
+ return new MethodInfo(signalDelegateData.Name, returnVal, MethodFlags.Default, arguments,
+ defaultArguments: null);
+ }
+
+ private static PropertyInfo DeterminePropertyInfo(MarshalType marshalType, string name)
+ {
+ var memberVariantType = MarshalUtils.ConvertMarshalTypeToVariantType(marshalType)!.Value;
+
+ var propUsage = PropertyUsageFlags.Default;
+
+ if (memberVariantType == VariantType.Nil)
+ propUsage |= PropertyUsageFlags.NilIsVariant;
+
+ return new PropertyInfo(memberVariantType, name,
+ PropertyHint.None, string.Empty, propUsage, exported: false);
+ }
+
+ private static void GenerateSignalEventInvoker(
+ GodotSignalDelegateData signal,
+ StringBuilder source
+ )
+ {
+ string signalName = signal.Name;
+ var invokeMethodData = signal.InvokeMethodData;
+
+ source.Append(" if (signal == GodotInternal.SignalName_");
+ source.Append(signalName);
+ source.Append(" && argCount == ");
+ source.Append(invokeMethodData.ParamTypes.Length);
+ source.Append(") {\n");
+ source.Append(" backing_");
+ source.Append(signalName);
+ source.Append("?.Invoke(");
+
+ for (int i = 0; i < invokeMethodData.ParamTypes.Length; i++)
+ {
+ if (i != 0)
+ source.Append(", ");
+
+ source.AppendNativeVariantToManagedExpr(string.Concat("args[", i.ToString(), "]"),
+ invokeMethodData.ParamTypeSymbols[i], invokeMethodData.ParamTypes[i]);
+ }
+
+ source.Append(");\n");
+
+ source.Append(" return;\n");
+
+ source.Append(" }\n");
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs
index 2bf1cb7a18..01aa65bfc3 100644
--- a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotBuildLogger.cs
@@ -7,8 +7,6 @@ namespace GodotTools.BuildLogger
{
public class GodotBuildLogger : ILogger
{
- public static readonly string AssemblyPath = Path.GetFullPath(typeof(GodotBuildLogger).Assembly.Location);
-
public string Parameters { get; set; }
public LoggerVerbosity Verbosity { get; set; }
diff --git a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj
index 0afec970c6..9e36497b06 100644
--- a/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools.BuildLogger/GodotTools.BuildLogger.csproj
@@ -5,6 +5,6 @@
<LangVersion>7.2</LangVersion>
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.Build.Framework" Version="16.5.0" />
+ <PackageReference Include="Microsoft.Build.Framework" Version="15.1.548" ExcludeAssets="runtime" />
</ItemGroup>
</Project>
diff --git a/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj b/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj
index d6d8962f90..cfd5c88a58 100644
--- a/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools.Core/GodotTools.Core.csproj
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ProjectGuid>{639E48BD-44E5-4091-8EDD-22D36DC0768D}</ProjectGuid>
- <TargetFramework>netstandard2.0</TargetFramework>
- <LangVersion>7.2</LangVersion>
+ <TargetFramework>net6.0</TargetFramework>
+ <LangVersion>10</LangVersion>
</PropertyGroup>
</Project>
diff --git a/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs b/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs
index 60a4f297c9..7c5502814f 100644
--- a/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.Core/StringExtensions.cs
@@ -34,7 +34,7 @@ namespace GodotTools.Core
path = path.Replace('\\', '/');
path = path[path.Length - 1] == '/' ? path.Substring(0, path.Length - 1) : path;
- string[] parts = path.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries);
+ string[] parts = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
path = string.Join(Path.DirectorySeparatorChar.ToString(), parts).Trim();
@@ -60,7 +60,7 @@ namespace GodotTools.Core
public static string ToSafeDirName(this string dirName, bool allowDirSeparator = false)
{
- var invalidChars = new List<string> {":", "*", "?", "\"", "<", ">", "|"};
+ var invalidChars = new List<string> { ":", "*", "?", "\"", "<", ">", "|" };
if (allowDirSeparator)
{
diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj
index 303ca3a293..d2132115f3 100644
--- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ProjectGuid>{B06C2951-C8E3-4F28-80B2-717CF327EB19}</ProjectGuid>
<OutputType>Exe</OutputType>
diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs
index bc09e1ebf9..72e2a1fc0d 100644
--- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs
@@ -123,12 +123,16 @@ namespace GodotTools.IdeMessaging
string projectMetadataDir = Path.Combine(godotProjectDir, ".godot", "mono", "metadata");
// FileSystemWatcher requires an existing directory
- if (!Directory.Exists(projectMetadataDir)) {
+ if (!Directory.Exists(projectMetadataDir))
+ {
// Check if the non hidden version exists
string nonHiddenProjectMetadataDir = Path.Combine(godotProjectDir, "godot", "mono", "metadata");
- if (Directory.Exists(nonHiddenProjectMetadataDir)) {
+ if (Directory.Exists(nonHiddenProjectMetadataDir))
+ {
projectMetadataDir = nonHiddenProjectMetadataDir;
- } else {
+ }
+ else
+ {
Directory.CreateDirectory(projectMetadataDir);
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotIdeMetadata.cs b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotIdeMetadata.cs
index 686202e81e..2448a2953b 100644
--- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotIdeMetadata.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotIdeMetadata.cs
@@ -25,10 +25,7 @@ namespace GodotTools.IdeMessaging
public override bool Equals(object obj)
{
- if (obj is GodotIdeMetadata metadata)
- return metadata == this;
-
- return false;
+ return obj is GodotIdeMetadata metadata && metadata == this;
}
public bool Equals(GodotIdeMetadata other)
diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Peer.cs b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Peer.cs
index 10d7e1898e..dd3913b4f3 100644
--- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Peer.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Peer.cs
@@ -78,7 +78,7 @@ namespace GodotTools.IdeMessaging
clientStream.WriteTimeout = ClientWriteTimeout;
clientReader = new StreamReader(clientStream, Encoding.UTF8);
- clientWriter = new StreamWriter(clientStream, Encoding.UTF8) {NewLine = "\n"};
+ clientWriter = new StreamWriter(clientStream, Encoding.UTF8) { NewLine = "\n" };
}
public async Task Process()
diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/ResponseAwaiter.cs b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/ResponseAwaiter.cs
index 548e7f06ee..a57c82b608 100644
--- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/ResponseAwaiter.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/ResponseAwaiter.cs
@@ -17,7 +17,7 @@ namespace GodotTools.IdeMessaging
if (content.Status == MessageStatus.Ok)
SetResult(JsonConvert.DeserializeObject<T>(content.Body));
else
- SetResult(new T {Status = content.Status});
+ SetResult(new T { Status = content.Status });
}
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Utils/NotifyAwaiter.cs b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Utils/NotifyAwaiter.cs
index d84a63c83c..a285d5fa97 100644
--- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Utils/NotifyAwaiter.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Utils/NotifyAwaiter.cs
@@ -21,14 +21,14 @@ namespace GodotTools.IdeMessaging.Utils
public void OnCompleted(Action continuation)
{
if (this.continuation != null)
- throw new InvalidOperationException("This awaiter has already been listened");
+ throw new InvalidOperationException("This awaiter already has a continuation.");
this.continuation = continuation;
}
public void SetResult(T result)
{
if (IsCompleted)
- throw new InvalidOperationException("This awaiter is already completed");
+ throw new InvalidOperationException("This awaiter is already completed.");
IsCompleted = true;
this.result = result;
@@ -39,7 +39,7 @@ namespace GodotTools.IdeMessaging.Utils
public void SetException(Exception exception)
{
if (IsCompleted)
- throw new InvalidOperationException("This awaiter is already completed");
+ throw new InvalidOperationException("This awaiter is already completed.");
IsCompleted = true;
this.exception = exception;
diff --git a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj
index 5b3ed0b1b7..c05096bdcc 100644
--- a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/GodotTools.OpenVisualStudio.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ProjectGuid>{EAFFF236-FA96-4A4D-BD23-0E51EF988277}</ProjectGuid>
<OutputType>Exe</OutputType>
diff --git a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs
index 7a4641dbbc..cc0deb6cc0 100644
--- a/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.OpenVisualStudio/Program.cs
@@ -249,8 +249,8 @@ namespace GodotTools.OpenVisualStudio
// Thread call was rejected, so try again.
int IOleMessageFilter.RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType)
{
+ // flag = SERVERCALL_RETRYLATER
if (dwRejectType == 2)
- // flag = SERVERCALL_RETRYLATER
{
// Retry the thread call immediately if return >= 0 & < 100
return 99;
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj
index 37123ba2b2..bde14b2b40 100644
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/GodotTools.ProjectEditor.csproj
@@ -1,32 +1,16 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ProjectGuid>{A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}</ProjectGuid>
- <TargetFramework>net472</TargetFramework>
- <LangVersion>7.2</LangVersion>
+ <TargetFramework>net6.0</TargetFramework>
+ <LangVersion>10</LangVersion>
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="Microsoft.Build" Version="16.5.0" />
+ <PackageReference Include="Microsoft.Build" Version="15.1.548" ExcludeAssets="runtime" />
+ <PackageReference Include="Microsoft.Build.Locator" Version="1.2.6" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\GodotTools.Core\GodotTools.Core.csproj" />
<ProjectReference Include="..\GodotTools.Shared\GodotTools.Shared.csproj" />
</ItemGroup>
- <!--
- The Microsoft.Build.Runtime package is too problematic so we create a MSBuild.exe stub. The workaround described
- here doesn't work with Microsoft.NETFramework.ReferenceAssemblies: https://github.com/microsoft/msbuild/issues/3486
- We need a MSBuild.exe file as there's an issue in Microsoft.Build where it executes platform dependent code when
- searching for MSBuild.exe before the fallback to not using it. A stub is fine as it should never be executed.
- -->
- <ItemGroup>
- <None Include="MSBuild.exe" CopyToOutputDirectory="Always" />
- </ItemGroup>
- <Target Name="CopyMSBuildStubWindows" AfterTargets="Build" Condition=" '$(GodotPlatform)' == 'windows' Or ( '$(GodotPlatform)' == '' And '$(OS)' == 'Windows_NT' ) ">
- <PropertyGroup>
- <GodotSourceRootPath>$(SolutionDir)/../../../../</GodotSourceRootPath>
- <GodotOutputDataDir>$(GodotSourceRootPath)/bin/GodotSharp</GodotOutputDataDir>
- </PropertyGroup>
- <!-- Need to copy it here as well on Windows -->
- <Copy SourceFiles="MSBuild.exe" DestinationFiles="$(GodotOutputDataDir)\Mono\lib\mono\v4.0\MSBuild.exe" />
- </Target>
</Project>
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/MSBuild.exe b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/MSBuild.exe
deleted file mode 100644
index e69de29bb2..0000000000
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/MSBuild.exe
+++ /dev/null
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
index 7d49d251dd..f3c8e89dff 100644
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectGenerator.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
using System.IO;
using System.Text;
using Microsoft.Build.Construction;
@@ -14,14 +15,15 @@ namespace GodotTools.ProjectEditor
public static ProjectRootElement GenGameProject(string name)
{
if (name.Length == 0)
- throw new ArgumentException("Project name is empty", nameof(name));
+ throw new ArgumentException("Project name is empty.", nameof(name));
var root = ProjectRootElement.Create(NewProjectFileOptions.None);
root.Sdk = GodotSdkAttrValue;
var mainGroup = root.AddPropertyGroup();
- mainGroup.AddProperty("TargetFramework", "netstandard2.1");
+ mainGroup.AddProperty("TargetFramework", "net6.0");
+ mainGroup.AddProperty("EnableDynamicLoading", "true");
string sanitizedName = IdentifierUtils.SanitizeQualifiedIdentifier(name, allowEmptyIdentifiers: true);
@@ -35,7 +37,7 @@ namespace GodotTools.ProjectEditor
public static string GenAndSaveGameProject(string dir, string name)
{
if (name.Length == 0)
- throw new ArgumentException("Project name is empty", nameof(name));
+ throw new ArgumentException("Project name is empty.", nameof(name));
string path = Path.Combine(dir, name + ".csproj");
@@ -44,7 +46,7 @@ namespace GodotTools.ProjectEditor
// Save (without BOM)
root.Save(path, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
- return Guid.NewGuid().ToString().ToUpper();
+ return Guid.NewGuid().ToString().ToUpperInvariant();
}
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs
index cdac9acb25..7b1d5c228a 100644
--- a/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.ProjectEditor/ProjectUtils.cs
@@ -19,6 +19,16 @@ namespace GodotTools.ProjectEditor
public static class ProjectUtils
{
+ public static void MSBuildLocatorRegisterDefaults(out Version version, out string path)
+ {
+ var instance = Microsoft.Build.Locator.MSBuildLocator.RegisterDefaults();
+ version = instance.Version;
+ path = instance.MSBuildPath;
+ }
+
+ public static void MSBuildLocatorRegisterMSBuildPath(string msbuildPath)
+ => Microsoft.Build.Locator.MSBuildLocator.RegisterMSBuildPath(msbuildPath);
+
public static MSBuildProject Open(string path)
{
var root = ProjectRootElement.Open(path);
@@ -42,7 +52,8 @@ namespace GodotTools.ProjectEditor
var root = project.Root;
string godotSdkAttrValue = ProjectGenerator.GodotSdkAttrValue;
- if (!string.IsNullOrEmpty(root.Sdk) && root.Sdk.Trim().Equals(godotSdkAttrValue, StringComparison.OrdinalIgnoreCase))
+ if (!string.IsNullOrEmpty(root.Sdk) &&
+ root.Sdk.Trim().Equals(godotSdkAttrValue, StringComparison.OrdinalIgnoreCase))
return;
root.Sdk = godotSdkAttrValue;
diff --git a/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets b/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets
index aab2d73bdd..4baae77b34 100644
--- a/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets
+++ b/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets
@@ -8,8 +8,8 @@
</Target>
<Target Name="GenerateGodotNupkgsVersionsFile"
- DependsOnTargets="PrepareForBuild;_GenerateGodotNupkgsVersionsFile"
- BeforeTargets="BeforeCompile;CoreCompile">
+ DependsOnTargets="_GenerateGodotNupkgsVersionsFile"
+ BeforeTargets="PrepareForBuild;CompileDesignTime;BeforeCompile;CoreCompile">
<ItemGroup>
<Compile Include="$(GeneratedGodotNupkgsVersionsFile)" />
<FileWrites Include="$(GeneratedGodotNupkgsVersionsFile)" />
diff --git a/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj b/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj
index 3bc1698c15..d60e6343ea 100644
--- a/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools.Shared/GodotTools.Shared.csproj
@@ -1,6 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
- <TargetFramework>netstandard2.0</TargetFramework>
+ <TargetFramework>net6.0</TargetFramework>
+ <!-- Specify compile items manually to avoid including dangling generated items. -->
+ <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
</PropertyGroup>
<Import Project="GenerateGodotNupkgsVersions.targets" />
</Project>
diff --git a/modules/mono/editor/GodotTools/GodotTools.sln b/modules/mono/editor/GodotTools/GodotTools.sln
index d3107a69db..564775635d 100644
--- a/modules/mono/editor/GodotTools/GodotTools.sln
+++ b/modules/mono/editor/GodotTools/GodotTools.sln
@@ -1,4 +1,4 @@
-
+
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotTools.ProjectEditor", "GodotTools.ProjectEditor\GodotTools.ProjectEditor.csproj", "{A8CDAD94-C6D4-4B19-A7E7-76C53CC92984}"
@@ -15,6 +15,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotTools.OpenVisualStudio
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotTools.Shared", "GodotTools.Shared\GodotTools.Shared.csproj", "{2758FFAF-8237-4CF2-B569-66BF8B3587BB}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot.SourceGenerators", "..\Godot.NET.Sdk\Godot.SourceGenerators\Godot.SourceGenerators.csproj", "{D8C421B2-8911-41EB-B983-F675C7141EB7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot.SourceGenerators.Internal", "..\..\glue\GodotSharp\Godot.SourceGenerators.Internal\Godot.SourceGenerators.Internal.csproj", "{55666071-BEC1-4A52-8A98-9A4A7A947DBF}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -49,5 +53,13 @@ Global
{2758FFAF-8237-4CF2-B569-66BF8B3587BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2758FFAF-8237-4CF2-B569-66BF8B3587BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2758FFAF-8237-4CF2-B569-66BF8B3587BB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D8C421B2-8911-41EB-B983-F675C7141EB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D8C421B2-8911-41EB-B983-F675C7141EB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D8C421B2-8911-41EB-B983-F675C7141EB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D8C421B2-8911-41EB-B983-F675C7141EB7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {55666071-BEC1-4A52-8A98-9A4A7A947DBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {55666071-BEC1-4A52-8A98-9A4A7A947DBF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {55666071-BEC1-4A52-8A98-9A4A7A947DBF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {55666071-BEC1-4A52-8A98-9A4A7A947DBF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs
index 28bf57dc21..edbf53a389 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs
@@ -4,28 +4,36 @@ using Godot.Collections;
using GodotTools.Internals;
using Path = System.IO.Path;
+#nullable enable
+
namespace GodotTools.Build
{
[Serializable]
- public sealed class BuildInfo : RefCounted // TODO Remove RefCounted once we have proper serialization
+ public sealed partial class BuildInfo : RefCounted // TODO Remove RefCounted once we have proper serialization
{
- public string Solution { get; }
- public string[] Targets { get; }
- public string Configuration { get; }
- public bool Restore { get; }
+ public string Solution { get; private set; }
+ public string Configuration { get; private set; }
+ public string? RuntimeIdentifier { get; private set; }
+ public string? PublishOutputDir { get; private set; }
+ public bool Restore { get; private set; }
+ public bool Rebuild { get; private set; }
+ public bool OnlyClean { get; private set; }
+
// TODO Use List once we have proper serialization
- public Array<string> CustomProperties { get; } = new Array<string>();
+ public Godot.Collections.Array CustomProperties { get; private set; } = new();
- public string LogsDirPath => Path.Combine(GodotSharpDirs.BuildLogsDirs, $"{Solution.MD5Text()}_{Configuration}");
+ public string LogsDirPath =>
+ Path.Combine(GodotSharpDirs.BuildLogsDirs, $"{Solution.MD5Text()}_{Configuration}");
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
- if (obj is BuildInfo other)
- return other.Solution == Solution && other.Targets == Targets &&
- other.Configuration == Configuration && other.Restore == Restore &&
- other.CustomProperties == CustomProperties && other.LogsDirPath == LogsDirPath;
-
- return false;
+ return obj is BuildInfo other &&
+ other.Solution == Solution &&
+ other.Configuration == Configuration && other.RuntimeIdentifier == RuntimeIdentifier &&
+ other.PublishOutputDir == PublishOutputDir && other.Restore == Restore &&
+ other.Rebuild == Rebuild && other.OnlyClean == OnlyClean &&
+ other.CustomProperties == CustomProperties &&
+ other.LogsDirPath == LogsDirPath;
}
public override int GetHashCode()
@@ -34,25 +42,44 @@ namespace GodotTools.Build
{
int hash = 17;
hash = (hash * 29) + Solution.GetHashCode();
- hash = (hash * 29) + Targets.GetHashCode();
hash = (hash * 29) + Configuration.GetHashCode();
+ hash = (hash * 29) + (RuntimeIdentifier?.GetHashCode() ?? 0);
+ hash = (hash * 29) + (PublishOutputDir?.GetHashCode() ?? 0);
hash = (hash * 29) + Restore.GetHashCode();
+ hash = (hash * 29) + Rebuild.GetHashCode();
+ hash = (hash * 29) + OnlyClean.GetHashCode();
hash = (hash * 29) + CustomProperties.GetHashCode();
hash = (hash * 29) + LogsDirPath.GetHashCode();
return hash;
}
}
+ // Needed for instantiation from Godot, after reloading assemblies
private BuildInfo()
{
+ Solution = string.Empty;
+ Configuration = string.Empty;
+ }
+
+ public BuildInfo(string solution, string configuration, bool restore, bool rebuild, bool onlyClean)
+ {
+ Solution = solution;
+ Configuration = configuration;
+ Restore = restore;
+ Rebuild = rebuild;
+ OnlyClean = onlyClean;
}
- public BuildInfo(string solution, string[] targets, string configuration, bool restore)
+ public BuildInfo(string solution, string configuration, string runtimeIdentifier,
+ string publishOutputDir, bool restore, bool rebuild, bool onlyClean)
{
Solution = solution;
- Targets = targets;
Configuration = configuration;
+ RuntimeIdentifier = runtimeIdentifier;
+ PublishOutputDir = publishOutputDir;
Restore = restore;
+ Rebuild = rebuild;
+ OnlyClean = onlyClean;
}
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs
index 21bff70b15..993c6d9217 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildManager.cs
@@ -1,12 +1,10 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Threading.Tasks;
-using GodotTools.Ides.Rider;
+using Godot;
using GodotTools.Internals;
-using JetBrains.Annotations;
-using static GodotTools.Internals.Globals;
using File = GodotTools.Utils.File;
-using OS = GodotTools.Utils.OS;
namespace GodotTools.Build
{
@@ -14,13 +12,8 @@ namespace GodotTools.Build
{
private static BuildInfo _buildInProgress;
- public const string PropNameMSBuildMono = "MSBuild (Mono)";
- public const string PropNameMSBuildVs = "MSBuild (VS Build Tools)";
- public const string PropNameMSBuildJetBrains = "MSBuild (JetBrains Rider)";
- public const string PropNameDotnetCli = "dotnet CLI";
-
public const string MsBuildIssuesFileName = "msbuild_issues.csv";
- public const string MsBuildLogFileName = "msbuild_log.txt";
+ private const string MsBuildLogFileName = "msbuild_log.txt";
public delegate void BuildLaunchFailedEventHandler(BuildInfo buildInfo, string reason);
@@ -62,14 +55,14 @@ namespace GodotTools.Build
private static void PrintVerbose(string text)
{
- if (Godot.OS.IsStdoutVerbose())
- Godot.GD.Print(text);
+ if (OS.IsStdoutVerbose())
+ GD.Print(text);
}
- public static bool Build(BuildInfo buildInfo)
+ private static bool Build(BuildInfo buildInfo)
{
if (_buildInProgress != null)
- throw new InvalidOperationException("A build is already in progress");
+ throw new InvalidOperationException("A build is already in progress.");
_buildInProgress = buildInfo;
@@ -103,7 +96,8 @@ namespace GodotTools.Build
}
catch (Exception e)
{
- BuildLaunchFailed?.Invoke(buildInfo, $"The build method threw an exception.\n{e.GetType().FullName}: {e.Message}");
+ BuildLaunchFailed?.Invoke(buildInfo,
+ $"The build method threw an exception.\n{e.GetType().FullName}: {e.Message}");
Console.Error.WriteLine(e);
return false;
}
@@ -117,7 +111,7 @@ namespace GodotTools.Build
public static async Task<bool> BuildAsync(BuildInfo buildInfo)
{
if (_buildInProgress != null)
- throw new InvalidOperationException("A build is already in progress");
+ throw new InvalidOperationException("A build is already in progress.");
_buildInProgress = buildInfo;
@@ -148,7 +142,8 @@ namespace GodotTools.Build
}
catch (Exception e)
{
- BuildLaunchFailed?.Invoke(buildInfo, $"The build method threw an exception.\n{e.GetType().FullName}: {e.Message}");
+ BuildLaunchFailed?.Invoke(buildInfo,
+ $"The build method threw an exception.\n{e.GetType().FullName}: {e.Message}");
Console.Error.WriteLine(e);
return false;
}
@@ -159,18 +154,54 @@ namespace GodotTools.Build
}
}
- public static bool BuildProjectBlocking(string config, [CanBeNull] string[] targets = null, [CanBeNull] string platform = null)
+ private static bool Publish(BuildInfo buildInfo)
{
- var buildInfo = new BuildInfo(GodotSharpDirs.ProjectSlnPath, targets ?? new[] {"Build"}, config, restore: true);
+ if (_buildInProgress != null)
+ throw new InvalidOperationException("A build is already in progress.");
- // If a platform was not specified, try determining the current one. If that fails, let MSBuild auto-detect it.
- if (platform != null || OS.PlatformNameMap.TryGetValue(Godot.OS.GetName(), out platform))
- buildInfo.CustomProperties.Add($"GodotTargetPlatform={platform}");
+ _buildInProgress = buildInfo;
- if (Internal.GodotIsRealTDouble())
- buildInfo.CustomProperties.Add("GodotRealTIsDouble=true");
+ try
+ {
+ BuildStarted?.Invoke(buildInfo);
+
+ // Required in order to update the build tasks list
+ Internal.GodotMainIteration();
- return BuildProjectBlocking(buildInfo);
+ try
+ {
+ RemoveOldIssuesFile(buildInfo);
+ }
+ catch (IOException e)
+ {
+ BuildLaunchFailed?.Invoke(buildInfo, $"Cannot remove issues file: {GetIssuesFilePath(buildInfo)}");
+ Console.Error.WriteLine(e);
+ }
+
+ try
+ {
+ int exitCode = BuildSystem.Publish(buildInfo, StdOutputReceived, StdErrorReceived);
+
+ if (exitCode != 0)
+ PrintVerbose(
+ $"dotnet publish exited with code: {exitCode}. Log file: {GetLogFilePath(buildInfo)}");
+
+ BuildFinished?.Invoke(exitCode == 0 ? BuildResult.Success : BuildResult.Error);
+
+ return exitCode == 0;
+ }
+ catch (Exception e)
+ {
+ BuildLaunchFailed?.Invoke(buildInfo,
+ $"The publish method threw an exception.\n{e.GetType().FullName}: {e.Message}");
+ Console.Error.WriteLine(e);
+ return false;
+ }
+ }
+ finally
+ {
+ _buildInProgress = null;
+ }
}
private static bool BuildProjectBlocking(BuildInfo buildInfo)
@@ -178,31 +209,109 @@ namespace GodotTools.Build
if (!File.Exists(buildInfo.Solution))
return true; // No solution to build
- // Make sure the API assemblies are up to date before building the project.
- // We may not have had the chance to update the release API assemblies, and the debug ones
- // may have been deleted by the user at some point after they were loaded by the Godot editor.
- string apiAssembliesUpdateError = Internal.UpdateApiAssembliesFromPrebuilt(buildInfo.Configuration == "ExportRelease" ? "Release" : "Debug");
+ using var pr = new EditorProgress("dotnet_build_project", "Building .NET project...", 1);
+
+ pr.Step("Building project solution", 0);
- if (!string.IsNullOrEmpty(apiAssembliesUpdateError))
+ if (!Build(buildInfo))
{
- ShowBuildErrorDialog("Failed to update the Godot API assemblies");
+ ShowBuildErrorDialog("Failed to build project solution");
return false;
}
- using (var pr = new EditorProgress("mono_project_debug_build", "Building project solution...", 1))
+ return true;
+ }
+
+ private static bool CleanProjectBlocking(BuildInfo buildInfo)
+ {
+ if (!File.Exists(buildInfo.Solution))
+ return true; // No solution to clean
+
+ using var pr = new EditorProgress("dotnet_clean_project", "Cleaning .NET project...", 1);
+
+ pr.Step("Cleaning project solution", 0);
+
+ if (!Build(buildInfo))
{
- pr.Step("Building project solution", 0);
+ ShowBuildErrorDialog("Failed to clean project solution");
+ return false;
+ }
- if (!Build(buildInfo))
- {
- ShowBuildErrorDialog("Failed to build project solution");
- return false;
- }
+ return true;
+ }
+
+ private static bool PublishProjectBlocking(BuildInfo buildInfo)
+ {
+ using var pr = new EditorProgress("dotnet_publish_project", "Publishing .NET project...", 1);
+
+ pr.Step("Running dotnet publish", 0);
+
+ if (!Publish(buildInfo))
+ {
+ ShowBuildErrorDialog("Failed to publish .NET project");
+ return false;
}
return true;
}
+ private static BuildInfo CreateBuildInfo(
+ [DisallowNull] string configuration,
+ [AllowNull] string platform = null,
+ bool rebuild = false,
+ bool onlyClean = false
+ )
+ {
+ var buildInfo = new BuildInfo(GodotSharpDirs.ProjectSlnPath, configuration,
+ restore: true, rebuild, onlyClean);
+
+ // If a platform was not specified, try determining the current one. If that fails, let MSBuild auto-detect it.
+ if (platform != null || Utils.OS.PlatformNameMap.TryGetValue(OS.GetName(), out platform))
+ buildInfo.CustomProperties.Add($"GodotTargetPlatform={platform}");
+
+ if (Internal.GodotIsRealTDouble())
+ buildInfo.CustomProperties.Add("GodotRealTIsDouble=true");
+
+ return buildInfo;
+ }
+
+ private static BuildInfo CreatePublishBuildInfo(
+ [DisallowNull] string configuration,
+ [DisallowNull] string platform,
+ [DisallowNull] string runtimeIdentifier,
+ [DisallowNull] string publishOutputDir
+ )
+ {
+ var buildInfo = new BuildInfo(GodotSharpDirs.ProjectSlnPath, configuration,
+ runtimeIdentifier, publishOutputDir, restore: true, rebuild: false, onlyClean: false);
+
+ buildInfo.CustomProperties.Add($"GodotTargetPlatform={platform}");
+
+ if (Internal.GodotIsRealTDouble())
+ buildInfo.CustomProperties.Add("GodotRealTIsDouble=true");
+
+ return buildInfo;
+ }
+
+ public static bool BuildProjectBlocking(
+ [DisallowNull] string configuration,
+ [AllowNull] string platform = null,
+ bool rebuild = false
+ ) => BuildProjectBlocking(CreateBuildInfo(configuration, platform, rebuild));
+
+ public static bool CleanProjectBlocking(
+ [DisallowNull] string configuration,
+ [AllowNull] string platform = null
+ ) => CleanProjectBlocking(CreateBuildInfo(configuration, platform, rebuild: false));
+
+ public static bool PublishProjectBlocking(
+ [DisallowNull] string configuration,
+ [DisallowNull] string platform,
+ [DisallowNull] string runtimeIdentifier,
+ string publishOutputDir
+ ) => PublishProjectBlocking(CreatePublishBuildInfo(configuration,
+ platform, runtimeIdentifier, publishOutputDir));
+
public static bool EditorBuildCallback()
{
if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
@@ -215,7 +324,7 @@ namespace GodotTools.Build
}
catch (Exception e)
{
- Godot.GD.PushError("Failed to setup Godot NuGet Offline Packages: " + e.Message);
+ GD.PushError("Failed to setup Godot NuGet Offline Packages: " + e.Message);
}
if (GodotSharpEditor.Instance.SkipBuildBeforePlaying)
@@ -226,47 +335,6 @@ namespace GodotTools.Build
public static void Initialize()
{
- // Build tool settings
- var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
-
- BuildTool msbuildDefault;
-
- if (OS.IsWindows)
- {
- if (RiderPathManager.IsExternalEditorSetToRider(editorSettings))
- msbuildDefault = BuildTool.JetBrainsMsBuild;
- else
- msbuildDefault = !string.IsNullOrEmpty(OS.PathWhich("dotnet")) ? BuildTool.DotnetCli : BuildTool.MsBuildVs;
- }
- else
- {
- msbuildDefault = !string.IsNullOrEmpty(OS.PathWhich("dotnet")) ? BuildTool.DotnetCli : BuildTool.MsBuildMono;
- }
-
- EditorDef("mono/builds/build_tool", msbuildDefault);
-
- string hintString;
-
- if (OS.IsWindows)
- {
- hintString = $"{PropNameMSBuildMono}:{(int)BuildTool.MsBuildMono}," +
- $"{PropNameMSBuildVs}:{(int)BuildTool.MsBuildVs}," +
- $"{PropNameMSBuildJetBrains}:{(int)BuildTool.JetBrainsMsBuild}," +
- $"{PropNameDotnetCli}:{(int)BuildTool.DotnetCli}";
- }
- else
- {
- hintString = $"{PropNameMSBuildMono}:{(int)BuildTool.MsBuildMono}," +
- $"{PropNameDotnetCli}:{(int)BuildTool.DotnetCli}";
- }
-
- editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary
- {
- ["type"] = Godot.Variant.Type.Int,
- ["name"] = "mono/builds/build_tool",
- ["hint"] = Godot.PropertyHint.Enum,
- ["hint_string"] = hintString
- });
}
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
index ebdaca0ce8..180cc3cf14 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
@@ -1,17 +1,16 @@
using Godot;
using System;
-using Godot.Collections;
+using System.Diagnostics.CodeAnalysis;
using GodotTools.Internals;
-using JetBrains.Annotations;
using File = GodotTools.Utils.File;
using Path = System.IO.Path;
namespace GodotTools.Build
{
- public class BuildOutputView : VBoxContainer, ISerializationListener
+ public partial class BuildOutputView : VBoxContainer, ISerializationListener
{
[Serializable]
- private class BuildIssue : RefCounted // TODO Remove RefCounted once we have proper serialization
+ private partial class BuildIssue : RefCounted // TODO Remove RefCounted once we have proper serialization
{
public bool Warning { get; set; }
public string File { get; set; }
@@ -22,7 +21,8 @@ namespace GodotTools.Build
public string ProjectFile { get; set; }
}
- [Signal] public event Action BuildStateChanged;
+ [Signal]
+ public delegate void BuildStateChangedEventHandler();
public bool HasBuildExited { get; private set; } = false;
@@ -58,7 +58,7 @@ namespace GodotTools.Build
}
// TODO Use List once we have proper serialization.
- private readonly Array<BuildIssue> _issues = new Array<BuildIssue>();
+ private Godot.Collections.Array<BuildIssue> _issues = new();
private ItemList _issuesList;
private PopupMenu _issuesListContextMenu;
private TextEdit _buildLog;
@@ -120,20 +120,22 @@ namespace GodotTools.Build
private void IssueActivated(int idx)
{
if (idx < 0 || idx >= _issuesList.ItemCount)
- throw new IndexOutOfRangeException("Item list index out of range");
+ throw new ArgumentOutOfRangeException(nameof(idx), "Item list index out of range.");
// Get correct issue idx from issue list
- int issueIndex = (int)(long)_issuesList.GetItemMetadata(idx);
+ int issueIndex = (int)_issuesList.GetItemMetadata(idx);
if (issueIndex < 0 || issueIndex >= _issues.Count)
- throw new IndexOutOfRangeException("Issue index out of range");
+ throw new InvalidOperationException("Issue index out of range.");
BuildIssue issue = _issues[issueIndex];
if (string.IsNullOrEmpty(issue.ProjectFile) && string.IsNullOrEmpty(issue.File))
return;
- string projectDir = issue.ProjectFile.Length > 0 ? issue.ProjectFile.GetBaseDir() : _buildInfo.Solution.GetBaseDir();
+ string projectDir = !string.IsNullOrEmpty(issue.ProjectFile) ?
+ issue.ProjectFile.GetBaseDir() :
+ _buildInfo.Solution.GetBaseDir();
string file = Path.Combine(projectDir.SimplifyGodotPath(), issue.File.SimplifyGodotPath());
@@ -291,7 +293,7 @@ namespace GodotTools.Build
public void RestartBuild()
{
if (!HasBuildExited)
- throw new InvalidOperationException("Build already started");
+ throw new InvalidOperationException("Build already started.");
BuildManager.RestartBuild(this);
}
@@ -299,7 +301,7 @@ namespace GodotTools.Build
public void StopBuild()
{
if (!HasBuildExited)
- throw new InvalidOperationException("Build is not in progress");
+ throw new InvalidOperationException("Build is not in progress.");
BuildManager.StopBuild(this);
}
@@ -412,6 +414,16 @@ namespace GodotTools.Build
{
// In case it didn't update yet. We don't want to have to serialize any pending output.
UpdateBuildLogText();
+
+ // NOTE:
+ // Currently, GodotTools is loaded in its own load context. This load context is not reloaded, but the script still are.
+ // Until that changes, we need workarounds like this one because events keep strong references to disposed objects.
+ BuildManager.BuildLaunchFailed -= BuildLaunchFailed;
+ BuildManager.BuildStarted -= BuildStarted;
+ BuildManager.BuildFinished -= BuildFinished;
+ // StdOutput/Error can be received from different threads, so we need to use CallDeferred
+ BuildManager.StdOutputReceived -= StdOutputReceived;
+ BuildManager.StdErrorReceived -= StdErrorReceived;
}
public void OnAfterDeserialize()
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
index 02e9d98647..d0cd529d1f 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
@@ -1,61 +1,93 @@
-using GodotTools.Core;
using System;
using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
+using System.Linq;
+using System.Text;
using System.Threading.Tasks;
using GodotTools.BuildLogger;
-using GodotTools.Internals;
using GodotTools.Utils;
-using Directory = System.IO.Directory;
namespace GodotTools.Build
{
public static class BuildSystem
{
- private static string MonoWindowsBinDir
+ private static Process LaunchBuild(BuildInfo buildInfo, Action<string> stdOutHandler,
+ Action<string> stdErrHandler)
{
- get
- {
- string monoWinBinDir = Path.Combine(Internal.MonoWindowsInstallRoot, "bin");
+ string dotnetPath = DotNetFinder.FindDotNetExe();
- if (!Directory.Exists(monoWinBinDir))
- throw new FileNotFoundException("Cannot find the Windows Mono install bin directory.");
+ if (dotnetPath == null)
+ throw new FileNotFoundException("Cannot find the dotnet executable.");
- return monoWinBinDir;
- }
+ var startInfo = new ProcessStartInfo(dotnetPath);
+
+ BuildArguments(buildInfo, startInfo.ArgumentList);
+
+ string launchMessage = startInfo.GetCommandLineDisplay(new StringBuilder("Running: ")).ToString();
+ stdOutHandler?.Invoke(launchMessage);
+ if (Godot.OS.IsStdoutVerbose())
+ Console.WriteLine(launchMessage);
+
+ startInfo.RedirectStandardOutput = true;
+ startInfo.RedirectStandardError = true;
+ startInfo.UseShellExecute = false;
+ startInfo.CreateNoWindow = true;
+
+ // Needed when running from Developer Command Prompt for VS
+ RemovePlatformVariable(startInfo.EnvironmentVariables);
+
+ var process = new Process { StartInfo = startInfo };
+
+ if (stdOutHandler != null)
+ process.OutputDataReceived += (_, e) => stdOutHandler.Invoke(e.Data);
+ if (stdErrHandler != null)
+ process.ErrorDataReceived += (_, e) => stdErrHandler.Invoke(e.Data);
+
+ process.Start();
+
+ process.BeginOutputReadLine();
+ process.BeginErrorReadLine();
+
+ return process;
}
- private static Godot.EditorSettings EditorSettings =>
- GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
+ public static int Build(BuildInfo buildInfo, Action<string> stdOutHandler, Action<string> stdErrHandler)
+ {
+ using (var process = LaunchBuild(buildInfo, stdOutHandler, stdErrHandler))
+ {
+ process.WaitForExit();
+
+ return process.ExitCode;
+ }
+ }
- private static bool UsingMonoMsBuildOnWindows
+ public static async Task<int> BuildAsync(BuildInfo buildInfo, Action<string> stdOutHandler,
+ Action<string> stdErrHandler)
{
- get
+ using (var process = LaunchBuild(buildInfo, stdOutHandler, stdErrHandler))
{
- if (OS.IsWindows)
- {
- return (BuildTool)EditorSettings.GetSetting("mono/builds/build_tool")
- == BuildTool.MsBuildMono;
- }
+ await process.WaitForExitAsync();
- return false;
+ return process.ExitCode;
}
}
- private static Process LaunchBuild(BuildInfo buildInfo, Action<string> stdOutHandler, Action<string> stdErrHandler)
+ private static Process LaunchPublish(BuildInfo buildInfo, Action<string> stdOutHandler,
+ Action<string> stdErrHandler)
{
- (string msbuildPath, BuildTool buildTool) = MsBuildFinder.FindMsBuild();
+ string dotnetPath = DotNetFinder.FindDotNetExe();
- if (msbuildPath == null)
- throw new FileNotFoundException("Cannot find the MSBuild executable.");
+ if (dotnetPath == null)
+ throw new FileNotFoundException("Cannot find the dotnet executable.");
- string compilerArgs = BuildArguments(buildTool, buildInfo);
+ var startInfo = new ProcessStartInfo(dotnetPath);
- var startInfo = new ProcessStartInfo(msbuildPath, compilerArgs);
+ BuildPublishArguments(buildInfo, startInfo.ArgumentList);
- string launchMessage = $"Running: \"{startInfo.FileName}\" {startInfo.Arguments}";
+ string launchMessage = startInfo.GetCommandLineDisplay(new StringBuilder("Running: ")).ToString();
stdOutHandler?.Invoke(launchMessage);
if (Godot.OS.IsStdoutVerbose())
Console.WriteLine(launchMessage);
@@ -63,27 +95,16 @@ namespace GodotTools.Build
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
- startInfo.CreateNoWindow = true;
-
- if (UsingMonoMsBuildOnWindows)
- {
- // These environment variables are required for Mono's MSBuild to find the compilers.
- // We use the batch files in Mono's bin directory to make sure the compilers are executed with mono.
- string monoWinBinDir = MonoWindowsBinDir;
- startInfo.EnvironmentVariables.Add("CscToolExe", Path.Combine(monoWinBinDir, "csc.bat"));
- startInfo.EnvironmentVariables.Add("VbcToolExe", Path.Combine(monoWinBinDir, "vbc.bat"));
- startInfo.EnvironmentVariables.Add("FscToolExe", Path.Combine(monoWinBinDir, "fsharpc.bat"));
- }
// Needed when running from Developer Command Prompt for VS
RemovePlatformVariable(startInfo.EnvironmentVariables);
- var process = new Process {StartInfo = startInfo};
+ var process = new Process { StartInfo = startInfo };
if (stdOutHandler != null)
- process.OutputDataReceived += (s, e) => stdOutHandler.Invoke(e.Data);
+ process.OutputDataReceived += (_, e) => stdOutHandler.Invoke(e.Data);
if (stdErrHandler != null)
- process.ErrorDataReceived += (s, e) => stdErrHandler.Invoke(e.Data);
+ process.ErrorDataReceived += (_, e) => stdErrHandler.Invoke(e.Data);
process.Start();
@@ -93,9 +114,9 @@ namespace GodotTools.Build
return process;
}
- public static int Build(BuildInfo buildInfo, Action<string> stdOutHandler, Action<string> stdErrHandler)
+ public static int Publish(BuildInfo buildInfo, Action<string> stdOutHandler, Action<string> stdErrHandler)
{
- using (var process = LaunchBuild(buildInfo, stdOutHandler, stdErrHandler))
+ using (var process = LaunchPublish(buildInfo, stdOutHandler, stdErrHandler))
{
process.WaitForExit();
@@ -103,38 +124,102 @@ namespace GodotTools.Build
}
}
- public static async Task<int> BuildAsync(BuildInfo buildInfo, Action<string> stdOutHandler, Action<string> stdErrHandler)
+ private static void BuildArguments(BuildInfo buildInfo, Collection<string> arguments)
{
- using (var process = LaunchBuild(buildInfo, stdOutHandler, stdErrHandler))
+ // `dotnet clean` / `dotnet build` commands
+ arguments.Add(buildInfo.OnlyClean ? "clean" : "build");
+
+ // Solution
+ arguments.Add(buildInfo.Solution);
+
+ // `dotnet clean` doesn't recognize these options
+ if (!buildInfo.OnlyClean)
{
- await process.WaitForExitAsync();
+ // Restore
+ // `dotnet build` restores by default, unless requested not to
+ if (!buildInfo.Restore)
+ arguments.Add("--no-restore");
+
+ // Incremental or rebuild
+ if (buildInfo.Rebuild)
+ arguments.Add("--no-incremental");
+ }
- return process.ExitCode;
+ // Configuration
+ arguments.Add("-c");
+ arguments.Add(buildInfo.Configuration);
+
+ // Verbosity
+ arguments.Add("-v");
+ arguments.Add("normal");
+
+ // Logger
+ AddLoggerArgument(buildInfo, arguments);
+
+ // Custom properties
+ foreach (var customProperty in buildInfo.CustomProperties)
+ {
+ arguments.Add("-p:" + (string)customProperty);
}
}
- private static string BuildArguments(BuildTool buildTool, BuildInfo buildInfo)
+ private static void BuildPublishArguments(BuildInfo buildInfo, Collection<string> arguments)
{
- string arguments = string.Empty;
+ arguments.Add("publish"); // `dotnet publish` command
+
+ // Solution
+ arguments.Add(buildInfo.Solution);
+
+ // Restore
+ // `dotnet publish` restores by default, unless requested not to
+ if (!buildInfo.Restore)
+ arguments.Add("--no-restore");
- if (buildTool == BuildTool.DotnetCli)
- arguments += "msbuild"; // `dotnet msbuild` command
+ // Incremental or rebuild
+ // TODO: Not supported in `dotnet publish` (https://github.com/dotnet/sdk/issues/11099)
+ // if (buildInfo.Rebuild)
+ // arguments.Add("--no-incremental");
- arguments += $@" ""{buildInfo.Solution}""";
+ // Configuration
+ arguments.Add("-c");
+ arguments.Add(buildInfo.Configuration);
- if (buildInfo.Restore)
- arguments += " /restore";
+ // Runtime Identifier
+ arguments.Add("-r");
+ arguments.Add(buildInfo.RuntimeIdentifier!);
- arguments += $@" /t:{string.Join(",", buildInfo.Targets)} " +
- $@"""/p:{"Configuration=" + buildInfo.Configuration}"" /v:normal " +
- $@"""/l:{typeof(GodotBuildLogger).FullName},{GodotBuildLogger.AssemblyPath};{buildInfo.LogsDirPath}""";
+ // Self-published
+ arguments.Add("--self-contained");
+ arguments.Add("true");
- foreach (string customProperty in buildInfo.CustomProperties)
+ // Verbosity
+ arguments.Add("-v");
+ arguments.Add("normal");
+
+ // Logger
+ AddLoggerArgument(buildInfo, arguments);
+
+ // Custom properties
+ foreach (var customProperty in buildInfo.CustomProperties)
+ {
+ arguments.Add("-p:" + (string)customProperty);
+ }
+
+ // Publish output directory
+ if (buildInfo.PublishOutputDir != null)
{
- arguments += " /p:" + customProperty;
+ arguments.Add("-o");
+ arguments.Add(buildInfo.PublishOutputDir);
}
+ }
+
+ private static void AddLoggerArgument(BuildInfo buildInfo, Collection<string> arguments)
+ {
+ string buildLoggerPath = Path.Combine(Internals.GodotSharpDirs.DataEditorToolsDir,
+ "GodotTools.BuildLogger.dll");
- return arguments;
+ arguments.Add(
+ $"-l:{typeof(GodotBuildLogger).FullName},{buildLoggerPath};{buildInfo.LogsDirPath}");
}
private static void RemovePlatformVariable(StringDictionary environmentVariables)
@@ -145,7 +230,7 @@ namespace GodotTools.Build
foreach (string env in environmentVariables.Keys)
{
- if (env.ToUpper() == "PLATFORM")
+ if (env.ToUpperInvariant() == "PLATFORM")
platformEnvironmentVariables.Add(env);
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildTool.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildTool.cs
deleted file mode 100644
index 837c8adddb..0000000000
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildTool.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace GodotTools.Build
-{
- public enum BuildTool : long
- {
- MsBuildMono,
- MsBuildVs,
- JetBrainsMsBuild,
- DotnetCli
- }
-}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/DotNetFinder.cs b/modules/mono/editor/GodotTools/GodotTools/Build/DotNetFinder.cs
new file mode 100644
index 0000000000..7bce53308c
--- /dev/null
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/DotNetFinder.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using JetBrains.Annotations;
+using OS = GodotTools.Utils.OS;
+
+namespace GodotTools.Build
+{
+ public static class DotNetFinder
+ {
+ [CanBeNull]
+ public static string FindDotNetExe()
+ {
+ // In the future, this method may do more than just search in PATH. We could look in
+ // known locations or use Godot's linked nethost to search from the hostfxr location.
+
+ return OS.PathWhich("dotnet");
+ }
+
+ public static bool TryFindDotNetSdk(
+ Version expectedVersion,
+ [NotNullWhen(true)] out Version version,
+ [NotNullWhen(true)] out string path
+ )
+ {
+ version = null;
+ path = null;
+
+ string dotNetExe = FindDotNetExe();
+
+ if (string.IsNullOrEmpty(dotNetExe))
+ return false;
+
+ using Process process = new Process();
+ process.StartInfo = new ProcessStartInfo(dotNetExe, "--list-sdks")
+ {
+ UseShellExecute = false,
+ RedirectStandardOutput = true
+ };
+
+ process.StartInfo.EnvironmentVariables["DOTNET_CLI_UI_LANGUAGE"] = "en-US";
+
+ var lines = new List<string>();
+
+ process.OutputDataReceived += (_, e) =>
+ {
+ if (!string.IsNullOrWhiteSpace(e.Data))
+ lines.Add(e.Data);
+ };
+
+ try
+ {
+ process.Start();
+ }
+ catch
+ {
+ return false;
+ }
+
+ process.BeginOutputReadLine();
+ process.WaitForExit();
+
+ Version latestVersionMatch = null;
+ string matchPath = null;
+
+ foreach (var line in lines)
+ {
+ string[] sdkLineParts = line.Trim()
+ .Split(' ', 2, StringSplitOptions.TrimEntries);
+
+ if (sdkLineParts.Length < 2)
+ continue;
+
+ if (!Version.TryParse(sdkLineParts[0], out var lineVersion))
+ continue;
+
+ // We're looking for the exact same major version
+ if (lineVersion.Major != expectedVersion.Major)
+ continue;
+
+ if (latestVersionMatch != null && lineVersion < latestVersionMatch)
+ continue;
+
+ latestVersionMatch = lineVersion;
+ matchPath = sdkLineParts[1].TrimStart('[').TrimEnd(']');
+ }
+
+ if (latestVersionMatch == null)
+ return false;
+
+ version = latestVersionMatch;
+ path = Path.Combine(matchPath!, version.ToString());
+
+ return true;
+ }
+ }
+}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
index 3c020a2589..d05995c495 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
@@ -1,13 +1,12 @@
using System;
using Godot;
using GodotTools.Internals;
-using JetBrains.Annotations;
using static GodotTools.Internals.Globals;
using File = GodotTools.Utils.File;
namespace GodotTools.Build
{
- public class MSBuildPanel : VBoxContainer
+ public partial class MSBuildPanel : VBoxContainer
{
public BuildOutputView BuildOutputView { get; private set; }
@@ -28,7 +27,6 @@ namespace GodotTools.Build
BuildOutputView.UpdateIssuesList();
}
- [UsedImplicitly]
public void BuildSolution()
{
if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
@@ -57,7 +55,6 @@ namespace GodotTools.Build
Internal.ReloadAssemblies(softReload: false);
}
- [UsedImplicitly]
private void RebuildSolution()
{
if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
@@ -73,7 +70,7 @@ namespace GodotTools.Build
GD.PushError("Failed to setup Godot NuGet Offline Packages: " + e.Message);
}
- if (!BuildManager.BuildProjectBlocking("Debug", targets: new[] { "Rebuild" }))
+ if (!BuildManager.BuildProjectBlocking("Debug", rebuild: true))
return; // Build failed
// Notify running game for hot-reload
@@ -86,13 +83,12 @@ namespace GodotTools.Build
Internal.ReloadAssemblies(softReload: false);
}
- [UsedImplicitly]
private void CleanSolution()
{
if (!File.Exists(GodotSharpDirs.ProjectSlnPath))
return; // No solution to build
- BuildManager.BuildProjectBlocking("Debug", targets: new[] { "Clean" });
+ _ = BuildManager.CleanProjectBlocking("Debug");
}
private void ViewLogToggled(bool pressed) => BuildOutputView.LogVisible = pressed;
@@ -143,7 +139,7 @@ namespace GodotTools.Build
_errorsBtn = new Button
{
- HintTooltip = "Show Errors".TTR(),
+ TooltipText = "Show Errors".TTR(),
Icon = GetThemeIcon("StatusError", "EditorIcons"),
ExpandIcon = false,
ToggleMode = true,
@@ -155,7 +151,7 @@ namespace GodotTools.Build
_warningsBtn = new Button
{
- HintTooltip = "Show Warnings".TTR(),
+ TooltipText = "Show Warnings".TTR(),
Icon = GetThemeIcon("NodeWarning", "EditorIcons"),
ExpandIcon = false,
ToggleMode = true,
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs
deleted file mode 100644
index a859c6f717..0000000000
--- a/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs
+++ /dev/null
@@ -1,233 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using Godot;
-using GodotTools.Ides.Rider;
-using GodotTools.Internals;
-using Directory = System.IO.Directory;
-using Environment = System.Environment;
-using File = System.IO.File;
-using Path = System.IO.Path;
-using OS = GodotTools.Utils.OS;
-
-namespace GodotTools.Build
-{
- public static class MsBuildFinder
- {
- private static string _msbuildToolsPath = string.Empty;
- private static string _msbuildUnixPath = string.Empty;
-
- public static (string, BuildTool) FindMsBuild()
- {
- var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
- var buildTool = (BuildTool)editorSettings.GetSetting("mono/builds/build_tool");
-
- if (OS.IsWindows)
- {
- switch (buildTool)
- {
- case BuildTool.DotnetCli:
- {
- string dotnetCliPath = OS.PathWhich("dotnet");
- if (!string.IsNullOrEmpty(dotnetCliPath))
- return (dotnetCliPath, BuildTool.DotnetCli);
- GD.PushError($"Cannot find executable for '{BuildManager.PropNameDotnetCli}'. Fallback to MSBuild from Visual Studio.");
- goto case BuildTool.MsBuildVs;
- }
- case BuildTool.MsBuildVs:
- {
- if (string.IsNullOrEmpty(_msbuildToolsPath) || !File.Exists(_msbuildToolsPath))
- {
- // Try to search it again if it wasn't found last time or if it was removed from its location
- _msbuildToolsPath = FindMsBuildToolsPathOnWindows();
-
- if (string.IsNullOrEmpty(_msbuildToolsPath))
- throw new FileNotFoundException($"Cannot find executable for '{BuildManager.PropNameMSBuildVs}'.");
- }
-
- if (!_msbuildToolsPath.EndsWith("\\"))
- _msbuildToolsPath += "\\";
-
- return (Path.Combine(_msbuildToolsPath, "MSBuild.exe"), BuildTool.MsBuildVs);
- }
- case BuildTool.MsBuildMono:
- {
- string msbuildPath = Path.Combine(Internal.MonoWindowsInstallRoot, "bin", "msbuild.bat");
-
- if (!File.Exists(msbuildPath))
- throw new FileNotFoundException($"Cannot find executable for '{BuildManager.PropNameMSBuildMono}'. Tried with path: {msbuildPath}");
-
- return (msbuildPath, BuildTool.MsBuildMono);
- }
- case BuildTool.JetBrainsMsBuild:
- {
- string editorPath = (string)editorSettings.GetSetting(RiderPathManager.EditorPathSettingName);
-
- if (!File.Exists(editorPath))
- throw new FileNotFoundException($"Cannot find Rider executable. Tried with path: {editorPath}");
-
- var riderDir = new FileInfo(editorPath).Directory?.Parent;
-
- string msbuildPath = Path.Combine(riderDir.FullName, @"tools\MSBuild\Current\Bin\MSBuild.exe");
-
- if (!File.Exists(msbuildPath))
- throw new FileNotFoundException($"Cannot find executable for '{BuildManager.PropNameMSBuildJetBrains}'. Tried with path: {msbuildPath}");
-
- return (msbuildPath, BuildTool.JetBrainsMsBuild);
- }
- default:
- throw new IndexOutOfRangeException("Invalid build tool in editor settings");
- }
- }
-
- if (OS.IsUnixLike)
- {
- switch (buildTool)
- {
- case BuildTool.DotnetCli:
- {
- string dotnetCliPath = FindBuildEngineOnUnix("dotnet");
- if (!string.IsNullOrEmpty(dotnetCliPath))
- return (dotnetCliPath, BuildTool.DotnetCli);
- GD.PushError($"Cannot find executable for '{BuildManager.PropNameDotnetCli}'. Fallback to MSBuild from Mono.");
- goto case BuildTool.MsBuildMono;
- }
- case BuildTool.MsBuildMono:
- {
- if (string.IsNullOrEmpty(_msbuildUnixPath) || !File.Exists(_msbuildUnixPath))
- {
- // Try to search it again if it wasn't found last time or if it was removed from its location
- _msbuildUnixPath = FindBuildEngineOnUnix("msbuild");
- }
-
- if (string.IsNullOrEmpty(_msbuildUnixPath))
- throw new FileNotFoundException($"Cannot find binary for '{BuildManager.PropNameMSBuildMono}'");
-
- return (_msbuildUnixPath, BuildTool.MsBuildMono);
- }
- default:
- throw new IndexOutOfRangeException("Invalid build tool in editor settings");
- }
- }
-
- throw new PlatformNotSupportedException();
- }
-
- private static IEnumerable<string> MsBuildHintDirs
- {
- get
- {
- var result = new List<string>();
-
- if (OS.IsMacOS)
- {
- result.Add("/Library/Frameworks/Mono.framework/Versions/Current/bin/");
- result.Add("/opt/local/bin/");
- result.Add("/usr/local/var/homebrew/linked/mono/bin/");
- result.Add("/usr/local/bin/");
- result.Add("/usr/local/bin/dotnet/");
- result.Add("/usr/local/share/dotnet/");
- }
-
- result.Add("/opt/novell/mono/bin/");
-
- return result;
- }
- }
-
- private static string FindBuildEngineOnUnix(string name)
- {
- string ret = OS.PathWhich(name);
-
- if (!string.IsNullOrEmpty(ret))
- return ret;
-
- string retFallback = OS.PathWhich($"{name}.exe");
-
- if (!string.IsNullOrEmpty(retFallback))
- return retFallback;
-
- foreach (string hintDir in MsBuildHintDirs)
- {
- string hintPath = Path.Combine(hintDir, name);
-
- if (File.Exists(hintPath))
- return hintPath;
- }
-
- return string.Empty;
- }
-
- private static string FindMsBuildToolsPathOnWindows()
- {
- if (!OS.IsWindows)
- throw new PlatformNotSupportedException();
-
- // Try to find 15.0 with vswhere
-
- string[] envNames = Internal.GodotIs32Bits() ?
- envNames = new[] { "ProgramFiles", "ProgramW6432" } :
- envNames = 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"};
-
- var outputArray = new Godot.Collections.Array<string>();
- int exitCode = Godot.OS.Execute(vsWherePath, vsWhereArgs,
- output: (Godot.Collections.Array)outputArray);
-
- if (exitCode != 0)
- return string.Empty;
-
- if (outputArray.Count == 0)
- return string.Empty;
-
- var lines = outputArray[0].Split('\n');
-
- foreach (string line in lines)
- {
- int sepIdx = line.IndexOf(':');
-
- if (sepIdx <= 0)
- continue;
-
- string key = line.Substring(0, sepIdx); // No need to trim
-
- if (key != "installationPath")
- continue;
-
- string value = line.Substring(sepIdx + 1).StripEdges();
-
- if (string.IsNullOrEmpty(value))
- throw new FormatException("installationPath value is empty");
-
- if (!value.EndsWith("\\"))
- value += "\\";
-
- // Since VS2019, the directory is simply named "Current"
- string msbuildDir = Path.Combine(value, "MSBuild\\Current\\Bin");
-
- if (Directory.Exists(msbuildDir))
- return msbuildDir;
-
- // Directory name "15.0" is used in VS 2017
- return Path.Combine(value, "MSBuild\\15.0\\Bin");
- }
-
- return string.Empty;
- }
- }
-}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs b/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs
index 63b97e981e..d2e0e128b5 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
@@ -39,7 +40,8 @@ namespace GodotTools.Build
// Since this can be considered pretty much a new NuGet.Config, add the default nuget.org source as well
XmlElement nugetOrgSourceEntry = xmlDoc.CreateElement("add");
nugetOrgSourceEntry.Attributes.Append(xmlDoc.CreateAttribute("key")).Value = "nuget.org";
- nugetOrgSourceEntry.Attributes.Append(xmlDoc.CreateAttribute("value")).Value = "https://api.nuget.org/v3/index.json";
+ nugetOrgSourceEntry.Attributes.Append(xmlDoc.CreateAttribute("value")).Value =
+ "https://api.nuget.org/v3/index.json";
nugetOrgSourceEntry.Attributes.Append(xmlDoc.CreateAttribute("protocolVersion")).Value = "3";
rootNode.AppendChild(xmlDoc.CreateElement("packageSources")).AppendChild(nugetOrgSourceEntry);
}
@@ -47,7 +49,7 @@ namespace GodotTools.Build
{
// Check that the root node is the expected one
if (rootNode.Name != nuGetConfigRootName)
- throw new Exception("Invalid root Xml node for NuGet.Config. " +
+ throw new FormatException("Invalid root Xml node for NuGet.Config. " +
$"Expected '{nuGetConfigRootName}' got '{rootNode.Name}'.");
}
@@ -181,8 +183,8 @@ namespace GodotTools.Build
// - The sha512 of the nupkg is base64 encoded.
// - We can get the nuspec from the nupkg which is a Zip file.
- string packageIdLower = packageId.ToLower();
- string packageVersionLower = packageVersion.ToLower();
+ string packageIdLower = packageId.ToLowerInvariant();
+ string packageVersionLower = packageVersion.ToLowerInvariant();
string destDir = Path.Combine(fallbackFolder, packageIdLower, packageVersionLower);
string nupkgDestPath = Path.Combine(destDir, $"{packageIdLower}.{packageVersionLower}.nupkg");
@@ -227,9 +229,11 @@ namespace GodotTools.Build
var nuspecEntry = archive.GetEntry(packageId + ".nuspec");
if (nuspecEntry == null)
- throw new InvalidOperationException($"Failed to extract package {packageId}.{packageVersion}. Could not find the nuspec file.");
+ throw new InvalidOperationException(
+ $"Failed to extract package {packageId}.{packageVersion}. Could not find the nuspec file.");
- nuspecEntry.ExtractToFile(Path.Combine(destDir, nuspecEntry.Name.ToLower().SimplifyGodotPath()));
+ nuspecEntry.ExtractToFile(Path.Combine(destDir, nuspecEntry.Name
+ .ToLowerInvariant().SimplifyGodotPath()));
// Extract the other package files
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs
index e9718cc82c..2184cae6d6 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/AotBuilder.cs
@@ -75,8 +75,24 @@ namespace GodotTools.Export
}
else
{
- string bits = features.Contains("64") ? "64" : features.Contains("32") ? "32" : null;
- CompileAssembliesForDesktop(exporter, platform, isDebug, bits, aotOpts, aotTempDir, outputDataDir, assembliesPrepared, bclDir);
+ string arch = "";
+ if (features.Contains("x86_64"))
+ {
+ arch = "x86_64";
+ }
+ else if (features.Contains("x86_32"))
+ {
+ arch = "x86_32";
+ }
+ else if (features.Contains("arm64"))
+ {
+ arch = "arm64";
+ }
+ else if (features.Contains("arm32"))
+ {
+ arch = "arm32";
+ }
+ CompileAssembliesForDesktop(exporter, platform, isDebug, arch, aotOpts, aotTempDir, outputDataDir, assembliesPrepared, bclDir);
}
}
@@ -112,7 +128,7 @@ namespace GodotTools.Export
}
}
- public static void CompileAssembliesForDesktop(ExportPlugin exporter, string platform, bool isDebug, string bits, AotOptions aotOpts, string aotTempDir, string outputDataDir, IDictionary<string, string> assemblies, string bclDir)
+ public static void CompileAssembliesForDesktop(ExportPlugin exporter, string platform, bool isDebug, string arch, AotOptions aotOpts, string aotTempDir, string outputDataDir, IDictionary<string, string> assemblies, string bclDir)
{
foreach (var assembly in assemblies)
{
@@ -126,9 +142,9 @@ namespace GodotTools.Export
string outputFileName = assemblyName + ".dll" + outputFileExtension;
string tempOutputFilePath = Path.Combine(aotTempDir, outputFileName);
- var compilerArgs = GetAotCompilerArgs(platform, isDebug, bits, aotOpts, assemblyPath, tempOutputFilePath);
+ var compilerArgs = GetAotCompilerArgs(platform, isDebug, arch, aotOpts, assemblyPath, tempOutputFilePath);
- string compilerDirPath = GetMonoCrossDesktopDirName(platform, bits);
+ string compilerDirPath = GetMonoCrossDesktopDirName(platform, arch);
ExecuteCompiler(FindCrossCompiler(compilerDirPath), compilerArgs, bclDir);
@@ -203,7 +219,7 @@ namespace GodotTools.Export
int clangExitCode = OS.ExecuteCommand(XcodeHelper.FindXcodeTool("clang"), clangArgs);
if (clangExitCode != 0)
- throw new Exception($"Command 'clang' exited with code: {clangExitCode}");
+ throw new InvalidOperationException($"Command 'clang' exited with code: {clangExitCode}.");
objFilePathsForiOSArch[arch].Add(objFilePath);
}
@@ -289,7 +305,7 @@ MONO_AOT_MODE_LAST = 1000,
// Archive the AOT object files into a static library
var arFilePathsForAllArchs = new List<string>();
- string projectAssemblyName = GodotSharpEditor.ProjectAssemblyName;
+ string projectAssemblyName = GodotSharpDirs.ProjectAssemblyName;
foreach (var archPathsPair in objFilePathsForiOSArch)
{
@@ -309,7 +325,7 @@ MONO_AOT_MODE_LAST = 1000,
int arExitCode = OS.ExecuteCommand(XcodeHelper.FindXcodeTool("ar"), arArgs);
if (arExitCode != 0)
- throw new Exception($"Command 'ar' exited with code: {arExitCode}");
+ throw new InvalidOperationException($"Command 'ar' exited with code: {arExitCode}.");
arFilePathsForAllArchs.Add(arOutputFilePath);
}
@@ -327,7 +343,7 @@ MONO_AOT_MODE_LAST = 1000,
int lipoExitCode = OS.ExecuteCommand(XcodeHelper.FindXcodeTool("lipo"), lipoArgs);
if (lipoExitCode != 0)
- throw new Exception($"Command 'lipo' exited with code: {lipoExitCode}");
+ throw new InvalidOperationException($"Command 'lipo' exited with code: {lipoExitCode}.");
// TODO: Add the AOT lib and interpreter libs as device only to suppress warnings when targeting the simulator
@@ -427,14 +443,14 @@ MONO_AOT_MODE_LAST = 1000,
}
else if (!Directory.Exists(androidToolchain))
{
- throw new FileNotFoundException("Android toolchain not found: " + androidToolchain);
+ throw new FileNotFoundException($"Android toolchain not found: '{androidToolchain}'.");
}
var androidToolPrefixes = new Dictionary<string, string>
{
- ["armeabi-v7a"] = "arm-linux-androideabi-",
- ["arm64-v8a"] = "aarch64-linux-android-",
- ["x86"] = "i686-linux-android-",
+ ["arm32"] = "arm-linux-androideabi-",
+ ["arm64"] = "aarch64-linux-android-",
+ ["x86_32"] = "i686-linux-android-",
["x86_64"] = "x86_64-linux-android-"
};
@@ -524,12 +540,12 @@ MONO_AOT_MODE_LAST = 1000,
Console.WriteLine($"Running: \"{process.StartInfo.FileName}\" {process.StartInfo.Arguments}");
if (!process.Start())
- throw new Exception("Failed to start process for Mono AOT compiler");
+ throw new InvalidOperationException("Failed to start process for Mono AOT compiler.");
process.WaitForExit();
if (process.ExitCode != 0)
- throw new Exception($"Mono AOT compiler exited with code: {process.ExitCode}");
+ throw new InvalidOperationException($"Mono AOT compiler exited with code: {process.ExitCode}.");
}
}
@@ -547,9 +563,9 @@ MONO_AOT_MODE_LAST = 1000,
{
var androidAbis = new[]
{
- "armeabi-v7a",
- "arm64-v8a",
- "x86",
+ "arm32",
+ "arm64",
+ "x86_32",
"x86_64"
};
@@ -560,9 +576,9 @@ MONO_AOT_MODE_LAST = 1000,
{
var abiArchs = new Dictionary<string, string>
{
- ["armeabi-v7a"] = "armv7",
- ["arm64-v8a"] = "aarch64-v8a",
- ["x86"] = "i686",
+ ["arm32"] = "armv7",
+ ["arm64"] = "aarch64-v8a",
+ ["x86_32"] = "i686",
["x86_64"] = "x86_64"
};
@@ -571,31 +587,25 @@ MONO_AOT_MODE_LAST = 1000,
return $"{arch}-linux-android";
}
- private static string GetMonoCrossDesktopDirName(string platform, string bits)
+ private static string GetMonoCrossDesktopDirName(string platform, string arch)
{
switch (platform)
{
case OS.Platforms.Windows:
case OS.Platforms.UWP:
{
- string arch = bits == "64" ? "x86_64" : "i686";
return $"windows-{arch}";
}
case OS.Platforms.MacOS:
{
- Debug.Assert(bits == null || bits == "64");
- string arch = "x86_64";
return $"{platform}-{arch}";
}
case OS.Platforms.LinuxBSD:
- case OS.Platforms.Server:
{
- string arch = bits == "64" ? "x86_64" : "i686";
return $"linux-{arch}";
}
case OS.Platforms.Haiku:
{
- string arch = bits == "64" ? "x86_64" : "i686";
return $"{platform}-{arch}";
}
default:
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
index cca18a2a1f..851a8b3689 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
@@ -4,11 +4,9 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
-using System.Runtime.CompilerServices;
using GodotTools.Build;
using GodotTools.Core;
using GodotTools.Internals;
-using JetBrains.Annotations;
using static GodotTools.Internals.Globals;
using Directory = GodotTools.Utils.Directory;
using File = GodotTools.Utils.File;
@@ -17,61 +15,13 @@ using Path = System.IO.Path;
namespace GodotTools.Export
{
- public class ExportPlugin : EditorExportPlugin
+ public partial class ExportPlugin : EditorExportPlugin
{
- [Flags]
- private enum I18NCodesets : long
- {
- None = 0,
- CJK = 1,
- MidEast = 2,
- Other = 4,
- Rare = 8,
- West = 16,
- All = CJK | MidEast | Other | Rare | West
- }
-
- private string _maybeLastExportError;
-
- private void AddI18NAssemblies(Godot.Collections.Dictionary<string, string> assemblies, string bclDir)
- {
- var codesets = (I18NCodesets)ProjectSettings.GetSetting("mono/export/i18n_codesets");
-
- if (codesets == I18NCodesets.None)
- return;
-
- void AddI18NAssembly(string name) => assemblies.Add(name, Path.Combine(bclDir, $"{name}.dll"));
-
- AddI18NAssembly("I18N");
-
- if ((codesets & I18NCodesets.CJK) != 0)
- AddI18NAssembly("I18N.CJK");
- if ((codesets & I18NCodesets.MidEast) != 0)
- AddI18NAssembly("I18N.MidEast");
- if ((codesets & I18NCodesets.Other) != 0)
- AddI18NAssembly("I18N.Other");
- if ((codesets & I18NCodesets.Rare) != 0)
- AddI18NAssembly("I18N.Rare");
- if ((codesets & I18NCodesets.West) != 0)
- AddI18NAssembly("I18N.West");
- }
-
public void RegisterExportSettings()
{
// TODO: These would be better as export preset options, but that doesn't seem to be supported yet
GlobalDef("mono/export/include_scripts_content", false);
- GlobalDef("mono/export/export_assemblies_inside_pck", true);
-
- GlobalDef("mono/export/i18n_codesets", I18NCodesets.All);
-
- ProjectSettings.AddPropertyInfo(new Godot.Collections.Dictionary
- {
- ["type"] = Variant.Type.Int,
- ["name"] = "mono/export/i18n_codesets",
- ["hint"] = PropertyHint.Flags,
- ["hint_string"] = "CJK,MidEast,Other,Rare,West"
- });
GlobalDef("mono/export/aot/enabled", false);
GlobalDef("mono/export/aot/full_aot", false);
@@ -85,11 +35,7 @@ namespace GodotTools.Export
GlobalDef("mono/export/aot/android_toolchain_path", "");
}
- private void AddFile(string srcPath, string dstPath, bool remap = false)
- {
- // Add file to the PCK
- AddFile(dstPath.Replace("\\", "/"), File.ReadAllBytes(srcPath), remap);
- }
+ private string _maybeLastExportError;
// With this method we can override how a file is exported in the PCK
public override void _ExportFile(string path, string type, string[] features)
@@ -100,7 +46,9 @@ namespace GodotTools.Export
return;
if (Path.GetExtension(path) != Internal.CSharpLanguageExtension)
- throw new ArgumentException($"Resource of type {Internal.CSharpLanguageType} has an invalid file extension: {path}", nameof(path));
+ throw new ArgumentException(
+ $"Resource of type {Internal.CSharpLanguageType} has an invalid file extension: {path}",
+ nameof(path));
// TODO What if the source file is not part of the game's C# project
@@ -150,161 +98,95 @@ namespace GodotTools.Export
return;
if (!DeterminePlatformFromFeatures(features, out string platform))
- throw new NotSupportedException("Target platform not supported");
+ throw new NotSupportedException("Target platform not supported.");
+
+ if (!new[] { OS.Platforms.Windows, OS.Platforms.LinuxBSD, OS.Platforms.MacOS }
+ .Contains(platform))
+ {
+ throw new NotImplementedException("Target platform not yet implemented.");
+ }
string outputDir = new FileInfo(path).Directory?.FullName ??
- throw new FileNotFoundException("Base directory not found");
+ throw new FileNotFoundException("Output base directory not found.");
string buildConfig = isDebug ? "ExportDebug" : "ExportRelease";
- if (!BuildManager.BuildProjectBlocking(buildConfig, platform: platform))
- throw new Exception("Failed to build project");
+ // TODO: This works for now, as we only implemented support for x86 family desktop so far, but it needs to be fixed
+ string arch = features.Contains("x86_64") ? "x86_64" : "x86";
- // Add dependency assemblies
+ string ridOS = DetermineRuntimeIdentifierOS(platform);
+ string ridArch = DetermineRuntimeIdentifierArch(arch);
+ string runtimeIdentifier = $"{ridOS}-{ridArch}";
- var assemblies = new Godot.Collections.Dictionary<string, string>();
+ // Create temporary publish output directory
- string projectDllName = GodotSharpEditor.ProjectAssemblyName;
- string projectDllSrcDir = Path.Combine(GodotSharpDirs.ResTempAssembliesBaseDir, buildConfig);
- string projectDllSrcPath = Path.Combine(projectDllSrcDir, $"{projectDllName}.dll");
+ string publishOutputTempDir = Path.Combine(Path.GetTempPath(), "godot-publish-dotnet",
+ $"{Process.GetCurrentProcess().Id}-{buildConfig}-{runtimeIdentifier}");
- assemblies[projectDllName] = projectDllSrcPath;
+ if (!Directory.Exists(publishOutputTempDir))
+ Directory.CreateDirectory(publishOutputTempDir);
- string bclDir = DeterminePlatformBclDir(platform);
+ // Execute dotnet publish
- if (platform == OS.Platforms.Android)
+ if (!BuildManager.PublishProjectBlocking(buildConfig, platform,
+ runtimeIdentifier, publishOutputTempDir))
{
- string godotAndroidExtProfileDir = GetBclProfileDir("godot_android_ext");
- string monoAndroidAssemblyPath = Path.Combine(godotAndroidExtProfileDir, "Mono.Android.dll");
+ throw new InvalidOperationException("Failed to build project.");
+ }
- if (!File.Exists(monoAndroidAssemblyPath))
- throw new FileNotFoundException("Assembly not found: 'Mono.Android'", monoAndroidAssemblyPath);
+ string soExt = ridOS switch
+ {
+ OS.DotNetOS.Win or OS.DotNetOS.Win10 => "dll",
+ OS.DotNetOS.OSX or OS.DotNetOS.iOS => "dylib",
+ _ => "so"
+ };
- assemblies["Mono.Android"] = monoAndroidAssemblyPath;
- }
- else if (platform == OS.Platforms.HTML5)
+ if (!File.Exists(Path.Combine(publishOutputTempDir, $"{GodotSharpDirs.ProjectAssemblyName}.dll"))
+ // NativeAOT shared library output
+ && !File.Exists(Path.Combine(publishOutputTempDir, $"{GodotSharpDirs.ProjectAssemblyName}.{soExt}")))
{
- // Ideally these would be added automatically since they're referenced by the wasm BCL assemblies.
- // However, at least in the case of 'WebAssembly.Net.Http' for some reason the BCL assemblies
- // reference a different version even though the assembly is the same, for some weird reason.
-
- var wasmFrameworkAssemblies = new[] { "WebAssembly.Bindings", "WebAssembly.Net.WebSockets" };
-
- foreach (string thisWasmFrameworkAssemblyName in wasmFrameworkAssemblies)
- {
- string thisWasmFrameworkAssemblyPath = Path.Combine(bclDir, thisWasmFrameworkAssemblyName + ".dll");
- if (!File.Exists(thisWasmFrameworkAssemblyPath))
- throw new FileNotFoundException($"Assembly not found: '{thisWasmFrameworkAssemblyName}'", thisWasmFrameworkAssemblyPath);
- assemblies[thisWasmFrameworkAssemblyName] = thisWasmFrameworkAssemblyPath;
- }
-
- // Assemblies that can have a different name in a newer version. Newer version must come first and it has priority.
- (string newName, string oldName)[] wasmFrameworkAssembliesOneOf = new[]
- {
- ("System.Net.Http.WebAssemblyHttpHandler", "WebAssembly.Net.Http")
- };
-
- foreach (var thisWasmFrameworkAssemblyName in wasmFrameworkAssembliesOneOf)
- {
- string thisWasmFrameworkAssemblyPath = Path.Combine(bclDir, thisWasmFrameworkAssemblyName.newName + ".dll");
- if (File.Exists(thisWasmFrameworkAssemblyPath))
- {
- assemblies[thisWasmFrameworkAssemblyName.newName] = thisWasmFrameworkAssemblyPath;
- }
- else
- {
- thisWasmFrameworkAssemblyPath = Path.Combine(bclDir, thisWasmFrameworkAssemblyName.oldName + ".dll");
- if (!File.Exists(thisWasmFrameworkAssemblyPath))
- {
- throw new FileNotFoundException("Expected one of the following assemblies but none were found: " +
- $"'{thisWasmFrameworkAssemblyName.newName}' / '{thisWasmFrameworkAssemblyName.oldName}'",
- thisWasmFrameworkAssemblyPath);
- }
-
- assemblies[thisWasmFrameworkAssemblyName.oldName] = thisWasmFrameworkAssemblyPath;
- }
- }
+ throw new NotSupportedException(
+ "Publish succeeded but project assembly not found in the output directory");
}
- var initialAssemblies = assemblies.Duplicate();
- internal_GetExportedAssemblyDependencies(initialAssemblies, buildConfig, bclDir, assemblies);
-
- AddI18NAssemblies(assemblies, bclDir);
+ // Copy all files from the dotnet publish output directory to
+ // a data directory next to the Godot output executable.
- string outputDataDir = null;
-
- if (PlatformHasTemplateDir(platform))
- outputDataDir = ExportDataDirectory(features, platform, isDebug, outputDir);
+ string outputDataDir = Path.Combine(outputDir, DetermineDataDirNameForProject());
- string apiConfig = isDebug ? "Debug" : "Release";
- string resAssembliesDir = Path.Combine(GodotSharpDirs.ResAssembliesBaseDir, apiConfig);
+ if (Directory.Exists(outputDataDir))
+ Directory.Delete(outputDataDir, recursive: true); // Clean first
- bool assembliesInsidePck = (bool)ProjectSettings.GetSetting("mono/export/export_assemblies_inside_pck") || outputDataDir == null;
+ Directory.CreateDirectory(outputDataDir);
- if (!assembliesInsidePck)
+ foreach (string dir in Directory.GetDirectories(publishOutputTempDir, "*", SearchOption.AllDirectories))
{
- string outputDataGameAssembliesDir = Path.Combine(outputDataDir, "Assemblies");
- if (!Directory.Exists(outputDataGameAssembliesDir))
- Directory.CreateDirectory(outputDataGameAssembliesDir);
+ Directory.CreateDirectory(Path.Combine(outputDataDir, dir.Substring(publishOutputTempDir.Length + 1)));
}
- foreach (var assembly in assemblies)
+ foreach (string file in Directory.GetFiles(publishOutputTempDir, "*", SearchOption.AllDirectories))
{
- void AddToAssembliesDir(string fileSrcPath)
- {
- if (assembliesInsidePck)
- {
- string fileDstPath = Path.Combine(resAssembliesDir, fileSrcPath.GetFile());
- AddFile(fileSrcPath, fileDstPath);
- }
- else
- {
- Debug.Assert(outputDataDir != null);
- string fileDstPath = Path.Combine(outputDataDir, "Assemblies", fileSrcPath.GetFile());
- File.Copy(fileSrcPath, fileDstPath);
- }
- }
-
- string assemblySrcPath = assembly.Value;
-
- string assemblyPathWithoutExtension = Path.ChangeExtension(assemblySrcPath, null);
- string pdbSrcPath = assemblyPathWithoutExtension + ".pdb";
-
- AddToAssembliesDir(assemblySrcPath);
-
- if (File.Exists(pdbSrcPath))
- AddToAssembliesDir(pdbSrcPath);
+ File.Copy(file, Path.Combine(outputDataDir, file.Substring(publishOutputTempDir.Length + 1)));
}
+ }
- // AOT compilation
- bool aotEnabled = platform == OS.Platforms.iOS || (bool)ProjectSettings.GetSetting("mono/export/aot/enabled");
+ private string DetermineRuntimeIdentifierOS(string platform)
+ => OS.DotNetOSPlatformMap[platform];
- if (aotEnabled)
+ private string DetermineRuntimeIdentifierArch(string arch)
+ {
+ return arch switch
{
- string aotToolchainPath = null;
-
- if (platform == OS.Platforms.Android)
- aotToolchainPath = (string)ProjectSettings.GetSetting("mono/export/aot/android_toolchain_path");
-
- if (aotToolchainPath == string.Empty)
- aotToolchainPath = null; // Don't risk it being used as current working dir
-
- // TODO: LLVM settings are hard-coded and disabled for now
- var aotOpts = new AotOptions
- {
- EnableLLVM = false,
- LLVMOnly = false,
- LLVMPath = "",
- LLVMOutputPath = "",
- FullAot = platform == OS.Platforms.iOS || (bool)(ProjectSettings.GetSetting("mono/export/aot/full_aot") ?? false),
- UseInterpreter = (bool)ProjectSettings.GetSetting("mono/export/aot/use_interpreter"),
- ExtraAotOptions = (string[])ProjectSettings.GetSetting("mono/export/aot/extra_aot_options") ?? Array.Empty<string>(),
- ExtraOptimizerOptions = (string[])ProjectSettings.GetSetting("mono/export/aot/extra_optimizer_options") ?? Array.Empty<string>(),
- ToolchainPath = aotToolchainPath
- };
-
- AotBuilder.CompileAssemblies(this, aotOpts, features, platform, isDebug, bclDir, outputDir, outputDataDir, assemblies);
- }
+ "x86" => "x86",
+ "x86_32" => "x86",
+ "x64" => "x64",
+ "x86_64" => "x64",
+ "armeabi-v7a" => "arm",
+ "arm64-v8a" => "arm64",
+ "armv7" => "arm",
+ "arm64" => "arm64",
+ _ => throw new ArgumentOutOfRangeException(nameof(arch), arch, "Unexpected architecture")
+ };
}
public override void _ExportEnd()
@@ -316,8 +198,10 @@ namespace GodotTools.Export
if (Directory.Exists(aotTempDir))
Directory.Delete(aotTempDir, recursive: true);
- // TODO: Just a workaround until the export plugins can be made to abort with errors
- if (!string.IsNullOrEmpty(_maybeLastExportError)) // Check empty as well, because it's set to empty after hot-reloading
+ // TODO: The following is just a workaround until the export plugins can be made to abort with errors
+
+ // We check for empty as well, because it's set to empty after hot-reloading
+ if (!string.IsNullOrEmpty(_maybeLastExportError))
{
string lastExportError = _maybeLastExportError;
_maybeLastExportError = null;
@@ -326,69 +210,11 @@ namespace GodotTools.Export
}
}
- [NotNull]
- private static string ExportDataDirectory(string[] features, string platform, bool isDebug, string outputDir)
- {
- string target = isDebug ? "release_debug" : "release";
-
- // NOTE: Bits is ok for now as all platforms with a data directory only have one or two architectures.
- // However, this may change in the future if we add arm linux or windows desktop templates.
- string bits = features.Contains("64") ? "64" : "32";
-
- string TemplateDirName() => $"data.mono.{platform}.{bits}.{target}";
-
- string templateDirPath = Path.Combine(Internal.FullExportTemplatesDir, TemplateDirName());
- bool validTemplatePathFound = true;
-
- if (!Directory.Exists(templateDirPath))
- {
- validTemplatePathFound = false;
-
- if (isDebug)
- {
- target = "debug"; // Support both 'release_debug' and 'debug' for the template data directory name
- templateDirPath = Path.Combine(Internal.FullExportTemplatesDir, TemplateDirName());
- validTemplatePathFound = true;
-
- if (!Directory.Exists(templateDirPath))
- validTemplatePathFound = false;
- }
- }
-
- if (!validTemplatePathFound)
- throw new FileNotFoundException("Data template directory not found", templateDirPath);
-
- string outputDataDir = Path.Combine(outputDir, DetermineDataDirNameForProject());
-
- if (Directory.Exists(outputDataDir))
- Directory.Delete(outputDataDir, recursive: true); // Clean first
-
- Directory.CreateDirectory(outputDataDir);
-
- foreach (string dir in Directory.GetDirectories(templateDirPath, "*", SearchOption.AllDirectories))
- {
- Directory.CreateDirectory(Path.Combine(outputDataDir, dir.Substring(templateDirPath.Length + 1)));
- }
-
- foreach (string file in Directory.GetFiles(templateDirPath, "*", SearchOption.AllDirectories))
- {
- File.Copy(file, Path.Combine(outputDataDir, file.Substring(templateDirPath.Length + 1)));
- }
-
- return outputDataDir;
- }
-
- private static bool PlatformHasTemplateDir(string platform)
- {
- // macOS export templates are contained in a zip, so we place our custom template inside it and let Godot do the rest.
- return !new[] { OS.Platforms.MacOS, OS.Platforms.Android, OS.Platforms.iOS, OS.Platforms.HTML5 }.Contains(platform);
- }
-
private static bool DeterminePlatformFromFeatures(IEnumerable<string> features, out string platform)
{
foreach (var feature in features)
{
- if (OS.PlatformNameMap.TryGetValue(feature, out platform))
+ if (OS.PlatformFeatureMap.TryGetValue(feature, out platform))
return true;
}
@@ -396,87 +222,11 @@ namespace GodotTools.Export
return false;
}
- private static string GetBclProfileDir(string profile)
- {
- string templatesDir = Internal.FullExportTemplatesDir;
- return Path.Combine(templatesDir, "bcl", profile);
- }
-
- private static string DeterminePlatformBclDir(string platform)
- {
- string templatesDir = Internal.FullExportTemplatesDir;
- string platformBclDir = Path.Combine(templatesDir, "bcl", platform);
-
- if (!File.Exists(Path.Combine(platformBclDir, "mscorlib.dll")))
- {
- string profile = DeterminePlatformBclProfile(platform);
- platformBclDir = Path.Combine(templatesDir, "bcl", profile);
-
- if (!File.Exists(Path.Combine(platformBclDir, "mscorlib.dll")))
- {
- if (PlatformRequiresCustomBcl(platform))
- throw new FileNotFoundException($"Missing BCL (Base Class Library) for platform: {platform}");
-
- platformBclDir = typeof(object).Assembly.Location.GetBaseDir(); // Use the one we're running on
- }
- }
-
- return platformBclDir;
- }
-
- /// <summary>
- /// Determines whether the BCL bundled with the Godot editor can be used for the target platform,
- /// or if it requires a custom BCL that must be distributed with the export templates.
- /// </summary>
- private static bool PlatformRequiresCustomBcl(string platform)
- {
- if (new[] { OS.Platforms.Android, OS.Platforms.iOS, OS.Platforms.HTML5 }.Contains(platform))
- return true;
-
- // The 'net_4_x' BCL is not compatible between Windows and the other platforms.
- // We use the names 'net_4_x_win' and 'net_4_x' to differentiate between the two.
-
- bool isWinOrUwp = new[]
- {
- OS.Platforms.Windows,
- OS.Platforms.UWP
- }.Contains(platform);
-
- return OS.IsWindows ? !isWinOrUwp : isWinOrUwp;
- }
-
- private static string DeterminePlatformBclProfile(string platform)
- {
- switch (platform)
- {
- case OS.Platforms.Windows:
- case OS.Platforms.UWP:
- return "net_4_x_win";
- case OS.Platforms.MacOS:
- case OS.Platforms.LinuxBSD:
- case OS.Platforms.Server:
- case OS.Platforms.Haiku:
- return "net_4_x";
- case OS.Platforms.Android:
- return "monodroid";
- case OS.Platforms.iOS:
- return "monotouch";
- case OS.Platforms.HTML5:
- return "wasm";
- default:
- throw new NotSupportedException($"Platform not supported: {platform}");
- }
- }
-
private static string DetermineDataDirNameForProject()
{
string appName = (string)ProjectSettings.GetSetting("application/config/name");
string appNameSafe = appName.ToSafeDirName();
return $"data_{appNameSafe}";
}
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_GetExportedAssemblyDependencies(Godot.Collections.Dictionary<string, string> initialAssemblies,
- string buildConfig, string customBclDir, Godot.Collections.Dictionary<string, string> dependencyAssemblies);
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/XcodeHelper.cs b/modules/mono/editor/GodotTools/GodotTools/Export/XcodeHelper.cs
index 93ef837a83..4f5bebfb42 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/XcodeHelper.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/XcodeHelper.cs
@@ -16,7 +16,7 @@ namespace GodotTools.Export
_XcodePath = FindXcode();
if (_XcodePath == null)
- throw new Exception("Could not find Xcode");
+ throw new FileNotFoundException("Could not find Xcode.");
}
return _XcodePath;
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index b39c3d1c0d..994c11fa72 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -13,13 +13,14 @@ using GodotTools.Internals;
using GodotTools.ProjectEditor;
using JetBrains.Annotations;
using static GodotTools.Internals.Globals;
+using Environment = System.Environment;
using File = GodotTools.Utils.File;
using OS = GodotTools.Utils.OS;
using Path = System.IO.Path;
namespace GodotTools
{
- public class GodotSharpEditor : EditorPlugin, ISerializationListener
+ public partial class GodotSharpEditor : EditorPlugin, ISerializationListener
{
private EditorSettings _editorSettings;
@@ -39,28 +40,27 @@ namespace GodotTools
public bool SkipBuildBeforePlaying { get; set; } = false;
- public static string ProjectAssemblyName
+ [UsedImplicitly]
+ private bool CreateProjectSolutionIfNeeded()
{
- get
+ if (!File.Exists(GodotSharpDirs.ProjectSlnPath) || !File.Exists(GodotSharpDirs.ProjectCsProjPath))
{
- string projectAssemblyName = (string)ProjectSettings.GetSetting("application/config/name");
- projectAssemblyName = projectAssemblyName.ToSafeDirName();
- if (string.IsNullOrEmpty(projectAssemblyName))
- projectAssemblyName = "UnnamedProject";
- return projectAssemblyName;
+ return CreateProjectSolution();
}
+
+ return true;
}
private bool CreateProjectSolution()
{
- using (var pr = new EditorProgress("create_csharp_solution", "Generating solution...".TTR(), 3))
+ using (var pr = new EditorProgress("create_csharp_solution", "Generating solution...".TTR(), 2))
{
pr.Step("Generating C# project...".TTR());
string resourceDir = ProjectSettings.GlobalizePath("res://");
string path = resourceDir;
- string name = ProjectAssemblyName;
+ string name = GodotSharpDirs.ProjectAssemblyName;
string guid = CsProjOperations.GenerateGameProject(path, name);
@@ -75,7 +75,7 @@ namespace GodotTools
{
Guid = guid,
PathRelativeToSolution = name + ".csproj",
- Configs = new List<string> {"Debug", "ExportDebug", "ExportRelease"}
+ Configs = new List<string> { "Debug", "ExportDebug", "ExportRelease" }
};
solution.AddNewProject(name, projectInfo);
@@ -90,24 +90,6 @@ namespace GodotTools
return false;
}
- pr.Step("Updating Godot API assemblies...".TTR());
-
- string debugApiAssembliesError = Internal.UpdateApiAssembliesFromPrebuilt("Debug");
-
- if (!string.IsNullOrEmpty(debugApiAssembliesError))
- {
- ShowErrorDialog("Failed to update the Godot API assemblies: " + debugApiAssembliesError);
- return false;
- }
-
- string releaseApiAssembliesError = Internal.UpdateApiAssembliesFromPrebuilt("Release");
-
- if (!string.IsNullOrEmpty(releaseApiAssembliesError))
- {
- ShowErrorDialog("Failed to update the Godot API assemblies: " + releaseApiAssembliesError);
- return false;
- }
-
pr.Step("Done".TTR());
// Here, after all calls to progress_task_step
@@ -141,7 +123,8 @@ namespace GodotTools
try
{
string fallbackFolder = NuGetUtils.GodotFallbackFolderPath;
- NuGetUtils.AddFallbackFolderToUserNuGetConfigs(NuGetUtils.GodotFallbackFolderName, fallbackFolder);
+ NuGetUtils.AddFallbackFolderToUserNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
+ fallbackFolder);
NuGetUtils.AddBundledPackagesToFallbackFolder(fallbackFolder);
}
catch (Exception e)
@@ -167,13 +150,6 @@ namespace GodotTools
Instance.MSBuildPanel.BuildSolution();
}
- public override void _Ready()
- {
- base._Ready();
-
- MSBuildPanel.BuildOutputView.BuildStateChanged += BuildStateChanged;
- }
-
private enum MenuOptions
{
CreateSln,
@@ -197,7 +173,7 @@ namespace GodotTools
[UsedImplicitly]
public Error OpenInExternalEditor(Script script, int line, int col)
{
- var editorId = (ExternalEditorId)_editorSettings.GetSetting("mono/editor/external_editor");
+ var editorId = (ExternalEditorId)(int)_editorSettings.GetSetting("mono/editor/external_editor");
switch (editorId)
{
@@ -219,13 +195,15 @@ namespace GodotTools
try
{
if (Godot.OS.IsStdoutVerbose())
- Console.WriteLine($"Running: \"{command}\" {string.Join(" ", args.Select(a => $"\"{a}\""))}");
+ Console.WriteLine(
+ $"Running: \"{command}\" {string.Join(" ", args.Select(a => $"\"{a}\""))}");
OS.RunProcess(command, args);
}
catch (Exception e)
{
- GD.PushError($"Error when trying to run code editor: VisualStudio. Exception message: '{e.Message}'");
+ GD.PushError(
+ $"Error when trying to run code editor: VisualStudio. Exception message: '{e.Message}'");
}
break;
@@ -347,7 +325,8 @@ namespace GodotTools
[UsedImplicitly]
public bool OverridesExternalEditor()
{
- return (ExternalEditorId)_editorSettings.GetSetting("mono/editor/external_editor") != ExternalEditorId.None;
+ return (ExternalEditorId)(int)_editorSettings.GetSetting("mono/editor/external_editor") !=
+ ExternalEditorId.None;
}
public override bool _Build()
@@ -363,12 +342,12 @@ namespace GodotTools
DotNetSolution.MigrateFromOldConfigNames(GodotSharpDirs.ProjectSlnPath);
var msbuildProject = ProjectUtils.Open(GodotSharpDirs.ProjectCsProjPath)
- ?? throw new Exception("Cannot open C# project");
+ ?? throw new InvalidOperationException("Cannot open C# project.");
// NOTE: The order in which changes are made to the project is important
// Migrate to MSBuild project Sdks style if using the old style
- ProjectUtils.MigrateToProjectSdksStyle(msbuildProject, ProjectAssemblyName);
+ ProjectUtils.MigrateToProjectSdksStyle(msbuildProject, GodotSharpDirs.ProjectAssemblyName);
ProjectUtils.EnsureGodotSdkIsUpToDate(msbuildProject);
@@ -400,18 +379,49 @@ namespace GodotTools
throw new InvalidOperationException();
Instance = this;
+ var dotNetSdkSearchVersion = Environment.Version;
+
+ // First we try to find the .NET Sdk ourselves to make sure we get the
+ // correct version first (`RegisterDefaults` always picks the latest).
+ if (DotNetFinder.TryFindDotNetSdk(dotNetSdkSearchVersion, out var sdkVersion, out string sdkPath))
+ {
+ if (Godot.OS.IsStdoutVerbose())
+ Console.WriteLine($"Found .NET Sdk version '{sdkVersion}': {sdkPath}");
+
+ ProjectUtils.MSBuildLocatorRegisterMSBuildPath(sdkPath);
+ }
+ else
+ {
+ try
+ {
+ ProjectUtils.MSBuildLocatorRegisterDefaults(out sdkVersion, out sdkPath);
+ if (Godot.OS.IsStdoutVerbose())
+ Console.WriteLine($"Found .NET Sdk version '{sdkVersion}': {sdkPath}");
+ }
+ catch (InvalidOperationException e)
+ {
+ if (Godot.OS.IsStdoutVerbose())
+ GD.PrintErr(e.ToString());
+ GD.PushError($".NET Sdk not found. The required version is '{dotNetSdkSearchVersion}'.");
+ }
+ }
+
var editorInterface = GetEditorInterface();
var editorBaseControl = editorInterface.GetBaseControl();
_editorSettings = editorInterface.GetEditorSettings();
+ GodotSharpDirs.RegisterProjectSettings();
+
_errorDialog = new AcceptDialog();
editorBaseControl.AddChild(_errorDialog);
MSBuildPanel = new MSBuildPanel();
+ MSBuildPanel.Ready += () =>
+ MSBuildPanel.BuildOutputView.BuildStateChanged += BuildStateChanged;
_bottomPanelBtn = AddControlToBottomPanel(MSBuildPanel, "MSBuild".TTR());
- AddChild(new HotReloadAssemblyWatcher {Name = "HotReloadAssemblyWatcher"});
+ AddChild(new HotReloadAssemblyWatcher { Name = "HotReloadAssemblyWatcher" });
_menuPopup = new PopupMenu();
_menuPopup.Hide();
@@ -423,7 +433,7 @@ namespace GodotTools
_toolBarBuildButton = new Button
{
Text = "Build",
- HintTooltip = "Build Solution".TTR(),
+ TooltipText = "Build Solution".TTR(),
FocusMode = Control.FocusModeEnum.None,
Shortcut = buildSolutionShortcut,
ShortcutInTooltip = true
@@ -472,9 +482,9 @@ namespace GodotTools
_editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary
{
- ["type"] = Variant.Type.Int,
+ ["type"] = (int)Variant.Type.Int,
["name"] = "mono/editor/external_editor",
- ["hint"] = PropertyHint.Enum,
+ ["hint"] = (int)PropertyHint.Enum,
["hint_string"] = settingsHintStr
});
@@ -487,7 +497,8 @@ namespace GodotTools
try
{
// At startup we make sure NuGet.Config files have our Godot NuGet fallback folder included
- NuGetUtils.AddFallbackFolderToUserNuGetConfigs(NuGetUtils.GodotFallbackFolderName, NuGetUtils.GodotFallbackFolderPath);
+ NuGetUtils.AddFallbackFolderToUserNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
+ NuGetUtils.GodotFallbackFolderPath);
}
catch (Exception e)
{
@@ -503,20 +514,23 @@ namespace GodotTools
protected override void Dispose(bool disposing)
{
- base.Dispose(disposing);
-
- if (_exportPluginWeak != null)
+ if (disposing)
{
- // We need to dispose our export plugin before the editor destroys EditorSettings.
- // Otherwise, if the GC disposes it at a later time, EditorExportPlatformAndroid
- // will be freed after EditorSettings already was, and its device polling thread
- // will try to access the EditorSettings singleton, resulting in null dereferencing.
- (_exportPluginWeak.GetRef() as ExportPlugin)?.Dispose();
+ if (IsInstanceValid(_exportPluginWeak))
+ {
+ // We need to dispose our export plugin before the editor destroys EditorSettings.
+ // Otherwise, if the GC disposes it at a later time, EditorExportPlatformAndroid
+ // will be freed after EditorSettings already was, and its device polling thread
+ // will try to access the EditorSettings singleton, resulting in null dereferencing.
+ (_exportPluginWeak.GetRef().AsGodotObject() as ExportPlugin)?.Dispose();
+
+ _exportPluginWeak.Dispose();
+ }
- _exportPluginWeak.Dispose();
+ GodotIdeManager?.Dispose();
}
- GodotIdeManager?.Dispose();
+ base.Dispose(disposing);
}
public void OnBeforeSerialize()
@@ -533,8 +547,10 @@ namespace GodotTools
public static GodotSharpEditor Instance { get; private set; }
[UsedImplicitly]
- private GodotSharpEditor()
+ private static IntPtr InternalCreateInstance(IntPtr unmanagedCallbacks, int unmanagedCallbacksSize)
{
+ Internal.Initialize(unmanagedCallbacks, unmanagedCallbacksSize);
+ return new GodotSharpEditor().NativeInstance;
}
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
index f1d45463c5..30525ba04a 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj
@@ -1,14 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ProjectGuid>{27B00618-A6F2-4828-B922-05CAEB08C286}</ProjectGuid>
- <TargetFramework>net472</TargetFramework>
- <LangVersion>7.2</LangVersion>
+ <TargetFramework>net6.0</TargetFramework>
+ <EnableDynamicLoading>true</EnableDynamicLoading>
+ <LangVersion>10</LangVersion>
<!-- The Godot editor uses the Debug Godot API assemblies -->
<GodotApiConfiguration>Debug</GodotApiConfiguration>
<GodotSourceRootPath>$(SolutionDir)/../../../../</GodotSourceRootPath>
<GodotOutputDataDir>$(GodotSourceRootPath)/bin/GodotSharp</GodotOutputDataDir>
<GodotApiAssembliesDir>$(GodotOutputDataDir)/Api/$(GodotApiConfiguration)</GodotApiAssembliesDir>
+ <ProduceReferenceAssembly>false</ProduceReferenceAssembly>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
+ <!-- Needed for our source generators to work despite this not being a Godot game project -->
+ <PropertyGroup>
+ <IsGodotToolsProject>true</IsGodotToolsProject>
+ </PropertyGroup>
+ <ItemGroup>
+ <CompilerVisibleProperty Include="IsGodotToolsProject" />
+ </ItemGroup>
<PropertyGroup Condition=" Exists('$(GodotApiAssembliesDir)/GodotSharp.dll') ">
<!-- The project is part of the Godot source tree -->
<!-- Use the Godot source tree output folder instead of '$(ProjectDir)/bin' -->
@@ -20,6 +30,8 @@
<PackageReference Include="JetBrains.Annotations" Version="2019.1.3.0" ExcludeAssets="runtime" PrivateAssets="all" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
+ <!-- For RiderPathLocator -->
+ <PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<Reference Include="GodotSharp">
<HintPath>$(GodotApiAssembliesDir)/GodotSharp.dll</HintPath>
<Private>False</Private>
@@ -30,6 +42,10 @@
</Reference>
</ItemGroup>
<ItemGroup>
+ <ProjectReference Include="..\..\Godot.NET.Sdk\Godot.SourceGenerators\Godot.SourceGenerators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
+ <ProjectReference Include="..\..\..\glue\GodotSharp\Godot.SourceGenerators.Internal\Godot.SourceGenerators.Internal.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
+ </ItemGroup>
+ <ItemGroup>
<ProjectReference Include="..\GodotTools.BuildLogger\GodotTools.BuildLogger.csproj" />
<ProjectReference Include="..\GodotTools.IdeMessaging\GodotTools.IdeMessaging.csproj" />
<ProjectReference Include="..\GodotTools.ProjectEditor\GodotTools.ProjectEditor.csproj" />
diff --git a/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs b/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs
index dd05f28af0..260d13a714 100644
--- a/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/HotReloadAssemblyWatcher.cs
@@ -1,10 +1,11 @@
using Godot;
using GodotTools.Internals;
+using JetBrains.Annotations;
using static GodotTools.Internals.Globals;
namespace GodotTools
{
- public class HotReloadAssemblyWatcher : Node
+ public partial class HotReloadAssemblyWatcher : Node
{
private Timer _watchTimer;
@@ -25,6 +26,7 @@ namespace GodotTools
Internal.ReloadAssemblies(softReload: false);
}
+ [UsedImplicitly]
public void RestartTimer()
{
_watchTimer.Stop();
@@ -38,7 +40,7 @@ namespace GodotTools
_watchTimer = new Timer
{
OneShot = false,
- WaitTime = (float)EditorDef("mono/assembly_watch_interval_sec", 0.5)
+ WaitTime = 0.5f
};
_watchTimer.Timeout += TimerTimeout;
AddChild(_watchTimer);
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs
index 23339fe50b..9df90ac608 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/GodotIdeManager.cs
@@ -8,7 +8,7 @@ using GodotTools.Internals;
namespace GodotTools.Ides
{
- public sealed class GodotIdeManager : Node, ISerializationListener
+ public sealed partial class GodotIdeManager : Node, ISerializationListener
{
private MessagingServer _messagingServer;
@@ -76,7 +76,7 @@ namespace GodotTools.Ides
public async Task<EditorPick?> LaunchIdeAsync(int millisecondsTimeout = 10000)
{
- var editorId = (ExternalEditorId)GodotSharpEditor.Instance.GetEditorInterface()
+ var editorId = (ExternalEditorId)(int)GodotSharpEditor.Instance.GetEditorInterface()
.GetEditorSettings().GetSetting("mono/editor/external_editor");
string editorIdentity = GetExternalEditorIdentity(editorId);
@@ -153,7 +153,7 @@ namespace GodotTools.Ides
}
default:
- throw new ArgumentOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(editorId));
}
}
@@ -180,17 +180,17 @@ namespace GodotTools.Ides
public void SendOpenFile(string file)
{
- SendRequest<OpenFileResponse>(new OpenFileRequest {File = file});
+ SendRequest<OpenFileResponse>(new OpenFileRequest { File = file });
}
public void SendOpenFile(string file, int line)
{
- SendRequest<OpenFileResponse>(new OpenFileRequest {File = file, Line = line});
+ SendRequest<OpenFileResponse>(new OpenFileRequest { File = file, Line = line });
}
public void SendOpenFile(string file, int line, int column)
{
- SendRequest<OpenFileResponse>(new OpenFileRequest {File = file, Line = line, Column = column});
+ SendRequest<OpenFileResponse>(new OpenFileRequest { File = file, Line = line, Column = column });
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs
index 6f11831b80..62db6e3af5 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/MessagingServer.cs
@@ -385,7 +385,7 @@ namespace GodotTools.Ides
// However, it doesn't fix resource loading if the rest of the path is also case insensitive.
string scriptFileLocalized = FsPathUtils.LocalizePathWithCaseChecked(request.ScriptFile);
- var response = new CodeCompletionResponse {Kind = request.Kind, ScriptFile = request.ScriptFile};
+ var response = new CodeCompletionResponse { Kind = request.Kind, ScriptFile = request.ScriptFile };
response.Suggestions = await Task.Run(() =>
Internal.CodeCompletionRequest(response.Kind, scriptFileLocalized ?? request.ScriptFile));
return response;
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs
index 71055f0125..dad6e35344 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathLocator.cs
@@ -1,9 +1,10 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
+using System.Runtime.Versioning;
using Godot;
-using JetBrains.Annotations;
using Microsoft.Win32;
using Newtonsoft.Json;
using Directory = System.IO.Directory;
@@ -41,7 +42,7 @@ namespace GodotTools.Ides.Rider
{
return CollectAllRiderPathsLinux();
}
- throw new Exception("Unexpected OS.");
+ throw new InvalidOperationException("Unexpected OS.");
}
catch (Exception e)
{
@@ -113,6 +114,7 @@ namespace GodotTools.Ides.Rider
return installInfos.ToArray();
}
+ [SupportedOSPlatform("windows")]
private static RiderInfo[] CollectRiderInfosWindows()
{
var installInfos = new List<RiderInfo>();
@@ -214,9 +216,10 @@ namespace GodotTools.Ides.Rider
return "../../build.txt";
if (OS.IsMacOS)
return "Contents/Resources/build.txt";
- throw new Exception("Unknown OS.");
+ throw new InvalidOperationException("Unknown OS.");
}
+ [SupportedOSPlatform("windows")]
private static void CollectPathsFromRegistry(string registryKey, List<string> installPaths)
{
using (var key = Registry.CurrentUser.OpenSubKey(registryKey))
@@ -229,6 +232,7 @@ namespace GodotTools.Ides.Rider
}
}
+ [SupportedOSPlatform("windows")]
private static void CollectPathsFromRegistry(List<string> installPaths, RegistryKey key)
{
if (key == null) return;
@@ -324,7 +328,7 @@ namespace GodotTools.Ides.Rider
{
public string install_location;
- [CanBeNull]
+ [return: MaybeNull]
public static string GetInstallLocationFromJson(string json)
{
try
@@ -378,7 +382,7 @@ namespace GodotTools.Ides.Rider
public string version;
public string versionSuffix;
- [CanBeNull]
+ [return: MaybeNull]
internal static ProductInfo GetProductInfo(string json)
{
try
@@ -402,7 +406,7 @@ namespace GodotTools.Ides.Rider
// ReSharper disable once InconsistentNaming
public ActiveApplication active_application;
- [CanBeNull]
+ [return: MaybeNull]
public static string GetLatestBuildFromJson(string json)
{
try
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
index ac29efb716..60602a5847 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
@@ -22,7 +22,7 @@ namespace GodotTools.Ides.Rider
public static void Initialize()
{
var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
- var editor = (ExternalEditorId)editorSettings.GetSetting("mono/editor/external_editor");
+ var editor = (ExternalEditorId)(int)editorSettings.GetSetting("mono/editor/external_editor");
if (editor == ExternalEditorId.Rider)
{
if (!editorSettings.HasSetting(EditorPathSettingName))
@@ -30,9 +30,9 @@ namespace GodotTools.Ides.Rider
Globals.EditorDef(EditorPathSettingName, "Optional");
editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary
{
- ["type"] = Variant.Type.String,
+ ["type"] = (int)Variant.Type.String,
["name"] = EditorPathSettingName,
- ["hint"] = PropertyHint.File,
+ ["hint"] = (int)PropertyHint.File,
["hint_string"] = ""
});
}
@@ -66,6 +66,9 @@ namespace GodotTools.Ides.Rider
if (string.IsNullOrEmpty(path))
return false;
+ if (path.IndexOfAny(Path.GetInvalidPathChars()) != -1)
+ return false;
+
var fileInfo = new FileInfo(path);
string filename = fileInfo.Name.ToLowerInvariant();
return filename.StartsWith("rider", StringComparison.Ordinal);
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs
index 70ba7c733a..8f39ad063e 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/EditorProgress.cs
@@ -1,6 +1,7 @@
using System;
using System.Runtime.CompilerServices;
using Godot;
+using Godot.NativeInterop;
namespace GodotTools.Internals
{
@@ -8,19 +9,12 @@ namespace GodotTools.Internals
{
public string Task { get; }
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_Create(string task, string label, int amount, bool canCancel);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_Dispose(string task);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool internal_Step(string task, string state, int step, bool forceRefresh);
-
public EditorProgress(string task, string label, int amount, bool canCancel = false)
{
Task = task;
- internal_Create(task, label, amount, canCancel);
+ using godot_string taskIn = Marshaling.ConvertStringToNative(task);
+ using godot_string labelIn = Marshaling.ConvertStringToNative(label);
+ Internal.godot_icall_EditorProgress_Create(taskIn, labelIn, amount, canCancel);
}
~EditorProgress()
@@ -33,18 +27,23 @@ namespace GodotTools.Internals
public void Dispose()
{
- internal_Dispose(Task);
+ using godot_string taskIn = Marshaling.ConvertStringToNative(Task);
+ Internal.godot_icall_EditorProgress_Dispose(taskIn);
GC.SuppressFinalize(this);
}
public void Step(string state, int step = -1, bool forceRefresh = true)
{
- internal_Step(Task, state, step, forceRefresh);
+ using godot_string taskIn = Marshaling.ConvertStringToNative(Task);
+ using godot_string stateIn = Marshaling.ConvertStringToNative(state);
+ Internal.godot_icall_EditorProgress_Step(taskIn, stateIn, step, forceRefresh);
}
public bool TryStep(string state, int step = -1, bool forceRefresh = true)
{
- return internal_Step(Task, state, step, forceRefresh);
+ using godot_string taskIn = Marshaling.ConvertStringToNative(Task);
+ using godot_string stateIn = Marshaling.ConvertStringToNative(state);
+ return Internal.godot_icall_EditorProgress_Step(taskIn, stateIn, step, forceRefresh);
}
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs
index 5c5ced8c29..acb7cc3ab0 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs
@@ -1,3 +1,4 @@
+using Godot.NativeInterop;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
@@ -5,35 +6,41 @@ namespace GodotTools.Internals
{
public static class Globals
{
- public static float EditorScale => internal_EditorScale();
-
- public static object GlobalDef(string setting, object defaultValue, bool restartIfChanged = false) =>
- internal_GlobalDef(setting, defaultValue, restartIfChanged);
-
- public static object EditorDef(string setting, object defaultValue, bool restartIfChanged = false) =>
- internal_EditorDef(setting, defaultValue, restartIfChanged);
-
- public static object EditorShortcut(string setting) =>
- internal_EditorShortcut(setting);
+ public static float EditorScale => Internal.godot_icall_Globals_EditorScale();
+
+ public static unsafe object GlobalDef(string setting, object defaultValue, bool restartIfChanged = false)
+ {
+ using godot_string settingIn = Marshaling.ConvertStringToNative(setting);
+ using godot_variant defaultValueIn = Marshaling.ConvertManagedObjectToVariant(defaultValue);
+ Internal.godot_icall_Globals_GlobalDef(settingIn, defaultValueIn, restartIfChanged, out godot_variant result);
+ using (result)
+ return Marshaling.ConvertVariantToManagedObject(result);
+ }
+
+ public static unsafe object EditorDef(string setting, object defaultValue, bool restartIfChanged = false)
+ {
+ using godot_string settingIn = Marshaling.ConvertStringToNative(setting);
+ using godot_variant defaultValueIn = Marshaling.ConvertManagedObjectToVariant(defaultValue);
+ Internal.godot_icall_Globals_EditorDef(settingIn, defaultValueIn, restartIfChanged, out godot_variant result);
+ using (result)
+ return Marshaling.ConvertVariantToManagedObject(result);
+ }
+
+ public static object EditorShortcut(string setting)
+ {
+ using godot_string settingIn = Marshaling.ConvertStringToNative(setting);
+ Internal.godot_icall_Globals_EditorShortcut(settingIn, out godot_variant result);
+ using (result)
+ return Marshaling.ConvertVariantToManagedObject(result);
+ }
[SuppressMessage("ReSharper", "InconsistentNaming")]
- public static string TTR(this string text) => internal_TTR(text);
-
- // Internal Calls
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern float internal_EditorScale();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern object internal_GlobalDef(string setting, object defaultValue, bool restartIfChanged);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern object internal_EditorDef(string setting, object defaultValue, bool restartIfChanged);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern object internal_EditorShortcut(string setting);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_TTR(string text);
+ public static string TTR(this string text)
+ {
+ using godot_string textIn = Marshaling.ConvertStringToNative(text);
+ Internal.godot_icall_Globals_TTR(textIn, out godot_string dest);
+ using (dest)
+ return Marshaling.ConvertStringToManaged(dest);
+ }
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
index 5e70c399b2..14285cc0f1 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
@@ -1,103 +1,125 @@
-using System.Runtime.CompilerServices;
+using System.IO;
+using Godot;
+using Godot.NativeInterop;
+using GodotTools.Core;
+using static GodotTools.Internals.Globals;
namespace GodotTools.Internals
{
public static class GodotSharpDirs
{
- public static string ResDataDir => internal_ResDataDir();
- public static string ResMetadataDir => internal_ResMetadataDir();
- public static string ResAssembliesBaseDir => internal_ResAssembliesBaseDir();
- public static string ResAssembliesDir => internal_ResAssembliesDir();
- public static string ResConfigDir => internal_ResConfigDir();
- public static string ResTempDir => internal_ResTempDir();
- public static string ResTempAssembliesBaseDir => internal_ResTempAssembliesBaseDir();
- public static string ResTempAssembliesDir => internal_ResTempAssembliesDir();
-
- public static string MonoUserDir => internal_MonoUserDir();
- public static string MonoLogsDir => internal_MonoLogsDir();
-
- #region Tools-only
- public static string MonoSolutionsDir => internal_MonoSolutionsDir();
- public static string BuildLogsDirs => internal_BuildLogsDirs();
-
- public static string ProjectSlnPath => internal_ProjectSlnPath();
- public static string ProjectCsProjPath => internal_ProjectCsProjPath();
-
- public static string DataEditorToolsDir => internal_DataEditorToolsDir();
- public static string DataEditorPrebuiltApiDir => internal_DataEditorPrebuiltApiDir();
- #endregion
-
- public static string DataMonoEtcDir => internal_DataMonoEtcDir();
- public static string DataMonoLibDir => internal_DataMonoLibDir();
-
- #region Windows-only
- public static string DataMonoBinDir => internal_DataMonoBinDir();
- #endregion
-
-
- #region Internal
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_ResDataDir();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_ResMetadataDir();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_ResAssembliesBaseDir();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_ResAssembliesDir();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_ResConfigDir();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_ResTempDir();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_ResTempAssembliesBaseDir();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_ResTempAssembliesDir();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_MonoUserDir();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_MonoLogsDir();
-
- #region Tools-only
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_MonoSolutionsDir();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_BuildLogsDirs();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_ProjectSlnPath();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_ProjectCsProjPath();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_DataEditorToolsDir();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_DataEditorPrebuiltApiDir();
- #endregion
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_DataMonoEtcDir();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_DataMonoLibDir();
-
- #region Windows-only
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_DataMonoBinDir();
- #endregion
-
- #endregion
+ public static string ResMetadataDir
+ {
+ get
+ {
+ Internal.godot_icall_GodotSharpDirs_ResMetadataDir(out godot_string dest);
+ using (dest)
+ return Marshaling.ConvertStringToManaged(dest);
+ }
+ }
+
+ public static string MonoUserDir
+ {
+ get
+ {
+ Internal.godot_icall_GodotSharpDirs_MonoUserDir(out godot_string dest);
+ using (dest)
+ return Marshaling.ConvertStringToManaged(dest);
+ }
+ }
+
+ public static string BuildLogsDirs
+ {
+ get
+ {
+ Internal.godot_icall_GodotSharpDirs_BuildLogsDirs(out godot_string dest);
+ using (dest)
+ return Marshaling.ConvertStringToManaged(dest);
+ }
+ }
+
+ public static string DataEditorToolsDir
+ {
+ get
+ {
+ Internal.godot_icall_GodotSharpDirs_DataEditorToolsDir(out godot_string dest);
+ using (dest)
+ return Marshaling.ConvertStringToManaged(dest);
+ }
+ }
+
+ public static void RegisterProjectSettings()
+ {
+ GlobalDef("dotnet/project/assembly_name", "");
+ GlobalDef("dotnet/project/solution_directory", "");
+ GlobalDef("dotnet/project/c#_project_directory", "");
+ }
+
+ private static void DetermineProjectLocation()
+ {
+ static string DetermineProjectName()
+ {
+ string projectAssemblyName = (string)ProjectSettings.GetSetting("application/config/name");
+ projectAssemblyName = projectAssemblyName.ToSafeDirName();
+ if (string.IsNullOrEmpty(projectAssemblyName))
+ projectAssemblyName = "UnnamedProject";
+ return projectAssemblyName;
+ }
+
+ _projectAssemblyName = (string)ProjectSettings.GetSetting("dotnet/project/assembly_name");
+ if (string.IsNullOrEmpty(_projectAssemblyName))
+ {
+ _projectAssemblyName = DetermineProjectName();
+ ProjectSettings.SetSetting("dotnet/project/assembly_name", _projectAssemblyName);
+ }
+
+ string slnParentDir = (string)ProjectSettings.GetSetting("dotnet/project/solution_directory");
+ if (string.IsNullOrEmpty(slnParentDir))
+ slnParentDir = "res://";
+
+ string csprojParentDir = (string)ProjectSettings.GetSetting("dotnet/project/c#_project_directory");
+ if (string.IsNullOrEmpty(csprojParentDir))
+ csprojParentDir = "res://";
+
+ _projectSlnPath = Path.Combine(ProjectSettings.GlobalizePath(slnParentDir),
+ string.Concat(_projectAssemblyName, ".sln"));
+
+ _projectCsProjPath = Path.Combine(ProjectSettings.GlobalizePath(csprojParentDir),
+ string.Concat(_projectAssemblyName, ".csproj"));
+ }
+
+ private static string _projectAssemblyName;
+ private static string _projectSlnPath;
+ private static string _projectCsProjPath;
+
+ public static string ProjectAssemblyName
+ {
+ get
+ {
+ if (_projectAssemblyName == null)
+ DetermineProjectLocation();
+ return _projectAssemblyName;
+ }
+ }
+
+ public static string ProjectSlnPath
+ {
+ get
+ {
+ if (_projectSlnPath == null)
+ DetermineProjectLocation();
+ return _projectSlnPath;
+ }
+ }
+
+ public static string ProjectCsProjPath
+ {
+ get
+ {
+ if (_projectCsProjPath == null)
+ DetermineProjectLocation();
+ return _projectCsProjPath;
+ }
+ }
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
index 12c90178c9..fd810996f7 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Internal.cs
@@ -1,114 +1,161 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using Godot;
+using Godot.NativeInterop;
+using Godot.SourceGenerators.Internal;
using GodotTools.IdeMessaging.Requests;
namespace GodotTools.Internals
{
- public static class Internal
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ [GenerateUnmanagedCallbacks(typeof(InternalUnmanagedCallbacks))]
+ internal static partial class Internal
{
public const string CSharpLanguageType = "CSharpScript";
public const string CSharpLanguageExtension = ".cs";
- public static string UpdateApiAssembliesFromPrebuilt(string config) =>
- internal_UpdateApiAssembliesFromPrebuilt(config);
+ public static string FullExportTemplatesDir
+ {
+ get
+ {
+ godot_icall_Internal_FullExportTemplatesDir(out godot_string dest);
+ using (dest)
+ return Marshaling.ConvertStringToManaged(dest);
+ }
+ }
- public static string FullExportTemplatesDir =>
- internal_FullExportTemplatesDir();
+ public static string SimplifyGodotPath(this string path) => Godot.StringExtensions.SimplifyPath(path);
- public static string SimplifyGodotPath(this string path) => internal_SimplifyGodotPath(path);
+ public static bool IsMacOSAppBundleInstalled(string bundleId)
+ {
+ using godot_string bundleIdIn = Marshaling.ConvertStringToNative(bundleId);
+ return godot_icall_Internal_IsMacOSAppBundleInstalled(bundleIdIn);
+ }
- public static bool IsMacOSAppBundleInstalled(string bundleId) => internal_IsMacOSAppBundleInstalled(bundleId);
+ public static bool GodotIs32Bits() => godot_icall_Internal_GodotIs32Bits();
- public static bool GodotIs32Bits() => internal_GodotIs32Bits();
+ public static bool GodotIsRealTDouble() => godot_icall_Internal_GodotIsRealTDouble();
- public static bool GodotIsRealTDouble() => internal_GodotIsRealTDouble();
+ public static void GodotMainIteration() => godot_icall_Internal_GodotMainIteration();
- public static void GodotMainIteration() => internal_GodotMainIteration();
+ public static bool IsAssembliesReloadingNeeded() => godot_icall_Internal_IsAssembliesReloadingNeeded();
- public static ulong GetCoreApiHash() => internal_GetCoreApiHash();
+ public static void ReloadAssemblies(bool softReload) => godot_icall_Internal_ReloadAssemblies(softReload);
- public static ulong GetEditorApiHash() => internal_GetEditorApiHash();
+ public static void EditorDebuggerNodeReloadScripts() => godot_icall_Internal_EditorDebuggerNodeReloadScripts();
- public static bool IsAssembliesReloadingNeeded() => internal_IsAssembliesReloadingNeeded();
+ public static bool ScriptEditorEdit(Resource resource, int line, int col, bool grabFocus = true) =>
+ godot_icall_Internal_ScriptEditorEdit(resource.NativeInstance, line, col, grabFocus);
- public static void ReloadAssemblies(bool softReload) => internal_ReloadAssemblies(softReload);
+ public static void EditorNodeShowScriptScreen() => godot_icall_Internal_EditorNodeShowScriptScreen();
- public static void EditorDebuggerNodeReloadScripts() => internal_EditorDebuggerNodeReloadScripts();
+ public static void EditorRunPlay() => godot_icall_Internal_EditorRunPlay();
- public static bool ScriptEditorEdit(Resource resource, int line, int col, bool grabFocus = true) =>
- internal_ScriptEditorEdit(resource, line, col, grabFocus);
+ public static void EditorRunStop() => godot_icall_Internal_EditorRunStop();
- public static void EditorNodeShowScriptScreen() => internal_EditorNodeShowScriptScreen();
+ public static void ScriptEditorDebugger_ReloadScripts() =>
+ godot_icall_Internal_ScriptEditorDebugger_ReloadScripts();
- public static string MonoWindowsInstallRoot => internal_MonoWindowsInstallRoot();
+ public static string[] CodeCompletionRequest(CodeCompletionRequest.CompletionKind kind,
+ string scriptFile)
+ {
+ using godot_string scriptFileIn = Marshaling.ConvertStringToNative(scriptFile);
+ godot_icall_Internal_CodeCompletionRequest((int)kind, scriptFileIn, out godot_packed_string_array res);
+ using (res)
+ return Marshaling.ConvertNativePackedStringArrayToSystemArray(res);
+ }
- public static void EditorRunPlay() => internal_EditorRunPlay();
+ #region Internal
- public static void EditorRunStop() => internal_EditorRunStop();
+ private static bool initialized = false;
- public static void ScriptEditorDebugger_ReloadScripts() => internal_ScriptEditorDebugger_ReloadScripts();
+ // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Global
+ internal static unsafe void Initialize(IntPtr unmanagedCallbacks, int unmanagedCallbacksSize)
+ {
+ if (initialized)
+ throw new InvalidOperationException("Already initialized.");
+ initialized = true;
- public static string[] CodeCompletionRequest(CodeCompletionRequest.CompletionKind kind, string scriptFile) =>
- internal_CodeCompletionRequest((int)kind, scriptFile);
+ if (unmanagedCallbacksSize != sizeof(InternalUnmanagedCallbacks))
+ throw new ArgumentException("Unmanaged callbacks size mismatch.", nameof(unmanagedCallbacksSize));
- #region Internal
+ _unmanagedCallbacks = Unsafe.AsRef<InternalUnmanagedCallbacks>((void*)unmanagedCallbacks);
+ }
+
+ private partial struct InternalUnmanagedCallbacks
+ {
+ }
+
+ /*
+ * IMPORTANT:
+ * The order of the methods defined in NativeFuncs must match the order
+ * in the array defined at the bottom of 'editor/editor_internal_calls.cpp'.
+ */
+
+ public static partial void godot_icall_GodotSharpDirs_ResMetadataDir(out godot_string r_dest);
+
+ public static partial void godot_icall_GodotSharpDirs_MonoUserDir(out godot_string r_dest);
+
+ public static partial void godot_icall_GodotSharpDirs_BuildLogsDirs(out godot_string r_dest);
+
+ public static partial void godot_icall_GodotSharpDirs_DataEditorToolsDir(out godot_string r_dest);
+
+ public static partial void godot_icall_EditorProgress_Create(in godot_string task, in godot_string label,
+ int amount, bool canCancel);
+
+ public static partial void godot_icall_EditorProgress_Dispose(in godot_string task);
+
+ public static partial bool godot_icall_EditorProgress_Step(in godot_string task, in godot_string state,
+ int step,
+ bool forceRefresh);
+
+ private static partial void godot_icall_Internal_FullExportTemplatesDir(out godot_string dest);
+
+ private static partial bool godot_icall_Internal_IsMacOSAppBundleInstalled(in godot_string bundleId);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_UpdateApiAssembliesFromPrebuilt(string config);
+ private static partial bool godot_icall_Internal_GodotIs32Bits();
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_FullExportTemplatesDir();
+ private static partial bool godot_icall_Internal_GodotIsRealTDouble();
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_SimplifyGodotPath(this string path);
+ private static partial void godot_icall_Internal_GodotMainIteration();
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool internal_IsMacOSAppBundleInstalled(string bundleId);
+ private static partial bool godot_icall_Internal_IsAssembliesReloadingNeeded();
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool internal_GodotIs32Bits();
+ private static partial void godot_icall_Internal_ReloadAssemblies(bool softReload);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool internal_GodotIsRealTDouble();
+ private static partial void godot_icall_Internal_EditorDebuggerNodeReloadScripts();
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_GodotMainIteration();
+ private static partial bool godot_icall_Internal_ScriptEditorEdit(IntPtr resource, int line, int col,
+ bool grabFocus);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern ulong internal_GetCoreApiHash();
+ private static partial void godot_icall_Internal_EditorNodeShowScriptScreen();
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern ulong internal_GetEditorApiHash();
+ private static partial void godot_icall_Internal_EditorRunPlay();
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool internal_IsAssembliesReloadingNeeded();
+ private static partial void godot_icall_Internal_EditorRunStop();
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_ReloadAssemblies(bool softReload);
+ private static partial void godot_icall_Internal_ScriptEditorDebugger_ReloadScripts();
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_EditorDebuggerNodeReloadScripts();
+ private static partial void godot_icall_Internal_CodeCompletionRequest(int kind, in godot_string scriptFile,
+ out godot_packed_string_array res);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool internal_ScriptEditorEdit(Resource resource, int line, int col, bool grabFocus);
+ public static partial float godot_icall_Globals_EditorScale();
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_EditorNodeShowScriptScreen();
+ public static partial void godot_icall_Globals_GlobalDef(in godot_string setting, in godot_variant defaultValue,
+ bool restartIfChanged, out godot_variant result);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string internal_MonoWindowsInstallRoot();
+ public static partial void godot_icall_Globals_EditorDef(in godot_string setting, in godot_variant defaultValue,
+ bool restartIfChanged, out godot_variant result);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_EditorRunPlay();
+ public static partial void
+ godot_icall_Globals_EditorShortcut(in godot_string setting, out godot_variant result);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_EditorRunStop();
+ public static partial void godot_icall_Globals_TTR(in godot_string text, out godot_string dest);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void internal_ScriptEditorDebugger_ReloadScripts();
+ public static partial void godot_icall_Utils_OS_GetPlatformName(out godot_string dest);
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string[] internal_CodeCompletionRequest(int kind, string scriptFile);
+ public static partial bool godot_icall_Utils_OS_UnixFileHasExecutableAccess(in godot_string filePath);
#endregion
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/FsPathUtils.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/FsPathUtils.cs
index 05499339b1..89bda704bb 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Utils/FsPathUtils.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Utils/FsPathUtils.cs
@@ -1,14 +1,14 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using Godot;
using GodotTools.Core;
-using JetBrains.Annotations;
namespace GodotTools.Utils
{
public static class FsPathUtils
{
- private static readonly string _resourcePath = ProjectSettings.GlobalizePath("res://");
+ private static readonly string ResourcePath = ProjectSettings.GlobalizePath("res://");
private static bool PathStartsWithAlreadyNorm(this string childPath, string parentPath)
{
@@ -30,11 +30,11 @@ namespace GodotTools.Utils
return childPathNorm.PathStartsWithAlreadyNorm(parentPathNorm);
}
- [CanBeNull]
+ [return: MaybeNull]
public static string LocalizePathWithCaseChecked(string path)
{
string pathNorm = path.NormalizePath() + Path.DirectorySeparatorChar;
- string resourcePathNorm = _resourcePath.NormalizePath() + Path.DirectorySeparatorChar;
+ string resourcePathNorm = ResourcePath.NormalizePath() + Path.DirectorySeparatorChar;
if (!pathNorm.PathStartsWithAlreadyNorm(resourcePathNorm))
return null;
diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
index 5cef6e5c3c..c16f803226 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
@@ -1,24 +1,24 @@
+using Godot.NativeInterop;
using System;
using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
-using System.Runtime.CompilerServices;
-using JetBrains.Annotations;
+using System.Runtime.Versioning;
+using System.Text;
+using GodotTools.Internals;
namespace GodotTools.Utils
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
public static class OS
{
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string GetPlatformName();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool UnixFileHasExecutableAccess(string filePath);
-
- public static class Names
+ /// <summary>
+ /// Display names for the OS platforms.
+ /// </summary>
+ private static class Names
{
public const string Windows = "Windows";
public const string MacOS = "macOS";
@@ -26,27 +26,58 @@ namespace GodotTools.Utils
public const string FreeBSD = "FreeBSD";
public const string NetBSD = "NetBSD";
public const string BSD = "BSD";
- public const string Server = "Server";
public const string UWP = "UWP";
public const string Haiku = "Haiku";
public const string Android = "Android";
public const string iOS = "iOS";
- public const string HTML5 = "HTML5";
+ public const string Web = "Web";
}
+ /// <summary>
+ /// Godot platform identifiers.
+ /// </summary>
public static class Platforms
{
public const string Windows = "windows";
public const string MacOS = "macos";
public const string LinuxBSD = "linuxbsd";
- public const string Server = "server";
public const string UWP = "uwp";
public const string Haiku = "haiku";
public const string Android = "android";
public const string iOS = "ios";
- public const string HTML5 = "javascript";
+ public const string Web = "web";
+ }
+
+ /// <summary>
+ /// OS name part of the .NET runtime identifier (RID).
+ /// See https://docs.microsoft.com/en-us/dotnet/core/rid-catalog.
+ /// </summary>
+ public static class DotNetOS
+ {
+ public const string Win = "win";
+ public const string OSX = "osx";
+ public const string Linux = "linux";
+ public const string Win10 = "win10";
+ public const string Android = "android";
+ public const string iOS = "ios";
+ public const string Browser = "browser";
}
+ public static readonly Dictionary<string, string> PlatformFeatureMap = new Dictionary<string, string>(
+ // Export `features` may be in lower case
+ StringComparer.InvariantCultureIgnoreCase
+ )
+ {
+ ["Windows"] = Platforms.Windows,
+ ["macOS"] = Platforms.MacOS,
+ ["Linux"] = Platforms.LinuxBSD,
+ ["UWP"] = Platforms.UWP,
+ ["Haiku"] = Platforms.Haiku,
+ ["Android"] = Platforms.Android,
+ ["iOS"] = Platforms.iOS,
+ ["Web"] = Platforms.Web
+ };
+
public static readonly Dictionary<string, string> PlatformNameMap = new Dictionary<string, string>
{
[Names.Windows] = Platforms.Windows,
@@ -55,55 +86,85 @@ namespace GodotTools.Utils
[Names.FreeBSD] = Platforms.LinuxBSD,
[Names.NetBSD] = Platforms.LinuxBSD,
[Names.BSD] = Platforms.LinuxBSD,
- [Names.Server] = Platforms.Server,
[Names.UWP] = Platforms.UWP,
[Names.Haiku] = Platforms.Haiku,
[Names.Android] = Platforms.Android,
[Names.iOS] = Platforms.iOS,
- [Names.HTML5] = Platforms.HTML5
+ [Names.Web] = Platforms.Web
+ };
+
+ public static readonly Dictionary<string, string> DotNetOSPlatformMap = new Dictionary<string, string>
+ {
+ [Platforms.Windows] = DotNetOS.Win,
+ [Platforms.MacOS] = DotNetOS.OSX,
+ // TODO:
+ // Does .NET 6 support BSD variants? If it does, it may need the name `unix`
+ // instead of `linux` in the runtime identifier. This would be a problem as
+ // Godot has a single export profile for both, named LinuxBSD.
+ [Platforms.LinuxBSD] = DotNetOS.Linux,
+ [Platforms.UWP] = DotNetOS.Win10,
+ [Platforms.Android] = DotNetOS.Android,
+ [Platforms.iOS] = DotNetOS.iOS,
+ [Platforms.Web] = DotNetOS.Browser
};
private static bool IsOS(string name)
{
- return name.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase);
+ Internal.godot_icall_Utils_OS_GetPlatformName(out godot_string dest);
+ using (dest)
+ {
+ string platformName = Marshaling.ConvertStringToManaged(dest);
+ return name.Equals(platformName, StringComparison.OrdinalIgnoreCase);
+ }
}
private static bool IsAnyOS(IEnumerable<string> names)
{
- return names.Any(p => p.Equals(GetPlatformName(), StringComparison.OrdinalIgnoreCase));
+ Internal.godot_icall_Utils_OS_GetPlatformName(out godot_string dest);
+ using (dest)
+ {
+ string platformName = Marshaling.ConvertStringToManaged(dest);
+ return names.Any(p => p.Equals(platformName, StringComparison.OrdinalIgnoreCase));
+ }
}
private static readonly IEnumerable<string> LinuxBSDPlatforms =
new[] { Names.Linux, Names.FreeBSD, Names.NetBSD, Names.BSD };
private static readonly IEnumerable<string> UnixLikePlatforms =
- new[] { Names.MacOS, Names.Server, Names.Haiku, Names.Android, Names.iOS }
+ new[] { Names.MacOS, Names.Haiku, Names.Android, Names.iOS }
.Concat(LinuxBSDPlatforms).ToArray();
- private static readonly Lazy<bool> _isWindows = new Lazy<bool>(() => IsOS(Names.Windows));
- private static readonly Lazy<bool> _isMacOS = new Lazy<bool>(() => IsOS(Names.MacOS));
- private static readonly Lazy<bool> _isLinuxBSD = new Lazy<bool>(() => IsAnyOS(LinuxBSDPlatforms));
- private static readonly Lazy<bool> _isServer = new Lazy<bool>(() => IsOS(Names.Server));
- private static readonly Lazy<bool> _isUWP = new Lazy<bool>(() => IsOS(Names.UWP));
- private static readonly Lazy<bool> _isHaiku = new Lazy<bool>(() => IsOS(Names.Haiku));
- private static readonly Lazy<bool> _isAndroid = new Lazy<bool>(() => IsOS(Names.Android));
- private static readonly Lazy<bool> _isiOS = new Lazy<bool>(() => IsOS(Names.iOS));
- private static readonly Lazy<bool> _isHTML5 = new Lazy<bool>(() => IsOS(Names.HTML5));
- private static readonly Lazy<bool> _isUnixLike = new Lazy<bool>(() => IsAnyOS(UnixLikePlatforms));
-
- public static bool IsWindows => _isWindows.Value || IsUWP;
- public static bool IsMacOS => _isMacOS.Value;
- public static bool IsLinuxBSD => _isLinuxBSD.Value;
- public static bool IsServer => _isServer.Value;
- public static bool IsUWP => _isUWP.Value;
+ private static readonly Lazy<bool> _isWindows = new(() => IsOS(Names.Windows));
+ private static readonly Lazy<bool> _isMacOS = new(() => IsOS(Names.MacOS));
+ private static readonly Lazy<bool> _isLinuxBSD = new(() => IsAnyOS(LinuxBSDPlatforms));
+ private static readonly Lazy<bool> _isUWP = new(() => IsOS(Names.UWP));
+ private static readonly Lazy<bool> _isHaiku = new(() => IsOS(Names.Haiku));
+ private static readonly Lazy<bool> _isAndroid = new(() => IsOS(Names.Android));
+ private static readonly Lazy<bool> _isiOS = new(() => IsOS(Names.iOS));
+ private static readonly Lazy<bool> _isWeb = new(() => IsOS(Names.Web));
+ private static readonly Lazy<bool> _isUnixLike = new(() => IsAnyOS(UnixLikePlatforms));
+
+ [SupportedOSPlatformGuard("windows")] public static bool IsWindows => _isWindows.Value || IsUWP;
+
+ [SupportedOSPlatformGuard("osx")] public static bool IsMacOS => _isMacOS.Value;
+
+ [SupportedOSPlatformGuard("linux")] public static bool IsLinuxBSD => _isLinuxBSD.Value;
+
+ [SupportedOSPlatformGuard("windows")] public static bool IsUWP => _isUWP.Value;
+
public static bool IsHaiku => _isHaiku.Value;
- public static bool IsAndroid => _isAndroid.Value;
- public static bool IsiOS => _isiOS.Value;
- public static bool IsHTML5 => _isHTML5.Value;
+
+ [SupportedOSPlatformGuard("android")] public static bool IsAndroid => _isAndroid.Value;
+
+ [SupportedOSPlatformGuard("ios")] public static bool IsiOS => _isiOS.Value;
+
+ [SupportedOSPlatformGuard("browser")] public static bool IsWeb => _isWeb.Value;
public static bool IsUnixLike => _isUnixLike.Value;
public static char PathSep => IsWindows ? ';' : ':';
+ [return: MaybeNull]
public static string PathWhich([NotNull] string name)
{
if (IsWindows)
@@ -112,9 +173,11 @@ namespace GodotTools.Utils
return PathWhichUnix(name);
}
+ [return: MaybeNull]
private static string PathWhichWindows([NotNull] string name)
{
- string[] windowsExts = Environment.GetEnvironmentVariable("PATHEXT")?.Split(PathSep) ?? Array.Empty<string>();
+ string[] windowsExts =
+ Environment.GetEnvironmentVariable("PATHEXT")?.Split(PathSep) ?? Array.Empty<string>();
string[] pathDirs = Environment.GetEnvironmentVariable("PATH")?.Split(PathSep);
char[] invalidPathChars = Path.GetInvalidPathChars();
@@ -133,7 +196,7 @@ namespace GodotTools.Utils
string nameExt = Path.GetExtension(name);
bool hasPathExt = !string.IsNullOrEmpty(nameExt) &&
- windowsExts.Contains(nameExt, StringComparer.OrdinalIgnoreCase);
+ windowsExts.Contains(nameExt, StringComparer.OrdinalIgnoreCase);
searchDirs.Add(System.IO.Directory.GetCurrentDirectory()); // last in the list
@@ -147,6 +210,7 @@ namespace GodotTools.Utils
select path + ext).FirstOrDefault(File.Exists);
}
+ [return: MaybeNull]
private static string PathWhichUnix([NotNull] string name)
{
string[] pathDirs = Environment.GetEnvironmentVariable("PATH")?.Split(PathSep);
@@ -168,19 +232,16 @@ namespace GodotTools.Utils
searchDirs.Add(System.IO.Directory.GetCurrentDirectory()); // last in the list
return searchDirs.Select(dir => Path.Combine(dir, name))
- .FirstOrDefault(path => File.Exists(path) && UnixFileHasExecutableAccess(path));
+ .FirstOrDefault(path =>
+ {
+ using godot_string pathIn = Marshaling.ConvertStringToNative(path);
+ return File.Exists(path) && Internal.godot_icall_Utils_OS_UnixFileHasExecutableAccess(pathIn);
+ });
}
public static void RunProcess(string command, IEnumerable<string> arguments)
{
- // TODO: Once we move to .NET Standard 2.1 we can use ProcessStartInfo.ArgumentList instead
- string CmdLineArgsToString(IEnumerable<string> args)
- {
- // Not perfect, but as long as we are careful...
- return string.Join(" ", args.Select(arg => arg.Contains(" ") ? $@"""{arg}""" : arg));
- }
-
- var startInfo = new ProcessStartInfo(command, CmdLineArgsToString(arguments))
+ var startInfo = new ProcessStartInfo(command)
{
RedirectStandardOutput = true,
RedirectStandardError = true,
@@ -188,44 +249,104 @@ namespace GodotTools.Utils
CreateNoWindow = true
};
- using (Process process = Process.Start(startInfo))
- {
- if (process == null)
- throw new Exception("No process was started");
+ foreach (string arg in arguments)
+ startInfo.ArgumentList.Add(arg);
- process.BeginOutputReadLine();
- process.BeginErrorReadLine();
- if (IsWindows && process.Id > 0)
- User32Dll.AllowSetForegroundWindow(process.Id); // allows application to focus itself
- }
+ using Process process = Process.Start(startInfo);
+
+ if (process == null)
+ throw new InvalidOperationException("No process was started.");
+
+ process.BeginOutputReadLine();
+ process.BeginErrorReadLine();
+
+ if (IsWindows && process.Id > 0)
+ User32Dll.AllowSetForegroundWindow(process.Id); // Allows application to focus itself
}
public static int ExecuteCommand(string command, IEnumerable<string> arguments)
{
- // TODO: Once we move to .NET Standard 2.1 we can use ProcessStartInfo.ArgumentList instead
- string CmdLineArgsToString(IEnumerable<string> args)
+ var startInfo = new ProcessStartInfo(command)
{
- // Not perfect, but as long as we are careful...
- return string.Join(" ", args.Select(arg => arg.Contains(" ") ? $@"""{arg}""" : arg));
- }
+ // Print the output
+ RedirectStandardOutput = false,
+ RedirectStandardError = false,
+ UseShellExecute = false
+ };
+
+ foreach (string arg in arguments)
+ startInfo.ArgumentList.Add(arg);
- var startInfo = new ProcessStartInfo(command, CmdLineArgsToString(arguments));
+ Console.WriteLine(startInfo.GetCommandLineDisplay(new StringBuilder("Executing: ")).ToString());
- Console.WriteLine($"Executing: \"{startInfo.FileName}\" {startInfo.Arguments}");
+ using var process = new Process { StartInfo = startInfo };
+ process.Start();
+ process.WaitForExit();
+
+ return process.ExitCode;
+ }
- // Print the output
- startInfo.RedirectStandardOutput = false;
- startInfo.RedirectStandardError = false;
+ private static void AppendProcessFileNameForDisplay(this StringBuilder builder, string fileName)
+ {
+ if (builder.Length > 0)
+ builder.Append(' ');
+
+ if (fileName.Contains(' '))
+ {
+ builder.Append('"');
+ builder.Append(fileName);
+ builder.Append('"');
+ }
+ else
+ {
+ builder.Append(fileName);
+ }
+ }
- startInfo.UseShellExecute = false;
+ private static void AppendProcessArgumentsForDisplay(this StringBuilder builder,
+ Collection<string> argumentList)
+ {
+ // This is intended just for reading. It doesn't need to be a valid command line.
+ // E.g.: We don't handle escaping of quotes.
- using (var process = new Process { StartInfo = startInfo })
+ foreach (string argument in argumentList)
{
- process.Start();
- process.WaitForExit();
+ if (builder.Length > 0)
+ builder.Append(' ');
- return process.ExitCode;
+ if (argument.Contains(' '))
+ {
+ builder.Append('"');
+ builder.Append(argument);
+ builder.Append('"');
+ }
+ else
+ {
+ builder.Append(argument);
+ }
}
}
+
+ public static StringBuilder GetCommandLineDisplay(
+ this ProcessStartInfo startInfo,
+ StringBuilder optionalBuilder = null
+ )
+ {
+ var builder = optionalBuilder ?? new StringBuilder();
+
+ builder.AppendProcessFileNameForDisplay(startInfo.FileName);
+
+ if (startInfo.ArgumentList.Count == 0)
+ {
+ builder.Append(' ');
+ builder.Append(startInfo.Arguments);
+ }
+ else
+ {
+ builder.AppendProcessArgumentsForDisplay(startInfo.ArgumentList);
+ }
+
+ return builder;
+ }
}
}
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 2e628cb576..0e496454a1 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -41,69 +41,99 @@
#include "core/string/ucaps.h"
#include "main/main.h"
-#include "../glue/cs_glue_version.gen.h"
#include "../godotsharp_defs.h"
-#include "../mono_gd/gd_mono_marshal.h"
#include "../utils/path_utils.h"
#include "../utils/string_utils.h"
+StringBuilder &operator<<(StringBuilder &r_sb, const String &p_string) {
+ r_sb.append(p_string);
+ return r_sb;
+}
+
+StringBuilder &operator<<(StringBuilder &r_sb, const char *p_cstring) {
+ r_sb.append(p_cstring);
+ return r_sb;
+}
+
#define CS_INDENT " " // 4 whitespaces
#define INDENT1 CS_INDENT
#define INDENT2 INDENT1 INDENT1
#define INDENT3 INDENT2 INDENT1
#define INDENT4 INDENT3 INDENT1
-#define INDENT5 INDENT4 INDENT1
-#define MEMBER_BEGIN "\n" INDENT2
+#define MEMBER_BEGIN "\n" INDENT1
#define OPEN_BLOCK "{\n"
#define CLOSE_BLOCK "}\n"
-#define OPEN_BLOCK_L2 INDENT2 OPEN_BLOCK INDENT3
-#define OPEN_BLOCK_L3 INDENT3 OPEN_BLOCK INDENT4
+#define OPEN_BLOCK_L1 INDENT1 OPEN_BLOCK
+#define OPEN_BLOCK_L2 INDENT2 OPEN_BLOCK
+#define CLOSE_BLOCK_L1 INDENT1 CLOSE_BLOCK
#define CLOSE_BLOCK_L2 INDENT2 CLOSE_BLOCK
#define CLOSE_BLOCK_L3 INDENT3 CLOSE_BLOCK
-#define CS_FIELD_MEMORYOWN "memoryOwn"
+#define BINDINGS_GLOBAL_SCOPE_CLASS "GD"
+#define BINDINGS_NATIVE_NAME_FIELD "NativeName"
+
+#define CS_PARAM_MEMORYOWN "memoryOwn"
#define CS_PARAM_METHODBIND "method"
#define CS_PARAM_INSTANCE "ptr"
-#define CS_SMETHOD_GETINSTANCE "GetPtr"
+#define CS_STATIC_METHOD_GETINSTANCE "GetPtr"
#define CS_METHOD_CALL "Call"
+#define CS_PROPERTY_SINGLETON "Singleton"
+#define CS_METHOD_INVOKE_GODOT_CLASS_METHOD "InvokeGodotClassMethod"
+#define CS_METHOD_HAS_GODOT_CLASS_METHOD "HasGodotClassMethod"
+
+#define CS_STATIC_FIELD_NATIVE_CTOR "NativeCtor"
+#define CS_STATIC_FIELD_METHOD_BIND_PREFIX "MethodBind"
+#define CS_STATIC_FIELD_METHOD_PROXY_NAME_PREFIX "MethodProxyName_"
-#define GLUE_HEADER_FILE "glue_header.h"
#define ICALL_PREFIX "godot_icall_"
-#define SINGLETON_ICALL_SUFFIX "_get_singleton"
-#define ICALL_GET_METHODBIND "__ClassDB_get_method"
+#define ICALL_CLASSDB_GET_METHOD "ClassDB_get_method"
+#define ICALL_CLASSDB_GET_CONSTRUCTOR "ClassDB_get_constructor"
#define C_LOCAL_RET "ret"
#define C_LOCAL_VARARG_RET "vararg_ret"
#define C_LOCAL_PTRCALL_ARGS "call_args"
-#define C_MACRO_OBJECT_CONSTRUCT "GODOTSHARP_INSTANCE_OBJECT"
-
-#define C_NS_MONOUTILS "GDMonoUtils"
-#define C_NS_MONOINTERNALS "GDMonoInternals"
-#define C_METHOD_TIE_MANAGED_TO_UNMANAGED C_NS_MONOINTERNALS "::tie_managed_to_unmanaged"
-#define C_METHOD_UNMANAGED_GET_MANAGED C_NS_MONOUTILS "::unmanaged_get_managed"
-
-#define C_NS_MONOMARSHAL "GDMonoMarshal"
-#define C_METHOD_MANAGED_TO_VARIANT C_NS_MONOMARSHAL "::mono_object_to_variant"
-#define C_METHOD_MANAGED_FROM_VARIANT C_NS_MONOMARSHAL "::variant_to_mono_object"
-#define C_METHOD_MONOSTR_TO_GODOT C_NS_MONOMARSHAL "::mono_string_to_godot"
-#define C_METHOD_MONOSTR_FROM_GODOT C_NS_MONOMARSHAL "::mono_string_from_godot"
-#define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL "::mono_array_to_" #m_type
-#define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "::" #m_type "_to_mono_array"
-#define C_METHOD_MANAGED_TO_CALLABLE C_NS_MONOMARSHAL "::managed_to_callable"
-#define C_METHOD_MANAGED_FROM_CALLABLE C_NS_MONOMARSHAL "::callable_to_managed"
-#define C_METHOD_MANAGED_TO_SIGNAL C_NS_MONOMARSHAL "::signal_info_to_callable"
-#define C_METHOD_MANAGED_FROM_SIGNAL C_NS_MONOMARSHAL "::callable_to_signal_info"
-
-#define BINDINGS_GENERATOR_VERSION UINT32_C(13)
+
+#define C_CLASS_NATIVE_FUNCS "NativeFuncs"
+#define C_NS_MONOUTILS "InteropUtils"
+#define C_METHOD_UNMANAGED_GET_MANAGED C_NS_MONOUTILS ".UnmanagedGetManaged"
+#define C_METHOD_ENGINE_GET_SINGLETON C_NS_MONOUTILS ".EngineGetSingleton"
+
+#define C_NS_MONOMARSHAL "Marshaling"
+#define C_METHOD_MONOSTR_TO_GODOT C_NS_MONOMARSHAL ".ConvertStringToNative"
+#define C_METHOD_MONOSTR_FROM_GODOT C_NS_MONOMARSHAL ".ConvertStringToManaged"
+#define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL ".ConvertSystemArrayToNative" #m_type
+#define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL ".ConvertNative" #m_type "ToSystemArray"
+#define C_METHOD_MANAGED_TO_CALLABLE C_NS_MONOMARSHAL ".ConvertCallableToNative"
+#define C_METHOD_MANAGED_FROM_CALLABLE C_NS_MONOMARSHAL ".ConvertCallableToManaged"
+#define C_METHOD_MANAGED_TO_SIGNAL C_NS_MONOMARSHAL ".ConvertSignalToNative"
+#define C_METHOD_MANAGED_FROM_SIGNAL C_NS_MONOMARSHAL ".ConvertSignalToManaged"
// Types that will be ignored by the generator and won't be available in C#.
const Vector<String> ignored_types = { "PhysicsServer3DExtension" };
-const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN("\t%0 %1_in = %1;\n");
+void BindingsGenerator::TypeInterface::postsetup_enum_type(BindingsGenerator::TypeInterface &r_enum_itype) {
+ // C interface for enums is the same as that of 'uint32_t'. Remember to apply
+ // any of the changes done here to the 'uint32_t' type interface as well.
+
+ r_enum_itype.cs_type = r_enum_itype.proxy_name;
+ r_enum_itype.cs_in_expr = "(int)%0";
+ r_enum_itype.cs_out = "%5return (%2)%0(%1);";
+
+ {
+ // The expected types for parameters and return value in ptrcall are 'int64_t' or 'uint64_t'.
+ r_enum_itype.c_in = "%5%0 %1_in = %1;\n";
+ r_enum_itype.c_out = "%5return (%0)%1;\n";
+ r_enum_itype.c_type = "long";
+ r_enum_itype.c_arg_in = "&%s_in";
+ }
+ r_enum_itype.c_type_in = "int";
+ r_enum_itype.c_type_out = r_enum_itype.c_type_in;
+ r_enum_itype.class_doc = &EditorHelp::get_doc_data()->class_list[r_enum_itype.proxy_name];
+}
static String fix_doc_description(const String &p_bbcode) {
// This seems to be the correct way to do this. It's the same EditorHelp does.
@@ -359,23 +389,23 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
xml_output.append(tag);
xml_output.append("</c>");
} else if (tag == "PackedByteArray") {
- xml_output.append("<see cref=\"T:byte[]\"/>");
+ xml_output.append("<see cref=\"byte\"/>[]");
} else if (tag == "PackedInt32Array") {
- xml_output.append("<see cref=\"T:int[]\"/>");
+ xml_output.append("<see cref=\"int\"/>[]");
} else if (tag == "PackedInt64Array") {
- xml_output.append("<see cref=\"T:long[]\"/>");
+ xml_output.append("<see cref=\"long\"/>[]");
} else if (tag == "PackedFloat32Array") {
- xml_output.append("<see cref=\"T:float[]\"/>");
+ xml_output.append("<see cref=\"float\"/>[]");
} else if (tag == "PackedFloat64Array") {
- xml_output.append("<see cref=\"T:double[]\"/>");
+ xml_output.append("<see cref=\"double\"/>[]");
} else if (tag == "PackedStringArray") {
- xml_output.append("<see cref=\"T:string[]\"/>");
+ xml_output.append("<see cref=\"string\"/>[]");
} else if (tag == "PackedVector2Array") {
- xml_output.append("<see cref=\"T:" BINDINGS_NAMESPACE ".Vector2[]\"/>");
+ xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Vector2\"/>[]");
} else if (tag == "PackedVector3Array") {
- xml_output.append("<see cref=\"T:" BINDINGS_NAMESPACE ".Vector3[]\"/>");
+ xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Vector3\"/>[]");
} else if (tag == "PackedColorArray") {
- xml_output.append("<see cref=\"T:" BINDINGS_NAMESPACE ".Color[]\"/>");
+ xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Color\"/>[]");
} else {
const TypeInterface *target_itype = _get_type_or_null(TypeReference(tag));
@@ -794,49 +824,28 @@ void BindingsGenerator::_apply_prefix_to_enum_constants(BindingsGenerator::EnumI
}
}
-void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
+Error BindingsGenerator::_populate_method_icalls_table(const TypeInterface &p_itype) {
for (const MethodInterface &imethod : p_itype.methods) {
if (imethod.is_virtual) {
continue;
}
- const TypeInterface *return_type = _get_type_or_placeholder(imethod.return_type);
+ const TypeInterface *return_type = _get_type_or_null(imethod.return_type);
+ ERR_FAIL_NULL_V(return_type, ERR_BUG); // Return type not found
- String im_sig = "IntPtr " CS_PARAM_METHODBIND;
- String im_unique_sig = imethod.return_type.cname.operator String() + ",IntPtr";
+ String im_unique_sig = get_ret_unique_sig(return_type) + ",CallMethodBind";
if (!imethod.is_static) {
- im_sig += ", IntPtr " CS_PARAM_INSTANCE;
- im_unique_sig += ",IntPtr";
+ im_unique_sig += ",CallInstance";
}
// Get arguments information
- int i = 0;
for (const ArgumentInterface &iarg : imethod.arguments) {
- const TypeInterface *arg_type = _get_type_or_placeholder(iarg.type);
-
- im_sig += ", ";
- im_sig += arg_type->im_type_in;
- im_sig += " arg";
- im_sig += itos(i + 1);
+ const TypeInterface *arg_type = _get_type_or_null(iarg.type);
+ ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Argument type not found
im_unique_sig += ",";
- im_unique_sig += get_unique_sig(*arg_type);
-
- i++;
- }
-
- String im_type_out = return_type->im_type_out;
-
- if (return_type->ret_as_byref_arg) {
- // Doesn't affect the unique signature
- im_type_out = "void";
-
- im_sig += ", ";
- im_sig += return_type->im_type_out;
- im_sig += " argRet";
-
- i++;
+ im_unique_sig += get_arg_unique_sig(*arg_type);
}
// godot_icall_{argc}_{icallcount}
@@ -845,7 +854,15 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
icall_method += "_";
icall_method += itos(method_icalls.size());
- InternalCall im_icall = InternalCall(p_itype.api_type, icall_method, im_type_out, im_sig, im_unique_sig);
+ InternalCall im_icall = InternalCall(p_itype.api_type, icall_method, im_unique_sig);
+
+ im_icall.is_vararg = imethod.is_vararg;
+ im_icall.is_static = imethod.is_static;
+ im_icall.return_type = imethod.return_type;
+
+ for (const List<ArgumentInterface>::Element *F = imethod.arguments.front(); F; F = F->next()) {
+ im_icall.argument_types.push_back(F->get().type);
+ }
List<InternalCall>::Element *match = method_icalls.find(im_icall);
@@ -859,47 +876,49 @@ void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
method_icalls_map.insert(&imethod, &added->get());
}
}
+
+ return OK;
}
void BindingsGenerator::_generate_array_extensions(StringBuilder &p_output) {
+ p_output.append("namespace " BINDINGS_NAMESPACE ";\n\n");
p_output.append("using System;\n\n");
- p_output.append("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
// The class where we put the extensions doesn't matter, so just use "GD".
- p_output.append(INDENT1 "public static partial class " BINDINGS_GLOBAL_SCOPE_CLASS "\n" INDENT1 "{");
+ p_output.append("public static partial class " BINDINGS_GLOBAL_SCOPE_CLASS "\n{");
#define ARRAY_IS_EMPTY(m_type) \
- p_output.append("\n" INDENT2 "/// <summary>\n"); \
- p_output.append(INDENT2 "/// Returns true if this " #m_type " array is empty or doesn't exist.\n"); \
- p_output.append(INDENT2 "/// </summary>\n"); \
- p_output.append(INDENT2 "/// <param name=\"instance\">The " #m_type " array check.</param>\n"); \
- p_output.append(INDENT2 "/// <returns>Whether or not the array is empty.</returns>\n"); \
- p_output.append(INDENT2 "public static bool IsEmpty(this " #m_type "[] instance)\n"); \
- p_output.append(INDENT2 OPEN_BLOCK); \
- p_output.append(INDENT3 "return instance == null || instance.Length == 0;\n"); \
- p_output.append(INDENT2 CLOSE_BLOCK);
+ p_output.append("\n" INDENT1 "/// <summary>\n"); \
+ p_output.append(INDENT1 "/// Returns true if this " #m_type " array is empty or doesn't exist.\n"); \
+ p_output.append(INDENT1 "/// </summary>\n"); \
+ p_output.append(INDENT1 "/// <param name=\"instance\">The " #m_type " array check.</param>\n"); \
+ p_output.append(INDENT1 "/// <returns>Whether or not the array is empty.</returns>\n"); \
+ p_output.append(INDENT1 "public static bool IsEmpty(this " #m_type "[] instance)\n"); \
+ p_output.append(OPEN_BLOCK_L1); \
+ p_output.append(INDENT2 "return instance == null || instance.Length == 0;\n"); \
+ p_output.append(INDENT1 CLOSE_BLOCK);
#define ARRAY_JOIN(m_type) \
- p_output.append("\n" INDENT2 "/// <summary>\n"); \
- p_output.append(INDENT2 "/// Converts this " #m_type " array to a string delimited by the given string.\n"); \
- p_output.append(INDENT2 "/// </summary>\n"); \
- p_output.append(INDENT2 "/// <param name=\"instance\">The " #m_type " array to convert.</param>\n"); \
- p_output.append(INDENT2 "/// <param name=\"delimiter\">The delimiter to use between items.</param>\n"); \
- p_output.append(INDENT2 "/// <returns>A single string with all items.</returns>\n"); \
- p_output.append(INDENT2 "public static string Join(this " #m_type "[] instance, string delimiter = \", \")\n"); \
- p_output.append(INDENT2 OPEN_BLOCK); \
- p_output.append(INDENT3 "return String.Join(delimiter, instance);\n"); \
- p_output.append(INDENT2 CLOSE_BLOCK);
+ p_output.append("\n" INDENT1 "/// <summary>\n"); \
+ p_output.append(INDENT1 "/// Converts this " #m_type " array to a string delimited by the given string.\n"); \
+ p_output.append(INDENT1 "/// </summary>\n"); \
+ p_output.append(INDENT1 "/// <param name=\"instance\">The " #m_type " array to convert.</param>\n"); \
+ p_output.append(INDENT1 "/// <param name=\"delimiter\">The delimiter to use between items.</param>\n"); \
+ p_output.append(INDENT1 "/// <returns>A single string with all items.</returns>\n"); \
+ p_output.append(INDENT1 "public static string Join(this " #m_type "[] instance, string delimiter = \", \")\n"); \
+ p_output.append(OPEN_BLOCK_L1); \
+ p_output.append(INDENT2 "return String.Join(delimiter, instance);\n"); \
+ p_output.append(INDENT1 CLOSE_BLOCK);
#define ARRAY_STRINGIFY(m_type) \
- p_output.append("\n" INDENT2 "/// <summary>\n"); \
- p_output.append(INDENT2 "/// Converts this " #m_type " array to a string with brackets.\n"); \
- p_output.append(INDENT2 "/// </summary>\n"); \
- p_output.append(INDENT2 "/// <param name=\"instance\">The " #m_type " array to convert.</param>\n"); \
- p_output.append(INDENT2 "/// <returns>A single string with all items.</returns>\n"); \
- p_output.append(INDENT2 "public static string Stringify(this " #m_type "[] instance)\n"); \
- p_output.append(INDENT2 OPEN_BLOCK); \
- p_output.append(INDENT3 "return \"[\" + instance.Join() + \"]\";\n"); \
- p_output.append(INDENT2 CLOSE_BLOCK);
+ p_output.append("\n" INDENT1 "/// <summary>\n"); \
+ p_output.append(INDENT1 "/// Converts this " #m_type " array to a string with brackets.\n"); \
+ p_output.append(INDENT1 "/// </summary>\n"); \
+ p_output.append(INDENT1 "/// <param name=\"instance\">The " #m_type " array to convert.</param>\n"); \
+ p_output.append(INDENT1 "/// <returns>A single string with all items.</returns>\n"); \
+ p_output.append(INDENT1 "public static string Stringify(this " #m_type "[] instance)\n"); \
+ p_output.append(OPEN_BLOCK_L1); \
+ p_output.append(INDENT2 "return \"[\" + instance.Join() + \"]\";\n"); \
+ p_output.append(INDENT1 CLOSE_BLOCK);
#define ARRAY_ALL(m_type) \
ARRAY_IS_EMPTY(m_type) \
@@ -925,18 +944,18 @@ void BindingsGenerator::_generate_array_extensions(StringBuilder &p_output) {
#undef ARRAY_JOIN
#undef ARRAY_STRINGIFY
- p_output.append(INDENT1 CLOSE_BLOCK); // End of GD class.
- p_output.append(CLOSE_BLOCK); // End of namespace.
+ p_output.append(CLOSE_BLOCK); // End of GD class.
}
void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
// Constants (in partial GD class)
+ p_output.append("namespace " BINDINGS_NAMESPACE ";\n\n");
+
p_output.append("\n#pragma warning disable CS1591 // Disable warning: "
"'Missing XML comment for publicly visible type or member'\n");
- p_output.append("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
- p_output.append(INDENT1 "public static partial class " BINDINGS_GLOBAL_SCOPE_CLASS "\n" INDENT1 "{");
+ p_output.append("public static partial class " BINDINGS_GLOBAL_SCOPE_CLASS "\n{");
for (const ConstantInterface &iconstant : global_constants) {
if (iconstant.const_doc && iconstant.const_doc->description.size()) {
@@ -947,12 +966,12 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
p_output.append(MEMBER_BEGIN "/// <summary>\n");
for (int i = 0; i < summary_lines.size(); i++) {
- p_output.append(INDENT2 "/// ");
+ p_output.append(INDENT1 "/// ");
p_output.append(summary_lines[i]);
p_output.append("\n");
}
- p_output.append(INDENT2 "/// </summary>");
+ p_output.append(INDENT1 "/// </summary>");
}
}
@@ -967,7 +986,7 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
p_output.append("\n");
}
- p_output.append(INDENT1 CLOSE_BLOCK); // end of GD class
+ p_output.append(CLOSE_BLOCK); // end of GD class
// Enums
@@ -985,21 +1004,21 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
CRASH_COND(enum_class_name != "Variant"); // Hard-coded...
- _log("Declaring global enum '%s' inside static class '%s'\n", enum_proxy_name.utf8().get_data(), enum_class_name.utf8().get_data());
+ _log("Declaring global enum '%s' inside struct '%s'\n", enum_proxy_name.utf8().get_data(), enum_class_name.utf8().get_data());
- p_output.append("\n" INDENT1 "public static partial class ");
+ p_output.append("\npublic partial struct ");
p_output.append(enum_class_name);
- p_output.append("\n" INDENT1 OPEN_BLOCK);
+ p_output.append("\n" OPEN_BLOCK);
}
if (ienum.is_flags) {
- p_output.append("\n" INDENT1 "[System.Flags]");
+ p_output.append("\n[System.Flags]");
}
- p_output.append("\n" INDENT1 "public enum ");
+ p_output.append("\npublic enum ");
p_output.append(enum_proxy_name);
p_output.append(" : long");
- p_output.append("\n" INDENT1 OPEN_BLOCK);
+ p_output.append("\n" OPEN_BLOCK);
const ConstantInterface &last = ienum.constants.back()->get();
for (const ConstantInterface &iconstant : ienum.constants) {
@@ -1008,34 +1027,32 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>();
if (summary_lines.size()) {
- p_output.append(INDENT2 "/// <summary>\n");
+ p_output.append(INDENT1 "/// <summary>\n");
for (int i = 0; i < summary_lines.size(); i++) {
- p_output.append(INDENT2 "/// ");
+ p_output.append(INDENT1 "/// ");
p_output.append(summary_lines[i]);
p_output.append("\n");
}
- p_output.append(INDENT2 "/// </summary>\n");
+ p_output.append(INDENT1 "/// </summary>\n");
}
}
- p_output.append(INDENT2);
+ p_output.append(INDENT1);
p_output.append(iconstant.proxy_name);
p_output.append(" = ");
p_output.append(itos(iconstant.value));
p_output.append(&iconstant != &last ? ",\n" : "\n");
}
- p_output.append(INDENT1 CLOSE_BLOCK);
+ p_output.append(CLOSE_BLOCK);
if (enum_in_static_class) {
- p_output.append(INDENT1 CLOSE_BLOCK);
+ p_output.append(CLOSE_BLOCK);
}
}
- p_output.append(CLOSE_BLOCK); // end of namespace
-
p_output.append("\n#pragma warning restore CS1591\n");
}
@@ -1106,42 +1123,38 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) {
compile_items.push_back(output_file);
}
- // Generate sources from compressed files
+ // Generate native calls
StringBuilder cs_icalls_content;
+ cs_icalls_content.append("namespace " BINDINGS_NAMESPACE ";\n\n");
cs_icalls_content.append("using System;\n"
- "using System.Runtime.CompilerServices;\n"
+ "using System.Diagnostics.CodeAnalysis;\n"
+ "using System.Runtime.InteropServices;\n"
+ "using Godot.NativeInterop;\n"
"\n");
- cs_icalls_content.append("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
- cs_icalls_content.append(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS "\n" INDENT1 "{");
+ cs_icalls_content.append("[SuppressMessage(\"ReSharper\", \"InconsistentNaming\")]\n");
+ cs_icalls_content.append("[SuppressMessage(\"ReSharper\", \"RedundantUnsafeContext\")]\n");
+ cs_icalls_content.append("[SuppressMessage(\"ReSharper\", \"RedundantNameQualifier\")]\n");
+ cs_icalls_content.append("[System.Runtime.CompilerServices.SkipLocalsInit]\n");
+ cs_icalls_content.append("internal static class " BINDINGS_CLASS_NATIVECALLS "\n{");
cs_icalls_content.append(MEMBER_BEGIN "internal static ulong godot_api_hash = ");
- cs_icalls_content.append(String::num_uint64(GDMono::get_singleton()->get_api_core_hash()) + ";\n");
- cs_icalls_content.append(MEMBER_BEGIN "internal static uint bindings_version = ");
- cs_icalls_content.append(String::num_uint64(BINDINGS_GENERATOR_VERSION) + ";\n");
- cs_icalls_content.append(MEMBER_BEGIN "internal static uint cs_glue_version = ");
- cs_icalls_content.append(String::num_uint64(CS_GLUE_VERSION) + ";\n");
+ cs_icalls_content.append(String::num_uint64(ClassDB::get_api_hash(ClassDB::API_CORE)) + ";\n");
-#define ADD_INTERNAL_CALL(m_icall) \
- if (!m_icall.editor_only) { \
- cs_icalls_content.append(MEMBER_BEGIN "[MethodImpl(MethodImplOptions.InternalCall)]\n"); \
- cs_icalls_content.append(INDENT2 "internal static extern "); \
- cs_icalls_content.append(m_icall.im_type_out + " "); \
- cs_icalls_content.append(m_icall.name + "("); \
- cs_icalls_content.append(m_icall.im_sig + ");\n"); \
- }
+ cs_icalls_content.append(MEMBER_BEGIN "private const int VarArgsSpanThreshold = 10;\n");
- for (const InternalCall &internal_call : core_custom_icalls) {
- ADD_INTERNAL_CALL(internal_call);
- }
- for (const InternalCall &internal_call : method_icalls) {
- ADD_INTERNAL_CALL(internal_call);
+ for (const InternalCall &icall : method_icalls) {
+ if (icall.editor_only) {
+ continue;
+ }
+ Error err = _generate_cs_native_calls(icall, cs_icalls_content);
+ if (err != OK) {
+ return err;
+ }
}
-#undef ADD_INTERNAL_CALL
-
- cs_icalls_content.append(INDENT1 CLOSE_BLOCK CLOSE_BLOCK);
+ cs_icalls_content.append(CLOSE_BLOCK);
String internal_methods_file = path::join(base_gen_dir, BINDINGS_CLASS_NATIVECALLS ".cs");
@@ -1152,6 +1165,8 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) {
compile_items.push_back(internal_methods_file);
+ // Generate GeneratedIncludes.props
+
StringBuilder includes_props_content;
includes_props_content.append("<Project>\n"
" <ItemGroup>\n");
@@ -1215,41 +1230,40 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) {
compile_items.push_back(output_file);
}
+ // Generate native calls
+
StringBuilder cs_icalls_content;
+ cs_icalls_content.append("namespace " BINDINGS_NAMESPACE ";\n\n");
cs_icalls_content.append("using System;\n"
- "using System.Runtime.CompilerServices;\n"
+ "using System.Diagnostics.CodeAnalysis;\n"
+ "using System.Runtime.InteropServices;\n"
+ "using Godot.NativeInterop;\n"
"\n");
- cs_icalls_content.append("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
- cs_icalls_content.append(INDENT1 "internal static class " BINDINGS_CLASS_NATIVECALLS_EDITOR "\n" INDENT1 OPEN_BLOCK);
-
- cs_icalls_content.append(INDENT2 "internal static ulong godot_api_hash = ");
- cs_icalls_content.append(String::num_uint64(GDMono::get_singleton()->get_api_editor_hash()) + ";\n");
- cs_icalls_content.append(INDENT2 "internal static uint bindings_version = ");
- cs_icalls_content.append(String::num_uint64(BINDINGS_GENERATOR_VERSION) + ";\n");
- cs_icalls_content.append(INDENT2 "internal static uint cs_glue_version = ");
- cs_icalls_content.append(String::num_uint64(CS_GLUE_VERSION) + ";\n");
- cs_icalls_content.append("\n");
+ cs_icalls_content.append("[SuppressMessage(\"ReSharper\", \"InconsistentNaming\")]\n");
+ cs_icalls_content.append("[SuppressMessage(\"ReSharper\", \"RedundantUnsafeContext\")]\n");
+ cs_icalls_content.append("[SuppressMessage(\"ReSharper\", \"RedundantNameQualifier\")]\n");
+ cs_icalls_content.append("[System.Runtime.CompilerServices.SkipLocalsInit]\n");
+ cs_icalls_content.append("internal static class " BINDINGS_CLASS_NATIVECALLS_EDITOR "\n" OPEN_BLOCK);
-#define ADD_INTERNAL_CALL(m_icall) \
- if (m_icall.editor_only) { \
- cs_icalls_content.append(INDENT2 "[MethodImpl(MethodImplOptions.InternalCall)]\n"); \
- cs_icalls_content.append(INDENT2 "internal static extern "); \
- cs_icalls_content.append(m_icall.im_type_out + " "); \
- cs_icalls_content.append(m_icall.name + "("); \
- cs_icalls_content.append(m_icall.im_sig + ");\n"); \
- }
+ cs_icalls_content.append(INDENT1 "internal static ulong godot_api_hash = ");
+ cs_icalls_content.append(String::num_uint64(ClassDB::get_api_hash(ClassDB::API_EDITOR)) + ";\n");
- for (const InternalCall &internal_call : editor_custom_icalls) {
- ADD_INTERNAL_CALL(internal_call);
- }
- for (const InternalCall &internal_call : method_icalls) {
- ADD_INTERNAL_CALL(internal_call);
- }
+ cs_icalls_content.append(MEMBER_BEGIN "private const int VarArgsSpanThreshold = 10;\n");
-#undef ADD_INTERNAL_CALL
+ cs_icalls_content.append("\n");
+
+ for (const InternalCall &icall : method_icalls) {
+ if (!icall.editor_only) {
+ continue;
+ }
+ Error err = _generate_cs_native_calls(icall, cs_icalls_content);
+ if (err != OK) {
+ return err;
+ }
+ }
- cs_icalls_content.append(INDENT1 CLOSE_BLOCK CLOSE_BLOCK);
+ cs_icalls_content.append(CLOSE_BLOCK);
String internal_methods_file = path::join(base_gen_dir, BINDINGS_CLASS_NATIVECALLS_EDITOR ".cs");
@@ -1260,6 +1274,8 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) {
compile_items.push_back(internal_methods_file);
+ // Generate GeneratedIncludes.props
+
StringBuilder includes_props_content;
includes_props_content.append("<Project>\n"
" <ItemGroup>\n");
@@ -1299,7 +1315,7 @@ Error BindingsGenerator::generate_cs_api(const String &p_output_dir) {
// Generate GodotSharp source files
- String core_proj_dir = output_dir.plus_file(CORE_API_ASSEMBLY_NAME);
+ String core_proj_dir = output_dir.path_join(CORE_API_ASSEMBLY_NAME);
proj_err = generate_cs_core_project(core_proj_dir);
if (proj_err != OK) {
@@ -1309,7 +1325,7 @@ Error BindingsGenerator::generate_cs_api(const String &p_output_dir) {
// Generate GodotSharpEditor source files
- String editor_proj_dir = output_dir.plus_file(EDITOR_API_ASSEMBLY_NAME);
+ String editor_proj_dir = output_dir.path_join(EDITOR_API_ASSEMBLY_NAME);
proj_err = generate_cs_editor_project(editor_proj_dir);
if (proj_err != OK) {
@@ -1343,16 +1359,15 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
CRASH_COND(itype.is_singleton);
}
- List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls;
-
_log("Generating %s.cs...\n", itype.proxy_name.utf8().get_data());
- String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor"); // Used only for derived types
-
StringBuilder output;
+ output.append("namespace " BINDINGS_NAMESPACE ";\n\n");
+
output.append("using System;\n"); // IntPtr
output.append("using System.Diagnostics;\n"); // DebuggerBrowsable
+ output.append("using Godot.NativeInterop;\n");
output.append("\n"
"#pragma warning disable CS1591 // Disable warning: "
@@ -1360,7 +1375,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
"#pragma warning disable CS1573 // Disable warning: "
"'Parameter has no matching param tag in the XML comment'\n");
- output.append("\nnamespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
+ output.append("\n#nullable disable\n");
const DocData::ClassDoc *class_doc = itype.class_doc;
@@ -1369,40 +1384,48 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>();
if (summary_lines.size()) {
- output.append(INDENT1 "/// <summary>\n");
+ output.append("/// <summary>\n");
for (int i = 0; i < summary_lines.size(); i++) {
- output.append(INDENT1 "/// ");
+ output.append("/// ");
output.append(summary_lines[i]);
output.append("\n");
}
- output.append(INDENT1 "/// </summary>\n");
+ output.append("/// </summary>\n");
}
}
- output.append(INDENT1 "public ");
+ // We generate a `GodotClassName` attribute if the engine class name is not the same as the
+ // generated C# class name. This allows introspection code to find the name associated with
+ // the class. If the attribute is not present, the C# class name can be used instead.
+ if (itype.name != itype.proxy_name) {
+ output << "[GodotClassName(\"" << itype.name << "\")]\n";
+ }
+
+ output.append("public ");
if (itype.is_singleton) {
output.append("static partial class ");
} else {
- output.append(itype.is_instantiable ? "partial class " : "abstract partial class ");
+ // Even if the class is not instantiable, we can't declare it abstract because
+ // the engine can still instantiate them and return them via the scripting API.
+ // Example: `SceneTreeTimer` returned from `SceneTree.create_timer`.
+ // See the reverted commit: ef5672d3f94a7321ed779c922088bb72adbb1521
+ output.append("partial class ");
}
output.append(itype.proxy_name);
- if (itype.is_singleton) {
- output.append("\n");
- } else if (is_derived_type) {
+ if (is_derived_type && !itype.is_singleton) {
if (obj_types.has(itype.base_name)) {
output.append(" : ");
output.append(obj_types[itype.base_name].proxy_name);
- output.append("\n");
} else {
ERR_PRINT("Base type '" + itype.base_name.operator String() + "' does not exist, for class '" + itype.name + "'.");
return ERR_INVALID_DATA;
}
}
- output.append(INDENT1 "{");
+ output.append("\n{");
// Add constants
@@ -1415,12 +1438,12 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output.append(MEMBER_BEGIN "/// <summary>\n");
for (int i = 0; i < summary_lines.size(); i++) {
- output.append(INDENT2 "/// ");
+ output.append(INDENT1 "/// ");
output.append(summary_lines[i]);
output.append("\n");
}
- output.append(INDENT2 "/// </summary>");
+ output.append(INDENT1 "/// </summary>");
}
}
@@ -1456,26 +1479,26 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>();
if (summary_lines.size()) {
- output.append(INDENT3 "/// <summary>\n");
+ output.append(INDENT2 "/// <summary>\n");
for (int i = 0; i < summary_lines.size(); i++) {
- output.append(INDENT3 "/// ");
+ output.append(INDENT2 "/// ");
output.append(summary_lines[i]);
output.append("\n");
}
- output.append(INDENT3 "/// </summary>\n");
+ output.append(INDENT2 "/// </summary>\n");
}
}
- output.append(INDENT3);
+ output.append(INDENT2);
output.append(iconstant.proxy_name);
output.append(" = ");
output.append(itos(iconstant.value));
output.append(&iconstant != &last ? ",\n" : "\n");
}
- output.append(INDENT2 CLOSE_BLOCK);
+ output.append(INDENT1 CLOSE_BLOCK);
}
// Add properties
@@ -1491,55 +1514,68 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
// Add the type name and the singleton pointer as static fields
output.append(MEMBER_BEGIN "private static Godot.Object singleton;\n");
- output.append(MEMBER_BEGIN "public static Godot.Object Singleton\n" INDENT2 "{\n" INDENT3
- "get\n" INDENT3 "{\n" INDENT4 "if (singleton == null)\n" INDENT5
- "singleton = Engine.GetSingleton(typeof(");
- output.append(itype.proxy_name);
- output.append(").Name);\n" INDENT4 "return singleton;\n" INDENT3 "}\n" INDENT2 "}\n");
- output.append(MEMBER_BEGIN "private static StringName " BINDINGS_NATIVE_NAME_FIELD " = \"");
+ output << MEMBER_BEGIN "public static Godot.Object " CS_PROPERTY_SINGLETON "\n" INDENT1 "{\n"
+ << INDENT2 "get\n" INDENT2 "{\n" INDENT3 "if (singleton == null)\n"
+ << INDENT4 "singleton = " C_METHOD_ENGINE_GET_SINGLETON "(typeof("
+ << itype.proxy_name
+ << ").Name);\n" INDENT3 "return singleton;\n" INDENT2 "}\n" INDENT1 "}\n";
+
+ output.append(MEMBER_BEGIN "private static readonly StringName " BINDINGS_NATIVE_NAME_FIELD " = \"");
output.append(itype.name);
output.append("\";\n");
+ } else {
+ // IMPORTANT: We also generate the static fields for Godot.Object instead of declaring
+ // them manually in the `Object.base.cs` partial class declaration, because they're
+ // required by other static fields in this generated partial class declaration.
+ // Static fields are initialized in order of declaration, but when they're in different
+ // partial class declarations then it becomes harder to tell (Rider warns about this).
- output.append(INDENT2 "internal static IntPtr " BINDINGS_PTR_FIELD " = ");
- output.append(itype.api_type == ClassDB::API_EDITOR ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS);
- output.append("." ICALL_PREFIX);
- output.append(itype.name);
- output.append(SINGLETON_ICALL_SUFFIX "();\n");
- } else if (is_derived_type) {
- // Add member fields
+ // Add native name static field
+
+ if (is_derived_type) {
+ output << MEMBER_BEGIN "private static readonly System.Type CachedType = typeof(" << itype.proxy_name << ");\n";
+ }
- output.append(MEMBER_BEGIN "private static StringName " BINDINGS_NATIVE_NAME_FIELD " = \"");
+ output.append(MEMBER_BEGIN "private static readonly StringName " BINDINGS_NATIVE_NAME_FIELD " = \"");
output.append(itype.name);
output.append("\";\n");
- // Add default constructor
if (itype.is_instantiable) {
- output.append(MEMBER_BEGIN "public ");
- output.append(itype.proxy_name);
- output.append("() : this(");
- output.append(itype.memory_own ? "true" : "false");
-
- // The default constructor may also be called by the engine when instancing existing native objects
- // The engine will initialize the pointer field of the managed side before calling the constructor
- // This is why we only allocate a new native object from the constructor if the pointer field is not set
- output.append(")\n" OPEN_BLOCK_L2 "if (" BINDINGS_PTR_FIELD " == IntPtr.Zero)\n" INDENT4 BINDINGS_PTR_FIELD " = ");
- output.append(itype.api_type == ClassDB::API_EDITOR ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS);
- output.append("." + ctor_method);
- output.append("(this);\n" INDENT3 "_InitializeGodotScriptInstanceInternals();\n" CLOSE_BLOCK_L2);
- } else {
- // Hide the constructor
+ // Add native constructor static field
+
+ output << MEMBER_BEGIN << "[DebuggerBrowsable(DebuggerBrowsableState.Never)]\n"
+ << INDENT1 "private static readonly unsafe delegate* unmanaged<IntPtr> "
+ << CS_STATIC_FIELD_NATIVE_CTOR " = " ICALL_CLASSDB_GET_CONSTRUCTOR
+ << "(" BINDINGS_NATIVE_NAME_FIELD ");\n";
+ }
+
+ if (is_derived_type) {
+ // Add default constructor
+ if (itype.is_instantiable) {
+ output << MEMBER_BEGIN "public " << itype.proxy_name << "() : this("
+ << (itype.memory_own ? "true" : "false") << ")\n" OPEN_BLOCK_L1
+ << INDENT2 "unsafe\n" INDENT2 OPEN_BLOCK
+ << INDENT3 "_ConstructAndInitialize(" CS_STATIC_FIELD_NATIVE_CTOR ", "
+ << BINDINGS_NATIVE_NAME_FIELD ", CachedType, refCounted: "
+ << (itype.is_ref_counted ? "true" : "false") << ");\n"
+ << CLOSE_BLOCK_L2 CLOSE_BLOCK_L1;
+ } else {
+ // Hide the constructor
+ output.append(MEMBER_BEGIN "internal ");
+ output.append(itype.proxy_name);
+ output.append("() {}\n");
+ }
+
+ // Add.. em.. trick constructor. Sort of.
output.append(MEMBER_BEGIN "internal ");
output.append(itype.proxy_name);
- output.append("() {}\n");
+ output.append("(bool " CS_PARAM_MEMORYOWN ") : base(" CS_PARAM_MEMORYOWN ") {}\n");
}
-
- // Add.. em.. trick constructor. Sort of.
- output.append(MEMBER_BEGIN "internal ");
- output.append(itype.proxy_name);
- output.append("(bool " CS_FIELD_MEMORYOWN ") : base(" CS_FIELD_MEMORYOWN ") {}\n");
}
+ // Methods
+
int method_bind_count = 0;
for (const MethodInterface &imethod : itype.methods) {
Error method_err = _generate_cs_method(itype, imethod, method_bind_count, output);
@@ -1547,30 +1583,186 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
"Failed to generate method '" + imethod.name + "' for class '" + itype.name + "'.");
}
+ // Signals
+
for (const SignalInterface &isignal : itype.signals_) {
Error method_err = _generate_cs_signal(itype, isignal, output);
ERR_FAIL_COND_V_MSG(method_err != OK, method_err,
"Failed to generate signal '" + isignal.name + "' for class '" + itype.name + "'.");
}
- if (itype.is_singleton) {
- InternalCall singleton_icall = InternalCall(itype.api_type, ICALL_PREFIX + itype.name + SINGLETON_ICALL_SUFFIX, "IntPtr");
+ // Script members look-up
- if (!find_icall_by_name(singleton_icall.name, custom_icalls)) {
- custom_icalls.push_back(singleton_icall);
+ if (!itype.is_singleton && (is_derived_type || itype.has_virtual_methods)) {
+ // Generate method names cache fields
+
+ for (const MethodInterface &imethod : itype.methods) {
+ if (!imethod.is_virtual) {
+ continue;
+ }
+
+ output << MEMBER_BEGIN "// ReSharper disable once InconsistentNaming\n"
+ << INDENT1 "[DebuggerBrowsable(DebuggerBrowsableState.Never)]\n"
+ << INDENT1 "private static readonly StringName "
+ << CS_STATIC_FIELD_METHOD_PROXY_NAME_PREFIX << imethod.name
+ << " = \"" << imethod.proxy_name << "\";\n";
}
- }
- if (is_derived_type && itype.is_instantiable) {
- InternalCall ctor_icall = InternalCall(itype.api_type, ctor_method, "IntPtr", itype.proxy_name + " obj");
+ // TODO: Only generate HasGodotClassMethod and InvokeGodotClassMethod if there's any method
+
+ // Generate InvokeGodotClassMethod
+
+ output << MEMBER_BEGIN "protected internal " << (is_derived_type ? "override" : "virtual")
+ << " bool " CS_METHOD_INVOKE_GODOT_CLASS_METHOD "(in godot_string_name method, "
+ << "NativeVariantPtrArgs args, int argCount, out godot_variant ret)\n"
+ << INDENT1 "{\n";
+
+ for (const MethodInterface &imethod : itype.methods) {
+ if (!imethod.is_virtual) {
+ continue;
+ }
- if (!find_icall_by_name(ctor_icall.name, custom_icalls)) {
- custom_icalls.push_back(ctor_icall);
+ // We also call HasGodotClassMethod to ensure the method is overridden and avoid calling
+ // the stub implementation. This solution adds some extra overhead to calls, but it's
+ // much simpler than other solutions. This won't be a problem once we move to function
+ // pointers of generated wrappers for each method, as lookup will only happen once.
+
+ // We check both native names (snake_case) and proxy names (PascalCase)
+ output << INDENT2 "if ((method == " << CS_STATIC_FIELD_METHOD_PROXY_NAME_PREFIX << imethod.name
+ << " || method == MethodName." << imethod.proxy_name
+ << ") && argCount == " << itos(imethod.arguments.size())
+ << " && " << CS_METHOD_HAS_GODOT_CLASS_METHOD << "((godot_string_name)"
+ << CS_STATIC_FIELD_METHOD_PROXY_NAME_PREFIX << imethod.name << ".NativeValue))\n"
+ << INDENT2 "{\n";
+
+ if (imethod.return_type.cname != name_cache.type_void) {
+ output << INDENT3 "var callRet = ";
+ } else {
+ output << INDENT3;
+ }
+
+ output << imethod.proxy_name << "(";
+
+ for (int i = 0; i < imethod.arguments.size(); i++) {
+ const ArgumentInterface &iarg = imethod.arguments[i];
+
+ const TypeInterface *arg_type = _get_type_or_null(iarg.type);
+ ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Argument type not found
+
+ if (i != 0) {
+ output << ", ";
+ }
+
+ if (arg_type->cname == name_cache.type_Array_generic || arg_type->cname == name_cache.type_Dictionary_generic) {
+ String arg_cs_type = arg_type->cs_type + _get_generic_type_parameters(*arg_type, iarg.type.generic_type_parameters);
+
+ output << "new " << arg_cs_type << "(" << sformat(arg_type->cs_variant_to_managed, "args[" + itos(i) + "]", arg_type->cs_type, arg_type->name) << ")";
+ } else {
+ output << sformat(arg_type->cs_variant_to_managed,
+ "args[" + itos(i) + "]", arg_type->cs_type, arg_type->name);
+ }
+ }
+
+ output << ");\n";
+
+ if (imethod.return_type.cname != name_cache.type_void) {
+ const TypeInterface *return_type = _get_type_or_null(imethod.return_type);
+ ERR_FAIL_NULL_V(return_type, ERR_BUG); // Return type not found
+
+ output << INDENT3 "ret = "
+ << sformat(return_type->cs_managed_to_variant, "callRet", return_type->cs_type, return_type->name)
+ << ";\n"
+ << INDENT3 "return true;\n";
+ } else {
+ output << INDENT3 "ret = default;\n"
+ << INDENT3 "return true;\n";
+ }
+
+ output << INDENT2 "}\n";
+ }
+
+ if (is_derived_type) {
+ output << INDENT2 "return base." CS_METHOD_INVOKE_GODOT_CLASS_METHOD "(method, args, argCount, out ret);\n";
+ } else {
+ output << INDENT2 "ret = default;\n"
+ << INDENT2 "return false;\n";
+ }
+
+ output << INDENT1 "}\n";
+
+ // Generate HasGodotClassMethod
+
+ output << MEMBER_BEGIN "protected internal " << (is_derived_type ? "override" : "virtual")
+ << " bool " CS_METHOD_HAS_GODOT_CLASS_METHOD "(in godot_string_name method)\n"
+ << INDENT1 "{\n";
+
+ for (const MethodInterface &imethod : itype.methods) {
+ if (!imethod.is_virtual) {
+ continue;
+ }
+
+ // We check for native names (snake_case). If we detect one, we call HasGodotClassMethod
+ // again, but this time with the respective proxy name (PascalCase). It's the job of
+ // user derived classes to override the method and check for those. Our C# source
+ // generators take care of generating those override methods.
+ output << INDENT2 "if (method == MethodName." << imethod.proxy_name
+ << ")\n" INDENT2 "{\n"
+ << INDENT3 "if (" CS_METHOD_HAS_GODOT_CLASS_METHOD "("
+ << CS_STATIC_FIELD_METHOD_PROXY_NAME_PREFIX << imethod.name
+ << ".NativeValue.DangerousSelfRef))\n" INDENT3 "{\n"
+ << INDENT4 "return true;\n"
+ << INDENT3 "}\n" INDENT2 "}\n";
}
+
+ if (is_derived_type) {
+ output << INDENT2 "return base." CS_METHOD_HAS_GODOT_CLASS_METHOD "(method);\n";
+ } else {
+ output << INDENT2 "return false;\n";
+ }
+
+ output << INDENT1 "}\n";
}
- output.append(INDENT1 CLOSE_BLOCK /* class */
- CLOSE_BLOCK /* namespace */);
+ //Generate StringName for all class members
+ bool is_inherit = !itype.is_singleton && obj_types.has(itype.base_name);
+ //PropertyName
+ if (is_inherit) {
+ output << MEMBER_BEGIN "public new class PropertyName : " << obj_types[itype.base_name].proxy_name << ".PropertyName";
+ } else {
+ output << MEMBER_BEGIN "public class PropertyName";
+ }
+ output << "\n"
+ << INDENT1 "{\n";
+ for (const PropertyInterface &iprop : itype.properties) {
+ output << INDENT2 "public static readonly StringName " << iprop.proxy_name << " = \"" << iprop.cname << "\";\n";
+ }
+ output << INDENT1 "}\n";
+ //MethodName
+ if (is_inherit) {
+ output << MEMBER_BEGIN "public new class MethodName : " << obj_types[itype.base_name].proxy_name << ".MethodName";
+ } else {
+ output << MEMBER_BEGIN "public class MethodName";
+ }
+ output << "\n"
+ << INDENT1 "{\n";
+ for (const MethodInterface &imethod : itype.methods) {
+ output << INDENT2 "public static readonly StringName " << imethod.proxy_name << " = \"" << imethod.cname << "\";\n";
+ }
+ output << INDENT1 "}\n";
+ //SignalName
+ if (is_inherit) {
+ output << MEMBER_BEGIN "public new class SignalName : " << obj_types[itype.base_name].proxy_name << ".SignalName";
+ } else {
+ output << MEMBER_BEGIN "public class SignalName";
+ }
+ output << "\n"
+ << INDENT1 "{\n";
+ for (const SignalInterface &isignal : itype.signals_) {
+ output << INDENT2 "public static readonly StringName " << isignal.proxy_name << " = \"" << isignal.cname << "\";\n";
+ }
+ output << INDENT1 "}\n";
+
+ output.append(CLOSE_BLOCK /* class */);
output.append("\n"
"#pragma warning restore CS1591\n"
@@ -1649,12 +1841,12 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
p_output.append(MEMBER_BEGIN "/// <summary>\n");
for (int i = 0; i < summary_lines.size(); i++) {
- p_output.append(INDENT2 "/// ");
+ p_output.append(INDENT1 "/// ");
p_output.append(summary_lines[i]);
p_output.append("\n");
}
- p_output.append(INDENT2 "/// </summary>");
+ p_output.append(INDENT1 "/// </summary>");
}
}
@@ -1669,15 +1861,15 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
p_output.append(prop_cs_type);
p_output.append(" ");
p_output.append(p_iprop.proxy_name);
- p_output.append("\n" INDENT2 OPEN_BLOCK);
+ p_output.append("\n" OPEN_BLOCK_L1);
if (getter) {
- p_output.append(INDENT3 "get\n"
+ p_output.append(INDENT2 "get\n"
// TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
"#pragma warning disable CS0618 // Disable warning about obsolete method\n"
- OPEN_BLOCK_L3);
+ OPEN_BLOCK_L2 INDENT3);
p_output.append("return ");
p_output.append(getter->proxy_name + "(");
@@ -1694,19 +1886,19 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
}
p_output.append(");\n"
- CLOSE_BLOCK_L3
+ CLOSE_BLOCK_L2
// TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
"#pragma warning restore CS0618\n");
}
if (setter) {
- p_output.append(INDENT3 "set\n"
+ p_output.append(INDENT2 "set\n"
// TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
"#pragma warning disable CS0618 // Disable warning about obsolete method\n"
- OPEN_BLOCK_L3);
+ OPEN_BLOCK_L2 INDENT3);
p_output.append(setter->proxy_name + "(");
if (p_iprop.index != -1) {
@@ -1722,19 +1914,20 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
}
p_output.append("value);\n"
- CLOSE_BLOCK_L3
+ CLOSE_BLOCK_L2
// TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
"#pragma warning restore CS0618\n");
}
- p_output.append(CLOSE_BLOCK_L2);
+ p_output.append(CLOSE_BLOCK_L1);
return OK;
}
Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output) {
- const TypeInterface *return_type = _get_type_or_placeholder(p_imethod.return_type);
+ const TypeInterface *return_type = _get_type_or_null(p_imethod.return_type);
+ ERR_FAIL_NULL_V(return_type, ERR_BUG); // Return type not found
ERR_FAIL_COND_V_MSG(return_type->is_singleton, ERR_BUG,
"Method return type is a singleton: '" + p_itype.name + "." + p_imethod.name + "'.");
@@ -1745,14 +1938,21 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
"' from the editor API. Core API cannot have dependencies on the editor API.");
}
- String method_bind_field = "__method_bind_" + itos(p_method_bind_count);
+ String method_bind_field = CS_STATIC_FIELD_METHOD_BIND_PREFIX + itos(p_method_bind_count);
String arguments_sig;
- String cs_in_statements;
+ StringBuilder cs_in_statements;
+ bool cs_in_expr_is_unsafe = false;
String icall_params = method_bind_field;
+
if (!p_imethod.is_static) {
- icall_params += ", " + sformat(p_itype.cs_in, "this");
+ if (p_itype.cs_in.size()) {
+ cs_in_statements << sformat(p_itype.cs_in, p_itype.c_type, "this",
+ String(), String(), String(), INDENT2);
+ }
+
+ icall_params += ", " + sformat(p_itype.cs_in_expr, "this");
}
StringBuilder default_args_doc;
@@ -1760,7 +1960,8 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
// Retrieve information from the arguments
const ArgumentInterface &first = p_imethod.arguments.front()->get();
for (const ArgumentInterface &iarg : p_imethod.arguments) {
- const TypeInterface *arg_type = _get_type_or_placeholder(iarg.type);
+ const TypeInterface *arg_type = _get_type_or_null(iarg.type);
+ ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Argument type not found
ERR_FAIL_COND_V_MSG(arg_type->is_singleton, ERR_BUG,
"Argument type is a singleton: '" + iarg.name + "' of method '" + p_itype.name + "." + p_imethod.name + "'.");
@@ -1813,27 +2014,23 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
if (iarg.default_argument.size() && iarg.def_param_mode != ArgumentInterface::CONSTANT) {
// The default value of an argument must be constant. Otherwise we make it Nullable and do the following:
// Type arg_in = arg.HasValue ? arg.Value : <non-const default value>;
- String arg_in = iarg.name;
- arg_in += "_in";
+ String arg_or_defval_local = iarg.name;
+ arg_or_defval_local += "OrDefVal";
- cs_in_statements += arg_cs_type;
- cs_in_statements += " ";
- cs_in_statements += arg_in;
- cs_in_statements += " = ";
- cs_in_statements += iarg.name;
+ cs_in_statements << INDENT2 << arg_cs_type << " " << arg_or_defval_local << " = " << iarg.name;
if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL) {
- cs_in_statements += ".HasValue ? ";
+ cs_in_statements << ".HasValue ? ";
} else {
- cs_in_statements += " != null ? ";
+ cs_in_statements << " != null ? ";
}
- cs_in_statements += iarg.name;
+ cs_in_statements << iarg.name;
if (iarg.def_param_mode == ArgumentInterface::NULLABLE_VAL) {
- cs_in_statements += ".Value : ";
+ cs_in_statements << ".Value : ";
} else {
- cs_in_statements += " : ";
+ cs_in_statements << " : ";
}
String cs_type = arg_cs_type;
@@ -1843,10 +2040,18 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
String def_arg = sformat(iarg.default_argument, cs_type);
- cs_in_statements += def_arg;
- cs_in_statements += ";\n" INDENT3;
+ cs_in_statements << def_arg << ";\n";
+
+ if (arg_type->cs_in.size()) {
+ cs_in_statements << sformat(arg_type->cs_in, arg_type->c_type, arg_or_defval_local,
+ String(), String(), String(), INDENT2);
+ }
- icall_params += arg_type->cs_in.is_empty() ? arg_in : sformat(arg_type->cs_in, arg_in);
+ if (arg_type->cs_in_expr.is_empty()) {
+ icall_params += arg_or_defval_local;
+ } else {
+ icall_params += sformat(arg_type->cs_in_expr, arg_or_defval_local, arg_type->c_type);
+ }
// Apparently the name attribute must not include the @
String param_tag_name = iarg.name.begins_with("@") ? iarg.name.substr(1, iarg.name.length()) : iarg.name;
@@ -1855,18 +2060,32 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
default_args_doc.append(MEMBER_BEGIN "/// <param name=\"" + param_tag_name + "\">If the parameter is null, then the default value is <c>" + param_def_arg + "</c>.</param>");
} else {
- icall_params += arg_type->cs_in.is_empty() ? iarg.name : sformat(arg_type->cs_in, iarg.name);
+ if (arg_type->cs_in.size()) {
+ cs_in_statements << sformat(arg_type->cs_in, arg_type->c_type, iarg.name,
+ String(), String(), String(), INDENT2);
+ }
+
+ icall_params += arg_type->cs_in_expr.is_empty() ? iarg.name : sformat(arg_type->cs_in_expr, iarg.name, arg_type->c_type);
}
+
+ cs_in_expr_is_unsafe |= arg_type->cs_in_expr_is_unsafe;
}
// Generate method
{
if (!p_imethod.is_virtual && !p_imethod.requires_object_call) {
- p_output.append(MEMBER_BEGIN "[DebuggerBrowsable(DebuggerBrowsableState.Never)]" MEMBER_BEGIN "private static readonly IntPtr ");
- p_output.append(method_bind_field);
- p_output.append(" = Object." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \"");
- p_output.append(p_imethod.name);
- p_output.append("\");\n");
+ p_output << MEMBER_BEGIN "[DebuggerBrowsable(DebuggerBrowsableState.Never)]\n"
+ << INDENT1 "private static readonly IntPtr " << method_bind_field << " = ";
+
+ if (p_itype.is_singleton) {
+ // Singletons are static classes. They don't derive Godot.Object,
+ // so we need to specify the type to call the static method.
+ p_output << "Object.";
+ }
+
+ p_output << ICALL_CLASSDB_GET_METHOD "(" BINDINGS_NATIVE_NAME_FIELD ", MethodName."
+ << p_imethod.proxy_name
+ << ");\n";
}
if (p_imethod.method_doc && p_imethod.method_doc->description.size()) {
@@ -1877,12 +2096,12 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
p_output.append(MEMBER_BEGIN "/// <summary>\n");
for (int i = 0; i < summary_lines.size(); i++) {
- p_output.append(INDENT2 "/// ");
+ p_output.append(INDENT1 "/// ");
p_output.append(summary_lines[i]);
p_output.append("\n");
}
- p_output.append(INDENT2 "/// </summary>");
+ p_output.append(INDENT1 "/// </summary>");
}
}
@@ -1890,16 +2109,6 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
p_output.append(default_args_doc.as_string());
}
- if (!p_imethod.is_internal) {
- // TODO: This alone adds ~0.2 MB of bloat to the core API assembly. It would be
- // better to generate a table in the C++ glue instead. That way the strings wouldn't
- // add that much extra bloat as they're already used in engine code. Also, it would
- // probably be much faster than looking up the attributes when fetching methods.
- p_output.append(MEMBER_BEGIN "[GodotMethod(\"");
- p_output.append(p_imethod.name);
- p_output.append("\")]");
- }
-
if (p_imethod.is_deprecated) {
if (p_imethod.deprecation_message.is_empty()) {
WARN_PRINT("An empty deprecation message is discouraged. Method: '" + p_imethod.proxy_name + "'.");
@@ -1919,21 +2128,23 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
p_output.append("virtual ");
}
+ if (cs_in_expr_is_unsafe) {
+ p_output.append("unsafe ");
+ }
+
String return_cs_type = return_type->cs_type + _get_generic_type_parameters(*return_type, p_imethod.return_type.generic_type_parameters);
p_output.append(return_cs_type + " ");
p_output.append(p_imethod.proxy_name + "(");
- p_output.append(arguments_sig + ")\n" OPEN_BLOCK_L2);
+ p_output.append(arguments_sig + ")\n" OPEN_BLOCK_L1);
if (p_imethod.is_virtual) {
// Godot virtual method must be overridden, therefore we return a default value by default.
if (return_type->cname == name_cache.type_void) {
- p_output.append("return;\n" CLOSE_BLOCK_L2);
+ p_output.append(CLOSE_BLOCK_L1);
} else {
- p_output.append("return default(");
- p_output.append(return_cs_type);
- p_output.append(");\n" CLOSE_BLOCK_L2);
+ p_output.append(INDENT2 "return default;\n" CLOSE_BLOCK_L1);
}
return OK; // Won't increment method bind count
@@ -1942,7 +2153,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
if (p_imethod.requires_object_call) {
// Fallback to Godot's object.Call(string, params)
- p_output.append(CS_METHOD_CALL "(\"");
+ p_output.append(INDENT2 CS_METHOD_CALL "(\"");
p_output.append(p_imethod.name);
p_output.append("\"");
@@ -1951,7 +2162,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
p_output.append(iarg.name);
}
- p_output.append(");\n" CLOSE_BLOCK_L2);
+ p_output.append(");\n" CLOSE_BLOCK_L1);
return OK; // Won't increment method bind count
}
@@ -1965,20 +2176,21 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
im_call += ".";
im_call += im_icall->name;
- if (p_imethod.arguments.size()) {
- p_output.append(cs_in_statements);
+ if (p_imethod.arguments.size() && cs_in_statements.get_string_length() > 0) {
+ p_output.append(cs_in_statements.as_string());
}
if (return_type->cname == name_cache.type_void) {
- p_output.append(im_call + "(" + icall_params + ");\n");
+ p_output << INDENT2 << im_call << "(" << icall_params << ");\n";
} else if (return_type->cs_out.is_empty()) {
- p_output.append("return " + im_call + "(" + icall_params + ");\n");
+ p_output << INDENT2 "return " << im_call << "(" << icall_params << ");\n";
} else {
- p_output.append(sformat(return_type->cs_out, im_call, icall_params, return_cs_type, return_type->im_type_out));
+ p_output.append(sformat(return_type->cs_out, im_call, icall_params,
+ return_cs_type, return_type->c_type_out, String(), INDENT2));
p_output.append("\n");
}
- p_output.append(CLOSE_BLOCK_L2);
+ p_output.append(CLOSE_BLOCK_L1);
}
p_method_bind_count++;
@@ -1992,7 +2204,8 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
// Retrieve information from the arguments
const ArgumentInterface &first = p_isignal.arguments.front()->get();
for (const ArgumentInterface &iarg : p_isignal.arguments) {
- const TypeInterface *arg_type = _get_type_or_placeholder(iarg.type);
+ const TypeInterface *arg_type = _get_type_or_null(iarg.type);
+ ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Argument type not found
ERR_FAIL_COND_V_MSG(arg_type->is_singleton, ERR_BUG,
"Argument type is a singleton: '" + iarg.name + "' of signal '" + p_itype.name + "." + p_isignal.name + "'.");
@@ -2024,12 +2237,12 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
p_output.append(MEMBER_BEGIN "/// <summary>\n");
for (int i = 0; i < summary_lines.size(); i++) {
- p_output.append(INDENT2 "/// ");
+ p_output.append(INDENT1 "/// ");
p_output.append(summary_lines[i]);
p_output.append("\n");
}
- p_output.append(INDENT2 "/// </summary>");
+ p_output.append(INDENT1 "/// </summary>");
}
}
@@ -2044,7 +2257,7 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
}
String delegate_name = p_isignal.proxy_name;
- delegate_name += "Handler"; // Delegate name is [SignalName]Handler
+ delegate_name += "EventHandler"; // Delegate name is [SignalName]EventHandler
// Generate delegate
p_output.append(MEMBER_BEGIN "public delegate void ");
@@ -2057,15 +2270,8 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
// Could we assume the StringName instance of signal name will never be freed (it's stored in ClassDB) before the managed world is unloaded?
// If so, we could store the pointer we get from `data_unique_pointer()` instead of allocating StringName here.
- // Cached signal name (StringName)
- p_output.append(MEMBER_BEGIN "[DebuggerBrowsable(DebuggerBrowsableState.Never)]" MEMBER_BEGIN "private static StringName __signal_name_");
- p_output.append(p_isignal.name);
- p_output.append(" = \"");
- p_output.append(p_isignal.name);
- p_output.append("\";\n");
-
// Generate event
- p_output.append(MEMBER_BEGIN "[Signal]" MEMBER_BEGIN "public ");
+ p_output.append(MEMBER_BEGIN "public ");
if (p_itype.is_singleton) {
p_output.append("static ");
@@ -2075,413 +2281,241 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
p_output.append(delegate_name);
p_output.append(" ");
p_output.append(p_isignal.proxy_name);
- p_output.append("\n" OPEN_BLOCK_L2);
+ p_output.append("\n" OPEN_BLOCK_L1 INDENT2);
if (p_itype.is_singleton) {
- p_output.append("add => Singleton.Connect(__signal_name_");
+ p_output.append("add => " CS_PROPERTY_SINGLETON ".Connect(SignalName.");
} else {
- p_output.append("add => Connect(__signal_name_");
+ p_output.append("add => Connect(SignalName.");
}
- p_output.append(p_isignal.name);
+ p_output.append(p_isignal.proxy_name);
p_output.append(", new Callable(value));\n");
if (p_itype.is_singleton) {
- p_output.append(INDENT3 "remove => Singleton.Disconnect(__signal_name_");
+ p_output.append(INDENT2 "remove => " CS_PROPERTY_SINGLETON ".Disconnect(SignalName.");
} else {
- p_output.append(INDENT3 "remove => Disconnect(__signal_name_");
+ p_output.append(INDENT2 "remove => Disconnect(SignalName.");
}
- p_output.append(p_isignal.name);
+ p_output.append(p_isignal.proxy_name);
p_output.append(", new Callable(value));\n");
- p_output.append(CLOSE_BLOCK_L2);
- }
-
- return OK;
-}
-
-Error BindingsGenerator::generate_glue(const String &p_output_dir) {
- ERR_FAIL_COND_V(!initialized, ERR_UNCONFIGURED);
-
- bool dir_exists = DirAccess::exists(p_output_dir);
- ERR_FAIL_COND_V_MSG(!dir_exists, ERR_FILE_BAD_PATH, "The output directory does not exist.");
-
- StringBuilder output;
-
- output.append("/* THIS FILE IS GENERATED DO NOT EDIT */\n");
- output.append("#include \"" GLUE_HEADER_FILE "\"\n");
- output.append("\n#ifdef MONO_GLUE_ENABLED\n");
-
- generated_icall_funcs.clear();
-
- for (const KeyValue<StringName, TypeInterface> &type_elem : obj_types) {
- const TypeInterface &itype = type_elem.value;
-
- bool is_derived_type = itype.base_name != StringName();
-
- if (!is_derived_type) {
- // Some Object assertions
- CRASH_COND(itype.cname != name_cache.type_Object);
- CRASH_COND(!itype.is_instantiable);
- CRASH_COND(itype.api_type != ClassDB::API_CORE);
- CRASH_COND(itype.is_singleton);
- }
-
- List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls;
-
- OS::get_singleton()->print("Generating %s...\n", itype.name.utf8().get_data());
-
- String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor"); // Used only for derived types
-
- for (const MethodInterface &imethod : itype.methods) {
- Error method_err = _generate_glue_method(itype, imethod, output);
- ERR_FAIL_COND_V_MSG(method_err != OK, method_err,
- "Failed to generate method '" + imethod.name + "' for class '" + itype.name + "'.");
- }
-
- if (itype.is_singleton) {
- String singleton_icall_name = ICALL_PREFIX + itype.name + SINGLETON_ICALL_SUFFIX;
- InternalCall singleton_icall = InternalCall(itype.api_type, singleton_icall_name, "IntPtr");
-
- if (!find_icall_by_name(singleton_icall.name, custom_icalls)) {
- custom_icalls.push_back(singleton_icall);
- }
-
- output.append("Object* ");
- output.append(singleton_icall_name);
- output.append("() " OPEN_BLOCK "\treturn Engine::get_singleton()->get_singleton_object(\"");
- output.append(itype.proxy_name);
- output.append("\");\n" CLOSE_BLOCK "\n");
- }
-
- if (is_derived_type && itype.is_instantiable) {
- InternalCall ctor_icall = InternalCall(itype.api_type, ctor_method, "IntPtr", itype.proxy_name + " obj");
-
- if (!find_icall_by_name(ctor_icall.name, custom_icalls)) {
- custom_icalls.push_back(ctor_icall);
- }
-
- output.append("Object* ");
- output.append(ctor_method);
- output.append("(MonoObject* obj) " OPEN_BLOCK
- "\t" C_MACRO_OBJECT_CONSTRUCT "(instance, \"");
- output.append(itype.name);
- output.append("\");\n"
- "\t" C_METHOD_TIE_MANAGED_TO_UNMANAGED "(obj, instance);\n"
- "\treturn instance;\n" CLOSE_BLOCK "\n");
- }
- }
-
- output.append("namespace GodotSharpBindings\n" OPEN_BLOCK "\n");
-
- output.append("uint64_t get_core_api_hash() { return ");
- output.append(String::num_uint64(GDMono::get_singleton()->get_api_core_hash()) + "U; }\n");
-
- output.append("#ifdef TOOLS_ENABLED\n"
- "uint64_t get_editor_api_hash() { return ");
- output.append(String::num_uint64(GDMono::get_singleton()->get_api_editor_hash()) + "U; }\n");
- output.append("#endif // TOOLS_ENABLED\n");
-
- output.append("uint32_t get_bindings_version() { return ");
- output.append(String::num_uint64(BINDINGS_GENERATOR_VERSION) + "; }\n");
-
- output.append("uint32_t get_cs_glue_version() { return ");
- output.append(String::num_uint64(CS_GLUE_VERSION) + "; }\n");
-
- output.append("\nvoid register_generated_icalls() " OPEN_BLOCK);
- output.append("\tgodot_register_glue_header_icalls();\n");
-
-#define ADD_INTERNAL_CALL_REGISTRATION(m_icall) \
- { \
- output.append("\tGDMonoUtils::add_internal_call("); \
- output.append("\"" BINDINGS_NAMESPACE "."); \
- output.append(m_icall.editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS); \
- output.append("::"); \
- output.append(m_icall.name); \
- output.append("\", "); \
- output.append(m_icall.name); \
- output.append(");\n"); \
- }
-
- bool tools_sequence = false;
- for (const InternalCall &internal_call : core_custom_icalls) {
- if (tools_sequence) {
- if (!internal_call.editor_only) {
- tools_sequence = false;
- output.append("#endif\n");
- }
- } else {
- if (internal_call.editor_only) {
- output.append("#ifdef TOOLS_ENABLED\n");
- tools_sequence = true;
- }
- }
-
- ADD_INTERNAL_CALL_REGISTRATION(internal_call);
- }
-
- if (tools_sequence) {
- tools_sequence = false;
- output.append("#endif\n");
- }
-
- output.append("#ifdef TOOLS_ENABLED\n");
- for (const InternalCall &internal_call : editor_custom_icalls) {
- ADD_INTERNAL_CALL_REGISTRATION(internal_call);
- }
- output.append("#endif // TOOLS_ENABLED\n");
-
- for (const InternalCall &internal_call : method_icalls) {
- if (tools_sequence) {
- if (!internal_call.editor_only) {
- tools_sequence = false;
- output.append("#endif\n");
- }
- } else {
- if (internal_call.editor_only) {
- output.append("#ifdef TOOLS_ENABLED\n");
- tools_sequence = true;
- }
- }
-
- ADD_INTERNAL_CALL_REGISTRATION(internal_call);
- }
-
- if (tools_sequence) {
- tools_sequence = false;
- output.append("#endif\n");
- }
-
-#undef ADD_INTERNAL_CALL_REGISTRATION
-
- output.append(CLOSE_BLOCK "\n} // namespace GodotSharpBindings\n");
-
- output.append("\n#endif // MONO_GLUE_ENABLED\n");
-
- Error save_err = _save_file(path::join(p_output_dir, "mono_glue.gen.cpp"), output);
- if (save_err != OK) {
- return save_err;
+ p_output.append(CLOSE_BLOCK_L1);
}
- OS::get_singleton()->print("Mono glue generated successfully\n");
-
- return OK;
-}
-
-uint32_t BindingsGenerator::get_version() {
- return BINDINGS_GENERATOR_VERSION;
-}
-
-Error BindingsGenerator::_save_file(const String &p_path, const StringBuilder &p_content) {
- Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE);
- ERR_FAIL_COND_V_MSG(file.is_null(), ERR_FILE_CANT_WRITE, "Cannot open file: '" + p_path + "'.");
-
- file->store_string(p_content.as_string());
-
return OK;
}
-Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::MethodInterface &p_imethod, StringBuilder &p_output) {
- if (p_imethod.is_virtual) {
- return OK; // Ignore
- }
+Error BindingsGenerator::_generate_cs_native_calls(const InternalCall &p_icall, StringBuilder &r_output) {
+ bool ret_void = p_icall.return_type.cname == name_cache.type_void;
- bool ret_void = p_imethod.return_type.cname == name_cache.type_void;
+ const TypeInterface *return_type = _get_type_or_null(p_icall.return_type);
+ ERR_FAIL_NULL_V(return_type, ERR_BUG); // Return type not found
- const TypeInterface *return_type = _get_type_or_placeholder(p_imethod.return_type);
+ StringBuilder c_func_sig;
+ StringBuilder c_in_statements;
+ StringBuilder c_args_var_content;
- String argc_str = itos(p_imethod.arguments.size());
+ c_func_sig << "IntPtr " CS_PARAM_METHODBIND;
- String c_func_sig = "MethodBind* " CS_PARAM_METHODBIND;
- if (!p_imethod.is_static) {
- c_func_sig += ", " + p_itype.c_type_in + " " CS_PARAM_INSTANCE;
+ if (!p_icall.is_static) {
+ c_func_sig += ", IntPtr " CS_PARAM_INSTANCE;
}
- String c_in_statements;
- String c_args_var_content;
// Get arguments information
int i = 0;
- for (const ArgumentInterface &iarg : p_imethod.arguments) {
- const TypeInterface *arg_type = _get_type_or_placeholder(iarg.type);
+ for (const TypeReference &arg_type_ref : p_icall.argument_types) {
+ const TypeInterface *arg_type = _get_type_or_null(arg_type_ref);
+ ERR_FAIL_NULL_V(arg_type, ERR_BUG); // Return type not found
String c_param_name = "arg" + itos(i + 1);
- if (p_imethod.is_vararg) {
- if (i < p_imethod.arguments.size() - 1) {
- c_in_statements += sformat(arg_type->c_in.size() ? arg_type->c_in : TypeInterface::DEFAULT_VARARG_C_IN, "Variant", c_param_name);
- c_in_statements += "\t" C_LOCAL_PTRCALL_ARGS ".set(";
- c_in_statements += itos(i);
- c_in_statements += sformat(", &%s_in);\n", c_param_name);
+ if (p_icall.is_vararg) {
+ if (i < p_icall.get_arguments_count() - 1) {
+ String c_in_vararg = arg_type->c_in_vararg;
+
+ if (arg_type->is_object_type) {
+ c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromGodotObjectPtr(%1);\n";
+ }
+
+ ERR_FAIL_COND_V_MSG(c_in_vararg.is_empty(), ERR_BUG,
+ "VarArg support not implemented for parameter type: " + arg_type->name);
+
+ c_in_statements
+ << sformat(c_in_vararg, return_type->c_type, c_param_name,
+ String(), String(), String(), INDENT3)
+ << INDENT3 C_LOCAL_PTRCALL_ARGS "[" << itos(i)
+ << "] = new IntPtr(&" << c_param_name << "_in);\n";
}
} else {
if (i > 0) {
- c_args_var_content += ", ";
+ c_args_var_content << ", ";
}
if (arg_type->c_in.size()) {
- c_in_statements += sformat(arg_type->c_in, arg_type->c_type, c_param_name);
+ c_in_statements << sformat(arg_type->c_in, arg_type->c_type, c_param_name,
+ String(), String(), String(), INDENT2);
}
- c_args_var_content += sformat(arg_type->c_arg_in, c_param_name);
+ c_args_var_content << sformat(arg_type->c_arg_in, c_param_name);
}
- c_func_sig += ", ";
- c_func_sig += arg_type->c_type_in;
- c_func_sig += " ";
- c_func_sig += c_param_name;
+ c_func_sig << ", " << arg_type->c_type_in << " " << c_param_name;
i++;
}
- if (return_type->ret_as_byref_arg) {
- c_func_sig += ", ";
- c_func_sig += return_type->c_type_in;
- c_func_sig += " ";
- c_func_sig += "arg_ret";
-
- i++;
- }
+ String icall_method = p_icall.name;
- HashMap<const MethodInterface *, const InternalCall *>::ConstIterator match = method_icalls_map.find(&p_imethod);
- ERR_FAIL_NULL_V(match, ERR_BUG);
+ // Generate icall function
- const InternalCall *im_icall = match->value;
- String icall_method = im_icall->name;
+ r_output << MEMBER_BEGIN "internal static unsafe " << (ret_void ? "void" : return_type->c_type_out) << " "
+ << icall_method << "(" << c_func_sig.as_string() << ") " OPEN_BLOCK;
- if (!generated_icall_funcs.find(im_icall)) {
- generated_icall_funcs.push_back(im_icall);
+ if (!ret_void && (!p_icall.is_vararg || return_type->cname != name_cache.type_Variant)) {
+ String ptrcall_return_type;
+ String initialization;
- if (im_icall->editor_only) {
- p_output.append("#ifdef TOOLS_ENABLED\n");
+ if (return_type->is_object_type) {
+ ptrcall_return_type = return_type->is_ref_counted ? "godot_ref" : return_type->c_type;
+ initialization = " = default";
+ } else {
+ ptrcall_return_type = return_type->c_type;
}
- // Generate icall function
-
- p_output.append((ret_void || return_type->ret_as_byref_arg) ? "void " : return_type->c_type_out + " ");
- p_output.append(icall_method);
- p_output.append("(");
- p_output.append(c_func_sig);
- p_output.append(") " OPEN_BLOCK);
+ r_output << INDENT2;
- if (!ret_void) {
- String ptrcall_return_type;
- String initialization;
+ if (return_type->is_ref_counted || return_type->c_type_is_disposable_struct) {
+ r_output << "using ";
- if (p_imethod.is_vararg && return_type->cname != name_cache.type_Variant) {
- // VarArg methods always return Variant, but there are some cases in which MethodInfo provides
- // a specific return type. We trust this information is valid. We need a temporary local to keep
- // the Variant alive until the method returns. Otherwise, if the returned Variant holds a RefPtr,
- // it could be deleted too early. This is the case with GDScript.new() which returns OBJECT.
- // Alternatively, we could just return Variant, but that would result in a worse API.
- p_output.append("\tVariant " C_LOCAL_VARARG_RET ";\n");
+ if (initialization.is_empty()) {
+ initialization = " = default";
}
+ } else if (return_type->c_ret_needs_default_initialization) {
+ initialization = " = default";
+ }
- if (return_type->is_object_type) {
- ptrcall_return_type = return_type->is_ref_counted ? "Ref<RefCounted>" : return_type->c_type;
- initialization = return_type->is_ref_counted ? "" : " = nullptr";
- } else {
- ptrcall_return_type = return_type->c_type;
- }
+ r_output << ptrcall_return_type << " " C_LOCAL_RET << initialization << ";\n";
+ }
- p_output.append("\t" + ptrcall_return_type);
- p_output.append(" " C_LOCAL_RET);
- p_output.append(initialization + ";\n");
+ if (!p_icall.is_static) {
+ r_output << INDENT2 "if (" CS_PARAM_INSTANCE " == IntPtr.Zero)\n"
+ << INDENT3 "throw new ArgumentNullException(nameof(" CS_PARAM_INSTANCE "));\n";
+ }
- String fail_ret = return_type->c_type_out.ends_with("*") && !return_type->ret_as_byref_arg ? "nullptr" : return_type->c_type_out + "()";
+ String argc_str = itos(p_icall.get_arguments_count());
- if (!p_imethod.is_static) {
- if (return_type->ret_as_byref_arg) {
- p_output.append("\tif (" CS_PARAM_INSTANCE " == nullptr) { *arg_ret = ");
- p_output.append(fail_ret);
- p_output.append("; ERR_FAIL_MSG(\"Parameter ' " CS_PARAM_INSTANCE " ' is null.\"); }\n");
- } else {
- p_output.append("\tERR_FAIL_NULL_V(" CS_PARAM_INSTANCE ", ");
- p_output.append(fail_ret);
- p_output.append(");\n");
- }
- }
- } else {
- if (!p_imethod.is_static) {
- p_output.append("\tERR_FAIL_NULL(" CS_PARAM_INSTANCE ");\n");
- }
- }
-
- if (p_imethod.arguments.size()) {
- if (p_imethod.is_vararg) {
- String vararg_arg = "arg" + argc_str;
- String real_argc_str = itos(p_imethod.arguments.size() - 1); // Arguments count without vararg
-
- p_output.append("\tint vararg_length = mono_array_length(");
- p_output.append(vararg_arg);
- p_output.append(");\n\tint total_length = ");
- p_output.append(real_argc_str);
- p_output.append(" + vararg_length;\n"
- "\tArgumentsVector<Variant> varargs(vararg_length);\n"
- "\tArgumentsVector<const Variant *> " C_LOCAL_PTRCALL_ARGS "(total_length);\n");
- p_output.append(c_in_statements);
- p_output.append("\tfor (int i = 0; i < vararg_length; i++) " OPEN_BLOCK
- "\t\tMonoObject* elem = mono_array_get(");
- p_output.append(vararg_arg);
- p_output.append(", MonoObject*, i);\n"
- "\t\tvarargs.set(i, GDMonoMarshal::mono_object_to_variant(elem));\n"
- "\t\t" C_LOCAL_PTRCALL_ARGS ".set(");
- p_output.append(real_argc_str);
- p_output.append(" + i, &varargs.get(i));\n\t" CLOSE_BLOCK);
- } else {
- p_output.append(c_in_statements);
- p_output.append("\tconst void* " C_LOCAL_PTRCALL_ARGS "[");
- p_output.append(argc_str + "] = { ");
- p_output.append(c_args_var_content + " };\n");
- }
- }
+ auto generate_call_and_return_stmts = [&](const char *base_indent) {
+ if (p_icall.is_vararg) {
+ // MethodBind Call
+ r_output << base_indent;
- if (p_imethod.is_vararg) {
- p_output.append("\tCallable::CallError vcall_error;\n\t");
+ // VarArg methods always return Variant, but there are some cases in which MethodInfo provides
+ // a specific return type. We trust this information is valid. We need a temporary local to keep
+ // the Variant alive until the method returns. Otherwise, if the returned Variant holds a RefPtr,
+ // it could be deleted too early. This is the case with GDScript.new() which returns OBJECT.
+ // Alternatively, we could just return Variant, but that would result in a worse API.
if (!ret_void) {
- // See the comment on the C_LOCAL_VARARG_RET declaration
if (return_type->cname != name_cache.type_Variant) {
- p_output.append(C_LOCAL_VARARG_RET " = ");
+ r_output << "using godot_variant " << C_LOCAL_VARARG_RET " = ";
} else {
- p_output.append(C_LOCAL_RET " = ");
+ r_output << "using godot_variant " << C_LOCAL_RET " = ";
}
}
- p_output.append(CS_PARAM_METHODBIND "->call(");
- p_output.append(p_imethod.is_static ? "nullptr" : CS_PARAM_INSTANCE);
- p_output.append(", ");
- p_output.append(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ".ptr()" : "nullptr");
- p_output.append(", total_length, vcall_error);\n");
+ r_output << C_CLASS_NATIVE_FUNCS ".godotsharp_method_bind_call("
+ << CS_PARAM_METHODBIND ", " << (p_icall.is_static ? "IntPtr.Zero" : CS_PARAM_INSTANCE)
+ << ", " << (p_icall.get_arguments_count() ? "(godot_variant**)" C_LOCAL_PTRCALL_ARGS : "null")
+ << ", total_length, out _);\n";
if (!ret_void) {
- // See the comment on the C_LOCAL_VARARG_RET declaration
if (return_type->cname != name_cache.type_Variant) {
- p_output.append("\t" C_LOCAL_RET " = " C_LOCAL_VARARG_RET ";\n");
+ if (return_type->cname == name_cache.enum_Error) {
+ r_output << base_indent << C_LOCAL_RET " = VariantUtils.ConvertToInt64(" C_LOCAL_VARARG_RET ");\n";
+ } else {
+ // TODO: Use something similar to c_in_vararg (see usage above, with error if not implemented)
+ CRASH_NOW_MSG("Custom VarArg return type not implemented: " + return_type->name);
+ r_output << base_indent << C_LOCAL_RET " = " C_LOCAL_VARARG_RET ";\n";
+ }
}
}
} else {
- p_output.append("\t" CS_PARAM_METHODBIND "->ptrcall(");
- p_output.append(p_imethod.is_static ? "nullptr" : CS_PARAM_INSTANCE);
- p_output.append(", ");
- p_output.append(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ", " : "nullptr, ");
- p_output.append(!ret_void ? "&" C_LOCAL_RET ");\n" : "nullptr);\n");
+ // MethodBind PtrCall
+ r_output << base_indent << C_CLASS_NATIVE_FUNCS ".godotsharp_method_bind_ptrcall("
+ << CS_PARAM_METHODBIND ", " << (p_icall.is_static ? "IntPtr.Zero" : CS_PARAM_INSTANCE)
+ << ", " << (p_icall.get_arguments_count() ? C_LOCAL_PTRCALL_ARGS : "null")
+ << ", " << (!ret_void ? "&" C_LOCAL_RET ");\n" : "null);\n");
}
+ // Return statement
+
if (!ret_void) {
if (return_type->c_out.is_empty()) {
- p_output.append("\treturn " C_LOCAL_RET ";\n");
- } else if (return_type->ret_as_byref_arg) {
- p_output.append(sformat(return_type->c_out, return_type->c_type_out, C_LOCAL_RET, return_type->name, "arg_ret"));
+ r_output << base_indent << "return " C_LOCAL_RET ";\n";
} else {
- p_output.append(sformat(return_type->c_out, return_type->c_type_out, C_LOCAL_RET, return_type->name));
+ r_output << sformat(return_type->c_out, return_type->c_type_out, C_LOCAL_RET,
+ return_type->name, String(), String(), base_indent);
}
}
+ };
+
+ if (p_icall.get_arguments_count()) {
+ if (p_icall.is_vararg) {
+ String vararg_arg = "arg" + argc_str;
+ String real_argc_str = itos(p_icall.get_arguments_count() - 1); // Arguments count without vararg
- p_output.append(CLOSE_BLOCK "\n");
+ p_icall.get_arguments_count();
- if (im_icall->editor_only) {
- p_output.append("#endif // TOOLS_ENABLED\n");
+ r_output << INDENT2 "int vararg_length = " << vararg_arg << ".Length;\n"
+ << INDENT2 "int total_length = " << real_argc_str << " + vararg_length;\n";
+
+ r_output << INDENT2 "Span<godot_variant.movable> varargs_span = vararg_length <= VarArgsSpanThreshold ?\n"
+ << INDENT3 "stackalloc godot_variant.movable[VarArgsSpanThreshold].Cleared() :\n"
+ << INDENT3 "new godot_variant.movable[vararg_length];\n";
+
+ r_output << INDENT2 "Span<IntPtr> " C_LOCAL_PTRCALL_ARGS "_span = total_length <= VarArgsSpanThreshold ?\n"
+ << INDENT3 "stackalloc IntPtr[VarArgsSpanThreshold] :\n"
+ << INDENT3 "new IntPtr[total_length];\n";
+
+ r_output << INDENT2 "using var variantSpanDisposer = new VariantSpanDisposer(varargs_span);\n";
+
+ r_output << INDENT2 "fixed (godot_variant.movable* varargs = &MemoryMarshal.GetReference(varargs_span))\n"
+ << INDENT2 "fixed (IntPtr* " C_LOCAL_PTRCALL_ARGS " = "
+ "&MemoryMarshal.GetReference(" C_LOCAL_PTRCALL_ARGS "_span))\n"
+ << OPEN_BLOCK_L2;
+
+ r_output << c_in_statements.as_string();
+
+ r_output << INDENT3 "for (int i = 0; i < vararg_length; i++) " OPEN_BLOCK
+ << INDENT4 "varargs[i] = " << vararg_arg << "[i].NativeVar;\n"
+ << INDENT4 C_LOCAL_PTRCALL_ARGS "[" << real_argc_str << " + i] = new IntPtr(&varargs[i]);\n"
+ << CLOSE_BLOCK_L3;
+
+ generate_call_and_return_stmts(INDENT3);
+
+ r_output << CLOSE_BLOCK_L2;
+ } else {
+ r_output << c_in_statements.as_string();
+
+ r_output << INDENT2 "void** " C_LOCAL_PTRCALL_ARGS " = stackalloc void*["
+ << argc_str << "] { " << c_args_var_content.as_string() << " };\n";
+
+ generate_call_and_return_stmts(INDENT2);
}
+ } else {
+ generate_call_and_return_stmts(INDENT2);
}
+ r_output << CLOSE_BLOCK_L1;
+
+ return OK;
+}
+
+Error BindingsGenerator::_save_file(const String &p_path, const StringBuilder &p_content) {
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE);
+ ERR_FAIL_COND_V_MSG(file.is_null(), ERR_FILE_CANT_WRITE, "Cannot open file: '" + p_path + "'.");
+
+ file->store_string(p_content.as_string());
+
return OK;
}
@@ -2514,27 +2548,6 @@ const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_null(con
return nullptr;
}
-const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_placeholder(const TypeReference &p_typeref) {
- const TypeInterface *found = _get_type_or_null(p_typeref);
-
- if (found) {
- return found;
- }
-
- ERR_PRINT(String() + "Type not found. Creating placeholder: '" + p_typeref.cname.operator String() + "'.");
-
- HashMap<StringName, TypeInterface>::ConstIterator match = placeholder_types.find(p_typeref.cname);
-
- if (match) {
- return &match->value;
- }
-
- TypeInterface placeholder;
- TypeInterface::create_placeholder_type(placeholder, p_typeref.cname);
-
- return &placeholder_types.insert(placeholder.cname, placeholder)->value;
-}
-
const String BindingsGenerator::_get_generic_type_parameters(const TypeInterface &p_itype, const List<TypeReference> &p_generic_type_parameters) {
if (p_generic_type_parameters.is_empty()) {
return "";
@@ -2548,7 +2561,8 @@ const String BindingsGenerator::_get_generic_type_parameters(const TypeInterface
int i = 0;
String params = "<";
for (const TypeReference &param_type : p_generic_type_parameters) {
- const TypeInterface *param_itype = _get_type_or_placeholder(param_type);
+ const TypeInterface *param_itype = _get_type_or_null(param_type);
+ ERR_FAIL_NULL_V(param_itype, "");
ERR_FAIL_COND_V_MSG(param_itype->is_singleton, "",
"Generic type parameter is a singleton: '" + param_itype->name + "'.");
@@ -2666,8 +2680,6 @@ bool BindingsGenerator::_arg_default_value_is_assignable_to_type(const Variant &
case Variant::RECT2:
case Variant::VECTOR3:
case Variant::RID:
- case Variant::ARRAY:
- case Variant::DICTIONARY:
case Variant::PACKED_BYTE_ARRAY:
case Variant::PACKED_INT32_ARRAY:
case Variant::PACKED_INT64_ARRAY:
@@ -2680,6 +2692,10 @@ bool BindingsGenerator::_arg_default_value_is_assignable_to_type(const Variant &
case Variant::CALLABLE:
case Variant::SIGNAL:
return p_arg_type.name == Variant::get_type_name(p_val.get_type());
+ case Variant::ARRAY:
+ return p_arg_type.name == Variant::get_type_name(p_val.get_type()) || p_arg_type.cname == name_cache.type_Array_generic;
+ case Variant::DICTIONARY:
+ return p_arg_type.name == Variant::get_type_name(p_val.get_type()) || p_arg_type.cname == name_cache.type_Dictionary_generic;
case Variant::OBJECT:
return p_arg_type.is_object_type;
case Variant::VECTOR2I:
@@ -2744,18 +2760,27 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
itype.is_ref_counted = ClassDB::is_parent_class(type_cname, name_cache.type_RefCounted);
itype.memory_own = itype.is_ref_counted;
- itype.c_out = "\treturn ";
+ itype.cs_variant_to_managed = "(%1)VariantUtils.ConvertToGodotObject(%0)";
+ itype.cs_managed_to_variant = "VariantUtils.CreateFromGodotObject(%0)";
+
+ itype.c_out = "%5return ";
itype.c_out += C_METHOD_UNMANAGED_GET_MANAGED;
- itype.c_out += itype.is_ref_counted ? "(%1.ptr());\n" : "(%1);\n";
+ itype.c_out += itype.is_ref_counted ? "(%1.Reference);\n" : "(%1);\n";
+
+ itype.cs_type = itype.proxy_name;
+
+ if (itype.is_singleton) {
+ itype.cs_in_expr = "Object." CS_STATIC_METHOD_GETINSTANCE "(" CS_PROPERTY_SINGLETON ")";
+ } else {
+ itype.cs_in_expr = "Object." CS_STATIC_METHOD_GETINSTANCE "(%0)";
+ }
- itype.cs_in = itype.is_singleton ? BINDINGS_PTR_FIELD : "Object." CS_SMETHOD_GETINSTANCE "(%0)";
+ itype.cs_out = "%5return (%2)%0(%1);";
- itype.c_type = "Object*";
+ itype.c_arg_in = "(void*)%s";
+ itype.c_type = "IntPtr";
itype.c_type_in = itype.c_type;
- itype.c_type_out = "MonoObject*";
- itype.cs_type = itype.proxy_name;
- itype.im_type_in = "IntPtr";
- itype.im_type_out = itype.proxy_name;
+ itype.c_type_out = "Object";
// Populate properties
@@ -2846,6 +2871,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
if (method_info.flags & METHOD_FLAG_VIRTUAL) {
imethod.is_virtual = true;
+ itype.has_virtual_methods = true;
}
PropertyInfo return_info = method_info.return_val;
@@ -2887,7 +2913,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
String() + "Return type is reference but hint is not '" _STR(PROPERTY_HINT_RESOURCE_TYPE) "'." +
" Are you returning a reference type by pointer? Method: '" + itype.name + "." + imethod.name + "'.");
} else if (return_info.type == Variant::ARRAY && return_info.hint == PROPERTY_HINT_ARRAY_TYPE) {
- imethod.return_type.cname = Variant::get_type_name(return_info.type);
+ imethod.return_type.cname = Variant::get_type_name(return_info.type) + "_@generic";
imethod.return_type.generic_type_parameters.push_back(TypeReference(return_info.hint_string));
} else if (return_info.hint == PROPERTY_HINT_RESOURCE_TYPE) {
imethod.return_type.cname = return_info.hint_string;
@@ -2919,7 +2945,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
} else if (arginfo.class_name != StringName()) {
iarg.type.cname = arginfo.class_name;
} else if (arginfo.type == Variant::ARRAY && arginfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
- iarg.type.cname = Variant::get_type_name(arginfo.type);
+ iarg.type.cname = Variant::get_type_name(arginfo.type) + "_@generic";
iarg.type.generic_type_parameters.push_back(TypeReference(arginfo.hint_string));
} else if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
iarg.type.cname = arginfo.hint_string;
@@ -2985,7 +3011,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
ERR_FAIL_COND_V_MSG(itype.find_property_by_name(imethod.cname), false,
"Method name conflicts with property: '" + itype.name + "." + imethod.name + "'.");
- // Classes starting with an underscore are ignored unless they're used as a property setter or getter
+ // Methods starting with an underscore are ignored unless they're used as a property setter or getter
if (!imethod.is_virtual && imethod.name[0] == '_') {
for (const PropertyInterface &iprop : itype.properties) {
if (iprop.setter == imethod.name || iprop.getter == imethod.name) {
@@ -3027,7 +3053,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
} else if (arginfo.class_name != StringName()) {
iarg.type.cname = arginfo.class_name;
} else if (arginfo.type == Variant::ARRAY && arginfo.hint == PROPERTY_HINT_ARRAY_TYPE) {
- iarg.type.cname = Variant::get_type_name(arginfo.type);
+ iarg.type.cname = Variant::get_type_name(arginfo.type) + "_@generic";
iarg.type.generic_type_parameters.push_back(TypeReference(arginfo.hint_string));
} else if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
iarg.type.cname = arginfo.hint_string;
@@ -3132,6 +3158,8 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
enum_itype.cname = StringName(enum_itype.name);
enum_itype.proxy_name = itype.proxy_name + "." + enum_proxy_name;
TypeInterface::postsetup_enum_type(enum_itype);
+ enum_itype.cs_variant_to_managed = "(%1)VariantUtils.ConvertToInt32(%0)";
+ enum_itype.cs_managed_to_variant = "VariantUtils.CreateFromInt((int)%0)";
enum_types.insert(enum_itype.cname, enum_itype);
}
@@ -3169,7 +3197,7 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
switch (p_val.get_type()) {
case Variant::NIL:
// Either Object type or Variant
- r_iarg.default_argument = "null";
+ r_iarg.default_argument = "default";
break;
// Atomic types
case Variant::BOOL:
@@ -3189,8 +3217,13 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
case Variant::STRING_NAME:
case Variant::NODE_PATH:
if (r_iarg.type.cname == name_cache.type_StringName || r_iarg.type.cname == name_cache.type_NodePath) {
- r_iarg.default_argument = "(%s)\"" + r_iarg.default_argument + "\"";
- r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF;
+ if (r_iarg.default_argument.length() > 0) {
+ r_iarg.default_argument = "(%s)\"" + r_iarg.default_argument + "\"";
+ r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF;
+ } else {
+ // No need for a special `in` statement to change `null` to `""`. Marshaling takes care of this already.
+ r_iarg.default_argument = "null";
+ }
} else {
CRASH_COND(r_iarg.type.cname != name_cache.type_String);
r_iarg.default_argument = "\"" + r_iarg.default_argument + "\"";
@@ -3236,8 +3269,11 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
r_iarg.default_argument = "null";
break;
case Variant::DICTIONARY:
- r_iarg.default_argument = "new %s()";
- r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF;
+ ERR_FAIL_COND_V_MSG(!p_val.operator Dictionary().is_empty(), false,
+ "Default value of type 'Dictionary' must be an empty dictionary.");
+ // The [cs_in] expression already interprets null values as empty dictionaries.
+ r_iarg.default_argument = "null";
+ r_iarg.def_param_mode = ArgumentInterface::CONSTANT;
break;
case Variant::RID:
ERR_FAIL_COND_V_MSG(r_iarg.type.cname != name_cache.type_RID, false,
@@ -3246,11 +3282,14 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
ERR_FAIL_COND_V_MSG(!p_val.is_zero(), false,
"Parameter of type '" + String(r_iarg.type.cname) + "' can only have null/zero as the default value.");
- r_iarg.default_argument = "null";
+ r_iarg.default_argument = "default";
break;
case Variant::ARRAY:
- r_iarg.default_argument = "new %s { }";
- r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF;
+ ERR_FAIL_COND_V_MSG(!p_val.operator Array().is_empty(), false,
+ "Default value of type 'Array' must be an empty array.");
+ // The [cs_in] expression already interprets null values as empty arrays.
+ r_iarg.default_argument = "null";
+ r_iarg.def_param_mode = ArgumentInterface::CONSTANT;
break;
case Variant::PACKED_BYTE_ARRAY:
case Variant::PACKED_INT32_ARRAY:
@@ -3325,12 +3364,12 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
r_iarg.default_argument = "default";
break;
default:
- CRASH_NOW_MSG("Unexpected Variant type: " + itos(p_val.get_type()));
+ ERR_FAIL_V_MSG(false, "Unexpected Variant type: " + itos(p_val.get_type()));
break;
}
- if (r_iarg.def_param_mode == ArgumentInterface::CONSTANT && r_iarg.type.cname == name_cache.type_Variant && r_iarg.default_argument != "null") {
- r_iarg.def_param_mode = ArgumentInterface::NULLABLE_REF;
+ if (r_iarg.def_param_mode == ArgumentInterface::CONSTANT && r_iarg.type.cname == name_cache.type_Variant && r_iarg.default_argument != "default") {
+ r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
}
return true;
@@ -3344,16 +3383,12 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
#define INSERT_STRUCT_TYPE(m_type) \
{ \
itype = TypeInterface::create_value_type(String(#m_type)); \
- itype.c_in = "\t%0 %1_in = MARSHALLED_IN(" #m_type ", %1);\n"; \
- itype.c_out = "\t*%3 = MARSHALLED_OUT(" #m_type ", %1);\n"; \
- itype.c_arg_in = "&%s_in"; \
- itype.c_type_in = "GDMonoMarshal::M_" #m_type "*"; \
- itype.c_type_out = "GDMonoMarshal::M_" #m_type; \
- itype.cs_in = "ref %s"; \
- /* in cs_out, im_type_out (%3) includes the 'out ' part */ \
- itype.cs_out = "%0(%1, %3 argRet); return argRet;"; \
- itype.im_type_out = "out " + itype.cs_type; \
- itype.ret_as_byref_arg = true; \
+ itype.c_type_in = #m_type "*"; \
+ itype.c_type_out = itype.cs_type; \
+ itype.cs_in_expr = "&%0"; \
+ itype.cs_in_expr_is_unsafe = true; \
+ itype.cs_variant_to_managed = "VariantUtils.ConvertTo%2(%0)"; \
+ itype.cs_managed_to_variant = "VariantUtils.CreateFrom%2(%0)"; \
builtin_types.insert(itype.cname, itype); \
}
@@ -3370,54 +3405,60 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
INSERT_STRUCT_TYPE(AABB)
INSERT_STRUCT_TYPE(Color)
INSERT_STRUCT_TYPE(Plane)
+ INSERT_STRUCT_TYPE(Vector4)
+ INSERT_STRUCT_TYPE(Vector4i)
+ INSERT_STRUCT_TYPE(Projection)
#undef INSERT_STRUCT_TYPE
// bool
itype = TypeInterface::create_value_type(String("bool"));
- {
- // MonoBoolean <---> bool
- itype.c_in = "\t%0 %1_in = (%0)%1;\n";
- itype.c_out = "\treturn (%0)%1;\n";
- itype.c_type = "bool";
- itype.c_type_in = "MonoBoolean";
- itype.c_type_out = itype.c_type_in;
- itype.c_arg_in = "&%s_in";
- }
- itype.im_type_in = itype.name;
- itype.im_type_out = itype.name;
+ itype.cs_in_expr = "%0.ToGodotBool()";
+ itype.cs_out = "%5return %0(%1).ToBool();";
+ itype.c_type = "godot_bool";
+ itype.c_type_in = itype.c_type;
+ itype.c_type_out = itype.c_type;
+ itype.c_arg_in = "&%s";
+ itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromBool(%1);\n";
+ itype.cs_variant_to_managed = "VariantUtils.ConvertToBool(%0)";
+ itype.cs_managed_to_variant = "VariantUtils.CreateFromBool(%0)";
builtin_types.insert(itype.cname, itype);
// Integer types
{
// C interface for 'uint32_t' is the same as that of enums. Remember to apply
// any of the changes done here to 'TypeInterface::postsetup_enum_type' as well.
-#define INSERT_INT_TYPE(m_name, m_c_type_in_out, m_c_type) \
- { \
- itype = TypeInterface::create_value_type(String(m_name)); \
- { \
- itype.c_in = "\t%0 %1_in = (%0)%1;\n"; \
- itype.c_out = "\treturn (%0)%1;\n"; \
- itype.c_type = #m_c_type; \
- itype.c_arg_in = "&%s_in"; \
- } \
- itype.c_type_in = #m_c_type_in_out; \
- itype.c_type_out = itype.c_type_in; \
- itype.im_type_in = itype.name; \
- itype.im_type_out = itype.name; \
- builtin_types.insert(itype.cname, itype); \
+#define INSERT_INT_TYPE(m_name, m_int_struct_name) \
+ { \
+ itype = TypeInterface::create_value_type(String(m_name)); \
+ if (itype.name != "long" && itype.name != "ulong") { \
+ itype.c_in = "%5%0 %1_in = %1;\n"; \
+ itype.c_out = "%5return (%0)%1;\n"; \
+ itype.c_type = "long"; \
+ itype.c_arg_in = "&%s_in"; \
+ } else { \
+ itype.c_arg_in = "&%s"; \
+ } \
+ itype.c_type_in = itype.name; \
+ itype.c_type_out = itype.name; \
+ itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromInt(%1);\n"; \
+ itype.cs_variant_to_managed = "VariantUtils.ConvertTo" m_int_struct_name "(%0)"; \
+ itype.cs_managed_to_variant = "VariantUtils.CreateFromInt(%0)"; \
+ builtin_types.insert(itype.cname, itype); \
}
// The expected type for all integers in ptrcall is 'int64_t', so that's what we use for 'c_type'
- INSERT_INT_TYPE("sbyte", int8_t, int64_t);
- INSERT_INT_TYPE("short", int16_t, int64_t);
- INSERT_INT_TYPE("int", int32_t, int64_t);
- INSERT_INT_TYPE("long", int64_t, int64_t);
- INSERT_INT_TYPE("byte", uint8_t, int64_t);
- INSERT_INT_TYPE("ushort", uint16_t, int64_t);
- INSERT_INT_TYPE("uint", uint32_t, int64_t);
- INSERT_INT_TYPE("ulong", uint64_t, int64_t);
+ INSERT_INT_TYPE("sbyte", "Int8");
+ INSERT_INT_TYPE("short", "Int16");
+ INSERT_INT_TYPE("int", "Int32");
+ INSERT_INT_TYPE("long", "Int64");
+ INSERT_INT_TYPE("byte", "UInt8");
+ INSERT_INT_TYPE("ushort", "UInt16");
+ INSERT_INT_TYPE("uint", "UInt32");
+ INSERT_INT_TYPE("ulong", "UInt64");
+
+#undef INSERT_INT_TYPE
}
// Floating point types
@@ -3427,18 +3468,19 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "float";
itype.cname = itype.name;
itype.proxy_name = "float";
+ itype.cs_type = itype.proxy_name;
{
// The expected type for 'float' in ptrcall is 'double'
- itype.c_in = "\t%0 %1_in = (%0)%1;\n";
- itype.c_out = "\treturn (%0)%1;\n";
+ itype.c_in = "%5%0 %1_in = %1;\n";
+ itype.c_out = "%5return (%0)%1;\n";
itype.c_type = "double";
- itype.c_type_in = "float";
- itype.c_type_out = "float";
itype.c_arg_in = "&%s_in";
}
- itype.cs_type = itype.proxy_name;
- itype.im_type_in = itype.proxy_name;
- itype.im_type_out = itype.proxy_name;
+ itype.c_type_in = itype.proxy_name;
+ itype.c_type_out = itype.proxy_name;
+ itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromFloat(%1);\n";
+ itype.cs_variant_to_managed = "VariantUtils.ConvertToFloat32(%0)";
+ itype.cs_managed_to_variant = "VariantUtils.CreateFromFloat(%0)";
builtin_types.insert(itype.cname, itype);
// double
@@ -3446,15 +3488,14 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "double";
itype.cname = itype.name;
itype.proxy_name = "double";
- {
- itype.c_type = "double";
- itype.c_type_in = "double";
- itype.c_type_out = "double";
- itype.c_arg_in = "&%s";
- }
itype.cs_type = itype.proxy_name;
- itype.im_type_in = itype.proxy_name;
- itype.im_type_out = itype.proxy_name;
+ itype.c_type = "double";
+ itype.c_arg_in = "&%s";
+ itype.c_type_in = itype.proxy_name;
+ itype.c_type_out = itype.proxy_name;
+ itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromFloat(%1);\n";
+ itype.cs_variant_to_managed = "VariantUtils.ConvertToFloat64(%0)";
+ itype.cs_managed_to_variant = "VariantUtils.CreateFromFloat(%0)";
builtin_types.insert(itype.cname, itype);
}
@@ -3463,15 +3504,17 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "String";
itype.cname = itype.name;
itype.proxy_name = "string";
- itype.c_in = "\t%0 %1_in = " C_METHOD_MONOSTR_TO_GODOT "(%1);\n";
- itype.c_out = "\treturn " C_METHOD_MONOSTR_FROM_GODOT "(%1);\n";
- itype.c_arg_in = "&%s_in";
- itype.c_type = itype.name;
- itype.c_type_in = "MonoString*";
- itype.c_type_out = "MonoString*";
itype.cs_type = itype.proxy_name;
- itype.im_type_in = itype.proxy_name;
- itype.im_type_out = itype.proxy_name;
+ itype.c_in = "%5using %0 %1_in = " C_METHOD_MONOSTR_TO_GODOT "(%1);\n";
+ itype.c_out = "%5return " C_METHOD_MONOSTR_FROM_GODOT "(%1);\n";
+ itype.c_arg_in = "&%s_in";
+ itype.c_type = "godot_string";
+ itype.c_type_in = itype.cs_type;
+ itype.c_type_out = itype.cs_type;
+ itype.c_type_is_disposable_struct = true;
+ itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromString(%1);\n";
+ itype.cs_variant_to_managed = "VariantUtils.ConvertToStringObject(%0)";
+ itype.cs_managed_to_variant = "VariantUtils.CreateFromString(%0)";
builtin_types.insert(itype.cname, itype);
// StringName
@@ -3479,17 +3522,19 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "StringName";
itype.cname = itype.name;
itype.proxy_name = "StringName";
- itype.c_in = "\t%0 %1_in = %1 ? *%1 : StringName();\n";
- itype.c_out = "\treturn memnew(StringName(%1));\n";
- itype.c_arg_in = "&%s_in";
- itype.c_type = itype.name;
- itype.c_type_in = itype.c_type + "*";
- itype.c_type_out = itype.c_type + "*";
itype.cs_type = itype.proxy_name;
- itype.cs_in = "StringName." CS_SMETHOD_GETINSTANCE "(%0)";
- itype.cs_out = "return new %2(%0(%1));";
- itype.im_type_in = "IntPtr";
- itype.im_type_out = "IntPtr";
+ itype.cs_in_expr = "(%1)(%0?.NativeValue ?? default)";
+ // Cannot pass null StringName to ptrcall
+ itype.c_out = "%5return %0.CreateTakingOwnershipOfDisposableValue(%1);\n";
+ itype.c_arg_in = "&%s";
+ itype.c_type = "godot_string_name";
+ itype.c_type_in = itype.c_type;
+ itype.c_type_out = itype.cs_type;
+ itype.c_in_vararg = "%5using godot_variant %1_in = VariantUtils.CreateFromStringName(%1);\n";
+ itype.c_type_is_disposable_struct = false; // [c_out] takes ownership
+ itype.c_ret_needs_default_initialization = true;
+ itype.cs_variant_to_managed = "VariantUtils.ConvertToStringNameObject(%0)";
+ itype.cs_managed_to_variant = "VariantUtils.CreateFromStringName(%0)";
builtin_types.insert(itype.cname, itype);
// NodePath
@@ -3497,15 +3542,18 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "NodePath";
itype.cname = itype.name;
itype.proxy_name = "NodePath";
- itype.c_out = "\treturn memnew(NodePath(%1));\n";
- itype.c_type = itype.name;
- itype.c_type_in = itype.c_type + "*";
- itype.c_type_out = itype.c_type + "*";
itype.cs_type = itype.proxy_name;
- itype.cs_in = "NodePath." CS_SMETHOD_GETINSTANCE "(%0)";
- itype.cs_out = "return new %2(%0(%1));";
- itype.im_type_in = "IntPtr";
- itype.im_type_out = "IntPtr";
+ itype.cs_in_expr = "(%1)(%0?.NativeValue ?? default)";
+ // Cannot pass null NodePath to ptrcall
+ itype.c_out = "%5return %0.CreateTakingOwnershipOfDisposableValue(%1);\n";
+ itype.c_arg_in = "&%s";
+ itype.c_type = "godot_node_path";
+ itype.c_type_in = itype.c_type;
+ itype.c_type_out = itype.cs_type;
+ itype.c_type_is_disposable_struct = false; // [c_out] takes ownership
+ itype.c_ret_needs_default_initialization = true;
+ itype.cs_variant_to_managed = "VariantUtils.ConvertToNodePathObject(%0)";
+ itype.cs_managed_to_variant = "VariantUtils.CreateFromNodePath(%0)";
builtin_types.insert(itype.cname, itype);
// RID
@@ -3513,45 +3561,45 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "RID";
itype.cname = itype.name;
itype.proxy_name = "RID";
- itype.c_out = "\treturn memnew(RID(%1));\n";
- itype.c_type = itype.name;
- itype.c_type_in = itype.c_type + "*";
- itype.c_type_out = itype.c_type + "*";
itype.cs_type = itype.proxy_name;
- itype.cs_in = "RID." CS_SMETHOD_GETINSTANCE "(%0)";
- itype.cs_out = "return new %2(%0(%1));";
- itype.im_type_in = "IntPtr";
- itype.im_type_out = "IntPtr";
+ itype.c_arg_in = "&%s";
+ itype.c_type = itype.cs_type;
+ itype.c_type_in = itype.c_type;
+ itype.c_type_out = itype.c_type;
+ itype.cs_variant_to_managed = "VariantUtils.ConvertToRID(%0)";
+ itype.cs_managed_to_variant = "VariantUtils.CreateFromRID(%0)";
builtin_types.insert(itype.cname, itype);
// Variant
itype = TypeInterface();
itype.name = "Variant";
itype.cname = itype.name;
- itype.proxy_name = "object";
- itype.c_in = "\t%0 %1_in = " C_METHOD_MANAGED_TO_VARIANT "(%1);\n";
- itype.c_out = "\treturn " C_METHOD_MANAGED_FROM_VARIANT "(%1);\n";
- itype.c_arg_in = "&%s_in";
- itype.c_type = itype.name;
- itype.c_type_in = "MonoObject*";
- itype.c_type_out = "MonoObject*";
+ itype.proxy_name = "Variant";
itype.cs_type = itype.proxy_name;
- itype.im_type_in = "object";
- itype.im_type_out = itype.proxy_name;
+ itype.c_in = "%5%0 %1_in = (%0)%1.NativeVar;\n";
+ itype.c_out = "%5return Variant.CreateTakingOwnershipOfDisposableValue(%1);\n";
+ itype.c_arg_in = "&%s_in";
+ itype.c_type = "godot_variant";
+ itype.c_type_in = itype.cs_type;
+ itype.c_type_out = itype.cs_type;
+ itype.c_type_is_disposable_struct = false; // [c_out] takes ownership
+ itype.c_ret_needs_default_initialization = true;
+ itype.cs_variant_to_managed = "Variant.CreateCopyingBorrowed(%0)";
+ itype.cs_managed_to_variant = "%0.CopyNativeVariant()";
builtin_types.insert(itype.cname, itype);
// Callable
itype = TypeInterface::create_value_type(String("Callable"));
- itype.c_in = "\t%0 %1_in = " C_METHOD_MANAGED_TO_CALLABLE "(*%1);\n";
- itype.c_out = "\t*%3 = " C_METHOD_MANAGED_FROM_CALLABLE "(%1);\n";
+ itype.cs_in_expr = "%0";
+ itype.c_in = "%5using %0 %1_in = " C_METHOD_MANAGED_TO_CALLABLE "(in %1);\n";
+ itype.c_out = "%5return " C_METHOD_MANAGED_FROM_CALLABLE "(in %1);\n";
itype.c_arg_in = "&%s_in";
- itype.c_type_in = "GDMonoMarshal::M_Callable*";
- itype.c_type_out = "GDMonoMarshal::M_Callable";
- itype.cs_in = "ref %s";
- /* in cs_out, im_type_out (%3) includes the 'out ' part */
- itype.cs_out = "%0(%1, %3 argRet); return argRet;";
- itype.im_type_out = "out " + itype.cs_type;
- itype.ret_as_byref_arg = true;
+ itype.c_type = "godot_callable";
+ itype.c_type_in = "in " + itype.cs_type;
+ itype.c_type_out = itype.cs_type;
+ itype.c_type_is_disposable_struct = true;
+ itype.cs_variant_to_managed = "VariantUtils.ConvertToCallableManaged(%0)";
+ itype.cs_managed_to_variant = "VariantUtils.CreateFromCallable(%0)";
builtin_types.insert(itype.cname, itype);
// Signal
@@ -3559,66 +3607,65 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "Signal";
itype.cname = itype.name;
itype.proxy_name = "SignalInfo";
- itype.c_in = "\t%0 %1_in = " C_METHOD_MANAGED_TO_SIGNAL "(*%1);\n";
- itype.c_out = "\t*%3 = " C_METHOD_MANAGED_FROM_SIGNAL "(%1);\n";
- itype.c_arg_in = "&%s_in";
- itype.c_type = itype.name;
- itype.c_type_in = "GDMonoMarshal::M_SignalInfo*";
- itype.c_type_out = "GDMonoMarshal::M_SignalInfo";
- itype.cs_in = "ref %s";
- /* in cs_out, im_type_out (%3) includes the 'out ' part */
- itype.cs_out = "%0(%1, %3 argRet); return argRet;";
itype.cs_type = itype.proxy_name;
- itype.im_type_in = "ref " + itype.cs_type;
- itype.im_type_out = "out " + itype.cs_type;
- itype.ret_as_byref_arg = true;
+ itype.cs_in_expr = "%0";
+ itype.c_in = "%5using %0 %1_in = " C_METHOD_MANAGED_TO_SIGNAL "(in %1);\n";
+ itype.c_out = "%5return " C_METHOD_MANAGED_FROM_SIGNAL "(&%1);\n";
+ itype.c_arg_in = "&%s_in";
+ itype.c_type = "godot_signal";
+ itype.c_type_in = "in " + itype.cs_type;
+ itype.c_type_out = itype.cs_type;
+ itype.c_type_is_disposable_struct = true;
+ itype.cs_variant_to_managed = "VariantUtils.ConvertToSignalInfo(%0)";
+ itype.cs_managed_to_variant = "VariantUtils.CreateFromSignalInfo(%0)";
builtin_types.insert(itype.cname, itype);
// VarArg (fictitious type to represent variable arguments)
itype = TypeInterface();
itype.name = "VarArg";
itype.cname = itype.name;
- itype.proxy_name = "object[]";
- itype.c_in = "\t%0 %1_in = " C_METHOD_MONOARRAY_TO(Array) "(%1);\n";
+ itype.proxy_name = "Variant[]";
+ itype.cs_type = "params Variant[]";
+ itype.cs_in_expr = "%0 ?? Array.Empty<Variant>()";
+ // c_type, c_in and c_arg_in are hard-coded in the generator.
+ // c_out and c_type_out are not applicable to VarArg.
itype.c_arg_in = "&%s_in";
- itype.c_type = "Array";
- itype.c_type_in = "MonoArray*";
- itype.cs_type = "params object[]";
- itype.im_type_in = "object[]";
+ itype.c_type_in = "Variant[]";
builtin_types.insert(itype.cname, itype);
-#define INSERT_ARRAY_FULL(m_name, m_type, m_proxy_t) \
- { \
- itype = TypeInterface(); \
- itype.name = #m_name; \
- itype.cname = itype.name; \
- itype.proxy_name = #m_proxy_t "[]"; \
- itype.c_in = "\t%0 %1_in = " C_METHOD_MONOARRAY_TO(m_type) "(%1);\n"; \
- itype.c_out = "\treturn " C_METHOD_MONOARRAY_FROM(m_type) "(%1);\n"; \
- itype.c_arg_in = "&%s_in"; \
- itype.c_type = #m_type; \
- itype.c_type_in = "MonoArray*"; \
- itype.c_type_out = "MonoArray*"; \
- itype.cs_type = itype.proxy_name; \
- itype.im_type_in = itype.proxy_name; \
- itype.im_type_out = itype.proxy_name; \
- builtin_types.insert(itype.name, itype); \
+#define INSERT_ARRAY_FULL(m_name, m_type, m_managed_type, m_proxy_t) \
+ { \
+ itype = TypeInterface(); \
+ itype.name = #m_name; \
+ itype.cname = itype.name; \
+ itype.proxy_name = #m_proxy_t "[]"; \
+ itype.cs_type = itype.proxy_name; \
+ itype.c_in = "%5using %0 %1_in = " C_METHOD_MONOARRAY_TO(m_type) "(%1);\n"; \
+ itype.c_out = "%5return " C_METHOD_MONOARRAY_FROM(m_type) "(%1);\n"; \
+ itype.c_arg_in = "&%s_in"; \
+ itype.c_type = #m_managed_type; \
+ itype.c_type_in = itype.proxy_name; \
+ itype.c_type_out = itype.proxy_name; \
+ itype.c_type_is_disposable_struct = true; \
+ itype.cs_variant_to_managed = "VariantUtils.ConvertAs%2ToSystemArray(%0)"; \
+ itype.cs_managed_to_variant = "VariantUtils.CreateFrom%2(%0)"; \
+ builtin_types.insert(itype.name, itype); \
}
-#define INSERT_ARRAY(m_type, m_proxy_t) INSERT_ARRAY_FULL(m_type, m_type, m_proxy_t)
+#define INSERT_ARRAY(m_type, m_managed_type, m_proxy_t) INSERT_ARRAY_FULL(m_type, m_type, m_managed_type, m_proxy_t)
- INSERT_ARRAY(PackedInt32Array, int);
- INSERT_ARRAY(PackedInt64Array, long);
- INSERT_ARRAY_FULL(PackedByteArray, PackedByteArray, byte);
+ INSERT_ARRAY(PackedInt32Array, godot_packed_int32_array, int);
+ INSERT_ARRAY(PackedInt64Array, godot_packed_int64_array, long);
+ INSERT_ARRAY_FULL(PackedByteArray, PackedByteArray, godot_packed_byte_array, byte);
- INSERT_ARRAY(PackedFloat32Array, float);
- INSERT_ARRAY(PackedFloat64Array, double);
+ INSERT_ARRAY(PackedFloat32Array, godot_packed_float32_array, float);
+ INSERT_ARRAY(PackedFloat64Array, godot_packed_float64_array, double);
- INSERT_ARRAY(PackedStringArray, string);
+ INSERT_ARRAY(PackedStringArray, godot_packed_string_array, string);
- INSERT_ARRAY(PackedColorArray, Color);
- INSERT_ARRAY(PackedVector2Array, Vector2);
- INSERT_ARRAY(PackedVector3Array, Vector3);
+ INSERT_ARRAY(PackedColorArray, godot_packed_color_array, Color);
+ INSERT_ARRAY(PackedVector2Array, godot_packed_vector2_array, Vector2);
+ INSERT_ARRAY(PackedVector3Array, godot_packed_vector3_array, Vector3);
#undef INSERT_ARRAY
@@ -3628,15 +3675,24 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.cname = itype.name;
itype.proxy_name = itype.name;
itype.type_parameter_count = 1;
- itype.c_out = "\treturn memnew(Array(%1));\n";
- itype.c_type = itype.name;
- itype.c_type_in = itype.c_type + "*";
- itype.c_type_out = itype.c_type + "*";
itype.cs_type = BINDINGS_NAMESPACE_COLLECTIONS "." + itype.proxy_name;
- itype.cs_in = "%0." CS_SMETHOD_GETINSTANCE "()";
- itype.cs_out = "return new %2(%0(%1));";
- itype.im_type_in = "IntPtr";
- itype.im_type_out = "IntPtr";
+ itype.cs_in_expr = "(%1)(%0 ?? new()).NativeValue";
+ itype.c_out = "%5return %0.CreateTakingOwnershipOfDisposableValue(%1);\n";
+ itype.c_arg_in = "&%s";
+ itype.c_type = "godot_array";
+ itype.c_type_in = itype.c_type;
+ itype.c_type_out = itype.cs_type;
+ itype.c_type_is_disposable_struct = false; // [c_out] takes ownership
+ itype.c_ret_needs_default_initialization = true;
+ itype.cs_variant_to_managed = "VariantUtils.ConvertToArrayObject(%0)";
+ itype.cs_managed_to_variant = "VariantUtils.CreateFromArray(%0)";
+ builtin_types.insert(itype.cname, itype);
+
+ // Array_@generic
+ // Re-use Array's itype
+ itype.name = "Array_@generic";
+ itype.cname = itype.name;
+ itype.cs_out = "%5return new %2(%0(%1));";
builtin_types.insert(itype.cname, itype);
// Dictionary
@@ -3645,15 +3701,24 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.cname = itype.name;
itype.proxy_name = itype.name;
itype.type_parameter_count = 2;
- itype.c_out = "\treturn memnew(Dictionary(%1));\n";
- itype.c_type = itype.name;
- itype.c_type_in = itype.c_type + "*";
- itype.c_type_out = itype.c_type + "*";
itype.cs_type = BINDINGS_NAMESPACE_COLLECTIONS "." + itype.proxy_name;
- itype.cs_in = "%0." CS_SMETHOD_GETINSTANCE "()";
- itype.cs_out = "return new %2(%0(%1));";
- itype.im_type_in = "IntPtr";
- itype.im_type_out = "IntPtr";
+ itype.cs_in_expr = "(%1)(%0 ?? new()).NativeValue";
+ itype.c_out = "%5return %0.CreateTakingOwnershipOfDisposableValue(%1);\n";
+ itype.c_arg_in = "&%s";
+ itype.c_type = "godot_dictionary";
+ itype.c_type_in = itype.c_type;
+ itype.c_type_out = itype.cs_type;
+ itype.c_type_is_disposable_struct = false; // [c_out] takes ownership
+ itype.c_ret_needs_default_initialization = true;
+ itype.cs_variant_to_managed = "VariantUtils.ConvertToDictionaryObject(%0)";
+ itype.cs_managed_to_variant = "VariantUtils.CreateFromDictionary(%0)";
+ builtin_types.insert(itype.cname, itype);
+
+ // Dictionary_@generic
+ // Re-use Dictionary's itype
+ itype.name = "Dictionary_@generic";
+ itype.cname = itype.name;
+ itype.cs_out = "%5return new %2(%0(%1));";
builtin_types.insert(itype.cname, itype);
// void (fictitious type to represent the return type of methods that do not return anything)
@@ -3661,12 +3726,10 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
itype.name = "void";
itype.cname = itype.name;
itype.proxy_name = itype.name;
- itype.c_type = itype.name;
+ itype.cs_type = itype.proxy_name;
+ itype.c_type = itype.proxy_name;
itype.c_type_in = itype.c_type;
itype.c_type_out = itype.c_type;
- itype.cs_type = itype.proxy_name;
- itype.im_type_in = itype.proxy_name;
- itype.im_type_out = itype.proxy_name;
builtin_types.insert(itype.cname, itype);
}
@@ -3721,6 +3784,8 @@ void BindingsGenerator::_populate_global_constants() {
enum_itype.cname = ienum.cname;
enum_itype.proxy_name = enum_itype.name;
TypeInterface::postsetup_enum_type(enum_itype);
+ enum_itype.cs_variant_to_managed = "(%1)VariantUtils.ConvertToInt32(%0)";
+ enum_itype.cs_managed_to_variant = "VariantUtils.CreateFromInt((int)%0)";
enum_types.insert(enum_itype.cname, enum_itype);
int prefix_length = _determine_enum_prefix(ienum);
@@ -3753,6 +3818,8 @@ void BindingsGenerator::_populate_global_constants() {
enum_itype.cname = enum_cname;
enum_itype.proxy_name = enum_itype.name;
TypeInterface::postsetup_enum_type(enum_itype);
+ enum_itype.cs_variant_to_managed = "(%1)VariantUtils.ConvertToInt32(%0)";
+ enum_itype.cs_managed_to_variant = "VariantUtils.CreateFromInt((int)%0)";
enum_types.insert(enum_itype.cname, enum_itype);
}
}
@@ -3791,21 +3858,18 @@ void BindingsGenerator::_initialize() {
// Generate internal calls (after populating type interfaces and global constants)
- core_custom_icalls.clear();
- editor_custom_icalls.clear();
-
for (const KeyValue<StringName, TypeInterface> &E : obj_types) {
- _generate_method_icalls(E.value);
+ const TypeInterface &itype = E.value;
+ Error err = _populate_method_icalls_table(itype);
+ ERR_FAIL_COND_MSG(err != OK, "Failed to generate icalls table for type: " + itype.name);
}
initialized = true;
}
static String generate_all_glue_option = "--generate-mono-glue";
-static String generate_cs_glue_option = "--generate-mono-cs-glue";
-static String generate_cpp_glue_option = "--generate-mono-cpp-glue";
-static void handle_cmdline_options(String glue_dir_path, String cs_dir_path, String cpp_dir_path) {
+static void handle_cmdline_options(String glue_dir_path) {
BindingsGenerator bindings_generator;
bindings_generator.set_log_print_enabled(true);
@@ -3814,43 +3878,25 @@ static void handle_cmdline_options(String glue_dir_path, String cs_dir_path, Str
return;
}
- if (glue_dir_path.length()) {
- if (bindings_generator.generate_glue(glue_dir_path) != OK) {
- ERR_PRINT(generate_all_glue_option + ": Failed to generate the C++ glue.");
- }
-
- if (bindings_generator.generate_cs_api(glue_dir_path.plus_file(API_SOLUTION_NAME)) != OK) {
- ERR_PRINT(generate_all_glue_option + ": Failed to generate the C# API.");
- }
- }
+ CRASH_COND(glue_dir_path.is_empty());
- if (cs_dir_path.length()) {
- if (bindings_generator.generate_cs_api(cs_dir_path) != OK) {
- ERR_PRINT(generate_cs_glue_option + ": Failed to generate the C# API.");
- }
+ if (bindings_generator.generate_cs_api(glue_dir_path.path_join(API_SOLUTION_NAME)) != OK) {
+ ERR_PRINT(generate_all_glue_option + ": Failed to generate the C# API.");
}
+}
- if (cpp_dir_path.length()) {
- if (bindings_generator.generate_glue(cpp_dir_path) != OK) {
- ERR_PRINT(generate_cpp_glue_option + ": Failed to generate the C++ glue.");
- }
- }
+static void cleanup_and_exit_godot() {
+ // Exit once done
+ Main::cleanup(true);
+ ::exit(0);
}
void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) {
- const int NUM_OPTIONS = 2;
-
String glue_dir_path;
- String cs_dir_path;
- String cpp_dir_path;
-
- int options_left = NUM_OPTIONS;
-
- bool exit_godot = false;
const List<String>::Element *elem = p_cmdline_args.front();
- while (elem && options_left) {
+ while (elem) {
if (elem->get() == generate_all_glue_option) {
const List<String>::Element *path_elem = elem->next();
@@ -3859,48 +3905,20 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
elem = elem->next();
} else {
ERR_PRINT(generate_all_glue_option + ": No output directory specified (expected path to '{GODOT_ROOT}/modules/mono/glue').");
- exit_godot = true;
- }
-
- --options_left;
- } else if (elem->get() == generate_cs_glue_option) {
- const List<String>::Element *path_elem = elem->next();
-
- if (path_elem) {
- cs_dir_path = path_elem->get();
- elem = elem->next();
- } else {
- ERR_PRINT(generate_cs_glue_option + ": No output directory specified.");
- exit_godot = true;
+ // Exit once done with invalid command line arguments
+ cleanup_and_exit_godot();
}
- --options_left;
- } else if (elem->get() == generate_cpp_glue_option) {
- const List<String>::Element *path_elem = elem->next();
-
- if (path_elem) {
- cpp_dir_path = path_elem->get();
- elem = elem->next();
- } else {
- ERR_PRINT(generate_cpp_glue_option + ": No output directory specified.");
- exit_godot = true;
- }
-
- --options_left;
+ break;
}
elem = elem->next();
}
- if (glue_dir_path.length() || cs_dir_path.length() || cpp_dir_path.length()) {
- handle_cmdline_options(glue_dir_path, cs_dir_path, cpp_dir_path);
- exit_godot = true;
- }
-
- if (exit_godot) {
+ if (glue_dir_path.length()) {
+ handle_cmdline_options(glue_dir_path);
// Exit once done
- Main::cleanup(true);
- ::exit(0);
+ cleanup_and_exit_godot();
}
}
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index ee170e4558..c1295385dc 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -229,6 +229,23 @@ class BindingsGenerator {
bool is_ref_counted = false;
/**
+ * Determines whether the native return value of this type must be disposed
+ * by the generated internal call (think of `godot_string`, whose destructor
+ * must be called). Some structs that are disposable may still disable this
+ * flag if the ownership is transferred.
+ */
+ bool c_type_is_disposable_struct = false;
+
+ /**
+ * Determines whether the native return value of this type must be zero initialized
+ * before its address is passed to ptrcall. This is required for types whose destructor
+ * is called before being assigned the return value by `PtrToArg::encode`, e.g.:
+ * Array, Dictionary, String, StringName, Variant.
+ * It's not necessary to set this to `true` if [c_type_is_disposable_struct] is already `true`.
+ */
+ bool c_ret_needs_default_initialization = false;
+
+ /**
* Used only by Object-derived types.
* Determines if this type is not abstract (incomplete).
* e.g.: CanvasItem cannot be instantiated.
@@ -242,31 +259,34 @@ class BindingsGenerator {
*/
bool memory_own = false;
- /**
- * This must be set to true for any struct bigger than 32-bits. Those cannot be passed/returned by value
- * with internal calls, so we must use pointers instead. Returns must be replace with out parameters.
- * In this case, [c_out] and [cs_out] must have a different format, explained below.
- * The Mono IL interpreter icall trampolines don't support passing structs bigger than 32-bits by value (at least not on WASM).
- */
- bool ret_as_byref_arg = false;
-
// !! The comments of the following fields make reference to other fields via square brackets, e.g.: [field_name]
// !! When renaming those fields, make sure to rename their references in the comments
// --- C INTERFACE ---
- static const char *DEFAULT_VARARG_C_IN;
+ /**
+ * One or more statements that transform the parameter before being passed as argument of a ptrcall.
+ * If the statement adds a local that must be passed as the argument instead of the parameter,
+ * the expression with the name of that local must be specified with [c_arg_in].
+ * Formatting elements:
+ * %0: [c_type] of the parameter
+ * %1: name of the parameter
+ * %2-4: reserved
+ * %5: indentation text
+ */
+ String c_in;
/**
- * One or more statements that manipulate the parameter before being passed as argument of a ptrcall.
+ * One or more statements that transform the parameter before being passed as argument of a vararg call.
* If the statement adds a local that must be passed as the argument instead of the parameter,
* the name of that local must be specified with [c_arg_in].
- * For variadic methods, this field is required and, if empty, [DEFAULT_VARARG_C_IN] is used instead.
* Formatting elements:
* %0: [c_type] of the parameter
* %1: name of the parameter
+ * %2-4: reserved
+ * %5: indentation text
*/
- String c_in;
+ String c_in_vararg;
/**
* Determines the expression that will be passed as argument to ptrcall.
@@ -291,7 +311,8 @@ class BindingsGenerator {
* %0: [c_type_out] of the return type
* %1: name of the variable to be returned
* %2: [name] of the return type
- * %3: name of the parameter that must be assigned the return value
+ * %3-4: reserved
+ * %5: indentation text
*/
String c_out;
@@ -327,7 +348,21 @@ class BindingsGenerator {
* An expression that overrides the way the parameter is passed to the internal call.
* If empty, the parameter is passed as is.
* Formatting elements:
- * %0 or %s: name of the parameter
+ * %0: name of the parameter
+ * %1: [c_type] of the parameter
+ */
+ String cs_in_expr;
+ bool cs_in_expr_is_unsafe = false;
+
+ /**
+ * One or more statements that transform the parameter before being passed to the internal call.
+ * If the statement adds a local that must be passed as the argument instead of the parameter,
+ * the expression with the name of that local must be specified with [cs_in_expr].
+ * Formatting elements:
+ * %0: [c_type] of the parameter
+ * %1: name of the parameter
+ * %2-4: reserved
+ * %5: indentation text
*/
String cs_in;
@@ -338,7 +373,9 @@ class BindingsGenerator {
* %0: internal method name
* %1: internal method call arguments without surrounding parenthesis
* %2: [cs_type] of the return type
- * %3: [im_type_out] of the return type
+ * %3: [c_type_out] of the return type
+ * %4: reserved
+ * %5: indentation text
*/
String cs_out;
@@ -349,14 +386,20 @@ class BindingsGenerator {
String cs_type;
/**
- * Type used for parameters of internal call methods.
+ * Formatting elements:
+ * %0: input expression of type `in godot_variant`
+ * %1: [cs_type] of this type
+ * %2: [name] of this type
*/
- String im_type_in;
+ String cs_variant_to_managed;
/**
- * Type used for the return type of internal call methods.
+ * Formatting elements:
+ * %0: input expression
+ * %1: [cs_type] of this type
+ * %2: [name] of this type
*/
- String im_type_out;
+ String cs_managed_to_variant;
const DocData::ClassDoc *class_doc = nullptr;
@@ -366,6 +409,8 @@ class BindingsGenerator {
List<MethodInterface> methods;
List<SignalInterface> signals_;
+ bool has_virtual_methods = false;
+
const MethodInterface *find_method_by_name(const StringName &p_cname) const {
for (const MethodInterface &E : methods) {
if (E.cname == p_cname) {
@@ -432,8 +477,8 @@ class BindingsGenerator {
itype.c_type = itype.name;
itype.cs_type = itype.proxy_name;
- itype.im_type_in = "ref " + itype.proxy_name;
- itype.im_type_out = itype.proxy_name;
+ itype.c_type_in = itype.proxy_name + "*";
+ itype.c_type_out = itype.proxy_name;
itype.class_doc = &EditorHelp::get_doc_data()->class_list[itype.proxy_name];
}
@@ -467,65 +512,27 @@ class BindingsGenerator {
return itype;
}
- static void create_placeholder_type(TypeInterface &r_itype, const StringName &p_cname) {
- r_itype.name = p_cname;
- r_itype.cname = p_cname;
- r_itype.proxy_name = r_itype.name;
-
- r_itype.c_type = r_itype.name;
- r_itype.c_type_in = "MonoObject*";
- r_itype.c_type_out = "MonoObject*";
- r_itype.cs_type = r_itype.proxy_name;
- r_itype.im_type_in = r_itype.proxy_name;
- r_itype.im_type_out = r_itype.proxy_name;
- }
-
- static void postsetup_enum_type(TypeInterface &r_enum_itype) {
- // C interface for enums is the same as that of 'uint32_t'. Remember to apply
- // any of the changes done here to the 'uint32_t' type interface as well.
-
- r_enum_itype.c_arg_in = "&%s_in";
- {
- // The expected types for parameters and return value in ptrcall are 'int64_t' or 'uint64_t'.
- r_enum_itype.c_in = "\t%0 %1_in = (%0)%1;\n";
- r_enum_itype.c_out = "\treturn (%0)%1;\n";
- r_enum_itype.c_type = "int64_t";
- }
- r_enum_itype.c_type_in = "int32_t";
- r_enum_itype.c_type_out = r_enum_itype.c_type_in;
-
- r_enum_itype.cs_type = r_enum_itype.proxy_name;
- r_enum_itype.cs_in = "(int)%s";
- r_enum_itype.cs_out = "return (%2)%0(%1);";
- r_enum_itype.im_type_in = "int";
- r_enum_itype.im_type_out = "int";
- r_enum_itype.class_doc = &EditorHelp::get_doc_data()->class_list[r_enum_itype.proxy_name];
- }
+ static void postsetup_enum_type(TypeInterface &r_enum_itype);
TypeInterface() {}
};
struct InternalCall {
String name;
- String im_type_out; // Return type for the C# method declaration. Also used as companion of [unique_siq]
- String im_sig; // Signature for the C# method declaration
String unique_sig; // Unique signature to avoid duplicates in containers
bool editor_only = false;
- InternalCall() {}
+ bool is_vararg = false;
+ bool is_static = false;
+ TypeReference return_type;
+ List<TypeReference> argument_types;
- InternalCall(const String &p_name, const String &p_im_type_out, const String &p_im_sig = String(), const String &p_unique_sig = String()) {
- name = p_name;
- im_type_out = p_im_type_out;
- im_sig = p_im_sig;
- unique_sig = p_unique_sig;
- editor_only = false;
- }
+ _FORCE_INLINE_ int get_arguments_count() const { return argument_types.size(); }
+
+ InternalCall() {}
- InternalCall(ClassDB::APIType api_type, const String &p_name, const String &p_im_type_out, const String &p_im_sig = String(), const String &p_unique_sig = String()) {
+ InternalCall(ClassDB::APIType api_type, const String &p_name, const String &p_unique_sig = String()) {
name = p_name;
- im_type_out = p_im_type_out;
- im_sig = p_im_sig;
unique_sig = p_unique_sig;
editor_only = api_type == ClassDB::API_EDITOR;
}
@@ -540,7 +547,6 @@ class BindingsGenerator {
HashMap<StringName, TypeInterface> obj_types;
- HashMap<StringName, TypeInterface> placeholder_types;
HashMap<StringName, TypeInterface> builtin_types;
HashMap<StringName, TypeInterface> enum_types;
@@ -548,13 +554,9 @@ class BindingsGenerator {
List<ConstantInterface> global_constants;
List<InternalCall> method_icalls;
+ /// Stores the unique internal calls from [method_icalls] that are assigned to each method.
HashMap<const MethodInterface *, const InternalCall *> method_icalls_map;
- List<const InternalCall *> generated_icall_funcs;
-
- List<InternalCall> core_custom_icalls;
- List<InternalCall> editor_custom_icalls;
-
HashMap<StringName, List<StringName>> blacklisted_methods;
void _initialize_blacklisted_methods();
@@ -571,6 +573,8 @@ class BindingsGenerator {
StringName type_String = StaticCString::create("String");
StringName type_StringName = StaticCString::create("StringName");
StringName type_NodePath = StaticCString::create("NodePath");
+ StringName type_Array_generic = StaticCString::create("Array_@generic");
+ StringName type_Dictionary_generic = StaticCString::create("Dictionary_@generic");
StringName type_at_GlobalScope = StaticCString::create("@GlobalScope");
StringName enum_Error = StaticCString::create("Error");
@@ -595,12 +599,14 @@ class BindingsGenerator {
StringName type_Vector4i = StaticCString::create("Vector4i");
// Object not included as it must be checked for all derived classes
- static constexpr int nullable_types_count = 17;
+ static constexpr int nullable_types_count = 18;
StringName nullable_types[nullable_types_count] = {
type_String,
type_StringName,
type_NodePath,
+ type_Array_generic,
+ type_Dictionary_generic,
StaticCString::create(_STR(Array)),
StaticCString::create(_STR(Dictionary)),
StaticCString::create(_STR(Callable)),
@@ -636,17 +642,6 @@ class BindingsGenerator {
NameCache name_cache;
- const List<InternalCall>::Element *find_icall_by_name(const String &p_name, const List<InternalCall> &p_list) {
- const List<InternalCall>::Element *it = p_list.front();
- while (it) {
- if (it->get().name == p_name) {
- return it;
- }
- it = it->next();
- }
- return nullptr;
- }
-
const ConstantInterface *find_constant_by_name(const String &p_name, const List<ConstantInterface> &p_constants) const {
for (const ConstantInterface &E : p_constants) {
if (E.name == p_name) {
@@ -657,18 +652,38 @@ class BindingsGenerator {
return nullptr;
}
- inline String get_unique_sig(const TypeInterface &p_type) {
- if (p_type.is_ref_counted) {
- return "Ref";
- } else if (p_type.is_object_type) {
+ inline String get_arg_unique_sig(const TypeInterface &p_type) {
+ // For parameters, we treat reference and non-reference derived types the same.
+ if (p_type.is_object_type) {
return "Obj";
} else if (p_type.is_enum) {
return "int";
+ } else if (p_type.cname == name_cache.type_Array_generic) {
+ return "Array";
+ } else if (p_type.cname == name_cache.type_Dictionary_generic) {
+ return "Dictionary";
}
return p_type.name;
}
+ inline String get_ret_unique_sig(const TypeInterface *p_type) {
+ // Reference derived return types are treated differently.
+ if (p_type->is_ref_counted) {
+ return "Ref";
+ } else if (p_type->is_object_type) {
+ return "Obj";
+ } else if (p_type->is_enum) {
+ return "int";
+ } else if (p_type->cname == name_cache.type_Array_generic) {
+ return "Array";
+ } else if (p_type->cname == name_cache.type_Dictionary_generic) {
+ return "Dictionary";
+ }
+
+ return p_type->name;
+ }
+
String bbcode_to_xml(const String &p_bbcode, const TypeInterface *p_itype);
void _append_xml_method(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts);
@@ -682,10 +697,9 @@ class BindingsGenerator {
int _determine_enum_prefix(const EnumInterface &p_ienum);
void _apply_prefix_to_enum_constants(EnumInterface &p_ienum, int p_prefix_length);
- void _generate_method_icalls(const TypeInterface &p_itype);
+ Error _populate_method_icalls_table(const TypeInterface &p_itype);
const TypeInterface *_get_type_or_null(const TypeReference &p_typeref);
- const TypeInterface *_get_type_or_placeholder(const TypeReference &p_typeref);
const String _get_generic_type_parameters(const TypeInterface &p_itype, const List<TypeReference> &p_generic_type_parameters);
@@ -706,11 +720,11 @@ class BindingsGenerator {
Error _generate_cs_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, int &p_method_bind_count, StringBuilder &p_output);
Error _generate_cs_signal(const BindingsGenerator::TypeInterface &p_itype, const BindingsGenerator::SignalInterface &p_isignal, StringBuilder &p_output);
+ Error _generate_cs_native_calls(const InternalCall &p_icall, StringBuilder &r_output);
+
void _generate_array_extensions(StringBuilder &p_output);
void _generate_global_constants(StringBuilder &p_output);
- Error _generate_glue_method(const TypeInterface &p_itype, const MethodInterface &p_imethod, StringBuilder &p_output);
-
Error _save_file(const String &p_path, const StringBuilder &p_content);
void _log(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
@@ -721,15 +735,12 @@ public:
Error generate_cs_core_project(const String &p_proj_dir);
Error generate_cs_editor_project(const String &p_proj_dir);
Error generate_cs_api(const String &p_output_dir);
- Error generate_glue(const String &p_output_dir);
_FORCE_INLINE_ bool is_log_print_enabled() { return log_print_enabled; }
_FORCE_INLINE_ void set_log_print_enabled(bool p_enabled) { log_print_enabled = p_enabled; }
_FORCE_INLINE_ bool is_initialized() { return initialized; }
- static uint32_t get_version();
-
static void handle_cmdline_args(const List<String> &p_cmdline_args);
BindingsGenerator() {
diff --git a/modules/mono/editor/code_completion.cpp b/modules/mono/editor/code_completion.cpp
index a1789412f4..40296eef10 100644
--- a/modules/mono/editor/code_completion.cpp
+++ b/modules/mono/editor/code_completion.cpp
@@ -35,6 +35,7 @@
#include "editor/editor_settings.h"
#include "scene/gui/control.h"
#include "scene/main/node.h"
+#include "scene/theme/theme_db.h"
namespace gdmono {
@@ -162,9 +163,9 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
}
if (dir_access->dir_exists(filename)) {
- directories.push_back(dir_access->get_current_dir().plus_file(filename));
+ directories.push_back(dir_access->get_current_dir().path_join(filename));
} else if (filename.ends_with(".tscn") || filename.ends_with(".scn")) {
- suggestions.push_back(quoted(dir_access->get_current_dir().plus_file(filename)));
+ suggestions.push_back(quoted(dir_access->get_current_dir().path_join(filename)));
}
filename = dir_access->get_next();
@@ -172,7 +173,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
}
} break;
case CompletionKind::SHADER_PARAMS: {
- print_verbose("Shared params completion for C# not implemented.");
+ print_verbose("Shader uniforms completion for C# is not implemented yet.");
} break;
case CompletionKind::SIGNALS: {
Ref<Script> script = ResourceLoader::load(p_script_file.simplify_path());
@@ -195,7 +196,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
Node *base = _try_find_owner_node_in_tree(script);
if (base && Object::cast_to<Control>(base)) {
List<StringName> sn;
- Theme::get_default()->get_color_list(base->get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_color_list(base->get_class(), &sn);
for (const StringName &E : sn) {
suggestions.push_back(quoted(E));
@@ -207,7 +208,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
Node *base = _try_find_owner_node_in_tree(script);
if (base && Object::cast_to<Control>(base)) {
List<StringName> sn;
- Theme::get_default()->get_constant_list(base->get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_constant_list(base->get_class(), &sn);
for (const StringName &E : sn) {
suggestions.push_back(quoted(E));
@@ -219,7 +220,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
Node *base = _try_find_owner_node_in_tree(script);
if (base && Object::cast_to<Control>(base)) {
List<StringName> sn;
- Theme::get_default()->get_font_list(base->get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_font_list(base->get_class(), &sn);
for (const StringName &E : sn) {
suggestions.push_back(quoted(E));
@@ -231,7 +232,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
Node *base = _try_find_owner_node_in_tree(script);
if (base && Object::cast_to<Control>(base)) {
List<StringName> sn;
- Theme::get_default()->get_font_size_list(base->get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_font_size_list(base->get_class(), &sn);
for (const StringName &E : sn) {
suggestions.push_back(quoted(E));
@@ -243,7 +244,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
Node *base = _try_find_owner_node_in_tree(script);
if (base && Object::cast_to<Control>(base)) {
List<StringName> sn;
- Theme::get_default()->get_stylebox_list(base->get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_stylebox_list(base->get_class(), &sn);
for (const StringName &E : sn) {
suggestions.push_back(quoted(E));
diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp
index cfbb937aac..6f42ad6916 100644
--- a/modules/mono/editor/editor_internal_calls.cpp
+++ b/modules/mono/editor/editor_internal_calls.cpp
@@ -41,183 +41,86 @@
#include "editor/editor_node.h"
#include "editor/editor_paths.h"
#include "editor/editor_scale.h"
+#include "editor/editor_settings.h"
#include "editor/plugins/script_editor_plugin.h"
#include "main/main.h"
#include "../csharp_script.h"
-#include "../glue/cs_glue_version.gen.h"
#include "../godotsharp_dirs.h"
-#include "../mono_gd/gd_mono_marshal.h"
#include "../utils/macos_utils.h"
#include "code_completion.h"
-#include "godotsharp_export.h"
-MonoString *godot_icall_GodotSharpDirs_ResDataDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_data_dir());
-}
-
-MonoString *godot_icall_GodotSharpDirs_ResMetadataDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_metadata_dir());
-}
-
-MonoString *godot_icall_GodotSharpDirs_ResAssembliesBaseDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_assemblies_base_dir());
-}
-
-MonoString *godot_icall_GodotSharpDirs_ResAssembliesDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_assemblies_dir());
-}
-
-MonoString *godot_icall_GodotSharpDirs_ResConfigDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_config_dir());
-}
-
-MonoString *godot_icall_GodotSharpDirs_ResTempDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_temp_dir());
-}
-
-MonoString *godot_icall_GodotSharpDirs_ResTempAssembliesBaseDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_temp_assemblies_base_dir());
-}
-
-MonoString *godot_icall_GodotSharpDirs_ResTempAssembliesDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_res_temp_assemblies_dir());
-}
-
-MonoString *godot_icall_GodotSharpDirs_MonoUserDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_mono_user_dir());
-}
+#include "../interop_types.h"
-MonoString *godot_icall_GodotSharpDirs_MonoLogsDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_mono_logs_dir());
-}
-
-MonoString *godot_icall_GodotSharpDirs_MonoSolutionsDir() {
-#ifdef TOOLS_ENABLED
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_mono_solutions_dir());
-#else
- return nullptr;
+#ifdef __cplusplus
+extern "C" {
#endif
-}
-MonoString *godot_icall_GodotSharpDirs_BuildLogsDirs() {
-#ifdef TOOLS_ENABLED
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_build_logs_dir());
-#else
- return nullptr;
-#endif
+void godot_icall_GodotSharpDirs_ResMetadataDir(godot_string *r_dest) {
+ memnew_placement(r_dest, String(GodotSharpDirs::get_res_metadata_dir()));
}
-MonoString *godot_icall_GodotSharpDirs_ProjectSlnPath() {
-#ifdef TOOLS_ENABLED
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_project_sln_path());
-#else
- return nullptr;
-#endif
+void godot_icall_GodotSharpDirs_MonoUserDir(godot_string *r_dest) {
+ memnew_placement(r_dest, String(GodotSharpDirs::get_mono_user_dir()));
}
-MonoString *godot_icall_GodotSharpDirs_ProjectCsProjPath() {
+void godot_icall_GodotSharpDirs_BuildLogsDirs(godot_string *r_dest) {
#ifdef TOOLS_ENABLED
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_project_csproj_path());
+ memnew_placement(r_dest, String(GodotSharpDirs::get_build_logs_dir()));
#else
return nullptr;
#endif
}
-MonoString *godot_icall_GodotSharpDirs_DataEditorToolsDir() {
+void godot_icall_GodotSharpDirs_DataEditorToolsDir(godot_string *r_dest) {
#ifdef TOOLS_ENABLED
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_data_editor_tools_dir());
+ memnew_placement(r_dest, String(GodotSharpDirs::get_data_editor_tools_dir()));
#else
return nullptr;
#endif
}
-MonoString *godot_icall_GodotSharpDirs_DataEditorPrebuiltApiDir() {
-#ifdef TOOLS_ENABLED
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_data_editor_prebuilt_api_dir());
-#else
- return nullptr;
-#endif
-}
-
-MonoString *godot_icall_GodotSharpDirs_DataMonoEtcDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_data_mono_etc_dir());
-}
-
-MonoString *godot_icall_GodotSharpDirs_DataMonoLibDir() {
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_data_mono_lib_dir());
-}
-
-MonoString *godot_icall_GodotSharpDirs_DataMonoBinDir() {
-#ifdef WINDOWS_ENABLED
- return GDMonoMarshal::mono_string_from_godot(GodotSharpDirs::get_data_mono_bin_dir());
-#else
- return nullptr;
-#endif
-}
-
-void godot_icall_EditorProgress_Create(MonoString *p_task, MonoString *p_label, int32_t p_amount, MonoBoolean p_can_cancel) {
- String task = GDMonoMarshal::mono_string_to_godot(p_task);
- String label = GDMonoMarshal::mono_string_to_godot(p_label);
+void godot_icall_EditorProgress_Create(const godot_string *p_task, const godot_string *p_label, int32_t p_amount, bool p_can_cancel) {
+ String task = *reinterpret_cast<const String *>(p_task);
+ String label = *reinterpret_cast<const String *>(p_label);
EditorNode::progress_add_task(task, label, p_amount, (bool)p_can_cancel);
}
-void godot_icall_EditorProgress_Dispose(MonoString *p_task) {
- String task = GDMonoMarshal::mono_string_to_godot(p_task);
+void godot_icall_EditorProgress_Dispose(const godot_string *p_task) {
+ String task = *reinterpret_cast<const String *>(p_task);
EditorNode::progress_end_task(task);
}
-MonoBoolean godot_icall_EditorProgress_Step(MonoString *p_task, MonoString *p_state, int32_t p_step, MonoBoolean p_force_refresh) {
- String task = GDMonoMarshal::mono_string_to_godot(p_task);
- String state = GDMonoMarshal::mono_string_to_godot(p_state);
+bool godot_icall_EditorProgress_Step(const godot_string *p_task, const godot_string *p_state, int32_t p_step, bool p_force_refresh) {
+ String task = *reinterpret_cast<const String *>(p_task);
+ String state = *reinterpret_cast<const String *>(p_state);
return EditorNode::progress_task_step(task, state, p_step, (bool)p_force_refresh);
}
-uint32_t godot_icall_ExportPlugin_GetExportedAssemblyDependencies(MonoObject *p_initial_assemblies,
- MonoString *p_build_config, MonoString *p_custom_bcl_dir, MonoObject *r_assembly_dependencies) {
- Dictionary initial_dependencies = GDMonoMarshal::mono_object_to_variant(p_initial_assemblies);
- String build_config = GDMonoMarshal::mono_string_to_godot(p_build_config);
- String custom_bcl_dir = GDMonoMarshal::mono_string_to_godot(p_custom_bcl_dir);
- Dictionary assembly_dependencies = GDMonoMarshal::mono_object_to_variant(r_assembly_dependencies);
-
- return GodotSharpExport::get_exported_assembly_dependencies(initial_dependencies, build_config, custom_bcl_dir, assembly_dependencies);
-}
-
-MonoString *godot_icall_Internal_UpdateApiAssembliesFromPrebuilt(MonoString *p_config) {
- String config = GDMonoMarshal::mono_string_to_godot(p_config);
- String error_str = GDMono::get_singleton()->update_api_assemblies_from_prebuilt(config);
- return GDMonoMarshal::mono_string_from_godot(error_str);
+void godot_icall_Internal_FullExportTemplatesDir(godot_string *r_dest) {
+ String full_templates_dir = EditorPaths::get_singleton()->get_export_templates_dir().path_join(VERSION_FULL_CONFIG);
+ memnew_placement(r_dest, String(full_templates_dir));
}
-MonoString *godot_icall_Internal_FullExportTemplatesDir() {
- String full_templates_dir = EditorPaths::get_singleton()->get_export_templates_dir().plus_file(VERSION_FULL_CONFIG);
- return GDMonoMarshal::mono_string_from_godot(full_templates_dir);
-}
-
-MonoString *godot_icall_Internal_SimplifyGodotPath(MonoString *p_path) {
- String path = GDMonoMarshal::mono_string_to_godot(p_path);
- return GDMonoMarshal::mono_string_from_godot(path.simplify_path());
-}
-
-MonoBoolean godot_icall_Internal_IsMacOSAppBundleInstalled(MonoString *p_bundle_id) {
+bool godot_icall_Internal_IsMacOSAppBundleInstalled(const godot_string *p_bundle_id) {
#ifdef MACOS_ENABLED
- String bundle_id = GDMonoMarshal::mono_string_to_godot(p_bundle_id);
- return (MonoBoolean)macos_is_app_bundle_installed(bundle_id);
+ String bundle_id = *reinterpret_cast<const String *>(p_bundle_id);
+ return (bool)macos_is_app_bundle_installed(bundle_id);
#else
(void)p_bundle_id; // UNUSED
- return (MonoBoolean) false;
+ return (bool)false;
#endif
}
-MonoBoolean godot_icall_Internal_GodotIs32Bits() {
+bool godot_icall_Internal_GodotIs32Bits() {
return sizeof(void *) == 4;
}
-MonoBoolean godot_icall_Internal_GodotIsRealTDouble() {
+bool godot_icall_Internal_GodotIsRealTDouble() {
#ifdef REAL_T_IS_DOUBLE
- return (MonoBoolean) true;
+ return (bool)true;
#else
- return (MonoBoolean) false;
+ return (bool)false;
#endif
}
@@ -225,23 +128,15 @@ void godot_icall_Internal_GodotMainIteration() {
Main::iteration();
}
-uint64_t godot_icall_Internal_GetCoreApiHash() {
- return ClassDB::get_api_hash(ClassDB::API_CORE);
-}
-
-uint64_t godot_icall_Internal_GetEditorApiHash() {
- return ClassDB::get_api_hash(ClassDB::API_EDITOR);
-}
-
-MonoBoolean godot_icall_Internal_IsAssembliesReloadingNeeded() {
+bool godot_icall_Internal_IsAssembliesReloadingNeeded() {
#ifdef GD_MONO_HOT_RELOAD
- return (MonoBoolean)CSharpLanguage::get_singleton()->is_assembly_reloading_needed();
+ return (bool)CSharpLanguage::get_singleton()->is_assembly_reloading_needed();
#else
- return (MonoBoolean) false;
+ return (bool)false;
#endif
}
-void godot_icall_Internal_ReloadAssemblies(MonoBoolean p_soft_reload) {
+void godot_icall_Internal_ReloadAssemblies(bool p_soft_reload) {
#ifdef GD_MONO_HOT_RELOAD
mono_bind::GodotSharp::get_singleton()->call_deferred(SNAME("_reload_assemblies"), (bool)p_soft_reload);
#endif
@@ -251,24 +146,15 @@ void godot_icall_Internal_EditorDebuggerNodeReloadScripts() {
EditorDebuggerNode::get_singleton()->reload_scripts();
}
-MonoBoolean godot_icall_Internal_ScriptEditorEdit(MonoObject *p_resource, int32_t p_line, int32_t p_col, MonoBoolean p_grab_focus) {
- Ref<Resource> resource = GDMonoMarshal::mono_object_to_variant(p_resource);
- return (MonoBoolean)ScriptEditor::get_singleton()->edit(resource, p_line, p_col, (bool)p_grab_focus);
+bool godot_icall_Internal_ScriptEditorEdit(Resource *p_resource, int32_t p_line, int32_t p_col, bool p_grab_focus) {
+ Ref<Resource> resource = p_resource;
+ return (bool)ScriptEditor::get_singleton()->edit(resource, p_line, p_col, (bool)p_grab_focus);
}
void godot_icall_Internal_EditorNodeShowScriptScreen() {
EditorNode::get_singleton()->call("_editor_select", EditorNode::EDITOR_SCRIPT);
}
-MonoString *godot_icall_Internal_MonoWindowsInstallRoot() {
-#ifdef WINDOWS_ENABLED
- String install_root_dir = GDMono::get_singleton()->get_mono_reg_info().install_root_dir;
- return GDMonoMarshal::mono_string_from_godot(install_root_dir);
-#else
- return nullptr;
-#endif
-}
-
void godot_icall_Internal_EditorRunPlay() {
EditorNode::get_singleton()->run_play();
}
@@ -284,114 +170,93 @@ void godot_icall_Internal_ScriptEditorDebugger_ReloadScripts() {
}
}
-MonoArray *godot_icall_Internal_CodeCompletionRequest(int32_t p_kind, MonoString *p_script_file) {
- String script_file = GDMonoMarshal::mono_string_to_godot(p_script_file);
+void godot_icall_Internal_CodeCompletionRequest(int32_t p_kind, const godot_string *p_script_file, godot_packed_array *r_ret) {
+ String script_file = *reinterpret_cast<const String *>(p_script_file);
PackedStringArray suggestions = gdmono::get_code_completion((gdmono::CompletionKind)p_kind, script_file);
- return GDMonoMarshal::PackedStringArray_to_mono_array(suggestions);
+ memnew_placement(r_ret, PackedStringArray(suggestions));
}
float godot_icall_Globals_EditorScale() {
return EDSCALE;
}
-MonoObject *godot_icall_Globals_GlobalDef(MonoString *p_setting, MonoObject *p_default_value, MonoBoolean p_restart_if_changed) {
- String setting = GDMonoMarshal::mono_string_to_godot(p_setting);
- Variant default_value = GDMonoMarshal::mono_object_to_variant(p_default_value);
+void godot_icall_Globals_GlobalDef(const godot_string *p_setting, const godot_variant *p_default_value, bool p_restart_if_changed, godot_variant *r_result) {
+ String setting = *reinterpret_cast<const String *>(p_setting);
+ Variant default_value = *reinterpret_cast<const Variant *>(p_default_value);
Variant result = _GLOBAL_DEF(setting, default_value, (bool)p_restart_if_changed);
- return GDMonoMarshal::variant_to_mono_object(result);
+ memnew_placement(r_result, Variant(result));
}
-MonoObject *godot_icall_Globals_EditorDef(MonoString *p_setting, MonoObject *p_default_value, MonoBoolean p_restart_if_changed) {
- String setting = GDMonoMarshal::mono_string_to_godot(p_setting);
- Variant default_value = GDMonoMarshal::mono_object_to_variant(p_default_value);
+void godot_icall_Globals_EditorDef(const godot_string *p_setting, const godot_variant *p_default_value, bool p_restart_if_changed, godot_variant *r_result) {
+ String setting = *reinterpret_cast<const String *>(p_setting);
+ Variant default_value = *reinterpret_cast<const Variant *>(p_default_value);
Variant result = _EDITOR_DEF(setting, default_value, (bool)p_restart_if_changed);
- return GDMonoMarshal::variant_to_mono_object(result);
+ memnew_placement(r_result, Variant(result));
}
-MonoObject *godot_icall_Globals_EditorShortcut(MonoString *p_setting) {
- String setting = GDMonoMarshal::mono_string_to_godot(p_setting);
+void godot_icall_Globals_EditorShortcut(const godot_string *p_setting, godot_variant *r_result) {
+ String setting = *reinterpret_cast<const String *>(p_setting);
Ref<Shortcut> result = ED_GET_SHORTCUT(setting);
- return GDMonoMarshal::variant_to_mono_object(result);
+ memnew_placement(r_result, Variant(result));
}
-MonoString *godot_icall_Globals_TTR(MonoString *p_text) {
- String text = GDMonoMarshal::mono_string_to_godot(p_text);
- return GDMonoMarshal::mono_string_from_godot(TTR(text));
+void godot_icall_Globals_TTR(const godot_string *p_text, godot_string *r_dest) {
+ String text = *reinterpret_cast<const String *>(p_text);
+ memnew_placement(r_dest, String(TTR(text)));
}
-MonoString *godot_icall_Utils_OS_GetPlatformName() {
+void godot_icall_Utils_OS_GetPlatformName(godot_string *r_dest) {
String os_name = OS::get_singleton()->get_name();
- return GDMonoMarshal::mono_string_from_godot(os_name);
+ memnew_placement(r_dest, String(os_name));
}
-MonoBoolean godot_icall_Utils_OS_UnixFileHasExecutableAccess(MonoString *p_file_path) {
+bool godot_icall_Utils_OS_UnixFileHasExecutableAccess(const godot_string *p_file_path) {
#ifdef UNIX_ENABLED
- String file_path = GDMonoMarshal::mono_string_to_godot(p_file_path);
+ String file_path = *reinterpret_cast<const String *>(p_file_path);
return access(file_path.utf8().get_data(), X_OK) == 0;
#else
ERR_FAIL_V(false);
#endif
}
-void register_editor_internal_calls() {
- // GodotSharpDirs
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResDataDir", godot_icall_GodotSharpDirs_ResDataDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResMetadataDir", godot_icall_GodotSharpDirs_ResMetadataDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResAssembliesBaseDir", godot_icall_GodotSharpDirs_ResAssembliesBaseDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResAssembliesDir", godot_icall_GodotSharpDirs_ResAssembliesDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResConfigDir", godot_icall_GodotSharpDirs_ResConfigDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempDir", godot_icall_GodotSharpDirs_ResTempDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempAssembliesBaseDir", godot_icall_GodotSharpDirs_ResTempAssembliesBaseDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ResTempAssembliesDir", godot_icall_GodotSharpDirs_ResTempAssembliesDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoUserDir", godot_icall_GodotSharpDirs_MonoUserDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoLogsDir", godot_icall_GodotSharpDirs_MonoLogsDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_MonoSolutionsDir", godot_icall_GodotSharpDirs_MonoSolutionsDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_BuildLogsDirs", godot_icall_GodotSharpDirs_BuildLogsDirs);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectSlnPath", godot_icall_GodotSharpDirs_ProjectSlnPath);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_ProjectCsProjPath", godot_icall_GodotSharpDirs_ProjectCsProjPath);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataEditorToolsDir", godot_icall_GodotSharpDirs_DataEditorToolsDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataEditorPrebuiltApiDir", godot_icall_GodotSharpDirs_DataEditorPrebuiltApiDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoEtcDir", godot_icall_GodotSharpDirs_DataMonoEtcDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoLibDir", godot_icall_GodotSharpDirs_DataMonoLibDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.GodotSharpDirs::internal_DataMonoBinDir", godot_icall_GodotSharpDirs_DataMonoBinDir);
-
- // EditorProgress
- GDMonoUtils::add_internal_call("GodotTools.Internals.EditorProgress::internal_Create", godot_icall_EditorProgress_Create);
- GDMonoUtils::add_internal_call("GodotTools.Internals.EditorProgress::internal_Dispose", godot_icall_EditorProgress_Dispose);
- GDMonoUtils::add_internal_call("GodotTools.Internals.EditorProgress::internal_Step", godot_icall_EditorProgress_Step);
-
- // ExportPlugin
- GDMonoUtils::add_internal_call("GodotTools.Export.ExportPlugin::internal_GetExportedAssemblyDependencies", godot_icall_ExportPlugin_GetExportedAssemblyDependencies);
-
- // Internals
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_UpdateApiAssembliesFromPrebuilt", godot_icall_Internal_UpdateApiAssembliesFromPrebuilt);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_FullExportTemplatesDir", godot_icall_Internal_FullExportTemplatesDir);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_SimplifyGodotPath", godot_icall_Internal_SimplifyGodotPath);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_IsMacOSAppBundleInstalled", godot_icall_Internal_IsMacOSAppBundleInstalled);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GodotIs32Bits", godot_icall_Internal_GodotIs32Bits);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GodotIsRealTDouble", godot_icall_Internal_GodotIsRealTDouble);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GodotMainIteration", godot_icall_Internal_GodotMainIteration);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GetCoreApiHash", godot_icall_Internal_GetCoreApiHash);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_GetEditorApiHash", godot_icall_Internal_GetEditorApiHash);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_IsAssembliesReloadingNeeded", godot_icall_Internal_IsAssembliesReloadingNeeded);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_ReloadAssemblies", godot_icall_Internal_ReloadAssemblies);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorDebuggerNodeReloadScripts", godot_icall_Internal_EditorDebuggerNodeReloadScripts);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_ScriptEditorEdit", godot_icall_Internal_ScriptEditorEdit);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorNodeShowScriptScreen", godot_icall_Internal_EditorNodeShowScriptScreen);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_MonoWindowsInstallRoot", godot_icall_Internal_MonoWindowsInstallRoot);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorRunPlay", godot_icall_Internal_EditorRunPlay);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_EditorRunStop", godot_icall_Internal_EditorRunStop);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_ScriptEditorDebugger_ReloadScripts", godot_icall_Internal_ScriptEditorDebugger_ReloadScripts);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Internal::internal_CodeCompletionRequest", godot_icall_Internal_CodeCompletionRequest);
-
- // Globals
- GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_EditorScale", godot_icall_Globals_EditorScale);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_GlobalDef", godot_icall_Globals_GlobalDef);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_EditorDef", godot_icall_Globals_EditorDef);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_EditorShortcut", godot_icall_Globals_EditorShortcut);
- GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_TTR", godot_icall_Globals_TTR);
-
- // Utils.OS
- GDMonoUtils::add_internal_call("GodotTools.Utils.OS::GetPlatformName", godot_icall_Utils_OS_GetPlatformName);
- GDMonoUtils::add_internal_call("GodotTools.Utils.OS::UnixFileHasExecutableAccess", godot_icall_Utils_OS_UnixFileHasExecutableAccess);
+#ifdef __cplusplus
+}
+#endif
+
+// The order in this array must match the declaration order of
+// the methods in 'GodotTools/Internals/Internal.cs'.
+static const void *unmanaged_callbacks[]{
+ (void *)godot_icall_GodotSharpDirs_ResMetadataDir,
+ (void *)godot_icall_GodotSharpDirs_MonoUserDir,
+ (void *)godot_icall_GodotSharpDirs_BuildLogsDirs,
+ (void *)godot_icall_GodotSharpDirs_DataEditorToolsDir,
+ (void *)godot_icall_EditorProgress_Create,
+ (void *)godot_icall_EditorProgress_Dispose,
+ (void *)godot_icall_EditorProgress_Step,
+ (void *)godot_icall_Internal_FullExportTemplatesDir,
+ (void *)godot_icall_Internal_IsMacOSAppBundleInstalled,
+ (void *)godot_icall_Internal_GodotIs32Bits,
+ (void *)godot_icall_Internal_GodotIsRealTDouble,
+ (void *)godot_icall_Internal_GodotMainIteration,
+ (void *)godot_icall_Internal_IsAssembliesReloadingNeeded,
+ (void *)godot_icall_Internal_ReloadAssemblies,
+ (void *)godot_icall_Internal_EditorDebuggerNodeReloadScripts,
+ (void *)godot_icall_Internal_ScriptEditorEdit,
+ (void *)godot_icall_Internal_EditorNodeShowScriptScreen,
+ (void *)godot_icall_Internal_EditorRunPlay,
+ (void *)godot_icall_Internal_EditorRunStop,
+ (void *)godot_icall_Internal_ScriptEditorDebugger_ReloadScripts,
+ (void *)godot_icall_Internal_CodeCompletionRequest,
+ (void *)godot_icall_Globals_EditorScale,
+ (void *)godot_icall_Globals_GlobalDef,
+ (void *)godot_icall_Globals_EditorDef,
+ (void *)godot_icall_Globals_EditorShortcut,
+ (void *)godot_icall_Globals_TTR,
+ (void *)godot_icall_Utils_OS_GetPlatformName,
+ (void *)godot_icall_Utils_OS_UnixFileHasExecutableAccess,
+};
+
+const void **godotsharp::get_editor_interop_funcs(int32_t &r_size) {
+ r_size = sizeof(unmanaged_callbacks);
+ return unmanaged_callbacks;
}
diff --git a/modules/mono/editor/editor_internal_calls.h b/modules/mono/editor/editor_internal_calls.h
index 8262ac211a..35391f1f04 100644
--- a/modules/mono/editor/editor_internal_calls.h
+++ b/modules/mono/editor/editor_internal_calls.h
@@ -31,6 +31,10 @@
#ifndef EDITOR_INTERNAL_CALLS_H
#define EDITOR_INTERNAL_CALLS_H
-void register_editor_internal_calls();
+#include "core/typedefs.h"
+
+namespace godotsharp {
+const void **get_editor_interop_funcs(int32_t &r_size);
+}
#endif // EDITOR_INTERNAL_CALLS_H
diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp
deleted file mode 100644
index f9ea403334..0000000000
--- a/modules/mono/editor/godotsharp_export.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/*************************************************************************/
-/* godotsharp_export.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "godotsharp_export.h"
-
-#include <mono/metadata/image.h>
-
-#include "core/config/project_settings.h"
-#include "core/io/file_access_pack.h"
-#include "core/os/os.h"
-
-#include "../mono_gd/gd_mono.h"
-#include "../mono_gd/gd_mono_assembly.h"
-#include "../mono_gd/gd_mono_cache.h"
-#include "../utils/macros.h"
-
-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 = 0;
- uint16_t minor = 0;
- uint16_t build = 0;
- uint16_t revision = 0;
-};
-
-AssemblyRefInfo get_assemblyref_name(MonoImage *p_image, int index) {
- const MonoTableInfo *table_info = mono_image_get_table_info(p_image, MONO_TABLE_ASSEMBLYREF);
-
- uint32_t cols[MONO_ASSEMBLYREF_SIZE];
-
- mono_metadata_decode_row(table_info, index, cols, MONO_ASSEMBLYREF_SIZE);
-
- return {
- String::utf8(mono_metadata_string_heap(p_image, cols[MONO_ASSEMBLYREF_NAME])),
- (uint16_t)cols[MONO_ASSEMBLYREF_MAJOR_VERSION],
- (uint16_t)cols[MONO_ASSEMBLYREF_MINOR_VERSION],
- (uint16_t)cols[MONO_ASSEMBLYREF_BUILD_NUMBER],
- (uint16_t)cols[MONO_ASSEMBLYREF_REV_NUMBER]
- };
-}
-
-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++) {
- AssemblyRefInfo ref_info = get_assemblyref_name(image, i);
-
- const String &ref_name = ref_info.name;
-
- if (r_assembly_dependencies.has(ref_name)) {
- continue;
- }
-
- mono_assembly_get_assemblyref(image, i, reusable_aname);
-
- GDMonoAssembly *ref_assembly = nullptr;
- 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 + "'.");
- }
-
- 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 + "'.");
- }
-
- return OK;
-}
-
-Error get_exported_assembly_dependencies(const Dictionary &p_initial_assemblies,
- const String &p_build_config, const String &p_custom_bcl_dir, Dictionary &r_assembly_dependencies) {
- MonoDomain *export_domain = GDMonoUtils::create_domain("GodotEngine.Domain.ProjectExport");
- ERR_FAIL_NULL_V(export_domain, FAILED);
- _GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(export_domain);
-
- _GDMONO_SCOPE_DOMAIN_(export_domain);
-
- Vector<String> search_dirs;
- GDMonoAssembly::fill_search_dirs(search_dirs, p_build_config, p_custom_bcl_dir);
-
- if (p_custom_bcl_dir.length()) {
- // Only one mscorlib can be loaded. We need this workaround to make sure we get it from the right BCL directory.
- r_assembly_dependencies["mscorlib"] = p_custom_bcl_dir.plus_file("mscorlib.dll").simplify_path();
- }
-
- for (const Variant *key = p_initial_assemblies.next(); key; key = p_initial_assemblies.next(key)) {
- String assembly_name = *key;
- String assembly_path = p_initial_assemblies[*key];
-
- GDMonoAssembly *assembly = nullptr;
- bool load_success = GDMono::get_singleton()->load_assembly_from(assembly_name, assembly_path, &assembly, /* refonly: */ true);
-
- ERR_FAIL_COND_V_MSG(!load_success, ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + assembly_name + "'.");
-
- 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;
- }
- }
-
- return OK;
-}
-} // namespace GodotSharpExport
diff --git a/modules/mono/editor/godotsharp_export.h b/modules/mono/editor/godotsharp_export.h
deleted file mode 100644
index 60620b5f4d..0000000000
--- a/modules/mono/editor/godotsharp_export.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*************************************************************************/
-/* godotsharp_export.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GODOTSHARP_EXPORT_H
-#define GODOTSHARP_EXPORT_H
-
-#include "core/error/error_list.h"
-#include "core/string/ustring.h"
-#include "core/variant/dictionary.h"
-
-#include "../mono_gd/gd_mono_header.h"
-
-namespace GodotSharpExport {
-
-Error get_assembly_dependencies(GDMonoAssembly *p_assembly, const Vector<String> &p_search_dirs, Dictionary &r_dependencies);
-
-Error get_exported_assembly_dependencies(const Dictionary &p_initial_assemblies,
- const String &p_build_config, const String &p_custom_lib_dir, Dictionary &r_assembly_dependencies);
-} // namespace GodotSharpExport
-
-#endif // GODOTSHARP_EXPORT_H
diff --git a/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs b/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs
index 2ca81ab7cd..1f5ea7532d 100644
--- a/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs
+++ b/modules/mono/editor/script_templates/CharacterBody2D/basic_movement.cs
@@ -8,8 +8,8 @@ public partial class _CLASS_ : _BASE_
public const float Speed = 300.0f;
public const float JumpVelocity = -400.0f;
- // Get the gravity from the project settings to be synced with RigidDynamicBody nodes.
- public float gravity = (float)ProjectSettings.GetSetting("physics/2d/default_gravity");
+ // Get the gravity from the project settings to be synced with RigidBody nodes.
+ public float gravity = ProjectSettings.GetSetting("physics/2d/default_gravity").AsSingle();
public override void _PhysicsProcess(float delta)
{
diff --git a/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs b/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs
index a6935fe497..4e978b7549 100644
--- a/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs
+++ b/modules/mono/editor/script_templates/CharacterBody3D/basic_movement.cs
@@ -8,8 +8,8 @@ public partial class _CLASS_ : _BASE_
public const float Speed = 5.0f;
public const float JumpVelocity = 4.5f;
- // Get the gravity from the project settings to be synced with RigidDynamicBody nodes.
- public float gravity = (float)ProjectSettings.GetSetting("physics/3d/default_gravity");
+ // Get the gravity from the project settings to be synced with RigidBody nodes.
+ public float gravity = ProjectSettings.GetSetting("physics/3d/default_gravity").AsSingle();
public override void _PhysicsProcess(float delta)
{
@@ -26,7 +26,7 @@ public partial class _CLASS_ : _BASE_
// Get the input direction and handle the movement/deceleration.
// As good practice, you should replace UI actions with custom gameplay actions.
Vector2 inputDir = Input.GetVector("ui_left", "ui_right", "ui_up", "ui_down");
- Vector3 direction = Transform.basis.Xform(new Vector3(inputDir.x, 0, inputDir.y)).Normalized();
+ Vector3 direction = (Transform.basis * new Vector3(inputDir.x, 0, inputDir.y)).Normalized();
if (direction != Vector3.Zero)
{
velocity.x = direction.x * Speed;
diff --git a/modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs b/modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs
index a1b93e7daa..bb482e0d6a 100644
--- a/modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs
+++ b/modules/mono/editor/script_templates/VisualShaderNodeCustom/basic.cs
@@ -55,7 +55,7 @@ public partial class VisualShaderNode_CLASS_ : _BASE_
return 0;
}
- public override string _GetCode(Godot.Collections.Array inputVars, Godot.Collections.Array outputVars, Shader.Mode mode, VisualShader.Type type)
+ public override string _GetCode(Godot.Collections.Array<string> inputVars, Godot.Collections.Array<string> outputVars, Shader.Mode mode, VisualShader.Type type)
{
return "";
}
diff --git a/modules/mono/glue/GodotSharp/.editorconfig b/modules/mono/glue/GodotSharp/.editorconfig
new file mode 100644
index 0000000000..d4e71b1bd9
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/.editorconfig
@@ -0,0 +1,8 @@
+[**/Generated/**.cs]
+# Validate parameter is non-null before using it
+# Useful for generated code, as it disables nullable
+dotnet_diagnostic.CA1062.severity = error
+# CA1069: Enums should not have duplicate values
+dotnet_diagnostic.CA1069.severity = none
+# CA1708: Identifiers should differ by more than case
+dotnet_diagnostic.CA1708.severity = none
diff --git a/modules/mono/glue/GodotSharp/ExternalAnnotations/System.Runtime.InteropServices.xml b/modules/mono/glue/GodotSharp/ExternalAnnotations/System.Runtime.InteropServices.xml
new file mode 100644
index 0000000000..2dc350d4f2
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/ExternalAnnotations/System.Runtime.InteropServices.xml
@@ -0,0 +1,5 @@
+<assembly name="System.Runtime.InteropServices">
+ <member name="T:System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute">
+ <attribute ctor="M:JetBrains.Annotations.MeansImplicitUseAttribute.#ctor" />
+ </member>
+</assembly>
diff --git a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/CallbacksInfo.cs b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/CallbacksInfo.cs
new file mode 100644
index 0000000000..686023a077
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/CallbacksInfo.cs
@@ -0,0 +1,24 @@
+using System.Collections.Immutable;
+using System.Linq;
+using Microsoft.CodeAnalysis;
+
+namespace Godot.SourceGenerators.Internal;
+
+internal struct CallbacksData
+{
+ public CallbacksData(INamedTypeSymbol nativeTypeSymbol, INamedTypeSymbol funcStructSymbol)
+ {
+ NativeTypeSymbol = nativeTypeSymbol;
+ FuncStructSymbol = funcStructSymbol;
+ Methods = NativeTypeSymbol.GetMembers()
+ .Where(symbol => symbol is IMethodSymbol { IsPartialDefinition: true })
+ .Cast<IMethodSymbol>()
+ .ToImmutableArray();
+ }
+
+ public INamedTypeSymbol NativeTypeSymbol { get; }
+
+ public INamedTypeSymbol FuncStructSymbol { get; }
+
+ public ImmutableArray<IMethodSymbol> Methods { get; }
+}
diff --git a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Common.cs b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Common.cs
new file mode 100644
index 0000000000..16e96c725a
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Common.cs
@@ -0,0 +1,65 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace Godot.SourceGenerators.Internal;
+
+internal static class Common
+{
+ public static void ReportNonPartialUnmanagedCallbacksClass(
+ GeneratorExecutionContext context,
+ ClassDeclarationSyntax cds, INamedTypeSymbol symbol
+ )
+ {
+ string message =
+ "Missing partial modifier on declaration of type '" +
+ $"{symbol.FullQualifiedName()}' which has attribute '{GeneratorClasses.GenerateUnmanagedCallbacksAttr}'";
+
+ string description = $"{message}. Classes with attribute '{GeneratorClasses.GenerateUnmanagedCallbacksAttr}' " +
+ "must be declared with the partial modifier.";
+
+ context.ReportDiagnostic(Diagnostic.Create(
+ new DiagnosticDescriptor(id: "GODOT-INTERNAL-G0001",
+ title: message,
+ messageFormat: message,
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description),
+ cds.GetLocation(),
+ cds.SyntaxTree.FilePath));
+ }
+
+ public static void ReportNonPartialUnmanagedCallbacksOuterClass(
+ GeneratorExecutionContext context,
+ TypeDeclarationSyntax outerTypeDeclSyntax
+ )
+ {
+ var outerSymbol = context.Compilation
+ .GetSemanticModel(outerTypeDeclSyntax.SyntaxTree)
+ .GetDeclaredSymbol(outerTypeDeclSyntax);
+
+ string fullQualifiedName = outerSymbol is INamedTypeSymbol namedTypeSymbol ?
+ namedTypeSymbol.FullQualifiedName() :
+ "type not found";
+
+ string message =
+ $"Missing partial modifier on declaration of type '{fullQualifiedName}', " +
+ $"which contains one or more subclasses with attribute " +
+ $"'{GeneratorClasses.GenerateUnmanagedCallbacksAttr}'";
+
+ string description = $"{message}. Classes with attribute " +
+ $"'{GeneratorClasses.GenerateUnmanagedCallbacksAttr}' and their " +
+ "containing types must be declared with the partial modifier.";
+
+ context.ReportDiagnostic(Diagnostic.Create(
+ new DiagnosticDescriptor(id: "GODOT-INTERNAL-G0002",
+ title: message,
+ messageFormat: message,
+ category: "Usage",
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description),
+ outerTypeDeclSyntax.GetLocation(),
+ outerTypeDeclSyntax.SyntaxTree.FilePath));
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/ExtensionMethods.cs b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/ExtensionMethods.cs
new file mode 100644
index 0000000000..fac362479a
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/ExtensionMethods.cs
@@ -0,0 +1,119 @@
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace Godot.SourceGenerators.Internal;
+
+internal static class ExtensionMethods
+{
+ public static AttributeData? GetGenerateUnmanagedCallbacksAttribute(this INamedTypeSymbol symbol)
+ => symbol.GetAttributes()
+ .FirstOrDefault(a => a.AttributeClass?.IsGenerateUnmanagedCallbacksAttribute() ?? false);
+
+ private static bool HasGenerateUnmanagedCallbacksAttribute(
+ this ClassDeclarationSyntax cds, Compilation compilation,
+ out INamedTypeSymbol? symbol
+ )
+ {
+ var sm = compilation.GetSemanticModel(cds.SyntaxTree);
+
+ var classTypeSymbol = sm.GetDeclaredSymbol(cds);
+ if (classTypeSymbol == null)
+ {
+ symbol = null;
+ return false;
+ }
+
+ if (!classTypeSymbol.GetAttributes()
+ .Any(a => a.AttributeClass?.IsGenerateUnmanagedCallbacksAttribute() ?? false))
+ {
+ symbol = null;
+ return false;
+ }
+
+ symbol = classTypeSymbol;
+ return true;
+ }
+
+ private static bool IsGenerateUnmanagedCallbacksAttribute(this INamedTypeSymbol symbol)
+ => symbol.ToString() == GeneratorClasses.GenerateUnmanagedCallbacksAttr;
+
+ public static IEnumerable<(ClassDeclarationSyntax cds, INamedTypeSymbol symbol)> SelectUnmanagedCallbacksClasses(
+ this IEnumerable<ClassDeclarationSyntax> source,
+ Compilation compilation
+ )
+ {
+ foreach (var cds in source)
+ {
+ if (cds.HasGenerateUnmanagedCallbacksAttribute(compilation, out var symbol))
+ yield return (cds, symbol!);
+ }
+ }
+
+ public static bool IsNested(this TypeDeclarationSyntax cds)
+ => cds.Parent is TypeDeclarationSyntax;
+
+ public static bool IsPartial(this TypeDeclarationSyntax cds)
+ => cds.Modifiers.Any(SyntaxKind.PartialKeyword);
+
+ public static bool AreAllOuterTypesPartial(
+ this TypeDeclarationSyntax cds,
+ out TypeDeclarationSyntax? typeMissingPartial
+ )
+ {
+ SyntaxNode? outerSyntaxNode = cds.Parent;
+
+ while (outerSyntaxNode is TypeDeclarationSyntax outerTypeDeclSyntax)
+ {
+ if (!outerTypeDeclSyntax.IsPartial())
+ {
+ typeMissingPartial = outerTypeDeclSyntax;
+ return false;
+ }
+
+ outerSyntaxNode = outerSyntaxNode.Parent;
+ }
+
+ typeMissingPartial = null;
+ return true;
+ }
+
+ public static string GetDeclarationKeyword(this INamedTypeSymbol namedTypeSymbol)
+ {
+ string? keyword = namedTypeSymbol.DeclaringSyntaxReferences
+ .OfType<TypeDeclarationSyntax>().FirstOrDefault()?
+ .Keyword.Text;
+
+ return keyword ?? namedTypeSymbol.TypeKind switch
+ {
+ TypeKind.Interface => "interface",
+ TypeKind.Struct => "struct",
+ _ => "class"
+ };
+ }
+
+ private static SymbolDisplayFormat FullyQualifiedFormatOmitGlobal { get; } =
+ SymbolDisplayFormat.FullyQualifiedFormat
+ .WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted);
+
+ public static string FullQualifiedName(this ITypeSymbol symbol)
+ => symbol.ToDisplayString(NullableFlowState.NotNull, FullyQualifiedFormatOmitGlobal);
+
+ public static string NameWithTypeParameters(this INamedTypeSymbol symbol)
+ {
+ return symbol.IsGenericType ?
+ string.Concat(symbol.Name, "<", string.Join(", ", symbol.TypeParameters), ">") :
+ symbol.Name;
+ }
+
+ public static string FullQualifiedName(this INamespaceSymbol symbol)
+ => symbol.ToDisplayString(FullyQualifiedFormatOmitGlobal);
+
+ public static string SanitizeQualifiedNameForUniqueHint(this string qualifiedName)
+ => qualifiedName
+ // AddSource() doesn't support angle brackets
+ .Replace("<", "(Of ")
+ .Replace(">", ")");
+}
diff --git a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/GeneratorClasses.cs b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/GeneratorClasses.cs
new file mode 100644
index 0000000000..1bbb33f5a1
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/GeneratorClasses.cs
@@ -0,0 +1,6 @@
+namespace Godot.SourceGenerators.Internal;
+
+internal static class GeneratorClasses
+{
+ public const string GenerateUnmanagedCallbacksAttr = "Godot.SourceGenerators.Internal.GenerateUnmanagedCallbacksAttribute";
+}
diff --git a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Godot.SourceGenerators.Internal.csproj b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Godot.SourceGenerators.Internal.csproj
new file mode 100644
index 0000000000..4d1a5bb76c
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/Godot.SourceGenerators.Internal.csproj
@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <TargetFramework>netstandard2.0</TargetFramework>
+ <LangVersion>10</LangVersion>
+ <Nullable>enable</Nullable>
+ </PropertyGroup>
+ <ItemGroup>
+ <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.10.0" PrivateAssets="all" />
+ <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" PrivateAssets="all" />
+ </ItemGroup>
+</Project>
diff --git a/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/UnmanagedCallbacksGenerator.cs b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/UnmanagedCallbacksGenerator.cs
new file mode 100644
index 0000000000..da578309bc
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/Godot.SourceGenerators.Internal/UnmanagedCallbacksGenerator.cs
@@ -0,0 +1,463 @@
+using System.Text;
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Text;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace Godot.SourceGenerators.Internal;
+
+[Generator]
+public class UnmanagedCallbacksGenerator : ISourceGenerator
+{
+ public void Initialize(GeneratorInitializationContext context)
+ {
+ context.RegisterForPostInitialization(ctx => { GenerateAttribute(ctx); });
+ }
+
+ public void Execute(GeneratorExecutionContext context)
+ {
+ INamedTypeSymbol[] unmanagedCallbacksClasses = context
+ .Compilation.SyntaxTrees
+ .SelectMany(tree =>
+ tree.GetRoot().DescendantNodes()
+ .OfType<ClassDeclarationSyntax>()
+ .SelectUnmanagedCallbacksClasses(context.Compilation)
+ // Report and skip non-partial classes
+ .Where(x =>
+ {
+ if (x.cds.IsPartial())
+ {
+ if (x.cds.IsNested() && !x.cds.AreAllOuterTypesPartial(out var typeMissingPartial))
+ {
+ Common.ReportNonPartialUnmanagedCallbacksOuterClass(context, typeMissingPartial!);
+ return false;
+ }
+
+ return true;
+ }
+
+ Common.ReportNonPartialUnmanagedCallbacksClass(context, x.cds, x.symbol);
+ return false;
+ })
+ .Select(x => x.symbol)
+ )
+ .Distinct<INamedTypeSymbol>(SymbolEqualityComparer.Default)
+ .ToArray();
+
+ foreach (var symbol in unmanagedCallbacksClasses)
+ {
+ var attr = symbol.GetGenerateUnmanagedCallbacksAttribute();
+ if (attr == null || attr.ConstructorArguments.Length != 1)
+ {
+ // TODO: Report error or throw exception, this is an invalid case and should never be reached
+ System.Diagnostics.Debug.Fail("FAILED!");
+ continue;
+ }
+
+ var funcStructType = (INamedTypeSymbol?)attr.ConstructorArguments[0].Value;
+ if (funcStructType == null)
+ {
+ // TODO: Report error or throw exception, this is an invalid case and should never be reached
+ System.Diagnostics.Debug.Fail("FAILED!");
+ continue;
+ }
+
+ var data = new CallbacksData(symbol, funcStructType);
+ GenerateInteropMethodImplementations(context, data);
+ GenerateUnmanagedCallbacksStruct(context, data);
+ }
+ }
+
+ private void GenerateAttribute(GeneratorPostInitializationContext context)
+ {
+ string source = @"using System;
+
+namespace Godot.SourceGenerators.Internal
+{
+internal class GenerateUnmanagedCallbacksAttribute : Attribute
+{
+ public Type FuncStructType { get; }
+
+ public GenerateUnmanagedCallbacksAttribute(Type funcStructType)
+ {
+ FuncStructType = funcStructType;
+ }
+}
+}";
+
+ context.AddSource("GenerateUnmanagedCallbacksAttribute.generated",
+ SourceText.From(source, Encoding.UTF8));
+ }
+
+ private void GenerateInteropMethodImplementations(GeneratorExecutionContext context, CallbacksData data)
+ {
+ var symbol = data.NativeTypeSymbol;
+
+ INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace;
+ string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ?
+ namespaceSymbol.FullQualifiedName() :
+ string.Empty;
+ bool hasNamespace = classNs.Length != 0;
+ bool isInnerClass = symbol.ContainingType != null;
+
+ var source = new StringBuilder();
+ var methodSource = new StringBuilder();
+ var methodCallArguments = new StringBuilder();
+ var methodSourceAfterCall = new StringBuilder();
+
+ source.Append(
+ @"using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Godot.Bridge;
+using Godot.NativeInterop;
+
+#pragma warning disable CA1707 // Disable warning: Identifiers should not contain underscores
+
+");
+
+ if (hasNamespace)
+ {
+ source.Append("namespace ");
+ source.Append(classNs);
+ source.Append("\n{\n");
+ }
+
+ if (isInnerClass)
+ {
+ var containingType = symbol.ContainingType;
+
+ while (containingType != null)
+ {
+ source.Append("partial ");
+ source.Append(containingType.GetDeclarationKeyword());
+ source.Append(" ");
+ source.Append(containingType.NameWithTypeParameters());
+ source.Append("\n{\n");
+
+ containingType = containingType.ContainingType;
+ }
+ }
+
+ source.Append("[System.Runtime.CompilerServices.SkipLocalsInit]\n");
+ source.Append($"unsafe partial class {symbol.Name}\n");
+ source.Append("{\n");
+ source.Append($" private static {data.FuncStructSymbol.FullQualifiedName()} _unmanagedCallbacks;\n\n");
+
+ foreach (var callback in data.Methods)
+ {
+ methodSource.Clear();
+ methodCallArguments.Clear();
+ methodSourceAfterCall.Clear();
+
+ source.Append(" [global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]\n");
+ source.Append($" {SyntaxFacts.GetText(callback.DeclaredAccessibility)} ");
+
+ if (callback.IsStatic)
+ source.Append("static ");
+
+ source.Append("partial ");
+ source.Append(callback.ReturnType.FullQualifiedName());
+ source.Append(' ');
+ source.Append(callback.Name);
+ source.Append('(');
+
+ for (int i = 0; i < callback.Parameters.Length; i++)
+ {
+ var parameter = callback.Parameters[i];
+
+ source.Append(parameter.ToDisplayString());
+ source.Append(' ');
+ source.Append(parameter.Name);
+
+ if (parameter.RefKind == RefKind.Out)
+ {
+ // Only assign default if the parameter won't be passed by-ref or copied later.
+ if (IsGodotInteropStruct(parameter.Type))
+ methodSource.Append($" {parameter.Name} = default;\n");
+ }
+
+ if (IsByRefParameter(parameter))
+ {
+ if (IsGodotInteropStruct(parameter.Type))
+ {
+ methodSource.Append(" ");
+ AppendCustomUnsafeAsPointer(methodSource, parameter, out string varName);
+ methodCallArguments.Append(varName);
+ }
+ else if (parameter.Type.IsValueType)
+ {
+ methodSource.Append(" ");
+ AppendCopyToStackAndGetPointer(methodSource, parameter, out string varName);
+ methodCallArguments.Append($"&{varName}");
+
+ if (parameter.RefKind is RefKind.Out or RefKind.Ref)
+ {
+ methodSourceAfterCall.Append($" {parameter.Name} = {varName};\n");
+ }
+ }
+ else
+ {
+ // If it's a by-ref param and we can't get the pointer
+ // just pass it by-ref and let it be pinned.
+ AppendRefKind(methodCallArguments, parameter.RefKind)
+ .Append(' ')
+ .Append(parameter.Name);
+ }
+ }
+ else
+ {
+ methodCallArguments.Append(parameter.Name);
+ }
+
+ if (i < callback.Parameters.Length - 1)
+ {
+ source.Append(", ");
+ methodCallArguments.Append(", ");
+ }
+ }
+
+ source.Append(")\n");
+ source.Append(" {\n");
+
+ source.Append(methodSource);
+ source.Append(" ");
+
+ if (!callback.ReturnsVoid)
+ {
+ if (methodSourceAfterCall.Length != 0)
+ source.Append($"{callback.ReturnType.FullQualifiedName()} ret = ");
+ else
+ source.Append("return ");
+ }
+
+ source.Append($"_unmanagedCallbacks.{callback.Name}(");
+ source.Append(methodCallArguments);
+ source.Append(");\n");
+
+ if (methodSourceAfterCall.Length != 0)
+ {
+ source.Append(methodSourceAfterCall);
+
+ if (!callback.ReturnsVoid)
+ source.Append(" return ret;\n");
+ }
+
+ source.Append(" }\n\n");
+ }
+
+ source.Append("}\n");
+
+ if (isInnerClass)
+ {
+ var containingType = symbol.ContainingType;
+
+ while (containingType != null)
+ {
+ source.Append("}\n"); // outer class
+
+ containingType = containingType.ContainingType;
+ }
+ }
+
+ if (hasNamespace)
+ source.Append("\n}");
+
+ source.Append("\n\n#pragma warning restore CA1707\n");
+
+ context.AddSource($"{data.NativeTypeSymbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()}.generated",
+ SourceText.From(source.ToString(), Encoding.UTF8));
+ }
+
+ private void GenerateUnmanagedCallbacksStruct(GeneratorExecutionContext context, CallbacksData data)
+ {
+ var symbol = data.FuncStructSymbol;
+
+ INamespaceSymbol namespaceSymbol = symbol.ContainingNamespace;
+ string classNs = namespaceSymbol != null && !namespaceSymbol.IsGlobalNamespace ?
+ namespaceSymbol.FullQualifiedName() :
+ string.Empty;
+ bool hasNamespace = classNs.Length != 0;
+ bool isInnerClass = symbol.ContainingType != null;
+
+ var source = new StringBuilder();
+
+ source.Append(
+ @"using System.Runtime.InteropServices;
+using Godot.NativeInterop;
+
+#pragma warning disable CA1707 // Disable warning: Identifiers should not contain underscores
+
+");
+ if (hasNamespace)
+ {
+ source.Append("namespace ");
+ source.Append(classNs);
+ source.Append("\n{\n");
+ }
+
+ if (isInnerClass)
+ {
+ var containingType = symbol.ContainingType;
+
+ while (containingType != null)
+ {
+ source.Append("partial ");
+ source.Append(containingType.GetDeclarationKeyword());
+ source.Append(" ");
+ source.Append(containingType.NameWithTypeParameters());
+ source.Append("\n{\n");
+
+ containingType = containingType.ContainingType;
+ }
+ }
+
+ source.Append("[StructLayout(LayoutKind.Sequential)]\n");
+ source.Append($"unsafe partial struct {symbol.Name}\n{{\n");
+
+ foreach (var callback in data.Methods)
+ {
+ source.Append(" ");
+ source.Append(callback.DeclaredAccessibility == Accessibility.Public ? "public " : "internal ");
+
+ source.Append("delegate* unmanaged<");
+
+ foreach (var parameter in callback.Parameters)
+ {
+ if (IsByRefParameter(parameter))
+ {
+ if (IsGodotInteropStruct(parameter.Type) || parameter.Type.IsValueType)
+ {
+ AppendPointerType(source, parameter.Type);
+ }
+ else
+ {
+ // If it's a by-ref param and we can't get the pointer
+ // just pass it by-ref and let it be pinned.
+ AppendRefKind(source, parameter.RefKind)
+ .Append(' ')
+ .Append(parameter.Type.FullQualifiedName());
+ }
+ }
+ else
+ {
+ source.Append(parameter.Type.FullQualifiedName());
+ }
+
+ source.Append(", ");
+ }
+
+ source.Append(callback.ReturnType.FullQualifiedName());
+ source.Append($"> {callback.Name};\n");
+ }
+
+ source.Append("}\n");
+
+ if (isInnerClass)
+ {
+ var containingType = symbol.ContainingType;
+
+ while (containingType != null)
+ {
+ source.Append("}\n"); // outer class
+
+ containingType = containingType.ContainingType;
+ }
+ }
+
+ if (hasNamespace)
+ source.Append("}\n");
+
+ source.Append("\n#pragma warning restore CA1707\n");
+
+ context.AddSource($"{symbol.FullQualifiedName().SanitizeQualifiedNameForUniqueHint()}.generated",
+ SourceText.From(source.ToString(), Encoding.UTF8));
+ }
+
+ private static bool IsGodotInteropStruct(ITypeSymbol type) =>
+ GodotInteropStructs.Contains(type.FullQualifiedName());
+
+ private static bool IsByRefParameter(IParameterSymbol parameter) =>
+ parameter.RefKind is RefKind.In or RefKind.Out or RefKind.Ref;
+
+ private static StringBuilder AppendRefKind(StringBuilder source, RefKind refKind) =>
+ refKind switch
+ {
+ RefKind.In => source.Append("in"),
+ RefKind.Out => source.Append("out"),
+ RefKind.Ref => source.Append("ref"),
+ _ => source,
+ };
+
+ private static void AppendPointerType(StringBuilder source, ITypeSymbol type)
+ {
+ source.Append(type.FullQualifiedName());
+ source.Append('*');
+ }
+
+ private static void AppendCustomUnsafeAsPointer(StringBuilder source, IParameterSymbol parameter,
+ out string varName)
+ {
+ varName = $"{parameter.Name}_ptr";
+
+ AppendPointerType(source, parameter.Type);
+ source.Append(' ');
+ source.Append(varName);
+ source.Append(" = ");
+
+ source.Append('(');
+ AppendPointerType(source, parameter.Type);
+ source.Append(')');
+
+ if (parameter.RefKind == RefKind.In)
+ source.Append("CustomUnsafe.ReadOnlyRefAsPointer(in ");
+ else
+ source.Append("CustomUnsafe.AsPointer(ref ");
+
+ source.Append(parameter.Name);
+
+ source.Append(");\n");
+ }
+
+ private static void AppendCopyToStackAndGetPointer(StringBuilder source, IParameterSymbol parameter,
+ out string varName)
+ {
+ varName = $"{parameter.Name}_copy";
+
+ source.Append(parameter.Type.FullQualifiedName());
+ source.Append(' ');
+ source.Append(varName);
+ if (parameter.RefKind is RefKind.In or RefKind.Ref)
+ {
+ source.Append(" = ");
+ source.Append(parameter.Name);
+ }
+
+ source.Append(";\n");
+ }
+
+ private static readonly string[] GodotInteropStructs =
+ {
+ "Godot.NativeInterop.godot_ref",
+ "Godot.NativeInterop.godot_variant_call_error",
+ "Godot.NativeInterop.godot_variant",
+ "Godot.NativeInterop.godot_string",
+ "Godot.NativeInterop.godot_string_name",
+ "Godot.NativeInterop.godot_node_path",
+ "Godot.NativeInterop.godot_signal",
+ "Godot.NativeInterop.godot_callable",
+ "Godot.NativeInterop.godot_array",
+ "Godot.NativeInterop.godot_dictionary",
+ "Godot.NativeInterop.godot_packed_byte_array",
+ "Godot.NativeInterop.godot_packed_int32_array",
+ "Godot.NativeInterop.godot_packed_int64_array",
+ "Godot.NativeInterop.godot_packed_float32_array",
+ "Godot.NativeInterop.godot_packed_float64_array",
+ "Godot.NativeInterop.godot_packed_string_array",
+ "Godot.NativeInterop.godot_packed_vector2_array",
+ "Godot.NativeInterop.godot_packed_vector3_array",
+ "Godot.NativeInterop.godot_packed_color_array",
+ };
+}
diff --git a/modules/mono/glue/GodotSharp/GodotPlugins/GodotPlugins.csproj b/modules/mono/glue/GodotSharp/GodotPlugins/GodotPlugins.csproj
new file mode 100644
index 0000000000..e720d3878c
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotPlugins/GodotPlugins.csproj
@@ -0,0 +1,17 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>net6.0</TargetFramework>
+ <LangVersion>10</LangVersion>
+ <Nullable>enable</Nullable>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+
+ <!-- To generate the .runtimeconfig.json file-->
+ <EnableDynamicLoading>true</EnableDynamicLoading>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\GodotSharp\GodotSharp.csproj" />
+ </ItemGroup>
+
+</Project>
diff --git a/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs b/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs
new file mode 100644
index 0000000000..8308bada24
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotPlugins/Main.cs
@@ -0,0 +1,270 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Loader;
+using Godot.Bridge;
+using Godot.NativeInterop;
+
+namespace GodotPlugins
+{
+ public static class Main
+ {
+ // IMPORTANT:
+ // Keeping strong references to the AssemblyLoadContext (our PluginLoadContext) prevents
+ // it from being unloaded. To avoid issues, we wrap the reference in this class, and mark
+ // all the methods that access it as non-inlineable. This way we prevent local references
+ // (either real or introduced by the JIT) to escape the scope of these methods due to
+ // inlining, which could keep the AssemblyLoadContext alive while trying to unload.
+ private sealed class PluginLoadContextWrapper
+ {
+ private PluginLoadContext? _pluginLoadContext;
+
+ public string? AssemblyLoadedPath
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ get => _pluginLoadContext?.AssemblyLoadedPath;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static (Assembly, PluginLoadContextWrapper) CreateAndLoadFromAssemblyName(
+ AssemblyName assemblyName,
+ string pluginPath,
+ ICollection<string> sharedAssemblies,
+ AssemblyLoadContext mainLoadContext
+ )
+ {
+ var wrapper = new PluginLoadContextWrapper();
+ wrapper._pluginLoadContext = new PluginLoadContext(
+ pluginPath, sharedAssemblies, mainLoadContext);
+ var assembly = wrapper._pluginLoadContext.LoadFromAssemblyName(assemblyName);
+ return (assembly, wrapper);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public WeakReference CreateWeakReference()
+ {
+ return new WeakReference(_pluginLoadContext, trackResurrection: true);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal void Unload()
+ {
+ _pluginLoadContext?.Unload();
+ _pluginLoadContext = null;
+ }
+ }
+
+ private static readonly List<AssemblyName> SharedAssemblies = new();
+ private static readonly Assembly CoreApiAssembly = typeof(Godot.Object).Assembly;
+ private static Assembly? _editorApiAssembly;
+ private static PluginLoadContextWrapper? _projectLoadContext;
+
+ private static readonly AssemblyLoadContext MainLoadContext =
+ AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()) ??
+ AssemblyLoadContext.Default;
+
+ private static DllImportResolver? _dllImportResolver;
+
+ // Right now we do it this way for simplicity as hot-reload is disabled. It will need to be changed later.
+ [UnmanagedCallersOnly]
+ // ReSharper disable once UnusedMember.Local
+ private static unsafe godot_bool InitializeFromEngine(IntPtr godotDllHandle, godot_bool editorHint,
+ PluginsCallbacks* pluginsCallbacks, ManagedCallbacks* managedCallbacks,
+ IntPtr unmanagedCallbacks, int unmanagedCallbacksSize)
+ {
+ try
+ {
+ _dllImportResolver = new GodotDllImportResolver(godotDllHandle).OnResolveDllImport;
+
+ SharedAssemblies.Add(CoreApiAssembly.GetName());
+ NativeLibrary.SetDllImportResolver(CoreApiAssembly, _dllImportResolver);
+
+ AlcReloadCfg.Configure(alcReloadEnabled: editorHint.ToBool());
+ NativeFuncs.Initialize(unmanagedCallbacks, unmanagedCallbacksSize);
+
+ if (editorHint.ToBool())
+ {
+ _editorApiAssembly = Assembly.Load("GodotSharpEditor");
+ SharedAssemblies.Add(_editorApiAssembly.GetName());
+ NativeLibrary.SetDllImportResolver(_editorApiAssembly, _dllImportResolver);
+ }
+
+ *pluginsCallbacks = new()
+ {
+ LoadProjectAssemblyCallback = &LoadProjectAssembly,
+ LoadToolsAssemblyCallback = &LoadToolsAssembly,
+ UnloadProjectPluginCallback = &UnloadProjectPlugin,
+ };
+
+ *managedCallbacks = ManagedCallbacks.Create();
+
+ return godot_bool.True;
+ }
+ catch (Exception e)
+ {
+ Console.Error.WriteLine(e);
+ return godot_bool.False;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct PluginsCallbacks
+ {
+ public unsafe delegate* unmanaged<char*, godot_string*, godot_bool> LoadProjectAssemblyCallback;
+ public unsafe delegate* unmanaged<char*, IntPtr, int, IntPtr> LoadToolsAssemblyCallback;
+ public unsafe delegate* unmanaged<godot_bool> UnloadProjectPluginCallback;
+ }
+
+ [UnmanagedCallersOnly]
+ private static unsafe godot_bool LoadProjectAssembly(char* nAssemblyPath, godot_string* outLoadedAssemblyPath)
+ {
+ try
+ {
+ if (_projectLoadContext != null)
+ return godot_bool.True; // Already loaded
+
+ string assemblyPath = new(nAssemblyPath);
+
+ (var projectAssembly, _projectLoadContext) = LoadPlugin(assemblyPath);
+
+ string loadedAssemblyPath = _projectLoadContext.AssemblyLoadedPath ?? assemblyPath;
+ *outLoadedAssemblyPath = Marshaling.ConvertStringToNative(loadedAssemblyPath);
+
+ ScriptManagerBridge.LookupScriptsInAssembly(projectAssembly);
+
+ return godot_bool.True;
+ }
+ catch (Exception e)
+ {
+ Console.Error.WriteLine(e);
+ return godot_bool.False;
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ private static unsafe IntPtr LoadToolsAssembly(char* nAssemblyPath,
+ IntPtr unmanagedCallbacks, int unmanagedCallbacksSize)
+ {
+ try
+ {
+ string assemblyPath = new(nAssemblyPath);
+
+ if (_editorApiAssembly == null)
+ throw new InvalidOperationException("The Godot editor API assembly is not loaded.");
+
+ var (assembly, _) = LoadPlugin(assemblyPath);
+
+ NativeLibrary.SetDllImportResolver(assembly, _dllImportResolver!);
+
+ var method = assembly.GetType("GodotTools.GodotSharpEditor")?
+ .GetMethod("InternalCreateInstance",
+ BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
+
+ if (method == null)
+ {
+ throw new MissingMethodException("GodotTools.GodotSharpEditor",
+ "InternalCreateInstance");
+ }
+
+ return (IntPtr?)method
+ .Invoke(null, new object[] { unmanagedCallbacks, unmanagedCallbacksSize })
+ ?? IntPtr.Zero;
+ }
+ catch (Exception e)
+ {
+ Console.Error.WriteLine(e);
+ return IntPtr.Zero;
+ }
+ }
+
+ private static (Assembly, PluginLoadContextWrapper) LoadPlugin(string assemblyPath)
+ {
+ string assemblyName = Path.GetFileNameWithoutExtension(assemblyPath);
+
+ var sharedAssemblies = new List<string>();
+
+ foreach (var sharedAssembly in SharedAssemblies)
+ {
+ string? sharedAssemblyName = sharedAssembly.Name;
+ if (sharedAssemblyName != null)
+ sharedAssemblies.Add(sharedAssemblyName);
+ }
+
+ return PluginLoadContextWrapper.CreateAndLoadFromAssemblyName(
+ new AssemblyName(assemblyName), assemblyPath, sharedAssemblies, MainLoadContext);
+ }
+
+ [UnmanagedCallersOnly]
+ private static godot_bool UnloadProjectPlugin()
+ {
+ try
+ {
+ return UnloadPlugin(ref _projectLoadContext).ToGodotBool();
+ }
+ catch (Exception e)
+ {
+ Console.Error.WriteLine(e);
+ return godot_bool.False;
+ }
+ }
+
+ private static bool UnloadPlugin(ref PluginLoadContextWrapper? pluginLoadContext)
+ {
+ try
+ {
+ if (pluginLoadContext == null)
+ return true;
+
+ Console.WriteLine("Unloading assembly load context...");
+
+ var alcWeakReference = pluginLoadContext.CreateWeakReference();
+
+ pluginLoadContext.Unload();
+ pluginLoadContext = null;
+
+ int startTimeMs = Environment.TickCount;
+ bool takingTooLong = false;
+
+ while (alcWeakReference.IsAlive)
+ {
+ GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
+ GC.WaitForPendingFinalizers();
+
+ if (!alcWeakReference.IsAlive)
+ break;
+
+ int elapsedTimeMs = Environment.TickCount - startTimeMs;
+
+ if (!takingTooLong && elapsedTimeMs >= 2000)
+ {
+ takingTooLong = true;
+
+ // TODO: How to log from GodotPlugins? (delegate pointer?)
+ Console.Error.WriteLine("Assembly unloading is taking longer than expected...");
+ }
+ else if (elapsedTimeMs >= 5000)
+ {
+ // TODO: How to log from GodotPlugins? (delegate pointer?)
+ Console.Error.WriteLine(
+ "Failed to unload assemblies. Possible causes: Strong GC handles, running threads, etc.");
+
+ return false;
+ }
+ }
+
+ Console.WriteLine("Assembly load context unloaded successfully.");
+
+ return true;
+ }
+ catch (Exception e)
+ {
+ // TODO: How to log exceptions from GodotPlugins? (delegate pointer?)
+ Console.Error.WriteLine(e);
+ return false;
+ }
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs b/modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs
new file mode 100644
index 0000000000..dcd572c65e
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotPlugins/PluginLoadContext.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Runtime.Loader;
+
+namespace GodotPlugins
+{
+ public class PluginLoadContext : AssemblyLoadContext
+ {
+ private readonly AssemblyDependencyResolver _resolver;
+ private readonly ICollection<string> _sharedAssemblies;
+ private readonly AssemblyLoadContext _mainLoadContext;
+
+ public string? AssemblyLoadedPath { get; private set; }
+
+ public PluginLoadContext(string pluginPath, ICollection<string> sharedAssemblies,
+ AssemblyLoadContext mainLoadContext)
+ : base(isCollectible: true)
+ {
+ _resolver = new AssemblyDependencyResolver(pluginPath);
+ _sharedAssemblies = sharedAssemblies;
+ _mainLoadContext = mainLoadContext;
+ }
+
+ protected override Assembly? Load(AssemblyName assemblyName)
+ {
+ if (assemblyName.Name == null)
+ return null;
+
+ if (_sharedAssemblies.Contains(assemblyName.Name))
+ return _mainLoadContext.LoadFromAssemblyName(assemblyName);
+
+ string? assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
+ if (assemblyPath != null)
+ {
+ AssemblyLoadedPath = assemblyPath;
+
+ // Load in memory to prevent locking the file
+ using var assemblyFile = File.Open(assemblyPath, FileMode.Open, FileAccess.Read, FileShare.Read);
+ string pdbPath = Path.ChangeExtension(assemblyPath, ".pdb");
+
+ if (File.Exists(pdbPath))
+ {
+ using var pdbFile = File.Open(pdbPath, FileMode.Open, FileAccess.Read, FileShare.Read);
+ return LoadFromStream(assemblyFile, pdbFile);
+ }
+
+ return LoadFromStream(assemblyFile);
+ }
+
+ return null;
+ }
+
+ protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
+ {
+ string? libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
+ if (libraryPath != null)
+ return LoadUnmanagedDllFromPath(libraryPath);
+
+ return IntPtr.Zero;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp.sln b/modules/mono/glue/GodotSharp/GodotSharp.sln
index 4896d0a07d..8db42c2d1a 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp.sln
+++ b/modules/mono/glue/GodotSharp/GodotSharp.sln
@@ -4,6 +4,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotSharp", "GodotSharp\Go
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotSharpEditor", "GodotSharpEditor\GodotSharpEditor.csproj", "{8FBEC238-D944-4074-8548-B3B524305905}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GodotPlugins", "GodotPlugins\GodotPlugins.csproj", "{944B77DB-497B-47F5-A1E3-81C35E3E9D4E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot.SourceGenerators.Internal", "Godot.SourceGenerators.Internal\Godot.SourceGenerators.Internal.csproj", "{7749662B-E30C-419A-B745-13852573360A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -18,5 +22,13 @@ Global
{8FBEC238-D944-4074-8548-B3B524305905}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8FBEC238-D944-4074-8548-B3B524305905}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8FBEC238-D944-4074-8548-B3B524305905}.Release|Any CPU.Build.0 = Release|Any CPU
+ {944B77DB-497B-47F5-A1E3-81C35E3E9D4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {944B77DB-497B-47F5-A1E3-81C35E3E9D4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {944B77DB-497B-47F5-A1E3-81C35E3E9D4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {944B77DB-497B-47F5-A1E3-81C35E3E9D4E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7749662B-E30C-419A-B745-13852573360A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7749662B-E30C-419A-B745-13852573360A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7749662B-E30C-419A-B745-13852573360A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7749662B-E30C-419A-B745-13852573360A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/modules/mono/glue/GodotSharp/GodotSharp.sln.DotSettings b/modules/mono/glue/GodotSharp/GodotSharp.sln.DotSettings
new file mode 100644
index 0000000000..ba65b61e95
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp.sln.DotSettings
@@ -0,0 +1,8 @@
+<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
+ <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GC/@EntryIndexedValue">GC</s:String>
+ <s:Boolean x:Key="/Default/UserDictionary/Words/=alcs/@EntryIndexedValue">True</s:Boolean>
+ <s:Boolean x:Key="/Default/UserDictionary/Words/=gdnative/@EntryIndexedValue">True</s:Boolean>
+ <s:Boolean x:Key="/Default/UserDictionary/Words/=godotsharp/@EntryIndexedValue">True</s:Boolean>
+ <s:Boolean x:Key="/Default/UserDictionary/Words/=icall/@EntryIndexedValue">True</s:Boolean>
+ <s:Boolean x:Key="/Default/UserDictionary/Words/=quat/@EntryIndexedValue">True</s:Boolean>
+ <s:Boolean x:Key="/Default/UserDictionary/Words/=vcall/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
index 850ae7fc3b..17f680361d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
@@ -1,8 +1,3 @@
-#if REAL_T_IS_DOUBLE
-using real_t = System.Double;
-#else
-using real_t = System.Single;
-#endif
using System;
using System.Runtime.InteropServices;
@@ -150,6 +145,9 @@ namespace Godot
/// Gets the position of one of the 8 endpoints of the <see cref="AABB"/>.
/// </summary>
/// <param name="idx">Which endpoint to get.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="idx"/> is less than 0 or greater than 7.
+ /// </exception>
/// <returns>An endpoint of the <see cref="AABB"/>.</returns>
public Vector3 GetEndpoint(int idx)
{
@@ -702,12 +700,7 @@ namespace Godot
/// <returns>Whether or not the AABB and the object are equal.</returns>
public override bool Equals(object obj)
{
- if (obj is AABB)
- {
- return Equals((AABB)obj);
- }
-
- return false;
+ return obj is AABB other && Equals(other);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
index a412047196..1c98dfcdf6 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Array.cs
@@ -1,47 +1,35 @@
using System;
using System.Collections.Generic;
using System.Collections;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
+using Godot.NativeInterop;
namespace Godot.Collections
{
- internal class ArraySafeHandle : SafeHandle
- {
- public ArraySafeHandle(IntPtr handle) : base(IntPtr.Zero, true)
- {
- this.handle = handle;
- }
-
- public override bool IsInvalid
- {
- get { return handle == IntPtr.Zero; }
- }
-
- protected override bool ReleaseHandle()
- {
- Array.godot_icall_Array_Dtor(handle);
- return true;
- }
- }
-
/// <summary>
/// Wrapper around Godot's Array class, an array of Variant
/// typed elements allocated in the engine in C++. Useful when
/// interfacing with the engine. Otherwise prefer .NET collections
/// such as <see cref="System.Array"/> or <see cref="List{T}"/>.
/// </summary>
- public class Array : IList, IDisposable
+ public sealed class Array :
+ IList<Variant>,
+ IReadOnlyList<Variant>,
+ ICollection,
+ IDisposable
{
- private ArraySafeHandle _safeHandle;
- private bool _disposed = false;
+ internal godot_array.movable NativeValue;
+
+ private WeakReference<IDisposable> _weakReferenceToSelf;
/// <summary>
/// Constructs a new empty <see cref="Array"/>.
/// </summary>
public Array()
{
- _safeHandle = new ArraySafeHandle(godot_icall_Array_Ctor());
+ NativeValue = (godot_array.movable)NativeFuncs.godotsharp_array_new();
+ _weakReferenceToSelf = DisposablesTracker.RegisterDisposable(this);
}
/// <summary>
@@ -49,12 +37,12 @@ namespace Godot.Collections
/// </summary>
/// <param name="collection">The collection of elements to construct from.</param>
/// <returns>A new Godot Array.</returns>
- public Array(IEnumerable collection) : this()
+ public Array(IEnumerable<Variant> collection) : this()
{
if (collection == null)
- throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'");
+ throw new ArgumentNullException(nameof(collection));
- foreach (object element in collection)
+ foreach (Variant element in collection)
Add(element);
}
@@ -63,31 +51,126 @@ namespace Godot.Collections
/// </summary>
/// <param name="array">The objects to put in the new array.</param>
/// <returns>A new Godot Array.</returns>
- public Array(params object[] array) : this()
+ public Array(Variant[] array) : this()
{
if (array == null)
- {
- throw new NullReferenceException($"Parameter '{nameof(array)} cannot be null.'");
- }
- _safeHandle = new ArraySafeHandle(godot_icall_Array_Ctor_MonoArray(array));
+ throw new ArgumentNullException(nameof(array));
+
+ NativeValue = (godot_array.movable)NativeFuncs.godotsharp_array_new();
+ _weakReferenceToSelf = DisposablesTracker.RegisterDisposable(this);
+
+ int length = array.Length;
+
+ Resize(length);
+
+ for (int i = 0; i < length; i++)
+ this[i] = array[i];
}
- internal Array(ArraySafeHandle handle)
+ public Array(Span<StringName> array) : this()
{
- _safeHandle = handle;
+ if (array == null)
+ throw new ArgumentNullException(nameof(array));
+
+ NativeValue = (godot_array.movable)NativeFuncs.godotsharp_array_new();
+ _weakReferenceToSelf = DisposablesTracker.RegisterDisposable(this);
+
+ int length = array.Length;
+
+ Resize(length);
+
+ for (int i = 0; i < length; i++)
+ this[i] = array[i];
}
- internal Array(IntPtr handle)
+ public Array(Span<NodePath> array) : this()
{
- _safeHandle = new ArraySafeHandle(handle);
+ if (array == null)
+ throw new ArgumentNullException(nameof(array));
+
+ NativeValue = (godot_array.movable)NativeFuncs.godotsharp_array_new();
+ _weakReferenceToSelf = DisposablesTracker.RegisterDisposable(this);
+
+ int length = array.Length;
+
+ Resize(length);
+
+ for (int i = 0; i < length; i++)
+ this[i] = array[i];
+ }
+
+ public Array(Span<RID> array) : this()
+ {
+ if (array == null)
+ throw new ArgumentNullException(nameof(array));
+
+ NativeValue = (godot_array.movable)NativeFuncs.godotsharp_array_new();
+ _weakReferenceToSelf = DisposablesTracker.RegisterDisposable(this);
+
+ int length = array.Length;
+
+ Resize(length);
+
+ for (int i = 0; i < length; i++)
+ this[i] = array[i];
+ }
+
+ // We must use ReadOnlySpan instead of Span here as this can accept implicit conversions
+ // from derived types (e.g.: Node[]). Implicit conversion from Derived[] to Base[] are
+ // fine as long as the array is not mutated. However, Span does this type checking at
+ // instantiation, so it's not possible to use it even when not mutating anything.
+ // ReSharper disable once RedundantNameQualifier
+ public Array(ReadOnlySpan<Godot.Object> array) : this()
+ {
+ if (array == null)
+ throw new ArgumentNullException(nameof(array));
+
+ NativeValue = (godot_array.movable)NativeFuncs.godotsharp_array_new();
+ _weakReferenceToSelf = DisposablesTracker.RegisterDisposable(this);
+
+ int length = array.Length;
+
+ Resize(length);
+
+ for (int i = 0; i < length; i++)
+ this[i] = array[i];
}
- internal IntPtr GetPtr()
+ private Array(godot_array nativeValueToOwn)
{
- if (_disposed)
- throw new ObjectDisposedException(GetType().FullName);
+ NativeValue = (godot_array.movable)(nativeValueToOwn.IsAllocated ?
+ nativeValueToOwn :
+ NativeFuncs.godotsharp_array_new());
+ _weakReferenceToSelf = DisposablesTracker.RegisterDisposable(this);
+ }
+
+ // Explicit name to make it very clear
+ internal static Array CreateTakingOwnershipOfDisposableValue(godot_array nativeValueToOwn)
+ => new Array(nativeValueToOwn);
- return _safeHandle.DangerousGetHandle();
+ ~Array()
+ {
+ Dispose(false);
+ }
+
+ /// <summary>
+ /// Disposes of this <see cref="Array"/>.
+ /// </summary>
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ public void Dispose(bool disposing)
+ {
+ // Always dispose `NativeValue` even if disposing is true
+ NativeValue.DangerousSelfRef.Dispose();
+
+ if (_weakReferenceToSelf != null)
+ {
+ DisposablesTracker.UnregisterDisposable(_weakReferenceToSelf);
+ }
}
/// <summary>
@@ -97,7 +180,10 @@ namespace Godot.Collections
/// <returns>A new Godot Array.</returns>
public Array Duplicate(bool deep = false)
{
- return new Array(godot_icall_Array_Duplicate(GetPtr(), deep));
+ godot_array newArray;
+ var self = (godot_array)NativeValue;
+ NativeFuncs.godotsharp_array_duplicate(ref self, deep.ToGodotBool(), out newArray);
+ return CreateTakingOwnershipOfDisposableValue(newArray);
}
/// <summary>
@@ -107,7 +193,8 @@ namespace Godot.Collections
/// <returns><see cref="Error.Ok"/> if successful, or an error code.</returns>
public Error Resize(int newSize)
{
- return godot_icall_Array_Resize(GetPtr(), newSize);
+ var self = (godot_array)NativeValue;
+ return NativeFuncs.godotsharp_array_resize(ref self, newSize);
}
/// <summary>
@@ -115,7 +202,8 @@ namespace Godot.Collections
/// </summary>
public void Shuffle()
{
- godot_icall_Array_Shuffle(GetPtr());
+ var self = (godot_array)NativeValue;
+ NativeFuncs.godotsharp_array_shuffle(ref self);
}
/// <summary>
@@ -126,94 +214,136 @@ namespace Godot.Collections
/// <returns>A new Godot Array with the contents of both arrays.</returns>
public static Array operator +(Array left, Array right)
{
- return new Array(godot_icall_Array_Concatenate(left.GetPtr(), right.GetPtr()));
- }
-
- // IDisposable
-
- /// <summary>
- /// Disposes of this <see cref="Array"/>.
- /// </summary>
- public void Dispose()
- {
- if (_disposed)
- return;
-
- if (_safeHandle != null)
+ if (left == null)
{
- _safeHandle.Dispose();
- _safeHandle = null;
+ if (right == null)
+ return new Array();
+
+ return right.Duplicate(deep: false);
}
- _disposed = true;
- }
+ if (right == null)
+ return left.Duplicate(deep: false);
+
+ int leftCount = left.Count;
+ int rightCount = right.Count;
- // IList
+ Array newArray = left.Duplicate(deep: false);
+ newArray.Resize(leftCount + rightCount);
- bool IList.IsReadOnly => false;
+ for (int i = 0; i < rightCount; i++)
+ newArray[i + leftCount] = right[i];
- bool IList.IsFixedSize => false;
+ return newArray;
+ }
/// <summary>
- /// Returns the object at the given <paramref name="index"/>.
+ /// Returns the item at the given <paramref name="index"/>.
/// </summary>
- /// <value>The object at the given <paramref name="index"/>.</value>
- public object this[int index]
+ /// <value>The <see cref="Variant"/> item at the given <paramref name="index"/>.</value>
+ public unsafe Variant this[int index]
{
- get => godot_icall_Array_At(GetPtr(), index);
- set => godot_icall_Array_SetAt(GetPtr(), index, value);
+ get
+ {
+ GetVariantBorrowElementAt(index, out godot_variant borrowElem);
+ return Variant.CreateCopyingBorrowed(borrowElem);
+ }
+ set
+ {
+ if (index < 0 || index >= Count)
+ throw new ArgumentOutOfRangeException(nameof(index));
+ var self = (godot_array)NativeValue;
+ godot_variant* ptrw = NativeFuncs.godotsharp_array_ptrw(ref self);
+ godot_variant* itemPtr = &ptrw[index];
+ (*itemPtr).Dispose();
+ *itemPtr = value.CopyNativeVariant();
+ }
}
/// <summary>
- /// Adds an object to the end of this <see cref="Array"/>.
+ /// Adds an item to the end of this <see cref="Array"/>.
/// This is the same as <c>append</c> or <c>push_back</c> in GDScript.
/// </summary>
- /// <param name="value">The object to add.</param>
- /// <returns>The new size after adding the object.</returns>
- public int Add(object value) => godot_icall_Array_Add(GetPtr(), value);
+ /// <param name="item">The <see cref="Variant"/> item to add.</param>
+ public void Add(Variant item)
+ {
+ godot_variant variantValue = (godot_variant)item.NativeVar;
+ var self = (godot_array)NativeValue;
+ _ = NativeFuncs.godotsharp_array_add(ref self, variantValue);
+ }
/// <summary>
- /// Checks if this <see cref="Array"/> contains the given object.
+ /// Checks if this <see cref="Array"/> contains the given item.
/// </summary>
- /// <param name="value">The item to look for.</param>
- /// <returns>Whether or not this array contains the given object.</returns>
- public bool Contains(object value) => godot_icall_Array_Contains(GetPtr(), value);
+ /// <param name="item">The <see cref="Variant"/> item to look for.</param>
+ /// <returns>Whether or not this array contains the given item.</returns>
+ public bool Contains(Variant item) => IndexOf(item) != -1;
/// <summary>
/// Erases all items from this <see cref="Array"/>.
/// </summary>
- public void Clear() => godot_icall_Array_Clear(GetPtr());
+ public void Clear() => Resize(0);
/// <summary>
- /// Searches this <see cref="Array"/> for an object
+ /// Searches this <see cref="Array"/> for an item
/// and returns its index or -1 if not found.
/// </summary>
- /// <param name="value">The object to search for.</param>
- /// <returns>The index of the object, or -1 if not found.</returns>
- public int IndexOf(object value) => godot_icall_Array_IndexOf(GetPtr(), value);
+ /// <param name="item">The <see cref="Variant"/> item to search for.</param>
+ /// <returns>The index of the item, or -1 if not found.</returns>
+ public int IndexOf(Variant item)
+ {
+ godot_variant variantValue = (godot_variant)item.NativeVar;
+ var self = (godot_array)NativeValue;
+ return NativeFuncs.godotsharp_array_index_of(ref self, variantValue);
+ }
/// <summary>
- /// Inserts a new object at a given position in the array.
+ /// Inserts a new item at a given position in the array.
/// The position must be a valid position of an existing item,
/// or the position at the end of the array.
/// Existing items will be moved to the right.
/// </summary>
/// <param name="index">The index to insert at.</param>
- /// <param name="value">The object to insert.</param>
- public void Insert(int index, object value) => godot_icall_Array_Insert(GetPtr(), index, value);
+ /// <param name="item">The <see cref="Variant"/> item to insert.</param>
+ public void Insert(int index, Variant item)
+ {
+ if (index < 0 || index > Count)
+ throw new ArgumentOutOfRangeException(nameof(index));
+
+ godot_variant variantValue = (godot_variant)item.NativeVar;
+ var self = (godot_array)NativeValue;
+ NativeFuncs.godotsharp_array_insert(ref self, index, variantValue);
+ }
/// <summary>
- /// Removes the first occurrence of the specified <paramref name="value"/>
+ /// Removes the first occurrence of the specified <paramref name="item"/>
/// from this <see cref="Array"/>.
/// </summary>
- /// <param name="value">The value to remove.</param>
- public void Remove(object value) => godot_icall_Array_Remove(GetPtr(), value);
+ /// <param name="item">The value to remove.</param>
+ public bool Remove(Variant item)
+ {
+ int index = IndexOf(item);
+ if (index >= 0)
+ {
+ RemoveAt(index);
+ return true;
+ }
+
+ return false;
+ }
/// <summary>
/// Removes an element from this <see cref="Array"/> by index.
/// </summary>
/// <param name="index">The index of the element to remove.</param>
- public void RemoveAt(int index) => godot_icall_Array_RemoveAt(GetPtr(), index);
+ public void RemoveAt(int index)
+ {
+ if (index < 0 || index > Count)
+ throw new ArgumentOutOfRangeException(nameof(index));
+
+ var self = (godot_array)NativeValue;
+ NativeFuncs.godotsharp_array_remove_at(ref self, index);
+ }
// ICollection
@@ -222,28 +352,77 @@ namespace Godot.Collections
/// This is also known as the size or length of the array.
/// </summary>
/// <returns>The number of elements.</returns>
- public int Count => godot_icall_Array_Count(GetPtr());
-
- object ICollection.SyncRoot => this;
+ public int Count => NativeValue.DangerousSelfRef.Size;
bool ICollection.IsSynchronized => false;
+ object ICollection.SyncRoot => false;
+
+ bool ICollection<Variant>.IsReadOnly => false;
+
/// <summary>
/// Copies the elements of this <see cref="Array"/> to the given
- /// untyped C# array, starting at the given index.
+ /// <see cref="Variant"/> C# array, starting at the given index.
/// </summary>
/// <param name="array">The array to copy to.</param>
- /// <param name="index">The index to start at.</param>
- public void CopyTo(System.Array array, int index)
+ /// <param name="arrayIndex">The index to start at.</param>
+ public void CopyTo(Variant[] array, int arrayIndex)
+ {
+ if (array == null)
+ throw new ArgumentNullException(nameof(array), "Value cannot be null.");
+
+ if (arrayIndex < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(arrayIndex),
+ "Number was less than the array's lower bound in the first dimension.");
+ }
+
+ int count = Count;
+
+ if (array.Length < (arrayIndex + count))
+ {
+ throw new ArgumentException(
+ "Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
+ }
+
+ unsafe
+ {
+ for (int i = 0; i < count; i++)
+ {
+ array[arrayIndex] = Variant.CreateCopyingBorrowed(NativeValue.DangerousSelfRef.Elements[i]);
+ arrayIndex++;
+ }
+ }
+ }
+
+ void ICollection.CopyTo(System.Array array, int index)
{
if (array == null)
throw new ArgumentNullException(nameof(array), "Value cannot be null.");
if (index < 0)
- throw new ArgumentOutOfRangeException(nameof(index), "Number was less than the array's lower bound in the first dimension.");
+ {
+ throw new ArgumentOutOfRangeException(nameof(index),
+ "Number was less than the array's lower bound in the first dimension.");
+ }
+
+ int count = Count;
- // Internal call may throw ArgumentException
- godot_icall_Array_CopyTo(GetPtr(), array, index);
+ if (array.Length < (index + count))
+ {
+ throw new ArgumentException(
+ "Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
+ }
+
+ unsafe
+ {
+ for (int i = 0; i < count; i++)
+ {
+ object obj = Marshaling.ConvertVariantToManagedObject(NativeValue.DangerousSelfRef.Elements[i]);
+ array.SetValue(obj, index);
+ index++;
+ }
+ }
}
// IEnumerable
@@ -252,7 +431,7 @@ namespace Godot.Collections
/// Gets an enumerator for this <see cref="Array"/>.
/// </summary>
/// <returns>An enumerator.</returns>
- public IEnumerator GetEnumerator()
+ public IEnumerator<Variant> GetEnumerator()
{
int count = Count;
@@ -262,77 +441,37 @@ namespace Godot.Collections
}
}
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+
/// <summary>
/// Converts this <see cref="Array"/> to a string.
/// </summary>
/// <returns>A string representation of this array.</returns>
public override string ToString()
{
- return godot_icall_Array_ToString(GetPtr());
+ var self = (godot_array)NativeValue;
+ NativeFuncs.godotsharp_array_to_string(ref self, out godot_string str);
+ using (str)
+ return Marshaling.ConvertStringToManaged(str);
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_Array_Ctor();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_Array_Ctor_MonoArray(System.Array array);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Array_Dtor(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern object godot_icall_Array_At(IntPtr ptr, int index);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern object godot_icall_Array_At_Generic(IntPtr ptr, int index, int elemTypeEncoding, IntPtr elemTypeClass);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Array_SetAt(IntPtr ptr, int index, object value);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern int godot_icall_Array_Count(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern int godot_icall_Array_Add(IntPtr ptr, object item);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Array_Clear(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_Array_Concatenate(IntPtr left, IntPtr right);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool godot_icall_Array_Contains(IntPtr ptr, object item);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Array_CopyTo(IntPtr ptr, System.Array array, int arrayIndex);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_Array_Duplicate(IntPtr ptr, bool deep);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern int godot_icall_Array_IndexOf(IntPtr ptr, object item);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Array_Insert(IntPtr ptr, int index, object item);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool godot_icall_Array_Remove(IntPtr ptr, object item);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Array_RemoveAt(IntPtr ptr, int index);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern Error godot_icall_Array_Resize(IntPtr ptr, int newSize);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern Error godot_icall_Array_Shuffle(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Array_Generic_GetElementTypeInfo(Type elemType, out int elemTypeEncoding, out IntPtr elemTypeClass);
+ /// <summary>
+ /// The variant returned via the <paramref name="elem"/> parameter is owned by the Array and must not be disposed.
+ /// </summary>
+ internal void GetVariantBorrowElementAt(int index, out godot_variant elem)
+ {
+ if (index < 0 || index >= Count)
+ throw new ArgumentOutOfRangeException(nameof(index));
+ GetVariantBorrowElementAtUnchecked(index, out elem);
+ }
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern string godot_icall_Array_ToString(IntPtr ptr);
+ /// <summary>
+ /// The variant returned via the <paramref name="elem"/> parameter is owned by the Array and must not be disposed.
+ /// </summary>
+ internal unsafe void GetVariantBorrowElementAtUnchecked(int index, out godot_variant elem)
+ {
+ elem = NativeValue.DangerousSelfRef.Elements[index];
+ }
}
/// <summary>
@@ -342,16 +481,45 @@ namespace Godot.Collections
/// such as arrays or <see cref="List{T}"/>.
/// </summary>
/// <typeparam name="T">The type of the array.</typeparam>
- public class Array<T> : IList<T>, ICollection<T>, IEnumerable<T>
+ [SuppressMessage("ReSharper", "RedundantExtendsListEntry")]
+ [SuppressMessage("Naming", "CA1710", MessageId = "Identifiers should have correct suffix")]
+ public sealed class Array<[MustBeVariant] T> :
+ IList<T>,
+ IReadOnlyList<T>,
+ ICollection<T>,
+ IEnumerable<T>
{
- private Array _objectArray;
+ // ReSharper disable StaticMemberInGenericType
+ // Warning is about unique static fields being created for each generic type combination:
+ // https://www.jetbrains.com/help/resharper/StaticMemberInGenericType.html
+ // In our case this is exactly what we want.
- internal static int elemTypeEncoding;
- internal static IntPtr elemTypeClass;
+ private static unsafe delegate* managed<in T, godot_variant> _convertToVariantCallback;
+ private static unsafe delegate* managed<in godot_variant, T> _convertToManagedCallback;
- static Array()
+ // ReSharper restore StaticMemberInGenericType
+
+ static unsafe Array()
{
- Array.godot_icall_Array_Generic_GetElementTypeInfo(typeof(T), out elemTypeEncoding, out elemTypeClass);
+ _convertToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<T>();
+ _convertToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<T>();
+ }
+
+ private static unsafe void ValidateVariantConversionCallbacks()
+ {
+ if (_convertToVariantCallback == null || _convertToManagedCallback == null)
+ {
+ throw new InvalidOperationException(
+ $"The array element type is not supported for conversion to Variant: '{typeof(T).FullName}'.");
+ }
+ }
+
+ private readonly Array _underlyingArray;
+
+ internal ref godot_array.movable NativeValue
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => ref _underlyingArray.NativeValue;
}
/// <summary>
@@ -359,7 +527,9 @@ namespace Godot.Collections
/// </summary>
public Array()
{
- _objectArray = new Array();
+ ValidateVariantConversionCallbacks();
+
+ _underlyingArray = new Array();
}
/// <summary>
@@ -369,10 +539,15 @@ namespace Godot.Collections
/// <returns>A new Godot Array.</returns>
public Array(IEnumerable<T> collection)
{
+ ValidateVariantConversionCallbacks();
+
if (collection == null)
- throw new NullReferenceException($"Parameter '{nameof(collection)} cannot be null.'");
+ throw new ArgumentNullException(nameof(collection));
+
+ _underlyingArray = new Array();
- _objectArray = new Array(collection);
+ foreach (T element in collection)
+ Add(element);
}
/// <summary>
@@ -380,13 +555,17 @@ namespace Godot.Collections
/// </summary>
/// <param name="array">The items to put in the new array.</param>
/// <returns>A new Godot Array.</returns>
- public Array(params T[] array) : this()
+ public Array(T[] array) : this()
{
+ ValidateVariantConversionCallbacks();
+
if (array == null)
- {
- throw new NullReferenceException($"Parameter '{nameof(array)} cannot be null.'");
- }
- _objectArray = new Array(array);
+ throw new ArgumentNullException(nameof(array));
+
+ _underlyingArray = new Array();
+
+ foreach (T element in array)
+ Add(element);
}
/// <summary>
@@ -395,23 +574,14 @@ namespace Godot.Collections
/// <param name="array">The untyped array to construct from.</param>
public Array(Array array)
{
- _objectArray = array;
- }
+ ValidateVariantConversionCallbacks();
- internal Array(IntPtr handle)
- {
- _objectArray = new Array(handle);
+ _underlyingArray = array;
}
- internal Array(ArraySafeHandle handle)
- {
- _objectArray = new Array(handle);
- }
-
- internal IntPtr GetPtr()
- {
- return _objectArray.GetPtr();
- }
+ // Explicit name to make it very clear
+ internal static Array<T> CreateTakingOwnershipOfDisposableValue(godot_array nativeValueToOwn)
+ => new Array<T>(Array.CreateTakingOwnershipOfDisposableValue(nativeValueToOwn));
/// <summary>
/// Converts this typed <see cref="Array{T}"/> to an untyped <see cref="Array"/>.
@@ -419,7 +589,7 @@ namespace Godot.Collections
/// <param name="from">The typed array to convert.</param>
public static explicit operator Array(Array<T> from)
{
- return from._objectArray;
+ return from?._underlyingArray;
}
/// <summary>
@@ -429,7 +599,7 @@ namespace Godot.Collections
/// <returns>A new Godot Array.</returns>
public Array<T> Duplicate(bool deep = false)
{
- return new Array<T>(_objectArray.Duplicate(deep));
+ return new Array<T>(_underlyingArray.Duplicate(deep));
}
/// <summary>
@@ -439,7 +609,7 @@ namespace Godot.Collections
/// <returns><see cref="Error.Ok"/> if successful, or an error code.</returns>
public Error Resize(int newSize)
{
- return _objectArray.Resize(newSize);
+ return _underlyingArray.Resize(newSize);
}
/// <summary>
@@ -447,7 +617,7 @@ namespace Godot.Collections
/// </summary>
public void Shuffle()
{
- _objectArray.Shuffle();
+ _underlyingArray.Shuffle();
}
/// <summary>
@@ -458,7 +628,18 @@ namespace Godot.Collections
/// <returns>A new Godot Array with the contents of both arrays.</returns>
public static Array<T> operator +(Array<T> left, Array<T> right)
{
- return new Array<T>(left._objectArray + right._objectArray);
+ if (left == null)
+ {
+ if (right == null)
+ return new Array<T>();
+
+ return right.Duplicate(deep: false);
+ }
+
+ if (right == null)
+ return left.Duplicate(deep: false);
+
+ return new Array<T>(left._underlyingArray + right._underlyingArray);
}
// IList<T>
@@ -467,10 +648,23 @@ namespace Godot.Collections
/// Returns the value at the given <paramref name="index"/>.
/// </summary>
/// <value>The value at the given <paramref name="index"/>.</value>
- public T this[int index]
+ public unsafe T this[int index]
{
- get { return (T)Array.godot_icall_Array_At_Generic(GetPtr(), index, elemTypeEncoding, elemTypeClass); }
- set { _objectArray[index] = value; }
+ get
+ {
+ _underlyingArray.GetVariantBorrowElementAt(index, out godot_variant borrowElem);
+ return _convertToManagedCallback(borrowElem);
+ }
+ set
+ {
+ if (index < 0 || index >= Count)
+ throw new ArgumentOutOfRangeException(nameof(index));
+ var self = (godot_array)_underlyingArray.NativeValue;
+ godot_variant* ptrw = NativeFuncs.godotsharp_array_ptrw(ref self);
+ godot_variant* itemPtr = &ptrw[index];
+ (*itemPtr).Dispose();
+ *itemPtr = _convertToVariantCallback(value);
+ }
}
/// <summary>
@@ -479,9 +673,11 @@ namespace Godot.Collections
/// </summary>
/// <param name="item">The item to search for.</param>
/// <returns>The index of the item, or -1 if not found.</returns>
- public int IndexOf(T item)
+ public unsafe int IndexOf(T item)
{
- return _objectArray.IndexOf(item);
+ using var variantValue = _convertToVariantCallback(item);
+ var self = (godot_array)_underlyingArray.NativeValue;
+ return NativeFuncs.godotsharp_array_index_of(ref self, variantValue);
}
/// <summary>
@@ -492,9 +688,14 @@ namespace Godot.Collections
/// </summary>
/// <param name="index">The index to insert at.</param>
/// <param name="item">The item to insert.</param>
- public void Insert(int index, T item)
+ public unsafe void Insert(int index, T item)
{
- _objectArray.Insert(index, item);
+ if (index < 0 || index > Count)
+ throw new ArgumentOutOfRangeException(nameof(index));
+
+ using var variantValue = _convertToVariantCallback(item);
+ var self = (godot_array)_underlyingArray.NativeValue;
+ NativeFuncs.godotsharp_array_insert(ref self, index, variantValue);
}
/// <summary>
@@ -503,7 +704,7 @@ namespace Godot.Collections
/// <param name="index">The index of the element to remove.</param>
public void RemoveAt(int index)
{
- _objectArray.RemoveAt(index);
+ _underlyingArray.RemoveAt(index);
}
// ICollection<T>
@@ -513,10 +714,7 @@ namespace Godot.Collections
/// This is also known as the size or length of the array.
/// </summary>
/// <returns>The number of elements.</returns>
- public int Count
- {
- get { return _objectArray.Count; }
- }
+ public int Count => _underlyingArray.Count;
bool ICollection<T>.IsReadOnly => false;
@@ -526,9 +724,11 @@ namespace Godot.Collections
/// </summary>
/// <param name="item">The item to add.</param>
/// <returns>The new size after adding the item.</returns>
- public void Add(T item)
+ public unsafe void Add(T item)
{
- _objectArray.Add(item);
+ using var variantValue = _convertToVariantCallback(item);
+ var self = (godot_array)_underlyingArray.NativeValue;
+ _ = NativeFuncs.godotsharp_array_add(ref self, variantValue);
}
/// <summary>
@@ -536,7 +736,7 @@ namespace Godot.Collections
/// </summary>
public void Clear()
{
- _objectArray.Clear();
+ _underlyingArray.Clear();
}
/// <summary>
@@ -544,10 +744,7 @@ namespace Godot.Collections
/// </summary>
/// <param name="item">The item to look for.</param>
/// <returns>Whether or not this array contains the given item.</returns>
- public bool Contains(T item)
- {
- return _objectArray.Contains(item);
- }
+ public bool Contains(T item) => IndexOf(item) != -1;
/// <summary>
/// Copies the elements of this <see cref="Array{T}"/> to the given
@@ -561,19 +758,22 @@ namespace Godot.Collections
throw new ArgumentNullException(nameof(array), "Value cannot be null.");
if (arrayIndex < 0)
- throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension.");
-
- // TODO This may be quite slow because every element access is an internal call.
- // It could be moved entirely to an internal call if we find out how to do the cast there.
+ {
+ throw new ArgumentOutOfRangeException(nameof(arrayIndex),
+ "Number was less than the array's lower bound in the first dimension.");
+ }
- int count = _objectArray.Count;
+ int count = Count;
if (array.Length < (arrayIndex + count))
- throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
+ {
+ throw new ArgumentException(
+ "Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
+ }
for (int i = 0; i < count; i++)
{
- array[arrayIndex] = (T)this[i];
+ array[arrayIndex] = this[i];
arrayIndex++;
}
}
@@ -586,7 +786,14 @@ namespace Godot.Collections
/// <returns>A <see langword="bool"/> indicating success or failure.</returns>
public bool Remove(T item)
{
- return Array.godot_icall_Array_Remove(GetPtr(), item);
+ int index = IndexOf(item);
+ if (index >= 0)
+ {
+ RemoveAt(index);
+ return true;
+ }
+
+ return false;
}
// IEnumerable<T>
@@ -597,23 +804,26 @@ namespace Godot.Collections
/// <returns>An enumerator.</returns>
public IEnumerator<T> GetEnumerator()
{
- int count = _objectArray.Count;
+ int count = _underlyingArray.Count;
for (int i = 0; i < count; i++)
{
- yield return (T)this[i];
+ yield return this[i];
}
}
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
/// <summary>
/// Converts this <see cref="Array{T}"/> to a string.
/// </summary>
/// <returns>A string representation of this array.</returns>
- public override string ToString() => _objectArray.ToString();
+ public override string ToString() => _underlyingArray.ToString();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Array<T> from) => Variant.CreateFrom(from);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Array<T>(Variant from) => from.AsGodotArray<T>();
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs
index 2febf37f05..b7d633517a 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/AssemblyHasScriptsAttribute.cs
@@ -1,5 +1,7 @@
using System;
+#nullable enable
+
namespace Godot
{
/// <summary>
@@ -8,25 +10,28 @@ namespace Godot
[AttributeUsage(AttributeTargets.Assembly)]
public class AssemblyHasScriptsAttribute : Attribute
{
- private readonly bool requiresLookup;
- private readonly System.Type[] scriptTypes;
+ public bool RequiresLookup { get; }
+ public Type[]? ScriptTypes { get; }
/// <summary>
/// Constructs a new AssemblyHasScriptsAttribute instance.
/// </summary>
public AssemblyHasScriptsAttribute()
{
- requiresLookup = true;
+ RequiresLookup = true;
+ ScriptTypes = null;
}
/// <summary>
/// Constructs a new AssemblyHasScriptsAttribute instance.
/// </summary>
/// <param name="scriptTypes">The specified type(s) of scripts.</param>
- public AssemblyHasScriptsAttribute(System.Type[] scriptTypes)
+ public AssemblyHasScriptsAttribute(Type[] scriptTypes)
{
- requiresLookup = false;
- this.scriptTypes = scriptTypes;
+ RequiresLookup = false;
+ ScriptTypes = scriptTypes;
}
}
}
+
+#nullable restore
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs
deleted file mode 100644
index 0b00878e8c..0000000000
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/DisableGodotGeneratorsAttribute.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-
-namespace Godot
-{
- /// <summary>
- /// An attribute that disables Godot Generators.
- /// </summary>
- [AttributeUsage(AttributeTargets.Class)]
- public class DisableGodotGeneratorsAttribute : Attribute { }
-}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs
index 46eb128d37..3d204bdf9f 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportAttribute.cs
@@ -6,7 +6,7 @@ namespace Godot
/// An attribute used to export objects.
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
- public class ExportAttribute : Attribute
+ public sealed class ExportAttribute : Attribute
{
private PropertyHint hint;
private string hintString;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportCategoryAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportCategoryAttribute.cs
new file mode 100644
index 0000000000..101e56f8d3
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportCategoryAttribute.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace Godot
+{
+ /// <summary>
+ /// Define a new category for the following exported properties. This helps to organize properties in the Inspector dock.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+ public sealed class ExportCategoryAttribute : Attribute
+ {
+ private string name;
+
+ /// <summary>
+ /// Define a new category for the following exported properties.
+ /// </summary>
+ /// <param name="name">The name of the category.</param>
+ public ExportCategoryAttribute(string name)
+ {
+ this.name = name;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportGroupAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportGroupAttribute.cs
new file mode 100644
index 0000000000..3bd532cec1
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportGroupAttribute.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Godot
+{
+ /// <summary>
+ /// Define a new group for the following exported properties. This helps to organize properties in the Inspector dock.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+ public sealed class ExportGroupAttribute : Attribute
+ {
+ private string name;
+ private string prefix;
+
+ /// <summary>
+ /// Define a new group for the following exported properties.
+ /// </summary>
+ /// <param name="name">The name of the group.</param>
+ /// <param name="prefix">If provided, the group would make group to only consider properties that have this prefix.</param>
+ public ExportGroupAttribute(string name, string prefix = "")
+ {
+ this.name = name;
+ this.prefix = prefix;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportSubgroupAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportSubgroupAttribute.cs
new file mode 100644
index 0000000000..2ae6eb0b68
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ExportSubgroupAttribute.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Godot
+{
+ /// <summary>
+ /// Define a new subgroup for the following exported properties. This helps to organize properties in the Inspector dock.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
+ public sealed class ExportSubgroupAttribute : Attribute
+ {
+ private string name;
+ private string prefix;
+
+ /// <summary>
+ /// Define a new subgroup for the following exported properties. This helps to organize properties in the Inspector dock.
+ /// </summary>
+ /// <param name="name">The name of the subgroup.</param>
+ /// <param name="prefix">If provided, the subgroup would make group to only consider properties that have this prefix.</param>
+ public ExportSubgroupAttribute(string name, string prefix = "")
+ {
+ this.name = name;
+ this.prefix = prefix;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs
deleted file mode 100644
index 8d4ff0fdb7..0000000000
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/GodotMethodAttribute.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-
-namespace Godot
-{
- /// <summary>
- /// An attribute for a method.
- /// </summary>
- [AttributeUsage(AttributeTargets.Method)]
- internal class GodotMethodAttribute : Attribute
- {
- private string methodName;
-
- public string MethodName { get { return methodName; } }
-
- /// <summary>
- /// Constructs a new GodotMethodAttribute instance.
- /// </summary>
- /// <param name="methodName">The name of the method.</param>
- public GodotMethodAttribute(string methodName)
- {
- this.methodName = methodName;
- }
- }
-}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/MustBeVariantAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/MustBeVariantAttribute.cs
new file mode 100644
index 0000000000..23088378d1
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/MustBeVariantAttribute.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Godot
+{
+ /// <summary>
+ /// Attribute that restricts generic type parameters to be only types
+ /// that can be marshaled from/to a <see cref="Variant"/>.
+ /// </summary>
+ [AttributeUsage(AttributeTargets.GenericParameter)]
+ public class MustBeVariantAttribute : Attribute { }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs
index 3ebb6612de..2c8a53ae1c 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/ScriptPathAttribute.cs
@@ -8,7 +8,7 @@ namespace Godot
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class ScriptPathAttribute : Attribute
{
- private string path;
+ public string Path { get; }
/// <summary>
/// Constructs a new ScriptPathAttribute instance.
@@ -16,7 +16,7 @@ namespace Godot
/// <param name="path">The file path to the script</param>
public ScriptPathAttribute(string path)
{
- this.path = path;
+ Path = path;
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs
index 07a214f543..38e68a89d5 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/SignalAttribute.cs
@@ -2,6 +2,6 @@ using System;
namespace Godot
{
- [AttributeUsage(AttributeTargets.Delegate | AttributeTargets.Event)]
+ [AttributeUsage(AttributeTargets.Delegate)]
public class SignalAttribute : Attribute { }
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
index 37bdc42c2d..fbd59d649f 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
@@ -1,8 +1,3 @@
-#if REAL_T_IS_DOUBLE
-using real_t = System.Double;
-#else
-using real_t = System.Single;
-#endif
using System;
using System.Runtime.InteropServices;
@@ -153,6 +148,9 @@ namespace Godot
/// Access whole columns in the form of <see cref="Vector3"/>.
/// </summary>
/// <param name="column">Which column vector.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="column"/> is not 0, 1, 2 or 3.
+ /// </exception>
/// <value>The basis column.</value>
public Vector3 this[int column]
{
@@ -167,7 +165,7 @@ namespace Godot
case 2:
return Column2;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(column));
}
}
set
@@ -184,7 +182,7 @@ namespace Godot
Column2 = value;
return;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(column));
}
}
}
@@ -371,8 +369,8 @@ namespace Godot
/// but are more efficient for some internal calculations.
/// </summary>
/// <param name="index">Which row.</param>
- /// <exception cref="IndexOutOfRangeException">
- /// Thrown when the <paramref name="index"/> is not 0, 1 or 2.
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is not 0, 1 or 2.
/// </exception>
/// <returns>One of <c>Row0</c>, <c>Row1</c>, or <c>Row2</c>.</returns>
public Vector3 GetRow(int index)
@@ -386,7 +384,7 @@ namespace Godot
case 2:
return Row2;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
@@ -396,8 +394,8 @@ namespace Godot
/// </summary>
/// <param name="index">Which row.</param>
/// <param name="value">The vector to set the row to.</param>
- /// <exception cref="IndexOutOfRangeException">
- /// Thrown when the <paramref name="index"/> is not 0, 1 or 2.
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is not 0, 1 or 2.
/// </exception>
public void SetRow(int index, Vector3 value)
{
@@ -413,7 +411,7 @@ namespace Godot
Row2 = value;
return;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
@@ -503,6 +501,15 @@ namespace Godot
);
}
+ internal Basis Lerp(Basis to, real_t weight)
+ {
+ Basis b = this;
+ b.Row0 = Row0.Lerp(to.Row0, weight);
+ b.Row1 = Row1.Lerp(to.Row1, weight);
+ b.Row2 = Row2.Lerp(to.Row2, weight);
+ return b;
+ }
+
/// <summary>
/// Returns the orthonormalized version of the basis matrix (useful to
/// call occasionally to avoid rounding errors for orthogonal matrices).
@@ -531,9 +538,9 @@ namespace Godot
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
/// <param name="angle">The angle to rotate, in radians.</param>
/// <returns>The rotated basis matrix.</returns>
- public Basis Rotated(Vector3 axis, real_t phi)
+ public Basis Rotated(Vector3 axis, real_t angle)
{
- return new Basis(axis, phi) * this;
+ return new Basis(axis, angle) * this;
}
/// <summary>
@@ -623,41 +630,6 @@ namespace Godot
return tr;
}
- /// <summary>
- /// Returns a vector transformed (multiplied) by the basis matrix.
- /// </summary>
- /// <seealso cref="XformInv(Vector3)"/>
- /// <param name="v">A vector to transform.</param>
- /// <returns>The transformed vector.</returns>
- public Vector3 Xform(Vector3 v)
- {
- return new Vector3
- (
- Row0.Dot(v),
- Row1.Dot(v),
- Row2.Dot(v)
- );
- }
-
- /// <summary>
- /// Returns a vector transformed (multiplied) by the transposed basis matrix.
- ///
- /// Note: This results in a multiplication by the inverse of the
- /// basis matrix only if it represents a rotation-reflection.
- /// </summary>
- /// <seealso cref="Xform(Vector3)"/>
- /// <param name="v">A vector to inversely transform.</param>
- /// <returns>The inversely transformed vector.</returns>
- public Vector3 XformInv(Vector3 v)
- {
- return new Vector3
- (
- Row0[0] * v.x + Row1[0] * v.y + Row2[0] * v.z,
- Row0[1] * v.x + Row1[1] * v.y + Row2[1] * v.z,
- Row0[2] * v.x + Row1[2] * v.y + Row2[2] * v.z
- );
- }
-
private static readonly Basis[] _orthoBases = {
new Basis(1f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 1f),
new Basis(0f, -1f, 0f, 1f, 0f, 0f, 0f, 0f, 1f),
@@ -774,15 +746,15 @@ namespace Godot
/// </summary>
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
/// <param name="angle">The angle to rotate, in radians.</param>
- public Basis(Vector3 axis, real_t phi)
+ public Basis(Vector3 axis, real_t angle)
{
Vector3 axisSq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z);
- real_t cosine = Mathf.Cos(phi);
+ real_t cosine = Mathf.Cos(angle);
Row0.x = axisSq.x + cosine * (1.0f - axisSq.x);
Row1.y = axisSq.y + cosine * (1.0f - axisSq.y);
Row2.z = axisSq.z + cosine * (1.0f - axisSq.z);
- real_t sine = Mathf.Sin(phi);
+ real_t sine = Mathf.Sin(angle);
real_t t = 1.0f - cosine;
real_t xyzt = axis.x * axis.y * t;
@@ -828,6 +800,22 @@ namespace Godot
}
/// <summary>
+ /// Constructs a pure scale basis matrix with no rotation or shearing.
+ /// The scale values are set as the main diagonal of the matrix,
+ /// and all of the other parts of the matrix are zero.
+ /// </summary>
+ /// <param name="scale">The scale Vector3.</param>
+ /// <returns>A pure scale Basis matrix.</returns>
+ public static Basis FromScale(Vector3 scale)
+ {
+ return new Basis(
+ scale.x, 0, 0,
+ 0, scale.y, 0,
+ 0, 0, scale.z
+ );
+ }
+
+ /// <summary>
/// Composes these two basis matrices by multiplying them
/// together. This has the effect of transforming the second basis
/// (the child) by the first basis (the parent).
@@ -846,6 +834,41 @@ namespace Godot
}
/// <summary>
+ /// Returns a Vector3 transformed (multiplied) by the basis matrix.
+ /// </summary>
+ /// <param name="basis">The basis matrix transformation to apply.</param>
+ /// <param name="vector">A Vector3 to transform.</param>
+ /// <returns>The transformed Vector3.</returns>
+ public static Vector3 operator *(Basis basis, Vector3 vector)
+ {
+ return new Vector3
+ (
+ basis.Row0.Dot(vector),
+ basis.Row1.Dot(vector),
+ basis.Row2.Dot(vector)
+ );
+ }
+
+ /// <summary>
+ /// Returns a Vector3 transformed (multiplied) by the transposed basis matrix.
+ ///
+ /// Note: This results in a multiplication by the inverse of the
+ /// basis matrix only if it represents a rotation-reflection.
+ /// </summary>
+ /// <param name="vector">A Vector3 to inversely transform.</param>
+ /// <param name="basis">The basis matrix transformation to apply.</param>
+ /// <returns>The inversely transformed vector.</returns>
+ public static Vector3 operator *(Vector3 vector, Basis basis)
+ {
+ return new Vector3
+ (
+ basis.Row0[0] * vector.x + basis.Row1[0] * vector.y + basis.Row2[0] * vector.z,
+ basis.Row0[1] * vector.x + basis.Row1[1] * vector.y + basis.Row2[1] * vector.z,
+ basis.Row0[2] * vector.x + basis.Row1[2] * vector.y + basis.Row2[2] * vector.z
+ );
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if the basis matrices are exactly
/// equal. Note: Due to floating-point precision errors, consider using
/// <see cref="IsEqualApprox"/> instead, which is more reliable.
@@ -881,12 +904,7 @@ namespace Godot
/// <returns>Whether or not the basis matrix and the object are exactly equal.</returns>
public override bool Equals(object obj)
{
- if (obj is Basis)
- {
- return Equals((Basis)obj);
- }
-
- return false;
+ return obj is Basis other && Equals(other);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/AlcReloadCfg.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/AlcReloadCfg.cs
new file mode 100644
index 0000000000..ac2e2fae3c
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/AlcReloadCfg.cs
@@ -0,0 +1,18 @@
+namespace Godot.Bridge;
+
+public static class AlcReloadCfg
+{
+ private static bool _configured = false;
+
+ public static void Configure(bool alcReloadEnabled)
+ {
+ if (_configured)
+ return;
+
+ _configured = true;
+
+ IsAlcReloadingEnabled = alcReloadEnabled;
+ }
+
+ internal static bool IsAlcReloadingEnabled = false;
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs
new file mode 100644
index 0000000000..ae44f8f4ba
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/CSharpInstanceBridge.cs
@@ -0,0 +1,253 @@
+using System;
+using System.Runtime.InteropServices;
+using Godot.NativeInterop;
+
+namespace Godot.Bridge
+{
+ internal static class CSharpInstanceBridge
+ {
+ [UnmanagedCallersOnly]
+ internal static unsafe godot_bool Call(IntPtr godotObjectGCHandle, godot_string_name* method,
+ godot_variant** args, int argCount, godot_variant_call_error* refCallError, godot_variant* ret)
+ {
+ try
+ {
+ var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+
+ if (godotObject == null)
+ {
+ *ret = default;
+ (*refCallError).Error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INSTANCE_IS_NULL;
+ return godot_bool.False;
+ }
+
+ bool methodInvoked = godotObject.InvokeGodotClassMethod(CustomUnsafe.AsRef(method),
+ new NativeVariantPtrArgs(args),
+ argCount, out godot_variant retValue);
+
+ if (!methodInvoked)
+ {
+ *ret = default;
+ // This is important, as it tells Object::call that no method was called.
+ // Otherwise, it would prevent Object::call from calling native methods.
+ (*refCallError).Error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD;
+ return godot_bool.False;
+ }
+
+ *ret = retValue;
+ return godot_bool.True;
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ *ret = default;
+ return godot_bool.False;
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe godot_bool Set(IntPtr godotObjectGCHandle, godot_string_name* name, godot_variant* value)
+ {
+ try
+ {
+ var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+
+ if (godotObject == null)
+ throw new InvalidOperationException();
+
+ if (godotObject.SetGodotClassPropertyValue(CustomUnsafe.AsRef(name), CustomUnsafe.AsRef(value)))
+ {
+ return godot_bool.True;
+ }
+
+ var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(name)));
+
+ Variant valueManaged = Variant.CreateCopyingBorrowed(*value);
+
+ return godotObject._Set(nameManaged, valueManaged).ToGodotBool();
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ return godot_bool.False;
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe godot_bool Get(IntPtr godotObjectGCHandle, godot_string_name* name,
+ godot_variant* outRet)
+ {
+ try
+ {
+ var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+
+ if (godotObject == null)
+ throw new InvalidOperationException();
+
+ if (godotObject.GetGodotClassPropertyValue(CustomUnsafe.AsRef(name), out godot_variant outRetValue))
+ {
+ *outRet = outRetValue;
+ return godot_bool.True;
+ }
+
+ var nameManaged = StringName.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(name)));
+
+ Variant ret = godotObject._Get(nameManaged);
+
+ if (ret.VariantType == Variant.Type.Nil)
+ {
+ *outRet = default;
+ return godot_bool.False;
+ }
+
+ *outRet = Marshaling.ConvertManagedObjectToVariant(ret);
+ return godot_bool.True;
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ *outRet = default;
+ return godot_bool.False;
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static void CallDispose(IntPtr godotObjectGCHandle, godot_bool okIfNull)
+ {
+ try
+ {
+ var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+
+ if (okIfNull.ToBool())
+ godotObject?.Dispose();
+ else
+ godotObject!.Dispose();
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe void CallToString(IntPtr godotObjectGCHandle, godot_string* outRes, godot_bool* outValid)
+ {
+ try
+ {
+ var self = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+
+ if (self == null)
+ {
+ *outRes = default;
+ *outValid = godot_bool.False;
+ return;
+ }
+
+ var resultStr = self.ToString();
+
+ if (resultStr == null)
+ {
+ *outRes = default;
+ *outValid = godot_bool.False;
+ return;
+ }
+
+ *outRes = Marshaling.ConvertStringToNative(resultStr);
+ *outValid = godot_bool.True;
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ *outRes = default;
+ *outValid = godot_bool.False;
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe godot_bool HasMethodUnknownParams(IntPtr godotObjectGCHandle, godot_string_name* method)
+ {
+ try
+ {
+ var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+
+ if (godotObject == null)
+ return godot_bool.False;
+
+ return godotObject.HasGodotClassMethod(CustomUnsafe.AsRef(method)).ToGodotBool();
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ return godot_bool.False;
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe void SerializeState(
+ IntPtr godotObjectGCHandle,
+ godot_dictionary* propertiesState,
+ godot_dictionary* signalEventsState
+ )
+ {
+ try
+ {
+ var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+
+ if (godotObject == null)
+ return;
+
+ // Call OnBeforeSerialize
+
+ // ReSharper disable once SuspiciousTypeConversion.Global
+ if (godotObject is ISerializationListener serializationListener)
+ serializationListener.OnBeforeSerialize();
+
+ // Save instance state
+
+ using var info = GodotSerializationInfo.CreateCopyingBorrowed(
+ *propertiesState, *signalEventsState);
+
+ godotObject.SaveGodotObjectData(info);
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe void DeserializeState(
+ IntPtr godotObjectGCHandle,
+ godot_dictionary* propertiesState,
+ godot_dictionary* signalEventsState
+ )
+ {
+ try
+ {
+ var godotObject = (Object)GCHandle.FromIntPtr(godotObjectGCHandle).Target;
+
+ if (godotObject == null)
+ return;
+
+ // Restore instance state
+
+ using var info = GodotSerializationInfo.CreateCopyingBorrowed(
+ *propertiesState, *signalEventsState);
+
+ godotObject.RestoreGodotObjectData(info);
+
+ // Call OnAfterDeserialize
+
+ // ReSharper disable once SuspiciousTypeConversion.Global
+ if (godotObject is ISerializationListener serializationListener)
+ serializationListener.OnAfterDeserialize();
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ }
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GCHandleBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GCHandleBridge.cs
new file mode 100644
index 0000000000..456a118b90
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GCHandleBridge.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Runtime.InteropServices;
+using Godot.NativeInterop;
+
+namespace Godot.Bridge
+{
+ internal static class GCHandleBridge
+ {
+ [UnmanagedCallersOnly]
+ internal static void FreeGCHandle(IntPtr gcHandlePtr)
+ {
+ try
+ {
+ CustomGCHandle.Free(GCHandle.FromIntPtr(gcHandlePtr));
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ }
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GodotSerializationInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GodotSerializationInfo.cs
new file mode 100644
index 0000000000..6d20f95007
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/GodotSerializationInfo.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using Godot.NativeInterop;
+
+namespace Godot.Bridge;
+
+public sealed class GodotSerializationInfo : IDisposable
+{
+ private readonly Collections.Dictionary _properties;
+ private readonly Collections.Dictionary _signalEvents;
+
+ public void Dispose()
+ {
+ _properties?.Dispose();
+ _signalEvents?.Dispose();
+
+ GC.SuppressFinalize(this);
+ }
+
+ private GodotSerializationInfo(in godot_dictionary properties, in godot_dictionary signalEvents)
+ {
+ _properties = Collections.Dictionary.CreateTakingOwnershipOfDisposableValue(properties);
+ _signalEvents = Collections.Dictionary.CreateTakingOwnershipOfDisposableValue(signalEvents);
+ }
+
+ internal static GodotSerializationInfo CreateCopyingBorrowed(
+ in godot_dictionary properties, in godot_dictionary signalEvents)
+ {
+ return new(NativeFuncs.godotsharp_dictionary_new_copy(properties),
+ NativeFuncs.godotsharp_dictionary_new_copy(signalEvents));
+ }
+
+ public void AddProperty(StringName name, Variant value)
+ {
+ _properties[name] = value;
+ }
+
+ public bool TryGetProperty(StringName name, out Variant value)
+ {
+ return _properties.TryGetValue(name, out value);
+ }
+
+ public void AddSignalEventDelegate(StringName name, Delegate eventDelegate)
+ {
+ var serializedData = new Collections.Array();
+
+ if (DelegateUtils.TrySerializeDelegate(eventDelegate, serializedData))
+ {
+ _signalEvents[name] = serializedData;
+ }
+ else if (OS.IsStdoutVerbose())
+ {
+ Console.WriteLine($"Failed to serialize event signal delegate: {name}");
+ }
+ }
+
+ public bool TryGetSignalEventDelegate<T>(StringName name, [MaybeNullWhen(false)] out T value)
+ where T : Delegate
+ {
+ if (_signalEvents.TryGetValue(name, out Variant serializedData))
+ {
+ if (DelegateUtils.TryDeserializeDelegate(serializedData.AsGodotArray(), out var eventDelegate))
+ {
+ value = eventDelegate as T;
+
+ if (value == null)
+ {
+ Console.WriteLine($"Cannot cast the deserialized event signal delegate: {name}. " +
+ $"Expected '{typeof(T).FullName}'; got '{eventDelegate.GetType().FullName}'.");
+ return false;
+ }
+
+ return true;
+ }
+ else if (OS.IsStdoutVerbose())
+ {
+ Console.WriteLine($"Failed to deserialize event signal delegate: {name}");
+ }
+
+ value = null;
+ return false;
+ }
+
+ value = null;
+ return false;
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
new file mode 100644
index 0000000000..57240624bc
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Runtime.InteropServices;
+using Godot.NativeInterop;
+
+namespace Godot.Bridge
+{
+ [StructLayout(LayoutKind.Sequential)]
+ public unsafe struct ManagedCallbacks
+ {
+ // @formatter:off
+ public delegate* unmanaged<IntPtr, godot_variant**, int, godot_bool*, void> SignalAwaiter_SignalCallback;
+ public delegate* unmanaged<IntPtr, godot_variant**, uint, godot_variant*, void> DelegateUtils_InvokeWithVariantArgs;
+ public delegate* unmanaged<IntPtr, IntPtr, godot_bool> DelegateUtils_DelegateEquals;
+ public delegate* unmanaged<IntPtr, godot_array*, godot_bool> DelegateUtils_TrySerializeDelegateWithGCHandle;
+ public delegate* unmanaged<godot_array*, IntPtr*, godot_bool> DelegateUtils_TryDeserializeDelegateWithGCHandle;
+ public delegate* unmanaged<void> ScriptManagerBridge_FrameCallback;
+ public delegate* unmanaged<godot_string_name*, IntPtr, IntPtr> ScriptManagerBridge_CreateManagedForGodotObjectBinding;
+ public delegate* unmanaged<IntPtr, IntPtr, godot_variant**, int, godot_bool> ScriptManagerBridge_CreateManagedForGodotObjectScriptInstance;
+ public delegate* unmanaged<IntPtr, godot_string_name*, void> ScriptManagerBridge_GetScriptNativeName;
+ public delegate* unmanaged<IntPtr, IntPtr, void> ScriptManagerBridge_SetGodotObjectPtr;
+ public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant**, int, godot_bool*, void> ScriptManagerBridge_RaiseEventSignal;
+ public delegate* unmanaged<IntPtr, IntPtr, godot_bool> ScriptManagerBridge_ScriptIsOrInherits;
+ public delegate* unmanaged<IntPtr, godot_string*, godot_bool> ScriptManagerBridge_AddScriptBridge;
+ public delegate* unmanaged<godot_string*, godot_ref*, void> ScriptManagerBridge_GetOrCreateScriptBridgeForPath;
+ public delegate* unmanaged<IntPtr, void> ScriptManagerBridge_RemoveScriptBridge;
+ public delegate* unmanaged<IntPtr, godot_bool> ScriptManagerBridge_TryReloadRegisteredScriptWithClass;
+ public delegate* unmanaged<IntPtr, godot_bool*, godot_array*, godot_dictionary*, godot_dictionary*, godot_ref*, void> ScriptManagerBridge_UpdateScriptClassInfo;
+ public delegate* unmanaged<IntPtr, IntPtr*, godot_bool, godot_bool> ScriptManagerBridge_SwapGCHandleForType;
+ public delegate* unmanaged<IntPtr, delegate* unmanaged<IntPtr, godot_string*, void*, int, void>, void> ScriptManagerBridge_GetPropertyInfoList;
+ public delegate* unmanaged<IntPtr, delegate* unmanaged<IntPtr, void*, int, void>, void> ScriptManagerBridge_GetPropertyDefaultValues;
+ public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant**, int, godot_variant_call_error*, godot_variant*, godot_bool> CSharpInstanceBridge_Call;
+ public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant*, godot_bool> CSharpInstanceBridge_Set;
+ public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant*, godot_bool> CSharpInstanceBridge_Get;
+ public delegate* unmanaged<IntPtr, godot_bool, void> CSharpInstanceBridge_CallDispose;
+ public delegate* unmanaged<IntPtr, godot_string*, godot_bool*, void> CSharpInstanceBridge_CallToString;
+ public delegate* unmanaged<IntPtr, godot_string_name*, godot_bool> CSharpInstanceBridge_HasMethodUnknownParams;
+ public delegate* unmanaged<IntPtr, godot_dictionary*, godot_dictionary*, void> CSharpInstanceBridge_SerializeState;
+ public delegate* unmanaged<IntPtr, godot_dictionary*, godot_dictionary*, void> CSharpInstanceBridge_DeserializeState;
+ public delegate* unmanaged<IntPtr, void> GCHandleBridge_FreeGCHandle;
+ public delegate* unmanaged<void*, void> DebuggingUtils_GetCurrentStackInfo;
+ public delegate* unmanaged<void> DisposablesTracker_OnGodotShuttingDown;
+ public delegate* unmanaged<godot_bool, void> GD_OnCoreApiAssemblyLoaded;
+ // @formatter:on
+
+ public static ManagedCallbacks Create()
+ {
+ return new()
+ {
+ // @formatter:off
+ SignalAwaiter_SignalCallback = &SignalAwaiter.SignalCallback,
+ DelegateUtils_InvokeWithVariantArgs = &DelegateUtils.InvokeWithVariantArgs,
+ DelegateUtils_DelegateEquals = &DelegateUtils.DelegateEquals,
+ DelegateUtils_TrySerializeDelegateWithGCHandle = &DelegateUtils.TrySerializeDelegateWithGCHandle,
+ DelegateUtils_TryDeserializeDelegateWithGCHandle = &DelegateUtils.TryDeserializeDelegateWithGCHandle,
+ ScriptManagerBridge_FrameCallback = &ScriptManagerBridge.FrameCallback,
+ ScriptManagerBridge_CreateManagedForGodotObjectBinding = &ScriptManagerBridge.CreateManagedForGodotObjectBinding,
+ ScriptManagerBridge_CreateManagedForGodotObjectScriptInstance = &ScriptManagerBridge.CreateManagedForGodotObjectScriptInstance,
+ ScriptManagerBridge_GetScriptNativeName = &ScriptManagerBridge.GetScriptNativeName,
+ ScriptManagerBridge_SetGodotObjectPtr = &ScriptManagerBridge.SetGodotObjectPtr,
+ ScriptManagerBridge_RaiseEventSignal = &ScriptManagerBridge.RaiseEventSignal,
+ ScriptManagerBridge_ScriptIsOrInherits = &ScriptManagerBridge.ScriptIsOrInherits,
+ ScriptManagerBridge_AddScriptBridge = &ScriptManagerBridge.AddScriptBridge,
+ ScriptManagerBridge_GetOrCreateScriptBridgeForPath = &ScriptManagerBridge.GetOrCreateScriptBridgeForPath,
+ ScriptManagerBridge_RemoveScriptBridge = &ScriptManagerBridge.RemoveScriptBridge,
+ ScriptManagerBridge_TryReloadRegisteredScriptWithClass = &ScriptManagerBridge.TryReloadRegisteredScriptWithClass,
+ ScriptManagerBridge_UpdateScriptClassInfo = &ScriptManagerBridge.UpdateScriptClassInfo,
+ ScriptManagerBridge_SwapGCHandleForType = &ScriptManagerBridge.SwapGCHandleForType,
+ ScriptManagerBridge_GetPropertyInfoList = &ScriptManagerBridge.GetPropertyInfoList,
+ ScriptManagerBridge_GetPropertyDefaultValues = &ScriptManagerBridge.GetPropertyDefaultValues,
+ CSharpInstanceBridge_Call = &CSharpInstanceBridge.Call,
+ CSharpInstanceBridge_Set = &CSharpInstanceBridge.Set,
+ CSharpInstanceBridge_Get = &CSharpInstanceBridge.Get,
+ CSharpInstanceBridge_CallDispose = &CSharpInstanceBridge.CallDispose,
+ CSharpInstanceBridge_CallToString = &CSharpInstanceBridge.CallToString,
+ CSharpInstanceBridge_HasMethodUnknownParams = &CSharpInstanceBridge.HasMethodUnknownParams,
+ CSharpInstanceBridge_SerializeState = &CSharpInstanceBridge.SerializeState,
+ CSharpInstanceBridge_DeserializeState = &CSharpInstanceBridge.DeserializeState,
+ GCHandleBridge_FreeGCHandle = &GCHandleBridge.FreeGCHandle,
+ DebuggingUtils_GetCurrentStackInfo = &DebuggingUtils.GetCurrentStackInfo,
+ DisposablesTracker_OnGodotShuttingDown = &DisposablesTracker.OnGodotShuttingDown,
+ GD_OnCoreApiAssemblyLoaded = &GD.OnCoreApiAssemblyLoaded,
+ // @formatter:on
+ };
+ }
+
+ public static void Create(IntPtr outManagedCallbacks)
+ => *(ManagedCallbacks*)outManagedCallbacks = Create();
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/MethodInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/MethodInfo.cs
new file mode 100644
index 0000000000..647ae436ff
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/MethodInfo.cs
@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+
+namespace Godot.Bridge;
+
+#nullable enable
+
+public struct MethodInfo
+{
+ public StringName Name { get; init; }
+ public PropertyInfo ReturnVal { get; init; }
+ public MethodFlags Flags { get; init; }
+ public int Id { get; init; } = 0;
+ public List<PropertyInfo>? Arguments { get; init; }
+ public List<Variant>? DefaultArguments { get; init; }
+
+ public MethodInfo(StringName name, PropertyInfo returnVal, MethodFlags flags,
+ List<PropertyInfo>? arguments, List<Variant>? defaultArguments)
+ {
+ Name = name;
+ ReturnVal = returnVal;
+ Flags = flags;
+ Arguments = arguments;
+ DefaultArguments = defaultArguments;
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs
new file mode 100644
index 0000000000..80d6f7b4a5
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/PropertyInfo.cs
@@ -0,0 +1,24 @@
+namespace Godot.Bridge;
+
+#nullable enable
+
+public struct PropertyInfo
+{
+ public Variant.Type Type { get; init; }
+ public StringName Name { get; init; }
+ public PropertyHint Hint { get; init; }
+ public string HintString { get; init; }
+ public PropertyUsageFlags Usage { get; init; }
+ public bool Exported { get; init; }
+
+ public PropertyInfo(Variant.Type type, StringName name, PropertyHint hint, string hintString,
+ PropertyUsageFlags usage, bool exported)
+ {
+ Type = type;
+ Name = name;
+ Hint = hint;
+ HintString = hintString;
+ Usage = usage;
+ Exported = exported;
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
new file mode 100644
index 0000000000..3884781988
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
@@ -0,0 +1,1028 @@
+#nullable enable
+
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Loader;
+using System.Runtime.Serialization;
+using Godot.NativeInterop;
+
+namespace Godot.Bridge
+{
+ // TODO: Make class internal once we replace LookupScriptsInAssembly (the only public member) with source generators
+ public static partial class ScriptManagerBridge
+ {
+ private static ConcurrentDictionary<AssemblyLoadContext, ConcurrentDictionary<Type, byte>>
+ _alcData = new();
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void OnAlcUnloading(AssemblyLoadContext alc)
+ {
+ if (_alcData.TryRemove(alc, out var typesInAlc))
+ {
+ foreach (var type in typesInAlc.Keys)
+ {
+ if (_scriptTypeBiMap.RemoveByScriptType(type, out IntPtr scriptPtr) &&
+ !_pathTypeBiMap.TryGetScriptPath(type, out _))
+ {
+ // For scripts without a path, we need to keep the class qualified name for reloading
+ _scriptDataForReload.TryAdd(scriptPtr,
+ (type.Assembly.GetName().Name, type.FullName ?? type.ToString()));
+ }
+
+ _pathTypeBiMap.RemoveByScriptType(type);
+ }
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void AddTypeForAlcReloading(Type type)
+ {
+ var alc = AssemblyLoadContext.GetLoadContext(type.Assembly);
+ if (alc == null)
+ return;
+
+ var typesInAlc = _alcData.GetOrAdd(alc,
+ static alc =>
+ {
+ alc.Unloading += OnAlcUnloading;
+ return new();
+ });
+ typesInAlc.TryAdd(type, 0);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void TrackAlcForUnloading(AssemblyLoadContext alc)
+ {
+ _ = _alcData.GetOrAdd(alc,
+ static alc =>
+ {
+ alc.Unloading += OnAlcUnloading;
+ return new();
+ });
+ }
+
+ private static ScriptTypeBiMap _scriptTypeBiMap = new();
+ private static PathScriptTypeBiMap _pathTypeBiMap = new();
+
+ private static ConcurrentDictionary<IntPtr, (string? assemblyName, string classFullName)>
+ _scriptDataForReload = new();
+
+ [UnmanagedCallersOnly]
+ internal static void FrameCallback()
+ {
+ try
+ {
+ Dispatcher.DefaultGodotTaskScheduler?.Activate();
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe IntPtr CreateManagedForGodotObjectBinding(godot_string_name* nativeTypeName,
+ IntPtr godotObject)
+ {
+ // TODO: Optimize with source generators and delegate pointers
+
+ try
+ {
+ using var stringName = StringName.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_string_name_new_copy(CustomUnsafe.AsRef(nativeTypeName)));
+ string nativeTypeNameStr = stringName.ToString();
+
+ Type nativeType = TypeGetProxyClass(nativeTypeNameStr) ?? throw new InvalidOperationException(
+ "Wrapper class not found for type: " + nativeTypeNameStr);
+ var obj = (Object)FormatterServices.GetUninitializedObject(nativeType);
+
+ var ctor = nativeType.GetConstructor(
+ BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
+ null, Type.EmptyTypes, null);
+
+ obj.NativePtr = godotObject;
+
+ _ = ctor!.Invoke(obj, null);
+
+ return GCHandle.ToIntPtr(CustomGCHandle.AllocStrong(obj));
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ return IntPtr.Zero;
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe godot_bool CreateManagedForGodotObjectScriptInstance(IntPtr scriptPtr,
+ IntPtr godotObject,
+ godot_variant** args, int argCount)
+ {
+ // TODO: Optimize with source generators and delegate pointers
+
+ try
+ {
+ // Performance is not critical here as this will be replaced with source generators.
+ Type scriptType = _scriptTypeBiMap.GetScriptType(scriptPtr);
+ var obj = (Object)FormatterServices.GetUninitializedObject(scriptType);
+
+ var ctor = scriptType
+ .GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
+ .Where(c => c.GetParameters().Length == argCount)
+ .FirstOrDefault();
+
+ if (ctor == null)
+ {
+ if (argCount == 0)
+ {
+ throw new MissingMemberException(
+ $"Cannot create script instance. The class '{scriptType.FullName}' does not define a parameterless constructor.");
+ }
+ else
+ {
+ throw new MissingMemberException(
+ $"The class '{scriptType.FullName}' does not define a constructor that takes x parameters.");
+ }
+ }
+
+ var parameters = ctor.GetParameters();
+ int paramCount = parameters.Length;
+
+ var invokeParams = new object?[paramCount];
+
+ for (int i = 0; i < paramCount; i++)
+ {
+ invokeParams[i] = Marshaling.ConvertVariantToManagedObjectOfType(
+ *args[i], parameters[i].ParameterType);
+ }
+
+ obj.NativePtr = godotObject;
+
+ _ = ctor.Invoke(obj, invokeParams);
+
+
+ return godot_bool.True;
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ return godot_bool.False;
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe void GetScriptNativeName(IntPtr scriptPtr, godot_string_name* outRes)
+ {
+ try
+ {
+ // Performance is not critical here as this will be replaced with source generators.
+ if (!_scriptTypeBiMap.TryGetScriptType(scriptPtr, out Type? scriptType))
+ {
+ *outRes = default;
+ return;
+ }
+
+ var native = Object.InternalGetClassNativeBase(scriptType);
+
+ var field = native?.GetField("NativeName", BindingFlags.DeclaredOnly | BindingFlags.Static |
+ BindingFlags.Public | BindingFlags.NonPublic);
+
+ if (field == null)
+ {
+ *outRes = default;
+ return;
+ }
+
+ var nativeName = (StringName?)field.GetValue(null);
+
+ if (nativeName == null)
+ {
+ *outRes = default;
+ return;
+ }
+
+ *outRes = NativeFuncs.godotsharp_string_name_new_copy((godot_string_name)nativeName.NativeValue);
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ *outRes = default;
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static void SetGodotObjectPtr(IntPtr gcHandlePtr, IntPtr newPtr)
+ {
+ try
+ {
+ var target = (Object?)GCHandle.FromIntPtr(gcHandlePtr).Target;
+ if (target != null)
+ target.NativePtr = newPtr;
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ }
+ }
+
+ private static Type? TypeGetProxyClass(string nativeTypeNameStr)
+ {
+ // Performance is not critical here as this will be replaced with a generated dictionary.
+
+ if (nativeTypeNameStr[0] == '_')
+ nativeTypeNameStr = nativeTypeNameStr.Substring(1);
+
+ Type? wrapperType = typeof(Object).Assembly.GetType("Godot." + nativeTypeNameStr);
+
+ if (wrapperType == null)
+ {
+ wrapperType = AppDomain.CurrentDomain.GetAssemblies()
+ .FirstOrDefault(a => a.GetName().Name == "GodotSharpEditor")?
+ .GetType("Godot." + nativeTypeNameStr);
+ }
+
+ static bool IsStatic(Type type) => type.IsAbstract && type.IsSealed;
+
+ if (wrapperType != null && IsStatic(wrapperType))
+ {
+ // A static class means this is a Godot singleton class. If an instance is needed we use Godot.Object.
+ return typeof(Object);
+ }
+
+ return wrapperType;
+ }
+
+ // Called from GodotPlugins
+ // ReSharper disable once UnusedMember.Local
+ public static void LookupScriptsInAssembly(Assembly assembly)
+ {
+ static void LookupScriptForClass(Type type)
+ {
+ var scriptPathAttr = type.GetCustomAttributes(inherit: false)
+ .OfType<ScriptPathAttribute>()
+ .FirstOrDefault();
+
+ if (scriptPathAttr == null)
+ return;
+
+ _pathTypeBiMap.Add(scriptPathAttr.Path, type);
+
+ if (AlcReloadCfg.IsAlcReloadingEnabled)
+ {
+ AddTypeForAlcReloading(type);
+ }
+ }
+
+ var assemblyHasScriptsAttr = assembly.GetCustomAttributes(inherit: false)
+ .OfType<AssemblyHasScriptsAttribute>()
+ .FirstOrDefault();
+
+ if (assemblyHasScriptsAttr == null)
+ return;
+
+ if (assemblyHasScriptsAttr.RequiresLookup)
+ {
+ // This is supported for scenarios where specifying all types would be cumbersome,
+ // such as when disabling C# source generators (for whatever reason) or when using a
+ // language other than C# that has nothing similar to source generators to automate it.
+
+ var typeOfGodotObject = typeof(Object);
+
+ foreach (var type in assembly.GetTypes())
+ {
+ if (type.IsNested)
+ continue;
+
+ if (!typeOfGodotObject.IsAssignableFrom(type))
+ continue;
+
+ LookupScriptForClass(type);
+ }
+ }
+ else
+ {
+ // This is the most likely scenario as we use C# source generators
+
+ var scriptTypes = assemblyHasScriptsAttr.ScriptTypes;
+
+ if (scriptTypes != null)
+ {
+ for (int i = 0; i < scriptTypes.Length; i++)
+ {
+ LookupScriptForClass(scriptTypes[i]);
+ }
+ }
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe void RaiseEventSignal(IntPtr ownerGCHandlePtr,
+ godot_string_name* eventSignalName, godot_variant** args, int argCount, godot_bool* outOwnerIsNull)
+ {
+ try
+ {
+ var owner = (Object?)GCHandle.FromIntPtr(ownerGCHandlePtr).Target;
+
+ if (owner == null)
+ {
+ *outOwnerIsNull = godot_bool.True;
+ return;
+ }
+
+ *outOwnerIsNull = godot_bool.False;
+
+ owner.RaiseGodotClassSignalCallbacks(CustomUnsafe.AsRef(eventSignalName),
+ new NativeVariantPtrArgs(args), argCount);
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ *outOwnerIsNull = godot_bool.False;
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static godot_bool ScriptIsOrInherits(IntPtr scriptPtr, IntPtr scriptPtrMaybeBase)
+ {
+ try
+ {
+ if (!_scriptTypeBiMap.TryGetScriptType(scriptPtr, out Type? scriptType))
+ return godot_bool.False;
+
+ if (!_scriptTypeBiMap.TryGetScriptType(scriptPtrMaybeBase, out Type? maybeBaseType))
+ return godot_bool.False;
+
+ return (scriptType == maybeBaseType || maybeBaseType.IsAssignableFrom(scriptType)).ToGodotBool();
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ return godot_bool.False;
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe godot_bool AddScriptBridge(IntPtr scriptPtr, godot_string* scriptPath)
+ {
+ try
+ {
+ lock (_scriptTypeBiMap.ReadWriteLock)
+ {
+ if (!_scriptTypeBiMap.IsScriptRegistered(scriptPtr))
+ {
+ string scriptPathStr = Marshaling.ConvertStringToManaged(*scriptPath);
+
+ if (!_pathTypeBiMap.TryGetScriptType(scriptPathStr, out Type? scriptType))
+ return godot_bool.False;
+
+ _scriptTypeBiMap.Add(scriptPtr, scriptType);
+ }
+ }
+
+ return godot_bool.True;
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ return godot_bool.False;
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe void GetOrCreateScriptBridgeForPath(godot_string* scriptPath, godot_ref* outScript)
+ {
+ string scriptPathStr = Marshaling.ConvertStringToManaged(*scriptPath);
+
+ if (!_pathTypeBiMap.TryGetScriptType(scriptPathStr, out Type? scriptType))
+ {
+ NativeFuncs.godotsharp_internal_new_csharp_script(outScript);
+ return;
+ }
+
+ GetOrCreateScriptBridgeForType(scriptType, outScript);
+ }
+
+ private static unsafe void GetOrCreateScriptBridgeForType(Type scriptType, godot_ref* outScript)
+ {
+ lock (_scriptTypeBiMap.ReadWriteLock)
+ {
+ if (_scriptTypeBiMap.TryGetScriptPtr(scriptType, out IntPtr scriptPtr))
+ {
+ // Use existing
+ NativeFuncs.godotsharp_ref_new_from_ref_counted_ptr(out *outScript, scriptPtr);
+ return;
+ }
+
+ // This path is slower, but it's only executed for the first instantiation of the type
+ CreateScriptBridgeForType(scriptType, outScript);
+ }
+ }
+
+ internal static unsafe void GetOrLoadOrCreateScriptForType(Type scriptType, godot_ref* outScript)
+ {
+ static bool GetPathOtherwiseGetOrCreateScript(Type scriptType, godot_ref* outScript,
+ [MaybeNullWhen(false)] out string scriptPath)
+ {
+ lock (_scriptTypeBiMap.ReadWriteLock)
+ {
+ if (_scriptTypeBiMap.TryGetScriptPtr(scriptType, out IntPtr scriptPtr))
+ {
+ // Use existing
+ NativeFuncs.godotsharp_ref_new_from_ref_counted_ptr(out *outScript, scriptPtr);
+ scriptPath = null;
+ return false;
+ }
+
+ // This path is slower, but it's only executed for the first instantiation of the type
+
+ if (_pathTypeBiMap.TryGetScriptPath(scriptType, out scriptPath))
+ return true;
+
+ CreateScriptBridgeForType(scriptType, outScript);
+ scriptPath = null;
+ return false;
+ }
+ }
+
+ if (GetPathOtherwiseGetOrCreateScript(scriptType, outScript, out string? scriptPath))
+ {
+ // This path is slower, but it's only executed for the first instantiation of the type
+
+ // This must be done outside the read-write lock, as the script resource loading can lock it
+ using godot_string scriptPathIn = Marshaling.ConvertStringToNative(scriptPath);
+ if (!NativeFuncs.godotsharp_internal_script_load(scriptPathIn, outScript).ToBool())
+ {
+ GD.PushError($"Cannot load script for type '{scriptType.FullName}'. Path: '{scriptPath}'.");
+
+ // If loading of the script fails, best we can do create a new script
+ // with no path, as we do for types without an associated script file.
+ GetOrCreateScriptBridgeForType(scriptType, outScript);
+ }
+ }
+ }
+
+ private static unsafe void CreateScriptBridgeForType(Type scriptType, godot_ref* outScript)
+ {
+ NativeFuncs.godotsharp_internal_new_csharp_script(outScript);
+ IntPtr scriptPtr = outScript->Reference;
+
+ // Caller takes care of locking
+ _scriptTypeBiMap.Add(scriptPtr, scriptType);
+
+ NativeFuncs.godotsharp_internal_reload_registered_script(scriptPtr);
+ }
+
+ [UnmanagedCallersOnly]
+ internal static void RemoveScriptBridge(IntPtr scriptPtr)
+ {
+ try
+ {
+ lock (_scriptTypeBiMap.ReadWriteLock)
+ {
+ _scriptTypeBiMap.Remove(scriptPtr);
+ }
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static godot_bool TryReloadRegisteredScriptWithClass(IntPtr scriptPtr)
+ {
+ try
+ {
+ lock (_scriptTypeBiMap.ReadWriteLock)
+ {
+ if (_scriptTypeBiMap.TryGetScriptType(scriptPtr, out _))
+ {
+ // NOTE:
+ // Currently, we reload all scripts, not only the ones from the unloaded ALC.
+ // As such, we need to handle this case instead of treating it as an error.
+ NativeFuncs.godotsharp_internal_reload_registered_script(scriptPtr);
+ return godot_bool.True;
+ }
+
+ if (!_scriptDataForReload.TryGetValue(scriptPtr, out var dataForReload))
+ {
+ GD.PushError("Missing class qualified name for reloading script");
+ return godot_bool.False;
+ }
+
+ _ = _scriptDataForReload.TryRemove(scriptPtr, out _);
+
+ if (dataForReload.assemblyName == null)
+ {
+ GD.PushError(
+ $"Missing assembly name of class '{dataForReload.classFullName}' for reloading script");
+ return godot_bool.False;
+ }
+
+ var scriptType = ReflectionUtils.FindTypeInLoadedAssemblies(dataForReload.assemblyName,
+ dataForReload.classFullName);
+
+ if (scriptType == null)
+ {
+ // The class was removed, can't reload
+ return godot_bool.False;
+ }
+
+ // ReSharper disable once RedundantNameQualifier
+ if (!typeof(Godot.Object).IsAssignableFrom(scriptType))
+ {
+ // The class no longer inherits Godot.Object, can't reload
+ return godot_bool.False;
+ }
+
+ _scriptTypeBiMap.Add(scriptPtr, scriptType);
+
+ NativeFuncs.godotsharp_internal_reload_registered_script(scriptPtr);
+
+ return godot_bool.True;
+ }
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ return godot_bool.False;
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe void UpdateScriptClassInfo(IntPtr scriptPtr, godot_bool* outTool,
+ godot_array* outMethodsDest, godot_dictionary* outRpcFunctionsDest,
+ godot_dictionary* outEventSignalsDest, godot_ref* outBaseScript)
+ {
+ try
+ {
+ // Performance is not critical here as this will be replaced with source generators.
+ var scriptType = _scriptTypeBiMap.GetScriptType(scriptPtr);
+
+ *outTool = scriptType.GetCustomAttributes(inherit: false)
+ .OfType<ToolAttribute>()
+ .Any().ToGodotBool();
+
+ if (!(*outTool).ToBool() && scriptType.IsNested)
+ {
+ *outTool = (scriptType.DeclaringType?.GetCustomAttributes(inherit: false)
+ .OfType<ToolAttribute>()
+ .Any() ?? false).ToGodotBool();
+ }
+
+ if (!(*outTool).ToBool() && scriptType.Assembly.GetName().Name == "GodotTools")
+ *outTool = godot_bool.True;
+
+ // Methods
+
+ // Performance is not critical here as this will be replaced with source generators.
+ using var methods = new Collections.Array();
+
+ Type? top = scriptType;
+ Type native = Object.InternalGetClassNativeBase(top);
+
+ while (top != null && top != native)
+ {
+ var methodList = GetMethodListForType(top);
+
+ if (methodList != null)
+ {
+ foreach (var method in methodList)
+ {
+ var methodInfo = new Collections.Dictionary();
+
+ methodInfo.Add("name", method.Name);
+
+ var methodParams = new Collections.Array();
+
+ if (method.Arguments != null)
+ {
+ foreach (var param in method.Arguments)
+ {
+ methodParams.Add(new Collections.Dictionary()
+ {
+ { "name", param.Name },
+ { "type", (int)param.Type },
+ { "usage", (int)param.Usage }
+ });
+ }
+ }
+
+ methodInfo.Add("params", methodParams);
+
+ methods.Add(methodInfo);
+ }
+ }
+
+ top = top.BaseType;
+ }
+
+ *outMethodsDest = NativeFuncs.godotsharp_array_new_copy(
+ (godot_array)methods.NativeValue);
+
+ // RPC functions
+
+ Collections.Dictionary rpcFunctions = new();
+
+ top = scriptType;
+
+ while (top != null && top != native)
+ {
+ foreach (var method in top.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance |
+ BindingFlags.NonPublic | BindingFlags.Public))
+ {
+ if (method.IsStatic)
+ continue;
+
+ string methodName = method.Name;
+
+ if (rpcFunctions.ContainsKey(methodName))
+ continue;
+
+ var rpcAttr = method.GetCustomAttributes(inherit: false)
+ .OfType<RPCAttribute>().FirstOrDefault();
+
+ if (rpcAttr == null)
+ continue;
+
+ var rpcConfig = new Collections.Dictionary();
+
+ rpcConfig["rpc_mode"] = (long)rpcAttr.Mode;
+ rpcConfig["call_local"] = rpcAttr.CallLocal;
+ rpcConfig["transfer_mode"] = (long)rpcAttr.TransferMode;
+ rpcConfig["channel"] = rpcAttr.TransferChannel;
+
+ rpcFunctions.Add(methodName, rpcConfig);
+ }
+
+ top = top.BaseType;
+ }
+
+ *outRpcFunctionsDest = NativeFuncs.godotsharp_dictionary_new_copy(
+ (godot_dictionary)(rpcFunctions).NativeValue);
+
+ // Event signals
+
+ // Performance is not critical here as this will be replaced with source generators.
+ using var signals = new Collections.Dictionary();
+
+ top = scriptType;
+
+ while (top != null && top != native)
+ {
+ var signalList = GetSignalListForType(top);
+
+ if (signalList != null)
+ {
+ foreach (var signal in signalList)
+ {
+ string signalName = signal.Name;
+
+ if (signals.ContainsKey(signalName))
+ continue;
+
+ var signalParams = new Collections.Array();
+
+ if (signal.Arguments != null)
+ {
+ foreach (var param in signal.Arguments)
+ {
+ signalParams.Add(new Collections.Dictionary()
+ {
+ { "name", param.Name },
+ { "type", (int)param.Type },
+ { "usage", (int)param.Usage }
+ });
+ }
+ }
+
+ signals.Add(signalName, signalParams);
+ }
+ }
+
+ top = top.BaseType;
+ }
+
+ *outEventSignalsDest = NativeFuncs.godotsharp_dictionary_new_copy(
+ (godot_dictionary)signals.NativeValue);
+
+ // Base script
+
+ var baseType = scriptType.BaseType;
+ if (baseType != null && baseType != native)
+ {
+ GetOrLoadOrCreateScriptForType(baseType, outBaseScript);
+ }
+ else
+ {
+ *outBaseScript = default;
+ }
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ *outTool = godot_bool.False;
+ *outRpcFunctionsDest = NativeFuncs.godotsharp_dictionary_new();
+ *outEventSignalsDest = NativeFuncs.godotsharp_dictionary_new();
+ *outBaseScript = default;
+ }
+ }
+
+ private static List<MethodInfo>? GetSignalListForType(Type type)
+ {
+ var getGodotSignalListMethod = type.GetMethod(
+ "GetGodotSignalList",
+ BindingFlags.DeclaredOnly | BindingFlags.Static |
+ BindingFlags.NonPublic | BindingFlags.Public);
+
+ if (getGodotSignalListMethod == null)
+ return null;
+
+ return (List<MethodInfo>?)getGodotSignalListMethod.Invoke(null, null);
+ }
+
+ private static List<MethodInfo>? GetMethodListForType(Type type)
+ {
+ var getGodotMethodListMethod = type.GetMethod(
+ "GetGodotMethodList",
+ BindingFlags.DeclaredOnly | BindingFlags.Static |
+ BindingFlags.NonPublic | BindingFlags.Public);
+
+ if (getGodotMethodListMethod == null)
+ return null;
+
+ return (List<MethodInfo>?)getGodotMethodListMethod.Invoke(null, null);
+ }
+
+ // ReSharper disable once InconsistentNaming
+ [SuppressMessage("ReSharper", "NotAccessedField.Local")]
+ [StructLayout(LayoutKind.Sequential)]
+ private ref struct godotsharp_property_info
+ {
+ // Careful with padding...
+ public godot_string_name Name; // Not owned
+ public godot_string HintString;
+ public int Type;
+ public int Hint;
+ public int Usage;
+ public godot_bool Exported;
+
+ public void Dispose()
+ {
+ HintString.Dispose();
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe void GetPropertyInfoList(IntPtr scriptPtr,
+ delegate* unmanaged<IntPtr, godot_string*, void*, int, void> addPropInfoFunc)
+ {
+ try
+ {
+ Type scriptType = _scriptTypeBiMap.GetScriptType(scriptPtr);
+ GetPropertyInfoListForType(scriptType, scriptPtr, addPropInfoFunc);
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ }
+ }
+
+ private static unsafe void GetPropertyInfoListForType(Type type, IntPtr scriptPtr,
+ delegate* unmanaged<IntPtr, godot_string*, void*, int, void> addPropInfoFunc)
+ {
+ try
+ {
+ var getGodotPropertyListMethod = type.GetMethod(
+ "GetGodotPropertyList",
+ BindingFlags.DeclaredOnly | BindingFlags.Static |
+ BindingFlags.NonPublic | BindingFlags.Public);
+
+ if (getGodotPropertyListMethod == null)
+ return;
+
+ var properties = (List<PropertyInfo>?)
+ getGodotPropertyListMethod.Invoke(null, null);
+
+ if (properties == null || properties.Count <= 0)
+ return;
+
+ int length = properties.Count;
+
+ // There's no recursion here, so it's ok to go with a big enough number for most cases
+ // stackMaxSize = stackMaxLength * sizeof(godotsharp_property_info)
+ const int stackMaxLength = 32;
+ bool useStack = length < stackMaxLength;
+
+ godotsharp_property_info* interopProperties;
+
+ if (useStack)
+ {
+ // Weird limitation, hence the need for aux:
+ // "In the case of pointer types, you can use a stackalloc expression only in a local variable declaration to initialize the variable."
+ var aux = stackalloc godotsharp_property_info[length];
+ interopProperties = aux;
+ }
+ else
+ {
+ interopProperties = ((godotsharp_property_info*)NativeMemory.Alloc((nuint)length, (nuint)sizeof(godotsharp_property_info)))!;
+ }
+
+ try
+ {
+ for (int i = 0; i < length; i++)
+ {
+ var property = properties[i];
+
+ godotsharp_property_info interopProperty = new()
+ {
+ Type = (int)property.Type,
+ Name = (godot_string_name)property.Name.NativeValue, // Not owned
+ Hint = (int)property.Hint,
+ HintString = Marshaling.ConvertStringToNative(property.HintString),
+ Usage = (int)property.Usage,
+ Exported = property.Exported.ToGodotBool()
+ };
+
+ interopProperties[i] = interopProperty;
+ }
+
+ using godot_string currentClassName = Marshaling.ConvertStringToNative(type.Name);
+
+ addPropInfoFunc(scriptPtr, &currentClassName, interopProperties, length);
+
+ // We're borrowing the StringName's without making an owning copy, so the
+ // managed collection needs to be kept alive until `addPropInfoFunc` returns.
+ GC.KeepAlive(properties);
+ }
+ finally
+ {
+ for (int i = 0; i < length; i++)
+ interopProperties[i].Dispose();
+
+ if (!useStack)
+ NativeMemory.Free(interopProperties);
+ }
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ }
+ }
+
+ // ReSharper disable once InconsistentNaming
+ [SuppressMessage("ReSharper", "NotAccessedField.Local")]
+ [StructLayout(LayoutKind.Sequential)]
+ private ref struct godotsharp_property_def_val_pair
+ {
+ // Careful with padding...
+ public godot_string_name Name; // Not owned
+ public godot_variant Value;
+
+ public void Dispose()
+ {
+ Value.Dispose();
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe void GetPropertyDefaultValues(IntPtr scriptPtr,
+ delegate* unmanaged<IntPtr, void*, int, void> addDefValFunc)
+ {
+ try
+ {
+ Type? top = _scriptTypeBiMap.GetScriptType(scriptPtr);
+ Type native = Object.InternalGetClassNativeBase(top);
+
+ while (top != null && top != native)
+ {
+ GetPropertyDefaultValuesForType(top, scriptPtr, addDefValFunc);
+
+ top = top.BaseType;
+ }
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ }
+ }
+
+ [SkipLocalsInit]
+ private static unsafe void GetPropertyDefaultValuesForType(Type type, IntPtr scriptPtr,
+ delegate* unmanaged<IntPtr, void*, int, void> addDefValFunc)
+ {
+ try
+ {
+ var getGodotPropertyDefaultValuesMethod = type.GetMethod(
+ "GetGodotPropertyDefaultValues",
+ BindingFlags.DeclaredOnly | BindingFlags.Static |
+ BindingFlags.NonPublic | BindingFlags.Public);
+
+ if (getGodotPropertyDefaultValuesMethod == null)
+ return;
+
+ var defaultValues = (Dictionary<StringName, object>?)
+ getGodotPropertyDefaultValuesMethod.Invoke(null, null);
+
+ if (defaultValues == null || defaultValues.Count <= 0)
+ return;
+
+ int length = defaultValues.Count;
+
+ // There's no recursion here, so it's ok to go with a big enough number for most cases
+ // stackMaxSize = stackMaxLength * sizeof(godotsharp_property_def_val_pair)
+ const int stackMaxLength = 32;
+ bool useStack = length < stackMaxLength;
+
+ godotsharp_property_def_val_pair* interopDefaultValues;
+
+ if (useStack)
+ {
+ // Weird limitation, hence the need for aux:
+ // "In the case of pointer types, you can use a stackalloc expression only in a local variable declaration to initialize the variable."
+ var aux = stackalloc godotsharp_property_def_val_pair[length];
+ interopDefaultValues = aux;
+ }
+ else
+ {
+ interopDefaultValues = ((godotsharp_property_def_val_pair*)NativeMemory.Alloc((nuint)length, (nuint)sizeof(godotsharp_property_def_val_pair)))!;
+ }
+
+ try
+ {
+ int i = 0;
+ foreach (var defaultValuePair in defaultValues)
+ {
+ godotsharp_property_def_val_pair interopProperty = new()
+ {
+ Name = (godot_string_name)defaultValuePair.Key.NativeValue, // Not owned
+ Value = Marshaling.ConvertManagedObjectToVariant(defaultValuePair.Value)
+ };
+
+ interopDefaultValues[i] = interopProperty;
+
+ i++;
+ }
+
+ addDefValFunc(scriptPtr, interopDefaultValues, length);
+
+ // We're borrowing the StringName's without making an owning copy, so the
+ // managed collection needs to be kept alive until `addDefValFunc` returns.
+ GC.KeepAlive(defaultValues);
+ }
+ finally
+ {
+ for (int i = 0; i < length; i++)
+ interopDefaultValues[i].Dispose();
+
+ if (!useStack)
+ NativeMemory.Free(interopDefaultValues);
+ }
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe godot_bool SwapGCHandleForType(IntPtr oldGCHandlePtr, IntPtr* outNewGCHandlePtr,
+ godot_bool createWeak)
+ {
+ try
+ {
+ var oldGCHandle = GCHandle.FromIntPtr(oldGCHandlePtr);
+
+ object? target = oldGCHandle.Target;
+
+ if (target == null)
+ {
+ CustomGCHandle.Free(oldGCHandle);
+ *outNewGCHandlePtr = IntPtr.Zero;
+ return godot_bool.False; // Called after the managed side was collected, so nothing to do here
+ }
+
+ // Release the current weak handle and replace it with a strong handle.
+ var newGCHandle = createWeak.ToBool() ?
+ CustomGCHandle.AllocWeak(target) :
+ CustomGCHandle.AllocStrong(target);
+
+ CustomGCHandle.Free(oldGCHandle);
+ *outNewGCHandlePtr = GCHandle.ToIntPtr(newGCHandle);
+ return godot_bool.True;
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ *outNewGCHandlePtr = IntPtr.Zero;
+ return godot_bool.False;
+ }
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.types.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.types.cs
new file mode 100644
index 0000000000..a58f6849ad
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.types.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Runtime.CompilerServices;
+
+namespace Godot.Bridge;
+
+#nullable enable
+
+public static partial class ScriptManagerBridge
+{
+ private class ScriptTypeBiMap
+ {
+ public readonly object ReadWriteLock = new();
+ private System.Collections.Generic.Dictionary<IntPtr, Type> _scriptTypeMap = new();
+ private System.Collections.Generic.Dictionary<Type, IntPtr> _typeScriptMap = new();
+
+ public void Add(IntPtr scriptPtr, Type scriptType)
+ {
+ // TODO: What if this is called while unloading a load context, but after we already did cleanup in preparation for unloading?
+
+ _scriptTypeMap.Add(scriptPtr, scriptType);
+ _typeScriptMap.Add(scriptType, scriptPtr);
+
+ if (AlcReloadCfg.IsAlcReloadingEnabled)
+ {
+ AddTypeForAlcReloading(scriptType);
+ }
+ }
+
+ public void Remove(IntPtr scriptPtr)
+ {
+ if (_scriptTypeMap.Remove(scriptPtr, out Type? scriptType))
+ _ = _typeScriptMap.Remove(scriptType);
+ }
+
+ public bool RemoveByScriptType(Type scriptType, out IntPtr scriptPtr)
+ {
+ if (_typeScriptMap.Remove(scriptType, out scriptPtr))
+ return _scriptTypeMap.Remove(scriptPtr);
+ return false;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Type GetScriptType(IntPtr scriptPtr) => _scriptTypeMap[scriptPtr];
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool TryGetScriptType(IntPtr scriptPtr, [MaybeNullWhen(false)] out Type scriptType) =>
+ _scriptTypeMap.TryGetValue(scriptPtr, out scriptType);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool TryGetScriptPtr(Type scriptType, out IntPtr scriptPtr) =>
+ _typeScriptMap.TryGetValue(scriptType, out scriptPtr);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool IsScriptRegistered(IntPtr scriptPtr) => _scriptTypeMap.ContainsKey(scriptPtr);
+ }
+
+ private class PathScriptTypeBiMap
+ {
+ private System.Collections.Generic.Dictionary<string, Type> _pathTypeMap = new();
+ private System.Collections.Generic.Dictionary<Type, string> _typePathMap = new();
+
+ public void Add(string scriptPath, Type scriptType)
+ {
+ _pathTypeMap.Add(scriptPath, scriptType);
+
+ // Due to partial classes, more than one file can point to the same type, so
+ // there could be duplicate keys in this case. We only add a type as key once.
+ _typePathMap.TryAdd(scriptType, scriptPath);
+ }
+
+ public void RemoveByScriptType(Type scriptType)
+ {
+ foreach (var pair in _pathTypeMap
+ .Where(p => p.Value == scriptType).ToArray())
+ {
+ _pathTypeMap.Remove(pair.Key);
+ }
+
+ _typePathMap.Remove(scriptType);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool TryGetScriptType(string scriptPath, [MaybeNullWhen(false)] out Type scriptType) =>
+ _pathTypeMap.TryGetValue(scriptPath, out scriptType);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool TryGetScriptPath(Type scriptType, [MaybeNullWhen(false)] out string scriptPath) =>
+ _typePathMap.TryGetValue(scriptType, out scriptPath);
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs
index 2722b64e6d..1b7f5158fd 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Callable.cs
@@ -1,5 +1,7 @@
using System;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Godot.NativeInterop;
namespace Godot
{
@@ -24,7 +26,7 @@ namespace Godot
/// }
/// </code>
/// </example>
- public struct Callable
+ public readonly struct Callable
{
private readonly Object _target;
private readonly StringName _method;
@@ -34,10 +36,12 @@ namespace Godot
/// Object that contains the method.
/// </summary>
public Object Target => _target;
+
/// <summary>
/// Name of the method that will be called.
/// </summary>
public StringName Method => _method;
+
/// <summary>
/// Delegate of the method that will be called.
/// </summary>
@@ -73,15 +77,43 @@ namespace Godot
_delegate = @delegate;
}
+ private const int VarArgsSpanThreshold = 5;
+
/// <summary>
/// Calls the method represented by this <see cref="Callable"/>.
/// Arguments can be passed and should match the method's signature.
/// </summary>
/// <param name="args">Arguments that will be passed to the method call.</param>
/// <returns>The value returned by the method.</returns>
- public object Call(params object[] args)
+ public unsafe Variant Call(params Variant[] args)
{
- return godot_icall_Callable_Call(ref this, args);
+ using godot_callable callable = Marshaling.ConvertCallableToNative(this);
+
+ int argc = args.Length;
+
+ Span<godot_variant.movable> argsStoreSpan = argc <= VarArgsSpanThreshold ?
+ stackalloc godot_variant.movable[VarArgsSpanThreshold].Cleared() :
+ new godot_variant.movable[argc];
+
+ Span<IntPtr> argsSpan = argc <= 10 ?
+ stackalloc IntPtr[argc] :
+ new IntPtr[argc];
+
+ using var variantSpanDisposer = new VariantSpanDisposer(argsStoreSpan);
+
+ fixed (godot_variant* varargs = &MemoryMarshal.GetReference(argsStoreSpan).DangerousSelfRef)
+ fixed (IntPtr* argsPtr = &MemoryMarshal.GetReference(argsSpan))
+ {
+ for (int i = 0; i < argc; i++)
+ {
+ varargs[i] = (godot_variant)args[i].NativeVar;
+ argsPtr[i] = new IntPtr(&varargs[i]);
+ }
+
+ godot_variant ret = NativeFuncs.godotsharp_callable_call(callable,
+ (godot_variant**)argsPtr, argc, out _);
+ return Variant.CreateTakingOwnershipOfDisposableValue(ret);
+ }
}
/// <summary>
@@ -89,15 +121,33 @@ namespace Godot
/// Arguments can be passed and should match the method's signature.
/// </summary>
/// <param name="args">Arguments that will be passed to the method call.</param>
- public void CallDeferred(params object[] args)
+ public unsafe void CallDeferred(params Variant[] args)
{
- godot_icall_Callable_CallDeferred(ref this, args);
- }
+ using godot_callable callable = Marshaling.ConvertCallableToNative(this);
+
+ int argc = args.Length;
+
+ Span<godot_variant.movable> argsStoreSpan = argc <= VarArgsSpanThreshold ?
+ stackalloc godot_variant.movable[VarArgsSpanThreshold].Cleared() :
+ new godot_variant.movable[argc];
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern object godot_icall_Callable_Call(ref Callable callable, object[] args);
+ Span<IntPtr> argsSpan = argc <= 10 ?
+ stackalloc IntPtr[argc] :
+ new IntPtr[argc];
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Callable_CallDeferred(ref Callable callable, object[] args);
+ using var variantSpanDisposer = new VariantSpanDisposer(argsStoreSpan);
+
+ fixed (godot_variant* varargs = &MemoryMarshal.GetReference(argsStoreSpan).DangerousSelfRef)
+ fixed (IntPtr* argsPtr = &MemoryMarshal.GetReference(argsSpan))
+ {
+ for (int i = 0; i < argc; i++)
+ {
+ varargs[i] = (godot_variant)args[i].NativeVar;
+ argsPtr[i] = new IntPtr(&varargs[i]);
+ }
+
+ NativeFuncs.godotsharp_callable_call_deferred(callable, (godot_variant**)argsPtr, argc);
+ }
+ }
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
index fc9d40ca48..33d8aef1a9 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
@@ -210,7 +210,7 @@ namespace Godot
case 3:
return a;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
set
@@ -230,7 +230,7 @@ namespace Godot
a = value;
return;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
}
@@ -595,7 +595,7 @@ namespace Godot
/// </summary>
/// <param name="rgba">A string for the HTML hexadecimal representation of this color.</param>
/// <exception name="ArgumentOutOfRangeException">
- /// Thrown when the given <paramref name="rgba"/> color code is invalid.
+ /// <paramref name="rgba"/> color code is invalid.
/// </exception>
private static Color FromHTML(string rgba)
{
@@ -841,7 +841,7 @@ namespace Godot
return ParseCol4(str, ofs) * 16 + ParseCol4(str, ofs + 1);
}
- private string ToHex32(float val)
+ private static string ToHex32(float val)
{
byte b = (byte)Mathf.RoundToInt(Mathf.Clamp(val * 255, 0, 255));
return b.HexEncode();
@@ -849,7 +849,7 @@ namespace Godot
internal static bool HtmlIsValid(string color)
{
- if (color.Length == 0)
+ if (string.IsNullOrEmpty(color))
{
return false;
}
@@ -916,7 +916,7 @@ namespace Godot
/// <c>new Color(1 - c.r, 1 - c.g, 1 - c.b, 1 - c.a)</c>.
/// </summary>
/// <param name="color">The color to invert.</param>
- /// <returns>The inverted color</returns>
+ /// <returns>The inverted color.</returns>
public static Color operator -(Color color)
{
return Colors.White - color;
@@ -1151,12 +1151,7 @@ namespace Godot
/// <returns>Whether or not the color and the other object are equal.</returns>
public override bool Equals(object obj)
{
- if (obj is Color)
- {
- return Equals((Color)obj);
- }
-
- return false;
+ return obj is Color other && Equals(other);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs
index 68c821b447..5bce66ea87 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Colors.cs
@@ -10,152 +10,152 @@ namespace Godot
{
// Color names and values are derived from core/math/color_names.inc
internal static readonly Dictionary<string, Color> namedColors = new Dictionary<string, Color> {
- {"ALICEBLUE", new Color(0.94f, 0.97f, 1.00f)},
- {"ANTIQUEWHITE", new Color(0.98f, 0.92f, 0.84f)},
- {"AQUA", new Color(0.00f, 1.00f, 1.00f)},
- {"AQUAMARINE", new Color(0.50f, 1.00f, 0.83f)},
- {"AZURE", new Color(0.94f, 1.00f, 1.00f)},
- {"BEIGE", new Color(0.96f, 0.96f, 0.86f)},
- {"BISQUE", new Color(1.00f, 0.89f, 0.77f)},
- {"BLACK", new Color(0.00f, 0.00f, 0.00f)},
- {"BLANCHEDALMOND", new Color(1.00f, 0.92f, 0.80f)},
- {"BLUE", new Color(0.00f, 0.00f, 1.00f)},
- {"BLUEVIOLET", new Color(0.54f, 0.17f, 0.89f)},
- {"BROWN", new Color(0.65f, 0.16f, 0.16f)},
- {"BURLYWOOD", new Color(0.87f, 0.72f, 0.53f)},
- {"CADETBLUE", new Color(0.37f, 0.62f, 0.63f)},
- {"CHARTREUSE", new Color(0.50f, 1.00f, 0.00f)},
- {"CHOCOLATE", new Color(0.82f, 0.41f, 0.12f)},
- {"CORAL", new Color(1.00f, 0.50f, 0.31f)},
- {"CORNFLOWERBLUE", new Color(0.39f, 0.58f, 0.93f)},
- {"CORNSILK", new Color(1.00f, 0.97f, 0.86f)},
- {"CRIMSON", new Color(0.86f, 0.08f, 0.24f)},
- {"CYAN", new Color(0.00f, 1.00f, 1.00f)},
- {"DARKBLUE", new Color(0.00f, 0.00f, 0.55f)},
- {"DARKCYAN", new Color(0.00f, 0.55f, 0.55f)},
- {"DARKGOLDENROD", new Color(0.72f, 0.53f, 0.04f)},
- {"DARKGRAY", new Color(0.66f, 0.66f, 0.66f)},
- {"DARKGREEN", new Color(0.00f, 0.39f, 0.00f)},
- {"DARKKHAKI", new Color(0.74f, 0.72f, 0.42f)},
- {"DARKMAGENTA", new Color(0.55f, 0.00f, 0.55f)},
- {"DARKOLIVEGREEN", new Color(0.33f, 0.42f, 0.18f)},
- {"DARKORANGE", new Color(1.00f, 0.55f, 0.00f)},
- {"DARKORCHID", new Color(0.60f, 0.20f, 0.80f)},
- {"DARKRED", new Color(0.55f, 0.00f, 0.00f)},
- {"DARKSALMON", new Color(0.91f, 0.59f, 0.48f)},
- {"DARKSEAGREEN", new Color(0.56f, 0.74f, 0.56f)},
- {"DARKSLATEBLUE", new Color(0.28f, 0.24f, 0.55f)},
- {"DARKSLATEGRAY", new Color(0.18f, 0.31f, 0.31f)},
- {"DARKTURQUOISE", new Color(0.00f, 0.81f, 0.82f)},
- {"DARKVIOLET", new Color(0.58f, 0.00f, 0.83f)},
- {"DEEPPINK", new Color(1.00f, 0.08f, 0.58f)},
- {"DEEPSKYBLUE", new Color(0.00f, 0.75f, 1.00f)},
- {"DIMGRAY", new Color(0.41f, 0.41f, 0.41f)},
- {"DODGERBLUE", new Color(0.12f, 0.56f, 1.00f)},
- {"FIREBRICK", new Color(0.70f, 0.13f, 0.13f)},
- {"FLORALWHITE", new Color(1.00f, 0.98f, 0.94f)},
- {"FORESTGREEN", new Color(0.13f, 0.55f, 0.13f)},
- {"FUCHSIA", new Color(1.00f, 0.00f, 1.00f)},
- {"GAINSBORO", new Color(0.86f, 0.86f, 0.86f)},
- {"GHOSTWHITE", new Color(0.97f, 0.97f, 1.00f)},
- {"GOLD", new Color(1.00f, 0.84f, 0.00f)},
- {"GOLDENROD", new Color(0.85f, 0.65f, 0.13f)},
- {"GRAY", new Color(0.75f, 0.75f, 0.75f)},
- {"GREEN", new Color(0.00f, 1.00f, 0.00f)},
- {"GREENYELLOW", new Color(0.68f, 1.00f, 0.18f)},
- {"HONEYDEW", new Color(0.94f, 1.00f, 0.94f)},
- {"HOTPINK", new Color(1.00f, 0.41f, 0.71f)},
- {"INDIANRED", new Color(0.80f, 0.36f, 0.36f)},
- {"INDIGO", new Color(0.29f, 0.00f, 0.51f)},
- {"IVORY", new Color(1.00f, 1.00f, 0.94f)},
- {"KHAKI", new Color(0.94f, 0.90f, 0.55f)},
- {"LAVENDER", new Color(0.90f, 0.90f, 0.98f)},
- {"LAVENDERBLUSH", new Color(1.00f, 0.94f, 0.96f)},
- {"LAWNGREEN", new Color(0.49f, 0.99f, 0.00f)},
- {"LEMONCHIFFON", new Color(1.00f, 0.98f, 0.80f)},
- {"LIGHTBLUE", new Color(0.68f, 0.85f, 0.90f)},
- {"LIGHTCORAL", new Color(0.94f, 0.50f, 0.50f)},
- {"LIGHTCYAN", new Color(0.88f, 1.00f, 1.00f)},
- {"LIGHTGOLDENROD", new Color(0.98f, 0.98f, 0.82f)},
- {"LIGHTGRAY", new Color(0.83f, 0.83f, 0.83f)},
- {"LIGHTGREEN", new Color(0.56f, 0.93f, 0.56f)},
- {"LIGHTPINK", new Color(1.00f, 0.71f, 0.76f)},
- {"LIGHTSALMON", new Color(1.00f, 0.63f, 0.48f)},
- {"LIGHTSEAGREEN", new Color(0.13f, 0.70f, 0.67f)},
- {"LIGHTSKYBLUE", new Color(0.53f, 0.81f, 0.98f)},
- {"LIGHTSLATEGRAY", new Color(0.47f, 0.53f, 0.60f)},
- {"LIGHTSTEELBLUE", new Color(0.69f, 0.77f, 0.87f)},
- {"LIGHTYELLOW", new Color(1.00f, 1.00f, 0.88f)},
- {"LIME", new Color(0.00f, 1.00f, 0.00f)},
- {"LIMEGREEN", new Color(0.20f, 0.80f, 0.20f)},
- {"LINEN", new Color(0.98f, 0.94f, 0.90f)},
- {"MAGENTA", new Color(1.00f, 0.00f, 1.00f)},
- {"MAROON", new Color(0.69f, 0.19f, 0.38f)},
- {"MEDIUMAQUAMARINE", new Color(0.40f, 0.80f, 0.67f)},
- {"MEDIUMBLUE", new Color(0.00f, 0.00f, 0.80f)},
- {"MEDIUMORCHID", new Color(0.73f, 0.33f, 0.83f)},
- {"MEDIUMPURPLE", new Color(0.58f, 0.44f, 0.86f)},
- {"MEDIUMSEAGREEN", new Color(0.24f, 0.70f, 0.44f)},
- {"MEDIUMSLATEBLUE", new Color(0.48f, 0.41f, 0.93f)},
- {"MEDIUMSPRINGGREEN", new Color(0.00f, 0.98f, 0.60f)},
- {"MEDIUMTURQUOISE", new Color(0.28f, 0.82f, 0.80f)},
- {"MEDIUMVIOLETRED", new Color(0.78f, 0.08f, 0.52f)},
- {"MIDNIGHTBLUE", new Color(0.10f, 0.10f, 0.44f)},
- {"MINTCREAM", new Color(0.96f, 1.00f, 0.98f)},
- {"MISTYROSE", new Color(1.00f, 0.89f, 0.88f)},
- {"MOCCASIN", new Color(1.00f, 0.89f, 0.71f)},
- {"NAVAJOWHITE", new Color(1.00f, 0.87f, 0.68f)},
- {"NAVYBLUE", new Color(0.00f, 0.00f, 0.50f)},
- {"OLDLACE", new Color(0.99f, 0.96f, 0.90f)},
- {"OLIVE", new Color(0.50f, 0.50f, 0.00f)},
- {"OLIVEDRAB", new Color(0.42f, 0.56f, 0.14f)},
- {"ORANGE", new Color(1.00f, 0.65f, 0.00f)},
- {"ORANGERED", new Color(1.00f, 0.27f, 0.00f)},
- {"ORCHID", new Color(0.85f, 0.44f, 0.84f)},
- {"PALEGOLDENROD", new Color(0.93f, 0.91f, 0.67f)},
- {"PALEGREEN", new Color(0.60f, 0.98f, 0.60f)},
- {"PALETURQUOISE", new Color(0.69f, 0.93f, 0.93f)},
- {"PALEVIOLETRED", new Color(0.86f, 0.44f, 0.58f)},
- {"PAPAYAWHIP", new Color(1.00f, 0.94f, 0.84f)},
- {"PEACHPUFF", new Color(1.00f, 0.85f, 0.73f)},
- {"PERU", new Color(0.80f, 0.52f, 0.25f)},
- {"PINK", new Color(1.00f, 0.75f, 0.80f)},
- {"PLUM", new Color(0.87f, 0.63f, 0.87f)},
- {"POWDERBLUE", new Color(0.69f, 0.88f, 0.90f)},
- {"PURPLE", new Color(0.63f, 0.13f, 0.94f)},
- {"REBECCAPURPLE", new Color(0.40f, 0.20f, 0.60f)},
- {"RED", new Color(1.00f, 0.00f, 0.00f)},
- {"ROSYBROWN", new Color(0.74f, 0.56f, 0.56f)},
- {"ROYALBLUE", new Color(0.25f, 0.41f, 0.88f)},
- {"SADDLEBROWN", new Color(0.55f, 0.27f, 0.07f)},
- {"SALMON", new Color(0.98f, 0.50f, 0.45f)},
- {"SANDYBROWN", new Color(0.96f, 0.64f, 0.38f)},
- {"SEAGREEN", new Color(0.18f, 0.55f, 0.34f)},
- {"SEASHELL", new Color(1.00f, 0.96f, 0.93f)},
- {"SIENNA", new Color(0.63f, 0.32f, 0.18f)},
- {"SILVER", new Color(0.75f, 0.75f, 0.75f)},
- {"SKYBLUE", new Color(0.53f, 0.81f, 0.92f)},
- {"SLATEBLUE", new Color(0.42f, 0.35f, 0.80f)},
- {"SLATEGRAY", new Color(0.44f, 0.50f, 0.56f)},
- {"SNOW", new Color(1.00f, 0.98f, 0.98f)},
- {"SPRINGGREEN", new Color(0.00f, 1.00f, 0.50f)},
- {"STEELBLUE", new Color(0.27f, 0.51f, 0.71f)},
- {"TAN", new Color(0.82f, 0.71f, 0.55f)},
- {"TEAL", new Color(0.00f, 0.50f, 0.50f)},
- {"THISTLE", new Color(0.85f, 0.75f, 0.85f)},
- {"TOMATO", new Color(1.00f, 0.39f, 0.28f)},
- {"TRANSPARENT", new Color(1.00f, 1.00f, 1.00f, 0.00f)},
- {"TURQUOISE", new Color(0.25f, 0.88f, 0.82f)},
- {"VIOLET", new Color(0.93f, 0.51f, 0.93f)},
- {"WEBGRAY", new Color(0.50f, 0.50f, 0.50f)},
- {"WEBGREEN", new Color(0.00f, 0.50f, 0.00f)},
- {"WEBMAROON", new Color(0.50f, 0.00f, 0.00f)},
- {"WEBPURPLE", new Color(0.50f, 0.00f, 0.50f)},
- {"WHEAT", new Color(0.96f, 0.87f, 0.70f)},
- {"WHITE", new Color(1.00f, 1.00f, 1.00f)},
- {"WHITESMOKE", new Color(0.96f, 0.96f, 0.96f)},
- {"YELLOW", new Color(1.00f, 1.00f, 0.00f)},
- {"YELLOWGREEN", new Color(0.60f, 0.80f, 0.20f)},
+ { "ALICEBLUE", new Color(0xF0F8FFFF) },
+ { "ANTIQUEWHITE", new Color(0xFAEBD7FF) },
+ { "AQUA", new Color(0x00FFFFFF) },
+ { "AQUAMARINE", new Color(0x7FFFD4FF) },
+ { "AZURE", new Color(0xF0FFFFFF) },
+ { "BEIGE", new Color(0xF5F5DCFF) },
+ { "BISQUE", new Color(0xFFE4C4FF) },
+ { "BLACK", new Color(0x000000FF) },
+ { "BLANCHEDALMOND", new Color(0xFFEBCDFF) },
+ { "BLUE", new Color(0x0000FFFF) },
+ { "BLUEVIOLET", new Color(0x8A2BE2FF) },
+ { "BROWN", new Color(0xA52A2AFF) },
+ { "BURLYWOOD", new Color(0xDEB887FF) },
+ { "CADETBLUE", new Color(0x5F9EA0FF) },
+ { "CHARTREUSE", new Color(0x7FFF00FF) },
+ { "CHOCOLATE", new Color(0xD2691EFF) },
+ { "CORAL", new Color(0xFF7F50FF) },
+ { "CORNFLOWERBLUE", new Color(0x6495EDFF) },
+ { "CORNSILK", new Color(0xFFF8DCFF) },
+ { "CRIMSON", new Color(0xDC143CFF) },
+ { "CYAN", new Color(0x00FFFFFF) },
+ { "DARKBLUE", new Color(0x00008BFF) },
+ { "DARKCYAN", new Color(0x008B8BFF) },
+ { "DARKGOLDENROD", new Color(0xB8860BFF) },
+ { "DARKGRAY", new Color(0xA9A9A9FF) },
+ { "DARKGREEN", new Color(0x006400FF) },
+ { "DARKKHAKI", new Color(0xBDB76BFF) },
+ { "DARKMAGENTA", new Color(0x8B008BFF) },
+ { "DARKOLIVEGREEN", new Color(0x556B2FFF) },
+ { "DARKORANGE", new Color(0xFF8C00FF) },
+ { "DARKORCHID", new Color(0x9932CCFF) },
+ { "DARKRED", new Color(0x8B0000FF) },
+ { "DARKSALMON", new Color(0xE9967AFF) },
+ { "DARKSEAGREEN", new Color(0x8FBC8FFF) },
+ { "DARKSLATEBLUE", new Color(0x483D8BFF) },
+ { "DARKSLATEGRAY", new Color(0x2F4F4FFF) },
+ { "DARKTURQUOISE", new Color(0x00CED1FF) },
+ { "DARKVIOLET", new Color(0x9400D3FF) },
+ { "DEEPPINK", new Color(0xFF1493FF) },
+ { "DEEPSKYBLUE", new Color(0x00BFFFFF) },
+ { "DIMGRAY", new Color(0x696969FF) },
+ { "DODGERBLUE", new Color(0x1E90FFFF) },
+ { "FIREBRICK", new Color(0xB22222FF) },
+ { "FLORALWHITE", new Color(0xFFFAF0FF) },
+ { "FORESTGREEN", new Color(0x228B22FF) },
+ { "FUCHSIA", new Color(0xFF00FFFF) },
+ { "GAINSBORO", new Color(0xDCDCDCFF) },
+ { "GHOSTWHITE", new Color(0xF8F8FFFF) },
+ { "GOLD", new Color(0xFFD700FF) },
+ { "GOLDENROD", new Color(0xDAA520FF) },
+ { "GRAY", new Color(0xBEBEBEFF) },
+ { "GREEN", new Color(0x00FF00FF) },
+ { "GREENYELLOW", new Color(0xADFF2FFF) },
+ { "HONEYDEW", new Color(0xF0FFF0FF) },
+ { "HOTPINK", new Color(0xFF69B4FF) },
+ { "INDIANRED", new Color(0xCD5C5CFF) },
+ { "INDIGO", new Color(0x4B0082FF) },
+ { "IVORY", new Color(0xFFFFF0FF) },
+ { "KHAKI", new Color(0xF0E68CFF) },
+ { "LAVENDER", new Color(0xE6E6FAFF) },
+ { "LAVENDERBLUSH", new Color(0xFFF0F5FF) },
+ { "LAWNGREEN", new Color(0x7CFC00FF) },
+ { "LEMONCHIFFON", new Color(0xFFFACDFF) },
+ { "LIGHTBLUE", new Color(0xADD8E6FF) },
+ { "LIGHTCORAL", new Color(0xF08080FF) },
+ { "LIGHTCYAN", new Color(0xE0FFFFFF) },
+ { "LIGHTGOLDENROD", new Color(0xFAFAD2FF) },
+ { "LIGHTGRAY", new Color(0xD3D3D3FF) },
+ { "LIGHTGREEN", new Color(0x90EE90FF) },
+ { "LIGHTPINK", new Color(0xFFB6C1FF) },
+ { "LIGHTSALMON", new Color(0xFFA07AFF) },
+ { "LIGHTSEAGREEN", new Color(0x20B2AAFF) },
+ { "LIGHTSKYBLUE", new Color(0x87CEFAFF) },
+ { "LIGHTSLATEGRAY", new Color(0x778899FF) },
+ { "LIGHTSTEELBLUE", new Color(0xB0C4DEFF) },
+ { "LIGHTYELLOW", new Color(0xFFFFE0FF) },
+ { "LIME", new Color(0x00FF00FF) },
+ { "LIMEGREEN", new Color(0x32CD32FF) },
+ { "LINEN", new Color(0xFAF0E6FF) },
+ { "MAGENTA", new Color(0xFF00FFFF) },
+ { "MAROON", new Color(0xB03060FF) },
+ { "MEDIUMAQUAMARINE", new Color(0x66CDAAFF) },
+ { "MEDIUMBLUE", new Color(0x0000CDFF) },
+ { "MEDIUMORCHID", new Color(0xBA55D3FF) },
+ { "MEDIUMPURPLE", new Color(0x9370DBFF) },
+ { "MEDIUMSEAGREEN", new Color(0x3CB371FF) },
+ { "MEDIUMSLATEBLUE", new Color(0x7B68EEFF) },
+ { "MEDIUMSPRINGGREEN", new Color(0x00FA9AFF) },
+ { "MEDIUMTURQUOISE", new Color(0x48D1CCFF) },
+ { "MEDIUMVIOLETRED", new Color(0xC71585FF) },
+ { "MIDNIGHTBLUE", new Color(0x191970FF) },
+ { "MINTCREAM", new Color(0xF5FFFAFF) },
+ { "MISTYROSE", new Color(0xFFE4E1FF) },
+ { "MOCCASIN", new Color(0xFFE4B5FF) },
+ { "NAVAJOWHITE", new Color(0xFFDEADFF) },
+ { "NAVYBLUE", new Color(0x000080FF) },
+ { "OLDLACE", new Color(0xFDF5E6FF) },
+ { "OLIVE", new Color(0x808000FF) },
+ { "OLIVEDRAB", new Color(0x6B8E23FF) },
+ { "ORANGE", new Color(0xFFA500FF) },
+ { "ORANGERED", new Color(0xFF4500FF) },
+ { "ORCHID", new Color(0xDA70D6FF) },
+ { "PALEGOLDENROD", new Color(0xEEE8AAFF) },
+ { "PALEGREEN", new Color(0x98FB98FF) },
+ { "PALETURQUOISE", new Color(0xAFEEEEFF) },
+ { "PALEVIOLETRED", new Color(0xDB7093FF) },
+ { "PAPAYAWHIP", new Color(0xFFEFD5FF) },
+ { "PEACHPUFF", new Color(0xFFDAB9FF) },
+ { "PERU", new Color(0xCD853FFF) },
+ { "PINK", new Color(0xFFC0CBFF) },
+ { "PLUM", new Color(0xDDA0DDFF) },
+ { "POWDERBLUE", new Color(0xB0E0E6FF) },
+ { "PURPLE", new Color(0xA020F0FF) },
+ { "REBECCAPURPLE", new Color(0x663399FF) },
+ { "RED", new Color(0xFF0000FF) },
+ { "ROSYBROWN", new Color(0xBC8F8FFF) },
+ { "ROYALBLUE", new Color(0x4169E1FF) },
+ { "SADDLEBROWN", new Color(0x8B4513FF) },
+ { "SALMON", new Color(0xFA8072FF) },
+ { "SANDYBROWN", new Color(0xF4A460FF) },
+ { "SEAGREEN", new Color(0x2E8B57FF) },
+ { "SEASHELL", new Color(0xFFF5EEFF) },
+ { "SIENNA", new Color(0xA0522DFF) },
+ { "SILVER", new Color(0xC0C0C0FF) },
+ { "SKYBLUE", new Color(0x87CEEBFF) },
+ { "SLATEBLUE", new Color(0x6A5ACDFF) },
+ { "SLATEGRAY", new Color(0x708090FF) },
+ { "SNOW", new Color(0xFFFAFAFF) },
+ { "SPRINGGREEN", new Color(0x00FF7FFF) },
+ { "STEELBLUE", new Color(0x4682B4FF) },
+ { "TAN", new Color(0xD2B48CFF) },
+ { "TEAL", new Color(0x008080FF) },
+ { "THISTLE", new Color(0xD8BFD8FF) },
+ { "TOMATO", new Color(0xFF6347FF) },
+ { "TRANSPARENT", new Color(0xFFFFFF00) },
+ { "TURQUOISE", new Color(0x40E0D0FF) },
+ { "VIOLET", new Color(0xEE82EEFF) },
+ { "WEBGRAY", new Color(0x808080FF) },
+ { "WEBGREEN", new Color(0x008000FF) },
+ { "WEBMAROON", new Color(0x800000FF) },
+ { "WEBPURPLE", new Color(0x800080FF) },
+ { "WHEAT", new Color(0xF5DEB3FF) },
+ { "WHITE", new Color(0xFFFFFFFF) },
+ { "WHITESMOKE", new Color(0xF5F5F5FF) },
+ { "YELLOW", new Color(0xFFFF00FF) },
+ { "YELLOWGREEN", new Color(0x9ACD32FF) },
};
#pragma warning disable CS1591 // Disable warning: "Missing XML comment for publicly visible type or member"
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/CustomGCHandle.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/CustomGCHandle.cs
new file mode 100644
index 0000000000..42f19ace1a
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/CustomGCHandle.cs
@@ -0,0 +1,98 @@
+#nullable enable
+
+using System;
+using System.Collections.Concurrent;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Loader;
+using Godot.Bridge;
+
+namespace Godot;
+
+/// <summary>
+/// Provides a GCHandle that becomes weak when unloading the assembly load context, without having
+/// to manually replace the GCHandle. This hides all the complexity of releasing strong GC handles
+/// to allow the assembly load context to unload properly.
+///
+/// Internally, a strong CustomGCHandle actually contains a weak GCHandle, while the actual strong
+/// reference is stored in a static table.
+/// </summary>
+public static class CustomGCHandle
+{
+ // ConditionalWeakTable uses DependentHandle, so it stores weak references.
+ // Having the assembly load context as key won't prevent it from unloading.
+ private static ConditionalWeakTable<AssemblyLoadContext, object?> _alcsBeingUnloaded = new();
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static bool IsAlcBeingUnloaded(AssemblyLoadContext alc) => _alcsBeingUnloaded.TryGetValue(alc, out _);
+
+ // ReSharper disable once RedundantNameQualifier
+ private static ConcurrentDictionary<
+ AssemblyLoadContext,
+ ConcurrentDictionary<GCHandle, object>
+ > _strongReferencesByAlc = new();
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void OnAlcUnloading(AssemblyLoadContext alc)
+ {
+ _alcsBeingUnloaded.Add(alc, null);
+
+ if (_strongReferencesByAlc.TryRemove(alc, out var strongReferences))
+ {
+ strongReferences.Clear();
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static GCHandle AllocStrong(object value)
+ => AllocStrong(value, value.GetType());
+
+ public static GCHandle AllocStrong(object value, Type valueType)
+ {
+ if (AlcReloadCfg.IsAlcReloadingEnabled)
+ {
+ var alc = AssemblyLoadContext.GetLoadContext(valueType.Assembly);
+
+ if (alc != null)
+ {
+ var weakHandle = GCHandle.Alloc(value, GCHandleType.Weak);
+
+ if (!IsAlcBeingUnloaded(alc))
+ {
+ var strongReferences = _strongReferencesByAlc.GetOrAdd(alc,
+ static alc =>
+ {
+ alc.Unloading += OnAlcUnloading;
+ return new();
+ });
+ strongReferences.TryAdd(weakHandle, value);
+ }
+
+ return weakHandle;
+ }
+ }
+
+ return GCHandle.Alloc(value, GCHandleType.Normal);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static GCHandle AllocWeak(object value) => GCHandle.Alloc(value, GCHandleType.Weak);
+
+ public static void Free(GCHandle handle)
+ {
+ if (AlcReloadCfg.IsAlcReloadingEnabled)
+ {
+ var target = handle.Target;
+
+ if (target != null)
+ {
+ var alc = AssemblyLoadContext.GetLoadContext(target.GetType().Assembly);
+
+ if (alc != null && _strongReferencesByAlc.TryGetValue(alc, out var strongReferences))
+ _ = strongReferences.TryRemove(handle, out _);
+ }
+ }
+
+ handle.Free();
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs
index edfe3464ec..c4161d2ded 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DebuggingUtils.cs
@@ -1,13 +1,18 @@
using System;
using System.Diagnostics;
using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Text;
+using Godot.NativeInterop;
+
+#nullable enable
namespace Godot
{
internal static class DebuggingUtils
{
- internal static void AppendTypeName(this StringBuilder sb, Type type)
+ private static void AppendTypeName(this StringBuilder sb, Type type)
{
if (type.IsPrimitive)
sb.Append(type.Name);
@@ -16,21 +21,97 @@ namespace Godot
else
sb.Append(type);
- sb.Append(" ");
+ sb.Append(' ');
}
- public static void InstallTraceListener()
+ internal static void InstallTraceListener()
{
Trace.Listeners.Clear();
Trace.Listeners.Add(new GodotTraceListener());
}
- public static void GetStackFrameInfo(StackFrame frame, out string fileName, out int fileLineNumber, out string methodDecl)
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal ref struct godot_stack_info
+ {
+ public godot_string File;
+ public godot_string Func;
+ public int Line;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal ref struct godot_stack_info_vector
{
- fileName = frame.GetFileName();
- fileLineNumber = frame.GetFileLineNumber();
+ private IntPtr _writeProxy;
+ private unsafe godot_stack_info* _ptr;
+
+ public readonly unsafe godot_stack_info* Elements
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr;
+ }
+
+ public void Resize(int size)
+ {
+ if (size < 0)
+ throw new ArgumentOutOfRangeException(nameof(size));
+ var err = NativeFuncs.godotsharp_stack_info_vector_resize(ref this, size);
+ if (err != Error.Ok)
+ throw new InvalidOperationException("Failed to resize vector. Error code is: " + err.ToString());
+ }
+
+ public unsafe void Dispose()
+ {
+ if (_ptr == null)
+ return;
+ NativeFuncs.godotsharp_stack_info_vector_destroy(ref this);
+ _ptr = null;
+ }
+ }
- MethodBase methodBase = frame.GetMethod();
+ [UnmanagedCallersOnly]
+ internal static unsafe void GetCurrentStackInfo(void* destVector)
+ {
+ try
+ {
+ var vector = (godot_stack_info_vector*)destVector;
+ var stackTrace = new StackTrace(skipFrames: 1, fNeedFileInfo: true);
+ int frameCount = stackTrace.FrameCount;
+
+ if (frameCount == 0)
+ return;
+
+ vector->Resize(frameCount);
+
+ int i = 0;
+ foreach (StackFrame frame in stackTrace.GetFrames())
+ {
+ string? fileName = frame.GetFileName();
+ int fileLineNumber = frame.GetFileLineNumber();
+
+ GetStackFrameMethodDecl(frame, out string methodDecl);
+
+ godot_stack_info* stackInfo = &vector->Elements[i];
+
+ // Assign directly to element in Vector. This way we don't need to worry
+ // about disposal if an exception is thrown. The Vector takes care of it.
+ stackInfo->File = Marshaling.ConvertStringToNative(fileName);
+ stackInfo->Func = Marshaling.ConvertStringToNative(methodDecl);
+ stackInfo->Line = fileLineNumber;
+
+ i++;
+ }
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ }
+ }
+
+ internal static void GetStackFrameMethodDecl(StackFrame frame, out string methodDecl)
+ {
+ MethodBase? methodBase = frame.GetMethod();
if (methodBase == null)
{
@@ -40,18 +121,18 @@ namespace Godot
var sb = new StringBuilder();
- if (methodBase is MethodInfo)
- sb.AppendTypeName(((MethodInfo)methodBase).ReturnType);
+ if (methodBase is MethodInfo methodInfo)
+ sb.AppendTypeName(methodInfo.ReturnType);
- sb.Append(methodBase.DeclaringType.FullName);
- sb.Append(".");
+ sb.Append(methodBase.DeclaringType?.FullName ?? "<unknown>");
+ sb.Append('.');
sb.Append(methodBase.Name);
if (methodBase.IsGenericMethod)
{
Type[] genericParams = methodBase.GetGenericArguments();
- sb.Append("<");
+ sb.Append('<');
for (int j = 0; j < genericParams.Length; j++)
{
@@ -61,10 +142,10 @@ namespace Godot
sb.AppendTypeName(genericParams[j]);
}
- sb.Append(">");
+ sb.Append('>');
}
- sb.Append("(");
+ sb.Append('(');
bool varArgs = (methodBase.CallingConvention & CallingConventions.VarArgs) != 0;
@@ -81,7 +162,7 @@ namespace Godot
sb.AppendTypeName(parameter[i].ParameterType);
}
- sb.Append(")");
+ sb.Append(')');
methodDecl = sb.ToString();
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
index 1dca9e6ea7..3c75d18943 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
@@ -1,14 +1,72 @@
+#nullable enable
+
using System;
using System.Collections.Generic;
-using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Godot.NativeInterop;
namespace Godot
{
internal static class DelegateUtils
{
+ [UnmanagedCallersOnly]
+ internal static godot_bool DelegateEquals(IntPtr delegateGCHandleA, IntPtr delegateGCHandleB)
+ {
+ try
+ {
+ var @delegateA = (Delegate?)GCHandle.FromIntPtr(delegateGCHandleA).Target;
+ var @delegateB = (Delegate?)GCHandle.FromIntPtr(delegateGCHandleB).Target;
+ return (@delegateA! == @delegateB!).ToGodotBool();
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ return godot_bool.False;
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe void InvokeWithVariantArgs(IntPtr delegateGCHandle, godot_variant** args, uint argc,
+ godot_variant* outRet)
+ {
+ try
+ {
+ // TODO: Optimize
+ var @delegate = (Delegate)GCHandle.FromIntPtr(delegateGCHandle).Target!;
+ var managedArgs = new object?[argc];
+
+ var parameterInfos = @delegate.Method.GetParameters();
+ var paramsLength = parameterInfos.Length;
+
+ if (argc != paramsLength)
+ {
+ throw new InvalidOperationException(
+ $"The delegate expects {paramsLength} arguments, but received {argc}.");
+ }
+
+ for (uint i = 0; i < argc; i++)
+ {
+ managedArgs[i] = Marshaling.ConvertVariantToManagedObjectOfType(
+ *args[i], parameterInfos[i].ParameterType);
+ }
+
+ object? invokeRet = @delegate.DynamicInvoke(managedArgs);
+
+ *outRet = Marshaling.ConvertManagedObjectToVariant(invokeRet);
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ *outRet = default;
+ }
+ }
+
+ // TODO: Check if we should be using BindingFlags.DeclaredOnly (would give better reflection performance).
+
private enum TargetKind : uint
{
Static,
@@ -39,20 +97,20 @@ namespace Godot
}
}
- if (TrySerializeSingleDelegate(@delegate, out byte[] buffer))
+ if (TrySerializeSingleDelegate(@delegate, out byte[]? buffer))
{
- serializedData.Add(buffer);
+ serializedData.Add((Span<byte>)buffer);
return true;
}
return false;
}
- private static bool TrySerializeSingleDelegate(Delegate @delegate, out byte[] buffer)
+ private static bool TrySerializeSingleDelegate(Delegate @delegate, [MaybeNullWhen(false)] out byte[] buffer)
{
buffer = null;
- object target = @delegate.Target;
+ object? target = @delegate.Target;
switch (target)
{
@@ -72,12 +130,14 @@ namespace Godot
return true;
}
}
+ // ReSharper disable once RedundantNameQualifier
case Godot.Object godotObject:
{
using (var stream = new MemoryStream())
using (var writer = new BinaryWriter(stream))
{
writer.Write((ulong)TargetKind.GodotObject);
+ // ReSharper disable once RedundantCast
writer.Write((ulong)godotObject.GetInstanceId());
SerializeType(writer, @delegate.GetType());
@@ -93,7 +153,7 @@ namespace Godot
{
Type targetType = target.GetType();
- if (targetType.GetCustomAttribute(typeof(CompilerGeneratedAttribute), true) != null)
+ if (targetType.IsDefined(typeof(CompilerGeneratedAttribute), true))
{
// Compiler generated. Probably a closure. Try to serialize it.
@@ -121,8 +181,18 @@ namespace Godot
if (variantType == Variant.Type.Nil)
return false;
+ static byte[] VarToBytes(in godot_variant var)
+ {
+ NativeFuncs.godotsharp_var_to_bytes(var, false.ToGodotBool(), out var varBytes);
+ using (varBytes)
+ return Marshaling.ConvertNativePackedByteArrayToSystemArray(varBytes);
+ }
+
writer.Write(field.Name);
- byte[] valueBuffer = GD.Var2Bytes(field.GetValue(target));
+
+ var fieldValue = field.GetValue(target);
+ using var fieldValueVariant = Marshaling.ConvertManagedObjectToVariant(fieldValue);
+ byte[] valueBuffer = VarToBytes(fieldValueVariant);
writer.Write(valueBuffer.Length);
writer.Write(valueBuffer);
}
@@ -139,9 +209,6 @@ namespace Godot
private static bool TrySerializeMethodInfo(BinaryWriter writer, MethodInfo methodInfo)
{
- if (methodInfo == null)
- return false;
-
SerializeType(writer, methodInfo.DeclaringType);
writer.Write(methodInfo.Name);
@@ -180,7 +247,7 @@ namespace Godot
return true;
}
- private static void SerializeType(BinaryWriter writer, Type type)
+ private static void SerializeType(BinaryWriter writer, Type? type)
{
if (type == null)
{
@@ -195,9 +262,8 @@ namespace Godot
int genericArgumentsCount = genericArgs.Length;
writer.Write(genericArgumentsCount);
- string assemblyQualifiedName = genericTypeDef.AssemblyQualifiedName;
- Debug.Assert(assemblyQualifiedName != null);
- writer.Write(assemblyQualifiedName);
+ writer.Write(genericTypeDef.Assembly.GetName().Name ?? "");
+ writer.Write(genericTypeDef.FullName ?? genericTypeDef.ToString());
for (int i = 0; i < genericArgs.Length; i++)
SerializeType(writer, genericArgs[i]);
@@ -207,17 +273,71 @@ namespace Godot
int genericArgumentsCount = 0;
writer.Write(genericArgumentsCount);
- string assemblyQualifiedName = type.AssemblyQualifiedName;
- Debug.Assert(assemblyQualifiedName != null);
- writer.Write(assemblyQualifiedName);
+ writer.Write(type.Assembly.GetName().Name ?? "");
+ writer.Write(type.FullName ?? type.ToString());
+ }
+ }
+
+ [UnmanagedCallersOnly]
+ internal static unsafe godot_bool TrySerializeDelegateWithGCHandle(IntPtr delegateGCHandle,
+ godot_array* nSerializedData)
+ {
+ try
+ {
+ var serializedData = Collections.Array.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_array_new_copy(*nSerializedData));
+
+ var @delegate = (Delegate)GCHandle.FromIntPtr(delegateGCHandle).Target!;
+
+ return TrySerializeDelegate(@delegate, serializedData)
+ .ToGodotBool();
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ return godot_bool.False;
}
}
- private static bool TryDeserializeDelegate(Collections.Array serializedData, out Delegate @delegate)
+ [UnmanagedCallersOnly]
+ internal static unsafe godot_bool TryDeserializeDelegateWithGCHandle(godot_array* nSerializedData,
+ IntPtr* delegateGCHandle)
{
+ try
+ {
+ var serializedData = Collections.Array.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_array_new_copy(*nSerializedData));
+
+ if (TryDeserializeDelegate(serializedData, out Delegate? @delegate))
+ {
+ *delegateGCHandle = GCHandle.ToIntPtr(CustomGCHandle.AllocStrong(@delegate));
+ return godot_bool.True;
+ }
+ else
+ {
+ *delegateGCHandle = IntPtr.Zero;
+ return godot_bool.False;
+ }
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ *delegateGCHandle = default;
+ return godot_bool.False;
+ }
+ }
+
+ internal static bool TryDeserializeDelegate(Collections.Array serializedData,
+ [MaybeNullWhen(false)] out Delegate @delegate)
+ {
+ @delegate = null;
+
if (serializedData.Count == 1)
{
- object elem = serializedData[0];
+ var elem = serializedData[0].Obj;
+
+ if (elem == null)
+ return false;
if (elem is Collections.Array multiCastData)
return TryDeserializeDelegate(multiCastData, out @delegate);
@@ -225,20 +345,23 @@ namespace Godot
return TryDeserializeSingleDelegate((byte[])elem, out @delegate);
}
- @delegate = null;
-
var delegates = new List<Delegate>(serializedData.Count);
- foreach (object elem in serializedData)
+ foreach (Variant variantElem in serializedData)
{
+ var elem = variantElem.Obj;
+
+ if (elem == null)
+ continue;
+
if (elem is Collections.Array multiCastData)
{
- if (TryDeserializeDelegate(multiCastData, out Delegate oneDelegate))
+ if (TryDeserializeDelegate(multiCastData, out Delegate? oneDelegate))
delegates.Add(oneDelegate);
}
else
{
- if (TryDeserializeSingleDelegate((byte[])elem, out Delegate oneDelegate))
+ if (TryDeserializeSingleDelegate((byte[])elem, out Delegate? oneDelegate))
delegates.Add(oneDelegate);
}
}
@@ -246,11 +369,11 @@ namespace Godot
if (delegates.Count <= 0)
return false;
- @delegate = delegates.Count == 1 ? delegates[0] : Delegate.Combine(delegates.ToArray());
+ @delegate = delegates.Count == 1 ? delegates[0] : Delegate.Combine(delegates.ToArray())!;
return true;
}
- private static bool TryDeserializeSingleDelegate(byte[] buffer, out Delegate @delegate)
+ private static bool TryDeserializeSingleDelegate(byte[] buffer, [MaybeNullWhen(false)] out Delegate @delegate)
{
@delegate = null;
@@ -263,49 +386,59 @@ namespace Godot
{
case TargetKind.Static:
{
- Type delegateType = DeserializeType(reader);
+ Type? delegateType = DeserializeType(reader);
if (delegateType == null)
return false;
- if (!TryDeserializeMethodInfo(reader, out MethodInfo methodInfo))
+ if (!TryDeserializeMethodInfo(reader, out MethodInfo? methodInfo))
+ return false;
+
+ @delegate = Delegate.CreateDelegate(delegateType, null, methodInfo, throwOnBindFailure: false);
+
+ if (@delegate == null)
return false;
- @delegate = Delegate.CreateDelegate(delegateType, null, methodInfo);
return true;
}
case TargetKind.GodotObject:
{
ulong objectId = reader.ReadUInt64();
+ // ReSharper disable once RedundantNameQualifier
Godot.Object godotObject = GD.InstanceFromId(objectId);
if (godotObject == null)
return false;
- Type delegateType = DeserializeType(reader);
+ Type? delegateType = DeserializeType(reader);
if (delegateType == null)
return false;
- if (!TryDeserializeMethodInfo(reader, out MethodInfo methodInfo))
+ if (!TryDeserializeMethodInfo(reader, out MethodInfo? methodInfo))
+ return false;
+
+ @delegate = Delegate.CreateDelegate(delegateType, godotObject, methodInfo,
+ throwOnBindFailure: false);
+
+ if (@delegate == null)
return false;
- @delegate = Delegate.CreateDelegate(delegateType, godotObject, methodInfo);
return true;
}
case TargetKind.CompilerGenerated:
{
- Type targetType = DeserializeType(reader);
+ Type? targetType = DeserializeType(reader);
if (targetType == null)
return false;
- Type delegateType = DeserializeType(reader);
+ Type? delegateType = DeserializeType(reader);
if (delegateType == null)
return false;
- if (!TryDeserializeMethodInfo(reader, out MethodInfo methodInfo))
+ if (!TryDeserializeMethodInfo(reader, out MethodInfo? methodInfo))
return false;
int fieldCount = reader.ReadInt32();
- object recreatedTarget = Activator.CreateInstance(targetType);
+ object recreatedTarget = Activator.CreateInstance(targetType)!;
for (int i = 0; i < fieldCount; i++)
{
@@ -313,11 +446,17 @@ namespace Godot
int valueBufferLength = reader.ReadInt32();
byte[] valueBuffer = reader.ReadBytes(valueBufferLength);
- FieldInfo fieldInfo = targetType.GetField(name, BindingFlags.Instance | BindingFlags.Public);
- fieldInfo?.SetValue(recreatedTarget, GD.Bytes2Var(valueBuffer));
+ FieldInfo? fieldInfo = targetType.GetField(name,
+ BindingFlags.Instance | BindingFlags.Public);
+ fieldInfo?.SetValue(recreatedTarget, GD.BytesToVar(valueBuffer));
}
- @delegate = Delegate.CreateDelegate(delegateType, recreatedTarget, methodInfo);
+ @delegate = Delegate.CreateDelegate(delegateType, recreatedTarget, methodInfo,
+ throwOnBindFailure: false);
+
+ if (@delegate == null)
+ return false;
+
return true;
}
default:
@@ -326,18 +465,22 @@ namespace Godot
}
}
- private static bool TryDeserializeMethodInfo(BinaryReader reader, out MethodInfo methodInfo)
+ private static bool TryDeserializeMethodInfo(BinaryReader reader,
+ [MaybeNullWhen(false)] out MethodInfo methodInfo)
{
methodInfo = null;
- Type declaringType = DeserializeType(reader);
+ Type? declaringType = DeserializeType(reader);
+
+ if (declaringType == null)
+ return false;
string methodName = reader.ReadString();
int flags = reader.ReadInt32();
bool hasReturn = reader.ReadBoolean();
- Type returnType = hasReturn ? DeserializeType(reader) : typeof(void);
+ Type? returnType = hasReturn ? DeserializeType(reader) : typeof(void);
int parametersCount = reader.ReadInt32();
@@ -347,7 +490,7 @@ namespace Godot
for (int i = 0; i < parametersCount; i++)
{
- Type parameterType = DeserializeType(reader);
+ Type? parameterType = DeserializeType(reader);
if (parameterType == null)
return false;
parameterTypes[i] = parameterType;
@@ -361,15 +504,23 @@ namespace Godot
return methodInfo != null && methodInfo.ReturnType == returnType;
}
- private static Type DeserializeType(BinaryReader reader)
+ private static Type? DeserializeType(BinaryReader reader)
{
int genericArgumentsCount = reader.ReadInt32();
if (genericArgumentsCount == -1)
return null;
- string assemblyQualifiedName = reader.ReadString();
- var type = Type.GetType(assemblyQualifiedName);
+ string assemblyName = reader.ReadString();
+
+ if (assemblyName.Length == 0)
+ {
+ GD.PushError($"Missing assembly name of type when attempting to deserialize delegate");
+ return null;
+ }
+
+ string typeFullName = reader.ReadString();
+ var type = ReflectionUtils.FindTypeInLoadedAssemblies(assemblyName, typeFullName);
if (type == null)
return null; // Type not found
@@ -380,7 +531,7 @@ namespace Godot
for (int i = 0; i < genericArgumentsCount; i++)
{
- Type genericArgumentType = DeserializeType(reader);
+ Type? genericArgumentType = DeserializeType(reader);
if (genericArgumentType == null)
return null;
genericArgumentTypes[i] = genericArgumentType;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
index e80b6af68f..93103d0f6b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dictionary.cs
@@ -1,79 +1,50 @@
using System;
using System.Collections.Generic;
using System.Collections;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using Godot.NativeInterop;
namespace Godot.Collections
{
- internal class DictionarySafeHandle : SafeHandle
- {
- public DictionarySafeHandle(IntPtr handle) : base(IntPtr.Zero, true)
- {
- this.handle = handle;
- }
-
- public override bool IsInvalid
- {
- get { return handle == IntPtr.Zero; }
- }
-
- protected override bool ReleaseHandle()
- {
- Dictionary.godot_icall_Dictionary_Dtor(handle);
- return true;
- }
- }
-
/// <summary>
/// Wrapper around Godot's Dictionary class, a dictionary of Variant
/// typed elements allocated in the engine in C++. Useful when
/// interfacing with the engine.
/// </summary>
- public class Dictionary : IDictionary, IDisposable
+ public sealed class Dictionary :
+ IDictionary<Variant, Variant>,
+ IReadOnlyDictionary<Variant, Variant>,
+ IDisposable
{
- private DictionarySafeHandle _safeHandle;
- private bool _disposed = false;
+ internal godot_dictionary.movable NativeValue;
+
+ private WeakReference<IDisposable> _weakReferenceToSelf;
/// <summary>
/// Constructs a new empty <see cref="Dictionary"/>.
/// </summary>
public Dictionary()
{
- _safeHandle = new DictionarySafeHandle(godot_icall_Dictionary_Ctor());
+ NativeValue = (godot_dictionary.movable)NativeFuncs.godotsharp_dictionary_new();
+ _weakReferenceToSelf = DisposablesTracker.RegisterDisposable(this);
}
- /// <summary>
- /// Constructs a new <see cref="Dictionary"/> from the given dictionary's elements.
- /// </summary>
- /// <param name="dictionary">The dictionary to construct from.</param>
- /// <returns>A new Godot Dictionary.</returns>
- public Dictionary(IDictionary dictionary) : this()
- {
- if (dictionary == null)
- throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'");
-
- foreach (DictionaryEntry entry in dictionary)
- Add(entry.Key, entry.Value);
- }
-
- internal Dictionary(DictionarySafeHandle handle)
+ private Dictionary(godot_dictionary nativeValueToOwn)
{
- _safeHandle = handle;
+ NativeValue = (godot_dictionary.movable)(nativeValueToOwn.IsAllocated ?
+ nativeValueToOwn :
+ NativeFuncs.godotsharp_dictionary_new());
+ _weakReferenceToSelf = DisposablesTracker.RegisterDisposable(this);
}
- internal Dictionary(IntPtr handle)
- {
- _safeHandle = new DictionarySafeHandle(handle);
- }
+ // Explicit name to make it very clear
+ internal static Dictionary CreateTakingOwnershipOfDisposableValue(godot_dictionary nativeValueToOwn)
+ => new Dictionary(nativeValueToOwn);
- internal IntPtr GetPtr()
+ ~Dictionary()
{
- if (_disposed)
- throw new ObjectDisposedException(GetType().FullName);
-
- return _safeHandle.DangerousGetHandle();
+ Dispose(false);
}
/// <summary>
@@ -81,16 +52,19 @@ namespace Godot.Collections
/// </summary>
public void Dispose()
{
- if (_disposed)
- return;
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
- if (_safeHandle != null)
+ public void Dispose(bool disposing)
+ {
+ // Always dispose `NativeValue` even if disposing is true
+ NativeValue.DangerousSelfRef.Dispose();
+
+ if (_weakReferenceToSelf != null)
{
- _safeHandle.Dispose();
- _safeHandle = null;
+ DisposablesTracker.UnregisterDisposable(_weakReferenceToSelf);
}
-
- _disposed = true;
}
/// <summary>
@@ -100,7 +74,10 @@ namespace Godot.Collections
/// <returns>A new Godot Dictionary.</returns>
public Dictionary Duplicate(bool deep = false)
{
- return new Dictionary(godot_icall_Dictionary_Duplicate(GetPtr(), deep));
+ godot_dictionary newDictionary;
+ var self = (godot_dictionary)NativeValue;
+ NativeFuncs.godotsharp_dictionary_duplicate(ref self, deep.ToGodotBool(), out newDictionary);
+ return CreateTakingOwnershipOfDisposableValue(newDictionary);
}
// IDictionary
@@ -108,176 +85,250 @@ namespace Godot.Collections
/// <summary>
/// Gets the collection of keys in this <see cref="Dictionary"/>.
/// </summary>
- public ICollection Keys
+ public ICollection<Variant> Keys
{
get
{
- IntPtr handle = godot_icall_Dictionary_Keys(GetPtr());
- return new Array(new ArraySafeHandle(handle));
+ godot_array keysArray;
+ var self = (godot_dictionary)NativeValue;
+ NativeFuncs.godotsharp_dictionary_keys(ref self, out keysArray);
+ return Array.CreateTakingOwnershipOfDisposableValue(keysArray);
}
}
/// <summary>
/// Gets the collection of elements in this <see cref="Dictionary"/>.
/// </summary>
- public ICollection Values
+ public ICollection<Variant> Values
{
get
{
- IntPtr handle = godot_icall_Dictionary_Values(GetPtr());
- return new Array(new ArraySafeHandle(handle));
+ godot_array valuesArray;
+ var self = (godot_dictionary)NativeValue;
+ NativeFuncs.godotsharp_dictionary_values(ref self, out valuesArray);
+ return Array.CreateTakingOwnershipOfDisposableValue(valuesArray);
}
}
+ IEnumerable<Variant> IReadOnlyDictionary<Variant, Variant>.Keys => Keys;
+
+ IEnumerable<Variant> IReadOnlyDictionary<Variant, Variant>.Values => Values;
+
private (Array keys, Array values, int count) GetKeyValuePairs()
{
- int count = godot_icall_Dictionary_KeyValuePairs(GetPtr(), out IntPtr keysHandle, out IntPtr valuesHandle);
- Array keys = new Array(new ArraySafeHandle(keysHandle));
- Array values = new Array(new ArraySafeHandle(valuesHandle));
- return (keys, values, count);
- }
+ var self = (godot_dictionary)NativeValue;
- bool IDictionary.IsFixedSize => false;
+ godot_array keysArray;
+ NativeFuncs.godotsharp_dictionary_keys(ref self, out keysArray);
+ var keys = Array.CreateTakingOwnershipOfDisposableValue(keysArray);
- bool IDictionary.IsReadOnly => false;
+ godot_array valuesArray;
+ NativeFuncs.godotsharp_dictionary_keys(ref self, out valuesArray);
+ var values = Array.CreateTakingOwnershipOfDisposableValue(valuesArray);
+
+ int count = NativeFuncs.godotsharp_dictionary_count(ref self);
+
+ return (keys, values, count);
+ }
/// <summary>
- /// Returns the object at the given <paramref name="key"/>.
+ /// Returns the value at the given <paramref name="key"/>.
/// </summary>
- /// <value>The object at the given <paramref name="key"/>.</value>
- public object this[object key]
+ /// <value>The value at the given <paramref name="key"/>.</value>
+ public Variant this[Variant key]
{
- get => godot_icall_Dictionary_GetValue(GetPtr(), key);
- set => godot_icall_Dictionary_SetValue(GetPtr(), key, value);
+ get
+ {
+ var self = (godot_dictionary)NativeValue;
+
+ if (NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
+ (godot_variant)key.NativeVar, out godot_variant value).ToBool())
+ {
+ return Variant.CreateTakingOwnershipOfDisposableValue(value);
+ }
+ else
+ {
+ throw new KeyNotFoundException();
+ }
+ }
+ set
+ {
+ var self = (godot_dictionary)NativeValue;
+ NativeFuncs.godotsharp_dictionary_set_value(ref self,
+ (godot_variant)key.NativeVar, (godot_variant)value.NativeVar);
+ }
}
/// <summary>
- /// Adds an object <paramref name="value"/> at key <paramref name="key"/>
+ /// Adds an value <paramref name="value"/> at key <paramref name="key"/>
/// to this <see cref="Dictionary"/>.
/// </summary>
- /// <param name="key">The key at which to add the object.</param>
- /// <param name="value">The object to add.</param>
- public void Add(object key, object value) => godot_icall_Dictionary_Add(GetPtr(), key, value);
+ /// <param name="key">The key at which to add the value.</param>
+ /// <param name="value">The value to add.</param>
+ public void Add(Variant key, Variant value)
+ {
+ var variantKey = (godot_variant)key.NativeVar;
+ var self = (godot_dictionary)NativeValue;
+
+ if (NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool())
+ throw new ArgumentException("An element with the same key already exists.", nameof(key));
+
+ godot_variant variantValue = (godot_variant)value.NativeVar;
+ NativeFuncs.godotsharp_dictionary_add(ref self, variantKey, variantValue);
+ }
+
+ void ICollection<KeyValuePair<Variant, Variant>>.Add(KeyValuePair<Variant, Variant> item)
+ => Add(item.Key, item.Value);
/// <summary>
/// Erases all items from this <see cref="Dictionary"/>.
/// </summary>
- public void Clear() => godot_icall_Dictionary_Clear(GetPtr());
+ public void Clear()
+ {
+ var self = (godot_dictionary)NativeValue;
+ NativeFuncs.godotsharp_dictionary_clear(ref self);
+ }
/// <summary>
/// Checks if this <see cref="Dictionary"/> contains the given key.
/// </summary>
/// <param name="key">The key to look for.</param>
/// <returns>Whether or not this dictionary contains the given key.</returns>
- public bool Contains(object key) => godot_icall_Dictionary_ContainsKey(GetPtr(), key);
+ public bool ContainsKey(Variant key)
+ {
+ var self = (godot_dictionary)NativeValue;
+ return NativeFuncs.godotsharp_dictionary_contains_key(ref self, (godot_variant)key.NativeVar).ToBool();
+ }
- /// <summary>
- /// Gets an enumerator for this <see cref="Dictionary"/>.
- /// </summary>
- /// <returns>An enumerator.</returns>
- public IDictionaryEnumerator GetEnumerator() => new DictionaryEnumerator(this);
+ public bool Contains(KeyValuePair<Variant, Variant> item)
+ {
+ godot_variant variantKey = (godot_variant)item.Key.NativeVar;
+ var self = (godot_dictionary)NativeValue;
+ bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
+ variantKey, out godot_variant retValue).ToBool();
+
+ using (retValue)
+ {
+ if (!found)
+ return false;
+
+ godot_variant variantValue = (godot_variant)item.Value.NativeVar;
+ return NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool();
+ }
+ }
/// <summary>
/// Removes an element from this <see cref="Dictionary"/> by key.
/// </summary>
/// <param name="key">The key of the element to remove.</param>
- public void Remove(object key) => godot_icall_Dictionary_RemoveKey(GetPtr(), key);
+ public bool Remove(Variant key)
+ {
+ var self = (godot_dictionary)NativeValue;
+ return NativeFuncs.godotsharp_dictionary_remove_key(ref self, (godot_variant)key.NativeVar).ToBool();
+ }
- // ICollection
+ public bool Remove(KeyValuePair<Variant, Variant> item)
+ {
+ godot_variant variantKey = (godot_variant)item.Key.NativeVar;
+ var self = (godot_dictionary)NativeValue;
+ bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
+ variantKey, out godot_variant retValue).ToBool();
+
+ using (retValue)
+ {
+ if (!found)
+ return false;
- object ICollection.SyncRoot => this;
+ godot_variant variantValue = (godot_variant)item.Value.NativeVar;
+ if (NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool())
+ {
+ return NativeFuncs.godotsharp_dictionary_remove_key(
+ ref self, variantKey).ToBool();
+ }
- bool ICollection.IsSynchronized => false;
+ return false;
+ }
+ }
/// <summary>
/// Returns the number of elements in this <see cref="Dictionary"/>.
/// This is also known as the size or length of the dictionary.
/// </summary>
/// <returns>The number of elements.</returns>
- public int Count => godot_icall_Dictionary_Count(GetPtr());
+ public int Count
+ {
+ get
+ {
+ var self = (godot_dictionary)NativeValue;
+ return NativeFuncs.godotsharp_dictionary_count(ref self);
+ }
+ }
+
+ bool ICollection<KeyValuePair<Variant, Variant>>.IsReadOnly => false;
+
+ public bool TryGetValue(Variant key, out Variant value)
+ {
+ var self = (godot_dictionary)NativeValue;
+ bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
+ (godot_variant)key.NativeVar, out godot_variant retValue).ToBool();
+
+ value = found ? Variant.CreateTakingOwnershipOfDisposableValue(retValue) : default;
+
+ return found;
+ }
/// <summary>
- /// Copies the elements of this <see cref="Dictionary"/> to the given
- /// untyped C# array, starting at the given index.
+ /// Copies the elements of this <see cref="Dictionary"/> to the given untyped
+ /// <see cref="KeyValuePair{TKey, TValue}"/> array, starting at the given index.
/// </summary>
/// <param name="array">The array to copy to.</param>
- /// <param name="index">The index to start at.</param>
- public void CopyTo(System.Array array, int index)
+ /// <param name="arrayIndex">The index to start at.</param>
+ public void CopyTo(KeyValuePair<Variant, Variant>[] array, int arrayIndex)
{
if (array == null)
throw new ArgumentNullException(nameof(array), "Value cannot be null.");
- if (index < 0)
- throw new ArgumentOutOfRangeException(nameof(index), "Number was less than the array's lower bound in the first dimension.");
+ if (arrayIndex < 0)
+ throw new ArgumentOutOfRangeException(nameof(arrayIndex),
+ "Number was less than the array's lower bound in the first dimension.");
var (keys, values, count) = GetKeyValuePairs();
- if (array.Length < (index + count))
- throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
+ if (array.Length < (arrayIndex + count))
+ throw new ArgumentException(
+ "Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
for (int i = 0; i < count; i++)
{
- array.SetValue(new DictionaryEntry(keys[i], values[i]), index);
- index++;
+ array[arrayIndex] = new(keys[i], values[i]);
+ arrayIndex++;
}
}
// IEnumerable
- IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
-
- private class DictionaryEnumerator : IDictionaryEnumerator
+ /// <summary>
+ /// Gets an enumerator for this <see cref="Dictionary"/>.
+ /// </summary>
+ /// <returns>An enumerator.</returns>
+ public IEnumerator<KeyValuePair<Variant, Variant>> GetEnumerator()
{
- private readonly Dictionary _dictionary;
- private readonly int _count;
- private int _index = -1;
- private bool _dirty = true;
-
- private DictionaryEntry _entry;
-
- public DictionaryEnumerator(Dictionary dictionary)
- {
- _dictionary = dictionary;
- _count = dictionary.Count;
- }
-
- public object Current => Entry;
-
- public DictionaryEntry Entry
- {
- get
- {
- if (_dirty)
- {
- UpdateEntry();
- }
- return _entry;
- }
- }
-
- private void UpdateEntry()
+ for (int i = 0; i < Count; i++)
{
- _dirty = false;
- godot_icall_Dictionary_KeyValuePairAt(_dictionary.GetPtr(), _index, out object key, out object value);
- _entry = new DictionaryEntry(key, value);
+ yield return GetKeyValuePair(i);
}
+ }
- public object Key => Entry.Key;
-
- public object Value => Entry.Value;
-
- public bool MoveNext()
- {
- _index++;
- _dirty = true;
- return _index < _count;
- }
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
- public void Reset()
- {
- _index = -1;
- _dirty = true;
- }
+ private KeyValuePair<Variant, Variant> GetKeyValuePair(int index)
+ {
+ var self = (godot_dictionary)NativeValue;
+ NativeFuncs.godotsharp_dictionary_key_value_pair_at(ref self, index,
+ out godot_variant key,
+ out godot_variant value);
+ return new KeyValuePair<Variant, Variant>(Variant.CreateTakingOwnershipOfDisposableValue(key),
+ Variant.CreateTakingOwnershipOfDisposableValue(value));
}
/// <summary>
@@ -286,74 +337,11 @@ namespace Godot.Collections
/// <returns>A string representation of this dictionary.</returns>
public override string ToString()
{
- return godot_icall_Dictionary_ToString(GetPtr());
+ var self = (godot_dictionary)NativeValue;
+ NativeFuncs.godotsharp_dictionary_to_string(ref self, out godot_string str);
+ using (str)
+ return Marshaling.ConvertStringToManaged(str);
}
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_Dictionary_Ctor();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Dictionary_Dtor(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern object godot_icall_Dictionary_GetValue(IntPtr ptr, object key);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern object godot_icall_Dictionary_GetValue_Generic(IntPtr ptr, object key, int valTypeEncoding, IntPtr valTypeClass);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Dictionary_SetValue(IntPtr ptr, object key, object value);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_Dictionary_Keys(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_Dictionary_Values(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern int godot_icall_Dictionary_Count(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern int godot_icall_Dictionary_KeyValuePairs(IntPtr ptr, out IntPtr keys, out IntPtr values);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Dictionary_KeyValuePairAt(IntPtr ptr, int index, out object key, out object value);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Dictionary_KeyValuePairAt_Generic(IntPtr ptr, int index, out object key, out object value, int valueTypeEncoding, IntPtr valueTypeClass);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Dictionary_Add(IntPtr ptr, object key, object value);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Dictionary_Clear(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool godot_icall_Dictionary_Contains(IntPtr ptr, object key, object value);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool godot_icall_Dictionary_ContainsKey(IntPtr ptr, object key);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_Dictionary_Duplicate(IntPtr ptr, bool deep);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool godot_icall_Dictionary_RemoveKey(IntPtr ptr, object key);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool godot_icall_Dictionary_Remove(IntPtr ptr, object key, object value);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool godot_icall_Dictionary_TryGetValue(IntPtr ptr, object key, out object value);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool godot_icall_Dictionary_TryGetValue_Generic(IntPtr ptr, object key, out object value, int valTypeEncoding, IntPtr valTypeClass);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Dictionary_Generic_GetValueTypeInfo(Type valueType, out int valTypeEncoding, out IntPtr valTypeClass);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern string godot_icall_Dictionary_ToString(IntPtr ptr);
}
/// <summary>
@@ -364,16 +352,51 @@ namespace Godot.Collections
/// </summary>
/// <typeparam name="TKey">The type of the dictionary's keys.</typeparam>
/// <typeparam name="TValue">The type of the dictionary's values.</typeparam>
- public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>
+ public class Dictionary<[MustBeVariant] TKey, [MustBeVariant] TValue> :
+ IDictionary<TKey, TValue>,
+ IReadOnlyDictionary<TKey, TValue>
{
- private readonly Dictionary _objectDict;
+ // ReSharper disable StaticMemberInGenericType
+ // Warning is about unique static fields being created for each generic type combination:
+ // https://www.jetbrains.com/help/resharper/StaticMemberInGenericType.html
+ // In our case this is exactly what we want.
+
+ private static unsafe delegate* managed<in TKey, godot_variant> _convertKeyToVariantCallback;
+ private static unsafe delegate* managed<in godot_variant, TKey> _convertKeyToManagedCallback;
+ private static unsafe delegate* managed<in TValue, godot_variant> _convertValueToVariantCallback;
+ private static unsafe delegate* managed<in godot_variant, TValue> _convertValueToManagedCallback;
+
+ // ReSharper restore StaticMemberInGenericType
+
+ static unsafe Dictionary()
+ {
+ _convertKeyToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<TKey>();
+ _convertKeyToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<TKey>();
+ _convertValueToVariantCallback = VariantConversionCallbacks.GetToVariantCallback<TValue>();
+ _convertValueToManagedCallback = VariantConversionCallbacks.GetToManagedCallback<TValue>();
+ }
+
+ private static unsafe void ValidateVariantConversionCallbacks()
+ {
+ if (_convertKeyToVariantCallback == null || _convertKeyToManagedCallback == null)
+ {
+ throw new InvalidOperationException(
+ $"The dictionary key type is not supported for conversion to Variant: '{typeof(TKey).FullName}'.");
+ }
+
+ if (_convertValueToVariantCallback == null || _convertValueToManagedCallback == null)
+ {
+ throw new InvalidOperationException(
+ $"The dictionary value type is not supported for conversion to Variant: '{typeof(TValue).FullName}'.");
+ }
+ }
- internal static int valTypeEncoding;
- internal static IntPtr valTypeClass;
+ private readonly Dictionary _underlyingDict;
- static Dictionary()
+ internal ref godot_dictionary.movable NativeValue
{
- Dictionary.godot_icall_Dictionary_Generic_GetValueTypeInfo(typeof(TValue), out valTypeEncoding, out valTypeClass);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => ref _underlyingDict.NativeValue;
}
/// <summary>
@@ -381,7 +404,9 @@ namespace Godot.Collections
/// </summary>
public Dictionary()
{
- _objectDict = new Dictionary();
+ ValidateVariantConversionCallbacks();
+
+ _underlyingDict = new Dictionary();
}
/// <summary>
@@ -391,19 +416,15 @@ namespace Godot.Collections
/// <returns>A new Godot Dictionary.</returns>
public Dictionary(IDictionary<TKey, TValue> dictionary)
{
- _objectDict = new Dictionary();
+ ValidateVariantConversionCallbacks();
if (dictionary == null)
- throw new NullReferenceException($"Parameter '{nameof(dictionary)} cannot be null.'");
-
- // TODO: Can be optimized
+ throw new ArgumentNullException(nameof(dictionary));
- IntPtr godotDictionaryPtr = GetPtr();
+ _underlyingDict = new Dictionary();
foreach (KeyValuePair<TKey, TValue> entry in dictionary)
- {
- Dictionary.godot_icall_Dictionary_Add(godotDictionaryPtr, entry.Key, entry.Value);
- }
+ Add(entry.Key, entry.Value);
}
/// <summary>
@@ -413,18 +434,15 @@ namespace Godot.Collections
/// <returns>A new Godot Dictionary.</returns>
public Dictionary(Dictionary dictionary)
{
- _objectDict = dictionary;
- }
+ ValidateVariantConversionCallbacks();
- internal Dictionary(IntPtr handle)
- {
- _objectDict = new Dictionary(handle);
+ _underlyingDict = dictionary;
}
- internal Dictionary(DictionarySafeHandle handle)
- {
- _objectDict = new Dictionary(handle);
- }
+ // Explicit name to make it very clear
+ internal static Dictionary<TKey, TValue> CreateTakingOwnershipOfDisposableValue(
+ godot_dictionary nativeValueToOwn)
+ => new Dictionary<TKey, TValue>(Dictionary.CreateTakingOwnershipOfDisposableValue(nativeValueToOwn));
/// <summary>
/// Converts this typed <see cref="Dictionary{TKey, TValue}"/> to an untyped <see cref="Dictionary"/>.
@@ -432,12 +450,7 @@ namespace Godot.Collections
/// <param name="from">The typed dictionary to convert.</param>
public static explicit operator Dictionary(Dictionary<TKey, TValue> from)
{
- return from._objectDict;
- }
-
- internal IntPtr GetPtr()
- {
- return _objectDict.GetPtr();
+ return from?._underlyingDict;
}
/// <summary>
@@ -447,7 +460,7 @@ namespace Godot.Collections
/// <returns>A new Godot Dictionary.</returns>
public Dictionary<TKey, TValue> Duplicate(bool deep = false)
{
- return new Dictionary<TKey, TValue>(_objectDict.Duplicate(deep));
+ return new Dictionary<TKey, TValue>(_underlyingDict.Duplicate(deep));
}
// IDictionary<TKey, TValue>
@@ -456,10 +469,32 @@ namespace Godot.Collections
/// Returns the value at the given <paramref name="key"/>.
/// </summary>
/// <value>The value at the given <paramref name="key"/>.</value>
- public TValue this[TKey key]
+ public unsafe TValue this[TKey key]
{
- get { return (TValue)Dictionary.godot_icall_Dictionary_GetValue_Generic(_objectDict.GetPtr(), key, valTypeEncoding, valTypeClass); }
- set { _objectDict[key] = value; }
+ get
+ {
+ using var variantKey = _convertKeyToVariantCallback(key);
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+
+ if (NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
+ variantKey, out godot_variant value).ToBool())
+ {
+ using (value)
+ return _convertValueToManagedCallback(value);
+ }
+ else
+ {
+ throw new KeyNotFoundException();
+ }
+ }
+ set
+ {
+ using var variantKey = _convertKeyToVariantCallback(key);
+ using var variantValue = _convertValueToVariantCallback(value);
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+ NativeFuncs.godotsharp_dictionary_set_value(ref self,
+ variantKey, variantValue);
+ }
}
/// <summary>
@@ -469,8 +504,10 @@ namespace Godot.Collections
{
get
{
- IntPtr handle = Dictionary.godot_icall_Dictionary_Keys(_objectDict.GetPtr());
- return new Array<TKey>(new ArraySafeHandle(handle));
+ godot_array keyArray;
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+ NativeFuncs.godotsharp_dictionary_keys(ref self, out keyArray);
+ return Array<TKey>.CreateTakingOwnershipOfDisposableValue(keyArray);
}
}
@@ -481,15 +518,30 @@ namespace Godot.Collections
{
get
{
- IntPtr handle = Dictionary.godot_icall_Dictionary_Values(_objectDict.GetPtr());
- return new Array<TValue>(new ArraySafeHandle(handle));
+ godot_array valuesArray;
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+ NativeFuncs.godotsharp_dictionary_values(ref self, out valuesArray);
+ return Array<TValue>.CreateTakingOwnershipOfDisposableValue(valuesArray);
}
}
- private KeyValuePair<TKey, TValue> GetKeyValuePair(int index)
+ IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => Keys;
+
+ IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => Values;
+
+ private unsafe KeyValuePair<TKey, TValue> GetKeyValuePair(int index)
{
- Dictionary.godot_icall_Dictionary_KeyValuePairAt_Generic(GetPtr(), index, out object key, out object value, valTypeEncoding, valTypeClass);
- return new KeyValuePair<TKey, TValue>((TKey)key, (TValue)value);
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+ NativeFuncs.godotsharp_dictionary_key_value_pair_at(ref self, index,
+ out godot_variant key,
+ out godot_variant value);
+ using (key)
+ using (value)
+ {
+ return new KeyValuePair<TKey, TValue>(
+ _convertKeyToManagedCallback(key),
+ _convertValueToManagedCallback(value));
+ }
}
/// <summary>
@@ -498,9 +550,16 @@ namespace Godot.Collections
/// </summary>
/// <param name="key">The key at which to add the object.</param>
/// <param name="value">The object to add.</param>
- public void Add(TKey key, TValue value)
+ public unsafe void Add(TKey key, TValue value)
{
- _objectDict.Add(key, value);
+ using var variantKey = _convertKeyToVariantCallback(key);
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+
+ if (NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool())
+ throw new ArgumentException("An element with the same key already exists.", nameof(key));
+
+ using var variantValue = _convertValueToVariantCallback(value);
+ NativeFuncs.godotsharp_dictionary_add(ref self, variantKey, variantValue);
}
/// <summary>
@@ -508,18 +567,22 @@ namespace Godot.Collections
/// </summary>
/// <param name="key">The key to look for.</param>
/// <returns>Whether or not this dictionary contains the given key.</returns>
- public bool ContainsKey(TKey key)
+ public unsafe bool ContainsKey(TKey key)
{
- return _objectDict.Contains(key);
+ using var variantKey = _convertKeyToVariantCallback(key);
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+ return NativeFuncs.godotsharp_dictionary_contains_key(ref self, variantKey).ToBool();
}
/// <summary>
/// Removes an element from this <see cref="Dictionary{TKey, TValue}"/> by key.
/// </summary>
/// <param name="key">The key of the element to remove.</param>
- public bool Remove(TKey key)
+ public unsafe bool Remove(TKey key)
{
- return Dictionary.godot_icall_Dictionary_RemoveKey(GetPtr(), key);
+ using var variantKey = _convertKeyToVariantCallback(key);
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+ return NativeFuncs.godotsharp_dictionary_remove_key(ref self, variantKey).ToBool();
}
/// <summary>
@@ -528,10 +591,16 @@ namespace Godot.Collections
/// <param name="key">The key of the element to get.</param>
/// <param name="value">The value at the given <paramref name="key"/>.</param>
/// <returns>If an object was found for the given <paramref name="key"/>.</returns>
- public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
+ public unsafe bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
{
- bool found = Dictionary.godot_icall_Dictionary_TryGetValue_Generic(GetPtr(), key, out object retValue, valTypeEncoding, valTypeClass);
- value = found ? (TValue)retValue : default;
+ using var variantKey = _convertKeyToVariantCallback(key);
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+ bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
+ variantKey, out godot_variant retValue).ToBool();
+
+ using (retValue)
+ value = found ? _convertValueToManagedCallback(retValue) : default;
+
return found;
}
@@ -542,29 +611,33 @@ namespace Godot.Collections
/// This is also known as the size or length of the dictionary.
/// </summary>
/// <returns>The number of elements.</returns>
- public int Count
- {
- get { return _objectDict.Count; }
- }
+ public int Count => _underlyingDict.Count;
bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => false;
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
- {
- _objectDict.Add(item.Key, item.Value);
- }
+ => Add(item.Key, item.Value);
/// <summary>
/// Erases all the items from this <see cref="Dictionary{TKey, TValue}"/>.
/// </summary>
- public void Clear()
- {
- _objectDict.Clear();
- }
+ public void Clear() => _underlyingDict.Clear();
- bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
+ unsafe bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
{
- return _objectDict.Contains(new KeyValuePair<object, object>(item.Key, item.Value));
+ using var variantKey = _convertKeyToVariantCallback(item.Key);
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+ bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
+ variantKey, out godot_variant retValue).ToBool();
+
+ using (retValue)
+ {
+ if (!found)
+ return false;
+
+ using var variantValue = _convertValueToVariantCallback(item.Value);
+ return NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool();
+ }
}
/// <summary>
@@ -579,12 +652,14 @@ namespace Godot.Collections
throw new ArgumentNullException(nameof(array), "Value cannot be null.");
if (arrayIndex < 0)
- throw new ArgumentOutOfRangeException(nameof(arrayIndex), "Number was less than the array's lower bound in the first dimension.");
+ throw new ArgumentOutOfRangeException(nameof(arrayIndex),
+ "Number was less than the array's lower bound in the first dimension.");
int count = Count;
if (array.Length < (arrayIndex + count))
- throw new ArgumentException("Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
+ throw new ArgumentException(
+ "Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
for (int i = 0; i < count; i++)
{
@@ -593,10 +668,27 @@ namespace Godot.Collections
}
}
- bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
+ unsafe bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
{
- return Dictionary.godot_icall_Dictionary_Remove(GetPtr(), item.Key, item.Value);
- ;
+ using var variantKey = _convertKeyToVariantCallback(item.Key);
+ var self = (godot_dictionary)_underlyingDict.NativeValue;
+ bool found = NativeFuncs.godotsharp_dictionary_try_get_value(ref self,
+ variantKey, out godot_variant retValue).ToBool();
+
+ using (retValue)
+ {
+ if (!found)
+ return false;
+
+ using var variantValue = _convertValueToVariantCallback(item.Value);
+ if (NativeFuncs.godotsharp_variant_equals(variantValue, retValue).ToBool())
+ {
+ return NativeFuncs.godotsharp_dictionary_remove_key(
+ ref self, variantKey).ToBool();
+ }
+
+ return false;
+ }
}
// IEnumerable<KeyValuePair<TKey, TValue>>
@@ -613,15 +705,18 @@ namespace Godot.Collections
}
}
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
/// <summary>
/// Converts this <see cref="Dictionary{TKey, TValue}"/> to a string.
/// </summary>
/// <returns>A string representation of this dictionary.</returns>
- public override string ToString() => _objectDict.ToString();
+ public override string ToString() => _underlyingDict.ToString();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Dictionary<TKey, TValue> from) => Variant.CreateFrom(from);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Dictionary<TKey, TValue>(Variant from) => from.AsGodotDictionary<TKey, TValue>();
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs
index 6475237002..e6cb4171a7 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Dispatcher.cs
@@ -1,20 +1,16 @@
-using System.Runtime.CompilerServices;
+using System;
+using System.Runtime.InteropServices;
+using Godot.NativeInterop;
namespace Godot
{
public static class Dispatcher
{
- /// <summary>
- /// Implements an external instance of GodotTaskScheduler.
- /// </summary>
- /// <returns>A GodotTaskScheduler instance.</returns>
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern GodotTaskScheduler godot_icall_DefaultGodotTaskScheduler();
+ internal static GodotTaskScheduler DefaultGodotTaskScheduler;
- /// <summary>
- /// Initializes the synchronization context as the context of the GodotTaskScheduler.
- /// </summary>
- public static GodotSynchronizationContext SynchronizationContext =>
- godot_icall_DefaultGodotTaskScheduler().Context;
+ internal static void InitializeDefaultGodotTaskScheduler()
+ => DefaultGodotTaskScheduler = new GodotTaskScheduler();
+
+ public static GodotSynchronizationContext SynchronizationContext => DefaultGodotTaskScheduler.Context;
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DisposablesTracker.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DisposablesTracker.cs
new file mode 100644
index 0000000000..421b588560
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DisposablesTracker.cs
@@ -0,0 +1,95 @@
+using System;
+using System.Collections.Concurrent;
+using System.Runtime.InteropServices;
+using Godot.NativeInterop;
+
+#nullable enable
+
+namespace Godot
+{
+ internal static class DisposablesTracker
+ {
+ [UnmanagedCallersOnly]
+ internal static void OnGodotShuttingDown()
+ {
+ try
+ {
+ OnGodotShuttingDownImpl();
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ }
+ }
+
+ private static void OnGodotShuttingDownImpl()
+ {
+ bool isStdoutVerbose;
+
+ try
+ {
+ isStdoutVerbose = OS.IsStdoutVerbose();
+ }
+ catch (ObjectDisposedException)
+ {
+ // OS singleton already disposed. Maybe OnUnloading was called twice.
+ isStdoutVerbose = false;
+ }
+
+ if (isStdoutVerbose)
+ GD.Print("Unloading: Disposing tracked instances...");
+
+ // Dispose Godot Objects first, and only then dispose other disposables
+ // like StringName, NodePath, Godot.Collections.Array/Dictionary, etc.
+ // The Godot Object Dispose() method may need any of the later instances.
+
+ foreach (WeakReference<Object> item in GodotObjectInstances.Keys)
+ {
+ if (item.TryGetTarget(out Object? self))
+ self.Dispose();
+ }
+
+ foreach (WeakReference<IDisposable> item in OtherInstances.Keys)
+ {
+ if (item.TryGetTarget(out IDisposable? self))
+ self.Dispose();
+ }
+
+ if (isStdoutVerbose)
+ GD.Print("Unloading: Finished disposing tracked instances.");
+ }
+
+ // ReSharper disable once RedundantNameQualifier
+ private static ConcurrentDictionary<WeakReference<Godot.Object>, byte> GodotObjectInstances { get; } =
+ new();
+
+ private static ConcurrentDictionary<WeakReference<IDisposable>, byte> OtherInstances { get; } =
+ new();
+
+ public static WeakReference<Object> RegisterGodotObject(Object godotObject)
+ {
+ var weakReferenceToSelf = new WeakReference<Object>(godotObject);
+ GodotObjectInstances.TryAdd(weakReferenceToSelf, 0);
+ return weakReferenceToSelf;
+ }
+
+ public static WeakReference<IDisposable> RegisterDisposable(IDisposable disposable)
+ {
+ var weakReferenceToSelf = new WeakReference<IDisposable>(disposable);
+ OtherInstances.TryAdd(weakReferenceToSelf, 0);
+ return weakReferenceToSelf;
+ }
+
+ public static void UnregisterGodotObject(Object godotObject, WeakReference<Object> weakReferenceToSelf)
+ {
+ if (!GodotObjectInstances.TryRemove(weakReferenceToSelf, out _))
+ throw new ArgumentException("Godot Object not registered.", nameof(weakReferenceToSelf));
+ }
+
+ public static void UnregisterDisposable(WeakReference<IDisposable> weakReference)
+ {
+ if (!OtherInstances.TryRemove(weakReference, out _))
+ throw new ArgumentException("Disposable not registered.", nameof(weakReference));
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DynamicObject.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DynamicObject.cs
deleted file mode 100644
index 26d5f9c796..0000000000
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DynamicObject.cs
+++ /dev/null
@@ -1,220 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Dynamic;
-using System.Linq.Expressions;
-using System.Runtime.CompilerServices;
-
-namespace Godot
-{
- /// <summary>
- /// Represents an <see cref="Object"/> whose members can be dynamically accessed at runtime through the Variant API.
- /// </summary>
- /// <remarks>
- /// <para>
- /// The <see cref="DynamicGodotObject"/> class enables access to the Variant
- /// members of a <see cref="Object"/> instance at runtime.
- /// </para>
- /// <para>
- /// This allows accessing the class members using their original names in the engine as well as the members from the
- /// script attached to the <see cref="Object"/>, regardless of the scripting language it was written in.
- /// </para>
- /// </remarks>
- /// <example>
- /// This sample shows how to use <see cref="DynamicGodotObject"/> to dynamically access the engine members of a <see cref="Object"/>.
- /// <code>
- /// dynamic sprite = GetNode("Sprite2D").DynamicGodotObject;
- /// sprite.add_child(this);
- ///
- /// if ((sprite.hframes * sprite.vframes) &gt; 0)
- /// sprite.frame = 0;
- /// </code>
- /// </example>
- /// <example>
- /// This sample shows how to use <see cref="DynamicGodotObject"/> to dynamically access the members of the script attached to a <see cref="Object"/>.
- /// <code>
- /// dynamic childNode = GetNode("ChildNode").DynamicGodotObject;
- ///
- /// if (childNode.print_allowed)
- /// {
- /// childNode.message = "Hello from C#";
- /// childNode.print_message(3);
- /// }
- /// </code>
- /// The <c>ChildNode</c> node has the following GDScript script attached:
- /// <code>
- /// // # ChildNode.gd
- /// // var print_allowed = true
- /// // var message = ""
- /// //
- /// // func print_message(times):
- /// // for i in times:
- /// // print(message)
- /// </code>
- /// </example>
- public class DynamicGodotObject : DynamicObject
- {
- /// <summary>
- /// Gets the <see cref="Object"/> associated with this <see cref="DynamicGodotObject"/>.
- /// </summary>
- public Object Value { get; }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="DynamicGodotObject"/> class.
- /// </summary>
- /// <param name="godotObject">
- /// The <see cref="Object"/> that will be associated with this <see cref="DynamicGodotObject"/>.
- /// </param>
- /// <exception cref="ArgumentNullException">
- /// Thrown when the <paramref name="godotObject"/> parameter is <see langword="null"/>.
- /// </exception>
- public DynamicGodotObject(Object godotObject)
- {
- if (godotObject == null)
- throw new ArgumentNullException(nameof(godotObject));
-
- Value = godotObject;
- }
-
- /// <inheritdoc/>
- public override IEnumerable<string> GetDynamicMemberNames()
- {
- return godot_icall_DynamicGodotObject_SetMemberList(Object.GetPtr(Value));
- }
-
- /// <inheritdoc/>
- public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result)
- {
- switch (binder.Operation)
- {
- case ExpressionType.Equal:
- case ExpressionType.NotEqual:
- if (binder.ReturnType == typeof(bool) || binder.ReturnType.IsAssignableFrom(typeof(bool)))
- {
- if (arg == null)
- {
- bool boolResult = Object.IsInstanceValid(Value);
-
- if (binder.Operation == ExpressionType.Equal)
- boolResult = !boolResult;
-
- result = boolResult;
- return true;
- }
-
- if (arg is Object other)
- {
- bool boolResult = (Value == other);
-
- if (binder.Operation == ExpressionType.NotEqual)
- boolResult = !boolResult;
-
- result = boolResult;
- return true;
- }
- }
-
- break;
- default:
- // We're not implementing operators <, <=, >, and >= (LessThan, LessThanOrEqual, GreaterThan, GreaterThanOrEqual).
- // These are used on the actual pointers in variant_op.cpp. It's better to let the user do that explicitly.
- break;
- }
-
- return base.TryBinaryOperation(binder, arg, out result);
- }
-
- /// <inheritdoc/>
- public override bool TryConvert(ConvertBinder binder, out object result)
- {
- if (binder.Type == typeof(Object))
- {
- result = Value;
- return true;
- }
-
- if (typeof(Object).IsAssignableFrom(binder.Type))
- {
- // Throws InvalidCastException when the cast fails
- result = Convert.ChangeType(Value, binder.Type);
- return true;
- }
-
- return base.TryConvert(binder, out result);
- }
-
- /// <inheritdoc/>
- public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
- {
- if (indexes.Length == 1)
- {
- if (indexes[0] is string name)
- {
- return godot_icall_DynamicGodotObject_GetMember(Object.GetPtr(Value), name, out result);
- }
- }
-
- return base.TryGetIndex(binder, indexes, out result);
- }
-
- /// <inheritdoc/>
- public override bool TryGetMember(GetMemberBinder binder, out object result)
- {
- return godot_icall_DynamicGodotObject_GetMember(Object.GetPtr(Value), binder.Name, out result);
- }
-
- /// <inheritdoc/>
- public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
- {
- return godot_icall_DynamicGodotObject_InvokeMember(Object.GetPtr(Value), binder.Name, args, out result);
- }
-
- /// <inheritdoc/>
- public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
- {
- if (indexes.Length == 1)
- {
- if (indexes[0] is string name)
- {
- return godot_icall_DynamicGodotObject_SetMember(Object.GetPtr(Value), name, value);
- }
- }
-
- return base.TrySetIndex(binder, indexes, value);
- }
-
- /// <inheritdoc/>
- public override bool TrySetMember(SetMemberBinder binder, object value)
- {
- return godot_icall_DynamicGodotObject_SetMember(Object.GetPtr(Value), binder.Name, value);
- }
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern string[] godot_icall_DynamicGodotObject_SetMemberList(IntPtr godotObject);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool godot_icall_DynamicGodotObject_InvokeMember(IntPtr godotObject, string name, object[] args, out object result);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool godot_icall_DynamicGodotObject_GetMember(IntPtr godotObject, string name, out object result);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool godot_icall_DynamicGodotObject_SetMember(IntPtr godotObject, string name, object value);
-
- #region We don't override these methods
-
- // Looks like this is not usable from C#
- //public override bool TryCreateInstance(CreateInstanceBinder binder, object[] args, out object result);
-
- // Object members cannot be deleted
- //public override bool TryDeleteIndex(DeleteIndexBinder binder, object[] indexes);
- //public override bool TryDeleteMember(DeleteMemberBinder binder);
-
- // Invocation on the object itself, e.g.: obj(param)
- //public override bool TryInvoke(InvokeBinder binder, object[] args, out object result);
-
- // No unnary operations to handle
- //public override bool TryUnaryOperation(UnaryOperationBinder binder, out object result);
-
- #endregion
- }
-}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs
index 1dc21b6303..03996bafdd 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs
@@ -36,7 +36,7 @@ namespace Godot
/// <seealso cref="GetNodeOrNull{T}(NodePath)"/>
/// <param name="path">The path to the node to fetch.</param>
/// <exception cref="InvalidCastException">
- /// Thrown when the given the fetched node can't be casted to the given type <typeparamref name="T"/>.
+ /// The fetched node can't be casted to the given type <typeparamref name="T"/>.
/// </exception>
/// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam>
/// <returns>
@@ -93,18 +93,22 @@ namespace Godot
/// Negative indices access the children from the last one.
/// To access a child node via its name, use <see cref="GetNode"/>.
/// </summary>
- /// <seealso cref="GetChildOrNull{T}(int)"/>
+ /// <seealso cref="GetChildOrNull{T}(int, bool)"/>
/// <param name="idx">Child index.</param>
+ /// <param name="includeInternal">
+ /// If <see langword="false"/>, internal children are skipped (see <c>internal</c>
+ /// parameter in <see cref="AddChild(Node, bool, InternalMode)"/>).
+ /// </param>
/// <exception cref="InvalidCastException">
- /// Thrown when the given the fetched node can't be casted to the given type <typeparamref name="T"/>.
+ /// The fetched node can't be casted to the given type <typeparamref name="T"/>.
/// </exception>
/// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam>
/// <returns>
/// The child <see cref="Node"/> at the given index <paramref name="idx"/>.
/// </returns>
- public T GetChild<T>(int idx) where T : class
+ public T GetChild<T>(int idx, bool includeInternal = false) where T : class
{
- return (T)(object)GetChild(idx);
+ return (T)(object)GetChild(idx, includeInternal);
}
/// <summary>
@@ -113,15 +117,20 @@ namespace Godot
/// Negative indices access the children from the last one.
/// To access a child node via its name, use <see cref="GetNode"/>.
/// </summary>
- /// <seealso cref="GetChild{T}(int)"/>
+ /// <seealso cref="GetChild{T}(int, bool)"/>
/// <param name="idx">Child index.</param>
+ /// <param name="includeInternal">
+ /// If <see langword="false"/>, internal children are skipped (see <c>internal</c>
+ /// parameter in <see cref="AddChild(Node, bool, InternalMode)"/>).
+ /// </param>
/// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam>
/// <returns>
/// The child <see cref="Node"/> at the given index <paramref name="idx"/>, or <see langword="null"/> if not found.
/// </returns>
- public T GetChildOrNull<T>(int idx) where T : class
+ public T GetChildOrNull<T>(int idx, bool includeInternal = false) where T : class
{
- return GetChild(idx) as T;
+ int count = GetChildCount(includeInternal);
+ return idx >= -count && idx < count ? GetChild(idx, includeInternal) as T : null;
}
/// <summary>
@@ -133,7 +142,7 @@ namespace Godot
/// </summary>
/// <seealso cref="GetOwnerOrNull{T}"/>
/// <exception cref="InvalidCastException">
- /// Thrown when the given the fetched node can't be casted to the given type <typeparamref name="T"/>.
+ /// The fetched node can't be casted to the given type <typeparamref name="T"/>.
/// </exception>
/// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam>
/// <returns>
@@ -167,7 +176,7 @@ namespace Godot
/// </summary>
/// <seealso cref="GetParentOrNull{T}"/>
/// <exception cref="InvalidCastException">
- /// Thrown when the given the fetched node can't be casted to the given type <typeparamref name="T"/>.
+ /// The fetched node can't be casted to the given type <typeparamref name="T"/>.
/// </exception>
/// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam>
/// <returns>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs
index 691fd85964..4094ceeb22 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ObjectExtensions.cs
@@ -1,5 +1,5 @@
using System;
-using System.Runtime.CompilerServices;
+using Godot.NativeInterop;
namespace Godot
{
@@ -32,10 +32,17 @@ namespace Godot
/// </returns>
public static WeakRef WeakRef(Object obj)
{
- return godot_icall_Object_weakref(GetPtr(obj));
- }
+ if (!IsInstanceValid(obj))
+ return null;
+
+ NativeFuncs.godotsharp_weakref(GetPtr(obj), out godot_ref weakRef);
+ using (weakRef)
+ {
+ if (weakRef.IsNull)
+ return null;
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern WeakRef godot_icall_Object_weakref(IntPtr obj);
+ return (WeakRef)InteropUtils.UnmanagedGetManaged(weakRef.Reference);
+ }
+ }
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs
index 435b59d5f3..8463403096 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs
@@ -11,7 +11,7 @@ namespace Godot
/// </summary>
/// <seealso cref="InstantiateOrNull{T}(GenEditState)"/>
/// <exception cref="InvalidCastException">
- /// Thrown when the given the instantiated node can't be casted to the given type <typeparamref name="T"/>.
+ /// The instantiated node can't be casted to the given type <typeparamref name="T"/>.
/// </exception>
/// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam>
/// <returns>The instantiated scene.</returns>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs
index 25c11d5cf6..b246e56fa9 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/ResourceLoaderExtensions.cs
@@ -19,7 +19,7 @@ namespace Godot
/// Returns an empty resource if no <see cref="ResourceFormatLoader"/> could handle the file.
/// </summary>
/// <exception cref="InvalidCastException">
- /// Thrown when the given the loaded resource can't be casted to the given type <typeparamref name="T"/>.
+ /// The loaded resource can't be casted to the given type <typeparamref name="T"/>.
/// </exception>
/// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Resource"/>.</typeparam>
public static T Load<T>(string path, string typeHint = null, CacheMode cacheMode = CacheMode.Reuse) where T : class
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs
deleted file mode 100644
index df130a5c77..0000000000
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/SceneTreeExtensions.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System;
-using System.Runtime.CompilerServices;
-using Godot.Collections;
-
-namespace Godot
-{
- public partial class SceneTree
- {
- /// <summary>
- /// Returns a list of all nodes assigned to the given <paramref name="group"/>.
- /// </summary>
- /// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam>
- public Array<T> GetNodesInGroup<T>(StringName group) where T : class
- {
- return new Array<T>(godot_icall_SceneTree_get_nodes_in_group_Generic(GetPtr(this), StringName.GetPtr(group), typeof(T)));
- }
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_SceneTree_get_nodes_in_group_Generic(IntPtr obj, IntPtr group, Type elemType);
- }
-}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
index bb076a9633..e4b79e7ec4 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
@@ -1,11 +1,6 @@
-#if REAL_T_IS_DOUBLE
-using real_t = System.Double;
-#else
-using real_t = System.Single;
-#endif
using System;
using System.Collections.Generic;
-using System.Runtime.CompilerServices;
+using Godot.NativeInterop;
namespace Godot
{
@@ -26,9 +21,11 @@ namespace Godot
/// <param name="bytes">Byte array that will be decoded to a <c>Variant</c>.</param>
/// <param name="allowObjects">If objects should be decoded.</param>
/// <returns>The decoded <c>Variant</c>.</returns>
- public static object Bytes2Var(byte[] bytes, bool allowObjects = false)
+ public static Variant BytesToVar(Span<byte> bytes, bool allowObjects = false)
{
- return godot_icall_GD_bytes2var(bytes, allowObjects);
+ using var varBytes = Marshaling.ConvertSystemArrayToNativePackedByteArray(bytes);
+ NativeFuncs.godotsharp_bytes_to_var(varBytes, allowObjects.ToGodotBool(), out godot_variant ret);
+ return Variant.CreateTakingOwnershipOfDisposableValue(ret);
}
/// <summary>
@@ -46,23 +43,24 @@ namespace Godot
/// </code>
/// </example>
/// <returns>The <c>Variant</c> converted to the given <paramref name="type"/>.</returns>
- public static object Convert(object what, Variant.Type type)
+ public static Variant Convert(Variant what, Variant.Type type)
{
- return godot_icall_GD_convert(what, type);
+ NativeFuncs.godotsharp_convert((godot_variant)what.NativeVar, (int)type, out godot_variant ret);
+ return Variant.CreateTakingOwnershipOfDisposableValue(ret);
}
/// <summary>
/// Converts from decibels to linear energy (audio).
/// </summary>
- /// <seealso cref="Linear2Db(real_t)"/>
+ /// <seealso cref="LinearToDb(real_t)"/>
/// <param name="db">Decibels to convert.</param>
/// <returns>Audio volume as linear energy.</returns>
- public static real_t Db2Linear(real_t db)
+ public static real_t DbToLinear(real_t db)
{
return (real_t)Math.Exp(db * 0.11512925464970228420089957273422);
}
- private static object[] GetPrintParams(object[] parameters)
+ private static string[] GetPrintParams(object[] parameters)
{
if (parameters == null)
{
@@ -82,9 +80,9 @@ namespace Godot
/// </example>
/// <param name="var">Variable that will be hashed.</param>
/// <returns>Hash of the variable passed.</returns>
- public static int Hash(object var)
+ public static int Hash(Variant var)
{
- return godot_icall_GD_hash(var);
+ return NativeFuncs.godotsharp_hash((godot_variant)var.NativeVar);
}
/// <summary>
@@ -110,25 +108,25 @@ namespace Godot
/// <returns>The <see cref="Object"/> instance.</returns>
public static Object InstanceFromId(ulong instanceId)
{
- return godot_icall_GD_instance_from_id(instanceId);
+ return InteropUtils.UnmanagedGetManaged(NativeFuncs.godotsharp_instance_from_id(instanceId));
}
/// <summary>
/// Converts from linear energy to decibels (audio).
/// This can be used to implement volume sliders that behave as expected (since volume isn't linear).
/// </summary>
- /// <seealso cref="Db2Linear(real_t)"/>
+ /// <seealso cref="DbToLinear(real_t)"/>
/// <example>
/// <code>
/// // "slider" refers to a node that inherits Range such as HSlider or VSlider.
/// // Its range must be configured to go from 0 to 1.
/// // Change the bus name if you'd like to change the volume of a specific bus only.
- /// AudioServer.SetBusVolumeDb(AudioServer.GetBusIndex("Master"), GD.Linear2Db(slider.value));
+ /// AudioServer.SetBusVolumeDb(AudioServer.GetBusIndex("Master"), GD.LinearToDb(slider.value));
/// </code>
/// </example>
/// <param name="linear">The linear energy to convert.</param>
/// <returns>Audio as decibels.</returns>
- public static real_t Linear2Db(real_t linear)
+ public static real_t LinearToDb(real_t linear)
{
return (real_t)(Math.Log(linear) * 8.6858896380650365530225783783321);
}
@@ -191,8 +189,6 @@ namespace Godot
/// Pushes an error message to Godot's built-in debugger and to the OS terminal.
///
/// Note: Errors printed this way will not pause project execution.
- /// To print an error message and pause project execution in debug builds,
- /// use [code]assert(false, "test error")[/code] instead.
/// </summary>
/// <example>
/// <code>
@@ -202,7 +198,8 @@ namespace Godot
/// <param name="message">Error message.</param>
public static void PushError(string message)
{
- godot_icall_GD_pusherror(message);
+ using var godotStr = Marshaling.ConvertStringToNative(message);
+ NativeFuncs.godotsharp_pusherror(godotStr);
}
/// <summary>
@@ -214,7 +211,8 @@ namespace Godot
/// <param name="message">Warning message.</param>
public static void PushWarning(string message)
{
- godot_icall_GD_pushwarning(message);
+ using var godotStr = Marshaling.ConvertStringToNative(message);
+ NativeFuncs.godotsharp_pushwarning(godotStr);
}
/// <summary>
@@ -235,15 +233,26 @@ namespace Godot
/// <param name="what">Arguments that will be printed.</param>
public static void Print(params object[] what)
{
- godot_icall_GD_print(GetPrintParams(what));
+ string str = string.Concat(GetPrintParams(what));
+ using var godotStr = Marshaling.ConvertStringToNative(str);
+ NativeFuncs.godotsharp_print(godotStr);
}
/// <summary>
- /// Converts one or more arguments of any type to string in the best way possible and prints them to the console. The following BBCode tags are supported: b, i, u, s, indent, code, url, center, right, color, bgcolor, fgcolor. Color tags only support named colors such as [code]red[/code], [i]not[/i] hexadecimal color codes. Unsupported tags will be left as-is in standard output.
- /// When printing to standard output, the supported subset of BBCode is converted to ANSI escape codes for the terminal emulator to display. Displaying ANSI escape codes is currently only supported on Linux and macOS. Support for ANSI escape codes may vary across terminal emulators, especially for italic and strikethrough.
+ /// Converts one or more arguments of any type to string in the best way possible
+ /// and prints them to the console.
+ /// The following BBCode tags are supported: b, i, u, s, indent, code, url, center,
+ /// right, color, bgcolor, fgcolor.
+ /// Color tags only support named colors such as <c>red</c>, not hexadecimal color codes.
+ /// Unsupported tags will be left as-is in standard output.
+ /// When printing to standard output, the supported subset of BBCode is converted to
+ /// ANSI escape codes for the terminal emulator to display. Displaying ANSI escape codes
+ /// is currently only supported on Linux and macOS. Support for ANSI escape codes may vary
+ /// across terminal emulators, especially for italic and strikethrough.
///
/// Note: Consider using <see cref="PushError(string)"/> and <see cref="PushWarning(string)"/>
- /// to print error and warning messages instead of <see cref="Print(object[])"/> or <see cref="PrintRich(object[])"/>.
+ /// to print error and warning messages instead of <see cref="Print(object[])"/> or
+ /// <see cref="PrintRich(object[])"/>.
/// This distinguishes them from print messages used for debugging purposes,
/// while also displaying a stack trace when an error or warning is printed.
/// </summary>
@@ -253,10 +262,11 @@ namespace Godot
/// </code>
/// </example>
/// <param name="what">Arguments that will be printed.</param>
- /// </summary>
public static void PrintRich(params object[] what)
{
- godot_icall_GD_print_rich(GetPrintParams(what));
+ string str = string.Concat(GetPrintParams(what));
+ using var godotStr = Marshaling.ConvertStringToNative(str);
+ NativeFuncs.godotsharp_print_rich(godotStr);
}
/// <summary>
@@ -278,7 +288,9 @@ namespace Godot
/// <param name="what">Arguments that will be printed.</param>
public static void PrintErr(params object[] what)
{
- godot_icall_GD_printerr(GetPrintParams(what));
+ string str = string.Concat(GetPrintParams(what));
+ using var godotStr = Marshaling.ConvertStringToNative(str);
+ NativeFuncs.godotsharp_printerr(godotStr);
}
/// <summary>
@@ -298,7 +310,9 @@ namespace Godot
/// <param name="what">Arguments that will be printed.</param>
public static void PrintRaw(params object[] what)
{
- godot_icall_GD_printraw(GetPrintParams(what));
+ string str = string.Concat(GetPrintParams(what));
+ using var godotStr = Marshaling.ConvertStringToNative(str);
+ NativeFuncs.godotsharp_printraw(godotStr);
}
/// <summary>
@@ -312,7 +326,9 @@ namespace Godot
/// <param name="what">Arguments that will be printed.</param>
public static void PrintS(params object[] what)
{
- godot_icall_GD_prints(GetPrintParams(what));
+ string str = string.Join(' ', GetPrintParams(what));
+ using var godotStr = Marshaling.ConvertStringToNative(str);
+ NativeFuncs.godotsharp_prints(godotStr);
}
/// <summary>
@@ -326,7 +342,9 @@ namespace Godot
/// <param name="what">Arguments that will be printed.</param>
public static void PrintT(params object[] what)
{
- godot_icall_GD_printt(GetPrintParams(what));
+ string str = string.Join('\t', GetPrintParams(what));
+ using var godotStr = Marshaling.ConvertStringToNative(str);
+ NativeFuncs.godotsharp_printt(godotStr);
}
/// <summary>
@@ -340,7 +358,7 @@ namespace Godot
/// <returns>A random <see langword="float"/> number.</returns>
public static float Randf()
{
- return godot_icall_GD_randf();
+ return NativeFuncs.godotsharp_randf();
}
/// <summary>
@@ -350,7 +368,7 @@ namespace Godot
/// <returns>A random normally-distributed <see langword="float"/> number.</returns>
public static double Randfn(double mean, double deviation)
{
- return godot_icall_GD_randfn(mean, deviation);
+ return NativeFuncs.godotsharp_randfn(mean, deviation);
}
/// <summary>
@@ -368,7 +386,7 @@ namespace Godot
/// <returns>A random <see langword="uint"/> number.</returns>
public static uint Randi()
{
- return godot_icall_GD_randi();
+ return NativeFuncs.godotsharp_randi();
}
/// <summary>
@@ -381,7 +399,7 @@ namespace Godot
/// </summary>
public static void Randomize()
{
- godot_icall_GD_randomize();
+ NativeFuncs.godotsharp_randomize();
}
/// <summary>
@@ -396,7 +414,7 @@ namespace Godot
/// <returns>A random <see langword="double"/> number inside the given range.</returns>
public static double RandRange(double from, double to)
{
- return godot_icall_GD_randf_range(from, to);
+ return NativeFuncs.godotsharp_randf_range(from, to);
}
/// <summary>
@@ -413,7 +431,7 @@ namespace Godot
/// <returns>A random <see langword="int"/> number inside the given range.</returns>
public static int RandRange(int from, int to)
{
- return godot_icall_GD_randi_range(from, to);
+ return NativeFuncs.godotsharp_randi_range(from, to);
}
/// <summary>
@@ -426,7 +444,7 @@ namespace Godot
/// <returns>A random <see langword="uint"/> number.</returns>
public static uint RandFromSeed(ref ulong seed)
{
- return godot_icall_GD_rand_seed(seed, out seed);
+ return NativeFuncs.godotsharp_rand_from_seed(seed, out seed);
}
/// <summary>
@@ -483,7 +501,7 @@ namespace Godot
/// <param name="seed">Seed that will be used.</param>
public static void Seed(ulong seed)
{
- godot_icall_GD_seed(seed);
+ NativeFuncs.godotsharp_seed(seed);
}
/// <summary>
@@ -491,59 +509,57 @@ namespace Godot
/// </summary>
/// <param name="what">Arguments that will converted to string.</param>
/// <returns>The string formed by the given arguments.</returns>
- public static string Str(params object[] what)
+ public static string Str(params Variant[] what)
{
- return godot_icall_GD_str(what);
+ using var whatGodot = new Godot.Collections.Array(what);
+ NativeFuncs.godotsharp_str((godot_array)whatGodot.NativeValue, out godot_string ret);
+ using (ret)
+ return Marshaling.ConvertStringToManaged(ret);
}
/// <summary>
- /// Converts a formatted string that was returned by <see cref="Var2Str(object)"/> to the original value.
+ /// Converts a formatted string that was returned by <see cref="VarToStr(Variant)"/> to the original value.
/// </summary>
/// <example>
/// <code>
/// string a = "{\"a\": 1, \"b\": 2 }";
- /// var b = (Godot.Collections.Dictionary)GD.Str2Var(a);
+ /// var b = (Godot.Collections.Dictionary)GD.StrToVar(a);
/// GD.Print(b["a"]); // Prints 1
/// </code>
/// </example>
/// <param name="str">String that will be converted to Variant.</param>
/// <returns>The decoded <c>Variant</c>.</returns>
- public static object Str2Var(string str)
+ public static Variant StrToVar(string str)
{
- return godot_icall_GD_str2var(str);
- }
-
- /// <summary>
- /// Returns whether the given class exists in <see cref="ClassDB"/>.
- /// </summary>
- /// <returns>If the class exists in <see cref="ClassDB"/>.</returns>
- public static bool TypeExists(StringName type)
- {
- return godot_icall_GD_type_exists(StringName.GetPtr(type));
+ using var godotStr = Marshaling.ConvertStringToNative(str);
+ NativeFuncs.godotsharp_str_to_var(godotStr, out godot_variant ret);
+ return Variant.CreateTakingOwnershipOfDisposableValue(ret);
}
/// <summary>
/// Encodes a <c>Variant</c> value to a byte array.
/// If <paramref name="fullObjects"/> is <see langword="true"/> encoding objects is allowed
/// (and can potentially include code).
- /// Deserialization can be done with <see cref="Bytes2Var(byte[], bool)"/>.
+ /// Deserialization can be done with <see cref="BytesToVar(Span{byte}, bool)"/>.
/// </summary>
/// <param name="var">Variant that will be encoded.</param>
/// <param name="fullObjects">If objects should be serialized.</param>
/// <returns>The <c>Variant</c> encoded as an array of bytes.</returns>
- public static byte[] Var2Bytes(object var, bool fullObjects = false)
+ public static byte[] VarToBytes(Variant var, bool fullObjects = false)
{
- return godot_icall_GD_var2bytes(var, fullObjects);
+ NativeFuncs.godotsharp_var_to_bytes((godot_variant)var.NativeVar, fullObjects.ToGodotBool(), out var varBytes);
+ using (varBytes)
+ return Marshaling.ConvertNativePackedByteArrayToSystemArray(varBytes);
}
/// <summary>
/// Converts a <c>Variant</c> <paramref name="var"/> to a formatted string that
- /// can later be parsed using <see cref="Str2Var(string)"/>.
+ /// can later be parsed using <see cref="StrToVar(string)"/>.
/// </summary>
/// <example>
/// <code>
/// var a = new Godot.Collections.Dictionary { ["a"] = 1, ["b"] = 2 };
- /// GD.Print(GD.Var2Str(a));
+ /// GD.Print(GD.VarToStr(a));
/// // Prints
/// // {
/// // "a": 1,
@@ -553,9 +569,11 @@ namespace Godot
/// </example>
/// <param name="var">Variant that will be converted to string.</param>
/// <returns>The <c>Variant</c> encoded as a string.</returns>
- public static string Var2Str(object var)
+ public static string VarToStr(Variant var)
{
- return godot_icall_GD_var2str(var);
+ NativeFuncs.godotsharp_var_to_str((godot_variant)var.NativeVar, out godot_string ret);
+ using (ret)
+ return Marshaling.ConvertStringToManaged(ret);
}
/// <summary>
@@ -564,85 +582,7 @@ namespace Godot
/// <returns>The <see cref="Variant.Type"/> for the given <paramref name="type"/>.</returns>
public static Variant.Type TypeToVariantType(Type type)
{
- return godot_icall_TypeToVariantType(type);
+ return Marshaling.ConvertManagedTypeToVariantType(type, out bool _);
}
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern object godot_icall_GD_bytes2var(byte[] bytes, bool allowObjects);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern object godot_icall_GD_convert(object what, Variant.Type type);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern int godot_icall_GD_hash(object var);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern Object godot_icall_GD_instance_from_id(ulong instanceId);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_GD_print(object[] what);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_GD_print_rich(object[] what);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_GD_printerr(object[] what);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_GD_printraw(object[] what);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_GD_prints(object[] what);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_GD_printt(object[] what);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_GD_randomize();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern uint godot_icall_GD_randi();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern float godot_icall_GD_randf();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern int godot_icall_GD_randi_range(int from, int to);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern double godot_icall_GD_randf_range(double from, double to);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern double godot_icall_GD_randfn(double mean, double deviation);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern uint godot_icall_GD_rand_seed(ulong seed, out ulong newSeed);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_GD_seed(ulong seed);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern string godot_icall_GD_str(object[] what);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern object godot_icall_GD_str2var(string str);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool godot_icall_GD_type_exists(IntPtr type);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern byte[] godot_icall_GD_var2bytes(object what, bool fullObjects);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern string godot_icall_GD_var2str(object var);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_GD_pusherror(string type);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_GD_pushwarning(string type);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern Variant.Type godot_icall_TypeToVariantType(Type type);
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTraceListener.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTraceListener.cs
index 9ccac1faaf..78a9d0fe9d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTraceListener.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotTraceListener.cs
@@ -17,10 +17,7 @@ namespace Godot
public override void Fail(string message, string detailMessage)
{
GD.PrintErr("Assertion failed: ", message);
- if (detailMessage != null)
- {
- GD.PrintErr(" Details: ", detailMessage);
- }
+ GD.PrintErr(" Details: ", detailMessage);
try
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotUnhandledExceptionEvent.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotUnhandledExceptionEvent.cs
index 729529d093..a17741ddeb 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotUnhandledExceptionEvent.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GodotUnhandledExceptionEvent.cs
@@ -1,17 +1,33 @@
using System;
+using System.Runtime.InteropServices;
+using Godot.NativeInterop;
namespace Godot
{
public static partial class GD
{
- /// <summary>
- /// Fires when an unhandled exception occurs, regardless of project settings.
- /// </summary>
- public static event EventHandler<UnhandledExceptionArgs> UnhandledException;
-
- private static void OnUnhandledException(Exception e)
+ [UnmanagedCallersOnly]
+ internal static void OnCoreApiAssemblyLoaded(godot_bool isDebug)
{
- UnhandledException?.Invoke(null, new UnhandledExceptionArgs(e));
+ try
+ {
+ Dispatcher.InitializeDefaultGodotTaskScheduler();
+
+ if (isDebug.ToBool())
+ {
+ DebuggingUtils.InstallTraceListener();
+
+ AppDomain.CurrentDomain.UnhandledException += (_, e) =>
+ {
+ // Exception.ToString() includes the inner exception
+ ExceptionUtils.LogUnhandledException((Exception)e.ExceptionObject);
+ };
+ }
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ }
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs
deleted file mode 100644
index 50ae2eb112..0000000000
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs
+++ /dev/null
@@ -1,154 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace Godot
-{
- internal static class MarshalUtils
- {
- /// <summary>
- /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
- /// is <see cref="Collections.Array{T}"/>; otherwise returns <see langword="false"/>.
- /// </summary>
- /// <exception cref="InvalidOperationException">
- /// Thrown when the given <paramref name="type"/> is not a generic type.
- /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
- /// </exception>
- private static bool TypeIsGenericArray(Type type) =>
- type.GetGenericTypeDefinition() == typeof(Collections.Array<>);
-
- /// <summary>
- /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
- /// is <see cref="Collections.Dictionary{TKey, TValue}"/>; otherwise returns <see langword="false"/>.
- /// </summary>
- /// <exception cref="InvalidOperationException">
- /// Thrown when the given <paramref name="type"/> is not a generic type.
- /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
- /// </exception>
- private static bool TypeIsGenericDictionary(Type type) =>
- type.GetGenericTypeDefinition() == typeof(Collections.Dictionary<,>);
-
- /// <summary>
- /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
- /// is <see cref="List{T}"/>; otherwise returns <see langword="false"/>.
- /// </summary>
- /// <exception cref="InvalidOperationException">
- /// Thrown when the given <paramref name="type"/> is not a generic type.
- /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
- /// </exception>
- private static bool TypeIsSystemGenericList(Type type) =>
- type.GetGenericTypeDefinition() == typeof(List<>);
-
- /// <summary>
- /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
- /// is <see cref="Dictionary{TKey, TValue}"/>; otherwise returns <see langword="false"/>.
- /// </summary>
- /// <exception cref="InvalidOperationException">
- /// Thrown when the given <paramref name="type"/> is not a generic type.
- /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
- /// </exception>
- private static bool TypeIsSystemGenericDictionary(Type type) =>
- type.GetGenericTypeDefinition() == typeof(Dictionary<,>);
-
- /// <summary>
- /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
- /// is <see cref="IEnumerable{T}"/>; otherwise returns <see langword="false"/>.
- /// </summary>
- /// <exception cref="InvalidOperationException">
- /// Thrown when the given <paramref name="type"/> is not a generic type.
- /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
- /// </exception>
- private static bool TypeIsGenericIEnumerable(Type type) => type.GetGenericTypeDefinition() == typeof(IEnumerable<>);
-
- /// <summary>
- /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
- /// is <see cref="ICollection{T}"/>; otherwise returns <see langword="false"/>.
- /// </summary>
- /// <exception cref="InvalidOperationException">
- /// Thrown when the given <paramref name="type"/> is not a generic type.
- /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
- /// </exception>
- private static bool TypeIsGenericICollection(Type type) => type.GetGenericTypeDefinition() == typeof(ICollection<>);
-
- /// <summary>
- /// Returns <see langword="true"/> if the generic type definition of <paramref name="type"/>
- /// is <see cref="IDictionary{TKey, TValue}"/>; otherwise returns <see langword="false"/>.
- /// </summary>
- /// <exception cref="InvalidOperationException">
- /// Thrown when the given <paramref name="type"/> is not a generic type.
- /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
- /// </exception>
- private static bool TypeIsGenericIDictionary(Type type) => type.GetGenericTypeDefinition() == typeof(IDictionary<,>);
-
- /// <summary>
- /// Returns <see langword="true"/> if the <see cref="FlagsAttribute"/> is applied to the given type.
- /// </summary>
- private static bool TypeHasFlagsAttribute(Type type) => type.IsDefined(typeof(FlagsAttribute), false);
-
- /// <summary>
- /// Returns the generic type definition of <paramref name="type"/>.
- /// </summary>
- /// <exception cref="InvalidOperationException">
- /// Thrown when the given <paramref name="type"/> is not a generic type.
- /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
- /// </exception>
- private static void GetGenericTypeDefinition(Type type, out Type genericTypeDefinition)
- {
- genericTypeDefinition = type.GetGenericTypeDefinition();
- }
-
- /// <summary>
- /// Gets the element type for the given <paramref name="arrayType"/>.
- /// </summary>
- /// <param name="arrayType">Type for the generic array.</param>
- /// <param name="elementType">Element type for the generic array.</param>
- /// <exception cref="InvalidOperationException">
- /// Thrown when the given <paramref name="arrayType"/> is not a generic type.
- /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
- /// </exception>
- private static void ArrayGetElementType(Type arrayType, out Type elementType)
- {
- elementType = arrayType.GetGenericArguments()[0];
- }
-
- /// <summary>
- /// Gets the key type and the value type for the given <paramref name="dictionaryType"/>.
- /// </summary>
- /// <param name="dictionaryType">The type for the generic dictionary.</param>
- /// <param name="keyType">Key type for the generic dictionary.</param>
- /// <param name="valueType">Value type for the generic dictionary.</param>
- /// <exception cref="InvalidOperationException">
- /// Thrown when the given <paramref name="dictionaryType"/> is not a generic type.
- /// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
- /// </exception>
- private static void DictionaryGetKeyValueTypes(Type dictionaryType, out Type keyType, out Type valueType)
- {
- var genericArgs = dictionaryType.GetGenericArguments();
- keyType = genericArgs[0];
- valueType = genericArgs[1];
- }
-
- /// <summary>
- /// Constructs a new <see cref="Type"/> from <see cref="Collections.Array{T}"/>
- /// where the generic type for the elements is <paramref name="elemType"/>.
- /// </summary>
- /// <param name="elemType">Element type for the array.</param>
- /// <returns>The generic array type with the specified element type.</returns>
- private static Type MakeGenericArrayType(Type elemType)
- {
- return typeof(Collections.Array<>).MakeGenericType(elemType);
- }
-
- /// <summary>
- /// Constructs a new <see cref="Type"/> from <see cref="Collections.Dictionary{TKey, TValue}"/>
- /// where the generic type for the keys is <paramref name="keyType"/> and
- /// for the values is <paramref name="valueType"/>.
- /// </summary>
- /// <param name="keyType">Key type for the dictionary.</param>
- /// <param name="valueType">Key type for the dictionary.</param>
- /// <returns>The generic dictionary type with the specified key and value types.</returns>
- private static Type MakeGenericDictionaryType(Type keyType, Type valueType)
- {
- return typeof(Collections.Dictionary<,>).MakeGenericType(keyType, valueType);
- }
- }
-}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
index 36b7d0f80f..b30012d214 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
@@ -1,8 +1,3 @@
-#if REAL_T_IS_DOUBLE
-using real_t = System.Double;
-#else
-using real_t = System.Single;
-#endif
using System;
namespace Godot
@@ -40,9 +35,9 @@ namespace Godot
public const real_t NaN = real_t.NaN;
// 0.0174532924f and 0.0174532925199433
- private const real_t _deg2RadConst = (real_t)0.0174532925199432957692369077M;
+ private const real_t _degToRadConst = (real_t)0.0174532925199432957692369077M;
// 57.29578f and 57.2957795130823
- private const real_t _rad2DegConst = (real_t)57.295779513082320876798154814M;
+ private const real_t _radToDegConst = (real_t)57.295779513082320876798154814M;
/// <summary>
/// Returns the absolute value of <paramref name="s"/> (i.e. positive value).
@@ -180,7 +175,8 @@ namespace Godot
}
/// <summary>
- /// Cubic interpolates between two values by a normalized value with pre and post values.
+ /// Cubic interpolates between two values by the factor defined in <paramref name="weight"/>
+ /// with pre and post values.
/// </summary>
/// <param name="from">The start value for interpolation.</param>
/// <param name="to">The destination value for interpolation.</param>
@@ -198,6 +194,93 @@ namespace Godot
}
/// <summary>
+ /// Cubic interpolates between two rotation values with shortest path
+ /// by the factor defined in <paramref name="weight"/> with pre and post values.
+ /// See also <see cref="LerpAngle"/>.
+ /// </summary>
+ /// <param name="from">The start value for interpolation.</param>
+ /// <param name="to">The destination value for interpolation.</param>
+ /// <param name="pre">The value which before "from" value for interpolation.</param>
+ /// <param name="post">The value which after "to" value for interpolation.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <returns>The resulting value of the interpolation.</returns>
+ public static real_t CubicInterpolateAngle(real_t from, real_t to, real_t pre, real_t post, real_t weight)
+ {
+ real_t fromRot = from % Mathf.Tau;
+
+ real_t preDiff = (pre - fromRot) % Mathf.Tau;
+ real_t preRot = fromRot + (2.0f * preDiff) % Mathf.Tau - preDiff;
+
+ real_t toDiff = (to - fromRot) % Mathf.Tau;
+ real_t toRot = fromRot + (2.0f * toDiff) % Mathf.Tau - toDiff;
+
+ real_t postDiff = (post - toRot) % Mathf.Tau;
+ real_t postRot = toRot + (2.0f * postDiff) % Mathf.Tau - postDiff;
+
+ return CubicInterpolate(fromRot, toRot, preRot, postRot, weight);
+ }
+
+ /// <summary>
+ /// Cubic interpolates between two values by the factor defined in <paramref name="weight"/>
+ /// with pre and post values.
+ /// It can perform smoother interpolation than <see cref="CubicInterpolate"/>
+ /// by the time values.
+ /// </summary>
+ /// <param name="from">The start value for interpolation.</param>
+ /// <param name="to">The destination value for interpolation.</param>
+ /// <param name="pre">The value which before "from" value for interpolation.</param>
+ /// <param name="post">The value which after "to" value for interpolation.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <param name="toT"></param>
+ /// <param name="preT"></param>
+ /// <param name="postT"></param>
+ /// <returns>The resulting value of the interpolation.</returns>
+ public static real_t CubicInterpolateInTime(real_t from, real_t to, real_t pre, real_t post, real_t weight, real_t toT, real_t preT, real_t postT)
+ {
+ /* Barry-Goldman method */
+ real_t t = Lerp(0.0f, toT, weight);
+ real_t a1 = Lerp(pre, from, preT == 0 ? 0.0f : (t - preT) / -preT);
+ real_t a2 = Lerp(from, to, toT == 0 ? 0.5f : t / toT);
+ real_t a3 = Lerp(to, post, postT - toT == 0 ? 1.0f : (t - toT) / (postT - toT));
+ real_t b1 = Lerp(a1, a2, toT - preT == 0 ? 0.0f : (t - preT) / (toT - preT));
+ real_t b2 = Lerp(a2, a3, postT == 0 ? 1.0f : t / postT);
+ return Lerp(b1, b2, toT == 0 ? 0.5f : t / toT);
+ }
+
+ /// <summary>
+ /// Cubic interpolates between two rotation values with shortest path
+ /// by the factor defined in <paramref name="weight"/> with pre and post values.
+ /// See also <see cref="LerpAngle"/>.
+ /// It can perform smoother interpolation than <see cref="CubicInterpolateAngle"/>
+ /// by the time values.
+ /// </summary>
+ /// <param name="from">The start value for interpolation.</param>
+ /// <param name="to">The destination value for interpolation.</param>
+ /// <param name="pre">The value which before "from" value for interpolation.</param>
+ /// <param name="post">The value which after "to" value for interpolation.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <param name="toT"></param>
+ /// <param name="preT"></param>
+ /// <param name="postT"></param>
+ /// <returns>The resulting value of the interpolation.</returns>
+ public static real_t CubicInterpolateAngleInTime(real_t from, real_t to, real_t pre, real_t post, real_t weight,
+ real_t toT, real_t preT, real_t postT)
+ {
+ real_t fromRot = from % Mathf.Tau;
+
+ real_t preDiff = (pre - fromRot) % Mathf.Tau;
+ real_t preRot = fromRot + (2.0f * preDiff) % Mathf.Tau - preDiff;
+
+ real_t toDiff = (to - fromRot) % Mathf.Tau;
+ real_t toRot = fromRot + (2.0f * toDiff) % Mathf.Tau - toDiff;
+
+ real_t postDiff = (post - toRot) % Mathf.Tau;
+ real_t postRot = toRot + (2.0f * postDiff) % Mathf.Tau - postDiff;
+
+ return CubicInterpolateInTime(fromRot, toRot, preRot, postRot, weight, toT, preT, postT);
+ }
+
+ /// <summary>
/// Returns the point at the given <paramref name="t"/> on a one-dimensional Bezier curve defined by
/// the given <paramref name="control1"/>, <paramref name="control2"/> and <paramref name="end"/> points.
/// </summary>
@@ -224,9 +307,9 @@ namespace Godot
/// </summary>
/// <param name="deg">An angle expressed in degrees.</param>
/// <returns>The same angle expressed in radians.</returns>
- public static real_t Deg2Rad(real_t deg)
+ public static real_t DegToRad(real_t deg)
{
- return deg * _deg2RadConst;
+ return deg * _degToRadConst;
}
/// <summary>
@@ -536,9 +619,9 @@ namespace Godot
/// </summary>
/// <param name="rad">An angle expressed in radians.</param>
/// <returns>The same angle expressed in degrees.</returns>
- public static real_t Rad2Deg(real_t rad)
+ public static real_t RadToDeg(real_t rad)
{
- return rad * _rad2DegConst;
+ return rad * _radToDegConst;
}
/// <summary>
@@ -759,9 +842,10 @@ namespace Godot
}
/// <summary>
- /// Returns the [code]value[/code] wrapped between [code]0[/code] and the [code]length[/code].
- /// If the limit is reached, the next value the function returned is decreased to the [code]0[/code] side or increased to the [code]length[/code] side (like a triangle wave).
- /// If [code]length[/code] is less than zero, it becomes positive.
+ /// Returns the <paramref name="value"/> wrapped between <c>0</c> and the <paramref name="length"/>.
+ /// If the limit is reached, the next value the function returned is decreased to the <c>0</c> side
+ /// or increased to the <paramref name="length"/> side (like a triangle wave).
+ /// If <paramref name="length"/> is less than zero, it becomes positive.
/// </summary>
/// <param name="value">The value to pingpong.</param>
/// <param name="length">The maximum value of the function.</param>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs
index f15d01b34b..ea05c1547c 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs
@@ -1,8 +1,3 @@
-#if REAL_T_IS_DOUBLE
-using real_t = System.Double;
-#else
-using real_t = System.Single;
-#endif
using System;
namespace Godot
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/CustomUnsafe.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/CustomUnsafe.cs
new file mode 100644
index 0000000000..afef20a7f2
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/CustomUnsafe.cs
@@ -0,0 +1,313 @@
+using System.Runtime.CompilerServices;
+
+namespace Godot.NativeInterop;
+
+// Ref structs are not allowed as generic type parameters, so we can't use Unsafe.AsPointer<T>/AsRef<T>.
+// As a workaround we create our own overloads for our structs with some tricks under the hood.
+
+public static class CustomUnsafe
+{
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_ref* AsPointer(ref godot_ref value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_ref* ReadOnlyRefAsPointer(in godot_ref value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_ref AsRef(godot_ref* source)
+ => ref *source;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_ref AsRef(in godot_ref source)
+ => ref *ReadOnlyRefAsPointer(in source);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_variant_call_error* AsPointer(ref godot_variant_call_error value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_variant_call_error* ReadOnlyRefAsPointer(in godot_variant_call_error value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_variant_call_error AsRef(godot_variant_call_error* source)
+ => ref *source;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_variant_call_error AsRef(in godot_variant_call_error source)
+ => ref *ReadOnlyRefAsPointer(in source);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_variant* AsPointer(ref godot_variant value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_variant* ReadOnlyRefAsPointer(in godot_variant value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_variant AsRef(godot_variant* source)
+ => ref *source;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_variant AsRef(in godot_variant source)
+ => ref *ReadOnlyRefAsPointer(in source);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_string* AsPointer(ref godot_string value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_string* ReadOnlyRefAsPointer(in godot_string value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_string AsRef(godot_string* source)
+ => ref *source;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_string AsRef(in godot_string source)
+ => ref *ReadOnlyRefAsPointer(in source);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_string_name* AsPointer(ref godot_string_name value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_string_name* ReadOnlyRefAsPointer(in godot_string_name value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_string_name AsRef(godot_string_name* source)
+ => ref *source;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_string_name AsRef(in godot_string_name source)
+ => ref *ReadOnlyRefAsPointer(in source);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_node_path* AsPointer(ref godot_node_path value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_node_path* ReadOnlyRefAsPointer(in godot_node_path value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_node_path AsRef(godot_node_path* source)
+ => ref *source;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_node_path AsRef(in godot_node_path source)
+ => ref *ReadOnlyRefAsPointer(in source);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_signal* AsPointer(ref godot_signal value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_signal* ReadOnlyRefAsPointer(in godot_signal value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_signal AsRef(godot_signal* source)
+ => ref *source;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_signal AsRef(in godot_signal source)
+ => ref *ReadOnlyRefAsPointer(in source);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_callable* AsPointer(ref godot_callable value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_callable* ReadOnlyRefAsPointer(in godot_callable value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_callable AsRef(godot_callable* source)
+ => ref *source;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_callable AsRef(in godot_callable source)
+ => ref *ReadOnlyRefAsPointer(in source);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_array* AsPointer(ref godot_array value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_array* ReadOnlyRefAsPointer(in godot_array value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_array AsRef(godot_array* source)
+ => ref *source;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_array AsRef(in godot_array source)
+ => ref *ReadOnlyRefAsPointer(in source);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_dictionary* AsPointer(ref godot_dictionary value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_dictionary* ReadOnlyRefAsPointer(in godot_dictionary value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_dictionary AsRef(godot_dictionary* source)
+ => ref *source;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_dictionary AsRef(in godot_dictionary source)
+ => ref *ReadOnlyRefAsPointer(in source);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_packed_byte_array* AsPointer(ref godot_packed_byte_array value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_packed_byte_array* ReadOnlyRefAsPointer(in godot_packed_byte_array value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_packed_byte_array AsRef(godot_packed_byte_array* source)
+ => ref *source;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_packed_byte_array AsRef(in godot_packed_byte_array source)
+ => ref *ReadOnlyRefAsPointer(in source);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_packed_int32_array* AsPointer(ref godot_packed_int32_array value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_packed_int32_array* ReadOnlyRefAsPointer(in godot_packed_int32_array value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_packed_int32_array AsRef(godot_packed_int32_array* source)
+ => ref *source;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_packed_int32_array AsRef(in godot_packed_int32_array source)
+ => ref *ReadOnlyRefAsPointer(in source);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_packed_int64_array* AsPointer(ref godot_packed_int64_array value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_packed_int64_array* ReadOnlyRefAsPointer(in godot_packed_int64_array value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_packed_int64_array AsRef(godot_packed_int64_array* source)
+ => ref *source;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_packed_int64_array AsRef(in godot_packed_int64_array source)
+ => ref *ReadOnlyRefAsPointer(in source);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_packed_float32_array* AsPointer(ref godot_packed_float32_array value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_packed_float32_array* ReadOnlyRefAsPointer(in godot_packed_float32_array value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_packed_float32_array AsRef(godot_packed_float32_array* source)
+ => ref *source;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_packed_float32_array AsRef(in godot_packed_float32_array source)
+ => ref *ReadOnlyRefAsPointer(in source);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_packed_float64_array* AsPointer(ref godot_packed_float64_array value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_packed_float64_array* ReadOnlyRefAsPointer(in godot_packed_float64_array value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_packed_float64_array AsRef(godot_packed_float64_array* source)
+ => ref *source;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_packed_float64_array AsRef(in godot_packed_float64_array source)
+ => ref *ReadOnlyRefAsPointer(in source);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_packed_string_array* AsPointer(ref godot_packed_string_array value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_packed_string_array* ReadOnlyRefAsPointer(in godot_packed_string_array value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_packed_string_array AsRef(godot_packed_string_array* source)
+ => ref *source;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_packed_string_array AsRef(in godot_packed_string_array source)
+ => ref *ReadOnlyRefAsPointer(in source);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_packed_vector2_array* AsPointer(ref godot_packed_vector2_array value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_packed_vector2_array* ReadOnlyRefAsPointer(in godot_packed_vector2_array value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_packed_vector2_array AsRef(godot_packed_vector2_array* source)
+ => ref *source;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_packed_vector2_array AsRef(in godot_packed_vector2_array source)
+ => ref *ReadOnlyRefAsPointer(in source);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_packed_vector3_array* AsPointer(ref godot_packed_vector3_array value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_packed_vector3_array* ReadOnlyRefAsPointer(in godot_packed_vector3_array value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_packed_vector3_array AsRef(godot_packed_vector3_array* source)
+ => ref *source;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_packed_vector3_array AsRef(in godot_packed_vector3_array source)
+ => ref *ReadOnlyRefAsPointer(in source);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_packed_color_array* AsPointer(ref godot_packed_color_array value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_packed_color_array* ReadOnlyRefAsPointer(in godot_packed_color_array value)
+ => value.GetUnsafeAddress();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_packed_color_array AsRef(godot_packed_color_array* source)
+ => ref *source;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe ref godot_packed_color_array AsRef(in godot_packed_color_array source)
+ => ref *ReadOnlyRefAsPointer(in source);
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs
new file mode 100644
index 0000000000..5a0ea2ba13
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/ExceptionUtils.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+
+#nullable enable
+
+namespace Godot.NativeInterop
+{
+ internal static class ExceptionUtils
+ {
+ public static void PushError(string message)
+ {
+ GD.PushError(message);
+ }
+
+ private static void OnExceptionLoggerException(Exception loggerException, Exception exceptionToLog)
+ {
+ try
+ {
+ // This better not throw
+ PushError(string.Concat("Exception thrown while trying to log another exception...",
+ "\n### Exception ###\n", exceptionToLog.ToString(),
+ "\n### Logger exception ###\n", loggerException.ToString()));
+ }
+ catch (Exception)
+ {
+ // Well, too bad...
+ }
+ }
+
+ private record struct StackInfoTuple(string? File, string Func, int Line);
+
+ private static void CollectExceptionInfo(Exception exception, List<StackInfoTuple> globalFrames,
+ StringBuilder excMsg)
+ {
+ if (excMsg.Length > 0)
+ excMsg.Append(" ---> ");
+ excMsg.Append(exception.GetType().FullName);
+ excMsg.Append(": ");
+ excMsg.Append(exception.Message);
+
+ var innerExc = exception.InnerException;
+
+ if (innerExc != null)
+ {
+ CollectExceptionInfo(innerExc, globalFrames, excMsg);
+ globalFrames.Add(new("", "--- End of inner exception stack trace ---", 0));
+ }
+
+ var stackTrace = new StackTrace(exception, fNeedFileInfo: true);
+
+ foreach (StackFrame frame in stackTrace.GetFrames())
+ {
+ DebuggingUtils.GetStackFrameMethodDecl(frame, out string methodDecl);
+ globalFrames.Add(new(frame.GetFileName(), methodDecl, frame.GetFileLineNumber()));
+ }
+ }
+
+ private static void SendToScriptDebugger(Exception e)
+ {
+ var globalFrames = new List<StackInfoTuple>();
+
+ var excMsg = new StringBuilder();
+
+ CollectExceptionInfo(e, globalFrames, excMsg);
+
+ string file = globalFrames.Count > 0 ? globalFrames[0].File ?? "" : "";
+ string func = globalFrames.Count > 0 ? globalFrames[0].Func : "";
+ int line = globalFrames.Count > 0 ? globalFrames[0].Line : 0;
+ string errorMsg = "Exception";
+
+ using godot_string nFile = Marshaling.ConvertStringToNative(file);
+ using godot_string nFunc = Marshaling.ConvertStringToNative(func);
+ using godot_string nErrorMsg = Marshaling.ConvertStringToNative(errorMsg);
+ using godot_string nExcMsg = Marshaling.ConvertStringToNative(excMsg.ToString());
+
+ using DebuggingUtils.godot_stack_info_vector stackInfoVector = default;
+
+ stackInfoVector.Resize(globalFrames.Count);
+
+ unsafe
+ {
+ for (int i = 0; i < globalFrames.Count; i++)
+ {
+ DebuggingUtils.godot_stack_info* stackInfo = &stackInfoVector.Elements[i];
+
+ var globalFrame = globalFrames[i];
+
+ // Assign directly to element in Vector. This way we don't need to worry
+ // about disposal if an exception is thrown. The Vector takes care of it.
+ stackInfo->File = Marshaling.ConvertStringToNative(globalFrame.File);
+ stackInfo->Func = Marshaling.ConvertStringToNative(globalFrame.Func);
+ stackInfo->Line = globalFrame.Line;
+ }
+
+ NativeFuncs.godotsharp_internal_script_debugger_send_error(nFunc, nFile, line,
+ nErrorMsg, nExcMsg, p_warning: godot_bool.False, stackInfoVector);
+ }
+ }
+
+ public static void LogException(Exception e)
+ {
+ try
+ {
+ if (NativeFuncs.godotsharp_internal_script_debugger_is_active())
+ {
+ SendToScriptDebugger(e);
+ }
+ else
+ {
+ GD.PushError(e.ToString());
+ }
+ }
+ catch (Exception unexpected)
+ {
+ OnExceptionLoggerException(unexpected, e);
+ }
+ }
+
+ public static void LogUnhandledException(Exception e)
+ {
+ try
+ {
+ if (NativeFuncs.godotsharp_internal_script_debugger_is_active())
+ {
+ SendToScriptDebugger(e);
+ }
+
+ // In this case, print it as well in addition to sending it to the script debugger
+ GD.PushError("Unhandled exception\n" + e);
+ }
+ catch (Exception unexpected)
+ {
+ OnExceptionLoggerException(unexpected, e);
+ }
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/GodotDllImportResolver.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/GodotDllImportResolver.cs
new file mode 100644
index 0000000000..5579992d2b
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/GodotDllImportResolver.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+#nullable enable
+
+namespace Godot.NativeInterop
+{
+ public class GodotDllImportResolver
+ {
+ private IntPtr _internalHandle;
+
+ public GodotDllImportResolver(IntPtr internalHandle)
+ {
+ _internalHandle = internalHandle;
+ }
+
+ public IntPtr OnResolveDllImport(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
+ {
+ if (libraryName == "__Internal")
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ return Win32.GetModuleHandle(IntPtr.Zero);
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ return _internalHandle;
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ return MacOS.dlopen(IntPtr.Zero, MacOS.RTLD_LAZY);
+ }
+ }
+
+ return IntPtr.Zero;
+ }
+
+ // ReSharper disable InconsistentNaming
+ private static class MacOS
+ {
+ private const string SystemLibrary = "/usr/lib/libSystem.dylib";
+
+ public const int RTLD_LAZY = 1;
+
+ [DllImport(SystemLibrary)]
+ public static extern IntPtr dlopen(IntPtr path, int mode);
+ }
+
+ private static class Win32
+ {
+ private const string SystemLibrary = "Kernel32.dll";
+
+ [DllImport(SystemLibrary)]
+ public static extern IntPtr GetModuleHandle(IntPtr lpModuleName);
+ }
+ // ReSharper restore InconsistentNaming
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs
new file mode 100644
index 0000000000..44806e8ecf
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropStructs.cs
@@ -0,0 +1,1091 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Godot.NativeInterop
+{
+ // NOTES:
+ // ref structs cannot implement interfaces, but they still work in `using` directives if they declare Dispose()
+
+ public static class GodotBoolExtensions
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe godot_bool ToGodotBool(this bool @bool)
+ {
+ return *(godot_bool*)&@bool;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe bool ToBool(this godot_bool godotBool)
+ {
+ return *(bool*)&godotBool;
+ }
+ }
+
+ // Apparently a struct with a byte is not blittable? It crashes when calling a UnmanagedCallersOnly function ptr.
+ // ReSharper disable once InconsistentNaming
+ public enum godot_bool : byte
+ {
+ True = 1,
+ False = 0
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ public ref struct godot_ref
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal readonly unsafe godot_ref* GetUnsafeAddress()
+ => (godot_ref*)Unsafe.AsPointer(ref Unsafe.AsRef(in _reference));
+
+ private IntPtr _reference;
+
+ public void Dispose()
+ {
+ if (_reference == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_ref_destroy(ref this);
+ _reference = IntPtr.Zero;
+ }
+
+ public readonly IntPtr Reference
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _reference;
+ }
+
+ public readonly bool IsNull
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _reference == IntPtr.Zero;
+ }
+ }
+
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ public enum godot_variant_call_error_error
+ {
+ GODOT_CALL_ERROR_CALL_OK = 0,
+ GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD,
+ GODOT_CALL_ERROR_CALL_ERROR_INVALID_ARGUMENT,
+ GODOT_CALL_ERROR_CALL_ERROR_TOO_MANY_ARGUMENTS,
+ GODOT_CALL_ERROR_CALL_ERROR_TOO_FEW_ARGUMENTS,
+ GODOT_CALL_ERROR_CALL_ERROR_INSTANCE_IS_NULL,
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ public ref struct godot_variant_call_error
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal readonly unsafe godot_variant_call_error* GetUnsafeAddress()
+ => (godot_variant_call_error*)Unsafe.AsPointer(ref Unsafe.AsRef(in error));
+
+ private godot_variant_call_error_error error;
+ private int argument;
+ private int expected;
+
+ public godot_variant_call_error_error Error
+ {
+ readonly get => error;
+ set => error = value;
+ }
+
+ public int Argument
+ {
+ readonly get => argument;
+ set => argument = value;
+ }
+
+ public Godot.Variant.Type Expected
+ {
+ readonly get => (Godot.Variant.Type)expected;
+ set => expected = (int)value;
+ }
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ // ReSharper disable once InconsistentNaming
+ public ref struct godot_variant
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal readonly unsafe godot_variant* GetUnsafeAddress()
+ => (godot_variant*)Unsafe.AsPointer(ref Unsafe.AsRef(in _typeField));
+
+ // Variant.Type is generated as an enum of type long, so we can't use for the field as it must only take 32-bits.
+ [FieldOffset(0)] private int _typeField;
+
+ // There's padding here
+
+ [FieldOffset(8)] private godot_variant_data _data;
+
+ [StructLayout(LayoutKind.Explicit)]
+ // ReSharper disable once InconsistentNaming
+ private unsafe ref struct godot_variant_data
+ {
+ [FieldOffset(0)] public godot_bool _bool;
+ [FieldOffset(0)] public long _int;
+ [FieldOffset(0)] public double _float;
+ [FieldOffset(0)] public Transform2D* _transform2D;
+ [FieldOffset(0)] public AABB* _aabb;
+ [FieldOffset(0)] public Basis* _basis;
+ [FieldOffset(0)] public Transform3D* _transform3D;
+ [FieldOffset(0)] public Vector4* _vector4;
+ [FieldOffset(0)] public Vector4i* _vector4i;
+ [FieldOffset(0)] public Projection* _projection;
+ [FieldOffset(0)] private godot_variant_data_mem _mem;
+
+ // The following fields are not in the C++ union, but this is how they're stored in _mem.
+ [FieldOffset(0)] public godot_string_name _m_string_name;
+ [FieldOffset(0)] public godot_string _m_string;
+ [FieldOffset(0)] public Vector3 _m_vector3;
+ [FieldOffset(0)] public Vector3i _m_vector3i;
+ [FieldOffset(0)] public Vector2 _m_vector2;
+ [FieldOffset(0)] public Vector2i _m_vector2i;
+ [FieldOffset(0)] public Rect2 _m_rect2;
+ [FieldOffset(0)] public Rect2i _m_rect2i;
+ [FieldOffset(0)] public Plane _m_plane;
+ [FieldOffset(0)] public Quaternion _m_quaternion;
+ [FieldOffset(0)] public Color _m_color;
+ [FieldOffset(0)] public godot_node_path _m_node_path;
+ [FieldOffset(0)] public RID _m_rid;
+ [FieldOffset(0)] public godot_variant_obj_data _m_obj_data;
+ [FieldOffset(0)] public godot_callable _m_callable;
+ [FieldOffset(0)] public godot_signal _m_signal;
+ [FieldOffset(0)] public godot_dictionary _m_dictionary;
+ [FieldOffset(0)] public godot_array _m_array;
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ public struct godot_variant_obj_data
+ {
+ public ulong id;
+ public IntPtr obj;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ public struct godot_variant_data_mem
+ {
+#pragma warning disable 169
+ private real_t _mem0;
+ private real_t _mem1;
+ private real_t _mem2;
+ private real_t _mem3;
+#pragma warning restore 169
+ }
+ }
+
+ public Variant.Type Type
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => (Variant.Type)_typeField;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _typeField = (int)value;
+ }
+
+ public godot_bool Bool
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._bool;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._bool = value;
+ }
+
+ public long Int
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._int;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._int = value;
+ }
+
+ public double Float
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._float;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._float = value;
+ }
+
+ public readonly unsafe Transform2D* Transform2D
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _data._transform2D;
+ }
+
+ public readonly unsafe AABB* AABB
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _data._aabb;
+ }
+
+ public readonly unsafe Basis* Basis
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _data._basis;
+ }
+
+ public readonly unsafe Transform3D* Transform3D
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _data._transform3D;
+ }
+
+ public readonly unsafe Vector4* Vector4
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _data._vector4;
+ }
+
+ public readonly unsafe Vector4i* Vector4i
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _data._vector4i;
+ }
+
+ public readonly unsafe Projection* Projection
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _data._projection;
+ }
+
+ public godot_string_name StringName
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._m_string_name;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._m_string_name = value;
+ }
+
+ public godot_string String
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._m_string;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._m_string = value;
+ }
+
+ public Vector3 Vector3
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._m_vector3;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._m_vector3 = value;
+ }
+
+ public Vector3i Vector3i
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._m_vector3i;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._m_vector3i = value;
+ }
+
+ public Vector2 Vector2
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._m_vector2;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._m_vector2 = value;
+ }
+
+ public Vector2i Vector2i
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._m_vector2i;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._m_vector2i = value;
+ }
+
+ public Rect2 Rect2
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._m_rect2;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._m_rect2 = value;
+ }
+
+ public Rect2i Rect2i
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._m_rect2i;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._m_rect2i = value;
+ }
+
+ public Plane Plane
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._m_plane;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._m_plane = value;
+ }
+
+ public Quaternion Quaternion
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._m_quaternion;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._m_quaternion = value;
+ }
+
+ public Color Color
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._m_color;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._m_color = value;
+ }
+
+ public godot_node_path NodePath
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._m_node_path;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._m_node_path = value;
+ }
+
+ public RID RID
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._m_rid;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._m_rid = value;
+ }
+
+ public godot_callable Callable
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._m_callable;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._m_callable = value;
+ }
+
+ public godot_signal Signal
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._m_signal;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._m_signal = value;
+ }
+
+ public godot_dictionary Dictionary
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._m_dictionary;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._m_dictionary = value;
+ }
+
+ public godot_array Array
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ readonly get => _data._m_array;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => _data._m_array = value;
+ }
+
+ public readonly IntPtr Object
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _data._m_obj_data.obj;
+ }
+
+ public void Dispose()
+ {
+ switch (Type)
+ {
+ case Variant.Type.Nil:
+ case Variant.Type.Bool:
+ case Variant.Type.Int:
+ case Variant.Type.Float:
+ case Variant.Type.Vector2:
+ case Variant.Type.Vector2i:
+ case Variant.Type.Rect2:
+ case Variant.Type.Rect2i:
+ case Variant.Type.Vector3:
+ case Variant.Type.Vector3i:
+ case Variant.Type.Plane:
+ case Variant.Type.Quaternion:
+ case Variant.Type.Color:
+ case Variant.Type.Rid:
+ return;
+ }
+
+ NativeFuncs.godotsharp_variant_destroy(ref this);
+ Type = Variant.Type.Nil;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ // ReSharper disable once InconsistentNaming
+ internal struct movable
+ {
+ // Variant.Type is generated as an enum of type long, so we can't use for the field as it must only take 32-bits.
+ [FieldOffset(0)] private int _typeField;
+
+ // There's padding here
+
+ [FieldOffset(8)] private godot_variant_data.godot_variant_data_mem _data;
+
+ public static unsafe explicit operator movable(in godot_variant value)
+ => *(movable*)CustomUnsafe.AsPointer(ref CustomUnsafe.AsRef(value));
+
+ public static unsafe explicit operator godot_variant(movable value)
+ => *(godot_variant*)Unsafe.AsPointer(ref value);
+
+ public unsafe ref godot_variant DangerousSelfRef =>
+ ref CustomUnsafe.AsRef((godot_variant*)Unsafe.AsPointer(ref this));
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ public ref struct godot_string
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal readonly unsafe godot_string* GetUnsafeAddress()
+ => (godot_string*)Unsafe.AsPointer(ref Unsafe.AsRef(in _ptr));
+
+ private IntPtr _ptr;
+
+ public void Dispose()
+ {
+ if (_ptr == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_string_destroy(ref this);
+ _ptr = IntPtr.Zero;
+ }
+
+ public readonly IntPtr Buffer
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr;
+ }
+
+ // Size including the null termination character
+ public readonly unsafe int Size
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr != IntPtr.Zero ? *((int*)_ptr - 1) : 0;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ public ref struct godot_string_name
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal readonly unsafe godot_string_name* GetUnsafeAddress()
+ => (godot_string_name*)Unsafe.AsPointer(ref Unsafe.AsRef(in _data));
+
+ private IntPtr _data;
+
+ public void Dispose()
+ {
+ if (_data == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_string_name_destroy(ref this);
+ _data = IntPtr.Zero;
+ }
+
+ public readonly bool IsAllocated
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _data != IntPtr.Zero;
+ }
+
+ public readonly bool IsEmpty
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // This is all that's needed to check if it's empty. Equivalent to `== StringName()` in C++.
+ get => _data == IntPtr.Zero;
+ }
+
+ public static bool operator ==(godot_string_name left, godot_string_name right)
+ {
+ return left._data == right._data;
+ }
+
+ public static bool operator !=(godot_string_name left, godot_string_name right)
+ {
+ return !(left == right);
+ }
+
+ public bool Equals(godot_string_name other)
+ {
+ return _data == other._data;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return obj is StringName s && s.Equals(this);
+ }
+
+ public override int GetHashCode()
+ {
+ return _data.GetHashCode();
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal struct movable
+ {
+ private IntPtr _data;
+
+ public static unsafe explicit operator movable(in godot_string_name value)
+ => *(movable*)CustomUnsafe.AsPointer(ref CustomUnsafe.AsRef(value));
+
+ public static unsafe explicit operator godot_string_name(movable value)
+ => *(godot_string_name*)Unsafe.AsPointer(ref value);
+
+ public unsafe ref godot_string_name DangerousSelfRef =>
+ ref CustomUnsafe.AsRef((godot_string_name*)Unsafe.AsPointer(ref this));
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ public ref struct godot_node_path
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal readonly unsafe godot_node_path* GetUnsafeAddress()
+ => (godot_node_path*)Unsafe.AsPointer(ref Unsafe.AsRef(in _data));
+
+ private IntPtr _data;
+
+ public void Dispose()
+ {
+ if (_data == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_node_path_destroy(ref this);
+ _data = IntPtr.Zero;
+ }
+
+ public readonly bool IsAllocated
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _data != IntPtr.Zero;
+ }
+
+ public readonly bool IsEmpty
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // This is all that's needed to check if it's empty. It's what the `is_empty()` C++ method does.
+ get => _data == IntPtr.Zero;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal struct movable
+ {
+ private IntPtr _data;
+
+ public static unsafe explicit operator movable(in godot_node_path value)
+ => *(movable*)CustomUnsafe.AsPointer(ref CustomUnsafe.AsRef(value));
+
+ public static unsafe explicit operator godot_node_path(movable value)
+ => *(godot_node_path*)Unsafe.AsPointer(ref value);
+
+ public unsafe ref godot_node_path DangerousSelfRef =>
+ ref CustomUnsafe.AsRef((godot_node_path*)Unsafe.AsPointer(ref this));
+ }
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ // ReSharper disable once InconsistentNaming
+ public ref struct godot_signal
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal readonly unsafe godot_signal* GetUnsafeAddress()
+ => (godot_signal*)Unsafe.AsPointer(ref Unsafe.AsRef(in _getUnsafeAddressHelper));
+
+ [FieldOffset(0)] private byte _getUnsafeAddressHelper;
+
+ [FieldOffset(0)] private godot_string_name _name;
+
+ // There's padding here on 32-bit
+
+ [FieldOffset(8)] private ulong _objectId;
+
+ public godot_signal(godot_string_name name, ulong objectId) : this()
+ {
+ _name = name;
+ _objectId = objectId;
+ }
+
+ public godot_string_name Name
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _name;
+ }
+
+ public ulong ObjectId
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _objectId;
+ }
+
+ public void Dispose()
+ {
+ if (!_name.IsAllocated)
+ return;
+ NativeFuncs.godotsharp_signal_destroy(ref this);
+ _name = default;
+ }
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ // ReSharper disable once InconsistentNaming
+ public ref struct godot_callable
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal readonly unsafe godot_callable* GetUnsafeAddress()
+ => (godot_callable*)Unsafe.AsPointer(ref Unsafe.AsRef(in _getUnsafeAddressHelper));
+
+ [FieldOffset(0)] private byte _getUnsafeAddressHelper;
+
+ [FieldOffset(0)] private godot_string_name _method;
+
+ // There's padding here on 32-bit
+
+ // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
+ [FieldOffset(8)] private ulong _objectId;
+ [FieldOffset(8)] private IntPtr _custom;
+
+ public godot_callable(godot_string_name method, ulong objectId) : this()
+ {
+ _method = method;
+ _objectId = objectId;
+ }
+
+ public void Dispose()
+ {
+ // _custom needs freeing as well
+ if (!_method.IsAllocated && _custom == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_callable_destroy(ref this);
+ _method = default;
+ _custom = IntPtr.Zero;
+ }
+ }
+
+ // A correctly constructed value needs to call the native default constructor to allocate `_p`.
+ // Don't pass a C# default constructed `godot_array` to native code, unless it's going to
+ // be re-assigned a new value (the copy constructor checks if `_p` is null so that's fine).
+ [StructLayout(LayoutKind.Explicit)]
+ // ReSharper disable once InconsistentNaming
+ public ref struct godot_array
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal readonly unsafe godot_array* GetUnsafeAddress()
+ => (godot_array*)Unsafe.AsPointer(ref Unsafe.AsRef(in _getUnsafeAddressHelper));
+
+ [FieldOffset(0)] private byte _getUnsafeAddressHelper;
+
+ [FieldOffset(0)] private unsafe ArrayPrivate* _p;
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct ArrayPrivate
+ {
+ private uint _safeRefCount;
+
+ public VariantVector _arrayVector;
+ // There are more fields here, but we don't care as we never store this in C#
+
+ public readonly int Size
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _arrayVector.Size;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct VariantVector
+ {
+ private IntPtr _writeProxy;
+ public unsafe godot_variant* _ptr;
+
+ public readonly unsafe int Size
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr != null ? *((int*)_ptr - 1) : 0;
+ }
+ }
+
+ public readonly unsafe godot_variant* Elements
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _p->_arrayVector._ptr;
+ }
+
+ public readonly unsafe bool IsAllocated
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _p != null;
+ }
+
+ public readonly unsafe int Size
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _p != null ? _p->Size : 0;
+ }
+
+ public unsafe void Dispose()
+ {
+ if (_p == null)
+ return;
+ NativeFuncs.godotsharp_array_destroy(ref this);
+ _p = null;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal struct movable
+ {
+ private unsafe ArrayPrivate* _p;
+
+ public static unsafe explicit operator movable(in godot_array value)
+ => *(movable*)CustomUnsafe.AsPointer(ref CustomUnsafe.AsRef(value));
+
+ public static unsafe explicit operator godot_array(movable value)
+ => *(godot_array*)Unsafe.AsPointer(ref value);
+
+ public unsafe ref godot_array DangerousSelfRef =>
+ ref CustomUnsafe.AsRef((godot_array*)Unsafe.AsPointer(ref this));
+ }
+ }
+
+ // IMPORTANT:
+ // A correctly constructed value needs to call the native default constructor to allocate `_p`.
+ // Don't pass a C# default constructed `godot_dictionary` to native code, unless it's going to
+ // be re-assigned a new value (the copy constructor checks if `_p` is null so that's fine).
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ public ref struct godot_dictionary
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal readonly unsafe godot_dictionary* GetUnsafeAddress()
+ => (godot_dictionary*)Unsafe.AsPointer(ref Unsafe.AsRef(in _p));
+
+ private IntPtr _p;
+
+ public readonly bool IsAllocated
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _p != IntPtr.Zero;
+ }
+
+ public void Dispose()
+ {
+ if (_p == IntPtr.Zero)
+ return;
+ NativeFuncs.godotsharp_dictionary_destroy(ref this);
+ _p = IntPtr.Zero;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ internal struct movable
+ {
+ private IntPtr _p;
+
+ public static unsafe explicit operator movable(in godot_dictionary value)
+ => *(movable*)CustomUnsafe.AsPointer(ref CustomUnsafe.AsRef(value));
+
+ public static unsafe explicit operator godot_dictionary(movable value)
+ => *(godot_dictionary*)Unsafe.AsPointer(ref value);
+
+ public unsafe ref godot_dictionary DangerousSelfRef =>
+ ref CustomUnsafe.AsRef((godot_dictionary*)Unsafe.AsPointer(ref this));
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ public ref struct godot_packed_byte_array
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal readonly unsafe godot_packed_byte_array* GetUnsafeAddress()
+ => (godot_packed_byte_array*)Unsafe.AsPointer(ref Unsafe.AsRef(in _writeProxy));
+
+ private IntPtr _writeProxy;
+ private unsafe byte* _ptr;
+
+ public unsafe void Dispose()
+ {
+ if (_ptr == null)
+ return;
+ NativeFuncs.godotsharp_packed_byte_array_destroy(ref this);
+ _ptr = null;
+ }
+
+ public readonly unsafe byte* Buffer
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr;
+ }
+
+ public readonly unsafe int Size
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr != null ? *((int*)_ptr - 1) : 0;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ public ref struct godot_packed_int32_array
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal readonly unsafe godot_packed_int32_array* GetUnsafeAddress()
+ => (godot_packed_int32_array*)Unsafe.AsPointer(ref Unsafe.AsRef(in _writeProxy));
+
+ private IntPtr _writeProxy;
+ private unsafe int* _ptr;
+
+ public unsafe void Dispose()
+ {
+ if (_ptr == null)
+ return;
+ NativeFuncs.godotsharp_packed_int32_array_destroy(ref this);
+ _ptr = null;
+ }
+
+ public readonly unsafe int* Buffer
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr;
+ }
+
+ public readonly unsafe int Size
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr != null ? *(_ptr - 1) : 0;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ public ref struct godot_packed_int64_array
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal readonly unsafe godot_packed_int64_array* GetUnsafeAddress()
+ => (godot_packed_int64_array*)Unsafe.AsPointer(ref Unsafe.AsRef(in _writeProxy));
+
+ private IntPtr _writeProxy;
+ private unsafe long* _ptr;
+
+ public unsafe void Dispose()
+ {
+ if (_ptr == null)
+ return;
+ NativeFuncs.godotsharp_packed_int64_array_destroy(ref this);
+ _ptr = null;
+ }
+
+ public readonly unsafe long* Buffer
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr;
+ }
+
+ public readonly unsafe int Size
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr != null ? *((int*)_ptr - 1) : 0;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ public ref struct godot_packed_float32_array
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal readonly unsafe godot_packed_float32_array* GetUnsafeAddress()
+ => (godot_packed_float32_array*)Unsafe.AsPointer(ref Unsafe.AsRef(in _writeProxy));
+
+ private IntPtr _writeProxy;
+ private unsafe float* _ptr;
+
+ public unsafe void Dispose()
+ {
+ if (_ptr == null)
+ return;
+ NativeFuncs.godotsharp_packed_float32_array_destroy(ref this);
+ _ptr = null;
+ }
+
+ public readonly unsafe float* Buffer
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr;
+ }
+
+ public readonly unsafe int Size
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr != null ? *((int*)_ptr - 1) : 0;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ public ref struct godot_packed_float64_array
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal readonly unsafe godot_packed_float64_array* GetUnsafeAddress()
+ => (godot_packed_float64_array*)Unsafe.AsPointer(ref Unsafe.AsRef(in _writeProxy));
+
+ private IntPtr _writeProxy;
+ private unsafe double* _ptr;
+
+ public unsafe void Dispose()
+ {
+ if (_ptr == null)
+ return;
+ NativeFuncs.godotsharp_packed_float64_array_destroy(ref this);
+ _ptr = null;
+ }
+
+ public readonly unsafe double* Buffer
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr;
+ }
+
+ public readonly unsafe int Size
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr != null ? *((int*)_ptr - 1) : 0;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ public ref struct godot_packed_string_array
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal readonly unsafe godot_packed_string_array* GetUnsafeAddress()
+ => (godot_packed_string_array*)Unsafe.AsPointer(ref Unsafe.AsRef(in _writeProxy));
+
+ private IntPtr _writeProxy;
+ private unsafe godot_string* _ptr;
+
+ public unsafe void Dispose()
+ {
+ if (_ptr == null)
+ return;
+ NativeFuncs.godotsharp_packed_string_array_destroy(ref this);
+ _ptr = null;
+ }
+
+ public readonly unsafe godot_string* Buffer
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr;
+ }
+
+ public readonly unsafe int Size
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr != null ? *((int*)_ptr - 1) : 0;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ public ref struct godot_packed_vector2_array
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal readonly unsafe godot_packed_vector2_array* GetUnsafeAddress()
+ => (godot_packed_vector2_array*)Unsafe.AsPointer(ref Unsafe.AsRef(in _writeProxy));
+
+ private IntPtr _writeProxy;
+ private unsafe Vector2* _ptr;
+
+ public unsafe void Dispose()
+ {
+ if (_ptr == null)
+ return;
+ NativeFuncs.godotsharp_packed_vector2_array_destroy(ref this);
+ _ptr = null;
+ }
+
+ public readonly unsafe Vector2* Buffer
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr;
+ }
+
+ public readonly unsafe int Size
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr != null ? *((int*)_ptr - 1) : 0;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ public ref struct godot_packed_vector3_array
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal readonly unsafe godot_packed_vector3_array* GetUnsafeAddress()
+ => (godot_packed_vector3_array*)Unsafe.AsPointer(ref Unsafe.AsRef(in _writeProxy));
+
+ private IntPtr _writeProxy;
+ private unsafe Vector3* _ptr;
+
+ public unsafe void Dispose()
+ {
+ if (_ptr == null)
+ return;
+ NativeFuncs.godotsharp_packed_vector3_array_destroy(ref this);
+ _ptr = null;
+ }
+
+ public readonly unsafe Vector3* Buffer
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr;
+ }
+
+ public readonly unsafe int Size
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr != null ? *((int*)_ptr - 1) : 0;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ // ReSharper disable once InconsistentNaming
+ public ref struct godot_packed_color_array
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal readonly unsafe godot_packed_color_array* GetUnsafeAddress()
+ => (godot_packed_color_array*)Unsafe.AsPointer(ref Unsafe.AsRef(in _writeProxy));
+
+ private IntPtr _writeProxy;
+ private unsafe Color* _ptr;
+
+ public unsafe void Dispose()
+ {
+ if (_ptr == null)
+ return;
+ NativeFuncs.godotsharp_packed_color_array_destroy(ref this);
+ _ptr = null;
+ }
+
+ public readonly unsafe Color* Buffer
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr;
+ }
+
+ public readonly unsafe int Size
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => _ptr != null ? *((int*)_ptr - 1) : 0;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs
new file mode 100644
index 0000000000..82f1c04d40
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/InteropUtils.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Runtime.InteropServices;
+using Godot.Bridge;
+
+// ReSharper disable InconsistentNaming
+
+namespace Godot.NativeInterop
+{
+ internal static class InteropUtils
+ {
+ public static Object UnmanagedGetManaged(IntPtr unmanaged)
+ {
+ // The native pointer may be null
+ if (unmanaged == IntPtr.Zero)
+ return null;
+
+ IntPtr gcHandlePtr;
+ godot_bool hasCsScriptInstance;
+
+ // First try to get the tied managed instance from a CSharpInstance script instance
+
+ gcHandlePtr = NativeFuncs.godotsharp_internal_unmanaged_get_script_instance_managed(
+ unmanaged, out hasCsScriptInstance);
+
+ if (gcHandlePtr != IntPtr.Zero)
+ return (Object)GCHandle.FromIntPtr(gcHandlePtr).Target;
+
+ // Otherwise, if the object has a CSharpInstance script instance, return null
+
+ if (hasCsScriptInstance.ToBool())
+ return null;
+
+ // If it doesn't have a CSharpInstance script instance, try with native instance bindings
+
+ gcHandlePtr = NativeFuncs.godotsharp_internal_unmanaged_get_instance_binding_managed(unmanaged);
+
+ object target = gcHandlePtr != IntPtr.Zero ? GCHandle.FromIntPtr(gcHandlePtr).Target : null;
+
+ if (target != null)
+ return (Object)target;
+
+ // If the native instance binding GC handle target was collected, create a new one
+
+ gcHandlePtr = NativeFuncs.godotsharp_internal_unmanaged_instance_binding_create_managed(
+ unmanaged, gcHandlePtr);
+
+ return gcHandlePtr != IntPtr.Zero ? (Object)GCHandle.FromIntPtr(gcHandlePtr).Target : null;
+ }
+
+ public static void TieManagedToUnmanaged(Object managed, IntPtr unmanaged,
+ StringName nativeName, bool refCounted, Type type, Type nativeType)
+ {
+ var gcHandle = refCounted ?
+ CustomGCHandle.AllocWeak(managed) :
+ CustomGCHandle.AllocStrong(managed, type);
+
+ if (type == nativeType)
+ {
+ var nativeNameSelf = (godot_string_name)nativeName.NativeValue;
+ NativeFuncs.godotsharp_internal_tie_native_managed_to_unmanaged(
+ GCHandle.ToIntPtr(gcHandle), unmanaged, nativeNameSelf, refCounted.ToGodotBool());
+ }
+ else
+ {
+ unsafe
+ {
+ // We don't dispose `script` ourselves here.
+ // `tie_user_managed_to_unmanaged` does it for us to avoid another P/Invoke call.
+ godot_ref script;
+ ScriptManagerBridge.GetOrLoadOrCreateScriptForType(type, &script);
+
+ // IMPORTANT: This must be called after GetOrCreateScriptBridgeForType
+ NativeFuncs.godotsharp_internal_tie_user_managed_to_unmanaged(
+ GCHandle.ToIntPtr(gcHandle), unmanaged, &script, refCounted.ToGodotBool());
+ }
+ }
+ }
+
+ public static void TieManagedToUnmanagedWithPreSetup(Object managed, IntPtr unmanaged,
+ Type type, Type nativeType)
+ {
+ if (type == nativeType)
+ return;
+
+ var strongGCHandle = CustomGCHandle.AllocStrong(managed);
+ NativeFuncs.godotsharp_internal_tie_managed_to_unmanaged_with_pre_setup(
+ GCHandle.ToIntPtr(strongGCHandle), unmanaged);
+ }
+
+ public static Object EngineGetSingleton(string name)
+ {
+ using godot_string src = Marshaling.ConvertStringToNative(name);
+ return UnmanagedGetManaged(NativeFuncs.godotsharp_engine_get_singleton(src));
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
new file mode 100644
index 0000000000..eee19aea46
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/Marshaling.cs
@@ -0,0 +1,1092 @@
+using System;
+using System.Runtime.InteropServices;
+
+// ReSharper disable InconsistentNaming
+
+// We want to use full name qualifiers here even if redundant for clarity
+// ReSharper disable RedundantNameQualifier
+
+#nullable enable
+
+namespace Godot.NativeInterop
+{
+ public static class Marshaling
+ {
+ internal static Variant.Type ConvertManagedTypeToVariantType(Type type, out bool r_nil_is_variant)
+ {
+ r_nil_is_variant = false;
+
+ switch (Type.GetTypeCode(type))
+ {
+ case TypeCode.Boolean:
+ return Variant.Type.Bool;
+ case TypeCode.Char:
+ return Variant.Type.Int;
+ case TypeCode.SByte:
+ return Variant.Type.Int;
+ case TypeCode.Int16:
+ return Variant.Type.Int;
+ case TypeCode.Int32:
+ return Variant.Type.Int;
+ case TypeCode.Int64:
+ return Variant.Type.Int;
+ case TypeCode.Byte:
+ return Variant.Type.Int;
+ case TypeCode.UInt16:
+ return Variant.Type.Int;
+ case TypeCode.UInt32:
+ return Variant.Type.Int;
+ case TypeCode.UInt64:
+ return Variant.Type.Int;
+ case TypeCode.Single:
+ return Variant.Type.Float;
+ case TypeCode.Double:
+ return Variant.Type.Float;
+ case TypeCode.String:
+ return Variant.Type.String;
+ default:
+ {
+ if (type == typeof(Vector2))
+ return Variant.Type.Vector2;
+
+ if (type == typeof(Vector2i))
+ return Variant.Type.Vector2i;
+
+ if (type == typeof(Rect2))
+ return Variant.Type.Rect2;
+
+ if (type == typeof(Rect2i))
+ return Variant.Type.Rect2i;
+
+ if (type == typeof(Transform2D))
+ return Variant.Type.Transform2d;
+
+ if (type == typeof(Vector3))
+ return Variant.Type.Vector3;
+
+ if (type == typeof(Vector3i))
+ return Variant.Type.Vector3i;
+
+ if (type == typeof(Vector4))
+ return Variant.Type.Vector4;
+
+ if (type == typeof(Vector4i))
+ return Variant.Type.Vector4i;
+
+ if (type == typeof(Basis))
+ return Variant.Type.Basis;
+
+ if (type == typeof(Quaternion))
+ return Variant.Type.Quaternion;
+
+ if (type == typeof(Transform3D))
+ return Variant.Type.Transform3d;
+
+ if (type == typeof(Projection))
+ return Variant.Type.Projection;
+
+ if (type == typeof(AABB))
+ return Variant.Type.Aabb;
+
+ if (type == typeof(Color))
+ return Variant.Type.Color;
+
+ if (type == typeof(Plane))
+ return Variant.Type.Plane;
+
+ if (type == typeof(Callable))
+ return Variant.Type.Callable;
+
+ if (type == typeof(SignalInfo))
+ return Variant.Type.Signal;
+
+ if (type.IsEnum)
+ return Variant.Type.Int;
+
+ if (type.IsArray || type.IsSZArray)
+ {
+ if (type == typeof(byte[]))
+ return Variant.Type.PackedByteArray;
+
+ if (type == typeof(int[]))
+ return Variant.Type.PackedInt32Array;
+
+ if (type == typeof(long[]))
+ return Variant.Type.PackedInt64Array;
+
+ if (type == typeof(float[]))
+ return Variant.Type.PackedFloat32Array;
+
+ if (type == typeof(double[]))
+ return Variant.Type.PackedFloat64Array;
+
+ if (type == typeof(string[]))
+ return Variant.Type.PackedStringArray;
+
+ if (type == typeof(Vector2[]))
+ return Variant.Type.PackedVector2Array;
+
+ if (type == typeof(Vector3[]))
+ return Variant.Type.PackedVector3Array;
+
+ if (type == typeof(Color[]))
+ return Variant.Type.PackedColorArray;
+
+ if (type == typeof(StringName[]))
+ return Variant.Type.Array;
+
+ if (type == typeof(NodePath[]))
+ return Variant.Type.Array;
+
+ if (type == typeof(RID[]))
+ return Variant.Type.Array;
+
+ if (typeof(Godot.Object[]).IsAssignableFrom(type))
+ return Variant.Type.Array;
+ }
+ else if (type.IsGenericType)
+ {
+ if (typeof(Godot.Object).IsAssignableFrom(type))
+ return Variant.Type.Object;
+ }
+ else if (type == typeof(Variant))
+ {
+ r_nil_is_variant = true;
+ return Variant.Type.Nil;
+ }
+ else
+ {
+ if (typeof(Godot.Object).IsAssignableFrom(type))
+ return Variant.Type.Object;
+
+ if (typeof(StringName) == type)
+ return Variant.Type.StringName;
+
+ if (typeof(NodePath) == type)
+ return Variant.Type.NodePath;
+
+ if (typeof(RID) == type)
+ return Variant.Type.Rid;
+
+ if (typeof(Collections.Dictionary) == type)
+ return Variant.Type.Dictionary;
+
+ if (typeof(Collections.Array) == type)
+ return Variant.Type.Array;
+ }
+
+ break;
+ }
+ }
+
+ // Unknown
+ return Variant.Type.Nil;
+ }
+
+ /* TODO: Reflection and type checking each time is slow. This will be replaced with source generators. */
+ public static godot_variant ConvertManagedObjectToVariant(object? p_obj)
+ {
+ if (p_obj == null)
+ return new godot_variant();
+
+ switch (p_obj)
+ {
+ case bool @bool:
+ return VariantUtils.CreateFromBool(@bool);
+ case char @char:
+ return VariantUtils.CreateFromInt(@char);
+ case sbyte @int8:
+ return VariantUtils.CreateFromInt(@int8);
+ case short @int16:
+ return VariantUtils.CreateFromInt(@int16);
+ case int @int32:
+ return VariantUtils.CreateFromInt(@int32);
+ case long @int64:
+ return VariantUtils.CreateFromInt(@int64);
+ case byte @uint8:
+ return VariantUtils.CreateFromInt(@uint8);
+ case ushort @uint16:
+ return VariantUtils.CreateFromInt(@uint16);
+ case uint @uint32:
+ return VariantUtils.CreateFromInt(@uint32);
+ case ulong @uint64:
+ return VariantUtils.CreateFromInt(@uint64);
+ case float @float:
+ return VariantUtils.CreateFromFloat(@float);
+ case double @double:
+ return VariantUtils.CreateFromFloat(@double);
+ case Vector2 @vector2:
+ return VariantUtils.CreateFromVector2(@vector2);
+ case Vector2i @vector2i:
+ return VariantUtils.CreateFromVector2i(@vector2i);
+ case Rect2 @rect2:
+ return VariantUtils.CreateFromRect2(@rect2);
+ case Rect2i @rect2i:
+ return VariantUtils.CreateFromRect2i(@rect2i);
+ case Transform2D @transform2D:
+ return VariantUtils.CreateFromTransform2D(@transform2D);
+ case Vector3 @vector3:
+ return VariantUtils.CreateFromVector3(@vector3);
+ case Vector3i @vector3i:
+ return VariantUtils.CreateFromVector3i(@vector3i);
+ case Vector4 @vector4:
+ return VariantUtils.CreateFromVector4(@vector4);
+ case Vector4i @vector4i:
+ return VariantUtils.CreateFromVector4i(@vector4i);
+ case Basis @basis:
+ return VariantUtils.CreateFromBasis(@basis);
+ case Quaternion @quaternion:
+ return VariantUtils.CreateFromQuaternion(@quaternion);
+ case Transform3D @transform3d:
+ return VariantUtils.CreateFromTransform3D(@transform3d);
+ case Projection @projection:
+ return VariantUtils.CreateFromProjection(@projection);
+ case AABB @aabb:
+ return VariantUtils.CreateFromAABB(@aabb);
+ case Color @color:
+ return VariantUtils.CreateFromColor(@color);
+ case Plane @plane:
+ return VariantUtils.CreateFromPlane(@plane);
+ case Callable @callable:
+ return VariantUtils.CreateFromCallable(@callable);
+ case SignalInfo @signalInfo:
+ return VariantUtils.CreateFromSignalInfo(@signalInfo);
+ case Enum @enum:
+ return VariantUtils.CreateFromInt(Convert.ToInt64(@enum));
+ case string @string:
+ return VariantUtils.CreateFromString(@string);
+ case byte[] byteArray:
+ return VariantUtils.CreateFromPackedByteArray(byteArray);
+ case int[] int32Array:
+ return VariantUtils.CreateFromPackedInt32Array(int32Array);
+ case long[] int64Array:
+ return VariantUtils.CreateFromPackedInt64Array(int64Array);
+ case float[] floatArray:
+ return VariantUtils.CreateFromPackedFloat32Array(floatArray);
+ case double[] doubleArray:
+ return VariantUtils.CreateFromPackedFloat64Array(doubleArray);
+ case string[] stringArray:
+ return VariantUtils.CreateFromPackedStringArray(stringArray);
+ case Vector2[] vector2Array:
+ return VariantUtils.CreateFromPackedVector2Array(vector2Array);
+ case Vector3[] vector3Array:
+ return VariantUtils.CreateFromPackedVector3Array(vector3Array);
+ case Color[] colorArray:
+ return VariantUtils.CreateFromPackedColorArray(colorArray);
+ case StringName[] stringNameArray:
+ return VariantUtils.CreateFromSystemArrayOfStringName(stringNameArray);
+ case NodePath[] nodePathArray:
+ return VariantUtils.CreateFromSystemArrayOfNodePath(nodePathArray);
+ case RID[] ridArray:
+ return VariantUtils.CreateFromSystemArrayOfRID(ridArray);
+ case Godot.Object[] godotObjectArray:
+ return VariantUtils.CreateFromSystemArrayOfGodotObject(godotObjectArray);
+ case Godot.Object godotObject:
+ return VariantUtils.CreateFromGodotObject(godotObject);
+ case StringName stringName:
+ return VariantUtils.CreateFromStringName(stringName);
+ case NodePath nodePath:
+ return VariantUtils.CreateFromNodePath(nodePath);
+ case RID rid:
+ return VariantUtils.CreateFromRID(rid);
+ case Collections.Dictionary godotDictionary:
+ return VariantUtils.CreateFromDictionary(godotDictionary);
+ case Collections.Array godotArray:
+ return VariantUtils.CreateFromArray(godotArray);
+ case Variant variant:
+ return NativeFuncs.godotsharp_variant_new_copy((godot_variant)variant.NativeVar);
+ }
+
+ GD.PushError("Attempted to convert an unmarshallable managed type to Variant. Name: '" +
+ p_obj.GetType().FullName + ".");
+ return new godot_variant();
+ }
+
+ public static object? ConvertVariantToManagedObjectOfType(in godot_variant p_var, Type type)
+ {
+ // This function is only needed to set the value of properties. Fields have their own implementation, set_value_from_variant.
+ switch (Type.GetTypeCode(type))
+ {
+ case TypeCode.Boolean:
+ return VariantUtils.ConvertToBool(p_var);
+ case TypeCode.Char:
+ return VariantUtils.ConvertToChar(p_var);
+ case TypeCode.SByte:
+ return VariantUtils.ConvertToInt8(p_var);
+ case TypeCode.Int16:
+ return VariantUtils.ConvertToInt16(p_var);
+ case TypeCode.Int32:
+ return VariantUtils.ConvertToInt32(p_var);
+ case TypeCode.Int64:
+ return VariantUtils.ConvertToInt64(p_var);
+ case TypeCode.Byte:
+ return VariantUtils.ConvertToUInt8(p_var);
+ case TypeCode.UInt16:
+ return VariantUtils.ConvertToUInt16(p_var);
+ case TypeCode.UInt32:
+ return VariantUtils.ConvertToUInt32(p_var);
+ case TypeCode.UInt64:
+ return VariantUtils.ConvertToUInt64(p_var);
+ case TypeCode.Single:
+ return VariantUtils.ConvertToFloat32(p_var);
+ case TypeCode.Double:
+ return VariantUtils.ConvertToFloat64(p_var);
+ case TypeCode.String:
+ return VariantUtils.ConvertToStringObject(p_var);
+ default:
+ {
+ if (type == typeof(Vector2))
+ return VariantUtils.ConvertToVector2(p_var);
+
+ if (type == typeof(Vector2i))
+ return VariantUtils.ConvertToVector2i(p_var);
+
+ if (type == typeof(Rect2))
+ return VariantUtils.ConvertToRect2(p_var);
+
+ if (type == typeof(Rect2i))
+ return VariantUtils.ConvertToRect2i(p_var);
+
+ if (type == typeof(Transform2D))
+ return VariantUtils.ConvertToTransform2D(p_var);
+
+ if (type == typeof(Vector3))
+ return VariantUtils.ConvertToVector3(p_var);
+
+ if (type == typeof(Vector3i))
+ return VariantUtils.ConvertToVector3i(p_var);
+
+ if (type == typeof(Vector4))
+ return VariantUtils.ConvertToVector4(p_var);
+
+ if (type == typeof(Vector4i))
+ return VariantUtils.ConvertToVector4i(p_var);
+
+ if (type == typeof(Basis))
+ return VariantUtils.ConvertToBasis(p_var);
+
+ if (type == typeof(Quaternion))
+ return VariantUtils.ConvertToQuaternion(p_var);
+
+ if (type == typeof(Transform3D))
+ return VariantUtils.ConvertToTransform3D(p_var);
+
+ if (type == typeof(Projection))
+ return VariantUtils.ConvertToProjection(p_var);
+
+ if (type == typeof(AABB))
+ return VariantUtils.ConvertToAABB(p_var);
+
+ if (type == typeof(Color))
+ return VariantUtils.ConvertToColor(p_var);
+
+ if (type == typeof(Plane))
+ return VariantUtils.ConvertToPlane(p_var);
+
+ if (type == typeof(Callable))
+ return VariantUtils.ConvertToCallableManaged(p_var);
+
+ if (type == typeof(SignalInfo))
+ return VariantUtils.ConvertToSignalInfo(p_var);
+
+ if (type.IsEnum)
+ {
+ var enumUnderlyingType = type.GetEnumUnderlyingType();
+ switch (Type.GetTypeCode(enumUnderlyingType))
+ {
+ case TypeCode.SByte:
+ return VariantUtils.ConvertToInt8(p_var);
+ case TypeCode.Int16:
+ return VariantUtils.ConvertToInt16(p_var);
+ case TypeCode.Int32:
+ return VariantUtils.ConvertToInt32(p_var);
+ case TypeCode.Int64:
+ return VariantUtils.ConvertToInt64(p_var);
+ case TypeCode.Byte:
+ return VariantUtils.ConvertToUInt8(p_var);
+ case TypeCode.UInt16:
+ return VariantUtils.ConvertToUInt16(p_var);
+ case TypeCode.UInt32:
+ return VariantUtils.ConvertToUInt32(p_var);
+ case TypeCode.UInt64:
+ return VariantUtils.ConvertToUInt64(p_var);
+ default:
+ {
+ GD.PushError(
+ "Attempted to convert Variant to enum value of unsupported underlying type. Name: " +
+ type.FullName + " : " + enumUnderlyingType.FullName + ".");
+ return null;
+ }
+ }
+ }
+
+ if (type.IsArray || type.IsSZArray)
+ {
+ return ConvertVariantToSystemArrayOfType(p_var, type);
+ }
+ else if (type.IsGenericType)
+ {
+ if (typeof(Godot.Object).IsAssignableFrom(type))
+ {
+ var godotObject = VariantUtils.ConvertToGodotObject(p_var);
+
+ if (!type.IsInstanceOfType(godotObject))
+ {
+ GD.PushError("Invalid cast when marshaling Godot.Object type." +
+ $" `{godotObject.GetType()}` is not assignable to `{type.FullName}`.");
+ return null;
+ }
+
+ return godotObject;
+ }
+
+ return null;
+ }
+ else if (type == typeof(Variant))
+ {
+ return Variant.CreateCopyingBorrowed(p_var);
+ }
+
+ if (ConvertVariantToManagedObjectOfClass(p_var, type, out object? res))
+ return res;
+
+ break;
+ }
+ }
+
+ GD.PushError("Attempted to convert Variant to unsupported type. Name: " +
+ type.FullName + ".");
+ return null;
+ }
+
+ private static object? ConvertVariantToSystemArrayOfType(in godot_variant p_var, Type type)
+ {
+ if (type == typeof(byte[]))
+ return VariantUtils.ConvertAsPackedByteArrayToSystemArray(p_var);
+
+ if (type == typeof(int[]))
+ return VariantUtils.ConvertAsPackedInt32ArrayToSystemArray(p_var);
+
+ if (type == typeof(long[]))
+ return VariantUtils.ConvertAsPackedInt64ArrayToSystemArray(p_var);
+
+ if (type == typeof(float[]))
+ return VariantUtils.ConvertAsPackedFloat32ArrayToSystemArray(p_var);
+
+ if (type == typeof(double[]))
+ return VariantUtils.ConvertAsPackedFloat64ArrayToSystemArray(p_var);
+
+ if (type == typeof(string[]))
+ return VariantUtils.ConvertAsPackedStringArrayToSystemArray(p_var);
+
+ if (type == typeof(Vector2[]))
+ return VariantUtils.ConvertAsPackedVector2ArrayToSystemArray(p_var);
+
+ if (type == typeof(Vector3[]))
+ return VariantUtils.ConvertAsPackedVector3ArrayToSystemArray(p_var);
+
+ if (type == typeof(Color[]))
+ return VariantUtils.ConvertAsPackedColorArrayToSystemArray(p_var);
+
+ if (type == typeof(StringName[]))
+ return VariantUtils.ConvertToSystemArrayOfStringName(p_var);
+
+ if (type == typeof(NodePath[]))
+ return VariantUtils.ConvertToSystemArrayOfNodePath(p_var);
+
+ if (type == typeof(RID[]))
+ return VariantUtils.ConvertToSystemArrayOfRID(p_var);
+
+ if (typeof(Godot.Object[]).IsAssignableFrom(type))
+ return VariantUtils.ConvertToSystemArrayOfGodotObject(p_var, type);
+
+ GD.PushError("Attempted to convert Variant to array of unsupported element type. Name: " +
+ type.GetElementType()!.FullName + ".");
+ return null;
+ }
+
+ private static bool ConvertVariantToManagedObjectOfClass(in godot_variant p_var, Type type,
+ out object? res)
+ {
+ if (typeof(Godot.Object).IsAssignableFrom(type))
+ {
+ if (p_var.Type == Variant.Type.Nil)
+ {
+ res = null;
+ return true;
+ }
+
+ if (p_var.Type != Variant.Type.Object)
+ {
+ GD.PushError("Invalid cast when marshaling Godot.Object type." +
+ $" Variant type is `{p_var.Type}`; expected `{p_var.Object}`.");
+ res = null;
+ return true;
+ }
+
+ var godotObjectPtr = VariantUtils.ConvertToGodotObjectPtr(p_var);
+
+ if (godotObjectPtr == IntPtr.Zero)
+ {
+ res = null;
+ return true;
+ }
+
+ var godotObject = InteropUtils.UnmanagedGetManaged(godotObjectPtr);
+
+ if (!type.IsInstanceOfType(godotObject))
+ {
+ GD.PushError("Invalid cast when marshaling Godot.Object type." +
+ $" `{godotObject.GetType()}` is not assignable to `{type.FullName}`.");
+ res = null;
+ return false;
+ }
+
+ res = godotObject;
+ return true;
+ }
+
+ if (typeof(StringName) == type)
+ {
+ res = VariantUtils.ConvertToStringNameObject(p_var);
+ return true;
+ }
+
+ if (typeof(NodePath) == type)
+ {
+ res = VariantUtils.ConvertToNodePathObject(p_var);
+ return true;
+ }
+
+ if (typeof(RID) == type)
+ {
+ res = VariantUtils.ConvertToRID(p_var);
+ return true;
+ }
+
+ if (typeof(Collections.Dictionary) == type)
+ {
+ res = VariantUtils.ConvertToDictionaryObject(p_var);
+ return true;
+ }
+
+ if (typeof(Collections.Array) == type)
+ {
+ res = VariantUtils.ConvertToArrayObject(p_var);
+ return true;
+ }
+
+ res = null;
+ return false;
+ }
+
+ public static unsafe object? ConvertVariantToManagedObject(in godot_variant p_var)
+ {
+ switch (p_var.Type)
+ {
+ case Variant.Type.Bool:
+ return p_var.Bool.ToBool();
+ case Variant.Type.Int:
+ return p_var.Int;
+ case Variant.Type.Float:
+ {
+#if REAL_T_IS_DOUBLE
+ return p_var.Float;
+#else
+ return (float)p_var.Float;
+#endif
+ }
+ case Variant.Type.String:
+ return ConvertStringToManaged(p_var.String);
+ case Variant.Type.Vector2:
+ return p_var.Vector2;
+ case Variant.Type.Vector2i:
+ return p_var.Vector2i;
+ case Variant.Type.Rect2:
+ return p_var.Rect2;
+ case Variant.Type.Rect2i:
+ return p_var.Rect2i;
+ case Variant.Type.Vector3:
+ return p_var.Vector3;
+ case Variant.Type.Vector3i:
+ return p_var.Vector3i;
+ case Variant.Type.Transform2d:
+ return *p_var.Transform2D;
+ case Variant.Type.Vector4:
+ return *p_var.Vector4;
+ case Variant.Type.Vector4i:
+ return *p_var.Vector4i;
+ case Variant.Type.Plane:
+ return p_var.Plane;
+ case Variant.Type.Quaternion:
+ return p_var.Quaternion;
+ case Variant.Type.Aabb:
+ return *p_var.AABB;
+ case Variant.Type.Basis:
+ return *p_var.Basis;
+ case Variant.Type.Transform3d:
+ return *p_var.Transform3D;
+ case Variant.Type.Projection:
+ return *p_var.Projection;
+ case Variant.Type.Color:
+ return p_var.Color;
+ case Variant.Type.StringName:
+ {
+ // The Variant owns the value, so we need to make a copy
+ return StringName.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_string_name_new_copy(p_var.StringName));
+ }
+ case Variant.Type.NodePath:
+ {
+ // The Variant owns the value, so we need to make a copy
+ return NodePath.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_node_path_new_copy(p_var.NodePath));
+ }
+ case Variant.Type.Rid:
+ return p_var.RID;
+ case Variant.Type.Object:
+ return InteropUtils.UnmanagedGetManaged(p_var.Object);
+ case Variant.Type.Callable:
+ return ConvertCallableToManaged(p_var.Callable);
+ case Variant.Type.Signal:
+ return ConvertSignalToManaged(p_var.Signal);
+ case Variant.Type.Dictionary:
+ {
+ // The Variant owns the value, so we need to make a copy
+ return Collections.Dictionary.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_dictionary_new_copy(p_var.Dictionary));
+ }
+ case Variant.Type.Array:
+ {
+ // The Variant owns the value, so we need to make a copy
+ return Collections.Array.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_array_new_copy(p_var.Array));
+ }
+ case Variant.Type.PackedByteArray:
+ return VariantUtils.ConvertAsPackedByteArrayToSystemArray(p_var);
+ case Variant.Type.PackedInt32Array:
+ return VariantUtils.ConvertAsPackedInt32ArrayToSystemArray(p_var);
+ case Variant.Type.PackedInt64Array:
+ return VariantUtils.ConvertAsPackedInt64ArrayToSystemArray(p_var);
+ case Variant.Type.PackedFloat32Array:
+ return VariantUtils.ConvertAsPackedFloat32ArrayToSystemArray(p_var);
+ case Variant.Type.PackedFloat64Array:
+ return VariantUtils.ConvertAsPackedFloat64ArrayToSystemArray(p_var);
+ case Variant.Type.PackedStringArray:
+ return VariantUtils.ConvertAsPackedStringArrayToSystemArray(p_var);
+ case Variant.Type.PackedVector2Array:
+ return VariantUtils.ConvertAsPackedVector2ArrayToSystemArray(p_var);
+ case Variant.Type.PackedVector3Array:
+ return VariantUtils.ConvertAsPackedVector3ArrayToSystemArray(p_var);
+ case Variant.Type.PackedColorArray:
+ return VariantUtils.ConvertAsPackedColorArrayToSystemArray(p_var);
+ default:
+ return null;
+ }
+ }
+
+ // String
+
+ public static unsafe godot_string ConvertStringToNative(string? p_mono_string)
+ {
+ if (p_mono_string == null)
+ return new godot_string();
+
+ fixed (char* methodChars = p_mono_string)
+ {
+ NativeFuncs.godotsharp_string_new_with_utf16_chars(out godot_string dest, methodChars);
+ return dest;
+ }
+ }
+
+ public static unsafe string ConvertStringToManaged(in godot_string p_string)
+ {
+ if (p_string.Buffer == IntPtr.Zero)
+ return string.Empty;
+
+ const int sizeOfChar32 = 4;
+ byte* bytes = (byte*)p_string.Buffer;
+ int size = p_string.Size;
+ if (size == 0)
+ return string.Empty;
+ size -= 1; // zero at the end
+ int sizeInBytes = size * sizeOfChar32;
+ return System.Text.Encoding.UTF32.GetString(bytes, sizeInBytes);
+ }
+
+ // Callable
+
+ public static godot_callable ConvertCallableToNative(in Callable p_managed_callable)
+ {
+ if (p_managed_callable.Delegate != null)
+ {
+ var gcHandle = CustomGCHandle.AllocStrong(p_managed_callable.Delegate);
+ NativeFuncs.godotsharp_callable_new_with_delegate(
+ GCHandle.ToIntPtr(gcHandle), out godot_callable callable);
+ return callable;
+ }
+ else
+ {
+ godot_string_name method;
+
+ if (p_managed_callable.Method != null && !p_managed_callable.Method.IsEmpty)
+ {
+ var src = (godot_string_name)p_managed_callable.Method.NativeValue;
+ method = NativeFuncs.godotsharp_string_name_new_copy(src);
+ }
+ else
+ {
+ method = default;
+ }
+
+ return new godot_callable(method /* Takes ownership of disposable */,
+ p_managed_callable.Target.GetInstanceId());
+ }
+ }
+
+ public static Callable ConvertCallableToManaged(in godot_callable p_callable)
+ {
+ if (NativeFuncs.godotsharp_callable_get_data_for_marshalling(p_callable,
+ out IntPtr delegateGCHandle, out IntPtr godotObject,
+ out godot_string_name name).ToBool())
+ {
+ if (delegateGCHandle != IntPtr.Zero)
+ {
+ return new Callable((Delegate?)GCHandle.FromIntPtr(delegateGCHandle).Target);
+ }
+ else
+ {
+ return new Callable(
+ InteropUtils.UnmanagedGetManaged(godotObject),
+ StringName.CreateTakingOwnershipOfDisposableValue(name));
+ }
+ }
+
+ // Some other unsupported callable
+ return new Callable();
+ }
+
+ // SignalInfo
+
+ public static godot_signal ConvertSignalToNative(in SignalInfo p_managed_signal)
+ {
+ ulong ownerId = p_managed_signal.Owner.GetInstanceId();
+ godot_string_name name;
+
+ if (p_managed_signal.Name != null && !p_managed_signal.Name.IsEmpty)
+ {
+ var src = (godot_string_name)p_managed_signal.Name.NativeValue;
+ name = NativeFuncs.godotsharp_string_name_new_copy(src);
+ }
+ else
+ {
+ name = default;
+ }
+
+ return new godot_signal(name, ownerId);
+ }
+
+ public static SignalInfo ConvertSignalToManaged(in godot_signal p_signal)
+ {
+ var owner = GD.InstanceFromId(p_signal.ObjectId);
+ var name = StringName.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_string_name_new_copy(p_signal.Name));
+ return new SignalInfo(owner, name);
+ }
+
+ // Array
+
+ internal static T[] ConvertNativeGodotArrayToSystemArrayOfGodotObjectType<T>(in godot_array p_array)
+ where T : Godot.Object
+ {
+ var array = Collections.Array.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_array_new_copy(p_array));
+
+ int length = array.Count;
+ var ret = new T[length];
+
+ for (int i = 0; i < length; i++)
+ ret[i] = (T)array[i].AsGodotObject();
+
+ return ret;
+ }
+
+ // TODO: This needs reflection. Look for an alternative.
+ internal static Godot.Object[] ConvertNativeGodotArrayToSystemArrayOfGodotObjectType(in godot_array p_array,
+ Type type)
+ {
+ var array = Collections.Array.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_array_new_copy(p_array));
+
+ int length = array.Count;
+ var ret = (Godot.Object[])Activator.CreateInstance(type, length)!;
+
+ for (int i = 0; i < length; i++)
+ ret[i] = array[i].AsGodotObject();
+
+ return ret;
+ }
+
+ internal static StringName[] ConvertNativeGodotArrayToSystemArrayOfStringName(in godot_array p_array)
+ {
+ var array = Collections.Array.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_array_new_copy(p_array));
+
+ int length = array.Count;
+ var ret = new StringName[length];
+
+ for (int i = 0; i < length; i++)
+ ret[i] = array[i].AsStringName();
+
+ return ret;
+ }
+
+ internal static NodePath[] ConvertNativeGodotArrayToSystemArrayOfNodePath(in godot_array p_array)
+ {
+ var array = Collections.Array.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_array_new_copy(p_array));
+
+ int length = array.Count;
+ var ret = new NodePath[length];
+
+ for (int i = 0; i < length; i++)
+ ret[i] = array[i].AsNodePath();
+
+ return ret;
+ }
+
+ internal static RID[] ConvertNativeGodotArrayToSystemArrayOfRID(in godot_array p_array)
+ {
+ var array = Collections.Array.CreateTakingOwnershipOfDisposableValue(
+ NativeFuncs.godotsharp_array_new_copy(p_array));
+
+ int length = array.Count;
+ var ret = new RID[length];
+
+ for (int i = 0; i < length; i++)
+ ret[i] = array[i].AsRID();
+
+ return ret;
+ }
+
+ // PackedByteArray
+
+ public static unsafe byte[] ConvertNativePackedByteArrayToSystemArray(in godot_packed_byte_array p_array)
+ {
+ byte* buffer = p_array.Buffer;
+ int size = p_array.Size;
+ if (size == 0)
+ return Array.Empty<byte>();
+ var array = new byte[size];
+ fixed (byte* dest = array)
+ Buffer.MemoryCopy(buffer, dest, size, size);
+ return array;
+ }
+
+ public static unsafe godot_packed_byte_array ConvertSystemArrayToNativePackedByteArray(Span<byte> p_array)
+ {
+ if (p_array.IsEmpty)
+ return new godot_packed_byte_array();
+ fixed (byte* src = p_array)
+ return NativeFuncs.godotsharp_packed_byte_array_new_mem_copy(src, p_array.Length);
+ }
+
+ // PackedInt32Array
+
+ public static unsafe int[] ConvertNativePackedInt32ArrayToSystemArray(godot_packed_int32_array p_array)
+ {
+ int* buffer = p_array.Buffer;
+ int size = p_array.Size;
+ if (size == 0)
+ return Array.Empty<int>();
+ int sizeInBytes = size * sizeof(int);
+ var array = new int[size];
+ fixed (int* dest = array)
+ Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes);
+ return array;
+ }
+
+ public static unsafe godot_packed_int32_array ConvertSystemArrayToNativePackedInt32Array(Span<int> p_array)
+ {
+ if (p_array.IsEmpty)
+ return new godot_packed_int32_array();
+ fixed (int* src = p_array)
+ return NativeFuncs.godotsharp_packed_int32_array_new_mem_copy(src, p_array.Length);
+ }
+
+ // PackedInt64Array
+
+ public static unsafe long[] ConvertNativePackedInt64ArrayToSystemArray(godot_packed_int64_array p_array)
+ {
+ long* buffer = p_array.Buffer;
+ int size = p_array.Size;
+ if (size == 0)
+ return Array.Empty<long>();
+ int sizeInBytes = size * sizeof(long);
+ var array = new long[size];
+ fixed (long* dest = array)
+ Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes);
+ return array;
+ }
+
+ public static unsafe godot_packed_int64_array ConvertSystemArrayToNativePackedInt64Array(Span<long> p_array)
+ {
+ if (p_array.IsEmpty)
+ return new godot_packed_int64_array();
+ fixed (long* src = p_array)
+ return NativeFuncs.godotsharp_packed_int64_array_new_mem_copy(src, p_array.Length);
+ }
+
+ // PackedFloat32Array
+
+ public static unsafe float[] ConvertNativePackedFloat32ArrayToSystemArray(godot_packed_float32_array p_array)
+ {
+ float* buffer = p_array.Buffer;
+ int size = p_array.Size;
+ if (size == 0)
+ return Array.Empty<float>();
+ int sizeInBytes = size * sizeof(float);
+ var array = new float[size];
+ fixed (float* dest = array)
+ Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes);
+ return array;
+ }
+
+ public static unsafe godot_packed_float32_array ConvertSystemArrayToNativePackedFloat32Array(
+ Span<float> p_array)
+ {
+ if (p_array.IsEmpty)
+ return new godot_packed_float32_array();
+ fixed (float* src = p_array)
+ return NativeFuncs.godotsharp_packed_float32_array_new_mem_copy(src, p_array.Length);
+ }
+
+ // PackedFloat64Array
+
+ public static unsafe double[] ConvertNativePackedFloat64ArrayToSystemArray(godot_packed_float64_array p_array)
+ {
+ double* buffer = p_array.Buffer;
+ int size = p_array.Size;
+ if (size == 0)
+ return Array.Empty<double>();
+ int sizeInBytes = size * sizeof(double);
+ var array = new double[size];
+ fixed (double* dest = array)
+ Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes);
+ return array;
+ }
+
+ public static unsafe godot_packed_float64_array ConvertSystemArrayToNativePackedFloat64Array(
+ Span<double> p_array)
+ {
+ if (p_array.IsEmpty)
+ return new godot_packed_float64_array();
+ fixed (double* src = p_array)
+ return NativeFuncs.godotsharp_packed_float64_array_new_mem_copy(src, p_array.Length);
+ }
+
+ // PackedStringArray
+
+ public static unsafe string[] ConvertNativePackedStringArrayToSystemArray(godot_packed_string_array p_array)
+ {
+ godot_string* buffer = p_array.Buffer;
+ int size = p_array.Size;
+ if (size == 0)
+ return Array.Empty<string>();
+ var array = new string[size];
+ for (int i = 0; i < size; i++)
+ array[i] = ConvertStringToManaged(buffer[i]);
+ return array;
+ }
+
+ public static godot_packed_string_array ConvertSystemArrayToNativePackedStringArray(Span<string> p_array)
+ {
+ godot_packed_string_array dest = new godot_packed_string_array();
+
+ if (p_array.IsEmpty)
+ return dest;
+
+ /* TODO: Replace godotsharp_packed_string_array_add with a single internal call to
+ get the write address. We can't use `dest._ptr` directly for writing due to COW. */
+
+ for (int i = 0; i < p_array.Length; i++)
+ {
+ using godot_string godotStrElem = ConvertStringToNative(p_array[i]);
+ NativeFuncs.godotsharp_packed_string_array_add(ref dest, godotStrElem);
+ }
+
+ return dest;
+ }
+
+ // PackedVector2Array
+
+ public static unsafe Vector2[] ConvertNativePackedVector2ArrayToSystemArray(godot_packed_vector2_array p_array)
+ {
+ Vector2* buffer = p_array.Buffer;
+ int size = p_array.Size;
+ if (size == 0)
+ return Array.Empty<Vector2>();
+ int sizeInBytes = size * sizeof(Vector2);
+ var array = new Vector2[size];
+ fixed (Vector2* dest = array)
+ Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes);
+ return array;
+ }
+
+ public static unsafe godot_packed_vector2_array ConvertSystemArrayToNativePackedVector2Array(
+ Span<Vector2> p_array)
+ {
+ if (p_array.IsEmpty)
+ return new godot_packed_vector2_array();
+ fixed (Vector2* src = p_array)
+ return NativeFuncs.godotsharp_packed_vector2_array_new_mem_copy(src, p_array.Length);
+ }
+
+ // PackedVector3Array
+
+ public static unsafe Vector3[] ConvertNativePackedVector3ArrayToSystemArray(godot_packed_vector3_array p_array)
+ {
+ Vector3* buffer = p_array.Buffer;
+ int size = p_array.Size;
+ if (size == 0)
+ return Array.Empty<Vector3>();
+ int sizeInBytes = size * sizeof(Vector3);
+ var array = new Vector3[size];
+ fixed (Vector3* dest = array)
+ Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes);
+ return array;
+ }
+
+ public static unsafe godot_packed_vector3_array ConvertSystemArrayToNativePackedVector3Array(
+ Span<Vector3> p_array)
+ {
+ if (p_array.IsEmpty)
+ return new godot_packed_vector3_array();
+ fixed (Vector3* src = p_array)
+ return NativeFuncs.godotsharp_packed_vector3_array_new_mem_copy(src, p_array.Length);
+ }
+
+ // PackedColorArray
+
+ public static unsafe Color[] ConvertNativePackedColorArrayToSystemArray(godot_packed_color_array p_array)
+ {
+ Color* buffer = p_array.Buffer;
+ int size = p_array.Size;
+ if (size == 0)
+ return Array.Empty<Color>();
+ int sizeInBytes = size * sizeof(Color);
+ var array = new Color[size];
+ fixed (Color* dest = array)
+ Buffer.MemoryCopy(buffer, dest, sizeInBytes, sizeInBytes);
+ return array;
+ }
+
+ public static unsafe godot_packed_color_array ConvertSystemArrayToNativePackedColorArray(Span<Color> p_array)
+ {
+ if (p_array.IsEmpty)
+ return new godot_packed_color_array();
+ fixed (Color* src = p_array)
+ return NativeFuncs.godotsharp_packed_color_array_new_mem_copy(src, p_array.Length);
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
new file mode 100644
index 0000000000..94dda5a74b
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.cs
@@ -0,0 +1,522 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using Godot.SourceGenerators.Internal;
+
+// ReSharper disable InconsistentNaming
+
+namespace Godot.NativeInterop
+{
+ /*
+ * IMPORTANT:
+ * The order of the methods defined in NativeFuncs must match the order
+ * in the array defined at the bottom of 'glue/runtime_interop.cpp'.
+ */
+
+ [GenerateUnmanagedCallbacks(typeof(UnmanagedCallbacks))]
+ public static unsafe partial class NativeFuncs
+ {
+ private static bool initialized = false;
+
+ // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Global
+ public static void Initialize(IntPtr unmanagedCallbacks, int unmanagedCallbacksSize)
+ {
+ if (initialized)
+ throw new InvalidOperationException("Already initialized.");
+ initialized = true;
+
+ if (unmanagedCallbacksSize != sizeof(UnmanagedCallbacks))
+ throw new ArgumentException("Unmanaged callbacks size mismatch.", nameof(unmanagedCallbacksSize));
+
+ _unmanagedCallbacks = Unsafe.AsRef<UnmanagedCallbacks>((void*)unmanagedCallbacks);
+ }
+
+ private partial struct UnmanagedCallbacks
+ {
+ }
+
+ // Custom functions
+
+ public static partial IntPtr godotsharp_method_bind_get_method(in godot_string_name p_classname,
+ in godot_string_name p_methodname);
+
+ public static partial delegate* unmanaged<IntPtr> godotsharp_get_class_constructor(
+ in godot_string_name p_classname);
+
+ public static partial IntPtr godotsharp_engine_get_singleton(in godot_string p_name);
+
+
+ internal static partial Error godotsharp_stack_info_vector_resize(
+ ref DebuggingUtils.godot_stack_info_vector p_stack_info_vector, int p_size);
+
+ internal static partial void godotsharp_stack_info_vector_destroy(
+ ref DebuggingUtils.godot_stack_info_vector p_stack_info_vector);
+
+ internal static partial void godotsharp_internal_script_debugger_send_error(in godot_string p_func,
+ in godot_string p_file, int p_line, in godot_string p_err, in godot_string p_descr,
+ godot_bool p_warning, in DebuggingUtils.godot_stack_info_vector p_stack_info_vector);
+
+ internal static partial bool godotsharp_internal_script_debugger_is_active();
+
+ internal static partial IntPtr godotsharp_internal_object_get_associated_gchandle(IntPtr ptr);
+
+ internal static partial void godotsharp_internal_object_disposed(IntPtr ptr, IntPtr gcHandleToFree);
+
+ internal static partial void godotsharp_internal_refcounted_disposed(IntPtr ptr, IntPtr gcHandleToFree,
+ godot_bool isFinalizer);
+
+ internal static partial Error godotsharp_internal_signal_awaiter_connect(IntPtr source,
+ in godot_string_name signal,
+ IntPtr target, IntPtr awaiterHandlePtr);
+
+ internal static partial void godotsharp_internal_tie_native_managed_to_unmanaged(IntPtr gcHandleIntPtr,
+ IntPtr unmanaged, in godot_string_name nativeName, godot_bool refCounted);
+
+ internal static partial void godotsharp_internal_tie_user_managed_to_unmanaged(IntPtr gcHandleIntPtr,
+ IntPtr unmanaged, godot_ref* scriptPtr, godot_bool refCounted);
+
+ internal static partial void godotsharp_internal_tie_managed_to_unmanaged_with_pre_setup(
+ IntPtr gcHandleIntPtr, IntPtr unmanaged);
+
+ internal static partial IntPtr godotsharp_internal_unmanaged_get_script_instance_managed(IntPtr p_unmanaged,
+ out godot_bool r_has_cs_script_instance);
+
+ internal static partial IntPtr godotsharp_internal_unmanaged_get_instance_binding_managed(IntPtr p_unmanaged);
+
+ internal static partial IntPtr godotsharp_internal_unmanaged_instance_binding_create_managed(IntPtr p_unmanaged,
+ IntPtr oldGCHandlePtr);
+
+ internal static partial void godotsharp_internal_new_csharp_script(godot_ref* r_dest);
+
+ internal static partial godot_bool godotsharp_internal_script_load(in godot_string p_path, godot_ref* r_dest);
+
+ internal static partial void godotsharp_internal_reload_registered_script(IntPtr scriptPtr);
+
+ internal static partial void godotsharp_array_filter_godot_objects_by_native(in godot_string_name p_native_name,
+ in godot_array p_input, out godot_array r_output);
+
+ internal static partial void godotsharp_array_filter_godot_objects_by_non_native(in godot_array p_input,
+ out godot_array r_output);
+
+ public static partial void godotsharp_ref_new_from_ref_counted_ptr(out godot_ref r_dest,
+ IntPtr p_ref_counted_ptr);
+
+ public static partial void godotsharp_ref_destroy(ref godot_ref p_instance);
+
+ public static partial void godotsharp_string_name_new_from_string(out godot_string_name r_dest,
+ in godot_string p_name);
+
+ public static partial void godotsharp_node_path_new_from_string(out godot_node_path r_dest,
+ in godot_string p_name);
+
+ public static partial void
+ godotsharp_string_name_as_string(out godot_string r_dest, in godot_string_name p_name);
+
+ public static partial void godotsharp_node_path_as_string(out godot_string r_dest, in godot_node_path p_np);
+
+ public static partial godot_packed_byte_array godotsharp_packed_byte_array_new_mem_copy(byte* p_src,
+ int p_length);
+
+ public static partial godot_packed_int32_array godotsharp_packed_int32_array_new_mem_copy(int* p_src,
+ int p_length);
+
+ public static partial godot_packed_int64_array godotsharp_packed_int64_array_new_mem_copy(long* p_src,
+ int p_length);
+
+ public static partial godot_packed_float32_array godotsharp_packed_float32_array_new_mem_copy(float* p_src,
+ int p_length);
+
+ public static partial godot_packed_float64_array godotsharp_packed_float64_array_new_mem_copy(double* p_src,
+ int p_length);
+
+ public static partial godot_packed_vector2_array godotsharp_packed_vector2_array_new_mem_copy(Vector2* p_src,
+ int p_length);
+
+ public static partial godot_packed_vector3_array godotsharp_packed_vector3_array_new_mem_copy(Vector3* p_src,
+ int p_length);
+
+ public static partial godot_packed_color_array godotsharp_packed_color_array_new_mem_copy(Color* p_src,
+ int p_length);
+
+ public static partial void godotsharp_packed_string_array_add(ref godot_packed_string_array r_dest,
+ in godot_string p_element);
+
+ public static partial void godotsharp_callable_new_with_delegate(IntPtr p_delegate_handle,
+ out godot_callable r_callable);
+
+ internal static partial godot_bool godotsharp_callable_get_data_for_marshalling(in godot_callable p_callable,
+ out IntPtr r_delegate_handle, out IntPtr r_object, out godot_string_name r_name);
+
+ internal static partial godot_variant godotsharp_callable_call(in godot_callable p_callable,
+ godot_variant** p_args, int p_arg_count, out godot_variant_call_error p_call_error);
+
+ internal static partial void godotsharp_callable_call_deferred(in godot_callable p_callable,
+ godot_variant** p_args, int p_arg_count);
+
+ // GDNative functions
+
+ // gdnative.h
+
+ public static partial void godotsharp_method_bind_ptrcall(IntPtr p_method_bind, IntPtr p_instance, void** p_args,
+ void* p_ret);
+
+ public static partial godot_variant godotsharp_method_bind_call(IntPtr p_method_bind, IntPtr p_instance,
+ godot_variant** p_args, int p_arg_count, out godot_variant_call_error p_call_error);
+
+ // variant.h
+
+ public static partial void
+ godotsharp_variant_new_string_name(out godot_variant r_dest, in godot_string_name p_s);
+
+ public static partial void godotsharp_variant_new_copy(out godot_variant r_dest, in godot_variant p_src);
+
+ public static partial void godotsharp_variant_new_node_path(out godot_variant r_dest, in godot_node_path p_np);
+
+ public static partial void godotsharp_variant_new_object(out godot_variant r_dest, IntPtr p_obj);
+
+ public static partial void godotsharp_variant_new_transform2d(out godot_variant r_dest, in Transform2D p_t2d);
+
+ public static partial void godotsharp_variant_new_vector4(out godot_variant r_dest, in Vector4 p_vec4);
+
+ public static partial void godotsharp_variant_new_vector4i(out godot_variant r_dest, in Vector4i p_vec4i);
+
+ public static partial void godotsharp_variant_new_basis(out godot_variant r_dest, in Basis p_basis);
+
+ public static partial void godotsharp_variant_new_transform3d(out godot_variant r_dest, in Transform3D p_trans);
+
+ public static partial void godotsharp_variant_new_projection(out godot_variant r_dest, in Projection p_proj);
+
+ public static partial void godotsharp_variant_new_aabb(out godot_variant r_dest, in AABB p_aabb);
+
+ public static partial void godotsharp_variant_new_dictionary(out godot_variant r_dest,
+ in godot_dictionary p_dict);
+
+ public static partial void godotsharp_variant_new_array(out godot_variant r_dest, in godot_array p_arr);
+
+ public static partial void godotsharp_variant_new_packed_byte_array(out godot_variant r_dest,
+ in godot_packed_byte_array p_pba);
+
+ public static partial void godotsharp_variant_new_packed_int32_array(out godot_variant r_dest,
+ in godot_packed_int32_array p_pia);
+
+ public static partial void godotsharp_variant_new_packed_int64_array(out godot_variant r_dest,
+ in godot_packed_int64_array p_pia);
+
+ public static partial void godotsharp_variant_new_packed_float32_array(out godot_variant r_dest,
+ in godot_packed_float32_array p_pra);
+
+ public static partial void godotsharp_variant_new_packed_float64_array(out godot_variant r_dest,
+ in godot_packed_float64_array p_pra);
+
+ public static partial void godotsharp_variant_new_packed_string_array(out godot_variant r_dest,
+ in godot_packed_string_array p_psa);
+
+ public static partial void godotsharp_variant_new_packed_vector2_array(out godot_variant r_dest,
+ in godot_packed_vector2_array p_pv2a);
+
+ public static partial void godotsharp_variant_new_packed_vector3_array(out godot_variant r_dest,
+ in godot_packed_vector3_array p_pv3a);
+
+ public static partial void godotsharp_variant_new_packed_color_array(out godot_variant r_dest,
+ in godot_packed_color_array p_pca);
+
+ public static partial godot_bool godotsharp_variant_as_bool(in godot_variant p_self);
+
+ public static partial Int64 godotsharp_variant_as_int(in godot_variant p_self);
+
+ public static partial double godotsharp_variant_as_float(in godot_variant p_self);
+
+ public static partial godot_string godotsharp_variant_as_string(in godot_variant p_self);
+
+ public static partial Vector2 godotsharp_variant_as_vector2(in godot_variant p_self);
+
+ public static partial Vector2i godotsharp_variant_as_vector2i(in godot_variant p_self);
+
+ public static partial Rect2 godotsharp_variant_as_rect2(in godot_variant p_self);
+
+ public static partial Rect2i godotsharp_variant_as_rect2i(in godot_variant p_self);
+
+ public static partial Vector3 godotsharp_variant_as_vector3(in godot_variant p_self);
+
+ public static partial Vector3i godotsharp_variant_as_vector3i(in godot_variant p_self);
+
+ public static partial Transform2D godotsharp_variant_as_transform2d(in godot_variant p_self);
+
+ public static partial Vector4 godotsharp_variant_as_vector4(in godot_variant p_self);
+
+ public static partial Vector4i godotsharp_variant_as_vector4i(in godot_variant p_self);
+
+ public static partial Plane godotsharp_variant_as_plane(in godot_variant p_self);
+
+ public static partial Quaternion godotsharp_variant_as_quaternion(in godot_variant p_self);
+
+ public static partial AABB godotsharp_variant_as_aabb(in godot_variant p_self);
+
+ public static partial Basis godotsharp_variant_as_basis(in godot_variant p_self);
+
+ public static partial Transform3D godotsharp_variant_as_transform3d(in godot_variant p_self);
+
+ public static partial Projection godotsharp_variant_as_projection(in godot_variant p_self);
+
+ public static partial Color godotsharp_variant_as_color(in godot_variant p_self);
+
+ public static partial godot_string_name godotsharp_variant_as_string_name(in godot_variant p_self);
+
+ public static partial godot_node_path godotsharp_variant_as_node_path(in godot_variant p_self);
+
+ public static partial RID godotsharp_variant_as_rid(in godot_variant p_self);
+
+ public static partial godot_callable godotsharp_variant_as_callable(in godot_variant p_self);
+
+ public static partial godot_signal godotsharp_variant_as_signal(in godot_variant p_self);
+
+ public static partial godot_dictionary godotsharp_variant_as_dictionary(in godot_variant p_self);
+
+ public static partial godot_array godotsharp_variant_as_array(in godot_variant p_self);
+
+ public static partial godot_packed_byte_array godotsharp_variant_as_packed_byte_array(in godot_variant p_self);
+
+ public static partial godot_packed_int32_array godotsharp_variant_as_packed_int32_array(in godot_variant p_self);
+
+ public static partial godot_packed_int64_array godotsharp_variant_as_packed_int64_array(in godot_variant p_self);
+
+ public static partial godot_packed_float32_array godotsharp_variant_as_packed_float32_array(
+ in godot_variant p_self);
+
+ public static partial godot_packed_float64_array godotsharp_variant_as_packed_float64_array(
+ in godot_variant p_self);
+
+ public static partial godot_packed_string_array godotsharp_variant_as_packed_string_array(
+ in godot_variant p_self);
+
+ public static partial godot_packed_vector2_array godotsharp_variant_as_packed_vector2_array(
+ in godot_variant p_self);
+
+ public static partial godot_packed_vector3_array godotsharp_variant_as_packed_vector3_array(
+ in godot_variant p_self);
+
+ public static partial godot_packed_color_array godotsharp_variant_as_packed_color_array(in godot_variant p_self);
+
+ public static partial godot_bool godotsharp_variant_equals(in godot_variant p_a, in godot_variant p_b);
+
+ // string.h
+
+ public static partial void godotsharp_string_new_with_utf16_chars(out godot_string r_dest, char* p_contents);
+
+ // string_name.h
+
+ public static partial void godotsharp_string_name_new_copy(out godot_string_name r_dest,
+ in godot_string_name p_src);
+
+ // node_path.h
+
+ public static partial void godotsharp_node_path_new_copy(out godot_node_path r_dest, in godot_node_path p_src);
+
+ // array.h
+
+ public static partial void godotsharp_array_new(out godot_array r_dest);
+
+ public static partial void godotsharp_array_new_copy(out godot_array r_dest, in godot_array p_src);
+
+ public static partial godot_variant* godotsharp_array_ptrw(ref godot_array p_self);
+
+ // dictionary.h
+
+ public static partial void godotsharp_dictionary_new(out godot_dictionary r_dest);
+
+ public static partial void godotsharp_dictionary_new_copy(out godot_dictionary r_dest,
+ in godot_dictionary p_src);
+
+ // destroy functions
+
+ public static partial void godotsharp_packed_byte_array_destroy(ref godot_packed_byte_array p_self);
+
+ public static partial void godotsharp_packed_int32_array_destroy(ref godot_packed_int32_array p_self);
+
+ public static partial void godotsharp_packed_int64_array_destroy(ref godot_packed_int64_array p_self);
+
+ public static partial void godotsharp_packed_float32_array_destroy(ref godot_packed_float32_array p_self);
+
+ public static partial void godotsharp_packed_float64_array_destroy(ref godot_packed_float64_array p_self);
+
+ public static partial void godotsharp_packed_string_array_destroy(ref godot_packed_string_array p_self);
+
+ public static partial void godotsharp_packed_vector2_array_destroy(ref godot_packed_vector2_array p_self);
+
+ public static partial void godotsharp_packed_vector3_array_destroy(ref godot_packed_vector3_array p_self);
+
+ public static partial void godotsharp_packed_color_array_destroy(ref godot_packed_color_array p_self);
+
+ public static partial void godotsharp_variant_destroy(ref godot_variant p_self);
+
+ public static partial void godotsharp_string_destroy(ref godot_string p_self);
+
+ public static partial void godotsharp_string_name_destroy(ref godot_string_name p_self);
+
+ public static partial void godotsharp_node_path_destroy(ref godot_node_path p_self);
+
+ public static partial void godotsharp_signal_destroy(ref godot_signal p_self);
+
+ public static partial void godotsharp_callable_destroy(ref godot_callable p_self);
+
+ public static partial void godotsharp_array_destroy(ref godot_array p_self);
+
+ public static partial void godotsharp_dictionary_destroy(ref godot_dictionary p_self);
+
+ // Array
+
+ public static partial int godotsharp_array_add(ref godot_array p_self, in godot_variant p_item);
+
+ public static partial void
+ godotsharp_array_duplicate(ref godot_array p_self, godot_bool p_deep, out godot_array r_dest);
+
+ public static partial int godotsharp_array_index_of(ref godot_array p_self, in godot_variant p_item);
+
+ public static partial void godotsharp_array_insert(ref godot_array p_self, int p_index, in godot_variant p_item);
+
+ public static partial void godotsharp_array_remove_at(ref godot_array p_self, int p_index);
+
+ public static partial Error godotsharp_array_resize(ref godot_array p_self, int p_new_size);
+
+ public static partial Error godotsharp_array_shuffle(ref godot_array p_self);
+
+ public static partial void godotsharp_array_to_string(ref godot_array p_self, out godot_string r_str);
+
+ // Dictionary
+
+ public static partial godot_bool godotsharp_dictionary_try_get_value(ref godot_dictionary p_self,
+ in godot_variant p_key,
+ out godot_variant r_value);
+
+ public static partial void godotsharp_dictionary_set_value(ref godot_dictionary p_self, in godot_variant p_key,
+ in godot_variant p_value);
+
+ public static partial void godotsharp_dictionary_keys(ref godot_dictionary p_self, out godot_array r_dest);
+
+ public static partial void godotsharp_dictionary_values(ref godot_dictionary p_self, out godot_array r_dest);
+
+ public static partial int godotsharp_dictionary_count(ref godot_dictionary p_self);
+
+ public static partial void godotsharp_dictionary_key_value_pair_at(ref godot_dictionary p_self, int p_index,
+ out godot_variant r_key, out godot_variant r_value);
+
+ public static partial void godotsharp_dictionary_add(ref godot_dictionary p_self, in godot_variant p_key,
+ in godot_variant p_value);
+
+ public static partial void godotsharp_dictionary_clear(ref godot_dictionary p_self);
+
+ public static partial godot_bool godotsharp_dictionary_contains_key(ref godot_dictionary p_self,
+ in godot_variant p_key);
+
+ public static partial void godotsharp_dictionary_duplicate(ref godot_dictionary p_self, godot_bool p_deep,
+ out godot_dictionary r_dest);
+
+ public static partial godot_bool godotsharp_dictionary_remove_key(ref godot_dictionary p_self,
+ in godot_variant p_key);
+
+ public static partial void godotsharp_dictionary_to_string(ref godot_dictionary p_self, out godot_string r_str);
+
+ // StringExtensions
+
+ public static partial void godotsharp_string_md5_buffer(in godot_string p_self,
+ out godot_packed_byte_array r_md5_buffer);
+
+ public static partial void godotsharp_string_md5_text(in godot_string p_self, out godot_string r_md5_text);
+
+ public static partial int godotsharp_string_rfind(in godot_string p_self, in godot_string p_what, int p_from);
+
+ public static partial int godotsharp_string_rfindn(in godot_string p_self, in godot_string p_what, int p_from);
+
+ public static partial void godotsharp_string_sha256_buffer(in godot_string p_self,
+ out godot_packed_byte_array r_sha256_buffer);
+
+ public static partial void godotsharp_string_sha256_text(in godot_string p_self,
+ out godot_string r_sha256_text);
+
+ public static partial void godotsharp_string_simplify_path(in godot_string p_self,
+ out godot_string r_simplified_path);
+
+ // NodePath
+
+ public static partial void godotsharp_node_path_get_as_property_path(in godot_node_path p_self,
+ ref godot_node_path r_dest);
+
+ public static partial void godotsharp_node_path_get_concatenated_names(in godot_node_path p_self,
+ out godot_string r_names);
+
+ public static partial void godotsharp_node_path_get_concatenated_subnames(in godot_node_path p_self,
+ out godot_string r_subnames);
+
+ public static partial void godotsharp_node_path_get_name(in godot_node_path p_self, int p_idx,
+ out godot_string r_name);
+
+ public static partial int godotsharp_node_path_get_name_count(in godot_node_path p_self);
+
+ public static partial void godotsharp_node_path_get_subname(in godot_node_path p_self, int p_idx,
+ out godot_string r_subname);
+
+ public static partial int godotsharp_node_path_get_subname_count(in godot_node_path p_self);
+
+ public static partial godot_bool godotsharp_node_path_is_absolute(in godot_node_path p_self);
+
+ // GD, etc
+
+ internal static partial void godotsharp_bytes_to_var(in godot_packed_byte_array p_bytes,
+ godot_bool p_allow_objects,
+ out godot_variant r_ret);
+
+ internal static partial void godotsharp_convert(in godot_variant p_what, int p_type,
+ out godot_variant r_ret);
+
+ internal static partial int godotsharp_hash(in godot_variant p_var);
+
+ internal static partial IntPtr godotsharp_instance_from_id(ulong p_instance_id);
+
+ internal static partial void godotsharp_print(in godot_string p_what);
+
+ public static partial void godotsharp_print_rich(in godot_string p_what);
+
+ internal static partial void godotsharp_printerr(in godot_string p_what);
+
+ internal static partial void godotsharp_printraw(in godot_string p_what);
+
+ internal static partial void godotsharp_prints(in godot_string p_what);
+
+ internal static partial void godotsharp_printt(in godot_string p_what);
+
+ internal static partial float godotsharp_randf();
+
+ internal static partial uint godotsharp_randi();
+
+ internal static partial void godotsharp_randomize();
+
+ internal static partial double godotsharp_randf_range(double from, double to);
+
+ internal static partial double godotsharp_randfn(double mean, double deviation);
+
+ internal static partial int godotsharp_randi_range(int from, int to);
+
+ internal static partial uint godotsharp_rand_from_seed(ulong seed, out ulong newSeed);
+
+ internal static partial void godotsharp_seed(ulong seed);
+
+ internal static partial void godotsharp_weakref(IntPtr p_obj, out godot_ref r_weak_ref);
+
+ internal static partial void godotsharp_str(in godot_array p_what, out godot_string r_ret);
+
+ internal static partial void godotsharp_str_to_var(in godot_string p_str, out godot_variant r_ret);
+
+ internal static partial void godotsharp_var_to_bytes(in godot_variant p_what, godot_bool p_full_objects,
+ out godot_packed_byte_array r_bytes);
+
+ internal static partial void godotsharp_var_to_str(in godot_variant p_var, out godot_string r_ret);
+
+ internal static partial void godotsharp_pusherror(in godot_string p_str);
+
+ internal static partial void godotsharp_pushwarning(in godot_string p_str);
+
+ // Object
+
+ public static partial void godotsharp_object_to_string(IntPtr ptr, out godot_string r_str);
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs
new file mode 100644
index 0000000000..2ea3c18d26
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeFuncs.extended.cs
@@ -0,0 +1,99 @@
+// ReSharper disable InconsistentNaming
+
+namespace Godot.NativeInterop
+{
+ public static partial class NativeFuncs
+ {
+ public static godot_variant godotsharp_variant_new_copy(in godot_variant src)
+ {
+ switch (src.Type)
+ {
+ case Variant.Type.Nil:
+ return default;
+ case Variant.Type.Bool:
+ return new godot_variant() { Bool = src.Bool };
+ case Variant.Type.Int:
+ return new godot_variant() { Int = src.Int };
+ case Variant.Type.Float:
+ return new godot_variant() { Float = src.Float };
+ case Variant.Type.Vector2:
+ return new godot_variant() { Vector2 = src.Vector2 };
+ case Variant.Type.Vector2i:
+ return new godot_variant() { Vector2i = src.Vector2i };
+ case Variant.Type.Rect2:
+ return new godot_variant() { Rect2 = src.Rect2 };
+ case Variant.Type.Rect2i:
+ return new godot_variant() { Rect2i = src.Rect2i };
+ case Variant.Type.Vector3:
+ return new godot_variant() { Vector3 = src.Vector3 };
+ case Variant.Type.Vector3i:
+ return new godot_variant() { Vector3i = src.Vector3i };
+ case Variant.Type.Plane:
+ return new godot_variant() { Plane = src.Plane };
+ case Variant.Type.Quaternion:
+ return new godot_variant() { Quaternion = src.Quaternion };
+ case Variant.Type.Color:
+ return new godot_variant() { Color = src.Color };
+ case Variant.Type.Rid:
+ return new godot_variant() { RID = src.RID };
+ }
+
+ godotsharp_variant_new_copy(out godot_variant ret, src);
+ return ret;
+ }
+
+ public static godot_string_name godotsharp_string_name_new_copy(in godot_string_name src)
+ {
+ if (src.IsEmpty)
+ return default;
+ godotsharp_string_name_new_copy(out godot_string_name ret, src);
+ return ret;
+ }
+
+ public static godot_node_path godotsharp_node_path_new_copy(in godot_node_path src)
+ {
+ if (src.IsEmpty)
+ return default;
+ godotsharp_node_path_new_copy(out godot_node_path ret, src);
+ return ret;
+ }
+
+ public static godot_array godotsharp_array_new()
+ {
+ godotsharp_array_new(out godot_array ret);
+ return ret;
+ }
+
+ public static godot_array godotsharp_array_new_copy(in godot_array src)
+ {
+ godotsharp_array_new_copy(out godot_array ret, src);
+ return ret;
+ }
+
+ public static godot_dictionary godotsharp_dictionary_new()
+ {
+ godotsharp_dictionary_new(out godot_dictionary ret);
+ return ret;
+ }
+
+ public static godot_dictionary godotsharp_dictionary_new_copy(in godot_dictionary src)
+ {
+ godotsharp_dictionary_new_copy(out godot_dictionary ret, src);
+ return ret;
+ }
+
+ public static godot_string_name godotsharp_string_name_new_from_string(string name)
+ {
+ using godot_string src = Marshaling.ConvertStringToNative(name);
+ godotsharp_string_name_new_from_string(out godot_string_name ret, src);
+ return ret;
+ }
+
+ public static godot_node_path godotsharp_node_path_new_from_string(string name)
+ {
+ using godot_string src = Marshaling.ConvertStringToNative(name);
+ godotsharp_node_path_new_from_string(out godot_node_path ret, src);
+ return ret;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeVariantPtrArgs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeVariantPtrArgs.cs
new file mode 100644
index 0000000000..422df74c23
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/NativeVariantPtrArgs.cs
@@ -0,0 +1,20 @@
+using System.Runtime.CompilerServices;
+
+namespace Godot.NativeInterop
+{
+ // Our source generators will add trampolines methods that access variant arguments.
+ // This struct makes that possible without having to enable `AllowUnsafeBlocks` in game projects.
+
+ public unsafe ref struct NativeVariantPtrArgs
+ {
+ private godot_variant** _args;
+
+ internal NativeVariantPtrArgs(godot_variant** args) => _args = args;
+
+ public ref godot_variant this[int index]
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => ref *_args[index];
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs
new file mode 100644
index 0000000000..a13fb936e8
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantConversionCallbacks.cs
@@ -0,0 +1,976 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+
+namespace Godot.NativeInterop;
+
+internal static unsafe class VariantConversionCallbacks
+{
+ [SuppressMessage("ReSharper", "RedundantNameQualifier")]
+ internal static delegate*<in T, godot_variant> GetToVariantCallback<T>()
+ {
+ static godot_variant FromBool(in bool @bool) =>
+ VariantUtils.CreateFromBool(@bool);
+
+ static godot_variant FromChar(in char @char) =>
+ VariantUtils.CreateFromInt(@char);
+
+ static godot_variant FromInt8(in sbyte @int8) =>
+ VariantUtils.CreateFromInt(@int8);
+
+ static godot_variant FromInt16(in short @int16) =>
+ VariantUtils.CreateFromInt(@int16);
+
+ static godot_variant FromInt32(in int @int32) =>
+ VariantUtils.CreateFromInt(@int32);
+
+ static godot_variant FromInt64(in long @int64) =>
+ VariantUtils.CreateFromInt(@int64);
+
+ static godot_variant FromUInt8(in byte @uint8) =>
+ VariantUtils.CreateFromInt(@uint8);
+
+ static godot_variant FromUInt16(in ushort @uint16) =>
+ VariantUtils.CreateFromInt(@uint16);
+
+ static godot_variant FromUInt32(in uint @uint32) =>
+ VariantUtils.CreateFromInt(@uint32);
+
+ static godot_variant FromUInt64(in ulong @uint64) =>
+ VariantUtils.CreateFromInt(@uint64);
+
+ static godot_variant FromFloat(in float @float) =>
+ VariantUtils.CreateFromFloat(@float);
+
+ static godot_variant FromDouble(in double @double) =>
+ VariantUtils.CreateFromFloat(@double);
+
+ static godot_variant FromVector2(in Vector2 @vector2) =>
+ VariantUtils.CreateFromVector2(@vector2);
+
+ static godot_variant FromVector2I(in Vector2i vector2I) =>
+ VariantUtils.CreateFromVector2i(vector2I);
+
+ static godot_variant FromRect2(in Rect2 @rect2) =>
+ VariantUtils.CreateFromRect2(@rect2);
+
+ static godot_variant FromRect2I(in Rect2i rect2I) =>
+ VariantUtils.CreateFromRect2i(rect2I);
+
+ static godot_variant FromTransform2D(in Transform2D @transform2D) =>
+ VariantUtils.CreateFromTransform2D(@transform2D);
+
+ static godot_variant FromVector3(in Vector3 @vector3) =>
+ VariantUtils.CreateFromVector3(@vector3);
+
+ static godot_variant FromVector3I(in Vector3i vector3I) =>
+ VariantUtils.CreateFromVector3i(vector3I);
+
+ static godot_variant FromBasis(in Basis @basis) =>
+ VariantUtils.CreateFromBasis(@basis);
+
+ static godot_variant FromQuaternion(in Quaternion @quaternion) =>
+ VariantUtils.CreateFromQuaternion(@quaternion);
+
+ static godot_variant FromTransform3D(in Transform3D @transform3d) =>
+ VariantUtils.CreateFromTransform3D(@transform3d);
+
+ static godot_variant FromAabb(in AABB @aabb) =>
+ VariantUtils.CreateFromAABB(@aabb);
+
+ static godot_variant FromColor(in Color @color) =>
+ VariantUtils.CreateFromColor(@color);
+
+ static godot_variant FromPlane(in Plane @plane) =>
+ VariantUtils.CreateFromPlane(@plane);
+
+ static godot_variant FromCallable(in Callable @callable) =>
+ VariantUtils.CreateFromCallable(@callable);
+
+ static godot_variant FromSignalInfo(in SignalInfo @signalInfo) =>
+ VariantUtils.CreateFromSignalInfo(@signalInfo);
+
+ static godot_variant FromString(in string @string) =>
+ VariantUtils.CreateFromString(@string);
+
+ static godot_variant FromByteArray(in byte[] byteArray) =>
+ VariantUtils.CreateFromPackedByteArray(byteArray);
+
+ static godot_variant FromInt32Array(in int[] int32Array) =>
+ VariantUtils.CreateFromPackedInt32Array(int32Array);
+
+ static godot_variant FromInt64Array(in long[] int64Array) =>
+ VariantUtils.CreateFromPackedInt64Array(int64Array);
+
+ static godot_variant FromFloatArray(in float[] floatArray) =>
+ VariantUtils.CreateFromPackedFloat32Array(floatArray);
+
+ static godot_variant FromDoubleArray(in double[] doubleArray) =>
+ VariantUtils.CreateFromPackedFloat64Array(doubleArray);
+
+ static godot_variant FromStringArray(in string[] stringArray) =>
+ VariantUtils.CreateFromPackedStringArray(stringArray);
+
+ static godot_variant FromVector2Array(in Vector2[] vector2Array) =>
+ VariantUtils.CreateFromPackedVector2Array(vector2Array);
+
+ static godot_variant FromVector3Array(in Vector3[] vector3Array) =>
+ VariantUtils.CreateFromPackedVector3Array(vector3Array);
+
+ static godot_variant FromColorArray(in Color[] colorArray) =>
+ VariantUtils.CreateFromPackedColorArray(colorArray);
+
+ static godot_variant FromStringNameArray(in StringName[] stringNameArray) =>
+ VariantUtils.CreateFromSystemArrayOfStringName(stringNameArray);
+
+ static godot_variant FromNodePathArray(in NodePath[] nodePathArray) =>
+ VariantUtils.CreateFromSystemArrayOfNodePath(nodePathArray);
+
+ static godot_variant FromRidArray(in RID[] ridArray) =>
+ VariantUtils.CreateFromSystemArrayOfRID(ridArray);
+
+ static godot_variant FromGodotObject(in Godot.Object godotObject) =>
+ VariantUtils.CreateFromGodotObject(godotObject);
+
+ static godot_variant FromStringName(in StringName stringName) =>
+ VariantUtils.CreateFromStringName(stringName);
+
+ static godot_variant FromNodePath(in NodePath nodePath) =>
+ VariantUtils.CreateFromNodePath(nodePath);
+
+ static godot_variant FromRid(in RID rid) =>
+ VariantUtils.CreateFromRID(rid);
+
+ static godot_variant FromGodotDictionary(in Collections.Dictionary godotDictionary) =>
+ VariantUtils.CreateFromDictionary(godotDictionary);
+
+ static godot_variant FromGodotArray(in Collections.Array godotArray) =>
+ VariantUtils.CreateFromArray(godotArray);
+
+ static godot_variant FromVariant(in Variant variant) =>
+ NativeFuncs.godotsharp_variant_new_copy((godot_variant)variant.NativeVar);
+
+ var typeOfT = typeof(T);
+
+ if (typeOfT == typeof(bool))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in bool, godot_variant>)
+ &FromBool;
+ }
+
+ if (typeOfT == typeof(char))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in char, godot_variant>)
+ &FromChar;
+ }
+
+ if (typeOfT == typeof(sbyte))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in sbyte, godot_variant>)
+ &FromInt8;
+ }
+
+ if (typeOfT == typeof(short))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in short, godot_variant>)
+ &FromInt16;
+ }
+
+ if (typeOfT == typeof(int))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in int, godot_variant>)
+ &FromInt32;
+ }
+
+ if (typeOfT == typeof(long))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in long, godot_variant>)
+ &FromInt64;
+ }
+
+ if (typeOfT == typeof(byte))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in byte, godot_variant>)
+ &FromUInt8;
+ }
+
+ if (typeOfT == typeof(ushort))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in ushort, godot_variant>)
+ &FromUInt16;
+ }
+
+ if (typeOfT == typeof(uint))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in uint, godot_variant>)
+ &FromUInt32;
+ }
+
+ if (typeOfT == typeof(ulong))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in ulong, godot_variant>)
+ &FromUInt64;
+ }
+
+ if (typeOfT == typeof(float))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in float, godot_variant>)
+ &FromFloat;
+ }
+
+ if (typeOfT == typeof(double))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in double, godot_variant>)
+ &FromDouble;
+ }
+
+ if (typeOfT == typeof(Vector2))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Vector2, godot_variant>)
+ &FromVector2;
+ }
+
+ if (typeOfT == typeof(Vector2i))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Vector2i, godot_variant>)
+ &FromVector2I;
+ }
+
+ if (typeOfT == typeof(Rect2))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Rect2, godot_variant>)
+ &FromRect2;
+ }
+
+ if (typeOfT == typeof(Rect2i))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Rect2i, godot_variant>)
+ &FromRect2I;
+ }
+
+ if (typeOfT == typeof(Transform2D))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Transform2D, godot_variant>)
+ &FromTransform2D;
+ }
+
+ if (typeOfT == typeof(Vector3))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Vector3, godot_variant>)
+ &FromVector3;
+ }
+
+ if (typeOfT == typeof(Vector3i))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Vector3i, godot_variant>)
+ &FromVector3I;
+ }
+
+ if (typeOfT == typeof(Basis))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Basis, godot_variant>)
+ &FromBasis;
+ }
+
+ if (typeOfT == typeof(Quaternion))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Quaternion, godot_variant>)
+ &FromQuaternion;
+ }
+
+ if (typeOfT == typeof(Transform3D))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Transform3D, godot_variant>)
+ &FromTransform3D;
+ }
+
+ if (typeOfT == typeof(AABB))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in AABB, godot_variant>)
+ &FromAabb;
+ }
+
+ if (typeOfT == typeof(Color))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Color, godot_variant>)
+ &FromColor;
+ }
+
+ if (typeOfT == typeof(Plane))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Plane, godot_variant>)
+ &FromPlane;
+ }
+
+ if (typeOfT == typeof(Callable))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Callable, godot_variant>)
+ &FromCallable;
+ }
+
+ if (typeOfT == typeof(SignalInfo))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in SignalInfo, godot_variant>)
+ &FromSignalInfo;
+ }
+
+ if (typeOfT.IsEnum)
+ {
+ var enumUnderlyingType = typeOfT.GetEnumUnderlyingType();
+
+ switch (Type.GetTypeCode(enumUnderlyingType))
+ {
+ case TypeCode.SByte:
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in sbyte, godot_variant>)
+ &FromInt8;
+ }
+ case TypeCode.Int16:
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in short, godot_variant>)
+ &FromInt16;
+ }
+ case TypeCode.Int32:
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in int, godot_variant>)
+ &FromInt32;
+ }
+ case TypeCode.Int64:
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in long, godot_variant>)
+ &FromInt64;
+ }
+ case TypeCode.Byte:
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in byte, godot_variant>)
+ &FromUInt8;
+ }
+ case TypeCode.UInt16:
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in ushort, godot_variant>)
+ &FromUInt16;
+ }
+ case TypeCode.UInt32:
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in uint, godot_variant>)
+ &FromUInt32;
+ }
+ case TypeCode.UInt64:
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in ulong, godot_variant>)
+ &FromUInt64;
+ }
+ default:
+ return null;
+ }
+ }
+
+ if (typeOfT == typeof(string))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in string, godot_variant>)
+ &FromString;
+ }
+
+ if (typeOfT == typeof(byte[]))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in byte[], godot_variant>)
+ &FromByteArray;
+ }
+
+ if (typeOfT == typeof(int[]))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in int[], godot_variant>)
+ &FromInt32Array;
+ }
+
+ if (typeOfT == typeof(long[]))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in long[], godot_variant>)
+ &FromInt64Array;
+ }
+
+ if (typeOfT == typeof(float[]))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in float[], godot_variant>)
+ &FromFloatArray;
+ }
+
+ if (typeOfT == typeof(double[]))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in double[], godot_variant>)
+ &FromDoubleArray;
+ }
+
+ if (typeOfT == typeof(string[]))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in string[], godot_variant>)
+ &FromStringArray;
+ }
+
+ if (typeOfT == typeof(Vector2[]))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Vector2[], godot_variant>)
+ &FromVector2Array;
+ }
+
+ if (typeOfT == typeof(Vector3[]))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Vector3[], godot_variant>)
+ &FromVector3Array;
+ }
+
+ if (typeOfT == typeof(Color[]))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Color[], godot_variant>)
+ &FromColorArray;
+ }
+
+ if (typeOfT == typeof(StringName[]))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in StringName[], godot_variant>)
+ &FromStringNameArray;
+ }
+
+ if (typeOfT == typeof(NodePath[]))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in NodePath[], godot_variant>)
+ &FromNodePathArray;
+ }
+
+ if (typeOfT == typeof(RID[]))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in RID[], godot_variant>)
+ &FromRidArray;
+ }
+
+ if (typeof(Godot.Object).IsAssignableFrom(typeOfT))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Godot.Object, godot_variant>)
+ &FromGodotObject;
+ }
+
+ if (typeOfT == typeof(StringName))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in StringName, godot_variant>)
+ &FromStringName;
+ }
+
+ if (typeOfT == typeof(NodePath))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in NodePath, godot_variant>)
+ &FromNodePath;
+ }
+
+ if (typeOfT == typeof(RID))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in RID, godot_variant>)
+ &FromRid;
+ }
+
+ if (typeOfT == typeof(Godot.Collections.Dictionary))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Godot.Collections.Dictionary, godot_variant>)
+ &FromGodotDictionary;
+ }
+
+ if (typeOfT == typeof(Godot.Collections.Array))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Godot.Collections.Array, godot_variant>)
+ &FromGodotArray;
+ }
+
+ if (typeOfT == typeof(Variant))
+ {
+ return (delegate*<in T, godot_variant>)(delegate*<in Variant, godot_variant>)
+ &FromVariant;
+ }
+
+ return null;
+ }
+
+ [SuppressMessage("ReSharper", "RedundantNameQualifier")]
+ internal static delegate*<in godot_variant, T> GetToManagedCallback<T>()
+ {
+ static bool ToBool(in godot_variant variant) =>
+ VariantUtils.ConvertToBool(variant);
+
+ static char ToChar(in godot_variant variant) =>
+ VariantUtils.ConvertToChar(variant);
+
+ static sbyte ToInt8(in godot_variant variant) =>
+ VariantUtils.ConvertToInt8(variant);
+
+ static short ToInt16(in godot_variant variant) =>
+ VariantUtils.ConvertToInt16(variant);
+
+ static int ToInt32(in godot_variant variant) =>
+ VariantUtils.ConvertToInt32(variant);
+
+ static long ToInt64(in godot_variant variant) =>
+ VariantUtils.ConvertToInt64(variant);
+
+ static byte ToUInt8(in godot_variant variant) =>
+ VariantUtils.ConvertToUInt8(variant);
+
+ static ushort ToUInt16(in godot_variant variant) =>
+ VariantUtils.ConvertToUInt16(variant);
+
+ static uint ToUInt32(in godot_variant variant) =>
+ VariantUtils.ConvertToUInt32(variant);
+
+ static ulong ToUInt64(in godot_variant variant) =>
+ VariantUtils.ConvertToUInt64(variant);
+
+ static float ToFloat(in godot_variant variant) =>
+ VariantUtils.ConvertToFloat32(variant);
+
+ static double ToDouble(in godot_variant variant) =>
+ VariantUtils.ConvertToFloat64(variant);
+
+ static Vector2 ToVector2(in godot_variant variant) =>
+ VariantUtils.ConvertToVector2(variant);
+
+ static Vector2i ToVector2I(in godot_variant variant) =>
+ VariantUtils.ConvertToVector2i(variant);
+
+ static Rect2 ToRect2(in godot_variant variant) =>
+ VariantUtils.ConvertToRect2(variant);
+
+ static Rect2i ToRect2I(in godot_variant variant) =>
+ VariantUtils.ConvertToRect2i(variant);
+
+ static Transform2D ToTransform2D(in godot_variant variant) =>
+ VariantUtils.ConvertToTransform2D(variant);
+
+ static Vector3 ToVector3(in godot_variant variant) =>
+ VariantUtils.ConvertToVector3(variant);
+
+ static Vector3i ToVector3I(in godot_variant variant) =>
+ VariantUtils.ConvertToVector3i(variant);
+
+ static Basis ToBasis(in godot_variant variant) =>
+ VariantUtils.ConvertToBasis(variant);
+
+ static Quaternion ToQuaternion(in godot_variant variant) =>
+ VariantUtils.ConvertToQuaternion(variant);
+
+ static Transform3D ToTransform3D(in godot_variant variant) =>
+ VariantUtils.ConvertToTransform3D(variant);
+
+ static AABB ToAabb(in godot_variant variant) =>
+ VariantUtils.ConvertToAABB(variant);
+
+ static Color ToColor(in godot_variant variant) =>
+ VariantUtils.ConvertToColor(variant);
+
+ static Plane ToPlane(in godot_variant variant) =>
+ VariantUtils.ConvertToPlane(variant);
+
+ static Callable ToCallable(in godot_variant variant) =>
+ VariantUtils.ConvertToCallableManaged(variant);
+
+ static SignalInfo ToSignalInfo(in godot_variant variant) =>
+ VariantUtils.ConvertToSignalInfo(variant);
+
+ static string ToString(in godot_variant variant) =>
+ VariantUtils.ConvertToStringObject(variant);
+
+ static byte[] ToByteArray(in godot_variant variant) =>
+ VariantUtils.ConvertAsPackedByteArrayToSystemArray(variant);
+
+ static int[] ToInt32Array(in godot_variant variant) =>
+ VariantUtils.ConvertAsPackedInt32ArrayToSystemArray(variant);
+
+ static long[] ToInt64Array(in godot_variant variant) =>
+ VariantUtils.ConvertAsPackedInt64ArrayToSystemArray(variant);
+
+ static float[] ToFloatArray(in godot_variant variant) =>
+ VariantUtils.ConvertAsPackedFloat32ArrayToSystemArray(variant);
+
+ static double[] ToDoubleArray(in godot_variant variant) =>
+ VariantUtils.ConvertAsPackedFloat64ArrayToSystemArray(variant);
+
+ static string[] ToStringArray(in godot_variant variant) =>
+ VariantUtils.ConvertAsPackedStringArrayToSystemArray(variant);
+
+ static Vector2[] ToVector2Array(in godot_variant variant) =>
+ VariantUtils.ConvertAsPackedVector2ArrayToSystemArray(variant);
+
+ static Vector3[] ToVector3Array(in godot_variant variant) =>
+ VariantUtils.ConvertAsPackedVector3ArrayToSystemArray(variant);
+
+ static Color[] ToColorArray(in godot_variant variant) =>
+ VariantUtils.ConvertAsPackedColorArrayToSystemArray(variant);
+
+ static StringName[] ToStringNameArray(in godot_variant variant) =>
+ VariantUtils.ConvertToSystemArrayOfStringName(variant);
+
+ static NodePath[] ToNodePathArray(in godot_variant variant) =>
+ VariantUtils.ConvertToSystemArrayOfNodePath(variant);
+
+ static RID[] ToRidArray(in godot_variant variant) =>
+ VariantUtils.ConvertToSystemArrayOfRID(variant);
+
+ static Godot.Object ToGodotObject(in godot_variant variant) =>
+ VariantUtils.ConvertToGodotObject(variant);
+
+ static StringName ToStringName(in godot_variant variant) =>
+ VariantUtils.ConvertToStringNameObject(variant);
+
+ static NodePath ToNodePath(in godot_variant variant) =>
+ VariantUtils.ConvertToNodePathObject(variant);
+
+ static RID ToRid(in godot_variant variant) =>
+ VariantUtils.ConvertToRID(variant);
+
+ static Collections.Dictionary ToGodotDictionary(in godot_variant variant) =>
+ VariantUtils.ConvertToDictionaryObject(variant);
+
+ static Collections.Array ToGodotArray(in godot_variant variant) =>
+ VariantUtils.ConvertToArrayObject(variant);
+
+ static Variant ToVariant(in godot_variant variant) =>
+ Variant.CreateCopyingBorrowed(variant);
+
+ var typeOfT = typeof(T);
+
+ // ReSharper disable RedundantCast
+ // Rider is being stupid here. These casts are definitely needed. We get build errors without them.
+
+ if (typeOfT == typeof(bool))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, bool>)
+ &ToBool;
+ }
+
+ if (typeOfT == typeof(char))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, char>)
+ &ToChar;
+ }
+
+ if (typeOfT == typeof(sbyte))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, sbyte>)
+ &ToInt8;
+ }
+
+ if (typeOfT == typeof(short))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, short>)
+ &ToInt16;
+ }
+
+ if (typeOfT == typeof(int))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, int>)
+ &ToInt32;
+ }
+
+ if (typeOfT == typeof(long))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, long>)
+ &ToInt64;
+ }
+
+ if (typeOfT == typeof(byte))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, byte>)
+ &ToUInt8;
+ }
+
+ if (typeOfT == typeof(ushort))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, ushort>)
+ &ToUInt16;
+ }
+
+ if (typeOfT == typeof(uint))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, uint>)
+ &ToUInt32;
+ }
+
+ if (typeOfT == typeof(ulong))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, ulong>)
+ &ToUInt64;
+ }
+
+ if (typeOfT == typeof(float))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, float>)
+ &ToFloat;
+ }
+
+ if (typeOfT == typeof(double))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, double>)
+ &ToDouble;
+ }
+
+ if (typeOfT == typeof(Vector2))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector2>)
+ &ToVector2;
+ }
+
+ if (typeOfT == typeof(Vector2i))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector2i>)
+ &ToVector2I;
+ }
+
+ if (typeOfT == typeof(Rect2))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Rect2>)
+ &ToRect2;
+ }
+
+ if (typeOfT == typeof(Rect2i))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Rect2i>)
+ &ToRect2I;
+ }
+
+ if (typeOfT == typeof(Transform2D))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Transform2D>)
+ &ToTransform2D;
+ }
+
+ if (typeOfT == typeof(Vector3))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector3>)
+ &ToVector3;
+ }
+
+ if (typeOfT == typeof(Vector3i))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector3i>)
+ &ToVector3I;
+ }
+
+ if (typeOfT == typeof(Basis))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Basis>)
+ &ToBasis;
+ }
+
+ if (typeOfT == typeof(Quaternion))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Quaternion>)
+ &ToQuaternion;
+ }
+
+ if (typeOfT == typeof(Transform3D))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Transform3D>)
+ &ToTransform3D;
+ }
+
+ if (typeOfT == typeof(AABB))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, AABB>)
+ &ToAabb;
+ }
+
+ if (typeOfT == typeof(Color))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Color>)
+ &ToColor;
+ }
+
+ if (typeOfT == typeof(Plane))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Plane>)
+ &ToPlane;
+ }
+
+ if (typeOfT == typeof(Callable))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Callable>)
+ &ToCallable;
+ }
+
+ if (typeOfT == typeof(SignalInfo))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, SignalInfo>)
+ &ToSignalInfo;
+ }
+
+ if (typeOfT.IsEnum)
+ {
+ var enumUnderlyingType = typeOfT.GetEnumUnderlyingType();
+
+ switch (Type.GetTypeCode(enumUnderlyingType))
+ {
+ case TypeCode.SByte:
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, sbyte>)
+ &ToInt8;
+ }
+ case TypeCode.Int16:
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, short>)
+ &ToInt16;
+ }
+ case TypeCode.Int32:
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, int>)
+ &ToInt32;
+ }
+ case TypeCode.Int64:
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, long>)
+ &ToInt64;
+ }
+ case TypeCode.Byte:
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, byte>)
+ &ToUInt8;
+ }
+ case TypeCode.UInt16:
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, ushort>)
+ &ToUInt16;
+ }
+ case TypeCode.UInt32:
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, uint>)
+ &ToUInt32;
+ }
+ case TypeCode.UInt64:
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, ulong>)
+ &ToUInt64;
+ }
+ default:
+ return null;
+ }
+ }
+
+ if (typeOfT == typeof(string))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, string>)
+ &ToString;
+ }
+
+ if (typeOfT == typeof(byte[]))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, byte[]>)
+ &ToByteArray;
+ }
+
+ if (typeOfT == typeof(int[]))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, int[]>)
+ &ToInt32Array;
+ }
+
+ if (typeOfT == typeof(long[]))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, long[]>)
+ &ToInt64Array;
+ }
+
+ if (typeOfT == typeof(float[]))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, float[]>)
+ &ToFloatArray;
+ }
+
+ if (typeOfT == typeof(double[]))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, double[]>)
+ &ToDoubleArray;
+ }
+
+ if (typeOfT == typeof(string[]))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, string[]>)
+ &ToStringArray;
+ }
+
+ if (typeOfT == typeof(Vector2[]))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector2[]>)
+ &ToVector2Array;
+ }
+
+ if (typeOfT == typeof(Vector3[]))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Vector3[]>)
+ &ToVector3Array;
+ }
+
+ if (typeOfT == typeof(Color[]))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Color[]>)
+ &ToColorArray;
+ }
+
+ if (typeOfT == typeof(StringName[]))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, StringName[]>)
+ &ToStringNameArray;
+ }
+
+ if (typeOfT == typeof(NodePath[]))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, NodePath[]>)
+ &ToNodePathArray;
+ }
+
+ if (typeOfT == typeof(RID[]))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, RID[]>)
+ &ToRidArray;
+ }
+
+ if (typeof(Godot.Object).IsAssignableFrom(typeOfT))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Godot.Object>)
+ &ToGodotObject;
+ }
+
+ if (typeOfT == typeof(StringName))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, StringName>)
+ &ToStringName;
+ }
+
+ if (typeOfT == typeof(NodePath))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, NodePath>)
+ &ToNodePath;
+ }
+
+ if (typeOfT == typeof(RID))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, RID>)
+ &ToRid;
+ }
+
+ if (typeOfT == typeof(Godot.Collections.Dictionary))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Godot.Collections.Dictionary>)
+ &ToGodotDictionary;
+ }
+
+ if (typeOfT == typeof(Godot.Collections.Array))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Godot.Collections.Array>)
+ &ToGodotArray;
+ }
+
+ if (typeOfT == typeof(Variant))
+ {
+ return (delegate*<in godot_variant, T>)(delegate*<in godot_variant, Variant>)
+ &ToVariant;
+ }
+
+ // ReSharper restore RedundantCast
+
+ return null;
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs
new file mode 100644
index 0000000000..46f31bbf4e
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantSpanHelpers.cs
@@ -0,0 +1,33 @@
+using System;
+
+namespace Godot.NativeInterop
+{
+ internal readonly ref struct VariantSpanDisposer
+ {
+ private readonly Span<godot_variant.movable> _variantSpan;
+
+ // IMPORTANT: The span element must be default initialized.
+ // Make sure call Clear() on the span if it was created with stackalloc.
+ public VariantSpanDisposer(Span<godot_variant.movable> variantSpan)
+ {
+ _variantSpan = variantSpan;
+ }
+
+ public void Dispose()
+ {
+ for (int i = 0; i < _variantSpan.Length; i++)
+ _variantSpan[i].DangerousSelfRef.Dispose();
+ }
+ }
+
+ internal static class VariantSpanExtensions
+ {
+ // Used to make sure we always initialize the span values to the default,
+ // as we need that in order to safely dispose all elements after.
+ public static Span<godot_variant.movable> Cleared(this Span<godot_variant.movable> span)
+ {
+ span.Clear();
+ return span;
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
new file mode 100644
index 0000000000..491ccf904e
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs
@@ -0,0 +1,611 @@
+using System;
+using System.Runtime.CompilerServices;
+using Godot.Collections;
+
+// ReSharper disable InconsistentNaming
+
+#nullable enable
+
+namespace Godot.NativeInterop
+{
+ public static class VariantUtils
+ {
+ public static godot_variant CreateFromRID(RID from)
+ => new() { Type = Variant.Type.Rid, RID = from };
+
+ public static godot_variant CreateFromBool(bool from)
+ => new() { Type = Variant.Type.Bool, Bool = from.ToGodotBool() };
+
+ public static godot_variant CreateFromInt(long from)
+ => new() { Type = Variant.Type.Int, Int = from };
+
+ public static godot_variant CreateFromInt(ulong from)
+ => new() { Type = Variant.Type.Int, Int = (long)from };
+
+ public static godot_variant CreateFromFloat(double from)
+ => new() { Type = Variant.Type.Float, Float = from };
+
+ public static godot_variant CreateFromVector2(Vector2 from)
+ => new() { Type = Variant.Type.Vector2, Vector2 = from };
+
+ public static godot_variant CreateFromVector2i(Vector2i from)
+ => new() { Type = Variant.Type.Vector2i, Vector2i = from };
+
+ public static godot_variant CreateFromVector3(Vector3 from)
+ => new() { Type = Variant.Type.Vector3, Vector3 = from };
+
+ public static godot_variant CreateFromVector3i(Vector3i from)
+ => new() { Type = Variant.Type.Vector3i, Vector3i = from };
+
+ public static godot_variant CreateFromRect2(Rect2 from)
+ => new() { Type = Variant.Type.Rect2, Rect2 = from };
+
+ public static godot_variant CreateFromRect2i(Rect2i from)
+ => new() { Type = Variant.Type.Rect2i, Rect2i = from };
+
+ public static godot_variant CreateFromQuaternion(Quaternion from)
+ => new() { Type = Variant.Type.Quaternion, Quaternion = from };
+
+ public static godot_variant CreateFromColor(Color from)
+ => new() { Type = Variant.Type.Color, Color = from };
+
+ public static godot_variant CreateFromPlane(Plane from)
+ => new() { Type = Variant.Type.Plane, Plane = from };
+
+ public static godot_variant CreateFromTransform2D(Transform2D from)
+ {
+ NativeFuncs.godotsharp_variant_new_transform2d(out godot_variant ret, from);
+ return ret;
+ }
+
+ public static godot_variant CreateFromVector4(Vector4 from)
+ {
+ NativeFuncs.godotsharp_variant_new_vector4(out godot_variant ret, from);
+ return ret;
+ }
+
+ public static godot_variant CreateFromVector4i(Vector4i from)
+ {
+ NativeFuncs.godotsharp_variant_new_vector4i(out godot_variant ret, from);
+ return ret;
+ }
+
+ public static godot_variant CreateFromBasis(Basis from)
+ {
+ NativeFuncs.godotsharp_variant_new_basis(out godot_variant ret, from);
+ return ret;
+ }
+
+ public static godot_variant CreateFromTransform3D(Transform3D from)
+ {
+ NativeFuncs.godotsharp_variant_new_transform3d(out godot_variant ret, from);
+ return ret;
+ }
+
+ public static godot_variant CreateFromProjection(Projection from)
+ {
+ NativeFuncs.godotsharp_variant_new_projection(out godot_variant ret, from);
+ return ret;
+ }
+
+ public static godot_variant CreateFromAABB(AABB from)
+ {
+ NativeFuncs.godotsharp_variant_new_aabb(out godot_variant ret, from);
+ return ret;
+ }
+
+ // Explicit name to make it very clear
+ public static godot_variant CreateFromCallableTakingOwnershipOfDisposableValue(godot_callable from)
+ => new() { Type = Variant.Type.Callable, Callable = from };
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_variant CreateFromCallable(Callable from)
+ => CreateFromCallableTakingOwnershipOfDisposableValue(
+ Marshaling.ConvertCallableToNative(from));
+
+ // Explicit name to make it very clear
+ public static godot_variant CreateFromSignalTakingOwnershipOfDisposableValue(godot_signal from)
+ => new() { Type = Variant.Type.Signal, Signal = from };
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_variant CreateFromSignalInfo(SignalInfo from)
+ => CreateFromSignalTakingOwnershipOfDisposableValue(
+ Marshaling.ConvertSignalToNative(from));
+
+ // Explicit name to make it very clear
+ public static godot_variant CreateFromStringTakingOwnershipOfDisposableValue(godot_string from)
+ => new() { Type = Variant.Type.String, String = from };
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_variant CreateFromString(string? from)
+ => CreateFromStringTakingOwnershipOfDisposableValue(Marshaling.ConvertStringToNative(from));
+
+ public static godot_variant CreateFromPackedByteArray(in godot_packed_byte_array from)
+ {
+ NativeFuncs.godotsharp_variant_new_packed_byte_array(out godot_variant ret, from);
+ return ret;
+ }
+
+ public static godot_variant CreateFromPackedInt32Array(in godot_packed_int32_array from)
+ {
+ NativeFuncs.godotsharp_variant_new_packed_int32_array(out godot_variant ret, from);
+ return ret;
+ }
+
+ public static godot_variant CreateFromPackedInt64Array(in godot_packed_int64_array from)
+ {
+ NativeFuncs.godotsharp_variant_new_packed_int64_array(out godot_variant ret, from);
+ return ret;
+ }
+
+ public static godot_variant CreateFromPackedFloat32Array(in godot_packed_float32_array from)
+ {
+ NativeFuncs.godotsharp_variant_new_packed_float32_array(out godot_variant ret, from);
+ return ret;
+ }
+
+ public static godot_variant CreateFromPackedFloat64Array(in godot_packed_float64_array from)
+ {
+ NativeFuncs.godotsharp_variant_new_packed_float64_array(out godot_variant ret, from);
+ return ret;
+ }
+
+ public static godot_variant CreateFromPackedStringArray(in godot_packed_string_array from)
+ {
+ NativeFuncs.godotsharp_variant_new_packed_string_array(out godot_variant ret, from);
+ return ret;
+ }
+
+ public static godot_variant CreateFromPackedVector2Array(in godot_packed_vector2_array from)
+ {
+ NativeFuncs.godotsharp_variant_new_packed_vector2_array(out godot_variant ret, from);
+ return ret;
+ }
+
+ public static godot_variant CreateFromPackedVector3Array(in godot_packed_vector3_array from)
+ {
+ NativeFuncs.godotsharp_variant_new_packed_vector3_array(out godot_variant ret, from);
+ return ret;
+ }
+
+ public static godot_variant CreateFromPackedColorArray(in godot_packed_color_array from)
+ {
+ NativeFuncs.godotsharp_variant_new_packed_color_array(out godot_variant ret, from);
+ return ret;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_variant CreateFromPackedByteArray(Span<byte> from)
+ => CreateFromPackedByteArray(Marshaling.ConvertSystemArrayToNativePackedByteArray(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_variant CreateFromPackedInt32Array(Span<int> from)
+ => CreateFromPackedInt32Array(Marshaling.ConvertSystemArrayToNativePackedInt32Array(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_variant CreateFromPackedInt64Array(Span<long> from)
+ => CreateFromPackedInt64Array(Marshaling.ConvertSystemArrayToNativePackedInt64Array(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_variant CreateFromPackedFloat32Array(Span<float> from)
+ => CreateFromPackedFloat32Array(Marshaling.ConvertSystemArrayToNativePackedFloat32Array(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_variant CreateFromPackedFloat64Array(Span<double> from)
+ => CreateFromPackedFloat64Array(Marshaling.ConvertSystemArrayToNativePackedFloat64Array(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_variant CreateFromPackedStringArray(Span<string> from)
+ => CreateFromPackedStringArray(Marshaling.ConvertSystemArrayToNativePackedStringArray(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_variant CreateFromPackedVector2Array(Span<Vector2> from)
+ => CreateFromPackedVector2Array(Marshaling.ConvertSystemArrayToNativePackedVector2Array(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_variant CreateFromPackedVector3Array(Span<Vector3> from)
+ => CreateFromPackedVector3Array(Marshaling.ConvertSystemArrayToNativePackedVector3Array(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_variant CreateFromPackedColorArray(Span<Color> from)
+ => CreateFromPackedColorArray(Marshaling.ConvertSystemArrayToNativePackedColorArray(from));
+
+ public static godot_variant CreateFromSystemArrayOfStringName(Span<StringName> from)
+ => CreateFromArray(new Collections.Array(from));
+
+ public static godot_variant CreateFromSystemArrayOfNodePath(Span<NodePath> from)
+ => CreateFromArray(new Collections.Array(from));
+
+ public static godot_variant CreateFromSystemArrayOfRID(Span<RID> from)
+ => CreateFromArray(new Collections.Array(from));
+
+ // ReSharper disable once RedundantNameQualifier
+ public static godot_variant CreateFromSystemArrayOfGodotObject(Godot.Object[]? from)
+ {
+ if (from == null)
+ return default; // Nil
+ using var fromGodot = new Collections.Array(from);
+ return CreateFromArray((godot_array)fromGodot.NativeValue);
+ }
+
+ public static godot_variant CreateFromArray(godot_array from)
+ {
+ NativeFuncs.godotsharp_variant_new_array(out godot_variant ret, from);
+ return ret;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_variant CreateFromArray(Collections.Array? from)
+ => from != null ? CreateFromArray((godot_array)from.NativeValue) : default;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_variant CreateFromArray<T>(Array<T>? from)
+ => from != null ? CreateFromArray((godot_array)((Collections.Array)from).NativeValue) : default;
+
+ public static godot_variant CreateFromDictionary(godot_dictionary from)
+ {
+ NativeFuncs.godotsharp_variant_new_dictionary(out godot_variant ret, from);
+ return ret;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_variant CreateFromDictionary(Dictionary? from)
+ => from != null ? CreateFromDictionary((godot_dictionary)from.NativeValue) : default;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_variant CreateFromDictionary<TKey, TValue>(Dictionary<TKey, TValue>? from)
+ => from != null ? CreateFromDictionary((godot_dictionary)((Dictionary)from).NativeValue) : default;
+
+ public static godot_variant CreateFromStringName(godot_string_name from)
+ {
+ NativeFuncs.godotsharp_variant_new_string_name(out godot_variant ret, from);
+ return ret;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_variant CreateFromStringName(StringName? from)
+ => from != null ? CreateFromStringName((godot_string_name)from.NativeValue) : default;
+
+ public static godot_variant CreateFromNodePath(godot_node_path from)
+ {
+ NativeFuncs.godotsharp_variant_new_node_path(out godot_variant ret, from);
+ return ret;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_variant CreateFromNodePath(NodePath? from)
+ => from != null ? CreateFromNodePath((godot_node_path)from.NativeValue) : default;
+
+ public static godot_variant CreateFromGodotObjectPtr(IntPtr from)
+ {
+ if (from == IntPtr.Zero)
+ return new godot_variant();
+ NativeFuncs.godotsharp_variant_new_object(out godot_variant ret, from);
+ return ret;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // ReSharper disable once RedundantNameQualifier
+ public static godot_variant CreateFromGodotObject(Godot.Object? from)
+ => from != null ? CreateFromGodotObjectPtr(Object.GetPtr(from)) : default;
+
+ // We avoid the internal call if the stored type is the same we want.
+
+ public static bool ConvertToBool(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Bool ?
+ p_var.Bool.ToBool() :
+ NativeFuncs.godotsharp_variant_as_bool(p_var).ToBool();
+
+ public static char ConvertToChar(in godot_variant p_var)
+ => (char)(p_var.Type == Variant.Type.Int ?
+ p_var.Int :
+ NativeFuncs.godotsharp_variant_as_int(p_var));
+
+ public static sbyte ConvertToInt8(in godot_variant p_var)
+ => (sbyte)(p_var.Type == Variant.Type.Int ?
+ p_var.Int :
+ NativeFuncs.godotsharp_variant_as_int(p_var));
+
+ public static short ConvertToInt16(in godot_variant p_var)
+ => (short)(p_var.Type == Variant.Type.Int ?
+ p_var.Int :
+ NativeFuncs.godotsharp_variant_as_int(p_var));
+
+ public static int ConvertToInt32(in godot_variant p_var)
+ => (int)(p_var.Type == Variant.Type.Int ?
+ p_var.Int :
+ NativeFuncs.godotsharp_variant_as_int(p_var));
+
+ public static long ConvertToInt64(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Int ? p_var.Int : NativeFuncs.godotsharp_variant_as_int(p_var);
+
+ public static byte ConvertToUInt8(in godot_variant p_var)
+ => (byte)(p_var.Type == Variant.Type.Int ?
+ p_var.Int :
+ NativeFuncs.godotsharp_variant_as_int(p_var));
+
+ public static ushort ConvertToUInt16(in godot_variant p_var)
+ => (ushort)(p_var.Type == Variant.Type.Int ?
+ p_var.Int :
+ NativeFuncs.godotsharp_variant_as_int(p_var));
+
+ public static uint ConvertToUInt32(in godot_variant p_var)
+ => (uint)(p_var.Type == Variant.Type.Int ?
+ p_var.Int :
+ NativeFuncs.godotsharp_variant_as_int(p_var));
+
+ public static ulong ConvertToUInt64(in godot_variant p_var)
+ => (ulong)(p_var.Type == Variant.Type.Int ?
+ p_var.Int :
+ NativeFuncs.godotsharp_variant_as_int(p_var));
+
+ public static float ConvertToFloat32(in godot_variant p_var)
+ => (float)(p_var.Type == Variant.Type.Float ?
+ p_var.Float :
+ NativeFuncs.godotsharp_variant_as_float(p_var));
+
+ public static double ConvertToFloat64(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Float ?
+ p_var.Float :
+ NativeFuncs.godotsharp_variant_as_float(p_var);
+
+ public static Vector2 ConvertToVector2(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Vector2 ?
+ p_var.Vector2 :
+ NativeFuncs.godotsharp_variant_as_vector2(p_var);
+
+ public static Vector2i ConvertToVector2i(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Vector2i ?
+ p_var.Vector2i :
+ NativeFuncs.godotsharp_variant_as_vector2i(p_var);
+
+ public static Rect2 ConvertToRect2(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Rect2 ?
+ p_var.Rect2 :
+ NativeFuncs.godotsharp_variant_as_rect2(p_var);
+
+ public static Rect2i ConvertToRect2i(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Rect2i ?
+ p_var.Rect2i :
+ NativeFuncs.godotsharp_variant_as_rect2i(p_var);
+
+ public static unsafe Transform2D ConvertToTransform2D(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Transform2d ?
+ *p_var.Transform2D :
+ NativeFuncs.godotsharp_variant_as_transform2d(p_var);
+
+ public static Vector3 ConvertToVector3(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Vector3 ?
+ p_var.Vector3 :
+ NativeFuncs.godotsharp_variant_as_vector3(p_var);
+
+ public static Vector3i ConvertToVector3i(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Vector3i ?
+ p_var.Vector3i :
+ NativeFuncs.godotsharp_variant_as_vector3i(p_var);
+
+ public static unsafe Vector4 ConvertToVector4(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Vector4 ?
+ *p_var.Vector4 :
+ NativeFuncs.godotsharp_variant_as_vector4(p_var);
+
+ public static unsafe Vector4i ConvertToVector4i(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Vector4i ?
+ *p_var.Vector4i :
+ NativeFuncs.godotsharp_variant_as_vector4i(p_var);
+
+ public static unsafe Basis ConvertToBasis(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Basis ?
+ *p_var.Basis :
+ NativeFuncs.godotsharp_variant_as_basis(p_var);
+
+ public static Quaternion ConvertToQuaternion(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Quaternion ?
+ p_var.Quaternion :
+ NativeFuncs.godotsharp_variant_as_quaternion(p_var);
+
+ public static unsafe Transform3D ConvertToTransform3D(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Transform3d ?
+ *p_var.Transform3D :
+ NativeFuncs.godotsharp_variant_as_transform3d(p_var);
+
+ public static unsafe Projection ConvertToProjection(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Projection ?
+ *p_var.Projection :
+ NativeFuncs.godotsharp_variant_as_projection(p_var);
+
+ public static unsafe AABB ConvertToAABB(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Aabb ?
+ *p_var.AABB :
+ NativeFuncs.godotsharp_variant_as_aabb(p_var);
+
+ public static Color ConvertToColor(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Color ?
+ p_var.Color :
+ NativeFuncs.godotsharp_variant_as_color(p_var);
+
+ public static Plane ConvertToPlane(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Plane ?
+ p_var.Plane :
+ NativeFuncs.godotsharp_variant_as_plane(p_var);
+
+ public static RID ConvertToRID(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Rid ?
+ p_var.RID :
+ NativeFuncs.godotsharp_variant_as_rid(p_var);
+
+ public static IntPtr ConvertToGodotObjectPtr(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Object ? p_var.Object : IntPtr.Zero;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // ReSharper disable once RedundantNameQualifier
+ public static Godot.Object ConvertToGodotObject(in godot_variant p_var)
+ => InteropUtils.UnmanagedGetManaged(ConvertToGodotObjectPtr(p_var));
+
+ public static string ConvertToStringObject(in godot_variant p_var)
+ {
+ switch (p_var.Type)
+ {
+ case Variant.Type.Nil:
+ return ""; // Otherwise, Variant -> String would return the string "Null"
+ case Variant.Type.String:
+ {
+ // We avoid the internal call if the stored type is the same we want.
+ return Marshaling.ConvertStringToManaged(p_var.String);
+ }
+ default:
+ {
+ using godot_string godotString = NativeFuncs.godotsharp_variant_as_string(p_var);
+ return Marshaling.ConvertStringToManaged(godotString);
+ }
+ }
+ }
+
+ public static godot_string_name ConvertToStringName(in godot_variant p_var)
+ => p_var.Type == Variant.Type.StringName ?
+ NativeFuncs.godotsharp_string_name_new_copy(p_var.StringName) :
+ NativeFuncs.godotsharp_variant_as_string_name(p_var);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static StringName ConvertToStringNameObject(in godot_variant p_var)
+ => StringName.CreateTakingOwnershipOfDisposableValue(ConvertToStringName(p_var));
+
+ public static godot_node_path ConvertToNodePath(in godot_variant p_var)
+ => p_var.Type == Variant.Type.NodePath ?
+ NativeFuncs.godotsharp_node_path_new_copy(p_var.NodePath) :
+ NativeFuncs.godotsharp_variant_as_node_path(p_var);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static NodePath ConvertToNodePathObject(in godot_variant p_var)
+ => NodePath.CreateTakingOwnershipOfDisposableValue(ConvertToNodePath(p_var));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_callable ConvertToCallable(in godot_variant p_var)
+ => NativeFuncs.godotsharp_variant_as_callable(p_var);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Callable ConvertToCallableManaged(in godot_variant p_var)
+ => Marshaling.ConvertCallableToManaged(ConvertToCallable(p_var));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static godot_signal ConvertToSignal(in godot_variant p_var)
+ => NativeFuncs.godotsharp_variant_as_signal(p_var);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static SignalInfo ConvertToSignalInfo(in godot_variant p_var)
+ => Marshaling.ConvertSignalToManaged(ConvertToSignal(p_var));
+
+ public static godot_array ConvertToArray(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Array ?
+ NativeFuncs.godotsharp_array_new_copy(p_var.Array) :
+ NativeFuncs.godotsharp_variant_as_array(p_var);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Collections.Array ConvertToArrayObject(in godot_variant p_var)
+ => Collections.Array.CreateTakingOwnershipOfDisposableValue(ConvertToArray(p_var));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Array<T> ConvertToArrayObject<T>(in godot_variant p_var)
+ => Array<T>.CreateTakingOwnershipOfDisposableValue(ConvertToArray(p_var));
+
+ public static godot_dictionary ConvertToDictionary(in godot_variant p_var)
+ => p_var.Type == Variant.Type.Dictionary ?
+ NativeFuncs.godotsharp_dictionary_new_copy(p_var.Dictionary) :
+ NativeFuncs.godotsharp_variant_as_dictionary(p_var);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Dictionary ConvertToDictionaryObject(in godot_variant p_var)
+ => Dictionary.CreateTakingOwnershipOfDisposableValue(ConvertToDictionary(p_var));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Dictionary<TKey, TValue> ConvertToDictionaryObject<TKey, TValue>(in godot_variant p_var)
+ => Dictionary<TKey, TValue>.CreateTakingOwnershipOfDisposableValue(ConvertToDictionary(p_var));
+
+ public static byte[] ConvertAsPackedByteArrayToSystemArray(in godot_variant p_var)
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_byte_array(p_var);
+ return Marshaling.ConvertNativePackedByteArrayToSystemArray(packedArray);
+ }
+
+ public static int[] ConvertAsPackedInt32ArrayToSystemArray(in godot_variant p_var)
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int32_array(p_var);
+ return Marshaling.ConvertNativePackedInt32ArrayToSystemArray(packedArray);
+ }
+
+ public static long[] ConvertAsPackedInt64ArrayToSystemArray(in godot_variant p_var)
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_int64_array(p_var);
+ return Marshaling.ConvertNativePackedInt64ArrayToSystemArray(packedArray);
+ }
+
+ public static float[] ConvertAsPackedFloat32ArrayToSystemArray(in godot_variant p_var)
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float32_array(p_var);
+ return Marshaling.ConvertNativePackedFloat32ArrayToSystemArray(packedArray);
+ }
+
+ public static double[] ConvertAsPackedFloat64ArrayToSystemArray(in godot_variant p_var)
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_float64_array(p_var);
+ return Marshaling.ConvertNativePackedFloat64ArrayToSystemArray(packedArray);
+ }
+
+ public static string[] ConvertAsPackedStringArrayToSystemArray(in godot_variant p_var)
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_string_array(p_var);
+ return Marshaling.ConvertNativePackedStringArrayToSystemArray(packedArray);
+ }
+
+ public static Vector2[] ConvertAsPackedVector2ArrayToSystemArray(in godot_variant p_var)
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector2_array(p_var);
+ return Marshaling.ConvertNativePackedVector2ArrayToSystemArray(packedArray);
+ }
+
+ public static Vector3[] ConvertAsPackedVector3ArrayToSystemArray(in godot_variant p_var)
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_vector3_array(p_var);
+ return Marshaling.ConvertNativePackedVector3ArrayToSystemArray(packedArray);
+ }
+
+ public static Color[] ConvertAsPackedColorArrayToSystemArray(in godot_variant p_var)
+ {
+ using var packedArray = NativeFuncs.godotsharp_variant_as_packed_color_array(p_var);
+ return Marshaling.ConvertNativePackedColorArrayToSystemArray(packedArray);
+ }
+
+ public static StringName[] ConvertToSystemArrayOfStringName(in godot_variant p_var)
+ {
+ using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var);
+ return Marshaling.ConvertNativeGodotArrayToSystemArrayOfStringName(godotArray);
+ }
+
+ public static NodePath[] ConvertToSystemArrayOfNodePath(in godot_variant p_var)
+ {
+ using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var);
+ return Marshaling.ConvertNativeGodotArrayToSystemArrayOfNodePath(godotArray);
+ }
+
+ public static RID[] ConvertToSystemArrayOfRID(in godot_variant p_var)
+ {
+ using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var);
+ return Marshaling.ConvertNativeGodotArrayToSystemArrayOfRID(godotArray);
+ }
+
+ public static T[] ConvertToSystemArrayOfGodotObject<T>(in godot_variant p_var)
+ // ReSharper disable once RedundantNameQualifier
+ where T : Godot.Object
+ {
+ using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var);
+ return Marshaling.ConvertNativeGodotArrayToSystemArrayOfGodotObjectType<T>(godotArray);
+ }
+
+ // ReSharper disable once RedundantNameQualifier
+ public static Godot.Object[] ConvertToSystemArrayOfGodotObject(in godot_variant p_var, Type type)
+ {
+ using var godotArray = NativeFuncs.godotsharp_variant_as_array(p_var);
+ return Marshaling.ConvertNativeGodotArrayToSystemArrayOfGodotObjectType(godotArray, type);
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
index 9ae01016cb..b02bd167a1 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NodePath.cs
@@ -1,5 +1,5 @@
using System;
-using System.Runtime.CompilerServices;
+using Godot.NativeInterop;
namespace Godot
{
@@ -39,22 +39,11 @@ namespace Godot
/// new NodePath("/root/MyAutoload"); // If you have an autoloaded node or scene.
/// </code>
/// </example>
- public sealed partial class NodePath : IDisposable
+ public sealed class NodePath : IDisposable
{
- private bool _disposed = false;
+ internal godot_node_path.movable NativeValue;
- private IntPtr ptr;
-
- internal static IntPtr GetPtr(NodePath instance)
- {
- if (instance == null)
- throw new NullReferenceException($"The instance of type {nameof(NodePath)} is null.");
-
- if (instance._disposed)
- throw new ObjectDisposedException(instance.GetType().FullName);
-
- return instance.ptr;
- }
+ private WeakReference<IDisposable> _weakReferenceToSelf;
~NodePath()
{
@@ -70,29 +59,33 @@ namespace Godot
GC.SuppressFinalize(this);
}
- private void Dispose(bool disposing)
+ public void Dispose(bool disposing)
{
- if (_disposed)
- return;
+ // Always dispose `NativeValue` even if disposing is true
+ NativeValue.DangerousSelfRef.Dispose();
- if (ptr != IntPtr.Zero)
+ if (_weakReferenceToSelf != null)
{
- godot_icall_NodePath_Dtor(ptr);
- ptr = IntPtr.Zero;
+ DisposablesTracker.UnregisterDisposable(_weakReferenceToSelf);
}
-
- _disposed = true;
}
- internal NodePath(IntPtr ptr)
+ private NodePath(godot_node_path nativeValueToOwn)
{
- this.ptr = ptr;
+ NativeValue = (godot_node_path.movable)nativeValueToOwn;
+ _weakReferenceToSelf = DisposablesTracker.RegisterDisposable(this);
}
+ // Explicit name to make it very clear
+ internal static NodePath CreateTakingOwnershipOfDisposableValue(godot_node_path nativeValueToOwn)
+ => new NodePath(nativeValueToOwn);
+
/// <summary>
/// Constructs an empty <see cref="NodePath"/>.
/// </summary>
- public NodePath() : this(string.Empty) { }
+ public NodePath()
+ {
+ }
/// <summary>
/// Constructs a <see cref="NodePath"/> from a string <paramref name="path"/>,
@@ -125,7 +118,11 @@ namespace Godot
/// <param name="path">A string that represents a path in a scene tree.</param>
public NodePath(string path)
{
- ptr = godot_icall_NodePath_Ctor(path);
+ if (!string.IsNullOrEmpty(path))
+ {
+ NativeValue = (godot_node_path.movable)NativeFuncs.godotsharp_node_path_new_from_string(path);
+ _weakReferenceToSelf = DisposablesTracker.RegisterDisposable(this);
+ }
}
/// <summary>
@@ -138,7 +135,7 @@ namespace Godot
/// Converts this <see cref="NodePath"/> to a string.
/// </summary>
/// <param name="from">The <see cref="NodePath"/> to convert.</param>
- public static implicit operator string(NodePath from) => from.ToString();
+ public static implicit operator string(NodePath from) => from?.ToString();
/// <summary>
/// Converts this <see cref="NodePath"/> to a string.
@@ -146,7 +143,13 @@ namespace Godot
/// <returns>A string representation of this <see cref="NodePath"/>.</returns>
public override string ToString()
{
- return godot_icall_NodePath_operator_String(GetPtr(this));
+ if (IsEmpty)
+ return string.Empty;
+
+ var src = (godot_node_path)NativeValue;
+ NativeFuncs.godotsharp_node_path_as_string(out godot_string dest, src);
+ using (dest)
+ return Marshaling.ConvertStringToManaged(dest);
}
/// <summary>
@@ -166,7 +169,10 @@ namespace Godot
/// <returns>The <see cref="NodePath"/> as a pure property path.</returns>
public NodePath GetAsPropertyPath()
{
- return new NodePath(godot_icall_NodePath_get_as_property_path(GetPtr(this)));
+ godot_node_path propertyPath = default;
+ var self = (godot_node_path)NativeValue;
+ NativeFuncs.godotsharp_node_path_get_as_property_path(self, ref propertyPath);
+ return CreateTakingOwnershipOfDisposableValue(propertyPath);
}
/// <summary>
@@ -181,7 +187,10 @@ namespace Godot
/// <returns>The names concatenated with <c>/</c>.</returns>
public string GetConcatenatedNames()
{
- return godot_icall_NodePath_get_concatenated_names(GetPtr(this));
+ var self = (godot_node_path)NativeValue;
+ NativeFuncs.godotsharp_node_path_get_concatenated_names(self, out godot_string names);
+ using (names)
+ return Marshaling.ConvertStringToManaged(names);
}
/// <summary>
@@ -195,9 +204,12 @@ namespace Godot
/// </code>
/// </example>
/// <returns>The subnames concatenated with <c>:</c>.</returns>
- public string GetConcatenatedSubnames()
+ public string GetConcatenatedSubNames()
{
- return godot_icall_NodePath_get_concatenated_subnames(GetPtr(this));
+ var self = (godot_node_path)NativeValue;
+ NativeFuncs.godotsharp_node_path_get_concatenated_subnames(self, out godot_string subNames);
+ using (subNames)
+ return Marshaling.ConvertStringToManaged(subNames);
}
/// <summary>
@@ -215,28 +227,35 @@ namespace Godot
/// <returns>The name at the given index <paramref name="idx"/>.</returns>
public string GetName(int idx)
{
- return godot_icall_NodePath_get_name(GetPtr(this), idx);
+ var self = (godot_node_path)NativeValue;
+ NativeFuncs.godotsharp_node_path_get_name(self, idx, out godot_string name);
+ using (name)
+ return Marshaling.ConvertStringToManaged(name);
}
/// <summary>
/// Gets the number of node names which make up the path.
- /// Subnames (see <see cref="GetSubnameCount"/>) are not included.
+ /// Subnames (see <see cref="GetSubNameCount"/>) are not included.
/// For example, <c>"Path2D/PathFollow2D/Sprite2D"</c> has 3 names.
/// </summary>
/// <returns>The number of node names which make up the path.</returns>
public int GetNameCount()
{
- return godot_icall_NodePath_get_name_count(GetPtr(this));
+ var self = (godot_node_path)NativeValue;
+ return NativeFuncs.godotsharp_node_path_get_name_count(self);
}
/// <summary>
- /// Gets the resource or property name indicated by <paramref name="idx"/> (0 to <see cref="GetSubnameCount"/>).
+ /// Gets the resource or property name indicated by <paramref name="idx"/> (0 to <see cref="GetSubNameCount"/>).
/// </summary>
/// <param name="idx">The subname index.</param>
/// <returns>The subname at the given index <paramref name="idx"/>.</returns>
- public string GetSubname(int idx)
+ public string GetSubName(int idx)
{
- return godot_icall_NodePath_get_subname(GetPtr(this), idx);
+ var self = (godot_node_path)NativeValue;
+ NativeFuncs.godotsharp_node_path_get_subname(self, idx, out godot_string subName);
+ using (subName)
+ return Marshaling.ConvertStringToManaged(subName);
}
/// <summary>
@@ -245,9 +264,10 @@ namespace Godot
/// For example, <c>"Path2D/PathFollow2D/Sprite2D:texture:load_path"</c> has 2 subnames.
/// </summary>
/// <returns>The number of subnames in the path.</returns>
- public int GetSubnameCount()
+ public int GetSubNameCount()
{
- return godot_icall_NodePath_get_subname_count(GetPtr(this));
+ var self = (godot_node_path)NativeValue;
+ return NativeFuncs.godotsharp_node_path_get_subname_count(self);
}
/// <summary>
@@ -259,52 +279,14 @@ namespace Godot
/// <returns>If the <see cref="NodePath"/> is an absolute path.</returns>
public bool IsAbsolute()
{
- return godot_icall_NodePath_is_absolute(GetPtr(this));
+ var self = (godot_node_path)NativeValue;
+ return NativeFuncs.godotsharp_node_path_is_absolute(self).ToBool();
}
/// <summary>
/// Returns <see langword="true"/> if the node path is empty.
/// </summary>
/// <returns>If the <see cref="NodePath"/> is empty.</returns>
- public bool IsEmpty()
- {
- return godot_icall_NodePath_is_empty(GetPtr(this));
- }
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern IntPtr godot_icall_NodePath_Ctor(string path);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void godot_icall_NodePath_Dtor(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string godot_icall_NodePath_operator_String(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern IntPtr godot_icall_NodePath_get_as_property_path(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string godot_icall_NodePath_get_concatenated_names(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string godot_icall_NodePath_get_concatenated_subnames(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string godot_icall_NodePath_get_name(IntPtr ptr, int arg1);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern int godot_icall_NodePath_get_name_count(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string godot_icall_NodePath_get_subname(IntPtr ptr, int arg1);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern int godot_icall_NodePath_get_subname_count(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool godot_icall_NodePath_is_absolute(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool godot_icall_NodePath_is_empty(IntPtr ptr);
+ public bool IsEmpty => NativeValue.DangerousSelfRef.IsEmpty;
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
index 746612477d..5cb678c280 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
@@ -1,54 +1,78 @@
using System;
-using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Godot.Bridge;
+using Godot.NativeInterop;
namespace Godot
{
public partial class Object : IDisposable
{
private bool _disposed = false;
+ private static readonly Type CachedType = typeof(Object);
- private static StringName nativeName = "Object";
+ internal IntPtr NativePtr;
+ private bool _memoryOwn;
- internal IntPtr ptr;
- internal bool memoryOwn;
+ private WeakReference<Object> _weakReferenceToSelf;
/// <summary>
/// Constructs a new <see cref="Object"/>.
/// </summary>
public Object() : this(false)
{
- if (ptr == IntPtr.Zero)
- ptr = godot_icall_Object_Ctor(this);
- _InitializeGodotScriptInstanceInternals();
+ unsafe
+ {
+ _ConstructAndInitialize(NativeCtor, NativeName, CachedType, refCounted: false);
+ }
}
- internal void _InitializeGodotScriptInstanceInternals()
+ internal unsafe void _ConstructAndInitialize(
+ delegate* unmanaged<IntPtr> nativeCtor,
+ StringName nativeName,
+ Type cachedType,
+ bool refCounted
+ )
{
- godot_icall_Object_ConnectEventSignals(ptr);
+ if (NativePtr == IntPtr.Zero)
+ {
+ NativePtr = nativeCtor();
+
+ InteropUtils.TieManagedToUnmanaged(this, NativePtr,
+ nativeName, refCounted, GetType(), cachedType);
+ }
+ else
+ {
+ InteropUtils.TieManagedToUnmanagedWithPreSetup(this, NativePtr,
+ GetType(), cachedType);
+ }
+
+ _weakReferenceToSelf = DisposablesTracker.RegisterGodotObject(this);
}
internal Object(bool memoryOwn)
{
- this.memoryOwn = memoryOwn;
+ _memoryOwn = memoryOwn;
}
/// <summary>
/// The pointer to the native instance of this <see cref="Object"/>.
/// </summary>
- public IntPtr NativeInstance
- {
- get { return ptr; }
- }
+ public IntPtr NativeInstance => NativePtr;
internal static IntPtr GetPtr(Object instance)
{
if (instance == null)
return IntPtr.Zero;
- if (instance._disposed)
+ // We check if NativePtr is null because this may be called by the debugger.
+ // If the debugger puts a breakpoint in one of the base constructors, before
+ // NativePtr is assigned, that would result in UB or crashes when calling
+ // native functions that receive the pointer, which can happen because the
+ // debugger calls ToString() and tries to get the value of properties.
+ if (instance._disposed || instance.NativePtr == IntPtr.Zero)
throw new ObjectDisposedException(instance.GetType().FullName);
- return instance.ptr;
+ return instance.NativePtr;
}
~Object()
@@ -73,22 +97,35 @@ namespace Godot
if (_disposed)
return;
- if (ptr != IntPtr.Zero)
+ _disposed = true;
+
+ if (NativePtr != IntPtr.Zero)
{
- if (memoryOwn)
+ IntPtr gcHandleToFree = NativeFuncs.godotsharp_internal_object_get_associated_gchandle(NativePtr);
+
+ if (gcHandleToFree != IntPtr.Zero)
+ {
+ object target = GCHandle.FromIntPtr(gcHandleToFree).Target;
+ // The GC handle may have been replaced in another thread. Release it only if
+ // it's associated to this managed instance, or if the target is no longer alive.
+ if (target != this && target != null)
+ gcHandleToFree = IntPtr.Zero;
+ }
+
+ if (_memoryOwn)
{
- memoryOwn = false;
- godot_icall_RefCounted_Disposed(this, ptr, !disposing);
+ NativeFuncs.godotsharp_internal_refcounted_disposed(NativePtr, gcHandleToFree,
+ (!disposing).ToGodotBool());
}
else
{
- godot_icall_Object_Disposed(this, ptr);
+ NativeFuncs.godotsharp_internal_object_disposed(NativePtr, gcHandleToFree);
}
- ptr = IntPtr.Zero;
+ NativePtr = IntPtr.Zero;
}
- _disposed = true;
+ DisposablesTracker.UnregisterGodotObject(this, _weakReferenceToSelf);
}
/// <summary>
@@ -97,7 +134,9 @@ namespace Godot
/// <returns>A string representation of this object.</returns>
public override string ToString()
{
- return godot_icall_Object_ToString(GetPtr(this));
+ NativeFuncs.godotsharp_object_to_string(GetPtr(this), out godot_string str);
+ using (str)
+ return Marshaling.ConvertStringToManaged(str);
}
/// <summary>
@@ -132,33 +171,72 @@ namespace Godot
return new SignalAwaiter(source, signal, this);
}
- /// <summary>
- /// Gets a new <see cref="DynamicGodotObject"/> associated with this instance.
- /// </summary>
- public dynamic DynamicObject => new DynamicGodotObject(this);
+ internal static Type InternalGetClassNativeBase(Type t)
+ {
+ do
+ {
+ var assemblyName = t.Assembly.GetName();
- internal static IntPtr __ClassDB_get_method(StringName type, string method)
+ if (assemblyName.Name == "GodotSharp")
+ return t;
+
+ if (assemblyName.Name == "GodotSharpEditor")
+ return t;
+ } while ((t = t.BaseType) != null);
+
+ return null;
+ }
+
+ // ReSharper disable once VirtualMemberNeverOverridden.Global
+ protected internal virtual bool SetGodotClassPropertyValue(in godot_string_name name, in godot_variant value)
+ {
+ return false;
+ }
+
+ // ReSharper disable once VirtualMemberNeverOverridden.Global
+ protected internal virtual bool GetGodotClassPropertyValue(in godot_string_name name, out godot_variant value)
+ {
+ value = default;
+ return false;
+ }
+
+ // ReSharper disable once VirtualMemberNeverOverridden.Global
+ protected internal virtual void RaiseGodotClassSignalCallbacks(in godot_string_name signal,
+ NativeVariantPtrArgs args, int argCount)
{
- return godot_icall_Object_ClassDB_get_method(StringName.GetPtr(type), method);
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_Object_Ctor(Object obj);
+ internal static IntPtr ClassDB_get_method(StringName type, StringName method)
+ {
+ var typeSelf = (godot_string_name)type.NativeValue;
+ var methodSelf = (godot_string_name)method.NativeValue;
+ IntPtr methodBind = NativeFuncs.godotsharp_method_bind_get_method(typeSelf, methodSelf);
+
+ if (methodBind == IntPtr.Zero)
+ throw new NativeMethodBindNotFoundException(type + "." + method);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Object_Disposed(Object obj, IntPtr ptr);
+ return methodBind;
+ }
+
+ internal static unsafe delegate* unmanaged<IntPtr> ClassDB_get_constructor(StringName type)
+ {
+ // for some reason the '??' operator doesn't support 'delegate*'
+ var typeSelf = (godot_string_name)type.NativeValue;
+ var nativeConstructor = NativeFuncs.godotsharp_get_class_constructor(typeSelf);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_RefCounted_Disposed(Object obj, IntPtr ptr, bool isFinalizer);
+ if (nativeConstructor == null)
+ throw new NativeConstructorNotFoundException(type);
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_Object_ConnectEventSignals(IntPtr obj);
+ return nativeConstructor;
+ }
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern string godot_icall_Object_ToString(IntPtr ptr);
+ protected internal virtual void SaveGodotObjectData(GodotSerializationInfo info)
+ {
+ }
- // Used by the generated API
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_Object_ClassDB_get_method(IntPtr type, string method);
+ // TODO: Should this be a constructor overload?
+ protected internal virtual void RestoreGodotObjectData(GodotSerializationInfo info)
+ {
+ }
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.exceptions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.exceptions.cs
new file mode 100644
index 0000000000..0fcc4ee01b
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.exceptions.cs
@@ -0,0 +1,142 @@
+using System;
+using System.Text;
+
+#nullable enable
+
+namespace Godot
+{
+ public partial class Object
+ {
+ public class NativeMemberNotFoundException : Exception
+ {
+ public NativeMemberNotFoundException()
+ {
+ }
+
+ public NativeMemberNotFoundException(string? message) : base(message)
+ {
+ }
+
+ public NativeMemberNotFoundException(string? message, Exception? innerException)
+ : base(message, innerException)
+ {
+ }
+ }
+
+ public class NativeConstructorNotFoundException : NativeMemberNotFoundException
+ {
+ private readonly string? _nativeClassName;
+
+ // ReSharper disable once InconsistentNaming
+ private const string Arg_NativeConstructorNotFoundException = "Unable to find the native constructor.";
+
+ public NativeConstructorNotFoundException()
+ : base(Arg_NativeConstructorNotFoundException)
+ {
+ }
+
+ public NativeConstructorNotFoundException(string? nativeClassName)
+ : this(Arg_NativeConstructorNotFoundException, nativeClassName)
+ {
+ }
+
+ public NativeConstructorNotFoundException(string? message, Exception? innerException)
+ : base(message, innerException)
+ {
+ }
+
+ public NativeConstructorNotFoundException(string? message, string? nativeClassName)
+ : base(message)
+ {
+ _nativeClassName = nativeClassName;
+ }
+
+ public NativeConstructorNotFoundException(string? message, string? nativeClassName, Exception? innerException)
+ : base(message, innerException)
+ {
+ _nativeClassName = nativeClassName;
+ }
+
+ public override string Message
+ {
+ get
+ {
+ StringBuilder sb;
+ if (string.IsNullOrEmpty(base.Message))
+ {
+ sb = new(Arg_NativeConstructorNotFoundException);
+ }
+ else
+ {
+ sb = new(base.Message);
+ }
+
+ if (!string.IsNullOrEmpty(_nativeClassName))
+ {
+ sb.Append($" (Method '{_nativeClassName}')");
+ }
+
+ return sb.ToString();
+ }
+ }
+ }
+
+ public class NativeMethodBindNotFoundException : NativeMemberNotFoundException
+ {
+ private readonly string? _nativeMethodName;
+
+ // ReSharper disable once InconsistentNaming
+ private const string Arg_NativeMethodBindNotFoundException = "Unable to find the native method bind.";
+
+ public NativeMethodBindNotFoundException()
+ : base(Arg_NativeMethodBindNotFoundException)
+ {
+ }
+
+ public NativeMethodBindNotFoundException(string? nativeMethodName)
+ : this(Arg_NativeMethodBindNotFoundException, nativeMethodName)
+ {
+ }
+
+ public NativeMethodBindNotFoundException(string? message, Exception? innerException)
+ : base(message, innerException)
+ {
+ }
+
+ public NativeMethodBindNotFoundException(string? message, string? nativeMethodName)
+ : base(message)
+ {
+ _nativeMethodName = nativeMethodName;
+ }
+
+ public NativeMethodBindNotFoundException(string? message, string? nativeMethodName, Exception? innerException)
+ : base(message, innerException)
+ {
+ _nativeMethodName = nativeMethodName;
+ }
+
+ public override string Message
+ {
+ get
+ {
+ StringBuilder sb;
+ if (string.IsNullOrEmpty(base.Message))
+ {
+ sb = new(Arg_NativeMethodBindNotFoundException);
+ }
+ else
+ {
+ sb = new(base.Message);
+ }
+
+ if (!string.IsNullOrEmpty(_nativeMethodName))
+ {
+ sb.Append($" (Method '{_nativeMethodName}')");
+ }
+
+ return sb.ToString();
+ }
+ }
+ }
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
index fd97a71e47..13070c8033 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
@@ -1,8 +1,3 @@
-#if REAL_T_IS_DOUBLE
-using real_t = System.Double;
-#else
-using real_t = System.Single;
-#endif
using System;
using System.Runtime.InteropServices;
@@ -358,12 +353,7 @@ namespace Godot
/// <returns>Whether or not the plane and the other object are exactly equal.</returns>
public override bool Equals(object obj)
{
- if (obj is Plane)
- {
- return Equals((Plane)obj);
- }
-
- return false;
+ return obj is Plane other && Equals(other);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
index d774021131..da895fd121 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
@@ -1,8 +1,3 @@
-#if REAL_T_IS_DOUBLE
-using real_t = System.Double;
-#else
-using real_t = System.Single;
-#endif
using System;
using System.Runtime.InteropServices;
@@ -44,22 +39,22 @@ namespace Godot
}
/// <summary>
- /// The projections's X column. Also accessible by using the index position <c>[0]</c>.
+ /// The projection's X column. Also accessible by using the index position <c>[0]</c>.
/// </summary>
public Vector4 x;
/// <summary>
- /// The projections's Y column. Also accessible by using the index position <c>[1]</c>.
+ /// The projection's Y column. Also accessible by using the index position <c>[1]</c>.
/// </summary>
public Vector4 y;
/// <summary>
- /// The projections's Z column. Also accessible by using the index position <c>[2]</c>.
+ /// The projection's Z column. Also accessible by using the index position <c>[2]</c>.
/// </summary>
public Vector4 z;
/// <summary>
- /// The projections's W column. Also accessible by using the index position <c>[3]</c>.
+ /// The projection's W column. Also accessible by using the index position <c>[3]</c>.
/// </summary>
public Vector4 w;
@@ -79,18 +74,6 @@ namespace Godot
}
/// <summary>
- /// Constructs a new <see cref="Projection"/> from an existing <see cref="Projection"/>.
- /// </summary>
- /// <param name="proj">The existing <see cref="Projection"/>.</param>
- public Projection(Projection proj)
- {
- x = proj.x;
- y = proj.y;
- z = proj.z;
- w = proj.w;
- }
-
- /// <summary>
/// Constructs a new <see cref="Projection"/> from a <see cref="Transform3D"/>.
/// </summary>
/// <param name="transform">The <see cref="Transform3D"/>.</param>
@@ -243,7 +226,7 @@ namespace Godot
{
fovyDegrees = GetFovy(fovyDegrees, (real_t)1.0 / aspect);
}
- real_t radians = Mathf.Deg2Rad(fovyDegrees / (real_t)2.0);
+ real_t radians = Mathf.DegToRad(fovyDegrees / (real_t)2.0);
real_t deltaZ = zFar - zNear;
real_t sine = Mathf.Sin(radians);
@@ -273,7 +256,7 @@ namespace Godot
fovyDegrees = GetFovy(fovyDegrees, (real_t)1.0 / aspect);
}
- real_t ymax = zNear * Mathf.Tan(Mathf.Deg2Rad(fovyDegrees / (real_t)2.0));
+ real_t ymax = zNear * Mathf.Tan(Mathf.DegToRad(fovyDegrees / (real_t)2.0));
real_t xmax = ymax * aspect;
real_t frustumshift = (intraocularDist / (real_t)2.0) * zNear / convergenceDist;
real_t left;
@@ -330,18 +313,18 @@ namespace Godot
Plane rightPlane = new Plane(x.w - x.x, y.w - y.x, z.w - z.x, -w.w + w.x).Normalized();
if (z.x == 0 && z.y == 0)
{
- return Mathf.Rad2Deg(Mathf.Acos(Mathf.Abs(rightPlane.Normal.x))) * (real_t)2.0;
+ return Mathf.RadToDeg(Mathf.Acos(Mathf.Abs(rightPlane.Normal.x))) * (real_t)2.0;
}
else
{
Plane leftPlane = new Plane(x.w + x.x, y.w + y.x, z.w + z.x, w.w + w.x).Normalized();
- return Mathf.Rad2Deg(Mathf.Acos(Mathf.Abs(leftPlane.Normal.x))) + Mathf.Rad2Deg(Mathf.Acos(Mathf.Abs(rightPlane.Normal.x)));
+ return Mathf.RadToDeg(Mathf.Acos(Mathf.Abs(leftPlane.Normal.x))) + Mathf.RadToDeg(Mathf.Acos(Mathf.Abs(rightPlane.Normal.x)));
}
}
public static real_t GetFovy(real_t fovx, real_t aspect)
{
- return Mathf.Rad2Deg(Mathf.Atan(aspect * Mathf.Tan(Mathf.Deg2Rad(fovx) * (real_t)0.5)) * (real_t)2.0);
+ return Mathf.RadToDeg(Mathf.Atan(aspect * Mathf.Tan(Mathf.DegToRad(fovx) * (real_t)0.5)) * (real_t)2.0);
}
public real_t GetLodMultiplier()
@@ -360,7 +343,7 @@ namespace Godot
public int GetPixelsPerMeter(int forPixelWidth)
{
- Vector3 result = Xform(new Vector3(1, 0, -1));
+ Vector3 result = this * new Vector3(1, 0, -1);
return (int)((result.x * (real_t)0.5 + (real_t)0.5) * forPixelWidth);
}
@@ -593,19 +576,51 @@ namespace Godot
}
/// <summary>
- /// Returns a vector transformed (multiplied) by this projection.
+ /// Returns a Vector4 transformed (multiplied) by the projection.
/// </summary>
/// <param name="proj">The projection to apply.</param>
- /// <param name="v">A vector to transform.</param>
- /// <returns>The transformed vector.</returns>
- public static Vector4 operator *(Projection proj, Vector4 v)
+ /// <param name="vector">A Vector4 to transform.</param>
+ /// <returns>The transformed Vector4.</returns>
+ public static Vector4 operator *(Projection proj, Vector4 vector)
{
return new Vector4(
- proj.x.x * v.x + proj.y.x * v.y + proj.z.x * v.z + proj.w.x * v.w,
- proj.x.y * v.x + proj.y.y * v.y + proj.z.y * v.z + proj.w.y * v.w,
- proj.x.z * v.x + proj.y.z * v.y + proj.z.z * v.z + proj.w.z * v.w,
- proj.x.w * v.x + proj.y.w * v.y + proj.z.w * v.z + proj.w.w * v.w
+ proj.x.x * vector.x + proj.y.x * vector.y + proj.z.x * vector.z + proj.w.x * vector.w,
+ proj.x.y * vector.x + proj.y.y * vector.y + proj.z.y * vector.z + proj.w.y * vector.w,
+ proj.x.z * vector.x + proj.y.z * vector.y + proj.z.z * vector.z + proj.w.z * vector.w,
+ proj.x.w * vector.x + proj.y.w * vector.y + proj.z.w * vector.z + proj.w.w * vector.w
+ );
+ }
+
+ /// <summary>
+ /// Returns a Vector4 transformed (multiplied) by the inverse projection.
+ /// </summary>
+ /// <param name="proj">The projection to apply.</param>
+ /// <param name="vector">A Vector4 to transform.</param>
+ /// <returns>The inversely transformed Vector4.</returns>
+ public static Vector4 operator *(Vector4 vector, Projection proj)
+ {
+ return new Vector4(
+ proj.x.x * vector.x + proj.x.y * vector.y + proj.x.z * vector.z + proj.x.w * vector.w,
+ proj.y.x * vector.x + proj.y.y * vector.y + proj.y.z * vector.z + proj.y.w * vector.w,
+ proj.z.x * vector.x + proj.z.y * vector.y + proj.z.z * vector.z + proj.z.w * vector.w,
+ proj.w.x * vector.x + proj.w.y * vector.y + proj.w.z * vector.z + proj.w.w * vector.w
+ );
+ }
+
+ /// <summary>
+ /// Returns a Vector3 transformed (multiplied) by the projection.
+ /// </summary>
+ /// <param name="proj">The projection to apply.</param>
+ /// <param name="vector">A Vector3 to transform.</param>
+ /// <returns>The transformed Vector3.</returns>
+ public static Vector3 operator *(Projection proj, Vector3 vector)
+ {
+ Vector3 ret = new Vector3(
+ proj.x.x * vector.x + proj.y.x * vector.y + proj.z.x * vector.z + proj.w.x,
+ proj.x.y * vector.x + proj.y.y * vector.y + proj.z.y * vector.z + proj.w.y,
+ proj.x.z * vector.x + proj.y.z * vector.y + proj.z.z * vector.z + proj.w.z
);
+ return ret / (proj.x.w * vector.x + proj.y.w * vector.y + proj.z.w * vector.z + proj.w.w);
}
/// <summary>
@@ -634,6 +649,9 @@ namespace Godot
/// Access whole columns in the form of <see cref="Vector4"/>.
/// </summary>
/// <param name="column">Which column vector.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="column"/> is not 0, 1, 2 or 3.
+ /// </exception>
public Vector4 this[int column]
{
get
@@ -649,7 +667,7 @@ namespace Godot
case 3:
return w;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(column));
}
}
set
@@ -669,7 +687,7 @@ namespace Godot
w = value;
return;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(column));
}
}
}
@@ -679,6 +697,9 @@ namespace Godot
/// </summary>
/// <param name="column">Which column vector.</param>
/// <param name="row">Which row of the column.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="column"/> or <paramref name="row"/> are not 0, 1, 2 or 3.
+ /// </exception>
public real_t this[int column, int row]
{
get
@@ -694,7 +715,7 @@ namespace Godot
case 3:
return w[row];
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(column));
}
}
set
@@ -714,26 +735,11 @@ namespace Godot
w[row] = value;
return;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(column));
}
}
}
- /// <summary>
- /// Returns a vector transformed (multiplied) by this projection.
- /// </summary>
- /// <param name="v">A vector to transform.</param>
- /// <returns>The transformed vector.</returns>
- private Vector3 Xform(Vector3 v)
- {
- Vector3 ret = new Vector3(
- x.x * v.x + y.x * v.y + z.x * v.z + w.x,
- x.y * v.x + y.y * v.y + z.y * v.z + w.y,
- x.z * v.x + y.z * v.y + z.z * v.z + w.z
- );
- return ret / (x.w * v.x + y.w * v.y + z.w * v.z + w.w);
- }
-
// Constants
private static readonly Projection _zero = new Projection(
new Vector4(0, 0, 0, 0),
@@ -800,11 +806,7 @@ namespace Godot
/// <returns>Whether or not the vector and the object are equal.</returns>
public override bool Equals(object obj)
{
- if (obj is Projection)
- {
- return Equals((Projection)obj);
- }
- return false;
+ return obj is Projection other && Equals(other);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
index e38dca414f..d459fe8c96 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
@@ -1,8 +1,3 @@
-#if REAL_T_IS_DOUBLE
-using real_t = System.Double;
-#else
-using real_t = System.Single;
-#endif
using System;
using System.Runtime.InteropServices;
@@ -52,6 +47,9 @@ namespace Godot
/// <summary>
/// Access quaternion components using their index.
/// </summary>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is not 0, 1, 2 or 3.
+ /// </exception>
/// <value>
/// <c>[0]</c> is equivalent to <see cref="x"/>,
/// <c>[1]</c> is equivalent to <see cref="y"/>,
@@ -73,7 +71,7 @@ namespace Godot
case 3:
return w;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
set
@@ -93,7 +91,7 @@ namespace Godot
w = value;
break;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
}
@@ -137,20 +135,136 @@ namespace Godot
}
/// <summary>
- /// Performs a cubic spherical interpolation between quaternions <paramref name="preA"/>, this quaternion,
+ /// Performs a spherical cubic interpolation between quaternions <paramref name="preA"/>, this quaternion,
+ /// <paramref name="b"/>, and <paramref name="postB"/>, by the given amount <paramref name="weight"/>.
+ /// </summary>
+ /// <param name="b">The destination quaternion.</param>
+ /// <param name="preA">A quaternion before this quaternion.</param>
+ /// <param name="postB">A quaternion after <paramref name="b"/>.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <returns>The interpolated quaternion.</returns>
+ public Quaternion SphericalCubicInterpolate(Quaternion b, Quaternion preA, Quaternion postB, real_t weight)
+ {
+#if DEBUG
+ if (!IsNormalized())
+ {
+ throw new InvalidOperationException("Quaternion is not normalized");
+ }
+ if (!b.IsNormalized())
+ {
+ throw new ArgumentException("Argument is not normalized", nameof(b));
+ }
+#endif
+
+ // Align flip phases.
+ Quaternion fromQ = new Basis(this).GetRotationQuaternion();
+ Quaternion preQ = new Basis(preA).GetRotationQuaternion();
+ Quaternion toQ = new Basis(b).GetRotationQuaternion();
+ Quaternion postQ = new Basis(postB).GetRotationQuaternion();
+
+ // Flip quaternions to shortest path if necessary.
+ bool flip1 = Math.Sign(fromQ.Dot(preQ)) < 0;
+ preQ = flip1 ? -preQ : preQ;
+ bool flip2 = Math.Sign(fromQ.Dot(toQ)) < 0;
+ toQ = flip2 ? -toQ : toQ;
+ bool flip3 = flip2 ? toQ.Dot(postQ) <= 0 : Math.Sign(toQ.Dot(postQ)) < 0;
+ postQ = flip3 ? -postQ : postQ;
+
+ // Calc by Expmap in fromQ space.
+ Quaternion lnFrom = new Quaternion(0, 0, 0, 0);
+ Quaternion lnTo = (fromQ.Inverse() * toQ).Log();
+ Quaternion lnPre = (fromQ.Inverse() * preQ).Log();
+ Quaternion lnPost = (fromQ.Inverse() * postQ).Log();
+ Quaternion ln = new Quaternion(
+ Mathf.CubicInterpolate(lnFrom.x, lnTo.x, lnPre.x, lnPost.x, weight),
+ Mathf.CubicInterpolate(lnFrom.y, lnTo.y, lnPre.y, lnPost.y, weight),
+ Mathf.CubicInterpolate(lnFrom.z, lnTo.z, lnPre.z, lnPost.z, weight),
+ 0);
+ Quaternion q1 = fromQ * ln.Exp();
+
+ // Calc by Expmap in toQ space.
+ lnFrom = (toQ.Inverse() * fromQ).Log();
+ lnTo = new Quaternion(0, 0, 0, 0);
+ lnPre = (toQ.Inverse() * preQ).Log();
+ lnPost = (toQ.Inverse() * postQ).Log();
+ ln = new Quaternion(
+ Mathf.CubicInterpolate(lnFrom.x, lnTo.x, lnPre.x, lnPost.x, weight),
+ Mathf.CubicInterpolate(lnFrom.y, lnTo.y, lnPre.y, lnPost.y, weight),
+ Mathf.CubicInterpolate(lnFrom.z, lnTo.z, lnPre.z, lnPost.z, weight),
+ 0);
+ Quaternion q2 = toQ * ln.Exp();
+
+ // To cancel error made by Expmap ambiguity, do blends.
+ return q1.Slerp(q2, weight);
+ }
+
+ /// <summary>
+ /// Performs a spherical cubic interpolation between quaternions <paramref name="preA"/>, this quaternion,
/// <paramref name="b"/>, and <paramref name="postB"/>, by the given amount <paramref name="weight"/>.
+ /// It can perform smoother interpolation than <see cref="SphericalCubicInterpolate"/>
+ /// by the time values.
/// </summary>
/// <param name="b">The destination quaternion.</param>
/// <param name="preA">A quaternion before this quaternion.</param>
/// <param name="postB">A quaternion after <paramref name="b"/>.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <param name="bT"></param>
+ /// <param name="preAT"></param>
+ /// <param name="postBT"></param>
/// <returns>The interpolated quaternion.</returns>
- public Quaternion CubicSlerp(Quaternion b, Quaternion preA, Quaternion postB, real_t weight)
+ public Quaternion SphericalCubicInterpolateInTime(Quaternion b, Quaternion preA, Quaternion postB, real_t weight, real_t bT, real_t preAT, real_t postBT)
{
- real_t t2 = (1.0f - weight) * weight * 2f;
- Quaternion sp = Slerp(b, weight);
- Quaternion sq = preA.Slerpni(postB, weight);
- return sp.Slerpni(sq, t2);
+#if DEBUG
+ if (!IsNormalized())
+ {
+ throw new InvalidOperationException("Quaternion is not normalized");
+ }
+ if (!b.IsNormalized())
+ {
+ throw new ArgumentException("Argument is not normalized", nameof(b));
+ }
+#endif
+
+ // Align flip phases.
+ Quaternion fromQ = new Basis(this).GetRotationQuaternion();
+ Quaternion preQ = new Basis(preA).GetRotationQuaternion();
+ Quaternion toQ = new Basis(b).GetRotationQuaternion();
+ Quaternion postQ = new Basis(postB).GetRotationQuaternion();
+
+ // Flip quaternions to shortest path if necessary.
+ bool flip1 = Math.Sign(fromQ.Dot(preQ)) < 0;
+ preQ = flip1 ? -preQ : preQ;
+ bool flip2 = Math.Sign(fromQ.Dot(toQ)) < 0;
+ toQ = flip2 ? -toQ : toQ;
+ bool flip3 = flip2 ? toQ.Dot(postQ) <= 0 : Math.Sign(toQ.Dot(postQ)) < 0;
+ postQ = flip3 ? -postQ : postQ;
+
+ // Calc by Expmap in fromQ space.
+ Quaternion lnFrom = new Quaternion(0, 0, 0, 0);
+ Quaternion lnTo = (fromQ.Inverse() * toQ).Log();
+ Quaternion lnPre = (fromQ.Inverse() * preQ).Log();
+ Quaternion lnPost = (fromQ.Inverse() * postQ).Log();
+ Quaternion ln = new Quaternion(
+ Mathf.CubicInterpolateInTime(lnFrom.x, lnTo.x, lnPre.x, lnPost.x, weight, bT, preAT, postBT),
+ Mathf.CubicInterpolateInTime(lnFrom.y, lnTo.y, lnPre.y, lnPost.y, weight, bT, preAT, postBT),
+ Mathf.CubicInterpolateInTime(lnFrom.z, lnTo.z, lnPre.z, lnPost.z, weight, bT, preAT, postBT),
+ 0);
+ Quaternion q1 = fromQ * ln.Exp();
+
+ // Calc by Expmap in toQ space.
+ lnFrom = (toQ.Inverse() * fromQ).Log();
+ lnTo = new Quaternion(0, 0, 0, 0);
+ lnPre = (toQ.Inverse() * preQ).Log();
+ lnPost = (toQ.Inverse() * postQ).Log();
+ ln = new Quaternion(
+ Mathf.CubicInterpolateInTime(lnFrom.x, lnTo.x, lnPre.x, lnPost.x, weight, bT, preAT, postBT),
+ Mathf.CubicInterpolateInTime(lnFrom.y, lnTo.y, lnPre.y, lnPost.y, weight, bT, preAT, postBT),
+ Mathf.CubicInterpolateInTime(lnFrom.z, lnTo.z, lnPre.z, lnPost.z, weight, bT, preAT, postBT),
+ 0);
+ Quaternion q2 = toQ * ln.Exp();
+
+ // To cancel error made by Expmap ambiguity, do blends.
+ return q1.Slerp(q2, weight);
}
/// <summary>
@@ -163,6 +277,34 @@ namespace Godot
return (x * b.x) + (y * b.y) + (z * b.z) + (w * b.w);
}
+ public Quaternion Exp()
+ {
+ Vector3 v = new Vector3(x, y, z);
+ real_t theta = v.Length();
+ v = v.Normalized();
+ if (theta < Mathf.Epsilon || !v.IsNormalized())
+ {
+ return new Quaternion(0, 0, 0, 1);
+ }
+ return new Quaternion(v, theta);
+ }
+
+ public real_t GetAngle()
+ {
+ return 2 * Mathf.Acos(w);
+ }
+
+ public Vector3 GetAxis()
+ {
+ if (Mathf.Abs(w) > 1 - Mathf.Epsilon)
+ {
+ return new Vector3(x, y, z);
+ }
+
+ real_t r = 1 / Mathf.Sqrt(1 - w * w);
+ return new Vector3(x * r, y * r, z * r);
+ }
+
/// <summary>
/// Returns Euler angles (in the YXZ convention: when decomposing,
/// first Z, then X, and Y last) corresponding to the rotation
@@ -175,7 +317,7 @@ namespace Godot
#if DEBUG
if (!IsNormalized())
{
- throw new InvalidOperationException("Quaternion is not normalized");
+ throw new InvalidOperationException("Quaternion is not normalized.");
}
#endif
var basis = new Basis(this);
@@ -191,7 +333,7 @@ namespace Godot
#if DEBUG
if (!IsNormalized())
{
- throw new InvalidOperationException("Quaternion is not normalized");
+ throw new InvalidOperationException("Quaternion is not normalized.");
}
#endif
return new Quaternion(-x, -y, -z, w);
@@ -206,6 +348,12 @@ namespace Godot
return Mathf.Abs(LengthSquared - 1) <= Mathf.Epsilon;
}
+ public Quaternion Log()
+ {
+ Vector3 v = GetAxis() * GetAngle();
+ return new Quaternion(v.x, v.y, v.z, 0);
+ }
+
/// <summary>
/// Returns a copy of the quaternion, normalized to unit length.
/// </summary>
@@ -229,16 +377,16 @@ namespace Godot
#if DEBUG
if (!IsNormalized())
{
- throw new InvalidOperationException("Quaternion is not normalized");
+ throw new InvalidOperationException("Quaternion is not normalized.");
}
if (!to.IsNormalized())
{
- throw new ArgumentException("Argument is not normalized", nameof(to));
+ throw new ArgumentException("Argument is not normalized.", nameof(to));
}
#endif
// Calculate cosine.
- real_t cosom = x * to.x + y * to.y + z * to.z + w * to.w;
+ real_t cosom = Dot(to);
var to1 = new Quaternion();
@@ -246,17 +394,11 @@ namespace Godot
if (cosom < 0.0)
{
cosom = -cosom;
- to1.x = -to.x;
- to1.y = -to.y;
- to1.z = -to.z;
- to1.w = -to.w;
+ to1 = -to;
}
else
{
- to1.x = to.x;
- to1.y = to.y;
- to1.z = to.z;
- to1.w = to.w;
+ to1 = to;
}
real_t sinom, scale0, scale1;
@@ -297,6 +439,17 @@ namespace Godot
/// <returns>The resulting quaternion of the interpolation.</returns>
public Quaternion Slerpni(Quaternion to, real_t weight)
{
+#if DEBUG
+ if (!IsNormalized())
+ {
+ throw new InvalidOperationException("Quaternion is not normalized");
+ }
+ if (!to.IsNormalized())
+ {
+ throw new ArgumentException("Argument is not normalized", nameof(to));
+ }
+#endif
+
real_t dot = Dot(to);
if (Mathf.Abs(dot) > 0.9999f)
@@ -318,24 +471,6 @@ namespace Godot
);
}
- /// <summary>
- /// Returns a vector transformed (multiplied) by this quaternion.
- /// </summary>
- /// <param name="v">A vector to transform.</param>
- /// <returns>The transformed vector.</returns>
- public Vector3 Xform(Vector3 v)
- {
-#if DEBUG
- if (!IsNormalized())
- {
- throw new InvalidOperationException("Quaternion is not normalized");
- }
-#endif
- var u = new Vector3(x, y, z);
- Vector3 uv = u.Cross(v);
- return v + (((uv * w) + u.Cross(uv)) * 2);
- }
-
// Constants
private static readonly Quaternion _identity = new Quaternion(0, 0, 0, 1);
@@ -363,15 +498,6 @@ namespace Godot
}
/// <summary>
- /// Constructs a <see cref="Quaternion"/> from the given <see cref="Quaternion"/>.
- /// </summary>
- /// <param name="q">The existing quaternion.</param>
- public Quaternion(Quaternion q)
- {
- this = q;
- }
-
- /// <summary>
/// Constructs a <see cref="Quaternion"/> from the given <see cref="Basis"/>.
/// </summary>
/// <param name="basis">The <see cref="Basis"/> to construct from.</param>
@@ -420,7 +546,7 @@ namespace Godot
#if DEBUG
if (!axis.IsNormalized())
{
- throw new ArgumentException("Argument is not normalized", nameof(axis));
+ throw new ArgumentException("Argument is not normalized.", nameof(axis));
}
#endif
@@ -466,6 +592,36 @@ namespace Godot
}
/// <summary>
+ /// Returns a Vector3 rotated (multiplied) by the quaternion.
+ /// </summary>
+ /// <param name="quaternion">The quaternion to rotate by.</param>
+ /// <param name="vector">A Vector3 to transform.</param>
+ /// <returns>The rotated Vector3.</returns>
+ public static Vector3 operator *(Quaternion quaternion, Vector3 vector)
+ {
+#if DEBUG
+ if (!quaternion.IsNormalized())
+ {
+ throw new InvalidOperationException("Quaternion is not normalized.");
+ }
+#endif
+ var u = new Vector3(quaternion.x, quaternion.y, quaternion.z);
+ Vector3 uv = u.Cross(vector);
+ return vector + (((uv * quaternion.w) + u.Cross(uv)) * 2);
+ }
+
+ /// <summary>
+ /// Returns a Vector3 rotated (multiplied) by the inverse quaternion.
+ /// </summary>
+ /// <param name="vector">A Vector3 to inversely rotate.</param>
+ /// <param name="quaternion">The quaternion to rotate by.</param>
+ /// <returns>The inversely rotated Vector3.</returns>
+ public static Vector3 operator *(Vector3 vector, Quaternion quaternion)
+ {
+ return quaternion.Inverse() * vector;
+ }
+
+ /// <summary>
/// Adds each component of the left <see cref="Quaternion"/>
/// to the right <see cref="Quaternion"/>. This operation is not
/// meaningful on its own, but it can be used as a part of a
@@ -508,38 +664,6 @@ namespace Godot
}
/// <summary>
- /// Rotates (multiplies) the <see cref="Vector3"/>
- /// by the given <see cref="Quaternion"/>.
- /// </summary>
- /// <param name="quat">The quaternion to rotate by.</param>
- /// <param name="vec">The vector to rotate.</param>
- /// <returns>The rotated vector.</returns>
- public static Vector3 operator *(Quaternion quat, Vector3 vec)
- {
-#if DEBUG
- if (!quat.IsNormalized())
- {
- throw new InvalidOperationException("Quaternion is not normalized.");
- }
-#endif
- var u = new Vector3(quat.x, quat.y, quat.z);
- Vector3 uv = u.Cross(vec);
- return vec + (((uv * quat.w) + u.Cross(uv)) * 2);
- }
-
- /// <summary>
- /// Inversely rotates (multiplies) the <see cref="Vector3"/>
- /// by the given <see cref="Quaternion"/>.
- /// </summary>
- /// <param name="vec">The vector to rotate.</param>
- /// <param name="quat">The quaternion to rotate by.</param>
- /// <returns>The inversely rotated vector.</returns>
- public static Vector3 operator *(Vector3 vec, Quaternion quat)
- {
- return quat.Inverse() * vec;
- }
-
- /// <summary>
/// Multiplies each component of the <see cref="Quaternion"/>
/// by the given <see cref="real_t"/>. This operation is not
/// meaningful on its own, but it can be used as a part of a
@@ -614,12 +738,7 @@ namespace Godot
/// <returns>Whether or not the quaternion and the other object are exactly equal.</returns>
public override bool Equals(object obj)
{
- if (obj is Quaternion)
- {
- return Equals((Quaternion)obj);
- }
-
- return false;
+ return obj is Quaternion other && Equals(other);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs
index 1588869ec0..a31fef8360 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/RID.cs
@@ -1,5 +1,7 @@
using System;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Godot.NativeInterop;
namespace Godot
{
@@ -9,99 +11,32 @@ namespace Godot
/// resource by themselves. They are used by and with the low-level Server
/// classes such as <see cref="RenderingServer"/>.
/// </summary>
- public sealed partial class RID : IDisposable
+ [StructLayout(LayoutKind.Sequential)]
+ public struct RID
{
- private bool _disposed = false;
+ private ulong _id; // Default is 0
- internal IntPtr ptr;
-
- internal static IntPtr GetPtr(RID instance)
- {
- if (instance == null)
- throw new NullReferenceException($"The instance of type {nameof(RID)} is null.");
-
- if (instance._disposed)
- throw new ObjectDisposedException(instance.GetType().FullName);
-
- return instance.ptr;
- }
-
- ~RID()
- {
- Dispose(false);
- }
-
- /// <summary>
- /// Disposes of this <see cref="RID"/>.
- /// </summary>
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- private void Dispose(bool disposing)
- {
- if (_disposed)
- return;
-
- if (ptr != IntPtr.Zero)
- {
- godot_icall_RID_Dtor(ptr);
- ptr = IntPtr.Zero;
- }
-
- _disposed = true;
- }
-
- internal RID(IntPtr ptr)
+ internal RID(ulong id)
{
- this.ptr = ptr;
- }
-
- /// <summary>
- /// The pointer to the native instance of this <see cref="RID"/>.
- /// </summary>
- public IntPtr NativeInstance
- {
- get { return ptr; }
- }
-
- internal RID()
- {
- this.ptr = IntPtr.Zero;
+ _id = id;
}
/// <summary>
/// Constructs a new <see cref="RID"/> for the given <see cref="Object"/> <paramref name="from"/>.
/// </summary>
public RID(Object from)
- {
- this.ptr = godot_icall_RID_Ctor(Object.GetPtr(from));
- }
+ => _id = from is Resource res ? res.GetRid()._id : default;
/// <summary>
/// Returns the ID of the referenced resource.
/// </summary>
/// <returns>The ID of the referenced resource.</returns>
- public int GetId()
- {
- return godot_icall_RID_get_id(GetPtr(this));
- }
+ public ulong Id => _id;
/// <summary>
/// Converts this <see cref="RID"/> to a string.
/// </summary>
/// <returns>A string representation of this RID.</returns>
- public override string ToString() => "[RID]";
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern IntPtr godot_icall_RID_Ctor(IntPtr from);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern void godot_icall_RID_Dtor(IntPtr ptr);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern int godot_icall_RID_get_id(IntPtr ptr);
+ public override string ToString() => $"RID({Id})";
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
index ec16920fed..0b475fec19 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
@@ -1,8 +1,3 @@
-#if REAL_T_IS_DOUBLE
-using real_t = System.Double;
-#else
-using real_t = System.Single;
-#endif
using System;
using System.Runtime.InteropServices;
@@ -431,12 +426,7 @@ namespace Godot
/// <returns>Whether or not the rect and the other object are exactly equal.</returns>
public override bool Equals(object obj)
{
- if (obj is Rect2)
- {
- return Equals((Rect2)obj);
- }
-
- return false;
+ return obj is Rect2 other && Equals(other);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
index 5d53b8330e..8a2a98d6ee 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
@@ -426,12 +426,7 @@ namespace Godot
/// <returns>Whether or not the rect and the other object are equal.</returns>
public override bool Equals(object obj)
{
- if (obj is Rect2i)
- {
- return Equals((Rect2i)obj);
- }
-
- return false;
+ return obj is Rect2i other && Equals(other);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/ReflectionUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/ReflectionUtils.cs
new file mode 100644
index 0000000000..ee605f8d8f
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/ReflectionUtils.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Linq;
+
+#nullable enable
+
+namespace Godot;
+
+internal class ReflectionUtils
+{
+ public static Type? FindTypeInLoadedAssemblies(string assemblyName, string typeFullName)
+ {
+ return AppDomain.CurrentDomain.GetAssemblies()
+ .FirstOrDefault(a => a.GetName().Name == assemblyName)?
+ .GetType(typeFullName);
+ }
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs
index 2ba0493002..96fb891086 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalAwaiter.cs
@@ -1,50 +1,67 @@
using System;
-using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Godot.NativeInterop;
namespace Godot
{
- public class SignalAwaiter : IAwaiter<object[]>, IAwaitable<object[]>
+ public class SignalAwaiter : IAwaiter<Variant[]>, IAwaitable<Variant[]>
{
private bool _completed;
- private object[] _result;
- private Action _action;
+ private Variant[] _result;
+ private Action _continuation;
public SignalAwaiter(Object source, StringName signal, Object target)
{
- godot_icall_SignalAwaiter_connect(Object.GetPtr(source), StringName.GetPtr(signal), Object.GetPtr(target), this);
+ var awaiterGcHandle = CustomGCHandle.AllocStrong(this);
+ using godot_string_name signalSrc = NativeFuncs.godotsharp_string_name_new_copy(
+ (godot_string_name)(signal?.NativeValue ?? default));
+ NativeFuncs.godotsharp_internal_signal_awaiter_connect(Object.GetPtr(source), in signalSrc,
+ Object.GetPtr(target), GCHandle.ToIntPtr(awaiterGcHandle));
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern Error godot_icall_SignalAwaiter_connect(IntPtr source, IntPtr signal, IntPtr target, SignalAwaiter awaiter);
+ public bool IsCompleted => _completed;
- public bool IsCompleted
+ public void OnCompleted(Action continuation)
{
- get
- {
- return _completed;
- }
+ _continuation = continuation;
}
- public void OnCompleted(Action action)
- {
- this._action = action;
- }
+ public Variant[] GetResult() => _result;
- public object[] GetResult()
- {
- return _result;
- }
+ public IAwaiter<Variant[]> GetAwaiter() => this;
- public IAwaiter<object[]> GetAwaiter()
+ [UnmanagedCallersOnly]
+ internal static unsafe void SignalCallback(IntPtr awaiterGCHandlePtr, godot_variant** args, int argCount,
+ godot_bool* outAwaiterIsNull)
{
- return this;
- }
+ try
+ {
+ var awaiter = (SignalAwaiter)GCHandle.FromIntPtr(awaiterGCHandlePtr).Target;
- internal void SignalCallback(object[] args)
- {
- _completed = true;
- _result = args;
- _action?.Invoke();
+ if (awaiter == null)
+ {
+ *outAwaiterIsNull = godot_bool.True;
+ return;
+ }
+
+ *outAwaiterIsNull = godot_bool.False;
+
+ awaiter._completed = true;
+
+ Variant[] signalArgs = new Variant[argCount];
+
+ for (int i = 0; i < argCount; i++)
+ signalArgs[i] = Variant.CreateCopyingBorrowed(*args[i]);
+
+ awaiter._result = signalArgs;
+
+ awaiter._continuation?.Invoke();
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ *outAwaiterIsNull = godot_bool.False;
+ }
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs
index 5680c9d55a..3f50df0a0d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/SignalInfo.cs
@@ -3,7 +3,7 @@ namespace Godot
/// <summary>
/// Represents a signal defined in an object.
/// </summary>
- public struct SignalInfo
+ public readonly struct SignalInfo
{
private readonly Object _owner;
private readonly StringName _signalName;
@@ -18,7 +18,7 @@ namespace Godot
public StringName Name => _signalName;
/// <summary>
- /// Creates a new <see cref="Signal"/> with the name <paramref name="name"/>
+ /// Creates a new <see cref="SignalInfo"/> with the name <paramref name="name"/>
/// in the specified <paramref name="owner"/>.
/// </summary>
/// <param name="owner">Object that contains the signal.</param>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
index a1f058ffe5..f0bc5949df 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs
@@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
using System.Globalization;
-using System.Runtime.CompilerServices;
using System.Security;
using System.Text;
using System.Text.RegularExpressions;
+using Godot.NativeInterop;
+
+#nullable enable
namespace Godot
{
@@ -177,6 +179,7 @@ namespace Godot
{
return 0;
}
+
if (from == 0 && to == len)
{
str = instance;
@@ -214,7 +217,7 @@ namespace Godot
/// <returns>The escaped string.</returns>
public static string CEscape(this string instance)
{
- var sb = new StringBuilder(string.Copy(instance));
+ var sb = new StringBuilder(instance);
sb.Replace("\\", "\\\\");
sb.Replace("\a", "\\a");
@@ -239,7 +242,7 @@ namespace Godot
/// <returns>The unescaped string.</returns>
public static string CUnescape(this string instance)
{
- var sb = new StringBuilder(string.Copy(instance));
+ var sb = new StringBuilder(instance);
sb.Replace("\\a", "\a");
sb.Replace("\\b", "\b");
@@ -471,7 +474,8 @@ namespace Godot
/// <returns>The starting position of the substring, or -1 if not found.</returns>
public static int Find(this string instance, string what, int from = 0, bool caseSensitive = true)
{
- return instance.IndexOf(what, from, caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
+ return instance.IndexOf(what, from,
+ caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
}
/// <summary>
@@ -490,7 +494,8 @@ namespace Godot
{
// TODO: Could be more efficient if we get a char version of `IndexOf`.
// See https://github.com/dotnet/runtime/issues/44116
- return instance.IndexOf(what.ToString(), from, caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
+ return instance.IndexOf(what.ToString(), from,
+ caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
}
/// <summary>Find the last occurrence of a substring.</summary>
@@ -519,7 +524,8 @@ namespace Godot
/// <returns>The starting position of the substring, or -1 if not found.</returns>
public static int FindLast(this string instance, string what, int from, bool caseSensitive = true)
{
- return instance.LastIndexOf(what, from, caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
+ return instance.LastIndexOf(what, from,
+ caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
}
/// <summary>
@@ -804,6 +810,7 @@ namespace Godot
{
match = instance[source] == text[target];
}
+
if (match)
{
source++;
@@ -926,7 +933,7 @@ namespace Godot
/// <returns>The escaped string.</returns>
public static string JSONEscape(this string instance)
{
- var sb = new StringBuilder(string.Copy(instance));
+ var sb = new StringBuilder(instance);
sb.Replace("\\", "\\\\");
sb.Replace("\b", "\\b");
@@ -1015,15 +1022,18 @@ namespace Godot
switch (expr[0])
{
case '*':
- return ExprMatch(instance, expr.Substring(1), caseSensitive) || (instance.Length > 0 && ExprMatch(instance.Substring(1), expr, caseSensitive));
+ return ExprMatch(instance, expr.Substring(1), caseSensitive) || (instance.Length > 0 &&
+ ExprMatch(instance.Substring(1), expr, caseSensitive));
case '?':
- return instance.Length > 0 && instance[0] != '.' && ExprMatch(instance.Substring(1), expr.Substring(1), caseSensitive);
+ return instance.Length > 0 && instance[0] != '.' &&
+ ExprMatch(instance.Substring(1), expr.Substring(1), caseSensitive);
default:
if (instance.Length == 0)
return false;
if (caseSensitive)
return instance[0] == expr[0];
- return (char.ToUpper(instance[0]) == char.ToUpper(expr[0])) && ExprMatch(instance.Substring(1), expr.Substring(1), caseSensitive);
+ return (char.ToUpper(instance[0]) == char.ToUpper(expr[0])) &&
+ ExprMatch(instance.Substring(1), expr.Substring(1), caseSensitive);
}
}
@@ -1070,12 +1080,12 @@ namespace Godot
/// <returns>The MD5 hash of the string.</returns>
public static byte[] MD5Buffer(this string instance)
{
- return godot_icall_String_md5_buffer(instance);
+ using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
+ NativeFuncs.godotsharp_string_md5_buffer(instanceStr, out var md5Buffer);
+ using (md5Buffer)
+ return Marshaling.ConvertNativePackedByteArrayToSystemArray(md5Buffer);
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern byte[] godot_icall_String_md5_buffer(string str);
-
/// <summary>
/// Returns the MD5 hash of the string as a string.
/// </summary>
@@ -1084,12 +1094,12 @@ namespace Godot
/// <returns>The MD5 hash of the string.</returns>
public static string MD5Text(this string instance)
{
- return godot_icall_String_md5_text(instance);
+ using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
+ NativeFuncs.godotsharp_string_md5_text(instanceStr, out var md5Text);
+ using (md5Text)
+ return Marshaling.ConvertStringToManaged(md5Text);
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern string godot_icall_String_md5_text(string str);
-
/// <summary>
/// Perform a case-insensitive comparison to another string, return -1 if less, 0 if equal and +1 if greater.
/// </summary>
@@ -1244,12 +1254,11 @@ namespace Godot
/// <returns>The position at which the substring was found, or -1 if not found.</returns>
public static int RFind(this string instance, string what, int from = -1)
{
- return godot_icall_String_rfind(instance, what, from);
+ using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
+ using godot_string whatStr = Marshaling.ConvertStringToNative(instance);
+ return NativeFuncs.godotsharp_string_rfind(instanceStr, whatStr, from);
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern int godot_icall_String_rfind(string str, string what, int from);
-
/// <summary>
/// Perform a search for a substring, but start from the end of the string instead of the beginning.
/// Also search case-insensitive.
@@ -1261,12 +1270,11 @@ namespace Godot
/// <returns>The position at which the substring was found, or -1 if not found.</returns>
public static int RFindN(this string instance, string what, int from = -1)
{
- return godot_icall_String_rfindn(instance, what, from);
+ using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
+ using godot_string whatStr = Marshaling.ConvertStringToNative(instance);
+ return NativeFuncs.godotsharp_string_rfindn(instanceStr, whatStr, from);
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern int godot_icall_String_rfindn(string str, string what, int from);
-
/// <summary>
/// Returns the right side of the string from a given position.
/// </summary>
@@ -1321,12 +1329,12 @@ namespace Godot
/// <returns>The SHA-256 hash of the string.</returns>
public static byte[] SHA256Buffer(this string instance)
{
- return godot_icall_String_sha256_buffer(instance);
+ using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
+ NativeFuncs.godotsharp_string_sha256_buffer(instanceStr, out var sha256Buffer);
+ using (sha256Buffer)
+ return Marshaling.ConvertNativePackedByteArrayToSystemArray(sha256Buffer);
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern byte[] godot_icall_String_sha256_buffer(string str);
-
/// <summary>
/// Returns the SHA-256 hash of the string as a string.
/// </summary>
@@ -1335,12 +1343,12 @@ namespace Godot
/// <returns>The SHA-256 hash of the string.</returns>
public static string SHA256Text(this string instance)
{
- return godot_icall_String_sha256_text(instance);
+ using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
+ NativeFuncs.godotsharp_string_sha256_text(instanceStr, out var sha256Text);
+ using (sha256Text)
+ return Marshaling.ConvertStringToManaged(sha256Text);
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern string godot_icall_String_sha256_text(string str);
-
/// <summary>
/// Returns the similarity index of the text compared to this string.
/// 1 means totally similar and 0 means totally dissimilar.
@@ -1355,6 +1363,7 @@ namespace Godot
// Equal strings are totally similar
return 1.0f;
}
+
if (instance.Length < 2 || text.Length < 2)
{
// No way to calculate similarity without a single bigram
@@ -1390,12 +1399,12 @@ namespace Godot
/// </summary>
public static string SimplifyPath(this string instance)
{
- return godot_icall_String_simplify_path(instance);
+ using godot_string instanceStr = Marshaling.ConvertStringToNative(instance);
+ NativeFuncs.godotsharp_string_simplify_path(instanceStr, out godot_string simplifiedPath);
+ using (simplifiedPath)
+ return Marshaling.ConvertStringToManaged(simplifiedPath);
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern string godot_icall_String_simplify_path(string str);
-
/// <summary>
/// Split the string by a divisor string, return an array of the substrings.
/// Example "One,Two,Three" will return ["One","Two","Three"] if split by ",".
@@ -1409,7 +1418,8 @@ namespace Godot
/// <returns>The array of strings split from the string.</returns>
public static string[] Split(this string instance, string divisor, bool allowEmpty = true)
{
- return instance.Split(new[] { divisor }, allowEmpty ? StringSplitOptions.None : StringSplitOptions.RemoveEmptyEntries);
+ return instance.Split(new[] { divisor },
+ allowEmpty ? StringSplitOptions.None : StringSplitOptions.RemoveEmptyEntries);
}
/// <summary>
@@ -1605,9 +1615,9 @@ namespace Godot
/// <seealso cref="XMLEscape(string)"/>
/// <param name="instance">The string to unescape.</param>
/// <returns>The unescaped string.</returns>
- public static string XMLUnescape(this string instance)
+ public static string? XMLUnescape(this string instance)
{
- return SecurityElement.FromString(instance).Text;
+ return SecurityElement.FromString(instance)?.Text;
}
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs
index b1d504410b..b9ee0bc278 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/StringName.cs
@@ -1,5 +1,5 @@
using System;
-using System.Runtime.CompilerServices;
+using Godot.NativeInterop;
namespace Godot
{
@@ -10,20 +10,11 @@ namespace Godot
/// Comparing them is much faster than with regular strings, because only the pointers are compared,
/// not the whole strings.
/// </summary>
- public sealed partial class StringName : IDisposable
+ public sealed class StringName : IDisposable
{
- private IntPtr ptr;
+ internal godot_string_name.movable NativeValue;
- internal static IntPtr GetPtr(StringName instance)
- {
- if (instance == null)
- throw new NullReferenceException($"The instance of type {nameof(StringName)} is null.");
-
- if (instance.ptr == IntPtr.Zero)
- throw new ObjectDisposedException(instance.GetType().FullName);
-
- return instance.ptr;
- }
+ private WeakReference<IDisposable> _weakReferenceToSelf;
~StringName()
{
@@ -39,35 +30,45 @@ namespace Godot
GC.SuppressFinalize(this);
}
- private void Dispose(bool disposing)
+ public void Dispose(bool disposing)
{
- if (ptr != IntPtr.Zero)
+ // Always dispose `NativeValue` even if disposing is true
+ NativeValue.DangerousSelfRef.Dispose();
+
+ if (_weakReferenceToSelf != null)
{
- godot_icall_StringName_Dtor(ptr);
- ptr = IntPtr.Zero;
+ DisposablesTracker.UnregisterDisposable(_weakReferenceToSelf);
}
}
- internal StringName(IntPtr ptr)
+ private StringName(godot_string_name nativeValueToOwn)
{
- this.ptr = ptr;
+ NativeValue = (godot_string_name.movable)nativeValueToOwn;
+ _weakReferenceToSelf = DisposablesTracker.RegisterDisposable(this);
}
+ // Explicit name to make it very clear
+ internal static StringName CreateTakingOwnershipOfDisposableValue(godot_string_name nativeValueToOwn)
+ => new StringName(nativeValueToOwn);
+
/// <summary>
/// Constructs an empty <see cref="StringName"/>.
/// </summary>
public StringName()
{
- ptr = IntPtr.Zero;
}
/// <summary>
- /// Constructs a <see cref="StringName"/> from the given <paramref name="path"/> string.
+ /// Constructs a <see cref="StringName"/> from the given <paramref name="name"/> string.
/// </summary>
- /// <param name="path">String to construct the <see cref="StringName"/> from.</param>
- public StringName(string path)
+ /// <param name="name">String to construct the <see cref="StringName"/> from.</param>
+ public StringName(string name)
{
- ptr = path == null ? IntPtr.Zero : godot_icall_StringName_Ctor(path);
+ if (!string.IsNullOrEmpty(name))
+ {
+ NativeValue = (godot_string_name.movable)NativeFuncs.godotsharp_string_name_new_from_string(name);
+ _weakReferenceToSelf = DisposablesTracker.RegisterDisposable(this);
+ }
}
/// <summary>
@@ -80,7 +81,7 @@ namespace Godot
/// Converts a <see cref="StringName"/> to a string.
/// </summary>
/// <param name="from">The <see cref="StringName"/> to convert.</param>
- public static implicit operator string(StringName from) => from.ToString();
+ public static implicit operator string(StringName from) => from?.ToString();
/// <summary>
/// Converts this <see cref="StringName"/> to a string.
@@ -88,28 +89,75 @@ namespace Godot
/// <returns>A string representation of this <see cref="StringName"/>.</returns>
public override string ToString()
{
- return ptr == IntPtr.Zero ? string.Empty : godot_icall_StringName_operator_String(GetPtr(this));
+ if (IsEmpty)
+ return string.Empty;
+
+ var src = (godot_string_name)NativeValue;
+ NativeFuncs.godotsharp_string_name_as_string(out godot_string dest, src);
+ using (dest)
+ return Marshaling.ConvertStringToManaged(dest);
}
/// <summary>
/// Check whether this <see cref="StringName"/> is empty.
/// </summary>
/// <returns>If the <see cref="StringName"/> is empty.</returns>
- public bool IsEmpty()
+ public bool IsEmpty => NativeValue.DangerousSelfRef.IsEmpty;
+
+ public static bool operator ==(StringName left, StringName right)
{
- return ptr == IntPtr.Zero || godot_icall_StringName_is_empty(GetPtr(this));
+ if (left is null)
+ return right is null;
+ return left.Equals(right);
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern IntPtr godot_icall_StringName_Ctor(string path);
+ public static bool operator !=(StringName left, StringName right)
+ {
+ return !(left == right);
+ }
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern void godot_icall_StringName_Dtor(IntPtr ptr);
+ public bool Equals(StringName other)
+ {
+ if (other is null)
+ return false;
+ return NativeValue.DangerousSelfRef == other.NativeValue.DangerousSelfRef;
+ }
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern string godot_icall_StringName_operator_String(IntPtr ptr);
+ public static bool operator ==(StringName left, in godot_string_name right)
+ {
+ if (left is null)
+ return right.IsEmpty;
+ return left.Equals(right);
+ }
- [MethodImpl(MethodImplOptions.InternalCall)]
- private static extern bool godot_icall_StringName_is_empty(IntPtr ptr);
+ public static bool operator !=(StringName left, in godot_string_name right)
+ {
+ return !(left == right);
+ }
+
+ public static bool operator ==(in godot_string_name left, StringName right)
+ {
+ return right == left;
+ }
+
+ public static bool operator !=(in godot_string_name left, StringName right)
+ {
+ return !(right == left);
+ }
+
+ public bool Equals(in godot_string_name other)
+ {
+ return NativeValue.DangerousSelfRef == other;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return ReferenceEquals(this, obj) || (obj is StringName other && Equals(other));
+ }
+
+ public override int GetHashCode()
+ {
+ return NativeValue.GetHashCode();
+ }
}
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
index e01db7b88c..894667db76 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
@@ -1,8 +1,3 @@
-#if REAL_T_IS_DOUBLE
-using real_t = System.Double;
-#else
-using real_t = System.Single;
-#endif
using System;
using System.Runtime.InteropServices;
@@ -80,6 +75,9 @@ namespace Godot
/// The third column is the <see cref="origin"/> vector.
/// </summary>
/// <param name="column">Which column vector.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="column"/> is not 0, 1 or 2.
+ /// </exception>
public Vector2 this[int column]
{
get
@@ -93,7 +91,7 @@ namespace Godot
case 2:
return origin;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(column));
}
}
set
@@ -110,7 +108,7 @@ namespace Godot
origin = value;
return;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(column));
}
}
}
@@ -297,17 +295,33 @@ namespace Godot
}
/// <summary>
- /// Rotates the transform by <paramref name="angle"/> (in radians), using matrix multiplication.
+ /// Rotates the transform by <paramref name="angle"/> (in radians).
+ /// The operation is done in the parent/global frame, equivalent to
+ /// multiplying the matrix from the left.
/// </summary>
/// <param name="angle">The angle to rotate, in radians.</param>
/// <returns>The rotated transformation matrix.</returns>
- public Transform2D Rotated(real_t phi)
+ public Transform2D Rotated(real_t angle)
{
- return this * new Transform2D(phi, new Vector2());
+ return this * new Transform2D(angle, new Vector2());
}
/// <summary>
- /// Scales the transform by the given scaling factor, using matrix multiplication.
+ /// Rotates the transform by <paramref name="angle"/> (in radians).
+ /// The operation is done in the local frame, equivalent to
+ /// multiplying the matrix from the right.
+ /// </summary>
+ /// <param name="angle">The angle to rotate, in radians.</param>
+ /// <returns>The rotated transformation matrix.</returns>
+ public Transform2D RotatedLocal(real_t angle)
+ {
+ return new Transform2D(angle, new Vector2()) * this;
+ }
+
+ /// <summary>
+ /// Scales the transform by the given scaling factor.
+ /// The operation is done in the parent/global frame, equivalent to
+ /// multiplying the matrix from the left.
/// </summary>
/// <param name="scale">The scale to introduce.</param>
/// <returns>The scaled transformation matrix.</returns>
@@ -320,12 +334,19 @@ namespace Godot
return copy;
}
- private void ScaleBasis(Vector2 scale)
+ /// <summary>
+ /// Scales the transform by the given scaling factor.
+ /// The operation is done in the local frame, equivalent to
+ /// multiplying the matrix from the right.
+ /// </summary>
+ /// <param name="scale">The scale to introduce.</param>
+ /// <returns>The scaled transformation matrix.</returns>
+ public Transform2D ScaledLocal(Vector2 scale)
{
- x.x *= scale.x;
- x.y *= scale.y;
- y.x *= scale.x;
- y.y *= scale.y;
+ Transform2D copy = this;
+ copy.x *= scale;
+ copy.y *= scale;
+ return copy;
}
private real_t Tdotx(Vector2 with)
@@ -339,44 +360,31 @@ namespace Godot
}
/// <summary>
- /// Translates the transform by the given <paramref name="offset"/>,
- /// relative to the transform's basis vectors.
- ///
- /// Unlike <see cref="Rotated"/> and <see cref="Scaled"/>,
- /// this does not use matrix multiplication.
+ /// Translates the transform by the given <paramref name="offset"/>.
+ /// The operation is done in the parent/global frame, equivalent to
+ /// multiplying the matrix from the left.
/// </summary>
/// <param name="offset">The offset to translate by.</param>
/// <returns>The translated matrix.</returns>
- public Transform2D TranslatedLocal(Vector2 offset)
+ public Transform2D Translated(Vector2 offset)
{
Transform2D copy = this;
- copy.origin += copy.BasisXform(offset);
+ copy.origin += offset;
return copy;
}
/// <summary>
- /// Returns a vector transformed (multiplied) by this transformation matrix.
- /// </summary>
- /// <seealso cref="XformInv(Vector2)"/>
- /// <param name="v">A vector to transform.</param>
- /// <returns>The transformed vector.</returns>
- [Obsolete("Xform is deprecated. Use the multiplication operator (Transform2D * Vector2) instead.")]
- public Vector2 Xform(Vector2 v)
- {
- return new Vector2(Tdotx(v), Tdoty(v)) + origin;
- }
-
- /// <summary>
- /// Returns a vector transformed (multiplied) by the inverse transformation matrix.
+ /// Translates the transform by the given <paramref name="offset"/>.
+ /// The operation is done in the local frame, equivalent to
+ /// multiplying the matrix from the right.
/// </summary>
- /// <seealso cref="Xform(Vector2)"/>
- /// <param name="v">A vector to inversely transform.</param>
- /// <returns>The inversely transformed vector.</returns>
- [Obsolete("XformInv is deprecated. Use the multiplication operator (Vector2 * Transform2D) instead.")]
- public Vector2 XformInv(Vector2 v)
+ /// <param name="offset">The offset to translate by.</param>
+ /// <returns>The translated matrix.</returns>
+ public Transform2D TranslatedLocal(Vector2 offset)
{
- Vector2 vInv = v - origin;
- return new Vector2(x.Dot(vInv), y.Dot(vInv));
+ Transform2D copy = this;
+ copy.origin += copy.BasisXform(offset);
+ return copy;
}
// Constants
@@ -472,7 +480,7 @@ namespace Godot
}
/// <summary>
- /// Returns a Vector2 transformed (multiplied) by transformation matrix.
+ /// Returns a Vector2 transformed (multiplied) by the transformation matrix.
/// </summary>
/// <param name="transform">The transformation to apply.</param>
/// <param name="vector">A Vector2 to transform.</param>
@@ -495,7 +503,7 @@ namespace Godot
}
/// <summary>
- /// Returns a Rect2 transformed (multiplied) by transformation matrix.
+ /// Returns a Rect2 transformed (multiplied) by the transformation matrix.
/// </summary>
/// <param name="transform">The transformation to apply.</param>
/// <param name="rect">A Rect2 to transform.</param>
@@ -506,7 +514,7 @@ namespace Godot
Vector2 toX = transform.x * rect.Size.x;
Vector2 toY = transform.y * rect.Size.y;
- return new Rect2(pos, rect.Size).Expand(pos + toX).Expand(pos + toY).Expand(pos + toX + toY);
+ return new Rect2(pos, new Vector2()).Expand(pos + toX).Expand(pos + toY).Expand(pos + toX + toY);
}
/// <summary>
@@ -522,11 +530,11 @@ namespace Godot
Vector2 to2 = new Vector2(rect.Position.x + rect.Size.x, rect.Position.y + rect.Size.y) * transform;
Vector2 to3 = new Vector2(rect.Position.x + rect.Size.x, rect.Position.y) * transform;
- return new Rect2(pos, rect.Size).Expand(to1).Expand(to2).Expand(to3);
+ return new Rect2(pos, new Vector2()).Expand(to1).Expand(to2).Expand(to3);
}
/// <summary>
- /// Returns a copy of the given Vector2[] transformed (multiplied) by transformation matrix.
+ /// Returns a copy of the given Vector2[] transformed (multiplied) by the transformation matrix.
/// </summary>
/// <param name="transform">The transformation to apply.</param>
/// <param name="array">A Vector2[] to transform.</param>
@@ -597,7 +605,7 @@ namespace Godot
/// <returns>Whether or not the transform and the object are exactly equal.</returns>
public override bool Equals(object obj)
{
- return obj is Transform2D transform2D && Equals(transform2D);
+ return obj is Transform2D other && Equals(other);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
index 7f03a8930d..2f7891e7ef 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
@@ -1,8 +1,3 @@
-#if REAL_T_IS_DOUBLE
-using real_t = System.Double;
-#else
-using real_t = System.Single;
-#endif
using System;
using System.Runtime.InteropServices;
@@ -37,6 +32,9 @@ namespace Godot
/// The fourth column is the <see cref="origin"/> vector.
/// </summary>
/// <param name="column">Which column vector.</param>
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="column"/> is not 0, 1, 2 or 3.
+ /// </exception>
public Vector3 this[int column]
{
get
@@ -52,7 +50,7 @@ namespace Godot
case 3:
return origin;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(column));
}
}
set
@@ -72,7 +70,7 @@ namespace Godot
origin = value;
return;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(column));
}
}
}
@@ -113,7 +111,7 @@ namespace Godot
public Transform3D AffineInverse()
{
Basis basisInv = basis.Inverse();
- return new Transform3D(basisInv, basisInv.Xform(-origin));
+ return new Transform3D(basisInv, basisInv * -origin);
}
/// <summary>
@@ -124,23 +122,9 @@ namespace Godot
/// <returns>The interpolated transform.</returns>
public Transform3D InterpolateWith(Transform3D transform, real_t weight)
{
- /* not sure if very "efficient" but good enough? */
-
- Vector3 sourceScale = basis.Scale;
- Quaternion sourceRotation = basis.GetRotationQuaternion();
- Vector3 sourceLocation = origin;
-
- Vector3 destinationScale = transform.basis.Scale;
- Quaternion destinationRotation = transform.basis.GetRotationQuaternion();
- Vector3 destinationLocation = transform.origin;
-
- var interpolated = new Transform3D();
- Quaternion quaternion = sourceRotation.Slerp(destinationRotation, weight).Normalized();
- Vector3 scale = sourceScale.Lerp(destinationScale, weight);
- interpolated.basis.SetQuaternionScale(quaternion, scale);
- interpolated.origin = sourceLocation.Lerp(destinationLocation, weight);
-
- return interpolated;
+ Basis retBasis = basis.Lerp(transform.basis, weight);
+ Vector3 retOrigin = origin.Lerp(transform.origin, weight);
+ return new Transform3D(retBasis, retOrigin);
}
/// <summary>
@@ -152,7 +136,7 @@ namespace Godot
public Transform3D Inverse()
{
Basis basisTr = basis.Transposed();
- return new Transform3D(basisTr, basisTr.Xform(-origin));
+ return new Transform3D(basisTr, basisTr * -origin);
}
/// <summary>
@@ -168,7 +152,7 @@ namespace Godot
/// <param name="target">The object to look at.</param>
/// <param name="up">The relative up direction.</param>
/// <returns>The resulting transform.</returns>
- public Transform3D LookingAt(Vector3 target, Vector3 up)
+ public readonly Transform3D LookingAt(Vector3 target, Vector3 up)
{
Transform3D t = this;
t.SetLookAt(origin, target, up);
@@ -186,19 +170,38 @@ namespace Godot
}
/// <summary>
- /// Rotates the transform around the given <paramref name="axis"/> by <paramref name="angle"/> (in radians),
- /// using matrix multiplication. The axis must be a normalized vector.
+ /// Rotates the transform around the given <paramref name="axis"/> by <paramref name="angle"/> (in radians).
+ /// The axis must be a normalized vector.
+ /// The operation is done in the parent/global frame, equivalent to
+ /// multiplying the matrix from the left.
+ /// </summary>
+ /// <param name="axis">The axis to rotate around. Must be normalized.</param>
+ /// <param name="angle">The angle to rotate, in radians.</param>
+ /// <returns>The rotated transformation matrix.</returns>
+ public readonly Transform3D Rotated(Vector3 axis, real_t angle)
+ {
+ return new Transform3D(new Basis(axis, angle), new Vector3()) * this;
+ }
+
+ /// <summary>
+ /// Rotates the transform around the given <paramref name="axis"/> by <paramref name="angle"/> (in radians).
+ /// The axis must be a normalized vector.
+ /// The operation is done in the local frame, equivalent to
+ /// multiplying the matrix from the right.
/// </summary>
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
/// <param name="angle">The angle to rotate, in radians.</param>
/// <returns>The rotated transformation matrix.</returns>
- public Transform3D Rotated(Vector3 axis, real_t phi)
+ public Transform3D RotatedLocal(Vector3 axis, real_t angle)
{
- return new Transform3D(new Basis(axis, phi), new Vector3()) * this;
+ Basis tmpBasis = new Basis(axis, angle);
+ return new Transform3D(basis * tmpBasis, origin);
}
/// <summary>
- /// Scales the transform by the given 3D scaling factor, using matrix multiplication.
+ /// Scales the transform by the given 3D <paramref name="scale"/> factor.
+ /// The operation is done in the parent/global frame, equivalent to
+ /// multiplying the matrix from the left.
/// </summary>
/// <param name="scale">The scale to introduce.</param>
/// <returns>The scaled transformation matrix.</returns>
@@ -207,6 +210,47 @@ namespace Godot
return new Transform3D(basis.Scaled(scale), origin * scale);
}
+ /// <summary>
+ /// Scales the transform by the given 3D <paramref name="scale"/> factor.
+ /// The operation is done in the local frame, equivalent to
+ /// multiplying the matrix from the right.
+ /// </summary>
+ /// <param name="scale">The scale to introduce.</param>
+ /// <returns>The scaled transformation matrix.</returns>
+ public Transform3D ScaledLocal(Vector3 scale)
+ {
+ Basis tmpBasis = Basis.FromScale(scale);
+ return new Transform3D(basis * tmpBasis, origin);
+ }
+
+ /// <summary>
+ /// Returns a transform spherically interpolated between this transform and
+ /// another <paramref name="transform"/> by <paramref name="weight"/>.
+ /// </summary>
+ /// <param name="transform">The other transform.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <returns>The interpolated transform.</returns>
+ public Transform3D SphericalInterpolateWith(Transform3D transform, real_t weight)
+ {
+ /* not sure if very "efficient" but good enough? */
+
+ Vector3 sourceScale = basis.Scale;
+ Quaternion sourceRotation = basis.GetRotationQuaternion();
+ Vector3 sourceLocation = origin;
+
+ Vector3 destinationScale = transform.basis.Scale;
+ Quaternion destinationRotation = transform.basis.GetRotationQuaternion();
+ Vector3 destinationLocation = transform.origin;
+
+ var interpolated = new Transform3D();
+ Quaternion quaternion = sourceRotation.Slerp(destinationRotation, weight).Normalized();
+ Vector3 scale = sourceScale.Lerp(destinationScale, weight);
+ interpolated.basis.SetQuaternionScale(quaternion, scale);
+ interpolated.origin = sourceLocation.Lerp(destinationLocation, weight);
+
+ return interpolated;
+ }
+
private void SetLookAt(Vector3 eye, Vector3 target, Vector3 up)
{
// Make rotation matrix
@@ -231,11 +275,21 @@ namespace Godot
}
/// <summary>
- /// Translates the transform by the given <paramref name="offset"/>,
- /// relative to the transform's basis vectors.
- ///
- /// Unlike <see cref="Rotated"/> and <see cref="Scaled"/>,
- /// this does not use matrix multiplication.
+ /// Translates the transform by the given <paramref name="offset"/>.
+ /// The operation is done in the parent/global frame, equivalent to
+ /// multiplying the matrix from the left.
+ /// </summary>
+ /// <param name="offset">The offset to translate by.</param>
+ /// <returns>The translated matrix.</returns>
+ public Transform3D Translated(Vector3 offset)
+ {
+ return new Transform3D(basis, origin + offset);
+ }
+
+ /// <summary>
+ /// Translates the transform by the given <paramref name="offset"/>.
+ /// The operation is done in the local frame, equivalent to
+ /// multiplying the matrix from the right.
/// </summary>
/// <param name="offset">The offset to translate by.</param>
/// <returns>The translated matrix.</returns>
@@ -249,43 +303,6 @@ namespace Godot
));
}
- /// <summary>
- /// Returns a vector transformed (multiplied) by this transformation matrix.
- /// </summary>
- /// <seealso cref="XformInv(Vector3)"/>
- /// <param name="v">A vector to transform.</param>
- /// <returns>The transformed vector.</returns>
- public Vector3 Xform(Vector3 v)
- {
- return new Vector3
- (
- basis.Row0.Dot(v) + origin.x,
- basis.Row1.Dot(v) + origin.y,
- basis.Row2.Dot(v) + origin.z
- );
- }
-
- /// <summary>
- /// Returns a vector transformed (multiplied) by the transposed transformation matrix.
- ///
- /// Note: This results in a multiplication by the inverse of the
- /// transformation matrix only if it represents a rotation-reflection.
- /// </summary>
- /// <seealso cref="Xform(Vector3)"/>
- /// <param name="v">A vector to inversely transform.</param>
- /// <returns>The inversely transformed vector.</returns>
- public Vector3 XformInv(Vector3 v)
- {
- Vector3 vInv = v - origin;
-
- return new Vector3
- (
- (basis.Row0[0] * vInv.x) + (basis.Row1[0] * vInv.y) + (basis.Row2[0] * vInv.z),
- (basis.Row0[1] * vInv.x) + (basis.Row1[1] * vInv.y) + (basis.Row2[1] * vInv.z),
- (basis.Row0[2] * vInv.x) + (basis.Row1[2] * vInv.y) + (basis.Row2[2] * vInv.z)
- );
- }
-
// Constants
private static readonly Transform3D _identity = new Transform3D(Basis.Identity, Vector3.Zero);
private static readonly Transform3D _flipX = new Transform3D(new Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1), Vector3.Zero);
@@ -362,12 +379,188 @@ namespace Godot
/// <returns>The composed transform.</returns>
public static Transform3D operator *(Transform3D left, Transform3D right)
{
- left.origin = left.Xform(right.origin);
+ left.origin = left * right.origin;
left.basis *= right.basis;
return left;
}
/// <summary>
+ /// Returns a Vector3 transformed (multiplied) by the transformation matrix.
+ /// </summary>
+ /// <param name="transform">The transformation to apply.</param>
+ /// <param name="vector">A Vector3 to transform.</param>
+ /// <returns>The transformed Vector3.</returns>
+ public static Vector3 operator *(Transform3D transform, Vector3 vector)
+ {
+ return new Vector3
+ (
+ transform.basis.Row0.Dot(vector) + transform.origin.x,
+ transform.basis.Row1.Dot(vector) + transform.origin.y,
+ transform.basis.Row2.Dot(vector) + transform.origin.z
+ );
+ }
+
+ /// <summary>
+ /// Returns a Vector3 transformed (multiplied) by the transposed transformation matrix.
+ ///
+ /// Note: This results in a multiplication by the inverse of the
+ /// transformation matrix only if it represents a rotation-reflection.
+ /// </summary>
+ /// <param name="vector">A Vector3 to inversely transform.</param>
+ /// <param name="transform">The transformation to apply.</param>
+ /// <returns>The inversely transformed Vector3.</returns>
+ public static Vector3 operator *(Vector3 vector, Transform3D transform)
+ {
+ Vector3 vInv = vector - transform.origin;
+
+ return new Vector3
+ (
+ (transform.basis.Row0[0] * vInv.x) + (transform.basis.Row1[0] * vInv.y) + (transform.basis.Row2[0] * vInv.z),
+ (transform.basis.Row0[1] * vInv.x) + (transform.basis.Row1[1] * vInv.y) + (transform.basis.Row2[1] * vInv.z),
+ (transform.basis.Row0[2] * vInv.x) + (transform.basis.Row1[2] * vInv.y) + (transform.basis.Row2[2] * vInv.z)
+ );
+ }
+
+ /// <summary>
+ /// Returns an AABB transformed (multiplied) by the transformation matrix.
+ /// </summary>
+ /// <param name="transform">The transformation to apply.</param>
+ /// <param name="aabb">An AABB to transform.</param>
+ /// <returns>The transformed AABB.</returns>
+ public static AABB operator *(Transform3D transform, AABB aabb)
+ {
+ Vector3 min = aabb.Position;
+ Vector3 max = aabb.Position + aabb.Size;
+
+ Vector3 tmin = transform.origin;
+ Vector3 tmax = transform.origin;
+ for (int i = 0; i < 3; i++)
+ {
+ for (int j = 0; j < 3; j++)
+ {
+ real_t e = transform.basis[i][j] * min[j];
+ real_t f = transform.basis[i][j] * max[j];
+ if (e < f)
+ {
+ tmin[i] += e;
+ tmax[i] += f;
+ }
+ else
+ {
+ tmin[i] += f;
+ tmax[i] += e;
+ }
+ }
+ }
+
+ return new AABB(tmin, tmax - tmin);
+ }
+
+ /// <summary>
+ /// Returns an AABB transformed (multiplied) by the inverse transformation matrix.
+ /// </summary>
+ /// <param name="aabb">An AABB to inversely transform.</param>
+ /// <param name="transform">The transformation to apply.</param>
+ /// <returns>The inversely transformed AABB.</returns>
+ public static AABB operator *(AABB aabb, Transform3D transform)
+ {
+ Vector3 pos = new Vector3(aabb.Position.x + aabb.Size.x, aabb.Position.y + aabb.Size.y, aabb.Position.z + aabb.Size.z) * transform;
+ Vector3 to1 = new Vector3(aabb.Position.x + aabb.Size.x, aabb.Position.y + aabb.Size.y, aabb.Position.z) * transform;
+ Vector3 to2 = new Vector3(aabb.Position.x + aabb.Size.x, aabb.Position.y, aabb.Position.z + aabb.Size.z) * transform;
+ Vector3 to3 = new Vector3(aabb.Position.x + aabb.Size.x, aabb.Position.y, aabb.Position.z) * transform;
+ Vector3 to4 = new Vector3(aabb.Position.x, aabb.Position.y + aabb.Size.y, aabb.Position.z + aabb.Size.z) * transform;
+ Vector3 to5 = new Vector3(aabb.Position.x, aabb.Position.y + aabb.Size.y, aabb.Position.z) * transform;
+ Vector3 to6 = new Vector3(aabb.Position.x, aabb.Position.y, aabb.Position.z + aabb.Size.z) * transform;
+ Vector3 to7 = new Vector3(aabb.Position.x, aabb.Position.y, aabb.Position.z) * transform;
+
+ return new AABB(pos, new Vector3()).Expand(to1).Expand(to2).Expand(to3).Expand(to4).Expand(to5).Expand(to6).Expand(to7);
+ }
+
+ /// <summary>
+ /// Returns a Plane transformed (multiplied) by the transformation matrix.
+ /// </summary>
+ /// <param name="transform">The transformation to apply.</param>
+ /// <param name="plane">A Plane to transform.</param>
+ /// <returns>The transformed Plane.</returns>
+ public static Plane operator *(Transform3D transform, Plane plane)
+ {
+ Basis bInvTrans = transform.basis.Inverse().Transposed();
+
+ // Transform a single point on the plane.
+ Vector3 point = transform * (plane.Normal * plane.D);
+
+ // Use inverse transpose for correct normals with non-uniform scaling.
+ Vector3 normal = (bInvTrans * plane.Normal).Normalized();
+
+ real_t d = normal.Dot(point);
+ return new Plane(normal, d);
+ }
+
+ /// <summary>
+ /// Returns a Plane transformed (multiplied) by the inverse transformation matrix.
+ /// </summary>
+ /// <param name="plane">A Plane to inversely transform.</param>
+ /// <param name="transform">The transformation to apply.</param>
+ /// <returns>The inversely transformed Plane.</returns>
+ public static Plane operator *(Plane plane, Transform3D transform)
+ {
+ Transform3D tInv = transform.AffineInverse();
+ Basis bTrans = transform.basis.Transposed();
+
+ // Transform a single point on the plane.
+ Vector3 point = tInv * (plane.Normal * plane.D);
+
+ // Note that instead of precalculating the transpose, an alternative
+ // would be to use the transpose for the basis transform.
+ // However that would be less SIMD friendly (requiring a swizzle).
+ // So the cost is one extra precalced value in the calling code.
+ // This is probably worth it, as this could be used in bottleneck areas. And
+ // where it is not a bottleneck, the non-fast method is fine.
+
+ // Use transpose for correct normals with non-uniform scaling.
+ Vector3 normal = (bTrans * plane.Normal).Normalized();
+
+ real_t d = normal.Dot(point);
+ return new Plane(normal, d);
+ }
+
+ /// <summary>
+ /// Returns a copy of the given Vector3[] transformed (multiplied) by the transformation matrix.
+ /// </summary>
+ /// <param name="transform">The transformation to apply.</param>
+ /// <param name="array">A Vector3[] to transform.</param>
+ /// <returns>The transformed copy of the Vector3[].</returns>
+ public static Vector3[] operator *(Transform3D transform, Vector3[] array)
+ {
+ Vector3[] newArray = new Vector3[array.Length];
+
+ for (int i = 0; i < array.Length; i++)
+ {
+ newArray[i] = transform * array[i];
+ }
+
+ return newArray;
+ }
+
+ /// <summary>
+ /// Returns a copy of the given Vector3[] transformed (multiplied) by the inverse transformation matrix.
+ /// </summary>
+ /// <param name="array">A Vector3[] to inversely transform.</param>
+ /// <param name="transform">The transformation to apply.</param>
+ /// <returns>The inversely transformed copy of the Vector3[].</returns>
+ public static Vector3[] operator *(Vector3[] array, Transform3D transform)
+ {
+ Vector3[] newArray = new Vector3[array.Length];
+
+ for (int i = 0; i < array.Length; i++)
+ {
+ newArray[i] = array[i] * transform;
+ }
+
+ return newArray;
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if the transforms are exactly equal.
/// Note: Due to floating-point precision errors, consider using
/// <see cref="IsEqualApprox"/> instead, which is more reliable.
@@ -401,14 +594,9 @@ namespace Godot
/// </summary>
/// <param name="obj">The object to compare with.</param>
/// <returns>Whether or not the transform and the object are exactly equal.</returns>
- public override bool Equals(object obj)
+ public override readonly bool Equals(object obj)
{
- if (obj is Transform3D)
- {
- return Equals((Transform3D)obj);
- }
-
- return false;
+ return obj is Transform3D other && Equals(other);
}
/// <summary>
@@ -418,7 +606,7 @@ namespace Godot
/// </summary>
/// <param name="other">The other transform to compare.</param>
/// <returns>Whether or not the matrices are exactly equal.</returns>
- public bool Equals(Transform3D other)
+ public readonly bool Equals(Transform3D other)
{
return basis.Equals(other.basis) && origin.Equals(other.origin);
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/UnhandledExceptionArgs.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/UnhandledExceptionArgs.cs
deleted file mode 100644
index eae8927ceb..0000000000
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/UnhandledExceptionArgs.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System;
-
-namespace Godot
-{
- /// <summary>
- /// Event arguments for when unhandled exceptions occur.
- /// </summary>
- public class UnhandledExceptionArgs
- {
- /// <summary>
- /// Exception object.
- /// </summary>
- public Exception Exception { get; private set; }
-
- internal UnhandledExceptionArgs(Exception exception)
- {
- Exception = exception;
- }
- }
-}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
index 7bdbe1c28b..87f397891e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
@@ -1,8 +1,3 @@
-#if REAL_T_IS_DOUBLE
-using real_t = System.Double;
-#else
-using real_t = System.Single;
-#endif
using System;
using System.Runtime.InteropServices;
@@ -44,8 +39,8 @@ namespace Godot
/// <summary>
/// Access vector components using their index.
/// </summary>
- /// <exception cref="IndexOutOfRangeException">
- /// Thrown when the given the <paramref name="index"/> is not 0 or 1.
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is not 0 or 1.
/// </exception>
/// <value>
/// <c>[0]</c> is equivalent to <see cref="x"/>,
@@ -62,7 +57,7 @@ namespace Godot
case 1:
return y;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
set
@@ -76,7 +71,7 @@ namespace Godot
y = value;
return;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
}
@@ -221,6 +216,29 @@ namespace Godot
}
/// <summary>
+ /// Performs a cubic interpolation between vectors <paramref name="preA"/>, this vector,
+ /// <paramref name="b"/>, and <paramref name="postB"/>, by the given amount <paramref name="weight"/>.
+ /// It can perform smoother interpolation than <see cref="CubicInterpolate"/>
+ /// by the time values.
+ /// </summary>
+ /// <param name="b">The destination vector.</param>
+ /// <param name="preA">A vector before this vector.</param>
+ /// <param name="postB">A vector after <paramref name="b"/>.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <param name="t"></param>
+ /// <param name="preAT"></param>
+ /// <param name="postBT"></param>
+ /// <returns>The interpolated vector.</returns>
+ public Vector2 CubicInterpolateInTime(Vector2 b, Vector2 preA, Vector2 postB, real_t weight, real_t t, real_t preAT, real_t postBT)
+ {
+ return new Vector2
+ (
+ Mathf.CubicInterpolateInTime(x, b.x, preA.x, postB.x, weight, t, preAT, postBT),
+ Mathf.CubicInterpolateInTime(y, b.y, preA.y, postB.y, weight, t, preAT, postBT)
+ );
+ }
+
+ /// <summary>
/// Returns the point at the given <paramref name="t"/> on a one-dimensional Bezier curve defined by this vector
/// and the given <paramref name="control1"/>, <paramref name="control2"/> and <paramref name="end"/> points.
/// </summary>
@@ -484,7 +502,7 @@ namespace Godot
#if DEBUG
if (!normal.IsNormalized())
{
- throw new ArgumentException("Argument is not normalized", nameof(normal));
+ throw new ArgumentException("Argument is not normalized.", nameof(normal));
}
#endif
return (2 * Dot(normal) * normal) - this;
@@ -495,10 +513,10 @@ namespace Godot
/// </summary>
/// <param name="angle">The angle to rotate by, in radians.</param>
/// <returns>The rotated vector.</returns>
- public Vector2 Rotated(real_t phi)
+ public Vector2 Rotated(real_t angle)
{
- real_t sine = Mathf.Sin(phi);
- real_t cosi = Mathf.Cos(phi);
+ real_t sine = Mathf.Sin(angle);
+ real_t cosi = Mathf.Cos(angle);
return new Vector2(
x * cosi - y * sine,
x * sine + y * cosi);
@@ -534,7 +552,7 @@ namespace Godot
///
/// This method also handles interpolating the lengths if the input vectors
/// have different lengths. For the special case of one or both input vectors
- /// having zero length, this method behaves like <see cref="Lerp"/>.
+ /// having zero length, this method behaves like <see cref="Lerp(Vector2, real_t)"/>.
/// </summary>
/// <param name="to">The destination vector for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
@@ -644,16 +662,6 @@ namespace Godot
}
/// <summary>
- /// Constructs a new <see cref="Vector2"/> from an existing <see cref="Vector2"/>.
- /// </summary>
- /// <param name="v">The existing <see cref="Vector2"/>.</param>
- public Vector2(Vector2 v)
- {
- x = v.x;
- y = v.y;
- }
-
- /// <summary>
/// Creates a unit Vector2 rotated to the given angle. This is equivalent to doing
/// <c>Vector2(Mathf.Cos(angle), Mathf.Sin(angle))</c> or <c>Vector2.Right.Rotated(angle)</c>.
/// </summary>
@@ -940,11 +948,7 @@ namespace Godot
/// <returns>Whether or not the vector and the object are equal.</returns>
public override bool Equals(object obj)
{
- if (obj is Vector2)
- {
- return Equals((Vector2)obj);
- }
- return false;
+ return obj is Vector2 other && Equals(other);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
index b61954a84c..bdadf696e3 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
@@ -1,8 +1,3 @@
-#if REAL_T_IS_DOUBLE
-using real_t = System.Double;
-#else
-using real_t = System.Single;
-#endif
using System;
using System.Runtime.InteropServices;
@@ -44,8 +39,8 @@ namespace Godot
/// <summary>
/// Access vector components using their index.
/// </summary>
- /// <exception cref="IndexOutOfRangeException">
- /// Thrown when the given the <paramref name="index"/> is not 0 or 1.
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is not 0 or 1.
/// </exception>
/// <value>
/// <c>[0]</c> is equivalent to <see cref="x"/>,
@@ -62,7 +57,7 @@ namespace Godot
case 1:
return y;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
set
@@ -76,7 +71,7 @@ namespace Godot
y = value;
return;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
}
@@ -355,27 +350,6 @@ namespace Godot
}
/// <summary>
- /// Constructs a new <see cref="Vector2i"/> from an existing <see cref="Vector2i"/>.
- /// </summary>
- /// <param name="vi">The existing <see cref="Vector2i"/>.</param>
- public Vector2i(Vector2i vi)
- {
- this.x = vi.x;
- this.y = vi.y;
- }
-
- /// <summary>
- /// Constructs a new <see cref="Vector2i"/> from an existing <see cref="Vector2"/>
- /// by rounding the components via <see cref="Mathf.RoundToInt(real_t)"/>.
- /// </summary>
- /// <param name="v">The <see cref="Vector2"/> to convert.</param>
- public Vector2i(Vector2 v)
- {
- this.x = Mathf.RoundToInt(v.x);
- this.y = Mathf.RoundToInt(v.y);
- }
-
- /// <summary>
/// Adds each component of the <see cref="Vector2i"/>
/// with the components of the given <see cref="Vector2i"/>.
/// </summary>
@@ -679,7 +653,10 @@ namespace Godot
/// <param name="value">The vector to convert.</param>
public static explicit operator Vector2i(Vector2 value)
{
- return new Vector2i(value);
+ return new Vector2i(
+ Mathf.RoundToInt(value.x),
+ Mathf.RoundToInt(value.y)
+ );
}
/// <summary>
@@ -690,12 +667,7 @@ namespace Godot
/// <returns>Whether or not the vector and the object are equal.</returns>
public override bool Equals(object obj)
{
- if (obj is Vector2i)
- {
- return Equals((Vector2i)obj);
- }
-
- return false;
+ return obj is Vector2i other && Equals(other);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
index 480165d44a..6649f3b784 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
@@ -1,8 +1,3 @@
-#if REAL_T_IS_DOUBLE
-using real_t = System.Double;
-#else
-using real_t = System.Single;
-#endif
using System;
using System.Runtime.InteropServices;
@@ -53,8 +48,8 @@ namespace Godot
/// <summary>
/// Access vector components using their index.
/// </summary>
- /// <exception cref="IndexOutOfRangeException">
- /// Thrown when the given the <paramref name="index"/> is not 0, 1 or 2.
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is not 0, 1 or 2.
/// </exception>
/// <value>
/// <c>[0]</c> is equivalent to <see cref="x"/>,
@@ -74,7 +69,7 @@ namespace Godot
case 2:
return z;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
set
@@ -91,7 +86,7 @@ namespace Godot
z = value;
return;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
}
@@ -214,6 +209,30 @@ namespace Godot
}
/// <summary>
+ /// Performs a cubic interpolation between vectors <paramref name="preA"/>, this vector,
+ /// <paramref name="b"/>, and <paramref name="postB"/>, by the given amount <paramref name="weight"/>.
+ /// It can perform smoother interpolation than <see cref="CubicInterpolate"/>
+ /// by the time values.
+ /// </summary>
+ /// <param name="b">The destination vector.</param>
+ /// <param name="preA">A vector before this vector.</param>
+ /// <param name="postB">A vector after <paramref name="b"/>.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <param name="t"></param>
+ /// <param name="preAT"></param>
+ /// <param name="postBT"></param>
+ /// <returns>The interpolated vector.</returns>
+ public Vector3 CubicInterpolateInTime(Vector3 b, Vector3 preA, Vector3 postB, real_t weight, real_t t, real_t preAT, real_t postBT)
+ {
+ return new Vector3
+ (
+ Mathf.CubicInterpolateInTime(x, b.x, preA.x, postB.x, weight, t, preAT, postBT),
+ Mathf.CubicInterpolateInTime(y, b.y, preA.y, postB.y, weight, t, preAT, postBT),
+ Mathf.CubicInterpolateInTime(z, b.z, preA.z, postB.z, weight, t, preAT, postBT)
+ );
+ }
+
+ /// <summary>
/// Returns the point at the given <paramref name="t"/> on a one-dimensional Bezier curve defined by this vector
/// and the given <paramref name="control1"/>, <paramref name="control2"/> and <paramref name="end"/> points.
/// </summary>
@@ -502,7 +521,7 @@ namespace Godot
#if DEBUG
if (!normal.IsNormalized())
{
- throw new ArgumentException("Argument is not normalized", nameof(normal));
+ throw new ArgumentException("Argument is not normalized.", nameof(normal));
}
#endif
return (2.0f * Dot(normal) * normal) - this;
@@ -515,15 +534,15 @@ namespace Godot
/// <param name="axis">The vector to rotate around. Must be normalized.</param>
/// <param name="angle">The angle to rotate by, in radians.</param>
/// <returns>The rotated vector.</returns>
- public Vector3 Rotated(Vector3 axis, real_t phi)
+ public Vector3 Rotated(Vector3 axis, real_t angle)
{
#if DEBUG
if (!axis.IsNormalized())
{
- throw new ArgumentException("Argument is not normalized", nameof(axis));
+ throw new ArgumentException("Argument is not normalized.", nameof(axis));
}
#endif
- return new Basis(axis, phi).Xform(this);
+ return new Basis(axis, angle) * this;
}
/// <summary>
@@ -574,7 +593,7 @@ namespace Godot
///
/// This method also handles interpolating the lengths if the input vectors
/// have different lengths. For the special case of one or both input vectors
- /// having zero length, this method behaves like <see cref="Lerp"/>.
+ /// having zero length, this method behaves like <see cref="Lerp(Vector3, real_t)"/>.
/// </summary>
/// <param name="to">The destination vector for interpolation.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
@@ -620,22 +639,6 @@ namespace Godot
);
}
- /// <summary>
- /// Returns a diagonal matrix with the vector as main diagonal.
- ///
- /// This is equivalent to a <see cref="Basis"/> with no rotation or shearing and
- /// this vector's components set as the scale.
- /// </summary>
- /// <returns>A <see cref="Basis"/> with the vector as its main diagonal.</returns>
- public Basis ToDiagonalMatrix()
- {
- return new Basis(
- x, 0, 0,
- 0, y, 0,
- 0, 0, z
- );
- }
-
// Constants
private static readonly Vector3 _zero = new Vector3(0, 0, 0);
private static readonly Vector3 _one = new Vector3(1, 1, 1);
@@ -713,17 +716,6 @@ namespace Godot
}
/// <summary>
- /// Constructs a new <see cref="Vector3"/> from an existing <see cref="Vector3"/>.
- /// </summary>
- /// <param name="v">The existing <see cref="Vector3"/>.</param>
- public Vector3(Vector3 v)
- {
- x = v.x;
- y = v.y;
- z = v.z;
- }
-
- /// <summary>
/// Adds each component of the <see cref="Vector3"/>
/// with the components of the given <see cref="Vector3"/>.
/// </summary>
@@ -1025,12 +1017,7 @@ namespace Godot
/// <returns>Whether or not the vector and the object are equal.</returns>
public override bool Equals(object obj)
{
- if (obj is Vector3)
- {
- return Equals((Vector3)obj);
- }
-
- return false;
+ return obj is Vector3 other && Equals(other);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs
index 0d4894f206..e88a043cb3 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs
@@ -1,8 +1,3 @@
-#if REAL_T_IS_DOUBLE
-using real_t = System.Double;
-#else
-using real_t = System.Single;
-#endif
using System;
using System.Runtime.InteropServices;
@@ -53,8 +48,8 @@ namespace Godot
/// <summary>
/// Access vector components using their <paramref name="index"/>.
/// </summary>
- /// <exception cref="IndexOutOfRangeException">
- /// Thrown when the given the <paramref name="index"/> is not 0, 1 or 2.
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is not 0, 1 or 2.
/// </exception>
/// <value>
/// <c>[0]</c> is equivalent to <see cref="x"/>,
@@ -74,7 +69,7 @@ namespace Godot
case 2:
return z;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
set
@@ -91,7 +86,7 @@ namespace Godot
z = value;
return;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
}
@@ -335,29 +330,6 @@ namespace Godot
}
/// <summary>
- /// Constructs a new <see cref="Vector3i"/> from an existing <see cref="Vector3i"/>.
- /// </summary>
- /// <param name="vi">The existing <see cref="Vector3i"/>.</param>
- public Vector3i(Vector3i vi)
- {
- this.x = vi.x;
- this.y = vi.y;
- this.z = vi.z;
- }
-
- /// <summary>
- /// Constructs a new <see cref="Vector3i"/> from an existing <see cref="Vector3"/>
- /// by rounding the components via <see cref="Mathf.RoundToInt(real_t)"/>.
- /// </summary>
- /// <param name="v">The <see cref="Vector3"/> to convert.</param>
- public Vector3i(Vector3 v)
- {
- this.x = Mathf.RoundToInt(v.x);
- this.y = Mathf.RoundToInt(v.y);
- this.z = Mathf.RoundToInt(v.z);
- }
-
- /// <summary>
/// Adds each component of the <see cref="Vector3i"/>
/// with the components of the given <see cref="Vector3i"/>.
/// </summary>
@@ -689,7 +661,11 @@ namespace Godot
/// <param name="value">The vector to convert.</param>
public static explicit operator Vector3i(Vector3 value)
{
- return new Vector3i(value);
+ return new Vector3i(
+ Mathf.RoundToInt(value.x),
+ Mathf.RoundToInt(value.y),
+ Mathf.RoundToInt(value.z)
+ );
}
/// <summary>
@@ -700,12 +676,7 @@ namespace Godot
/// <returns>Whether or not the vector and the object are equal.</returns>
public override bool Equals(object obj)
{
- if (obj is Vector3i)
- {
- return Equals((Vector3i)obj);
- }
-
- return false;
+ return obj is Vector3i other && Equals(other);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
index 72fe9cb16f..d1962c68cf 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
@@ -1,8 +1,3 @@
-#if REAL_T_IS_DOUBLE
-using real_t = System.Double;
-#else
-using real_t = System.Single;
-#endif
using System;
using System.Runtime.InteropServices;
@@ -62,8 +57,8 @@ namespace Godot
/// <summary>
/// Access vector components using their index.
/// </summary>
- /// <exception cref="IndexOutOfRangeException">
- /// Thrown when the given the <paramref name="index"/> is not 0, 1, 2 or 3.
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is not 0, 1, 2 or 3.
/// </exception>
/// <value>
/// <c>[0]</c> is equivalent to <see cref="x"/>,
@@ -86,7 +81,7 @@ namespace Godot
case 3:
return w;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
set
@@ -106,7 +101,7 @@ namespace Godot
w = value;
return;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
}
@@ -140,7 +135,6 @@ namespace Godot
}
}
-
/// <summary>
/// Returns a new vector with all components in absolute values (i.e. positive).
/// </summary>
@@ -178,16 +172,84 @@ namespace Godot
);
}
+ /// <summary>
+ /// Performs a cubic interpolation between vectors <paramref name="preA"/>, this vector,
+ /// <paramref name="b"/>, and <paramref name="postB"/>, by the given amount <paramref name="weight"/>.
+ /// </summary>
+ /// <param name="b">The destination vector.</param>
+ /// <param name="preA">A vector before this vector.</param>
+ /// <param name="postB">A vector after <paramref name="b"/>.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <returns>The interpolated vector.</returns>
+ public Vector4 CubicInterpolate(Vector4 b, Vector4 preA, Vector4 postB, real_t weight)
+ {
+ return new Vector4
+ (
+ Mathf.CubicInterpolate(x, b.x, preA.x, postB.x, weight),
+ Mathf.CubicInterpolate(y, b.y, preA.y, postB.y, weight),
+ Mathf.CubicInterpolate(y, b.z, preA.z, postB.z, weight),
+ Mathf.CubicInterpolate(w, b.w, preA.w, postB.w, weight)
+ );
+ }
/// <summary>
- /// Returns a new vector with all components rounded down (towards negative infinity).
+ /// Performs a cubic interpolation between vectors <paramref name="preA"/>, this vector,
+ /// <paramref name="b"/>, and <paramref name="postB"/>, by the given amount <paramref name="weight"/>.
+ /// It can perform smoother interpolation than <see cref="CubicInterpolate"/>
+ /// by the time values.
/// </summary>
- /// <returns>A vector with <see cref="Mathf.Floor"/> called on each component.</returns>
- public Vector4 Floor()
+ /// <param name="b">The destination vector.</param>
+ /// <param name="preA">A vector before this vector.</param>
+ /// <param name="postB">A vector after <paramref name="b"/>.</param>
+ /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
+ /// <param name="t"></param>
+ /// <param name="preAT"></param>
+ /// <param name="postBT"></param>
+ /// <returns>The interpolated vector.</returns>
+ public Vector4 CubicInterpolateInTime(Vector4 b, Vector4 preA, Vector4 postB, real_t weight, real_t t, real_t preAT, real_t postBT)
{
- return new Vector4(Mathf.Floor(x), Mathf.Floor(y), Mathf.Floor(z), Mathf.Floor(w));
+ return new Vector4
+ (
+ Mathf.CubicInterpolateInTime(x, b.x, preA.x, postB.x, weight, t, preAT, postBT),
+ Mathf.CubicInterpolateInTime(y, b.y, preA.y, postB.y, weight, t, preAT, postBT),
+ Mathf.CubicInterpolateInTime(y, b.z, preA.z, postB.z, weight, t, preAT, postBT),
+ Mathf.CubicInterpolateInTime(w, b.w, preA.w, postB.w, weight, t, preAT, postBT)
+ );
}
+ /// <summary>
+ /// Returns the normalized vector pointing from this vector to <paramref name="to"/>.
+ /// </summary>
+ /// <param name="to">The other vector to point towards.</param>
+ /// <returns>The direction from this vector to <paramref name="to"/>.</returns>
+ public Vector4 DirectionTo(Vector4 to)
+ {
+ Vector4 ret = new Vector4(to.x - x, to.y - y, to.z - z, to.w - w);
+ ret.Normalize();
+ return ret;
+ }
+
+ /// <summary>
+ /// Returns the squared distance between this vector and <paramref name="to"/>.
+ /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if
+ /// you need to compare vectors or need the squared distance for some formula.
+ /// </summary>
+ /// <param name="to">The other vector to use.</param>
+ /// <returns>The squared distance between the two vectors.</returns>
+ public real_t DistanceSquaredTo(Vector4 to)
+ {
+ return (to - this).LengthSquared();
+ }
+
+ /// <summary>
+ /// Returns the distance between this vector and <paramref name="to"/>.
+ /// </summary>
+ /// <param name="to">The other vector to use.</param>
+ /// <returns>The distance between the two vectors.</returns>
+ public real_t DistanceTo(Vector4 to)
+ {
+ return (to - this).Length();
+ }
/// <summary>
/// Returns the dot product of this vector and <paramref name="with"/>.
@@ -200,6 +262,15 @@ namespace Godot
}
/// <summary>
+ /// Returns a new vector with all components rounded down (towards negative infinity).
+ /// </summary>
+ /// <returns>A vector with <see cref="Mathf.Floor"/> called on each component.</returns>
+ public Vector4 Floor()
+ {
+ return new Vector4(Mathf.Floor(x), Mathf.Floor(y), Mathf.Floor(z), Mathf.Floor(w));
+ }
+
+ /// <summary>
/// Returns the inverse of this vector. This is the same as <c>new Vector4(1 / v.x, 1 / v.y, 1 / v.z, 1 / v.w)</c>.
/// </summary>
/// <returns>The inverse of this vector.</returns>
@@ -318,6 +389,42 @@ namespace Godot
}
/// <summary>
+ /// Returns a vector composed of the <see cref="Mathf.PosMod(real_t, real_t)"/> of this vector's components
+ /// and <paramref name="mod"/>.
+ /// </summary>
+ /// <param name="mod">A value representing the divisor of the operation.</param>
+ /// <returns>
+ /// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="mod"/>.
+ /// </returns>
+ public Vector4 PosMod(real_t mod)
+ {
+ return new Vector4(
+ Mathf.PosMod(x, mod),
+ Mathf.PosMod(y, mod),
+ Mathf.PosMod(z, mod),
+ Mathf.PosMod(w, mod)
+ );
+ }
+
+ /// <summary>
+ /// Returns a vector composed of the <see cref="Mathf.PosMod(real_t, real_t)"/> of this vector's components
+ /// and <paramref name="modv"/>'s components.
+ /// </summary>
+ /// <param name="modv">A vector representing the divisors of the operation.</param>
+ /// <returns>
+ /// A vector with each component <see cref="Mathf.PosMod(real_t, real_t)"/> by <paramref name="modv"/>'s components.
+ /// </returns>
+ public Vector4 PosMod(Vector4 modv)
+ {
+ return new Vector4(
+ Mathf.PosMod(x, modv.x),
+ Mathf.PosMod(y, modv.y),
+ Mathf.PosMod(z, modv.z),
+ Mathf.PosMod(w, modv.w)
+ );
+ }
+
+ /// <summary>
/// Returns this vector with all components rounded to the nearest integer,
/// with halfway cases rounded towards the nearest multiple of two.
/// </summary>
@@ -343,6 +450,21 @@ namespace Godot
return v;
}
+ /// <summary>
+ /// Returns this vector with each component snapped to the nearest multiple of <paramref name="step"/>.
+ /// This can also be used to round to an arbitrary number of decimals.
+ /// </summary>
+ /// <param name="step">A vector value representing the step size to snap to.</param>
+ public Vector4 Snapped(Vector4 step)
+ {
+ return new Vector4(
+ Mathf.Snapped(x, step.x),
+ Mathf.Snapped(y, step.y),
+ Mathf.Snapped(z, step.z),
+ Mathf.Snapped(w, step.w)
+ );
+ }
+
// Constants
private static readonly Vector4 _zero = new Vector4(0, 0, 0, 0);
private static readonly Vector4 _one = new Vector4(1, 1, 1, 1);
@@ -380,18 +502,6 @@ namespace Godot
}
/// <summary>
- /// Constructs a new <see cref="Vector4"/> from an existing <see cref="Vector4"/>.
- /// </summary>
- /// <param name="v">The existing <see cref="Vector4"/>.</param>
- public Vector4(Vector4 v)
- {
- x = v.x;
- y = v.y;
- z = v.z;
- w = v.w;
- }
-
- /// <summary>
/// Adds each component of the <see cref="Vector4"/>
/// with the components of the given <see cref="Vector4"/>.
/// </summary>
@@ -669,12 +779,7 @@ namespace Godot
/// <returns>Whether or not the vector and the object are equal.</returns>
public override bool Equals(object obj)
{
- if (obj is Vector4)
- {
- return Equals((Vector4)obj);
- }
-
- return false;
+ return obj is Vector4 other && Equals(other);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs
index 365dcef486..4b1bb3ba19 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs
@@ -1,8 +1,3 @@
-#if REAL_T_IS_DOUBLE
-using real_t = System.Double;
-#else
-using real_t = System.Single;
-#endif
using System;
using System.Runtime.InteropServices;
@@ -62,8 +57,8 @@ namespace Godot
/// <summary>
/// Access vector components using their <paramref name="index"/>.
/// </summary>
- /// <exception cref="IndexOutOfRangeException">
- /// Thrown when the given the <paramref name="index"/> is not 0, 1, 2 or 3.
+ /// <exception cref="ArgumentOutOfRangeException">
+ /// <paramref name="index"/> is not 0, 1, 2 or 3.
/// </exception>
/// <value>
/// <c>[0]</c> is equivalent to <see cref="x"/>,
@@ -86,7 +81,7 @@ namespace Godot
case 3:
return w;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
set
@@ -106,7 +101,7 @@ namespace Godot
w = value;
return;
default:
- throw new IndexOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index));
}
}
}
@@ -263,31 +258,6 @@ namespace Godot
}
/// <summary>
- /// Constructs a new <see cref="Vector4i"/> from an existing <see cref="Vector4i"/>.
- /// </summary>
- /// <param name="vi">The existing <see cref="Vector4i"/>.</param>
- public Vector4i(Vector4i vi)
- {
- this.x = vi.x;
- this.y = vi.y;
- this.z = vi.z;
- this.w = vi.w;
- }
-
- /// <summary>
- /// Constructs a new <see cref="Vector4i"/> from an existing <see cref="Vector4"/>
- /// by rounding the components via <see cref="Mathf.RoundToInt(real_t)"/>.
- /// </summary>
- /// <param name="v">The <see cref="Vector4"/> to convert.</param>
- public Vector4i(Vector4 v)
- {
- this.x = Mathf.RoundToInt(v.x);
- this.y = Mathf.RoundToInt(v.y);
- this.z = Mathf.RoundToInt(v.z);
- this.w = Mathf.RoundToInt(v.w);
- }
-
- /// <summary>
/// Adds each component of the <see cref="Vector4i"/>
/// with the components of the given <see cref="Vector4i"/>.
/// </summary>
@@ -643,7 +613,12 @@ namespace Godot
/// <param name="value">The vector to convert.</param>
public static explicit operator Vector4i(Vector4 value)
{
- return new Vector4i(value);
+ return new Vector4i(
+ Mathf.RoundToInt(value.x),
+ Mathf.RoundToInt(value.y),
+ Mathf.RoundToInt(value.z),
+ Mathf.RoundToInt(value.w)
+ );
}
/// <summary>
@@ -654,12 +629,7 @@ namespace Godot
/// <returns>Whether or not the vector and the object are equal.</returns>
public override bool Equals(object obj)
{
- if (obj is Vector4i)
- {
- return Equals((Vector4i)obj);
- }
-
- return false;
+ return obj is Vector4i other && Equals(other);
}
/// <summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GlobalUsings.cs b/modules/mono/glue/GodotSharp/GodotSharp/GlobalUsings.cs
new file mode 100644
index 0000000000..263a934fae
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GlobalUsings.cs
@@ -0,0 +1,5 @@
+#if REAL_T_IS_DOUBLE
+global using real_t = System.Double;
+#else
+global using real_t = System.Single;
+#endif
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
index 4f55ce47e8..aae7a5ebfa 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -4,25 +4,71 @@
<OutputPath>bin/$(Configuration)</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<RootNamespace>Godot</RootNamespace>
- <TargetFramework>netstandard2.1</TargetFramework>
+ <TargetFramework>net6.0</TargetFramework>
<DocumentationFile>$(OutputPath)/$(AssemblyName).xml</DocumentationFile>
<EnableDefaultItems>false</EnableDefaultItems>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <LangVersion>10</LangVersion>
+
+ <AnalysisMode>Recommended</AnalysisMode>
+
+ <!-- Disabled temporarily as it pollutes the warnings, but we need to document public APIs. -->
+ <NoWarn>CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup>
+ <Description>Godot C# Core API.</Description>
+ <Authors>Godot Engine contributors</Authors>
+
+ <PackageId>GodotSharp</PackageId>
+ <Version>4.0.0</Version>
+ <PackageVersion>$(PackageVersion_GodotSharp)</PackageVersion>
+ <RepositoryUrl>https://github.com/godotengine/godot/tree/master/modules/mono/glue/GodotSharp/GodotSharp</RepositoryUrl>
+ <PackageProjectUrl>$(RepositoryUrl)</PackageProjectUrl>
+ <PackageLicenseExpression>MIT</PackageLicenseExpression>
+
+ <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
+ </PropertyGroup>
+ <ItemGroup>
+ <!-- SdkPackageVersions.props for easy access -->
+ <None Include="$(GodotSdkPackageVersionsFilePath)">
+ <Link>SdkPackageVersions.props</Link>
+ </None>
+ </ItemGroup>
+ <PropertyGroup>
<DefineConstants>$(DefineConstants);GODOT</DefineConstants>
</PropertyGroup>
<ItemGroup>
+ <PackageReference Include="ReflectionAnalyzers" Version="0.1.22-dev" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers" />
+ <!--PackageReference Include="IDisposableAnalyzers" Version="3.4.13" PrivateAssets="all" IncludeAssets="runtime; build; native; contentfiles; analyzers" /-->
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Godot.SourceGenerators.Internal\Godot.SourceGenerators.Internal.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
+ </ItemGroup>
+ <!-- Sources -->
+ <ItemGroup>
<Compile Include="Core\AABB.cs" />
+ <Compile Include="Core\Bridge\GodotSerializationInfo.cs" />
+ <Compile Include="Core\Bridge\MethodInfo.cs" />
+ <Compile Include="Core\CustomGCHandle.cs" />
<Compile Include="Core\Array.cs" />
<Compile Include="Core\Attributes\AssemblyHasScriptsAttribute.cs" />
- <Compile Include="Core\Attributes\DisableGodotGeneratorsAttribute.cs" />
<Compile Include="Core\Attributes\ExportAttribute.cs" />
- <Compile Include="Core\Attributes\GodotMethodAttribute.cs" />
+ <Compile Include="Core\Attributes\ExportCategoryAttribute.cs" />
+ <Compile Include="Core\Attributes\ExportGroupAttribute.cs" />
+ <Compile Include="Core\Attributes\ExportSubgroupAttribute.cs" />
+ <Compile Include="Core\Attributes\MustBeVariantAttribute.cs" />
<Compile Include="Core\Attributes\RPCAttribute.cs" />
<Compile Include="Core\Attributes\ScriptPathAttribute.cs" />
<Compile Include="Core\Attributes\SignalAttribute.cs" />
<Compile Include="Core\Attributes\ToolAttribute.cs" />
<Compile Include="Core\Basis.cs" />
+ <Compile Include="Core\Bridge\CSharpInstanceBridge.cs" />
+ <Compile Include="Core\Bridge\GCHandleBridge.cs" />
+ <Compile Include="Core\Bridge\AlcReloadCfg.cs" />
+ <Compile Include="Core\Bridge\ManagedCallbacks.cs" />
+ <Compile Include="Core\Bridge\PropertyInfo.cs" />
+ <Compile Include="Core\Bridge\ScriptManagerBridge.cs" />
+ <Compile Include="Core\Bridge\ScriptManagerBridge.types.cs" />
<Compile Include="Core\Callable.cs" />
<Compile Include="Core\Color.cs" />
<Compile Include="Core\Colors.cs" />
@@ -30,45 +76,58 @@
<Compile Include="Core\DelegateUtils.cs" />
<Compile Include="Core\Dictionary.cs" />
<Compile Include="Core\Dispatcher.cs" />
- <Compile Include="Core\DynamicObject.cs" />
<Compile Include="Core\Extensions\NodeExtensions.cs" />
<Compile Include="Core\Extensions\ObjectExtensions.cs" />
<Compile Include="Core\Extensions\PackedSceneExtensions.cs" />
<Compile Include="Core\Extensions\ResourceLoaderExtensions.cs" />
- <Compile Include="Core\Extensions\SceneTreeExtensions.cs" />
<Compile Include="Core\GD.cs" />
<Compile Include="Core\GodotSynchronizationContext.cs" />
<Compile Include="Core\GodotTaskScheduler.cs" />
<Compile Include="Core\GodotTraceListener.cs" />
<Compile Include="Core\GodotUnhandledExceptionEvent.cs" />
+ <Compile Include="Core\DisposablesTracker.cs" />
<Compile Include="Core\Interfaces\IAwaitable.cs" />
<Compile Include="Core\Interfaces\IAwaiter.cs" />
<Compile Include="Core\Interfaces\ISerializationListener.cs" />
- <Compile Include="Core\MarshalUtils.cs" />
<Compile Include="Core\Mathf.cs" />
<Compile Include="Core\MathfEx.cs" />
+ <Compile Include="Core\NativeInterop\CustomUnsafe.cs" />
+ <Compile Include="Core\NativeInterop\ExceptionUtils.cs" />
+ <Compile Include="Core\NativeInterop\GodotDllImportResolver.cs" />
+ <Compile Include="Core\NativeInterop\InteropUtils.cs" />
+ <Compile Include="Core\NativeInterop\NativeFuncs.extended.cs" />
+ <Compile Include="Core\NativeInterop\NativeVariantPtrArgs.cs" />
+ <Compile Include="Core\NativeInterop\VariantConversionCallbacks.cs" />
+ <Compile Include="Core\NativeInterop\VariantSpanHelpers.cs" />
+ <Compile Include="Core\NativeInterop\VariantUtils.cs" />
<Compile Include="Core\NodePath.cs" />
<Compile Include="Core\Object.base.cs" />
+ <Compile Include="Core\Object.exceptions.cs" />
<Compile Include="Core\Plane.cs" />
<Compile Include="Core\Projection.cs" />
<Compile Include="Core\Quaternion.cs" />
<Compile Include="Core\Rect2.cs" />
<Compile Include="Core\Rect2i.cs" />
+ <Compile Include="Core\ReflectionUtils.cs" />
<Compile Include="Core\RID.cs" />
+ <Compile Include="Core\NativeInterop\NativeFuncs.cs" />
+ <Compile Include="Core\NativeInterop\InteropStructs.cs" />
+ <Compile Include="Core\NativeInterop\Marshaling.cs" />
<Compile Include="Core\SignalInfo.cs" />
<Compile Include="Core\SignalAwaiter.cs" />
<Compile Include="Core\StringExtensions.cs" />
<Compile Include="Core\StringName.cs" />
<Compile Include="Core\Transform2D.cs" />
<Compile Include="Core\Transform3D.cs" />
- <Compile Include="Core\UnhandledExceptionArgs.cs" />
<Compile Include="Core\Vector2.cs" />
<Compile Include="Core\Vector2i.cs" />
<Compile Include="Core\Vector3.cs" />
<Compile Include="Core\Vector3i.cs" />
<Compile Include="Core\Vector4.cs" />
<Compile Include="Core\Vector4i.cs" />
+ <Compile Include="GlobalUsings.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Variant.cs" />
</ItemGroup>
<!--
We import a props file with auto-generated includes. This works well with Rider.
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj.DotSettings b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj.DotSettings
new file mode 100644
index 0000000000..1add6cc77e
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj.DotSettings
@@ -0,0 +1,5 @@
+<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
+ <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=core/@EntryIndexedValue">True</s:Boolean>
+ <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=generated/@EntryIndexedValue">True</s:Boolean>
+ <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=generated_005Cgodotobjects/@EntryIndexedValue">True</s:Boolean>
+</wpf:ResourceDictionary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs b/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs
new file mode 100644
index 0000000000..85ef258922
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Variant.cs
@@ -0,0 +1,841 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using Godot.NativeInterop;
+
+namespace Godot;
+
+#nullable enable
+
+[SuppressMessage("ReSharper", "RedundantNameQualifier")]
+public partial struct Variant : IDisposable
+{
+ internal godot_variant.movable NativeVar;
+ private object? _obj;
+ private Disposer? _disposer;
+
+ private sealed class Disposer : IDisposable
+ {
+ private godot_variant.movable _native;
+
+ private WeakReference<IDisposable>? _weakReferenceToSelf;
+
+ public Disposer(in godot_variant.movable nativeVar)
+ {
+ _native = nativeVar;
+ _weakReferenceToSelf = DisposablesTracker.RegisterDisposable(this);
+ }
+
+ ~Disposer()
+ {
+ Dispose(false);
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ private void Dispose(bool disposing)
+ {
+ _native.DangerousSelfRef.Dispose();
+
+ if (_weakReferenceToSelf != null)
+ {
+ DisposablesTracker.UnregisterDisposable(_weakReferenceToSelf);
+ }
+ }
+ }
+
+ private Variant(in godot_variant nativeVar)
+ {
+ NativeVar = (godot_variant.movable)nativeVar;
+ _obj = null;
+
+ switch (nativeVar.Type)
+ {
+ case Type.Nil:
+ case Type.Bool:
+ case Type.Int:
+ case Type.Float:
+ case Type.Vector2:
+ case Type.Vector2i:
+ case Type.Rect2:
+ case Type.Rect2i:
+ case Type.Vector3:
+ case Type.Vector3i:
+ case Type.Plane:
+ case Type.Quaternion:
+ case Type.Color:
+ case Type.Rid:
+ _disposer = null;
+ break;
+ default:
+ {
+ _disposer = new Disposer(NativeVar);
+ break;
+ }
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // Explicit name to make it very clear
+ public static Variant CreateTakingOwnershipOfDisposableValue(in godot_variant nativeValueToOwn) =>
+ new(nativeValueToOwn);
+
+ // Explicit name to make it very clear
+ public static Variant CreateCopyingBorrowed(in godot_variant nativeValueToOwn) =>
+ new(NativeFuncs.godotsharp_variant_new_copy(nativeValueToOwn));
+
+ /// <summary>
+ /// Constructs a new <see cref="Godot.NativeInterop.godot_variant"/> from this instance.
+ /// The caller is responsible of disposing the new instance to avoid memory leaks.
+ /// </summary>
+ public godot_variant CopyNativeVariant() =>
+ NativeFuncs.godotsharp_variant_new_copy((godot_variant)NativeVar);
+
+ public void Dispose()
+ {
+ _disposer?.Dispose();
+ NativeVar = default;
+ _obj = null;
+ }
+
+ // TODO: Consider renaming Variant.Type to VariantType and this property to Type. VariantType would also avoid ambiguity with System.Type.
+ public Type VariantType => NativeVar.DangerousSelfRef.Type;
+
+ public override string ToString() => AsString();
+
+ public object? Obj
+ {
+ get
+ {
+ if (_obj == null)
+ _obj = Marshaling.ConvertVariantToManagedObject((godot_variant)NativeVar);
+
+ return _obj;
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool AsBool() =>
+ VariantUtils.ConvertToBool((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public char AsChar() =>
+ (char)VariantUtils.ConvertToUInt16((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public sbyte AsSByte() =>
+ VariantUtils.ConvertToInt8((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public short AsInt16() =>
+ VariantUtils.ConvertToInt16((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public int AsInt32() =>
+ VariantUtils.ConvertToInt32((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public long AsInt64() =>
+ VariantUtils.ConvertToInt64((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public byte AsByte() =>
+ VariantUtils.ConvertToUInt8((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ushort AsUInt16() =>
+ VariantUtils.ConvertToUInt16((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public uint AsUInt32() =>
+ VariantUtils.ConvertToUInt32((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public ulong AsUInt64() =>
+ VariantUtils.ConvertToUInt64((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public float AsSingle() =>
+ VariantUtils.ConvertToFloat32((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public double AsDouble() =>
+ VariantUtils.ConvertToFloat64((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public string AsString() =>
+ VariantUtils.ConvertToStringObject((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Vector2 AsVector2() =>
+ VariantUtils.ConvertToVector2((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Vector2i AsVector2i() =>
+ VariantUtils.ConvertToVector2i((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Rect2 AsRect2() =>
+ VariantUtils.ConvertToRect2((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Rect2i AsRect2i() =>
+ VariantUtils.ConvertToRect2i((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Transform2D AsTransform2D() =>
+ VariantUtils.ConvertToTransform2D((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Vector3 AsVector3() =>
+ VariantUtils.ConvertToVector3((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Vector3i AsVector3i() =>
+ VariantUtils.ConvertToVector3i((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Basis AsBasis() =>
+ VariantUtils.ConvertToBasis((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Quaternion AsQuaternion() =>
+ VariantUtils.ConvertToQuaternion((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Transform3D AsTransform3D() =>
+ VariantUtils.ConvertToTransform3D((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Vector4 AsVector4() =>
+ VariantUtils.ConvertToVector4((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Vector4i AsVector4i() =>
+ VariantUtils.ConvertToVector4i((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Projection AsProjection() =>
+ VariantUtils.ConvertToProjection((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public AABB AsAABB() =>
+ VariantUtils.ConvertToAABB((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Color AsColor() =>
+ VariantUtils.ConvertToColor((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Plane AsPlane() =>
+ VariantUtils.ConvertToPlane((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Callable AsCallable() =>
+ VariantUtils.ConvertToCallableManaged((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public SignalInfo AsSignalInfo() =>
+ VariantUtils.ConvertToSignalInfo((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public byte[] AsByteArray() =>
+ VariantUtils.ConvertAsPackedByteArrayToSystemArray((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public int[] AsInt32Array() =>
+ VariantUtils.ConvertAsPackedInt32ArrayToSystemArray((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public long[] AsInt64Array() =>
+ VariantUtils.ConvertAsPackedInt64ArrayToSystemArray((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public float[] AsFloat32Array() =>
+ VariantUtils.ConvertAsPackedFloat32ArrayToSystemArray((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public double[] AsFloat64Array() =>
+ VariantUtils.ConvertAsPackedFloat64ArrayToSystemArray((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public string[] AsStringArray() =>
+ VariantUtils.ConvertAsPackedStringArrayToSystemArray((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Vector2[] AsVector2Array() =>
+ VariantUtils.ConvertAsPackedVector2ArrayToSystemArray((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Vector3[] AsVector3Array() =>
+ VariantUtils.ConvertAsPackedVector3ArrayToSystemArray((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Color[] AsColorArray() =>
+ VariantUtils.ConvertAsPackedColorArrayToSystemArray((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public T[] AsGodotObjectArray<T>()
+ where T : Godot.Object =>
+ VariantUtils.ConvertToSystemArrayOfGodotObject<T>((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Collections.Dictionary<TKey, TValue> AsGodotDictionary<TKey, TValue>() =>
+ VariantUtils.ConvertToDictionaryObject<TKey, TValue>((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Collections.Array<T> AsGodotArray<T>() =>
+ VariantUtils.ConvertToArrayObject<T>((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public StringName[] AsSystemArrayOfStringName() =>
+ VariantUtils.ConvertToSystemArrayOfStringName((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public NodePath[] AsSystemArrayOfNodePath() =>
+ VariantUtils.ConvertToSystemArrayOfNodePath((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public RID[] AsSystemArrayOfRID() =>
+ VariantUtils.ConvertToSystemArrayOfRID((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Godot.Object AsGodotObject() =>
+ VariantUtils.ConvertToGodotObject((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public StringName AsStringName() =>
+ VariantUtils.ConvertToStringNameObject((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public NodePath AsNodePath() =>
+ VariantUtils.ConvertToNodePathObject((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public RID AsRID() =>
+ VariantUtils.ConvertToRID((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Collections.Dictionary AsGodotDictionary() =>
+ VariantUtils.ConvertToDictionaryObject((godot_variant)NativeVar);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Collections.Array AsGodotArray() =>
+ VariantUtils.ConvertToArrayObject((godot_variant)NativeVar);
+
+ // Explicit conversion operators to supported types
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator bool(Variant from) => from.AsBool();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator char(Variant from) => from.AsChar();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator sbyte(Variant from) => from.AsSByte();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator short(Variant from) => from.AsInt16();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator int(Variant from) => from.AsInt32();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator long(Variant from) => from.AsInt64();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator byte(Variant from) => from.AsByte();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator ushort(Variant from) => from.AsUInt16();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator uint(Variant from) => from.AsUInt32();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator ulong(Variant from) => from.AsUInt64();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator float(Variant from) => from.AsSingle();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator double(Variant from) => from.AsDouble();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator string(Variant from) => from.AsString();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Vector2(Variant from) => from.AsVector2();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Vector2i(Variant from) => from.AsVector2i();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Rect2(Variant from) => from.AsRect2();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Rect2i(Variant from) => from.AsRect2i();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Transform2D(Variant from) => from.AsTransform2D();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Vector3(Variant from) => from.AsVector3();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Vector3i(Variant from) => from.AsVector3i();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Basis(Variant from) => from.AsBasis();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Quaternion(Variant from) => from.AsQuaternion();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Transform3D(Variant from) => from.AsTransform3D();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Vector4(Variant from) => from.AsVector4();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Vector4i(Variant from) => from.AsVector4i();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Projection(Variant from) => from.AsProjection();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator AABB(Variant from) => from.AsAABB();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Color(Variant from) => from.AsColor();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Plane(Variant from) => from.AsPlane();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Callable(Variant from) => from.AsCallable();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator SignalInfo(Variant from) => from.AsSignalInfo();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator byte[](Variant from) => from.AsByteArray();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator int[](Variant from) => from.AsInt32Array();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator long[](Variant from) => from.AsInt64Array();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator float[](Variant from) => from.AsFloat32Array();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator double[](Variant from) => from.AsFloat64Array();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator string[](Variant from) => from.AsStringArray();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Vector2[](Variant from) => from.AsVector2Array();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Vector3[](Variant from) => from.AsVector3Array();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Color[](Variant from) => from.AsColorArray();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator StringName[](Variant from) => from.AsSystemArrayOfStringName();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator NodePath[](Variant from) => from.AsSystemArrayOfNodePath();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator RID[](Variant from) => from.AsSystemArrayOfRID();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Godot.Object(Variant from) => from.AsGodotObject();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator StringName(Variant from) => from.AsStringName();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator NodePath(Variant from) => from.AsNodePath();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator RID(Variant from) => from.AsRID();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Collections.Dictionary(Variant from) => from.AsGodotDictionary();
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static explicit operator Collections.Array(Variant from) => from.AsGodotArray();
+
+ // While we provide implicit conversion operators, normal methods are still needed for
+ // casts that are not done implicitly (e.g.: raw array to Span, enum to integer, etc).
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(bool from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(char from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(sbyte from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(short from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(int from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(long from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(byte from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(ushort from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(uint from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(ulong from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(float from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(double from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(string from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Vector2 from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Vector2i from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Rect2 from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Rect2i from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Transform2D from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Vector3 from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Vector3i from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Basis from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Quaternion from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Transform3D from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Vector4 from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Vector4i from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Projection from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(AABB from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Color from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Plane from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Callable from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(SignalInfo from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Span<byte> from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Span<int> from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Span<long> from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Span<float> from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Span<double> from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Span<string> from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Span<Vector2> from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Span<Vector3> from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Span<Color> from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Godot.Object[] from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom<TKey, TValue>(Collections.Dictionary<TKey, TValue> from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromDictionary(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom<T>(Collections.Array<T> from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromArray(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Span<StringName> from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Span<NodePath> from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Span<RID> from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Godot.Object from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(StringName from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(NodePath from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(RID from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Collections.Dictionary from) => from;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Variant CreateFrom(Collections.Array from) => from;
+
+ // Implicit conversion operators
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(bool from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromBool(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(char from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromInt(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(sbyte from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromInt(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(short from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromInt(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(int from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromInt(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(long from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromInt(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(byte from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromInt(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(ushort from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromInt(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(uint from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromInt(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(ulong from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromInt(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(float from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromFloat(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(double from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromFloat(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(string from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromString(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Vector2 from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromVector2(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Vector2i from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromVector2i(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Rect2 from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromRect2(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Rect2i from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromRect2i(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Transform2D from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromTransform2D(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Vector3 from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromVector3(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Vector3i from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromVector3i(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Basis from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromBasis(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Quaternion from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromQuaternion(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Transform3D from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromTransform3D(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Vector4 from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromVector4(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Vector4i from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromVector4i(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Projection from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromProjection(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(AABB from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromAABB(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Color from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromColor(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Plane from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromPlane(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Callable from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromCallable(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(SignalInfo from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSignalInfo(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Span<byte> from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromPackedByteArray(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Span<int> from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromPackedInt32Array(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Span<long> from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromPackedInt64Array(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Span<float> from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromPackedFloat32Array(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Span<double> from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromPackedFloat64Array(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Span<string> from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromPackedStringArray(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Span<Vector2> from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromPackedVector2Array(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Span<Vector3> from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromPackedVector3Array(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Span<Color> from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromPackedColorArray(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Godot.Object[] from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemArrayOfGodotObject(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Span<StringName> from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemArrayOfStringName(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Span<NodePath> from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemArrayOfNodePath(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Span<RID> from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromSystemArrayOfRID(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Godot.Object from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromGodotObject(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(StringName from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromStringName(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(NodePath from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromNodePath(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(RID from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromRID(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Collections.Dictionary from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromDictionary(from));
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Variant(Collections.Array from) =>
+ CreateTakingOwnershipOfDisposableValue(VariantUtils.CreateFromArray(from));
+}
diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
index a8c4ba96b5..ebf09aab7b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj
@@ -4,9 +4,24 @@
<OutputPath>bin/$(Configuration)</OutputPath>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<RootNamespace>Godot</RootNamespace>
- <TargetFramework>netstandard2.1</TargetFramework>
+ <TargetFramework>net6.0</TargetFramework>
<DocumentationFile>$(OutputPath)/$(AssemblyName).xml</DocumentationFile>
<EnableDefaultItems>false</EnableDefaultItems>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <LangVersion>10</LangVersion>
+ </PropertyGroup>
+ <PropertyGroup>
+ <Description>Godot C# Editor API.</Description>
+ <Authors>Godot Engine contributors</Authors>
+
+ <PackageId>GodotSharpEditor</PackageId>
+ <Version>4.0.0</Version>
+ <PackageVersion>$(PackageVersion_GodotSharp)</PackageVersion>
+ <RepositoryUrl>https://github.com/godotengine/godot/tree/master/modules/mono/glue/GodotSharp/GodotSharpEditor</RepositoryUrl>
+ <PackageProjectUrl>$(RepositoryUrl)</PackageProjectUrl>
+ <PackageLicenseExpression>MIT</PackageLicenseExpression>
+
+ <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<PropertyGroup>
<DefineConstants>$(DefineConstants);GODOT</DefineConstants>
diff --git a/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj.DotSettings b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj.DotSettings
new file mode 100644
index 0000000000..c7ff6fd3ee
--- /dev/null
+++ b/modules/mono/glue/GodotSharp/GodotSharpEditor/GodotSharpEditor.csproj.DotSettings
@@ -0,0 +1,4 @@
+<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
+ <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=generated/@EntryIndexedValue">True</s:Boolean>
+ <s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=generated_005Cgodotobjects/@EntryIndexedValue">True</s:Boolean>
+</wpf:ResourceDictionary>
diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp
deleted file mode 100644
index 7b9dbc87cf..0000000000
--- a/modules/mono/glue/base_object_glue.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-/*************************************************************************/
-/* base_object_glue.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifdef MONO_GLUE_ENABLED
-
-#include "core/object/class_db.h"
-#include "core/object/ref_counted.h"
-#include "core/string/string_name.h"
-
-#include "../csharp_script.h"
-#include "../mono_gd/gd_mono_cache.h"
-#include "../mono_gd/gd_mono_class.h"
-#include "../mono_gd/gd_mono_internals.h"
-#include "../mono_gd/gd_mono_marshal.h"
-#include "../mono_gd/gd_mono_utils.h"
-#include "../signal_awaiter_utils.h"
-#include "arguments_vector.h"
-
-Object *godot_icall_Object_Ctor(MonoObject *p_obj) {
- Object *instance = memnew(Object);
- GDMonoInternals::tie_managed_to_unmanaged(p_obj, instance);
- return instance;
-}
-
-void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(p_ptr == nullptr);
-#endif
-
- if (p_ptr->get_script_instance()) {
- CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_ptr->get_script_instance());
- if (cs_instance) {
- if (!cs_instance->is_destructing_script_instance()) {
- cs_instance->mono_object_disposed(p_obj);
- p_ptr->set_script_instance(nullptr);
- }
- return;
- }
- }
-
- void *data = CSharpLanguage::get_existing_instance_binding(p_ptr);
-
- if (data) {
- CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
- if (script_binding.inited) {
- MonoGCHandleData &gchandle = script_binding.gchandle;
- if (!gchandle.is_released()) {
- CSharpLanguage::release_script_gchandle(p_obj, gchandle);
- }
- }
- }
-}
-
-void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(p_ptr == nullptr);
- // This is only called with RefCounted derived classes
- CRASH_COND(!Object::cast_to<RefCounted>(p_ptr));
-#endif
-
- RefCounted *rc = static_cast<RefCounted *>(p_ptr);
-
- if (rc->get_script_instance()) {
- CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(rc->get_script_instance());
- if (cs_instance) {
- if (!cs_instance->is_destructing_script_instance()) {
- bool delete_owner;
- bool remove_script_instance;
-
- cs_instance->mono_object_disposed_baseref(p_obj, p_is_finalizer, delete_owner, remove_script_instance);
-
- if (delete_owner) {
- memdelete(rc);
- } else if (remove_script_instance) {
- rc->set_script_instance(nullptr);
- }
- }
- return;
- }
- }
-
- // Unsafe refcount decrement. The managed instance also counts as a reference.
- // See: CSharpLanguage::alloc_instance_binding_data(Object *p_object)
- CSharpLanguage::get_singleton()->pre_unsafe_unreference(rc);
- if (rc->unreference()) {
- memdelete(rc);
- } else {
- void *data = CSharpLanguage::get_existing_instance_binding(rc);
-
- if (data) {
- CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
- if (script_binding.inited) {
- MonoGCHandleData &gchandle = script_binding.gchandle;
- if (!gchandle.is_released()) {
- CSharpLanguage::release_script_gchandle(p_obj, gchandle);
- }
- }
- }
- }
-}
-
-void godot_icall_Object_ConnectEventSignals(Object *p_ptr) {
- CSharpInstance *csharp_instance = CAST_CSHARP_INSTANCE(p_ptr->get_script_instance());
- if (csharp_instance) {
- csharp_instance->connect_event_signals();
- }
-}
-
-MethodBind *godot_icall_Object_ClassDB_get_method(StringName *p_type, MonoString *p_method) {
- StringName type = p_type ? *p_type : StringName();
- StringName method(GDMonoMarshal::mono_string_to_godot(p_method));
- return ClassDB::get_method(type, method);
-}
-
-MonoObject *godot_icall_Object_weakref(Object *p_ptr) {
- if (!p_ptr) {
- return nullptr;
- }
-
- Ref<WeakRef> wref;
- RefCounted *rc = Object::cast_to<RefCounted>(p_ptr);
-
- if (rc) {
- Ref<RefCounted> r = rc;
- if (!r.is_valid()) {
- return nullptr;
- }
-
- wref.instantiate();
- wref->set_ref(r);
- } else {
- wref.instantiate();
- wref->set_obj(p_ptr);
- }
-
- return GDMonoUtils::unmanaged_get_managed(wref.ptr());
-}
-
-int32_t godot_icall_SignalAwaiter_connect(Object *p_source, StringName *p_signal, Object *p_target, MonoObject *p_awaiter) {
- StringName signal = p_signal ? *p_signal : StringName();
- return (int32_t)gd_mono_connect_signal_awaiter(p_source, signal, p_target, p_awaiter);
-}
-
-MonoArray *godot_icall_DynamicGodotObject_SetMemberList(Object *p_ptr) {
- List<PropertyInfo> property_list;
- p_ptr->get_property_list(&property_list);
-
- MonoArray *result = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(String), property_list.size());
-
- int i = 0;
- for (const PropertyInfo &E : property_list) {
- MonoString *boxed = GDMonoMarshal::mono_string_from_godot(E.name);
- mono_array_setref(result, i, boxed);
- i++;
- }
-
- return result;
-}
-
-MonoBoolean godot_icall_DynamicGodotObject_InvokeMember(Object *p_ptr, MonoString *p_name, MonoArray *p_args, MonoObject **r_result) {
- String name = GDMonoMarshal::mono_string_to_godot(p_name);
-
- int argc = mono_array_length(p_args);
-
- ArgumentsVector<Variant> arg_store(argc);
- ArgumentsVector<const Variant *> args(argc);
-
- for (int i = 0; i < argc; i++) {
- MonoObject *elem = mono_array_get(p_args, MonoObject *, i);
- arg_store.set(i, GDMonoMarshal::mono_object_to_variant(elem));
- args.set(i, &arg_store.get(i));
- }
-
- Callable::CallError error;
- Variant result = p_ptr->callp(StringName(name), args.ptr(), argc, error);
-
- *r_result = GDMonoMarshal::variant_to_mono_object(result);
-
- return error.error == Callable::CallError::CALL_OK;
-}
-
-MonoBoolean godot_icall_DynamicGodotObject_GetMember(Object *p_ptr, MonoString *p_name, MonoObject **r_result) {
- String name = GDMonoMarshal::mono_string_to_godot(p_name);
-
- bool valid;
- Variant value = p_ptr->get(StringName(name), &valid);
-
- if (valid) {
- *r_result = GDMonoMarshal::variant_to_mono_object(value);
- }
-
- return valid;
-}
-
-MonoBoolean godot_icall_DynamicGodotObject_SetMember(Object *p_ptr, MonoString *p_name, MonoObject *p_value) {
- String name = GDMonoMarshal::mono_string_to_godot(p_name);
- Variant value = GDMonoMarshal::mono_object_to_variant(p_value);
-
- bool valid;
- p_ptr->set(StringName(name), value, &valid);
-
- return valid;
-}
-
-MonoString *godot_icall_Object_ToString(Object *p_ptr) {
-#ifdef DEBUG_ENABLED
- // Cannot happen in C#; would get an ObjectDisposedException instead.
- CRASH_COND(p_ptr == nullptr);
-#endif
- // Can't call 'Object::to_string()' here, as that can end up calling 'ToString' again resulting in an endless circular loop.
- String result = "[" + p_ptr->get_class() + ":" + itos(p_ptr->get_instance_id()) + "]";
- return GDMonoMarshal::mono_string_from_godot(result);
-}
-
-void godot_register_object_icalls() {
- GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_Ctor", godot_icall_Object_Ctor);
- GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_Disposed", godot_icall_Object_Disposed);
- GDMonoUtils::add_internal_call("Godot.Object::godot_icall_RefCounted_Disposed", godot_icall_RefCounted_Disposed);
- GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ConnectEventSignals", godot_icall_Object_ConnectEventSignals);
- GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ClassDB_get_method", godot_icall_Object_ClassDB_get_method);
- GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ToString", godot_icall_Object_ToString);
- GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_weakref", godot_icall_Object_weakref);
- GDMonoUtils::add_internal_call("Godot.SignalAwaiter::godot_icall_SignalAwaiter_connect", godot_icall_SignalAwaiter_connect);
- GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMemberList", godot_icall_DynamicGodotObject_SetMemberList);
- GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_InvokeMember", godot_icall_DynamicGodotObject_InvokeMember);
- GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_GetMember", godot_icall_DynamicGodotObject_GetMember);
- GDMonoUtils::add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMember", godot_icall_DynamicGodotObject_SetMember);
-}
-
-#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp
deleted file mode 100644
index 8a9f30459c..0000000000
--- a/modules/mono/glue/collections_glue.cpp
+++ /dev/null
@@ -1,374 +0,0 @@
-/*************************************************************************/
-/* collections_glue.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifdef MONO_GLUE_ENABLED
-
-#include <mono/metadata/exception.h>
-
-#include "core/variant/array.h"
-
-#include "../mono_gd/gd_mono_cache.h"
-#include "../mono_gd/gd_mono_class.h"
-#include "../mono_gd/gd_mono_marshal.h"
-#include "../mono_gd/gd_mono_utils.h"
-
-Array *godot_icall_Array_Ctor() {
- return memnew(Array);
-}
-
-void godot_icall_Array_Dtor(Array *ptr) {
- memdelete(ptr);
-}
-
-MonoObject *godot_icall_Array_At(Array *ptr, int32_t index) {
- if (index < 0 || index >= ptr->size()) {
- GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
- return nullptr;
- }
- return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index));
-}
-
-MonoObject *godot_icall_Array_At_Generic(Array *ptr, int32_t index, uint32_t type_encoding, GDMonoClass *type_class) {
- if (index < 0 || index >= ptr->size()) {
- GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
- return nullptr;
- }
- return GDMonoMarshal::variant_to_mono_object(ptr->operator[](index), ManagedType(type_encoding, type_class));
-}
-
-void godot_icall_Array_SetAt(Array *ptr, int32_t index, MonoObject *value) {
- if (index < 0 || index >= ptr->size()) {
- GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
- return;
- }
- ptr->operator[](index) = GDMonoMarshal::mono_object_to_variant(value);
-}
-
-int32_t godot_icall_Array_Count(Array *ptr) {
- return ptr->size();
-}
-
-int32_t godot_icall_Array_Add(Array *ptr, MonoObject *item) {
- ptr->append(GDMonoMarshal::mono_object_to_variant(item));
- return ptr->size();
-}
-
-void godot_icall_Array_Clear(Array *ptr) {
- ptr->clear();
-}
-
-MonoBoolean godot_icall_Array_Contains(Array *ptr, MonoObject *item) {
- return ptr->find(GDMonoMarshal::mono_object_to_variant(item)) != -1;
-}
-
-void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int32_t array_index) {
- unsigned int count = ptr->size();
-
- if (mono_array_length(array) < (array_index + count)) {
- MonoException *exc = mono_get_exception_argument("", "Destination array was not long enough. Check destIndex and length, and the array's lower bounds.");
- GDMonoUtils::set_pending_exception(exc);
- return;
- }
-
- for (unsigned int i = 0; i < count; i++) {
- MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(ptr->operator[](i));
- mono_array_setref(array, array_index, boxed);
- array_index++;
- }
-}
-
-Array *godot_icall_Array_Ctor_MonoArray(MonoArray *mono_array) {
- Array *godot_array = memnew(Array);
- unsigned int count = mono_array_length(mono_array);
- godot_array->resize(count);
- for (unsigned int i = 0; i < count; i++) {
- MonoObject *item = mono_array_get(mono_array, MonoObject *, i);
- godot_icall_Array_SetAt(godot_array, i, item);
- }
- return godot_array;
-}
-
-Array *godot_icall_Array_Duplicate(Array *ptr, MonoBoolean deep) {
- return memnew(Array(ptr->duplicate(deep)));
-}
-
-Array *godot_icall_Array_Concatenate(Array *left, Array *right) {
- int count = left->size() + right->size();
- Array *new_array = memnew(Array(left->duplicate(false)));
- new_array->resize(count);
- for (unsigned int i = 0; i < (unsigned int)right->size(); i++) {
- new_array->operator[](i + left->size()) = right->operator[](i);
- }
- return new_array;
-}
-
-int32_t godot_icall_Array_IndexOf(Array *ptr, MonoObject *item) {
- return ptr->find(GDMonoMarshal::mono_object_to_variant(item));
-}
-
-void godot_icall_Array_Insert(Array *ptr, int32_t index, MonoObject *item) {
- if (index < 0 || index > ptr->size()) {
- GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
- return;
- }
- ptr->insert(index, GDMonoMarshal::mono_object_to_variant(item));
-}
-
-MonoBoolean godot_icall_Array_Remove(Array *ptr, MonoObject *item) {
- int idx = ptr->find(GDMonoMarshal::mono_object_to_variant(item));
- if (idx >= 0) {
- ptr->remove_at(idx);
- return true;
- }
- return false;
-}
-
-void godot_icall_Array_RemoveAt(Array *ptr, int32_t index) {
- if (index < 0 || index >= ptr->size()) {
- GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
- return;
- }
- ptr->remove_at(index);
-}
-
-int32_t godot_icall_Array_Resize(Array *ptr, int32_t new_size) {
- return (int32_t)ptr->resize(new_size);
-}
-
-void godot_icall_Array_Shuffle(Array *ptr) {
- ptr->shuffle();
-}
-
-void godot_icall_Array_Generic_GetElementTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class) {
- MonoType *elem_type = mono_reflection_type_get_type(refltype);
-
- *type_encoding = mono_type_get_type(elem_type);
- MonoClass *type_class_raw = mono_class_from_mono_type(elem_type);
- *type_class = GDMono::get_singleton()->get_class(type_class_raw);
-}
-
-MonoString *godot_icall_Array_ToString(Array *ptr) {
- return GDMonoMarshal::mono_string_from_godot(Variant(*ptr).operator String());
-}
-
-Dictionary *godot_icall_Dictionary_Ctor() {
- return memnew(Dictionary);
-}
-
-void godot_icall_Dictionary_Dtor(Dictionary *ptr) {
- memdelete(ptr);
-}
-
-MonoObject *godot_icall_Dictionary_GetValue(Dictionary *ptr, MonoObject *key) {
- Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
- if (ret == nullptr) {
- MonoObject *exc = mono_object_new(mono_domain_get(), CACHED_CLASS(KeyNotFoundException)->get_mono_ptr());
-#ifdef DEBUG_ENABLED
- CRASH_COND(!exc);
-#endif
- GDMonoUtils::runtime_object_init(exc, CACHED_CLASS(KeyNotFoundException));
- GDMonoUtils::set_pending_exception((MonoException *)exc);
- return nullptr;
- }
- return GDMonoMarshal::variant_to_mono_object(ret);
-}
-
-MonoObject *godot_icall_Dictionary_GetValue_Generic(Dictionary *ptr, MonoObject *key, uint32_t type_encoding, GDMonoClass *type_class) {
- Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
- if (ret == nullptr) {
- MonoObject *exc = mono_object_new(mono_domain_get(), CACHED_CLASS(KeyNotFoundException)->get_mono_ptr());
-#ifdef DEBUG_ENABLED
- CRASH_COND(!exc);
-#endif
- GDMonoUtils::runtime_object_init(exc, CACHED_CLASS(KeyNotFoundException));
- GDMonoUtils::set_pending_exception((MonoException *)exc);
- return nullptr;
- }
- return GDMonoMarshal::variant_to_mono_object(ret, ManagedType(type_encoding, type_class));
-}
-
-void godot_icall_Dictionary_SetValue(Dictionary *ptr, MonoObject *key, MonoObject *value) {
- ptr->operator[](GDMonoMarshal::mono_object_to_variant(key)) = GDMonoMarshal::mono_object_to_variant(value);
-}
-
-Array *godot_icall_Dictionary_Keys(Dictionary *ptr) {
- return memnew(Array(ptr->keys()));
-}
-
-Array *godot_icall_Dictionary_Values(Dictionary *ptr) {
- return memnew(Array(ptr->values()));
-}
-
-int32_t godot_icall_Dictionary_Count(Dictionary *ptr) {
- return ptr->size();
-}
-
-int32_t godot_icall_Dictionary_KeyValuePairs(Dictionary *ptr, Array **keys, Array **values) {
- *keys = godot_icall_Dictionary_Keys(ptr);
- *values = godot_icall_Dictionary_Values(ptr);
- return godot_icall_Dictionary_Count(ptr);
-}
-
-void godot_icall_Dictionary_KeyValuePairAt(Dictionary *ptr, int index, MonoObject **key, MonoObject **value) {
- *key = GDMonoMarshal::variant_to_mono_object(ptr->get_key_at_index(index));
- *value = GDMonoMarshal::variant_to_mono_object(ptr->get_value_at_index(index));
-}
-
-void godot_icall_Dictionary_KeyValuePairAt_Generic(Dictionary *ptr, int index, MonoObject **key, MonoObject **value, uint32_t value_type_encoding, GDMonoClass *value_type_class) {
- ManagedType type(value_type_encoding, value_type_class);
- *key = GDMonoMarshal::variant_to_mono_object(ptr->get_key_at_index(index));
- *value = GDMonoMarshal::variant_to_mono_object(ptr->get_value_at_index(index), type);
-}
-
-void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *value) {
- Variant varKey = GDMonoMarshal::mono_object_to_variant(key);
- Variant *ret = ptr->getptr(varKey);
- if (ret != nullptr) {
- GDMonoUtils::set_pending_exception(mono_get_exception_argument("key", "An element with the same key already exists"));
- return;
- }
- ptr->operator[](varKey) = GDMonoMarshal::mono_object_to_variant(value);
-}
-
-void godot_icall_Dictionary_Clear(Dictionary *ptr) {
- ptr->clear();
-}
-
-MonoBoolean godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value) {
- // no dupes
- Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
- return ret != nullptr && *ret == GDMonoMarshal::mono_object_to_variant(value);
-}
-
-MonoBoolean godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key) {
- return ptr->has(GDMonoMarshal::mono_object_to_variant(key));
-}
-
-Dictionary *godot_icall_Dictionary_Duplicate(Dictionary *ptr, MonoBoolean deep) {
- return memnew(Dictionary(ptr->duplicate(deep)));
-}
-
-MonoBoolean godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key) {
- return ptr->erase(GDMonoMarshal::mono_object_to_variant(key));
-}
-
-MonoBoolean godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value) {
- Variant varKey = GDMonoMarshal::mono_object_to_variant(key);
-
- // no dupes
- Variant *ret = ptr->getptr(varKey);
- if (ret != nullptr && *ret == GDMonoMarshal::mono_object_to_variant(value)) {
- ptr->erase(varKey);
- return true;
- }
-
- return false;
-}
-
-MonoBoolean godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value) {
- Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
- if (ret == nullptr) {
- *value = nullptr;
- return false;
- }
- *value = GDMonoMarshal::variant_to_mono_object(ret);
- return true;
-}
-
-MonoBoolean godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class) {
- Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
- if (ret == nullptr) {
- *value = nullptr;
- return false;
- }
- *value = GDMonoMarshal::variant_to_mono_object(ret, ManagedType(type_encoding, type_class));
- return true;
-}
-
-void godot_icall_Dictionary_Generic_GetValueTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class) {
- MonoType *value_type = mono_reflection_type_get_type(refltype);
-
- *type_encoding = mono_type_get_type(value_type);
- MonoClass *type_class_raw = mono_class_from_mono_type(value_type);
- *type_class = GDMono::get_singleton()->get_class(type_class_raw);
-}
-
-MonoString *godot_icall_Dictionary_ToString(Dictionary *ptr) {
- return GDMonoMarshal::mono_string_from_godot(Variant(*ptr).operator String());
-}
-
-void godot_register_collections_icalls() {
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor", godot_icall_Array_Ctor);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Ctor_MonoArray", godot_icall_Array_Ctor_MonoArray);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Dtor", godot_icall_Array_Dtor);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_At", godot_icall_Array_At);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_At_Generic", godot_icall_Array_At_Generic);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_SetAt", godot_icall_Array_SetAt);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Count", godot_icall_Array_Count);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Add", godot_icall_Array_Add);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Clear", godot_icall_Array_Clear);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Concatenate", godot_icall_Array_Concatenate);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Contains", godot_icall_Array_Contains);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_CopyTo", godot_icall_Array_CopyTo);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Duplicate", godot_icall_Array_Duplicate);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_IndexOf", godot_icall_Array_IndexOf);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Insert", godot_icall_Array_Insert);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Remove", godot_icall_Array_Remove);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_RemoveAt", godot_icall_Array_RemoveAt);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Resize", godot_icall_Array_Resize);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Shuffle", godot_icall_Array_Shuffle);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_Generic_GetElementTypeInfo", godot_icall_Array_Generic_GetElementTypeInfo);
- GDMonoUtils::add_internal_call("Godot.Collections.Array::godot_icall_Array_ToString", godot_icall_Array_ToString);
-
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Ctor", godot_icall_Dictionary_Ctor);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Dtor", godot_icall_Dictionary_Dtor);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue", godot_icall_Dictionary_GetValue);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_GetValue_Generic", godot_icall_Dictionary_GetValue_Generic);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_SetValue", godot_icall_Dictionary_SetValue);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Keys", godot_icall_Dictionary_Keys);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Values", godot_icall_Dictionary_Values);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Count", godot_icall_Dictionary_Count);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairs", godot_icall_Dictionary_KeyValuePairs);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairAt", godot_icall_Dictionary_KeyValuePairAt);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_KeyValuePairAt_Generic", godot_icall_Dictionary_KeyValuePairAt_Generic);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Add", godot_icall_Dictionary_Add);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Clear", godot_icall_Dictionary_Clear);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Contains", godot_icall_Dictionary_Contains);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ContainsKey", godot_icall_Dictionary_ContainsKey);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Duplicate", godot_icall_Dictionary_Duplicate);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_RemoveKey", godot_icall_Dictionary_RemoveKey);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Remove", godot_icall_Dictionary_Remove);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue", godot_icall_Dictionary_TryGetValue);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_TryGetValue_Generic", godot_icall_Dictionary_TryGetValue_Generic);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_Generic_GetValueTypeInfo", godot_icall_Dictionary_Generic_GetValueTypeInfo);
- GDMonoUtils::add_internal_call("Godot.Collections.Dictionary::godot_icall_Dictionary_ToString", godot_icall_Dictionary_ToString);
-}
-
-#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/gd_glue.cpp b/modules/mono/glue/gd_glue.cpp
deleted file mode 100644
index 8b1c2b729e..0000000000
--- a/modules/mono/glue/gd_glue.cpp
+++ /dev/null
@@ -1,348 +0,0 @@
-/*************************************************************************/
-/* gd_glue.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifdef MONO_GLUE_ENABLED
-
-#include "core/io/marshalls.h"
-#include "core/os/os.h"
-#include "core/string/ustring.h"
-#include "core/variant/array.h"
-#include "core/variant/variant.h"
-#include "core/variant/variant_parser.h"
-
-#include "../mono_gd/gd_mono_cache.h"
-#include "../mono_gd/gd_mono_marshal.h"
-#include "../mono_gd/gd_mono_utils.h"
-
-MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes, MonoBoolean p_allow_objects) {
- Variant ret;
- PackedByteArray varr = GDMonoMarshal::mono_array_to_PackedByteArray(p_bytes);
- Error err = decode_variant(ret, varr.ptr(), varr.size(), nullptr, p_allow_objects);
- if (err != OK) {
- ret = RTR("Not enough bytes for decoding bytes, or invalid format.");
- }
- return GDMonoMarshal::variant_to_mono_object(ret);
-}
-
-MonoObject *godot_icall_GD_convert(MonoObject *p_what, int32_t p_type) {
- Variant what = GDMonoMarshal::mono_object_to_variant(p_what);
- const Variant *args[1] = { &what };
- Callable::CallError ce;
- Variant ret;
- Variant::construct(Variant::Type(p_type), ret, args, 1, ce);
- ERR_FAIL_COND_V(ce.error != Callable::CallError::CALL_OK, nullptr);
- return GDMonoMarshal::variant_to_mono_object(ret);
-}
-
-int godot_icall_GD_hash(MonoObject *p_var) {
- return GDMonoMarshal::mono_object_to_variant(p_var).hash();
-}
-
-MonoObject *godot_icall_GD_instance_from_id(uint64_t p_instance_id) {
- return GDMonoUtils::unmanaged_get_managed(ObjectDB::get_instance(ObjectID(p_instance_id)));
-}
-
-void godot_icall_GD_print(MonoArray *p_what) {
- String str;
- int length = mono_array_length(p_what);
-
- for (int i = 0; i < length; i++) {
- MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
-
- MonoException *exc = nullptr;
- String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- return;
- }
-
- str += elem_str;
- }
-
- print_line(str);
-}
-
-void godot_icall_GD_print_rich(MonoArray *p_what) {
- String str;
- int length = mono_array_length(p_what);
-
- for (int i = 0; i < length; i++) {
- MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
-
- MonoException *exc = nullptr;
- String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- return;
- }
-
- str += elem_str;
- }
-
- print_line_rich(str);
-}
-
-void godot_icall_GD_printerr(MonoArray *p_what) {
- String str;
- int length = mono_array_length(p_what);
-
- for (int i = 0; i < length; i++) {
- MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
-
- MonoException *exc = nullptr;
- String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- return;
- }
-
- str += elem_str;
- }
-
- print_error(str);
-}
-
-void godot_icall_GD_printraw(MonoArray *p_what) {
- String str;
- int length = mono_array_length(p_what);
-
- for (int i = 0; i < length; i++) {
- MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
-
- MonoException *exc = nullptr;
- String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- return;
- }
-
- str += elem_str;
- }
-
- OS::get_singleton()->print("%s", str.utf8().get_data());
-}
-
-void godot_icall_GD_prints(MonoArray *p_what) {
- String str;
- int length = mono_array_length(p_what);
-
- for (int i = 0; i < length; i++) {
- MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
-
- MonoException *exc = nullptr;
- String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- return;
- }
-
- if (i) {
- str += " ";
- }
-
- str += elem_str;
- }
-
- print_line(str);
-}
-
-void godot_icall_GD_printt(MonoArray *p_what) {
- String str;
- int length = mono_array_length(p_what);
-
- for (int i = 0; i < length; i++) {
- MonoObject *elem = mono_array_get(p_what, MonoObject *, i);
-
- MonoException *exc = nullptr;
- String elem_str = GDMonoMarshal::mono_object_to_variant_string(elem, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- return;
- }
-
- if (i) {
- str += "\t";
- }
-
- str += elem_str;
- }
-
- print_line(str);
-}
-
-void godot_icall_GD_randomize() {
- Math::randomize();
-}
-
-uint32_t godot_icall_GD_randi() {
- return Math::rand();
-}
-
-float godot_icall_GD_randf() {
- return Math::randf();
-}
-
-int32_t godot_icall_GD_randi_range(int32_t from, int32_t to) {
- return Math::random(from, to);
-}
-
-double godot_icall_GD_randf_range(double from, double to) {
- return Math::random(from, to);
-}
-
-double godot_icall_GD_randfn(double mean, double deviation) {
- return Math::randfn(mean, deviation);
-}
-
-uint32_t godot_icall_GD_rand_seed(uint64_t seed, uint64_t *newSeed) {
- uint32_t ret = Math::rand_from_seed(&seed);
- *newSeed = seed;
- return ret;
-}
-
-void godot_icall_GD_seed(uint64_t p_seed) {
- Math::seed(p_seed);
-}
-
-MonoString *godot_icall_GD_str(MonoArray *p_what) {
- String str;
- Array what = GDMonoMarshal::mono_array_to_Array(p_what);
-
- for (int i = 0; i < what.size(); i++) {
- String os = what[i].operator String();
-
- if (i == 0) {
- str = os;
- } else {
- str += os;
- }
- }
-
- return GDMonoMarshal::mono_string_from_godot(str);
-}
-
-MonoObject *godot_icall_GD_str2var(MonoString *p_str) {
- Variant ret;
-
- VariantParser::StreamString ss;
- ss.s = GDMonoMarshal::mono_string_to_godot(p_str);
-
- String errs;
- int line;
- Error err = VariantParser::parse(&ss, ret, errs, line);
- if (err != OK) {
- String err_str = "Parse error at line " + itos(line) + ": " + errs + ".";
- ERR_PRINT(err_str);
- ret = err_str;
- }
-
- return GDMonoMarshal::variant_to_mono_object(ret);
-}
-
-MonoBoolean godot_icall_GD_type_exists(StringName *p_type) {
- StringName type = p_type ? *p_type : StringName();
- return ClassDB::class_exists(type);
-}
-
-void godot_icall_GD_pusherror(MonoString *p_str) {
- ERR_PRINT(GDMonoMarshal::mono_string_to_godot(p_str));
-}
-
-void godot_icall_GD_pushwarning(MonoString *p_str) {
- WARN_PRINT(GDMonoMarshal::mono_string_to_godot(p_str));
-}
-
-MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var, MonoBoolean p_full_objects) {
- Variant var = GDMonoMarshal::mono_object_to_variant(p_var);
-
- PackedByteArray barr;
- int len;
- Error err = encode_variant(var, nullptr, len, p_full_objects);
- ERR_FAIL_COND_V_MSG(err != OK, nullptr, "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).");
-
- barr.resize(len);
- encode_variant(var, barr.ptrw(), len, p_full_objects);
-
- return GDMonoMarshal::PackedByteArray_to_mono_array(barr);
-}
-
-MonoString *godot_icall_GD_var2str(MonoObject *p_var) {
- String vars;
- VariantWriter::write_to_string(GDMonoMarshal::mono_object_to_variant(p_var), vars);
- return GDMonoMarshal::mono_string_from_godot(vars);
-}
-
-uint32_t godot_icall_TypeToVariantType(MonoReflectionType *p_refl_type) {
- return (uint32_t)GDMonoMarshal::managed_to_variant_type(ManagedType::from_reftype(p_refl_type));
-}
-
-MonoObject *godot_icall_DefaultGodotTaskScheduler() {
- return GDMonoCache::cached_data.task_scheduler_handle->get_target();
-}
-
-void godot_register_gd_icalls() {
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_bytes2var", godot_icall_GD_bytes2var);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_convert", godot_icall_GD_convert);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_hash", godot_icall_GD_hash);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_instance_from_id", godot_icall_GD_instance_from_id);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_pusherror", godot_icall_GD_pusherror);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_pushwarning", godot_icall_GD_pushwarning);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_print", godot_icall_GD_print);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_print_rich", godot_icall_GD_print_rich);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_printerr", godot_icall_GD_printerr);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_printraw", godot_icall_GD_printraw);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_prints", godot_icall_GD_prints);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_printt", godot_icall_GD_printt);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randomize", godot_icall_GD_randomize);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randi", godot_icall_GD_randi);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randf", godot_icall_GD_randf);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randi_range", godot_icall_GD_randi_range);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randf_range", godot_icall_GD_randf_range);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_randfn", godot_icall_GD_randfn);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_rand_seed", godot_icall_GD_rand_seed);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_seed", godot_icall_GD_seed);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_str", godot_icall_GD_str);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_str2var", godot_icall_GD_str2var);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_type_exists", godot_icall_GD_type_exists);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_var2bytes", godot_icall_GD_var2bytes);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_GD_var2str", godot_icall_GD_var2str);
- GDMonoUtils::add_internal_call("Godot.GD::godot_icall_TypeToVariantType", godot_icall_TypeToVariantType);
-
- // Dispatcher
- GDMonoUtils::add_internal_call("Godot.Dispatcher::godot_icall_DefaultGodotTaskScheduler", godot_icall_DefaultGodotTaskScheduler);
-}
-
-#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h
deleted file mode 100644
index f9ad1a9893..0000000000
--- a/modules/mono/glue/glue_header.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*************************************************************************/
-/* glue_header.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GLUE_HEADER_H
-#define GLUE_HEADER_H
-
-#ifdef MONO_GLUE_ENABLED
-
-#include "../mono_gd/gd_mono_marshal.h"
-
-void godot_register_collections_icalls();
-void godot_register_gd_icalls();
-void godot_register_string_name_icalls();
-void godot_register_nodepath_icalls();
-void godot_register_callable_icalls();
-void godot_register_object_icalls();
-void godot_register_rid_icalls();
-void godot_register_string_icalls();
-void godot_register_scene_tree_icalls();
-
-/**
- * Registers internal calls that were not generated. This function is called
- * from the generated GodotSharpBindings::register_generated_icalls() function.
- */
-void godot_register_glue_header_icalls() {
- godot_register_collections_icalls();
- godot_register_gd_icalls();
- godot_register_string_name_icalls();
- godot_register_nodepath_icalls();
- godot_register_callable_icalls();
- godot_register_object_icalls();
- godot_register_rid_icalls();
- godot_register_string_icalls();
- godot_register_scene_tree_icalls();
-}
-
-// Used by the generated glue
-
-#include "core/config/engine.h"
-#include "core/object/class_db.h"
-#include "core/object/method_bind.h"
-#include "core/object/ref_counted.h"
-#include "core/string/node_path.h"
-#include "core/string/ustring.h"
-#include "core/typedefs.h"
-#include "core/variant/array.h"
-#include "core/variant/dictionary.h"
-
-#include "../mono_gd/gd_mono_class.h"
-#include "../mono_gd/gd_mono_internals.h"
-#include "../mono_gd/gd_mono_utils.h"
-
-#define GODOTSHARP_INSTANCE_OBJECT(m_instance, m_type) \
- static ClassDB::ClassInfo *ci = nullptr; \
- if (!ci) { \
- ci = ClassDB::classes.getptr(m_type); \
- } \
- Object *m_instance = ci->creation_func();
-
-#include "arguments_vector.h"
-
-#endif // MONO_GLUE_ENABLED
-
-#endif // GLUE_HEADER_H
diff --git a/modules/mono/glue/nodepath_glue.cpp b/modules/mono/glue/nodepath_glue.cpp
deleted file mode 100644
index 16e1509eb0..0000000000
--- a/modules/mono/glue/nodepath_glue.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*************************************************************************/
-/* nodepath_glue.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifdef MONO_GLUE_ENABLED
-
-#include "core/string/node_path.h"
-#include "core/string/ustring.h"
-
-#include "../mono_gd/gd_mono_marshal.h"
-
-NodePath *godot_icall_NodePath_Ctor(MonoString *p_path) {
- return memnew(NodePath(GDMonoMarshal::mono_string_to_godot(p_path)));
-}
-
-void godot_icall_NodePath_Dtor(NodePath *p_ptr) {
- ERR_FAIL_NULL(p_ptr);
- memdelete(p_ptr);
-}
-
-MonoString *godot_icall_NodePath_operator_String(NodePath *p_np) {
- return GDMonoMarshal::mono_string_from_godot(p_np->operator String());
-}
-
-MonoBoolean godot_icall_NodePath_is_absolute(NodePath *p_ptr) {
- return (MonoBoolean)p_ptr->is_absolute();
-}
-
-int32_t godot_icall_NodePath_get_name_count(NodePath *p_ptr) {
- return p_ptr->get_name_count();
-}
-
-MonoString *godot_icall_NodePath_get_name(NodePath *p_ptr, uint32_t p_idx) {
- return GDMonoMarshal::mono_string_from_godot(p_ptr->get_name(p_idx));
-}
-
-int32_t godot_icall_NodePath_get_subname_count(NodePath *p_ptr) {
- return p_ptr->get_subname_count();
-}
-
-MonoString *godot_icall_NodePath_get_subname(NodePath *p_ptr, uint32_t p_idx) {
- return GDMonoMarshal::mono_string_from_godot(p_ptr->get_subname(p_idx));
-}
-
-MonoString *godot_icall_NodePath_get_concatenated_names(NodePath *p_ptr) {
- return GDMonoMarshal::mono_string_from_godot(p_ptr->get_concatenated_names());
-}
-
-MonoString *godot_icall_NodePath_get_concatenated_subnames(NodePath *p_ptr) {
- return GDMonoMarshal::mono_string_from_godot(p_ptr->get_concatenated_subnames());
-}
-
-NodePath *godot_icall_NodePath_get_as_property_path(NodePath *p_ptr) {
- return memnew(NodePath(p_ptr->get_as_property_path()));
-}
-
-MonoBoolean godot_icall_NodePath_is_empty(NodePath *p_ptr) {
- return (MonoBoolean)p_ptr->is_empty();
-}
-
-void godot_register_nodepath_icalls() {
- GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_Ctor", godot_icall_NodePath_Ctor);
- GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_Dtor", godot_icall_NodePath_Dtor);
- GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_operator_String", godot_icall_NodePath_operator_String);
- GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_as_property_path", godot_icall_NodePath_get_as_property_path);
- GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_concatenated_names", godot_icall_NodePath_get_concatenated_names);
- GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_concatenated_subnames", godot_icall_NodePath_get_concatenated_subnames);
- GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_name", godot_icall_NodePath_get_name);
- GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_name_count", godot_icall_NodePath_get_name_count);
- GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_subname", godot_icall_NodePath_get_subname);
- GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_subname_count", godot_icall_NodePath_get_subname_count);
- GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_is_absolute", godot_icall_NodePath_is_absolute);
- GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_is_empty", godot_icall_NodePath_is_empty);
-}
-
-#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/runtime_interop.cpp b/modules/mono/glue/runtime_interop.cpp
new file mode 100644
index 0000000000..0d68cb54b9
--- /dev/null
+++ b/modules/mono/glue/runtime_interop.cpp
@@ -0,0 +1,1513 @@
+/*************************************************************************/
+/* runtime_interop.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "runtime_interop.h"
+
+#include "core/config/engine.h"
+#include "core/debugger/engine_debugger.h"
+#include "core/debugger/script_debugger.h"
+#include "core/io/marshalls.h"
+#include "core/object/class_db.h"
+#include "core/object/method_bind.h"
+#include "core/os/os.h"
+#include "core/string/string_name.h"
+
+#include "../interop_types.h"
+
+#include "modules/mono/csharp_script.h"
+#include "modules/mono/managed_callable.h"
+#include "modules/mono/mono_gd/gd_mono_cache.h"
+#include "modules/mono/signal_awaiter_utils.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// For ArrayPrivate and DictionaryPrivate
+static_assert(sizeof(SafeRefCount) == sizeof(uint32_t));
+
+typedef Object *(*godotsharp_class_creation_func)();
+
+MethodBind *godotsharp_method_bind_get_method(const StringName *p_classname, const StringName *p_methodname) {
+ return ClassDB::get_method(*p_classname, *p_methodname);
+}
+
+godotsharp_class_creation_func godotsharp_get_class_constructor(const StringName *p_classname) {
+ ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(*p_classname);
+ if (class_info) {
+ return class_info->creation_func;
+ }
+ return nullptr;
+}
+
+Object *godotsharp_engine_get_singleton(const String *p_name) {
+ return Engine::get_singleton()->get_singleton_object(*p_name);
+}
+
+int32_t godotsharp_stack_info_vector_resize(
+ Vector<ScriptLanguage::StackInfo> *p_stack_info_vector, int p_size) {
+ return (int32_t)p_stack_info_vector->resize(p_size);
+}
+
+void godotsharp_stack_info_vector_destroy(
+ Vector<ScriptLanguage::StackInfo> *p_stack_info_vector) {
+ p_stack_info_vector->~Vector();
+}
+
+void godotsharp_internal_script_debugger_send_error(const String *p_func,
+ const String *p_file, int32_t p_line, const String *p_err, const String *p_descr,
+ bool p_warning, const Vector<ScriptLanguage::StackInfo> *p_stack_info_vector) {
+ EngineDebugger::get_script_debugger()->send_error(*p_func, *p_file, p_line, *p_err, *p_descr,
+ true, p_warning ? ERR_HANDLER_WARNING : ERR_HANDLER_ERROR, *p_stack_info_vector);
+}
+
+bool godotsharp_internal_script_debugger_is_active() {
+ return EngineDebugger::is_active();
+}
+
+GCHandleIntPtr godotsharp_internal_object_get_associated_gchandle(Object *p_ptr) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(p_ptr == nullptr);
+#endif
+
+ if (p_ptr->get_script_instance()) {
+ CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_ptr->get_script_instance());
+ if (cs_instance) {
+ if (!cs_instance->is_destructing_script_instance()) {
+ return cs_instance->get_gchandle_intptr();
+ }
+ return { nullptr };
+ }
+ }
+
+ void *data = CSharpLanguage::get_existing_instance_binding(p_ptr);
+
+ if (data) {
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
+ if (script_binding.inited) {
+ MonoGCHandleData &gchandle = script_binding.gchandle;
+ return !gchandle.is_released() ? gchandle.get_intptr() : GCHandleIntPtr{ nullptr };
+ }
+ }
+
+ return { nullptr };
+}
+
+void godotsharp_internal_object_disposed(Object *p_ptr, GCHandleIntPtr p_gchandle_to_free) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(p_ptr == nullptr);
+#endif
+
+ if (p_ptr->get_script_instance()) {
+ CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_ptr->get_script_instance());
+ if (cs_instance) {
+ if (!cs_instance->is_destructing_script_instance()) {
+ cs_instance->mono_object_disposed(p_gchandle_to_free);
+ p_ptr->set_script_instance(nullptr);
+ }
+ return;
+ }
+ }
+
+ void *data = CSharpLanguage::get_existing_instance_binding(p_ptr);
+
+ if (data) {
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
+ if (script_binding.inited) {
+ if (!script_binding.gchandle.is_released()) {
+ CSharpLanguage::release_binding_gchandle_thread_safe(p_gchandle_to_free, script_binding);
+ }
+ }
+ }
+}
+
+void godotsharp_internal_refcounted_disposed(Object *p_ptr, GCHandleIntPtr p_gchandle_to_free, bool p_is_finalizer) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(p_ptr == nullptr);
+ // This is only called with RefCounted derived classes
+ CRASH_COND(!Object::cast_to<RefCounted>(p_ptr));
+#endif
+
+ RefCounted *rc = static_cast<RefCounted *>(p_ptr);
+
+ if (rc->get_script_instance()) {
+ CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(rc->get_script_instance());
+ if (cs_instance) {
+ if (!cs_instance->is_destructing_script_instance()) {
+ bool delete_owner;
+ bool remove_script_instance;
+
+ cs_instance->mono_object_disposed_baseref(p_gchandle_to_free, p_is_finalizer,
+ delete_owner, remove_script_instance);
+
+ if (delete_owner) {
+ memdelete(rc);
+ } else if (remove_script_instance) {
+ rc->set_script_instance(nullptr);
+ }
+ }
+ return;
+ }
+ }
+
+ // Unsafe refcount decrement. The managed instance also counts as a reference.
+ // See: CSharpLanguage::alloc_instance_binding_data(Object *p_object)
+ CSharpLanguage::get_singleton()->pre_unsafe_unreference(rc);
+ if (rc->unreference()) {
+ memdelete(rc);
+ } else {
+ void *data = CSharpLanguage::get_existing_instance_binding(rc);
+
+ if (data) {
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
+ if (script_binding.inited) {
+ if (!script_binding.gchandle.is_released()) {
+ CSharpLanguage::release_binding_gchandle_thread_safe(p_gchandle_to_free, script_binding);
+ }
+ }
+ }
+ }
+}
+
+int32_t godotsharp_internal_signal_awaiter_connect(Object *p_source, StringName *p_signal, Object *p_target, GCHandleIntPtr p_awaiter_handle_ptr) {
+ StringName signal = p_signal ? *p_signal : StringName();
+ return (int32_t)gd_mono_connect_signal_awaiter(p_source, signal, p_target, p_awaiter_handle_ptr);
+}
+
+GCHandleIntPtr godotsharp_internal_unmanaged_get_script_instance_managed(Object *p_unmanaged, bool *r_has_cs_script_instance) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!p_unmanaged);
+ CRASH_COND(!r_has_cs_script_instance);
+#endif
+
+ if (p_unmanaged->get_script_instance()) {
+ CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(p_unmanaged->get_script_instance());
+
+ if (cs_instance) {
+ *r_has_cs_script_instance = true;
+ return cs_instance->get_gchandle_intptr();
+ }
+ }
+
+ *r_has_cs_script_instance = false;
+ return { nullptr };
+}
+
+GCHandleIntPtr godotsharp_internal_unmanaged_get_instance_binding_managed(Object *p_unmanaged) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!p_unmanaged);
+#endif
+
+ void *data = CSharpLanguage::get_instance_binding(p_unmanaged);
+ ERR_FAIL_NULL_V(data, { nullptr });
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->value();
+ ERR_FAIL_COND_V(!script_binding.inited, { nullptr });
+
+ return script_binding.gchandle.get_intptr();
+}
+
+GCHandleIntPtr godotsharp_internal_unmanaged_instance_binding_create_managed(Object *p_unmanaged, GCHandleIntPtr p_old_gchandle) {
+#ifdef DEBUG_ENABLED
+ CRASH_COND(!p_unmanaged);
+#endif
+
+ void *data = CSharpLanguage::get_instance_binding(p_unmanaged);
+ ERR_FAIL_NULL_V(data, { nullptr });
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->value();
+ ERR_FAIL_COND_V(!script_binding.inited, { nullptr });
+
+ MonoGCHandleData &gchandle = script_binding.gchandle;
+
+ // TODO: Possible data race?
+ CRASH_COND(gchandle.get_intptr().value != p_old_gchandle.value);
+
+ CSharpLanguage::get_singleton()->release_script_gchandle(gchandle);
+ script_binding.inited = false;
+
+ // Create a new one
+
+#ifdef DEBUG_ENABLED
+ CRASH_COND(script_binding.type_name == StringName());
+#endif
+
+ bool parent_is_object_class = ClassDB::is_parent_class(p_unmanaged->get_class_name(), script_binding.type_name);
+ ERR_FAIL_COND_V_MSG(!parent_is_object_class, { nullptr },
+ "Type inherits from native type '" + script_binding.type_name + "', so it can't be instantiated in object of type: '" + p_unmanaged->get_class() + "'.");
+
+ GCHandleIntPtr strong_gchandle =
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_CreateManagedForGodotObjectBinding(
+ &script_binding.type_name, p_unmanaged);
+
+ ERR_FAIL_NULL_V(strong_gchandle.value, { nullptr });
+
+ gchandle = MonoGCHandleData(strong_gchandle, gdmono::GCHandleType::STRONG_HANDLE);
+ script_binding.inited = true;
+
+ // Tie managed to unmanaged
+ RefCounted *rc = Object::cast_to<RefCounted>(p_unmanaged);
+
+ if (rc) {
+ // Unsafe refcount increment. The managed instance also counts as a reference.
+ // This way if the unmanaged world has no references to our owner
+ // but the managed instance is alive, the refcount will be 1 instead of 0.
+ // See: godot_icall_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr)
+ rc->reference();
+ CSharpLanguage::get_singleton()->post_unsafe_reference(rc);
+ }
+
+ return gchandle.get_intptr();
+}
+
+void godotsharp_internal_tie_native_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, const StringName *p_native_name, bool p_ref_counted) {
+ CSharpLanguage::tie_native_managed_to_unmanaged(p_gchandle_intptr, p_unmanaged, p_native_name, p_ref_counted);
+}
+
+void godotsharp_internal_tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, Ref<CSharpScript> *p_script, bool p_ref_counted) {
+ CSharpLanguage::tie_user_managed_to_unmanaged(p_gchandle_intptr, p_unmanaged, p_script, p_ref_counted);
+}
+
+void godotsharp_internal_tie_managed_to_unmanaged_with_pre_setup(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged) {
+ CSharpLanguage::tie_managed_to_unmanaged_with_pre_setup(p_gchandle_intptr, p_unmanaged);
+}
+
+void godotsharp_internal_new_csharp_script(Ref<CSharpScript> *r_dest) {
+ memnew_placement(r_dest, Ref<CSharpScript>(memnew(CSharpScript)));
+}
+
+bool godotsharp_internal_script_load(const String *p_path, Ref<CSharpScript> *r_dest) {
+ Ref<Resource> res = ResourceLoader::load(*p_path);
+ if (res.is_valid()) {
+ memnew_placement(r_dest, Ref<CSharpScript>(res));
+ return true;
+ } else {
+ memnew_placement(r_dest, Ref<CSharpScript>());
+ return false;
+ }
+}
+
+void godotsharp_internal_reload_registered_script(CSharpScript *p_script) {
+ CRASH_COND(!p_script);
+ CSharpScript::reload_registered_script(Ref<CSharpScript>(p_script));
+}
+
+void godotsharp_array_filter_godot_objects_by_native(StringName *p_native_name, const Array *p_input, Array *r_output) {
+ memnew_placement(r_output, Array);
+
+ for (int i = 0; i < p_input->size(); ++i) {
+ if (ClassDB::is_parent_class(((Object *)(*p_input)[i])->get_class(), *p_native_name)) {
+ r_output->push_back(p_input[i]);
+ }
+ }
+}
+
+void godotsharp_array_filter_godot_objects_by_non_native(const Array *p_input, Array *r_output) {
+ memnew_placement(r_output, Array);
+
+ for (int i = 0; i < p_input->size(); ++i) {
+ CSharpInstance *si = CAST_CSHARP_INSTANCE(((Object *)(*p_input)[i])->get_script_instance());
+
+ if (si != nullptr) {
+ r_output->push_back(p_input[i]);
+ }
+ }
+}
+
+void godotsharp_ref_new_from_ref_counted_ptr(Ref<RefCounted> *r_dest, RefCounted *p_ref_counted_ptr) {
+ memnew_placement(r_dest, Ref<RefCounted>(p_ref_counted_ptr));
+}
+
+void godotsharp_ref_destroy(Ref<RefCounted> *p_instance) {
+ p_instance->~Ref();
+}
+
+void godotsharp_string_name_new_from_string(StringName *r_dest, const String *p_name) {
+ memnew_placement(r_dest, StringName(*p_name));
+}
+
+void godotsharp_node_path_new_from_string(NodePath *r_dest, const String *p_name) {
+ memnew_placement(r_dest, NodePath(*p_name));
+}
+
+void godotsharp_string_name_as_string(String *r_dest, const StringName *p_name) {
+ memnew_placement(r_dest, String(p_name->operator String()));
+}
+
+void godotsharp_node_path_as_string(String *r_dest, const NodePath *p_np) {
+ memnew_placement(r_dest, String(p_np->operator String()));
+}
+
+godot_packed_array godotsharp_packed_byte_array_new_mem_copy(const uint8_t *p_src, int32_t p_length) {
+ godot_packed_array ret;
+ memnew_placement(&ret, PackedByteArray);
+ PackedByteArray *array = reinterpret_cast<PackedByteArray *>(&ret);
+ array->resize(p_length);
+ uint8_t *dst = array->ptrw();
+ memcpy(dst, p_src, p_length * sizeof(uint8_t));
+ return ret;
+}
+
+godot_packed_array godotsharp_packed_int32_array_new_mem_copy(const int32_t *p_src, int32_t p_length) {
+ godot_packed_array ret;
+ memnew_placement(&ret, PackedInt32Array);
+ PackedInt32Array *array = reinterpret_cast<PackedInt32Array *>(&ret);
+ array->resize(p_length);
+ int32_t *dst = array->ptrw();
+ memcpy(dst, p_src, p_length * sizeof(int32_t));
+ return ret;
+}
+
+godot_packed_array godotsharp_packed_int64_array_new_mem_copy(const int64_t *p_src, int32_t p_length) {
+ godot_packed_array ret;
+ memnew_placement(&ret, PackedInt64Array);
+ PackedInt64Array *array = reinterpret_cast<PackedInt64Array *>(&ret);
+ array->resize(p_length);
+ int64_t *dst = array->ptrw();
+ memcpy(dst, p_src, p_length * sizeof(int64_t));
+ return ret;
+}
+
+godot_packed_array godotsharp_packed_float32_array_new_mem_copy(const float *p_src, int32_t p_length) {
+ godot_packed_array ret;
+ memnew_placement(&ret, PackedFloat32Array);
+ PackedFloat32Array *array = reinterpret_cast<PackedFloat32Array *>(&ret);
+ array->resize(p_length);
+ float *dst = array->ptrw();
+ memcpy(dst, p_src, p_length * sizeof(float));
+ return ret;
+}
+
+godot_packed_array godotsharp_packed_float64_array_new_mem_copy(const double *p_src, int32_t p_length) {
+ godot_packed_array ret;
+ memnew_placement(&ret, PackedFloat64Array);
+ PackedFloat64Array *array = reinterpret_cast<PackedFloat64Array *>(&ret);
+ array->resize(p_length);
+ double *dst = array->ptrw();
+ memcpy(dst, p_src, p_length * sizeof(double));
+ return ret;
+}
+
+godot_packed_array godotsharp_packed_vector2_array_new_mem_copy(const Vector2 *p_src, int32_t p_length) {
+ godot_packed_array ret;
+ memnew_placement(&ret, PackedVector2Array);
+ PackedVector2Array *array = reinterpret_cast<PackedVector2Array *>(&ret);
+ array->resize(p_length);
+ Vector2 *dst = array->ptrw();
+ memcpy(dst, p_src, p_length * sizeof(Vector2));
+ return ret;
+}
+
+godot_packed_array godotsharp_packed_vector3_array_new_mem_copy(const Vector3 *p_src, int32_t p_length) {
+ godot_packed_array ret;
+ memnew_placement(&ret, PackedVector3Array);
+ PackedVector3Array *array = reinterpret_cast<PackedVector3Array *>(&ret);
+ array->resize(p_length);
+ Vector3 *dst = array->ptrw();
+ memcpy(dst, p_src, p_length * sizeof(Vector3));
+ return ret;
+}
+
+godot_packed_array godotsharp_packed_color_array_new_mem_copy(const Color *p_src, int32_t p_length) {
+ godot_packed_array ret;
+ memnew_placement(&ret, PackedColorArray);
+ PackedColorArray *array = reinterpret_cast<PackedColorArray *>(&ret);
+ array->resize(p_length);
+ Color *dst = array->ptrw();
+ memcpy(dst, p_src, p_length * sizeof(Color));
+ return ret;
+}
+
+void godotsharp_packed_string_array_add(PackedStringArray *r_dest, const String *p_element) {
+ r_dest->append(*p_element);
+}
+
+void godotsharp_callable_new_with_delegate(GCHandleIntPtr p_delegate_handle, Callable *r_callable) {
+ // TODO: Use pooling for ManagedCallable instances.
+ CallableCustom *managed_callable = memnew(ManagedCallable(p_delegate_handle));
+ memnew_placement(r_callable, Callable(managed_callable));
+}
+
+bool godotsharp_callable_get_data_for_marshalling(const Callable *p_callable,
+ GCHandleIntPtr *r_delegate_handle, Object **r_object, StringName *r_name) {
+ if (p_callable->is_custom()) {
+ CallableCustom *custom = p_callable->get_custom();
+ CallableCustom::CompareEqualFunc compare_equal_func = custom->get_compare_equal_func();
+
+ if (compare_equal_func == ManagedCallable::compare_equal_func_ptr) {
+ ManagedCallable *managed_callable = static_cast<ManagedCallable *>(custom);
+ *r_delegate_handle = managed_callable->get_delegate();
+ *r_object = nullptr;
+ memnew_placement(r_name, StringName());
+ return true;
+ } else if (compare_equal_func == SignalAwaiterCallable::compare_equal_func_ptr) {
+ SignalAwaiterCallable *signal_awaiter_callable = static_cast<SignalAwaiterCallable *>(custom);
+ *r_delegate_handle = { nullptr };
+ *r_object = ObjectDB::get_instance(signal_awaiter_callable->get_object());
+ memnew_placement(r_name, StringName(signal_awaiter_callable->get_signal()));
+ return true;
+ } else if (compare_equal_func == EventSignalCallable::compare_equal_func_ptr) {
+ EventSignalCallable *event_signal_callable = static_cast<EventSignalCallable *>(custom);
+ *r_delegate_handle = { nullptr };
+ *r_object = ObjectDB::get_instance(event_signal_callable->get_object());
+ memnew_placement(r_name, StringName(event_signal_callable->get_signal()));
+ return true;
+ }
+
+ // Some other CallableCustom. We only support ManagedCallable.
+ *r_delegate_handle = { nullptr };
+ *r_object = nullptr;
+ memnew_placement(r_name, StringName());
+ return false;
+ } else {
+ *r_delegate_handle = { nullptr };
+ *r_object = ObjectDB::get_instance(p_callable->get_object_id());
+ memnew_placement(r_name, StringName(p_callable->get_method()));
+ return true;
+ }
+}
+
+godot_variant godotsharp_callable_call(Callable *p_callable, const Variant **p_args, const int32_t p_arg_count, Callable::CallError *p_call_error) {
+ godot_variant ret;
+ memnew_placement(&ret, Variant);
+
+ Variant *ret_val = (Variant *)&ret;
+
+ p_callable->callp(p_args, p_arg_count, *ret_val, *p_call_error);
+
+ return ret;
+}
+
+void godotsharp_callable_call_deferred(Callable *p_callable, const Variant **p_args, const int32_t p_arg_count) {
+ p_callable->call_deferredp(p_args, p_arg_count);
+}
+
+// GDNative functions
+
+// gdnative.h
+
+void godotsharp_method_bind_ptrcall(MethodBind *p_method_bind, Object *p_instance, const void **p_args, void *p_ret) {
+ p_method_bind->ptrcall(p_instance, p_args, p_ret);
+}
+
+godot_variant godotsharp_method_bind_call(MethodBind *p_method_bind, Object *p_instance, const godot_variant **p_args, const int32_t p_arg_count, Callable::CallError *p_call_error) {
+ godot_variant ret;
+ memnew_placement(&ret, Variant());
+
+ Variant *ret_val = (Variant *)&ret;
+
+ *ret_val = p_method_bind->call(p_instance, (const Variant **)p_args, p_arg_count, *p_call_error);
+
+ return ret;
+}
+
+// variant.h
+
+void godotsharp_variant_new_copy(godot_variant *r_dest, const Variant *p_src) {
+ memnew_placement(r_dest, Variant(*p_src));
+}
+
+void godotsharp_variant_new_string_name(godot_variant *r_dest, const StringName *p_s) {
+ memnew_placement(r_dest, Variant(*p_s));
+}
+
+void godotsharp_variant_new_node_path(godot_variant *r_dest, const NodePath *p_np) {
+ memnew_placement(r_dest, Variant(*p_np));
+}
+
+void godotsharp_variant_new_object(godot_variant *r_dest, const Object *p_obj) {
+ memnew_placement(r_dest, Variant(p_obj));
+}
+
+void godotsharp_variant_new_transform2d(godot_variant *r_dest, const Transform2D *p_t2d) {
+ memnew_placement(r_dest, Variant(*p_t2d));
+}
+
+void godotsharp_variant_new_vector4(godot_variant *r_dest, const Vector4 *p_vec4) {
+ memnew_placement(r_dest, Variant(*p_vec4));
+}
+
+void godotsharp_variant_new_vector4i(godot_variant *r_dest, const Vector4i *p_vec4i) {
+ memnew_placement(r_dest, Variant(*p_vec4i));
+}
+
+void godotsharp_variant_new_basis(godot_variant *r_dest, const Basis *p_basis) {
+ memnew_placement(r_dest, Variant(*p_basis));
+}
+
+void godotsharp_variant_new_transform3d(godot_variant *r_dest, const Transform3D *p_trans) {
+ memnew_placement(r_dest, Variant(*p_trans));
+}
+
+void godotsharp_variant_new_projection(godot_variant *r_dest, const Projection *p_proj) {
+ memnew_placement(r_dest, Variant(*p_proj));
+}
+
+void godotsharp_variant_new_aabb(godot_variant *r_dest, const AABB *p_aabb) {
+ memnew_placement(r_dest, Variant(*p_aabb));
+}
+
+void godotsharp_variant_new_dictionary(godot_variant *r_dest, const Dictionary *p_dict) {
+ memnew_placement(r_dest, Variant(*p_dict));
+}
+
+void godotsharp_variant_new_array(godot_variant *r_dest, const Array *p_arr) {
+ memnew_placement(r_dest, Variant(*p_arr));
+}
+
+void godotsharp_variant_new_packed_byte_array(godot_variant *r_dest, const PackedByteArray *p_pba) {
+ memnew_placement(r_dest, Variant(*p_pba));
+}
+
+void godotsharp_variant_new_packed_int32_array(godot_variant *r_dest, const PackedInt32Array *p_pia) {
+ memnew_placement(r_dest, Variant(*p_pia));
+}
+
+void godotsharp_variant_new_packed_int64_array(godot_variant *r_dest, const PackedInt64Array *p_pia) {
+ memnew_placement(r_dest, Variant(*p_pia));
+}
+
+void godotsharp_variant_new_packed_float32_array(godot_variant *r_dest, const PackedFloat32Array *p_pra) {
+ memnew_placement(r_dest, Variant(*p_pra));
+}
+
+void godotsharp_variant_new_packed_float64_array(godot_variant *r_dest, const PackedFloat64Array *p_pra) {
+ memnew_placement(r_dest, Variant(*p_pra));
+}
+
+void godotsharp_variant_new_packed_string_array(godot_variant *r_dest, const PackedStringArray *p_psa) {
+ memnew_placement(r_dest, Variant(*p_psa));
+}
+
+void godotsharp_variant_new_packed_vector2_array(godot_variant *r_dest, const PackedVector2Array *p_pv2a) {
+ memnew_placement(r_dest, Variant(*p_pv2a));
+}
+
+void godotsharp_variant_new_packed_vector3_array(godot_variant *r_dest, const PackedVector3Array *p_pv3a) {
+ memnew_placement(r_dest, Variant(*p_pv3a));
+}
+
+void godotsharp_variant_new_packed_color_array(godot_variant *r_dest, const PackedColorArray *p_pca) {
+ memnew_placement(r_dest, Variant(*p_pca));
+}
+
+bool godotsharp_variant_as_bool(const Variant *p_self) {
+ return p_self->operator bool();
+}
+
+int64_t godotsharp_variant_as_int(const Variant *p_self) {
+ return p_self->operator int64_t();
+}
+
+double godotsharp_variant_as_float(const Variant *p_self) {
+ return p_self->operator double();
+}
+
+godot_string godotsharp_variant_as_string(const Variant *p_self) {
+ godot_string raw_dest;
+ String *dest = (String *)&raw_dest;
+ memnew_placement(dest, String(p_self->operator String()));
+ return raw_dest;
+}
+
+godot_vector2 godotsharp_variant_as_vector2(const Variant *p_self) {
+ godot_vector2 raw_dest;
+ Vector2 *dest = (Vector2 *)&raw_dest;
+ memnew_placement(dest, Vector2(p_self->operator Vector2()));
+ return raw_dest;
+}
+
+godot_vector2i godotsharp_variant_as_vector2i(const Variant *p_self) {
+ godot_vector2i raw_dest;
+ Vector2i *dest = (Vector2i *)&raw_dest;
+ memnew_placement(dest, Vector2i(p_self->operator Vector2i()));
+ return raw_dest;
+}
+
+godot_rect2 godotsharp_variant_as_rect2(const Variant *p_self) {
+ godot_rect2 raw_dest;
+ Rect2 *dest = (Rect2 *)&raw_dest;
+ memnew_placement(dest, Rect2(p_self->operator Rect2()));
+ return raw_dest;
+}
+
+godot_rect2i godotsharp_variant_as_rect2i(const Variant *p_self) {
+ godot_rect2i raw_dest;
+ Rect2i *dest = (Rect2i *)&raw_dest;
+ memnew_placement(dest, Rect2i(p_self->operator Rect2i()));
+ return raw_dest;
+}
+
+godot_vector3 godotsharp_variant_as_vector3(const Variant *p_self) {
+ godot_vector3 raw_dest;
+ Vector3 *dest = (Vector3 *)&raw_dest;
+ memnew_placement(dest, Vector3(p_self->operator Vector3()));
+ return raw_dest;
+}
+
+godot_vector3i godotsharp_variant_as_vector3i(const Variant *p_self) {
+ godot_vector3i raw_dest;
+ Vector3i *dest = (Vector3i *)&raw_dest;
+ memnew_placement(dest, Vector3i(p_self->operator Vector3i()));
+ return raw_dest;
+}
+
+godot_transform2d godotsharp_variant_as_transform2d(const Variant *p_self) {
+ godot_transform2d raw_dest;
+ Transform2D *dest = (Transform2D *)&raw_dest;
+ memnew_placement(dest, Transform2D(p_self->operator Transform2D()));
+ return raw_dest;
+}
+
+godot_vector4 godotsharp_variant_as_vector4(const Variant *p_self) {
+ godot_vector4 raw_dest;
+ Vector4 *dest = (Vector4 *)&raw_dest;
+ memnew_placement(dest, Vector4(p_self->operator Vector4()));
+ return raw_dest;
+}
+
+godot_vector4i godotsharp_variant_as_vector4i(const Variant *p_self) {
+ godot_vector4i raw_dest;
+ Vector4i *dest = (Vector4i *)&raw_dest;
+ memnew_placement(dest, Vector4i(p_self->operator Vector4i()));
+ return raw_dest;
+}
+
+godot_plane godotsharp_variant_as_plane(const Variant *p_self) {
+ godot_plane raw_dest;
+ Plane *dest = (Plane *)&raw_dest;
+ memnew_placement(dest, Plane(p_self->operator Plane()));
+ return raw_dest;
+}
+
+godot_quaternion godotsharp_variant_as_quaternion(const Variant *p_self) {
+ godot_quaternion raw_dest;
+ Quaternion *dest = (Quaternion *)&raw_dest;
+ memnew_placement(dest, Quaternion(p_self->operator Quaternion()));
+ return raw_dest;
+}
+
+godot_aabb godotsharp_variant_as_aabb(const Variant *p_self) {
+ godot_aabb raw_dest;
+ AABB *dest = (AABB *)&raw_dest;
+ memnew_placement(dest, AABB(p_self->operator ::AABB()));
+ return raw_dest;
+}
+
+godot_basis godotsharp_variant_as_basis(const Variant *p_self) {
+ godot_basis raw_dest;
+ Basis *dest = (Basis *)&raw_dest;
+ memnew_placement(dest, Basis(p_self->operator Basis()));
+ return raw_dest;
+}
+
+godot_transform3d godotsharp_variant_as_transform3d(const Variant *p_self) {
+ godot_transform3d raw_dest;
+ Transform3D *dest = (Transform3D *)&raw_dest;
+ memnew_placement(dest, Transform3D(p_self->operator Transform3D()));
+ return raw_dest;
+}
+
+godot_projection godotsharp_variant_as_projection(const Variant *p_self) {
+ godot_projection raw_dest;
+ Projection *dest = (Projection *)&raw_dest;
+ memnew_placement(dest, Projection(p_self->operator Projection()));
+ return raw_dest;
+}
+
+godot_color godotsharp_variant_as_color(const Variant *p_self) {
+ godot_color raw_dest;
+ Color *dest = (Color *)&raw_dest;
+ memnew_placement(dest, Color(p_self->operator Color()));
+ return raw_dest;
+}
+
+godot_string_name godotsharp_variant_as_string_name(const Variant *p_self) {
+ godot_string_name raw_dest;
+ StringName *dest = (StringName *)&raw_dest;
+ memnew_placement(dest, StringName(p_self->operator StringName()));
+ return raw_dest;
+}
+
+godot_node_path godotsharp_variant_as_node_path(const Variant *p_self) {
+ godot_node_path raw_dest;
+ NodePath *dest = (NodePath *)&raw_dest;
+ memnew_placement(dest, NodePath(p_self->operator NodePath()));
+ return raw_dest;
+}
+
+godot_rid godotsharp_variant_as_rid(const Variant *p_self) {
+ godot_rid raw_dest;
+ RID *dest = (RID *)&raw_dest;
+ memnew_placement(dest, RID(p_self->operator ::RID()));
+ return raw_dest;
+}
+
+godot_callable godotsharp_variant_as_callable(const Variant *p_self) {
+ godot_callable raw_dest;
+ Callable *dest = (Callable *)&raw_dest;
+ memnew_placement(dest, Callable(p_self->operator Callable()));
+ return raw_dest;
+}
+
+godot_signal godotsharp_variant_as_signal(const Variant *p_self) {
+ godot_signal raw_dest;
+ Signal *dest = (Signal *)&raw_dest;
+ memnew_placement(dest, Signal(p_self->operator Signal()));
+ return raw_dest;
+}
+
+godot_dictionary godotsharp_variant_as_dictionary(const Variant *p_self) {
+ godot_dictionary raw_dest;
+ Dictionary *dest = (Dictionary *)&raw_dest;
+ memnew_placement(dest, Dictionary(p_self->operator Dictionary()));
+ return raw_dest;
+}
+
+godot_array godotsharp_variant_as_array(const Variant *p_self) {
+ godot_array raw_dest;
+ Array *dest = (Array *)&raw_dest;
+ memnew_placement(dest, Array(p_self->operator Array()));
+ return raw_dest;
+}
+
+godot_packed_array godotsharp_variant_as_packed_byte_array(const Variant *p_self) {
+ godot_packed_array raw_dest;
+ PackedByteArray *dest = (PackedByteArray *)&raw_dest;
+ memnew_placement(dest, PackedByteArray(p_self->operator PackedByteArray()));
+ return raw_dest;
+}
+
+godot_packed_array godotsharp_variant_as_packed_int32_array(const Variant *p_self) {
+ godot_packed_array raw_dest;
+ PackedInt32Array *dest = (PackedInt32Array *)&raw_dest;
+ memnew_placement(dest, PackedInt32Array(p_self->operator PackedInt32Array()));
+ return raw_dest;
+}
+
+godot_packed_array godotsharp_variant_as_packed_int64_array(const Variant *p_self) {
+ godot_packed_array raw_dest;
+ PackedInt64Array *dest = (PackedInt64Array *)&raw_dest;
+ memnew_placement(dest, PackedInt64Array(p_self->operator PackedInt64Array()));
+ return raw_dest;
+}
+
+godot_packed_array godotsharp_variant_as_packed_float32_array(const Variant *p_self) {
+ godot_packed_array raw_dest;
+ PackedFloat32Array *dest = (PackedFloat32Array *)&raw_dest;
+ memnew_placement(dest, PackedFloat32Array(p_self->operator PackedFloat32Array()));
+ return raw_dest;
+}
+
+godot_packed_array godotsharp_variant_as_packed_float64_array(const Variant *p_self) {
+ godot_packed_array raw_dest;
+ PackedFloat64Array *dest = (PackedFloat64Array *)&raw_dest;
+ memnew_placement(dest, PackedFloat64Array(p_self->operator PackedFloat64Array()));
+ return raw_dest;
+}
+
+godot_packed_array godotsharp_variant_as_packed_string_array(const Variant *p_self) {
+ godot_packed_array raw_dest;
+ PackedStringArray *dest = (PackedStringArray *)&raw_dest;
+ memnew_placement(dest, PackedStringArray(p_self->operator PackedStringArray()));
+ return raw_dest;
+}
+
+godot_packed_array godotsharp_variant_as_packed_vector2_array(const Variant *p_self) {
+ godot_packed_array raw_dest;
+ PackedVector2Array *dest = (PackedVector2Array *)&raw_dest;
+ memnew_placement(dest, PackedVector2Array(p_self->operator PackedVector2Array()));
+ return raw_dest;
+}
+
+godot_packed_array godotsharp_variant_as_packed_vector3_array(const Variant *p_self) {
+ godot_packed_array raw_dest;
+ PackedVector3Array *dest = (PackedVector3Array *)&raw_dest;
+ memnew_placement(dest, PackedVector3Array(p_self->operator PackedVector3Array()));
+ return raw_dest;
+}
+
+godot_packed_array godotsharp_variant_as_packed_color_array(const Variant *p_self) {
+ godot_packed_array raw_dest;
+ PackedColorArray *dest = (PackedColorArray *)&raw_dest;
+ memnew_placement(dest, PackedColorArray(p_self->operator PackedColorArray()));
+ return raw_dest;
+}
+
+bool godotsharp_variant_equals(const godot_variant *p_a, const godot_variant *p_b) {
+ return *reinterpret_cast<const Variant *>(p_a) == *reinterpret_cast<const Variant *>(p_b);
+}
+
+// string.h
+
+void godotsharp_string_new_with_utf16_chars(String *r_dest, const char16_t *p_contents) {
+ memnew_placement(r_dest, String());
+ r_dest->parse_utf16(p_contents);
+}
+
+// string_name.h
+
+void godotsharp_string_name_new_copy(StringName *r_dest, const StringName *p_src) {
+ memnew_placement(r_dest, StringName(*p_src));
+}
+
+// node_path.h
+
+void godotsharp_node_path_new_copy(NodePath *r_dest, const NodePath *p_src) {
+ memnew_placement(r_dest, NodePath(*p_src));
+}
+
+// array.h
+
+void godotsharp_array_new(Array *r_dest) {
+ memnew_placement(r_dest, Array);
+}
+
+void godotsharp_array_new_copy(Array *r_dest, const Array *p_src) {
+ memnew_placement(r_dest, Array(*p_src));
+}
+
+godot_variant *godotsharp_array_ptrw(godot_array *p_self) {
+ return reinterpret_cast<godot_variant *>(&reinterpret_cast<Array *>(p_self)->operator[](0));
+}
+
+// dictionary.h
+
+void godotsharp_dictionary_new(Dictionary *r_dest) {
+ memnew_placement(r_dest, Dictionary);
+}
+
+void godotsharp_dictionary_new_copy(Dictionary *r_dest, const Dictionary *p_src) {
+ memnew_placement(r_dest, Dictionary(*p_src));
+}
+
+// destroy functions
+
+void godotsharp_packed_byte_array_destroy(PackedByteArray *p_self) {
+ p_self->~PackedByteArray();
+}
+
+void godotsharp_packed_int32_array_destroy(PackedInt32Array *p_self) {
+ p_self->~PackedInt32Array();
+}
+
+void godotsharp_packed_int64_array_destroy(PackedInt64Array *p_self) {
+ p_self->~PackedInt64Array();
+}
+
+void godotsharp_packed_float32_array_destroy(PackedFloat32Array *p_self) {
+ p_self->~PackedFloat32Array();
+}
+
+void godotsharp_packed_float64_array_destroy(PackedFloat64Array *p_self) {
+ p_self->~PackedFloat64Array();
+}
+
+void godotsharp_packed_string_array_destroy(PackedStringArray *p_self) {
+ p_self->~PackedStringArray();
+}
+
+void godotsharp_packed_vector2_array_destroy(PackedVector2Array *p_self) {
+ p_self->~PackedVector2Array();
+}
+
+void godotsharp_packed_vector3_array_destroy(PackedVector3Array *p_self) {
+ p_self->~PackedVector3Array();
+}
+
+void godotsharp_packed_color_array_destroy(PackedColorArray *p_self) {
+ p_self->~PackedColorArray();
+}
+
+void godotsharp_variant_destroy(Variant *p_self) {
+ p_self->~Variant();
+}
+
+void godotsharp_string_destroy(String *p_self) {
+ p_self->~String();
+}
+
+void godotsharp_string_name_destroy(StringName *p_self) {
+ p_self->~StringName();
+}
+
+void godotsharp_node_path_destroy(NodePath *p_self) {
+ p_self->~NodePath();
+}
+
+void godotsharp_signal_destroy(Signal *p_self) {
+ p_self->~Signal();
+}
+
+void godotsharp_callable_destroy(Callable *p_self) {
+ p_self->~Callable();
+}
+
+void godotsharp_array_destroy(Array *p_self) {
+ p_self->~Array();
+}
+
+void godotsharp_dictionary_destroy(Dictionary *p_self) {
+ p_self->~Dictionary();
+}
+
+// Array
+
+int32_t godotsharp_array_add(Array *p_self, const Variant *p_item) {
+ p_self->append(*p_item);
+ return p_self->size();
+}
+
+void godotsharp_array_duplicate(const Array *p_self, bool p_deep, Array *r_dest) {
+ memnew_placement(r_dest, Array(p_self->duplicate(p_deep)));
+}
+
+int32_t godotsharp_array_index_of(const Array *p_self, const Variant *p_item) {
+ return p_self->find(*p_item);
+}
+
+void godotsharp_array_insert(Array *p_self, int32_t p_index, const Variant *p_item) {
+ p_self->insert(p_index, *p_item);
+}
+
+void godotsharp_array_remove_at(Array *p_self, int32_t p_index) {
+ p_self->remove_at(p_index);
+}
+
+int32_t godotsharp_array_resize(Array *p_self, int32_t p_new_size) {
+ return (int32_t)p_self->resize(p_new_size);
+}
+
+void godotsharp_array_shuffle(Array *p_self) {
+ p_self->shuffle();
+}
+
+void godotsharp_array_to_string(const Array *p_self, String *r_str) {
+ *r_str = Variant(*p_self).operator String();
+}
+
+// Dictionary
+
+bool godotsharp_dictionary_try_get_value(const Dictionary *p_self, const Variant *p_key, Variant *r_value) {
+ const Variant *ret = p_self->getptr(*p_key);
+ if (ret == nullptr) {
+ memnew_placement(r_value, Variant());
+ return false;
+ }
+ memnew_placement(r_value, Variant(*ret));
+ return true;
+}
+
+void godotsharp_dictionary_set_value(Dictionary *p_self, const Variant *p_key, const Variant *p_value) {
+ p_self->operator[](*p_key) = *p_value;
+}
+
+void godotsharp_dictionary_keys(const Dictionary *p_self, Array *r_dest) {
+ memnew_placement(r_dest, Array(p_self->keys()));
+}
+
+void godotsharp_dictionary_values(const Dictionary *p_self, Array *r_dest) {
+ memnew_placement(r_dest, Array(p_self->values()));
+}
+
+int32_t godotsharp_dictionary_count(const Dictionary *p_self) {
+ return p_self->size();
+}
+
+void godotsharp_dictionary_key_value_pair_at(const Dictionary *p_self, int32_t p_index, Variant *r_key, Variant *r_value) {
+ memnew_placement(r_key, Variant(p_self->get_key_at_index(p_index)));
+ memnew_placement(r_value, Variant(p_self->get_value_at_index(p_index)));
+}
+
+void godotsharp_dictionary_add(Dictionary *p_self, const Variant *p_key, const Variant *p_value) {
+ p_self->operator[](*p_key) = *p_value;
+}
+
+void godotsharp_dictionary_clear(Dictionary *p_self) {
+ p_self->clear();
+}
+
+bool godotsharp_dictionary_contains_key(const Dictionary *p_self, const Variant *p_key) {
+ return p_self->has(*p_key);
+}
+
+void godotsharp_dictionary_duplicate(const Dictionary *p_self, bool p_deep, Dictionary *r_dest) {
+ memnew_placement(r_dest, Dictionary(p_self->duplicate(p_deep)));
+}
+
+bool godotsharp_dictionary_remove_key(Dictionary *p_self, const Variant *p_key) {
+ return p_self->erase(*p_key);
+}
+
+void godotsharp_dictionary_to_string(const Dictionary *p_self, String *r_str) {
+ *r_str = Variant(*p_self).operator String();
+}
+
+void godotsharp_string_md5_buffer(const String *p_self, PackedByteArray *r_md5_buffer) {
+ memnew_placement(r_md5_buffer, PackedByteArray(p_self->md5_buffer()));
+}
+
+void godotsharp_string_md5_text(const String *p_self, String *r_md5_text) {
+ memnew_placement(r_md5_text, String(p_self->md5_text()));
+}
+
+int32_t godotsharp_string_rfind(const String *p_self, const String *p_what, int32_t p_from) {
+ return p_self->rfind(*p_what, p_from);
+}
+
+int32_t godotsharp_string_rfindn(const String *p_self, const String *p_what, int32_t p_from) {
+ return p_self->rfindn(*p_what, p_from);
+}
+
+void godotsharp_string_sha256_buffer(const String *p_self, PackedByteArray *r_sha256_buffer) {
+ memnew_placement(r_sha256_buffer, PackedByteArray(p_self->sha256_buffer()));
+}
+
+void godotsharp_string_sha256_text(const String *p_self, String *r_sha256_text) {
+ memnew_placement(r_sha256_text, String(p_self->sha256_text()));
+}
+
+void godotsharp_string_simplify_path(const String *p_self, String *r_simplified_path) {
+ memnew_placement(r_simplified_path, String(p_self->simplify_path()));
+}
+
+void godotsharp_node_path_get_as_property_path(const NodePath *p_ptr, NodePath *r_dest) {
+ memnew_placement(r_dest, NodePath(p_ptr->get_as_property_path()));
+}
+
+void godotsharp_node_path_get_concatenated_names(const NodePath *p_self, String *r_subnames) {
+ memnew_placement(r_subnames, String(p_self->get_concatenated_names()));
+}
+
+void godotsharp_node_path_get_concatenated_subnames(const NodePath *p_self, String *r_subnames) {
+ memnew_placement(r_subnames, String(p_self->get_concatenated_subnames()));
+}
+
+void godotsharp_node_path_get_name(const NodePath *p_self, uint32_t p_idx, String *r_name) {
+ memnew_placement(r_name, String(p_self->get_name(p_idx)));
+}
+
+int32_t godotsharp_node_path_get_name_count(const NodePath *p_self) {
+ return p_self->get_name_count();
+}
+
+void godotsharp_node_path_get_subname(const NodePath *p_self, uint32_t p_idx, String *r_subname) {
+ memnew_placement(r_subname, String(p_self->get_subname(p_idx)));
+}
+
+int32_t godotsharp_node_path_get_subname_count(const NodePath *p_self) {
+ return p_self->get_subname_count();
+}
+
+bool godotsharp_node_path_is_absolute(const NodePath *p_self) {
+ return p_self->is_absolute();
+}
+
+void godotsharp_randomize() {
+ Math::randomize();
+}
+
+uint32_t godotsharp_randi() {
+ return Math::rand();
+}
+
+float godotsharp_randf() {
+ return Math::randf();
+}
+
+int32_t godotsharp_randi_range(int32_t p_from, int32_t p_to) {
+ return Math::random(p_from, p_to);
+}
+
+double godotsharp_randf_range(double p_from, double p_to) {
+ return Math::random(p_from, p_to);
+}
+
+double godotsharp_randfn(double p_mean, double p_deviation) {
+ return Math::randfn(p_mean, p_deviation);
+}
+
+void godotsharp_seed(uint64_t p_seed) {
+ Math::seed(p_seed);
+}
+
+uint32_t godotsharp_rand_from_seed(uint64_t p_seed, uint64_t *r_new_seed) {
+ uint32_t ret = Math::rand_from_seed(&p_seed);
+ *r_new_seed = p_seed;
+ return ret;
+}
+
+void godotsharp_weakref(Object *p_ptr, Ref<RefCounted> *r_weak_ref) {
+ if (!p_ptr) {
+ return;
+ }
+
+ Ref<WeakRef> wref;
+ RefCounted *rc = Object::cast_to<RefCounted>(p_ptr);
+
+ if (rc) {
+ Ref<RefCounted> r = rc;
+ if (!r.is_valid()) {
+ return;
+ }
+
+ wref.instantiate();
+ wref->set_ref(r);
+ } else {
+ wref.instantiate();
+ wref->set_obj(p_ptr);
+ }
+
+ memnew_placement(r_weak_ref, Ref<RefCounted>(wref));
+}
+
+void godotsharp_str(const godot_array *p_what, godot_string *r_ret) {
+ String &str = *memnew_placement(r_ret, String);
+ const Array &what = *reinterpret_cast<const Array *>(p_what);
+
+ for (int i = 0; i < what.size(); i++) {
+ String os = what[i].operator String();
+
+ if (i == 0) {
+ str = os;
+ } else {
+ str += os;
+ }
+ }
+}
+
+void godotsharp_print(const godot_string *p_what) {
+ print_line(*reinterpret_cast<const String *>(p_what));
+}
+
+void godotsharp_print_rich(const godot_string *p_what) {
+ print_line_rich(*reinterpret_cast<const String *>(p_what));
+}
+
+void godotsharp_printerr(const godot_string *p_what) {
+ print_error(*reinterpret_cast<const String *>(p_what));
+}
+
+void godotsharp_printt(const godot_string *p_what) {
+ print_line(*reinterpret_cast<const String *>(p_what));
+}
+
+void godotsharp_prints(const godot_string *p_what) {
+ print_line(*reinterpret_cast<const String *>(p_what));
+}
+
+void godotsharp_printraw(const godot_string *p_what) {
+ OS::get_singleton()->print("%s", reinterpret_cast<const String *>(p_what)->utf8().get_data());
+}
+
+void godotsharp_pusherror(const godot_string *p_str) {
+ ERR_PRINT(*reinterpret_cast<const String *>(p_str));
+}
+
+void godotsharp_pushwarning(const godot_string *p_str) {
+ WARN_PRINT(*reinterpret_cast<const String *>(p_str));
+}
+
+void godotsharp_var_to_str(const godot_variant *p_var, godot_string *r_ret) {
+ const Variant &var = *reinterpret_cast<const Variant *>(p_var);
+ String &vars = *memnew_placement(r_ret, String);
+ VariantWriter::write_to_string(var, vars);
+}
+
+void godotsharp_str_to_var(const godot_string *p_str, godot_variant *r_ret) {
+ Variant ret;
+
+ VariantParser::StreamString ss;
+ ss.s = *reinterpret_cast<const String *>(p_str);
+
+ String errs;
+ int line;
+ Error err = VariantParser::parse(&ss, ret, errs, line);
+ if (err != OK) {
+ String err_str = "Parse error at line " + itos(line) + ": " + errs + ".";
+ ERR_PRINT(err_str);
+ ret = err_str;
+ }
+ memnew_placement(r_ret, Variant(ret));
+}
+
+void godotsharp_var_to_bytes(const godot_variant *p_var, bool p_full_objects, godot_packed_array *r_bytes) {
+ const Variant &var = *reinterpret_cast<const Variant *>(p_var);
+ PackedByteArray &bytes = *memnew_placement(r_bytes, PackedByteArray);
+
+ int len;
+ Error err = encode_variant(var, nullptr, len, p_full_objects);
+ ERR_FAIL_COND_MSG(err != OK, "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).");
+
+ bytes.resize(len);
+ encode_variant(var, bytes.ptrw(), len, p_full_objects);
+}
+
+void godotsharp_bytes_to_var(const godot_packed_array *p_bytes, bool p_allow_objects, godot_variant *r_ret) {
+ const PackedByteArray *bytes = reinterpret_cast<const PackedByteArray *>(p_bytes);
+ Variant ret;
+ Error err = decode_variant(ret, bytes->ptr(), bytes->size(), nullptr, p_allow_objects);
+ if (err != OK) {
+ ret = RTR("Not enough bytes for decoding bytes, or invalid format.");
+ }
+ memnew_placement(r_ret, Variant(ret));
+}
+
+int godotsharp_hash(const godot_variant *p_var) {
+ return reinterpret_cast<const Variant *>(p_var)->hash();
+}
+
+void godotsharp_convert(const godot_variant *p_what, int32_t p_type, godot_variant *r_ret) {
+ const Variant *args[1] = { reinterpret_cast<const Variant *>(p_what) };
+ Callable::CallError ce;
+ Variant ret;
+ Variant::construct(Variant::Type(p_type), ret, args, 1, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ memnew_placement(r_ret, Variant);
+ ERR_FAIL_MSG("Unable to convert parameter from '" +
+ Variant::get_type_name(reinterpret_cast<const Variant *>(p_what)->get_type()) +
+ "' to '" + Variant::get_type_name(Variant::Type(p_type)) + "'.");
+ }
+ memnew_placement(r_ret, Variant(ret));
+}
+
+Object *godotsharp_instance_from_id(uint64_t p_instance_id) {
+ return ObjectDB::get_instance(ObjectID(p_instance_id));
+}
+
+void godotsharp_object_to_string(Object *p_ptr, godot_string *r_str) {
+#ifdef DEBUG_ENABLED
+ // Cannot happen in C#; would get an ObjectDisposedException instead.
+ CRASH_COND(p_ptr == nullptr);
+#endif
+ // Can't call 'Object::to_string()' here, as that can end up calling 'ToString' again resulting in an endless circular loop.
+ memnew_placement(r_str,
+ String("[" + p_ptr->get_class() + ":" + itos(p_ptr->get_instance_id()) + "]"));
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+// The order in this array must match the declaration order of
+// the methods in 'GodotSharp/Core/NativeInterop/NativeFuncs.cs'.
+static const void *unmanaged_callbacks[]{
+ (void *)godotsharp_method_bind_get_method,
+ (void *)godotsharp_get_class_constructor,
+ (void *)godotsharp_engine_get_singleton,
+ (void *)godotsharp_stack_info_vector_resize,
+ (void *)godotsharp_stack_info_vector_destroy,
+ (void *)godotsharp_internal_script_debugger_send_error,
+ (void *)godotsharp_internal_script_debugger_is_active,
+ (void *)godotsharp_internal_object_get_associated_gchandle,
+ (void *)godotsharp_internal_object_disposed,
+ (void *)godotsharp_internal_refcounted_disposed,
+ (void *)godotsharp_internal_signal_awaiter_connect,
+ (void *)godotsharp_internal_tie_native_managed_to_unmanaged,
+ (void *)godotsharp_internal_tie_user_managed_to_unmanaged,
+ (void *)godotsharp_internal_tie_managed_to_unmanaged_with_pre_setup,
+ (void *)godotsharp_internal_unmanaged_get_script_instance_managed,
+ (void *)godotsharp_internal_unmanaged_get_instance_binding_managed,
+ (void *)godotsharp_internal_unmanaged_instance_binding_create_managed,
+ (void *)godotsharp_internal_new_csharp_script,
+ (void *)godotsharp_internal_script_load,
+ (void *)godotsharp_internal_reload_registered_script,
+ (void *)godotsharp_array_filter_godot_objects_by_native,
+ (void *)godotsharp_array_filter_godot_objects_by_non_native,
+ (void *)godotsharp_ref_new_from_ref_counted_ptr,
+ (void *)godotsharp_ref_destroy,
+ (void *)godotsharp_string_name_new_from_string,
+ (void *)godotsharp_node_path_new_from_string,
+ (void *)godotsharp_string_name_as_string,
+ (void *)godotsharp_node_path_as_string,
+ (void *)godotsharp_packed_byte_array_new_mem_copy,
+ (void *)godotsharp_packed_int32_array_new_mem_copy,
+ (void *)godotsharp_packed_int64_array_new_mem_copy,
+ (void *)godotsharp_packed_float32_array_new_mem_copy,
+ (void *)godotsharp_packed_float64_array_new_mem_copy,
+ (void *)godotsharp_packed_vector2_array_new_mem_copy,
+ (void *)godotsharp_packed_vector3_array_new_mem_copy,
+ (void *)godotsharp_packed_color_array_new_mem_copy,
+ (void *)godotsharp_packed_string_array_add,
+ (void *)godotsharp_callable_new_with_delegate,
+ (void *)godotsharp_callable_get_data_for_marshalling,
+ (void *)godotsharp_callable_call,
+ (void *)godotsharp_callable_call_deferred,
+ (void *)godotsharp_method_bind_ptrcall,
+ (void *)godotsharp_method_bind_call,
+ (void *)godotsharp_variant_new_string_name,
+ (void *)godotsharp_variant_new_copy,
+ (void *)godotsharp_variant_new_node_path,
+ (void *)godotsharp_variant_new_object,
+ (void *)godotsharp_variant_new_transform2d,
+ (void *)godotsharp_variant_new_vector4,
+ (void *)godotsharp_variant_new_vector4i,
+ (void *)godotsharp_variant_new_basis,
+ (void *)godotsharp_variant_new_transform3d,
+ (void *)godotsharp_variant_new_projection,
+ (void *)godotsharp_variant_new_aabb,
+ (void *)godotsharp_variant_new_dictionary,
+ (void *)godotsharp_variant_new_array,
+ (void *)godotsharp_variant_new_packed_byte_array,
+ (void *)godotsharp_variant_new_packed_int32_array,
+ (void *)godotsharp_variant_new_packed_int64_array,
+ (void *)godotsharp_variant_new_packed_float32_array,
+ (void *)godotsharp_variant_new_packed_float64_array,
+ (void *)godotsharp_variant_new_packed_string_array,
+ (void *)godotsharp_variant_new_packed_vector2_array,
+ (void *)godotsharp_variant_new_packed_vector3_array,
+ (void *)godotsharp_variant_new_packed_color_array,
+ (void *)godotsharp_variant_as_bool,
+ (void *)godotsharp_variant_as_int,
+ (void *)godotsharp_variant_as_float,
+ (void *)godotsharp_variant_as_string,
+ (void *)godotsharp_variant_as_vector2,
+ (void *)godotsharp_variant_as_vector2i,
+ (void *)godotsharp_variant_as_rect2,
+ (void *)godotsharp_variant_as_rect2i,
+ (void *)godotsharp_variant_as_vector3,
+ (void *)godotsharp_variant_as_vector3i,
+ (void *)godotsharp_variant_as_transform2d,
+ (void *)godotsharp_variant_as_vector4,
+ (void *)godotsharp_variant_as_vector4i,
+ (void *)godotsharp_variant_as_plane,
+ (void *)godotsharp_variant_as_quaternion,
+ (void *)godotsharp_variant_as_aabb,
+ (void *)godotsharp_variant_as_basis,
+ (void *)godotsharp_variant_as_transform3d,
+ (void *)godotsharp_variant_as_projection,
+ (void *)godotsharp_variant_as_color,
+ (void *)godotsharp_variant_as_string_name,
+ (void *)godotsharp_variant_as_node_path,
+ (void *)godotsharp_variant_as_rid,
+ (void *)godotsharp_variant_as_callable,
+ (void *)godotsharp_variant_as_signal,
+ (void *)godotsharp_variant_as_dictionary,
+ (void *)godotsharp_variant_as_array,
+ (void *)godotsharp_variant_as_packed_byte_array,
+ (void *)godotsharp_variant_as_packed_int32_array,
+ (void *)godotsharp_variant_as_packed_int64_array,
+ (void *)godotsharp_variant_as_packed_float32_array,
+ (void *)godotsharp_variant_as_packed_float64_array,
+ (void *)godotsharp_variant_as_packed_string_array,
+ (void *)godotsharp_variant_as_packed_vector2_array,
+ (void *)godotsharp_variant_as_packed_vector3_array,
+ (void *)godotsharp_variant_as_packed_color_array,
+ (void *)godotsharp_variant_equals,
+ (void *)godotsharp_string_new_with_utf16_chars,
+ (void *)godotsharp_string_name_new_copy,
+ (void *)godotsharp_node_path_new_copy,
+ (void *)godotsharp_array_new,
+ (void *)godotsharp_array_new_copy,
+ (void *)godotsharp_array_ptrw,
+ (void *)godotsharp_dictionary_new,
+ (void *)godotsharp_dictionary_new_copy,
+ (void *)godotsharp_packed_byte_array_destroy,
+ (void *)godotsharp_packed_int32_array_destroy,
+ (void *)godotsharp_packed_int64_array_destroy,
+ (void *)godotsharp_packed_float32_array_destroy,
+ (void *)godotsharp_packed_float64_array_destroy,
+ (void *)godotsharp_packed_string_array_destroy,
+ (void *)godotsharp_packed_vector2_array_destroy,
+ (void *)godotsharp_packed_vector3_array_destroy,
+ (void *)godotsharp_packed_color_array_destroy,
+ (void *)godotsharp_variant_destroy,
+ (void *)godotsharp_string_destroy,
+ (void *)godotsharp_string_name_destroy,
+ (void *)godotsharp_node_path_destroy,
+ (void *)godotsharp_signal_destroy,
+ (void *)godotsharp_callable_destroy,
+ (void *)godotsharp_array_destroy,
+ (void *)godotsharp_dictionary_destroy,
+ (void *)godotsharp_array_add,
+ (void *)godotsharp_array_duplicate,
+ (void *)godotsharp_array_index_of,
+ (void *)godotsharp_array_insert,
+ (void *)godotsharp_array_remove_at,
+ (void *)godotsharp_array_resize,
+ (void *)godotsharp_array_shuffle,
+ (void *)godotsharp_array_to_string,
+ (void *)godotsharp_dictionary_try_get_value,
+ (void *)godotsharp_dictionary_set_value,
+ (void *)godotsharp_dictionary_keys,
+ (void *)godotsharp_dictionary_values,
+ (void *)godotsharp_dictionary_count,
+ (void *)godotsharp_dictionary_key_value_pair_at,
+ (void *)godotsharp_dictionary_add,
+ (void *)godotsharp_dictionary_clear,
+ (void *)godotsharp_dictionary_contains_key,
+ (void *)godotsharp_dictionary_duplicate,
+ (void *)godotsharp_dictionary_remove_key,
+ (void *)godotsharp_dictionary_to_string,
+ (void *)godotsharp_string_md5_buffer,
+ (void *)godotsharp_string_md5_text,
+ (void *)godotsharp_string_rfind,
+ (void *)godotsharp_string_rfindn,
+ (void *)godotsharp_string_sha256_buffer,
+ (void *)godotsharp_string_sha256_text,
+ (void *)godotsharp_string_simplify_path,
+ (void *)godotsharp_node_path_get_as_property_path,
+ (void *)godotsharp_node_path_get_concatenated_names,
+ (void *)godotsharp_node_path_get_concatenated_subnames,
+ (void *)godotsharp_node_path_get_name,
+ (void *)godotsharp_node_path_get_name_count,
+ (void *)godotsharp_node_path_get_subname,
+ (void *)godotsharp_node_path_get_subname_count,
+ (void *)godotsharp_node_path_is_absolute,
+ (void *)godotsharp_bytes_to_var,
+ (void *)godotsharp_convert,
+ (void *)godotsharp_hash,
+ (void *)godotsharp_instance_from_id,
+ (void *)godotsharp_print,
+ (void *)godotsharp_print_rich,
+ (void *)godotsharp_printerr,
+ (void *)godotsharp_printraw,
+ (void *)godotsharp_prints,
+ (void *)godotsharp_printt,
+ (void *)godotsharp_randf,
+ (void *)godotsharp_randi,
+ (void *)godotsharp_randomize,
+ (void *)godotsharp_randf_range,
+ (void *)godotsharp_randfn,
+ (void *)godotsharp_randi_range,
+ (void *)godotsharp_rand_from_seed,
+ (void *)godotsharp_seed,
+ (void *)godotsharp_weakref,
+ (void *)godotsharp_str,
+ (void *)godotsharp_str_to_var,
+ (void *)godotsharp_var_to_bytes,
+ (void *)godotsharp_var_to_str,
+ (void *)godotsharp_pusherror,
+ (void *)godotsharp_pushwarning,
+ (void *)godotsharp_object_to_string,
+};
+
+const void **godotsharp::get_runtime_interop_funcs(int32_t &r_size) {
+ r_size = sizeof(unmanaged_callbacks);
+ return unmanaged_callbacks;
+}
diff --git a/modules/mono/glue/runtime_interop.h b/modules/mono/glue/runtime_interop.h
new file mode 100644
index 0000000000..9725ced593
--- /dev/null
+++ b/modules/mono/glue/runtime_interop.h
@@ -0,0 +1,40 @@
+/*************************************************************************/
+/* runtime_interop.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef RUNTIME_INTEROP_H
+#define RUNTIME_INTEROP_H
+
+#include "core/typedefs.h"
+
+namespace godotsharp {
+const void **get_runtime_interop_funcs(int32_t &r_size);
+}
+
+#endif // RUNTIME_INTEROP_H
diff --git a/modules/mono/glue/scene_tree_glue.cpp b/modules/mono/glue/scene_tree_glue.cpp
deleted file mode 100644
index c60e7c4869..0000000000
--- a/modules/mono/glue/scene_tree_glue.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-/*************************************************************************/
-/* scene_tree_glue.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifdef MONO_GLUE_ENABLED
-
-#include "core/object/class_db.h"
-#include "core/string/string_name.h"
-#include "core/variant/array.h"
-#include "scene/main/node.h"
-#include "scene/main/scene_tree.h"
-
-#include "../csharp_script.h"
-#include "../mono_gd/gd_mono_marshal.h"
-#include "../mono_gd/gd_mono_utils.h"
-
-Array *godot_icall_SceneTree_get_nodes_in_group_Generic(SceneTree *ptr, StringName *group, MonoReflectionType *refltype) {
- List<Node *> nodes;
- Array ret;
-
- // Retrieve all the nodes in the group
- ptr->get_nodes_in_group(*group, &nodes);
-
- // No need to bother if the group is empty
- if (!nodes.is_empty()) {
- MonoType *elem_type = mono_reflection_type_get_type(refltype);
- MonoClass *mono_class = mono_class_from_mono_type(elem_type);
- GDMonoClass *klass = GDMono::get_singleton()->get_class(mono_class);
-
- if (klass == GDMonoUtils::get_class_native_base(klass)) {
- // If we're trying to get native objects, just check the inheritance list
- StringName native_class_name = GDMonoUtils::get_native_godot_class_name(klass);
- for (int i = 0; i < nodes.size(); ++i) {
- if (ClassDB::is_parent_class(nodes[i]->get_class(), native_class_name)) {
- ret.push_back(nodes[i]);
- }
- }
- } else {
- // If we're trying to get csharpscript instances, get the mono object and compare the classes
- for (int i = 0; i < nodes.size(); ++i) {
- CSharpInstance *si = CAST_CSHARP_INSTANCE(nodes[i]->get_script_instance());
-
- if (si != nullptr) {
- MonoObject *obj = si->get_mono_object();
- if (obj != nullptr && mono_object_get_class(obj) == mono_class) {
- ret.push_back(nodes[i]);
- }
- }
- }
- }
- }
-
- return memnew(Array(ret));
-}
-
-void godot_register_scene_tree_icalls() {
- GDMonoUtils::add_internal_call("Godot.SceneTree::godot_icall_SceneTree_get_nodes_in_group_Generic", godot_icall_SceneTree_get_nodes_in_group_Generic);
-}
-
-#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/string_glue.cpp b/modules/mono/glue/string_glue.cpp
deleted file mode 100644
index fc6b13ceb3..0000000000
--- a/modules/mono/glue/string_glue.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*************************************************************************/
-/* string_glue.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifdef MONO_GLUE_ENABLED
-
-#include "core/string/ustring.h"
-#include "core/templates/vector.h"
-#include "core/variant/variant.h"
-
-#include "../mono_gd/gd_mono_marshal.h"
-
-MonoArray *godot_icall_String_md5_buffer(MonoString *p_str) {
- Vector<uint8_t> ret = GDMonoMarshal::mono_string_to_godot(p_str).md5_buffer();
- // TODO Check possible Array/Vector<uint8_t> problem?
- return GDMonoMarshal::Array_to_mono_array(Variant(ret));
-}
-
-MonoString *godot_icall_String_md5_text(MonoString *p_str) {
- String ret = GDMonoMarshal::mono_string_to_godot(p_str).md5_text();
- return GDMonoMarshal::mono_string_from_godot(ret);
-}
-
-int godot_icall_String_rfind(MonoString *p_str, MonoString *p_what, int p_from) {
- String what = GDMonoMarshal::mono_string_to_godot(p_what);
- return GDMonoMarshal::mono_string_to_godot(p_str).rfind(what, p_from);
-}
-
-int godot_icall_String_rfindn(MonoString *p_str, MonoString *p_what, int p_from) {
- String what = GDMonoMarshal::mono_string_to_godot(p_what);
- return GDMonoMarshal::mono_string_to_godot(p_str).rfindn(what, p_from);
-}
-
-MonoArray *godot_icall_String_sha256_buffer(MonoString *p_str) {
- Vector<uint8_t> ret = GDMonoMarshal::mono_string_to_godot(p_str).sha256_buffer();
- return GDMonoMarshal::Array_to_mono_array(Variant(ret));
-}
-
-MonoString *godot_icall_String_sha256_text(MonoString *p_str) {
- String ret = GDMonoMarshal::mono_string_to_godot(p_str).sha256_text();
- return GDMonoMarshal::mono_string_from_godot(ret);
-}
-
-MonoString *godot_icall_String_simplify_path(MonoString *p_str) {
- String ret = GDMonoMarshal::mono_string_to_godot(p_str).simplify_path();
- return GDMonoMarshal::mono_string_from_godot(ret);
-}
-
-void godot_register_string_icalls() {
- GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_md5_buffer", godot_icall_String_md5_buffer);
- GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_md5_text", godot_icall_String_md5_text);
- GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_rfind", godot_icall_String_rfind);
- GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_rfindn", godot_icall_String_rfindn);
- GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_buffer", godot_icall_String_sha256_buffer);
- GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_sha256_text", godot_icall_String_sha256_text);
- GDMonoUtils::add_internal_call("Godot.StringExtensions::godot_icall_String_simplify_path", godot_icall_String_simplify_path);
-}
-
-#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/string_name_glue.cpp b/modules/mono/glue/string_name_glue.cpp
deleted file mode 100644
index 46d15316ba..0000000000
--- a/modules/mono/glue/string_name_glue.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*************************************************************************/
-/* string_name_glue.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifdef MONO_GLUE_ENABLED
-
-#include "core/string/string_name.h"
-#include "core/string/ustring.h"
-
-#include "../mono_gd/gd_mono_marshal.h"
-
-StringName *godot_icall_StringName_Ctor(MonoString *p_path) {
- return memnew(StringName(GDMonoMarshal::mono_string_to_godot(p_path)));
-}
-
-void godot_icall_StringName_Dtor(StringName *p_ptr) {
- ERR_FAIL_NULL(p_ptr);
- memdelete(p_ptr);
-}
-
-MonoString *godot_icall_StringName_operator_String(StringName *p_np) {
- return GDMonoMarshal::mono_string_from_godot(p_np->operator String());
-}
-
-MonoBoolean godot_icall_StringName_is_empty(StringName *p_ptr) {
- return (MonoBoolean)(*p_ptr == StringName());
-}
-
-void godot_register_string_name_icalls() {
- GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_Ctor", godot_icall_StringName_Ctor);
- GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_Dtor", godot_icall_StringName_Dtor);
- GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_operator_String", godot_icall_StringName_operator_String);
- GDMonoUtils::add_internal_call("Godot.StringName::godot_icall_StringName_is_empty", godot_icall_StringName_is_empty);
-}
-
-#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/godotsharp_defs.h b/modules/mono/godotsharp_defs.h
index e5f1abe8d7..a81a52e4b8 100644
--- a/modules/mono/godotsharp_defs.h
+++ b/modules/mono/godotsharp_defs.h
@@ -33,14 +33,10 @@
#define BINDINGS_NAMESPACE "Godot"
#define BINDINGS_NAMESPACE_COLLECTIONS BINDINGS_NAMESPACE ".Collections"
-#define BINDINGS_GLOBAL_SCOPE_CLASS "GD"
-#define BINDINGS_PTR_FIELD "ptr"
-#define BINDINGS_NATIVE_NAME_FIELD "nativeName"
#define API_SOLUTION_NAME "GodotSharp"
#define CORE_API_ASSEMBLY_NAME "GodotSharp"
#define EDITOR_API_ASSEMBLY_NAME "GodotSharpEditor"
#define TOOLS_ASM_NAME "GodotTools"
-#define TOOLS_PROJECT_EDITOR_ASM_NAME "GodotTools.ProjectEditor"
#define BINDINGS_CLASS_NATIVECALLS "NativeCalls"
#define BINDINGS_CLASS_NATIVECALLS_EDITOR "EditorNativeCalls"
diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp
index f17b24e399..c7e47d2718 100644
--- a/modules/mono/godotsharp_dirs.cpp
+++ b/modules/mono/godotsharp_dirs.cpp
@@ -64,7 +64,7 @@ String _get_expected_build_config() {
String _get_mono_user_dir() {
#ifdef TOOLS_ENABLED
if (EditorPaths::get_singleton()) {
- return EditorPaths::get_singleton()->get_data_dir().plus_file("mono");
+ return EditorPaths::get_singleton()->get_data_dir().path_join("mono");
} else {
String settings_path;
@@ -72,23 +72,23 @@ String _get_mono_user_dir() {
String exe_dir = OS::get_singleton()->get_executable_path().get_base_dir();
// On macOS, look outside .app bundle, since .app bundle is read-only.
- if (OS::get_singleton()->has_feature("macos") && exe_dir.ends_with("MacOS") && exe_dir.plus_file("..").simplify_path().ends_with("Contents")) {
- exe_dir = exe_dir.plus_file("../../..").simplify_path();
+ if (OS::get_singleton()->has_feature("macos") && exe_dir.ends_with("MacOS") && exe_dir.path_join("..").simplify_path().ends_with("Contents")) {
+ exe_dir = exe_dir.path_join("../../..").simplify_path();
}
Ref<DirAccess> d = DirAccess::create_for_path(exe_dir);
if (d->file_exists("._sc_") || d->file_exists("_sc_")) {
// contain yourself
- settings_path = exe_dir.plus_file("editor_data");
+ settings_path = exe_dir.path_join("editor_data");
} else {
- settings_path = OS::get_singleton()->get_data_path().plus_file(OS::get_singleton()->get_godot_dir_name());
+ settings_path = OS::get_singleton()->get_data_path().path_join(OS::get_singleton()->get_godot_dir_name());
}
- return settings_path.plus_file("mono");
+ return settings_path.path_join("mono");
}
#else
- return OS::get_singleton()->get_user_data_dir().plus_file("mono");
+ return OS::get_singleton()->get_user_data_dir().path_join("mono");
#endif
}
@@ -96,8 +96,6 @@ class _GodotSharpDirs {
public:
String res_data_dir;
String res_metadata_dir;
- String res_assemblies_base_dir;
- String res_assemblies_dir;
String res_config_dir;
String res_temp_dir;
String res_temp_assemblies_base_dir;
@@ -105,15 +103,14 @@ public:
String mono_user_dir;
String mono_logs_dir;
+ String api_assemblies_base_dir;
+ String api_assemblies_dir;
+
#ifdef TOOLS_ENABLED
String mono_solutions_dir;
String build_logs_dir;
- String sln_filepath;
- String csproj_filepath;
-
String data_editor_tools_dir;
- String data_editor_prebuilt_api_dir;
#else
// Equivalent of res_assemblies_dir, but in the data directory rather than in 'res://'.
// Only defined on export templates. Used when exporting assemblies outside of PCKs.
@@ -129,73 +126,64 @@ public:
private:
_GodotSharpDirs() {
- res_data_dir = ProjectSettings::get_singleton()->get_project_data_path().plus_file("mono");
- res_metadata_dir = res_data_dir.plus_file("metadata");
- res_assemblies_base_dir = res_data_dir.plus_file("assemblies");
- res_assemblies_dir = res_assemblies_base_dir.plus_file(GDMono::get_expected_api_build_config());
- res_config_dir = res_data_dir.plus_file("etc").plus_file("mono");
+ res_data_dir = ProjectSettings::get_singleton()->get_project_data_path().path_join("mono");
+ res_metadata_dir = res_data_dir.path_join("metadata");
+ res_config_dir = res_data_dir.path_join("etc").path_join("mono");
// TODO use paths from csproj
- res_temp_dir = res_data_dir.plus_file("temp");
- res_temp_assemblies_base_dir = res_temp_dir.plus_file("bin");
- res_temp_assemblies_dir = res_temp_assemblies_base_dir.plus_file(_get_expected_build_config());
+ res_temp_dir = res_data_dir.path_join("temp");
+ res_temp_assemblies_base_dir = res_temp_dir.path_join("bin");
+ res_temp_assemblies_dir = res_temp_assemblies_base_dir.path_join(_get_expected_build_config());
-#ifdef JAVASCRIPT_ENABLED
+ api_assemblies_base_dir = res_data_dir.path_join("assemblies");
+
+#ifdef WEB_ENABLED
mono_user_dir = "user://";
#else
mono_user_dir = _get_mono_user_dir();
#endif
- mono_logs_dir = mono_user_dir.plus_file("mono_logs");
+ mono_logs_dir = mono_user_dir.path_join("mono_logs");
#ifdef TOOLS_ENABLED
- mono_solutions_dir = mono_user_dir.plus_file("solutions");
- build_logs_dir = mono_user_dir.plus_file("build_logs");
-
- String appname = ProjectSettings::get_singleton()->get("application/config/name");
- String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
- if (appname_safe.is_empty()) {
- appname_safe = "UnnamedProject";
- }
+ mono_solutions_dir = mono_user_dir.path_join("solutions");
+ build_logs_dir = mono_user_dir.path_join("build_logs");
String base_path = ProjectSettings::get_singleton()->globalize_path("res://");
-
- sln_filepath = base_path.plus_file(appname_safe + ".sln");
- csproj_filepath = base_path.plus_file(appname_safe + ".csproj");
#endif
String exe_dir = OS::get_singleton()->get_executable_path().get_base_dir();
#ifdef TOOLS_ENABLED
- String data_dir_root = exe_dir.plus_file("GodotSharp");
- data_editor_tools_dir = data_dir_root.plus_file("Tools");
- data_editor_prebuilt_api_dir = data_dir_root.plus_file("Api");
+ String data_dir_root = exe_dir.path_join("GodotSharp");
+ data_editor_tools_dir = data_dir_root.path_join("Tools");
+ api_assemblies_base_dir = data_dir_root.path_join("Api");
- String data_mono_root_dir = data_dir_root.plus_file("Mono");
- data_mono_etc_dir = data_mono_root_dir.plus_file("etc");
+ String data_mono_root_dir = data_dir_root.path_join("Mono");
+ data_mono_etc_dir = data_mono_root_dir.path_join("etc");
#ifdef ANDROID_ENABLED
data_mono_lib_dir = gdmono::android::support::get_app_native_lib_dir();
#else
- data_mono_lib_dir = data_mono_root_dir.plus_file("lib");
+ data_mono_lib_dir = data_mono_root_dir.path_join("lib");
#endif
#ifdef WINDOWS_ENABLED
- data_mono_bin_dir = data_mono_root_dir.plus_file("bin");
+ data_mono_bin_dir = data_mono_root_dir.path_join("bin");
#endif
#ifdef MACOS_ENABLED
if (!DirAccess::exists(data_editor_tools_dir)) {
- data_editor_tools_dir = exe_dir.plus_file("../Resources/GodotSharp/Tools");
+ data_editor_tools_dir = exe_dir.path_join("../Resources/GodotSharp/Tools");
}
- if (!DirAccess::exists(data_editor_prebuilt_api_dir)) {
- data_editor_prebuilt_api_dir = exe_dir.plus_file("../Resources/GodotSharp/Api");
+ if (!DirAccess::exists(api_assemblies_base_dir)) {
+ api_assemblies_base_dir = exe_dir.path_join("../Resources/GodotSharp/Api");
}
if (!DirAccess::exists(data_mono_root_dir)) {
- data_mono_etc_dir = exe_dir.plus_file("../Resources/GodotSharp/Mono/etc");
- data_mono_lib_dir = exe_dir.plus_file("../Resources/GodotSharp/Mono/lib");
+ data_mono_etc_dir = exe_dir.path_join("../Resources/GodotSharp/Mono/etc");
+ data_mono_lib_dir = exe_dir.path_join("../Resources/GodotSharp/Mono/lib");
}
#endif
@@ -203,37 +191,43 @@ private:
String appname = ProjectSettings::get_singleton()->get("application/config/name");
String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
- String data_dir_root = exe_dir.plus_file("data_" + appname_safe);
+ String data_dir_root = exe_dir.path_join("data_" + appname_safe);
if (!DirAccess::exists(data_dir_root)) {
- data_dir_root = exe_dir.plus_file("data_Godot");
+ data_dir_root = exe_dir.path_join("data_Godot");
}
- String data_mono_root_dir = data_dir_root.plus_file("Mono");
- data_mono_etc_dir = data_mono_root_dir.plus_file("etc");
+ String data_mono_root_dir = data_dir_root.path_join("Mono");
+ data_mono_etc_dir = data_mono_root_dir.path_join("etc");
#ifdef ANDROID_ENABLED
data_mono_lib_dir = gdmono::android::support::get_app_native_lib_dir();
#else
- data_mono_lib_dir = data_mono_root_dir.plus_file("lib");
- data_game_assemblies_dir = data_dir_root.plus_file("Assemblies");
+ data_mono_lib_dir = data_mono_root_dir.path_join("lib");
+ data_game_assemblies_dir = data_dir_root.path_join("Assemblies");
#endif
#ifdef WINDOWS_ENABLED
- data_mono_bin_dir = data_mono_root_dir.plus_file("bin");
+ data_mono_bin_dir = data_mono_root_dir.path_join("bin");
#endif
#ifdef MACOS_ENABLED
if (!DirAccess::exists(data_mono_root_dir)) {
- data_mono_etc_dir = exe_dir.plus_file("../Resources/GodotSharp/Mono/etc");
- data_mono_lib_dir = exe_dir.plus_file("../Resources/GodotSharp/Mono/lib");
+ data_mono_etc_dir = exe_dir.path_join("../Resources/GodotSharp/Mono/etc");
+ data_mono_lib_dir = exe_dir.path_join("../Resources/GodotSharp/Mono/lib");
}
if (!DirAccess::exists(data_game_assemblies_dir)) {
- data_game_assemblies_dir = exe_dir.plus_file("../Resources/GodotSharp/Assemblies");
+ data_game_assemblies_dir = exe_dir.path_join("../Resources/GodotSharp/Assemblies");
}
#endif
#endif
+
+#ifdef TOOLS_ENABLED
+ api_assemblies_dir = api_assemblies_base_dir.path_join(GDMono::get_expected_api_build_config());
+#else
+ api_assemblies_dir = data_dir_root;
+#endif
}
public:
@@ -251,14 +245,6 @@ String get_res_metadata_dir() {
return _GodotSharpDirs::get_singleton().res_metadata_dir;
}
-String get_res_assemblies_base_dir() {
- return _GodotSharpDirs::get_singleton().res_assemblies_base_dir;
-}
-
-String get_res_assemblies_dir() {
- return _GodotSharpDirs::get_singleton().res_assemblies_dir;
-}
-
String get_res_config_dir() {
return _GodotSharpDirs::get_singleton().res_config_dir;
}
@@ -275,6 +261,14 @@ String get_res_temp_assemblies_dir() {
return _GodotSharpDirs::get_singleton().res_temp_assemblies_dir;
}
+String get_api_assemblies_dir() {
+ return _GodotSharpDirs::get_singleton().api_assemblies_dir;
+}
+
+String get_api_assemblies_base_dir() {
+ return _GodotSharpDirs::get_singleton().api_assemblies_base_dir;
+}
+
String get_mono_user_dir() {
return _GodotSharpDirs::get_singleton().mono_user_dir;
}
@@ -292,21 +286,9 @@ String get_build_logs_dir() {
return _GodotSharpDirs::get_singleton().build_logs_dir;
}
-String get_project_sln_path() {
- return _GodotSharpDirs::get_singleton().sln_filepath;
-}
-
-String get_project_csproj_path() {
- return _GodotSharpDirs::get_singleton().csproj_filepath;
-}
-
String get_data_editor_tools_dir() {
return _GodotSharpDirs::get_singleton().data_editor_tools_dir;
}
-
-String get_data_editor_prebuilt_api_dir() {
- return _GodotSharpDirs::get_singleton().data_editor_prebuilt_api_dir;
-}
#else
String get_data_game_assemblies_dir() {
return _GodotSharpDirs::get_singleton().data_game_assemblies_dir;
diff --git a/modules/mono/godotsharp_dirs.h b/modules/mono/godotsharp_dirs.h
index da25e0778f..03e62ffd82 100644
--- a/modules/mono/godotsharp_dirs.h
+++ b/modules/mono/godotsharp_dirs.h
@@ -37,13 +37,14 @@ namespace GodotSharpDirs {
String get_res_data_dir();
String get_res_metadata_dir();
-String get_res_assemblies_base_dir();
-String get_res_assemblies_dir();
String get_res_config_dir();
String get_res_temp_dir();
String get_res_temp_assemblies_base_dir();
String get_res_temp_assemblies_dir();
+String get_api_assemblies_dir();
+String get_api_assemblies_base_dir();
+
String get_mono_user_dir();
String get_mono_logs_dir();
@@ -51,11 +52,7 @@ String get_mono_logs_dir();
String get_mono_solutions_dir();
String get_build_logs_dir();
-String get_project_sln_path();
-String get_project_csproj_path();
-
String get_data_editor_tools_dir();
-String get_data_editor_prebuilt_api_dir();
#else
String get_data_game_assemblies_dir();
#endif
diff --git a/modules/mono/interop_types.h b/modules/mono/interop_types.h
new file mode 100644
index 0000000000..6942a91559
--- /dev/null
+++ b/modules/mono/interop_types.h
@@ -0,0 +1,208 @@
+/*************************************************************************/
+/* interop_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef INTEROP_TYPES_H
+#define INTEROP_TYPES_H
+
+#include "core/math/math_defs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <stdint.h>
+
+// This is taken from the old GDNative, which was removed.
+
+#define GODOT_VARIANT_SIZE (sizeof(real_t) * 4 + sizeof(int64_t))
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_VARIANT_SIZE];
+} godot_variant;
+
+#define GODOT_ARRAY_SIZE sizeof(void *)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_ARRAY_SIZE];
+} godot_array;
+
+#define GODOT_DICTIONARY_SIZE sizeof(void *)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_DICTIONARY_SIZE];
+} godot_dictionary;
+
+#define GODOT_STRING_SIZE sizeof(void *)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_STRING_SIZE];
+} godot_string;
+
+#define GODOT_STRING_NAME_SIZE sizeof(void *)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_STRING_NAME_SIZE];
+} godot_string_name;
+
+#define GODOT_PACKED_ARRAY_SIZE (2 * sizeof(void *))
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_PACKED_ARRAY_SIZE];
+} godot_packed_array;
+
+#define GODOT_VECTOR2_SIZE (sizeof(real_t) * 2)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_VECTOR2_SIZE];
+} godot_vector2;
+
+#define GODOT_VECTOR2I_SIZE (sizeof(int32_t) * 2)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_VECTOR2I_SIZE];
+} godot_vector2i;
+
+#define GODOT_RECT2_SIZE (sizeof(real_t) * 4)
+
+typedef struct godot_rect2 {
+ uint8_t _dont_touch_that[GODOT_RECT2_SIZE];
+} godot_rect2;
+
+#define GODOT_RECT2I_SIZE (sizeof(int32_t) * 4)
+
+typedef struct godot_rect2i {
+ uint8_t _dont_touch_that[GODOT_RECT2I_SIZE];
+} godot_rect2i;
+
+#define GODOT_VECTOR3_SIZE (sizeof(real_t) * 3)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_VECTOR3_SIZE];
+} godot_vector3;
+
+#define GODOT_VECTOR3I_SIZE (sizeof(int32_t) * 3)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_VECTOR3I_SIZE];
+} godot_vector3i;
+
+#define GODOT_TRANSFORM2D_SIZE (sizeof(real_t) * 6)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_TRANSFORM2D_SIZE];
+} godot_transform2d;
+
+#define GODOT_VECTOR4_SIZE (sizeof(real_t) * 4)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_VECTOR4_SIZE];
+} godot_vector4;
+
+#define GODOT_VECTOR4I_SIZE (sizeof(int32_t) * 4)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_VECTOR4I_SIZE];
+} godot_vector4i;
+
+#define GODOT_PLANE_SIZE (sizeof(real_t) * 4)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_PLANE_SIZE];
+} godot_plane;
+
+#define GODOT_QUATERNION_SIZE (sizeof(real_t) * 4)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_QUATERNION_SIZE];
+} godot_quaternion;
+
+#define GODOT_AABB_SIZE (sizeof(real_t) * 6)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_AABB_SIZE];
+} godot_aabb;
+
+#define GODOT_BASIS_SIZE (sizeof(real_t) * 9)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_BASIS_SIZE];
+} godot_basis;
+
+#define GODOT_TRANSFORM3D_SIZE (sizeof(real_t) * 12)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_TRANSFORM3D_SIZE];
+} godot_transform3d;
+
+#define GODOT_PROJECTION_SIZE (sizeof(real_t) * 4 * 4)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_PROJECTION_SIZE];
+} godot_projection;
+
+// Colors should always use 32-bit floats, so don't use real_t here.
+#define GODOT_COLOR_SIZE (sizeof(float) * 4)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_COLOR_SIZE];
+} godot_color;
+
+#define GODOT_NODE_PATH_SIZE sizeof(void *)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_NODE_PATH_SIZE];
+} godot_node_path;
+
+#define GODOT_RID_SIZE sizeof(uint64_t)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_RID_SIZE];
+} godot_rid;
+
+// Alignment hardcoded in `core/variant/callable.h`.
+#define GODOT_CALLABLE_SIZE (16)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_CALLABLE_SIZE];
+} godot_callable;
+
+// Alignment hardcoded in `core/variant/callable.h`.
+#define GODOT_SIGNAL_SIZE (16)
+
+typedef struct {
+ uint8_t _dont_touch_that[GODOT_SIGNAL_SIZE];
+} godot_signal;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // INTEROP_TYPES_H
diff --git a/modules/mono/managed_callable.cpp b/modules/mono/managed_callable.cpp
index c159bb9eea..9305dc645a 100644
--- a/modules/mono/managed_callable.cpp
+++ b/modules/mono/managed_callable.cpp
@@ -31,8 +31,7 @@
#include "managed_callable.h"
#include "csharp_script.h"
-#include "mono_gd/gd_mono_marshal.h"
-#include "mono_gd/gd_mono_utils.h"
+#include "mono_gd/gd_mono_cache.h"
#ifdef GD_MONO_HOT_RELOAD
SelfList<ManagedCallable>::List ManagedCallable::instances;
@@ -44,18 +43,16 @@ bool ManagedCallable::compare_equal(const CallableCustom *p_a, const CallableCus
const ManagedCallable *a = static_cast<const ManagedCallable *>(p_a);
const ManagedCallable *b = static_cast<const ManagedCallable *>(p_b);
- MonoDelegate *delegate_a = (MonoDelegate *)a->delegate_handle.get_target();
- MonoDelegate *delegate_b = (MonoDelegate *)b->delegate_handle.get_target();
-
- if (!delegate_a || !delegate_b) {
- if (!delegate_a && !delegate_b) {
+ if (!a->delegate_handle.value || !b->delegate_handle.value) {
+ if (!a->delegate_handle.value && !b->delegate_handle.value) {
return true;
}
return false;
}
// Call Delegate's 'Equals'
- return GDMonoUtils::mono_delegate_equal(delegate_a, delegate_b);
+ return GDMonoCache::managed_callbacks.DelegateUtils_DelegateEquals(
+ a->delegate_handle, b->delegate_handle);
}
bool ManagedCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) {
@@ -66,8 +63,7 @@ bool ManagedCallable::compare_less(const CallableCustom *p_a, const CallableCust
}
uint32_t ManagedCallable::hash() const {
- uint32_t hash = delegate_invoke->get_name().hash();
- return hash_murmur3_one_64(delegate_handle.handle, hash);
+ return hash_murmur3_one_64((uint64_t)delegate_handle.value);
}
String ManagedCallable::get_as_text() const {
@@ -91,41 +87,24 @@ void ManagedCallable::call(const Variant **p_arguments, int p_argcount, Variant
r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; // Can't find anything better
r_return_value = Variant();
-#ifdef GD_MONO_HOT_RELOAD
- // Lost during hot-reload
- ERR_FAIL_NULL(delegate_invoke);
- ERR_FAIL_COND(delegate_handle.is_released());
-#endif
-
- ERR_FAIL_COND(delegate_invoke->get_parameters_count() < p_argcount);
-
- MonoObject *delegate = delegate_handle.get_target();
+ ERR_FAIL_COND(delegate_handle.value == nullptr);
- MonoException *exc = nullptr;
- MonoObject *ret = delegate_invoke->invoke(delegate, p_arguments, &exc);
+ GDMonoCache::managed_callbacks.DelegateUtils_InvokeWithVariantArgs(
+ delegate_handle, p_arguments, p_argcount, &r_return_value);
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- } else {
- r_return_value = GDMonoMarshal::mono_object_to_variant(ret);
- r_call_error.error = Callable::CallError::CALL_OK;
- }
+ r_call_error.error = Callable::CallError::CALL_OK;
}
-void ManagedCallable::set_delegate(MonoDelegate *p_delegate) {
- delegate_handle = MonoGCHandleData::new_strong_handle((MonoObject *)p_delegate);
- MonoMethod *delegate_invoke_raw = mono_get_delegate_invoke(mono_object_get_class((MonoObject *)p_delegate));
- const StringName &delegate_invoke_name = CSharpLanguage::get_singleton()->get_string_names().delegate_invoke_method_name;
- delegate_invoke = memnew(GDMonoMethod(delegate_invoke_name, delegate_invoke_raw)); // TODO: Use pooling for this GDMonoMethod instances
+void ManagedCallable::release_delegate_handle() {
+ if (delegate_handle.value) {
+ GDMonoCache::managed_callbacks.GCHandleBridge_FreeGCHandle(delegate_handle);
+ delegate_handle = { nullptr };
+ }
}
-ManagedCallable::ManagedCallable(MonoDelegate *p_delegate) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(p_delegate == nullptr);
-#endif
-
- set_delegate(p_delegate);
-
+// Why you do this clang-format...
+/* clang-format off */
+ManagedCallable::ManagedCallable(GCHandleIntPtr p_delegate_handle) : delegate_handle(p_delegate_handle) {
#ifdef GD_MONO_HOT_RELOAD
{
MutexLock lock(instances_mutex);
@@ -133,6 +112,7 @@ ManagedCallable::ManagedCallable(MonoDelegate *p_delegate) {
}
#endif
}
+/* clang-format on */
ManagedCallable::~ManagedCallable() {
#ifdef GD_MONO_HOT_RELOAD
@@ -143,5 +123,5 @@ ManagedCallable::~ManagedCallable() {
}
#endif
- delegate_handle.release();
+ release_delegate_handle();
}
diff --git a/modules/mono/managed_callable.h b/modules/mono/managed_callable.h
index 11bee6cf60..aa3344f4d5 100644
--- a/modules/mono/managed_callable.h
+++ b/modules/mono/managed_callable.h
@@ -31,19 +31,15 @@
#ifndef MANAGED_CALLABLE_H
#define MANAGED_CALLABLE_H
-#include <mono/metadata/object.h>
-
#include "core/os/mutex.h"
#include "core/templates/self_list.h"
#include "core/variant/callable.h"
#include "mono_gc_handle.h"
-#include "mono_gd/gd_mono_method.h"
class ManagedCallable : public CallableCustom {
friend class CSharpLanguage;
- MonoGCHandleData delegate_handle;
- GDMonoMethod *delegate_invoke = nullptr;
+ GCHandleIntPtr delegate_handle;
#ifdef GD_MONO_HOT_RELOAD
SelfList<ManagedCallable> self_instance = this;
@@ -60,9 +56,7 @@ public:
ObjectID get_object() const override;
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
- _FORCE_INLINE_ MonoDelegate *get_delegate() { return (MonoDelegate *)delegate_handle.get_target(); }
-
- void set_delegate(MonoDelegate *p_delegate);
+ _FORCE_INLINE_ GCHandleIntPtr get_delegate() const { return delegate_handle; }
static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b);
static bool compare_less(const CallableCustom *p_a, const CallableCustom *p_b);
@@ -70,7 +64,9 @@ public:
static constexpr CompareEqualFunc compare_equal_func_ptr = &ManagedCallable::compare_equal;
static constexpr CompareEqualFunc compare_less_func_ptr = &ManagedCallable::compare_less;
- ManagedCallable(MonoDelegate *p_delegate);
+ void release_delegate_handle();
+
+ ManagedCallable(GCHandleIntPtr p_delegate_handle);
~ManagedCallable();
};
diff --git a/modules/mono/mono_gc_handle.cpp b/modules/mono/mono_gc_handle.cpp
index f3dafa6ecf..9cf0a641b9 100644
--- a/modules/mono/mono_gc_handle.cpp
+++ b/modules/mono/mono_gc_handle.cpp
@@ -31,34 +31,20 @@
#include "mono_gc_handle.h"
#include "mono_gd/gd_mono.h"
+#include "mono_gd/gd_mono_cache.h"
void MonoGCHandleData::release() {
#ifdef DEBUG_ENABLED
- CRASH_COND(handle && GDMono::get_singleton() == nullptr);
+ CRASH_COND(handle.value && GDMono::get_singleton() == nullptr);
#endif
- if (handle && GDMono::get_singleton()->is_runtime_initialized()) {
- GDMonoUtils::free_gchandle(handle);
- handle = 0;
+ if (handle.value && GDMonoCache::godot_api_cache_updated &&
+ GDMono::get_singleton()->is_runtime_initialized()) {
+ free_gchandle(handle);
+ handle.value = nullptr;
}
}
-
-MonoGCHandleData MonoGCHandleData::new_strong_handle(MonoObject *p_object) {
- return MonoGCHandleData(GDMonoUtils::new_strong_gchandle(p_object), gdmono::GCHandleType::STRONG_HANDLE);
-}
-
-MonoGCHandleData MonoGCHandleData::new_strong_handle_pinned(MonoObject *p_object) {
- return MonoGCHandleData(GDMonoUtils::new_strong_gchandle_pinned(p_object), gdmono::GCHandleType::STRONG_HANDLE);
-}
-
-MonoGCHandleData MonoGCHandleData::new_weak_handle(MonoObject *p_object) {
- return MonoGCHandleData(GDMonoUtils::new_weak_gchandle(p_object), gdmono::GCHandleType::WEAK_HANDLE);
-}
-
-Ref<MonoGCHandleRef> MonoGCHandleRef::create_strong(MonoObject *p_object) {
- return memnew(MonoGCHandleRef(MonoGCHandleData::new_strong_handle(p_object)));
-}
-
-Ref<MonoGCHandleRef> MonoGCHandleRef::create_weak(MonoObject *p_object) {
- return memnew(MonoGCHandleRef(MonoGCHandleData::new_weak_handle(p_object)));
+void MonoGCHandleData::free_gchandle(GCHandleIntPtr p_gchandle) {
+ CRASH_COND(!GDMonoCache::godot_api_cache_updated);
+ GDMonoCache::managed_callbacks.GCHandleBridge_FreeGCHandle(p_gchandle);
}
diff --git a/modules/mono/mono_gc_handle.h b/modules/mono/mono_gc_handle.h
index e2aff1d19d..4e4c13fee6 100644
--- a/modules/mono/mono_gc_handle.h
+++ b/modules/mono/mono_gc_handle.h
@@ -31,8 +31,6 @@
#ifndef MONO_GC_HANDLE_H
#define MONO_GC_HANDLE_H
-#include <mono/jit/jit.h>
-
#include "core/object/ref_counted.h"
namespace gdmono {
@@ -44,18 +42,32 @@ enum class GCHandleType : char {
};
}
+extern "C" {
+struct GCHandleIntPtr {
+ void *value;
+
+ _FORCE_INLINE_ bool operator==(const GCHandleIntPtr &p_other) { return value == p_other.value; }
+ _FORCE_INLINE_ bool operator!=(const GCHandleIntPtr &p_other) { return value != p_other.value; }
+
+ GCHandleIntPtr() = delete;
+};
+}
+
+static_assert(sizeof(GCHandleIntPtr) == sizeof(void *));
+
// Manual release of the GC handle must be done when using this struct
struct MonoGCHandleData {
- uint32_t handle = 0;
+ GCHandleIntPtr handle = { nullptr };
gdmono::GCHandleType type = gdmono::GCHandleType::NIL;
- _FORCE_INLINE_ bool is_released() const { return !handle; }
+ _FORCE_INLINE_ bool is_released() const { return !handle.value; }
_FORCE_INLINE_ bool is_weak() const { return type == gdmono::GCHandleType::WEAK_HANDLE; }
-
- _FORCE_INLINE_ MonoObject *get_target() const { return handle ? mono_gchandle_get_target(handle) : nullptr; }
+ _FORCE_INLINE_ GCHandleIntPtr get_intptr() const { return handle; }
void release();
+ static void free_gchandle(GCHandleIntPtr p_gchandle);
+
void operator=(const MonoGCHandleData &p_other) {
#ifdef DEBUG_ENABLED
CRASH_COND(!is_released());
@@ -68,40 +80,10 @@ struct MonoGCHandleData {
MonoGCHandleData() {}
- MonoGCHandleData(uint32_t p_handle, gdmono::GCHandleType p_type) :
+ MonoGCHandleData(GCHandleIntPtr p_handle, gdmono::GCHandleType p_type) :
handle(p_handle),
type(p_type) {
}
-
- static MonoGCHandleData new_strong_handle(MonoObject *p_object);
- static MonoGCHandleData new_strong_handle_pinned(MonoObject *p_object);
- static MonoGCHandleData new_weak_handle(MonoObject *p_object);
-};
-
-class MonoGCHandleRef : public RefCounted {
- GDCLASS(MonoGCHandleRef, RefCounted);
-
- MonoGCHandleData data;
-
-public:
- static Ref<MonoGCHandleRef> create_strong(MonoObject *p_object);
- static Ref<MonoGCHandleRef> create_weak(MonoObject *p_object);
-
- _FORCE_INLINE_ bool is_released() const { return data.is_released(); }
- _FORCE_INLINE_ bool is_weak() const { return data.is_weak(); }
-
- _FORCE_INLINE_ MonoObject *get_target() const { return data.get_target(); }
-
- void release() { data.release(); }
-
- _FORCE_INLINE_ void set_handle(uint32_t p_handle, gdmono::GCHandleType p_handle_type) {
- data = MonoGCHandleData(p_handle, p_handle_type);
- }
-
- MonoGCHandleRef(const MonoGCHandleData &p_gc_handle_data) :
- data(p_gc_handle_data) {
- }
- ~MonoGCHandleRef() { release(); }
};
#endif // MONO_GC_HANDLE_H
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index d3d3bb2bef..e698e92d7a 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -30,13 +30,6 @@
#include "gd_mono.h"
-#include <mono/metadata/environment.h>
-#include <mono/metadata/exception.h>
-#include <mono/metadata/mono-config.h>
-#include <mono/metadata/mono-debug.h>
-#include <mono/metadata/mono-gc.h>
-#include <mono/metadata/profiler.h>
-
#include "core/config/project_settings.h"
#include "core/debugger/engine_debugger.h"
#include "core/io/dir_access.h"
@@ -45,1077 +38,519 @@
#include "core/os/thread.h"
#include "../csharp_script.h"
+#include "../glue/runtime_interop.h"
#include "../godotsharp_dirs.h"
#include "../utils/path_utils.h"
#include "gd_mono_cache.h"
-#include "gd_mono_class.h"
-#include "gd_mono_marshal.h"
-#include "gd_mono_utils.h"
+#ifdef TOOLS_ENABLED
+#include <nethost.h>
+#endif
+
+#include <coreclr_delegates.h>
+#include <hostfxr.h>
+#ifdef UNIX_ENABLED
+#include <dlfcn.h>
+#endif
+
+// TODO mobile
+#if 0
#ifdef ANDROID_ENABLED
-#include "android_mono_config.h"
#include "support/android_support.h"
#elif defined(IOS_ENABLED)
#include "support/ios_support.h"
#endif
-
-#if defined(TOOL_ENABLED) && defined(GD_MONO_SINGLE_APPDOMAIN)
-// This will no longer be the case if we replace appdomains with AssemblyLoadContext
-#error "Editor build requires support for multiple appdomains"
-#endif
-
-#if defined(GD_MONO_HOT_RELOAD) && defined(GD_MONO_SINGLE_APPDOMAIN)
-#error "Hot reloading requires multiple appdomains"
#endif
-// TODO:
-// This has turned into a gigantic mess. There's too much going on here. Too much #ifdef as well.
-// It's just painful to read... It needs to be re-structured. Please, clean this up, future me.
-
GDMono *GDMono::singleton = nullptr;
namespace {
-
-#if defined(JAVASCRIPT_ENABLED)
-extern "C" {
-void mono_wasm_load_runtime(const char *managed_path, int enable_debugging);
-}
-#endif
-
-#if !defined(JAVASCRIPT_ENABLED)
-
-void gd_mono_setup_runtime_main_args() {
- CharString execpath = OS::get_singleton()->get_executable_path().utf8();
-
- List<String> cmdline_args = OS::get_singleton()->get_cmdline_args();
-
- List<CharString> cmdline_args_utf8;
- Vector<char *> main_args;
- main_args.resize(cmdline_args.size() + 1);
-
- main_args.write[0] = execpath.ptrw();
-
- int i = 1;
- for (const String &E : cmdline_args) {
- CharString &stored = cmdline_args_utf8.push_back(E.utf8())->get();
- main_args.write[i] = stored.ptrw();
- i++;
- }
-
- mono_runtime_set_main_args(main_args.size(), main_args.ptrw());
-}
-
-void gd_mono_profiler_init() {
- String profiler_args = GLOBAL_DEF("mono/profiler/args", "log:calls,alloc,sample,output=output.mlpd");
- bool profiler_enabled = GLOBAL_DEF("mono/profiler/enabled", false);
- if (profiler_enabled) {
- mono_profiler_load(profiler_args.utf8());
- return;
- }
-
- const String env_var_name = "MONO_ENV_OPTIONS";
- if (OS::get_singleton()->has_environment(env_var_name)) {
- const String mono_env_ops = OS::get_singleton()->get_environment(env_var_name);
- // Usually MONO_ENV_OPTIONS looks like: --profile=jb:prof=timeline,ctl=remote,host=127.0.0.1:55467
- const String prefix = "--profile=";
- if (mono_env_ops.begins_with(prefix)) {
- const String ops = mono_env_ops.substr(prefix.length(), mono_env_ops.length());
- mono_profiler_load(ops.utf8());
- }
- }
-}
-
-void gd_mono_debug_init() {
- CharString da_args = OS::get_singleton()->get_environment("GODOT_MONO_DEBUGGER_AGENT").utf8();
-
- if (da_args.length()) {
- OS::get_singleton()->set_environment("GODOT_MONO_DEBUGGER_AGENT", String());
- }
-
-#ifdef TOOLS_ENABLED
- int da_port = GLOBAL_DEF("mono/debugger_agent/port", 23685);
- bool da_suspend = GLOBAL_DEF("mono/debugger_agent/wait_for_debugger", false);
- int da_timeout = GLOBAL_DEF("mono/debugger_agent/wait_timeout", 3000);
-
- if (Engine::get_singleton()->is_editor_hint() ||
- ProjectSettings::get_singleton()->get_resource_path().is_empty() ||
- Engine::get_singleton()->is_project_manager_hint()) {
- if (da_args.size() == 0) {
- return;
- }
- }
-
- if (da_args.length() == 0) {
- da_args = String("--debugger-agent=transport=dt_socket,address=127.0.0.1:" + itos(da_port) +
- ",embedding=1,server=y,suspend=" + (da_suspend ? "y,timeout=" + itos(da_timeout) : "n"))
- .utf8();
- }
+hostfxr_initialize_for_dotnet_command_line_fn hostfxr_initialize_for_dotnet_command_line = nullptr;
+hostfxr_initialize_for_runtime_config_fn hostfxr_initialize_for_runtime_config = nullptr;
+hostfxr_get_runtime_delegate_fn hostfxr_get_runtime_delegate = nullptr;
+hostfxr_close_fn hostfxr_close = nullptr;
+
+#ifdef _WIN32
+static_assert(sizeof(char_t) == sizeof(char16_t));
+using HostFxrCharString = Char16String;
+#define HOSTFXR_STR(m_str) L##m_str
#else
- if (da_args.length() == 0) {
- return; // Exported games don't use the project settings to setup the debugger agent
- }
+static_assert(sizeof(char_t) == sizeof(char));
+using HostFxrCharString = CharString;
+#define HOSTFXR_STR(m_str) m_str
#endif
- // Debugging enabled
-
- mono_debug_init(MONO_DEBUG_FORMAT_MONO);
-
- // --debugger-agent=help
- const char *options[] = {
- "--soft-breakpoints",
- da_args.get_data()
- };
- mono_jit_parse_options(2, (char **)options);
-}
-
-#endif // !defined(JAVASCRIPT_ENABLED)
-
-#if defined(JAVASCRIPT_ENABLED)
-MonoDomain *gd_initialize_mono_runtime() {
- const char *vfs_prefix = "managed";
- int enable_debugging = 0;
-
- // TODO: Provide a way to enable debugging on WASM release builds.
-#ifdef DEBUG_ENABLED
- enable_debugging = 1;
+HostFxrCharString str_to_hostfxr(const String &p_str) {
+#ifdef _WIN32
+ return p_str.utf16();
+#else
+ return p_str.utf8();
#endif
-
- mono_wasm_load_runtime(vfs_prefix, enable_debugging);
-
- return mono_get_root_domain();
}
-#else
-MonoDomain *gd_initialize_mono_runtime() {
- gd_mono_debug_init();
-#if defined(IOS_ENABLED) || defined(ANDROID_ENABLED)
- // I don't know whether this actually matters or not
- const char *runtime_version = "mobile";
+#ifdef TOOLS_ENABLED
+String str_from_hostfxr(const char_t *p_buffer) {
+#ifdef _WIN32
+ return String::utf16((const char16_t *)p_buffer);
#else
- const char *runtime_version = "v4.0.30319";
+ return String::utf8((const char *)p_buffer);
#endif
-
- return mono_jit_init_version("GodotEngine.RootDomain", runtime_version);
}
#endif
-} // namespace
-
-void GDMono::add_mono_shared_libs_dir_to_path() {
- // TODO: Replace this with a mono_dl_fallback
-
- // By default Mono seems to search shared libraries in the following directories:
- // Current working directory, @executable_path@ and PATH
- // The parent directory of the image file (assembly where the dllimport method is declared)
- // @executable_path@/../lib
- // @executable_path@/../Libraries (__MACH__ only)
- // This does not work when embedding Mono unless we use the same directory structure.
- // To fix this we append the directory containing our shared libraries to PATH.
-
-#if defined(WINDOWS_ENABLED) || defined(UNIX_ENABLED)
- String path_var("PATH");
- String path_value = OS::get_singleton()->get_environment(path_var);
-
-#ifdef WINDOWS_ENABLED
- path_value += ';';
+const char_t *get_data(const HostFxrCharString &p_char_str) {
+ return (const char_t *)p_char_str.get_data();
+}
- String bundled_bin_dir = GodotSharpDirs::get_data_mono_bin_dir();
#ifdef TOOLS_ENABLED
- if (DirAccess::exists(bundled_bin_dir)) {
- path_value += bundled_bin_dir;
- } else {
- path_value += mono_reg_info.bin_dir;
- }
-#else
- if (DirAccess::exists(bundled_bin_dir)) {
- path_value += bundled_bin_dir;
- }
-#endif // TOOLS_ENABLED
+String find_hostfxr(size_t p_known_buffer_size, get_hostfxr_parameters *p_get_hostfxr_params) {
+ // Pre-allocate a large buffer for the path to hostfxr
+ Vector<char_t> buffer;
+ buffer.resize(p_known_buffer_size);
-#else
- path_value += ':';
+ int rc = get_hostfxr_path(buffer.ptrw(), &p_known_buffer_size, p_get_hostfxr_params);
- String bundled_lib_dir = GodotSharpDirs::get_data_mono_lib_dir();
- if (DirAccess::exists(bundled_lib_dir)) {
- path_value += bundled_lib_dir;
- } else {
- // TODO: Do we need to add the lib dir when using the system installed Mono on Unix platforms?
- }
-#endif // WINDOWS_ENABLED
+ ERR_FAIL_COND_V_MSG(rc != 0, String(), "get_hostfxr_path failed with code: " + itos(rc));
- OS::get_singleton()->set_environment(path_var, path_value);
-#endif // WINDOWS_ENABLED || UNIX_ENABLED
+ return str_from_hostfxr(buffer.ptr());
}
+#endif
-void GDMono::determine_mono_dirs(String &r_assembly_rootdir, String &r_config_dir) {
- String bundled_assembly_rootdir = GodotSharpDirs::get_data_mono_lib_dir();
- String bundled_config_dir = GodotSharpDirs::get_data_mono_etc_dir();
-
+String find_hostfxr() {
#ifdef TOOLS_ENABLED
-
-#if defined(WINDOWS_ENABLED)
- mono_reg_info = MonoRegUtils::find_mono();
-
- if (mono_reg_info.assembly_dir.length() && DirAccess::exists(mono_reg_info.assembly_dir)) {
- r_assembly_rootdir = mono_reg_info.assembly_dir;
- }
-
- if (mono_reg_info.config_dir.length() && DirAccess::exists(mono_reg_info.config_dir)) {
- r_config_dir = mono_reg_info.config_dir;
- }
-#elif defined(MACOS_ENABLED)
- const char *c_assembly_rootdir = mono_assembly_getrootdir();
- const char *c_config_dir = mono_get_config_dir();
-
- if (!c_assembly_rootdir || !c_config_dir || !DirAccess::exists(c_assembly_rootdir) || !DirAccess::exists(c_config_dir)) {
- Vector<const char *> locations;
- locations.push_back("/Library/Frameworks/Mono.framework/Versions/Current/");
- locations.push_back("/usr/local/var/homebrew/linked/mono/");
-
- for (int i = 0; i < locations.size(); i++) {
- String hint_assembly_rootdir = path::join(locations[i], "lib");
- String hint_mscorlib_path = path::join(hint_assembly_rootdir, "mono", "4.5", "mscorlib.dll");
- String hint_config_dir = path::join(locations[i], "etc");
-
- if (FileAccess::exists(hint_mscorlib_path) && DirAccess::exists(hint_config_dir)) {
- r_assembly_rootdir = hint_assembly_rootdir;
- r_config_dir = hint_config_dir;
- break;
+ const int CoreHostLibMissingFailure = 0x80008083;
+ const int HostApiBufferTooSmall = 0x80008098;
+
+ size_t buffer_size = 0;
+ int rc = get_hostfxr_path(nullptr, &buffer_size, nullptr);
+
+ if (rc == HostApiBufferTooSmall) {
+ return find_hostfxr(buffer_size, nullptr);
+ }
+
+ if (rc == CoreHostLibMissingFailure) {
+ // Apparently `get_hostfxr_path` doesn't look for dotnet in `PATH`? (I suppose it needs the
+ // `DOTNET_ROOT` environment variable). If it fails, we try to find the dotnet executable
+ // in `PATH` ourselves and pass its location as `dotnet_root` to `get_hostfxr_path`.
+ String dotnet_exe = path::find_executable("dotnet");
+
+ if (!dotnet_exe.is_empty()) {
+ // The file found in PATH may be a symlink
+ dotnet_exe = path::abspath(path::realpath(dotnet_exe));
+
+ // TODO:
+ // Sometimes, the symlink may not point to the dotnet executable in the dotnet root.
+ // That's the case with snaps. The snap install should have been found with the
+ // previous `get_hostfxr_path`, but it would still be better to do this properly
+ // and use something like `dotnet --list-sdks/runtimes` to find the actual location.
+ // This way we could also check if the proper sdk or runtime is installed. This would
+ // allow us to fail gracefully and show some helpful information in the editor.
+
+ HostFxrCharString dotnet_root = str_to_hostfxr(dotnet_exe.get_base_dir());
+
+ get_hostfxr_parameters get_hostfxr_parameters = {
+ sizeof(get_hostfxr_parameters),
+ nullptr,
+ get_data(dotnet_root)
+ };
+
+ buffer_size = 0;
+ rc = get_hostfxr_path(nullptr, &buffer_size, &get_hostfxr_parameters);
+ if (rc == HostApiBufferTooSmall) {
+ return find_hostfxr(buffer_size, &get_hostfxr_parameters);
}
}
}
-#endif
- if (DirAccess::exists(bundled_assembly_rootdir)) {
- r_assembly_rootdir = bundled_assembly_rootdir;
+ if (rc == CoreHostLibMissingFailure) {
+ ERR_PRINT(String() + ".NET: One of the dependent libraries is missing. " +
+ "Typically when the `hostfxr`, `hostpolicy` or `coreclr` dynamic " +
+ "libraries are not present in the expected locations.");
}
- if (DirAccess::exists(bundled_config_dir)) {
- r_config_dir = bundled_config_dir;
- }
-
-#ifdef WINDOWS_ENABLED
- if (r_assembly_rootdir.is_empty() || r_config_dir.is_empty()) {
- ERR_PRINT("Cannot find Mono in the registry.");
- // Assertion: if they are not set, then they weren't found in the registry
- CRASH_COND(mono_reg_info.assembly_dir.length() > 0 || mono_reg_info.config_dir.length() > 0);
- }
-#endif // WINDOWS_ENABLED
-
+ return String();
#else
- // Export templates always use the bundled directories
- r_assembly_rootdir = bundled_assembly_rootdir;
- r_config_dir = bundled_config_dir;
-#endif
-}
-
-void GDMono::initialize() {
- ERR_FAIL_NULL(Engine::get_singleton());
-
- print_verbose("Mono: Initializing module...");
-
- char *runtime_build_info = mono_get_runtime_build_info();
- print_verbose("Mono JIT compiler version " + String(runtime_build_info));
- mono_free(runtime_build_info);
-
- _init_godot_api_hashes();
- _init_exception_policy();
-
- GDMonoLog::get_singleton()->initialize();
-
-#if !defined(JAVASCRIPT_ENABLED)
- String assembly_rootdir;
- String config_dir;
- determine_mono_dirs(assembly_rootdir, config_dir);
-
- // Leak if we call mono_set_dirs more than once
- mono_set_dirs(assembly_rootdir.length() ? assembly_rootdir.utf8().get_data() : nullptr,
- config_dir.length() ? config_dir.utf8().get_data() : nullptr);
- add_mono_shared_libs_dir_to_path();
-#endif
-
-#ifdef ANDROID_ENABLED
- mono_config_parse_memory(get_godot_android_mono_config().utf8().get_data());
+#if defined(WINDOWS_ENABLED)
+ String probe_path = GodotSharpDirs::get_api_assemblies_dir()
+ .path_join("hostfxr.dll");
+#elif defined(MACOS_ENABLED)
+ String probe_path = GodotSharpDirs::get_api_assemblies_dir()
+ .path_join("libhostfxr.dylib");
+#elif defined(UNIX_ENABLED)
+ String probe_path = GodotSharpDirs::get_api_assemblies_dir()
+ .path_join("libhostfxr.so");
#else
- mono_config_parse(nullptr);
+#error "Platform not supported (yet?)"
#endif
-#if defined(ANDROID_ENABLED)
- gdmono::android::support::initialize();
-#elif defined(IOS_ENABLED)
- gdmono::ios::support::initialize();
-#endif
+ if (FileAccess::exists(probe_path)) {
+ return probe_path;
+ }
- GDMonoAssembly::initialize();
+ return String();
-#if !defined(JAVASCRIPT_ENABLED)
- gd_mono_profiler_init();
#endif
+}
- mono_install_unhandled_exception_hook(&unhandled_exception_hook, nullptr);
-
-#ifndef TOOLS_ENABLED
- // Exported games that don't use C# must still work. They likely don't ship with mscorlib.
- // We only initialize the Mono runtime if we can find mscorlib. Otherwise it would crash.
- if (GDMonoAssembly::find_assembly("mscorlib.dll").is_empty()) {
- print_verbose("Mono: Skipping runtime initialization because 'mscorlib.dll' could not be found");
- return;
- }
-#endif
+bool load_hostfxr(void *&r_hostfxr_dll_handle) {
+ String hostfxr_path = find_hostfxr();
-#if !defined(NO_MONO_THREADS_SUSPEND_WORKAROUND)
- // FIXME: Temporary workaround. See: https://github.com/godotengine/godot/issues/29812
- if (!OS::get_singleton()->has_environment("MONO_THREADS_SUSPEND")) {
- OS::get_singleton()->set_environment("MONO_THREADS_SUSPEND", "preemptive");
+ if (hostfxr_path.is_empty()) {
+ return false;
}
-#endif
- // NOTE: Internal calls must be registered after the Mono runtime initialization.
- // Otherwise registration fails with the error: 'assertion 'hash != nullptr' failed'.
+ print_verbose("Found hostfxr: " + hostfxr_path);
- root_domain = gd_initialize_mono_runtime();
- ERR_FAIL_NULL_MSG(root_domain, "Mono: Failed to initialize runtime.");
+ Error err = OS::get_singleton()->open_dynamic_library(hostfxr_path, r_hostfxr_dll_handle);
- GDMonoUtils::set_main_thread(GDMonoUtils::get_current_thread());
-
-#if !defined(JAVASCRIPT_ENABLED)
- gd_mono_setup_runtime_main_args(); // Required for System.Environment.GetCommandLineArgs
-#endif
+ if (err != OK) {
+ return false;
+ }
- runtime_initialized = true;
+ void *lib = r_hostfxr_dll_handle;
- print_verbose("Mono: Runtime initialized");
+ void *symbol = nullptr;
-#if defined(ANDROID_ENABLED)
- gdmono::android::support::register_internal_calls();
-#endif
+ err = OS::get_singleton()->get_dynamic_library_symbol_handle(lib, "hostfxr_initialize_for_dotnet_command_line", symbol);
+ ERR_FAIL_COND_V(err != OK, false);
+ hostfxr_initialize_for_dotnet_command_line = (hostfxr_initialize_for_dotnet_command_line_fn)symbol;
- // mscorlib assembly MUST be present at initialization
- bool corlib_loaded = _load_corlib_assembly();
- ERR_FAIL_COND_MSG(!corlib_loaded, "Mono: Failed to load mscorlib assembly.");
+ err = OS::get_singleton()->get_dynamic_library_symbol_handle(lib, "hostfxr_initialize_for_runtime_config", symbol);
+ ERR_FAIL_COND_V(err != OK, false);
+ hostfxr_initialize_for_runtime_config = (hostfxr_initialize_for_runtime_config_fn)symbol;
-#ifndef GD_MONO_SINGLE_APPDOMAIN
- Error domain_load_err = _load_scripts_domain();
- ERR_FAIL_COND_MSG(domain_load_err != OK, "Mono: Failed to load scripts domain.");
-#else
- scripts_domain = root_domain;
-#endif
+ err = OS::get_singleton()->get_dynamic_library_symbol_handle(lib, "hostfxr_get_runtime_delegate", symbol);
+ ERR_FAIL_COND_V(err != OK, false);
+ hostfxr_get_runtime_delegate = (hostfxr_get_runtime_delegate_fn)symbol;
- _register_internal_calls();
+ err = OS::get_singleton()->get_dynamic_library_symbol_handle(lib, "hostfxr_close", symbol);
+ ERR_FAIL_COND_V(err != OK, false);
+ hostfxr_close = (hostfxr_close_fn)symbol;
- print_verbose("Mono: INITIALIZED");
+ return (hostfxr_initialize_for_runtime_config &&
+ hostfxr_get_runtime_delegate &&
+ hostfxr_close);
}
-void GDMono::initialize_load_assemblies() {
-#ifndef MONO_GLUE_ENABLED
- CRASH_NOW_MSG("Mono: This binary was built with 'mono_glue=no'; cannot load assemblies.");
-#endif
-
- // Load assemblies. The API and tools assemblies are required,
- // the application is aborted if these assemblies cannot be loaded.
-
- _load_api_assemblies();
-
-#if defined(TOOLS_ENABLED)
- bool tool_assemblies_loaded = _load_tools_assemblies();
- CRASH_COND_MSG(!tool_assemblies_loaded, "Mono: Failed to load '" TOOLS_ASM_NAME "' assemblies.");
-
- if (Engine::get_singleton()->is_project_manager_hint()) {
- return;
- }
-#endif
-
- // Load the project's main assembly. This doesn't necessarily need to succeed.
- // The game may not be using .NET at all, or if the project does use .NET and
- // we're running in the editor, it may just happen to be it wasn't built yet.
- if (!_load_project_assembly()) {
- if (OS::get_singleton()->is_stdout_verbose()) {
- print_error("Mono: Failed to load project assembly");
- }
- }
-}
-
-bool GDMono::_are_api_assemblies_out_of_sync() {
- bool out_of_sync = core_api_assembly.assembly && (core_api_assembly.out_of_sync || !GDMonoCache::cached_data.godot_api_cache_updated);
#ifdef TOOLS_ENABLED
- if (!out_of_sync) {
- out_of_sync = editor_api_assembly.assembly && editor_api_assembly.out_of_sync;
+load_assembly_and_get_function_pointer_fn initialize_hostfxr_for_config(const char_t *p_config_path) {
+ hostfxr_handle cxt = nullptr;
+ int rc = hostfxr_initialize_for_runtime_config(p_config_path, nullptr, &cxt);
+ if (rc != 0 || cxt == nullptr) {
+ hostfxr_close(cxt);
+ ERR_FAIL_V_MSG(nullptr, "hostfxr_initialize_for_runtime_config failed with code: " + itos(rc));
}
-#endif
- return out_of_sync;
-}
-namespace GodotSharpBindings {
-#ifdef MONO_GLUE_ENABLED
+ void *load_assembly_and_get_function_pointer = nullptr;
-uint64_t get_core_api_hash();
-#ifdef TOOLS_ENABLED
-uint64_t get_editor_api_hash();
-#endif
-uint32_t get_bindings_version();
-uint32_t get_cs_glue_version();
-
-void register_generated_icalls();
+ rc = hostfxr_get_runtime_delegate(cxt,
+ hdt_load_assembly_and_get_function_pointer, &load_assembly_and_get_function_pointer);
+ if (rc != 0 || load_assembly_and_get_function_pointer == nullptr) {
+ ERR_FAIL_V_MSG(nullptr, "hostfxr_get_runtime_delegate failed with code: " + itos(rc));
+ }
-#else
+ hostfxr_close(cxt);
-uint64_t get_core_api_hash() {
- GD_UNREACHABLE();
-}
-#ifdef TOOLS_ENABLED
-uint64_t get_editor_api_hash() {
- GD_UNREACHABLE();
-}
-#endif
-uint32_t get_bindings_version() {
- GD_UNREACHABLE();
-}
-
-uint32_t get_cs_glue_version() {
- GD_UNREACHABLE();
+ return (load_assembly_and_get_function_pointer_fn)load_assembly_and_get_function_pointer;
}
+#else
+load_assembly_and_get_function_pointer_fn initialize_hostfxr_self_contained(
+ const char_t *p_main_assembly_path) {
+ hostfxr_handle cxt = nullptr;
-void register_generated_icalls() {
- /* Fine, just do nothing */
-}
+ List<String> cmdline_args = OS::get_singleton()->get_cmdline_args();
-#endif // MONO_GLUE_ENABLED
-} // namespace GodotSharpBindings
+ List<HostFxrCharString> argv_store;
+ Vector<const char_t *> argv;
+ argv.resize(cmdline_args.size() + 1);
-void GDMono::_register_internal_calls() {
- GodotSharpBindings::register_generated_icalls();
-}
+ argv.write[0] = p_main_assembly_path;
-void GDMono::_init_godot_api_hashes() {
-#if defined(MONO_GLUE_ENABLED) && defined(DEBUG_METHODS_ENABLED)
- if (get_api_core_hash() != GodotSharpBindings::get_core_api_hash()) {
- ERR_PRINT("Mono: Core API hash mismatch.");
+ int i = 1;
+ for (const String &E : cmdline_args) {
+ HostFxrCharString &stored = argv_store.push_back(str_to_hostfxr(E))->get();
+ argv.write[i] = get_data(stored);
+ i++;
}
-#ifdef TOOLS_ENABLED
- if (get_api_editor_hash() != GodotSharpBindings::get_editor_api_hash()) {
- ERR_PRINT("Mono: Editor API hash mismatch.");
+ int rc = hostfxr_initialize_for_dotnet_command_line(argv.size(), argv.ptrw(), nullptr, &cxt);
+ if (rc != 0 || cxt == nullptr) {
+ hostfxr_close(cxt);
+ ERR_FAIL_V_MSG(nullptr, "hostfxr_initialize_for_dotnet_command_line failed with code: " + itos(rc));
}
-#endif // TOOLS_ENABLED
-#endif // MONO_GLUE_ENABLED && DEBUG_METHODS_ENABLED
-}
-void GDMono::_init_exception_policy() {
- PropertyInfo exc_policy_prop = PropertyInfo(Variant::INT, "mono/runtime/unhandled_exception_policy", PROPERTY_HINT_ENUM,
- vformat("Terminate Application:%s,Log Error:%s", (int)POLICY_TERMINATE_APP, (int)POLICY_LOG_ERROR));
- unhandled_exception_policy = (UnhandledExceptionPolicy)(int)GLOBAL_DEF(exc_policy_prop.name, (int)POLICY_TERMINATE_APP);
- ProjectSettings::get_singleton()->set_custom_property_info(exc_policy_prop.name, exc_policy_prop);
+ void *load_assembly_and_get_function_pointer = nullptr;
- if (Engine::get_singleton()->is_editor_hint()) {
- // Unhandled exceptions should not terminate the editor
- unhandled_exception_policy = POLICY_LOG_ERROR;
+ rc = hostfxr_get_runtime_delegate(cxt,
+ hdt_load_assembly_and_get_function_pointer, &load_assembly_and_get_function_pointer);
+ if (rc != 0 || load_assembly_and_get_function_pointer == nullptr) {
+ ERR_FAIL_V_MSG(nullptr, "hostfxr_get_runtime_delegate failed with code: " + itos(rc));
}
-}
-
-void GDMono::add_assembly(int32_t p_domain_id, GDMonoAssembly *p_assembly) {
- assemblies[p_domain_id][p_assembly->get_name()] = p_assembly;
-}
-GDMonoAssembly *GDMono::get_loaded_assembly(const String &p_name) {
- if (p_name == "mscorlib" && corlib_assembly) {
- return corlib_assembly;
- }
+ hostfxr_close(cxt);
- MonoDomain *domain = mono_domain_get();
- int32_t domain_id = domain ? mono_domain_get_id(domain) : 0;
- GDMonoAssembly **result = assemblies[domain_id].getptr(p_name);
- return result ? *result : nullptr;
+ return (load_assembly_and_get_function_pointer_fn)load_assembly_and_get_function_pointer;
}
-
-bool GDMono::load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(!r_assembly);
#endif
- MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8());
- bool result = load_assembly(p_name, aname, r_assembly, p_refonly);
- mono_assembly_name_free(aname);
- mono_free(aname);
-
- return result;
-}
-
-bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(!r_assembly);
+#ifdef TOOLS_ENABLED
+using godot_plugins_initialize_fn = bool (*)(void *, bool, gdmono::PluginCallbacks *, GDMonoCache::ManagedCallbacks *, const void **, int32_t);
+#else
+using godot_plugins_initialize_fn = bool (*)(void *, GDMonoCache::ManagedCallbacks *, const void **, int32_t);
#endif
- return load_assembly(p_name, p_aname, r_assembly, p_refonly, GDMonoAssembly::get_default_search_dirs());
-}
+#ifdef TOOLS_ENABLED
+godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime_initialized) {
+ godot_plugins_initialize_fn godot_plugins_initialize = nullptr;
-bool GDMono::load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly, const Vector<String> &p_search_dirs) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(!r_assembly);
-#endif
+ HostFxrCharString godot_plugins_path = str_to_hostfxr(
+ GodotSharpDirs::get_api_assemblies_dir().path_join("GodotPlugins.dll"));
- print_verbose("Mono: Loading assembly " + p_name + (p_refonly ? " (refonly)" : "") + "...");
+ HostFxrCharString config_path = str_to_hostfxr(
+ GodotSharpDirs::get_api_assemblies_dir().path_join("GodotPlugins.runtimeconfig.json"));
- GDMonoAssembly *assembly = GDMonoAssembly::load(p_name, p_aname, p_refonly, p_search_dirs);
+ load_assembly_and_get_function_pointer_fn load_assembly_and_get_function_pointer =
+ initialize_hostfxr_for_config(get_data(config_path));
+ ERR_FAIL_NULL_V(load_assembly_and_get_function_pointer, nullptr);
- if (!assembly) {
- return false;
- }
+ r_runtime_initialized = true;
- *r_assembly = assembly;
+ print_verbose(".NET: hostfxr initialized");
- print_verbose("Mono: Assembly " + p_name + (p_refonly ? " (refonly)" : "") + " loaded from path: " + (*r_assembly)->get_path());
+ int rc = load_assembly_and_get_function_pointer(get_data(godot_plugins_path),
+ HOSTFXR_STR("GodotPlugins.Main, GodotPlugins"),
+ HOSTFXR_STR("InitializeFromEngine"),
+ UNMANAGEDCALLERSONLY_METHOD,
+ nullptr,
+ (void **)&godot_plugins_initialize);
+ ERR_FAIL_COND_V_MSG(rc != 0, nullptr, ".NET: Failed to get GodotPlugins initialization function pointer");
- return true;
+ return godot_plugins_initialize;
}
+#else
+static String get_assembly_name() {
+ String assembly_name = ProjectSettings::get_singleton()->get_setting("dotnet/project/assembly_name");
-bool GDMono::load_assembly_from(const String &p_name, const String &p_path, GDMonoAssembly **r_assembly, bool p_refonly) {
- CRASH_COND(!r_assembly);
-
- print_verbose("Mono: Loading assembly " + p_name + (p_refonly ? " (refonly)" : "") + "...");
-
- GDMonoAssembly *assembly = GDMonoAssembly::load_from(p_name, p_path, p_refonly);
-
- if (!assembly) {
- return false;
+ if (assembly_name.is_empty()) {
+ assembly_name = ProjectSettings::get_singleton()->get_safe_project_name();
}
- *r_assembly = assembly;
-
- print_verbose("Mono: Assembly " + p_name + (p_refonly ? " (refonly)" : "") + " loaded from path: " + (*r_assembly)->get_path());
-
- return true;
+ return assembly_name;
}
-ApiAssemblyInfo::Version ApiAssemblyInfo::Version::get_from_loaded_assembly(GDMonoAssembly *p_api_assembly, ApiAssemblyInfo::Type p_api_type) {
- ApiAssemblyInfo::Version api_assembly_version;
+godot_plugins_initialize_fn initialize_hostfxr_and_godot_plugins(bool &r_runtime_initialized) {
+ godot_plugins_initialize_fn godot_plugins_initialize = nullptr;
- const char *nativecalls_name = p_api_type == ApiAssemblyInfo::API_CORE
- ? BINDINGS_CLASS_NATIVECALLS
- : BINDINGS_CLASS_NATIVECALLS_EDITOR;
+ String assembly_name = get_assembly_name();
- GDMonoClass *nativecalls_klass = p_api_assembly->get_class(BINDINGS_NAMESPACE, nativecalls_name);
+ HostFxrCharString assembly_path = str_to_hostfxr(GodotSharpDirs::get_api_assemblies_dir()
+ .path_join(assembly_name + ".dll"));
- if (nativecalls_klass) {
- GDMonoField *api_hash_field = nativecalls_klass->get_field("godot_api_hash");
- if (api_hash_field) {
- api_assembly_version.godot_api_hash = GDMonoMarshal::unbox<uint64_t>(api_hash_field->get_value(nullptr));
- }
+ load_assembly_and_get_function_pointer_fn load_assembly_and_get_function_pointer =
+ initialize_hostfxr_self_contained(get_data(assembly_path));
+ ERR_FAIL_NULL_V(load_assembly_and_get_function_pointer, nullptr);
- GDMonoField *binds_ver_field = nativecalls_klass->get_field("bindings_version");
- if (binds_ver_field) {
- api_assembly_version.bindings_version = GDMonoMarshal::unbox<uint32_t>(binds_ver_field->get_value(nullptr));
- }
+ r_runtime_initialized = true;
- GDMonoField *cs_glue_ver_field = nativecalls_klass->get_field("cs_glue_version");
- if (cs_glue_ver_field) {
- api_assembly_version.cs_glue_version = GDMonoMarshal::unbox<uint32_t>(cs_glue_ver_field->get_value(nullptr));
- }
- }
+ print_verbose(".NET: hostfxr initialized");
- return api_assembly_version;
-}
+ int rc = load_assembly_and_get_function_pointer(get_data(assembly_path),
+ get_data(str_to_hostfxr("GodotPlugins.Game.Main, " + assembly_name)),
+ HOSTFXR_STR("InitializeFromGameProject"),
+ UNMANAGEDCALLERSONLY_METHOD,
+ nullptr,
+ (void **)&godot_plugins_initialize);
+ ERR_FAIL_COND_V_MSG(rc != 0, nullptr, ".NET: Failed to get GodotPlugins initialization function pointer");
-String ApiAssemblyInfo::to_string(ApiAssemblyInfo::Type p_type) {
- return p_type == ApiAssemblyInfo::API_CORE ? "API_CORE" : "API_EDITOR";
+ return godot_plugins_initialize;
}
-bool GDMono::_load_corlib_assembly() {
- if (corlib_assembly) {
- return true;
- }
-
- bool success = load_assembly("mscorlib", &corlib_assembly);
-
- if (success) {
- GDMonoCache::update_corlib_cache();
- }
-
- return success;
-}
+godot_plugins_initialize_fn try_load_native_aot_library(void *&r_aot_dll_handle) {
+ String assembly_name = get_assembly_name();
-#ifdef TOOLS_ENABLED
-bool GDMono::copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const String &p_config) {
- String src_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config);
- String dst_dir = GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config);
-
- String assembly_name = p_api_type == ApiAssemblyInfo::API_CORE ? CORE_API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME;
+#if defined(WINDOWS_ENABLED)
+ String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().path_join(assembly_name + ".dll");
+#elif defined(MACOS_ENABLED)
+ String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().path_join(assembly_name + ".dylib");
+#elif defined(UNIX_ENABLED)
+ String native_aot_so_path = GodotSharpDirs::get_api_assemblies_dir().path_join(assembly_name + ".so");
+#else
+#error "Platform not supported (yet?)"
+#endif
- // Create destination directory if needed
- if (!DirAccess::exists(dst_dir)) {
- Ref<DirAccess> da = DirAccess::create_for_path(dst_dir);
- Error err = da->make_dir_recursive(dst_dir);
+ if (FileAccess::exists(native_aot_so_path)) {
+ Error err = OS::get_singleton()->open_dynamic_library(native_aot_so_path, r_aot_dll_handle);
if (err != OK) {
- ERR_PRINT("Failed to create destination directory for the API assemblies. Error: " + itos(err) + ".");
- return false;
+ return nullptr;
}
- }
- Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ void *lib = r_aot_dll_handle;
- String xml_file = assembly_name + ".xml";
- if (da->copy(src_dir.plus_file(xml_file), dst_dir.plus_file(xml_file)) != OK) {
- WARN_PRINT("Failed to copy '" + xml_file + "'.");
- }
+ void *symbol = nullptr;
- String pdb_file = assembly_name + ".pdb";
- if (da->copy(src_dir.plus_file(pdb_file), dst_dir.plus_file(pdb_file)) != OK) {
- WARN_PRINT("Failed to copy '" + pdb_file + "'.");
+ err = OS::get_singleton()->get_dynamic_library_symbol_handle(lib, "godotsharp_game_main_init", symbol);
+ ERR_FAIL_COND_V(err != OK, nullptr);
+ return (godot_plugins_initialize_fn)symbol;
}
- String assembly_file = assembly_name + ".dll";
- if (da->copy(src_dir.plus_file(assembly_file), dst_dir.plus_file(assembly_file)) != OK) {
- ERR_PRINT("Failed to copy '" + assembly_file + "'.");
- return false;
- }
-
- return true;
+ return nullptr;
}
+#endif
-static bool try_get_cached_api_hash_for(const String &p_api_assemblies_dir, bool &r_out_of_sync) {
- String core_api_assembly_path = p_api_assemblies_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
- String editor_api_assembly_path = p_api_assemblies_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
-
- if (!FileAccess::exists(core_api_assembly_path) || !FileAccess::exists(editor_api_assembly_path)) {
- return false;
- }
-
- String cached_api_hash_path = p_api_assemblies_dir.plus_file("api_hash_cache.cfg");
+} // namespace
- if (!FileAccess::exists(cached_api_hash_path)) {
+static bool _on_core_api_assembly_loaded() {
+ if (!GDMonoCache::godot_api_cache_updated) {
return false;
}
- Ref<ConfigFile> cfg;
- cfg.instantiate();
- Error cfg_err = cfg->load(cached_api_hash_path);
- ERR_FAIL_COND_V(cfg_err != OK, false);
-
- // Checking the modified time is good enough
- if (FileAccess::get_modified_time(core_api_assembly_path) != (uint64_t)cfg->get_value("core", "modified_time") ||
- FileAccess::get_modified_time(editor_api_assembly_path) != (uint64_t)cfg->get_value("editor", "modified_time")) {
- return false;
- }
+ bool debug;
+#ifdef DEBUG_ENABLED
+ debug = true;
+#else
+ debug = false;
+#endif
- r_out_of_sync = GodotSharpBindings::get_bindings_version() != (uint32_t)cfg->get_value("core", "bindings_version") ||
- GodotSharpBindings::get_cs_glue_version() != (uint32_t)cfg->get_value("core", "cs_glue_version") ||
- GodotSharpBindings::get_bindings_version() != (uint32_t)cfg->get_value("editor", "bindings_version") ||
- GodotSharpBindings::get_cs_glue_version() != (uint32_t)cfg->get_value("editor", "cs_glue_version") ||
- GodotSharpBindings::get_core_api_hash() != (uint64_t)cfg->get_value("core", "api_hash") ||
- GodotSharpBindings::get_editor_api_hash() != (uint64_t)cfg->get_value("editor", "api_hash");
+ GDMonoCache::managed_callbacks.GD_OnCoreApiAssemblyLoaded(debug);
return true;
}
-static void create_cached_api_hash_for(const String &p_api_assemblies_dir) {
- String core_api_assembly_path = p_api_assemblies_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
- String editor_api_assembly_path = p_api_assemblies_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
- String cached_api_hash_path = p_api_assemblies_dir.plus_file("api_hash_cache.cfg");
-
- Ref<ConfigFile> cfg;
- cfg.instantiate();
-
- cfg->set_value("core", "modified_time", FileAccess::get_modified_time(core_api_assembly_path));
- cfg->set_value("editor", "modified_time", FileAccess::get_modified_time(editor_api_assembly_path));
-
- cfg->set_value("core", "bindings_version", GodotSharpBindings::get_bindings_version());
- cfg->set_value("core", "cs_glue_version", GodotSharpBindings::get_cs_glue_version());
- cfg->set_value("editor", "bindings_version", GodotSharpBindings::get_bindings_version());
- cfg->set_value("editor", "cs_glue_version", GodotSharpBindings::get_cs_glue_version());
-
- // This assumes the prebuilt api assemblies we copied to the project are not out of sync
- cfg->set_value("core", "api_hash", GodotSharpBindings::get_core_api_hash());
- cfg->set_value("editor", "api_hash", GodotSharpBindings::get_editor_api_hash());
-
- Error err = cfg->save(cached_api_hash_path);
- ERR_FAIL_COND(err != OK);
-}
-
-bool GDMono::_temp_domain_load_are_assemblies_out_of_sync(const String &p_config) {
- MonoDomain *temp_domain = GDMonoUtils::create_domain("GodotEngine.Domain.CheckApiAssemblies");
- ERR_FAIL_NULL_V(temp_domain, "Failed to create temporary domain to check API assemblies");
- _GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(temp_domain);
-
- _GDMONO_SCOPE_DOMAIN_(temp_domain);
-
- GDMono::LoadedApiAssembly temp_core_api_assembly;
- GDMono::LoadedApiAssembly temp_editor_api_assembly;
-
- if (!_try_load_api_assemblies(temp_core_api_assembly, temp_editor_api_assembly,
- p_config, /* refonly: */ true, /* loaded_callback: */ nullptr)) {
- return temp_core_api_assembly.out_of_sync || temp_editor_api_assembly.out_of_sync;
- }
-
- return true; // Failed to load, assume they're outdated assemblies
-}
-
-String GDMono::update_api_assemblies_from_prebuilt(const String &p_config, const bool *p_core_api_out_of_sync, const bool *p_editor_api_out_of_sync) {
-#define FAIL_REASON(m_out_of_sync, m_prebuilt_exists) \
- ( \
- (m_out_of_sync ? String("The assembly is invalidated ") : String("The assembly was not found ")) + \
- (m_prebuilt_exists ? String("and the prebuilt assemblies are missing.") : String("and we failed to copy the prebuilt assemblies.")))
+void GDMono::initialize() {
+ print_verbose(".NET: Initializing module...");
- String dst_assemblies_dir = GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config);
+ _init_godot_api_hashes();
- String core_assembly_path = dst_assemblies_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
- String editor_assembly_path = dst_assemblies_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
+ godot_plugins_initialize_fn godot_plugins_initialize = nullptr;
- bool api_assemblies_out_of_sync = false;
+ if (!load_hostfxr(hostfxr_dll_handle)) {
+#if !defined(TOOLS_ENABLED)
+ godot_plugins_initialize = try_load_native_aot_library(hostfxr_dll_handle);
- if (p_core_api_out_of_sync && p_editor_api_out_of_sync) {
- api_assemblies_out_of_sync = p_core_api_out_of_sync || p_editor_api_out_of_sync;
- } else if (FileAccess::exists(core_assembly_path) && FileAccess::exists(editor_assembly_path)) {
- // Determine if they're out of sync
- if (!try_get_cached_api_hash_for(dst_assemblies_dir, api_assemblies_out_of_sync)) {
- api_assemblies_out_of_sync = _temp_domain_load_are_assemblies_out_of_sync(p_config);
+ if (godot_plugins_initialize != nullptr) {
+ is_native_aot = true;
+ } else {
+ ERR_FAIL_MSG(".NET: Failed to load hostfxr");
}
+#else
+ ERR_FAIL_MSG(".NET: Failed to load hostfxr");
+#endif
}
- // Note: Even if only one of the assemblies if missing or out of sync, we update both
-
- if (!api_assemblies_out_of_sync && FileAccess::exists(core_assembly_path) && FileAccess::exists(editor_assembly_path)) {
- return String(); // No update needed
- }
-
- print_verbose("Updating '" + p_config + "' API assemblies");
-
- String prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config);
- String prebuilt_core_dll_path = prebuilt_api_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
- String prebuilt_editor_dll_path = prebuilt_api_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
-
- if (!FileAccess::exists(prebuilt_core_dll_path) || !FileAccess::exists(prebuilt_editor_dll_path)) {
- return FAIL_REASON(api_assemblies_out_of_sync, /* prebuilt_exists: */ false);
+ if (!is_native_aot) {
+ godot_plugins_initialize = initialize_hostfxr_and_godot_plugins(runtime_initialized);
+ ERR_FAIL_NULL(godot_plugins_initialize);
}
- // Copy the prebuilt Api
- if (!copy_prebuilt_api_assembly(ApiAssemblyInfo::API_CORE, p_config) ||
- !copy_prebuilt_api_assembly(ApiAssemblyInfo::API_EDITOR, p_config)) {
- return FAIL_REASON(api_assemblies_out_of_sync, /* prebuilt_exists: */ true);
- }
+ int32_t interop_funcs_size = 0;
+ const void **interop_funcs = godotsharp::get_runtime_interop_funcs(interop_funcs_size);
- // Cache the api hash of the assemblies we just copied
- create_cached_api_hash_for(dst_assemblies_dir);
+ GDMonoCache::ManagedCallbacks managed_callbacks{};
- return String(); // Updated successfully
+ void *godot_dll_handle = nullptr;
-#undef FAIL_REASON
-}
+#if defined(UNIX_ENABLED) && !defined(MACOS_ENABLED) && !defined(IOS_ENABLED)
+ // Managed code can access it on its own on other platforms
+ godot_dll_handle = dlopen(nullptr, RTLD_NOW);
#endif
-bool GDMono::_load_core_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, const String &p_config, bool p_refonly) {
- if (r_loaded_api_assembly.assembly) {
- return true;
- }
-
#ifdef TOOLS_ENABLED
- // For the editor and the editor player we want to load it from a specific path to make sure we can keep it up to date
-
- // If running the project manager, load it from the prebuilt API directory
- String assembly_dir = !Engine::get_singleton()->is_project_manager_hint()
- ? GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config)
- : GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config);
-
- String assembly_path = assembly_dir.plus_file(CORE_API_ASSEMBLY_NAME ".dll");
-
- bool success = FileAccess::exists(assembly_path) &&
- load_assembly_from(CORE_API_ASSEMBLY_NAME, assembly_path, &r_loaded_api_assembly.assembly, p_refonly);
+ gdmono::PluginCallbacks plugin_callbacks_res;
+ bool init_ok = godot_plugins_initialize(godot_dll_handle,
+ Engine::get_singleton()->is_editor_hint(),
+ &plugin_callbacks_res, &managed_callbacks,
+ interop_funcs, interop_funcs_size);
+ ERR_FAIL_COND_MSG(!init_ok, ".NET: GodotPlugins initialization failed");
+
+ plugin_callbacks = plugin_callbacks_res;
#else
- bool success = load_assembly(CORE_API_ASSEMBLY_NAME, &r_loaded_api_assembly.assembly, p_refonly);
+ bool init_ok = godot_plugins_initialize(godot_dll_handle, &managed_callbacks,
+ interop_funcs, interop_funcs_size);
+ ERR_FAIL_COND_MSG(!init_ok, ".NET: GodotPlugins initialization failed");
#endif
- if (success) {
- ApiAssemblyInfo::Version api_assembly_ver = ApiAssemblyInfo::Version::get_from_loaded_assembly(r_loaded_api_assembly.assembly, ApiAssemblyInfo::API_CORE);
- r_loaded_api_assembly.out_of_sync = GodotSharpBindings::get_core_api_hash() != api_assembly_ver.godot_api_hash ||
- GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version ||
- GodotSharpBindings::get_cs_glue_version() != api_assembly_ver.cs_glue_version;
- } else {
- r_loaded_api_assembly.out_of_sync = false;
- }
+ GDMonoCache::update_godot_api_cache(managed_callbacks);
- return success;
-}
+ print_verbose(".NET: GodotPlugins initialized");
-#ifdef TOOLS_ENABLED
-bool GDMono::_load_editor_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, const String &p_config, bool p_refonly) {
- if (r_loaded_api_assembly.assembly) {
- return true;
- }
-
- // For the editor and the editor player we want to load it from a specific path to make sure we can keep it up to date
-
- // If running the project manager, load it from the prebuilt API directory
- String assembly_dir = !Engine::get_singleton()->is_project_manager_hint()
- ? GodotSharpDirs::get_res_assemblies_base_dir().plus_file(p_config)
- : GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file(p_config);
-
- String assembly_path = assembly_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll");
-
- bool success = FileAccess::exists(assembly_path) &&
- load_assembly_from(EDITOR_API_ASSEMBLY_NAME, assembly_path, &r_loaded_api_assembly.assembly, p_refonly);
-
- if (success) {
- ApiAssemblyInfo::Version api_assembly_ver = ApiAssemblyInfo::Version::get_from_loaded_assembly(r_loaded_api_assembly.assembly, ApiAssemblyInfo::API_EDITOR);
- r_loaded_api_assembly.out_of_sync = GodotSharpBindings::get_editor_api_hash() != api_assembly_ver.godot_api_hash ||
- GodotSharpBindings::get_bindings_version() != api_assembly_ver.bindings_version ||
- GodotSharpBindings::get_cs_glue_version() != api_assembly_ver.cs_glue_version;
- } else {
- r_loaded_api_assembly.out_of_sync = false;
- }
-
- return success;
+ _on_core_api_assembly_loaded();
}
-#endif
-bool GDMono::_try_load_api_assemblies(LoadedApiAssembly &r_core_api_assembly, LoadedApiAssembly &r_editor_api_assembly,
- const String &p_config, bool p_refonly, CoreApiAssemblyLoadedCallback p_callback) {
- if (!_load_core_api_assembly(r_core_api_assembly, p_config, p_refonly)) {
- if (OS::get_singleton()->is_stdout_verbose()) {
- print_error("Mono: Failed to load Core API assembly");
- }
- return false;
+#ifdef TOOLS_ENABLED
+void GDMono::initialize_load_assemblies() {
+ if (Engine::get_singleton()->is_project_manager_hint()) {
+ return;
}
-#ifdef TOOLS_ENABLED
- if (!_load_editor_api_assembly(r_editor_api_assembly, p_config, p_refonly)) {
+ // Load the project's main assembly. This doesn't necessarily need to succeed.
+ // The game may not be using .NET at all, or if the project does use .NET and
+ // we're running in the editor, it may just happen to be it wasn't built yet.
+ if (!_load_project_assembly()) {
if (OS::get_singleton()->is_stdout_verbose()) {
- print_error("Mono: Failed to load Editor API assembly");
+ print_error(".NET: Failed to load project assembly");
}
- return false;
}
-
- if (r_editor_api_assembly.out_of_sync) {
- return false;
- }
-#endif
-
- // Check if the core API assembly is out of sync only after trying to load the
- // editor API assembly. Otherwise, if both assemblies are out of sync, we would
- // only update the former as we won't know the latter also needs to be updated.
- if (r_core_api_assembly.out_of_sync) {
- return false;
- }
-
- if (p_callback) {
- return p_callback();
- }
-
- return true;
}
-
-bool GDMono::_on_core_api_assembly_loaded() {
- GDMonoCache::update_godot_api_cache();
-
- if (!GDMonoCache::cached_data.godot_api_cache_updated) {
- return false;
- }
-
- get_singleton()->_install_trace_listener();
-
- return true;
-}
-
-bool GDMono::_try_load_api_assemblies_preset() {
- return _try_load_api_assemblies(core_api_assembly, editor_api_assembly,
- get_expected_api_build_config(), /* refonly: */ false, _on_core_api_assembly_loaded);
-}
-
-void GDMono::_load_api_assemblies() {
- bool api_assemblies_loaded = _try_load_api_assemblies_preset();
-
-#if defined(TOOLS_ENABLED) && !defined(GD_MONO_SINGLE_APPDOMAIN)
- if (!api_assemblies_loaded) {
- // The API assemblies are out of sync or some other error happened. Fine, try one more time, but
- // this time update them from the prebuilt assemblies directory before trying to load them again.
-
- // Shouldn't happen. The project manager loads the prebuilt API assemblies
- CRASH_COND_MSG(Engine::get_singleton()->is_project_manager_hint(), "Failed to load one of the prebuilt API assemblies.");
-
- // 1. Unload the scripts domain
- Error domain_unload_err = _unload_scripts_domain();
- CRASH_COND_MSG(domain_unload_err != OK, "Mono: Failed to unload scripts domain.");
-
- // 2. Update the API assemblies
- String update_error = update_api_assemblies_from_prebuilt("Debug", &core_api_assembly.out_of_sync, &editor_api_assembly.out_of_sync);
- CRASH_COND_MSG(!update_error.is_empty(), update_error);
-
- // 3. Load the scripts domain again
- Error domain_load_err = _load_scripts_domain();
- CRASH_COND_MSG(domain_load_err != OK, "Mono: Failed to load scripts domain.");
-
- // 4. Try loading the updated assemblies
- api_assemblies_loaded = _try_load_api_assemblies_preset();
- }
#endif
- if (!api_assemblies_loaded) {
- // welp... too bad
-
- if (_are_api_assemblies_out_of_sync()) {
- if (core_api_assembly.out_of_sync) {
- ERR_PRINT("The assembly '" CORE_API_ASSEMBLY_NAME "' is out of sync.");
- } else if (!GDMonoCache::cached_data.godot_api_cache_updated) {
- ERR_PRINT("The loaded assembly '" CORE_API_ASSEMBLY_NAME "' is in sync, but the cache update failed.");
- }
+void GDMono::_init_godot_api_hashes() {
+#ifdef DEBUG_METHODS_ENABLED
+ get_api_core_hash();
#ifdef TOOLS_ENABLED
- if (editor_api_assembly.out_of_sync) {
- ERR_PRINT("The assembly '" EDITOR_API_ASSEMBLY_NAME "' is out of sync.");
- }
-#endif
-
- CRASH_NOW();
- } else {
- CRASH_NOW_MSG("Failed to load one of the API assemblies.");
- }
- }
+ get_api_editor_hash();
+#endif // TOOLS_ENABLED
+#endif // DEBUG_METHODS_ENABLED
}
#ifdef TOOLS_ENABLED
-bool GDMono::_load_tools_assemblies() {
- if (tools_assembly && tools_project_editor_assembly) {
- return true;
- }
-
- bool success = load_assembly(TOOLS_ASM_NAME, &tools_assembly) &&
- load_assembly(TOOLS_PROJECT_EDITOR_ASM_NAME, &tools_project_editor_assembly);
-
- return success;
-}
-#endif
-
bool GDMono::_load_project_assembly() {
- if (project_assembly) {
- return true;
- }
-
- String appname = ProjectSettings::get_singleton()->get("application/config/name");
- String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
- if (appname_safe.is_empty()) {
- appname_safe = "UnnamedProject";
- }
-
- bool success = load_assembly(appname_safe, &project_assembly);
-
- if (success) {
- mono_assembly_set_main(project_assembly->get_assembly());
- CSharpLanguage::get_singleton()->lookup_scripts_in_assembly(project_assembly);
- }
-
- return success;
-}
+ String assembly_name = ProjectSettings::get_singleton()->get_setting("dotnet/project/assembly_name");
-void GDMono::_install_trace_listener() {
-#ifdef DEBUG_ENABLED
- // Install the trace listener now before the project assembly is loaded
- GDMonoClass *debug_utils = get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, "DebuggingUtils");
- GDMonoMethod *install_func = debug_utils->get_method("InstallTraceListener");
-
- MonoException *exc = nullptr;
- install_func->invoke_raw(nullptr, nullptr, &exc);
- if (exc) {
- GDMonoUtils::debug_print_unhandled_exception(exc);
- ERR_PRINT("Failed to install 'System.Diagnostics.Trace' listener.");
+ if (assembly_name.is_empty()) {
+ assembly_name = ProjectSettings::get_singleton()->get_safe_project_name();
}
-#endif
-}
-
-#ifndef GD_MONO_SINGLE_APPDOMAIN
-Error GDMono::_load_scripts_domain() {
- ERR_FAIL_COND_V(scripts_domain != nullptr, ERR_BUG);
-
- print_verbose("Mono: Loading scripts domain...");
-
- scripts_domain = GDMonoUtils::create_domain("GodotEngine.Domain.Scripts");
- ERR_FAIL_NULL_V_MSG(scripts_domain, ERR_CANT_CREATE, "Mono: Could not create scripts app domain.");
-
- mono_domain_set(scripts_domain, true);
-
- return OK;
-}
-
-Error GDMono::_unload_scripts_domain() {
- ERR_FAIL_NULL_V(scripts_domain, ERR_BUG);
-
- print_verbose("Mono: Finalizing scripts domain...");
-
- if (mono_domain_get() != root_domain) {
- mono_domain_set(root_domain, true);
- }
+ String assembly_path = GodotSharpDirs::get_res_temp_assemblies_dir()
+ .path_join(assembly_name + ".dll");
+ assembly_path = ProjectSettings::get_singleton()->globalize_path(assembly_path);
- finalizing_scripts_domain = true;
-
- if (!mono_domain_finalize(scripts_domain, 2000)) {
- ERR_PRINT("Mono: Domain finalization timeout.");
+ if (!FileAccess::exists(assembly_path)) {
+ return false;
}
- finalizing_scripts_domain = false;
-
- mono_gc_collect(mono_gc_max_generation());
-
- GDMonoCache::clear_godot_api_cache();
-
- _domain_assemblies_cleanup(mono_domain_get_id(scripts_domain));
-
- core_api_assembly.assembly = nullptr;
-#ifdef TOOLS_ENABLED
- editor_api_assembly.assembly = nullptr;
-#endif
-
- project_assembly = nullptr;
-#ifdef TOOLS_ENABLED
- tools_assembly = nullptr;
- tools_project_editor_assembly = nullptr;
-#endif
-
- MonoDomain *domain = scripts_domain;
- scripts_domain = nullptr;
-
- print_verbose("Mono: Unloading scripts domain...");
+ String loaded_assembly_path;
+ bool success = plugin_callbacks.LoadProjectAssemblyCallback(assembly_path.utf16(), &loaded_assembly_path);
- MonoException *exc = nullptr;
- mono_domain_try_unload(domain, (MonoObject **)&exc);
-
- if (exc) {
- ERR_PRINT("Exception thrown when unloading scripts domain.");
- GDMonoUtils::debug_unhandled_exception(exc);
- return FAILED;
+ if (success) {
+ project_assembly_path = loaded_assembly_path.simplify_path();
+ project_assembly_modified_time = FileAccess::get_modified_time(loaded_assembly_path);
}
- return OK;
+ return success;
}
#endif
#ifdef GD_MONO_HOT_RELOAD
-Error GDMono::reload_scripts_domain() {
+Error GDMono::reload_project_assemblies() {
ERR_FAIL_COND_V(!runtime_initialized, ERR_BUG);
- if (scripts_domain) {
- Error domain_unload_err = _unload_scripts_domain();
- ERR_FAIL_COND_V_MSG(domain_unload_err != OK, domain_unload_err, "Mono: Failed to unload scripts domain.");
- }
-
- CSharpLanguage::get_singleton()->_on_scripts_domain_unloaded();
-
- Error domain_load_err = _load_scripts_domain();
- ERR_FAIL_COND_V_MSG(domain_load_err != OK, domain_load_err, "Mono: Failed to load scripts domain.");
+ finalizing_scripts_domain = true;
- // Load assemblies. The API and tools assemblies are required,
- // the application is aborted if these assemblies cannot be loaded.
+ CSharpLanguage::get_singleton()->_on_scripts_domain_about_to_unload();
- _load_api_assemblies();
+ if (!get_plugin_callbacks().UnloadProjectPluginCallback()) {
+ ERR_FAIL_V_MSG(Error::FAILED, ".NET: Failed to unload assemblies.");
+ }
-#if defined(TOOLS_ENABLED)
- bool tools_assemblies_loaded = _load_tools_assemblies();
- CRASH_COND_MSG(!tools_assemblies_loaded, "Mono: Failed to load '" TOOLS_ASM_NAME "' assemblies.");
-#endif
+ finalizing_scripts_domain = false;
// Load the project's main assembly. Here, during hot-reloading, we do
// consider failing to load the project's main assembly to be an error.
- // However, unlike the API and tools assemblies, the application can continue working.
if (!_load_project_assembly()) {
- print_error("Mono: Failed to load project assembly");
+ print_error(".NET: Failed to load project assembly.");
return ERR_CANT_OPEN;
}
@@ -1123,204 +558,38 @@ Error GDMono::reload_scripts_domain() {
}
#endif
-#ifndef GD_MONO_SINGLE_APPDOMAIN
-Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
- CRASH_COND(p_domain == nullptr);
- CRASH_COND(p_domain == GDMono::get_singleton()->get_scripts_domain()); // Should use _unload_scripts_domain() instead
-
- String domain_name = mono_domain_get_friendly_name(p_domain);
-
- print_verbose("Mono: Unloading domain '" + domain_name + "'...");
-
- if (mono_domain_get() == p_domain) {
- mono_domain_set(root_domain, true);
- }
-
- if (!mono_domain_finalize(p_domain, 2000)) {
- ERR_PRINT("Mono: Domain finalization timeout.");
- }
-
- mono_gc_collect(mono_gc_max_generation());
-
- _domain_assemblies_cleanup(mono_domain_get_id(p_domain));
-
- MonoException *exc = nullptr;
- mono_domain_try_unload(p_domain, (MonoObject **)&exc);
-
- if (exc) {
- ERR_PRINT("Exception thrown when unloading domain '" + domain_name + "'.");
- GDMonoUtils::debug_print_unhandled_exception(exc);
- return FAILED;
- }
-
- return OK;
-}
-#endif
-
-GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) {
- MonoImage *image = mono_class_get_image(p_raw_class);
-
- if (image == corlib_assembly->get_image()) {
- return corlib_assembly->get_class(p_raw_class);
- }
-
- int32_t domain_id = mono_domain_get_id(mono_domain_get());
- HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id];
-
- for (const KeyValue<String, GDMonoAssembly *> &E : domain_assemblies) {
- GDMonoAssembly *assembly = E.value;
- if (assembly->get_image() == image) {
- GDMonoClass *klass = assembly->get_class(p_raw_class);
- if (klass) {
- return klass;
- }
- }
- }
-
- return nullptr;
-}
-
-GDMonoClass *GDMono::get_class(const StringName &p_namespace, const StringName &p_name) {
- GDMonoClass *klass = corlib_assembly->get_class(p_namespace, p_name);
- if (klass) {
- return klass;
- }
-
- int32_t domain_id = mono_domain_get_id(mono_domain_get());
- HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id];
-
- for (const KeyValue<String, GDMonoAssembly *> &E : domain_assemblies) {
- GDMonoAssembly *assembly = E.value;
- klass = assembly->get_class(p_namespace, p_name);
- if (klass) {
- return klass;
- }
- }
-
- return nullptr;
-}
-
-void GDMono::_domain_assemblies_cleanup(int32_t p_domain_id) {
- HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[p_domain_id];
-
- for (const KeyValue<String, GDMonoAssembly *> &E : domain_assemblies) {
- memdelete(E.value);
- }
-
- assemblies.erase(p_domain_id);
-}
-
-void GDMono::unhandled_exception_hook(MonoObject *p_exc, void *) {
- // This method will be called by the runtime when a thrown exception is not handled.
- // It won't be called when we manually treat a thrown exception as unhandled.
- // We assume the exception was already printed before calling this hook.
-
-#ifdef DEBUG_ENABLED
- GDMonoUtils::debug_send_unhandled_exception_error((MonoException *)p_exc);
- if (EngineDebugger::is_active()) {
- EngineDebugger::get_singleton()->poll_events(false);
- }
-#endif
-
- exit(mono_environment_exitcode_get());
-
- GD_UNREACHABLE();
-}
-
GDMono::GDMono() {
singleton = this;
- gdmono_log = memnew(GDMonoLog);
-
runtime_initialized = false;
finalizing_scripts_domain = false;
- root_domain = nullptr;
- scripts_domain = nullptr;
-
- corlib_assembly = nullptr;
- project_assembly = nullptr;
-#ifdef TOOLS_ENABLED
- tools_assembly = nullptr;
- tools_project_editor_assembly = nullptr;
-#endif
-
api_core_hash = 0;
#ifdef TOOLS_ENABLED
api_editor_hash = 0;
#endif
-
- unhandled_exception_policy = POLICY_TERMINATE_APP;
}
GDMono::~GDMono() {
- if (is_runtime_initialized()) {
-#ifndef GD_MONO_SINGLE_APPDOMAIN
- if (scripts_domain) {
- Error err = _unload_scripts_domain();
- if (err != OK) {
- ERR_PRINT("Mono: Failed to unload scripts domain.");
- }
- }
-#else
- CRASH_COND(scripts_domain != root_domain);
-
- print_verbose("Mono: Finalizing scripts domain...");
-
- if (mono_domain_get() != root_domain) {
- mono_domain_set(root_domain, true);
- }
-
- finalizing_scripts_domain = true;
-
- if (!mono_domain_finalize(root_domain, 2000)) {
- ERR_PRINT("Mono: Domain finalization timeout.");
- }
-
- finalizing_scripts_domain = false;
-
- mono_gc_collect(mono_gc_max_generation());
-
- GDMonoCache::clear_godot_api_cache();
-
- _domain_assemblies_cleanup(mono_domain_get_id(root_domain));
-
- core_api_assembly.assembly = nullptr;
-
- project_assembly = nullptr;
-
- root_domain = nullptr;
- scripts_domain = nullptr;
-
- // Leave the rest to 'mono_jit_cleanup'
-#endif
-
- for (const KeyValue<int32_t, HashMap<String, GDMonoAssembly *>> &E : assemblies) {
- const HashMap<String, GDMonoAssembly *> &domain_assemblies = E.value;
+ finalizing_scripts_domain = true;
- for (const KeyValue<String, GDMonoAssembly *> &F : domain_assemblies) {
- memdelete(F.value);
- }
+ if (is_runtime_initialized()) {
+ if (GDMonoCache::godot_api_cache_updated) {
+ GDMonoCache::managed_callbacks.DisposablesTracker_OnGodotShuttingDown();
}
- assemblies.clear();
-
- print_verbose("Mono: Runtime cleanup...");
-
- mono_jit_cleanup(root_domain);
-
- print_verbose("Mono: Finalized");
+ }
- runtime_initialized = false;
+ if (hostfxr_dll_handle) {
+ OS::get_singleton()->close_dynamic_library(hostfxr_dll_handle);
}
+ finalizing_scripts_domain = false;
+ runtime_initialized = false;
+
#if defined(ANDROID_ENABLED)
gdmono::android::support::cleanup();
#endif
- if (gdmono_log) {
- memdelete(gdmono_log);
- }
-
singleton = nullptr;
}
@@ -1328,62 +597,7 @@ namespace mono_bind {
GodotSharp *GodotSharp::singleton = nullptr;
-void GodotSharp::attach_thread() {
- GDMonoUtils::attach_current_thread();
-}
-
-void GodotSharp::detach_thread() {
- GDMonoUtils::detach_current_thread();
-}
-
-int32_t GodotSharp::get_domain_id() {
- MonoDomain *domain = mono_domain_get();
- ERR_FAIL_NULL_V(domain, -1);
- return mono_domain_get_id(domain);
-}
-
-int32_t GodotSharp::get_scripts_domain_id() {
- ERR_FAIL_NULL_V_MSG(GDMono::get_singleton(),
- -1, "The Mono runtime is not initialized");
- MonoDomain *domain = GDMono::get_singleton()->get_scripts_domain();
- ERR_FAIL_NULL_V(domain, -1);
- return mono_domain_get_id(domain);
-}
-
-bool GodotSharp::is_scripts_domain_loaded() {
- return GDMono::get_singleton() != nullptr &&
- GDMono::get_singleton()->is_runtime_initialized() &&
- GDMono::get_singleton()->get_scripts_domain() != nullptr;
-}
-
-bool GodotSharp::_is_domain_finalizing_for_unload(int32_t p_domain_id) {
- return is_domain_finalizing_for_unload(p_domain_id);
-}
-
-bool GodotSharp::is_domain_finalizing_for_unload(int32_t p_domain_id) {
- return is_domain_finalizing_for_unload(mono_domain_get_by_id(p_domain_id));
-}
-
-bool GodotSharp::is_domain_finalizing_for_unload(MonoDomain *p_domain) {
- GDMono *gd_mono = GDMono::get_singleton();
-
- ERR_FAIL_COND_V_MSG(!gd_mono || !gd_mono->is_runtime_initialized(),
- false, "The Mono runtime is not initialized");
-
- ERR_FAIL_NULL_V(p_domain, true);
-
- if (p_domain == gd_mono->get_scripts_domain() && gd_mono->is_finalizing_scripts_domain()) {
- return true;
- }
-
- return mono_domain_is_unloading(p_domain);
-}
-
-bool GodotSharp::is_runtime_shutting_down() {
- return mono_runtime_is_shutting_down();
-}
-
-bool GodotSharp::is_runtime_initialized() {
+bool GodotSharp::_is_runtime_initialized() {
return GDMono::get_singleton() != nullptr && GDMono::get_singleton()->is_runtime_initialized();
}
@@ -1399,16 +613,7 @@ void GodotSharp::_reload_assemblies(bool p_soft_reload) {
}
void GodotSharp::_bind_methods() {
- ClassDB::bind_method(D_METHOD("attach_thread"), &GodotSharp::attach_thread);
- ClassDB::bind_method(D_METHOD("detach_thread"), &GodotSharp::detach_thread);
-
- ClassDB::bind_method(D_METHOD("get_domain_id"), &GodotSharp::get_domain_id);
- ClassDB::bind_method(D_METHOD("get_scripts_domain_id"), &GodotSharp::get_scripts_domain_id);
- ClassDB::bind_method(D_METHOD("is_scripts_domain_loaded"), &GodotSharp::is_scripts_domain_loaded);
- ClassDB::bind_method(D_METHOD("is_domain_finalizing_for_unload", "domain_id"), &GodotSharp::_is_domain_finalizing_for_unload);
-
- ClassDB::bind_method(D_METHOD("is_runtime_shutting_down"), &GodotSharp::is_runtime_shutting_down);
- ClassDB::bind_method(D_METHOD("is_runtime_initialized"), &GodotSharp::is_runtime_initialized);
+ ClassDB::bind_method(D_METHOD("is_runtime_initialized"), &GodotSharp::_is_runtime_initialized);
ClassDB::bind_method(D_METHOD("_reload_assemblies"), &GodotSharp::_reload_assemblies);
}
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index 51fd0f8483..43811a4325 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -34,131 +34,54 @@
#include "core/io/config_file.h"
#include "../godotsharp_defs.h"
-#include "gd_mono_assembly.h"
-#include "gd_mono_log.h"
-#ifdef WINDOWS_ENABLED
-#include "../utils/mono_reg_utils.h"
+#ifdef WIN32
+#define GD_CLR_STDCALL __stdcall
+#else
+#define GD_CLR_STDCALL
#endif
-namespace ApiAssemblyInfo {
-enum Type {
- API_CORE,
- API_EDITOR
-};
-
-struct Version {
- uint64_t godot_api_hash = 0;
- uint32_t bindings_version = 0;
- uint32_t cs_glue_version = 0;
-
- bool operator==(const Version &p_other) const {
- return godot_api_hash == p_other.godot_api_hash &&
- bindings_version == p_other.bindings_version &&
- cs_glue_version == p_other.cs_glue_version;
- }
-
- Version() {}
-
- Version(uint64_t p_godot_api_hash,
- uint32_t p_bindings_version,
- uint32_t p_cs_glue_version) :
- godot_api_hash(p_godot_api_hash),
- bindings_version(p_bindings_version),
- cs_glue_version(p_cs_glue_version) {
- }
+namespace gdmono {
- static Version get_from_loaded_assembly(GDMonoAssembly *p_api_assembly, Type p_api_type);
+#ifdef TOOLS_ENABLED
+struct PluginCallbacks {
+ using FuncLoadProjectAssemblyCallback = bool(GD_CLR_STDCALL *)(const char16_t *, String *);
+ using FuncLoadToolsAssemblyCallback = Object *(GD_CLR_STDCALL *)(const char16_t *, const void **, int32_t);
+ using FuncUnloadProjectPluginCallback = bool(GD_CLR_STDCALL *)();
+ FuncLoadProjectAssemblyCallback LoadProjectAssemblyCallback = nullptr;
+ FuncLoadToolsAssemblyCallback LoadToolsAssemblyCallback = nullptr;
+ FuncUnloadProjectPluginCallback UnloadProjectPluginCallback = nullptr;
};
+#endif
-String to_string(Type p_type);
-} // namespace ApiAssemblyInfo
-
-class GDMono {
-public:
- enum UnhandledExceptionPolicy {
- POLICY_TERMINATE_APP,
- POLICY_LOG_ERROR
- };
-
- struct LoadedApiAssembly {
- GDMonoAssembly *assembly = nullptr;
- bool out_of_sync = false;
+} // namespace gdmono
- LoadedApiAssembly() {}
- };
+#undef GD_CLR_STDCALL
-private:
+class GDMono {
bool runtime_initialized;
bool finalizing_scripts_domain;
- UnhandledExceptionPolicy unhandled_exception_policy;
+ void *hostfxr_dll_handle = nullptr;
+ bool is_native_aot = false;
- MonoDomain *root_domain = nullptr;
- MonoDomain *scripts_domain = nullptr;
+ String project_assembly_path;
+ uint64_t project_assembly_modified_time = 0;
- HashMap<int32_t, HashMap<String, GDMonoAssembly *>> assemblies;
-
- GDMonoAssembly *corlib_assembly = nullptr;
- GDMonoAssembly *project_assembly = nullptr;
#ifdef TOOLS_ENABLED
- GDMonoAssembly *tools_assembly = nullptr;
- GDMonoAssembly *tools_project_editor_assembly = nullptr;
-#endif
-
- LoadedApiAssembly core_api_assembly;
- LoadedApiAssembly editor_api_assembly;
-
- typedef bool (*CoreApiAssemblyLoadedCallback)();
-
- bool _are_api_assemblies_out_of_sync();
- bool _temp_domain_load_are_assemblies_out_of_sync(const String &p_config);
-
- bool _load_core_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, const String &p_config, bool p_refonly);
-#ifdef TOOLS_ENABLED
- bool _load_editor_api_assembly(LoadedApiAssembly &r_loaded_api_assembly, const String &p_config, bool p_refonly);
-#endif
-
- static bool _on_core_api_assembly_loaded();
-
- bool _load_corlib_assembly();
-#ifdef TOOLS_ENABLED
- bool _load_tools_assemblies();
-#endif
bool _load_project_assembly();
-
- bool _try_load_api_assemblies(LoadedApiAssembly &r_core_api_assembly, LoadedApiAssembly &r_editor_api_assembly,
- const String &p_config, bool p_refonly, CoreApiAssemblyLoadedCallback p_callback);
- bool _try_load_api_assemblies_preset();
- void _load_api_assemblies();
-
- void _install_trace_listener();
-
- void _register_internal_calls();
-
-#ifndef GD_MONO_SINGLE_APPDOMAIN
- Error _load_scripts_domain();
- Error _unload_scripts_domain();
#endif
- void _domain_assemblies_cleanup(int32_t p_domain_id);
-
uint64_t api_core_hash;
#ifdef TOOLS_ENABLED
uint64_t api_editor_hash;
#endif
void _init_godot_api_hashes();
- void _init_exception_policy();
-
- GDMonoLog *gdmono_log = nullptr;
-#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED)
- MonoRegInfo mono_reg_info;
+#ifdef TOOLS_ENABLED
+ gdmono::PluginCallbacks plugin_callbacks;
#endif
- void add_mono_shared_libs_dir_to_path();
- void determine_mono_dirs(String &r_assembly_rootdir, String &r_config_dir);
-
protected:
static GDMono *singleton;
@@ -192,107 +115,43 @@ public:
#endif
}
-#ifdef TOOLS_ENABLED
- bool copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const String &p_config);
- String update_api_assemblies_from_prebuilt(const String &p_config, const bool *p_core_api_out_of_sync = nullptr, const bool *p_editor_api_out_of_sync = nullptr);
-#endif
-
- static GDMono *get_singleton() { return singleton; }
-
- [[noreturn]] static void unhandled_exception_hook(MonoObject *p_exc, void *p_user_data);
-
- UnhandledExceptionPolicy get_unhandled_exception_policy() const { return unhandled_exception_policy; }
-
- // Do not use these, unless you know what you're doing
- void add_assembly(int32_t p_domain_id, GDMonoAssembly *p_assembly);
- GDMonoAssembly *get_loaded_assembly(const String &p_name);
-
- _FORCE_INLINE_ bool is_runtime_initialized() const { return runtime_initialized && !mono_runtime_is_shutting_down() /* stays true after shutdown finished */; }
+ static GDMono *get_singleton() {
+ return singleton;
+ }
- _FORCE_INLINE_ bool is_finalizing_scripts_domain() { return finalizing_scripts_domain; }
+ _FORCE_INLINE_ bool is_runtime_initialized() const {
+ return runtime_initialized;
+ }
+ _FORCE_INLINE_ bool is_finalizing_scripts_domain() {
+ return finalizing_scripts_domain;
+ }
- _FORCE_INLINE_ MonoDomain *get_scripts_domain() { return scripts_domain; }
+ _FORCE_INLINE_ const String &get_project_assembly_path() const {
+ return project_assembly_path;
+ }
+ _FORCE_INLINE_ uint64_t get_project_assembly_modified_time() const {
+ return project_assembly_modified_time;
+ }
- _FORCE_INLINE_ GDMonoAssembly *get_corlib_assembly() const { return corlib_assembly; }
- _FORCE_INLINE_ GDMonoAssembly *get_core_api_assembly() const { return core_api_assembly.assembly; }
- _FORCE_INLINE_ GDMonoAssembly *get_project_assembly() const { return project_assembly; }
#ifdef TOOLS_ENABLED
- _FORCE_INLINE_ GDMonoAssembly *get_editor_api_assembly() const { return editor_api_assembly.assembly; }
- _FORCE_INLINE_ GDMonoAssembly *get_tools_assembly() const { return tools_assembly; }
- _FORCE_INLINE_ GDMonoAssembly *get_tools_project_editor_assembly() const { return tools_project_editor_assembly; }
-#endif
-
-#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED)
- const MonoRegInfo &get_mono_reg_info() { return mono_reg_info; }
+ const gdmono::PluginCallbacks &get_plugin_callbacks() {
+ return plugin_callbacks;
+ }
#endif
- GDMonoClass *get_class(MonoClass *p_raw_class);
- GDMonoClass *get_class(const StringName &p_namespace, const StringName &p_name);
-
#ifdef GD_MONO_HOT_RELOAD
- Error reload_scripts_domain();
+ Error reload_project_assemblies();
#endif
- bool load_assembly(const String &p_name, GDMonoAssembly **r_assembly, bool p_refonly = false);
- bool load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly = false);
- bool load_assembly(const String &p_name, MonoAssemblyName *p_aname, GDMonoAssembly **r_assembly, bool p_refonly, const Vector<String> &p_search_dirs);
- bool load_assembly_from(const String &p_name, const String &p_path, GDMonoAssembly **r_assembly, bool p_refonly = false);
-
- Error finalize_and_unload_domain(MonoDomain *p_domain);
-
void initialize();
+#ifdef TOOLS_ENABLED
void initialize_load_assemblies();
+#endif
GDMono();
~GDMono();
};
-namespace gdmono {
-
-class ScopeDomain {
- MonoDomain *prev_domain = nullptr;
-
-public:
- ScopeDomain(MonoDomain *p_domain) {
- prev_domain = mono_domain_get();
- if (prev_domain != p_domain) {
- mono_domain_set(p_domain, false);
- } else {
- prev_domain = nullptr;
- }
- }
-
- ~ScopeDomain() {
- if (prev_domain) {
- mono_domain_set(prev_domain, false);
- }
- }
-};
-
-class ScopeExitDomainUnload {
- MonoDomain *domain = nullptr;
-
-public:
- ScopeExitDomainUnload(MonoDomain *p_domain) :
- domain(p_domain) {
- }
-
- ~ScopeExitDomainUnload() {
- if (domain) {
- GDMono::get_singleton()->finalize_and_unload_domain(domain);
- }
- }
-};
-} // namespace gdmono
-
-#define _GDMONO_SCOPE_DOMAIN_(m_mono_domain) \
- gdmono::ScopeDomain __gdmono__scope__domain__(m_mono_domain); \
- (void)__gdmono__scope__domain__;
-
-#define _GDMONO_SCOPE_EXIT_DOMAIN_UNLOAD_(m_mono_domain) \
- gdmono::ScopeExitDomainUnload __gdmono__scope__exit__domain__unload__(m_mono_domain); \
- (void)__gdmono__scope__exit__domain__unload__;
-
namespace mono_bind {
class GodotSharp : public Object {
@@ -300,9 +159,8 @@ class GodotSharp : public Object {
friend class GDMono;
- bool _is_domain_finalizing_for_unload(int32_t p_domain_id);
-
void _reload_assemblies(bool p_soft_reload);
+ bool _is_runtime_initialized();
protected:
static GodotSharp *singleton;
@@ -311,20 +169,6 @@ protected:
public:
static GodotSharp *get_singleton() { return singleton; }
- void attach_thread();
- void detach_thread();
-
- int32_t get_domain_id();
- int32_t get_scripts_domain_id();
-
- bool is_scripts_domain_loaded();
-
- bool is_domain_finalizing_for_unload(int32_t p_domain_id);
- bool is_domain_finalizing_for_unload(MonoDomain *p_domain);
-
- bool is_runtime_shutting_down();
- bool is_runtime_initialized();
-
GodotSharp();
~GodotSharp();
};
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
deleted file mode 100644
index 42c6b6305f..0000000000
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ /dev/null
@@ -1,482 +0,0 @@
-/*************************************************************************/
-/* gd_mono_assembly.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "gd_mono_assembly.h"
-
-#include <mono/metadata/mono-debug.h>
-#include <mono/metadata/tokentype.h>
-
-#include "core/config/project_settings.h"
-#include "core/io/file_access.h"
-#include "core/io/file_access_pack.h"
-#include "core/os/os.h"
-#include "core/templates/list.h"
-
-#include "../godotsharp_dirs.h"
-#include "gd_mono_cache.h"
-#include "gd_mono_class.h"
-
-Vector<String> GDMonoAssembly::search_dirs;
-
-void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config, const String &p_custom_bcl_dir) {
- String framework_dir;
-
- if (!p_custom_bcl_dir.is_empty()) {
- framework_dir = p_custom_bcl_dir;
- } else if (mono_assembly_getrootdir()) {
- framework_dir = String::utf8(mono_assembly_getrootdir()).plus_file("mono").plus_file("4.5");
- }
-
- if (!framework_dir.is_empty()) {
- r_search_dirs.push_back(framework_dir);
- r_search_dirs.push_back(framework_dir.plus_file("Facades"));
- }
-
-#if !defined(TOOLS_ENABLED)
- String data_game_assemblies_dir = GodotSharpDirs::get_data_game_assemblies_dir();
- if (!data_game_assemblies_dir.is_empty()) {
- r_search_dirs.push_back(data_game_assemblies_dir);
- }
-#endif
-
- if (p_custom_config.length()) {
- r_search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_base_dir().plus_file(p_custom_config));
- } else {
- r_search_dirs.push_back(GodotSharpDirs::get_res_temp_assemblies_dir());
- }
-
- if (p_custom_config.is_empty()) {
- r_search_dirs.push_back(GodotSharpDirs::get_res_assemblies_dir());
- } else {
- String api_config = p_custom_config == "ExportRelease" ? "Release" : "Debug";
- r_search_dirs.push_back(GodotSharpDirs::get_res_assemblies_base_dir().plus_file(api_config));
- }
-
- r_search_dirs.push_back(GodotSharpDirs::get_res_assemblies_base_dir());
- r_search_dirs.push_back(OS::get_singleton()->get_resource_dir());
- r_search_dirs.push_back(OS::get_singleton()->get_executable_path().get_base_dir());
-
-#ifdef TOOLS_ENABLED
- r_search_dirs.push_back(GodotSharpDirs::get_data_editor_tools_dir());
-
- // For GodotTools to find the api assemblies
- r_search_dirs.push_back(GodotSharpDirs::get_data_editor_prebuilt_api_dir().plus_file("Debug"));
-#endif
-}
-
-// This is how these assembly loading hooks work:
-//
-// - The 'search' hook checks if the assembly has already been loaded, to avoid loading again.
-// - The 'preload' hook does the actual loading and is only called if the
-// 'search' hook didn't find the assembly in the list of loaded assemblies.
-// - The 'load' hook is called after the assembly has been loaded. Its job is to add the
-// assembly to the list of loaded assemblies so that the 'search' hook can look it up.
-
-void GDMonoAssembly::assembly_load_hook(MonoAssembly *assembly, [[maybe_unused]] void *user_data) {
- String name = String::utf8(mono_assembly_name_get_name(mono_assembly_get_name(assembly)));
-
- MonoImage *image = mono_assembly_get_image(assembly);
-
- GDMonoAssembly *gdassembly = memnew(GDMonoAssembly(name, image, assembly));
-
-#ifdef GD_MONO_HOT_RELOAD
- String path = String::utf8(mono_image_get_filename(image));
- if (FileAccess::exists(path)) {
- gdassembly->modified_time = FileAccess::get_modified_time(path);
- }
-#endif
-
- MonoDomain *domain = mono_domain_get();
- GDMono::get_singleton()->add_assembly(domain ? mono_domain_get_id(domain) : 0, gdassembly);
-}
-
-MonoAssembly *GDMonoAssembly::assembly_search_hook(MonoAssemblyName *aname, void *user_data) {
- return GDMonoAssembly::_search_hook(aname, user_data, false);
-}
-
-MonoAssembly *GDMonoAssembly::assembly_refonly_search_hook(MonoAssemblyName *aname, void *user_data) {
- return GDMonoAssembly::_search_hook(aname, user_data, true);
-}
-
-MonoAssembly *GDMonoAssembly::assembly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data) {
- return GDMonoAssembly::_preload_hook(aname, assemblies_path, user_data, false);
-}
-
-MonoAssembly *GDMonoAssembly::assembly_refonly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data) {
- return GDMonoAssembly::_preload_hook(aname, assemblies_path, user_data, true);
-}
-
-MonoAssembly *GDMonoAssembly::_search_hook(MonoAssemblyName *aname, [[maybe_unused]] void *user_data, bool refonly) {
- String name = String::utf8(mono_assembly_name_get_name(aname));
- bool has_extension = name.ends_with(".dll") || name.ends_with(".exe");
-
- GDMonoAssembly *loaded_asm = GDMono::get_singleton()->get_loaded_assembly(has_extension ? name.get_basename() : name);
- if (loaded_asm) {
- return loaded_asm->get_assembly();
- }
-
- return nullptr;
-}
-
-MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **, [[maybe_unused]] void *user_data, bool refonly) {
- String name = String::utf8(mono_assembly_name_get_name(aname));
- return _load_assembly_search(name, aname, refonly, search_dirs);
-}
-
-MonoAssembly *GDMonoAssembly::_load_assembly_search(const String &p_name, MonoAssemblyName *p_aname, bool p_refonly, const Vector<String> &p_search_dirs) {
- MonoAssembly *res = nullptr;
- String path;
-
- bool has_extension = p_name.ends_with(".dll") || p_name.ends_with(".exe");
-
- for (int i = 0; i < p_search_dirs.size(); i++) {
- const String &search_dir = p_search_dirs[i];
-
- if (has_extension) {
- path = search_dir.plus_file(p_name);
- if (FileAccess::exists(path)) {
- res = _real_load_assembly_from(path, p_refonly, p_aname);
- if (res != nullptr) {
- return res;
- }
- }
- } else {
- path = search_dir.plus_file(p_name + ".dll");
- if (FileAccess::exists(path)) {
- res = _real_load_assembly_from(path, p_refonly, p_aname);
- if (res != nullptr) {
- return res;
- }
- }
-
- path = search_dir.plus_file(p_name + ".exe");
- if (FileAccess::exists(path)) {
- res = _real_load_assembly_from(path, p_refonly, p_aname);
- if (res != nullptr) {
- return res;
- }
- }
- }
- }
-
- return nullptr;
-}
-
-String GDMonoAssembly::find_assembly(const String &p_name) {
- String path;
-
- bool has_extension = p_name.ends_with(".dll") || p_name.ends_with(".exe");
-
- for (int i = 0; i < search_dirs.size(); i++) {
- const String &search_dir = search_dirs[i];
-
- if (has_extension) {
- path = search_dir.plus_file(p_name);
- if (FileAccess::exists(path)) {
- return path;
- }
- } else {
- path = search_dir.plus_file(p_name + ".dll");
- if (FileAccess::exists(path)) {
- return path;
- }
-
- path = search_dir.plus_file(p_name + ".exe");
- if (FileAccess::exists(path)) {
- return path;
- }
- }
- }
-
- return String();
-}
-
-void GDMonoAssembly::initialize() {
- fill_search_dirs(search_dirs);
-
- mono_install_assembly_search_hook(&assembly_search_hook, nullptr);
- mono_install_assembly_refonly_search_hook(&assembly_refonly_search_hook, nullptr);
- mono_install_assembly_preload_hook(&assembly_preload_hook, nullptr);
- mono_install_assembly_refonly_preload_hook(&assembly_refonly_preload_hook, nullptr);
- mono_install_assembly_load_hook(&assembly_load_hook, nullptr);
-}
-
-MonoAssembly *GDMonoAssembly::_real_load_assembly_from(const String &p_path, bool p_refonly, MonoAssemblyName *p_aname) {
- Vector<uint8_t> data = FileAccess::get_file_as_array(p_path);
- ERR_FAIL_COND_V_MSG(data.is_empty(), nullptr, "Could read the assembly in the specified location");
-
- String image_filename;
-
-#ifdef ANDROID_ENABLED
- if (p_path.begins_with("res://")) {
- image_filename = p_path.substr(6, p_path.length());
- } else {
- image_filename = ProjectSettings::get_singleton()->globalize_path(p_path);
- }
-#else
- // FIXME: globalize_path does not work on exported games
- image_filename = ProjectSettings::get_singleton()->globalize_path(p_path);
-#endif
-
- MonoImageOpenStatus status = MONO_IMAGE_OK;
-
- MonoImage *image = mono_image_open_from_data_with_name(
- (char *)&data[0], data.size(),
- true, &status, p_refonly,
- image_filename.utf8());
-
- ERR_FAIL_COND_V_MSG(status != MONO_IMAGE_OK || !image, nullptr, "Failed to open assembly image from memory: '" + p_path + "'.");
-
- if (p_aname != nullptr) {
- // Check assembly version
- const MonoTableInfo *table = mono_image_get_table_info(image, MONO_TABLE_ASSEMBLY);
-
- ERR_FAIL_NULL_V(table, nullptr);
-
- if (mono_table_info_get_rows(table)) {
- uint32_t cols[MONO_ASSEMBLY_SIZE];
- mono_metadata_decode_row(table, 0, cols, MONO_ASSEMBLY_SIZE);
-
- // Not sure about .NET's policy. We will only ensure major and minor are equal, and ignore build and revision.
- uint16_t major = cols[MONO_ASSEMBLY_MAJOR_VERSION];
- uint16_t minor = cols[MONO_ASSEMBLY_MINOR_VERSION];
-
- uint16_t required_minor;
- uint16_t required_major = mono_assembly_name_get_version(p_aname, &required_minor, nullptr, nullptr);
-
- if (required_major != 0) {
- if (major != required_major && minor != required_minor) {
- mono_image_close(image);
- return nullptr;
- }
- }
- }
- }
-
-#ifdef DEBUG_ENABLED
- Vector<uint8_t> pdb_data;
- String pdb_path(p_path + ".pdb");
-
- if (!FileAccess::exists(pdb_path)) {
- pdb_path = p_path.get_basename() + ".pdb"; // without .dll
-
- if (!FileAccess::exists(pdb_path)) {
- goto no_pdb;
- }
- }
-
- pdb_data = FileAccess::get_file_as_array(pdb_path);
-
- // mono_debug_close_image doesn't seem to be needed
- mono_debug_open_image_from_memory(image, &pdb_data[0], pdb_data.size());
-
-no_pdb:
-
-#endif
-
- bool need_manual_load_hook = mono_image_get_assembly(image) != nullptr; // Re-using an existing image with an assembly loaded
-
- status = MONO_IMAGE_OK;
-
- MonoAssembly *assembly = mono_assembly_load_from_full(image, image_filename.utf8().get_data(), &status, p_refonly);
-
- ERR_FAIL_COND_V_MSG(status != MONO_IMAGE_OK || !assembly, nullptr, "Failed to load assembly for image");
-
- if (need_manual_load_hook) {
- // For some reason if an assembly survived domain reloading (maybe because it's referenced somewhere else),
- // the mono internal search hook don't detect it, yet mono_image_open_from_data_with_name re-uses the image
- // and assembly, and mono_assembly_load_from_full doesn't call the load hook. We need to call it manually.
- String name = String::utf8(mono_assembly_name_get_name(mono_assembly_get_name(assembly)));
- bool has_extension = name.ends_with(".dll") || name.ends_with(".exe");
- GDMonoAssembly *loaded_asm = GDMono::get_singleton()->get_loaded_assembly(has_extension ? name.get_basename() : name);
- if (!loaded_asm) {
- assembly_load_hook(assembly, nullptr);
- }
- }
-
- // Decrement refcount which was previously incremented by mono_image_open_from_data_with_name
- mono_image_close(image);
-
- return assembly;
-}
-
-void GDMonoAssembly::unload() {
- ERR_FAIL_NULL(image); // Should not be called if already unloaded
-
- for (const KeyValue<MonoClass *, GDMonoClass *> &E : cached_raw) {
- memdelete(E.value);
- }
-
- cached_classes.clear();
- cached_raw.clear();
-
- assembly = nullptr;
- image = nullptr;
-}
-
-String GDMonoAssembly::get_path() const {
- return String::utf8(mono_image_get_filename(image));
-}
-
-bool GDMonoAssembly::has_attribute(GDMonoClass *p_attr_class) {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_NULL_V(p_attr_class, false);
-#endif
-
- if (!attrs_fetched) {
- fetch_attributes();
- }
-
- if (!attributes) {
- return false;
- }
-
- return mono_custom_attrs_has_attr(attributes, p_attr_class->get_mono_ptr());
-}
-
-MonoObject *GDMonoAssembly::get_attribute(GDMonoClass *p_attr_class) {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_NULL_V(p_attr_class, nullptr);
-#endif
-
- if (!attrs_fetched) {
- fetch_attributes();
- }
-
- if (!attributes) {
- return nullptr;
- }
-
- return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr());
-}
-
-void GDMonoAssembly::fetch_attributes() {
- ERR_FAIL_COND(attributes != nullptr);
-
- attributes = mono_custom_attrs_from_assembly(assembly);
- attrs_fetched = true;
-}
-
-GDMonoClass *GDMonoAssembly::get_class(const StringName &p_namespace, const StringName &p_name) {
- ERR_FAIL_NULL_V(image, nullptr);
-
- ClassKey key(p_namespace, p_name);
-
- GDMonoClass **match = cached_classes.getptr(key);
-
- if (match) {
- return *match;
- }
-
- MonoClass *mono_class = mono_class_from_name(image, String(p_namespace).utf8(), String(p_name).utf8());
-
- if (!mono_class) {
- return nullptr;
- }
-
- GDMonoClass *wrapped_class = memnew(GDMonoClass(p_namespace, p_name, mono_class, this));
-
- cached_classes[key] = wrapped_class;
- cached_raw[mono_class] = wrapped_class;
-
- return wrapped_class;
-}
-
-GDMonoClass *GDMonoAssembly::get_class(MonoClass *p_mono_class) {
- ERR_FAIL_NULL_V(image, nullptr);
-
- HashMap<MonoClass *, GDMonoClass *>::Iterator match = cached_raw.find(p_mono_class);
-
- if (match) {
- return match->value;
- }
-
- StringName namespace_name = String::utf8(mono_class_get_namespace(p_mono_class));
- StringName class_name = String::utf8(mono_class_get_name(p_mono_class));
-
- GDMonoClass *wrapped_class = memnew(GDMonoClass(namespace_name, class_name, p_mono_class, this));
-
- cached_classes[ClassKey(namespace_name, class_name)] = wrapped_class;
- cached_raw[p_mono_class] = wrapped_class;
-
- return wrapped_class;
-}
-
-GDMonoAssembly *GDMonoAssembly::load(const String &p_name, MonoAssemblyName *p_aname, bool p_refonly, const Vector<String> &p_search_dirs) {
- if (GDMono::get_singleton()->get_corlib_assembly() && (p_name == "mscorlib" || p_name == "mscorlib.dll")) {
- return GDMono::get_singleton()->get_corlib_assembly();
- }
-
- // We need to manually call the search hook in this case, as it won't be called in the next step
- MonoAssembly *assembly = mono_assembly_invoke_search_hook(p_aname);
-
- if (!assembly) {
- assembly = _load_assembly_search(p_name, p_aname, p_refonly, p_search_dirs);
- if (!assembly) {
- return nullptr;
- }
- }
-
- GDMonoAssembly *loaded_asm = GDMono::get_singleton()->get_loaded_assembly(p_name);
- ERR_FAIL_NULL_V_MSG(loaded_asm, nullptr, "Loaded assembly missing from table. Did we not receive the load hook?");
- ERR_FAIL_COND_V(loaded_asm->get_assembly() != assembly, nullptr);
-
- return loaded_asm;
-}
-
-GDMonoAssembly *GDMonoAssembly::load_from(const String &p_name, const String &p_path, bool p_refonly) {
- if (p_name == "mscorlib" || p_name == "mscorlib.dll") {
- return GDMono::get_singleton()->get_corlib_assembly();
- }
-
- // We need to manually call the search hook in this case, as it won't be called in the next step
- MonoAssemblyName *aname = mono_assembly_name_new(p_name.utf8());
- MonoAssembly *assembly = mono_assembly_invoke_search_hook(aname);
- mono_assembly_name_free(aname);
- mono_free(aname);
-
- if (!assembly) {
- assembly = _real_load_assembly_from(p_path, p_refonly);
- if (!assembly) {
- return nullptr;
- }
- }
-
- GDMonoAssembly *loaded_asm = GDMono::get_singleton()->get_loaded_assembly(p_name);
- ERR_FAIL_NULL_V_MSG(loaded_asm, nullptr, "Loaded assembly missing from table. Did we not receive the load hook?");
-
- return loaded_asm;
-}
-
-GDMonoAssembly::~GDMonoAssembly() {
- if (image) {
- unload();
- }
-}
diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h
deleted file mode 100644
index 0a3ae6c4fe..0000000000
--- a/modules/mono/mono_gd/gd_mono_assembly.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*************************************************************************/
-/* gd_mono_assembly.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GD_MONO_ASSEMBLY_H
-#define GD_MONO_ASSEMBLY_H
-
-#include <mono/jit/jit.h>
-#include <mono/metadata/assembly.h>
-
-#include "core/string/ustring.h"
-#include "core/templates/hash_map.h"
-#include "core/templates/rb_map.h"
-#include "gd_mono_utils.h"
-
-class GDMonoAssembly {
- struct ClassKey {
- struct Hasher {
- static _FORCE_INLINE_ uint32_t hash(const ClassKey &p_key) {
- uint32_t hash = 0;
-
- GDMonoUtils::hash_combine(hash, p_key.namespace_name.hash());
- GDMonoUtils::hash_combine(hash, p_key.class_name.hash());
-
- return hash;
- }
- };
-
- _FORCE_INLINE_ bool operator==(const ClassKey &p_a) const {
- return p_a.class_name == class_name && p_a.namespace_name == namespace_name;
- }
-
- ClassKey() {}
-
- ClassKey(const StringName &p_namespace_name, const StringName &p_class_name) {
- namespace_name = p_namespace_name;
- class_name = p_class_name;
- }
-
- StringName namespace_name;
- StringName class_name;
- };
-
- String name;
- MonoImage *image = nullptr;
- MonoAssembly *assembly = nullptr;
-
- bool attrs_fetched = false;
- MonoCustomAttrInfo *attributes = nullptr;
-
-#ifdef GD_MONO_HOT_RELOAD
- uint64_t modified_time = 0;
-#endif
-
- HashMap<ClassKey, GDMonoClass *, ClassKey::Hasher> cached_classes;
- HashMap<MonoClass *, GDMonoClass *> cached_raw;
-
- static Vector<String> search_dirs;
-
- static void assembly_load_hook(MonoAssembly *assembly, void *user_data);
- static MonoAssembly *assembly_search_hook(MonoAssemblyName *aname, void *user_data);
- static MonoAssembly *assembly_refonly_search_hook(MonoAssemblyName *aname, void *user_data);
- static MonoAssembly *assembly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data);
- static MonoAssembly *assembly_refonly_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data);
-
- static MonoAssembly *_search_hook(MonoAssemblyName *aname, void *user_data, bool refonly);
- static MonoAssembly *_preload_hook(MonoAssemblyName *aname, char **assemblies_path, void *user_data, bool refonly);
-
- static MonoAssembly *_real_load_assembly_from(const String &p_path, bool p_refonly, MonoAssemblyName *p_aname = nullptr);
- static MonoAssembly *_load_assembly_search(const String &p_name, MonoAssemblyName *p_aname, bool p_refonly, const Vector<String> &p_search_dirs);
-
- friend class GDMono;
- static void initialize();
-
-public:
- void unload();
-
- _FORCE_INLINE_ MonoImage *get_image() const { return image; }
- _FORCE_INLINE_ MonoAssembly *get_assembly() const { return assembly; }
- _FORCE_INLINE_ String get_name() const { return name; }
-
-#ifdef GD_MONO_HOT_RELOAD
- _FORCE_INLINE_ uint64_t get_modified_time() const { return modified_time; }
-#endif
-
- String get_path() const;
-
- bool has_attribute(GDMonoClass *p_attr_class);
- MonoObject *get_attribute(GDMonoClass *p_attr_class);
-
- void fetch_attributes();
-
- GDMonoClass *get_class(const StringName &p_namespace, const StringName &p_name);
- GDMonoClass *get_class(MonoClass *p_mono_class);
-
- static String find_assembly(const String &p_name);
-
- static void fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config = String(), const String &p_custom_bcl_dir = String());
- static const Vector<String> &get_default_search_dirs() { return search_dirs; }
-
- static GDMonoAssembly *load(const String &p_name, MonoAssemblyName *p_aname, bool p_refonly, const Vector<String> &p_search_dirs);
- static GDMonoAssembly *load_from(const String &p_name, const String &p_path, bool p_refonly);
-
- GDMonoAssembly(const String &p_name, MonoImage *p_image, MonoAssembly *p_assembly) :
- name(p_name),
- image(p_image),
- assembly(p_assembly) {
- }
- ~GDMonoAssembly();
-};
-
-#endif // GD_MONO_ASSEMBLY_H
diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp
index 69d8c7edc9..bfd803f326 100644
--- a/modules/mono/mono_gd/gd_mono_cache.cpp
+++ b/modules/mono/mono_gd/gd_mono_cache.cpp
@@ -30,310 +30,66 @@
#include "gd_mono_cache.h"
-#include "gd_mono.h"
-#include "gd_mono_class.h"
-#include "gd_mono_marshal.h"
-#include "gd_mono_method.h"
-#include "gd_mono_utils.h"
+#include "core/error/error_macros.h"
namespace GDMonoCache {
-CachedData cached_data;
+ManagedCallbacks managed_callbacks;
+bool godot_api_cache_updated = false;
-#define CACHE_AND_CHECK(m_var, m_val) \
- { \
- CRASH_COND(m_var != nullptr); \
- m_var = m_val; \
- ERR_FAIL_COND_MSG(m_var == nullptr, "Mono Cache: Member " #m_var " is null."); \
- }
-
-#define CACHE_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(cached_data.class_##m_class, m_val)
-#define CACHE_NS_CLASS_AND_CHECK(m_ns, m_class, m_val) CACHE_AND_CHECK(cached_data.class_##m_ns##_##m_class, m_val)
-#define CACHE_RAW_MONO_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(cached_data.rawclass_##m_class, m_val)
-#define CACHE_FIELD_AND_CHECK(m_class, m_field, m_val) CACHE_AND_CHECK(cached_data.field_##m_class##_##m_field, m_val)
-#define CACHE_METHOD_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(cached_data.method_##m_class##_##m_method, m_val)
-#define CACHE_PROPERTY_AND_CHECK(m_class, m_property, m_val) CACHE_AND_CHECK(cached_data.property_##m_class##_##m_property, m_val)
+void update_godot_api_cache(const ManagedCallbacks &p_managed_callbacks) {
+ int checked_count = 0;
-#define CACHE_METHOD_THUNK_AND_CHECK_IMPL(m_var, m_val) \
- { \
- CRASH_COND(!m_var.is_null()); \
- ERR_FAIL_COND_MSG(m_val == nullptr, "Mono Cache: Method for member " #m_var " is null."); \
- m_var.set_from_method(m_val); \
- ERR_FAIL_COND_MSG(m_var.is_null(), "Mono Cache: Member " #m_var " is null."); \
+#define CHECK_CALLBACK_NOT_NULL_IMPL(m_var, m_class, m_method) \
+ { \
+ ERR_FAIL_COND_MSG(m_var == nullptr, \
+ "Mono Cache: Managed callback for '" #m_class "_" #m_method "' is null."); \
+ checked_count += 1; \
}
-#define CACHE_METHOD_THUNK_AND_CHECK(m_class, m_method, m_val) CACHE_METHOD_THUNK_AND_CHECK_IMPL(cached_data.methodthunk_##m_class##_##m_method, m_val)
-
-void CachedData::clear_corlib_cache() {
- corlib_cache_updated = false;
-
- class_MonoObject = nullptr;
- class_bool = nullptr;
- class_int8_t = nullptr;
- class_int16_t = nullptr;
- class_int32_t = nullptr;
- class_int64_t = nullptr;
- class_uint8_t = nullptr;
- class_uint16_t = nullptr;
- class_uint32_t = nullptr;
- class_uint64_t = nullptr;
- class_float = nullptr;
- class_double = nullptr;
- class_String = nullptr;
- class_IntPtr = nullptr;
-
- class_System_Collections_IEnumerable = nullptr;
- class_System_Collections_ICollection = nullptr;
- class_System_Collections_IDictionary = nullptr;
-
-#ifdef DEBUG_ENABLED
- class_System_Diagnostics_StackTrace = nullptr;
- methodthunk_System_Diagnostics_StackTrace_GetFrames.nullify();
- method_System_Diagnostics_StackTrace_ctor_bool = nullptr;
- method_System_Diagnostics_StackTrace_ctor_Exception_bool = nullptr;
-#endif
-
- class_KeyNotFoundException = nullptr;
-}
-
-void CachedData::clear_godot_api_cache() {
- godot_api_cache_updated = false;
-
- rawclass_Dictionary = nullptr;
-
- class_Vector2 = nullptr;
- class_Vector2i = nullptr;
- class_Rect2 = nullptr;
- class_Rect2i = nullptr;
- class_Transform2D = nullptr;
- class_Vector3 = nullptr;
- class_Vector3i = nullptr;
- class_Vector4 = nullptr;
- class_Vector4i = nullptr;
- class_Basis = nullptr;
- class_Quaternion = nullptr;
- class_Transform3D = nullptr;
- class_Projection = nullptr;
- class_AABB = nullptr;
- class_Color = nullptr;
- class_Plane = nullptr;
- class_StringName = nullptr;
- class_NodePath = nullptr;
- class_RID = nullptr;
- class_GodotObject = nullptr;
- class_GodotResource = nullptr;
- class_Node = nullptr;
- class_Control = nullptr;
- class_Node3D = nullptr;
- class_WeakRef = nullptr;
- class_Callable = nullptr;
- class_SignalInfo = nullptr;
- class_Array = nullptr;
- class_Dictionary = nullptr;
- class_MarshalUtils = nullptr;
- class_ISerializationListener = nullptr;
-
-#ifdef DEBUG_ENABLED
- class_DebuggingUtils = nullptr;
- methodthunk_DebuggingUtils_GetStackFrameInfo.nullify();
-#endif
-
- class_ExportAttribute = nullptr;
- field_ExportAttribute_hint = nullptr;
- field_ExportAttribute_hintString = nullptr;
- class_SignalAttribute = nullptr;
- class_ToolAttribute = nullptr;
- class_RPCAttribute = nullptr;
- property_RPCAttribute_Mode = nullptr;
- property_RPCAttribute_CallLocal = nullptr;
- property_RPCAttribute_TransferMode = nullptr;
- property_RPCAttribute_TransferChannel = nullptr;
- class_GodotMethodAttribute = nullptr;
- field_GodotMethodAttribute_methodName = nullptr;
- class_ScriptPathAttribute = nullptr;
- field_ScriptPathAttribute_path = nullptr;
- class_AssemblyHasScriptsAttribute = nullptr;
- field_AssemblyHasScriptsAttribute_requiresLookup = nullptr;
- field_AssemblyHasScriptsAttribute_scriptTypes = nullptr;
-
- field_GodotObject_ptr = nullptr;
- field_StringName_ptr = nullptr;
- field_NodePath_ptr = nullptr;
- field_Image_ptr = nullptr;
- field_RID_ptr = nullptr;
-
- methodthunk_GodotObject_Dispose.nullify();
- methodthunk_Array_GetPtr.nullify();
- methodthunk_Dictionary_GetPtr.nullify();
- methodthunk_SignalAwaiter_SignalCallback.nullify();
- methodthunk_GodotTaskScheduler_Activate.nullify();
-
- methodthunk_Delegate_Equals.nullify();
-
- methodthunk_DelegateUtils_TrySerializeDelegate.nullify();
- methodthunk_DelegateUtils_TryDeserializeDelegate.nullify();
-
- // Start of MarshalUtils methods
-
- methodthunk_MarshalUtils_TypeIsGenericArray.nullify();
- methodthunk_MarshalUtils_TypeIsGenericDictionary.nullify();
- methodthunk_MarshalUtils_TypeIsSystemGenericList.nullify();
- methodthunk_MarshalUtils_TypeIsSystemGenericDictionary.nullify();
- methodthunk_MarshalUtils_TypeIsGenericIEnumerable.nullify();
- methodthunk_MarshalUtils_TypeIsGenericICollection.nullify();
- methodthunk_MarshalUtils_TypeIsGenericIDictionary.nullify();
- methodthunk_MarshalUtils_TypeHasFlagsAttribute.nullify();
-
- methodthunk_MarshalUtils_GetGenericTypeDefinition.nullify();
-
- methodthunk_MarshalUtils_ArrayGetElementType.nullify();
- methodthunk_MarshalUtils_DictionaryGetKeyValueTypes.nullify();
-
- methodthunk_MarshalUtils_MakeGenericArrayType.nullify();
- methodthunk_MarshalUtils_MakeGenericDictionaryType.nullify();
-
- // End of MarshalUtils methods
-
- task_scheduler_handle = Ref<MonoGCHandleRef>();
-}
-
-#define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, #m_class))
-#define GODOT_API_NS_CLASS(m_ns, m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(m_ns, #m_class))
-
-void update_corlib_cache() {
- CACHE_CLASS_AND_CHECK(MonoObject, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_object_class()));
- CACHE_CLASS_AND_CHECK(bool, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_boolean_class()));
- CACHE_CLASS_AND_CHECK(int8_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_sbyte_class()));
- CACHE_CLASS_AND_CHECK(int16_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int16_class()));
- CACHE_CLASS_AND_CHECK(int32_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int32_class()));
- CACHE_CLASS_AND_CHECK(int64_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_int64_class()));
- CACHE_CLASS_AND_CHECK(uint8_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_byte_class()));
- CACHE_CLASS_AND_CHECK(uint16_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint16_class()));
- CACHE_CLASS_AND_CHECK(uint32_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint32_class()));
- CACHE_CLASS_AND_CHECK(uint64_t, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_uint64_class()));
- CACHE_CLASS_AND_CHECK(float, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_single_class()));
- CACHE_CLASS_AND_CHECK(double, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_double_class()));
- CACHE_CLASS_AND_CHECK(String, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_string_class()));
- CACHE_CLASS_AND_CHECK(IntPtr, GDMono::get_singleton()->get_corlib_assembly()->get_class(mono_get_intptr_class()));
-
- CACHE_CLASS_AND_CHECK(System_Collections_IEnumerable, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IEnumerable"));
- CACHE_CLASS_AND_CHECK(System_Collections_ICollection, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "ICollection"));
- CACHE_CLASS_AND_CHECK(System_Collections_IDictionary, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections", "IDictionary"));
-
-#ifdef DEBUG_ENABLED
- CACHE_CLASS_AND_CHECK(System_Diagnostics_StackTrace, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Diagnostics", "StackTrace"));
- CACHE_METHOD_THUNK_AND_CHECK(System_Diagnostics_StackTrace, GetFrames, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method("GetFrames"));
- CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(bool)", true));
- CACHE_METHOD_AND_CHECK(System_Diagnostics_StackTrace, ctor_Exception_bool, CACHED_CLASS(System_Diagnostics_StackTrace)->get_method_with_desc("System.Diagnostics.StackTrace:.ctor(System.Exception,bool)", true));
-#endif
-
- CACHE_METHOD_THUNK_AND_CHECK(Delegate, Equals, GDMono::get_singleton()->get_corlib_assembly()->get_class("System", "Delegate")->get_method_with_desc("System.Delegate:Equals(object)", true));
-
- CACHE_CLASS_AND_CHECK(KeyNotFoundException, GDMono::get_singleton()->get_corlib_assembly()->get_class("System.Collections.Generic", "KeyNotFoundException"));
-
- cached_data.corlib_cache_updated = true;
-}
-
-void update_godot_api_cache() {
- CACHE_CLASS_AND_CHECK(Vector2, GODOT_API_CLASS(Vector2));
- CACHE_CLASS_AND_CHECK(Vector2i, GODOT_API_CLASS(Vector2i));
- CACHE_CLASS_AND_CHECK(Rect2, GODOT_API_CLASS(Rect2));
- CACHE_CLASS_AND_CHECK(Rect2i, GODOT_API_CLASS(Rect2i));
- CACHE_CLASS_AND_CHECK(Transform2D, GODOT_API_CLASS(Transform2D));
- CACHE_CLASS_AND_CHECK(Vector3, GODOT_API_CLASS(Vector3));
- CACHE_CLASS_AND_CHECK(Vector3i, GODOT_API_CLASS(Vector3i));
- CACHE_CLASS_AND_CHECK(Vector4, GODOT_API_CLASS(Vector4));
- CACHE_CLASS_AND_CHECK(Vector4i, GODOT_API_CLASS(Vector4i));
- CACHE_CLASS_AND_CHECK(Basis, GODOT_API_CLASS(Basis));
- CACHE_CLASS_AND_CHECK(Quaternion, GODOT_API_CLASS(Quaternion));
- CACHE_CLASS_AND_CHECK(Transform3D, GODOT_API_CLASS(Transform3D));
- CACHE_CLASS_AND_CHECK(Projection, GODOT_API_CLASS(Projection));
- CACHE_CLASS_AND_CHECK(AABB, GODOT_API_CLASS(AABB));
- CACHE_CLASS_AND_CHECK(Color, GODOT_API_CLASS(Color));
- CACHE_CLASS_AND_CHECK(Plane, GODOT_API_CLASS(Plane));
- CACHE_CLASS_AND_CHECK(StringName, GODOT_API_CLASS(StringName));
- CACHE_CLASS_AND_CHECK(NodePath, GODOT_API_CLASS(NodePath));
- CACHE_CLASS_AND_CHECK(RID, GODOT_API_CLASS(RID));
- CACHE_CLASS_AND_CHECK(GodotObject, GODOT_API_CLASS(Object));
- CACHE_CLASS_AND_CHECK(GodotResource, GODOT_API_CLASS(Resource));
- CACHE_CLASS_AND_CHECK(Node, GODOT_API_CLASS(Node));
- CACHE_CLASS_AND_CHECK(Control, GODOT_API_CLASS(Control));
- CACHE_CLASS_AND_CHECK(Node3D, GODOT_API_CLASS(Node3D));
- CACHE_CLASS_AND_CHECK(WeakRef, GODOT_API_CLASS(WeakRef));
- CACHE_CLASS_AND_CHECK(Callable, GODOT_API_CLASS(Callable));
- CACHE_CLASS_AND_CHECK(SignalInfo, GODOT_API_CLASS(SignalInfo));
- CACHE_CLASS_AND_CHECK(Array, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Array));
- CACHE_CLASS_AND_CHECK(Dictionary, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary));
- CACHE_CLASS_AND_CHECK(MarshalUtils, GODOT_API_CLASS(MarshalUtils));
- CACHE_CLASS_AND_CHECK(ISerializationListener, GODOT_API_CLASS(ISerializationListener));
-
-#ifdef DEBUG_ENABLED
- CACHE_CLASS_AND_CHECK(DebuggingUtils, GODOT_API_CLASS(DebuggingUtils));
-#endif
-
- // Attributes
- CACHE_CLASS_AND_CHECK(ExportAttribute, GODOT_API_CLASS(ExportAttribute));
- CACHE_FIELD_AND_CHECK(ExportAttribute, hint, CACHED_CLASS(ExportAttribute)->get_field("hint"));
- CACHE_FIELD_AND_CHECK(ExportAttribute, hintString, CACHED_CLASS(ExportAttribute)->get_field("hintString"));
- CACHE_CLASS_AND_CHECK(SignalAttribute, GODOT_API_CLASS(SignalAttribute));
- CACHE_CLASS_AND_CHECK(ToolAttribute, GODOT_API_CLASS(ToolAttribute));
- CACHE_CLASS_AND_CHECK(RPCAttribute, GODOT_API_CLASS(RPCAttribute));
- CACHE_PROPERTY_AND_CHECK(RPCAttribute, Mode, CACHED_CLASS(RPCAttribute)->get_property("Mode"));
- CACHE_PROPERTY_AND_CHECK(RPCAttribute, CallLocal, CACHED_CLASS(RPCAttribute)->get_property("CallLocal"));
- CACHE_PROPERTY_AND_CHECK(RPCAttribute, TransferMode, CACHED_CLASS(RPCAttribute)->get_property("TransferMode"));
- CACHE_PROPERTY_AND_CHECK(RPCAttribute, TransferChannel, CACHED_CLASS(RPCAttribute)->get_property("TransferChannel"));
- CACHE_CLASS_AND_CHECK(GodotMethodAttribute, GODOT_API_CLASS(GodotMethodAttribute));
- CACHE_FIELD_AND_CHECK(GodotMethodAttribute, methodName, CACHED_CLASS(GodotMethodAttribute)->get_field("methodName"));
- CACHE_CLASS_AND_CHECK(ScriptPathAttribute, GODOT_API_CLASS(ScriptPathAttribute));
- CACHE_FIELD_AND_CHECK(ScriptPathAttribute, path, CACHED_CLASS(ScriptPathAttribute)->get_field("path"));
- CACHE_CLASS_AND_CHECK(AssemblyHasScriptsAttribute, GODOT_API_CLASS(AssemblyHasScriptsAttribute));
- CACHE_FIELD_AND_CHECK(AssemblyHasScriptsAttribute, requiresLookup, CACHED_CLASS(AssemblyHasScriptsAttribute)->get_field("requiresLookup"));
- CACHE_FIELD_AND_CHECK(AssemblyHasScriptsAttribute, scriptTypes, CACHED_CLASS(AssemblyHasScriptsAttribute)->get_field("scriptTypes"));
-
- CACHE_FIELD_AND_CHECK(GodotObject, ptr, CACHED_CLASS(GodotObject)->get_field(BINDINGS_PTR_FIELD));
- CACHE_FIELD_AND_CHECK(StringName, ptr, CACHED_CLASS(StringName)->get_field(BINDINGS_PTR_FIELD));
- CACHE_FIELD_AND_CHECK(NodePath, ptr, CACHED_CLASS(NodePath)->get_field(BINDINGS_PTR_FIELD));
- CACHE_FIELD_AND_CHECK(RID, ptr, CACHED_CLASS(RID)->get_field(BINDINGS_PTR_FIELD));
-
- CACHE_METHOD_THUNK_AND_CHECK(GodotObject, Dispose, CACHED_CLASS(GodotObject)->get_method("Dispose", 0));
- CACHE_METHOD_THUNK_AND_CHECK(Array, GetPtr, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Array)->get_method("GetPtr", 0));
- CACHE_METHOD_THUNK_AND_CHECK(Dictionary, GetPtr, GODOT_API_NS_CLASS(BINDINGS_NAMESPACE_COLLECTIONS, Dictionary)->get_method("GetPtr", 0));
- CACHE_METHOD_THUNK_AND_CHECK(SignalAwaiter, SignalCallback, GODOT_API_CLASS(SignalAwaiter)->get_method("SignalCallback", 1));
- CACHE_METHOD_THUNK_AND_CHECK(GodotTaskScheduler, Activate, GODOT_API_CLASS(GodotTaskScheduler)->get_method("Activate", 0));
-
- CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, TrySerializeDelegate, GODOT_API_CLASS(DelegateUtils)->get_method("TrySerializeDelegate", 2));
- CACHE_METHOD_THUNK_AND_CHECK(DelegateUtils, TryDeserializeDelegate, GODOT_API_CLASS(DelegateUtils)->get_method("TryDeserializeDelegate", 2));
-
- // Start of MarshalUtils methods
-
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericArray, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericArray", 1));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericDictionary", 1));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsSystemGenericList, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsSystemGenericList", 1));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsSystemGenericDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsSystemGenericDictionary", 1));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericIEnumerable, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericIEnumerable", 1));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericICollection, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericICollection", 1));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericIDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericIDictionary", 1));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeHasFlagsAttribute, GODOT_API_CLASS(MarshalUtils)->get_method("TypeHasFlagsAttribute", 1));
-
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GetGenericTypeDefinition, GODOT_API_CLASS(MarshalUtils)->get_method("GetGenericTypeDefinition", 2));
-
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, GODOT_API_CLASS(MarshalUtils)->get_method("ArrayGetElementType", 2));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, GODOT_API_CLASS(MarshalUtils)->get_method("DictionaryGetKeyValueTypes", 3));
-
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericArrayType, GODOT_API_CLASS(MarshalUtils)->get_method("MakeGenericArrayType", 1));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericDictionaryType, GODOT_API_CLASS(MarshalUtils)->get_method("MakeGenericDictionaryType", 2));
-
- // End of MarshalUtils methods
-
-#ifdef DEBUG_ENABLED
- CACHE_METHOD_THUNK_AND_CHECK(DebuggingUtils, GetStackFrameInfo, GODOT_API_CLASS(DebuggingUtils)->get_method("GetStackFrameInfo", 4));
-#endif
-
- // TODO Move to CSharpLanguage::init() and do handle disposal
- MonoObject *task_scheduler = mono_object_new(mono_domain_get(), GODOT_API_CLASS(GodotTaskScheduler)->get_mono_ptr());
- GDMonoUtils::runtime_object_init(task_scheduler, GODOT_API_CLASS(GodotTaskScheduler));
- cached_data.task_scheduler_handle = MonoGCHandleRef::create_strong(task_scheduler);
+#define CHECK_CALLBACK_NOT_NULL(m_class, m_method) CHECK_CALLBACK_NOT_NULL_IMPL(p_managed_callbacks.m_class##_##m_method, m_class, m_method)
+
+ CHECK_CALLBACK_NOT_NULL(SignalAwaiter, SignalCallback);
+ CHECK_CALLBACK_NOT_NULL(DelegateUtils, InvokeWithVariantArgs);
+ CHECK_CALLBACK_NOT_NULL(DelegateUtils, DelegateEquals);
+ CHECK_CALLBACK_NOT_NULL(DelegateUtils, TrySerializeDelegateWithGCHandle);
+ CHECK_CALLBACK_NOT_NULL(DelegateUtils, TryDeserializeDelegateWithGCHandle);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, FrameCallback);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, CreateManagedForGodotObjectBinding);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, CreateManagedForGodotObjectScriptInstance);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, GetScriptNativeName);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, SetGodotObjectPtr);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, RaiseEventSignal);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, ScriptIsOrInherits);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, AddScriptBridge);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, GetOrCreateScriptBridgeForPath);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, RemoveScriptBridge);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, TryReloadRegisteredScriptWithClass);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, UpdateScriptClassInfo);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, SwapGCHandleForType);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, GetPropertyInfoList);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, GetPropertyDefaultValues);
+ CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, Call);
+ CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, Set);
+ CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, Get);
+ CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, CallDispose);
+ CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, CallToString);
+ CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, HasMethodUnknownParams);
+ CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, SerializeState);
+ CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, DeserializeState);
+ CHECK_CALLBACK_NOT_NULL(GCHandleBridge, FreeGCHandle);
+ CHECK_CALLBACK_NOT_NULL(DebuggingUtils, GetCurrentStackInfo);
+ CHECK_CALLBACK_NOT_NULL(DisposablesTracker, OnGodotShuttingDown);
+ CHECK_CALLBACK_NOT_NULL(GD, OnCoreApiAssemblyLoaded);
+
+ managed_callbacks = p_managed_callbacks;
+
+ // It's easy to forget to add new callbacks here, so this should help
+ if (checked_count * sizeof(void *) != sizeof(ManagedCallbacks)) {
+ int missing_count = (sizeof(ManagedCallbacks) / sizeof(void *)) - checked_count;
+ WARN_PRINT("The presence of " + itos(missing_count) + " callback(s) was not validated");
+ }
- cached_data.godot_api_cache_updated = true;
+ godot_api_cache_updated = true;
}
} // namespace GDMonoCache
diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h
index e9cc26899e..ca3a6c95a7 100644
--- a/modules/mono/mono_gd/gd_mono_cache.h
+++ b/modules/mono/mono_gd/gd_mono_cache.h
@@ -31,174 +31,120 @@
#ifndef GD_MONO_CACHE_H
#define GD_MONO_CACHE_H
-#include "gd_mono_header.h"
-#include "gd_mono_method_thunk.h"
+#include <stdint.h>
+
+#include "../csharp_script.h"
+#include "../interop_types.h"
+#include "../mono_gc_handle.h"
+#include "core/object/object.h"
+#include "core/string/string_name.h"
+#include "core/string/ustring.h"
+#include "core/variant/callable.h"
+#include "core/variant/dictionary.h"
+#include "core/variant/variant.h"
+
+class CSharpScript;
namespace GDMonoCache {
-struct CachedData {
- // -----------------------------------------------
- // corlib classes
-
- // Let's use the no-namespace format for these too
- GDMonoClass *class_MonoObject = nullptr; // object
- GDMonoClass *class_bool = nullptr; // bool
- GDMonoClass *class_int8_t = nullptr; // sbyte
- GDMonoClass *class_int16_t = nullptr; // short
- GDMonoClass *class_int32_t = nullptr; // int
- GDMonoClass *class_int64_t = nullptr; // long
- GDMonoClass *class_uint8_t = nullptr; // byte
- GDMonoClass *class_uint16_t = nullptr; // ushort
- GDMonoClass *class_uint32_t = nullptr; // uint
- GDMonoClass *class_uint64_t = nullptr; // ulong
- GDMonoClass *class_float = nullptr; // float
- GDMonoClass *class_double = nullptr; // double
- GDMonoClass *class_String = nullptr; // string
- GDMonoClass *class_IntPtr = nullptr; // System.IntPtr
-
- GDMonoClass *class_System_Collections_IEnumerable = nullptr;
- GDMonoClass *class_System_Collections_ICollection = nullptr;
- GDMonoClass *class_System_Collections_IDictionary = nullptr;
-
-#ifdef DEBUG_ENABLED
- GDMonoClass *class_System_Diagnostics_StackTrace = nullptr;
- GDMonoMethodThunkR<MonoArray *, MonoObject *> methodthunk_System_Diagnostics_StackTrace_GetFrames;
- GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_bool = nullptr;
- GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool = nullptr;
+#ifdef WIN32
+#define GD_CLR_STDCALL __stdcall
+#else
+#define GD_CLR_STDCALL
#endif
- GDMonoClass *class_KeyNotFoundException = nullptr;
-
- MonoClass *rawclass_Dictionary = nullptr;
- // -----------------------------------------------
-
- GDMonoClass *class_Vector2 = nullptr;
- GDMonoClass *class_Vector2i = nullptr;
- GDMonoClass *class_Rect2 = nullptr;
- GDMonoClass *class_Rect2i = nullptr;
- GDMonoClass *class_Transform2D = nullptr;
- GDMonoClass *class_Vector3 = nullptr;
- GDMonoClass *class_Vector3i = nullptr;
- GDMonoClass *class_Vector4 = nullptr;
- GDMonoClass *class_Vector4i = nullptr;
- GDMonoClass *class_Basis = nullptr;
- GDMonoClass *class_Quaternion = nullptr;
- GDMonoClass *class_Transform3D = nullptr;
- GDMonoClass *class_Projection = nullptr;
- GDMonoClass *class_AABB = nullptr;
- GDMonoClass *class_Color = nullptr;
- GDMonoClass *class_Plane = nullptr;
- GDMonoClass *class_StringName = nullptr;
- GDMonoClass *class_NodePath = nullptr;
- GDMonoClass *class_RID = nullptr;
- GDMonoClass *class_GodotObject = nullptr;
- GDMonoClass *class_GodotResource = nullptr;
- GDMonoClass *class_Node = nullptr;
- GDMonoClass *class_Control = nullptr;
- GDMonoClass *class_Node3D = nullptr;
- GDMonoClass *class_WeakRef = nullptr;
- GDMonoClass *class_Callable = nullptr;
- GDMonoClass *class_SignalInfo = nullptr;
- GDMonoClass *class_Array = nullptr;
- GDMonoClass *class_Dictionary = nullptr;
- GDMonoClass *class_MarshalUtils = nullptr;
- GDMonoClass *class_ISerializationListener = nullptr;
-
-#ifdef DEBUG_ENABLED
- GDMonoClass *class_DebuggingUtils = nullptr;
- GDMonoMethodThunk<MonoObject *, MonoString **, int *, MonoString **> methodthunk_DebuggingUtils_GetStackFrameInfo;
-#endif
+struct godotsharp_property_info {
+ godot_string_name name; // Not owned
+ godot_string hint_string;
+ Variant::Type type;
+ PropertyHint hint;
+ PropertyUsageFlags usage;
+ bool exported;
+};
- GDMonoClass *class_ExportAttribute = nullptr;
- GDMonoField *field_ExportAttribute_hint = nullptr;
- GDMonoField *field_ExportAttribute_hintString = nullptr;
- GDMonoClass *class_SignalAttribute = nullptr;
- GDMonoClass *class_ToolAttribute = nullptr;
- GDMonoClass *class_RPCAttribute = nullptr;
- GDMonoProperty *property_RPCAttribute_Mode = nullptr;
- GDMonoProperty *property_RPCAttribute_CallLocal = nullptr;
- GDMonoProperty *property_RPCAttribute_TransferMode = nullptr;
- GDMonoProperty *property_RPCAttribute_TransferChannel = nullptr;
- GDMonoClass *class_GodotMethodAttribute = nullptr;
- GDMonoField *field_GodotMethodAttribute_methodName = nullptr;
- GDMonoClass *class_ScriptPathAttribute = nullptr;
- GDMonoField *field_ScriptPathAttribute_path = nullptr;
- GDMonoClass *class_AssemblyHasScriptsAttribute = nullptr;
- GDMonoField *field_AssemblyHasScriptsAttribute_requiresLookup = nullptr;
- GDMonoField *field_AssemblyHasScriptsAttribute_scriptTypes = nullptr;
-
- GDMonoField *field_GodotObject_ptr = nullptr;
- GDMonoField *field_StringName_ptr = nullptr;
- GDMonoField *field_NodePath_ptr = nullptr;
- GDMonoField *field_Image_ptr = nullptr;
- GDMonoField *field_RID_ptr = nullptr;
-
- GDMonoMethodThunk<MonoObject *> methodthunk_GodotObject_Dispose;
- GDMonoMethodThunkR<Array *, MonoObject *> methodthunk_Array_GetPtr;
- GDMonoMethodThunkR<Dictionary *, MonoObject *> methodthunk_Dictionary_GetPtr;
- GDMonoMethodThunk<MonoObject *, MonoArray *> methodthunk_SignalAwaiter_SignalCallback;
- GDMonoMethodThunk<MonoObject *> methodthunk_GodotTaskScheduler_Activate;
-
- GDMonoMethodThunkR<MonoBoolean, MonoObject *, MonoObject *> methodthunk_Delegate_Equals;
-
- GDMonoMethodThunkR<MonoBoolean, MonoDelegate *, MonoObject *> methodthunk_DelegateUtils_TrySerializeDelegate;
- GDMonoMethodThunkR<MonoBoolean, MonoObject *, MonoDelegate **> methodthunk_DelegateUtils_TryDeserializeDelegate;
-
- // Start of MarshalUtils methods
-
- GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericArray;
- GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericDictionary;
- GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsSystemGenericList;
- GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsSystemGenericDictionary;
- GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIEnumerable;
- GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericICollection;
- GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIDictionary;
- GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeHasFlagsAttribute;
-
- GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_GetGenericTypeDefinition;
-
- GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_ArrayGetElementType;
- GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **, MonoReflectionType **> methodthunk_MarshalUtils_DictionaryGetKeyValueTypes;
-
- GDMonoMethodThunkR<MonoReflectionType *, MonoReflectionType *> methodthunk_MarshalUtils_MakeGenericArrayType;
- GDMonoMethodThunkR<MonoReflectionType *, MonoReflectionType *, MonoReflectionType *> methodthunk_MarshalUtils_MakeGenericDictionaryType;
-
- // End of MarshalUtils methods
-
- Ref<MonoGCHandleRef> task_scheduler_handle;
-
- bool corlib_cache_updated;
- bool godot_api_cache_updated;
-
- void clear_corlib_cache();
- void clear_godot_api_cache();
-
- CachedData() {
- clear_corlib_cache();
- clear_godot_api_cache();
- }
+struct godotsharp_property_def_val_pair {
+ godot_string_name name; // Not owned
+ godot_variant value;
};
-extern CachedData cached_data;
+struct ManagedCallbacks {
+ using Callback_ScriptManagerBridge_GetPropertyInfoList_Add = void(GD_CLR_STDCALL *)(CSharpScript *p_script, const String *, godotsharp_property_info *p_props, int32_t p_count);
+ using Callback_ScriptManagerBridge_GetPropertyDefaultValues_Add = void(GD_CLR_STDCALL *)(CSharpScript *p_script, godotsharp_property_def_val_pair *p_def_vals, int32_t p_count);
+
+ using FuncSignalAwaiter_SignalCallback = void(GD_CLR_STDCALL *)(GCHandleIntPtr, const Variant **, int32_t, bool *);
+ using FuncDelegateUtils_InvokeWithVariantArgs = void(GD_CLR_STDCALL *)(GCHandleIntPtr, const Variant **, uint32_t, const Variant *);
+ using FuncDelegateUtils_DelegateEquals = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, GCHandleIntPtr);
+ using FuncDelegateUtils_TrySerializeDelegateWithGCHandle = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const Array *);
+ using FuncDelegateUtils_TryDeserializeDelegateWithGCHandle = bool(GD_CLR_STDCALL *)(const Array *, GCHandleIntPtr *);
+ using FuncScriptManagerBridge_FrameCallback = void(GD_CLR_STDCALL *)();
+ using FuncScriptManagerBridge_CreateManagedForGodotObjectBinding = GCHandleIntPtr(GD_CLR_STDCALL *)(const StringName *, Object *);
+ using FuncScriptManagerBridge_CreateManagedForGodotObjectScriptInstance = bool(GD_CLR_STDCALL *)(const CSharpScript *, Object *, const Variant **, int32_t);
+ using FuncScriptManagerBridge_GetScriptNativeName = void(GD_CLR_STDCALL *)(const CSharpScript *, StringName *);
+ using FuncScriptManagerBridge_SetGodotObjectPtr = void(GD_CLR_STDCALL *)(GCHandleIntPtr, Object *);
+ using FuncScriptManagerBridge_RaiseEventSignal = void(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *, const Variant **, int32_t, bool *);
+ using FuncScriptManagerBridge_ScriptIsOrInherits = bool(GD_CLR_STDCALL *)(const CSharpScript *, const CSharpScript *);
+ using FuncScriptManagerBridge_AddScriptBridge = bool(GD_CLR_STDCALL *)(const CSharpScript *, const String *);
+ using FuncScriptManagerBridge_GetOrCreateScriptBridgeForPath = void(GD_CLR_STDCALL *)(const String *, Ref<CSharpScript> *);
+ using FuncScriptManagerBridge_RemoveScriptBridge = void(GD_CLR_STDCALL *)(const CSharpScript *);
+ using FuncScriptManagerBridge_TryReloadRegisteredScriptWithClass = bool(GD_CLR_STDCALL *)(const CSharpScript *);
+ using FuncScriptManagerBridge_UpdateScriptClassInfo = void(GD_CLR_STDCALL *)(const CSharpScript *, bool *, Array *, Dictionary *, Dictionary *, Ref<CSharpScript> *);
+ using FuncScriptManagerBridge_SwapGCHandleForType = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, GCHandleIntPtr *, bool);
+ using FuncScriptManagerBridge_GetPropertyInfoList = void(GD_CLR_STDCALL *)(CSharpScript *, Callback_ScriptManagerBridge_GetPropertyInfoList_Add);
+ using FuncScriptManagerBridge_GetPropertyDefaultValues = void(GD_CLR_STDCALL *)(CSharpScript *, Callback_ScriptManagerBridge_GetPropertyDefaultValues_Add);
+ using FuncCSharpInstanceBridge_Call = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *, const Variant **, int32_t, Callable::CallError *, Variant *);
+ using FuncCSharpInstanceBridge_Set = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *, const Variant *);
+ using FuncCSharpInstanceBridge_Get = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *, Variant *);
+ using FuncCSharpInstanceBridge_CallDispose = void(GD_CLR_STDCALL *)(GCHandleIntPtr, bool);
+ using FuncCSharpInstanceBridge_CallToString = void(GD_CLR_STDCALL *)(GCHandleIntPtr, String *, bool *);
+ using FuncCSharpInstanceBridge_HasMethodUnknownParams = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *);
+ using FuncCSharpInstanceBridge_SerializeState = void(GD_CLR_STDCALL *)(GCHandleIntPtr, const Dictionary *, const Dictionary *);
+ using FuncCSharpInstanceBridge_DeserializeState = void(GD_CLR_STDCALL *)(GCHandleIntPtr, const Dictionary *, const Dictionary *);
+ using FuncGCHandleBridge_FreeGCHandle = void(GD_CLR_STDCALL *)(GCHandleIntPtr);
+ using FuncDebuggingUtils_GetCurrentStackInfo = void(GD_CLR_STDCALL *)(Vector<ScriptLanguage::StackInfo> *);
+ using FuncDisposablesTracker_OnGodotShuttingDown = void(GD_CLR_STDCALL *)();
+ using FuncGD_OnCoreApiAssemblyLoaded = void(GD_CLR_STDCALL *)(bool);
+
+ FuncSignalAwaiter_SignalCallback SignalAwaiter_SignalCallback;
+ FuncDelegateUtils_InvokeWithVariantArgs DelegateUtils_InvokeWithVariantArgs;
+ FuncDelegateUtils_DelegateEquals DelegateUtils_DelegateEquals;
+ FuncDelegateUtils_TrySerializeDelegateWithGCHandle DelegateUtils_TrySerializeDelegateWithGCHandle;
+ FuncDelegateUtils_TryDeserializeDelegateWithGCHandle DelegateUtils_TryDeserializeDelegateWithGCHandle;
+ FuncScriptManagerBridge_FrameCallback ScriptManagerBridge_FrameCallback;
+ FuncScriptManagerBridge_CreateManagedForGodotObjectBinding ScriptManagerBridge_CreateManagedForGodotObjectBinding;
+ FuncScriptManagerBridge_CreateManagedForGodotObjectScriptInstance ScriptManagerBridge_CreateManagedForGodotObjectScriptInstance;
+ FuncScriptManagerBridge_GetScriptNativeName ScriptManagerBridge_GetScriptNativeName;
+ FuncScriptManagerBridge_SetGodotObjectPtr ScriptManagerBridge_SetGodotObjectPtr;
+ FuncScriptManagerBridge_RaiseEventSignal ScriptManagerBridge_RaiseEventSignal;
+ FuncScriptManagerBridge_ScriptIsOrInherits ScriptManagerBridge_ScriptIsOrInherits;
+ FuncScriptManagerBridge_AddScriptBridge ScriptManagerBridge_AddScriptBridge;
+ FuncScriptManagerBridge_GetOrCreateScriptBridgeForPath ScriptManagerBridge_GetOrCreateScriptBridgeForPath;
+ FuncScriptManagerBridge_RemoveScriptBridge ScriptManagerBridge_RemoveScriptBridge;
+ FuncScriptManagerBridge_TryReloadRegisteredScriptWithClass ScriptManagerBridge_TryReloadRegisteredScriptWithClass;
+ FuncScriptManagerBridge_UpdateScriptClassInfo ScriptManagerBridge_UpdateScriptClassInfo;
+ FuncScriptManagerBridge_SwapGCHandleForType ScriptManagerBridge_SwapGCHandleForType;
+ FuncScriptManagerBridge_GetPropertyInfoList ScriptManagerBridge_GetPropertyInfoList;
+ FuncScriptManagerBridge_GetPropertyDefaultValues ScriptManagerBridge_GetPropertyDefaultValues;
+ FuncCSharpInstanceBridge_Call CSharpInstanceBridge_Call;
+ FuncCSharpInstanceBridge_Set CSharpInstanceBridge_Set;
+ FuncCSharpInstanceBridge_Get CSharpInstanceBridge_Get;
+ FuncCSharpInstanceBridge_CallDispose CSharpInstanceBridge_CallDispose;
+ FuncCSharpInstanceBridge_CallToString CSharpInstanceBridge_CallToString;
+ FuncCSharpInstanceBridge_HasMethodUnknownParams CSharpInstanceBridge_HasMethodUnknownParams;
+ FuncCSharpInstanceBridge_SerializeState CSharpInstanceBridge_SerializeState;
+ FuncCSharpInstanceBridge_DeserializeState CSharpInstanceBridge_DeserializeState;
+ FuncGCHandleBridge_FreeGCHandle GCHandleBridge_FreeGCHandle;
+ FuncDebuggingUtils_GetCurrentStackInfo DebuggingUtils_GetCurrentStackInfo;
+ FuncDisposablesTracker_OnGodotShuttingDown DisposablesTracker_OnGodotShuttingDown;
+ FuncGD_OnCoreApiAssemblyLoaded GD_OnCoreApiAssemblyLoaded;
+};
-void update_corlib_cache();
-void update_godot_api_cache();
+extern ManagedCallbacks managed_callbacks;
+extern bool godot_api_cache_updated;
-inline void clear_corlib_cache() {
- cached_data.clear_corlib_cache();
-}
+void update_godot_api_cache(const ManagedCallbacks &p_managed_callbacks);
-inline void clear_godot_api_cache() {
- cached_data.clear_godot_api_cache();
-}
} // namespace GDMonoCache
-#define CACHED_CLASS(m_class) (GDMonoCache::cached_data.class_##m_class)
-#define CACHED_CLASS_RAW(m_class) (GDMonoCache::cached_data.class_##m_class->get_mono_ptr())
-#define CACHED_RAW_MONO_CLASS(m_class) (GDMonoCache::cached_data.rawclass_##m_class)
-#define CACHED_FIELD(m_class, m_field) (GDMonoCache::cached_data.field_##m_class##_##m_field)
-#define CACHED_METHOD(m_class, m_method) (GDMonoCache::cached_data.method_##m_class##_##m_method)
-#define CACHED_METHOD_THUNK(m_class, m_method) (GDMonoCache::cached_data.methodthunk_##m_class##_##m_method)
-#define CACHED_PROPERTY(m_class, m_property) (GDMonoCache::cached_data.property_##m_class##_##m_property)
+#undef GD_CLR_STDCALL
#endif // GD_MONO_CACHE_H
diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp
deleted file mode 100644
index 51c5aa3542..0000000000
--- a/modules/mono/mono_gd/gd_mono_class.cpp
+++ /dev/null
@@ -1,576 +0,0 @@
-/*************************************************************************/
-/* gd_mono_class.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "gd_mono_class.h"
-
-#include <mono/metadata/attrdefs.h>
-#include <mono/metadata/debug-helpers.h>
-
-#include "gd_mono_assembly.h"
-#include "gd_mono_cache.h"
-#include "gd_mono_marshal.h"
-
-String GDMonoClass::get_full_name(MonoClass *p_mono_class) {
- // mono_type_get_full_name is not exposed to embedders, but this seems to do the job
- MonoReflectionType *type_obj = mono_type_get_object(mono_domain_get(), get_mono_type(p_mono_class));
-
- MonoException *exc = nullptr;
- MonoString *str = GDMonoUtils::object_to_string((MonoObject *)type_obj, &exc);
- UNHANDLED_EXCEPTION(exc);
-
- return GDMonoMarshal::mono_string_to_godot(str);
-}
-
-MonoType *GDMonoClass::get_mono_type(MonoClass *p_mono_class) {
- return mono_class_get_type(p_mono_class);
-}
-
-String GDMonoClass::get_full_name() const {
- return get_full_name(mono_class);
-}
-
-String GDMonoClass::get_type_desc() const {
- return GDMonoUtils::get_type_desc(get_mono_type());
-}
-
-MonoType *GDMonoClass::get_mono_type() const {
- // Careful, you cannot compare two MonoType*.
- // There is mono_metadata_type_equal, how is this different from comparing two MonoClass*?
- return get_mono_type(mono_class);
-}
-
-uint32_t GDMonoClass::get_flags() const {
- return mono_class_get_flags(mono_class);
-}
-
-bool GDMonoClass::is_static() const {
- uint32_t static_class_flags = MONO_TYPE_ATTR_ABSTRACT | MONO_TYPE_ATTR_SEALED;
- return (get_flags() & static_class_flags) == static_class_flags;
-}
-
-bool GDMonoClass::is_assignable_from(GDMonoClass *p_from) const {
- return mono_class_is_assignable_from(mono_class, p_from->mono_class);
-}
-
-StringName GDMonoClass::get_namespace() const {
- GDMonoClass *nesting_class = get_nesting_class();
- if (!nesting_class) {
- return namespace_name;
- }
- return nesting_class->get_namespace();
-}
-
-String GDMonoClass::get_name_for_lookup() const {
- GDMonoClass *nesting_class = get_nesting_class();
- if (!nesting_class) {
- return class_name;
- }
- return nesting_class->get_name_for_lookup() + "/" + class_name;
-}
-
-GDMonoClass *GDMonoClass::get_parent_class() const {
- MonoClass *parent_mono_class = mono_class_get_parent(mono_class);
- return parent_mono_class ? GDMono::get_singleton()->get_class(parent_mono_class) : nullptr;
-}
-
-GDMonoClass *GDMonoClass::get_nesting_class() const {
- MonoClass *nesting_type = mono_class_get_nesting_type(mono_class);
- return nesting_type ? GDMono::get_singleton()->get_class(nesting_type) : nullptr;
-}
-
-#ifdef TOOLS_ENABLED
-Vector<MonoClassField *> GDMonoClass::get_enum_fields() {
- bool class_is_enum = mono_class_is_enum(mono_class);
- ERR_FAIL_COND_V(!class_is_enum, Vector<MonoClassField *>());
-
- Vector<MonoClassField *> enum_fields;
-
- void *iter = nullptr;
- MonoClassField *raw_field = nullptr;
- while ((raw_field = mono_class_get_fields(get_mono_ptr(), &iter)) != nullptr) {
- uint32_t field_flags = mono_field_get_flags(raw_field);
-
- // Enums have an instance field named value__ which holds the value of the enum.
- // Enum constants are static, so we will use this to ignore the value__ field.
- if (field_flags & MONO_FIELD_ATTR_PUBLIC && field_flags & MONO_FIELD_ATTR_STATIC) {
- enum_fields.push_back(raw_field);
- }
- }
-
- return enum_fields;
-}
-#endif
-
-bool GDMonoClass::has_attribute(GDMonoClass *p_attr_class) {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_NULL_V(p_attr_class, false);
-#endif
-
- if (!attrs_fetched) {
- fetch_attributes();
- }
-
- if (!attributes) {
- return false;
- }
-
- return mono_custom_attrs_has_attr(attributes, p_attr_class->get_mono_ptr());
-}
-
-MonoObject *GDMonoClass::get_attribute(GDMonoClass *p_attr_class) {
-#ifdef DEBUG_ENABLED
- ERR_FAIL_NULL_V(p_attr_class, nullptr);
-#endif
-
- if (!attrs_fetched) {
- fetch_attributes();
- }
-
- if (!attributes) {
- return nullptr;
- }
-
- return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr());
-}
-
-void GDMonoClass::fetch_attributes() {
- ERR_FAIL_COND(attributes != nullptr);
-
- attributes = mono_custom_attrs_from_class(get_mono_ptr());
- attrs_fetched = true;
-}
-
-void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base) {
- CRASH_COND(!CACHED_CLASS(GodotObject)->is_assignable_from(this));
-
- if (methods_fetched) {
- return;
- }
-
- void *iter = nullptr;
- MonoMethod *raw_method = nullptr;
- while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != nullptr) {
- StringName name = String::utf8(mono_method_get_name(raw_method));
-
- // get_method implicitly fetches methods and adds them to this->methods
- GDMonoMethod *method = get_method(raw_method, name);
- ERR_CONTINUE(!method);
-
- if (method->get_name() != name) {
-#ifdef DEBUG_ENABLED
- String fullname = method->get_ret_type_full_name() + " " + name + "(" + method->get_signature_desc(true) + ")";
- WARN_PRINT("Method '" + fullname + "' is hidden by Godot API method. Should be '" +
- method->get_full_name_no_class() + "'. In class '" + namespace_name + "." + class_name + "'.");
-#endif
- continue;
- }
-
-#ifdef DEBUG_ENABLED
- // For debug builds, we also fetched from native base classes as well before if this is not a native base class.
- // This allows us to warn the user here if they are using snake_case by mistake.
-
- if (p_native_base != this) {
- GDMonoClass *native_top = p_native_base;
- while (native_top) {
- GDMonoMethod *m = native_top->get_method(name, method->get_parameters_count());
-
- if (m && m->get_name() != name) {
- // found
- String fullname = m->get_ret_type_full_name() + " " + name + "(" + m->get_signature_desc(true) + ")";
- WARN_PRINT("Method '" + fullname + "' should be '" + m->get_full_name_no_class() +
- "'. In class '" + namespace_name + "." + class_name + "'.");
- break;
- }
-
- if (native_top == CACHED_CLASS(GodotObject)) {
- break;
- }
-
- native_top = native_top->get_parent_class();
- }
- }
-#endif
-
- uint32_t flags = mono_method_get_flags(method->mono_method, nullptr);
-
- if (!(flags & MONO_METHOD_ATTR_VIRTUAL)) {
- continue;
- }
-
- // Virtual method of Godot Object derived type, let's try to find GodotMethod attribute
-
- GDMonoClass *top = p_native_base;
-
- while (top) {
- GDMonoMethod *base_method = top->get_method(name, method->get_parameters_count());
-
- if (base_method && base_method->has_attribute(CACHED_CLASS(GodotMethodAttribute))) {
- // Found base method with GodotMethod attribute.
- // We get the original API method name from this attribute.
- // This name must point to the virtual method.
-
- MonoObject *attr = base_method->get_attribute(CACHED_CLASS(GodotMethodAttribute));
-
- StringName godot_method_name = CACHED_FIELD(GodotMethodAttribute, methodName)->get_string_value(attr);
-#ifdef DEBUG_ENABLED
- CRASH_COND(godot_method_name == StringName());
-#endif
- MethodKey key = MethodKey(godot_method_name, method->get_parameters_count());
- GDMonoMethod **existing_method = methods.getptr(key);
- if (existing_method) {
- memdelete(*existing_method); // Must delete old one
- }
- methods.insert(key, method);
-
- break;
- }
-
- if (top == CACHED_CLASS(GodotObject)) {
- break;
- }
-
- top = top->get_parent_class();
- }
- }
-
- methods_fetched = true;
-}
-
-GDMonoMethod *GDMonoClass::get_fetched_method_unknown_params(const StringName &p_name) {
- ERR_FAIL_COND_V(!methods_fetched, nullptr);
-
- for (const KeyValue<MethodKey, GDMonoMethod *> &E : methods) {
- if (E.key.name == p_name) {
- return E.value;
- }
- }
-
- return nullptr;
-}
-
-bool GDMonoClass::has_fetched_method_unknown_params(const StringName &p_name) {
- return get_fetched_method_unknown_params(p_name) != nullptr;
-}
-
-bool GDMonoClass::implements_interface(GDMonoClass *p_interface) {
- return mono_class_implements_interface(mono_class, p_interface->get_mono_ptr());
-}
-
-bool GDMonoClass::has_public_parameterless_ctor() {
- GDMonoMethod *ctor = get_method(".ctor", 0);
- return ctor && ctor->get_visibility() == IMonoClassMember::PUBLIC;
-}
-
-GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, uint16_t p_params_count) {
- MethodKey key = MethodKey(p_name, p_params_count);
-
- GDMonoMethod **match = methods.getptr(key);
-
- if (match) {
- return *match;
- }
-
- if (methods_fetched) {
- return nullptr;
- }
-
- MonoMethod *raw_method = mono_class_get_method_from_name(mono_class, String(p_name).utf8().get_data(), p_params_count);
-
- if (raw_method) {
- GDMonoMethod *method = memnew(GDMonoMethod(p_name, raw_method));
- methods.insert(key, method);
-
- return method;
- }
-
- return nullptr;
-}
-
-GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method) {
- MonoMethodSignature *sig = mono_method_signature(p_raw_method);
-
- int params_count = mono_signature_get_param_count(sig);
- StringName method_name = String::utf8(mono_method_get_name(p_raw_method));
-
- return get_method(p_raw_method, method_name, params_count);
-}
-
-GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName &p_name) {
- MonoMethodSignature *sig = mono_method_signature(p_raw_method);
- int params_count = mono_signature_get_param_count(sig);
- return get_method(p_raw_method, p_name, params_count);
-}
-
-GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName &p_name, uint16_t p_params_count) {
- ERR_FAIL_NULL_V(p_raw_method, nullptr);
-
- MethodKey key = MethodKey(p_name, p_params_count);
-
- GDMonoMethod **match = methods.getptr(key);
-
- if (match) {
- return *match;
- }
-
- GDMonoMethod *method = memnew(GDMonoMethod(p_name, p_raw_method));
- methods.insert(key, method);
-
- return method;
-}
-
-GDMonoMethod *GDMonoClass::get_method_with_desc(const String &p_description, bool p_include_namespace) {
- MonoMethodDesc *desc = mono_method_desc_new(p_description.utf8().get_data(), p_include_namespace);
- MonoMethod *method = mono_method_desc_search_in_class(desc, mono_class);
- mono_method_desc_free(desc);
-
- if (!method) {
- return nullptr;
- }
-
- ERR_FAIL_COND_V(mono_method_get_class(method) != mono_class, nullptr);
-
- return get_method(method);
-}
-
-GDMonoField *GDMonoClass::get_field(const StringName &p_name) {
- HashMap<StringName, GDMonoField *>::Iterator result = fields.find(p_name);
-
- if (result) {
- return result->value;
- }
-
- if (fields_fetched) {
- return nullptr;
- }
-
- MonoClassField *raw_field = mono_class_get_field_from_name(mono_class, String(p_name).utf8().get_data());
-
- if (raw_field) {
- GDMonoField *field = memnew(GDMonoField(raw_field, this));
- fields.insert(p_name, field);
-
- return field;
- }
-
- return nullptr;
-}
-
-const Vector<GDMonoField *> &GDMonoClass::get_all_fields() {
- if (fields_fetched) {
- return fields_list;
- }
-
- void *iter = nullptr;
- MonoClassField *raw_field = nullptr;
- while ((raw_field = mono_class_get_fields(mono_class, &iter)) != nullptr) {
- StringName name = String::utf8(mono_field_get_name(raw_field));
-
- HashMap<StringName, GDMonoField *>::Iterator match = fields.find(name);
-
- if (match) {
- fields_list.push_back(match->value);
- } else {
- GDMonoField *field = memnew(GDMonoField(raw_field, this));
- fields.insert(name, field);
- fields_list.push_back(field);
- }
- }
-
- fields_fetched = true;
-
- return fields_list;
-}
-
-GDMonoProperty *GDMonoClass::get_property(const StringName &p_name) {
- HashMap<StringName, GDMonoProperty *>::Iterator result = properties.find(p_name);
-
- if (result) {
- return result->value;
- }
-
- if (properties_fetched) {
- return nullptr;
- }
-
- MonoProperty *raw_property = mono_class_get_property_from_name(mono_class, String(p_name).utf8().get_data());
-
- if (raw_property) {
- GDMonoProperty *property = memnew(GDMonoProperty(raw_property, this));
- properties.insert(p_name, property);
-
- return property;
- }
-
- return nullptr;
-}
-
-const Vector<GDMonoProperty *> &GDMonoClass::get_all_properties() {
- if (properties_fetched) {
- return properties_list;
- }
-
- void *iter = nullptr;
- MonoProperty *raw_property = nullptr;
- while ((raw_property = mono_class_get_properties(mono_class, &iter)) != nullptr) {
- StringName name = String::utf8(mono_property_get_name(raw_property));
-
- HashMap<StringName, GDMonoProperty *>::Iterator match = properties.find(name);
-
- if (match) {
- properties_list.push_back(match->value);
- } else {
- GDMonoProperty *property = memnew(GDMonoProperty(raw_property, this));
- properties.insert(name, property);
- properties_list.push_back(property);
- }
- }
-
- properties_fetched = true;
-
- return properties_list;
-}
-
-const Vector<GDMonoClass *> &GDMonoClass::get_all_delegates() {
- if (delegates_fetched) {
- return delegates_list;
- }
-
- // If the class is generic we must use the generic type definition.
- MonoClass *klass = mono_class;
- if (mono_type_get_type(get_mono_type()) == MONO_TYPE_GENERICINST) {
- MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), get_mono_type());
- GDMonoUtils::Marshal::get_generic_type_definition(reftype, &reftype);
- MonoType *type = mono_reflection_type_get_type(reftype);
- klass = mono_class_from_mono_type(type);
- }
-
- void *iter = nullptr;
- MonoClass *raw_class = nullptr;
- while ((raw_class = mono_class_get_nested_types(klass, &iter)) != nullptr) {
- if (mono_class_is_delegate(raw_class)) {
- StringName name = String::utf8(mono_class_get_name(raw_class));
-
- HashMap<StringName, GDMonoClass *>::Iterator match = delegates.find(name);
-
- if (match) {
- delegates_list.push_back(match->value);
- } else {
- GDMonoClass *delegate = memnew(GDMonoClass(String::utf8(mono_class_get_namespace(raw_class)), String::utf8(mono_class_get_name(raw_class)), raw_class, assembly));
- delegates.insert(name, delegate);
- delegates_list.push_back(delegate);
- }
- }
- }
-
- delegates_fetched = true;
-
- return delegates_list;
-}
-
-const Vector<GDMonoMethod *> &GDMonoClass::get_all_methods() {
- if (!method_list_fetched) {
- void *iter = nullptr;
- MonoMethod *raw_method = nullptr;
- while ((raw_method = mono_class_get_methods(get_mono_ptr(), &iter)) != nullptr) {
- method_list.push_back(memnew(GDMonoMethod(String::utf8(mono_method_get_name(raw_method)), raw_method)));
- }
-
- method_list_fetched = true;
- }
-
- return method_list;
-}
-
-GDMonoClass::GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly) {
- namespace_name = p_namespace;
- class_name = p_name;
- mono_class = p_class;
- assembly = p_assembly;
-
- attrs_fetched = false;
- attributes = nullptr;
-
- methods_fetched = false;
- method_list_fetched = false;
- fields_fetched = false;
- properties_fetched = false;
- delegates_fetched = false;
-}
-
-GDMonoClass::~GDMonoClass() {
- if (attributes) {
- mono_custom_attrs_free(attributes);
- }
-
- for (const KeyValue<StringName, GDMonoField *> &E : fields) {
- memdelete(E.value);
- }
-
- for (const KeyValue<StringName, GDMonoProperty *> &E : properties) {
- memdelete(E.value);
- }
-
- {
- // Ugly workaround...
- // We may have duplicated values, because we redirect snake_case methods to PascalCasel (only Godot API methods).
- // This way, we end with both the snake_case name and the PascalCasel name paired with the same method.
- // Therefore, we must avoid deleting the same pointer twice.
-
- int offset = 0;
- Vector<GDMonoMethod *> deleted_methods;
- deleted_methods.resize(methods.size());
-
- for (const KeyValue<MethodKey, GDMonoMethod *> &E : methods) {
- GDMonoMethod *method = E.value;
-
- if (method) {
- for (int i = 0; i < offset; i++) {
- if (deleted_methods[i] == method) {
- // Already deleted
- goto already_deleted;
- }
- }
-
- deleted_methods.write[offset] = method;
- ++offset;
-
- memdelete(method);
- }
-
- already_deleted:;
- }
-
- methods.clear();
- }
-
- for (int i = 0; i < method_list.size(); ++i) {
- memdelete(method_list[i]);
- }
-}
diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h
deleted file mode 100644
index 6b35da30f9..0000000000
--- a/modules/mono/mono_gd/gd_mono_class.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/*************************************************************************/
-/* gd_mono_class.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GD_MONO_CLASS_H
-#define GD_MONO_CLASS_H
-
-#include "core/string/ustring.h"
-#include "core/templates/rb_map.h"
-
-#include "gd_mono_field.h"
-#include "gd_mono_header.h"
-#include "gd_mono_method.h"
-#include "gd_mono_property.h"
-#include "gd_mono_utils.h"
-
-class GDMonoClass {
- struct MethodKey {
- struct Hasher {
- static _FORCE_INLINE_ uint32_t hash(const MethodKey &p_key) {
- uint32_t hash = 0;
-
- GDMonoUtils::hash_combine(hash, p_key.name.hash());
- GDMonoUtils::hash_combine(hash, HashMapHasherDefault::hash(p_key.params_count));
-
- return hash;
- }
- };
-
- _FORCE_INLINE_ bool operator==(const MethodKey &p_a) const {
- return p_a.params_count == params_count && p_a.name == name;
- }
-
- MethodKey() {}
-
- MethodKey(const StringName &p_name, uint16_t p_params_count) :
- name(p_name), params_count(p_params_count) {
- }
-
- StringName name;
- uint16_t params_count = 0;
- };
-
- StringName namespace_name;
- StringName class_name;
-
- MonoClass *mono_class = nullptr;
- GDMonoAssembly *assembly = nullptr;
-
- bool attrs_fetched;
- MonoCustomAttrInfo *attributes = nullptr;
-
- // This contains both the original method names and remapped method names from the native Godot identifiers to the C# functions.
- // Most method-related functions refer to this and it's possible this is unintuitive for outside users; this may be a prime location for refactoring or renaming.
- bool methods_fetched;
- HashMap<MethodKey, GDMonoMethod *, MethodKey::Hasher> methods;
-
- bool method_list_fetched;
- Vector<GDMonoMethod *> method_list;
-
- bool fields_fetched;
- HashMap<StringName, GDMonoField *> fields;
- Vector<GDMonoField *> fields_list;
-
- bool properties_fetched;
- HashMap<StringName, GDMonoProperty *> properties;
- Vector<GDMonoProperty *> properties_list;
-
- bool delegates_fetched;
- HashMap<StringName, GDMonoClass *> delegates;
- Vector<GDMonoClass *> delegates_list;
-
- friend class GDMonoAssembly;
- GDMonoClass(const StringName &p_namespace, const StringName &p_name, MonoClass *p_class, GDMonoAssembly *p_assembly);
-
-public:
- static String get_full_name(MonoClass *p_mono_class);
- static MonoType *get_mono_type(MonoClass *p_mono_class);
-
- String get_full_name() const;
- String get_type_desc() const;
- MonoType *get_mono_type() const;
-
- uint32_t get_flags() const;
- bool is_static() const;
-
- bool is_assignable_from(GDMonoClass *p_from) const;
-
- StringName get_namespace() const;
- _FORCE_INLINE_ StringName get_name() const { return class_name; }
- String get_name_for_lookup() const;
-
- _FORCE_INLINE_ MonoClass *get_mono_ptr() const { return mono_class; }
- _FORCE_INLINE_ const GDMonoAssembly *get_assembly() const { return assembly; }
-
- GDMonoClass *get_parent_class() const;
- GDMonoClass *get_nesting_class() const;
-
-#ifdef TOOLS_ENABLED
- Vector<MonoClassField *> get_enum_fields();
-#endif
-
- GDMonoMethod *get_fetched_method_unknown_params(const StringName &p_name);
- bool has_fetched_method_unknown_params(const StringName &p_name);
-
- bool has_attribute(GDMonoClass *p_attr_class);
- MonoObject *get_attribute(GDMonoClass *p_attr_class);
-
- void fetch_attributes();
- void fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base);
-
- bool implements_interface(GDMonoClass *p_interface);
- bool has_public_parameterless_ctor();
-
- GDMonoMethod *get_method(const StringName &p_name, uint16_t p_params_count = 0);
- GDMonoMethod *get_method(MonoMethod *p_raw_method);
- GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name);
- GDMonoMethod *get_method(MonoMethod *p_raw_method, const StringName &p_name, uint16_t p_params_count);
- GDMonoMethod *get_method_with_desc(const String &p_description, bool p_include_namespace);
-
- GDMonoField *get_field(const StringName &p_name);
- const Vector<GDMonoField *> &get_all_fields();
-
- GDMonoProperty *get_property(const StringName &p_name);
- const Vector<GDMonoProperty *> &get_all_properties();
-
- const Vector<GDMonoClass *> &get_all_delegates();
-
- const Vector<GDMonoMethod *> &get_all_methods();
-
- ~GDMonoClass();
-};
-
-#endif // GD_MONO_CLASS_H
diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
deleted file mode 100644
index cb025fc67a..0000000000
--- a/modules/mono/mono_gd/gd_mono_field.cpp
+++ /dev/null
@@ -1,556 +0,0 @@
-/*************************************************************************/
-/* gd_mono_field.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "gd_mono_field.h"
-
-#include <mono/metadata/attrdefs.h>
-
-#include "gd_mono_cache.h"
-#include "gd_mono_class.h"
-#include "gd_mono_marshal.h"
-#include "gd_mono_utils.h"
-
-void GDMonoField::set_value(MonoObject *p_object, MonoObject *p_value) {
- mono_field_set_value(p_object, mono_field, p_value);
-}
-
-void GDMonoField::set_value_raw(MonoObject *p_object, void *p_ptr) {
- mono_field_set_value(p_object, mono_field, &p_ptr);
-}
-
-void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_value) {
- switch (type.type_encoding) {
- case MONO_TYPE_BOOLEAN: {
- MonoBoolean val = p_value.operator bool();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_CHAR: {
- int16_t val = p_value.operator unsigned short();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_I1: {
- int8_t val = p_value.operator signed char();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_I2: {
- int16_t val = p_value.operator signed short();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_I4: {
- int32_t val = p_value.operator signed int();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_I8: {
- int64_t val = p_value.operator int64_t();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_U1: {
- uint8_t val = p_value.operator unsigned char();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_U2: {
- uint16_t val = p_value.operator unsigned short();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_U4: {
- uint32_t val = p_value.operator unsigned int();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_U8: {
- uint64_t val = p_value.operator uint64_t();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_R4: {
- float val = p_value.operator float();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_R8: {
- double val = p_value.operator double();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case MONO_TYPE_VALUETYPE: {
- GDMonoClass *tclass = type.type_class;
-
- if (tclass == CACHED_CLASS(Vector2)) {
- GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_value.operator ::Vector2());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Vector2i)) {
- GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_value.operator ::Vector2i());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Rect2)) {
- GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_value.operator ::Rect2());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Rect2i)) {
- GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_value.operator ::Rect2i());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Transform2D)) {
- GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_value.operator ::Transform2D());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Vector3)) {
- GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_value.operator ::Vector3());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Vector3i)) {
- GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_value.operator ::Vector3i());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Vector4)) {
- GDMonoMarshal::M_Vector4 from = MARSHALLED_OUT(Vector4, p_value.operator ::Vector4());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Vector4i)) {
- GDMonoMarshal::M_Vector4i from = MARSHALLED_OUT(Vector4i, p_value.operator ::Vector4i());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Basis)) {
- GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_value.operator ::Basis());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Quaternion)) {
- GDMonoMarshal::M_Quaternion from = MARSHALLED_OUT(Quaternion, p_value.operator ::Quaternion());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Transform3D)) {
- GDMonoMarshal::M_Transform3D from = MARSHALLED_OUT(Transform3D, p_value.operator ::Transform3D());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Projection)) {
- GDMonoMarshal::M_Projection from = MARSHALLED_OUT(Projection, p_value.operator ::Projection());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(AABB)) {
- GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_value.operator ::AABB());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Color)) {
- GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_value.operator ::Color());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Plane)) {
- GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_value.operator ::Plane());
- mono_field_set_value(p_object, mono_field, &from);
- break;
- }
-
- if (tclass == CACHED_CLASS(Callable)) {
- GDMonoMarshal::M_Callable val = GDMonoMarshal::callable_to_managed(p_value.operator Callable());
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
-
- if (tclass == CACHED_CLASS(SignalInfo)) {
- GDMonoMarshal::M_SignalInfo val = GDMonoMarshal::signal_info_to_managed(p_value.operator Signal());
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
-
- if (mono_class_is_enum(tclass->get_mono_ptr())) {
- MonoType *enum_basetype = mono_class_enum_basetype(tclass->get_mono_ptr());
- switch (mono_type_get_type(enum_basetype)) {
- case MONO_TYPE_BOOLEAN: {
- MonoBoolean val = p_value.operator bool();
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
- case MONO_TYPE_CHAR: {
- uint16_t val = p_value.operator unsigned short();
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
- case MONO_TYPE_I1: {
- int8_t val = p_value.operator signed char();
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
- case MONO_TYPE_I2: {
- int16_t val = p_value.operator signed short();
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
- case MONO_TYPE_I4: {
- int32_t val = p_value.operator signed int();
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
- case MONO_TYPE_I8: {
- int64_t val = p_value.operator int64_t();
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
- case MONO_TYPE_U1: {
- uint8_t val = p_value.operator unsigned char();
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
- case MONO_TYPE_U2: {
- uint16_t val = p_value.operator unsigned short();
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
- case MONO_TYPE_U4: {
- uint32_t val = p_value.operator unsigned int();
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
- case MONO_TYPE_U8: {
- uint64_t val = p_value.operator uint64_t();
- mono_field_set_value(p_object, mono_field, &val);
- break;
- }
- default: {
- ERR_FAIL_MSG("Attempted to convert Variant to a managed enum value of unmarshallable base type.");
- }
- }
-
- break;
- }
-
- ERR_FAIL_MSG("Attempted to set the value of a field of unmarshallable type: '" + tclass->get_name() + "'.");
- } break;
- case MONO_TYPE_STRING: {
- if (p_value.get_type() == Variant::NIL) {
- // Otherwise, Variant -> String would return the string "Null"
- MonoString *mono_string = nullptr;
- mono_field_set_value(p_object, mono_field, mono_string);
- } else {
- MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value);
- mono_field_set_value(p_object, mono_field, mono_string);
- }
- } break;
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY: {
- MonoArray *managed = GDMonoMarshal::variant_to_mono_array(p_value, type.type_class);
- if (likely(managed != nullptr)) {
- mono_field_set_value(p_object, mono_field, managed);
- }
- } break;
- case MONO_TYPE_CLASS: {
- MonoObject *managed = GDMonoMarshal::variant_to_mono_object_of_class(p_value, type.type_class);
- if (likely(managed != nullptr)) {
- mono_field_set_value(p_object, mono_field, managed);
- }
- } break;
- case MONO_TYPE_GENERICINST: {
- MonoObject *managed = GDMonoMarshal::variant_to_mono_object_of_genericinst(p_value, type.type_class);
- if (likely(managed != nullptr)) {
- mono_field_set_value(p_object, mono_field, managed);
- }
- } break;
- case MONO_TYPE_OBJECT: {
- // Variant
- switch (p_value.get_type()) {
- case Variant::BOOL: {
- MonoBoolean val = p_value.operator bool();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case Variant::INT: {
- int32_t val = p_value.operator signed int();
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case Variant::FLOAT: {
-#ifdef REAL_T_IS_DOUBLE
- double val = p_value.operator double();
- mono_field_set_value(p_object, mono_field, &val);
-#else
- float val = p_value.operator float();
- mono_field_set_value(p_object, mono_field, &val);
-#endif
- } break;
- case Variant::STRING: {
- MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value);
- mono_field_set_value(p_object, mono_field, mono_string);
- } break;
- case Variant::VECTOR2: {
- GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_value.operator ::Vector2());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::VECTOR2I: {
- GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_value.operator ::Vector2i());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::RECT2: {
- GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_value.operator ::Rect2());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::RECT2I: {
- GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_value.operator ::Rect2i());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::VECTOR3: {
- GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_value.operator ::Vector3());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::VECTOR3I: {
- GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_value.operator ::Vector3i());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::VECTOR4: {
- GDMonoMarshal::M_Vector4 from = MARSHALLED_OUT(Vector4, p_value.operator ::Vector4());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::VECTOR4I: {
- GDMonoMarshal::M_Vector4i from = MARSHALLED_OUT(Vector4i, p_value.operator ::Vector4i());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::TRANSFORM2D: {
- GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_value.operator ::Transform2D());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::PLANE: {
- GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_value.operator ::Plane());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::QUATERNION: {
- GDMonoMarshal::M_Quaternion from = MARSHALLED_OUT(Quaternion, p_value.operator ::Quaternion());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::AABB: {
- GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_value.operator ::AABB());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::BASIS: {
- GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_value.operator ::Basis());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::TRANSFORM3D: {
- GDMonoMarshal::M_Transform3D from = MARSHALLED_OUT(Transform3D, p_value.operator ::Transform3D());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::PROJECTION: {
- GDMonoMarshal::M_Projection from = MARSHALLED_OUT(Projection, p_value.operator ::Projection());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::COLOR: {
- GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_value.operator ::Color());
- mono_field_set_value(p_object, mono_field, &from);
- } break;
- case Variant::STRING_NAME: {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator StringName());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::NODE_PATH: {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator NodePath());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::RID: {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator ::RID());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::OBJECT: {
- MonoObject *managed = GDMonoUtils::unmanaged_get_managed(p_value.operator Object *());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::CALLABLE: {
- GDMonoMarshal::M_Callable val = GDMonoMarshal::callable_to_managed(p_value.operator Callable());
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case Variant::SIGNAL: {
- GDMonoMarshal::M_SignalInfo val = GDMonoMarshal::signal_info_to_managed(p_value.operator Signal());
- mono_field_set_value(p_object, mono_field, &val);
- } break;
- case Variant::DICTIONARY: {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Dictionary(), CACHED_CLASS(Dictionary));
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::ARRAY: {
- MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::PACKED_BYTE_ARRAY: {
- MonoArray *managed = GDMonoMarshal::PackedByteArray_to_mono_array(p_value.operator ::PackedByteArray());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::PACKED_INT32_ARRAY: {
- MonoArray *managed = GDMonoMarshal::PackedInt32Array_to_mono_array(p_value.operator ::PackedInt32Array());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::PACKED_INT64_ARRAY: {
- MonoArray *managed = GDMonoMarshal::PackedInt64Array_to_mono_array(p_value.operator ::PackedInt64Array());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::PACKED_FLOAT32_ARRAY: {
- MonoArray *managed = GDMonoMarshal::PackedFloat32Array_to_mono_array(p_value.operator ::PackedFloat32Array());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::PACKED_FLOAT64_ARRAY: {
- MonoArray *managed = GDMonoMarshal::PackedFloat64Array_to_mono_array(p_value.operator ::PackedFloat64Array());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::PACKED_STRING_ARRAY: {
- MonoArray *managed = GDMonoMarshal::PackedStringArray_to_mono_array(p_value.operator ::PackedStringArray());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::PACKED_VECTOR2_ARRAY: {
- MonoArray *managed = GDMonoMarshal::PackedVector2Array_to_mono_array(p_value.operator ::PackedVector2Array());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::PACKED_VECTOR3_ARRAY: {
- MonoArray *managed = GDMonoMarshal::PackedVector3Array_to_mono_array(p_value.operator ::PackedVector3Array());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- case Variant::PACKED_COLOR_ARRAY: {
- MonoArray *managed = GDMonoMarshal::PackedColorArray_to_mono_array(p_value.operator ::PackedColorArray());
- mono_field_set_value(p_object, mono_field, managed);
- } break;
- default:
- break;
- }
- } break;
- default: {
- ERR_PRINT("Attempted to set the value of a field of unexpected type encoding: " + itos(type.type_encoding) + ".");
- } break;
- }
-}
-
-MonoObject *GDMonoField::get_value(MonoObject *p_object) {
- return mono_field_get_value_object(mono_domain_get(), mono_field, p_object);
-}
-
-bool GDMonoField::get_bool_value(MonoObject *p_object) {
- return (bool)GDMonoMarshal::unbox<MonoBoolean>(get_value(p_object));
-}
-
-int GDMonoField::get_int_value(MonoObject *p_object) {
- return GDMonoMarshal::unbox<int32_t>(get_value(p_object));
-}
-
-String GDMonoField::get_string_value(MonoObject *p_object) {
- MonoObject *val = get_value(p_object);
- return GDMonoMarshal::mono_string_to_godot((MonoString *)val);
-}
-
-bool GDMonoField::has_attribute(GDMonoClass *p_attr_class) {
- ERR_FAIL_NULL_V(p_attr_class, false);
-
- if (!attrs_fetched) {
- fetch_attributes();
- }
-
- if (!attributes) {
- return false;
- }
-
- return mono_custom_attrs_has_attr(attributes, p_attr_class->get_mono_ptr());
-}
-
-MonoObject *GDMonoField::get_attribute(GDMonoClass *p_attr_class) {
- ERR_FAIL_NULL_V(p_attr_class, nullptr);
-
- if (!attrs_fetched) {
- fetch_attributes();
- }
-
- if (!attributes) {
- return nullptr;
- }
-
- return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr());
-}
-
-void GDMonoField::fetch_attributes() {
- ERR_FAIL_COND(attributes != nullptr);
- attributes = mono_custom_attrs_from_field(owner->get_mono_ptr(), mono_field);
- attrs_fetched = true;
-}
-
-bool GDMonoField::is_static() {
- return mono_field_get_flags(mono_field) & MONO_FIELD_ATTR_STATIC;
-}
-
-IMonoClassMember::Visibility GDMonoField::get_visibility() {
- switch (mono_field_get_flags(mono_field) & MONO_FIELD_ATTR_FIELD_ACCESS_MASK) {
- case MONO_FIELD_ATTR_PRIVATE:
- return IMonoClassMember::PRIVATE;
- case MONO_FIELD_ATTR_FAM_AND_ASSEM:
- return IMonoClassMember::PROTECTED_AND_INTERNAL;
- case MONO_FIELD_ATTR_ASSEMBLY:
- return IMonoClassMember::INTERNAL;
- case MONO_FIELD_ATTR_FAMILY:
- return IMonoClassMember::PROTECTED;
- case MONO_FIELD_ATTR_PUBLIC:
- return IMonoClassMember::PUBLIC;
- default:
- ERR_FAIL_V(IMonoClassMember::PRIVATE);
- }
-}
-
-GDMonoField::GDMonoField(MonoClassField *p_mono_field, GDMonoClass *p_owner) {
- owner = p_owner;
- mono_field = p_mono_field;
- name = String::utf8(mono_field_get_name(mono_field));
- MonoType *field_type = mono_field_get_type(mono_field);
- type.type_encoding = mono_type_get_type(field_type);
- MonoClass *field_type_class = mono_class_from_mono_type(field_type);
- type.type_class = GDMono::get_singleton()->get_class(field_type_class);
-
- attrs_fetched = false;
- attributes = nullptr;
-}
-
-GDMonoField::~GDMonoField() {
- if (attributes) {
- mono_custom_attrs_free(attributes);
- }
-}
diff --git a/modules/mono/mono_gd/gd_mono_field.h b/modules/mono/mono_gd/gd_mono_field.h
deleted file mode 100644
index 1d30f7a369..0000000000
--- a/modules/mono/mono_gd/gd_mono_field.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*************************************************************************/
-/* gd_mono_field.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GD_MONO_FIELD_H
-#define GD_MONO_FIELD_H
-
-#include "gd_mono.h"
-#include "gd_mono_header.h"
-#include "i_mono_class_member.h"
-
-class GDMonoField : public IMonoClassMember {
- GDMonoClass *owner = nullptr;
- MonoClassField *mono_field = nullptr;
-
- StringName name;
- ManagedType type;
-
- bool attrs_fetched;
- MonoCustomAttrInfo *attributes = nullptr;
-
-public:
- virtual GDMonoClass *get_enclosing_class() const final { return owner; }
-
- virtual MemberType get_member_type() const final { return MEMBER_TYPE_FIELD; }
-
- virtual StringName get_name() const final { return name; }
-
- virtual bool is_static() final;
- virtual Visibility get_visibility() final;
-
- virtual bool has_attribute(GDMonoClass *p_attr_class) final;
- virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) final;
- void fetch_attributes();
-
- _FORCE_INLINE_ ManagedType get_type() const { return type; }
-
- void set_value(MonoObject *p_object, MonoObject *p_value);
- void set_value_raw(MonoObject *p_object, void *p_ptr);
- void set_value_from_variant(MonoObject *p_object, const Variant &p_value);
-
- MonoObject *get_value(MonoObject *p_object);
-
- bool get_bool_value(MonoObject *p_object);
- int get_int_value(MonoObject *p_object);
- String get_string_value(MonoObject *p_object);
-
- GDMonoField(MonoClassField *p_mono_field, GDMonoClass *p_owner);
- ~GDMonoField();
-};
-
-#endif // GD_MONO_FIELD_H
diff --git a/modules/mono/mono_gd/gd_mono_header.h b/modules/mono/mono_gd/gd_mono_header.h
deleted file mode 100644
index bf21283080..0000000000
--- a/modules/mono/mono_gd/gd_mono_header.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*************************************************************************/
-/* gd_mono_header.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GD_MONO_HEADER_H
-#define GD_MONO_HEADER_H
-
-#include <cstdint>
-
-#ifdef WIN32
-#define GD_MONO_STDCALL __stdcall
-#else
-#define GD_MONO_STDCALL
-#endif
-
-class GDMonoAssembly;
-class GDMonoClass;
-class GDMonoField;
-class GDMonoMethod;
-class GDMonoProperty;
-
-class IMonoClassMember;
-
-#include "managed_type.h"
-
-#endif // GD_MONO_HEADER_H
diff --git a/modules/mono/mono_gd/gd_mono_internals.cpp b/modules/mono/mono_gd/gd_mono_internals.cpp
deleted file mode 100644
index d206b0dfc3..0000000000
--- a/modules/mono/mono_gd/gd_mono_internals.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-/*************************************************************************/
-/* gd_mono_internals.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "gd_mono_internals.h"
-
-#include "../csharp_script.h"
-#include "../mono_gc_handle.h"
-#include "../utils/macros.h"
-#include "gd_mono_class.h"
-#include "gd_mono_marshal.h"
-#include "gd_mono_utils.h"
-
-#include "core/debugger/engine_debugger.h"
-#include "core/debugger/script_debugger.h"
-
-#include <mono/metadata/exception.h>
-
-namespace GDMonoInternals {
-void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
- // This method should not fail
-
- CRASH_COND(!unmanaged);
-
- // All mono objects created from the managed world (e.g.: 'new Player()')
- // need to have a CSharpScript in order for their methods to be callable from the unmanaged side
-
- RefCounted *rc = Object::cast_to<RefCounted>(unmanaged);
-
- GDMonoClass *klass = GDMonoUtils::get_object_class(managed);
-
- CRASH_COND(!klass);
-
- GDMonoClass *native = GDMonoUtils::get_class_native_base(klass);
-
- CRASH_COND(native == nullptr);
-
- if (native == klass) {
- // If it's just a wrapper Godot class and not a custom inheriting class, then attach a
- // script binding instead. One of the advantages of this is that if a script is attached
- // later and it's not a C# script, then the managed object won't have to be disposed.
- // Another reason for doing this is that this instance could outlive CSharpLanguage, which would
- // be problematic when using a script. See: https://github.com/godotengine/godot/issues/25621
-
- CSharpScriptBinding script_binding;
-
- script_binding.inited = true;
- script_binding.type_name = NATIVE_GDMONOCLASS_NAME(klass);
- script_binding.wrapper_class = klass;
- script_binding.gchandle = rc ? MonoGCHandleData::new_weak_handle(managed) : MonoGCHandleData::new_strong_handle(managed);
- script_binding.owner = unmanaged;
-
- if (rc) {
- // Unsafe refcount increment. The managed instance also counts as a reference.
- // This way if the unmanaged world has no references to our owner
- // but the managed instance is alive, the refcount will be 1 instead of 0.
- // See: godot_icall_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr)
-
- // May not me referenced yet, so we must use init_ref() instead of reference()
- if (rc->init_ref()) {
- CSharpLanguage::get_singleton()->post_unsafe_reference(rc);
- }
- }
-
- // The object was just created, no script instance binding should have been attached
- CRASH_COND(CSharpLanguage::has_instance_binding(unmanaged));
-
- void *data;
- {
- MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex());
- data = (void *)CSharpLanguage::get_singleton()->insert_script_binding(unmanaged, script_binding);
- }
-
- // Should be thread safe because the object was just created and nothing else should be referencing it
- CSharpLanguage::set_instance_binding(unmanaged, data);
-
- return;
- }
-
- MonoGCHandleData gchandle = rc ? MonoGCHandleData::new_weak_handle(managed) : MonoGCHandleData::new_strong_handle(managed);
-
- Ref<CSharpScript> script = CSharpScript::create_for_managed_type(klass, native);
-
- CRASH_COND(script.is_null());
-
- CSharpInstance *csharp_instance = CSharpInstance::create_for_managed_type(unmanaged, script.ptr(), gchandle);
-
- unmanaged->set_script_and_instance(script, csharp_instance);
-}
-
-void unhandled_exception(MonoException *p_exc) {
- mono_print_unhandled_exception((MonoObject *)p_exc);
- gd_unhandled_exception_event(p_exc);
-
- if (GDMono::get_singleton()->get_unhandled_exception_policy() == GDMono::POLICY_TERMINATE_APP) {
- // Too bad 'mono_invoke_unhandled_exception_hook' is not exposed to embedders
- mono_unhandled_exception((MonoObject *)p_exc);
- GDMono::unhandled_exception_hook((MonoObject *)p_exc, nullptr);
- GD_UNREACHABLE();
- } else {
-#ifdef DEBUG_ENABLED
- GDMonoUtils::debug_send_unhandled_exception_error(p_exc);
- if (EngineDebugger::is_active()) {
- EngineDebugger::get_singleton()->poll_events(false);
- }
-#endif
- }
-}
-
-void gd_unhandled_exception_event(MonoException *p_exc) {
- MonoImage *mono_image = GDMono::get_singleton()->get_core_api_assembly()->get_image();
-
- MonoClass *gd_klass = mono_class_from_name(mono_image, "Godot", "GD");
- MonoMethod *unhandled_exception_method = mono_class_get_method_from_name(gd_klass, "OnUnhandledException", -1);
- void *args[1];
- args[0] = p_exc;
- mono_runtime_invoke(unhandled_exception_method, nullptr, (void **)args, nullptr);
-}
-} // namespace GDMonoInternals
diff --git a/modules/mono/mono_gd/gd_mono_internals.h b/modules/mono/mono_gd/gd_mono_internals.h
deleted file mode 100644
index a8f9cfa3ca..0000000000
--- a/modules/mono/mono_gd/gd_mono_internals.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*************************************************************************/
-/* gd_mono_internals.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GD_MONO_INTERNALS_H
-#define GD_MONO_INTERNALS_H
-
-#include <mono/jit/jit.h>
-
-#include "../utils/macros.h"
-
-#include "core/object/class_db.h"
-
-namespace GDMonoInternals {
-void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged);
-
-/**
- * Do not call this function directly.
- * Use GDMonoUtils::debug_unhandled_exception(MonoException *) instead.
- */
-void unhandled_exception(MonoException *p_exc);
-
-void gd_unhandled_exception_event(MonoException *p_exc);
-} // namespace GDMonoInternals
-
-#endif // GD_MONO_INTERNALS_H
diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp
deleted file mode 100644
index 6ea3c5539e..0000000000
--- a/modules/mono/mono_gd/gd_mono_log.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
-/*************************************************************************/
-/* gd_mono_log.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "gd_mono_log.h"
-
-#include <stdlib.h> // abort
-
-#include "core/io/dir_access.h"
-#include "core/os/os.h"
-
-#include "../godotsharp_dirs.h"
-#include "../utils/string_utils.h"
-
-static CharString get_default_log_level() {
-#ifdef DEBUG_ENABLED
- return String("info").utf8();
-#else
- return String("warning").utf8();
-#endif
-}
-
-GDMonoLog *GDMonoLog::singleton = nullptr;
-
-#ifdef GD_MONO_LOG_ENABLED
-
-static int get_log_level_id(const char *p_log_level) {
- const char *valid_log_levels[] = { "error", "critical", "warning", "message", "info", "debug", nullptr };
-
- int i = 0;
- while (valid_log_levels[i]) {
- if (!strcmp(valid_log_levels[i], p_log_level)) {
- return i;
- }
- i++;
- }
-
- return -1;
-}
-
-static String make_text(const char *log_domain, const char *log_level, const char *message) {
- String text(message);
- text += " (in domain ";
- text += log_domain;
- if (log_level) {
- text += ", ";
- text += log_level;
- }
- text += ")";
- return text;
-}
-
-void GDMonoLog::mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *) {
- if (GDMonoLog::get_singleton()->log_level_id >= get_log_level_id(log_level)) {
- String text = make_text(log_domain, log_level, message);
- text += "\n";
-
- GDMonoLog::get_singleton()->log_file->seek_end();
- GDMonoLog::get_singleton()->log_file->store_string(text);
- }
-
- if (fatal) {
- String text = make_text(log_domain, log_level, message);
- ERR_PRINT("Mono: FATAL ERROR '" + text + "', ABORTING! Logfile: '" + GDMonoLog::get_singleton()->log_file_path + "'.");
- // Make sure to flush before aborting
- GDMonoLog::get_singleton()->log_file->flush();
- GDMonoLog::get_singleton()->log_file.unref();
-
- abort();
- }
-}
-
-bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) {
- if (!DirAccess::exists(p_logs_dir)) {
- Ref<DirAccess> diraccess = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND_V(diraccess.is_null(), false);
- Error logs_mkdir_err = diraccess->make_dir_recursive(p_logs_dir);
- ERR_FAIL_COND_V_MSG(logs_mkdir_err != OK, false, "Failed to create mono logs directory.");
- }
-
- return true;
-}
-
-void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) {
- static const uint64_t MAX_SECS = 5 * 86400; // 5 days
-
- Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND(da.is_null());
-
- Error err = da->change_dir(p_logs_dir);
- ERR_FAIL_COND_MSG(err != OK, "Cannot change directory to '" + p_logs_dir + "'.");
-
- ERR_FAIL_COND(da->list_dir_begin() != OK);
-
- String current = da->get_next();
- while (!current.is_empty()) {
- if (da->current_is_dir() || !current.ends_with(".txt")) {
- current = da->get_next();
- continue;
- }
-
- uint64_t modified_time = FileAccess::get_modified_time(da->get_current_dir().plus_file(current));
-
- if (OS::get_singleton()->get_unix_time() - modified_time > MAX_SECS) {
- da->remove(current);
- }
- current = da->get_next();
- }
-
- da->list_dir_end();
-}
-
-void GDMonoLog::initialize() {
- CharString log_level = OS::get_singleton()->get_environment("GODOT_MONO_LOG_LEVEL").utf8();
-
- if (log_level.length() != 0 && get_log_level_id(log_level.get_data()) == -1) {
- ERR_PRINT(String() + "Mono: Ignoring invalid log level (GODOT_MONO_LOG_LEVEL): '" + log_level.get_data() + "'.");
- log_level = CharString();
- }
-
- if (log_level.length() == 0) {
- log_level = get_default_log_level();
- }
-
- String logs_dir = GodotSharpDirs::get_mono_logs_dir();
-
- if (_try_create_logs_dir(logs_dir)) {
- _delete_old_log_files(logs_dir);
-
- OS::Date date_now = OS::get_singleton()->get_date();
- OS::Time time_now = OS::get_singleton()->get_time();
-
- String log_file_name = str_format("%04d-%02d-%02d_%02d.%02d.%02d",
- (int)date_now.year, (int)date_now.month, (int)date_now.day,
- (int)time_now.hour, (int)time_now.minute, (int)time_now.second);
-
- log_file_name += str_format("_%d", OS::get_singleton()->get_process_id());
-
- log_file_name += ".log";
-
- log_file_path = logs_dir.plus_file(log_file_name);
-
- log_file = FileAccess::open(log_file_path, FileAccess::WRITE);
- if (log_file.is_null()) {
- ERR_PRINT("Mono: Cannot create log file at: " + log_file_path);
- }
- }
-
- mono_trace_set_level_string(log_level.get_data());
- log_level_id = get_log_level_id(log_level.get_data());
-
- if (log_file.is_valid()) {
- OS::get_singleton()->print("Mono: Log file is: '%s'\n", log_file_path.utf8().get_data());
- mono_trace_set_log_handler(mono_log_callback, this);
- } else {
- OS::get_singleton()->printerr("Mono: No log file, using default log handler\n");
- }
-}
-
-GDMonoLog::GDMonoLog() {
- singleton = this;
-}
-
-GDMonoLog::~GDMonoLog() {
- singleton = nullptr;
-}
-
-#else
-
-void GDMonoLog::initialize() {
- CharString log_level = get_default_log_level();
- mono_trace_set_level_string(log_level.get_data());
-}
-
-GDMonoLog::GDMonoLog() {
- singleton = this;
-}
-
-GDMonoLog::~GDMonoLog() {
- singleton = nullptr;
-}
-
-#endif // !defined(JAVASCRIPT_ENABLED)
diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h
deleted file mode 100644
index 93ba6a410e..0000000000
--- a/modules/mono/mono_gd/gd_mono_log.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*************************************************************************/
-/* gd_mono_log.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GD_MONO_LOG_H
-#define GD_MONO_LOG_H
-
-#include <mono/utils/mono-logger.h>
-
-#include "core/typedefs.h"
-
-#if !defined(JAVASCRIPT_ENABLED) && !defined(IOS_ENABLED)
-// We have custom mono log callbacks for WASM and iOS
-#define GD_MONO_LOG_ENABLED
-#endif
-
-#ifdef GD_MONO_LOG_ENABLED
-#include "core/io/file_access.h"
-#endif
-
-class GDMonoLog {
-#ifdef GD_MONO_LOG_ENABLED
- int log_level_id = -1;
-
- Ref<FileAccess> log_file;
- String log_file_path;
-
- bool _try_create_logs_dir(const String &p_logs_dir);
- void _delete_old_log_files(const String &p_logs_dir);
-
- static void mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data);
-#endif
-
- static GDMonoLog *singleton;
-
-public:
- _FORCE_INLINE_ static GDMonoLog *get_singleton() { return singleton; }
-
- void initialize();
-
- GDMonoLog();
- ~GDMonoLog();
-};
-
-#endif // GD_MONO_LOG_H
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
deleted file mode 100644
index a860442764..0000000000
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ /dev/null
@@ -1,1824 +0,0 @@
-/*************************************************************************/
-/* gd_mono_marshal.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "gd_mono_marshal.h"
-
-#include "../signal_awaiter_utils.h"
-#include "gd_mono.h"
-#include "gd_mono_cache.h"
-#include "gd_mono_class.h"
-
-namespace GDMonoMarshal {
-
-Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_variant) {
- switch (p_type.type_encoding) {
- case MONO_TYPE_BOOLEAN:
- return Variant::BOOL;
-
- case MONO_TYPE_I1:
- return Variant::INT;
- case MONO_TYPE_I2:
- return Variant::INT;
- case MONO_TYPE_I4:
- return Variant::INT;
- case MONO_TYPE_I8:
- return Variant::INT;
-
- case MONO_TYPE_U1:
- return Variant::INT;
- case MONO_TYPE_U2:
- return Variant::INT;
- case MONO_TYPE_U4:
- return Variant::INT;
- case MONO_TYPE_U8:
- return Variant::INT;
-
- case MONO_TYPE_R4:
- return Variant::FLOAT;
- case MONO_TYPE_R8:
- return Variant::FLOAT;
-
- case MONO_TYPE_STRING: {
- return Variant::STRING;
- } break;
-
- case MONO_TYPE_VALUETYPE: {
- GDMonoClass *vtclass = p_type.type_class;
-
- if (vtclass == CACHED_CLASS(Vector2)) {
- return Variant::VECTOR2;
- }
-
- if (vtclass == CACHED_CLASS(Vector2i)) {
- return Variant::VECTOR2I;
- }
-
- if (vtclass == CACHED_CLASS(Rect2)) {
- return Variant::RECT2;
- }
-
- if (vtclass == CACHED_CLASS(Rect2i)) {
- return Variant::RECT2I;
- }
-
- if (vtclass == CACHED_CLASS(Transform2D)) {
- return Variant::TRANSFORM2D;
- }
-
- if (vtclass == CACHED_CLASS(Vector3)) {
- return Variant::VECTOR3;
- }
-
- if (vtclass == CACHED_CLASS(Vector3i)) {
- return Variant::VECTOR3I;
- }
- if (vtclass == CACHED_CLASS(Vector4)) {
- return Variant::VECTOR4;
- }
-
- if (vtclass == CACHED_CLASS(Vector4i)) {
- return Variant::VECTOR4I;
- }
-
- if (vtclass == CACHED_CLASS(Basis)) {
- return Variant::BASIS;
- }
-
- if (vtclass == CACHED_CLASS(Quaternion)) {
- return Variant::QUATERNION;
- }
-
- if (vtclass == CACHED_CLASS(Transform3D)) {
- return Variant::TRANSFORM3D;
- }
- if (vtclass == CACHED_CLASS(Projection)) {
- return Variant::PROJECTION;
- }
- if (vtclass == CACHED_CLASS(AABB)) {
- return Variant::AABB;
- }
-
- if (vtclass == CACHED_CLASS(Color)) {
- return Variant::COLOR;
- }
-
- if (vtclass == CACHED_CLASS(Plane)) {
- return Variant::PLANE;
- }
-
- if (vtclass == CACHED_CLASS(Callable)) {
- return Variant::CALLABLE;
- }
-
- if (vtclass == CACHED_CLASS(SignalInfo)) {
- return Variant::SIGNAL;
- }
-
- if (mono_class_is_enum(vtclass->get_mono_ptr())) {
- return Variant::INT;
- }
- } break;
-
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY: {
- MonoClass *elem_class = mono_class_get_element_class(p_type.type_class->get_mono_ptr());
-
- if (elem_class == CACHED_CLASS_RAW(MonoObject)) {
- return Variant::ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(uint8_t)) {
- return Variant::PACKED_BYTE_ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(int32_t)) {
- return Variant::PACKED_INT32_ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(int64_t)) {
- return Variant::PACKED_INT64_ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(float)) {
- return Variant::PACKED_FLOAT32_ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(double)) {
- return Variant::PACKED_FLOAT64_ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(String)) {
- return Variant::PACKED_STRING_ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(Vector2)) {
- return Variant::PACKED_VECTOR2_ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(Vector3)) {
- return Variant::PACKED_VECTOR3_ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(Color)) {
- return Variant::PACKED_COLOR_ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(StringName)) {
- return Variant::ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(NodePath)) {
- return Variant::ARRAY;
- }
-
- if (elem_class == CACHED_CLASS_RAW(RID)) {
- return Variant::ARRAY;
- }
-
- if (mono_class_is_enum(elem_class)) {
- return Variant::ARRAY;
- }
-
- GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(elem_class);
- if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) {
- return Variant::ARRAY;
- }
- } break;
-
- case MONO_TYPE_CLASS: {
- GDMonoClass *type_class = p_type.type_class;
-
- // GodotObject
- if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
- return Variant::OBJECT;
- }
-
- if (CACHED_CLASS(StringName) == type_class) {
- return Variant::STRING_NAME;
- }
-
- if (CACHED_CLASS(NodePath) == type_class) {
- return Variant::NODE_PATH;
- }
-
- if (CACHED_CLASS(RID) == type_class) {
- return Variant::RID;
- }
-
- if (CACHED_CLASS(Dictionary) == type_class) {
- return Variant::DICTIONARY;
- }
-
- if (CACHED_CLASS(Array) == type_class) {
- return Variant::ARRAY;
- }
-
- // IDictionary
- if (p_type.type_class == CACHED_CLASS(System_Collections_IDictionary)) {
- return Variant::DICTIONARY;
- }
-
- // ICollection or IEnumerable
- if (p_type.type_class == CACHED_CLASS(System_Collections_ICollection) ||
- p_type.type_class == CACHED_CLASS(System_Collections_IEnumerable)) {
- return Variant::ARRAY;
- }
- } break;
-
- case MONO_TYPE_OBJECT: {
- if (r_nil_is_variant) {
- *r_nil_is_variant = true;
- }
- return Variant::NIL;
- } break;
-
- case MONO_TYPE_GENERICINST: {
- MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
-
- // Godot.Collections.Dictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
- return Variant::DICTIONARY;
- }
-
- // Godot.Collections.Array<T>
- if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
- return Variant::ARRAY;
- }
-
- // System.Collections.Generic.Dictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) {
- return Variant::DICTIONARY;
- }
-
- // System.Collections.Generic.List<T>
- if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) {
- return Variant::ARRAY;
- }
-
- // IDictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) {
- return Variant::DICTIONARY;
- }
-
- // ICollection<T> or IEnumerable<T>
- if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) {
- return Variant::ARRAY;
- }
-
- // GodotObject
- GDMonoClass *type_class = p_type.type_class;
- if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
- return Variant::OBJECT;
- }
- } break;
-
- default: {
- } break;
- }
-
- if (r_nil_is_variant) {
- *r_nil_is_variant = false;
- }
-
- // Unknown
- return Variant::NIL;
-}
-
-bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_elem_type) {
- switch (p_array_type.type_encoding) {
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY: {
- MonoClass *elem_class = mono_class_get_element_class(p_array_type.type_class->get_mono_ptr());
- r_elem_type = ManagedType::from_class(elem_class);
- return true;
- } break;
- case MONO_TYPE_GENERICINST: {
- MonoReflectionType *array_reftype = mono_type_get_object(mono_domain_get(), p_array_type.type_class->get_mono_type());
-
- if (GDMonoUtils::Marshal::type_is_generic_array(array_reftype) ||
- GDMonoUtils::Marshal::type_is_system_generic_list(array_reftype) ||
- GDMonoUtils::Marshal::type_is_generic_icollection(array_reftype) ||
- GDMonoUtils::Marshal::type_is_generic_ienumerable(array_reftype)) {
- MonoReflectionType *elem_reftype;
-
- GDMonoUtils::Marshal::array_get_element_type(array_reftype, &elem_reftype);
-
- r_elem_type = ManagedType::from_reftype(elem_reftype);
- return true;
- }
- } break;
- default: {
- } break;
- }
-
- return false;
-}
-
-MonoString *variant_to_mono_string(const Variant &p_var) {
- if (p_var.get_type() == Variant::NIL) {
- return nullptr; // Otherwise, Variant -> String would return the string "Null"
- }
- return mono_string_from_godot(p_var.operator String());
-}
-
-MonoArray *variant_to_mono_array(const Variant &p_var, GDMonoClass *p_type_class) {
- MonoArrayType *array_type = mono_type_get_array_type(p_type_class->get_mono_type());
-
- if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) {
- return Array_to_mono_array(p_var.operator Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) {
- return PackedByteArray_to_mono_array(p_var.operator PackedByteArray());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) {
- return PackedInt32Array_to_mono_array(p_var.operator PackedInt32Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(int64_t)) {
- return PackedInt64Array_to_mono_array(p_var.operator PackedInt64Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(float)) {
- return PackedFloat32Array_to_mono_array(p_var.operator PackedFloat32Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(double)) {
- return PackedFloat64Array_to_mono_array(p_var.operator PackedFloat64Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(String)) {
- return PackedStringArray_to_mono_array(p_var.operator PackedStringArray());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) {
- return PackedVector2Array_to_mono_array(p_var.operator PackedVector2Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) {
- return PackedVector3Array_to_mono_array(p_var.operator PackedVector3Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Color)) {
- return PackedColorArray_to_mono_array(p_var.operator PackedColorArray());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(StringName)) {
- return Array_to_mono_array(p_var.operator Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(NodePath)) {
- return Array_to_mono_array(p_var.operator Array());
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(RID)) {
- return Array_to_mono_array(p_var.operator Array());
- }
-
- if (mono_class_is_assignable_from(CACHED_CLASS(GodotObject)->get_mono_ptr(), array_type->eklass)) {
- return Array_to_mono_array(p_var.operator ::Array(), array_type->eklass);
- }
-
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to array of unsupported element type:" + GDMonoClass::get_full_name(array_type->eklass) + "'.");
-}
-
-MonoObject *variant_to_mono_object_of_class(const Variant &p_var, GDMonoClass *p_type_class) {
- // GodotObject
- if (CACHED_CLASS(GodotObject)->is_assignable_from(p_type_class)) {
- return GDMonoUtils::unmanaged_get_managed(p_var.operator Object *());
- }
-
- if (CACHED_CLASS(StringName) == p_type_class) {
- return GDMonoUtils::create_managed_from(p_var.operator StringName());
- }
-
- if (CACHED_CLASS(NodePath) == p_type_class) {
- return GDMonoUtils::create_managed_from(p_var.operator NodePath());
- }
-
- if (CACHED_CLASS(RID) == p_type_class) {
- return GDMonoUtils::create_managed_from(p_var.operator ::RID());
- }
-
- // Godot.Collections.Dictionary or IDictionary
- if (CACHED_CLASS(Dictionary) == p_type_class || CACHED_CLASS(System_Collections_IDictionary) == p_type_class) {
- return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), CACHED_CLASS(Dictionary));
- }
-
- // Godot.Collections.Array or ICollection or IEnumerable
- if (CACHED_CLASS(Array) == p_type_class ||
- CACHED_CLASS(System_Collections_ICollection) == p_type_class ||
- CACHED_CLASS(System_Collections_IEnumerable) == p_type_class) {
- return GDMonoUtils::create_managed_from(p_var.operator Array(), CACHED_CLASS(Array));
- }
-
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type: '" + p_type_class->get_full_name() + "'.");
-}
-
-MonoObject *variant_to_mono_object_of_genericinst(const Variant &p_var, GDMonoClass *p_type_class) {
- MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type_class->get_mono_type());
-
- // Godot.Collections.Dictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
- return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), p_type_class);
- }
-
- // Godot.Collections.Array<T>
- if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
- return GDMonoUtils::create_managed_from(p_var.operator Array(), p_type_class);
- }
-
- // System.Collections.Generic.Dictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) {
- MonoReflectionType *key_reftype = nullptr;
- MonoReflectionType *value_reftype = nullptr;
- GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
- return Dictionary_to_system_generic_dict(p_var.operator Dictionary(), p_type_class, key_reftype, value_reftype);
- }
-
- // System.Collections.Generic.List<T>
- if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) {
- MonoReflectionType *elem_reftype = nullptr;
- GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
- return Array_to_system_generic_list(p_var.operator Array(), p_type_class, elem_reftype);
- }
-
- // IDictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_generic_idictionary(reftype)) {
- MonoReflectionType *key_reftype;
- MonoReflectionType *value_reftype;
- GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
- GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(key_reftype, value_reftype);
-
- return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), godot_dict_class);
- }
-
- // ICollection<T> or IEnumerable<T>
- if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) {
- MonoReflectionType *elem_reftype;
- GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
- GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(elem_reftype);
-
- return GDMonoUtils::create_managed_from(p_var.operator Array(), godot_array_class);
- }
-
- // GodotObject
- if (CACHED_CLASS(GodotObject)->is_assignable_from(p_type_class)) {
- return GDMonoUtils::unmanaged_get_managed(p_var.operator Object *());
- }
-
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported generic type: '" + p_type_class->get_full_name() + "'.");
-}
-
-MonoObject *variant_to_mono_object(const Variant &p_var) {
- // Variant
- switch (p_var.get_type()) {
- case Variant::BOOL: {
- MonoBoolean val = p_var.operator bool();
- return BOX_BOOLEAN(val);
- }
- case Variant::INT: {
- int64_t val = p_var.operator int64_t();
- return BOX_INT64(val);
- }
- case Variant::FLOAT: {
-#ifdef REAL_T_IS_DOUBLE
- double val = p_var.operator double();
- return BOX_DOUBLE(val);
-#else
- float val = p_var.operator float();
- return BOX_FLOAT(val);
-#endif
- }
- case Variant::STRING:
- return (MonoObject *)mono_string_from_godot(p_var.operator String());
- case Variant::VECTOR2: {
- GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var.operator ::Vector2());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from);
- }
- case Variant::VECTOR2I: {
- GDMonoMarshal::M_Vector2i from = MARSHALLED_OUT(Vector2i, p_var.operator ::Vector2i());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2i), &from);
- }
- case Variant::RECT2: {
- GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var.operator ::Rect2());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from);
- }
- case Variant::RECT2I: {
- GDMonoMarshal::M_Rect2i from = MARSHALLED_OUT(Rect2i, p_var.operator ::Rect2i());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2i), &from);
- }
- case Variant::VECTOR3: {
- GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var.operator ::Vector3());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from);
- }
- case Variant::VECTOR3I: {
- GDMonoMarshal::M_Vector3i from = MARSHALLED_OUT(Vector3i, p_var.operator ::Vector3i());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3i), &from);
- }
- case Variant::TRANSFORM2D: {
- GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var.operator ::Transform2D());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from);
- }
- case Variant::VECTOR4: {
- GDMonoMarshal::M_Vector4 from = MARSHALLED_OUT(Vector4, p_var.operator ::Vector4());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector4), &from);
- }
- case Variant::VECTOR4I: {
- GDMonoMarshal::M_Vector4i from = MARSHALLED_OUT(Vector4i, p_var.operator ::Vector4i());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector4i), &from);
- }
- case Variant::PLANE: {
- GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var.operator ::Plane());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from);
- }
- case Variant::QUATERNION: {
- GDMonoMarshal::M_Quaternion from = MARSHALLED_OUT(Quaternion, p_var.operator ::Quaternion());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quaternion), &from);
- }
- case Variant::AABB: {
- GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var.operator ::AABB());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from);
- }
- case Variant::BASIS: {
- GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var.operator ::Basis());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from);
- }
- case Variant::TRANSFORM3D: {
- GDMonoMarshal::M_Transform3D from = MARSHALLED_OUT(Transform3D, p_var.operator ::Transform3D());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform3D), &from);
- }
- case Variant::PROJECTION: {
- GDMonoMarshal::M_Projection from = MARSHALLED_OUT(Projection, p_var.operator ::Projection());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Projection), &from);
- }
- case Variant::COLOR: {
- GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var.operator ::Color());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from);
- }
- case Variant::STRING_NAME:
- return GDMonoUtils::create_managed_from(p_var.operator StringName());
- case Variant::NODE_PATH:
- return GDMonoUtils::create_managed_from(p_var.operator NodePath());
- case Variant::RID:
- return GDMonoUtils::create_managed_from(p_var.operator ::RID());
- case Variant::OBJECT:
- return GDMonoUtils::unmanaged_get_managed(p_var.operator Object *());
- case Variant::CALLABLE: {
- GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var.operator Callable());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Callable), &from);
- }
- case Variant::SIGNAL: {
- GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var.operator Signal());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(SignalInfo), &from);
- }
- case Variant::DICTIONARY:
- return GDMonoUtils::create_managed_from(p_var.operator Dictionary(), CACHED_CLASS(Dictionary));
- case Variant::ARRAY:
- return GDMonoUtils::create_managed_from(p_var.operator Array(), CACHED_CLASS(Array));
- case Variant::PACKED_BYTE_ARRAY:
- return (MonoObject *)PackedByteArray_to_mono_array(p_var.operator PackedByteArray());
- case Variant::PACKED_INT32_ARRAY:
- return (MonoObject *)PackedInt32Array_to_mono_array(p_var.operator PackedInt32Array());
- case Variant::PACKED_INT64_ARRAY:
- return (MonoObject *)PackedInt64Array_to_mono_array(p_var.operator PackedInt64Array());
- case Variant::PACKED_FLOAT32_ARRAY:
- return (MonoObject *)PackedFloat32Array_to_mono_array(p_var.operator PackedFloat32Array());
- case Variant::PACKED_FLOAT64_ARRAY:
- return (MonoObject *)PackedFloat64Array_to_mono_array(p_var.operator PackedFloat64Array());
- case Variant::PACKED_STRING_ARRAY:
- return (MonoObject *)PackedStringArray_to_mono_array(p_var.operator PackedStringArray());
- case Variant::PACKED_VECTOR2_ARRAY:
- return (MonoObject *)PackedVector2Array_to_mono_array(p_var.operator PackedVector2Array());
- case Variant::PACKED_VECTOR3_ARRAY:
- return (MonoObject *)PackedVector3Array_to_mono_array(p_var.operator PackedVector3Array());
- case Variant::PACKED_COLOR_ARRAY:
- return (MonoObject *)PackedColorArray_to_mono_array(p_var.operator PackedColorArray());
- default:
- return nullptr;
- }
-}
-
-size_t variant_get_managed_unboxed_size(const ManagedType &p_type) {
- // This method prints no errors for unsupported types. It's called on all methods, not only
- // those that end up being invoked with Variant parameters.
-
- // For MonoObject* we return 0, as it doesn't need to be stored.
- constexpr size_t zero_for_mono_object = 0;
-
- switch (p_type.type_encoding) {
- case MONO_TYPE_BOOLEAN:
- return sizeof(MonoBoolean);
- case MONO_TYPE_CHAR:
- return sizeof(uint16_t);
- case MONO_TYPE_I1:
- return sizeof(int8_t);
- case MONO_TYPE_I2:
- return sizeof(int16_t);
- case MONO_TYPE_I4:
- return sizeof(int32_t);
- case MONO_TYPE_I8:
- return sizeof(int64_t);
- case MONO_TYPE_U1:
- return sizeof(uint8_t);
- case MONO_TYPE_U2:
- return sizeof(uint16_t);
- case MONO_TYPE_U4:
- return sizeof(uint32_t);
- case MONO_TYPE_U8:
- return sizeof(uint64_t);
- case MONO_TYPE_R4:
- return sizeof(float);
- case MONO_TYPE_R8:
- return sizeof(double);
- case MONO_TYPE_VALUETYPE: {
- GDMonoClass *vtclass = p_type.type_class;
-
-#define RETURN_CHECK_FOR_STRUCT(m_struct) \
- if (vtclass == CACHED_CLASS(m_struct)) { \
- return sizeof(M_##m_struct); \
- }
-
- RETURN_CHECK_FOR_STRUCT(Vector2);
- RETURN_CHECK_FOR_STRUCT(Vector2i);
- RETURN_CHECK_FOR_STRUCT(Rect2);
- RETURN_CHECK_FOR_STRUCT(Rect2i);
- RETURN_CHECK_FOR_STRUCT(Transform2D);
- RETURN_CHECK_FOR_STRUCT(Vector3);
- RETURN_CHECK_FOR_STRUCT(Vector3i);
- RETURN_CHECK_FOR_STRUCT(Basis);
- RETURN_CHECK_FOR_STRUCT(Quaternion);
- RETURN_CHECK_FOR_STRUCT(Transform3D);
- RETURN_CHECK_FOR_STRUCT(AABB);
- RETURN_CHECK_FOR_STRUCT(Color);
- RETURN_CHECK_FOR_STRUCT(Plane);
- RETURN_CHECK_FOR_STRUCT(Callable);
- RETURN_CHECK_FOR_STRUCT(SignalInfo);
-
-#undef RETURN_CHECK_FOR_STRUCT
-
- if (mono_class_is_enum(vtclass->get_mono_ptr())) {
- MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr());
- switch (mono_type_get_type(enum_basetype)) {
- case MONO_TYPE_BOOLEAN:
- return sizeof(MonoBoolean);
- case MONO_TYPE_CHAR:
- return sizeof(uint16_t);
- case MONO_TYPE_I1:
- return sizeof(int8_t);
- case MONO_TYPE_I2:
- return sizeof(int16_t);
- case MONO_TYPE_I4:
- return sizeof(int32_t);
- case MONO_TYPE_I8:
- return sizeof(int64_t);
- case MONO_TYPE_U1:
- return sizeof(uint8_t);
- case MONO_TYPE_U2:
- return sizeof(uint16_t);
- case MONO_TYPE_U4:
- return sizeof(uint32_t);
- case MONO_TYPE_U8:
- return sizeof(uint64_t);
- default: {
- // Enum with unsupported base type. We return nullptr MonoObject* on error.
- return zero_for_mono_object;
- }
- }
- }
-
- // Enum with unsupported value type. We return nullptr MonoObject* on error.
- } break;
- case MONO_TYPE_STRING:
- return zero_for_mono_object;
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY:
- case MONO_TYPE_CLASS:
- case MONO_TYPE_GENERICINST:
- return zero_for_mono_object;
- case MONO_TYPE_OBJECT:
- return zero_for_mono_object;
- }
-
- // Unsupported type encoding. We return nullptr MonoObject* on error.
- return zero_for_mono_object;
-}
-
-void *variant_to_managed_unboxed(const Variant &p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset) {
-#define RETURN_TYPE_VAL(m_type, m_val) \
- *reinterpret_cast<m_type *>(r_buffer) = m_val; \
- r_offset += sizeof(m_type); \
- return r_buffer;
-
- switch (p_type.type_encoding) {
- case MONO_TYPE_BOOLEAN:
- RETURN_TYPE_VAL(MonoBoolean, (MonoBoolean)p_var.operator bool());
- case MONO_TYPE_CHAR:
- RETURN_TYPE_VAL(uint16_t, p_var.operator unsigned short());
- case MONO_TYPE_I1:
- RETURN_TYPE_VAL(int8_t, p_var.operator signed char());
- case MONO_TYPE_I2:
- RETURN_TYPE_VAL(int16_t, p_var.operator signed short());
- case MONO_TYPE_I4:
- RETURN_TYPE_VAL(int32_t, p_var.operator signed int());
- case MONO_TYPE_I8:
- RETURN_TYPE_VAL(int64_t, p_var.operator int64_t());
- case MONO_TYPE_U1:
- RETURN_TYPE_VAL(uint8_t, p_var.operator unsigned char());
- case MONO_TYPE_U2:
- RETURN_TYPE_VAL(uint16_t, p_var.operator unsigned short());
- case MONO_TYPE_U4:
- RETURN_TYPE_VAL(uint32_t, p_var.operator unsigned int());
- case MONO_TYPE_U8:
- RETURN_TYPE_VAL(uint64_t, p_var.operator uint64_t());
- case MONO_TYPE_R4:
- RETURN_TYPE_VAL(float, p_var.operator float());
- case MONO_TYPE_R8:
- RETURN_TYPE_VAL(double, p_var.operator double());
- case MONO_TYPE_VALUETYPE: {
- GDMonoClass *vtclass = p_type.type_class;
-
-#define RETURN_CHECK_FOR_STRUCT(m_struct) \
- if (vtclass == CACHED_CLASS(m_struct)) { \
- GDMonoMarshal::M_##m_struct from = MARSHALLED_OUT(m_struct, p_var.operator ::m_struct()); \
- RETURN_TYPE_VAL(M_##m_struct, from); \
- }
-
- RETURN_CHECK_FOR_STRUCT(Vector2);
- RETURN_CHECK_FOR_STRUCT(Vector2i);
- RETURN_CHECK_FOR_STRUCT(Rect2);
- RETURN_CHECK_FOR_STRUCT(Rect2i);
- RETURN_CHECK_FOR_STRUCT(Transform2D);
- RETURN_CHECK_FOR_STRUCT(Vector3);
- RETURN_CHECK_FOR_STRUCT(Vector3i);
- RETURN_CHECK_FOR_STRUCT(Basis);
- RETURN_CHECK_FOR_STRUCT(Quaternion);
- RETURN_CHECK_FOR_STRUCT(Transform3D);
- RETURN_CHECK_FOR_STRUCT(AABB);
- RETURN_CHECK_FOR_STRUCT(Color);
- RETURN_CHECK_FOR_STRUCT(Plane);
-
-#undef RETURN_CHECK_FOR_STRUCT
-
- if (vtclass == CACHED_CLASS(Callable)) {
- GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var.operator Callable());
- RETURN_TYPE_VAL(M_Callable, from);
- }
-
- if (vtclass == CACHED_CLASS(SignalInfo)) {
- GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var.operator Signal());
- RETURN_TYPE_VAL(M_SignalInfo, from);
- }
-
- if (mono_class_is_enum(vtclass->get_mono_ptr())) {
- MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr());
- switch (mono_type_get_type(enum_basetype)) {
- case MONO_TYPE_BOOLEAN: {
- MonoBoolean val = p_var.operator bool();
- RETURN_TYPE_VAL(MonoBoolean, val);
- }
- case MONO_TYPE_CHAR: {
- uint16_t val = p_var.operator unsigned short();
- RETURN_TYPE_VAL(uint16_t, val);
- }
- case MONO_TYPE_I1: {
- int8_t val = p_var.operator signed char();
- RETURN_TYPE_VAL(int8_t, val);
- }
- case MONO_TYPE_I2: {
- int16_t val = p_var.operator signed short();
- RETURN_TYPE_VAL(int16_t, val);
- }
- case MONO_TYPE_I4: {
- int32_t val = p_var.operator signed int();
- RETURN_TYPE_VAL(int32_t, val);
- }
- case MONO_TYPE_I8: {
- int64_t val = p_var.operator int64_t();
- RETURN_TYPE_VAL(int64_t, val);
- }
- case MONO_TYPE_U1: {
- uint8_t val = p_var.operator unsigned char();
- RETURN_TYPE_VAL(uint8_t, val);
- }
- case MONO_TYPE_U2: {
- uint16_t val = p_var.operator unsigned short();
- RETURN_TYPE_VAL(uint16_t, val);
- }
- case MONO_TYPE_U4: {
- uint32_t val = p_var.operator unsigned int();
- RETURN_TYPE_VAL(uint32_t, val);
- }
- case MONO_TYPE_U8: {
- uint64_t val = p_var.operator uint64_t();
- RETURN_TYPE_VAL(uint64_t, val);
- }
- default: {
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to enum value of unsupported base type: '" + GDMonoClass::get_full_name(mono_class_from_mono_type(enum_basetype)) + "'.");
- }
- }
- }
-
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported value type: '" + p_type.type_class->get_full_name() + "'.");
- } break;
-#undef RETURN_TYPE_VAL
- case MONO_TYPE_STRING:
- return variant_to_mono_string(p_var);
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY:
- return variant_to_mono_array(p_var, p_type.type_class);
- case MONO_TYPE_CLASS:
- return variant_to_mono_object_of_class(p_var, p_type.type_class);
- case MONO_TYPE_GENERICINST:
- return variant_to_mono_object_of_genericinst(p_var, p_type.type_class);
- case MONO_TYPE_OBJECT:
- return variant_to_mono_object(p_var);
- }
-
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type with encoding: " + itos(p_type.type_encoding) + ".");
-}
-
-MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type) {
- switch (p_type.type_encoding) {
- case MONO_TYPE_BOOLEAN: {
- MonoBoolean val = p_var.operator bool();
- return BOX_BOOLEAN(val);
- }
- case MONO_TYPE_CHAR: {
- uint16_t val = p_var.operator unsigned short();
- return BOX_UINT16(val);
- }
- case MONO_TYPE_I1: {
- int8_t val = p_var.operator signed char();
- return BOX_INT8(val);
- }
- case MONO_TYPE_I2: {
- int16_t val = p_var.operator signed short();
- return BOX_INT16(val);
- }
- case MONO_TYPE_I4: {
- int32_t val = p_var.operator signed int();
- return BOX_INT32(val);
- }
- case MONO_TYPE_I8: {
- int64_t val = p_var.operator int64_t();
- return BOX_INT64(val);
- }
- case MONO_TYPE_U1: {
- uint8_t val = p_var.operator unsigned char();
- return BOX_UINT8(val);
- }
- case MONO_TYPE_U2: {
- uint16_t val = p_var.operator unsigned short();
- return BOX_UINT16(val);
- }
- case MONO_TYPE_U4: {
- uint32_t val = p_var.operator unsigned int();
- return BOX_UINT32(val);
- }
- case MONO_TYPE_U8: {
- uint64_t val = p_var.operator uint64_t();
- return BOX_UINT64(val);
- }
- case MONO_TYPE_R4: {
- float val = p_var.operator float();
- return BOX_FLOAT(val);
- }
- case MONO_TYPE_R8: {
- double val = p_var.operator double();
- return BOX_DOUBLE(val);
- }
- case MONO_TYPE_VALUETYPE: {
- GDMonoClass *vtclass = p_type.type_class;
-
-#define RETURN_CHECK_FOR_STRUCT(m_struct) \
- if (vtclass == CACHED_CLASS(m_struct)) { \
- GDMonoMarshal::M_##m_struct from = MARSHALLED_OUT(m_struct, p_var.operator ::m_struct()); \
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(m_struct), &from); \
- }
-
- RETURN_CHECK_FOR_STRUCT(Vector2);
- RETURN_CHECK_FOR_STRUCT(Vector2i);
- RETURN_CHECK_FOR_STRUCT(Rect2);
- RETURN_CHECK_FOR_STRUCT(Rect2i);
- RETURN_CHECK_FOR_STRUCT(Transform2D);
- RETURN_CHECK_FOR_STRUCT(Vector3);
- RETURN_CHECK_FOR_STRUCT(Vector3i);
- RETURN_CHECK_FOR_STRUCT(Basis);
- RETURN_CHECK_FOR_STRUCT(Quaternion);
- RETURN_CHECK_FOR_STRUCT(Transform3D);
- RETURN_CHECK_FOR_STRUCT(AABB);
- RETURN_CHECK_FOR_STRUCT(Color);
- RETURN_CHECK_FOR_STRUCT(Plane);
-
-#undef RETURN_CHECK_FOR_STRUCT
-
- if (vtclass == CACHED_CLASS(Callable)) {
- GDMonoMarshal::M_Callable from = GDMonoMarshal::callable_to_managed(p_var.operator Callable());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Callable), &from);
- }
-
- if (vtclass == CACHED_CLASS(SignalInfo)) {
- GDMonoMarshal::M_SignalInfo from = GDMonoMarshal::signal_info_to_managed(p_var.operator Signal());
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(SignalInfo), &from);
- }
-
- if (mono_class_is_enum(vtclass->get_mono_ptr())) {
- MonoType *enum_basetype = mono_class_enum_basetype(vtclass->get_mono_ptr());
- MonoClass *enum_baseclass = mono_class_from_mono_type(enum_basetype);
- switch (mono_type_get_type(enum_basetype)) {
- case MONO_TYPE_BOOLEAN: {
- MonoBoolean val = p_var.operator bool();
- return BOX_ENUM(enum_baseclass, val);
- }
- case MONO_TYPE_CHAR: {
- uint16_t val = p_var.operator unsigned short();
- return BOX_ENUM(enum_baseclass, val);
- }
- case MONO_TYPE_I1: {
- int8_t val = p_var.operator signed char();
- return BOX_ENUM(enum_baseclass, val);
- }
- case MONO_TYPE_I2: {
- int16_t val = p_var.operator signed short();
- return BOX_ENUM(enum_baseclass, val);
- }
- case MONO_TYPE_I4: {
- int32_t val = p_var.operator signed int();
- return BOX_ENUM(enum_baseclass, val);
- }
- case MONO_TYPE_I8: {
- int64_t val = p_var.operator int64_t();
- return BOX_ENUM(enum_baseclass, val);
- }
- case MONO_TYPE_U1: {
- uint8_t val = p_var.operator unsigned char();
- return BOX_ENUM(enum_baseclass, val);
- }
- case MONO_TYPE_U2: {
- uint16_t val = p_var.operator unsigned short();
- return BOX_ENUM(enum_baseclass, val);
- }
- case MONO_TYPE_U4: {
- uint32_t val = p_var.operator unsigned int();
- return BOX_ENUM(enum_baseclass, val);
- }
- case MONO_TYPE_U8: {
- uint64_t val = p_var.operator uint64_t();
- return BOX_ENUM(enum_baseclass, val);
- }
- default: {
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to enum value of unsupported base type: '" + GDMonoClass::get_full_name(enum_baseclass) + "'.");
- }
- }
- }
-
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported value type: '" + p_type.type_class->get_full_name() + "'.");
- } break;
- case MONO_TYPE_STRING:
- return (MonoObject *)variant_to_mono_string(p_var);
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY:
- return (MonoObject *)variant_to_mono_array(p_var, p_type.type_class);
- case MONO_TYPE_CLASS:
- return variant_to_mono_object_of_class(p_var, p_type.type_class);
- case MONO_TYPE_GENERICINST:
- return variant_to_mono_object_of_genericinst(p_var, p_type.type_class);
- case MONO_TYPE_OBJECT:
- return variant_to_mono_object(p_var);
- }
-
- ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported type with encoding: " + itos(p_type.type_encoding) + ".");
-}
-
-Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type, bool p_fail_with_err = true) {
- ERR_FAIL_COND_V(!p_type.type_class, Variant());
-
-#ifdef DEBUG_ENABLED
- CRASH_COND_MSG(p_type.type_encoding == MONO_TYPE_OBJECT, "Type of object should be known.");
-#endif
-
- switch (p_type.type_encoding) {
- case MONO_TYPE_BOOLEAN:
- return (bool)unbox<MonoBoolean>(p_obj);
- case MONO_TYPE_CHAR:
- return unbox<uint16_t>(p_obj);
- case MONO_TYPE_I1:
- return unbox<int8_t>(p_obj);
- case MONO_TYPE_I2:
- return unbox<int16_t>(p_obj);
- case MONO_TYPE_I4:
- return unbox<int32_t>(p_obj);
- case MONO_TYPE_I8:
- return unbox<int64_t>(p_obj);
- case MONO_TYPE_U1:
- return unbox<uint8_t>(p_obj);
- case MONO_TYPE_U2:
- return unbox<uint16_t>(p_obj);
- case MONO_TYPE_U4:
- return unbox<uint32_t>(p_obj);
- case MONO_TYPE_U8:
- return unbox<uint64_t>(p_obj);
- case MONO_TYPE_R4:
- return unbox<float>(p_obj);
- case MONO_TYPE_R8:
- return unbox<double>(p_obj);
- case MONO_TYPE_VALUETYPE: {
- GDMonoClass *vtclass = p_type.type_class;
-
- if (vtclass == CACHED_CLASS(Vector2)) {
- return MARSHALLED_IN(Vector2, unbox_addr<GDMonoMarshal::M_Vector2>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Vector2i)) {
- return MARSHALLED_IN(Vector2i, unbox_addr<GDMonoMarshal::M_Vector2i>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Rect2)) {
- return MARSHALLED_IN(Rect2, unbox_addr<GDMonoMarshal::M_Rect2>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Rect2i)) {
- return MARSHALLED_IN(Rect2i, unbox_addr<GDMonoMarshal::M_Rect2i>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Transform2D)) {
- return MARSHALLED_IN(Transform2D, unbox_addr<GDMonoMarshal::M_Transform2D>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Vector3)) {
- return MARSHALLED_IN(Vector3, unbox_addr<GDMonoMarshal::M_Vector3>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Vector3i)) {
- return MARSHALLED_IN(Vector3i, unbox_addr<GDMonoMarshal::M_Vector3i>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Basis)) {
- return MARSHALLED_IN(Basis, unbox_addr<GDMonoMarshal::M_Basis>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Quaternion)) {
- return MARSHALLED_IN(Quaternion, unbox_addr<GDMonoMarshal::M_Quaternion>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Transform3D)) {
- return MARSHALLED_IN(Transform3D, unbox_addr<GDMonoMarshal::M_Transform3D>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(AABB)) {
- return MARSHALLED_IN(AABB, unbox_addr<GDMonoMarshal::M_AABB>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Color)) {
- return MARSHALLED_IN(Color, unbox_addr<GDMonoMarshal::M_Color>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Plane)) {
- return MARSHALLED_IN(Plane, unbox_addr<GDMonoMarshal::M_Plane>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(Callable)) {
- return managed_to_callable(unbox<GDMonoMarshal::M_Callable>(p_obj));
- }
-
- if (vtclass == CACHED_CLASS(SignalInfo)) {
- return managed_to_signal_info(unbox<GDMonoMarshal::M_SignalInfo>(p_obj));
- }
-
- if (mono_class_is_enum(vtclass->get_mono_ptr())) {
- return unbox<int32_t>(p_obj);
- }
- } break;
- case MONO_TYPE_STRING: {
- if (p_obj == nullptr) {
- return Variant(); // NIL
- }
- return mono_string_to_godot_not_null((MonoString *)p_obj);
- } break;
- case MONO_TYPE_ARRAY:
- case MONO_TYPE_SZARRAY: {
- MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type());
-
- if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) {
- return mono_array_to_Array((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) {
- return mono_array_to_PackedByteArray((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) {
- return mono_array_to_PackedInt32Array((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(int64_t)) {
- return mono_array_to_PackedInt64Array((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(float)) {
- return mono_array_to_PackedFloat32Array((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(double)) {
- return mono_array_to_PackedFloat64Array((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(String)) {
- return mono_array_to_PackedStringArray((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) {
- return mono_array_to_PackedVector2Array((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) {
- return mono_array_to_PackedVector3Array((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(Color)) {
- return mono_array_to_PackedColorArray((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(StringName)) {
- return mono_array_to_Array((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(NodePath)) {
- return mono_array_to_Array((MonoArray *)p_obj);
- }
-
- if (array_type->eklass == CACHED_CLASS_RAW(RID)) {
- return mono_array_to_Array((MonoArray *)p_obj);
- }
-
- GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass);
- if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) {
- return mono_array_to_Array((MonoArray *)p_obj);
- }
-
- if (p_fail_with_err) {
- ERR_FAIL_V_MSG(Variant(), "Attempted to convert a managed array of unmarshallable element type to Variant.");
- } else {
- return Variant();
- }
- } break;
- case MONO_TYPE_CLASS: {
- GDMonoClass *type_class = p_type.type_class;
-
- // GodotObject
- if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
- Object *ptr = unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_obj));
- if (ptr != nullptr) {
- RefCounted *rc = Object::cast_to<RefCounted>(ptr);
- return rc ? Variant(Ref<RefCounted>(rc)) : Variant(ptr);
- }
- return Variant();
- }
-
- if (CACHED_CLASS(StringName) == type_class) {
- StringName *ptr = unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_obj));
- return ptr ? Variant(*ptr) : Variant();
- }
-
- if (CACHED_CLASS(NodePath) == type_class) {
- NodePath *ptr = unbox<NodePath *>(CACHED_FIELD(NodePath, ptr)->get_value(p_obj));
- return ptr ? Variant(*ptr) : Variant();
- }
-
- if (CACHED_CLASS(RID) == type_class) {
- RID *ptr = unbox<RID *>(CACHED_FIELD(RID, ptr)->get_value(p_obj));
- return ptr ? Variant(*ptr) : Variant();
- }
-
- // Godot.Collections.Dictionary
- if (CACHED_CLASS(Dictionary) == type_class) {
- MonoException *exc = nullptr;
- Dictionary *ptr = CACHED_METHOD_THUNK(Dictionary, GetPtr).invoke(p_obj, &exc);
- UNHANDLED_EXCEPTION(exc);
- return ptr ? Variant(*ptr) : Variant();
- }
-
- // Godot.Collections.Array
- if (CACHED_CLASS(Array) == type_class) {
- MonoException *exc = nullptr;
- Array *ptr = CACHED_METHOD_THUNK(Array, GetPtr).invoke(p_obj, &exc);
- UNHANDLED_EXCEPTION(exc);
- return ptr ? Variant(*ptr) : Variant();
- }
- } break;
- case MONO_TYPE_GENERICINST: {
- MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), p_type.type_class->get_mono_type());
-
- // Godot.Collections.Dictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_generic_dictionary(reftype)) {
- MonoException *exc = nullptr;
- MonoObject *ret = p_type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
- UNHANDLED_EXCEPTION(exc);
- return *unbox<Dictionary *>(ret);
- }
-
- // Godot.Collections.Array<T>
- if (GDMonoUtils::Marshal::type_is_generic_array(reftype)) {
- MonoException *exc = nullptr;
- MonoObject *ret = p_type.type_class->get_method("GetPtr")->invoke(p_obj, &exc);
- UNHANDLED_EXCEPTION(exc);
- return *unbox<Array *>(ret);
- }
-
- // System.Collections.Generic.Dictionary<TKey, TValue>
- if (GDMonoUtils::Marshal::type_is_system_generic_dictionary(reftype)) {
- MonoReflectionType *key_reftype = nullptr;
- MonoReflectionType *value_reftype = nullptr;
- GDMonoUtils::Marshal::dictionary_get_key_value_types(reftype, &key_reftype, &value_reftype);
- return system_generic_dict_to_Dictionary(p_obj, p_type.type_class, key_reftype, value_reftype);
- }
-
- // System.Collections.Generic.List<T>
- if (GDMonoUtils::Marshal::type_is_system_generic_list(reftype)) {
- MonoReflectionType *elem_reftype = nullptr;
- GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
- return system_generic_list_to_Array_variant(p_obj, p_type.type_class, elem_reftype);
- }
-
- // GodotObject
- GDMonoClass *type_class = p_type.type_class;
- if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
- Object *ptr = unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_obj));
- if (ptr != nullptr) {
- RefCounted *rc = Object::cast_to<RefCounted>(ptr);
- return rc ? Variant(Ref<RefCounted>(rc)) : Variant(ptr);
- }
- return Variant();
- }
- } break;
- }
-
- if (p_fail_with_err) {
- ERR_FAIL_V_MSG(Variant(), "Attempted to convert an unmarshallable managed type to Variant. Name: '" + p_type.type_class->get_name() + "' Encoding: " + itos(p_type.type_encoding) + ".");
- } else {
- return Variant();
- }
-}
-
-Variant mono_object_to_variant(MonoObject *p_obj) {
- if (!p_obj) {
- return Variant();
- }
-
- ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj));
-
- return mono_object_to_variant_impl(p_obj, type);
-}
-
-Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type) {
- if (!p_obj) {
- return Variant();
- }
-
- return mono_object_to_variant_impl(p_obj, p_type);
-}
-
-Variant mono_object_to_variant_no_err(MonoObject *p_obj, const ManagedType &p_type) {
- if (!p_obj) {
- return Variant();
- }
-
- return mono_object_to_variant_impl(p_obj, p_type, /* fail_with_err: */ false);
-}
-
-String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc) {
- if (p_obj == nullptr) {
- return String("null");
- }
-
- ManagedType type = ManagedType::from_class(mono_object_get_class(p_obj));
- Variant var = GDMonoMarshal::mono_object_to_variant_no_err(p_obj, type);
-
- if (var.get_type() == Variant::NIL) { // `&& p_obj != nullptr` but omitted because always true
- // Cannot convert MonoObject* to Variant; fallback to 'ToString()'.
- MonoException *exc = nullptr;
- MonoString *mono_str = GDMonoUtils::object_to_string(p_obj, &exc);
-
- if (exc) {
- if (r_exc) {
- *r_exc = exc;
- }
- return String();
- }
-
- return GDMonoMarshal::mono_string_to_godot(mono_str);
- } else {
- return var.operator String();
- }
-}
-
-MonoObject *Dictionary_to_system_generic_dict(const Dictionary &p_dict, GDMonoClass *p_class, MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype) {
- String ctor_desc = ":.ctor(System.Collections.Generic.IDictionary`2<" + GDMonoUtils::get_type_desc(p_key_reftype) +
- ", " + GDMonoUtils::get_type_desc(p_value_reftype) + ">)";
- GDMonoMethod *ctor = p_class->get_method_with_desc(ctor_desc, true);
- CRASH_COND(ctor == nullptr);
-
- MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr());
- ERR_FAIL_NULL_V(mono_object, nullptr);
-
- GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(p_key_reftype, p_value_reftype);
- MonoObject *godot_dict = GDMonoUtils::create_managed_from(p_dict, godot_dict_class);
-
- void *ctor_args[1] = { godot_dict };
-
- MonoException *exc = nullptr;
- ctor->invoke_raw(mono_object, ctor_args, &exc);
- UNHANDLED_EXCEPTION(exc);
-
- return mono_object;
-}
-
-Dictionary system_generic_dict_to_Dictionary(MonoObject *p_obj, [[maybe_unused]] GDMonoClass *p_class, MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype) {
- GDMonoClass *godot_dict_class = GDMonoUtils::Marshal::make_generic_dictionary_type(p_key_reftype, p_value_reftype);
- String ctor_desc = ":.ctor(System.Collections.Generic.IDictionary`2<" + GDMonoUtils::get_type_desc(p_key_reftype) +
- ", " + GDMonoUtils::get_type_desc(p_value_reftype) + ">)";
- GDMonoMethod *godot_dict_ctor = godot_dict_class->get_method_with_desc(ctor_desc, true);
- CRASH_COND(godot_dict_ctor == nullptr);
-
- MonoObject *godot_dict = mono_object_new(mono_domain_get(), godot_dict_class->get_mono_ptr());
- ERR_FAIL_NULL_V(godot_dict, Dictionary());
-
- void *ctor_args[1] = { p_obj };
-
- MonoException *exc = nullptr;
- godot_dict_ctor->invoke_raw(godot_dict, ctor_args, &exc);
- UNHANDLED_EXCEPTION(exc);
-
- exc = nullptr;
- MonoObject *ret = godot_dict_class->get_method("GetPtr")->invoke(godot_dict, &exc);
- UNHANDLED_EXCEPTION(exc);
-
- return *unbox<Dictionary *>(ret);
-}
-
-MonoObject *Array_to_system_generic_list(const Array &p_array, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype) {
- MonoType *elem_type = mono_reflection_type_get_type(p_elem_reftype);
-
- String ctor_desc = ":.ctor(System.Collections.Generic.IEnumerable`1<" + GDMonoUtils::get_type_desc(elem_type) + ">)";
- GDMonoMethod *ctor = p_class->get_method_with_desc(ctor_desc, true);
- CRASH_COND(ctor == nullptr);
-
- MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr());
- ERR_FAIL_NULL_V(mono_object, nullptr);
-
- GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(p_elem_reftype);
- MonoObject *godot_array = GDMonoUtils::create_managed_from(p_array, godot_array_class);
-
- void *ctor_args[1] = { godot_array };
-
- MonoException *exc = nullptr;
- ctor->invoke_raw(mono_object, ctor_args, &exc);
- UNHANDLED_EXCEPTION(exc);
-
- return mono_object;
-}
-
-Variant system_generic_list_to_Array_variant(MonoObject *p_obj, GDMonoClass *p_class, [[maybe_unused]] MonoReflectionType *p_elem_reftype) {
- GDMonoMethod *to_array = p_class->get_method("ToArray", 0);
- CRASH_COND(to_array == nullptr);
-
- MonoException *exc = nullptr;
- MonoObject *array = to_array->invoke_raw(p_obj, nullptr, &exc);
- UNHANDLED_EXCEPTION(exc);
-
- ERR_FAIL_NULL_V(array, Variant());
-
- ManagedType type = ManagedType::from_class(mono_object_get_class(array));
-
- bool result_is_array = type.type_encoding != MONO_TYPE_SZARRAY && type.type_encoding != MONO_TYPE_ARRAY;
- ERR_FAIL_COND_V(result_is_array, Variant());
-
- return mono_object_to_variant(array, type);
-}
-
-MonoArray *Array_to_mono_array(const Array &p_array) {
- int length = p_array.size();
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), length);
-
- for (int i = 0; i < length; i++) {
- MonoObject *boxed = variant_to_mono_object(p_array[i]);
- mono_array_setref(ret, i, boxed);
- }
-
- return ret;
-}
-
-MonoArray *Array_to_mono_array(const Array &p_array, MonoClass *p_array_type_class) {
- int length = p_array.size();
- MonoArray *ret = mono_array_new(mono_domain_get(), p_array_type_class, length);
-
- for (int i = 0; i < length; i++) {
- MonoObject *boxed = variant_to_mono_object(p_array[i]);
- mono_array_setref(ret, i, boxed);
- }
-
- return ret;
-}
-
-Array mono_array_to_Array(MonoArray *p_array) {
- Array ret;
- if (!p_array) {
- return ret;
- }
- int length = mono_array_length(p_array);
- ret.resize(length);
-
- for (int i = 0; i < length; i++) {
- MonoObject *elem = mono_array_get(p_array, MonoObject *, i);
- ret[i] = mono_object_to_variant(elem);
- }
-
- return ret;
-}
-
-MonoArray *PackedInt32Array_to_mono_array(const PackedInt32Array &p_array) {
- const int32_t *src = p_array.ptr();
- int length = p_array.size();
-
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(int32_t), length);
-
- int32_t *dst = mono_array_addr(ret, int32_t, 0);
- memcpy(dst, src, length * sizeof(int32_t));
-
- return ret;
-}
-
-PackedInt32Array mono_array_to_PackedInt32Array(MonoArray *p_array) {
- PackedInt32Array ret;
- if (!p_array) {
- return ret;
- }
- int length = mono_array_length(p_array);
- ret.resize(length);
- int32_t *dst = ret.ptrw();
-
- const int32_t *src = mono_array_addr(p_array, int32_t, 0);
- memcpy(dst, src, length * sizeof(int32_t));
-
- return ret;
-}
-
-MonoArray *PackedInt64Array_to_mono_array(const PackedInt64Array &p_array) {
- const int64_t *src = p_array.ptr();
- int length = p_array.size();
-
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(int64_t), length);
-
- int64_t *dst = mono_array_addr(ret, int64_t, 0);
- memcpy(dst, src, length * sizeof(int64_t));
-
- return ret;
-}
-
-PackedInt64Array mono_array_to_PackedInt64Array(MonoArray *p_array) {
- PackedInt64Array ret;
- if (!p_array) {
- return ret;
- }
- int length = mono_array_length(p_array);
- ret.resize(length);
- int64_t *dst = ret.ptrw();
-
- const int64_t *src = mono_array_addr(p_array, int64_t, 0);
- memcpy(dst, src, length * sizeof(int64_t));
-
- return ret;
-}
-
-MonoArray *PackedByteArray_to_mono_array(const PackedByteArray &p_array) {
- const uint8_t *src = p_array.ptr();
- int length = p_array.size();
-
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(uint8_t), length);
-
- uint8_t *dst = mono_array_addr(ret, uint8_t, 0);
- memcpy(dst, src, length * sizeof(uint8_t));
-
- return ret;
-}
-
-PackedByteArray mono_array_to_PackedByteArray(MonoArray *p_array) {
- PackedByteArray ret;
- if (!p_array) {
- return ret;
- }
- int length = mono_array_length(p_array);
- ret.resize(length);
- uint8_t *dst = ret.ptrw();
-
- const uint8_t *src = mono_array_addr(p_array, uint8_t, 0);
- memcpy(dst, src, length * sizeof(uint8_t));
-
- return ret;
-}
-
-MonoArray *PackedFloat32Array_to_mono_array(const PackedFloat32Array &p_array) {
- const float *src = p_array.ptr();
- int length = p_array.size();
-
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(float), length);
-
- float *dst = mono_array_addr(ret, float, 0);
- memcpy(dst, src, length * sizeof(float));
-
- return ret;
-}
-
-PackedFloat32Array mono_array_to_PackedFloat32Array(MonoArray *p_array) {
- PackedFloat32Array ret;
- if (!p_array) {
- return ret;
- }
- int length = mono_array_length(p_array);
- ret.resize(length);
- float *dst = ret.ptrw();
-
- const float *src = mono_array_addr(p_array, float, 0);
- memcpy(dst, src, length * sizeof(float));
-
- return ret;
-}
-
-MonoArray *PackedFloat64Array_to_mono_array(const PackedFloat64Array &p_array) {
- const double *src = p_array.ptr();
- int length = p_array.size();
-
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(double), length);
-
- double *dst = mono_array_addr(ret, double, 0);
- memcpy(dst, src, length * sizeof(double));
-
- return ret;
-}
-
-PackedFloat64Array mono_array_to_PackedFloat64Array(MonoArray *p_array) {
- PackedFloat64Array ret;
- if (!p_array) {
- return ret;
- }
- int length = mono_array_length(p_array);
- ret.resize(length);
- double *dst = ret.ptrw();
-
- const double *src = mono_array_addr(p_array, double, 0);
- memcpy(dst, src, length * sizeof(double));
-
- return ret;
-}
-
-MonoArray *PackedStringArray_to_mono_array(const PackedStringArray &p_array) {
- const String *r = p_array.ptr();
- int length = p_array.size();
-
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(String), length);
-
- for (int i = 0; i < length; i++) {
- MonoString *boxed = mono_string_from_godot(r[i]);
- mono_array_setref(ret, i, boxed);
- }
-
- return ret;
-}
-
-PackedStringArray mono_array_to_PackedStringArray(MonoArray *p_array) {
- PackedStringArray ret;
- if (!p_array) {
- return ret;
- }
- int length = mono_array_length(p_array);
- ret.resize(length);
- String *w = ret.ptrw();
-
- for (int i = 0; i < length; i++) {
- MonoString *elem = mono_array_get(p_array, MonoString *, i);
- w[i] = mono_string_to_godot(elem);
- }
-
- return ret;
-}
-
-MonoArray *PackedColorArray_to_mono_array(const PackedColorArray &p_array) {
- const Color *src = p_array.ptr();
- int length = p_array.size();
-
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Color), length);
-
- if constexpr (InteropLayout::MATCHES_Color) {
- Color *dst = mono_array_addr(ret, Color, 0);
- memcpy(dst, src, length * sizeof(Color));
- } else {
- for (int i = 0; i < length; i++) {
- M_Color *raw = (M_Color *)mono_array_addr_with_size(ret, sizeof(M_Color), i);
- *raw = MARSHALLED_OUT(Color, src[i]);
- }
- }
-
- return ret;
-}
-
-PackedColorArray mono_array_to_PackedColorArray(MonoArray *p_array) {
- PackedColorArray ret;
- if (!p_array) {
- return ret;
- }
- int length = mono_array_length(p_array);
- ret.resize(length);
- Color *dst = ret.ptrw();
-
- if constexpr (InteropLayout::MATCHES_Color) {
- const Color *src = mono_array_addr(p_array, Color, 0);
- memcpy(dst, src, length * sizeof(Color));
- } else {
- for (int i = 0; i < length; i++) {
- dst[i] = MARSHALLED_IN(Color, (M_Color *)mono_array_addr_with_size(p_array, sizeof(M_Color), i));
- }
- }
-
- return ret;
-}
-
-MonoArray *PackedVector2Array_to_mono_array(const PackedVector2Array &p_array) {
- const Vector2 *src = p_array.ptr();
- int length = p_array.size();
-
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Vector2), length);
-
- if constexpr (InteropLayout::MATCHES_Vector2) {
- Vector2 *dst = mono_array_addr(ret, Vector2, 0);
- memcpy(dst, src, length * sizeof(Vector2));
- } else {
- for (int i = 0; i < length; i++) {
- M_Vector2 *raw = (M_Vector2 *)mono_array_addr_with_size(ret, sizeof(M_Vector2), i);
- *raw = MARSHALLED_OUT(Vector2, src[i]);
- }
- }
-
- return ret;
-}
-
-PackedVector2Array mono_array_to_PackedVector2Array(MonoArray *p_array) {
- PackedVector2Array ret;
- if (!p_array) {
- return ret;
- }
- int length = mono_array_length(p_array);
- ret.resize(length);
- Vector2 *dst = ret.ptrw();
-
- if constexpr (InteropLayout::MATCHES_Vector2) {
- const Vector2 *src = mono_array_addr(p_array, Vector2, 0);
- memcpy(dst, src, length * sizeof(Vector2));
- } else {
- for (int i = 0; i < length; i++) {
- dst[i] = MARSHALLED_IN(Vector2, (M_Vector2 *)mono_array_addr_with_size(p_array, sizeof(M_Vector2), i));
- }
- }
-
- return ret;
-}
-
-MonoArray *PackedVector3Array_to_mono_array(const PackedVector3Array &p_array) {
- const Vector3 *src = p_array.ptr();
- int length = p_array.size();
-
- MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Vector3), length);
-
- if constexpr (InteropLayout::MATCHES_Vector3) {
- Vector3 *dst = mono_array_addr(ret, Vector3, 0);
- memcpy(dst, src, length * sizeof(Vector3));
- } else {
- for (int i = 0; i < length; i++) {
- M_Vector3 *raw = (M_Vector3 *)mono_array_addr_with_size(ret, sizeof(M_Vector3), i);
- *raw = MARSHALLED_OUT(Vector3, src[i]);
- }
- }
-
- return ret;
-}
-
-PackedVector3Array mono_array_to_PackedVector3Array(MonoArray *p_array) {
- PackedVector3Array ret;
- if (!p_array) {
- return ret;
- }
- int length = mono_array_length(p_array);
- ret.resize(length);
- Vector3 *dst = ret.ptrw();
-
- if constexpr (InteropLayout::MATCHES_Vector3) {
- const Vector3 *src = mono_array_addr(p_array, Vector3, 0);
- memcpy(dst, src, length * sizeof(Vector3));
- } else {
- for (int i = 0; i < length; i++) {
- dst[i] = MARSHALLED_IN(Vector3, (M_Vector3 *)mono_array_addr_with_size(p_array, sizeof(M_Vector3), i));
- }
- }
-
- return ret;
-}
-
-Callable managed_to_callable(const M_Callable &p_managed_callable) {
- if (p_managed_callable.delegate) {
- // TODO: Use pooling for ManagedCallable instances.
- CallableCustom *managed_callable = memnew(ManagedCallable(p_managed_callable.delegate));
- return Callable(managed_callable);
- } else {
- Object *target = p_managed_callable.target
- ? unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_managed_callable.target))
- : nullptr;
- StringName *method_ptr = p_managed_callable.method_string_name
- ? unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_managed_callable.method_string_name))
- : nullptr;
- StringName method = method_ptr ? *method_ptr : StringName();
- return Callable(target, method);
- }
-}
-
-M_Callable callable_to_managed(const Callable &p_callable) {
- if (p_callable.is_custom()) {
- CallableCustom *custom = p_callable.get_custom();
- CallableCustom::CompareEqualFunc compare_equal_func = custom->get_compare_equal_func();
-
- if (compare_equal_func == ManagedCallable::compare_equal_func_ptr) {
- ManagedCallable *managed_callable = static_cast<ManagedCallable *>(custom);
- return {
- nullptr, nullptr,
- managed_callable->get_delegate()
- };
- } else if (compare_equal_func == SignalAwaiterCallable::compare_equal_func_ptr) {
- SignalAwaiterCallable *signal_awaiter_callable = static_cast<SignalAwaiterCallable *>(custom);
- return {
- GDMonoUtils::unmanaged_get_managed(ObjectDB::get_instance(signal_awaiter_callable->get_object())),
- GDMonoUtils::create_managed_from(signal_awaiter_callable->get_signal()),
- nullptr
- };
- } else if (compare_equal_func == EventSignalCallable::compare_equal_func_ptr) {
- EventSignalCallable *event_signal_callable = static_cast<EventSignalCallable *>(custom);
- return {
- GDMonoUtils::unmanaged_get_managed(ObjectDB::get_instance(event_signal_callable->get_object())),
- GDMonoUtils::create_managed_from(event_signal_callable->get_signal()),
- nullptr
- };
- }
-
- // Some other CallableCustom. We only support ManagedCallable.
- return { nullptr, nullptr, nullptr };
- } else {
- MonoObject *target_managed = GDMonoUtils::unmanaged_get_managed(p_callable.get_object());
- MonoObject *method_string_name_managed = GDMonoUtils::create_managed_from(p_callable.get_method());
- return { target_managed, method_string_name_managed, nullptr };
- }
-}
-
-Signal managed_to_signal_info(const M_SignalInfo &p_managed_signal) {
- Object *owner = p_managed_signal.owner
- ? unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_managed_signal.owner))
- : nullptr;
- StringName *name_ptr = p_managed_signal.name_string_name
- ? unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(p_managed_signal.name_string_name))
- : nullptr;
- StringName name = name_ptr ? *name_ptr : StringName();
- return Signal(owner, name);
-}
-
-M_SignalInfo signal_info_to_managed(const Signal &p_signal) {
- Object *owner = p_signal.get_object();
- MonoObject *owner_managed = GDMonoUtils::unmanaged_get_managed(owner);
- MonoObject *name_string_name_managed = GDMonoUtils::create_managed_from(p_signal.get_name());
- return { owner_managed, name_string_name_managed };
-}
-} // namespace GDMonoMarshal
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
deleted file mode 100644
index 51f11ab18a..0000000000
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ /dev/null
@@ -1,605 +0,0 @@
-/*************************************************************************/
-/* gd_mono_marshal.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GD_MONO_MARSHAL_H
-#define GD_MONO_MARSHAL_H
-
-#include "core/variant/variant.h"
-
-#include "../managed_callable.h"
-#include "gd_mono.h"
-#include "gd_mono_utils.h"
-
-namespace GDMonoMarshal {
-
-template <typename T>
-T unbox(MonoObject *p_obj) {
- return *(T *)mono_object_unbox(p_obj);
-}
-
-template <typename T>
-T *unbox_addr(MonoObject *p_obj) {
- return (T *)mono_object_unbox(p_obj);
-}
-
-#define BOX_DOUBLE(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(double), &x)
-#define BOX_FLOAT(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(float), &x)
-#define BOX_INT64(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int64_t), &x)
-#define BOX_INT32(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int32_t), &x)
-#define BOX_INT16(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int16_t), &x)
-#define BOX_INT8(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(int8_t), &x)
-#define BOX_UINT64(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(uint64_t), &x)
-#define BOX_UINT32(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(uint32_t), &x)
-#define BOX_UINT16(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(uint16_t), &x)
-#define BOX_UINT8(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(uint8_t), &x)
-#define BOX_BOOLEAN(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(bool), &x)
-#define BOX_PTR(x) mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(IntPtr), x)
-#define BOX_ENUM(m_enum_class, x) mono_value_box(mono_domain_get(), m_enum_class, &x)
-
-Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_variant = nullptr);
-
-bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_elem_type);
-
-// String
-
-_FORCE_INLINE_ String mono_string_to_godot_not_null(MonoString *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) {
- if (p_mono_string == nullptr) {
- return String();
- }
-
- return mono_string_to_godot_not_null(p_mono_string);
-}
-
-_FORCE_INLINE_ MonoString *mono_string_from_godot(const String &p_string) {
- return mono_string_from_utf32((mono_unichar4 *)(p_string.get_data()));
-}
-
-// Variant
-
-size_t variant_get_managed_unboxed_size(const ManagedType &p_type);
-void *variant_to_managed_unboxed(const Variant &p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset);
-MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_type);
-
-MonoObject *variant_to_mono_object(const Variant &p_var);
-MonoArray *variant_to_mono_array(const Variant &p_var, GDMonoClass *p_type_class);
-MonoObject *variant_to_mono_object_of_class(const Variant &p_var, GDMonoClass *p_type_class);
-MonoObject *variant_to_mono_object_of_genericinst(const Variant &p_var, GDMonoClass *p_type_class);
-MonoString *variant_to_mono_string(const Variant &p_var);
-
-// These overloads were added to avoid passing a `const Variant *` to the `const Variant &`
-// parameter. That would result in the `Variant(bool)` copy constructor being called as
-// pointers are implicitly converted to bool. Implicit conversions are f-ing evil.
-
-_FORCE_INLINE_ void *variant_to_managed_unboxed(const Variant *p_var, const ManagedType &p_type, void *r_buffer, unsigned int &r_offset) {
- return variant_to_managed_unboxed(*p_var, p_type, r_buffer, r_offset);
-}
-_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_type) {
- return variant_to_mono_object(*p_var, p_type);
-}
-_FORCE_INLINE_ MonoObject *variant_to_mono_object(const Variant *p_var) {
- return variant_to_mono_object(*p_var);
-}
-_FORCE_INLINE_ MonoArray *variant_to_mono_array(const Variant *p_var, GDMonoClass *p_type_class) {
- return variant_to_mono_array(*p_var, p_type_class);
-}
-_FORCE_INLINE_ MonoObject *variant_to_mono_object_of_class(const Variant *p_var, GDMonoClass *p_type_class) {
- return variant_to_mono_object_of_class(*p_var, p_type_class);
-}
-_FORCE_INLINE_ MonoObject *variant_to_mono_object_of_genericinst(const Variant *p_var, GDMonoClass *p_type_class) {
- return variant_to_mono_object_of_genericinst(*p_var, p_type_class);
-}
-_FORCE_INLINE_ MonoString *variant_to_mono_string(const Variant *p_var) {
- return variant_to_mono_string(*p_var);
-}
-
-Variant mono_object_to_variant(MonoObject *p_obj);
-Variant mono_object_to_variant(MonoObject *p_obj, const ManagedType &p_type);
-Variant mono_object_to_variant_no_err(MonoObject *p_obj, const ManagedType &p_type);
-
-/// Tries to convert the MonoObject* to Variant and then convert the Variant to String.
-/// If the MonoObject* cannot be converted to Variant, then 'ToString()' is called instead.
-String mono_object_to_variant_string(MonoObject *p_obj, MonoException **r_exc);
-
-// System.Collections.Generic
-
-MonoObject *Dictionary_to_system_generic_dict(const Dictionary &p_dict, GDMonoClass *p_class, MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype);
-Dictionary system_generic_dict_to_Dictionary(MonoObject *p_obj, GDMonoClass *p_class, MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype);
-
-MonoObject *Array_to_system_generic_list(const Array &p_array, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype);
-Variant system_generic_list_to_Array_variant(MonoObject *p_obj, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype);
-
-// Array
-
-MonoArray *Array_to_mono_array(const Array &p_array);
-MonoArray *Array_to_mono_array(const Array &p_array, MonoClass *p_array_type_class);
-Array mono_array_to_Array(MonoArray *p_array);
-
-// PackedInt32Array
-
-MonoArray *PackedInt32Array_to_mono_array(const PackedInt32Array &p_array);
-PackedInt32Array mono_array_to_PackedInt32Array(MonoArray *p_array);
-
-// PackedInt64Array
-
-MonoArray *PackedInt64Array_to_mono_array(const PackedInt64Array &p_array);
-PackedInt64Array mono_array_to_PackedInt64Array(MonoArray *p_array);
-
-// PackedByteArray
-
-MonoArray *PackedByteArray_to_mono_array(const PackedByteArray &p_array);
-PackedByteArray mono_array_to_PackedByteArray(MonoArray *p_array);
-
-// PackedFloat32Array
-
-MonoArray *PackedFloat32Array_to_mono_array(const PackedFloat32Array &p_array);
-PackedFloat32Array mono_array_to_PackedFloat32Array(MonoArray *p_array);
-
-// PackedFloat64Array
-
-MonoArray *PackedFloat64Array_to_mono_array(const PackedFloat64Array &p_array);
-PackedFloat64Array mono_array_to_PackedFloat64Array(MonoArray *p_array);
-
-// PackedStringArray
-
-MonoArray *PackedStringArray_to_mono_array(const PackedStringArray &p_array);
-PackedStringArray mono_array_to_PackedStringArray(MonoArray *p_array);
-
-// PackedColorArray
-
-MonoArray *PackedColorArray_to_mono_array(const PackedColorArray &p_array);
-PackedColorArray mono_array_to_PackedColorArray(MonoArray *p_array);
-
-// PackedVector2Array
-
-MonoArray *PackedVector2Array_to_mono_array(const PackedVector2Array &p_array);
-PackedVector2Array mono_array_to_PackedVector2Array(MonoArray *p_array);
-
-// PackedVector3Array
-
-MonoArray *PackedVector3Array_to_mono_array(const PackedVector3Array &p_array);
-PackedVector3Array mono_array_to_PackedVector3Array(MonoArray *p_array);
-
-#pragma pack(push, 1)
-
-struct M_Callable {
- MonoObject *target = nullptr;
- MonoObject *method_string_name = nullptr;
- MonoDelegate *delegate = nullptr;
-};
-
-struct M_SignalInfo {
- MonoObject *owner = nullptr;
- MonoObject *name_string_name = nullptr;
-};
-
-#pragma pack(pop)
-
-// Callable
-Callable managed_to_callable(const M_Callable &p_managed_callable);
-M_Callable callable_to_managed(const Callable &p_callable);
-
-// SignalInfo
-Signal managed_to_signal_info(const M_SignalInfo &p_managed_signal);
-M_SignalInfo signal_info_to_managed(const Signal &p_signal);
-
-// Structures
-
-namespace InteropLayout {
-
-enum {
- MATCHES_int = (sizeof(int32_t) == sizeof(uint32_t)),
-
- MATCHES_float = (sizeof(float) == sizeof(uint32_t)),
-
- MATCHES_double = (sizeof(double) == sizeof(uint64_t)),
-
-#ifdef REAL_T_IS_DOUBLE
- MATCHES_real_t = (sizeof(real_t) == sizeof(uint64_t)),
-#else
- MATCHES_real_t = (sizeof(real_t) == sizeof(uint32_t)),
-#endif
-
- MATCHES_Vector2 = (MATCHES_real_t && (sizeof(Vector2) == (sizeof(real_t) * 2)) &&
- offsetof(Vector2, x) == (sizeof(real_t) * 0) &&
- offsetof(Vector2, y) == (sizeof(real_t) * 1)),
-
- MATCHES_Vector2i = (MATCHES_int && (sizeof(Vector2i) == (sizeof(int32_t) * 2)) &&
- offsetof(Vector2i, x) == (sizeof(int32_t) * 0) &&
- offsetof(Vector2i, y) == (sizeof(int32_t) * 1)),
-
- MATCHES_Rect2 = (MATCHES_Vector2 && (sizeof(Rect2) == (sizeof(Vector2) * 2)) &&
- offsetof(Rect2, position) == (sizeof(Vector2) * 0) &&
- offsetof(Rect2, size) == (sizeof(Vector2) * 1)),
-
- MATCHES_Rect2i = (MATCHES_Vector2i && (sizeof(Rect2i) == (sizeof(Vector2i) * 2)) &&
- offsetof(Rect2i, position) == (sizeof(Vector2i) * 0) &&
- offsetof(Rect2i, size) == (sizeof(Vector2i) * 1)),
-
- MATCHES_Transform2D = (MATCHES_Vector2 && (sizeof(Transform2D) == (sizeof(Vector2) * 3))), // No field offset required, it stores an array
-
- MATCHES_Vector3 = (MATCHES_real_t && (sizeof(Vector3) == (sizeof(real_t) * 3)) &&
- offsetof(Vector3, x) == (sizeof(real_t) * 0) &&
- offsetof(Vector3, y) == (sizeof(real_t) * 1) &&
- offsetof(Vector3, z) == (sizeof(real_t) * 2)),
-
- MATCHES_Vector4 = (MATCHES_real_t && (sizeof(Vector4) == (sizeof(real_t) * 4)) &&
- offsetof(Vector4, x) == (sizeof(real_t) * 0) &&
- offsetof(Vector4, y) == (sizeof(real_t) * 1) &&
- offsetof(Vector4, z) == (sizeof(real_t) * 2) &&
- offsetof(Vector4, w) == (sizeof(real_t) * 3)),
-
- MATCHES_Vector4i = (MATCHES_int && (sizeof(Vector4i) == (sizeof(int32_t) * 4)) &&
- offsetof(Vector4i, x) == (sizeof(int32_t) * 0) &&
- offsetof(Vector4i, y) == (sizeof(int32_t) * 1) &&
- offsetof(Vector4i, z) == (sizeof(int32_t) * 2) &&
- offsetof(Vector4i, w) == (sizeof(int32_t) * 3)),
-
- MATCHES_Vector3i = (MATCHES_int && (sizeof(Vector3i) == (sizeof(int32_t) * 3)) &&
- offsetof(Vector3i, x) == (sizeof(int32_t) * 0) &&
- offsetof(Vector3i, y) == (sizeof(int32_t) * 1) &&
- offsetof(Vector3i, z) == (sizeof(int32_t) * 2)),
-
- MATCHES_Basis = (MATCHES_Vector3 && (sizeof(Basis) == (sizeof(Vector3) * 3))), // No field offset required, it stores an array
-
- MATCHES_Quaternion = (MATCHES_real_t && (sizeof(Quaternion) == (sizeof(real_t) * 4)) &&
- offsetof(Quaternion, x) == (sizeof(real_t) * 0) &&
- offsetof(Quaternion, y) == (sizeof(real_t) * 1) &&
- offsetof(Quaternion, z) == (sizeof(real_t) * 2) &&
- offsetof(Quaternion, w) == (sizeof(real_t) * 3)),
-
- MATCHES_Transform3D = (MATCHES_Basis && MATCHES_Vector3 && (sizeof(Transform3D) == (sizeof(Basis) + sizeof(Vector3))) &&
- offsetof(Transform3D, basis) == 0 &&
- offsetof(Transform3D, origin) == sizeof(Basis)),
-
- MATCHES_Projection = (MATCHES_Vector4 && (sizeof(Projection) == (sizeof(Vector4) * 4))),
-
- MATCHES_AABB = (MATCHES_Vector3 && (sizeof(AABB) == (sizeof(Vector3) * 2)) &&
- offsetof(AABB, position) == (sizeof(Vector3) * 0) &&
- offsetof(AABB, size) == (sizeof(Vector3) * 1)),
-
- MATCHES_Color = (MATCHES_float && (sizeof(Color) == (sizeof(float) * 4)) &&
- offsetof(Color, r) == (sizeof(float) * 0) &&
- offsetof(Color, g) == (sizeof(float) * 1) &&
- offsetof(Color, b) == (sizeof(float) * 2) &&
- offsetof(Color, a) == (sizeof(float) * 3)),
-
- MATCHES_Plane = (MATCHES_Vector3 && MATCHES_real_t && (sizeof(Plane) == (sizeof(Vector3) + sizeof(real_t))) &&
- offsetof(Plane, normal) == 0 &&
- offsetof(Plane, d) == sizeof(Vector3))
-};
-
-// In the future we may force this if we want to ref return these structs
-#ifdef GD_MONO_FORCE_INTEROP_STRUCT_COPY
-/* clang-format off */
-static_assert(MATCHES_Vector2 && MATCHES_Rect2 && MATCHES_Transform2D && MATCHES_Vector3 && MATCHES_Vector4 &&
- MATCHES_Basis && MATCHES_Quaternion && MATCHES_Transform3D && MATCHES_Projection && MATCHES_AABB && MATCHES_Color &&
- MATCHES_Plane && MATCHES_Vector2i && MATCHES_Rect2i && MATCHES_Vector3i && MATCHES_Vector4i);
-/* clang-format on */
-#endif
-} // namespace InteropLayout
-
-#pragma pack(push, 1)
-
-struct M_Vector2 {
- real_t x, y;
-
- static _FORCE_INLINE_ Vector2 convert_to(const M_Vector2 &p_from) {
- return Vector2(p_from.x, p_from.y);
- }
-
- static _FORCE_INLINE_ M_Vector2 convert_from(const Vector2 &p_from) {
- M_Vector2 ret = { p_from.x, p_from.y };
- return ret;
- }
-};
-
-struct M_Vector2i {
- int32_t x, y;
-
- static _FORCE_INLINE_ Vector2i convert_to(const M_Vector2i &p_from) {
- return Vector2i(p_from.x, p_from.y);
- }
-
- static _FORCE_INLINE_ M_Vector2i convert_from(const Vector2i &p_from) {
- M_Vector2i ret = { p_from.x, p_from.y };
- return ret;
- }
-};
-
-struct M_Rect2 {
- M_Vector2 position;
- M_Vector2 size;
-
- static _FORCE_INLINE_ Rect2 convert_to(const M_Rect2 &p_from) {
- return Rect2(M_Vector2::convert_to(p_from.position),
- M_Vector2::convert_to(p_from.size));
- }
-
- static _FORCE_INLINE_ M_Rect2 convert_from(const Rect2 &p_from) {
- M_Rect2 ret = { M_Vector2::convert_from(p_from.position), M_Vector2::convert_from(p_from.size) };
- return ret;
- }
-};
-
-struct M_Rect2i {
- M_Vector2i position;
- M_Vector2i size;
-
- static _FORCE_INLINE_ Rect2i convert_to(const M_Rect2i &p_from) {
- return Rect2i(M_Vector2i::convert_to(p_from.position),
- M_Vector2i::convert_to(p_from.size));
- }
-
- static _FORCE_INLINE_ M_Rect2i convert_from(const Rect2i &p_from) {
- M_Rect2i ret = { M_Vector2i::convert_from(p_from.position), M_Vector2i::convert_from(p_from.size) };
- return ret;
- }
-};
-
-struct M_Transform2D {
- M_Vector2 elements[3];
-
- static _FORCE_INLINE_ Transform2D convert_to(const M_Transform2D &p_from) {
- return Transform2D(p_from.elements[0].x, p_from.elements[0].y,
- p_from.elements[1].x, p_from.elements[1].y,
- p_from.elements[2].x, p_from.elements[2].y);
- }
-
- static _FORCE_INLINE_ M_Transform2D convert_from(const Transform2D &p_from) {
- M_Transform2D ret = {
- M_Vector2::convert_from(p_from.columns[0]),
- M_Vector2::convert_from(p_from.columns[1]),
- M_Vector2::convert_from(p_from.columns[2])
- };
- return ret;
- }
-};
-
-struct M_Vector3 {
- real_t x, y, z;
-
- static _FORCE_INLINE_ Vector3 convert_to(const M_Vector3 &p_from) {
- return Vector3(p_from.x, p_from.y, p_from.z);
- }
-
- static _FORCE_INLINE_ M_Vector3 convert_from(const Vector3 &p_from) {
- M_Vector3 ret = { p_from.x, p_from.y, p_from.z };
- return ret;
- }
-};
-
-struct M_Vector3i {
- int32_t x, y, z;
-
- static _FORCE_INLINE_ Vector3i convert_to(const M_Vector3i &p_from) {
- return Vector3i(p_from.x, p_from.y, p_from.z);
- }
-
- static _FORCE_INLINE_ M_Vector3i convert_from(const Vector3i &p_from) {
- M_Vector3i ret = { p_from.x, p_from.y, p_from.z };
- return ret;
- }
-};
-
-struct M_Vector4 {
- real_t x, y, z, w;
-
- static _FORCE_INLINE_ Vector4 convert_to(const M_Vector4 &p_from) {
- return Vector4(p_from.x, p_from.y, p_from.z, p_from.w);
- }
-
- static _FORCE_INLINE_ M_Vector4 convert_from(const Vector4 &p_from) {
- M_Vector4 ret = { p_from.x, p_from.y, p_from.z, p_from.w };
- return ret;
- }
-};
-
-struct M_Vector4i {
- int32_t x, y, z, w;
-
- static _FORCE_INLINE_ Vector4i convert_to(const M_Vector4i &p_from) {
- return Vector4i(p_from.x, p_from.y, p_from.z, p_from.w);
- }
-
- static _FORCE_INLINE_ M_Vector4i convert_from(const Vector4i &p_from) {
- M_Vector4i ret = { p_from.x, p_from.y, p_from.z, p_from.w };
- return ret;
- }
-};
-
-struct M_Basis {
- M_Vector3 elements[3];
-
- static _FORCE_INLINE_ Basis convert_to(const M_Basis &p_from) {
- return Basis(M_Vector3::convert_to(p_from.elements[0]),
- M_Vector3::convert_to(p_from.elements[1]),
- M_Vector3::convert_to(p_from.elements[2]));
- }
-
- static _FORCE_INLINE_ M_Basis convert_from(const Basis &p_from) {
- M_Basis ret = {
- M_Vector3::convert_from(p_from.rows[0]),
- M_Vector3::convert_from(p_from.rows[1]),
- M_Vector3::convert_from(p_from.rows[2])
- };
- return ret;
- }
-};
-
-struct M_Quaternion {
- real_t x, y, z, w;
-
- static _FORCE_INLINE_ Quaternion convert_to(const M_Quaternion &p_from) {
- return Quaternion(p_from.x, p_from.y, p_from.z, p_from.w);
- }
-
- static _FORCE_INLINE_ M_Quaternion convert_from(const Quaternion &p_from) {
- M_Quaternion ret = { p_from.x, p_from.y, p_from.z, p_from.w };
- return ret;
- }
-};
-
-struct M_Transform3D {
- M_Basis basis;
- M_Vector3 origin;
-
- static _FORCE_INLINE_ Transform3D convert_to(const M_Transform3D &p_from) {
- return Transform3D(M_Basis::convert_to(p_from.basis), M_Vector3::convert_to(p_from.origin));
- }
-
- static _FORCE_INLINE_ M_Transform3D convert_from(const Transform3D &p_from) {
- M_Transform3D ret = { M_Basis::convert_from(p_from.basis), M_Vector3::convert_from(p_from.origin) };
- return ret;
- }
-};
-
-struct M_Projection {
- M_Vector4 vec1;
- M_Vector4 vec2;
- M_Vector4 vec3;
- M_Vector4 vec4;
-
- static _FORCE_INLINE_ Projection convert_to(const M_Projection &p_from) {
- return Projection(M_Vector4::convert_to(p_from.vec1), M_Vector4::convert_to(p_from.vec2), M_Vector4::convert_to(p_from.vec3), M_Vector4::convert_to(p_from.vec4));
- }
-
- static _FORCE_INLINE_ M_Projection convert_from(const Projection &p_from) {
- M_Projection ret = { M_Vector4::convert_from(p_from.matrix[0]), M_Vector4::convert_from(p_from.matrix[1]), M_Vector4::convert_from(p_from.matrix[2]), M_Vector4::convert_from(p_from.matrix[3]) };
- return ret;
- }
-};
-
-struct M_AABB {
- M_Vector3 position;
- M_Vector3 size;
-
- static _FORCE_INLINE_ AABB convert_to(const M_AABB &p_from) {
- return AABB(M_Vector3::convert_to(p_from.position), M_Vector3::convert_to(p_from.size));
- }
-
- static _FORCE_INLINE_ M_AABB convert_from(const AABB &p_from) {
- M_AABB ret = { M_Vector3::convert_from(p_from.position), M_Vector3::convert_from(p_from.size) };
- return ret;
- }
-};
-
-struct M_Color {
- float r, g, b, a;
-
- static _FORCE_INLINE_ Color convert_to(const M_Color &p_from) {
- return Color(p_from.r, p_from.g, p_from.b, p_from.a);
- }
-
- static _FORCE_INLINE_ M_Color convert_from(const Color &p_from) {
- M_Color ret = { p_from.r, p_from.g, p_from.b, p_from.a };
- return ret;
- }
-};
-
-struct M_Plane {
- M_Vector3 normal;
- real_t d;
-
- static _FORCE_INLINE_ Plane convert_to(const M_Plane &p_from) {
- return Plane(M_Vector3::convert_to(p_from.normal), p_from.d);
- }
-
- static _FORCE_INLINE_ M_Plane convert_from(const Plane &p_from) {
- M_Plane ret = { M_Vector3::convert_from(p_from.normal), p_from.d };
- return ret;
- }
-};
-
-#pragma pack(pop)
-
-#define DECL_TYPE_MARSHAL_TEMPLATES(m_type) \
- template <int> \
- _FORCE_INLINE_ m_type marshalled_in_##m_type##_impl(const M_##m_type *p_from); \
- \
- template <> \
- _FORCE_INLINE_ m_type marshalled_in_##m_type##_impl<0>(const M_##m_type *p_from) { \
- return M_##m_type::convert_to(*p_from); \
- } \
- \
- template <> \
- _FORCE_INLINE_ m_type marshalled_in_##m_type##_impl<1>(const M_##m_type *p_from) { \
- return *reinterpret_cast<const m_type *>(p_from); \
- } \
- \
- _FORCE_INLINE_ m_type marshalled_in_##m_type(const M_##m_type *p_from) { \
- return marshalled_in_##m_type##_impl<InteropLayout::MATCHES_##m_type>(p_from); \
- } \
- \
- template <int> \
- _FORCE_INLINE_ M_##m_type marshalled_out_##m_type##_impl(const m_type &p_from); \
- \
- template <> \
- _FORCE_INLINE_ M_##m_type marshalled_out_##m_type##_impl<0>(const m_type &p_from) { \
- return M_##m_type::convert_from(p_from); \
- } \
- \
- template <> \
- _FORCE_INLINE_ M_##m_type marshalled_out_##m_type##_impl<1>(const m_type &p_from) { \
- return *reinterpret_cast<const M_##m_type *>(&p_from); \
- } \
- \
- _FORCE_INLINE_ M_##m_type marshalled_out_##m_type(const m_type &p_from) { \
- return marshalled_out_##m_type##_impl<InteropLayout::MATCHES_##m_type>(p_from); \
- }
-
-DECL_TYPE_MARSHAL_TEMPLATES(Vector2)
-DECL_TYPE_MARSHAL_TEMPLATES(Vector2i)
-DECL_TYPE_MARSHAL_TEMPLATES(Rect2)
-DECL_TYPE_MARSHAL_TEMPLATES(Rect2i)
-DECL_TYPE_MARSHAL_TEMPLATES(Transform2D)
-DECL_TYPE_MARSHAL_TEMPLATES(Vector3)
-DECL_TYPE_MARSHAL_TEMPLATES(Vector3i)
-DECL_TYPE_MARSHAL_TEMPLATES(Basis)
-DECL_TYPE_MARSHAL_TEMPLATES(Vector4)
-DECL_TYPE_MARSHAL_TEMPLATES(Vector4i)
-DECL_TYPE_MARSHAL_TEMPLATES(Quaternion)
-DECL_TYPE_MARSHAL_TEMPLATES(Transform3D)
-DECL_TYPE_MARSHAL_TEMPLATES(Projection)
-DECL_TYPE_MARSHAL_TEMPLATES(AABB)
-DECL_TYPE_MARSHAL_TEMPLATES(Color)
-DECL_TYPE_MARSHAL_TEMPLATES(Plane)
-
-#define MARSHALLED_IN(m_type, m_from_ptr) (GDMonoMarshal::marshalled_in_##m_type(m_from_ptr))
-#define MARSHALLED_OUT(m_type, m_from) (GDMonoMarshal::marshalled_out_##m_type(m_from))
-} // namespace GDMonoMarshal
-
-#endif // GD_MONO_MARSHAL_H
diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp
deleted file mode 100644
index 6734b44783..0000000000
--- a/modules/mono/mono_gd/gd_mono_method.cpp
+++ /dev/null
@@ -1,296 +0,0 @@
-/*************************************************************************/
-/* gd_mono_method.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "gd_mono_method.h"
-
-#include <mono/metadata/attrdefs.h>
-#include <mono/metadata/debug-helpers.h>
-
-#include "gd_mono_cache.h"
-#include "gd_mono_class.h"
-#include "gd_mono_marshal.h"
-#include "gd_mono_utils.h"
-
-void GDMonoMethod::_update_signature() {
- // Apparently MonoMethodSignature needs not to be freed.
- // mono_method_signature caches the result, we don't need to cache it ourselves.
-
- MonoMethodSignature *method_sig = mono_method_signature(mono_method);
- _update_signature(method_sig);
-}
-
-void GDMonoMethod::_update_signature(MonoMethodSignature *p_method_sig) {
- params_count = mono_signature_get_param_count(p_method_sig);
-
- MonoType *ret_type = mono_signature_get_return_type(p_method_sig);
- if (ret_type) {
- return_type.type_encoding = mono_type_get_type(ret_type);
-
- if (return_type.type_encoding != MONO_TYPE_VOID) {
- MonoClass *ret_type_class = mono_class_from_mono_type(ret_type);
- return_type.type_class = GDMono::get_singleton()->get_class(ret_type_class);
- }
- }
-
- void *iter = nullptr;
- MonoType *param_raw_type;
- while ((param_raw_type = mono_signature_get_params(p_method_sig, &iter)) != nullptr) {
- ManagedType param_type;
-
- param_type.type_encoding = mono_type_get_type(param_raw_type);
-
- MonoClass *param_type_class = mono_class_from_mono_type(param_raw_type);
- param_type.type_class = GDMono::get_singleton()->get_class(param_type_class);
-
- param_types.push_back(param_type);
- }
-
- // clear the cache
- method_info_fetched = false;
- method_info = MethodInfo();
-
- for (int i = 0; i < params_count; i++) {
- params_buffer_size += GDMonoMarshal::variant_get_managed_unboxed_size(param_types[i]);
- }
-}
-
-GDMonoClass *GDMonoMethod::get_enclosing_class() const {
- return GDMono::get_singleton()->get_class(mono_method_get_class(mono_method));
-}
-
-bool GDMonoMethod::is_static() {
- return mono_method_get_flags(mono_method, nullptr) & MONO_METHOD_ATTR_STATIC;
-}
-
-IMonoClassMember::Visibility GDMonoMethod::get_visibility() {
- switch (mono_method_get_flags(mono_method, nullptr) & MONO_METHOD_ATTR_ACCESS_MASK) {
- case MONO_METHOD_ATTR_PRIVATE:
- return IMonoClassMember::PRIVATE;
- case MONO_METHOD_ATTR_FAM_AND_ASSEM:
- return IMonoClassMember::PROTECTED_AND_INTERNAL;
- case MONO_METHOD_ATTR_ASSEM:
- return IMonoClassMember::INTERNAL;
- case MONO_METHOD_ATTR_FAMILY:
- return IMonoClassMember::PROTECTED;
- case MONO_METHOD_ATTR_PUBLIC:
- return IMonoClassMember::PUBLIC;
- default:
- ERR_FAIL_V(IMonoClassMember::PRIVATE);
- }
-}
-
-MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc) const {
- MonoException *exc = nullptr;
- MonoObject *ret;
-
- if (params_count > 0) {
- void **params = (void **)alloca(params_count * sizeof(void *));
- uint8_t *buffer = (uint8_t *)alloca(params_buffer_size);
- unsigned int offset = 0;
-
- for (int i = 0; i < params_count; i++) {
- params[i] = GDMonoMarshal::variant_to_managed_unboxed(p_params[i], param_types[i], buffer + offset, offset);
- }
-
- ret = GDMonoUtils::runtime_invoke(mono_method, p_object, params, &exc);
- } else {
- ret = GDMonoUtils::runtime_invoke(mono_method, p_object, nullptr, &exc);
- }
-
- if (exc) {
- ret = nullptr;
- if (r_exc) {
- *r_exc = exc;
- } else {
- GDMonoUtils::set_pending_exception(exc);
- }
- }
-
- return ret;
-}
-
-MonoObject *GDMonoMethod::invoke(MonoObject *p_object, MonoException **r_exc) const {
- ERR_FAIL_COND_V(get_parameters_count() > 0, nullptr);
- return invoke_raw(p_object, nullptr, r_exc);
-}
-
-MonoObject *GDMonoMethod::invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc) const {
- MonoException *exc = nullptr;
- MonoObject *ret = GDMonoUtils::runtime_invoke(mono_method, p_object, p_params, &exc);
-
- if (exc) {
- ret = nullptr;
- if (r_exc) {
- *r_exc = exc;
- } else {
- GDMonoUtils::set_pending_exception(exc);
- }
- }
-
- return ret;
-}
-
-bool GDMonoMethod::has_attribute(GDMonoClass *p_attr_class) {
- ERR_FAIL_NULL_V(p_attr_class, false);
-
- if (!attrs_fetched) {
- fetch_attributes();
- }
-
- if (!attributes) {
- return false;
- }
-
- return mono_custom_attrs_has_attr(attributes, p_attr_class->get_mono_ptr());
-}
-
-MonoObject *GDMonoMethod::get_attribute(GDMonoClass *p_attr_class) {
- ERR_FAIL_NULL_V(p_attr_class, nullptr);
-
- if (!attrs_fetched) {
- fetch_attributes();
- }
-
- if (!attributes) {
- return nullptr;
- }
-
- return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr());
-}
-
-void GDMonoMethod::fetch_attributes() {
- ERR_FAIL_COND(attributes != nullptr);
- attributes = mono_custom_attrs_from_method(mono_method);
- attrs_fetched = true;
-}
-
-String GDMonoMethod::get_full_name(bool p_signature) const {
- char *res = mono_method_full_name(mono_method, p_signature);
- String full_name(res);
- mono_free(res);
- return full_name;
-}
-
-String GDMonoMethod::get_full_name_no_class() const {
- String res;
-
- MonoMethodSignature *method_sig = mono_method_signature(mono_method);
-
- char *ret_str = mono_type_full_name(mono_signature_get_return_type(method_sig));
- res += ret_str;
- mono_free(ret_str);
-
- res += " ";
- res += name;
- res += "(";
-
- char *sig_desc = mono_signature_get_desc(method_sig, true);
- res += sig_desc;
- mono_free(sig_desc);
-
- res += ")";
-
- return res;
-}
-
-String GDMonoMethod::get_ret_type_full_name() const {
- MonoMethodSignature *method_sig = mono_method_signature(mono_method);
- char *ret_str = mono_type_full_name(mono_signature_get_return_type(method_sig));
- String res = ret_str;
- mono_free(ret_str);
- return res;
-}
-
-String GDMonoMethod::get_signature_desc(bool p_namespaces) const {
- MonoMethodSignature *method_sig = mono_method_signature(mono_method);
- char *sig_desc = mono_signature_get_desc(method_sig, p_namespaces);
- String res = sig_desc;
- mono_free(sig_desc);
- return res;
-}
-
-void GDMonoMethod::get_parameter_names(Vector<StringName> &names) const {
- if (params_count > 0) {
- const char **_names = memnew_arr(const char *, params_count);
- mono_method_get_param_names(mono_method, _names);
- for (int i = 0; i < params_count; ++i) {
- names.push_back(StringName(_names[i]));
- }
- memdelete_arr(_names);
- }
-}
-
-void GDMonoMethod::get_parameter_types(Vector<ManagedType> &types) const {
- for (int i = 0; i < params_count; ++i) {
- types.push_back(param_types[i]);
- }
-}
-
-const MethodInfo &GDMonoMethod::get_method_info() {
- if (!method_info_fetched) {
- method_info.name = name;
-
- bool nil_is_variant = false;
- method_info.return_val = PropertyInfo(GDMonoMarshal::managed_to_variant_type(return_type, &nil_is_variant), "");
- if (method_info.return_val.type == Variant::NIL && nil_is_variant) {
- method_info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- }
-
- Vector<StringName> names;
- get_parameter_names(names);
-
- for (int i = 0; i < params_count; ++i) {
- nil_is_variant = false;
- PropertyInfo arg_info = PropertyInfo(GDMonoMarshal::managed_to_variant_type(param_types[i], &nil_is_variant), names[i]);
- if (arg_info.type == Variant::NIL && nil_is_variant) {
- arg_info.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- }
-
- method_info.arguments.push_back(arg_info);
- }
-
- // TODO: default arguments
-
- method_info_fetched = true;
- }
-
- return method_info;
-}
-
-GDMonoMethod::GDMonoMethod(StringName p_name, MonoMethod *p_method) :
- name(p_name), mono_method(p_method) {
- _update_signature();
-}
-
-GDMonoMethod::~GDMonoMethod() {
- if (attributes) {
- mono_custom_attrs_free(attributes);
- }
-}
diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h
deleted file mode 100644
index be11ef5bfe..0000000000
--- a/modules/mono/mono_gd/gd_mono_method.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*************************************************************************/
-/* gd_mono_method.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GD_MONO_METHOD_H
-#define GD_MONO_METHOD_H
-
-#include "gd_mono.h"
-#include "gd_mono_header.h"
-#include "i_mono_class_member.h"
-
-class GDMonoMethod : public IMonoClassMember {
- StringName name;
-
- uint16_t params_count;
- unsigned int params_buffer_size = 0;
- ManagedType return_type;
- Vector<ManagedType> param_types;
-
- bool method_info_fetched = false;
- MethodInfo method_info;
-
- bool attrs_fetched = false;
- MonoCustomAttrInfo *attributes = nullptr;
-
- void _update_signature();
- void _update_signature(MonoMethodSignature *p_method_sig);
-
- friend class GDMonoClass;
-
- MonoMethod *mono_method = nullptr;
-
-public:
- virtual GDMonoClass *get_enclosing_class() const final;
-
- virtual MemberType get_member_type() const final { return MEMBER_TYPE_METHOD; }
-
- virtual StringName get_name() const final { return name; }
-
- virtual bool is_static() final;
-
- virtual Visibility get_visibility() final;
-
- virtual bool has_attribute(GDMonoClass *p_attr_class) final;
- virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) final;
- void fetch_attributes();
-
- _FORCE_INLINE_ MonoMethod *get_mono_ptr() const { return mono_method; }
-
- _FORCE_INLINE_ uint16_t get_parameters_count() const { return params_count; }
- _FORCE_INLINE_ ManagedType get_return_type() const { return return_type; }
-
- MonoObject *invoke(MonoObject *p_object, const Variant **p_params, MonoException **r_exc = nullptr) const;
- MonoObject *invoke(MonoObject *p_object, MonoException **r_exc = nullptr) const;
- MonoObject *invoke_raw(MonoObject *p_object, void **p_params, MonoException **r_exc = nullptr) const;
-
- String get_full_name(bool p_signature = false) const;
- String get_full_name_no_class() const;
- String get_ret_type_full_name() const;
- String get_signature_desc(bool p_namespaces = false) const;
-
- void get_parameter_names(Vector<StringName> &names) const;
- void get_parameter_types(Vector<ManagedType> &types) const;
-
- const MethodInfo &get_method_info();
-
- GDMonoMethod(StringName p_name, MonoMethod *p_method);
- ~GDMonoMethod();
-};
-
-#endif // GD_MONO_METHOD_H
diff --git a/modules/mono/mono_gd/gd_mono_method_thunk.h b/modules/mono/mono_gd/gd_mono_method_thunk.h
deleted file mode 100644
index 0180dee3ea..0000000000
--- a/modules/mono/mono_gd/gd_mono_method_thunk.h
+++ /dev/null
@@ -1,320 +0,0 @@
-/*************************************************************************/
-/* gd_mono_method_thunk.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GD_MONO_METHOD_THUNK_H
-#define GD_MONO_METHOD_THUNK_H
-
-#include <type_traits>
-
-#include "gd_mono_class.h"
-#include "gd_mono_header.h"
-#include "gd_mono_marshal.h"
-#include "gd_mono_method.h"
-#include "gd_mono_utils.h"
-
-#if !defined(JAVASCRIPT_ENABLED) && !defined(IOS_ENABLED)
-#define HAVE_METHOD_THUNKS
-#endif
-
-#ifdef HAVE_METHOD_THUNKS
-
-template <class... ParamTypes>
-struct GDMonoMethodThunk {
- typedef void(GD_MONO_STDCALL *M)(ParamTypes... p_args, MonoException **);
-
- M mono_method_thunk = nullptr;
-
-public:
- _FORCE_INLINE_ void invoke(ParamTypes... p_args, MonoException **r_exc) {
- GD_MONO_BEGIN_RUNTIME_INVOKE;
- mono_method_thunk(p_args..., r_exc);
- GD_MONO_END_RUNTIME_INVOKE;
- }
-
- _FORCE_INLINE_ bool is_null() {
- return mono_method_thunk == nullptr;
- }
-
- _FORCE_INLINE_ void nullify() {
- mono_method_thunk = nullptr;
- }
-
- _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(p_mono_method == nullptr);
- CRASH_COND(p_mono_method->get_return_type().type_encoding != MONO_TYPE_VOID);
-
- if (p_mono_method->is_static()) {
- CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes));
- } else {
- CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1));
- }
-#endif
- mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method->get_mono_ptr());
- }
-
- GDMonoMethodThunk() {}
-
- explicit GDMonoMethodThunk(GDMonoMethod *p_mono_method) {
- set_from_method(p_mono_method);
- }
-};
-
-template <class R, class... ParamTypes>
-struct GDMonoMethodThunkR {
- typedef R(GD_MONO_STDCALL *M)(ParamTypes... p_args, MonoException **);
-
- M mono_method_thunk = nullptr;
-
-public:
- _FORCE_INLINE_ R invoke(ParamTypes... p_args, MonoException **r_exc) {
- GD_MONO_BEGIN_RUNTIME_INVOKE;
- R r = mono_method_thunk(p_args..., r_exc);
- GD_MONO_END_RUNTIME_INVOKE;
- return r;
- }
-
- _FORCE_INLINE_ bool is_null() {
- return mono_method_thunk == nullptr;
- }
-
- _FORCE_INLINE_ void nullify() {
- mono_method_thunk = nullptr;
- }
-
- _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(p_mono_method == nullptr);
- CRASH_COND(p_mono_method->get_return_type().type_encoding == MONO_TYPE_VOID);
-
- if (p_mono_method->is_static()) {
- CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes));
- } else {
- CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1));
- }
-#endif
- mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method->get_mono_ptr());
- }
-
- GDMonoMethodThunkR() {}
-
- explicit GDMonoMethodThunkR(GDMonoMethod *p_mono_method) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(p_mono_method == nullptr);
-#endif
- mono_method_thunk = (M)mono_method_get_unmanaged_thunk(p_mono_method->get_mono_ptr());
- }
-};
-
-#else
-
-template <unsigned int ThunkParamCount, class P1, class... ParamTypes>
-struct VariadicInvokeMonoMethodImpl {
- static void invoke(GDMonoMethod *p_mono_method, P1 p_arg1, ParamTypes... p_args, MonoException **r_exc) {
- if (p_mono_method->is_static()) {
- void *args[ThunkParamCount] = { p_arg1, p_args... };
- p_mono_method->invoke_raw(nullptr, args, r_exc);
- } else {
- void *args[ThunkParamCount] = { p_args... };
- p_mono_method->invoke_raw((MonoObject *)p_arg1, args, r_exc);
- }
- }
-};
-
-template <unsigned int ThunkParamCount, class... ParamTypes>
-struct VariadicInvokeMonoMethod {
- static void invoke(GDMonoMethod *p_mono_method, ParamTypes... p_args, MonoException **r_exc) {
- VariadicInvokeMonoMethodImpl<ThunkParamCount, ParamTypes...>::invoke(p_mono_method, p_args..., r_exc);
- }
-};
-
-template <>
-struct VariadicInvokeMonoMethod<0> {
- static void invoke(GDMonoMethod *p_mono_method, MonoException **r_exc) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(!p_mono_method->is_static());
-#endif
- p_mono_method->invoke_raw(nullptr, nullptr, r_exc);
- }
-};
-
-template <class P1>
-struct VariadicInvokeMonoMethod<1, P1> {
- static void invoke(GDMonoMethod *p_mono_method, P1 p_arg1, MonoException **r_exc) {
- if (p_mono_method->is_static()) {
- void *args[1] = { p_arg1 };
- p_mono_method->invoke_raw(nullptr, args, r_exc);
- } else {
- p_mono_method->invoke_raw((MonoObject *)p_arg1, nullptr, r_exc);
- }
- }
-};
-
-template <class R>
-R unbox_if_needed(MonoObject *p_val, const ManagedType &, typename std::enable_if<!std::is_pointer<R>::value>::type * = 0) {
- return GDMonoMarshal::unbox<R>(p_val);
-}
-
-template <class R>
-R unbox_if_needed(MonoObject *p_val, const ManagedType &p_type, typename std::enable_if<std::is_pointer<R>::value>::type * = 0) {
- if (mono_class_is_valuetype(p_type.type_class->get_mono_ptr())) {
- return GDMonoMarshal::unbox<R>(p_val);
- } else {
- // If it's not a value type, we assume 'R' is a pointer to 'MonoObject' or a compatible type, like 'MonoException'.
- return (R)p_val;
- }
-}
-
-template <unsigned int ThunkParamCount, class R, class P1, class... ParamTypes>
-struct VariadicInvokeMonoMethodRImpl {
- static R invoke(GDMonoMethod *p_mono_method, P1 p_arg1, ParamTypes... p_args, MonoException **r_exc) {
- if (p_mono_method->is_static()) {
- void *args[ThunkParamCount] = { p_arg1, p_args... };
- MonoObject *r = p_mono_method->invoke_raw(nullptr, args, r_exc);
- return unbox_if_needed<R>(r, p_mono_method->get_return_type());
- } else {
- void *args[ThunkParamCount] = { p_args... };
- MonoObject *r = p_mono_method->invoke_raw((MonoObject *)p_arg1, args, r_exc);
- return unbox_if_needed<R>(r, p_mono_method->get_return_type());
- }
- }
-};
-
-template <unsigned int ThunkParamCount, class R, class... ParamTypes>
-struct VariadicInvokeMonoMethodR {
- static R invoke(GDMonoMethod *p_mono_method, ParamTypes... p_args, MonoException **r_exc) {
- return VariadicInvokeMonoMethodRImpl<ThunkParamCount, R, ParamTypes...>::invoke(p_mono_method, p_args..., r_exc);
- }
-};
-
-template <class R>
-struct VariadicInvokeMonoMethodR<0, R> {
- static R invoke(GDMonoMethod *p_mono_method, MonoException **r_exc) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(!p_mono_method->is_static());
-#endif
- MonoObject *r = p_mono_method->invoke_raw(nullptr, nullptr, r_exc);
- return unbox_if_needed<R>(r, p_mono_method->get_return_type());
- }
-};
-
-template <class R, class P1>
-struct VariadicInvokeMonoMethodR<1, R, P1> {
- static R invoke(GDMonoMethod *p_mono_method, P1 p_arg1, MonoException **r_exc) {
- if (p_mono_method->is_static()) {
- void *args[1] = { p_arg1 };
- MonoObject *r = p_mono_method->invoke_raw(nullptr, args, r_exc);
- return unbox_if_needed<R>(r, p_mono_method->get_return_type());
- } else {
- MonoObject *r = p_mono_method->invoke_raw((MonoObject *)p_arg1, nullptr, r_exc);
- return unbox_if_needed<R>(r, p_mono_method->get_return_type());
- }
- }
-};
-
-template <class... ParamTypes>
-struct GDMonoMethodThunk {
- GDMonoMethod *mono_method = nullptr;
-
-public:
- _FORCE_INLINE_ void invoke(ParamTypes... p_args, MonoException **r_exc) {
- VariadicInvokeMonoMethod<sizeof...(ParamTypes), ParamTypes...>::invoke(mono_method, p_args..., r_exc);
- }
-
- _FORCE_INLINE_ bool is_null() {
- return mono_method == nullptr;
- }
-
- _FORCE_INLINE_ void nullify() {
- mono_method = nullptr;
- }
-
- _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(p_mono_method == nullptr);
- CRASH_COND(p_mono_method->get_return_type().type_encoding != MONO_TYPE_VOID);
-
- if (p_mono_method->is_static()) {
- CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes));
- } else {
- CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1));
- }
-#endif
- mono_method = p_mono_method;
- }
-
- GDMonoMethodThunk() {}
-
- explicit GDMonoMethodThunk(GDMonoMethod *p_mono_method) {
- set_from_method(p_mono_method);
- }
-};
-
-template <class R, class... ParamTypes>
-struct GDMonoMethodThunkR {
- GDMonoMethod *mono_method = nullptr;
-
-public:
- _FORCE_INLINE_ R invoke(ParamTypes... p_args, MonoException **r_exc) {
- return VariadicInvokeMonoMethodR<sizeof...(ParamTypes), R, ParamTypes...>::invoke(mono_method, p_args..., r_exc);
- }
-
- _FORCE_INLINE_ bool is_null() {
- return mono_method == nullptr;
- }
-
- _FORCE_INLINE_ void nullify() {
- mono_method = nullptr;
- }
-
- _FORCE_INLINE_ void set_from_method(GDMonoMethod *p_mono_method) {
-#ifdef DEBUG_ENABLED
- CRASH_COND(p_mono_method == nullptr);
- CRASH_COND(p_mono_method->get_return_type().type_encoding == MONO_TYPE_VOID);
-
- if (p_mono_method->is_static()) {
- CRASH_COND(p_mono_method->get_parameters_count() != sizeof...(ParamTypes));
- } else {
- CRASH_COND(p_mono_method->get_parameters_count() != (sizeof...(ParamTypes) - 1));
- }
-#endif
- mono_method = p_mono_method;
- }
-
- GDMonoMethodThunkR() {}
-
- explicit GDMonoMethodThunkR(GDMonoMethod *p_mono_method) {
- set_from_method(p_mono_method);
- }
-};
-
-#endif
-
-#endif // GD_MONO_METHOD_THUNK_H
diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp
deleted file mode 100644
index c9775ae9cb..0000000000
--- a/modules/mono/mono_gd/gd_mono_property.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-/*************************************************************************/
-/* gd_mono_property.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "gd_mono_property.h"
-
-#include "gd_mono_cache.h"
-#include "gd_mono_class.h"
-#include "gd_mono_marshal.h"
-#include "gd_mono_utils.h"
-
-#include <mono/metadata/attrdefs.h>
-
-GDMonoProperty::GDMonoProperty(MonoProperty *p_mono_property, GDMonoClass *p_owner) {
- owner = p_owner;
- mono_property = p_mono_property;
- name = String::utf8(mono_property_get_name(mono_property));
-
- MonoMethod *prop_method = mono_property_get_get_method(mono_property);
-
- if (prop_method) {
- MonoMethodSignature *getter_sig = mono_method_signature(prop_method);
-
- MonoType *ret_type = mono_signature_get_return_type(getter_sig);
-
- type.type_encoding = mono_type_get_type(ret_type);
- MonoClass *ret_type_class = mono_class_from_mono_type(ret_type);
- type.type_class = GDMono::get_singleton()->get_class(ret_type_class);
- } else {
- prop_method = mono_property_get_set_method(mono_property);
-
- MonoMethodSignature *setter_sig = mono_method_signature(prop_method);
-
- void *iter = nullptr;
- MonoType *param_raw_type = mono_signature_get_params(setter_sig, &iter);
-
- type.type_encoding = mono_type_get_type(param_raw_type);
- MonoClass *param_type_class = mono_class_from_mono_type(param_raw_type);
- type.type_class = GDMono::get_singleton()->get_class(param_type_class);
- }
-
- param_buffer_size = GDMonoMarshal::variant_get_managed_unboxed_size(type);
-
- attrs_fetched = false;
- attributes = nullptr;
-}
-
-GDMonoProperty::~GDMonoProperty() {
- if (attributes) {
- mono_custom_attrs_free(attributes);
- }
-}
-
-bool GDMonoProperty::is_static() {
- MonoMethod *prop_method = mono_property_get_get_method(mono_property);
- if (prop_method == nullptr) {
- prop_method = mono_property_get_set_method(mono_property);
- }
- return mono_method_get_flags(prop_method, nullptr) & MONO_METHOD_ATTR_STATIC;
-}
-
-IMonoClassMember::Visibility GDMonoProperty::get_visibility() {
- MonoMethod *prop_method = mono_property_get_get_method(mono_property);
- if (prop_method == nullptr) {
- prop_method = mono_property_get_set_method(mono_property);
- }
-
- switch (mono_method_get_flags(prop_method, nullptr) & MONO_METHOD_ATTR_ACCESS_MASK) {
- case MONO_METHOD_ATTR_PRIVATE:
- return IMonoClassMember::PRIVATE;
- case MONO_METHOD_ATTR_FAM_AND_ASSEM:
- return IMonoClassMember::PROTECTED_AND_INTERNAL;
- case MONO_METHOD_ATTR_ASSEM:
- return IMonoClassMember::INTERNAL;
- case MONO_METHOD_ATTR_FAMILY:
- return IMonoClassMember::PROTECTED;
- case MONO_METHOD_ATTR_PUBLIC:
- return IMonoClassMember::PUBLIC;
- default:
- ERR_FAIL_V(IMonoClassMember::PRIVATE);
- }
-}
-
-bool GDMonoProperty::has_attribute(GDMonoClass *p_attr_class) {
- ERR_FAIL_NULL_V(p_attr_class, false);
-
- if (!attrs_fetched) {
- fetch_attributes();
- }
-
- if (!attributes) {
- return false;
- }
-
- return mono_custom_attrs_has_attr(attributes, p_attr_class->get_mono_ptr());
-}
-
-MonoObject *GDMonoProperty::get_attribute(GDMonoClass *p_attr_class) {
- ERR_FAIL_NULL_V(p_attr_class, nullptr);
-
- if (!attrs_fetched) {
- fetch_attributes();
- }
-
- if (!attributes) {
- return nullptr;
- }
-
- return mono_custom_attrs_get_attr(attributes, p_attr_class->get_mono_ptr());
-}
-
-void GDMonoProperty::fetch_attributes() {
- ERR_FAIL_COND(attributes != nullptr);
- attributes = mono_custom_attrs_from_property(owner->get_mono_ptr(), mono_property);
- attrs_fetched = true;
-}
-
-bool GDMonoProperty::has_getter() {
- return mono_property_get_get_method(mono_property) != nullptr;
-}
-
-bool GDMonoProperty::has_setter() {
- return mono_property_get_set_method(mono_property) != nullptr;
-}
-
-void GDMonoProperty::set_value_from_variant(MonoObject *p_object, const Variant &p_value, MonoException **r_exc) {
- uint8_t *buffer = (uint8_t *)alloca(param_buffer_size);
- unsigned int offset = 0;
-
- void *params[1] = {
- GDMonoMarshal::variant_to_managed_unboxed(p_value, type, buffer, offset)
- };
-
-#ifdef DEBUG_ENABLED
- CRASH_COND(offset != param_buffer_size);
-#endif
-
- MonoException *exc = nullptr;
- GDMonoUtils::property_set_value(mono_property, p_object, params, &exc);
- if (exc) {
- if (r_exc) {
- *r_exc = exc;
- } else {
- GDMonoUtils::set_pending_exception(exc);
- }
- }
-}
-
-MonoObject *GDMonoProperty::get_value(MonoObject *p_object, MonoException **r_exc) {
- MonoException *exc = nullptr;
- MonoObject *ret = GDMonoUtils::property_get_value(mono_property, p_object, nullptr, &exc);
-
- if (exc) {
- ret = nullptr;
- if (r_exc) {
- *r_exc = exc;
- } else {
- GDMonoUtils::set_pending_exception(exc);
- }
- }
-
- return ret;
-}
-
-bool GDMonoProperty::get_bool_value(MonoObject *p_object) {
- return (bool)GDMonoMarshal::unbox<MonoBoolean>(get_value(p_object));
-}
-
-int GDMonoProperty::get_int_value(MonoObject *p_object) {
- return GDMonoMarshal::unbox<int32_t>(get_value(p_object));
-}
-
-String GDMonoProperty::get_string_value(MonoObject *p_object) {
- MonoObject *val = get_value(p_object);
- return GDMonoMarshal::mono_string_to_godot((MonoString *)val);
-}
diff --git a/modules/mono/mono_gd/gd_mono_property.h b/modules/mono/mono_gd/gd_mono_property.h
deleted file mode 100644
index 6fc681aeb5..0000000000
--- a/modules/mono/mono_gd/gd_mono_property.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*************************************************************************/
-/* gd_mono_property.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GD_MONO_PROPERTY_H
-#define GD_MONO_PROPERTY_H
-
-#include "gd_mono.h"
-#include "gd_mono_header.h"
-#include "i_mono_class_member.h"
-
-class GDMonoProperty : public IMonoClassMember {
- GDMonoClass *owner = nullptr;
- MonoProperty *mono_property = nullptr;
-
- StringName name;
- ManagedType type;
-
- bool attrs_fetched;
- MonoCustomAttrInfo *attributes = nullptr;
-
- unsigned int param_buffer_size;
-
-public:
- virtual GDMonoClass *get_enclosing_class() const final { return owner; }
-
- virtual MemberType get_member_type() const final { return MEMBER_TYPE_PROPERTY; }
-
- virtual StringName get_name() const final { return name; }
-
- virtual bool is_static() final;
- virtual Visibility get_visibility() final;
-
- virtual bool has_attribute(GDMonoClass *p_attr_class) final;
- virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) final;
- void fetch_attributes();
-
- bool has_getter();
- bool has_setter();
-
- _FORCE_INLINE_ ManagedType get_type() const { return type; }
-
- void set_value_from_variant(MonoObject *p_object, const Variant &p_value, MonoException **r_exc = nullptr);
- MonoObject *get_value(MonoObject *p_object, MonoException **r_exc = nullptr);
-
- bool get_bool_value(MonoObject *p_object);
- int get_int_value(MonoObject *p_object);
- String get_string_value(MonoObject *p_object);
-
- GDMonoProperty(MonoProperty *p_mono_property, GDMonoClass *p_owner);
- ~GDMonoProperty();
-};
-
-#endif // GD_MONO_PROPERTY_H
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
deleted file mode 100644
index 1983d6ebe2..0000000000
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ /dev/null
@@ -1,677 +0,0 @@
-/*************************************************************************/
-/* gd_mono_utils.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "gd_mono_utils.h"
-
-#include <mono/metadata/debug-helpers.h>
-#include <mono/metadata/exception.h>
-
-#include "core/debugger/engine_debugger.h"
-#include "core/debugger/script_debugger.h"
-#include "core/io/dir_access.h"
-#include "core/object/ref_counted.h"
-#include "core/os/mutex.h"
-#include "core/os/os.h"
-
-#ifdef TOOLS_ENABLED
-#include "editor/debugger/editor_debugger_node.h"
-#endif
-
-#include "../csharp_script.h"
-#include "../utils/macros.h"
-#include "gd_mono.h"
-#include "gd_mono_cache.h"
-#include "gd_mono_class.h"
-#include "gd_mono_marshal.h"
-
-namespace GDMonoUtils {
-
-MonoObject *unmanaged_get_managed(Object *unmanaged) {
- if (!unmanaged) {
- return nullptr;
- }
-
- if (unmanaged->get_script_instance()) {
- CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(unmanaged->get_script_instance());
-
- if (cs_instance) {
- return cs_instance->get_mono_object();
- }
- }
-
- // If the owner does not have a CSharpInstance...
-
- void *data = CSharpLanguage::get_instance_binding(unmanaged);
- ERR_FAIL_NULL_V(data, nullptr);
- CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->value();
- ERR_FAIL_COND_V(!script_binding.inited, nullptr);
-
- MonoGCHandleData &gchandle = script_binding.gchandle;
-
- MonoObject *target = gchandle.get_target();
-
- if (target) {
- return target;
- }
-
- CSharpLanguage::get_singleton()->release_script_gchandle(gchandle);
-
- // Create a new one
-
-#ifdef DEBUG_ENABLED
- CRASH_COND(script_binding.type_name == StringName());
- CRASH_COND(script_binding.wrapper_class == nullptr);
-#endif
-
- MonoObject *mono_object = GDMonoUtils::create_managed_for_godot_object(script_binding.wrapper_class, script_binding.type_name, unmanaged);
- ERR_FAIL_NULL_V(mono_object, nullptr);
-
- gchandle = MonoGCHandleData::new_strong_handle(mono_object);
-
- // Tie managed to unmanaged
- RefCounted *rc = Object::cast_to<RefCounted>(unmanaged);
-
- if (rc) {
- // Unsafe refcount increment. The managed instance also counts as a reference.
- // This way if the unmanaged world has no references to our owner
- // but the managed instance is alive, the refcount will be 1 instead of 0.
- // See: godot_icall_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr)
- rc->reference();
- CSharpLanguage::get_singleton()->post_unsafe_reference(rc);
- }
-
- return mono_object;
-}
-
-void set_main_thread(MonoThread *p_thread) {
- mono_thread_set_main(p_thread);
-}
-
-MonoThread *attach_current_thread() {
- ERR_FAIL_COND_V(!GDMono::get_singleton()->is_runtime_initialized(), nullptr);
- MonoDomain *scripts_domain = GDMono::get_singleton()->get_scripts_domain();
-#ifndef GD_MONO_SINGLE_APPDOMAIN
- MonoThread *mono_thread = mono_thread_attach(scripts_domain ? scripts_domain : mono_get_root_domain());
-#else
- // The scripts domain is the root domain
- MonoThread *mono_thread = mono_thread_attach(scripts_domain);
-#endif
- ERR_FAIL_NULL_V(mono_thread, nullptr);
- return mono_thread;
-}
-
-void detach_current_thread() {
- ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized());
- MonoThread *mono_thread = mono_thread_current();
- ERR_FAIL_NULL(mono_thread);
- mono_thread_detach(mono_thread);
-}
-
-void detach_current_thread(MonoThread *p_mono_thread) {
- ERR_FAIL_COND(!GDMono::get_singleton()->is_runtime_initialized());
- ERR_FAIL_NULL(p_mono_thread);
- mono_thread_detach(p_mono_thread);
-}
-
-MonoThread *get_current_thread() {
- return mono_thread_current();
-}
-
-bool is_thread_attached() {
- return mono_domain_get() != nullptr;
-}
-
-uint32_t new_strong_gchandle(MonoObject *p_object) {
- return mono_gchandle_new(p_object, /* pinned: */ false);
-}
-
-uint32_t new_strong_gchandle_pinned(MonoObject *p_object) {
- return mono_gchandle_new(p_object, /* pinned: */ true);
-}
-
-uint32_t new_weak_gchandle(MonoObject *p_object) {
- return mono_gchandle_new_weakref(p_object, /* track_resurrection: */ false);
-}
-
-void free_gchandle(uint32_t p_gchandle) {
- mono_gchandle_free(p_gchandle);
-}
-
-void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoException **r_exc) {
- GDMonoMethod *ctor = p_class->get_method(".ctor", 0);
- ERR_FAIL_NULL(ctor);
- ctor->invoke_raw(p_this_obj, nullptr, r_exc);
-}
-
-bool mono_delegate_equal(MonoDelegate *p_a, MonoDelegate *p_b) {
- MonoException *exc = nullptr;
- MonoBoolean res = CACHED_METHOD_THUNK(Delegate, Equals).invoke((MonoObject *)p_a, (MonoObject *)p_b, &exc);
- UNHANDLED_EXCEPTION(exc);
- return (bool)res;
-}
-
-GDMonoClass *get_object_class(MonoObject *p_object) {
- return GDMono::get_singleton()->get_class(mono_object_get_class(p_object));
-}
-
-GDMonoClass *type_get_proxy_class(const StringName &p_type) {
- String class_name = p_type;
-
- if (class_name[0] == '_') {
- class_name = class_name.substr(1, class_name.length());
- }
-
- GDMonoClass *klass = GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, class_name);
-
- if (klass && klass->is_static()) {
- // A static class means this is a Godot singleton class. If an instance is needed we use Godot.Object.
- return GDMonoCache::cached_data.class_GodotObject;
- }
-
-#ifdef TOOLS_ENABLED
- if (!klass) {
- return GDMono::get_singleton()->get_editor_api_assembly()->get_class(BINDINGS_NAMESPACE, class_name);
- }
-#endif
-
- return klass;
-}
-
-GDMonoClass *get_class_native_base(GDMonoClass *p_class) {
- GDMonoClass *klass = p_class;
-
- do {
- const GDMonoAssembly *assembly = klass->get_assembly();
-
- if (assembly == GDMono::get_singleton()->get_core_api_assembly()) {
- return klass;
- }
-#ifdef TOOLS_ENABLED
- if (assembly == GDMono::get_singleton()->get_editor_api_assembly()) {
- return klass;
- }
-#endif
- } while ((klass = klass->get_parent_class()) != nullptr);
-
- return nullptr;
-}
-
-MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringName &p_native, Object *p_object) {
- bool parent_is_object_class = ClassDB::is_parent_class(p_object->get_class_name(), p_native);
- ERR_FAIL_COND_V_MSG(!parent_is_object_class, nullptr,
- "Type inherits from native type '" + p_native + "', so it can't be instantiated in object of type: '" + p_object->get_class() + "'.");
-
- MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr());
- ERR_FAIL_NULL_V(mono_object, nullptr);
-
- CACHED_FIELD(GodotObject, ptr)->set_value_raw(mono_object, p_object);
-
- // Construct
- GDMonoUtils::runtime_object_init(mono_object, p_class);
-
- return mono_object;
-}
-
-MonoObject *create_managed_from(const StringName &p_from) {
- MonoObject *mono_object = mono_object_new(mono_domain_get(), CACHED_CLASS_RAW(StringName));
- ERR_FAIL_NULL_V(mono_object, nullptr);
-
- // Construct
- GDMonoUtils::runtime_object_init(mono_object, CACHED_CLASS(StringName));
-
- CACHED_FIELD(StringName, ptr)->set_value_raw(mono_object, memnew(StringName(p_from)));
-
- return mono_object;
-}
-
-MonoObject *create_managed_from(const NodePath &p_from) {
- MonoObject *mono_object = mono_object_new(mono_domain_get(), CACHED_CLASS_RAW(NodePath));
- ERR_FAIL_NULL_V(mono_object, nullptr);
-
- // Construct
- GDMonoUtils::runtime_object_init(mono_object, CACHED_CLASS(NodePath));
-
- CACHED_FIELD(NodePath, ptr)->set_value_raw(mono_object, memnew(NodePath(p_from)));
-
- return mono_object;
-}
-
-MonoObject *create_managed_from(const RID &p_from) {
- MonoObject *mono_object = mono_object_new(mono_domain_get(), CACHED_CLASS_RAW(RID));
- ERR_FAIL_NULL_V(mono_object, nullptr);
-
- // Construct
- GDMonoUtils::runtime_object_init(mono_object, CACHED_CLASS(RID));
-
- CACHED_FIELD(RID, ptr)->set_value_raw(mono_object, memnew(RID(p_from)));
-
- return mono_object;
-}
-
-MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class) {
- MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr());
- ERR_FAIL_NULL_V(mono_object, nullptr);
-
- // Search constructor that takes a pointer as parameter
- MonoMethod *m;
- void *iter = nullptr;
- while ((m = mono_class_get_methods(p_class->get_mono_ptr(), &iter))) {
- if (strcmp(mono_method_get_name(m), ".ctor") == 0) {
- MonoMethodSignature *sig = mono_method_signature(m);
- void *front = nullptr;
- if (mono_signature_get_param_count(sig) == 1 &&
- mono_class_from_mono_type(mono_signature_get_params(sig, &front)) == CACHED_CLASS(IntPtr)->get_mono_ptr()) {
- break;
- }
- }
- }
-
- CRASH_COND(m == nullptr);
-
- Array *new_array = memnew(Array(p_from));
- void *args[1] = { &new_array };
-
- MonoException *exc = nullptr;
- GDMonoUtils::runtime_invoke(m, mono_object, args, &exc);
- UNHANDLED_EXCEPTION(exc);
-
- return mono_object;
-}
-
-MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class) {
- MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr());
- ERR_FAIL_NULL_V(mono_object, nullptr);
-
- // Search constructor that takes a pointer as parameter
- MonoMethod *m;
- void *iter = nullptr;
- while ((m = mono_class_get_methods(p_class->get_mono_ptr(), &iter))) {
- if (strcmp(mono_method_get_name(m), ".ctor") == 0) {
- MonoMethodSignature *sig = mono_method_signature(m);
- void *front = nullptr;
- if (mono_signature_get_param_count(sig) == 1 &&
- mono_class_from_mono_type(mono_signature_get_params(sig, &front)) == CACHED_CLASS(IntPtr)->get_mono_ptr()) {
- break;
- }
- }
- }
-
- CRASH_COND(m == nullptr);
-
- Dictionary *new_dict = memnew(Dictionary(p_from));
- void *args[1] = { &new_dict };
-
- MonoException *exc = nullptr;
- GDMonoUtils::runtime_invoke(m, mono_object, args, &exc);
- UNHANDLED_EXCEPTION(exc);
-
- return mono_object;
-}
-
-MonoDomain *create_domain(const String &p_friendly_name) {
- print_verbose("Mono: Creating domain '" + p_friendly_name + "'...");
-
- MonoDomain *domain = mono_domain_create_appdomain((char *)p_friendly_name.utf8().get_data(), nullptr);
-
- if (domain) {
- // Workaround to avoid this exception:
- // System.Configuration.ConfigurationErrorsException: Error Initializing the configuration system.
- // ---> System.ArgumentException: The 'ExeConfigFilename' argument cannot be null.
- mono_domain_set_config(domain, ".", "");
- }
-
- return domain;
-}
-
-String get_type_desc(MonoType *p_type) {
- return mono_type_full_name(p_type);
-}
-
-String get_type_desc(MonoReflectionType *p_reftype) {
- return get_type_desc(mono_reflection_type_get_type(p_reftype));
-}
-
-String get_exception_name_and_message(MonoException *p_exc) {
- String res;
-
- MonoClass *klass = mono_object_get_class((MonoObject *)p_exc);
- MonoType *type = mono_class_get_type(klass);
-
- char *full_name = mono_type_full_name(type);
- res += full_name;
- mono_free(full_name);
-
- res += ": ";
-
- MonoProperty *prop = mono_class_get_property_from_name(klass, "Message");
- MonoString *msg = (MonoString *)property_get_value(prop, (MonoObject *)p_exc, nullptr, nullptr);
- res += GDMonoMarshal::mono_string_to_godot(msg);
-
- return res;
-}
-
-void debug_print_unhandled_exception(MonoException *p_exc) {
- print_unhandled_exception(p_exc);
- debug_send_unhandled_exception_error(p_exc);
-}
-
-void debug_send_unhandled_exception_error(MonoException *p_exc) {
-#ifdef DEBUG_ENABLED
- if (!EngineDebugger::is_active()) {
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
- ERR_PRINT(GDMonoUtils::get_exception_name_and_message(p_exc));
- }
-#endif
- return;
- }
-
- static thread_local bool _recursion_flag_ = false;
- if (_recursion_flag_) {
- return;
- }
- _recursion_flag_ = true;
- SCOPE_EXIT { _recursion_flag_ = false; };
-
- ScriptLanguage::StackInfo separator;
- separator.file = String();
- separator.func = "--- " + RTR("End of inner exception stack trace") + " ---";
- separator.line = 0;
-
- Vector<ScriptLanguage::StackInfo> si;
- String exc_msg;
-
- while (p_exc != nullptr) {
- GDMonoClass *st_klass = CACHED_CLASS(System_Diagnostics_StackTrace);
- MonoObject *stack_trace = mono_object_new(mono_domain_get(), st_klass->get_mono_ptr());
-
- MonoBoolean need_file_info = true;
- void *ctor_args[2] = { p_exc, &need_file_info };
-
- MonoException *unexpected_exc = nullptr;
- CACHED_METHOD(System_Diagnostics_StackTrace, ctor_Exception_bool)->invoke_raw(stack_trace, ctor_args, &unexpected_exc);
-
- if (unexpected_exc) {
- GDMonoInternals::unhandled_exception(unexpected_exc);
- return;
- }
-
- Vector<ScriptLanguage::StackInfo> _si;
- if (stack_trace != nullptr) {
- _si = CSharpLanguage::get_singleton()->stack_trace_get_info(stack_trace);
- for (int i = _si.size() - 1; i >= 0; i--) {
- si.insert(0, _si[i]);
- }
- }
-
- exc_msg += (exc_msg.length() > 0 ? " ---> " : "") + GDMonoUtils::get_exception_name_and_message(p_exc);
-
- GDMonoClass *exc_class = GDMono::get_singleton()->get_class(mono_get_exception_class());
- GDMonoProperty *inner_exc_prop = exc_class->get_property("InnerException");
- CRASH_COND(inner_exc_prop == nullptr);
-
- MonoObject *inner_exc = inner_exc_prop->get_value((MonoObject *)p_exc);
- if (inner_exc != nullptr) {
- si.insert(0, separator);
- }
-
- p_exc = (MonoException *)inner_exc;
- }
-
- String file = si.size() ? si[0].file : __FILE__;
- String func = si.size() ? si[0].func : FUNCTION_STR;
- int line = si.size() ? si[0].line : __LINE__;
- String error_msg = "Unhandled exception";
-
- EngineDebugger::get_script_debugger()->send_error(func, file, line, error_msg, exc_msg, true, ERR_HANDLER_ERROR, si);
-#endif
-}
-
-void debug_unhandled_exception(MonoException *p_exc) {
- GDMonoInternals::unhandled_exception(p_exc); // prints the exception as well
-}
-
-void print_unhandled_exception(MonoException *p_exc) {
- mono_print_unhandled_exception((MonoObject *)p_exc);
-}
-
-void set_pending_exception(MonoException *p_exc) {
-#ifdef NO_PENDING_EXCEPTIONS
- debug_unhandled_exception(p_exc);
-#else
- if (get_runtime_invoke_count() == 0) {
- debug_unhandled_exception(p_exc);
- return;
- }
-
- if (!mono_runtime_set_pending_exception(p_exc, false)) {
- ERR_PRINT("Exception thrown from managed code, but it could not be set as pending:");
- GDMonoUtils::debug_print_unhandled_exception(p_exc);
- }
-#endif
-}
-
-thread_local int current_invoke_count = 0;
-
-MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **r_exc) {
- GD_MONO_BEGIN_RUNTIME_INVOKE;
- MonoObject *ret = mono_runtime_invoke(p_method, p_obj, p_params, (MonoObject **)r_exc);
- GD_MONO_END_RUNTIME_INVOKE;
- return ret;
-}
-
-MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc) {
- GD_MONO_BEGIN_RUNTIME_INVOKE;
- MonoString *ret = mono_object_to_string(p_obj, (MonoObject **)r_exc);
- GD_MONO_END_RUNTIME_INVOKE;
- return ret;
-}
-
-void property_set_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **r_exc) {
- GD_MONO_BEGIN_RUNTIME_INVOKE;
- mono_property_set_value(p_prop, p_obj, p_params, (MonoObject **)r_exc);
- GD_MONO_END_RUNTIME_INVOKE;
-}
-
-MonoObject *property_get_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **r_exc) {
- GD_MONO_BEGIN_RUNTIME_INVOKE;
- MonoObject *ret = mono_property_get_value(p_prop, p_obj, p_params, (MonoObject **)r_exc);
- GD_MONO_END_RUNTIME_INVOKE;
- return ret;
-}
-
-uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool &r_error) {
- r_error = false;
- switch (mono_type_get_type(p_enum_basetype)) {
- case MONO_TYPE_BOOLEAN:
- return (bool)GDMonoMarshal::unbox<MonoBoolean>(p_boxed) ? 1 : 0;
- case MONO_TYPE_CHAR:
- return GDMonoMarshal::unbox<uint16_t>(p_boxed);
- case MONO_TYPE_U1:
- return GDMonoMarshal::unbox<uint8_t>(p_boxed);
- case MONO_TYPE_U2:
- return GDMonoMarshal::unbox<uint16_t>(p_boxed);
- case MONO_TYPE_U4:
- return GDMonoMarshal::unbox<uint32_t>(p_boxed);
- case MONO_TYPE_U8:
- return GDMonoMarshal::unbox<uint64_t>(p_boxed);
- case MONO_TYPE_I1:
- return GDMonoMarshal::unbox<int8_t>(p_boxed);
- case MONO_TYPE_I2:
- return GDMonoMarshal::unbox<int16_t>(p_boxed);
- case MONO_TYPE_I4:
- return GDMonoMarshal::unbox<int32_t>(p_boxed);
- case MONO_TYPE_I8:
- return GDMonoMarshal::unbox<int64_t>(p_boxed);
- default:
- r_error = true;
- return 0;
- }
-}
-
-void dispose(MonoObject *p_mono_object, MonoException **r_exc) {
- CACHED_METHOD_THUNK(GodotObject, Dispose).invoke(p_mono_object, r_exc);
-}
-
-namespace Marshal {
-
-#ifdef MONO_GLUE_ENABLED
-#ifdef TOOLS_ENABLED
-#define NO_GLUE_RET(m_ret) \
- { \
- if (!GDMonoCache::cached_data.godot_api_cache_updated) \
- return m_ret; \
- }
-#else
-#define NO_GLUE_RET(m_ret) \
- {}
-#endif
-#else
-#define NO_GLUE_RET(m_ret) \
- { return m_ret; }
-#endif
-
-bool type_is_generic_array(MonoReflectionType *p_reftype) {
- NO_GLUE_RET(false);
- MonoException *exc = nullptr;
- MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericArray).invoke(p_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
- return (bool)res;
-}
-
-bool type_is_generic_dictionary(MonoReflectionType *p_reftype) {
- NO_GLUE_RET(false);
- MonoException *exc = nullptr;
- MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericDictionary).invoke(p_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
- return (bool)res;
-}
-
-bool type_is_system_generic_list(MonoReflectionType *p_reftype) {
- NO_GLUE_RET(false);
- MonoException *exc = nullptr;
- MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsSystemGenericList).invoke(p_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
- return (bool)res;
-}
-
-bool type_is_system_generic_dictionary(MonoReflectionType *p_reftype) {
- NO_GLUE_RET(false);
- MonoException *exc = nullptr;
- MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsSystemGenericDictionary).invoke(p_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
- return (bool)res;
-}
-
-bool type_is_generic_ienumerable(MonoReflectionType *p_reftype) {
- NO_GLUE_RET(false);
- MonoException *exc = nullptr;
- MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericIEnumerable).invoke(p_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
- return (bool)res;
-}
-
-bool type_is_generic_icollection(MonoReflectionType *p_reftype) {
- NO_GLUE_RET(false);
- MonoException *exc = nullptr;
- MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericICollection).invoke(p_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
- return (bool)res;
-}
-
-bool type_is_generic_idictionary(MonoReflectionType *p_reftype) {
- NO_GLUE_RET(false);
- MonoException *exc = nullptr;
- MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeIsGenericIDictionary).invoke(p_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
- return (bool)res;
-}
-
-bool type_has_flags_attribute(MonoReflectionType *p_reftype) {
- NO_GLUE_RET(false);
- MonoException *exc = nullptr;
- MonoBoolean res = CACHED_METHOD_THUNK(MarshalUtils, TypeHasFlagsAttribute).invoke(p_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
- return (bool)res;
-}
-
-void get_generic_type_definition(MonoReflectionType *p_reftype, MonoReflectionType **r_generic_reftype) {
- MonoException *exc = nullptr;
- CACHED_METHOD_THUNK(MarshalUtils, GetGenericTypeDefinition).invoke(p_reftype, r_generic_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
-}
-
-void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype) {
- MonoException *exc = nullptr;
- CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType).invoke(p_array_reftype, r_elem_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
-}
-
-void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype) {
- MonoException *exc = nullptr;
- CACHED_METHOD_THUNK(MarshalUtils, DictionaryGetKeyValueTypes).invoke(p_dict_reftype, r_key_reftype, r_value_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
-}
-
-GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype) {
- NO_GLUE_RET(nullptr);
- MonoException *exc = nullptr;
- MonoReflectionType *reftype = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericArrayType).invoke(p_elem_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
- return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype)));
-}
-
-GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype) {
- NO_GLUE_RET(nullptr);
- MonoException *exc = nullptr;
- MonoReflectionType *reftype = CACHED_METHOD_THUNK(MarshalUtils, MakeGenericDictionaryType).invoke(p_key_reftype, p_value_reftype, &exc);
- UNHANDLED_EXCEPTION(exc);
- return GDMono::get_singleton()->get_class(mono_class_from_mono_type(mono_reflection_type_get_type(reftype)));
-}
-} // namespace Marshal
-
-ScopeThreadAttach::ScopeThreadAttach() {
- if (likely(GDMono::get_singleton()->is_runtime_initialized()) && unlikely(!mono_domain_get())) {
- mono_thread = GDMonoUtils::attach_current_thread();
- }
-}
-
-ScopeThreadAttach::~ScopeThreadAttach() {
- if (unlikely(mono_thread)) {
- GDMonoUtils::detach_current_thread(mono_thread);
- }
-}
-
-StringName get_native_godot_class_name(GDMonoClass *p_class) {
- MonoObject *native_name_obj = p_class->get_field(BINDINGS_NATIVE_NAME_FIELD)->get_value(nullptr);
- StringName *ptr = GDMonoMarshal::unbox<StringName *>(CACHED_FIELD(StringName, ptr)->get_value(native_name_obj));
- return ptr ? *ptr : StringName();
-}
-} // namespace GDMonoUtils
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
deleted file mode 100644
index 300cacfa4b..0000000000
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ /dev/null
@@ -1,205 +0,0 @@
-/*************************************************************************/
-/* gd_mono_utils.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GD_MONO_UTILS_H
-#define GD_MONO_UTILS_H
-
-#include <mono/metadata/threads.h>
-
-#include "../mono_gc_handle.h"
-#include "../utils/macros.h"
-#include "gd_mono_header.h"
-#ifdef JAVASCRIPT_ENABLED
-#include "gd_mono_wasm_m2n.h"
-#endif
-
-#include "core/object/class_db.h"
-#include "core/object/ref_counted.h"
-
-#define UNHANDLED_EXCEPTION(m_exc) \
- if (unlikely(m_exc != nullptr)) { \
- GDMonoUtils::debug_unhandled_exception(m_exc); \
- GD_UNREACHABLE(); \
- } else \
- ((void)0)
-
-namespace GDMonoUtils {
-
-namespace Marshal {
-
-bool type_is_generic_array(MonoReflectionType *p_reftype);
-bool type_is_generic_dictionary(MonoReflectionType *p_reftype);
-bool type_is_system_generic_list(MonoReflectionType *p_reftype);
-bool type_is_system_generic_dictionary(MonoReflectionType *p_reftype);
-bool type_is_generic_ienumerable(MonoReflectionType *p_reftype);
-bool type_is_generic_icollection(MonoReflectionType *p_reftype);
-bool type_is_generic_idictionary(MonoReflectionType *p_reftype);
-bool type_has_flags_attribute(MonoReflectionType *p_reftype);
-
-void get_generic_type_definition(MonoReflectionType *p_reftype, MonoReflectionType **r_generic_reftype);
-
-void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype);
-void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype);
-
-GDMonoClass *make_generic_array_type(MonoReflectionType *p_elem_reftype);
-GDMonoClass *make_generic_dictionary_type(MonoReflectionType *p_key_reftype, MonoReflectionType *p_value_reftype);
-} // namespace Marshal
-
-_FORCE_INLINE_ void hash_combine(uint32_t &p_hash, const uint32_t &p_with_hash) {
- p_hash ^= p_with_hash + 0x9e3779b9 + (p_hash << 6) + (p_hash >> 2);
-}
-
-/**
- * If the object has a csharp script, returns the target of the gchandle stored in the script instance
- * Otherwise returns a newly constructed MonoObject* which is attached to the object
- * Returns nullptr on error
- */
-MonoObject *unmanaged_get_managed(Object *unmanaged);
-
-void set_main_thread(MonoThread *p_thread);
-MonoThread *attach_current_thread();
-void detach_current_thread();
-void detach_current_thread(MonoThread *p_mono_thread);
-MonoThread *get_current_thread();
-bool is_thread_attached();
-
-uint32_t new_strong_gchandle(MonoObject *p_object);
-uint32_t new_strong_gchandle_pinned(MonoObject *p_object);
-uint32_t new_weak_gchandle(MonoObject *p_object);
-void free_gchandle(uint32_t p_gchandle);
-
-void runtime_object_init(MonoObject *p_this_obj, GDMonoClass *p_class, MonoException **r_exc = nullptr);
-
-bool mono_delegate_equal(MonoDelegate *p_a, MonoDelegate *p_b);
-
-GDMonoClass *get_object_class(MonoObject *p_object);
-GDMonoClass *type_get_proxy_class(const StringName &p_type);
-GDMonoClass *get_class_native_base(GDMonoClass *p_class);
-
-MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringName &p_native, Object *p_object);
-
-MonoObject *create_managed_from(const StringName &p_from);
-MonoObject *create_managed_from(const NodePath &p_from);
-MonoObject *create_managed_from(const RID &p_from);
-MonoObject *create_managed_from(const Array &p_from, GDMonoClass *p_class);
-MonoObject *create_managed_from(const Dictionary &p_from, GDMonoClass *p_class);
-
-MonoDomain *create_domain(const String &p_friendly_name);
-
-String get_type_desc(MonoType *p_type);
-String get_type_desc(MonoReflectionType *p_reftype);
-
-String get_exception_name_and_message(MonoException *p_exc);
-
-void debug_print_unhandled_exception(MonoException *p_exc);
-void debug_send_unhandled_exception_error(MonoException *p_exc);
-void debug_unhandled_exception(MonoException *p_exc);
-void print_unhandled_exception(MonoException *p_exc);
-
-/**
- * Sets the exception as pending. The exception will be thrown when returning to managed code.
- * If no managed method is being invoked by the runtime, the exception will be treated as
- * an unhandled exception and the method will not return.
- */
-void set_pending_exception(MonoException *p_exc);
-
-extern thread_local int current_invoke_count;
-
-_FORCE_INLINE_ int get_runtime_invoke_count() {
- return current_invoke_count;
-}
-
-_FORCE_INLINE_ int &get_runtime_invoke_count_ref() {
- return current_invoke_count;
-}
-
-MonoObject *runtime_invoke(MonoMethod *p_method, void *p_obj, void **p_params, MonoException **r_exc);
-
-MonoString *object_to_string(MonoObject *p_obj, MonoException **r_exc);
-
-void property_set_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **r_exc);
-MonoObject *property_get_value(MonoProperty *p_prop, void *p_obj, void **p_params, MonoException **r_exc);
-
-uint64_t unbox_enum_value(MonoObject *p_boxed, MonoType *p_enum_basetype, bool &r_error);
-
-void dispose(MonoObject *p_mono_object, MonoException **r_exc);
-
-struct ScopeThreadAttach {
- ScopeThreadAttach();
- ~ScopeThreadAttach();
-
-private:
- MonoThread *mono_thread = nullptr;
-};
-
-StringName get_native_godot_class_name(GDMonoClass *p_class);
-
-template <typename... P>
-void add_internal_call(const char *p_name, void (*p_func)(P...)) {
-#ifdef JAVASCRIPT_ENABLED
- GDMonoWasmM2n::ICallTrampolines<P...>::add();
-#endif
- mono_add_internal_call(p_name, (void *)p_func);
-}
-
-template <typename R, typename... P>
-void add_internal_call(const char *p_name, R (*p_func)(P...)) {
-#ifdef JAVASCRIPT_ENABLED
- GDMonoWasmM2n::ICallTrampolinesR<R, P...>::add();
-#endif
- mono_add_internal_call(p_name, (void *)p_func);
-}
-} // namespace GDMonoUtils
-
-#define NATIVE_GDMONOCLASS_NAME(m_class) (GDMonoUtils::get_native_godot_class_name(m_class))
-
-#define GD_MONO_BEGIN_RUNTIME_INVOKE \
- int &_runtime_invoke_count_ref = GDMonoUtils::get_runtime_invoke_count_ref(); \
- _runtime_invoke_count_ref += 1; \
- ((void)0)
-
-#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)0)
-
-#ifdef DEBUG_ENABLED
-#define GD_MONO_ASSERT_THREAD_ATTACHED \
- CRASH_COND(!GDMonoUtils::is_thread_attached()); \
- ((void)0)
-#else
-#define GD_MONO_ASSERT_THREAD_ATTACHED ((void)0)
-#endif
-
-#endif // GD_MONO_UTILS_H
diff --git a/modules/mono/mono_gd/gd_mono_wasm_m2n.h b/modules/mono/mono_gd/gd_mono_wasm_m2n.h
deleted file mode 100644
index 83e2750e5a..0000000000
--- a/modules/mono/mono_gd/gd_mono_wasm_m2n.h
+++ /dev/null
@@ -1,263 +0,0 @@
-/*************************************************************************/
-/* gd_mono_wasm_m2n.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef GD_MONO_WASM_M2N_H
-#define GD_MONO_WASM_M2N_H
-
-#ifdef JAVASCRIPT_ENABLED
-
-#include "core/string/ustring.h"
-#include "core/typedefs.h"
-
-#include <mono/metadata/loader.h>
-#include <mono/utils/mono-publib.h>
-#include <stdexcept>
-#include <type_traits>
-
-extern "C" {
-
-struct Mono_InterpMethodArguments {
- size_t ilen;
- void **iargs;
- size_t flen;
- double *fargs = nullptr;
- void **retval;
- size_t is_float_ret;
- //#ifdef TARGET_WASM
- void *sig = nullptr;
- //#endif
-};
-} // extern "C"
-
-namespace GDMonoWasmM2n {
-
-template <typename T, size_t Size>
-struct array {
- T elems[Size];
-};
-
-template <typename T>
-constexpr char get_m2n_cookie_impl() {
-#define M2N_REG_COOKIE(m_type, m_cookie) \
- if constexpr (std::is_same_v<m_type, T>) { \
- return m_cookie; \
- }
-
- M2N_REG_COOKIE(MonoBoolean, 'I');
- M2N_REG_COOKIE(int8_t, 'I');
- M2N_REG_COOKIE(uint8_t, 'I');
- M2N_REG_COOKIE(int16_t, 'I');
- M2N_REG_COOKIE(uint16_t, 'I');
- M2N_REG_COOKIE(int32_t, 'I');
- M2N_REG_COOKIE(uint32_t, 'I');
- M2N_REG_COOKIE(int64_t, 'L');
- M2N_REG_COOKIE(uint64_t, 'L');
- M2N_REG_COOKIE(float, 'F');
- M2N_REG_COOKIE(double, 'D');
-
- if constexpr (std::is_pointer_v<T>) {
- if constexpr (sizeof(void *) == 4) {
- return 'I';
- } else {
- return 'L';
- }
- }
-
- if constexpr (std::is_void_v<T>) {
- return 'V';
- }
-
- return 'X';
-
-#undef M2N_REG_COOKIE
-}
-
-template <typename T>
-constexpr char get_m2n_cookie() {
- constexpr char cookie = get_m2n_cookie_impl<T>();
- static_assert(cookie != 'X', "Type not supported in internal call signature.");
- return cookie;
-}
-
-template <typename... T>
-constexpr array<const char, sizeof...(T) + 2> get_m2n_cookies() {
- return array<const char, sizeof...(T) + 2>{ 'V', get_m2n_cookie<T>()..., '\0' };
-}
-
-template <typename R, typename... T>
-constexpr array<const char, sizeof...(T) + 2> get_m2n_cookies_r() {
- return array<const char, sizeof...(T) + 2>{ get_m2n_cookie<R>(), get_m2n_cookie<T>()..., '\0' };
-}
-
-template <typename T>
-constexpr size_t calc_m2n_index(size_t &r_int_idx, size_t &r_float_idx) {
- constexpr char cookie = get_m2n_cookie<T>();
-
- static_assert(cookie == 'I' || cookie == 'L' || cookie == 'F' || cookie == 'D');
-
- if constexpr (cookie == 'I' || cookie == 'L') {
- size_t ret = r_int_idx;
- r_int_idx += cookie == 'I' ? 1 : 2;
- return ret;
- } else {
- size_t ret = r_float_idx;
- r_float_idx += cookie == 'F' ? 1 : 2;
- return ret;
- }
-}
-
-template <typename... P>
-constexpr array<size_t, sizeof...(P)> get_indices_for_type() {
- size_t int_idx = 0;
- size_t float_idx = 0;
- return array<size_t, sizeof...(P)>{ calc_m2n_index<P>(int_idx, float_idx)... };
-}
-
-constexpr size_t fidx(size_t p_x) {
- if constexpr (sizeof(void *) == 4) {
- return p_x * 2;
- } else {
- return p_x;
- }
-}
-
-template <typename T>
-T m2n_arg_cast(Mono_InterpMethodArguments *p_margs, size_t p_idx) {
- constexpr char cookie = get_m2n_cookie<T>();
-
- static_assert(cookie == 'I' || cookie == 'L' || cookie == 'F' || cookie == 'D');
-
- if constexpr (cookie == 'I') {
- return (T)(size_t)p_margs->iargs[p_idx];
- } else if constexpr (cookie == 'L') {
- static_assert(std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t> ||
- (sizeof(void *) == 8 && std::is_pointer_v<T>),
- "Invalid type for cookie 'L'.");
-
- union {
- T l;
- struct {
- int32_t lo;
- int32_t hi;
- } pair;
- } p;
-
- p.pair.lo = (int32_t)(size_t)p_margs->iargs[p_idx];
- p.pair.hi = (int32_t)(size_t)p_margs->iargs[p_idx + 1];
-
- return p.l;
- } else if constexpr (cookie == 'F') {
- return *reinterpret_cast<float *>(&p_margs->fargs[fidx(p_idx)]);
- } else if constexpr (cookie == 'D') {
- return (T)p_margs->fargs[p_idx];
- }
-}
-
-template <typename... P, size_t... Is>
-void m2n_trampoline_with_idx_seq(void *p_target_func, Mono_InterpMethodArguments *p_margs, IndexSequence<Is...>) {
- constexpr array<size_t, sizeof...(P)> indices = get_indices_for_type<P...>();
- typedef void (*Func)(P...);
- Func func = (Func)p_target_func;
- func(m2n_arg_cast<P>(p_margs, indices.elems[Is])...);
-}
-
-template <typename R, typename... P, size_t... Is>
-void m2n_trampoline_with_idx_seq_r(void *p_target_func, Mono_InterpMethodArguments *p_margs, IndexSequence<Is...>) {
- constexpr array<size_t, sizeof...(P)> indices = get_indices_for_type<P...>();
- typedef R (*Func)(P...);
- Func func = (Func)p_target_func;
- R res = func(m2n_arg_cast<P>(p_margs, indices.elems[Is])...);
- *reinterpret_cast<R *>(p_margs->retval) = res;
-}
-
-inline void m2n_trampoline_with_idx_seq_0(void *p_target_func, Mono_InterpMethodArguments *p_margs) {
- typedef void (*Func)();
- Func func = (Func)p_target_func;
- func();
-}
-
-template <typename R>
-void m2n_trampoline_with_idx_seq_r0(void *p_target_func, Mono_InterpMethodArguments *p_margs) {
- typedef R (*Func)();
- Func func = (Func)p_target_func;
- R res = func();
- *reinterpret_cast<R *>(p_margs->retval) = res;
-}
-
-template <typename... P>
-void m2n_trampoline(void *p_target_func, Mono_InterpMethodArguments *p_margs) {
- if constexpr (sizeof...(P) == 0) {
- m2n_trampoline_with_idx_seq_0(p_target_func, p_margs);
- } else {
- m2n_trampoline_with_idx_seq<P...>(p_target_func, p_margs, BuildIndexSequence<sizeof...(P)>{});
- }
-}
-
-template <typename R, typename... P>
-void m2n_trampoline_r(void *p_target_func, Mono_InterpMethodArguments *p_margs) {
- if constexpr (sizeof...(P) == 0) {
- m2n_trampoline_with_idx_seq_r0<R>(p_target_func, p_margs);
- } else {
- m2n_trampoline_with_idx_seq_r<R, P...>(p_target_func, p_margs, BuildIndexSequence<sizeof...(P)>{});
- }
-}
-
-typedef void (*TrampolineFunc)(void *p_target_func, Mono_InterpMethodArguments *p_margs);
-
-void set_trampoline(const char *cookies, TrampolineFunc trampoline_func);
-
-void lazy_initialize();
-
-template <typename... P>
-struct ICallTrampolines {
- static constexpr auto cookies = get_m2n_cookies<P...>();
-
- static void add() {
- lazy_initialize();
- set_trampoline(cookies.elems, &m2n_trampoline<P...>);
- }
-};
-
-template <typename R, typename... P>
-struct ICallTrampolinesR {
- static constexpr auto cookies = get_m2n_cookies_r<R, P...>();
-
- static void add() {
- lazy_initialize();
- set_trampoline(cookies.elems, &m2n_trampoline_r<R, P...>);
- }
-};
-
-void initialize();
-} // namespace GDMonoWasmM2n
-
-#endif
-
-#endif // GD_MONO_WASM_M2N_H
diff --git a/modules/mono/mono_gd/i_mono_class_member.h b/modules/mono/mono_gd/i_mono_class_member.h
deleted file mode 100644
index 14e8ca82b9..0000000000
--- a/modules/mono/mono_gd/i_mono_class_member.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*************************************************************************/
-/* i_mono_class_member.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef I_MONO_CLASS_MEMBER_H
-#define I_MONO_CLASS_MEMBER_H
-
-#include "gd_mono_header.h"
-
-#include <mono/metadata/object.h>
-
-class IMonoClassMember {
-public:
- enum Visibility {
- PRIVATE,
- PROTECTED_AND_INTERNAL, // FAM_AND_ASSEM
- INTERNAL, // ASSEMBLY
- PROTECTED, // FAMILY
- PUBLIC
- };
-
- enum MemberType {
- MEMBER_TYPE_FIELD,
- MEMBER_TYPE_PROPERTY,
- MEMBER_TYPE_METHOD
- };
-
- virtual ~IMonoClassMember() {}
-
- virtual GDMonoClass *get_enclosing_class() const = 0;
-
- virtual MemberType get_member_type() const = 0;
-
- virtual StringName get_name() const = 0;
-
- virtual bool is_static() = 0;
-
- virtual Visibility get_visibility() = 0;
-
- virtual bool has_attribute(GDMonoClass *p_attr_class) = 0;
- virtual MonoObject *get_attribute(GDMonoClass *p_attr_class) = 0;
-};
-
-#endif // I_MONO_CLASS_MEMBER_H
diff --git a/modules/mono/mono_gd/managed_type.cpp b/modules/mono/mono_gd/managed_type.cpp
deleted file mode 100644
index 5860d7db1e..0000000000
--- a/modules/mono/mono_gd/managed_type.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*************************************************************************/
-/* managed_type.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "managed_type.h"
-
-#include "gd_mono.h"
-#include "gd_mono_class.h"
-
-ManagedType ManagedType::from_class(GDMonoClass *p_class) {
- return ManagedType(mono_type_get_type(p_class->get_mono_type()), p_class);
-}
-
-ManagedType ManagedType::from_class(MonoClass *p_mono_class) {
- GDMonoClass *tclass = GDMono::get_singleton()->get_class(p_mono_class);
- ERR_FAIL_COND_V(!tclass, ManagedType());
-
- return ManagedType(mono_type_get_type(tclass->get_mono_type()), tclass);
-}
-
-ManagedType ManagedType::from_type(MonoType *p_mono_type) {
- MonoClass *mono_class = mono_class_from_mono_type(p_mono_type);
- GDMonoClass *tclass = GDMono::get_singleton()->get_class(mono_class);
- ERR_FAIL_COND_V(!tclass, ManagedType());
-
- return ManagedType(mono_type_get_type(p_mono_type), tclass);
-}
-
-ManagedType ManagedType::from_reftype(MonoReflectionType *p_mono_reftype) {
- MonoType *mono_type = mono_reflection_type_get_type(p_mono_reftype);
- return from_type(mono_type);
-}
diff --git a/modules/mono/mono_gd/managed_type.h b/modules/mono/mono_gd/managed_type.h
deleted file mode 100644
index 603ff3aca1..0000000000
--- a/modules/mono/mono_gd/managed_type.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*************************************************************************/
-/* managed_type.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef MANAGED_TYPE_H
-#define MANAGED_TYPE_H
-
-#include <mono/metadata/object.h>
-
-#include "gd_mono_header.h"
-
-struct ManagedType {
- int type_encoding = 0;
- GDMonoClass *type_class = nullptr;
-
- static ManagedType from_class(GDMonoClass *p_class);
- static ManagedType from_class(MonoClass *p_mono_class);
- static ManagedType from_type(MonoType *p_mono_type);
- static ManagedType from_reftype(MonoReflectionType *p_mono_reftype);
-
- ManagedType() {}
-
- ManagedType(int p_type_encoding, GDMonoClass *p_type_class) :
- type_encoding(p_type_encoding),
- type_class(p_type_class) {
- }
-};
-
-#endif // MANAGED_TYPE_H
diff --git a/modules/mono/mono_gd/support/android_support.cpp b/modules/mono/mono_gd/support/android_support.cpp
index 4797d5dae1..7fb983cd37 100644
--- a/modules/mono/mono_gd/support/android_support.cpp
+++ b/modules/mono/mono_gd/support/android_support.cpp
@@ -359,7 +359,7 @@ MonoArray *_gd_mono_android_cert_store_lookup(MonoString *p_alias) {
ScopedLocalRef<jbyteArray> encoded(env, (jbyteArray)env->CallObjectMethod(certificate, getEncoded));
jsize encodedLength = env->GetArrayLength(encoded);
- MonoArray *encoded_ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(uint8_t), encodedLength);
+ MonoArray *encoded_ret = mono_array_new(mono_domain_get(), mono_get_byte_class(), encodedLength);
uint8_t *dest = (uint8_t *)mono_array_addr(encoded_ret, uint8_t, 0);
env->GetByteArrayRegion(encoded, 0, encodedLength, reinterpret_cast<jbyte *>(dest));
diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp
index 437c4ca54a..55d2138674 100644
--- a/modules/mono/signal_awaiter_utils.cpp
+++ b/modules/mono/signal_awaiter_utils.cpp
@@ -32,16 +32,14 @@
#include "csharp_script.h"
#include "mono_gd/gd_mono_cache.h"
-#include "mono_gd/gd_mono_class.h"
-#include "mono_gd/gd_mono_marshal.h"
-#include "mono_gd/gd_mono_utils.h"
-Error gd_mono_connect_signal_awaiter(Object *p_source, const StringName &p_signal, Object *p_target, MonoObject *p_awaiter) {
+Error gd_mono_connect_signal_awaiter(Object *p_source, const StringName &p_signal, Object *p_target, GCHandleIntPtr p_awaiter_handle_ptr) {
ERR_FAIL_NULL_V(p_source, ERR_INVALID_DATA);
ERR_FAIL_NULL_V(p_target, ERR_INVALID_DATA);
// TODO: Use pooling for ManagedCallable instances.
- SignalAwaiterCallable *awaiter_callable = memnew(SignalAwaiterCallable(p_target, p_awaiter, p_signal));
+ MonoGCHandleData awaiter_handle(p_awaiter_handle_ptr, gdmono::GCHandleType::STRONG_HANDLE);
+ SignalAwaiterCallable *awaiter_callable = memnew(SignalAwaiterCallable(p_target, awaiter_handle, p_signal));
Callable callable = Callable(awaiter_callable);
return p_source->connect(p_signal, callable, Object::CONNECT_ONESHOT);
@@ -51,7 +49,7 @@ bool SignalAwaiterCallable::compare_equal(const CallableCustom *p_a, const Calla
// Only called if both instances are of type SignalAwaiterCallable. Static cast is safe.
const SignalAwaiterCallable *a = static_cast<const SignalAwaiterCallable *>(p_a);
const SignalAwaiterCallable *b = static_cast<const SignalAwaiterCallable *>(p_b);
- return a->awaiter_handle.handle == b->awaiter_handle.handle;
+ return a->awaiter_handle.handle.value == b->awaiter_handle.handle.value;
}
bool SignalAwaiterCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) {
@@ -92,6 +90,10 @@ ObjectID SignalAwaiterCallable::get_object() const {
return target_id;
}
+StringName SignalAwaiterCallable::get_signal() const {
+ return signal;
+}
+
void SignalAwaiterCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; // Can't find anything better
r_return_value = Variant();
@@ -101,38 +103,20 @@ void SignalAwaiterCallable::call(const Variant **p_arguments, int p_argcount, Va
"Resumed after await, but class instance is gone.");
#endif
- MonoArray *signal_args = nullptr;
-
- if (p_argcount > 0) {
- signal_args = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), p_argcount);
-
- for (int i = 0; i < p_argcount; i++) {
- MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(*p_arguments[i]);
- mono_array_setref(signal_args, i, boxed);
- }
- }
+ bool awaiter_is_null = false;
+ GDMonoCache::managed_callbacks.SignalAwaiter_SignalCallback(awaiter_handle.get_intptr(), p_arguments, p_argcount, &awaiter_is_null);
- MonoObject *awaiter = awaiter_handle.get_target();
-
- if (!awaiter) {
+ if (awaiter_is_null) {
r_call_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
return;
}
- MonoException *exc = nullptr;
- CACHED_METHOD_THUNK(SignalAwaiter, SignalCallback).invoke(awaiter, signal_args, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- ERR_FAIL();
- } else {
- r_call_error.error = Callable::CallError::CALL_OK;
- }
+ r_call_error.error = Callable::CallError::CALL_OK;
}
-SignalAwaiterCallable::SignalAwaiterCallable(Object *p_target, MonoObject *p_awaiter, const StringName &p_signal) :
+SignalAwaiterCallable::SignalAwaiterCallable(Object *p_target, MonoGCHandleData p_awaiter_handle, const StringName &p_signal) :
target_id(p_target->get_instance_id()),
- awaiter_handle(MonoGCHandleData::new_strong_handle(p_awaiter)),
+ awaiter_handle(p_awaiter_handle),
signal(p_signal) {
}
@@ -148,7 +132,7 @@ bool EventSignalCallable::compare_equal(const CallableCustom *p_a, const Callabl
return false;
}
- if (a->event_signal != b->event_signal) {
+ if (a->event_signal_name != b->event_signal_name) {
return false;
}
@@ -163,7 +147,7 @@ bool EventSignalCallable::compare_less(const CallableCustom *p_a, const Callable
}
uint32_t EventSignalCallable::hash() const {
- uint32_t hash = event_signal->field->get_name().hash();
+ uint32_t hash = event_signal_name.hash();
return hash_murmur3_one_64(owner->get_instance_id(), hash);
}
@@ -173,8 +157,7 @@ String EventSignalCallable::get_as_text() const {
if (script.is_valid() && script->get_path().is_resource_file()) {
class_name += "(" + script->get_path().get_file() + ")";
}
- StringName signal = event_signal->field->get_name();
- return class_name + "::EventSignalMiddleman::" + String(signal);
+ return class_name + "::EventSignalMiddleman::" + String(event_signal_name);
}
CallableCustom::CompareEqualFunc EventSignalCallable::get_compare_equal_func() const {
@@ -190,39 +173,32 @@ ObjectID EventSignalCallable::get_object() const {
}
StringName EventSignalCallable::get_signal() const {
- return event_signal->field->get_name();
+ return event_signal_name;
}
void EventSignalCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; // Can't find anything better
r_return_value = Variant();
- ERR_FAIL_COND(p_argcount < event_signal->invoke_method->get_parameters_count());
-
CSharpInstance *csharp_instance = CAST_CSHARP_INSTANCE(owner->get_script_instance());
ERR_FAIL_NULL(csharp_instance);
- MonoObject *owner_managed = csharp_instance->get_mono_object();
- ERR_FAIL_NULL(owner_managed);
+ GCHandleIntPtr owner_gchandle_intptr = csharp_instance->get_gchandle_intptr();
+
+ bool awaiter_is_null = false;
+ GDMonoCache::managed_callbacks.ScriptManagerBridge_RaiseEventSignal(
+ owner_gchandle_intptr, &event_signal_name,
+ p_arguments, p_argcount, &awaiter_is_null);
- MonoObject *delegate_field_value = event_signal->field->get_value(owner_managed);
- if (!delegate_field_value) {
- r_call_error.error = Callable::CallError::CALL_OK;
+ if (awaiter_is_null) {
+ r_call_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
return;
}
- MonoException *exc = nullptr;
- event_signal->invoke_method->invoke(delegate_field_value, p_arguments, &exc);
-
- if (exc) {
- GDMonoUtils::set_pending_exception(exc);
- ERR_FAIL();
- } else {
- r_call_error.error = Callable::CallError::CALL_OK;
- }
+ r_call_error.error = Callable::CallError::CALL_OK;
}
-EventSignalCallable::EventSignalCallable(Object *p_owner, const CSharpScript::EventSignal *p_event_signal) :
+EventSignalCallable::EventSignalCallable(Object *p_owner, const StringName &p_event_signal_name) :
owner(p_owner),
- event_signal(p_event_signal) {
+ event_signal_name(p_event_signal_name) {
}
diff --git a/modules/mono/signal_awaiter_utils.h b/modules/mono/signal_awaiter_utils.h
index 532aa3e327..a53ae56bf5 100644
--- a/modules/mono/signal_awaiter_utils.h
+++ b/modules/mono/signal_awaiter_utils.h
@@ -36,9 +36,14 @@
#include "csharp_script.h"
#include "mono_gc_handle.h"
-Error gd_mono_connect_signal_awaiter(Object *p_source, const StringName &p_signal, Object *p_target, MonoObject *p_awaiter);
+Error gd_mono_connect_signal_awaiter(Object *p_source, const StringName &p_signal, Object *p_target, GCHandleIntPtr p_awaiter_handle_ptr);
-class SignalAwaiterCallable : public CallableCustom {
+class BaseSignalCallable : public CallableCustom {
+public:
+ virtual StringName get_signal() const = 0;
+};
+
+class SignalAwaiterCallable : public BaseSignalCallable {
ObjectID target_id;
MonoGCHandleData awaiter_handle;
StringName signal;
@@ -59,17 +64,17 @@ public:
ObjectID get_object() const override;
- _FORCE_INLINE_ StringName get_signal() const { return signal; }
+ StringName get_signal() const override;
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
- SignalAwaiterCallable(Object *p_target, MonoObject *p_awaiter, const StringName &p_signal);
+ SignalAwaiterCallable(Object *p_target, MonoGCHandleData p_awaiter_handle, const StringName &p_signal);
~SignalAwaiterCallable();
};
-class EventSignalCallable : public CallableCustom {
+class EventSignalCallable : public BaseSignalCallable {
Object *owner = nullptr;
- const CSharpScript::EventSignal *event_signal;
+ StringName event_signal_name;
public:
static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b);
@@ -87,11 +92,11 @@ public:
ObjectID get_object() const override;
- StringName get_signal() const;
+ StringName get_signal() const override;
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
- EventSignalCallable(Object *p_owner, const CSharpScript::EventSignal *p_event_signal);
+ EventSignalCallable(Object *p_owner, const StringName &p_event_signal_name);
};
#endif // SIGNAL_AWAITER_UTILS_H
diff --git a/modules/mono/utils/mono_reg_utils.cpp b/modules/mono/utils/mono_reg_utils.cpp
deleted file mode 100644
index 8e37e6943c..0000000000
--- a/modules/mono/utils/mono_reg_utils.cpp
+++ /dev/null
@@ -1,242 +0,0 @@
-/*************************************************************************/
-/* mono_reg_utils.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "mono_reg_utils.h"
-#include "core/io/dir_access.h"
-
-#ifdef WINDOWS_ENABLED
-
-#include "core/os/os.h"
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-namespace MonoRegUtils {
-
-template <int>
-REGSAM bitness_sam_impl();
-
-template <>
-REGSAM bitness_sam_impl<4>() {
- return KEY_WOW64_64KEY;
-}
-
-template <>
-REGSAM bitness_sam_impl<8>() {
- return KEY_WOW64_32KEY;
-}
-
-REGSAM _get_bitness_sam() {
- return bitness_sam_impl<sizeof(size_t)>();
-}
-
-LONG _RegOpenKey(HKEY hKey, LPCWSTR lpSubKey, PHKEY phkResult) {
- LONG res = RegOpenKeyExW(hKey, lpSubKey, 0, KEY_READ, phkResult);
-
- if (res != ERROR_SUCCESS) {
- res = RegOpenKeyExW(hKey, lpSubKey, 0, KEY_READ | _get_bitness_sam(), phkResult);
- }
-
- return res;
-}
-
-LONG _RegKeyQueryString(HKEY hKey, const String &p_value_name, String &r_value) {
- Vector<WCHAR> buffer;
- buffer.resize(512);
- DWORD dwBufferSize = buffer.size();
-
- 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, (LPCWSTR)(p_value_name.utf16().get_data()), 0, nullptr, (LPBYTE)buffer.ptr(), &dwBufferSize);
- }
-
- if (res == ERROR_SUCCESS) {
- r_value = String(buffer.ptr(), buffer.size());
- } else {
- r_value = String();
- }
-
- return res;
-}
-
-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, (LPCWSTR)(p_subkey.utf16().get_data()), &hKey);
-
- if (res != ERROR_SUCCESS) {
- goto cleanup;
- }
-
- if (!p_old_reg) {
- res = _RegKeyQueryString(hKey, "Version", r_info.version);
- if (res != ERROR_SUCCESS) {
- goto cleanup;
- }
- }
-
- res = _RegKeyQueryString(hKey, "SdkInstallRoot", r_info.install_root_dir);
- if (res != ERROR_SUCCESS) {
- goto cleanup;
- }
-
- res = _RegKeyQueryString(hKey, "FrameworkAssemblyDirectory", r_info.assembly_dir);
- if (res != ERROR_SUCCESS) {
- goto cleanup;
- }
-
- res = _RegKeyQueryString(hKey, "MonoConfigDir", r_info.config_dir);
- if (res != ERROR_SUCCESS) {
- goto cleanup;
- }
-
- if (r_info.install_root_dir.ends_with("\\")) {
- r_info.bin_dir = r_info.install_root_dir + "bin";
- } else {
- r_info.bin_dir = r_info.install_root_dir + "\\bin";
- }
-
-cleanup:
- RegCloseKey(hKey);
- return res;
-}
-
-LONG _find_mono_in_reg_old(const String &p_subkey, MonoRegInfo &r_info) {
- String default_clr;
-
- HKEY hKey;
- LONG res = _RegOpenKey(HKEY_LOCAL_MACHINE, (LPCWSTR)(p_subkey.utf16().get_data()), &hKey);
-
- if (res != ERROR_SUCCESS) {
- goto cleanup;
- }
-
- res = _RegKeyQueryString(hKey, "DefaultCLR", default_clr);
-
- if (res == ERROR_SUCCESS && default_clr.length()) {
- r_info.version = default_clr;
- res = _find_mono_in_reg(p_subkey + "\\" + default_clr, r_info, true);
- }
-
-cleanup:
- RegCloseKey(hKey);
- return res;
-}
-
-MonoRegInfo find_mono() {
- MonoRegInfo info;
-
- if (_find_mono_in_reg("Software\\Mono", info) == ERROR_SUCCESS) {
- return info;
- }
-
- if (_find_mono_in_reg_old("Software\\Novell\\Mono", info) == ERROR_SUCCESS) {
- return info;
- }
-
- return MonoRegInfo();
-}
-
-String find_msbuild_tools_path() {
- String msbuild_tools_path;
-
- // Try to find 15.0 with vswhere
-
- String vswhere_path = OS::get_singleton()->get_environment(sizeof(size_t) == 8 ? "ProgramFiles(x86)" : "ProgramFiles");
- vswhere_path += "\\Microsoft Visual Studio\\Installer\\vswhere.exe";
-
- List<String> vswhere_args;
- vswhere_args.push_back("-latest");
- vswhere_args.push_back("-products");
- vswhere_args.push_back("*");
- vswhere_args.push_back("-requires");
- vswhere_args.push_back("Microsoft.Component.MSBuild");
-
- String output;
- int exit_code;
- OS::get_singleton()->execute(vswhere_path, vswhere_args, &output, &exit_code);
-
- if (exit_code == 0) {
- Vector<String> lines = output.split("\n");
-
- for (int i = 0; i < lines.size(); i++) {
- const String &line = lines[i];
- int sep_idx = line.find(":");
-
- if (sep_idx > 0) {
- String key = line.substr(0, sep_idx); // No need to trim
-
- if (key == "installationPath") {
- String val = line.substr(sep_idx + 1, line.length()).strip_edges();
-
- ERR_BREAK(val.is_empty());
-
- if (!val.ends_with("\\")) {
- val += "\\";
- }
-
- // Since VS2019, the directory is simply named "Current"
- String msbuild_dir = val + "MSBuild\\Current\\Bin";
- if (DirAccess::exists(msbuild_dir)) {
- return msbuild_dir;
- }
-
- // Directory name "15.0" is used in VS 2017
- return val + "MSBuild\\15.0\\Bin";
- }
- }
- }
- }
-
- // Try to find 14.0 in the Registry
-
- HKEY hKey;
- LONG res = _RegOpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\14.0", &hKey);
-
- if (res != ERROR_SUCCESS) {
- goto cleanup;
- }
-
- res = _RegKeyQueryString(hKey, "MSBuildToolsPath", msbuild_tools_path);
-
- if (res != ERROR_SUCCESS) {
- goto cleanup;
- }
-
-cleanup:
- RegCloseKey(hKey);
-
- return msbuild_tools_path;
-}
-} // namespace MonoRegUtils
-
-#endif // WINDOWS_ENABLED
diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp
index a1905dfcfe..269e41e2f4 100644
--- a/modules/mono/utils/path_utils.cpp
+++ b/modules/mono/utils/path_utils.cpp
@@ -51,6 +51,37 @@
namespace path {
+String find_executable(const String &p_name) {
+#ifdef WINDOWS_ENABLED
+ Vector<String> exts = OS::get_singleton()->get_environment("PATHEXT").split(ENV_PATH_SEP, false);
+#endif
+ Vector<String> env_path = OS::get_singleton()->get_environment("PATH").split(ENV_PATH_SEP, false);
+
+ if (env_path.is_empty()) {
+ return String();
+ }
+
+ for (int i = 0; i < env_path.size(); i++) {
+ String p = path::join(env_path[i], p_name);
+
+#ifdef WINDOWS_ENABLED
+ for (int j = 0; j < exts.size(); j++) {
+ String p2 = p + exts[j].to_lower(); // lowercase to reduce risk of case mismatch warning
+
+ if (FileAccess::exists(p2)) {
+ return p2;
+ }
+ }
+#else
+ if (FileAccess::exists(p)) {
+ return p;
+ }
+#endif
+ }
+
+ return String();
+}
+
String cwd() {
#ifdef WINDOWS_ENABLED
const DWORD expected_size = ::GetCurrentDirectoryW(0, nullptr);
@@ -174,7 +205,7 @@ String relative_to_impl(const String &p_path, const String &p_relative_to) {
return p_path;
}
- return String("..").plus_file(relative_to_impl(p_path, base_dir));
+ return String("..").path_join(relative_to_impl(p_path, base_dir));
}
}
diff --git a/modules/mono/utils/path_utils.h b/modules/mono/utils/path_utils.h
index 9a2c757361..d1c3d3ccfd 100644
--- a/modules/mono/utils/path_utils.h
+++ b/modules/mono/utils/path_utils.h
@@ -36,6 +36,8 @@
namespace path {
+String find_executable(const String &p_name);
+
String join(const String &p_a, const String &p_b);
String join(const String &p_a, const String &p_b, const String &p_c);
String join(const String &p_a, const String &p_b, const String &p_c, const String &p_d);
diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp
index 975f2d8332..b0f94310b8 100644
--- a/modules/mono/utils/string_utils.cpp
+++ b/modules/mono/utils/string_utils.cpp
@@ -65,7 +65,7 @@ int sfind(const String &p_text, int p_from) {
break;
case 1: {
char32_t c = src[read_pos];
- found = src[read_pos] == 's' || (c >= '0' && c <= '4');
+ found = src[read_pos] == 's' || (c >= '0' && c <= '5');
break;
}
default:
@@ -86,32 +86,13 @@ int sfind(const String &p_text, int p_from) {
}
} // namespace
-String sformat(const String &p_text, const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4, const Variant &p5) {
+String sformat(const String &p_text, const String &p1, const String &p2,
+ const String &p3, const String &p4, const String &p5, const String &p6) {
if (p_text.length() < 2) {
return p_text;
}
- Array args;
-
- if (p1.get_type() != Variant::NIL) {
- args.push_back(p1);
-
- if (p2.get_type() != Variant::NIL) {
- args.push_back(p2);
-
- if (p3.get_type() != Variant::NIL) {
- args.push_back(p3);
-
- if (p4.get_type() != Variant::NIL) {
- args.push_back(p4);
-
- if (p5.get_type() != Variant::NIL) {
- args.push_back(p5);
- }
- }
- }
- }
- }
+ String args[6] = { p1, p2, p3, p4, p5, p6 };
String new_string;
@@ -125,7 +106,7 @@ String sformat(const String &p_text, const Variant &p1, const Variant &p2, const
int req_index = (c == 's' ? findex++ : c - '0');
new_string += p_text.substr(search_from, result - search_from);
- new_string += args[req_index].operator String();
+ new_string += args[req_index];
search_from = result + 2;
}
diff --git a/modules/mono/utils/string_utils.h b/modules/mono/utils/string_utils.h
index fa4c5e89f4..b00dd9dde8 100644
--- a/modules/mono/utils/string_utils.h
+++ b/modules/mono/utils/string_utils.h
@@ -36,7 +36,8 @@
#include <stdarg.h>
-String sformat(const String &p_text, const Variant &p1 = Variant(), const Variant &p2 = Variant(), const Variant &p3 = Variant(), const Variant &p4 = Variant(), const Variant &p5 = Variant());
+String sformat(const String &p_text, const String &p1 = String(), const String &p2 = String(),
+ const String &p3 = String(), const String &p4 = String(), const String &p5 = String(), const String &p6 = String());
#ifdef TOOLS_ENABLED
bool is_csharp_keyword(const String &p_name);
diff --git a/modules/msdfgen/config.py b/modules/msdfgen/config.py
index 653e466a74..631894400d 100644
--- a/modules/msdfgen/config.py
+++ b/modules/msdfgen/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
- return env.module_check_dependencies("msdfgen", ["freetype"])
+ env.module_add_dependencies("msdfgen", ["freetype"])
+ return True
def configure(env):
diff --git a/modules/multiplayer/doc_classes/MultiplayerSpawner.xml b/modules/multiplayer/doc_classes/MultiplayerSpawner.xml
index 881796ed26..c0265c9161 100644
--- a/modules/multiplayer/doc_classes/MultiplayerSpawner.xml
+++ b/modules/multiplayer/doc_classes/MultiplayerSpawner.xml
@@ -14,7 +14,7 @@
<methods>
<method name="_spawn_custom" qualifiers="virtual">
<return type="Node" />
- <argument index="0" name="data" type="Variant" />
+ <param index="0" name="data" type="Variant" />
<description>
Method called on all peers when a custom spawn was requested by the authority using [method spawn]. Should return a [Node] that is not in the scene tree.
@@ -23,7 +23,7 @@
</method>
<method name="add_spawnable_scene">
<return type="void" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Adds a scene path to spawnable scenes, making it automatically replicated from the multiplayer authority to other peers when added as children of the node pointed by [member spawn_path].
</description>
@@ -36,7 +36,7 @@
</method>
<method name="get_spawnable_scene" qualifiers="const">
<return type="String" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Returns the spawnable scene path by index.
</description>
@@ -49,7 +49,7 @@
</method>
<method name="spawn">
<return type="Node" />
- <argument index="0" name="data" type="Variant" default="null" />
+ <param index="0" name="data" type="Variant" default="null" />
<description>
Requests a custom spawn, with [code]data[/code] passed to [method _spawn_custom] on all peers. Returns the locally spawned node instance already inside the scene tree, and added as a child of the node pointed by [member spawn_path].
@@ -69,13 +69,13 @@
</members>
<signals>
<signal name="despawned">
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
Emitted when a spawnable scene or custom spawn was despawned by the multiplayer authority. Only called on puppets.
</description>
</signal>
<signal name="spawned">
- <argument index="0" name="node" type="Node" />
+ <param index="0" name="node" type="Node" />
<description>
Emitted when a spawnable scene or custom spawn was spawned by the multiplayer authority. Only called on puppets.
</description>
diff --git a/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml b/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml
index a2ea64061c..9a4d755d64 100644
--- a/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml
+++ b/modules/multiplayer/doc_classes/MultiplayerSynchronizer.xml
@@ -16,7 +16,7 @@
<methods>
<method name="add_visibility_filter">
<return type="void" />
- <argument index="0" name="filter" type="Callable" />
+ <param index="0" name="filter" type="Callable" />
<description>
Adds a peer visibility filter for this synchronizer.
@@ -25,29 +25,29 @@
</method>
<method name="get_visibility_for" qualifiers="const">
<return type="bool" />
- <argument index="0" name="peer" type="int" />
+ <param index="0" name="peer" type="int" />
<description>
Queries the current visibility for peer [code]peer[/code].
</description>
</method>
<method name="remove_visibility_filter">
<return type="void" />
- <argument index="0" name="filter" type="Callable" />
+ <param index="0" name="filter" type="Callable" />
<description>
Removes a peer visiblity filter from this synchronizer.
</description>
</method>
<method name="set_visibility_for">
<return type="void" />
- <argument index="0" name="peer" type="int" />
- <argument index="1" name="visible" type="bool" />
+ <param index="0" name="peer" type="int" />
+ <param index="1" name="visible" type="bool" />
<description>
Sets the visibility of [code]peer[/code] to [code]visible[/code]. If [code]peer[/code] is [code]0[/code], the value of [member public_visibility] will be updated instead.
</description>
</method>
<method name="update_visibility">
<return type="void" />
- <argument index="0" name="for_peer" type="int" default="0" />
+ <param index="0" name="for_peer" type="int" default="0" />
<description>
Updates the visibility of [code]peer[/code] according to visibility filters. If [code]peer[/code] is [code]0[/code] (the default), all peers' visibilties are updated.
</description>
@@ -73,7 +73,7 @@
</members>
<signals>
<signal name="visibility_changed">
- <argument index="0" name="for_peer" type="int" />
+ <param index="0" name="for_peer" type="int" />
<description>
Emitted when visibility of [code]for_peer[/code] is updated. See [method update_visibility].
</description>
diff --git a/modules/multiplayer/doc_classes/SceneMultiplayer.xml b/modules/multiplayer/doc_classes/SceneMultiplayer.xml
index 0c3ed2d784..62bb396d15 100644
--- a/modules/multiplayer/doc_classes/SceneMultiplayer.xml
+++ b/modules/multiplayer/doc_classes/SceneMultiplayer.xml
@@ -21,10 +21,10 @@
</method>
<method name="send_bytes">
<return type="int" enum="Error" />
- <argument index="0" name="bytes" type="PackedByteArray" />
- <argument index="1" name="id" type="int" default="0" />
- <argument index="2" name="mode" type="int" enum="MultiplayerPeer.TransferMode" default="2" />
- <argument index="3" name="channel" type="int" default="0" />
+ <param index="0" name="bytes" type="PackedByteArray" />
+ <param index="1" name="id" type="int" default="0" />
+ <param index="2" name="mode" type="int" enum="MultiplayerPeer.TransferMode" default="2" />
+ <param index="3" name="channel" type="int" default="0" />
<description>
Sends the given raw [code]bytes[/code] to a specific peer identified by [code]id[/code] (see [method MultiplayerPeer.set_target_peer]). Default ID is [code]0[/code], i.e. broadcast to all peers.
</description>
@@ -45,8 +45,8 @@
</members>
<signals>
<signal name="peer_packet">
- <argument index="0" name="id" type="int" />
- <argument index="1" name="packet" type="PackedByteArray" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="packet" type="PackedByteArray" />
<description>
Emitted when this MultiplayerAPI's [member MultiplayerAPI.multiplayer_peer] receives a [code]packet[/code] with custom data (see [method send_bytes]). ID is the peer ID of the peer that sent the packet.
</description>
diff --git a/modules/multiplayer/doc_classes/SceneReplicationConfig.xml b/modules/multiplayer/doc_classes/SceneReplicationConfig.xml
index fc91592c7a..fdc441e9c3 100644
--- a/modules/multiplayer/doc_classes/SceneReplicationConfig.xml
+++ b/modules/multiplayer/doc_classes/SceneReplicationConfig.xml
@@ -10,8 +10,8 @@
<methods>
<method name="add_property">
<return type="void" />
- <argument index="0" name="path" type="NodePath" />
- <argument index="1" name="index" type="int" default="-1" />
+ <param index="0" name="path" type="NodePath" />
+ <param index="1" name="index" type="int" default="-1" />
<description>
Adds the property identified by the given [code]path[/code] to the list of the properties being synchronized, optionally passing an [code]index[/code].
</description>
@@ -24,51 +24,51 @@
</method>
<method name="has_property" qualifiers="const">
<return type="bool" />
- <argument index="0" name="path" type="NodePath" />
+ <param index="0" name="path" type="NodePath" />
<description>
Returns whether the given [code]path[/code] is configured for synchronization.
</description>
</method>
<method name="property_get_index" qualifiers="const">
<return type="int" />
- <argument index="0" name="path" type="NodePath" />
+ <param index="0" name="path" type="NodePath" />
<description>
Finds the index of the given [code]path[/code].
</description>
</method>
<method name="property_get_spawn">
<return type="bool" />
- <argument index="0" name="path" type="NodePath" />
+ <param index="0" name="path" type="NodePath" />
<description>
Returns whether the property identified by the given [code]path[/code] is configured to be synchronized on spawn.
</description>
</method>
<method name="property_get_sync">
<return type="bool" />
- <argument index="0" name="path" type="NodePath" />
+ <param index="0" name="path" type="NodePath" />
<description>
Returns whether the property identified by the given [code]path[/code] is configured to be synchronized on process.
</description>
</method>
<method name="property_set_spawn">
<return type="void" />
- <argument index="0" name="path" type="NodePath" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="path" type="NodePath" />
+ <param index="1" name="enabled" type="bool" />
<description>
Sets whether the property identified by the given [code]path[/code] is configured to be synchronized on spawn.
</description>
</method>
<method name="property_set_sync">
<return type="void" />
- <argument index="0" name="path" type="NodePath" />
- <argument index="1" name="enabled" type="bool" />
+ <param index="0" name="path" type="NodePath" />
+ <param index="1" name="enabled" type="bool" />
<description>
Sets whether the property identified by the given [code]path[/code] is configured to be synchronized on process.
</description>
</method>
<method name="remove_property">
<return type="void" />
- <argument index="0" name="path" type="NodePath" />
+ <param index="0" name="path" type="NodePath" />
<description>
Removes the property identified by the given [code]path[/code] from the configuration.
</description>
diff --git a/modules/multiplayer/editor/replication_editor_plugin.cpp b/modules/multiplayer/editor/replication_editor_plugin.cpp
index c6484264d0..f045018f25 100644
--- a/modules/multiplayer/editor/replication_editor_plugin.cpp
+++ b/modules/multiplayer/editor/replication_editor_plugin.cpp
@@ -32,9 +32,13 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
+#include "editor/editor_settings.h"
+#include "editor/editor_undo_redo_manager.h"
#include "editor/inspector_dock.h"
+#include "editor/scene_tree_editor.h"
#include "modules/multiplayer/multiplayer_synchronizer.h"
#include "scene/gui/dialogs.h"
+#include "scene/gui/separator.h"
#include "scene/gui/tree.h"
void ReplicationEditor::_pick_node_filter_text_changed(const String &p_newtext) {
@@ -136,7 +140,7 @@ void ReplicationEditor::_add_sync_property(String p_path) {
return;
}
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_singleton()->get_undo_redo();
undo_redo->create_action(TTR("Add property to synchronizer"));
if (config.is_null()) {
@@ -252,8 +256,6 @@ void ReplicationEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_checked", "property", "column", "checked"), &ReplicationEditor::_update_checked);
ClassDB::bind_method("_can_drop_data_fw", &ReplicationEditor::_can_drop_data_fw);
ClassDB::bind_method("_drop_data_fw", &ReplicationEditor::_drop_data_fw);
-
- ADD_SIGNAL(MethodInfo("keying_changed"));
}
bool ReplicationEditor::_can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
@@ -319,10 +321,6 @@ void ReplicationEditor::_notification(int p_what) {
add_pick_button->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
pin->set_icon(get_theme_icon(SNAME("Pin"), SNAME("EditorIcons")));
} break;
-
- case NOTIFICATION_VISIBILITY_CHANGED: {
- update_keying();
- } break;
}
}
@@ -338,28 +336,15 @@ void ReplicationEditor::_add_pressed() {
return;
}
String np_text = np_line_edit->get_text();
- if (np_text.find(":") == -1) {
- np_text = ":" + np_text;
- }
- NodePath prop = NodePath(np_text);
- if (prop.is_empty()) {
- return;
- }
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
- undo_redo->create_action(TTR("Add property"));
- config = current->get_replication_config();
- if (config.is_null()) {
- config.instantiate();
- current->set_replication_config(config);
- undo_redo->add_do_method(current, "set_replication_config", config);
- undo_redo->add_undo_method(current, "set_replication_config", Ref<SceneReplicationConfig>());
- _update_config();
+ int idx = np_text.find(":");
+ if (idx == -1) {
+ np_text = ".:" + np_text;
+ } else if (idx == 0) {
+ np_text = "." + np_text;
}
- undo_redo->add_do_method(config.ptr(), "add_property", prop);
- undo_redo->add_undo_method(config.ptr(), "remove_property", prop);
- undo_redo->add_do_method(this, "_update_config");
- undo_redo->add_undo_method(this, "_update_config");
- undo_redo->commit_action();
+ NodePath path = NodePath(np_text);
+
+ _add_sync_property(path);
}
void ReplicationEditor::_tree_item_edited() {
@@ -370,7 +355,7 @@ void ReplicationEditor::_tree_item_edited() {
int column = tree->get_edited_column();
ERR_FAIL_COND(column < 1 || column > 2);
const NodePath prop = ti->get_metadata(0);
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
bool value = ti->is_checked(column);
String method;
if (column == 1) {
@@ -410,7 +395,7 @@ void ReplicationEditor::_dialog_closed(bool p_confirmed) {
int idx = config->property_get_index(prop);
bool spawn = config->property_get_spawn(prop);
bool sync = config->property_get_sync(prop);
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> undo_redo = EditorNode::get_undo_redo();
undo_redo->create_action(TTR("Remove Property"));
undo_redo->add_do_method(config.ptr(), "remove_property", prop);
undo_redo->add_undo_method(config.ptr(), "add_property", prop, idx);
@@ -437,32 +422,12 @@ void ReplicationEditor::_update_checked(const NodePath &p_prop, int p_column, bo
}
}
-void ReplicationEditor::update_keying() {
- /// TODO make keying usable.
-#if 0
- bool keying_enabled = false;
- EditorSelectionHistory *editor_history = EditorNode::get_singleton()->get_editor_selection_history();
- if (is_visible_in_tree() && config.is_valid() && editor_history->get_path_size() > 0) {
- Object *obj = ObjectDB::get_instance(editor_history->get_path_object(0));
- keying_enabled = Object::cast_to<Node>(obj) != nullptr;
- }
-
- if (keying_enabled == keying) {
- return;
- }
-
- keying = keying_enabled;
- emit_signal(SNAME("keying_changed"));
-#endif
-}
-
void ReplicationEditor::_update_config() {
deleting = NodePath();
tree->clear();
tree->create_item();
drop_label->set_visible(true);
if (!config.is_valid()) {
- update_keying();
return;
}
TypedArray<NodePath> props = config->get_properties();
@@ -473,7 +438,6 @@ void ReplicationEditor::_update_config() {
const NodePath path = props[i];
_add_property(path, config->property_get_spawn(path), config->property_get_sync(path));
}
- update_keying();
}
void ReplicationEditor::edit(MultiplayerSynchronizer *p_sync) {
@@ -529,43 +493,6 @@ void ReplicationEditor::_add_property(const NodePath &p_property, bool p_spawn,
item->set_editable(2, true);
}
-void ReplicationEditor::property_keyed(const String &p_property) {
- ERR_FAIL_COND(!current || config.is_null());
- Node *root = current->get_node(current->get_root_path());
- ERR_FAIL_COND(!root);
- EditorSelectionHistory *history = EditorNode::get_singleton()->get_editor_selection_history();
- ERR_FAIL_COND(history->get_path_size() == 0);
- Node *node = Object::cast_to<Node>(ObjectDB::get_instance(history->get_path_object(0)));
- ERR_FAIL_COND(!node);
- if (node->is_class("MultiplayerSynchronizer")) {
- error_dialog->set_text(TTR("Properties of 'MultiplayerSynchronizer' cannot be configured for replication."));
- error_dialog->popup_centered();
- return;
- }
- if (history->get_path_size() > 1 || p_property.get_slice_count(":") > 1) {
- error_dialog->set_text(TTR("Subresources cannot yet be configured for replication."));
- error_dialog->popup_centered();
- return;
- }
-
- String path = root->get_path_to(node);
- for (int i = 1; i < history->get_path_size(); i++) {
- String prop = history->get_path_property(i);
- ERR_FAIL_COND(prop == "");
- path += ":" + prop;
- }
- path += ":" + p_property;
-
- NodePath prop = path;
- UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
- undo_redo->create_action(TTR("Add property"));
- undo_redo->add_do_method(config.ptr(), "add_property", prop);
- undo_redo->add_undo_method(config.ptr(), "remove_property", prop);
- undo_redo->add_do_method(this, "_update_config");
- undo_redo->add_undo_method(this, "_update_config");
- undo_redo->commit_action();
-}
-
/// ReplicationEditorPlugin
ReplicationEditorPlugin::ReplicationEditorPlugin() {
repl_editor = memnew(ReplicationEditor);
@@ -577,26 +504,9 @@ ReplicationEditorPlugin::ReplicationEditorPlugin() {
ReplicationEditorPlugin::~ReplicationEditorPlugin() {
}
-void ReplicationEditorPlugin::_keying_changed() {
- // TODO make lock usable.
- //InspectorDock::get_inspector_singleton()->set_keying(repl_editor->has_keying(), this);
-}
-
-void ReplicationEditorPlugin::_property_keyed(const String &p_keyed, const Variant &p_value, bool p_advance) {
- if (!repl_editor->has_keying()) {
- return;
- }
- repl_editor->property_keyed(p_keyed);
-}
-
void ReplicationEditorPlugin::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- //Node3DEditor::get_singleton()->connect("transform_key_request", callable_mp(this, &AnimationPlayerEditorPlugin::_transform_key_request));
- InspectorDock::get_inspector_singleton()->connect("property_keyed", callable_mp(this, &ReplicationEditorPlugin::_property_keyed));
- repl_editor->connect("keying_changed", callable_mp(this, &ReplicationEditorPlugin::_keying_changed));
- // TODO make lock usable.
- //InspectorDock::get_inspector_singleton()->connect("object_inspected", callable_mp(repl_editor, &ReplicationEditor::update_keying));
get_tree()->connect("node_removed", callable_mp(this, &ReplicationEditorPlugin::_node_removed));
} break;
}
@@ -632,8 +542,6 @@ bool ReplicationEditorPlugin::handles(Object *p_object) const {
void ReplicationEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
- //editor->hide_animation_player_editors();
- //editor->animation_panel_make_visible(true);
button->show();
EditorNode::get_singleton()->make_bottom_panel_item_visible(repl_editor);
} else if (!repl_editor->get_pin()->is_pressed()) {
diff --git a/modules/multiplayer/editor/replication_editor_plugin.h b/modules/multiplayer/editor/replication_editor_plugin.h
index 0bb2cb888d..e60e49cc25 100644
--- a/modules/multiplayer/editor/replication_editor_plugin.h
+++ b/modules/multiplayer/editor/replication_editor_plugin.h
@@ -40,7 +40,9 @@
class ConfirmationDialog;
class MultiplayerSynchronizer;
+class SceneTreeDialog;
class Tree;
+class TreeItem;
class ReplicationEditor : public VBoxContainer {
GDCLASS(ReplicationEditor, VBoxContainer);
@@ -59,7 +61,6 @@ private:
Ref<SceneReplicationConfig> config;
NodePath deleting;
Tree *tree = nullptr;
- bool keying = false;
PropertySelector *prop_selector = nullptr;
SceneTreeDialog *pick_node = nullptr;
@@ -96,11 +97,8 @@ protected:
void _notification(int p_what);
public:
- void update_keying();
void edit(MultiplayerSynchronizer *p_object);
- bool has_keying() const { return keying; }
MultiplayerSynchronizer *get_current() const { return current; }
- void property_keyed(const String &p_property);
Button *get_pin() { return pin; }
ReplicationEditor();
@@ -115,8 +113,6 @@ private:
ReplicationEditor *repl_editor = nullptr;
void _node_removed(Node *p_node);
- void _keying_changed();
- void _property_keyed(const String &p_keyed, const Variant &p_value, bool p_advance);
void _pinned();
@@ -131,17 +127,5 @@ public:
ReplicationEditorPlugin();
~ReplicationEditorPlugin();
};
-#else
-class ReplicationEditorPlugin : public EditorPlugin {
- GDCLASS(ReplicationEditorPlugin, EditorPlugin);
-
-public:
- virtual void edit(Object *p_object) override {}
- virtual bool handles(Object *p_object) const override { return false; }
- virtual void make_visible(bool p_visible) override {}
-
- ReplicationEditorPlugin() {}
- ~ReplicationEditorPlugin() {}
-};
#endif // REPLICATION_EDITOR_PLUGIN_H
diff --git a/modules/navigation/editor/navigation_mesh_editor_plugin.cpp b/modules/navigation/editor/navigation_mesh_editor_plugin.cpp
index c243e3e6e3..5cdff7b52a 100644
--- a/modules/navigation/editor/navigation_mesh_editor_plugin.cpp
+++ b/modules/navigation/editor/navigation_mesh_editor_plugin.cpp
@@ -110,7 +110,7 @@ NavigationMeshEditor::NavigationMeshEditor() {
button_reset->set_flat(true);
bake_hbox->add_child(button_reset);
// No button text, we only use a revert icon which is set when entering the tree.
- button_reset->set_tooltip(TTR("Clear the navigation mesh."));
+ button_reset->set_tooltip_text(TTR("Clear the navigation mesh."));
button_reset->connect("pressed", callable_mp(this, &NavigationMeshEditor::_clear_pressed));
bake_info = memnew(Label);
diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp
index 2cdb5b7cb4..4191e46f62 100644
--- a/modules/navigation/godot_navigation_server.cpp
+++ b/modules/navigation/godot_navigation_server.cpp
@@ -123,8 +123,8 @@ void GodotNavigationServer::add_command(SetCommand *command) const {
}
}
-Array GodotNavigationServer::get_maps() const {
- Array all_map_rids;
+TypedArray<RID> GodotNavigationServer::get_maps() const {
+ TypedArray<RID> all_map_rids;
List<RID> maps_owned;
map_owner.get_owned_list(&maps_owned);
if (maps_owned.size()) {
@@ -245,8 +245,8 @@ RID GodotNavigationServer::map_get_closest_point_owner(RID p_map, const Vector3
return map->get_closest_point_owner(p_point);
}
-Array GodotNavigationServer::map_get_regions(RID p_map) const {
- Array regions_rids;
+TypedArray<RID> GodotNavigationServer::map_get_regions(RID p_map) const {
+ TypedArray<RID> regions_rids;
const NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND_V(map == nullptr, regions_rids);
const LocalVector<NavRegion *> regions = map->get_regions();
@@ -257,8 +257,8 @@ Array GodotNavigationServer::map_get_regions(RID p_map) const {
return regions_rids;
}
-Array GodotNavigationServer::map_get_agents(RID p_map) const {
- Array agents_rids;
+TypedArray<RID> GodotNavigationServer::map_get_agents(RID p_map) const {
+ TypedArray<RID> agents_rids;
const NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND_V(map == nullptr, agents_rids);
const LocalVector<RvoAgent *> agents = map->get_agents();
@@ -453,11 +453,11 @@ COMMAND_2(agent_set_map, RID, p_agent, RID, p_map) {
}
}
-COMMAND_2(agent_set_neighbor_dist, RID, p_agent, real_t, p_dist) {
+COMMAND_2(agent_set_neighbor_distance, RID, p_agent, real_t, p_distance) {
RvoAgent *agent = agent_owner.get_or_null(p_agent);
ERR_FAIL_COND(agent == nullptr);
- agent->get_agent()->neighborDist_ = p_dist;
+ agent->get_agent()->neighborDist_ = p_distance;
}
COMMAND_2(agent_set_max_neighbors, RID, p_agent, int, p_count) {
diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h
index da1f8cba0b..05ba46ede1 100644
--- a/modules/navigation/godot_navigation_server.h
+++ b/modules/navigation/godot_navigation_server.h
@@ -85,7 +85,7 @@ public:
void add_command(SetCommand *command) const;
- virtual Array get_maps() const override;
+ virtual TypedArray<RID> get_maps() const override;
virtual RID map_create() const override;
COMMAND_2(map_set_active, RID, p_map, bool, p_active);
@@ -107,8 +107,8 @@ public:
virtual Vector3 map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const override;
virtual RID map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const override;
- virtual Array map_get_regions(RID p_map) const override;
- virtual Array map_get_agents(RID p_map) const override;
+ virtual TypedArray<RID> map_get_regions(RID p_map) const override;
+ virtual TypedArray<RID> map_get_agents(RID p_map) const override;
virtual void map_force_update(RID p_map) override;
@@ -135,7 +135,7 @@ public:
virtual RID agent_create() const override;
COMMAND_2(agent_set_map, RID, p_agent, RID, p_map);
virtual RID agent_get_map(RID p_agent) const override;
- COMMAND_2(agent_set_neighbor_dist, RID, p_agent, real_t, p_dist);
+ COMMAND_2(agent_set_neighbor_distance, RID, p_agent, real_t, p_distance);
COMMAND_2(agent_set_max_neighbors, RID, p_agent, int, p_count);
COMMAND_2(agent_set_time_horizon, RID, p_agent, real_t, p_time);
COMMAND_2(agent_set_radius, RID, p_agent, real_t, p_radius);
diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp
index 6e8ac77f79..848e554fb0 100644
--- a/modules/navigation/navigation_mesh_generator.cpp
+++ b/modules/navigation/navigation_mesh_generator.cpp
@@ -42,6 +42,7 @@
#include "scene/resources/concave_polygon_shape_3d.h"
#include "scene/resources/convex_polygon_shape_3d.h"
#include "scene/resources/cylinder_shape_3d.h"
+#include "scene/resources/height_map_shape_3d.h"
#include "scene/resources/primitive_meshes.h"
#include "scene/resources/shape_3d.h"
#include "scene/resources/sphere_shape_3d.h"
@@ -275,6 +276,50 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans
_add_faces(faces, transform, p_vertices, p_indices);
}
}
+
+ HeightMapShape3D *heightmap_shape = Object::cast_to<HeightMapShape3D>(*s);
+ if (heightmap_shape) {
+ int heightmap_depth = heightmap_shape->get_map_depth();
+ int heightmap_width = heightmap_shape->get_map_width();
+
+ if (heightmap_depth >= 2 && heightmap_width >= 2) {
+ const Vector<real_t> &map_data = heightmap_shape->get_map_data();
+
+ Vector2 heightmap_gridsize(heightmap_width - 1, heightmap_depth - 1);
+ Vector2 start = heightmap_gridsize * -0.5;
+
+ Vector<Vector3> vertex_array;
+ vertex_array.resize((heightmap_depth - 1) * (heightmap_width - 1) * 6);
+ int map_data_current_index = 0;
+
+ for (int d = 0; d < heightmap_depth - 1; d++) {
+ for (int w = 0; w < heightmap_width - 1; w++) {
+ if (map_data_current_index + 1 + heightmap_depth < map_data.size()) {
+ float top_left_height = map_data[map_data_current_index];
+ float top_right_height = map_data[map_data_current_index + 1];
+ float bottom_left_height = map_data[map_data_current_index + heightmap_depth];
+ float bottom_right_height = map_data[map_data_current_index + 1 + heightmap_depth];
+
+ Vector3 top_left = Vector3(start.x + w, top_left_height, start.y + d);
+ Vector3 top_right = Vector3(start.x + w + 1.0, top_right_height, start.y + d);
+ Vector3 bottom_left = Vector3(start.x + w, bottom_left_height, start.y + d + 1.0);
+ Vector3 bottom_right = Vector3(start.x + w + 1.0, bottom_right_height, start.y + d + 1.0);
+
+ vertex_array.push_back(top_right);
+ vertex_array.push_back(bottom_left);
+ vertex_array.push_back(top_left);
+ vertex_array.push_back(top_right);
+ vertex_array.push_back(bottom_right);
+ vertex_array.push_back(bottom_left);
+ }
+ map_data_current_index += 1;
+ }
+ }
+ if (vertex_array.size() > 0) {
+ _add_faces(vertex_array, transform, p_vertices, p_indices);
+ }
+ }
+ }
}
}
}
@@ -362,6 +407,50 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans
PackedVector3Array faces = Variant(dict["faces"]);
_add_faces(faces, shapes[i], p_vertices, p_indices);
} break;
+ case PhysicsServer3D::SHAPE_HEIGHTMAP: {
+ Dictionary dict = data;
+ ///< dict( int:"width", int:"depth",float:"cell_size", float_array:"heights"
+ int heightmap_depth = dict["depth"];
+ int heightmap_width = dict["width"];
+
+ if (heightmap_depth >= 2 && heightmap_width >= 2) {
+ const Vector<real_t> &map_data = dict["heights"];
+
+ Vector2 heightmap_gridsize(heightmap_width - 1, heightmap_depth - 1);
+ Vector2 start = heightmap_gridsize * -0.5;
+
+ Vector<Vector3> vertex_array;
+ vertex_array.resize((heightmap_depth - 1) * (heightmap_width - 1) * 6);
+ int map_data_current_index = 0;
+
+ for (int d = 0; d < heightmap_depth - 1; d++) {
+ for (int w = 0; w < heightmap_width - 1; w++) {
+ if (map_data_current_index + 1 + heightmap_depth < map_data.size()) {
+ float top_left_height = map_data[map_data_current_index];
+ float top_right_height = map_data[map_data_current_index + 1];
+ float bottom_left_height = map_data[map_data_current_index + heightmap_depth];
+ float bottom_right_height = map_data[map_data_current_index + 1 + heightmap_depth];
+
+ Vector3 top_left = Vector3(start.x + w, top_left_height, start.y + d);
+ Vector3 top_right = Vector3(start.x + w + 1.0, top_right_height, start.y + d);
+ Vector3 bottom_left = Vector3(start.x + w, bottom_left_height, start.y + d + 1.0);
+ Vector3 bottom_right = Vector3(start.x + w + 1.0, bottom_right_height, start.y + d + 1.0);
+
+ vertex_array.push_back(top_right);
+ vertex_array.push_back(bottom_left);
+ vertex_array.push_back(top_left);
+ vertex_array.push_back(top_right);
+ vertex_array.push_back(bottom_right);
+ vertex_array.push_back(bottom_left);
+ }
+ map_data_current_index += 1;
+ }
+ }
+ if (vertex_array.size() > 0) {
+ _add_faces(vertex_array, shapes[i], p_vertices, p_indices);
+ }
+ }
+ } break;
default: {
WARN_PRINT("Unsupported collision shape type.");
} break;
diff --git a/modules/noise/config.py b/modules/noise/config.py
index 74db20f2a4..2318d28c53 100644
--- a/modules/noise/config.py
+++ b/modules/noise/config.py
@@ -10,7 +10,7 @@ def get_doc_classes():
return [
"FastNoiseLite",
"Noise",
- "NoiseTexture",
+ "NoiseTexture2D",
]
diff --git a/modules/noise/doc_classes/Noise.xml b/modules/noise/doc_classes/Noise.xml
index 5af204575c..735ca388de 100644
--- a/modules/noise/doc_classes/Noise.xml
+++ b/modules/noise/doc_classes/Noise.xml
@@ -13,59 +13,59 @@
<methods>
<method name="get_image" qualifiers="const">
<return type="Image" />
- <argument index="0" name="width" type="int" />
- <argument index="1" name="height" type="int" />
- <argument index="2" name="invert" type="bool" default="false" />
- <argument index="3" name="in_3d_space" type="bool" default="false" />
+ <param index="0" name="width" type="int" />
+ <param index="1" name="height" type="int" />
+ <param index="2" name="invert" type="bool" default="false" />
+ <param index="3" name="in_3d_space" type="bool" default="false" />
<description>
Returns a 2D [Image] noise image.
</description>
</method>
<method name="get_noise_1d" qualifiers="const">
<return type="float" />
- <argument index="0" name="x" type="float" />
+ <param index="0" name="x" type="float" />
<description>
Returns the 1D noise value at the given (x) coordinate.
</description>
</method>
<method name="get_noise_2d" qualifiers="const">
<return type="float" />
- <argument index="0" name="x" type="float" />
- <argument index="1" name="y" type="float" />
+ <param index="0" name="x" type="float" />
+ <param index="1" name="y" type="float" />
<description>
Returns the 2D noise value at the given position.
</description>
</method>
<method name="get_noise_2dv" qualifiers="const">
<return type="float" />
- <argument index="0" name="v" type="Vector2" />
+ <param index="0" name="v" type="Vector2" />
<description>
Returns the 2D noise value at the given position.
</description>
</method>
<method name="get_noise_3d" qualifiers="const">
<return type="float" />
- <argument index="0" name="x" type="float" />
- <argument index="1" name="y" type="float" />
- <argument index="2" name="z" type="float" />
+ <param index="0" name="x" type="float" />
+ <param index="1" name="y" type="float" />
+ <param index="2" name="z" type="float" />
<description>
Returns the 3D noise value at the given position.
</description>
</method>
<method name="get_noise_3dv" qualifiers="const">
<return type="float" />
- <argument index="0" name="v" type="Vector3" />
+ <param index="0" name="v" type="Vector3" />
<description>
Returns the 3D noise value at the given position.
</description>
</method>
<method name="get_seamless_image" qualifiers="const">
<return type="Image" />
- <argument index="0" name="width" type="int" />
- <argument index="1" name="height" type="int" />
- <argument index="2" name="invert" type="bool" default="false" />
- <argument index="3" name="in_3d_space" type="bool" default="false" />
- <argument index="4" name="skirt" type="float" default="0.1" />
+ <param index="0" name="width" type="int" />
+ <param index="1" name="height" type="int" />
+ <param index="2" name="invert" type="bool" default="false" />
+ <param index="3" name="in_3d_space" type="bool" default="false" />
+ <param index="4" name="skirt" type="float" default="0.1" />
<description>
Returns a seamless 2D [Image] noise image.
</description>
diff --git a/modules/noise/doc_classes/NoiseTexture.xml b/modules/noise/doc_classes/NoiseTexture2D.xml
index 62a223b387..9eea2738c5 100644
--- a/modules/noise/doc_classes/NoiseTexture.xml
+++ b/modules/noise/doc_classes/NoiseTexture2D.xml
@@ -1,14 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NoiseTexture" inherits="Texture2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="NoiseTexture2D" inherits="Texture2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
A texture filled with noise generated by a [Noise] object.
</brief_description>
<description>
Uses [FastNoiseLite] or other libraries to fill the texture data of your desired size.
- NoiseTexture can also generate normalmap textures.
+ NoiseTexture2D can also generate normalmap textures.
The class uses [Thread]s to generate the texture data internally, so [method Texture2D.get_image] may return [code]null[/code] if the generation process has not completed yet. In that case, you need to wait for the texture to be generated before accessing the image and the generated byte data:
[codeblock]
- var texture = NoiseTexture.new()
+ var texture = NoiseTexture2D.new()
texture.noise = FastNoiseLite.new()
await texture.changed
var image = texture.get_image()
diff --git a/modules/noise/editor/noise_editor_plugin.cpp b/modules/noise/editor/noise_editor_plugin.cpp
index 27a86f45b5..e8e73e4fd9 100644
--- a/modules/noise/editor/noise_editor_plugin.cpp
+++ b/modules/noise/editor/noise_editor_plugin.cpp
@@ -35,7 +35,7 @@
#include "editor/editor_scale.h"
#include "modules/noise/noise.h"
-#include "modules/noise/noise_texture.h"
+#include "modules/noise/noise_texture_2d.h"
class NoisePreview : public Control {
GDCLASS(NoisePreview, Control)
@@ -60,7 +60,7 @@ public:
_3d_space_switch = memnew(Button);
_3d_space_switch->set_text(TTR("3D"));
- _3d_space_switch->set_tooltip(TTR("Toggles whether the noise preview is computed in 3D space."));
+ _3d_space_switch->set_tooltip_text(TTR("Toggles whether the noise preview is computed in 3D space."));
_3d_space_switch->set_toggle_mode(true);
_3d_space_switch->set_offset(SIDE_LEFT, PADDING_3D_SPACE_SWITCH);
_3d_space_switch->set_offset(SIDE_TOP, PADDING_3D_SPACE_SWITCH);
@@ -102,7 +102,7 @@ private:
void update_preview() {
if (MIN(_preview_texture_size.width, _preview_texture_size.height) > 0) {
- Ref<NoiseTexture> tex;
+ Ref<NoiseTexture2D> tex;
tex.instantiate();
tex->set_width(_preview_texture_size.width);
tex->set_height(_preview_texture_size.height);
diff --git a/modules/noise/fastnoise_lite.cpp b/modules/noise/fastnoise_lite.cpp
index b21e3247d7..06d97838f6 100644
--- a/modules/noise/fastnoise_lite.cpp
+++ b/modules/noise/fastnoise_lite.cpp
@@ -476,24 +476,24 @@ void FastNoiseLite::_bind_methods() {
BIND_ENUM_CONSTANT(DOMAIN_WARP_FRACTAL_INDEPENDENT);
}
-void FastNoiseLite::_validate_property(PropertyInfo &property) const {
- if (property.name.begins_with("cellular") && get_noise_type() != TYPE_CELLULAR) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void FastNoiseLite::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name.begins_with("cellular") && get_noise_type() != TYPE_CELLULAR) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
return;
}
- if (property.name != "fractal_type" && property.name.begins_with("fractal") && get_fractal_type() == FRACTAL_NONE) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name != "fractal_type" && p_property.name.begins_with("fractal") && get_fractal_type() == FRACTAL_NONE) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
return;
}
- if (property.name == "fractal_ping_pong_strength" && get_fractal_type() != FRACTAL_PING_PONG) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == "fractal_ping_pong_strength" && get_fractal_type() != FRACTAL_PING_PONG) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
return;
}
- if (property.name != "domain_warp_enabled" && property.name.begins_with("domain_warp") && !domain_warp_enabled) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name != "domain_warp_enabled" && p_property.name.begins_with("domain_warp") && !domain_warp_enabled) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
return;
}
}
diff --git a/modules/noise/fastnoise_lite.h b/modules/noise/fastnoise_lite.h
index fe8cd7ce6e..50c633b923 100644
--- a/modules/noise/fastnoise_lite.h
+++ b/modules/noise/fastnoise_lite.h
@@ -92,7 +92,7 @@ public:
protected:
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
private:
_FastNoiseLite _noise;
diff --git a/modules/noise/noise_texture.cpp b/modules/noise/noise_texture_2d.cpp
index ca55d3b96d..8d279f9dd3 100644
--- a/modules/noise/noise_texture.cpp
+++ b/modules/noise/noise_texture_2d.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* noise_texture.cpp */
+/* noise_texture_2d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,58 +28,58 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "noise_texture.h"
+#include "noise_texture_2d.h"
#include "core/core_string_names.h"
#include "noise.h"
-NoiseTexture::NoiseTexture() {
+NoiseTexture2D::NoiseTexture2D() {
noise = Ref<Noise>();
_queue_update();
}
-NoiseTexture::~NoiseTexture() {
+NoiseTexture2D::~NoiseTexture2D() {
if (texture.is_valid()) {
RS::get_singleton()->free(texture);
}
noise_thread.wait_to_finish();
}
-void NoiseTexture::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_update_texture"), &NoiseTexture::_update_texture);
- ClassDB::bind_method(D_METHOD("_generate_texture"), &NoiseTexture::_generate_texture);
- ClassDB::bind_method(D_METHOD("_thread_done", "image"), &NoiseTexture::_thread_done);
+void NoiseTexture2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_update_texture"), &NoiseTexture2D::_update_texture);
+ ClassDB::bind_method(D_METHOD("_generate_texture"), &NoiseTexture2D::_generate_texture);
+ ClassDB::bind_method(D_METHOD("_thread_done", "image"), &NoiseTexture2D::_thread_done);
- ClassDB::bind_method(D_METHOD("set_width", "width"), &NoiseTexture::set_width);
- ClassDB::bind_method(D_METHOD("set_height", "height"), &NoiseTexture::set_height);
+ ClassDB::bind_method(D_METHOD("set_width", "width"), &NoiseTexture2D::set_width);
+ ClassDB::bind_method(D_METHOD("set_height", "height"), &NoiseTexture2D::set_height);
- ClassDB::bind_method(D_METHOD("set_invert", "invert"), &NoiseTexture::set_invert);
- ClassDB::bind_method(D_METHOD("get_invert"), &NoiseTexture::get_invert);
+ ClassDB::bind_method(D_METHOD("set_invert", "invert"), &NoiseTexture2D::set_invert);
+ ClassDB::bind_method(D_METHOD("get_invert"), &NoiseTexture2D::get_invert);
- ClassDB::bind_method(D_METHOD("set_in_3d_space", "enable"), &NoiseTexture::set_in_3d_space);
- ClassDB::bind_method(D_METHOD("is_in_3d_space"), &NoiseTexture::is_in_3d_space);
+ ClassDB::bind_method(D_METHOD("set_in_3d_space", "enable"), &NoiseTexture2D::set_in_3d_space);
+ ClassDB::bind_method(D_METHOD("is_in_3d_space"), &NoiseTexture2D::is_in_3d_space);
- ClassDB::bind_method(D_METHOD("set_generate_mipmaps", "invert"), &NoiseTexture::set_generate_mipmaps);
- ClassDB::bind_method(D_METHOD("is_generating_mipmaps"), &NoiseTexture::is_generating_mipmaps);
+ ClassDB::bind_method(D_METHOD("set_generate_mipmaps", "invert"), &NoiseTexture2D::set_generate_mipmaps);
+ ClassDB::bind_method(D_METHOD("is_generating_mipmaps"), &NoiseTexture2D::is_generating_mipmaps);
- ClassDB::bind_method(D_METHOD("set_seamless", "seamless"), &NoiseTexture::set_seamless);
- ClassDB::bind_method(D_METHOD("get_seamless"), &NoiseTexture::get_seamless);
+ ClassDB::bind_method(D_METHOD("set_seamless", "seamless"), &NoiseTexture2D::set_seamless);
+ ClassDB::bind_method(D_METHOD("get_seamless"), &NoiseTexture2D::get_seamless);
- ClassDB::bind_method(D_METHOD("set_seamless_blend_skirt", "seamless_blend_skirt"), &NoiseTexture::set_seamless_blend_skirt);
- ClassDB::bind_method(D_METHOD("get_seamless_blend_skirt"), &NoiseTexture::get_seamless_blend_skirt);
+ ClassDB::bind_method(D_METHOD("set_seamless_blend_skirt", "seamless_blend_skirt"), &NoiseTexture2D::set_seamless_blend_skirt);
+ ClassDB::bind_method(D_METHOD("get_seamless_blend_skirt"), &NoiseTexture2D::get_seamless_blend_skirt);
- ClassDB::bind_method(D_METHOD("set_as_normal_map", "as_normal_map"), &NoiseTexture::set_as_normal_map);
- ClassDB::bind_method(D_METHOD("is_normal_map"), &NoiseTexture::is_normal_map);
+ ClassDB::bind_method(D_METHOD("set_as_normal_map", "as_normal_map"), &NoiseTexture2D::set_as_normal_map);
+ ClassDB::bind_method(D_METHOD("is_normal_map"), &NoiseTexture2D::is_normal_map);
- ClassDB::bind_method(D_METHOD("set_bump_strength", "bump_strength"), &NoiseTexture::set_bump_strength);
- ClassDB::bind_method(D_METHOD("get_bump_strength"), &NoiseTexture::get_bump_strength);
+ ClassDB::bind_method(D_METHOD("set_bump_strength", "bump_strength"), &NoiseTexture2D::set_bump_strength);
+ ClassDB::bind_method(D_METHOD("get_bump_strength"), &NoiseTexture2D::get_bump_strength);
- ClassDB::bind_method(D_METHOD("set_color_ramp", "gradient"), &NoiseTexture::set_color_ramp);
- ClassDB::bind_method(D_METHOD("get_color_ramp"), &NoiseTexture::get_color_ramp);
+ ClassDB::bind_method(D_METHOD("set_color_ramp", "gradient"), &NoiseTexture2D::set_color_ramp);
+ ClassDB::bind_method(D_METHOD("get_color_ramp"), &NoiseTexture2D::get_color_ramp);
- ClassDB::bind_method(D_METHOD("set_noise", "noise"), &NoiseTexture::set_noise);
- ClassDB::bind_method(D_METHOD("get_noise"), &NoiseTexture::get_noise);
+ ClassDB::bind_method(D_METHOD("set_noise", "noise"), &NoiseTexture2D::set_noise);
+ ClassDB::bind_method(D_METHOD("get_noise"), &NoiseTexture2D::get_noise);
ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048,1,or_greater,suffix:px"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048,1,or_greater,suffix:px"), "set_height", "get_height");
@@ -94,21 +94,21 @@ void NoiseTexture::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "noise", PROPERTY_HINT_RESOURCE_TYPE, "Noise"), "set_noise", "get_noise");
}
-void NoiseTexture::_validate_property(PropertyInfo &property) const {
- if (property.name == "bump_strength") {
+void NoiseTexture2D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "bump_strength") {
if (!as_normal_map) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
- if (property.name == "seamless_blend_skirt") {
+ if (p_property.name == "seamless_blend_skirt") {
if (!seamless) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
}
-void NoiseTexture::_set_texture_image(const Ref<Image> &p_image) {
+void NoiseTexture2D::_set_texture_image(const Ref<Image> &p_image) {
image = p_image;
if (image.is_valid()) {
if (texture.is_valid()) {
@@ -121,7 +121,7 @@ void NoiseTexture::_set_texture_image(const Ref<Image> &p_image) {
emit_changed();
}
-void NoiseTexture::_thread_done(const Ref<Image> &p_image) {
+void NoiseTexture2D::_thread_done(const Ref<Image> &p_image) {
_set_texture_image(p_image);
noise_thread.wait_to_finish();
if (regen_queued) {
@@ -130,12 +130,12 @@ void NoiseTexture::_thread_done(const Ref<Image> &p_image) {
}
}
-void NoiseTexture::_thread_function(void *p_ud) {
- NoiseTexture *tex = static_cast<NoiseTexture *>(p_ud);
+void NoiseTexture2D::_thread_function(void *p_ud) {
+ NoiseTexture2D *tex = static_cast<NoiseTexture2D *>(p_ud);
tex->call_deferred(SNAME("_thread_done"), tex->_generate_texture());
}
-void NoiseTexture::_queue_update() {
+void NoiseTexture2D::_queue_update() {
if (update_queued) {
return;
}
@@ -144,7 +144,7 @@ void NoiseTexture::_queue_update() {
call_deferred(SNAME("_update_texture"));
}
-Ref<Image> NoiseTexture::_generate_texture() {
+Ref<Image> NoiseTexture2D::_generate_texture() {
// Prevent memdelete due to unref() on other thread.
Ref<Noise> ref_noise = noise;
@@ -172,7 +172,7 @@ Ref<Image> NoiseTexture::_generate_texture() {
return image;
}
-Ref<Image> NoiseTexture::_modulate_with_gradient(Ref<Image> p_image, Ref<Gradient> p_gradient) {
+Ref<Image> NoiseTexture2D::_modulate_with_gradient(Ref<Image> p_image, Ref<Gradient> p_gradient) {
int width = p_image->get_width();
int height = p_image->get_height();
@@ -191,7 +191,7 @@ Ref<Image> NoiseTexture::_modulate_with_gradient(Ref<Image> p_image, Ref<Gradien
return new_image;
}
-void NoiseTexture::_update_texture() {
+void NoiseTexture2D::_update_texture() {
bool use_thread = true;
if (first_time) {
use_thread = false;
@@ -215,25 +215,25 @@ void NoiseTexture::_update_texture() {
update_queued = false;
}
-void NoiseTexture::set_noise(Ref<Noise> p_noise) {
+void NoiseTexture2D::set_noise(Ref<Noise> p_noise) {
if (p_noise == noise) {
return;
}
if (noise.is_valid()) {
- noise->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture::_queue_update));
+ noise->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture2D::_queue_update));
}
noise = p_noise;
if (noise.is_valid()) {
- noise->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture::_queue_update));
+ noise->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture2D::_queue_update));
}
_queue_update();
}
-Ref<Noise> NoiseTexture::get_noise() {
+Ref<Noise> NoiseTexture2D::get_noise() {
return noise;
}
-void NoiseTexture::set_width(int p_width) {
+void NoiseTexture2D::set_width(int p_width) {
ERR_FAIL_COND(p_width <= 0);
if (p_width == size.x) {
return;
@@ -242,7 +242,7 @@ void NoiseTexture::set_width(int p_width) {
_queue_update();
}
-void NoiseTexture::set_height(int p_height) {
+void NoiseTexture2D::set_height(int p_height) {
ERR_FAIL_COND(p_height <= 0);
if (p_height == size.y) {
return;
@@ -251,7 +251,7 @@ void NoiseTexture::set_height(int p_height) {
_queue_update();
}
-void NoiseTexture::set_invert(bool p_invert) {
+void NoiseTexture2D::set_invert(bool p_invert) {
if (p_invert == invert) {
return;
}
@@ -259,22 +259,22 @@ void NoiseTexture::set_invert(bool p_invert) {
_queue_update();
}
-bool NoiseTexture::get_invert() const {
+bool NoiseTexture2D::get_invert() const {
return invert;
}
-void NoiseTexture::set_in_3d_space(bool p_enable) {
+void NoiseTexture2D::set_in_3d_space(bool p_enable) {
if (p_enable == in_3d_space) {
return;
}
in_3d_space = p_enable;
_queue_update();
}
-bool NoiseTexture::is_in_3d_space() const {
+bool NoiseTexture2D::is_in_3d_space() const {
return in_3d_space;
}
-void NoiseTexture::set_generate_mipmaps(bool p_enable) {
+void NoiseTexture2D::set_generate_mipmaps(bool p_enable) {
if (p_enable == generate_mipmaps) {
return;
}
@@ -282,11 +282,11 @@ void NoiseTexture::set_generate_mipmaps(bool p_enable) {
_queue_update();
}
-bool NoiseTexture::is_generating_mipmaps() const {
+bool NoiseTexture2D::is_generating_mipmaps() const {
return generate_mipmaps;
}
-void NoiseTexture::set_seamless(bool p_seamless) {
+void NoiseTexture2D::set_seamless(bool p_seamless) {
if (p_seamless == seamless) {
return;
}
@@ -295,11 +295,11 @@ void NoiseTexture::set_seamless(bool p_seamless) {
notify_property_list_changed();
}
-bool NoiseTexture::get_seamless() {
+bool NoiseTexture2D::get_seamless() {
return seamless;
}
-void NoiseTexture::set_seamless_blend_skirt(real_t p_blend_skirt) {
+void NoiseTexture2D::set_seamless_blend_skirt(real_t p_blend_skirt) {
ERR_FAIL_COND(p_blend_skirt < 0.05 || p_blend_skirt > 1);
if (p_blend_skirt == seamless_blend_skirt) {
@@ -308,11 +308,11 @@ void NoiseTexture::set_seamless_blend_skirt(real_t p_blend_skirt) {
seamless_blend_skirt = p_blend_skirt;
_queue_update();
}
-real_t NoiseTexture::get_seamless_blend_skirt() {
+real_t NoiseTexture2D::get_seamless_blend_skirt() {
return seamless_blend_skirt;
}
-void NoiseTexture::set_as_normal_map(bool p_as_normal_map) {
+void NoiseTexture2D::set_as_normal_map(bool p_as_normal_map) {
if (p_as_normal_map == as_normal_map) {
return;
}
@@ -321,11 +321,11 @@ void NoiseTexture::set_as_normal_map(bool p_as_normal_map) {
notify_property_list_changed();
}
-bool NoiseTexture::is_normal_map() {
+bool NoiseTexture2D::is_normal_map() {
return as_normal_map;
}
-void NoiseTexture::set_bump_strength(float p_bump_strength) {
+void NoiseTexture2D::set_bump_strength(float p_bump_strength) {
if (p_bump_strength == bump_strength) {
return;
}
@@ -335,37 +335,37 @@ void NoiseTexture::set_bump_strength(float p_bump_strength) {
}
}
-float NoiseTexture::get_bump_strength() {
+float NoiseTexture2D::get_bump_strength() {
return bump_strength;
}
-void NoiseTexture::set_color_ramp(const Ref<Gradient> &p_gradient) {
+void NoiseTexture2D::set_color_ramp(const Ref<Gradient> &p_gradient) {
if (p_gradient == color_ramp) {
return;
}
if (color_ramp.is_valid()) {
- color_ramp->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture::_queue_update));
+ color_ramp->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture2D::_queue_update));
}
color_ramp = p_gradient;
if (color_ramp.is_valid()) {
- color_ramp->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture::_queue_update));
+ color_ramp->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture2D::_queue_update));
}
_queue_update();
}
-Ref<Gradient> NoiseTexture::get_color_ramp() const {
+Ref<Gradient> NoiseTexture2D::get_color_ramp() const {
return color_ramp;
}
-int NoiseTexture::get_width() const {
+int NoiseTexture2D::get_width() const {
return size.x;
}
-int NoiseTexture::get_height() const {
+int NoiseTexture2D::get_height() const {
return size.y;
}
-RID NoiseTexture::get_rid() const {
+RID NoiseTexture2D::get_rid() const {
if (!texture.is_valid()) {
texture = RS::get_singleton()->texture_2d_placeholder_create();
}
@@ -373,6 +373,6 @@ RID NoiseTexture::get_rid() const {
return texture;
}
-Ref<Image> NoiseTexture::get_image() const {
+Ref<Image> NoiseTexture2D::get_image() const {
return image;
}
diff --git a/modules/noise/noise_texture.h b/modules/noise/noise_texture_2d.h
index 6c088562a1..8f8e256fb9 100644
--- a/modules/noise/noise_texture.h
+++ b/modules/noise/noise_texture_2d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* noise_texture.h */
+/* noise_texture_2d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,16 +28,16 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef NOISE_TEXTURE_H
-#define NOISE_TEXTURE_H
+#ifndef NOISE_TEXTURE_2D_H
+#define NOISE_TEXTURE_2D_H
#include "noise.h"
#include "core/object/ref_counted.h"
#include "scene/resources/texture.h"
-class NoiseTexture : public Texture2D {
- GDCLASS(NoiseTexture, Texture2D);
+class NoiseTexture2D : public Texture2D {
+ GDCLASS(NoiseTexture2D, Texture2D);
private:
Ref<Image> image;
@@ -75,7 +75,7 @@ private:
protected:
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_noise(Ref<Noise> p_noise);
@@ -116,8 +116,8 @@ public:
virtual Ref<Image> get_image() const override;
- NoiseTexture();
- virtual ~NoiseTexture();
+ NoiseTexture2D();
+ virtual ~NoiseTexture2D();
};
-#endif // NOISE_TEXTURE_H
+#endif // NOISE_TEXTURE_2D_H
diff --git a/modules/noise/register_types.cpp b/modules/noise/register_types.cpp
index d0cfc4e944..c44bf9828f 100644
--- a/modules/noise/register_types.cpp
+++ b/modules/noise/register_types.cpp
@@ -32,7 +32,7 @@
#include "fastnoise_lite.h"
#include "noise.h"
-#include "noise_texture.h"
+#include "noise_texture_2d.h"
#ifdef TOOLS_ENABLED
#include "editor/editor_plugin.h"
@@ -41,9 +41,10 @@
void initialize_noise_module(ModuleInitializationLevel p_level) {
if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
- GDREGISTER_CLASS(NoiseTexture);
+ GDREGISTER_CLASS(NoiseTexture2D);
GDREGISTER_ABSTRACT_CLASS(Noise);
GDREGISTER_CLASS(FastNoiseLite);
+ ClassDB::add_compatibility_class("NoiseTexture", "NoiseTexture2D");
}
#ifdef TOOLS_ENABLED
diff --git a/modules/openxr/doc_classes/OpenXRAction.xml b/modules/openxr/doc_classes/OpenXRAction.xml
index 6ff8c1ad26..d1a2ce2d2e 100644
--- a/modules/openxr/doc_classes/OpenXRAction.xml
+++ b/modules/openxr/doc_classes/OpenXRAction.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
This resource defines an OpenXR action. Actions can be used both for inputs (buttons/joystick/trigger/etc) and outputs (haptics).
- OpenXR performs automatic conversion between action type and input type whenever possible. An analogue trigger bound to a boolean action will thus return [code]false[/core] if the trigger is depressed and [code]true[/code] if pressed fully.
+ OpenXR performs automatic conversion between action type and input type whenever possible. An analogue trigger bound to a boolean action will thus return [code]false[/code] if the trigger is depressed and [code]true[/code] if pressed fully.
Actions are not directly bound to specific devices, instead OpenXR recognises a limited number of top level paths that identify devices by usage. We can restrict which devices an action can be bound to by these top level paths. For instance an action that should only be used for hand held controllers can have the top level paths "/user/hand/left" and "/user/hand/right" associated with them. See the [url=https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#semantic-path-reserved]reserved path section in the OpenXR specification[/url] for more info on the top level paths.
Note that the name of the resource is used to register the action with.
</description>
diff --git a/modules/openxr/doc_classes/OpenXRActionMap.xml b/modules/openxr/doc_classes/OpenXRActionMap.xml
index a29d10be41..8a2f666e3f 100644
--- a/modules/openxr/doc_classes/OpenXRActionMap.xml
+++ b/modules/openxr/doc_classes/OpenXRActionMap.xml
@@ -13,14 +13,14 @@
<methods>
<method name="add_action_set">
<return type="void" />
- <argument index="0" name="action_set" type="OpenXRActionSet" />
+ <param index="0" name="action_set" type="OpenXRActionSet" />
<description>
Add an action set.
</description>
</method>
<method name="add_interaction_profile">
<return type="void" />
- <argument index="0" name="interaction_profile" type="OpenXRInteractionProfile" />
+ <param index="0" name="interaction_profile" type="OpenXRInteractionProfile" />
<description>
Add an interaction profile.
</description>
@@ -33,21 +33,21 @@
</method>
<method name="find_action_set" qualifiers="const">
<return type="OpenXRActionSet" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
Retrieve an action set by name.
</description>
</method>
<method name="find_interaction_profile" qualifiers="const">
<return type="OpenXRInteractionProfile" />
- <argument index="0" name="name" type="String" />
+ <param index="0" name="name" type="String" />
<description>
Find an interaction profile by its name (path).
</description>
</method>
<method name="get_action_set" qualifiers="const">
<return type="OpenXRActionSet" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Retrieve the action set at this index.
</description>
@@ -60,7 +60,7 @@
</method>
<method name="get_interaction_profile" qualifiers="const">
<return type="OpenXRInteractionProfile" />
- <argument index="0" name="idx" type="int" />
+ <param index="0" name="idx" type="int" />
<description>
Get the interaction profile at this index.
</description>
@@ -73,14 +73,14 @@
</method>
<method name="remove_action_set">
<return type="void" />
- <argument index="0" name="action_set" type="OpenXRActionSet" />
+ <param index="0" name="action_set" type="OpenXRActionSet" />
<description>
Remove an action set.
</description>
</method>
<method name="remove_interaction_profile">
<return type="void" />
- <argument index="0" name="interaction_profile" type="OpenXRInteractionProfile" />
+ <param index="0" name="interaction_profile" type="OpenXRInteractionProfile" />
<description>
Remove an interaction profile.
</description>
diff --git a/modules/openxr/doc_classes/OpenXRActionSet.xml b/modules/openxr/doc_classes/OpenXRActionSet.xml
index 55cc0aaad4..db3259ec07 100644
--- a/modules/openxr/doc_classes/OpenXRActionSet.xml
+++ b/modules/openxr/doc_classes/OpenXRActionSet.xml
@@ -12,7 +12,7 @@
<methods>
<method name="add_action">
<return type="void" />
- <argument index="0" name="action" type="OpenXRAction" />
+ <param index="0" name="action" type="OpenXRAction" />
<description>
Add an action to this action set.
</description>
@@ -25,7 +25,7 @@
</method>
<method name="remove_action">
<return type="void" />
- <argument index="0" name="action" type="OpenXRAction" />
+ <param index="0" name="action" type="OpenXRAction" />
<description>
Remove an action from this action set.
</description>
diff --git a/modules/openxr/doc_classes/OpenXRIPBinding.xml b/modules/openxr/doc_classes/OpenXRIPBinding.xml
index f96637f2f5..00806bda06 100644
--- a/modules/openxr/doc_classes/OpenXRIPBinding.xml
+++ b/modules/openxr/doc_classes/OpenXRIPBinding.xml
@@ -11,7 +11,7 @@
<methods>
<method name="add_path">
<return type="void" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Add an input/output path to this binding.
</description>
@@ -24,14 +24,14 @@
</method>
<method name="has_path" qualifiers="const">
<return type="bool" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Returns [code]true[/code] if this input/output path is part of this binding.
</description>
</method>
<method name="remove_path">
<return type="void" />
- <argument index="0" name="path" type="String" />
+ <param index="0" name="path" type="String" />
<description>
Removes this input/output path from this binding.
</description>
diff --git a/modules/openxr/doc_classes/OpenXRInteractionProfile.xml b/modules/openxr/doc_classes/OpenXRInteractionProfile.xml
index 71c0db44ed..950bde031f 100644
--- a/modules/openxr/doc_classes/OpenXRInteractionProfile.xml
+++ b/modules/openxr/doc_classes/OpenXRInteractionProfile.xml
@@ -12,7 +12,7 @@
<methods>
<method name="get_binding" qualifiers="const">
<return type="OpenXRIPBinding" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Retrieve the binding at this index.
</description>
diff --git a/modules/openxr/editor/openxr_action_editor.cpp b/modules/openxr/editor/openxr_action_editor.cpp
index 41c6465f43..52216fa483 100644
--- a/modules/openxr/editor/openxr_action_editor.cpp
+++ b/modules/openxr/editor/openxr_action_editor.cpp
@@ -104,7 +104,7 @@ OpenXRActionEditor::OpenXRActionEditor(Ref<OpenXRAction> p_action) {
// maybe add dropdown to edit our toplevel paths, or do we deduce them from our suggested bindings?
rem_action = memnew(Button);
- rem_action->set_tooltip(TTR("Remove action"));
+ rem_action->set_tooltip_text(TTR("Remove action"));
rem_action->connect("pressed", callable_mp(this, &OpenXRActionEditor::_on_remove_action));
rem_action->set_flat(true);
add_child(rem_action);
diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp
index 0a2d0a3110..fcbe4d57f6 100644
--- a/modules/openxr/editor/openxr_action_map_editor.cpp
+++ b/modules/openxr/editor/openxr_action_map_editor.cpp
@@ -316,13 +316,13 @@ OpenXRActionMapEditor::OpenXRActionMapEditor() {
add_action_set = memnew(Button);
add_action_set->set_text(TTR("Add Action Set"));
- add_action_set->set_tooltip(TTR("Add an action set."));
+ add_action_set->set_tooltip_text(TTR("Add an action set."));
add_action_set->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_add_action_set));
top_hb->add_child(add_action_set);
add_interaction_profile = memnew(Button);
add_interaction_profile->set_text(TTR("Add profile"));
- add_interaction_profile->set_tooltip(TTR("Add an interaction profile."));
+ add_interaction_profile->set_tooltip_text(TTR("Add an interaction profile."));
add_interaction_profile->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_add_interaction_profile));
top_hb->add_child(add_interaction_profile);
@@ -331,13 +331,13 @@ OpenXRActionMapEditor::OpenXRActionMapEditor() {
save_as = memnew(Button);
save_as->set_text(TTR("Save"));
- save_as->set_tooltip(TTR("Save this OpenXR action map."));
+ save_as->set_tooltip_text(TTR("Save this OpenXR action map."));
save_as->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_save_action_map));
top_hb->add_child(save_as);
_default = memnew(Button);
_default->set_text(TTR("Reset to Default"));
- _default->set_tooltip(TTR("Reset to default OpenXR action map."));
+ _default->set_tooltip_text(TTR("Reset to default OpenXR action map."));
_default->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_reset_to_default_layout));
top_hb->add_child(_default);
diff --git a/modules/openxr/editor/openxr_action_set_editor.cpp b/modules/openxr/editor/openxr_action_set_editor.cpp
index 7bf8557c5b..804808a6b9 100644
--- a/modules/openxr/editor/openxr_action_set_editor.cpp
+++ b/modules/openxr/editor/openxr_action_set_editor.cpp
@@ -199,13 +199,13 @@ OpenXRActionSetEditor::OpenXRActionSetEditor(Ref<OpenXRActionMap> p_action_map,
action_set_hb->add_child(action_set_priority);
add_action = memnew(Button);
- add_action->set_tooltip("Add Action.");
+ add_action->set_tooltip_text("Add Action.");
add_action->connect("pressed", callable_mp(this, &OpenXRActionSetEditor::_on_add_action));
add_action->set_flat(true);
action_set_hb->add_child(add_action);
rem_action_set = memnew(Button);
- rem_action_set->set_tooltip("Remove Action Set.");
+ rem_action_set->set_tooltip_text("Remove Action Set.");
rem_action_set->connect("pressed", callable_mp(this, &OpenXRActionSetEditor::_on_remove_action_set));
rem_action_set->set_flat(true);
action_set_hb->add_child(rem_action_set);
diff --git a/modules/raycast/SCsub b/modules/raycast/SCsub
index ef4c598194..074795759a 100644
--- a/modules/raycast/SCsub
+++ b/modules/raycast/SCsub
@@ -66,7 +66,7 @@ if env["builtin_embree"]:
env_raycast.Append(CPPDEFINES=["EMBREE_TARGET_SSE2", "EMBREE_LOWEST_ISA", "TASKING_INTERNAL", "NDEBUG"])
if not env.msvc:
- if env["arch"] in ["x86", "x86_64"]:
+ if env["arch"] == "x86_64":
env_raycast.Append(CPPFLAGS=["-msse2", "-mxsave"])
if env["platform"] == "windows":
@@ -83,7 +83,7 @@ if env["builtin_embree"]:
env_thirdparty.disable_warnings()
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
- if not env["arch"] in ["x86", "x86_64"] or env.msvc:
+ if env["arch"] == "arm64" or env.msvc:
# Embree needs those, it will automatically use SSE2NEON in ARM
env_thirdparty.Append(CPPDEFINES=["__SSE2__", "__SSE__"])
diff --git a/modules/raycast/config.py b/modules/raycast/config.py
index 7e8b3e9840..833ad50018 100644
--- a/modules/raycast/config.py
+++ b/modules/raycast/config.py
@@ -1,18 +1,9 @@
def can_build(env, platform):
- # Depends on Embree library, which only supports x86_64 and aarch64.
- if env["arch"].startswith("rv") or env["arch"].startswith("ppc"):
- return False
+ # Depends on Embree library, which only supports x86_64 and arm64.
+ if platform == "windows":
+ return env["arch"] == "x86_64" # TODO build for Windows on ARM
- if platform == "android":
- return env["android_arch"] in ["arm64v8", "x86_64"]
-
- if platform == "javascript":
- return False # No SIMD support yet
-
- if env["bits"] == "32":
- return False
-
- return True
+ return env["arch"] in ["x86_64", "arm64"]
def configure(env):
diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml
index deabc5ccd3..56404f796c 100644
--- a/modules/regex/doc_classes/RegEx.xml
+++ b/modules/regex/doc_classes/RegEx.xml
@@ -57,11 +57,18 @@
</method>
<method name="compile">
<return type="int" enum="Error" />
- <argument index="0" name="pattern" type="String" />
+ <param index="0" name="pattern" type="String" />
<description>
Compiles and assign the search pattern to use. Returns [constant OK] if the compilation is successful. If an error is encountered, details are printed to standard output and an error is returned.
</description>
</method>
+ <method name="create_from_string" qualifiers="static">
+ <return type="RegEx" />
+ <param index="0" name="pattern" type="String" />
+ <description>
+ Creates and compiles a new [RegEx] object.
+ </description>
+ </method>
<method name="get_group_count" qualifiers="const">
<return type="int" />
<description>
@@ -69,7 +76,7 @@
</description>
</method>
<method name="get_names" qualifiers="const">
- <return type="Array" />
+ <return type="PackedStringArray" />
<description>
Returns an array of names of named capturing groups in the compiled pattern. They are ordered by appearance.
</description>
@@ -88,29 +95,29 @@
</method>
<method name="search" qualifiers="const">
<return type="RegExMatch" />
- <argument index="0" name="subject" type="String" />
- <argument index="1" name="offset" type="int" default="0" />
- <argument index="2" name="end" type="int" default="-1" />
+ <param index="0" name="subject" type="String" />
+ <param index="1" name="offset" type="int" default="0" />
+ <param index="2" name="end" type="int" default="-1" />
<description>
Searches the text for the compiled pattern. Returns a [RegExMatch] container of the first matching result if found, otherwise [code]null[/code]. The region to search within can be specified without modifying where the start and end anchor would be.
</description>
</method>
<method name="search_all" qualifiers="const">
- <return type="Array" />
- <argument index="0" name="subject" type="String" />
- <argument index="1" name="offset" type="int" default="0" />
- <argument index="2" name="end" type="int" default="-1" />
+ <return type="RegExMatch[]" />
+ <param index="0" name="subject" type="String" />
+ <param index="1" name="offset" type="int" default="0" />
+ <param index="2" name="end" type="int" default="-1" />
<description>
Searches the text for the compiled pattern. Returns an array of [RegExMatch] containers for each non-overlapping result. If no results were found, an empty array is returned instead. The region to search within can be specified without modifying where the start and end anchor would be.
</description>
</method>
<method name="sub" qualifiers="const">
<return type="String" />
- <argument index="0" name="subject" type="String" />
- <argument index="1" name="replacement" type="String" />
- <argument index="2" name="all" type="bool" default="false" />
- <argument index="3" name="offset" type="int" default="0" />
- <argument index="4" name="end" type="int" default="-1" />
+ <param index="0" name="subject" type="String" />
+ <param index="1" name="replacement" type="String" />
+ <param index="2" name="all" type="bool" default="false" />
+ <param index="3" name="offset" type="int" default="0" />
+ <param index="4" name="end" type="int" default="-1" />
<description>
Searches the text for the compiled pattern and replaces it with the specified string. Escapes and backreferences such as [code]$1[/code] and [code]$name[/code] are expanded and resolved. By default, only the first instance is replaced, but it can be changed for all instances (global replacement). The region to search within can be specified without modifying where the start and end anchor would be.
</description>
diff --git a/modules/regex/doc_classes/RegExMatch.xml b/modules/regex/doc_classes/RegExMatch.xml
index 530a541ae8..5bcf070e82 100644
--- a/modules/regex/doc_classes/RegExMatch.xml
+++ b/modules/regex/doc_classes/RegExMatch.xml
@@ -11,7 +11,7 @@
<methods>
<method name="get_end" qualifiers="const">
<return type="int" />
- <argument index="0" name="name" type="Variant" default="0" />
+ <param index="0" name="name" type="Variant" default="0" />
<description>
Returns the end position of the match within the source string. The end position of capturing groups can be retrieved by providing its group number as an integer or its string name (if it's a named group). The default value of 0 refers to the whole pattern.
Returns -1 if the group did not match or doesn't exist.
@@ -25,7 +25,7 @@
</method>
<method name="get_start" qualifiers="const">
<return type="int" />
- <argument index="0" name="name" type="Variant" default="0" />
+ <param index="0" name="name" type="Variant" default="0" />
<description>
Returns the starting position of the match within the source string. The starting position of capturing groups can be retrieved by providing its group number as an integer or its string name (if it's a named group). The default value of 0 refers to the whole pattern.
Returns -1 if the group did not match or doesn't exist.
@@ -33,7 +33,7 @@
</method>
<method name="get_string" qualifiers="const">
<return type="String" />
- <argument index="0" name="name" type="Variant" default="0" />
+ <param index="0" name="name" type="Variant" default="0" />
<description>
Returns the substring of the match from the source string. Capturing groups can be retrieved by providing its group number as an integer or its string name (if it's a named group). The default value of 0 refers to the whole pattern.
Returns an empty string if the group did not match or doesn't exist.
diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp
index 67ce37219b..b2e6ea1004 100644
--- a/modules/regex/regex.cpp
+++ b/modules/regex/regex.cpp
@@ -159,6 +159,13 @@ void RegEx::_pattern_info(uint32_t what, void *where) const {
pcre2_pattern_info_32((pcre2_code_32 *)code, what, where);
}
+Ref<RegEx> RegEx::create_from_string(const String &p_pattern) {
+ Ref<RegEx> ret;
+ ret.instantiate();
+ ret->compile(p_pattern);
+ return ret;
+}
+
void RegEx::clear() {
if (code) {
pcre2_code_free_32((pcre2_code_32 *)code);
@@ -258,11 +265,11 @@ Ref<RegExMatch> RegEx::search(const String &p_subject, int p_offset, int p_end)
return result;
}
-Array RegEx::search_all(const String &p_subject, int p_offset, int p_end) const {
+TypedArray<RegExMatch> RegEx::search_all(const String &p_subject, int p_offset, int p_end) const {
ERR_FAIL_COND_V_MSG(p_offset < 0, Array(), "RegEx search offset must be >= 0");
int last_end = -1;
- Array result;
+ TypedArray<RegExMatch> result;
Ref<RegExMatch> match = search(p_subject, p_offset, p_end);
while (match.is_valid()) {
if (last_end == match->get_end(0)) {
@@ -344,8 +351,8 @@ int RegEx::get_group_count() const {
return count;
}
-Array RegEx::get_names() const {
- Array result;
+PackedStringArray RegEx::get_names() const {
+ PackedStringArray result;
ERR_FAIL_COND_V(!is_valid(), result);
@@ -384,6 +391,8 @@ RegEx::~RegEx() {
}
void RegEx::_bind_methods() {
+ ClassDB::bind_static_method("RegEx", D_METHOD("create_from_string", "pattern"), &RegEx::create_from_string);
+
ClassDB::bind_method(D_METHOD("clear"), &RegEx::clear);
ClassDB::bind_method(D_METHOD("compile", "pattern"), &RegEx::compile);
ClassDB::bind_method(D_METHOD("search", "subject", "offset", "end"), &RegEx::search, DEFVAL(0), DEFVAL(-1));
diff --git a/modules/regex/regex.h b/modules/regex/regex.h
index 1455188670..6920d2634d 100644
--- a/modules/regex/regex.h
+++ b/modules/regex/regex.h
@@ -37,6 +37,7 @@
#include "core/templates/vector.h"
#include "core/variant/array.h"
#include "core/variant/dictionary.h"
+#include "core/variant/typed_array.h"
class RegExMatch : public RefCounted {
GDCLASS(RegExMatch, RefCounted);
@@ -81,17 +82,19 @@ protected:
static void _bind_methods();
public:
+ static Ref<RegEx> create_from_string(const String &p_pattern);
+
void clear();
Error compile(const String &p_pattern);
Ref<RegExMatch> search(const String &p_subject, int p_offset = 0, int p_end = -1) const;
- Array search_all(const String &p_subject, int p_offset = 0, int p_end = -1) const;
+ TypedArray<RegExMatch> search_all(const String &p_subject, int p_offset = 0, int p_end = -1) const;
String sub(const String &p_subject, const String &p_replacement, bool p_all = false, int p_offset = 0, int p_end = -1) const;
bool is_valid() const;
String get_pattern() const;
int get_group_count() const;
- Array get_names() const;
+ PackedStringArray get_names() const;
RegEx();
RegEx(const String &p_pattern);
diff --git a/modules/regex/tests/test_regex.h b/modules/regex/tests/test_regex.h
index 91af393db1..c81094d3ae 100644
--- a/modules/regex/tests/test_regex.h
+++ b/modules/regex/tests/test_regex.h
@@ -46,7 +46,7 @@ TEST_CASE("[RegEx] Initialization") {
CHECK(re1.get_pattern() == pattern);
CHECK(re1.get_group_count() == 1);
- Array names = re1.get_names();
+ PackedStringArray names = re1.get_names();
CHECK(names.size() == 1);
CHECK(names[0] == "vowel");
diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp
index 87e2fae2d0..5f839bd979 100644
--- a/modules/svg/image_loader_svg.cpp
+++ b/modules/svg/image_loader_svg.cpp
@@ -35,13 +35,13 @@
#include <thorvg.h>
-void ImageLoaderSVG::_replace_color_property(const String &p_prefix, String &r_string) {
- // Replace colors in the SVG based on what is configured in `replace_colors`.
+void ImageLoaderSVG::_replace_color_property(const HashMap<Color, Color> &p_color_map, const String &p_prefix, String &r_string) {
+ // Replace colors in the SVG based on what is passed in `p_color_map`.
// Used to change the colors of editor icons based on the used theme.
// The strings being replaced are typically of the form:
// fill="#5abbef"
// But can also be 3-letter codes, include alpha, be "none" or a named color
- // string ("blue"). So we convert to Godot Color to compare with `replace_colors`.
+ // string ("blue"). So we convert to Godot Color to compare with `p_color_map`.
const int prefix_len = p_prefix.length();
int pos = r_string.find(p_prefix);
@@ -52,8 +52,8 @@ void ImageLoaderSVG::_replace_color_property(const String &p_prefix, String &r_s
const String color_code = r_string.substr(pos, end_pos - pos);
if (color_code != "none" && !color_code.begins_with("url(")) {
const Color color = Color(color_code); // Handles both HTML codes and named colors.
- if (replace_colors.has(color)) {
- r_string = r_string.left(pos) + "#" + replace_colors[color].operator Color().to_html(false) + r_string.substr(end_pos);
+ if (p_color_map.has(color)) {
+ r_string = r_string.left(pos) + "#" + p_color_map[color].to_html(false) + r_string.substr(end_pos);
}
}
// Search for other occurrences.
@@ -61,13 +61,13 @@ void ImageLoaderSVG::_replace_color_property(const String &p_prefix, String &r_s
}
}
-void ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, bool p_convert_color) {
+void ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map) {
ERR_FAIL_COND(Math::is_zero_approx(p_scale));
- if (p_convert_color) {
- _replace_color_property("stop-color=\"", p_string);
- _replace_color_property("fill=\"", p_string);
- _replace_color_property("stroke=\"", p_string);
+ if (p_color_map.size()) {
+ _replace_color_property(p_color_map, "stop-color=\"", p_string);
+ _replace_color_property(p_color_map, "fill=\"", p_string);
+ _replace_color_property(p_color_map, "stroke=\"", p_string);
}
std::unique_ptr<tvg::Picture> picture = tvg::Picture::gen();
@@ -136,11 +136,11 @@ void ImageLoaderSVG::get_recognized_extensions(List<String> *p_extensions) const
p_extensions->push_back("svg");
}
-Error ImageLoaderSVG::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, bool p_force_linear, float p_scale) {
+Error ImageLoaderSVG::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, uint32_t p_flags, float p_scale) {
String svg = p_fileaccess->get_as_utf8_string();
- create_image_from_string(p_image, svg, p_scale, false, false);
+ create_image_from_string(p_image, svg, p_scale, false, HashMap<Color, Color>());
ERR_FAIL_COND_V(p_image->is_empty(), FAILED);
- if (p_force_linear) {
+ if (p_flags & FLAG_FORCE_LINEAR) {
p_image->srgb_to_linear();
}
return OK;
diff --git a/modules/svg/image_loader_svg.h b/modules/svg/image_loader_svg.h
index 94c17fda43..fc89b63edb 100644
--- a/modules/svg/image_loader_svg.h
+++ b/modules/svg/image_loader_svg.h
@@ -34,15 +34,12 @@
#include "core/io/image_loader.h"
class ImageLoaderSVG : public ImageFormatLoader {
- Dictionary replace_colors;
- void _replace_color_property(const String &p_prefix, String &r_string);
+ void _replace_color_property(const HashMap<Color, Color> &p_color_map, const String &p_prefix, String &r_string);
public:
- // Called by the editor to handle theme icon colors.
- void set_replace_colors(Dictionary p_replace_colors) { replace_colors = p_replace_colors; }
- void create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, bool p_convert_color);
+ void create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, const HashMap<Color, Color> &p_color_map);
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, bool p_force_linear, float p_scale) override;
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, uint32_t p_flags, float p_scale) override;
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
};
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub
index d212fe62b4..7017a203f2 100644
--- a/modules/text_server_adv/SCsub
+++ b/modules/text_server_adv/SCsub
@@ -36,8 +36,8 @@ def make_icu_data(target, source, env):
# Thirdparty source files
thirdparty_obj = []
-freetype_enabled = env.module_check_dependencies("text_server_adv", ["freetype"], True)
-msdfgen_enabled = env.module_check_dependencies("text_server_adv", ["msdfgen"], True)
+freetype_enabled = "freetype" in env.module_list
+msdfgen_enabled = "msdfgen" in env.module_list
if env["builtin_harfbuzz"]:
env_harfbuzz = env_modules.Clone()
@@ -113,15 +113,18 @@ if env["builtin_harfbuzz"]:
if freetype_enabled:
thirdparty_sources += [
"src/hb-ft.cc",
- "src/hb-graphite2.cc",
]
+ if env["graphite"]:
+ thirdparty_sources += [
+ "src/hb-graphite2.cc",
+ ]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
env_harfbuzz.Prepend(CPPPATH=["#thirdparty/harfbuzz/src"])
env_harfbuzz.Append(CCFLAGS=["-DHAVE_ICU"])
if env["builtin_icu"]:
- env_harfbuzz.Prepend(CPPPATH=["#thirdparty/icu4c/common/"])
+ env_harfbuzz.Prepend(CPPPATH=["#thirdparty/icu4c/common/", "#thirdparty/icu4c/i18n/"])
env_harfbuzz.Append(CCFLAGS=["-DU_HAVE_LIB_SUFFIX=1", "-DU_LIB_SUFFIX_C_NAME=_godot", "-DHAVE_ICU_BUILTIN"])
if freetype_enabled:
@@ -133,14 +136,14 @@ if env["builtin_harfbuzz"]:
)
if env["builtin_freetype"]:
env_harfbuzz.Prepend(CPPPATH=["#thirdparty/freetype/include"])
- if env["builtin_graphite"]:
+ if env["builtin_graphite"] and env["graphite"]:
env_harfbuzz.Prepend(CPPPATH=["#thirdparty/graphite/include"])
env_harfbuzz.Append(CCFLAGS=["-DGRAPHITE2_STATIC"])
if env["platform"] == "android" or env["platform"] == "linuxbsd":
env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"])
- if env["platform"] == "javascript":
+ if env["platform"] == "web":
if env["threads_enabled"]:
env_harfbuzz.Append(CCFLAGS=["-DHAVE_PTHREAD"])
else:
@@ -165,7 +168,7 @@ if env["builtin_harfbuzz"]:
env.Append(LIBS=[lib])
-if env["builtin_graphite"] and freetype_enabled:
+if env["builtin_graphite"] and freetype_enabled and env["graphite"]:
env_graphite = env_modules.Clone()
env_graphite.disable_warnings()
@@ -439,6 +442,10 @@ if env["builtin_icu"]:
"common/uvectr32.cpp",
"common/uvectr64.cpp",
"common/wintz.cpp",
+ "i18n/scriptset.cpp",
+ "i18n/ucln_in.cpp",
+ "i18n/uspoof.cpp",
+ "i18n/uspoof_impl.cpp",
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
@@ -451,7 +458,7 @@ if env["builtin_icu"]:
else:
thirdparty_sources += ["icu_data/icudata_stub.cpp"]
- env_icu.Prepend(CPPPATH=["#thirdparty/icu4c/common/"])
+ env_icu.Prepend(CPPPATH=["#thirdparty/icu4c/common/", "#thirdparty/icu4c/i18n/"])
env_icu.Append(
CXXFLAGS=[
"-DU_STATIC_IMPLEMENTATION",
@@ -463,6 +470,7 @@ if env["builtin_icu"]:
"-DUCONFIG_NO_IDNA",
"-DUCONFIG_NO_FILE_IO",
"-DUCONFIG_NO_TRANSLITERATION",
+ "-DUCONFIG_NO_REGULAR_EXPRESSIONS",
"-DPKGDATA_MODE=static",
"-DU_ENABLE_DYLOAD=0",
"-DU_HAVE_LIB_SUFFIX=1",
@@ -480,7 +488,7 @@ if env["builtin_icu"]:
if env_text_server_adv["tools"]:
env_text_server_adv.Append(CXXFLAGS=["-DICU_STATIC_DATA"])
- env_text_server_adv.Prepend(CPPPATH=["#thirdparty/icu4c/common/"])
+ env_text_server_adv.Prepend(CPPPATH=["#thirdparty/icu4c/common/", "#thirdparty/icu4c/i18n/"])
lib = env_icu.add_library("icu_builtin", thirdparty_sources)
thirdparty_obj += lib
@@ -507,9 +515,10 @@ if env["builtin_msdfgen"] and msdfgen_enabled:
env_text_server_adv.Prepend(CPPPATH=["#thirdparty/msdfgen"])
if env["builtin_freetype"] and freetype_enabled:
+ env_text_server_adv.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"])
env_text_server_adv.Prepend(CPPPATH=["#thirdparty/freetype/include"])
-if env["builtin_graphite"] and freetype_enabled:
+if env["builtin_graphite"] and freetype_enabled and env["graphite"]:
env_text_server_adv.Prepend(CPPPATH=["#thirdparty/graphite/include"])
env_text_server_adv.add_source_files(module_obj, "*.cpp")
diff --git a/modules/text_server_adv/config.py b/modules/text_server_adv/config.py
index 8c8df9b05e..179a2ff378 100644
--- a/modules/text_server_adv/config.py
+++ b/modules/text_server_adv/config.py
@@ -2,6 +2,14 @@ def can_build(env, platform):
return True
+def get_opts(platform):
+ from SCons.Variables import BoolVariable
+
+ return [
+ BoolVariable("graphite", "Enable SIL Graphite smart fonts support", True),
+ ]
+
+
def configure(env):
pass
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 64788bfeff..366e1ba604 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -29,12 +29,12 @@
/*************************************************************************/
#include "text_server_adv.h"
-#include "core/object/worker_thread_pool.h"
#ifdef GDEXTENSION
// Headers for building as GDExtension plug-in.
#include <godot_cpp/classes/file.hpp>
+#include <godot_cpp/classes/project_settings.hpp>
#include <godot_cpp/classes/rendering_server.hpp>
#include <godot_cpp/classes/translation_server.hpp>
#include <godot_cpp/core/error_macros.hpp>
@@ -44,8 +44,10 @@ using namespace godot;
#else
// Headers for building as built-in module.
+#include "core/config/project_settings.h"
#include "core/core_bind.h"
#include "core/error/error_macros.h"
+#include "core/object/worker_thread_pool.h"
#include "core/string/print_string.h"
#include "core/string/translation.h"
@@ -346,6 +348,8 @@ bool TextServerAdvanced::has_feature(Feature p_feature) const {
case FEATURE_FONT_VARIABLE:
case FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION:
case FEATURE_USE_SUPPORT_DATA:
+ case FEATURE_UNICODE_IDENTIFIERS:
+ case FEATURE_UNICODE_SECURITY:
return true;
default: {
}
@@ -789,6 +793,10 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
for (int i = 0; i < p_data->textures.size(); i++) {
const FontTexture &ct = p_data->textures[i];
+ if (p_image_format != ct.format) {
+ continue;
+ }
+
if (mw > ct.texture_w || mh > ct.texture_h) { // Too big for this texture.
continue;
}
@@ -1080,9 +1088,28 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
#endif
#ifdef MODULE_FREETYPE_ENABLED
-_FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitmap(FontForSizeAdvanced *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance) const {
+_FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitmap(FontForSizeAdvanced *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance, bool p_bgra) const {
int w = bitmap.width;
int h = bitmap.rows;
+ int color_size = 2;
+
+ switch (bitmap.pixel_mode) {
+ case FT_PIXEL_MODE_MONO:
+ case FT_PIXEL_MODE_GRAY: {
+ color_size = 2;
+ } break;
+ case FT_PIXEL_MODE_BGRA: {
+ color_size = 4;
+ } break;
+ case FT_PIXEL_MODE_LCD: {
+ color_size = 4;
+ w /= 3;
+ } break;
+ case FT_PIXEL_MODE_LCD_V: {
+ color_size = 4;
+ h /= 3;
+ } break;
+ }
int mw = w + p_rect_margin * 4;
int mh = h + p_rect_margin * 4;
@@ -1090,7 +1117,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
ERR_FAIL_COND_V(mw > 4096, FontGlyph());
ERR_FAIL_COND_V(mh > 4096, FontGlyph());
- int color_size = bitmap.pixel_mode == FT_PIXEL_MODE_BGRA ? 4 : 2;
Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8;
FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, color_size, require_format, mw, mh, false);
@@ -1125,6 +1151,34 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
wr[ofs + 3] = bitmap.buffer[ofs_color + 3];
} break;
+ case FT_PIXEL_MODE_LCD: {
+ int ofs_color = i * bitmap.pitch + (j * 3);
+ if (p_bgra) {
+ wr[ofs + 0] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
+ wr[ofs + 2] = bitmap.buffer[ofs_color + 2];
+ wr[ofs + 3] = 255;
+ } else {
+ wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
+ wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
+ wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 3] = 255;
+ }
+ } break;
+ case FT_PIXEL_MODE_LCD_V: {
+ int ofs_color = i * bitmap.pitch * 3 + j;
+ if (p_bgra) {
+ wr[ofs + 0] = bitmap.buffer[ofs_color + bitmap.pitch * 2];
+ wr[ofs + 1] = bitmap.buffer[ofs_color + bitmap.pitch];
+ wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 3] = 255;
+ } else {
+ wr[ofs + 0] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 1] = bitmap.buffer[ofs_color + bitmap.pitch];
+ wr[ofs + 2] = bitmap.buffer[ofs_color + bitmap.pitch * 2];
+ wr[ofs + 3] = 255;
+ }
+ } break;
default:
ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + String::num_int64(bitmap.pixel_mode) + ".");
break;
@@ -1228,9 +1282,44 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontAdvanced *p_font_data,
FT_Outline_Transform(&fd->face->glyph->outline, &mat);
}
+ FT_Render_Mode aa_mode = FT_RENDER_MODE_NORMAL;
+ bool bgra = false;
+ switch (p_font_data->antialiasing) {
+ case FONT_ANTIALIASING_NONE: {
+ aa_mode = FT_RENDER_MODE_MONO;
+ } break;
+ case FONT_ANTIALIASING_GRAY: {
+ aa_mode = FT_RENDER_MODE_NORMAL;
+ } break;
+ case FONT_ANTIALIASING_LCD: {
+ int aa_layout = (int)((p_glyph >> 24) & 7);
+ switch (aa_layout) {
+ case FONT_LCD_SUBPIXEL_LAYOUT_HRGB: {
+ aa_mode = FT_RENDER_MODE_LCD;
+ bgra = false;
+ } break;
+ case FONT_LCD_SUBPIXEL_LAYOUT_HBGR: {
+ aa_mode = FT_RENDER_MODE_LCD;
+ bgra = true;
+ } break;
+ case FONT_LCD_SUBPIXEL_LAYOUT_VRGB: {
+ aa_mode = FT_RENDER_MODE_LCD_V;
+ bgra = false;
+ } break;
+ case FONT_LCD_SUBPIXEL_LAYOUT_VBGR: {
+ aa_mode = FT_RENDER_MODE_LCD_V;
+ bgra = true;
+ } break;
+ default: {
+ aa_mode = FT_RENDER_MODE_NORMAL;
+ } break;
+ }
+ } break;
+ }
+
if (!outline) {
if (!p_font_data->msdf) {
- error = FT_Render_Glyph(fd->face->glyph, p_font_data->antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
+ error = FT_Render_Glyph(fd->face->glyph, aa_mode);
}
FT_GlyphSlot slot = fd->face->glyph;
if (!error) {
@@ -1242,7 +1331,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontAdvanced *p_font_data,
ERR_FAIL_V_MSG(false, "Compiled without MSDFGEN support!");
#endif
} else {
- gl = rasterize_bitmap(fd, rect_range, slot->bitmap, slot->bitmap_top, slot->bitmap_left, Vector2((h + (1 << 9)) >> 10, (v + (1 << 9)) >> 10) / 64.0);
+ gl = rasterize_bitmap(fd, rect_range, slot->bitmap, slot->bitmap_top, slot->bitmap_left, Vector2((h + (1 << 9)) >> 10, (v + (1 << 9)) >> 10) / 64.0, bgra);
}
}
} else {
@@ -1262,11 +1351,11 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontAdvanced *p_font_data,
if (FT_Glyph_Stroke(&glyph, stroker, 1) != 0) {
goto cleanup_glyph;
}
- if (FT_Glyph_To_Bitmap(&glyph, p_font_data->antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, nullptr, 1) != 0) {
+ if (FT_Glyph_To_Bitmap(&glyph, aa_mode, nullptr, 1) != 0) {
goto cleanup_glyph;
}
glyph_bitmap = (FT_BitmapGlyph)glyph;
- gl = rasterize_bitmap(fd, rect_range, glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, Vector2());
+ gl = rasterize_bitmap(fd, rect_range, glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, Vector2(), bgra);
cleanup_glyph:
FT_Done_Glyph(glyph);
@@ -1311,12 +1400,14 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontAdvanced *p_f
fargs.stream = &fd->stream;
int max_index = 0;
- FT_Face tmp_face;
+ FT_Face tmp_face = nullptr;
error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
- if (error == 0) {
+ if (tmp_face && error == 0) {
max_index = tmp_face->num_faces - 1;
}
- FT_Done_Face(tmp_face);
+ if (tmp_face) {
+ FT_Done_Face(tmp_face);
+ }
error = FT_Open_Face(ft_library, &fargs, CLAMP(p_font_data->face_index, 0, max_index), &fd->face);
if (error) {
@@ -1921,23 +2012,23 @@ String TextServerAdvanced::font_get_name(const RID &p_font_rid) const {
return fd->font_name;
}
-void TextServerAdvanced::font_set_antialiased(const RID &p_font_rid, bool p_antialiased) {
+void TextServerAdvanced::font_set_antialiasing(RID p_font_rid, TextServer::FontAntialiasing p_antialiasing) {
FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
- if (fd->antialiased != p_antialiased) {
+ if (fd->antialiasing != p_antialiasing) {
_font_clear_cache(fd);
- fd->antialiased = p_antialiased;
+ fd->antialiasing = p_antialiasing;
}
}
-bool TextServerAdvanced::font_is_antialiased(const RID &p_font_rid) const {
+TextServer::FontAntialiasing TextServerAdvanced::font_get_antialiasing(RID p_font_rid) const {
FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, false);
+ ERR_FAIL_COND_V(!fd, TextServer::FONT_ANTIALIASING_NONE);
MutexLock lock(fd->mutex);
- return fd->antialiased;
+ return fd->antialiasing;
}
void TextServerAdvanced::font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) {
@@ -2166,12 +2257,12 @@ double TextServerAdvanced::font_get_oversampling(const RID &p_font_rid) const {
return fd->oversampling;
}
-Array TextServerAdvanced::font_get_size_cache_list(const RID &p_font_rid) const {
+TypedArray<Vector2i> TextServerAdvanced::font_get_size_cache_list(const RID &p_font_rid) const {
FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, Array());
+ ERR_FAIL_COND_V(!fd, TypedArray<Vector2i>());
MutexLock lock(fd->mutex);
- Array ret;
+ TypedArray<Vector2i> ret;
for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) {
ret.push_back(E.key);
}
@@ -2450,15 +2541,15 @@ PackedInt32Array TextServerAdvanced::font_get_texture_offsets(const RID &p_font_
return tex.offsets;
}
-Array TextServerAdvanced::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {
+PackedInt32Array TextServerAdvanced::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {
FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, Array());
+ ERR_FAIL_COND_V(!fd, PackedInt32Array());
MutexLock lock(fd->mutex);
Vector2i size = _get_size_outline(fd, p_size);
- ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Array());
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array());
- Array ret;
+ PackedInt32Array ret;
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
for (const KeyValue<int32_t, FontGlyph> &E : gl) {
ret.push_back(E.key);
@@ -2510,7 +2601,16 @@ Vector2 TextServerAdvanced::font_get_glyph_advance(const RID &p_font_rid, int64_
Vector2i size = _get_size(fd, p_size);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
- if (!_ensure_glyph(fd, size, p_glyph)) {
+
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
+ if (!_ensure_glyph(fd, size, p_glyph | mod)) {
return Vector2(); // Invalid or non graphicl glyph, do not display errors.
}
@@ -2553,7 +2653,16 @@ Vector2 TextServerAdvanced::font_get_glyph_offset(const RID &p_font_rid, const V
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
- if (!_ensure_glyph(fd, size, p_glyph)) {
+
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
+ if (!_ensure_glyph(fd, size, p_glyph | mod)) {
return Vector2(); // Invalid or non graphicl glyph, do not display errors.
}
@@ -2589,7 +2698,16 @@ Vector2 TextServerAdvanced::font_get_glyph_size(const RID &p_font_rid, const Vec
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
- if (!_ensure_glyph(fd, size, p_glyph)) {
+
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
+ if (!_ensure_glyph(fd, size, p_glyph | mod)) {
return Vector2(); // Invalid or non graphicl glyph, do not display errors.
}
@@ -2625,7 +2743,16 @@ Rect2 TextServerAdvanced::font_get_glyph_uv_rect(const RID &p_font_rid, const Ve
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Rect2());
- if (!_ensure_glyph(fd, size, p_glyph)) {
+
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
+ if (!_ensure_glyph(fd, size, p_glyph | mod)) {
return Rect2(); // Invalid or non graphicl glyph, do not display errors.
}
@@ -2656,7 +2783,16 @@ int64_t TextServerAdvanced::font_get_glyph_texture_idx(const RID &p_font_rid, co
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), -1);
- if (!_ensure_glyph(fd, size, p_glyph)) {
+
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
+ if (!_ensure_glyph(fd, size, p_glyph | mod)) {
return -1; // Invalid or non graphicl glyph, do not display errors.
}
@@ -2687,7 +2823,16 @@ RID TextServerAdvanced::font_get_glyph_texture_rid(const RID &p_font_rid, const
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), RID());
- if (!_ensure_glyph(fd, size, p_glyph)) {
+
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
+ if (!_ensure_glyph(fd, size, p_glyph | mod)) {
return RID(); // Invalid or non graphicl glyph, do not display errors.
}
@@ -2726,7 +2871,16 @@ Size2 TextServerAdvanced::font_get_glyph_texture_size(const RID &p_font_rid, con
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Size2());
- if (!_ensure_glyph(fd, size, p_glyph)) {
+
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
+ if (!_ensure_glyph(fd, size, p_glyph | mod)) {
return Size2(); // Invalid or non graphicl glyph, do not display errors.
}
@@ -2807,16 +2961,16 @@ Dictionary TextServerAdvanced::font_get_glyph_contours(const RID &p_font_rid, in
#endif
}
-Array TextServerAdvanced::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const {
+TypedArray<Vector2i> TextServerAdvanced::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const {
FontAdvanced *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, Array());
+ ERR_FAIL_COND_V(!fd, TypedArray<Vector2i>());
MutexLock lock(fd->mutex);
Vector2i size = _get_size(fd, p_size);
- ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Array());
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), TypedArray<Vector2i>());
- Array ret;
+ TypedArray<Vector2i> ret;
for (const KeyValue<Vector2i, FontForSizeAdvanced *> &E : fd->cache) {
ret.push_back(E.key);
}
@@ -2982,16 +3136,18 @@ void TextServerAdvanced::font_render_range(const RID &p_font_rid, const Vector2i
if (fd->msdf) {
_ensure_glyph(fd, size, (int32_t)idx);
} else {
- if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
- _ensure_glyph(fd, size, (int32_t)idx | (0 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (1 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (2 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (3 << 27));
- } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
- _ensure_glyph(fd, size, (int32_t)idx | (1 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (0 << 27));
- } else {
- _ensure_glyph(fd, size, (int32_t)idx);
+ for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) {
+ if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
+ _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24));
+ } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
+ _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24));
+ } else {
+ _ensure_glyph(fd, size, (int32_t)idx | (aa << 24));
+ }
}
}
}
@@ -3012,16 +3168,18 @@ void TextServerAdvanced::font_render_glyph(const RID &p_font_rid, const Vector2i
if (fd->msdf) {
_ensure_glyph(fd, size, (int32_t)idx);
} else {
- if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
- _ensure_glyph(fd, size, (int32_t)idx | (0 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (1 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (2 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (3 << 27));
- } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
- _ensure_glyph(fd, size, (int32_t)idx | (1 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (0 << 27));
- } else {
- _ensure_glyph(fd, size, (int32_t)idx);
+ for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) {
+ if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
+ _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24));
+ } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
+ _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24));
+ } else {
+ _ensure_glyph(fd, size, (int32_t)idx | (aa << 24));
+ }
}
}
}
@@ -3037,9 +3195,19 @@ void TextServerAdvanced::font_draw_glyph(const RID &p_font_rid, const RID &p_can
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
int32_t index = p_index & 0xffffff; // Remove subpixel shifts.
+ bool lcd_aa = false;
#ifdef MODULE_FREETYPE_ENABLED
if (!fd->msdf && fd->cache[size]->face) {
+ // LCD layout, bits 24, 25, 26
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ lcd_aa = true;
+ index = index | (layout << 24);
+ }
+ }
+ // Subpixel X-shift, bits 27, 28
if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125));
index = index | (xshift << 27);
@@ -3061,7 +3229,7 @@ void TextServerAdvanced::font_draw_glyph(const RID &p_font_rid, const RID &p_can
if (gl.texture_idx != -1) {
Color modulate = p_color;
#ifdef MODULE_FREETYPE_ENABLED
- if (fd->cache[size]->face && FT_HAS_COLOR(fd->cache[size]->face)) {
+ if (fd->cache[size]->face && (fd->cache[size]->textures[gl.texture_idx].format == Image::FORMAT_RGBA8) && !lcd_aa) {
modulate.r = modulate.g = modulate.b = 1.0;
}
#endif
@@ -3099,7 +3267,11 @@ void TextServerAdvanced::font_draw_glyph(const RID &p_font_rid, const RID &p_can
}
cpos += gl.rect.position;
Size2 csize = gl.rect.size;
- RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false);
+ if (lcd_aa) {
+ RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate);
+ } else {
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false);
+ }
}
}
}
@@ -3115,9 +3287,19 @@ void TextServerAdvanced::font_draw_glyph_outline(const RID &p_font_rid, const RI
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
int32_t index = p_index & 0xffffff; // Remove subpixel shifts.
+ bool lcd_aa = false;
#ifdef MODULE_FREETYPE_ENABLED
if (!fd->msdf && fd->cache[size]->face) {
+ // LCD layout, bits 24, 25, 26
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ lcd_aa = true;
+ index = index | (layout << 24);
+ }
+ }
+ // Subpixel X-shift, bits 27, 28
if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125));
index = index | (xshift << 27);
@@ -3177,7 +3359,11 @@ void TextServerAdvanced::font_draw_glyph_outline(const RID &p_font_rid, const RI
}
cpos += gl.rect.position;
Size2 csize = gl.rect.size;
- RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false);
+ if (lcd_aa) {
+ RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate);
+ } else {
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false);
+ }
}
}
}
@@ -4243,7 +4429,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(const RID &p_shaped_l
Glyph *sd_glyphs = sd->glyphs.ptrw();
- if (p_trim_flags.has_flag(OVERRUN_TRIM) || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) {
+ if ((p_trim_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIM || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) {
sd->overrun_trim_data.trim_pos = -1;
sd->overrun_trim_data.ellipsis_pos = -1;
return;
@@ -4704,7 +4890,7 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(const RID &p_shape
for (int i = 0; i < sd_size; i++) {
if (sd_glyphs[i].count > 0) {
char32_t c = sd->text[sd_glyphs[i].start - sd->start];
- if (c == 0x0640) {
+ if (c == 0x0640 && sd_glyphs[i].start == sd_glyphs[i].end - 1) {
sd_glyphs[i].flags |= GRAPHEME_IS_ELONGATION;
}
if (sd->jstops.has(sd_glyphs[i].start)) {
@@ -4716,6 +4902,11 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(const RID &p_shape
if (sd_glyphs[i].font_rid != RID()) {
Glyph gl = _shape_single_glyph(sd, 0x0640, HB_SCRIPT_ARABIC, HB_DIRECTION_RTL, sd->glyphs[i].font_rid, sd->glyphs[i].font_size);
if ((sd_glyphs[i].flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) {
+#if HB_VERSION_ATLEAST(5, 1, 0)
+ if ((i > 0) && ((sd_glyphs[i - 1].flags & GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL) != GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL)) {
+ continue;
+ }
+#endif
gl.start = sd_glyphs[i].start;
gl.end = sd_glyphs[i].end;
gl.repeat = 0;
@@ -4906,11 +5097,16 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
hb_buffer_clear_contents(p_sd->hb_buffer);
hb_buffer_set_direction(p_sd->hb_buffer, p_direction);
+ int flags = (p_start == 0 ? HB_BUFFER_FLAG_BOT : 0) | (p_end == p_sd->text.length() ? HB_BUFFER_FLAG_EOT : 0);
if (p_sd->preserve_control) {
- hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)(HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES | (p_start == 0 ? HB_BUFFER_FLAG_BOT : 0) | (p_end == p_sd->text.length() ? HB_BUFFER_FLAG_EOT : 0)));
+ flags |= HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES;
} else {
- hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)(HB_BUFFER_FLAG_DEFAULT | (p_start == 0 ? HB_BUFFER_FLAG_BOT : 0) | (p_end == p_sd->text.length() ? HB_BUFFER_FLAG_EOT : 0)));
+ flags |= HB_BUFFER_FLAG_DEFAULT;
}
+#if HB_VERSION_ATLEAST(5, 1, 0)
+ flags |= HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL;
+#endif
+ hb_buffer_set_flags(p_sd->hb_buffer, (hb_buffer_flags_t)flags);
hb_buffer_set_script(p_sd->hb_buffer, p_script);
if (p_sd->spans[p_span].language.is_empty()) {
@@ -4933,6 +5129,14 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(p_sd->hb_buffer, &glyph_count);
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(p_sd->hb_buffer, &glyph_count);
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
// Process glyphs.
if (glyph_count > 0) {
Glyph *w = (Glyph *)memalloc(glyph_count * sizeof(Glyph));
@@ -4974,13 +5178,19 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
gl.font_rid = p_fonts[p_fb_index];
gl.font_size = fs;
- if (glyph_info[i].mask & HB_GLYPH_FLAG_DEFINED) {
+ if (glyph_info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK) {
gl.flags |= GRAPHEME_IS_CONNECTED;
}
+#if HB_VERSION_ATLEAST(5, 1, 0)
+ if (glyph_info[i].mask & HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL) {
+ gl.flags |= GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL;
+ }
+#endif
+
gl.index = glyph_info[i].codepoint;
if (gl.index != 0) {
- _ensure_glyph(fd, fss, gl.index);
+ _ensure_glyph(fd, fss, gl.index | mod);
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
if (subpos) {
gl.advance = glyph_pos[i].x_advance / (64.0 / scale) + ea;
@@ -5639,6 +5849,68 @@ String TextServerAdvanced::percent_sign(const String &p_language) const {
return "%";
}
+int TextServerAdvanced::is_confusable(const String &p_string, const PackedStringArray &p_dict) const {
+ UErrorCode status = U_ZERO_ERROR;
+ int match_index = -1;
+
+ Char16String utf16 = p_string.utf16();
+ Vector<UChar *> skeletons;
+ skeletons.resize(p_dict.size());
+
+ USpoofChecker *sc = uspoof_open(&status);
+ uspoof_setChecks(sc, USPOOF_CONFUSABLE, &status);
+ for (int i = 0; i < p_dict.size(); i++) {
+ Char16String word = p_dict[i].utf16();
+ int32_t len = uspoof_getSkeleton(sc, 0, word.get_data(), -1, NULL, 0, &status);
+ skeletons.write[i] = (UChar *)memalloc(++len * sizeof(UChar));
+ status = U_ZERO_ERROR;
+ uspoof_getSkeleton(sc, 0, word.get_data(), -1, skeletons.write[i], len, &status);
+ }
+
+ int32_t len = uspoof_getSkeleton(sc, 0, utf16.get_data(), -1, NULL, 0, &status);
+ UChar *skel = (UChar *)memalloc(++len * sizeof(UChar));
+ status = U_ZERO_ERROR;
+ uspoof_getSkeleton(sc, 0, utf16.get_data(), -1, skel, len, &status);
+ for (int i = 0; i < skeletons.size(); i++) {
+ if (u_strcmp(skel, skeletons[i]) == 0) {
+ match_index = i;
+ break;
+ }
+ }
+ memfree(skel);
+
+ for (int i = 0; i < skeletons.size(); i++) {
+ memfree(skeletons.write[i]);
+ }
+ uspoof_close(sc);
+
+ ERR_FAIL_COND_V_MSG(U_FAILURE(status), -1, u_errorName(status));
+
+ return match_index;
+}
+
+bool TextServerAdvanced::spoof_check(const String &p_string) const {
+ UErrorCode status = U_ZERO_ERROR;
+ Char16String utf16 = p_string.utf16();
+
+ USet *allowed = uset_openEmpty();
+ uset_addAll(allowed, uspoof_getRecommendedSet(&status));
+ uset_addAll(allowed, uspoof_getInclusionSet(&status));
+
+ USpoofChecker *sc = uspoof_open(&status);
+ uspoof_setAllowedChars(sc, allowed, &status);
+ uspoof_setRestrictionLevel(sc, USPOOF_MODERATELY_RESTRICTIVE);
+
+ int32_t bitmask = uspoof_check(sc, utf16.get_data(), -1, NULL, &status);
+
+ uspoof_close(sc);
+ uset_close(allowed);
+
+ ERR_FAIL_COND_V_MSG(U_FAILURE(status), false, u_errorName(status));
+
+ return (bitmask != 0);
+}
+
String TextServerAdvanced::strip_diacritics(const String &p_string) const {
UErrorCode err = U_ZERO_ERROR;
@@ -5757,6 +6029,191 @@ PackedInt32Array TextServerAdvanced::string_get_word_breaks(const String &p_stri
return ret;
}
+bool TextServerAdvanced::is_valid_identifier(const String &p_string) const {
+ enum UAX31SequenceStatus {
+ SEQ_NOT_STARTED,
+ SEQ_STARTED,
+ SEQ_STARTED_VIR,
+ SEQ_NEAR_END,
+ };
+
+ const char32_t *str = p_string.ptr();
+ int len = p_string.length();
+
+ if (len == 0) {
+ return false; // Empty string.
+ }
+
+ UErrorCode err = U_ZERO_ERROR;
+ Char16String utf16 = p_string.utf16();
+ const UNormalizer2 *norm_c = unorm2_getNFCInstance(&err);
+ if (U_FAILURE(err)) {
+ return false; // Failed to load normalizer.
+ }
+ bool isnurom = unorm2_isNormalized(norm_c, utf16.ptr(), utf16.length(), &err);
+ if (U_FAILURE(err) || !isnurom) {
+ return false; // Do not conform to Normalization Form C.
+ }
+
+ UAX31SequenceStatus A1_sequence_status = SEQ_NOT_STARTED;
+ UScriptCode A1_scr = USCRIPT_INHERITED;
+ UAX31SequenceStatus A2_sequence_status = SEQ_NOT_STARTED;
+ UScriptCode A2_scr = USCRIPT_INHERITED;
+ UAX31SequenceStatus B_sequence_status = SEQ_NOT_STARTED;
+ UScriptCode B_scr = USCRIPT_INHERITED;
+
+ for (int i = 0; i < len; i++) {
+ err = U_ZERO_ERROR;
+ UScriptCode scr = uscript_getScript(str[i], &err);
+ if (U_FAILURE(err)) {
+ return false; // Invalid script.
+ }
+ if (uscript_getUsage(scr) != USCRIPT_USAGE_RECOMMENDED) {
+ return false; // Not a recommended script.
+ }
+ uint8_t cat = u_charType(str[i]);
+ int32_t jt = u_getIntPropertyValue(str[i], UCHAR_JOINING_TYPE);
+
+ // UAX #31 section 2.3 subsections A1, A2 and B, check ZWNJ and ZWJ usage.
+ switch (A1_sequence_status) {
+ case SEQ_NEAR_END: {
+ if ((A1_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A1_scr)) {
+ return false; // Mixed script.
+ }
+ if (jt == U_JT_RIGHT_JOINING || jt == U_JT_DUAL_JOINING) {
+ A1_sequence_status = SEQ_NOT_STARTED; // Valid end of sequence, reset.
+ } else if (jt != U_JT_TRANSPARENT) {
+ return false; // Invalid end of sequence.
+ }
+ } break;
+ case SEQ_STARTED: {
+ if ((A1_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A1_scr)) {
+ A1_sequence_status = SEQ_NOT_STARTED; // Reset.
+ } else {
+ if (jt != U_JT_TRANSPARENT) {
+ if (str[i] == 0x200C /*ZWNJ*/) {
+ A1_sequence_status = SEQ_NEAR_END;
+ continue;
+ } else {
+ A1_sequence_status = SEQ_NOT_STARTED; // Reset.
+ }
+ }
+ }
+ } break;
+ default:
+ break;
+ }
+ if (A1_sequence_status == SEQ_NOT_STARTED) {
+ if (jt == U_JT_LEFT_JOINING || jt == U_JT_DUAL_JOINING) {
+ A1_sequence_status = SEQ_STARTED;
+ A1_scr = scr;
+ }
+ };
+
+ switch (A2_sequence_status) {
+ case SEQ_NEAR_END: {
+ if ((A2_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A2_scr)) {
+ return false; // Mixed script.
+ }
+ if (cat == U_UPPERCASE_LETTER || cat == U_LOWERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_MODIFIER_LETTER || cat == U_OTHER_LETTER) {
+ A2_sequence_status = SEQ_NOT_STARTED; // Valid end of sequence, reset.
+ } else if (cat != U_MODIFIER_LETTER || u_getCombiningClass(str[i]) == 0) {
+ return false; // Invalid end of sequence.
+ }
+ } break;
+ case SEQ_STARTED_VIR: {
+ if ((A2_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A2_scr)) {
+ A2_sequence_status = SEQ_NOT_STARTED; // Reset.
+ } else {
+ if (str[i] == 0x200C /*ZWNJ*/) {
+ A2_sequence_status = SEQ_NEAR_END;
+ continue;
+ } else if (cat != U_MODIFIER_LETTER || u_getCombiningClass(str[i]) == 0) {
+ A2_sequence_status = SEQ_NOT_STARTED; // Reset.
+ }
+ }
+ } break;
+ case SEQ_STARTED: {
+ if ((A2_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != A2_scr)) {
+ A2_sequence_status = SEQ_NOT_STARTED; // Reset.
+ } else {
+ if (u_getCombiningClass(str[i]) == 9 /*Virama Combining Class*/) {
+ A2_sequence_status = SEQ_STARTED_VIR;
+ } else if (cat != U_MODIFIER_LETTER) {
+ A2_sequence_status = SEQ_NOT_STARTED; // Reset.
+ }
+ }
+ } break;
+ default:
+ break;
+ }
+ if (A2_sequence_status == SEQ_NOT_STARTED) {
+ if (cat == U_UPPERCASE_LETTER || cat == U_LOWERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_MODIFIER_LETTER || cat == U_OTHER_LETTER) {
+ A2_sequence_status = SEQ_STARTED;
+ A2_scr = scr;
+ }
+ }
+
+ switch (B_sequence_status) {
+ case SEQ_NEAR_END: {
+ if ((B_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != B_scr)) {
+ return false; // Mixed script.
+ }
+ if (u_getIntPropertyValue(str[i], UCHAR_INDIC_SYLLABIC_CATEGORY) != U_INSC_VOWEL_DEPENDENT) {
+ B_sequence_status = SEQ_NOT_STARTED; // Valid end of sequence, reset.
+ } else {
+ return false; // Invalid end of sequence.
+ }
+ } break;
+ case SEQ_STARTED_VIR: {
+ if ((B_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != B_scr)) {
+ B_sequence_status = SEQ_NOT_STARTED; // Reset.
+ } else {
+ if (str[i] == 0x200D /*ZWJ*/) {
+ B_sequence_status = SEQ_NEAR_END;
+ continue;
+ } else if (cat != U_MODIFIER_LETTER || u_getCombiningClass(str[i]) == 0) {
+ B_sequence_status = SEQ_NOT_STARTED; // Reset.
+ }
+ }
+ } break;
+ case SEQ_STARTED: {
+ if ((B_scr > USCRIPT_INHERITED) && (scr > USCRIPT_INHERITED) && (scr != B_scr)) {
+ B_sequence_status = SEQ_NOT_STARTED; // Reset.
+ } else {
+ if (u_getCombiningClass(str[i]) == 9 /*Virama Combining Class*/) {
+ B_sequence_status = SEQ_STARTED_VIR;
+ } else if (cat != U_MODIFIER_LETTER) {
+ B_sequence_status = SEQ_NOT_STARTED; // Reset.
+ }
+ }
+ } break;
+ default:
+ break;
+ }
+ if (B_sequence_status == SEQ_NOT_STARTED) {
+ if (cat == U_UPPERCASE_LETTER || cat == U_LOWERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_MODIFIER_LETTER || cat == U_OTHER_LETTER) {
+ B_sequence_status = SEQ_STARTED;
+ B_scr = scr;
+ }
+ }
+
+ if (u_hasBinaryProperty(str[i], UCHAR_PATTERN_SYNTAX) || u_hasBinaryProperty(str[i], UCHAR_PATTERN_WHITE_SPACE) || u_hasBinaryProperty(str[i], UCHAR_NONCHARACTER_CODE_POINT)) {
+ return false; // Not a XID_Start or XID_Continue character.
+ }
+ if (i == 0) {
+ if (!(cat == U_LOWERCASE_LETTER || cat == U_UPPERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_OTHER_LETTER || cat == U_MODIFIER_LETTER || cat == U_LETTER_NUMBER || str[0] == 0x2118 || str[0] == 0x212E || str[0] == 0x309B || str[0] == 0x309C || str[0] == 0x005F)) {
+ return false; // Not a XID_Start character.
+ }
+ } else {
+ if (!(cat == U_LOWERCASE_LETTER || cat == U_UPPERCASE_LETTER || cat == U_TITLECASE_LETTER || cat == U_OTHER_LETTER || cat == U_MODIFIER_LETTER || cat == U_LETTER_NUMBER || cat == U_NON_SPACING_MARK || cat == U_COMBINING_SPACING_MARK || cat == U_DECIMAL_DIGIT_NUMBER || cat == U_CONNECTOR_PUNCTUATION || str[i] == 0x2118 || str[i] == 0x212E || str[i] == 0x309B || str[i] == 0x309C || str[i] == 0x1369 || str[i] == 0x1371 || str[i] == 0x00B7 || str[i] == 0x0387 || str[i] == 0x19DA || str[i] == 0x0E33 || str[i] == 0x0EB3 || str[i] == 0xFF9E || str[i] == 0xFF9F)) {
+ return false; // Not a XID_Continue character.
+ }
+ }
+ }
+ return true;
+}
+
TextServerAdvanced::TextServerAdvanced() {
_insert_num_systems_lang();
_insert_feature_sets();
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 8cd0e753ba..02abc31c55 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -101,6 +101,7 @@ using namespace godot;
#include <unicode/uloc.h>
#include <unicode/unorm2.h>
#include <unicode/uscript.h>
+#include <unicode/uspoof.h>
#include <unicode/ustring.h>
#include <unicode/utypes.h>
@@ -112,7 +113,10 @@ using namespace godot;
#include FT_ADVANCES_H
#include FT_MULTIPLE_MASTERS_H
#include FT_BBOX_H
-
+#include FT_CONFIG_OPTIONS_H
+#if !defined(FT_CONFIG_OPTION_USE_BROTLI) && !defined(_MSC_VER)
+#warning FreeType is configured without Brotli support, built-in fonts will not be available.
+#endif
#include <hb-ft.h>
#include <hb-ot.h>
#endif
@@ -219,7 +223,7 @@ class TextServerAdvanced : public TextServerExtension {
struct FontAdvanced {
Mutex mutex;
- bool antialiased = true;
+ TextServer::FontAntialiasing antialiasing = TextServer::FONT_ANTIALIASING_GRAY;
bool mipmaps = false;
bool msdf = false;
int msdf_range = 14;
@@ -267,7 +271,7 @@ class TextServerAdvanced : public TextServerExtension {
_FORCE_INLINE_ FontGlyph rasterize_msdf(FontAdvanced *p_font_data, FontForSizeAdvanced *p_data, int p_pixel_range, int p_rect_margin, FT_Outline *outline, const Vector2 &advance) const;
#endif
#ifdef MODULE_FREETYPE_ENABLED
- _FORCE_INLINE_ FontGlyph rasterize_bitmap(FontForSizeAdvanced *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance) const;
+ _FORCE_INLINE_ FontGlyph rasterize_bitmap(FontForSizeAdvanced *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance, bool p_bgra) const;
#endif
_FORCE_INLINE_ bool _ensure_glyph(FontAdvanced *p_font_data, const Vector2i &p_size, int32_t p_glyph) const;
_FORCE_INLINE_ bool _ensure_cache_for_size(FontAdvanced *p_font_data, const Vector2i &p_size) const;
@@ -494,8 +498,8 @@ public:
virtual void font_set_name(const RID &p_font_rid, const String &p_name) override;
virtual String font_get_name(const RID &p_font_rid) const override;
- virtual void font_set_antialiased(const RID &p_font_rid, bool p_antialiased) override;
- virtual bool font_is_antialiased(const RID &p_font_rid) const override;
+ virtual void font_set_antialiasing(RID p_font_rid, TextServer::FontAntialiasing p_antialiasing) override;
+ virtual TextServer::FontAntialiasing font_get_antialiasing(RID p_font_rid) const override;
virtual void font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) override;
virtual bool font_get_generate_mipmaps(const RID &p_font_rid) const override;
@@ -533,7 +537,7 @@ public:
virtual void font_set_oversampling(const RID &p_font_rid, double p_oversampling) override;
virtual double font_get_oversampling(const RID &p_font_rid) const override;
- virtual Array font_get_size_cache_list(const RID &p_font_rid) const override;
+ virtual TypedArray<Vector2i> font_get_size_cache_list(const RID &p_font_rid) const override;
virtual void font_clear_size_cache(const RID &p_font_rid) override;
virtual void font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) override;
@@ -562,7 +566,7 @@ public:
virtual void font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) override;
virtual PackedInt32Array font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const override;
- virtual Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const override;
+ virtual PackedInt32Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const override;
virtual void font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) override;
virtual void font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) override;
@@ -586,7 +590,7 @@ public:
virtual Dictionary font_get_glyph_contours(const RID &p_font, int64_t p_size, int64_t p_index) const override;
- virtual Array font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const override;
+ virtual TypedArray<Vector2i> font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const override;
virtual void font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) override;
virtual void font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) override;
@@ -701,7 +705,11 @@ public:
virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const override;
+ virtual int is_confusable(const String &p_string, const PackedStringArray &p_dict) const override;
+ virtual bool spoof_check(const String &p_string) const override;
+
virtual String strip_diacritics(const String &p_string) const override;
+ virtual bool is_valid_identifier(const String &p_string) const override;
virtual String string_to_upper(const String &p_string, const String &p_language = "") const override;
virtual String string_to_lower(const String &p_string, const String &p_language = "") const override;
diff --git a/modules/text_server_fb/SCsub b/modules/text_server_fb/SCsub
index ca9322e450..429d2e1fdc 100644
--- a/modules/text_server_fb/SCsub
+++ b/modules/text_server_fb/SCsub
@@ -3,8 +3,8 @@
Import("env")
Import("env_modules")
-freetype_enabled = env.module_check_dependencies("text_server_fb", ["freetype"], True)
-msdfgen_enabled = env.module_check_dependencies("text_server_fb", ["msdfgen"], True)
+freetype_enabled = "freetype" in env.module_list
+msdfgen_enabled = "msdfgen" in env.module_list
env_text_server_fb = env_modules.Clone()
@@ -12,6 +12,7 @@ if env["builtin_msdfgen"] and msdfgen_enabled:
env_text_server_fb.Prepend(CPPPATH=["#thirdparty/msdfgen"])
if env["builtin_freetype"] and freetype_enabled:
+ env_text_server_fb.Append(CPPDEFINES=["FT_CONFIG_OPTION_USE_BROTLI"])
env_text_server_fb.Prepend(CPPPATH=["#thirdparty/freetype/include"])
env_text_server_fb.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 50ea4677b1..53b303cb20 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -34,6 +34,7 @@
// Headers for building as GDExtension plug-in.
#include <godot_cpp/classes/file.hpp>
+#include <godot_cpp/classes/project_settings.hpp>
#include <godot_cpp/classes/rendering_server.hpp>
#include <godot_cpp/classes/translation_server.hpp>
#include <godot_cpp/core/error_macros.hpp>
@@ -43,6 +44,7 @@ using namespace godot;
#else
// Headers for building as built-in module.
+#include "core/config/project_settings.h"
#include "core/error/error_macros.h"
#include "core/string/print_string.h"
#include "core/string/ucaps.h"
@@ -209,6 +211,10 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
for (int i = 0; i < p_data->textures.size(); i++) {
const FontTexture &ct = p_data->textures[i];
+ if (p_image_format != ct.format) {
+ continue;
+ }
+
if (mw > ct.texture_w || mh > ct.texture_h) { // Too big for this texture.
continue;
}
@@ -500,9 +506,28 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
#endif
#ifdef MODULE_FREETYPE_ENABLED
-_FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitmap(FontForSizeFallback *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance) const {
+_FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitmap(FontForSizeFallback *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance, bool p_bgra) const {
int w = bitmap.width;
int h = bitmap.rows;
+ int color_size = 2;
+
+ switch (bitmap.pixel_mode) {
+ case FT_PIXEL_MODE_MONO:
+ case FT_PIXEL_MODE_GRAY: {
+ color_size = 2;
+ } break;
+ case FT_PIXEL_MODE_BGRA: {
+ color_size = 4;
+ } break;
+ case FT_PIXEL_MODE_LCD: {
+ color_size = 4;
+ w /= 3;
+ } break;
+ case FT_PIXEL_MODE_LCD_V: {
+ color_size = 4;
+ h /= 3;
+ } break;
+ }
int mw = w + p_rect_margin * 4;
int mh = h + p_rect_margin * 4;
@@ -510,7 +535,6 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
ERR_FAIL_COND_V(mw > 4096, FontGlyph());
ERR_FAIL_COND_V(mh > 4096, FontGlyph());
- int color_size = bitmap.pixel_mode == FT_PIXEL_MODE_BGRA ? 4 : 2;
Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8;
FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, color_size, require_format, mw, mh, false);
@@ -545,6 +569,34 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
wr[ofs + 3] = bitmap.buffer[ofs_color + 3];
} break;
+ case FT_PIXEL_MODE_LCD: {
+ int ofs_color = i * bitmap.pitch + (j * 3);
+ if (p_bgra) {
+ wr[ofs + 0] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
+ wr[ofs + 2] = bitmap.buffer[ofs_color + 2];
+ wr[ofs + 3] = 255;
+ } else {
+ wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
+ wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
+ wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 3] = 255;
+ }
+ } break;
+ case FT_PIXEL_MODE_LCD_V: {
+ int ofs_color = i * bitmap.pitch * 3 + j;
+ if (p_bgra) {
+ wr[ofs + 0] = bitmap.buffer[ofs_color + bitmap.pitch * 2];
+ wr[ofs + 1] = bitmap.buffer[ofs_color + bitmap.pitch];
+ wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 3] = 255;
+ } else {
+ wr[ofs + 0] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 1] = bitmap.buffer[ofs_color + bitmap.pitch];
+ wr[ofs + 2] = bitmap.buffer[ofs_color + bitmap.pitch * 2];
+ wr[ofs + 3] = 255;
+ }
+ } break;
default:
ERR_FAIL_V_MSG(FontGlyph(), "Font uses unsupported pixel format: " + String::num_int64(bitmap.pixel_mode) + ".");
break;
@@ -650,9 +702,44 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontFallback *p_font_data,
FT_Outline_Transform(&fd->face->glyph->outline, &mat);
}
+ FT_Render_Mode aa_mode = FT_RENDER_MODE_NORMAL;
+ bool bgra = false;
+ switch (p_font_data->antialiasing) {
+ case FONT_ANTIALIASING_NONE: {
+ aa_mode = FT_RENDER_MODE_MONO;
+ } break;
+ case FONT_ANTIALIASING_GRAY: {
+ aa_mode = FT_RENDER_MODE_NORMAL;
+ } break;
+ case FONT_ANTIALIASING_LCD: {
+ int aa_layout = (int)((p_glyph >> 24) & 7);
+ switch (aa_layout) {
+ case FONT_LCD_SUBPIXEL_LAYOUT_HRGB: {
+ aa_mode = FT_RENDER_MODE_LCD;
+ bgra = false;
+ } break;
+ case FONT_LCD_SUBPIXEL_LAYOUT_HBGR: {
+ aa_mode = FT_RENDER_MODE_LCD;
+ bgra = true;
+ } break;
+ case FONT_LCD_SUBPIXEL_LAYOUT_VRGB: {
+ aa_mode = FT_RENDER_MODE_LCD_V;
+ bgra = false;
+ } break;
+ case FONT_LCD_SUBPIXEL_LAYOUT_VBGR: {
+ aa_mode = FT_RENDER_MODE_LCD_V;
+ bgra = true;
+ } break;
+ default: {
+ aa_mode = FT_RENDER_MODE_NORMAL;
+ } break;
+ }
+ } break;
+ }
+
if (!outline) {
if (!p_font_data->msdf) {
- error = FT_Render_Glyph(fd->face->glyph, p_font_data->antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);
+ error = FT_Render_Glyph(fd->face->glyph, aa_mode);
}
FT_GlyphSlot slot = fd->face->glyph;
if (!error) {
@@ -664,7 +751,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontFallback *p_font_data,
ERR_FAIL_V_MSG(false, "Compiled without MSDFGEN support!");
#endif
} else {
- gl = rasterize_bitmap(fd, rect_range, slot->bitmap, slot->bitmap_top, slot->bitmap_left, Vector2((h + (1 << 9)) >> 10, (v + (1 << 9)) >> 10) / 64.0);
+ gl = rasterize_bitmap(fd, rect_range, slot->bitmap, slot->bitmap_top, slot->bitmap_left, Vector2((h + (1 << 9)) >> 10, (v + (1 << 9)) >> 10) / 64.0, bgra);
}
}
} else {
@@ -684,11 +771,11 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontFallback *p_font_data,
if (FT_Glyph_Stroke(&glyph, stroker, 1) != 0) {
goto cleanup_glyph;
}
- if (FT_Glyph_To_Bitmap(&glyph, p_font_data->antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, nullptr, 1) != 0) {
+ if (FT_Glyph_To_Bitmap(&glyph, aa_mode, nullptr, 1) != 0) {
goto cleanup_glyph;
}
glyph_bitmap = (FT_BitmapGlyph)glyph;
- gl = rasterize_bitmap(fd, rect_range, glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, Vector2());
+ gl = rasterize_bitmap(fd, rect_range, glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, Vector2(), bgra);
cleanup_glyph:
FT_Done_Glyph(glyph);
@@ -733,12 +820,14 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontFallback *p_f
fargs.stream = &fd->stream;
int max_index = 0;
- FT_Face tmp_face;
+ FT_Face tmp_face = nullptr;
error = FT_Open_Face(ft_library, &fargs, -1, &tmp_face);
- if (error == 0) {
+ if (tmp_face && error == 0) {
max_index = tmp_face->num_faces - 1;
}
- FT_Done_Face(tmp_face);
+ if (tmp_face) {
+ FT_Done_Face(tmp_face);
+ }
error = FT_Open_Face(ft_library, &fargs, CLAMP(p_font_data->face_index, 0, max_index), &fd->face);
if (error) {
@@ -1012,23 +1101,23 @@ String TextServerFallback::font_get_name(const RID &p_font_rid) const {
return fd->font_name;
}
-void TextServerFallback::font_set_antialiased(const RID &p_font_rid, bool p_antialiased) {
+void TextServerFallback::font_set_antialiasing(RID p_font_rid, TextServer::FontAntialiasing p_antialiasing) {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
- if (fd->antialiased != p_antialiased) {
+ if (fd->antialiasing != p_antialiasing) {
_font_clear_cache(fd);
- fd->antialiased = p_antialiased;
+ fd->antialiasing = p_antialiasing;
}
}
-bool TextServerFallback::font_is_antialiased(const RID &p_font_rid) const {
+TextServer::FontAntialiasing TextServerFallback::font_get_antialiasing(RID p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, false);
+ ERR_FAIL_COND_V(!fd, TextServer::FONT_ANTIALIASING_NONE);
MutexLock lock(fd->mutex);
- return fd->antialiased;
+ return fd->antialiasing;
}
void TextServerFallback::font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) {
@@ -1257,12 +1346,12 @@ double TextServerFallback::font_get_oversampling(const RID &p_font_rid) const {
return fd->oversampling;
}
-Array TextServerFallback::font_get_size_cache_list(const RID &p_font_rid) const {
+TypedArray<Vector2i> TextServerFallback::font_get_size_cache_list(const RID &p_font_rid) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, Array());
+ ERR_FAIL_COND_V(!fd, TypedArray<Vector2i>());
MutexLock lock(fd->mutex);
- Array ret;
+ TypedArray<Vector2i> ret;
for (const KeyValue<Vector2i, FontForSizeFallback *> &E : fd->cache) {
ret.push_back(E.key);
}
@@ -1541,15 +1630,15 @@ PackedInt32Array TextServerFallback::font_get_texture_offsets(const RID &p_font_
return tex.offsets;
}
-Array TextServerFallback::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {
+PackedInt32Array TextServerFallback::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, Array());
+ ERR_FAIL_COND_V(!fd, PackedInt32Array());
MutexLock lock(fd->mutex);
Vector2i size = _get_size_outline(fd, p_size);
- ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Array());
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), PackedInt32Array());
- Array ret;
+ PackedInt32Array ret;
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
for (const KeyValue<int32_t, FontGlyph> &E : gl) {
ret.push_back(E.key);
@@ -1587,7 +1676,16 @@ Vector2 TextServerFallback::font_get_glyph_advance(const RID &p_font_rid, int64_
Vector2i size = _get_size(fd, p_size);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
- if (!_ensure_glyph(fd, size, p_glyph)) {
+
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
+ if (!_ensure_glyph(fd, size, p_glyph | mod)) {
return Vector2(); // Invalid or non graphicl glyph, do not display errors.
}
@@ -1630,7 +1728,16 @@ Vector2 TextServerFallback::font_get_glyph_offset(const RID &p_font_rid, const V
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
- if (!_ensure_glyph(fd, size, p_glyph)) {
+
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
+ if (!_ensure_glyph(fd, size, p_glyph | mod)) {
return Vector2(); // Invalid or non graphicl glyph, do not display errors.
}
@@ -1666,7 +1773,16 @@ Vector2 TextServerFallback::font_get_glyph_size(const RID &p_font_rid, const Vec
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
- if (!_ensure_glyph(fd, size, p_glyph)) {
+
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
+ if (!_ensure_glyph(fd, size, p_glyph | mod)) {
return Vector2(); // Invalid or non graphicl glyph, do not display errors.
}
@@ -1702,7 +1818,16 @@ Rect2 TextServerFallback::font_get_glyph_uv_rect(const RID &p_font_rid, const Ve
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Rect2());
- if (!_ensure_glyph(fd, size, p_glyph)) {
+
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
+ if (!_ensure_glyph(fd, size, p_glyph | mod)) {
return Rect2(); // Invalid or non graphicl glyph, do not display errors.
}
@@ -1733,7 +1858,16 @@ int64_t TextServerFallback::font_get_glyph_texture_idx(const RID &p_font_rid, co
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), -1);
- if (!_ensure_glyph(fd, size, p_glyph)) {
+
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
+ if (!_ensure_glyph(fd, size, p_glyph | mod)) {
return -1; // Invalid or non graphicl glyph, do not display errors.
}
@@ -1764,7 +1898,16 @@ RID TextServerFallback::font_get_glyph_texture_rid(const RID &p_font_rid, const
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), RID());
- if (!_ensure_glyph(fd, size, p_glyph)) {
+
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
+ if (!_ensure_glyph(fd, size, p_glyph | mod)) {
return RID(); // Invalid or non graphicl glyph, do not display errors.
}
@@ -1803,7 +1946,16 @@ Size2 TextServerFallback::font_get_glyph_texture_size(const RID &p_font_rid, con
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Size2());
- if (!_ensure_glyph(fd, size, p_glyph)) {
+
+ int mod = 0;
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ mod = (layout << 24);
+ }
+ }
+
+ if (!_ensure_glyph(fd, size, p_glyph | mod)) {
return Size2(); // Invalid or non graphicl glyph, do not display errors.
}
@@ -1884,16 +2036,16 @@ Dictionary TextServerFallback::font_get_glyph_contours(const RID &p_font_rid, in
#endif
}
-Array TextServerFallback::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const {
+TypedArray<Vector2i> TextServerFallback::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const {
FontFallback *fd = font_owner.get_or_null(p_font_rid);
- ERR_FAIL_COND_V(!fd, Array());
+ ERR_FAIL_COND_V(!fd, TypedArray<Vector2i>());
MutexLock lock(fd->mutex);
Vector2i size = _get_size(fd, p_size);
- ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Array());
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), TypedArray<Vector2i>());
- Array ret;
+ TypedArray<Vector2i> ret;
for (const KeyValue<Vector2i, Vector2> &E : fd->cache[size]->kerning_map) {
ret.push_back(E.key);
}
@@ -2041,16 +2193,18 @@ void TextServerFallback::font_render_range(const RID &p_font_rid, const Vector2i
if (fd->msdf) {
_ensure_glyph(fd, size, (int32_t)idx);
} else {
- if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
- _ensure_glyph(fd, size, (int32_t)idx | (0 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (1 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (2 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (3 << 27));
- } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
- _ensure_glyph(fd, size, (int32_t)idx | (1 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (0 << 27));
- } else {
- _ensure_glyph(fd, size, (int32_t)idx);
+ for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) {
+ if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
+ _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24));
+ } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
+ _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24));
+ } else {
+ _ensure_glyph(fd, size, (int32_t)idx | (aa << 24));
+ }
}
}
}
@@ -2071,16 +2225,18 @@ void TextServerFallback::font_render_glyph(const RID &p_font_rid, const Vector2i
if (fd->msdf) {
_ensure_glyph(fd, size, (int32_t)idx);
} else {
- if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
- _ensure_glyph(fd, size, (int32_t)idx | (0 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (1 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (2 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (3 << 27));
- } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
- _ensure_glyph(fd, size, (int32_t)idx | (1 << 27));
- _ensure_glyph(fd, size, (int32_t)idx | (0 << 27));
- } else {
- _ensure_glyph(fd, size, (int32_t)idx);
+ for (int aa = 0; aa < ((fd->antialiasing == FONT_ANTIALIASING_LCD) ? FONT_LCD_SUBPIXEL_LAYOUT_MAX : 1); aa++) {
+ if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
+ _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (2 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (3 << 27) | (aa << 24));
+ } else if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_HALF) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE)) {
+ _ensure_glyph(fd, size, (int32_t)idx | (1 << 27) | (aa << 24));
+ _ensure_glyph(fd, size, (int32_t)idx | (0 << 27) | (aa << 24));
+ } else {
+ _ensure_glyph(fd, size, (int32_t)idx | (aa << 24));
+ }
}
}
}
@@ -2096,9 +2252,19 @@ void TextServerFallback::font_draw_glyph(const RID &p_font_rid, const RID &p_can
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
int32_t index = p_index & 0xffffff; // Remove subpixel shifts.
+ bool lcd_aa = false;
#ifdef MODULE_FREETYPE_ENABLED
if (!fd->msdf && fd->cache[size]->face) {
+ // LCD layout, bits 24, 25, 26
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ lcd_aa = true;
+ index = index | (layout << 24);
+ }
+ }
+ // Subpixel X-shift, bits 27, 28
if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125));
index = index | (xshift << 27);
@@ -2120,7 +2286,7 @@ void TextServerFallback::font_draw_glyph(const RID &p_font_rid, const RID &p_can
if (gl.texture_idx != -1) {
Color modulate = p_color;
#ifdef MODULE_FREETYPE_ENABLED
- if (fd->cache[size]->face && FT_HAS_COLOR(fd->cache[size]->face)) {
+ if (fd->cache[size]->face && (fd->cache[size]->textures[gl.texture_idx].format == Image::FORMAT_RGBA8) && !lcd_aa) {
modulate.r = modulate.g = modulate.b = 1.0;
}
#endif
@@ -2158,7 +2324,11 @@ void TextServerFallback::font_draw_glyph(const RID &p_font_rid, const RID &p_can
}
cpos += gl.rect.position;
Size2 csize = gl.rect.size;
- RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false);
+ if (lcd_aa) {
+ RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate);
+ } else {
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false);
+ }
}
}
}
@@ -2174,9 +2344,19 @@ void TextServerFallback::font_draw_glyph_outline(const RID &p_font_rid, const RI
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
int32_t index = p_index & 0xffffff; // Remove subpixel shifts.
+ bool lcd_aa = false;
#ifdef MODULE_FREETYPE_ENABLED
if (!fd->msdf && fd->cache[size]->face) {
+ // LCD layout, bits 24, 25, 26
+ if (fd->antialiasing == FONT_ANTIALIASING_LCD) {
+ TextServer::FontLCDSubpixelLayout layout = (TextServer::FontLCDSubpixelLayout)(int)GLOBAL_GET("gui/theme/lcd_subpixel_layout");
+ if (layout != FONT_LCD_SUBPIXEL_LAYOUT_NONE) {
+ lcd_aa = true;
+ index = index | (layout << 24);
+ }
+ }
+ // Subpixel X-shift, bits 27, 28
if ((fd->subpixel_positioning == SUBPIXEL_POSITIONING_ONE_QUARTER) || (fd->subpixel_positioning == SUBPIXEL_POSITIONING_AUTO && size.x <= SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE)) {
int xshift = (int)(Math::floor(4 * (p_pos.x + 0.125)) - 4 * Math::floor(p_pos.x + 0.125));
index = index | (xshift << 27);
@@ -2236,7 +2416,11 @@ void TextServerFallback::font_draw_glyph_outline(const RID &p_font_rid, const RI
}
cpos += gl.rect.position;
Size2 csize = gl.rect.size;
- RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false);
+ if (lcd_aa) {
+ RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate);
+ } else {
+ RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, false, false);
+ }
}
}
}
@@ -3204,7 +3388,7 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(const RID &p_shaped_l
Glyph *sd_glyphs = sd->glyphs.ptrw();
- if (p_trim_flags.has_flag(OVERRUN_TRIM) || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) {
+ if ((p_trim_flags & OVERRUN_TRIM) == OVERRUN_NO_TRIM || sd_glyphs == nullptr || p_width <= 0 || !(sd->width > p_width || enforce_ellipsis)) {
sd->overrun_trim_data.trim_pos = -1;
sd->overrun_trim_data.ellipsis_pos = -1;
return;
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index adb5cbb817..940c57a354 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -98,6 +98,10 @@ using namespace godot;
#include FT_ADVANCES_H
#include FT_MULTIPLE_MASTERS_H
#include FT_BBOX_H
+#include FT_CONFIG_OPTIONS_H
+#if !defined(FT_CONFIG_OPTION_USE_BROTLI) && !defined(_MSC_VER)
+#warning FreeType is configured without Brotli support, built-in fonts will not be available.
+#endif
#endif
/*************************************************************************/
@@ -175,7 +179,7 @@ class TextServerFallback : public TextServerExtension {
struct FontFallback {
Mutex mutex;
- bool antialiased = true;
+ TextServer::FontAntialiasing antialiasing = TextServer::FONT_ANTIALIASING_GRAY;
bool mipmaps = false;
bool msdf = false;
int msdf_range = 14;
@@ -221,7 +225,7 @@ class TextServerFallback : public TextServerExtension {
_FORCE_INLINE_ FontGlyph rasterize_msdf(FontFallback *p_font_data, FontForSizeFallback *p_data, int p_pixel_range, int p_rect_margin, FT_Outline *outline, const Vector2 &advance) const;
#endif
#ifdef MODULE_FREETYPE_ENABLED
- _FORCE_INLINE_ FontGlyph rasterize_bitmap(FontForSizeFallback *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance) const;
+ _FORCE_INLINE_ FontGlyph rasterize_bitmap(FontForSizeFallback *p_data, int p_rect_margin, FT_Bitmap bitmap, int yofs, int xofs, const Vector2 &advance, bool p_bgra) const;
#endif
_FORCE_INLINE_ bool _ensure_glyph(FontFallback *p_font_data, const Vector2i &p_size, int32_t p_glyph) const;
_FORCE_INLINE_ bool _ensure_cache_for_size(FontFallback *p_font_data, const Vector2i &p_size) const;
@@ -374,8 +378,8 @@ public:
virtual void font_set_name(const RID &p_font_rid, const String &p_name) override;
virtual String font_get_name(const RID &p_font_rid) const override;
- virtual void font_set_antialiased(const RID &p_font_rid, bool p_antialiased) override;
- virtual bool font_is_antialiased(const RID &p_font_rid) const override;
+ virtual void font_set_antialiasing(RID p_font_rid, TextServer::FontAntialiasing p_antialiasing) override;
+ virtual TextServer::FontAntialiasing font_get_antialiasing(RID p_font_rid) const override;
virtual void font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) override;
virtual bool font_get_generate_mipmaps(const RID &p_font_rid) const override;
@@ -413,7 +417,7 @@ public:
virtual void font_set_oversampling(const RID &p_font_rid, double p_oversampling) override;
virtual double font_get_oversampling(const RID &p_font_rid) const override;
- virtual Array font_get_size_cache_list(const RID &p_font_rid) const override;
+ virtual TypedArray<Vector2i> font_get_size_cache_list(const RID &p_font_rid) const override;
virtual void font_clear_size_cache(const RID &p_font_rid) override;
virtual void font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) override;
@@ -442,7 +446,7 @@ public:
virtual void font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) override;
virtual PackedInt32Array font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const override;
- virtual Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const override;
+ virtual PackedInt32Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const override;
virtual void font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) override;
virtual void font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) override;
@@ -465,7 +469,7 @@ public:
virtual Dictionary font_get_glyph_contours(const RID &p_font, int64_t p_size, int64_t p_index) const override;
- virtual Array font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const override;
+ virtual TypedArray<Vector2i> font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const override;
virtual void font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) override;
virtual void font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) override;
diff --git a/modules/tga/SCsub b/modules/tga/SCsub
index 067caa6ea0..ccd7d2ee37 100644
--- a/modules/tga/SCsub
+++ b/modules/tga/SCsub
@@ -5,5 +5,5 @@ Import("env_modules")
env_tga = env_modules.Clone()
-# Godot's own source files
+# Godot source files
env_tga.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/tga/image_loader_tga.cpp b/modules/tga/image_loader_tga.cpp
index 08ad1ef9f8..16d9bf7b93 100644
--- a/modules/tga/image_loader_tga.cpp
+++ b/modules/tga/image_loader_tga.cpp
@@ -230,7 +230,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff
return OK;
}
-Error ImageLoaderTGA::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) {
+Error ImageLoaderTGA::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) {
Vector<uint8_t> src_image;
uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
diff --git a/modules/tga/image_loader_tga.h b/modules/tga/image_loader_tga.h
index 9b7cbbac77..d95c5ff30b 100644
--- a/modules/tga/image_loader_tga.h
+++ b/modules/tga/image_loader_tga.h
@@ -73,7 +73,7 @@ class ImageLoaderTGA : public ImageFormatLoader {
static Error convert_to_image(Ref<Image> p_image, const uint8_t *p_buffer, const tga_header_s &p_header, const uint8_t *p_palette, const bool p_is_monochrome, size_t p_input_size);
public:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderTGA();
};
diff --git a/modules/theora/config.py b/modules/theora/config.py
index 7f354a8fda..9a27e8e132 100644
--- a/modules/theora/config.py
+++ b/modules/theora/config.py
@@ -1,7 +1,8 @@
def can_build(env, platform):
if env["arch"].startswith("rv"):
return False
- return env.module_check_dependencies("theora", ["ogg", "vorbis"])
+ env.module_add_dependencies("theora", ["ogg", "vorbis"])
+ return True
def configure(env):
diff --git a/modules/theora/doc_classes/VideoStreamTheora.xml b/modules/theora/doc_classes/VideoStreamTheora.xml
index 0f2dece8e7..e07af8f169 100644
--- a/modules/theora/doc_classes/VideoStreamTheora.xml
+++ b/modules/theora/doc_classes/VideoStreamTheora.xml
@@ -18,7 +18,7 @@
</method>
<method name="set_file">
<return type="void" />
- <argument index="0" name="file" type="String" />
+ <param index="0" name="file" type="String" />
<description>
Sets the Ogg Theora video file that this [VideoStreamTheora] resource handles. The [code]file[/code] name should have the [code].ogv[/code] extension.
</description>
diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp
index 864df765ee..6f61251f9b 100644
--- a/modules/tinyexr/image_loader_tinyexr.cpp
+++ b/modules/tinyexr/image_loader_tinyexr.cpp
@@ -37,7 +37,7 @@
#include "thirdparty/tinyexr/tinyexr.h"
-Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) {
+Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) {
Vector<uint8_t> src_image;
uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
@@ -229,7 +229,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool
color.a = *a_channel++;
}
- if (p_force_linear) {
+ if (p_flags & FLAG_FORCE_LINEAR) {
color = color.srgb_to_linear();
}
@@ -260,7 +260,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool
color.a = *a_channel++;
}
- if (p_force_linear) {
+ if (p_flags & FLAG_FORCE_LINEAR) {
color = color.srgb_to_linear();
}
diff --git a/modules/tinyexr/image_loader_tinyexr.h b/modules/tinyexr/image_loader_tinyexr.h
index 0d3de93956..8da2a0d4af 100644
--- a/modules/tinyexr/image_loader_tinyexr.h
+++ b/modules/tinyexr/image_loader_tinyexr.h
@@ -35,7 +35,7 @@
class ImageLoaderTinyEXR : public ImageFormatLoader {
public:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderTinyEXR();
};
diff --git a/modules/upnp/doc_classes/UPNP.xml b/modules/upnp/doc_classes/UPNP.xml
index 066506922c..4888dca822 100644
--- a/modules/upnp/doc_classes/UPNP.xml
+++ b/modules/upnp/doc_classes/UPNP.xml
@@ -1,16 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="UPNP" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
- UPNP network functions.
+ Universal Plug and Play (UPnP) functions for network device discovery, querying and port forwarding.
</brief_description>
<description>
- Provides UPNP functionality to discover [UPNPDevice]s on the local network and execute commands on them, like managing port mappings (port forwarding) and querying the local and remote network IP address. Note that methods on this class are synchronous and block the calling thread.
- To forward a specific port:
+ This class can be used to discover compatible [UPNPDevice]s on the local network and execute commands on them, like managing port mappings (for port forwarding/NAT traversal) and querying the local and remote network IP address. Note that methods on this class are synchronous and block the calling thread.
+ To forward a specific port (here [code]7777[/code], note both [method discover] and [method add_port_mapping] can return errors that should be checked):
[codeblock]
- const PORT = 7777
var upnp = UPNP.new()
- upnp.discover(2000, 2, "InternetGatewayDevice")
- upnp.add_port_mapping(port)
+ upnp.discover()
+ upnp.add_port_mapping(7777)
[/codeblock]
To close a specific port (e.g. after you have finished using it):
[codeblock]
@@ -21,7 +20,7 @@
# Emitted when UPnP port mapping setup is completed (regardless of success or failure).
signal upnp_completed(error)
- # Replace this with your own server port number between 1025 and 65535.
+ # Replace this with your own server port number between 1024 and 65535.
const SERVER_PORT = 3928
var thread = null
@@ -48,28 +47,38 @@
# Wait for thread finish here to handle game exit while the thread is running.
thread.wait_to_finish()
[/codeblock]
+ [b]Terminology:[/b] In the context of UPnP networking, "gateway" (or "internet gateway device", short IGD) refers to network devices that allow computers in the local network to access the internet ("wide area network", WAN). These gateways are often also called "routers".
+ [b]Pitfalls:[/b]
+ - As explained above, these calls are blocking and shouldn't be run on the main thread, especially as they can block for multiple seconds at a time. Use threading!
+ - Networking is physical and messy. Packets get lost in transit or get filtered, addresses, free ports and assigned mappings change, and devices may leave or join the network at any time. Be mindful of this, be diligent when checking and handling errors, and handle these gracefully if you can: add clear error UI, timeouts and re-try handling.
+ - Port mappings may change (and be removed) at any time, and the remote/external IP address of the gateway can change likewise. You should consider re-querying the external IP and try to update/refresh the port mapping periodically (for example, every 5 minutes and on networking failures).
+ - Not all devices support UPnP, and some users disable UPnP support. You need to handle this (e.g. documenting and requiring the user to manually forward ports, or adding alternative methods of NAT traversal, like a relay/mirror server, or NAT hole punching, STUN/TURN, etc.).
+ - Consider what happens on mapping conflicts. Maybe multiple users on the same network would like to play your game at the same time, or maybe another application uses the same port. Make the port configurable, and optimally choose a port automatically (re-trying with a different port on failure).
+ [b]Further reading:[/b] If you want to know more about UPnP (and the Internet Gateway Device (IGD) and Port Control Protocol (PCP) specifically), [url=https://en.wikipedia.org/wiki/Universal_Plug_and_Play]Wikipedia[/url] is a good first stop, the specification can be found at the [url=https://openconnectivity.org/developer/specifications/upnp-resources/upnp/]Open Connectivity Foundation[/url] and Godot's implementation is based on the [url=https://github.com/miniupnp/miniupnp]MiniUPnP client[/url].
</description>
<tutorials>
</tutorials>
<methods>
<method name="add_device">
<return type="void" />
- <argument index="0" name="device" type="UPNPDevice" />
+ <param index="0" name="device" type="UPNPDevice" />
<description>
Adds the given [UPNPDevice] to the list of discovered devices.
</description>
</method>
<method name="add_port_mapping" qualifiers="const">
<return type="int" />
- <argument index="0" name="port" type="int" />
- <argument index="1" name="port_internal" type="int" default="0" />
- <argument index="2" name="desc" type="String" default="&quot;&quot;" />
- <argument index="3" name="proto" type="String" default="&quot;UDP&quot;" />
- <argument index="4" name="duration" type="int" default="0" />
+ <param index="0" name="port" type="int" />
+ <param index="1" name="port_internal" type="int" default="0" />
+ <param index="2" name="desc" type="String" default="&quot;&quot;" />
+ <param index="3" name="proto" type="String" default="&quot;UDP&quot;" />
+ <param index="4" name="duration" type="int" default="0" />
<description>
- Adds a mapping to forward the external [code]port[/code] (between 1 and 65535) on the default gateway (see [method get_gateway]) to the [code]internal_port[/code] on the local machine for the given protocol [code]proto[/code] (either [code]TCP[/code] or [code]UDP[/code], with UDP being the default). If a port mapping for the given port and protocol combination already exists on that gateway device, this method tries to overwrite it. If that is not desired, you can retrieve the gateway manually with [method get_gateway] and call [method add_port_mapping] on it, if any.
+ Adds a mapping to forward the external [code]port[/code] (between 1 and 65535, although recommended to use port 1024 or above) on the default gateway (see [method get_gateway]) to the [code]internal_port[/code] on the local machine for the given protocol [code]proto[/code] (either [code]TCP[/code] or [code]UDP[/code], with UDP being the default). If a port mapping for the given port and protocol combination already exists on that gateway device, this method tries to overwrite it. If that is not desired, you can retrieve the gateway manually with [method get_gateway] and call [method add_port_mapping] on it, if any. Note that forwarding a well-known port (below 1024) with UPnP may fail depending on the device.
+ Depending on the gateway device, if a mapping for that port already exists, it will either be updated or it will refuse this command due to that conflict, especially if the existing mapping for that port wasn't created via UPnP or points to a different network address (or device) than this one.
If [code]internal_port[/code] is [code]0[/code] (the default), the same port number is used for both the external and the internal port (the [code]port[/code] value).
- The description ([code]desc[/code]) is shown in some router UIs and can be used to point out which application added the mapping. The mapping's lease duration can be limited by specifying a [code]duration[/code] (in seconds). However, some routers are incompatible with one or both of these, so use with caution and add fallback logic in case of errors to retry without them if in doubt.
+ The description ([code]desc[/code]) is shown in some routers management UIs and can be used to point out which application added the mapping.
+ The mapping's lease [code]duration[/code] can be limited by specifying a duration in seconds. The default of [code]0[/code] means no duration, i.e. a permanent lease and notably some devices only support these permanent leases. Note that whether permanent or not, this is only a request and the gateway may still decide at any point to remove the mapping (which usually happens on a reboot of the gateway, when its external IP address changes, or on some models when it detects a port mapping has become inactive, i.e. had no traffic for multiple minutes). If not [code]0[/code] (permanent), the allowed range according to spec is between [code]120[/code] (2 minutes) and [code]86400[/code] seconds (24 hours).
See [enum UPNPResult] for possible return values.
</description>
</method>
@@ -81,17 +90,17 @@
</method>
<method name="delete_port_mapping" qualifiers="const">
<return type="int" />
- <argument index="0" name="port" type="int" />
- <argument index="1" name="proto" type="String" default="&quot;UDP&quot;" />
+ <param index="0" name="port" type="int" />
+ <param index="1" name="proto" type="String" default="&quot;UDP&quot;" />
<description>
- Deletes the port mapping for the given port and protocol combination on the default gateway (see [method get_gateway]) if one exists. [code]port[/code] must be a valid port between 1 and 65535, [code]proto[/code] can be either [code]TCP[/code] or [code]UDP[/code]. See [enum UPNPResult] for possible return values.
+ Deletes the port mapping for the given port and protocol combination on the default gateway (see [method get_gateway]) if one exists. [code]port[/code] must be a valid port between 1 and 65535, [code]proto[/code] can be either [code]TCP[/code] or [code]UDP[/code]. May be refused for mappings pointing to addresses other than this one, for well-known ports (below 1024), or for mappings not added via UPnP. See [enum UPNPResult] for possible return values.
</description>
</method>
<method name="discover">
<return type="int" />
- <argument index="0" name="timeout" type="int" default="2000" />
- <argument index="1" name="ttl" type="int" default="2" />
- <argument index="2" name="device_filter" type="String" default="&quot;InternetGatewayDevice&quot;" />
+ <param index="0" name="timeout" type="int" default="2000" />
+ <param index="1" name="ttl" type="int" default="2" />
+ <param index="2" name="device_filter" type="String" default="&quot;InternetGatewayDevice&quot;" />
<description>
Discovers local [UPNPDevice]s. Clears the list of previously discovered devices.
Filters for IGD (InternetGatewayDevice) type devices by default, as those manage port forwarding. [code]timeout[/code] is the time to wait for responses in milliseconds. [code]ttl[/code] is the time-to-live; only touch this if you know what you're doing.
@@ -100,7 +109,7 @@
</method>
<method name="get_device" qualifiers="const">
<return type="UPNPDevice" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Returns the [UPNPDevice] at the given [code]index[/code].
</description>
@@ -125,15 +134,15 @@
</method>
<method name="remove_device">
<return type="void" />
- <argument index="0" name="index" type="int" />
+ <param index="0" name="index" type="int" />
<description>
Removes the device at [code]index[/code] from the list of discovered devices.
</description>
</method>
<method name="set_device">
<return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="device" type="UPNPDevice" />
+ <param index="0" name="index" type="int" />
+ <param index="1" name="device" type="UPNPDevice" />
<description>
Sets the device at [code]index[/code] from the list of discovered devices to [code]device[/code].
</description>
diff --git a/modules/upnp/doc_classes/UPNPDevice.xml b/modules/upnp/doc_classes/UPNPDevice.xml
index 7749ac18ab..538ca72391 100644
--- a/modules/upnp/doc_classes/UPNPDevice.xml
+++ b/modules/upnp/doc_classes/UPNPDevice.xml
@@ -1,29 +1,29 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="UPNPDevice" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
- UPNP device.
+ Universal Plug and Play (UPnP) device.
</brief_description>
<description>
- UPNP device. See [UPNP] for UPNP discovery and utility functions. Provides low-level access to UPNP control commands. Allows to manage port mappings (port forwarding) and to query network information of the device (like local and external IP address and status). Note that methods on this class are synchronous and block the calling thread.
+ Universal Plug and Play (UPnP) device. See [UPNP] for UPnP discovery and utility functions. Provides low-level access to UPNP control commands. Allows to manage port mappings (port forwarding) and to query network information of the device (like local and external IP address and status). Note that methods on this class are synchronous and block the calling thread.
</description>
<tutorials>
</tutorials>
<methods>
<method name="add_port_mapping" qualifiers="const">
<return type="int" />
- <argument index="0" name="port" type="int" />
- <argument index="1" name="port_internal" type="int" default="0" />
- <argument index="2" name="desc" type="String" default="&quot;&quot;" />
- <argument index="3" name="proto" type="String" default="&quot;UDP&quot;" />
- <argument index="4" name="duration" type="int" default="0" />
+ <param index="0" name="port" type="int" />
+ <param index="1" name="port_internal" type="int" default="0" />
+ <param index="2" name="desc" type="String" default="&quot;&quot;" />
+ <param index="3" name="proto" type="String" default="&quot;UDP&quot;" />
+ <param index="4" name="duration" type="int" default="0" />
<description>
Adds a port mapping to forward the given external port on this [UPNPDevice] for the given protocol to the local machine. See [method UPNP.add_port_mapping].
</description>
</method>
<method name="delete_port_mapping" qualifiers="const">
<return type="int" />
- <argument index="0" name="port" type="int" />
- <argument index="1" name="proto" type="String" default="&quot;UDP&quot;" />
+ <param index="0" name="port" type="int" />
+ <param index="1" name="proto" type="String" default="&quot;UDP&quot;" />
<description>
Deletes the port mapping identified by the given port and protocol combination on this device. See [method UPNP.delete_port_mapping].
</description>
diff --git a/modules/upnp/upnp.cpp b/modules/upnp/upnp.cpp
index d762ca4f09..82fe39e003 100644
--- a/modules/upnp/upnp.cpp
+++ b/modules/upnp/upnp.cpp
@@ -319,8 +319,6 @@ int UPNP::add_port_mapping(int port, int port_internal, String desc, String prot
return UPNP_RESULT_NO_GATEWAY;
}
- dev->delete_port_mapping(port, proto);
-
return dev->add_port_mapping(port, port_internal, desc, proto, duration);
}
diff --git a/modules/visual_script/SCsub b/modules/visual_script/SCsub
deleted file mode 100644
index b91cceae09..0000000000
--- a/modules/visual_script/SCsub
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/env python
-
-Import("env")
-Import("env_modules")
-
-env_vs = env_modules.Clone()
-
-env_vs.add_source_files(env.modules_sources, "*.cpp")
-
-if env["tools"]:
- env_vs.add_source_files(env.modules_sources, "editor/*.cpp")
diff --git a/modules/visual_script/config.py b/modules/visual_script/config.py
deleted file mode 100644
index e8990c43c8..0000000000
--- a/modules/visual_script/config.py
+++ /dev/null
@@ -1,63 +0,0 @@
-def can_build(env, platform):
- return True
-
-
-def configure(env):
- pass
-
-
-def get_doc_classes():
- return [
- "VisualScriptBasicTypeConstant",
- "VisualScriptBuiltinFunc",
- "VisualScriptClassConstant",
- "VisualScriptComment",
- "VisualScriptComposeArray",
- "VisualScriptCondition",
- "VisualScriptConstant",
- "VisualScriptConstructor",
- "VisualScriptCustomNode",
- "VisualScriptCustomNodes",
- "VisualScriptDeconstruct",
- "VisualScriptEditor",
- "VisualScriptEmitSignal",
- "VisualScriptEngineSingleton",
- "VisualScriptExpression",
- "VisualScriptFunctionCall",
- "VisualScriptFunctionState",
- "VisualScriptFunction",
- "VisualScriptGlobalConstant",
- "VisualScriptIndexGet",
- "VisualScriptIndexSet",
- "VisualScriptInputAction",
- "VisualScriptIterator",
- "VisualScriptLists",
- "VisualScriptLocalVarSet",
- "VisualScriptLocalVar",
- "VisualScriptMathConstant",
- "VisualScriptNode",
- "VisualScriptOperator",
- "VisualScriptPreload",
- "VisualScriptPropertyGet",
- "VisualScriptPropertySet",
- "VisualScriptResourcePath",
- "VisualScriptReturn",
- "VisualScriptSceneNode",
- "VisualScriptSceneTree",
- "VisualScriptSelect",
- "VisualScriptSelf",
- "VisualScriptSequence",
- "VisualScriptSubCall",
- "VisualScriptSwitch",
- "VisualScriptTypeCast",
- "VisualScriptVariableGet",
- "VisualScriptVariableSet",
- "VisualScriptWhile",
- "VisualScript",
- "VisualScriptYieldSignal",
- "VisualScriptYield",
- ]
-
-
-def get_doc_path():
- return "doc_classes"
diff --git a/modules/visual_script/doc_classes/VisualScript.xml b/modules/visual_script/doc_classes/VisualScript.xml
deleted file mode 100644
index 5807c98d32..0000000000
--- a/modules/visual_script/doc_classes/VisualScript.xml
+++ /dev/null
@@ -1,357 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScript" inherits="Script" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A script implemented in the Visual Script programming environment.
- </brief_description>
- <description>
- A script implemented in the Visual Script programming environment. The script extends the functionality of all objects that instance it.
- [method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes.
- You are most likely to use this class via the Visual Script editor or when writing plugins for it.
- </description>
- <tutorials>
- <link title="VisualScript documentation index">$DOCS_URL/tutorials/scripting/visual_script/index.html</link>
- </tutorials>
- <methods>
- <method name="add_custom_signal">
- <return type="void" />
- <argument index="0" name="name" type="StringName" />
- <description>
- Add a custom signal with the specified name to the VisualScript.
- </description>
- </method>
- <method name="add_function">
- <return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="func_node_id" type="int" />
- <description>
- Add a function with the specified name to the VisualScript, and assign the root [VisualScriptFunction] node's id as [code]func_node_id[/code].
- </description>
- </method>
- <method name="add_node">
- <return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="node" type="VisualScriptNode" />
- <argument index="2" name="position" type="Vector2" default="Vector2(0, 0)" />
- <description>
- Add a node to the VisualScript.
- </description>
- </method>
- <method name="add_variable">
- <return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="default_value" type="Variant" default="null" />
- <argument index="2" name="export" type="bool" default="false" />
- <description>
- Add a variable to the VisualScript, optionally giving it a default value or marking it as exported.
- </description>
- </method>
- <method name="custom_signal_add_argument">
- <return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="type" type="int" enum="Variant.Type" />
- <argument index="2" name="argname" type="String" />
- <argument index="3" name="index" type="int" default="-1" />
- <description>
- Add an argument to a custom signal added with [method add_custom_signal].
- </description>
- </method>
- <method name="custom_signal_get_argument_count" qualifiers="const">
- <return type="int" />
- <argument index="0" name="name" type="StringName" />
- <description>
- Get the count of a custom signal's arguments.
- </description>
- </method>
- <method name="custom_signal_get_argument_name" qualifiers="const">
- <return type="String" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="argidx" type="int" />
- <description>
- Get the name of a custom signal's argument.
- </description>
- </method>
- <method name="custom_signal_get_argument_type" qualifiers="const">
- <return type="int" enum="Variant.Type" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="argidx" type="int" />
- <description>
- Get the type of a custom signal's argument.
- </description>
- </method>
- <method name="custom_signal_remove_argument">
- <return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="argidx" type="int" />
- <description>
- Remove a specific custom signal's argument.
- </description>
- </method>
- <method name="custom_signal_set_argument_name">
- <return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="argidx" type="int" />
- <argument index="2" name="argname" type="String" />
- <description>
- Rename a custom signal's argument.
- </description>
- </method>
- <method name="custom_signal_set_argument_type">
- <return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="argidx" type="int" />
- <argument index="2" name="type" type="int" enum="Variant.Type" />
- <description>
- Change the type of a custom signal's argument.
- </description>
- </method>
- <method name="custom_signal_swap_argument">
- <return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="argidx" type="int" />
- <argument index="2" name="withidx" type="int" />
- <description>
- Swap two of the arguments of a custom signal.
- </description>
- </method>
- <method name="data_connect">
- <return type="void" />
- <argument index="0" name="from_node" type="int" />
- <argument index="1" name="from_port" type="int" />
- <argument index="2" name="to_node" type="int" />
- <argument index="3" name="to_port" type="int" />
- <description>
- Connect two data ports. The value of [code]from_node[/code]'s [code]from_port[/code] would be fed into [code]to_node[/code]'s [code]to_port[/code].
- </description>
- </method>
- <method name="data_disconnect">
- <return type="void" />
- <argument index="0" name="from_node" type="int" />
- <argument index="1" name="from_port" type="int" />
- <argument index="2" name="to_node" type="int" />
- <argument index="3" name="to_port" type="int" />
- <description>
- Disconnect two data ports previously connected with [method data_connect].
- </description>
- </method>
- <method name="get_function_node_id" qualifiers="const">
- <return type="int" />
- <argument index="0" name="name" type="StringName" />
- <description>
- Returns the id of a function's entry point node.
- </description>
- </method>
- <method name="get_node" qualifiers="const">
- <return type="VisualScriptNode" />
- <argument index="0" name="id" type="int" />
- <description>
- Returns a node given its id.
- </description>
- </method>
- <method name="get_node_position" qualifiers="const">
- <return type="Vector2" />
- <argument index="0" name="id" type="int" />
- <description>
- Returns a node's position in pixels.
- </description>
- </method>
- <method name="get_scroll" qualifiers="const">
- <return type="Vector2" />
- <description>
- Returns the current position of the center of the screen.
- </description>
- </method>
- <method name="get_variable_default_value" qualifiers="const">
- <return type="Variant" />
- <argument index="0" name="name" type="StringName" />
- <description>
- Returns the default (initial) value of a variable.
- </description>
- </method>
- <method name="get_variable_export" qualifiers="const">
- <return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <description>
- Returns whether a variable is exported.
- </description>
- </method>
- <method name="get_variable_info" qualifiers="const">
- <return type="Dictionary" />
- <argument index="0" name="name" type="StringName" />
- <description>
- Returns the information for a given variable as a dictionary. The information includes its name, type, hint and usage.
- </description>
- </method>
- <method name="has_custom_signal" qualifiers="const">
- <return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <description>
- Returns whether a signal exists with the specified name.
- </description>
- </method>
- <method name="has_data_connection" qualifiers="const">
- <return type="bool" />
- <argument index="0" name="from_node" type="int" />
- <argument index="1" name="from_port" type="int" />
- <argument index="2" name="to_node" type="int" />
- <argument index="3" name="to_port" type="int" />
- <description>
- Returns whether the specified data ports are connected.
- </description>
- </method>
- <method name="has_function" qualifiers="const">
- <return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <description>
- Returns whether a function exists with the specified name.
- </description>
- </method>
- <method name="has_node" qualifiers="const">
- <return type="bool" />
- <argument index="0" name="id" type="int" />
- <description>
- Returns whether a node exists with the given id.
- </description>
- </method>
- <method name="has_sequence_connection" qualifiers="const">
- <return type="bool" />
- <argument index="0" name="from_node" type="int" />
- <argument index="1" name="from_output" type="int" />
- <argument index="2" name="to_node" type="int" />
- <description>
- Returns whether the specified sequence ports are connected.
- </description>
- </method>
- <method name="has_variable" qualifiers="const">
- <return type="bool" />
- <argument index="0" name="name" type="StringName" />
- <description>
- Returns whether a variable exists with the specified name.
- </description>
- </method>
- <method name="remove_custom_signal">
- <return type="void" />
- <argument index="0" name="name" type="StringName" />
- <description>
- Remove a custom signal with the given name.
- </description>
- </method>
- <method name="remove_function">
- <return type="void" />
- <argument index="0" name="name" type="StringName" />
- <description>
- Remove a specific function and its nodes from the script.
- </description>
- </method>
- <method name="remove_node">
- <return type="void" />
- <argument index="0" name="id" type="int" />
- <description>
- Remove the node with the specified id.
- </description>
- </method>
- <method name="remove_variable">
- <return type="void" />
- <argument index="0" name="name" type="StringName" />
- <description>
- Remove a variable with the given name.
- </description>
- </method>
- <method name="rename_custom_signal">
- <return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="new_name" type="StringName" />
- <description>
- Change the name of a custom signal.
- </description>
- </method>
- <method name="rename_function">
- <return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="new_name" type="StringName" />
- <description>
- Change the name of a function.
- </description>
- </method>
- <method name="rename_variable">
- <return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="new_name" type="StringName" />
- <description>
- Change the name of a variable.
- </description>
- </method>
- <method name="sequence_connect">
- <return type="void" />
- <argument index="0" name="from_node" type="int" />
- <argument index="1" name="from_output" type="int" />
- <argument index="2" name="to_node" type="int" />
- <description>
- Connect two sequence ports. The execution will flow from of [code]from_node[/code]'s [code]from_output[/code] into [code]to_node[/code].
- Unlike [method data_connect], there isn't a [code]to_port[/code], since the target node can have only one sequence port.
- </description>
- </method>
- <method name="sequence_disconnect">
- <return type="void" />
- <argument index="0" name="from_node" type="int" />
- <argument index="1" name="from_output" type="int" />
- <argument index="2" name="to_node" type="int" />
- <description>
- Disconnect two sequence ports previously connected with [method sequence_connect].
- </description>
- </method>
- <method name="set_instance_base_type">
- <return type="void" />
- <argument index="0" name="type" type="StringName" />
- <description>
- Set the base type of the script.
- </description>
- </method>
- <method name="set_node_position">
- <return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="position" type="Vector2" />
- <description>
- Set the node position in the VisualScript graph.
- </description>
- </method>
- <method name="set_scroll">
- <return type="void" />
- <argument index="0" name="offset" type="Vector2" />
- <description>
- Set the screen center to the given position.
- </description>
- </method>
- <method name="set_variable_default_value">
- <return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="value" type="Variant" />
- <description>
- Change the default (initial) value of a variable.
- </description>
- </method>
- <method name="set_variable_export">
- <return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="enable" type="bool" />
- <description>
- Change whether a variable is exported.
- </description>
- </method>
- <method name="set_variable_info">
- <return type="void" />
- <argument index="0" name="name" type="StringName" />
- <argument index="1" name="value" type="Dictionary" />
- <description>
- Set a variable's info, using the same format as [method get_variable_info].
- </description>
- </method>
- </methods>
- <signals>
- <signal name="node_ports_changed">
- <argument index="0" name="id" type="int" />
- <description>
- Emitted when the ports of a node are changed.
- </description>
- </signal>
- </signals>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml b/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml
deleted file mode 100644
index 0ed66f44e1..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptBasicTypeConstant" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node representing a constant from the base types.
- </brief_description>
- <description>
- A Visual Script node representing a constant from base types, such as [constant Vector3.AXIS_X].
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type" default="0">
- The type to get the constant from.
- </member>
- <member name="constant" type="StringName" setter="set_basic_type_constant" getter="get_basic_type_constant">
- The name of the constant to return.
- </member>
- </members>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
deleted file mode 100644
index 647b627d25..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
+++ /dev/null
@@ -1,221 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptBuiltinFunc" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node used to call built-in functions.
- </brief_description>
- <description>
- A built-in function used inside a [VisualScript]. It is usually a math function or an utility function.
- See also [@GDScript], for the same functions in the GDScript language.
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="function" type="int" setter="set_func" getter="get_func" enum="VisualScriptBuiltinFunc.BuiltinFunc" default="0">
- The function to be executed.
- </member>
- </members>
- <constants>
- <constant name="MATH_SIN" value="0" enum="BuiltinFunc">
- Returns the sine of the input.
- </constant>
- <constant name="MATH_COS" value="1" enum="BuiltinFunc">
- Returns the cosine of the input.
- </constant>
- <constant name="MATH_TAN" value="2" enum="BuiltinFunc">
- Returns the tangent of the input.
- </constant>
- <constant name="MATH_SINH" value="3" enum="BuiltinFunc">
- Returns the hyperbolic sine of the input.
- </constant>
- <constant name="MATH_COSH" value="4" enum="BuiltinFunc">
- Returns the hyperbolic cosine of the input.
- </constant>
- <constant name="MATH_TANH" value="5" enum="BuiltinFunc">
- Returns the hyperbolic tangent of the input.
- </constant>
- <constant name="MATH_ASIN" value="6" enum="BuiltinFunc">
- Returns the arc sine of the input.
- </constant>
- <constant name="MATH_ACOS" value="7" enum="BuiltinFunc">
- Returns the arc cosine of the input.
- </constant>
- <constant name="MATH_ATAN" value="8" enum="BuiltinFunc">
- Returns the arc tangent of the input.
- </constant>
- <constant name="MATH_ATAN2" value="9" enum="BuiltinFunc">
- Returns the arc tangent of the input, using the signs of both parameters to determine the exact angle.
- </constant>
- <constant name="MATH_SQRT" value="10" enum="BuiltinFunc">
- Returns the square root of the input.
- </constant>
- <constant name="MATH_FMOD" value="11" enum="BuiltinFunc">
- Returns the remainder of one input divided by the other, using floating-point numbers.
- </constant>
- <constant name="MATH_FPOSMOD" value="12" enum="BuiltinFunc">
- Returns the positive remainder of one input divided by the other, using floating-point numbers.
- </constant>
- <constant name="MATH_FLOOR" value="13" enum="BuiltinFunc">
- Returns the input rounded down.
- </constant>
- <constant name="MATH_CEIL" value="14" enum="BuiltinFunc">
- Returns the input rounded up.
- </constant>
- <constant name="MATH_ROUND" value="15" enum="BuiltinFunc">
- Returns the input rounded to the nearest integer.
- </constant>
- <constant name="MATH_ABS" value="16" enum="BuiltinFunc">
- Returns the absolute value of the input.
- </constant>
- <constant name="MATH_SIGN" value="17" enum="BuiltinFunc">
- Returns the sign of the input, turning it into 1, -1, or 0. Useful to determine if the input is positive or negative.
- </constant>
- <constant name="MATH_POW" value="18" enum="BuiltinFunc">
- Returns the input raised to a given power.
- </constant>
- <constant name="MATH_LOG" value="19" enum="BuiltinFunc">
- Returns the natural logarithm of the input. Note that this is not the typical base-10 logarithm function calculators use.
- </constant>
- <constant name="MATH_EXP" value="20" enum="BuiltinFunc">
- Returns the mathematical constant [b]e[/b] raised to the specified power of the input. [b]e[/b] has an approximate value of 2.71828.
- </constant>
- <constant name="MATH_ISNAN" value="21" enum="BuiltinFunc">
- Returns whether the input is NaN (Not a Number) or not. NaN is usually produced by dividing 0 by 0, though other ways exist.
- </constant>
- <constant name="MATH_ISINF" value="22" enum="BuiltinFunc">
- Returns whether the input is an infinite floating-point number or not. Infinity is usually produced by dividing a number by 0, though other ways exist.
- </constant>
- <constant name="MATH_EASE" value="23" enum="BuiltinFunc">
- Easing function, based on exponent. 0 is constant, 1 is linear, 0 to 1 is ease-in, 1+ is ease out. Negative values are in-out/out in.
- </constant>
- <constant name="MATH_STEP_DECIMALS" value="24" enum="BuiltinFunc">
- Returns the number of digit places after the decimal that the first non-zero digit occurs.
- </constant>
- <constant name="MATH_SNAPPED" value="25" enum="BuiltinFunc">
- Returns the input snapped to a given step.
- </constant>
- <constant name="MATH_LERP" value="26" enum="BuiltinFunc">
- Returns a number linearly interpolated between the first two inputs, based on the third input. Uses the formula [code]a + (a - b) * t[/code].
- </constant>
- <constant name="MATH_CUBIC_INTERPOLATE" value="27" enum="BuiltinFunc">
- </constant>
- <constant name="MATH_INVERSE_LERP" value="28" enum="BuiltinFunc">
- </constant>
- <constant name="MATH_RANGE_LERP" value="29" enum="BuiltinFunc">
- </constant>
- <constant name="MATH_MOVE_TOWARD" value="30" enum="BuiltinFunc">
- Moves the number toward a value, based on the third input.
- </constant>
- <constant name="MATH_RANDOMIZE" value="31" enum="BuiltinFunc">
- Randomize the seed (or the internal state) of the random number generator. Current implementation reseeds using a number based on time.
- </constant>
- <constant name="MATH_RANDI" value="32" enum="BuiltinFunc">
- Returns a random 32 bits integer value. To obtain a random value between 0 to N (where N is smaller than 2^32 - 1), you can use it with the remainder function.
- </constant>
- <constant name="MATH_RANDF" value="33" enum="BuiltinFunc">
- Returns a random floating-point value between 0 and 1. To obtain a random value between 0 to N, you can use it with multiplication.
- </constant>
- <constant name="MATH_RANDI_RANGE" value="34" enum="BuiltinFunc">
- Returns a random 32-bit integer value between the two inputs.
- </constant>
- <constant name="MATH_RANDF_RANGE" value="35" enum="BuiltinFunc">
- Returns a random floating-point value between the two inputs.
- </constant>
- <constant name="MATH_RANDFN" value="36" enum="BuiltinFunc">
- Returns a normally-distributed pseudo-random number, using Box-Muller transform with the specified mean and a standard deviation. This is also called Gaussian distribution.
- </constant>
- <constant name="MATH_SEED" value="37" enum="BuiltinFunc">
- Set the seed for the random number generator.
- </constant>
- <constant name="MATH_RANDSEED" value="38" enum="BuiltinFunc">
- Returns a random value from the given seed, along with the new seed.
- </constant>
- <constant name="MATH_DEG2RAD" value="39" enum="BuiltinFunc">
- Convert the input from degrees to radians.
- </constant>
- <constant name="MATH_RAD2DEG" value="40" enum="BuiltinFunc">
- Convert the input from radians to degrees.
- </constant>
- <constant name="MATH_LINEAR2DB" value="41" enum="BuiltinFunc">
- Convert the input from linear volume to decibel volume.
- </constant>
- <constant name="MATH_DB2LINEAR" value="42" enum="BuiltinFunc">
- Convert the input from decibel volume to linear volume.
- </constant>
- <constant name="MATH_WRAP" value="43" enum="BuiltinFunc">
- </constant>
- <constant name="MATH_WRAPF" value="44" enum="BuiltinFunc">
- </constant>
- <constant name="MATH_PINGPONG" value="45" enum="BuiltinFunc">
- Returns the [code]value[/code] wrapped between [code]0[/code] and the [code]length[/code]. If the limit is reached, the next value the function returned is decreased to the [code]0[/code] side or increased to the [code]length[/code] side (like a triangle wave). If [code]length[/code] is less than zero, it becomes positive.
- </constant>
- <constant name="LOGIC_MAX" value="46" enum="BuiltinFunc">
- Returns the greater of the two numbers, also known as their maximum.
- </constant>
- <constant name="LOGIC_MIN" value="47" enum="BuiltinFunc">
- Returns the lesser of the two numbers, also known as their minimum.
- </constant>
- <constant name="LOGIC_CLAMP" value="48" enum="BuiltinFunc">
- Returns the input clamped inside the given range, ensuring the result is never outside it. Equivalent to [code]min(max(input, range_low), range_high)[/code].
- </constant>
- <constant name="LOGIC_NEAREST_PO2" value="49" enum="BuiltinFunc">
- Returns the nearest power of 2 to the input.
- </constant>
- <constant name="OBJ_WEAKREF" value="50" enum="BuiltinFunc">
- Create a [WeakRef] from the input.
- </constant>
- <constant name="TYPE_CONVERT" value="51" enum="BuiltinFunc">
- Convert between types.
- </constant>
- <constant name="TYPE_OF" value="52" enum="BuiltinFunc">
- Returns the type of the input as an integer. Check [enum Variant.Type] for the integers that might be returned.
- </constant>
- <constant name="TYPE_EXISTS" value="53" enum="BuiltinFunc">
- Checks if a type is registered in the [ClassDB].
- </constant>
- <constant name="TEXT_CHAR" value="54" enum="BuiltinFunc">
- Returns a character with the given ascii value.
- </constant>
- <constant name="TEXT_STR" value="55" enum="BuiltinFunc">
- Convert the input to a string.
- </constant>
- <constant name="TEXT_PRINT" value="56" enum="BuiltinFunc">
- Print the given string to the output window.
- </constant>
- <constant name="TEXT_PRINTERR" value="57" enum="BuiltinFunc">
- Print the given string to the standard error output.
- </constant>
- <constant name="TEXT_PRINTRAW" value="58" enum="BuiltinFunc">
- Print the given string to the standard output, without adding a newline.
- </constant>
- <constant name="TEXT_PRINT_VERBOSE" value="59" enum="BuiltinFunc">
- </constant>
- <constant name="VAR_TO_STR" value="60" enum="BuiltinFunc">
- Serialize a [Variant] to a string.
- </constant>
- <constant name="STR_TO_VAR" value="61" enum="BuiltinFunc">
- Deserialize a [Variant] from a string serialized using [constant VAR_TO_STR].
- </constant>
- <constant name="VAR_TO_BYTES" value="62" enum="BuiltinFunc">
- Serialize a [Variant] to a [PackedByteArray].
- </constant>
- <constant name="BYTES_TO_VAR" value="63" enum="BuiltinFunc">
- Deserialize a [Variant] from a [PackedByteArray] serialized using [constant VAR_TO_BYTES].
- </constant>
- <constant name="MATH_SMOOTHSTEP" value="64" enum="BuiltinFunc">
- Returns a number smoothly interpolated between the first two inputs, based on the third input. Similar to [constant MATH_LERP], but interpolates faster at the beginning and slower at the end. Using Hermite interpolation formula:
- [codeblock]
- var t = clamp((weight - from) / (to - from), 0.0, 1.0)
- return t * t * (3.0 - 2.0 * t)
- [/codeblock]
- </constant>
- <constant name="MATH_POSMOD" value="65" enum="BuiltinFunc">
- </constant>
- <constant name="MATH_LERP_ANGLE" value="66" enum="BuiltinFunc">
- </constant>
- <constant name="TEXT_ORD" value="67" enum="BuiltinFunc">
- </constant>
- <constant name="FUNC_MAX" value="68" enum="BuiltinFunc">
- Represents the size of the [enum BuiltinFunc] enum.
- </constant>
- </constants>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml b/modules/visual_script/doc_classes/VisualScriptClassConstant.xml
deleted file mode 100644
index 2509084f0e..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptClassConstant" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Gets a constant from a given class.
- </brief_description>
- <description>
- This node returns a constant from a given class, such as [constant TYPE_INT]. See the given class' documentation for available constants.
- [b]Input Ports:[/b]
- none
- [b]Output Ports:[/b]
- - Data (variant): [code]value[/code]
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&amp;&quot;Object&quot;">
- The constant's parent class.
- </member>
- <member name="constant" type="StringName" setter="set_class_constant" getter="get_class_constant" default="&amp;&quot;&quot;">
- The constant to return. See the given class for its available constants.
- </member>
- </members>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptComment.xml b/modules/visual_script/doc_classes/VisualScriptComment.xml
deleted file mode 100644
index cf4b57ca19..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptComment.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptComment" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node used to annotate the script.
- </brief_description>
- <description>
- A Visual Script node used to display annotations in the script, so that code may be documented.
- Comment nodes can be resized so they encompass a group of nodes.
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="description" type="String" setter="set_description" getter="get_description" default="&quot;&quot;">
- The text inside the comment node.
- </member>
- <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2(150, 150)">
- The comment node's size (in pixels).
- </member>
- <member name="title" type="String" setter="set_title" getter="get_title" default="&quot;Comment&quot;">
- The comment node's title.
- </member>
- </members>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptComposeArray.xml b/modules/visual_script/doc_classes/VisualScriptComposeArray.xml
deleted file mode 100644
index ea73867c4b..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptComposeArray.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptComposeArray" inherits="VisualScriptLists" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script Node used to create array from a list of items.
- </brief_description>
- <description>
- A Visual Script Node used to compose array from the list of elements provided with custom in-graph UI hard coded in the VisualScript Editor.
- </description>
- <tutorials>
- </tutorials>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptCondition.xml b/modules/visual_script/doc_classes/VisualScriptCondition.xml
deleted file mode 100644
index a29388569f..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptCondition.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptCondition" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node which branches the flow.
- </brief_description>
- <description>
- A Visual Script node that checks a [bool] input port. If [code]true[/code], it will exit via the "true" sequence port. If [code]false[/code], it will exit via the "false" sequence port. After exiting either, it exits via the "done" port. Sequence ports may be left disconnected.
- [b]Input Ports:[/b]
- - Sequence: [code]if (cond) is[/code]
- - Data (boolean): [code]cond[/code]
- [b]Output Ports:[/b]
- - Sequence: [code]true[/code]
- - Sequence: [code]false[/code]
- - Sequence: [code]done[/code]
- </description>
- <tutorials>
- </tutorials>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptConstant.xml b/modules/visual_script/doc_classes/VisualScriptConstant.xml
deleted file mode 100644
index 645ede9001..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptConstant.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptConstant" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Gets a contant's value.
- </brief_description>
- <description>
- This node returns a constant's value.
- [b]Input Ports:[/b]
- none
- [b]Output Ports:[/b]
- - Data (variant): [code]get[/code]
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="type" type="int" setter="set_constant_type" getter="get_constant_type" enum="Variant.Type" default="0">
- The constant's type.
- </member>
- <member name="value" type="Variant" setter="set_constant_value" getter="get_constant_value">
- The constant's value.
- </member>
- </members>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptConstructor.xml b/modules/visual_script/doc_classes/VisualScriptConstructor.xml
deleted file mode 100644
index 5ec17350bd..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptConstructor.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptConstructor" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node which calls a base type constructor.
- </brief_description>
- <description>
- A Visual Script node which calls a base type constructor. It can be used for type conversion as well.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_constructor" qualifiers="const">
- <return type="Dictionary" />
- <description>
- </description>
- </method>
- <method name="get_constructor_type" qualifiers="const">
- <return type="int" enum="Variant.Type" />
- <description>
- </description>
- </method>
- <method name="set_constructor">
- <return type="void" />
- <argument index="0" name="constructor" type="Dictionary" />
- <description>
- </description>
- </method>
- <method name="set_constructor_type">
- <return type="void" />
- <argument index="0" name="type" type="int" enum="Variant.Type" />
- <description>
- </description>
- </method>
- </methods>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptCustomNode.xml b/modules/visual_script/doc_classes/VisualScriptCustomNode.xml
deleted file mode 100644
index 97b89fb987..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptCustomNode.xml
+++ /dev/null
@@ -1,166 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptCustomNode" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A scripted Visual Script node.
- </brief_description>
- <description>
- A custom Visual Script node which can be scripted in powerful ways.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="_get_caption" qualifiers="virtual const">
- <return type="String" />
- <description>
- Returns the node's title.
- </description>
- </method>
- <method name="_get_category" qualifiers="virtual const">
- <return type="String" />
- <description>
- Returns the node's category.
- </description>
- </method>
- <method name="_get_input_value_port_count" qualifiers="virtual const">
- <return type="int" />
- <description>
- Returns the count of input value ports.
- </description>
- </method>
- <method name="_get_input_value_port_hint" qualifiers="virtual const">
- <return type="int" />
- <argument index="0" name="input_idx" type="int" />
- <description>
- Returns the specified input port's hint. See the [enum @GlobalScope.PropertyHint] hints.
- </description>
- </method>
- <method name="_get_input_value_port_hint_string" qualifiers="virtual const">
- <return type="String" />
- <argument index="0" name="input_idx" type="int" />
- <description>
- Returns the specified input port's hint string.
- </description>
- </method>
- <method name="_get_input_value_port_name" qualifiers="virtual const">
- <return type="String" />
- <argument index="0" name="input_idx" type="int" />
- <description>
- Returns the specified input port's name.
- </description>
- </method>
- <method name="_get_input_value_port_type" qualifiers="virtual const">
- <return type="int" />
- <argument index="0" name="input_idx" type="int" />
- <description>
- Returns the specified input port's type. See the [enum Variant.Type] values.
- </description>
- </method>
- <method name="_get_output_sequence_port_count" qualifiers="virtual const">
- <return type="int" />
- <description>
- Returns the amount of output [b]sequence[/b] ports.
- </description>
- </method>
- <method name="_get_output_sequence_port_text" qualifiers="virtual const">
- <return type="String" />
- <argument index="0" name="seq_idx" type="int" />
- <description>
- Returns the specified [b]sequence[/b] output's name.
- </description>
- </method>
- <method name="_get_output_value_port_count" qualifiers="virtual const">
- <return type="int" />
- <description>
- Returns the amount of output value ports.
- </description>
- </method>
- <method name="_get_output_value_port_hint" qualifiers="virtual const">
- <return type="int" />
- <argument index="0" name="output_idx" type="int" />
- <description>
- Returns the specified output port's hint. See the [enum @GlobalScope.PropertyHint] hints.
- </description>
- </method>
- <method name="_get_output_value_port_hint_string" qualifiers="virtual const">
- <return type="String" />
- <argument index="0" name="output_idx" type="int" />
- <description>
- Returns the specified output port's hint string.
- </description>
- </method>
- <method name="_get_output_value_port_name" qualifiers="virtual const">
- <return type="String" />
- <argument index="0" name="output_idx" type="int" />
- <description>
- Returns the specified output port's name.
- </description>
- </method>
- <method name="_get_output_value_port_type" qualifiers="virtual const">
- <return type="int" />
- <argument index="0" name="output_idx" type="int" />
- <description>
- Returns the specified output port's type. See the [enum Variant.Type] values.
- </description>
- </method>
- <method name="_get_text" qualifiers="virtual const">
- <return type="String" />
- <description>
- Returns the custom node's text, which is shown right next to the input [b]sequence[/b] port (if there is none, on the place that is usually taken by it).
- </description>
- </method>
- <method name="_get_working_memory_size" qualifiers="virtual const">
- <return type="int" />
- <description>
- Returns the size of the custom node's working memory. See [method _step] for more details.
- </description>
- </method>
- <method name="_has_input_sequence_port" qualifiers="virtual const">
- <return type="bool" />
- <description>
- Returns whether the custom node has an input [b]sequence[/b] port.
- </description>
- </method>
- <method name="_step" qualifiers="virtual const">
- <return type="Variant" />
- <argument index="0" name="inputs" type="Array" />
- <argument index="1" name="outputs" type="Array" />
- <argument index="2" name="start_mode" type="int" />
- <argument index="3" name="working_mem" type="Array" />
- <description>
- Execute the custom node's logic, returning the index of the output sequence port to use or a [String] when there is an error.
- The [code]inputs[/code] array contains the values of the input ports.
- [code]outputs[/code] is an array whose indices should be set to the respective outputs.
- The [code]start_mode[/code] is usually [constant START_MODE_BEGIN_SEQUENCE], unless you have used the [code]STEP_*[/code] constants.
- [code]working_mem[/code] is an array which can be used to persist information between runs of the custom node. The size needs to be predefined using [method _get_working_memory_size].
- When returning, you can mask the returned value with one of the [code]STEP_*[/code] constants.
- </description>
- </method>
- </methods>
- <constants>
- <constant name="START_MODE_BEGIN_SEQUENCE" value="0" enum="StartMode">
- The start mode used the first time when [method _step] is called.
- </constant>
- <constant name="START_MODE_CONTINUE_SEQUENCE" value="1" enum="StartMode">
- The start mode used when [method _step] is called after coming back from a [constant STEP_PUSH_STACK_BIT].
- </constant>
- <constant name="START_MODE_RESUME_YIELD" value="2" enum="StartMode">
- The start mode used when [method _step] is called after resuming from [constant STEP_YIELD_BIT].
- </constant>
- <constant name="STEP_PUSH_STACK_BIT" value="16777216">
- Hint used by [method _step] to tell that control should return to it when there is no other node left to execute.
- This is used by [VisualScriptCondition] to redirect the sequence to the "Done" port after the [code]true[/code]/[code]false[/code] branch has finished execution.
- </constant>
- <constant name="STEP_GO_BACK_BIT" value="33554432">
- Hint used by [method _step] to tell that control should return back, either hitting a previous [constant STEP_PUSH_STACK_BIT] or exiting the function.
- </constant>
- <constant name="STEP_NO_ADVANCE_BIT" value="67108864">
- </constant>
- <constant name="STEP_EXIT_FUNCTION_BIT" value="134217728">
- Hint used by [method _step] to tell that control should stop and exit the function.
- </constant>
- <constant name="STEP_YIELD_BIT" value="268435456">
- Hint used by [method _step] to tell that the function should be yielded.
- Using this requires you to have at least one working memory slot, which is used for the [VisualScriptFunctionState].
- </constant>
- </constants>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptCustomNodes.xml b/modules/visual_script/doc_classes/VisualScriptCustomNodes.xml
deleted file mode 100644
index f04c862174..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptCustomNodes.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptCustomNodes" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Manages custom nodes for the Visual Script editor.
- </brief_description>
- <description>
- This singleton can be used to manage (i.e., add or remove) custom nodes for the Visual Script editor.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="add_custom_node">
- <return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="category" type="String" />
- <argument index="2" name="script" type="Script" />
- <description>
- Add a custom Visual Script node to the editor. It'll be placed under "Custom Nodes" with the [code]category[/code] as the parameter.
- </description>
- </method>
- <method name="remove_custom_node">
- <return type="void" />
- <argument index="0" name="name" type="String" />
- <argument index="1" name="category" type="String" />
- <description>
- Remove a custom Visual Script node from the editor. Custom nodes already placed on scripts won't be removed.
- </description>
- </method>
- </methods>
- <signals>
- <signal name="custom_nodes_updated">
- <description>
- Emitted when a custom Visual Script node is added or removed.
- </description>
- </signal>
- </signals>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml b/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml
deleted file mode 100644
index b544fd9d90..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptDeconstruct" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node which deconstructs a base type instance into its parts.
- </brief_description>
- <description>
- A Visual Script node which deconstructs a base type instance into its parts.
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="type" type="int" setter="set_deconstruct_type" getter="get_deconstruct_type" enum="Variant.Type" default="0">
- The type to deconstruct.
- </member>
- </members>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml b/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml
deleted file mode 100644
index c0cefa0ab7..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptEmitSignal" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Emits a specified signal.
- </brief_description>
- <description>
- Emits a specified signal when it is executed.
- [b]Input Ports:[/b]
- - Sequence: [code]emit[/code]
- [b]Output Ports:[/b]
- - Sequence
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="signal" type="StringName" setter="set_signal" getter="get_signal" default="&amp;&quot;&quot;">
- The signal to emit.
- </member>
- </members>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml b/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml
deleted file mode 100644
index f60a048845..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptEngineSingleton" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node returning a singleton from [@GlobalScope].
- </brief_description>
- <description>
- A Visual Script node returning a singleton from [@GlobalScope].
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="constant" type="String" setter="set_singleton" getter="get_singleton" default="&quot;&quot;">
- The singleton's name.
- </member>
- </members>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptExpression.xml b/modules/visual_script/doc_classes/VisualScriptExpression.xml
deleted file mode 100644
index 14750e7c8d..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptExpression.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptExpression" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node that can execute a custom expression.
- </brief_description>
- <description>
- A Visual Script node that can execute a custom expression. Values can be provided for the input and the expression result can be retrieved from the output.
- </description>
- <tutorials>
- </tutorials>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptFunction.xml b/modules/visual_script/doc_classes/VisualScriptFunction.xml
deleted file mode 100644
index 74d9f194eb..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptFunction.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptFunction" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node representing a function.
- </brief_description>
- <description>
- [VisualScriptFunction] represents a function header. It is the starting point for the function body and can be used to tweak the function's properties (e.g. RPC mode).
- </description>
- <tutorials>
- </tutorials>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml b/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
deleted file mode 100644
index 543263ff8e..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptFunctionCall" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node for calling a function.
- </brief_description>
- <description>
- [VisualScriptFunctionCall] is created when you add or drag and drop a function onto the Visual Script graph. It allows to tweak parameters of the call, e.g. what object the function is called on.
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="base_script" type="String" setter="set_base_script" getter="get_base_script">
- The script to be used when [member call_mode] is set to [constant CALL_MODE_INSTANCE].
- </member>
- <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&amp;&quot;Object&quot;">
- The base type to be used when [member call_mode] is set to [constant CALL_MODE_INSTANCE].
- </member>
- <member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type">
- The type to be used when [member call_mode] is set to [constant CALL_MODE_BASIC_TYPE].
- </member>
- <member name="call_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptFunctionCall.CallMode" default="0">
- [code]call_mode[/code] determines the target object on which the method will be called. See [enum CallMode] for options.
- </member>
- <member name="function" type="StringName" setter="set_function" getter="get_function" default="&amp;&quot;&quot;">
- The name of the function to be called.
- </member>
- <member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path">
- The node path to use when [member call_mode] is set to [constant CALL_MODE_NODE_PATH].
- </member>
- <member name="rpc_call_mode" type="int" setter="set_rpc_call_mode" getter="get_rpc_call_mode" enum="VisualScriptFunctionCall.RPCCallMode" default="0">
- The mode for RPC calls. See [method Node.rpc] for more details and [enum RPCCallMode] for available options.
- </member>
- <member name="singleton" type="StringName" setter="set_singleton" getter="get_singleton">
- The singleton to call the method on. Used when [member call_mode] is set to [constant CALL_MODE_SINGLETON].
- </member>
- <member name="use_default_args" type="int" setter="set_use_default_args" getter="get_use_default_args">
- Number of default arguments that will be used when calling the function. Can't be higher than the number of available default arguments in the method's declaration.
- </member>
- <member name="validate" type="bool" setter="set_validate" getter="get_validate" default="true">
- If [code]false[/code], call errors (e.g. wrong number of arguments) will be ignored.
- </member>
- </members>
- <constants>
- <constant name="CALL_MODE_SELF" value="0" enum="CallMode">
- The method will be called on this [Object].
- </constant>
- <constant name="CALL_MODE_NODE_PATH" value="1" enum="CallMode">
- The method will be called on the given [Node] in the scene tree.
- </constant>
- <constant name="CALL_MODE_INSTANCE" value="2" enum="CallMode">
- The method will be called on an instanced node with the given type and script.
- </constant>
- <constant name="CALL_MODE_BASIC_TYPE" value="3" enum="CallMode">
- The method will be called on a GDScript basic type (e.g. [Vector2]).
- </constant>
- <constant name="CALL_MODE_SINGLETON" value="4" enum="CallMode">
- The method will be called on a singleton.
- </constant>
- <constant name="RPC_DISABLED" value="0" enum="RPCCallMode">
- The method will be called locally.
- </constant>
- <constant name="RPC_RELIABLE" value="1" enum="RPCCallMode">
- The method will be called remotely.
- </constant>
- <constant name="RPC_UNRELIABLE" value="2" enum="RPCCallMode">
- The method will be called remotely using an unreliable protocol.
- </constant>
- <constant name="RPC_RELIABLE_TO_ID" value="3" enum="RPCCallMode">
- The method will be called remotely for the given peer.
- </constant>
- <constant name="RPC_UNRELIABLE_TO_ID" value="4" enum="RPCCallMode">
- The method will be called remotely for the given peer, using an unreliable protocol.
- </constant>
- </constants>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml b/modules/visual_script/doc_classes/VisualScriptFunctionState.xml
deleted file mode 100644
index ef09c9d4a0..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptFunctionState" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node representing a function state.
- </brief_description>
- <description>
- [VisualScriptFunctionState] is returned from [VisualScriptYield] and can be used to resume a paused function call.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="connect_to_signal">
- <return type="void" />
- <argument index="0" name="obj" type="Object" />
- <argument index="1" name="signals" type="String" />
- <argument index="2" name="args" type="Array" />
- <description>
- Connects this [VisualScriptFunctionState] to a signal in the given object to automatically resume when it's emitted.
- </description>
- </method>
- <method name="is_valid" qualifiers="const">
- <return type="bool" />
- <description>
- Returns whether the function state is valid.
- </description>
- </method>
- <method name="resume">
- <return type="Variant" />
- <argument index="0" name="args" type="Array" default="[]" />
- <description>
- Resumes the function to run from the point it was yielded.
- </description>
- </method>
- </methods>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml b/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml
deleted file mode 100644
index 42ada99257..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptGlobalConstant" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node returning a constant from [@GlobalScope].
- </brief_description>
- <description>
- A Visual Script node returning a constant from [@GlobalScope].
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="constant" type="int" setter="set_global_constant" getter="get_global_constant" default="0">
- The constant to be used.
- </member>
- </members>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptIndexGet.xml b/modules/visual_script/doc_classes/VisualScriptIndexGet.xml
deleted file mode 100644
index 8828bf9039..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptIndexGet.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptIndexGet" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node for getting a value from an array or a dictionary.
- </brief_description>
- <description>
- [VisualScriptIndexGet] will return the value stored in an array or a dictionary under the given index.
- </description>
- <tutorials>
- </tutorials>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptIndexSet.xml b/modules/visual_script/doc_classes/VisualScriptIndexSet.xml
deleted file mode 100644
index 5c81dcd339..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptIndexSet.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptIndexSet" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node for setting a value in an array or a dictionary.
- </brief_description>
- <description>
- [VisualScriptIndexSet] will set the value stored in an array or a dictionary under the given index to the provided new value.
- </description>
- <tutorials>
- </tutorials>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptInputAction.xml b/modules/visual_script/doc_classes/VisualScriptInputAction.xml
deleted file mode 100644
index 51c2eaf353..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptInputAction.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptInputAction" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node returning a state of an action.
- </brief_description>
- <description>
- [VisualScriptInputAction] can be used to check if an action is pressed or released.
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="action" type="StringName" setter="set_action_name" getter="get_action_name" default="&amp;&quot;&quot;">
- Name of the action.
- </member>
- <member name="mode" type="int" setter="set_action_mode" getter="get_action_mode" enum="VisualScriptInputAction.Mode" default="0">
- State of the action to check. See [enum Mode] for options.
- </member>
- </members>
- <constants>
- <constant name="MODE_PRESSED" value="0" enum="Mode">
- [code]True[/code] if action is pressed.
- </constant>
- <constant name="MODE_RELEASED" value="1" enum="Mode">
- [code]True[/code] if action is released (i.e. not pressed).
- </constant>
- <constant name="MODE_JUST_PRESSED" value="2" enum="Mode">
- [code]True[/code] on the frame the action was pressed.
- </constant>
- <constant name="MODE_JUST_RELEASED" value="3" enum="Mode">
- [code]True[/code] on the frame the action was released.
- </constant>
- </constants>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptIterator.xml b/modules/visual_script/doc_classes/VisualScriptIterator.xml
deleted file mode 100644
index ef6846deba..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptIterator.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptIterator" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Steps through items in a given input.
- </brief_description>
- <description>
- This node steps through each item in a given input. Input can be any sequence data type, such as an [Array] or [String]. When each item has been processed, execution passed out the [code]exit[/code] Sequence port.
- [b]Input Ports:[/b]
- - Sequence: [code]for (elem) in (input)[/code]
- - Data (variant): [code]input[/code]
- [b]Output Ports:[/b]
- - Sequence: [code]each[/code]
- - Sequence: [code]exit[/code]
- - Data (variant): [code]elem[/code]
- </description>
- <tutorials>
- </tutorials>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptLists.xml b/modules/visual_script/doc_classes/VisualScriptLists.xml
deleted file mode 100644
index 27a81fce2f..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptLists.xml
+++ /dev/null
@@ -1,77 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptLists" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script virtual class for in-graph editable nodes.
- </brief_description>
- <description>
- A Visual Script virtual class that defines the shape and the default behavior of the nodes that have to be in-graph editable nodes.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="add_input_data_port">
- <return type="void" />
- <argument index="0" name="type" type="int" enum="Variant.Type" />
- <argument index="1" name="name" type="String" />
- <argument index="2" name="index" type="int" />
- <description>
- Adds an input port to the Visual Script node.
- </description>
- </method>
- <method name="add_output_data_port">
- <return type="void" />
- <argument index="0" name="type" type="int" enum="Variant.Type" />
- <argument index="1" name="name" type="String" />
- <argument index="2" name="index" type="int" />
- <description>
- Adds an output port to the Visual Script node.
- </description>
- </method>
- <method name="remove_input_data_port">
- <return type="void" />
- <argument index="0" name="index" type="int" />
- <description>
- Removes an input port from the Visual Script node.
- </description>
- </method>
- <method name="remove_output_data_port">
- <return type="void" />
- <argument index="0" name="index" type="int" />
- <description>
- Removes an output port from the Visual Script node.
- </description>
- </method>
- <method name="set_input_data_port_name">
- <return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="name" type="String" />
- <description>
- Sets the name of an input port.
- </description>
- </method>
- <method name="set_input_data_port_type">
- <return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="type" type="int" enum="Variant.Type" />
- <description>
- Sets the type of an input port.
- </description>
- </method>
- <method name="set_output_data_port_name">
- <return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="name" type="String" />
- <description>
- Sets the name of an output port.
- </description>
- </method>
- <method name="set_output_data_port_type">
- <return type="void" />
- <argument index="0" name="index" type="int" />
- <argument index="1" name="type" type="int" enum="Variant.Type" />
- <description>
- Sets the type of an output port.
- </description>
- </method>
- </methods>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml b/modules/visual_script/doc_classes/VisualScriptLocalVar.xml
deleted file mode 100644
index dbf9049f0a..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptLocalVar" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Gets a local variable's value.
- </brief_description>
- <description>
- Returns a local variable's value. "Var Name" must be supplied, with an optional type.
- [b]Input Ports:[/b]
- none
- [b]Output Ports:[/b]
- - Data (variant): [code]get[/code]
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="type" type="int" setter="set_var_type" getter="get_var_type" enum="Variant.Type" default="0">
- The local variable's type.
- </member>
- <member name="var_name" type="StringName" setter="set_var_name" getter="get_var_name" default="&amp;&quot;new_local&quot;">
- The local variable's name.
- </member>
- </members>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml b/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml
deleted file mode 100644
index 1ae4e20f97..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptLocalVarSet" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Changes a local variable's value.
- </brief_description>
- <description>
- Changes a local variable's value to the given input. The new value is also provided on an output Data port.
- [b]Input Ports:[/b]
- - Sequence
- - Data (variant): [code]set[/code]
- [b]Output Ports:[/b]
- - Sequence
- - Data (variant): [code]get[/code]
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="type" type="int" setter="set_var_type" getter="get_var_type" enum="Variant.Type" default="0">
- The local variable's type.
- </member>
- <member name="var_name" type="StringName" setter="set_var_name" getter="get_var_name" default="&amp;&quot;new_local&quot;">
- The local variable's name.
- </member>
- </members>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptMathConstant.xml b/modules/visual_script/doc_classes/VisualScriptMathConstant.xml
deleted file mode 100644
index 01c36e763b..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptMathConstant.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptMathConstant" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Commonly used mathematical constants.
- </brief_description>
- <description>
- Provides common math constants, such as Pi, on an output Data port.
- [b]Input Ports:[/b]
- none
- [b]Output Ports:[/b]
- - Data (variant): [code]get[/code]
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="constant" type="int" setter="set_math_constant" getter="get_math_constant" enum="VisualScriptMathConstant.MathConstant" default="0">
- The math constant.
- </member>
- </members>
- <constants>
- <constant name="MATH_CONSTANT_ONE" value="0" enum="MathConstant">
- Unity: [code]1[/code].
- </constant>
- <constant name="MATH_CONSTANT_PI" value="1" enum="MathConstant">
- Pi: [code]3.141593[/code].
- </constant>
- <constant name="MATH_CONSTANT_HALF_PI" value="2" enum="MathConstant">
- Pi divided by two: [code]1.570796[/code].
- </constant>
- <constant name="MATH_CONSTANT_TAU" value="3" enum="MathConstant">
- Tau: [code]6.283185[/code].
- </constant>
- <constant name="MATH_CONSTANT_E" value="4" enum="MathConstant">
- Mathematical constant [code]e[/code], the natural log base: [code]2.718282[/code].
- </constant>
- <constant name="MATH_CONSTANT_SQRT2" value="5" enum="MathConstant">
- Square root of two: [code]1.414214[/code].
- </constant>
- <constant name="MATH_CONSTANT_INF" value="6" enum="MathConstant">
- Infinity: [code]inf[/code].
- </constant>
- <constant name="MATH_CONSTANT_NAN" value="7" enum="MathConstant">
- Not a number: [code]nan[/code].
- </constant>
- <constant name="MATH_CONSTANT_MAX" value="8" enum="MathConstant">
- Represents the size of the [enum MathConstant] enum.
- </constant>
- </constants>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptNode.xml b/modules/visual_script/doc_classes/VisualScriptNode.xml
deleted file mode 100644
index 2eb99dc25f..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptNode.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptNode" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A node which is part of a [VisualScript].
- </brief_description>
- <description>
- A node which is part of a [VisualScript]. Not to be confused with [Node], which is a part of a [SceneTree].
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_default_input_value" qualifiers="const">
- <return type="Variant" />
- <argument index="0" name="port_idx" type="int" />
- <description>
- Returns the default value of a given port. The default value is used when nothing is connected to the port.
- </description>
- </method>
- <method name="get_visual_script" qualifiers="const">
- <return type="VisualScript" />
- <description>
- Returns the [VisualScript] instance the node is bound to.
- </description>
- </method>
- <method name="ports_changed_notify">
- <return type="void" />
- <description>
- Notify that the node's ports have changed. Usually used in conjunction with [VisualScriptCustomNode] .
- </description>
- </method>
- <method name="set_default_input_value">
- <return type="void" />
- <argument index="0" name="port_idx" type="int" />
- <argument index="1" name="value" type="Variant" />
- <description>
- Change the default value of a given port.
- </description>
- </method>
- </methods>
- <signals>
- <signal name="ports_changed">
- <description>
- Emitted when the available input/output ports are changed.
- </description>
- </signal>
- </signals>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptOperator.xml b/modules/visual_script/doc_classes/VisualScriptOperator.xml
deleted file mode 100644
index 47ca6ddb90..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptOperator.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptOperator" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node that performs an operation on two values.
- </brief_description>
- <description>
- [b]Input Ports:[/b]
- - Data (variant): [code]A[/code]
- - Data (variant): [code]B[/code]
- [b]Output Ports:[/b]
- - Data (variant): [code]result[/code]
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="operator" type="int" setter="set_operator" getter="get_operator" enum="Variant.Operator" default="6">
- The operation to be performed. See [enum Variant.Operator] for available options.
- </member>
- <member name="type" type="int" setter="set_typed" getter="get_typed" enum="Variant.Type" default="0">
- The type of the values for this operation. See [enum Variant.Type] for available options.
- </member>
- </members>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptPreload.xml b/modules/visual_script/doc_classes/VisualScriptPreload.xml
deleted file mode 100644
index 146d6cd9c3..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptPreload.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptPreload" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Creates a new [Resource] or loads one from the filesystem.
- </brief_description>
- <description>
- Creates a new [Resource] or loads one from the filesystem.
- [b]Input Ports:[/b]
- none
- [b]Output Ports:[/b]
- - Data (object): [code]res[/code]
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="resource" type="Resource" setter="set_preload" getter="get_preload">
- The [Resource] to load.
- </member>
- </members>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
deleted file mode 100644
index 77cd6393a9..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptPropertyGet" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node returning a value of a property from an [Object].
- </brief_description>
- <description>
- [VisualScriptPropertyGet] can return a value of any property from the current object or other objects.
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="base_script" type="String" setter="set_base_script" getter="get_base_script">
- The script to be used when [member set_mode] is set to [constant CALL_MODE_INSTANCE].
- </member>
- <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&amp;&quot;Object&quot;">
- The base type to be used when [member set_mode] is set to [constant CALL_MODE_INSTANCE].
- </member>
- <member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type">
- The type to be used when [member set_mode] is set to [constant CALL_MODE_BASIC_TYPE].
- </member>
- <member name="index" type="StringName" setter="set_index" getter="get_index">
- The indexed name of the property to retrieve. See [method Object.get_indexed] for details.
- </member>
- <member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path">
- The node path to use when [member set_mode] is set to [constant CALL_MODE_NODE_PATH].
- </member>
- <member name="property" type="StringName" setter="set_property" getter="get_property" default="&amp;&quot;&quot;">
- The name of the property to retrieve. Changing this will clear [member index].
- </member>
- <member name="set_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptPropertyGet.CallMode" default="0">
- [code]set_mode[/code] determines the target object from which the property will be retrieved. See [enum CallMode] for options.
- </member>
- </members>
- <constants>
- <constant name="CALL_MODE_SELF" value="0" enum="CallMode">
- The property will be retrieved from this [Object].
- </constant>
- <constant name="CALL_MODE_NODE_PATH" value="1" enum="CallMode">
- The property will be retrieved from the given [Node] in the scene tree.
- </constant>
- <constant name="CALL_MODE_INSTANCE" value="2" enum="CallMode">
- The property will be retrieved from an instanced node with the given type and script.
- </constant>
- <constant name="CALL_MODE_BASIC_TYPE" value="3" enum="CallMode">
- The property will be retrieved from a GDScript basic type (e.g. [Vector2]).
- </constant>
- </constants>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml b/modules/visual_script/doc_classes/VisualScriptPropertySet.xml
deleted file mode 100644
index 6cffa328c7..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml
+++ /dev/null
@@ -1,84 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptPropertySet" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node that sets a property of an [Object].
- </brief_description>
- <description>
- [VisualScriptPropertySet] can set the value of any property from the current object or other objects.
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="assign_op" type="int" setter="set_assign_op" getter="get_assign_op" enum="VisualScriptPropertySet.AssignOp" default="0">
- The additional operation to perform when assigning. See [enum AssignOp] for options.
- </member>
- <member name="base_script" type="String" setter="set_base_script" getter="get_base_script">
- The script to be used when [member set_mode] is set to [constant CALL_MODE_INSTANCE].
- </member>
- <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&amp;&quot;Object&quot;">
- The base type to be used when [member set_mode] is set to [constant CALL_MODE_INSTANCE].
- </member>
- <member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type">
- The type to be used when [member set_mode] is set to [constant CALL_MODE_BASIC_TYPE].
- </member>
- <member name="index" type="StringName" setter="set_index" getter="get_index">
- The indexed name of the property to set. See [method Object.set_indexed] for details.
- </member>
- <member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path">
- The node path to use when [member set_mode] is set to [constant CALL_MODE_NODE_PATH].
- </member>
- <member name="property" type="StringName" setter="set_property" getter="get_property" default="&amp;&quot;&quot;">
- The name of the property to set. Changing this will clear [member index].
- </member>
- <member name="set_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptPropertySet.CallMode" default="0">
- [code]set_mode[/code] determines the target object on which the property will be set. See [enum CallMode] for options.
- </member>
- </members>
- <constants>
- <constant name="CALL_MODE_SELF" value="0" enum="CallMode">
- The property will be set on this [Object].
- </constant>
- <constant name="CALL_MODE_NODE_PATH" value="1" enum="CallMode">
- The property will be set on the given [Node] in the scene tree.
- </constant>
- <constant name="CALL_MODE_INSTANCE" value="2" enum="CallMode">
- The property will be set on an instanced node with the given type and script.
- </constant>
- <constant name="CALL_MODE_BASIC_TYPE" value="3" enum="CallMode">
- The property will be set on a GDScript basic type (e.g. [Vector2]).
- </constant>
- <constant name="ASSIGN_OP_NONE" value="0" enum="AssignOp">
- The property will be assigned regularly.
- </constant>
- <constant name="ASSIGN_OP_ADD" value="1" enum="AssignOp">
- The value will be added to the property. Equivalent of doing [code]+=[/code].
- </constant>
- <constant name="ASSIGN_OP_SUB" value="2" enum="AssignOp">
- The value will be subtracted from the property. Equivalent of doing [code]-=[/code].
- </constant>
- <constant name="ASSIGN_OP_MUL" value="3" enum="AssignOp">
- The property will be multiplied by the value. Equivalent of doing [code]*=[/code].
- </constant>
- <constant name="ASSIGN_OP_DIV" value="4" enum="AssignOp">
- The property will be divided by the value. Equivalent of doing [code]/=[/code].
- </constant>
- <constant name="ASSIGN_OP_MOD" value="5" enum="AssignOp">
- A modulo operation will be performed on the property and the value. Equivalent of doing [code]%=[/code].
- </constant>
- <constant name="ASSIGN_OP_SHIFT_LEFT" value="6" enum="AssignOp">
- The property will be binarly shifted to the left by the given value. Equivalent of doing [code]&lt;&lt;[/code].
- </constant>
- <constant name="ASSIGN_OP_SHIFT_RIGHT" value="7" enum="AssignOp">
- The property will be binarly shifted to the right by the given value. Equivalent of doing [code]&gt;&gt;[/code].
- </constant>
- <constant name="ASSIGN_OP_BIT_AND" value="8" enum="AssignOp">
- A binary [code]AND[/code] operation will be performed on the property. Equivalent of doing [code]&amp;=[/code].
- </constant>
- <constant name="ASSIGN_OP_BIT_OR" value="9" enum="AssignOp">
- A binary [code]OR[/code] operation will be performed on the property. Equivalent of doing [code]|=[/code].
- </constant>
- <constant name="ASSIGN_OP_BIT_XOR" value="10" enum="AssignOp">
- A binary [code]XOR[/code] operation will be performed on the property. Equivalent of doing [code]^=[/code].
- </constant>
- </constants>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptResourcePath.xml b/modules/visual_script/doc_classes/VisualScriptResourcePath.xml
deleted file mode 100644
index 6ca8260ade..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptResourcePath.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptResourcePath" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="path" type="String" setter="set_resource_path" getter="get_resource_path" default="&quot;&quot;">
- </member>
- </members>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptReturn.xml b/modules/visual_script/doc_classes/VisualScriptReturn.xml
deleted file mode 100644
index 1d59392782..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptReturn.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptReturn" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Exits a function and returns an optional value.
- </brief_description>
- <description>
- Ends the execution of a function and returns control to the calling function. Optionally, it can return a [Variant] value.
- [b]Input Ports:[/b]
- - Sequence
- - Data (variant): [code]result[/code] (optional)
- [b]Output Ports:[/b]
- none
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="return_enabled" type="bool" setter="set_enable_return_value" getter="is_return_value_enabled" default="false">
- If [code]true[/code], the [code]return[/code] input port is available.
- </member>
- <member name="return_type" type="int" setter="set_return_type" getter="get_return_type" enum="Variant.Type" default="0">
- The return value's data type.
- </member>
- </members>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptSceneNode.xml b/modules/visual_script/doc_classes/VisualScriptSceneNode.xml
deleted file mode 100644
index a769d11d94..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptSceneNode.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptSceneNode" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Node reference.
- </brief_description>
- <description>
- A direct reference to a node.
- [b]Input Ports:[/b]
- none
- [b]Output Ports:[/b]
- - Data: [code]node[/code] (obj)
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="node_path" type="NodePath" setter="set_node_path" getter="get_node_path" default="NodePath(&quot;.&quot;)">
- The node's path in the scene tree.
- </member>
- </members>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptSceneTree.xml b/modules/visual_script/doc_classes/VisualScriptSceneTree.xml
deleted file mode 100644
index 84ab90892f..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptSceneTree.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptSceneTree" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node for accessing [SceneTree] methods.
- </brief_description>
- <description>
- A Visual Script node for accessing [SceneTree] methods.
- </description>
- <tutorials>
- </tutorials>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptSelect.xml b/modules/visual_script/doc_classes/VisualScriptSelect.xml
deleted file mode 100644
index 1aa916f779..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptSelect.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptSelect" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Chooses between two input values.
- </brief_description>
- <description>
- Chooses between two input values based on a Boolean condition.
- [b]Input Ports:[/b]
- - Data (boolean): [code]cond[/code]
- - Data (variant): [code]a[/code]
- - Data (variant): [code]b[/code]
- [b]Output Ports:[/b]
- - Data (variant): [code]out[/code]
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="type" type="int" setter="set_typed" getter="get_typed" enum="Variant.Type" default="0">
- The input variables' type.
- </member>
- </members>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptSelf.xml b/modules/visual_script/doc_classes/VisualScriptSelf.xml
deleted file mode 100644
index 8cc59dbccd..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptSelf.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptSelf" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Outputs a reference to the current instance.
- </brief_description>
- <description>
- Provides a reference to the node running the visual script.
- [b]Input Ports:[/b]
- none
- [b]Output Ports:[/b]
- - Data (object): [code]instance[/code]
- </description>
- <tutorials>
- </tutorials>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptSequence.xml b/modules/visual_script/doc_classes/VisualScriptSequence.xml
deleted file mode 100644
index 9adbc30e0d..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptSequence.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptSequence" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Executes a series of Sequence ports.
- </brief_description>
- <description>
- Steps through a series of one or more output Sequence ports. The [code]current[/code] data port outputs the currently executing item.
- [b]Input Ports:[/b]
- - Sequence: [code]in order[/code]
- [b]Output Ports:[/b]
- - Sequence: [code]1[/code]
- - Sequence: [code]2 - n[/code] (optional)
- - Data (int): [code]current[/code]
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="steps" type="int" setter="set_steps" getter="get_steps" default="1">
- The number of steps in the sequence.
- </member>
- </members>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptSubCall.xml b/modules/visual_script/doc_classes/VisualScriptSubCall.xml
deleted file mode 100644
index 535e89fc82..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptSubCall.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptSubCall" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Calls a method called [code]_subcall[/code] in this object.
- </brief_description>
- <description>
- [VisualScriptSubCall] will call method named [code]_subcall[/code] in the current script. It will fail if the method doesn't exist or the provided arguments are wrong.
- </description>
- <tutorials>
- </tutorials>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptSwitch.xml b/modules/visual_script/doc_classes/VisualScriptSwitch.xml
deleted file mode 100644
index 7befe89f50..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptSwitch.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptSwitch" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Branches program flow based on a given input's value.
- </brief_description>
- <description>
- Branches the flow based on an input's value. Use [b]Case Count[/b] in the Inspector to set the number of branches and each comparison's optional type.
- [b]Input Ports:[/b]
- - Sequence: [code]'input' is[/code]
- - Data (variant): [code]=[/code]
- - Data (variant): [code]=[/code] (optional)
- - Data (variant): [code]input[/code]
- [b]Output Ports:[/b]
- - Sequence
- - Sequence (optional)
- - Sequence: [code]done[/code]
- </description>
- <tutorials>
- </tutorials>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml b/modules/visual_script/doc_classes/VisualScriptTypeCast.xml
deleted file mode 100644
index ec84a75601..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptTypeCast" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node that casts the given value to another type.
- </brief_description>
- <description>
- [VisualScriptTypeCast] will perform a type conversion to an [Object]-derived type.
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="base_script" type="String" setter="set_base_script" getter="get_base_script" default="&quot;&quot;">
- The target script class to be converted to. If none, only the [member base_type] will be used.
- </member>
- <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&amp;&quot;Object&quot;">
- The target type to be converted to.
- </member>
- </members>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml b/modules/visual_script/doc_classes/VisualScriptVariableGet.xml
deleted file mode 100644
index 8d99b4b9d0..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptVariableGet" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Gets a variable's value.
- </brief_description>
- <description>
- Returns a variable's value. "Var Name" must be supplied, with an optional type.
- [b]Input Ports:[/b]
- none
- [b]Output Ports:[/b]
- - Data (variant): [code]value[/code]
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="var_name" type="StringName" setter="set_variable" getter="get_variable" default="&amp;&quot;&quot;">
- The variable's name.
- </member>
- </members>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml b/modules/visual_script/doc_classes/VisualScriptVariableSet.xml
deleted file mode 100644
index 4f568cc0f6..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptVariableSet" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Changes a variable's value.
- </brief_description>
- <description>
- Changes a variable's value to the given input.
- [b]Input Ports:[/b]
- - Sequence
- - Data (variant): [code]set[/code]
- [b]Output Ports:[/b]
- - Sequence
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="var_name" type="StringName" setter="set_variable" getter="get_variable" default="&amp;&quot;&quot;">
- The variable's name.
- </member>
- </members>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptWhile.xml b/modules/visual_script/doc_classes/VisualScriptWhile.xml
deleted file mode 100644
index 4e7cccef17..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptWhile.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptWhile" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Conditional loop.
- </brief_description>
- <description>
- Loops while a condition is [code]true[/code]. Execution continues out the [code]exit[/code] Sequence port when the loop terminates.
- [b]Input Ports:[/b]
- - Sequence: [code]while(cond)[/code]
- - Data (bool): [code]cond[/code]
- [b]Output Ports:[/b]
- - Sequence: [code]repeat[/code]
- - Sequence: [code]exit[/code]
- </description>
- <tutorials>
- </tutorials>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptYield.xml b/modules/visual_script/doc_classes/VisualScriptYield.xml
deleted file mode 100644
index ec757a3ac4..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptYield.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptYield" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node used to pause a function execution.
- </brief_description>
- <description>
- [VisualScriptYield] will pause the function call and return [VisualScriptFunctionState], which can be used to resume the function.
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="mode" type="int" setter="set_yield_mode" getter="get_yield_mode" enum="VisualScriptYield.YieldMode" default="1">
- The mode to use for yielding. See [enum YieldMode] for available options.
- </member>
- <member name="wait_time" type="float" setter="set_wait_time" getter="get_wait_time">
- The time to wait when [member mode] is set to [constant YIELD_WAIT].
- </member>
- </members>
- <constants>
- <constant name="YIELD_FRAME" value="1" enum="YieldMode">
- Yields during an idle frame.
- </constant>
- <constant name="YIELD_PHYSICS_FRAME" value="2" enum="YieldMode">
- Yields during a physics frame.
- </constant>
- <constant name="YIELD_WAIT" value="3" enum="YieldMode">
- Yields a function and waits the given time.
- </constant>
- </constants>
-</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml b/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
deleted file mode 100644
index c3f4bc49c5..0000000000
--- a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptYieldSignal" inherits="VisualScriptNode" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- A Visual Script node yielding for a signal.
- </brief_description>
- <description>
- [VisualScriptYieldSignal] will pause the function execution until the provided signal is emitted.
- </description>
- <tutorials>
- </tutorials>
- <members>
- <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&amp;&quot;Object&quot;">
- The base type to be used when [member call_mode] is set to [constant CALL_MODE_INSTANCE].
- </member>
- <member name="call_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptYieldSignal.CallMode" default="0">
- [code]call_mode[/code] determines the target object to wait for the signal emission. See [enum CallMode] for options.
- </member>
- <member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path">
- The node path to use when [member call_mode] is set to [constant CALL_MODE_NODE_PATH].
- </member>
- <member name="signal" type="StringName" setter="set_signal" getter="get_signal" default="&amp;&quot;&quot;">
- The signal name to be waited for.
- </member>
- </members>
- <constants>
- <constant name="CALL_MODE_SELF" value="0" enum="CallMode">
- A signal from this [Object] will be used.
- </constant>
- <constant name="CALL_MODE_NODE_PATH" value="1" enum="CallMode">
- A signal from the given [Node] in the scene tree will be used.
- </constant>
- <constant name="CALL_MODE_INSTANCE" value="2" enum="CallMode">
- A signal from an instanced node with the given type will be used.
- </constant>
- </constants>
-</class>
diff --git a/modules/visual_script/editor/visual_script_editor.cpp b/modules/visual_script/editor/visual_script_editor.cpp
deleted file mode 100644
index 1e9755f45f..0000000000
--- a/modules/visual_script/editor/visual_script_editor.cpp
+++ /dev/null
@@ -1,4936 +0,0 @@
-/*************************************************************************/
-/* visual_script_editor.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "visual_script_editor.h"
-
-#include "../visual_script_expression.h"
-#include "../visual_script_flow_control.h"
-#include "../visual_script_func_nodes.h"
-#include "../visual_script_nodes.h"
-#include "core/input/input.h"
-#include "core/object/class_db.h"
-#include "core/object/script_language.h"
-#include "core/os/keyboard.h"
-#include "core/variant/variant.h"
-#include "editor/editor_node.h"
-#include "editor/editor_resource_preview.h"
-#include "editor/editor_scale.h"
-#include "scene/gui/view_panner.h"
-#include "scene/main/window.h"
-
-#ifdef TOOLS_ENABLED
-class VisualScriptEditorSignalEdit : public Object {
- GDCLASS(VisualScriptEditorSignalEdit, Object);
-
- StringName sig;
-
-public:
- UndoRedo *undo_redo;
- Ref<VisualScript> script;
-
-protected:
- static void _bind_methods() {
- ClassDB::bind_method("_sig_changed", &VisualScriptEditorSignalEdit::_sig_changed);
- ADD_SIGNAL(MethodInfo("changed"));
- }
-
- void _sig_changed() {
- notify_property_list_changed();
- emit_signal(SNAME("changed"));
- }
-
- bool _set(const StringName &p_name, const Variant &p_value) {
- if (sig == StringName()) {
- return false;
- }
-
- if (p_name == "argument_count") {
- int new_argc = p_value;
- int argc = script->custom_signal_get_argument_count(sig);
- if (argc == new_argc) {
- return true;
- }
-
- undo_redo->create_action(TTR("Change Signal Arguments"));
-
- if (new_argc < argc) {
- for (int i = new_argc; i < argc; i++) {
- undo_redo->add_do_method(script.ptr(), "custom_signal_remove_argument", sig, new_argc);
- undo_redo->add_undo_method(script.ptr(), "custom_signal_add_argument", sig, script->custom_signal_get_argument_name(sig, i), script->custom_signal_get_argument_type(sig, i), -1);
- }
- } else if (new_argc > argc) {
- for (int i = argc; i < new_argc; i++) {
- undo_redo->add_do_method(script.ptr(), "custom_signal_add_argument", sig, Variant::NIL, "arg" + itos(i + 1), -1);
- undo_redo->add_undo_method(script.ptr(), "custom_signal_remove_argument", sig, argc);
- }
- }
-
- undo_redo->add_do_method(this, "_sig_changed");
- undo_redo->add_undo_method(this, "_sig_changed");
-
- undo_redo->commit_action();
-
- return true;
- }
- if (String(p_name).begins_with("argument/")) {
- int idx = String(p_name).get_slice("/", 1).to_int() - 1;
- ERR_FAIL_INDEX_V(idx, script->custom_signal_get_argument_count(sig), false);
- String what = String(p_name).get_slice("/", 2);
- if (what == "type") {
- int old_type = script->custom_signal_get_argument_type(sig, idx);
- int new_type = p_value;
- undo_redo->create_action(TTR("Change Argument Type"));
- undo_redo->add_do_method(script.ptr(), "custom_signal_set_argument_type", sig, idx, new_type);
- undo_redo->add_undo_method(script.ptr(), "custom_signal_set_argument_type", sig, idx, old_type);
- undo_redo->commit_action();
-
- return true;
- }
-
- if (what == "name") {
- String old_name = script->custom_signal_get_argument_name(sig, idx);
- String new_name = p_value;
- undo_redo->create_action(TTR("Change Argument name"));
- undo_redo->add_do_method(script.ptr(), "custom_signal_set_argument_name", sig, idx, new_name);
- undo_redo->add_undo_method(script.ptr(), "custom_signal_set_argument_name", sig, idx, old_name);
- undo_redo->commit_action();
- return true;
- }
- }
-
- return false;
- }
-
- bool _get(const StringName &p_name, Variant &r_ret) const {
- if (sig == StringName()) {
- return false;
- }
-
- if (p_name == "argument_count") {
- r_ret = script->custom_signal_get_argument_count(sig);
- return true;
- }
- if (String(p_name).begins_with("argument/")) {
- int idx = String(p_name).get_slice("/", 1).to_int() - 1;
- ERR_FAIL_INDEX_V(idx, script->custom_signal_get_argument_count(sig), false);
- String what = String(p_name).get_slice("/", 2);
- if (what == "type") {
- r_ret = script->custom_signal_get_argument_type(sig, idx);
- return true;
- }
- if (what == "name") {
- r_ret = script->custom_signal_get_argument_name(sig, idx);
- return true;
- }
- }
-
- return false;
- }
- void _get_property_list(List<PropertyInfo> *p_list) const {
- if (sig == StringName()) {
- return;
- }
-
- p_list->push_back(PropertyInfo(Variant::INT, "argument_count", PROPERTY_HINT_RANGE, "0,256"));
- String argt = "Variant";
- for (int i = 1; i < Variant::VARIANT_MAX; i++) {
- argt += "," + Variant::get_type_name(Variant::Type(i));
- }
-
- for (int i = 0; i < script->custom_signal_get_argument_count(sig); i++) {
- p_list->push_back(PropertyInfo(Variant::INT, "argument/" + itos(i + 1) + "/type", PROPERTY_HINT_ENUM, argt));
- p_list->push_back(PropertyInfo(Variant::STRING, "argument/" + itos(i + 1) + "/name"));
- }
- }
-
-public:
- void edit(const StringName &p_sig) {
- sig = p_sig;
- notify_property_list_changed();
- }
-
- VisualScriptEditorSignalEdit() { undo_redo = nullptr; }
-};
-
-class VisualScriptEditorVariableEdit : public Object {
- GDCLASS(VisualScriptEditorVariableEdit, Object);
-
- StringName var;
-
-public:
- UndoRedo *undo_redo;
- Ref<VisualScript> script;
-
-protected:
- static void _bind_methods() {
- ClassDB::bind_method("_var_changed", &VisualScriptEditorVariableEdit::_var_changed);
- ClassDB::bind_method("_var_value_changed", &VisualScriptEditorVariableEdit::_var_value_changed);
- ADD_SIGNAL(MethodInfo("changed"));
- }
-
- void _var_changed() {
- notify_property_list_changed();
- emit_signal(SNAME("changed"));
- }
- void _var_value_changed() {
- emit_signal(SNAME("changed"));
- }
-
- bool _set(const StringName &p_name, const Variant &p_value) {
- if (var == StringName()) {
- return false;
- }
-
- if (String(p_name) == "value") {
- undo_redo->create_action(TTR("Set Variable Default Value"));
- Variant current = script->get_variable_default_value(var);
- undo_redo->add_do_method(script.ptr(), "set_variable_default_value", var, p_value);
- undo_redo->add_undo_method(script.ptr(), "set_variable_default_value", var, current);
- undo_redo->add_do_method(this, "_var_value_changed");
- undo_redo->add_undo_method(this, "_var_value_changed");
- undo_redo->commit_action();
- return true;
- }
-
- Dictionary d = script->call("get_variable_info", var);
-
- if (String(p_name) == "type") {
- Dictionary dc = d.duplicate();
- dc["type"] = p_value;
- undo_redo->create_action(TTR("Set Variable Type"));
- undo_redo->add_do_method(script.ptr(), "set_variable_info", var, dc);
- undo_redo->add_undo_method(script.ptr(), "set_variable_info", var, d);
-
- // Setting the default value.
- Variant::Type type = (Variant::Type)(int)p_value;
- if (type != Variant::NIL) {
- Variant default_value;
- Callable::CallError ce;
- Variant::construct(type, default_value, nullptr, 0, ce);
- if (ce.error == Callable::CallError::CALL_OK) {
- undo_redo->add_do_method(script.ptr(), "set_variable_default_value", var, default_value);
- undo_redo->add_undo_method(script.ptr(), "set_variable_default_value", var, dc["value"]);
- }
- }
-
- undo_redo->add_do_method(this, "_var_changed");
- undo_redo->add_undo_method(this, "_var_changed");
- undo_redo->commit_action();
- return true;
- }
-
- if (String(p_name) == "hint") {
- Dictionary dc = d.duplicate();
- dc["hint"] = p_value;
- undo_redo->create_action(TTR("Set Variable Type"));
- undo_redo->add_do_method(script.ptr(), "set_variable_info", var, dc);
- undo_redo->add_undo_method(script.ptr(), "set_variable_info", var, d);
- undo_redo->add_do_method(this, "_var_changed");
- undo_redo->add_undo_method(this, "_var_changed");
- undo_redo->commit_action();
- return true;
- }
-
- if (String(p_name) == "hint_string") {
- Dictionary dc = d.duplicate();
- dc["hint_string"] = p_value;
- undo_redo->create_action(TTR("Set Variable Type"));
- undo_redo->add_do_method(script.ptr(), "set_variable_info", var, dc);
- undo_redo->add_undo_method(script.ptr(), "set_variable_info", var, d);
- undo_redo->add_do_method(this, "_var_changed");
- undo_redo->add_undo_method(this, "_var_changed");
- undo_redo->commit_action();
- return true;
- }
-
- if (String(p_name) == "export") {
- script->set_variable_export(var, p_value);
- InspectorDock::get_inspector_singleton()->update_tree();
- return true;
- }
-
- return false;
- }
-
- bool _get(const StringName &p_name, Variant &r_ret) const {
- if (var == StringName()) {
- return false;
- }
-
- if (String(p_name) == "value") {
- r_ret = script->get_variable_default_value(var);
- return true;
- }
-
- PropertyInfo pinfo = script->get_variable_info(var);
-
- if (String(p_name) == "type") {
- r_ret = pinfo.type;
- return true;
- }
- if (String(p_name) == "hint") {
- r_ret = pinfo.hint;
- return true;
- }
- if (String(p_name) == "hint_string") {
- r_ret = pinfo.hint_string;
- return true;
- }
-
- if (String(p_name) == "export") {
- r_ret = script->get_variable_export(var);
- return true;
- }
-
- return false;
- }
- void _get_property_list(List<PropertyInfo> *p_list) const {
- if (var == StringName()) {
- return;
- }
-
- String argt = "Variant";
- for (int i = 1; i < Variant::VARIANT_MAX; i++) {
- argt += "," + Variant::get_type_name(Variant::Type(i));
- }
- p_list->push_back(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt));
- p_list->push_back(PropertyInfo(script->get_variable_info(var).type, "value", script->get_variable_info(var).hint, script->get_variable_info(var).hint_string, PROPERTY_USAGE_DEFAULT));
- // Update this when PropertyHint changes.
- p_list->push_back(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,ExpRange,Enum,ExpEasing,Length,SpriteFrame,KeyAccel,Flags,Layers2dRender,Layers2dPhysics,Layer3dRender,Layer3dPhysics,File,Dir,GlobalFile,GlobalDir,ResourceType,MultilineText,PlaceholderText,ColorNoAlpha,ImageCompressLossy,ImageCompressLossLess,ObjectId,String,NodePathToEditedNode,MethodOfVariantType,MethodOfBaseType,MethodOfInstance,MethodOfScript,PropertyOfVariantType,PropertyOfBaseType,PropertyOfInstance,PropertyOfScript,ObjectTooBig,NodePathValidTypes"));
- p_list->push_back(PropertyInfo(Variant::STRING, "hint_string"));
- p_list->push_back(PropertyInfo(Variant::BOOL, "export"));
- }
-
-public:
- void edit(const StringName &p_var) {
- var = p_var;
- notify_property_list_changed();
- }
-
- VisualScriptEditorVariableEdit() { undo_redo = nullptr; }
-};
-
-static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) {
- Color color;
- if (dark_theme) {
- switch (p_type) {
- case Variant::NIL:
- color = Color(0.41, 0.93, 0.74);
- break;
-
- case Variant::BOOL:
- color = Color(0.55, 0.65, 0.94);
- break;
- case Variant::INT:
- color = Color(0.49, 0.78, 0.94);
- break;
- case Variant::FLOAT:
- color = Color(0.38, 0.85, 0.96);
- break;
- case Variant::STRING:
- color = Color(0.42, 0.65, 0.93);
- break;
-
- case Variant::VECTOR2:
- color = Color(0.74, 0.57, 0.95);
- break;
- case Variant::VECTOR2I:
- color = Color(0.74, 0.57, 0.95);
- break;
- case Variant::RECT2:
- color = Color(0.95, 0.57, 0.65);
- break;
- case Variant::RECT2I:
- color = Color(0.95, 0.57, 0.65);
- break;
- case Variant::VECTOR3:
- color = Color(0.84, 0.49, 0.93);
- break;
- case Variant::VECTOR3I:
- color = Color(0.84, 0.49, 0.93);
- break;
- case Variant::VECTOR4:
- color = Color(0.84, 0.49, 0.94);
- break;
- case Variant::VECTOR4I:
- color = Color(0.84, 0.49, 0.94);
- break;
- case Variant::TRANSFORM2D:
- color = Color(0.77, 0.93, 0.41);
- break;
- case Variant::PLANE:
- color = Color(0.97, 0.44, 0.44);
- break;
- case Variant::QUATERNION:
- color = Color(0.93, 0.41, 0.64);
- break;
- case Variant::AABB:
- color = Color(0.93, 0.47, 0.57);
- break;
- case Variant::BASIS:
- color = Color(0.89, 0.93, 0.41);
- break;
- case Variant::TRANSFORM3D:
- color = Color(0.96, 0.66, 0.43);
- break;
-
- case Variant::COLOR:
- color = Color(0.62, 1.0, 0.44);
- break;
- case Variant::NODE_PATH:
- color = Color(0.41, 0.58, 0.93);
- break;
- case Variant::RID:
- color = Color(0.41, 0.93, 0.6);
- break;
- case Variant::OBJECT:
- color = Color(0.47, 0.95, 0.91);
- break;
- case Variant::DICTIONARY:
- color = Color(0.47, 0.93, 0.69);
- break;
-
- case Variant::ARRAY:
- color = Color(0.88, 0.88, 0.88);
- break;
- case Variant::PACKED_BYTE_ARRAY:
- color = Color(0.67, 0.96, 0.78);
- break;
- case Variant::PACKED_INT32_ARRAY:
- color = Color(0.69, 0.86, 0.96);
- break;
- case Variant::PACKED_FLOAT32_ARRAY:
- color = Color(0.59, 0.91, 0.97);
- break;
- case Variant::PACKED_INT64_ARRAY:
- color = Color(0.69, 0.86, 0.96);
- break;
- case Variant::PACKED_FLOAT64_ARRAY:
- color = Color(0.59, 0.91, 0.97);
- break;
- case Variant::PACKED_STRING_ARRAY:
- color = Color(0.62, 0.77, 0.95);
- break;
- case Variant::PACKED_VECTOR2_ARRAY:
- color = Color(0.82, 0.7, 0.96);
- break;
- case Variant::PACKED_VECTOR3_ARRAY:
- color = Color(0.87, 0.61, 0.95);
- break;
- case Variant::PACKED_COLOR_ARRAY:
- color = Color(0.91, 1.0, 0.59);
- break;
-
- default:
- color.set_hsv(p_type / float(Variant::VARIANT_MAX), 0.7, 0.7);
- }
- } else {
- switch (p_type) {
- case Variant::NIL:
- color = Color(0.15, 0.89, 0.63);
- break;
-
- case Variant::BOOL:
- color = Color(0.43, 0.56, 0.92);
- break;
- case Variant::INT:
- color = Color(0.31, 0.7, 0.91);
- break;
- case Variant::FLOAT:
- color = Color(0.15, 0.8, 0.94);
- break;
- case Variant::STRING:
- color = Color(0.27, 0.56, 0.91);
- break;
-
- case Variant::VECTOR2:
- color = Color(0.68, 0.46, 0.93);
- break;
- case Variant::VECTOR2I:
- color = Color(0.68, 0.46, 0.93);
- break;
- case Variant::RECT2:
- color = Color(0.93, 0.46, 0.56);
- break;
- case Variant::RECT2I:
- color = Color(0.93, 0.46, 0.56);
- break;
- case Variant::VECTOR3:
- color = Color(0.86, 0.42, 0.93);
- break;
- case Variant::VECTOR3I:
- color = Color(0.86, 0.42, 0.93);
- break;
- case Variant::TRANSFORM2D:
- color = Color(0.59, 0.81, 0.1);
- break;
- case Variant::PLANE:
- color = Color(0.97, 0.44, 0.44);
- break;
- case Variant::QUATERNION:
- color = Color(0.93, 0.41, 0.64);
- break;
- case Variant::AABB:
- color = Color(0.93, 0.47, 0.57);
- break;
- case Variant::BASIS:
- color = Color(0.7, 0.73, 0.1);
- break;
- case Variant::TRANSFORM3D:
- color = Color(0.96, 0.56, 0.28);
- break;
-
- case Variant::COLOR:
- color = Color(0.24, 0.75, 0.0);
- break;
- case Variant::NODE_PATH:
- color = Color(0.41, 0.58, 0.93);
- break;
- case Variant::RID:
- color = Color(0.17, 0.9, 0.45);
- break;
- case Variant::OBJECT:
- color = Color(0.07, 0.84, 0.76);
- break;
- case Variant::DICTIONARY:
- color = Color(0.34, 0.91, 0.62);
- break;
-
- case Variant::ARRAY:
- color = Color(0.45, 0.45, 0.45);
- break;
- case Variant::PACKED_BYTE_ARRAY:
- color = Color(0.38, 0.92, 0.6);
- break;
- case Variant::PACKED_INT32_ARRAY:
- color = Color(0.38, 0.73, 0.92);
- break;
- case Variant::PACKED_FLOAT32_ARRAY:
- color = Color(0.25, 0.83, 0.95);
- break;
- case Variant::PACKED_INT64_ARRAY:
- color = Color(0.38, 0.73, 0.92);
- break;
- case Variant::PACKED_FLOAT64_ARRAY:
- color = Color(0.25, 0.83, 0.95);
- break;
- case Variant::PACKED_STRING_ARRAY:
- color = Color(0.38, 0.62, 0.92);
- break;
- case Variant::PACKED_VECTOR2_ARRAY:
- color = Color(0.62, 0.36, 0.92);
- break;
- case Variant::PACKED_VECTOR3_ARRAY:
- color = Color(0.79, 0.35, 0.92);
- break;
- case Variant::PACKED_COLOR_ARRAY:
- color = Color(0.57, 0.73, 0.0);
- break;
-
- default:
- color.set_hsv(p_type / float(Variant::VARIANT_MAX), 0.3, 0.3);
- }
- }
-
- return color;
-}
-
-void VisualScriptEditor::_update_graph_connections() {
- graph->clear_connections();
-
- List<VisualScript::SequenceConnection> sequence_conns;
- script->get_sequence_connection_list(&sequence_conns);
-
- for (const VisualScript::SequenceConnection &E : sequence_conns) {
- graph->connect_node(itos(E.from_node), E.from_output, itos(E.to_node), 0);
- }
-
- List<VisualScript::DataConnection> data_conns;
- script->get_data_connection_list(&data_conns);
-
- for (VisualScript::DataConnection &dc : data_conns) {
- Ref<VisualScriptNode> from_node = script->get_node(dc.from_node);
- Ref<VisualScriptNode> to_node = script->get_node(dc.to_node);
-
- if (to_node->has_input_sequence_port()) {
- dc.to_port++;
- }
-
- dc.from_port += from_node->get_output_sequence_port_count();
-
- graph->connect_node(itos(dc.from_node), dc.from_port, itos(dc.to_node), dc.to_port);
- }
-}
-
-void VisualScriptEditor::_update_graph(int p_only_id) {
- if (updating_graph) {
- return;
- }
-
- updating_graph = true;
-
- //byebye all nodes
- if (p_only_id >= 0) {
- if (graph->has_node(itos(p_only_id))) {
- Node *gid = graph->get_node(itos(p_only_id));
- if (gid) {
- memdelete(gid);
- }
- }
- } else {
- for (int i = 0; i < graph->get_child_count(); i++) {
- if (Object::cast_to<GraphNode>(graph->get_child(i))) {
- memdelete(graph->get_child(i));
- i--;
- }
- }
- }
- graph->show();
- select_func_text->hide();
-
- Ref<Texture2D> type_icons[Variant::VARIANT_MAX] = {
- Control::get_theme_icon(SNAME("Variant"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("bool"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("int"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("float"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("String"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Vector2"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Vector2i"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Rect2"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Rect2i"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Vector3"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Vector3i"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Transform2D"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Plane"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Quaternion"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("AABB"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Basis"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Transform3D"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Color"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("StringName"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("NodePath"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("RID"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("MiniObject"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Callable"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Signal"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Dictionary"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Array"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("PackedByteArray"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("PackedInt32Array"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("PackedInt64Array"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("PackedFloat32Array"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("PackedFloat64Array"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("PackedStringArray"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("PackedVector2Array"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("PackedVector3Array"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("PackedColorArray"), SNAME("EditorIcons"))
- };
-
- // Visual script specific theme for MSDF font.
- Ref<Theme> vstheme;
- vstheme.instantiate();
- Ref<Font> label_font = EditorNode::get_singleton()->get_editor_theme()->get_font("main_msdf", "EditorFonts");
- vstheme->set_font("font", "Label", label_font);
- vstheme->set_font("font", "LineEdit", label_font);
- vstheme->set_font("font", "Button", label_font);
-
- Ref<Texture2D> seq_port = Control::get_theme_icon(SNAME("VisualShaderPort"), SNAME("EditorIcons"));
- List<int> node_ids;
- script->get_node_list(&node_ids);
-
- List<int> ids;
- script->get_node_list(&ids);
-
- for (int &E : ids) {
- if (p_only_id >= 0 && p_only_id != E) {
- continue;
- }
-
- Ref<VisualScriptNode> node = script->get_node(E);
- Vector2 pos = script->get_node_position(E);
-
- GraphNode *gnode = memnew(GraphNode);
- gnode->set_title(node->get_caption());
- gnode->set_position_offset(pos * EDSCALE);
- if (error_line == E) {
- gnode->set_overlay(GraphNode::OVERLAY_POSITION);
- } else if (node->is_breakpoint()) {
- gnode->set_overlay(GraphNode::OVERLAY_BREAKPOINT);
- }
-
- gnode->set_meta("__vnode", node);
- gnode->set_name(itos(E));
- gnode->connect("dragged", callable_mp(this, &VisualScriptEditor::_node_moved).bind(E));
- gnode->connect("close_request", callable_mp(this, &VisualScriptEditor::_remove_node).bind(E), CONNECT_DEFERRED);
-
- {
- Ref<VisualScriptFunction> v = node;
- if (!v.is_valid()) {
- gnode->set_show_close_button(true);
- }
- }
-
- bool has_gnode_text = false;
-
- Ref<VisualScriptLists> nd_list = node;
- bool is_vslist = nd_list.is_valid();
- if (is_vslist) {
- HBoxContainer *hbnc = memnew(HBoxContainer);
- if (nd_list->is_input_port_editable()) {
- has_gnode_text = true;
- Button *btn = memnew(Button);
- btn->set_text(TTR("Add Input Port"));
- hbnc->add_child(btn);
- btn->connect("pressed", callable_mp(this, &VisualScriptEditor::_add_input_port).bind(E), CONNECT_DEFERRED);
- }
- if (nd_list->is_output_port_editable()) {
- if (nd_list->is_input_port_editable()) {
- hbnc->add_spacer();
- }
- has_gnode_text = true;
- Button *btn = memnew(Button);
- btn->set_text(TTR("Add Output Port"));
- hbnc->add_child(btn);
- btn->connect("pressed", callable_mp(this, &VisualScriptEditor::_add_output_port).bind(E), CONNECT_DEFERRED);
- }
- gnode->add_child(hbnc);
- } else if (Object::cast_to<VisualScriptExpression>(node.ptr())) {
- has_gnode_text = true;
- LineEdit *line_edit = memnew(LineEdit);
- line_edit->set_text(node->get_text());
- line_edit->set_expand_to_text_length_enabled(true);
- line_edit->add_theme_font_override("font", get_theme_font(SNAME("source"), SNAME("EditorFonts")));
- gnode->add_child(line_edit);
- line_edit->connect("text_changed", callable_mp(this, &VisualScriptEditor::_expression_text_changed).bind(E));
- } else {
- String text = node->get_text();
- if (!text.is_empty()) {
- has_gnode_text = true;
- Label *label = memnew(Label);
- label->set_text(text);
- gnode->add_child(label);
- }
- }
-
- if (Object::cast_to<VisualScriptComment>(node.ptr())) {
- Ref<VisualScriptComment> vsc = node;
- gnode->set_comment(true);
- gnode->set_resizable(true);
- gnode->set_custom_minimum_size(vsc->get_size() * EDSCALE);
- gnode->connect("resize_request", callable_mp(this, &VisualScriptEditor::_comment_node_resized).bind(E));
- }
-
- if (node_styles.has(node->get_category())) {
- Ref<StyleBoxFlat> sbf = node_styles[node->get_category()];
- if (gnode->is_comment()) {
- sbf = EditorNode::get_singleton()->get_theme_base()->get_theme()->get_stylebox(SNAME("comment"), SNAME("GraphNode"));
- }
-
- Color c = sbf->get_border_color();
- c = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0, 0.85) : Color(0.0, 0.0, 0.0, 0.85);
- Color ic = c;
- gnode->add_theme_color_override("title_color", c);
- c.a = 1;
- gnode->add_theme_color_override("close_color", c);
- gnode->add_theme_color_override("resizer_color", ic);
- gnode->add_theme_style_override("frame", sbf);
- }
-
- const Color mono_color = get_theme_color(SNAME("mono_color"), SNAME("Editor"));
-
- int slot_idx = 0;
-
- bool single_seq_output = node->get_output_sequence_port_count() == 1 && node->get_output_sequence_port_text(0) == String();
- if ((node->has_input_sequence_port() || single_seq_output) || has_gnode_text) {
- // IF has_gnode_text is true BUT we have no sequence ports to draw (in here),
- // we still draw the disabled default ones to shift up the slots by one,
- // so the slots DON'T start with the content text.
-
- // IF has_gnode_text is false, but we DO want to draw default sequence ports,
- // we draw a dummy text to take up the position of the sequence nodes, so all the other ports are still aligned correctly.
- if (!has_gnode_text) {
- Label *dummy = memnew(Label);
- dummy->set_text(" ");
- gnode->add_child(dummy);
- }
- gnode->set_slot(0, node->has_input_sequence_port(), TYPE_SEQUENCE, mono_color, single_seq_output, TYPE_SEQUENCE, mono_color, seq_port, seq_port);
- slot_idx++;
- }
-
- int mixed_seq_ports = 0;
-
- if (!single_seq_output) {
- if (node->has_mixed_input_and_sequence_ports()) {
- mixed_seq_ports = node->get_output_sequence_port_count();
- } else {
- for (int i = 0; i < node->get_output_sequence_port_count(); i++) {
- Label *text2 = memnew(Label);
- text2->set_text(node->get_output_sequence_port_text(i));
- text2->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
- gnode->add_child(text2);
- gnode->set_slot(slot_idx, false, 0, Color(), true, TYPE_SEQUENCE, mono_color, seq_port, seq_port);
- slot_idx++;
- }
- }
- }
-
- for (int i = 0; i < MAX(node->get_output_value_port_count(), MAX(mixed_seq_ports, node->get_input_value_port_count())); i++) {
- bool left_ok = false;
- Variant::Type left_type = Variant::NIL;
- String left_name;
-
- if (i < node->get_input_value_port_count()) {
- PropertyInfo pi = node->get_input_value_port_info(i);
- left_ok = true;
- left_type = pi.type;
- left_name = pi.name;
- }
-
- bool right_ok = false;
- Variant::Type right_type = Variant::NIL;
- String right_name;
-
- if (i >= mixed_seq_ports && i < node->get_output_value_port_count() + mixed_seq_ports) {
- PropertyInfo pi = node->get_output_value_port_info(i - mixed_seq_ports);
- right_ok = true;
- right_type = pi.type;
- right_name = pi.name;
- }
- VBoxContainer *vbc = memnew(VBoxContainer);
- HBoxContainer *hbc = memnew(HBoxContainer);
- HBoxContainer *hbc2 = memnew(HBoxContainer);
- vbc->add_child(hbc);
- vbc->add_child(hbc2);
- if (left_ok) {
- Ref<Texture2D> t;
- if (left_type >= 0 && left_type < Variant::VARIANT_MAX) {
- t = type_icons[left_type];
- }
- if (t.is_valid()) {
- TextureRect *tf = memnew(TextureRect);
- tf->set_texture(t);
- tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
- hbc->add_child(tf);
- }
-
- if (is_vslist) {
- if (nd_list->is_input_port_name_editable()) {
- LineEdit *name_box = memnew(LineEdit);
- hbc->add_child(name_box);
- name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0));
- name_box->set_text(left_name);
- name_box->set_expand_to_text_length_enabled(true);
- name_box->connect("resized", callable_mp(this, &VisualScriptEditor::_update_node_size).bind(E));
- name_box->connect("focus_exited", callable_mp(this, &VisualScriptEditor::_port_name_focus_out).bind(name_box, E, i, true));
- } else {
- hbc->add_child(memnew(Label(left_name)));
- }
-
- if (nd_list->is_input_port_type_editable()) {
- OptionButton *opbtn = memnew(OptionButton);
- for (int j = Variant::NIL; j < Variant::VARIANT_MAX; j++) {
- opbtn->add_item(Variant::get_type_name(Variant::Type(j)));
- }
- opbtn->select(left_type);
- opbtn->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
- hbc->add_child(opbtn);
- opbtn->connect("item_selected", callable_mp(this, &VisualScriptEditor::_change_port_type).bind(E, i, true), CONNECT_DEFERRED);
- }
-
- Button *rmbtn = memnew(Button);
- rmbtn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
- hbc->add_child(rmbtn);
- rmbtn->connect("pressed", callable_mp(this, &VisualScriptEditor::_remove_input_port).bind(E, i), CONNECT_DEFERRED);
- } else {
- hbc->add_child(memnew(Label(left_name)));
- }
-
- if (left_type != Variant::NIL && !script->is_input_value_port_connected(E, i)) {
- PropertyInfo pi = node->get_input_value_port_info(i);
- Button *button = memnew(Button);
- Variant value = node->get_default_input_value(i);
- if (value.get_type() != left_type) {
- //different type? for now convert
- //not the same, reconvert
- Callable::CallError ce;
- const Variant *existingp = &value;
- Variant::construct(left_type, value, &existingp, 1, ce);
- }
-
- if (left_type == Variant::COLOR) {
- button->set_custom_minimum_size(Size2(30, 0) * EDSCALE);
- button->connect("draw", callable_mp(this, &VisualScriptEditor::_draw_color_over_button).bind(button, value));
- } else if (left_type == Variant::OBJECT && Ref<Resource>(value).is_valid()) {
- Ref<Resource> res = value;
- Array arr;
- arr.push_back(button->get_instance_id());
- arr.push_back(String(value));
- EditorResourcePreview::get_singleton()->queue_edited_resource_preview(res, this, "_button_resource_previewed", arr);
-
- } else if (pi.type == Variant::INT && pi.hint == PROPERTY_HINT_ENUM) {
- bool found = false;
- const Vector<String> options = pi.hint_string.split(",");
- int64_t current_val = 0;
- for (const String &option : options) {
- Vector<String> text_split = option.split(":");
- if (text_split.size() != 1) {
- current_val = text_split[1].to_int();
- }
- if (value.operator int() == current_val) {
- button->set_text(text_split[0]);
- found = true;
- break;
- }
- current_val += 1;
- }
- if (!found) {
- button->set_text(value);
- }
- } else if (pi.type == Variant::INT && pi.hint == PROPERTY_HINT_FLAGS) {
- Vector<String> value_texts;
- const Vector<String> options = pi.hint_string.split(",");
- uint32_t v = value;
- for (const String &option : options) {
- uint32_t current_val;
- Vector<String> text_split = option.split(":");
- if (text_split.size() != -1) {
- current_val = text_split[1].to_int();
- } else {
- current_val = 1 << i;
- }
- if ((v & current_val) == current_val) {
- value_texts.push_back(text_split[0]);
- }
- }
- if (value_texts.size() != 0) {
- String value_text = value_texts[0];
- for (const String &text : value_texts) {
- value_text += " | " + text;
- }
- button->set_text(value_text);
- } else {
- button->set_text(value);
- }
- } else {
- button->set_text(value);
- }
- button->connect("pressed", callable_mp(this, &VisualScriptEditor::_default_value_edited).bind(button, E, i));
- hbc2->add_child(button);
- }
- } else {
- Control *c = memnew(Control);
- c->set_custom_minimum_size(Size2(10, 0) * EDSCALE);
- hbc->add_child(c);
- }
-
- hbc->add_spacer();
- hbc2->add_spacer();
-
- if (i < mixed_seq_ports) {
- Label *text2 = memnew(Label);
- text2->set_text(node->get_output_sequence_port_text(i));
- text2->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
- hbc->add_child(text2);
- }
-
- if (right_ok) {
- if (is_vslist) {
- Button *rmbtn = memnew(Button);
- rmbtn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
- hbc->add_child(rmbtn);
- rmbtn->connect("pressed", callable_mp(this, &VisualScriptEditor::_remove_output_port).bind(E, i), CONNECT_DEFERRED);
-
- if (nd_list->is_output_port_type_editable()) {
- OptionButton *opbtn = memnew(OptionButton);
- for (int j = Variant::NIL; j < Variant::VARIANT_MAX; j++) {
- opbtn->add_item(Variant::get_type_name(Variant::Type(j)));
- }
- opbtn->select(right_type);
- opbtn->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
- hbc->add_child(opbtn);
- opbtn->connect("item_selected", callable_mp(this, &VisualScriptEditor::_change_port_type).bind(E, i, false), CONNECT_DEFERRED);
- }
-
- if (nd_list->is_output_port_name_editable()) {
- LineEdit *name_box = memnew(LineEdit);
- hbc->add_child(name_box);
- name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0));
- name_box->set_text(right_name);
- name_box->set_expand_to_text_length_enabled(true);
- name_box->connect("resized", callable_mp(this, &VisualScriptEditor::_update_node_size).bind(E));
- name_box->connect("focus_exited", callable_mp(this, &VisualScriptEditor::_port_name_focus_out).bind(name_box, E, i, false));
- } else {
- hbc->add_child(memnew(Label(right_name)));
- }
- } else {
- hbc->add_child(memnew(Label(right_name)));
- }
-
- Ref<Texture2D> t;
- if (right_type >= 0 && right_type < Variant::VARIANT_MAX) {
- t = type_icons[right_type];
- }
- if (t.is_valid()) {
- TextureRect *tf = memnew(TextureRect);
- tf->set_texture(t);
- tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
- hbc->add_child(tf);
- }
- }
-
- gnode->add_child(vbc);
-
- bool dark_theme = get_theme_constant(SNAME("dark_theme"), SNAME("Editor"));
- if (i < mixed_seq_ports) {
- gnode->set_slot(slot_idx, left_ok, left_type, _color_from_type(left_type, dark_theme), true, TYPE_SEQUENCE, mono_color, Ref<Texture2D>(), seq_port);
- } else {
- gnode->set_slot(slot_idx, left_ok, left_type, _color_from_type(left_type, dark_theme), right_ok, right_type, _color_from_type(right_type, dark_theme));
- }
-
- slot_idx++;
- }
- graph->add_child(gnode);
- gnode->set_theme(vstheme);
- if (gnode->is_comment()) {
- graph->move_child(gnode, 0);
- }
- }
-
- _update_graph_connections();
-
- float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity");
- graph->set_minimap_opacity(graph_minimap_opacity);
-
- float graph_lines_curvature = EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature");
- graph->set_connection_lines_curvature(graph_lines_curvature);
-
- // Use default_func instead of default_func for now I think that should be good stop gap solution to ensure not breaking anything.
- graph->call_deferred(SNAME("set_scroll_ofs"), script->get_scroll() * EDSCALE);
- updating_graph = false;
-}
-
-void VisualScriptEditor::_change_port_type(int p_select, int p_id, int p_port, bool is_input) {
- Ref<VisualScriptLists> vsn = script->get_node(p_id);
- if (!vsn.is_valid()) {
- return;
- }
-
- undo_redo->create_action(TTR("Change Port Type"));
- if (is_input) {
- undo_redo->add_do_method(vsn.ptr(), "set_input_data_port_type", p_port, Variant::Type(p_select));
- undo_redo->add_undo_method(vsn.ptr(), "set_input_data_port_type", p_port, vsn->get_input_value_port_info(p_port).type);
- } else {
- undo_redo->add_do_method(vsn.ptr(), "set_output_data_port_type", p_port, Variant::Type(p_select));
- undo_redo->add_undo_method(vsn.ptr(), "set_output_data_port_type", p_port, vsn->get_output_value_port_info(p_port).type);
- }
- undo_redo->commit_action();
-}
-
-void VisualScriptEditor::_update_node_size(int p_id) {
- Node *node = graph->get_node(itos(p_id));
- if (Object::cast_to<Control>(node)) {
- Object::cast_to<Control>(node)->reset_size(); // Shrink if text is smaller.
- }
-}
-
-void VisualScriptEditor::_port_name_focus_out(const Node *p_name_box, int p_id, int p_port, bool is_input) {
- Ref<VisualScriptLists> vsn = script->get_node(p_id);
- if (!vsn.is_valid()) {
- return;
- }
-
- String text;
-
- if (Object::cast_to<LineEdit>(p_name_box)) {
- text = Object::cast_to<LineEdit>(p_name_box)->get_text();
- } else {
- return;
- }
-
- undo_redo->create_action(TTR("Change Port Name"));
- if (is_input) {
- undo_redo->add_do_method(vsn.ptr(), "set_input_data_port_name", p_port, text);
- undo_redo->add_undo_method(vsn.ptr(), "set_input_data_port_name", p_port, vsn->get_input_value_port_info(p_port).name);
- } else {
- undo_redo->add_do_method(vsn.ptr(), "set_output_data_port_name", p_port, text);
- undo_redo->add_undo_method(vsn.ptr(), "set_output_data_port_name", p_port, vsn->get_output_value_port_info(p_port).name);
- }
- undo_redo->commit_action();
-}
-
-void VisualScriptEditor::_update_members() {
- ERR_FAIL_COND(!script.is_valid());
-
- updating_members = true;
-
- members->clear();
- TreeItem *root = members->create_item();
-
- TreeItem *functions = members->create_item(root);
- functions->set_selectable(0, false);
- functions->set_text(0, TTR("Functions:"));
- functions->add_button(0, Control::get_theme_icon(SNAME("Override"), SNAME("EditorIcons")), 1, false, TTR("Override an existing built-in function."));
- functions->add_button(0, Control::get_theme_icon(SNAME("Add"), SNAME("EditorIcons")), 0, false, TTR("Create a new function."));
- functions->set_custom_color(0, Control::get_theme_color(SNAME("mono_color"), SNAME("Editor")));
-
- List<StringName> func_names;
- script->get_function_list(&func_names);
- func_names.sort_custom<StringName::AlphCompare>();
- for (const StringName &E : func_names) {
- TreeItem *ti = members->create_item(functions);
- ti->set_text(0, E);
- ti->set_selectable(0, true);
- ti->set_metadata(0, E);
- ti->add_button(0, Control::get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")), 0);
- if (selected == E) {
- ti->select(0);
- }
- }
-
- TreeItem *variables = members->create_item(root);
- variables->set_selectable(0, false);
- variables->set_text(0, TTR("Variables:"));
- variables->add_button(0, Control::get_theme_icon(SNAME("Add"), SNAME("EditorIcons")), -1, false, TTR("Create a new variable."));
- variables->set_custom_color(0, Control::get_theme_color(SNAME("mono_color"), SNAME("Editor")));
-
- Ref<Texture2D> type_icons[Variant::VARIANT_MAX] = {
- Control::get_theme_icon(SNAME("Variant"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("bool"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("int"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("float"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("String"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Vector2"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Vector2i"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Rect2"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Rect2i"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Vector3"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Vector3i"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Transform2D"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Plane"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Quaternion"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("AABB"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Basis"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Transform3D"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Color"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("StringName"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("NodePath"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("RID"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("MiniObject"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Callable"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Signal"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Dictionary"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("Array"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("PackedByteArray"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("PackedInt32Array"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("PackedInt64Array"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("PackedFloat32Array"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("PackedFloat64Array"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("PackedStringArray"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("PackedVector2Array"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("PackedVector3Array"), SNAME("EditorIcons")),
- Control::get_theme_icon(SNAME("PackedColorArray"), SNAME("EditorIcons"))
- };
-
- List<StringName> var_names;
- script->get_variable_list(&var_names);
- var_names.sort_custom<StringName::AlphCompare>();
- for (const StringName &E : var_names) {
- TreeItem *ti = members->create_item(variables);
-
- ti->set_text(0, E);
-
- ti->set_suffix(0, "= " + _sanitized_variant_text(E));
- ti->set_icon(0, type_icons[script->get_variable_info(E).type]);
-
- ti->set_selectable(0, true);
- ti->set_editable(0, true);
- ti->set_metadata(0, E);
- if (selected == E) {
- ti->select(0);
- }
- }
-
- TreeItem *_signals = members->create_item(root);
- _signals->set_selectable(0, false);
- _signals->set_text(0, TTR("Signals:"));
- _signals->add_button(0, Control::get_theme_icon(SNAME("Add"), SNAME("EditorIcons")), -1, false, TTR("Create a new signal."));
- _signals->set_custom_color(0, Control::get_theme_color(SNAME("mono_color"), SNAME("Editor")));
-
- List<StringName> signal_names;
- script->get_custom_signal_list(&signal_names);
- for (const StringName &E : signal_names) {
- TreeItem *ti = members->create_item(_signals);
- ti->set_text(0, E);
- ti->set_selectable(0, true);
- ti->set_editable(0, true);
- ti->set_metadata(0, E);
- if (selected == E) {
- ti->select(0);
- }
- }
-
- String base_type = script->get_instance_base_type();
- String icon_type = base_type;
- if (!Control::has_theme_icon(base_type, SNAME("EditorIcons"))) {
- icon_type = "Object";
- }
-
- base_type_select->set_text(base_type);
- base_type_select->set_icon(Control::get_theme_icon(icon_type, SNAME("EditorIcons")));
-
- updating_members = false;
-}
-
-String VisualScriptEditor::_sanitized_variant_text(const StringName &property_name) {
- Variant var = script->get_variable_default_value(property_name);
-
- if (script->get_variable_info(property_name).type != Variant::NIL) {
- Callable::CallError ce;
- const Variant *converted = &var;
- Variant n;
- Variant::construct(script->get_variable_info(property_name).type, n, &converted, 1, ce);
- var = n;
- }
-
- return String(var);
-}
-
-void VisualScriptEditor::_member_selected() {
- if (updating_members) {
- return;
- }
-
- TreeItem *ti = members->get_selected();
- ERR_FAIL_COND(!ti);
-
- selected = ti->get_metadata(0);
-
- if (ti->get_parent() == members->get_root()->get_first_child()) {
-#ifdef MACOS_ENABLED
- bool held_ctrl = Input::get_singleton()->is_key_pressed(Key::META);
-#else
- bool held_ctrl = Input::get_singleton()->is_key_pressed(Key::CTRL);
-#endif
- if (held_ctrl) {
- ERR_FAIL_COND(!script->has_function(selected));
- _center_on_node(script->get_function_node_id(selected));
- }
- }
-}
-
-void VisualScriptEditor::_member_edited() {
- if (updating_members) {
- return;
- }
-
- TreeItem *ti = members->get_edited();
- ERR_FAIL_COND(!ti);
-
- String name = ti->get_metadata(0);
- String new_name = ti->get_text(0);
-
- if (name == new_name) {
- return;
- }
-
- if (!new_name.is_valid_identifier()) {
- EditorNode::get_singleton()->show_warning(TTR("Name is not a valid identifier:") + " " + new_name);
- updating_members = true;
- ti->set_text(0, name);
- updating_members = false;
- return;
- }
-
- if (script->has_function(new_name) || script->has_variable(new_name) || script->has_custom_signal(new_name)) {
- EditorNode::get_singleton()->show_warning(TTR("Name already in use by another func/var/signal:") + " " + new_name);
- updating_members = true;
- ti->set_text(0, name);
- updating_members = false;
- return;
- }
-
- TreeItem *root = members->get_root();
-
- if (ti->get_parent() == root->get_first_child()) {
- selected = new_name;
-
- int node_id = script->get_function_node_id(name);
- Ref<VisualScriptFunction> func;
- if (script->has_node(node_id)) {
- func = script->get_node(node_id);
- }
- undo_redo->create_action(TTR("Rename Function"));
- undo_redo->add_do_method(script.ptr(), "rename_function", name, new_name);
- undo_redo->add_undo_method(script.ptr(), "rename_function", new_name, name);
- if (func.is_valid()) {
- undo_redo->add_do_method(func.ptr(), "set_name", new_name);
- undo_redo->add_undo_method(func.ptr(), "set_name", name);
- }
-
- // Also fix all function calls.
- List<int> lst;
- script->get_node_list(&lst);
- for (int &F : lst) {
- Ref<VisualScriptFunctionCall> fncall = script->get_node(F);
- if (!fncall.is_valid()) {
- continue;
- }
- if (fncall->get_function() == name) {
- undo_redo->add_do_method(fncall.ptr(), "set_function", new_name);
- undo_redo->add_undo_method(fncall.ptr(), "set_function", name);
- }
- }
-
- undo_redo->add_do_method(this, "_update_members");
- undo_redo->add_undo_method(this, "_update_members");
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
- undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
- undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
- undo_redo->commit_action();
-
- return; // Or crash because it will become invalid.
- }
-
- if (ti->get_parent() == root->get_first_child()->get_next()) {
- selected = new_name;
- undo_redo->create_action(TTR("Rename Variable"));
- undo_redo->add_do_method(script.ptr(), "rename_variable", name, new_name);
- undo_redo->add_undo_method(script.ptr(), "rename_variable", new_name, name);
-
- // Also fix all variable setter & getter calls
- List<int> lst;
- script->get_node_list(&lst);
- for (int &P : lst) {
- Ref<VisualScriptPropertySet> pset = script->get_node(P);
- if (pset.is_valid() && pset->get_property() == name) {
- undo_redo->add_do_method(pset.ptr(), "set_property", new_name);
- undo_redo->add_undo_method(pset.ptr(), "set_property", name);
- }
- Ref<VisualScriptPropertyGet> pget = script->get_node(P);
- if (pget.is_valid() && pget->get_property() == name) {
- undo_redo->add_do_method(pget.ptr(), "set_property", new_name);
- undo_redo->add_undo_method(pget.ptr(), "set_property", name);
- }
- }
-
- undo_redo->add_do_method(this, "_update_members");
- undo_redo->add_undo_method(this, "_update_members");
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
- undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
- undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
- undo_redo->commit_action();
-
- return; // Or crash because it will become invalid.
- }
-
- if (ti->get_parent() == root->get_first_child()->get_next()->get_next()) {
- selected = new_name;
- undo_redo->create_action(TTR("Rename Signal"));
- undo_redo->add_do_method(script.ptr(), "rename_custom_signal", name, new_name);
- undo_redo->add_undo_method(script.ptr(), "rename_custom_signal", new_name, name);
-
- // Also fix all signal emitting nodes
- List<int> lst;
- script->get_node_list(&lst);
- for (int &P : lst) {
- Ref<VisualScriptEmitSignal> psig = script->get_node(P);
- if (psig.is_valid() && psig->get_signal() == name) {
- undo_redo->add_do_method(psig.ptr(), "set_signal", new_name);
- undo_redo->add_undo_method(psig.ptr(), "set_signal", name);
- }
- }
-
- undo_redo->add_do_method(this, "_update_members");
- undo_redo->add_undo_method(this, "_update_members");
- undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
- undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
- undo_redo->commit_action();
-
- return; // Or crash because it will become invalid.
- }
-}
-
-void VisualScriptEditor::_create_function_dialog() {
- function_create_dialog->popup_centered();
- func_name_box->set_text("");
- func_name_box->grab_focus();
- for (int i = 0; i < func_input_vbox->get_child_count(); i++) {
- Node *nd = func_input_vbox->get_child(i);
- nd->queue_delete();
- }
-}
-
-void VisualScriptEditor::_create_function() {
- String name = _validate_name((func_name_box->get_text().is_empty()) ? "new_func" : func_name_box->get_text());
- selected = name;
- Vector2 pos = _get_available_pos();
-
- Ref<VisualScriptFunction> func_node;
- func_node.instantiate();
- func_node->set_name(name);
-
- for (int i = 0; i < func_input_vbox->get_child_count(); i++) {
- OptionButton *opbtn = Object::cast_to<OptionButton>(func_input_vbox->get_child(i)->get_child(3));
- LineEdit *lne = Object::cast_to<LineEdit>(func_input_vbox->get_child(i)->get_child(1));
- if (!opbtn || !lne) {
- continue;
- }
- Variant::Type arg_type = Variant::Type(opbtn->get_selected());
- String arg_name = lne->get_text();
- func_node->add_argument(arg_type, arg_name);
- }
-
- int func_node_id = script->get_available_id();
-
- undo_redo->create_action(TTR("Add Function"));
- undo_redo->add_do_method(script.ptr(), "add_function", name, func_node_id);
- undo_redo->add_undo_method(script.ptr(), "remove_function", name);
- undo_redo->add_do_method(script.ptr(), "add_node", func_node_id, func_node, pos);
- undo_redo->add_undo_method(script.ptr(), "remove_node", func_node_id);
- undo_redo->add_do_method(this, "_update_members");
- undo_redo->add_undo_method(this, "_update_members");
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
- undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
- undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
- undo_redo->commit_action();
-
- _update_graph();
-}
-
-void VisualScriptEditor::_add_node_dialog() {
- _generic_search(graph->get_global_position() + Vector2(55, 80), true);
-}
-
-void VisualScriptEditor::_add_func_input() {
- HBoxContainer *hbox = memnew(HBoxContainer);
- hbox->set_h_size_flags(SIZE_EXPAND_FILL);
-
- Label *name_label = memnew(Label);
- name_label->set_text(TTR("Name:"));
- hbox->add_child(name_label);
-
- LineEdit *name_box = memnew(LineEdit);
- name_box->set_h_size_flags(SIZE_EXPAND_FILL);
- name_box->set_text("input");
- name_box->connect("focus_entered", callable_mp(this, &VisualScriptEditor::_deselect_input_names));
- hbox->add_child(name_box);
-
- Label *type_label = memnew(Label);
- type_label->set_text(TTR("Type:"));
- hbox->add_child(type_label);
-
- OptionButton *type_box = memnew(OptionButton);
- type_box->set_custom_minimum_size(Size2(120 * EDSCALE, 0));
- for (int i = Variant::NIL; i < Variant::VARIANT_MAX; i++) {
- type_box->add_item(Variant::get_type_name(Variant::Type(i)));
- }
- type_box->select(1);
- hbox->add_child(type_box);
-
- Button *delete_button = memnew(Button);
- delete_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
- delete_button->set_tooltip(vformat(TTR("Delete input port")));
- hbox->add_child(delete_button);
-
- for (int i = 0; i < func_input_vbox->get_child_count(); i++) {
- LineEdit *line_edit = (LineEdit *)func_input_vbox->get_child(i)->get_child(1);
- line_edit->deselect();
- }
-
- func_input_vbox->add_child(hbox);
- hbox->set_meta("id", hbox->get_index());
-
- delete_button->connect("pressed", callable_mp(this, &VisualScriptEditor::_remove_func_input).bind(hbox));
-
- name_box->select_all();
- name_box->grab_focus();
-}
-
-void VisualScriptEditor::_remove_func_input(Node *p_node) {
- func_input_vbox->remove_child(p_node);
- p_node->queue_delete();
-}
-
-void VisualScriptEditor::_deselect_input_names() {
- int cn = func_input_vbox->get_child_count();
- for (int i = 0; i < cn; i++) {
- LineEdit *lne = Object::cast_to<LineEdit>(func_input_vbox->get_child(i)->get_child(1));
- if (lne) {
- lne->deselect();
- }
- }
-}
-
-void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_button, MouseButton p_mouse_button) {
- if (p_mouse_button != MouseButton::LEFT) {
- return;
- }
-
- TreeItem *ti = Object::cast_to<TreeItem>(p_item);
-
- TreeItem *root = members->get_root();
-
- if (ti->get_parent() == root) {
- //main buttons
- if (ti == root->get_first_child()) {
- // Add function, this one uses menu.
-
- if (p_button == 1) {
- // Ensure script base exists otherwise use custom base type.
- ERR_FAIL_COND(script.is_null());
- new_virtual_method_select->select_method_from_base_type(script->get_instance_base_type(), true);
- return;
- } else if (p_button == 0) {
- String name = _validate_name("new_function");
- selected = name;
- Vector2 pos = _get_available_pos();
-
- Ref<VisualScriptFunction> func_node;
- func_node.instantiate();
- func_node->set_name(name);
- int fn_id = script->get_available_id();
-
- undo_redo->create_action(TTR("Add Function"));
- undo_redo->add_do_method(script.ptr(), "add_function", name, fn_id);
- undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, pos);
- undo_redo->add_undo_method(script.ptr(), "remove_function", name);
- undo_redo->add_undo_method(script.ptr(), "remove_node", fn_id);
- undo_redo->add_do_method(this, "_update_members");
- undo_redo->add_undo_method(this, "_update_members");
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
- undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
- undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
- undo_redo->commit_action();
-
- _update_graph();
- }
-
- return; // Or crash because it will become invalid.
- }
-
- if (ti == root->get_first_child()->get_next()) {
- // Add variable.
- String name = _validate_name("new_variable");
- selected = name;
-
- undo_redo->create_action(TTR("Add Variable"));
- undo_redo->add_do_method(script.ptr(), "add_variable", name);
- undo_redo->add_undo_method(script.ptr(), "remove_variable", name);
- undo_redo->add_do_method(this, "_update_members");
- undo_redo->add_undo_method(this, "_update_members");
- undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
- undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
- undo_redo->commit_action();
- return; // Or crash because it will become invalid.
- }
-
- if (ti == root->get_first_child()->get_next()->get_next()) {
- // Add variable.
- String name = _validate_name("new_signal");
- selected = name;
-
- undo_redo->create_action(TTR("Add Signal"));
- undo_redo->add_do_method(script.ptr(), "add_custom_signal", name);
- undo_redo->add_undo_method(script.ptr(), "remove_custom_signal", name);
- undo_redo->add_do_method(this, "_update_members");
- undo_redo->add_undo_method(this, "_update_members");
- undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
- undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
- undo_redo->commit_action();
- return; // Or crash because it will become invalid.
- }
- } else if (ti->get_parent() == root->get_first_child()) {
- selected = ti->get_text(0);
- function_name_edit->set_position(get_screen_position() + get_local_mouse_position() - Vector2(60, -10));
- function_name_edit->popup();
- function_name_box->set_text(selected);
- function_name_box->select_all();
- function_name_box->grab_focus();
- }
-}
-
-void VisualScriptEditor::_add_input_port(int p_id) {
- Ref<VisualScriptLists> vsn = script->get_node(p_id);
- if (!vsn.is_valid()) {
- return;
- }
-
- updating_graph = true;
-
- undo_redo->create_action(TTR("Add Input Port"), UndoRedo::MERGE_ENDS);
- undo_redo->add_do_method(vsn.ptr(), "add_input_data_port", Variant::NIL, "arg", -1);
- undo_redo->add_do_method(this, "_update_graph", p_id);
-
- undo_redo->add_undo_method(vsn.ptr(), "remove_input_data_port", vsn->get_input_value_port_count());
- undo_redo->add_undo_method(this, "_update_graph", p_id);
-
- updating_graph = false;
-
- undo_redo->commit_action();
-}
-
-void VisualScriptEditor::_add_output_port(int p_id) {
- Ref<VisualScriptLists> vsn = script->get_node(p_id);
- if (!vsn.is_valid()) {
- return;
- }
-
- updating_graph = true;
-
- undo_redo->create_action(TTR("Add Output Port"), UndoRedo::MERGE_ENDS);
- undo_redo->add_do_method(vsn.ptr(), "add_output_data_port", Variant::NIL, "arg", -1);
- undo_redo->add_do_method(this, "_update_graph", p_id);
-
- undo_redo->add_undo_method(vsn.ptr(), "remove_output_data_port", vsn->get_output_value_port_count());
- undo_redo->add_undo_method(this, "_update_graph", p_id);
-
- updating_graph = false;
-
- undo_redo->commit_action();
-}
-
-void VisualScriptEditor::_remove_input_port(int p_id, int p_port) {
- Ref<VisualScriptLists> vsn = script->get_node(p_id);
- if (!vsn.is_valid()) {
- return;
- }
-
- updating_graph = true;
-
- undo_redo->create_action(TTR("Remove Input Port"), UndoRedo::MERGE_ENDS);
-
- int conn_from = -1, conn_port = -1;
- script->get_input_value_port_connection_source(p_id, p_port, &conn_from, &conn_port);
-
- if (conn_from != -1) {
- undo_redo->add_do_method(script.ptr(), "data_disconnect", conn_from, conn_port, p_id, p_port);
- }
-
- undo_redo->add_do_method(vsn.ptr(), "remove_input_data_port", p_port);
- undo_redo->add_do_method(this, "_update_graph", p_id);
-
- if (conn_from != -1) {
- undo_redo->add_undo_method(script.ptr(), "data_connect", conn_from, conn_port, p_id, p_port);
- }
-
- undo_redo->add_undo_method(vsn.ptr(), "add_input_data_port", vsn->get_input_value_port_info(p_port).type, vsn->get_input_value_port_info(p_port).name, p_port);
- undo_redo->add_undo_method(this, "_update_graph", p_id);
-
- updating_graph = false;
-
- undo_redo->commit_action();
-}
-
-void VisualScriptEditor::_remove_output_port(int p_id, int p_port) {
- Ref<VisualScriptLists> vsn = script->get_node(p_id);
- if (!vsn.is_valid()) {
- return;
- }
-
- updating_graph = true;
-
- undo_redo->create_action(TTR("Remove Output Port"), UndoRedo::MERGE_ENDS);
-
- List<VisualScript::DataConnection> data_connections;
- script->get_data_connection_list(&data_connections);
-
- HashMap<int, RBSet<int>> conn_map;
- for (const VisualScript::DataConnection &E : data_connections) {
- if (E.from_node == p_id && E.from_port == p_port) {
- // Push into the connections map.
- if (!conn_map.has(E.to_node)) {
- conn_map.insert(E.to_node, RBSet<int>());
- }
- conn_map[E.to_node].insert(E.to_port);
- }
- }
-
- undo_redo->add_do_method(vsn.ptr(), "remove_output_data_port", p_port);
- undo_redo->add_do_method(this, "_update_graph", p_id);
-
- for (const KeyValue<int, RBSet<int>> &E : conn_map) {
- for (const int &F : E.value) {
- undo_redo->add_undo_method(script.ptr(), "data_connect", p_id, p_port, E.key, F);
- }
- }
-
- undo_redo->add_undo_method(vsn.ptr(), "add_output_data_port", vsn->get_output_value_port_info(p_port).type, vsn->get_output_value_port_info(p_port).name, p_port);
- undo_redo->add_undo_method(this, "_update_graph", p_id);
-
- updating_graph = false;
-
- undo_redo->commit_action();
-}
-
-void VisualScriptEditor::_expression_text_changed(const String &p_text, int p_id) {
- Ref<VisualScriptExpression> vse = script->get_node(p_id);
- if (!vse.is_valid()) {
- return;
- }
-
- updating_graph = true;
-
- undo_redo->create_action(TTR("Change Expression"), UndoRedo::MERGE_ENDS);
- undo_redo->add_do_property(vse.ptr(), "expression", p_text);
- undo_redo->add_undo_property(vse.ptr(), "expression", vse->get("expression"));
- undo_redo->add_do_method(this, "_update_graph", p_id);
- undo_redo->add_undo_method(this, "_update_graph", p_id);
- undo_redo->commit_action();
-
- Node *node = graph->get_node(itos(p_id));
- if (Object::cast_to<Control>(node)) {
- Object::cast_to<Control>(node)->reset_size(); // Shrink if text is smaller.
- }
-
- updating_graph = false;
-}
-
-Vector2 VisualScriptEditor::_get_pos_in_graph(Vector2 p_point) const {
- Vector2 pos = (graph->get_scroll_ofs() + p_point) / (graph->get_zoom() * EDSCALE);
- if (graph->is_using_snap()) {
- int snap = graph->get_snap();
- pos = pos.snapped(Vector2(snap, snap));
- }
- return pos;
-}
-
-Vector2 VisualScriptEditor::_get_available_pos(bool p_centered, Vector2 p_pos) const {
- if (p_centered) {
- p_pos = _get_pos_in_graph(graph->get_size() * 0.5);
- }
-
- while (true) {
- bool exists = false;
- List<int> existing;
- script->get_node_list(&existing);
- for (int &E : existing) {
- Point2 pos = script->get_node_position(E);
- if (pos.distance_to(p_pos) < 50) {
- p_pos += Vector2(graph->get_snap(), graph->get_snap());
- exists = true;
- break;
- }
- }
- if (exists) {
- continue;
- }
- break;
- }
-
- return p_pos;
-}
-
-String VisualScriptEditor::_validate_name(const String &p_name) const {
- String valid = p_name;
-
- int counter = 1;
- while (true) {
- bool exists = script->has_function(valid) || script->has_variable(valid) || script->has_custom_signal(valid);
-
- if (exists) {
- counter++;
- valid = p_name + "_" + itos(counter);
- continue;
- }
-
- break;
- }
-
- return valid;
-}
-
-void VisualScriptEditor::_on_nodes_copy() {
- clipboard->nodes.clear();
- clipboard->data_connections.clear();
- clipboard->sequence_connections.clear();
-
- for (int i = 0; i < graph->get_child_count(); i++) {
- GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
- if (gn) {
- if (gn->is_selected()) {
- int id = gn->get_name().operator String().to_int();
- Ref<VisualScriptNode> node = script->get_node(id);
- if (Object::cast_to<VisualScriptFunction>(*node)) {
- EditorNode::get_singleton()->show_warning(TTR("Can't copy the function node."));
- return;
- }
- if (node.is_valid()) {
- clipboard->nodes[id] = node->duplicate(true);
- clipboard->nodes_positions[id] = script->get_node_position(id);
- }
- }
- }
- }
-
- if (clipboard->nodes.is_empty()) {
- return;
- }
-
- List<VisualScript::SequenceConnection> sequence_connections;
- script->get_sequence_connection_list(&sequence_connections);
-
- for (const VisualScript::SequenceConnection &E : sequence_connections) {
- if (clipboard->nodes.has(E.from_node) && clipboard->nodes.has(E.to_node)) {
- clipboard->sequence_connections.insert(E);
- }
- }
-
- List<VisualScript::DataConnection> data_connections;
- script->get_data_connection_list(&data_connections);
-
- for (const VisualScript::DataConnection &E : data_connections) {
- if (clipboard->nodes.has(E.from_node) && clipboard->nodes.has(E.to_node)) {
- clipboard->data_connections.insert(E);
- }
- }
-}
-
-void VisualScriptEditor::_on_nodes_paste() {
- if (clipboard->nodes.is_empty()) {
- EditorNode::get_singleton()->show_warning(TTR("Clipboard is empty!"));
- return;
- }
-
- HashMap<int, int> remap;
-
- undo_redo->create_action(TTR("Paste VisualScript Nodes"));
- int idc = script->get_available_id() + 1;
-
- RBSet<int> to_select;
-
- RBSet<Vector2> existing_positions;
-
- {
- List<int> nodes;
- script->get_node_list(&nodes);
- for (int &E : nodes) {
- Vector2 pos = script->get_node_position(E).snapped(Vector2(2, 2));
- existing_positions.insert(pos);
- }
- }
-
- bool first_paste = true;
- Vector2 position_offset = Vector2(0, 0);
-
- for (KeyValue<int, Ref<VisualScriptNode>> &E : clipboard->nodes) {
- Ref<VisualScriptNode> node = E.value->duplicate();
-
- int new_id = idc++;
- to_select.insert(new_id);
-
- remap[E.key] = new_id;
-
- Vector2 paste_pos = clipboard->nodes_positions[E.key];
-
- if (first_paste) {
- position_offset = _get_pos_in_graph(mouse_up_position - graph->get_global_position()) - paste_pos;
- first_paste = false;
- }
-
- paste_pos += position_offset;
-
- while (existing_positions.has(paste_pos.snapped(Vector2(2, 2)))) {
- paste_pos += Vector2(20, 20) * EDSCALE;
- }
-
- undo_redo->add_do_method(script.ptr(), "add_node", new_id, node, paste_pos);
- undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
- }
-
- for (const VisualScript::SequenceConnection &E : clipboard->sequence_connections) {
- undo_redo->add_do_method(script.ptr(), "sequence_connect", remap[E.from_node], E.from_output, remap[E.to_node]);
- undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", remap[E.from_node], E.from_output, remap[E.to_node]);
- }
-
- for (const VisualScript::DataConnection &E : clipboard->data_connections) {
- undo_redo->add_do_method(script.ptr(), "data_connect", remap[E.from_node], E.from_port, remap[E.to_node], E.to_port);
- undo_redo->add_undo_method(script.ptr(), "data_disconnect", remap[E.from_node], E.from_port, remap[E.to_node], E.to_port);
- }
-
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
-
- undo_redo->commit_action();
-
- for (int i = 0; i < graph->get_child_count(); i++) {
- GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
- if (gn) {
- int id = gn->get_name().operator String().to_int();
- gn->set_selected(to_select.has(id));
- }
- }
-}
-
-void VisualScriptEditor::_on_nodes_delete() {
- // Delete all the selected nodes.
-
- List<int> to_erase;
-
- for (int i = 0; i < graph->get_child_count(); i++) {
- GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
- if (gn) {
- if (gn->is_selected() && gn->is_close_button_visible()) {
- to_erase.push_back(gn->get_name().operator String().to_int());
- }
- }
- }
-
- if (to_erase.is_empty()) {
- return;
- }
-
- undo_redo->create_action(TTR("Remove VisualScript Nodes"));
-
- for (int &F : to_erase) {
- int cr_node = F;
-
- undo_redo->add_do_method(script.ptr(), "remove_node", cr_node);
- undo_redo->add_undo_method(script.ptr(), "add_node", cr_node, script->get_node(cr_node), script->get_node_position(cr_node));
-
- List<VisualScript::SequenceConnection> sequence_conns;
- script->get_sequence_connection_list(&sequence_conns);
-
- for (const VisualScript::SequenceConnection &E : sequence_conns) {
- if (E.from_node == cr_node || E.to_node == cr_node) {
- undo_redo->add_undo_method(script.ptr(), "sequence_connect", E.from_node, E.from_output, E.to_node);
- }
- }
-
- List<VisualScript::DataConnection> data_conns;
- script->get_data_connection_list(&data_conns);
-
- for (const VisualScript::DataConnection &E : data_conns) {
- if (E.from_node == F || E.to_node == F) {
- undo_redo->add_undo_method(script.ptr(), "data_connect", E.from_node, E.from_port, E.to_node, E.to_port);
- }
- }
- }
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
-
- undo_redo->commit_action();
-}
-
-void VisualScriptEditor::_on_nodes_duplicate() {
- RBSet<int> to_duplicate;
-
- for (int i = 0; i < graph->get_child_count(); i++) {
- GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
- if (gn) {
- if (gn->is_selected() && gn->is_close_button_visible()) {
- int id = gn->get_name().operator String().to_int();
- to_duplicate.insert(id);
- }
- }
- }
-
- if (to_duplicate.is_empty()) {
- return;
- }
-
- undo_redo->create_action(TTR("Duplicate VisualScript Nodes"));
- int idc = script->get_available_id() + 1;
-
- RBSet<int> to_select;
- HashMap<int, int> remap;
-
- for (const int &F : to_duplicate) {
- // Duplicate from the specific function but place it into the default func as it would lack the connections.
- Ref<VisualScriptNode> node = script->get_node(F);
-
- Ref<VisualScriptNode> dupe = node->duplicate(true);
-
- int new_id = idc++;
- remap.insert(F, new_id);
-
- to_select.insert(new_id);
- undo_redo->add_do_method(script.ptr(), "add_node", new_id, dupe, script->get_node_position(F) + Vector2(20, 20));
- undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
- }
-
- List<VisualScript::SequenceConnection> seqs;
- script->get_sequence_connection_list(&seqs);
- for (const VisualScript::SequenceConnection &E : seqs) {
- if (to_duplicate.has(E.from_node) && to_duplicate.has(E.to_node)) {
- undo_redo->add_do_method(script.ptr(), "sequence_connect", remap[E.from_node], E.from_output, remap[E.to_node]);
- }
- }
-
- List<VisualScript::DataConnection> data;
- script->get_data_connection_list(&data);
- for (const VisualScript::DataConnection &E : data) {
- if (to_duplicate.has(E.from_node) && to_duplicate.has(E.to_node)) {
- undo_redo->add_do_method(script.ptr(), "data_connect", remap[E.from_node], E.from_port, remap[E.to_node], E.to_port);
- }
- }
-
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
-
- undo_redo->commit_action();
-
- for (int i = 0; i < graph->get_child_count(); i++) {
- GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
- if (gn) {
- int id = gn->get_name().operator String().to_int();
- gn->set_selected(to_select.has(id));
- }
- }
-
- if (to_select.size()) {
- EditorNode::get_singleton()->push_item(script->get_node(to_select.front()->get()).ptr());
- }
-}
-
-void VisualScriptEditor::_generic_search(Vector2 pos, bool node_centered) {
- if (node_centered) {
- port_action_pos = graph->get_size() / 2.0f;
- } else {
- port_action_pos = graph->get_viewport()->get_mouse_position() - graph->get_global_position();
- }
-
- new_connect_node_select->select_from_visual_script(script, false); // do not reset text
-}
-
-void VisualScriptEditor::input(const Ref<InputEvent> &p_event) {
- ERR_FAIL_COND(p_event.is_null());
-
- // GUI input for VS Editor Plugin
- Ref<InputEventMouseButton> key = p_event;
-
- if (key.is_valid() && key->is_pressed()) {
- mouse_up_position = get_screen_position() + get_local_mouse_position();
- }
-}
-
-void VisualScriptEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
- Ref<InputEventMouseButton> key = p_event;
-
- if (key.is_valid() && key->is_pressed() && key->get_button_mask() == MouseButton::RIGHT) {
- bool is_empty_selection = true;
-
- for (int i = 0; i < graph->get_child_count(); i++) {
- GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
- if (gn && gn->is_selected()) {
- is_empty_selection = false;
- break;
- }
- }
- if (is_empty_selection && clipboard->nodes.is_empty()) {
- _generic_search();
- } else {
- popup_menu->set_item_disabled(int(EDIT_CUT_NODES), is_empty_selection);
- popup_menu->set_item_disabled(int(EDIT_COPY_NODES), is_empty_selection);
- popup_menu->set_item_disabled(int(EDIT_PASTE_NODES), clipboard->nodes.is_empty());
- popup_menu->set_item_disabled(int(EDIT_DELETE_NODES), is_empty_selection);
- popup_menu->set_item_disabled(int(EDIT_DUPLICATE_NODES), is_empty_selection);
- popup_menu->set_item_disabled(int(EDIT_CLEAR_COPY_BUFFER), clipboard->nodes.is_empty());
-
- popup_menu->set_position(mouse_up_position);
- popup_menu->popup();
- }
- }
-}
-
-void VisualScriptEditor::_members_gui_input(const Ref<InputEvent> &p_event) {
- Ref<InputEventKey> key = p_event;
- if (key.is_valid() && key->is_pressed() && !key->is_echo()) {
- if (members->has_focus()) {
- TreeItem *ti = members->get_selected();
- if (ti) {
- TreeItem *root = members->get_root();
- if (ti->get_parent() == root->get_first_child()) {
- member_type = MEMBER_FUNCTION;
- }
- if (ti->get_parent() == root->get_first_child()->get_next()) {
- member_type = MEMBER_VARIABLE;
- }
- if (ti->get_parent() == root->get_first_child()->get_next()->get_next()) {
- member_type = MEMBER_SIGNAL;
- }
- member_name = ti->get_text(0);
- }
- if (ED_IS_SHORTCUT("ui_graph_delete", p_event)) {
- _member_option(MEMBER_REMOVE);
- }
- if (ED_IS_SHORTCUT("visual_script_editor/edit_member", p_event)) {
- _member_option(MEMBER_EDIT);
- }
- }
- }
-
- Ref<InputEventMouseButton> btn = p_event;
- if (btn.is_valid() && btn->is_double_click()) {
- TreeItem *ti = members->get_selected();
- if (ti && ti->get_parent() == members->get_root()->get_first_child()) { // to check if it's a function
- _center_on_node(script->get_function_node_id(ti->get_metadata(0)));
- }
- }
-}
-
-void VisualScriptEditor::_rename_function(const String &name, const String &new_name) {
- if (!new_name.is_valid_identifier()) {
- EditorNode::get_singleton()->show_warning(TTR("Name is not a valid identifier:") + " " + new_name);
- return;
- }
-
- if (script->has_function(new_name) || script->has_variable(new_name) || script->has_custom_signal(new_name)) {
- EditorNode::get_singleton()->show_warning(TTR("Name already in use by another func/var/signal:") + " " + new_name);
- return;
- }
-
- int node_id = script->get_function_node_id(name);
- Ref<VisualScriptFunction> func;
- if (script->has_node(node_id)) {
- func = script->get_node(node_id);
- }
- undo_redo->create_action(TTR("Rename Function"));
- undo_redo->add_do_method(script.ptr(), "rename_function", name, new_name);
- undo_redo->add_undo_method(script.ptr(), "rename_function", new_name, name);
- if (func.is_valid()) {
- undo_redo->add_do_method(func.ptr(), "set_name", new_name);
- undo_redo->add_undo_method(func.ptr(), "set_name", name);
- }
-
- // Also fix all function calls.
- List<int> lst;
- script->get_node_list(&lst);
- for (int &F : lst) {
- Ref<VisualScriptFunctionCall> fncall = script->get_node(F);
- if (!fncall.is_valid()) {
- continue;
- }
- if (fncall->get_function() == name) {
- undo_redo->add_do_method(fncall.ptr(), "set_function", new_name);
- undo_redo->add_undo_method(fncall.ptr(), "set_function", name);
- }
- }
-
- undo_redo->add_do_method(this, "_update_members");
- undo_redo->add_undo_method(this, "_update_members");
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
- undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
- undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
- undo_redo->commit_action();
-}
-
-void VisualScriptEditor::_fn_name_box_input(const Ref<InputEvent> &p_event) {
- if (!function_name_edit->is_visible()) {
- return;
- }
-
- Ref<InputEventKey> key = p_event;
- if (key.is_valid() && key->is_pressed() && key->get_keycode() == Key::ENTER) {
- function_name_edit->hide();
- _on_fn_name_box_confirmed();
- function_name_box->clear();
- }
-}
-
-void VisualScriptEditor::_on_fn_name_box_confirmed() {
- _rename_function(selected, function_name_box->get_text());
-}
-
-Variant VisualScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
- if (p_from == members) {
- TreeItem *it = members->get_item_at_position(p_point);
- if (!it) {
- return Variant();
- }
-
- String type = it->get_metadata(0);
-
- if (type.is_empty()) {
- return Variant();
- }
-
- Dictionary dd;
- TreeItem *root = members->get_root();
-
- if (it->get_parent() == root->get_first_child()) {
- dd["type"] = "visual_script_function_drag";
- dd["function"] = type;
- } else if (it->get_parent() == root->get_first_child()->get_next()) {
- dd["type"] = "visual_script_variable_drag";
- dd["variable"] = type;
- } else if (it->get_parent() == root->get_first_child()->get_next()->get_next()) {
- dd["type"] = "visual_script_signal_drag";
- dd["signal"] = type;
-
- } else {
- return Variant();
- }
-
- Label *label = memnew(Label);
- label->set_text(it->get_text(0));
- set_drag_preview(label);
- return dd;
- }
- return Variant();
-}
-
-bool VisualScriptEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
- if (p_from == graph) {
- Dictionary d = p_data;
- if (d.has("type") &&
- (String(d["type"]) == "visual_script_node_drag" ||
- String(d["type"]) == "visual_script_function_drag" ||
- String(d["type"]) == "visual_script_variable_drag" ||
- String(d["type"]) == "visual_script_signal_drag" ||
- String(d["type"]) == "obj_property" ||
- String(d["type"]) == "resource" ||
- String(d["type"]) == "files" ||
- String(d["type"]) == "nodes")) {
- if (String(d["type"]) == "obj_property") {
-#ifdef MACOS_ENABLED
- const_cast<VisualScriptEditor *>(this)->_show_hint(vformat(TTR("Hold %s to drop a Getter. Hold Shift to drop a generic signature."), find_keycode_name(Key::META)));
-#else
- const_cast<VisualScriptEditor *>(this)->_show_hint(TTR("Hold Ctrl to drop a Getter. Hold Shift to drop a generic signature."));
-#endif
- }
-
- if (String(d["type"]) == "nodes") {
-#ifdef MACOS_ENABLED
- const_cast<VisualScriptEditor *>(this)->_show_hint(vformat(TTR("Hold %s to drop a simple reference to the node."), find_keycode_name(Key::META)));
-#else
- const_cast<VisualScriptEditor *>(this)->_show_hint(TTR("Hold Ctrl to drop a simple reference to the node."));
-#endif
- }
-
- if (String(d["type"]) == "visual_script_variable_drag") {
-#ifdef MACOS_ENABLED
- const_cast<VisualScriptEditor *>(this)->_show_hint(vformat(TTR("Hold %s to drop a Variable Setter."), find_keycode_name(Key::META)));
-#else
- const_cast<VisualScriptEditor *>(this)->_show_hint(TTR("Hold Ctrl to drop a Variable Setter."));
-#endif
- }
-
- return true;
- }
- }
-
- return false;
-}
-
-static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) {
- if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene) {
- return nullptr;
- }
-
- Ref<Script> scr = p_current_node->get_script();
-
- if (scr.is_valid() && scr == script) {
- return p_current_node;
- }
-
- for (int i = 0; i < p_current_node->get_child_count(); i++) {
- Node *n = _find_script_node(p_edited_scene, p_current_node->get_child(i), script);
- if (n) {
- return n;
- }
- }
-
- return nullptr;
-}
-
-void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
- if (p_from != graph) {
- return;
- }
-
- Dictionary d = p_data;
-
- if (!d.has("type")) {
- return;
- }
-
- if (String(d["type"]) == "visual_script_node_drag") {
- if (!d.has("node_type") || String(d["node_type"]) == "Null") {
- return;
- }
-
- Vector2 pos = _get_pos_in_graph(p_point);
-
- int new_id = _create_new_node_from_name(d["node_type"], pos);
-
- Node *node = graph->get_node(itos(new_id));
- if (node) {
- graph->set_selected(node);
- _node_selected(node);
- }
- }
-
- if (String(d["type"]) == "visual_script_variable_drag") {
-#ifdef MACOS_ENABLED
- bool use_set = Input::get_singleton()->is_key_pressed(Key::META);
-#else
- bool use_set = Input::get_singleton()->is_key_pressed(Key::CTRL);
-#endif
- Vector2 pos = _get_pos_in_graph(p_point);
-
- Ref<VisualScriptNode> vnode;
- if (use_set) {
- Ref<VisualScriptPropertySet> pset;
- pset.instantiate();
- vnode = pset;
- } else {
- Ref<VisualScriptPropertyGet> pget;
- pget.instantiate();
- vnode = pget;
- }
-
- int new_id = script->get_available_id();
- undo_redo->create_action(TTR("Add Node"));
- undo_redo->add_do_method(vnode.ptr(), "set_property", d["variable"]);
- undo_redo->add_do_method(vnode.ptr(), "set_base_script", script->get_path());
-
- undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos);
- undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
- undo_redo->commit_action();
-
- Node *node = graph->get_node(itos(new_id));
- if (node) {
- graph->set_selected(node);
- _node_selected(node);
- }
- }
-
- if (String(d["type"]) == "visual_script_function_drag") {
- Vector2 pos = _get_pos_in_graph(p_point);
-
- Ref<VisualScriptFunctionCall> vnode;
- vnode.instantiate();
- vnode->set_call_mode(VisualScriptFunctionCall::CALL_MODE_SELF);
-
- int new_id = script->get_available_id();
-
- undo_redo->create_action(TTR("Add Node"));
- undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos);
- undo_redo->add_do_method(vnode.ptr(), "set_base_type", script->get_instance_base_type());
- undo_redo->add_do_method(vnode.ptr(), "set_function", d["function"]);
-
- undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
- undo_redo->commit_action();
-
- Node *node = graph->get_node(itos(new_id));
- if (node) {
- graph->set_selected(node);
- _node_selected(node);
- }
- }
-
- if (String(d["type"]) == "visual_script_signal_drag") {
- Vector2 pos = _get_pos_in_graph(p_point);
-
- Ref<VisualScriptEmitSignal> vnode;
- vnode.instantiate();
- vnode->set_signal(d["signal"]);
-
- int new_id = script->get_available_id();
-
- undo_redo->create_action(TTR("Add Node"));
- undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos);
- undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
- undo_redo->commit_action();
-
- Node *node = graph->get_node(itos(new_id));
- if (node) {
- graph->set_selected(node);
- _node_selected(node);
- }
- }
-
- if (String(d["type"]) == "resource") {
- Vector2 pos = _get_pos_in_graph(p_point);
-
- Ref<VisualScriptPreload> prnode;
- prnode.instantiate();
- prnode->set_preload(d["resource"]);
-
- int new_id = script->get_available_id();
-
- undo_redo->create_action(TTR("Add Preload Node"));
- undo_redo->add_do_method(script.ptr(), "add_node", new_id, prnode, pos);
- undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
- undo_redo->commit_action();
-
- Node *node = graph->get_node(itos(new_id));
- if (node) {
- graph->set_selected(node);
- _node_selected(node);
- }
- }
-
- if (String(d["type"]) == "files") {
-#ifdef MACOS_ENABLED
- bool use_preload = Input::get_singleton()->is_key_pressed(Key::META);
-#else
- bool use_preload = Input::get_singleton()->is_key_pressed(Key::CTRL);
-#endif
- Vector2 pos = _get_pos_in_graph(p_point);
-
- Array files = d["files"];
-
- List<int> new_ids;
- int new_id = script->get_available_id();
-
- if (files.size()) {
- undo_redo->create_action(TTR("Add Node(s)"));
-
- for (int i = 0; i < files.size(); i++) {
- Ref<Resource> res = ResourceLoader::load(files[i]);
- if (!res.is_valid()) {
- continue;
- }
- Ref<Script> drop_script = ResourceLoader::load(files[i]);
- if (drop_script.is_valid() && drop_script->is_tool() && drop_script->get_instance_base_type() == "VisualScriptCustomNode" && !use_preload) {
- Ref<VisualScriptCustomNode> vscn;
- vscn.instantiate();
- vscn->set_script(drop_script);
-
- undo_redo->add_do_method(script.ptr(), "add_node", new_id, vscn, pos);
- undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
- } else {
- Ref<VisualScriptPreload> prnode;
- prnode.instantiate();
- prnode->set_preload(res);
-
- undo_redo->add_do_method(script.ptr(), "add_node", new_id, prnode, pos);
- undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
- }
- new_ids.push_back(new_id);
- new_id++;
- pos += Vector2(20, 20);
- }
-
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
- undo_redo->commit_action();
- }
-
- for (int &E : new_ids) {
- Node *node = graph->get_node(itos(E));
- if (node) {
- graph->set_selected(node);
- _node_selected(node);
- }
- }
- }
-
- if (String(d["type"]) == "nodes") {
- Node *sn = _find_script_node(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root(), script);
-
- if (!sn) {
- EditorNode::get_singleton()->show_warning(vformat(TTR("Can't drop nodes because script '%s' is not used in this scene."), get_name()));
- return;
- }
-
-#ifdef MACOS_ENABLED
- bool use_node = Input::get_singleton()->is_key_pressed(Key::META);
-#else
- bool use_node = Input::get_singleton()->is_key_pressed(Key::CTRL);
-#endif
-
- Array nodes = d["nodes"];
-
- Vector2 pos = _get_pos_in_graph(p_point);
-
- undo_redo->create_action(TTR("Add Node(s) From Tree"));
- int base_id = script->get_available_id();
-
- if (use_node || nodes.size() > 1) {
- for (int i = 0; i < nodes.size(); i++) {
- NodePath np = nodes[i];
- Node *node = get_node(np);
- if (!node) {
- continue;
- }
-
- Ref<VisualScriptNode> n;
-
- Ref<VisualScriptSceneNode> scene_node;
- scene_node.instantiate();
- scene_node->set_node_path(sn->get_path_to(node));
- n = scene_node;
-
- undo_redo->add_do_method(script.ptr(), "add_node", base_id, n, pos);
- undo_redo->add_undo_method(script.ptr(), "remove_node", base_id);
-
- base_id++;
- pos += Vector2(25, 25);
- }
-
- } else {
- NodePath np = nodes[0];
- Node *node = get_node(np);
- drop_position = pos;
- drop_node = node;
- drop_path = sn->get_path_to(node);
- new_connect_node_select->select_from_instance(node, false);
- }
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
- undo_redo->commit_action();
- }
-
- if (String(d["type"]) == "obj_property") {
- Node *sn = _find_script_node(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root(), script);
-
- if (!sn && !Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
- EditorNode::get_singleton()->show_warning(vformat(TTR("Can't drop properties because script '%s' is not used in this scene.\nDrop holding 'Shift' to just copy the signature."), get_name()));
- return;
- }
-
- Object *obj = d["object"];
-
- if (!obj) {
- return;
- }
-
- Node *node = Object::cast_to<Node>(obj);
- Vector2 pos = _get_pos_in_graph(p_point);
-
-#ifdef MACOS_ENABLED
- bool use_get = Input::get_singleton()->is_key_pressed(Key::META);
-#else
- bool use_get = Input::get_singleton()->is_key_pressed(Key::CTRL);
-#endif
-
- if (!node || Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
- if (use_get) {
- undo_redo->create_action(TTR("Add Getter Property"));
- } else {
- undo_redo->create_action(TTR("Add Setter Property"));
- }
-
- int base_id = script->get_available_id();
-
- Ref<VisualScriptNode> vnode;
-
- if (!use_get) {
- Ref<VisualScriptPropertySet> pset;
- pset.instantiate();
- pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE);
- pset->set_base_type(obj->get_class());
- vnode = pset;
- } else {
- Ref<VisualScriptPropertyGet> pget;
- pget.instantiate();
- pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE);
- pget->set_base_type(obj->get_class());
- vnode = pget;
- }
-
- undo_redo->add_do_method(script.ptr(), "add_node", base_id, vnode, pos);
- undo_redo->add_do_method(vnode.ptr(), "set_property", d["property"]);
- if (!obj->get_script().is_null()) {
- undo_redo->add_do_method(vnode.ptr(), "set_base_script", Ref<Script>(obj->get_script())->get_path());
- }
- if (!use_get) {
- undo_redo->add_do_method(vnode.ptr(), "set_default_input_value", 0, d["value"]);
- }
-
- undo_redo->add_undo_method(script.ptr(), "remove_node", base_id);
-
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
- undo_redo->commit_action();
-
- } else {
- if (use_get) {
- undo_redo->create_action(TTR("Add Getter Property"));
- } else {
- undo_redo->create_action(TTR("Add Setter Property"));
- }
-
- int base_id = script->get_available_id();
-
- Ref<VisualScriptNode> vnode;
-
- if (!use_get) {
- Ref<VisualScriptPropertySet> pset;
- pset.instantiate();
- if (sn == node) {
- pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_SELF);
- } else {
- pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_NODE_PATH);
- pset->set_base_path(sn->get_path_to(node));
- }
- vnode = pset;
- } else {
- Ref<VisualScriptPropertyGet> pget;
- pget.instantiate();
- if (sn == node) {
- pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_SELF);
- } else {
- pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_NODE_PATH);
- pget->set_base_path(sn->get_path_to(node));
- }
- vnode = pget;
- }
- undo_redo->add_do_method(script.ptr(), "add_node", base_id, vnode, pos);
- undo_redo->add_do_method(vnode.ptr(), "set_property", d["property"]);
- if (!obj->get_script().is_null()) {
- undo_redo->add_do_method(vnode.ptr(), "set_base_script", Ref<Script>(obj->get_script())->get_path());
- }
- if (!use_get) {
- undo_redo->add_do_method(vnode.ptr(), "set_default_input_value", 0, d["value"]);
- }
-
- undo_redo->add_undo_method(script.ptr(), "remove_node", base_id);
-
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
- undo_redo->commit_action();
- }
- }
-}
-
-void VisualScriptEditor::_draw_color_over_button(Object *obj, Color p_color) {
- Button *button = Object::cast_to<Button>(obj);
- if (!button) {
- return;
- }
-
- Ref<StyleBox> normal = get_theme_stylebox(SNAME("normal"), SNAME("Button"));
- button->draw_rect(Rect2(normal->get_offset(), button->get_size() - normal->get_minimum_size()), p_color);
-}
-
-void VisualScriptEditor::_button_resource_previewed(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, Variant p_ud) {
- Array ud = p_ud;
- ERR_FAIL_COND(ud.size() != 2);
-
- ObjectID id = ud[0];
- Object *obj = ObjectDB::get_instance(id);
-
- if (!obj) {
- return;
- }
-
- Button *b = Object::cast_to<Button>(obj);
- ERR_FAIL_COND(!b);
-
- if (p_preview.is_null()) {
- b->set_text(ud[1]);
- } else {
- b->set_icon(p_preview);
- }
-}
-
-/////////////////////////
-
-void VisualScriptEditor::apply_code() {
-}
-
-Ref<Resource> VisualScriptEditor::get_edited_resource() const {
- return script;
-}
-
-void VisualScriptEditor::set_edited_resource(const Ref<Resource> &p_res) {
- ERR_FAIL_COND(script.is_valid());
- ERR_FAIL_COND(p_res.is_null());
- script = p_res;
- signal_editor->script = script;
- signal_editor->undo_redo = undo_redo;
- variable_editor->script = script;
- variable_editor->undo_redo = undo_redo;
-
- script->connect("node_ports_changed", callable_mp(this, &VisualScriptEditor::_node_ports_changed));
-
- _update_graph();
- call_deferred(SNAME("_update_members"));
-}
-
-void VisualScriptEditor::enable_editor() {
-}
-
-Vector<String> VisualScriptEditor::get_functions() {
- return Vector<String>();
-}
-
-void VisualScriptEditor::reload_text() {
-}
-
-String VisualScriptEditor::get_name() {
- String name;
-
- name = script->get_path().get_file();
- if (name.is_empty()) {
- // This appears for newly created built-in scripts before saving the scene.
- name = TTR("[unsaved]");
- } else if (script->is_built_in()) {
- const String &script_name = script->get_name();
- if (!script_name.is_empty()) {
- // If the built-in script has a custom resource name defined,
- // display the built-in script name as follows: `ResourceName (scene_file.tscn)`
- name = vformat("%s (%s)", script_name, name.get_slice("::", 0));
- }
- }
-
- if (is_unsaved()) {
- name += "(*)";
- }
-
- return name;
-}
-
-Ref<Texture2D> VisualScriptEditor::get_theme_icon() {
- String icon_name = "VisualScript";
- if (script->is_built_in()) {
- icon_name += "Internal";
- }
-
- if (Control::has_theme_icon(icon_name, "EditorIcons")) {
- return Control::get_theme_icon(icon_name, SNAME("EditorIcons"));
- }
-
- return Control::get_theme_icon(SNAME("VisualScript"), SNAME("EditorIcons"));
-}
-
-bool VisualScriptEditor::is_unsaved() {
- bool unsaved =
- script->is_edited() ||
- script->are_subnodes_edited() ||
- script->get_path().is_empty(); // In memory.
- return unsaved;
-}
-
-Variant VisualScriptEditor::get_edit_state() {
- Dictionary d;
- d["scroll"] = graph->get_scroll_ofs();
- d["zoom"] = graph->get_zoom();
- d["using_snap"] = graph->is_using_snap();
- d["snap"] = graph->get_snap();
- return d;
-}
-
-void VisualScriptEditor::set_edit_state(const Variant &p_state) {
- Dictionary d = p_state;
-
- _update_graph();
- _update_members();
-
- if (d.has("scroll")) {
- graph->set_scroll_ofs(d["scroll"]);
- }
- if (d.has("zoom")) {
- graph->set_zoom(d["zoom"]);
- }
- if (d.has("snap")) {
- graph->set_snap(d["snap"]);
- }
- if (d.has("snap_enabled")) {
- graph->set_use_snap(d["snap_enabled"]);
- }
-}
-
-void VisualScriptEditor::_center_on_node(int p_id) {
- Node *n = graph->get_node(itos(p_id));
- GraphNode *gn = Object::cast_to<GraphNode>(n);
-
- // Clear selection.
- for (int i = 0; i < graph->get_child_count(); i++) {
- GraphNode *gnd = Object::cast_to<GraphNode>(graph->get_child(i));
- if (gnd) {
- gnd->set_selected(false);
- }
- }
-
- if (gn) {
- gn->set_selected(true);
- Vector2 new_scroll = gn->get_position_offset() * graph->get_zoom() - graph->get_size() * 0.5 + gn->get_size() * 0.5;
- graph->set_scroll_ofs(new_scroll);
- script->set_scroll(new_scroll / EDSCALE);
- script->set_edited(true);
- }
-}
-
-void VisualScriptEditor::goto_line(int p_line, bool p_with_error) {
- p_line += 1; // Add one because script lines begin from 0.
-
- if (p_with_error) {
- error_line = p_line;
- }
-
- if (script->has_node(p_line)) {
- _update_graph();
- _update_members();
-
- call_deferred(SNAME("call_deferred"), "_center_on_node", p_line); // The editor might be just created and size might not exist yet.
- }
-}
-
-void VisualScriptEditor::set_executing_line(int p_line) {
- // todo: add a way to show which node is executing right now.
-}
-
-void VisualScriptEditor::clear_executing_line() {
- // todo: add a way to show which node is executing right now.
-}
-
-void VisualScriptEditor::trim_trailing_whitespace() {
-}
-
-void VisualScriptEditor::insert_final_newline() {
-}
-
-void VisualScriptEditor::convert_indent_to_spaces() {
-}
-
-void VisualScriptEditor::convert_indent_to_tabs() {
-}
-
-void VisualScriptEditor::ensure_focus() {
- graph->grab_focus();
-}
-
-void VisualScriptEditor::tag_saved_version() {
-}
-
-void VisualScriptEditor::reload(bool p_soft) {
- _update_graph();
-}
-
-Array VisualScriptEditor::get_breakpoints() {
- Array breakpoints;
- List<StringName> functions;
- script->get_function_list(&functions);
- for (int i = 0; i < functions.size(); i++) {
- List<int> nodes;
- script->get_node_list(&nodes);
- for (int &F : nodes) {
- Ref<VisualScriptNode> vsn = script->get_node(F);
- if (vsn->is_breakpoint()) {
- breakpoints.push_back(F - 1); // Subtract 1 because breakpoints in text start from zero.
- }
- }
- }
- return breakpoints;
-}
-
-void VisualScriptEditor::add_callback(const String &p_function, PackedStringArray p_args) {
- if (script->has_function(p_function)) {
- _update_members();
- _update_graph();
- _center_on_node(script->get_function_node_id(p_function));
- return;
- }
-
- Ref<VisualScriptFunction> func;
- func.instantiate();
- for (int i = 0; i < p_args.size(); i++) {
- String name = p_args[i];
- Variant::Type type = Variant::NIL;
-
- if (name.contains(":")) {
- String tt = name.get_slice(":", 1);
- name = name.get_slice(":", 0);
- for (int j = 0; j < Variant::VARIANT_MAX; j++) {
- String tname = Variant::get_type_name(Variant::Type(j));
- if (tname == tt) {
- type = Variant::Type(j);
- break;
- }
- }
- }
-
- func->add_argument(type, name);
- }
- int fn_id = script->get_available_id();
- func->set_name(p_function);
- script->add_function(p_function, fn_id);
- script->add_node(fn_id, func);
-
- _update_members();
- _update_graph();
-
- _center_on_node(script->get_function_node_id(p_function));
-}
-
-bool VisualScriptEditor::show_members_overview() {
- return false;
-}
-
-void VisualScriptEditor::update_settings() {
- _update_graph();
-}
-
-void VisualScriptEditor::set_debugger_active(bool p_active) {
- if (!p_active) {
- error_line = -1;
- _update_graph(); //clear line break
- }
-}
-
-Control *VisualScriptEditor::get_base_editor() const {
- return graph;
-}
-
-void VisualScriptEditor::set_tooltip_request_func(const Callable &p_toolip_callback) {
-}
-
-Control *VisualScriptEditor::get_edit_menu() {
- return edit_menu;
-}
-
-void VisualScriptEditor::_change_base_type() {
- select_base_type->popup_create(true, true);
-}
-
-void VisualScriptEditor::_toggle_tool_script() {
- script->set_tool_enabled(!script->is_tool());
-}
-
-void VisualScriptEditor::clear_edit_menu() {
- memdelete(edit_menu);
- memdelete(members_section);
-}
-
-void VisualScriptEditor::_change_base_type_callback() {
- String bt = select_base_type->get_selected_type();
-
- ERR_FAIL_COND(bt.is_empty());
- undo_redo->create_action(TTR("Change Base Type"));
- undo_redo->add_do_method(script.ptr(), "set_instance_base_type", bt);
- undo_redo->add_undo_method(script.ptr(), "set_instance_base_type", script->get_instance_base_type());
- undo_redo->add_do_method(this, "_update_members");
- undo_redo->add_undo_method(this, "_update_members");
- undo_redo->commit_action();
-}
-
-void VisualScriptEditor::_node_selected(Node *p_node) {
- Ref<VisualScriptNode> vnode = p_node->get_meta("__vnode");
- if (vnode.is_null()) {
- return;
- }
-
- EditorNode::get_singleton()->push_item(vnode.ptr()); //edit node in inspector
-}
-
-static bool _get_out_slot(const Ref<VisualScriptNode> &p_node, int p_slot, int &r_real_slot, bool &r_sequence) {
- if (p_slot < p_node->get_output_sequence_port_count()) {
- r_sequence = true;
- r_real_slot = p_slot;
-
- return true;
- }
-
- r_real_slot = p_slot - p_node->get_output_sequence_port_count();
- r_sequence = false;
-
- return (r_real_slot < p_node->get_output_value_port_count());
-}
-
-static bool _get_in_slot(const Ref<VisualScriptNode> &p_node, int p_slot, int &r_real_slot, bool &r_sequence) {
- if (p_slot == 0 && p_node->has_input_sequence_port()) {
- r_sequence = true;
- r_real_slot = 0;
- return true;
- }
-
- r_real_slot = p_slot - (p_node->has_input_sequence_port() ? 1 : 0);
- r_sequence = false;
-
- return r_real_slot < p_node->get_input_value_port_count();
-}
-
-void VisualScriptEditor::_begin_node_move() {
- undo_redo->create_action(TTR("Move Node(s)"));
-}
-
-void VisualScriptEditor::_end_node_move() {
- undo_redo->commit_action();
-}
-
-void VisualScriptEditor::_move_node(int p_id, const Vector2 &p_to) {
- if (!script->has_node(p_id)) {
- return;
- }
-
- Node *node = graph->get_node(itos(p_id));
-
- if (Object::cast_to<GraphNode>(node)) {
- Object::cast_to<GraphNode>(node)->set_position_offset(p_to);
- }
-
- script->set_node_position(p_id, p_to / EDSCALE);
-}
-
-void VisualScriptEditor::_node_moved(Vector2 p_from, Vector2 p_to, int p_id) {
- undo_redo->add_do_method(this, "_move_node", p_id, p_to);
- undo_redo->add_undo_method(this, "_move_node", p_id, p_from);
-}
-
-void VisualScriptEditor::_remove_node(int p_id) {
- undo_redo->create_action(TTR("Remove VisualScript Node"));
-
- undo_redo->add_do_method(script.ptr(), "remove_node", p_id);
- undo_redo->add_undo_method(script.ptr(), "add_node", p_id, script->get_node(p_id), script->get_node_position(p_id));
-
- List<VisualScript::SequenceConnection> sequence_conns;
- script->get_sequence_connection_list(&sequence_conns);
-
- for (const VisualScript::SequenceConnection &E : sequence_conns) {
- if (E.from_node == p_id || E.to_node == p_id) {
- undo_redo->add_undo_method(script.ptr(), "sequence_connect", E.from_node, E.from_output, E.to_node);
- }
- }
-
- List<VisualScript::DataConnection> data_conns;
- script->get_data_connection_list(&data_conns);
-
- for (const VisualScript::DataConnection &E : data_conns) {
- if (E.from_node == p_id || E.to_node == p_id) {
- undo_redo->add_undo_method(script.ptr(), "data_connect", E.from_node, E.from_port, E.to_node, E.to_port);
- }
- }
-
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
-
- undo_redo->commit_action();
-}
-
-void VisualScriptEditor::_node_ports_changed(int p_id) {
- _update_graph(p_id);
-}
-
-bool VisualScriptEditor::node_has_sequence_connections(int p_id) {
- List<VisualScript::SequenceConnection> sequence_conns;
- script->get_sequence_connection_list(&sequence_conns);
-
- for (const VisualScript::SequenceConnection &E : sequence_conns) {
- int from = E.from_node;
- int to = E.to_node;
-
- if (to == p_id || from == p_id) {
- return true;
- }
- }
-
- return false;
-}
-
-void VisualScriptEditor::_graph_connected(const String &p_from, int p_from_slot, const String &p_to, int p_to_slot) {
- Ref<VisualScriptNode> from_node = script->get_node(p_from.to_int());
- ERR_FAIL_COND(!from_node.is_valid());
-
- bool from_seq;
- int from_port;
-
- if (!_get_out_slot(from_node, p_from_slot, from_port, from_seq)) {
- return; //can't connect this, it's invalid
- }
-
- Ref<VisualScriptNode> to_node = script->get_node(p_to.to_int());
- ERR_FAIL_COND(!to_node.is_valid());
-
- bool to_seq;
- int to_port;
-
- if (!_get_in_slot(to_node, p_to_slot, to_port, to_seq)) {
- return; //can't connect this, it's invalid
- }
-
- ERR_FAIL_COND(from_seq != to_seq);
-
- // Checking to prevent warnings.
- if (from_seq) {
- if (script->has_sequence_connection(p_from.to_int(), from_port, p_to.to_int())) {
- return;
- }
- } else if (script->has_data_connection(p_from.to_int(), from_port, p_to.to_int(), to_port)) {
- return;
- }
-
- // Preventing connection to itself.
- if (p_from.to_int() == p_to.to_int()) {
- return;
- }
-
- // Do all the checks here.
- StringName func; // This the func where we store the one the nodes at the end of the resolution on having multiple nodes.
-
- undo_redo->create_action(TTR("Connect Nodes"));
-
- if (from_seq) {
- undo_redo->add_do_method(script.ptr(), "sequence_connect", p_from.to_int(), from_port, p_to.to_int());
- // This undo error on undo after move can't be removed without painful gymnastics
- undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", p_from.to_int(), from_port, p_to.to_int());
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
- } else {
- bool converted = false;
-
- Ref<VisualScriptOperator> oper = to_node;
- if (oper.is_valid() && oper->get_typed() == Variant::NIL) {
- // It's an operator Node and if the type is already nil
- if (from_node->get_output_value_port_info(from_port).type != Variant::NIL) {
- oper->set_typed(from_node->get_output_value_port_info(from_port).type);
- }
- }
-
- Ref<VisualScriptOperator> operf = from_node;
- if (operf.is_valid() && operf->get_typed() == Variant::NIL) {
- // It's an operator Node and if the type is already nil
- if (to_node->get_input_value_port_info(to_port).type != Variant::NIL) {
- operf->set_typed(to_node->get_input_value_port_info(to_port).type);
- }
- }
-
- // Disconnect current, and connect the new one
- if (script->is_input_value_port_connected(p_to.to_int(), to_port)) {
- if (can_swap && data_disconnect_node == p_to.to_int()) {
- int conn_from;
- int conn_port;
- script->get_input_value_port_connection_source(p_to.to_int(), to_port, &conn_from, &conn_port);
- undo_redo->add_do_method(script.ptr(), "data_disconnect", conn_from, conn_port, p_to.to_int(), to_port);
- undo_redo->add_do_method(script.ptr(), "data_connect", conn_from, conn_port, data_disconnect_node, data_disconnect_port);
- undo_redo->add_undo_method(script.ptr(), "data_disconnect", conn_from, conn_port, data_disconnect_node, data_disconnect_port);
- undo_redo->add_undo_method(script.ptr(), "data_connect", conn_from, conn_port, p_to.to_int(), to_port);
- can_swap = false; // swapped
- } else {
- int conn_from;
- int conn_port;
- script->get_input_value_port_connection_source(p_to.to_int(), to_port, &conn_from, &conn_port);
- undo_redo->add_do_method(script.ptr(), "data_disconnect", conn_from, conn_port, p_to.to_int(), to_port);
- undo_redo->add_undo_method(script.ptr(), "data_connect", conn_from, conn_port, p_to.to_int(), to_port);
- }
- }
- if (!converted) {
- undo_redo->add_do_method(script.ptr(), "data_connect", p_from.to_int(), from_port, p_to.to_int(), to_port);
- undo_redo->add_undo_method(script.ptr(), "data_disconnect", p_from.to_int(), from_port, p_to.to_int(), to_port);
-
- // Update nodes in graph
- undo_redo->add_do_method(this, "_update_graph", p_from.to_int());
- undo_redo->add_do_method(this, "_update_graph", p_to.to_int());
- undo_redo->add_undo_method(this, "_update_graph", p_from.to_int());
- undo_redo->add_undo_method(this, "_update_graph", p_to.to_int());
- } else {
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
- }
- }
-
- undo_redo->commit_action();
-}
-
-void VisualScriptEditor::_graph_disconnected(const String &p_from, int p_from_slot, const String &p_to, int p_to_slot) {
- Ref<VisualScriptNode> from_node = script->get_node(p_from.to_int());
- ERR_FAIL_COND(!from_node.is_valid());
-
- bool from_seq;
- int from_port;
-
- if (!_get_out_slot(from_node, p_from_slot, from_port, from_seq)) {
- return; // Can't connect this, it's invalid.
- }
-
- Ref<VisualScriptNode> to_node = script->get_node(p_to.to_int());
- ERR_FAIL_COND(!to_node.is_valid());
-
- bool to_seq;
- int to_port;
-
- if (!_get_in_slot(to_node, p_to_slot, to_port, to_seq)) {
- return; // Can't connect this, it's invalid.
- }
-
- ERR_FAIL_COND(from_seq != to_seq);
-
- undo_redo->create_action(TTR("Disconnect Nodes"));
-
- if (from_seq) {
- undo_redo->add_do_method(script.ptr(), "sequence_disconnect", p_from.to_int(), from_port, p_to.to_int());
- undo_redo->add_undo_method(script.ptr(), "sequence_connect", p_from.to_int(), from_port, p_to.to_int());
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
- } else {
- can_swap = true;
- data_disconnect_node = p_to.to_int();
- data_disconnect_port = to_port;
-
- undo_redo->add_do_method(script.ptr(), "data_disconnect", p_from.to_int(), from_port, p_to.to_int(), to_port);
- undo_redo->add_undo_method(script.ptr(), "data_connect", p_from.to_int(), from_port, p_to.to_int(), to_port);
- // Update relevant nodes in the graph.
- undo_redo->add_do_method(this, "_update_graph", p_from.to_int());
- undo_redo->add_do_method(this, "_update_graph", p_to.to_int());
- undo_redo->add_undo_method(this, "_update_graph", p_from.to_int());
- undo_redo->add_undo_method(this, "_update_graph", p_to.to_int());
- }
-
- undo_redo->commit_action();
-}
-
-void VisualScriptEditor::_graph_connect_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_pos) {
- Node *node = graph->get_node(p_from);
- GraphNode *gn = Object::cast_to<GraphNode>(node);
- if (!gn) {
- return;
- }
-
- Ref<VisualScriptNode> vsn = script->get_node(p_from.to_int());
- if (!vsn.is_valid()) {
- return;
- }
- if (vsn->get_output_value_port_count() || vsn->get_output_sequence_port_count()) {
- port_action_pos = p_release_pos;
- }
-
- if (p_from_slot < vsn->get_output_sequence_port_count()) {
- port_action_node = p_from.to_int();
- port_action_output = p_from_slot;
- _port_action_menu(CREATE_ACTION);
- } else {
- port_action_output = p_from_slot - vsn->get_output_sequence_port_count();
- port_action_node = p_from.to_int();
- _port_action_menu(CREATE_CALL_SET_GET);
- }
-}
-
-VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_port_action_node, int p_port_action_output, RBSet<int> &visited_nodes) {
- VisualScriptNode::TypeGuess tg;
- tg.type = Variant::NIL;
-
- if (visited_nodes.has(p_port_action_node)) {
- return tg; //no loop
- }
-
- visited_nodes.insert(p_port_action_node);
-
- Ref<VisualScriptNode> node = script->get_node(p_port_action_node);
-
- if (!node.is_valid() || node->get_output_value_port_count() <= p_port_action_output) {
- return tg;
- }
-
- Vector<VisualScriptNode::TypeGuess> in_guesses;
-
- for (int i = 0; i < node->get_input_value_port_count(); i++) {
- PropertyInfo pi = node->get_input_value_port_info(i);
- VisualScriptNode::TypeGuess g;
- g.type = pi.type;
-
- if (g.type == Variant::NIL || g.type == Variant::OBJECT) {
- // Any or object input, must further guess what this is.
- int from_node;
- int from_port;
-
- if (script->get_input_value_port_connection_source(p_port_action_node, i, &from_node, &from_port)) {
- g = _guess_output_type(from_node, from_port, visited_nodes);
- } else {
- Variant defval = node->get_default_input_value(i);
- if (defval.get_type() == Variant::OBJECT) {
- Object *obj = defval;
-
- if (obj) {
- g.type = Variant::OBJECT;
- g.gdclass = obj->get_class();
- g.script = obj->get_script();
- }
- }
- }
- }
-
- in_guesses.push_back(g);
- }
-
- return node->guess_output_type(in_guesses.ptrw(), p_port_action_output);
-}
-
-void VisualScriptEditor::_port_action_menu(int p_option) {
- RBSet<int> vn;
-
- switch (p_option) {
- case CREATE_CALL_SET_GET: {
- Ref<VisualScriptFunctionCall> n;
- n.instantiate();
-
- VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);
-
- if (tg.gdclass != StringName()) {
- n->set_base_type(tg.gdclass);
- } else {
- n->set_base_type("Object");
- }
- String type_string;
- String base_script = "";
- if (script->get_node(port_action_node)->get_output_value_port_count() > 0) {
- type_string = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint_string;
- VisualScriptFunctionCall *vsfc = Object::cast_to<VisualScriptFunctionCall>(*script->get_node(port_action_node));
- if (vsfc) {
- base_script = vsfc->get_base_script();
- } else {
- VisualScriptPropertyGet *vspg = Object::cast_to<VisualScriptPropertyGet>(*script->get_node(port_action_node));
- if (vspg) {
- base_script = vspg->get_base_script();
- } else {
- VisualScriptPropertySet *vsps = Object::cast_to<VisualScriptPropertySet>(*script->get_node(port_action_node));
- if (vsps) {
- base_script = vsps->get_base_script();
- }
- }
- }
- }
- if (tg.type == Variant::OBJECT) {
- if (tg.script.is_valid()) {
- new_connect_node_select->select_from_script(tg.script);
- } else if (type_string != String()) {
- new_connect_node_select->select_from_base_type(type_string, base_script);
- } else {
- new_connect_node_select->select_from_base_type(n->get_base_type(), base_script);
- }
- } else if (tg.type == Variant::NIL) {
- new_connect_node_select->select_from_base_type("", base_script);
- } else {
- new_connect_node_select->select_from_basic_type(tg.type);
- }
- // Ensure that the dialog fits inside the graph.
- Vector2 pos = mouse_up_position;
- Size2 bounds = graph->get_global_position() + graph->get_size() - new_connect_node_select->get_size();
- pos.x = pos.x > bounds.x ? bounds.x : pos.x;
- pos.y = pos.y > bounds.y ? bounds.y : pos.y;
- new_connect_node_select->set_position(pos);
- } break;
- case CREATE_ACTION: {
- VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);
- PropertyInfo property_info;
- if (script->get_node(port_action_node)->get_output_value_port_count() > 0) {
- property_info = script->get_node(port_action_node)->get_output_value_port_info(port_action_output);
- }
- if (tg.type == Variant::OBJECT) {
- if (property_info.type == Variant::OBJECT && !property_info.hint_string.is_empty()) {
- new_connect_node_select->select_from_action(property_info.hint_string);
- } else {
- new_connect_node_select->select_from_action("");
- }
- } else if (tg.type == Variant::NIL) {
- new_connect_node_select->select_from_action("");
- } else {
- new_connect_node_select->select_from_action(Variant::get_type_name(tg.type));
- }
- // Ensure that the dialog fits inside the graph.
- Vector2 pos = mouse_up_position;
- Size2 bounds = graph->get_global_position() + graph->get_size() - new_connect_node_select->get_size();
- pos.x = pos.x > bounds.x ? bounds.x : pos.x;
- pos.y = pos.y > bounds.y ? bounds.y : pos.y;
- new_connect_node_select->set_position(pos);
- } break;
- }
-}
-
-void VisualScriptEditor::connect_data(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode, int new_id) {
- undo_redo->create_action(TTR("Connect Node Data"));
- VisualScriptReturn *vnode_return = Object::cast_to<VisualScriptReturn>(vnode.ptr());
- if (vnode_return != nullptr && vnode_old->get_output_value_port_count() > 0) {
- vnode_return->set_enable_return_value(true);
- }
- if (vnode_old->get_output_value_port_count() <= 0) {
- undo_redo->commit_action();
- return;
- }
- if (vnode->get_input_value_port_count() <= 0) {
- undo_redo->commit_action();
- return;
- }
- int port = port_action_output;
- int value_count = vnode_old->get_output_value_port_count();
- if (port >= value_count) {
- port = 0;
- }
- undo_redo->add_do_method(script.ptr(), "data_connect", port_action_node, port, new_id, 0);
- undo_redo->add_undo_method(script.ptr(), "data_disconnect", port_action_node, port, new_id, 0);
- undo_redo->commit_action();
-}
-
-void VisualScriptEditor::_selected_connect_node(const String &p_text, const String &p_category, const bool p_connecting) {
-#ifdef MACOS_ENABLED
- bool held_ctrl = Input::get_singleton()->is_key_pressed(Key::META);
-#else
- bool held_ctrl = Input::get_singleton()->is_key_pressed(Key::CTRL);
-#endif
- Vector2 pos = _get_pos_in_graph(port_action_pos);
-
- RBSet<int> vn;
- bool port_node_exists = true;
-
- if (drop_position != Vector2()) {
- pos = drop_position;
- }
- drop_position = Vector2();
-
- Ref<VisualScriptNode> vnode;
- Ref<VisualScriptNode> vnode_old;
- if (port_node_exists && p_connecting) {
- vnode_old = script->get_node(port_action_node);
- }
-
- if (p_category.begins_with("VisualScriptNode")) {
- Ref<VisualScriptNode> n = VisualScriptLanguage::singleton->create_node_from_name(p_text);
-
- if (Object::cast_to<VisualScriptTypeCast>(n.ptr()) && vnode_old.is_valid()) {
- Variant::Type type = vnode_old->get_output_value_port_info(port_action_output).type;
- String hint_name = vnode_old->get_output_value_port_info(port_action_output).hint_string;
-
- if (type == Variant::OBJECT) {
- Object::cast_to<VisualScriptTypeCast>(n.ptr())->set_base_type(hint_name);
- } else if (type == Variant::NIL) {
- Object::cast_to<VisualScriptTypeCast>(n.ptr())->set_base_type("");
- } else {
- Object::cast_to<VisualScriptTypeCast>(n.ptr())->set_base_type(Variant::get_type_name(type));
- }
- }
- vnode = n;
- }
-
- if (p_category == String("Class") && !p_connecting) {
- Ref<VisualScriptFunctionCall> n;
- n.instantiate();
- n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_SINGLETON);
- n->set_singleton("ClassDB");
- n->set_function("instantiate");
- // Did not find a way to edit the input port value
- vnode = n;
- } else if (p_category == String("class_method")) {
- Ref<VisualScriptFunctionCall> n;
- n.instantiate();
- if (!drop_path.is_empty()) {
- if (drop_path == ".") {
- n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_SELF);
- } else {
- n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_NODE_PATH);
- n->set_base_path(drop_path);
- }
- } else {
- n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE);
- }
- if (drop_node) {
- n->set_base_type(drop_node->get_class());
- if (drop_node->get_script_instance()) {
- n->set_base_script(drop_node->get_script_instance()->get_script()->get_path());
- }
- }
- vnode = n;
- } else if (p_category == String("class_property")) {
- Vector<String> property_path = p_text.split(":");
- if (held_ctrl) {
- Ref<VisualScriptPropertySet> n;
- n.instantiate();
- n->set_property(property_path[1]);
- if (!drop_path.is_empty()) {
- if (drop_path == ".") {
- n->set_call_mode(VisualScriptPropertySet::CALL_MODE_SELF);
- } else {
- n->set_call_mode(VisualScriptPropertySet::CALL_MODE_NODE_PATH);
- n->set_base_path(drop_path);
- }
- }
- if (drop_node) {
- n->set_base_type(drop_node->get_class());
- if (drop_node->get_script_instance()) {
- n->set_base_script(drop_node->get_script_instance()->get_script()->get_path());
- }
- }
- vnode = n;
- } else {
- Ref<VisualScriptPropertyGet> n;
- n.instantiate();
- n->set_property(property_path[1]);
- if (!drop_path.is_empty()) {
- if (drop_path == ".") {
- n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_SELF);
- } else {
- n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_NODE_PATH);
- n->set_base_path(drop_path);
- }
- }
- if (drop_node) {
- n->set_base_type(drop_node->get_class());
- if (drop_node->get_script_instance()) {
- n->set_base_script(drop_node->get_script_instance()->get_script()->get_path());
- }
- }
- vnode = n;
- }
- } else if (p_category == String("class_constant")) {
- Vector<String> property_path = p_text.split(":");
- if (ClassDB::class_exists(property_path[0])) {
- Ref<VisualScriptClassConstant> n;
- n.instantiate();
- n->set_base_type(property_path[0]);
- n->set_class_constant(property_path[1]);
- vnode = n;
- } else {
- Ref<VisualScriptBasicTypeConstant> n;
- n.instantiate();
- if (property_path[0] == "Nil") {
- n->set_basic_type(Variant::NIL);
- } else if (property_path[0] == "bool") {
- n->set_basic_type(Variant::BOOL);
- } else if (property_path[0] == "int") {
- n->set_basic_type(Variant::INT);
- } else if (property_path[0] == "float") {
- n->set_basic_type(Variant::FLOAT);
- } else if (property_path[0] == "String") {
- n->set_basic_type(Variant::STRING);
- } else if (property_path[0] == "Vector2") {
- n->set_basic_type(Variant::VECTOR2);
- } else if (property_path[0] == "Vector2i") {
- n->set_basic_type(Variant::VECTOR2I);
- } else if (property_path[0] == "Rect2") {
- n->set_basic_type(Variant::RECT2);
- } else if (property_path[0] == "Rect2i") {
- n->set_basic_type(Variant::RECT2I);
- } else if (property_path[0] == "Transform2D") {
- n->set_basic_type(Variant::TRANSFORM2D);
- } else if (property_path[0] == "Vector3") {
- n->set_basic_type(Variant::VECTOR3);
- } else if (property_path[0] == "Vector3i") {
- n->set_basic_type(Variant::VECTOR3I);
- } else if (property_path[0] == "Plane") {
- n->set_basic_type(Variant::PLANE);
- } else if (property_path[0] == "ABB") {
- n->set_basic_type(Variant::AABB);
- } else if (property_path[0] == "Quaternion") {
- n->set_basic_type(Variant::QUATERNION);
- } else if (property_path[0] == "Basis") {
- n->set_basic_type(Variant::BASIS);
- } else if (property_path[0] == "Transform3D") {
- n->set_basic_type(Variant::TRANSFORM3D);
- } else if (property_path[0] == "Color") {
- n->set_basic_type(Variant::COLOR);
- } else if (property_path[0] == "RID") {
- n->set_basic_type(Variant::RID);
- } else if (property_path[0] == "Object") {
- n->set_basic_type(Variant::OBJECT);
- } else if (property_path[0] == "Callable") {
- n->set_basic_type(Variant::CALLABLE);
- } else if (property_path[0] == "Signal") {
- n->set_basic_type(Variant::SIGNAL);
- } else if (property_path[0] == "StringName") {
- n->set_basic_type(Variant::STRING_NAME);
- } else if (property_path[0] == "NodePath") {
- n->set_basic_type(Variant::NODE_PATH);
- } else if (property_path[0] == "Dictionary") {
- n->set_basic_type(Variant::DICTIONARY);
- } else if (property_path[0] == "Array") {
- n->set_basic_type(Variant::ARRAY);
- } else if (property_path[0] == "PackedByteArray") {
- n->set_basic_type(Variant::PACKED_BYTE_ARRAY);
- } else if (property_path[0] == "PackedInt32Array") {
- n->set_basic_type(Variant::PACKED_INT32_ARRAY);
- } else if (property_path[0] == "PackedInt64Array") {
- n->set_basic_type(Variant::PACKED_INT64_ARRAY);
- } else if (property_path[0] == "PackedFloat32Array") {
- n->set_basic_type(Variant::PACKED_FLOAT32_ARRAY);
- } else if (property_path[0] == "PackedStringArray") {
- n->set_basic_type(Variant::PACKED_STRING_ARRAY);
- } else if (property_path[0] == "PackedVector2Array") {
- n->set_basic_type(Variant::PACKED_VECTOR2_ARRAY);
- } else if (property_path[0] == "PackedVector3Array") {
- n->set_basic_type(Variant::PACKED_VECTOR3_ARRAY);
- } else if (property_path[0] == "PackedColorArray") {
- n->set_basic_type(Variant::PACKED_COLOR_ARRAY);
- }
- n->set_basic_type_constant(property_path[1]);
- vnode = n;
- }
-
- } else if (p_category == String("class_signal")) {
- Vector<String> property_path = p_text.split(":");
- ERR_FAIL_COND(!(script->has_custom_signal(property_path[1]) || ClassDB::has_signal(script->get_instance_base_type(), property_path[1])));
-
- Ref<VisualScriptEmitSignal> n;
- n.instantiate();
- n->set_signal(property_path[1]);
- vnode = n;
- }
- if (vnode == nullptr) {
- print_error("Category not handled: " + p_category.quote());
- }
-
- if (Object::cast_to<VisualScriptFunctionCall>(vnode.ptr()) && p_category != "Class" && p_category != "VisualScriptNode") {
- Vector<String> property_path = p_text.split(":");
- String class_of_method = property_path[0];
- String method_name = property_path[1];
-
- Ref<VisualScriptFunctionCall> vsfc = vnode;
- vsfc->set_function(method_name);
-
- if (port_node_exists && p_connecting) {
- VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);
-
- if (tg.type == Variant::OBJECT) {
- vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE);
- vsfc->set_base_type(String(""));
- if (tg.gdclass != StringName()) {
- vsfc->set_base_type(tg.gdclass);
- } else if (script->get_node(port_action_node).is_valid()) {
- PropertyHint hint = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint;
- String base_type = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint_string;
-
- if (!base_type.is_empty() && hint == PROPERTY_HINT_TYPE_STRING) {
- vsfc->set_base_type(base_type);
- }
- if (method_name == "call" || method_name == "call_deferred") {
- vsfc->set_function(String(""));
- }
- }
- if (tg.script.is_valid()) {
- vsfc->set_base_script(tg.script->get_path());
- }
- } else if (tg.type == Variant::NIL) {
- vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE);
- vsfc->set_base_type(String(""));
- } else {
- vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE);
- vsfc->set_basic_type(tg.type);
- }
- }
- }
-
- if (port_node_exists && p_connecting) {
- if (Object::cast_to<VisualScriptPropertySet>(vnode.ptr())) {
- Ref<VisualScriptPropertySet> vsp = vnode;
-
- VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);
- if (tg.type == Variant::OBJECT) {
- vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE);
- vsp->set_base_type(String(""));
- if (tg.gdclass != StringName()) {
- vsp->set_base_type(tg.gdclass);
-
- } else if (script->get_node(port_action_node).is_valid()) {
- PropertyHint hint = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint;
- String base_type = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint_string;
-
- if (!base_type.is_empty() && hint == PROPERTY_HINT_TYPE_STRING) {
- vsp->set_base_type(base_type);
- }
- }
- if (tg.script.is_valid()) {
- vsp->set_base_script(tg.script->get_path());
- }
- } else if (tg.type == Variant::NIL) {
- vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE);
- vsp->set_base_type(String(""));
- } else {
- vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_BASIC_TYPE);
- vsp->set_basic_type(tg.type);
- }
- }
-
- if (Object::cast_to<VisualScriptPropertyGet>(vnode.ptr())) {
- Ref<VisualScriptPropertyGet> vsp = vnode;
-
- VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);
- if (tg.type == Variant::OBJECT) {
- vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE);
- vsp->set_base_type(String(""));
- if (tg.gdclass != StringName()) {
- vsp->set_base_type(tg.gdclass);
-
- } else if (script->get_node(port_action_node).is_valid()) {
- PropertyHint hint = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint;
- String base_type = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint_string;
- if (!base_type.is_empty() && hint == PROPERTY_HINT_TYPE_STRING) {
- vsp->set_base_type(base_type);
- }
- }
- if (tg.script.is_valid()) {
- vsp->set_base_script(tg.script->get_path());
- }
- } else if (tg.type == Variant::NIL) {
- vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE);
- vsp->set_base_type(String(""));
- } else {
- vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_BASIC_TYPE);
- vsp->set_basic_type(tg.type);
- }
- }
- }
- if (vnode == nullptr) {
- print_error("Not able to create node from category: \"" + p_category + "\" and text \"" + p_text + "\" Not created");
- return;
- }
-
- int new_id = script->get_available_id();
- undo_redo->create_action(TTR("Add Node"));
- undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos);
- undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
- undo_redo->add_do_method(this, "_update_graph", new_id);
- undo_redo->add_undo_method(this, "_update_graph", new_id);
- undo_redo->commit_action();
-
- port_action_new_node = new_id;
-
- String base_script = "";
- String base_type = "";
- if (port_node_exists) {
- if (vnode_old.is_valid()) {
- if (Object::cast_to<VisualScriptTypeCast>(vnode_old.ptr())) {
- base_type = Object::cast_to<VisualScriptTypeCast>(vnode_old.ptr())->get_base_type();
- base_script = Object::cast_to<VisualScriptTypeCast>(vnode_old.ptr())->get_base_script();
- } else if (Object::cast_to<VisualScriptFunctionCall>(vnode_old.ptr())) {
- base_type = Object::cast_to<VisualScriptFunctionCall>(vnode_old.ptr())->get_base_type();
- base_script = Object::cast_to<VisualScriptFunctionCall>(vnode_old.ptr())->get_base_script();
- } else if (Object::cast_to<VisualScriptPropertySet>(vnode_old.ptr())) {
- base_type = Object::cast_to<VisualScriptPropertySet>(vnode_old.ptr())->get_base_type();
- base_script = Object::cast_to<VisualScriptPropertySet>(vnode_old.ptr())->get_base_script();
- } else if (Object::cast_to<VisualScriptPropertyGet>(vnode_old.ptr())) {
- base_type = Object::cast_to<VisualScriptPropertyGet>(vnode_old.ptr())->get_base_type();
- base_script = Object::cast_to<VisualScriptPropertyGet>(vnode_old.ptr())->get_base_script();
- }
- }
-
- Vector<String> property_path = p_text.split(":");
- if (ClassDB::is_parent_class(script->get_instance_base_type(), property_path[0]) || script->get_path().ends_with(property_path[0].unquote())) {
- if (!p_connecting) {
- base_type = script->get_instance_base_type();
- base_script = script->get_path();
- }
- } else {
- base_type = property_path[0];
- base_script = "";
- }
-
- if (drop_node) {
- Ref<Script> script = drop_node->get_script();
- if (script != nullptr) {
- base_script = script->get_path();
- }
- }
-
- if (vnode_old.is_valid() && p_connecting) {
- if (base_type == "") {
- base_type = property_path[0];
- } else if (ClassDB::is_parent_class(property_path[0], base_type)) {
- base_type = property_path[0];
- }
- connect_seq(vnode_old, vnode, port_action_new_node);
- connect_data(vnode_old, vnode, port_action_new_node);
- }
- }
- if (Object::cast_to<VisualScriptTypeCast>(vnode.ptr())) {
- Object::cast_to<VisualScriptTypeCast>(vnode.ptr())->set_base_type(base_type);
- Object::cast_to<VisualScriptTypeCast>(vnode.ptr())->set_base_script(base_script);
- } else if (Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())) {
- if (base_type_map.has(base_type)) {
- Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_basic_type(base_type_map[base_type]);
- Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE);
- } else {
- Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_base_type(base_type);
- Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_base_script(base_script);
- }
- } else if (Object::cast_to<VisualScriptPropertySet>(vnode.ptr())) {
- Object::cast_to<VisualScriptPropertySet>(vnode.ptr())->set_base_type(base_type);
- Object::cast_to<VisualScriptPropertySet>(vnode.ptr())->set_base_script(base_script);
- } else if (Object::cast_to<VisualScriptPropertyGet>(vnode.ptr())) {
- Object::cast_to<VisualScriptPropertyGet>(vnode.ptr())->set_base_type(base_type);
- Object::cast_to<VisualScriptPropertyGet>(vnode.ptr())->set_base_script(base_script);
- }
-
- drop_path = String();
- drop_node = nullptr;
-
- _update_graph(port_action_new_node);
-}
-
-void VisualScriptEditor::connect_seq(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode_new, int new_id) {
- VisualScriptOperator *vnode_operator = Object::cast_to<VisualScriptOperator>(vnode_new.ptr());
- if (vnode_operator != nullptr && !vnode_operator->has_input_sequence_port()) {
- return;
- }
- VisualScriptConstructor *vnode_constructor = Object::cast_to<VisualScriptConstructor>(vnode_new.ptr());
- if (vnode_constructor != nullptr) {
- return;
- }
- if (vnode_old->get_output_sequence_port_count() <= 0) {
- return;
- }
- if (!vnode_new->has_input_sequence_port()) {
- return;
- }
-
- undo_redo->create_action(TTR("Connect Node Sequence"));
- int pass_port = -vnode_old->get_output_sequence_port_count() + 1;
- int return_port = port_action_output - 1;
- if (vnode_old->get_output_value_port_info(port_action_output).name == String("pass") &&
- !script->get_output_sequence_ports_connected(port_action_node).has(pass_port)) {
- undo_redo->add_do_method(script.ptr(), "sequence_connect", port_action_node, pass_port, new_id);
- undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", port_action_node, pass_port, new_id);
- } else if (vnode_old->get_output_value_port_info(port_action_output).name == String("return") &&
- !script->get_output_sequence_ports_connected(port_action_node).has(return_port)) {
- undo_redo->add_do_method(script.ptr(), "sequence_connect", port_action_node, return_port, new_id);
- undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", port_action_node, return_port, new_id);
- } else {
- for (int port = 0; port < vnode_old->get_output_sequence_port_count(); port++) {
- int count = vnode_old->get_output_sequence_port_count();
- if (port_action_output < count && !script->get_output_sequence_ports_connected(port_action_node).has(port_action_output)) {
- undo_redo->add_do_method(script.ptr(), "sequence_connect", port_action_node, port_action_output, new_id);
- undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", port_action_node, port_action_output, new_id);
- break;
- } else if (!script->get_output_sequence_ports_connected(port_action_node).has(port)) {
- undo_redo->add_do_method(script.ptr(), "sequence_connect", port_action_node, port, new_id);
- undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", port_action_node, port, new_id);
- break;
- }
- }
- }
-
- undo_redo->commit_action();
-}
-
-void VisualScriptEditor::_selected_new_virtual_method(const String &p_text, const String &p_category, const bool p_connecting) {
- String name = p_text.substr(p_text.find_char(':') + 1);
- if (script->has_function(name)) {
- EditorNode::get_singleton()->show_warning(vformat(TTR("Script already has function '%s'"), name));
- return;
- }
-
- MethodInfo minfo;
- {
- List<MethodInfo> methods;
- bool found = false;
- ClassDB::get_virtual_methods(script->get_instance_base_type(), &methods);
- for (const MethodInfo &E : methods) {
- if (E.name == name) {
- minfo = E;
- found = true;
- }
- }
-
- ERR_FAIL_COND(!found);
- }
-
- selected = name;
- Ref<VisualScriptFunction> func_node;
- func_node.instantiate();
- func_node->set_name(name);
- int fn_id = script->get_available_id();
- undo_redo->create_action(TTR("Add Function"));
- undo_redo->add_do_method(script.ptr(), "add_function", name, fn_id);
-
- for (int i = 0; i < minfo.arguments.size(); i++) {
- func_node->add_argument(minfo.arguments[i].type, minfo.arguments[i].name, -1, minfo.arguments[i].hint, minfo.arguments[i].hint_string);
- }
-
- Vector2 pos = _get_available_pos();
-
- undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, pos);
- undo_redo->add_undo_method(script.ptr(), "remove_node", fn_id);
- if (minfo.return_val.type != Variant::NIL || minfo.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {
- Ref<VisualScriptReturn> ret_node;
- ret_node.instantiate();
- ret_node->set_return_type(minfo.return_val.type);
- ret_node->set_enable_return_value(true);
- ret_node->set_name(name);
- int nid = script->get_available_id() + 1;
- undo_redo->add_do_method(script.ptr(), "add_node", nid, ret_node, _get_available_pos(false, pos + Vector2(500, 0)));
- undo_redo->add_undo_method(script.ptr(), "remove_node", nid);
- }
-
- undo_redo->add_undo_method(script.ptr(), "remove_function", name);
- undo_redo->add_do_method(this, "_update_members");
- undo_redo->add_undo_method(this, "_update_members");
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
-
- undo_redo->commit_action();
-
- _update_graph();
-}
-
-void VisualScriptEditor::_cancel_connect_node() {
- // Ensure the cancel is done.
- port_action_new_node = -1;
-}
-
-int VisualScriptEditor::_create_new_node_from_name(const String &p_text, const Vector2 &p_point) {
- Ref<VisualScriptNode> vnode = VisualScriptLanguage::singleton->create_node_from_name(p_text);
- int new_id = script->get_available_id();
- undo_redo->create_action(TTR("Add Node"));
- undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, p_point);
- undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
- undo_redo->commit_action();
- return new_id;
-}
-
-void VisualScriptEditor::_default_value_changed() {
- Ref<VisualScriptNode> vsn = script->get_node(editing_id);
- if (vsn.is_null()) {
- return;
- }
-
- undo_redo->create_action(TTR("Change Input Value"));
- undo_redo->add_do_method(vsn.ptr(), "set_default_input_value", editing_input, default_value_edit->get_variant());
- undo_redo->add_undo_method(vsn.ptr(), "set_default_input_value", editing_input, vsn->get_default_input_value(editing_input));
-
- undo_redo->add_do_method(this, "_update_graph", editing_id);
- undo_redo->add_undo_method(this, "_update_graph", editing_id);
- undo_redo->commit_action();
-}
-
-void VisualScriptEditor::_default_value_edited(Node *p_button, int p_id, int p_input_port) {
- Ref<VisualScriptNode> vsn = script->get_node(p_id);
- if (vsn.is_null()) {
- return;
- }
-
- PropertyInfo pinfo = vsn->get_input_value_port_info(p_input_port);
- Variant existing = vsn->get_default_input_value(p_input_port);
- if (pinfo.type != Variant::NIL && existing.get_type() != pinfo.type) {
- Callable::CallError ce;
- Variant e = existing;
- const Variant *existingp = &e;
- Variant::construct(pinfo.type, existing, &existingp, 1, ce);
- }
-
- default_value_edit->set_position(Object::cast_to<Control>(p_button)->get_screen_position() + Vector2(0, Object::cast_to<Control>(p_button)->get_size().y) * graph->get_zoom());
- default_value_edit->reset_size();
-
- if (pinfo.type == Variant::NODE_PATH) {
- Node *edited_scene = get_tree()->get_edited_scene_root();
- if (edited_scene) { // Fixing an old crash bug ( Visual Script Crashes on editing NodePath with an empty scene open).
- Node *script_node = _find_script_node(edited_scene, edited_scene, script);
-
- if (script_node) {
- // Pick a node relative to the script, IF the script exists.
- pinfo.hint = PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE;
- pinfo.hint_string = script_node->get_path();
- } else {
- // Pick a path relative to edited scene.
- pinfo.hint = PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE;
- pinfo.hint_string = get_tree()->get_edited_scene_root()->get_path();
- }
- }
- }
-
- if (default_value_edit->edit(nullptr, pinfo.name, pinfo.type, existing, pinfo.hint, pinfo.hint_string)) {
- if (pinfo.hint == PROPERTY_HINT_MULTILINE_TEXT) {
- default_value_edit->popup_centered_ratio();
- } else {
- default_value_edit->popup();
- }
- }
-
- editing_id = p_id;
- editing_input = p_input_port;
-}
-
-void VisualScriptEditor::_show_hint(const String &p_hint) {
- hint_text->set_text(p_hint);
- hint_text->show();
- hint_text_timer->start();
-}
-
-void VisualScriptEditor::_hide_timer() {
- hint_text->hide();
-}
-
-void VisualScriptEditor::_toggle_scripts_pressed() {
- ScriptEditor::get_singleton()->toggle_scripts_panel();
- update_toggle_scripts_button();
-}
-
-void VisualScriptEditor::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_ENTER_TREE:
- case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- graph->get_panner()->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/sub_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
- graph->set_warped_panning(bool(EditorSettings::get_singleton()->get("editors/panning/warped_mouse_panning")));
- graph->set_minimap_opacity(EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity"));
- graph->set_connection_lines_curvature(EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature"));
- _update_graph();
- } break;
-
- case NOTIFICATION_READY: {
- variable_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_members));
- variable_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_graph).bind(-1), CONNECT_DEFERRED);
- signal_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_members));
- signal_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_graph).bind(-1), CONNECT_DEFERRED);
- [[fallthrough]];
- }
- case NOTIFICATION_THEME_CHANGED: {
- if (p_what != NOTIFICATION_READY && !is_visible_in_tree()) {
- return;
- }
-
- update_toggle_scripts_button();
-
- edit_variable_edit->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
- edit_signal_edit->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
- func_input_scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
-
- Ref<Theme> tm = EditorNode::get_singleton()->get_theme_base()->get_theme();
-
- bool dark_theme = tm->get_constant("dark_theme", "Editor");
-
- if (dark_theme) {
- node_colors["flow_control"] = Color(0.96, 0.96, 0.96);
- node_colors["functions"] = Color(0.96, 0.52, 0.51);
- node_colors["data"] = Color(0.5, 0.96, 0.81);
- node_colors["operators"] = Color(0.67, 0.59, 0.87);
- node_colors["custom"] = Color(0.5, 0.73, 0.96);
- node_colors["constants"] = Color(0.96, 0.5, 0.69);
- } else {
- node_colors["flow_control"] = Color(0.26, 0.26, 0.26);
- node_colors["functions"] = Color(0.95, 0.4, 0.38);
- node_colors["data"] = Color(0.07, 0.73, 0.51);
- node_colors["operators"] = Color(0.51, 0.4, 0.82);
- node_colors["custom"] = Color(0.31, 0.63, 0.95);
- node_colors["constants"] = Color(0.94, 0.18, 0.49);
- }
-
- for (const KeyValue<StringName, Color> &E : node_colors) {
- const Ref<StyleBoxFlat> sb = tm->get_stylebox(SNAME("frame"), SNAME("GraphNode"));
-
- if (!sb.is_null()) {
- Ref<StyleBoxFlat> frame_style = sb->duplicate();
- // Adjust the border color to be close to the GraphNode's background color.
- // This keeps the node's title area from being too distracting.
- Color color = dark_theme ? E.value.darkened(0.75) : E.value.lightened(0.75);
- color.a = 0.9;
- frame_style->set_border_color(color);
- node_styles[E.key] = frame_style;
- }
- }
-
- if (is_visible_in_tree() && script.is_valid()) {
- _update_members();
- _update_graph();
- }
- } break;
-
- case NOTIFICATION_VISIBILITY_CHANGED: {
- update_toggle_scripts_button();
- members_section->set_visible(is_visible_in_tree());
- } break;
- }
-}
-
-void VisualScriptEditor::_graph_ofs_changed(const Vector2 &p_ofs) {
- if (updating_graph || !script.is_valid()) {
- return;
- }
-
- updating_graph = true;
-
- script->set_scroll(graph->get_scroll_ofs() / EDSCALE);
- script->set_edited(true);
- updating_graph = false;
-}
-
-void VisualScriptEditor::_comment_node_resized(const Vector2 &p_new_size, int p_node) {
- if (updating_graph) {
- return;
- }
- Ref<VisualScriptComment> vsc = script->get_node(p_node);
- if (vsc.is_null()) {
- return;
- }
-
- Node *node = graph->get_node(itos(p_node));
- GraphNode *gn = Object::cast_to<GraphNode>(node);
- if (!gn) {
- return;
- }
-
- Vector2 new_size = p_new_size;
- if (graph->is_using_snap()) {
- Vector2 snap = Vector2(graph->get_snap(), graph->get_snap());
- Vector2 min_size = (gn->get_minimum_size() + (snap * 0.5)).snapped(snap);
- new_size = new_size.snapped(snap).max(min_size);
- }
-
- updating_graph = true;
-
- graph->set_block_minimum_size_adjust(true); //faster resize
-
- undo_redo->create_action(TTR("Resize Comment"), UndoRedo::MERGE_ENDS);
- undo_redo->add_do_method(vsc.ptr(), "set_size", new_size / EDSCALE);
- undo_redo->add_undo_method(vsc.ptr(), "set_size", vsc->get_size());
- undo_redo->commit_action();
-
- gn->set_custom_minimum_size(new_size);
- gn->reset_size();
- graph->set_block_minimum_size_adjust(false);
- updating_graph = false;
-}
-
-void VisualScriptEditor::_menu_option(int p_what) {
- switch (p_what) {
- case EDIT_ADD_NODE: {
- _generic_search();
- } break;
- case EDIT_DELETE_NODES: {
- _on_nodes_delete();
- } break;
- case EDIT_TOGGLE_BREAKPOINT: {
- List<String> reselect;
- for (int i = 0; i < graph->get_child_count(); i++) {
- GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
- if (gn) {
- if (gn->is_selected()) {
- int id = String(gn->get_name()).to_int();
- Ref<VisualScriptNode> vsn = script->get_node(id);
- if (vsn.is_valid()) {
- vsn->set_breakpoint(!vsn->is_breakpoint());
- reselect.push_back(gn->get_name());
- }
- }
- }
- }
-
- _update_graph();
-
- for (const String &E : reselect) {
- GraphNode *gn = Object::cast_to<GraphNode>(graph->get_node(E));
- gn->set_selected(true);
- }
-
- } break;
- case EDIT_FIND_NODE_TYPE: {
- _generic_search();
- } break;
- case EDIT_COPY_NODES: {
- _on_nodes_copy();
- } break;
- case EDIT_CUT_NODES: {
- _on_nodes_copy();
- _on_nodes_delete();
- } break;
- case EDIT_PASTE_NODES: {
- _on_nodes_paste();
- } break;
- case EDIT_DUPLICATE_NODES: {
- _on_nodes_duplicate();
- } break;
- case EDIT_CREATE_FUNCTION: {
- // Create Function.
- HashMap<int, Ref<VisualScriptNode>> nodes;
- RBSet<int> selections;
- for (int i = 0; i < graph->get_child_count(); i++) {
- GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
- if (gn) {
- if (gn->is_selected()) {
- int id = String(gn->get_name()).to_int();
- Ref<VisualScriptNode> node = script->get_node(id);
- if (Object::cast_to<VisualScriptFunction>(*node)) {
- EditorNode::get_singleton()->show_warning(TTR("Can't create function with a function node."));
- return;
- }
- if (node.is_valid()) {
- nodes.insert(id, node);
- selections.insert(id);
- }
- }
- }
- }
-
- if (nodes.size() == 0) {
- return; // nothing to be done if there are no valid nodes selected
- }
-
- RBSet<VisualScript::SequenceConnection> seqmove;
- RBSet<VisualScript::DataConnection> datamove;
-
- RBSet<VisualScript::SequenceConnection> seqext;
- RBSet<VisualScript::DataConnection> dataext;
-
- int start_node = -1;
- RBSet<int> end_nodes;
- if (nodes.size() == 1) {
- Ref<VisualScriptNode> nd = script->get_node(nodes.begin()->key);
- if (nd.is_valid() && nd->has_input_sequence_port()) {
- start_node = nodes.begin()->key;
- } else {
- EditorNode::get_singleton()->show_warning(TTR("Select at least one node with sequence port."));
- return;
- }
- } else {
- List<VisualScript::SequenceConnection> seqs;
- script->get_sequence_connection_list(&seqs);
-
- if (seqs.size() == 0) {
- // In case there are no sequence connections,
- // select the top most node cause that's probably how,
- // the user wants to connect the nodes.
- int top_nd = -1;
- Vector2 top;
- for (const KeyValue<int, Ref<VisualScriptNode>> &E : nodes) {
- Ref<VisualScriptNode> nd = script->get_node(E.key);
- if (nd.is_valid() && nd->has_input_sequence_port()) {
- if (top_nd < 0) {
- top_nd = E.key;
- top = script->get_node_position(top_nd);
- }
- Vector2 pos = script->get_node_position(E.key);
- if (top.y > pos.y) {
- top_nd = E.key;
- top = pos;
- }
- }
- }
- Ref<VisualScriptNode> nd = script->get_node(top_nd);
- if (nd.is_valid() && nd->has_input_sequence_port()) {
- start_node = top_nd;
- } else {
- EditorNode::get_singleton()->show_warning(TTR("Select at least one node with sequence port."));
- return;
- }
- } else {
- // Pick the node with input sequence.
- RBSet<int> nodes_from;
- RBSet<int> nodes_to;
- for (const VisualScript::SequenceConnection &E : seqs) {
- if (nodes.has(E.from_node) && nodes.has(E.to_node)) {
- seqmove.insert(E);
- nodes_from.insert(E.from_node);
- } else if (nodes.has(E.from_node) && !nodes.has(E.to_node)) {
- seqext.insert(E);
- } else if (!nodes.has(E.from_node) && nodes.has(E.to_node)) {
- if (start_node == -1) {
- seqext.insert(E);
- start_node = E.to_node;
- } else {
- EditorNode::get_singleton()->show_warning(TTR("Try to only have one sequence input in selection."));
- return;
- }
- }
- nodes_to.insert(E.to_node);
- }
-
- // To use to add return nodes.
- _get_ends(start_node, seqs, selections, end_nodes);
-
- if (start_node == -1) {
- // If we still don't have a start node then,
- // run through the nodes and select the first tree node,
- // i.e. node without any input sequence but output sequence.
- for (const int &E : nodes_from) {
- if (!nodes_to.has(E)) {
- start_node = E;
- }
- }
- }
- }
- }
-
- if (start_node == -1) {
- return; // This should not happen, but just in case something goes wrong.
- }
-
- List<Variant::Type> inputs; // input types
- List<Pair<int, int>> input_connections;
- {
- List<VisualScript::DataConnection> dats;
- script->get_data_connection_list(&dats);
- for (const VisualScript::DataConnection &E : dats) {
- if (nodes.has(E.from_node) && nodes.has(E.to_node)) {
- datamove.insert(E);
- } else if (!nodes.has(E.from_node) && nodes.has(E.to_node)) {
- // Add all these as inputs for the Function.
- Ref<VisualScriptNode> node = script->get_node(E.to_node);
- if (node.is_valid()) {
- dataext.insert(E);
- PropertyInfo pi = node->get_input_value_port_info(E.to_port);
- inputs.push_back(pi.type);
- input_connections.push_back(Pair<int, int>(E.to_node, E.to_port));
- }
- } else if (nodes.has(E.from_node) && !nodes.has(E.to_node)) {
- dataext.insert(E);
- }
- }
- }
- int fn_id = script->get_available_id();
- {
- String new_fn = _validate_name("new_function");
-
- Vector2 pos = _get_available_pos(false, script->get_node_position(start_node) - Vector2(80, 150));
-
- Ref<VisualScriptFunction> func_node;
- func_node.instantiate();
- func_node->set_name(new_fn);
-
- undo_redo->create_action(TTR("Create Function"));
-
- undo_redo->add_do_method(script.ptr(), "add_function", new_fn, fn_id);
- undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, pos);
- undo_redo->add_undo_method(script.ptr(), "remove_function", new_fn);
- undo_redo->add_undo_method(script.ptr(), "remove_node", fn_id);
- undo_redo->add_do_method(this, "_update_members");
- undo_redo->add_undo_method(this, "_update_members");
- undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
- undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");
- // Might make the system more intelligent by checking port from info.
- int i = 0;
- List<Pair<int, int>>::Element *F = input_connections.front();
- for (List<Variant::Type>::Element *E = inputs.front(); E && F; E = E->next(), F = F->next()) {
- func_node->add_argument(E->get(), "arg_" + String::num_int64(i), i);
- undo_redo->add_do_method(script.ptr(), "data_connect", fn_id, i, F->get().first, F->get().second);
- i++; // increment i
- }
- // Ensure Preview Selection is of newly created function node.
- if (selections.size()) {
- EditorNode::get_singleton()->push_item(func_node.ptr());
- }
- }
- // Move the nodes.
-
- // Handles reconnection of sequence connections on undo, start here in case of issues.
- for (const VisualScript::SequenceConnection &E : seqext) {
- undo_redo->add_do_method(script.ptr(), "sequence_disconnect", E.from_node, E.from_output, E.to_node);
- undo_redo->add_undo_method(script.ptr(), "sequence_connect", E.from_node, E.from_output, E.to_node);
- }
- for (const VisualScript::DataConnection &E : dataext) {
- undo_redo->add_do_method(script.ptr(), "data_disconnect", E.from_node, E.from_port, E.to_node, E.to_port);
- undo_redo->add_undo_method(script.ptr(), "data_connect", E.from_node, E.from_port, E.to_node, E.to_port);
- }
-
- // I don't really think we need support for non sequenced functions at this moment.
- undo_redo->add_do_method(script.ptr(), "sequence_connect", fn_id, 0, start_node);
-
- // Could fail with the new changes, start here when searching for bugs in create function shortcut.
- int m = 1;
- for (const int &G : end_nodes) {
- Ref<VisualScriptReturn> ret_node;
- ret_node.instantiate();
-
- int ret_id = fn_id + (m++);
- selections.insert(ret_id);
- Vector2 posi = _get_available_pos(false, script->get_node_position(G) + Vector2(80, -100));
- undo_redo->add_do_method(script.ptr(), "add_node", ret_id, ret_node, posi);
- undo_redo->add_undo_method(script.ptr(), "remove_node", ret_id);
-
- undo_redo->add_do_method(script.ptr(), "sequence_connect", G, 0, ret_id);
- // Add data outputs from each of the end_nodes.
- Ref<VisualScriptNode> vsn = script->get_node(G);
- if (vsn.is_valid() && vsn->get_output_value_port_count() > 0) {
- ret_node->set_enable_return_value(true);
- // Use the zeroth data port cause that's the likely one that is planned to be used.
- ret_node->set_return_type(vsn->get_output_value_port_info(0).type);
- undo_redo->add_do_method(script.ptr(), "data_connect", G, 0, ret_id, 0);
- }
- }
-
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
-
- undo_redo->commit_action();
-
- // Make sure all Nodes get marked for selection so that they can be moved together.
- selections.insert(fn_id);
- for (int k = 0; k < graph->get_child_count(); k++) {
- GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(k));
- if (gn) {
- int id = gn->get_name().operator String().to_int();
- gn->set_selected(selections.has(id));
- }
- }
-
- } break;
- case REFRESH_GRAPH: {
- _update_graph();
- } break;
- case EDIT_CLEAR_COPY_BUFFER: {
- clipboard->nodes.clear();
- clipboard->nodes_positions.clear();
- clipboard->data_connections.clear();
- clipboard->sequence_connections.clear();
- } break;
- }
-}
-
-// This is likely going to be very slow and I am not sure if I should keep it,
-// but I hope that it will not be a problem considering that we won't be creating functions so frequently,
-// and cyclic connections would be a problem but hopefully we won't let them get to this point.
-void VisualScriptEditor::_get_ends(int p_node, const List<VisualScript::SequenceConnection> &p_seqs, const RBSet<int> &p_selected, RBSet<int> &r_end_nodes) {
- for (const VisualScript::SequenceConnection &E : p_seqs) {
- int from = E.from_node;
- int to = E.to_node;
-
- if (from == p_node && p_selected.has(to)) {
- // This is an interior connection move forward to the to node.
- _get_ends(to, p_seqs, p_selected, r_end_nodes);
- } else if (from == p_node && !p_selected.has(to)) {
- r_end_nodes.insert(from);
- }
- }
-}
-
-void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos, MouseButton p_button) {
- if (p_button != MouseButton::RIGHT) {
- return;
- }
-
- TreeItem *ti = members->get_selected();
- ERR_FAIL_COND(!ti);
-
- member_popup->clear();
- member_popup->set_position(members->get_screen_position() + p_pos);
- member_popup->reset_size();
-
- function_name_edit->set_position(members->get_screen_position() + p_pos);
- function_name_edit->reset_size();
-
- TreeItem *root = members->get_root();
-
- Ref<Texture2D> del_icon = Control::get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"));
-
- Ref<Texture2D> edit_icon = Control::get_theme_icon(SNAME("Edit"), SNAME("EditorIcons"));
-
- if (ti->get_parent() == root->get_first_child()) {
- member_type = MEMBER_FUNCTION;
- member_name = ti->get_text(0);
- member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT);
- member_popup->add_separator();
- member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("ui_graph_delete"), MEMBER_REMOVE);
- member_popup->popup();
- return;
- }
-
- if (ti->get_parent() == root->get_first_child()->get_next()) {
- member_type = MEMBER_VARIABLE;
- member_name = ti->get_text(0);
- member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT);
- member_popup->add_separator();
- member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("ui_graph_delete"), MEMBER_REMOVE);
- member_popup->popup();
- return;
- }
-
- if (ti->get_parent() == root->get_first_child()->get_next()->get_next()) {
- member_type = MEMBER_SIGNAL;
- member_name = ti->get_text(0);
- member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT);
- member_popup->add_separator();
- member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("ui_graph_delete"), MEMBER_REMOVE);
- member_popup->popup();
- return;
- }
-}
-
-void VisualScriptEditor::_member_option(int p_option) {
- switch (member_type) {
- case MEMBER_FUNCTION: {
- if (p_option == MEMBER_REMOVE) {
- // Delete the function.
- String name = member_name;
- List<String> lst;
- int fn_node = script->get_function_node_id(name);
- undo_redo->create_action(TTR("Remove Function"));
- undo_redo->add_do_method(script.ptr(), "remove_function", name);
- undo_redo->add_do_method(script.ptr(), "remove_node", fn_node);
- undo_redo->add_undo_method(script.ptr(), "add_function", name, fn_node);
- undo_redo->add_undo_method(script.ptr(), "add_node", fn_node, script->get_node(fn_node), script->get_node_position(fn_node));
- List<VisualScript::SequenceConnection> seqcons;
- script->get_sequence_connection_list(&seqcons);
- for (const VisualScript::SequenceConnection &E : seqcons) {
- if (E.from_node == fn_node) {
- undo_redo->add_undo_method(script.ptr(), "sequence_connect", fn_node, E.from_output, E.to_node);
- }
- }
- List<VisualScript::DataConnection> datcons;
- script->get_data_connection_list(&datcons);
- for (const VisualScript::DataConnection &E : datcons) {
- if (E.from_node == fn_node) {
- undo_redo->add_undo_method(script.ptr(), "data_connect", fn_node, E.from_port, E.to_node, E.to_port);
- }
- }
- undo_redo->add_do_method(this, "_update_members");
- undo_redo->add_undo_method(this, "_update_members");
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
- undo_redo->commit_action();
- } else if (p_option == MEMBER_EDIT) {
- selected = members->get_selected()->get_text(0);
- function_name_edit->popup();
- function_name_box->set_text(selected);
- function_name_box->select_all();
- function_name_box->grab_focus();
- }
- } break;
- case MEMBER_VARIABLE: {
- String name = member_name;
-
- if (p_option == MEMBER_REMOVE) {
- undo_redo->create_action(TTR("Remove Variable"));
- undo_redo->add_do_method(script.ptr(), "remove_variable", name);
- undo_redo->add_undo_method(script.ptr(), "add_variable", name, script->get_variable_default_value(name));
- undo_redo->add_undo_method(script.ptr(), "set_variable_info", name, script->call("get_variable_info", name)); //return as dict
- undo_redo->add_do_method(this, "_update_members");
- undo_redo->add_undo_method(this, "_update_members");
- undo_redo->commit_action();
- } else if (p_option == MEMBER_EDIT) {
- variable_editor->edit(name);
- edit_variable_dialog->set_title(TTR("Editing Variable:") + " " + name);
- edit_variable_dialog->popup_centered(Size2(400, 200) * EDSCALE);
- }
- } break;
- case MEMBER_SIGNAL: {
- String name = member_name;
-
- if (p_option == MEMBER_REMOVE) {
- undo_redo->create_action(TTR("Remove Signal"));
- undo_redo->add_do_method(script.ptr(), "remove_custom_signal", name);
- undo_redo->add_undo_method(script.ptr(), "add_custom_signal", name);
-
- for (int i = 0; i < script->custom_signal_get_argument_count(name); i++) {
- undo_redo->add_undo_method(script.ptr(), "custom_signal_add_argument", name, script->custom_signal_get_argument_name(name, i), script->custom_signal_get_argument_type(name, i));
- }
-
- undo_redo->add_do_method(this, "_update_members");
- undo_redo->add_undo_method(this, "_update_members");
- undo_redo->commit_action();
- } else if (p_option == MEMBER_EDIT) {
- signal_editor->edit(name);
- edit_signal_dialog->set_title(TTR("Editing Signal:") + " " + name);
- edit_signal_dialog->popup_centered(Size2(400, 300) * EDSCALE);
- }
- } break;
- }
-}
-
-void VisualScriptEditor::add_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) {
-}
-
-void VisualScriptEditor::set_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) {
-}
-
-void VisualScriptEditor::update_toggle_scripts_button() {
- if (is_layout_rtl()) {
- toggle_scripts_button->set_icon(Control::get_theme_icon(ScriptEditor::get_singleton()->is_scripts_panel_toggled() ? SNAME("Forward") : SNAME("Back"), SNAME("EditorIcons")));
- } else {
- toggle_scripts_button->set_icon(Control::get_theme_icon(ScriptEditor::get_singleton()->is_scripts_panel_toggled() ? SNAME("Back") : SNAME("Forward"), SNAME("EditorIcons")));
- }
- toggle_scripts_button->set_tooltip(vformat("%s (%s)", TTR("Toggle Scripts Panel"), ED_GET_SHORTCUT("script_editor/toggle_scripts_panel")->get_as_text()));
-}
-
-void VisualScriptEditor::_bind_methods() {
- ClassDB::bind_method("_move_node", &VisualScriptEditor::_move_node);
- ClassDB::bind_method("_update_graph", &VisualScriptEditor::_update_graph, DEFVAL(-1));
-
- ClassDB::bind_method("_center_on_node", &VisualScriptEditor::_center_on_node);
- ClassDB::bind_method("_button_resource_previewed", &VisualScriptEditor::_button_resource_previewed);
- ClassDB::bind_method("_port_action_menu", &VisualScriptEditor::_port_action_menu);
-
- ClassDB::bind_method("_create_new_node_from_name", &VisualScriptEditor::_create_new_node_from_name);
-
- ClassDB::bind_method("_get_drag_data_fw", &VisualScriptEditor::get_drag_data_fw);
- ClassDB::bind_method("_can_drop_data_fw", &VisualScriptEditor::can_drop_data_fw);
- ClassDB::bind_method("_drop_data_fw", &VisualScriptEditor::drop_data_fw);
-
- ClassDB::bind_method("_update_graph_connections", &VisualScriptEditor::_update_graph_connections);
- ClassDB::bind_method("_update_members", &VisualScriptEditor::_update_members);
-
- ClassDB::bind_method("_generic_search", &VisualScriptEditor::_generic_search);
-}
-
-VisualScriptEditor::VisualScriptEditor() {
- if (!clipboard) {
- clipboard = memnew(Clipboard);
- }
-
- edit_menu = memnew(MenuButton);
- edit_menu->set_shortcut_context(this);
- edit_menu->set_text(TTR("Edit"));
- edit_menu->set_switch_on_hover(true);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_graph_delete"), EDIT_DELETE_NODES);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/toggle_breakpoint"), EDIT_TOGGLE_BREAKPOINT);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/find_node_type"), EDIT_FIND_NODE_TYPE);
- edit_menu->get_popup()->add_separator();
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_copy"), EDIT_COPY_NODES);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_cut"), EDIT_CUT_NODES);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_paste"), EDIT_PASTE_NODES);
- edit_menu->get_popup()->add_separator();
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/create_function"), EDIT_CREATE_FUNCTION);
- edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/refresh_nodes"), REFRESH_GRAPH);
- edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &VisualScriptEditor::_menu_option));
-
- members_section = memnew(VBoxContainer);
- // Add but wait until done setting up this.
- ScriptEditor::get_singleton()->get_left_list_split()->call_deferred(SNAME("add_child"), members_section);
- members_section->set_v_size_flags(SIZE_EXPAND_FILL);
-
- CheckButton *tool_script_check = memnew(CheckButton);
- tool_script_check->set_text(TTR("Make Tool:"));
- members_section->add_child(tool_script_check);
- tool_script_check->connect("pressed", callable_mp(this, &VisualScriptEditor::_toggle_tool_script));
-
- /// Members ///
-
- members = memnew(Tree);
- members_section->add_margin_child(TTR("Members:"), members, true);
- members->set_custom_minimum_size(Size2(0, 50 * EDSCALE));
- members->set_hide_root(true);
- members->connect("button_clicked", callable_mp(this, &VisualScriptEditor::_member_button));
- members->connect("item_edited", callable_mp(this, &VisualScriptEditor::_member_edited));
- members->connect("cell_selected", callable_mp(this, &VisualScriptEditor::_member_selected), CONNECT_DEFERRED);
- members->connect("gui_input", callable_mp(this, &VisualScriptEditor::_members_gui_input));
- members->connect("item_mouse_selected", callable_mp(this, &VisualScriptEditor::_member_rmb_selected));
- members->set_allow_rmb_select(true);
- members->set_allow_reselect(true);
- members->set_hide_folding(true);
- members->set_drag_forwarding(this);
-
- member_popup = memnew(PopupMenu);
- add_child(member_popup);
- member_popup->connect("id_pressed", callable_mp(this, &VisualScriptEditor::_member_option));
-
- function_name_edit = memnew(AcceptDialog);
- function_name_edit->set_title(TTR("Rename Function"));
- function_name_box = memnew(LineEdit);
- function_name_edit->add_child(function_name_box);
- function_name_box->connect("gui_input", callable_mp(this, &VisualScriptEditor::_fn_name_box_input));
- function_name_edit->get_ok_button()->connect("pressed", callable_mp(this, &VisualScriptEditor::_on_fn_name_box_confirmed));
- function_name_box->set_expand_to_text_length_enabled(true);
- add_child(function_name_edit);
-
- /// Actual Graph ///
-
- graph = memnew(GraphEdit);
- add_child(graph);
- graph->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- graph->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
- graph->set_show_zoom_label(true);
- graph->connect("node_selected", callable_mp(this, &VisualScriptEditor::_node_selected));
- graph->connect("begin_node_move", callable_mp(this, &VisualScriptEditor::_begin_node_move));
- graph->connect("end_node_move", callable_mp(this, &VisualScriptEditor::_end_node_move));
- graph->connect("copy_nodes_request", callable_mp(this, &VisualScriptEditor::_on_nodes_copy));
- graph->connect("paste_nodes_request", callable_mp(this, &VisualScriptEditor::_on_nodes_paste));
- graph->connect("delete_nodes_request", callable_mp(this, &VisualScriptEditor::_on_nodes_delete));
- graph->connect("duplicate_nodes_request", callable_mp(this, &VisualScriptEditor::_on_nodes_duplicate));
- graph->connect("gui_input", callable_mp(this, &VisualScriptEditor::_graph_gui_input));
- graph->set_drag_forwarding(this);
- float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity");
- graph->set_minimap_opacity(graph_minimap_opacity);
- float graph_lines_curvature = EditorSettings::get_singleton()->get("editors/visual_editors/lines_curvature");
- graph->set_connection_lines_curvature(graph_lines_curvature);
- graph->hide();
- graph->connect("scroll_offset_changed", callable_mp(this, &VisualScriptEditor::_graph_ofs_changed));
-
- status_bar = memnew(HBoxContainer);
- add_child(status_bar);
- status_bar->set_h_size_flags(SIZE_EXPAND_FILL);
- status_bar->set_custom_minimum_size(Size2(0, 24 * EDSCALE));
-
- toggle_scripts_button = memnew(Button);
- toggle_scripts_button->set_flat(true);
- toggle_scripts_button->connect("pressed", callable_mp(this, &VisualScriptEditor::_toggle_scripts_pressed));
- status_bar->add_child(toggle_scripts_button);
-
- /// Add Buttons to Top Bar/Zoom bar.
- HBoxContainer *graph_hbc = graph->get_zoom_hbox();
-
- Label *base_lbl = memnew(Label);
- base_lbl->set_text(TTR("Change Base Type:") + " ");
- graph_hbc->add_child(base_lbl);
-
- base_type_select = memnew(Button);
- base_type_select->connect("pressed", callable_mp(this, &VisualScriptEditor::_change_base_type));
- graph_hbc->add_child(base_type_select);
-
- Button *add_nds = memnew(Button);
- add_nds->set_text(TTR("Add Nodes..."));
- graph_hbc->add_child(add_nds);
- add_nds->connect("pressed", callable_mp(this, &VisualScriptEditor::_add_node_dialog));
-
- Button *fn_btn = memnew(Button);
- fn_btn->set_text(TTR("Add Function..."));
- graph_hbc->add_child(fn_btn);
- fn_btn->connect("pressed", callable_mp(this, &VisualScriptEditor::_create_function_dialog));
-
- // Add Function Dialog.
- VBoxContainer *function_vb = memnew(VBoxContainer);
- function_vb->set_v_size_flags(SIZE_EXPAND_FILL);
- function_vb->set_custom_minimum_size(Size2(450, 300) * EDSCALE);
-
- HBoxContainer *func_name_hbox = memnew(HBoxContainer);
- function_vb->add_child(func_name_hbox);
-
- Label *func_name_label = memnew(Label);
- func_name_label->set_text(TTR("Name:"));
- func_name_hbox->add_child(func_name_label);
-
- func_name_box = memnew(LineEdit);
- func_name_box->set_h_size_flags(SIZE_EXPAND_FILL);
- func_name_box->set_placeholder(TTR("function_name"));
- func_name_box->set_text("");
- func_name_box->connect("focus_entered", callable_mp(this, &VisualScriptEditor::_deselect_input_names));
- func_name_hbox->add_child(func_name_box);
-
- // Add minor setting for function if needed, here!
-
- function_vb->add_child(memnew(HSeparator));
-
- Button *add_input_button = memnew(Button);
- add_input_button->set_h_size_flags(SIZE_EXPAND_FILL);
- add_input_button->set_text(TTR("Add Input"));
- add_input_button->connect("pressed", callable_mp(this, &VisualScriptEditor::_add_func_input));
- function_vb->add_child(add_input_button);
-
- func_input_scroll = memnew(ScrollContainer);
- func_input_scroll->set_v_size_flags(SIZE_EXPAND_FILL);
- function_vb->add_child(func_input_scroll);
-
- func_input_vbox = memnew(VBoxContainer);
- func_input_vbox->set_h_size_flags(SIZE_EXPAND_FILL);
- func_input_scroll->add_child(func_input_vbox);
-
- function_create_dialog = memnew(ConfirmationDialog);
- function_create_dialog->set_title(TTR("Create Function"));
- function_create_dialog->add_child(function_vb);
- function_create_dialog->set_ok_button_text(TTR("Create"));
- function_create_dialog->get_ok_button()->connect("pressed", callable_mp(this, &VisualScriptEditor::_create_function));
- add_child(function_create_dialog);
-
- select_func_text = memnew(Label);
- select_func_text->set_text(TTR("Select or create a function to edit its graph."));
- select_func_text->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
- select_func_text->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
- select_func_text->set_h_size_flags(SIZE_EXPAND_FILL);
- add_child(select_func_text);
-
- hint_text = memnew(Label);
- hint_text->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -100);
- hint_text->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0);
- hint_text->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0);
- hint_text->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
- hint_text->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
- graph->add_child(hint_text);
-
- hint_text_timer = memnew(Timer);
- hint_text_timer->set_wait_time(4);
- hint_text_timer->connect("timeout", callable_mp(this, &VisualScriptEditor::_hide_timer));
- add_child(hint_text_timer);
-
- // Allowed casts (connections).
- for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- graph->add_valid_connection_type(Variant::NIL, i);
- graph->add_valid_connection_type(i, Variant::NIL);
- for (int j = 0; j < Variant::VARIANT_MAX; j++) {
- if (Variant::can_convert(Variant::Type(i), Variant::Type(j))) {
- graph->add_valid_connection_type(i, j);
- }
- }
-
- graph->add_valid_right_disconnect_type(i);
- }
-
- graph->add_valid_left_disconnect_type(TYPE_SEQUENCE);
-
- graph->connect("connection_request", callable_mp(this, &VisualScriptEditor::_graph_connected));
- graph->connect("disconnection_request", callable_mp(this, &VisualScriptEditor::_graph_disconnected));
- graph->connect("connection_to_empty", callable_mp(this, &VisualScriptEditor::_graph_connect_to_empty));
-
- edit_signal_dialog = memnew(AcceptDialog);
- edit_signal_dialog->set_ok_button_text(TTR("Close"));
- add_child(edit_signal_dialog);
-
- signal_editor = memnew(VisualScriptEditorSignalEdit);
- edit_signal_edit = memnew(EditorInspector);
- edit_signal_dialog->add_child(edit_signal_edit);
-
- edit_signal_edit->edit(signal_editor);
-
- edit_variable_dialog = memnew(AcceptDialog);
- edit_variable_dialog->set_ok_button_text(TTR("Close"));
- add_child(edit_variable_dialog);
-
- variable_editor = memnew(VisualScriptEditorVariableEdit);
- edit_variable_edit = memnew(EditorInspector);
- edit_variable_dialog->add_child(edit_variable_edit);
-
- edit_variable_edit->edit(variable_editor);
-
- select_base_type = memnew(CreateDialog);
- select_base_type->set_base_type("Object"); // Anything goes.
- select_base_type->connect("create", callable_mp(this, &VisualScriptEditor::_change_base_type_callback));
- add_child(select_base_type);
-
- undo_redo = EditorNode::get_singleton()->get_undo_redo();
-
- set_process_input(true);
-
- default_value_edit = memnew(CustomPropertyEditor);
- add_child(default_value_edit);
- default_value_edit->connect("variant_changed", callable_mp(this, &VisualScriptEditor::_default_value_changed));
-
- new_connect_node_select = memnew(VisualScriptPropertySelector);
- add_child(new_connect_node_select);
- new_connect_node_select->connect("selected", callable_mp(this, &VisualScriptEditor::_selected_connect_node));
- new_connect_node_select->get_cancel_button()->connect("pressed", callable_mp(this, &VisualScriptEditor::_cancel_connect_node));
-
- new_virtual_method_select = memnew(VisualScriptPropertySelector);
- add_child(new_virtual_method_select);
- new_virtual_method_select->connect("selected", callable_mp(this, &VisualScriptEditor::_selected_new_virtual_method));
-
- popup_menu = memnew(PopupMenu);
- add_child(popup_menu);
- popup_menu->add_item(TTR("Add Node"), EDIT_ADD_NODE);
- popup_menu->add_separator();
- popup_menu->add_item(TTR("Cut"), EDIT_CUT_NODES);
- popup_menu->add_item(TTR("Copy"), EDIT_COPY_NODES);
- popup_menu->add_item(TTR("Paste"), EDIT_PASTE_NODES);
- popup_menu->add_item(TTR("Delete"), EDIT_DELETE_NODES);
- popup_menu->add_item(TTR("Duplicate"), EDIT_DUPLICATE_NODES);
- popup_menu->add_item(TTR("Clear Copy Buffer"), EDIT_CLEAR_COPY_BUFFER);
- popup_menu->connect("id_pressed", callable_mp(this, &VisualScriptEditor::_menu_option));
-
- base_type_map.insert("String", Variant::STRING);
- base_type_map.insert("Vector2", Variant::VECTOR2);
- base_type_map.insert("Vector2i", Variant::VECTOR2I);
- base_type_map.insert("Rect2", Variant::RECT2);
- base_type_map.insert("Rect2i", Variant::RECT2I);
- base_type_map.insert("Vector3", Variant::VECTOR3);
- base_type_map.insert("Vector3i", Variant::VECTOR3I);
- base_type_map.insert("Vector4", Variant::VECTOR4);
- base_type_map.insert("Vector4i", Variant::VECTOR4I);
- base_type_map.insert("Transform2D", Variant::TRANSFORM2D);
- base_type_map.insert("Plane", Variant::PLANE);
- base_type_map.insert("Quaternion", Variant::QUATERNION);
- base_type_map.insert("AABB", Variant::AABB);
- base_type_map.insert("Basis", Variant::BASIS);
- base_type_map.insert("Transform3D", Variant::TRANSFORM3D);
- base_type_map.insert("Projection", Variant::PROJECTION);
- base_type_map.insert("Color", Variant::COLOR);
- base_type_map.insert("NodePath", Variant::NODE_PATH);
- base_type_map.insert("RID", Variant::RID);
- base_type_map.insert("Callable", Variant::CALLABLE);
- base_type_map.insert("Dictionary", Variant::DICTIONARY);
- base_type_map.insert("Array", Variant::ARRAY);
- base_type_map.insert("PackedByteArray", Variant::PACKED_BYTE_ARRAY);
- base_type_map.insert("PackedInt32Array", Variant::PACKED_INT32_ARRAY);
- base_type_map.insert("PackedFloat32Array", Variant::PACKED_FLOAT32_ARRAY);
- base_type_map.insert("PackedInt64Array", Variant::PACKED_INT64_ARRAY);
- base_type_map.insert("PackedFloat64Array", Variant::PACKED_FLOAT64_ARRAY);
- base_type_map.insert("PackedStringArray", Variant::PACKED_STRING_ARRAY);
- base_type_map.insert("PackedVector2Array", Variant::PACKED_VECTOR2_ARRAY);
- base_type_map.insert("PackedVector3Array", Variant::PACKED_VECTOR3_ARRAY);
- base_type_map.insert("PackedColorArray", Variant::PACKED_COLOR_ARRAY);
-}
-
-VisualScriptEditor::~VisualScriptEditor() {
- undo_redo->clear_history(); // Avoid crashes.
- memdelete(signal_editor);
- memdelete(variable_editor);
-}
-
-static ScriptEditorBase *create_editor(const Ref<Resource> &p_resource) {
- if (Object::cast_to<VisualScript>(*p_resource)) {
- return memnew(VisualScriptEditor);
- }
-
- return nullptr;
-}
-
-VisualScriptEditor::Clipboard *VisualScriptEditor::clipboard = nullptr;
-
-void VisualScriptEditor::free_clipboard() {
- if (clipboard) {
- memdelete(clipboard);
- }
-}
-
-static void register_editor_callback() {
- ScriptEditor::register_create_script_editor_function(create_editor);
-
- ED_SHORTCUT("visual_script_editor/toggle_breakpoint", TTR("Toggle Breakpoint"), Key::F9);
- ED_SHORTCUT("visual_script_editor/find_node_type", TTR("Find Node Type"), KeyModifierMask::CMD + Key::F);
- ED_SHORTCUT("visual_script_editor/create_function", TTR("Make Function"), KeyModifierMask::CMD + Key::G);
- ED_SHORTCUT("visual_script_editor/refresh_nodes", TTR("Refresh Graph"), KeyModifierMask::CMD + Key::R);
- ED_SHORTCUT("visual_script_editor/edit_member", TTR("Edit Member"), KeyModifierMask::CMD + Key::E);
-}
-
-void VisualScriptEditor::register_editor() {
- // Too early to register stuff here, request a callback.
- EditorNode::add_plugin_init_callback(register_editor_callback);
-}
-
-void VisualScriptEditor::validate() {
-}
-
-// VisualScriptCustomNodes
-
-Ref<VisualScriptNode> VisualScriptCustomNodes::create_node_custom(const String &p_name) {
- Ref<VisualScriptCustomNode> node;
- node.instantiate();
- node->set_script(singleton->custom_nodes[p_name]);
- return node;
-}
-
-VisualScriptCustomNodes *VisualScriptCustomNodes::singleton = nullptr;
-HashMap<String, Ref<RefCounted>> VisualScriptCustomNodes::custom_nodes;
-
-VisualScriptCustomNodes::VisualScriptCustomNodes() {
- singleton = this;
-}
-
-VisualScriptCustomNodes::~VisualScriptCustomNodes() {
- custom_nodes.clear();
-}
-
-void VisualScriptCustomNodes::add_custom_node(const String &p_name, const String &p_category, const Ref<Script> &p_script) {
- String node_name = "custom/" + p_category + "/" + p_name;
- custom_nodes.insert(node_name, p_script);
- VisualScriptLanguage::singleton->add_register_func(node_name, &VisualScriptCustomNodes::create_node_custom);
- emit_signal(SNAME("custom_nodes_updated"));
-}
-
-void VisualScriptCustomNodes::remove_custom_node(const String &p_name, const String &p_category) {
- String node_name = "custom/" + p_category + "/" + p_name;
- custom_nodes.erase(node_name);
- VisualScriptLanguage::singleton->remove_register_func(node_name);
- emit_signal(SNAME("custom_nodes_updated"));
-}
-
-void VisualScriptCustomNodes::_bind_methods() {
- ClassDB::bind_method(D_METHOD("add_custom_node", "name", "category", "script"), &VisualScriptCustomNodes::add_custom_node);
- ClassDB::bind_method(D_METHOD("remove_custom_node", "name", "category"), &VisualScriptCustomNodes::remove_custom_node);
- ADD_SIGNAL(MethodInfo("custom_nodes_updated"));
-}
-
-#endif
diff --git a/modules/visual_script/editor/visual_script_editor.h b/modules/visual_script/editor/visual_script_editor.h
deleted file mode 100644
index a6df7bba73..0000000000
--- a/modules/visual_script/editor/visual_script_editor.h
+++ /dev/null
@@ -1,377 +0,0 @@
-/*************************************************************************/
-/* visual_script_editor.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef VISUAL_SCRIPT_EDITOR_H
-#define VISUAL_SCRIPT_EDITOR_H
-
-#include "../visual_script.h"
-#include "editor/create_dialog.h"
-#include "editor/plugins/script_editor_plugin.h"
-#include "editor/property_editor.h"
-#include "scene/gui/graph_edit.h"
-#include "visual_script_property_selector.h"
-
-class VisualScriptEditorSignalEdit;
-class VisualScriptEditorVariableEdit;
-
-#ifdef TOOLS_ENABLED
-
-// TODO: Maybe this class should be refactored.
-// See https://github.com/godotengine/godot/issues/51913
-class VisualScriptEditor : public ScriptEditorBase {
- GDCLASS(VisualScriptEditor, ScriptEditorBase);
-
- enum {
- TYPE_SEQUENCE = 1000,
- INDEX_BASE_SEQUENCE = 1024
- };
-
- enum {
- EDIT_ADD_NODE,
- EDIT_SEPARATOR, // popup menu separator - ignored
- EDIT_CUT_NODES,
- EDIT_COPY_NODES,
- EDIT_PASTE_NODES,
- EDIT_DELETE_NODES,
- EDIT_DUPLICATE_NODES,
- EDIT_CLEAR_COPY_BUFFER,
-
- EDIT_CREATE_FUNCTION,
- EDIT_TOGGLE_BREAKPOINT,
- EDIT_FIND_NODE_TYPE,
- REFRESH_GRAPH,
- };
-
- enum PortAction {
- CREATE_CALL_SET_GET,
- CREATE_ACTION,
- };
-
- enum MemberAction {
- MEMBER_EDIT,
- MEMBER_REMOVE
- };
-
- enum MemberType {
- MEMBER_FUNCTION,
- MEMBER_VARIABLE,
- MEMBER_SIGNAL
- };
-
- VBoxContainer *members_section = nullptr;
- MenuButton *edit_menu = nullptr;
-
- Ref<VisualScript> script;
-
- Button *base_type_select = nullptr;
-
- LineEdit *func_name_box = nullptr;
- ScrollContainer *func_input_scroll = nullptr;
- VBoxContainer *func_input_vbox = nullptr;
- ConfirmationDialog *function_create_dialog = nullptr;
-
- GraphEdit *graph = nullptr;
- HBoxContainer *status_bar = nullptr;
- Button *toggle_scripts_button = nullptr;
-
- VisualScriptEditorSignalEdit *signal_editor = nullptr;
-
- AcceptDialog *edit_signal_dialog = nullptr;
- EditorInspector *edit_signal_edit = nullptr;
-
- VisualScriptPropertySelector *method_select = nullptr;
- VisualScriptPropertySelector *new_connect_node_select = nullptr;
- VisualScriptPropertySelector *new_virtual_method_select = nullptr;
-
- VisualScriptEditorVariableEdit *variable_editor = nullptr;
-
- AcceptDialog *edit_variable_dialog = nullptr;
- EditorInspector *edit_variable_edit = nullptr;
-
- CustomPropertyEditor *default_value_edit = nullptr;
-
- UndoRedo *undo_redo = nullptr;
-
- Tree *members = nullptr;
- AcceptDialog *function_name_edit = nullptr;
- LineEdit *function_name_box = nullptr;
-
- Label *hint_text = nullptr;
- Timer *hint_text_timer = nullptr;
-
- Label *select_func_text = nullptr;
-
- bool updating_graph = false;
-
- void _show_hint(const String &p_hint);
- void _hide_timer();
-
- CreateDialog *select_base_type = nullptr;
-
- struct VirtualInMenu {
- String name;
- Variant::Type ret;
- bool ret_variant;
- Vector<Pair<Variant::Type, String>> args;
- };
-
- HashMap<StringName, Color> node_colors;
- HashMap<StringName, Ref<StyleBox>> node_styles;
- HashMap<StringName, Variant::Type> base_type_map;
-
- void _update_graph_connections();
- void _update_graph(int p_only_id = -1);
-
- bool updating_members = false;
-
- void _update_members();
- String _sanitized_variant_text(const StringName &property_name);
-
- StringName selected;
-
- String _validate_name(const String &p_name) const;
-
- struct Clipboard {
- HashMap<int, Ref<VisualScriptNode>> nodes;
- HashMap<int, Vector2> nodes_positions;
-
- RBSet<VisualScript::SequenceConnection> sequence_connections;
- RBSet<VisualScript::DataConnection> data_connections;
- };
-
- static Clipboard *clipboard;
-
- PopupMenu *popup_menu = nullptr;
- PopupMenu *member_popup = nullptr;
- MemberType member_type;
- String member_name;
-
- PortAction port_action;
- int port_action_node = 0;
- int port_action_output = 0;
- Vector2 port_action_pos;
- int port_action_new_node = 0;
-
- bool saved_pos_dirty = false;
-
- Vector2 mouse_up_position;
-
- void _port_action_menu(int p_option);
-
- void connect_data(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode, int new_id);
-
- NodePath drop_path;
- Node *drop_node = nullptr;
- Vector2 drop_position;
- void _selected_connect_node(const String &p_text, const String &p_category, const bool p_connecting = true);
- void connect_seq(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode_new, int new_id);
-
- void _cancel_connect_node();
- int _create_new_node_from_name(const String &p_text, const Vector2 &p_point);
- void _selected_new_virtual_method(const String &p_text, const String &p_category, const bool p_connecting);
-
- int error_line = -1;
-
- void _node_selected(Node *p_node);
- void _center_on_node(int p_id);
-
- void _node_filter_changed(const String &p_text);
- void _change_base_type_callback();
- void _change_base_type();
- void _toggle_tool_script();
- void _member_selected();
- void _member_edited();
-
- void _begin_node_move();
- void _end_node_move();
- void _move_node(int p_id, const Vector2 &p_to);
-
- void _get_ends(int p_node, const List<VisualScript::SequenceConnection> &p_seqs, const RBSet<int> &p_selected, RBSet<int> &r_end_nodes);
-
- void _node_moved(Vector2 p_from, Vector2 p_to, int p_id);
- void _remove_node(int p_id);
- void _graph_connected(const String &p_from, int p_from_slot, const String &p_to, int p_to_slot);
- void _graph_disconnected(const String &p_from, int p_from_slot, const String &p_to, int p_to_slot);
- void _graph_connect_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_pos);
-
- void _node_ports_changed(int p_id);
- void _node_create();
-
- void _update_available_nodes();
-
- void _member_button(Object *p_item, int p_column, int p_button, MouseButton p_mouse_button);
-
- void _expression_text_changed(const String &p_text, int p_id);
- void _add_input_port(int p_id);
- void _add_output_port(int p_id);
- void _remove_input_port(int p_id, int p_port);
- void _remove_output_port(int p_id, int p_port);
- void _change_port_type(int p_select, int p_id, int p_port, bool is_input);
- void _update_node_size(int p_id);
- void _port_name_focus_out(const Node *p_name_box, int p_id, int p_port, bool is_input);
-
- Vector2 _get_pos_in_graph(Vector2 p_point) const;
- Vector2 _get_available_pos(bool p_centered = true, Vector2 p_pos = Vector2()) const;
-
- bool node_has_sequence_connections(int p_id);
-
- void _generic_search(Vector2 pos = Vector2(), bool node_centered = false);
-
- virtual void input(const Ref<InputEvent> &p_event) override;
- void _graph_gui_input(const Ref<InputEvent> &p_event);
- void _members_gui_input(const Ref<InputEvent> &p_event);
- void _fn_name_box_input(const Ref<InputEvent> &p_event);
- void _on_fn_name_box_confirmed();
- void _rename_function(const String &p_name, const String &p_new_name);
-
- void _create_function_dialog();
- void _create_function();
- void _add_func_input();
- void _remove_func_input(Node *p_node);
- void _deselect_input_names();
- void _add_node_dialog();
- void _node_item_selected();
- void _node_item_unselected();
-
- void _on_nodes_copy();
- void _on_nodes_paste();
- void _on_nodes_delete();
- void _on_nodes_duplicate();
-
- Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
- bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
- void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
-
- int editing_id = 0;
- int editing_input = 0;
-
- bool can_swap = false;
- int data_disconnect_node = 0;
- int data_disconnect_port = 0;
-
- void _default_value_changed();
- void _default_value_edited(Node *p_button, int p_id, int p_input_port);
-
- void _menu_option(int p_what);
-
- void _graph_ofs_changed(const Vector2 &p_ofs);
- void _comment_node_resized(const Vector2 &p_new_size, int p_node);
-
- void _draw_color_over_button(Object *obj, Color p_color);
- void _button_resource_previewed(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, Variant p_ud);
-
- VisualScriptNode::TypeGuess _guess_output_type(int p_port_action_node, int p_port_action_output, RBSet<int> &p_visited_nodes);
-
- void _member_rmb_selected(const Vector2 &p_pos, MouseButton p_button);
- void _member_option(int p_option);
-
- void _toggle_scripts_pressed();
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- virtual void add_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) override;
- virtual void set_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) override;
-
- virtual void apply_code() override;
- virtual Ref<Resource> get_edited_resource() const override;
- virtual void set_edited_resource(const Ref<Resource> &p_res) override;
- virtual void enable_editor() override;
- virtual Vector<String> get_functions() override;
- virtual void reload_text() override;
- virtual String get_name() override;
- virtual Ref<Texture2D> get_theme_icon() override;
- virtual bool is_unsaved() override;
- virtual Variant get_edit_state() override;
- virtual void set_edit_state(const Variant &p_state) override;
- virtual void goto_line(int p_line, bool p_with_error = false) override;
- virtual void set_executing_line(int p_line) override;
- virtual void clear_executing_line() override;
- virtual void trim_trailing_whitespace() override;
- virtual void insert_final_newline() override;
- virtual void convert_indent_to_spaces() override;
- virtual void convert_indent_to_tabs() override;
- virtual void ensure_focus() override;
- virtual void tag_saved_version() override;
- virtual void reload(bool p_soft) override;
- virtual Array get_breakpoints() override;
- virtual void set_breakpoint(int p_line, bool p_enable) override{};
- virtual void clear_breakpoints() override{};
- virtual void add_callback(const String &p_function, PackedStringArray p_args) override;
- virtual void update_settings() override;
- virtual bool show_members_overview() override;
- virtual void set_debugger_active(bool p_active) override;
- virtual void set_tooltip_request_func(const Callable &p_toolip_callback) override;
- virtual Control *get_edit_menu() override;
- virtual void clear_edit_menu() override;
- virtual void set_find_replace_bar(FindReplaceBar *p_bar) override { p_bar->hide(); }; // Not needed here.
- virtual bool can_lose_focus_on_node_selection() override { return false; }
- virtual void validate() override;
-
- virtual Control *get_base_editor() const override;
-
- static void register_editor();
-
- static void free_clipboard();
-
- void update_toggle_scripts_button() override;
-
- VisualScriptEditor();
- ~VisualScriptEditor();
-};
-
-// Singleton
-class VisualScriptCustomNodes : public Object {
- GDCLASS(VisualScriptCustomNodes, Object);
-
- friend class VisualScriptLanguage;
-
-protected:
- static void _bind_methods();
- static VisualScriptCustomNodes *singleton;
-
- static HashMap<String, Ref<RefCounted>> custom_nodes;
- static Ref<VisualScriptNode> create_node_custom(const String &p_name);
-
-public:
- static VisualScriptCustomNodes *get_singleton() { return singleton; }
-
- void add_custom_node(const String &p_name, const String &p_category, const Ref<Script> &p_script);
- void remove_custom_node(const String &p_name, const String &p_category);
-
- VisualScriptCustomNodes();
- ~VisualScriptCustomNodes();
-};
-
-#endif
-
-#endif // VISUAL_SCRIPT_EDITOR_H
diff --git a/modules/visual_script/editor/visual_script_property_selector.cpp b/modules/visual_script/editor/visual_script_property_selector.cpp
deleted file mode 100644
index 712c89368b..0000000000
--- a/modules/visual_script/editor/visual_script_property_selector.cpp
+++ /dev/null
@@ -1,1277 +0,0 @@
-/*************************************************************************/
-/* visual_script_property_selector.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "visual_script_property_selector.h"
-
-#include "../visual_script.h"
-#include "../visual_script_builtin_funcs.h"
-#include "../visual_script_flow_control.h"
-#include "../visual_script_func_nodes.h"
-#include "../visual_script_nodes.h"
-#include "core/os/keyboard.h"
-#include "editor/doc_tools.h"
-#include "editor/editor_feature_profile.h"
-#include "editor/editor_scale.h"
-#include "editor/editor_settings.h"
-#include "scene/main/node.h"
-#include "scene/main/window.h"
-
-void VisualScriptPropertySelector::_update_icons() {
- search_box->set_right_icon(results_tree->get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
- search_box->set_clear_button_enabled(true);
- search_box->add_theme_icon_override("right_icon", results_tree->get_theme_icon(SNAME("Search"), SNAME("EditorIcons")));
-
- search_visual_script_nodes->set_icon(results_tree->get_theme_icon(SNAME("VisualScript"), SNAME("EditorIcons")));
- search_classes->set_icon(results_tree->get_theme_icon(SNAME("Object"), SNAME("EditorIcons")));
- search_methods->set_icon(results_tree->get_theme_icon(SNAME("MemberMethod"), SNAME("EditorIcons")));
- search_operators->set_icon(results_tree->get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
- search_signals->set_icon(results_tree->get_theme_icon(SNAME("MemberSignal"), SNAME("EditorIcons")));
- search_constants->set_icon(results_tree->get_theme_icon(SNAME("MemberConstant"), SNAME("EditorIcons")));
- search_properties->set_icon(results_tree->get_theme_icon(SNAME("MemberProperty"), SNAME("EditorIcons")));
- search_theme_items->set_icon(results_tree->get_theme_icon(SNAME("MemberTheme"), SNAME("EditorIcons")));
-
- case_sensitive_button->set_icon(results_tree->get_theme_icon(SNAME("MatchCase"), SNAME("EditorIcons")));
- hierarchy_button->set_icon(results_tree->get_theme_icon(SNAME("ClassList"), SNAME("EditorIcons")));
-}
-
-void VisualScriptPropertySelector::_sbox_input(const Ref<InputEvent> &p_ie) {
- Ref<InputEventKey> k = p_ie;
-
- if (k.is_valid()) {
- switch (k->get_keycode()) {
- case Key::UP:
- case Key::DOWN:
- case Key::PAGEUP:
- case Key::PAGEDOWN: {
- results_tree->gui_input(k);
- search_box->accept_event();
- } break;
- default:
- break;
- }
- }
-}
-
-void VisualScriptPropertySelector::_update_results_i(int p_int) {
- _update_results();
-}
-
-void VisualScriptPropertySelector::_update_results_s(String p_string) {
- _update_results();
-}
-
-void VisualScriptPropertySelector::_update_results_search_all() {
- if (search_classes->is_pressed()) {
- scope_combo->select(COMBO_ALL);
- }
- _update_results();
-}
-
-void VisualScriptPropertySelector::_update_results() {
- _update_icons();
- search_runner = Ref<SearchRunner>(memnew(SearchRunner(this, results_tree)));
- set_process(true);
-}
-
-void VisualScriptPropertySelector::_confirmed() {
- TreeItem *ti = results_tree->get_selected();
- if (!ti) {
- return;
- }
- emit_signal(SNAME("selected"), ti->get_metadata(0), ti->get_metadata(1), connecting);
- set_visible(false);
-}
-
-void VisualScriptPropertySelector::_item_selected() {
- help_bit->set_text(results_tree->get_selected()->get_meta("description", "No description available"));
-}
-
-void VisualScriptPropertySelector::_hide_requested() {
- _cancel_pressed(); // From AcceptDialog.
-}
-
-void VisualScriptPropertySelector::_notification(int p_what) {
- switch (p_what) {
- case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- _update_icons();
- } break;
-
- case NOTIFICATION_ENTER_TREE: {
- connect("confirmed", callable_mp(this, &VisualScriptPropertySelector::_confirmed));
- } break;
-
- case NOTIFICATION_PROCESS: {
- // Update background search.
- if (search_runner.is_valid()) {
- if (search_runner->work()) {
- // Search done.
- get_ok_button()->set_disabled(!results_tree->get_selected());
-
- search_runner = Ref<SearchRunner>();
- set_process(false);
- }
- } else {
- // if one is valid
- set_process(false);
- }
- } break;
- }
-}
-
-void VisualScriptPropertySelector::select_method_from_base_type(const String &p_base, const bool p_virtuals_only, const bool p_connecting, bool clear_text) {
- set_title(TTR("Select method from base type"));
- base_type = p_base;
- base_script = "";
- type = Variant::NIL;
- connecting = p_connecting;
-
- if (clear_text) {
- if (p_virtuals_only) {
- search_box->set_text("._"); // show all _methods
- search_box->set_caret_column(2);
- } else {
- search_box->set_text("."); // show all methods
- search_box->set_caret_column(1);
- }
- }
-
- search_visual_script_nodes->set_pressed(false);
- search_classes->set_pressed(false);
- search_methods->set_pressed(true);
- search_operators->set_pressed(false);
- search_signals->set_pressed(false);
- search_constants->set_pressed(false);
- search_properties->set_pressed(false);
- search_theme_items->set_pressed(false);
-
- scope_combo->select(COMBO_BASE);
-
- results_tree->clear();
- show_window(.5f);
- search_box->grab_focus();
-
- _update_results();
-}
-
-void VisualScriptPropertySelector::select_from_base_type(const String &p_base, const String &p_base_script, bool p_virtuals_only, const bool p_connecting, bool clear_text) {
- set_title(TTR("Select from base type"));
- base_type = p_base;
- base_script = p_base_script.trim_prefix("res://").quote(); // filepath to EditorHelp::get_doc_data().name
- type = Variant::NIL;
- connecting = p_connecting;
-
- if (clear_text) {
- if (p_virtuals_only) {
- search_box->set_text("_");
- } else {
- search_box->set_text(" ");
- }
- }
- search_box->select_all();
-
- search_visual_script_nodes->set_pressed(false);
- search_classes->set_pressed(false);
- search_methods->set_pressed(true);
- search_operators->set_pressed(false);
- search_signals->set_pressed(true);
- search_constants->set_pressed(false);
- search_properties->set_pressed(true);
- search_theme_items->set_pressed(false);
-
- scope_combo->select(COMBO_RELATED);
-
- results_tree->clear();
- show_window(.5f);
- search_box->grab_focus();
- _update_results();
-}
-
-void VisualScriptPropertySelector::select_from_script(const Ref<Script> &p_script, const bool p_connecting, bool clear_text) {
- set_title(TTR("Select from script"));
- ERR_FAIL_COND(p_script.is_null());
-
- base_type = p_script->get_instance_base_type();
- base_script = p_script->get_path().trim_prefix("res://").quote(); // filepath to EditorHelp::get_doc_data().name
- type = Variant::NIL;
- script = p_script->get_instance_id();
- connecting = p_connecting;
-
- if (clear_text) {
- search_box->set_text("");
- }
- search_box->select_all();
-
- search_visual_script_nodes->set_pressed(false);
- search_classes->set_pressed(true);
- search_methods->set_pressed(true);
- search_operators->set_pressed(true);
- search_signals->set_pressed(true);
- search_constants->set_pressed(true);
- search_properties->set_pressed(true);
- search_theme_items->set_pressed(false);
-
- scope_combo->select(COMBO_BASE);
-
- results_tree->clear();
- show_window(.5f);
- search_box->grab_focus();
- _update_results();
-}
-
-void VisualScriptPropertySelector::select_from_basic_type(Variant::Type p_type, const bool p_connecting, bool clear_text) {
- set_title(TTR("Select from basic type"));
- ERR_FAIL_COND(p_type == Variant::NIL);
- base_type = Variant::get_type_name(p_type);
- base_script = "";
- type = p_type;
- connecting = p_connecting;
-
- if (clear_text) {
- search_box->set_text(" ");
- }
- search_box->select_all();
-
- search_visual_script_nodes->set_pressed(false);
- search_classes->set_pressed(false);
- search_methods->set_pressed(true);
- search_operators->set_pressed(true);
- search_signals->set_pressed(false);
- search_constants->set_pressed(true);
- search_properties->set_pressed(true);
- search_theme_items->set_pressed(false);
-
- scope_combo->select(COMBO_BASE);
-
- results_tree->clear();
- show_window(.5f);
- search_box->grab_focus();
-
- _update_results();
-}
-
-void VisualScriptPropertySelector::select_from_action(const String &p_type, const bool p_connecting, bool clear_text) {
- set_title(TTR("Select from action"));
- base_type = p_type;
- base_script = "";
- type = Variant::NIL;
- connecting = p_connecting;
-
- if (clear_text) {
- search_box->set_text("");
- }
- search_box->select_all();
-
- search_visual_script_nodes->set_pressed(true);
- search_classes->set_pressed(false);
- search_methods->set_pressed(false);
- search_operators->set_pressed(false);
- search_signals->set_pressed(false);
- search_constants->set_pressed(false);
- search_properties->set_pressed(false);
- search_theme_items->set_pressed(false);
-
- scope_combo->select(COMBO_RELATED);
-
- results_tree->clear();
- show_window(.5f);
- search_box->grab_focus();
- _update_results();
-}
-
-void VisualScriptPropertySelector::select_from_instance(Object *p_instance, const bool p_connecting, bool clear_text) {
- set_title(TTR("Select from instance"));
- base_type = p_instance->get_class();
-
- const Ref<Script> &p_script = p_instance->get_script();
- if (p_script == nullptr) {
- base_script = "";
- } else {
- base_script = p_script->get_path().trim_prefix("res://").quote(); // filepath to EditorHelp::get_doc_data().name
- }
-
- type = Variant::NIL;
- connecting = p_connecting;
-
- if (clear_text) {
- search_box->set_text(" ");
- }
- search_box->select_all();
-
- search_visual_script_nodes->set_pressed(false);
- search_classes->set_pressed(false);
- search_methods->set_pressed(true);
- search_operators->set_pressed(false);
- search_signals->set_pressed(true);
- search_constants->set_pressed(true);
- search_properties->set_pressed(true);
- search_theme_items->set_pressed(false);
-
- scope_combo->select(COMBO_BASE);
-
- results_tree->clear();
- show_window(.5f);
- search_box->grab_focus();
- _update_results();
-}
-
-void VisualScriptPropertySelector::select_from_visual_script(const Ref<Script> &p_script, bool clear_text) {
- set_title(TTR("Select from visual script"));
- base_type = p_script->get_instance_base_type();
- if (p_script == nullptr) {
- base_script = "";
- } else {
- base_script = p_script->get_path().trim_prefix("res://").quote(); // filepath to EditorHelp::get_doc_data().name
- }
- type = Variant::NIL;
- connecting = false;
-
- if (clear_text) {
- search_box->set_text(" ");
- }
- search_box->select_all();
-
- search_visual_script_nodes->set_pressed(true);
- search_classes->set_pressed(false);
- search_methods->set_pressed(true);
- search_operators->set_pressed(false);
- search_signals->set_pressed(true);
- search_constants->set_pressed(true);
- search_properties->set_pressed(true);
- search_theme_items->set_pressed(false);
-
- scope_combo->select(COMBO_BASE);
-
- results_tree->clear();
- show_window(.5f);
- search_box->grab_focus();
- _update_results();
-}
-
-void VisualScriptPropertySelector::show_window(float p_screen_ratio) {
- popup_centered_ratio(p_screen_ratio);
-}
-
-void VisualScriptPropertySelector::_bind_methods() {
- ADD_SIGNAL(MethodInfo("selected", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::STRING, "category"), PropertyInfo(Variant::BOOL, "connecting")));
-}
-
-VisualScriptPropertySelector::VisualScriptPropertySelector() {
- vbox = memnew(VBoxContainer);
- add_child(vbox);
-
- HBoxContainer *hbox = memnew(HBoxContainer);
- hbox->set_alignment(hbox->ALIGNMENT_CENTER);
- vbox->add_child(hbox);
-
- case_sensitive_button = memnew(Button);
- case_sensitive_button->set_flat(true);
- case_sensitive_button->set_tooltip(TTR("Case Sensitive"));
- case_sensitive_button->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results));
- case_sensitive_button->set_toggle_mode(true);
- case_sensitive_button->set_focus_mode(Control::FOCUS_NONE);
- hbox->add_child(case_sensitive_button);
-
- hierarchy_button = memnew(Button);
- hierarchy_button->set_flat(true);
- hierarchy_button->set_tooltip(TTR("Show Hierarchy"));
- hierarchy_button->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results));
- hierarchy_button->set_toggle_mode(true);
- hierarchy_button->set_pressed(true);
- hierarchy_button->set_focus_mode(Control::FOCUS_NONE);
- hbox->add_child(hierarchy_button);
-
- hbox->add_child(memnew(VSeparator));
-
- search_visual_script_nodes = memnew(Button);
- search_visual_script_nodes->set_flat(true);
- search_visual_script_nodes->set_tooltip(TTR("Search Visual Script Nodes"));
- search_visual_script_nodes->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results));
- search_visual_script_nodes->set_toggle_mode(true);
- search_visual_script_nodes->set_pressed(true);
- search_visual_script_nodes->set_focus_mode(Control::FOCUS_NONE);
- hbox->add_child(search_visual_script_nodes);
-
- search_classes = memnew(Button);
- search_classes->set_flat(true);
- search_classes->set_tooltip(TTR("Search Classes"));
- search_classes->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results_search_all));
- search_classes->set_toggle_mode(true);
- search_classes->set_pressed(true);
- search_classes->set_focus_mode(Control::FOCUS_NONE);
- hbox->add_child(search_classes);
-
- search_operators = memnew(Button);
- search_operators->set_flat(true);
- search_operators->set_tooltip(TTR("Search Operators"));
- search_operators->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results));
- search_operators->set_toggle_mode(true);
- search_operators->set_pressed(true);
- search_operators->set_focus_mode(Control::FOCUS_NONE);
- hbox->add_child(search_operators);
-
- hbox->add_child(memnew(VSeparator));
-
- search_methods = memnew(Button);
- search_methods->set_flat(true);
- search_methods->set_tooltip(TTR("Search Methods"));
- search_methods->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results));
- search_methods->set_toggle_mode(true);
- search_methods->set_pressed(true);
- search_methods->set_focus_mode(Control::FOCUS_NONE);
- hbox->add_child(search_methods);
-
- search_signals = memnew(Button);
- search_signals->set_flat(true);
- search_signals->set_tooltip(TTR("Search Signals"));
- search_signals->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results));
- search_signals->set_toggle_mode(true);
- search_signals->set_pressed(true);
- search_signals->set_focus_mode(Control::FOCUS_NONE);
- hbox->add_child(search_signals);
-
- search_constants = memnew(Button);
- search_constants->set_flat(true);
- search_constants->set_tooltip(TTR("Search Constants"));
- search_constants->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results));
- search_constants->set_toggle_mode(true);
- search_constants->set_pressed(true);
- search_constants->set_focus_mode(Control::FOCUS_NONE);
- hbox->add_child(search_constants);
-
- search_properties = memnew(Button);
- search_properties->set_flat(true);
- search_properties->set_tooltip(TTR("Search Properties"));
- search_properties->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results));
- search_properties->set_toggle_mode(true);
- search_properties->set_pressed(true);
- search_properties->set_focus_mode(Control::FOCUS_NONE);
- hbox->add_child(search_properties);
-
- search_theme_items = memnew(Button);
- search_theme_items->set_flat(true);
- search_theme_items->set_tooltip(TTR("Search Theme Items"));
- search_theme_items->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results));
- search_theme_items->set_toggle_mode(true);
- search_theme_items->set_pressed(true);
- search_theme_items->set_focus_mode(Control::FOCUS_NONE);
- hbox->add_child(search_theme_items);
-
- scope_combo = memnew(OptionButton);
- scope_combo->set_custom_minimum_size(Size2(200, 0) * EDSCALE);
- scope_combo->set_tooltip(TTR("Select the search limits"));
- scope_combo->set_stretch_ratio(0); // Fixed width.
- scope_combo->add_item(TTR("Search Related"), SCOPE_RELATED);
- scope_combo->add_separator();
- scope_combo->add_item(TTR("Search Base"), SCOPE_BASE);
- scope_combo->add_item(TTR("Search Inheriters"), SCOPE_INHERITERS);
- scope_combo->add_item(TTR("Search Unrelated"), SCOPE_UNRELATED);
- scope_combo->add_item(TTR("Search All"), SCOPE_ALL);
- scope_combo->connect("item_selected", callable_mp(this, &VisualScriptPropertySelector::_update_results_i));
- hbox->add_child(scope_combo);
-
- search_box = memnew(LineEdit);
- search_box->set_tooltip(TTR("Enter \" \" to show all filtered options\nEnter \".\" to show all filtered methods, operators and constructors\nUse CTRL_KEY to drop property setters"));
- search_box->set_custom_minimum_size(Size2(200, 0) * EDSCALE);
- search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- search_box->connect("text_changed", callable_mp(this, &VisualScriptPropertySelector::_update_results_s));
- search_box->connect("gui_input", callable_mp(this, &VisualScriptPropertySelector::_sbox_input));
- register_text_enter(search_box);
- vbox->add_child(search_box);
-
- results_tree = memnew(Tree);
- results_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- results_tree->set_hide_root(true);
- results_tree->set_hide_folding(false);
- results_tree->set_columns(2);
- results_tree->set_column_title(0, TTR("Name"));
- results_tree->set_column_clip_content(0, true);
- results_tree->set_column_title(1, TTR("Member Type"));
- results_tree->set_column_expand(1, false);
- results_tree->set_column_custom_minimum_width(1, 150 * EDSCALE);
- results_tree->set_column_clip_content(1, true);
- results_tree->set_custom_minimum_size(Size2(0, 100) * EDSCALE);
- results_tree->set_select_mode(Tree::SELECT_ROW);
- results_tree->connect("item_activated", callable_mp(this, &VisualScriptPropertySelector::_confirmed));
- results_tree->connect("item_selected", callable_mp(this, &VisualScriptPropertySelector::_item_selected));
- vbox->add_child(results_tree);
-
- ScrollContainer *scroller = memnew(ScrollContainer);
- scroller->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
- scroller->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- scroller->set_custom_minimum_size(Size2(600, 400) * EDSCALE);
- vbox->add_child(scroller);
-
- help_bit = memnew(EditorHelpBit);
- help_bit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- help_bit->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- scroller->add_child(help_bit);
-
- help_bit->connect("request_hide", callable_mp(this, &VisualScriptPropertySelector::_hide_requested));
- set_ok_button_text(TTR("Open"));
- get_ok_button()->set_disabled(true);
- set_hide_on_ok(false);
-}
-
-bool VisualScriptPropertySelector::SearchRunner::_is_class_disabled_by_feature_profile(const StringName &p_class) {
- Ref<EditorFeatureProfile> profile = EditorFeatureProfileManager::get_singleton()->get_current_profile();
- if (profile.is_null()) {
- return false;
- }
-
- StringName class_name = p_class;
- while (class_name != StringName()) {
- if (!ClassDB::class_exists(class_name)) {
- return false;
- }
-
- if (profile->is_class_disabled(class_name)) {
- return true;
- }
- class_name = ClassDB::get_parent_class(class_name);
- }
-
- return false;
-}
-
-bool VisualScriptPropertySelector::SearchRunner::_is_class_disabled_by_scope(const StringName &p_class) {
- bool is_base_script = false;
- if (p_class == selector_ui->base_script) {
- is_base_script = true;
- }
- bool is_base = false;
- if (selector_ui->base_type == p_class) {
- is_base = true;
- }
- bool is_parent = false;
- if ((ClassDB::is_parent_class(selector_ui->base_type, p_class)) && !is_base) {
- is_parent = true;
- }
-
- bool is_inheriter = false;
- List<StringName> inheriters;
- ClassDB::get_inheriters_from_class(selector_ui->base_type, &inheriters);
- if (inheriters.find(p_class)) {
- is_inheriter = true;
- }
-
- if (scope_flags & SCOPE_BASE) {
- if (is_base_script || is_base || is_parent) {
- return false;
- }
- }
- if (scope_flags & SCOPE_INHERITERS) {
- if (is_base_script || is_base || is_inheriter) {
- return false;
- }
- }
- // if (scope_flags & SCOPE_RELATED) {
- // /* code */
- // }
- if (scope_flags & SCOPE_UNRELATED) {
- if (!is_base_script && !is_base && !is_inheriter) {
- return false;
- }
- }
- return true;
-}
-
-bool VisualScriptPropertySelector::SearchRunner::_slice() {
- bool phase_done = false;
- switch (phase) {
- case PHASE_INIT:
- phase_done = _phase_init();
- break;
- case PHASE_MATCH_CLASSES_INIT:
- phase_done = _phase_match_classes_init();
- break;
- case PHASE_NODE_CLASSES_INIT:
- phase_done = _phase_node_classes_init();
- break;
- case PHASE_NODE_CLASSES_BUILD:
- phase_done = _phase_node_classes_build();
- break;
- case PHASE_MATCH_CLASSES:
- phase_done = _phase_match_classes();
- break;
- case PHASE_CLASS_ITEMS_INIT:
- phase_done = _phase_class_items_init();
- break;
- case PHASE_CLASS_ITEMS:
- phase_done = _phase_class_items();
- break;
- case PHASE_MEMBER_ITEMS_INIT:
- phase_done = _phase_member_items_init();
- break;
- case PHASE_MEMBER_ITEMS:
- phase_done = _phase_member_items();
- break;
- case PHASE_SELECT_MATCH:
- phase_done = _phase_select_match();
- break;
- case PHASE_MAX:
- return true;
- default:
- WARN_PRINT("Invalid or unhandled phase in EditorHelpSearch::Runner, aborting search.");
- return true;
- };
-
- if (phase_done) {
- phase++;
- }
- return false;
-}
-
-bool VisualScriptPropertySelector::SearchRunner::_phase_init() {
- search_flags = 0; // selector_ui->filter_combo->get_selected_id();
- if (selector_ui->search_visual_script_nodes->is_pressed()) {
- search_flags |= SEARCH_VISUAL_SCRIPT_NODES;
- }
- if (selector_ui->search_classes->is_pressed()) {
- search_flags |= SEARCH_CLASSES;
- }
- // if (selector_ui->search_constructors->is_pressed()) {
- search_flags |= SEARCH_CONSTRUCTORS;
- // }
- if (selector_ui->search_methods->is_pressed()) {
- search_flags |= SEARCH_METHODS;
- }
- if (selector_ui->search_operators->is_pressed()) {
- search_flags |= SEARCH_OPERATORS;
- }
- if (selector_ui->search_signals->is_pressed()) {
- search_flags |= SEARCH_SIGNALS;
- }
- if (selector_ui->search_constants->is_pressed()) {
- search_flags |= SEARCH_CONSTANTS;
- }
- if (selector_ui->search_properties->is_pressed()) {
- search_flags |= SEARCH_PROPERTIES;
- }
- if (selector_ui->search_theme_items->is_pressed()) {
- search_flags |= SEARCH_THEME_ITEMS;
- }
- if (selector_ui->case_sensitive_button->is_pressed()) {
- search_flags |= SEARCH_CASE_SENSITIVE;
- }
- if (selector_ui->hierarchy_button->is_pressed()) {
- search_flags |= SEARCH_SHOW_HIERARCHY;
- }
- scope_flags = selector_ui->scope_combo->get_selected_id();
-
- return true;
-}
-
-bool VisualScriptPropertySelector::SearchRunner::_phase_match_classes_init() {
- combined_docs = EditorHelp::get_doc_data()->class_list;
- matches.clear();
- matched_item = nullptr;
- match_highest_score = 0;
-
- if (
- (selector_ui->base_script.unquote() != "") &&
- (selector_ui->base_script.unquote() != ".") &&
- !combined_docs.has(selector_ui->base_script)) {
- String file_path = "res://" + selector_ui->base_script.unquote(); // EditorHelp::get_doc_data().name to filepath
- Ref<Script> script;
- script = ResourceLoader::load(file_path);
- if (!script.is_null()) {
- DocData::ClassDoc class_doc = DocData::ClassDoc();
-
- class_doc.name = selector_ui->base_script;
-
- class_doc.inherits = script->get_instance_base_type();
- class_doc.brief_description = ".vs files not supported by EditorHelp::get_doc_data()";
- class_doc.description = "";
-
- Object *obj = ObjectDB::get_instance(script->get_instance_id());
- if (Object::cast_to<Script>(obj)) {
- List<MethodInfo> methods;
- Object::cast_to<Script>(obj)->get_script_method_list(&methods);
- for (List<MethodInfo>::Element *M = methods.front(); M; M = M->next()) {
- class_doc.methods.push_back(_get_method_doc(M->get()));
- }
-
- List<MethodInfo> signals;
- Object::cast_to<Script>(obj)->get_script_signal_list(&signals);
- for (List<MethodInfo>::Element *S = signals.front(); S; S = S->next()) {
- class_doc.signals.push_back(_get_method_doc(S->get()));
- }
-
- List<PropertyInfo> properties;
- Object::cast_to<Script>(obj)->get_script_property_list(&properties);
- for (List<PropertyInfo>::Element *P = properties.front(); P; P = P->next()) {
- DocData::PropertyDoc pd = DocData::PropertyDoc();
- pd.name = P->get().name;
- pd.type = Variant::get_type_name(P->get().type);
- class_doc.properties.push_back(pd);
- }
- }
- combined_docs.insert(class_doc.name, class_doc);
- }
- }
- iterator_doc = combined_docs.begin();
- return true;
-}
-
-bool VisualScriptPropertySelector::SearchRunner::_phase_node_classes_init() {
- VisualScriptLanguage::singleton->get_registered_node_names(&vs_nodes);
- _add_class_doc("functions", "", "");
- _add_class_doc("operators", "", "");
- return true;
-}
-
-bool VisualScriptPropertySelector::SearchRunner::_phase_node_classes_build() {
- if (vs_nodes.is_empty()) {
- return true;
- }
- String registered_node_name = vs_nodes[0];
- vs_nodes.pop_front();
-
- Vector<String> path = registered_node_name.split("/");
- if (path[0] == "constants") {
- _add_class_doc(registered_node_name, "", "constants");
- } else if (path[0] == "custom") {
- _add_class_doc(registered_node_name, "", "custom");
- } else if (path[0] == "data") {
- _add_class_doc(registered_node_name, "", "data");
- } else if (path[0] == "flow_control") {
- _add_class_doc(registered_node_name, "", "flow_control");
- } else if (path[0] == "functions") {
- if (path[1] == "built_in") {
- _add_class_doc(registered_node_name, "functions", "built_in");
- } else if (path[1] == "by_type") {
- // No action is required.
- // Using function references from ClassDB to remove confusion for users.
- } else if (path[1] == "constructors") {
- _add_class_doc(registered_node_name, "", "constructors");
- } else if (path[1] == "deconstruct") {
- _add_class_doc(registered_node_name, "", "deconstruct");
- } else if (path[1] == "wait") {
- _add_class_doc(registered_node_name, "functions", "yield");
- } else {
- _add_class_doc(registered_node_name, "functions", "");
- }
- } else if (path[0] == "index") {
- _add_class_doc(registered_node_name, "", "index");
- } else if (path[0] == "operators") {
- if (path[1] == "bitwise") {
- _add_class_doc(registered_node_name, "operators", "bitwise");
- } else if (path[1] == "compare") {
- _add_class_doc(registered_node_name, "operators", "compare");
- } else if (path[1] == "logic") {
- _add_class_doc(registered_node_name, "operators", "logic");
- } else if (path[1] == "math") {
- _add_class_doc(registered_node_name, "operators", "math");
- } else {
- _add_class_doc(registered_node_name, "operators", "");
- }
- }
- return false;
-}
-
-bool VisualScriptPropertySelector::SearchRunner::_phase_match_classes() {
- DocData::ClassDoc &class_doc = iterator_doc->value;
- if (
- (!_is_class_disabled_by_feature_profile(class_doc.name) && !_is_class_disabled_by_scope(class_doc.name)) ||
- _match_visual_script(class_doc)) {
- if (class_doc.inherits == "VisualScriptCustomNode") {
- class_doc.script_path = "res://" + class_doc.name.unquote();
- Ref<Script> script = ResourceLoader::load(class_doc.script_path);
- Ref<VisualScriptCustomNode> vsn;
- vsn.instantiate();
- vsn->set_script(script);
- class_doc.name = vsn->get_caption();
- if (combined_docs.has(vsn->get_category())) {
- class_doc.inherits = vsn->get_category();
- } else if (combined_docs.has("VisualScriptNode/" + vsn->get_category())) {
- class_doc.inherits = "VisualScriptNode/" + vsn->get_category();
- } else if (combined_docs.has("VisualScriptCustomNode/" + vsn->get_category())) {
- class_doc.inherits = "VisualScriptCustomNode/" + vsn->get_category();
- } else {
- class_doc.inherits = "";
- }
- class_doc.category = "VisualScriptCustomNode/" + vsn->get_category();
- class_doc.brief_description = "";
- class_doc.constructors.clear();
- class_doc.methods.clear();
- class_doc.operators.clear();
- class_doc.signals.clear();
- class_doc.constants.clear();
- class_doc.enums.clear();
- class_doc.properties.clear();
- class_doc.theme_properties.clear();
- }
-
- matches[class_doc.name] = ClassMatch();
- ClassMatch &match = matches[class_doc.name];
-
- match.category = class_doc.category;
- match.doc = &class_doc;
- // Match class name.
- if (search_flags & SEARCH_CLASSES || _match_visual_script(class_doc)) {
- if (term == "") {
- match.name = !_match_is_hidden(class_doc);
- } else {
- match.name = _match_string(term, class_doc.name);
- }
- // match.name = term == "" || _match_string(term, class_doc.name);
- }
-
- // Match members if the term is long enough.
- if (term.length() >= 0) {
- if (search_flags & SEARCH_CONSTRUCTORS) {
- for (int i = 0; i < class_doc.constructors.size(); i++) {
- String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? class_doc.constructors[i].name : class_doc.constructors[i].name.to_lower();
- if (method_name.find(term) > -1 ||
- term == " " ||
- (term.begins_with(".") && method_name.begins_with(term.substr(1))) ||
- (term.ends_with("(") && method_name.ends_with(term.left(term.length() - 1).strip_edges())) ||
- (term.begins_with(".") && term.ends_with("(") && method_name == term.substr(1, term.length() - 2).strip_edges())) {
- match.constructors.push_back(const_cast<DocData::MethodDoc *>(&class_doc.constructors[i]));
- }
- }
- }
- if (search_flags & SEARCH_METHODS) {
- for (int i = 0; i < class_doc.methods.size(); i++) {
- String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? class_doc.methods[i].name : class_doc.methods[i].name.to_lower();
- if (method_name.find(term) > -1 ||
- term == " " ||
- (term.begins_with(".") && method_name.begins_with(term.substr(1))) ||
- (term.ends_with("(") && method_name.ends_with(term.left(term.length() - 1).strip_edges())) ||
- (term.begins_with(".") && term.ends_with("(") && method_name == term.substr(1, term.length() - 2).strip_edges())) {
- match.methods.push_back(const_cast<DocData::MethodDoc *>(&class_doc.methods[i]));
- }
- }
- }
- if (search_flags & SEARCH_OPERATORS) {
- for (int i = 0; i < class_doc.operators.size(); i++) {
- String method_name = (search_flags & SEARCH_CASE_SENSITIVE) ? class_doc.operators[i].name : class_doc.operators[i].name.to_lower();
- if (method_name.find(term) > -1 ||
- term == " " ||
- (term.begins_with(".") && method_name.begins_with(term.substr(1))) ||
- (term.ends_with("(") && method_name.ends_with(term.left(term.length() - 1).strip_edges())) ||
- (term.begins_with(".") && term.ends_with("(") && method_name == term.substr(1, term.length() - 2).strip_edges())) {
- match.operators.push_back(const_cast<DocData::MethodDoc *>(&class_doc.operators[i]));
- }
- }
- }
- if (search_flags & SEARCH_SIGNALS) {
- for (int i = 0; i < class_doc.signals.size(); i++) {
- if (_match_string(term, class_doc.signals[i].name) ||
- term == " ") {
- match.signals.push_back(const_cast<DocData::MethodDoc *>(&class_doc.signals[i]));
- }
- }
- }
- if (search_flags & SEARCH_CONSTANTS) {
- for (int i = 0; i < class_doc.constants.size(); i++) {
- if (_match_string(term, class_doc.constants[i].name) ||
- term == " ") {
- match.constants.push_back(const_cast<DocData::ConstantDoc *>(&class_doc.constants[i]));
- }
- }
- }
- if (search_flags & SEARCH_PROPERTIES) {
- for (int i = 0; i < class_doc.properties.size(); i++) {
- if (_match_string(term, class_doc.properties[i].name) ||
- term == " " ||
- _match_string(term, class_doc.properties[i].getter) ||
- _match_string(term, class_doc.properties[i].setter)) {
- match.properties.push_back(const_cast<DocData::PropertyDoc *>(&class_doc.properties[i]));
- }
- }
- }
- if (search_flags & SEARCH_THEME_ITEMS) {
- for (int i = 0; i < class_doc.theme_properties.size(); i++) {
- if (_match_string(term, class_doc.theme_properties[i].name) ||
- term == " ") {
- match.theme_properties.push_back(const_cast<DocData::ThemeItemDoc *>(&class_doc.theme_properties[i]));
- }
- }
- }
- }
- }
-
- ++iterator_doc;
- return !iterator_doc;
-}
-
-bool VisualScriptPropertySelector::SearchRunner::_phase_class_items_init() {
- results_tree->clear();
- iterator_match = matches.begin();
-
- root_item = results_tree->create_item();
- class_items.clear();
-
- return true;
-}
-
-bool VisualScriptPropertySelector::SearchRunner::_phase_class_items() {
- if (!iterator_match) {
- return true;
- }
-
- ClassMatch &match = iterator_match->value;
-
- if (search_flags & SEARCH_SHOW_HIERARCHY) {
- if (match.required()) {
- _create_class_hierarchy(match);
- }
- } else {
- if (match.name) {
- _create_class_item(root_item, match.doc, true);
- }
- }
-
- ++iterator_match;
- return !iterator_match;
-}
-
-bool VisualScriptPropertySelector::SearchRunner::_phase_member_items_init() {
- iterator_match = matches.begin();
-
- return true;
-}
-
-bool VisualScriptPropertySelector::SearchRunner::_phase_member_items() {
- if (!iterator_match) {
- return true;
- }
-
- ClassMatch &match = iterator_match->value;
-
- TreeItem *parent = (search_flags & SEARCH_SHOW_HIERARCHY) ? class_items[match.doc->name] : root_item;
- bool constructor_created = false;
- for (int i = 0; i < match.methods.size(); i++) {
- String text = match.methods[i]->name;
- if (!constructor_created) {
- if (match.doc->name == match.methods[i]->name) {
- text += " " + TTR("(constructors)");
- constructor_created = true;
- }
- } else {
- if (match.doc->name == match.methods[i]->name) {
- continue;
- }
- }
- _create_method_item(parent, match.doc, text, match.methods[i]);
- }
- for (int i = 0; i < match.signals.size(); i++) {
- _create_signal_item(parent, match.doc, match.signals[i]);
- }
- for (int i = 0; i < match.constants.size(); i++) {
- _create_constant_item(parent, match.doc, match.constants[i]);
- }
- for (int i = 0; i < match.properties.size(); i++) {
- _create_property_item(parent, match.doc, match.properties[i]);
- }
- for (int i = 0; i < match.theme_properties.size(); i++) {
- _create_theme_property_item(parent, match.doc, match.theme_properties[i]);
- }
-
- ++iterator_match;
- return !iterator_match;
-}
-
-bool VisualScriptPropertySelector::SearchRunner::_phase_select_match() {
- if (matched_item) {
- matched_item->select(0);
- }
- return true;
-}
-
-bool VisualScriptPropertySelector::SearchRunner::_match_string(const String &p_term, const String &p_string) const {
- if (search_flags & SEARCH_CASE_SENSITIVE) {
- return p_string.find(p_term) > -1;
- } else {
- return p_string.findn(p_term) > -1;
- }
-}
-
-bool VisualScriptPropertySelector::SearchRunner::_match_visual_script(DocData::ClassDoc &class_doc) {
- if (class_doc.category.ends_with("_class")) {
- if (class_doc.category.begins_with("VisualScript") && search_flags & SEARCH_CLASSES) {
- if (matches.has(class_doc.inherits)) {
- return true;
- }
- }
- return false;
- }
- if (class_doc.category.begins_with("VisualScript") && search_flags & SEARCH_VISUAL_SCRIPT_NODES) {
- return true;
- }
- if (class_doc.name.begins_with("operators") && search_flags & SEARCH_OPERATORS) {
- return true;
- }
- if (class_doc.category.begins_with("VisualScriptNode/deconstruct")) {
- if (class_doc.name.find(selector_ui->base_type, 0) > -1) {
- return true;
- }
- }
-
- return false;
-}
-
-bool VisualScriptPropertySelector::SearchRunner::_match_is_hidden(DocData::ClassDoc &class_doc) {
- if (class_doc.category.begins_with("VisualScript")) {
- if (class_doc.name.begins_with("flow_control")) {
- return false;
- } else if (class_doc.name.begins_with("operators")) {
- return !(search_flags & SEARCH_OPERATORS);
- } else if (class_doc.name.begins_with("functions/built_in/print")) {
- return false;
- }
- return true;
- }
- return false;
-}
-
-void VisualScriptPropertySelector::SearchRunner::_match_item(TreeItem *p_item, const String &p_text) {
- float inverse_length = 1.f / float(p_text.length());
-
- // Favor types where search term is a substring close to the start of the type.
- float w = 0.5f;
- int pos = p_text.findn(term);
- float score = (pos > -1) ? 1.0f - w * MIN(1, 3 * pos * inverse_length) : MAX(0.f, .9f - w);
-
- // Favor shorter items: they resemble the search term more.
- w = 0.1f;
- score *= (1 - w) + w * (term.length() * inverse_length);
-
- if (match_highest_score == 0 || score > match_highest_score) {
- matched_item = p_item;
- match_highest_score = score;
- }
-}
-
-void VisualScriptPropertySelector::SearchRunner::_add_class_doc(String class_name, String inherits, String category) {
- DocData::ClassDoc class_doc = DocData::ClassDoc();
- class_doc.name = class_name;
- class_doc.inherits = inherits;
- class_doc.category = "VisualScriptNode/" + category;
- class_doc.brief_description = category;
- combined_docs.insert(class_doc.name, class_doc);
-}
-
-DocData::MethodDoc VisualScriptPropertySelector::SearchRunner::_get_method_doc(MethodInfo method_info) {
- DocData::MethodDoc method_doc = DocData::MethodDoc();
- method_doc.name = method_info.name;
- method_doc.return_type = Variant::get_type_name(method_info.return_val.type);
- method_doc.description = "No description available";
- for (List<PropertyInfo>::Element *P = method_info.arguments.front(); P; P = P->next()) {
- DocData::ArgumentDoc argument_doc = DocData::ArgumentDoc();
- argument_doc.name = P->get().name;
- argument_doc.type = Variant::get_type_name(P->get().type);
- method_doc.arguments.push_back(argument_doc);
- }
- return method_doc;
-}
-
-TreeItem *VisualScriptPropertySelector::SearchRunner::_create_class_hierarchy(const ClassMatch &p_match) {
- if (class_items.has(p_match.doc->name)) {
- return class_items[p_match.doc->name];
- }
-
- // Ensure parent nodes are created first.
- TreeItem *parent = root_item;
- if (p_match.doc->inherits != "") {
- if (class_items.has(p_match.doc->inherits)) {
- parent = class_items[p_match.doc->inherits];
- } else if (matches.has(p_match.doc->inherits)) {
- ClassMatch &base_match = matches[p_match.doc->inherits];
- parent = _create_class_hierarchy(base_match);
- }
- }
-
- TreeItem *class_item = _create_class_item(parent, p_match.doc, !p_match.name);
- class_items[p_match.doc->name] = class_item;
- return class_item;
-}
-
-TreeItem *VisualScriptPropertySelector::SearchRunner::_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray) {
- Ref<Texture2D> icon = empty_icon;
- String text_0 = p_doc->name;
- String text_1 = "Class";
-
- String what = "Class";
- String details = p_doc->name;
- if (p_doc->category.begins_with("VisualScriptCustomNode/")) {
- Vector<String> path = p_doc->name.split("/");
- icon = ui_service->get_theme_icon(SNAME("VisualScript"), SNAME("EditorIcons"));
- text_0 = path[path.size() - 1];
- text_1 = "VisualScriptCustomNode";
- what = "VisualScriptCustomNode";
- details = "CustomNode";
- } else if (p_doc->category.begins_with("VisualScriptNode/")) {
- Vector<String> path = p_doc->name.split("/");
- icon = ui_service->get_theme_icon(SNAME("VisualScript"), SNAME("EditorIcons"));
- text_0 = path[path.size() - 1];
- if (p_doc->category.begins_with("VisualScriptNode/deconstruct")) {
- text_0 = "deconstruct " + text_0;
- }
- text_1 = "VisualScriptNode";
- what = "VisualScriptNode";
- details = p_doc->name;
-
- if (path.size() == 1) {
- if (path[0] == "functions" || path[0] == "operators") {
- text_1 = "VisualScript";
- p_gray = true;
- what = "no_result";
- details = "";
- }
- }
-
- } else {
- if (p_doc->name.is_quoted()) {
- text_0 = p_doc->name.unquote().get_file();
- if (ui_service->has_theme_icon(p_doc->inherits, "EditorIcons")) {
- icon = ui_service->get_theme_icon(p_doc->inherits, "EditorIcons");
- }
- } else if (ui_service->has_theme_icon(p_doc->name, "EditorIcons")) {
- icon = ui_service->get_theme_icon(p_doc->name, "EditorIcons");
- } else if (ClassDB::class_exists(p_doc->name) && ClassDB::is_parent_class(p_doc->name, "Object")) {
- icon = ui_service->get_theme_icon(SNAME("Object"), SNAME("EditorIcons"));
- }
- }
- String tooltip = p_doc->brief_description.strip_edges();
-
- TreeItem *item = results_tree->create_item(p_parent);
- item->set_icon(0, icon);
- item->set_text(0, text_0);
- item->set_text(1, TTR(text_1));
- item->set_tooltip(0, tooltip);
- item->set_tooltip(1, tooltip);
- item->set_metadata(0, details);
- item->set_metadata(1, what);
- if (p_gray) {
- item->set_custom_color(0, disabled_color);
- item->set_custom_color(1, disabled_color);
- }
-
- _match_item(item, p_doc->name);
-
- return item;
-}
-
-TreeItem *VisualScriptPropertySelector::SearchRunner::_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc) {
- String tooltip = p_doc->return_type + " " + p_class_doc->name + "." + p_doc->name + "(";
- for (int i = 0; i < p_doc->arguments.size(); i++) {
- const DocData::ArgumentDoc &arg = p_doc->arguments[i];
- tooltip += arg.type + " " + arg.name;
- if (arg.default_value != "") {
- tooltip += " = " + arg.default_value;
- }
- if (i < p_doc->arguments.size() - 1) {
- tooltip += ", ";
- }
- }
- tooltip += ")";
- return _create_member_item(p_parent, p_class_doc->name, "MemberMethod", p_doc->name, p_text, TTRC("Method"), "method", tooltip, p_doc->description);
-}
-
-TreeItem *VisualScriptPropertySelector::SearchRunner::_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc) {
- String tooltip = p_doc->return_type + " " + p_class_doc->name + "." + p_doc->name + "(";
- for (int i = 0; i < p_doc->arguments.size(); i++) {
- const DocData::ArgumentDoc &arg = p_doc->arguments[i];
- tooltip += arg.type + " " + arg.name;
- if (arg.default_value != "") {
- tooltip += " = " + arg.default_value;
- }
- if (i < p_doc->arguments.size() - 1) {
- tooltip += ", ";
- }
- }
- tooltip += ")";
- return _create_member_item(p_parent, p_class_doc->name, "MemberSignal", p_doc->name, p_doc->name, TTRC("Signal"), "signal", tooltip, p_doc->description);
-}
-
-TreeItem *VisualScriptPropertySelector::SearchRunner::_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ConstantDoc *p_doc) {
- String tooltip = p_class_doc->name + "." + p_doc->name;
- return _create_member_item(p_parent, p_class_doc->name, "MemberConstant", p_doc->name, p_doc->name, TTRC("Constant"), "constant", tooltip, p_doc->description);
-}
-
-TreeItem *VisualScriptPropertySelector::SearchRunner::_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc) {
- String tooltip = p_doc->type + " " + p_class_doc->name + "." + p_doc->name;
- tooltip += "\n " + p_class_doc->name + "." + p_doc->setter + "(value) setter";
- tooltip += "\n " + p_class_doc->name + "." + p_doc->getter + "() getter";
- return _create_member_item(p_parent, p_class_doc->name, "MemberProperty", p_doc->name, p_doc->name, TTRC("Property"), "property", tooltip, p_doc->description);
-}
-
-TreeItem *VisualScriptPropertySelector::SearchRunner::_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ThemeItemDoc *p_doc) {
- String tooltip = p_doc->type + " " + p_class_doc->name + "." + p_doc->name;
- return _create_member_item(p_parent, p_class_doc->name, "MemberTheme", p_doc->name, p_doc->name, TTRC("Theme Property"), "theme_item", tooltip, p_doc->description);
-}
-
-TreeItem *VisualScriptPropertySelector::SearchRunner::_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, const String &p_description) {
- Ref<Texture2D> icon;
- String text;
- if (search_flags & SEARCH_SHOW_HIERARCHY) {
- icon = ui_service->get_theme_icon(p_icon, SNAME("EditorIcons"));
- text = p_text;
- } else {
- icon = ui_service->get_theme_icon(p_icon, SNAME("EditorIcons"));
- text = p_class_name + "." + p_text;
- }
-
- TreeItem *item = results_tree->create_item(p_parent);
- item->set_icon(0, icon);
- item->set_text(0, text);
- item->set_text(1, TTRGET(p_type));
- item->set_tooltip(0, p_tooltip);
- item->set_tooltip(1, p_tooltip);
- item->set_metadata(0, p_class_name + ":" + p_name);
- item->set_metadata(1, "class_" + p_metatype);
- item->set_meta("description", p_description);
-
- _match_item(item, p_name);
-
- return item;
-}
-
-bool VisualScriptPropertySelector::SearchRunner::work(uint64_t slot) {
- // Return true when the search has been completed, otherwise false.
- const uint64_t until = OS::get_singleton()->get_ticks_usec() + slot;
- while (!_slice()) {
- if (OS::get_singleton()->get_ticks_usec() > until) {
- return false;
- }
- }
- return true;
-}
-
-VisualScriptPropertySelector::SearchRunner::SearchRunner(VisualScriptPropertySelector *p_selector_ui, Tree *p_results_tree) :
- selector_ui(p_selector_ui),
- ui_service(p_selector_ui->vbox),
- results_tree(p_results_tree),
- term(p_selector_ui->search_box->get_text()),
- empty_icon(ui_service->get_theme_icon(SNAME("ArrowRight"), SNAME("EditorIcons"))),
- disabled_color(ui_service->get_theme_color(SNAME("disabled_font_color"), SNAME("Editor"))) {
-}
diff --git a/modules/visual_script/editor/visual_script_property_selector.h b/modules/visual_script/editor/visual_script_property_selector.h
deleted file mode 100644
index 4de626467e..0000000000
--- a/modules/visual_script/editor/visual_script_property_selector.h
+++ /dev/null
@@ -1,229 +0,0 @@
-/*************************************************************************/
-/* visual_script_property_selector.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef VISUAL_SCRIPT_PROPERTY_SELECTOR_H
-#define VISUAL_SCRIPT_PROPERTY_SELECTOR_H
-
-#include "../visual_script.h"
-#include "editor/editor_help.h"
-#include "scene/gui/rich_text_label.h"
-#include "scene/gui/tree.h"
-
-class VisualScriptPropertySelector : public ConfirmationDialog {
- GDCLASS(VisualScriptPropertySelector, ConfirmationDialog);
-
- enum SearchFlags {
- SEARCH_CLASSES = 1 << 0,
- SEARCH_CONSTRUCTORS = 1 << 1,
- SEARCH_METHODS = 1 << 2,
- SEARCH_OPERATORS = 1 << 3,
- SEARCH_SIGNALS = 1 << 4,
- SEARCH_CONSTANTS = 1 << 5,
- SEARCH_PROPERTIES = 1 << 6,
- SEARCH_THEME_ITEMS = 1 << 7,
- SEARCH_VISUAL_SCRIPT_NODES = 1 << 8,
- SEARCH_ALL = SEARCH_CLASSES | SEARCH_CONSTRUCTORS | SEARCH_METHODS | SEARCH_OPERATORS | SEARCH_SIGNALS | SEARCH_CONSTANTS | SEARCH_PROPERTIES | SEARCH_THEME_ITEMS,
- SEARCH_CASE_SENSITIVE = 1 << 29,
- SEARCH_SHOW_HIERARCHY = 1 << 30,
- };
-
- enum ScopeFlags {
- SCOPE_BASE = 1 << 0,
- SCOPE_INHERITERS = 1 << 1,
- SCOPE_UNRELATED = 1 << 2,
- SCOPE_RELATED = SCOPE_BASE | SCOPE_INHERITERS,
- SCOPE_ALL = SCOPE_BASE | SCOPE_INHERITERS | SCOPE_UNRELATED
- };
-
- enum ScopeCombo {
- COMBO_RELATED,
- COMBO_SEPARATOR,
- COMBO_BASE,
- COMBO_INHERITERS,
- COMBO_UNRELATED,
- COMBO_ALL,
- };
-
- LineEdit *search_box = nullptr;
-
- Button *case_sensitive_button = nullptr;
- Button *hierarchy_button = nullptr;
-
- Button *search_visual_script_nodes = nullptr;
- Button *search_classes = nullptr;
- Button *search_operators = nullptr;
-
- Button *search_methods = nullptr;
- Button *search_signals = nullptr;
- Button *search_constants = nullptr;
- Button *search_properties = nullptr;
- Button *search_theme_items = nullptr;
-
- OptionButton *scope_combo = nullptr;
- Tree *results_tree = nullptr;
-
- class SearchRunner;
- Ref<SearchRunner> search_runner;
-
- void _update_icons();
-
- void _sbox_input(const Ref<InputEvent> &p_ie);
- void _update_results_i(int p_int);
- void _update_results_s(String p_string);
- void _update_results_search_all();
- void _update_results();
-
- void _confirmed();
- void _item_selected();
- void _hide_requested();
-
- EditorHelpBit *help_bit = nullptr;
-
- bool properties = false;
- bool visual_script_generic = false;
- bool connecting = false;
- String selected;
- Variant::Type type;
- String base_type;
- String base_script;
- ObjectID script;
- Object *instance = nullptr;
- bool virtuals_only = false;
- VBoxContainer *vbox = nullptr;
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- void select_method_from_base_type(const String &p_base, const bool p_virtuals_only = false, const bool p_connecting = true, bool clear_text = true);
- void select_from_base_type(const String &p_base, const String &p_base_script = "", bool p_virtuals_only = false, const bool p_connecting = true, bool clear_text = true);
- void select_from_script(const Ref<Script> &p_script, const bool p_connecting = true, bool clear_text = true);
- void select_from_basic_type(Variant::Type p_type, const bool p_connecting = true, bool clear_text = true);
- void select_from_action(const String &p_type, const bool p_connecting = true, bool clear_text = true);
- void select_from_instance(Object *p_instance, const bool p_connecting = true, bool clear_text = true);
- void select_from_visual_script(const Ref<Script> &p_script, bool clear_text = true);
-
- void show_window(float p_screen_ratio);
-
- VisualScriptPropertySelector();
-};
-
-class VisualScriptPropertySelector::SearchRunner : public RefCounted {
- enum Phase {
- PHASE_INIT,
- PHASE_MATCH_CLASSES_INIT,
- PHASE_NODE_CLASSES_INIT,
- PHASE_NODE_CLASSES_BUILD,
- PHASE_MATCH_CLASSES,
- PHASE_CLASS_ITEMS_INIT,
- PHASE_CLASS_ITEMS,
- PHASE_MEMBER_ITEMS_INIT,
- PHASE_MEMBER_ITEMS,
- PHASE_SELECT_MATCH,
- PHASE_MAX
- };
- int phase = 0;
-
- struct ClassMatch {
- DocData::ClassDoc *doc;
- bool name = false;
- String category = "";
- Vector<DocData::MethodDoc *> constructors;
- Vector<DocData::MethodDoc *> methods;
- Vector<DocData::MethodDoc *> operators;
- Vector<DocData::MethodDoc *> signals;
- Vector<DocData::ConstantDoc *> constants;
- Vector<DocData::PropertyDoc *> properties;
- Vector<DocData::ThemeItemDoc *> theme_properties;
-
- bool required() {
- return name || methods.size() || signals.size() || constants.size() || properties.size() || theme_properties.size();
- }
- };
-
- VisualScriptPropertySelector *selector_ui = nullptr;
- Control *ui_service = nullptr;
- Tree *results_tree = nullptr;
- String term;
- int search_flags = 0;
- int scope_flags = 0;
-
- Ref<Texture2D> empty_icon;
- Color disabled_color;
-
- HashMap<String, DocData::ClassDoc>::Iterator iterator_doc;
- HashMap<String, ClassMatch> matches;
- HashMap<String, ClassMatch>::Iterator iterator_match;
- TreeItem *root_item = nullptr;
- HashMap<String, TreeItem *> class_items;
- TreeItem *matched_item = nullptr;
- float match_highest_score = 0;
-
- HashMap<String, DocData::ClassDoc> combined_docs;
- List<String> vs_nodes;
-
- bool _is_class_disabled_by_feature_profile(const StringName &p_class);
- bool _is_class_disabled_by_scope(const StringName &p_class);
-
- bool _slice();
- bool _phase_init();
- bool _phase_match_classes_init();
- bool _phase_node_classes_init();
- bool _phase_node_classes_build();
- bool _phase_match_classes();
- bool _phase_class_items_init();
- bool _phase_class_items();
- bool _phase_member_items_init();
- bool _phase_member_items();
- bool _phase_select_match();
-
- bool _match_string(const String &p_term, const String &p_string) const;
- bool _match_visual_script(DocData::ClassDoc &class_doc);
- bool _match_is_hidden(DocData::ClassDoc &class_doc);
- void _match_item(TreeItem *p_item, const String &p_text);
- void _add_class_doc(String class_name, String inherits, String category);
- DocData::MethodDoc _get_method_doc(MethodInfo method_info);
- TreeItem *_create_class_hierarchy(const ClassMatch &p_match);
- TreeItem *_create_class_item(TreeItem *p_parent, const DocData::ClassDoc *p_doc, bool p_gray);
- TreeItem *_create_method_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const String &p_text, const DocData::MethodDoc *p_doc);
- TreeItem *_create_signal_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::MethodDoc *p_doc);
- TreeItem *_create_constant_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ConstantDoc *p_doc);
- TreeItem *_create_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::PropertyDoc *p_doc);
- TreeItem *_create_theme_property_item(TreeItem *p_parent, const DocData::ClassDoc *p_class_doc, const DocData::ThemeItemDoc *p_doc);
- TreeItem *_create_member_item(TreeItem *p_parent, const String &p_class_name, const String &p_icon, const String &p_name, const String &p_text, const String &p_type, const String &p_metatype, const String &p_tooltip, const String &p_description);
-
-public:
- bool work(uint64_t slot = 100000);
-
- SearchRunner(VisualScriptPropertySelector *p_selector_ui, Tree *p_results_tree);
-};
-
-#endif // VISUAL_SCRIPT_PROPERTY_SELECTOR_H
diff --git a/modules/visual_script/icons/VisualScript.svg b/modules/visual_script/icons/VisualScript.svg
deleted file mode 100644
index bc698247c9..0000000000
--- a/modules/visual_script/icons/VisualScript.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g transform="translate(0 -1036.4)"><ellipse cx="3" cy="1039.4" fill="#e0e0e0"/><path d="m7 1-.56445 2.2578a5 5 0 0 0 -.68945.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -.28516.68555l-2.2539.5625v2h5.2715a2 2 0 0 1 -.27148-1 2 2 0 0 1 2-2 2 2 0 0 1 2 2 2 2 0 0 1 -.26953 1h5.2695v-2l-2.2578-.56445a5 5 0 0 0 -.2793-.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -.68555-.28516l-.5625-2.2539h-2zm-4 9v6h2a3 3 0 0 0 3-3v-3h-2v3a1 1 0 0 1 -1 1v-4zm8 0a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v2h2a2 2 0 0 0 1.7324-1 2 2 0 0 0 0-2 2 2 0 0 0 -1.7324-1h2v-2z" fill="#e0e0e0" transform="translate(0 1036.4)"/></g></svg>
diff --git a/modules/visual_script/icons/VisualScriptInternal.svg b/modules/visual_script/icons/VisualScriptInternal.svg
deleted file mode 100644
index 8ab39ad929..0000000000
--- a/modules/visual_script/icons/VisualScriptInternal.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><circle cx="3" cy="3.000024" fill="#e0e0e0" r="0"/><path d="m11 10a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v2h2a2 2 0 0 0 1.7324-1 2 2 0 0 0 0-2 2 2 0 0 0 -1.7324-1h2v-2z" fill="#e0e0e0"/><path d="m3 10v6h2a3 3 0 0 0 3-3v-3h-2v3a1 1 0 0 1 -1 1v-4z" fill="#e0e0e0"/><path d="m7 1-.56445 2.2578a5 5 0 0 0 -.68945.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -.28516.68555l-2.2539.5625v2h5.2715a2 2 0 0 1 -.27148-1 2 2 0 0 1 2-2 2 2 0 0 1 2 2 2 2 0 0 1 -.26953 1h5.2695v-2l-2.2578-.56445a5 5 0 0 0 -.2793-.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -.68555-.28516l-.5625-2.2539h-2z" fill="none" stroke="#e0e0e0"/></svg>
diff --git a/modules/visual_script/register_types.cpp b/modules/visual_script/register_types.cpp
deleted file mode 100644
index 04a7442d0a..0000000000
--- a/modules/visual_script/register_types.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-/*************************************************************************/
-/* register_types.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "register_types.h"
-
-#include "core/config/engine.h"
-#include "core/io/resource_loader.h"
-#include "visual_script.h"
-#include "visual_script_builtin_funcs.h"
-#include "visual_script_expression.h"
-#include "visual_script_flow_control.h"
-#include "visual_script_func_nodes.h"
-#include "visual_script_nodes.h"
-#include "visual_script_yield_nodes.h"
-
-VisualScriptLanguage *visual_script_language = nullptr;
-
-#ifdef TOOLS_ENABLED
-#include "editor/visual_script_editor.h"
-static VisualScriptCustomNodes *vs_custom_nodes_singleton = nullptr;
-#endif
-
-void initialize_visual_script_module(ModuleInitializationLevel p_level) {
- if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) {
- visual_script_language = memnew(VisualScriptLanguage);
- //script_language_gd->init();
- ScriptServer::register_language(visual_script_language);
-
- GDREGISTER_CLASS(VisualScript);
- GDREGISTER_ABSTRACT_CLASS(VisualScriptNode);
- GDREGISTER_CLASS(VisualScriptFunctionState);
- GDREGISTER_CLASS(VisualScriptFunction);
- GDREGISTER_ABSTRACT_CLASS(VisualScriptLists);
- GDREGISTER_CLASS(VisualScriptComposeArray);
- GDREGISTER_CLASS(VisualScriptOperator);
- GDREGISTER_CLASS(VisualScriptVariableSet);
- GDREGISTER_CLASS(VisualScriptVariableGet);
- GDREGISTER_CLASS(VisualScriptConstant);
- GDREGISTER_CLASS(VisualScriptIndexGet);
- GDREGISTER_CLASS(VisualScriptIndexSet);
- GDREGISTER_CLASS(VisualScriptGlobalConstant);
- GDREGISTER_CLASS(VisualScriptClassConstant);
- GDREGISTER_CLASS(VisualScriptMathConstant);
- GDREGISTER_CLASS(VisualScriptBasicTypeConstant);
- GDREGISTER_CLASS(VisualScriptEngineSingleton);
- GDREGISTER_CLASS(VisualScriptSceneNode);
- GDREGISTER_CLASS(VisualScriptSceneTree);
- GDREGISTER_CLASS(VisualScriptResourcePath);
- GDREGISTER_CLASS(VisualScriptSelf);
- GDREGISTER_CLASS(VisualScriptCustomNode);
- GDREGISTER_CLASS(VisualScriptSubCall);
- GDREGISTER_CLASS(VisualScriptComment);
- GDREGISTER_CLASS(VisualScriptConstructor);
- GDREGISTER_CLASS(VisualScriptLocalVar);
- GDREGISTER_CLASS(VisualScriptLocalVarSet);
- GDREGISTER_CLASS(VisualScriptInputAction);
- GDREGISTER_CLASS(VisualScriptDeconstruct);
- GDREGISTER_CLASS(VisualScriptPreload);
- GDREGISTER_CLASS(VisualScriptTypeCast);
-
- GDREGISTER_CLASS(VisualScriptFunctionCall);
- GDREGISTER_CLASS(VisualScriptPropertySet);
- GDREGISTER_CLASS(VisualScriptPropertyGet);
- //ClassDB::register_type<VisualScriptScriptCall>();
- GDREGISTER_CLASS(VisualScriptEmitSignal);
-
- GDREGISTER_CLASS(VisualScriptReturn);
- GDREGISTER_CLASS(VisualScriptCondition);
- GDREGISTER_CLASS(VisualScriptWhile);
- GDREGISTER_CLASS(VisualScriptIterator);
- GDREGISTER_CLASS(VisualScriptSequence);
- //GDREGISTER_CLASS(VisualScriptInputFilter);
- GDREGISTER_CLASS(VisualScriptSwitch);
- GDREGISTER_CLASS(VisualScriptSelect);
-
- GDREGISTER_CLASS(VisualScriptYield);
- GDREGISTER_CLASS(VisualScriptYieldSignal);
-
- GDREGISTER_CLASS(VisualScriptBuiltinFunc);
-
- GDREGISTER_CLASS(VisualScriptExpression);
-
- register_visual_script_nodes();
- register_visual_script_func_nodes();
- register_visual_script_builtin_func_node();
- register_visual_script_flow_control_nodes();
- register_visual_script_yield_nodes();
- register_visual_script_expression_node();
- }
-
-#ifdef TOOLS_ENABLED
- if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
- ClassDB::set_current_api(ClassDB::API_EDITOR);
- GDREGISTER_CLASS(VisualScriptCustomNodes);
- ClassDB::set_current_api(ClassDB::API_CORE);
- vs_custom_nodes_singleton = memnew(VisualScriptCustomNodes);
- Engine::get_singleton()->add_singleton(Engine::Singleton("VisualScriptCustomNodes", VisualScriptCustomNodes::get_singleton()));
-
- VisualScriptEditor::register_editor();
- }
-#endif
-}
-
-void uninitialize_visual_script_module(ModuleInitializationLevel p_level) {
- if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) {
- unregister_visual_script_nodes();
-
- ScriptServer::unregister_language(visual_script_language);
-
- if (visual_script_language) {
- memdelete(visual_script_language);
- }
- }
-
-#ifdef TOOLS_ENABLED
- if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
- VisualScriptEditor::free_clipboard();
- if (vs_custom_nodes_singleton) {
- memdelete(vs_custom_nodes_singleton);
- }
- }
-#endif
-}
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
deleted file mode 100644
index 4215a979e0..0000000000
--- a/modules/visual_script/visual_script.cpp
+++ /dev/null
@@ -1,2502 +0,0 @@
-/*************************************************************************/
-/* visual_script.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "visual_script.h"
-
-#include "core/config/project_settings.h"
-#include "core/core_string_names.h"
-#include "core/os/os.h"
-#include "scene/main/node.h"
-#include "visual_script_nodes.h"
-
-// Used by editor, this is not really saved.
-void VisualScriptNode::set_breakpoint(bool p_breakpoint) {
- breakpoint = p_breakpoint;
-}
-
-bool VisualScriptNode::is_breakpoint() const {
- return breakpoint;
-}
-
-void VisualScriptNode::ports_changed_notify() {
- emit_signal(SNAME("ports_changed"));
-}
-
-void VisualScriptNode::set_default_input_value(int p_port, const Variant &p_value) {
- ERR_FAIL_INDEX(p_port, default_input_values.size());
-
- default_input_values[p_port] = p_value;
-
-#ifdef TOOLS_ENABLED
- if (script_used.is_valid()) {
- script_used->set_edited(true);
- }
-#endif
-}
-
-Variant VisualScriptNode::get_default_input_value(int p_port) const {
- ERR_FAIL_INDEX_V(p_port, default_input_values.size(), Variant());
- return default_input_values[p_port];
-}
-
-void VisualScriptNode::_set_default_input_values(Array p_values) {
- default_input_values = p_values;
-}
-
-void VisualScriptNode::validate_input_default_values() {
- default_input_values.resize(MAX(default_input_values.size(), get_input_value_port_count())); //let it grow as big as possible, we don't want to lose values on resize
-
- // Actually validate on save.
- for (int i = 0; i < get_input_value_port_count(); i++) {
- Variant::Type expected = get_input_value_port_info(i).type;
-
- if (expected == Variant::NIL || expected == default_input_values[i].get_type()) {
- continue;
- } else {
- // Not the same, reconvert.
- Callable::CallError ce;
- Variant existing = default_input_values[i];
- const Variant *existingp = &existing;
- Variant::construct(expected, default_input_values[i], &existingp, 1, ce);
- if (ce.error != Callable::CallError::CALL_OK) {
- //could not convert? force..
- Variant::construct(expected, default_input_values[i], nullptr, 0, ce);
- }
- }
- }
-}
-
-Array VisualScriptNode::_get_default_input_values() const {
- // Validate on save, since on load there is little info about this.
- Array values = default_input_values;
- values.resize(get_input_value_port_count());
-
- return values;
-}
-
-String VisualScriptNode::get_text() const {
- return "";
-}
-
-void VisualScriptNode::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_visual_script"), &VisualScriptNode::get_visual_script);
- ClassDB::bind_method(D_METHOD("set_default_input_value", "port_idx", "value"), &VisualScriptNode::set_default_input_value);
- ClassDB::bind_method(D_METHOD("get_default_input_value", "port_idx"), &VisualScriptNode::get_default_input_value);
- ClassDB::bind_method(D_METHOD("ports_changed_notify"), &VisualScriptNode::ports_changed_notify);
- ClassDB::bind_method(D_METHOD("_set_default_input_values", "values"), &VisualScriptNode::_set_default_input_values);
- ClassDB::bind_method(D_METHOD("_get_default_input_values"), &VisualScriptNode::_get_default_input_values);
-
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_default_input_values", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_default_input_values", "_get_default_input_values");
- ADD_SIGNAL(MethodInfo("ports_changed"));
-}
-
-VisualScriptNode::TypeGuess VisualScriptNode::guess_output_type(TypeGuess *p_inputs, int p_output) const {
- ERR_FAIL_COND_V(get_output_value_port_count() <= p_output, TypeGuess());
-
- PropertyInfo pinfo = get_output_value_port_info(p_output);
-
- TypeGuess tg;
-
- tg.type = pinfo.type;
- if (pinfo.hint == PROPERTY_HINT_RESOURCE_TYPE) {
- tg.gdclass = pinfo.hint_string;
- }
-
- return tg;
-}
-
-Ref<VisualScript> VisualScriptNode::get_visual_script() const {
- return script_used;
-}
-
-VisualScriptNode::VisualScriptNode() {
-}
-
-////////////////
-
-/////////////////////
-
-VisualScriptNodeInstance::VisualScriptNodeInstance() {
-}
-
-VisualScriptNodeInstance::~VisualScriptNodeInstance() {
- if (sequence_outputs) {
- memdelete_arr(sequence_outputs);
- }
-
- if (input_ports) {
- memdelete_arr(input_ports);
- }
-
- if (output_ports) {
- memdelete_arr(output_ports);
- }
-}
-
-void VisualScript::add_function(const StringName &p_name, int p_func_node_id) {
- ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(!String(p_name).is_valid_identifier());
- ERR_FAIL_COND(functions.has(p_name));
- ERR_FAIL_COND(variables.has(p_name));
- ERR_FAIL_COND(custom_signals.has(p_name));
-
- functions[p_name] = Function();
- functions[p_name].func_id = p_func_node_id;
-}
-
-bool VisualScript::has_function(const StringName &p_name) const {
- return functions.has(p_name);
-}
-
-void VisualScript::remove_function(const StringName &p_name) {
- ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(!functions.has(p_name));
-
- // Let the editor handle the node removal.
- functions.erase(p_name);
-}
-
-void VisualScript::rename_function(const StringName &p_name, const StringName &p_new_name) {
- ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(!functions.has(p_name));
- if (p_new_name == p_name) {
- return;
- }
-
- ERR_FAIL_COND(!String(p_new_name).is_valid_identifier());
-
- ERR_FAIL_COND(functions.has(p_new_name));
- ERR_FAIL_COND(variables.has(p_new_name));
- ERR_FAIL_COND(custom_signals.has(p_new_name));
-
- functions[p_new_name] = functions[p_name];
- functions.erase(p_name);
-}
-
-void VisualScript::set_scroll(const Vector2 &p_scroll) {
- scroll = p_scroll;
-}
-
-Vector2 VisualScript::get_scroll() const {
- return scroll;
-}
-
-void VisualScript::get_function_list(List<StringName> *r_functions) const {
- for (const KeyValue<StringName, Function> &E : functions) {
- r_functions->push_back(E.key);
- }
-}
-
-int VisualScript::get_function_node_id(const StringName &p_name) const {
- ERR_FAIL_COND_V(!functions.has(p_name), -1);
-
- return functions[p_name].func_id;
-}
-
-void VisualScript::_node_ports_changed(int p_id) {
- Ref<VisualScriptNode> vsn = nodes[p_id].node;
-
- vsn->validate_input_default_values();
-
- // Must revalidate all the functions.
-
- {
- List<SequenceConnection> to_remove;
-
- for (const SequenceConnection &E : sequence_connections) {
- if (E.from_node == p_id && E.from_output >= vsn->get_output_sequence_port_count()) {
- to_remove.push_back(E);
- }
- if (E.to_node == p_id && !vsn->has_input_sequence_port()) {
- to_remove.push_back(E);
- }
- }
-
- while (to_remove.size()) {
- sequence_connections.erase(to_remove.front()->get());
- to_remove.pop_front();
- }
- }
-
- {
- List<DataConnection> to_remove;
-
- for (const DataConnection &E : data_connections) {
- if (E.from_node == p_id && E.from_port >= vsn->get_output_value_port_count()) {
- to_remove.push_back(E);
- }
- if (E.to_node == p_id && E.to_port >= vsn->get_input_value_port_count()) {
- to_remove.push_back(E);
- }
- }
-
- while (to_remove.size()) {
- data_connections.erase(to_remove.front()->get());
- to_remove.pop_front();
- }
- }
-
-#ifdef TOOLS_ENABLED
- set_edited(true); // Something changed, let's set as edited.
- emit_signal(SNAME("node_ports_changed"), p_id);
-#endif
-}
-
-void VisualScript::add_node(int p_id, const Ref<VisualScriptNode> &p_node, const Point2 &p_pos) {
- ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(nodes.has(p_id)); // ID can exist only one in script.
- ERR_FAIL_COND(p_node.is_null());
-
- NodeData nd;
- nd.node = p_node;
- nd.pos = p_pos;
-
- Ref<VisualScriptNode> vsn = p_node;
- vsn->connect("ports_changed", callable_mp(this, &VisualScript::_node_ports_changed).bind(p_id));
- vsn->script_used = Ref<VisualScript>(this);
- vsn->validate_input_default_values(); // Validate when fully loaded.
-
- nodes[p_id] = nd;
-}
-
-void VisualScript::remove_node(int p_id) {
- ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(!nodes.has(p_id));
- {
- List<SequenceConnection> to_remove;
-
- for (const SequenceConnection &E : sequence_connections) {
- if (E.from_node == p_id || E.to_node == p_id) {
- to_remove.push_back(E);
- }
- }
-
- while (to_remove.size()) {
- sequence_connections.erase(to_remove.front()->get());
- to_remove.pop_front();
- }
- }
-
- {
- List<DataConnection> to_remove;
-
- for (const DataConnection &E : data_connections) {
- if (E.from_node == p_id || E.to_node == p_id) {
- to_remove.push_back(E);
- }
- }
-
- while (to_remove.size()) {
- data_connections.erase(to_remove.front()->get());
- to_remove.pop_front();
- }
- }
-
- nodes[p_id].node->disconnect("ports_changed", callable_mp(this, &VisualScript::_node_ports_changed));
- nodes[p_id].node->script_used.unref();
-
- nodes.erase(p_id);
-}
-
-bool VisualScript::has_node(int p_id) const {
- return nodes.has(p_id);
-}
-
-Ref<VisualScriptNode> VisualScript::get_node(int p_id) const {
- ERR_FAIL_COND_V(!nodes.has(p_id), Ref<VisualScriptNode>());
-
- return nodes[p_id].node;
-}
-
-void VisualScript::set_node_position(int p_id, const Point2 &p_pos) {
- ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(!nodes.has(p_id));
- nodes[p_id].pos = p_pos;
-}
-
-Point2 VisualScript::get_node_position(int p_id) const {
- ERR_FAIL_COND_V(!nodes.has(p_id), Point2());
- return nodes[p_id].pos;
-}
-
-void VisualScript::get_node_list(List<int> *r_nodes) const {
- for (const KeyValue<int, NodeData> &E : nodes) {
- r_nodes->push_back(E.key);
- }
-}
-
-void VisualScript::sequence_connect(int p_from_node, int p_from_output, int p_to_node) {
- ERR_FAIL_COND(instances.size());
-
- SequenceConnection sc;
- sc.from_node = p_from_node;
- sc.from_output = p_from_output;
- sc.to_node = p_to_node;
- ERR_FAIL_COND(sequence_connections.has(sc));
-
- sequence_connections.insert(sc);
-}
-
-void VisualScript::sequence_disconnect(int p_from_node, int p_from_output, int p_to_node) {
- SequenceConnection sc;
- sc.from_node = p_from_node;
- sc.from_output = p_from_output;
- sc.to_node = p_to_node;
- ERR_FAIL_COND(!sequence_connections.has(sc));
-
- sequence_connections.erase(sc);
-}
-
-bool VisualScript::has_sequence_connection(int p_from_node, int p_from_output, int p_to_node) const {
- SequenceConnection sc;
- sc.from_node = p_from_node;
- sc.from_output = p_from_output;
- sc.to_node = p_to_node;
-
- return sequence_connections.has(sc);
-}
-
-void VisualScript::get_sequence_connection_list(List<SequenceConnection> *r_connection) const {
- for (const SequenceConnection &E : sequence_connections) {
- r_connection->push_back(E);
- }
-}
-
-void VisualScript::data_connect(int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
- ERR_FAIL_COND(instances.size());
-
- DataConnection dc;
- dc.from_node = p_from_node;
- dc.from_port = p_from_port;
- dc.to_node = p_to_node;
- dc.to_port = p_to_port;
-
- ERR_FAIL_COND(data_connections.has(dc));
-
- data_connections.insert(dc);
-}
-
-void VisualScript::data_disconnect(int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
- DataConnection dc;
- dc.from_node = p_from_node;
- dc.from_port = p_from_port;
- dc.to_node = p_to_node;
- dc.to_port = p_to_port;
-
- ERR_FAIL_COND(!data_connections.has(dc));
-
- data_connections.erase(dc);
-}
-
-bool VisualScript::has_data_connection(int p_from_node, int p_from_port, int p_to_node, int p_to_port) const {
- DataConnection dc;
- dc.from_node = p_from_node;
- dc.from_port = p_from_port;
- dc.to_node = p_to_node;
- dc.to_port = p_to_port;
-
- return data_connections.has(dc);
-}
-
-bool VisualScript::is_input_value_port_connected(int p_node, int p_port) const {
- for (const DataConnection &E : data_connections) {
- if (E.to_node == p_node && E.to_port == p_port) {
- return true;
- }
- }
- return false;
-}
-
-bool VisualScript::get_input_value_port_connection_source(int p_node, int p_port, int *r_node, int *r_port) const {
- for (const DataConnection &E : data_connections) {
- if (E.to_node == p_node && E.to_port == p_port) {
- *r_node = E.from_node;
- *r_port = E.from_port;
- return true;
- }
- }
- return false;
-}
-
-void VisualScript::get_data_connection_list(List<DataConnection> *r_connection) const {
- for (const DataConnection &E : data_connections) {
- r_connection->push_back(E);
- }
-}
-
-void VisualScript::set_tool_enabled(bool p_enabled) {
- is_tool_script = p_enabled;
-}
-
-void VisualScript::add_variable(const StringName &p_name, const Variant &p_default_value, bool p_export) {
- ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(!String(p_name).is_valid_identifier());
- ERR_FAIL_COND(variables.has(p_name));
-
- Variable v;
- v.default_value = p_default_value;
- v.info.type = p_default_value.get_type();
- v.info.name = p_name;
- v.info.hint = PROPERTY_HINT_NONE;
- v._export = p_export;
-
- variables[p_name] = v;
-
-#ifdef TOOLS_ENABLED
- _update_placeholders();
-#endif
-}
-
-bool VisualScript::has_variable(const StringName &p_name) const {
- return variables.has(p_name);
-}
-
-void VisualScript::remove_variable(const StringName &p_name) {
- ERR_FAIL_COND(!variables.has(p_name));
- variables.erase(p_name);
-
-#ifdef TOOLS_ENABLED
- _update_placeholders();
-#endif
-}
-
-void VisualScript::set_variable_default_value(const StringName &p_name, const Variant &p_value) {
- ERR_FAIL_COND(!variables.has(p_name));
-
- variables[p_name].default_value = p_value;
-
-#ifdef TOOLS_ENABLED
- _update_placeholders();
-#endif
-}
-
-Variant VisualScript::get_variable_default_value(const StringName &p_name) const {
- ERR_FAIL_COND_V(!variables.has(p_name), Variant());
- return variables[p_name].default_value;
-}
-
-void VisualScript::set_variable_info(const StringName &p_name, const PropertyInfo &p_info) {
- ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(!variables.has(p_name));
- variables[p_name].info = p_info;
- variables[p_name].info.name = p_name;
-
-#ifdef TOOLS_ENABLED
- _update_placeholders();
-#endif
-}
-
-PropertyInfo VisualScript::get_variable_info(const StringName &p_name) const {
- ERR_FAIL_COND_V(!variables.has(p_name), PropertyInfo());
- return variables[p_name].info;
-}
-
-void VisualScript::set_variable_export(const StringName &p_name, bool p_export) {
- ERR_FAIL_COND(!variables.has(p_name));
-
- variables[p_name]._export = p_export;
-#ifdef TOOLS_ENABLED
- _update_placeholders();
-#endif
-}
-
-bool VisualScript::get_variable_export(const StringName &p_name) const {
- ERR_FAIL_COND_V(!variables.has(p_name), false);
- return variables[p_name]._export;
-}
-
-void VisualScript::_set_variable_info(const StringName &p_name, const Dictionary &p_info) {
- PropertyInfo pinfo;
- if (p_info.has("type")) {
- pinfo.type = Variant::Type(int(p_info["type"]));
- }
- if (p_info.has("name")) {
- pinfo.name = p_info["name"];
- }
- if (p_info.has("hint")) {
- pinfo.hint = PropertyHint(int(p_info["hint"]));
- }
- if (p_info.has("hint_string")) {
- pinfo.hint_string = p_info["hint_string"];
- }
- if (p_info.has("usage")) {
- pinfo.usage = p_info["usage"];
- }
-
- set_variable_info(p_name, pinfo);
-}
-
-Dictionary VisualScript::_get_variable_info(const StringName &p_name) const {
- PropertyInfo pinfo = get_variable_info(p_name);
- Dictionary d;
- d["type"] = pinfo.type;
- d["name"] = pinfo.name;
- d["hint"] = pinfo.hint;
- d["hint_string"] = pinfo.hint_string;
- d["usage"] = pinfo.usage;
-
- return d;
-}
-
-void VisualScript::get_variable_list(List<StringName> *r_variables) const {
- for (const KeyValue<StringName, Variable> &E : variables) {
- r_variables->push_back(E.key);
- }
-}
-
-void VisualScript::set_instance_base_type(const StringName &p_type) {
- ERR_FAIL_COND(instances.size());
- base_type = p_type;
-}
-
-void VisualScript::rename_variable(const StringName &p_name, const StringName &p_new_name) {
- ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(!variables.has(p_name));
- if (p_new_name == p_name) {
- return;
- }
-
- ERR_FAIL_COND(!String(p_new_name).is_valid_identifier());
-
- ERR_FAIL_COND(functions.has(p_new_name));
- ERR_FAIL_COND(variables.has(p_new_name));
- ERR_FAIL_COND(custom_signals.has(p_new_name));
-
- variables[p_new_name] = variables[p_name];
- variables.erase(p_name);
- List<int> ids;
- get_node_list(&ids);
- for (int &E : ids) {
- Ref<VisualScriptVariableGet> nodeget = get_node(E);
- if (nodeget.is_valid()) {
- if (nodeget->get_variable() == p_name) {
- nodeget->set_variable(p_new_name);
- }
- } else {
- Ref<VisualScriptVariableSet> nodeset = get_node(E);
- if (nodeset.is_valid()) {
- if (nodeset->get_variable() == p_name) {
- nodeset->set_variable(p_new_name);
- }
- }
- }
- }
-}
-
-void VisualScript::add_custom_signal(const StringName &p_name) {
- ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(!String(p_name).is_valid_identifier());
- ERR_FAIL_COND(custom_signals.has(p_name));
-
- custom_signals[p_name] = Vector<Argument>();
-}
-
-bool VisualScript::has_custom_signal(const StringName &p_name) const {
- return custom_signals.has(p_name);
-}
-
-void VisualScript::custom_signal_add_argument(const StringName &p_func, Variant::Type p_type, const String &p_name, int p_index) {
- ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(!custom_signals.has(p_func));
- Argument arg;
- arg.type = p_type;
- arg.name = p_name;
- if (p_index < 0) {
- custom_signals[p_func].push_back(arg);
- } else {
- custom_signals[p_func].insert(0, arg);
- }
-}
-
-void VisualScript::custom_signal_set_argument_type(const StringName &p_func, int p_argidx, Variant::Type p_type) {
- ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(!custom_signals.has(p_func));
- ERR_FAIL_INDEX(p_argidx, custom_signals[p_func].size());
- custom_signals[p_func].write[p_argidx].type = p_type;
-}
-
-Variant::Type VisualScript::custom_signal_get_argument_type(const StringName &p_func, int p_argidx) const {
- ERR_FAIL_COND_V(!custom_signals.has(p_func), Variant::NIL);
- ERR_FAIL_INDEX_V(p_argidx, custom_signals[p_func].size(), Variant::NIL);
- return custom_signals[p_func][p_argidx].type;
-}
-
-void VisualScript::custom_signal_set_argument_name(const StringName &p_func, int p_argidx, const String &p_name) {
- ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(!custom_signals.has(p_func));
- ERR_FAIL_INDEX(p_argidx, custom_signals[p_func].size());
- custom_signals[p_func].write[p_argidx].name = p_name;
-}
-
-String VisualScript::custom_signal_get_argument_name(const StringName &p_func, int p_argidx) const {
- ERR_FAIL_COND_V(!custom_signals.has(p_func), String());
- ERR_FAIL_INDEX_V(p_argidx, custom_signals[p_func].size(), String());
- return custom_signals[p_func][p_argidx].name;
-}
-
-void VisualScript::custom_signal_remove_argument(const StringName &p_func, int p_argidx) {
- ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(!custom_signals.has(p_func));
- ERR_FAIL_INDEX(p_argidx, custom_signals[p_func].size());
- custom_signals[p_func].remove_at(p_argidx);
-}
-
-int VisualScript::custom_signal_get_argument_count(const StringName &p_func) const {
- ERR_FAIL_COND_V(!custom_signals.has(p_func), 0);
- return custom_signals[p_func].size();
-}
-
-void VisualScript::custom_signal_swap_argument(const StringName &p_func, int p_argidx, int p_with_argidx) {
- ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(!custom_signals.has(p_func));
- ERR_FAIL_INDEX(p_argidx, custom_signals[p_func].size());
- ERR_FAIL_INDEX(p_with_argidx, custom_signals[p_func].size());
-
- SWAP(custom_signals[p_func].write[p_argidx], custom_signals[p_func].write[p_with_argidx]);
-}
-
-void VisualScript::remove_custom_signal(const StringName &p_name) {
- ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(!custom_signals.has(p_name));
- custom_signals.erase(p_name);
-}
-
-void VisualScript::rename_custom_signal(const StringName &p_name, const StringName &p_new_name) {
- ERR_FAIL_COND(instances.size());
- ERR_FAIL_COND(!custom_signals.has(p_name));
- if (p_new_name == p_name) {
- return;
- }
-
- ERR_FAIL_COND(!String(p_new_name).is_valid_identifier());
-
- ERR_FAIL_COND(functions.has(p_new_name));
- ERR_FAIL_COND(variables.has(p_new_name));
- ERR_FAIL_COND(custom_signals.has(p_new_name));
-
- custom_signals[p_new_name] = custom_signals[p_name];
- custom_signals.erase(p_name);
-}
-
-void VisualScript::get_custom_signal_list(List<StringName> *r_custom_signals) const {
- for (const KeyValue<StringName, Vector<Argument>> &E : custom_signals) {
- r_custom_signals->push_back(E.key);
- }
-
- r_custom_signals->sort_custom<StringName::AlphCompare>();
-}
-
-int VisualScript::get_available_id() const {
- // This is infinitely increasing,
- // so one might want to implement a better solution,
- // if the there is a case for huge number of nodes to be added to visual script.
-
- int max = -1;
- for (const KeyValue<int, NodeData> &E : nodes) {
- if (E.key > max) {
- max = E.key;
- }
- }
- return (max + 1);
-}
-
-/////////////////////////////////
-
-bool VisualScript::can_instantiate() const {
- return true; // ScriptServer::is_scripting_enabled();
-}
-
-StringName VisualScript::get_instance_base_type() const {
- return base_type;
-}
-
-Ref<Script> VisualScript::get_base_script() const {
- return Ref<Script>(); // No inheritance in visual script.
-}
-
-#ifdef TOOLS_ENABLED
-void VisualScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {
- placeholders.erase(p_placeholder);
-}
-
-void VisualScript::_update_placeholders() {
- if (placeholders.size() == 0) {
- return; // No bother if no placeholders.
- }
- List<PropertyInfo> pinfo;
- HashMap<StringName, Variant> values;
-
- for (const KeyValue<StringName, Variable> &E : variables) {
- if (!variables[E.key]._export) {
- continue;
- }
-
- PropertyInfo p = variables[E.key].info;
- p.name = String(E.key);
- pinfo.push_back(p);
- values[p.name] = variables[E.key].default_value;
- }
-
- for (PlaceHolderScriptInstance *E : placeholders) {
- E->update(pinfo, values);
- }
-}
-
-#endif
-
-ScriptInstance *VisualScript::instance_create(Object *p_this) {
-#ifdef TOOLS_ENABLED
-
- if (!ScriptServer::is_scripting_enabled() && !is_tool_script) {
- PlaceHolderScriptInstance *sins = memnew(PlaceHolderScriptInstance(VisualScriptLanguage::singleton, Ref<Script>((Script *)this), p_this));
- placeholders.insert(sins);
-
- List<PropertyInfo> pinfo;
- HashMap<StringName, Variant> values;
-
- for (const KeyValue<StringName, Variable> &E : variables) {
- if (!variables[E.key]._export) {
- continue;
- }
-
- PropertyInfo p = variables[E.key].info;
- p.name = String(E.key);
- pinfo.push_back(p);
- values[p.name] = variables[E.key].default_value;
- }
- sins->update(pinfo, values);
-
- return sins;
- }
-#endif
-
- VisualScriptInstance *instance = memnew(VisualScriptInstance);
- instance->create(Ref<VisualScript>(this), p_this);
-
- {
- MutexLock lock(VisualScriptLanguage::singleton->lock);
-
- instances[p_this] = instance;
- }
-
- return instance;
-}
-
-bool VisualScript::instance_has(const Object *p_this) const {
- return instances.has((Object *)p_this);
-}
-
-bool VisualScript::has_source_code() const {
- return false;
-}
-
-String VisualScript::get_source_code() const {
- return String();
-}
-
-void VisualScript::set_source_code(const String &p_code) {
-}
-
-Error VisualScript::reload(bool p_keep_state) {
- return OK;
-}
-
-bool VisualScript::is_tool() const {
- return is_tool_script;
-}
-
-bool VisualScript::is_valid() const {
- return true; // Always valid.
-}
-
-ScriptLanguage *VisualScript::get_language() const {
- return VisualScriptLanguage::singleton;
-}
-
-bool VisualScript::has_script_signal(const StringName &p_signal) const {
- return custom_signals.has(p_signal);
-}
-
-void VisualScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
- for (const KeyValue<StringName, Vector<Argument>> &E : custom_signals) {
- MethodInfo mi;
- mi.name = E.key;
- for (int i = 0; i < E.value.size(); i++) {
- PropertyInfo arg;
- arg.type = E.value[i].type;
- arg.name = E.value[i].name;
- mi.arguments.push_back(arg);
- }
-
- r_signals->push_back(mi);
- }
-}
-
-bool VisualScript::get_property_default_value(const StringName &p_property, Variant &r_value) const {
- if (!variables.has(p_property)) {
- return false;
- }
-
- r_value = variables[p_property].default_value;
- return true;
-}
-
-void VisualScript::get_script_method_list(List<MethodInfo> *p_list) const {
- for (const KeyValue<StringName, Function> &E : functions) {
- MethodInfo mi;
- mi.name = E.key;
- if (functions[E.key].func_id >= 0) {
- Ref<VisualScriptFunction> func = nodes[functions[E.key].func_id].node;
- if (func.is_valid()) {
- for (int i = 0; i < func->get_argument_count(); i++) {
- PropertyInfo arg;
- arg.name = func->get_argument_name(i);
- arg.type = func->get_argument_type(i);
- mi.arguments.push_back(arg);
- }
-
- p_list->push_back(mi);
- }
- }
- }
-}
-
-bool VisualScript::has_method(const StringName &p_method) const {
- return functions.has(p_method);
-}
-
-MethodInfo VisualScript::get_method_info(const StringName &p_method) const {
- const Function funct = functions[p_method];
- if (funct.func_id == -1) {
- return MethodInfo();
- }
-
- MethodInfo mi;
- mi.name = p_method;
- if (funct.func_id >= 0) {
- Ref<VisualScriptFunction> func = nodes[funct.func_id].node;
- if (func.is_valid()) {
- for (int i = 0; i < func->get_argument_count(); i++) {
- PropertyInfo arg;
- arg.name = func->get_argument_name(i);
- arg.type = func->get_argument_type(i);
- mi.arguments.push_back(arg);
- }
-
- if (!func->is_sequenced()) {
- mi.flags |= METHOD_FLAG_CONST;
- }
- }
- }
-
- return mi;
-}
-
-void VisualScript::get_script_property_list(List<PropertyInfo> *p_list) const {
- List<StringName> vars;
- get_variable_list(&vars);
-
- for (const StringName &E : vars) {
- if (!variables[E]._export) {
- continue;
- }
- PropertyInfo pi = variables[E].info;
- pi.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
- p_list->push_back(pi);
- }
-}
-
-int VisualScript::get_member_line(const StringName &p_member) const {
- return functions[p_member].func_id; // will be -1 if not found
-}
-
-#ifdef TOOLS_ENABLED
-bool VisualScript::are_subnodes_edited() const {
- for (const KeyValue<int, NodeData> &F : nodes) {
- if (F.value.node->is_edited()) {
- return true;
- }
- }
- return false;
-}
-#endif
-
-const Variant VisualScript::get_rpc_config() const {
- return rpc_functions;
-}
-
-void VisualScript::_set_data(const Dictionary &p_data) {
- Dictionary d = p_data;
- if (d.has("base_type")) {
- base_type = d["base_type"];
- }
-
- variables.clear();
- Array vars = d["variables"];
- for (int i = 0; i < vars.size(); i++) {
- Dictionary v = vars[i];
- StringName name = v["name"];
- add_variable(name);
- _set_variable_info(name, v);
- set_variable_default_value(name, v["default_value"]);
- set_variable_export(name, v.has("export") && bool(v["export"]));
- }
-
- custom_signals.clear();
- Array sigs = d["signals"];
- for (int i = 0; i < sigs.size(); i++) {
- Dictionary cs = sigs[i];
- add_custom_signal(cs["name"]);
-
- Array args = cs["arguments"];
- for (int j = 0; j < args.size(); j += 2) {
- custom_signal_add_argument(cs["name"], Variant::Type(int(args[j + 1])), args[j]);
- }
- }
-
- Array funcs = d["functions"];
- functions.clear();
-
- for (int i = 0; i < funcs.size(); i++) {
- Dictionary func = funcs[i];
- add_function(func["name"], func["function_id"]);
- }
- {
- Array nodes = d["nodes"];
- for (int i = 0; i < nodes.size(); i += 3) {
- add_node(nodes[i], nodes[i + 2], nodes[i + 1]);
- }
-
- Array sequence_connections = d["sequence_connections"];
- for (int j = 0; j < sequence_connections.size(); j += 3) {
- sequence_connect(sequence_connections[j + 0], sequence_connections[j + 1], sequence_connections[j + 2]);
- }
-
- Array data_connections = d["data_connections"];
- for (int j = 0; j < data_connections.size(); j += 4) {
- data_connect(data_connections[j + 0], data_connections[j + 1], data_connections[j + 2], data_connections[j + 3]);
- }
- }
- is_tool_script = d["is_tool_script"];
- scroll = d["scroll"];
-
- // Takes all the rpc methods.
- rpc_functions.clear();
- for (const KeyValue<StringName, Function> &E : functions) {
- if (E.value.func_id >= 0 && nodes.has(E.value.func_id)) {
- Ref<VisualScriptFunction> vsf = nodes[E.value.func_id].node;
- if (!vsf.is_valid() || vsf->get_rpc_mode() == MultiplayerAPI::RPC_MODE_DISABLED) {
- continue;
- }
- Dictionary nd;
- nd["rpc_mode"] = vsf->get_rpc_mode();
- nd["transfer_mode"] = MultiplayerPeer::TRANSFER_MODE_RELIABLE; // TODO
- nd["call_local"] = false; // TODO
- rpc_functions[E.key] = nd;
- }
- }
-}
-
-Dictionary VisualScript::_get_data() const {
- Dictionary d;
- d["base_type"] = base_type;
-
- Array vars;
- for (const KeyValue<StringName, Variable> &E : variables) {
- Dictionary var = _get_variable_info(E.key);
- var["name"] = E.key; // Make sure it's the right one.
- var["default_value"] = E.value.default_value;
- var["export"] = E.value._export;
- vars.push_back(var);
- }
- d["variables"] = vars;
-
- Array sigs;
- for (const KeyValue<StringName, Vector<Argument>> &E : custom_signals) {
- Dictionary cs;
- cs["name"] = E.key;
- Array args;
- for (int i = 0; i < E.value.size(); i++) {
- args.push_back(E.value[i].name);
- args.push_back(E.value[i].type);
- }
- cs["arguments"] = args;
-
- sigs.push_back(cs);
- }
-
- d["signals"] = sigs;
-
- Array funcs;
- for (const KeyValue<StringName, Function> &E : functions) {
- Dictionary func;
- func["name"] = E.key;
- func["function_id"] = E.value.func_id;
- funcs.push_back(func);
- }
- d["functions"] = funcs;
-
- Array nds;
- for (const KeyValue<int, NodeData> &F : nodes) {
- nds.push_back(F.key);
- nds.push_back(F.value.pos);
- nds.push_back(F.value.node);
- }
- d["nodes"] = nds;
-
- Array seqconns;
- for (const SequenceConnection &F : sequence_connections) {
- seqconns.push_back(F.from_node);
- seqconns.push_back(F.from_output);
- seqconns.push_back(F.to_node);
- }
- d["sequence_connections"] = seqconns;
-
- Array dataconns;
- for (const DataConnection &F : data_connections) {
- dataconns.push_back(F.from_node);
- dataconns.push_back(F.from_port);
- dataconns.push_back(F.to_node);
- dataconns.push_back(F.to_port);
- }
- d["data_connections"] = dataconns;
-
- d["is_tool_script"] = is_tool_script;
- d["scroll"] = scroll;
-
- return d;
-}
-
-void VisualScript::_bind_methods() {
- ClassDB::bind_method(D_METHOD("add_function", "name", "func_node_id"), &VisualScript::add_function);
- ClassDB::bind_method(D_METHOD("has_function", "name"), &VisualScript::has_function);
- ClassDB::bind_method(D_METHOD("remove_function", "name"), &VisualScript::remove_function);
- ClassDB::bind_method(D_METHOD("rename_function", "name", "new_name"), &VisualScript::rename_function);
- ClassDB::bind_method(D_METHOD("set_scroll", "offset"), &VisualScript::set_scroll);
- ClassDB::bind_method(D_METHOD("get_scroll"), &VisualScript::get_scroll);
-
- ClassDB::bind_method(D_METHOD("add_node", "id", "node", "position"), &VisualScript::add_node, DEFVAL(Point2()));
- ClassDB::bind_method(D_METHOD("remove_node", "id"), &VisualScript::remove_node);
- ClassDB::bind_method(D_METHOD("get_function_node_id", "name"), &VisualScript::get_function_node_id);
-
- ClassDB::bind_method(D_METHOD("get_node", "id"), &VisualScript::get_node);
- ClassDB::bind_method(D_METHOD("has_node", "id"), &VisualScript::has_node);
- ClassDB::bind_method(D_METHOD("set_node_position", "id", "position"), &VisualScript::set_node_position);
- ClassDB::bind_method(D_METHOD("get_node_position", "id"), &VisualScript::get_node_position);
-
- ClassDB::bind_method(D_METHOD("sequence_connect", "from_node", "from_output", "to_node"), &VisualScript::sequence_connect);
- ClassDB::bind_method(D_METHOD("sequence_disconnect", "from_node", "from_output", "to_node"), &VisualScript::sequence_disconnect);
- ClassDB::bind_method(D_METHOD("has_sequence_connection", "from_node", "from_output", "to_node"), &VisualScript::has_sequence_connection);
-
- ClassDB::bind_method(D_METHOD("data_connect", "from_node", "from_port", "to_node", "to_port"), &VisualScript::data_connect);
- ClassDB::bind_method(D_METHOD("data_disconnect", "from_node", "from_port", "to_node", "to_port"), &VisualScript::data_disconnect);
- ClassDB::bind_method(D_METHOD("has_data_connection", "from_node", "from_port", "to_node", "to_port"), &VisualScript::has_data_connection);
-
- ClassDB::bind_method(D_METHOD("add_variable", "name", "default_value", "export"), &VisualScript::add_variable, DEFVAL(Variant()), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("has_variable", "name"), &VisualScript::has_variable);
- ClassDB::bind_method(D_METHOD("remove_variable", "name"), &VisualScript::remove_variable);
- ClassDB::bind_method(D_METHOD("set_variable_default_value", "name", "value"), &VisualScript::set_variable_default_value);
- ClassDB::bind_method(D_METHOD("get_variable_default_value", "name"), &VisualScript::get_variable_default_value);
- ClassDB::bind_method(D_METHOD("set_variable_info", "name", "value"), &VisualScript::_set_variable_info);
- ClassDB::bind_method(D_METHOD("get_variable_info", "name"), &VisualScript::_get_variable_info);
- ClassDB::bind_method(D_METHOD("set_variable_export", "name", "enable"), &VisualScript::set_variable_export);
- ClassDB::bind_method(D_METHOD("get_variable_export", "name"), &VisualScript::get_variable_export);
- ClassDB::bind_method(D_METHOD("rename_variable", "name", "new_name"), &VisualScript::rename_variable);
-
- ClassDB::bind_method(D_METHOD("add_custom_signal", "name"), &VisualScript::add_custom_signal);
- ClassDB::bind_method(D_METHOD("has_custom_signal", "name"), &VisualScript::has_custom_signal);
- ClassDB::bind_method(D_METHOD("custom_signal_add_argument", "name", "type", "argname", "index"), &VisualScript::custom_signal_add_argument, DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("custom_signal_set_argument_type", "name", "argidx", "type"), &VisualScript::custom_signal_set_argument_type);
- ClassDB::bind_method(D_METHOD("custom_signal_get_argument_type", "name", "argidx"), &VisualScript::custom_signal_get_argument_type);
- ClassDB::bind_method(D_METHOD("custom_signal_set_argument_name", "name", "argidx", "argname"), &VisualScript::custom_signal_set_argument_name);
- ClassDB::bind_method(D_METHOD("custom_signal_get_argument_name", "name", "argidx"), &VisualScript::custom_signal_get_argument_name);
- ClassDB::bind_method(D_METHOD("custom_signal_remove_argument", "name", "argidx"), &VisualScript::custom_signal_remove_argument);
- ClassDB::bind_method(D_METHOD("custom_signal_get_argument_count", "name"), &VisualScript::custom_signal_get_argument_count);
- ClassDB::bind_method(D_METHOD("custom_signal_swap_argument", "name", "argidx", "withidx"), &VisualScript::custom_signal_swap_argument);
- ClassDB::bind_method(D_METHOD("remove_custom_signal", "name"), &VisualScript::remove_custom_signal);
- ClassDB::bind_method(D_METHOD("rename_custom_signal", "name", "new_name"), &VisualScript::rename_custom_signal);
-
- ClassDB::bind_method(D_METHOD("set_instance_base_type", "type"), &VisualScript::set_instance_base_type);
-
- ClassDB::bind_method(D_METHOD("_set_data", "data"), &VisualScript::_set_data);
- ClassDB::bind_method(D_METHOD("_get_data"), &VisualScript::_get_data);
-
- ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
-
- ADD_SIGNAL(MethodInfo("node_ports_changed", PropertyInfo(Variant::INT, "id")));
-}
-
-VisualScript::VisualScript() {
- base_type = "Object";
- is_tool_script = false;
-}
-
-bool VisualScript::inherits_script(const Ref<Script> &p_script) const {
- return this == p_script.ptr(); // There is no inheritance in visual scripts, so this is enough.
-}
-
-RBSet<int> VisualScript::get_output_sequence_ports_connected(int from_node) {
- List<VisualScript::SequenceConnection> *sc = memnew(List<VisualScript::SequenceConnection>);
- get_sequence_connection_list(sc);
- RBSet<int> connected;
- for (List<VisualScript::SequenceConnection>::Element *E = sc->front(); E; E = E->next()) {
- if (E->get().from_node == from_node) {
- connected.insert(E->get().from_output);
- }
- }
- memdelete(sc);
- return connected;
-}
-
-VisualScript::~VisualScript() {
- // Remove all nodes and stuff that hold data refs.
- for (const KeyValue<int, NodeData> &E : nodes) {
- remove_node(E.key);
- }
-}
-
-////////////////////////////////////////////
-
-bool VisualScriptInstance::set(const StringName &p_name, const Variant &p_value) {
- HashMap<StringName, Variant>::Iterator E = variables.find(p_name);
- if (!E) {
- return false;
- }
-
- E->value = p_value;
-
- return true;
-}
-
-bool VisualScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
- HashMap<StringName, Variant>::ConstIterator E = variables.find(p_name);
- if (!E) {
- return false;
- }
-
- r_ret = E->value;
- return true;
-}
-
-void VisualScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const {
- for (const KeyValue<StringName, VisualScript::Variable> &E : script->variables) {
- if (!E.value._export) {
- continue;
- }
- PropertyInfo p = E.value.info;
- p.name = String(E.key);
- p.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
- p_properties->push_back(p);
- }
-}
-
-Variant::Type VisualScriptInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const {
- if (!script->variables.has(p_name)) {
- if (r_is_valid) {
- *r_is_valid = false;
- }
- ERR_FAIL_V(Variant::NIL);
- }
-
- if (r_is_valid) {
- *r_is_valid = true;
- }
-
- return script->variables[p_name].info.type;
-}
-
-void VisualScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
- for (const KeyValue<StringName, VisualScript::Function> &E : script->functions) {
- MethodInfo mi;
- mi.name = E.key;
- if (E.value.func_id >= 0 && script->nodes.has(E.value.func_id)) {
- Ref<VisualScriptFunction> vsf = script->nodes[E.value.func_id].node;
- if (vsf.is_valid()) {
- for (int i = 0; i < vsf->get_argument_count(); i++) {
- PropertyInfo arg;
- arg.name = vsf->get_argument_name(i);
- arg.type = vsf->get_argument_type(i);
-
- mi.arguments.push_back(arg);
- }
-
- if (!vsf->is_sequenced()) { // Assumed constant if not sequenced.
- mi.flags |= METHOD_FLAG_CONST;
- }
- }
- }
- p_list->push_back(mi);
- }
-}
-
-bool VisualScriptInstance::has_method(const StringName &p_method) const {
- return script->functions.has(p_method);
-}
-
-//#define VSDEBUG(m_text) print_line(m_text)
-#define VSDEBUG(m_text)
-
-void VisualScriptInstance::_dependency_step(VisualScriptNodeInstance *node, int p_pass, int *pass_stack, const Variant **input_args, Variant **output_args, Variant *variant_stack, Callable::CallError &r_error, String &error_str, VisualScriptNodeInstance **r_error_node) {
- ERR_FAIL_COND(node->pass_idx == -1);
-
- if (pass_stack[node->pass_idx] == p_pass) {
- return;
- }
-
- pass_stack[node->pass_idx] = p_pass;
-
- if (!node->dependencies.is_empty()) {
- int dc = node->dependencies.size();
- VisualScriptNodeInstance **deps = node->dependencies.ptrw();
-
- for (int i = 0; i < dc; i++) {
- _dependency_step(deps[i], p_pass, pass_stack, input_args, output_args, variant_stack, r_error, error_str, r_error_node);
- if (r_error.error != Callable::CallError::CALL_OK) {
- return;
- }
- }
- }
-
- for (int i = 0; i < node->input_port_count; i++) {
- int index = node->input_ports[i] & VisualScriptNodeInstance::INPUT_MASK;
-
- if (node->input_ports[i] & VisualScriptNodeInstance::INPUT_DEFAULT_VALUE_BIT) {
- // Is a default value (unassigned input port).
- input_args[i] = &default_values[index];
- } else {
- // Regular temporary in stack.
- input_args[i] = &variant_stack[index];
- }
- }
- for (int i = 0; i < node->output_port_count; i++) {
- output_args[i] = &variant_stack[node->output_ports[i]];
- }
-
- Variant *working_mem = node->working_mem_idx >= 0 ? &variant_stack[node->working_mem_idx] : (Variant *)nullptr;
-
- node->step(input_args, output_args, VisualScriptNodeInstance::START_MODE_BEGIN_SEQUENCE, working_mem, r_error, error_str);
- // Ignore return.
- if (r_error.error != Callable::CallError::CALL_OK) {
- *r_error_node = node;
- }
-}
-
-Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p_stack, int p_stack_size, VisualScriptNodeInstance *p_node, int p_flow_stack_pos, int p_pass, bool p_resuming_yield, Callable::CallError &r_error) {
- HashMap<StringName, Function>::Iterator F = functions.find(p_method);
- ERR_FAIL_COND_V(!F, Variant());
- Function *f = &F->value;
-
- // This call goes separate, so it can be yielded and suspended.
- Variant *variant_stack = (Variant *)p_stack;
- bool *sequence_bits = (bool *)(variant_stack + f->max_stack);
- const Variant **input_args = (const Variant **)(sequence_bits + f->node_count);
- Variant **output_args = (Variant **)(input_args + max_input_args);
- int flow_max = f->flow_stack_size;
- int *flow_stack = flow_max ? (int *)(output_args + max_output_args) : (int *)nullptr;
- int *pass_stack = flow_stack ? (int *)(flow_stack + flow_max) : (int *)nullptr;
-
- String error_str;
-
- VisualScriptNodeInstance *node = p_node;
- bool error = false;
- int current_node_id = f->node;
- Variant return_value;
- Variant *working_mem = nullptr;
-
- int flow_stack_pos = p_flow_stack_pos;
-
-#ifdef DEBUG_ENABLED
- if (EngineDebugger::is_active()) {
- VisualScriptLanguage::singleton->enter_function(this, &p_method, variant_stack, &working_mem, &current_node_id);
- }
-#endif
-
- while (true) {
- p_pass++; // Increment pass.
- current_node_id = node->get_id();
-
- VSDEBUG("==========AT NODE: " + itos(current_node_id) + " base: " + node->get_base_node()->get_class_name());
- VSDEBUG("AT STACK POS: " + itos(flow_stack_pos));
-
- // Setup working mem.
- working_mem = node->working_mem_idx >= 0 ? &variant_stack[node->working_mem_idx] : (Variant *)nullptr;
-
- VSDEBUG("WORKING MEM: " + itos(node->working_mem_idx));
-
- if (current_node_id == f->node) {
- // If function node, set up function arguments from beginning of stack.
-
- for (int i = 0; i < f->argument_count; i++) {
- input_args[i] = &variant_stack[i];
- }
- } else {
- // Run dependencies first.
-
- if (!node->dependencies.is_empty()) {
- int dc = node->dependencies.size();
- VisualScriptNodeInstance **deps = node->dependencies.ptrw();
-
- for (int i = 0; i < dc; i++) {
- _dependency_step(deps[i], p_pass, pass_stack, input_args, output_args, variant_stack, r_error, error_str, &node);
- if (r_error.error != Callable::CallError::CALL_OK) {
- error = true;
- current_node_id = node->id;
- break;
- }
- }
- }
-
- if (!error) {
- // Setup input pointers normally.
- VSDEBUG("INPUT PORTS: " + itos(node->input_port_count));
-
- for (int i = 0; i < node->input_port_count; i++) {
- int index = node->input_ports[i] & VisualScriptNodeInstance::INPUT_MASK;
-
- if (node->input_ports[i] & VisualScriptNodeInstance::INPUT_DEFAULT_VALUE_BIT) {
- // Is a default value (unassigned input port).
- input_args[i] = &default_values[index];
- VSDEBUG("\tPORT " + itos(i) + " DEFAULT VAL");
- } else {
- // Regular temporary in stack.
- input_args[i] = &variant_stack[index];
- VSDEBUG("PORT " + itos(i) + " AT STACK " + itos(index));
- }
- }
- }
- }
-
- if (error) {
- break;
- }
-
- // Setup output pointers.
-
- VSDEBUG("OUTPUT PORTS: " + itos(node->output_port_count));
- for (int i = 0; i < node->output_port_count; i++) {
- output_args[i] = &variant_stack[node->output_ports[i]];
- VSDEBUG("PORT " + itos(i) + " AT STACK " + itos(node->output_ports[i]));
- }
-
- // Do step.
-
- VisualScriptNodeInstance::StartMode start_mode;
- {
- if (p_resuming_yield) {
- start_mode = VisualScriptNodeInstance::START_MODE_RESUME_YIELD;
- p_resuming_yield = false; // Should resume only the first time.
- } else if (flow_stack && (flow_stack[flow_stack_pos] & VisualScriptNodeInstance::FLOW_STACK_PUSHED_BIT)) {
- // If there is a push bit, it means we are continuing a sequence.
- start_mode = VisualScriptNodeInstance::START_MODE_CONTINUE_SEQUENCE;
- } else {
- start_mode = VisualScriptNodeInstance::START_MODE_BEGIN_SEQUENCE;
- }
- }
-
- VSDEBUG("STEP - STARTSEQ: " + itos(start_mode));
-
- int ret = node->step(input_args, output_args, start_mode, working_mem, r_error, error_str);
-
- if (r_error.error != Callable::CallError::CALL_OK) {
- // Use error from step.
- error = true;
- break;
- }
-
- if (ret & VisualScriptNodeInstance::STEP_YIELD_BIT) {
- // Yielded!
- if (node->get_working_memory_size() == 0) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- error_str = RTR("A node yielded without working memory, please read the docs on how to yield properly!");
- error = true;
- break;
-
- } else {
- Ref<VisualScriptFunctionState> state = *working_mem;
- if (!state.is_valid()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- error_str = RTR("Node yielded, but did not return a function state in the first working memory.");
- error = true;
- break;
- }
-
- // Step 1, capture all state.
- state->instance_id = get_owner_ptr()->get_instance_id();
- state->script_id = get_script()->get_instance_id();
- state->instance = this;
- state->function = p_method;
- state->working_mem_index = node->working_mem_idx;
- state->variant_stack_size = f->max_stack;
- state->node = node;
- state->flow_stack_pos = flow_stack_pos;
- state->stack.resize(p_stack_size);
- state->pass = p_pass;
- memcpy(state->stack.ptrw(), p_stack, p_stack_size);
- // Step 2, run away, return directly.
- r_error.error = Callable::CallError::CALL_OK;
-
-#ifdef DEBUG_ENABLED
- // Will re-enter later, so exiting.
- if (EngineDebugger::is_active()) {
- VisualScriptLanguage::singleton->exit_function();
- }
-#endif
-
- return state;
- }
- }
-
-#ifdef DEBUG_ENABLED
- if (EngineDebugger::is_active()) {
- // line
- bool do_break = false;
-
- if (EngineDebugger::get_script_debugger()->get_lines_left() > 0) {
- if (EngineDebugger::get_script_debugger()->get_depth() <= 0) {
- EngineDebugger::get_script_debugger()->set_lines_left(EngineDebugger::get_script_debugger()->get_lines_left() - 1);
- }
- if (EngineDebugger::get_script_debugger()->get_lines_left() <= 0) {
- do_break = true;
- }
- }
-
- if (EngineDebugger::get_script_debugger()->is_breakpoint(current_node_id, source)) {
- do_break = true;
- }
-
- if (do_break) {
- VisualScriptLanguage::singleton->debug_break("Breakpoint", true);
- }
-
- EngineDebugger::get_singleton()->line_poll();
- }
-#endif
- int output = ret & VisualScriptNodeInstance::STEP_MASK;
-
- VSDEBUG("STEP RETURN: " + itos(ret));
-
- if (ret & VisualScriptNodeInstance::STEP_EXIT_FUNCTION_BIT) {
- if (node->get_working_memory_size() == 0) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- error_str = RTR("Return value must be assigned to first element of node working memory! Fix your node please.");
- error = true;
- } else {
- // Assign from working memory, first element.
- return_value = *working_mem;
- }
-
- VSDEBUG("EXITING FUNCTION - VALUE " + String(return_value));
- break; // Exit function requested, bye
- }
-
- VisualScriptNodeInstance *next = nullptr; // Next node.
-
- if ((ret == output || ret & VisualScriptNodeInstance::STEP_FLAG_PUSH_STACK_BIT) && node->sequence_output_count) {
- // If no exit bit was set, and has sequence outputs, guess next node.
- if (output >= node->sequence_output_count) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- error_str = RTR("Node returned an invalid sequence output:") + " " + itos(output);
- error = true;
- break;
- }
-
- next = node->sequence_outputs[output];
- VSDEBUG("GOT NEXT NODE - " + (next ? itos(next->get_id()) : "Null"));
- }
-
- if (flow_stack) {
- // Update flow stack pos (may have changed).
- flow_stack[flow_stack_pos] = current_node_id;
-
- // Add stack push bit if requested.
- if (ret & VisualScriptNodeInstance::STEP_FLAG_PUSH_STACK_BIT) {
- flow_stack[flow_stack_pos] |= VisualScriptNodeInstance::FLOW_STACK_PUSHED_BIT;
- sequence_bits[node->sequence_index] = true; // Remember sequence bit.
- VSDEBUG("NEXT SEQ - FLAG BIT");
- } else {
- sequence_bits[node->sequence_index] = false; // Forget sequence bit.
- VSDEBUG("NEXT SEQ - NORMAL");
- }
-
- if (ret & VisualScriptNodeInstance::STEP_FLAG_GO_BACK_BIT) {
- // Go back request.
-
- if (flow_stack_pos > 0) {
- flow_stack_pos--;
- node = instances[flow_stack[flow_stack_pos] & VisualScriptNodeInstance::FLOW_STACK_MASK];
- VSDEBUG("NEXT IS GO BACK");
- } else {
- VSDEBUG("NEXT IS GO BACK, BUT NO NEXT SO EXIT");
- break; // Simply exit without value or error.
- }
- } else if (next) {
- if (sequence_bits[next->sequence_index]) {
- // What happened here is that we are entering a node that is in the middle of doing a sequence (pushed stack) from the front
- // because each node has a working memory, we can't really do a sub-sequence
- // as a result, the sequence will be restarted and the stack will roll back to find where this node
- // started the sequence.
-
- bool found = false;
-
- for (int i = flow_stack_pos; i >= 0; i--) {
- if ((flow_stack[i] & VisualScriptNodeInstance::FLOW_STACK_MASK) == next->get_id()) {
- flow_stack_pos = i; // Roll back and remove bit.
- flow_stack[i] = next->get_id();
- sequence_bits[next->sequence_index] = false;
- found = true;
- }
- }
-
- if (!found) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- error_str = RTR("Found sequence bit but not the node in the stack (please report).");
- error = true;
- break;
- }
-
- node = next;
- VSDEBUG("RE-ENTERED A LOOP, RETURNED STACK POS TO - " + itos(flow_stack_pos));
-
- } else {
- // Check for stack overflow.
- if (flow_stack_pos + 1 >= flow_max) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- error_str = vformat(RTR("Stack overflow (stack size: %s). Check for infinite recursion in your script."), output);
- error = true;
- break;
- }
-
- node = next;
-
- flow_stack_pos++;
- flow_stack[flow_stack_pos] = node->get_id();
-
- VSDEBUG("INCREASE FLOW STACK");
- }
-
- } else {
- // No next node, try to go back in stack to pushed bit.
-
- bool found = false;
-
- for (int i = flow_stack_pos; i >= 0; i--) {
- VSDEBUG("FS " + itos(i) + " - " + itos(flow_stack[i]));
- if (flow_stack[i] & VisualScriptNodeInstance::FLOW_STACK_PUSHED_BIT) {
- node = instances[flow_stack[i] & VisualScriptNodeInstance::FLOW_STACK_MASK];
- flow_stack_pos = i;
- found = true;
- break;
- }
- }
-
- if (!found) {
- VSDEBUG("NO NEXT NODE, NO GO BACK, EXITING");
- break; // Done, couldn't find a push stack bit.
- }
-
- VSDEBUG("NO NEXT NODE, GO BACK TO: " + itos(flow_stack_pos));
- }
- } else {
- node = next; // Stackless mode, simply assign next node.
- }
- }
-
- if (error) {
- // Error
- // Function, file, line, error, explanation.
- String err_file = script->get_path();
- String err_func = p_method;
- int err_line = current_node_id; // Not a line but it works as one.
-
- if (node && (r_error.error != Callable::CallError::CALL_ERROR_INVALID_METHOD || error_str.is_empty())) {
- if (!error_str.is_empty()) {
- error_str += " ";
- }
-
- if (r_error.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
- int errorarg = r_error.argument;
- error_str += "Cannot convert argument " + itos(errorarg + 1) + " to " + Variant::get_type_name(Variant::Type(r_error.expected)) + ".";
- } else if (r_error.error == Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {
- error_str += "Expected " + itos(r_error.argument) + " arguments.";
- } else if (r_error.error == Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
- error_str += "Expected " + itos(r_error.argument) + " arguments.";
- } else if (r_error.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
- error_str += "Invalid Call.";
- } else if (r_error.error == Callable::CallError::CALL_ERROR_METHOD_NOT_CONST) {
- error_str += "Method not const in a const instance.";
- } else if (r_error.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
- error_str += "Base Instance is null";
- }
- }
-
- //if (!GDScriptLanguage::get_singleton()->debug_break(err_text,false)) {
- // debugger break did not happen
-
- if (!VisualScriptLanguage::singleton->debug_break(error_str, false)) {
- _err_print_error(err_func.utf8().get_data(), err_file.utf8().get_data(), err_line, error_str.utf8().get_data(), false, ERR_HANDLER_SCRIPT);
- }
-
- //}
- } else {
- //return_value=
- }
-
-#ifdef DEBUG_ENABLED
- if (EngineDebugger::is_active()) {
- VisualScriptLanguage::singleton->exit_function();
- }
-#endif
-
- // Clean up variant stack.
- for (int i = 0; i < f->max_stack; i++) {
- variant_stack[i].~Variant();
- }
-
- return return_value;
-}
-
-Variant VisualScriptInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- r_error.error = Callable::CallError::CALL_OK; //ok by default
-
- HashMap<StringName, Function>::Iterator F = functions.find(p_method);
- if (!F) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return Variant();
- }
-
- VSDEBUG("CALLING: " + String(p_method));
-
- Function *f = &F->value;
-
- int total_stack_size = 0;
-
- total_stack_size += f->max_stack * sizeof(Variant); //variants
- total_stack_size += f->node_count * sizeof(bool);
- total_stack_size += (max_input_args + max_output_args) * sizeof(Variant *); //arguments
- total_stack_size += f->flow_stack_size * sizeof(int); //flow
- total_stack_size += f->pass_stack_size * sizeof(int);
-
- VSDEBUG("STACK SIZE: " + itos(total_stack_size));
- VSDEBUG("STACK VARIANTS: : " + itos(f->max_stack));
- VSDEBUG("SEQBITS: : " + itos(f->node_count));
- VSDEBUG("MAX INPUT: " + itos(max_input_args));
- VSDEBUG("MAX OUTPUT: " + itos(max_output_args));
- VSDEBUG("FLOW STACK SIZE: " + itos(f->flow_stack_size));
- VSDEBUG("PASS STACK SIZE: " + itos(f->pass_stack_size));
-
- void *stack = alloca(total_stack_size);
-
- Variant *variant_stack = (Variant *)stack;
- bool *sequence_bits = (bool *)(variant_stack + f->max_stack);
- const Variant **input_args = (const Variant **)(sequence_bits + f->node_count);
- Variant **output_args = (Variant **)(input_args + max_input_args);
- int flow_max = f->flow_stack_size;
- int *flow_stack = flow_max ? (int *)(output_args + max_output_args) : (int *)nullptr;
- int *pass_stack = flow_stack ? (int *)(flow_stack + flow_max) : (int *)nullptr;
-
- for (int i = 0; i < f->node_count; i++) {
- sequence_bits[i] = false; // All starts as false.
- }
-
- memset(pass_stack, 0, f->pass_stack_size * sizeof(int));
-
- HashMap<int, VisualScriptNodeInstance *>::Iterator E = instances.find(f->node);
- if (!E) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
-
- ERR_FAIL_V_MSG(Variant(), "No VisualScriptFunction node in function.");
- }
-
- VisualScriptNodeInstance *node = E->value;
-
- if (flow_stack) {
- flow_stack[0] = node->get_id();
- }
-
- VSDEBUG("ARGUMENTS: " + itos(f->argument_count) = " RECEIVED: " + itos(p_argcount));
-
- if (p_argcount < f->argument_count) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = node->get_input_port_count();
-
- return Variant();
- }
-
- if (p_argcount > f->argument_count) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_error.argument = node->get_input_port_count();
-
- return Variant();
- }
-
- // Allocate variant stack.
- for (int i = 0; i < f->max_stack; i++) {
- memnew_placement(&variant_stack[i], Variant);
- }
-
- // Allocate function arguments (must be copied for yield to work properly).
- for (int i = 0; i < p_argcount; i++) {
- variant_stack[i] = *p_args[i];
- }
-
- return _call_internal(p_method, stack, total_stack_size, node, 0, 0, false, r_error);
-}
-
-void VisualScriptInstance::notification(int p_notification) {
- // Do nothing as this is called using virtual.
-
- Variant what = p_notification;
- const Variant *whatp = &what;
- Callable::CallError ce;
- callp(VisualScriptLanguage::singleton->notification, &whatp, 1, ce); // Do as call.
-}
-
-String VisualScriptInstance::to_string(bool *r_valid) {
- if (has_method(CoreStringNames::get_singleton()->_to_string)) {
- Callable::CallError ce;
- Variant ret = callp(CoreStringNames::get_singleton()->_to_string, nullptr, 0, ce);
- if (ce.error == Callable::CallError::CALL_OK) {
- if (ret.get_type() != Variant::STRING) {
- if (r_valid) {
- *r_valid = false;
- }
- ERR_FAIL_V_MSG(String(), "Wrong type for " + CoreStringNames::get_singleton()->_to_string + ", must be a String.");
- }
- if (r_valid) {
- *r_valid = true;
- }
- return ret.operator String();
- }
- }
- if (r_valid) {
- *r_valid = false;
- }
- return String();
-}
-
-Ref<Script> VisualScriptInstance::get_script() const {
- return script;
-}
-
-const Variant VisualScriptInstance::get_rpc_config() const {
- return script->get_rpc_config();
-}
-
-void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_owner) {
- script = p_script;
- owner = p_owner;
- source = p_script->get_path();
-
- max_input_args = 0;
- max_output_args = 0;
-
- // Setup variables.
- {
- for (const KeyValue<StringName, VisualScript::Variable> &E : script->variables) {
- variables[E.key] = E.value.default_value;
- }
- }
-
- // Setup functions from sequence trees.
- {
- for (const KeyValue<StringName, VisualScript::Function> &E : script->functions) {
- const VisualScript::Function &vsfn = E.value;
- Function function;
- function.node = vsfn.func_id;
- function.max_stack = 0;
- function.flow_stack_size = 0;
- function.pass_stack_size = 0;
- function.node_count = 0;
-
- HashMap<StringName, int> local_var_indices;
-
- if (function.node < 0) {
- VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No start node in function: " + String(E.key));
- ERR_CONTINUE(function.node < 0);
- }
-
- {
- Ref<VisualScriptFunction> func_node = script->get_node(vsfn.func_id);
-
- if (func_node.is_null()) {
- VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No VisualScriptFunction typed start node in function: " + String(E.key));
- }
-
- ERR_CONTINUE(!func_node.is_valid());
-
- function.argument_count = func_node->get_argument_count();
- function.max_stack += function.argument_count;
- function.flow_stack_size = func_node->is_stack_less() ? 0 : func_node->get_stack_size();
- max_input_args = MAX(max_input_args, function.argument_count);
- }
- // Function nodes graphs.
- RBSet<VisualScript::SequenceConnection> seqconns;
- RBSet<VisualScript::DataConnection> dataconns;
- RBSet<int> node_ids;
- node_ids.insert(function.node);
- {
- List<int> nd_queue;
- nd_queue.push_back(function.node);
- while (!nd_queue.is_empty()) {
- for (const VisualScript::SequenceConnection &F : script->sequence_connections) {
- if (nd_queue.front()->get() == F.from_node && !node_ids.has(F.to_node)) {
- nd_queue.push_back(F.to_node);
- node_ids.insert(F.to_node);
- }
- if (nd_queue.front()->get() == F.from_node && !seqconns.has(F)) {
- seqconns.insert(F);
- }
- }
- nd_queue.pop_front();
- }
- HashMap<int, HashMap<int, Pair<int, int>>> dc_lut; // :: to -> to_port -> (from, from_port)
- for (const VisualScript::DataConnection &F : script->data_connections) {
- dc_lut[F.to_node][F.to_port] = Pair<int, int>(F.from_node, F.from_port);
- }
- for (const int &F : node_ids) {
- nd_queue.push_back(F);
- }
- List<int> dc_keys;
- while (!nd_queue.is_empty()) {
- int ky = nd_queue.front()->get();
- for (const KeyValue<int, Pair<int, int>> &F : dc_lut[ky]) {
- VisualScript::DataConnection dc;
- dc.from_node = F.value.first;
- dc.from_port = F.value.second;
- dc.to_node = ky;
- dc.to_port = F.key;
- dataconns.insert(dc);
- nd_queue.push_back(dc.from_node);
- node_ids.insert(dc.from_node);
- }
- dc_keys.clear(); // Necessary as get_key_list does a push_back not a set.
- nd_queue.pop_front();
- }
- }
-
- //Multiple passes are required to set up this complex thing..
- //First create the nodes.
- for (const int &F : node_ids) {
- Ref<VisualScriptNode> node = script->nodes[F].node;
-
- VisualScriptNodeInstance *instance = node->instantiate(this); // Create instance.
- ERR_FAIL_COND(!instance);
-
- instance->base = node.ptr();
-
- instance->id = F;
- instance->input_port_count = node->get_input_value_port_count();
- instance->input_ports = nullptr;
- instance->output_port_count = node->get_output_value_port_count();
- instance->output_ports = nullptr;
- instance->sequence_output_count = node->get_output_sequence_port_count();
- instance->sequence_index = function.node_count++;
- instance->sequence_outputs = nullptr;
- instance->pass_idx = -1;
-
- if (instance->input_port_count) {
- instance->input_ports = memnew_arr(int, instance->input_port_count);
- for (int i = 0; i < instance->input_port_count; i++) {
- instance->input_ports[i] = -1; // If not assigned, will become default value.
- }
- }
-
- if (instance->output_port_count) {
- instance->output_ports = memnew_arr(int, instance->output_port_count);
- for (int i = 0; i < instance->output_port_count; i++) {
- instance->output_ports[i] = -1; // If not assigned, will output to trash.
- }
- }
-
- if (instance->sequence_output_count) {
- instance->sequence_outputs = memnew_arr(VisualScriptNodeInstance *, instance->sequence_output_count);
- for (int i = 0; i < instance->sequence_output_count; i++) {
- instance->sequence_outputs[i] = nullptr; // If it remains null, flow ends here.
- }
- }
-
- if (Object::cast_to<VisualScriptLocalVar>(node.ptr()) || Object::cast_to<VisualScriptLocalVarSet>(*node)) {
- // Working memory is shared only for this node, for the same variables.
- Ref<VisualScriptLocalVar> vslv = node;
-
- StringName var_name;
-
- if (Object::cast_to<VisualScriptLocalVar>(*node)) {
- var_name = String(Object::cast_to<VisualScriptLocalVar>(*node)->get_var_name()).strip_edges();
- } else {
- var_name = String(Object::cast_to<VisualScriptLocalVarSet>(*node)->get_var_name()).strip_edges();
- }
-
- if (!local_var_indices.has(var_name)) {
- local_var_indices[var_name] = function.max_stack;
- function.max_stack++;
- }
-
- instance->working_mem_idx = local_var_indices[var_name];
-
- } else if (instance->get_working_memory_size()) {
- instance->working_mem_idx = function.max_stack;
- function.max_stack += instance->get_working_memory_size();
- } else {
- instance->working_mem_idx = -1; //no working mem
- }
-
- max_input_args = MAX(max_input_args, instance->input_port_count);
- max_output_args = MAX(max_output_args, instance->output_port_count);
-
- instances[F] = instance;
- }
-
- function.trash_pos = function.max_stack++; // create pos for trash
-
- // Second pass, do data connections.
- for (const VisualScript::DataConnection &F : dataconns) {
- VisualScript::DataConnection dc = F;
- ERR_CONTINUE(!instances.has(dc.from_node));
- VisualScriptNodeInstance *from = instances[dc.from_node];
- ERR_CONTINUE(!instances.has(dc.to_node));
- VisualScriptNodeInstance *to = instances[dc.to_node];
- ERR_CONTINUE(dc.from_port >= from->output_port_count);
- ERR_CONTINUE(dc.to_port >= to->input_port_count);
-
- if (from->output_ports[dc.from_port] == -1) {
- int stack_pos = function.max_stack++;
- from->output_ports[dc.from_port] = stack_pos;
- }
-
- if (from->get_sequence_output_count() == 0 && to->dependencies.find(from) == -1) {
- // If the node we are reading from has no output sequence, we must call step() before reading from it.
- if (from->pass_idx == -1) {
- from->pass_idx = function.pass_stack_size;
- function.pass_stack_size++;
- }
- to->dependencies.push_back(from);
- }
-
- to->input_ports[dc.to_port] = from->output_ports[dc.from_port]; // Read from wherever the stack is.
- }
-
- // Third pass, do sequence connections.
- for (const VisualScript::SequenceConnection &F : seqconns) {
- VisualScript::SequenceConnection sc = F;
- ERR_CONTINUE(!instances.has(sc.from_node));
- VisualScriptNodeInstance *from = instances[sc.from_node];
- ERR_CONTINUE(!instances.has(sc.to_node));
- VisualScriptNodeInstance *to = instances[sc.to_node];
- ERR_CONTINUE(sc.from_output >= from->sequence_output_count);
-
- from->sequence_outputs[sc.from_output] = to;
- }
-
- //fourth pass:
- // 1) unassigned input ports to default values
- // 2) connect unassigned output ports to trash
- for (const int &F : node_ids) {
- ERR_CONTINUE(!instances.has(F));
-
- Ref<VisualScriptNode> node = script->nodes[F].node;
- VisualScriptNodeInstance *instance = instances[F];
-
- // Connect to default values.
- for (int i = 0; i < instance->input_port_count; i++) {
- if (instance->input_ports[i] == -1) {
- // Unassigned, connect to default val.
- instance->input_ports[i] = default_values.size() | VisualScriptNodeInstance::INPUT_DEFAULT_VALUE_BIT;
- default_values.push_back(node->get_default_input_value(i));
- }
- }
-
- // Connect to trash.
- for (int i = 0; i < instance->output_port_count; i++) {
- if (instance->output_ports[i] == -1) {
- instance->output_ports[i] = function.trash_pos; //trash is same for all
- }
- }
- }
-
- functions[E.key] = function;
- }
- }
-}
-
-ScriptLanguage *VisualScriptInstance::get_language() {
- return VisualScriptLanguage::singleton;
-}
-
-VisualScriptInstance::VisualScriptInstance() {
-}
-
-VisualScriptInstance::~VisualScriptInstance() {
- {
- MutexLock lock(VisualScriptLanguage::singleton->lock);
-
- script->instances.erase(owner);
- }
-
- for (const KeyValue<int, VisualScriptNodeInstance *> &E : instances) {
- memdelete(E.value);
- }
-}
-
-/////////////////////////////////////////////
-
-/////////////////////
-
-Variant VisualScriptFunctionState::_signal_callback(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
- ERR_FAIL_COND_V(function == StringName(), Variant());
-
-#ifdef DEBUG_ENABLED
-
- ERR_FAIL_COND_V_MSG(instance_id.is_valid() && !ObjectDB::get_instance(instance_id), Variant(), "Resumed after yield, but class instance is gone.");
- ERR_FAIL_COND_V_MSG(script_id.is_valid() && !ObjectDB::get_instance(script_id), Variant(), "Resumed after yield, but script is gone.");
-
-#endif
-
- r_error.error = Callable::CallError::CALL_OK;
-
- Array args;
-
- if (p_argcount == 0) {
- r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_error.argument = 1;
- return Variant();
- } else if (p_argcount == 1) {
- //noooneee, reserved for me, me and only me.
- } else {
- for (int i = 0; i < p_argcount - 1; i++) {
- args.push_back(*p_args[i]);
- }
- }
-
- Ref<VisualScriptFunctionState> self = *p_args[p_argcount - 1]; //hi, I'm myself, needed this to remain alive.
-
- if (self.is_null()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = p_argcount - 1;
- r_error.expected = Variant::OBJECT;
- return Variant();
- }
-
- r_error.error = Callable::CallError::CALL_OK;
-
- Variant *working_mem = ((Variant *)stack.ptr()) + working_mem_index;
-
- *working_mem = args; // Arguments go to working mem.
-
- Variant ret = instance->_call_internal(function, stack.ptrw(), stack.size(), node, flow_stack_pos, pass, true, r_error);
- function = StringName(); //invalidate
- return ret;
-}
-
-void VisualScriptFunctionState::connect_to_signal(Object *p_obj, const String &p_signal, Array p_binds) {
- ERR_FAIL_NULL(p_obj);
- Vector<Variant> binds;
- for (int i = 0; i < p_binds.size(); i++) {
- binds.push_back(p_binds[i]);
- }
- binds.push_back(Ref<VisualScriptFunctionState>(this)); //add myself on the back to avoid dying from unreferencing
-
- Vector<const Variant *> bind_ptrs;
- bind_ptrs.resize(p_binds.size());
- for (int i = 0; i < bind_ptrs.size(); i++) {
- bind_ptrs.write[i] = &binds.write[i];
- }
-
- p_obj->connect(p_signal, Callable(this, "_signal_callback").bindp((const Variant **)bind_ptrs.ptr(), bind_ptrs.size()), CONNECT_ONESHOT);
-}
-
-bool VisualScriptFunctionState::is_valid() const {
- return function != StringName();
-}
-
-Variant VisualScriptFunctionState::resume(Array p_args) {
- ERR_FAIL_COND_V(function == StringName(), Variant());
-#ifdef DEBUG_ENABLED
-
- ERR_FAIL_COND_V_MSG(instance_id.is_valid() && !ObjectDB::get_instance(instance_id), Variant(), "Resumed after yield, but class instance is gone.");
- ERR_FAIL_COND_V_MSG(script_id.is_valid() && !ObjectDB::get_instance(script_id), Variant(), "Resumed after yield, but script is gone.");
-
-#endif
-
- Callable::CallError r_error;
- r_error.error = Callable::CallError::CALL_OK;
-
- Variant *working_mem = ((Variant *)stack.ptr()) + working_mem_index;
-
- *working_mem = p_args; // Arguments go to working mem.
-
- Variant ret = instance->_call_internal(function, stack.ptrw(), stack.size(), node, flow_stack_pos, pass, true, r_error);
- function = StringName(); //invalidate
- return ret;
-}
-
-void VisualScriptFunctionState::_bind_methods() {
- ClassDB::bind_method(D_METHOD("connect_to_signal", "obj", "signals", "args"), &VisualScriptFunctionState::connect_to_signal);
- ClassDB::bind_method(D_METHOD("resume", "args"), &VisualScriptFunctionState::resume, DEFVAL(Array()));
- ClassDB::bind_method(D_METHOD("is_valid"), &VisualScriptFunctionState::is_valid);
- ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "_signal_callback", &VisualScriptFunctionState::_signal_callback, MethodInfo("_signal_callback"));
-}
-
-VisualScriptFunctionState::VisualScriptFunctionState() {
-}
-
-VisualScriptFunctionState::~VisualScriptFunctionState() {
- if (function != StringName()) {
- Variant *s = ((Variant *)stack.ptr());
- for (int i = 0; i < variant_stack_size; i++) {
- s[i].~Variant();
- }
- }
-}
-
-///////////////////////////////////////////////
-
-String VisualScriptLanguage::get_name() const {
- return "VisualScript";
-}
-
-/* LANGUAGE FUNCTIONS */
-void VisualScriptLanguage::init() {
-}
-
-String VisualScriptLanguage::get_type() const {
- return "VisualScript";
-}
-
-String VisualScriptLanguage::get_extension() const {
- return "vs";
-}
-
-Error VisualScriptLanguage::execute_file(const String &p_path) {
- return OK;
-}
-
-void VisualScriptLanguage::finish() {
-}
-
-/* EDITOR FUNCTIONS */
-void VisualScriptLanguage::get_reserved_words(List<String> *p_words) const {
-}
-
-bool VisualScriptLanguage::is_control_flow_keyword(String p_keyword) const {
- return false;
-}
-
-void VisualScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
-}
-
-void VisualScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const {
-}
-
-bool VisualScriptLanguage::is_using_templates() {
- return false;
-}
-
-Ref<Script> VisualScriptLanguage::make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const {
- Ref<VisualScript> script;
- script.instantiate();
- script->set_instance_base_type(p_base_class_name);
- return script;
-}
-
-bool VisualScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, HashSet<int> *r_safe_lines) const {
- return false;
-}
-
-Script *VisualScriptLanguage::create_script() const {
- return memnew(VisualScript);
-}
-
-bool VisualScriptLanguage::has_named_classes() const {
- return false;
-}
-
-bool VisualScriptLanguage::supports_builtin_mode() const {
- return true;
-}
-
-int VisualScriptLanguage::find_function(const String &p_function, const String &p_code) const {
- return -1;
-}
-
-String VisualScriptLanguage::make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const {
- return String();
-}
-
-void VisualScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_to_line) const {
-}
-
-void VisualScriptLanguage::add_global_constant(const StringName &p_variable, const Variant &p_value) {
-}
-
-/* DEBUGGER FUNCTIONS */
-
-bool VisualScriptLanguage::debug_break_parse(const String &p_file, int p_node, const String &p_error) {
- // Break because of parse error.
-
- if (EngineDebugger::is_active() && Thread::get_caller_id() == Thread::get_main_id()) {
- _debug_parse_err_node = p_node;
- _debug_parse_err_file = p_file;
- _debug_error = p_error;
- EngineDebugger::get_script_debugger()->debug(this, false, true);
- return true;
- } else {
- return false;
- }
-}
-
-bool VisualScriptLanguage::debug_break(const String &p_error, bool p_allow_continue) {
- if (EngineDebugger::is_active() && Thread::get_caller_id() == Thread::get_main_id()) {
- _debug_parse_err_node = -1;
- _debug_parse_err_file = "";
- _debug_error = p_error;
- EngineDebugger::get_script_debugger()->debug(this, p_allow_continue, true);
- return true;
- } else {
- return false;
- }
-}
-
-String VisualScriptLanguage::debug_get_error() const {
- return _debug_error;
-}
-
-int VisualScriptLanguage::debug_get_stack_level_count() const {
- if (_debug_parse_err_node >= 0) {
- return 1;
- }
-
- return _debug_call_stack_pos;
-}
-
-int VisualScriptLanguage::debug_get_stack_level_line(int p_level) const {
- if (_debug_parse_err_node >= 0) {
- return _debug_parse_err_node;
- }
-
- ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, -1);
-
- int l = _debug_call_stack_pos - p_level - 1;
-
- return *(_call_stack[l].current_id);
-}
-
-String VisualScriptLanguage::debug_get_stack_level_function(int p_level) const {
- if (_debug_parse_err_node >= 0) {
- return "";
- }
-
- ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, "");
- int l = _debug_call_stack_pos - p_level - 1;
- return *_call_stack[l].function;
-}
-
-String VisualScriptLanguage::debug_get_stack_level_source(int p_level) const {
- if (_debug_parse_err_node >= 0) {
- return _debug_parse_err_file;
- }
-
- ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, "");
- int l = _debug_call_stack_pos - p_level - 1;
- return _call_stack[l].instance->get_script_ptr()->get_path();
-}
-
-void VisualScriptLanguage::debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
- if (_debug_parse_err_node >= 0) {
- return;
- }
-
- ERR_FAIL_INDEX(p_level, _debug_call_stack_pos);
-
- int l = _debug_call_stack_pos - p_level - 1;
- const StringName *f = _call_stack[l].function;
-
- ERR_FAIL_COND(!_call_stack[l].instance->functions.has(*f));
-
- VisualScriptNodeInstance *node = _call_stack[l].instance->instances[*_call_stack[l].current_id];
- ERR_FAIL_COND(!node);
-
- p_locals->push_back("node_name");
- p_values->push_back(node->get_base_node()->get_text());
-
- for (int i = 0; i < node->input_port_count; i++) {
- String name = node->get_base_node()->get_input_value_port_info(i).name;
- if (name.is_empty()) {
- name = "in_" + itos(i);
- }
-
- p_locals->push_back("input/" + name);
-
- //value is trickier
-
- int in_from = node->input_ports[i];
- int in_value = in_from & VisualScriptNodeInstance::INPUT_MASK;
-
- if (in_from & VisualScriptNodeInstance::INPUT_DEFAULT_VALUE_BIT) {
- p_values->push_back(_call_stack[l].instance->default_values[in_value]);
- } else {
- p_values->push_back(_call_stack[l].stack[in_value]);
- }
- }
-
- for (int i = 0; i < node->output_port_count; i++) {
- String name = node->get_base_node()->get_output_value_port_info(i).name;
- if (name.is_empty()) {
- name = "out_" + itos(i);
- }
-
- p_locals->push_back("output/" + name);
-
- //value is trickier
-
- int in_from = node->output_ports[i];
- p_values->push_back(_call_stack[l].stack[in_from]);
- }
-
- for (int i = 0; i < node->get_working_memory_size(); i++) {
- p_locals->push_back("working_mem/mem_" + itos(i));
- p_values->push_back((*_call_stack[l].work_mem)[i]);
- }
-}
-
-void VisualScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
- if (_debug_parse_err_node >= 0) {
- return;
- }
-
- ERR_FAIL_INDEX(p_level, _debug_call_stack_pos);
- int l = _debug_call_stack_pos - p_level - 1;
-
- Ref<VisualScript> vs = _call_stack[l].instance->get_script();
- if (vs.is_null()) {
- return;
- }
-
- List<StringName> vars;
- vs->get_variable_list(&vars);
- for (const StringName &E : vars) {
- Variant v;
- if (_call_stack[l].instance->get_variable(E, &v)) {
- p_members->push_back("variables/" + E);
- p_values->push_back(v);
- }
- }
-}
-
-void VisualScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
- // No globals are really reachable in gdscript.
-}
-
-String VisualScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) {
- return "";
-}
-
-void VisualScriptLanguage::reload_all_scripts() {
-}
-
-void VisualScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) {
-}
-
-/* LOADER FUNCTIONS */
-
-void VisualScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const {
- p_extensions->push_back("vs");
-}
-
-void VisualScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const {
-}
-
-void VisualScriptLanguage::get_public_constants(List<Pair<String, Variant>> *p_constants) const {
-}
-
-void VisualScriptLanguage::get_public_annotations(List<MethodInfo> *p_annotations) const {
-}
-
-void VisualScriptLanguage::profiling_start() {
-}
-
-void VisualScriptLanguage::profiling_stop() {
-}
-
-int VisualScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) {
- return 0;
-}
-
-int VisualScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) {
- return 0;
-}
-
-VisualScriptLanguage *VisualScriptLanguage::singleton = nullptr;
-
-void VisualScriptLanguage::add_register_func(const String &p_name, VisualScriptNodeRegisterFunc p_func) {
- ERR_FAIL_COND(register_funcs.has(p_name));
- register_funcs[p_name] = p_func;
-}
-
-void VisualScriptLanguage::remove_register_func(const String &p_name) {
- ERR_FAIL_COND(!register_funcs.has(p_name));
- register_funcs.erase(p_name);
-}
-
-Ref<VisualScriptNode> VisualScriptLanguage::create_node_from_name(const String &p_name) {
- ERR_FAIL_COND_V(!register_funcs.has(p_name), Ref<VisualScriptNode>());
-
- return register_funcs[p_name](p_name);
-}
-
-void VisualScriptLanguage::get_registered_node_names(List<String> *r_names) {
- for (const KeyValue<String, VisualScriptNodeRegisterFunc> &E : register_funcs) {
- r_names->push_back(E.key);
- }
-}
-
-VisualScriptLanguage::VisualScriptLanguage() {
- singleton = this;
-
- int dmcs = GLOBAL_DEF("debug/settings/visual_script/max_call_stack", 1024);
- ProjectSettings::get_singleton()->set_custom_property_info("debug/settings/visual_script/max_call_stack", PropertyInfo(Variant::INT, "debug/settings/visual_script/max_call_stack", PROPERTY_HINT_RANGE, "1024,4096,1,or_greater")); //minimum is 1024
-
- if (EngineDebugger::is_active()) {
- // Debugging enabled!
- _debug_max_call_stack = dmcs;
- _call_stack = memnew_arr(CallLevel, _debug_max_call_stack + 1);
-
- } else {
- _debug_max_call_stack = 0;
- _call_stack = nullptr;
- }
-}
-
-VisualScriptLanguage::~VisualScriptLanguage() {
- if (_call_stack) {
- memdelete_arr(_call_stack);
- }
- singleton = nullptr;
-}
diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h
deleted file mode 100644
index 14cb14e8d9..0000000000
--- a/modules/visual_script/visual_script.h
+++ /dev/null
@@ -1,627 +0,0 @@
-/*************************************************************************/
-/* visual_script.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef VISUAL_SCRIPT_H
-#define VISUAL_SCRIPT_H
-
-#include "core/debugger/engine_debugger.h"
-#include "core/debugger/script_debugger.h"
-#include "core/doc_data.h"
-#include "core/object/script_language.h"
-#include "core/os/thread.h"
-#include "core/templates/rb_set.h"
-
-class VisualScriptInstance;
-class VisualScriptNodeInstance;
-class VisualScript;
-
-class VisualScriptNode : public Resource {
- GDCLASS(VisualScriptNode, Resource);
-
- friend class VisualScript;
-
- Ref<VisualScript> script_used;
-
- Array default_input_values;
- bool breakpoint = false;
-
- void _set_default_input_values(Array p_values);
- Array _get_default_input_values() const;
-
- void validate_input_default_values();
-
-protected:
- void ports_changed_notify();
- static void _bind_methods();
-
-public:
- Ref<VisualScript> get_visual_script() const;
-
- virtual int get_output_sequence_port_count() const = 0;
- virtual bool has_input_sequence_port() const = 0;
-
- virtual String get_output_sequence_port_text(int p_port) const = 0;
-
- virtual bool has_mixed_input_and_sequence_ports() const { return false; }
-
- virtual int get_input_value_port_count() const = 0;
- virtual int get_output_value_port_count() const = 0;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const = 0;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const = 0;
-
- void set_default_input_value(int p_port, const Variant &p_value);
- Variant get_default_input_value(int p_port) const;
-
- virtual String get_caption() const = 0;
- virtual String get_text() const;
- virtual String get_category() const = 0;
-
- // Used by editor, this is not really saved.
- void set_breakpoint(bool p_breakpoint);
- bool is_breakpoint() const;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) = 0;
-
- struct TypeGuess {
- Variant::Type type = Variant::NIL;
- StringName gdclass;
- Ref<Script> script;
- };
-
- virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const;
-
- VisualScriptNode();
-};
-
-class VisualScriptNodeInstance {
- friend class VisualScriptInstance;
- friend class VisualScriptLanguage; // For debugger.
-
- enum { // Input argument addressing.
- INPUT_SHIFT = 1 << 24,
- INPUT_MASK = INPUT_SHIFT - 1,
- INPUT_DEFAULT_VALUE_BIT = INPUT_SHIFT, // from unassigned input port, using default value (edited by user)
- };
-
- int id = 0;
- int sequence_index = 0;
- VisualScriptNodeInstance **sequence_outputs = nullptr;
- int sequence_output_count = 0;
- Vector<VisualScriptNodeInstance *> dependencies;
- int *input_ports = nullptr;
- int input_port_count = 0;
- int *output_ports = nullptr;
- int output_port_count = 0;
- int working_mem_idx = 0;
- int pass_idx = 0;
-
- VisualScriptNode *base = nullptr;
-
-public:
- enum StartMode {
- START_MODE_BEGIN_SEQUENCE,
- START_MODE_CONTINUE_SEQUENCE,
- START_MODE_RESUME_YIELD
- };
-
- enum {
- STEP_SHIFT = 1 << 24,
- STEP_MASK = STEP_SHIFT - 1,
- STEP_FLAG_PUSH_STACK_BIT = STEP_SHIFT, // push bit to stack
- STEP_FLAG_GO_BACK_BIT = STEP_SHIFT << 1, // go back to previous node
- STEP_NO_ADVANCE_BIT = STEP_SHIFT << 2, // do not advance past this node
- STEP_EXIT_FUNCTION_BIT = STEP_SHIFT << 3, // return from function
- STEP_YIELD_BIT = STEP_SHIFT << 4, // yield (will find VisualScriptFunctionState state in first working memory)
-
- FLOW_STACK_PUSHED_BIT = 1 << 30, // in flow stack, means bit was pushed (must go back here if end of sequence)
- FLOW_STACK_MASK = FLOW_STACK_PUSHED_BIT - 1
-
- };
-
- _FORCE_INLINE_ int get_input_port_count() const { return input_port_count; }
- _FORCE_INLINE_ int get_output_port_count() const { return output_port_count; }
- _FORCE_INLINE_ int get_sequence_output_count() const { return sequence_output_count; }
-
- _FORCE_INLINE_ int get_id() const { return id; }
-
- virtual int get_working_memory_size() const { return 0; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) = 0; // Do a step, return which sequence port to go out.
-
- Ref<VisualScriptNode> get_base_node() { return Ref<VisualScriptNode>(base); }
-
- VisualScriptNodeInstance();
- virtual ~VisualScriptNodeInstance();
-};
-
-class VisualScript : public Script {
- GDCLASS(VisualScript, Script);
-
- RES_BASE_EXTENSION("vs");
-
-public:
- struct SequenceConnection {
- union {
- struct {
- uint64_t from_node : 24;
- uint64_t from_output : 16;
- uint64_t to_node : 24;
- };
- uint64_t id = 0;
- };
-
- bool operator<(const SequenceConnection &p_connection) const {
- return id < p_connection.id;
- }
- };
-
- struct DataConnection {
- union {
- struct {
- uint64_t from_node : 24;
- uint64_t from_port : 8;
- uint64_t to_node : 24;
- uint64_t to_port : 8;
- };
- uint64_t id = 0;
- };
-
- bool operator<(const DataConnection &p_connection) const {
- return id < p_connection.id;
- }
- };
-
-private:
- friend class VisualScriptInstance;
-
- StringName base_type;
- struct Argument {
- String name;
- Variant::Type type = Variant::Type::NIL;
- };
-
- struct NodeData {
- Point2 pos;
- Ref<VisualScriptNode> node;
- };
-
- HashMap<int, NodeData> nodes; // Can be a sparse map.
-
- RBSet<SequenceConnection> sequence_connections;
- RBSet<DataConnection> data_connections;
-
- Vector2 scroll;
-
- struct Function {
- int func_id;
- Function() { func_id = -1; }
- };
-
- struct Variable {
- PropertyInfo info;
- Variant default_value;
- bool _export = false;
- // Add getter & setter options here.
- };
-
- HashMap<StringName, Function> functions;
- HashMap<StringName, Variable> variables;
- HashMap<StringName, Vector<Argument>> custom_signals;
- Dictionary rpc_functions;
-
- HashMap<Object *, VisualScriptInstance *> instances;
-
- bool is_tool_script;
-
-#ifdef TOOLS_ENABLED
- RBSet<PlaceHolderScriptInstance *> placeholders;
- // void _update_placeholder(PlaceHolderScriptInstance *p_placeholder);
- virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override;
- void _update_placeholders();
-#endif
-
- void _set_variable_info(const StringName &p_name, const Dictionary &p_info);
- Dictionary _get_variable_info(const StringName &p_name) const;
-
- void _set_data(const Dictionary &p_data);
- Dictionary _get_data() const;
-
-protected:
- void _node_ports_changed(int p_id);
- static void _bind_methods();
-
-public:
- bool inherits_script(const Ref<Script> &p_script) const override;
-
- void set_scroll(const Vector2 &p_scroll);
- Vector2 get_scroll() const;
-
- void add_function(const StringName &p_name, int p_func_node_id);
- bool has_function(const StringName &p_name) const;
- void remove_function(const StringName &p_name);
- void rename_function(const StringName &p_name, const StringName &p_new_name);
- void get_function_list(List<StringName> *r_functions) const;
- int get_function_node_id(const StringName &p_name) const;
- void set_tool_enabled(bool p_enabled);
-
- void add_node(int p_id, const Ref<VisualScriptNode> &p_node, const Point2 &p_pos = Point2());
- void remove_node(int p_id);
- bool has_node(int p_id) const;
- Ref<VisualScriptNode> get_node(int p_id) const;
- void set_node_position(int p_id, const Point2 &p_pos);
- Point2 get_node_position(int p_id) const;
- void get_node_list(List<int> *r_nodes) const;
-
- void sequence_connect(int p_from_node, int p_from_output, int p_to_node);
- void sequence_disconnect(int p_from_node, int p_from_output, int p_to_node);
- bool has_sequence_connection(int p_from_node, int p_from_output, int p_to_node) const;
- void get_sequence_connection_list(List<SequenceConnection> *r_connection) const;
- RBSet<int> get_output_sequence_ports_connected(int from_node);
-
- void data_connect(int p_from_node, int p_from_port, int p_to_node, int p_to_port);
- void data_disconnect(int p_from_node, int p_from_port, int p_to_node, int p_to_port);
- bool has_data_connection(int p_from_node, int p_from_port, int p_to_node, int p_to_port) const;
- void get_data_connection_list(List<DataConnection> *r_connection) const;
-
- bool is_input_value_port_connected(int p_node, int p_port) const;
- bool get_input_value_port_connection_source(int p_node, int p_port, int *r_node, int *r_port) const;
-
- void add_variable(const StringName &p_name, const Variant &p_default_value = Variant(), bool p_export = false);
- bool has_variable(const StringName &p_name) const;
- void remove_variable(const StringName &p_name);
- void set_variable_default_value(const StringName &p_name, const Variant &p_value);
- Variant get_variable_default_value(const StringName &p_name) const;
- void set_variable_info(const StringName &p_name, const PropertyInfo &p_info);
- PropertyInfo get_variable_info(const StringName &p_name) const;
- void set_variable_export(const StringName &p_name, bool p_export);
- bool get_variable_export(const StringName &p_name) const;
- void get_variable_list(List<StringName> *r_variables) const;
- void rename_variable(const StringName &p_name, const StringName &p_new_name);
-
- void add_custom_signal(const StringName &p_name);
- bool has_custom_signal(const StringName &p_name) const;
- void custom_signal_add_argument(const StringName &p_func, Variant::Type p_type, const String &p_name, int p_index = -1);
- void custom_signal_set_argument_type(const StringName &p_func, int p_argidx, Variant::Type p_type);
- Variant::Type custom_signal_get_argument_type(const StringName &p_func, int p_argidx) const;
- void custom_signal_set_argument_name(const StringName &p_func, int p_argidx, const String &p_name);
- String custom_signal_get_argument_name(const StringName &p_func, int p_argidx) const;
- void custom_signal_remove_argument(const StringName &p_func, int p_argidx);
- int custom_signal_get_argument_count(const StringName &p_func) const;
- void custom_signal_swap_argument(const StringName &p_func, int p_argidx, int p_with_argidx);
- void remove_custom_signal(const StringName &p_name);
- void rename_custom_signal(const StringName &p_name, const StringName &p_new_name);
- RBSet<int> get_output_sequence_ports_connected(const String &edited_func, int from_node);
-
- void get_custom_signal_list(List<StringName> *r_custom_signals) const;
-
- int get_available_id() const;
-
- void set_instance_base_type(const StringName &p_type);
-
- virtual bool can_instantiate() const override;
-
- virtual Ref<Script> get_base_script() const override;
- virtual StringName get_instance_base_type() const override;
- virtual ScriptInstance *instance_create(Object *p_this) override;
- virtual bool instance_has(const Object *p_this) const override;
-
- virtual bool has_source_code() const override;
- virtual String get_source_code() const override;
- virtual void set_source_code(const String &p_code) override;
- virtual Error reload(bool p_keep_state = false) override;
-
-#ifdef TOOLS_ENABLED
- virtual Vector<DocData::ClassDoc> get_documentation() const override {
- Vector<DocData::ClassDoc> docs;
- return docs;
- }
-#endif // TOOLS_ENABLED
-
- virtual bool is_tool() const override;
- virtual bool is_valid() const override;
-
- virtual ScriptLanguage *get_language() const override;
-
- virtual bool has_script_signal(const StringName &p_signal) const override;
- virtual void get_script_signal_list(List<MethodInfo> *r_signals) const override;
-
- virtual bool get_property_default_value(const StringName &p_property, Variant &r_value) const override;
- virtual void get_script_method_list(List<MethodInfo> *p_list) const override;
-
- virtual bool has_method(const StringName &p_method) const override;
- virtual MethodInfo get_method_info(const StringName &p_method) const override;
-
- virtual void get_script_property_list(List<PropertyInfo> *p_list) const override;
-
- virtual int get_member_line(const StringName &p_member) const override;
-
- virtual const Variant get_rpc_config() const override;
-
-#ifdef TOOLS_ENABLED
- virtual bool are_subnodes_edited() const;
-#endif
-
- VisualScript();
- ~VisualScript();
-};
-
-class VisualScriptInstance : public ScriptInstance {
- Object *owner = nullptr;
- Ref<VisualScript> script;
-
- HashMap<StringName, Variant> variables; // Using variable path, not script.
- HashMap<int, VisualScriptNodeInstance *> instances;
-
- struct Function {
- int node = 0;
- int max_stack = 0;
- int trash_pos = 0;
- int flow_stack_size = 0;
- int pass_stack_size = 0;
- int node_count = 0;
- int argument_count = 0;
- };
-
- HashMap<StringName, Function> functions;
-
- Vector<Variant> default_values;
- int max_input_args = 0;
- int max_output_args = 0;
-
- StringName source;
-
- void _dependency_step(VisualScriptNodeInstance *node, int p_pass, int *pass_stack, const Variant **input_args, Variant **output_args, Variant *variant_stack, Callable::CallError &r_error, String &error_str, VisualScriptNodeInstance **r_error_node);
- Variant _call_internal(const StringName &p_method, void *p_stack, int p_stack_size, VisualScriptNodeInstance *p_node, int p_flow_stack_pos, int p_pass, bool p_resuming_yield, Callable::CallError &r_error);
-
- friend class VisualScriptFunctionState; // For yield.
- friend class VisualScriptLanguage; // For debugger.
-public:
- virtual bool set(const StringName &p_name, const Variant &p_value);
- virtual bool get(const StringName &p_name, Variant &r_ret) const;
- virtual void get_property_list(List<PropertyInfo> *p_properties) const;
- virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const;
-
- virtual void get_method_list(List<MethodInfo> *p_list) const;
- virtual bool has_method(const StringName &p_method) const;
- virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);
- virtual void notification(int p_notification);
- String to_string(bool *r_valid);
-
- bool set_variable(const StringName &p_variable, const Variant &p_value) {
- HashMap<StringName, Variant>::Iterator E = variables.find(p_variable);
- if (!E) {
- return false;
- }
-
- E->value = p_value;
- return true;
- }
-
- bool get_variable(const StringName &p_variable, Variant *r_variable) const {
- HashMap<StringName, Variant>::ConstIterator E = variables.find(p_variable);
- if (!E) {
- return false;
- }
-
- *r_variable = E->value;
- return true;
- }
-
- virtual Ref<Script> get_script() const;
-
- _FORCE_INLINE_ VisualScript *get_script_ptr() { return script.ptr(); }
- _FORCE_INLINE_ Object *get_owner_ptr() { return owner; }
-
- void create(const Ref<VisualScript> &p_script, Object *p_owner);
-
- virtual ScriptLanguage *get_language();
-
- virtual const Variant get_rpc_config() const;
-
- VisualScriptInstance();
- ~VisualScriptInstance();
-};
-
-class VisualScriptFunctionState : public RefCounted {
- GDCLASS(VisualScriptFunctionState, RefCounted);
- friend class VisualScriptInstance;
-
- ObjectID instance_id;
- ObjectID script_id;
- VisualScriptInstance *instance = nullptr;
- StringName function;
- Vector<uint8_t> stack;
- int working_mem_index = 0;
- int variant_stack_size = 0;
- VisualScriptNodeInstance *node = nullptr;
- int flow_stack_pos = 0;
- int pass = 0;
-
- Variant _signal_callback(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
-
-protected:
- static void _bind_methods();
-
-public:
- void connect_to_signal(Object *p_obj, const String &p_signal, Array p_binds);
- bool is_valid() const;
- Variant resume(Array p_args);
- VisualScriptFunctionState();
- ~VisualScriptFunctionState();
-};
-
-typedef Ref<VisualScriptNode> (*VisualScriptNodeRegisterFunc)(const String &p_type);
-
-class VisualScriptLanguage : public ScriptLanguage {
- HashMap<String, VisualScriptNodeRegisterFunc> register_funcs;
-
- struct CallLevel {
- Variant *stack = nullptr;
- Variant **work_mem = nullptr;
- const StringName *function = nullptr;
- VisualScriptInstance *instance = nullptr;
- int *current_id = nullptr;
- };
-
- int _debug_parse_err_node = -1;
- String _debug_parse_err_file = "";
- String _debug_error;
- int _debug_call_stack_pos = 0;
- int _debug_max_call_stack;
- CallLevel *_call_stack = nullptr;
-
-public:
- StringName notification = "_notification";
- StringName _get_output_port_unsequenced;
- StringName _step = "_step";
- StringName _subcall = "_subcall";
-
- static VisualScriptLanguage *singleton;
-
- Mutex lock;
-
- bool debug_break(const String &p_error, bool p_allow_continue = true);
- bool debug_break_parse(const String &p_file, int p_node, const String &p_error);
-
- _FORCE_INLINE_ void enter_function(VisualScriptInstance *p_instance, const StringName *p_function, Variant *p_stack, Variant **p_work_mem, int *current_id) {
- if (Thread::get_main_id() != Thread::get_caller_id()) {
- return; // No support for other threads than main for now.
- }
-
- if (EngineDebugger::get_script_debugger()->get_lines_left() > 0 && EngineDebugger::get_script_debugger()->get_depth() >= 0) {
- EngineDebugger::get_script_debugger()->set_depth(EngineDebugger::get_script_debugger()->get_depth() + 1);
- }
-
- if (_debug_call_stack_pos >= _debug_max_call_stack) {
- // Stack overflow.
- _debug_error = vformat("Stack overflow (stack size: %s). Check for infinite recursion in your script.", _debug_max_call_stack);
- EngineDebugger::get_script_debugger()->debug(this);
- return;
- }
-
- _call_stack[_debug_call_stack_pos].stack = p_stack;
- _call_stack[_debug_call_stack_pos].instance = p_instance;
- _call_stack[_debug_call_stack_pos].function = p_function;
- _call_stack[_debug_call_stack_pos].work_mem = p_work_mem;
- _call_stack[_debug_call_stack_pos].current_id = current_id;
- _debug_call_stack_pos++;
- }
-
- _FORCE_INLINE_ void exit_function() {
- if (Thread::get_main_id() != Thread::get_caller_id()) {
- return; // No support for other threads than main for now.
- }
-
- if (EngineDebugger::get_script_debugger()->get_lines_left() > 0 && EngineDebugger::get_script_debugger()->get_depth() >= 0) {
- EngineDebugger::get_script_debugger()->set_depth(EngineDebugger::get_script_debugger()->get_depth() - 1);
- }
-
- if (_debug_call_stack_pos == 0) {
- _debug_error = "Stack underflow (engine bug), please report.";
- EngineDebugger::get_script_debugger()->debug(this);
- return;
- }
-
- _debug_call_stack_pos--;
- }
-
- //////////////////////////////////////
-
- virtual String get_name() const override;
-
- /* LANGUAGE FUNCTIONS */
- virtual void init() override;
- virtual String get_type() const override;
- virtual String get_extension() const override;
- virtual Error execute_file(const String &p_path) override;
- virtual void finish() override;
-
- /* EDITOR FUNCTIONS */
- virtual void get_reserved_words(List<String> *p_words) const override;
- virtual bool is_control_flow_keyword(String p_keyword) const override;
- virtual void get_comment_delimiters(List<String> *p_delimiters) const override;
- virtual void get_string_delimiters(List<String> *p_delimiters) const override;
- virtual bool is_using_templates() override;
- virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override;
- virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, HashSet<int> *r_safe_lines = nullptr) const override;
- virtual Script *create_script() const override;
- virtual bool has_named_classes() const override;
- virtual bool supports_builtin_mode() const override;
- virtual int find_function(const String &p_function, const String &p_code) const override;
- virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const override;
- virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const override;
- virtual void add_global_constant(const StringName &p_variable, const Variant &p_value) override;
-
- /* DEBUGGER FUNCTIONS */
-
- virtual String debug_get_error() const override;
- virtual int debug_get_stack_level_count() const override;
- virtual int debug_get_stack_level_line(int p_level) const override;
- virtual String debug_get_stack_level_function(int p_level) const override;
- virtual String debug_get_stack_level_source(int p_level) const override;
- virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override;
- virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override;
- virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override;
- virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1) override;
-
- virtual void reload_all_scripts() override;
- virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) override;
- /* LOADER FUNCTIONS */
-
- virtual void get_recognized_extensions(List<String> *p_extensions) const override;
- virtual void get_public_functions(List<MethodInfo> *p_functions) const override;
- virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const override;
- virtual void get_public_annotations(List<MethodInfo> *p_annotations) const override;
-
- virtual void profiling_start() override;
- virtual void profiling_stop() override;
-
- virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) override;
- virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) override;
-
- void add_register_func(const String &p_name, VisualScriptNodeRegisterFunc p_func);
- void remove_register_func(const String &p_name);
- Ref<VisualScriptNode> create_node_from_name(const String &p_name);
- void get_registered_node_names(List<String> *r_names);
-
- VisualScriptLanguage();
- ~VisualScriptLanguage();
-};
-
-// Aid for registering.
-template <class T>
-static Ref<VisualScriptNode> create_node_generic(const String &p_name) {
- Ref<T> node;
- node.instantiate();
- return node;
-}
-
-#endif // VISUAL_SCRIPT_H
diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp
deleted file mode 100644
index 44e792869d..0000000000
--- a/modules/visual_script/visual_script_builtin_funcs.cpp
+++ /dev/null
@@ -1,1380 +0,0 @@
-/*************************************************************************/
-/* visual_script_builtin_funcs.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "visual_script_builtin_funcs.h"
-
-#include "core/io/marshalls.h"
-#include "core/math/math_funcs.h"
-#include "core/object/class_db.h"
-#include "core/object/ref_counted.h"
-#include "core/os/os.h"
-#include "core/variant/variant_parser.h"
-
-const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX] = {
- "sin",
- "cos",
- "tan",
- "sinh",
- "cosh",
- "tanh",
- "asin",
- "acos",
- "atan",
- "atan2",
- "sqrt",
- "fmod",
- "fposmod",
- "floor",
- "ceil",
- "round",
- "abs",
- "sign",
- "pow",
- "log",
- "exp",
- "is_nan",
- "is_inf",
- "ease",
- "step_decimals",
- "snapped",
- "lerp",
- "cubic_interpolate",
- "inverse_lerp",
- "range_lerp",
- "move_toward",
- "randomize",
- "randi",
- "randf",
- "randi_range",
- "randf_range",
- "randfn",
- "seed",
- "rand_seed",
- "deg2rad",
- "rad2deg",
- "linear2db",
- "db2linear",
- "wrapi",
- "wrapf",
- "pingpong",
- "max",
- "min",
- "clamp",
- "nearest_po2",
- "weakref",
- "convert",
- "typeof",
- "type_exists",
- "char",
- "str",
- "print",
- "printerr",
- "printraw",
- "print_verbose",
- "var2str",
- "str2var",
- "var2bytes",
- "bytes2var",
- "smoothstep",
- "posmod",
- "lerp_angle",
- "ord",
-};
-
-VisualScriptBuiltinFunc::BuiltinFunc VisualScriptBuiltinFunc::find_function(const String &p_string) {
- for (int i = 0; i < FUNC_MAX; i++) {
- if (p_string == func_name[i]) {
- return BuiltinFunc(i);
- }
- }
-
- return FUNC_MAX;
-}
-
-String VisualScriptBuiltinFunc::get_func_name(BuiltinFunc p_func) {
- ERR_FAIL_INDEX_V(p_func, FUNC_MAX, String());
- return func_name[p_func];
-}
-
-int VisualScriptBuiltinFunc::get_output_sequence_port_count() const {
- return has_input_sequence_port() ? 1 : 0;
-}
-
-bool VisualScriptBuiltinFunc::has_input_sequence_port() const {
- switch (func) {
- case MATH_RANDOMIZE:
- case TEXT_PRINT:
- case TEXT_PRINTERR:
- case TEXT_PRINTRAW:
- case TEXT_PRINT_VERBOSE:
- case MATH_SEED:
- return true;
- default:
- return false;
- }
-}
-
-int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) {
- switch (p_func) {
- case MATH_RANDOMIZE:
- case MATH_RANDI:
- case MATH_RANDF:
- return 0;
- case MATH_SIN:
- case MATH_COS:
- case MATH_TAN:
- case MATH_SINH:
- case MATH_COSH:
- case MATH_TANH:
- case MATH_ASIN:
- case MATH_ACOS:
- case MATH_ATAN:
- case MATH_SQRT:
- case MATH_FLOOR:
- case MATH_CEIL:
- case MATH_ROUND:
- case MATH_ABS:
- case MATH_SIGN:
- case MATH_LOG:
- case MATH_EXP:
- case MATH_ISNAN:
- case MATH_ISINF:
- case MATH_STEP_DECIMALS:
- case MATH_SEED:
- case MATH_RANDSEED:
- case MATH_DEG2RAD:
- case MATH_RAD2DEG:
- case MATH_LINEAR2DB:
- case MATH_DB2LINEAR:
- case LOGIC_NEAREST_PO2:
- case OBJ_WEAKREF:
- case TYPE_OF:
- case TEXT_CHAR:
- case TEXT_ORD:
- case TEXT_STR:
- case TEXT_PRINT:
- case TEXT_PRINTERR:
- case TEXT_PRINTRAW:
- case TEXT_PRINT_VERBOSE:
- case VAR_TO_STR:
- case STR_TO_VAR:
- case TYPE_EXISTS:
- return 1;
- case VAR_TO_BYTES:
- case BYTES_TO_VAR:
- case MATH_ATAN2:
- case MATH_FMOD:
- case MATH_FPOSMOD:
- case MATH_POSMOD:
- case MATH_PINGPONG:
- case MATH_POW:
- case MATH_EASE:
- case MATH_SNAPPED:
- case MATH_RANDI_RANGE:
- case MATH_RANDF_RANGE:
- case MATH_RANDFN:
- case LOGIC_MAX:
- case LOGIC_MIN:
- case TYPE_CONVERT:
- return 2;
- case MATH_LERP:
- case MATH_LERP_ANGLE:
- case MATH_INVERSE_LERP:
- case MATH_SMOOTHSTEP:
- case MATH_MOVE_TOWARD:
- case MATH_WRAP:
- case MATH_WRAPF:
- case LOGIC_CLAMP:
- return 3;
- case MATH_CUBIC_INTERPOLATE:
- case MATH_RANGE_LERP:
- return 5;
- case FUNC_MAX: {
- }
- }
- return 0;
-}
-
-int VisualScriptBuiltinFunc::get_input_value_port_count() const {
- return get_func_argument_count(func);
-}
-
-int VisualScriptBuiltinFunc::get_output_value_port_count() const {
- switch (func) {
- case MATH_RANDOMIZE:
- case TEXT_PRINT:
- case TEXT_PRINTERR:
- case TEXT_PRINTRAW:
- case TEXT_PRINT_VERBOSE:
- case MATH_SEED:
- return 0;
- case MATH_RANDSEED:
- return 2;
- default:
- return 1;
- }
-
- return 1;
-}
-
-String VisualScriptBuiltinFunc::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const {
- switch (func) {
- case MATH_SIN:
- case MATH_COS:
- case MATH_TAN:
- case MATH_SINH:
- case MATH_COSH:
- case MATH_TANH:
- case MATH_ASIN:
- case MATH_ACOS:
- case MATH_ATAN:
- case MATH_SQRT:
- case MATH_FLOOR:
- case MATH_CEIL:
- case MATH_ROUND:
- case MATH_ABS:
- case MATH_SIGN:
- case MATH_LOG:
- case MATH_EXP:
- case MATH_ISNAN:
- case MATH_ISINF: {
- return PropertyInfo(Variant::FLOAT, "s");
- } break;
- case MATH_ATAN2: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::FLOAT, "y");
- } else {
- return PropertyInfo(Variant::FLOAT, "x");
- }
- } break;
- case MATH_FMOD:
- case MATH_FPOSMOD:
- case LOGIC_MAX:
- case LOGIC_MIN: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::FLOAT, "a");
- } else {
- return PropertyInfo(Variant::FLOAT, "b");
- }
- } break;
- case MATH_POSMOD: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::INT, "a");
- } else {
- return PropertyInfo(Variant::INT, "b");
- }
- } break;
- case MATH_POW: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::FLOAT, "base");
- } else {
- return PropertyInfo(Variant::FLOAT, "exp");
- }
- } break;
- case MATH_EASE: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::FLOAT, "s");
- } else {
- return PropertyInfo(Variant::FLOAT, "curve");
- }
- } break;
- case MATH_STEP_DECIMALS: {
- return PropertyInfo(Variant::FLOAT, "step");
- } break;
- case MATH_SNAPPED: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::FLOAT, "s");
- } else {
- return PropertyInfo(Variant::FLOAT, "steps");
- }
- } break;
- case MATH_LERP:
- case MATH_LERP_ANGLE:
- case MATH_INVERSE_LERP:
- case MATH_SMOOTHSTEP: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::FLOAT, "from");
- } else if (p_idx == 1) {
- return PropertyInfo(Variant::FLOAT, "to");
- } else {
- return PropertyInfo(Variant::FLOAT, "weight");
- }
- } break;
- case MATH_CUBIC_INTERPOLATE: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::FLOAT, "from");
- } else if (p_idx == 1) {
- return PropertyInfo(Variant::FLOAT, "to");
- } else if (p_idx == 2) {
- return PropertyInfo(Variant::FLOAT, "pre");
- } else if (p_idx == 3) {
- return PropertyInfo(Variant::FLOAT, "post");
- } else {
- return PropertyInfo(Variant::FLOAT, "weight");
- }
- } break;
- case MATH_RANGE_LERP: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::FLOAT, "value");
- } else if (p_idx == 1) {
- return PropertyInfo(Variant::FLOAT, "istart");
- } else if (p_idx == 2) {
- return PropertyInfo(Variant::FLOAT, "istop");
- } else if (p_idx == 3) {
- return PropertyInfo(Variant::FLOAT, "ostart");
- } else {
- return PropertyInfo(Variant::FLOAT, "ostop");
- }
- } break;
- case MATH_MOVE_TOWARD: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::FLOAT, "from");
- } else if (p_idx == 1) {
- return PropertyInfo(Variant::FLOAT, "to");
- } else {
- return PropertyInfo(Variant::FLOAT, "delta");
- }
- } break;
- case MATH_RANDOMIZE:
- case MATH_RANDI:
- case MATH_RANDF: {
- } break;
- case MATH_RANDI_RANGE: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::INT, "from");
- } else {
- return PropertyInfo(Variant::INT, "to");
- }
- } break;
- case MATH_RANDF_RANGE: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::FLOAT, "from");
- } else {
- return PropertyInfo(Variant::FLOAT, "to");
- }
- } break;
- case MATH_RANDFN: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::FLOAT, "mean");
- } else {
- return PropertyInfo(Variant::FLOAT, "deviation");
- }
- } break;
- case MATH_SEED:
- case MATH_RANDSEED: {
- return PropertyInfo(Variant::INT, "seed");
- } break;
- case MATH_DEG2RAD: {
- return PropertyInfo(Variant::FLOAT, "deg");
- } break;
- case MATH_RAD2DEG: {
- return PropertyInfo(Variant::FLOAT, "rad");
- } break;
- case MATH_LINEAR2DB: {
- return PropertyInfo(Variant::FLOAT, "nrg");
- } break;
- case MATH_DB2LINEAR: {
- return PropertyInfo(Variant::FLOAT, "db");
- } break;
- case MATH_PINGPONG: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::FLOAT, "value");
- } else {
- return PropertyInfo(Variant::FLOAT, "length");
- }
- } break;
- case MATH_WRAP: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::INT, "value");
- } else if (p_idx == 1) {
- return PropertyInfo(Variant::INT, "min");
- } else {
- return PropertyInfo(Variant::INT, "max");
- }
- } break;
- case MATH_WRAPF:
- case LOGIC_CLAMP: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::FLOAT, "value");
- } else if (p_idx == 1) {
- return PropertyInfo(Variant::FLOAT, "min");
- } else {
- return PropertyInfo(Variant::FLOAT, "max");
- }
- } break;
- case LOGIC_NEAREST_PO2: {
- return PropertyInfo(Variant::INT, "value");
- } break;
- case OBJ_WEAKREF: {
- return PropertyInfo(Variant::OBJECT, "source");
- } break;
- case TYPE_CONVERT: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::NIL, "what");
- } else {
- return PropertyInfo(Variant::STRING, "type");
- }
- } break;
- case TYPE_OF: {
- return PropertyInfo(Variant::NIL, "what");
- } break;
- case TYPE_EXISTS: {
- return PropertyInfo(Variant::STRING, "type");
- } break;
- case TEXT_ORD: {
- return PropertyInfo(Variant::STRING, "character");
- } break;
- case TEXT_CHAR: {
- return PropertyInfo(Variant::INT, "ascii");
- } break;
- case TEXT_STR:
- case TEXT_PRINT:
- case TEXT_PRINTERR:
- case TEXT_PRINTRAW:
- case TEXT_PRINT_VERBOSE: {
- return PropertyInfo(Variant::NIL, "value");
- } break;
- case STR_TO_VAR: {
- return PropertyInfo(Variant::STRING, "string");
- } break;
- case VAR_TO_STR:
- case VAR_TO_BYTES: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::NIL, "var");
- } else {
- return PropertyInfo(Variant::BOOL, "full_objects");
- }
-
- } break;
- case BYTES_TO_VAR: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::PACKED_BYTE_ARRAY, "bytes");
- } else {
- return PropertyInfo(Variant::BOOL, "allow_objects");
- }
- } break;
- case FUNC_MAX: {
- }
- }
-
- return PropertyInfo();
-}
-
-PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) const {
- Variant::Type t = Variant::NIL;
- switch (func) {
- case MATH_SIN:
- case MATH_COS:
- case MATH_TAN:
- case MATH_SINH:
- case MATH_COSH:
- case MATH_TANH:
- case MATH_ASIN:
- case MATH_ACOS:
- case MATH_ATAN:
- case MATH_ATAN2:
- case MATH_SQRT:
- case MATH_FMOD:
- case MATH_FPOSMOD:
- case MATH_FLOOR:
- case MATH_CEIL: {
- t = Variant::FLOAT;
- } break;
- case MATH_POSMOD: {
- t = Variant::INT;
- } break;
- case MATH_ROUND: {
- t = Variant::FLOAT;
- } break;
- case MATH_ABS: {
- t = Variant::NIL;
- } break;
- case MATH_SIGN: {
- t = Variant::NIL;
- } break;
- case MATH_POW:
- case MATH_LOG:
- case MATH_EXP: {
- t = Variant::FLOAT;
- } break;
- case MATH_ISNAN:
- case MATH_ISINF: {
- t = Variant::BOOL;
- } break;
- case MATH_EASE: {
- t = Variant::FLOAT;
- } break;
- case MATH_STEP_DECIMALS: {
- t = Variant::INT;
- } break;
- case MATH_SNAPPED:
- case MATH_LERP:
- case MATH_CUBIC_INTERPOLATE:
- case MATH_LERP_ANGLE:
- case MATH_INVERSE_LERP:
- case MATH_RANGE_LERP:
- case MATH_SMOOTHSTEP:
- case MATH_MOVE_TOWARD:
- case MATH_RANDOMIZE: {
- } break;
- case MATH_RANDI: {
- t = Variant::INT;
- } break;
- case MATH_RANDF:
- case MATH_RANDFN:
- case MATH_RANDF_RANGE: {
- t = Variant::FLOAT;
- } break;
- case MATH_RANDI_RANGE: {
- t = Variant::INT;
- } break;
- case MATH_SEED: {
- } break;
- case MATH_RANDSEED: {
- if (p_idx == 0) {
- return PropertyInfo(Variant::INT, "rnd");
- } else {
- return PropertyInfo(Variant::INT, "seed");
- }
- } break;
- case MATH_DEG2RAD:
- case MATH_RAD2DEG:
- case MATH_LINEAR2DB:
- case MATH_WRAPF:
- case MATH_PINGPONG:
- case MATH_DB2LINEAR: {
- t = Variant::FLOAT;
- } break;
- case MATH_WRAP: {
- t = Variant::INT;
- } break;
- case LOGIC_MAX:
- case LOGIC_MIN:
- case LOGIC_CLAMP: {
- } break;
-
- case LOGIC_NEAREST_PO2: {
- t = Variant::NIL;
- } break;
- case OBJ_WEAKREF: {
- t = Variant::OBJECT;
-
- } break;
- case TYPE_CONVERT: {
- } break;
- case TEXT_ORD:
- case TYPE_OF: {
- t = Variant::INT;
-
- } break;
- case TYPE_EXISTS: {
- t = Variant::BOOL;
-
- } break;
- case TEXT_CHAR:
- case TEXT_STR: {
- t = Variant::STRING;
-
- } break;
- case TEXT_PRINT: {
- } break;
- case TEXT_PRINTERR: {
- } break;
- case TEXT_PRINTRAW: {
- } break;
- case TEXT_PRINT_VERBOSE: {
- } break;
- case VAR_TO_STR: {
- t = Variant::STRING;
- } break;
- case STR_TO_VAR: {
- } break;
- case VAR_TO_BYTES: {
- if (p_idx == 0) {
- t = Variant::PACKED_BYTE_ARRAY;
- } else {
- t = Variant::BOOL;
- }
-
- } break;
- case BYTES_TO_VAR: {
- if (p_idx == 1) {
- t = Variant::BOOL;
- }
- } break;
- case FUNC_MAX: {
- }
- }
-
- return PropertyInfo(t, "");
-}
-
-/*
-String VisualScriptBuiltinFunc::get_caption() const {
- return "BuiltinFunc";
-}
-
-*/
-
-String VisualScriptBuiltinFunc::get_caption() const {
- return func_name[func];
-}
-
-void VisualScriptBuiltinFunc::set_func(BuiltinFunc p_which) {
- ERR_FAIL_INDEX(p_which, FUNC_MAX);
- func = p_which;
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-VisualScriptBuiltinFunc::BuiltinFunc VisualScriptBuiltinFunc::get_func() {
- return func;
-}
-
-#define VALIDATE_ARG_NUM(m_arg) \
- if (!p_inputs[m_arg]->is_num()) { \
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \
- r_error.argument = m_arg; \
- r_error.expected = Variant::FLOAT; \
- return; \
- }
-
-void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant *r_return, Callable::CallError &r_error, String &r_error_str) {
- switch (p_func) {
- case VisualScriptBuiltinFunc::MATH_SIN: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::sin((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_COS: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::cos((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_TAN: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::tan((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_SINH: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::sinh((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_COSH: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::cosh((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_TANH: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::tanh((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_ASIN: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::asin((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_ACOS: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::acos((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_ATAN: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::atan((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_ATAN2: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- *r_return = Math::atan2((double)*p_inputs[0], (double)*p_inputs[1]);
- } break;
- case VisualScriptBuiltinFunc::MATH_SQRT: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::sqrt((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_FMOD: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- *r_return = Math::fmod((double)*p_inputs[0], (double)*p_inputs[1]);
- } break;
- case VisualScriptBuiltinFunc::MATH_FPOSMOD: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- *r_return = Math::fposmod((double)*p_inputs[0], (double)*p_inputs[1]);
- } break;
- case VisualScriptBuiltinFunc::MATH_POSMOD: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- *r_return = Math::posmod((int64_t)*p_inputs[0], (int64_t)*p_inputs[1]);
- } break;
- case VisualScriptBuiltinFunc::MATH_FLOOR: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::floor((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_CEIL: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::ceil((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_ROUND: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::round((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_ABS: {
- if (p_inputs[0]->get_type() == Variant::INT) {
- int64_t i = *p_inputs[0];
- *r_return = ABS(i);
- } else if (p_inputs[0]->get_type() == Variant::FLOAT) {
- real_t r = *p_inputs[0];
- *r_return = Math::abs(r);
- } else {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::FLOAT;
- }
- } break;
- case VisualScriptBuiltinFunc::MATH_SIGN: {
- if (p_inputs[0]->get_type() == Variant::INT) {
- int64_t i = *p_inputs[0];
- *r_return = i < 0 ? -1 : (i > 0 ? +1 : 0);
- } else if (p_inputs[0]->get_type() == Variant::FLOAT) {
- real_t r = *p_inputs[0];
- *r_return = r < 0.0 ? -1.0 : (r > 0.0 ? +1.0 : 0.0);
- } else {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::FLOAT;
- }
- } break;
- case VisualScriptBuiltinFunc::MATH_POW: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- *r_return = Math::pow((double)*p_inputs[0], (double)*p_inputs[1]);
- } break;
- case VisualScriptBuiltinFunc::MATH_LOG: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::log((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_EXP: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::exp((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_ISNAN: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::is_nan((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_ISINF: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::is_inf((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_EASE: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- *r_return = Math::ease((double)*p_inputs[0], (double)*p_inputs[1]);
- } break;
- case VisualScriptBuiltinFunc::MATH_STEP_DECIMALS: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::step_decimals((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_SNAPPED: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- *r_return = Math::snapped((double)*p_inputs[0], (double)*p_inputs[1]);
- } break;
- case VisualScriptBuiltinFunc::MATH_LERP: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- *r_return = Math::lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
- } break;
- case VisualScriptBuiltinFunc::MATH_CUBIC_INTERPOLATE: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- VALIDATE_ARG_NUM(3);
- VALIDATE_ARG_NUM(4);
- *r_return = Math::cubic_interpolate((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2], (double)*p_inputs[3], (double)*p_inputs[4]);
- } break;
- case VisualScriptBuiltinFunc::MATH_LERP_ANGLE: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- *r_return = Math::lerp_angle((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
- } break;
- case VisualScriptBuiltinFunc::MATH_INVERSE_LERP: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- *r_return = Math::inverse_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
- } break;
- case VisualScriptBuiltinFunc::MATH_RANGE_LERP: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- VALIDATE_ARG_NUM(3);
- VALIDATE_ARG_NUM(4);
- *r_return = Math::range_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2], (double)*p_inputs[3], (double)*p_inputs[4]);
- } break;
- case VisualScriptBuiltinFunc::MATH_SMOOTHSTEP: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- *r_return = Math::smoothstep((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
- } break;
- case VisualScriptBuiltinFunc::MATH_MOVE_TOWARD: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- *r_return = Math::move_toward((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
- } break;
- case VisualScriptBuiltinFunc::MATH_RANDOMIZE: {
- Math::randomize();
-
- } break;
- case VisualScriptBuiltinFunc::MATH_RANDI: {
- *r_return = Math::rand();
- } break;
- case VisualScriptBuiltinFunc::MATH_RANDF: {
- *r_return = Math::randf();
- } break;
- case VisualScriptBuiltinFunc::MATH_RANDI_RANGE: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- *r_return = Math::random((int)*p_inputs[0], (int)*p_inputs[1]);
- } break;
- case VisualScriptBuiltinFunc::MATH_RANDF_RANGE: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- *r_return = Math::random((double)*p_inputs[0], (double)*p_inputs[1]);
- } break;
- case VisualScriptBuiltinFunc::MATH_RANDFN: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- *r_return = Math::randfn((double)*p_inputs[0], (double)*p_inputs[1]);
- } break;
- case VisualScriptBuiltinFunc::MATH_SEED: {
- VALIDATE_ARG_NUM(0);
- uint64_t seed = *p_inputs[0];
- Math::seed(seed);
-
- } break;
- case VisualScriptBuiltinFunc::MATH_RANDSEED: {
- VALIDATE_ARG_NUM(0);
- uint64_t seed = *p_inputs[0];
- int ret = Math::rand_from_seed(&seed);
- Array reta;
- reta.push_back(ret);
- reta.push_back(seed);
- *r_return = reta;
-
- } break;
- case VisualScriptBuiltinFunc::MATH_DEG2RAD: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::deg2rad((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_RAD2DEG: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::rad2deg((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_LINEAR2DB: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::linear2db((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_DB2LINEAR: {
- VALIDATE_ARG_NUM(0);
- *r_return = Math::db2linear((double)*p_inputs[0]);
- } break;
- case VisualScriptBuiltinFunc::MATH_PINGPONG: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- *r_return = Math::pingpong((double)*p_inputs[0], (double)*p_inputs[1]);
- } break;
- case VisualScriptBuiltinFunc::MATH_WRAP: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- *r_return = Math::wrapi((int64_t)*p_inputs[0], (int64_t)*p_inputs[1], (int64_t)*p_inputs[2]);
- } break;
- case VisualScriptBuiltinFunc::MATH_WRAPF: {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
- *r_return = Math::wrapf((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
- } break;
- case VisualScriptBuiltinFunc::LOGIC_MAX: {
- if (p_inputs[0]->get_type() == Variant::INT && p_inputs[1]->get_type() == Variant::INT) {
- int64_t a = *p_inputs[0];
- int64_t b = *p_inputs[1];
- *r_return = MAX(a, b);
- } else {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
-
- real_t a = *p_inputs[0];
- real_t b = *p_inputs[1];
-
- *r_return = MAX(a, b);
- }
-
- } break;
- case VisualScriptBuiltinFunc::LOGIC_MIN: {
- if (p_inputs[0]->get_type() == Variant::INT && p_inputs[1]->get_type() == Variant::INT) {
- int64_t a = *p_inputs[0];
- int64_t b = *p_inputs[1];
- *r_return = MIN(a, b);
- } else {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
-
- real_t a = *p_inputs[0];
- real_t b = *p_inputs[1];
-
- *r_return = MIN(a, b);
- }
- } break;
- case VisualScriptBuiltinFunc::LOGIC_CLAMP: {
- if (p_inputs[0]->get_type() == Variant::INT && p_inputs[1]->get_type() == Variant::INT && p_inputs[2]->get_type() == Variant::INT) {
- int64_t a = *p_inputs[0];
- int64_t b = *p_inputs[1];
- int64_t c = *p_inputs[2];
- *r_return = CLAMP(a, b, c);
- } else {
- VALIDATE_ARG_NUM(0);
- VALIDATE_ARG_NUM(1);
- VALIDATE_ARG_NUM(2);
-
- real_t a = *p_inputs[0];
- real_t b = *p_inputs[1];
- real_t c = *p_inputs[2];
-
- *r_return = CLAMP(a, b, c);
- }
- } break;
- case VisualScriptBuiltinFunc::LOGIC_NEAREST_PO2: {
- VALIDATE_ARG_NUM(0);
- int64_t num = *p_inputs[0];
- *r_return = next_power_of_2(num);
- } break;
- case VisualScriptBuiltinFunc::OBJ_WEAKREF: {
- if (p_inputs[0]->get_type() != Variant::OBJECT) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::OBJECT;
-
- return;
- }
-
- if (p_inputs[0]->is_ref_counted()) {
- Ref<RefCounted> r = *p_inputs[0];
- if (!r.is_valid()) {
- return;
- }
-
- Ref<WeakRef> wref = memnew(WeakRef);
- wref->set_ref(r);
- *r_return = wref;
- } else {
- Object *obj = *p_inputs[0];
- if (!obj) {
- return;
- }
- Ref<WeakRef> wref = memnew(WeakRef);
- wref->set_obj(obj);
- *r_return = wref;
- }
-
- } break;
- case VisualScriptBuiltinFunc::TYPE_CONVERT: {
- VALIDATE_ARG_NUM(1);
- int type = *p_inputs[1];
- if (type < 0 || type >= Variant::VARIANT_MAX) {
- r_error_str = RTR("Invalid type argument to convert(), use TYPE_* constants.");
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::INT;
- return;
-
- } else {
- Variant::construct(Variant::Type(type), *r_return, p_inputs, 1, r_error);
- }
- } break;
- case VisualScriptBuiltinFunc::TYPE_OF: {
- *r_return = p_inputs[0]->get_type();
-
- } break;
- case VisualScriptBuiltinFunc::TYPE_EXISTS: {
- *r_return = ClassDB::class_exists(*p_inputs[0]);
-
- } break;
- case VisualScriptBuiltinFunc::TEXT_CHAR: {
- char32_t result[2] = { *p_inputs[0], 0 };
-
- *r_return = String(result);
-
- } break;
- case VisualScriptBuiltinFunc::TEXT_ORD: {
- if (p_inputs[0]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
-
- return;
- }
-
- String str = p_inputs[0]->operator String();
-
- if (str.length() != 1) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- *r_return = "Expected a string of length 1 (a character).";
-
- return;
- }
-
- *r_return = str.get(0);
-
- } break;
- case VisualScriptBuiltinFunc::TEXT_STR: {
- String str = *p_inputs[0];
-
- *r_return = str;
-
- } break;
- case VisualScriptBuiltinFunc::TEXT_PRINT: {
- String str = *p_inputs[0];
- print_line(str);
-
- } break;
-
- case VisualScriptBuiltinFunc::TEXT_PRINTERR: {
- String str = *p_inputs[0];
- print_error(str);
-
- } break;
- case VisualScriptBuiltinFunc::TEXT_PRINTRAW: {
- String str = *p_inputs[0];
- OS::get_singleton()->print("%s", str.utf8().get_data());
-
- } break;
- case VisualScriptBuiltinFunc::TEXT_PRINT_VERBOSE: {
- String str = *p_inputs[0];
- print_verbose(str);
- } break;
- case VisualScriptBuiltinFunc::VAR_TO_STR: {
- String vars;
- VariantWriter::write_to_string(*p_inputs[0], vars);
- *r_return = vars;
- } break;
- case VisualScriptBuiltinFunc::STR_TO_VAR: {
- if (p_inputs[0]->get_type() != Variant::STRING) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
-
- return;
- }
-
- VariantParser::StreamString ss;
- ss.s = *p_inputs[0];
-
- String errs;
- int line;
- Error err = VariantParser::parse(&ss, *r_return, errs, line);
-
- if (err != OK) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::STRING;
- *r_return = "Parse error at line " + itos(line) + ": " + errs;
- return;
- }
-
- } break;
- case VisualScriptBuiltinFunc::VAR_TO_BYTES: {
- if (p_inputs[1]->get_type() != Variant::BOOL) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::BOOL;
- return;
- }
- PackedByteArray barr;
- int len;
- bool full_objects = *p_inputs[1];
- Error err = encode_variant(*p_inputs[0], nullptr, len, full_objects);
- if (err) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::NIL;
- r_error_str = "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).";
- return;
- }
-
- barr.resize(len);
- {
- uint8_t *w = barr.ptrw();
- encode_variant(*p_inputs[0], w, len, full_objects);
- }
- *r_return = barr;
- } break;
- case VisualScriptBuiltinFunc::BYTES_TO_VAR: {
- if (p_inputs[0]->get_type() != Variant::PACKED_BYTE_ARRAY) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::PACKED_BYTE_ARRAY;
- return;
- }
- if (p_inputs[1]->get_type() != Variant::BOOL) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 1;
- r_error.expected = Variant::BOOL;
- return;
- }
-
- PackedByteArray varr = *p_inputs[0];
- bool allow_objects = *p_inputs[1];
- Variant ret;
- {
- const uint8_t *r = varr.ptr();
- Error err = decode_variant(ret, r, varr.size(), nullptr, allow_objects);
- if (err != OK) {
- r_error_str = RTR("Not enough bytes for decoding bytes, or invalid format.");
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
- r_error.expected = Variant::PACKED_BYTE_ARRAY;
- return;
- }
- }
-
- *r_return = ret;
-
- } break;
- default: {
- }
- }
-}
-
-class VisualScriptNodeInstanceBuiltinFunc : public VisualScriptNodeInstance {
-public:
- VisualScriptBuiltinFunc *node = nullptr;
- VisualScriptInstance *instance = nullptr;
-
- VisualScriptBuiltinFunc::BuiltinFunc func;
-
- //virtual int get_working_memory_size() const override { return 0; }
- //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
- //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- VisualScriptBuiltinFunc::exec_func(func, p_inputs, p_outputs[0], r_error, r_error_str);
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptBuiltinFunc::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceBuiltinFunc *instance = memnew(VisualScriptNodeInstanceBuiltinFunc);
- instance->node = this;
- instance->instance = p_instance;
- instance->func = func;
- return instance;
-}
-
-void VisualScriptBuiltinFunc::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_func", "which"), &VisualScriptBuiltinFunc::set_func);
- ClassDB::bind_method(D_METHOD("get_func"), &VisualScriptBuiltinFunc::get_func);
-
- String cc;
-
- for (int i = 0; i < FUNC_MAX; i++) {
- if (i > 0) {
- cc += ",";
- }
- cc += func_name[i];
- }
- ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, cc), "set_func", "get_func");
-
- BIND_ENUM_CONSTANT(MATH_SIN);
- BIND_ENUM_CONSTANT(MATH_COS);
- BIND_ENUM_CONSTANT(MATH_TAN);
- BIND_ENUM_CONSTANT(MATH_SINH);
- BIND_ENUM_CONSTANT(MATH_COSH);
- BIND_ENUM_CONSTANT(MATH_TANH);
- BIND_ENUM_CONSTANT(MATH_ASIN);
- BIND_ENUM_CONSTANT(MATH_ACOS);
- BIND_ENUM_CONSTANT(MATH_ATAN);
- BIND_ENUM_CONSTANT(MATH_ATAN2);
- BIND_ENUM_CONSTANT(MATH_SQRT);
- BIND_ENUM_CONSTANT(MATH_FMOD);
- BIND_ENUM_CONSTANT(MATH_FPOSMOD);
- BIND_ENUM_CONSTANT(MATH_FLOOR);
- BIND_ENUM_CONSTANT(MATH_CEIL);
- BIND_ENUM_CONSTANT(MATH_ROUND);
- BIND_ENUM_CONSTANT(MATH_ABS);
- BIND_ENUM_CONSTANT(MATH_SIGN);
- BIND_ENUM_CONSTANT(MATH_POW);
- BIND_ENUM_CONSTANT(MATH_LOG);
- BIND_ENUM_CONSTANT(MATH_EXP);
- BIND_ENUM_CONSTANT(MATH_ISNAN);
- BIND_ENUM_CONSTANT(MATH_ISINF);
- BIND_ENUM_CONSTANT(MATH_EASE);
- BIND_ENUM_CONSTANT(MATH_STEP_DECIMALS);
- BIND_ENUM_CONSTANT(MATH_SNAPPED);
- BIND_ENUM_CONSTANT(MATH_LERP);
- BIND_ENUM_CONSTANT(MATH_CUBIC_INTERPOLATE);
- BIND_ENUM_CONSTANT(MATH_INVERSE_LERP);
- BIND_ENUM_CONSTANT(MATH_RANGE_LERP);
- BIND_ENUM_CONSTANT(MATH_MOVE_TOWARD);
- BIND_ENUM_CONSTANT(MATH_RANDOMIZE);
- BIND_ENUM_CONSTANT(MATH_RANDI);
- BIND_ENUM_CONSTANT(MATH_RANDF);
- BIND_ENUM_CONSTANT(MATH_RANDI_RANGE);
- BIND_ENUM_CONSTANT(MATH_RANDF_RANGE);
- BIND_ENUM_CONSTANT(MATH_RANDFN);
- BIND_ENUM_CONSTANT(MATH_SEED);
- BIND_ENUM_CONSTANT(MATH_RANDSEED);
- BIND_ENUM_CONSTANT(MATH_DEG2RAD);
- BIND_ENUM_CONSTANT(MATH_RAD2DEG);
- BIND_ENUM_CONSTANT(MATH_LINEAR2DB);
- BIND_ENUM_CONSTANT(MATH_DB2LINEAR);
- BIND_ENUM_CONSTANT(MATH_WRAP);
- BIND_ENUM_CONSTANT(MATH_WRAPF);
- BIND_ENUM_CONSTANT(MATH_PINGPONG);
- BIND_ENUM_CONSTANT(LOGIC_MAX);
- BIND_ENUM_CONSTANT(LOGIC_MIN);
- BIND_ENUM_CONSTANT(LOGIC_CLAMP);
- BIND_ENUM_CONSTANT(LOGIC_NEAREST_PO2);
- BIND_ENUM_CONSTANT(OBJ_WEAKREF);
- BIND_ENUM_CONSTANT(TYPE_CONVERT);
- BIND_ENUM_CONSTANT(TYPE_OF);
- BIND_ENUM_CONSTANT(TYPE_EXISTS);
- BIND_ENUM_CONSTANT(TEXT_CHAR);
- BIND_ENUM_CONSTANT(TEXT_STR);
- BIND_ENUM_CONSTANT(TEXT_PRINT);
- BIND_ENUM_CONSTANT(TEXT_PRINTERR);
- BIND_ENUM_CONSTANT(TEXT_PRINTRAW);
- BIND_ENUM_CONSTANT(TEXT_PRINT_VERBOSE);
- BIND_ENUM_CONSTANT(VAR_TO_STR);
- BIND_ENUM_CONSTANT(STR_TO_VAR);
- BIND_ENUM_CONSTANT(VAR_TO_BYTES);
- BIND_ENUM_CONSTANT(BYTES_TO_VAR);
- BIND_ENUM_CONSTANT(MATH_SMOOTHSTEP);
- BIND_ENUM_CONSTANT(MATH_POSMOD);
- BIND_ENUM_CONSTANT(MATH_LERP_ANGLE);
- BIND_ENUM_CONSTANT(TEXT_ORD);
- BIND_ENUM_CONSTANT(FUNC_MAX);
-}
-
-VisualScriptBuiltinFunc::VisualScriptBuiltinFunc(VisualScriptBuiltinFunc::BuiltinFunc func) {
- this->func = func;
-}
-
-VisualScriptBuiltinFunc::VisualScriptBuiltinFunc() {
- func = MATH_SIN;
-}
-
-template <VisualScriptBuiltinFunc::BuiltinFunc func>
-static Ref<VisualScriptNode> create_builtin_func_node(const String &p_name) {
- Ref<VisualScriptBuiltinFunc> node = memnew(VisualScriptBuiltinFunc(func));
- return node;
-}
-
-void register_visual_script_builtin_func_node() {
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/sin", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SIN>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/cos", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_COS>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/tan", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_TAN>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/sinh", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SINH>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/cosh", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_COSH>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/tanh", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_TANH>);
-
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/asin", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ASIN>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/acos", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ACOS>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/atan", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ATAN>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/atan2", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ATAN2>);
-
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/sqrt", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SQRT>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/fmod", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FMOD>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/fposmod", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FPOSMOD>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/posmod", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_POSMOD>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/floor", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_FLOOR>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/ceil", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_CEIL>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/round", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ROUND>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/abs", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ABS>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/sign", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SIGN>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/pow", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_POW>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/log", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LOG>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/exp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_EXP>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/isnan", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ISNAN>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/isinf", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_ISINF>);
-
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/ease", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_EASE>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/step_decimals", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_STEP_DECIMALS>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/snapped", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SNAPPED>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LERP>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/cubic_interpolate", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_CUBIC_INTERPOLATE>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/lerp_angle", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LERP_ANGLE>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/inverse_lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_INVERSE_LERP>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/range_lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANGE_LERP>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/smoothstep", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SMOOTHSTEP>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/move_toward", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_MOVE_TOWARD>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/randomize", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDOMIZE>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/randi", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDI>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/randf", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDF>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/randi_range", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDI_RANGE>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/randf_range", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDF_RANGE>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/randfn", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDFN>);
-
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/seed", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SEED>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/randseed", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDSEED>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/deg2rad", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DEG2RAD>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/rad2deg", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RAD2DEG>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/linear2db", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LINEAR2DB>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/db2linear", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DB2LINEAR>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/wrapi", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_WRAP>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/wrapf", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_WRAPF>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/pingpong", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_PINGPONG>);
-
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/max", create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MAX>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/min", create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_MIN>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/clamp", create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_CLAMP>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/nearest_po2", create_builtin_func_node<VisualScriptBuiltinFunc::LOGIC_NEAREST_PO2>);
-
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/weakref", create_builtin_func_node<VisualScriptBuiltinFunc::OBJ_WEAKREF>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/convert", create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_CONVERT>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/typeof", create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_OF>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/type_exists", create_builtin_func_node<VisualScriptBuiltinFunc::TYPE_EXISTS>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/char", create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_CHAR>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/ord", create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_ORD>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/str", create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_STR>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/print", create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINT>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/printerr", create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINTERR>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/printraw", create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINTRAW>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/print_verbose", create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINT_VERBOSE>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/var2str", create_builtin_func_node<VisualScriptBuiltinFunc::VAR_TO_STR>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/str2var", create_builtin_func_node<VisualScriptBuiltinFunc::STR_TO_VAR>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/var2bytes", create_builtin_func_node<VisualScriptBuiltinFunc::VAR_TO_BYTES>);
- VisualScriptLanguage::singleton->add_register_func("functions/built_in/bytes2var", create_builtin_func_node<VisualScriptBuiltinFunc::BYTES_TO_VAR>);
-}
diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h
deleted file mode 100644
index 18935b9995..0000000000
--- a/modules/visual_script/visual_script_builtin_funcs.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*************************************************************************/
-/* visual_script_builtin_funcs.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef VISUAL_SCRIPT_BUILTIN_FUNCS_H
-#define VISUAL_SCRIPT_BUILTIN_FUNCS_H
-
-#include "visual_script.h"
-
-class VisualScriptBuiltinFunc : public VisualScriptNode {
- GDCLASS(VisualScriptBuiltinFunc, VisualScriptNode);
-
-public:
- enum BuiltinFunc {
- MATH_SIN,
- MATH_COS,
- MATH_TAN,
- MATH_SINH,
- MATH_COSH,
- MATH_TANH,
- MATH_ASIN,
- MATH_ACOS,
- MATH_ATAN,
- MATH_ATAN2,
- MATH_SQRT,
- MATH_FMOD,
- MATH_FPOSMOD,
- MATH_FLOOR,
- MATH_CEIL,
- MATH_ROUND,
- MATH_ABS,
- MATH_SIGN,
- MATH_POW,
- MATH_LOG,
- MATH_EXP,
- MATH_ISNAN,
- MATH_ISINF,
- MATH_EASE,
- MATH_STEP_DECIMALS,
- MATH_SNAPPED,
- MATH_LERP,
- MATH_CUBIC_INTERPOLATE,
- MATH_INVERSE_LERP,
- MATH_RANGE_LERP,
- MATH_MOVE_TOWARD,
- MATH_RANDOMIZE,
- MATH_RANDI,
- MATH_RANDF,
- MATH_RANDI_RANGE,
- MATH_RANDF_RANGE,
- MATH_RANDFN,
- MATH_SEED,
- MATH_RANDSEED,
- MATH_DEG2RAD,
- MATH_RAD2DEG,
- MATH_LINEAR2DB,
- MATH_DB2LINEAR,
- MATH_WRAP,
- MATH_WRAPF,
- MATH_PINGPONG,
- LOGIC_MAX,
- LOGIC_MIN,
- LOGIC_CLAMP,
- LOGIC_NEAREST_PO2,
- OBJ_WEAKREF,
- TYPE_CONVERT,
- TYPE_OF,
- TYPE_EXISTS,
- TEXT_CHAR,
- TEXT_STR,
- TEXT_PRINT,
- TEXT_PRINTERR,
- TEXT_PRINTRAW,
- TEXT_PRINT_VERBOSE,
- VAR_TO_STR,
- STR_TO_VAR,
- VAR_TO_BYTES,
- BYTES_TO_VAR,
- MATH_SMOOTHSTEP,
- MATH_POSMOD,
- MATH_LERP_ANGLE,
- TEXT_ORD,
- FUNC_MAX
- };
-
- static int get_func_argument_count(BuiltinFunc p_func);
- static String get_func_name(BuiltinFunc p_func);
- static void exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant *r_return, Callable::CallError &r_error, String &r_error_str);
- static BuiltinFunc find_function(const String &p_string);
-
-private:
- static const char *func_name[FUNC_MAX];
- BuiltinFunc func;
-
-protected:
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- //virtual String get_text() const;
- virtual String get_category() const override { return "functions"; }
-
- void set_func(BuiltinFunc p_which);
- BuiltinFunc get_func();
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptBuiltinFunc(VisualScriptBuiltinFunc::BuiltinFunc func);
- VisualScriptBuiltinFunc();
-};
-
-VARIANT_ENUM_CAST(VisualScriptBuiltinFunc::BuiltinFunc)
-
-void register_visual_script_builtin_func_node();
-
-#endif // VISUAL_SCRIPT_BUILTIN_FUNCS_H
diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp
deleted file mode 100644
index e0f6436094..0000000000
--- a/modules/visual_script/visual_script_expression.cpp
+++ /dev/null
@@ -1,1570 +0,0 @@
-/*************************************************************************/
-/* visual_script_expression.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "visual_script_expression.h"
-
-bool VisualScriptExpression::_set(const StringName &p_name, const Variant &p_value) {
- if (String(p_name) == "expression") {
- expression = p_value;
- expression_dirty = true;
- ports_changed_notify();
- return true;
- }
-
- if (String(p_name) == "out_type") {
- output_type = Variant::Type(int(p_value));
- expression_dirty = true;
- ports_changed_notify();
- return true;
- }
- if (String(p_name) == "sequenced") {
- sequenced = p_value;
- ports_changed_notify();
- return true;
- }
-
- if (String(p_name) == "input_count") {
- int from = inputs.size();
- inputs.resize(int(p_value));
- for (int i = from; i < inputs.size(); i++) {
- inputs.write[i].name = String::chr('a' + i);
- if (from == 0) {
- inputs.write[i].type = output_type;
- } else {
- inputs.write[i].type = inputs[from - 1].type;
- }
- }
- expression_dirty = true;
- ports_changed_notify();
- notify_property_list_changed();
- return true;
- }
-
- if (String(p_name).begins_with("input_")) {
- int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int();
- ERR_FAIL_INDEX_V(idx, inputs.size(), false);
-
- String what = String(p_name).get_slice("/", 1);
-
- if (what == "type") {
- inputs.write[idx].type = Variant::Type(int(p_value));
- } else if (what == "name") {
- inputs.write[idx].name = p_value;
- } else {
- return false;
- }
-
- expression_dirty = true;
- ports_changed_notify();
- return true;
- }
-
- return false;
-}
-
-bool VisualScriptExpression::_get(const StringName &p_name, Variant &r_ret) const {
- if (String(p_name) == "expression") {
- r_ret = expression;
- return true;
- }
-
- if (String(p_name) == "out_type") {
- r_ret = output_type;
- return true;
- }
-
- if (String(p_name) == "sequenced") {
- r_ret = sequenced;
- return true;
- }
-
- if (String(p_name) == "input_count") {
- r_ret = inputs.size();
- return true;
- }
-
- if (String(p_name).begins_with("input_")) {
- int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int();
- ERR_FAIL_INDEX_V(idx, inputs.size(), false);
-
- String what = String(p_name).get_slice("/", 1);
-
- if (what == "type") {
- r_ret = inputs[idx].type;
- } else if (what == "name") {
- r_ret = inputs[idx].name;
- } else {
- return false;
- }
-
- return true;
- }
-
- return false;
-}
-
-void VisualScriptExpression::_get_property_list(List<PropertyInfo> *p_list) const {
- String argt = "Any";
- for (int i = 1; i < Variant::VARIANT_MAX; i++) {
- argt += "," + Variant::get_type_name(Variant::Type(i));
- }
-
- p_list->push_back(PropertyInfo(Variant::STRING, "expression", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
- p_list->push_back(PropertyInfo(Variant::INT, "out_type", PROPERTY_HINT_ENUM, argt));
- p_list->push_back(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,64,1"));
- p_list->push_back(PropertyInfo(Variant::BOOL, "sequenced"));
-
- for (int i = 0; i < inputs.size(); i++) {
- p_list->push_back(PropertyInfo(Variant::INT, "input_" + itos(i) + "/type", PROPERTY_HINT_ENUM, argt));
- p_list->push_back(PropertyInfo(Variant::STRING, "input_" + itos(i) + "/name"));
- }
-}
-
-int VisualScriptExpression::get_output_sequence_port_count() const {
- return sequenced ? 1 : 0;
-}
-
-bool VisualScriptExpression::has_input_sequence_port() const {
- return sequenced;
-}
-
-String VisualScriptExpression::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-int VisualScriptExpression::get_input_value_port_count() const {
- return inputs.size();
-}
-
-int VisualScriptExpression::get_output_value_port_count() const {
- return 1;
-}
-
-PropertyInfo VisualScriptExpression::get_input_value_port_info(int p_idx) const {
- return PropertyInfo(inputs[p_idx].type, inputs[p_idx].name);
-}
-
-PropertyInfo VisualScriptExpression::get_output_value_port_info(int p_idx) const {
- return PropertyInfo(output_type, "result");
-}
-
-String VisualScriptExpression::get_caption() const {
- return RTR("Expression");
-}
-
-String VisualScriptExpression::get_text() const {
- return expression;
-}
-
-Error VisualScriptExpression::_get_token(Token &r_token) {
- while (true) {
-#define GET_CHAR() (str_ofs >= expression.length() ? 0 : expression[str_ofs++])
-
- char32_t cchar = GET_CHAR();
- if (cchar == 0) {
- r_token.type = TK_EOF;
- return OK;
- }
-
- switch (cchar) {
- case 0: {
- r_token.type = TK_EOF;
- return OK;
- } break;
- case '{': {
- r_token.type = TK_CURLY_BRACKET_OPEN;
- return OK;
- };
- case '}': {
- r_token.type = TK_CURLY_BRACKET_CLOSE;
- return OK;
- };
- case '[': {
- r_token.type = TK_BRACKET_OPEN;
- return OK;
- };
- case ']': {
- r_token.type = TK_BRACKET_CLOSE;
- return OK;
- };
- case '(': {
- r_token.type = TK_PARENTHESIS_OPEN;
- return OK;
- };
- case ')': {
- r_token.type = TK_PARENTHESIS_CLOSE;
- return OK;
- };
- case ',': {
- r_token.type = TK_COMMA;
- return OK;
- };
- case ':': {
- r_token.type = TK_COLON;
- return OK;
- };
- case '.': {
- r_token.type = TK_PERIOD;
- return OK;
- };
- case '=': {
- cchar = GET_CHAR();
- if (cchar == '=') {
- r_token.type = TK_OP_EQUAL;
- } else {
- _set_error("Expected '='");
- r_token.type = TK_ERROR;
- return ERR_PARSE_ERROR;
- }
- return OK;
- };
- case '!': {
- if (expression[str_ofs] == '=') {
- r_token.type = TK_OP_NOT_EQUAL;
- str_ofs++;
- } else {
- r_token.type = TK_OP_NOT;
- }
- return OK;
- };
- case '>': {
- if (expression[str_ofs] == '=') {
- r_token.type = TK_OP_GREATER_EQUAL;
- str_ofs++;
- } else if (expression[str_ofs] == '>') {
- r_token.type = TK_OP_SHIFT_RIGHT;
- str_ofs++;
- } else {
- r_token.type = TK_OP_GREATER;
- }
- return OK;
- };
- case '<': {
- if (expression[str_ofs] == '=') {
- r_token.type = TK_OP_LESS_EQUAL;
- str_ofs++;
- } else if (expression[str_ofs] == '<') {
- r_token.type = TK_OP_SHIFT_LEFT;
- str_ofs++;
- } else {
- r_token.type = TK_OP_LESS;
- }
- return OK;
- };
- case '+': {
- r_token.type = TK_OP_ADD;
- return OK;
- };
- case '-': {
- r_token.type = TK_OP_SUB;
- return OK;
- };
- case '/': {
- r_token.type = TK_OP_DIV;
- return OK;
- };
- case '*': {
- r_token.type = TK_OP_MUL;
- return OK;
- };
- case '%': {
- r_token.type = TK_OP_MOD;
- return OK;
- };
- case '&': {
- if (expression[str_ofs] == '&') {
- r_token.type = TK_OP_AND;
- str_ofs++;
- } else {
- r_token.type = TK_OP_BIT_AND;
- }
- return OK;
- };
- case '|': {
- if (expression[str_ofs] == '|') {
- r_token.type = TK_OP_OR;
- str_ofs++;
- } else {
- r_token.type = TK_OP_BIT_OR;
- }
- return OK;
- };
- case '^': {
- r_token.type = TK_OP_BIT_XOR;
-
- return OK;
- };
- case '~': {
- r_token.type = TK_OP_BIT_INVERT;
-
- return OK;
- };
- case '"': {
- String str;
- char32_t prev = 0;
- while (true) {
- char32_t ch = GET_CHAR();
-
- if (ch == 0) {
- _set_error("Unterminated String");
- r_token.type = TK_ERROR;
- return ERR_PARSE_ERROR;
- } else if (ch == '"') {
- break;
- } else if (ch == '\\') {
- //escaped characters...
-
- char32_t next = GET_CHAR();
- if (next == 0) {
- _set_error("Unterminated String");
- r_token.type = TK_ERROR;
- return ERR_PARSE_ERROR;
- }
- char32_t res = 0;
-
- switch (next) {
- case 'b':
- res = 8;
- break;
- case 't':
- res = 9;
- break;
- case 'n':
- res = 10;
- break;
- case 'f':
- res = 12;
- break;
- case 'r':
- res = 13;
- break;
- case 'U':
- case 'u': {
- // Hexadecimal sequence.
- int hex_len = (next == 'U') ? 6 : 4;
- for (int j = 0; j < hex_len; j++) {
- char32_t c = GET_CHAR();
-
- if (c == 0) {
- _set_error("Unterminated String");
- r_token.type = TK_ERROR;
- return ERR_PARSE_ERROR;
- }
- if (!is_hex_digit(c)) {
- _set_error("Malformed hex constant in string");
- r_token.type = TK_ERROR;
- return ERR_PARSE_ERROR;
- }
- char32_t v;
- if (is_digit(c)) {
- 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 {
- ERR_PRINT("Bug parsing hex constant.");
- v = 0;
- }
-
- res <<= 4;
- res |= v;
- }
-
- } break;
- default: {
- res = next;
- } break;
- }
-
- // Parse UTF-16 pair.
- if ((res & 0xfffffc00) == 0xd800) {
- if (prev == 0) {
- prev = res;
- continue;
- } else {
- _set_error("Invalid UTF-16 sequence in string, unpaired lead surrogate");
- r_token.type = TK_ERROR;
- return ERR_PARSE_ERROR;
- }
- } else if ((res & 0xfffffc00) == 0xdc00) {
- if (prev == 0) {
- _set_error("Invalid UTF-16 sequence in string, unpaired trail surrogate");
- r_token.type = TK_ERROR;
- return ERR_PARSE_ERROR;
- } else {
- res = (prev << 10UL) + res - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
- prev = 0;
- }
- }
- if (prev != 0) {
- _set_error("Invalid UTF-16 sequence in string, unpaired lead surrogate");
- r_token.type = TK_ERROR;
- return ERR_PARSE_ERROR;
- }
- str += res;
- } else {
- if (prev != 0) {
- _set_error("Invalid UTF-16 sequence in string, unpaired lead surrogate");
- r_token.type = TK_ERROR;
- return ERR_PARSE_ERROR;
- }
- str += ch;
- }
- }
- if (prev != 0) {
- _set_error("Invalid UTF-16 sequence in string, unpaired lead surrogate");
- r_token.type = TK_ERROR;
- return ERR_PARSE_ERROR;
- }
-
- r_token.type = TK_CONSTANT;
- r_token.value = str;
- return OK;
-
- } break;
- default: {
- if (cchar <= 32) {
- break;
- }
-
- if (is_digit(cchar)) {
- //a number
-
- String num;
-#define READING_SIGN 0
-#define READING_INT 1
-#define READING_DEC 2
-#define READING_EXP 3
-#define READING_DONE 4
- int reading = READING_INT;
-
- char32_t c = cchar;
- bool exp_sign = false;
- bool exp_beg = false;
- bool is_float = false;
-
- while (true) {
- switch (reading) {
- case READING_INT: {
- if (is_digit(c)) {
- //pass
- } else if (c == '.') {
- reading = READING_DEC;
- is_float = true;
- } else if (c == 'e') {
- reading = READING_EXP;
- } else {
- reading = READING_DONE;
- }
-
- } break;
- case READING_DEC: {
- if (is_digit(c)) {
- } else if (c == 'e') {
- reading = READING_EXP;
-
- } else {
- reading = READING_DONE;
- }
-
- } break;
- case READING_EXP: {
- if (is_digit(c)) {
- exp_beg = true;
-
- } else if ((c == '-' || c == '+') && !exp_sign && !exp_beg) {
- if (c == '-') {
- is_float = true;
- }
- exp_sign = true;
-
- } else {
- reading = READING_DONE;
- }
- } break;
- }
-
- if (reading == READING_DONE) {
- break;
- }
- num += String::chr(c);
- c = GET_CHAR();
- }
-
- str_ofs--;
-
- r_token.type = TK_CONSTANT;
-
- if (is_float) {
- r_token.value = num.to_float();
- } else {
- r_token.value = num.to_int();
- }
- return OK;
-
- } else if (is_ascii_char(cchar) || cchar == '_') {
- String id;
- bool first = true;
-
- while (is_ascii_char(cchar) || cchar == '_' || (!first && is_digit(cchar))) {
- id += String::chr(cchar);
- cchar = GET_CHAR();
- first = false;
- }
-
- str_ofs--; //go back one
-
- if (id == "in") {
- r_token.type = TK_OP_IN;
- } else if (id == "null") {
- r_token.type = TK_CONSTANT;
- r_token.value = Variant();
- } else if (id == "true") {
- r_token.type = TK_CONSTANT;
- r_token.value = true;
- } else if (id == "false") {
- r_token.type = TK_CONSTANT;
- r_token.value = false;
- } else if (id == "PI") {
- r_token.type = TK_CONSTANT;
- r_token.value = Math_PI;
- } else if (id == "TAU") {
- r_token.type = TK_CONSTANT;
- r_token.value = Math_TAU;
- } else if (id == "INF") {
- r_token.type = TK_CONSTANT;
- r_token.value = INFINITY;
- } else if (id == "NAN") {
- r_token.type = TK_CONSTANT;
- r_token.value = NAN;
- } else if (id == "not") {
- r_token.type = TK_OP_NOT;
- } else if (id == "or") {
- r_token.type = TK_OP_OR;
- } else if (id == "and") {
- r_token.type = TK_OP_AND;
- } else if (id == "self") {
- r_token.type = TK_SELF;
- } else {
- for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- if (id == Variant::get_type_name(Variant::Type(i))) {
- r_token.type = TK_BASIC_TYPE;
- r_token.value = i;
- return OK;
- }
- }
-
- VisualScriptBuiltinFunc::BuiltinFunc bifunc = VisualScriptBuiltinFunc::find_function(id);
- if (bifunc != VisualScriptBuiltinFunc::FUNC_MAX) {
- r_token.type = TK_BUILTIN_FUNC;
- r_token.value = bifunc;
- return OK;
- }
-
- r_token.type = TK_IDENTIFIER;
- r_token.value = id;
- }
-
- return OK;
- } else {
- _set_error("Unexpected character.");
- r_token.type = TK_ERROR;
- return ERR_PARSE_ERROR;
- }
- }
- }
- }
-
- r_token.type = TK_ERROR;
- return ERR_PARSE_ERROR;
-}
-
-const char *VisualScriptExpression::token_name[TK_MAX] = {
- "CURLY BRACKET OPEN",
- "CURLY BRACKET CLOSE",
- "BRACKET OPEN",
- "BRACKET CLOSE",
- "PARENTHESIS OPEN",
- "PARENTHESIS CLOSE",
- "IDENTIFIER",
- "BUILTIN FUNC",
- "SELF",
- "CONSTANT",
- "BASIC TYPE",
- "COLON",
- "COMMA",
- "PERIOD",
- "OP IN",
- "OP EQUAL",
- "OP NOT EQUAL",
- "OP LESS",
- "OP LESS EQUAL",
- "OP GREATER",
- "OP GREATER EQUAL",
- "OP AND",
- "OP OR",
- "OP NOT",
- "OP ADD",
- "OP SUB",
- "OP MUL",
- "OP DIV",
- "OP MOD",
- "OP SHIFT LEFT",
- "OP SHIFT RIGHT",
- "OP BIT AND",
- "OP BIT OR",
- "OP BIT XOR",
- "OP BIT INVERT",
- "EOF",
- "ERROR"
-};
-
-VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
- Vector<Expression> expression;
-
- while (true) {
- //keep appending stuff to expression
- ENode *expr = nullptr;
-
- Token tk;
- _get_token(tk);
- if (error_set) {
- return nullptr;
- }
-
- switch (tk.type) {
- case TK_CURLY_BRACKET_OPEN: {
- //a dictionary
- DictionaryNode *dn = alloc_node<DictionaryNode>();
-
- while (true) {
- int cofs = str_ofs;
- _get_token(tk);
- if (tk.type == TK_CURLY_BRACKET_CLOSE) {
- break;
- }
- str_ofs = cofs; //revert
- //parse an expression
- ENode *expr2 = _parse_expression();
- if (!expr2) {
- return nullptr;
- }
- dn->dict.push_back(expr2);
-
- _get_token(tk);
- if (tk.type != TK_COLON) {
- _set_error("Expected ':'");
- return nullptr;
- }
-
- expr2 = _parse_expression();
- if (!expr2) {
- return nullptr;
- }
-
- dn->dict.push_back(expr2);
-
- cofs = str_ofs;
- _get_token(tk);
- if (tk.type == TK_COMMA) {
- //all good
- } else if (tk.type == TK_CURLY_BRACKET_CLOSE) {
- str_ofs = cofs;
- } else {
- _set_error("Expected ',' or '}'");
- }
- }
-
- expr = dn;
- } break;
- case TK_BRACKET_OPEN: {
- //an array
-
- ArrayNode *an = alloc_node<ArrayNode>();
-
- while (true) {
- int cofs = str_ofs;
- _get_token(tk);
- if (tk.type == TK_BRACKET_CLOSE) {
- break;
- }
- str_ofs = cofs; //revert
- //parse an expression
- ENode *expr2 = _parse_expression();
- if (!expr2) {
- return nullptr;
- }
- an->array.push_back(expr2);
-
- cofs = str_ofs;
- _get_token(tk);
- if (tk.type == TK_COMMA) {
- //all good
- } else if (tk.type == TK_BRACKET_CLOSE) {
- str_ofs = cofs;
- } else {
- _set_error("Expected ',' or ']'");
- }
- }
-
- expr = an;
- } break;
- case TK_PARENTHESIS_OPEN: {
- //a suexpression
- ENode *e = _parse_expression();
- if (error_set) {
- return nullptr;
- }
- _get_token(tk);
- if (tk.type != TK_PARENTHESIS_CLOSE) {
- _set_error("Expected ')'");
- return nullptr;
- }
-
- expr = e;
-
- } break;
- case TK_IDENTIFIER: {
- String what = tk.value;
- int index = -1;
- for (int i = 0; i < inputs.size(); i++) {
- if (what == inputs[i].name) {
- index = i;
- break;
- }
- }
-
- if (index != -1) {
- InputNode *input = alloc_node<InputNode>();
- input->index = index;
- expr = input;
- } else {
- _set_error("Invalid input identifier '" + what + "'. For script variables, use self (locals are for inputs)." + what);
- return nullptr;
- }
- } break;
- case TK_SELF: {
- SelfNode *self = alloc_node<SelfNode>();
- expr = self;
- } break;
- case TK_CONSTANT: {
- ConstantNode *constant = alloc_node<ConstantNode>();
- constant->value = tk.value;
- expr = constant;
- } break;
- case TK_BASIC_TYPE: {
- //constructor..
-
- Variant::Type bt = Variant::Type(int(tk.value));
- _get_token(tk);
- if (tk.type != TK_PARENTHESIS_OPEN) {
- _set_error("Expected '('");
- return nullptr;
- }
-
- ConstructorNode *constructor = alloc_node<ConstructorNode>();
- constructor->data_type = bt;
-
- while (true) {
- int cofs = str_ofs;
- _get_token(tk);
- if (tk.type == TK_PARENTHESIS_CLOSE) {
- break;
- }
- str_ofs = cofs; //revert
- //parse an expression
- ENode *expr2 = _parse_expression();
- if (!expr2) {
- return nullptr;
- }
-
- constructor->arguments.push_back(expr2);
-
- cofs = str_ofs;
- _get_token(tk);
- if (tk.type == TK_COMMA) {
- //all good
- } else if (tk.type == TK_PARENTHESIS_CLOSE) {
- str_ofs = cofs;
- } else {
- _set_error("Expected ',' or ')'");
- }
- }
-
- expr = constructor;
-
- } break;
- case TK_BUILTIN_FUNC: {
- //builtin function
-
- _get_token(tk);
- if (tk.type != TK_PARENTHESIS_OPEN) {
- _set_error("Expected '('");
- return nullptr;
- }
-
- BuiltinFuncNode *bifunc = alloc_node<BuiltinFuncNode>();
- bifunc->func = VisualScriptBuiltinFunc::BuiltinFunc(int(tk.value));
-
- while (true) {
- int cofs = str_ofs;
- _get_token(tk);
- if (tk.type == TK_PARENTHESIS_CLOSE) {
- break;
- }
- str_ofs = cofs; //revert
- //parse an expression
- ENode *expr2 = _parse_expression();
- if (!expr2) {
- return nullptr;
- }
-
- bifunc->arguments.push_back(expr2);
-
- cofs = str_ofs;
- _get_token(tk);
- if (tk.type == TK_COMMA) {
- //all good
- } else if (tk.type == TK_PARENTHESIS_CLOSE) {
- str_ofs = cofs;
- } else {
- _set_error("Expected ',' or ')'");
- }
- }
-
- int expected_args = VisualScriptBuiltinFunc::get_func_argument_count(bifunc->func);
- if (bifunc->arguments.size() != expected_args) {
- _set_error("Builtin func '" + VisualScriptBuiltinFunc::get_func_name(bifunc->func) + "' expects " + itos(expected_args) + " arguments.");
- }
-
- expr = bifunc;
-
- } break;
- case TK_OP_SUB: {
- Expression e;
- e.is_op = true;
- e.op = Variant::OP_NEGATE;
- expression.push_back(e);
- continue;
- } break;
- case TK_OP_NOT: {
- Expression e;
- e.is_op = true;
- e.op = Variant::OP_NOT;
- expression.push_back(e);
- continue;
- } break;
-
- default: {
- _set_error("Expected expression.");
- return nullptr;
- } break;
- }
-
- //before going to operators, must check indexing!
-
- while (true) {
- int cofs2 = str_ofs;
- _get_token(tk);
- if (error_set) {
- return nullptr;
- }
-
- bool done = false;
-
- switch (tk.type) {
- case TK_BRACKET_OPEN: {
- //value indexing
-
- IndexNode *index = alloc_node<IndexNode>();
- index->base = expr;
-
- ENode *what = _parse_expression();
- if (!what) {
- return nullptr;
- }
-
- index->index = what;
-
- _get_token(tk);
- if (tk.type != TK_BRACKET_CLOSE) {
- _set_error("Expected ']' at end of index.");
- return nullptr;
- }
- expr = index;
-
- } break;
- case TK_PERIOD: {
- //named indexing or function call
- _get_token(tk);
- if (tk.type != TK_IDENTIFIER) {
- _set_error("Expected identifier after '.'");
- return nullptr;
- }
-
- StringName identifier = tk.value;
-
- int cofs = str_ofs;
- _get_token(tk);
- if (tk.type == TK_PARENTHESIS_OPEN) {
- //function call
- CallNode *func_call = alloc_node<CallNode>();
- func_call->method = identifier;
- func_call->base = expr;
-
- while (true) {
- int cofs3 = str_ofs;
- _get_token(tk);
- if (tk.type == TK_PARENTHESIS_CLOSE) {
- break;
- }
- str_ofs = cofs3; //revert
- //parse an expression
- ENode *expr2 = _parse_expression();
- if (!expr2) {
- return nullptr;
- }
-
- func_call->arguments.push_back(expr2);
-
- cofs3 = str_ofs;
- _get_token(tk);
- if (tk.type == TK_COMMA) {
- //all good
- } else if (tk.type == TK_PARENTHESIS_CLOSE) {
- str_ofs = cofs3;
- } else {
- _set_error("Expected ',' or ')'");
- }
- }
-
- expr = func_call;
- } else {
- //named indexing
- str_ofs = cofs;
-
- NamedIndexNode *index = alloc_node<NamedIndexNode>();
- index->base = expr;
- index->name = identifier;
- expr = index;
- }
-
- } break;
- default: {
- str_ofs = cofs2;
- done = true;
- } break;
- }
-
- if (done) {
- break;
- }
- }
-
- //push expression
- {
- Expression e;
- e.is_op = false;
- e.node = expr;
- expression.push_back(e);
- }
-
- //ok finally look for an operator
-
- int cofs = str_ofs;
- _get_token(tk);
- if (error_set) {
- return nullptr;
- }
-
- Variant::Operator op = Variant::OP_MAX;
-
- switch (tk.type) {
- case TK_OP_IN:
- op = Variant::OP_IN;
- break;
- case TK_OP_EQUAL:
- op = Variant::OP_EQUAL;
- break;
- case TK_OP_NOT_EQUAL:
- op = Variant::OP_NOT_EQUAL;
- break;
- case TK_OP_LESS:
- op = Variant::OP_LESS;
- break;
- case TK_OP_LESS_EQUAL:
- op = Variant::OP_LESS_EQUAL;
- break;
- case TK_OP_GREATER:
- op = Variant::OP_GREATER;
- break;
- case TK_OP_GREATER_EQUAL:
- op = Variant::OP_GREATER_EQUAL;
- break;
- case TK_OP_AND:
- op = Variant::OP_AND;
- break;
- case TK_OP_OR:
- op = Variant::OP_OR;
- break;
- case TK_OP_NOT:
- op = Variant::OP_NOT;
- break;
- case TK_OP_ADD:
- op = Variant::OP_ADD;
- break;
- case TK_OP_SUB:
- op = Variant::OP_SUBTRACT;
- break;
- case TK_OP_MUL:
- op = Variant::OP_MULTIPLY;
- break;
- case TK_OP_DIV:
- op = Variant::OP_DIVIDE;
- break;
- case TK_OP_MOD:
- op = Variant::OP_MODULE;
- break;
- case TK_OP_SHIFT_LEFT:
- op = Variant::OP_SHIFT_LEFT;
- break;
- case TK_OP_SHIFT_RIGHT:
- op = Variant::OP_SHIFT_RIGHT;
- break;
- case TK_OP_BIT_AND:
- op = Variant::OP_BIT_AND;
- break;
- case TK_OP_BIT_OR:
- op = Variant::OP_BIT_OR;
- break;
- case TK_OP_BIT_XOR:
- op = Variant::OP_BIT_XOR;
- break;
- case TK_OP_BIT_INVERT:
- op = Variant::OP_BIT_NEGATE;
- break;
- default: {
- };
- }
-
- if (op == Variant::OP_MAX) { //stop appending stuff
- str_ofs = cofs;
- break;
- }
-
- //push operator and go on
- {
- Expression e;
- e.is_op = true;
- e.op = op;
- expression.push_back(e);
- }
- }
-
- /* Reduce the set of expressions and place them in an operator tree, respecting precedence */
-
- while (expression.size() > 1) {
- int next_op = -1;
- int min_priority = 0xFFFFF;
- bool is_unary = false;
-
- for (int i = 0; i < expression.size(); i++) {
- if (!expression[i].is_op) {
- continue;
- }
-
- int priority;
-
- bool unary = false;
-
- switch (expression[i].op) {
- case Variant::OP_BIT_NEGATE:
- priority = 0;
- unary = true;
- break;
- case Variant::OP_NEGATE:
- priority = 1;
- unary = true;
- break;
-
- case Variant::OP_MULTIPLY:
- priority = 2;
- break;
- case Variant::OP_DIVIDE:
- priority = 2;
- break;
- case Variant::OP_MODULE:
- priority = 2;
- break;
-
- case Variant::OP_ADD:
- priority = 3;
- break;
- case Variant::OP_SUBTRACT:
- priority = 3;
- break;
-
- case Variant::OP_SHIFT_LEFT:
- priority = 4;
- break;
- case Variant::OP_SHIFT_RIGHT:
- priority = 4;
- break;
-
- case Variant::OP_BIT_AND:
- priority = 5;
- break;
- case Variant::OP_BIT_XOR:
- priority = 6;
- break;
- case Variant::OP_BIT_OR:
- priority = 7;
- break;
-
- case Variant::OP_LESS:
- priority = 8;
- break;
- case Variant::OP_LESS_EQUAL:
- priority = 8;
- break;
- case Variant::OP_GREATER:
- priority = 8;
- break;
- case Variant::OP_GREATER_EQUAL:
- priority = 8;
- break;
-
- case Variant::OP_EQUAL:
- priority = 8;
- break;
- case Variant::OP_NOT_EQUAL:
- priority = 8;
- break;
-
- case Variant::OP_IN:
- priority = 10;
- break;
-
- case Variant::OP_NOT:
- priority = 11;
- unary = true;
- break;
- case Variant::OP_AND:
- priority = 12;
- break;
- case Variant::OP_OR:
- priority = 13;
- break;
-
- default: {
- _set_error("Parser bug, invalid operator in expression: " + itos(expression[i].op));
- return nullptr;
- }
- }
-
- if (priority < min_priority) {
- // < is used for left to right (default)
- // <= is used for right to left
-
- next_op = i;
- min_priority = priority;
- is_unary = unary;
- }
- }
-
- if (next_op == -1) {
- _set_error("Yet another parser bug....");
- ERR_FAIL_V(nullptr);
- }
-
- // OK! create operator..
- if (is_unary) {
- int expr_pos = next_op;
- while (expression[expr_pos].is_op) {
- expr_pos++;
- if (expr_pos == expression.size()) {
- //can happen..
- _set_error("Unexpected end of expression...");
- return nullptr;
- }
- }
-
- //consecutively do unary operators
- for (int i = expr_pos - 1; i >= next_op; i--) {
- OperatorNode *op = alloc_node<OperatorNode>();
- op->op = expression[i].op;
- op->nodes[0] = expression[i + 1].node;
- op->nodes[1] = nullptr;
- expression.write[i].is_op = false;
- expression.write[i].node = op;
- expression.remove_at(i + 1);
- }
-
- } else {
- if (next_op < 1 || next_op >= (expression.size() - 1)) {
- _set_error("Parser bug...");
- ERR_FAIL_V(nullptr);
- }
-
- OperatorNode *op = alloc_node<OperatorNode>();
- op->op = expression[next_op].op;
-
- if (expression[next_op - 1].is_op) {
- _set_error("Parser bug...");
- ERR_FAIL_V(nullptr);
- }
-
- if (expression[next_op + 1].is_op) {
- // this is not invalid and can really appear
- // but it becomes invalid anyway because no binary op
- // can be followed by a unary op in a valid combination,
- // due to how precedence works, unaries will always disappear first
-
- _set_error("Unexpected two consecutive operators.");
- return nullptr;
- }
-
- op->nodes[0] = expression[next_op - 1].node; //expression goes as left
- op->nodes[1] = expression[next_op + 1].node; //next expression goes as right
-
- //replace all 3 nodes by this operator and make it an expression
- expression.write[next_op - 1].node = op;
- expression.remove_at(next_op);
- expression.remove_at(next_op);
- }
- }
-
- return expression[0].node;
-}
-
-bool VisualScriptExpression::_compile_expression() {
- if (!expression_dirty) {
- return error_set;
- }
-
- if (nodes) {
- memdelete(nodes);
- nodes = nullptr;
- root = nullptr;
- }
-
- error_str = String();
- error_set = false;
- str_ofs = 0;
-
- root = _parse_expression();
-
- if (error_set) {
- root = nullptr;
- if (nodes) {
- memdelete(nodes);
- }
- nodes = nullptr;
- return true;
- }
-
- expression_dirty = false;
- return false;
-}
-
-class VisualScriptNodeInstanceExpression : public VisualScriptNodeInstance {
-public:
- VisualScriptInstance *instance = nullptr;
- VisualScriptExpression *expression = nullptr;
-
- //virtual int get_working_memory_size() const override { return 0; }
- //execute by parsing the tree directly
- virtual bool _execute(const Variant **p_inputs, VisualScriptExpression::ENode *p_node, Variant &r_ret, String &r_error_str, Callable::CallError &ce) {
- switch (p_node->type) {
- case VisualScriptExpression::ENode::TYPE_INPUT: {
- const VisualScriptExpression::InputNode *in = static_cast<const VisualScriptExpression::InputNode *>(p_node);
- r_ret = *p_inputs[in->index];
- } break;
- case VisualScriptExpression::ENode::TYPE_CONSTANT: {
- const VisualScriptExpression::ConstantNode *c = static_cast<const VisualScriptExpression::ConstantNode *>(p_node);
- r_ret = c->value;
-
- } break;
- case VisualScriptExpression::ENode::TYPE_SELF: {
- r_ret = instance->get_owner_ptr();
- } break;
- case VisualScriptExpression::ENode::TYPE_OPERATOR: {
- const VisualScriptExpression::OperatorNode *op = static_cast<const VisualScriptExpression::OperatorNode *>(p_node);
-
- Variant a;
- bool ret = _execute(p_inputs, op->nodes[0], a, r_error_str, ce);
- if (ret) {
- return true;
- }
-
- Variant b;
-
- if (op->nodes[1]) {
- ret = _execute(p_inputs, op->nodes[1], b, r_error_str, ce);
- if (ret) {
- return true;
- }
- }
-
- bool valid = true;
- Variant::evaluate(op->op, a, b, r_ret, valid);
- if (!valid) {
- r_error_str = "Invalid operands to operator " + Variant::get_operator_name(op->op) + ": " + Variant::get_type_name(a.get_type()) + " and " + Variant::get_type_name(b.get_type()) + ".";
- return true;
- }
-
- } break;
- case VisualScriptExpression::ENode::TYPE_INDEX: {
- const VisualScriptExpression::IndexNode *index = static_cast<const VisualScriptExpression::IndexNode *>(p_node);
-
- Variant base;
- bool ret = _execute(p_inputs, index->base, base, r_error_str, ce);
- if (ret) {
- return true;
- }
-
- Variant idx;
-
- ret = _execute(p_inputs, index->index, idx, r_error_str, ce);
- if (ret) {
- return true;
- }
-
- bool valid;
- r_ret = base.get(idx, &valid);
- if (!valid) {
- r_error_str = "Invalid index of type " + Variant::get_type_name(idx.get_type()) + " for base of type " + Variant::get_type_name(base.get_type()) + ".";
- return true;
- }
-
- } break;
- case VisualScriptExpression::ENode::TYPE_NAMED_INDEX: {
- const VisualScriptExpression::NamedIndexNode *index = static_cast<const VisualScriptExpression::NamedIndexNode *>(p_node);
-
- Variant base;
- bool ret = _execute(p_inputs, index->base, base, r_error_str, ce);
- if (ret) {
- return true;
- }
-
- bool valid;
- r_ret = base.get_named(index->name, valid);
- if (!valid) {
- r_error_str = "Invalid index '" + String(index->name) + "' for base of type " + Variant::get_type_name(base.get_type()) + ".";
- return true;
- }
-
- } break;
- case VisualScriptExpression::ENode::TYPE_ARRAY: {
- const VisualScriptExpression::ArrayNode *array = static_cast<const VisualScriptExpression::ArrayNode *>(p_node);
-
- Array arr;
- arr.resize(array->array.size());
- for (int i = 0; i < array->array.size(); i++) {
- Variant value;
- bool ret = _execute(p_inputs, array->array[i], value, r_error_str, ce);
- if (ret) {
- return true;
- }
- arr[i] = value;
- }
-
- r_ret = arr;
-
- } break;
- case VisualScriptExpression::ENode::TYPE_DICTIONARY: {
- const VisualScriptExpression::DictionaryNode *dictionary = static_cast<const VisualScriptExpression::DictionaryNode *>(p_node);
-
- Dictionary d;
- for (int i = 0; i < dictionary->dict.size(); i += 2) {
- Variant key;
- bool ret = _execute(p_inputs, dictionary->dict[i + 0], key, r_error_str, ce);
- if (ret) {
- return true;
- }
-
- Variant value;
- ret = _execute(p_inputs, dictionary->dict[i + 1], value, r_error_str, ce);
- if (ret) {
- return true;
- }
-
- d[key] = value;
- }
-
- r_ret = d;
- } break;
- case VisualScriptExpression::ENode::TYPE_CONSTRUCTOR: {
- const VisualScriptExpression::ConstructorNode *constructor = static_cast<const VisualScriptExpression::ConstructorNode *>(p_node);
-
- Vector<Variant> arr;
- Vector<const Variant *> argp;
- arr.resize(constructor->arguments.size());
- argp.resize(constructor->arguments.size());
-
- for (int i = 0; i < constructor->arguments.size(); i++) {
- Variant value;
- bool ret = _execute(p_inputs, constructor->arguments[i], value, r_error_str, ce);
- if (ret) {
- return true;
- }
- arr.write[i] = value;
- argp.write[i] = &arr[i];
- }
-
- Variant::construct(constructor->data_type, r_ret, (const Variant **)argp.ptr(), argp.size(), ce);
-
- if (ce.error != Callable::CallError::CALL_OK) {
- r_error_str = "Invalid arguments to construct '" + Variant::get_type_name(constructor->data_type) + "'.";
- return true;
- }
-
- } break;
- case VisualScriptExpression::ENode::TYPE_BUILTIN_FUNC: {
- const VisualScriptExpression::BuiltinFuncNode *bifunc = static_cast<const VisualScriptExpression::BuiltinFuncNode *>(p_node);
-
- Vector<Variant> arr;
- Vector<const Variant *> argp;
- arr.resize(bifunc->arguments.size());
- argp.resize(bifunc->arguments.size());
-
- for (int i = 0; i < bifunc->arguments.size(); i++) {
- Variant value;
- bool ret = _execute(p_inputs, bifunc->arguments[i], value, r_error_str, ce);
- if (ret) {
- return true;
- }
- arr.write[i] = value;
- argp.write[i] = &arr[i];
- }
-
- VisualScriptBuiltinFunc::exec_func(bifunc->func, (const Variant **)argp.ptr(), &r_ret, ce, r_error_str);
-
- if (ce.error != Callable::CallError::CALL_OK) {
- r_error_str = "Builtin Call Failed. " + r_error_str;
- return true;
- }
-
- } break;
- case VisualScriptExpression::ENode::TYPE_CALL: {
- const VisualScriptExpression::CallNode *call = static_cast<const VisualScriptExpression::CallNode *>(p_node);
-
- Variant base;
- bool ret = _execute(p_inputs, call->base, base, r_error_str, ce);
- if (ret) {
- return true;
- }
-
- Vector<Variant> arr;
- Vector<const Variant *> argp;
- arr.resize(call->arguments.size());
- argp.resize(call->arguments.size());
-
- for (int i = 0; i < call->arguments.size(); i++) {
- Variant value;
- bool ret2 = _execute(p_inputs, call->arguments[i], value, r_error_str, ce);
- if (ret2) {
- return true;
- }
- arr.write[i] = value;
- argp.write[i] = &arr[i];
- }
-
- base.callp(call->method, (const Variant **)argp.ptr(), argp.size(), r_ret, ce);
-
- if (ce.error != Callable::CallError::CALL_OK) {
- r_error_str = "On call to '" + String(call->method) + "':";
- return true;
- }
-
- } break;
- }
- return false;
- }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- if (!expression->root || expression->error_set) {
- r_error_str = expression->error_str;
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return 0;
- }
-
- bool error = _execute(p_inputs, expression->root, *p_outputs[0], r_error_str, r_error);
- if (error && r_error.error == Callable::CallError::CALL_OK) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- }
-
-#ifdef DEBUG_ENABLED
- if (!error && expression->output_type != Variant::NIL && !Variant::can_convert_strict(p_outputs[0]->get_type(), expression->output_type)) {
- r_error_str += "Can't convert expression result from " + Variant::get_type_name(p_outputs[0]->get_type()) + " to " + Variant::get_type_name(expression->output_type) + ".";
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- }
-#endif
-
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptExpression::instantiate(VisualScriptInstance *p_instance) {
- _compile_expression();
- VisualScriptNodeInstanceExpression *instance = memnew(VisualScriptNodeInstanceExpression);
- instance->instance = p_instance;
- instance->expression = this;
- return instance;
-}
-
-void VisualScriptExpression::reset_state() {
- if (nodes) {
- memdelete(nodes);
- nodes = nullptr;
- root = nullptr;
- }
-
- error_str = String();
- error_set = false;
- str_ofs = 0;
- inputs.clear();
-}
-
-VisualScriptExpression::VisualScriptExpression() {
-}
-
-VisualScriptExpression::~VisualScriptExpression() {
- if (nodes) {
- memdelete(nodes);
- }
-}
-
-void register_visual_script_expression_node() {
- VisualScriptLanguage::singleton->add_register_func("operators/expression", create_node_generic<VisualScriptExpression>);
-}
diff --git a/modules/visual_script/visual_script_expression.h b/modules/visual_script/visual_script_expression.h
deleted file mode 100644
index 7e10f98f36..0000000000
--- a/modules/visual_script/visual_script_expression.h
+++ /dev/null
@@ -1,284 +0,0 @@
-/*************************************************************************/
-/* visual_script_expression.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef VISUAL_SCRIPT_EXPRESSION_H
-#define VISUAL_SCRIPT_EXPRESSION_H
-
-#include "visual_script.h"
-#include "visual_script_builtin_funcs.h"
-
-class VisualScriptExpression : public VisualScriptNode {
- GDCLASS(VisualScriptExpression, VisualScriptNode);
- friend class VisualScriptNodeInstanceExpression;
-
- struct Input {
- Variant::Type type = Variant::NIL;
- String name;
- };
-
- Vector<Input> inputs;
- Variant::Type output_type = Variant::NIL;
-
- String expression;
-
- bool sequenced = false;
- int str_ofs = 0;
- bool expression_dirty = true;
-
- bool _compile_expression();
-
- enum TokenType {
- TK_CURLY_BRACKET_OPEN,
- TK_CURLY_BRACKET_CLOSE,
- TK_BRACKET_OPEN,
- TK_BRACKET_CLOSE,
- TK_PARENTHESIS_OPEN,
- TK_PARENTHESIS_CLOSE,
- TK_IDENTIFIER,
- TK_BUILTIN_FUNC,
- TK_SELF,
- TK_CONSTANT,
- TK_BASIC_TYPE,
- TK_COLON,
- TK_COMMA,
- TK_PERIOD,
- TK_OP_IN,
- TK_OP_EQUAL,
- TK_OP_NOT_EQUAL,
- TK_OP_LESS,
- TK_OP_LESS_EQUAL,
- TK_OP_GREATER,
- TK_OP_GREATER_EQUAL,
- TK_OP_AND,
- TK_OP_OR,
- TK_OP_NOT,
- TK_OP_ADD,
- TK_OP_SUB,
- TK_OP_MUL,
- TK_OP_DIV,
- TK_OP_MOD,
- TK_OP_SHIFT_LEFT,
- TK_OP_SHIFT_RIGHT,
- TK_OP_BIT_AND,
- TK_OP_BIT_OR,
- TK_OP_BIT_XOR,
- TK_OP_BIT_INVERT,
- TK_EOF,
- TK_ERROR,
- TK_MAX
- };
-
- static const char *token_name[TK_MAX];
- struct Token {
- TokenType type;
- Variant value;
- };
-
- void _set_error(const String &p_err) {
- if (error_set) {
- return;
- }
- error_str = p_err;
- error_set = true;
- }
-
- Error _get_token(Token &r_token);
-
- String error_str;
- bool error_set = true;
-
- struct ENode {
- enum Type {
- TYPE_INPUT,
- TYPE_CONSTANT,
- TYPE_SELF,
- TYPE_OPERATOR,
- TYPE_INDEX,
- TYPE_NAMED_INDEX,
- TYPE_ARRAY,
- TYPE_DICTIONARY,
- TYPE_CONSTRUCTOR,
- TYPE_BUILTIN_FUNC,
- TYPE_CALL
- };
-
- ENode *next = nullptr;
-
- Type type = Type::TYPE_SELF;
-
- virtual ~ENode() {
- if (next) {
- memdelete(next);
- }
- }
- };
-
- struct Expression {
- bool is_op = false;
- union {
- Variant::Operator op;
- ENode *node = nullptr;
- };
- };
-
- ENode *_parse_expression();
-
- struct InputNode : public ENode {
- int index = 0;
- InputNode() {
- type = TYPE_INPUT;
- }
- };
-
- struct ConstantNode : public ENode {
- Variant value;
- ConstantNode() {
- type = TYPE_CONSTANT;
- }
- };
-
- struct OperatorNode : public ENode {
- Variant::Operator op = Variant::Operator::OP_ADD;
-
- ENode *nodes[2] = { nullptr, nullptr };
-
- OperatorNode() {
- type = TYPE_OPERATOR;
- }
- };
-
- struct SelfNode : public ENode {
- SelfNode() {
- type = TYPE_SELF;
- }
- };
-
- struct IndexNode : public ENode {
- ENode *base = nullptr;
- ENode *index = nullptr;
-
- IndexNode() {
- type = TYPE_INDEX;
- }
- };
-
- struct NamedIndexNode : public ENode {
- ENode *base = nullptr;
- StringName name;
-
- NamedIndexNode() {
- type = TYPE_NAMED_INDEX;
- }
- };
-
- struct ConstructorNode : public ENode {
- Variant::Type data_type = Variant::Type::NIL;
- Vector<ENode *> arguments;
-
- ConstructorNode() {
- type = TYPE_CONSTRUCTOR;
- }
- };
-
- struct CallNode : public ENode {
- ENode *base = nullptr;
- StringName method;
- Vector<ENode *> arguments;
-
- CallNode() {
- type = TYPE_CALL;
- }
- };
-
- struct ArrayNode : public ENode {
- Vector<ENode *> array;
- ArrayNode() {
- type = TYPE_ARRAY;
- }
- };
-
- struct DictionaryNode : public ENode {
- Vector<ENode *> dict;
- DictionaryNode() {
- type = TYPE_DICTIONARY;
- }
- };
-
- struct BuiltinFuncNode : public ENode {
- VisualScriptBuiltinFunc::BuiltinFunc func = VisualScriptBuiltinFunc::BuiltinFunc::BYTES_TO_VAR;
- Vector<ENode *> arguments;
- BuiltinFuncNode() {
- type = TYPE_BUILTIN_FUNC;
- }
- };
-
- template <class T>
- T *alloc_node() {
- T *node = memnew(T);
- node->next = nodes;
- nodes = node;
- return node;
- }
-
- ENode *root = nullptr;
- ENode *nodes = nullptr;
-
-protected:
- bool _set(const StringName &p_name, const Variant &p_value);
- bool _get(const StringName &p_name, Variant &r_ret) const;
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
-public:
- virtual void reset_state() override;
-
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_text() const override;
- virtual String get_category() const override { return "operators"; }
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptExpression();
- ~VisualScriptExpression();
-};
-
-void register_visual_script_expression_node();
-
-#endif // VISUAL_SCRIPT_EXPRESSION_H
diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp
deleted file mode 100644
index 19bbd834cc..0000000000
--- a/modules/visual_script/visual_script_flow_control.cpp
+++ /dev/null
@@ -1,880 +0,0 @@
-/*************************************************************************/
-/* visual_script_flow_control.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "visual_script_flow_control.h"
-
-#include "core/config/project_settings.h"
-#include "core/io/resource_loader.h"
-#include "core/os/keyboard.h"
-
-//////////////////////////////////////////
-////////////////RETURN////////////////////
-//////////////////////////////////////////
-
-int VisualScriptReturn::get_output_sequence_port_count() const {
- return 0;
-}
-
-bool VisualScriptReturn::has_input_sequence_port() const {
- return true;
-}
-
-int VisualScriptReturn::get_input_value_port_count() const {
- return with_value ? 1 : 0;
-}
-
-int VisualScriptReturn::get_output_value_port_count() const {
- return 0;
-}
-
-String VisualScriptReturn::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptReturn::get_input_value_port_info(int p_idx) const {
- PropertyInfo pinfo;
- pinfo.name = "result";
- pinfo.type = type;
- return pinfo;
-}
-
-PropertyInfo VisualScriptReturn::get_output_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-String VisualScriptReturn::get_caption() const {
- return RTR("Return");
-}
-
-String VisualScriptReturn::get_text() const {
- return get_name();
-}
-
-void VisualScriptReturn::set_return_type(Variant::Type p_type) {
- if (type == p_type) {
- return;
- }
- type = p_type;
- ports_changed_notify();
-}
-
-Variant::Type VisualScriptReturn::get_return_type() const {
- return type;
-}
-
-void VisualScriptReturn::set_enable_return_value(bool p_enable) {
- if (with_value == p_enable) {
- return;
- }
-
- with_value = p_enable;
- ports_changed_notify();
-}
-
-bool VisualScriptReturn::is_return_value_enabled() const {
- return with_value;
-}
-
-void VisualScriptReturn::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_return_type", "type"), &VisualScriptReturn::set_return_type);
- ClassDB::bind_method(D_METHOD("get_return_type"), &VisualScriptReturn::get_return_type);
- ClassDB::bind_method(D_METHOD("set_enable_return_value", "enable"), &VisualScriptReturn::set_enable_return_value);
- ClassDB::bind_method(D_METHOD("is_return_value_enabled"), &VisualScriptReturn::is_return_value_enabled);
-
- String argt = "Any";
- for (int i = 1; i < Variant::VARIANT_MAX; i++) {
- argt += "," + Variant::get_type_name(Variant::Type(i));
- }
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "return_enabled"), "set_enable_return_value", "is_return_value_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "return_type", PROPERTY_HINT_ENUM, argt), "set_return_type", "get_return_type");
-}
-
-class VisualScriptNodeInstanceReturn : public VisualScriptNodeInstance {
-public:
- VisualScriptReturn *node = nullptr;
- VisualScriptInstance *instance = nullptr;
- bool with_value = false;
-
- virtual int get_working_memory_size() const override { return 1; }
- //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
- //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- if (with_value) {
- *p_working_mem = *p_inputs[0];
- return STEP_EXIT_FUNCTION_BIT;
- } else {
- *p_working_mem = Variant();
- return 0;
- }
- }
-};
-
-VisualScriptNodeInstance *VisualScriptReturn::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceReturn *instance = memnew(VisualScriptNodeInstanceReturn);
- instance->node = this;
- instance->instance = p_instance;
- instance->with_value = with_value;
- return instance;
-}
-
-VisualScriptReturn::VisualScriptReturn() {
- with_value = false;
- type = Variant::NIL;
-}
-
-template <bool with_value>
-static Ref<VisualScriptNode> create_return_node(const String &p_name) {
- Ref<VisualScriptReturn> node;
- node.instantiate();
- node->set_enable_return_value(with_value);
- return node;
-}
-
-//////////////////////////////////////////
-////////////////CONDITION/////////////////
-//////////////////////////////////////////
-
-int VisualScriptCondition::get_output_sequence_port_count() const {
- return 3;
-}
-
-bool VisualScriptCondition::has_input_sequence_port() const {
- return true;
-}
-
-int VisualScriptCondition::get_input_value_port_count() const {
- return 1;
-}
-
-int VisualScriptCondition::get_output_value_port_count() const {
- return 0;
-}
-
-String VisualScriptCondition::get_output_sequence_port_text(int p_port) const {
- if (p_port == 0) {
- return "true";
- } else if (p_port == 1) {
- return "false";
- } else {
- return "done";
- }
-}
-
-PropertyInfo VisualScriptCondition::get_input_value_port_info(int p_idx) const {
- PropertyInfo pinfo;
- pinfo.name = "cond";
- pinfo.type = Variant::BOOL;
- return pinfo;
-}
-
-PropertyInfo VisualScriptCondition::get_output_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-String VisualScriptCondition::get_caption() const {
- return RTR("Condition");
-}
-
-String VisualScriptCondition::get_text() const {
- return RTR("if (cond) is:");
-}
-
-void VisualScriptCondition::_bind_methods() {
-}
-
-class VisualScriptNodeInstanceCondition : public VisualScriptNodeInstance {
-public:
- VisualScriptCondition *node = nullptr;
- VisualScriptInstance *instance = nullptr;
-
- //virtual int get_working_memory_size() const override { return 1; }
- //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
- //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- if (p_start_mode == START_MODE_CONTINUE_SEQUENCE) {
- return 2;
- } else if (p_inputs[0]->operator bool()) {
- return 0 | STEP_FLAG_PUSH_STACK_BIT;
- } else {
- return 1 | STEP_FLAG_PUSH_STACK_BIT;
- }
- }
-};
-
-VisualScriptNodeInstance *VisualScriptCondition::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceCondition *instance = memnew(VisualScriptNodeInstanceCondition);
- instance->node = this;
- instance->instance = p_instance;
- return instance;
-}
-
-VisualScriptCondition::VisualScriptCondition() {
-}
-
-//////////////////////////////////////////
-////////////////WHILE/////////////////
-//////////////////////////////////////////
-
-int VisualScriptWhile::get_output_sequence_port_count() const {
- return 2;
-}
-
-bool VisualScriptWhile::has_input_sequence_port() const {
- return true;
-}
-
-int VisualScriptWhile::get_input_value_port_count() const {
- return 1;
-}
-
-int VisualScriptWhile::get_output_value_port_count() const {
- return 0;
-}
-
-String VisualScriptWhile::get_output_sequence_port_text(int p_port) const {
- if (p_port == 0) {
- return "repeat";
- } else {
- return "exit";
- }
-}
-
-PropertyInfo VisualScriptWhile::get_input_value_port_info(int p_idx) const {
- PropertyInfo pinfo;
- pinfo.name = "cond";
- pinfo.type = Variant::BOOL;
- return pinfo;
-}
-
-PropertyInfo VisualScriptWhile::get_output_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-String VisualScriptWhile::get_caption() const {
- return RTR("While");
-}
-
-String VisualScriptWhile::get_text() const {
- return RTR("while (cond):");
-}
-
-void VisualScriptWhile::_bind_methods() {
-}
-
-class VisualScriptNodeInstanceWhile : public VisualScriptNodeInstance {
-public:
- VisualScriptWhile *node = nullptr;
- VisualScriptInstance *instance = nullptr;
-
- //virtual int get_working_memory_size() const override { return 1; }
- //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
- //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- bool keep_going = p_inputs[0]->operator bool();
-
- if (keep_going) {
- return 0 | STEP_FLAG_PUSH_STACK_BIT;
- } else {
- return 1;
- }
- }
-};
-
-VisualScriptNodeInstance *VisualScriptWhile::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceWhile *instance = memnew(VisualScriptNodeInstanceWhile);
- instance->node = this;
- instance->instance = p_instance;
- return instance;
-}
-
-VisualScriptWhile::VisualScriptWhile() {
-}
-
-//////////////////////////////////////////
-////////////////ITERATOR/////////////////
-//////////////////////////////////////////
-
-int VisualScriptIterator::get_output_sequence_port_count() const {
- return 2;
-}
-
-bool VisualScriptIterator::has_input_sequence_port() const {
- return true;
-}
-
-int VisualScriptIterator::get_input_value_port_count() const {
- return 1;
-}
-
-int VisualScriptIterator::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptIterator::get_output_sequence_port_text(int p_port) const {
- if (p_port == 0) {
- return "each";
- } else {
- return "exit";
- }
-}
-
-PropertyInfo VisualScriptIterator::get_input_value_port_info(int p_idx) const {
- PropertyInfo pinfo;
- pinfo.name = "input";
- pinfo.type = Variant::NIL;
- return pinfo;
-}
-
-PropertyInfo VisualScriptIterator::get_output_value_port_info(int p_idx) const {
- PropertyInfo pinfo;
- pinfo.name = "elem";
- pinfo.type = Variant::NIL;
- return pinfo;
-}
-
-String VisualScriptIterator::get_caption() const {
- return RTR("Iterator");
-}
-
-String VisualScriptIterator::get_text() const {
- return RTR("for (elem) in (input):");
-}
-
-void VisualScriptIterator::_bind_methods() {
-}
-
-class VisualScriptNodeInstanceIterator : public VisualScriptNodeInstance {
-public:
- VisualScriptIterator *node = nullptr;
- VisualScriptInstance *instance = nullptr;
-
- virtual int get_working_memory_size() const override { return 2; }
- //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
- //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- if (p_start_mode == START_MODE_BEGIN_SEQUENCE) {
- p_working_mem[0] = *p_inputs[0];
- bool valid;
- bool can_iter = p_inputs[0]->iter_init(p_working_mem[1], valid);
-
- if (!valid) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = RTR("Input type not iterable:") + " " + Variant::get_type_name(p_inputs[0]->get_type());
- return 0;
- }
-
- if (!can_iter) {
- return 1; //nothing to iterate
- }
-
- *p_outputs[0] = p_working_mem[0].iter_get(p_working_mem[1], valid);
-
- if (!valid) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = RTR("Iterator became invalid");
- return 0;
- }
-
- } else { //continue sequence
-
- bool valid;
- bool can_iter = p_working_mem[0].iter_next(p_working_mem[1], valid);
-
- if (!valid) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = RTR("Iterator became invalid:") + " " + Variant::get_type_name(p_inputs[0]->get_type());
- return 0;
- }
-
- if (!can_iter) {
- return 1; //nothing to iterate
- }
-
- *p_outputs[0] = p_working_mem[0].iter_get(p_working_mem[1], valid);
-
- if (!valid) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = RTR("Iterator became invalid");
- return 0;
- }
- }
-
- return 0 | STEP_FLAG_PUSH_STACK_BIT; //go around
- }
-};
-
-VisualScriptNodeInstance *VisualScriptIterator::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceIterator *instance = memnew(VisualScriptNodeInstanceIterator);
- instance->node = this;
- instance->instance = p_instance;
- return instance;
-}
-
-VisualScriptIterator::VisualScriptIterator() {
-}
-
-//////////////////////////////////////////
-////////////////SEQUENCE/////////////////
-//////////////////////////////////////////
-
-int VisualScriptSequence::get_output_sequence_port_count() const {
- return steps;
-}
-
-bool VisualScriptSequence::has_input_sequence_port() const {
- return true;
-}
-
-int VisualScriptSequence::get_input_value_port_count() const {
- return 0;
-}
-
-int VisualScriptSequence::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptSequence::get_output_sequence_port_text(int p_port) const {
- return itos(p_port + 1);
-}
-
-PropertyInfo VisualScriptSequence::get_input_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-PropertyInfo VisualScriptSequence::get_output_value_port_info(int p_idx) const {
- return PropertyInfo(Variant::INT, "current");
-}
-
-String VisualScriptSequence::get_caption() const {
- return RTR("Sequence");
-}
-
-String VisualScriptSequence::get_text() const {
- return RTR("in order:");
-}
-
-void VisualScriptSequence::set_steps(int p_steps) {
- ERR_FAIL_COND(p_steps < 1);
- if (steps == p_steps) {
- return;
- }
-
- steps = p_steps;
- ports_changed_notify();
-}
-
-int VisualScriptSequence::get_steps() const {
- return steps;
-}
-
-void VisualScriptSequence::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_steps", "steps"), &VisualScriptSequence::set_steps);
- ClassDB::bind_method(D_METHOD("get_steps"), &VisualScriptSequence::get_steps);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "steps", PROPERTY_HINT_RANGE, "1,64,1"), "set_steps", "get_steps");
-}
-
-class VisualScriptNodeInstanceSequence : public VisualScriptNodeInstance {
-public:
- VisualScriptSequence *node = nullptr;
- VisualScriptInstance *instance = nullptr;
- int steps = 0;
-
- virtual int get_working_memory_size() const override { return 1; }
- //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
- //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- if (p_start_mode == START_MODE_BEGIN_SEQUENCE) {
- p_working_mem[0] = 0;
- }
-
- int step = p_working_mem[0];
-
- *p_outputs[0] = step;
-
- if (step + 1 == steps) {
- return step;
- } else {
- p_working_mem[0] = step + 1;
- return step | STEP_FLAG_PUSH_STACK_BIT;
- }
- }
-};
-
-VisualScriptNodeInstance *VisualScriptSequence::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceSequence *instance = memnew(VisualScriptNodeInstanceSequence);
- instance->node = this;
- instance->instance = p_instance;
- instance->steps = steps;
- return instance;
-}
-
-VisualScriptSequence::VisualScriptSequence() {
- steps = 1;
-}
-
-//////////////////////////////////////////
-////////////////EVENT TYPE FILTER///////////
-//////////////////////////////////////////
-
-int VisualScriptSwitch::get_output_sequence_port_count() const {
- return case_values.size() + 1;
-}
-
-bool VisualScriptSwitch::has_input_sequence_port() const {
- return true;
-}
-
-int VisualScriptSwitch::get_input_value_port_count() const {
- return case_values.size() + 1;
-}
-
-int VisualScriptSwitch::get_output_value_port_count() const {
- return 0;
-}
-
-String VisualScriptSwitch::get_output_sequence_port_text(int p_port) const {
- if (p_port == case_values.size()) {
- return "done";
- }
-
- return String();
-}
-
-PropertyInfo VisualScriptSwitch::get_input_value_port_info(int p_idx) const {
- if (p_idx < case_values.size()) {
- return PropertyInfo(case_values[p_idx].type, " =");
- } else {
- return PropertyInfo(Variant::NIL, "input");
- }
-}
-
-PropertyInfo VisualScriptSwitch::get_output_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-String VisualScriptSwitch::get_caption() const {
- return RTR("Switch");
-}
-
-String VisualScriptSwitch::get_text() const {
- return RTR("'input' is:");
-}
-
-class VisualScriptNodeInstanceSwitch : public VisualScriptNodeInstance {
-public:
- VisualScriptInstance *instance = nullptr;
- int case_count = 0;
-
- //virtual int get_working_memory_size() const override { return 0; }
- //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
- //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- if (p_start_mode == START_MODE_CONTINUE_SEQUENCE) {
- return case_count; //exit
- }
-
- for (int i = 0; i < case_count; i++) {
- if (*p_inputs[i] == *p_inputs[case_count]) {
- return i | STEP_FLAG_PUSH_STACK_BIT;
- }
- }
-
- return case_count;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptSwitch::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceSwitch *instance = memnew(VisualScriptNodeInstanceSwitch);
- instance->instance = p_instance;
- instance->case_count = case_values.size();
- return instance;
-}
-
-bool VisualScriptSwitch::_set(const StringName &p_name, const Variant &p_value) {
- if (String(p_name) == "case_count") {
- case_values.resize(p_value);
- notify_property_list_changed();
- ports_changed_notify();
- return true;
- }
-
- if (String(p_name).begins_with("case/")) {
- int idx = String(p_name).get_slice("/", 1).to_int();
- ERR_FAIL_INDEX_V(idx, case_values.size(), false);
-
- case_values.write[idx].type = Variant::Type(int(p_value));
- notify_property_list_changed();
- ports_changed_notify();
-
- return true;
- }
-
- return false;
-}
-
-bool VisualScriptSwitch::_get(const StringName &p_name, Variant &r_ret) const {
- if (String(p_name) == "case_count") {
- r_ret = case_values.size();
- return true;
- }
-
- if (String(p_name).begins_with("case/")) {
- int idx = String(p_name).get_slice("/", 1).to_int();
- ERR_FAIL_INDEX_V(idx, case_values.size(), false);
-
- r_ret = case_values[idx].type;
- return true;
- }
-
- return false;
-}
-
-void VisualScriptSwitch::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::INT, "case_count", PROPERTY_HINT_RANGE, "0,128"));
-
- String argt = "Any";
- for (int i = 1; i < Variant::VARIANT_MAX; i++) {
- argt += "," + Variant::get_type_name(Variant::Type(i));
- }
-
- for (int i = 0; i < case_values.size(); i++) {
- p_list->push_back(PropertyInfo(Variant::INT, "case/" + itos(i), PROPERTY_HINT_ENUM, argt));
- }
-}
-
-void VisualScriptSwitch::reset_state() {
- case_values.clear();
-}
-
-void VisualScriptSwitch::_bind_methods() {
-}
-
-VisualScriptSwitch::VisualScriptSwitch() {
-}
-
-//////////////////////////////////////////
-////////////////TYPE CAST///////////
-//////////////////////////////////////////
-
-int VisualScriptTypeCast::get_output_sequence_port_count() const {
- return 2;
-}
-
-bool VisualScriptTypeCast::has_input_sequence_port() const {
- return true;
-}
-
-int VisualScriptTypeCast::get_input_value_port_count() const {
- return 1;
-}
-
-int VisualScriptTypeCast::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptTypeCast::get_output_sequence_port_text(int p_port) const {
- return p_port == 0 ? "yes" : "no";
-}
-
-PropertyInfo VisualScriptTypeCast::get_input_value_port_info(int p_idx) const {
- return PropertyInfo(Variant::OBJECT, "instance");
-}
-
-PropertyInfo VisualScriptTypeCast::get_output_value_port_info(int p_idx) const {
- return PropertyInfo(Variant::OBJECT, "", PROPERTY_HINT_TYPE_STRING, get_base_type());
-}
-
-String VisualScriptTypeCast::get_caption() const {
- return RTR("Type Cast");
-}
-
-String VisualScriptTypeCast::get_text() const {
- if (!script.is_empty()) {
- return vformat(RTR("Is %s?"), script.get_file());
- } else {
- return vformat(RTR("Is %s?"), base_type);
- }
-}
-
-void VisualScriptTypeCast::set_base_type(const StringName &p_type) {
- if (base_type == p_type) {
- return;
- }
-
- base_type = p_type;
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-StringName VisualScriptTypeCast::get_base_type() const {
- return base_type;
-}
-
-void VisualScriptTypeCast::set_base_script(const String &p_path) {
- if (script == p_path) {
- return;
- }
-
- script = p_path;
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-String VisualScriptTypeCast::get_base_script() const {
- return script;
-}
-
-VisualScriptTypeCast::TypeGuess VisualScriptTypeCast::guess_output_type(TypeGuess *p_inputs, int p_output) const {
- TypeGuess tg;
- tg.type = Variant::OBJECT;
- if (!script.is_empty()) {
- tg.script = ResourceLoader::load(script);
- }
- //if (!tg.script.is_valid()) {
- // tg.gdclass = base_type;
- //}
-
- return tg;
-}
-
-class VisualScriptNodeInstanceTypeCast : public VisualScriptNodeInstance {
-public:
- VisualScriptInstance *instance = nullptr;
- StringName base_type;
- String script;
-
- //virtual int get_working_memory_size() const override { return 0; }
- //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
- //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- Object *obj = *p_inputs[0];
-
- *p_outputs[0] = Variant();
-
- if (!obj) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = "Instance is null";
- return 0;
- }
-
- if (!script.is_empty()) {
- Ref<Script> obj_script = obj->get_script();
- if (!obj_script.is_valid()) {
- return 1; //well, definitely not the script because object we got has no script.
- }
-
- if (!ResourceCache::has(script)) {
- //if the script is not in use by anyone, we can safely assume whatever we got is not casting to it.
- return 1;
- }
- Ref<Script> cast_script = ResourceCache::get_ref(script);
- if (!cast_script.is_valid()) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = "Script path is not a script: " + script;
- return 1;
- }
-
- while (obj_script.is_valid()) {
- if (cast_script == obj_script) {
- *p_outputs[0] = *p_inputs[0]; //copy
- return 0; // it is the script, yey
- }
-
- obj_script = obj_script->get_base_script();
- }
-
- return 1; //not found sorry
- }
-
- if (ClassDB::is_parent_class(obj->get_class_name(), base_type)) {
- *p_outputs[0] = *p_inputs[0]; //copy
- return 0;
- } else {
- return 1;
- }
- }
-};
-
-VisualScriptNodeInstance *VisualScriptTypeCast::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceTypeCast *instance = memnew(VisualScriptNodeInstanceTypeCast);
- instance->instance = p_instance;
- instance->base_type = base_type;
- instance->script = script;
- return instance;
-}
-
-void VisualScriptTypeCast::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_base_type", "type"), &VisualScriptTypeCast::set_base_type);
- ClassDB::bind_method(D_METHOD("get_base_type"), &VisualScriptTypeCast::get_base_type);
-
- ClassDB::bind_method(D_METHOD("set_base_script", "path"), &VisualScriptTypeCast::set_base_script);
- ClassDB::bind_method(D_METHOD("get_base_script"), &VisualScriptTypeCast::get_base_script);
-
- List<String> script_extensions;
- for (int i = 0; i > ScriptServer::get_language_count(); i++) {
- ScriptServer::get_language(i)->get_recognized_extensions(&script_extensions);
- }
-
- String script_ext_hint;
- for (const String &E : script_extensions) {
- if (!script_ext_hint.is_empty()) {
- script_ext_hint += ",";
- }
- script_ext_hint += "*." + E;
- }
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script");
-}
-
-VisualScriptTypeCast::VisualScriptTypeCast() {
- base_type = "Object";
-}
-
-void register_visual_script_flow_control_nodes() {
- VisualScriptLanguage::singleton->add_register_func("flow_control/return", create_return_node<false>);
- VisualScriptLanguage::singleton->add_register_func("flow_control/return_with_value", create_return_node<true>);
- VisualScriptLanguage::singleton->add_register_func("flow_control/condition", create_node_generic<VisualScriptCondition>);
- VisualScriptLanguage::singleton->add_register_func("flow_control/while", create_node_generic<VisualScriptWhile>);
- VisualScriptLanguage::singleton->add_register_func("flow_control/iterator", create_node_generic<VisualScriptIterator>);
- VisualScriptLanguage::singleton->add_register_func("flow_control/sequence", create_node_generic<VisualScriptSequence>);
- VisualScriptLanguage::singleton->add_register_func("flow_control/switch", create_node_generic<VisualScriptSwitch>);
- //VisualScriptLanguage::singleton->add_register_func("flow_control/input", create_node_generic<VisualScriptInputFilter>);
- VisualScriptLanguage::singleton->add_register_func("flow_control/type_cast", create_node_generic<VisualScriptTypeCast>);
-}
diff --git a/modules/visual_script/visual_script_flow_control.h b/modules/visual_script/visual_script_flow_control.h
deleted file mode 100644
index 7ffdf3df65..0000000000
--- a/modules/visual_script/visual_script_flow_control.h
+++ /dev/null
@@ -1,268 +0,0 @@
-/*************************************************************************/
-/* visual_script_flow_control.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef VISUAL_SCRIPT_FLOW_CONTROL_H
-#define VISUAL_SCRIPT_FLOW_CONTROL_H
-
-#include "visual_script.h"
-
-class VisualScriptReturn : public VisualScriptNode {
- GDCLASS(VisualScriptReturn, VisualScriptNode);
-
- Variant::Type type;
- bool with_value;
-
-protected:
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_text() const override;
- virtual String get_category() const override { return "flow_control"; }
-
- void set_return_type(Variant::Type);
- Variant::Type get_return_type() const;
-
- void set_enable_return_value(bool p_enable);
- bool is_return_value_enabled() const;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptReturn();
-};
-
-class VisualScriptCondition : public VisualScriptNode {
- GDCLASS(VisualScriptCondition, VisualScriptNode);
-
-protected:
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_text() const override;
- virtual String get_category() const override { return "flow_control"; }
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptCondition();
-};
-
-class VisualScriptWhile : public VisualScriptNode {
- GDCLASS(VisualScriptWhile, VisualScriptNode);
-
-protected:
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_text() const override;
- virtual String get_category() const override { return "flow_control"; }
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptWhile();
-};
-
-class VisualScriptIterator : public VisualScriptNode {
- GDCLASS(VisualScriptIterator, VisualScriptNode);
-
-protected:
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_text() const override;
- virtual String get_category() const override { return "flow_control"; }
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptIterator();
-};
-
-class VisualScriptSequence : public VisualScriptNode {
- GDCLASS(VisualScriptSequence, VisualScriptNode);
-
- int steps;
-
-protected:
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_text() const override;
- virtual String get_category() const override { return "flow_control"; }
-
- void set_steps(int p_steps);
- int get_steps() const;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptSequence();
-};
-
-class VisualScriptSwitch : public VisualScriptNode {
- GDCLASS(VisualScriptSwitch, VisualScriptNode);
-
- struct Case {
- Variant::Type type;
- Case() { type = Variant::NIL; }
- };
-
- Vector<Case> case_values;
-
- friend class VisualScriptNodeInstanceSwitch;
-
-protected:
- bool _set(const StringName &p_name, const Variant &p_value);
- bool _get(const StringName &p_name, Variant &r_ret) const;
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
- static void _bind_methods();
-
-public:
- virtual void reset_state() override;
-
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
- virtual bool has_mixed_input_and_sequence_ports() const override { return true; }
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_text() const override;
- virtual String get_category() const override { return "flow_control"; }
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptSwitch();
-};
-
-class VisualScriptTypeCast : public VisualScriptNode {
- GDCLASS(VisualScriptTypeCast, VisualScriptNode);
-
- StringName base_type;
- String script;
-
-protected:
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_text() const override;
- virtual String get_category() const override { return "flow_control"; }
-
- void set_base_type(const StringName &p_type);
- StringName get_base_type() const;
-
- void set_base_script(const String &p_path);
- String get_base_script() const;
-
- virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptTypeCast();
-};
-
-void register_visual_script_flow_control_nodes();
-
-#endif // VISUAL_SCRIPT_FLOW_CONTROL_H
diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp
deleted file mode 100644
index b16358ae38..0000000000
--- a/modules/visual_script/visual_script_func_nodes.cpp
+++ /dev/null
@@ -1,2444 +0,0 @@
-/*************************************************************************/
-/* visual_script_func_nodes.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "visual_script_func_nodes.h"
-
-#include "core/config/engine.h"
-#include "core/io/resource_loader.h"
-#include "core/os/os.h"
-#include "core/templates/local_vector.h"
-#include "scene/main/node.h"
-#include "scene/main/scene_tree.h"
-#include "visual_script_nodes.h"
-
-//////////////////////////////////////////
-////////////////CALL//////////////////////
-//////////////////////////////////////////
-
-int VisualScriptFunctionCall::get_output_sequence_port_count() const {
- if ((method_cache.flags & METHOD_FLAG_CONST && call_mode != CALL_MODE_INSTANCE) || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_builtin_method_const(basic_type, function))) {
- return 0;
- } else {
- return 1;
- }
-}
-
-bool VisualScriptFunctionCall::has_input_sequence_port() const {
- return !((method_cache.flags & METHOD_FLAG_CONST && call_mode != CALL_MODE_INSTANCE) || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_builtin_method_const(basic_type, function)));
-}
-#ifdef TOOLS_ENABLED
-
-static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) {
- if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene) {
- return nullptr;
- }
-
- Ref<Script> scr = p_current_node->get_script();
-
- if (scr.is_valid() && scr == script) {
- return p_current_node;
- }
-
- for (int i = 0; i < p_current_node->get_child_count(); i++) {
- Node *n = _find_script_node(p_edited_scene, p_current_node->get_child(i), script);
- if (n) {
- return n;
- }
- }
-
- return nullptr;
-}
-
-#endif
-Node *VisualScriptFunctionCall::_get_base_node() const {
-#ifdef TOOLS_ENABLED
- Ref<Script> script = get_visual_script();
- if (!script.is_valid()) {
- return nullptr;
- }
-
- MainLoop *main_loop = OS::get_singleton()->get_main_loop();
- SceneTree *scene_tree = Object::cast_to<SceneTree>(main_loop);
-
- if (!scene_tree) {
- return nullptr;
- }
-
- Node *edited_scene = scene_tree->get_edited_scene_root();
-
- if (!edited_scene) {
- return nullptr;
- }
-
- Node *script_node = _find_script_node(edited_scene, edited_scene, script);
-
- if (!script_node) {
- return nullptr;
- }
-
- if (!script_node->has_node(base_path)) {
- return nullptr;
- }
-
- Node *path_to = script_node->get_node(base_path);
-
- return path_to;
-#else
-
- return nullptr;
-#endif
-}
-
-StringName VisualScriptFunctionCall::_get_base_type() const {
- if (call_mode == CALL_MODE_SELF && get_visual_script().is_valid()) {
- return get_visual_script()->get_instance_base_type();
- } else if (call_mode == CALL_MODE_NODE_PATH && get_visual_script().is_valid()) {
- Node *path = _get_base_node();
- if (path) {
- return path->get_class();
- }
- }
-
- return base_type;
-}
-
-int VisualScriptFunctionCall::get_input_value_port_count() const {
- if (call_mode == CALL_MODE_BASIC_TYPE) {
- Vector<Variant::Type> types;
- int argc = Variant::get_builtin_method_argument_count(basic_type, function);
- for (int i = 0; i < argc; i++) {
- types.push_back(Variant::get_builtin_method_argument_type(basic_type, function, i));
- }
- return types.size() + (rpc_call_mode >= RPC_RELIABLE_TO_ID ? 1 : 0) + 1;
-
- } else {
- MethodBind *mb = ClassDB::get_method(_get_base_type(), function);
- if (mb) {
- int defaulted_args = mb->get_argument_count() < use_default_args ? mb->get_argument_count() : use_default_args;
- return mb->get_argument_count() + (call_mode == CALL_MODE_INSTANCE ? 1 : 0) + (rpc_call_mode >= RPC_RELIABLE_TO_ID ? 1 : 0) - defaulted_args;
- }
-
- int defaulted_args = method_cache.arguments.size() < use_default_args ? method_cache.arguments.size() : use_default_args;
- return method_cache.arguments.size() + (call_mode == CALL_MODE_INSTANCE ? 1 : 0) + (rpc_call_mode >= RPC_RELIABLE_TO_ID ? 1 : 0) - defaulted_args;
- }
-}
-
-int VisualScriptFunctionCall::get_output_value_port_count() const {
- if (call_mode == CALL_MODE_BASIC_TYPE) {
- bool returns = Variant::has_builtin_method_return_value(basic_type, function);
- return returns ? 1 : 0;
-
- } else {
- int ret;
- MethodBind *mb = ClassDB::get_method(_get_base_type(), function);
- if (mb) {
- ret = mb->has_return() ? 1 : 0;
- } else {
- ret = 1; //it is assumed that script always returns something
- }
-
- if (call_mode == CALL_MODE_INSTANCE) {
- ret++;
- }
-
- return ret;
- }
-}
-
-String VisualScriptFunctionCall::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptFunctionCall::get_input_value_port_info(int p_idx) const {
- if (call_mode == CALL_MODE_INSTANCE || call_mode == CALL_MODE_BASIC_TYPE) {
- if (p_idx == 0) {
- PropertyInfo pi;
- pi.type = (call_mode == CALL_MODE_INSTANCE ? Variant::OBJECT : basic_type);
- pi.name = (call_mode == CALL_MODE_INSTANCE ? String("instance") : Variant::get_type_name(basic_type).to_lower());
- return pi;
- } else {
- p_idx--;
- }
- }
-
- if (rpc_call_mode >= RPC_RELIABLE_TO_ID) {
- if (p_idx == 0) {
- return PropertyInfo(Variant::INT, "peer_id");
- } else {
- p_idx--;
- }
- }
-
-#ifdef DEBUG_METHODS_ENABLED
-
- if (call_mode == CALL_MODE_BASIC_TYPE) {
- return PropertyInfo(Variant::get_builtin_method_argument_type(basic_type, function, p_idx), Variant::get_builtin_method_argument_name(basic_type, function, p_idx));
- } else {
- MethodBind *mb = ClassDB::get_method(_get_base_type(), function);
- if (mb) {
- return mb->get_argument_info(p_idx);
- }
-
- if (p_idx >= 0 && p_idx < method_cache.arguments.size()) {
- return method_cache.arguments[p_idx];
- }
-
- return PropertyInfo();
- }
-#else
- return PropertyInfo();
-#endif
-}
-
-PropertyInfo VisualScriptFunctionCall::get_output_value_port_info(int p_idx) const {
-#ifdef DEBUG_METHODS_ENABLED
-
- if (call_mode == CALL_MODE_BASIC_TYPE) {
- return PropertyInfo(Variant::get_builtin_method_return_type(basic_type, function), "");
- } else {
- if (call_mode == CALL_MODE_INSTANCE) {
- if (p_idx == 0) {
- return PropertyInfo(Variant::OBJECT, "pass", PROPERTY_HINT_TYPE_STRING, get_base_type());
- } else {
- p_idx--;
- }
- }
-
- PropertyInfo ret;
-
- /*MethodBind *mb = ClassDB::get_method(_get_base_type(),function);
- if (mb) {
- ret = mb->get_argument_info(-1);
- } else {*/
-
- ret = method_cache.return_val;
-
- //}
-
- if (call_mode == CALL_MODE_INSTANCE) {
- ret.name = "return";
- } else {
- ret.name = "";
- }
- return ret;
- }
-#else
- return PropertyInfo();
-#endif
-}
-
-String VisualScriptFunctionCall::get_caption() const {
- return " " + String(function) + "()";
-}
-
-String VisualScriptFunctionCall::get_text() const {
- String text;
-
- if (call_mode == CALL_MODE_BASIC_TYPE) {
- text = vformat(RTR("On %s"), Variant::get_type_name(basic_type));
- } else if (call_mode == CALL_MODE_INSTANCE) {
- text = vformat(RTR("On %s"), base_type);
- } else if (call_mode == CALL_MODE_NODE_PATH) {
- text = "[" + String(base_path.simplified()) + "]";
- } else if (call_mode == CALL_MODE_SELF) {
- text = RTR("On Self");
- } else if (call_mode == CALL_MODE_SINGLETON) {
- text = String(singleton) + ":" + String(function) + "()";
- }
-
- if (rpc_call_mode) {
- text += " RPC";
- if (rpc_call_mode == RPC_UNRELIABLE || rpc_call_mode == RPC_UNRELIABLE_TO_ID) {
- text += " UNREL";
- }
- }
-
- return text;
-}
-
-void VisualScriptFunctionCall::set_basic_type(Variant::Type p_type) {
- if (basic_type == p_type) {
- return;
- }
- basic_type = p_type;
-
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-Variant::Type VisualScriptFunctionCall::get_basic_type() const {
- return basic_type;
-}
-
-void VisualScriptFunctionCall::set_base_type(const StringName &p_type) {
- if (base_type == p_type) {
- return;
- }
-
- base_type = p_type;
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-StringName VisualScriptFunctionCall::get_base_type() const {
- return base_type;
-}
-
-void VisualScriptFunctionCall::set_base_script(const String &p_path) {
- if (base_script == p_path) {
- return;
- }
-
- base_script = p_path;
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-String VisualScriptFunctionCall::get_base_script() const {
- return base_script;
-}
-
-void VisualScriptFunctionCall::set_singleton(const StringName &p_type) {
- if (singleton == p_type) {
- return;
- }
-
- singleton = p_type;
- Object *obj = Engine::get_singleton()->get_singleton_object(singleton);
- if (obj) {
- base_type = obj->get_class();
- }
-
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-StringName VisualScriptFunctionCall::get_singleton() const {
- return singleton;
-}
-
-void VisualScriptFunctionCall::_update_method_cache() {
- StringName type;
- Ref<Script> script;
-
- if (call_mode == CALL_MODE_NODE_PATH) {
- Node *node = _get_base_node();
- if (node) {
- type = node->get_class();
- base_type = type; //cache, too
- script = node->get_script();
- }
- } else if (call_mode == CALL_MODE_SELF) {
- if (get_visual_script().is_valid()) {
- type = get_visual_script()->get_instance_base_type();
- base_type = type; //cache, too
- script = get_visual_script();
- }
-
- } else if (call_mode == CALL_MODE_SINGLETON) {
- Object *obj = Engine::get_singleton()->get_singleton_object(singleton);
- if (obj) {
- type = obj->get_class();
- script = obj->get_script();
- }
-
- } else if (call_mode == CALL_MODE_INSTANCE) {
- type = base_type;
- if (!base_script.is_empty()) {
- if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) {
- ScriptServer::edit_request_func(base_script); //make sure it's loaded
- }
-
- if (ResourceCache::has(base_script)) {
- script = ResourceCache::get_ref(base_script);
- } else {
- return;
- }
- }
- }
-
- MethodBind *mb = ClassDB::get_method(type, function);
- if (mb) {
- use_default_args = mb->get_default_argument_count();
- method_cache = MethodInfo();
- for (int i = 0; i < mb->get_argument_count(); i++) {
-#ifdef DEBUG_METHODS_ENABLED
- method_cache.arguments.push_back(mb->get_argument_info(i));
-#else
- method_cache.arguments.push_back(PropertyInfo());
-#endif
- }
-
- if (mb->is_const()) {
- method_cache.flags |= METHOD_FLAG_CONST;
- }
-
-#ifdef DEBUG_METHODS_ENABLED
-
- method_cache.return_val = mb->get_return_info();
-#endif
-
- if (mb->is_vararg()) {
- //for vararg just give it 10 arguments (should be enough for most use cases)
- for (int i = 0; i < 10; i++) {
- method_cache.arguments.push_back(PropertyInfo(Variant::NIL, "arg" + itos(i)));
- use_default_args++;
- }
- }
- } else if (script.is_valid() && script->has_method(function)) {
- method_cache = script->get_method_info(function);
- use_default_args = method_cache.default_arguments.size();
- }
-}
-
-void VisualScriptFunctionCall::set_function(const StringName &p_type) {
- if (function == p_type) {
- return;
- }
-
- function = p_type;
-
- if (call_mode == CALL_MODE_BASIC_TYPE) {
- use_default_args = Variant::get_builtin_method_default_arguments(basic_type, function).size();
- } else {
- //update all caches
-
- _update_method_cache();
- }
-
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-StringName VisualScriptFunctionCall::get_function() const {
- return function;
-}
-
-void VisualScriptFunctionCall::set_base_path(const NodePath &p_type) {
- if (base_path == p_type) {
- return;
- }
-
- base_path = p_type;
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-NodePath VisualScriptFunctionCall::get_base_path() const {
- return base_path;
-}
-
-void VisualScriptFunctionCall::set_call_mode(CallMode p_mode) {
- if (call_mode == p_mode) {
- return;
- }
-
- call_mode = p_mode;
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-VisualScriptFunctionCall::CallMode VisualScriptFunctionCall::get_call_mode() const {
- return call_mode;
-}
-
-void VisualScriptFunctionCall::set_use_default_args(int p_amount) {
- if (use_default_args == p_amount) {
- return;
- }
-
- use_default_args = p_amount;
- ports_changed_notify();
-}
-
-void VisualScriptFunctionCall::set_rpc_call_mode(VisualScriptFunctionCall::RPCCallMode p_mode) {
- if (rpc_call_mode == p_mode) {
- return;
- }
- rpc_call_mode = p_mode;
- ports_changed_notify();
- notify_property_list_changed();
-}
-
-VisualScriptFunctionCall::RPCCallMode VisualScriptFunctionCall::get_rpc_call_mode() const {
- return rpc_call_mode;
-}
-
-int VisualScriptFunctionCall::get_use_default_args() const {
- return use_default_args;
-}
-
-void VisualScriptFunctionCall::set_validate(bool p_amount) {
- validate = p_amount;
-}
-
-bool VisualScriptFunctionCall::get_validate() const {
- return validate;
-}
-
-void VisualScriptFunctionCall::_set_argument_cache(const Dictionary &p_cache) {
- //so everything works in case all else fails
- method_cache = MethodInfo::from_dict(p_cache);
-}
-
-Dictionary VisualScriptFunctionCall::_get_argument_cache() const {
- return method_cache;
-}
-
-void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const {
- if (property.name == "base_type") {
- if (call_mode != CALL_MODE_INSTANCE) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
- }
- }
-
- if (property.name == "base_script") {
- if (call_mode != CALL_MODE_INSTANCE) {
- property.usage = PROPERTY_USAGE_NONE;
- }
- }
-
- if (property.name == "basic_type") {
- if (call_mode != CALL_MODE_BASIC_TYPE) {
- property.usage = PROPERTY_USAGE_NONE;
- }
- }
-
- if (property.name == "singleton") {
- if (call_mode != CALL_MODE_SINGLETON) {
- property.usage = PROPERTY_USAGE_NONE;
- } else {
- List<Engine::Singleton> names;
- Engine::get_singleton()->get_singletons(&names);
- property.hint = PROPERTY_HINT_ENUM;
- String sl;
- for (const Engine::Singleton &E : names) {
- if (!sl.is_empty()) {
- sl += ",";
- }
- sl += E.name;
- }
- property.hint_string = sl;
- }
- }
-
- if (property.name == "node_path") {
- if (call_mode != CALL_MODE_NODE_PATH) {
- property.usage = PROPERTY_USAGE_NONE;
- } else {
- Node *bnode = _get_base_node();
- if (bnode) {
- property.hint_string = bnode->get_path(); //convert to long string
- }
- }
- }
-
- if (property.name == "function") {
- if (call_mode == CALL_MODE_BASIC_TYPE) {
- property.hint = PROPERTY_HINT_METHOD_OF_VARIANT_TYPE;
- property.hint_string = Variant::get_type_name(basic_type);
-
- } else if (call_mode == CALL_MODE_SELF && get_visual_script().is_valid()) {
- property.hint = PROPERTY_HINT_METHOD_OF_SCRIPT;
- property.hint_string = itos(get_visual_script()->get_instance_id());
- } else if (call_mode == CALL_MODE_SINGLETON) {
- Object *obj = Engine::get_singleton()->get_singleton_object(singleton);
- if (obj) {
- property.hint = PROPERTY_HINT_METHOD_OF_INSTANCE;
- property.hint_string = itos(obj->get_instance_id());
- } else {
- property.hint = PROPERTY_HINT_METHOD_OF_BASE_TYPE;
- property.hint_string = base_type; //should be cached
- }
- } else if (call_mode == CALL_MODE_INSTANCE) {
- property.hint = PROPERTY_HINT_METHOD_OF_BASE_TYPE;
- property.hint_string = base_type;
-
- if (!base_script.is_empty()) {
- if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) {
- ScriptServer::edit_request_func(base_script); //make sure it's loaded
- }
-
- if (ResourceCache::has(base_script)) {
- Ref<Script> script = ResourceCache::get_ref(base_script);
- if (script.is_valid()) {
- property.hint = PROPERTY_HINT_METHOD_OF_SCRIPT;
- property.hint_string = itos(script->get_instance_id());
- }
- }
- }
-
- } else if (call_mode == CALL_MODE_NODE_PATH) {
- Node *node = _get_base_node();
- if (node) {
- property.hint = PROPERTY_HINT_METHOD_OF_INSTANCE;
- property.hint_string = itos(node->get_instance_id());
- } else {
- property.hint = PROPERTY_HINT_METHOD_OF_BASE_TYPE;
- property.hint_string = get_base_type();
- }
- }
- }
-
- if (property.name == "use_default_args") {
- property.hint = PROPERTY_HINT_RANGE;
-
- int mc = 0;
-
- if (call_mode == CALL_MODE_BASIC_TYPE) {
- mc = Variant::get_builtin_method_default_arguments(basic_type, function).size();
- } else {
- MethodBind *mb = ClassDB::get_method(_get_base_type(), function);
- if (mb) {
- mc = mb->get_default_argument_count();
- }
- }
-
- if (mc == 0) {
- property.usage = PROPERTY_USAGE_NONE; //do not show
- } else {
- property.hint_string = "0," + itos(mc) + ",1";
- }
- }
-
- if (property.name == "rpc_call_mode") {
- if (call_mode == CALL_MODE_BASIC_TYPE) {
- property.usage = PROPERTY_USAGE_NONE;
- }
- }
-}
-
-void VisualScriptFunctionCall::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_base_type", "base_type"), &VisualScriptFunctionCall::set_base_type);
- ClassDB::bind_method(D_METHOD("get_base_type"), &VisualScriptFunctionCall::get_base_type);
-
- ClassDB::bind_method(D_METHOD("set_base_script", "base_script"), &VisualScriptFunctionCall::set_base_script);
- ClassDB::bind_method(D_METHOD("get_base_script"), &VisualScriptFunctionCall::get_base_script);
-
- ClassDB::bind_method(D_METHOD("set_basic_type", "basic_type"), &VisualScriptFunctionCall::set_basic_type);
- ClassDB::bind_method(D_METHOD("get_basic_type"), &VisualScriptFunctionCall::get_basic_type);
-
- ClassDB::bind_method(D_METHOD("set_singleton", "singleton"), &VisualScriptFunctionCall::set_singleton);
- ClassDB::bind_method(D_METHOD("get_singleton"), &VisualScriptFunctionCall::get_singleton);
-
- ClassDB::bind_method(D_METHOD("set_function", "function"), &VisualScriptFunctionCall::set_function);
- ClassDB::bind_method(D_METHOD("get_function"), &VisualScriptFunctionCall::get_function);
-
- ClassDB::bind_method(D_METHOD("set_call_mode", "mode"), &VisualScriptFunctionCall::set_call_mode);
- ClassDB::bind_method(D_METHOD("get_call_mode"), &VisualScriptFunctionCall::get_call_mode);
-
- ClassDB::bind_method(D_METHOD("set_base_path", "base_path"), &VisualScriptFunctionCall::set_base_path);
- ClassDB::bind_method(D_METHOD("get_base_path"), &VisualScriptFunctionCall::get_base_path);
-
- ClassDB::bind_method(D_METHOD("set_use_default_args", "amount"), &VisualScriptFunctionCall::set_use_default_args);
- ClassDB::bind_method(D_METHOD("get_use_default_args"), &VisualScriptFunctionCall::get_use_default_args);
-
- ClassDB::bind_method(D_METHOD("_set_argument_cache", "argument_cache"), &VisualScriptFunctionCall::_set_argument_cache);
- ClassDB::bind_method(D_METHOD("_get_argument_cache"), &VisualScriptFunctionCall::_get_argument_cache);
-
- ClassDB::bind_method(D_METHOD("set_rpc_call_mode", "mode"), &VisualScriptFunctionCall::set_rpc_call_mode);
- ClassDB::bind_method(D_METHOD("get_rpc_call_mode"), &VisualScriptFunctionCall::get_rpc_call_mode);
-
- ClassDB::bind_method(D_METHOD("set_validate", "enable"), &VisualScriptFunctionCall::set_validate);
- ClassDB::bind_method(D_METHOD("get_validate"), &VisualScriptFunctionCall::get_validate);
-
- String bt;
- for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- if (i > 0) {
- bt += ",";
- }
-
- bt += Variant::get_type_name(Variant::Type(i));
- }
-
- List<String> script_extensions;
- for (int i = 0; i < ScriptServer::get_language_count(); i++) {
- ScriptServer::get_language(i)->get_recognized_extensions(&script_extensions);
- }
-
- String script_ext_hint;
- for (const String &E : script_extensions) {
- if (!script_ext_hint.is_empty()) {
- script_ext_hint += ",";
- }
- script_ext_hint += "*." + E;
- }
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "call_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type,Singleton"), "set_call_mode", "get_call_mode");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "singleton"), "set_singleton", "get_singleton");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "basic_type", PROPERTY_HINT_ENUM, bt), "set_basic_type", "get_basic_type");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path");
- ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "argument_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_argument_cache", "_get_argument_cache");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "function"), "set_function", "get_function"); //when set, if loaded properly, will override argument count.
- ADD_PROPERTY(PropertyInfo(Variant::INT, "use_default_args"), "set_use_default_args", "get_use_default_args");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "validate"), "set_validate", "get_validate");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "rpc_call_mode", PROPERTY_HINT_ENUM, "Disabled,Reliable,Unreliable,ReliableToID,UnreliableToID"), "set_rpc_call_mode", "get_rpc_call_mode"); //when set, if loaded properly, will override argument count.
-
- BIND_ENUM_CONSTANT(CALL_MODE_SELF);
- BIND_ENUM_CONSTANT(CALL_MODE_NODE_PATH);
- BIND_ENUM_CONSTANT(CALL_MODE_INSTANCE);
- BIND_ENUM_CONSTANT(CALL_MODE_BASIC_TYPE);
- BIND_ENUM_CONSTANT(CALL_MODE_SINGLETON);
-
- BIND_ENUM_CONSTANT(RPC_DISABLED);
- BIND_ENUM_CONSTANT(RPC_RELIABLE);
- BIND_ENUM_CONSTANT(RPC_UNRELIABLE);
- BIND_ENUM_CONSTANT(RPC_RELIABLE_TO_ID);
- BIND_ENUM_CONSTANT(RPC_UNRELIABLE_TO_ID);
-}
-
-class VisualScriptNodeInstanceFunctionCall : public VisualScriptNodeInstance {
-public:
- VisualScriptFunctionCall::CallMode call_mode;
- NodePath node_path;
- int input_args = 0;
- bool validate = false;
- int returns = 0;
- VisualScriptFunctionCall::RPCCallMode rpc_mode;
- StringName function;
- StringName singleton;
-
- VisualScriptFunctionCall *node = nullptr;
- VisualScriptInstance *instance = nullptr;
-
- //virtual int get_working_memory_size() const override { return 0; }
- //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
- //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
-
- _FORCE_INLINE_ bool call_rpc(Object *p_base, const Variant **p_args, int p_argcount) {
- if (!p_base) {
- return false;
- }
-
- Node *node = Object::cast_to<Node>(p_base);
- if (!node) {
- return false;
- }
-
- int to_id = 0;
- //bool reliable = true;
-
- if (rpc_mode >= VisualScriptFunctionCall::RPC_RELIABLE_TO_ID) {
- to_id = *p_args[0];
- p_args += 1;
- p_argcount -= 1;
- //if (rpc_mode == VisualScriptFunctionCall::RPC_UNRELIABLE_TO_ID) {
- //reliable = false;
- //}
- }
- //else if (rpc_mode == VisualScriptFunctionCall::RPC_UNRELIABLE) {
- //reliable = false;
- //}
-
- // TODO reliable?
- node->rpcp(to_id, function, p_args, p_argcount);
-
- return true;
- }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- switch (call_mode) {
- case VisualScriptFunctionCall::CALL_MODE_SELF: {
- Object *object = instance->get_owner_ptr();
-
- if (rpc_mode) {
- call_rpc(object, p_inputs, input_args);
- } else if (returns) {
- *p_outputs[0] = object->callp(function, p_inputs, input_args, r_error);
- } else {
- object->callp(function, p_inputs, input_args, r_error);
- }
- } break;
- case VisualScriptFunctionCall::CALL_MODE_NODE_PATH: {
- Node *node = Object::cast_to<Node>(instance->get_owner_ptr());
- if (!node) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = "Base object is not a Node!";
- return 0;
- }
-
- Node *another = node->get_node(node_path);
- if (!another) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = "Path does not lead Node!";
- return 0;
- }
-
- if (rpc_mode) {
- call_rpc(node, p_inputs, input_args);
- } else if (returns) {
- *p_outputs[0] = another->callp(function, p_inputs, input_args, r_error);
- } else {
- another->callp(function, p_inputs, input_args, r_error);
- }
-
- } break;
- case VisualScriptFunctionCall::CALL_MODE_INSTANCE:
- case VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE: {
- Variant v = *p_inputs[0];
-
- if (rpc_mode) {
- Object *obj = v;
- if (obj) {
- call_rpc(obj, p_inputs + 1, input_args - 1);
- }
- } else if (returns) {
- if (call_mode == VisualScriptFunctionCall::CALL_MODE_INSTANCE) {
- if (returns >= 2) {
- v.callp(function, p_inputs + 1, input_args, *p_outputs[1], r_error);
- } else if (returns == 1) {
- Variant ret;
- v.callp(function, p_inputs + 1, input_args, ret, r_error);
- } else {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = "Invalid returns count for call_mode == CALL_MODE_INSTANCE";
- return 0;
- }
- } else {
- v.callp(function, p_inputs + 1, input_args, *p_outputs[0], r_error);
- }
- } else {
- Variant ret;
- v.callp(function, p_inputs + 1, input_args, ret, r_error);
- }
-
- if (call_mode == VisualScriptFunctionCall::CALL_MODE_INSTANCE) {
- *p_outputs[0] = *p_inputs[0];
- }
-
- } break;
- case VisualScriptFunctionCall::CALL_MODE_SINGLETON: {
- Object *object = Engine::get_singleton()->get_singleton_object(singleton);
- if (!object) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = "Invalid singleton name: '" + String(singleton) + "'";
- return 0;
- }
-
- if (rpc_mode) {
- call_rpc(object, p_inputs, input_args);
- } else if (returns) {
- *p_outputs[0] = object->callp(function, p_inputs, input_args, r_error);
- } else {
- object->callp(function, p_inputs, input_args, r_error);
- }
- } break;
- }
-
- if (!validate) {
- //ignore call errors if validation is disabled
- r_error.error = Callable::CallError::CALL_OK;
- r_error_str = String();
- }
-
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptFunctionCall::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceFunctionCall *instance = memnew(VisualScriptNodeInstanceFunctionCall);
- instance->node = this;
- instance->instance = p_instance;
- instance->singleton = singleton;
- instance->function = function;
- instance->call_mode = call_mode;
- instance->returns = get_output_value_port_count();
- instance->node_path = base_path;
- instance->input_args = get_input_value_port_count() - ((call_mode == CALL_MODE_BASIC_TYPE || call_mode == CALL_MODE_INSTANCE) ? 1 : 0);
- instance->rpc_mode = rpc_call_mode;
- instance->validate = validate;
- return instance;
-}
-
-VisualScriptFunctionCall::TypeGuess VisualScriptFunctionCall::guess_output_type(TypeGuess *p_inputs, int p_output) const {
- if (p_output == 0 && call_mode == CALL_MODE_INSTANCE) {
- return p_inputs[0];
- }
-
- return VisualScriptNode::guess_output_type(p_inputs, p_output);
-}
-
-VisualScriptFunctionCall::VisualScriptFunctionCall() {
- validate = true;
- call_mode = CALL_MODE_SELF;
- basic_type = Variant::NIL;
- use_default_args = 0;
- base_type = "Object";
- rpc_call_mode = RPC_DISABLED;
-}
-
-template <VisualScriptFunctionCall::CallMode cmode>
-static Ref<VisualScriptNode> create_function_call_node(const String &p_name) {
- Ref<VisualScriptFunctionCall> node;
- node.instantiate();
- node->set_call_mode(cmode);
- return node;
-}
-
-//////////////////////////////////////////
-////////////////SET//////////////////////
-//////////////////////////////////////////
-
-int VisualScriptPropertySet::get_output_sequence_port_count() const {
- return 1;
-}
-
-bool VisualScriptPropertySet::has_input_sequence_port() const {
- return true;
-}
-
-Node *VisualScriptPropertySet::_get_base_node() const {
-#ifdef TOOLS_ENABLED
- Ref<Script> script = get_visual_script();
- if (!script.is_valid()) {
- return nullptr;
- }
-
- MainLoop *main_loop = OS::get_singleton()->get_main_loop();
-
- SceneTree *scene_tree = Object::cast_to<SceneTree>(main_loop);
-
- if (!scene_tree) {
- return nullptr;
- }
-
- Node *edited_scene = scene_tree->get_edited_scene_root();
-
- if (!edited_scene) {
- return nullptr;
- }
-
- Node *script_node = _find_script_node(edited_scene, edited_scene, script);
-
- if (!script_node) {
- return nullptr;
- }
-
- if (!script_node->has_node(base_path)) {
- return nullptr;
- }
-
- Node *path_to = script_node->get_node(base_path);
-
- return path_to;
-#else
-
- return nullptr;
-#endif
-}
-
-StringName VisualScriptPropertySet::_get_base_type() const {
- if (call_mode == CALL_MODE_SELF && get_visual_script().is_valid()) {
- return get_visual_script()->get_instance_base_type();
- } else if (call_mode == CALL_MODE_NODE_PATH && get_visual_script().is_valid()) {
- Node *path = _get_base_node();
- if (path) {
- return path->get_class();
- }
- }
-
- return base_type;
-}
-
-int VisualScriptPropertySet::get_input_value_port_count() const {
- int pc = (call_mode == CALL_MODE_BASIC_TYPE || call_mode == CALL_MODE_INSTANCE) ? 2 : 1;
-
- return pc;
-}
-
-int VisualScriptPropertySet::get_output_value_port_count() const {
- return (call_mode == CALL_MODE_BASIC_TYPE || call_mode == CALL_MODE_INSTANCE) ? 1 : 0;
-}
-
-String VisualScriptPropertySet::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-void VisualScriptPropertySet::_adjust_input_index(PropertyInfo &pinfo) const {
- if (index != StringName()) {
- Variant v;
- Callable::CallError ce;
- Variant::construct(pinfo.type, v, nullptr, 0, ce);
- Variant i = v.get(index);
- pinfo.type = i.get_type();
- }
-}
-
-PropertyInfo VisualScriptPropertySet::get_input_value_port_info(int p_idx) const {
- if (call_mode == CALL_MODE_INSTANCE || call_mode == CALL_MODE_BASIC_TYPE) {
- if (p_idx == 0) {
- PropertyInfo pi;
- pi.type = (call_mode == CALL_MODE_INSTANCE ? Variant::OBJECT : basic_type);
- pi.name = "instance";
- return pi;
- }
- }
-
- List<PropertyInfo> props;
- ClassDB::get_property_list(_get_base_type(), &props, false);
- for (const PropertyInfo &E : props) {
- if (E.name == property) {
- String detail_prop_name = property;
- if (index != StringName()) {
- detail_prop_name += "." + String(index);
- }
- PropertyInfo pinfo = PropertyInfo(E.type, detail_prop_name, E.hint, E.hint_string);
- _adjust_input_index(pinfo);
- return pinfo;
- }
- }
-
- PropertyInfo pinfo = type_cache;
- _adjust_input_index(pinfo);
- return pinfo;
-}
-
-PropertyInfo VisualScriptPropertySet::get_output_value_port_info(int p_idx) const {
- if (call_mode == CALL_MODE_BASIC_TYPE) {
- return PropertyInfo(basic_type, "pass");
- } else if (call_mode == CALL_MODE_INSTANCE) {
- return PropertyInfo(Variant::OBJECT, "pass", PROPERTY_HINT_TYPE_STRING, get_base_type());
- } else {
- return PropertyInfo();
- }
-}
-
-String VisualScriptPropertySet::get_caption() const {
- static const LocalVector<String> opname = {
- RTR("Set %s"),
- RTR("Add %s"),
- RTR("Subtract %s"),
- RTR("Multiply %s"),
- RTR("Divide %s"),
- RTR("Mod %s"),
- RTR("ShiftLeft %s"),
- RTR("ShiftRight %s"),
- RTR("BitAnd %s"),
- RTR("BitOr %s"),
- RTR("BitXor %s"),
- };
-
- String prop = property;
- if (index != StringName()) {
- prop += "." + String(index);
- }
-
- return vformat(opname[assign_op], prop);
-}
-
-String VisualScriptPropertySet::get_text() const {
- if (!has_input_sequence_port()) {
- return "";
- }
- if (call_mode == CALL_MODE_BASIC_TYPE) {
- return vformat(RTR("On %s"), Variant::get_type_name(basic_type));
- } else if (call_mode == CALL_MODE_INSTANCE) {
- return vformat(RTR("On %s"), base_type);
- } else if (call_mode == CALL_MODE_NODE_PATH) {
- return " [" + String(base_path.simplified()) + "]";
- } else {
- return RTR("On Self");
- }
-}
-
-void VisualScriptPropertySet::_update_base_type() {
- //cache it because this information may not be available on load
- if (call_mode == CALL_MODE_NODE_PATH) {
- Node *node = _get_base_node();
- if (node) {
- base_type = node->get_class();
- }
- } else if (call_mode == CALL_MODE_SELF) {
- if (get_visual_script().is_valid()) {
- base_type = get_visual_script()->get_instance_base_type();
- }
- }
-}
-
-void VisualScriptPropertySet::set_basic_type(Variant::Type p_type) {
- if (basic_type == p_type) {
- return;
- }
- basic_type = p_type;
-
- notify_property_list_changed();
- _update_base_type();
- ports_changed_notify();
-}
-
-Variant::Type VisualScriptPropertySet::get_basic_type() const {
- return basic_type;
-}
-
-void VisualScriptPropertySet::set_base_type(const StringName &p_type) {
- if (base_type == p_type) {
- return;
- }
-
- base_type = p_type;
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-StringName VisualScriptPropertySet::get_base_type() const {
- return base_type;
-}
-
-void VisualScriptPropertySet::set_base_script(const String &p_path) {
- if (base_script == p_path) {
- return;
- }
-
- base_script = p_path;
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-String VisualScriptPropertySet::get_base_script() const {
- return base_script;
-}
-
-void VisualScriptPropertySet::_update_cache() {
- if (!Object::cast_to<SceneTree>(OS::get_singleton()->get_main_loop())) {
- return;
- }
-
- if (!Engine::get_singleton()->is_editor_hint()) { //only update cache if editor exists, it's pointless otherwise
- return;
- }
-
- if (call_mode == CALL_MODE_BASIC_TYPE) {
- //not super efficient..
-
- Variant v;
- Callable::CallError ce;
- Variant::construct(basic_type, v, nullptr, 0, ce);
-
- List<PropertyInfo> pinfo;
- v.get_property_list(&pinfo);
-
- for (const PropertyInfo &E : pinfo) {
- if (E.name == property) {
- type_cache = E;
- }
- }
-
- } else {
- StringName type;
- Ref<Script> script;
- Node *node = nullptr;
-
- if (call_mode == CALL_MODE_NODE_PATH) {
- node = _get_base_node();
- if (node) {
- type = node->get_class();
- base_type = type; //cache, too
- script = node->get_script();
- }
- } else if (call_mode == CALL_MODE_SELF) {
- if (get_visual_script().is_valid()) {
- type = get_visual_script()->get_instance_base_type();
- base_type = type; //cache, too
- script = get_visual_script();
- }
- } else if (call_mode == CALL_MODE_INSTANCE) {
- type = base_type;
- if (!base_script.is_empty()) {
- if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) {
- ScriptServer::edit_request_func(base_script); //make sure it's loaded
- }
-
- if (ResourceCache::has(base_script)) {
- script = ResourceCache::get_ref(base_script);
- } else {
- return;
- }
- }
- }
-
- List<PropertyInfo> pinfo;
-
- if (node) {
- node->get_property_list(&pinfo);
- } else {
- ClassDB::get_property_list(type, &pinfo);
- }
-
- if (script.is_valid()) {
- script->get_script_property_list(&pinfo);
- }
-
- for (const PropertyInfo &E : pinfo) {
- if (E.name == property) {
- type_cache = E;
- return;
- }
- }
- }
-}
-
-void VisualScriptPropertySet::set_property(const StringName &p_type) {
- if (property == p_type) {
- return;
- }
-
- property = p_type;
- index = StringName();
- _update_cache();
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-StringName VisualScriptPropertySet::get_property() const {
- return property;
-}
-
-void VisualScriptPropertySet::set_base_path(const NodePath &p_type) {
- if (base_path == p_type) {
- return;
- }
-
- base_path = p_type;
- _update_base_type();
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-NodePath VisualScriptPropertySet::get_base_path() const {
- return base_path;
-}
-
-void VisualScriptPropertySet::set_call_mode(CallMode p_mode) {
- if (call_mode == p_mode) {
- return;
- }
-
- call_mode = p_mode;
- _update_base_type();
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-VisualScriptPropertySet::CallMode VisualScriptPropertySet::get_call_mode() const {
- return call_mode;
-}
-
-void VisualScriptPropertySet::_set_type_cache(const Dictionary &p_type) {
- type_cache = PropertyInfo::from_dict(p_type);
-}
-
-Dictionary VisualScriptPropertySet::_get_type_cache() const {
- return type_cache;
-}
-
-void VisualScriptPropertySet::set_index(const StringName &p_type) {
- if (index == p_type) {
- return;
- }
- index = p_type;
- _update_cache();
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-StringName VisualScriptPropertySet::get_index() const {
- return index;
-}
-
-void VisualScriptPropertySet::set_assign_op(AssignOp p_op) {
- ERR_FAIL_INDEX(p_op, ASSIGN_OP_MAX);
- if (assign_op == p_op) {
- return;
- }
-
- assign_op = p_op;
- _update_cache();
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-VisualScriptPropertySet::AssignOp VisualScriptPropertySet::get_assign_op() const {
- return assign_op;
-}
-
-void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const {
- if (property.name == "base_type") {
- if (call_mode != CALL_MODE_INSTANCE) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
- }
- }
-
- if (property.name == "base_script") {
- if (call_mode != CALL_MODE_INSTANCE) {
- property.usage = PROPERTY_USAGE_NONE;
- }
- }
-
- if (property.name == "basic_type") {
- if (call_mode != CALL_MODE_BASIC_TYPE) {
- property.usage = PROPERTY_USAGE_NONE;
- }
- }
-
- if (property.name == "node_path") {
- if (call_mode != CALL_MODE_NODE_PATH) {
- property.usage = PROPERTY_USAGE_NONE;
- } else {
- Node *bnode = _get_base_node();
- if (bnode) {
- property.hint_string = bnode->get_path(); //convert to long string
- }
- }
- }
-
- if (property.name == "property") {
- if (call_mode == CALL_MODE_BASIC_TYPE) {
- property.hint = PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE;
- property.hint_string = Variant::get_type_name(basic_type);
-
- } else if (call_mode == CALL_MODE_SELF && get_visual_script().is_valid()) {
- property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT;
- property.hint_string = itos(get_visual_script()->get_instance_id());
- } else if (call_mode == CALL_MODE_INSTANCE) {
- property.hint = PROPERTY_HINT_PROPERTY_OF_BASE_TYPE;
- property.hint_string = base_type;
-
- if (!base_script.is_empty()) {
- if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) {
- ScriptServer::edit_request_func(base_script); //make sure it's loaded
- }
-
- if (ResourceCache::has(base_script)) {
- Ref<Script> script = ResourceCache::get_ref(base_script);
- if (script.is_valid()) {
- property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT;
- property.hint_string = itos(script->get_instance_id());
- }
- }
- }
-
- } else if (call_mode == CALL_MODE_NODE_PATH) {
- Node *node = _get_base_node();
- if (node) {
- property.hint = PROPERTY_HINT_PROPERTY_OF_INSTANCE;
- property.hint_string = itos(node->get_instance_id());
- } else {
- property.hint = PROPERTY_HINT_PROPERTY_OF_BASE_TYPE;
- property.hint_string = get_base_type();
- }
- }
- }
-
- if (property.name == "index") {
- Callable::CallError ce;
- Variant v;
- Variant::construct(type_cache.type, v, nullptr, 0, ce);
- List<PropertyInfo> plist;
- v.get_property_list(&plist);
- String options = "";
- for (const PropertyInfo &E : plist) {
- options += "," + E.name;
- }
-
- property.hint = PROPERTY_HINT_ENUM;
- property.hint_string = options;
- property.type = Variant::STRING;
- if (options.is_empty()) {
- property.usage = PROPERTY_USAGE_NONE; //hide if type has no usable index
- }
- }
-}
-
-void VisualScriptPropertySet::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_base_type", "base_type"), &VisualScriptPropertySet::set_base_type);
- ClassDB::bind_method(D_METHOD("get_base_type"), &VisualScriptPropertySet::get_base_type);
-
- ClassDB::bind_method(D_METHOD("set_base_script", "base_script"), &VisualScriptPropertySet::set_base_script);
- ClassDB::bind_method(D_METHOD("get_base_script"), &VisualScriptPropertySet::get_base_script);
-
- ClassDB::bind_method(D_METHOD("set_basic_type", "basic_type"), &VisualScriptPropertySet::set_basic_type);
- ClassDB::bind_method(D_METHOD("get_basic_type"), &VisualScriptPropertySet::get_basic_type);
-
- ClassDB::bind_method(D_METHOD("_set_type_cache", "type_cache"), &VisualScriptPropertySet::_set_type_cache);
- ClassDB::bind_method(D_METHOD("_get_type_cache"), &VisualScriptPropertySet::_get_type_cache);
-
- ClassDB::bind_method(D_METHOD("set_property", "property"), &VisualScriptPropertySet::set_property);
- ClassDB::bind_method(D_METHOD("get_property"), &VisualScriptPropertySet::get_property);
-
- ClassDB::bind_method(D_METHOD("set_call_mode", "mode"), &VisualScriptPropertySet::set_call_mode);
- ClassDB::bind_method(D_METHOD("get_call_mode"), &VisualScriptPropertySet::get_call_mode);
-
- ClassDB::bind_method(D_METHOD("set_base_path", "base_path"), &VisualScriptPropertySet::set_base_path);
- ClassDB::bind_method(D_METHOD("get_base_path"), &VisualScriptPropertySet::get_base_path);
-
- ClassDB::bind_method(D_METHOD("set_index", "index"), &VisualScriptPropertySet::set_index);
- ClassDB::bind_method(D_METHOD("get_index"), &VisualScriptPropertySet::get_index);
-
- ClassDB::bind_method(D_METHOD("set_assign_op", "assign_op"), &VisualScriptPropertySet::set_assign_op);
- ClassDB::bind_method(D_METHOD("get_assign_op"), &VisualScriptPropertySet::get_assign_op);
-
- String bt;
- for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- if (i > 0) {
- bt += ",";
- }
-
- bt += Variant::get_type_name(Variant::Type(i));
- }
-
- List<String> script_extensions;
- for (int i = 0; i < ScriptServer::get_language_count(); i++) {
- ScriptServer::get_language(i)->get_recognized_extensions(&script_extensions);
- }
-
- String script_ext_hint;
- for (const String &E : script_extensions) {
- if (!script_ext_hint.is_empty()) {
- script_ext_hint += ",";
- }
- script_ext_hint += "*." + E;
- }
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "set_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type"), "set_call_mode", "get_call_mode");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "type_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_type_cache", "_get_type_cache");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "basic_type", PROPERTY_HINT_ENUM, bt), "set_basic_type", "get_basic_type");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "property"), "set_property", "get_property");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "index"), "set_index", "get_index");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "assign_op", PROPERTY_HINT_ENUM, "Assign,Add,Sub,Mul,Div,Mod,ShiftLeft,ShiftRight,BitAnd,BitOr,Bitxor"), "set_assign_op", "get_assign_op");
-
- BIND_ENUM_CONSTANT(CALL_MODE_SELF);
- BIND_ENUM_CONSTANT(CALL_MODE_NODE_PATH);
- BIND_ENUM_CONSTANT(CALL_MODE_INSTANCE);
- BIND_ENUM_CONSTANT(CALL_MODE_BASIC_TYPE);
-
- BIND_ENUM_CONSTANT(ASSIGN_OP_NONE);
- BIND_ENUM_CONSTANT(ASSIGN_OP_ADD);
- BIND_ENUM_CONSTANT(ASSIGN_OP_SUB);
- BIND_ENUM_CONSTANT(ASSIGN_OP_MUL);
- BIND_ENUM_CONSTANT(ASSIGN_OP_DIV);
- BIND_ENUM_CONSTANT(ASSIGN_OP_MOD);
- BIND_ENUM_CONSTANT(ASSIGN_OP_SHIFT_LEFT);
- BIND_ENUM_CONSTANT(ASSIGN_OP_SHIFT_RIGHT);
- BIND_ENUM_CONSTANT(ASSIGN_OP_BIT_AND);
- BIND_ENUM_CONSTANT(ASSIGN_OP_BIT_OR);
- BIND_ENUM_CONSTANT(ASSIGN_OP_BIT_XOR);
-}
-
-class VisualScriptNodeInstancePropertySet : public VisualScriptNodeInstance {
-public:
- VisualScriptPropertySet::CallMode call_mode;
- NodePath node_path;
- StringName property;
-
- VisualScriptPropertySet *node = nullptr;
- VisualScriptInstance *instance = nullptr;
- VisualScriptPropertySet::AssignOp assign_op;
- StringName index;
- bool needs_get = false;
-
- //virtual int get_working_memory_size() const override { return 0; }
- //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
- //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
-
- _FORCE_INLINE_ void _process_get(Variant &source, const Variant &p_argument, bool &valid) {
- if (index != StringName() && assign_op == VisualScriptPropertySet::ASSIGN_OP_NONE) {
- source.set_named(index, p_argument, valid);
- } else {
- Variant value;
- if (index != StringName()) {
- value = source.get_named(index, valid);
- } else {
- value = source;
- }
-
- switch (assign_op) {
- case VisualScriptPropertySet::ASSIGN_OP_NONE: {
- //should never get here
- } break;
- case VisualScriptPropertySet::ASSIGN_OP_ADD: {
- value = Variant::evaluate(Variant::OP_ADD, value, p_argument);
- } break;
- case VisualScriptPropertySet::ASSIGN_OP_SUB: {
- value = Variant::evaluate(Variant::OP_SUBTRACT, value, p_argument);
- } break;
- case VisualScriptPropertySet::ASSIGN_OP_MUL: {
- value = Variant::evaluate(Variant::OP_MULTIPLY, value, p_argument);
- } break;
- case VisualScriptPropertySet::ASSIGN_OP_DIV: {
- value = Variant::evaluate(Variant::OP_DIVIDE, value, p_argument);
- } break;
- case VisualScriptPropertySet::ASSIGN_OP_MOD: {
- value = Variant::evaluate(Variant::OP_MODULE, value, p_argument);
- } break;
- case VisualScriptPropertySet::ASSIGN_OP_SHIFT_LEFT: {
- value = Variant::evaluate(Variant::OP_SHIFT_LEFT, value, p_argument);
- } break;
- case VisualScriptPropertySet::ASSIGN_OP_SHIFT_RIGHT: {
- value = Variant::evaluate(Variant::OP_SHIFT_RIGHT, value, p_argument);
- } break;
- case VisualScriptPropertySet::ASSIGN_OP_BIT_AND: {
- value = Variant::evaluate(Variant::OP_BIT_AND, value, p_argument);
- } break;
- case VisualScriptPropertySet::ASSIGN_OP_BIT_OR: {
- value = Variant::evaluate(Variant::OP_BIT_OR, value, p_argument);
- } break;
- case VisualScriptPropertySet::ASSIGN_OP_BIT_XOR: {
- value = Variant::evaluate(Variant::OP_BIT_XOR, value, p_argument);
- } break;
- default: {
- }
- }
-
- if (index != StringName()) {
- source.set_named(index, value, valid);
- } else {
- source = value;
- }
- }
- }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- switch (call_mode) {
- case VisualScriptPropertySet::CALL_MODE_SELF: {
- Object *object = instance->get_owner_ptr();
-
- bool valid;
-
- if (needs_get) {
- Variant value = object->get(property, &valid);
- _process_get(value, *p_inputs[0], valid);
- object->set(property, value, &valid);
- } else {
- object->set(property, *p_inputs[0], &valid);
- }
-
- if (!valid) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = "Invalid set value '" + String(*p_inputs[0]) + "' on property '" + String(property) + "' of type " + object->get_class();
- }
- } break;
- case VisualScriptPropertySet::CALL_MODE_NODE_PATH: {
- Node *node = Object::cast_to<Node>(instance->get_owner_ptr());
- if (!node) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = "Base object is not a Node!";
- return 0;
- }
-
- Node *another = node->get_node(node_path);
- if (!another) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = "Path does not lead Node!";
- return 0;
- }
-
- bool valid;
-
- if (needs_get) {
- Variant value = another->get(property, &valid);
- _process_get(value, *p_inputs[0], valid);
- another->set(property, value, &valid);
- } else {
- another->set(property, *p_inputs[0], &valid);
- }
-
- if (!valid) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = "Invalid set value '" + String(*p_inputs[0]) + "' on property '" + String(property) + "' of type " + another->get_class();
- }
-
- } break;
- case VisualScriptPropertySet::CALL_MODE_INSTANCE:
- case VisualScriptPropertySet::CALL_MODE_BASIC_TYPE: {
- Variant v = *p_inputs[0];
-
- bool valid;
-
- if (needs_get) {
- Variant value = v.get_named(property, valid);
- _process_get(value, *p_inputs[1], valid);
- v.set_named(property, value, valid);
-
- } else {
- v.set_named(property, *p_inputs[1], valid);
- }
-
- if (!valid) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = "Invalid set value '" + String(*p_inputs[1]) + "' (" + Variant::get_type_name(p_inputs[1]->get_type()) + ") on property '" + String(property) + "' of type " + Variant::get_type_name(v.get_type());
- }
-
- *p_outputs[0] = v;
-
- } break;
- }
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptPropertySet::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstancePropertySet *instance = memnew(VisualScriptNodeInstancePropertySet);
- instance->node = this;
- instance->instance = p_instance;
- instance->property = property;
- instance->call_mode = call_mode;
- instance->node_path = base_path;
- instance->assign_op = assign_op;
- instance->index = index;
- instance->needs_get = index != StringName() || assign_op != ASSIGN_OP_NONE;
- return instance;
-}
-
-VisualScriptPropertySet::TypeGuess VisualScriptPropertySet::guess_output_type(TypeGuess *p_inputs, int p_output) const {
- if (p_output == 0 && call_mode == CALL_MODE_INSTANCE) {
- return p_inputs[0];
- }
-
- return VisualScriptNode::guess_output_type(p_inputs, p_output);
-}
-
-VisualScriptPropertySet::VisualScriptPropertySet() {
- assign_op = ASSIGN_OP_NONE;
- call_mode = CALL_MODE_SELF;
- base_type = "Object";
- basic_type = Variant::NIL;
-}
-
-template <VisualScriptPropertySet::CallMode cmode>
-static Ref<VisualScriptNode> create_property_set_node(const String &p_name) {
- Ref<VisualScriptPropertySet> node;
- node.instantiate();
- node->set_call_mode(cmode);
- return node;
-}
-
-//////////////////////////////////////////
-////////////////GET//////////////////////
-//////////////////////////////////////////
-
-int VisualScriptPropertyGet::get_output_sequence_port_count() const {
- return 0; // (call_mode==CALL_MODE_SELF || call_mode==CALL_MODE_NODE_PATH)?0:1;
-}
-
-bool VisualScriptPropertyGet::has_input_sequence_port() const {
- return false; //(call_mode==CALL_MODE_SELF || call_mode==CALL_MODE_NODE_PATH)?false:true;
-}
-
-void VisualScriptPropertyGet::_update_base_type() {
- //cache it because this information may not be available on load
- if (call_mode == CALL_MODE_NODE_PATH) {
- Node *node = _get_base_node();
- if (node) {
- base_type = node->get_class();
- }
- } else if (call_mode == CALL_MODE_SELF) {
- if (get_visual_script().is_valid()) {
- base_type = get_visual_script()->get_instance_base_type();
- }
- }
-}
-
-Node *VisualScriptPropertyGet::_get_base_node() const {
-#ifdef TOOLS_ENABLED
- Ref<Script> script = get_visual_script();
- if (!script.is_valid()) {
- return nullptr;
- }
-
- MainLoop *main_loop = OS::get_singleton()->get_main_loop();
-
- SceneTree *scene_tree = Object::cast_to<SceneTree>(main_loop);
-
- if (!scene_tree) {
- return nullptr;
- }
-
- Node *edited_scene = scene_tree->get_edited_scene_root();
-
- if (!edited_scene) {
- return nullptr;
- }
-
- Node *script_node = _find_script_node(edited_scene, edited_scene, script);
-
- if (!script_node) {
- return nullptr;
- }
-
- if (!script_node->has_node(base_path)) {
- return nullptr;
- }
-
- Node *path_to = script_node->get_node(base_path);
-
- return path_to;
-#else
-
- return nullptr;
-#endif
-}
-
-StringName VisualScriptPropertyGet::_get_base_type() const {
- if (call_mode == CALL_MODE_SELF && get_visual_script().is_valid()) {
- return get_visual_script()->get_instance_base_type();
- } else if (call_mode == CALL_MODE_NODE_PATH && get_visual_script().is_valid()) {
- Node *path = _get_base_node();
- if (path) {
- return path->get_class();
- }
- }
-
- return base_type;
-}
-
-int VisualScriptPropertyGet::get_input_value_port_count() const {
- return (call_mode == CALL_MODE_BASIC_TYPE || call_mode == CALL_MODE_INSTANCE) ? 1 : 0;
-}
-
-int VisualScriptPropertyGet::get_output_value_port_count() const {
- int pc = (call_mode == CALL_MODE_BASIC_TYPE || call_mode == CALL_MODE_INSTANCE) ? 2 : 1;
-
- return pc;
-}
-
-String VisualScriptPropertyGet::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptPropertyGet::get_input_value_port_info(int p_idx) const {
- if (call_mode == CALL_MODE_INSTANCE || call_mode == CALL_MODE_BASIC_TYPE) {
- if (p_idx == 0) {
- PropertyInfo pi;
- pi.type = (call_mode == CALL_MODE_INSTANCE ? Variant::OBJECT : basic_type);
- pi.name = (call_mode == CALL_MODE_INSTANCE ? String("instance") : Variant::get_type_name(basic_type).to_lower());
- return pi;
- }
- }
- return PropertyInfo();
-}
-
-PropertyInfo VisualScriptPropertyGet::get_output_value_port_info(int p_idx) const {
- if (call_mode == CALL_MODE_BASIC_TYPE && p_idx == 0) {
- return PropertyInfo(basic_type, "pass");
- } else if (call_mode == CALL_MODE_INSTANCE && p_idx == 0) {
- return PropertyInfo(Variant::OBJECT, "pass", PROPERTY_HINT_TYPE_STRING, get_base_type());
- } else {
- List<PropertyInfo> props;
- ClassDB::get_property_list(_get_base_type(), &props, false);
- for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
- if (E->get().name == property) {
- PropertyInfo pinfo = PropertyInfo(E->get().type, String(property) + "." + String(index), E->get().hint, E->get().hint_string);
- _adjust_input_index(pinfo);
- return pinfo;
- }
- }
- }
-
- PropertyInfo pinfo = PropertyInfo(type_cache, "value");
- _adjust_input_index(pinfo);
- return pinfo;
-}
-
-String VisualScriptPropertyGet::get_caption() const {
- String prop = property;
- if (index != StringName()) {
- prop += "." + String(index);
- }
-
- return vformat(RTR("Get %s"), prop);
-}
-
-String VisualScriptPropertyGet::get_text() const {
- if (call_mode == CALL_MODE_BASIC_TYPE) {
- return vformat(RTR("On %s"), Variant::get_type_name(basic_type));
- } else if (call_mode == CALL_MODE_INSTANCE) {
- return vformat(RTR("On %s"), base_type);
- } else if (call_mode == CALL_MODE_NODE_PATH) {
- return " [" + String(base_path.simplified()) + "]";
- } else {
- return RTR("On Self");
- }
-}
-
-void VisualScriptPropertyGet::set_base_type(const StringName &p_type) {
- if (base_type == p_type) {
- return;
- }
-
- base_type = p_type;
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-StringName VisualScriptPropertyGet::get_base_type() const {
- return base_type;
-}
-
-void VisualScriptPropertyGet::set_base_script(const String &p_path) {
- if (base_script == p_path) {
- return;
- }
-
- base_script = p_path;
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-String VisualScriptPropertyGet::get_base_script() const {
- return base_script;
-}
-
-void VisualScriptPropertyGet::_update_cache() {
- if (call_mode == CALL_MODE_BASIC_TYPE) {
- //not super efficient..
-
- Variant v;
- Callable::CallError ce;
- Variant::construct(basic_type, v, nullptr, 0, ce);
-
- List<PropertyInfo> pinfo;
- v.get_property_list(&pinfo);
-
- for (const PropertyInfo &E : pinfo) {
- if (E.name == property) {
- type_cache = E.type;
- return;
- }
- }
-
- } else {
- StringName type;
- Ref<Script> script;
- Node *node = nullptr;
-
- if (call_mode == CALL_MODE_NODE_PATH) {
- node = _get_base_node();
- if (node) {
- type = node->get_class();
- base_type = type; //cache, too
- script = node->get_script();
- }
- } else if (call_mode == CALL_MODE_SELF) {
- if (get_visual_script().is_valid()) {
- type = get_visual_script()->get_instance_base_type();
- base_type = type; //cache, too
- script = get_visual_script();
- }
- } else if (call_mode == CALL_MODE_INSTANCE) {
- type = base_type;
- if (!base_script.is_empty()) {
- if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) {
- ScriptServer::edit_request_func(base_script); //make sure it's loaded
- }
-
- if (ResourceCache::has(base_script)) {
- script = ResourceCache::get_ref(base_script);
- } else {
- return;
- }
- }
- }
-
- bool valid = false;
-
- Variant::Type type_ret;
-
- type_ret = ClassDB::get_property_type(base_type, property, &valid);
-
- if (valid) {
- type_cache = type_ret;
- return; //all dandy
- }
-
- if (node) {
- Variant prop = node->get(property, &valid);
- if (valid) {
- type_cache = prop.get_type();
- return; //all dandy again
- }
- }
-
- if (script.is_valid()) {
- type_ret = script->get_static_property_type(property, &valid);
-
- if (valid) {
- type_cache = type_ret;
- return; //all dandy
- }
- }
- }
-}
-
-void VisualScriptPropertyGet::set_property(const StringName &p_type) {
- if (property == p_type) {
- return;
- }
-
- property = p_type;
-
- _update_cache();
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-StringName VisualScriptPropertyGet::get_property() const {
- return property;
-}
-
-void VisualScriptPropertyGet::set_base_path(const NodePath &p_type) {
- if (base_path == p_type) {
- return;
- }
-
- base_path = p_type;
- notify_property_list_changed();
- _update_base_type();
- ports_changed_notify();
-}
-
-NodePath VisualScriptPropertyGet::get_base_path() const {
- return base_path;
-}
-
-void VisualScriptPropertyGet::set_call_mode(CallMode p_mode) {
- if (call_mode == p_mode) {
- return;
- }
-
- call_mode = p_mode;
- notify_property_list_changed();
- _update_base_type();
- ports_changed_notify();
-}
-
-VisualScriptPropertyGet::CallMode VisualScriptPropertyGet::get_call_mode() const {
- return call_mode;
-}
-
-void VisualScriptPropertyGet::set_basic_type(Variant::Type p_type) {
- if (basic_type == p_type) {
- return;
- }
- basic_type = p_type;
-
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-Variant::Type VisualScriptPropertyGet::get_basic_type() const {
- return basic_type;
-}
-
-void VisualScriptPropertyGet::_set_type_cache(Variant::Type p_type) {
- type_cache = p_type;
-}
-
-Variant::Type VisualScriptPropertyGet::_get_type_cache() const {
- return type_cache;
-}
-
-void VisualScriptPropertyGet::_adjust_input_index(PropertyInfo &pinfo) const {
- if (index != StringName()) {
- Variant v;
- Callable::CallError ce;
- Variant::construct(pinfo.type, v, nullptr, 0, ce);
- Variant i = v.get(index);
- pinfo.type = i.get_type();
- pinfo.name = String(property) + "." + index;
- } else {
- pinfo.name = String(property);
- }
-}
-
-void VisualScriptPropertyGet::set_index(const StringName &p_type) {
- if (index == p_type) {
- return;
- }
- index = p_type;
- _update_cache();
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-StringName VisualScriptPropertyGet::get_index() const {
- return index;
-}
-
-void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const {
- if (property.name == "base_type") {
- if (call_mode != CALL_MODE_INSTANCE) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
- }
- }
-
- if (property.name == "base_script") {
- if (call_mode != CALL_MODE_INSTANCE) {
- property.usage = PROPERTY_USAGE_NONE;
- }
- }
-
- if (property.name == "basic_type") {
- if (call_mode != CALL_MODE_BASIC_TYPE) {
- property.usage = PROPERTY_USAGE_NONE;
- }
- }
-
- if (property.name == "node_path") {
- if (call_mode != CALL_MODE_NODE_PATH) {
- property.usage = PROPERTY_USAGE_NONE;
- } else {
- Node *bnode = _get_base_node();
- if (bnode) {
- property.hint_string = bnode->get_path(); //convert to long string
- }
- }
- }
-
- if (property.name == "property") {
- if (call_mode == CALL_MODE_BASIC_TYPE) {
- property.hint = PROPERTY_HINT_PROPERTY_OF_VARIANT_TYPE;
- property.hint_string = Variant::get_type_name(basic_type);
-
- } else if (call_mode == CALL_MODE_SELF && get_visual_script().is_valid()) {
- property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT;
- property.hint_string = itos(get_visual_script()->get_instance_id());
- } else if (call_mode == CALL_MODE_INSTANCE) {
- property.hint = PROPERTY_HINT_PROPERTY_OF_BASE_TYPE;
- property.hint_string = base_type;
-
- if (!base_script.is_empty()) {
- if (!ResourceCache::has(base_script) && ScriptServer::edit_request_func) {
- ScriptServer::edit_request_func(base_script); //make sure it's loaded
- }
-
- if (ResourceCache::has(base_script)) {
- Ref<Script> script = ResourceCache::get_ref(base_script);
- if (script.is_valid()) {
- property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT;
- property.hint_string = itos(script->get_instance_id());
- }
- }
- }
- } else if (call_mode == CALL_MODE_NODE_PATH) {
- Node *node = _get_base_node();
- if (node) {
- property.hint = PROPERTY_HINT_PROPERTY_OF_INSTANCE;
- property.hint_string = itos(node->get_instance_id());
- } else {
- property.hint = PROPERTY_HINT_PROPERTY_OF_BASE_TYPE;
- property.hint_string = get_base_type();
- }
- }
- }
-
- if (property.name == "index") {
- Callable::CallError ce;
- Variant v;
- Variant::construct(type_cache, v, nullptr, 0, ce);
- List<PropertyInfo> plist;
- v.get_property_list(&plist);
- String options = "";
- for (const PropertyInfo &E : plist) {
- options += "," + E.name;
- }
-
- property.hint = PROPERTY_HINT_ENUM;
- property.hint_string = options;
- property.type = Variant::STRING;
- if (options.is_empty()) {
- property.usage = PROPERTY_USAGE_NONE; //hide if type has no usable index
- }
- }
-}
-
-void VisualScriptPropertyGet::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_base_type", "base_type"), &VisualScriptPropertyGet::set_base_type);
- ClassDB::bind_method(D_METHOD("get_base_type"), &VisualScriptPropertyGet::get_base_type);
-
- ClassDB::bind_method(D_METHOD("set_base_script", "base_script"), &VisualScriptPropertyGet::set_base_script);
- ClassDB::bind_method(D_METHOD("get_base_script"), &VisualScriptPropertyGet::get_base_script);
-
- ClassDB::bind_method(D_METHOD("set_basic_type", "basic_type"), &VisualScriptPropertyGet::set_basic_type);
- ClassDB::bind_method(D_METHOD("get_basic_type"), &VisualScriptPropertyGet::get_basic_type);
-
- ClassDB::bind_method(D_METHOD("_set_type_cache", "type_cache"), &VisualScriptPropertyGet::_set_type_cache);
- ClassDB::bind_method(D_METHOD("_get_type_cache"), &VisualScriptPropertyGet::_get_type_cache);
-
- ClassDB::bind_method(D_METHOD("set_property", "property"), &VisualScriptPropertyGet::set_property);
- ClassDB::bind_method(D_METHOD("get_property"), &VisualScriptPropertyGet::get_property);
-
- ClassDB::bind_method(D_METHOD("set_call_mode", "mode"), &VisualScriptPropertyGet::set_call_mode);
- ClassDB::bind_method(D_METHOD("get_call_mode"), &VisualScriptPropertyGet::get_call_mode);
-
- ClassDB::bind_method(D_METHOD("set_base_path", "base_path"), &VisualScriptPropertyGet::set_base_path);
- ClassDB::bind_method(D_METHOD("get_base_path"), &VisualScriptPropertyGet::get_base_path);
-
- ClassDB::bind_method(D_METHOD("set_index", "index"), &VisualScriptPropertyGet::set_index);
- ClassDB::bind_method(D_METHOD("get_index"), &VisualScriptPropertyGet::get_index);
-
- String bt;
- for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- if (i > 0) {
- bt += ",";
- }
-
- bt += Variant::get_type_name(Variant::Type(i));
- }
-
- List<String> script_extensions;
- for (int i = 0; i < ScriptServer::get_language_count(); i++) {
- ScriptServer::get_language(i)->get_recognized_extensions(&script_extensions);
- }
-
- String script_ext_hint;
- for (const String &E : script_extensions) {
- if (!script_ext_hint.is_empty()) {
- script_ext_hint += ",";
- }
- script_ext_hint += "." + E;
- }
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "set_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance,Basic Type"), "set_call_mode", "get_call_mode");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_script", PROPERTY_HINT_FILE, script_ext_hint), "set_base_script", "get_base_script");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "type_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_type_cache", "_get_type_cache");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "basic_type", PROPERTY_HINT_ENUM, bt), "set_basic_type", "get_basic_type");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "property"), "set_property", "get_property");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "index", PROPERTY_HINT_ENUM), "set_index", "get_index");
-
- BIND_ENUM_CONSTANT(CALL_MODE_SELF);
- BIND_ENUM_CONSTANT(CALL_MODE_NODE_PATH);
- BIND_ENUM_CONSTANT(CALL_MODE_INSTANCE);
- BIND_ENUM_CONSTANT(CALL_MODE_BASIC_TYPE);
-}
-
-class VisualScriptNodeInstancePropertyGet : public VisualScriptNodeInstance {
-public:
- VisualScriptPropertyGet::CallMode call_mode;
- NodePath node_path;
- StringName property;
- StringName index;
-
- VisualScriptPropertyGet *node = nullptr;
- VisualScriptInstance *instance = nullptr;
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- switch (call_mode) {
- case VisualScriptPropertyGet::CALL_MODE_SELF: {
- Object *object = instance->get_owner_ptr();
-
- bool valid;
-
- *p_outputs[0] = object->get(property, &valid);
-
- if (index != StringName()) {
- *p_outputs[0] = p_outputs[0]->get_named(index, valid);
- }
-
- if (!valid) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = RTR("Invalid index property name.");
- return 0;
- }
- } break;
- case VisualScriptPropertyGet::CALL_MODE_NODE_PATH: {
- Node *node = Object::cast_to<Node>(instance->get_owner_ptr());
- if (!node) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = RTR("Base object is not a Node!");
- return 0;
- }
-
- Node *another = node->get_node(node_path);
- if (!another) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = RTR("Path does not lead Node!");
- return 0;
- }
-
- bool valid;
-
- *p_outputs[0] = another->get(property, &valid);
-
- if (index != StringName()) {
- *p_outputs[0] = p_outputs[0]->get_named(index, valid);
- }
-
- if (!valid) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = vformat(RTR("Invalid index property name '%s' in node %s."), String(property), another->get_name());
- return 0;
- }
-
- } break;
- default: {
- bool valid;
- Variant v = *p_inputs[0];
-
- *p_outputs[1] = v.get(property, &valid);
- if (index != StringName()) {
- *p_outputs[1] = p_outputs[1]->get_named(index, valid);
- }
-
- if (!valid) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = RTR("Invalid index property name.");
- }
-
- *p_outputs[0] = v;
- };
- }
-
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptPropertyGet::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstancePropertyGet *instance = memnew(VisualScriptNodeInstancePropertyGet);
- instance->node = this;
- instance->instance = p_instance;
- instance->property = property;
- instance->call_mode = call_mode;
- instance->node_path = base_path;
- instance->index = index;
-
- return instance;
-}
-
-VisualScriptPropertyGet::VisualScriptPropertyGet() {
- call_mode = CALL_MODE_SELF;
- base_type = "Object";
- basic_type = Variant::NIL;
- type_cache = Variant::NIL;
-}
-
-template <VisualScriptPropertyGet::CallMode cmode>
-static Ref<VisualScriptNode> create_property_get_node(const String &p_name) {
- Ref<VisualScriptPropertyGet> node;
- node.instantiate();
- node->set_call_mode(cmode);
- return node;
-}
-
-//////////////////////////////////////////
-////////////////EMIT//////////////////////
-//////////////////////////////////////////
-
-int VisualScriptEmitSignal::get_output_sequence_port_count() const {
- return 1;
-}
-
-bool VisualScriptEmitSignal::has_input_sequence_port() const {
- return true;
-}
-
-int VisualScriptEmitSignal::get_input_value_port_count() const {
- Ref<VisualScript> vs = get_visual_script();
- if (vs.is_valid()) {
- if (!vs->has_custom_signal(name)) {
- return 0;
- }
-
- return vs->custom_signal_get_argument_count(name);
- }
-
- return 0;
-}
-
-int VisualScriptEmitSignal::get_output_value_port_count() const {
- return 0;
-}
-
-String VisualScriptEmitSignal::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptEmitSignal::get_input_value_port_info(int p_idx) const {
- Ref<VisualScript> vs = get_visual_script();
- if (vs.is_valid()) {
- if (!vs->has_custom_signal(name)) {
- return PropertyInfo();
- }
-
- return PropertyInfo(vs->custom_signal_get_argument_type(name, p_idx), vs->custom_signal_get_argument_name(name, p_idx));
- }
-
- return PropertyInfo();
-}
-
-PropertyInfo VisualScriptEmitSignal::get_output_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-String VisualScriptEmitSignal::get_caption() const {
- return vformat(RTR("Emit %s"), name);
-}
-
-void VisualScriptEmitSignal::set_signal(const StringName &p_type) {
- if (name == p_type) {
- return;
- }
-
- name = p_type;
-
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-StringName VisualScriptEmitSignal::get_signal() const {
- return name;
-}
-
-void VisualScriptEmitSignal::_validate_property(PropertyInfo &property) const {
- if (property.name == "signal") {
- property.hint = PROPERTY_HINT_ENUM;
-
- List<StringName> sigs;
- List<MethodInfo> base_sigs;
-
- Ref<VisualScript> vs = get_visual_script();
- if (vs.is_valid()) {
- vs->get_custom_signal_list(&sigs);
- ClassDB::get_signal_list(vs->get_instance_base_type(), &base_sigs);
- }
-
- String ml;
- for (const StringName &E : sigs) {
- if (!ml.is_empty()) {
- ml += ",";
- }
- ml += E;
- }
- for (const MethodInfo &E : base_sigs) {
- if (!ml.is_empty()) {
- ml += ",";
- }
- ml += E.name;
- }
-
- property.hint_string = ml;
- }
-}
-
-void VisualScriptEmitSignal::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_signal", "name"), &VisualScriptEmitSignal::set_signal);
- ClassDB::bind_method(D_METHOD("get_signal"), &VisualScriptEmitSignal::get_signal);
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "signal"), "set_signal", "get_signal");
-}
-
-class VisualScriptNodeInstanceEmitSignal : public VisualScriptNodeInstance {
-public:
- VisualScriptEmitSignal *node = nullptr;
- VisualScriptInstance *instance = nullptr;
- int argcount = 0;
- StringName name;
-
- //virtual int get_working_memory_size() const override { return 0; }
- //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
- //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- Object *obj = instance->get_owner_ptr();
-
- obj->emit_signalp(name, p_inputs, argcount);
-
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptEmitSignal::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceEmitSignal *instance = memnew(VisualScriptNodeInstanceEmitSignal);
- instance->node = this;
- instance->instance = p_instance;
- instance->name = name;
- instance->argcount = get_input_value_port_count();
- return instance;
-}
-
-VisualScriptEmitSignal::VisualScriptEmitSignal() {
-}
-
-static Ref<VisualScriptNode> create_basic_type_call_node(const String &p_name) {
- Vector<String> path = p_name.split("/");
- ERR_FAIL_COND_V(path.size() < 4, Ref<VisualScriptNode>());
- String base_type = path[2];
- String method = path[3];
-
- Ref<VisualScriptFunctionCall> node;
- node.instantiate();
-
- Variant::Type type = Variant::VARIANT_MAX;
-
- for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- if (Variant::get_type_name(Variant::Type(i)) == base_type) {
- type = Variant::Type(i);
- break;
- }
- }
-
- ERR_FAIL_COND_V(type == Variant::VARIANT_MAX, Ref<VisualScriptNode>());
-
- node->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE);
- node->set_basic_type(type);
- node->set_function(method);
-
- return node;
-}
-
-void register_visual_script_func_nodes() {
- VisualScriptLanguage::singleton->add_register_func("functions/call", create_node_generic<VisualScriptFunctionCall>);
- VisualScriptLanguage::singleton->add_register_func("functions/set", create_node_generic<VisualScriptPropertySet>);
- VisualScriptLanguage::singleton->add_register_func("functions/get", create_node_generic<VisualScriptPropertyGet>);
-
- //VisualScriptLanguage::singleton->add_register_func("functions/call_script/call_self",create_script_call_node<VisualScriptScriptCall::CALL_MODE_SELF>);
- //VisualScriptLanguage::singleton->add_register_func("functions/call_script/call_node",create_script_call_node<VisualScriptScriptCall::CALL_MODE_NODE_PATH>);
- VisualScriptLanguage::singleton->add_register_func("functions/emit_signal", create_node_generic<VisualScriptEmitSignal>);
-
- for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- Variant::Type t = Variant::Type(i);
- String type_name = Variant::get_type_name(t);
- Callable::CallError ce;
- Variant vt;
- Variant::construct(t, vt, nullptr, 0, ce);
- List<MethodInfo> ml;
- vt.get_method_list(&ml);
-
- for (const MethodInfo &E : ml) {
- VisualScriptLanguage::singleton->add_register_func("functions/by_type/" + type_name + "/" + E.name, create_basic_type_call_node);
- }
- }
-}
diff --git a/modules/visual_script/visual_script_func_nodes.h b/modules/visual_script/visual_script_func_nodes.h
deleted file mode 100644
index 886ed7bc81..0000000000
--- a/modules/visual_script/visual_script_func_nodes.h
+++ /dev/null
@@ -1,363 +0,0 @@
-/*************************************************************************/
-/* visual_script_func_nodes.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef VISUAL_SCRIPT_FUNC_NODES_H
-#define VISUAL_SCRIPT_FUNC_NODES_H
-
-#include "visual_script.h"
-
-class VisualScriptFunctionCall : public VisualScriptNode {
- GDCLASS(VisualScriptFunctionCall, VisualScriptNode);
-
-public:
- enum CallMode {
- CALL_MODE_SELF,
- CALL_MODE_NODE_PATH,
- CALL_MODE_INSTANCE,
- CALL_MODE_BASIC_TYPE,
- CALL_MODE_SINGLETON,
- };
-
- enum RPCCallMode {
- RPC_DISABLED,
- RPC_RELIABLE,
- RPC_UNRELIABLE,
- RPC_RELIABLE_TO_ID,
- RPC_UNRELIABLE_TO_ID
- };
-
-private:
- CallMode call_mode;
- StringName base_type;
- String base_script;
- Variant::Type basic_type;
- NodePath base_path;
- StringName function;
- int use_default_args;
- RPCCallMode rpc_call_mode;
- StringName singleton;
- bool validate;
-
- Node *_get_base_node() const;
- StringName _get_base_type() const;
-
- MethodInfo method_cache;
- void _update_method_cache();
-
- void _set_argument_cache(const Dictionary &p_cache);
- Dictionary _get_argument_cache() const;
-
-protected:
- virtual void _validate_property(PropertyInfo &property) const override;
-
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_text() const override;
- virtual String get_category() const override { return "functions"; }
-
- void set_basic_type(Variant::Type p_type);
- Variant::Type get_basic_type() const;
-
- void set_base_type(const StringName &p_type);
- StringName get_base_type() const;
-
- void set_base_script(const String &p_path);
- String get_base_script() const;
-
- void set_singleton(const StringName &p_type);
- StringName get_singleton() const;
-
- void set_function(const StringName &p_type);
- StringName get_function() const;
-
- void set_base_path(const NodePath &p_type);
- NodePath get_base_path() const;
-
- void set_call_mode(CallMode p_mode);
- CallMode get_call_mode() const;
-
- void set_use_default_args(int p_amount);
- int get_use_default_args() const;
-
- void set_validate(bool p_amount);
- bool get_validate() const;
-
- void set_rpc_call_mode(RPCCallMode p_mode);
- RPCCallMode get_rpc_call_mode() const;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override;
-
- VisualScriptFunctionCall();
-};
-
-VARIANT_ENUM_CAST(VisualScriptFunctionCall::CallMode);
-VARIANT_ENUM_CAST(VisualScriptFunctionCall::RPCCallMode);
-
-class VisualScriptPropertySet : public VisualScriptNode {
- GDCLASS(VisualScriptPropertySet, VisualScriptNode);
-
-public:
- enum CallMode {
- CALL_MODE_SELF,
- CALL_MODE_NODE_PATH,
- CALL_MODE_INSTANCE,
- CALL_MODE_BASIC_TYPE,
-
- };
-
- enum AssignOp {
- ASSIGN_OP_NONE,
- ASSIGN_OP_ADD,
- ASSIGN_OP_SUB,
- ASSIGN_OP_MUL,
- ASSIGN_OP_DIV,
- ASSIGN_OP_MOD,
- ASSIGN_OP_SHIFT_LEFT,
- ASSIGN_OP_SHIFT_RIGHT,
- ASSIGN_OP_BIT_AND,
- ASSIGN_OP_BIT_OR,
- ASSIGN_OP_BIT_XOR,
- ASSIGN_OP_MAX
- };
-
-private:
- PropertyInfo type_cache;
-
- CallMode call_mode;
- Variant::Type basic_type;
- StringName base_type;
- String base_script;
- NodePath base_path;
- StringName property;
- StringName index;
- AssignOp assign_op;
-
- Node *_get_base_node() const;
- StringName _get_base_type() const;
-
- void _update_base_type();
-
- void _update_cache();
-
- void _set_type_cache(const Dictionary &p_type);
- Dictionary _get_type_cache() const;
-
- void _adjust_input_index(PropertyInfo &pinfo) const;
-
-protected:
- virtual void _validate_property(PropertyInfo &property) const override;
-
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_text() const override;
- virtual String get_category() const override { return "functions"; }
-
- void set_base_type(const StringName &p_type);
- StringName get_base_type() const;
-
- void set_base_script(const String &p_path);
- String get_base_script() const;
-
- void set_basic_type(Variant::Type p_type);
- Variant::Type get_basic_type() const;
-
- void set_property(const StringName &p_type);
- StringName get_property() const;
-
- void set_base_path(const NodePath &p_type);
- NodePath get_base_path() const;
-
- void set_call_mode(CallMode p_mode);
- CallMode get_call_mode() const;
-
- void set_index(const StringName &p_type);
- StringName get_index() const;
-
- void set_assign_op(AssignOp p_op);
- AssignOp get_assign_op() const;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
- virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override;
-
- VisualScriptPropertySet();
-};
-
-VARIANT_ENUM_CAST(VisualScriptPropertySet::CallMode);
-VARIANT_ENUM_CAST(VisualScriptPropertySet::AssignOp);
-
-class VisualScriptPropertyGet : public VisualScriptNode {
- GDCLASS(VisualScriptPropertyGet, VisualScriptNode);
-
-public:
- enum CallMode {
- CALL_MODE_SELF,
- CALL_MODE_NODE_PATH,
- CALL_MODE_INSTANCE,
- CALL_MODE_BASIC_TYPE,
-
- };
-
-private:
- Variant::Type type_cache;
-
- CallMode call_mode;
- Variant::Type basic_type;
- StringName base_type;
- String base_script;
- NodePath base_path;
- StringName property;
- StringName index;
-
- void _update_base_type();
- Node *_get_base_node() const;
- StringName _get_base_type() const;
-
- void _update_cache();
-
- void _set_type_cache(Variant::Type p_type);
- Variant::Type _get_type_cache() const;
-
- void _adjust_input_index(PropertyInfo &pinfo) const;
-
-protected:
- virtual void _validate_property(PropertyInfo &property) const override;
-
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_text() const override;
- virtual String get_category() const override { return "functions"; }
-
- void set_base_type(const StringName &p_type);
- StringName get_base_type() const;
-
- void set_base_script(const String &p_path);
- String get_base_script() const;
-
- void set_basic_type(Variant::Type p_type);
- Variant::Type get_basic_type() const;
-
- void set_property(const StringName &p_type);
- StringName get_property() const;
-
- void set_base_path(const NodePath &p_type);
- NodePath get_base_path() const;
-
- void set_call_mode(CallMode p_mode);
- CallMode get_call_mode() const;
-
- void set_index(const StringName &p_type);
- StringName get_index() const;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptPropertyGet();
-};
-
-VARIANT_ENUM_CAST(VisualScriptPropertyGet::CallMode);
-
-class VisualScriptEmitSignal : public VisualScriptNode {
- GDCLASS(VisualScriptEmitSignal, VisualScriptNode);
-
-private:
- StringName name;
-
-protected:
- virtual void _validate_property(PropertyInfo &property) const override;
-
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- //virtual String get_text() const;
- virtual String get_category() const override { return "functions"; }
-
- void set_signal(const StringName &p_type);
- StringName get_signal() const;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptEmitSignal();
-};
-
-void register_visual_script_func_nodes();
-
-#endif // VISUAL_SCRIPT_FUNC_NODES_H
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
deleted file mode 100644
index 5907e6a489..0000000000
--- a/modules/visual_script/visual_script_nodes.cpp
+++ /dev/null
@@ -1,4072 +0,0 @@
-/*************************************************************************/
-/* visual_script_nodes.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "visual_script_nodes.h"
-
-#include "core/config/engine.h"
-#include "core/config/project_settings.h"
-#include "core/core_constants.h"
-#include "core/input/input.h"
-#include "core/os/os.h"
-#include "scene/main/node.h"
-#include "scene/main/scene_tree.h"
-
-//////////////////////////////////////////
-////////////////FUNCTION//////////////////
-//////////////////////////////////////////
-
-bool VisualScriptFunction::_set(const StringName &p_name, const Variant &p_value) {
- if (p_name == "argument_count") {
- int new_argc = p_value;
- int argc = arguments.size();
- if (argc == new_argc) {
- return true;
- }
-
- arguments.resize(new_argc);
-
- for (int i = argc; i < new_argc; i++) {
- arguments.write[i].name = "arg" + itos(i + 1);
- arguments.write[i].type = Variant::NIL;
- }
- ports_changed_notify();
- notify_property_list_changed();
- return true;
- }
- if (String(p_name).begins_with("argument_")) {
- int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1;
- ERR_FAIL_INDEX_V(idx, arguments.size(), false);
- String what = String(p_name).get_slice("/", 1);
- if (what == "type") {
- Variant::Type new_type = Variant::Type(int(p_value));
- arguments.write[idx].type = new_type;
- ports_changed_notify();
-
- return true;
- }
-
- if (what == "name") {
- arguments.write[idx].name = p_value;
- ports_changed_notify();
- return true;
- }
- }
-
- if (p_name == "stack/stackless") {
- set_stack_less(p_value);
- return true;
- }
-
- if (p_name == "stack/size") {
- stack_size = p_value;
- return true;
- }
-
- if (p_name == "rpc/mode") {
- rpc_mode = MultiplayerAPI::RPCMode(int(p_value));
- return true;
- }
-
- if (p_name == "sequenced/sequenced") {
- sequenced = p_value;
- ports_changed_notify();
- return true;
- }
-
- return false;
-}
-
-bool VisualScriptFunction::_get(const StringName &p_name, Variant &r_ret) const {
- if (p_name == "argument_count") {
- r_ret = arguments.size();
- return true;
- }
- if (String(p_name).begins_with("argument_")) {
- int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1;
- ERR_FAIL_INDEX_V(idx, arguments.size(), false);
- String what = String(p_name).get_slice("/", 1);
- if (what == "type") {
- r_ret = arguments[idx].type;
- return true;
- }
- if (what == "name") {
- r_ret = arguments[idx].name;
- return true;
- }
- }
-
- if (p_name == "stack/stackless") {
- r_ret = stack_less;
- return true;
- }
-
- if (p_name == "stack/size") {
- r_ret = stack_size;
- return true;
- }
-
- if (p_name == "rpc/mode") {
- r_ret = rpc_mode;
- return true;
- }
-
- if (p_name == "sequenced/sequenced") {
- r_ret = sequenced;
- return true;
- }
-
- return false;
-}
-
-void VisualScriptFunction::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::INT, "argument_count", PROPERTY_HINT_RANGE, "0,256"));
- String argt = "Any";
- for (int i = 1; i < Variant::VARIANT_MAX; i++) {
- argt += "," + Variant::get_type_name(Variant::Type(i));
- }
-
- for (int i = 0; i < arguments.size(); i++) {
- p_list->push_back(PropertyInfo(Variant::INT, "argument_" + itos(i + 1) + "/type", PROPERTY_HINT_ENUM, argt));
- p_list->push_back(PropertyInfo(Variant::STRING, "argument_" + itos(i + 1) + "/name"));
- }
-
- p_list->push_back(PropertyInfo(Variant::BOOL, "sequenced/sequenced"));
-
- if (!stack_less) {
- p_list->push_back(PropertyInfo(Variant::INT, "stack/size", PROPERTY_HINT_RANGE, "1,100000"));
- }
- p_list->push_back(PropertyInfo(Variant::BOOL, "stack/stackless"));
- p_list->push_back(PropertyInfo(Variant::INT, "rpc/mode", PROPERTY_HINT_ENUM, "Disabled,Any,Authority"));
-}
-
-int VisualScriptFunction::get_output_sequence_port_count() const {
- return 1;
-}
-
-bool VisualScriptFunction::has_input_sequence_port() const {
- return false;
-}
-
-int VisualScriptFunction::get_input_value_port_count() const {
- return 0;
-}
-
-int VisualScriptFunction::get_output_value_port_count() const {
- return arguments.size();
-}
-
-String VisualScriptFunction::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptFunction::get_input_value_port_info(int p_idx) const {
- ERR_FAIL_V(PropertyInfo());
-}
-
-PropertyInfo VisualScriptFunction::get_output_value_port_info(int p_idx) const {
- // Need to check it without ERR_FAIL_COND, to prevent warnings from appearing on node creation via dragging.
- if (p_idx < 0 || p_idx >= arguments.size()) {
- return PropertyInfo();
- }
- PropertyInfo out;
- out.type = arguments[p_idx].type;
- out.name = arguments[p_idx].name;
- out.hint = arguments[p_idx].hint;
- out.hint_string = arguments[p_idx].hint_string;
- return out;
-}
-
-String VisualScriptFunction::get_caption() const {
- return RTR("Function");
-}
-
-String VisualScriptFunction::get_text() const {
- return get_name(); //use name as function name I guess
-}
-
-void VisualScriptFunction::add_argument(Variant::Type p_type, const String &p_name, int p_index, const PropertyHint p_hint, const String &p_hint_string) {
- Argument arg;
- arg.name = p_name;
- arg.type = p_type;
- arg.hint = p_hint;
- arg.hint_string = p_hint_string;
- if (p_index >= 0) {
- arguments.insert(p_index, arg);
- } else {
- arguments.push_back(arg);
- }
-
- ports_changed_notify();
-}
-
-void VisualScriptFunction::set_argument_type(int p_argidx, Variant::Type p_type) {
- ERR_FAIL_INDEX(p_argidx, arguments.size());
-
- arguments.write[p_argidx].type = p_type;
- ports_changed_notify();
-}
-
-Variant::Type VisualScriptFunction::get_argument_type(int p_argidx) const {
- ERR_FAIL_INDEX_V(p_argidx, arguments.size(), Variant::NIL);
- return arguments[p_argidx].type;
-}
-
-void VisualScriptFunction::set_argument_name(int p_argidx, const String &p_name) {
- ERR_FAIL_INDEX(p_argidx, arguments.size());
-
- arguments.write[p_argidx].name = p_name;
- ports_changed_notify();
-}
-
-String VisualScriptFunction::get_argument_name(int p_argidx) const {
- ERR_FAIL_INDEX_V(p_argidx, arguments.size(), String());
- return arguments[p_argidx].name;
-}
-
-void VisualScriptFunction::remove_argument(int p_argidx) {
- ERR_FAIL_INDEX(p_argidx, arguments.size());
-
- arguments.remove_at(p_argidx);
- ports_changed_notify();
-}
-
-int VisualScriptFunction::get_argument_count() const {
- return arguments.size();
-}
-
-void VisualScriptFunction::set_rpc_mode(MultiplayerAPI::RPCMode p_mode) {
- rpc_mode = p_mode;
-}
-
-MultiplayerAPI::RPCMode VisualScriptFunction::get_rpc_mode() const {
- return rpc_mode;
-}
-
-class VisualScriptNodeInstanceFunction : public VisualScriptNodeInstance {
-public:
- VisualScriptFunction *node = nullptr;
- VisualScriptInstance *instance = nullptr;
-
- //virtual int get_working_memory_size() const override { return 0; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- int ac = node->get_argument_count();
-
- for (int i = 0; i < ac; i++) {
-#ifdef DEBUG_ENABLED
- Variant::Type expected = node->get_argument_type(i);
- if (expected != Variant::NIL) {
- if (!Variant::can_convert_strict(p_inputs[i]->get_type(), expected)) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.expected = expected;
- r_error.argument = i;
- return 0;
- }
- }
-#endif
-
- *p_outputs[i] = *p_inputs[i];
- }
-
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptFunction::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceFunction *instance = memnew(VisualScriptNodeInstanceFunction);
- instance->node = this;
- instance->instance = p_instance;
- return instance;
-}
-
-void VisualScriptFunction::reset_state() {
- arguments.clear();
- stack_size = 256;
- stack_less = false;
- sequenced = true;
- rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
-}
-
-VisualScriptFunction::VisualScriptFunction() {
- stack_size = 256;
- stack_less = false;
- sequenced = true;
- rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
-}
-
-void VisualScriptFunction::set_stack_less(bool p_enable) {
- stack_less = p_enable;
- notify_property_list_changed();
-}
-
-bool VisualScriptFunction::is_stack_less() const {
- return stack_less;
-}
-
-void VisualScriptFunction::set_sequenced(bool p_enable) {
- sequenced = p_enable;
-}
-
-bool VisualScriptFunction::is_sequenced() const {
- return sequenced;
-}
-
-void VisualScriptFunction::set_stack_size(int p_size) {
- ERR_FAIL_COND(p_size < 1 || p_size > 100000);
- stack_size = p_size;
-}
-
-int VisualScriptFunction::get_stack_size() const {
- return stack_size;
-}
-
-//////////////////////////////////////////
-/////////////////LISTS////////////////////
-//////////////////////////////////////////
-
-int VisualScriptLists::get_output_sequence_port_count() const {
- if (sequenced) {
- return 1;
- }
- return 0;
-}
-
-bool VisualScriptLists::has_input_sequence_port() const {
- return sequenced;
-}
-
-String VisualScriptLists::get_output_sequence_port_text(int p_port) const {
- return "";
-}
-
-int VisualScriptLists::get_input_value_port_count() const {
- return inputports.size();
-}
-
-int VisualScriptLists::get_output_value_port_count() const {
- return outputports.size();
-}
-
-PropertyInfo VisualScriptLists::get_input_value_port_info(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, inputports.size(), PropertyInfo());
-
- PropertyInfo pi;
- pi.name = inputports[p_idx].name;
- pi.type = inputports[p_idx].type;
- return pi;
-}
-
-PropertyInfo VisualScriptLists::get_output_value_port_info(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, outputports.size(), PropertyInfo());
-
- PropertyInfo pi;
- pi.name = outputports[p_idx].name;
- pi.type = outputports[p_idx].type;
- return pi;
-}
-
-bool VisualScriptLists::is_input_port_editable() const {
- return ((flags & INPUT_EDITABLE) == INPUT_EDITABLE);
-}
-
-bool VisualScriptLists::is_input_port_name_editable() const {
- return ((flags & INPUT_NAME_EDITABLE) == INPUT_NAME_EDITABLE);
-}
-
-bool VisualScriptLists::is_input_port_type_editable() const {
- return ((flags & INPUT_TYPE_EDITABLE) == INPUT_TYPE_EDITABLE);
-}
-
-bool VisualScriptLists::is_output_port_editable() const {
- return ((flags & OUTPUT_EDITABLE) == OUTPUT_EDITABLE);
-}
-
-bool VisualScriptLists::is_output_port_name_editable() const {
- return ((flags & INPUT_NAME_EDITABLE) == INPUT_NAME_EDITABLE);
-}
-
-bool VisualScriptLists::is_output_port_type_editable() const {
- return ((flags & INPUT_TYPE_EDITABLE) == INPUT_TYPE_EDITABLE);
-}
-
-// for the inspector
-bool VisualScriptLists::_set(const StringName &p_name, const Variant &p_value) {
- if (p_name == "input_count" && is_input_port_editable()) {
- int new_argc = p_value;
- int argc = inputports.size();
- if (argc == new_argc) {
- return true;
- }
-
- inputports.resize(new_argc);
-
- for (int i = argc; i < new_argc; i++) {
- inputports.write[i].name = "arg" + itos(i + 1);
- inputports.write[i].type = Variant::NIL;
- }
- ports_changed_notify();
- notify_property_list_changed();
- return true;
- }
- if (String(p_name).begins_with("input_") && is_input_port_editable()) {
- int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1;
- ERR_FAIL_INDEX_V(idx, inputports.size(), false);
- String what = String(p_name).get_slice("/", 1);
- if (what == "type") {
- Variant::Type new_type = Variant::Type(int(p_value));
- inputports.write[idx].type = new_type;
- ports_changed_notify();
-
- return true;
- }
-
- if (what == "name") {
- inputports.write[idx].name = p_value;
- ports_changed_notify();
- return true;
- }
- }
-
- if (p_name == "output_count" && is_output_port_editable()) {
- int new_argc = p_value;
- int argc = outputports.size();
- if (argc == new_argc) {
- return true;
- }
-
- outputports.resize(new_argc);
-
- for (int i = argc; i < new_argc; i++) {
- outputports.write[i].name = "arg" + itos(i + 1);
- outputports.write[i].type = Variant::NIL;
- }
- ports_changed_notify();
- notify_property_list_changed();
- return true;
- }
- if (String(p_name).begins_with("output_") && is_output_port_editable()) {
- int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1;
- ERR_FAIL_INDEX_V(idx, outputports.size(), false);
- String what = String(p_name).get_slice("/", 1);
- if (what == "type") {
- Variant::Type new_type = Variant::Type(int(p_value));
- outputports.write[idx].type = new_type;
- ports_changed_notify();
-
- return true;
- }
-
- if (what == "name") {
- outputports.write[idx].name = p_value;
- ports_changed_notify();
- return true;
- }
- }
-
- if (p_name == "sequenced/sequenced") {
- sequenced = p_value;
- ports_changed_notify();
- return true;
- }
-
- return false;
-}
-
-bool VisualScriptLists::_get(const StringName &p_name, Variant &r_ret) const {
- if (p_name == "input_count" && is_input_port_editable()) {
- r_ret = inputports.size();
- return true;
- }
- if (String(p_name).begins_with("input_") && is_input_port_editable()) {
- int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1;
- ERR_FAIL_INDEX_V(idx, inputports.size(), false);
- String what = String(p_name).get_slice("/", 1);
- if (what == "type") {
- r_ret = inputports[idx].type;
- return true;
- }
- if (what == "name") {
- r_ret = inputports[idx].name;
- return true;
- }
- }
-
- if (p_name == "output_count" && is_output_port_editable()) {
- r_ret = outputports.size();
- return true;
- }
- if (String(p_name).begins_with("output_") && is_output_port_editable()) {
- int idx = String(p_name).get_slicec('_', 1).get_slicec('/', 0).to_int() - 1;
- ERR_FAIL_INDEX_V(idx, outputports.size(), false);
- String what = String(p_name).get_slice("/", 1);
- if (what == "type") {
- r_ret = outputports[idx].type;
- return true;
- }
- if (what == "name") {
- r_ret = outputports[idx].name;
- return true;
- }
- }
-
- if (p_name == "sequenced/sequenced") {
- r_ret = sequenced;
- return true;
- }
-
- return false;
-}
-
-void VisualScriptLists::_get_property_list(List<PropertyInfo> *p_list) const {
- if (is_input_port_editable()) {
- p_list->push_back(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,256"));
- String argt = "Any";
- for (int i = 1; i < Variant::VARIANT_MAX; i++) {
- argt += "," + Variant::get_type_name(Variant::Type(i));
- }
-
- for (int i = 0; i < inputports.size(); i++) {
- p_list->push_back(PropertyInfo(Variant::INT, "input_" + itos(i + 1) + "/type", PROPERTY_HINT_ENUM, argt));
- p_list->push_back(PropertyInfo(Variant::STRING, "input_" + itos(i + 1) + "/name"));
- }
- }
-
- if (is_output_port_editable()) {
- p_list->push_back(PropertyInfo(Variant::INT, "output_count", PROPERTY_HINT_RANGE, "0,256"));
- String argt = "Any";
- for (int i = 1; i < Variant::VARIANT_MAX; i++) {
- argt += "," + Variant::get_type_name(Variant::Type(i));
- }
-
- for (int i = 0; i < outputports.size(); i++) {
- p_list->push_back(PropertyInfo(Variant::INT, "output_" + itos(i + 1) + "/type", PROPERTY_HINT_ENUM, argt));
- p_list->push_back(PropertyInfo(Variant::STRING, "output_" + itos(i + 1) + "/name"));
- }
- }
- p_list->push_back(PropertyInfo(Variant::BOOL, "sequenced/sequenced"));
-}
-
-// input data port interaction
-void VisualScriptLists::add_input_data_port(Variant::Type p_type, const String &p_name, int p_index) {
- if (!is_input_port_editable()) {
- return;
- }
-
- Port inp;
- inp.name = p_name;
- inp.type = p_type;
- if (p_index >= 0) {
- inputports.insert(p_index, inp);
- } else {
- inputports.push_back(inp);
- }
-
- ports_changed_notify();
- notify_property_list_changed();
-}
-
-void VisualScriptLists::set_input_data_port_type(int p_idx, Variant::Type p_type) {
- if (!is_input_port_type_editable()) {
- return;
- }
-
- ERR_FAIL_INDEX(p_idx, inputports.size());
-
- inputports.write[p_idx].type = p_type;
- ports_changed_notify();
- notify_property_list_changed();
-}
-
-void VisualScriptLists::set_input_data_port_name(int p_idx, const String &p_name) {
- if (!is_input_port_name_editable()) {
- return;
- }
-
- ERR_FAIL_INDEX(p_idx, inputports.size());
-
- inputports.write[p_idx].name = p_name;
- ports_changed_notify();
- notify_property_list_changed();
-}
-
-void VisualScriptLists::remove_input_data_port(int p_argidx) {
- if (!is_input_port_editable()) {
- return;
- }
-
- ERR_FAIL_INDEX(p_argidx, inputports.size());
-
- inputports.remove_at(p_argidx);
-
- ports_changed_notify();
- notify_property_list_changed();
-}
-
-// output data port interaction
-void VisualScriptLists::add_output_data_port(Variant::Type p_type, const String &p_name, int p_index) {
- if (!is_output_port_editable()) {
- return;
- }
-
- Port out;
- out.name = p_name;
- out.type = p_type;
- if (p_index >= 0) {
- outputports.insert(p_index, out);
- } else {
- outputports.push_back(out);
- }
-
- ports_changed_notify();
- notify_property_list_changed();
-}
-
-void VisualScriptLists::set_output_data_port_type(int p_idx, Variant::Type p_type) {
- if (!is_output_port_type_editable()) {
- return;
- }
-
- ERR_FAIL_INDEX(p_idx, outputports.size());
-
- outputports.write[p_idx].type = p_type;
- ports_changed_notify();
- notify_property_list_changed();
-}
-
-void VisualScriptLists::set_output_data_port_name(int p_idx, const String &p_name) {
- if (!is_output_port_name_editable()) {
- return;
- }
-
- ERR_FAIL_INDEX(p_idx, outputports.size());
-
- outputports.write[p_idx].name = p_name;
- ports_changed_notify();
- notify_property_list_changed();
-}
-
-void VisualScriptLists::remove_output_data_port(int p_argidx) {
- if (!is_output_port_editable()) {
- return;
- }
-
- ERR_FAIL_INDEX(p_argidx, outputports.size());
-
- outputports.remove_at(p_argidx);
-
- ports_changed_notify();
- notify_property_list_changed();
-}
-
-// sequences
-void VisualScriptLists::set_sequenced(bool p_enable) {
- if (sequenced == p_enable) {
- return;
- }
- sequenced = p_enable;
- ports_changed_notify();
-}
-
-bool VisualScriptLists::is_sequenced() const {
- return sequenced;
-}
-
-void VisualScriptLists::reset_state() {
- inputports.clear();
- outputports.clear();
- sequenced = false;
- flags = 0;
-}
-
-VisualScriptLists::VisualScriptLists() {
- // initialize
- sequenced = false;
- flags = 0;
-}
-
-void VisualScriptLists::_bind_methods() {
- ClassDB::bind_method(D_METHOD("add_input_data_port", "type", "name", "index"), &VisualScriptLists::add_input_data_port);
- ClassDB::bind_method(D_METHOD("set_input_data_port_name", "index", "name"), &VisualScriptLists::set_input_data_port_name);
- ClassDB::bind_method(D_METHOD("set_input_data_port_type", "index", "type"), &VisualScriptLists::set_input_data_port_type);
- ClassDB::bind_method(D_METHOD("remove_input_data_port", "index"), &VisualScriptLists::remove_input_data_port);
-
- ClassDB::bind_method(D_METHOD("add_output_data_port", "type", "name", "index"), &VisualScriptLists::add_output_data_port);
- ClassDB::bind_method(D_METHOD("set_output_data_port_name", "index", "name"), &VisualScriptLists::set_output_data_port_name);
- ClassDB::bind_method(D_METHOD("set_output_data_port_type", "index", "type"), &VisualScriptLists::set_output_data_port_type);
- ClassDB::bind_method(D_METHOD("remove_output_data_port", "index"), &VisualScriptLists::remove_output_data_port);
-}
-
-//////////////////////////////////////////
-//////////////COMPOSEARRAY////////////////
-//////////////////////////////////////////
-
-int VisualScriptComposeArray::get_output_sequence_port_count() const {
- if (sequenced) {
- return 1;
- }
- return 0;
-}
-
-bool VisualScriptComposeArray::has_input_sequence_port() const {
- return sequenced;
-}
-
-String VisualScriptComposeArray::get_output_sequence_port_text(int p_port) const {
- return "";
-}
-
-int VisualScriptComposeArray::get_input_value_port_count() const {
- return inputports.size();
-}
-
-int VisualScriptComposeArray::get_output_value_port_count() const {
- return 1;
-}
-
-PropertyInfo VisualScriptComposeArray::get_input_value_port_info(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, inputports.size(), PropertyInfo());
-
- PropertyInfo pi;
- pi.name = inputports[p_idx].name;
- pi.type = inputports[p_idx].type;
- return pi;
-}
-
-PropertyInfo VisualScriptComposeArray::get_output_value_port_info(int p_idx) const {
- PropertyInfo pi;
- pi.name = "out";
- pi.type = Variant::ARRAY;
- return pi;
-}
-
-String VisualScriptComposeArray::get_caption() const {
- return RTR("Compose Array");
-}
-
-String VisualScriptComposeArray::get_text() const {
- return "";
-}
-
-class VisualScriptComposeArrayNode : public VisualScriptNodeInstance {
-public:
- int input_count = 0;
- virtual int get_working_memory_size() const override { return 0; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- if (input_count > 0) {
- Array arr;
- for (int i = 0; i < input_count; i++) {
- arr.push_back((*p_inputs[i]));
- }
- Variant va = Variant(arr);
-
- *p_outputs[0] = va;
- }
-
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptComposeArray::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptComposeArrayNode *instance = memnew(VisualScriptComposeArrayNode);
- instance->input_count = inputports.size();
- return instance;
-}
-
-VisualScriptComposeArray::VisualScriptComposeArray() {
- // initialize stuff here
- sequenced = false;
- flags = INPUT_EDITABLE;
-}
-
-//////////////////////////////////////////
-////////////////OPERATOR//////////////////
-//////////////////////////////////////////
-
-int VisualScriptOperator::get_output_sequence_port_count() const {
- return 0;
-}
-
-bool VisualScriptOperator::has_input_sequence_port() const {
- return false;
-}
-
-int VisualScriptOperator::get_input_value_port_count() const {
- return (op == Variant::OP_BIT_NEGATE || op == Variant::OP_NOT || op == Variant::OP_NEGATE || op == Variant::OP_POSITIVE) ? 1 : 2;
-}
-
-int VisualScriptOperator::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptOperator::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptOperator::get_input_value_port_info(int p_idx) const {
- static const Variant::Type port_types[Variant::OP_MAX][2] = {
- { Variant::NIL, Variant::NIL }, //OP_EQUAL,
- { Variant::NIL, Variant::NIL }, //OP_NOT_EQUAL,
- { Variant::NIL, Variant::NIL }, //OP_LESS,
- { Variant::NIL, Variant::NIL }, //OP_LESS_EQUAL,
- { Variant::NIL, Variant::NIL }, //OP_GREATER,
- { Variant::NIL, Variant::NIL }, //OP_GREATER_EQUAL,
- //mathematic
- { Variant::NIL, Variant::NIL }, //OP_ADD,
- { Variant::NIL, Variant::NIL }, //OP_SUBTRACT,
- { Variant::NIL, Variant::NIL }, //OP_MULTIPLY,
- { Variant::NIL, Variant::NIL }, //OP_DIVIDE,
- { Variant::NIL, Variant::NIL }, //OP_NEGATE,
- { Variant::NIL, Variant::NIL }, //OP_POSITIVE,
- { Variant::INT, Variant::INT }, //OP_MODULE,
- //bitwise
- { Variant::INT, Variant::INT }, //OP_SHIFT_LEFT,
- { Variant::INT, Variant::INT }, //OP_SHIFT_RIGHT,
- { Variant::INT, Variant::INT }, //OP_BIT_AND,
- { Variant::INT, Variant::INT }, //OP_BIT_OR,
- { Variant::INT, Variant::INT }, //OP_BIT_XOR,
- { Variant::INT, Variant::INT }, //OP_BIT_NEGATE,
- //logic
- { Variant::BOOL, Variant::BOOL }, //OP_AND,
- { Variant::BOOL, Variant::BOOL }, //OP_OR,
- { Variant::BOOL, Variant::BOOL }, //OP_XOR,
- { Variant::BOOL, Variant::BOOL }, //OP_NOT,
- //containment
- { Variant::NIL, Variant::NIL } //OP_IN,
- };
-
- ERR_FAIL_INDEX_V(p_idx, 2, PropertyInfo());
-
- PropertyInfo pinfo;
- pinfo.name = p_idx == 0 ? "A" : "B";
- pinfo.type = port_types[op][p_idx];
- if (pinfo.type == Variant::NIL) {
- pinfo.type = typed;
- }
- return pinfo;
-}
-
-PropertyInfo VisualScriptOperator::get_output_value_port_info(int p_idx) const {
- static const Variant::Type port_types[Variant::OP_MAX] = {
- //comparison
- Variant::BOOL, //OP_EQUAL,
- Variant::BOOL, //OP_NOT_EQUAL,
- Variant::BOOL, //OP_LESS,
- Variant::BOOL, //OP_LESS_EQUAL,
- Variant::BOOL, //OP_GREATER,
- Variant::BOOL, //OP_GREATER_EQUAL,
- //mathematic
- Variant::NIL, //OP_ADD,
- Variant::NIL, //OP_SUBTRACT,
- Variant::NIL, //OP_MULTIPLY,
- Variant::NIL, //OP_DIVIDE,
- Variant::NIL, //OP_NEGATE,
- Variant::NIL, //OP_POSITIVE,
- Variant::INT, //OP_MODULE,
- //bitwise
- Variant::INT, //OP_SHIFT_LEFT,
- Variant::INT, //OP_SHIFT_RIGHT,
- Variant::INT, //OP_BIT_AND,
- Variant::INT, //OP_BIT_OR,
- Variant::INT, //OP_BIT_XOR,
- Variant::INT, //OP_BIT_NEGATE,
- //logic
- Variant::BOOL, //OP_AND,
- Variant::BOOL, //OP_OR,
- Variant::BOOL, //OP_XOR,
- Variant::BOOL, //OP_NOT,
- //containment
- Variant::BOOL //OP_IN,
- };
-
- PropertyInfo pinfo;
- pinfo.name = "";
- pinfo.type = port_types[op];
- if (pinfo.type == Variant::NIL) {
- pinfo.type = typed;
- }
- return pinfo;
-}
-
-String VisualScriptOperator::get_caption() const {
- switch (op) {
- // comparison
- case Variant::OP_EQUAL:
- return U"A = B";
- case Variant::OP_NOT_EQUAL:
- return U"A \u2260 B";
- case Variant::OP_LESS:
- return U"A < B";
- case Variant::OP_LESS_EQUAL:
- return U"A \u2264 B";
- case Variant::OP_GREATER:
- return U"A > B";
- case Variant::OP_GREATER_EQUAL:
- return U"A \u2265 B";
-
- // mathematic
- case Variant::OP_ADD:
- return U"A + B";
- case Variant::OP_SUBTRACT:
- return U"A - B";
- case Variant::OP_MULTIPLY:
- return U"A \u00D7 B";
- case Variant::OP_DIVIDE:
- return U"A \u00F7 B";
- case Variant::OP_NEGATE:
- return U"\u00AC A";
- case Variant::OP_POSITIVE:
- return U"+ A";
- case Variant::OP_MODULE:
- return U"A mod B";
-
- // bitwise
- case Variant::OP_SHIFT_LEFT:
- return U"A << B";
- case Variant::OP_SHIFT_RIGHT:
- return U"A >> B";
- case Variant::OP_BIT_AND:
- return U"A & B";
- case Variant::OP_BIT_OR:
- return U"A | B";
- case Variant::OP_BIT_XOR:
- return U"A ^ B";
- case Variant::OP_BIT_NEGATE:
- return U"~A";
-
- // logic
- case Variant::OP_AND:
- return U"A and B";
- case Variant::OP_OR:
- return U"A or B";
- case Variant::OP_XOR:
- return U"A xor B";
- case Variant::OP_NOT:
- return U"not A";
- case Variant::OP_IN:
- return U"A in B";
-
- default: {
- ERR_FAIL_V_MSG(
- U"Unknown node",
- U"Unknown node type encountered, caption not available.");
- }
- }
-}
-
-String VisualScriptOperator::get_operator_name(Variant::Operator p_op) {
- switch (p_op) {
- // comparison
- case Variant::OP_EQUAL:
- return "Are Equal";
- case Variant::OP_NOT_EQUAL:
- return "Are Not Equal";
- case Variant::OP_LESS:
- return "Less Than";
- case Variant::OP_LESS_EQUAL:
- return "Less Than or Equal";
- case Variant::OP_GREATER:
- return "Greater Than";
- case Variant::OP_GREATER_EQUAL:
- return "Greater Than or Equal";
-
- // mathematic
- case Variant::OP_ADD:
- return "Add";
- case Variant::OP_SUBTRACT:
- return "Subtract";
- case Variant::OP_MULTIPLY:
- return "Multiply";
- case Variant::OP_DIVIDE:
- return "Divide";
- case Variant::OP_NEGATE:
- return "Negate";
- case Variant::OP_POSITIVE:
- return "Positive";
- case Variant::OP_MODULE:
- return "Remainder";
-
- // bitwise
- case Variant::OP_SHIFT_LEFT:
- return "Bit Shift Left";
- case Variant::OP_SHIFT_RIGHT:
- return "Bit Shift Right";
- case Variant::OP_BIT_AND:
- return "Bit And";
- case Variant::OP_BIT_OR:
- return "Bit Or";
- case Variant::OP_BIT_XOR:
- return "Bit Xor";
- case Variant::OP_BIT_NEGATE:
- return "Bit Negate";
-
- // logic
- case Variant::OP_AND:
- return "And";
- case Variant::OP_OR:
- return "Or";
- case Variant::OP_XOR:
- return "Xor";
- case Variant::OP_NOT:
- return "Not";
- case Variant::OP_IN:
- return "In";
-
- default: {
- ERR_FAIL_INDEX_V(p_op, Variant::OP_MAX, "");
- return "Unknown Operator";
- }
- }
-}
-
-void VisualScriptOperator::set_operator(Variant::Operator p_op) {
- if (op == p_op) {
- return;
- }
- op = p_op;
- ports_changed_notify();
-}
-
-Variant::Operator VisualScriptOperator::get_operator() const {
- return op;
-}
-
-void VisualScriptOperator::set_typed(Variant::Type p_op) {
- if (typed == p_op) {
- return;
- }
-
- typed = p_op;
- ports_changed_notify();
-}
-
-Variant::Type VisualScriptOperator::get_typed() const {
- return typed;
-}
-
-void VisualScriptOperator::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_operator", "op"), &VisualScriptOperator::set_operator);
- ClassDB::bind_method(D_METHOD("get_operator"), &VisualScriptOperator::get_operator);
-
- ClassDB::bind_method(D_METHOD("set_typed", "type"), &VisualScriptOperator::set_typed);
- ClassDB::bind_method(D_METHOD("get_typed"), &VisualScriptOperator::get_typed);
-
- String types;
- for (int i = 0; i < Variant::OP_MAX; i++) {
- if (i > 0) {
- types += ",";
- }
- types += get_operator_name(static_cast<Variant::Operator>(i));
- }
-
- String argt = "Any";
- for (int i = 1; i < Variant::VARIANT_MAX; i++) {
- argt += "," + Variant::get_type_name(Variant::Type(i));
- }
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "operator", PROPERTY_HINT_ENUM, types), "set_operator", "get_operator");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_typed", "get_typed");
-}
-
-class VisualScriptNodeInstanceOperator : public VisualScriptNodeInstance {
-public:
- bool unary = false;
- Variant::Operator op;
-
- //virtual int get_working_memory_size() const override { return 0; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- bool valid;
- if (unary) {
- Variant::evaluate(op, *p_inputs[0], Variant(), *p_outputs[0], valid);
- } else {
- Variant::evaluate(op, *p_inputs[0], *p_inputs[1], *p_outputs[0], valid);
- }
-
- if (!valid) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- if (p_outputs[0]->get_type() == Variant::STRING) {
- r_error_str = *p_outputs[0];
- } else {
- if (unary) {
- r_error_str = String(Variant::get_operator_name(op)) + ": " + RTR("Invalid argument of type:") + " " + Variant::get_type_name(p_inputs[0]->get_type());
- } else {
- r_error_str = String(Variant::get_operator_name(op)) + ": " + RTR("Invalid arguments:") + " A: " + Variant::get_type_name(p_inputs[0]->get_type()) + ", B: " + Variant::get_type_name(p_inputs[1]->get_type());
- }
- }
- }
-
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptOperator::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceOperator *instance = memnew(VisualScriptNodeInstanceOperator);
- instance->unary = get_input_value_port_count() == 1;
- instance->op = op;
- return instance;
-}
-
-VisualScriptOperator::VisualScriptOperator() {
- op = Variant::OP_ADD;
- typed = Variant::NIL;
-}
-
-template <Variant::Operator OP>
-static Ref<VisualScriptNode> create_op_node(const String &p_name) {
- Ref<VisualScriptOperator> node;
- node.instantiate();
- node->set_operator(OP);
- return node;
-}
-
-//////////////////////////////////////////
-////////////////OPERATOR//////////////////
-//////////////////////////////////////////
-
-int VisualScriptSelect::get_output_sequence_port_count() const {
- return 0;
-}
-
-bool VisualScriptSelect::has_input_sequence_port() const {
- return false;
-}
-
-int VisualScriptSelect::get_input_value_port_count() const {
- return 3;
-}
-
-int VisualScriptSelect::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptSelect::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptSelect::get_input_value_port_info(int p_idx) const {
- if (p_idx == 0) {
- return PropertyInfo(Variant::BOOL, "cond");
- } else if (p_idx == 1) {
- return PropertyInfo(typed, "a");
- } else {
- return PropertyInfo(typed, "b");
- }
-}
-
-PropertyInfo VisualScriptSelect::get_output_value_port_info(int p_idx) const {
- return PropertyInfo(typed, "out");
-}
-
-String VisualScriptSelect::get_caption() const {
- return RTR("Select");
-}
-
-String VisualScriptSelect::get_text() const {
- return RTR("a if cond, else b");
-}
-
-void VisualScriptSelect::set_typed(Variant::Type p_op) {
- if (typed == p_op) {
- return;
- }
-
- typed = p_op;
- ports_changed_notify();
-}
-
-Variant::Type VisualScriptSelect::get_typed() const {
- return typed;
-}
-
-void VisualScriptSelect::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_typed", "type"), &VisualScriptSelect::set_typed);
- ClassDB::bind_method(D_METHOD("get_typed"), &VisualScriptSelect::get_typed);
-
- String argt = "Any";
- for (int i = 1; i < Variant::VARIANT_MAX; i++) {
- argt += "," + Variant::get_type_name(Variant::Type(i));
- }
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_typed", "get_typed");
-}
-
-class VisualScriptNodeInstanceSelect : public VisualScriptNodeInstance {
-public:
- //virtual int get_working_memory_size() const override { return 0; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- bool cond = *p_inputs[0];
- if (cond) {
- *p_outputs[0] = *p_inputs[1];
- } else {
- *p_outputs[0] = *p_inputs[2];
- }
-
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptSelect::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceSelect *instance = memnew(VisualScriptNodeInstanceSelect);
- return instance;
-}
-
-VisualScriptSelect::VisualScriptSelect() {
- typed = Variant::NIL;
-}
-
-//////////////////////////////////////////
-////////////////VARIABLE GET//////////////////
-//////////////////////////////////////////
-
-int VisualScriptVariableGet::get_output_sequence_port_count() const {
- return 0;
-}
-
-bool VisualScriptVariableGet::has_input_sequence_port() const {
- return false;
-}
-
-int VisualScriptVariableGet::get_input_value_port_count() const {
- return 0;
-}
-
-int VisualScriptVariableGet::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptVariableGet::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptVariableGet::get_input_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-PropertyInfo VisualScriptVariableGet::get_output_value_port_info(int p_idx) const {
- PropertyInfo pinfo;
- pinfo.name = "value";
- if (get_visual_script().is_valid() && get_visual_script()->has_variable(variable)) {
- PropertyInfo vinfo = get_visual_script()->get_variable_info(variable);
- pinfo.type = vinfo.type;
- pinfo.hint = vinfo.hint;
- pinfo.hint_string = vinfo.hint_string;
- }
- return pinfo;
-}
-
-String VisualScriptVariableGet::get_caption() const {
- return vformat(RTR("Get %s"), variable);
-}
-
-void VisualScriptVariableGet::set_variable(StringName p_variable) {
- if (variable == p_variable) {
- return;
- }
- variable = p_variable;
- ports_changed_notify();
-}
-
-StringName VisualScriptVariableGet::get_variable() const {
- return variable;
-}
-
-void VisualScriptVariableGet::_validate_property(PropertyInfo &property) const {
- if (property.name == "var_name" && get_visual_script().is_valid()) {
- Ref<VisualScript> vs = get_visual_script();
- List<StringName> vars;
- vs->get_variable_list(&vars);
-
- String vhint;
- for (const StringName &E : vars) {
- if (!vhint.is_empty()) {
- vhint += ",";
- }
-
- vhint += E.operator String();
- }
-
- property.hint = PROPERTY_HINT_ENUM;
- property.hint_string = vhint;
- }
-}
-
-void VisualScriptVariableGet::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_variable", "name"), &VisualScriptVariableGet::set_variable);
- ClassDB::bind_method(D_METHOD("get_variable"), &VisualScriptVariableGet::get_variable);
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "var_name"), "set_variable", "get_variable");
-}
-
-class VisualScriptNodeInstanceVariableGet : public VisualScriptNodeInstance {
-public:
- VisualScriptVariableGet *node = nullptr;
- VisualScriptInstance *instance = nullptr;
- StringName variable;
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- if (!instance->get_variable(variable, p_outputs[0])) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = RTR("VariableGet not found in script:") + " '" + String(variable) + "'";
- return 0;
- }
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptVariableGet::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceVariableGet *instance = memnew(VisualScriptNodeInstanceVariableGet);
- instance->node = this;
- instance->instance = p_instance;
- instance->variable = variable;
- return instance;
-}
-
-VisualScriptVariableGet::VisualScriptVariableGet() {
-}
-
-//////////////////////////////////////////
-////////////////VARIABLE SET//////////////////
-//////////////////////////////////////////
-
-int VisualScriptVariableSet::get_output_sequence_port_count() const {
- return 1;
-}
-
-bool VisualScriptVariableSet::has_input_sequence_port() const {
- return true;
-}
-
-int VisualScriptVariableSet::get_input_value_port_count() const {
- return 1;
-}
-
-int VisualScriptVariableSet::get_output_value_port_count() const {
- return 0;
-}
-
-String VisualScriptVariableSet::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptVariableSet::get_input_value_port_info(int p_idx) const {
- PropertyInfo pinfo;
- pinfo.name = "set";
- if (get_visual_script().is_valid() && get_visual_script()->has_variable(variable)) {
- PropertyInfo vinfo = get_visual_script()->get_variable_info(variable);
- pinfo.type = vinfo.type;
- pinfo.hint = vinfo.hint;
- pinfo.hint_string = vinfo.hint_string;
- }
- return pinfo;
-}
-
-PropertyInfo VisualScriptVariableSet::get_output_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-String VisualScriptVariableSet::get_caption() const {
- return vformat(RTR("Set %s"), variable);
-}
-
-void VisualScriptVariableSet::set_variable(StringName p_variable) {
- if (variable == p_variable) {
- return;
- }
- variable = p_variable;
- ports_changed_notify();
-}
-
-StringName VisualScriptVariableSet::get_variable() const {
- return variable;
-}
-
-void VisualScriptVariableSet::_validate_property(PropertyInfo &property) const {
- if (property.name == "var_name" && get_visual_script().is_valid()) {
- Ref<VisualScript> vs = get_visual_script();
- List<StringName> vars;
- vs->get_variable_list(&vars);
-
- String vhint;
- for (const StringName &E : vars) {
- if (!vhint.is_empty()) {
- vhint += ",";
- }
-
- vhint += E.operator String();
- }
-
- property.hint = PROPERTY_HINT_ENUM;
- property.hint_string = vhint;
- }
-}
-
-void VisualScriptVariableSet::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_variable", "name"), &VisualScriptVariableSet::set_variable);
- ClassDB::bind_method(D_METHOD("get_variable"), &VisualScriptVariableSet::get_variable);
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "var_name"), "set_variable", "get_variable");
-}
-
-class VisualScriptNodeInstanceVariableSet : public VisualScriptNodeInstance {
-public:
- VisualScriptVariableSet *node = nullptr;
- VisualScriptInstance *instance = nullptr;
- StringName variable;
-
- //virtual int get_working_memory_size() const override { return 0; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- if (!instance->set_variable(variable, *p_inputs[0])) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = RTR("VariableSet not found in script:") + " '" + String(variable) + "'";
- }
-
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptVariableSet::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceVariableSet *instance = memnew(VisualScriptNodeInstanceVariableSet);
- instance->node = this;
- instance->instance = p_instance;
- instance->variable = variable;
- return instance;
-}
-
-VisualScriptVariableSet::VisualScriptVariableSet() {
-}
-
-//////////////////////////////////////////
-////////////////CONSTANT//////////////////
-//////////////////////////////////////////
-
-int VisualScriptConstant::get_output_sequence_port_count() const {
- return 0;
-}
-
-bool VisualScriptConstant::has_input_sequence_port() const {
- return false;
-}
-
-int VisualScriptConstant::get_input_value_port_count() const {
- return 0;
-}
-
-int VisualScriptConstant::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptConstant::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptConstant::get_input_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-PropertyInfo VisualScriptConstant::get_output_value_port_info(int p_idx) const {
- PropertyInfo pinfo;
- pinfo.name = String(value);
- pinfo.type = type;
- return pinfo;
-}
-
-String VisualScriptConstant::get_caption() const {
- return RTR("Constant");
-}
-
-void VisualScriptConstant::set_constant_type(Variant::Type p_type) {
- if (type == p_type) {
- return;
- }
-
- type = p_type;
- Callable::CallError ce;
- Variant::construct(type, value, nullptr, 0, ce);
- ports_changed_notify();
- notify_property_list_changed();
-}
-
-Variant::Type VisualScriptConstant::get_constant_type() const {
- return type;
-}
-
-void VisualScriptConstant::set_constant_value(Variant p_value) {
- if (value == p_value) {
- return;
- }
-
- value = p_value;
- ports_changed_notify();
-}
-
-Variant VisualScriptConstant::get_constant_value() const {
- return value;
-}
-
-void VisualScriptConstant::_validate_property(PropertyInfo &property) const {
- if (property.name == "value") {
- property.type = type;
- if (type == Variant::NIL) {
- property.usage = PROPERTY_USAGE_NONE; //do not save if nil
- }
- }
-}
-
-void VisualScriptConstant::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_constant_type", "type"), &VisualScriptConstant::set_constant_type);
- ClassDB::bind_method(D_METHOD("get_constant_type"), &VisualScriptConstant::get_constant_type);
-
- ClassDB::bind_method(D_METHOD("set_constant_value", "value"), &VisualScriptConstant::set_constant_value);
- ClassDB::bind_method(D_METHOD("get_constant_value"), &VisualScriptConstant::get_constant_value);
-
- String argt = "Null";
- for (int i = 1; i < Variant::VARIANT_MAX; i++) {
- argt += "," + Variant::get_type_name(Variant::Type(i));
- }
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_constant_type", "get_constant_type");
- ADD_PROPERTY(PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT | PROPERTY_USAGE_DEFAULT), "set_constant_value", "get_constant_value");
-}
-
-class VisualScriptNodeInstanceConstant : public VisualScriptNodeInstance {
-public:
- Variant constant;
- //virtual int get_working_memory_size() const override { return 0; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- *p_outputs[0] = constant;
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptConstant::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceConstant *instance = memnew(VisualScriptNodeInstanceConstant);
- instance->constant = value;
- return instance;
-}
-
-VisualScriptConstant::VisualScriptConstant() {
- type = Variant::NIL;
-}
-
-//////////////////////////////////////////
-////////////////PRELOAD//////////////////
-//////////////////////////////////////////
-
-int VisualScriptPreload::get_output_sequence_port_count() const {
- return 0;
-}
-
-bool VisualScriptPreload::has_input_sequence_port() const {
- return false;
-}
-
-int VisualScriptPreload::get_input_value_port_count() const {
- return 0;
-}
-
-int VisualScriptPreload::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptPreload::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptPreload::get_input_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-PropertyInfo VisualScriptPreload::get_output_value_port_info(int p_idx) const {
- PropertyInfo pinfo;
- pinfo.type = Variant::OBJECT;
- if (preload.is_valid()) {
- pinfo.hint = PROPERTY_HINT_RESOURCE_TYPE;
- pinfo.hint_string = preload->get_class();
- if (preload->get_path().is_resource_file()) {
- pinfo.name = preload->get_path();
- } else if (!preload->get_name().is_empty()) {
- pinfo.name = preload->get_name();
- } else {
- pinfo.name = preload->get_class();
- }
- } else {
- pinfo.name = "<empty>";
- }
-
- return pinfo;
-}
-
-String VisualScriptPreload::get_caption() const {
- return RTR("Preload");
-}
-
-void VisualScriptPreload::set_preload(const Ref<Resource> &p_preload) {
- if (preload == p_preload) {
- return;
- }
-
- preload = p_preload;
- ports_changed_notify();
-}
-
-Ref<Resource> VisualScriptPreload::get_preload() const {
- return preload;
-}
-
-void VisualScriptPreload::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_preload", "resource"), &VisualScriptPreload::set_preload);
- ClassDB::bind_method(D_METHOD("get_preload"), &VisualScriptPreload::get_preload);
-
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), "set_preload", "get_preload");
-}
-
-class VisualScriptNodeInstancePreload : public VisualScriptNodeInstance {
-public:
- Ref<Resource> preload;
- //virtual int get_working_memory_size() const override { return 0; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- *p_outputs[0] = preload;
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptPreload::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstancePreload *instance = memnew(VisualScriptNodeInstancePreload);
- instance->preload = preload;
- return instance;
-}
-
-VisualScriptPreload::VisualScriptPreload() {
-}
-
-//////////////////////////////////////////
-////////////////INDEX////////////////////
-//////////////////////////////////////////
-
-int VisualScriptIndexGet::get_output_sequence_port_count() const {
- return 0;
-}
-
-bool VisualScriptIndexGet::has_input_sequence_port() const {
- return false;
-}
-
-int VisualScriptIndexGet::get_input_value_port_count() const {
- return 2;
-}
-
-int VisualScriptIndexGet::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptIndexGet::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptIndexGet::get_input_value_port_info(int p_idx) const {
- if (p_idx == 0) {
- return PropertyInfo(Variant::NIL, "base");
- } else {
- return PropertyInfo(Variant::NIL, "index");
- }
-}
-
-PropertyInfo VisualScriptIndexGet::get_output_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-String VisualScriptIndexGet::get_caption() const {
- return RTR("Get Index");
-}
-
-class VisualScriptNodeInstanceIndexGet : public VisualScriptNodeInstance {
-public:
- //virtual int get_working_memory_size() const override { return 0; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- bool valid;
- *p_outputs[0] = p_inputs[0]->get(*p_inputs[1], &valid);
-
- if (!valid) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = "Invalid get: " + p_inputs[0]->get_construct_string();
- }
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptIndexGet::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceIndexGet *instance = memnew(VisualScriptNodeInstanceIndexGet);
- return instance;
-}
-
-VisualScriptIndexGet::VisualScriptIndexGet() {
-}
-
-//////////////////////////////////////////
-////////////////INDEXSET//////////////////
-//////////////////////////////////////////
-
-int VisualScriptIndexSet::get_output_sequence_port_count() const {
- return 1;
-}
-
-bool VisualScriptIndexSet::has_input_sequence_port() const {
- return true;
-}
-
-int VisualScriptIndexSet::get_input_value_port_count() const {
- return 3;
-}
-
-int VisualScriptIndexSet::get_output_value_port_count() const {
- return 0;
-}
-
-String VisualScriptIndexSet::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptIndexSet::get_input_value_port_info(int p_idx) const {
- if (p_idx == 0) {
- return PropertyInfo(Variant::NIL, "base");
- } else if (p_idx == 1) {
- return PropertyInfo(Variant::NIL, "index");
-
- } else {
- return PropertyInfo(Variant::NIL, "value");
- }
-}
-
-PropertyInfo VisualScriptIndexSet::get_output_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-String VisualScriptIndexSet::get_caption() const {
- return RTR("Set Index");
-}
-
-class VisualScriptNodeInstanceIndexSet : public VisualScriptNodeInstance {
-public:
- //virtual int get_working_memory_size() const override { return 0; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- bool valid;
- ((Variant *)p_inputs[0])->set(*p_inputs[1], *p_inputs[2], &valid);
-
- if (!valid) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = "Invalid set: " + p_inputs[1]->get_construct_string();
- }
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptIndexSet::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceIndexSet *instance = memnew(VisualScriptNodeInstanceIndexSet);
- return instance;
-}
-
-VisualScriptIndexSet::VisualScriptIndexSet() {
-}
-
-//////////////////////////////////////////
-////////////////GLOBALCONSTANT///////////
-//////////////////////////////////////////
-
-int VisualScriptGlobalConstant::get_output_sequence_port_count() const {
- return 0;
-}
-
-bool VisualScriptGlobalConstant::has_input_sequence_port() const {
- return false;
-}
-
-int VisualScriptGlobalConstant::get_input_value_port_count() const {
- return 0;
-}
-
-int VisualScriptGlobalConstant::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptGlobalConstant::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptGlobalConstant::get_input_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-PropertyInfo VisualScriptGlobalConstant::get_output_value_port_info(int p_idx) const {
- String name = CoreConstants::get_global_constant_name(index);
- return PropertyInfo(Variant::INT, name);
-}
-
-String VisualScriptGlobalConstant::get_caption() const {
- return RTR("Global Constant");
-}
-
-void VisualScriptGlobalConstant::set_global_constant(int p_which) {
- index = p_which;
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-int VisualScriptGlobalConstant::get_global_constant() {
- return index;
-}
-
-class VisualScriptNodeInstanceGlobalConstant : public VisualScriptNodeInstance {
-public:
- int index = 0;
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- *p_outputs[0] = CoreConstants::get_global_constant_value(index);
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptGlobalConstant::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceGlobalConstant *instance = memnew(VisualScriptNodeInstanceGlobalConstant);
- instance->index = index;
- return instance;
-}
-
-void VisualScriptGlobalConstant::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_global_constant", "index"), &VisualScriptGlobalConstant::set_global_constant);
- ClassDB::bind_method(D_METHOD("get_global_constant"), &VisualScriptGlobalConstant::get_global_constant);
-
- String cc;
-
- for (int i = 0; i < CoreConstants::get_global_constant_count(); i++) {
- if (i > 0) {
- cc += ",";
- }
- cc += CoreConstants::get_global_constant_name(i);
- }
- ADD_PROPERTY(PropertyInfo(Variant::INT, "constant", PROPERTY_HINT_ENUM, cc), "set_global_constant", "get_global_constant");
-}
-
-VisualScriptGlobalConstant::VisualScriptGlobalConstant() {
- index = 0;
-}
-
-//////////////////////////////////////////
-////////////////CLASSCONSTANT///////////
-//////////////////////////////////////////
-
-int VisualScriptClassConstant::get_output_sequence_port_count() const {
- return 0;
-}
-
-bool VisualScriptClassConstant::has_input_sequence_port() const {
- return false;
-}
-
-int VisualScriptClassConstant::get_input_value_port_count() const {
- return 0;
-}
-
-int VisualScriptClassConstant::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptClassConstant::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptClassConstant::get_input_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-PropertyInfo VisualScriptClassConstant::get_output_value_port_info(int p_idx) const {
- if (name == "") {
- return PropertyInfo(Variant::INT, String(base_type));
- } else {
- return PropertyInfo(Variant::INT, String(base_type) + "." + String(name));
- }
-}
-
-String VisualScriptClassConstant::get_caption() const {
- return RTR("Class Constant");
-}
-
-void VisualScriptClassConstant::set_class_constant(const StringName &p_which) {
- name = p_which;
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-StringName VisualScriptClassConstant::get_class_constant() {
- return name;
-}
-
-void VisualScriptClassConstant::set_base_type(const StringName &p_which) {
- base_type = p_which;
- List<String> constants;
- ClassDB::get_integer_constant_list(base_type, &constants, true);
- if (constants.size() > 0) {
- bool found_name = false;
- for (const String &E : constants) {
- if (E == name) {
- found_name = true;
- break;
- }
- }
- if (!found_name) {
- name = constants[0];
- }
- } else {
- name = "";
- }
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-StringName VisualScriptClassConstant::get_base_type() {
- return base_type;
-}
-
-class VisualScriptNodeInstanceClassConstant : public VisualScriptNodeInstance {
-public:
- int value = 0;
- bool valid = false;
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- if (!valid) {
- r_error_str = "Invalid constant name, pick a valid class constant.";
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- }
-
- *p_outputs[0] = value;
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptClassConstant::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceClassConstant *instance = memnew(VisualScriptNodeInstanceClassConstant);
- instance->value = ClassDB::get_integer_constant(base_type, name, &instance->valid);
- return instance;
-}
-
-void VisualScriptClassConstant::_validate_property(PropertyInfo &property) const {
- if (property.name == "constant") {
- List<String> constants;
- ClassDB::get_integer_constant_list(base_type, &constants, true);
-
- property.hint_string = "";
- for (const String &E : constants) {
- if (!property.hint_string.is_empty()) {
- property.hint_string += ",";
- }
- property.hint_string += E;
- }
- }
-}
-
-void VisualScriptClassConstant::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_class_constant", "name"), &VisualScriptClassConstant::set_class_constant);
- ClassDB::bind_method(D_METHOD("get_class_constant"), &VisualScriptClassConstant::get_class_constant);
-
- ClassDB::bind_method(D_METHOD("set_base_type", "name"), &VisualScriptClassConstant::set_base_type);
- ClassDB::bind_method(D_METHOD("get_base_type"), &VisualScriptClassConstant::get_base_type);
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "constant", PROPERTY_HINT_ENUM, ""), "set_class_constant", "get_class_constant");
-}
-
-VisualScriptClassConstant::VisualScriptClassConstant() {
- base_type = "Object";
-}
-
-//////////////////////////////////////////
-////////////////BASICTYPECONSTANT///////////
-//////////////////////////////////////////
-
-int VisualScriptBasicTypeConstant::get_output_sequence_port_count() const {
- return 0;
-}
-
-bool VisualScriptBasicTypeConstant::has_input_sequence_port() const {
- return false;
-}
-
-int VisualScriptBasicTypeConstant::get_input_value_port_count() const {
- return 0;
-}
-
-int VisualScriptBasicTypeConstant::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptBasicTypeConstant::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptBasicTypeConstant::get_input_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-PropertyInfo VisualScriptBasicTypeConstant::get_output_value_port_info(int p_idx) const {
- return PropertyInfo(type, "value");
-}
-
-String VisualScriptBasicTypeConstant::get_caption() const {
- return RTR("Basic Constant");
-}
-
-String VisualScriptBasicTypeConstant::get_text() const {
- if (name == "") {
- return Variant::get_type_name(type);
- } else {
- return Variant::get_type_name(type) + "." + String(name);
- }
-}
-
-void VisualScriptBasicTypeConstant::set_basic_type_constant(const StringName &p_which) {
- name = p_which;
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-StringName VisualScriptBasicTypeConstant::get_basic_type_constant() const {
- return name;
-}
-
-void VisualScriptBasicTypeConstant::set_basic_type(Variant::Type p_which) {
- type = p_which;
-
- List<StringName> constants;
- Variant::get_constants_for_type(type, &constants);
- if (constants.size() > 0) {
- bool found_name = false;
- for (const StringName &E : constants) {
- if (E == name) {
- found_name = true;
- break;
- }
- }
- if (!found_name) {
- name = constants[0];
- }
- } else {
- name = "";
- }
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-Variant::Type VisualScriptBasicTypeConstant::get_basic_type() const {
- return type;
-}
-
-class VisualScriptNodeInstanceBasicTypeConstant : public VisualScriptNodeInstance {
-public:
- Variant value;
- bool valid = false;
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- if (!valid) {
- r_error_str = "Invalid constant name, pick a valid basic type constant.";
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- }
-
- *p_outputs[0] = value;
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptBasicTypeConstant::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceBasicTypeConstant *instance = memnew(VisualScriptNodeInstanceBasicTypeConstant);
- instance->value = Variant::get_constant_value(type, name, &instance->valid);
- return instance;
-}
-
-void VisualScriptBasicTypeConstant::_validate_property(PropertyInfo &property) const {
- if (property.name == "constant") {
- List<StringName> constants;
- Variant::get_constants_for_type(type, &constants);
-
- if (constants.size() == 0) {
- property.usage = PROPERTY_USAGE_NONE;
- return;
- }
- property.hint_string = "";
- for (const StringName &E : constants) {
- if (!property.hint_string.is_empty()) {
- property.hint_string += ",";
- }
- property.hint_string += String(E);
- }
- }
-}
-
-void VisualScriptBasicTypeConstant::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_basic_type", "name"), &VisualScriptBasicTypeConstant::set_basic_type);
- ClassDB::bind_method(D_METHOD("get_basic_type"), &VisualScriptBasicTypeConstant::get_basic_type);
-
- ClassDB::bind_method(D_METHOD("set_basic_type_constant", "name"), &VisualScriptBasicTypeConstant::set_basic_type_constant);
- ClassDB::bind_method(D_METHOD("get_basic_type_constant"), &VisualScriptBasicTypeConstant::get_basic_type_constant);
-
- String argt = "Null";
- for (int i = 1; i < Variant::VARIANT_MAX; i++) {
- argt += "," + Variant::get_type_name(Variant::Type(i));
- }
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "basic_type", PROPERTY_HINT_ENUM, argt), "set_basic_type", "get_basic_type");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "constant", PROPERTY_HINT_ENUM, ""), "set_basic_type_constant", "get_basic_type_constant");
-}
-
-VisualScriptBasicTypeConstant::VisualScriptBasicTypeConstant() {
- type = Variant::NIL;
-}
-
-//////////////////////////////////////////
-////////////////MATHCONSTANT///////////
-//////////////////////////////////////////
-
-const char *VisualScriptMathConstant::const_name[MATH_CONSTANT_MAX] = {
- "One",
- "PI",
- "PI/2",
- "TAU",
- "E",
- "Sqrt2",
- "INF",
- "NAN"
-};
-
-double VisualScriptMathConstant::const_value[MATH_CONSTANT_MAX] = {
- 1.0,
- Math_PI,
- Math_PI * 0.5,
- Math_TAU,
- 2.71828182845904523536,
- Math::sqrt(2.0),
- INFINITY,
- NAN
-};
-
-int VisualScriptMathConstant::get_output_sequence_port_count() const {
- return 0;
-}
-
-bool VisualScriptMathConstant::has_input_sequence_port() const {
- return false;
-}
-
-int VisualScriptMathConstant::get_input_value_port_count() const {
- return 0;
-}
-
-int VisualScriptMathConstant::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptMathConstant::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptMathConstant::get_input_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-PropertyInfo VisualScriptMathConstant::get_output_value_port_info(int p_idx) const {
- return PropertyInfo(Variant::FLOAT, const_name[constant]);
-}
-
-String VisualScriptMathConstant::get_caption() const {
- return RTR("Math Constant");
-}
-
-void VisualScriptMathConstant::set_math_constant(MathConstant p_which) {
- constant = p_which;
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-VisualScriptMathConstant::MathConstant VisualScriptMathConstant::get_math_constant() {
- return constant;
-}
-
-class VisualScriptNodeInstanceMathConstant : public VisualScriptNodeInstance {
-public:
- float value = 0.0f;
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- *p_outputs[0] = value;
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptMathConstant::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceMathConstant *instance = memnew(VisualScriptNodeInstanceMathConstant);
- instance->value = const_value[constant];
- return instance;
-}
-
-void VisualScriptMathConstant::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_math_constant", "which"), &VisualScriptMathConstant::set_math_constant);
- ClassDB::bind_method(D_METHOD("get_math_constant"), &VisualScriptMathConstant::get_math_constant);
-
- String cc;
-
- for (int i = 0; i < MATH_CONSTANT_MAX; i++) {
- if (i > 0) {
- cc += ",";
- }
- cc += const_name[i];
- }
- ADD_PROPERTY(PropertyInfo(Variant::INT, "constant", PROPERTY_HINT_ENUM, cc), "set_math_constant", "get_math_constant");
-
- BIND_ENUM_CONSTANT(MATH_CONSTANT_ONE);
- BIND_ENUM_CONSTANT(MATH_CONSTANT_PI);
- BIND_ENUM_CONSTANT(MATH_CONSTANT_HALF_PI);
- BIND_ENUM_CONSTANT(MATH_CONSTANT_TAU);
- BIND_ENUM_CONSTANT(MATH_CONSTANT_E);
- BIND_ENUM_CONSTANT(MATH_CONSTANT_SQRT2);
- BIND_ENUM_CONSTANT(MATH_CONSTANT_INF);
- BIND_ENUM_CONSTANT(MATH_CONSTANT_NAN);
- BIND_ENUM_CONSTANT(MATH_CONSTANT_MAX);
-}
-
-VisualScriptMathConstant::VisualScriptMathConstant() {
- constant = MATH_CONSTANT_ONE;
-}
-
-//////////////////////////////////////////
-////////////////ENGINESINGLETON///////////
-//////////////////////////////////////////
-
-int VisualScriptEngineSingleton::get_output_sequence_port_count() const {
- return 0;
-}
-
-bool VisualScriptEngineSingleton::has_input_sequence_port() const {
- return false;
-}
-
-int VisualScriptEngineSingleton::get_input_value_port_count() const {
- return 0;
-}
-
-int VisualScriptEngineSingleton::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptEngineSingleton::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptEngineSingleton::get_input_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-PropertyInfo VisualScriptEngineSingleton::get_output_value_port_info(int p_idx) const {
- return PropertyInfo(Variant::OBJECT, singleton);
-}
-
-String VisualScriptEngineSingleton::get_caption() const {
- return RTR("Get Engine Singleton");
-}
-
-void VisualScriptEngineSingleton::set_singleton(const String &p_string) {
- singleton = p_string;
-
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-String VisualScriptEngineSingleton::get_singleton() {
- return singleton;
-}
-
-class VisualScriptNodeInstanceEngineSingleton : public VisualScriptNodeInstance {
-public:
- Object *singleton = nullptr;
-
- //virtual int get_working_memory_size() const override { return 0; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- *p_outputs[0] = singleton;
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptEngineSingleton::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceEngineSingleton *instance = memnew(VisualScriptNodeInstanceEngineSingleton);
- instance->singleton = Engine::get_singleton()->get_singleton_object(singleton);
- return instance;
-}
-
-VisualScriptEngineSingleton::TypeGuess VisualScriptEngineSingleton::guess_output_type(TypeGuess *p_inputs, int p_output) const {
- Object *obj = Engine::get_singleton()->get_singleton_object(singleton);
- TypeGuess tg;
- tg.type = Variant::OBJECT;
- if (obj) {
- tg.gdclass = obj->get_class();
- tg.script = obj->get_script();
- }
-
- return tg;
-}
-
-void VisualScriptEngineSingleton::_validate_property(PropertyInfo &property) const {
- String cc;
-
- List<Engine::Singleton> singletons;
-
- Engine::get_singleton()->get_singletons(&singletons);
-
- for (const Engine::Singleton &E : singletons) {
- if (E.name == "VS" || E.name == "PS" || E.name == "PS2D" || E.name == "AS" || E.name == "TS" || E.name == "SS" || E.name == "SS2D") {
- continue; //skip these, too simple named
- }
-
- if (!cc.is_empty()) {
- cc += ",";
- }
- cc += E.name;
- }
-
- property.hint = PROPERTY_HINT_ENUM;
- property.hint_string = cc;
-}
-
-void VisualScriptEngineSingleton::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_singleton", "name"), &VisualScriptEngineSingleton::set_singleton);
- ClassDB::bind_method(D_METHOD("get_singleton"), &VisualScriptEngineSingleton::get_singleton);
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "constant"), "set_singleton", "get_singleton");
-}
-
-VisualScriptEngineSingleton::VisualScriptEngineSingleton() {
- singleton = String();
-}
-
-//////////////////////////////////////////
-////////////////GETNODE///////////
-//////////////////////////////////////////
-
-int VisualScriptSceneNode::get_output_sequence_port_count() const {
- return 0;
-}
-
-bool VisualScriptSceneNode::has_input_sequence_port() const {
- return false;
-}
-
-int VisualScriptSceneNode::get_input_value_port_count() const {
- return 0;
-}
-
-int VisualScriptSceneNode::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptSceneNode::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptSceneNode::get_input_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-PropertyInfo VisualScriptSceneNode::get_output_value_port_info(int p_idx) const {
- return PropertyInfo(Variant::OBJECT, path.simplified());
-}
-
-String VisualScriptSceneNode::get_caption() const {
- return RTR("Get Scene Node");
-}
-
-void VisualScriptSceneNode::set_node_path(const NodePath &p_path) {
- path = p_path;
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-NodePath VisualScriptSceneNode::get_node_path() {
- return path;
-}
-
-class VisualScriptNodeInstanceSceneNode : public VisualScriptNodeInstance {
-public:
- VisualScriptSceneNode *node = nullptr;
- VisualScriptInstance *instance = nullptr;
- NodePath path;
-
- //virtual int get_working_memory_size() const override { return 0; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- Node *node = Object::cast_to<Node>(instance->get_owner_ptr());
- if (!node) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = "Base object is not a Node!";
- return 0;
- }
-
- Node *another = node->get_node(path);
- if (!another) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = "Path does not lead Node!";
- return 0;
- }
-
- *p_outputs[0] = another;
-
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptSceneNode::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceSceneNode *instance = memnew(VisualScriptNodeInstanceSceneNode);
- instance->node = this;
- instance->instance = p_instance;
- instance->path = path;
- return instance;
-}
-
-#ifdef TOOLS_ENABLED
-
-static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) {
- if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene) {
- return nullptr;
- }
-
- Ref<Script> scr = p_current_node->get_script();
-
- if (scr.is_valid() && scr == script) {
- return p_current_node;
- }
-
- for (int i = 0; i < p_current_node->get_child_count(); i++) {
- Node *n = _find_script_node(p_edited_scene, p_current_node->get_child(i), script);
- if (n) {
- return n;
- }
- }
-
- return nullptr;
-}
-
-#endif
-
-VisualScriptSceneNode::TypeGuess VisualScriptSceneNode::guess_output_type(TypeGuess *p_inputs, int p_output) const {
- VisualScriptSceneNode::TypeGuess tg;
- tg.type = Variant::OBJECT;
- tg.gdclass = SNAME("Node");
-
-#ifdef TOOLS_ENABLED
- Ref<Script> script = get_visual_script();
- if (!script.is_valid()) {
- return tg;
- }
-
- MainLoop *main_loop = OS::get_singleton()->get_main_loop();
- SceneTree *scene_tree = Object::cast_to<SceneTree>(main_loop);
-
- if (!scene_tree) {
- return tg;
- }
-
- Node *edited_scene = scene_tree->get_edited_scene_root();
-
- if (!edited_scene) {
- return tg;
- }
-
- Node *script_node = _find_script_node(edited_scene, edited_scene, script);
-
- if (!script_node) {
- return tg;
- }
-
- Node *another = script_node->get_node(path);
-
- if (another) {
- tg.gdclass = another->get_class();
- tg.script = another->get_script();
- }
-#endif
- return tg;
-}
-
-void VisualScriptSceneNode::_validate_property(PropertyInfo &property) const {
-#ifdef TOOLS_ENABLED
- if (property.name == "node_path") {
- Ref<Script> script = get_visual_script();
- if (!script.is_valid()) {
- return;
- }
-
- MainLoop *main_loop = OS::get_singleton()->get_main_loop();
- SceneTree *scene_tree = Object::cast_to<SceneTree>(main_loop);
-
- if (!scene_tree) {
- return;
- }
-
- Node *edited_scene = scene_tree->get_edited_scene_root();
-
- if (!edited_scene) {
- return;
- }
-
- Node *script_node = _find_script_node(edited_scene, edited_scene, script);
-
- if (!script_node) {
- return;
- }
-
- property.hint_string = script_node->get_path();
- }
-#endif
-}
-
-void VisualScriptSceneNode::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_node_path", "path"), &VisualScriptSceneNode::set_node_path);
- ClassDB::bind_method(D_METHOD("get_node_path"), &VisualScriptSceneNode::get_node_path);
-
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_node_path", "get_node_path");
-}
-
-VisualScriptSceneNode::VisualScriptSceneNode() {
- path = String(".");
-}
-
-//////////////////////////////////////////
-////////////////SceneTree///////////
-//////////////////////////////////////////
-
-int VisualScriptSceneTree::get_output_sequence_port_count() const {
- return 0;
-}
-
-bool VisualScriptSceneTree::has_input_sequence_port() const {
- return false;
-}
-
-int VisualScriptSceneTree::get_input_value_port_count() const {
- return 0;
-}
-
-int VisualScriptSceneTree::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptSceneTree::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptSceneTree::get_input_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-PropertyInfo VisualScriptSceneTree::get_output_value_port_info(int p_idx) const {
- return PropertyInfo(Variant::OBJECT, "Scene Tree", PROPERTY_HINT_TYPE_STRING, "SceneTree");
-}
-
-String VisualScriptSceneTree::get_caption() const {
- return RTR("Get Scene Tree");
-}
-
-class VisualScriptNodeInstanceSceneTree : public VisualScriptNodeInstance {
-public:
- VisualScriptSceneTree *node = nullptr;
- VisualScriptInstance *instance = nullptr;
-
- //virtual int get_working_memory_size() const override { return 0; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- Node *node = Object::cast_to<Node>(instance->get_owner_ptr());
- if (!node) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = "Base object is not a Node!";
- return 0;
- }
-
- SceneTree *tree = node->get_tree();
- if (!tree) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = "Attempt to get SceneTree while node is not in the active tree.";
- return 0;
- }
-
- *p_outputs[0] = tree;
-
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptSceneTree::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceSceneTree *instance = memnew(VisualScriptNodeInstanceSceneTree);
- instance->node = this;
- instance->instance = p_instance;
- return instance;
-}
-
-VisualScriptSceneTree::TypeGuess VisualScriptSceneTree::guess_output_type(TypeGuess *p_inputs, int p_output) const {
- TypeGuess tg;
- tg.type = Variant::OBJECT;
- tg.gdclass = SNAME("SceneTree");
- return tg;
-}
-
-void VisualScriptSceneTree::_validate_property(PropertyInfo &property) const {
-}
-
-void VisualScriptSceneTree::_bind_methods() {
-}
-
-VisualScriptSceneTree::VisualScriptSceneTree() {
-}
-
-//////////////////////////////////////////
-////////////////RESPATH///////////
-//////////////////////////////////////////
-
-int VisualScriptResourcePath::get_output_sequence_port_count() const {
- return 0;
-}
-
-bool VisualScriptResourcePath::has_input_sequence_port() const {
- return false;
-}
-
-int VisualScriptResourcePath::get_input_value_port_count() const {
- return 0;
-}
-
-int VisualScriptResourcePath::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptResourcePath::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptResourcePath::get_input_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-PropertyInfo VisualScriptResourcePath::get_output_value_port_info(int p_idx) const {
- return PropertyInfo(Variant::STRING, path);
-}
-
-String VisualScriptResourcePath::get_caption() const {
- return RTR("Resource Path");
-}
-
-void VisualScriptResourcePath::set_resource_path(const String &p_path) {
- path = p_path;
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-String VisualScriptResourcePath::get_resource_path() {
- return path;
-}
-
-class VisualScriptNodeInstanceResourcePath : public VisualScriptNodeInstance {
-public:
- String path;
-
- //virtual int get_working_memory_size() const override { return 0; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- *p_outputs[0] = path;
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptResourcePath::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceResourcePath *instance = memnew(VisualScriptNodeInstanceResourcePath);
- instance->path = path;
- return instance;
-}
-
-void VisualScriptResourcePath::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_resource_path", "path"), &VisualScriptResourcePath::set_resource_path);
- ClassDB::bind_method(D_METHOD("get_resource_path"), &VisualScriptResourcePath::get_resource_path);
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "path", PROPERTY_HINT_FILE), "set_resource_path", "get_resource_path");
-}
-
-VisualScriptResourcePath::VisualScriptResourcePath() {
- path = "";
-}
-
-//////////////////////////////////////////
-////////////////SELF///////////
-//////////////////////////////////////////
-
-int VisualScriptSelf::get_output_sequence_port_count() const {
- return 0;
-}
-
-bool VisualScriptSelf::has_input_sequence_port() const {
- return false;
-}
-
-int VisualScriptSelf::get_input_value_port_count() const {
- return 0;
-}
-
-int VisualScriptSelf::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptSelf::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptSelf::get_input_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-PropertyInfo VisualScriptSelf::get_output_value_port_info(int p_idx) const {
- StringName type_name;
- if (get_visual_script().is_valid()) {
- type_name = get_visual_script()->get_instance_base_type();
- } else {
- type_name = SNAME("instance");
- }
-
- return PropertyInfo(Variant::OBJECT, type_name);
-}
-
-String VisualScriptSelf::get_caption() const {
- return RTR("Get Self");
-}
-
-class VisualScriptNodeInstanceSelf : public VisualScriptNodeInstance {
-public:
- VisualScriptInstance *instance = nullptr;
-
- //virtual int get_working_memory_size() const override { return 0; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- *p_outputs[0] = instance->get_owner_ptr();
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptSelf::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceSelf *instance = memnew(VisualScriptNodeInstanceSelf);
- instance->instance = p_instance;
- return instance;
-}
-
-VisualScriptSelf::TypeGuess VisualScriptSelf::guess_output_type(TypeGuess *p_inputs, int p_output) const {
- VisualScriptSceneNode::TypeGuess tg;
- tg.type = Variant::OBJECT;
- tg.gdclass = SNAME("Object");
-
- Ref<Script> script = get_visual_script();
- if (!script.is_valid()) {
- return tg;
- }
-
- tg.gdclass = script->get_instance_base_type();
- tg.script = script;
-
- return tg;
-}
-
-void VisualScriptSelf::_bind_methods() {
-}
-
-VisualScriptSelf::VisualScriptSelf() {
-}
-
-//////////////////////////////////////////
-////////////////CUSTOM (SCRIPTED)///////////
-//////////////////////////////////////////
-
-int VisualScriptCustomNode::get_output_sequence_port_count() const {
- int ret;
- if (GDVIRTUAL_CALL(_get_output_sequence_port_count, ret)) {
- return ret;
- }
- return 0;
-}
-
-bool VisualScriptCustomNode::has_input_sequence_port() const {
- bool ret;
- if (GDVIRTUAL_CALL(_has_input_sequence_port, ret)) {
- return ret;
- }
- return false;
-}
-
-int VisualScriptCustomNode::get_input_value_port_count() const {
- int ret;
- if (GDVIRTUAL_CALL(_get_input_value_port_count, ret)) {
- return ret;
- }
- return 0;
-}
-
-int VisualScriptCustomNode::get_output_value_port_count() const {
- int ret;
- if (GDVIRTUAL_CALL(_get_output_value_port_count, ret)) {
- return ret;
- }
- return 0;
-}
-
-String VisualScriptCustomNode::get_output_sequence_port_text(int p_port) const {
- String ret;
- if (GDVIRTUAL_CALL(_get_output_sequence_port_text, p_port, ret)) {
- return ret;
- }
-
- return String();
-}
-
-PropertyInfo VisualScriptCustomNode::get_input_value_port_info(int p_idx) const {
- PropertyInfo info;
- {
- int type;
- if (GDVIRTUAL_CALL(_get_input_value_port_type, p_idx, type)) {
- info.type = Variant::Type(type);
- }
- }
- {
- String name;
- if (GDVIRTUAL_CALL(_get_input_value_port_name, p_idx, name)) {
- info.name = name;
- }
- }
- {
- int hint;
- if (GDVIRTUAL_CALL(_get_input_value_port_hint, p_idx, hint)) {
- info.hint = PropertyHint(hint);
- }
- }
-
- {
- String hint_string;
- if (GDVIRTUAL_CALL(_get_input_value_port_hint_string, p_idx, hint_string)) {
- info.hint_string = hint_string;
- }
- }
-
- return info;
-}
-
-PropertyInfo VisualScriptCustomNode::get_output_value_port_info(int p_idx) const {
- PropertyInfo info;
- {
- int type;
- if (GDVIRTUAL_CALL(_get_output_value_port_type, p_idx, type)) {
- info.type = Variant::Type(type);
- }
- }
- {
- String name;
- if (GDVIRTUAL_CALL(_get_output_value_port_name, p_idx, name)) {
- info.name = name;
- }
- }
- {
- int hint;
- if (GDVIRTUAL_CALL(_get_output_value_port_hint, p_idx, hint)) {
- info.hint = PropertyHint(hint);
- }
- }
-
- {
- String hint_string;
- if (GDVIRTUAL_CALL(_get_output_value_port_hint_string, p_idx, hint_string)) {
- info.hint_string = hint_string;
- }
- }
- return info;
-}
-
-VisualScriptCustomNode::TypeGuess VisualScriptCustomNode::guess_output_type(TypeGuess *p_inputs, int p_output) const {
- TypeGuess tg;
- PropertyInfo pi = VisualScriptCustomNode::get_output_value_port_info(p_output);
- tg.type = pi.type;
- if (pi.type == Variant::OBJECT) {
- if (pi.hint == PROPERTY_HINT_RESOURCE_TYPE) {
- if (pi.hint_string.is_resource_file()) {
- tg.script = ResourceLoader::load(pi.hint_string);
- } else if (ClassDB::class_exists(pi.hint_string)) {
- tg.gdclass = pi.hint_string;
- }
- }
- }
- return tg;
-}
-
-String VisualScriptCustomNode::get_caption() const {
- String ret;
- if (GDVIRTUAL_CALL(_get_caption, ret)) {
- return ret;
- }
- return RTR("CustomNode");
-}
-
-String VisualScriptCustomNode::get_text() const {
- String ret;
- if (GDVIRTUAL_CALL(_get_text, ret)) {
- return ret;
- }
- return "";
-}
-
-String VisualScriptCustomNode::get_category() const {
- String ret;
- if (GDVIRTUAL_CALL(_get_category, ret)) {
- return ret;
- }
- return "Custom";
-}
-
-class VisualScriptNodeInstanceCustomNode : public VisualScriptNodeInstance {
-public:
- VisualScriptInstance *instance = nullptr;
- VisualScriptCustomNode *node = nullptr;
- int in_count = 0;
- int out_count = 0;
- int work_mem_size = 0;
-
- virtual int get_working_memory_size() const override { return work_mem_size; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- if (GDVIRTUAL_IS_OVERRIDDEN_PTR(node, _step)) {
- Array in_values;
- Array out_values;
- Array work_mem;
-
- in_values.resize(in_count);
-
- for (int i = 0; i < in_count; i++) {
- in_values[i] = *p_inputs[i];
- }
-
- out_values.resize(out_count);
-
- work_mem.resize(work_mem_size);
-
- for (int i = 0; i < work_mem_size; i++) {
- work_mem[i] = p_working_mem[i];
- }
-
- int ret_out;
-
- Variant ret;
- GDVIRTUAL_CALL_PTR(node, _step, in_values, out_values, p_start_mode, work_mem, ret);
- if (ret.get_type() == Variant::STRING) {
- r_error_str = ret;
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return 0;
- } else if (ret.is_num()) {
- ret_out = ret;
- } else {
- r_error_str = RTR("Invalid return value from _step(), must be integer (seq out), or string (error).");
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return 0;
- }
-
- for (int i = 0; i < out_count; i++) {
- if (i < out_values.size()) {
- *p_outputs[i] = out_values[i];
- }
- }
-
- for (int i = 0; i < work_mem_size; i++) {
- if (i < work_mem.size()) {
- p_working_mem[i] = work_mem[i];
- }
- }
-
- return ret_out;
- } else {
- r_error_str = RTR("Custom node has no _step() method, can't process graph.");
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- }
-
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptCustomNode::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceCustomNode *instance = memnew(VisualScriptNodeInstanceCustomNode);
- instance->instance = p_instance;
- instance->node = this;
- instance->in_count = get_input_value_port_count();
- instance->out_count = get_output_value_port_count();
-
- instance->work_mem_size = 0;
- GDVIRTUAL_CALL(_get_working_memory_size, instance->work_mem_size);
-
- return instance;
-}
-
-void VisualScriptCustomNode::_script_changed() {
- call_deferred(SNAME("ports_changed_notify"));
-}
-
-void VisualScriptCustomNode::_bind_methods() {
- GDVIRTUAL_BIND(_get_output_sequence_port_count);
- GDVIRTUAL_BIND(_has_input_sequence_port);
- GDVIRTUAL_BIND(_get_output_sequence_port_text, "seq_idx");
-
- GDVIRTUAL_BIND(_get_input_value_port_count);
- GDVIRTUAL_BIND(_get_input_value_port_type, "input_idx");
- GDVIRTUAL_BIND(_get_input_value_port_name, "input_idx");
- GDVIRTUAL_BIND(_get_input_value_port_hint, "input_idx");
- GDVIRTUAL_BIND(_get_input_value_port_hint_string, "input_idx");
-
- GDVIRTUAL_BIND(_get_output_value_port_count);
- GDVIRTUAL_BIND(_get_output_value_port_type, "output_idx");
- GDVIRTUAL_BIND(_get_output_value_port_name, "output_idx");
- GDVIRTUAL_BIND(_get_output_value_port_hint, "output_idx");
- GDVIRTUAL_BIND(_get_output_value_port_hint_string, "output_idx");
-
- GDVIRTUAL_BIND(_get_caption);
- GDVIRTUAL_BIND(_get_text);
- GDVIRTUAL_BIND(_get_category);
-
- GDVIRTUAL_BIND(_get_working_memory_size);
-
- GDVIRTUAL_BIND(_step, "inputs", "outputs", "start_mode", "working_mem");
-
- BIND_ENUM_CONSTANT(START_MODE_BEGIN_SEQUENCE);
- BIND_ENUM_CONSTANT(START_MODE_CONTINUE_SEQUENCE);
- BIND_ENUM_CONSTANT(START_MODE_RESUME_YIELD);
-
- BIND_CONSTANT(STEP_PUSH_STACK_BIT);
- BIND_CONSTANT(STEP_GO_BACK_BIT);
- BIND_CONSTANT(STEP_NO_ADVANCE_BIT);
- BIND_CONSTANT(STEP_EXIT_FUNCTION_BIT);
- BIND_CONSTANT(STEP_YIELD_BIT);
-}
-
-VisualScriptCustomNode::VisualScriptCustomNode() {
- connect("script_changed", callable_mp(this, &VisualScriptCustomNode::_script_changed));
-}
-
-//////////////////////////////////////////
-////////////////SUBCALL///////////
-//////////////////////////////////////////
-
-int VisualScriptSubCall::get_output_sequence_port_count() const {
- return 1;
-}
-
-bool VisualScriptSubCall::has_input_sequence_port() const {
- return true;
-}
-
-int VisualScriptSubCall::get_input_value_port_count() const {
- Ref<Script> script = get_script();
-
- if (script.is_valid() && script->has_method(VisualScriptLanguage::singleton->_subcall)) {
- MethodInfo mi = script->get_method_info(VisualScriptLanguage::singleton->_subcall);
- return mi.arguments.size();
- }
-
- return 0;
-}
-
-int VisualScriptSubCall::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptSubCall::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptSubCall::get_input_value_port_info(int p_idx) const {
- Ref<Script> script = get_script();
- if (script.is_valid() && script->has_method(VisualScriptLanguage::singleton->_subcall)) {
- MethodInfo mi = script->get_method_info(VisualScriptLanguage::singleton->_subcall);
- return mi.arguments[p_idx];
- }
-
- return PropertyInfo();
-}
-
-PropertyInfo VisualScriptSubCall::get_output_value_port_info(int p_idx) const {
- Ref<Script> script = get_script();
- if (script.is_valid() && script->has_method(VisualScriptLanguage::singleton->_subcall)) {
- MethodInfo mi = script->get_method_info(VisualScriptLanguage::singleton->_subcall);
- return mi.return_val;
- }
- return PropertyInfo();
-}
-
-String VisualScriptSubCall::get_caption() const {
- return RTR("SubCall");
-}
-
-String VisualScriptSubCall::get_text() const {
- Ref<Script> script = get_script();
- if (script.is_valid()) {
- if (!script->get_name().is_empty()) {
- return script->get_name();
- }
- if (script->get_path().is_resource_file()) {
- return script->get_path().get_file();
- }
- return script->get_class();
- }
- return "";
-}
-
-String VisualScriptSubCall::get_category() const {
- return "custom";
-}
-
-class VisualScriptNodeInstanceSubCall : public VisualScriptNodeInstance {
-public:
- VisualScriptInstance *instance = nullptr;
- VisualScriptSubCall *subcall = nullptr;
- int input_args = 0;
- bool valid = false;
-
- //virtual int get_working_memory_size() const override { return 0; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- if (!valid) {
- r_error_str = "Node requires a script with a _subcall(<args>) method to work.";
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return 0;
- }
- *p_outputs[0] = subcall->callp(VisualScriptLanguage::singleton->_subcall, p_inputs, input_args, r_error);
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptSubCall::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceSubCall *instance = memnew(VisualScriptNodeInstanceSubCall);
- instance->instance = p_instance;
- Ref<Script> script = get_script();
- if (script.is_valid() && script->has_method(VisualScriptLanguage::singleton->_subcall)) {
- instance->valid = true;
- instance->input_args = get_input_value_port_count();
- } else {
- instance->valid = false;
- }
- return instance;
-}
-
-void VisualScriptSubCall::_bind_methods() {
- // Since this is script only, registering virtual function is no longer valid. Will have to go in docs.
-}
-
-VisualScriptSubCall::VisualScriptSubCall() {
-}
-
-//////////////////////////////////////////
-////////////////Comment///////////
-//////////////////////////////////////////
-
-int VisualScriptComment::get_output_sequence_port_count() const {
- return 0;
-}
-
-bool VisualScriptComment::has_input_sequence_port() const {
- return false;
-}
-
-int VisualScriptComment::get_input_value_port_count() const {
- return 0;
-}
-
-int VisualScriptComment::get_output_value_port_count() const {
- return 0;
-}
-
-String VisualScriptComment::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptComment::get_input_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-PropertyInfo VisualScriptComment::get_output_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-String VisualScriptComment::get_caption() const {
- return title;
-}
-
-String VisualScriptComment::get_text() const {
- return description;
-}
-
-void VisualScriptComment::set_title(const String &p_title) {
- if (title == p_title) {
- return;
- }
- title = p_title;
- ports_changed_notify();
-}
-
-String VisualScriptComment::get_title() const {
- return title;
-}
-
-void VisualScriptComment::set_description(const String &p_description) {
- if (description == p_description) {
- return;
- }
- description = p_description;
- ports_changed_notify();
-}
-
-String VisualScriptComment::get_description() const {
- return description;
-}
-
-void VisualScriptComment::set_size(const Size2 &p_size) {
- if (size == p_size) {
- return;
- }
- size = p_size;
- ports_changed_notify();
-}
-
-Size2 VisualScriptComment::get_size() const {
- return size;
-}
-
-String VisualScriptComment::get_category() const {
- return "data";
-}
-
-class VisualScriptNodeInstanceComment : public VisualScriptNodeInstance {
-public:
- VisualScriptInstance *instance = nullptr;
-
- //virtual int get_working_memory_size() const override { return 0; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptComment::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceComment *instance = memnew(VisualScriptNodeInstanceComment);
- instance->instance = p_instance;
- return instance;
-}
-
-void VisualScriptComment::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_title", "title"), &VisualScriptComment::set_title);
- ClassDB::bind_method(D_METHOD("get_title"), &VisualScriptComment::get_title);
-
- ClassDB::bind_method(D_METHOD("set_description", "description"), &VisualScriptComment::set_description);
- ClassDB::bind_method(D_METHOD("get_description"), &VisualScriptComment::get_description);
-
- ClassDB::bind_method(D_METHOD("set_size", "size"), &VisualScriptComment::set_size);
- ClassDB::bind_method(D_METHOD("get_size"), &VisualScriptComment::get_size);
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "description", PROPERTY_HINT_MULTILINE_TEXT), "set_description", "get_description");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
-}
-
-VisualScriptComment::VisualScriptComment() {
- title = "Comment";
- size = Size2(150, 150);
-}
-
-//////////////////////////////////////////
-////////////////Constructor///////////
-//////////////////////////////////////////
-
-int VisualScriptConstructor::get_output_sequence_port_count() const {
- return 0;
-}
-
-bool VisualScriptConstructor::has_input_sequence_port() const {
- return false;
-}
-
-int VisualScriptConstructor::get_input_value_port_count() const {
- return constructor.arguments.size();
-}
-
-int VisualScriptConstructor::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptConstructor::get_output_sequence_port_text(int p_port) const {
- return "";
-}
-
-PropertyInfo VisualScriptConstructor::get_input_value_port_info(int p_idx) const {
- return constructor.arguments[p_idx];
-}
-
-PropertyInfo VisualScriptConstructor::get_output_value_port_info(int p_idx) const {
- return PropertyInfo(type, "value");
-}
-
-String VisualScriptConstructor::get_caption() const {
- return vformat(RTR("Construct %s"), Variant::get_type_name(type));
-}
-
-String VisualScriptConstructor::get_category() const {
- return "functions";
-}
-
-void VisualScriptConstructor::set_constructor_type(Variant::Type p_type) {
- if (type == p_type) {
- return;
- }
-
- type = p_type;
- ports_changed_notify();
-}
-
-Variant::Type VisualScriptConstructor::get_constructor_type() const {
- return type;
-}
-
-void VisualScriptConstructor::set_constructor(const Dictionary &p_info) {
- constructor = MethodInfo::from_dict(p_info);
- ports_changed_notify();
-}
-
-Dictionary VisualScriptConstructor::get_constructor() const {
- return constructor;
-}
-
-class VisualScriptNodeInstanceConstructor : public VisualScriptNodeInstance {
-public:
- VisualScriptInstance *instance = nullptr;
- Variant::Type type;
- int argcount = 0;
-
- //virtual int get_working_memory_size() const override { return 0; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- Callable::CallError ce;
- Variant::construct(type, *p_outputs[0], p_inputs, argcount, ce);
- if (ce.error != Callable::CallError::CALL_OK) {
- r_error_str = "Invalid arguments for constructor";
- }
-
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptConstructor::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceConstructor *instance = memnew(VisualScriptNodeInstanceConstructor);
- instance->instance = p_instance;
- instance->type = type;
- instance->argcount = constructor.arguments.size();
- return instance;
-}
-
-void VisualScriptConstructor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_constructor_type", "type"), &VisualScriptConstructor::set_constructor_type);
- ClassDB::bind_method(D_METHOD("get_constructor_type"), &VisualScriptConstructor::get_constructor_type);
-
- ClassDB::bind_method(D_METHOD("set_constructor", "constructor"), &VisualScriptConstructor::set_constructor);
- ClassDB::bind_method(D_METHOD("get_constructor"), &VisualScriptConstructor::get_constructor);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_constructor_type", "get_constructor_type");
- ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "constructor", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_constructor", "get_constructor");
-}
-
-VisualScriptConstructor::VisualScriptConstructor() {
- type = Variant::NIL;
-}
-
-static HashMap<String, Pair<Variant::Type, MethodInfo>> constructor_map;
-
-static Ref<VisualScriptNode> create_constructor_node(const String &p_name) {
- ERR_FAIL_COND_V(!constructor_map.has(p_name), Ref<VisualScriptNode>());
-
- Ref<VisualScriptConstructor> vsc;
- vsc.instantiate();
- vsc->set_constructor_type(constructor_map[p_name].first);
- vsc->set_constructor(constructor_map[p_name].second);
-
- return vsc;
-}
-
-//////////////////////////////////////////
-////////////////LocalVar///////////
-//////////////////////////////////////////
-
-int VisualScriptLocalVar::get_output_sequence_port_count() const {
- return 0;
-}
-
-bool VisualScriptLocalVar::has_input_sequence_port() const {
- return false;
-}
-
-int VisualScriptLocalVar::get_input_value_port_count() const {
- return 0;
-}
-
-int VisualScriptLocalVar::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptLocalVar::get_output_sequence_port_text(int p_port) const {
- return "";
-}
-
-PropertyInfo VisualScriptLocalVar::get_input_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-PropertyInfo VisualScriptLocalVar::get_output_value_port_info(int p_idx) const {
- return PropertyInfo(type, name);
-}
-
-String VisualScriptLocalVar::get_caption() const {
- return RTR("Get Local Var");
-}
-
-String VisualScriptLocalVar::get_category() const {
- return "data";
-}
-
-void VisualScriptLocalVar::set_var_name(const StringName &p_name) {
- if (name == p_name) {
- return;
- }
-
- name = p_name;
- ports_changed_notify();
-}
-
-StringName VisualScriptLocalVar::get_var_name() const {
- return name;
-}
-
-void VisualScriptLocalVar::set_var_type(Variant::Type p_type) {
- type = p_type;
- ports_changed_notify();
-}
-
-Variant::Type VisualScriptLocalVar::get_var_type() const {
- return type;
-}
-
-class VisualScriptNodeInstanceLocalVar : public VisualScriptNodeInstance {
-public:
- VisualScriptInstance *instance = nullptr;
- StringName name;
-
- virtual int get_working_memory_size() const override { return 1; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- *p_outputs[0] = *p_working_mem;
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptLocalVar::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceLocalVar *instance = memnew(VisualScriptNodeInstanceLocalVar);
- instance->instance = p_instance;
- instance->name = name;
-
- return instance;
-}
-
-void VisualScriptLocalVar::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_var_name", "name"), &VisualScriptLocalVar::set_var_name);
- ClassDB::bind_method(D_METHOD("get_var_name"), &VisualScriptLocalVar::get_var_name);
-
- ClassDB::bind_method(D_METHOD("set_var_type", "type"), &VisualScriptLocalVar::set_var_type);
- ClassDB::bind_method(D_METHOD("get_var_type"), &VisualScriptLocalVar::get_var_type);
-
- String argt = "Any";
- for (int i = 1; i < Variant::VARIANT_MAX; i++) {
- argt += "," + Variant::get_type_name(Variant::Type(i));
- }
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "var_name"), "set_var_name", "get_var_name");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_var_type", "get_var_type");
-}
-
-VisualScriptLocalVar::VisualScriptLocalVar() {
- name = "new_local";
- type = Variant::NIL;
-}
-
-//////////////////////////////////////////
-////////////////LocalVar///////////
-//////////////////////////////////////////
-
-int VisualScriptLocalVarSet::get_output_sequence_port_count() const {
- return 1;
-}
-
-bool VisualScriptLocalVarSet::has_input_sequence_port() const {
- return true;
-}
-
-int VisualScriptLocalVarSet::get_input_value_port_count() const {
- return 1;
-}
-
-int VisualScriptLocalVarSet::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptLocalVarSet::get_output_sequence_port_text(int p_port) const {
- return "";
-}
-
-PropertyInfo VisualScriptLocalVarSet::get_input_value_port_info(int p_idx) const {
- return PropertyInfo(type, "set");
-}
-
-PropertyInfo VisualScriptLocalVarSet::get_output_value_port_info(int p_idx) const {
- return PropertyInfo(type, "get");
-}
-
-String VisualScriptLocalVarSet::get_caption() const {
- return RTR("Set Local Var");
-}
-
-String VisualScriptLocalVarSet::get_text() const {
- return name;
-}
-
-String VisualScriptLocalVarSet::get_category() const {
- return "data";
-}
-
-void VisualScriptLocalVarSet::set_var_name(const StringName &p_name) {
- if (name == p_name) {
- return;
- }
-
- name = p_name;
- ports_changed_notify();
-}
-
-StringName VisualScriptLocalVarSet::get_var_name() const {
- return name;
-}
-
-void VisualScriptLocalVarSet::set_var_type(Variant::Type p_type) {
- type = p_type;
- ports_changed_notify();
-}
-
-Variant::Type VisualScriptLocalVarSet::get_var_type() const {
- return type;
-}
-
-class VisualScriptNodeInstanceLocalVarSet : public VisualScriptNodeInstance {
-public:
- VisualScriptInstance *instance = nullptr;
- StringName name;
-
- virtual int get_working_memory_size() const override { return 1; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- *p_working_mem = *p_inputs[0];
- *p_outputs[0] = *p_working_mem;
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptLocalVarSet::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceLocalVarSet *instance = memnew(VisualScriptNodeInstanceLocalVarSet);
- instance->instance = p_instance;
- instance->name = name;
-
- return instance;
-}
-
-void VisualScriptLocalVarSet::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_var_name", "name"), &VisualScriptLocalVarSet::set_var_name);
- ClassDB::bind_method(D_METHOD("get_var_name"), &VisualScriptLocalVarSet::get_var_name);
-
- ClassDB::bind_method(D_METHOD("set_var_type", "type"), &VisualScriptLocalVarSet::set_var_type);
- ClassDB::bind_method(D_METHOD("get_var_type"), &VisualScriptLocalVarSet::get_var_type);
-
- String argt = "Any";
- for (int i = 1; i < Variant::VARIANT_MAX; i++) {
- argt += "," + Variant::get_type_name(Variant::Type(i));
- }
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "var_name"), "set_var_name", "get_var_name");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_var_type", "get_var_type");
-}
-
-VisualScriptLocalVarSet::VisualScriptLocalVarSet() {
- name = "new_local";
- type = Variant::NIL;
-}
-
-//////////////////////////////////////////
-////////////////LocalVar///////////
-//////////////////////////////////////////
-
-int VisualScriptInputAction::get_output_sequence_port_count() const {
- return 0;
-}
-
-bool VisualScriptInputAction::has_input_sequence_port() const {
- return false;
-}
-
-int VisualScriptInputAction::get_input_value_port_count() const {
- return 0;
-}
-
-int VisualScriptInputAction::get_output_value_port_count() const {
- return 1;
-}
-
-String VisualScriptInputAction::get_output_sequence_port_text(int p_port) const {
- return "";
-}
-
-PropertyInfo VisualScriptInputAction::get_input_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-PropertyInfo VisualScriptInputAction::get_output_value_port_info(int p_idx) const {
- String mstr;
- switch (mode) {
- case MODE_PRESSED: {
- mstr = "pressed";
- } break;
- case MODE_RELEASED: {
- mstr = "not pressed";
- } break;
- case MODE_JUST_PRESSED: {
- mstr = "just pressed";
- } break;
- case MODE_JUST_RELEASED: {
- mstr = "just released";
- } break;
- }
-
- return PropertyInfo(Variant::BOOL, mstr);
-}
-
-String VisualScriptInputAction::get_caption() const {
- return vformat(RTR("Action %s"), name);
-}
-
-String VisualScriptInputAction::get_category() const {
- return "data";
-}
-
-void VisualScriptInputAction::set_action_name(const StringName &p_name) {
- if (name == p_name) {
- return;
- }
-
- name = p_name;
- ports_changed_notify();
-}
-
-StringName VisualScriptInputAction::get_action_name() const {
- return name;
-}
-
-void VisualScriptInputAction::set_action_mode(Mode p_mode) {
- if (mode == p_mode) {
- return;
- }
-
- mode = p_mode;
- ports_changed_notify();
-}
-
-VisualScriptInputAction::Mode VisualScriptInputAction::get_action_mode() const {
- return mode;
-}
-
-class VisualScriptNodeInstanceInputAction : public VisualScriptNodeInstance {
-public:
- VisualScriptInstance *instance = nullptr;
- StringName action;
- VisualScriptInputAction::Mode mode;
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- switch (mode) {
- case VisualScriptInputAction::MODE_PRESSED: {
- *p_outputs[0] = Input::get_singleton()->is_action_pressed(action);
- } break;
- case VisualScriptInputAction::MODE_RELEASED: {
- *p_outputs[0] = !Input::get_singleton()->is_action_pressed(action);
- } break;
- case VisualScriptInputAction::MODE_JUST_PRESSED: {
- *p_outputs[0] = Input::get_singleton()->is_action_just_pressed(action);
- } break;
- case VisualScriptInputAction::MODE_JUST_RELEASED: {
- *p_outputs[0] = Input::get_singleton()->is_action_just_released(action);
- } break;
- }
-
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptInputAction::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceInputAction *instance = memnew(VisualScriptNodeInstanceInputAction);
- instance->instance = p_instance;
- instance->action = name;
- instance->mode = mode;
-
- return instance;
-}
-
-void VisualScriptInputAction::_validate_property(PropertyInfo &property) const {
- if (property.name == "action") {
- property.hint = PROPERTY_HINT_ENUM;
- String actions;
-
- List<PropertyInfo> pinfo;
- ProjectSettings::get_singleton()->get_property_list(&pinfo);
- Vector<String> al;
-
- for (const PropertyInfo &pi : pinfo) {
- if (!pi.name.begins_with("input/")) {
- continue;
- }
-
- String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
-
- al.push_back(name);
- }
-
- al.sort();
-
- for (int i = 0; i < al.size(); i++) {
- if (!actions.is_empty()) {
- actions += ",";
- }
- actions += al[i];
- }
-
- property.hint_string = actions;
- }
-}
-
-void VisualScriptInputAction::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_action_name", "name"), &VisualScriptInputAction::set_action_name);
- ClassDB::bind_method(D_METHOD("get_action_name"), &VisualScriptInputAction::get_action_name);
-
- ClassDB::bind_method(D_METHOD("set_action_mode", "mode"), &VisualScriptInputAction::set_action_mode);
- ClassDB::bind_method(D_METHOD("get_action_mode"), &VisualScriptInputAction::get_action_mode);
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "action"), "set_action_name", "get_action_name");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Pressed,Released,JustPressed,JustReleased"), "set_action_mode", "get_action_mode");
-
- BIND_ENUM_CONSTANT(MODE_PRESSED);
- BIND_ENUM_CONSTANT(MODE_RELEASED);
- BIND_ENUM_CONSTANT(MODE_JUST_PRESSED);
- BIND_ENUM_CONSTANT(MODE_JUST_RELEASED);
-}
-
-VisualScriptInputAction::VisualScriptInputAction() {
- name = "";
- mode = MODE_PRESSED;
-}
-
-//////////////////////////////////////////
-////////////////Constructor///////////
-//////////////////////////////////////////
-
-int VisualScriptDeconstruct::get_output_sequence_port_count() const {
- return 0;
-}
-
-bool VisualScriptDeconstruct::has_input_sequence_port() const {
- return false;
-}
-
-int VisualScriptDeconstruct::get_input_value_port_count() const {
- return 1;
-}
-
-int VisualScriptDeconstruct::get_output_value_port_count() const {
- return elements.size();
-}
-
-String VisualScriptDeconstruct::get_output_sequence_port_text(int p_port) const {
- return "";
-}
-
-PropertyInfo VisualScriptDeconstruct::get_input_value_port_info(int p_idx) const {
- return PropertyInfo(type, "value");
-}
-
-PropertyInfo VisualScriptDeconstruct::get_output_value_port_info(int p_idx) const {
- return PropertyInfo(elements[p_idx].type, elements[p_idx].name);
-}
-
-String VisualScriptDeconstruct::get_caption() const {
- return vformat(RTR("Deconstruct %s"), Variant::get_type_name(type));
-}
-
-String VisualScriptDeconstruct::get_category() const {
- return "functions";
-}
-
-void VisualScriptDeconstruct::_update_elements() {
- elements.clear();
- Variant v;
- Callable::CallError ce;
- Variant::construct(type, v, nullptr, 0, ce);
-
- List<PropertyInfo> pinfo;
- v.get_property_list(&pinfo);
-
- for (const PropertyInfo &E : pinfo) {
- Element e;
- e.name = E.name;
- e.type = E.type;
- elements.push_back(e);
- }
-}
-
-void VisualScriptDeconstruct::set_deconstruct_type(Variant::Type p_type) {
- if (type == p_type) {
- return;
- }
-
- type = p_type;
- _update_elements();
- ports_changed_notify();
- notify_property_list_changed(); //to make input appear/disappear
-}
-
-Variant::Type VisualScriptDeconstruct::get_deconstruct_type() const {
- return type;
-}
-
-void VisualScriptDeconstruct::_set_elem_cache(const Array &p_elements) {
- ERR_FAIL_COND(p_elements.size() % 2 == 1);
- elements.resize(p_elements.size() / 2);
- for (int i = 0; i < elements.size(); i++) {
- elements.write[i].name = p_elements[i * 2 + 0];
- elements.write[i].type = Variant::Type(int(p_elements[i * 2 + 1]));
- }
-}
-
-Array VisualScriptDeconstruct::_get_elem_cache() const {
- Array ret;
- for (int i = 0; i < elements.size(); i++) {
- ret.push_back(elements[i].name);
- ret.push_back(elements[i].type);
- }
- return ret;
-}
-
-class VisualScriptNodeInstanceDeconstruct : public VisualScriptNodeInstance {
-public:
- VisualScriptInstance *instance = nullptr;
- Vector<StringName> outputs;
-
- //virtual int get_working_memory_size() const override { return 0; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- Variant in = *p_inputs[0];
-
- for (int i = 0; i < outputs.size(); i++) {
- bool valid;
- *p_outputs[i] = in.get(outputs[i], &valid);
- if (!valid) {
- r_error_str = "Can't obtain element '" + String(outputs[i]) + "' from " + Variant::get_type_name(in.get_type());
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return 0;
- }
- }
-
- return 0;
- }
-};
-
-VisualScriptNodeInstance *VisualScriptDeconstruct::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceDeconstruct *instance = memnew(VisualScriptNodeInstanceDeconstruct);
- instance->instance = p_instance;
- instance->outputs.resize(elements.size());
- for (int i = 0; i < elements.size(); i++) {
- instance->outputs.write[i] = elements[i].name;
- }
-
- return instance;
-}
-
-void VisualScriptDeconstruct::_validate_property(PropertyInfo &property) const {
-}
-
-void VisualScriptDeconstruct::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_deconstruct_type", "type"), &VisualScriptDeconstruct::set_deconstruct_type);
- ClassDB::bind_method(D_METHOD("get_deconstruct_type"), &VisualScriptDeconstruct::get_deconstruct_type);
-
- ClassDB::bind_method(D_METHOD("_set_elem_cache", "_cache"), &VisualScriptDeconstruct::_set_elem_cache);
- ClassDB::bind_method(D_METHOD("_get_elem_cache"), &VisualScriptDeconstruct::_get_elem_cache);
-
- String argt = "Any";
- for (int i = 1; i < Variant::VARIANT_MAX; i++) {
- argt += "," + Variant::get_type_name(Variant::Type(i));
- }
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt), "set_deconstruct_type", "get_deconstruct_type");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "elem_cache", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_elem_cache", "_get_elem_cache");
-}
-
-VisualScriptDeconstruct::VisualScriptDeconstruct() {
- type = Variant::NIL;
-}
-
-template <Variant::Type T>
-static Ref<VisualScriptNode> create_node_deconst_typed(const String &p_name) {
- Ref<VisualScriptDeconstruct> node;
- node.instantiate();
- node->set_deconstruct_type(T);
- return node;
-}
-
-void register_visual_script_nodes() {
- VisualScriptLanguage::singleton->add_register_func("data/set_variable", create_node_generic<VisualScriptVariableSet>);
- VisualScriptLanguage::singleton->add_register_func("data/get_variable", create_node_generic<VisualScriptVariableGet>);
- VisualScriptLanguage::singleton->add_register_func("data/engine_singleton", create_node_generic<VisualScriptEngineSingleton>);
- VisualScriptLanguage::singleton->add_register_func("data/scene_node", create_node_generic<VisualScriptSceneNode>);
- VisualScriptLanguage::singleton->add_register_func("data/scene_tree", create_node_generic<VisualScriptSceneTree>);
- VisualScriptLanguage::singleton->add_register_func("data/resource_path", create_node_generic<VisualScriptResourcePath>);
- VisualScriptLanguage::singleton->add_register_func("data/self", create_node_generic<VisualScriptSelf>);
- VisualScriptLanguage::singleton->add_register_func("data/comment", create_node_generic<VisualScriptComment>);
- VisualScriptLanguage::singleton->add_register_func("data/get_local_variable", create_node_generic<VisualScriptLocalVar>);
- VisualScriptLanguage::singleton->add_register_func("data/set_local_variable", create_node_generic<VisualScriptLocalVarSet>);
- VisualScriptLanguage::singleton->add_register_func("data/preload", create_node_generic<VisualScriptPreload>);
- VisualScriptLanguage::singleton->add_register_func("data/action", create_node_generic<VisualScriptInputAction>);
-
- VisualScriptLanguage::singleton->add_register_func("constants/constant", create_node_generic<VisualScriptConstant>);
- VisualScriptLanguage::singleton->add_register_func("constants/math_constant", create_node_generic<VisualScriptMathConstant>);
- VisualScriptLanguage::singleton->add_register_func("constants/class_constant", create_node_generic<VisualScriptClassConstant>);
- VisualScriptLanguage::singleton->add_register_func("constants/global_constant", create_node_generic<VisualScriptGlobalConstant>);
- VisualScriptLanguage::singleton->add_register_func("constants/basic_type_constant", create_node_generic<VisualScriptBasicTypeConstant>);
-
- VisualScriptLanguage::singleton->add_register_func("custom/custom_node", create_node_generic<VisualScriptCustomNode>);
- VisualScriptLanguage::singleton->add_register_func("custom/sub_call", create_node_generic<VisualScriptSubCall>);
-
- VisualScriptLanguage::singleton->add_register_func("index/get_index", create_node_generic<VisualScriptIndexGet>);
- VisualScriptLanguage::singleton->add_register_func("index/set_index", create_node_generic<VisualScriptIndexSet>);
-
- VisualScriptLanguage::singleton->add_register_func("operators/compare/equal", create_op_node<Variant::OP_EQUAL>);
- VisualScriptLanguage::singleton->add_register_func("operators/compare/not_equal", create_op_node<Variant::OP_NOT_EQUAL>);
- VisualScriptLanguage::singleton->add_register_func("operators/compare/less", create_op_node<Variant::OP_LESS>);
- VisualScriptLanguage::singleton->add_register_func("operators/compare/less_equal", create_op_node<Variant::OP_LESS_EQUAL>);
- VisualScriptLanguage::singleton->add_register_func("operators/compare/greater", create_op_node<Variant::OP_GREATER>);
- VisualScriptLanguage::singleton->add_register_func("operators/compare/greater_equal", create_op_node<Variant::OP_GREATER_EQUAL>);
- //mathematic
- VisualScriptLanguage::singleton->add_register_func("operators/math/add", create_op_node<Variant::OP_ADD>);
- VisualScriptLanguage::singleton->add_register_func("operators/math/subtract", create_op_node<Variant::OP_SUBTRACT>);
- VisualScriptLanguage::singleton->add_register_func("operators/math/multiply", create_op_node<Variant::OP_MULTIPLY>);
- VisualScriptLanguage::singleton->add_register_func("operators/math/divide", create_op_node<Variant::OP_DIVIDE>);
- VisualScriptLanguage::singleton->add_register_func("operators/math/negate", create_op_node<Variant::OP_NEGATE>);
- VisualScriptLanguage::singleton->add_register_func("operators/math/positive", create_op_node<Variant::OP_POSITIVE>);
- VisualScriptLanguage::singleton->add_register_func("operators/math/remainder", create_op_node<Variant::OP_MODULE>);
- //bitwise
- VisualScriptLanguage::singleton->add_register_func("operators/bitwise/shift_left", create_op_node<Variant::OP_SHIFT_LEFT>);
- VisualScriptLanguage::singleton->add_register_func("operators/bitwise/shift_right", create_op_node<Variant::OP_SHIFT_RIGHT>);
- VisualScriptLanguage::singleton->add_register_func("operators/bitwise/bit_and", create_op_node<Variant::OP_BIT_AND>);
- VisualScriptLanguage::singleton->add_register_func("operators/bitwise/bit_or", create_op_node<Variant::OP_BIT_OR>);
- VisualScriptLanguage::singleton->add_register_func("operators/bitwise/bit_xor", create_op_node<Variant::OP_BIT_XOR>);
- VisualScriptLanguage::singleton->add_register_func("operators/bitwise/bit_negate", create_op_node<Variant::OP_BIT_NEGATE>);
- //logic
- VisualScriptLanguage::singleton->add_register_func("operators/logic/and", create_op_node<Variant::OP_AND>);
- VisualScriptLanguage::singleton->add_register_func("operators/logic/or", create_op_node<Variant::OP_OR>);
- VisualScriptLanguage::singleton->add_register_func("operators/logic/xor", create_op_node<Variant::OP_XOR>);
- VisualScriptLanguage::singleton->add_register_func("operators/logic/not", create_op_node<Variant::OP_NOT>);
- VisualScriptLanguage::singleton->add_register_func("operators/logic/in", create_op_node<Variant::OP_IN>);
- VisualScriptLanguage::singleton->add_register_func("operators/logic/select", create_node_generic<VisualScriptSelect>);
-
- VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR2), create_node_deconst_typed<Variant::Type::VECTOR2>);
- VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR2I), create_node_deconst_typed<Variant::Type::VECTOR2I>);
- VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR3), create_node_deconst_typed<Variant::Type::VECTOR3>);
- VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR3I), create_node_deconst_typed<Variant::Type::VECTOR3I>);
- VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR4), create_node_deconst_typed<Variant::Type::VECTOR4>);
- VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR4I), create_node_deconst_typed<Variant::Type::VECTOR4I>);
- VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::COLOR), create_node_deconst_typed<Variant::Type::COLOR>);
- VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::RECT2), create_node_deconst_typed<Variant::Type::RECT2>);
- VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::RECT2I), create_node_deconst_typed<Variant::Type::RECT2I>);
- VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::TRANSFORM2D), create_node_deconst_typed<Variant::Type::TRANSFORM2D>);
- VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::PLANE), create_node_deconst_typed<Variant::Type::PLANE>);
- VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::QUATERNION), create_node_deconst_typed<Variant::Type::QUATERNION>);
- VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::AABB), create_node_deconst_typed<Variant::Type::AABB>);
- VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::BASIS), create_node_deconst_typed<Variant::Type::BASIS>);
- VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::TRANSFORM3D), create_node_deconst_typed<Variant::Type::TRANSFORM3D>);
- VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::PROJECTION), create_node_deconst_typed<Variant::Type::PROJECTION>);
- VisualScriptLanguage::singleton->add_register_func("functions/compose_array", create_node_generic<VisualScriptComposeArray>);
-
- for (int i = 1; i < Variant::VARIANT_MAX; i++) {
- List<MethodInfo> constructors;
- Variant::get_constructor_list(Variant::Type(i), &constructors);
-
- for (const MethodInfo &E : constructors) {
- if (E.arguments.size() > 0) {
- String name = "functions/constructors/" + Variant::get_type_name(Variant::Type(i)) + "(";
- for (int j = 0; j < E.arguments.size(); j++) {
- if (j > 0) {
- name += ", ";
- }
- if (E.arguments.size() == 1) {
- name += Variant::get_type_name(E.arguments[j].type);
- } else {
- name += E.arguments[j].name;
- }
- }
- name += ")";
- VisualScriptLanguage::singleton->add_register_func(name, create_constructor_node);
- Pair<Variant::Type, MethodInfo> pair;
- pair.first = Variant::Type(i);
- pair.second = E;
- constructor_map[name] = pair;
- }
- }
- }
-}
-
-void unregister_visual_script_nodes() {
- constructor_map.clear();
-}
diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h
deleted file mode 100644
index 35e3c490cd..0000000000
--- a/modules/visual_script/visual_script_nodes.h
+++ /dev/null
@@ -1,1092 +0,0 @@
-/*************************************************************************/
-/* visual_script_nodes.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef VISUAL_SCRIPT_NODES_H
-#define VISUAL_SCRIPT_NODES_H
-
-#include "core/object/gdvirtual.gen.inc"
-#include "core/object/script_language.h"
-#include "scene/main/multiplayer_api.h"
-#include "visual_script.h"
-
-class VisualScriptFunction : public VisualScriptNode {
- GDCLASS(VisualScriptFunction, VisualScriptNode);
-
- struct Argument {
- String name;
- Variant::Type type;
- PropertyHint hint;
- String hint_string;
- };
-
- Vector<Argument> arguments;
-
- bool stack_less;
- int stack_size;
- MultiplayerAPI::RPCMode rpc_mode;
- bool sequenced;
-
-protected:
- bool _set(const StringName &p_name, const Variant &p_value);
- bool _get(const StringName &p_name, Variant &r_ret) const;
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_text() const override;
- virtual String get_category() const override { return "flow_control"; }
-
- void add_argument(Variant::Type p_type, const String &p_name, int p_index = -1, const PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = String(""));
- void set_argument_type(int p_argidx, Variant::Type p_type);
- Variant::Type get_argument_type(int p_argidx) const;
- void set_argument_name(int p_argidx, const String &p_name);
- String get_argument_name(int p_argidx) const;
- void remove_argument(int p_argidx);
- int get_argument_count() const;
-
- void set_stack_less(bool p_enable);
- bool is_stack_less() const;
-
- void set_sequenced(bool p_enable);
- bool is_sequenced() const;
-
- void set_stack_size(int p_size);
- int get_stack_size() const;
-
- void set_rpc_mode(MultiplayerAPI::RPCMode p_mode);
- MultiplayerAPI::RPCMode get_rpc_mode() const;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- virtual void reset_state() override;
-
- VisualScriptFunction();
-};
-
-class VisualScriptLists : public VisualScriptNode {
- GDCLASS(VisualScriptLists, VisualScriptNode)
-
- struct Port {
- String name;
- Variant::Type type;
- };
-
-protected:
- Vector<Port> inputports;
- Vector<Port> outputports;
-
- enum {
- OUTPUT_EDITABLE = 0x0001,
- OUTPUT_NAME_EDITABLE = 0x0002,
- OUTPUT_TYPE_EDITABLE = 0x0004,
- INPUT_EDITABLE = 0x0008,
- INPUT_NAME_EDITABLE = 0x000F,
- INPUT_TYPE_EDITABLE = 0x0010,
- };
-
- int flags;
-
- bool sequenced;
-
- bool _set(const StringName &p_name, const Variant &p_value);
- bool _get(const StringName &p_name, Variant &r_ret) const;
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
- static void _bind_methods();
-
-public:
- virtual void reset_state() override;
-
- virtual bool is_output_port_editable() const;
- virtual bool is_output_port_name_editable() const;
- virtual bool is_output_port_type_editable() const;
-
- virtual bool is_input_port_editable() const;
- virtual bool is_input_port_name_editable() const;
- virtual bool is_input_port_type_editable() const;
-
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- void add_input_data_port(Variant::Type p_type, const String &p_name, int p_index = -1);
- void set_input_data_port_type(int p_idx, Variant::Type p_type);
- void set_input_data_port_name(int p_idx, const String &p_name);
- void remove_input_data_port(int p_argidx);
-
- void add_output_data_port(Variant::Type p_type, const String &p_name, int p_index = -1);
- void set_output_data_port_type(int p_idx, Variant::Type p_type);
- void set_output_data_port_name(int p_idx, const String &p_name);
- void remove_output_data_port(int p_argidx);
-
- void set_sequenced(bool p_enable);
- bool is_sequenced() const;
-
- VisualScriptLists();
-};
-
-class VisualScriptComposeArray : public VisualScriptLists {
- GDCLASS(VisualScriptComposeArray, VisualScriptLists)
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_text() const override;
- virtual String get_category() const override { return "functions"; }
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptComposeArray();
-};
-
-class VisualScriptOperator : public VisualScriptNode {
- GDCLASS(VisualScriptOperator, VisualScriptNode);
-
- Variant::Type typed;
- Variant::Operator op;
-
-protected:
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_category() const override { return "operators"; }
-
- void set_operator(Variant::Operator p_op);
- Variant::Operator get_operator() const;
-
- void set_typed(Variant::Type p_op);
- Variant::Type get_typed() const;
-
- static String get_operator_name(Variant::Operator p_op);
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptOperator();
-};
-
-class VisualScriptSelect : public VisualScriptNode {
- GDCLASS(VisualScriptSelect, VisualScriptNode);
-
- Variant::Type typed;
-
-protected:
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_text() const override;
- virtual String get_category() const override { return "operators"; }
-
- void set_typed(Variant::Type p_op);
- Variant::Type get_typed() const;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptSelect();
-};
-
-class VisualScriptVariableGet : public VisualScriptNode {
- GDCLASS(VisualScriptVariableGet, VisualScriptNode);
-
- StringName variable;
-
-protected:
- virtual void _validate_property(PropertyInfo &property) const override;
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_category() const override { return "data"; }
-
- void set_variable(StringName p_variable);
- StringName get_variable() const;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptVariableGet();
-};
-
-class VisualScriptVariableSet : public VisualScriptNode {
- GDCLASS(VisualScriptVariableSet, VisualScriptNode);
-
- StringName variable;
-
-protected:
- virtual void _validate_property(PropertyInfo &property) const override;
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_category() const override { return "data"; }
-
- void set_variable(StringName p_variable);
- StringName get_variable() const;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptVariableSet();
-};
-
-class VisualScriptConstant : public VisualScriptNode {
- GDCLASS(VisualScriptConstant, VisualScriptNode);
-
- Variant::Type type;
- Variant value;
-
-protected:
- virtual void _validate_property(PropertyInfo &property) const override;
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_category() const override { return "constants"; }
-
- void set_constant_type(Variant::Type p_type);
- Variant::Type get_constant_type() const;
-
- void set_constant_value(Variant p_value);
- Variant get_constant_value() const;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptConstant();
-};
-
-class VisualScriptPreload : public VisualScriptNode {
- GDCLASS(VisualScriptPreload, VisualScriptNode);
-
- Ref<Resource> preload;
-
-protected:
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_category() const override { return "data"; }
-
- void set_preload(const Ref<Resource> &p_preload);
- Ref<Resource> get_preload() const;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptPreload();
-};
-
-class VisualScriptIndexGet : public VisualScriptNode {
- GDCLASS(VisualScriptIndexGet, VisualScriptNode);
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_category() const override { return "operators"; }
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptIndexGet();
-};
-
-class VisualScriptIndexSet : public VisualScriptNode {
- GDCLASS(VisualScriptIndexSet, VisualScriptNode);
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_category() const override { return "operators"; }
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptIndexSet();
-};
-
-class VisualScriptGlobalConstant : public VisualScriptNode {
- GDCLASS(VisualScriptGlobalConstant, VisualScriptNode);
-
- int index;
-
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_category() const override { return "constants"; }
-
- void set_global_constant(int p_which);
- int get_global_constant();
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptGlobalConstant();
-};
-
-class VisualScriptClassConstant : public VisualScriptNode {
- GDCLASS(VisualScriptClassConstant, VisualScriptNode);
-
- StringName base_type;
- StringName name;
-
-protected:
- static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_category() const override { return "constants"; }
-
- void set_class_constant(const StringName &p_which);
- StringName get_class_constant();
-
- void set_base_type(const StringName &p_which);
- StringName get_base_type();
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptClassConstant();
-};
-
-class VisualScriptBasicTypeConstant : public VisualScriptNode {
- GDCLASS(VisualScriptBasicTypeConstant, VisualScriptNode);
-
- Variant::Type type;
- StringName name;
-
-protected:
- static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_text() const override;
- virtual String get_category() const override { return "constants"; }
-
- void set_basic_type_constant(const StringName &p_which);
- StringName get_basic_type_constant() const;
-
- void set_basic_type(Variant::Type p_which);
- Variant::Type get_basic_type() const;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptBasicTypeConstant();
-};
-
-class VisualScriptMathConstant : public VisualScriptNode {
- GDCLASS(VisualScriptMathConstant, VisualScriptNode);
-
-public:
- enum MathConstant {
- MATH_CONSTANT_ONE,
- MATH_CONSTANT_PI,
- MATH_CONSTANT_HALF_PI,
- MATH_CONSTANT_TAU,
- MATH_CONSTANT_E,
- MATH_CONSTANT_SQRT2,
- MATH_CONSTANT_INF,
- MATH_CONSTANT_NAN,
- MATH_CONSTANT_MAX
- };
-
-private:
- static const char *const_name[MATH_CONSTANT_MAX];
- static double const_value[MATH_CONSTANT_MAX];
- MathConstant constant;
-
-protected:
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_category() const override { return "constants"; }
-
- void set_math_constant(MathConstant p_which);
- MathConstant get_math_constant();
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptMathConstant();
-};
-
-VARIANT_ENUM_CAST(VisualScriptMathConstant::MathConstant)
-
-class VisualScriptEngineSingleton : public VisualScriptNode {
- GDCLASS(VisualScriptEngineSingleton, VisualScriptNode);
-
- String singleton;
-
-protected:
- void _validate_property(PropertyInfo &property) const override;
-
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_category() const override { return "data"; }
-
- void set_singleton(const String &p_string);
- String get_singleton();
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override;
-
- VisualScriptEngineSingleton();
-};
-
-class VisualScriptSceneNode : public VisualScriptNode {
- GDCLASS(VisualScriptSceneNode, VisualScriptNode);
-
- NodePath path;
-
-protected:
- virtual void _validate_property(PropertyInfo &property) const override;
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_category() const override { return "data"; }
-
- void set_node_path(const NodePath &p_path);
- NodePath get_node_path();
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override;
-
- VisualScriptSceneNode();
-};
-
-class VisualScriptSceneTree : public VisualScriptNode {
- GDCLASS(VisualScriptSceneTree, VisualScriptNode);
-
-protected:
- virtual void _validate_property(PropertyInfo &property) const override;
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_category() const override { return "data"; }
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override;
-
- VisualScriptSceneTree();
-};
-
-class VisualScriptResourcePath : public VisualScriptNode {
- GDCLASS(VisualScriptResourcePath, VisualScriptNode);
-
- String path;
-
-protected:
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_category() const override { return "data"; }
-
- void set_resource_path(const String &p_path);
- String get_resource_path();
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptResourcePath();
-};
-
-class VisualScriptSelf : public VisualScriptNode {
- GDCLASS(VisualScriptSelf, VisualScriptNode);
-
-protected:
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_category() const override { return "data"; }
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override;
-
- VisualScriptSelf();
-};
-
-class VisualScriptCustomNode : public VisualScriptNode {
- GDCLASS(VisualScriptCustomNode, VisualScriptNode);
-
-protected:
- static void _bind_methods();
- friend class VisualScriptNodeInstanceCustomNode;
- GDVIRTUAL0RC(int, _get_output_sequence_port_count)
- GDVIRTUAL0RC(bool, _has_input_sequence_port)
- GDVIRTUAL1RC(String, _get_output_sequence_port_text, int)
-
- GDVIRTUAL0RC(int, _get_input_value_port_count)
- GDVIRTUAL1RC(int, _get_input_value_port_type, int)
- GDVIRTUAL1RC(String, _get_input_value_port_name, int)
- GDVIRTUAL1RC(int, _get_input_value_port_hint, int)
- GDVIRTUAL1RC(String, _get_input_value_port_hint_string, int)
-
- GDVIRTUAL0RC(int, _get_output_value_port_count)
- GDVIRTUAL1RC(int, _get_output_value_port_type, int)
- GDVIRTUAL1RC(String, _get_output_value_port_name, int)
- GDVIRTUAL1RC(int, _get_output_value_port_hint, int)
- GDVIRTUAL1RC(String, _get_output_value_port_hint_string, int)
-
- GDVIRTUAL0RC(String, _get_caption)
- GDVIRTUAL0RC(String, _get_text)
- GDVIRTUAL0RC(String, _get_category)
-
- GDVIRTUAL0RC(int, _get_working_memory_size)
-
- GDVIRTUAL4RC(Variant, _step, Array, Array, int, Array)
-
-public:
- enum StartMode { //replicated for step
- START_MODE_BEGIN_SEQUENCE,
- START_MODE_CONTINUE_SEQUENCE,
- START_MODE_RESUME_YIELD
- };
-
- enum { //replicated for step
- STEP_SHIFT = 1 << 24,
- STEP_MASK = STEP_SHIFT - 1,
- STEP_PUSH_STACK_BIT = STEP_SHIFT, //push bit to stack
- STEP_GO_BACK_BIT = STEP_SHIFT << 1, //go back to previous node
- STEP_NO_ADVANCE_BIT = STEP_SHIFT << 2, //do not advance past this node
- STEP_EXIT_FUNCTION_BIT = STEP_SHIFT << 3, //return from function
- STEP_YIELD_BIT = STEP_SHIFT << 4, //yield (will find VisualScriptFunctionState state in first working memory)
- };
-
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_text() const override;
- virtual String get_category() const override;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override;
-
- void _script_changed();
-
- VisualScriptCustomNode();
-};
-
-VARIANT_ENUM_CAST(VisualScriptCustomNode::StartMode);
-
-class VisualScriptSubCall : public VisualScriptNode {
- GDCLASS(VisualScriptSubCall, VisualScriptNode);
-
-protected:
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_text() const override;
- virtual String get_category() const override;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptSubCall();
-};
-
-class VisualScriptComment : public VisualScriptNode {
- GDCLASS(VisualScriptComment, VisualScriptNode);
-
- String title;
- String description;
- Size2 size;
-
-protected:
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_text() const override;
- virtual String get_category() const override;
-
- void set_title(const String &p_title);
- String get_title() const;
-
- void set_description(const String &p_description);
- String get_description() const;
-
- void set_size(const Size2 &p_size);
- Size2 get_size() const;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptComment();
-};
-
-class VisualScriptConstructor : public VisualScriptNode {
- GDCLASS(VisualScriptConstructor, VisualScriptNode);
-
- Variant::Type type;
- MethodInfo constructor;
-
-protected:
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_category() const override;
-
- void set_constructor_type(Variant::Type p_type);
- Variant::Type get_constructor_type() const;
-
- void set_constructor(const Dictionary &p_info);
- Dictionary get_constructor() const;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptConstructor();
-};
-
-class VisualScriptLocalVar : public VisualScriptNode {
- GDCLASS(VisualScriptLocalVar, VisualScriptNode);
-
- StringName name;
- Variant::Type type;
-
-protected:
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_category() const override;
-
- void set_var_name(const StringName &p_name);
- StringName get_var_name() const;
-
- void set_var_type(Variant::Type p_type);
- Variant::Type get_var_type() const;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptLocalVar();
-};
-
-class VisualScriptLocalVarSet : public VisualScriptNode {
- GDCLASS(VisualScriptLocalVarSet, VisualScriptNode);
-
- StringName name;
- Variant::Type type;
-
-protected:
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_text() const override;
- virtual String get_category() const override;
-
- void set_var_name(const StringName &p_name);
- StringName get_var_name() const;
-
- void set_var_type(Variant::Type p_type);
- Variant::Type get_var_type() const;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptLocalVarSet();
-};
-
-class VisualScriptInputAction : public VisualScriptNode {
- GDCLASS(VisualScriptInputAction, VisualScriptNode);
-
-public:
- enum Mode {
- MODE_PRESSED,
- MODE_RELEASED,
- MODE_JUST_PRESSED,
- MODE_JUST_RELEASED,
- };
-
- StringName name;
- Mode mode;
-
-protected:
- virtual void _validate_property(PropertyInfo &property) const override;
-
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_category() const override;
-
- void set_action_name(const StringName &p_name);
- StringName get_action_name() const;
-
- void set_action_mode(Mode p_mode);
- Mode get_action_mode() const;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptInputAction();
-};
-
-VARIANT_ENUM_CAST(VisualScriptInputAction::Mode)
-
-class VisualScriptDeconstruct : public VisualScriptNode {
- GDCLASS(VisualScriptDeconstruct, VisualScriptNode);
-
- struct Element {
- StringName name;
- Variant::Type type;
- };
-
- Vector<Element> elements;
-
- void _update_elements();
- Variant::Type type;
-
- void _set_elem_cache(const Array &p_elements);
- Array _get_elem_cache() const;
-
- virtual void _validate_property(PropertyInfo &property) const override;
-
-protected:
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_category() const override;
-
- void set_deconstruct_type(Variant::Type p_type);
- Variant::Type get_deconstruct_type() const;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptDeconstruct();
-};
-
-void register_visual_script_nodes();
-void unregister_visual_script_nodes();
-
-#endif // VISUAL_SCRIPT_NODES_H
diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp
deleted file mode 100644
index 96e91a0baf..0000000000
--- a/modules/visual_script/visual_script_yield_nodes.cpp
+++ /dev/null
@@ -1,598 +0,0 @@
-/*************************************************************************/
-/* visual_script_yield_nodes.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "visual_script_yield_nodes.h"
-
-#include "core/os/os.h"
-#include "scene/main/node.h"
-#include "scene/main/scene_tree.h"
-#include "visual_script_nodes.h"
-
-//////////////////////////////////////////
-////////////////YIELD///////////
-//////////////////////////////////////////
-
-int VisualScriptYield::get_output_sequence_port_count() const {
- return 1;
-}
-
-bool VisualScriptYield::has_input_sequence_port() const {
- return true;
-}
-
-int VisualScriptYield::get_input_value_port_count() const {
- return 0;
-}
-
-int VisualScriptYield::get_output_value_port_count() const {
- return 0;
-}
-
-String VisualScriptYield::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptYield::get_input_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-PropertyInfo VisualScriptYield::get_output_value_port_info(int p_idx) const {
- return PropertyInfo();
-}
-
-String VisualScriptYield::get_caption() const {
- return yield_mode == YIELD_RETURN ? RTR("Yield") : RTR("Wait");
-}
-
-String VisualScriptYield::get_text() const {
- switch (yield_mode) {
- case YIELD_RETURN:
- return "";
- break;
- case YIELD_FRAME:
- return RTR("Next Frame");
- break;
- case YIELD_PHYSICS_FRAME:
- return RTR("Next Physics Frame");
- break;
- case YIELD_WAIT:
- return vformat(RTR("%s sec(s)"), rtos(wait_time));
- break;
- }
-
- return String();
-}
-
-class VisualScriptNodeInstanceYield : public VisualScriptNodeInstance {
-public:
- VisualScriptYield::YieldMode mode;
- double wait_time = 0.0;
-
- virtual int get_working_memory_size() const override { return 1; } //yield needs at least 1
- //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
- //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- if (p_start_mode == START_MODE_RESUME_YIELD) {
- return 0; //resuming yield
- } else {
- //yield
-
- SceneTree *tree = Object::cast_to<SceneTree>(OS::get_singleton()->get_main_loop());
- if (!tree) {
- r_error_str = "Main Loop is not SceneTree";
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- return 0;
- }
-
- Ref<VisualScriptFunctionState> state;
- state.instantiate();
-
- int ret = STEP_YIELD_BIT;
- switch (mode) {
- case VisualScriptYield::YIELD_RETURN:
- ret = STEP_EXIT_FUNCTION_BIT;
- break; //return the yield
- case VisualScriptYield::YIELD_FRAME:
- state->connect_to_signal(tree, "process_frame", Array());
- break;
- case VisualScriptYield::YIELD_PHYSICS_FRAME:
- state->connect_to_signal(tree, "physics_frame", Array());
- break;
- case VisualScriptYield::YIELD_WAIT:
- state->connect_to_signal(tree->create_timer(wait_time).ptr(), "timeout", Array());
- break;
- }
-
- *p_working_mem = state;
-
- return ret;
- }
- }
-};
-
-VisualScriptNodeInstance *VisualScriptYield::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceYield *instance = memnew(VisualScriptNodeInstanceYield);
- //instance->instance=p_instance;
- instance->mode = yield_mode;
- instance->wait_time = wait_time;
- return instance;
-}
-
-void VisualScriptYield::set_yield_mode(YieldMode p_mode) {
- if (yield_mode == p_mode) {
- return;
- }
- yield_mode = p_mode;
- ports_changed_notify();
- notify_property_list_changed();
-}
-
-VisualScriptYield::YieldMode VisualScriptYield::get_yield_mode() {
- return yield_mode;
-}
-
-void VisualScriptYield::set_wait_time(double p_time) {
- if (wait_time == p_time) {
- return;
- }
- wait_time = p_time;
- ports_changed_notify();
-}
-
-double VisualScriptYield::get_wait_time() {
- return wait_time;
-}
-
-void VisualScriptYield::_validate_property(PropertyInfo &property) const {
- if (property.name == "wait_time") {
- if (yield_mode != YIELD_WAIT) {
- property.usage = PROPERTY_USAGE_NONE;
- }
- }
-}
-
-void VisualScriptYield::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_yield_mode", "mode"), &VisualScriptYield::set_yield_mode);
- ClassDB::bind_method(D_METHOD("get_yield_mode"), &VisualScriptYield::get_yield_mode);
-
- ClassDB::bind_method(D_METHOD("set_wait_time", "sec"), &VisualScriptYield::set_wait_time);
- ClassDB::bind_method(D_METHOD("get_wait_time"), &VisualScriptYield::get_wait_time);
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Frame,Physics Frame,Time", PROPERTY_USAGE_NO_EDITOR), "set_yield_mode", "get_yield_mode");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wait_time"), "set_wait_time", "get_wait_time");
-
- BIND_ENUM_CONSTANT(YIELD_FRAME);
- BIND_ENUM_CONSTANT(YIELD_PHYSICS_FRAME);
- BIND_ENUM_CONSTANT(YIELD_WAIT);
-}
-
-VisualScriptYield::VisualScriptYield() {
- yield_mode = YIELD_FRAME;
- wait_time = 1;
-}
-
-template <VisualScriptYield::YieldMode MODE>
-static Ref<VisualScriptNode> create_yield_node(const String &p_name) {
- Ref<VisualScriptYield> node;
- node.instantiate();
- node->set_yield_mode(MODE);
- return node;
-}
-
-///////////////////////////////////////////////////
-////////////////YIELD SIGNAL//////////////////////
-//////////////////////////////////////////////////
-
-int VisualScriptYieldSignal::get_output_sequence_port_count() const {
- return 1;
-}
-
-bool VisualScriptYieldSignal::has_input_sequence_port() const {
- return true;
-}
-#ifdef TOOLS_ENABLED
-
-static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) {
- if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene) {
- return nullptr;
- }
-
- Ref<Script> scr = p_current_node->get_script();
-
- if (scr.is_valid() && scr == script) {
- return p_current_node;
- }
-
- for (int i = 0; i < p_current_node->get_child_count(); i++) {
- Node *n = _find_script_node(p_edited_scene, p_current_node->get_child(i), script);
- if (n) {
- return n;
- }
- }
-
- return nullptr;
-}
-
-#endif
-Node *VisualScriptYieldSignal::_get_base_node() const {
-#ifdef TOOLS_ENABLED
- Ref<Script> script = get_visual_script();
- if (!script.is_valid()) {
- return nullptr;
- }
-
- MainLoop *main_loop = OS::get_singleton()->get_main_loop();
- SceneTree *scene_tree = Object::cast_to<SceneTree>(main_loop);
-
- if (!scene_tree) {
- return nullptr;
- }
-
- Node *edited_scene = scene_tree->get_edited_scene_root();
-
- if (!edited_scene) {
- return nullptr;
- }
-
- Node *script_node = _find_script_node(edited_scene, edited_scene, script);
-
- if (!script_node) {
- return nullptr;
- }
-
- if (!script_node->has_node(base_path)) {
- return nullptr;
- }
-
- Node *path_to = script_node->get_node(base_path);
-
- return path_to;
-#else
-
- return nullptr;
-#endif
-}
-
-StringName VisualScriptYieldSignal::_get_base_type() const {
- if (call_mode == CALL_MODE_SELF && get_visual_script().is_valid()) {
- return get_visual_script()->get_instance_base_type();
- } else if (call_mode == CALL_MODE_NODE_PATH && get_visual_script().is_valid()) {
- Node *path = _get_base_node();
- if (path) {
- return path->get_class();
- }
- }
-
- return base_type;
-}
-
-int VisualScriptYieldSignal::get_input_value_port_count() const {
- if (call_mode == CALL_MODE_INSTANCE) {
- return 1;
- } else {
- return 0;
- }
-}
-
-int VisualScriptYieldSignal::get_output_value_port_count() const {
- MethodInfo sr;
-
- if (!ClassDB::get_signal(_get_base_type(), signal, &sr)) {
- return 0;
- }
-
- return sr.arguments.size();
-}
-
-String VisualScriptYieldSignal::get_output_sequence_port_text(int p_port) const {
- return String();
-}
-
-PropertyInfo VisualScriptYieldSignal::get_input_value_port_info(int p_idx) const {
- if (call_mode == CALL_MODE_INSTANCE) {
- return PropertyInfo(Variant::OBJECT, "instance");
- } else {
- return PropertyInfo();
- }
-}
-
-PropertyInfo VisualScriptYieldSignal::get_output_value_port_info(int p_idx) const {
- MethodInfo sr;
-
- if (!ClassDB::get_signal(_get_base_type(), signal, &sr)) {
- return PropertyInfo(); //no signal
- }
- ERR_FAIL_INDEX_V(p_idx, sr.arguments.size(), PropertyInfo());
- return sr.arguments[p_idx];
-}
-
-String VisualScriptYieldSignal::get_caption() const {
- switch (call_mode) {
- case CALL_MODE_SELF: {
- return RTR("WaitSignal");
- } break;
- case CALL_MODE_NODE_PATH: {
- return RTR("WaitNodeSignal");
- } break;
- case CALL_MODE_INSTANCE: {
- return RTR("WaitInstanceSignal");
- } break;
- }
- return String();
-}
-
-String VisualScriptYieldSignal::get_text() const {
- if (call_mode == CALL_MODE_SELF) {
- return " " + String(signal) + "()";
- } else {
- return " " + _get_base_type() + "." + String(signal) + "()";
- }
-}
-
-void VisualScriptYieldSignal::set_base_type(const StringName &p_type) {
- if (base_type == p_type) {
- return;
- }
-
- base_type = p_type;
-
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-StringName VisualScriptYieldSignal::get_base_type() const {
- return base_type;
-}
-
-void VisualScriptYieldSignal::set_signal(const StringName &p_type) {
- if (signal == p_type) {
- return;
- }
-
- signal = p_type;
-
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-StringName VisualScriptYieldSignal::get_signal() const {
- return signal;
-}
-
-void VisualScriptYieldSignal::set_base_path(const NodePath &p_type) {
- if (base_path == p_type) {
- return;
- }
-
- base_path = p_type;
-
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-NodePath VisualScriptYieldSignal::get_base_path() const {
- return base_path;
-}
-
-void VisualScriptYieldSignal::set_call_mode(CallMode p_mode) {
- if (call_mode == p_mode) {
- return;
- }
-
- call_mode = p_mode;
-
- notify_property_list_changed();
- ports_changed_notify();
-}
-
-VisualScriptYieldSignal::CallMode VisualScriptYieldSignal::get_call_mode() const {
- return call_mode;
-}
-
-void VisualScriptYieldSignal::_validate_property(PropertyInfo &property) const {
- if (property.name == "base_type") {
- if (call_mode != CALL_MODE_INSTANCE) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
- }
- }
-
- if (property.name == "node_path") {
- if (call_mode != CALL_MODE_NODE_PATH) {
- property.usage = PROPERTY_USAGE_NONE;
- } else {
- Node *bnode = _get_base_node();
- if (bnode) {
- property.hint_string = bnode->get_path(); //convert to long string
- }
- }
- }
-
- if (property.name == "signal") {
- property.hint = PROPERTY_HINT_ENUM;
-
- List<MethodInfo> methods;
-
- ClassDB::get_signal_list(_get_base_type(), &methods);
-
- List<String> mstring;
- for (const MethodInfo &E : methods) {
- if (E.name.begins_with("_")) {
- continue;
- }
- mstring.push_back(E.name.get_slice(":", 0));
- }
-
- mstring.sort();
-
- String ml;
- for (const String &E : mstring) {
- if (!ml.is_empty()) {
- ml += ",";
- }
- ml += E;
- }
-
- property.hint_string = ml;
- }
-}
-
-void VisualScriptYieldSignal::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_base_type", "base_type"), &VisualScriptYieldSignal::set_base_type);
- ClassDB::bind_method(D_METHOD("get_base_type"), &VisualScriptYieldSignal::get_base_type);
-
- ClassDB::bind_method(D_METHOD("set_signal", "signal"), &VisualScriptYieldSignal::set_signal);
- ClassDB::bind_method(D_METHOD("get_signal"), &VisualScriptYieldSignal::get_signal);
-
- ClassDB::bind_method(D_METHOD("set_call_mode", "mode"), &VisualScriptYieldSignal::set_call_mode);
- ClassDB::bind_method(D_METHOD("get_call_mode"), &VisualScriptYieldSignal::get_call_mode);
-
- ClassDB::bind_method(D_METHOD("set_base_path", "base_path"), &VisualScriptYieldSignal::set_base_path);
- ClassDB::bind_method(D_METHOD("get_base_path"), &VisualScriptYieldSignal::get_base_path);
-
- String bt;
- for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- if (i > 0) {
- bt += ",";
- }
-
- bt += Variant::get_type_name(Variant::Type(i));
- }
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "call_mode", PROPERTY_HINT_ENUM, "Self,Node Path,Instance"), "set_call_mode", "get_call_mode");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type", PROPERTY_HINT_TYPE_STRING, "Object"), "set_base_type", "get_base_type");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_path", PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE), "set_base_path", "get_base_path");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "signal"), "set_signal", "get_signal");
-
- BIND_ENUM_CONSTANT(CALL_MODE_SELF);
- BIND_ENUM_CONSTANT(CALL_MODE_NODE_PATH);
- BIND_ENUM_CONSTANT(CALL_MODE_INSTANCE);
-}
-
-class VisualScriptNodeInstanceYieldSignal : public VisualScriptNodeInstance {
-public:
- VisualScriptYieldSignal::CallMode call_mode;
- NodePath node_path;
- int output_args = 0;
- StringName signal;
-
- VisualScriptYieldSignal *node = nullptr;
- VisualScriptInstance *instance = nullptr;
-
- virtual int get_working_memory_size() const override { return 1; }
- //virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
- //virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
-
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
- if (p_start_mode == START_MODE_RESUME_YIELD) {
- return 0; //resuming yield
- } else {
- //yield
-
- Object *object = nullptr;
-
- switch (call_mode) {
- case VisualScriptYieldSignal::CALL_MODE_SELF: {
- object = instance->get_owner_ptr();
-
- } break;
- case VisualScriptYieldSignal::CALL_MODE_NODE_PATH: {
- Node *node = Object::cast_to<Node>(instance->get_owner_ptr());
- if (!node) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = "Base object is not a Node!";
- return 0;
- }
-
- Node *another = node->get_node(node_path);
- if (!another) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = "Path does not lead Node!";
- return 0;
- }
-
- object = another;
-
- } break;
- case VisualScriptYieldSignal::CALL_MODE_INSTANCE: {
- object = *p_inputs[0];
- if (!object) {
- r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
- r_error_str = "Supplied instance input is null.";
- return 0;
- }
-
- } break;
- }
-
- Ref<VisualScriptFunctionState> state;
- state.instantiate();
-
- state->connect_to_signal(object, signal, Array());
-
- *p_working_mem = state;
-
- return STEP_YIELD_BIT;
- }
- }
-};
-
-VisualScriptNodeInstance *VisualScriptYieldSignal::instantiate(VisualScriptInstance *p_instance) {
- VisualScriptNodeInstanceYieldSignal *instance = memnew(VisualScriptNodeInstanceYieldSignal);
- instance->node = this;
- instance->instance = p_instance;
- instance->signal = signal;
- instance->call_mode = call_mode;
- instance->node_path = base_path;
- instance->output_args = get_output_value_port_count();
- return instance;
-}
-
-VisualScriptYieldSignal::VisualScriptYieldSignal() {
- call_mode = CALL_MODE_SELF;
- base_type = "Object";
-}
-
-template <VisualScriptYieldSignal::CallMode cmode>
-static Ref<VisualScriptNode> create_yield_signal_node(const String &p_name) {
- Ref<VisualScriptYieldSignal> node;
- node.instantiate();
- node->set_call_mode(cmode);
- return node;
-}
-
-void register_visual_script_yield_nodes() {
- VisualScriptLanguage::singleton->add_register_func("functions/wait/wait_frame", create_yield_node<VisualScriptYield::YIELD_FRAME>);
- VisualScriptLanguage::singleton->add_register_func("functions/wait/wait_physics_frame", create_yield_node<VisualScriptYield::YIELD_PHYSICS_FRAME>);
- VisualScriptLanguage::singleton->add_register_func("functions/wait/wait_time", create_yield_node<VisualScriptYield::YIELD_WAIT>);
-
- VisualScriptLanguage::singleton->add_register_func("functions/yield", create_yield_node<VisualScriptYield::YIELD_RETURN>);
- VisualScriptLanguage::singleton->add_register_func("functions/yield_signal", create_node_generic<VisualScriptYieldSignal>);
-}
diff --git a/modules/visual_script/visual_script_yield_nodes.h b/modules/visual_script/visual_script_yield_nodes.h
deleted file mode 100644
index a7bf4e8a78..0000000000
--- a/modules/visual_script/visual_script_yield_nodes.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*************************************************************************/
-/* visual_script_yield_nodes.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef VISUAL_SCRIPT_YIELD_NODES_H
-#define VISUAL_SCRIPT_YIELD_NODES_H
-
-#include "visual_script.h"
-
-class VisualScriptYield : public VisualScriptNode {
- GDCLASS(VisualScriptYield, VisualScriptNode);
-
-public:
- enum YieldMode {
- YIELD_RETURN,
- YIELD_FRAME,
- YIELD_PHYSICS_FRAME,
- YIELD_WAIT
-
- };
-
-private:
- YieldMode yield_mode;
- double wait_time;
-
-protected:
- virtual void _validate_property(PropertyInfo &property) const override;
-
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_text() const override;
- virtual String get_category() const override { return "functions"; }
-
- void set_yield_mode(YieldMode p_mode);
- YieldMode get_yield_mode();
-
- void set_wait_time(double p_time);
- double get_wait_time();
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptYield();
-};
-VARIANT_ENUM_CAST(VisualScriptYield::YieldMode)
-
-class VisualScriptYieldSignal : public VisualScriptNode {
- GDCLASS(VisualScriptYieldSignal, VisualScriptNode);
-
-public:
- enum CallMode {
- CALL_MODE_SELF,
- CALL_MODE_NODE_PATH,
- CALL_MODE_INSTANCE,
-
- };
-
-private:
- CallMode call_mode;
- StringName base_type;
- NodePath base_path;
- StringName signal;
-
- Node *_get_base_node() const;
- StringName _get_base_type() const;
-
-protected:
- virtual void _validate_property(PropertyInfo &property) const override;
-
- static void _bind_methods();
-
-public:
- virtual int get_output_sequence_port_count() const override;
- virtual bool has_input_sequence_port() const override;
-
- virtual String get_output_sequence_port_text(int p_port) const override;
-
- virtual int get_input_value_port_count() const override;
- virtual int get_output_value_port_count() const override;
-
- virtual PropertyInfo get_input_value_port_info(int p_idx) const override;
- virtual PropertyInfo get_output_value_port_info(int p_idx) const override;
-
- virtual String get_caption() const override;
- virtual String get_text() const override;
- virtual String get_category() const override { return "functions"; }
-
- void set_base_type(const StringName &p_type);
- StringName get_base_type() const;
-
- void set_signal(const StringName &p_type);
- StringName get_signal() const;
-
- void set_base_path(const NodePath &p_type);
- NodePath get_base_path() const;
-
- void set_call_mode(CallMode p_mode);
- CallMode get_call_mode() const;
-
- virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override;
-
- VisualScriptYieldSignal();
-};
-
-VARIANT_ENUM_CAST(VisualScriptYieldSignal::CallMode);
-
-void register_visual_script_yield_nodes();
-
-#endif // VISUAL_SCRIPT_YIELD_NODES_H
diff --git a/modules/vorbis/config.py b/modules/vorbis/config.py
index 7ce885a37a..a231ef179d 100644
--- a/modules/vorbis/config.py
+++ b/modules/vorbis/config.py
@@ -1,5 +1,6 @@
def can_build(env, platform):
- return env.module_check_dependencies("vorbis", ["ogg"])
+ env.module_add_dependencies("vorbis", ["ogg"])
+ return True
def configure(env):
diff --git a/modules/webp/SCsub b/modules/webp/SCsub
index 80d62400c8..72ad1ea5e4 100644
--- a/modules/webp/SCsub
+++ b/modules/webp/SCsub
@@ -12,123 +12,129 @@ thirdparty_obj = []
if env["builtin_libwebp"]:
thirdparty_dir = "#thirdparty/libwebp/"
thirdparty_sources = [
- "dec/alpha_dec.c",
- "dec/buffer_dec.c",
- "dec/frame_dec.c",
- "dec/idec_dec.c",
- "dec/io_dec.c",
- "dec/quant_dec.c",
- "dec/tree_dec.c",
- "dec/vp8_dec.c",
- "dec/vp8l_dec.c",
- "dec/webp_dec.c",
- "demux/anim_decode.c",
- "demux/demux.c",
- "dsp/alpha_processing.c",
- "dsp/alpha_processing_mips_dsp_r2.c",
- "dsp/alpha_processing_neon.c",
- "dsp/alpha_processing_sse2.c",
- "dsp/alpha_processing_sse41.c",
- "dsp/cost.c",
- "dsp/cost_mips32.c",
- "dsp/cost_mips_dsp_r2.c",
- "dsp/cost_neon.c",
- "dsp/cost_sse2.c",
- "dsp/cpu.c",
- "dsp/dec.c",
- "dsp/dec_clip_tables.c",
- "dsp/dec_mips32.c",
- "dsp/dec_mips_dsp_r2.c",
- "dsp/dec_msa.c",
- "dsp/dec_neon.c",
- "dsp/dec_sse2.c",
- "dsp/dec_sse41.c",
- "dsp/enc.c",
- "dsp/enc_mips32.c",
- "dsp/enc_mips_dsp_r2.c",
- "dsp/enc_msa.c",
- "dsp/enc_neon.c",
- "dsp/enc_sse2.c",
- "dsp/enc_sse41.c",
- "dsp/filters.c",
- "dsp/filters_mips_dsp_r2.c",
- "dsp/filters_msa.c",
- "dsp/filters_neon.c",
- "dsp/filters_sse2.c",
- "dsp/lossless.c",
- "dsp/lossless_enc.c",
- "dsp/lossless_enc_mips32.c",
- "dsp/lossless_enc_mips_dsp_r2.c",
- "dsp/lossless_enc_msa.c",
- "dsp/lossless_enc_neon.c",
- "dsp/lossless_enc_sse2.c",
- "dsp/lossless_enc_sse41.c",
- "dsp/lossless_mips_dsp_r2.c",
- "dsp/lossless_msa.c",
- "dsp/lossless_neon.c",
- "dsp/lossless_sse2.c",
- "dsp/lossless_sse41.c",
- "dsp/rescaler.c",
- "dsp/rescaler_mips32.c",
- "dsp/rescaler_mips_dsp_r2.c",
- "dsp/rescaler_msa.c",
- "dsp/rescaler_neon.c",
- "dsp/rescaler_sse2.c",
- "dsp/ssim.c",
- "dsp/ssim_sse2.c",
- "dsp/upsampling.c",
- "dsp/upsampling_mips_dsp_r2.c",
- "dsp/upsampling_msa.c",
- "dsp/upsampling_neon.c",
- "dsp/upsampling_sse2.c",
- "dsp/upsampling_sse41.c",
- "dsp/yuv.c",
- "dsp/yuv_mips32.c",
- "dsp/yuv_mips_dsp_r2.c",
- "dsp/yuv_neon.c",
- "dsp/yuv_sse2.c",
- "dsp/yuv_sse41.c",
- "enc/alpha_enc.c",
- "enc/analysis_enc.c",
- "enc/backward_references_cost_enc.c",
- "enc/backward_references_enc.c",
- "enc/config_enc.c",
- "enc/cost_enc.c",
- "enc/filter_enc.c",
- "enc/frame_enc.c",
- "enc/histogram_enc.c",
- "enc/iterator_enc.c",
- "enc/near_lossless_enc.c",
- "enc/picture_csp_enc.c",
- "enc/picture_enc.c",
- "enc/picture_psnr_enc.c",
- "enc/picture_rescale_enc.c",
- "enc/picture_tools_enc.c",
- "enc/predictor_enc.c",
- "enc/quant_enc.c",
- "enc/syntax_enc.c",
- "enc/token_enc.c",
- "enc/tree_enc.c",
- "enc/vp8l_enc.c",
- "enc/webp_enc.c",
- "mux/anim_encode.c",
- "mux/muxedit.c",
- "mux/muxinternal.c",
- "mux/muxread.c",
- "utils/bit_reader_utils.c",
- "utils/bit_writer_utils.c",
- "utils/color_cache_utils.c",
- "utils/filters_utils.c",
- "utils/huffman_encode_utils.c",
- "utils/huffman_utils.c",
- "utils/quant_levels_dec_utils.c",
- "utils/quant_levels_utils.c",
- "utils/random_utils.c",
- "utils/rescaler_utils.c",
- "utils/thread_utils.c",
- "utils/utils.c",
+ "sharpyuv/sharpyuv.c",
+ "sharpyuv/sharpyuv_csp.c",
+ "sharpyuv/sharpyuv_dsp.c",
+ "sharpyuv/sharpyuv_gamma.c",
+ "sharpyuv/sharpyuv_neon.c",
+ "sharpyuv/sharpyuv_sse2.c",
+ "src/dec/alpha_dec.c",
+ "src/dec/buffer_dec.c",
+ "src/dec/frame_dec.c",
+ "src/dec/idec_dec.c",
+ "src/dec/io_dec.c",
+ "src/dec/quant_dec.c",
+ "src/dec/tree_dec.c",
+ "src/dec/vp8_dec.c",
+ "src/dec/vp8l_dec.c",
+ "src/dec/webp_dec.c",
+ "src/demux/anim_decode.c",
+ "src/demux/demux.c",
+ "src/dsp/alpha_processing.c",
+ "src/dsp/alpha_processing_mips_dsp_r2.c",
+ "src/dsp/alpha_processing_neon.c",
+ "src/dsp/alpha_processing_sse2.c",
+ "src/dsp/alpha_processing_sse41.c",
+ "src/dsp/cost.c",
+ "src/dsp/cost_mips32.c",
+ "src/dsp/cost_mips_dsp_r2.c",
+ "src/dsp/cost_neon.c",
+ "src/dsp/cost_sse2.c",
+ "src/dsp/cpu.c",
+ "src/dsp/dec.c",
+ "src/dsp/dec_clip_tables.c",
+ "src/dsp/dec_mips32.c",
+ "src/dsp/dec_mips_dsp_r2.c",
+ "src/dsp/dec_msa.c",
+ "src/dsp/dec_neon.c",
+ "src/dsp/dec_sse2.c",
+ "src/dsp/dec_sse41.c",
+ "src/dsp/enc.c",
+ "src/dsp/enc_mips32.c",
+ "src/dsp/enc_mips_dsp_r2.c",
+ "src/dsp/enc_msa.c",
+ "src/dsp/enc_neon.c",
+ "src/dsp/enc_sse2.c",
+ "src/dsp/enc_sse41.c",
+ "src/dsp/filters.c",
+ "src/dsp/filters_mips_dsp_r2.c",
+ "src/dsp/filters_msa.c",
+ "src/dsp/filters_neon.c",
+ "src/dsp/filters_sse2.c",
+ "src/dsp/lossless.c",
+ "src/dsp/lossless_enc.c",
+ "src/dsp/lossless_enc_mips32.c",
+ "src/dsp/lossless_enc_mips_dsp_r2.c",
+ "src/dsp/lossless_enc_msa.c",
+ "src/dsp/lossless_enc_neon.c",
+ "src/dsp/lossless_enc_sse2.c",
+ "src/dsp/lossless_enc_sse41.c",
+ "src/dsp/lossless_mips_dsp_r2.c",
+ "src/dsp/lossless_msa.c",
+ "src/dsp/lossless_neon.c",
+ "src/dsp/lossless_sse2.c",
+ "src/dsp/lossless_sse41.c",
+ "src/dsp/rescaler.c",
+ "src/dsp/rescaler_mips32.c",
+ "src/dsp/rescaler_mips_dsp_r2.c",
+ "src/dsp/rescaler_msa.c",
+ "src/dsp/rescaler_neon.c",
+ "src/dsp/rescaler_sse2.c",
+ "src/dsp/ssim.c",
+ "src/dsp/ssim_sse2.c",
+ "src/dsp/upsampling.c",
+ "src/dsp/upsampling_mips_dsp_r2.c",
+ "src/dsp/upsampling_msa.c",
+ "src/dsp/upsampling_neon.c",
+ "src/dsp/upsampling_sse2.c",
+ "src/dsp/upsampling_sse41.c",
+ "src/dsp/yuv.c",
+ "src/dsp/yuv_mips32.c",
+ "src/dsp/yuv_mips_dsp_r2.c",
+ "src/dsp/yuv_neon.c",
+ "src/dsp/yuv_sse2.c",
+ "src/dsp/yuv_sse41.c",
+ "src/enc/alpha_enc.c",
+ "src/enc/analysis_enc.c",
+ "src/enc/backward_references_cost_enc.c",
+ "src/enc/backward_references_enc.c",
+ "src/enc/config_enc.c",
+ "src/enc/cost_enc.c",
+ "src/enc/filter_enc.c",
+ "src/enc/frame_enc.c",
+ "src/enc/histogram_enc.c",
+ "src/enc/iterator_enc.c",
+ "src/enc/near_lossless_enc.c",
+ "src/enc/picture_csp_enc.c",
+ "src/enc/picture_enc.c",
+ "src/enc/picture_psnr_enc.c",
+ "src/enc/picture_rescale_enc.c",
+ "src/enc/picture_tools_enc.c",
+ "src/enc/predictor_enc.c",
+ "src/enc/quant_enc.c",
+ "src/enc/syntax_enc.c",
+ "src/enc/token_enc.c",
+ "src/enc/tree_enc.c",
+ "src/enc/vp8l_enc.c",
+ "src/enc/webp_enc.c",
+ "src/mux/anim_encode.c",
+ "src/mux/muxedit.c",
+ "src/mux/muxinternal.c",
+ "src/mux/muxread.c",
+ "src/utils/bit_reader_utils.c",
+ "src/utils/bit_writer_utils.c",
+ "src/utils/color_cache_utils.c",
+ "src/utils/filters_utils.c",
+ "src/utils/huffman_encode_utils.c",
+ "src/utils/huffman_utils.c",
+ "src/utils/quant_levels_dec_utils.c",
+ "src/utils/quant_levels_utils.c",
+ "src/utils/random_utils.c",
+ "src/utils/rescaler_utils.c",
+ "src/utils/thread_utils.c",
+ "src/utils/utils.c",
]
- thirdparty_sources = [thirdparty_dir + "src/" + file for file in thirdparty_sources]
+ thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
env_webp.Prepend(CPPPATH=[thirdparty_dir, thirdparty_dir + "src/"])
diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp
index 778d562278..705ab508ab 100644
--- a/modules/webp/image_loader_webp.cpp
+++ b/modules/webp/image_loader_webp.cpp
@@ -48,7 +48,7 @@ static Ref<Image> _webp_mem_loader_func(const uint8_t *p_png, int p_size) {
return img;
}
-Error ImageLoaderWebP::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) {
+Error ImageLoaderWebP::load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale) {
Vector<uint8_t> src_image;
uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
diff --git a/modules/webp/image_loader_webp.h b/modules/webp/image_loader_webp.h
index 9a5dc6cd7c..d868ae3f7f 100644
--- a/modules/webp/image_loader_webp.h
+++ b/modules/webp/image_loader_webp.h
@@ -35,7 +35,7 @@
class ImageLoaderWebP : public ImageFormatLoader {
public:
- virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, uint32_t p_flags, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderWebP();
};
diff --git a/modules/webrtc/SCsub b/modules/webrtc/SCsub
index e6b9959840..e315633f55 100644
--- a/modules/webrtc/SCsub
+++ b/modules/webrtc/SCsub
@@ -5,7 +5,7 @@ Import("env_modules")
env_webrtc = env_modules.Clone()
-if env["platform"] == "javascript":
+if env["platform"] == "web":
# Our JavaScript/C++ interface.
env.AddJSLibraries(["library_godot_webrtc.js"])
diff --git a/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml b/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml
index f937fba9d6..5387deaa47 100644
--- a/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml
+++ b/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml
@@ -49,8 +49,8 @@
</method>
<method name="_get_packet" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="r_buffer" type="const uint8_t **" />
- <argument index="1" name="r_buffer_size" type="int32_t*" />
+ <param index="0" name="r_buffer" type="const uint8_t **" />
+ <param index="1" name="r_buffer_size" type="int32_t*" />
<description>
</description>
</method>
@@ -86,14 +86,14 @@
</method>
<method name="_put_packet" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="p_buffer" type="const uint8_t*" />
- <argument index="1" name="p_buffer_size" type="int" />
+ <param index="0" name="p_buffer" type="const uint8_t*" />
+ <param index="1" name="p_buffer_size" type="int" />
<description>
</description>
</method>
<method name="_set_write_mode" qualifiers="virtual">
<return type="void" />
- <argument index="0" name="p_write_mode" type="int" />
+ <param index="0" name="p_write_mode" type="int" />
<description>
</description>
</method>
diff --git a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml
index df92097135..927888fe21 100644
--- a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml
+++ b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml
@@ -14,9 +14,9 @@
<methods>
<method name="add_peer">
<return type="int" enum="Error" />
- <argument index="0" name="peer" type="WebRTCPeerConnection" />
- <argument index="1" name="peer_id" type="int" />
- <argument index="2" name="unreliable_lifetime" type="int" default="1" />
+ <param index="0" name="peer" type="WebRTCPeerConnection" />
+ <param index="1" name="peer_id" type="int" />
+ <param index="2" name="unreliable_lifetime" type="int" default="1" />
<description>
Add a new peer to the mesh with the given [code]peer_id[/code]. The [WebRTCPeerConnection] must be in state [constant WebRTCPeerConnection.STATE_NEW].
Three channels will be created for reliable, unreliable, and ordered transport. The value of [code]unreliable_lifetime[/code] will be passed to the [code]maxPacketLifetime[/code] option when creating unreliable and ordered channels (see [method WebRTCPeerConnection.create_data_channel]).
@@ -30,7 +30,7 @@
</method>
<method name="get_peer">
<return type="Dictionary" />
- <argument index="0" name="peer_id" type="int" />
+ <param index="0" name="peer_id" type="int" />
<description>
Returns a dictionary representation of the peer with given [code]peer_id[/code] with three keys. [code]connection[/code] containing the [WebRTCPeerConnection] to this peer, [code]channels[/code] an array of three [WebRTCDataChannel], and [code]connected[/code] a boolean representing if the peer connection is currently connected (all three channels are open).
</description>
@@ -43,16 +43,16 @@
</method>
<method name="has_peer">
<return type="bool" />
- <argument index="0" name="peer_id" type="int" />
+ <param index="0" name="peer_id" type="int" />
<description>
Returns [code]true[/code] if the given [code]peer_id[/code] is in the peers map (it might not be connected though).
</description>
</method>
<method name="initialize">
<return type="int" enum="Error" />
- <argument index="0" name="peer_id" type="int" />
- <argument index="1" name="server_compatibility" type="bool" default="false" />
- <argument index="2" name="channels_config" type="Array" default="[]" />
+ <param index="0" name="peer_id" type="int" />
+ <param index="1" name="server_compatibility" type="bool" default="false" />
+ <param index="2" name="channels_config" type="Array" default="[]" />
<description>
Initialize the multiplayer peer with the given [code]peer_id[/code] (must be between 1 and 2147483647).
If [code]server_compatibilty[/code] is [code]false[/code] (default), the multiplayer peer will be immediately in state [constant MultiplayerPeer.CONNECTION_CONNECTED] and [signal MultiplayerPeer.connection_succeeded] will not be emitted.
@@ -62,7 +62,7 @@
</method>
<method name="remove_peer">
<return type="void" />
- <argument index="0" name="peer_id" type="int" />
+ <param index="0" name="peer_id" type="int" />
<description>
Remove the peer with given [code]peer_id[/code] from the mesh. If the peer was connected, and [signal MultiplayerPeer.peer_connected] was emitted for it, then [signal MultiplayerPeer.peer_disconnected] will be emitted.
</description>
diff --git a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml
index fed67397d1..e99aeb4f51 100644
--- a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml
+++ b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml
@@ -16,9 +16,9 @@
<methods>
<method name="add_ice_candidate">
<return type="int" enum="Error" />
- <argument index="0" name="media" type="String" />
- <argument index="1" name="index" type="int" />
- <argument index="2" name="name" type="String" />
+ <param index="0" name="media" type="String" />
+ <param index="1" name="index" type="int" />
+ <param index="2" name="name" type="String" />
<description>
Add an ice candidate generated by a remote peer (and received over the signaling server). See [signal ice_candidate_created].
</description>
@@ -32,8 +32,8 @@
</method>
<method name="create_data_channel">
<return type="WebRTCDataChannel" />
- <argument index="0" name="label" type="String" />
- <argument index="1" name="options" type="Dictionary" default="{}" />
+ <param index="0" name="label" type="String" />
+ <param index="1" name="options" type="Dictionary" default="{}" />
<description>
Returns a new [WebRTCDataChannel] (or [code]null[/code] on failure) with given [code]label[/code] and optionally configured via the [code]options[/code] dictionary. This method can only be called when the connection is in state [constant STATE_NEW].
There are two ways to create a working data channel: either call [method create_data_channel] on only one of the peer and listen to [signal data_channel_received] on the other, or call [method create_data_channel] on both peers, with the same values, and the [code]negotiated[/code] option set to [code]true[/code].
@@ -69,7 +69,7 @@
</method>
<method name="initialize">
<return type="int" enum="Error" />
- <argument index="0" name="configuration" type="Dictionary" default="{}" />
+ <param index="0" name="configuration" type="Dictionary" default="{}" />
<description>
Re-initialize this peer connection, closing any previously active connection, and going back to state [constant STATE_NEW]. A dictionary of [code]options[/code] can be passed to configure the peer connection.
Valid [code]options[/code] are:
@@ -97,15 +97,15 @@
</method>
<method name="set_default_extension" qualifiers="static">
<return type="void" />
- <argument index="0" name="extension_class" type="StringName" />
+ <param index="0" name="extension_class" type="StringName" />
<description>
Sets the [code]extension_class[/code] as the default [WebRTCPeerConnectionExtension] returned when creating a new [WebRTCPeerConnection].
</description>
</method>
<method name="set_local_description">
<return type="int" enum="Error" />
- <argument index="0" name="type" type="String" />
- <argument index="1" name="sdp" type="String" />
+ <param index="0" name="type" type="String" />
+ <param index="1" name="sdp" type="String" />
<description>
Sets the SDP description of the local peer. This should be called in response to [signal session_description_created].
After calling this function the peer will start emitting [signal ice_candidate_created] (unless an [enum Error] different from [constant OK] is returned).
@@ -113,8 +113,8 @@
</method>
<method name="set_remote_description">
<return type="int" enum="Error" />
- <argument index="0" name="type" type="String" />
- <argument index="1" name="sdp" type="String" />
+ <param index="0" name="type" type="String" />
+ <param index="1" name="sdp" type="String" />
<description>
Sets the SDP description of the remote peer. This should be called with the values generated by a remote peer and received over the signaling server.
If [code]type[/code] is [code]offer[/code] the peer will emit [signal session_description_created] with the appropriate answer.
@@ -124,23 +124,23 @@
</methods>
<signals>
<signal name="data_channel_received">
- <argument index="0" name="channel" type="WebRTCDataChannel" />
+ <param index="0" name="channel" type="WebRTCDataChannel" />
<description>
Emitted when a new in-band channel is received, i.e. when the channel was created with [code]negotiated: false[/code] (default).
The object will be an instance of [WebRTCDataChannel]. You must keep a reference of it or it will be closed automatically. See [method create_data_channel].
</description>
</signal>
<signal name="ice_candidate_created">
- <argument index="0" name="media" type="String" />
- <argument index="1" name="index" type="int" />
- <argument index="2" name="name" type="String" />
+ <param index="0" name="media" type="String" />
+ <param index="1" name="index" type="int" />
+ <param index="2" name="name" type="String" />
<description>
Emitted when a new ICE candidate has been created. The three parameters are meant to be passed to the remote peer over the signaling server.
</description>
</signal>
<signal name="session_description_created">
- <argument index="0" name="type" type="String" />
- <argument index="1" name="sdp" type="String" />
+ <param index="0" name="type" type="String" />
+ <param index="1" name="sdp" type="String" />
<description>
Emitted after a successful call to [method create_offer] or [method set_remote_description] (when it generates an answer). The parameters are meant to be passed to [method set_local_description] on this object, and sent to the remote peer over the signaling server.
</description>
diff --git a/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml b/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml
index 163d939ac1..e22e939a66 100644
--- a/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml
+++ b/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml
@@ -9,9 +9,9 @@
<methods>
<method name="_add_ice_candidate" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="p_sdp_mid_name" type="String" />
- <argument index="1" name="p_sdp_mline_index" type="int" />
- <argument index="2" name="p_sdp_name" type="String" />
+ <param index="0" name="p_sdp_mid_name" type="String" />
+ <param index="1" name="p_sdp_mline_index" type="int" />
+ <param index="2" name="p_sdp_name" type="String" />
<description>
</description>
</method>
@@ -22,8 +22,8 @@
</method>
<method name="_create_data_channel" qualifiers="virtual">
<return type="Object" />
- <argument index="0" name="p_label" type="String" />
- <argument index="1" name="p_config" type="Dictionary" />
+ <param index="0" name="p_label" type="String" />
+ <param index="1" name="p_config" type="Dictionary" />
<description>
</description>
</method>
@@ -39,7 +39,7 @@
</method>
<method name="_initialize" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="p_config" type="Dictionary" />
+ <param index="0" name="p_config" type="Dictionary" />
<description>
</description>
</method>
@@ -50,15 +50,15 @@
</method>
<method name="_set_local_description" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="p_type" type="String" />
- <argument index="1" name="p_sdp" type="String" />
+ <param index="0" name="p_type" type="String" />
+ <param index="1" name="p_sdp" type="String" />
<description>
</description>
</method>
<method name="_set_remote_description" qualifiers="virtual">
<return type="int" />
- <argument index="0" name="p_type" type="String" />
- <argument index="1" name="p_sdp" type="String" />
+ <param index="0" name="p_type" type="String" />
+ <param index="1" name="p_sdp" type="String" />
<description>
</description>
</method>
diff --git a/modules/webrtc/webrtc_data_channel_js.cpp b/modules/webrtc/webrtc_data_channel_js.cpp
index 0fb074b0c2..232f6998d3 100644
--- a/modules/webrtc/webrtc_data_channel_js.cpp
+++ b/modules/webrtc/webrtc_data_channel_js.cpp
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
#include "webrtc_data_channel_js.h"
diff --git a/modules/webrtc/webrtc_data_channel_js.h b/modules/webrtc/webrtc_data_channel_js.h
index d059ec31ed..0caa76885a 100644
--- a/modules/webrtc/webrtc_data_channel_js.h
+++ b/modules/webrtc/webrtc_data_channel_js.h
@@ -31,7 +31,7 @@
#ifndef WEBRTC_DATA_CHANNEL_JS_H
#define WEBRTC_DATA_CHANNEL_JS_H
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
#include "webrtc_data_channel.h"
@@ -89,6 +89,6 @@ public:
~WebRTCDataChannelJS();
};
-#endif // JAVASCRIPT_ENABLED
+#endif // WEB_ENABLED
#endif // WEBRTC_DATA_CHANNEL_JS_H
diff --git a/modules/webrtc/webrtc_peer_connection.cpp b/modules/webrtc/webrtc_peer_connection.cpp
index 75716017d7..d885b9262b 100644
--- a/modules/webrtc/webrtc_peer_connection.cpp
+++ b/modules/webrtc/webrtc_peer_connection.cpp
@@ -30,7 +30,7 @@
#include "webrtc_peer_connection.h"
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
#include "webrtc_peer_connection_js.h"
#endif
@@ -44,7 +44,7 @@ void WebRTCPeerConnection::set_default_extension(const StringName &p_extension)
}
WebRTCPeerConnection *WebRTCPeerConnection::create() {
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
return memnew(WebRTCPeerConnectionJS);
#else
if (default_extension == String()) {
diff --git a/modules/webrtc/webrtc_peer_connection_js.cpp b/modules/webrtc/webrtc_peer_connection_js.cpp
index ee3a302fa2..f48705253b 100644
--- a/modules/webrtc/webrtc_peer_connection_js.cpp
+++ b/modules/webrtc/webrtc_peer_connection_js.cpp
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
#include "webrtc_peer_connection_js.h"
diff --git a/modules/webrtc/webrtc_peer_connection_js.h b/modules/webrtc/webrtc_peer_connection_js.h
index 76b8c7fff8..50266129e4 100644
--- a/modules/webrtc/webrtc_peer_connection_js.h
+++ b/modules/webrtc/webrtc_peer_connection_js.h
@@ -31,7 +31,7 @@
#ifndef WEBRTC_PEER_CONNECTION_JS_H
#define WEBRTC_PEER_CONNECTION_JS_H
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
#include "webrtc_peer_connection.h"
diff --git a/modules/websocket/SCsub b/modules/websocket/SCsub
index dc0661995f..890fb71592 100644
--- a/modules/websocket/SCsub
+++ b/modules/websocket/SCsub
@@ -7,7 +7,7 @@ env_ws = env_modules.Clone()
thirdparty_obj = []
-if env["platform"] == "javascript":
+if env["platform"] == "web":
# Our JavaScript/C++ interface.
env.AddJSLibraries(["library_godot_websocket.js"])
diff --git a/modules/websocket/doc_classes/WebSocketClient.xml b/modules/websocket/doc_classes/WebSocketClient.xml
index ad2acf8a21..7d73194ea9 100644
--- a/modules/websocket/doc_classes/WebSocketClient.xml
+++ b/modules/websocket/doc_classes/WebSocketClient.xml
@@ -15,23 +15,23 @@
<methods>
<method name="connect_to_url">
<return type="int" enum="Error" />
- <argument index="0" name="url" type="String" />
- <argument index="1" name="protocols" type="PackedStringArray" default="PackedStringArray()" />
- <argument index="2" name="gd_mp_api" type="bool" default="false" />
- <argument index="3" name="custom_headers" type="PackedStringArray" default="PackedStringArray()" />
+ <param index="0" name="url" type="String" />
+ <param index="1" name="protocols" type="PackedStringArray" default="PackedStringArray()" />
+ <param index="2" name="gd_mp_api" type="bool" default="false" />
+ <param index="3" name="custom_headers" type="PackedStringArray" default="PackedStringArray()" />
<description>
Connects to the given URL requesting one of the given [code]protocols[/code] as sub-protocol. If the list empty (default), no sub-protocol will be requested.
If [code]true[/code] is passed as [code]gd_mp_api[/code], the client will behave like a multiplayer peer for the [MultiplayerAPI], connections to non-Godot servers will not work, and [signal data_received] will not be emitted.
If [code]false[/code] is passed instead (default), you must call [PacketPeer] functions ([code]put_packet[/code], [code]get_packet[/code], etc.) on the [WebSocketPeer] returned via [code]get_peer(1)[/code] and not on this object directly (e.g. [code]get_peer(1).put_packet(data)[/code]).
You can optionally pass a list of [code]custom_headers[/code] to be added to the handshake HTTP request.
- [b]Note:[/b] To avoid mixed content warnings or errors in HTML5, you may have to use a [code]url[/code] that starts with [code]wss://[/code] (secure) instead of [code]ws://[/code]. When doing so, make sure to use the fully qualified domain name that matches the one defined in the server's SSL certificate. Do not connect directly via the IP address for [code]wss://[/code] connections, as it won't match with the SSL certificate.
- [b]Note:[/b] Specifying [code]custom_headers[/code] is not supported in HTML5 exports due to browsers restrictions.
+ [b]Note:[/b] To avoid mixed content warnings or errors in Web, you may have to use a [code]url[/code] that starts with [code]wss://[/code] (secure) instead of [code]ws://[/code]. When doing so, make sure to use the fully qualified domain name that matches the one defined in the server's SSL certificate. Do not connect directly via the IP address for [code]wss://[/code] connections, as it won't match with the SSL certificate.
+ [b]Note:[/b] Specifying [code]custom_headers[/code] is not supported in Web exports due to browsers restrictions.
</description>
</method>
<method name="disconnect_from_host">
<return type="void" />
- <argument index="0" name="code" type="int" default="1000" />
- <argument index="1" name="reason" type="String" default="&quot;&quot;" />
+ <param index="0" name="code" type="int" default="1000" />
+ <param index="1" name="reason" type="String" default="&quot;&quot;" />
<description>
Disconnects this client from the connected host. See [method WebSocketPeer.close] for more information.
</description>
@@ -52,7 +52,7 @@
<members>
<member name="trusted_ssl_certificate" type="X509Certificate" setter="set_trusted_ssl_certificate" getter="get_trusted_ssl_certificate">
If specified, this [X509Certificate] will be the only one accepted when connecting to an SSL host. Any other certificate provided by the server will be regarded as invalid.
- [b]Note:[/b] Specifying a custom [code]trusted_ssl_certificate[/code] is not supported in HTML5 exports due to browsers restrictions.
+ [b]Note:[/b] Specifying a custom [code]trusted_ssl_certificate[/code] is not supported in Web exports due to browsers restrictions.
</member>
<member name="verify_ssl" type="bool" setter="set_verify_ssl_enabled" getter="is_verify_ssl_enabled">
If [code]true[/code], SSL certificate verification is enabled.
@@ -61,7 +61,7 @@
</members>
<signals>
<signal name="connection_closed">
- <argument index="0" name="was_clean_close" type="bool" />
+ <param index="0" name="was_clean_close" type="bool" />
<description>
Emitted when the connection to the server is closed. [code]was_clean_close[/code] will be [code]true[/code] if the connection was shutdown cleanly.
</description>
@@ -72,7 +72,7 @@
</description>
</signal>
<signal name="connection_established">
- <argument index="0" name="protocol" type="String" />
+ <param index="0" name="protocol" type="String" />
<description>
Emitted when a connection with the server is established, [code]protocol[/code] will contain the sub-protocol agreed with the server.
</description>
@@ -84,8 +84,8 @@
</description>
</signal>
<signal name="server_close_request">
- <argument index="0" name="code" type="int" />
- <argument index="1" name="reason" type="String" />
+ <param index="0" name="code" type="int" />
+ <param index="1" name="reason" type="String" />
<description>
Emitted when the server requests a clean close. You should keep polling until you get a [signal connection_closed] signal to achieve the clean close. See [method WebSocketPeer.close] for more details.
</description>
diff --git a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
index 4a617f4c82..4cc4d515e7 100644
--- a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
+++ b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
@@ -12,28 +12,28 @@
<methods>
<method name="get_peer" qualifiers="const">
<return type="WebSocketPeer" />
- <argument index="0" name="peer_id" type="int" />
+ <param index="0" name="peer_id" type="int" />
<description>
Returns the [WebSocketPeer] associated to the given [code]peer_id[/code].
</description>
</method>
<method name="set_buffers">
<return type="int" enum="Error" />
- <argument index="0" name="input_buffer_size_kb" type="int" />
- <argument index="1" name="input_max_packets" type="int" />
- <argument index="2" name="output_buffer_size_kb" type="int" />
- <argument index="3" name="output_max_packets" type="int" />
+ <param index="0" name="input_buffer_size_kb" type="int" />
+ <param index="1" name="input_max_packets" type="int" />
+ <param index="2" name="output_buffer_size_kb" type="int" />
+ <param index="3" name="output_max_packets" type="int" />
<description>
Configures the buffer sizes for this WebSocket peer. Default values can be specified in the Project Settings under [code]network/limits[/code]. For server, values are meant per connected peer.
The first two parameters define the size and queued packets limits of the input buffer, the last two of the output buffer.
Buffer sizes are expressed in KiB, so [code]4 = 2^12 = 4096 bytes[/code]. All parameters will be rounded up to the nearest power of two.
- [b]Note:[/b] HTML5 exports only use the input buffer since the output one is managed by browsers.
+ [b]Note:[/b] Web exports only use the input buffer since the output one is managed by browsers.
</description>
</method>
</methods>
<signals>
<signal name="peer_packet">
- <argument index="0" name="peer_source" type="int" />
+ <param index="0" name="peer_source" type="int" />
<description>
Emitted when a packet is received from a peer.
[b]Note:[/b] This signal is only emitted when the client or server is configured to use Godot multiplayer API.
diff --git a/modules/websocket/doc_classes/WebSocketPeer.xml b/modules/websocket/doc_classes/WebSocketPeer.xml
index 6466654517..627b9c607c 100644
--- a/modules/websocket/doc_classes/WebSocketPeer.xml
+++ b/modules/websocket/doc_classes/WebSocketPeer.xml
@@ -12,32 +12,32 @@
<methods>
<method name="close">
<return type="void" />
- <argument index="0" name="code" type="int" default="1000" />
- <argument index="1" name="reason" type="String" default="&quot;&quot;" />
+ <param index="0" name="code" type="int" default="1000" />
+ <param index="1" name="reason" type="String" default="&quot;&quot;" />
<description>
Closes this WebSocket connection. [code]code[/code] is the status code for the closure (see RFC 6455 section 7.4 for a list of valid status codes). [code]reason[/code] is the human readable reason for closing the connection (can be any UTF-8 string that's smaller than 123 bytes).
[b]Note:[/b] To achieve a clean close, you will need to keep polling until either [signal WebSocketClient.connection_closed] or [signal WebSocketServer.client_disconnected] is received.
- [b]Note:[/b] The HTML5 export might not support all status codes. Please refer to browser-specific documentation for more details.
+ [b]Note:[/b] The Web export might not support all status codes. Please refer to browser-specific documentation for more details.
</description>
</method>
<method name="get_connected_host" qualifiers="const">
<return type="String" />
<description>
Returns the IP address of the connected peer.
- [b]Note:[/b] Not available in the HTML5 export.
+ [b]Note:[/b] Not available in the Web export.
</description>
</method>
<method name="get_connected_port" qualifiers="const">
<return type="int" />
<description>
Returns the remote port of the connected peer.
- [b]Note:[/b] Not available in the HTML5 export.
+ [b]Note:[/b] Not available in the Web export.
</description>
</method>
<method name="get_current_outbound_buffered_amount" qualifiers="const">
<return type="int" />
<description>
- Returns the current amount of data in the outbound websocket buffer. [b]Note:[/b] HTML5 exports use WebSocket.bufferedAmount, while other platforms use an internal buffer.
+ Returns the current amount of data in the outbound websocket buffer. [b]Note:[/b] Web exports use WebSocket.bufferedAmount, while other platforms use an internal buffer.
</description>
</method>
<method name="get_write_mode" qualifiers="const">
@@ -54,15 +54,15 @@
</method>
<method name="set_no_delay">
<return type="void" />
- <argument index="0" name="enabled" type="bool" />
+ <param index="0" name="enabled" type="bool" />
<description>
Disable Nagle's algorithm on the underling TCP socket (default). See [method StreamPeerTCP.set_no_delay] for more information.
- [b]Note:[/b] Not available in the HTML5 export.
+ [b]Note:[/b] Not available in the Web export.
</description>
</method>
<method name="set_write_mode">
<return type="void" />
- <argument index="0" name="mode" type="int" enum="WebSocketPeer.WriteMode" />
+ <param index="0" name="mode" type="int" enum="WebSocketPeer.WriteMode" />
<description>
Sets the socket to use the given [enum WriteMode].
</description>
diff --git a/modules/websocket/doc_classes/WebSocketServer.xml b/modules/websocket/doc_classes/WebSocketServer.xml
index 46b0274de3..19c36700e6 100644
--- a/modules/websocket/doc_classes/WebSocketServer.xml
+++ b/modules/websocket/doc_classes/WebSocketServer.xml
@@ -6,7 +6,7 @@
<description>
This class implements a WebSocket server that can also support the high-level multiplayer API.
After starting the server ([method listen]), you will need to [method MultiplayerPeer.poll] it at regular intervals (e.g. inside [method Node._process]). When clients connect, disconnect, or send data, you will receive the appropriate signal.
- [b]Note:[/b] Not available in HTML5 exports.
+ [b]Note:[/b] Not available in Web exports.
[b]Note:[/b] When exporting to Android, make sure to enable the [code]INTERNET[/code] permission in the Android export preset before exporting the project or using one-click deploy. Otherwise, network communication of any kind will be blocked by Android.
</description>
<tutorials>
@@ -14,30 +14,30 @@
<methods>
<method name="disconnect_peer">
<return type="void" />
- <argument index="0" name="id" type="int" />
- <argument index="1" name="code" type="int" default="1000" />
- <argument index="2" name="reason" type="String" default="&quot;&quot;" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="code" type="int" default="1000" />
+ <param index="2" name="reason" type="String" default="&quot;&quot;" />
<description>
Disconnects the peer identified by [code]id[/code] from the server. See [method WebSocketPeer.close] for more information.
</description>
</method>
<method name="get_peer_address" qualifiers="const">
<return type="String" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Returns the IP address of the given peer.
</description>
</method>
<method name="get_peer_port" qualifiers="const">
<return type="int" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Returns the remote port of the given peer.
</description>
</method>
<method name="has_peer" qualifiers="const">
<return type="bool" />
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Returns [code]true[/code] if a peer with the given ID is connected.
</description>
@@ -50,9 +50,9 @@
</method>
<method name="listen">
<return type="int" enum="Error" />
- <argument index="0" name="port" type="int" />
- <argument index="1" name="protocols" type="PackedStringArray" default="PackedStringArray()" />
- <argument index="2" name="gd_mp_api" type="bool" default="false" />
+ <param index="0" name="port" type="int" />
+ <param index="1" name="protocols" type="PackedStringArray" default="PackedStringArray()" />
+ <param index="2" name="gd_mp_api" type="bool" default="false" />
<description>
Starts listening on the given port.
You can specify the desired subprotocols via the "protocols" array. If the list empty (default), no sub-protocol will be requested.
@@ -62,7 +62,7 @@
</method>
<method name="set_extra_headers">
<return type="void" />
- <argument index="0" name="headers" type="PackedStringArray" default="PackedStringArray()" />
+ <param index="0" name="headers" type="PackedStringArray" default="PackedStringArray()" />
<description>
Sets additional headers to be sent to clients during the HTTP handshake.
</description>
@@ -93,31 +93,31 @@
</members>
<signals>
<signal name="client_close_request">
- <argument index="0" name="id" type="int" />
- <argument index="1" name="code" type="int" />
- <argument index="2" name="reason" type="String" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="code" type="int" />
+ <param index="2" name="reason" type="String" />
<description>
Emitted when a client requests a clean close. You should keep polling until you get a [signal client_disconnected] signal with the same [code]id[/code] to achieve the clean close. See [method WebSocketPeer.close] for more details.
</description>
</signal>
<signal name="client_connected">
- <argument index="0" name="id" type="int" />
- <argument index="1" name="protocol" type="String" />
- <argument index="2" name="resource_name" type="String" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="protocol" type="String" />
+ <param index="2" name="resource_name" type="String" />
<description>
Emitted when a new client connects. "protocol" will be the sub-protocol agreed with the client, and "resource_name" will be the resource name of the URI the peer used.
"resource_name" is a path (at the very least a single forward slash) and potentially a query string.
</description>
</signal>
<signal name="client_disconnected">
- <argument index="0" name="id" type="int" />
- <argument index="1" name="was_clean_close" type="bool" />
+ <param index="0" name="id" type="int" />
+ <param index="1" name="was_clean_close" type="bool" />
<description>
Emitted when a client disconnects. [code]was_clean_close[/code] will be [code]true[/code] if the connection was shutdown cleanly.
</description>
</signal>
<signal name="data_received">
- <argument index="0" name="id" type="int" />
+ <param index="0" name="id" type="int" />
<description>
Emitted when a new message is received.
[b]Note:[/b] This signal is [i]not[/i] emitted when used as high-level multiplayer peer.
diff --git a/modules/websocket/emws_client.cpp b/modules/websocket/emws_client.cpp
index e051a3b564..65e0703c00 100644
--- a/modules/websocket/emws_client.cpp
+++ b/modules/websocket/emws_client.cpp
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
#include "emws_client.h"
@@ -82,12 +82,12 @@ Error EMWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
String str = "ws://";
if (p_custom_headers.size()) {
- WARN_PRINT_ONCE("Custom headers are not supported in HTML5 platform.");
+ WARN_PRINT_ONCE("Custom headers are not supported in Web platform.");
}
if (p_ssl) {
str = "wss://";
if (ssl_cert.is_valid()) {
- WARN_PRINT_ONCE("Custom SSL certificate is not supported in HTML5 platform.");
+ WARN_PRINT_ONCE("Custom SSL certificate is not supported in Web platform.");
}
}
str += p_host + ":" + itos(p_port) + p_path;
@@ -126,11 +126,11 @@ void EMWSClient::disconnect_from_host(int p_code, String p_reason) {
}
IPAddress EMWSClient::get_connected_host() const {
- ERR_FAIL_V_MSG(IPAddress(), "Not supported in HTML5 export.");
+ ERR_FAIL_V_MSG(IPAddress(), "Not supported in Web export.");
}
uint16_t EMWSClient::get_connected_port() const {
- ERR_FAIL_V_MSG(0, "Not supported in HTML5 export.");
+ ERR_FAIL_V_MSG(0, "Not supported in Web export.");
}
int EMWSClient::get_max_packet_size() const {
@@ -156,4 +156,4 @@ EMWSClient::~EMWSClient() {
}
}
-#endif // JAVASCRIPT_ENABLED
+#endif // WEB_ENABLED
diff --git a/modules/websocket/emws_client.h b/modules/websocket/emws_client.h
index b71fd78124..ff63a76753 100644
--- a/modules/websocket/emws_client.h
+++ b/modules/websocket/emws_client.h
@@ -31,7 +31,7 @@
#ifndef EMWS_CLIENT_H
#define EMWS_CLIENT_H
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
#include "core/error/error_list.h"
#include "emws_peer.h"
@@ -66,6 +66,6 @@ public:
~EMWSClient();
};
-#endif // JAVASCRIPT_ENABLED
+#endif // WEB_ENABLED
#endif // EMWS_CLIENT_H
diff --git a/modules/websocket/emws_peer.cpp b/modules/websocket/emws_peer.cpp
index 86169f88e9..859c92b457 100644
--- a/modules/websocket/emws_peer.cpp
+++ b/modules/websocket/emws_peer.cpp
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
#include "emws_peer.h"
@@ -110,15 +110,15 @@ void EMWSPeer::close(int p_code, String p_reason) {
}
IPAddress EMWSPeer::get_connected_host() const {
- ERR_FAIL_V_MSG(IPAddress(), "Not supported in HTML5 export.");
+ ERR_FAIL_V_MSG(IPAddress(), "Not supported in Web export.");
}
uint16_t EMWSPeer::get_connected_port() const {
- ERR_FAIL_V_MSG(0, "Not supported in HTML5 export.");
+ ERR_FAIL_V_MSG(0, "Not supported in Web export.");
}
void EMWSPeer::set_no_delay(bool p_enabled) {
- ERR_FAIL_MSG("'set_no_delay' is not supported in HTML5 export.");
+ ERR_FAIL_MSG("'set_no_delay' is not supported in Web export.");
}
EMWSPeer::EMWSPeer() {
@@ -129,4 +129,4 @@ EMWSPeer::~EMWSPeer() {
close();
}
-#endif // JAVASCRIPT_ENABLED
+#endif // WEB_ENABLED
diff --git a/modules/websocket/emws_peer.h b/modules/websocket/emws_peer.h
index f52f615c35..cdbc9212a5 100644
--- a/modules/websocket/emws_peer.h
+++ b/modules/websocket/emws_peer.h
@@ -31,7 +31,7 @@
#ifndef EMWS_PEER_H
#define EMWS_PEER_H
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
#include "core/error/error_list.h"
#include "core/io/packet_peer.h"
@@ -88,6 +88,6 @@ public:
~EMWSPeer();
};
-#endif // JAVASCRIPT_ENABLED
+#endif // WEB_ENABLED
#endif // EMWS_PEER_H
diff --git a/modules/websocket/register_types.cpp b/modules/websocket/register_types.cpp
index f562de111f..faa7021b2f 100644
--- a/modules/websocket/register_types.cpp
+++ b/modules/websocket/register_types.cpp
@@ -33,11 +33,13 @@
#include "core/config/project_settings.h"
#include "core/error/error_macros.h"
-#ifdef JAVASCRIPT_ENABLED
+#include "websocket_client.h"
+#include "websocket_server.h"
+
+#ifdef WEB_ENABLED
#include "emscripten.h"
#include "emws_client.h"
#include "emws_peer.h"
-#include "emws_server.h"
#else
#include "wsl_client.h"
#include "wsl_server.h"
@@ -57,10 +59,9 @@ static void _editor_init_callback() {
void initialize_websocket_module(ModuleInitializationLevel p_level) {
if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
EMWSPeer::make_default();
EMWSClient::make_default();
- EMWSServer::make_default();
#else
WSLPeer::make_default();
WSLClient::make_default();
diff --git a/modules/websocket/remote_debugger_peer_websocket.cpp b/modules/websocket/remote_debugger_peer_websocket.cpp
index 6319c3c664..f703873cbf 100644
--- a/modules/websocket/remote_debugger_peer_websocket.cpp
+++ b/modules/websocket/remote_debugger_peer_websocket.cpp
@@ -103,7 +103,7 @@ void RemoteDebuggerPeerWebSocket::close() {
}
bool RemoteDebuggerPeerWebSocket::can_block() const {
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
return false;
#else
return true;
@@ -111,7 +111,7 @@ bool RemoteDebuggerPeerWebSocket::can_block() const {
}
RemoteDebuggerPeerWebSocket::RemoteDebuggerPeerWebSocket(Ref<WebSocketPeer> p_peer) {
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
ws_client = Ref<WebSocketClient>(memnew(EMWSClient));
#else
ws_client = Ref<WebSocketClient>(memnew(WSLClient));
diff --git a/modules/websocket/remote_debugger_peer_websocket.h b/modules/websocket/remote_debugger_peer_websocket.h
index 3227065ded..a37a789cbe 100644
--- a/modules/websocket/remote_debugger_peer_websocket.h
+++ b/modules/websocket/remote_debugger_peer_websocket.h
@@ -33,7 +33,7 @@
#include "core/debugger/remote_debugger_peer.h"
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
#include "emws_client.h"
#else
#include "wsl_client.h"
diff --git a/modules/websocket/wsl_client.cpp b/modules/websocket/wsl_client.cpp
index 478dbb9d47..2bb57226ea 100644
--- a/modules/websocket/wsl_client.cpp
+++ b/modules/websocket/wsl_client.cpp
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef JAVASCRIPT_ENABLED
+#ifndef WEB_ENABLED
#include "wsl_client.h"
#include "core/config/project_settings.h"
@@ -404,4 +404,4 @@ WSLClient::~WSLClient() {
disconnect_from_host();
}
-#endif // JAVASCRIPT_ENABLED
+#endif // WEB_ENABLED
diff --git a/modules/websocket/wsl_client.h b/modules/websocket/wsl_client.h
index 58b867fbe4..5d90bc4034 100644
--- a/modules/websocket/wsl_client.h
+++ b/modules/websocket/wsl_client.h
@@ -31,7 +31,7 @@
#ifndef WSL_CLIENT_H
#define WSL_CLIENT_H
-#ifndef JAVASCRIPT_ENABLED
+#ifndef WEB_ENABLED
#include "core/error/error_list.h"
#include "core/io/stream_peer_ssl.h"
@@ -86,6 +86,6 @@ public:
~WSLClient();
};
-#endif // JAVASCRIPT_ENABLED
+#endif // WEB_ENABLED
#endif // WSL_CLIENT_H
diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp
index 15df4d039c..97bd87a526 100644
--- a/modules/websocket/wsl_peer.cpp
+++ b/modules/websocket/wsl_peer.cpp
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef JAVASCRIPT_ENABLED
+#ifndef WEB_ENABLED
#include "wsl_peer.h"
@@ -348,4 +348,4 @@ WSLPeer::~WSLPeer() {
_data = nullptr;
}
-#endif // JAVASCRIPT_ENABLED
+#endif // WEB_ENABLED
diff --git a/modules/websocket/wsl_peer.h b/modules/websocket/wsl_peer.h
index aabd3fd43e..92672eb2c4 100644
--- a/modules/websocket/wsl_peer.h
+++ b/modules/websocket/wsl_peer.h
@@ -31,7 +31,7 @@
#ifndef WSL_PEER_H
#define WSL_PEER_H
-#ifndef JAVASCRIPT_ENABLED
+#ifndef WEB_ENABLED
#include "core/error/error_list.h"
#include "core/io/packet_peer.h"
@@ -110,6 +110,6 @@ public:
~WSLPeer();
};
-#endif // JAVASCRIPT_ENABLED
+#endif // WEB_ENABLED
#endif // WSL_PEER_H
diff --git a/modules/websocket/wsl_server.cpp b/modules/websocket/wsl_server.cpp
index 517b9643f8..7457ac7087 100644
--- a/modules/websocket/wsl_server.cpp
+++ b/modules/websocket/wsl_server.cpp
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef JAVASCRIPT_ENABLED
+#ifndef WEB_ENABLED
#include "wsl_server.h"
#include "core/config/project_settings.h"
@@ -326,4 +326,4 @@ WSLServer::~WSLServer() {
stop();
}
-#endif // JAVASCRIPT_ENABLED
+#endif // WEB_ENABLED
diff --git a/modules/websocket/wsl_server.h b/modules/websocket/wsl_server.h
index ec7567c732..b0b7a6a5c9 100644
--- a/modules/websocket/wsl_server.h
+++ b/modules/websocket/wsl_server.h
@@ -31,7 +31,7 @@
#ifndef WSL_SERVER_H
#define WSL_SERVER_H
-#ifndef JAVASCRIPT_ENABLED
+#ifndef WEB_ENABLED
#include "websocket_server.h"
#include "wsl_peer.h"
@@ -93,6 +93,6 @@ public:
~WSLServer();
};
-#endif // JAVASCRIPT_ENABLED
+#endif // WEB_ENABLED
#endif // WSL_SERVER_H
diff --git a/modules/webxr/SCsub b/modules/webxr/SCsub
index 0a96af0811..81caa4a279 100644
--- a/modules/webxr/SCsub
+++ b/modules/webxr/SCsub
@@ -3,7 +3,7 @@
Import("env")
Import("env_modules")
-if env["platform"] == "javascript":
+if env["platform"] == "web":
env.AddJSLibraries(["native/library_godot_webxr.js"])
env.AddJSExterns(["native/webxr.externs.js"])
diff --git a/modules/webxr/doc_classes/WebXRInterface.xml b/modules/webxr/doc_classes/WebXRInterface.xml
index 48447eb074..49ff454f07 100644
--- a/modules/webxr/doc_classes/WebXRInterface.xml
+++ b/modules/webxr/doc_classes/WebXRInterface.xml
@@ -5,9 +5,9 @@
</brief_description>
<description>
WebXR is an open standard that allows creating VR and AR applications that run in the web browser.
- As such, this interface is only available when running in an HTML5 export.
+ As such, this interface is only available when running in Web exports.
WebXR supports a wide range of devices, from the very capable (like Valve Index, HTC Vive, Oculus Rift and Quest) down to the much less capable (like Google Cardboard, Oculus Go, GearVR, or plain smartphones).
- Since WebXR is based on Javascript, it makes extensive use of callbacks, which means that [WebXRInterface] is forced to use signals, where other AR/VR interfaces would instead use functions that return a result immediately. This makes [WebXRInterface] quite a bit more complicated to initialize than other AR/VR interfaces.
+ Since WebXR is based on JavaScript, it makes extensive use of callbacks, which means that [WebXRInterface] is forced to use signals, where other AR/VR interfaces would instead use functions that return a result immediately. This makes [WebXRInterface] quite a bit more complicated to initialize than other AR/VR interfaces.
Here's the minimum code required to start an immersive VR session:
[codeblock]
extends Node3D
@@ -96,7 +96,7 @@
<methods>
<method name="get_controller" qualifiers="const">
<return type="XRPositionalTracker" />
- <argument index="0" name="controller_id" type="int" />
+ <param index="0" name="controller_id" type="int" />
<description>
Gets an [XRPositionalTracker] for the given [code]controller_id[/code].
In the context of WebXR, a "controller" can be an advanced VR controller like the Oculus Touch or Index controllers, or even a tap on the screen, a spoken voice command or a button press on the device itself. When a non-traditional controller is used, interpret the position and orientation of the [XRPositionalTracker] as a ray pointing at the object the user wishes to interact with.
@@ -111,7 +111,7 @@
</method>
<method name="is_session_supported">
<return type="void" />
- <argument index="0" name="session_mode" type="String" />
+ <param index="0" name="session_mode" type="String" />
<description>
Checks if the given [code]session_mode[/code] is supported by the user's browser.
Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRSessionMode]WebXR's XRSessionMode[/url], including: [code]"immersive-vr"[/code], [code]"immersive-ar"[/code], and [code]"inline"[/code].
@@ -166,21 +166,21 @@
</description>
</signal>
<signal name="select">
- <argument index="0" name="controller_id" type="int" />
+ <param index="0" name="controller_id" type="int" />
<description>
Emitted after one of the "controllers" has finished its "primary action".
Use [method get_controller] to get more information about the controller.
</description>
</signal>
<signal name="selectend">
- <argument index="0" name="controller_id" type="int" />
+ <param index="0" name="controller_id" type="int" />
<description>
Emitted when one of the "controllers" has finished its "primary action".
Use [method get_controller] to get more information about the controller.
</description>
</signal>
<signal name="selectstart">
- <argument index="0" name="controller_id" type="int" />
+ <param index="0" name="controller_id" type="int" />
<description>
Emitted when one of the "controllers" has started its "primary action".
Use [method get_controller] to get more information about the controller.
@@ -193,7 +193,7 @@
</description>
</signal>
<signal name="session_failed">
- <argument index="0" name="message" type="String" />
+ <param index="0" name="message" type="String" />
<description>
Emitted by [method XRInterface.initialize] if the session fails to start.
[code]message[/code] may optionally contain an error message from WebXR, or an empty string if no message is available.
@@ -206,28 +206,28 @@
</description>
</signal>
<signal name="session_supported">
- <argument index="0" name="session_mode" type="String" />
- <argument index="1" name="supported" type="bool" />
+ <param index="0" name="session_mode" type="String" />
+ <param index="1" name="supported" type="bool" />
<description>
Emitted by [method is_session_supported] to indicate if the given [code]session_mode[/code] is supported or not.
</description>
</signal>
<signal name="squeeze">
- <argument index="0" name="controller_id" type="int" />
+ <param index="0" name="controller_id" type="int" />
<description>
Emitted after one of the "controllers" has finished its "primary squeeze action".
Use [method get_controller] to get more information about the controller.
</description>
</signal>
<signal name="squeezeend">
- <argument index="0" name="controller_id" type="int" />
+ <param index="0" name="controller_id" type="int" />
<description>
Emitted when one of the "controllers" has finished its "primary squeeze action".
Use [method get_controller] to get more information about the controller.
</description>
</signal>
<signal name="squeezestart">
- <argument index="0" name="controller_id" type="int" />
+ <param index="0" name="controller_id" type="int" />
<description>
Emitted when one of the "controllers" has started its "primary squeeze action".
Use [method get_controller] to get more information about the controller.
diff --git a/modules/webxr/register_types.cpp b/modules/webxr/register_types.cpp
index cd403a4996..f4959c482f 100644
--- a/modules/webxr/register_types.cpp
+++ b/modules/webxr/register_types.cpp
@@ -33,7 +33,7 @@
#include "webxr_interface.h"
#include "webxr_interface_js.h"
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
Ref<WebXRInterfaceJS> webxr;
#endif
@@ -44,7 +44,7 @@ void initialize_webxr_module(ModuleInitializationLevel p_level) {
GDREGISTER_ABSTRACT_CLASS(WebXRInterface);
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
webxr.instantiate();
XRServer::get_singleton()->add_interface(webxr);
#endif
@@ -55,7 +55,7 @@ void uninitialize_webxr_module(ModuleInitializationLevel p_level) {
return;
}
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
if (webxr.is_valid()) {
// uninitialise our interface if it is initialised
if (webxr->is_initialized()) {
diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp
index 07e6760555..7d97dbfa0b 100644
--- a/modules/webxr/webxr_interface_js.cpp
+++ b/modules/webxr/webxr_interface_js.cpp
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
#include "webxr_interface_js.h"
@@ -518,4 +518,4 @@ WebXRInterfaceJS::~WebXRInterfaceJS() {
};
};
-#endif // JAVASCRIPT_ENABLED
+#endif // WEB_ENABLED
diff --git a/modules/webxr/webxr_interface_js.h b/modules/webxr/webxr_interface_js.h
index f1ffedba46..dbe89dad83 100644
--- a/modules/webxr/webxr_interface_js.h
+++ b/modules/webxr/webxr_interface_js.h
@@ -31,7 +31,7 @@
#ifndef WEBXR_INTERFACE_JS_H
#define WEBXR_INTERFACE_JS_H
-#ifdef JAVASCRIPT_ENABLED
+#ifdef WEB_ENABLED
#include "webxr_interface.h"
@@ -98,6 +98,6 @@ public:
~WebXRInterfaceJS();
};
-#endif // JAVASCRIPT_ENABLED
+#endif // WEB_ENABLED
#endif // WEBXR_INTERFACE_JS_H
diff --git a/platform/android/README.md b/platform/android/README.md
index 343e588553..f6aabab708 100644
--- a/platform/android/README.md
+++ b/platform/android/README.md
@@ -3,6 +3,13 @@
This folder contains the Java and C++ (JNI) code for the Android platform port,
using [Gradle](https://gradle.org/) as a build system.
+## Documentation
+
+- [Compiling for Android](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_android.html)
+ - Instructions on building this platform port from source.
+- [Exporting for Android](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_android.html)
+ - Instructions on using the compiled export templates to export a project.
+
## Artwork license
[`logo.png`](logo.png) and [`run_icon.png`](run_icon.png) are licensed under
diff --git a/platform/android/SCsub b/platform/android/SCsub
index d370a4d18d..344ca036de 100644
--- a/platform/android/SCsub
+++ b/platform/android/SCsub
@@ -41,13 +41,13 @@ lib = env_android.add_shared_library("#bin/libgodot", [android_objects], SHLIBSU
env.Depends(lib, thirdparty_obj)
lib_arch_dir = ""
-if env["android_arch"] == "armv7":
+if env["arch"] == "arm32":
lib_arch_dir = "armeabi-v7a"
-elif env["android_arch"] == "arm64v8":
+elif env["arch"] == "arm64":
lib_arch_dir = "arm64-v8a"
-elif env["android_arch"] == "x86":
+elif env["arch"] == "x86_32":
lib_arch_dir = "x86"
-elif env["android_arch"] == "x86_64":
+elif env["arch"] == "x86_64":
lib_arch_dir = "x86_64"
else:
print("WARN: Architecture not suitable for embedding into APK; keeping .so at \\bin")
diff --git a/platform/android/android_input_handler.cpp b/platform/android/android_input_handler.cpp
index 81802298d9..6427346365 100644
--- a/platform/android/android_input_handler.cpp
+++ b/platform/android/android_input_handler.cpp
@@ -56,10 +56,10 @@ void AndroidInputHandler::_set_key_modifier_state(Ref<InputEventWithModifiers> e
ev->set_ctrl_pressed(control_mem);
}
-void AndroidInputHandler::process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed) {
+void AndroidInputHandler::process_key_event(int p_keycode, int p_physical_keycode, int p_unicode, bool p_pressed) {
static char32_t prev_wc = 0;
- char32_t unicode = p_unicode_char;
- if ((p_unicode_char & 0xfffffc00) == 0xd800) {
+ char32_t unicode = p_unicode;
+ if ((p_unicode & 0xfffffc00) == 0xd800) {
if (prev_wc != 0) {
ERR_PRINT("invalid utf16 surrogate input");
}
@@ -78,39 +78,38 @@ void AndroidInputHandler::process_key_event(int p_keycode, int p_scancode, int p
Ref<InputEventKey> ev;
ev.instantiate();
- int val = unicode;
- Key keycode = android_get_keysym(p_keycode);
- Key phy_keycode = android_get_keysym(p_scancode);
- if (keycode == Key::SHIFT) {
- shift_mem = p_pressed;
+ Key physical_keycode = godot_code_from_android_code(p_physical_keycode);
+ Key keycode = physical_keycode;
+ if (p_keycode != 0) {
+ keycode = godot_code_from_unicode(p_keycode);
}
- if (keycode == Key::ALT) {
- alt_mem = p_pressed;
- }
- if (keycode == Key::CTRL) {
- control_mem = p_pressed;
- }
- if (keycode == Key::META) {
- meta_mem = p_pressed;
+
+ switch (physical_keycode) {
+ case Key::SHIFT: {
+ shift_mem = p_pressed;
+ } break;
+ case Key::ALT: {
+ alt_mem = p_pressed;
+ } break;
+ case Key::CTRL: {
+ control_mem = p_pressed;
+ } break;
+ case Key::META: {
+ meta_mem = p_pressed;
+ } break;
+ default:
+ break;
}
ev->set_keycode(keycode);
- ev->set_physical_keycode(phy_keycode);
- ev->set_unicode(val);
+ ev->set_physical_keycode(physical_keycode);
+ ev->set_unicode(unicode);
ev->set_pressed(p_pressed);
_set_key_modifier_state(ev);
- if (val == '\n') {
- ev->set_keycode(Key::ENTER);
- } else if (val == 61448) {
- ev->set_keycode(Key::BACKSPACE);
- ev->set_unicode((char32_t)Key::BACKSPACE);
- } else if (val == 61453) {
- ev->set_keycode(Key::ENTER);
- ev->set_unicode((char32_t)Key::ENTER);
- } else if (p_keycode == 4) {
+ if (p_physical_keycode == AKEYCODE_BACK) {
if (DisplayServerAndroid *dsa = Object::cast_to<DisplayServerAndroid>(DisplayServer::get_singleton())) {
dsa->send_window_event(DisplayServer::WINDOW_EVENT_GO_BACK_REQUEST, true);
}
diff --git a/platform/android/android_input_handler.h b/platform/android/android_input_handler.h
index 1397ca59e4..6dfab7def8 100644
--- a/platform/android/android_input_handler.h
+++ b/platform/android/android_input_handler.h
@@ -83,7 +83,7 @@ public:
void process_mouse_event(int input_device, int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor = 0, float event_horizontal_factor = 0);
void process_double_tap(int event_android_button_mask, Point2 p_pos);
void process_joy_event(JoypadEvent p_event);
- void process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed);
+ void process_key_event(int p_keycode, int p_physical_keycode, int p_unicode, bool p_pressed);
};
#endif // ANDROID_INPUT_HANDLER_H
diff --git a/platform/android/android_keys_utils.cpp b/platform/android/android_keys_utils.cpp
index 885e4ff145..d2c5fdfd6c 100644
--- a/platform/android/android_keys_utils.cpp
+++ b/platform/android/android_keys_utils.cpp
@@ -30,12 +30,49 @@
#include "android_keys_utils.h"
-Key android_get_keysym(unsigned int p_code) {
- for (int i = 0; _ak_to_keycode[i].keysym != Key::UNKNOWN; i++) {
- if (_ak_to_keycode[i].keycode == p_code) {
- return _ak_to_keycode[i].keysym;
+Key godot_code_from_android_code(unsigned int p_code) {
+ for (int i = 0; android_godot_code_pairs[i].android_code != AKEYCODE_MAX; i++) {
+ if (android_godot_code_pairs[i].android_code == p_code) {
+ return android_godot_code_pairs[i].godot_code;
}
}
-
return Key::UNKNOWN;
}
+
+Key godot_code_from_unicode(unsigned int p_code) {
+ unsigned int code = p_code;
+ if (code > 0xFF) {
+ return Key::UNKNOWN;
+ }
+ // Known control codes.
+ if (code == '\b') { // 0x08
+ return Key::BACKSPACE;
+ }
+ if (code == '\t') { // 0x09
+ return Key::TAB;
+ }
+ if (code == '\n') { // 0x0A
+ return Key::ENTER;
+ }
+ if (code == 0x1B) {
+ return Key::ESCAPE;
+ }
+ if (code == 0x1F) {
+ return Key::KEY_DELETE;
+ }
+ // Unknown control codes.
+ if (code <= 0x1F || (code >= 0x80 && code <= 0x9F)) {
+ return Key::UNKNOWN;
+ }
+ // Convert to uppercase.
+ if (code >= 'a' && code <= 'z') { // 0x61 - 0x7A
+ code -= ('a' - 'A');
+ }
+ if (code >= u'à' && code <= u'ö') { // 0xE0 - 0xF6
+ code -= (u'à' - u'À'); // 0xE0 - 0xC0
+ }
+ if (code >= u'ø' && code <= u'þ') { // 0xF8 - 0xFF
+ code -= (u'ø' - u'Ø'); // 0xF8 - 0xD8
+ }
+ return Key(code);
+}
diff --git a/platform/android/android_keys_utils.h b/platform/android/android_keys_utils.h
index 24a6589fba..5ec3ee17aa 100644
--- a/platform/android/android_keys_utils.h
+++ b/platform/android/android_keys_utils.h
@@ -34,129 +34,140 @@
#include <android/input.h>
#include <core/os/keyboard.h>
-struct _WinTranslatePair {
- Key keysym = Key::NONE;
- unsigned int keycode = 0;
+#define AKEYCODE_MAX 0xFFFF
+
+struct AndroidGodotCodePair {
+ unsigned int android_code = 0;
+ Key godot_code = Key::NONE;
};
-static _WinTranslatePair _ak_to_keycode[] = {
- { Key::TAB, AKEYCODE_TAB },
- { Key::ENTER, AKEYCODE_ENTER },
- { Key::SHIFT, AKEYCODE_SHIFT_LEFT },
- { Key::SHIFT, AKEYCODE_SHIFT_RIGHT },
- { Key::ALT, AKEYCODE_ALT_LEFT },
- { Key::ALT, AKEYCODE_ALT_RIGHT },
- { Key::MENU, AKEYCODE_MENU },
- { Key::PAUSE, AKEYCODE_MEDIA_PLAY_PAUSE },
- { Key::ESCAPE, AKEYCODE_BACK },
- { Key::SPACE, AKEYCODE_SPACE },
- { Key::PAGEUP, AKEYCODE_PAGE_UP },
- { Key::PAGEDOWN, AKEYCODE_PAGE_DOWN },
- { Key::HOME, AKEYCODE_HOME }, //(0x24)
- { Key::LEFT, AKEYCODE_DPAD_LEFT },
- { Key::UP, AKEYCODE_DPAD_UP },
- { Key::RIGHT, AKEYCODE_DPAD_RIGHT },
- { Key::DOWN, AKEYCODE_DPAD_DOWN },
- { Key::PERIODCENTERED, AKEYCODE_DPAD_CENTER },
- { Key::BACKSPACE, AKEYCODE_DEL },
- { Key::KEY_0, AKEYCODE_0 },
- { Key::KEY_1, AKEYCODE_1 },
- { Key::KEY_2, AKEYCODE_2 },
- { Key::KEY_3, AKEYCODE_3 },
- { Key::KEY_4, AKEYCODE_4 },
- { Key::KEY_5, AKEYCODE_5 },
- { Key::KEY_6, AKEYCODE_6 },
- { Key::KEY_7, AKEYCODE_7 },
- { Key::KEY_8, AKEYCODE_8 },
- { Key::KEY_9, AKEYCODE_9 },
- { Key::A, AKEYCODE_A },
- { Key::B, AKEYCODE_B },
- { Key::C, AKEYCODE_C },
- { Key::D, AKEYCODE_D },
- { Key::E, AKEYCODE_E },
- { Key::F, AKEYCODE_F },
- { Key::G, AKEYCODE_G },
- { Key::H, AKEYCODE_H },
- { Key::I, AKEYCODE_I },
- { Key::J, AKEYCODE_J },
- { Key::K, AKEYCODE_K },
- { Key::L, AKEYCODE_L },
- { Key::M, AKEYCODE_M },
- { Key::N, AKEYCODE_N },
- { Key::O, AKEYCODE_O },
- { Key::P, AKEYCODE_P },
- { Key::Q, AKEYCODE_Q },
- { Key::R, AKEYCODE_R },
- { Key::S, AKEYCODE_S },
- { Key::T, AKEYCODE_T },
- { Key::U, AKEYCODE_U },
- { Key::V, AKEYCODE_V },
- { Key::W, AKEYCODE_W },
- { Key::X, AKEYCODE_X },
- { Key::Y, AKEYCODE_Y },
- { Key::Z, AKEYCODE_Z },
- { Key::HOMEPAGE, AKEYCODE_EXPLORER },
- { Key::LAUNCH0, AKEYCODE_BUTTON_A },
- { Key::LAUNCH1, AKEYCODE_BUTTON_B },
- { Key::LAUNCH2, AKEYCODE_BUTTON_C },
- { Key::LAUNCH3, AKEYCODE_BUTTON_X },
- { Key::LAUNCH4, AKEYCODE_BUTTON_Y },
- { Key::LAUNCH5, AKEYCODE_BUTTON_Z },
- { Key::LAUNCH6, AKEYCODE_BUTTON_L1 },
- { Key::LAUNCH7, AKEYCODE_BUTTON_R1 },
- { Key::LAUNCH8, AKEYCODE_BUTTON_L2 },
- { Key::LAUNCH9, AKEYCODE_BUTTON_R2 },
- { Key::LAUNCHA, AKEYCODE_BUTTON_THUMBL },
- { Key::LAUNCHB, AKEYCODE_BUTTON_THUMBR },
- { Key::LAUNCHC, AKEYCODE_BUTTON_START },
- { Key::LAUNCHD, AKEYCODE_BUTTON_SELECT },
- { Key::LAUNCHE, AKEYCODE_BUTTON_MODE },
- { Key::VOLUMEMUTE, AKEYCODE_MUTE },
- { Key::VOLUMEDOWN, AKEYCODE_VOLUME_DOWN },
- { Key::VOLUMEUP, AKEYCODE_VOLUME_UP },
- { Key::BACK, AKEYCODE_MEDIA_REWIND },
- { Key::FORWARD, AKEYCODE_MEDIA_FAST_FORWARD },
- { Key::MEDIANEXT, AKEYCODE_MEDIA_NEXT },
- { Key::MEDIAPREVIOUS, AKEYCODE_MEDIA_PREVIOUS },
- { Key::MEDIASTOP, AKEYCODE_MEDIA_STOP },
- { Key::PLUS, AKEYCODE_PLUS },
- { Key::EQUAL, AKEYCODE_EQUALS }, // the '+' key
- { Key::COMMA, AKEYCODE_COMMA }, // the ',' key
- { Key::MINUS, AKEYCODE_MINUS }, // the '-' key
- { Key::SLASH, AKEYCODE_SLASH }, // the '/?' key
- { Key::BACKSLASH, AKEYCODE_BACKSLASH },
- { Key::BRACKETLEFT, AKEYCODE_LEFT_BRACKET },
- { Key::BRACKETRIGHT, AKEYCODE_RIGHT_BRACKET },
- { Key::CTRL, AKEYCODE_CTRL_LEFT },
- { Key::CTRL, AKEYCODE_CTRL_RIGHT },
- { Key::UNKNOWN, 0 }
+static AndroidGodotCodePair android_godot_code_pairs[] = {
+ { AKEYCODE_UNKNOWN, Key::UNKNOWN }, // (0) Unknown key code.
+ { AKEYCODE_HOME, Key::HOME }, // (3) Home key.
+ { AKEYCODE_BACK, Key::BACK }, // (4) Back key.
+ { AKEYCODE_0, Key::KEY_0 }, // (7) '0' key.
+ { AKEYCODE_1, Key::KEY_1 }, // (8) '1' key.
+ { AKEYCODE_2, Key::KEY_2 }, // (9) '2' key.
+ { AKEYCODE_3, Key::KEY_3 }, // (10) '3' key.
+ { AKEYCODE_4, Key::KEY_4 }, // (11) '4' key.
+ { AKEYCODE_5, Key::KEY_5 }, // (12) '5' key.
+ { AKEYCODE_6, Key::KEY_6 }, // (13) '6' key.
+ { AKEYCODE_7, Key::KEY_7 }, // (14) '7' key.
+ { AKEYCODE_8, Key::KEY_8 }, // (15) '8' key.
+ { AKEYCODE_9, Key::KEY_9 }, // (16) '9' key.
+ { AKEYCODE_STAR, Key::ASTERISK }, // (17) '*' key.
+ { AKEYCODE_POUND, Key::NUMBERSIGN }, // (18) '#' key.
+ { AKEYCODE_DPAD_UP, Key::UP }, // (19) Directional Pad Up key.
+ { AKEYCODE_DPAD_DOWN, Key::DOWN }, // (20) Directional Pad Down key.
+ { AKEYCODE_DPAD_LEFT, Key::LEFT }, // (21) Directional Pad Left key.
+ { AKEYCODE_DPAD_RIGHT, Key::RIGHT }, // (22) Directional Pad Right key.
+ { AKEYCODE_VOLUME_UP, Key::VOLUMEUP }, // (24) Volume Up key.
+ { AKEYCODE_VOLUME_DOWN, Key::VOLUMEDOWN }, // (25) Volume Down key.
+ { AKEYCODE_CLEAR, Key::CLEAR }, // (28) Clear key.
+ { AKEYCODE_A, Key::A }, // (29) 'A' key.
+ { AKEYCODE_B, Key::B }, // (30) 'B' key.
+ { AKEYCODE_C, Key::C }, // (31) 'C' key.
+ { AKEYCODE_D, Key::D }, // (32) 'D' key.
+ { AKEYCODE_E, Key::E }, // (33) 'E' key.
+ { AKEYCODE_F, Key::F }, // (34) 'F' key.
+ { AKEYCODE_G, Key::G }, // (35) 'G' key.
+ { AKEYCODE_H, Key::H }, // (36) 'H' key.
+ { AKEYCODE_I, Key::I }, // (37) 'I' key.
+ { AKEYCODE_J, Key::J }, // (38) 'J' key.
+ { AKEYCODE_K, Key::K }, // (39) 'K' key.
+ { AKEYCODE_L, Key::L }, // (40) 'L' key.
+ { AKEYCODE_M, Key::M }, // (41) 'M' key.
+ { AKEYCODE_N, Key::N }, // (42) 'N' key.
+ { AKEYCODE_O, Key::O }, // (43) 'O' key.
+ { AKEYCODE_P, Key::P }, // (44) 'P' key.
+ { AKEYCODE_Q, Key::Q }, // (45) 'Q' key.
+ { AKEYCODE_R, Key::R }, // (46) 'R' key.
+ { AKEYCODE_S, Key::S }, // (47) 'S' key.
+ { AKEYCODE_T, Key::T }, // (48) 'T' key.
+ { AKEYCODE_U, Key::U }, // (49) 'U' key.
+ { AKEYCODE_V, Key::V }, // (50) 'V' key.
+ { AKEYCODE_W, Key::W }, // (51) 'W' key.
+ { AKEYCODE_X, Key::X }, // (52) 'X' key.
+ { AKEYCODE_Y, Key::Y }, // (53) 'Y' key.
+ { AKEYCODE_Z, Key::Z }, // (54) 'Z' key.
+ { AKEYCODE_COMMA, Key::COMMA }, // (55) ',’ key.
+ { AKEYCODE_PERIOD, Key::PERIOD }, // (56) '.' key.
+ { AKEYCODE_ALT_LEFT, Key::ALT }, // (57) Left Alt modifier key.
+ { AKEYCODE_ALT_RIGHT, Key::ALT }, // (58) Right Alt modifier key.
+ { AKEYCODE_SHIFT_LEFT, Key::SHIFT }, // (59) Left Shift modifier key.
+ { AKEYCODE_SHIFT_RIGHT, Key::SHIFT }, // (60) Right Shift modifier key.
+ { AKEYCODE_TAB, Key::TAB }, // (61) Tab key.
+ { AKEYCODE_SPACE, Key::SPACE }, // (62) Space key.
+ { AKEYCODE_ENTER, Key::ENTER }, // (66) Enter key.
+ { AKEYCODE_DEL, Key::BACKSPACE }, // (67) Backspace key.
+ { AKEYCODE_GRAVE, Key::QUOTELEFT }, // (68) '`' (backtick) key.
+ { AKEYCODE_MINUS, Key::MINUS }, // (69) '-'.
+ { AKEYCODE_EQUALS, Key::EQUAL }, // (70) '=' key.
+ { AKEYCODE_LEFT_BRACKET, Key::BRACKETLEFT }, // (71) '[' key.
+ { AKEYCODE_RIGHT_BRACKET, Key::BRACKETRIGHT }, // (72) ']' key.
+ { AKEYCODE_BACKSLASH, Key::BACKSLASH }, // (73) '\' key.
+ { AKEYCODE_SEMICOLON, Key::SEMICOLON }, // (74) ';' key.
+ { AKEYCODE_APOSTROPHE, Key::APOSTROPHE }, // (75) ''' (apostrophe) key.
+ { AKEYCODE_SLASH, Key::SLASH }, // (76) '/' key.
+ { AKEYCODE_AT, Key::AT }, // (77) '@' key.
+ { AKEYCODE_PLUS, Key::PLUS }, // (81) '+' key.
+ { AKEYCODE_MENU, Key::MENU }, // (82) Menu key.
+ { AKEYCODE_SEARCH, Key::SEARCH }, // (84) Search key.
+ { AKEYCODE_MEDIA_STOP, Key::MEDIASTOP }, // (86) Stop media key.
+ { AKEYCODE_MEDIA_PREVIOUS, Key::MEDIAPREVIOUS }, // (88) Play Previous media key.
+ { AKEYCODE_PAGE_UP, Key::PAGEUP }, // (92) Page Up key.
+ { AKEYCODE_PAGE_DOWN, Key::PAGEDOWN }, // (93) Page Down key.
+ { AKEYCODE_ESCAPE, Key::ESCAPE }, // (111) Escape key.
+ { AKEYCODE_FORWARD_DEL, Key::KEY_DELETE }, // (112) Forward Delete key.
+ { AKEYCODE_CTRL_LEFT, Key::CTRL }, // (113) Left Control modifier key.
+ { AKEYCODE_CTRL_RIGHT, Key::CTRL }, // (114) Right Control modifier key.
+ { AKEYCODE_CAPS_LOCK, Key::CAPSLOCK }, // (115) Caps Lock key.
+ { AKEYCODE_SCROLL_LOCK, Key::SCROLLLOCK }, // (116) Scroll Lock key.
+ { AKEYCODE_META_LEFT, Key::META }, // (117) Left Meta modifier key.
+ { AKEYCODE_META_RIGHT, Key::META }, // (118) Right Meta modifier key.
+ { AKEYCODE_SYSRQ, Key::PRINT }, // (120) System Request / Print Screen key.
+ { AKEYCODE_BREAK, Key::PAUSE }, // (121) Break / Pause key.
+ { AKEYCODE_INSERT, Key::INSERT }, // (124) Insert key.
+ { AKEYCODE_FORWARD, Key::FORWARD }, // (125) Forward key.
+ { AKEYCODE_MEDIA_PLAY, Key::MEDIAPLAY }, // (126) Play media key.
+ { AKEYCODE_MEDIA_RECORD, Key::MEDIARECORD }, // (130) Record media key.
+ { AKEYCODE_F1, Key::F1 }, // (131) F1 key.
+ { AKEYCODE_F2, Key::F2 }, // (132) F2 key.
+ { AKEYCODE_F3, Key::F3 }, // (133) F3 key.
+ { AKEYCODE_F4, Key::F4 }, // (134) F4 key.
+ { AKEYCODE_F5, Key::F5 }, // (135) F5 key.
+ { AKEYCODE_F6, Key::F6 }, // (136) F6 key.
+ { AKEYCODE_F7, Key::F7 }, // (137) F7 key.
+ { AKEYCODE_F8, Key::F8 }, // (138) F8 key.
+ { AKEYCODE_F9, Key::F9 }, // (139) F9 key.
+ { AKEYCODE_F10, Key::F10 }, // (140) F10 key.
+ { AKEYCODE_F11, Key::F11 }, // (141) F11 key.
+ { AKEYCODE_F12, Key::F12 }, // (142) F12 key.
+ { AKEYCODE_NUM_LOCK, Key::NUMLOCK }, // (143) Num Lock key.
+ { AKEYCODE_NUMPAD_0, Key::KP_0 }, // (144) Numeric keypad '0' key.
+ { AKEYCODE_NUMPAD_1, Key::KP_1 }, // (145) Numeric keypad '1' key.
+ { AKEYCODE_NUMPAD_2, Key::KP_2 }, // (146) Numeric keypad '2' key.
+ { AKEYCODE_NUMPAD_3, Key::KP_3 }, // (147) Numeric keypad '3' key.
+ { AKEYCODE_NUMPAD_4, Key::KP_4 }, // (148) Numeric keypad '4' key.
+ { AKEYCODE_NUMPAD_5, Key::KP_5 }, // (149) Numeric keypad '5' key.
+ { AKEYCODE_NUMPAD_6, Key::KP_6 }, // (150) Numeric keypad '6' key.
+ { AKEYCODE_NUMPAD_7, Key::KP_7 }, // (151) Numeric keypad '7' key.
+ { AKEYCODE_NUMPAD_8, Key::KP_8 }, // (152) Numeric keypad '8' key.
+ { AKEYCODE_NUMPAD_9, Key::KP_9 }, // (153) Numeric keypad '9' key.
+ { AKEYCODE_NUMPAD_DIVIDE, Key::KP_DIVIDE }, // (154) Numeric keypad '/' key (for division).
+ { AKEYCODE_NUMPAD_MULTIPLY, Key::KP_MULTIPLY }, // (155) Numeric keypad '*' key (for multiplication).
+ { AKEYCODE_NUMPAD_SUBTRACT, Key::KP_SUBTRACT }, // (156) Numeric keypad '-' key (for subtraction).
+ { AKEYCODE_NUMPAD_ADD, Key::KP_ADD }, // (157) Numeric keypad '+' key (for addition).
+ { AKEYCODE_NUMPAD_DOT, Key::KP_PERIOD }, // (158) Numeric keypad '.' key (for decimals or digit grouping).
+ { AKEYCODE_NUMPAD_ENTER, Key::KP_ENTER }, // (160) Numeric keypad Enter key.
+ { AKEYCODE_VOLUME_MUTE, Key::VOLUMEMUTE }, // (164) Volume Mute key.
+ { AKEYCODE_YEN, Key::YEN }, // (216) Japanese Yen key.
+ { AKEYCODE_HELP, Key::HELP }, // (259) Help key.
+ { AKEYCODE_REFRESH, Key::REFRESH }, // (285) Refresh key.
+ { AKEYCODE_MAX, Key::UNKNOWN }
};
-/*
-TODO: map these android key:
- AKEYCODE_SOFT_LEFT = 1,
- AKEYCODE_SOFT_RIGHT = 2,
- AKEYCODE_CALL = 5,
- AKEYCODE_ENDCALL = 6,
- AKEYCODE_STAR = 17,
- AKEYCODE_POUND = 18,
- AKEYCODE_POWER = 26,
- AKEYCODE_CAMERA = 27,
- AKEYCODE_CLEAR = 28,
- AKEYCODE_SYM = 63,
- AKEYCODE_ENVELOPE = 65,
- AKEYCODE_GRAVE = 68,
- AKEYCODE_SEMICOLON = 74,
- AKEYCODE_APOSTROPHE = 75,
- AKEYCODE_AT = 77,
- AKEYCODE_NUM = 78,
- AKEYCODE_HEADSETHOOK = 79,
- AKEYCODE_FOCUS = 80, // *Camera* focus
- AKEYCODE_NOTIFICATION = 83,
- AKEYCODE_SEARCH = 84,
- AKEYCODE_PICTSYMBOLS = 94,
- AKEYCODE_SWITCH_CHARSET = 95,
-*/
-Key android_get_keysym(unsigned int p_code);
+Key godot_code_from_android_code(unsigned int p_code);
+Key godot_code_from_unicode(unsigned int p_code);
#endif // ANDROID_KEYS_UTILS_H
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 2ff5bf59ea..ad63821162 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -22,7 +22,6 @@ def get_opts():
return [
("ANDROID_SDK_ROOT", "Path to the Android SDK", get_env_android_sdk_root()),
("ndk_platform", 'Target platform (android-<api>, e.g. "android-24")', "android-24"),
- EnumVariable("android_arch", "Target architecture", "arm64v8", ("armv7", "arm64v8", "x86", "x86_64")),
]
@@ -46,6 +45,7 @@ def get_ndk_version():
def get_flags():
return [
+ ("arch", "arm64"), # Default for convenience.
("tools", False),
]
@@ -75,35 +75,37 @@ def install_ndk_if_needed(env):
def configure(env):
+ # Validate arch.
+ supported_arches = ["x86_32", "x86_64", "arm32", "arm64"]
+ if env["arch"] not in supported_arches:
+ print(
+ 'Unsupported CPU architecture "%s" for Android. Supported architectures are: %s.'
+ % (env["arch"], ", ".join(supported_arches))
+ )
+ sys.exit()
+
install_ndk_if_needed(env)
ndk_root = env["ANDROID_NDK_ROOT"]
# Architecture
- if env["android_arch"] not in ["armv7", "arm64v8", "x86", "x86_64"]:
- env["android_arch"] = "arm64v8"
-
- print("Building for Android, platform " + env["ndk_platform"] + " (" + env["android_arch"] + ")")
-
- if get_min_sdk_version(env["ndk_platform"]) < 21:
- if env["android_arch"] == "x86_64" or env["android_arch"] == "arm64v8":
- print(
- "WARNING: android_arch="
- + env["android_arch"]
- + " is not supported by ndk_platform lower than android-21; setting ndk_platform=android-21"
- )
- env["ndk_platform"] = "android-21"
+ if get_min_sdk_version(env["ndk_platform"]) < 21 and env["arch"] in ["x86_64", "arm64"]:
+ print(
+ 'WARNING: arch="%s" is not supported with "ndk_platform" lower than "android-21". Forcing platform 21.'
+ % env["arch"]
+ )
+ env["ndk_platform"] = "android-21"
- if env["android_arch"] == "armv7":
+ if env["arch"] == "arm32":
target_triple = "armv7a-linux-androideabi"
env.extra_suffix = ".armv7" + env.extra_suffix
- elif env["android_arch"] == "arm64v8":
+ elif env["arch"] == "arm64":
target_triple = "aarch64-linux-android"
env.extra_suffix = ".armv8" + env.extra_suffix
- elif env["android_arch"] == "x86":
+ elif env["arch"] == "x86_32":
target_triple = "i686-linux-android"
env.extra_suffix = ".x86" + env.extra_suffix
- elif env["android_arch"] == "x86_64":
+ elif env["arch"] == "x86_64":
target_triple = "x86_64-linux-android"
env.extra_suffix = ".x86_64" + env.extra_suffix
@@ -176,14 +178,14 @@ def configure(env):
if get_min_sdk_version(env["ndk_platform"]) >= 24:
env.Append(CPPDEFINES=[("_FILE_OFFSET_BITS", 64)])
- if env["android_arch"] == "x86":
+ if env["arch"] == "x86_32":
# The NDK adds this if targeting API < 24, so we can drop it when Godot targets it at least
env.Append(CCFLAGS=["-mstackrealign"])
- elif env["android_arch"] == "armv7":
+ elif env["arch"] == "arm32":
env.Append(CCFLAGS="-march=armv7-a -mfloat-abi=softfp".split())
env.Append(CPPDEFINES=["__ARM_ARCH_7__", "__ARM_ARCH_7A__"])
env.Append(CPPDEFINES=["__ARM_NEON__"])
- elif env["android_arch"] == "arm64v8":
+ elif env["arch"] == "arm64":
env.Append(CCFLAGS=["-mfix-cortex-a53-835769"])
env.Append(CPPDEFINES=["__ARM_ARCH_8A__"])
diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp
index eb344d3b43..373c6e37f1 100644
--- a/platform/android/dir_access_jandroid.cpp
+++ b/platform/android/dir_access_jandroid.cpp
@@ -135,6 +135,20 @@ String DirAccessJAndroid::get_drive(int p_drive) {
}
}
+String DirAccessJAndroid::get_current_dir(bool p_include_drive) const {
+ String base = _get_root_path();
+ String bd = current_dir;
+ if (!base.is_empty()) {
+ bd = current_dir.replace_first(base, "");
+ }
+
+ if (bd.begins_with("/")) {
+ return _get_root_string() + bd.substr(1, bd.length());
+ } else {
+ return _get_root_string() + bd;
+ }
+}
+
Error DirAccessJAndroid::change_dir(String p_dir) {
String new_dir = get_absolute_path(p_dir);
if (new_dir == current_dir) {
@@ -155,7 +169,7 @@ String DirAccessJAndroid::get_absolute_path(String p_path) {
}
if (p_path.is_relative_path()) {
- p_path = get_current_dir().plus_file(p_path);
+ p_path = get_current_dir().path_join(p_path);
}
p_path = fix_path(p_path);
diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h
index d469c9d317..5b7b4a9c4d 100644
--- a/platform/android/dir_access_jandroid.h
+++ b/platform/android/dir_access_jandroid.h
@@ -67,6 +67,7 @@ public:
virtual int get_drive_count() override;
virtual String get_drive(int p_drive) override;
+ virtual String get_current_dir(bool p_include_drive = true) const override; ///< return current dir location
virtual Error change_dir(String p_dir) override; ///< can be relative or absolute, return false on success
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index 86f933d4bc..d3bce12de1 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -83,7 +83,7 @@ bool DisplayServerAndroid::tts_is_paused() const {
return TTS_Android::is_paused();
}
-Array DisplayServerAndroid::tts_get_voices() const {
+TypedArray<Dictionary> DisplayServerAndroid::tts_get_voices() const {
return TTS_Android::get_voices();
}
@@ -136,7 +136,7 @@ bool DisplayServerAndroid::clipboard_has() const {
}
}
-Array DisplayServerAndroid::get_display_cutouts() const {
+TypedArray<Rect2> DisplayServerAndroid::get_display_cutouts() const {
GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
ERR_FAIL_NULL_V(godot_io_java, Array());
return godot_io_java->get_display_cutouts();
@@ -221,12 +221,12 @@ bool DisplayServerAndroid::screen_is_touchscreen(int p_screen) const {
return true;
}
-void DisplayServerAndroid::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) {
+void DisplayServerAndroid::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, VirtualKeyboardType p_type, int p_max_length, int p_cursor_start, int p_cursor_end) {
GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
ERR_FAIL_NULL(godot_io_java);
if (godot_io_java->has_vk()) {
- godot_io_java->show_vk(p_existing_text, p_multiline, p_max_length, p_cursor_start, p_cursor_end);
+ godot_io_java->show_vk(p_existing_text, (int)p_type, p_max_length, p_cursor_start, p_cursor_end);
} else {
ERR_PRINT("Virtual keyboard not available");
}
diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h
index 65bf2ec1a8..6e14ba3e23 100644
--- a/platform/android/display_server_android.h
+++ b/platform/android/display_server_android.h
@@ -93,7 +93,7 @@ public:
virtual bool tts_is_speaking() const override;
virtual bool tts_is_paused() const override;
- virtual Array tts_get_voices() const override;
+ virtual TypedArray<Dictionary> tts_get_voices() const override;
virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override;
virtual void tts_pause() override;
@@ -104,7 +104,7 @@ public:
virtual String clipboard_get() const override;
virtual bool clipboard_has() const override;
- virtual Array get_display_cutouts() const override;
+ virtual TypedArray<Rect2> get_display_cutouts() const override;
virtual Rect2i get_display_safe_area() const override;
virtual void screen_set_keep_on(bool p_enable) override;
@@ -122,7 +122,7 @@ public:
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
- virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_length = -1, int p_cursor_start = -1, int p_cursor_end = -1) override;
+ virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), VirtualKeyboardType p_type = KEYBOARD_TYPE_DEFAULT, int p_max_length = -1, int p_cursor_start = -1, int p_cursor_end = -1) override;
virtual void virtual_keyboard_hide() override;
virtual int virtual_keyboard_get_height() const override;
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 6f1b4bde40..0f8ef3f7d6 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -248,6 +248,7 @@ static const char *AAB_ASSETS_DIRECTORY = "res://android/build/assetPacks/instal
static const int DEFAULT_MIN_SDK_VERSION = 19; // Should match the value in 'platform/android/java/app/config.gradle#minSdk'
static const int DEFAULT_TARGET_SDK_VERSION = 32; // Should match the value in 'platform/android/java/app/config.gradle#targetSdk'
+#ifndef ANDROID_ENABLED
void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) {
EditorExportPlatformAndroid *ea = static_cast<EditorExportPlatformAndroid *>(ud);
@@ -277,7 +278,6 @@ void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) {
}
}
-#ifndef ANDROID_ENABLED
// Check for devices updates
String adb = get_adb_path();
if (FileAccess::exists(adb)) {
@@ -389,7 +389,6 @@ void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) {
ea->devices_changed.set();
}
}
-#endif
uint64_t sleep = 200;
uint64_t wait = 3000000;
@@ -402,7 +401,6 @@ void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) {
}
}
-#ifndef ANDROID_ENABLED
if (EditorSettings::get_singleton()->get("export/android/shutdown_adb_on_exit")) {
String adb = get_adb_path();
if (!FileAccess::exists(adb)) {
@@ -413,8 +411,8 @@ void EditorExportPlatformAndroid::_check_for_changes_poll_thread(void *ud) {
args.push_back("kill-server");
OS::get_singleton()->execute(adb, args);
}
-#endif
}
+#endif
String EditorExportPlatformAndroid::get_project_name(const String &p_name) const {
String aname;
@@ -626,7 +624,7 @@ Vector<String> EditorExportPlatformAndroid::list_gdap_files(const String &p_path
Vector<PluginConfigAndroid> EditorExportPlatformAndroid::get_plugins() {
Vector<PluginConfigAndroid> loaded_plugins;
- String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/plugins");
+ String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().path_join("android/plugins");
// Add the prebuilt plugins
loaded_plugins.append_array(PluginConfigAndroid::get_prebuilt_plugins(plugins_dir));
@@ -637,7 +635,7 @@ Vector<PluginConfigAndroid> EditorExportPlatformAndroid::get_plugins() {
if (!plugins_filenames.is_empty()) {
Ref<ConfigFile> config_file = memnew(ConfigFile);
for (int i = 0; i < plugins_filenames.size(); i++) {
- PluginConfigAndroid config = PluginConfigAndroid::load_plugin_config(config_file, plugins_dir.plus_file(plugins_filenames[i]));
+ PluginConfigAndroid config = PluginConfigAndroid::load_plugin_config(config_file, plugins_dir.path_join(plugins_filenames[i]));
if (config.valid_config) {
loaded_plugins.push_back(config);
} else {
@@ -698,7 +696,7 @@ Error EditorExportPlatformAndroid::save_apk_so(void *p_userdata, const SharedObj
if (abi_index != -1) {
exported = true;
String abi = abis[abi_index];
- String dst_path = String("lib").plus_file(abi).plus_file(p_so.path.get_file());
+ String dst_path = String("lib").path_join(abi).path_join(p_so.path.get_file());
Vector<uint8_t> array = FileAccess::get_file_as_array(p_so.path);
Error store_err = store_in_apk(ed, dst_path, array);
ERR_FAIL_COND_V_MSG(store_err, store_err, "Cannot store in apk file '" + dst_path + "'.");
@@ -739,7 +737,7 @@ Error EditorExportPlatformAndroid::copy_gradle_so(void *p_userdata, const Shared
String type = export_data->debug ? "debug" : "release";
String abi = abis[abi_index];
String filename = p_so.path.get_file();
- String dst_path = base.plus_file(type).plus_file(abi).plus_file(filename);
+ String dst_path = base.path_join(type).path_join(abi).path_join(filename);
Vector<uint8_t> data = FileAccess::get_file_as_array(p_so.path);
print_verbose("Copying .so file from " + p_so.path + " to " + dst_path);
Error err = store_file_at_path(dst_path, data);
@@ -1853,7 +1851,7 @@ Error EditorExportPlatformAndroid::run(const Ref<EditorExportPreset> &p_preset,
p_debug_flags |= DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST;
}
- String tmp_export_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpexport." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
+ String tmp_export_path = EditorPaths::get_singleton()->get_cache_dir().path_join("tmpexport." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
#define CLEANUP_AND_RETURN(m_err) \
{ \
@@ -2006,7 +2004,7 @@ String EditorExportPlatformAndroid::get_adb_path() {
exe_ext = ".exe";
}
String sdk_path = EditorSettings::get_singleton()->get("export/android/android_sdk_path");
- return sdk_path.plus_file("platform-tools/adb" + exe_ext);
+ return sdk_path.path_join("platform-tools/adb" + exe_ext);
}
String EditorExportPlatformAndroid::get_apksigner_path() {
@@ -2019,7 +2017,7 @@ String EditorExportPlatformAndroid::get_apksigner_path() {
String apksigner_path = "";
Error errn;
- String build_tools_dir = sdk_path.plus_file("build-tools");
+ String build_tools_dir = sdk_path.path_join("build-tools");
Ref<DirAccess> da = DirAccess::open(build_tools_dir, &errn);
if (errn != OK) {
print_error("Unable to open Android 'build-tools' directory.");
@@ -2032,7 +2030,7 @@ String EditorExportPlatformAndroid::get_apksigner_path() {
while (!sub_dir.is_empty()) {
if (!sub_dir.begins_with(".") && da->current_is_dir()) {
// Check if the tool is here.
- String tool_path = build_tools_dir.plus_file(sub_dir).plus_file(apksigner_command_name);
+ String tool_path = build_tools_dir.path_join(sub_dir).path_join(apksigner_command_name);
if (FileAccess::exists(tool_path)) {
apksigner_path = tool_path;
break;
@@ -2049,7 +2047,7 @@ String EditorExportPlatformAndroid::get_apksigner_path() {
return apksigner_path;
}
-bool EditorExportPlatformAndroid::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+bool EditorExportPlatformAndroid::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
String err;
bool valid = false;
const bool custom_build_enabled = p_preset->get("custom_build/use_custom_build");
@@ -2097,7 +2095,7 @@ bool EditorExportPlatformAndroid::can_export(const Ref<EditorExportPreset> &p_pr
valid = installed_android_build_template && !r_missing_templates;
}
- // Validate the rest of the configuration.
+ // Validate the rest of the export configuration.
String dk = p_preset->get("keystore/debug");
String dk_user = p_preset->get("keystore/debug_user");
@@ -2137,7 +2135,7 @@ bool EditorExportPlatformAndroid::can_export(const Ref<EditorExportPreset> &p_pr
} else {
Error errn;
// Check for the platform-tools directory.
- Ref<DirAccess> da = DirAccess::open(sdk_path.plus_file("platform-tools"), &errn);
+ Ref<DirAccess> da = DirAccess::open(sdk_path.path_join("platform-tools"), &errn);
if (errn != OK) {
err += TTR("Invalid Android SDK path in Editor Settings.");
err += TTR("Missing 'platform-tools' directory!");
@@ -2155,7 +2153,7 @@ bool EditorExportPlatformAndroid::can_export(const Ref<EditorExportPreset> &p_pr
}
// Check for the build-tools directory.
- Ref<DirAccess> build_tools_da = DirAccess::open(sdk_path.plus_file("build-tools"), &errn);
+ Ref<DirAccess> build_tools_da = DirAccess::open(sdk_path.path_join("build-tools"), &errn);
if (errn != OK) {
err += TTR("Invalid Android SDK path in Editor Settings.");
err += TTR("Missing 'build-tools' directory!");
@@ -2173,6 +2171,19 @@ bool EditorExportPlatformAndroid::can_export(const Ref<EditorExportPreset> &p_pr
}
}
+ if (!err.is_empty()) {
+ r_error = err;
+ }
+
+ return valid;
+}
+
+bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const {
+ String err;
+ bool valid = true;
+ const bool custom_build_enabled = p_preset->get("custom_build/use_custom_build");
+
+ // Validate the project configuration.
bool apk_expansion = p_preset->get("apk_expansion/enable");
if (apk_expansion) {
@@ -2299,7 +2310,7 @@ String EditorExportPlatformAndroid::get_apk_expansion_fullpath(const Ref<EditorE
int version_code = p_preset->get("version/code");
String package_name = p_preset->get("package/unique_name");
String apk_file_name = "main." + itos(version_code) + "." + get_package_name(package_name) + ".obb";
- String fullpath = p_path.get_base_dir().plus_file(apk_file_name);
+ String fullpath = p_path.get_base_dir().path_join(apk_file_name);
return fullpath;
}
@@ -2660,8 +2671,8 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
build_command = "gradlew";
#endif
- String build_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/build");
- build_command = build_path.plus_file(build_command);
+ String build_path = ProjectSettings::get_singleton()->get_resource_path().path_join("android/build");
+ build_command = build_path.path_join(build_command);
String package_name = get_package_name(p_preset->get("package/unique_name"));
String version_code = itos(p_preset->get("version/code"));
@@ -2731,7 +2742,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
debug_user = EditorSettings::get_singleton()->get("export/android/debug_keystore_user");
}
if (debug_keystore.is_relative_path()) {
- debug_keystore = OS::get_singleton()->get_resource_dir().plus_file(debug_keystore).simplify_path();
+ debug_keystore = OS::get_singleton()->get_resource_dir().path_join(debug_keystore).simplify_path();
}
if (!FileAccess::exists(debug_keystore)) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Could not find keystore, unable to export."));
@@ -2747,7 +2758,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
String release_username = p_preset->get("keystore/release_user");
String release_password = p_preset->get("keystore/release_password");
if (release_keystore.is_relative_path()) {
- release_keystore = OS::get_singleton()->get_resource_dir().plus_file(release_keystore).simplify_path();
+ release_keystore = OS::get_singleton()->get_resource_dir().path_join(release_keystore).simplify_path();
}
if (!FileAccess::exists(release_keystore)) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Could not find keystore, unable to export."));
@@ -2782,7 +2793,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
String export_filename = p_path.get_file();
String export_path = p_path.get_base_dir();
if (export_path.is_relative_path()) {
- export_path = OS::get_singleton()->get_resource_dir().plus_file(export_path);
+ export_path = OS::get_singleton()->get_resource_dir().path_join(export_path);
}
export_path = ProjectSettings::get_singleton()->globalize_path(export_path).simplify_path();
@@ -2841,7 +2852,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
Ref<FileAccess> io2_fa;
zlib_filefunc_def io2 = zipio_create_io(&io2_fa);
- String tmp_unaligned_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpexport-unaligned." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
+ String tmp_unaligned_path = EditorPaths::get_singleton()->get_cache_dir().path_join("tmpexport-unaligned." + uitos(OS::get_singleton()->get_unix_time()) + ".apk");
#define CLEANUP_AND_RETURN(m_err) \
{ \
@@ -3125,10 +3136,14 @@ EditorExportPlatformAndroid::EditorExportPlatformAndroid() {
devices_changed.set();
plugins_changed.set();
+#ifndef ANDROID_ENABLED
check_for_changes_thread.start(_check_for_changes_poll_thread, this);
+#endif
}
EditorExportPlatformAndroid::~EditorExportPlatformAndroid() {
+#ifndef ANDROID_ENABLED
quit_request.set();
check_for_changes_thread.wait_to_finish();
+#endif
}
diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h
index 1da3f68f9a..46012bd46c 100644
--- a/platform/android/export/export_plugin.h
+++ b/platform/android/export/export_plugin.h
@@ -80,10 +80,12 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
Vector<Device> devices;
SafeFlag devices_changed;
Mutex device_lock;
+#ifndef ANDROID_ENABLED
Thread check_for_changes_thread;
SafeFlag quit_request;
static void _check_for_changes_poll_thread(void *ud);
+#endif
String get_project_name(const String &p_name) const;
@@ -186,7 +188,8 @@ public:
static String get_apksigner_path();
- virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
diff --git a/platform/android/export/godot_plugin_config.cpp b/platform/android/export/godot_plugin_config.cpp
index 3daf6e44cd..21580ae907 100644
--- a/platform/android/export/godot_plugin_config.cpp
+++ b/platform/android/export/godot_plugin_config.cpp
@@ -50,7 +50,7 @@ String PluginConfigAndroid::resolve_local_dependency_path(String plugin_config_d
if (dependency_path.is_absolute_path()) {
absolute_path = ProjectSettings::get_singleton()->globalize_path(dependency_path);
} else {
- absolute_path = plugin_config_dir.plus_file(dependency_path);
+ absolute_path = plugin_config_dir.path_join(dependency_path);
}
}
diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h
index e6fd8c857b..8d7ade8ead 100644
--- a/platform/android/file_access_android.h
+++ b/platform/android/file_access_android.h
@@ -49,34 +49,34 @@ class FileAccessAndroid : public FileAccess {
public:
static AAssetManager *asset_manager;
- virtual Error _open(const String &p_path, int p_mode_flags); // open a file
- virtual bool is_open() const; // true when file is open
+ virtual Error _open(const String &p_path, int p_mode_flags) override; // open a file
+ virtual bool is_open() const override; // true when file is open
/// returns the path for the current open file
- virtual String get_path() const;
+ virtual String get_path() const override;
/// returns the absolute path for the current open file
- virtual String get_path_absolute() const;
+ virtual String get_path_absolute() const override;
- virtual void seek(uint64_t p_position); // seek to a given position
- virtual void seek_end(int64_t p_position = 0); // seek from the end of file
- virtual uint64_t get_position() const; // get position in the file
- virtual uint64_t get_length() const; // get size of the file
+ virtual void seek(uint64_t p_position) override; // seek to a given position
+ virtual void seek_end(int64_t p_position = 0) override; // seek from the end of file
+ virtual uint64_t get_position() const override; // get position in the file
+ virtual uint64_t get_length() const override; // get size of the file
- virtual bool eof_reached() const; // reading passed EOF
+ virtual bool eof_reached() const override; // reading passed EOF
- virtual uint8_t get_8() const; // get a byte
- virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const;
+ virtual uint8_t get_8() const override; // get a byte
+ virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override;
- virtual Error get_error() const; // get last error
+ virtual Error get_error() const override; // get last error
- virtual void flush();
- virtual void store_8(uint8_t p_dest); // store a byte
+ virtual void flush() override;
+ virtual void store_8(uint8_t p_dest) override; // store a byte
- virtual bool file_exists(const String &p_path); // return true if a file exists
+ virtual bool file_exists(const String &p_path) override; // return true if a file exists
- virtual uint64_t _get_modified_time(const String &p_file) { return 0; }
- virtual uint32_t _get_unix_permissions(const String &p_file) { return 0; }
- virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) { return FAILED; }
+ virtual uint64_t _get_modified_time(const String &p_file) override { return 0; }
+ virtual uint32_t _get_unix_permissions(const String &p_file) override { return 0; }
+ virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override { return FAILED; }
~FileAccessAndroid();
};
diff --git a/platform/android/file_access_filesystem_jandroid.cpp b/platform/android/file_access_filesystem_jandroid.cpp
index 733d92f741..56561cb616 100644
--- a/platform/android/file_access_filesystem_jandroid.cpp
+++ b/platform/android/file_access_filesystem_jandroid.cpp
@@ -29,9 +29,11 @@
/*************************************************************************/
#include "file_access_filesystem_jandroid.h"
+
#include "core/os/os.h"
#include "core/templates/local_vector.h"
#include "thread_jandroid.h"
+
#include <unistd.h>
jobject FileAccessFilesystemJAndroid::file_access_handler = nullptr;
@@ -44,6 +46,7 @@ jmethodID FileAccessFilesystemJAndroid::_file_seek_end = nullptr;
jmethodID FileAccessFilesystemJAndroid::_file_read = nullptr;
jmethodID FileAccessFilesystemJAndroid::_file_tell = nullptr;
jmethodID FileAccessFilesystemJAndroid::_file_eof = nullptr;
+jmethodID FileAccessFilesystemJAndroid::_file_set_eof = nullptr;
jmethodID FileAccessFilesystemJAndroid::_file_close = nullptr;
jmethodID FileAccessFilesystemJAndroid::_file_write = nullptr;
jmethodID FileAccessFilesystemJAndroid::_file_flush = nullptr;
@@ -160,6 +163,16 @@ bool FileAccessFilesystemJAndroid::eof_reached() const {
}
}
+void FileAccessFilesystemJAndroid::_set_eof(bool eof) {
+ if (_file_set_eof) {
+ ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use.");
+
+ JNIEnv *env = get_jni_env();
+ ERR_FAIL_COND(env == nullptr);
+ env->CallVoidMethod(file_access_handler, _file_set_eof, id, eof);
+ }
+}
+
uint8_t FileAccessFilesystemJAndroid::get_8() const {
ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use.");
uint8_t byte;
@@ -182,6 +195,7 @@ String FileAccessFilesystemJAndroid::get_line() const {
while (true) {
size_t line_buffer_size = MIN(buffer_size_limit, file_size - get_position());
if (line_buffer_size <= 0) {
+ const_cast<FileAccessFilesystemJAndroid *>(this)->_set_eof(true);
break;
}
@@ -198,7 +212,7 @@ String FileAccessFilesystemJAndroid::get_line() const {
if (elem == '\n' || elem == '\0') {
// Found the end of the line
const_cast<FileAccessFilesystemJAndroid *>(this)->seek(start_position + line_buffer_position + 1);
- if (result.parse_utf8((const char *)line_buffer.ptr(), line_buffer_position)) {
+ if (result.parse_utf8((const char *)line_buffer.ptr(), line_buffer_position, true)) {
return String();
}
return result;
@@ -206,7 +220,7 @@ String FileAccessFilesystemJAndroid::get_line() const {
}
}
- if (result.parse_utf8((const char *)line_buffer.ptr(), line_buffer_position)) {
+ if (result.parse_utf8((const char *)line_buffer.ptr(), line_buffer_position, true)) {
return String();
}
return result;
@@ -308,6 +322,7 @@ void FileAccessFilesystemJAndroid::setup(jobject p_file_access_handler) {
_file_get_size = env->GetMethodID(cls, "fileGetSize", "(I)J");
_file_tell = env->GetMethodID(cls, "fileGetPosition", "(I)J");
_file_eof = env->GetMethodID(cls, "isFileEof", "(I)Z");
+ _file_set_eof = env->GetMethodID(cls, "setFileEof", "(IZ)V");
_file_seek = env->GetMethodID(cls, "fileSeek", "(IJ)V");
_file_seek_end = env->GetMethodID(cls, "fileSeekFromEnd", "(IJ)V");
_file_read = env->GetMethodID(cls, "fileRead", "(ILjava/nio/ByteBuffer;)I");
diff --git a/platform/android/file_access_filesystem_jandroid.h b/platform/android/file_access_filesystem_jandroid.h
index 7deb8de37b..76d7db6e3a 100644
--- a/platform/android/file_access_filesystem_jandroid.h
+++ b/platform/android/file_access_filesystem_jandroid.h
@@ -44,6 +44,7 @@ class FileAccessFilesystemJAndroid : public FileAccess {
static jmethodID _file_seek_end;
static jmethodID _file_tell;
static jmethodID _file_eof;
+ static jmethodID _file_set_eof;
static jmethodID _file_read;
static jmethodID _file_write;
static jmethodID _file_flush;
@@ -56,6 +57,7 @@ class FileAccessFilesystemJAndroid : public FileAccess {
String path_src;
void _close(); ///< close a file
+ void _set_eof(bool eof);
public:
virtual Error _open(const String &p_path, int p_mode_flags) override; ///< open a file
diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle
index da30bd3a95..81c7130c03 100644
--- a/platform/android/java/build.gradle
+++ b/platform/android/java/build.gradle
@@ -28,7 +28,7 @@ allprojects {
}
ext {
- supportedAbis = ["armv7", "arm64v8", "x86", "x86_64"]
+ supportedAbis = ["arm32", "arm64", "x86_32", "x86_64"]
supportedTargetsMap = [release: "release", dev: "debug", debug: "release_debug"]
supportedFlavors = ["editor", "template"]
@@ -37,7 +37,7 @@ ext {
// If building manually on the command line, it's recommended to use the
// `./gradlew generateGodotTemplates` build command instead after running the `scons` command(s).
// The {selectedAbis} values must be from the {supportedAbis} values.
- selectedAbis = ["arm64v8"]
+ selectedAbis = ["arm64"]
}
def rootDir = "../../.."
diff --git a/platform/android/java/lib/build.gradle b/platform/android/java/lib/build.gradle
index 6b82326a27..318ae1143f 100644
--- a/platform/android/java/lib/build.gradle
+++ b/platform/android/java/lib/build.gradle
@@ -159,7 +159,7 @@ android {
def taskName = getSconsTaskName(flavorName, buildType, selectedAbi)
tasks.create(name: taskName, type: Exec) {
executable sconsExecutableFile.absolutePath
- args "--directory=${pathToRootDir}", "platform=android", "tools=${toolsFlag}", "target=${sconsTarget}", "android_arch=${selectedAbi}", "-j" + Runtime.runtime.availableProcessors()
+ args "--directory=${pathToRootDir}", "platform=android", "tools=${toolsFlag}", "target=${sconsTarget}", "arch=${selectedAbi}", "-j" + Runtime.runtime.availableProcessors()
}
// Schedule the tasks so the generated libs are present before the aar file is packaged.
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
index 0434efdf4c..d283de8ce8 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
@@ -203,9 +203,10 @@ public class GodotIO {
return result;
}
- public void showKeyboard(String p_existing_text, boolean p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
- if (edit != null)
- edit.showKeyboard(p_existing_text, p_multiline, p_max_input_length, p_cursor_start, p_cursor_end);
+ public void showKeyboard(String p_existing_text, int p_type, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
+ if (edit != null) {
+ edit.showKeyboard(p_existing_text, GodotEditText.VirtualKeyboardType.values()[p_type], p_max_input_length, p_cursor_start, p_cursor_end);
+ }
//InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
//inputMgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
index e2ae62d9cf..f855fc6cf6 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
@@ -151,7 +151,7 @@ public class GodotLib {
/**
* Forward regular key events from the main thread to the GL thread.
*/
- public static native void key(int p_keycode, int p_scancode, int p_unicode_char, boolean p_pressed);
+ public static native void key(int p_keycode, int p_physical_keycode, int p_unicode, boolean p_pressed);
/**
* Forward game device's key events from the main thread to the GL thread.
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 ecb2af0a7b..7925b54fc4 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
@@ -52,6 +52,18 @@ public class GodotEditText extends EditText {
private final static int HANDLER_OPEN_IME_KEYBOARD = 2;
private final static int HANDLER_CLOSE_IME_KEYBOARD = 3;
+ // Enum must be kept up-to-date with DisplayServer::VirtualKeyboardType
+ public enum VirtualKeyboardType {
+ KEYBOARD_TYPE_DEFAULT,
+ KEYBOARD_TYPE_MULTILINE,
+ KEYBOARD_TYPE_NUMBER,
+ KEYBOARD_TYPE_NUMBER_DECIMAL,
+ KEYBOARD_TYPE_PHONE,
+ KEYBOARD_TYPE_EMAIL_ADDRESS,
+ KEYBOARD_TYPE_PASSWORD,
+ KEYBOARD_TYPE_URL
+ }
+
// ===========================================================
// Fields
// ===========================================================
@@ -60,7 +72,7 @@ public class GodotEditText extends EditText {
private EditHandler sHandler = new EditHandler(this);
private String mOriginText;
private int mMaxInputLength = Integer.MAX_VALUE;
- private boolean mMultiline = false;
+ private VirtualKeyboardType mKeyboardType = VirtualKeyboardType.KEYBOARD_TYPE_DEFAULT;
private static class EditHandler extends Handler {
private final WeakReference<GodotEditText> mEdit;
@@ -100,8 +112,8 @@ public class GodotEditText extends EditText {
setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_DONE);
}
- public boolean isMultiline() {
- return mMultiline;
+ public VirtualKeyboardType getKeyboardType() {
+ return mKeyboardType;
}
private void handleMessage(final Message msg) {
@@ -122,8 +134,31 @@ public class GodotEditText extends EditText {
}
int inputType = InputType.TYPE_CLASS_TEXT;
- if (edit.isMultiline()) {
- inputType |= InputType.TYPE_TEXT_FLAG_MULTI_LINE;
+ switch (edit.getKeyboardType()) {
+ case KEYBOARD_TYPE_DEFAULT:
+ inputType = InputType.TYPE_CLASS_TEXT;
+ break;
+ case KEYBOARD_TYPE_MULTILINE:
+ inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE;
+ break;
+ case KEYBOARD_TYPE_NUMBER:
+ inputType = InputType.TYPE_CLASS_NUMBER;
+ break;
+ case KEYBOARD_TYPE_NUMBER_DECIMAL:
+ inputType = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED;
+ break;
+ case KEYBOARD_TYPE_PHONE:
+ inputType = InputType.TYPE_CLASS_PHONE;
+ break;
+ case KEYBOARD_TYPE_EMAIL_ADDRESS:
+ inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
+ break;
+ case KEYBOARD_TYPE_PASSWORD:
+ inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD;
+ break;
+ case KEYBOARD_TYPE_URL:
+ inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI;
+ break;
}
edit.setInputType(inputType);
@@ -201,7 +236,7 @@ public class GodotEditText extends EditText {
// ===========================================================
// Methods
// ===========================================================
- public void showKeyboard(String p_existing_text, boolean p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
+ public void showKeyboard(String p_existing_text, VirtualKeyboardType p_type, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
int maxInputLength = (p_max_input_length <= 0) ? Integer.MAX_VALUE : p_max_input_length;
if (p_cursor_start == -1) { // cursor position not given
this.mOriginText = p_existing_text;
@@ -214,7 +249,7 @@ public class GodotEditText extends EditText {
this.mMaxInputLength = maxInputLength - (p_existing_text.length() - p_cursor_end);
}
- this.mMultiline = p_multiline;
+ this.mKeyboardType = p_type;
final Message msg = new Message();
msg.what = HANDLER_OPEN_IME_KEYBOARD;
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
index ccfb865b1a..da15b2490c 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
@@ -96,10 +96,14 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
GodotLib.joybutton(godotJoyId, button, false);
}
} else {
- final int scanCode = event.getScanCode();
- final int chr = event.getUnicodeChar(0);
- GodotLib.key(keyCode, scanCode, chr, false);
- }
+ // getKeyCode(): The physical key that was pressed.
+ // Godot's keycodes match the ASCII codes, so for single byte unicode characters,
+ // we can use the unmodified unicode character to determine Godot's keycode.
+ final int keycode = event.getUnicodeChar(0);
+ final int physical_keycode = event.getKeyCode();
+ final int unicode = event.getUnicodeChar();
+ GodotLib.key(keycode, physical_keycode, unicode, false);
+ };
return true;
}
@@ -131,9 +135,10 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
GodotLib.joybutton(godotJoyId, button, true);
}
} else {
- final int scanCode = event.getScanCode();
- final int chr = event.getUnicodeChar(0);
- GodotLib.key(keyCode, scanCode, chr, true);
+ final int keycode = event.getUnicodeChar(0);
+ final int physical_keycode = event.getKeyCode();
+ final int unicode = event.getUnicodeChar();
+ GodotLib.key(keycode, physical_keycode, unicode, true);
}
return true;
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java
index e940aafa9e..c959b5f28c 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java
@@ -92,11 +92,9 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
@Override
public void beforeTextChanged(final CharSequence pCharSequence, final int start, final int count, final int after) {
- //Log.d(TAG, "beforeTextChanged(" + pCharSequence + ")start: " + start + ",count: " + count + ",after: " + after);
-
for (int i = 0; i < count; ++i) {
- GodotLib.key(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, 0, true);
- GodotLib.key(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, 0, false);
+ GodotLib.key(0, KeyEvent.KEYCODE_DEL, 0, true);
+ GodotLib.key(0, KeyEvent.KEYCODE_DEL, 0, false);
if (mHasSelection) {
mHasSelection = false;
@@ -107,20 +105,18 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
@Override
public void onTextChanged(final CharSequence pCharSequence, final int start, final int before, final int count) {
- //Log.d(TAG, "onTextChanged(" + pCharSequence + ")start: " + start + ",count: " + count + ",before: " + before);
-
final int[] newChars = new int[count];
for (int i = start; i < start + count; ++i) {
newChars[i - start] = pCharSequence.charAt(i);
}
for (int i = 0; i < count; ++i) {
int key = newChars[i];
- if ((key == '\n') && !mEdit.isMultiline()) {
+ if ((key == '\n') && !(mEdit.getKeyboardType() == GodotEditText.VirtualKeyboardType.KEYBOARD_TYPE_MULTILINE)) {
// Return keys are handled through action events
continue;
}
- GodotLib.key(0, 0, key, true);
- GodotLib.key(0, 0, key, false);
+ GodotLib.key(key, 0, key, true);
+ GodotLib.key(key, 0, key, false);
}
}
@@ -131,16 +127,16 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
for (int i = 0; i < characters.length(); i++) {
final int ch = characters.codePointAt(i);
- GodotLib.key(0, 0, ch, true);
- GodotLib.key(0, 0, ch, false);
+ GodotLib.key(ch, 0, ch, true);
+ GodotLib.key(ch, 0, ch, false);
}
}
if (pActionID == EditorInfo.IME_ACTION_DONE) {
// Enter key has been pressed
mRenderView.queueOnRenderThread(() -> {
- GodotLib.key(KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER, 0, true);
- GodotLib.key(KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER, 0, false);
+ GodotLib.key(0, KeyEvent.KEYCODE_ENTER, 0, true);
+ GodotLib.key(0, KeyEvent.KEYCODE_ENTER, 0, false);
});
mRenderView.getView().requestFocus();
return true;
diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt b/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt
index 463dabfb23..f23537a29e 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt
@@ -104,7 +104,6 @@ internal abstract class DataAccess(private val filePath: String) {
protected abstract val fileChannel: FileChannel
internal var endOfFile = false
- private set
fun close() {
try {
@@ -125,9 +124,7 @@ internal abstract class DataAccess(private val filePath: String) {
fun seek(position: Long) {
try {
fileChannel.position(position)
- if (position <= size()) {
- endOfFile = false
- }
+ endOfFile = position >= fileChannel.size()
} catch (e: Exception) {
Log.w(TAG, "Exception when seeking file $filePath.", e)
}
@@ -161,8 +158,7 @@ internal abstract class DataAccess(private val filePath: String) {
fun read(buffer: ByteBuffer): Int {
return try {
val readBytes = fileChannel.read(buffer)
- endOfFile = readBytes == -1
- || (fileChannel.position() >= fileChannel.size() && fileChannel.size() > 0)
+ endOfFile = readBytes == -1 || (fileChannel.position() >= fileChannel.size())
if (readBytes == -1) {
0
} else {
diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt b/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt
index 04b6772c45..83da3a24b3 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt
@@ -194,6 +194,11 @@ class FileAccessHandler(val context: Context) {
return files[fileId].endOfFile
}
+ fun setFileEof(fileId: Int, eof: Boolean) {
+ val file = files[fileId] ?: return
+ file.endOfFile = eof
+ }
+
fun fileClose(fileId: Int) {
if (hasFileId(fileId)) {
files[fileId].close()
diff --git a/platform/android/java_godot_io_wrapper.cpp b/platform/android/java_godot_io_wrapper.cpp
index b71c6ef1e6..cea64a7f22 100644
--- a/platform/android/java_godot_io_wrapper.cpp
+++ b/platform/android/java_godot_io_wrapper.cpp
@@ -61,7 +61,7 @@ GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instanc
_get_scaled_density = p_env->GetMethodID(cls, "getScaledDensity", "()F");
_get_screen_refresh_rate = p_env->GetMethodID(cls, "getScreenRefreshRate", "(D)D");
_get_unique_id = p_env->GetMethodID(cls, "getUniqueID", "()Ljava/lang/String;");
- _show_keyboard = p_env->GetMethodID(cls, "showKeyboard", "(Ljava/lang/String;ZIII)V");
+ _show_keyboard = p_env->GetMethodID(cls, "showKeyboard", "(Ljava/lang/String;IIII)V");
_hide_keyboard = p_env->GetMethodID(cls, "hideKeyboard", "()V");
_set_screen_orientation = p_env->GetMethodID(cls, "setScreenOrientation", "(I)V");
_get_screen_orientation = p_env->GetMethodID(cls, "getScreenOrientation", "()I");
@@ -165,8 +165,8 @@ float GodotIOJavaWrapper::get_screen_refresh_rate(float fallback) {
return fallback;
}
-Array GodotIOJavaWrapper::get_display_cutouts() {
- Array result;
+TypedArray<Rect2> GodotIOJavaWrapper::get_display_cutouts() {
+ TypedArray<Rect2> result;
ERR_FAIL_NULL_V(_get_display_cutouts, result);
JNIEnv *env = get_jni_env();
ERR_FAIL_NULL_V(env, result);
@@ -214,12 +214,12 @@ bool GodotIOJavaWrapper::has_vk() {
return (_show_keyboard != nullptr) && (_hide_keyboard != nullptr);
}
-void GodotIOJavaWrapper::show_vk(const String &p_existing, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
+void GodotIOJavaWrapper::show_vk(const String &p_existing, int p_type, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
if (_show_keyboard) {
JNIEnv *env = get_jni_env();
ERR_FAIL_NULL(env);
jstring jStr = env->NewStringUTF(p_existing.utf8().get_data());
- env->CallVoidMethod(godot_io_instance, _show_keyboard, jStr, p_multiline, p_max_input_length, p_cursor_start, p_cursor_end);
+ env->CallVoidMethod(godot_io_instance, _show_keyboard, jStr, p_type, p_max_input_length, p_cursor_start, p_cursor_end);
}
}
diff --git a/platform/android/java_godot_io_wrapper.h b/platform/android/java_godot_io_wrapper.h
index aec7d1db97..9a1a877b6f 100644
--- a/platform/android/java_godot_io_wrapper.h
+++ b/platform/android/java_godot_io_wrapper.h
@@ -38,7 +38,7 @@
#include <jni.h>
#include "core/math/rect2i.h"
-#include "core/variant/array.h"
+#include "core/variant/typed_array.h"
#include "string_android.h"
// Class that makes functions in java/src/org/godotengine/godot/GodotIO.java callable from C++
@@ -78,11 +78,11 @@ public:
int get_screen_dpi();
float get_scaled_density();
float get_screen_refresh_rate(float fallback);
- Array get_display_cutouts();
+ TypedArray<Rect2> get_display_cutouts();
Rect2i get_display_safe_area();
String get_unique_id();
bool has_vk();
- void show_vk(const String &p_existing, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end);
+ void show_vk(const String &p_existing, int p_type, int p_max_input_length, int p_cursor_start, int p_cursor_end);
void hide_vk();
int get_vk_height();
void set_vk_height(int p_height);
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index f4de4acfad..422c05e5ce 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -376,12 +376,11 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(
}
// Called on the UI thread
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_scancode, jint p_unicode_char, jboolean p_pressed) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_physical_keycode, jint p_unicode, jboolean p_pressed) {
if (step.get() <= 0) {
return;
}
-
- input_handler->process_key_event(p_keycode, p_scancode, p_unicode_char, p_pressed);
+ input_handler->process_key_event(p_keycode, p_physical_keycode, p_unicode, p_pressed);
}
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z) {
diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h
index de16f197b8..3c48ca0459 100644
--- a/platform/android/java_godot_lib_jni.h
+++ b/platform/android/java_godot_lib_jni.h
@@ -51,7 +51,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FI(JNIEn
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FIFF(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask, jfloat vertical_factor, jfloat horizontal_factor);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jclass clazz, jint p_type, jfloat p_x, jfloat p_y);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubleTap(JNIEnv *env, jclass clazz, jint p_button_mask, jint p_x, jint p_y);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_scancode, jint p_unicode_char, jboolean p_pressed);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_physical_keycode, jint p_unicode, jboolean p_pressed);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jclass clazz, jint p_device, jint p_axis, jfloat p_value);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, jclass clazz, jint p_device, jint p_hat_x, jint p_hat_y);
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 0f551e7f4f..142dc54c45 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -362,7 +362,7 @@ void OS_Android::vibrate_handheld(int p_duration_ms) {
}
String OS_Android::get_config_path() const {
- return get_user_data_dir().plus_file("config");
+ return get_user_data_dir().path_join("config");
}
bool OS_Android::_check_internal_feature_support(const String &p_feature) {
@@ -370,15 +370,15 @@ bool OS_Android::_check_internal_feature_support(const String &p_feature) {
return true;
}
#if defined(__aarch64__)
- if (p_feature == "arm64-v8a") {
+ if (p_feature == "arm64-v8a" || p_feature == "arm64") {
return true;
}
#elif defined(__ARM_ARCH_7A__)
- if (p_feature == "armeabi-v7a" || p_feature == "armeabi") {
+ if (p_feature == "armeabi-v7a" || p_feature == "armeabi" || p_feature == "arm32") {
return true;
}
#elif defined(__arm__)
- if (p_feature == "armeabi") {
+ if (p_feature == "armeabi" || p_feature == "arm") {
return true;
}
#endif
diff --git a/platform/ios/README.md b/platform/ios/README.md
new file mode 100644
index 0000000000..82c275ad31
--- /dev/null
+++ b/platform/ios/README.md
@@ -0,0 +1,14 @@
+# iOS platform port
+
+This folder contains the C++, Objective-C and Objective-C++ code for the iOS
+platform port.
+
+See also [`misc/dist/ios_xcode`](/misc/dist/ios_xcode) folder for the Xcode
+project template used for packaging the iOS export templates.
+
+## Documentation
+
+- [Compiling for iOS](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_ios.html)
+ - Instructions on building this platform port from source.
+- [Exporting for iOS](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_ios.html)
+ - Instructions on using the compiled export templates to export a project.
diff --git a/platform/ios/detect.py b/platform/ios/detect.py
index 67c90b10a0..1a8d24d12d 100644
--- a/platform/ios/detect.py
+++ b/platform/ios/detect.py
@@ -36,12 +36,22 @@ def get_opts():
def get_flags():
return [
+ ("arch", "arm64"), # Default for convenience.
("tools", False),
("use_volk", False),
]
def configure(env):
+ # Validate arch.
+ supported_arches = ["x86_64", "arm64"]
+ if env["arch"] not in supported_arches:
+ print(
+ 'Unsupported CPU architecture "%s" for iOS. Supported architectures are: %s.'
+ % (env["arch"], ", ".join(supported_arches))
+ )
+ sys.exit()
+
## Build type
if env["target"].startswith("release"):
@@ -64,11 +74,6 @@ def configure(env):
env.Append(CCFLAGS=["-flto"])
env.Append(LINKFLAGS=["-flto"])
- ## Architecture
- env["bits"] = "64"
- if env["arch"] != "x86_64":
- env["arch"] = "arm64"
-
## Compiler configuration
# Save this in environment for use by other modules
diff --git a/platform/ios/display_server_ios.h b/platform/ios/display_server_ios.h
index 5dd4d177ea..f3624f24ab 100644
--- a/platform/ios/display_server_ios.h
+++ b/platform/ios/display_server_ios.h
@@ -127,7 +127,7 @@ public:
virtual bool tts_is_speaking() const override;
virtual bool tts_is_paused() const override;
- virtual Array tts_get_voices() const override;
+ virtual TypedArray<Dictionary> tts_get_voices() const override;
virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override;
virtual void tts_pause() override;
@@ -199,7 +199,7 @@ public:
virtual bool screen_is_touchscreen(int p_screen) const override;
- virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) override;
+ virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, VirtualKeyboardType p_type, int p_max_length, int p_cursor_start, int p_cursor_end) override;
virtual void virtual_keyboard_hide() override;
void virtual_keyboard_set_height(int height);
diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm
index 6172940572..74d6bc2e97 100644
--- a/platform/ios/display_server_ios.mm
+++ b/platform/ios/display_server_ios.mm
@@ -128,7 +128,7 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode
}
#endif
- bool keep_screen_on = bool(GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true));
+ bool keep_screen_on = bool(GLOBAL_GET("display/window/energy_saving/keep_screen_on"));
screen_set_keep_on(keep_screen_on);
Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events);
@@ -336,8 +336,8 @@ bool DisplayServerIOS::tts_is_paused() const {
return [tts isPaused];
}
-Array DisplayServerIOS::tts_get_voices() const {
- ERR_FAIL_COND_V(!tts, Array());
+TypedArray<Dictionary> DisplayServerIOS::tts_get_voices() const {
+ ERR_FAIL_COND_V(!tts, TypedArray<Dictionary>());
return [tts getVoices];
}
@@ -585,12 +585,44 @@ bool DisplayServerIOS::screen_is_touchscreen(int p_screen) const {
return true;
}
-void DisplayServerIOS::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) {
+void DisplayServerIOS::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, VirtualKeyboardType p_type, int p_max_length, int p_cursor_start, int p_cursor_end) {
NSString *existingString = [[NSString alloc] initWithUTF8String:p_existing_text.utf8().get_data()];
+ AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeDefault;
+ AppDelegate.viewController.keyboardView.textContentType = nil;
+ switch (p_type) {
+ case KEYBOARD_TYPE_DEFAULT: {
+ AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeDefault;
+ } break;
+ case KEYBOARD_TYPE_MULTILINE: {
+ AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeDefault;
+ } break;
+ case KEYBOARD_TYPE_NUMBER: {
+ AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeNumberPad;
+ } break;
+ case KEYBOARD_TYPE_NUMBER_DECIMAL: {
+ AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeDecimalPad;
+ } break;
+ case KEYBOARD_TYPE_PHONE: {
+ AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypePhonePad;
+ AppDelegate.viewController.keyboardView.textContentType = UITextContentTypeTelephoneNumber;
+ } break;
+ case KEYBOARD_TYPE_EMAIL_ADDRESS: {
+ AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeEmailAddress;
+ AppDelegate.viewController.keyboardView.textContentType = UITextContentTypeEmailAddress;
+ } break;
+ case KEYBOARD_TYPE_PASSWORD: {
+ AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeDefault;
+ AppDelegate.viewController.keyboardView.textContentType = UITextContentTypePassword;
+ } break;
+ case KEYBOARD_TYPE_URL: {
+ AppDelegate.viewController.keyboardView.keyboardType = UIKeyboardTypeWebSearch;
+ AppDelegate.viewController.keyboardView.textContentType = UITextContentTypeURL;
+ } break;
+ }
+
[AppDelegate.viewController.keyboardView
becomeFirstResponderWithString:existingString
- multiline:p_multiline
cursorStart:p_cursor_start
cursorEnd:p_cursor_end];
}
diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp
index 9ca2948542..7aacb2de85 100644
--- a/platform/ios/export/export_plugin.cpp
+++ b/platform/ios/export/export_plugin.cpp
@@ -140,27 +140,27 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photolibrary_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need access to the photo library"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/photolibrary_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/iphone_120x120", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPhone/iPod Touch with Retina display
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/iphone_180x180", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPhone with Retina HD display
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/iphone_120x120", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPhone/iPod Touch with Retina display
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/iphone_180x180", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPhone with Retina HD display
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_76x76", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_152x152", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad with Retina display
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_167x167", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad Pro
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_76x76", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPad
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_152x152", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPad with Retina display
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/ipad_167x167", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Home screen on iPad Pro
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/app_store_1024x1024", PROPERTY_HINT_FILE, "*.png"), "")); // App Store
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/app_store_1024x1024", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // App Store
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/spotlight_40x40", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/spotlight_80x80", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight on devices with Retina display
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/spotlight_40x40", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Spotlight
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "icons/spotlight_80x80", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), "")); // Spotlight on devices with Retina display
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_launch_screen_storyboard"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "storyboard/image_scale_mode", PROPERTY_HINT_ENUM, "Same as Logo,Center,Scale to Fit,Scale to Fill,Scale"), 0));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@2x", PROPERTY_HINT_FILE, "*.png"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@3x", PROPERTY_HINT_FILE, "*.png"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@2x", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@3x", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_custom_bg_color"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::COLOR, "storyboard/custom_bg_color"), Color()));
for (uint64_t i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) {
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, loading_screen_infos[i].preset_key, PROPERTY_HINT_FILE, "*.png"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, loading_screen_infos[i].preset_key, PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), ""));
}
}
@@ -387,13 +387,17 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
String locale_files;
Vector<String> translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations");
if (translations.size() > 0) {
- int index = 0;
+ HashSet<String> languages;
for (const String &E : translations) {
Ref<Translation> tr = ResourceLoader::load(E);
- if (tr.is_valid()) {
- String lang = tr->get_locale();
- locale_files += "D0BCFE4518AEBDA2004A" + itos(index).pad_zeros(4) + " /* " + lang + " */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = " + lang + "; path = " + lang + ".lproj/InfoPlist.strings; sourceTree = \"<group>\"; };";
+ if (tr.is_valid() && tr->get_locale() != "en") {
+ languages.insert(tr->get_locale());
}
+ }
+
+ int index = 0;
+ for (const String &lang : languages) {
+ locale_files += "D0BCFE4518AEBDA2004A" + itos(index).pad_zeros(4) + " /* " + lang + " */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = " + lang + "; path = " + lang + ".lproj/InfoPlist.strings; sourceTree = \"<group>\"; };\n";
index++;
}
}
@@ -402,17 +406,50 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
String locale_files;
Vector<String> translations = ProjectSettings::get_singleton()->get("internationalization/locale/translations");
if (translations.size() > 0) {
- int index = 0;
+ HashSet<String> languages;
for (const String &E : translations) {
Ref<Translation> tr = ResourceLoader::load(E);
- if (tr.is_valid()) {
- String lang = tr->get_locale();
- locale_files += "D0BCFE4518AEBDA2004A" + itos(index).pad_zeros(4) + " /* " + lang + " */,";
+ if (tr.is_valid() && tr->get_locale() != "en") {
+ languages.insert(tr->get_locale());
}
+ }
+
+ int index = 0;
+ for (const String &lang : languages) {
+ locale_files += "D0BCFE4518AEBDA2004A" + itos(index).pad_zeros(4) + " /* " + lang + " */,\n";
index++;
}
}
strnew += lines[i].replace("$pbx_locale_build_reference", locale_files);
+ } else if (lines[i].find("$swift_runtime_migration") != -1) {
+ String value = !p_config.use_swift_runtime ? "" : "LastSwiftMigration = 1250;";
+ strnew += lines[i].replace("$swift_runtime_migration", value) + "\n";
+ } else if (lines[i].find("$swift_runtime_build_settings") != -1) {
+ String value = !p_config.use_swift_runtime ? "" : R"(
+ CLANG_ENABLE_MODULES = YES;
+ SWIFT_OBJC_BRIDGING_HEADER = "$binary/dummy.h";
+ SWIFT_VERSION = 5.0;
+ )";
+ value = value.replace("$binary", p_config.binary_name);
+ strnew += lines[i].replace("$swift_runtime_build_settings", value) + "\n";
+ } else if (lines[i].find("$swift_runtime_fileref") != -1) {
+ String value = !p_config.use_swift_runtime ? "" : R"(
+ 90B4C2AA2680BC560039117A /* dummy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "dummy.h"; sourceTree = "<group>"; };
+ 90B4C2B52680C7E90039117A /* dummy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "dummy.swift"; sourceTree = "<group>"; };
+ )";
+ strnew += lines[i].replace("$swift_runtime_fileref", value) + "\n";
+ } else if (lines[i].find("$swift_runtime_binary_files") != -1) {
+ String value = !p_config.use_swift_runtime ? "" : R"(
+ 90B4C2AA2680BC560039117A /* dummy.h */,
+ 90B4C2B52680C7E90039117A /* dummy.swift */,
+ )";
+ strnew += lines[i].replace("$swift_runtime_binary_files", value) + "\n";
+ } else if (lines[i].find("$swift_runtime_buildfile") != -1) {
+ String value = !p_config.use_swift_runtime ? "" : "90B4C2B62680C7E90039117A /* dummy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90B4C2B52680C7E90039117A /* dummy.swift */; };";
+ strnew += lines[i].replace("$swift_runtime_buildfile", value) + "\n";
+ } else if (lines[i].find("$swift_runtime_build_phase") != -1) {
+ String value = !p_config.use_swift_runtime ? "" : "90B4C2B62680C7E90039117A /* dummy.swift */,";
+ strnew += lines[i].replace("$swift_runtime_build_phase", value) + "\n";
} else {
strnew += lines[i] + "\n";
}
@@ -502,26 +539,27 @@ struct IconInfo {
const char *actual_size_side;
const char *scale;
const char *unscaled_size;
+ const bool force_opaque;
};
static const IconInfo icon_infos[] = {
// Home screen on iPhone
- { "icons/iphone_120x120", "iphone", "Icon-120.png", "120", "2x", "60x60" },
- { "icons/iphone_120x120", "iphone", "Icon-120.png", "120", "3x", "40x40" },
- { "icons/iphone_180x180", "iphone", "Icon-180.png", "180", "3x", "60x60" },
+ { "icons/iphone_120x120", "iphone", "Icon-120.png", "120", "2x", "60x60", false },
+ { "icons/iphone_120x120", "iphone", "Icon-120.png", "120", "3x", "40x40", false },
+ { "icons/iphone_180x180", "iphone", "Icon-180.png", "180", "3x", "60x60", false },
// Home screen on iPad
- { "icons/ipad_76x76", "ipad", "Icon-76.png", "76", "1x", "76x76" },
- { "icons/ipad_152x152", "ipad", "Icon-152.png", "152", "2x", "76x76" },
- { "icons/ipad_167x167", "ipad", "Icon-167.png", "167", "2x", "83.5x83.5" },
+ { "icons/ipad_76x76", "ipad", "Icon-76.png", "76", "1x", "76x76", false },
+ { "icons/ipad_152x152", "ipad", "Icon-152.png", "152", "2x", "76x76", false },
+ { "icons/ipad_167x167", "ipad", "Icon-167.png", "167", "2x", "83.5x83.5", false },
// App Store
- { "icons/app_store_1024x1024", "ios-marketing", "Icon-1024.png", "1024", "1x", "1024x1024" },
+ { "icons/app_store_1024x1024", "ios-marketing", "Icon-1024.png", "1024", "1x", "1024x1024", true },
// Spotlight
- { "icons/spotlight_40x40", "ipad", "Icon-40.png", "40", "1x", "40x40" },
- { "icons/spotlight_80x80", "iphone", "Icon-80.png", "80", "2x", "40x40" },
- { "icons/spotlight_80x80", "ipad", "Icon-80.png", "80", "2x", "40x40" }
+ { "icons/spotlight_40x40", "ipad", "Icon-40.png", "40", "1x", "40x40", false },
+ { "icons/spotlight_80x80", "iphone", "Icon-80.png", "80", "2x", "40x40", false },
+ { "icons/spotlight_80x80", "ipad", "Icon-80.png", "80", "2x", "40x40", false }
};
Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_preset, const String &p_iconset_dir) {
@@ -541,14 +579,17 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr
Ref<Image> img = memnew(Image);
Error err = ImageLoader::load_image(icon_path, img);
if (err != OK) {
- ERR_PRINT("Invalid icon (" + String(info.preset_key) + "): '" + icon_path + "'.");
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Invalid icon (%s): '%s'.", info.preset_key, icon_path));
+ return ERR_UNCONFIGURED;
+ }
+ if (info.force_opaque && img->detect_alpha() != Image::ALPHA_NONE) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Icon (%s) must be opaque.", info.preset_key));
return ERR_UNCONFIGURED;
}
img->resize(side_size, side_size);
err = img->save_png(p_iconset_dir + info.export_name);
if (err) {
- String err_str = String("Failed to export icon(" + String(info.preset_key) + "): '" + icon_path + "'.");
- ERR_PRINT(err_str.utf8().get_data());
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Failed to export icon (%s): '%s'.", info.preset_key, icon_path));
return err;
}
} else {
@@ -556,11 +597,15 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr
Ref<Image> img = memnew(Image);
Error err = ImageLoader::load_image(icon_path, img);
if (err != OK) {
- ERR_PRINT("Invalid icon (" + String(info.preset_key) + "): '" + icon_path + "'.");
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Invalid icon (%s): '%s'.", info.preset_key, icon_path));
+ return ERR_UNCONFIGURED;
+ }
+ if (info.force_opaque && img->detect_alpha() != Image::ALPHA_NONE) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Icon (%s) must be opaque.", info.preset_key));
return ERR_UNCONFIGURED;
}
if (img->get_width() != side_size || img->get_height() != side_size) {
- WARN_PRINT("Icon (" + String(info.preset_key) + "): '" + icon_path + "' has incorrect size (" + String::num_int64(img->get_width()) + "x" + String::num_int64(img->get_height()) + ") and was automatically resized to " + String::num_int64(side_size) + "x" + String::num_int64(side_size) + ".");
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Export Icons"), vformat("Icon (%s): '%s' has incorrect size %s and was automatically resized to %s.", info.preset_key, icon_path, img->get_size(), Vector2i(side_size, side_size)));
img->resize(side_size, side_size);
err = img->save_png(p_iconset_dir + info.export_name);
} else {
@@ -568,8 +613,7 @@ Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_pr
}
if (err) {
- String err_str = String("Failed to export icon(" + String(info.preset_key) + "): '" + icon_path + "'.");
- ERR_PRINT(err_str.utf8().get_data());
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Export Icons"), vformat("Failed to export icon (%s): '%s'.", info.preset_key, icon_path));
return err;
}
}
@@ -605,7 +649,7 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor
if (custom_launch_image_2x.length() > 0 && custom_launch_image_3x.length() > 0) {
Ref<Image> image;
- String image_path = p_dest_dir.plus_file("splash@2x.png");
+ String image_path = p_dest_dir.path_join("splash@2x.png");
image.instantiate();
Error err = image->load(custom_launch_image_2x);
@@ -619,7 +663,7 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor
}
image.unref();
- image_path = p_dest_dir.plus_file("splash@3x.png");
+ image_path = p_dest_dir.path_join("splash@3x.png");
image.instantiate();
err = image->load(custom_launch_image_3x);
@@ -652,8 +696,8 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor
// because Godot's own boot logo uses single image for all resolutions.
// Also not using @1x image, because devices using this image variant
// are not supported by iOS 9, which is minimal target.
- const String splash_png_path_2x = p_dest_dir.plus_file("splash@2x.png");
- const String splash_png_path_3x = p_dest_dir.plus_file("splash@3x.png");
+ const String splash_png_path_2x = p_dest_dir.path_join("splash@2x.png");
+ const String splash_png_path_3x = p_dest_dir.path_join("splash@3x.png");
if (splash->save_png(splash_png_path_2x) != OK) {
return ERR_FILE_CANT_WRITE;
@@ -768,7 +812,7 @@ Error EditorExportPlatformIOS::_walk_dir_recursive(Ref<DirAccess> &p_da, FileHan
dirs.push_back(path);
}
} else {
- Error err = p_handler(current_dir.plus_file(path), p_userdata);
+ Error err = p_handler(current_dir.path_join(path), p_userdata);
if (err) {
p_da->list_dir_end();
return err;
@@ -984,7 +1028,7 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
if (p_is_framework && p_asset.ends_with(".dylib")) {
// For iOS we need to turn .dylib into .framework
// to be able to send application to AppStore
- asset_path = String("dylibs").plus_file(base_dir);
+ asset_path = String("dylibs").path_join(base_dir);
String file_name;
@@ -996,12 +1040,12 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
String framework_name = file_name + ".framework";
- asset_path = asset_path.plus_file(framework_name);
- destination_dir = p_out_dir.plus_file(asset_path);
- destination = destination_dir.plus_file(file_name);
+ asset_path = asset_path.path_join(framework_name);
+ destination_dir = p_out_dir.path_join(asset_path);
+ destination = destination_dir.path_join(file_name);
create_framework = true;
} else if (p_is_framework && (p_asset.ends_with(".framework") || p_asset.ends_with(".xcframework"))) {
- asset_path = String("dylibs").plus_file(base_dir);
+ asset_path = String("dylibs").path_join(base_dir);
String file_name;
@@ -1011,8 +1055,8 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
file_name = *p_custom_file_name;
}
- asset_path = asset_path.plus_file(file_name);
- destination_dir = p_out_dir.plus_file(asset_path);
+ asset_path = asset_path.path_join(file_name);
+ destination_dir = p_out_dir.path_join(asset_path);
destination = destination_dir;
} else {
asset_path = base_dir;
@@ -1025,9 +1069,9 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
file_name = *p_custom_file_name;
}
- destination_dir = p_out_dir.plus_file(asset_path);
- asset_path = asset_path.plus_file(file_name);
- destination = p_out_dir.plus_file(asset_path);
+ destination_dir = p_out_dir.path_join(asset_path);
+ asset_path = asset_path.path_join(file_name);
+ destination = p_out_dir.path_join(asset_path);
}
Ref<DirAccess> filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
@@ -1044,7 +1088,7 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
if (err) {
return err;
}
- IOSExportAsset exported_asset = { binary_name.plus_file(asset_path), p_is_framework, p_should_embed };
+ IOSExportAsset exported_asset = { binary_name.path_join(asset_path), p_is_framework, p_should_embed };
r_exported_assets.push_back(exported_asset);
if (create_framework) {
@@ -1062,7 +1106,7 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
{
List<String> install_name_args;
install_name_args.push_back("-id");
- install_name_args.push_back(String("@rpath").plus_file(framework_name).plus_file(file_name));
+ install_name_args.push_back(String("@rpath").path_join(framework_name).path_join(file_name));
install_name_args.push_back(destination);
OS::get_singleton()->execute("install_name_tool", install_name_args);
@@ -1097,7 +1141,7 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
String info_plist = info_plist_format.replace("$name", file_name);
- Ref<FileAccess> f = FileAccess::open(destination_dir.plus_file("Info.plist"), FileAccess::WRITE);
+ Ref<FileAccess> f = FileAccess::open(destination_dir.path_join("Info.plist"), FileAccess::WRITE);
if (f.is_valid()) {
f->store_string(info_plist);
}
@@ -1298,6 +1342,10 @@ Error EditorExportPlatformIOS::_export_ios_plugins(const Ref<EditorExportPreset>
plugin_initialization_cpp_code += "\t" + initialization_method;
plugin_deinitialization_cpp_code += "\t" + deinitialization_method;
+
+ if (plugin.use_swift_runtime) {
+ p_config_data.use_swift_runtime = true;
+ }
}
// Updating `Info.plist`
@@ -1479,7 +1527,8 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
"",
"",
"",
- Vector<String>()
+ Vector<String>(),
+ false
};
Vector<IOSExportAsset> assets;
@@ -1528,8 +1577,6 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
//write
- file = file.replace_first("ios/", "");
-
if (files_to_parse.has(file)) {
_fix_config_file(p_preset, data, config_data, p_debug);
} else if (file.begins_with("libgodot.ios")) {
@@ -1619,27 +1666,31 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
f->store_line("NSPhotoLibraryUsageDescription = \"" + p_preset->get("privacy/photolibrary_usage_description").operator String() + "\";");
}
+ HashSet<String> languages;
for (const String &E : translations) {
Ref<Translation> tr = ResourceLoader::load(E);
- if (tr.is_valid()) {
- String lang = tr->get_locale();
- String fname = dest_dir + binary_name + "/" + lang + ".lproj";
- tmp_app_path->make_dir_recursive(fname);
- Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE);
- f->store_line("/* Localized versions of Info.plist keys */");
- f->store_line("");
- if (appnames.has(lang)) {
- f->store_line("CFBundleDisplayName = \"" + appnames[lang].operator String() + "\";");
- }
- if (camera_usage_descriptions.has(lang)) {
- f->store_line("NSCameraUsageDescription = \"" + camera_usage_descriptions[lang].operator String() + "\";");
- }
- if (microphone_usage_descriptions.has(lang)) {
- f->store_line("NSMicrophoneUsageDescription = \"" + microphone_usage_descriptions[lang].operator String() + "\";");
- }
- if (photolibrary_usage_descriptions.has(lang)) {
- f->store_line("NSPhotoLibraryUsageDescription = \"" + photolibrary_usage_descriptions[lang].operator String() + "\";");
- }
+ if (tr.is_valid() && tr->get_locale() != "en") {
+ languages.insert(tr->get_locale());
+ }
+ }
+
+ for (const String &lang : languages) {
+ String fname = dest_dir + binary_name + "/" + lang + ".lproj";
+ tmp_app_path->make_dir_recursive(fname);
+ Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE);
+ f->store_line("/* Localized versions of Info.plist keys */");
+ f->store_line("");
+ if (appnames.has(lang)) {
+ f->store_line("CFBundleDisplayName = \"" + appnames[lang].operator String() + "\";");
+ }
+ if (camera_usage_descriptions.has(lang)) {
+ f->store_line("NSCameraUsageDescription = \"" + camera_usage_descriptions[lang].operator String() + "\";");
+ }
+ if (microphone_usage_descriptions.has(lang)) {
+ f->store_line("NSMicrophoneUsageDescription = \"" + microphone_usage_descriptions[lang].operator String() + "\";");
+ }
+ if (photolibrary_usage_descriptions.has(lang)) {
+ f->store_line("NSPhotoLibraryUsageDescription = \"" + photolibrary_usage_descriptions[lang].operator String() + "\";");
}
}
}
@@ -1785,7 +1836,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
return OK;
}
-bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+bool EditorExportPlatformIOS::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
String err;
bool valid = false;
@@ -1810,7 +1861,18 @@ bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset
valid = dvalid || rvalid;
r_missing_templates = !valid;
- // Validate the rest of the configuration.
+ if (!err.is_empty()) {
+ r_error = err;
+ }
+
+ return valid;
+}
+
+bool EditorExportPlatformIOS::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const {
+ String err;
+ bool valid = true;
+
+ // Validate the project configuration.
String team_id = p_preset->get("application/app_store_team_id");
if (team_id.length() == 0) {
@@ -1841,10 +1903,14 @@ bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset
EditorExportPlatformIOS::EditorExportPlatformIOS() {
logo = ImageTexture::create_from_image(memnew(Image(_ios_logo)));
plugins_changed.set();
+#ifndef ANDROID_ENABLED
check_for_changes_thread.start(_check_for_changes_poll_thread, this);
+#endif
}
EditorExportPlatformIOS::~EditorExportPlatformIOS() {
+#ifndef ANDROID_ENABLED
quit_request.set();
check_for_changes_thread.wait_to_finish();
+#endif
}
diff --git a/platform/ios/export/export_plugin.h b/platform/ios/export/export_plugin.h
index 07e30c1d00..639f2416a5 100644
--- a/platform/ios/export/export_plugin.h
+++ b/platform/ios/export/export_plugin.h
@@ -57,8 +57,10 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
// Plugins
SafeFlag plugins_changed;
+#ifndef ANDROID_ENABLED
Thread check_for_changes_thread;
SafeFlag quit_request;
+#endif
Mutex plugins_lock;
Vector<PluginConfigIOS> plugins;
@@ -79,6 +81,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
String modules_buildphase;
String modules_buildgrp;
Vector<String> capabilities;
+ bool use_swift_runtime;
};
struct ExportArchitecture {
String name;
@@ -138,6 +141,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
return true;
}
+#ifndef ANDROID_ENABLED
static void _check_for_changes_poll_thread(void *ud) {
EditorExportPlatformIOS *ea = static_cast<EditorExportPlatformIOS *>(ud);
@@ -171,6 +175,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
}
}
}
+#endif
protected:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
@@ -197,7 +202,8 @@ public:
}
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
- virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
virtual void get_platform_features(List<String> *r_features) const override {
r_features->push_back("mobile");
@@ -232,9 +238,9 @@ public:
if (da->current_is_dir()) {
if (p_check_directories) {
- Vector<String> directory_files = list_plugin_config_files(p_path.plus_file(file), false);
+ Vector<String> directory_files = list_plugin_config_files(p_path.path_join(file), false);
for (int i = 0; i < directory_files.size(); ++i) {
- dir_files.push_back(file.plus_file(directory_files[i]));
+ dir_files.push_back(file.path_join(directory_files[i]));
}
}
@@ -254,7 +260,7 @@ public:
static Vector<PluginConfigIOS> get_plugins() {
Vector<PluginConfigIOS> loaded_plugins;
- String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().plus_file("ios/plugins");
+ String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().path_join("ios/plugins");
if (DirAccess::exists(plugins_dir)) {
Vector<String> plugins_filenames = list_plugin_config_files(plugins_dir, true);
@@ -262,7 +268,7 @@ public:
if (!plugins_filenames.is_empty()) {
Ref<ConfigFile> config_file = memnew(ConfigFile);
for (int i = 0; i < plugins_filenames.size(); i++) {
- PluginConfigIOS config = PluginConfigIOS::load_plugin_config(config_file, plugins_dir.plus_file(plugins_filenames[i]));
+ PluginConfigIOS config = PluginConfigIOS::load_plugin_config(config_file, plugins_dir.path_join(plugins_filenames[i]));
if (config.valid_config) {
loaded_plugins.push_back(config);
} else {
diff --git a/platform/ios/export/godot_plugin_config.cpp b/platform/ios/export/godot_plugin_config.cpp
index 9118b95337..42797d449b 100644
--- a/platform/ios/export/godot_plugin_config.cpp
+++ b/platform/ios/export/godot_plugin_config.cpp
@@ -46,7 +46,7 @@ String PluginConfigIOS::resolve_local_dependency_path(String plugin_config_dir,
}
String res_path = ProjectSettings::get_singleton()->globalize_path("res://");
- absolute_path = plugin_config_dir.plus_file(dependency_path);
+ absolute_path = plugin_config_dir.path_join(dependency_path);
return absolute_path.replace(res_path, "res://");
}
@@ -64,7 +64,7 @@ String PluginConfigIOS::resolve_system_dependency_path(String dependency_path) {
String system_path = "/System/Library/Frameworks";
- return system_path.plus_file(dependency_path);
+ return system_path.path_join(dependency_path);
}
Vector<String> PluginConfigIOS::resolve_local_dependencies(String plugin_config_dir, Vector<String> p_paths) {
@@ -121,8 +121,8 @@ bool PluginConfigIOS::validate_plugin(PluginConfigIOS &plugin_config) {
String file_path = plugin_config.binary.get_base_dir();
String file_name = plugin_config.binary.get_basename().get_file();
String file_extension = plugin_config.binary.get_extension();
- String release_file_name = file_path.plus_file(file_name + ".release." + file_extension);
- String debug_file_name = file_path.plus_file(file_name + ".debug." + file_extension);
+ String release_file_name = file_path.path_join(file_name + ".release." + file_extension);
+ String debug_file_name = file_path.path_join(file_name + ".debug." + file_extension);
if ((plugin_extension == "a" && FileAccess::exists(release_file_name) && FileAccess::exists(debug_file_name)) ||
(plugin_extension == "xcframework" && DirAccess::exists(release_file_name) && DirAccess::exists(debug_file_name))) {
@@ -144,7 +144,7 @@ String PluginConfigIOS::get_plugin_main_binary(PluginConfigIOS &plugin_config, b
String plugin_extension = plugin_config.binary.get_extension();
String plugin_file = plugin_name_prefix + "." + (p_debug ? "debug" : "release") + "." + plugin_extension;
- return plugin_binary_dir.plus_file(plugin_file);
+ return plugin_binary_dir.path_join(plugin_file);
}
uint64_t PluginConfigIOS::get_plugin_modification_time(const PluginConfigIOS &plugin_config, const String &config_path) {
@@ -156,8 +156,8 @@ uint64_t PluginConfigIOS::get_plugin_modification_time(const PluginConfigIOS &pl
String file_path = plugin_config.binary.get_base_dir();
String file_name = plugin_config.binary.get_basename().get_file();
String plugin_extension = plugin_config.binary.get_extension();
- String release_file_name = file_path.plus_file(file_name + ".release." + plugin_extension);
- String debug_file_name = file_path.plus_file(file_name + ".debug." + plugin_extension);
+ String release_file_name = file_path.path_join(file_name + ".release." + plugin_extension);
+ String debug_file_name = file_path.path_join(file_name + ".debug." + plugin_extension);
last_updated = MAX(last_updated, FileAccess::get_modified_time(release_file_name));
last_updated = MAX(last_updated, FileAccess::get_modified_time(debug_file_name));
@@ -184,6 +184,7 @@ PluginConfigIOS PluginConfigIOS::load_plugin_config(Ref<ConfigFile> config_file,
String config_base_dir = path.get_base_dir();
plugin_config.name = config_file->get_value(PluginConfigIOS::CONFIG_SECTION, PluginConfigIOS::CONFIG_NAME_KEY, String());
+ plugin_config.use_swift_runtime = config_file->get_value(PluginConfigIOS::CONFIG_SECTION, PluginConfigIOS::CONFIG_USE_SWIFT_KEY, false);
plugin_config.initialization_method = config_file->get_value(PluginConfigIOS::CONFIG_SECTION, PluginConfigIOS::CONFIG_INITIALIZE_KEY, String());
plugin_config.deinitialization_method = config_file->get_value(PluginConfigIOS::CONFIG_SECTION, PluginConfigIOS::CONFIG_DEINITIALIZE_KEY, String());
diff --git a/platform/ios/export/godot_plugin_config.h b/platform/ios/export/godot_plugin_config.h
index 5ca8b05b42..98e8456ed5 100644
--- a/platform/ios/export/godot_plugin_config.h
+++ b/platform/ios/export/godot_plugin_config.h
@@ -39,6 +39,7 @@
The `config` section and fields are required and defined as follow:
- **name**: name of the plugin
- **binary**: path to static `.a` library
+- **use_swift_runtime**: optional boolean field used to determine if Swift runtime is used
The `dependencies` and fields are optional.
- **linked**: dependencies that should only be linked.
@@ -57,6 +58,7 @@ struct PluginConfigIOS {
inline static const char *CONFIG_SECTION = "config";
inline static const char *CONFIG_NAME_KEY = "name";
inline static const char *CONFIG_BINARY_KEY = "binary";
+ inline static const char *CONFIG_USE_SWIFT_KEY = "use_swift_runtime";
inline static const char *CONFIG_INITIALIZE_KEY = "initialization";
inline static const char *CONFIG_DEINITIALIZE_KEY = "deinitialization";
@@ -93,6 +95,7 @@ struct PluginConfigIOS {
// Required config section
String name;
String binary;
+ bool use_swift_runtime;
String initialization_method;
String deinitialization_method;
diff --git a/platform/ios/keyboard_input_view.h b/platform/ios/keyboard_input_view.h
index 33fa5d571a..fc34e6a11b 100644
--- a/platform/ios/keyboard_input_view.h
+++ b/platform/ios/keyboard_input_view.h
@@ -32,6 +32,6 @@
@interface GodotKeyboardInputView : UITextView
-- (BOOL)becomeFirstResponderWithString:(NSString *)existingString multiline:(BOOL)flag cursorStart:(NSInteger)start cursorEnd:(NSInteger)end;
+- (BOOL)becomeFirstResponderWithString:(NSString *)existingString cursorStart:(NSInteger)start cursorEnd:(NSInteger)end;
@end
diff --git a/platform/ios/keyboard_input_view.mm b/platform/ios/keyboard_input_view.mm
index 76e3f23c9d..f031a1de22 100644
--- a/platform/ios/keyboard_input_view.mm
+++ b/platform/ios/keyboard_input_view.mm
@@ -84,7 +84,7 @@
return YES;
}
-- (BOOL)becomeFirstResponderWithString:(NSString *)existingString multiline:(BOOL)flag cursorStart:(NSInteger)start cursorEnd:(NSInteger)end {
+- (BOOL)becomeFirstResponderWithString:(NSString *)existingString cursorStart:(NSInteger)start cursorEnd:(NSInteger)end {
self.text = existingString;
self.previousText = existingString;
diff --git a/platform/ios/platform_config.h b/platform/ios/platform_config.h
index fed77d8932..3af08b0d65 100644
--- a/platform/ios/platform_config.h
+++ b/platform/ios/platform_config.h
@@ -32,8 +32,6 @@
#define OPENGL_INCLUDE_H <ES3/gl.h>
-#define PLATFORM_REFCOUNT
-
#define PTHREAD_RENAME_SELF
#define _weakify(var) __weak typeof(var) GDWeak_##var = var;
diff --git a/platform/javascript/README.md b/platform/javascript/README.md
deleted file mode 100644
index f181bea9e0..0000000000
--- a/platform/javascript/README.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# HTML5 platform port
-
-This folder contains the C++ and JavaScript code for the HTML5/WebAssembly platform port,
-compiled using [Emscripten](https://emscripten.org/).
-
-It also contains a ESLint linting setup (see [`package.json`](package.json)).
-
-See also [`misc/dist/html`](/misc/dist/html) folder for files used by this platform
-such as the HTML5 shell.
-
-## Artwork license
-
-[`logo.png`](logo.png) and [`run_icon.png`](run_icon.png) are licensed under
-[Creative Commons Attribution 3.0 Unported](https://www.w3.org/html/logo/faq.html#how-licenced)
-per the HTML5 logo usage guidelines.
diff --git a/platform/linuxbsd/README.md b/platform/linuxbsd/README.md
index 0d3fb37be5..efa8682062 100644
--- a/platform/linuxbsd/README.md
+++ b/platform/linuxbsd/README.md
@@ -2,10 +2,20 @@
This folder contains the C++ code for the Linux/*BSD platform port.
+See also [`misc/dist/linux`](/misc/dist/linux) folder for additional files
+used by this platform.
+
+## Documentation
+
+- [Compiling for Linux/*BSD](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_linuxbsd.html)
+ - Instructions on building this platform port from source.
+- [Exporting for Linux/*BSD](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_linux.html)
+ - Instructions on using the compiled export templates to export a project.
+
## Artwork license
[`logo.png`](logo.png) is derived from the [Linux logo](https://isc.tamu.edu/~lewing/linux/):
> Permission to use and/or modify this image is granted provided you acknowledge me
- <lewing@isc.tamu.edu> and [The GIMP](https://isc.tamu.edu/~lewing/gimp/)
- if someone asks.
+> <lewing@isc.tamu.edu> and [The GIMP](https://isc.tamu.edu/~lewing/gimp/)
+> if someone asks.
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 00e2b9e6eb..dd829bdb9b 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -2,6 +2,7 @@ import os
import platform
import sys
from methods import get_compiler_version, using_gcc
+from platform_methods import detect_arch
def is_active():
@@ -52,10 +53,21 @@ def get_opts():
def get_flags():
- return []
+ return [
+ ("arch", detect_arch()),
+ ]
def configure(env):
+ # Validate arch.
+ supported_arches = ["x86_32", "x86_64", "arm32", "arm64", "rv64", "ppc32", "ppc64"]
+ if env["arch"] not in supported_arches:
+ print(
+ 'Unsupported CPU architecture "%s" for Linux / *BSD. Supported architectures are: %s.'
+ % (env["arch"], ", ".join(supported_arches))
+ )
+ sys.exit()
+
## Build type
if env["target"] == "release":
@@ -80,23 +92,7 @@ def configure(env):
env.Prepend(CCFLAGS=["-g3"])
env.Append(LINKFLAGS=["-rdynamic"])
- ## Architecture
-
- is64 = sys.maxsize > 2**32
- if env["bits"] == "default":
- env["bits"] = "64" if is64 else "32"
-
- machines = {
- "riscv64": "rv64",
- "ppc64le": "ppc64",
- "ppc64": "ppc64",
- "ppcle": "ppc",
- "ppc": "ppc",
- }
-
- if env["arch"] == "" and platform.machine() in machines:
- env["arch"] = machines[platform.machine()]
-
+ # CPU architecture flags.
if env["arch"] == "rv64":
# G = General-purpose extensions, C = Compression extension (very common).
env.Append(CCFLAGS=["-march=rv64gc"])
@@ -262,8 +258,7 @@ def configure(env):
env["builtin_libvorbis"] = False # Needed to link against system libtheora
env.ParseConfig("pkg-config theora theoradec --cflags --libs")
else:
- list_of_x86 = ["x86_64", "x86", "i386", "i586"]
- if any(platform.machine() in s for s in list_of_x86):
+ if env["arch"] in ["x86_64", "x86_32"]:
env["x86_libtheora_opt_gcc"] = True
if not env["builtin_libvorbis"]:
@@ -392,7 +387,9 @@ def configure(env):
import subprocess
import re
- linker_version_str = subprocess.check_output([env.subst(env["LINK"]), "-Wl,--version"]).decode("utf-8")
+ linker_version_str = subprocess.check_output(
+ [env.subst(env["LINK"]), "-Wl,--version"] + env.subst(env["LINKFLAGS"])
+ ).decode("utf-8")
gnu_ld_version = re.search("^GNU ld [^$]*(\d+\.\d+)$", linker_version_str, re.MULTILINE)
if not gnu_ld_version:
print(
@@ -405,11 +402,12 @@ def configure(env):
env.Append(LINKFLAGS=["-T", "platform/linuxbsd/pck_embed.legacy.ld"])
## Cross-compilation
-
- if is64 and env["bits"] == "32":
+ # TODO: Support cross-compilation on architectures other than x86.
+ host_is_64_bit = sys.maxsize > 2**32
+ if host_is_64_bit and env["arch"] == "x86_32":
env.Append(CCFLAGS=["-m32"])
env.Append(LINKFLAGS=["-m32", "-L/usr/lib/i386-linux-gnu"])
- elif not is64 and env["bits"] == "64":
+ elif not host_is_64_bit and env["arch"] == "x86_64":
env.Append(CCFLAGS=["-m64"])
env.Append(LINKFLAGS=["-m64", "-L/usr/lib/i686-linux-gnu"])
diff --git a/platform/linuxbsd/detect_prime_x11.cpp b/platform/linuxbsd/detect_prime_x11.cpp
index 42b7f68a5e..fb833ab5e6 100644
--- a/platform/linuxbsd/detect_prime_x11.cpp
+++ b/platform/linuxbsd/detect_prime_x11.cpp
@@ -177,6 +177,11 @@ int detect_prime() {
} else {
// In child, exit() here will not quit the engine.
+ // Prevent false leak reports as we will not be properly
+ // cleaning up these processes, and fork() makes a copy
+ // of all globals.
+ CoreGlobals::leak_reporting_enabled = false;
+
char string[201];
close(fdset[0]);
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 3409e43ba5..017fc3e3a2 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -322,8 +322,8 @@ bool DisplayServerX11::tts_is_paused() const {
return tts->is_paused();
}
-Array DisplayServerX11::tts_get_voices() const {
- ERR_FAIL_COND_V(!tts, Array());
+TypedArray<Dictionary> DisplayServerX11::tts_get_voices() const {
+ ERR_FAIL_COND_V(!tts, TypedArray<Dictionary>());
return tts->get_voices();
}
@@ -1522,11 +1522,15 @@ void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent
XSetTransientForHint(x11_display, wd_window.x11_window, None);
+ XWindowAttributes xwa;
+ XSync(x11_display, False);
+ XGetWindowAttributes(x11_display, wd_parent.x11_window, &xwa);
+
// Set focus to parent sub window to avoid losing all focus when closing a nested sub-menu.
// 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.no_focus && !wd_window.is_popup && wd_window.focused) {
- if (!wd_parent.no_focus && !wd_window.is_popup) {
+ if ((xwa.map_state == IsViewable) && !wd_parent.no_focus && !wd_window.is_popup) {
XSetInputFocus(x11_display, wd_parent.x11_window, RevertToPointerRoot, CurrentTime);
}
}
@@ -1865,6 +1869,14 @@ bool DisplayServerX11::_window_fullscreen_check(WindowID p_window) const {
return retval;
}
+void DisplayServerX11::_validate_fullscreen_on_map(WindowID p_window) {
+ const WindowData &wd = windows[p_window];
+ if (wd.fullscreen && !_window_fullscreen_check(p_window)) {
+ // Unmapped fullscreen attempt didn't take effect, redo...
+ _set_wm_fullscreen(p_window, true);
+ }
+}
+
bool DisplayServerX11::window_is_maximize_allowed(WindowID p_window) const {
_THREAD_SAFE_METHOD_
return _window_maximize_check(p_window, "_NET_WM_ALLOWED_ACTIONS");
@@ -3646,10 +3658,17 @@ void DisplayServerX11::process_events() {
const WindowData &wd = windows[window_id];
+ // Have we failed to set fullscreen while the window was unmapped?
+ _validate_fullscreen_on_map(window_id);
+
+ XWindowAttributes xwa;
+ XSync(x11_display, False);
+ XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
+
// 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.no_focus && !wd.is_popup) {
+ if ((xwa.map_state == IsViewable) && !wd.no_focus && !wd.is_popup) {
XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime);
}
} break;
@@ -4982,6 +5001,9 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
XNextEvent(x11_display, &xevent);
if (xevent.type == ConfigureNotify) {
_window_changed(&xevent);
+ } else if (xevent.type == MapNotify) {
+ // Have we failed to set fullscreen while the window was unmapped?
+ _validate_fullscreen_on_map(main_window);
}
}
@@ -4991,7 +5013,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
#ifdef DBUS_ENABLED
screensaver = memnew(FreeDesktopScreenSaver);
- screen_set_keep_on(GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true));
+ screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on"));
#endif
r_error = OK;
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index 9ce6a557db..6b9f57d78f 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -268,6 +268,7 @@ class DisplayServerX11 : public DisplayServer {
void _update_real_mouse_position(const WindowData &wd);
bool _window_maximize_check(WindowID p_window, const char *p_atom_name) const;
bool _window_fullscreen_check(WindowID p_window) const;
+ void _validate_fullscreen_on_map(WindowID p_window);
void _update_size_hints(WindowID p_window);
void _set_wm_fullscreen(WindowID p_window, bool p_enabled);
void _set_wm_maximized(WindowID p_window, bool p_enabled);
@@ -308,7 +309,7 @@ public:
#ifdef SPEECHD_ENABLED
virtual bool tts_is_speaking() const override;
virtual bool tts_is_paused() const override;
- virtual Array tts_get_voices() const override;
+ virtual TypedArray<Dictionary> tts_get_voices() const override;
virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override;
virtual void tts_pause() override;
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp
index e306c1054b..61faf3061c 100644
--- a/platform/linuxbsd/os_linuxbsd.cpp
+++ b/platform/linuxbsd/os_linuxbsd.cpp
@@ -65,7 +65,7 @@ void OS_LinuxBSD::alert(const String &p_alert, const String &p_title) {
for (int i = 0; i < path_elems.size(); i++) {
for (uint64_t k = 0; k < sizeof(message_programs) / sizeof(char *); k++) {
- String tested_path = path_elems[i].plus_file(message_programs[k]);
+ String tested_path = path_elems[i].path_join(message_programs[k]);
if (FileAccess::exists(tested_path)) {
program = tested_path;
@@ -368,6 +368,7 @@ Vector<String> OS_LinuxBSD::get_system_fonts() const {
FcPatternDestroy(pattern);
}
FcObjectSetDestroy(object_set);
+ FcConfigDestroy(config);
for (const String &E : font_names) {
ret.push_back(E);
@@ -417,6 +418,8 @@ String OS_LinuxBSD::get_system_font_path(const String &p_font_name, bool p_bold,
FcPatternDestroy(pattern);
}
FcObjectSetDestroy(object_set);
+ FcConfigDestroy(config);
+
return ret;
#else
ERR_FAIL_V_MSG(String(), "Godot was compiled without fontconfig, system font support is disabled.");
@@ -429,10 +432,10 @@ String OS_LinuxBSD::get_config_path() const {
return get_environment("XDG_CONFIG_HOME");
} else {
WARN_PRINT_ONCE("`XDG_CONFIG_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.config` or `.` per the XDG Base Directory specification.");
- return has_environment("HOME") ? get_environment("HOME").plus_file(".config") : ".";
+ return has_environment("HOME") ? get_environment("HOME").path_join(".config") : ".";
}
} else if (has_environment("HOME")) {
- return get_environment("HOME").plus_file(".config");
+ return get_environment("HOME").path_join(".config");
} else {
return ".";
}
@@ -444,10 +447,10 @@ String OS_LinuxBSD::get_data_path() const {
return get_environment("XDG_DATA_HOME");
} else {
WARN_PRINT_ONCE("`XDG_DATA_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.local/share` or `get_config_path()` per the XDG Base Directory specification.");
- return has_environment("HOME") ? get_environment("HOME").plus_file(".local/share") : get_config_path();
+ return has_environment("HOME") ? get_environment("HOME").path_join(".local/share") : get_config_path();
}
} else if (has_environment("HOME")) {
- return get_environment("HOME").plus_file(".local/share");
+ return get_environment("HOME").path_join(".local/share");
} else {
return get_config_path();
}
@@ -459,10 +462,10 @@ String OS_LinuxBSD::get_cache_path() const {
return get_environment("XDG_CACHE_HOME");
} else {
WARN_PRINT_ONCE("`XDG_CACHE_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.cache` or `get_config_path()` per the XDG Base Directory specification.");
- return has_environment("HOME") ? get_environment("HOME").plus_file(".cache") : get_config_path();
+ return has_environment("HOME") ? get_environment("HOME").path_join(".cache") : get_config_path();
}
} else if (has_environment("HOME")) {
- return get_environment("HOME").plus_file(".cache");
+ return get_environment("HOME").path_join(".cache");
} else {
return get_config_path();
}
@@ -516,8 +519,6 @@ String OS_LinuxBSD::get_system_dir(SystemDir p_dir, bool p_shared_storage) const
}
void OS_LinuxBSD::run() {
- force_quit = false;
-
if (!main_loop) {
return;
}
@@ -529,7 +530,7 @@ void OS_LinuxBSD::run() {
//int frames=0;
//uint64_t frame=0;
- while (!force_quit) {
+ while (true) {
DisplayServer::get_singleton()->process_events(); // get rid of pending events
#ifdef JOYDEV_ENABLED
joypad->process_joypads();
@@ -727,7 +728,6 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) {
OS_LinuxBSD::OS_LinuxBSD() {
main_loop = nullptr;
- force_quit = false;
#ifdef PULSEAUDIO_ENABLED
AudioDriverManager::add_driver(&driver_pulseaudio);
diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h
index cc4e91e885..d5b2321316 100644
--- a/platform/linuxbsd/os_linuxbsd.h
+++ b/platform/linuxbsd/os_linuxbsd.h
@@ -43,8 +43,6 @@
class OS_LinuxBSD : public OS_Unix {
virtual void delete_main_loop() override;
- bool force_quit;
-
#ifdef FONTCONFIG_ENABLED
bool font_config_initialized = false;
#endif
diff --git a/platform/macos/README.md b/platform/macos/README.md
new file mode 100644
index 0000000000..feead80736
--- /dev/null
+++ b/platform/macos/README.md
@@ -0,0 +1,19 @@
+# macOS platform port
+
+This folder contains the C++, Objective-C and Objective-C++ code for the macOS
+platform port.
+
+See also [`misc/dist/macos`](/misc/dist/macos) folder for additional files used
+by this platform. [`misc/dist/macos_tools.app`](/misc/dist/macos_tools.app) is
+an `.app` bundle template used for packaging the macOS editor, while
+[`misc/dist/macos_template.app`](/misc/dist/macos_template.app) is used for
+packaging macOS export templates.
+
+## Documentation
+
+- [Compiling for macOS](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_macos.html)
+ - Instructions on building this platform port from source.
+- [Exporting for macOS](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_macos.html)
+ - Instructions on using the compiled export templates to export a project.
+- [Running Godot apps on macOS](https://docs.godotengine.org/en/latest/tutorials/export/running_on_macos.html)
+ - Instructions on running Godot projects on macOS.
diff --git a/platform/macos/detect.py b/platform/macos/detect.py
index 20e7afa772..e5bcb46b02 100644
--- a/platform/macos/detect.py
+++ b/platform/macos/detect.py
@@ -1,6 +1,7 @@
import os
import sys
from methods import detect_darwin_sdk_path
+from platform_methods import detect_arch
def is_active():
@@ -37,6 +38,7 @@ def get_opts():
def get_flags():
return [
+ ("arch", detect_arch()),
("use_volk", False),
]
@@ -71,6 +73,15 @@ def get_mvk_sdk_path():
def configure(env):
+ # Validate arch.
+ supported_arches = ["x86_64", "arm64"]
+ if env["arch"] not in supported_arches:
+ print(
+ 'Unsupported CPU architecture "%s" for macOS. Supported architectures are: %s.'
+ % (env["arch"], ", ".join(supported_arches))
+ )
+ sys.exit()
+
## Build type
if env["target"] == "release":
@@ -96,25 +107,20 @@ def configure(env):
env.Prepend(CCFLAGS=["-g3"])
env.Prepend(LINKFLAGS=["-Xlinker", "-no_deduplicate"])
- ## Architecture
-
- # macOS no longer runs on 32-bit since 10.7 which is unsupported since 2014
- # As such, we only support 64-bit
- env["bits"] = "64"
-
## Compiler configuration
# Save this in environment for use by other modules
if "OSXCROSS_ROOT" in os.environ:
env["osxcross"] = True
+ # CPU architecture.
if env["arch"] == "arm64":
- print("Building for macOS 11.0+, platform arm64.")
+ print("Building for macOS 11.0+.")
env.Append(ASFLAGS=["-arch", "arm64", "-mmacosx-version-min=11.0"])
env.Append(CCFLAGS=["-arch", "arm64", "-mmacosx-version-min=11.0"])
env.Append(LINKFLAGS=["-arch", "arm64", "-mmacosx-version-min=11.0"])
- else:
- print("Building for macOS 10.12+, platform x86_64.")
+ elif env["arch"] == "x86_64":
+ print("Building for macOS 10.12+.")
env.Append(ASFLAGS=["-arch", "x86_64", "-mmacosx-version-min=10.12"])
env.Append(CCFLAGS=["-arch", "x86_64", "-mmacosx-version-min=10.12"])
env.Append(LINKFLAGS=["-arch", "x86_64", "-mmacosx-version-min=10.12"])
@@ -185,9 +191,8 @@ def configure(env):
## Dependencies
- if env["builtin_libtheora"]:
- if env["arch"] != "arm64":
- env["x86_libtheora_opt_gcc"] = True
+ if env["builtin_libtheora"] and env["arch"] == "x86_64":
+ env["x86_libtheora_opt_gcc"] = True
## Flags
diff --git a/platform/macos/dir_access_macos.h b/platform/macos/dir_access_macos.h
index 1ac1b995de..920e69ef3e 100644
--- a/platform/macos/dir_access_macos.h
+++ b/platform/macos/dir_access_macos.h
@@ -43,12 +43,12 @@
class DirAccessMacOS : public DirAccessUnix {
protected:
- virtual String fix_unicode_name(const char *p_name) const;
+ virtual String fix_unicode_name(const char *p_name) const override;
- virtual int get_drive_count();
- virtual String get_drive(int p_drive);
+ virtual int get_drive_count() override;
+ virtual String get_drive(int p_drive) override;
- virtual bool is_hidden(const String &p_name);
+ virtual bool is_hidden(const String &p_name) override;
};
#endif // UNIX ENABLED || LIBC_FILEIO_ENABLED
diff --git a/platform/macos/dir_access_macos.mm b/platform/macos/dir_access_macos.mm
index 94d937a7dc..3373cada1f 100644
--- a/platform/macos/dir_access_macos.mm
+++ b/platform/macos/dir_access_macos.mm
@@ -69,7 +69,7 @@ String DirAccessMacOS::get_drive(int p_drive) {
}
bool DirAccessMacOS::is_hidden(const String &p_name) {
- String f = get_current_dir().plus_file(p_name);
+ String f = get_current_dir().path_join(p_name);
NSURL *url = [NSURL fileURLWithPath:@(f.utf8().get_data())];
NSNumber *hidden = nil;
if (![url getResourceValue:&hidden forKey:NSURLIsHiddenKey error:nil]) {
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index 41031ec81b..a08667a259 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -50,6 +50,7 @@
#import <ApplicationServices/ApplicationServices.h>
#import <CoreVideo/CoreVideo.h>
#import <Foundation/Foundation.h>
+#import <IOKit/pwr_mgt/IOPMLib.h>
#undef BitMap
#undef CursorShape
@@ -171,6 +172,8 @@ private:
HashMap<WindowID, WindowData> windows;
+ IOPMAssertionID screen_keep_on_assertion = kIOPMNullAssertionID;
+
const NSMenu *_get_menu_root(const String &p_menu_root) const;
NSMenu *_get_menu_root(const String &p_menu_root);
@@ -193,6 +196,9 @@ private:
static NSCursor *_cursor_from_selector(SEL p_selector, SEL p_fallback = nil);
+ bool _has_help_menu() const;
+ NSMenuItem *_menu_add_item(const String &p_menu_root, const String &p_label, Key p_accel, int p_index, int *r_out);
+
public:
NSMenu *get_dock_menu() const;
void menu_callback(id p_sender);
@@ -221,15 +227,15 @@ public:
virtual bool has_feature(Feature p_feature) const override;
virtual String get_name() const override;
- virtual void global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
- virtual void global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
- virtual void global_menu_add_icon_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
- virtual void global_menu_add_icon_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
- virtual void global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
- virtual void global_menu_add_icon_radio_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
- virtual void global_menu_add_multistate_item(const String &p_menu_root, const String &p_label, int p_max_states, int p_default_state, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
- virtual void global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu, int p_index = -1) override;
- virtual void global_menu_add_separator(const String &p_menu_root, int p_index = -1) override;
+ virtual int global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
+ virtual int global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
+ virtual int global_menu_add_icon_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
+ virtual int global_menu_add_icon_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
+ virtual int global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
+ virtual int global_menu_add_icon_radio_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
+ virtual int global_menu_add_multistate_item(const String &p_menu_root, const String &p_label, int p_max_states, int p_default_state, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
+ virtual int global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu, int p_index = -1) override;
+ virtual int global_menu_add_separator(const String &p_menu_root, int p_index = -1) override;
virtual int global_menu_get_item_index_from_text(const String &p_menu_root, const String &p_text) const override;
virtual int global_menu_get_item_index_from_tag(const String &p_menu_root, const Variant &p_tag) const override;
@@ -247,6 +253,7 @@ public:
virtual int global_menu_get_item_state(const String &p_menu_root, int p_idx) const override;
virtual int global_menu_get_item_max_states(const String &p_menu_root, int p_idx) const override;
virtual Ref<Texture2D> global_menu_get_item_icon(const String &p_menu_root, int p_idx) const override;
+ virtual int global_menu_get_item_indentation_level(const String &p_menu_root, int p_idx) const override;
virtual void global_menu_set_item_checked(const String &p_menu_root, int p_idx, bool p_checked) override;
virtual void global_menu_set_item_checkable(const String &p_menu_root, int p_idx, bool p_checkable) override;
@@ -261,6 +268,7 @@ public:
virtual void global_menu_set_item_state(const String &p_menu_root, int p_idx, int p_state) override;
virtual void global_menu_set_item_max_states(const String &p_menu_root, int p_idx, int p_max_states) override;
virtual void global_menu_set_item_icon(const String &p_menu_root, int p_idx, const Ref<Texture2D> &p_icon) override;
+ virtual void global_menu_set_item_indentation_level(const String &p_menu_root, int p_idx, int p_level) override;
virtual int global_menu_get_item_count(const String &p_menu_root) const override;
@@ -269,7 +277,7 @@ public:
virtual bool tts_is_speaking() const override;
virtual bool tts_is_paused() const override;
- virtual Array tts_get_voices() const override;
+ virtual TypedArray<Dictionary> tts_get_voices() const override;
virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override;
virtual void tts_pause() override;
@@ -299,6 +307,8 @@ public:
virtual float screen_get_max_scale() const override;
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
+ virtual void screen_set_keep_on(bool p_enable) override;
+ virtual bool screen_is_kept_on() const override;
virtual Vector<int> get_window_list() const override;
@@ -367,6 +377,11 @@ public:
virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override;
virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override;
+ virtual bool window_maximize_on_title_dbl_click() const override;
+ virtual bool window_minimize_on_title_dbl_click() const override;
+
+ virtual Vector2i window_get_safe_title_margins(WindowID p_window = MAIN_WINDOW_ID) const override;
+
virtual Point2i ime_get_selection() const override;
virtual String ime_get_text() const override;
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index b9bc182dde..b06ae9f27c 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -39,6 +39,7 @@
#include "tts_macos.h"
+#include "core/config/project_settings.h"
#include "core/io/marshalls.h"
#include "core/math/geometry_2d.h"
#include "core/os/keyboard.h"
@@ -62,7 +63,7 @@
const NSMenu *DisplayServerMacOS::_get_menu_root(const String &p_menu_root) const {
const NSMenu *menu = nullptr;
- if (p_menu_root == "") {
+ if (p_menu_root == "" || p_menu_root.to_lower() == "_main") {
// Main menu.
menu = [NSApp mainMenu];
} else if (p_menu_root.to_lower() == "_dock") {
@@ -83,7 +84,7 @@ const NSMenu *DisplayServerMacOS::_get_menu_root(const String &p_menu_root) cons
NSMenu *DisplayServerMacOS::_get_menu_root(const String &p_menu_root) {
NSMenu *menu = nullptr;
- if (p_menu_root == "") {
+ if (p_menu_root == "" || p_menu_root.to_lower() == "_main") {
// Main menu.
menu = [NSApp mainMenu];
} else if (p_menu_root.to_lower() == "_dock") {
@@ -702,6 +703,7 @@ bool DisplayServerMacOS::has_feature(Feature p_feature) const {
//case FEATURE_KEEP_SCREEN_ON:
case FEATURE_SWAP_BUFFERS:
case FEATURE_TEXT_TO_SPEECH:
+ case FEATURE_EXTEND_TO_TITLE:
return true;
default: {
}
@@ -713,18 +715,51 @@ String DisplayServerMacOS::get_name() const {
return "macOS";
}
-void DisplayServerMacOS::global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
- _THREAD_SAFE_METHOD_
+bool DisplayServerMacOS::_has_help_menu() const {
+ if ([NSApp helpMenu]) {
+ return true;
+ } else {
+ NSMenu *menu = [NSApp mainMenu];
+ const NSMenuItem *menu_item = [menu itemAtIndex:[menu numberOfItems] - 1];
+ if (menu_item) {
+ String menu_name = String::utf8([[menu_item title] UTF8String]);
+ if (menu_name == "Help" || menu_name == RTR("Help")) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
+NSMenuItem *DisplayServerMacOS::_menu_add_item(const String &p_menu_root, const String &p_label, Key p_accel, int p_index, int *r_out) {
NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
String keycode = KeyMappingMacOS::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK);
NSMenuItem *menu_item;
- if (p_index != -1) {
- menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index];
+ int item_count = ((menu == [NSApp mainMenu]) && _has_help_menu()) ? [menu numberOfItems] - 1 : [menu numberOfItems];
+ if ((menu == [NSApp mainMenu]) && (p_label == "Help" || p_label == RTR("Help"))) {
+ p_index = [menu numberOfItems];
+ } else if (p_index < 0) {
+ p_index = item_count;
} else {
- menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]];
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_index++;
+ }
+ p_index = CLAMP(p_index, 0, item_count);
}
+ menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index];
+ *r_out = (menu == [NSApp mainMenu]) ? p_index - 1 : p_index;
+ return menu_item;
+ }
+ return nullptr;
+}
+
+int DisplayServerMacOS::global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
+ _THREAD_SAFE_METHOD_
+
+ int out = -1;
+ NSMenuItem *menu_item = _menu_add_item(p_menu_root, p_label, p_accel, p_index, &out);
+ if (menu_item) {
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
obj->meta = p_tag;
@@ -734,20 +769,15 @@ void DisplayServerMacOS::global_menu_add_item(const String &p_menu_root, const S
[menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)];
[menu_item setRepresentedObject:obj];
}
+ return out;
}
-void DisplayServerMacOS::global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
+int DisplayServerMacOS::global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
_THREAD_SAFE_METHOD_
- NSMenu *menu = _get_menu_root(p_menu_root);
- if (menu) {
- String keycode = KeyMappingMacOS::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK);
- NSMenuItem *menu_item;
- if (p_index != -1) {
- menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index];
- } else {
- menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]];
- }
+ int out = -1;
+ NSMenuItem *menu_item = _menu_add_item(p_menu_root, p_label, p_accel, p_index, &out);
+ if (menu_item) {
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
obj->meta = p_tag;
@@ -757,20 +787,15 @@ void DisplayServerMacOS::global_menu_add_check_item(const String &p_menu_root, c
[menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)];
[menu_item setRepresentedObject:obj];
}
+ return out;
}
-void DisplayServerMacOS::global_menu_add_icon_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
+int DisplayServerMacOS::global_menu_add_icon_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
_THREAD_SAFE_METHOD_
- NSMenu *menu = _get_menu_root(p_menu_root);
- if (menu) {
- String keycode = KeyMappingMacOS::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK);
- NSMenuItem *menu_item;
- if (p_index != -1) {
- menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index];
- } else {
- menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]];
- }
+ int out = -1;
+ NSMenuItem *menu_item = _menu_add_item(p_menu_root, p_label, p_accel, p_index, &out);
+ if (menu_item) {
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
obj->meta = p_tag;
@@ -789,20 +814,15 @@ void DisplayServerMacOS::global_menu_add_icon_item(const String &p_menu_root, co
[menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)];
[menu_item setRepresentedObject:obj];
}
+ return out;
}
-void DisplayServerMacOS::global_menu_add_icon_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
+int DisplayServerMacOS::global_menu_add_icon_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
_THREAD_SAFE_METHOD_
- NSMenu *menu = _get_menu_root(p_menu_root);
- if (menu) {
- String keycode = KeyMappingMacOS::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK);
- NSMenuItem *menu_item;
- if (p_index != -1) {
- menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index];
- } else {
- menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]];
- }
+ int out = -1;
+ NSMenuItem *menu_item = _menu_add_item(p_menu_root, p_label, p_accel, p_index, &out);
+ if (menu_item) {
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
obj->meta = p_tag;
@@ -821,20 +841,15 @@ void DisplayServerMacOS::global_menu_add_icon_check_item(const String &p_menu_ro
[menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)];
[menu_item setRepresentedObject:obj];
}
+ return out;
}
-void DisplayServerMacOS::global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
+int DisplayServerMacOS::global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
_THREAD_SAFE_METHOD_
- NSMenu *menu = _get_menu_root(p_menu_root);
- if (menu) {
- String keycode = KeyMappingMacOS::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK);
- NSMenuItem *menu_item;
- if (p_index != -1) {
- menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index];
- } else {
- menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]];
- }
+ int out = -1;
+ NSMenuItem *menu_item = _menu_add_item(p_menu_root, p_label, p_accel, p_index, &out);
+ if (menu_item) {
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
obj->meta = p_tag;
@@ -844,20 +859,15 @@ void DisplayServerMacOS::global_menu_add_radio_check_item(const String &p_menu_r
[menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)];
[menu_item setRepresentedObject:obj];
}
+ return out;
}
-void DisplayServerMacOS::global_menu_add_icon_radio_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
+int DisplayServerMacOS::global_menu_add_icon_radio_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
_THREAD_SAFE_METHOD_
- NSMenu *menu = _get_menu_root(p_menu_root);
- if (menu) {
- String keycode = KeyMappingMacOS::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK);
- NSMenuItem *menu_item;
- if (p_index != -1) {
- menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index];
- } else {
- menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]];
- }
+ int out = -1;
+ NSMenuItem *menu_item = _menu_add_item(p_menu_root, p_label, p_accel, p_index, &out);
+ if (menu_item) {
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
obj->meta = p_tag;
@@ -876,20 +886,31 @@ void DisplayServerMacOS::global_menu_add_icon_radio_check_item(const String &p_m
[menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)];
[menu_item setRepresentedObject:obj];
}
+ return out;
}
-void DisplayServerMacOS::global_menu_add_multistate_item(const String &p_menu_root, const String &p_label, int p_max_states, int p_default_state, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
+int DisplayServerMacOS::global_menu_add_multistate_item(const String &p_menu_root, const String &p_label, int p_max_states, int p_default_state, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
_THREAD_SAFE_METHOD_
NSMenu *menu = _get_menu_root(p_menu_root);
+ int out = -1;
if (menu) {
String keycode = KeyMappingMacOS::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK);
NSMenuItem *menu_item;
- if (p_index != -1) {
- menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index];
+ int item_count = ((menu == [NSApp mainMenu]) && _has_help_menu()) ? [menu numberOfItems] - 1 : [menu numberOfItems];
+ if ((menu == [NSApp mainMenu]) && (p_label == "Help" || p_label == RTR("Help"))) {
+ p_index = [menu numberOfItems];
+ } else if (p_index < 0) {
+ p_index = item_count;
} else {
- menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]];
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_index++;
+ }
+ p_index = CLAMP(p_index, 0, item_count);
}
+ menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index];
+ out = (menu == [NSApp mainMenu]) ? p_index - 1 : p_index;
+
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
obj->meta = p_tag;
@@ -899,44 +920,69 @@ void DisplayServerMacOS::global_menu_add_multistate_item(const String &p_menu_ro
[menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_accel)];
[menu_item setRepresentedObject:obj];
}
+ return out;
}
-void DisplayServerMacOS::global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu, int p_index) {
+int DisplayServerMacOS::global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu, int p_index) {
_THREAD_SAFE_METHOD_
NSMenu *menu = _get_menu_root(p_menu_root);
NSMenu *sub_menu = _get_menu_root(p_submenu);
+ int out = -1;
if (menu && sub_menu) {
if (sub_menu == menu) {
ERR_PRINT("Can't set submenu to self!");
- return;
+ return -1;
}
if ([sub_menu supermenu]) {
ERR_PRINT("Can't set submenu to menu that is already a submenu of some other menu!");
- return;
+ return -1;
}
NSMenuItem *menu_item;
- if (p_index != -1) {
- menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:nil keyEquivalent:@"" atIndex:p_index];
+ int item_count = ((menu == [NSApp mainMenu]) && _has_help_menu()) ? [menu numberOfItems] - 1 : [menu numberOfItems];
+ if ((menu == [NSApp mainMenu]) && (p_label == "Help" || p_label == RTR("Help"))) {
+ p_index = [menu numberOfItems];
+ } else if (p_index < 0) {
+ p_index = item_count;
} else {
- menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:nil keyEquivalent:@""];
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_index++;
+ }
+ p_index = CLAMP(p_index, 0, item_count);
}
+ menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:nil keyEquivalent:@"" atIndex:p_index];
+ out = (menu == [NSApp mainMenu]) ? p_index - 1 : p_index;
+
+ GodotMenuItem *obj = [[GodotMenuItem alloc] init];
+ obj->callback = Callable();
+ obj->checkable_type = CHECKABLE_TYPE_NONE;
+ obj->max_states = 0;
+ obj->state = 0;
+ [menu_item setRepresentedObject:obj];
+
[sub_menu setTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()]];
[menu setSubmenu:sub_menu forItem:menu_item];
}
+ return out;
}
-void DisplayServerMacOS::global_menu_add_separator(const String &p_menu_root, int p_index) {
+int DisplayServerMacOS::global_menu_add_separator(const String &p_menu_root, int p_index) {
_THREAD_SAFE_METHOD_
NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
- if (p_index != -1) {
- [menu insertItem:[NSMenuItem separatorItem] atIndex:p_index];
+ if (menu == [NSApp mainMenu]) { // Do not add separators into main menu.
+ return -1;
+ }
+ if (p_index < 0) {
+ p_index = [menu numberOfItems];
} else {
- [menu addItem:[NSMenuItem separatorItem]];
+ p_index = CLAMP(p_index, 0, [menu numberOfItems]);
}
+ [menu insertItem:[NSMenuItem separatorItem] atIndex:p_index];
+ return p_index;
}
+ return -1;
}
int DisplayServerMacOS::global_menu_get_item_index_from_text(const String &p_menu_root, const String &p_text) const {
@@ -944,7 +990,11 @@ int DisplayServerMacOS::global_menu_get_item_index_from_text(const String &p_men
const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
- return [menu indexOfItemWithTitle:[NSString stringWithUTF8String:p_text.utf8().get_data()]];
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ return [menu indexOfItemWithTitle:[NSString stringWithUTF8String:p_text.utf8().get_data()]] - 1;
+ } else {
+ return [menu indexOfItemWithTitle:[NSString stringWithUTF8String:p_text.utf8().get_data()]];
+ }
}
return -1;
@@ -955,12 +1005,16 @@ int DisplayServerMacOS::global_menu_get_item_index_from_tag(const String &p_menu
const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
- for (NSInteger i = 0; i < [menu numberOfItems]; i++) {
+ for (NSInteger i = (menu == [NSApp mainMenu]) ? 1 : 0; i < [menu numberOfItems]; i++) {
const NSMenuItem *menu_item = [menu itemAtIndex:i];
if (menu_item) {
const GodotMenuItem *obj = [menu_item representedObject];
if (obj && obj->meta == p_tag) {
- return i;
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ return i - 1;
+ } else {
+ return i;
+ }
}
}
}
@@ -974,6 +1028,11 @@ bool DisplayServerMacOS::global_menu_is_item_checked(const String &p_menu_root,
const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
+ ERR_FAIL_COND_V(p_idx < 0, false);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
+ }
+ ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], false);
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
return ([menu_item state] == NSControlStateValueOn);
@@ -987,6 +1046,11 @@ bool DisplayServerMacOS::global_menu_is_item_checkable(const String &p_menu_root
const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
+ ERR_FAIL_COND_V(p_idx < 0, false);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
+ }
+ ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], false);
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
@@ -1003,6 +1067,11 @@ bool DisplayServerMacOS::global_menu_is_item_radio_checkable(const String &p_men
const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
+ ERR_FAIL_COND_V(p_idx < 0, false);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
+ }
+ ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], false);
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
@@ -1019,6 +1088,11 @@ Callable DisplayServerMacOS::global_menu_get_item_callback(const String &p_menu_
const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
+ ERR_FAIL_COND_V(p_idx < 0, Callable());
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
+ }
+ ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], Callable());
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
@@ -1035,6 +1109,11 @@ Variant DisplayServerMacOS::global_menu_get_item_tag(const String &p_menu_root,
const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
+ ERR_FAIL_COND_V(p_idx < 0, Variant());
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
+ }
+ ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], Variant());
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
@@ -1051,6 +1130,11 @@ String DisplayServerMacOS::global_menu_get_item_text(const String &p_menu_root,
const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
+ ERR_FAIL_COND_V(p_idx < 0, String());
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
+ }
+ ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], String());
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
return String::utf8([[menu_item title] UTF8String]);
@@ -1064,6 +1148,11 @@ String DisplayServerMacOS::global_menu_get_item_submenu(const String &p_menu_roo
const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
+ ERR_FAIL_COND_V(p_idx < 0, String());
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
+ }
+ ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], String());
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
const NSMenu *sub_menu = [menu_item submenu];
@@ -1084,6 +1173,11 @@ Key DisplayServerMacOS::global_menu_get_item_accelerator(const String &p_menu_ro
const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
+ ERR_FAIL_COND_V(p_idx < 0, Key::NONE);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
+ }
+ ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], Key::NONE);
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
String ret = String::utf8([[menu_item keyEquivalent] UTF8String]);
@@ -1115,6 +1209,11 @@ bool DisplayServerMacOS::global_menu_is_item_disabled(const String &p_menu_root,
const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
+ ERR_FAIL_COND_V(p_idx < 0, false);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
+ }
+ ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], false);
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
return ![menu_item isEnabled];
@@ -1128,6 +1227,11 @@ String DisplayServerMacOS::global_menu_get_item_tooltip(const String &p_menu_roo
const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
+ ERR_FAIL_COND_V(p_idx < 0, String());
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
+ }
+ ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], String());
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
return String::utf8([[menu_item toolTip] UTF8String]);
@@ -1141,6 +1245,11 @@ int DisplayServerMacOS::global_menu_get_item_state(const String &p_menu_root, in
const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
+ ERR_FAIL_COND_V(p_idx < 0, 0);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
+ }
+ ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], 0);
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
@@ -1157,6 +1266,11 @@ int DisplayServerMacOS::global_menu_get_item_max_states(const String &p_menu_roo
const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
+ ERR_FAIL_COND_V(p_idx < 0, 0);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
+ }
+ ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], 0);
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
@@ -1173,6 +1287,11 @@ Ref<Texture2D> DisplayServerMacOS::global_menu_get_item_icon(const String &p_men
const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
+ ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>());
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
+ }
+ ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], Ref<Texture2D>());
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
@@ -1186,14 +1305,34 @@ Ref<Texture2D> DisplayServerMacOS::global_menu_get_item_icon(const String &p_men
return Ref<Texture2D>();
}
+int DisplayServerMacOS::global_menu_get_item_indentation_level(const String &p_menu_root, int p_idx) const {
+ _THREAD_SAFE_METHOD_
+
+ const NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ ERR_FAIL_COND_V(p_idx < 0, 0);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
+ }
+ ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], 0);
+ const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ return [menu_item indentationLevel];
+ }
+ }
+ return 0;
+}
+
void DisplayServerMacOS::global_menu_set_item_checked(const String &p_menu_root, int p_idx, bool p_checked) {
_THREAD_SAFE_METHOD_
NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
- if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
- return;
+ ERR_FAIL_COND(p_idx < 0);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
}
+ ERR_FAIL_COND(p_idx >= [menu numberOfItems]);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
if (p_checked) {
@@ -1210,12 +1349,15 @@ void DisplayServerMacOS::global_menu_set_item_checkable(const String &p_menu_roo
NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
- if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
- return;
+ ERR_FAIL_COND(p_idx < 0);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
}
+ ERR_FAIL_COND(p_idx >= [menu numberOfItems]);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
+ ERR_FAIL_COND(!obj);
obj->checkable_type = (p_checkable) ? CHECKABLE_TYPE_CHECK_BOX : CHECKABLE_TYPE_NONE;
}
}
@@ -1226,12 +1368,15 @@ void DisplayServerMacOS::global_menu_set_item_radio_checkable(const String &p_me
NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
- if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
- return;
+ ERR_FAIL_COND(p_idx < 0);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
}
+ ERR_FAIL_COND(p_idx >= [menu numberOfItems]);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
+ ERR_FAIL_COND(!obj);
obj->checkable_type = (p_checkable) ? CHECKABLE_TYPE_RADIO_BUTTON : CHECKABLE_TYPE_NONE;
}
}
@@ -1242,12 +1387,15 @@ void DisplayServerMacOS::global_menu_set_item_callback(const String &p_menu_root
NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
- if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
- return;
+ ERR_FAIL_COND(p_idx < 0);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
}
+ ERR_FAIL_COND(p_idx >= [menu numberOfItems]);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
+ ERR_FAIL_COND(!obj);
obj->callback = p_callback;
}
}
@@ -1258,12 +1406,15 @@ void DisplayServerMacOS::global_menu_set_item_tag(const String &p_menu_root, int
NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
- if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
- return;
+ ERR_FAIL_COND(p_idx < 0);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
}
+ ERR_FAIL_COND(p_idx >= [menu numberOfItems]);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
+ ERR_FAIL_COND(!obj);
obj->meta = p_tag;
}
}
@@ -1274,9 +1425,11 @@ void DisplayServerMacOS::global_menu_set_item_text(const String &p_menu_root, in
NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
- if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
- return;
+ ERR_FAIL_COND(p_idx < 0);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
}
+ ERR_FAIL_COND(p_idx >= [menu numberOfItems]);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
[menu_item setTitle:[NSString stringWithUTF8String:p_text.utf8().get_data()]];
@@ -1298,9 +1451,11 @@ void DisplayServerMacOS::global_menu_set_item_submenu(const String &p_menu_root,
ERR_PRINT("Can't set submenu to menu that is already a submenu of some other menu!");
return;
}
- if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
- return;
+ ERR_FAIL_COND(p_idx < 0);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
}
+ ERR_FAIL_COND(p_idx >= [menu numberOfItems]);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
[menu setSubmenu:sub_menu forItem:menu_item];
@@ -1313,9 +1468,11 @@ void DisplayServerMacOS::global_menu_set_item_accelerator(const String &p_menu_r
NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
- if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
- return;
+ ERR_FAIL_COND(p_idx < 0);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
}
+ ERR_FAIL_COND(p_idx >= [menu numberOfItems]);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
[menu_item setKeyEquivalentModifierMask:KeyMappingMacOS::keycode_get_native_mask(p_keycode)];
@@ -1330,9 +1487,11 @@ void DisplayServerMacOS::global_menu_set_item_disabled(const String &p_menu_root
NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
- if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
- return;
+ ERR_FAIL_COND(p_idx < 0);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
}
+ ERR_FAIL_COND(p_idx >= [menu numberOfItems]);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
[menu_item setEnabled:(!p_disabled)];
@@ -1345,9 +1504,11 @@ void DisplayServerMacOS::global_menu_set_item_tooltip(const String &p_menu_root,
NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
- if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
- return;
+ ERR_FAIL_COND(p_idx < 0);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
}
+ ERR_FAIL_COND(p_idx >= [menu numberOfItems]);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
[menu_item setToolTip:[NSString stringWithUTF8String:p_tooltip.utf8().get_data()]];
@@ -1360,15 +1521,16 @@ void DisplayServerMacOS::global_menu_set_item_state(const String &p_menu_root, i
NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
- if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
- return;
+ ERR_FAIL_COND(p_idx < 0);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
}
+ ERR_FAIL_COND(p_idx >= [menu numberOfItems]);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
- if (obj) {
- obj->state = p_state;
- }
+ ERR_FAIL_COND(!obj);
+ obj->state = p_state;
}
}
}
@@ -1378,15 +1540,16 @@ void DisplayServerMacOS::global_menu_set_item_max_states(const String &p_menu_ro
NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
- if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
- return;
+ ERR_FAIL_COND(p_idx < 0);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
}
+ ERR_FAIL_COND(p_idx >= [menu numberOfItems]);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
- if (obj) {
- obj->max_states = p_max_states;
- }
+ ERR_FAIL_COND(!obj);
+ obj->max_states = p_max_states;
}
}
}
@@ -1396,12 +1559,15 @@ void DisplayServerMacOS::global_menu_set_item_icon(const String &p_menu_root, in
NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
- if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
- return;
+ ERR_FAIL_COND(p_idx < 0);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
}
+ ERR_FAIL_COND(p_idx >= [menu numberOfItems]);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
+ ERR_FAIL_COND(!obj);
if (p_icon.is_valid()) {
obj->img = p_icon->get_image();
obj->img = obj->img->duplicate();
@@ -1418,12 +1584,33 @@ void DisplayServerMacOS::global_menu_set_item_icon(const String &p_menu_root, in
}
}
+void DisplayServerMacOS::global_menu_set_item_indentation_level(const String &p_menu_root, int p_idx, int p_level) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ ERR_FAIL_COND(p_idx < 0);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
+ }
+ ERR_FAIL_COND(p_idx >= [menu numberOfItems]);
+ NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ [menu_item setIndentationLevel:p_level];
+ }
+ }
+}
+
int DisplayServerMacOS::global_menu_get_item_count(const String &p_menu_root) const {
_THREAD_SAFE_METHOD_
const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
- return [menu numberOfItems];
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ return [menu numberOfItems] - 1;
+ } else {
+ return [menu numberOfItems];
+ }
} else {
return 0;
}
@@ -1434,9 +1621,11 @@ void DisplayServerMacOS::global_menu_remove_item(const String &p_menu_root, int
NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
- if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not delete Apple menu.
- return;
+ ERR_FAIL_COND(p_idx < 0);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
}
+ ERR_FAIL_COND(p_idx >= [menu numberOfItems]);
[menu removeItemAtIndex:p_idx];
}
}
@@ -1452,6 +1641,9 @@ void DisplayServerMacOS::global_menu_clear(const String &p_menu_root) {
NSMenuItem *menu_item = [menu addItemWithTitle:@"" action:nil keyEquivalent:@""];
[menu setSubmenu:apple_menu forItem:menu_item];
}
+ if (submenu.has(p_menu_root)) {
+ submenu.erase(p_menu_root);
+ }
}
}
@@ -1465,7 +1657,7 @@ bool DisplayServerMacOS::tts_is_paused() const {
return [tts isPaused];
}
-Array DisplayServerMacOS::tts_get_voices() const {
+TypedArray<Dictionary> DisplayServerMacOS::tts_get_voices() const {
ERR_FAIL_COND_V(!tts, Array());
return [tts getVoices];
}
@@ -1891,6 +2083,24 @@ float DisplayServerMacOS::screen_get_refresh_rate(int p_screen) const {
return SCREEN_REFRESH_RATE_FALLBACK;
}
+bool DisplayServerMacOS::screen_is_kept_on() const {
+ return (screen_keep_on_assertion);
+}
+
+void DisplayServerMacOS::screen_set_keep_on(bool p_enable) {
+ if (screen_keep_on_assertion) {
+ IOPMAssertionRelease(screen_keep_on_assertion);
+ screen_keep_on_assertion = kIOPMNullAssertionID;
+ }
+
+ if (p_enable) {
+ String app_name_string = ProjectSettings::get_singleton()->get("application/config/name");
+ NSString *name = [NSString stringWithUTF8String:(app_name_string.is_empty() ? "Godot Engine" : app_name_string.utf8().get_data())];
+ NSString *reason = @"Godot Engine running with display/window/energy_saving/keep_screen_on = true";
+ IOPMAssertionCreateWithDescription(kIOPMAssertPreventUserIdleDisplaySleep, (__bridge CFStringRef)name, (__bridge CFStringRef)reason, (__bridge CFStringRef)reason, nullptr, 0, nullptr, &screen_keep_on_assertion);
+ }
+}
+
Vector<DisplayServer::WindowID> DisplayServerMacOS::get_window_list() const {
_THREAD_SAFE_METHOD_
@@ -2329,6 +2539,45 @@ bool DisplayServerMacOS::window_is_maximize_allowed(WindowID p_window) const {
return true;
}
+bool DisplayServerMacOS::window_maximize_on_title_dbl_click() const {
+ id value = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleActionOnDoubleClick"];
+ if ([value isKindOfClass:[NSString class]]) {
+ return [value isEqualToString:@"Maximize"];
+ }
+ return false;
+}
+
+bool DisplayServerMacOS::window_minimize_on_title_dbl_click() const {
+ id value = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleActionOnDoubleClick"];
+ if ([value isKindOfClass:[NSString class]]) {
+ return [value isEqualToString:@"Minimize"];
+ }
+ return false;
+}
+
+Vector2i DisplayServerMacOS::window_get_safe_title_margins(WindowID p_window) const {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND_V(!windows.has(p_window), Vector2i());
+ const WindowData &wd = windows[p_window];
+
+ float max_x = 0.f;
+ NSButton *cb = [wd.window_object standardWindowButton:NSWindowCloseButton];
+ if (cb) {
+ max_x = MAX(max_x, [cb frame].origin.x + [cb frame].size.width);
+ }
+ NSButton *mb = [wd.window_object standardWindowButton:NSWindowMiniaturizeButton];
+ if (mb) {
+ max_x = MAX(max_x, [mb frame].origin.x + [mb frame].size.width);
+ }
+ NSButton *zb = [wd.window_object standardWindowButton:NSWindowZoomButton];
+ if (zb) {
+ max_x = MAX(max_x, [zb frame].origin.x + [zb frame].size.width);
+ }
+
+ return Vector2i(max_x * screen_get_max_scale(), 0);
+}
+
void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) {
_THREAD_SAFE_METHOD_
@@ -2347,6 +2596,19 @@ void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, Win
[wd.window_object setStyleMask:[wd.window_object styleMask] | NSWindowStyleMaskResizable];
}
} break;
+ case WINDOW_FLAG_EXTEND_TO_TITLE: {
+ NSRect rect = [wd.window_object frame];
+ if (p_enabled) {
+ [wd.window_object setTitlebarAppearsTransparent:YES];
+ [wd.window_object setTitleVisibility:NSWindowTitleHidden];
+ [wd.window_object setStyleMask:[wd.window_object styleMask] | NSWindowStyleMaskFullSizeContentView];
+ } else {
+ [wd.window_object setTitlebarAppearsTransparent:NO];
+ [wd.window_object setTitleVisibility:NSWindowTitleVisible];
+ [wd.window_object setStyleMask:[wd.window_object styleMask] & ~NSWindowStyleMaskFullSizeContentView];
+ }
+ [wd.window_object setFrame:rect display:YES];
+ } break;
case WINDOW_FLAG_BORDERLESS: {
// OrderOut prevents a lose focus bug with the window.
if ([wd.window_object isVisible]) {
@@ -2414,6 +2676,9 @@ bool DisplayServerMacOS::window_get_flag(WindowFlags p_flag, WindowID p_window)
case WINDOW_FLAG_RESIZE_DISABLED: {
return wd.resize_disabled;
} break;
+ case WINDOW_FLAG_EXTEND_TO_TITLE: {
+ return [wd.window_object styleMask] & NSWindowStyleMaskFullSizeContentView;
+ } break;
case WINDOW_FLAG_BORDERLESS: {
return [wd.window_object styleMask] == NSWindowStyleMaskBorderless;
} break;
@@ -3203,7 +3468,7 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM
[apple_menu addItem:[NSMenuItem separatorItem]];
- title = [NSString stringWithFormat:NSLocalizedString(@"Quit %@", nil), nsappname];
+ title = [NSString stringWithFormat:NSLocalizedString(@"\t\tQuit %@", nil), nsappname];
[apple_menu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
// Add items to the menu bar.
@@ -3266,9 +3531,16 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM
RendererCompositorRD::make_current();
}
#endif
+
+ screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on"));
}
DisplayServerMacOS::~DisplayServerMacOS() {
+ if (screen_keep_on_assertion) {
+ IOPMAssertionRelease(screen_keep_on_assertion);
+ screen_keep_on_assertion = kIOPMNullAssertionID;
+ }
+
// Destroy all windows.
for (HashMap<WindowID, WindowData>::Iterator E = windows.begin(); E;) {
HashMap<WindowID, WindowData>::Iterator F = E;
diff --git a/platform/macos/export/codesign.cpp b/platform/macos/export/codesign.cpp
index fd044c00cc..c2bdf555d0 100644
--- a/platform/macos/export/codesign.cpp
+++ b/platform/macos/export/codesign.cpp
@@ -172,7 +172,7 @@ bool CodeSignCodeResources::add_file1(const String &p_root, const String &p_path
f.name = p_path;
f.optional = (found == CRMatch::CR_MATCH_OPTIONAL);
f.nested = false;
- f.hash = hash_sha1_base64(p_root.plus_file(p_path));
+ f.hash = hash_sha1_base64(p_root.path_join(p_path));
print_verbose(vformat("CodeSign/CodeResources: File(V1) %s hash1:%s", f.name, f.hash));
files1.push_back(f);
@@ -182,7 +182,7 @@ bool CodeSignCodeResources::add_file1(const String &p_root, const String &p_path
bool CodeSignCodeResources::add_file2(const String &p_root, const String &p_path) {
CRMatch found = match_rules2(p_path);
if (found == CRMatch::CR_MATCH_NESTED) {
- return add_nested_file(p_root, p_path, p_root.plus_file(p_path));
+ return add_nested_file(p_root, p_path, p_root.path_join(p_path));
}
if (found != CRMatch::CR_MATCH_YES && found != CRMatch::CR_MATCH_OPTIONAL) {
return true; // No match.
@@ -192,8 +192,8 @@ bool CodeSignCodeResources::add_file2(const String &p_root, const String &p_path
f.name = p_path;
f.optional = (found == CRMatch::CR_MATCH_OPTIONAL);
f.nested = false;
- f.hash = hash_sha1_base64(p_root.plus_file(p_path));
- f.hash2 = hash_sha256_base64(p_root.plus_file(p_path));
+ f.hash = hash_sha1_base64(p_root.path_join(p_path));
+ f.hash2 = hash_sha256_base64(p_root.path_join(p_path));
print_verbose(vformat("CodeSign/CodeResources: File(V2) %s hash1:%s hash2:%s", f.name, f.hash, f.hash2));
@@ -214,17 +214,17 @@ bool CodeSignCodeResources::add_nested_file(const String &p_root, const String &
Vector<String> files_to_add;
if (LipO::is_lipo(p_exepath)) {
- String tmp_path_name = EditorPaths::get_singleton()->get_cache_dir().plus_file("_lipo");
+ String tmp_path_name = EditorPaths::get_singleton()->get_cache_dir().path_join("_lipo");
Error err = da->make_dir_recursive(tmp_path_name);
ERR_FAIL_COND_V_MSG(err != OK, false, vformat("CodeSign/CodeResources: Failed to create \"%s\" subfolder.", tmp_path_name));
LipO lip;
if (lip.open_file(p_exepath)) {
for (int i = 0; i < lip.get_arch_count(); i++) {
- if (!lip.extract_arch(i, tmp_path_name.plus_file("_rqexe_" + itos(i)))) {
+ if (!lip.extract_arch(i, tmp_path_name.path_join("_rqexe_" + itos(i)))) {
CLEANUP();
ERR_FAIL_V_MSG(false, "CodeSign/CodeResources: Failed to extract thin binary.");
}
- files_to_add.push_back(tmp_path_name.plus_file("_rqexe_" + itos(i)));
+ files_to_add.push_back(tmp_path_name.path_join("_rqexe_" + itos(i)));
}
}
} else if (MachO::is_macho(p_exepath)) {
@@ -285,7 +285,7 @@ bool CodeSignCodeResources::add_nested_file(const String &p_root, const String &
bool CodeSignCodeResources::add_folder_recursive(const String &p_root, const String &p_path, const String &p_main_exe_path) {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
ERR_FAIL_COND_V(da.is_null(), false);
- Error err = da->change_dir(p_root.plus_file(p_path));
+ Error err = da->change_dir(p_root.path_join(p_path));
ERR_FAIL_COND_V(err != OK, false);
bool ret = true;
@@ -293,27 +293,27 @@ bool CodeSignCodeResources::add_folder_recursive(const String &p_root, const Str
String n = da->get_next();
while (n != String()) {
if (n != "." && n != "..") {
- String path = p_root.plus_file(p_path).plus_file(n);
+ String path = p_root.path_join(p_path).path_join(n);
if (path == p_main_exe_path) {
n = da->get_next();
continue; // Skip main executable.
}
if (da->current_is_dir()) {
- CRMatch found = match_rules2(p_path.plus_file(n));
+ CRMatch found = match_rules2(p_path.path_join(n));
String fmw_ver = "Current"; // Framework version (default).
String info_path;
String main_exe;
bool bundle = false;
- if (da->file_exists(path.plus_file("Contents/Info.plist"))) {
- info_path = path.plus_file("Contents/Info.plist");
- main_exe = path.plus_file("Contents/MacOS");
+ if (da->file_exists(path.path_join("Contents/Info.plist"))) {
+ info_path = path.path_join("Contents/Info.plist");
+ main_exe = path.path_join("Contents/MacOS");
bundle = true;
- } else if (da->file_exists(path.plus_file(vformat("Versions/%s/Resources/Info.plist", fmw_ver)))) {
- info_path = path.plus_file(vformat("Versions/%s/Resources/Info.plist", fmw_ver));
- main_exe = path.plus_file(vformat("Versions/%s", fmw_ver));
+ } else if (da->file_exists(path.path_join(vformat("Versions/%s/Resources/Info.plist", fmw_ver)))) {
+ info_path = path.path_join(vformat("Versions/%s/Resources/Info.plist", fmw_ver));
+ main_exe = path.path_join(vformat("Versions/%s", fmw_ver));
bundle = true;
- } else if (da->file_exists(path.plus_file("Info.plist"))) {
- info_path = path.plus_file("Info.plist");
+ } else if (da->file_exists(path.path_join("Info.plist"))) {
+ info_path = path.path_join("Info.plist");
main_exe = path;
bundle = true;
}
@@ -322,20 +322,20 @@ bool CodeSignCodeResources::add_folder_recursive(const String &p_root, const Str
PList info_plist;
if (info_plist.load_file(info_path)) {
if (info_plist.get_root()->data_type == PList::PLNodeType::PL_NODE_TYPE_DICT && info_plist.get_root()->data_dict.has("CFBundleExecutable")) {
- main_exe = main_exe.plus_file(String::utf8(info_plist.get_root()->data_dict["CFBundleExecutable"]->data_string.get_data()));
+ main_exe = main_exe.path_join(String::utf8(info_plist.get_root()->data_dict["CFBundleExecutable"]->data_string.get_data()));
} else {
ERR_FAIL_V_MSG(false, "CodeSign/CodeResources: Invalid Info.plist, no exe name.");
}
} else {
ERR_FAIL_V_MSG(false, "CodeSign/CodeResources: Invalid Info.plist, can't load.");
}
- ret = ret && add_nested_file(p_root, p_path.plus_file(n), main_exe);
+ ret = ret && add_nested_file(p_root, p_path.path_join(n), main_exe);
} else {
- ret = ret && add_folder_recursive(p_root, p_path.plus_file(n), p_main_exe_path);
+ ret = ret && add_folder_recursive(p_root, p_path.path_join(n), p_main_exe_path);
}
} else {
- ret = ret && add_file1(p_root, p_path.plus_file(n));
- ret = ret && add_file2(p_root, p_path.plus_file(n));
+ ret = ret && add_file1(p_root, p_path.path_join(n));
+ ret = ret && add_file2(p_root, p_path.path_join(n));
}
}
@@ -1222,7 +1222,7 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const
}
if (info_plist.get_root()->data_type == PList::PLNodeType::PL_NODE_TYPE_DICT && info_plist.get_root()->data_dict.has("CFBundleExecutable")) {
- main_exe = p_exe_path.plus_file(String::utf8(info_plist.get_root()->data_dict["CFBundleExecutable"]->data_string.get_data()));
+ main_exe = p_exe_path.path_join(String::utf8(info_plist.get_root()->data_dict["CFBundleExecutable"]->data_string.get_data()));
} else {
r_error_msg = TTR("Invalid Info.plist, no exe name.");
ERR_FAIL_V_MSG(FAILED, "CodeSign: Invalid Info.plist, no exe name.");
@@ -1244,7 +1244,7 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const
Vector<String> files_to_sign;
if (LipO::is_lipo(main_exe)) {
print_verbose(vformat("CodeSign: Executable is fat, extracting..."));
- String tmp_path_name = EditorPaths::get_singleton()->get_cache_dir().plus_file("_lipo");
+ String tmp_path_name = EditorPaths::get_singleton()->get_cache_dir().path_join("_lipo");
Error err = da->make_dir_recursive(tmp_path_name);
if (err != OK) {
r_error_msg = vformat(TTR("Failed to create \"%s\" subfolder."), tmp_path_name);
@@ -1253,12 +1253,12 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const
LipO lip;
if (lip.open_file(main_exe)) {
for (int i = 0; i < lip.get_arch_count(); i++) {
- if (!lip.extract_arch(i, tmp_path_name.plus_file("_exe_" + itos(i)))) {
+ if (!lip.extract_arch(i, tmp_path_name.path_join("_exe_" + itos(i)))) {
CLEANUP();
r_error_msg = TTR("Failed to extract thin binary.");
ERR_FAIL_V_MSG(FAILED, "CodeSign: Failed to extract thin binary.");
}
- files_to_sign.push_back(tmp_path_name.plus_file("_exe_" + itos(i)));
+ files_to_sign.push_back(tmp_path_name.path_join("_exe_" + itos(i)));
}
}
} else if (MachO::is_macho(main_exe)) {
@@ -1338,15 +1338,15 @@ Error CodeSign::_codesign_file(bool p_use_hardened_runtime, bool p_force, const
r_error_msg = TTR("Failed to process nested resources.");
ERR_FAIL_V_MSG(FAILED, "CodeSign: Failed to process nested resources.");
}
- Error err = da->make_dir_recursive(p_bundle_path.plus_file("_CodeSignature"));
+ Error err = da->make_dir_recursive(p_bundle_path.path_join("_CodeSignature"));
if (err != OK) {
CLEANUP();
r_error_msg = TTR("Failed to create _CodeSignature subfolder.");
ERR_FAIL_V_MSG(FAILED, "CodeSign: Failed to create _CodeSignature subfolder.");
}
- cr.save_to_file(p_bundle_path.plus_file("_CodeSignature").plus_file("CodeResources"));
- res_hash1 = file_hash_sha1(p_bundle_path.plus_file("_CodeSignature").plus_file("CodeResources"));
- res_hash2 = file_hash_sha256(p_bundle_path.plus_file("_CodeSignature").plus_file("CodeResources"));
+ cr.save_to_file(p_bundle_path.path_join("_CodeSignature").path_join("CodeResources"));
+ res_hash1 = file_hash_sha1(p_bundle_path.path_join("_CodeSignature").path_join("CodeResources"));
+ res_hash2 = file_hash_sha256(p_bundle_path.path_join("_CodeSignature").path_join("CodeResources"));
if (res_hash1.is_empty() || res_hash2.is_empty()) {
CLEANUP();
r_error_msg = TTR("Failed to get CodeResources hash.");
@@ -1530,18 +1530,18 @@ Error CodeSign::codesign(bool p_use_hardened_runtime, bool p_force, const String
String bundle_path;
bool bundle = false;
bool ios_bundle = false;
- if (da->file_exists(p_path.plus_file("Contents/Info.plist"))) {
- info_path = p_path.plus_file("Contents/Info.plist");
- main_exe = p_path.plus_file("Contents/MacOS");
- bundle_path = p_path.plus_file("Contents");
+ if (da->file_exists(p_path.path_join("Contents/Info.plist"))) {
+ info_path = p_path.path_join("Contents/Info.plist");
+ main_exe = p_path.path_join("Contents/MacOS");
+ bundle_path = p_path.path_join("Contents");
bundle = true;
- } else if (da->file_exists(p_path.plus_file(vformat("Versions/%s/Resources/Info.plist", fmw_ver)))) {
- info_path = p_path.plus_file(vformat("Versions/%s/Resources/Info.plist", fmw_ver));
- main_exe = p_path.plus_file(vformat("Versions/%s", fmw_ver));
- bundle_path = p_path.plus_file(vformat("Versions/%s", fmw_ver));
+ } else if (da->file_exists(p_path.path_join(vformat("Versions/%s/Resources/Info.plist", fmw_ver)))) {
+ info_path = p_path.path_join(vformat("Versions/%s/Resources/Info.plist", fmw_ver));
+ main_exe = p_path.path_join(vformat("Versions/%s", fmw_ver));
+ bundle_path = p_path.path_join(vformat("Versions/%s", fmw_ver));
bundle = true;
- } else if (da->file_exists(p_path.plus_file("Info.plist"))) {
- info_path = p_path.plus_file("Info.plist");
+ } else if (da->file_exists(p_path.path_join("Info.plist"))) {
+ info_path = p_path.path_join("Info.plist");
main_exe = p_path;
bundle_path = p_path;
bundle = true;
diff --git a/platform/macos/export/export.cpp b/platform/macos/export/export.cpp
index ff7457081f..f219616df4 100644
--- a/platform/macos/export/export.cpp
+++ b/platform/macos/export/export.cpp
@@ -33,8 +33,12 @@
#include "export_plugin.h"
void register_macos_exporter() {
- EDITOR_DEF("export/macos/force_builtin_codesign", false);
- EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::BOOL, "export/macos/force_builtin_codesign", PROPERTY_HINT_NONE));
+ EDITOR_DEF("export/macos/rcodesign", "");
+#ifdef WINDOWS_ENABLED
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/macos/rcodesign", PROPERTY_HINT_GLOBAL_FILE, "*.exe"));
+#else
+ EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/macos/rcodesign", PROPERTY_HINT_GLOBAL_FILE));
+#endif
Ref<EditorExportPlatformMacOS> platform;
platform.instantiate();
diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp
index bcc2636c07..50104aced5 100644
--- a/platform/macos/export/export_plugin.cpp
+++ b/platform/macos/export/export_plugin.cpp
@@ -51,11 +51,51 @@ void EditorExportPlatformMacOS::get_preset_features(const Ref<EditorExportPreset
r_features->push_back(p_preset->get("binary_format/architecture"));
}
-bool EditorExportPlatformMacOS::get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const {
- // These options are not supported by built-in codesign, used on non macOS host.
- if (!OS::get_singleton()->has_feature("macos")) {
- if (p_option == "codesign/identity" || p_option == "codesign/timestamp" || p_option == "codesign/hardened_runtime" || p_option == "codesign/custom_options" || p_option.begins_with("notarization/")) {
- return false;
+bool EditorExportPlatformMacOS::get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
+ // Hide irrelevant code signing options.
+ if (p_preset) {
+ int codesign_tool = p_preset->get("codesign/codesign");
+ switch (codesign_tool) {
+ case 1: { // built-in ad-hoc
+ if (p_option == "codesign/identity" || p_option == "codesign/certificate_file" || p_option == "codesign/certificate_password" || p_option == "codesign/custom_options") {
+ return false;
+ }
+ } break;
+ case 2: { // "rcodesign"
+ if (p_option == "codesign/identity") {
+ return false;
+ }
+ } break;
+#ifdef MACOS_ENABLED
+ case 3: { // "codesign"
+ if (p_option == "codesign/certificate_file" || p_option == "codesign/certificate_password") {
+ return false;
+ }
+ } break;
+#endif
+ default: { // disabled
+ if (p_option == "codesign/identity" || p_option == "codesign/certificate_file" || p_option == "codesign/certificate_password" || p_option == "codesign/custom_options" || p_option.begins_with("codesign/entitlements")) {
+ return false;
+ }
+ } break;
+ }
+
+ // Hide irrelevant notarization options.
+ int notary_tool = p_preset->get("notarization/notarization");
+ switch (notary_tool) {
+ case 1: { // "rcodesign"
+ if (p_option == "notarization/apple_id_name" || p_option == "notarization/apple_id_password" || p_option == "notarization/apple_team_id") {
+ return false;
+ }
+ } break;
+ case 2: { // "altool"
+ // All options are visible.
+ } break;
+ default: { // disabled
+ if (p_option == "notarization/apple_id_name" || p_option == "notarization/apple_id_password" || p_option == "notarization/apple_team_id" || p_option == "notarization/api_uuid" || p_option == "notarization/api_key") {
+ return false;
+ }
+ } break;
}
}
@@ -83,40 +123,22 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "application/copyright_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "display/high_res"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the microphone"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/microphone_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/camera_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the camera"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/camera_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/location_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the location information"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/location_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/address_book_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the address book"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/address_book_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/calendar_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the calendar"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/calendar_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photos_library_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the photo library"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/photos_library_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/desktop_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Desktop folder"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/desktop_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/documents_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Documents folder"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/documents_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/downloads_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Downloads folder"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/downloads_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/network_volumes_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use network volumes"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/network_volumes_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/removable_volumes_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use removable volumes"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/removable_volumes_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), true));
+#ifdef MACOS_ENABLED
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/codesign", PROPERTY_HINT_ENUM, "Disabled,Built-in (ad-hoc only),PyOxidizer rcodesign,Xcode codesign"), 3, true));
+#else
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/codesign", PROPERTY_HINT_ENUM, "Disabled,Built-in (ad-hoc only),PyOxidizer rcodesign"), 1, true));
+#endif
+ // "codesign" only options:
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_PLACEHOLDER_TEXT, "Type: Name (ID)"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/replace_existing_signature"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/hardened_runtime"), true));
+ // "rcodesign" only options:
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/certificate_file", PROPERTY_HINT_GLOBAL_FILE, "*.pfx,*.p12"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/certificate_password", PROPERTY_HINT_PASSWORD), ""));
+ // "codesign" and "rcodesign" only options:
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements/custom_file", PROPERTY_HINT_GLOBAL_FILE, "*.plist"), ""));
-
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_jit_code_execution"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_unsigned_executable_memory"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_dyld_environment_variables"), false));
-
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/disable_library_validation"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/audio_input"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/camera"), false));
@@ -126,7 +148,6 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/photos_library"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/apple_events"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/debugging"), false));
-
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/enabled"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/network_server"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/app_sandbox/network_client"), false));
@@ -137,13 +158,43 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_music", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_movies", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::ARRAY, "codesign/entitlements/app_sandbox/helper_executables", PROPERTY_HINT_ARRAY_TYPE, itos(Variant::STRING) + "/" + itos(PROPERTY_HINT_GLOBAL_FILE) + ":"), Array()));
-
r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray()));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "notarization/enable"), false));
+#ifdef MACOS_ENABLED
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "notarization/notarization", PROPERTY_HINT_ENUM, "Disabled,PyOxidizer rcodesign,Xcode altool"), 0, true));
+#else
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "notarization/notarization", PROPERTY_HINT_ENUM, "Disabled,PyOxidizer rcodesign"), 0, true));
+#endif
+ // "altool" only options:
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Apple ID email"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_password", PROPERTY_HINT_PLACEHOLDER_TEXT, "Enable two-factor authentication and provide app-specific password"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_password", PROPERTY_HINT_PASSWORD, "Enable two-factor authentication and provide app-specific password"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_team_id", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide team ID if your Apple ID belongs to multiple teams"), ""));
+ // "altool" and "rcodesign" only options:
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_uuid", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect issuer ID"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/api_key", PROPERTY_HINT_PLACEHOLDER_TEXT, "App Store Connect API key ID"), ""));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the microphone"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/microphone_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/camera_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the camera"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/camera_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/location_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the location information"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/location_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/address_book_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the address book"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/address_book_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/calendar_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the calendar"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/calendar_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photos_library_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the photo library"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/photos_library_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/desktop_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Desktop folder"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/desktop_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/documents_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Documents folder"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/documents_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/downloads_folder_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use Downloads folder"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/downloads_folder_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/network_volumes_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use network volumes"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/network_volumes_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/removable_volumes_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use removable volumes"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "privacy/removable_volumes_usage_description_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), false));
@@ -254,7 +305,7 @@ void EditorExportPlatformMacOS::_make_icon(const Ref<Image> &p_icon, Vector<uint
if (icon_infos[i].is_png) {
// Encode PNG icon.
it->set_image(copy);
- String path = EditorPaths::get_singleton()->get_cache_dir().plus_file("icon.png");
+ String path = EditorPaths::get_singleton()->get_cache_dir().path_join("icon.png");
ResourceSaver::save(it, path);
{
@@ -415,156 +466,284 @@ void EditorExportPlatformMacOS::_fix_plist(const Ref<EditorExportPreset> &p_pres
*/
Error EditorExportPlatformMacOS::_notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
+ int notary_tool = p_preset->get("notarization/notarization");
+ switch (notary_tool) {
+ case 1: { // "rcodesign"
+ print_verbose("using rcodesign notarization...");
+
+ String rcodesign = EditorSettings::get_singleton()->get("export/macos/rcodesign").operator String();
+ if (rcodesign.is_empty()) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("rcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign)."));
+ return Error::FAILED;
+ }
+
+ List<String> args;
+
+ args.push_back("notary-submit");
+
+ if (p_preset->get("notarization/api_uuid") == "") {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("App Store Connect issuer ID name not specified."));
+ return Error::FAILED;
+ }
+ if (p_preset->get("notarization/api_key") == "") {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("App Store Connect API key ID not specified."));
+ return Error::FAILED;
+ }
+
+ args.push_back("--api-issuer");
+ args.push_back(p_preset->get("notarization/api_uuid"));
+
+ args.push_back("--api-key");
+ args.push_back(p_preset->get("notarization/api_key"));
+
+ args.push_back(p_path);
+
+ String str;
+ int exitcode = 0;
+
+ Error err = OS::get_singleton()->execute(rcodesign, args, &str, &exitcode, true);
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Could not start rcodesign executable."));
+ return err;
+ }
+
+ int rq_offset = str.find("created submission ID:");
+ if (exitcode != 0 || rq_offset == -1) {
+ print_line("rcodesign (" + p_path + "):\n" + str);
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Notarization failed, see editor log for details."));
+ return Error::FAILED;
+ } else {
+ print_verbose("rcodesign (" + p_path + "):\n" + str);
+ int next_nl = str.find("\n", rq_offset);
+ String request_uuid = (next_nl == -1) ? str.substr(rq_offset + 14, -1) : str.substr(rq_offset + 14, next_nl - rq_offset - 14);
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), vformat(TTR("Notarization request UUID: \"%s\""), request_uuid));
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("The notarization process generally takes less than an hour."));
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("You can check progress manually by opening a Terminal and running the following command:"));
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"rcodesign notary-log --api-issuer <api uuid> --api-key <api key> <request uuid>\"");
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("Run the following command to staple the notarization ticket to the exported application (optional):"));
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"rcodesign staple <app path>\"");
+ }
+ } break;
#ifdef MACOS_ENABLED
- List<String> args;
+ case 2: { // "altool"
+ print_verbose("using altool notarization...");
- args.push_back("altool");
- args.push_back("--notarize-app");
+ if (!FileAccess::exists("/usr/bin/xcrun") && !FileAccess::exists("/bin/xcrun")) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Xcode command line tools are not installed."));
+ return Error::FAILED;
+ }
- args.push_back("--primary-bundle-id");
- args.push_back(p_preset->get("application/bundle_identifier"));
+ List<String> args;
- args.push_back("--username");
- args.push_back(p_preset->get("notarization/apple_id_name"));
+ args.push_back("altool");
+ args.push_back("--notarize-app");
- args.push_back("--password");
- args.push_back(p_preset->get("notarization/apple_id_password"));
+ args.push_back("--primary-bundle-id");
+ args.push_back(p_preset->get("application/bundle_identifier"));
- args.push_back("--type");
- args.push_back("osx");
+ if (p_preset->get("notarization/apple_id_name") == "" && p_preset->get("notarization/api_uuid") == "") {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Neither Apple ID name nor App Store Connect issuer ID name not specified."));
+ return Error::FAILED;
+ }
+ if (p_preset->get("notarization/apple_id_name") != "" && p_preset->get("notarization/api_uuid") != "") {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Both Apple ID name and App Store Connect issuer ID name are specified, only one should be set at the same time."));
+ return Error::FAILED;
+ }
- if (p_preset->get("notarization/apple_team_id")) {
- args.push_back("--asc-provider");
- args.push_back(p_preset->get("notarization/apple_team_id"));
- }
+ if (p_preset->get("notarization/apple_id_name") != "") {
+ if (p_preset->get("notarization/apple_id_password") == "") {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("Apple ID password not specified."));
+ return Error::FAILED;
+ }
+ args.push_back("--username");
+ args.push_back(p_preset->get("notarization/apple_id_name"));
- args.push_back("--file");
- args.push_back(p_path);
+ args.push_back("--password");
+ args.push_back(p_preset->get("notarization/apple_id_password"));
+ } else {
+ if (p_preset->get("notarization/api_key") == "") {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Notarization"), TTR("App Store Connect API key ID not specified."));
+ return Error::FAILED;
+ }
+ args.push_back("--apiIssuer");
+ args.push_back(p_preset->get("notarization/api_uuid"));
- String str;
- Error err = OS::get_singleton()->execute("xcrun", args, &str, nullptr, true);
- if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
- add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Could not start xcrun executable."));
- return err;
- }
+ args.push_back("--apiKey");
+ args.push_back(p_preset->get("notarization/api_key"));
+ }
- print_verbose("altool (" + p_path + "):\n" + str);
- int rq_offset = str.find("RequestUUID");
- if (rq_offset == -1) {
- add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Notarization failed."));
- return FAILED;
- } else {
- int next_nl = str.find("\n", rq_offset);
- String request_uuid = (next_nl == -1) ? str.substr(rq_offset + 14, -1) : str.substr(rq_offset + 14, next_nl - rq_offset - 14);
- add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), vformat(TTR("Notarization request UUID: \"%s\""), request_uuid));
- add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("The notarization process generally takes less than an hour. When the process is completed, you'll receive an email."));
- add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("You can check progress manually by opening a Terminal and running the following command:"));
- add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"xcrun altool --notarization-history 0 -u <your email> -p <app-specific pwd>\"");
- add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("Run the following command to staple the notarization ticket to the exported application (optional):"));
- add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"xcrun stapler staple <app path>\"");
- }
+ args.push_back("--type");
+ args.push_back("osx");
-#endif
+ if (p_preset->get("notarization/apple_team_id")) {
+ args.push_back("--asc-provider");
+ args.push_back(p_preset->get("notarization/apple_team_id"));
+ }
+
+ args.push_back("--file");
+ args.push_back(p_path);
+
+ String str;
+ int exitcode = 0;
+ Error err = OS::get_singleton()->execute("xcrun", args, &str, &exitcode, true);
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Could not start xcrun executable."));
+ return err;
+ }
+ int rq_offset = str.find("RequestUUID");
+ if (exitcode != 0 || rq_offset == -1) {
+ print_line("xcrun altool (" + p_path + "):\n" + str);
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Notarization"), TTR("Notarization failed, see editor log for details."));
+ return Error::FAILED;
+ } else {
+ print_verbose("xcrun altool (" + p_path + "):\n" + str);
+ int next_nl = str.find("\n", rq_offset);
+ String request_uuid = (next_nl == -1) ? str.substr(rq_offset + 14, -1) : str.substr(rq_offset + 14, next_nl - rq_offset - 14);
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), vformat(TTR("Notarization request UUID: \"%s\""), request_uuid));
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("The notarization process generally takes less than an hour. When the process is completed, you'll receive an email."));
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("You can check progress manually by opening a Terminal and running the following command:"));
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"xcrun altool --notarization-history 0 -u <your email> -p <app-specific pwd>\"");
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t" + TTR("Run the following command to staple the notarization ticket to the exported application (optional):"));
+ add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), "\t\t\"xcrun stapler staple <app path>\"");
+ }
+ } break;
+#endif
+ default: {
+ };
+ }
return OK;
}
Error EditorExportPlatformMacOS::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn) {
- bool force_builtin_codesign = EditorSettings::get_singleton()->get("export/macos/force_builtin_codesign");
- bool ad_hoc = (p_preset->get("codesign/identity") == "" || p_preset->get("codesign/identity") == "-");
-
- if ((!FileAccess::exists("/usr/bin/codesign") && !FileAccess::exists("/bin/codesign")) || force_builtin_codesign) {
- print_verbose("using built-in codesign...");
+ int codesign_tool = p_preset->get("codesign/codesign");
+ switch (codesign_tool) {
+ case 1: { // built-in ad-hoc
+ print_verbose("using built-in codesign...");
#ifdef MODULE_REGEX_ENABLED
-
-#ifdef MACOS_ENABLED
- if (p_preset->get("codesign/timestamp") && p_warn) {
- add_message(EXPORT_MESSAGE_INFO, TTR("Code Signing"), TTR("Timestamping is not compatible with ad-hoc signature, and was disabled!"));
- }
- if (p_preset->get("codesign/hardened_runtime") && p_warn) {
- add_message(EXPORT_MESSAGE_INFO, TTR("Code Signing"), TTR("Hardened Runtime is not compatible with ad-hoc signature, and was disabled!"));
- }
-#endif
-
- String error_msg;
- Error err = CodeSign::codesign(false, p_preset->get("codesign/replace_existing_signature"), p_path, p_ent_path, error_msg);
- if (err != OK) {
- add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Built-in CodeSign failed with error \"%s\"."), error_msg));
- return FAILED;
- }
+ String error_msg;
+ Error err = CodeSign::codesign(false, true, p_path, p_ent_path, error_msg);
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), vformat(TTR("Built-in CodeSign failed with error \"%s\"."), error_msg));
+ return Error::FAILED;
+ }
#else
- add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Built-in CodeSign require regex module."));
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Built-in CodeSign require regex module."));
#endif
- return OK;
- } else {
- print_verbose("using external codesign...");
- List<String> args;
- if (p_preset->get("codesign/timestamp")) {
- if (ad_hoc) {
- if (p_warn) {
- add_message(EXPORT_MESSAGE_INFO, TTR("Code Signing"), TTR("Timestamping is not compatible with ad-hoc signature, and was disabled!"));
- }
- } else {
- args.push_back("--timestamp");
+ } break;
+ case 2: { // "rcodesign"
+ print_verbose("using rcodesign codesign...");
+
+ String rcodesign = EditorSettings::get_singleton()->get("export/macos/rcodesign").operator String();
+ if (rcodesign.is_empty()) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Xrcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign)."));
+ return Error::FAILED;
}
- }
- if (p_preset->get("codesign/hardened_runtime")) {
- if (ad_hoc) {
- if (p_warn) {
- add_message(EXPORT_MESSAGE_INFO, TTR("Code Signing"), TTR("Hardened Runtime is not compatible with ad-hoc signature, and was disabled!"));
- }
+
+ List<String> args;
+ args.push_back("sign");
+
+ if (p_path.get_extension() != "dmg") {
+ args.push_back("--entitlements-xml-path");
+ args.push_back(p_ent_path);
+ }
+
+ String certificate_file = p_preset->get("codesign/certificate_file");
+ String certificate_pass = p_preset->get("codesign/certificate_password");
+ if (!certificate_file.is_empty() && !certificate_file.is_empty()) {
+ args.push_back("--p12-file");
+ args.push_back(certificate_file);
+ args.push_back("--p12-password");
+ args.push_back(certificate_pass);
+ }
+
+ args.push_back("-v"); /* provide some more feedback */
+
+ args.push_back(p_path);
+
+ String str;
+ int exitcode = 0;
+
+ Error err = OS::get_singleton()->execute(rcodesign, args, &str, &exitcode, true);
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start rcodesign executable."));
+ return err;
+ }
+
+ if (exitcode != 0) {
+ print_line("rcodesign (" + p_path + "):\n" + str);
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Code signing failed, see editor log for details."));
+ return Error::FAILED;
} else {
+ print_verbose("rcodesign (" + p_path + "):\n" + str);
+ }
+ } break;
+#ifdef MACOS_ENABLED
+ case 3: { // "codesign"
+ print_verbose("using xcode codesign...");
+
+ if (!FileAccess::exists("/usr/bin/codesign") && !FileAccess::exists("/bin/codesign")) {
+ add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Xcode command line tools are not installed."));
+ return Error::FAILED;
+ }
+
+ bool ad_hoc = (p_preset->get("codesign/identity") == "" || p_preset->get("codesign/identity") == "-");
+
+ List<String> args;
+ if (!ad_hoc) {
+ args.push_back("--timestamp");
args.push_back("--options");
args.push_back("runtime");
}
- }
- if (p_path.get_extension() != "dmg") {
- args.push_back("--entitlements");
- args.push_back(p_ent_path);
- }
-
- PackedStringArray user_args = p_preset->get("codesign/custom_options");
- for (int i = 0; i < user_args.size(); i++) {
- String user_arg = user_args[i].strip_edges();
- if (!user_arg.is_empty()) {
- args.push_back(user_arg);
+ if (p_path.get_extension() != "dmg") {
+ args.push_back("--entitlements");
+ args.push_back(p_ent_path);
}
- }
- args.push_back("-s");
- if (ad_hoc) {
- args.push_back("-");
- } else {
- args.push_back(p_preset->get("codesign/identity"));
- }
+ PackedStringArray user_args = p_preset->get("codesign/custom_options");
+ for (int i = 0; i < user_args.size(); i++) {
+ String user_arg = user_args[i].strip_edges();
+ if (!user_arg.is_empty()) {
+ args.push_back(user_arg);
+ }
+ }
- args.push_back("-v"); /* provide some more feedback */
+ args.push_back("-s");
+ if (ad_hoc) {
+ args.push_back("-");
+ } else {
+ args.push_back(p_preset->get("codesign/identity"));
+ }
- if (p_preset->get("codesign/replace_existing_signature")) {
+ args.push_back("-v"); /* provide some more feedback */
args.push_back("-f");
- }
- args.push_back(p_path);
+ args.push_back(p_path);
- String str;
- Error err = OS::get_singleton()->execute("codesign", args, &str, nullptr, true);
- if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
- add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start codesign executable, make sure Xcode command line tools are installed."));
- return err;
- }
+ String str;
+ int exitcode = 0;
- print_verbose("codesign (" + p_path + "):\n" + str);
- if (str.find("no identity found") != -1) {
- add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("No identity found."));
- return FAILED;
- }
- if ((str.find("unrecognized blob type") != -1) || (str.find("cannot read entitlement data") != -1)) {
- add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Invalid entitlements file."));
- return FAILED;
- }
- return OK;
+ Error err = OS::get_singleton()->execute("codesign", args, &str, nullptr, true);
+ if (err != OK) {
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start codesign executable, make sure Xcode command line tools are installed."));
+ return err;
+ }
+
+ if (exitcode != 0) {
+ print_line("codesign (" + p_path + "):\n" + str);
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Code signing failed, see editor log for details."));
+ return Error::FAILED;
+ } else {
+ print_verbose("codesign (" + p_path + "):\n" + str);
+ }
+ } break;
+#endif
+ default: {
+ };
}
+
+ return OK;
}
Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPreset> &p_preset, const String &p_path,
@@ -587,7 +766,7 @@ Error EditorExportPlatformMacOS::_code_sign_directory(const Ref<EditorExportPres
dir_access->list_dir_begin();
String current_file{ dir_access->get_next() };
while (!current_file.is_empty()) {
- String current_file_path{ p_path.plus_file(current_file) };
+ String current_file_path{ p_path.path_join(current_file) };
if (current_file == ".." || current_file == ".") {
current_file = dir_access->get_next();
@@ -801,9 +980,9 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
tmp_app_path_name = p_path;
scr_path = p_path.get_basename() + ".command";
} else {
- tmp_base_path_name = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name);
- tmp_app_path_name = tmp_base_path_name.plus_file(tmp_app_dir_name);
- scr_path = tmp_base_path_name.plus_file(pkg_name + ".command");
+ tmp_base_path_name = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name);
+ tmp_app_path_name = tmp_base_path_name.path_join(tmp_app_dir_name);
+ scr_path = tmp_base_path_name.path_join(pkg_name + ".command");
}
print_verbose("Exporting to " + tmp_app_path_name);
@@ -816,7 +995,9 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
err = ERR_CANT_CREATE;
}
- DirAccess::remove_file_or_error(scr_path);
+ if (FileAccess::exists(scr_path)) {
+ DirAccess::remove_file_or_error(scr_path);
+ }
if (DirAccess::exists(tmp_app_path_name)) {
String old_dir = tmp_app_dir->get_current_dir();
if (tmp_app_dir->change_dir(tmp_app_path_name) == OK) {
@@ -919,54 +1100,58 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
f->store_line("NSHumanReadableCopyright = \"" + p_preset->get("application/copyright").operator String() + "\";");
}
+ HashSet<String> languages;
for (const String &E : translations) {
Ref<Translation> tr = ResourceLoader::load(E);
- if (tr.is_valid()) {
- String lang = tr->get_locale();
- String fname = tmp_app_path_name + "/Contents/Resources/" + lang + ".lproj";
- tmp_app_dir->make_dir_recursive(fname);
- Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE);
- f->store_line("/* Localized versions of Info.plist keys */");
- f->store_line("");
- if (appnames.has(lang)) {
- f->store_line("CFBundleDisplayName = \"" + appnames[lang].operator String() + "\";");
- }
- if (microphone_usage_descriptions.has(lang)) {
- f->store_line("NSMicrophoneUsageDescription = \"" + microphone_usage_descriptions[lang].operator String() + "\";");
- }
- if (camera_usage_descriptions.has(lang)) {
- f->store_line("NSCameraUsageDescription = \"" + camera_usage_descriptions[lang].operator String() + "\";");
- }
- if (location_usage_descriptions.has(lang)) {
- f->store_line("NSLocationUsageDescription = \"" + location_usage_descriptions[lang].operator String() + "\";");
- }
- if (address_book_usage_descriptions.has(lang)) {
- f->store_line("NSContactsUsageDescription = \"" + address_book_usage_descriptions[lang].operator String() + "\";");
- }
- if (calendar_usage_descriptions.has(lang)) {
- f->store_line("NSCalendarsUsageDescription = \"" + calendar_usage_descriptions[lang].operator String() + "\";");
- }
- if (photos_library_usage_descriptions.has(lang)) {
- f->store_line("NSPhotoLibraryUsageDescription = \"" + photos_library_usage_descriptions[lang].operator String() + "\";");
- }
- if (desktop_folder_usage_descriptions.has(lang)) {
- f->store_line("NSDesktopFolderUsageDescription = \"" + desktop_folder_usage_descriptions[lang].operator String() + "\";");
- }
- if (documents_folder_usage_descriptions.has(lang)) {
- f->store_line("NSDocumentsFolderUsageDescription = \"" + documents_folder_usage_descriptions[lang].operator String() + "\";");
- }
- if (downloads_folder_usage_descriptions.has(lang)) {
- f->store_line("NSDownloadsFolderUsageDescription = \"" + downloads_folder_usage_descriptions[lang].operator String() + "\";");
- }
- if (network_volumes_usage_descriptions.has(lang)) {
- f->store_line("NSNetworkVolumesUsageDescription = \"" + network_volumes_usage_descriptions[lang].operator String() + "\";");
- }
- if (removable_volumes_usage_descriptions.has(lang)) {
- f->store_line("NSRemovableVolumesUsageDescription = \"" + removable_volumes_usage_descriptions[lang].operator String() + "\";");
- }
- if (copyrights.has(lang)) {
- f->store_line("NSHumanReadableCopyright = \"" + copyrights[lang].operator String() + "\";");
- }
+ if (tr.is_valid() && tr->get_locale() != "en") {
+ languages.insert(tr->get_locale());
+ }
+ }
+
+ for (const String &lang : languages) {
+ String fname = tmp_app_path_name + "/Contents/Resources/" + lang + ".lproj";
+ tmp_app_dir->make_dir_recursive(fname);
+ Ref<FileAccess> f = FileAccess::open(fname + "/InfoPlist.strings", FileAccess::WRITE);
+ f->store_line("/* Localized versions of Info.plist keys */");
+ f->store_line("");
+ if (appnames.has(lang)) {
+ f->store_line("CFBundleDisplayName = \"" + appnames[lang].operator String() + "\";");
+ }
+ if (microphone_usage_descriptions.has(lang)) {
+ f->store_line("NSMicrophoneUsageDescription = \"" + microphone_usage_descriptions[lang].operator String() + "\";");
+ }
+ if (camera_usage_descriptions.has(lang)) {
+ f->store_line("NSCameraUsageDescription = \"" + camera_usage_descriptions[lang].operator String() + "\";");
+ }
+ if (location_usage_descriptions.has(lang)) {
+ f->store_line("NSLocationUsageDescription = \"" + location_usage_descriptions[lang].operator String() + "\";");
+ }
+ if (address_book_usage_descriptions.has(lang)) {
+ f->store_line("NSContactsUsageDescription = \"" + address_book_usage_descriptions[lang].operator String() + "\";");
+ }
+ if (calendar_usage_descriptions.has(lang)) {
+ f->store_line("NSCalendarsUsageDescription = \"" + calendar_usage_descriptions[lang].operator String() + "\";");
+ }
+ if (photos_library_usage_descriptions.has(lang)) {
+ f->store_line("NSPhotoLibraryUsageDescription = \"" + photos_library_usage_descriptions[lang].operator String() + "\";");
+ }
+ if (desktop_folder_usage_descriptions.has(lang)) {
+ f->store_line("NSDesktopFolderUsageDescription = \"" + desktop_folder_usage_descriptions[lang].operator String() + "\";");
+ }
+ if (documents_folder_usage_descriptions.has(lang)) {
+ f->store_line("NSDocumentsFolderUsageDescription = \"" + documents_folder_usage_descriptions[lang].operator String() + "\";");
+ }
+ if (downloads_folder_usage_descriptions.has(lang)) {
+ f->store_line("NSDownloadsFolderUsageDescription = \"" + downloads_folder_usage_descriptions[lang].operator String() + "\";");
+ }
+ if (network_volumes_usage_descriptions.has(lang)) {
+ f->store_line("NSNetworkVolumesUsageDescription = \"" + network_volumes_usage_descriptions[lang].operator String() + "\";");
+ }
+ if (removable_volumes_usage_descriptions.has(lang)) {
+ f->store_line("NSRemovableVolumesUsageDescription = \"" + removable_volumes_usage_descriptions[lang].operator String() + "\";");
+ }
+ if (copyrights.has(lang)) {
+ f->store_line("NSHumanReadableCopyright = \"" + copyrights[lang].operator String() + "\";");
}
}
}
@@ -1004,7 +1189,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
add_message(EXPORT_MESSAGE_INFO, TTR("Export"), TTR("Relative symlinks are not supported on this OS, the exported project might be broken!"));
#endif
// Handle symlinks in the archive.
- file = tmp_app_path_name.plus_file(file);
+ file = tmp_app_path_name.path_join(file);
if (err == OK) {
err = tmp_app_dir->make_dir_recursive(file.get_base_dir());
if (err != OK) {
@@ -1088,7 +1273,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
print_verbose("ADDING: " + file + " size: " + itos(data.size()));
// Write it into our application bundle.
- file = tmp_app_path_name.plus_file(file);
+ file = tmp_app_path_name.path_join(file);
if (err == OK) {
err = tmp_app_dir->make_dir_recursive(file.get_base_dir());
if (err != OK) {
@@ -1144,12 +1329,12 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
err = save_pack(p_preset, p_debug, pack_path, &shared_objects);
// See if we can code sign our new package.
- bool sign_enabled = p_preset->get("codesign/enable");
+ bool sign_enabled = (p_preset->get("codesign/codesign").operator int() > 0);
String ent_path = p_preset->get("codesign/entitlements/custom_file");
- String hlp_ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + "_helper.entitlements");
+ String hlp_ent_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name + "_helper.entitlements");
if (sign_enabled && (ent_path.is_empty())) {
- ent_path = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name + ".entitlements");
+ ent_path = EditorPaths::get_singleton()->get_cache_dir().path_join(pkg_name + ".entitlements");
Ref<FileAccess> ent_f = FileAccess::open(ent_path, FileAccess::WRITE);
if (ent_f.is_valid()) {
@@ -1310,14 +1495,25 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
}
}
- bool ad_hoc = true;
- if (err == OK) {
+ bool ad_hoc = false;
+ int codesign_tool = p_preset->get("codesign/codesign");
+ switch (codesign_tool) {
+ case 1: { // built-in ad-hoc
+ ad_hoc = true;
+ } break;
+ case 2: { // "rcodesign"
+ ad_hoc = p_preset->get("codesign/certificate_file").operator String().is_empty() || p_preset->get("codesign/certificate_password").operator String().is_empty();
+ } break;
#ifdef MACOS_ENABLED
- String sign_identity = p_preset->get("codesign/identity");
-#else
- String sign_identity = "-";
+ case 3: { // "codesign"
+ ad_hoc = (p_preset->get("codesign/identity") == "" || p_preset->get("codesign/identity") == "-");
+ } break;
#endif
- ad_hoc = (sign_identity == "" || sign_identity == "-");
+ default: {
+ };
+ }
+
+ if (err == OK) {
bool lib_validation = p_preset->get("codesign/entitlements/disable_library_validation");
if ((!dylibs_found.is_empty() || !shared_objects.is_empty()) && sign_enabled && ad_hoc && !lib_validation) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Code Signing"), TTR("Ad-hoc signed applications require the 'Disable Library Validation' entitlement to load dynamic libraries."));
@@ -1333,7 +1529,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
String path_in_app = tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file();
err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, true);
} else {
- String path_in_app = tmp_app_path_name.plus_file(shared_objects[i].target).plus_file(src_path.get_file());
+ String path_in_app = tmp_app_path_name.path_join(shared_objects[i].target).path_join(src_path.get_file());
err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, false);
}
if (err != OK) {
@@ -1400,8 +1596,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
}
}
-#ifdef MACOS_ENABLED
- bool noto_enabled = p_preset->get("notarization/enable");
+ bool noto_enabled = (p_preset->get("notarization/notarization").operator int() > 0);
if (err == OK && noto_enabled) {
if (export_format == "app") {
add_message(EXPORT_MESSAGE_INFO, TTR("Notarization"), TTR("Notarization requires the app to be archived first, select the DMG or ZIP export format instead."));
@@ -1412,10 +1607,11 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
err = _notarize(p_preset, p_path);
}
}
-#endif
// Clean up temporary entitlements files.
- DirAccess::remove_file_or_error(hlp_ent_path);
+ if (FileAccess::exists(hlp_ent_path)) {
+ DirAccess::remove_file_or_error(hlp_ent_path);
+ }
// Clean up temporary .app dir and generated entitlements.
if ((String)(p_preset->get("codesign/entitlements/custom_file")) == "") {
@@ -1434,7 +1630,7 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
}
void EditorExportPlatformMacOS::_zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name) {
- String dir = p_folder.is_empty() ? p_root_path : p_root_path.plus_file(p_folder);
+ String dir = p_folder.is_empty() ? p_root_path : p_root_path.path_join(p_folder);
Ref<DirAccess> da = DirAccess::open(dir);
da->list_dir_begin();
@@ -1464,7 +1660,7 @@ void EditorExportPlatformMacOS::_zip_folder_recursive(zipFile &p_zip, const Stri
zipfi.internal_fa = 0;
zipOpenNewFileInZip4(p_zip,
- p_folder.plus_file(f).utf8().get_data(),
+ p_folder.path_join(f).utf8().get_data(),
&zipfi,
nullptr,
0,
@@ -1486,7 +1682,7 @@ void EditorExportPlatformMacOS::_zip_folder_recursive(zipFile &p_zip, const Stri
zipWriteInFileInZip(p_zip, target.utf8().get_data(), target.utf8().size());
zipCloseFileInZip(p_zip);
} else if (da->current_is_dir()) {
- _zip_folder_recursive(p_zip, p_root_path, p_folder.plus_file(f), p_pkg_name);
+ _zip_folder_recursive(p_zip, p_root_path, p_folder.path_join(f), p_pkg_name);
} else {
bool is_executable = (p_folder.ends_with("MacOS") && (f == p_pkg_name)) || p_folder.ends_with("Helpers") || f.ends_with(".command");
@@ -1509,7 +1705,7 @@ void EditorExportPlatformMacOS::_zip_folder_recursive(zipFile &p_zip, const Stri
zipfi.internal_fa = 0;
zipOpenNewFileInZip4(p_zip,
- p_folder.plus_file(f).utf8().get_data(),
+ p_folder.path_join(f).utf8().get_data(),
&zipfi,
nullptr,
0,
@@ -1527,9 +1723,9 @@ void EditorExportPlatformMacOS::_zip_folder_recursive(zipFile &p_zip, const Stri
0x0314, // "version made by", 0x03 - Unix, 0x14 - ZIP specification version 2.0, required to store Unix file permissions
0);
- Ref<FileAccess> fa = FileAccess::open(dir.plus_file(f), FileAccess::READ);
+ Ref<FileAccess> fa = FileAccess::open(dir.path_join(f), FileAccess::READ);
if (fa.is_null()) {
- add_message(EXPORT_MESSAGE_ERROR, TTR("ZIP Creation"), vformat(TTR("Could not open file to read from path \"%s\"."), dir.plus_file(f)));
+ add_message(EXPORT_MESSAGE_ERROR, TTR("ZIP Creation"), vformat(TTR("Could not open file to read from path \"%s\"."), dir.path_join(f)));
return;
}
const int bufsize = 16384;
@@ -1550,7 +1746,7 @@ void EditorExportPlatformMacOS::_zip_folder_recursive(zipFile &p_zip, const Stri
da->list_dir_end();
}
-bool EditorExportPlatformMacOS::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+bool EditorExportPlatformMacOS::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
String err;
bool valid = false;
@@ -1580,6 +1776,17 @@ bool EditorExportPlatformMacOS::can_export(const Ref<EditorExportPreset> &p_pres
valid = dvalid || rvalid;
r_missing_templates = !valid;
+ if (!err.is_empty()) {
+ r_error = err;
+ }
+
+ return valid;
+}
+
+bool EditorExportPlatformMacOS::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const {
+ String err;
+ bool valid = true;
+
String identifier = p_preset->get("application/bundle_identifier");
String pn_err;
if (!is_package_name_valid(identifier, &pn_err)) {
@@ -1587,65 +1794,98 @@ bool EditorExportPlatformMacOS::can_export(const Ref<EditorExportPreset> &p_pres
valid = false;
}
- bool sign_enabled = p_preset->get("codesign/enable");
-
+ bool ad_hoc = false;
+ int codesign_tool = p_preset->get("codesign/codesign");
+ switch (codesign_tool) {
+ case 1: { // built-in ad-hoc
+ ad_hoc = true;
+ } break;
+ case 2: { // "rcodesign"
+ ad_hoc = p_preset->get("codesign/certificate_file").operator String().is_empty() || p_preset->get("codesign/certificate_password").operator String().is_empty();
+ } break;
#ifdef MACOS_ENABLED
- bool noto_enabled = p_preset->get("notarization/enable");
- bool ad_hoc = ((p_preset->get("codesign/identity") == "") || (p_preset->get("codesign/identity") == "-"));
-
- if (!ad_hoc && (bool)EditorSettings::get_singleton()->get("export/macos/force_builtin_codesign")) {
- err += TTR("Warning: Built-in \"codesign\" is selected in the Editor Settings. Code signing is limited to ad-hoc signature only.") + "\n";
- }
- if (!ad_hoc && !FileAccess::exists("/usr/bin/codesign") && !FileAccess::exists("/bin/codesign")) {
- err += TTR("Warning: Xcode command line tools are not installed, using built-in \"codesign\". Code signing is limited to ad-hoc signature only.") + "\n";
+ case 3: { // "codesign"
+ ad_hoc = (p_preset->get("codesign/identity") == "" || p_preset->get("codesign/identity") == "-");
+ } break;
+#endif
+ default: {
+ };
}
+ int notary_tool = p_preset->get("notarization/notarization");
- if (noto_enabled) {
+ if (notary_tool > 0) {
if (ad_hoc) {
err += TTR("Notarization: Notarization with an ad-hoc signature is not supported.") + "\n";
valid = false;
}
- if (!sign_enabled) {
+ if (codesign_tool == 0) {
err += TTR("Notarization: Code signing is required for notarization.") + "\n";
valid = false;
}
- if (!(bool)p_preset->get("codesign/hardened_runtime")) {
- err += TTR("Notarization: Hardened runtime is required for notarization.") + "\n";
- valid = false;
- }
- if (!(bool)p_preset->get("codesign/timestamp")) {
- err += TTR("Notarization: Timestamping is required for notarization.") + "\n";
- valid = false;
- }
- if (p_preset->get("notarization/apple_id_name") == "") {
- err += TTR("Notarization: Apple ID name not specified.") + "\n";
- valid = false;
- }
- if (p_preset->get("notarization/apple_id_password") == "") {
- err += TTR("Notarization: Apple ID password not specified.") + "\n";
- valid = false;
+ if (notary_tool == 2) {
+ if (!FileAccess::exists("/usr/bin/xcrun") && !FileAccess::exists("/bin/xcrun")) {
+ err += TTR("Notarization: Xcode command line tools are not installed.") + "\n";
+ valid = false;
+ }
+ if (p_preset->get("notarization/apple_id_name") == "" && p_preset->get("notarization/api_uuid") == "") {
+ err += TTR("Notarization: Neither Apple ID name nor App Store Connect issuer ID name not specified.") + "\n";
+ valid = false;
+ } else if (p_preset->get("notarization/apple_id_name") != "" && p_preset->get("notarization/api_uuid") != "") {
+ err += TTR("Notarization: Both Apple ID name and App Store Connect issuer ID name are specified, only one should be set at the same time.") + "\n";
+ valid = false;
+ } else {
+ if (p_preset->get("notarization/apple_id_name") != "") {
+ if (p_preset->get("notarization/apple_id_password") == "") {
+ err += TTR("Notarization: Apple ID password not specified.") + "\n";
+ }
+ valid = false;
+ }
+ if (p_preset->get("notarization/api_uuid") != "") {
+ if (p_preset->get("notarization/api_key") == "") {
+ err += TTR("Notarization: App Store Connect API key ID not specified.") + "\n";
+ valid = false;
+ }
+ }
+ }
+ } else if (notary_tool == 1) {
+ if (p_preset->get("notarization/api_uuid") == "") {
+ err += TTR("Notarization: App Store Connect issuer ID name not specified.") + "\n";
+ valid = false;
+ }
+ if (p_preset->get("notarization/api_key") == "") {
+ err += TTR("Notarization: App Store Connect API key ID not specified.") + "\n";
+ valid = false;
+ }
+
+ String rcodesign = EditorSettings::get_singleton()->get("export/macos/rcodesign").operator String();
+ if (rcodesign.is_empty()) {
+ err += TTR("Notarization: rcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign).") + "\n";
+ valid = false;
+ }
}
} else {
err += TTR("Warning: Notarization is disabled. The exported project will be blocked by Gatekeeper if it's downloaded from an unknown source.") + "\n";
- if (!sign_enabled) {
+ if (codesign_tool == 0) {
err += TTR("Code signing is disabled. The exported project will not run on Macs with enabled Gatekeeper and Apple Silicon powered Macs.") + "\n";
- } else {
- if ((bool)p_preset->get("codesign/hardened_runtime") && ad_hoc) {
- err += TTR("Hardened Runtime is not compatible with ad-hoc signature, and will be disabled!") + "\n";
- }
- if ((bool)p_preset->get("codesign/timestamp") && ad_hoc) {
- err += TTR("Timestamping is not compatible with ad-hoc signature, and will be disabled!") + "\n";
- }
}
}
-#else
- err += TTR("Warning: Notarization is not supported from this OS. The exported project will be blocked by Gatekeeper if it's downloaded from an unknown source.") + "\n";
- if (!sign_enabled) {
- err += TTR("Code signing is disabled. The exported project will not run on Macs with enabled Gatekeeper and Apple Silicon powered Macs.") + "\n";
- }
-#endif
- if (sign_enabled) {
+ if (codesign_tool > 0) {
+ if (ad_hoc) {
+ err += TTR("Code signing: Using ad-hoc signature. The exported project will be blocked by Gatekeeper") + "\n";
+ }
+ if (codesign_tool == 3) {
+ if (!FileAccess::exists("/usr/bin/codesign") && !FileAccess::exists("/bin/codesign")) {
+ err += TTR("Code signing: Xcode command line tools are not installed.") + "\n";
+ valid = false;
+ }
+ } else if (codesign_tool == 2) {
+ String rcodesign = EditorSettings::get_singleton()->get("export/macos/rcodesign").operator String();
+ if (rcodesign.is_empty()) {
+ err += TTR("Code signing: rcodesign path is not set. Configure rcodesign path in the Editor Settings (Export > macOS > rcodesign).") + "\n";
+ valid = false;
+ }
+ }
if ((bool)p_preset->get("codesign/entitlements/audio_input") && ((String)p_preset->get("privacy/microphone_usage_description")).is_empty()) {
err += TTR("Privacy: Microphone access is enabled, but usage description is not specified.") + "\n";
valid = false;
diff --git a/platform/macos/export/export_plugin.h b/platform/macos/export/export_plugin.h
index 21bc380d55..87790129d3 100644
--- a/platform/macos/export/export_plugin.h
+++ b/platform/macos/export/export_plugin.h
@@ -101,7 +101,7 @@ class EditorExportPlatformMacOS : public EditorExportPlatform {
protected:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const override;
virtual void get_export_options(List<ExportOption> *r_options) override;
- virtual bool get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
+ virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
public:
virtual String get_name() const override { return "macOS"; }
@@ -119,7 +119,8 @@ public:
}
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
- virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
virtual void get_platform_features(List<String> *r_features) const override {
r_features->push_back("pc");
diff --git a/platform/macos/godot_menu_item.h b/platform/macos/godot_menu_item.h
index 2c12897f10..e0b9f41632 100644
--- a/platform/macos/godot_menu_item.h
+++ b/platform/macos/godot_menu_item.h
@@ -46,7 +46,6 @@ enum GlobalMenuCheckType {
@public
Callable callback;
Variant meta;
- int id;
GlobalMenuCheckType checkable_type;
int max_states;
int state;
diff --git a/platform/macos/os_macos.h b/platform/macos/os_macos.h
index a1eb0f7f69..61db99689c 100644
--- a/platform/macos/os_macos.h
+++ b/platform/macos/os_macos.h
@@ -40,8 +40,6 @@
#include "servers/audio_server.h"
class OS_MacOS : public OS_Unix {
- bool force_quit = false;
-
JoypadMacOS *joypad_macos = nullptr;
#ifdef COREAUDIO_ENABLED
diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm
index cc550043de..35c4e4b03d 100644
--- a/platform/macos/os_macos.mm
+++ b/platform/macos/os_macos.mm
@@ -48,8 +48,8 @@
_FORCE_INLINE_ String OS_MacOS::get_framework_executable(const String &p_path) {
// Append framework executable name, or return as is if p_path is not a framework.
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- if (da->dir_exists(p_path) && da->file_exists(p_path.plus_file(p_path.get_file().get_basename()))) {
- return p_path.plus_file(p_path.get_file().get_basename());
+ if (da->dir_exists(p_path) && da->file_exists(p_path.path_join(p_path.get_file().get_basename()))) {
+ return p_path.path_join(p_path.get_file().get_basename());
} else {
return p_path;
}
@@ -155,12 +155,12 @@ Error OS_MacOS::open_dynamic_library(const String p_path, void *&p_library_handl
if (!FileAccess::exists(path)) {
// Load .dylib or framework from within the executable path.
- path = get_framework_executable(get_executable_path().get_base_dir().plus_file(p_path.get_file()));
+ path = get_framework_executable(get_executable_path().get_base_dir().path_join(p_path.get_file()));
}
if (!FileAccess::exists(path)) {
// Load .dylib or framework from a standard macOS location.
- path = get_framework_executable(get_executable_path().get_base_dir().plus_file("../Frameworks").plus_file(p_path.get_file()));
+ path = get_framework_executable(get_executable_path().get_base_dir().path_join("../Frameworks").path_join(p_path.get_file()));
}
p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
@@ -187,7 +187,7 @@ String OS_MacOS::get_config_path() const {
}
}
if (has_environment("HOME")) {
- return get_environment("HOME").plus_file("Library/Application Support");
+ return get_environment("HOME").path_join("Library/Application Support");
}
return ".";
}
@@ -214,7 +214,7 @@ String OS_MacOS::get_cache_path() const {
}
}
if (has_environment("HOME")) {
- return get_environment("HOME").plus_file("Library/Caches");
+ return get_environment("HOME").path_join("Library/Caches");
}
return get_config_path();
}
@@ -512,8 +512,6 @@ Error OS_MacOS::move_to_trash(const String &p_path) {
}
void OS_MacOS::run() {
- force_quit = false;
-
if (!main_loop) {
return;
}
@@ -521,7 +519,7 @@ void OS_MacOS::run() {
main_loop->initialize();
bool quit = false;
- while (!force_quit && !quit) {
+ while (!quit) {
@try {
if (DisplayServer::get_singleton()) {
DisplayServer::get_singleton()->process_events(); // Get rid of pending events.
@@ -541,7 +539,6 @@ void OS_MacOS::run() {
OS_MacOS::OS_MacOS() {
main_loop = nullptr;
- force_quit = false;
Vector<Logger *> loggers;
loggers.push_back(memnew(MacOSTerminalLogger));
diff --git a/platform/uwp/README.md b/platform/uwp/README.md
new file mode 100644
index 0000000000..575f90e3c7
--- /dev/null
+++ b/platform/uwp/README.md
@@ -0,0 +1,20 @@
+# UWP platform port
+
+> **Warning**
+>
+> The UWP platform port is not currently in a working state for the `master`
+> branch, and may be dropped in the future.
+
+This folder contains the C++ code for the Universal Windows Platform (UWP)
+platform port. **This is not to be confused with the "standard" Win32 port**,
+which is available in [`platform/windows`](/platform/windows).
+
+See also [`misc/dist/uwp_template`](/misc/dist/uwp_template) folder for the UWP
+project template used for packaging the UWP export templates.
+
+## Documentation
+
+- [Compiling for Universal Windows Platform](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_uwp.html)
+ - Instructions on building this platform port from source.
+- [Exporting for Universal Windows Platform](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_uwp.html)
+ - Instructions on using the compiled export templates to export a project.
diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py
index 9c91378b22..2c5746cb06 100644
--- a/platform/uwp/detect.py
+++ b/platform/uwp/detect.py
@@ -1,6 +1,7 @@
import methods
import os
import sys
+from platform_methods import detect_arch
def is_active():
@@ -31,6 +32,7 @@ def get_opts():
def get_flags():
return [
+ ("arch", detect_arch()),
("tools", False),
("xaudio2", True),
("builtin_pcre2_with_jit", False),
@@ -38,19 +40,17 @@ def get_flags():
def configure(env):
- env.msvc = True
-
- if env["bits"] != "default":
- print("Error: bits argument is disabled for MSVC")
+ # Validate arch.
+ supported_arches = ["x86_32", "x86_64", "arm32"]
+ if env["arch"] not in supported_arches:
print(
- """
- Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console
- (or Visual Studio settings) that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits
- argument (example: scons p=uwp) and SCons will attempt to detect what MSVC compiler will be executed and inform you.
- """
+ 'Unsupported CPU architecture "%s" for UWP. Supported architectures are: %s.'
+ % (env["arch"], ", ".join(supported_arches))
)
sys.exit()
+ env.msvc = True
+
## Build type
if env["target"] == "release":
@@ -101,11 +101,10 @@ def configure(env):
arch = ""
if str(os.getenv("Platform")).lower() == "arm":
-
- print("Compiled program architecture will be an ARM executable. (forcing bits=32).")
+ print("Compiled program architecture will be an ARM executable (forcing arch=arm32).")
arch = "arm"
- env["bits"] = "32"
+ env["arch"] = "arm32"
env.Append(LINKFLAGS=["/MACHINE:ARM"])
env.Append(LIBPATH=[vc_base_path + "lib/store/arm"])
@@ -117,20 +116,20 @@ def configure(env):
compiler_version_str = methods.detect_visual_c_compiler_version(env["ENV"])
if compiler_version_str == "amd64" or compiler_version_str == "x86_amd64":
- env["bits"] = "64"
- print("Compiled program architecture will be a x64 executable (forcing bits=64).")
+ env["arch"] = "x86_64"
+ print("Compiled program architecture will be a x64 executable (forcing arch=x86_64).")
elif compiler_version_str == "x86" or compiler_version_str == "amd64_x86":
- env["bits"] = "32"
- print("Compiled program architecture will be a x86 executable. (forcing bits=32).")
+ env["arch"] = "x86_32"
+ print("Compiled program architecture will be a x86 executable (forcing arch=x86_32).")
else:
print(
- "Failed to detect MSVC compiler architecture version... Defaulting to 32-bit executable settings"
- " (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture"
+ "Failed to detect MSVC compiler architecture version... Defaulting to x86 32-bit executable settings"
+ " (forcing arch=x86_32). Compilation attempt will continue, but SCons can not detect for what architecture"
" this build is compiled for. You should check your settings/compilation setup."
)
- env["bits"] = "32"
+ env["arch"] = "x86_32"
- if env["bits"] == "32":
+ if env["arch"] == "x86_32":
arch = "x86"
angle_build_cmd += "Win32"
diff --git a/platform/uwp/export/app_packager.cpp b/platform/uwp/export/app_packager.cpp
index 09717b9d69..87224d38b8 100644
--- a/platform/uwp/export/app_packager.cpp
+++ b/platform/uwp/export/app_packager.cpp
@@ -408,7 +408,7 @@ void AppxPackager::finish() {
// Create and add block map file
EditorNode::progress_task_step("export", "Creating block map...", 4);
- const String &tmp_blockmap_file_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpblockmap.xml");
+ const String &tmp_blockmap_file_path = EditorPaths::get_singleton()->get_cache_dir().path_join("tmpblockmap.xml");
make_block_map(tmp_blockmap_file_path);
{
@@ -425,7 +425,7 @@ void AppxPackager::finish() {
EditorNode::progress_task_step("export", "Setting content types...", 5);
- const String &tmp_content_types_file_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("tmpcontenttypes.xml");
+ const String &tmp_content_types_file_path = EditorPaths::get_singleton()->get_cache_dir().path_join("tmpcontenttypes.xml");
make_content_types(tmp_content_types_file_path);
{
diff --git a/platform/uwp/export/export_plugin.cpp b/platform/uwp/export/export_plugin.cpp
index 070c46242f..4e4afb9704 100644
--- a/platform/uwp/export/export_plugin.cpp
+++ b/platform/uwp/export/export_plugin.cpp
@@ -121,7 +121,7 @@ void EditorExportPlatformUWP::get_export_options(List<ExportOption> *r_options)
}
}
-bool EditorExportPlatformUWP::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+bool EditorExportPlatformUWP::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
#ifndef DEV_ENABLED
// We don't provide export templates for the UWP platform currently as it
// has not been ported for Godot 4.0. This is skipped in DEV_ENABLED so that
@@ -163,7 +163,26 @@ bool EditorExportPlatformUWP::can_export(const Ref<EditorExportPreset> &p_preset
valid = dvalid || rvalid;
r_missing_templates = !valid;
- // Validate the rest of the configuration.
+ if (!err.is_empty()) {
+ r_error = err;
+ }
+
+ return valid;
+}
+
+bool EditorExportPlatformUWP::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const {
+#ifndef DEV_ENABLED
+ // We don't provide export templates for the UWP platform currently as it
+ // has not been ported for Godot 4.0. This is skipped in DEV_ENABLED so that
+ // contributors can still test the pipeline if/when we can build it again.
+ r_error = "The UWP platform is currently not supported in Godot 4.0.\n";
+ return false;
+#endif
+
+ String err;
+ bool valid = true;
+
+ // Validate the project configuration.
if (!_valid_resource_name(p_preset->get("package/short_name"))) {
valid = false;
diff --git a/platform/uwp/export/export_plugin.h b/platform/uwp/export/export_plugin.h
index 4a3c5db377..b0427d1a65 100644
--- a/platform/uwp/export/export_plugin.h
+++ b/platform/uwp/export/export_plugin.h
@@ -329,7 +329,7 @@ class EditorExportPlatformUWP : public EditorExportPlatform {
return data;
}
- String tmp_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("uwp_tmp_logo.png");
+ String tmp_path = EditorPaths::get_singleton()->get_cache_dir().path_join("uwp_tmp_logo.png");
Error err = texture->get_image()->save_png(tmp_path);
@@ -429,7 +429,8 @@ public:
virtual void get_export_options(List<ExportOption> *r_options) override;
- virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index f37759c66f..494f5ec4b9 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -275,7 +275,7 @@ Error OS_UWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
display_request->RequestActive();
}
- set_keep_screen_on(GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true));
+ set_keep_screen_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on"));
return OK;
}
@@ -716,7 +716,7 @@ bool OS_UWP::has_virtual_keyboard() const {
return UIViewSettings::GetForCurrentView()->UserInteractionMode == UserInteractionMode::Touch;
}
-void OS_UWP::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
+void OS_UWP::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect, VirtualKeyboardType p_type, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
InputPane ^ pane = InputPane::GetForCurrentView();
pane->TryShow();
}
@@ -781,7 +781,7 @@ void OS_UWP::run() {
int frames = 0;
uint64_t frame = 0;
- while (!force_quit) {
+ while (true) {
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
if (managed_object->alert_close_handle) {
continue;
@@ -811,7 +811,6 @@ bool OS_UWP::_check_internal_feature_support(const String &p_feature) {
OS_UWP::OS_UWP() {
key_event_pos = 0;
- force_quit = false;
alt_mem = false;
gr_mem = false;
shift_mem = false;
diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h
index b9d035ff41..5a58486ee7 100644
--- a/platform/uwp/os_uwp.h
+++ b/platform/uwp/os_uwp.h
@@ -106,7 +106,6 @@ private:
bool shift_mem;
bool control_mem;
bool meta_mem;
- bool force_quit;
MouseButton last_button_state = MouseButton::NONE;
CursorShape cursor_shape;
@@ -231,7 +230,7 @@ public:
virtual bool has_touchscreen_ui_hint() const;
virtual bool has_virtual_keyboard() const;
- virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1);
+ virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), VirtualKeyboardType p_type = KEYBOARD_TYPE_DEFAULT, int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1);
virtual void hide_virtual_keyboard();
virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr);
diff --git a/platform/javascript/.eslintrc.engine.js b/platform/web/.eslintrc.engine.js
index 78df6d41d9..78df6d41d9 100644
--- a/platform/javascript/.eslintrc.engine.js
+++ b/platform/web/.eslintrc.engine.js
diff --git a/platform/javascript/.eslintrc.js b/platform/web/.eslintrc.js
index 2c81f1f02d..2c81f1f02d 100644
--- a/platform/javascript/.eslintrc.js
+++ b/platform/web/.eslintrc.js
diff --git a/platform/javascript/.eslintrc.libs.js b/platform/web/.eslintrc.libs.js
index 8e579fd462..8e579fd462 100644
--- a/platform/javascript/.eslintrc.libs.js
+++ b/platform/web/.eslintrc.libs.js
diff --git a/platform/web/README.md b/platform/web/README.md
new file mode 100644
index 0000000000..1265ca09df
--- /dev/null
+++ b/platform/web/README.md
@@ -0,0 +1,22 @@
+# Web platform port
+
+This folder contains the C++ and JavaScript code for the Web platform port,
+compiled using [Emscripten](https://emscripten.org/).
+
+It also contains a ESLint linting setup (see [`package.json`](package.json)).
+
+See also [`misc/dist/html`](/misc/dist/html) folder for additional files used by
+this platform such as the html shell (web page).
+
+## Documentation
+
+- [Compiling for the Web](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_web.html)
+ - Instructions on building this platform port from source.
+- [Exporting for the Web](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_web.html)
+ - Instructions on using the compiled export templates to export a project.
+
+## Artwork license
+
+[`logo.png`](logo.png) and [`run_icon.png`](run_icon.png) are licensed under
+[Creative Commons Attribution 3.0 Unported](https://www.w3.org/html/logo/faq.html#how-licenced)
+per the HTML5 logo usage guidelines.
diff --git a/platform/javascript/SCsub b/platform/web/SCsub
index 4827dc4627..78d7ce4074 100644
--- a/platform/javascript/SCsub
+++ b/platform/web/SCsub
@@ -2,14 +2,14 @@
Import("env")
-javascript_files = [
- "audio_driver_javascript.cpp",
- "display_server_javascript.cpp",
- "http_client_javascript.cpp",
+web_files = [
+ "audio_driver_web.cpp",
+ "display_server_web.cpp",
+ "http_client_web.cpp",
"javascript_singleton.cpp",
- "javascript_main.cpp",
- "os_javascript.cpp",
- "api/javascript_tools_editor_plugin.cpp",
+ "web_main.cpp",
+ "os_web.cpp",
+ "api/web_tools_editor_plugin.cpp",
]
sys_env = env.Clone()
@@ -52,14 +52,14 @@ if env["gdnative_enabled"]:
# Force exporting the standard library (printf, malloc, etc.)
sys_env["ENV"]["EMCC_FORCE_STDLIBS"] = "libc,libc++,libc++abi"
# The main emscripten runtime, with exported standard libraries.
- sys = sys_env.Program(build_targets, ["javascript_runtime.cpp"])
+ sys = sys_env.Program(build_targets, ["web_runtime.cpp"])
# The side library, containing all Godot code.
wasm_env = env.Clone()
wasm_env.Append(CPPDEFINES=["WASM_GDNATIVE"]) # So that OS knows it can run GDNative libraries.
wasm_env.Append(CCFLAGS=["-s", "SIDE_MODULE=2"])
wasm_env.Append(LINKFLAGS=["-s", "SIDE_MODULE=2"])
- wasm = wasm_env.add_program("#bin/godot.side${PROGSUFFIX}.wasm", javascript_files)
+ wasm = wasm_env.add_program("#bin/godot.side${PROGSUFFIX}.wasm", web_files)
build = sys + [wasm[0]]
else:
build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"]
@@ -67,7 +67,7 @@ else:
build_targets.append("#bin/godot${PROGSUFFIX}.worker.js")
# We use IDBFS. Since Emscripten 1.39.1 it needs to be linked explicitly.
sys_env.Append(LIBS=["idbfs.js"])
- build = sys_env.Program(build_targets, javascript_files + ["javascript_runtime.cpp"])
+ build = sys_env.Program(build_targets, web_files + ["web_runtime.cpp"])
sys_env.Depends(build[0], sys_env["JS_LIBS"])
sys_env.Depends(build[0], sys_env["JS_PRE"])
@@ -78,7 +78,7 @@ engine = [
"js/engine/config.js",
"js/engine/engine.js",
]
-externs = [env.File("#platform/javascript/js/engine/engine.externs.js")]
+externs = [env.File("#platform/web/js/engine/engine.externs.js")]
js_engine = env.CreateEngineFile("#bin/godot${PROGSUFFIX}.engine.js", engine, externs)
env.Depends(js_engine, externs)
diff --git a/platform/javascript/api/api.cpp b/platform/web/api/api.cpp
index 46a0a816bf..a724b0456d 100644
--- a/platform/javascript/api/api.cpp
+++ b/platform/web/api/api.cpp
@@ -31,20 +31,20 @@
#include "api.h"
#include "core/config/engine.h"
#include "javascript_singleton.h"
-#include "javascript_tools_editor_plugin.h"
+#include "web_tools_editor_plugin.h"
-static JavaScript *javascript_eval;
+static JavaScript *javascript_singleton;
-void register_javascript_api() {
- JavaScriptToolsEditorPlugin::initialize();
+void register_web_api() {
+ WebToolsEditorPlugin::initialize();
GDREGISTER_ABSTRACT_CLASS(JavaScriptObject);
GDREGISTER_ABSTRACT_CLASS(JavaScript);
- javascript_eval = memnew(JavaScript);
- Engine::get_singleton()->add_singleton(Engine::Singleton("JavaScript", javascript_eval));
+ javascript_singleton = memnew(JavaScript);
+ Engine::get_singleton()->add_singleton(Engine::Singleton("JavaScript", javascript_singleton));
}
-void unregister_javascript_api() {
- memdelete(javascript_eval);
+void unregister_web_api() {
+ memdelete(javascript_singleton);
}
JavaScript *JavaScript::singleton = nullptr;
@@ -76,7 +76,7 @@ void JavaScript::_bind_methods() {
ADD_SIGNAL(MethodInfo("pwa_update_available"));
}
-#if !defined(JAVASCRIPT_ENABLED) || !defined(JAVASCRIPT_EVAL_ENABLED)
+#if !defined(WEB_ENABLED) || !defined(JAVASCRIPT_EVAL_ENABLED)
Variant JavaScript::eval(const String &p_code, bool p_use_global_exec_context) {
return Variant();
}
@@ -104,7 +104,7 @@ Variant JavaScript::_create_object_bind(const Variant **p_args, int p_argcount,
return Ref<JavaScriptObject>();
}
#endif
-#if !defined(JAVASCRIPT_ENABLED)
+#if !defined(WEB_ENABLED)
bool JavaScript::pwa_needs_update() const {
return false;
}
diff --git a/platform/javascript/api/api.h b/platform/web/api/api.h
index 97e06c8577..f073e817d1 100644
--- a/platform/javascript/api/api.h
+++ b/platform/web/api/api.h
@@ -28,10 +28,10 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef JAVASCRIPT_API_H
-#define JAVASCRIPT_API_H
+#ifndef WEB_API_H
+#define WEB_API_H
-void register_javascript_api();
-void unregister_javascript_api();
+void register_web_api();
+void unregister_web_api();
-#endif // JAVASCRIPT_API_H
+#endif // WEB_API_H
diff --git a/platform/javascript/api/javascript_singleton.h b/platform/web/api/javascript_singleton.h
index e93b0a18a1..e93b0a18a1 100644
--- a/platform/javascript/api/javascript_singleton.h
+++ b/platform/web/api/javascript_singleton.h
diff --git a/platform/javascript/api/javascript_tools_editor_plugin.cpp b/platform/web/api/web_tools_editor_plugin.cpp
index 1507f32375..46fcb2d452 100644
--- a/platform/javascript/api/javascript_tools_editor_plugin.cpp
+++ b/platform/web/api/web_tools_editor_plugin.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* javascript_tools_editor_plugin.cpp */
+/* web_tools_editor_plugin.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#if defined(TOOLS_ENABLED) && defined(JAVASCRIPT_ENABLED)
-#include "javascript_tools_editor_plugin.h"
+#if defined(TOOLS_ENABLED) && defined(WEB_ENABLED)
+#include "web_tools_editor_plugin.h"
#include "core/config/engine.h"
#include "core/config/project_settings.h"
@@ -40,24 +40,24 @@
#include <emscripten/emscripten.h>
-// JavaScript functions defined in library_godot_editor_tools.js
+// Web functions defined in library_godot_editor_tools.js
extern "C" {
extern void godot_js_os_download_buffer(const uint8_t *p_buf, int p_buf_size, const char *p_name, const char *p_mime);
}
-static void _javascript_editor_init_callback() {
- EditorNode::get_singleton()->add_editor_plugin(memnew(JavaScriptToolsEditorPlugin));
+static void _web_editor_init_callback() {
+ EditorNode::get_singleton()->add_editor_plugin(memnew(WebToolsEditorPlugin));
}
-void JavaScriptToolsEditorPlugin::initialize() {
- EditorNode::add_init_callback(_javascript_editor_init_callback);
+void WebToolsEditorPlugin::initialize() {
+ EditorNode::add_init_callback(_web_editor_init_callback);
}
-JavaScriptToolsEditorPlugin::JavaScriptToolsEditorPlugin() {
- add_tool_menu_item("Download Project Source", callable_mp(this, &JavaScriptToolsEditorPlugin::_download_zip));
+WebToolsEditorPlugin::WebToolsEditorPlugin() {
+ add_tool_menu_item("Download Project Source", callable_mp(this, &WebToolsEditorPlugin::_download_zip));
}
-void JavaScriptToolsEditorPlugin::_download_zip(Variant p_v) {
+void WebToolsEditorPlugin::_download_zip(Variant p_v) {
if (!Engine::get_singleton() || !Engine::get_singleton()->is_editor_hint()) {
ERR_PRINT("Downloading the project as a ZIP archive is only available in Editor mode.");
return;
@@ -76,7 +76,7 @@ void JavaScriptToolsEditorPlugin::_download_zip(Variant p_v) {
const String datetime_safe =
Time::get_singleton()->get_datetime_string_from_system(false, true).replace(" ", "_");
const String output_name = OS::get_singleton()->get_safe_dir_name(vformat("%s_%s.zip"));
- const String output_path = String("/tmp").plus_file(output_name);
+ const String output_path = String("/tmp").path_join(output_name);
zipFile zip = zipOpen2(output_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io);
const String base_path = resource_path.substr(0, resource_path.rfind("/")) + "/";
@@ -95,7 +95,7 @@ void JavaScriptToolsEditorPlugin::_download_zip(Variant p_v) {
DirAccess::remove_file_or_error(output_path);
}
-void JavaScriptToolsEditorPlugin::_zip_file(String p_path, String p_base_path, zipFile p_zip) {
+void WebToolsEditorPlugin::_zip_file(String p_path, String p_base_path, zipFile p_zip) {
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
if (f.is_null()) {
WARN_PRINT("Unable to open file for zipping: " + p_path);
@@ -121,7 +121,7 @@ void JavaScriptToolsEditorPlugin::_zip_file(String p_path, String p_base_path, z
zipCloseFileInZip(p_zip);
}
-void JavaScriptToolsEditorPlugin::_zip_recursive(String p_path, String p_base_path, zipFile p_zip) {
+void WebToolsEditorPlugin::_zip_recursive(String p_path, String p_base_path, zipFile p_zip) {
Ref<DirAccess> dir = DirAccess::open(p_path);
if (dir.is_null()) {
WARN_PRINT("Unable to open directory for zipping: " + p_path);
@@ -131,7 +131,7 @@ void JavaScriptToolsEditorPlugin::_zip_recursive(String p_path, String p_base_pa
String cur = dir->get_next();
String project_data_dir_name = ProjectSettings::get_singleton()->get_project_data_dir_name();
while (!cur.is_empty()) {
- String cs = p_path.plus_file(cur);
+ String cs = p_path.path_join(cur);
if (cur == "." || cur == ".." || cur == project_data_dir_name) {
// Skip
} else if (dir->current_is_dir()) {
diff --git a/platform/javascript/api/javascript_tools_editor_plugin.h b/platform/web/api/web_tools_editor_plugin.h
index cbf5f49497..6af1dec3fb 100644
--- a/platform/javascript/api/javascript_tools_editor_plugin.h
+++ b/platform/web/api/web_tools_editor_plugin.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* javascript_tools_editor_plugin.h */
+/* web_tools_editor_plugin.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,15 +28,15 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef JAVASCRIPT_TOOLS_EDITOR_PLUGIN_H
-#define JAVASCRIPT_TOOLS_EDITOR_PLUGIN_H
+#ifndef WEB_TOOLS_EDITOR_PLUGIN_H
+#define WEB_TOOLS_EDITOR_PLUGIN_H
-#if defined(TOOLS_ENABLED) && defined(JAVASCRIPT_ENABLED)
+#if defined(TOOLS_ENABLED) && defined(WEB_ENABLED)
#include "core/io/zip_io.h"
#include "editor/editor_plugin.h"
-class JavaScriptToolsEditorPlugin : public EditorPlugin {
- GDCLASS(JavaScriptToolsEditorPlugin, EditorPlugin);
+class WebToolsEditorPlugin : public EditorPlugin {
+ GDCLASS(WebToolsEditorPlugin, EditorPlugin);
private:
void _zip_file(String p_path, String p_base_path, zipFile p_zip);
@@ -46,13 +46,13 @@ private:
public:
static void initialize();
- JavaScriptToolsEditorPlugin();
+ WebToolsEditorPlugin();
};
#else
-class JavaScriptToolsEditorPlugin {
+class WebToolsEditorPlugin {
public:
static void initialize() {}
};
#endif
-#endif // JAVASCRIPT_TOOLS_EDITOR_PLUGIN_H
+#endif // WEB_TOOLS_EDITOR_PLUGIN_H
diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/web/audio_driver_web.cpp
index d45885b8e8..0e37afc2cc 100644
--- a/platform/javascript/audio_driver_javascript.cpp
+++ b/platform/web/audio_driver_web.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* audio_driver_javascript.cpp */
+/* audio_driver_web.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,27 +28,27 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "audio_driver_javascript.h"
+#include "audio_driver_web.h"
#include "core/config/project_settings.h"
#include <emscripten.h>
-AudioDriverJavaScript::AudioContext AudioDriverJavaScript::audio_context;
+AudioDriverWeb::AudioContext AudioDriverWeb::audio_context;
-bool AudioDriverJavaScript::is_available() {
+bool AudioDriverWeb::is_available() {
return godot_audio_is_available() != 0;
}
-void AudioDriverJavaScript::_state_change_callback(int p_state) {
- AudioDriverJavaScript::audio_context.state = p_state;
+void AudioDriverWeb::_state_change_callback(int p_state) {
+ AudioDriverWeb::audio_context.state = p_state;
}
-void AudioDriverJavaScript::_latency_update_callback(float p_latency) {
- AudioDriverJavaScript::audio_context.output_latency = p_latency;
+void AudioDriverWeb::_latency_update_callback(float p_latency) {
+ AudioDriverWeb::audio_context.output_latency = p_latency;
}
-void AudioDriverJavaScript::_audio_driver_process(int p_from, int p_samples) {
+void AudioDriverWeb::_audio_driver_process(int p_from, int p_samples) {
int32_t *stream_buffer = reinterpret_cast<int32_t *>(output_rb);
const int max_samples = memarr_len(output_rb);
@@ -74,7 +74,7 @@ void AudioDriverJavaScript::_audio_driver_process(int p_from, int p_samples) {
}
}
-void AudioDriverJavaScript::_audio_driver_capture(int p_from, int p_samples) {
+void AudioDriverWeb::_audio_driver_capture(int p_from, int p_samples) {
if (get_input_buffer().size() == 0) {
return; // Input capture stopped.
}
@@ -100,7 +100,7 @@ void AudioDriverJavaScript::_audio_driver_capture(int p_from, int p_samples) {
}
}
-Error AudioDriverJavaScript::init() {
+Error AudioDriverWeb::init() {
int latency = GLOBAL_GET("audio/driver/output_latency");
if (!audio_context.inited) {
audio_context.mix_rate = GLOBAL_GET("audio/driver/mix_rate");
@@ -132,29 +132,29 @@ Error AudioDriverJavaScript::init() {
return OK;
}
-void AudioDriverJavaScript::start() {
+void AudioDriverWeb::start() {
start(output_rb, memarr_len(output_rb), input_rb, memarr_len(input_rb));
}
-void AudioDriverJavaScript::resume() {
+void AudioDriverWeb::resume() {
if (audio_context.state == 0) { // 'suspended'
godot_audio_resume();
}
}
-float AudioDriverJavaScript::get_latency() {
+float AudioDriverWeb::get_latency() {
return audio_context.output_latency + (float(buffer_length) / mix_rate);
}
-int AudioDriverJavaScript::get_mix_rate() const {
+int AudioDriverWeb::get_mix_rate() const {
return mix_rate;
}
-AudioDriver::SpeakerMode AudioDriverJavaScript::get_speaker_mode() const {
+AudioDriver::SpeakerMode AudioDriverWeb::get_speaker_mode() const {
return get_speaker_mode_by_total_channels(channel_count);
}
-void AudioDriverJavaScript::finish() {
+void AudioDriverWeb::finish() {
finish_driver();
if (output_rb) {
memdelete_arr(output_rb);
@@ -166,7 +166,7 @@ void AudioDriverJavaScript::finish() {
}
}
-Error AudioDriverJavaScript::capture_start() {
+Error AudioDriverWeb::capture_start() {
lock();
input_buffer_init(buffer_length);
unlock();
@@ -176,7 +176,7 @@ Error AudioDriverJavaScript::capture_start() {
return OK;
}
-Error AudioDriverJavaScript::capture_stop() {
+Error AudioDriverWeb::capture_stop() {
godot_audio_capture_stop();
lock();
input_buffer.clear();
diff --git a/platform/javascript/audio_driver_javascript.h b/platform/web/audio_driver_web.h
index 807e2f936b..dfce277c0c 100644
--- a/platform/javascript/audio_driver_javascript.h
+++ b/platform/web/audio_driver_web.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* audio_driver_javascript.h */
+/* audio_driver_web.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef AUDIO_DRIVER_JAVASCRIPT_H
-#define AUDIO_DRIVER_JAVASCRIPT_H
+#ifndef AUDIO_DRIVER_WEB_H
+#define AUDIO_DRIVER_WEB_H
#include "core/os/mutex.h"
#include "core/os/thread.h"
@@ -37,7 +37,7 @@
#include "godot_audio.h"
-class AudioDriverJavaScript : public AudioDriver {
+class AudioDriverWeb : public AudioDriver {
private:
struct AudioContext {
bool inited = false;
@@ -58,7 +58,7 @@ private:
static void _state_change_callback(int p_state);
static void _latency_update_callback(float p_latency);
- static AudioDriverJavaScript *singleton;
+ static AudioDriverWeb *singleton;
protected:
void _audio_driver_process(int p_from = 0, int p_samples = 0);
@@ -86,11 +86,11 @@ public:
static void resume();
- AudioDriverJavaScript() {}
+ AudioDriverWeb() {}
};
#ifdef NO_THREADS
-class AudioDriverScriptProcessor : public AudioDriverJavaScript {
+class AudioDriverScriptProcessor : public AudioDriverWeb {
private:
static void _process_callback();
@@ -109,7 +109,7 @@ public:
AudioDriverScriptProcessor() { singleton = this; }
};
-class AudioDriverWorklet : public AudioDriverJavaScript {
+class AudioDriverWorklet : public AudioDriverWeb {
private:
static void _process_callback(int p_pos, int p_samples);
static void _capture_callback(int p_pos, int p_samples);
@@ -129,7 +129,7 @@ public:
AudioDriverWorklet() { singleton = this; }
};
#else
-class AudioDriverWorklet : public AudioDriverJavaScript {
+class AudioDriverWorklet : public AudioDriverWeb {
private:
enum {
STATE_LOCK,
@@ -158,4 +158,4 @@ public:
};
#endif
-#endif // AUDIO_DRIVER_JAVASCRIPT_H
+#endif // AUDIO_DRIVER_WEB_H
diff --git a/platform/javascript/detect.py b/platform/web/detect.py
index a769260f01..ae0ff2c4ea 100644
--- a/platform/javascript/detect.py
+++ b/platform/web/detect.py
@@ -18,7 +18,7 @@ def is_active():
def get_name():
- return "JavaScript"
+ return "Web"
def can_build():
@@ -46,6 +46,7 @@ def get_opts():
def get_flags():
return [
+ ("arch", "wasm32"),
("tools", False),
("builtin_pcre2_with_jit", False),
("vulkan", False),
@@ -53,6 +54,15 @@ def get_flags():
def configure(env):
+ # Validate arch.
+ supported_arches = ["wasm32"]
+ if env["arch"] not in supported_arches:
+ print(
+ 'Unsupported CPU architecture "%s" for iOS. Supported architectures are: %s.'
+ % (env["arch"], ", ".join(supported_arches))
+ )
+ sys.exit()
+
try:
env["initial_memory"] = int(env["initial_memory"])
except Exception:
@@ -172,8 +182,8 @@ def configure(env):
env["LIBPREFIXES"] = ["$LIBPREFIX"]
env["LIBSUFFIXES"] = ["$LIBSUFFIX"]
- env.Prepend(CPPPATH=["#platform/javascript"])
- env.Append(CPPDEFINES=["JAVASCRIPT_ENABLED", "UNIX_ENABLED"])
+ env.Prepend(CPPPATH=["#platform/web"])
+ env.Append(CPPDEFINES=["WEB_ENABLED", "UNIX_ENABLED"])
if env["opengl3"]:
env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"])
diff --git a/platform/javascript/display_server_javascript.cpp b/platform/web/display_server_web.cpp
index bcff3306d5..b36f9d14a4 100644
--- a/platform/javascript/display_server_javascript.cpp
+++ b/platform/web/display_server_web.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* display_server_javascript.cpp */
+/* display_server_web.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,12 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "display_server_javascript.h"
+#include "display_server_web.h"
#ifdef GLES3_ENABLED
#include "drivers/gles3/rasterizer_gles3.h"
#endif
-#include "platform/javascript/os_javascript.h"
+#include "platform/web/os_web.h"
#include "servers/rendering/dummy/rasterizer_dummy.h"
#include <emscripten.h>
@@ -48,17 +48,17 @@
#define DOM_BUTTON_XBUTTON1 3
#define DOM_BUTTON_XBUTTON2 4
-DisplayServerJavaScript *DisplayServerJavaScript::get_singleton() {
- return static_cast<DisplayServerJavaScript *>(DisplayServer::get_singleton());
+DisplayServerWeb *DisplayServerWeb::get_singleton() {
+ return static_cast<DisplayServerWeb *>(DisplayServer::get_singleton());
}
// Window (canvas)
-bool DisplayServerJavaScript::check_size_force_redraw() {
+bool DisplayServerWeb::check_size_force_redraw() {
return godot_js_display_size_update() != 0;
}
-void DisplayServerJavaScript::fullscreen_change_callback(int p_fullscreen) {
- DisplayServerJavaScript *display = get_singleton();
+void DisplayServerWeb::fullscreen_change_callback(int p_fullscreen) {
+ DisplayServerWeb *display = get_singleton();
if (p_fullscreen) {
display->window_mode = WINDOW_MODE_FULLSCREEN;
} else {
@@ -67,8 +67,8 @@ void DisplayServerJavaScript::fullscreen_change_callback(int p_fullscreen) {
}
// Drag and drop callback.
-void DisplayServerJavaScript::drop_files_js_callback(char **p_filev, int p_filec) {
- DisplayServerJavaScript *ds = get_singleton();
+void DisplayServerWeb::drop_files_js_callback(char **p_filev, int p_filec) {
+ DisplayServerWeb *ds = get_singleton();
if (!ds) {
ERR_FAIL_MSG("Unable to drop files because the DisplayServer is not active");
}
@@ -86,9 +86,9 @@ void DisplayServerJavaScript::drop_files_js_callback(char **p_filev, int p_filec
ds->drop_files_callback.callp((const Variant **)&vp, 1, ret, ce);
}
-// JavaScript quit request callback.
-void DisplayServerJavaScript::request_quit_callback() {
- DisplayServerJavaScript *ds = get_singleton();
+// Web quit request callback.
+void DisplayServerWeb::request_quit_callback() {
+ DisplayServerWeb *ds = get_singleton();
if (ds && !ds->window_event_callback.is_null()) {
Variant event = int(DisplayServer::WINDOW_EVENT_CLOSE_REQUEST);
Variant *eventp = &event;
@@ -100,18 +100,18 @@ void DisplayServerJavaScript::request_quit_callback() {
// Keys
-void DisplayServerJavaScript::dom2godot_mod(Ref<InputEventWithModifiers> ev, int p_mod) {
+void DisplayServerWeb::dom2godot_mod(Ref<InputEventWithModifiers> ev, int p_mod) {
ev->set_shift_pressed(p_mod & 1);
ev->set_alt_pressed(p_mod & 2);
ev->set_ctrl_pressed(p_mod & 4);
ev->set_meta_pressed(p_mod & 8);
}
-void DisplayServerJavaScript::key_callback(int p_pressed, int p_repeat, int p_modifiers) {
- DisplayServerJavaScript *ds = get_singleton();
+void DisplayServerWeb::key_callback(int p_pressed, int p_repeat, int p_modifiers) {
+ DisplayServerWeb *ds = get_singleton();
JSKeyEvent &key_event = ds->key_event;
// Resume audio context after input in case autoplay was denied.
- OS_JavaScript::get_singleton()->resume_audio();
+ OS_Web::get_singleton()->resume_audio();
Ref<InputEventKey> ev;
ev.instantiate();
@@ -133,8 +133,8 @@ void DisplayServerJavaScript::key_callback(int p_pressed, int p_repeat, int p_mo
// Mouse
-int DisplayServerJavaScript::mouse_button_callback(int p_pressed, int p_button, double p_x, double p_y, int p_modifiers) {
- DisplayServerJavaScript *ds = get_singleton();
+int DisplayServerWeb::mouse_button_callback(int p_pressed, int p_button, double p_x, double p_y, int p_modifiers) {
+ DisplayServerWeb *ds = get_singleton();
Point2 pos(p_x, p_y);
Ref<InputEventMouseButton> ev;
@@ -199,7 +199,7 @@ int DisplayServerJavaScript::mouse_button_callback(int p_pressed, int p_button,
Input::get_singleton()->parse_input_event(ev);
// Resume audio context after input in case autoplay was denied.
- OS_JavaScript::get_singleton()->resume_audio();
+ OS_Web::get_singleton()->resume_audio();
// Make sure to flush all events so we can call restricted APIs inside the event.
Input::get_singleton()->flush_buffered_events();
@@ -209,7 +209,7 @@ int DisplayServerJavaScript::mouse_button_callback(int p_pressed, int p_button,
return true;
}
-void DisplayServerJavaScript::mouse_move_callback(double p_x, double p_y, double p_rel_x, double p_rel_y, int p_modifiers) {
+void DisplayServerWeb::mouse_move_callback(double p_x, double p_y, double p_rel_x, double p_rel_y, int p_modifiers) {
MouseButton input_mask = Input::get_singleton()->get_mouse_button_mask();
// For motion outside the canvas, only read mouse movement if dragging
// started inside the canvas; imitating desktop app behaviour.
@@ -233,7 +233,7 @@ void DisplayServerJavaScript::mouse_move_callback(double p_x, double p_y, double
}
// Cursor
-const char *DisplayServerJavaScript::godot2dom_cursor(DisplayServer::CursorShape p_shape) {
+const char *DisplayServerWeb::godot2dom_cursor(DisplayServer::CursorShape p_shape) {
switch (p_shape) {
case DisplayServer::CURSOR_ARROW:
return "default";
@@ -274,15 +274,15 @@ const char *DisplayServerJavaScript::godot2dom_cursor(DisplayServer::CursorShape
}
}
-bool DisplayServerJavaScript::tts_is_speaking() const {
+bool DisplayServerWeb::tts_is_speaking() const {
return godot_js_tts_is_speaking();
}
-bool DisplayServerJavaScript::tts_is_paused() const {
+bool DisplayServerWeb::tts_is_paused() const {
return godot_js_tts_is_paused();
}
-void DisplayServerJavaScript::update_voices_callback(int p_size, const char **p_voice) {
+void DisplayServerWeb::update_voices_callback(int p_size, const char **p_voice) {
get_singleton()->voices.clear();
for (int i = 0; i < p_size; i++) {
Vector<String> tokens = String::utf8(p_voice[i]).split(";", true, 2);
@@ -296,12 +296,12 @@ void DisplayServerJavaScript::update_voices_callback(int p_size, const char **p_
}
}
-Array DisplayServerJavaScript::tts_get_voices() const {
+TypedArray<Dictionary> DisplayServerWeb::tts_get_voices() const {
godot_js_tts_get_voices(update_voices_callback);
return voices;
}
-void DisplayServerJavaScript::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) {
+void DisplayServerWeb::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) {
if (p_interrupt) {
tts_stop();
}
@@ -314,18 +314,18 @@ void DisplayServerJavaScript::tts_speak(const String &p_text, const String &p_vo
CharString string = p_text.utf8();
utterance_ids[p_utterance_id] = string;
- godot_js_tts_speak(string.get_data(), p_voice.utf8().get_data(), CLAMP(p_volume, 0, 100), CLAMP(p_pitch, 0.f, 2.f), CLAMP(p_rate, 0.1f, 10.f), p_utterance_id, DisplayServerJavaScript::_js_utterance_callback);
+ godot_js_tts_speak(string.get_data(), p_voice.utf8().get_data(), CLAMP(p_volume, 0, 100), CLAMP(p_pitch, 0.f, 2.f), CLAMP(p_rate, 0.1f, 10.f), p_utterance_id, DisplayServerWeb::_js_utterance_callback);
}
-void DisplayServerJavaScript::tts_pause() {
+void DisplayServerWeb::tts_pause() {
godot_js_tts_pause();
}
-void DisplayServerJavaScript::tts_resume() {
+void DisplayServerWeb::tts_resume() {
godot_js_tts_resume();
}
-void DisplayServerJavaScript::tts_stop() {
+void DisplayServerWeb::tts_stop() {
for (const KeyValue<int, CharString> &E : utterance_ids) {
tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_CANCELED, E.key);
}
@@ -333,8 +333,8 @@ void DisplayServerJavaScript::tts_stop() {
godot_js_tts_stop();
}
-void DisplayServerJavaScript::_js_utterance_callback(int p_event, int p_id, int p_pos) {
- DisplayServerJavaScript *ds = (DisplayServerJavaScript *)DisplayServer::get_singleton();
+void DisplayServerWeb::_js_utterance_callback(int p_event, int p_id, int p_pos) {
+ DisplayServerWeb *ds = (DisplayServerWeb *)DisplayServer::get_singleton();
if (ds->utterance_ids.has(p_id)) {
int pos = 0;
if ((TTSUtteranceEvent)p_event == DisplayServer::TTS_UTTERANCE_BOUNDARY) {
@@ -358,7 +358,7 @@ void DisplayServerJavaScript::_js_utterance_callback(int p_event, int p_id, int
}
}
-void DisplayServerJavaScript::cursor_set_shape(CursorShape p_shape) {
+void DisplayServerWeb::cursor_set_shape(CursorShape p_shape) {
ERR_FAIL_INDEX(p_shape, CURSOR_MAX);
if (cursor_shape == p_shape) {
return;
@@ -367,11 +367,11 @@ void DisplayServerJavaScript::cursor_set_shape(CursorShape p_shape) {
godot_js_display_cursor_set_shape(godot2dom_cursor(cursor_shape));
}
-DisplayServer::CursorShape DisplayServerJavaScript::cursor_get_shape() const {
+DisplayServer::CursorShape DisplayServerWeb::cursor_get_shape() const {
return cursor_shape;
}
-void DisplayServerJavaScript::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
+void DisplayServerWeb::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
if (p_cursor.is_valid()) {
Ref<Texture2D> texture = p_cursor;
Ref<AtlasTexture> atlas_texture = p_cursor;
@@ -446,8 +446,8 @@ void DisplayServerJavaScript::cursor_set_custom_image(const Ref<Resource> &p_cur
}
// Mouse mode
-void DisplayServerJavaScript::mouse_set_mode(MouseMode p_mode) {
- ERR_FAIL_COND_MSG(p_mode == MOUSE_MODE_CONFINED || p_mode == MOUSE_MODE_CONFINED_HIDDEN, "MOUSE_MODE_CONFINED is not supported for the HTML5 platform.");
+void DisplayServerWeb::mouse_set_mode(MouseMode p_mode) {
+ ERR_FAIL_COND_MSG(p_mode == MOUSE_MODE_CONFINED || p_mode == MOUSE_MODE_CONFINED_HIDDEN, "MOUSE_MODE_CONFINED is not supported for the Web platform.");
if (p_mode == mouse_get_mode()) {
return;
}
@@ -466,7 +466,7 @@ void DisplayServerJavaScript::mouse_set_mode(MouseMode p_mode) {
}
}
-DisplayServer::MouseMode DisplayServerJavaScript::mouse_get_mode() const {
+DisplayServer::MouseMode DisplayServerWeb::mouse_get_mode() const {
if (godot_js_display_cursor_is_hidden()) {
return MOUSE_MODE_HIDDEN;
}
@@ -477,12 +477,12 @@ DisplayServer::MouseMode DisplayServerJavaScript::mouse_get_mode() const {
return MOUSE_MODE_VISIBLE;
}
-Point2i DisplayServerJavaScript::mouse_get_position() const {
+Point2i DisplayServerWeb::mouse_get_position() const {
return Input::get_singleton()->get_mouse_position();
}
// Wheel
-int DisplayServerJavaScript::mouse_wheel_callback(double p_delta_x, double p_delta_y) {
+int DisplayServerWeb::mouse_wheel_callback(double p_delta_x, double p_delta_y) {
if (!godot_js_display_canvas_is_focused()) {
if (get_singleton()->cursor_inside_canvas) {
godot_js_display_canvas_focus();
@@ -532,8 +532,8 @@ int DisplayServerJavaScript::mouse_wheel_callback(double p_delta_x, double p_del
}
// Touch
-void DisplayServerJavaScript::touch_callback(int p_type, int p_count) {
- DisplayServerJavaScript *ds = get_singleton();
+void DisplayServerWeb::touch_callback(int p_type, int p_count) {
+ DisplayServerWeb *ds = get_singleton();
const JSTouchEvent &touch_event = ds->touch_event;
for (int i = 0; i < p_count; i++) {
@@ -555,7 +555,7 @@ void DisplayServerJavaScript::touch_callback(int p_type, int p_count) {
Ref<InputEventScreenTouch> ev;
// Resume audio context after input in case autoplay was denied.
- OS_JavaScript::get_singleton()->resume_audio();
+ OS_Web::get_singleton()->resume_audio();
ev.instantiate();
ev->set_index(touch_event.identifier[i]);
@@ -571,13 +571,13 @@ void DisplayServerJavaScript::touch_callback(int p_type, int p_count) {
}
}
-bool DisplayServerJavaScript::screen_is_touchscreen(int p_screen) const {
+bool DisplayServerWeb::screen_is_touchscreen(int p_screen) const {
return godot_js_display_touchscreen_is_available();
}
// Virtual Keyboard
-void DisplayServerJavaScript::vk_input_text_callback(const char *p_text, int p_cursor) {
- DisplayServerJavaScript *ds = DisplayServerJavaScript::get_singleton();
+void DisplayServerWeb::vk_input_text_callback(const char *p_text, int p_cursor) {
+ DisplayServerWeb *ds = DisplayServerWeb::get_singleton();
if (!ds || ds->input_text_callback.is_null()) {
return;
}
@@ -604,20 +604,20 @@ void DisplayServerJavaScript::vk_input_text_callback(const char *p_text, int p_c
}
}
-void DisplayServerJavaScript::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
- godot_js_display_vk_show(p_existing_text.utf8().get_data(), p_multiline, p_cursor_start, p_cursor_end);
+void DisplayServerWeb::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, VirtualKeyboardType p_type, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
+ godot_js_display_vk_show(p_existing_text.utf8().get_data(), p_type, p_cursor_start, p_cursor_end);
}
-void DisplayServerJavaScript::virtual_keyboard_hide() {
+void DisplayServerWeb::virtual_keyboard_hide() {
godot_js_display_vk_hide();
}
-void DisplayServerJavaScript::window_blur_callback() {
+void DisplayServerWeb::window_blur_callback() {
Input::get_singleton()->release_pressed_events();
}
// Gamepad
-void DisplayServerJavaScript::gamepad_callback(int p_index, int p_connected, const char *p_id, const char *p_guid) {
+void DisplayServerWeb::gamepad_callback(int p_index, int p_connected, const char *p_id, const char *p_guid) {
Input *input = Input::get_singleton();
if (p_connected) {
input->joy_connection_changed(p_index, true, String::utf8(p_id), String::utf8(p_guid));
@@ -626,7 +626,7 @@ void DisplayServerJavaScript::gamepad_callback(int p_index, int p_connected, con
}
}
-void DisplayServerJavaScript::process_joypads() {
+void DisplayServerWeb::process_joypads() {
Input *input = Input::get_singleton();
int32_t pads = godot_js_input_gamepad_sample_count();
int32_t s_btns_num = 0;
@@ -654,7 +654,7 @@ void DisplayServerJavaScript::process_joypads() {
}
}
-Vector<String> DisplayServerJavaScript::get_rendering_drivers_func() {
+Vector<String> DisplayServerWeb::get_rendering_drivers_func() {
Vector<String> drivers;
#ifdef GLES3_ENABLED
drivers.push_back("opengl3");
@@ -663,23 +663,23 @@ Vector<String> DisplayServerJavaScript::get_rendering_drivers_func() {
}
// Clipboard
-void DisplayServerJavaScript::update_clipboard_callback(const char *p_text) {
+void DisplayServerWeb::update_clipboard_callback(const char *p_text) {
get_singleton()->clipboard = String::utf8(p_text);
}
-void DisplayServerJavaScript::clipboard_set(const String &p_text) {
+void DisplayServerWeb::clipboard_set(const String &p_text) {
clipboard = p_text;
int err = godot_js_display_clipboard_set(p_text.utf8().get_data());
ERR_FAIL_COND_MSG(err, "Clipboard API is not supported.");
}
-String DisplayServerJavaScript::clipboard_get() const {
+String DisplayServerWeb::clipboard_get() const {
godot_js_display_clipboard_get(update_clipboard_callback);
return clipboard;
}
-void DisplayServerJavaScript::send_window_event_callback(int p_notification) {
- DisplayServerJavaScript *ds = get_singleton();
+void DisplayServerWeb::send_window_event_callback(int p_notification) {
+ DisplayServerWeb *ds = get_singleton();
if (!ds) {
return;
}
@@ -695,7 +695,7 @@ void DisplayServerJavaScript::send_window_event_callback(int p_notification) {
}
}
-void DisplayServerJavaScript::set_icon(const Ref<Image> &p_icon) {
+void DisplayServerWeb::set_icon(const Ref<Image> &p_icon) {
ERR_FAIL_COND(p_icon.is_null());
Ref<Image> icon = p_icon;
if (icon->is_compressed()) {
@@ -727,7 +727,7 @@ void DisplayServerJavaScript::set_icon(const Ref<Image> &p_icon) {
godot_js_display_window_icon_set(png.ptr(), len);
}
-void DisplayServerJavaScript::_dispatch_input_event(const Ref<InputEvent> &p_event) {
+void DisplayServerWeb::_dispatch_input_event(const Ref<InputEvent> &p_event) {
Callable cb = get_singleton()->input_event_callback;
if (!cb.is_null()) {
Variant ev = p_event;
@@ -738,11 +738,11 @@ void DisplayServerJavaScript::_dispatch_input_event(const Ref<InputEvent> &p_eve
}
}
-DisplayServer *DisplayServerJavaScript::create_func(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Size2i &p_resolution, Error &r_error) {
- return memnew(DisplayServerJavaScript(p_rendering_driver, p_window_mode, p_vsync_mode, p_flags, p_resolution, r_error));
+DisplayServer *DisplayServerWeb::create_func(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Size2i &p_resolution, Error &r_error) {
+ return memnew(DisplayServerWeb(p_rendering_driver, p_window_mode, p_vsync_mode, p_flags, p_resolution, r_error));
}
-DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Size2i &p_resolution, Error &r_error) {
+DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Size2i &p_resolution, Error &r_error) {
r_error = OK; // Always succeeds for now.
// Ensure the canvas ID.
@@ -788,17 +788,17 @@ DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_drive
#endif
// JS Input interface (js/libs/library_godot_input.js)
- godot_js_input_mouse_button_cb(&DisplayServerJavaScript::mouse_button_callback);
- godot_js_input_mouse_move_cb(&DisplayServerJavaScript::mouse_move_callback);
- godot_js_input_mouse_wheel_cb(&DisplayServerJavaScript::mouse_wheel_callback);
- godot_js_input_touch_cb(&DisplayServerJavaScript::touch_callback, touch_event.identifier, touch_event.coords);
- godot_js_input_key_cb(&DisplayServerJavaScript::key_callback, key_event.code, key_event.key);
+ godot_js_input_mouse_button_cb(&DisplayServerWeb::mouse_button_callback);
+ godot_js_input_mouse_move_cb(&DisplayServerWeb::mouse_move_callback);
+ godot_js_input_mouse_wheel_cb(&DisplayServerWeb::mouse_wheel_callback);
+ godot_js_input_touch_cb(&DisplayServerWeb::touch_callback, touch_event.identifier, touch_event.coords);
+ godot_js_input_key_cb(&DisplayServerWeb::key_callback, key_event.code, key_event.key);
godot_js_input_paste_cb(update_clipboard_callback);
godot_js_input_drop_files_cb(drop_files_js_callback);
- godot_js_input_gamepad_cb(&DisplayServerJavaScript::gamepad_callback);
+ godot_js_input_gamepad_cb(&DisplayServerWeb::gamepad_callback);
// JS Display interface (js/libs/library_godot_display.js)
- godot_js_display_fullscreen_cb(&DisplayServerJavaScript::fullscreen_change_callback);
+ godot_js_display_fullscreen_cb(&DisplayServerWeb::fullscreen_change_callback);
godot_js_display_window_blur_cb(&window_blur_callback);
godot_js_display_notification_cb(&send_window_event_callback,
WINDOW_EVENT_MOUSE_ENTER,
@@ -810,7 +810,7 @@ DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_drive
Input::get_singleton()->set_event_dispatch_function(_dispatch_input_event);
}
-DisplayServerJavaScript::~DisplayServerJavaScript() {
+DisplayServerWeb::~DisplayServerWeb() {
#ifdef GLES3_ENABLED
if (webgl_ctx) {
emscripten_webgl_commit_frame();
@@ -819,7 +819,7 @@ DisplayServerJavaScript::~DisplayServerJavaScript() {
#endif
}
-bool DisplayServerJavaScript::has_feature(Feature p_feature) const {
+bool DisplayServerWeb::has_feature(Feature p_feature) const {
switch (p_feature) {
//case FEATURE_GLOBAL_MENU:
//case FEATURE_HIDPI:
@@ -846,139 +846,139 @@ bool DisplayServerJavaScript::has_feature(Feature p_feature) const {
}
}
-void DisplayServerJavaScript::register_javascript_driver() {
- register_create_function("javascript", create_func, get_rendering_drivers_func);
+void DisplayServerWeb::register_web_driver() {
+ register_create_function("web", create_func, get_rendering_drivers_func);
}
-String DisplayServerJavaScript::get_name() const {
- return "javascript";
+String DisplayServerWeb::get_name() const {
+ return "web";
}
-int DisplayServerJavaScript::get_screen_count() const {
+int DisplayServerWeb::get_screen_count() const {
return 1;
}
-Point2i DisplayServerJavaScript::screen_get_position(int p_screen) const {
+Point2i DisplayServerWeb::screen_get_position(int p_screen) const {
return Point2i(); // TODO offsetX/Y?
}
-Size2i DisplayServerJavaScript::screen_get_size(int p_screen) const {
+Size2i DisplayServerWeb::screen_get_size(int p_screen) const {
int size[2];
godot_js_display_screen_size_get(size, size + 1);
return Size2(size[0], size[1]);
}
-Rect2i DisplayServerJavaScript::screen_get_usable_rect(int p_screen) const {
+Rect2i DisplayServerWeb::screen_get_usable_rect(int p_screen) const {
int size[2];
godot_js_display_window_size_get(size, size + 1);
return Rect2i(0, 0, size[0], size[1]);
}
-int DisplayServerJavaScript::screen_get_dpi(int p_screen) const {
+int DisplayServerWeb::screen_get_dpi(int p_screen) const {
return godot_js_display_screen_dpi_get();
}
-float DisplayServerJavaScript::screen_get_scale(int p_screen) const {
+float DisplayServerWeb::screen_get_scale(int p_screen) const {
return godot_js_display_pixel_ratio_get();
}
-float DisplayServerJavaScript::screen_get_refresh_rate(int p_screen) const {
- return SCREEN_REFRESH_RATE_FALLBACK; // Javascript doesn't have much of a need for the screen refresh rate, and there's no native way to do so.
+float DisplayServerWeb::screen_get_refresh_rate(int p_screen) const {
+ return SCREEN_REFRESH_RATE_FALLBACK; // Web doesn't have much of a need for the screen refresh rate, and there's no native way to do so.
}
-Vector<DisplayServer::WindowID> DisplayServerJavaScript::get_window_list() const {
+Vector<DisplayServer::WindowID> DisplayServerWeb::get_window_list() const {
Vector<WindowID> ret;
ret.push_back(MAIN_WINDOW_ID);
return ret;
}
-DisplayServerJavaScript::WindowID DisplayServerJavaScript::get_window_at_screen_position(const Point2i &p_position) const {
+DisplayServerWeb::WindowID DisplayServerWeb::get_window_at_screen_position(const Point2i &p_position) const {
return MAIN_WINDOW_ID;
}
-void DisplayServerJavaScript::window_attach_instance_id(ObjectID p_instance, WindowID p_window) {
+void DisplayServerWeb::window_attach_instance_id(ObjectID p_instance, WindowID p_window) {
window_attached_instance_id = p_instance;
}
-ObjectID DisplayServerJavaScript::window_get_attached_instance_id(WindowID p_window) const {
+ObjectID DisplayServerWeb::window_get_attached_instance_id(WindowID p_window) const {
return window_attached_instance_id;
}
-void DisplayServerJavaScript::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) {
+void DisplayServerWeb::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) {
// Not supported.
}
-void DisplayServerJavaScript::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) {
+void DisplayServerWeb::window_set_window_event_callback(const Callable &p_callable, WindowID p_window) {
window_event_callback = p_callable;
}
-void DisplayServerJavaScript::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) {
+void DisplayServerWeb::window_set_input_event_callback(const Callable &p_callable, WindowID p_window) {
input_event_callback = p_callable;
}
-void DisplayServerJavaScript::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) {
+void DisplayServerWeb::window_set_input_text_callback(const Callable &p_callable, WindowID p_window) {
input_text_callback = p_callable;
}
-void DisplayServerJavaScript::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) {
+void DisplayServerWeb::window_set_drop_files_callback(const Callable &p_callable, WindowID p_window) {
drop_files_callback = p_callable;
}
-void DisplayServerJavaScript::window_set_title(const String &p_title, WindowID p_window) {
+void DisplayServerWeb::window_set_title(const String &p_title, WindowID p_window) {
godot_js_display_window_title_set(p_title.utf8().get_data());
}
-int DisplayServerJavaScript::window_get_current_screen(WindowID p_window) const {
+int DisplayServerWeb::window_get_current_screen(WindowID p_window) const {
return 1;
}
-void DisplayServerJavaScript::window_set_current_screen(int p_screen, WindowID p_window) {
+void DisplayServerWeb::window_set_current_screen(int p_screen, WindowID p_window) {
// Not implemented.
}
-Point2i DisplayServerJavaScript::window_get_position(WindowID p_window) const {
+Point2i DisplayServerWeb::window_get_position(WindowID p_window) const {
return Point2i(); // TODO Does this need implementation?
}
-void DisplayServerJavaScript::window_set_position(const Point2i &p_position, WindowID p_window) {
+void DisplayServerWeb::window_set_position(const Point2i &p_position, WindowID p_window) {
// Not supported.
}
-void DisplayServerJavaScript::window_set_transient(WindowID p_window, WindowID p_parent) {
+void DisplayServerWeb::window_set_transient(WindowID p_window, WindowID p_parent) {
// Not supported.
}
-void DisplayServerJavaScript::window_set_max_size(const Size2i p_size, WindowID p_window) {
+void DisplayServerWeb::window_set_max_size(const Size2i p_size, WindowID p_window) {
// Not supported.
}
-Size2i DisplayServerJavaScript::window_get_max_size(WindowID p_window) const {
+Size2i DisplayServerWeb::window_get_max_size(WindowID p_window) const {
return Size2i();
}
-void DisplayServerJavaScript::window_set_min_size(const Size2i p_size, WindowID p_window) {
+void DisplayServerWeb::window_set_min_size(const Size2i p_size, WindowID p_window) {
// Not supported.
}
-Size2i DisplayServerJavaScript::window_get_min_size(WindowID p_window) const {
+Size2i DisplayServerWeb::window_get_min_size(WindowID p_window) const {
return Size2i();
}
-void DisplayServerJavaScript::window_set_size(const Size2i p_size, WindowID p_window) {
+void DisplayServerWeb::window_set_size(const Size2i p_size, WindowID p_window) {
godot_js_display_desired_size_set(p_size.x, p_size.y);
}
-Size2i DisplayServerJavaScript::window_get_size(WindowID p_window) const {
+Size2i DisplayServerWeb::window_get_size(WindowID p_window) const {
int size[2];
godot_js_display_window_size_get(size, size + 1);
return Size2i(size[0], size[1]);
}
-Size2i DisplayServerJavaScript::window_get_real_size(WindowID p_window) const {
+Size2i DisplayServerWeb::window_get_real_size(WindowID p_window) const {
return window_get_size(p_window);
}
-void DisplayServerJavaScript::window_set_mode(WindowMode p_mode, WindowID p_window) {
+void DisplayServerWeb::window_set_mode(WindowMode p_mode, WindowID p_window) {
if (window_mode == p_mode) {
return;
}
@@ -993,65 +993,65 @@ void DisplayServerJavaScript::window_set_mode(WindowMode p_mode, WindowID p_wind
case WINDOW_MODE_EXCLUSIVE_FULLSCREEN:
case WINDOW_MODE_FULLSCREEN: {
int result = godot_js_display_fullscreen_request();
- ERR_FAIL_COND_MSG(result, "The request was denied. Remember that enabling fullscreen is only possible from an input callback for the HTML5 platform.");
+ ERR_FAIL_COND_MSG(result, "The request was denied. Remember that enabling fullscreen is only possible from an input callback for the Web platform.");
} break;
case WINDOW_MODE_MAXIMIZED:
case WINDOW_MODE_MINIMIZED:
- WARN_PRINT("WindowMode MAXIMIZED and MINIMIZED are not supported in HTML5 platform.");
+ WARN_PRINT("WindowMode MAXIMIZED and MINIMIZED are not supported in Web platform.");
break;
default:
break;
}
}
-DisplayServerJavaScript::WindowMode DisplayServerJavaScript::window_get_mode(WindowID p_window) const {
+DisplayServerWeb::WindowMode DisplayServerWeb::window_get_mode(WindowID p_window) const {
return window_mode;
}
-bool DisplayServerJavaScript::window_is_maximize_allowed(WindowID p_window) const {
+bool DisplayServerWeb::window_is_maximize_allowed(WindowID p_window) const {
return false;
}
-void DisplayServerJavaScript::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) {
+void DisplayServerWeb::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) {
// Not supported.
}
-bool DisplayServerJavaScript::window_get_flag(WindowFlags p_flag, WindowID p_window) const {
+bool DisplayServerWeb::window_get_flag(WindowFlags p_flag, WindowID p_window) const {
return false;
}
-void DisplayServerJavaScript::window_request_attention(WindowID p_window) {
+void DisplayServerWeb::window_request_attention(WindowID p_window) {
// Not supported.
}
-void DisplayServerJavaScript::window_move_to_foreground(WindowID p_window) {
+void DisplayServerWeb::window_move_to_foreground(WindowID p_window) {
// Not supported.
}
-bool DisplayServerJavaScript::window_can_draw(WindowID p_window) const {
+bool DisplayServerWeb::window_can_draw(WindowID p_window) const {
return true;
}
-bool DisplayServerJavaScript::can_any_window_draw() const {
+bool DisplayServerWeb::can_any_window_draw() const {
return true;
}
-void DisplayServerJavaScript::process_events() {
+void DisplayServerWeb::process_events() {
Input::get_singleton()->flush_buffered_events();
if (godot_js_input_gamepad_sample() == OK) {
process_joypads();
}
}
-int DisplayServerJavaScript::get_current_video_driver() const {
+int DisplayServerWeb::get_current_video_driver() const {
return 1;
}
-bool DisplayServerJavaScript::get_swap_cancel_ok() {
+bool DisplayServerWeb::get_swap_cancel_ok() {
return swap_cancel_ok;
}
-void DisplayServerJavaScript::swap_buffers() {
+void DisplayServerWeb::swap_buffers() {
#ifdef GLES3_ENABLED
if (webgl_ctx) {
emscripten_webgl_commit_frame();
diff --git a/platform/javascript/display_server_javascript.h b/platform/web/display_server_web.h
index 79b0fbb652..85076b906f 100644
--- a/platform/javascript/display_server_javascript.h
+++ b/platform/web/display_server_web.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* display_server_javascript.h */
+/* display_server_web.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,15 +28,15 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef DISPLAY_SERVER_JAVASCRIPT_H
-#define DISPLAY_SERVER_JAVASCRIPT_H
+#ifndef DISPLAY_SERVER_WEB_H
+#define DISPLAY_SERVER_WEB_H
#include "servers/display_server.h"
#include <emscripten.h>
#include <emscripten/html5.h>
-class DisplayServerJavaScript : public DisplayServer {
+class DisplayServerWeb : public DisplayServer {
private:
struct JSTouchEvent {
uint32_t identifier[32] = { 0 };
@@ -112,7 +112,7 @@ protected:
public:
// Override return type to make writing static callbacks less tedious.
- static DisplayServerJavaScript *get_singleton();
+ static DisplayServerWeb *get_singleton();
// utilities
bool check_size_force_redraw();
@@ -124,7 +124,7 @@ public:
// tts
virtual bool tts_is_speaking() const override;
virtual bool tts_is_paused() const override;
- virtual Array tts_get_voices() const override;
+ virtual TypedArray<Dictionary> tts_get_voices() const override;
virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override;
virtual void tts_pause() override;
@@ -157,7 +157,7 @@ public:
virtual float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
- virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1) override;
+ virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), VirtualKeyboardType p_type = KEYBOARD_TYPE_DEFAULT, int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1) override;
virtual void virtual_keyboard_hide() override;
// windows
@@ -220,9 +220,9 @@ public:
virtual bool get_swap_cancel_ok() override;
virtual void swap_buffers() override;
- static void register_javascript_driver();
- DisplayServerJavaScript(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Size2i &p_resolution, Error &r_error);
- ~DisplayServerJavaScript();
+ static void register_web_driver();
+ DisplayServerWeb(const String &p_rendering_driver, WindowMode p_window_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Size2i &p_resolution, Error &r_error);
+ ~DisplayServerWeb();
};
-#endif // DISPLAY_SERVER_JAVASCRIPT_H
+#endif // DISPLAY_SERVER_WEB_H
diff --git a/platform/javascript/dom_keys.inc b/platform/web/dom_keys.inc
index 115b5479e4..115b5479e4 100644
--- a/platform/javascript/dom_keys.inc
+++ b/platform/web/dom_keys.inc
diff --git a/platform/javascript/emscripten_helpers.py b/platform/web/emscripten_helpers.py
index 3cb1d75e52..b7b1026ef7 100644
--- a/platform/javascript/emscripten_helpers.py
+++ b/platform/web/emscripten_helpers.py
@@ -39,11 +39,11 @@ def create_engine_file(env, target, source, externs):
def create_template_zip(env, js, wasm, extra):
binary_name = "godot.tools" if env["tools"] else "godot"
- zip_dir = env.Dir("#bin/.javascript_zip")
+ zip_dir = env.Dir("#bin/.web_zip")
in_files = [
js,
wasm,
- "#platform/javascript/js/libs/audio.worklet.js",
+ "#platform/web/js/libs/audio.worklet.js",
]
out_files = [
zip_dir.File(binary_name + ".js"),
diff --git a/platform/javascript/export/export_server.h b/platform/web/export/editor_http_server.h
index ddbe3cca30..38b9a66d7e 100644
--- a/platform/javascript/export/export_server.h
+++ b/platform/web/export/editor_http_server.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* export_server.h */
+/* editor_http_server.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef JAVASCRIPT_EXPORT_SERVER_H
-#define JAVASCRIPT_EXPORT_SERVER_H
+#ifndef WEB_EDITOR_HTTP_SERVER_H
+#define WEB_EDITOR_HTTP_SERVER_H
#include "core/io/image_loader.h"
#include "core/io/stream_peer_ssl.h"
@@ -62,8 +62,8 @@ private:
void _set_internal_certs(Ref<Crypto> p_crypto) {
const String cache_path = EditorPaths::get_singleton()->get_cache_dir();
- const String key_path = cache_path.plus_file("html5_server.key");
- const String crt_path = cache_path.plus_file("html5_server.crt");
+ const String key_path = cache_path.path_join("html5_server.key");
+ const String crt_path = cache_path.path_join("html5_server.crt");
bool regen = !FileAccess::exists(key_path) || !FileAccess::exists(crt_path);
if (!regen) {
key = Ref<CryptoKey>(CryptoKey::create());
@@ -139,8 +139,8 @@ public:
const String req_file = path.get_file();
const String req_ext = path.get_extension();
- const String cache_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("web");
- const String filepath = cache_path.plus_file(req_file);
+ const String cache_path = EditorPaths::get_singleton()->get_cache_dir().path_join("web");
+ const String filepath = cache_path.path_join(req_file);
if (!mimes.has(req_ext) || !FileAccess::exists(filepath)) {
String s = "HTTP/1.1 404 Not Found\r\n";
@@ -247,4 +247,4 @@ public:
}
};
-#endif // JAVASCRIPT_EXPORT_SERVER_H
+#endif // WEB_EDITOR_HTTP_SERVER_H
diff --git a/platform/javascript/export/export.cpp b/platform/web/export/export.cpp
index ea236f62f7..3d40f2c10d 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/web/export/export.cpp
@@ -33,7 +33,7 @@
#include "editor/editor_settings.h"
#include "export_plugin.h"
-void register_javascript_exporter() {
+void register_web_exporter() {
EDITOR_DEF("export/web/http_host", "localhost");
EDITOR_DEF("export/web/http_port", 8060);
EDITOR_DEF("export/web/use_ssl", false);
@@ -43,7 +43,7 @@ void register_javascript_exporter() {
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/web/ssl_key", PROPERTY_HINT_GLOBAL_FILE, "*.key"));
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/web/ssl_certificate", PROPERTY_HINT_GLOBAL_FILE, "*.crt,*.pem"));
- Ref<EditorExportPlatformJavaScript> platform;
+ Ref<EditorExportPlatformWeb> platform;
platform.instantiate();
EditorExport::get_singleton()->add_export_platform(platform);
}
diff --git a/platform/javascript/export/export.h b/platform/web/export/export.h
index 29c335ed0e..7947f292a4 100644
--- a/platform/javascript/export/export.h
+++ b/platform/web/export/export.h
@@ -28,9 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef JAVASCRIPT_EXPORT_H
-#define JAVASCRIPT_EXPORT_H
+#ifndef WEB_EXPORT_H
+#define WEB_EXPORT_H
-void register_javascript_exporter();
+void register_web_exporter();
-#endif // JAVASCRIPT_EXPORT_H
+#endif // WEB_EXPORT_H
diff --git a/platform/javascript/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp
index b99f88d067..2cd8ec88ef 100644
--- a/platform/javascript/export/export_plugin.cpp
+++ b/platform/web/export/export_plugin.cpp
@@ -33,7 +33,7 @@
#include "core/config/project_settings.h"
#include "editor/editor_settings.h"
-Error EditorExportPlatformJavaScript::_extract_template(const String &p_template, const String &p_dir, const String &p_name, bool pwa) {
+Error EditorExportPlatformWeb::_extract_template(const String &p_template, const String &p_dir, const String &p_name, bool pwa) {
Ref<FileAccess> io_fa;
zlib_filefunc_def io = zipio_create_io(&io_fa);
unzFile pkg = unzOpen2(p_template.utf8().get_data(), &io);
@@ -75,7 +75,7 @@ Error EditorExportPlatformJavaScript::_extract_template(const String &p_template
unzCloseCurrentFile(pkg);
//write
- String dst = p_dir.plus_file(file.replace("godot", p_name));
+ String dst = p_dir.path_join(file.replace("godot", p_name));
Ref<FileAccess> f = FileAccess::open(dst, FileAccess::WRITE);
if (f.is_null()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Prepare Templates"), vformat(TTR("Could not write file: \"%s\"."), dst));
@@ -89,7 +89,7 @@ Error EditorExportPlatformJavaScript::_extract_template(const String &p_template
return OK;
}
-Error EditorExportPlatformJavaScript::_write_or_error(const uint8_t *p_content, int p_size, String p_path) {
+Error EditorExportPlatformWeb::_write_or_error(const uint8_t *p_content, int p_size, String p_path) {
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
if (f.is_null()) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not write file: \"%s\"."), p_path));
@@ -99,7 +99,7 @@ Error EditorExportPlatformJavaScript::_write_or_error(const uint8_t *p_content,
return OK;
}
-void EditorExportPlatformJavaScript::_replace_strings(HashMap<String, String> p_replaces, Vector<uint8_t> &r_template) {
+void EditorExportPlatformWeb::_replace_strings(HashMap<String, String> p_replaces, Vector<uint8_t> &r_template) {
String str_template = String::utf8(reinterpret_cast<const char *>(r_template.ptr()), r_template.size());
String out;
Vector<String> lines = str_template.split("\n");
@@ -117,7 +117,7 @@ void EditorExportPlatformJavaScript::_replace_strings(HashMap<String, String> p_
}
}
-void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects, const Dictionary &p_file_sizes) {
+void EditorExportPlatformWeb::_fix_html(Vector<uint8_t> &p_html, const Ref<EditorExportPreset> &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector<SharedObject> p_shared_objects, const Dictionary &p_file_sizes) {
// Engine.js config
Dictionary config;
Array libs;
@@ -159,10 +159,10 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Re
_replace_strings(replaces, p_html);
}
-Error EditorExportPlatformJavaScript::_add_manifest_icon(const String &p_path, const String &p_icon, int p_size, Array &r_arr) {
+Error EditorExportPlatformWeb::_add_manifest_icon(const String &p_path, const String &p_icon, int p_size, Array &r_arr) {
const String name = p_path.get_file().get_basename();
const String icon_name = vformat("%s.%dx%d.png", name, p_size, p_size);
- const String icon_dest = p_path.get_base_dir().plus_file(icon_name);
+ const String icon_dest = p_path.get_base_dir().path_join(icon_name);
Ref<Image> icon;
if (!p_icon.is_empty()) {
@@ -192,7 +192,7 @@ Error EditorExportPlatformJavaScript::_add_manifest_icon(const String &p_path, c
return err;
}
-Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &p_preset, const String p_path, const Vector<SharedObject> &p_shared_objects) {
+Error EditorExportPlatformWeb::_build_pwa(const Ref<EditorExportPreset> &p_preset, const String p_path, const Vector<SharedObject> &p_shared_objects) {
String proj_name = ProjectSettings::get_singleton()->get_setting("application/config/name");
if (proj_name.is_empty()) {
proj_name = "Godot Game";
@@ -234,7 +234,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &
}
replaces["@GODOT_OPT_CACHE@"] = Variant(opt_cache_files).to_json_string();
- const String sw_path = dir.plus_file(name + ".service.worker.js");
+ const String sw_path = dir.path_join(name + ".service.worker.js");
Vector<uint8_t> sw;
{
Ref<FileAccess> f = FileAccess::open(sw_path, FileAccess::READ);
@@ -246,7 +246,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &
f->get_buffer(sw.ptrw(), sw.size());
}
_replace_strings(replaces, sw);
- Error err = _write_or_error(sw.ptr(), sw.size(), dir.plus_file(name + ".service.worker.js"));
+ Error err = _write_or_error(sw.ptr(), sw.size(), dir.path_join(name + ".service.worker.js"));
if (err != OK) {
return err;
}
@@ -255,7 +255,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &
const String offline_page = p_preset->get("progressive_web_app/offline_page");
if (!offline_page.is_empty()) {
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- const String offline_dest = dir.plus_file(name + ".offline.html");
+ const String offline_dest = dir.path_join(name + ".offline.html");
err = da->copy(ProjectSettings::get_singleton()->globalize_path(offline_page), offline_dest);
if (err != OK) {
add_message(EXPORT_MESSAGE_ERROR, TTR("PWA"), vformat(TTR("Could not read file: \"%s\"."), offline_dest));
@@ -295,7 +295,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &
manifest["icons"] = icons_arr;
CharString cs = Variant(manifest).to_json_string().utf8();
- err = _write_or_error((const uint8_t *)cs.get_data(), cs.length(), dir.plus_file(name + ".manifest.json"));
+ err = _write_or_error((const uint8_t *)cs.get_data(), cs.length(), dir.path_join(name + ".manifest.json"));
if (err != OK) {
return err;
}
@@ -303,7 +303,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> &
return OK;
}
-void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const {
+void EditorExportPlatformWeb::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const {
if (p_preset->get("vram_texture_compression/for_desktop")) {
r_features->push_back("s3tc");
}
@@ -326,7 +326,7 @@ void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportP
}
}
-void EditorExportPlatformJavaScript::get_export_options(List<ExportOption> *r_options) {
+void EditorExportPlatformWeb::get_export_options(List<ExportOption> *r_options) {
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
@@ -350,25 +350,25 @@ void EditorExportPlatformJavaScript::get_export_options(List<ExportOption> *r_op
r_options->push_back(ExportOption(PropertyInfo(Variant::COLOR, "progressive_web_app/background_color", PROPERTY_HINT_COLOR_NO_ALPHA), Color()));
}
-String EditorExportPlatformJavaScript::get_name() const {
- return "HTML5";
+String EditorExportPlatformWeb::get_name() const {
+ return "Web";
}
-String EditorExportPlatformJavaScript::get_os_name() const {
- return "HTML5";
+String EditorExportPlatformWeb::get_os_name() const {
+ return "Web";
}
-Ref<Texture2D> EditorExportPlatformJavaScript::get_logo() const {
+Ref<Texture2D> EditorExportPlatformWeb::get_logo() const {
return logo;
}
-bool EditorExportPlatformJavaScript::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+bool EditorExportPlatformWeb::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
#ifndef DEV_ENABLED
- // We don't provide export templates for the HTML5 platform currently as there
+ // We don't provide export templates for the Web platform currently as there
// is no suitable renderer to use with them. So we forbid exporting and tell
// users why. This is skipped in DEV_ENABLED so that contributors can still test
// the pipeline once we start having WebGL or WebGPU support.
- r_error = "The HTML5 platform is currently not supported in Godot 4.0, as there is no suitable renderer for it.\n";
+ r_error = "The Web platform is currently not supported in Godot 4.0, as there is no suitable renderer for it.\n";
return false;
#endif
@@ -396,7 +396,27 @@ bool EditorExportPlatformJavaScript::can_export(const Ref<EditorExportPreset> &p
valid = dvalid || rvalid;
r_missing_templates = !valid;
- // Validate the rest of the configuration.
+ if (!err.is_empty()) {
+ r_error = err;
+ }
+
+ return valid;
+}
+
+bool EditorExportPlatformWeb::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const {
+#ifndef DEV_ENABLED
+ // We don't provide export templates for the Web platform currently as there
+ // is no suitable renderer to use with them. So we forbid exporting and tell
+ // users why. This is skipped in DEV_ENABLED so that contributors can still test
+ // the pipeline once we start having WebGL or WebGPU support.
+ r_error = "The Web platform is currently not supported in Godot 4.0, as there is no suitable renderer for it.\n";
+ return false;
+#endif
+
+ String err;
+ bool valid = true;
+
+ // Validate the project configuration.
if (p_preset->get("vram_texture_compression/for_mobile")) {
String etc_error = test_etc2();
@@ -413,13 +433,13 @@ bool EditorExportPlatformJavaScript::can_export(const Ref<EditorExportPreset> &p
return valid;
}
-List<String> EditorExportPlatformJavaScript::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
+List<String> EditorExportPlatformWeb::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
List<String> list;
list.push_back("html");
return list;
}
-Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
+Error EditorExportPlatformWeb::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
const String custom_debug = p_preset->get("custom_template/debug");
@@ -461,7 +481,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
{
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
for (int i = 0; i < shared_objects.size(); i++) {
- String dst = base_dir.plus_file(shared_objects[i].path.get_file());
+ String dst = base_dir.path_join(shared_objects[i].path.get_file());
error = da->copy(shared_objects[i].path, dst);
if (error != OK) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Could not write file: \"%s\"."), shared_objects[i].path.get_file()));
@@ -542,7 +562,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
return OK;
}
-bool EditorExportPlatformJavaScript::poll_export() {
+bool EditorExportPlatformWeb::poll_export() {
Ref<EditorExportPreset> preset;
for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
@@ -566,22 +586,22 @@ bool EditorExportPlatformJavaScript::poll_export() {
return menu_options != prev;
}
-Ref<ImageTexture> EditorExportPlatformJavaScript::get_option_icon(int p_index) const {
+Ref<ImageTexture> EditorExportPlatformWeb::get_option_icon(int p_index) const {
return p_index == 1 ? stop_icon : EditorExportPlatform::get_option_icon(p_index);
}
-int EditorExportPlatformJavaScript::get_options_count() const {
+int EditorExportPlatformWeb::get_options_count() const {
return menu_options;
}
-Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_preset, int p_option, int p_debug_flags) {
+Error EditorExportPlatformWeb::run(const Ref<EditorExportPreset> &p_preset, int p_option, int p_debug_flags) {
if (p_option == 1) {
MutexLock lock(server_lock);
server->stop();
return OK;
}
- const String dest = EditorPaths::get_singleton()->get_cache_dir().plus_file("web");
+ const String dest = EditorPaths::get_singleton()->get_cache_dir().path_join("web");
Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (!da->dir_exists(dest)) {
Error err = da->make_dir_recursive(dest);
@@ -591,7 +611,7 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese
}
}
- const String basepath = dest.plus_file("tmp_js_export");
+ const String basepath = dest.path_join("tmp_js_export");
Error err = export_project(p_preset, true, basepath + ".html", p_debug_flags);
if (err != OK) {
// Export generates several files, clean them up on failure.
@@ -643,12 +663,12 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese
return OK;
}
-Ref<Texture2D> EditorExportPlatformJavaScript::get_run_icon() const {
+Ref<Texture2D> EditorExportPlatformWeb::get_run_icon() const {
return run_icon;
}
-void EditorExportPlatformJavaScript::_server_thread_poll(void *data) {
- EditorExportPlatformJavaScript *ej = static_cast<EditorExportPlatformJavaScript *>(data);
+void EditorExportPlatformWeb::_server_thread_poll(void *data) {
+ EditorExportPlatformWeb *ej = static_cast<EditorExportPlatformWeb *>(data);
while (!ej->server_quit) {
OS::get_singleton()->delay_usec(6900);
{
@@ -658,12 +678,12 @@ void EditorExportPlatformJavaScript::_server_thread_poll(void *data) {
}
}
-EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() {
+EditorExportPlatformWeb::EditorExportPlatformWeb() {
server.instantiate();
server_thread.start(_server_thread_poll, this);
- logo = ImageTexture::create_from_image(memnew(Image(_javascript_logo)));
- run_icon = ImageTexture::create_from_image(memnew(Image(_javascript_run_icon)));
+ logo = ImageTexture::create_from_image(memnew(Image(_web_logo)));
+ run_icon = ImageTexture::create_from_image(memnew(Image(_web_run_icon)));
Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme();
if (theme.is_valid()) {
@@ -673,7 +693,7 @@ EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() {
}
}
-EditorExportPlatformJavaScript::~EditorExportPlatformJavaScript() {
+EditorExportPlatformWeb::~EditorExportPlatformWeb() {
server->stop();
server_quit = true;
server_thread.wait_to_finish();
diff --git a/platform/javascript/export/export_plugin.h b/platform/web/export/export_plugin.h
index fbaa3615cb..9c1bf2a5ef 100644
--- a/platform/javascript/export/export_plugin.h
+++ b/platform/web/export/export_plugin.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef JAVASCRIPT_EXPORT_PLUGIN_H
-#define JAVASCRIPT_EXPORT_PLUGIN_H
+#ifndef WEB_EXPORT_PLUGIN_H
+#define WEB_EXPORT_PLUGIN_H
#include "core/config/project_settings.h"
#include "core/io/image_loader.h"
@@ -39,13 +39,13 @@
#include "editor/editor_node.h"
#include "editor/export/editor_export_platform.h"
#include "main/splash.gen.h"
-#include "platform/javascript/logo.gen.h"
-#include "platform/javascript/run_icon.gen.h"
+#include "platform/web/logo.gen.h"
+#include "platform/web/run_icon.gen.h"
-#include "export_server.h"
+#include "editor_http_server.h"
-class EditorExportPlatformJavaScript : public EditorExportPlatform {
- GDCLASS(EditorExportPlatformJavaScript, EditorExportPlatform);
+class EditorExportPlatformWeb : public EditorExportPlatform {
+ GDCLASS(EditorExportPlatformWeb, EditorExportPlatform);
Ref<ImageTexture> logo;
Ref<ImageTexture> run_icon;
@@ -118,7 +118,8 @@ public:
virtual String get_os_name() const override;
virtual Ref<Texture2D> get_logo() const override;
- virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
@@ -140,8 +141,8 @@ public:
String get_debug_protocol() const override { return "ws://"; }
- EditorExportPlatformJavaScript();
- ~EditorExportPlatformJavaScript();
+ EditorExportPlatformWeb();
+ ~EditorExportPlatformWeb();
};
-#endif // JAVASCRIPT_EXPORT_PLUGIN_H
+#endif // WEB_EXPORT_PLUGIN_H
diff --git a/platform/javascript/godot_audio.h b/platform/web/godot_audio.h
index 3855b7301e..3855b7301e 100644
--- a/platform/javascript/godot_audio.h
+++ b/platform/web/godot_audio.h
diff --git a/platform/javascript/godot_js.h b/platform/web/godot_js.h
index 1dce8035a6..a323f2d157 100644
--- a/platform/javascript/godot_js.h
+++ b/platform/web/godot_js.h
@@ -121,7 +121,7 @@ extern void godot_js_display_notification_cb(void (*p_callback)(int p_notificati
extern int godot_js_display_vk_available();
extern int godot_js_display_tts_available();
extern void godot_js_display_vk_cb(void (*p_input)(const char *p_text, int p_cursor));
-extern void godot_js_display_vk_show(const char *p_text, int p_multiline, int p_start, int p_end);
+extern void godot_js_display_vk_show(const char *p_text, int p_type, int p_start, int p_end);
extern void godot_js_display_vk_hide();
#ifdef __cplusplus
diff --git a/platform/javascript/godot_webgl2.h b/platform/web/godot_webgl2.h
index 968b70f84b..968b70f84b 100644
--- a/platform/javascript/godot_webgl2.h
+++ b/platform/web/godot_webgl2.h
diff --git a/platform/javascript/http_client_javascript.cpp b/platform/web/http_client_web.cpp
index 32bdfed4c7..bfdea95f4a 100644
--- a/platform/javascript/http_client_javascript.cpp
+++ b/platform/web/http_client_web.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* http_client_javascript.cpp */
+/* http_client_web.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,19 +28,19 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "http_client_javascript.h"
+#include "http_client_web.h"
-void HTTPClientJavaScript::_parse_headers(int p_len, const char **p_headers, void *p_ref) {
- HTTPClientJavaScript *client = static_cast<HTTPClientJavaScript *>(p_ref);
+void HTTPClientWeb::_parse_headers(int p_len, const char **p_headers, void *p_ref) {
+ HTTPClientWeb *client = static_cast<HTTPClientWeb *>(p_ref);
for (int i = 0; i < p_len; i++) {
client->response_headers.push_back(String::utf8(p_headers[i]));
}
}
-Error HTTPClientJavaScript::connect_to_host(const String &p_host, int p_port, bool p_ssl, bool p_verify_host) {
+Error HTTPClientWeb::connect_to_host(const String &p_host, int p_port, bool p_ssl, bool p_verify_host) {
close();
if (p_ssl && !p_verify_host) {
- WARN_PRINT("Disabling HTTPClientJavaScript's host verification is not supported for the HTML5 platform, host will be verified");
+ WARN_PRINT("Disabling HTTPClientWeb's host verification is not supported for the Web platform, host will be verified");
}
port = p_port;
@@ -71,17 +71,17 @@ Error HTTPClientJavaScript::connect_to_host(const String &p_host, int p_port, bo
return OK;
}
-void HTTPClientJavaScript::set_connection(const Ref<StreamPeer> &p_connection) {
- ERR_FAIL_MSG("Accessing an HTTPClientJavaScript's StreamPeer is not supported for the HTML5 platform.");
+void HTTPClientWeb::set_connection(const Ref<StreamPeer> &p_connection) {
+ ERR_FAIL_MSG("Accessing an HTTPClientWeb's StreamPeer is not supported for the Web platform.");
}
-Ref<StreamPeer> HTTPClientJavaScript::get_connection() const {
- ERR_FAIL_V_MSG(Ref<RefCounted>(), "Accessing an HTTPClientJavaScript's StreamPeer is not supported for the HTML5 platform.");
+Ref<StreamPeer> HTTPClientWeb::get_connection() const {
+ ERR_FAIL_V_MSG(Ref<RefCounted>(), "Accessing an HTTPClientWeb's StreamPeer is not supported for the Web platform.");
}
-Error HTTPClientJavaScript::request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_len) {
+Error HTTPClientWeb::request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_len) {
ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V_MSG(p_method == METHOD_TRACE || p_method == METHOD_CONNECT, ERR_UNAVAILABLE, "HTTP methods TRACE and CONNECT are not supported for the HTML5 platform.");
+ ERR_FAIL_COND_V_MSG(p_method == METHOD_TRACE || p_method == METHOD_CONNECT, ERR_UNAVAILABLE, "HTTP methods TRACE and CONNECT are not supported for the Web platform.");
ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(host.is_empty(), ERR_UNCONFIGURED);
ERR_FAIL_COND_V(port < 0, ERR_UNCONFIGURED);
@@ -107,7 +107,7 @@ Error HTTPClientJavaScript::request(Method p_method, const String &p_url, const
return OK;
}
-void HTTPClientJavaScript::close() {
+void HTTPClientWeb::close() {
host = "";
port = -1;
use_tls = false;
@@ -121,23 +121,23 @@ void HTTPClientJavaScript::close() {
}
}
-HTTPClientJavaScript::Status HTTPClientJavaScript::get_status() const {
+HTTPClientWeb::Status HTTPClientWeb::get_status() const {
return status;
}
-bool HTTPClientJavaScript::has_response() const {
+bool HTTPClientWeb::has_response() const {
return response_headers.size() > 0;
}
-bool HTTPClientJavaScript::is_response_chunked() const {
+bool HTTPClientWeb::is_response_chunked() const {
return godot_js_fetch_is_chunked(js_id);
}
-int HTTPClientJavaScript::get_response_code() const {
+int HTTPClientWeb::get_response_code() const {
return polled_response_code;
}
-Error HTTPClientJavaScript::get_response_headers(List<String> *r_response) {
+Error HTTPClientWeb::get_response_headers(List<String> *r_response) {
if (!response_headers.size()) {
return ERR_INVALID_PARAMETER;
}
@@ -148,11 +148,11 @@ Error HTTPClientJavaScript::get_response_headers(List<String> *r_response) {
return OK;
}
-int64_t HTTPClientJavaScript::get_response_body_length() const {
+int64_t HTTPClientWeb::get_response_body_length() const {
return godot_js_fetch_body_length_get(js_id);
}
-PackedByteArray HTTPClientJavaScript::read_response_body_chunk() {
+PackedByteArray HTTPClientWeb::read_response_body_chunk() {
ERR_FAIL_COND_V(status != STATUS_BODY, PackedByteArray());
if (response_buffer.size() != read_limit) {
@@ -177,23 +177,23 @@ PackedByteArray HTTPClientJavaScript::read_response_body_chunk() {
return chunk;
}
-void HTTPClientJavaScript::set_blocking_mode(bool p_enable) {
- ERR_FAIL_COND_MSG(p_enable, "HTTPClientJavaScript blocking mode is not supported for the HTML5 platform.");
+void HTTPClientWeb::set_blocking_mode(bool p_enable) {
+ ERR_FAIL_COND_MSG(p_enable, "HTTPClientWeb blocking mode is not supported for the Web platform.");
}
-bool HTTPClientJavaScript::is_blocking_mode_enabled() const {
+bool HTTPClientWeb::is_blocking_mode_enabled() const {
return false;
}
-void HTTPClientJavaScript::set_read_chunk_size(int p_size) {
+void HTTPClientWeb::set_read_chunk_size(int p_size) {
read_limit = p_size;
}
-int HTTPClientJavaScript::get_read_chunk_size() const {
+int HTTPClientWeb::get_read_chunk_size() const {
return read_limit;
}
-Error HTTPClientJavaScript::poll() {
+Error HTTPClientWeb::poll() {
switch (status) {
case STATUS_DISCONNECTED:
return ERR_UNCONFIGURED;
@@ -227,9 +227,9 @@ Error HTTPClientJavaScript::poll() {
#ifdef DEBUG_ENABLED
// forcing synchronous requests is not possible on the web
if (last_polling_frame == Engine::get_singleton()->get_process_frames()) {
- WARN_PRINT("HTTPClientJavaScript polled multiple times in one frame, "
+ WARN_PRINT("HTTPClientWeb polled multiple times in one frame, "
"but request cannot progress more than once per "
- "frame on the HTML5 platform.");
+ "frame on the Web platform.");
}
last_polling_frame = Engine::get_singleton()->get_process_frames();
#endif
@@ -258,15 +258,15 @@ Error HTTPClientJavaScript::poll() {
return OK;
}
-HTTPClient *HTTPClientJavaScript::_create_func() {
- return memnew(HTTPClientJavaScript);
+HTTPClient *HTTPClientWeb::_create_func() {
+ return memnew(HTTPClientWeb);
}
-HTTPClient *(*HTTPClient::_create)() = HTTPClientJavaScript::_create_func;
+HTTPClient *(*HTTPClient::_create)() = HTTPClientWeb::_create_func;
-HTTPClientJavaScript::HTTPClientJavaScript() {
+HTTPClientWeb::HTTPClientWeb() {
}
-HTTPClientJavaScript::~HTTPClientJavaScript() {
+HTTPClientWeb::~HTTPClientWeb() {
close();
}
diff --git a/platform/javascript/http_client_javascript.h b/platform/web/http_client_web.h
index fcd225ffc9..ff776d72af 100644
--- a/platform/javascript/http_client_javascript.h
+++ b/platform/web/http_client_web.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* http_client_javascript.h */
+/* http_client_web.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef HTTP_CLIENT_JAVASCRIPT_H
-#define HTTP_CLIENT_JAVASCRIPT_H
+#ifndef HTTP_CLIENT_WEB_H
+#define HTTP_CLIENT_WEB_H
#include "core/io/http_client.h"
@@ -59,7 +59,7 @@ extern int godot_js_fetch_is_chunked(int p_id);
}
#endif
-class HTTPClientJavaScript : public HTTPClient {
+class HTTPClientWeb : public HTTPClient {
private:
int js_id = 0;
Status status = STATUS_DISCONNECTED;
@@ -102,8 +102,8 @@ public:
void set_read_chunk_size(int p_size) override;
int get_read_chunk_size() const override;
Error poll() override;
- HTTPClientJavaScript();
- ~HTTPClientJavaScript();
+ HTTPClientWeb();
+ ~HTTPClientWeb();
};
-#endif // HTTP_CLIENT_JAVASCRIPT_H
+#endif // HTTP_CLIENT_WEB_H
diff --git a/platform/javascript/javascript_singleton.cpp b/platform/web/javascript_singleton.cpp
index 204e92b82b..36ab4db452 100644
--- a/platform/javascript/javascript_singleton.cpp
+++ b/platform/web/javascript_singleton.cpp
@@ -31,7 +31,7 @@
#include "api/javascript_singleton.h"
#include "emscripten.h"
-#include "os_javascript.h"
+#include "os_web.h"
extern "C" {
extern void godot_js_os_download_buffer(const uint8_t *p_buf, int p_buf_size, const char *p_name, const char *p_mime);
@@ -359,8 +359,8 @@ void JavaScript::download_buffer(Vector<uint8_t> p_arr, const String &p_name, co
}
bool JavaScript::pwa_needs_update() const {
- return OS_JavaScript::get_singleton()->pwa_needs_update();
+ return OS_Web::get_singleton()->pwa_needs_update();
}
Error JavaScript::pwa_update() {
- return OS_JavaScript::get_singleton()->pwa_update();
+ return OS_Web::get_singleton()->pwa_update();
}
diff --git a/platform/javascript/js/engine/config.js b/platform/web/js/engine/config.js
index 9c4b6c2012..9c4b6c2012 100644
--- a/platform/javascript/js/engine/config.js
+++ b/platform/web/js/engine/config.js
diff --git a/platform/javascript/js/engine/engine.externs.js b/platform/web/js/engine/engine.externs.js
index 35a66a93ae..35a66a93ae 100644
--- a/platform/javascript/js/engine/engine.externs.js
+++ b/platform/web/js/engine/engine.externs.js
diff --git a/platform/javascript/js/engine/engine.js b/platform/web/js/engine/engine.js
index d2ba595083..6f0d51b2be 100644
--- a/platform/javascript/js/engine/engine.js
+++ b/platform/web/js/engine/engine.js
@@ -6,7 +6,7 @@
* of `Promises <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises>`__.
*
* @module Engine
- * @header HTML5 shell class reference
+ * @header Web export JavaScript reference
*/
const Engine = (function () {
const preloader = new Preloader();
diff --git a/platform/javascript/js/engine/preloader.js b/platform/web/js/engine/preloader.js
index 564c68d264..564c68d264 100644
--- a/platform/javascript/js/engine/preloader.js
+++ b/platform/web/js/engine/preloader.js
diff --git a/platform/javascript/js/jsdoc2rst/publish.js b/platform/web/js/jsdoc2rst/publish.js
index ad9c0fbaaa..ad9c0fbaaa 100644
--- a/platform/javascript/js/jsdoc2rst/publish.js
+++ b/platform/web/js/jsdoc2rst/publish.js
diff --git a/platform/javascript/js/libs/audio.worklet.js b/platform/web/js/libs/audio.worklet.js
index ea4d8cb221..ea4d8cb221 100644
--- a/platform/javascript/js/libs/audio.worklet.js
+++ b/platform/web/js/libs/audio.worklet.js
diff --git a/platform/javascript/js/libs/library_godot_audio.js b/platform/web/js/libs/library_godot_audio.js
index 756c1ac595..756c1ac595 100644
--- a/platform/javascript/js/libs/library_godot_audio.js
+++ b/platform/web/js/libs/library_godot_audio.js
diff --git a/platform/javascript/js/libs/library_godot_display.js b/platform/web/js/libs/library_godot_display.js
index 5997631bf8..91cb8e728a 100644
--- a/platform/javascript/js/libs/library_godot_display.js
+++ b/platform/web/js/libs/library_godot_display.js
@@ -73,7 +73,7 @@ const GodotDisplayVK = {
GodotDisplayVK.textarea = create('textarea');
GodotDisplayVK.updateSize();
},
- show: function (text, multiline, start, end) {
+ show: function (text, type, start, end) {
if (!GodotDisplayVK.textinput || !GodotDisplayVK.textarea) {
return;
}
@@ -81,7 +81,46 @@ const GodotDisplayVK = {
GodotDisplayVK.hide();
}
GodotDisplayVK.updateSize();
- const elem = multiline ? GodotDisplayVK.textarea : GodotDisplayVK.textinput;
+
+ let elem = GodotDisplayVK.textinput;
+ switch (type) {
+ case 0: // KEYBOARD_TYPE_DEFAULT
+ elem.type = 'text';
+ elem.inputmode = '';
+ break;
+ case 1: // KEYBOARD_TYPE_MULTILINE
+ elem = GodotDisplayVK.textarea;
+ break;
+ case 2: // KEYBOARD_TYPE_NUMBER
+ elem.type = 'text';
+ elem.inputmode = 'numeric';
+ break;
+ case 3: // KEYBOARD_TYPE_NUMBER_DECIMAL
+ elem.type = 'text';
+ elem.inputmode = 'decimal';
+ break;
+ case 4: // KEYBOARD_TYPE_PHONE
+ elem.type = 'tel';
+ elem.inputmode = '';
+ break;
+ case 5: // KEYBOARD_TYPE_EMAIL_ADDRESS
+ elem.type = 'email';
+ elem.inputmode = '';
+ break;
+ case 6: // KEYBOARD_TYPE_PASSWORD
+ elem.type = 'password';
+ elem.inputmode = '';
+ break;
+ case 7: // KEYBOARD_TYPE_URL
+ elem.type = 'url';
+ elem.inputmode = '';
+ break;
+ default:
+ elem.type = 'text';
+ elem.inputmode = '';
+ break;
+ }
+
elem.readonly = false;
elem.disabled = false;
elem.value = text;
@@ -297,26 +336,12 @@ const GodotDisplay = {
$GodotDisplay__deps: ['$GodotConfig', '$GodotRuntime', '$GodotDisplayCursor', '$GodotEventListeners', '$GodotDisplayScreen', '$GodotDisplayVK'],
$GodotDisplay: {
window_icon: '',
- findDPI: function () {
- function testDPI(dpi) {
- return window.matchMedia(`(max-resolution: ${dpi}dpi)`).matches;
- }
- function bisect(low, high, func) {
- const mid = parseInt(((high - low) / 2) + low, 10);
- if (high - low <= 1) {
- return func(high) ? high : low;
- }
- if (func(mid)) {
- return bisect(low, mid, func);
- }
- return bisect(mid, high, func);
- }
- try {
- const dpi = bisect(0, 800, testDPI);
- return dpi >= 96 ? dpi : 96;
- } catch (e) {
- return 96;
- }
+ getDPI: function () {
+ // devicePixelRatio is given in dppx
+ // https://drafts.csswg.org/css-values/#resolution
+ // > due to the 1:96 fixed ratio of CSS *in* to CSS *px*, 1dppx is equivalent to 96dpi.
+ const dpi = Math.round(window.devicePixelRatio * 96);
+ return dpi >= 96 ? dpi : 96;
},
},
@@ -422,7 +447,7 @@ const GodotDisplay = {
godot_js_display_screen_dpi_get__sig: 'i',
godot_js_display_screen_dpi_get: function () {
- return GodotDisplay.findDPI();
+ return GodotDisplay.getDPI();
},
godot_js_display_pixel_ratio_get__sig: 'f',
@@ -511,7 +536,7 @@ const GodotDisplay = {
}
navigator.clipboard.writeText(text).catch(function (e) {
// Setting OS clipboard is only possible from an input callback.
- GodotRuntime.error('Setting OS clipboard is only possible from an input callback for the HTML5 plafrom. Exception:', e);
+ GodotRuntime.error('Setting OS clipboard is only possible from an input callback for the Web plafrom. Exception:', e);
});
return 0;
},
@@ -694,11 +719,11 @@ const GodotDisplay = {
* Virtual Keyboard
*/
godot_js_display_vk_show__sig: 'viiii',
- godot_js_display_vk_show: function (p_text, p_multiline, p_start, p_end) {
+ godot_js_display_vk_show: function (p_text, p_type, p_start, p_end) {
const text = GodotRuntime.parseString(p_text);
const start = p_start > 0 ? p_start : 0;
const end = p_end > 0 ? p_end : start;
- GodotDisplayVK.show(text, p_multiline, start, end);
+ GodotDisplayVK.show(text, p_type, start, end);
},
godot_js_display_vk_hide__sig: 'v',
diff --git a/platform/javascript/js/libs/library_godot_fetch.js b/platform/web/js/libs/library_godot_fetch.js
index 285e50a035..285e50a035 100644
--- a/platform/javascript/js/libs/library_godot_fetch.js
+++ b/platform/web/js/libs/library_godot_fetch.js
diff --git a/platform/javascript/js/libs/library_godot_input.js b/platform/web/js/libs/library_godot_input.js
index 51571d64a2..51571d64a2 100644
--- a/platform/javascript/js/libs/library_godot_input.js
+++ b/platform/web/js/libs/library_godot_input.js
diff --git a/platform/javascript/js/libs/library_godot_javascript_singleton.js b/platform/web/js/libs/library_godot_javascript_singleton.js
index 692f27676a..692f27676a 100644
--- a/platform/javascript/js/libs/library_godot_javascript_singleton.js
+++ b/platform/web/js/libs/library_godot_javascript_singleton.js
diff --git a/platform/javascript/js/libs/library_godot_os.js b/platform/web/js/libs/library_godot_os.js
index 377eec3234..377eec3234 100644
--- a/platform/javascript/js/libs/library_godot_os.js
+++ b/platform/web/js/libs/library_godot_os.js
diff --git a/platform/javascript/js/libs/library_godot_runtime.js b/platform/web/js/libs/library_godot_runtime.js
index e2f7c8dca6..e2f7c8dca6 100644
--- a/platform/javascript/js/libs/library_godot_runtime.js
+++ b/platform/web/js/libs/library_godot_runtime.js
diff --git a/platform/javascript/logo.png b/platform/web/logo.png
index c046d87dc4..c046d87dc4 100644
--- a/platform/javascript/logo.png
+++ b/platform/web/logo.png
Binary files differ
diff --git a/platform/javascript/os_javascript.cpp b/platform/web/os_web.cpp
index dc81b8b4b6..461dc71119 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/web/os_web.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* os_javascript.cpp */
+/* os_web.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "os_javascript.h"
+#include "os_web.h"
#include "core/debugger/engine_debugger.h"
#include "drivers/unix/dir_access_unix.h"
#include "drivers/unix/file_access_unix.h"
#include "main/main.h"
-#include "platform/javascript/display_server_javascript.h"
+#include "platform/web/display_server_web.h"
#include "modules/modules_enabled.gen.h" // For websocket.
#ifdef MODULE_WEBSOCKET_ENABLED
@@ -48,14 +48,14 @@
#include "api/javascript_singleton.h"
#include "godot_js.h"
-void OS_JavaScript::alert(const String &p_alert, const String &p_title) {
+void OS_Web::alert(const String &p_alert, const String &p_title) {
godot_js_display_alert(p_alert.utf8().get_data());
}
// Lifecycle
-void OS_JavaScript::initialize() {
+void OS_Web::initialize() {
OS_Unix::initialize_core();
- DisplayServerJavaScript::register_javascript_driver();
+ DisplayServerWeb::register_web_driver();
#ifdef MODULE_WEBSOCKET_ENABLED
EngineDebugger::register_uri_handler("ws://", RemoteDebuggerPeerWebSocket::create);
@@ -63,23 +63,23 @@ void OS_JavaScript::initialize() {
#endif
}
-void OS_JavaScript::resume_audio() {
- AudioDriverJavaScript::resume();
+void OS_Web::resume_audio() {
+ AudioDriverWeb::resume();
}
-void OS_JavaScript::set_main_loop(MainLoop *p_main_loop) {
+void OS_Web::set_main_loop(MainLoop *p_main_loop) {
main_loop = p_main_loop;
}
-MainLoop *OS_JavaScript::get_main_loop() const {
+MainLoop *OS_Web::get_main_loop() const {
return main_loop;
}
-void OS_JavaScript::fs_sync_callback() {
+void OS_Web::fs_sync_callback() {
get_singleton()->idb_is_syncing = false;
}
-bool OS_JavaScript::main_loop_iterate() {
+bool OS_Web::main_loop_iterate() {
if (is_userfs_persistent() && idb_needs_sync && !idb_is_syncing) {
idb_is_syncing = true;
idb_needs_sync = false;
@@ -91,16 +91,16 @@ bool OS_JavaScript::main_loop_iterate() {
return Main::iteration();
}
-void OS_JavaScript::delete_main_loop() {
+void OS_Web::delete_main_loop() {
if (main_loop) {
memdelete(main_loop);
}
main_loop = nullptr;
}
-void OS_JavaScript::finalize() {
+void OS_Web::finalize() {
delete_main_loop();
- for (AudioDriverJavaScript *driver : audio_drivers) {
+ for (AudioDriverWeb *driver : audio_drivers) {
memdelete(driver);
}
audio_drivers.clear();
@@ -108,44 +108,44 @@ void OS_JavaScript::finalize() {
// Miscellaneous
-Error OS_JavaScript::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) {
+Error OS_Web::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) {
return create_process(p_path, p_arguments);
}
-Error OS_JavaScript::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) {
+Error OS_Web::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) {
Array args;
for (const String &E : p_arguments) {
args.push_back(E);
}
String json_args = Variant(args).to_json_string();
int failed = godot_js_os_execute(json_args.utf8().get_data());
- ERR_FAIL_COND_V_MSG(failed, ERR_UNAVAILABLE, "OS::execute() or create_process() must be implemented in JavaScript via 'engine.setOnExecute' if required.");
+ ERR_FAIL_COND_V_MSG(failed, ERR_UNAVAILABLE, "OS::execute() or create_process() must be implemented in Web via 'engine.setOnExecute' if required.");
return OK;
}
-Error OS_JavaScript::kill(const ProcessID &p_pid) {
- ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "OS::kill() is not available on the HTML5 platform.");
+Error OS_Web::kill(const ProcessID &p_pid) {
+ ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "OS::kill() is not available on the Web platform.");
}
-int OS_JavaScript::get_process_id() const {
- ERR_FAIL_V_MSG(0, "OS::get_process_id() is not available on the HTML5 platform.");
+int OS_Web::get_process_id() const {
+ ERR_FAIL_V_MSG(0, "OS::get_process_id() is not available on the Web platform.");
}
-bool OS_JavaScript::is_process_running(const ProcessID &p_pid) const {
+bool OS_Web::is_process_running(const ProcessID &p_pid) const {
return false;
}
-int OS_JavaScript::get_processor_count() const {
+int OS_Web::get_processor_count() const {
return godot_js_os_hw_concurrency_get();
}
-bool OS_JavaScript::_check_internal_feature_support(const String &p_feature) {
+bool OS_Web::_check_internal_feature_support(const String &p_feature) {
if (p_feature == "html5" || p_feature == "web") {
return true;
}
#ifdef JAVASCRIPT_EVAL_ENABLED
- if (p_feature == "javascript") {
+ if (p_feature == "web") {
return true;
}
#endif
@@ -163,42 +163,42 @@ bool OS_JavaScript::_check_internal_feature_support(const String &p_feature) {
return false;
}
-String OS_JavaScript::get_executable_path() const {
+String OS_Web::get_executable_path() const {
return OS::get_executable_path();
}
-Error OS_JavaScript::shell_open(String p_uri) {
+Error OS_Web::shell_open(String p_uri) {
// Open URI in a new tab, browser will deal with it by protocol.
godot_js_os_shell_open(p_uri.utf8().get_data());
return OK;
}
-String OS_JavaScript::get_name() const {
- return "HTML5";
+String OS_Web::get_name() const {
+ return "Web";
}
-void OS_JavaScript::vibrate_handheld(int p_duration_ms) {
+void OS_Web::vibrate_handheld(int p_duration_ms) {
godot_js_input_vibrate_handheld(p_duration_ms);
}
-String OS_JavaScript::get_user_data_dir() const {
+String OS_Web::get_user_data_dir() const {
return "/userfs";
}
-String OS_JavaScript::get_cache_path() const {
+String OS_Web::get_cache_path() const {
return "/home/web_user/.cache";
}
-String OS_JavaScript::get_config_path() const {
+String OS_Web::get_config_path() const {
return "/home/web_user/.config";
}
-String OS_JavaScript::get_data_path() const {
+String OS_Web::get_data_path() const {
return "/home/web_user/.local/share";
}
-void OS_JavaScript::file_access_close_callback(const String &p_file, int p_flags) {
- OS_JavaScript *os = OS_JavaScript::get_singleton();
+void OS_Web::file_access_close_callback(const String &p_file, int p_flags) {
+ OS_Web *os = OS_Web::get_singleton();
if (!(os->is_userfs_persistent() && (p_flags & FileAccess::WRITE))) {
return; // FS persistence is not working or we are not writing.
}
@@ -212,24 +212,24 @@ void OS_JavaScript::file_access_close_callback(const String &p_file, int p_flags
}
}
-void OS_JavaScript::update_pwa_state_callback() {
- if (OS_JavaScript::get_singleton()) {
- OS_JavaScript::get_singleton()->pwa_is_waiting = true;
+void OS_Web::update_pwa_state_callback() {
+ if (OS_Web::get_singleton()) {
+ OS_Web::get_singleton()->pwa_is_waiting = true;
}
if (JavaScript::get_singleton()) {
JavaScript::get_singleton()->emit_signal("pwa_update_available");
}
}
-Error OS_JavaScript::pwa_update() {
+Error OS_Web::pwa_update() {
return godot_js_pwa_update() ? FAILED : OK;
}
-bool OS_JavaScript::is_userfs_persistent() const {
+bool OS_Web::is_userfs_persistent() const {
return idb_available;
}
-Error OS_JavaScript::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) {
+Error OS_Web::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) {
String path = p_path.get_file();
p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ". Error: " + dlerror());
@@ -241,21 +241,21 @@ Error OS_JavaScript::open_dynamic_library(const String p_path, void *&p_library_
return OK;
}
-OS_JavaScript *OS_JavaScript::get_singleton() {
- return static_cast<OS_JavaScript *>(OS::get_singleton());
+OS_Web *OS_Web::get_singleton() {
+ return static_cast<OS_Web *>(OS::get_singleton());
}
-void OS_JavaScript::initialize_joypads() {
+void OS_Web::initialize_joypads() {
}
-OS_JavaScript::OS_JavaScript() {
+OS_Web::OS_Web() {
char locale_ptr[16];
godot_js_config_locale_get(locale_ptr, 16);
setenv("LANG", locale_ptr, true);
- godot_js_pwa_cb(&OS_JavaScript::update_pwa_state_callback);
+ godot_js_pwa_cb(&OS_Web::update_pwa_state_callback);
- if (AudioDriverJavaScript::is_available()) {
+ if (AudioDriverWeb::is_available()) {
#ifdef NO_THREADS
audio_drivers.push_back(memnew(AudioDriverScriptProcessor));
#endif
diff --git a/platform/javascript/os_javascript.h b/platform/web/os_web.h
index 35e13c94fc..64f3a4d133 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/web/os_web.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* os_javascript.h */
+/* os_web.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,19 +28,19 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef OS_JAVASCRIPT_H
-#define OS_JAVASCRIPT_H
+#ifndef OS_WEB_H
+#define OS_WEB_H
-#include "audio_driver_javascript.h"
+#include "audio_driver_web.h"
#include "core/input/input.h"
#include "drivers/unix/os_unix.h"
#include "servers/audio_server.h"
#include <emscripten/html5.h>
-class OS_JavaScript : public OS_Unix {
+class OS_Web : public OS_Unix {
MainLoop *main_loop = nullptr;
- List<AudioDriverJavaScript *> audio_drivers;
+ List<AudioDriverWeb *> audio_drivers;
bool idb_is_syncing = false;
bool idb_available = false;
@@ -65,7 +65,7 @@ protected:
public:
// Override return type to make writing static callbacks less tedious.
- static OS_JavaScript *get_singleton();
+ static OS_Web *get_singleton();
bool pwa_needs_update() const { return pwa_is_waiting; }
Error pwa_update();
@@ -87,7 +87,7 @@ public:
Error shell_open(String p_uri) override;
String get_name() const override;
// Override default OS implementation which would block the main thread with delay_usec.
- // Implemented in javascript_main.cpp loop callback instead.
+ // Implemented in web_main.cpp loop callback instead.
void add_frame_delay(bool p_can_draw) override {}
void vibrate_handheld(int p_duration_ms) override;
@@ -98,7 +98,6 @@ public:
String get_user_data_dir() const override;
bool is_userfs_persistent() const override;
- bool is_single_window() const override { return true; }
void alert(const String &p_alert, const String &p_title = "ALERT!") override;
@@ -106,7 +105,7 @@ public:
void resume_audio();
- OS_JavaScript();
+ OS_Web();
};
-#endif // OS_JAVASCRIPT_H
+#endif // OS_WEB_H
diff --git a/platform/javascript/package-lock.json b/platform/web/package-lock.json
index f8c67b206f..f8c67b206f 100644
--- a/platform/javascript/package-lock.json
+++ b/platform/web/package-lock.json
diff --git a/platform/javascript/package.json b/platform/web/package.json
index 8c38bc89e8..a57205415a 100644
--- a/platform/javascript/package.json
+++ b/platform/web/package.json
@@ -2,7 +2,7 @@
"name": "godot",
"private": true,
"version": "1.0.0",
- "description": "Development and linting setup for Godot's HTML5 platform code",
+ "description": "Development and linting setup for Godot's Web platform code",
"scripts": {
"docs": "jsdoc --template js/jsdoc2rst/ js/engine/engine.js js/engine/config.js --destination ''",
"lint": "npm run lint:engine && npm run lint:libs && npm run lint:modules && npm run lint:tools",
diff --git a/platform/javascript/platform_config.h b/platform/web/platform_config.h
index 1970fe0fa0..5e48992af8 100644
--- a/platform/javascript/platform_config.h
+++ b/platform/web/platform_config.h
@@ -30,4 +30,4 @@
#include <alloca.h>
-#define OPENGL_INCLUDE_H "platform/javascript/godot_webgl2.h"
+#define OPENGL_INCLUDE_H "platform/web/godot_webgl2.h"
diff --git a/platform/javascript/run_icon.png b/platform/web/run_icon.png
index 574abb0150..574abb0150 100644
--- a/platform/javascript/run_icon.png
+++ b/platform/web/run_icon.png
Binary files differ
diff --git a/platform/javascript/serve.json b/platform/web/serve.json
index f2ef24751f..f2ef24751f 100644
--- a/platform/javascript/serve.json
+++ b/platform/web/serve.json
diff --git a/platform/javascript/javascript_main.cpp b/platform/web/web_main.cpp
index 307a80feea..0f4411727a 100644
--- a/platform/javascript/javascript_main.cpp
+++ b/platform/web/web_main.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* javascript_main.cpp */
+/* web_main.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -31,21 +31,21 @@
#include "core/config/engine.h"
#include "core/io/resource_loader.h"
#include "main/main.h"
-#include "platform/javascript/display_server_javascript.h"
-#include "platform/javascript/os_javascript.h"
+#include "platform/web/display_server_web.h"
+#include "platform/web/os_web.h"
#include <emscripten/emscripten.h>
#include <stdlib.h>
#include "godot_js.h"
-static OS_JavaScript *os = nullptr;
+static OS_Web *os = nullptr;
static uint64_t target_ticks = 0;
void exit_callback() {
emscripten_cancel_main_loop(); // After this, we can exit!
Main::cleanup();
- int exit_code = OS_JavaScript::get_singleton()->get_exit_code();
+ int exit_code = OS_Web::get_singleton()->get_exit_code();
memdelete(os);
os = nullptr;
emscripten_force_exit(exit_code); // No matter that we call cancel_main_loop, regular "exit" will not work, forcing.
@@ -58,7 +58,7 @@ void cleanup_after_sync() {
void main_loop_callback() {
uint64_t current_ticks = os->get_ticks_usec();
- bool force_draw = DisplayServerJavaScript::get_singleton()->check_size_force_redraw();
+ bool force_draw = DisplayServerWeb::get_singleton()->check_size_force_redraw();
if (force_draw) {
Main::force_redraw();
} else if (current_ticks < target_ticks) {
@@ -81,8 +81,8 @@ void main_loop_callback() {
}
/// When calling main, it is assumed FS is setup and synced.
-extern EMSCRIPTEN_KEEPALIVE int godot_js_main(int argc, char *argv[]) {
- os = new OS_JavaScript();
+extern EMSCRIPTEN_KEEPALIVE int godot_web_main(int argc, char *argv[]) {
+ os = new OS_Web();
// We must override main when testing is enabled
TEST_MAIN_OVERRIDE
diff --git a/platform/javascript/javascript_runtime.cpp b/platform/web/web_runtime.cpp
index 932d0d5cb6..93a1745a83 100644
--- a/platform/javascript/javascript_runtime.cpp
+++ b/platform/web/web_runtime.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* javascript_runtime.cpp */
+/* web_runtime.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-extern int godot_js_main(int argc, char *argv[]);
+extern int godot_web_main(int argc, char *argv[]);
int main(int argc, char *argv[]) {
- return godot_js_main(argc, argv);
+ return godot_web_main(argc, argv);
}
diff --git a/platform/windows/README.md b/platform/windows/README.md
new file mode 100644
index 0000000000..c04032ae1d
--- /dev/null
+++ b/platform/windows/README.md
@@ -0,0 +1,15 @@
+# Windows platform port
+
+This folder contains the C++ code for the Windows platform port.
+
+See also [`misc/dist/windows`](/misc/dist/windows) folder for additional files
+used by this platform.
+
+## Documentation
+
+- [Compiling for Windows](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_windows.html)
+ - Instructions on building this platform port from source.
+- [Exporting for Windows](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_windows.html)
+ - Instructions on using the compiled export templates to export a project.
+- [Changing application icon for Windows](https://docs.godotengine.org/en/stable/tutorials/export/changing_application_icon_for_windows.html)
+ - Instructions on using a custom icon for the exported project executable.
diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp
index 6ce10e6f0f..b501ee78db 100644
--- a/platform/windows/crash_handler_windows.cpp
+++ b/platform/windows/crash_handler_windows.cpp
@@ -173,10 +173,18 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) {
frame.AddrStack.Mode = AddrModeFlat;
frame.AddrFrame.Mode = AddrModeFlat;
-#ifdef _M_X64
+#if defined(_M_X64)
frame.AddrPC.Offset = context->Rip;
frame.AddrStack.Offset = context->Rsp;
frame.AddrFrame.Offset = context->Rbp;
+#elif defined(_M_ARM64) || defined(_M_ARM64EC)
+ frame.AddrPC.Offset = context->Pc;
+ frame.AddrStack.Offset = context->Sp;
+ frame.AddrFrame.Offset = context->Fp;
+#elif defined(_M_ARM)
+ frame.AddrPC.Offset = context->Pc;
+ frame.AddrStack.Offset = context->Sp;
+ frame.AddrFrame.Offset = context->R11;
#else
frame.AddrPC.Offset = context->Eip;
frame.AddrStack.Offset = context->Esp;
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index dd2df1f004..5607eab342 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -1,5 +1,8 @@
import methods
import os
+import subprocess
+import sys
+from platform_methods import detect_arch
# To match other platforms
STACK_SIZE = 8388608
@@ -13,6 +16,38 @@ def get_name():
return "Windows"
+def try_cmd(test, prefix, arch):
+ if arch:
+ try:
+ out = subprocess.Popen(
+ get_mingw_bin_prefix(prefix, arch) + test,
+ shell=True,
+ stderr=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ )
+ out.communicate()
+ if out.returncode == 0:
+ return True
+ except Exception:
+ pass
+ else:
+ for a in ["x86_64", "x86_32", "arm64", "arm32"]:
+ try:
+ out = subprocess.Popen(
+ get_mingw_bin_prefix(prefix, a) + test,
+ shell=True,
+ stderr=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ )
+ out.communicate()
+ if out.returncode == 0:
+ return True
+ except Exception:
+ pass
+
+ return False
+
+
def can_build():
if os.name == "nt":
# Building natively on Windows
@@ -20,7 +55,7 @@ def can_build():
if os.getenv("VCINSTALLDIR"): # MSVC, manual setup
return True
- # Otherwise, let SCons find MSVC if installed, or else Mingw.
+ # Otherwise, let SCons find MSVC if installed, or else MinGW.
# Since we're just returning True here, if there's no compiler
# installed, we'll get errors when it tries to build with the
# null compiler.
@@ -28,46 +63,132 @@ def can_build():
if os.name == "posix":
# Cross-compiling with MinGW-w64 (old MinGW32 is not supported)
- mingw32 = "i686-w64-mingw32-"
- mingw64 = "x86_64-w64-mingw32-"
+ prefix = os.getenv("MINGW_PREFIX", "")
- if os.getenv("MINGW32_PREFIX"):
- mingw32 = os.getenv("MINGW32_PREFIX")
- if os.getenv("MINGW64_PREFIX"):
- mingw64 = os.getenv("MINGW64_PREFIX")
-
- test = "gcc --version > /dev/null 2>&1"
- if os.system(mingw64 + test) == 0 or os.system(mingw32 + test) == 0:
+ if try_cmd("gcc --version", prefix, "") or try_cmd("clang --version", prefix, ""):
return True
return False
+def get_mingw_bin_prefix(prefix, arch):
+ if not prefix:
+ mingw_bin_prefix = ""
+ elif prefix[-1] != "/":
+ mingw_bin_prefix = prefix + "/bin/"
+ else:
+ mingw_bin_prefix = prefix + "bin/"
+
+ if arch == "x86_64":
+ mingw_bin_prefix += "x86_64-w64-mingw32-"
+ elif arch == "x86_32":
+ mingw_bin_prefix += "i686-w64-mingw32-"
+ elif arch == "arm32":
+ mingw_bin_prefix += "armv7-w64-mingw32-"
+ elif arch == "arm64":
+ mingw_bin_prefix += "aarch64-w64-mingw32-"
+
+ return mingw_bin_prefix
+
+
+def detect_build_env_arch():
+ msvc_target_aliases = {
+ "amd64": "x86_64",
+ "i386": "x86_32",
+ "i486": "x86_32",
+ "i586": "x86_32",
+ "i686": "x86_32",
+ "x86": "x86_32",
+ "x64": "x86_64",
+ "x86_64": "x86_64",
+ "arm": "arm32",
+ "arm64": "arm64",
+ "aarch64": "arm64",
+ }
+ if os.getenv("VCINSTALLDIR") or os.getenv("VCTOOLSINSTALLDIR"):
+ if os.getenv("Platform"):
+ msvc_arch = os.getenv("Platform").lower()
+ if msvc_arch in msvc_target_aliases.keys():
+ return msvc_target_aliases[msvc_arch]
+
+ if os.getenv("VSCMD_ARG_TGT_ARCH"):
+ msvc_arch = os.getenv("VSCMD_ARG_TGT_ARCH").lower()
+ if msvc_arch in msvc_target_aliases.keys():
+ return msvc_target_aliases[msvc_arch]
+
+ # Pre VS 2017 checks.
+ if os.getenv("VCINSTALLDIR"):
+ PATH = os.getenv("PATH").upper()
+ VCINSTALLDIR = os.getenv("VCINSTALLDIR").upper()
+ path_arch = {
+ "BIN\\x86_ARM;": "arm32",
+ "BIN\\amd64_ARM;": "arm32",
+ "BIN\\x86_ARM64;": "arm64",
+ "BIN\\amd64_ARM64;": "arm64",
+ "BIN\\x86_amd64;": "a86_64",
+ "BIN\\amd64;": "x86_64",
+ "BIN\\amd64_x86;": "x86_32",
+ "BIN;": "x86_32",
+ }
+ for path, arch in path_arch.items():
+ final_path = VCINSTALLDIR + path
+ if final_path in PATH:
+ return arch
+
+ # VS 2017 and newer.
+ if os.getenv("VCTOOLSINSTALLDIR"):
+ host_path_index = os.getenv("PATH").upper().find(os.getenv("VCTOOLSINSTALLDIR").upper() + "BIN\\HOST")
+ if host_path_index > -1:
+ first_path_arch = os.getenv("PATH").split(";")[0].rsplit("\\", 1)[-1].lower()
+ return msvc_target_aliases[first_path_arch]
+
+ msys_target_aliases = {
+ "mingw32": "x86_32",
+ "mingw64": "x86_64",
+ "ucrt64": "x86_64",
+ "clang64": "x86_64",
+ "clang32": "x86_32",
+ "clangarm64": "arm64",
+ }
+ if os.getenv("MSYSTEM"):
+ msys_arch = os.getenv("MSYSTEM").lower()
+ if msys_arch in msys_target_aliases.keys():
+ return msys_target_aliases[msys_arch]
+
+ return ""
+
+
def get_opts():
from SCons.Variables import BoolVariable, EnumVariable
- mingw32 = ""
- mingw64 = ""
- if os.name == "posix":
- mingw32 = "i686-w64-mingw32-"
- mingw64 = "x86_64-w64-mingw32-"
-
- if os.getenv("MINGW32_PREFIX"):
- mingw32 = os.getenv("MINGW32_PREFIX")
- if os.getenv("MINGW64_PREFIX"):
- mingw64 = os.getenv("MINGW64_PREFIX")
+ mingw = os.getenv("MINGW_PREFIX", "")
return [
- ("mingw_prefix_32", "MinGW prefix (Win32)", mingw32),
- ("mingw_prefix_64", "MinGW prefix (Win64)", mingw64),
+ ("mingw_prefix", "MinGW prefix", mingw),
# Targeted Windows version: 7 (and later), minimum supported version
# XP support dropped after EOL due to missing API for IPv6 and other issues
# Vista support dropped after EOL due to GH-10243
- ("target_win_version", "Targeted Windows version, >= 0x0601 (Windows 7)", "0x0601"),
- BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True),
+ (
+ "target_win_version",
+ "Targeted Windows version, >= 0x0601 (Windows 7)",
+ "0x0601",
+ ),
+ BoolVariable(
+ "debug_symbols",
+ "Add debugging symbols to release/release_debug builds",
+ True,
+ ),
EnumVariable("windows_subsystem", "Windows subsystem", "gui", ("gui", "console")),
- 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(
+ "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.", False),
BoolVariable("use_llvm", "Use the LLVM compiler", False),
BoolVariable("use_thinlto", "Use ThinLTO", False),
@@ -77,62 +198,63 @@ def get_opts():
def get_flags():
- return []
+ arch = detect_build_env_arch() or detect_arch()
+
+ return [
+ ("arch", arch),
+ ]
def build_res_file(target, source, env):
- if env["bits"] == "32":
- cmdbase = env["mingw_prefix_32"]
- else:
- cmdbase = env["mingw_prefix_64"]
- cmdbase = cmdbase + "windres --include-dir . "
- import subprocess
+ arch_aliases = {
+ "x86_32": "pe-i386",
+ "x86_64": "pe-x86-64",
+ "arm32": "armv7-w64-mingw32",
+ "arm64": "aarch64-w64-mingw32",
+ }
+ cmdbase = "windres --include-dir . --target=" + arch_aliases[env["arch"]]
+
+ mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"])
for x in range(len(source)):
- cmd = cmdbase + "-i " + str(source[x]) + " -o " + str(target[x])
+ ok = True
+ # Try prefixed executable (MinGW on Linux).
+ cmd = mingw_bin_prefix + cmdbase + " -i " + str(source[x]) + " -o " + str(target[x])
try:
out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
if len(out[1]):
- return 1
+ ok = False
except Exception:
- return 1
+ ok = False
+
+ # Try generic executable (MSYS2).
+ if not ok:
+ cmd = cmdbase + " -i " + str(source[x]) + " -o " + str(target[x])
+ try:
+ out = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE).communicate()
+ if len(out[1]):
+ return -1
+ except Exception:
+ return -1
+
return 0
def setup_msvc_manual(env):
- """Set up env to use MSVC manually, using VCINSTALLDIR"""
- if env["bits"] != "default":
+ """Running from VCVARS environment"""
+
+ env_arch = detect_build_env_arch()
+ if env["arch"] != env_arch:
print(
"""
- Bits argument is not supported for MSVC compilation. Architecture depends on the Native/Cross Compile Tools Prompt/Developer Console
- (or Visual Studio settings) that is being used to run SCons. As a consequence, bits argument is disabled. Run scons again without bits
- argument (example: scons p=windows) and SCons will attempt to detect what MSVC compiler will be executed and inform you.
+ Arch argument (%s) is not matching Native/Cross Compile Tools Prompt/Developer Console (or Visual Studio settings) that is being used to run SCons (%s).
+ Run SCons again without arch argument (example: scons p=windows) and SCons will attempt to detect what MSVC compiler will be executed and inform you.
"""
+ % (env["arch"], env_arch)
)
- raise SCons.Errors.UserError("Bits argument should not be used when using VCINSTALLDIR")
-
- # Force bits arg
- # (Actually msys2 mingw can support 64-bit, we could detect that)
- env["bits"] = "32"
- env["x86_libtheora_opt_vc"] = True
-
- # find compiler manually
- compiler_version_str = methods.detect_visual_c_compiler_version(env["ENV"])
- print("Found MSVC compiler: " + compiler_version_str)
-
- # If building for 64bit architecture, disable assembly optimisations for 32 bit builds (theora as of writing)... vc compiler for 64bit can not compile _asm
- if compiler_version_str == "amd64" or compiler_version_str == "x86_amd64":
- env["bits"] = "64"
- env["x86_libtheora_opt_vc"] = False
- print("Compiled program architecture will be a 64 bit executable (forcing bits=64).")
- elif compiler_version_str == "x86" or compiler_version_str == "amd64_x86":
- print("Compiled program architecture will be a 32 bit executable. (forcing bits=32).")
- else:
- print(
- "Failed to manually detect MSVC compiler architecture version... Defaulting to 32bit executable settings"
- " (forcing bits=32). Compilation attempt will continue, but SCons can not detect for what architecture this"
- " build is compiled for. You should check your settings/compilation setup, or avoid setting VCINSTALLDIR."
- )
+ sys.exit(200)
+
+ print("Found MSVC, arch %s" % (env_arch))
def setup_msvc_auto(env):
@@ -141,6 +263,18 @@ def setup_msvc_auto(env):
# If MSVC_VERSION is set by SCons, we know MSVC is installed.
# But we may want a different version or target arch.
+ # Valid architectures for MSVC's TARGET_ARCH:
+ # ['amd64', 'emt64', 'i386', 'i486', 'i586', 'i686', 'ia64', 'itanium', 'x86', 'x86_64', 'arm', 'arm64', 'aarch64']
+ # Our x86_64 and arm64 are the same, and we need to map the 32-bit
+ # architectures to other names since MSVC isn't as explicit.
+ # The rest we don't need to worry about because they are
+ # aliases or aren't supported by Godot (itanium & ia64).
+ msvc_arch_aliases = {"x86_32": "x86", "arm32": "arm"}
+ if env["arch"] in msvc_arch_aliases.keys():
+ env["TARGET_ARCH"] = msvc_arch_aliases[env["arch"]]
+ else:
+ env["TARGET_ARCH"] = env["arch"]
+
# The env may have already been set up with default MSVC tools, so
# reset a few things so we can set it up with the tools we want.
# (Ideally we'd decide on the tool config before configuring any
@@ -149,35 +283,55 @@ def setup_msvc_auto(env):
env["MSVC_SETUP_RUN"] = False # Need to set this to re-run the tool
env["MSVS_VERSION"] = None
env["MSVC_VERSION"] = None
- env["TARGET_ARCH"] = None
- if env["bits"] != "default":
- env["TARGET_ARCH"] = {"32": "x86", "64": "x86_64"}[env["bits"]]
+
if "msvc_version" in env:
env["MSVC_VERSION"] = env["msvc_version"]
env.Tool("msvc")
env.Tool("mssdk") # we want the MS SDK
+
# Note: actual compiler version can be found in env['MSVC_VERSION'], e.g. "14.1" for VS2015
- # Get actual target arch into bits (it may be "default" at this point):
- if env["TARGET_ARCH"] in ("amd64", "x86_64"):
- env["bits"] = "64"
- else:
- env["bits"] = "32"
- print("Found MSVC version %s, arch %s, bits=%s" % (env["MSVC_VERSION"], env["TARGET_ARCH"], env["bits"]))
- if env["TARGET_ARCH"] in ("amd64", "x86_64"):
- env["x86_libtheora_opt_vc"] = False
+ print("Found MSVC version %s, arch %s" % (env["MSVC_VERSION"], env["arch"]))
def setup_mingw(env):
"""Set up env for use with mingw"""
- # Nothing to do here
- print("Using MinGW")
+ env_arch = detect_build_env_arch()
+ if os.getenv("MSYSTEM") == "MSYS":
+ print(
+ """
+ Running from base MSYS2 console/environment, use target specific environment instead (e.g., mingw32, mingw64, clang32, clang64).
+ """
+ )
+ sys.exit(201)
+
+ if env_arch != "" and env["arch"] != env_arch:
+ print(
+ """
+ Arch argument (%s) is not matching MSYS2 console/environment that is being used to run SCons (%s).
+ Run SCons again without arch argument (example: scons p=windows) and SCons will attempt to detect what MSYS2 compiler will be executed and inform you.
+ """
+ % (env["arch"], env_arch)
+ )
+ sys.exit(202)
-def configure_msvc(env, manual_msvc_config):
+ if not try_cmd("gcc --version", env["mingw_prefix"], env["arch"]) and not try_cmd(
+ "clang --version", env["mingw_prefix"], env["arch"]
+ ):
+ print(
+ """
+ No valid compilers found, use MINGW_PREFIX environment variable to set MinGW path.
+ """
+ )
+ sys.exit(202)
+
+ print("Using MinGW, arch %s" % (env["arch"]))
+
+
+def configure_msvc(env, vcvars_msvc_config):
"""Configure env to work with MSVC"""
# Build type
-
if env["target"] == "release":
if env["optimize"] == "speed": # optimize for speed (default)
env.Append(CCFLAGS=["/O2"])
@@ -217,6 +371,9 @@ def configure_msvc(env, manual_msvc_config):
else:
env.AppendUnique(CCFLAGS=["/MD"])
+ if env["arch"] == "x86_32":
+ env["x86_libtheora_opt_vc"] = True
+
env.AppendUnique(CCFLAGS=["/Gd", "/GR", "/nologo"])
env.AppendUnique(CCFLAGS=["/utf-8"]) # Force to use Unicode encoding.
env.AppendUnique(CXXFLAGS=["/TP"]) # assume all sources are C++
@@ -225,7 +382,7 @@ def configure_msvc(env, manual_msvc_config):
# for notes on why this shouldn't be enabled for gcc
env.AppendUnique(CCFLAGS=["/bigobj"])
- if manual_msvc_config: # should be automatic if SCons found it
+ if vcvars_msvc_config: # should be automatic if SCons found it
if os.getenv("WindowsSdkDir") is not None:
env.Prepend(CPPPATH=[os.getenv("WindowsSdkDir") + "/Include"])
else:
@@ -244,7 +401,7 @@ def configure_msvc(env, manual_msvc_config):
]
)
env.AppendUnique(CPPDEFINES=["NOMINMAX"]) # disable bogus min/max WinDef.h macros
- if env["bits"] == "64":
+ if env["arch"] == "x86_64":
env.AppendUnique(CPPDEFINES=["_WIN64"])
## Libs
@@ -284,7 +441,7 @@ def configure_msvc(env, manual_msvc_config):
env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS])
- if manual_msvc_config:
+ if vcvars_msvc_config:
if os.getenv("WindowsSdkDir") is not None:
env.Append(LIBPATH=[os.getenv("WindowsSdkDir") + "/Lib"])
else:
@@ -300,7 +457,7 @@ def configure_msvc(env, manual_msvc_config):
else:
env.AppendUnique(LINKFLAGS=["/LTCG"])
- if manual_msvc_config:
+ if vcvars_msvc_config:
env.Prepend(CPPPATH=[p for p in os.getenv("INCLUDE").split(";")])
env.Append(LIBPATH=[p for p in os.getenv("LIB").split(";")])
@@ -324,14 +481,20 @@ def configure_mingw(env):
## Build type
+ if not env["use_llvm"] and not try_cmd("gcc --version", env["mingw_prefix"], env["arch"]):
+ env["use_llvm"] = True
+
+ if env["use_llvm"] and not try_cmd("clang --version", env["mingw_prefix"], env["arch"]):
+ env["use_llvm"] = False
+
if env["target"] == "release":
env.Append(CCFLAGS=["-msse2"])
if env["optimize"] == "speed": # optimize for speed (default)
- if env["bits"] == "64":
- env.Append(CCFLAGS=["-O3"])
- else:
+ if env["arch"] == "x86_32":
env.Append(CCFLAGS=["-O2"])
+ else:
+ env.Append(CCFLAGS=["-O3"])
else: # optimize for size
env.Prepend(CCFLAGS=["-Os"])
@@ -365,39 +528,39 @@ def configure_mingw(env):
if os.name != "nt":
env["PROGSUFFIX"] = env["PROGSUFFIX"] + ".exe" # for linux cross-compilation
- if env["bits"] == "default":
- if os.name == "nt":
- env["bits"] = "64" if "PROGRAMFILES(X86)" in os.environ else "32"
- else: # default to 64-bit on Linux
- env["bits"] = "64"
-
- mingw_prefix = ""
-
- if env["bits"] == "32":
+ if env["arch"] == "x86_32":
if env["use_static_cpp"]:
env.Append(LINKFLAGS=["-static"])
env.Append(LINKFLAGS=["-static-libgcc"])
env.Append(LINKFLAGS=["-static-libstdc++"])
- mingw_prefix = env["mingw_prefix_32"]
else:
if env["use_static_cpp"]:
env.Append(LINKFLAGS=["-static"])
- mingw_prefix = env["mingw_prefix_64"]
+
+ if env["arch"] in ["x86_32", "x86_64"]:
+ env["x86_libtheora_opt_gcc"] = True
+
+ mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"])
if env["use_llvm"]:
- env["CC"] = mingw_prefix + "clang"
- env["CXX"] = mingw_prefix + "clang++"
- env["AS"] = mingw_prefix + "as"
- env["AR"] = mingw_prefix + "ar"
- env["RANLIB"] = mingw_prefix + "ranlib"
+ env["CC"] = mingw_bin_prefix + "clang"
+ env["CXX"] = mingw_bin_prefix + "clang++"
+ if try_cmd("as --version", env["mingw_prefix"], env["arch"]):
+ env["AS"] = mingw_bin_prefix + "as"
+ if try_cmd("ar --version", env["mingw_prefix"], env["arch"]):
+ env["AR"] = mingw_bin_prefix + "ar"
+ if try_cmd("ranlib --version", env["mingw_prefix"], env["arch"]):
+ env["RANLIB"] = mingw_bin_prefix + "ranlib"
+ env.extra_suffix = ".llvm" + env.extra_suffix
else:
- env["CC"] = mingw_prefix + "gcc"
- env["CXX"] = mingw_prefix + "g++"
- env["AS"] = mingw_prefix + "as"
- env["AR"] = mingw_prefix + "gcc-ar"
- env["RANLIB"] = mingw_prefix + "gcc-ranlib"
-
- env["x86_libtheora_opt_gcc"] = True
+ env["CC"] = mingw_bin_prefix + "gcc"
+ env["CXX"] = mingw_bin_prefix + "g++"
+ if try_cmd("as --version", env["mingw_prefix"], env["arch"]):
+ env["AS"] = mingw_bin_prefix + "as"
+ if try_cmd("gcc-ar --version", env["mingw_prefix"], env["arch"]):
+ env["AR"] = mingw_bin_prefix + "gcc-ar"
+ if try_cmd("gcc-ranlib --version", env["mingw_prefix"], env["arch"]):
+ env["RANLIB"] = mingw_bin_prefix + "gcc-ranlib"
if env["use_lto"]:
if not env["use_llvm"] and env.GetOption("num_jobs") > 1:
@@ -415,10 +578,16 @@ def configure_mingw(env):
## Compile flags
- env.Append(CCFLAGS=["-mwindows"])
+ if not env["use_llvm"]:
+ env.Append(CCFLAGS=["-mwindows"])
env.Append(CPPDEFINES=["WINDOWS_ENABLED", "WASAPI_ENABLED", "WINMIDI_ENABLED"])
- env.Append(CPPDEFINES=[("WINVER", env["target_win_version"]), ("_WIN32_WINNT", env["target_win_version"])])
+ env.Append(
+ CPPDEFINES=[
+ ("WINVER", env["target_win_version"]),
+ ("_WIN32_WINNT", env["target_win_version"]),
+ ]
+ )
env.Append(
LIBS=[
"mingw32",
@@ -460,32 +629,38 @@ def configure_mingw(env):
def configure(env):
+ # Validate arch.
+ supported_arches = ["x86_32", "x86_64", "arm32", "arm64"]
+ if env["arch"] not in supported_arches:
+ print(
+ 'Unsupported CPU architecture "%s" for Windows. Supported architectures are: %s.'
+ % (env["arch"], ", ".join(supported_arches))
+ )
+ sys.exit()
+
# At this point the env has been set up with basic tools/compilers.
env.Prepend(CPPPATH=["#platform/windows"])
- print("Configuring for Windows: target=%s, bits=%s" % (env["target"], env["bits"]))
-
if os.name == "nt":
env["ENV"] = os.environ # this makes build less repeatable, but simplifies some things
env["ENV"]["TMP"] = os.environ["TMP"]
# First figure out which compiler, version, and target arch we're using
- if os.getenv("VCINSTALLDIR") and not env["use_mingw"]:
- # Manual setup of MSVC
+ if os.getenv("VCINSTALLDIR") and detect_build_env_arch() and not env["use_mingw"]:
setup_msvc_manual(env)
env.msvc = True
- manual_msvc_config = True
+ vcvars_msvc_config = True
elif env.get("MSVC_VERSION", "") and not env["use_mingw"]:
setup_msvc_auto(env)
env.msvc = True
- manual_msvc_config = False
+ vcvars_msvc_config = False
else:
setup_mingw(env)
env.msvc = False
# Now set compiler/linker flags
if env.msvc:
- configure_msvc(env, manual_msvc_config)
+ configure_msvc(env, vcvars_msvc_config)
else: # MinGW
configure_mingw(env)
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index f6baab1644..7eb61b3038 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -144,8 +144,8 @@ bool DisplayServerWindows::tts_is_paused() const {
return tts->is_paused();
}
-Array DisplayServerWindows::tts_get_voices() const {
- ERR_FAIL_COND_V(!tts, Array());
+TypedArray<Dictionary> DisplayServerWindows::tts_get_voices() const {
+ ERR_FAIL_COND_V(!tts, TypedArray<Dictionary>());
return tts->get_voices();
}
@@ -531,10 +531,43 @@ DisplayServer::ScreenOrientation DisplayServerWindows::screen_get_orientation(in
}
void DisplayServerWindows::screen_set_keep_on(bool p_enable) {
+ if (keep_screen_on == p_enable) {
+ return;
+ }
+
+ if (p_enable) {
+ const String reason = "Godot Engine running with display/window/energy_saving/keep_screen_on = true";
+ Char16String reason_utf16 = reason.utf16();
+
+ REASON_CONTEXT context;
+ context.Version = POWER_REQUEST_CONTEXT_VERSION;
+ context.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING;
+ context.Reason.SimpleReasonString = (LPWSTR)(reason_utf16.ptrw());
+ power_request = PowerCreateRequest(&context);
+ if (power_request == INVALID_HANDLE_VALUE) {
+ print_error("Failed to enable screen_keep_on.");
+ return;
+ }
+ if (PowerSetRequest(power_request, POWER_REQUEST_TYPE::PowerRequestSystemRequired) == 0) {
+ print_error("Failed to request system sleep override.");
+ return;
+ }
+ if (PowerSetRequest(power_request, POWER_REQUEST_TYPE::PowerRequestDisplayRequired) == 0) {
+ print_error("Failed to request display timeout override.");
+ return;
+ }
+ } else {
+ PowerClearRequest(power_request, POWER_REQUEST_TYPE::PowerRequestSystemRequired);
+ PowerClearRequest(power_request, POWER_REQUEST_TYPE::PowerRequestDisplayRequired);
+ CloseHandle(power_request);
+ power_request = nullptr;
+ }
+
+ keep_screen_on = p_enable;
}
bool DisplayServerWindows::screen_is_kept_on() const {
- return false;
+ return keep_screen_on;
}
Vector<DisplayServer::WindowID> DisplayServerWindows::get_window_list() const {
@@ -3619,6 +3652,9 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
// Init TTS
tts = memnew(TTS_Windows);
+ // Enforce default keep screen on value.
+ screen_set_keep_on(GLOBAL_GET("display/window/energy_saving/keep_screen_on"));
+
// Note: Wacom WinTab driver API for pen input, for devices incompatible with Windows Ink.
HMODULE wintab_lib = LoadLibraryW(L"wintab32.dll");
if (wintab_lib) {
@@ -3822,6 +3858,9 @@ DisplayServerWindows::~DisplayServerWindows() {
SetWindowLongPtr(windows[MAIN_WINDOW_ID].hWnd, GWLP_WNDPROC, (LONG_PTR)user_proc);
}
+ // Close power request handle.
+ screen_set_keep_on(false);
+
#ifdef GLES3_ENABLED
// destroy windows .. NYI?
// FIXME wglDeleteContext is never called
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index ddbf674c64..556ce9ff5d 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -331,6 +331,8 @@ class DisplayServerWindows : public DisplayServer {
HINSTANCE hInstance; // Holds The Instance Of The Application
String rendering_driver;
bool app_focused = false;
+ bool keep_screen_on = false;
+ HANDLE power_request;
TTS_Windows *tts = nullptr;
@@ -476,7 +478,7 @@ public:
virtual bool tts_is_speaking() const override;
virtual bool tts_is_paused() const override;
- virtual Array tts_get_voices() const override;
+ virtual TypedArray<Dictionary> tts_get_voices() const override;
virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false) override;
virtual void tts_pause() override;
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index febef5ad12..016d201f2c 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -113,7 +113,7 @@ List<String> EditorExportPlatformWindows::get_binary_extensions(const Ref<Editor
return list;
}
-bool EditorExportPlatformWindows::get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const {
+bool EditorExportPlatformWindows::get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
// This option is not supported by "osslsigncode", used on non-Windows host.
if (!OS::get_singleton()->has_feature("windows") && p_option == "codesign/identity_type") {
return false;
@@ -123,12 +123,12 @@ bool EditorExportPlatformWindows::get_export_option_visibility(const String &p_o
void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_options) {
EditorExportPlatformPC::get_export_options(r_options);
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32"), "x86_64"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm64"), "x86_64"));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/identity_type", PROPERTY_HINT_ENUM, "Select automatically,Use PKCS12 file (specify *.PFX/*.P12 file),Use certificate store (specify SHA1 hash)"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_GLOBAL_FILE, "*.pfx,*.p12"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/password"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/password", PROPERTY_HINT_PASSWORD), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/timestamp_server_url"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/digest_algorithm", PROPERTY_HINT_ENUM, "SHA1,SHA256"), 1));
@@ -231,7 +231,7 @@ Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset
String str;
Error err = OS::get_singleton()->execute(rcedit_path, args, &str, nullptr, true);
if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
- add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), TTR("Could not start rcedit executable. Configure rcedit path in the Editor Settings (Export > Windows > Rcedit), or disable \"Application > Modify Resources\" in the export preset."));
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Resources Modification"), TTR("Could not start rcedit executable. Configure rcedit path in the Editor Settings (Export > Windows > rcedit), or disable \"Application > Modify Resources\" in the export preset."));
return err;
}
print_line("rcedit (" + p_path + "): " + str);
@@ -379,7 +379,11 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
String str;
Error err = OS::get_singleton()->execute(signtool_path, args, &str, nullptr, true);
if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
- add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start signtool executable. Configure signtool path in the Editor Settings (Export > Windows > Signtool), or disable \"Codesign\" in the export preset."));
+#ifndef WINDOWS_ENABLED
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start signtool executable. Configure signtool path in the Editor Settings (Export > Windows > signtool), or disable \"Codesign\" in the export preset."));
+#else
+ add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start osslsigncode executable. Configure signtool path in the Editor Settings (Export > Windows > osslsigncode), or disable \"Codesign\" in the export preset."));
+#endif
return err;
}
@@ -412,15 +416,26 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
return OK;
}
-bool EditorExportPlatformWindows::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+bool EditorExportPlatformWindows::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
String err = "";
- bool valid = EditorExportPlatformPC::can_export(p_preset, err, r_missing_templates);
+ bool valid = EditorExportPlatformPC::has_valid_export_configuration(p_preset, err, r_missing_templates);
String rcedit_path = EditorSettings::get_singleton()->get("export/windows/rcedit");
if (p_preset->get("application/modify_resources") && rcedit_path.is_empty()) {
- err += TTR("The rcedit tool must be configured in the Editor Settings (Export > Windows > Rcedit) to change the icon or app information data.") + "\n";
+ err += TTR("The rcedit tool must be configured in the Editor Settings (Export > Windows > rcedit) to change the icon or app information data.") + "\n";
+ }
+
+ if (!err.is_empty()) {
+ r_error = err;
}
+ return valid;
+}
+
+bool EditorExportPlatformWindows::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const {
+ String err = "";
+ bool valid = true;
+
String icon_path = ProjectSettings::get_singleton()->globalize_path(p_preset->get("application/icon"));
if (!icon_path.is_empty() && !FileAccess::exists(icon_path)) {
err += TTR("Invalid icon path:") + " " + icon_path + "\n";
diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h
index b9e59829a0..f85331c898 100644
--- a/platform/windows/export/export_plugin.h
+++ b/platform/windows/export/export_plugin.h
@@ -48,8 +48,9 @@ public:
virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) override;
virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
virtual void get_export_options(List<ExportOption> *r_options) override;
- virtual bool get_export_option_visibility(const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
- virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual bool has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const override;
+ virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
virtual String get_template_file_name(const String &p_target, const String &p_arch) const override;
virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override;
};
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index ad4be950cc..403d53ae53 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -237,7 +237,7 @@ Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_han
if (!FileAccess::exists(path)) {
//this code exists so gdnative can load .dll files from within the executable path
- path = get_executable_path().get_base_dir().plus_file(p_path.get_file());
+ path = get_executable_path().get_base_dir().path_join(p_path.get_file());
}
typedef DLL_DIRECTORY_COOKIE(WINAPI * PAddDllDirectory)(PCWSTR);
@@ -902,7 +902,7 @@ void OS_Windows::run() {
main_loop->initialize();
- while (!force_quit) {
+ while (true) {
DisplayServer::get_singleton()->process_events(); // get rid of pending events
if (Main::iteration()) {
break;
@@ -1071,13 +1071,13 @@ String OS_Windows::get_user_data_dir() const {
if (custom_dir.is_empty()) {
custom_dir = appname;
}
- return get_data_path().plus_file(custom_dir).replace("\\", "/");
+ return get_data_path().path_join(custom_dir).replace("\\", "/");
} else {
- return get_data_path().plus_file(get_godot_dir_name()).plus_file("app_userdata").plus_file(appname).replace("\\", "/");
+ return get_data_path().path_join(get_godot_dir_name()).path_join("app_userdata").path_join(appname).replace("\\", "/");
}
}
- return get_data_path().plus_file(get_godot_dir_name()).plus_file("app_userdata").plus_file("[unnamed project]");
+ return get_data_path().path_join(get_godot_dir_name()).path_join("app_userdata").path_join("[unnamed project]");
}
String OS_Windows::get_unique_id() const {
@@ -1132,8 +1132,6 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) {
main_loop = nullptr;
process_map = nullptr;
- force_quit = false;
-
hInstance = _hInstance;
#ifdef STDOUT_FILE
stdo = fopen("stdout.txt", "wb");
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 80fc860738..3e054c068c 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -110,7 +110,6 @@ class OS_Windows : public OS {
ErrorHandlerList error_handlers;
#endif
- bool force_quit;
HWND main_window;
// functions used by main to initialize/deinitialize the OS
diff --git a/platform/windows/platform_windows_builders.py b/platform/windows/platform_windows_builders.py
index 22e33b51b4..33ca2e8ffa 100644
--- a/platform/windows/platform_windows_builders.py
+++ b/platform/windows/platform_windows_builders.py
@@ -9,7 +9,7 @@ from platform_methods import subprocess_main
def make_debug_mingw(target, source, env):
mingw_prefix = ""
- if env["bits"] == "32":
+ if env["arch"] == "x86_32":
mingw_prefix = env["mingw_prefix_32"]
else:
mingw_prefix = env["mingw_prefix_64"]
diff --git a/platform_methods.py b/platform_methods.py
index be4957475d..1a2520794c 100644
--- a/platform_methods.py
+++ b/platform_methods.py
@@ -1,6 +1,7 @@
import os
import sys
import json
+import platform
import uuid
import functools
import subprocess
@@ -71,9 +72,42 @@ def run_in_subprocess(builder_function):
def subprocess_main(namespace):
-
with open(sys.argv[1]) as json_file:
data = json.load(json_file)
fn = namespace[data["fn"]]
fn(*data["args"])
+
+
+# CPU architecture options.
+architectures = ["x86_32", "x86_64", "arm32", "arm64", "rv64", "ppc32", "ppc64", "wasm32"]
+architecture_aliases = {
+ "x86": "x86_32",
+ "x64": "x86_64",
+ "amd64": "x86_64",
+ "armv7": "arm32",
+ "armv8": "arm64",
+ "arm64v8": "arm64",
+ "aarch64": "arm64",
+ "rv": "rv64",
+ "riscv": "rv64",
+ "riscv64": "rv64",
+ "ppcle": "ppc32",
+ "ppc": "ppc32",
+ "ppc64le": "ppc64",
+}
+
+
+def detect_arch():
+ host_machine = platform.machine().lower()
+ if host_machine in architectures:
+ return host_machine
+ elif host_machine in architecture_aliases.keys():
+ return architecture_aliases[host_machine]
+ elif "86" in host_machine:
+ # Catches x86, i386, i486, i586, i686, etc.
+ return "x86_32"
+ else:
+ print("Unsupported CPU architecture: " + host_machine)
+ print("Falling back to x86_64.")
+ return "x86_64"
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp
index d56c7b8811..4565462247 100644
--- a/scene/2d/animated_sprite_2d.cpp
+++ b/scene/2d/animated_sprite_2d.cpp
@@ -104,47 +104,50 @@ Rect2 AnimatedSprite2D::_get_rect() const {
return Rect2(ofs, s);
}
-void AnimatedSprite2D::_validate_property(PropertyInfo &property) const {
+void AnimatedSprite2D::_validate_property(PropertyInfo &p_property) const {
if (!frames.is_valid()) {
return;
}
- if (property.name == "animation") {
- property.hint = PROPERTY_HINT_ENUM;
+ if (p_property.name == "animation") {
+ p_property.hint = PROPERTY_HINT_ENUM;
List<StringName> names;
frames->get_animation_list(&names);
names.sort_custom<StringName::AlphCompare>();
bool current_found = false;
+ bool is_first_element = true;
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- if (E->prev()) {
- property.hint_string += ",";
+ for (const StringName &E : names) {
+ if (!is_first_element) {
+ p_property.hint_string += ",";
+ } else {
+ is_first_element = false;
}
- property.hint_string += String(E->get());
- if (animation == E->get()) {
+ p_property.hint_string += String(E);
+ if (animation == E) {
current_found = true;
}
}
if (!current_found) {
- if (property.hint_string.is_empty()) {
- property.hint_string = String(animation);
+ if (p_property.hint_string.is_empty()) {
+ p_property.hint_string = String(animation);
} else {
- property.hint_string = String(animation) + "," + property.hint_string;
+ p_property.hint_string = String(animation) + "," + p_property.hint_string;
}
}
}
- if (property.name == "frame") {
- property.hint = PROPERTY_HINT_RANGE;
+ if (p_property.name == "frame") {
+ p_property.hint = PROPERTY_HINT_RANGE;
if (frames->has_animation(animation) && frames->get_frame_count(animation) > 0) {
- property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1";
+ p_property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1";
} else {
// Avoid an error, `hint_string` is required for `PROPERTY_HINT_RANGE`.
- property.hint_string = "0,0,1";
+ p_property.hint_string = "0,0,1";
}
- property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
+ p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
}
diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h
index ec38795a1a..0a19e250d8 100644
--- a/scene/2d/animated_sprite_2d.h
+++ b/scene/2d/animated_sprite_2d.h
@@ -62,7 +62,7 @@ class AnimatedSprite2D : public Node2D {
protected:
static void _bind_methods();
void _notification(int p_what);
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
#ifdef TOOLS_ENABLED
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index 7890348314..75f1497edc 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -498,8 +498,8 @@ StringName Area2D::get_audio_bus_name() const {
return "Master";
}
-void Area2D::_validate_property(PropertyInfo &property) const {
- if (property.name == "audio_bus_name") {
+void Area2D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "audio_bus_name") {
String options;
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
if (i > 0) {
@@ -509,28 +509,28 @@ void Area2D::_validate_property(PropertyInfo &property) const {
options += name;
}
- property.hint_string = options;
- } else if (property.name.begins_with("gravity") && property.name != "gravity_space_override") {
+ p_property.hint_string = options;
+ } else if (p_property.name.begins_with("gravity") && p_property.name != "gravity_space_override") {
if (gravity_space_override == SPACE_OVERRIDE_DISABLED) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
} else {
if (gravity_is_point) {
- if (property.name == "gravity_direction") {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name == "gravity_direction") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
} else {
- if (property.name.begins_with("gravity_point_")) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name.begins_with("gravity_point_")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
}
- } else if (property.name.begins_with("linear_damp") && property.name != "linear_damp_space_override") {
+ } else if (p_property.name.begins_with("linear_damp") && p_property.name != "linear_damp_space_override") {
if (linear_damp_space_override == SPACE_OVERRIDE_DISABLED) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- } else if (property.name.begins_with("angular_damp") && property.name != "angular_damp_space_override") {
+ } else if (p_property.name.begins_with("angular_damp") && p_property.name != "angular_damp_space_override") {
if (angular_damp_space_override == SPACE_OVERRIDE_DISABLED) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
}
diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h
index a584420ced..3d8d77eabb 100644
--- a/scene/2d/area_2d.h
+++ b/scene/2d/area_2d.h
@@ -135,7 +135,7 @@ private:
protected:
void _notification(int p_what);
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_gravity_space_override_mode(SpaceOverride p_mode);
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index 94d22111ea..fc019b6cf9 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -185,7 +185,7 @@ void AudioStreamPlayer2D::_update_panning() {
}
float multiplier = Math::pow(1.0f - dist / max_distance, attenuation);
- multiplier *= Math::db2linear(volume_db); //also apply player volume!
+ multiplier *= Math::db_to_linear(volume_db); //also apply player volume!
float pan = relative_to_listener.x / screen_size.x;
// Don't let the panning effect extend (too far) beyond the screen.
@@ -323,8 +323,8 @@ bool AudioStreamPlayer2D::_is_active() const {
return active.is_set();
}
-void AudioStreamPlayer2D::_validate_property(PropertyInfo &property) const {
- if (property.name == "bus") {
+void AudioStreamPlayer2D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "bus") {
String options;
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
if (i > 0) {
@@ -334,7 +334,7 @@ void AudioStreamPlayer2D::_validate_property(PropertyInfo &property) const {
options += name;
}
- property.hint_string = options;
+ p_property.hint_string = options;
}
}
diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h
index d1c4dc4fdf..616d7fdb60 100644
--- a/scene/2d/audio_stream_player_2d.h
+++ b/scene/2d/audio_stream_player_2d.h
@@ -85,7 +85,7 @@ private:
float cached_global_panning_strength = 1.0f;
protected:
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index c43a796170..88f9c2a4a6 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -655,9 +655,9 @@ bool Camera2D::is_margin_drawing_enabled() const {
return margin_drawing_enabled;
}
-void Camera2D::_validate_property(PropertyInfo &property) const {
- if (!smoothing_enabled && property.name == "smoothing_speed") {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void Camera2D::_validate_property(PropertyInfo &p_property) const {
+ if (!smoothing_enabled && p_property.name == "smoothing_speed") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h
index 294a6fcb80..78654ee606 100644
--- a/scene/2d/camera_2d.h
+++ b/scene/2d/camera_2d.h
@@ -100,7 +100,7 @@ protected:
void _notification(int p_what);
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_offset(const Vector2 &p_offset);
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index a8c12f4893..a79c81e8bd 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -186,6 +186,17 @@ bool CollisionObject2D::get_collision_mask_value(int p_layer_number) const {
return get_collision_mask() & (1 << (p_layer_number - 1));
}
+void CollisionObject2D::set_collision_priority(real_t p_priority) {
+ collision_priority = p_priority;
+ if (!area) {
+ PhysicsServer2D::get_singleton()->body_set_collision_priority(get_rid(), p_priority);
+ }
+}
+
+real_t CollisionObject2D::get_collision_priority() const {
+ return collision_priority;
+}
+
void CollisionObject2D::set_disable_mode(DisableMode p_mode) {
if (disable_mode == p_mode) {
return;
@@ -350,8 +361,8 @@ void CollisionObject2D::get_shape_owners(List<uint32_t> *r_owners) {
}
}
-Array CollisionObject2D::_get_shape_owners() {
- Array ret;
+PackedInt32Array CollisionObject2D::_get_shape_owners() {
+ PackedInt32Array ret;
for (const KeyValue<uint32_t, ShapeData> &E : shapes) {
ret.push_back(E.key);
}
@@ -574,6 +585,8 @@ void CollisionObject2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &CollisionObject2D::get_collision_layer_value);
ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &CollisionObject2D::set_collision_mask_value);
ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &CollisionObject2D::get_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("set_collision_priority", "priority"), &CollisionObject2D::set_collision_priority);
+ ClassDB::bind_method(D_METHOD("get_collision_priority"), &CollisionObject2D::get_collision_priority);
ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &CollisionObject2D::set_disable_mode);
ClassDB::bind_method(D_METHOD("get_disable_mode"), &CollisionObject2D::get_disable_mode);
ClassDB::bind_method(D_METHOD("set_pickable", "enabled"), &CollisionObject2D::set_pickable);
@@ -599,6 +612,10 @@ void CollisionObject2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("shape_find_owner", "shape_index"), &CollisionObject2D::shape_find_owner);
GDVIRTUAL_BIND(_input_event, "viewport", "event", "shape_idx");
+ GDVIRTUAL_BIND(_mouse_enter);
+ GDVIRTUAL_BIND(_mouse_exit);
+ GDVIRTUAL_BIND(_mouse_shape_enter, "shape_idx");
+ GDVIRTUAL_BIND(_mouse_shape_exit, "shape_idx");
ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "viewport", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::INT, "shape_idx")));
ADD_SIGNAL(MethodInfo("mouse_entered"));
@@ -611,6 +628,7 @@ void CollisionObject2D::_bind_methods() {
ADD_GROUP("Collision", "collision_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_priority"), "set_collision_priority", "get_collision_priority");
ADD_GROUP("Input", "input_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_pickable"), "set_pickable", "is_pickable");
diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h
index 997afee6c4..48ea59e040 100644
--- a/scene/2d/collision_object_2d.h
+++ b/scene/2d/collision_object_2d.h
@@ -49,6 +49,7 @@ public:
private:
uint32_t collision_layer = 1;
uint32_t collision_mask = 1;
+ real_t collision_priority = 1.0;
bool area = false;
RID rid;
@@ -102,6 +103,10 @@ protected:
void set_body_mode(PhysicsServer2D::BodyMode p_mode);
GDVIRTUAL3(_input_event, Viewport *, Ref<InputEvent>, int)
+ GDVIRTUAL0(_mouse_enter)
+ GDVIRTUAL0(_mouse_exit)
+ GDVIRTUAL1(_mouse_shape_enter, int)
+ GDVIRTUAL1(_mouse_shape_exit, int)
public:
void set_collision_layer(uint32_t p_layer);
uint32_t get_collision_layer() const;
@@ -115,13 +120,16 @@ public:
void set_collision_mask_value(int p_layer_number, bool p_value);
bool get_collision_mask_value(int p_layer_number) const;
+ void set_collision_priority(real_t p_priority);
+ real_t get_collision_priority() const;
+
void set_disable_mode(DisableMode p_mode);
DisableMode get_disable_mode() const;
uint32_t create_shape_owner(Object *p_owner);
void remove_shape_owner(uint32_t owner);
void get_shape_owners(List<uint32_t> *r_owners);
- Array _get_shape_owners();
+ PackedInt32Array _get_shape_owners();
void shape_owner_set_transform(uint32_t p_owner, const Transform2D &p_transform);
Transform2D shape_owner_get_transform(uint32_t p_owner) const;
diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp
index 8df29851e5..04cd999982 100644
--- a/scene/2d/collision_polygon_2d.cpp
+++ b/scene/2d/collision_polygon_2d.cpp
@@ -239,7 +239,7 @@ TypedArray<String> CollisionPolygon2D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject2D>(get_parent())) {
- warnings.push_back(RTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidDynamicBody2D, CharacterBody2D, etc. to give them a shape."));
+ warnings.push_back(RTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, CharacterBody2D, etc. to give them a shape."));
}
int polygon_count = polygon.size();
diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index 9c0c26f6d9..cbecf28877 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -172,7 +172,7 @@ TypedArray<String> CollisionShape2D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject2D>(get_parent())) {
- warnings.push_back(RTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidDynamicBody2D, CharacterBody2D, etc. to give them a shape."));
+ warnings.push_back(RTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, CharacterBody2D, etc. to give them a shape."));
}
if (!shape.is_valid()) {
warnings.push_back(RTR("A shape must be provided for CollisionShape2D to function. Please create a shape resource for it!"));
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index 4155d0797f..1929475c8f 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -32,7 +32,7 @@
#include "core/core_string_names.h"
#include "scene/2d/gpu_particles_2d.h"
-#include "scene/resources/particles_material.h"
+#include "scene/resources/particle_process_material.h"
void CPUParticles2D::set_emitting(bool p_emitting) {
if (emitting == p_emitting) {
@@ -503,32 +503,32 @@ bool CPUParticles2D::get_split_scale() {
return split_scale;
}
-void CPUParticles2D::_validate_property(PropertyInfo &property) const {
- if (property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) {
- property.usage = PROPERTY_USAGE_NONE;
+void CPUParticles2D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "emission_rect_extents" && emission_shape != EMISSION_SHAPE_RECTANGLE) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "emission_rect_extents" && emission_shape != EMISSION_SHAPE_RECTANGLE) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) {
- property.usage = PROPERTY_USAGE_NONE;
+ if ((p_property.name == "emission_point_texture" || p_property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "emission_points" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "emission_points" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "emission_colors" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "emission_colors" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("scale_curve_") && !split_scale) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("scale_curve_") && !split_scale) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
@@ -745,12 +745,12 @@ void CPUParticles2D::_particles_process(double p_delta) {
p.start_color_rand = Color(1, 1, 1, 1);
}
- real_t angle1_rad = direction.angle() + Math::deg2rad((Math::randf() * 2.0 - 1.0) * spread);
+ real_t angle1_rad = direction.angle() + Math::deg_to_rad((Math::randf() * 2.0 - 1.0) * spread);
Vector2 rot = Vector2(Math::cos(angle1_rad), Math::sin(angle1_rad));
p.velocity = rot * Math::lerp(parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], parameters_max[PARAM_INITIAL_LINEAR_VELOCITY], (real_t)Math::randf());
real_t base_angle = tex_angle * Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand);
- p.rotation = Math::deg2rad(base_angle);
+ p.rotation = Math::deg_to_rad(base_angle);
p.custom[0] = 0.0; // unused
p.custom[1] = 0.0; // phase [0..1]
@@ -890,7 +890,7 @@ void CPUParticles2D::_particles_process(double p_delta) {
real_t orbit_amount = tex_orbit_velocity * Math::lerp(parameters_min[PARAM_ORBIT_VELOCITY], parameters_max[PARAM_ORBIT_VELOCITY], rand_from_seed(alt_seed));
if (orbit_amount != 0.0) {
real_t ang = orbit_amount * local_delta * Math_TAU;
- // Not sure why the ParticlesMaterial code uses a clockwise rotation matrix,
+ // Not sure why the ParticleProcessMaterial code uses a clockwise rotation matrix,
// but we use -ang here to reproduce its behavior.
Transform2D rot = Transform2D(-ang, Vector2());
p.transform[2] -= diff;
@@ -912,7 +912,7 @@ void CPUParticles2D::_particles_process(double p_delta) {
}
real_t base_angle = (tex_angle)*Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand);
base_angle += p.custom[1] * lifetime * tex_angular_velocity * Math::lerp(parameters_min[PARAM_ANGULAR_VELOCITY], parameters_max[PARAM_ANGULAR_VELOCITY], rand_from_seed(alt_seed));
- p.rotation = Math::deg2rad(base_angle); //angle
+ p.rotation = Math::deg_to_rad(base_angle); //angle
p.custom[2] = tex_anim_offset * Math::lerp(parameters_min[PARAM_ANIM_OFFSET], parameters_max[PARAM_ANIM_OFFSET], p.anim_offset_rand) + tv * tex_anim_speed * Math::lerp(parameters_min[PARAM_ANIM_SPEED], parameters_max[PARAM_ANIM_SPEED], rand_from_seed(alt_seed));
}
//apply color
@@ -1184,7 +1184,7 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) {
set_material(mat);
}
- Ref<ParticlesMaterial> material = particles->get_process_material();
+ Ref<ParticleProcessMaterial> material = particles->get_process_material();
if (material.is_null()) {
return;
}
@@ -1205,14 +1205,14 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) {
set_color_initial_ramp(gti->get_gradient());
}
- set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY));
+ set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, material->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY));
set_emission_shape(EmissionShape(material->get_emission_shape()));
set_emission_sphere_radius(material->get_emission_sphere_radius());
Vector2 rect_extents = Vector2(material->get_emission_box_extents().x, material->get_emission_box_extents().y);
set_emission_rect_extents(rect_extents);
- Ref<CurveXYZTexture> scale3D = material->get_param_texture(ParticlesMaterial::PARAM_SCALE);
+ Ref<CurveXYZTexture> scale3D = material->get_param_texture(ParticleProcessMaterial::PARAM_SCALE);
if (scale3D.is_valid()) {
split_scale = true;
scale_curve_x = scale3D->get_curve_x();
@@ -1222,14 +1222,14 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) {
set_gravity(gravity);
set_lifetime_randomness(material->get_lifetime_randomness());
-#define CONVERT_PARAM(m_param) \
- set_param_min(m_param, material->get_param_min(ParticlesMaterial::m_param)); \
- { \
- Ref<CurveTexture> ctex = material->get_param_texture(ParticlesMaterial::m_param); \
- if (ctex.is_valid()) \
- set_param_curve(m_param, ctex->get_curve()); \
- } \
- set_param_max(m_param, material->get_param_max(ParticlesMaterial::m_param));
+#define CONVERT_PARAM(m_param) \
+ set_param_min(m_param, material->get_param_min(ParticleProcessMaterial::m_param)); \
+ { \
+ Ref<CurveTexture> ctex = material->get_param_texture(ParticleProcessMaterial::m_param); \
+ if (ctex.is_valid()) \
+ set_param_curve(m_param, ctex->get_curve()); \
+ } \
+ set_param_max(m_param, material->get_param_max(ParticleProcessMaterial::m_param));
CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY);
CONVERT_PARAM(PARAM_ANGULAR_VELOCITY);
@@ -1470,7 +1470,7 @@ CPUParticles2D::CPUParticles2D() {
set_emitting(true);
set_amount(8);
- set_use_local_coordinates(true);
+ set_use_local_coordinates(false);
set_param_min(PARAM_INITIAL_LINEAR_VELOCITY, 0);
set_param_min(PARAM_ANGULAR_VELOCITY, 0);
diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h
index 51d58723b4..8f1671d280 100644
--- a/scene/2d/cpu_particles_2d.h
+++ b/scene/2d/cpu_particles_2d.h
@@ -193,7 +193,7 @@ private:
protected:
static void _bind_methods();
void _notification(int p_what);
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_emitting(bool p_emitting);
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index a869cf2525..65ead7afbc 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -30,7 +30,7 @@
#include "gpu_particles_2d.h"
-#include "scene/resources/particles_material.h"
+#include "scene/resources/particle_process_material.h"
#ifdef TOOLS_ENABLED
#include "core/config/engine.h"
@@ -123,10 +123,10 @@ void GPUParticles2D::_update_particle_emission_transform() {
void GPUParticles2D::set_process_material(const Ref<Material> &p_material) {
process_material = p_material;
- Ref<ParticlesMaterial> pm = p_material;
- if (pm.is_valid() && !pm->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_DISABLE_Z) && pm->get_gravity() == Vector3(0, -9.8, 0)) {
+ Ref<ParticleProcessMaterial> pm = p_material;
+ if (pm.is_valid() && !pm->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_DISABLE_Z) && pm->get_gravity() == Vector3(0, -9.8, 0)) {
// Likely a new (3D) material, modify it to match 2D space
- pm->set_particle_flag(ParticlesMaterial::PARTICLE_FLAG_DISABLE_Z, true);
+ pm->set_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_DISABLE_Z, true);
pm->set_gravity(Vector3(0, 98, 0));
}
RID material_rid;
@@ -308,10 +308,10 @@ TypedArray<String> GPUParticles2D::get_configuration_warnings() const {
CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr());
if (get_material().is_null() || (mat && !mat->get_particles_animation())) {
- const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr());
+ const ParticleProcessMaterial *process = Object::cast_to<ParticleProcessMaterial>(process_material.ptr());
if (process &&
- (process->get_param_max(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param_max(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
- process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
+ (process->get_param_max(ParticleProcessMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param_max(ParticleProcessMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
+ process->get_param_texture(ParticleProcessMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticleProcessMaterial::PARAM_ANIM_OFFSET).is_valid())) {
warnings.push_back(RTR("Particles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled."));
}
}
@@ -340,7 +340,7 @@ Ref<Texture2D> GPUParticles2D::get_texture() const {
return texture;
}
-void GPUParticles2D::_validate_property(PropertyInfo &property) const {
+void GPUParticles2D::_validate_property(PropertyInfo &p_property) const {
}
void GPUParticles2D::emit_particle(const Transform2D &p_transform2d, const Vector2 &p_velocity2d, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) {
@@ -625,7 +625,7 @@ void GPUParticles2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_sections", PROPERTY_HINT_RANGE, "2,128,1"), "set_trail_sections", "get_trail_sections");
ADD_PROPERTY(PropertyInfo(Variant::INT, "trail_section_subdivisions", PROPERTY_HINT_RANGE, "1,1024,1"), "set_trail_section_subdivisions", "get_trail_section_subdivisions");
ADD_GROUP("Process Material", "process_");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticleProcessMaterial"), "set_process_material", "get_process_material");
ADD_GROUP("Textures", "");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
@@ -660,7 +660,7 @@ GPUParticles2D::GPUParticles2D() {
set_explosiveness_ratio(0);
set_randomness_ratio(0);
set_visibility_rect(Rect2(Vector2(-100, -100), Vector2(200, 200)));
- set_use_local_coordinates(true);
+ set_use_local_coordinates(false);
set_draw_order(DRAW_ORDER_LIFETIME);
set_speed_scale(1);
set_fixed_fps(30);
diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h
index a4231cc45d..7eece32898 100644
--- a/scene/2d/gpu_particles_2d.h
+++ b/scene/2d/gpu_particles_2d.h
@@ -84,7 +84,7 @@ private:
protected:
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
void _update_collision_size();
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index 0481a58431..7eb6b43af7 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -227,9 +227,9 @@ real_t Light2D::get_shadow_smooth() const {
return shadow_smooth;
}
-void Light2D::_validate_property(PropertyInfo &property) const {
- if (!shadow && (property.name == "shadow_color" || property.name == "shadow_filter" || property.name == "shadow_filter_smooth" || property.name == "shadow_item_cull_mask")) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void Light2D::_validate_property(PropertyInfo &p_property) const {
+ if (!shadow && (p_property.name == "shadow_color" || p_property.name == "shadow_filter" || p_property.name == "shadow_filter_smooth" || p_property.name == "shadow_item_cull_mask")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h
index a84b6516c0..373cfe59fd 100644
--- a/scene/2d/light_2d.h
+++ b/scene/2d/light_2d.h
@@ -79,7 +79,7 @@ protected:
_FORCE_INLINE_ RID _get_light() const { return canvas_light; }
void _notification(int p_what);
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_enabled(bool p_enabled);
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index 06e5cbc97e..837f3061f1 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -346,13 +346,13 @@ void Line2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_points", "points"), &Line2D::set_points);
ClassDB::bind_method(D_METHOD("get_points"), &Line2D::get_points);
- ClassDB::bind_method(D_METHOD("set_point_position", "i", "position"), &Line2D::set_point_position);
- ClassDB::bind_method(D_METHOD("get_point_position", "i"), &Line2D::get_point_position);
+ ClassDB::bind_method(D_METHOD("set_point_position", "index", "position"), &Line2D::set_point_position);
+ ClassDB::bind_method(D_METHOD("get_point_position", "index"), &Line2D::get_point_position);
ClassDB::bind_method(D_METHOD("get_point_count"), &Line2D::get_point_count);
- ClassDB::bind_method(D_METHOD("add_point", "position", "at_position"), &Line2D::add_point, DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("remove_point", "i"), &Line2D::remove_point);
+ ClassDB::bind_method(D_METHOD("add_point", "position", "index"), &Line2D::add_point, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("remove_point", "index"), &Line2D::remove_point);
ClassDB::bind_method(D_METHOD("clear_points"), &Line2D::clear_points);
diff --git a/scene/2d/position_2d.cpp b/scene/2d/marker_2d.cpp
index cfa4d0401e..ba1d2ffbfd 100644
--- a/scene/2d/position_2d.cpp
+++ b/scene/2d/marker_2d.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* position_2d.cpp */
+/* marker_2d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,9 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "position_2d.h"
+#include "marker_2d.h"
-void Position2D::_draw_cross() {
+void Marker2D::_draw_cross() {
const real_t extents = get_gizmo_extents();
// Add more points to create a "hard stop" in the color gradient.
@@ -50,7 +50,7 @@ void Position2D::_draw_cross() {
// Use the axis color which is brighter for the positive axis.
// Use a darkened axis color for the negative axis.
- // This makes it possible to see in which direction the Position3D node is rotated
+ // This makes it possible to see in which direction the Marker3D node is rotated
// (which can be important depending on how it's used).
// Axis colors are taken from `axis_x_color` and `axis_y_color` (defined in `editor/editor_themes.cpp`).
const Color color_x = Color(0.96, 0.20, 0.32);
@@ -73,17 +73,17 @@ void Position2D::_draw_cross() {
}
#ifdef TOOLS_ENABLED
-Rect2 Position2D::_edit_get_rect() const {
+Rect2 Marker2D::_edit_get_rect() const {
real_t extents = get_gizmo_extents();
return Rect2(Point2(-extents, -extents), Size2(extents * 2, extents * 2));
}
-bool Position2D::_edit_use_rect() const {
+bool Marker2D::_edit_use_rect() const {
return false;
}
#endif
-void Position2D::_notification(int p_what) {
+void Marker2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
update();
@@ -100,21 +100,21 @@ void Position2D::_notification(int p_what) {
}
}
-void Position2D::set_gizmo_extents(real_t p_extents) {
+void Marker2D::set_gizmo_extents(real_t p_extents) {
gizmo_extents = p_extents;
update();
}
-real_t Position2D::get_gizmo_extents() const {
+real_t Marker2D::get_gizmo_extents() const {
return gizmo_extents;
}
-void Position2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_gizmo_extents", "extents"), &Position2D::set_gizmo_extents);
- ClassDB::bind_method(D_METHOD("get_gizmo_extents"), &Position2D::get_gizmo_extents);
+void Marker2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_gizmo_extents", "extents"), &Marker2D::set_gizmo_extents);
+ ClassDB::bind_method(D_METHOD("get_gizmo_extents"), &Marker2D::get_gizmo_extents);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gizmo_extents", PROPERTY_HINT_RANGE, "0,1000,0.1,or_greater,suffix:px"), "set_gizmo_extents", "get_gizmo_extents");
}
-Position2D::Position2D() {
+Marker2D::Marker2D() {
}
diff --git a/scene/2d/position_2d.h b/scene/2d/marker_2d.h
index 99b0266130..e287018dfc 100644
--- a/scene/2d/position_2d.h
+++ b/scene/2d/marker_2d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* position_2d.h */
+/* marker_2d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef POSITION_2D_H
-#define POSITION_2D_H
+#ifndef MARKER_2D_H
+#define MARKER_2D_H
#include "scene/2d/node_2d.h"
-class Position2D : public Node2D {
- GDCLASS(Position2D, Node2D);
+class Marker2D : public Node2D {
+ GDCLASS(Marker2D, Node2D);
real_t gizmo_extents = 10.0;
@@ -53,7 +53,7 @@ public:
void set_gizmo_extents(real_t p_extents);
real_t get_gizmo_extents() const;
- Position2D();
+ Marker2D();
};
-#endif // POSITION_2D_H
+#endif // MARKER_2D_H
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp
index a5f7faffef..d7f75c63a4 100644
--- a/scene/2d/navigation_agent_2d.cpp
+++ b/scene/2d/navigation_agent_2d.cpp
@@ -49,8 +49,8 @@ void NavigationAgent2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &NavigationAgent2D::set_radius);
ClassDB::bind_method(D_METHOD("get_radius"), &NavigationAgent2D::get_radius);
- ClassDB::bind_method(D_METHOD("set_neighbor_dist", "neighbor_dist"), &NavigationAgent2D::set_neighbor_dist);
- ClassDB::bind_method(D_METHOD("get_neighbor_dist"), &NavigationAgent2D::get_neighbor_dist);
+ ClassDB::bind_method(D_METHOD("set_neighbor_distance", "neighbor_distance"), &NavigationAgent2D::set_neighbor_distance);
+ ClassDB::bind_method(D_METHOD("get_neighbor_distance"), &NavigationAgent2D::get_neighbor_distance);
ClassDB::bind_method(D_METHOD("set_max_neighbors", "max_neighbors"), &NavigationAgent2D::set_max_neighbors);
ClassDB::bind_method(D_METHOD("get_max_neighbors"), &NavigationAgent2D::get_max_neighbors);
@@ -96,7 +96,7 @@ void NavigationAgent2D::_bind_methods() {
ADD_GROUP("Avoidance", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.1,500,0.01,suffix:px"), "set_radius", "get_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "neighbor_dist", PROPERTY_HINT_RANGE, "0.1,100000,0.01,suffix:px"), "set_neighbor_dist", "get_neighbor_dist");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "neighbor_distance", PROPERTY_HINT_RANGE, "0.1,100000,0.01,suffix:px"), "set_neighbor_distance", "get_neighbor_distance");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_neighbors", PROPERTY_HINT_RANGE, "1,10000,1"), "set_max_neighbors", "get_max_neighbors");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_horizon", PROPERTY_HINT_RANGE, "0.1,10000,0.01,suffix:s"), "set_time_horizon", "get_time_horizon");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_speed", PROPERTY_HINT_RANGE, "0.1,100000,0.01,suffix:px/s"), "set_max_speed", "get_max_speed");
@@ -173,7 +173,7 @@ void NavigationAgent2D::_notification(int p_what) {
NavigationAgent2D::NavigationAgent2D() {
agent = NavigationServer2D::get_singleton()->agent_create();
- set_neighbor_dist(500.0);
+ set_neighbor_distance(500.0);
set_max_neighbors(10);
set_time_horizon(20.0);
set_radius(10.0);
@@ -275,9 +275,9 @@ void NavigationAgent2D::set_radius(real_t p_radius) {
NavigationServer2D::get_singleton()->agent_set_radius(agent, radius);
}
-void NavigationAgent2D::set_neighbor_dist(real_t p_dist) {
- neighbor_dist = p_dist;
- NavigationServer2D::get_singleton()->agent_set_neighbor_dist(agent, neighbor_dist);
+void NavigationAgent2D::set_neighbor_distance(real_t p_distance) {
+ neighbor_distance = p_distance;
+ NavigationServer2D::get_singleton()->agent_set_neighbor_distance(agent, neighbor_distance);
}
void NavigationAgent2D::set_max_neighbors(int p_count) {
diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h
index 76eba20058..11b845665d 100644
--- a/scene/2d/navigation_agent_2d.h
+++ b/scene/2d/navigation_agent_2d.h
@@ -50,7 +50,7 @@ class NavigationAgent2D : public Node {
real_t path_desired_distance = 1.0;
real_t target_desired_distance = 1.0;
real_t radius = 0.0;
- real_t neighbor_dist = 0.0;
+ real_t neighbor_distance = 0.0;
int max_neighbors = 0;
real_t time_horizon = 0.0;
real_t max_speed = 0.0;
@@ -110,9 +110,9 @@ public:
return radius;
}
- void set_neighbor_dist(real_t p_dist);
- real_t get_neighbor_dist() const {
- return neighbor_dist;
+ void set_neighbor_distance(real_t p_distance);
+ real_t get_neighbor_distance() const {
+ return neighbor_distance;
}
void set_max_neighbors(int p_count);
diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp
index 0320c6c917..a592d20cba 100644
--- a/scene/2d/navigation_obstacle_2d.cpp
+++ b/scene/2d/navigation_obstacle_2d.cpp
@@ -127,7 +127,7 @@ TypedArray<String> NavigationObstacle2D::get_configuration_warnings() const {
}
if (Object::cast_to<StaticBody2D>(get_parent())) {
- warnings.push_back(RTR("The NavigationObstacle2D is intended for constantly moving bodies like CharacterBody2D or RigidDynamicBody2D as it creates only an RVO avoidance radius and does not follow scene geometry exactly."
+ warnings.push_back(RTR("The NavigationObstacle2D is intended for constantly moving bodies like CharacterBody2D or RigidBody2D as it creates only an RVO avoidance radius and does not follow scene geometry exactly."
"\nNot constantly moving or complete static objects should be captured with a refreshed NavigationPolygon so agents can not only avoid them but also move along those objects outline at high detail"));
}
@@ -135,7 +135,7 @@ TypedArray<String> NavigationObstacle2D::get_configuration_warnings() const {
}
void NavigationObstacle2D::initialize_agent() {
- NavigationServer2D::get_singleton()->agent_set_neighbor_dist(agent, 0.0);
+ NavigationServer2D::get_singleton()->agent_set_neighbor_distance(agent, 0.0);
NavigationServer2D::get_singleton()->agent_set_max_neighbors(agent, 0);
NavigationServer2D::get_singleton()->agent_set_time_horizon(agent, 0.0);
NavigationServer2D::get_singleton()->agent_set_max_speed(agent, 0.0);
diff --git a/scene/2d/navigation_obstacle_2d.h b/scene/2d/navigation_obstacle_2d.h
index afda05956a..5795c6c94f 100644
--- a/scene/2d/navigation_obstacle_2d.h
+++ b/scene/2d/navigation_obstacle_2d.h
@@ -46,7 +46,7 @@ class NavigationObstacle2D : public Node {
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &p_property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
public:
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index 6f189a57e8..00aa4b0b59 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -422,7 +422,7 @@ real_t NavigationRegion2D::get_enter_cost() const {
void NavigationRegion2D::set_travel_cost(real_t p_travel_cost) {
ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive.");
travel_cost = MAX(p_travel_cost, 0.0);
- NavigationServer2D::get_singleton()->region_set_enter_cost(region, travel_cost);
+ NavigationServer2D::get_singleton()->region_set_travel_cost(region, travel_cost);
}
real_t NavigationRegion2D::get_travel_cost() const {
@@ -494,7 +494,7 @@ void NavigationRegion2D::_notification(int p_what) {
// Generate the polygon color, slightly randomly modified from the settings one.
Color random_variation_color;
- random_variation_color.set_hsv(color.get_h() + rand.random(-1.0, 1.0) * 0.05, color.get_s(), color.get_v() + rand.random(-1.0, 1.0) * 0.1);
+ random_variation_color.set_hsv(color.get_h() + rand.random(-1.0, 1.0) * 0.1, color.get_s(), color.get_v() + rand.random(-1.0, 1.0) * 0.2);
random_variation_color.a = color.a;
Vector<Color> colors;
colors.push_back(random_variation_color);
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index 9862c4bfb1..bbc326a4b4 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -175,10 +175,10 @@ void PathFollow2D::_update_transform() {
if (path_length == 0) {
return;
}
- Vector2 pos = c->interpolate_baked(offset, cubic);
+ Vector2 pos = c->interpolate_baked(progress, cubic);
if (rotates) {
- real_t ahead = offset + lookahead;
+ real_t ahead = progress + lookahead;
if (loop && ahead >= path_length) {
// If our lookahead will loop, we need to check if the path is closed.
@@ -202,7 +202,7 @@ void PathFollow2D::_update_transform() {
// This will happen at the end of non-looping or non-closed paths.
// We'll try a look behind instead, in order to get a meaningful angle.
tangent_to_curve =
- (pos - c->interpolate_baked(offset - lookahead, cubic)).normalized();
+ (pos - c->interpolate_baked(progress - lookahead, cubic)).normalized();
} else {
tangent_to_curve = (ahead_pos - pos).normalized();
}
@@ -245,14 +245,14 @@ bool PathFollow2D::get_cubic_interpolation() const {
return cubic;
}
-void PathFollow2D::_validate_property(PropertyInfo &property) const {
- if (property.name == "offset") {
+void PathFollow2D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "offset") {
real_t max = 10000.0;
if (path && path->get_curve().is_valid()) {
max = path->get_curve()->get_baked_length();
}
- property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater";
+ p_property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater";
}
}
@@ -269,8 +269,8 @@ TypedArray<String> PathFollow2D::get_configuration_warnings() const {
}
void PathFollow2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_offset", "offset"), &PathFollow2D::set_offset);
- ClassDB::bind_method(D_METHOD("get_offset"), &PathFollow2D::get_offset);
+ ClassDB::bind_method(D_METHOD("set_progress", "progress"), &PathFollow2D::set_progress);
+ ClassDB::bind_method(D_METHOD("get_progress"), &PathFollow2D::get_progress);
ClassDB::bind_method(D_METHOD("set_h_offset", "h_offset"), &PathFollow2D::set_h_offset);
ClassDB::bind_method(D_METHOD("get_h_offset"), &PathFollow2D::get_h_offset);
@@ -278,8 +278,8 @@ void PathFollow2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_v_offset", "v_offset"), &PathFollow2D::set_v_offset);
ClassDB::bind_method(D_METHOD("get_v_offset"), &PathFollow2D::get_v_offset);
- ClassDB::bind_method(D_METHOD("set_unit_offset", "unit_offset"), &PathFollow2D::set_unit_offset);
- ClassDB::bind_method(D_METHOD("get_unit_offset"), &PathFollow2D::get_unit_offset);
+ ClassDB::bind_method(D_METHOD("set_progress_ratio", "ratio"), &PathFollow2D::set_progress_ratio);
+ ClassDB::bind_method(D_METHOD("get_progress_ratio"), &PathFollow2D::get_progress_ratio);
ClassDB::bind_method(D_METHOD("set_rotates", "enable"), &PathFollow2D::set_rotates);
ClassDB::bind_method(D_METHOD("is_rotating"), &PathFollow2D::is_rotating);
@@ -293,8 +293,8 @@ void PathFollow2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_lookahead", "lookahead"), &PathFollow2D::set_lookahead);
ClassDB::bind_method(D_METHOD("get_lookahead"), &PathFollow2D::get_lookahead);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser,or_greater,suffix:px"), "set_offset", "get_offset");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser,or_greater,suffix:px"), "set_progress", "get_progress");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_progress_ratio", "get_progress_ratio");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset"), "set_h_offset", "get_h_offset");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_offset"), "set_v_offset", "get_v_offset");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotates"), "set_rotates", "is_rotating");
@@ -303,20 +303,20 @@ void PathFollow2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lookahead", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001"), "set_lookahead", "get_lookahead");
}
-void PathFollow2D::set_offset(real_t p_offset) {
- ERR_FAIL_COND(!isfinite(p_offset));
- offset = p_offset;
+void PathFollow2D::set_progress(real_t p_progress) {
+ ERR_FAIL_COND(!isfinite(p_progress));
+ progress = p_progress;
if (path) {
if (path->get_curve().is_valid()) {
real_t path_length = path->get_curve()->get_baked_length();
if (loop && path_length) {
- offset = Math::fposmod(offset, path_length);
- if (!Math::is_zero_approx(p_offset) && Math::is_zero_approx(offset)) {
- offset = path_length;
+ progress = Math::fposmod(progress, path_length);
+ if (!Math::is_zero_approx(p_progress) && Math::is_zero_approx(progress)) {
+ progress = path_length;
}
} else {
- offset = CLAMP(offset, 0, path_length);
+ progress = CLAMP(progress, 0, path_length);
}
}
@@ -346,19 +346,19 @@ real_t PathFollow2D::get_v_offset() const {
return v_offset;
}
-real_t PathFollow2D::get_offset() const {
- return offset;
+real_t PathFollow2D::get_progress() const {
+ return progress;
}
-void PathFollow2D::set_unit_offset(real_t p_unit_offset) {
+void PathFollow2D::set_progress_ratio(real_t p_ratio) {
if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) {
- set_offset(p_unit_offset * path->get_curve()->get_baked_length());
+ set_progress(p_ratio * path->get_curve()->get_baked_length());
}
}
-real_t PathFollow2D::get_unit_offset() const {
+real_t PathFollow2D::get_progress_ratio() const {
if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) {
- return get_offset() / path->get_curve()->get_baked_length();
+ return get_progress() / path->get_curve()->get_baked_length();
} else {
return 0;
}
diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h
index bc55f84831..3d66ca1fab 100644
--- a/scene/2d/path_2d.h
+++ b/scene/2d/path_2d.h
@@ -65,7 +65,7 @@ class PathFollow2D : public Node2D {
public:
private:
Path2D *path = nullptr;
- real_t offset = 0.0;
+ real_t progress = 0.0;
real_t h_offset = 0.0;
real_t v_offset = 0.0;
real_t lookahead = 4.0;
@@ -76,14 +76,14 @@ private:
void _update_transform();
protected:
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
static void _bind_methods();
public:
- void set_offset(real_t p_offset);
- real_t get_offset() const;
+ void set_progress(real_t p_progress);
+ real_t get_progress() const;
void set_h_offset(real_t p_h_offset);
real_t get_h_offset() const;
@@ -91,8 +91,8 @@ public:
void set_v_offset(real_t p_v_offset);
real_t get_v_offset() const;
- void set_unit_offset(real_t p_unit_offset);
- real_t get_unit_offset() const;
+ void set_progress_ratio(real_t p_ratio);
+ real_t get_progress_ratio() const;
void set_lookahead(real_t p_lookahead);
real_t get_lookahead() const;
diff --git a/scene/2d/physical_bone_2d.cpp b/scene/2d/physical_bone_2d.cpp
index 2999736d64..e6933b8a40 100644
--- a/scene/2d/physical_bone_2d.cpp
+++ b/scene/2d/physical_bone_2d.cpp
@@ -35,7 +35,7 @@
void PhysicalBone2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
- // Position the RigidDynamicBody in the correct position.
+ // Position the RigidBody in the correct position.
if (follow_bone_when_simulating) {
_position_at_bone2d();
}
@@ -158,6 +158,7 @@ void PhysicalBone2D::_start_physics_simulation() {
// Apply the layers and masks.
PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
+ PhysicsServer2D::get_singleton()->body_set_collision_priority(get_rid(), get_collision_priority());
// Apply the correct mode.
_apply_body_mode();
@@ -176,6 +177,7 @@ void PhysicalBone2D::_stop_physics_simulation() {
set_physics_process_internal(false);
PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), 0);
PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), 0);
+ PhysicsServer2D::get_singleton()->body_set_collision_priority(get_rid(), 1.0);
PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_STATIC);
}
}
@@ -285,7 +287,7 @@ void PhysicalBone2D::_bind_methods() {
}
PhysicalBone2D::PhysicalBone2D() {
- // Stop the RigidDynamicBody from executing its force integration.
+ // Stop the RigidBody from executing its force integration.
PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), 0);
PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), 0);
PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_STATIC);
diff --git a/scene/2d/physical_bone_2d.h b/scene/2d/physical_bone_2d.h
index 22d329c320..9fbfa04100 100644
--- a/scene/2d/physical_bone_2d.h
+++ b/scene/2d/physical_bone_2d.h
@@ -36,8 +36,8 @@
class Joint2D;
-class PhysicalBone2D : public RigidDynamicBody2D {
- GDCLASS(PhysicalBone2D, RigidDynamicBody2D);
+class PhysicalBone2D : public RigidBody2D {
+ GDCLASS(PhysicalBone2D, RigidBody2D);
protected:
void _notification(int p_what);
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index ce22f32b01..43158344b4 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -325,7 +325,7 @@ AnimatableBody2D::AnimatableBody2D() :
StaticBody2D(PhysicsServer2D::BODY_MODE_KINEMATIC) {
}
-void RigidDynamicBody2D::_body_enter_tree(ObjectID p_id) {
+void RigidBody2D::_body_enter_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
@@ -347,7 +347,7 @@ void RigidDynamicBody2D::_body_enter_tree(ObjectID p_id) {
contact_monitor->locked = false;
}
-void RigidDynamicBody2D::_body_exit_tree(ObjectID p_id) {
+void RigidBody2D::_body_exit_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
@@ -368,7 +368,7 @@ void RigidDynamicBody2D::_body_exit_tree(ObjectID p_id) {
contact_monitor->locked = false;
}
-void RigidDynamicBody2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape) {
+void RigidBody2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape) {
bool body_in = p_status == 1;
ObjectID objid = p_instance;
@@ -387,8 +387,8 @@ void RigidDynamicBody2D::_body_inout(int p_status, const RID &p_body, ObjectID p
//E->value.rc=0;
E->value.in_scene = node && node->is_inside_tree();
if (node) {
- node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidDynamicBody2D::_body_enter_tree).bind(objid));
- node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidDynamicBody2D::_body_exit_tree).bind(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody2D::_body_enter_tree).bind(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody2D::_body_exit_tree).bind(objid));
if (E->value.in_scene) {
emit_signal(SceneStringNames::get_singleton()->body_entered, node);
}
@@ -416,8 +416,8 @@ void RigidDynamicBody2D::_body_inout(int p_status, const RID &p_body, ObjectID p
if (E->value.shapes.is_empty()) {
if (node) {
- node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidDynamicBody2D::_body_enter_tree));
- node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidDynamicBody2D::_body_exit_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody2D::_body_enter_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody2D::_body_exit_tree));
if (in_scene) {
emit_signal(SceneStringNames::get_singleton()->body_exited, node);
}
@@ -431,19 +431,19 @@ void RigidDynamicBody2D::_body_inout(int p_status, const RID &p_body, ObjectID p
}
}
-struct _RigidDynamicBody2DInOut {
+struct _RigidBody2DInOut {
RID rid;
ObjectID id;
int shape = 0;
int local_shape = 0;
};
-void RigidDynamicBody2D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state) {
- RigidDynamicBody2D *body = static_cast<RigidDynamicBody2D *>(p_instance);
+void RigidBody2D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState2D *p_state) {
+ RigidBody2D *body = static_cast<RigidBody2D *>(p_instance);
body->_body_state_changed(p_state);
}
-void RigidDynamicBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) {
+void RigidBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) {
set_block_transform_notify(true); // don't want notify (would feedback loop)
if (!freeze || freeze_mode != FREEZE_MODE_KINEMATIC) {
set_global_transform(p_state->get_transform());
@@ -473,9 +473,9 @@ void RigidDynamicBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state)
}
}
- _RigidDynamicBody2DInOut *toadd = (_RigidDynamicBody2DInOut *)alloca(p_state->get_contact_count() * sizeof(_RigidDynamicBody2DInOut));
+ _RigidBody2DInOut *toadd = (_RigidBody2DInOut *)alloca(p_state->get_contact_count() * sizeof(_RigidBody2DInOut));
int toadd_count = 0; //state->get_contact_count();
- RigidDynamicBody2D_RemoveAction *toremove = (RigidDynamicBody2D_RemoveAction *)alloca(rc * sizeof(RigidDynamicBody2D_RemoveAction));
+ RigidBody2D_RemoveAction *toremove = (RigidBody2D_RemoveAction *)alloca(rc * sizeof(RigidBody2D_RemoveAction));
int toremove_count = 0;
//put the ones to add
@@ -539,7 +539,7 @@ void RigidDynamicBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state)
}
}
-void RigidDynamicBody2D::_apply_body_mode() {
+void RigidBody2D::_apply_body_mode() {
if (freeze) {
switch (freeze_mode) {
case FREEZE_MODE_STATIC: {
@@ -550,13 +550,13 @@ void RigidDynamicBody2D::_apply_body_mode() {
} break;
}
} else if (lock_rotation) {
- set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC_LINEAR);
+ set_body_mode(PhysicsServer2D::BODY_MODE_RIGID_LINEAR);
} else {
- set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC);
+ set_body_mode(PhysicsServer2D::BODY_MODE_RIGID);
}
}
-void RigidDynamicBody2D::set_lock_rotation_enabled(bool p_lock_rotation) {
+void RigidBody2D::set_lock_rotation_enabled(bool p_lock_rotation) {
if (p_lock_rotation == lock_rotation) {
return;
}
@@ -565,11 +565,11 @@ void RigidDynamicBody2D::set_lock_rotation_enabled(bool p_lock_rotation) {
_apply_body_mode();
}
-bool RigidDynamicBody2D::is_lock_rotation_enabled() const {
+bool RigidBody2D::is_lock_rotation_enabled() const {
return lock_rotation;
}
-void RigidDynamicBody2D::set_freeze_enabled(bool p_freeze) {
+void RigidBody2D::set_freeze_enabled(bool p_freeze) {
if (p_freeze == freeze) {
return;
}
@@ -578,11 +578,11 @@ void RigidDynamicBody2D::set_freeze_enabled(bool p_freeze) {
_apply_body_mode();
}
-bool RigidDynamicBody2D::is_freeze_enabled() const {
+bool RigidBody2D::is_freeze_enabled() const {
return freeze;
}
-void RigidDynamicBody2D::set_freeze_mode(FreezeMode p_freeze_mode) {
+void RigidBody2D::set_freeze_mode(FreezeMode p_freeze_mode) {
if (p_freeze_mode == freeze_mode) {
return;
}
@@ -591,31 +591,31 @@ void RigidDynamicBody2D::set_freeze_mode(FreezeMode p_freeze_mode) {
_apply_body_mode();
}
-RigidDynamicBody2D::FreezeMode RigidDynamicBody2D::get_freeze_mode() const {
+RigidBody2D::FreezeMode RigidBody2D::get_freeze_mode() const {
return freeze_mode;
}
-void RigidDynamicBody2D::set_mass(real_t p_mass) {
+void RigidBody2D::set_mass(real_t p_mass) {
ERR_FAIL_COND(p_mass <= 0);
mass = p_mass;
PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_MASS, mass);
}
-real_t RigidDynamicBody2D::get_mass() const {
+real_t RigidBody2D::get_mass() const {
return mass;
}
-void RigidDynamicBody2D::set_inertia(real_t p_inertia) {
+void RigidBody2D::set_inertia(real_t p_inertia) {
ERR_FAIL_COND(p_inertia < 0);
inertia = p_inertia;
PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_INERTIA, inertia);
}
-real_t RigidDynamicBody2D::get_inertia() const {
+real_t RigidBody2D::get_inertia() const {
return inertia;
}
-void RigidDynamicBody2D::set_center_of_mass_mode(CenterOfMassMode p_mode) {
+void RigidBody2D::set_center_of_mass_mode(CenterOfMassMode p_mode) {
if (center_of_mass_mode == p_mode) {
return;
}
@@ -637,11 +637,11 @@ void RigidDynamicBody2D::set_center_of_mass_mode(CenterOfMassMode p_mode) {
}
}
-RigidDynamicBody2D::CenterOfMassMode RigidDynamicBody2D::get_center_of_mass_mode() const {
+RigidBody2D::CenterOfMassMode RigidBody2D::get_center_of_mass_mode() const {
return center_of_mass_mode;
}
-void RigidDynamicBody2D::set_center_of_mass(const Vector2 &p_center_of_mass) {
+void RigidBody2D::set_center_of_mass(const Vector2 &p_center_of_mass) {
if (center_of_mass == p_center_of_mass) {
return;
}
@@ -652,102 +652,102 @@ void RigidDynamicBody2D::set_center_of_mass(const Vector2 &p_center_of_mass) {
PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_CENTER_OF_MASS, center_of_mass);
}
-const Vector2 &RigidDynamicBody2D::get_center_of_mass() const {
+const Vector2 &RigidBody2D::get_center_of_mass() const {
return center_of_mass;
}
-void RigidDynamicBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
+void RigidBody2D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
if (physics_material_override.is_valid()) {
- if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidDynamicBody2D::_reload_physics_characteristics))) {
- physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidDynamicBody2D::_reload_physics_characteristics));
+ if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody2D::_reload_physics_characteristics))) {
+ physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody2D::_reload_physics_characteristics));
}
}
physics_material_override = p_physics_material_override;
if (physics_material_override.is_valid()) {
- physics_material_override->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidDynamicBody2D::_reload_physics_characteristics));
+ physics_material_override->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody2D::_reload_physics_characteristics));
}
_reload_physics_characteristics();
}
-Ref<PhysicsMaterial> RigidDynamicBody2D::get_physics_material_override() const {
+Ref<PhysicsMaterial> RigidBody2D::get_physics_material_override() const {
return physics_material_override;
}
-void RigidDynamicBody2D::set_gravity_scale(real_t p_gravity_scale) {
+void RigidBody2D::set_gravity_scale(real_t p_gravity_scale) {
gravity_scale = p_gravity_scale;
PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_GRAVITY_SCALE, gravity_scale);
}
-real_t RigidDynamicBody2D::get_gravity_scale() const {
+real_t RigidBody2D::get_gravity_scale() const {
return gravity_scale;
}
-void RigidDynamicBody2D::set_linear_damp_mode(DampMode p_mode) {
+void RigidBody2D::set_linear_damp_mode(DampMode p_mode) {
linear_damp_mode = p_mode;
PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_LINEAR_DAMP_MODE, linear_damp_mode);
}
-RigidDynamicBody2D::DampMode RigidDynamicBody2D::get_linear_damp_mode() const {
+RigidBody2D::DampMode RigidBody2D::get_linear_damp_mode() const {
return linear_damp_mode;
}
-void RigidDynamicBody2D::set_angular_damp_mode(DampMode p_mode) {
+void RigidBody2D::set_angular_damp_mode(DampMode p_mode) {
angular_damp_mode = p_mode;
PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_ANGULAR_DAMP_MODE, angular_damp_mode);
}
-RigidDynamicBody2D::DampMode RigidDynamicBody2D::get_angular_damp_mode() const {
+RigidBody2D::DampMode RigidBody2D::get_angular_damp_mode() const {
return angular_damp_mode;
}
-void RigidDynamicBody2D::set_linear_damp(real_t p_linear_damp) {
+void RigidBody2D::set_linear_damp(real_t p_linear_damp) {
ERR_FAIL_COND(p_linear_damp < -1);
linear_damp = p_linear_damp;
PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_LINEAR_DAMP, linear_damp);
}
-real_t RigidDynamicBody2D::get_linear_damp() const {
+real_t RigidBody2D::get_linear_damp() const {
return linear_damp;
}
-void RigidDynamicBody2D::set_angular_damp(real_t p_angular_damp) {
+void RigidBody2D::set_angular_damp(real_t p_angular_damp) {
ERR_FAIL_COND(p_angular_damp < -1);
angular_damp = p_angular_damp;
PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_ANGULAR_DAMP, angular_damp);
}
-real_t RigidDynamicBody2D::get_angular_damp() const {
+real_t RigidBody2D::get_angular_damp() const {
return angular_damp;
}
-void RigidDynamicBody2D::set_axis_velocity(const Vector2 &p_axis) {
+void RigidBody2D::set_axis_velocity(const Vector2 &p_axis) {
Vector2 axis = p_axis.normalized();
linear_velocity -= axis * axis.dot(linear_velocity);
linear_velocity += p_axis;
PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
}
-void RigidDynamicBody2D::set_linear_velocity(const Vector2 &p_velocity) {
+void RigidBody2D::set_linear_velocity(const Vector2 &p_velocity) {
linear_velocity = p_velocity;
PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
}
-Vector2 RigidDynamicBody2D::get_linear_velocity() const {
+Vector2 RigidBody2D::get_linear_velocity() const {
return linear_velocity;
}
-void RigidDynamicBody2D::set_angular_velocity(real_t p_velocity) {
+void RigidBody2D::set_angular_velocity(real_t p_velocity) {
angular_velocity = p_velocity;
PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity);
}
-real_t RigidDynamicBody2D::get_angular_velocity() const {
+real_t RigidBody2D::get_angular_velocity() const {
return angular_velocity;
}
-void RigidDynamicBody2D::set_use_custom_integrator(bool p_enable) {
+void RigidBody2D::set_use_custom_integrator(bool p_enable) {
if (custom_integrator == p_enable) {
return;
}
@@ -756,100 +756,106 @@ void RigidDynamicBody2D::set_use_custom_integrator(bool p_enable) {
PhysicsServer2D::get_singleton()->body_set_omit_force_integration(get_rid(), p_enable);
}
-bool RigidDynamicBody2D::is_using_custom_integrator() {
+bool RigidBody2D::is_using_custom_integrator() {
return custom_integrator;
}
-void RigidDynamicBody2D::set_sleeping(bool p_sleeping) {
+void RigidBody2D::set_sleeping(bool p_sleeping) {
sleeping = p_sleeping;
PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_SLEEPING, sleeping);
}
-void RigidDynamicBody2D::set_can_sleep(bool p_active) {
+void RigidBody2D::set_can_sleep(bool p_active) {
can_sleep = p_active;
PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_CAN_SLEEP, p_active);
}
-bool RigidDynamicBody2D::is_able_to_sleep() const {
+bool RigidBody2D::is_able_to_sleep() const {
return can_sleep;
}
-bool RigidDynamicBody2D::is_sleeping() const {
+bool RigidBody2D::is_sleeping() const {
return sleeping;
}
-void RigidDynamicBody2D::set_max_contacts_reported(int p_amount) {
+void RigidBody2D::set_max_contacts_reported(int p_amount) {
max_contacts_reported = p_amount;
PhysicsServer2D::get_singleton()->body_set_max_contacts_reported(get_rid(), p_amount);
}
-int RigidDynamicBody2D::get_max_contacts_reported() const {
+int RigidBody2D::get_max_contacts_reported() const {
return max_contacts_reported;
}
-void RigidDynamicBody2D::apply_central_impulse(const Vector2 &p_impulse) {
+int RigidBody2D::get_contact_count() const {
+ PhysicsDirectBodyState2D *bs = PhysicsServer2D::get_singleton()->body_get_direct_state(get_rid());
+ ERR_FAIL_NULL_V(bs, 0);
+ return bs->get_contact_count();
+}
+
+void RigidBody2D::apply_central_impulse(const Vector2 &p_impulse) {
PhysicsServer2D::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse);
}
-void RigidDynamicBody2D::apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position) {
+void RigidBody2D::apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position) {
PhysicsServer2D::get_singleton()->body_apply_impulse(get_rid(), p_impulse, p_position);
}
-void RigidDynamicBody2D::apply_torque_impulse(real_t p_torque) {
+void RigidBody2D::apply_torque_impulse(real_t p_torque) {
PhysicsServer2D::get_singleton()->body_apply_torque_impulse(get_rid(), p_torque);
}
-void RigidDynamicBody2D::apply_central_force(const Vector2 &p_force) {
+void RigidBody2D::apply_central_force(const Vector2 &p_force) {
PhysicsServer2D::get_singleton()->body_apply_central_force(get_rid(), p_force);
}
-void RigidDynamicBody2D::apply_force(const Vector2 &p_force, const Vector2 &p_position) {
+void RigidBody2D::apply_force(const Vector2 &p_force, const Vector2 &p_position) {
PhysicsServer2D::get_singleton()->body_apply_force(get_rid(), p_force, p_position);
}
-void RigidDynamicBody2D::apply_torque(real_t p_torque) {
+void RigidBody2D::apply_torque(real_t p_torque) {
PhysicsServer2D::get_singleton()->body_apply_torque(get_rid(), p_torque);
}
-void RigidDynamicBody2D::add_constant_central_force(const Vector2 &p_force) {
+void RigidBody2D::add_constant_central_force(const Vector2 &p_force) {
PhysicsServer2D::get_singleton()->body_add_constant_central_force(get_rid(), p_force);
}
-void RigidDynamicBody2D::add_constant_force(const Vector2 &p_force, const Vector2 &p_position) {
+void RigidBody2D::add_constant_force(const Vector2 &p_force, const Vector2 &p_position) {
PhysicsServer2D::get_singleton()->body_add_constant_force(get_rid(), p_force, p_position);
}
-void RigidDynamicBody2D::add_constant_torque(const real_t p_torque) {
+void RigidBody2D::add_constant_torque(const real_t p_torque) {
PhysicsServer2D::get_singleton()->body_add_constant_torque(get_rid(), p_torque);
}
-void RigidDynamicBody2D::set_constant_force(const Vector2 &p_force) {
+void RigidBody2D::set_constant_force(const Vector2 &p_force) {
PhysicsServer2D::get_singleton()->body_set_constant_force(get_rid(), p_force);
}
-Vector2 RigidDynamicBody2D::get_constant_force() const {
+Vector2 RigidBody2D::get_constant_force() const {
return PhysicsServer2D::get_singleton()->body_get_constant_force(get_rid());
}
-void RigidDynamicBody2D::set_constant_torque(real_t p_torque) {
+void RigidBody2D::set_constant_torque(real_t p_torque) {
PhysicsServer2D::get_singleton()->body_set_constant_torque(get_rid(), p_torque);
}
-real_t RigidDynamicBody2D::get_constant_torque() const {
+real_t RigidBody2D::get_constant_torque() const {
return PhysicsServer2D::get_singleton()->body_get_constant_torque(get_rid());
}
-void RigidDynamicBody2D::set_continuous_collision_detection_mode(CCDMode p_mode) {
+void RigidBody2D::set_continuous_collision_detection_mode(CCDMode p_mode) {
ccd_mode = p_mode;
PhysicsServer2D::get_singleton()->body_set_continuous_collision_detection_mode(get_rid(), PhysicsServer2D::CCDMode(p_mode));
}
-RigidDynamicBody2D::CCDMode RigidDynamicBody2D::get_continuous_collision_detection_mode() const {
+RigidBody2D::CCDMode RigidBody2D::get_continuous_collision_detection_mode() const {
return ccd_mode;
}
-TypedArray<Node2D> RigidDynamicBody2D::get_colliding_bodies() const {
- ERR_FAIL_COND_V(!contact_monitor, Array());
+TypedArray<Node2D> RigidBody2D::get_colliding_bodies() const {
+ ERR_FAIL_COND_V(!contact_monitor, TypedArray<Node2D>());
TypedArray<Node2D> ret;
ret.resize(contact_monitor->body_map.size());
@@ -866,7 +872,7 @@ TypedArray<Node2D> RigidDynamicBody2D::get_colliding_bodies() const {
return ret;
}
-void RigidDynamicBody2D::set_contact_monitor(bool p_enabled) {
+void RigidBody2D::set_contact_monitor(bool p_enabled) {
if (p_enabled == is_contact_monitor_enabled()) {
return;
}
@@ -880,8 +886,8 @@ void RigidDynamicBody2D::set_contact_monitor(bool p_enabled) {
Node *node = Object::cast_to<Node>(obj);
if (node) {
- node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidDynamicBody2D::_body_enter_tree));
- node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidDynamicBody2D::_body_exit_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody2D::_body_enter_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody2D::_body_exit_tree));
}
}
@@ -893,11 +899,11 @@ void RigidDynamicBody2D::set_contact_monitor(bool p_enabled) {
}
}
-bool RigidDynamicBody2D::is_contact_monitor_enabled() const {
+bool RigidBody2D::is_contact_monitor_enabled() const {
return contact_monitor != nullptr;
}
-void RigidDynamicBody2D::_notification(int p_what) {
+void RigidBody2D::_notification(int p_what) {
#ifdef TOOLS_ENABLED
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -915,102 +921,103 @@ void RigidDynamicBody2D::_notification(int p_what) {
#endif
}
-TypedArray<String> RigidDynamicBody2D::get_configuration_warnings() const {
+TypedArray<String> RigidBody2D::get_configuration_warnings() const {
Transform2D t = get_transform();
TypedArray<String> warnings = CollisionObject2D::get_configuration_warnings();
if (ABS(t.columns[0].length() - 1.0) > 0.05 || ABS(t.columns[1].length() - 1.0) > 0.05) {
- warnings.push_back(RTR("Size changes to RigidDynamicBody2D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
+ warnings.push_back(RTR("Size changes to RigidBody2D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
}
return warnings;
}
-void RigidDynamicBody2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_mass", "mass"), &RigidDynamicBody2D::set_mass);
- ClassDB::bind_method(D_METHOD("get_mass"), &RigidDynamicBody2D::get_mass);
+void RigidBody2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_mass", "mass"), &RigidBody2D::set_mass);
+ ClassDB::bind_method(D_METHOD("get_mass"), &RigidBody2D::get_mass);
- ClassDB::bind_method(D_METHOD("get_inertia"), &RigidDynamicBody2D::get_inertia);
- ClassDB::bind_method(D_METHOD("set_inertia", "inertia"), &RigidDynamicBody2D::set_inertia);
+ ClassDB::bind_method(D_METHOD("get_inertia"), &RigidBody2D::get_inertia);
+ ClassDB::bind_method(D_METHOD("set_inertia", "inertia"), &RigidBody2D::set_inertia);
- ClassDB::bind_method(D_METHOD("set_center_of_mass_mode", "mode"), &RigidDynamicBody2D::set_center_of_mass_mode);
- ClassDB::bind_method(D_METHOD("get_center_of_mass_mode"), &RigidDynamicBody2D::get_center_of_mass_mode);
+ ClassDB::bind_method(D_METHOD("set_center_of_mass_mode", "mode"), &RigidBody2D::set_center_of_mass_mode);
+ ClassDB::bind_method(D_METHOD("get_center_of_mass_mode"), &RigidBody2D::get_center_of_mass_mode);
- ClassDB::bind_method(D_METHOD("set_center_of_mass", "center_of_mass"), &RigidDynamicBody2D::set_center_of_mass);
- ClassDB::bind_method(D_METHOD("get_center_of_mass"), &RigidDynamicBody2D::get_center_of_mass);
+ ClassDB::bind_method(D_METHOD("set_center_of_mass", "center_of_mass"), &RigidBody2D::set_center_of_mass);
+ ClassDB::bind_method(D_METHOD("get_center_of_mass"), &RigidBody2D::get_center_of_mass);
- ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidDynamicBody2D::set_physics_material_override);
- ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidDynamicBody2D::get_physics_material_override);
+ ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody2D::set_physics_material_override);
+ ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody2D::get_physics_material_override);
- ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidDynamicBody2D::set_gravity_scale);
- ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidDynamicBody2D::get_gravity_scale);
+ ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidBody2D::set_gravity_scale);
+ ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidBody2D::get_gravity_scale);
- ClassDB::bind_method(D_METHOD("set_linear_damp_mode", "linear_damp_mode"), &RigidDynamicBody2D::set_linear_damp_mode);
- ClassDB::bind_method(D_METHOD("get_linear_damp_mode"), &RigidDynamicBody2D::get_linear_damp_mode);
+ ClassDB::bind_method(D_METHOD("set_linear_damp_mode", "linear_damp_mode"), &RigidBody2D::set_linear_damp_mode);
+ ClassDB::bind_method(D_METHOD("get_linear_damp_mode"), &RigidBody2D::get_linear_damp_mode);
- ClassDB::bind_method(D_METHOD("set_angular_damp_mode", "angular_damp_mode"), &RigidDynamicBody2D::set_angular_damp_mode);
- ClassDB::bind_method(D_METHOD("get_angular_damp_mode"), &RigidDynamicBody2D::get_angular_damp_mode);
+ ClassDB::bind_method(D_METHOD("set_angular_damp_mode", "angular_damp_mode"), &RigidBody2D::set_angular_damp_mode);
+ ClassDB::bind_method(D_METHOD("get_angular_damp_mode"), &RigidBody2D::get_angular_damp_mode);
- ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &RigidDynamicBody2D::set_linear_damp);
- ClassDB::bind_method(D_METHOD("get_linear_damp"), &RigidDynamicBody2D::get_linear_damp);
+ ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &RigidBody2D::set_linear_damp);
+ ClassDB::bind_method(D_METHOD("get_linear_damp"), &RigidBody2D::get_linear_damp);
- ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &RigidDynamicBody2D::set_angular_damp);
- ClassDB::bind_method(D_METHOD("get_angular_damp"), &RigidDynamicBody2D::get_angular_damp);
+ ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &RigidBody2D::set_angular_damp);
+ ClassDB::bind_method(D_METHOD("get_angular_damp"), &RigidBody2D::get_angular_damp);
- ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidDynamicBody2D::set_linear_velocity);
- ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidDynamicBody2D::get_linear_velocity);
+ ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidBody2D::set_linear_velocity);
+ ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidBody2D::get_linear_velocity);
- ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &RigidDynamicBody2D::set_angular_velocity);
- ClassDB::bind_method(D_METHOD("get_angular_velocity"), &RigidDynamicBody2D::get_angular_velocity);
+ ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &RigidBody2D::set_angular_velocity);
+ ClassDB::bind_method(D_METHOD("get_angular_velocity"), &RigidBody2D::get_angular_velocity);
- ClassDB::bind_method(D_METHOD("set_max_contacts_reported", "amount"), &RigidDynamicBody2D::set_max_contacts_reported);
- ClassDB::bind_method(D_METHOD("get_max_contacts_reported"), &RigidDynamicBody2D::get_max_contacts_reported);
+ ClassDB::bind_method(D_METHOD("set_max_contacts_reported", "amount"), &RigidBody2D::set_max_contacts_reported);
+ ClassDB::bind_method(D_METHOD("get_max_contacts_reported"), &RigidBody2D::get_max_contacts_reported);
+ ClassDB::bind_method(D_METHOD("get_contact_count"), &RigidBody2D::get_contact_count);
- ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &RigidDynamicBody2D::set_use_custom_integrator);
- ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &RigidDynamicBody2D::is_using_custom_integrator);
+ ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &RigidBody2D::set_use_custom_integrator);
+ ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &RigidBody2D::is_using_custom_integrator);
- ClassDB::bind_method(D_METHOD("set_contact_monitor", "enabled"), &RigidDynamicBody2D::set_contact_monitor);
- ClassDB::bind_method(D_METHOD("is_contact_monitor_enabled"), &RigidDynamicBody2D::is_contact_monitor_enabled);
+ ClassDB::bind_method(D_METHOD("set_contact_monitor", "enabled"), &RigidBody2D::set_contact_monitor);
+ ClassDB::bind_method(D_METHOD("is_contact_monitor_enabled"), &RigidBody2D::is_contact_monitor_enabled);
- ClassDB::bind_method(D_METHOD("set_continuous_collision_detection_mode", "mode"), &RigidDynamicBody2D::set_continuous_collision_detection_mode);
- ClassDB::bind_method(D_METHOD("get_continuous_collision_detection_mode"), &RigidDynamicBody2D::get_continuous_collision_detection_mode);
+ ClassDB::bind_method(D_METHOD("set_continuous_collision_detection_mode", "mode"), &RigidBody2D::set_continuous_collision_detection_mode);
+ ClassDB::bind_method(D_METHOD("get_continuous_collision_detection_mode"), &RigidBody2D::get_continuous_collision_detection_mode);
- ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidDynamicBody2D::set_axis_velocity);
- ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidDynamicBody2D::apply_central_impulse, Vector2());
- ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &RigidDynamicBody2D::apply_impulse, Vector2());
- ClassDB::bind_method(D_METHOD("apply_torque_impulse", "torque"), &RigidDynamicBody2D::apply_torque_impulse);
+ ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidBody2D::set_axis_velocity);
+ ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidBody2D::apply_central_impulse, Vector2());
+ ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &RigidBody2D::apply_impulse, Vector2());
+ ClassDB::bind_method(D_METHOD("apply_torque_impulse", "torque"), &RigidBody2D::apply_torque_impulse);
- ClassDB::bind_method(D_METHOD("apply_central_force", "force"), &RigidDynamicBody2D::apply_central_force);
- ClassDB::bind_method(D_METHOD("apply_force", "force", "position"), &RigidDynamicBody2D::apply_force, Vector2());
- ClassDB::bind_method(D_METHOD("apply_torque", "torque"), &RigidDynamicBody2D::apply_torque);
+ ClassDB::bind_method(D_METHOD("apply_central_force", "force"), &RigidBody2D::apply_central_force);
+ ClassDB::bind_method(D_METHOD("apply_force", "force", "position"), &RigidBody2D::apply_force, Vector2());
+ ClassDB::bind_method(D_METHOD("apply_torque", "torque"), &RigidBody2D::apply_torque);
- ClassDB::bind_method(D_METHOD("add_constant_central_force", "force"), &RigidDynamicBody2D::add_constant_central_force);
- ClassDB::bind_method(D_METHOD("add_constant_force", "force", "position"), &RigidDynamicBody2D::add_constant_force, Vector2());
- ClassDB::bind_method(D_METHOD("add_constant_torque", "torque"), &RigidDynamicBody2D::add_constant_torque);
+ ClassDB::bind_method(D_METHOD("add_constant_central_force", "force"), &RigidBody2D::add_constant_central_force);
+ ClassDB::bind_method(D_METHOD("add_constant_force", "force", "position"), &RigidBody2D::add_constant_force, Vector2());
+ ClassDB::bind_method(D_METHOD("add_constant_torque", "torque"), &RigidBody2D::add_constant_torque);
- ClassDB::bind_method(D_METHOD("set_constant_force", "force"), &RigidDynamicBody2D::set_constant_force);
- ClassDB::bind_method(D_METHOD("get_constant_force"), &RigidDynamicBody2D::get_constant_force);
+ ClassDB::bind_method(D_METHOD("set_constant_force", "force"), &RigidBody2D::set_constant_force);
+ ClassDB::bind_method(D_METHOD("get_constant_force"), &RigidBody2D::get_constant_force);
- ClassDB::bind_method(D_METHOD("set_constant_torque", "torque"), &RigidDynamicBody2D::set_constant_torque);
- ClassDB::bind_method(D_METHOD("get_constant_torque"), &RigidDynamicBody2D::get_constant_torque);
+ ClassDB::bind_method(D_METHOD("set_constant_torque", "torque"), &RigidBody2D::set_constant_torque);
+ ClassDB::bind_method(D_METHOD("get_constant_torque"), &RigidBody2D::get_constant_torque);
- ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidDynamicBody2D::set_sleeping);
- ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidDynamicBody2D::is_sleeping);
+ ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidBody2D::set_sleeping);
+ ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidBody2D::is_sleeping);
- ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidDynamicBody2D::set_can_sleep);
- ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidDynamicBody2D::is_able_to_sleep);
+ ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidBody2D::set_can_sleep);
+ ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidBody2D::is_able_to_sleep);
- ClassDB::bind_method(D_METHOD("set_lock_rotation_enabled", "lock_rotation"), &RigidDynamicBody2D::set_lock_rotation_enabled);
- ClassDB::bind_method(D_METHOD("is_lock_rotation_enabled"), &RigidDynamicBody2D::is_lock_rotation_enabled);
+ ClassDB::bind_method(D_METHOD("set_lock_rotation_enabled", "lock_rotation"), &RigidBody2D::set_lock_rotation_enabled);
+ ClassDB::bind_method(D_METHOD("is_lock_rotation_enabled"), &RigidBody2D::is_lock_rotation_enabled);
- ClassDB::bind_method(D_METHOD("set_freeze_enabled", "freeze_mode"), &RigidDynamicBody2D::set_freeze_enabled);
- ClassDB::bind_method(D_METHOD("is_freeze_enabled"), &RigidDynamicBody2D::is_freeze_enabled);
+ ClassDB::bind_method(D_METHOD("set_freeze_enabled", "freeze_mode"), &RigidBody2D::set_freeze_enabled);
+ ClassDB::bind_method(D_METHOD("is_freeze_enabled"), &RigidBody2D::is_freeze_enabled);
- ClassDB::bind_method(D_METHOD("set_freeze_mode", "freeze_mode"), &RigidDynamicBody2D::set_freeze_mode);
- ClassDB::bind_method(D_METHOD("get_freeze_mode"), &RigidDynamicBody2D::get_freeze_mode);
+ ClassDB::bind_method(D_METHOD("set_freeze_mode", "freeze_mode"), &RigidBody2D::set_freeze_mode);
+ ClassDB::bind_method(D_METHOD("get_freeze_mode"), &RigidBody2D::get_freeze_mode);
- ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidDynamicBody2D::get_colliding_bodies);
+ ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody2D::get_colliding_bodies);
GDVIRTUAL_BIND(_integrate_forces, "state");
@@ -1023,7 +1030,7 @@ void RigidDynamicBody2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator");
ADD_PROPERTY(PropertyInfo(Variant::INT, "continuous_cd", PROPERTY_HINT_ENUM, "Disabled,Cast Ray,Cast Shape"), "set_continuous_collision_detection_mode", "get_continuous_collision_detection_mode");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "contacts_reported", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), "set_max_contacts_reported", "get_max_contacts_reported");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_contacts_reported", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), "set_max_contacts_reported", "get_max_contacts_reported");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "contact_monitor"), "set_contact_monitor", "is_contact_monitor_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleeping", "is_sleeping");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep");
@@ -1062,26 +1069,26 @@ void RigidDynamicBody2D::_bind_methods() {
BIND_ENUM_CONSTANT(CCD_MODE_CAST_SHAPE);
}
-void RigidDynamicBody2D::_validate_property(PropertyInfo &property) const {
+void RigidBody2D::_validate_property(PropertyInfo &p_property) const {
if (center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM) {
- if (property.name == "center_of_mass") {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name == "center_of_mass") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
}
-RigidDynamicBody2D::RigidDynamicBody2D() :
- PhysicsBody2D(PhysicsServer2D::BODY_MODE_DYNAMIC) {
+RigidBody2D::RigidBody2D() :
+ PhysicsBody2D(PhysicsServer2D::BODY_MODE_RIGID) {
PhysicsServer2D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
}
-RigidDynamicBody2D::~RigidDynamicBody2D() {
+RigidBody2D::~RigidBody2D() {
if (contact_monitor) {
memdelete(contact_monitor);
}
}
-void RigidDynamicBody2D::_reload_physics_characteristics() {
+void RigidBody2D::_reload_physics_characteristics() {
if (physics_material_override.is_null()) {
PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, 0);
PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_FRICTION, 1);
@@ -1107,9 +1114,9 @@ bool CharacterBody2D::move_and_slide() {
if ((on_floor || on_wall) && platform_rid.is_valid()) {
bool excluded = false;
if (on_floor) {
- excluded = (moving_platform_floor_layers & platform_layer) == 0;
+ excluded = (platform_floor_layers & platform_layer) == 0;
} else if (on_wall) {
- excluded = (moving_platform_wall_layers & platform_layer) == 0;
+ excluded = (platform_wall_layers & platform_layer) == 0;
}
if (!excluded) {
//this approach makes sure there is less delay between the actual body velocity and the one we saved
@@ -1159,10 +1166,10 @@ bool CharacterBody2D::move_and_slide() {
// Compute real velocity.
real_velocity = get_position_delta() / delta;
- if (moving_platform_apply_velocity_on_leave != PLATFORM_VEL_ON_LEAVE_NEVER) {
+ if (platform_on_leave != PLATFORM_ON_LEAVE_DO_NOTHING) {
// Add last platform velocity when just left a moving platform.
if (!on_floor && !on_wall) {
- if (moving_platform_apply_velocity_on_leave == PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY && current_platform_velocity.dot(up_direction) < 0) {
+ if (platform_on_leave == PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY && current_platform_velocity.dot(up_direction) < 0) {
current_platform_velocity = current_platform_velocity.slide(up_direction);
}
velocity += current_platform_velocity;
@@ -1606,20 +1613,20 @@ void CharacterBody2D::set_slide_on_ceiling_enabled(bool p_enabled) {
slide_on_ceiling = p_enabled;
}
-uint32_t CharacterBody2D::get_moving_platform_floor_layers() const {
- return moving_platform_floor_layers;
+uint32_t CharacterBody2D::get_platform_floor_layers() const {
+ return platform_floor_layers;
}
-void CharacterBody2D::set_moving_platform_floor_layers(uint32_t p_exclude_layers) {
- moving_platform_floor_layers = p_exclude_layers;
+void CharacterBody2D::set_platform_floor_layers(uint32_t p_exclude_layers) {
+ platform_floor_layers = p_exclude_layers;
}
-uint32_t CharacterBody2D::get_moving_platform_wall_layers() const {
- return moving_platform_wall_layers;
+uint32_t CharacterBody2D::get_platform_wall_layers() const {
+ return platform_wall_layers;
}
-void CharacterBody2D::set_moving_platform_wall_layers(uint32_t p_exclude_layers) {
- moving_platform_wall_layers = p_exclude_layers;
+void CharacterBody2D::set_platform_wall_layers(uint32_t p_exclude_layers) {
+ platform_wall_layers = p_exclude_layers;
}
void CharacterBody2D::set_motion_mode(MotionMode p_mode) {
@@ -1630,12 +1637,12 @@ CharacterBody2D::MotionMode CharacterBody2D::get_motion_mode() const {
return motion_mode;
}
-void CharacterBody2D::set_moving_platform_apply_velocity_on_leave(MovingPlatformApplyVelocityOnLeave p_on_leave_apply_velocity) {
- moving_platform_apply_velocity_on_leave = p_on_leave_apply_velocity;
+void CharacterBody2D::set_platform_on_leave(PlatformOnLeave p_on_leave_apply_velocity) {
+ platform_on_leave = p_on_leave_apply_velocity;
}
-CharacterBody2D::MovingPlatformApplyVelocityOnLeave CharacterBody2D::get_moving_platform_apply_velocity_on_leave() const {
- return moving_platform_apply_velocity_on_leave;
+CharacterBody2D::PlatformOnLeave CharacterBody2D::get_platform_on_leave() const {
+ return platform_on_leave;
}
int CharacterBody2D::get_max_slides() const {
@@ -1702,7 +1709,7 @@ void CharacterBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &CharacterBody2D::set_velocity);
ClassDB::bind_method(D_METHOD("get_velocity"), &CharacterBody2D::get_velocity);
- ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &CharacterBody2D::set_safe_margin);
+ ClassDB::bind_method(D_METHOD("set_safe_margin", "margin"), &CharacterBody2D::set_safe_margin);
ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody2D::get_safe_margin);
ClassDB::bind_method(D_METHOD("is_floor_stop_on_slope_enabled"), &CharacterBody2D::is_floor_stop_on_slope_enabled);
ClassDB::bind_method(D_METHOD("set_floor_stop_on_slope_enabled", "enabled"), &CharacterBody2D::set_floor_stop_on_slope_enabled);
@@ -1713,10 +1720,10 @@ void CharacterBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_slide_on_ceiling_enabled", "enabled"), &CharacterBody2D::set_slide_on_ceiling_enabled);
ClassDB::bind_method(D_METHOD("is_slide_on_ceiling_enabled"), &CharacterBody2D::is_slide_on_ceiling_enabled);
- ClassDB::bind_method(D_METHOD("set_moving_platform_floor_layers", "exclude_layer"), &CharacterBody2D::set_moving_platform_floor_layers);
- ClassDB::bind_method(D_METHOD("get_moving_platform_floor_layers"), &CharacterBody2D::get_moving_platform_floor_layers);
- ClassDB::bind_method(D_METHOD("set_moving_platform_wall_layers", "exclude_layer"), &CharacterBody2D::set_moving_platform_wall_layers);
- ClassDB::bind_method(D_METHOD("get_moving_platform_wall_layers"), &CharacterBody2D::get_moving_platform_wall_layers);
+ ClassDB::bind_method(D_METHOD("set_platform_floor_layers", "exclude_layer"), &CharacterBody2D::set_platform_floor_layers);
+ ClassDB::bind_method(D_METHOD("get_platform_floor_layers"), &CharacterBody2D::get_platform_floor_layers);
+ ClassDB::bind_method(D_METHOD("set_platform_wall_layers", "exclude_layer"), &CharacterBody2D::set_platform_wall_layers);
+ ClassDB::bind_method(D_METHOD("get_platform_wall_layers"), &CharacterBody2D::get_platform_wall_layers);
ClassDB::bind_method(D_METHOD("get_max_slides"), &CharacterBody2D::get_max_slides);
ClassDB::bind_method(D_METHOD("set_max_slides", "max_slides"), &CharacterBody2D::set_max_slides);
@@ -1730,8 +1737,8 @@ void CharacterBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_up_direction", "up_direction"), &CharacterBody2D::set_up_direction);
ClassDB::bind_method(D_METHOD("set_motion_mode", "mode"), &CharacterBody2D::set_motion_mode);
ClassDB::bind_method(D_METHOD("get_motion_mode"), &CharacterBody2D::get_motion_mode);
- ClassDB::bind_method(D_METHOD("set_moving_platform_apply_velocity_on_leave", "on_leave_apply_velocity"), &CharacterBody2D::set_moving_platform_apply_velocity_on_leave);
- ClassDB::bind_method(D_METHOD("get_moving_platform_apply_velocity_on_leave"), &CharacterBody2D::get_moving_platform_apply_velocity_on_leave);
+ ClassDB::bind_method(D_METHOD("set_platform_on_leave", "on_leave_apply_velocity"), &CharacterBody2D::set_platform_on_leave);
+ ClassDB::bind_method(D_METHOD("get_platform_on_leave"), &CharacterBody2D::get_platform_on_leave);
ClassDB::bind_method(D_METHOD("is_on_floor"), &CharacterBody2D::is_on_floor);
ClassDB::bind_method(D_METHOD("is_on_floor_only"), &CharacterBody2D::is_on_floor_only);
@@ -1756,34 +1763,38 @@ void CharacterBody2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slide_on_ceiling"), "set_slide_on_ceiling_enabled", "is_slide_on_ceiling_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_slides", "get_max_slides");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wall_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians", PROPERTY_USAGE_DEFAULT), "set_wall_min_slide_angle", "get_wall_min_slide_angle");
+
ADD_GROUP("Floor", "floor_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_stop_on_slope"), "set_floor_stop_on_slope_enabled", "is_floor_stop_on_slope_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_constant_speed"), "set_floor_constant_speed_enabled", "is_floor_constant_speed_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_block_on_wall"), "set_floor_block_on_wall_enabled", "is_floor_block_on_wall_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians"), "set_floor_max_angle", "get_floor_max_angle");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_snap_length", PROPERTY_HINT_RANGE, "0,32,0.1,or_greater,suffix:px"), "set_floor_snap_length", "get_floor_snap_length");
- ADD_GROUP("Moving Platform", "moving_platform");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_apply_velocity_on_leave", PROPERTY_HINT_ENUM, "Always,Upward Only,Never", PROPERTY_USAGE_DEFAULT), "set_moving_platform_apply_velocity_on_leave", "get_moving_platform_apply_velocity_on_leave");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_floor_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_floor_layers", "get_moving_platform_floor_layers");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_wall_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_wall_layers", "get_moving_platform_wall_layers");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001,suffix:px"), "set_safe_margin", "get_safe_margin");
+
+ ADD_GROUP("Moving Platform", "platform");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_on_leave", PROPERTY_HINT_ENUM, "Add Velocity,Add Upward Velocity,Do Nothing", PROPERTY_USAGE_DEFAULT), "set_platform_on_leave", "get_platform_on_leave");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_floor_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_platform_floor_layers", "get_platform_floor_layers");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_wall_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_platform_wall_layers", "get_platform_wall_layers");
+
+ ADD_GROUP("Collision", "");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001,suffix:px"), "set_safe_margin", "get_safe_margin");
BIND_ENUM_CONSTANT(MOTION_MODE_GROUNDED);
BIND_ENUM_CONSTANT(MOTION_MODE_FLOATING);
- BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_ALWAYS);
- BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY);
- BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_NEVER);
+ BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_ADD_VELOCITY);
+ BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY);
+ BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_DO_NOTHING);
}
-void CharacterBody2D::_validate_property(PropertyInfo &property) const {
+void CharacterBody2D::_validate_property(PropertyInfo &p_property) const {
if (motion_mode == MOTION_MODE_FLOATING) {
- if (property.name.begins_with("floor_") || property.name == "up_direction" || property.name == "slide_on_ceiling") {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name.begins_with("floor_") || p_property.name == "up_direction" || p_property.name == "slide_on_ceiling") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
} else {
- if (property.name == "wall_min_slide_angle") {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name == "wall_min_slide_angle") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
}
@@ -1823,6 +1834,10 @@ real_t KinematicCollision2D::get_angle(const Vector2 &p_up_direction) const {
return result.get_angle(p_up_direction);
}
+real_t KinematicCollision2D::get_depth() const {
+ return result.collision_depth;
+}
+
Object *KinematicCollision2D::get_local_shape() const {
if (!owner) {
return nullptr;
@@ -1874,6 +1889,7 @@ void KinematicCollision2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_travel"), &KinematicCollision2D::get_travel);
ClassDB::bind_method(D_METHOD("get_remainder"), &KinematicCollision2D::get_remainder);
ClassDB::bind_method(D_METHOD("get_angle", "up_direction"), &KinematicCollision2D::get_angle, DEFVAL(Vector2(0.0, -1.0)));
+ ClassDB::bind_method(D_METHOD("get_depth"), &KinematicCollision2D::get_depth);
ClassDB::bind_method(D_METHOD("get_local_shape"), &KinematicCollision2D::get_local_shape);
ClassDB::bind_method(D_METHOD("get_collider"), &KinematicCollision2D::get_collider);
ClassDB::bind_method(D_METHOD("get_collider_id"), &KinematicCollision2D::get_collider_id);
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 7401fc7578..eaba9aadad 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -113,8 +113,8 @@ private:
bool is_sync_to_physics_enabled() const;
};
-class RigidDynamicBody2D : public PhysicsBody2D {
- GDCLASS(RigidDynamicBody2D, PhysicsBody2D);
+class RigidBody2D : public PhysicsBody2D {
+ GDCLASS(RigidBody2D, PhysicsBody2D);
public:
enum FreezeMode {
@@ -186,7 +186,7 @@ private:
local_shape = p_ls;
}
};
- struct RigidDynamicBody2D_RemoveAction {
+ struct RigidBody2D_RemoveAction {
RID rid;
ObjectID body_id;
ShapePair pair;
@@ -216,7 +216,7 @@ protected:
void _notification(int p_what);
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState2D *)
@@ -284,6 +284,7 @@ public:
void set_max_contacts_reported(int p_amount);
int get_max_contacts_reported() const;
+ int get_contact_count() const;
void set_continuous_collision_detection_mode(CCDMode p_mode);
CCDMode get_continuous_collision_detection_mode() const;
@@ -310,17 +311,17 @@ public:
virtual TypedArray<String> get_configuration_warnings() const override;
- RigidDynamicBody2D();
- ~RigidDynamicBody2D();
+ RigidBody2D();
+ ~RigidBody2D();
private:
void _reload_physics_characteristics();
};
-VARIANT_ENUM_CAST(RigidDynamicBody2D::FreezeMode);
-VARIANT_ENUM_CAST(RigidDynamicBody2D::CenterOfMassMode);
-VARIANT_ENUM_CAST(RigidDynamicBody2D::DampMode);
-VARIANT_ENUM_CAST(RigidDynamicBody2D::CCDMode);
+VARIANT_ENUM_CAST(RigidBody2D::FreezeMode);
+VARIANT_ENUM_CAST(RigidBody2D::CenterOfMassMode);
+VARIANT_ENUM_CAST(RigidBody2D::DampMode);
+VARIANT_ENUM_CAST(RigidBody2D::CCDMode);
class CharacterBody2D : public PhysicsBody2D {
GDCLASS(CharacterBody2D, PhysicsBody2D);
@@ -330,10 +331,10 @@ public:
MOTION_MODE_GROUNDED,
MOTION_MODE_FLOATING,
};
- enum MovingPlatformApplyVelocityOnLeave {
- PLATFORM_VEL_ON_LEAVE_ALWAYS,
- PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY,
- PLATFORM_VEL_ON_LEAVE_NEVER,
+ enum PlatformOnLeave {
+ PLATFORM_ON_LEAVE_ADD_VELOCITY,
+ PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY,
+ PLATFORM_ON_LEAVE_DO_NOTHING,
};
bool move_and_slide();
@@ -364,7 +365,7 @@ public:
private:
real_t margin = 0.08;
MotionMode motion_mode = MOTION_MODE_GROUNDED;
- MovingPlatformApplyVelocityOnLeave moving_platform_apply_velocity_on_leave = PLATFORM_VEL_ON_LEAVE_ALWAYS;
+ PlatformOnLeave platform_on_leave = PLATFORM_ON_LEAVE_ADD_VELOCITY;
bool floor_constant_speed = false;
bool floor_stop_on_slope = true;
@@ -372,12 +373,12 @@ private:
bool slide_on_ceiling = true;
int max_slides = 4;
int platform_layer = 0;
- real_t floor_max_angle = Math::deg2rad((real_t)45.0);
+ real_t floor_max_angle = Math::deg_to_rad((real_t)45.0);
real_t floor_snap_length = 1;
- real_t wall_min_slide_angle = Math::deg2rad((real_t)15.0);
+ real_t wall_min_slide_angle = Math::deg_to_rad((real_t)15.0);
Vector2 up_direction = Vector2(0.0, -1.0);
- uint32_t moving_platform_floor_layers = UINT32_MAX;
- uint32_t moving_platform_wall_layers = 0;
+ uint32_t platform_floor_layers = UINT32_MAX;
+ uint32_t platform_wall_layers = 0;
Vector2 velocity;
Vector2 floor_normal;
@@ -423,17 +424,17 @@ private:
real_t get_wall_min_slide_angle() const;
void set_wall_min_slide_angle(real_t p_radians);
- uint32_t get_moving_platform_floor_layers() const;
- void set_moving_platform_floor_layers(const uint32_t p_exclude_layer);
+ uint32_t get_platform_floor_layers() const;
+ void set_platform_floor_layers(const uint32_t p_exclude_layer);
- uint32_t get_moving_platform_wall_layers() const;
- void set_moving_platform_wall_layers(const uint32_t p_exclude_layer);
+ uint32_t get_platform_wall_layers() const;
+ void set_platform_wall_layers(const uint32_t p_exclude_layer);
void set_motion_mode(MotionMode p_mode);
MotionMode get_motion_mode() const;
- void set_moving_platform_apply_velocity_on_leave(MovingPlatformApplyVelocityOnLeave p_on_leave_velocity);
- MovingPlatformApplyVelocityOnLeave get_moving_platform_apply_velocity_on_leave() const;
+ void set_platform_on_leave(PlatformOnLeave p_on_leave_velocity);
+ PlatformOnLeave get_platform_on_leave() const;
void _move_and_slide_floating(double p_delta);
void _move_and_slide_grounded(double p_delta, bool p_was_on_floor);
@@ -450,11 +451,11 @@ private:
protected:
void _notification(int p_what);
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
};
VARIANT_ENUM_CAST(CharacterBody2D::MotionMode);
-VARIANT_ENUM_CAST(CharacterBody2D::MovingPlatformApplyVelocityOnLeave);
+VARIANT_ENUM_CAST(CharacterBody2D::PlatformOnLeave);
class KinematicCollision2D : public RefCounted {
GDCLASS(KinematicCollision2D, RefCounted);
@@ -473,6 +474,7 @@ public:
Vector2 get_travel() const;
Vector2 get_remainder() const;
real_t get_angle(const Vector2 &p_up_direction = Vector2(0.0, -1.0)) const;
+ real_t get_depth() const;
Object *get_local_shape() const;
Object *get_collider() const;
ObjectID get_collider_id() const;
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index ba62941d3a..8161fb5bd9 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -90,9 +90,9 @@ bool Polygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toler
}
#endif
-void Polygon2D::_validate_property(PropertyInfo &property) const {
- if (!invert && property.name == "invert_border") {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void Polygon2D::_validate_property(PropertyInfo &p_property) const {
+ if (!invert && p_property.name == "invert_border") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
@@ -602,8 +602,8 @@ void Polygon2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture_scale", "texture_scale"), &Polygon2D::set_texture_scale);
ClassDB::bind_method(D_METHOD("get_texture_scale"), &Polygon2D::get_texture_scale);
- ClassDB::bind_method(D_METHOD("set_invert", "invert"), &Polygon2D::set_invert);
- ClassDB::bind_method(D_METHOD("get_invert"), &Polygon2D::get_invert);
+ ClassDB::bind_method(D_METHOD("set_invert_enabled", "invert"), &Polygon2D::set_invert);
+ ClassDB::bind_method(D_METHOD("get_invert_enabled"), &Polygon2D::get_invert);
ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &Polygon2D::set_antialiased);
ClassDB::bind_method(D_METHOD("get_antialiased"), &Polygon2D::get_antialiased);
@@ -646,7 +646,7 @@ void Polygon2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton2D"), "set_skeleton", "get_skeleton");
ADD_GROUP("Invert", "invert_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert_enable"), "set_invert", "get_invert");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert_enabled"), "set_invert_enabled", "get_invert_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "invert_border", PROPERTY_HINT_RANGE, "0.1,16384,0.1,suffix:px"), "set_invert_border", "get_invert_border");
ADD_GROUP("Data", "");
diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h
index d6a1be0f6d..d333152f62 100644
--- a/scene/2d/polygon_2d.h
+++ b/scene/2d/polygon_2d.h
@@ -77,7 +77,7 @@ class Polygon2D : public Node2D {
protected:
void _notification(int p_what);
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
#ifdef TOOLS_ENABLED
diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp
index 68e5ffdcf9..c4036faa79 100644
--- a/scene/2d/ray_cast_2d.cpp
+++ b/scene/2d/ray_cast_2d.cpp
@@ -82,6 +82,10 @@ Object *RayCast2D::get_collider() const {
return ObjectDB::get_instance(against);
}
+RID RayCast2D::get_collider_rid() const {
+ return against_rid;
+}
+
int RayCast2D::get_collider_shape() const {
return against_shape;
}
@@ -203,12 +207,14 @@ void RayCast2D::_update_raycast_state() {
if (dss->intersect_ray(ray_params, rr)) {
collided = true;
against = rr.collider_id;
+ against_rid = rr.rid;
collision_point = rr.position;
collision_normal = rr.normal;
against_shape = rr.shape;
} else {
collided = false;
against = ObjectID();
+ against_rid = RID();
against_shape = 0;
}
@@ -321,6 +327,7 @@ void RayCast2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("force_raycast_update"), &RayCast2D::force_raycast_update);
ClassDB::bind_method(D_METHOD("get_collider"), &RayCast2D::get_collider);
+ ClassDB::bind_method(D_METHOD("get_collider_rid"), &RayCast2D::get_collider_rid);
ClassDB::bind_method(D_METHOD("get_collider_shape"), &RayCast2D::get_collider_shape);
ClassDB::bind_method(D_METHOD("get_collision_point"), &RayCast2D::get_collision_point);
ClassDB::bind_method(D_METHOD("get_collision_normal"), &RayCast2D::get_collision_normal);
diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/ray_cast_2d.h
index 1fb97d89fe..57f993fe8d 100644
--- a/scene/2d/ray_cast_2d.h
+++ b/scene/2d/ray_cast_2d.h
@@ -41,6 +41,7 @@ class RayCast2D : public Node2D {
bool enabled = true;
bool collided = false;
ObjectID against;
+ RID against_rid;
int against_shape = 0;
Vector2 collision_point;
Vector2 collision_normal;
@@ -91,6 +92,7 @@ public:
bool is_colliding() const;
Object *get_collider() const;
+ RID get_collider_rid() const;
int get_collider_shape() const;
Vector2 get_collision_point() const;
Vector2 get_collision_normal() const;
diff --git a/scene/2d/shape_cast_2d.cpp b/scene/2d/shape_cast_2d.cpp
index 7589af0924..316988d298 100644
--- a/scene/2d/shape_cast_2d.cpp
+++ b/scene/2d/shape_cast_2d.cpp
@@ -217,7 +217,7 @@ void ShapeCast2D::_notification(int p_what) {
if (shape.is_null()) {
break;
}
- Color draw_col = get_tree()->get_debug_collisions_color();
+ Color draw_col = collided ? Color(1.0, 0.01, 0) : get_tree()->get_debug_collisions_color();
if (!enabled) {
float g = draw_col.get_v();
draw_col.r = g;
@@ -235,18 +235,25 @@ void ShapeCast2D::_notification(int p_what) {
// Draw an arrow indicating where the ShapeCast is pointing to.
if (target_position != Vector2()) {
- Transform2D xf;
- xf.rotate(target_position.angle());
- xf.translate_local(Vector2(target_position.length(), 0));
+ const real_t max_arrow_size = 6;
+ const real_t line_width = 1.4;
+ bool no_line = target_position.length() < line_width;
+ real_t arrow_size = CLAMP(target_position.length() * 2 / 3, line_width, max_arrow_size);
- draw_line(Vector2(), target_position, draw_col, 2);
+ if (no_line) {
+ arrow_size = target_position.length();
+ } else {
+ draw_line(Vector2(), target_position - target_position.normalized() * arrow_size, draw_col, line_width);
+ }
- float tsize = 8;
+ Transform2D xf;
+ xf.rotate(target_position.angle());
+ xf.translate_local(Vector2(no_line ? 0 : target_position.length() - arrow_size, 0));
Vector<Vector2> pts = {
- xf.xform(Vector2(tsize, 0)),
- xf.xform(Vector2(0, Math_SQRT12 * tsize)),
- xf.xform(Vector2(0, -Math_SQRT12 * tsize))
+ xf.xform(Vector2(arrow_size, 0)),
+ xf.xform(Vector2(0, 0.5 * arrow_size)),
+ xf.xform(Vector2(0, -0.5 * arrow_size))
};
Vector<Color> cols = { draw_col, draw_col, draw_col };
@@ -291,6 +298,8 @@ void ShapeCast2D::_update_shapecast_state() {
collision_safe_fraction = 0.0;
collision_unsafe_fraction = 0.0;
+ bool prev_collision_state = collided;
+
if (target_position != Vector2()) {
dss->cast_motion(params, collision_safe_fraction, collision_unsafe_fraction);
if (collision_unsafe_fraction < 1.0) {
@@ -314,6 +323,10 @@ void ShapeCast2D::_update_shapecast_state() {
}
}
collided = !result.is_empty();
+
+ if (prev_collision_state != collided) {
+ update();
+ }
}
void ShapeCast2D::force_shapecast_update() {
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index cbacb7f579..13a32fbfd4 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -44,7 +44,7 @@ bool Bone2D::_set(const StringName &p_path, const Variant &p_value) {
} else if (path.begins_with("length")) {
set_length(p_value);
} else if (path.begins_with("bone_angle")) {
- set_bone_angle(Math::deg2rad(real_t(p_value)));
+ set_bone_angle(Math::deg_to_rad(real_t(p_value)));
} else if (path.begins_with("default_length")) {
set_length(p_value);
}
@@ -66,7 +66,7 @@ bool Bone2D::_get(const StringName &p_path, Variant &r_ret) const {
} else if (path.begins_with("length")) {
r_ret = get_length();
} else if (path.begins_with("bone_angle")) {
- r_ret = Math::rad2deg(get_bone_angle());
+ r_ret = Math::rad_to_deg(get_bone_angle());
} else if (path.begins_with("default_length")) {
r_ret = get_length();
}
diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp
index b3062ca02a..e1983f9cb9 100644
--- a/scene/2d/sprite_2d.cpp
+++ b/scene/2d/sprite_2d.cpp
@@ -368,19 +368,19 @@ Rect2 Sprite2D::get_rect() const {
return Rect2(ofs, s);
}
-void Sprite2D::_validate_property(PropertyInfo &property) const {
- if (property.name == "frame") {
- property.hint = PROPERTY_HINT_RANGE;
- property.hint_string = "0," + itos(vframes * hframes - 1) + ",1";
- property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
+void Sprite2D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "frame") {
+ p_property.hint = PROPERTY_HINT_RANGE;
+ p_property.hint_string = "0," + itos(vframes * hframes - 1) + ",1";
+ p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
- if (property.name == "frame_coords") {
- property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
+ if (p_property.name == "frame_coords") {
+ p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
- if (!region_enabled && (property.name == "region_rect" || property.name == "region_filter_clip")) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (!region_enabled && (p_property.name == "region_rect" || p_property.name == "region_filter_clip")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
diff --git a/scene/2d/sprite_2d.h b/scene/2d/sprite_2d.h
index 5b33bb6802..60f5940cfe 100644
--- a/scene/2d/sprite_2d.h
+++ b/scene/2d/sprite_2d.h
@@ -64,7 +64,7 @@ protected:
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
#ifdef TOOLS_ENABLED
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 5ba8c95a06..129cce93fa 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -553,7 +553,7 @@ int TileMap::get_layers_count() const {
void TileMap::add_layer(int p_to_pos) {
if (p_to_pos < 0) {
- p_to_pos = layers.size();
+ p_to_pos = layers.size() + p_to_pos + 1;
}
ERR_FAIL_INDEX(p_to_pos, (int)layers.size() + 1);
@@ -612,6 +612,9 @@ void TileMap::remove_layer(int p_layer) {
}
void TileMap::set_layer_name(int p_layer, String p_name) {
+ if (p_layer < 0) {
+ p_layer = layers.size() + p_layer;
+ }
ERR_FAIL_INDEX(p_layer, (int)layers.size());
layers[p_layer].name = p_name;
emit_signal(SNAME("changed"));
@@ -623,6 +626,9 @@ String TileMap::get_layer_name(int p_layer) const {
}
void TileMap::set_layer_enabled(int p_layer, bool p_enabled) {
+ if (p_layer < 0) {
+ p_layer = layers.size() + p_layer;
+ }
ERR_FAIL_INDEX(p_layer, (int)layers.size());
layers[p_layer].enabled = p_enabled;
_clear_layer_internals(p_layer);
@@ -638,6 +644,9 @@ bool TileMap::is_layer_enabled(int p_layer) const {
}
void TileMap::set_layer_modulate(int p_layer, Color p_modulate) {
+ if (p_layer < 0) {
+ p_layer = layers.size() + p_layer;
+ }
ERR_FAIL_INDEX(p_layer, (int)layers.size());
layers[p_layer].modulate = p_modulate;
_clear_layer_internals(p_layer);
@@ -651,6 +660,9 @@ Color TileMap::get_layer_modulate(int p_layer) const {
}
void TileMap::set_layer_y_sort_enabled(int p_layer, bool p_y_sort_enabled) {
+ if (p_layer < 0) {
+ p_layer = layers.size() + p_layer;
+ }
ERR_FAIL_INDEX(p_layer, (int)layers.size());
layers[p_layer].y_sort_enabled = p_y_sort_enabled;
_clear_layer_internals(p_layer);
@@ -666,6 +678,9 @@ bool TileMap::is_layer_y_sort_enabled(int p_layer) const {
}
void TileMap::set_layer_y_sort_origin(int p_layer, int p_y_sort_origin) {
+ if (p_layer < 0) {
+ p_layer = layers.size() + p_layer;
+ }
ERR_FAIL_INDEX(p_layer, (int)layers.size());
layers[p_layer].y_sort_origin = p_y_sort_origin;
_clear_layer_internals(p_layer);
@@ -679,6 +694,9 @@ int TileMap::get_layer_y_sort_origin(int p_layer) const {
}
void TileMap::set_layer_z_index(int p_layer, int p_z_index) {
+ if (p_layer < 0) {
+ p_layer = layers.size() + p_layer;
+ }
ERR_FAIL_INDEX(p_layer, (int)layers.size());
layers[p_layer].z_index = p_z_index;
_clear_layer_internals(p_layer);
@@ -2063,6 +2081,18 @@ int TileMap::get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bo
return E->value.alternative_tile;
}
+TileData *TileMap::get_cell_tile_data(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const {
+ int source_id = get_cell_source_id(p_layer, p_coords, p_use_proxies);
+ ERR_FAIL_COND_V_MSG(source_id == TileSet::INVALID_SOURCE, nullptr, vformat("Invalid TileSetSource at cell %s. Make sure a tile exists at this cell.", p_coords));
+
+ Ref<TileSetAtlasSource> source = tile_set->get_source(source_id);
+ if (source.is_valid()) {
+ return source->get_tile_data(get_cell_atlas_coords(p_layer, p_coords, p_use_proxies), get_cell_alternative_tile(p_layer, p_coords, p_use_proxies));
+ }
+
+ return nullptr;
+}
+
Ref<TileMapPattern> TileMap::get_pattern(int p_layer, TypedArray<Vector2i> p_coords_array) {
ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), nullptr);
ERR_FAIL_COND_V(!tile_set.is_valid(), nullptr);
@@ -3827,7 +3857,7 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_layer_name", "layer"), &TileMap::get_layer_name);
ClassDB::bind_method(D_METHOD("set_layer_enabled", "layer", "enabled"), &TileMap::set_layer_enabled);
ClassDB::bind_method(D_METHOD("is_layer_enabled", "layer"), &TileMap::is_layer_enabled);
- ClassDB::bind_method(D_METHOD("set_layer_modulate", "layer", "enabled"), &TileMap::set_layer_modulate);
+ ClassDB::bind_method(D_METHOD("set_layer_modulate", "layer", "modulate"), &TileMap::set_layer_modulate);
ClassDB::bind_method(D_METHOD("get_layer_modulate", "layer"), &TileMap::get_layer_modulate);
ClassDB::bind_method(D_METHOD("set_layer_y_sort_enabled", "layer", "y_sort_enabled"), &TileMap::set_layer_y_sort_enabled);
ClassDB::bind_method(D_METHOD("is_layer_y_sort_enabled", "layer"), &TileMap::is_layer_y_sort_enabled);
@@ -3846,9 +3876,10 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_cell", "layer", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMap::set_cell, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(0));
ClassDB::bind_method(D_METHOD("erase_cell", "layer", "coords"), &TileMap::erase_cell);
- ClassDB::bind_method(D_METHOD("get_cell_source_id", "layer", "coords", "use_proxies"), &TileMap::get_cell_source_id);
- ClassDB::bind_method(D_METHOD("get_cell_atlas_coords", "layer", "coords", "use_proxies"), &TileMap::get_cell_atlas_coords);
- ClassDB::bind_method(D_METHOD("get_cell_alternative_tile", "layer", "coords", "use_proxies"), &TileMap::get_cell_alternative_tile);
+ ClassDB::bind_method(D_METHOD("get_cell_source_id", "layer", "coords", "use_proxies"), &TileMap::get_cell_source_id, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_cell_atlas_coords", "layer", "coords", "use_proxies"), &TileMap::get_cell_atlas_coords, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_cell_alternative_tile", "layer", "coords", "use_proxies"), &TileMap::get_cell_alternative_tile, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_cell_tile_data", "layer", "coords", "use_proxies"), &TileMap::get_cell_tile_data, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_coords_for_body_rid", "body"), &TileMap::get_coords_for_body_rid);
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index 012bf01df9..ecc6ee1d59 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -343,6 +343,8 @@ public:
int get_cell_source_id(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const;
Vector2i get_cell_atlas_coords(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const;
int get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const;
+ // Helper method to make accessing the data easier.
+ TileData *get_cell_tile_data(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const;
// Patterns.
Ref<TileMapPattern> get_pattern(int p_layer, TypedArray<Vector2i> p_coords_array);
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp
index e9e19488e9..db7c3233f6 100644
--- a/scene/3d/area_3d.cpp
+++ b/scene/3d/area_3d.cpp
@@ -598,8 +598,8 @@ float Area3D::get_reverb_uniformity() const {
return reverb_uniformity;
}
-void Area3D::_validate_property(PropertyInfo &property) const {
- if (property.name == "audio_bus_name" || property.name == "reverb_bus_name") {
+void Area3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "audio_bus_name" || p_property.name == "reverb_bus_name") {
String options;
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
if (i > 0) {
@@ -609,32 +609,30 @@ void Area3D::_validate_property(PropertyInfo &property) const {
options += name;
}
- property.hint_string = options;
- } else if (property.name.begins_with("gravity") && property.name != "gravity_space_override") {
+ p_property.hint_string = options;
+ } else if (p_property.name.begins_with("gravity") && p_property.name != "gravity_space_override") {
if (gravity_space_override == SPACE_OVERRIDE_DISABLED) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
} else {
if (gravity_is_point) {
- if (property.name == "gravity_direction") {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name == "gravity_direction") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
} else {
- if (property.name.begins_with("gravity_point_")) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name.begins_with("gravity_point_")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
}
- } else if (property.name.begins_with("linear_damp") && property.name != "linear_damp_space_override") {
+ } else if (p_property.name.begins_with("linear_damp") && p_property.name != "linear_damp_space_override") {
if (linear_damp_space_override == SPACE_OVERRIDE_DISABLED) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- } else if (property.name.begins_with("angular_damp") && property.name != "angular_damp_space_override") {
+ } else if (p_property.name.begins_with("angular_damp") && p_property.name != "angular_damp_space_override") {
if (angular_damp_space_override == SPACE_OVERRIDE_DISABLED) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
-
- CollisionObject3D::_validate_property(property);
}
void Area3D::_bind_methods() {
diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h
index 3b892baf57..48364739b7 100644
--- a/scene/3d/area_3d.h
+++ b/scene/3d/area_3d.h
@@ -141,7 +141,7 @@ private:
float reverb_amount = 0.0;
float reverb_uniformity = 0.0;
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _initialize_wind();
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 65b00742ee..0e7b71f74a 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -149,7 +149,7 @@ void AudioStreamPlayer3D::_calc_reverb_vol(Area3D *area, Vector3 listener_area_p
if (uniformity > 0.0) {
float distance = listener_area_pos.length();
- float attenuation = Math::db2linear(_get_attenuation_db(distance));
+ float attenuation = Math::db_to_linear(_get_attenuation_db(distance));
// Determine the fraction of sound that would come from each speaker if they were all driven uniformly.
float center_val[3] = { 0.5f, 0.25f, 0.16666f };
@@ -213,12 +213,12 @@ float AudioStreamPlayer3D::_get_attenuation_db(float p_distance) const {
float att = 0;
switch (attenuation_model) {
case ATTENUATION_INVERSE_DISTANCE: {
- att = Math::linear2db(1.0 / ((p_distance / unit_size) + CMP_EPSILON));
+ att = Math::linear_to_db(1.0 / ((p_distance / unit_size) + CMP_EPSILON));
} break;
case ATTENUATION_INVERSE_SQUARE_DISTANCE: {
float d = (p_distance / unit_size);
d *= d;
- att = Math::linear2db(1.0 / (d + CMP_EPSILON));
+ att = Math::linear_to_db(1.0 / (d + CMP_EPSILON));
} break;
case ATTENUATION_LOGARITHMIC: {
att = -20 * Math::log(p_distance / unit_size + CMP_EPSILON);
@@ -443,7 +443,7 @@ Vector<AudioFrame> AudioStreamPlayer3D::_update_panning() {
}
}
- float multiplier = Math::db2linear(_get_attenuation_db(dist));
+ float multiplier = Math::db_to_linear(_get_attenuation_db(dist));
if (max_distance > 0) {
multiplier *= MAX(0, 1.0 - (dist / max_distance));
}
@@ -453,13 +453,13 @@ Vector<AudioFrame> AudioStreamPlayer3D::_update_panning() {
if (emission_angle_enabled) {
Vector3 listenertopos = global_pos - listener_node->get_global_transform().origin;
float c = listenertopos.normalized().dot(get_global_transform().basis.get_column(2).normalized()); //it's z negative
- float angle = Math::rad2deg(Math::acos(c));
+ float angle = Math::rad_to_deg(Math::acos(c));
if (angle > emission_angle) {
db_att -= -emission_angle_filter_attenuation_db;
}
}
- linear_attenuation = Math::db2linear(db_att);
+ linear_attenuation = Math::db_to_linear(db_att);
for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
AudioServer::get_singleton()->set_playback_highshelf_params(playback, linear_attenuation, attenuation_filter_cutoff_hz);
}
@@ -648,8 +648,8 @@ bool AudioStreamPlayer3D::_is_active() const {
return active.is_set();
}
-void AudioStreamPlayer3D::_validate_property(PropertyInfo &property) const {
- if (property.name == "bus") {
+void AudioStreamPlayer3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "bus") {
String options;
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
if (i > 0) {
@@ -659,10 +659,8 @@ void AudioStreamPlayer3D::_validate_property(PropertyInfo &property) const {
options += name;
}
- property.hint_string = options;
+ p_property.hint_string = options;
}
-
- Node3D::_validate_property(property);
}
void AudioStreamPlayer3D::_bus_layout_changed() {
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index 647b18a4a7..ef48269544 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -120,7 +120,7 @@ private:
float cached_global_panning_strength = 1.0f;
protected:
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp
index fbd5b5b65b..b3ff6497a7 100644
--- a/scene/3d/bone_attachment_3d.cpp
+++ b/scene/3d/bone_attachment_3d.cpp
@@ -30,8 +30,8 @@
#include "bone_attachment_3d.h"
-void BoneAttachment3D::_validate_property(PropertyInfo &property) const {
- if (property.name == "bone_name") {
+void BoneAttachment3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "bone_name") {
// Because it is a constant function, we cannot use the _get_skeleton_3d function.
const Skeleton3D *parent = nullptr;
if (use_external_skeleton) {
@@ -51,15 +51,13 @@ void BoneAttachment3D::_validate_property(PropertyInfo &property) const {
names += parent->get_bone_name(i);
}
- property.hint = PROPERTY_HINT_ENUM;
- property.hint_string = names;
+ p_property.hint = PROPERTY_HINT_ENUM;
+ p_property.hint_string = names;
} else {
- property.hint = PROPERTY_HINT_NONE;
- property.hint_string = "";
+ p_property.hint = PROPERTY_HINT_NONE;
+ p_property.hint_string = "";
}
}
-
- Node3D::_validate_property(property);
}
bool BoneAttachment3D::_set(const StringName &p_path, const Variant &p_value) {
diff --git a/scene/3d/bone_attachment_3d.h b/scene/3d/bone_attachment_3d.h
index 3224361a25..f85053e614 100644
--- a/scene/3d/bone_attachment_3d.h
+++ b/scene/3d/bone_attachment_3d.h
@@ -64,7 +64,7 @@ class BoneAttachment3D : public Node3D {
Skeleton3D *_get_skeleton3d();
protected:
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
bool _get(const StringName &p_path, Variant &r_ret) const;
bool _set(const StringName &p_path, const Variant &p_value);
void _get_property_list(List<PropertyInfo> *p_list) const;
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
index da4a14394d..b8b6296c45 100644
--- a/scene/3d/camera_3d.cpp
+++ b/scene/3d/camera_3d.cpp
@@ -71,8 +71,6 @@ void Camera3D::_validate_property(PropertyInfo &p_property) const {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
-
- Node3D::_validate_property(p_property);
}
void Camera3D::_update_camera() {
@@ -487,7 +485,7 @@ void Camera3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_keep_aspect_mode"), &Camera3D::get_keep_aspect_mode);
ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &Camera3D::set_doppler_tracking);
ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &Camera3D::get_doppler_tracking);
- ClassDB::bind_method(D_METHOD("get_frustum"), &Camera3D::get_frustum);
+ ClassDB::bind_method(D_METHOD("get_frustum"), &Camera3D::_get_frustum);
ClassDB::bind_method(D_METHOD("is_position_in_frustum", "world_point"), &Camera3D::is_position_in_frustum);
ClassDB::bind_method(D_METHOD("get_camera_rid"), &Camera3D::get_camera);
ClassDB::bind_method(D_METHOD("get_pyramid_shape_rid"), &Camera3D::get_pyramid_shape_rid);
@@ -507,7 +505,7 @@ void Camera3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal,Frustum"), "set_projection", "get_projection");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fov", PROPERTY_HINT_RANGE, "1,179,0.1,degrees"), "set_fov", "get_fov");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.001,16384,0.01,suffix:m"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.001,16384,0.001,suffix:m"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frustum_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_frustum_offset", "get_frustum_offset");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "near", PROPERTY_HINT_RANGE, "0.001,10,0.001,or_greater,exp,suffix:m"), "set_near", "get_near");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "far", PROPERTY_HINT_RANGE, "0.01,4000,0.01,or_greater,exp,suffix:m"), "set_far", "get_far");
@@ -617,6 +615,11 @@ Vector<Plane> Camera3D::get_frustum() const {
return cm.get_projection_planes(get_camera_transform());
}
+TypedArray<Plane> Camera3D::_get_frustum() const {
+ Variant ret = get_frustum();
+ return ret;
+}
+
bool Camera3D::is_position_in_frustum(const Vector3 &p_position) const {
Vector<Plane> frustum = get_frustum();
for (int i = 0; i < frustum.size(); i++) {
diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h
index cedd976890..bba9b7d1e4 100644
--- a/scene/3d/camera_3d.h
+++ b/scene/3d/camera_3d.h
@@ -86,6 +86,7 @@ private:
// void _camera_make_current(Node *p_camera);
friend class Viewport;
void _update_audio_listener_state();
+ TypedArray<Plane> _get_frustum() const;
DopplerTracking doppler_tracking = DOPPLER_TRACKING_DISABLED;
Ref<VelocityTracker3D> velocity_tracker;
@@ -99,7 +100,7 @@ protected:
void _update_camera_mode();
void _notification(int p_what);
- virtual void _validate_property(PropertyInfo &p_property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index 9a5d4f5480..f5e3e8b015 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -183,6 +183,17 @@ bool CollisionObject3D::get_collision_mask_value(int p_layer_number) const {
return get_collision_mask() & (1 << (p_layer_number - 1));
}
+void CollisionObject3D::set_collision_priority(real_t p_priority) {
+ collision_priority = p_priority;
+ if (!area) {
+ PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), p_priority);
+ }
+}
+
+real_t CollisionObject3D::get_collision_priority() const {
+ return collision_priority;
+}
+
void CollisionObject3D::set_disable_mode(DisableMode p_mode) {
if (disable_mode == p_mode) {
return;
@@ -432,6 +443,8 @@ void CollisionObject3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &CollisionObject3D::get_collision_layer_value);
ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &CollisionObject3D::set_collision_mask_value);
ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &CollisionObject3D::get_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("set_collision_priority", "priority"), &CollisionObject3D::set_collision_priority);
+ ClassDB::bind_method(D_METHOD("get_collision_priority"), &CollisionObject3D::get_collision_priority);
ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &CollisionObject3D::set_disable_mode);
ClassDB::bind_method(D_METHOD("get_disable_mode"), &CollisionObject3D::get_disable_mode);
ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &CollisionObject3D::set_ray_pickable);
@@ -456,6 +469,8 @@ void CollisionObject3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("shape_find_owner", "shape_index"), &CollisionObject3D::shape_find_owner);
GDVIRTUAL_BIND(_input_event, "camera", "event", "position", "normal", "shape_idx");
+ GDVIRTUAL_BIND(_mouse_enter);
+ GDVIRTUAL_BIND(_mouse_exit);
ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "position"), PropertyInfo(Variant::VECTOR3, "normal"), PropertyInfo(Variant::INT, "shape_idx")));
ADD_SIGNAL(MethodInfo("mouse_entered"));
@@ -466,6 +481,7 @@ void CollisionObject3D::_bind_methods() {
ADD_GROUP("Collision", "collision_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_priority"), "set_collision_priority", "get_collision_priority");
ADD_GROUP("Input", "input_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_ray_pickable"), "set_ray_pickable", "is_ray_pickable");
@@ -532,8 +548,8 @@ void CollisionObject3D::get_shape_owners(List<uint32_t> *r_owners) {
}
}
-Array CollisionObject3D::_get_shape_owners() {
- Array ret;
+PackedInt32Array CollisionObject3D::_get_shape_owners() {
+ PackedInt32Array ret;
for (const KeyValue<uint32_t, ShapeData> &E : shapes) {
ret.push_back(E.key);
}
diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h
index 3ec3aa0fc1..c638be9d90 100644
--- a/scene/3d/collision_object_3d.h
+++ b/scene/3d/collision_object_3d.h
@@ -47,6 +47,7 @@ public:
private:
uint32_t collision_layer = 1;
uint32_t collision_mask = 1;
+ real_t collision_priority = 1.0;
bool area = false;
@@ -112,6 +113,8 @@ protected:
bool is_only_update_transform_changes_enabled() const;
GDVIRTUAL5(_input_event, Camera3D *, Ref<InputEvent>, Vector3, Vector3, int)
+ GDVIRTUAL0(_mouse_enter)
+ GDVIRTUAL0(_mouse_exit)
public:
void set_collision_layer(uint32_t p_layer);
uint32_t get_collision_layer() const;
@@ -125,13 +128,16 @@ public:
void set_collision_mask_value(int p_layer_number, bool p_value);
bool get_collision_mask_value(int p_layer_number) const;
+ void set_collision_priority(real_t p_priority);
+ real_t get_collision_priority() const;
+
void set_disable_mode(DisableMode p_mode);
DisableMode get_disable_mode() const;
uint32_t create_shape_owner(Object *p_owner);
void remove_shape_owner(uint32_t owner);
void get_shape_owners(List<uint32_t> *r_owners);
- Array _get_shape_owners();
+ PackedInt32Array _get_shape_owners();
void shape_owner_set_transform(uint32_t p_owner, const Transform3D &p_transform);
Transform3D shape_owner_get_transform(uint32_t p_owner) const;
diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp
index bd6a70e566..90099d787b 100644
--- a/scene/3d/collision_polygon_3d.cpp
+++ b/scene/3d/collision_polygon_3d.cpp
@@ -171,7 +171,7 @@ TypedArray<String> CollisionPolygon3D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject3D>(get_parent())) {
- warnings.push_back(RTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidDynamicBody3D, CharacterBody3D, etc. to give them a shape."));
+ warnings.push_back(RTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, CharacterBody3D, etc. to give them a shape."));
}
if (polygon.is_empty()) {
diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp
index 759997de7b..a9bc28b464 100644
--- a/scene/3d/collision_shape_3d.cpp
+++ b/scene/3d/collision_shape_3d.cpp
@@ -118,7 +118,7 @@ TypedArray<String> CollisionShape3D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<CollisionObject3D>(get_parent())) {
- warnings.push_back(RTR("CollisionShape3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidDynamicBody3D, CharacterBody3D, etc. to give them a shape."));
+ warnings.push_back(RTR("CollisionShape3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, CharacterBody3D, etc. to give them a shape."));
}
if (!shape.is_valid()) {
@@ -126,9 +126,9 @@ TypedArray<String> CollisionShape3D::get_configuration_warnings() const {
}
if (shape.is_valid() &&
- Object::cast_to<RigidDynamicBody3D>(get_parent()) &&
+ Object::cast_to<RigidBody3D>(get_parent()) &&
Object::cast_to<ConcavePolygonShape3D>(*shape)) {
- warnings.push_back(RTR("ConcavePolygonShape3D doesn't support RigidDynamicBody3D in another mode than static."));
+ warnings.push_back(RTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static."));
}
return warnings;
diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
index 4df0c37ad6..9dc61b35af 100644
--- a/scene/3d/cpu_particles_3d.cpp
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -33,7 +33,7 @@
#include "scene/3d/camera_3d.h"
#include "scene/3d/gpu_particles_3d.h"
#include "scene/main/viewport.h"
-#include "scene/resources/particles_material.h"
+#include "scene/resources/particle_process_material.h"
AABB CPUParticles3D::get_aabb() const {
return AABB();
@@ -516,36 +516,34 @@ bool CPUParticles3D::get_split_scale() {
return split_scale;
}
-void CPUParticles3D::_validate_property(PropertyInfo &property) const {
- if (property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) {
- property.usage = PROPERTY_USAGE_NONE;
+void CPUParticles3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if ((property.name == "emission_point_texture" || property.name == "emission_color_texture" || property.name == "emission_points") && (emission_shape != EMISSION_SHAPE_POINTS && (emission_shape != EMISSION_SHAPE_DIRECTED_POINTS))) {
- property.usage = PROPERTY_USAGE_NONE;
+ if ((p_property.name == "emission_point_texture" || p_property.name == "emission_color_texture" || p_property.name == "emission_points") && (emission_shape != EMISSION_SHAPE_POINTS && (emission_shape != EMISSION_SHAPE_DIRECTED_POINTS))) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("emission_ring_") && emission_shape != EMISSION_SHAPE_RING) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("emission_ring_") && emission_shape != EMISSION_SHAPE_RING) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("scale_curve_") && !split_scale) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("scale_curve_") && !split_scale) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
-
- Node3D::_validate_property(property);
}
static uint32_t idhash(uint32_t x) {
@@ -768,13 +766,13 @@ void CPUParticles3D::_particles_process(double p_delta) {
}
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- real_t angle1_rad = Math::atan2(direction.y, direction.x) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * spread);
+ real_t angle1_rad = Math::atan2(direction.y, direction.x) + Math::deg_to_rad((Math::randf() * 2.0 - 1.0) * spread);
Vector3 rot = Vector3(Math::cos(angle1_rad), Math::sin(angle1_rad), 0.0);
p.velocity = rot * Math::lerp(parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], parameters_max[PARAM_INITIAL_LINEAR_VELOCITY], (real_t)Math::randf());
} else {
//initiate velocity spread in 3D
- real_t angle1_rad = Math::deg2rad((Math::randf() * (real_t)2.0 - (real_t)1.0) * spread);
- real_t angle2_rad = Math::deg2rad((Math::randf() * (real_t)2.0 - (real_t)1.0) * ((real_t)1.0 - flatness) * spread);
+ real_t angle1_rad = Math::deg_to_rad((Math::randf() * (real_t)2.0 - (real_t)1.0) * spread);
+ real_t angle2_rad = Math::deg_to_rad((Math::randf() * (real_t)2.0 - (real_t)1.0) * ((real_t)1.0 - flatness) * spread);
Vector3 direction_xz = Vector3(Math::sin(angle1_rad), 0, Math::cos(angle1_rad));
Vector3 direction_yz = Vector3(0, Math::sin(angle2_rad), Math::cos(angle2_rad));
@@ -798,7 +796,7 @@ void CPUParticles3D::_particles_process(double p_delta) {
}
real_t base_angle = tex_angle * Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand);
- p.custom[0] = Math::deg2rad(base_angle); //angle
+ p.custom[0] = Math::deg_to_rad(base_angle); //angle
p.custom[1] = 0.0; //phase
p.custom[2] = tex_anim_offset * Math::lerp(parameters_min[PARAM_ANIM_OFFSET], parameters_max[PARAM_ANIM_OFFSET], p.anim_offset_rand); //animation offset (0-1)
p.transform = Transform3D();
@@ -985,7 +983,7 @@ void CPUParticles3D::_particles_process(double p_delta) {
real_t orbit_amount = tex_orbit_velocity * Math::lerp(parameters_min[PARAM_ORBIT_VELOCITY], parameters_max[PARAM_ORBIT_VELOCITY], rand_from_seed(alt_seed));
if (orbit_amount != 0.0) {
real_t ang = orbit_amount * local_delta * Math_TAU;
- // Not sure why the ParticlesMaterial code uses a clockwise rotation matrix,
+ // Not sure why the ParticleProcessMaterial code uses a clockwise rotation matrix,
// but we use -ang here to reproduce its behavior.
Transform2D rot = Transform2D(-ang, Vector2());
Vector2 rotv = rot.basis_xform(Vector2(diff.x, diff.y));
@@ -1009,7 +1007,7 @@ void CPUParticles3D::_particles_process(double p_delta) {
}
real_t base_angle = (tex_angle)*Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand);
base_angle += p.custom[1] * lifetime * tex_angular_velocity * Math::lerp(parameters_min[PARAM_ANGULAR_VELOCITY], parameters_max[PARAM_ANGULAR_VELOCITY], rand_from_seed(alt_seed));
- p.custom[0] = Math::deg2rad(base_angle); //angle
+ p.custom[0] = Math::deg_to_rad(base_angle); //angle
p.custom[2] = tex_anim_offset * Math::lerp(parameters_min[PARAM_ANIM_OFFSET], parameters_max[PARAM_ANIM_OFFSET], p.anim_offset_rand) + tv * tex_anim_speed * Math::lerp(parameters_min[PARAM_ANIM_SPEED], parameters_max[PARAM_ANIM_SPEED], rand_from_seed(alt_seed)); //angle
}
//apply color
@@ -1345,7 +1343,7 @@ void CPUParticles3D::convert_from_particles(Node *p_particles) {
set_draw_order(DrawOrder(particles->get_draw_order()));
set_mesh(particles->get_draw_pass_mesh(0));
- Ref<ParticlesMaterial> material = particles->get_process_material();
+ Ref<ParticleProcessMaterial> material = particles->get_process_material();
if (material.is_null()) {
return;
}
@@ -1366,14 +1364,14 @@ void CPUParticles3D::convert_from_particles(Node *p_particles) {
set_color_initial_ramp(gti->get_gradient());
}
- set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY));
- set_particle_flag(PARTICLE_FLAG_ROTATE_Y, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_ROTATE_Y));
- set_particle_flag(PARTICLE_FLAG_DISABLE_Z, material->get_particle_flag(ParticlesMaterial::PARTICLE_FLAG_DISABLE_Z));
+ set_particle_flag(PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY, material->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY));
+ set_particle_flag(PARTICLE_FLAG_ROTATE_Y, material->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_ROTATE_Y));
+ set_particle_flag(PARTICLE_FLAG_DISABLE_Z, material->get_particle_flag(ParticleProcessMaterial::PARTICLE_FLAG_DISABLE_Z));
set_emission_shape(EmissionShape(material->get_emission_shape()));
set_emission_sphere_radius(material->get_emission_sphere_radius());
set_emission_box_extents(material->get_emission_box_extents());
- Ref<CurveXYZTexture> scale3D = material->get_param_texture(ParticlesMaterial::PARAM_SCALE);
+ Ref<CurveXYZTexture> scale3D = material->get_param_texture(ParticleProcessMaterial::PARAM_SCALE);
if (scale3D.is_valid()) {
split_scale = true;
scale_curve_x = scale3D->get_curve_x();
@@ -1384,14 +1382,14 @@ void CPUParticles3D::convert_from_particles(Node *p_particles) {
set_gravity(material->get_gravity());
set_lifetime_randomness(material->get_lifetime_randomness());
-#define CONVERT_PARAM(m_param) \
- set_param_min(m_param, material->get_param_min(ParticlesMaterial::m_param)); \
- { \
- Ref<CurveTexture> ctex = material->get_param_texture(ParticlesMaterial::m_param); \
- if (ctex.is_valid()) \
- set_param_curve(m_param, ctex->get_curve()); \
- } \
- set_param_max(m_param, material->get_param_max(ParticlesMaterial::m_param));
+#define CONVERT_PARAM(m_param) \
+ set_param_min(m_param, material->get_param_min(ParticleProcessMaterial::m_param)); \
+ { \
+ Ref<CurveTexture> ctex = material->get_param_texture(ParticleProcessMaterial::m_param); \
+ if (ctex.is_valid()) \
+ set_param_curve(m_param, ctex->get_curve()); \
+ } \
+ set_param_max(m_param, material->get_param_max(ParticleProcessMaterial::m_param));
CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY);
CONVERT_PARAM(PARAM_ANGULAR_VELOCITY);
diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h
index 4cb693f494..d84b0aedd2 100644
--- a/scene/3d/cpu_particles_3d.h
+++ b/scene/3d/cpu_particles_3d.h
@@ -138,7 +138,7 @@ private:
real_t randomness_ratio = 0.0;
double lifetime_randomness = 0.0;
double speed_scale = 1.0;
- bool local_coords = true;
+ bool local_coords = false;
int fixed_fps = 0;
bool fractional_delta = true;
@@ -198,7 +198,7 @@ private:
protected:
static void _bind_methods();
void _notification(int p_what);
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
AABB get_aabb() const override;
diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp
index 0112f24e0c..460402ad1d 100644
--- a/scene/3d/decal.cpp
+++ b/scene/3d/decal.cpp
@@ -152,11 +152,10 @@ AABB Decal::get_aabb() const {
return aabb;
}
-void Decal::_validate_property(PropertyInfo &property) const {
- if (!distance_fade_enabled && (property.name == "distance_fade_begin" || property.name == "distance_fade_length")) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void Decal::_validate_property(PropertyInfo &p_property) const {
+ if (!distance_fade_enabled && (p_property.name == "distance_fade_begin" || p_property.name == "distance_fade_length")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- VisualInstance3D::_validate_property(property);
}
TypedArray<String> Decal::get_configuration_warnings() const {
diff --git a/scene/3d/decal.h b/scene/3d/decal.h
index 38da4c14e3..1a7d55b108 100644
--- a/scene/3d/decal.h
+++ b/scene/3d/decal.h
@@ -62,7 +62,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
virtual TypedArray<String> get_configuration_warnings() const override;
diff --git a/scene/3d/fog_volume.cpp b/scene/3d/fog_volume.cpp
index 1b329143b6..319129603e 100644
--- a/scene/3d/fog_volume.cpp
+++ b/scene/3d/fog_volume.cpp
@@ -45,12 +45,11 @@ void FogVolume::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "FogMaterial,ShaderMaterial"), "set_material", "get_material");
}
-void FogVolume::_validate_property(PropertyInfo &property) const {
- if (property.name == "extents" && shape == RS::FOG_VOLUME_SHAPE_WORLD) {
- property.usage = PROPERTY_USAGE_NONE;
+void FogVolume::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "extents" && shape == RS::FOG_VOLUME_SHAPE_WORLD) {
+ p_property.usage = PROPERTY_USAGE_NONE;
return;
}
- VisualInstance3D::_validate_property(property);
}
void FogVolume::set_extents(const Vector3 &p_extents) {
diff --git a/scene/3d/fog_volume.h b/scene/3d/fog_volume.h
index 556a92ad3f..fcdc1e2807 100644
--- a/scene/3d/fog_volume.h
+++ b/scene/3d/fog_volume.h
@@ -49,7 +49,7 @@ class FogVolume : public VisualInstance3D {
protected:
_FORCE_INLINE_ RID _get_volume() { return volume; }
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_extents(const Vector3 &p_extents);
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index 01aff32954..bd63939d74 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -30,7 +30,7 @@
#include "gpu_particles_3d.h"
-#include "scene/resources/particles_material.h"
+#include "scene/resources/particle_process_material.h"
AABB GPUParticles3D::get_aabb() const {
return AABB();
@@ -306,10 +306,10 @@ TypedArray<String> GPUParticles3D::get_configuration_warnings() const {
if (process_material.is_null()) {
warnings.push_back(RTR("A material to process the particles is not assigned, so no behavior is imprinted."));
} else {
- const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr());
+ const ParticleProcessMaterial *process = Object::cast_to<ParticleProcessMaterial>(process_material.ptr());
if (!anim_material_found && process &&
- (process->get_param_max(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param_max(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
- process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
+ (process->get_param_max(ParticleProcessMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param_max(ParticleProcessMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
+ process->get_param_texture(ParticleProcessMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticleProcessMaterial::PARAM_ANIM_OFFSET).is_valid())) {
warnings.push_back(RTR("Particles animation requires the usage of a BaseMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."));
}
}
@@ -376,16 +376,14 @@ AABB GPUParticles3D::capture_aabb() const {
return RS::get_singleton()->particles_get_current_aabb(particles);
}
-void GPUParticles3D::_validate_property(PropertyInfo &property) const {
- if (property.name.begins_with("draw_pass_")) {
- int index = property.name.get_slicec('_', 2).to_int() - 1;
+void GPUParticles3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name.begins_with("draw_pass_")) {
+ int index = p_property.name.get_slicec('_', 2).to_int() - 1;
if (index >= draw_passes.size()) {
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
return;
}
}
-
- GeometryInstance3D::_validate_property(property);
}
void GPUParticles3D::emit_particle(const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) {
@@ -587,7 +585,7 @@ void GPUParticles3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trail_enabled"), "set_trail_enabled", "is_trail_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "trail_length_secs", PROPERTY_HINT_RANGE, "0.01,10,0.01,suffix:s"), "set_trail_length", "get_trail_length");
ADD_GROUP("Process Material", "");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticleProcessMaterial"), "set_process_material", "get_process_material");
ADD_GROUP("Draw Passes", "draw_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_passes", PROPERTY_HINT_RANGE, "0," + itos(MAX_DRAW_PASSES) + ",1"), "set_draw_passes", "get_draw_passes");
for (int i = 0; i < MAX_DRAW_PASSES; i++) {
@@ -631,7 +629,7 @@ GPUParticles3D::GPUParticles3D() {
set_randomness_ratio(0);
set_trail_length(0.3);
set_visibility_aabb(AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8)));
- set_use_local_coordinates(true);
+ set_use_local_coordinates(false);
set_draw_passes(1);
set_draw_order(DRAW_ORDER_INDEX);
set_speed_scale(1);
diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h
index 0c745dd734..2ad9672474 100644
--- a/scene/3d/gpu_particles_3d.h
+++ b/scene/3d/gpu_particles_3d.h
@@ -94,7 +94,7 @@ private:
protected:
static void _bind_methods();
void _notification(int p_what);
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
AABB get_aabb() const override;
diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp
index 1fcd5160f6..1cfd889272 100644
--- a/scene/3d/gpu_particles_collision_3d.cpp
+++ b/scene/3d/gpu_particles_collision_3d.cpp
@@ -127,6 +127,10 @@ GPUParticlesCollisionBox3D::~GPUParticlesCollisionBox3D() {
void GPUParticlesCollisionSDF3D::_find_meshes(const AABB &p_aabb, Node *p_at_node, List<PlotMesh> &plot_meshes) {
MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_at_node);
if (mi && mi->is_visible_in_tree()) {
+ if ((mi->get_layer_mask() & bake_mask) == 0) {
+ return;
+ }
+
Ref<Mesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
AABB aabb = mesh->get_aabb();
@@ -445,7 +449,7 @@ Ref<Image> GPUParticlesCollisionSDF3D::bake() {
//compute bvh
- ERR_FAIL_COND_V(faces.size() <= 1, Ref<Image>());
+ ERR_FAIL_COND_V_MSG(faces.size() <= 1, Ref<Image>(), "No faces detected during GPUParticlesCollisionSDF3D bake. Check whether there are visible meshes matching the bake mask within its extents.");
LocalVector<FacePos> face_pos;
@@ -499,6 +503,16 @@ Ref<Image> GPUParticlesCollisionSDF3D::bake() {
return ret;
}
+TypedArray<String> GPUParticlesCollisionSDF3D::get_configuration_warnings() const {
+ TypedArray<String> warnings = Node::get_configuration_warnings();
+
+ if (bake_mask == 0) {
+ warnings.push_back(RTR("The Bake Mask has no bits enabled, which means baking will not produce any collision for this GPUParticlesCollisionSDF3D.\nTo resolve this, enable at least one bit in the Bake Mask property."));
+ }
+
+ return warnings;
+}
+
void GPUParticlesCollisionSDF3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GPUParticlesCollisionSDF3D::set_extents);
ClassDB::bind_method(D_METHOD("get_extents"), &GPUParticlesCollisionSDF3D::get_extents);
@@ -512,9 +526,15 @@ void GPUParticlesCollisionSDF3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_thickness", "thickness"), &GPUParticlesCollisionSDF3D::set_thickness);
ClassDB::bind_method(D_METHOD("get_thickness"), &GPUParticlesCollisionSDF3D::get_thickness);
+ ClassDB::bind_method(D_METHOD("set_bake_mask", "mask"), &GPUParticlesCollisionSDF3D::set_bake_mask);
+ ClassDB::bind_method(D_METHOD("get_bake_mask"), &GPUParticlesCollisionSDF3D::get_bake_mask);
+ ClassDB::bind_method(D_METHOD("set_bake_mask_value", "layer_number", "value"), &GPUParticlesCollisionSDF3D::set_bake_mask_value);
+ ClassDB::bind_method(D_METHOD("get_bake_mask_value", "layer_number"), &GPUParticlesCollisionSDF3D::get_bake_mask_value);
+
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater,suffix:m"), "set_extents", "get_extents");
ADD_PROPERTY(PropertyInfo(Variant::INT, "resolution", PROPERTY_HINT_ENUM, "16,32,64,128,256,512,suffix:px"), "set_resolution", "get_resolution");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "thickness", PROPERTY_HINT_RANGE, "0.0,2.0,0.01,suffix:m"), "set_thickness", "get_thickness");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_bake_mask", "get_bake_mask");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture3D"), "set_texture", "get_texture");
BIND_ENUM_CONSTANT(RESOLUTION_16);
@@ -553,6 +573,31 @@ GPUParticlesCollisionSDF3D::Resolution GPUParticlesCollisionSDF3D::get_resolutio
return resolution;
}
+void GPUParticlesCollisionSDF3D::set_bake_mask(uint32_t p_mask) {
+ bake_mask = p_mask;
+ update_configuration_warnings();
+}
+
+uint32_t GPUParticlesCollisionSDF3D::get_bake_mask() const {
+ return bake_mask;
+}
+
+void GPUParticlesCollisionSDF3D::set_bake_mask_value(int p_layer_number, bool p_value) {
+ ERR_FAIL_COND_MSG(p_layer_number < 1 || p_layer_number > 20, vformat("The render layer number (%d) must be between 1 and 20 (inclusive).", p_layer_number));
+ uint32_t mask = get_bake_mask();
+ if (p_value) {
+ mask |= 1 << (p_layer_number - 1);
+ } else {
+ mask &= ~(1 << (p_layer_number - 1));
+ }
+ set_bake_mask(mask);
+}
+
+bool GPUParticlesCollisionSDF3D::get_bake_mask_value(int p_layer_number) const {
+ ERR_FAIL_COND_V_MSG(p_layer_number < 1 || p_layer_number > 20, false, vformat("The render layer number (%d) must be between 1 and 20 (inclusive).", p_layer_number));
+ return bake_mask & (1 << (p_layer_number - 1));
+}
+
void GPUParticlesCollisionSDF3D::set_texture(const Ref<Texture3D> &p_texture) {
texture = p_texture;
RID tex = texture.is_valid() ? texture->get_rid() : RID();
diff --git a/scene/3d/gpu_particles_collision_3d.h b/scene/3d/gpu_particles_collision_3d.h
index 4b2cb930fa..712bd015ff 100644
--- a/scene/3d/gpu_particles_collision_3d.h
+++ b/scene/3d/gpu_particles_collision_3d.h
@@ -110,6 +110,7 @@ public:
private:
Vector3 extents = Vector3(1, 1, 1);
Resolution resolution = RESOLUTION_64;
+ uint32_t bake_mask = 0xFFFFFFFF;
Ref<Texture3D> texture;
float thickness = 1.0;
@@ -161,6 +162,8 @@ protected:
static void _bind_methods();
public:
+ virtual TypedArray<String> get_configuration_warnings() const override;
+
void set_thickness(float p_thickness);
float get_thickness() const;
@@ -170,6 +173,12 @@ public:
void set_resolution(Resolution p_resolution);
Resolution get_resolution() const;
+ void set_bake_mask(uint32_t p_mask);
+ uint32_t get_bake_mask() const;
+
+ void set_bake_mask_value(int p_layer_number, bool p_enable);
+ bool get_bake_mask_value(int p_layer_number) const;
+
void set_texture(const Ref<Texture3D> &p_texture);
Ref<Texture3D> get_texture() const;
diff --git a/scene/3d/joint_3d.cpp b/scene/3d/joint_3d.cpp
index b0509475a7..d5cab6728a 100644
--- a/scene/3d/joint_3d.cpp
+++ b/scene/3d/joint_3d.cpp
@@ -221,11 +221,11 @@ void Joint3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_exclude_nodes_from_collision", "enable"), &Joint3D::set_exclude_nodes_from_collision);
ClassDB::bind_method(D_METHOD("get_exclude_nodes_from_collision"), &Joint3D::get_exclude_nodes_from_collision);
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_a", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody3D"), "set_node_a", "get_node_a");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "nodes/node_b", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody3D"), "set_node_b", "get_node_b");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "solver/priority", PROPERTY_HINT_RANGE, "1,8,1"), "set_solver_priority", "get_solver_priority");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_a", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody3D"), "set_node_a", "get_node_a");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_b", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody3D"), "set_node_b", "get_node_b");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "solver_priority", PROPERTY_HINT_RANGE, "1,8,1"), "set_solver_priority", "get_solver_priority");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision/exclude_nodes"), "set_exclude_nodes_from_collision", "get_exclude_nodes_from_collision");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exclude_nodes_from_collision"), "set_exclude_nodes_from_collision", "get_exclude_nodes_from_collision");
}
Joint3D::Joint3D() {
@@ -292,22 +292,6 @@ PinJoint3D::PinJoint3D() {
///////////////////////////////////
-void HingeJoint3D::_set_upper_limit(real_t p_limit) {
- set_param(PARAM_LIMIT_UPPER, Math::deg2rad(p_limit));
-}
-
-real_t HingeJoint3D::_get_upper_limit() const {
- return Math::rad2deg(get_param(PARAM_LIMIT_UPPER));
-}
-
-void HingeJoint3D::_set_lower_limit(real_t p_limit) {
- set_param(PARAM_LIMIT_LOWER, Math::deg2rad(p_limit));
-}
-
-real_t HingeJoint3D::_get_lower_limit() const {
- return Math::rad2deg(get_param(PARAM_LIMIT_LOWER));
-}
-
void HingeJoint3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &HingeJoint3D::set_param);
ClassDB::bind_method(D_METHOD("get_param", "param"), &HingeJoint3D::get_param);
@@ -315,17 +299,11 @@ void HingeJoint3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_flag", "flag", "enabled"), &HingeJoint3D::set_flag);
ClassDB::bind_method(D_METHOD("get_flag", "flag"), &HingeJoint3D::get_flag);
- ClassDB::bind_method(D_METHOD("_set_upper_limit", "upper_limit"), &HingeJoint3D::_set_upper_limit);
- ClassDB::bind_method(D_METHOD("_get_upper_limit"), &HingeJoint3D::_get_upper_limit);
-
- ClassDB::bind_method(D_METHOD("_set_lower_limit", "lower_limit"), &HingeJoint3D::_set_lower_limit);
- ClassDB::bind_method(D_METHOD("_get_lower_limit"), &HingeJoint3D::_get_lower_limit);
-
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "params/bias", PROPERTY_HINT_RANGE, "0.00,0.99,0.01"), "set_param", "get_param", PARAM_BIAS);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit/enable"), "set_flag", "get_flag", FLAG_USE_LIMIT);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit/upper", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_upper_limit", "_get_upper_limit");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit/lower", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_lower_limit", "_get_lower_limit");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/upper", PROPERTY_HINT_RANGE, "-180,180,0.1,radians"), "set_param", "get_param", PARAM_LIMIT_UPPER);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/lower", PROPERTY_HINT_RANGE, "-180,180,0.1,radians"), "set_param", "get_param", PARAM_LIMIT_LOWER);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"), "set_param", "get_param", PARAM_LIMIT_BIAS);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_SOFTNESS);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/relaxation", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param", "get_param", PARAM_LIMIT_RELAXATION);
@@ -420,34 +398,10 @@ HingeJoint3D::HingeJoint3D() {
/////////////////////////////////////////////////
-//////////////////////////////////
-
-void SliderJoint3D::_set_upper_limit_angular(real_t p_limit_angular) {
- set_param(PARAM_ANGULAR_LIMIT_UPPER, Math::deg2rad(p_limit_angular));
-}
-
-real_t SliderJoint3D::_get_upper_limit_angular() const {
- return Math::rad2deg(get_param(PARAM_ANGULAR_LIMIT_UPPER));
-}
-
-void SliderJoint3D::_set_lower_limit_angular(real_t p_limit_angular) {
- set_param(PARAM_ANGULAR_LIMIT_LOWER, Math::deg2rad(p_limit_angular));
-}
-
-real_t SliderJoint3D::_get_lower_limit_angular() const {
- return Math::rad2deg(get_param(PARAM_ANGULAR_LIMIT_LOWER));
-}
-
void SliderJoint3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &SliderJoint3D::set_param);
ClassDB::bind_method(D_METHOD("get_param", "param"), &SliderJoint3D::get_param);
- ClassDB::bind_method(D_METHOD("_set_upper_limit_angular", "upper_limit_angular"), &SliderJoint3D::_set_upper_limit_angular);
- ClassDB::bind_method(D_METHOD("_get_upper_limit_angular"), &SliderJoint3D::_get_upper_limit_angular);
-
- ClassDB::bind_method(D_METHOD("_set_lower_limit_angular", "lower_limit_angular"), &SliderJoint3D::_set_lower_limit_angular);
- ClassDB::bind_method(D_METHOD("_get_lower_limit_angular"), &SliderJoint3D::_get_lower_limit_angular);
-
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/upper_distance", PROPERTY_HINT_RANGE, "-1024,1024,0.01,suffix:m"), "set_param", "get_param", PARAM_LINEAR_LIMIT_UPPER);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/lower_distance", PROPERTY_HINT_RANGE, "-1024,1024,0.01,suffix:m"), "set_param", "get_param", PARAM_LINEAR_LIMIT_LOWER);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_limit/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_LIMIT_SOFTNESS);
@@ -460,8 +414,8 @@ void SliderJoint3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_ortho/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_RESTITUTION);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_ortho/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_LINEAR_ORTHOGONAL_DAMPING);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_upper_limit_angular", "_get_upper_limit_angular");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_lower_limit_angular", "_get_lower_limit_angular");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.1,radians"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_UPPER);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.1,radians"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_LOWER);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_SOFTNESS);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_RESTITUTION);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit/damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"), "set_param", "get_param", PARAM_ANGULAR_LIMIT_DAMPING);
@@ -562,34 +516,12 @@ SliderJoint3D::SliderJoint3D() {
//////////////////////////////////
-void ConeTwistJoint3D::_set_swing_span(real_t p_limit_angular) {
- set_param(PARAM_SWING_SPAN, Math::deg2rad(p_limit_angular));
-}
-
-real_t ConeTwistJoint3D::_get_swing_span() const {
- return Math::rad2deg(get_param(PARAM_SWING_SPAN));
-}
-
-void ConeTwistJoint3D::_set_twist_span(real_t p_limit_angular) {
- set_param(PARAM_TWIST_SPAN, Math::deg2rad(p_limit_angular));
-}
-
-real_t ConeTwistJoint3D::_get_twist_span() const {
- return Math::rad2deg(get_param(PARAM_TWIST_SPAN));
-}
-
void ConeTwistJoint3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &ConeTwistJoint3D::set_param);
ClassDB::bind_method(D_METHOD("get_param", "param"), &ConeTwistJoint3D::get_param);
- ClassDB::bind_method(D_METHOD("_set_swing_span", "swing_span"), &ConeTwistJoint3D::_set_swing_span);
- ClassDB::bind_method(D_METHOD("_get_swing_span"), &ConeTwistJoint3D::_get_swing_span);
-
- ClassDB::bind_method(D_METHOD("_set_twist_span", "twist_span"), &ConeTwistJoint3D::_set_twist_span);
- ClassDB::bind_method(D_METHOD("_get_twist_span"), &ConeTwistJoint3D::_get_twist_span);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "swing_span", PROPERTY_HINT_RANGE, "-180,180,0.1"), "_set_swing_span", "_get_swing_span");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "twist_span", PROPERTY_HINT_RANGE, "-40000,40000,0.1"), "_set_twist_span", "_get_twist_span");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "swing_span", PROPERTY_HINT_RANGE, "-180,180,0.1,radians"), "set_param", "get_param", PARAM_SWING_SPAN);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "twist_span", PROPERTY_HINT_RANGE, "-40000,40000,0.1,radians"), "set_param", "get_param", PARAM_TWIST_SPAN);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "bias", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_BIAS);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"), "set_param", "get_param", PARAM_SOFTNESS);
@@ -620,8 +552,6 @@ real_t ConeTwistJoint3D::get_param(Param p_param) const {
void ConeTwistJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) {
Transform3D gt = get_global_transform();
- //Vector3 cone_twistpos = gt.origin;
- //Vector3 cone_twistdir = gt.basis.get_axis(2);
Transform3D ainv = body_a->get_global_transform().affine_inverse();
@@ -652,73 +582,7 @@ ConeTwistJoint3D::ConeTwistJoint3D() {
/////////////////////////////////////////////////////////////////////
-void Generic6DOFJoint3D::_set_angular_hi_limit_x(real_t p_limit_angular) {
- set_param_x(PARAM_ANGULAR_UPPER_LIMIT, Math::deg2rad(p_limit_angular));
-}
-
-real_t Generic6DOFJoint3D::_get_angular_hi_limit_x() const {
- return Math::rad2deg(get_param_x(PARAM_ANGULAR_UPPER_LIMIT));
-}
-
-void Generic6DOFJoint3D::_set_angular_lo_limit_x(real_t p_limit_angular) {
- set_param_x(PARAM_ANGULAR_LOWER_LIMIT, Math::deg2rad(p_limit_angular));
-}
-
-real_t Generic6DOFJoint3D::_get_angular_lo_limit_x() const {
- return Math::rad2deg(get_param_x(PARAM_ANGULAR_LOWER_LIMIT));
-}
-
-void Generic6DOFJoint3D::_set_angular_hi_limit_y(real_t p_limit_angular) {
- set_param_y(PARAM_ANGULAR_UPPER_LIMIT, Math::deg2rad(p_limit_angular));
-}
-
-real_t Generic6DOFJoint3D::_get_angular_hi_limit_y() const {
- return Math::rad2deg(get_param_y(PARAM_ANGULAR_UPPER_LIMIT));
-}
-
-void Generic6DOFJoint3D::_set_angular_lo_limit_y(real_t p_limit_angular) {
- set_param_y(PARAM_ANGULAR_LOWER_LIMIT, Math::deg2rad(p_limit_angular));
-}
-
-real_t Generic6DOFJoint3D::_get_angular_lo_limit_y() const {
- return Math::rad2deg(get_param_y(PARAM_ANGULAR_LOWER_LIMIT));
-}
-
-void Generic6DOFJoint3D::_set_angular_hi_limit_z(real_t p_limit_angular) {
- set_param_z(PARAM_ANGULAR_UPPER_LIMIT, Math::deg2rad(p_limit_angular));
-}
-
-real_t Generic6DOFJoint3D::_get_angular_hi_limit_z() const {
- return Math::rad2deg(get_param_z(PARAM_ANGULAR_UPPER_LIMIT));
-}
-
-void Generic6DOFJoint3D::_set_angular_lo_limit_z(real_t p_limit_angular) {
- set_param_z(PARAM_ANGULAR_LOWER_LIMIT, Math::deg2rad(p_limit_angular));
-}
-
-real_t Generic6DOFJoint3D::_get_angular_lo_limit_z() const {
- return Math::rad2deg(get_param_z(PARAM_ANGULAR_LOWER_LIMIT));
-}
-
void Generic6DOFJoint3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_set_angular_hi_limit_x", "angle"), &Generic6DOFJoint3D::_set_angular_hi_limit_x);
- ClassDB::bind_method(D_METHOD("_get_angular_hi_limit_x"), &Generic6DOFJoint3D::_get_angular_hi_limit_x);
-
- ClassDB::bind_method(D_METHOD("_set_angular_lo_limit_x", "angle"), &Generic6DOFJoint3D::_set_angular_lo_limit_x);
- ClassDB::bind_method(D_METHOD("_get_angular_lo_limit_x"), &Generic6DOFJoint3D::_get_angular_lo_limit_x);
-
- ClassDB::bind_method(D_METHOD("_set_angular_hi_limit_y", "angle"), &Generic6DOFJoint3D::_set_angular_hi_limit_y);
- ClassDB::bind_method(D_METHOD("_get_angular_hi_limit_y"), &Generic6DOFJoint3D::_get_angular_hi_limit_y);
-
- ClassDB::bind_method(D_METHOD("_set_angular_lo_limit_y", "angle"), &Generic6DOFJoint3D::_set_angular_lo_limit_y);
- ClassDB::bind_method(D_METHOD("_get_angular_lo_limit_y"), &Generic6DOFJoint3D::_get_angular_lo_limit_y);
-
- ClassDB::bind_method(D_METHOD("_set_angular_hi_limit_z", "angle"), &Generic6DOFJoint3D::_set_angular_hi_limit_z);
- ClassDB::bind_method(D_METHOD("_get_angular_hi_limit_z"), &Generic6DOFJoint3D::_get_angular_hi_limit_z);
-
- ClassDB::bind_method(D_METHOD("_set_angular_lo_limit_z", "angle"), &Generic6DOFJoint3D::_set_angular_lo_limit_z);
- ClassDB::bind_method(D_METHOD("_get_angular_lo_limit_z"), &Generic6DOFJoint3D::_get_angular_lo_limit_z);
-
ClassDB::bind_method(D_METHOD("set_param_x", "param", "value"), &Generic6DOFJoint3D::set_param_x);
ClassDB::bind_method(D_METHOD("get_param_x", "param"), &Generic6DOFJoint3D::get_param_x);
@@ -794,8 +658,8 @@ void Generic6DOFJoint3D::_bind_methods() {
ADD_GROUP("Angular Limit", "angular_limit_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_ANGULAR_LIMIT);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_x/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_x", "_get_angular_hi_limit_x");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_x/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_x", "_get_angular_lo_limit_x");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01,radians"), "set_param_x", "get_param_x", PARAM_ANGULAR_UPPER_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01,radians"), "set_param_x", "get_param_x", PARAM_ANGULAR_LOWER_LIMIT);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_ANGULAR_LIMIT_SOFTNESS);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_ANGULAR_RESTITUTION);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_ANGULAR_DAMPING);
@@ -803,8 +667,8 @@ void Generic6DOFJoint3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_x/erp"), "set_param_x", "get_param_x", PARAM_ANGULAR_ERP);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_ANGULAR_LIMIT);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_y/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_y", "_get_angular_hi_limit_y");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_y/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_y", "_get_angular_lo_limit_y");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01,radians"), "set_param_y", "get_param_y", PARAM_ANGULAR_UPPER_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01,radians"), "set_param_y", "get_param_y", PARAM_ANGULAR_LOWER_LIMIT);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_ANGULAR_LIMIT_SOFTNESS);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_ANGULAR_RESTITUTION);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_ANGULAR_DAMPING);
@@ -812,8 +676,8 @@ void Generic6DOFJoint3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_y/erp"), "set_param_y", "get_param_y", PARAM_ANGULAR_ERP);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_ANGULAR_LIMIT);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_z/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_z", "_get_angular_hi_limit_z");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_limit_z/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_z", "_get_angular_lo_limit_z");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01,radians"), "set_param_z", "get_param_z", PARAM_ANGULAR_UPPER_LIMIT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01,radians"), "set_param_z", "get_param_z", PARAM_ANGULAR_LOWER_LIMIT);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_ANGULAR_LIMIT_SOFTNESS);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_ANGULAR_RESTITUTION);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_limit_z/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_ANGULAR_DAMPING);
diff --git a/scene/3d/joint_3d.h b/scene/3d/joint_3d.h
index ea356ef3b7..cb967023e8 100644
--- a/scene/3d/joint_3d.h
+++ b/scene/3d/joint_3d.h
@@ -136,12 +136,6 @@ protected:
virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override;
static void _bind_methods();
- void _set_upper_limit(real_t p_limit);
- real_t _get_upper_limit() const;
-
- void _set_lower_limit(real_t p_limit);
- real_t _get_lower_limit() const;
-
public:
void set_param(Param p_param, real_t p_value);
real_t get_param(Param p_param) const;
@@ -188,12 +182,6 @@ public:
};
protected:
- void _set_upper_limit_angular(real_t p_limit_angular);
- real_t _get_upper_limit_angular() const;
-
- void _set_lower_limit_angular(real_t p_limit_angular);
- real_t _get_lower_limit_angular() const;
-
real_t params[PARAM_MAX];
virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override;
static void _bind_methods();
@@ -221,12 +209,6 @@ public:
};
protected:
- void _set_swing_span(real_t p_limit_angular);
- real_t _get_swing_span() const;
-
- void _set_twist_span(real_t p_limit_angular);
- real_t _get_twist_span() const;
-
real_t params[PARAM_MAX];
virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override;
static void _bind_methods();
@@ -281,24 +263,6 @@ public:
};
protected:
- void _set_angular_hi_limit_x(real_t p_limit_angular);
- real_t _get_angular_hi_limit_x() const;
-
- void _set_angular_hi_limit_y(real_t p_limit_angular);
- real_t _get_angular_hi_limit_y() const;
-
- void _set_angular_hi_limit_z(real_t p_limit_angular);
- real_t _get_angular_hi_limit_z() const;
-
- void _set_angular_lo_limit_x(real_t p_limit_angular);
- real_t _get_angular_lo_limit_x() const;
-
- void _set_angular_lo_limit_y(real_t p_limit_angular);
- real_t _get_angular_lo_limit_y() const;
-
- void _set_angular_lo_limit_z(real_t p_limit_angular);
- real_t _get_angular_lo_limit_z() const;
-
real_t params_x[PARAM_MAX];
bool flags_x[FLAG_MAX];
real_t params_y[PARAM_MAX];
diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp
index bc435c5451..e4a7cf6ee5 100644
--- a/scene/3d/label_3d.cpp
+++ b/scene/3d/label_3d.cpp
@@ -31,8 +31,10 @@
#include "label_3d.h"
#include "core/core_string_names.h"
+#include "scene/main/viewport.h"
#include "scene/resources/theme.h"
#include "scene/scene_string_names.h"
+#include "scene/theme/theme_db.h"
void Label3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_horizontal_alignment", "alignment"), &Label3D::set_horizontal_alignment);
@@ -126,7 +128,7 @@ void Label3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "no_depth_test"), "set_draw_flag", "get_draw_flag", FLAG_DISABLE_DEPTH_TEST);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "fixed_size"), "set_draw_flag", "get_draw_flag", FLAG_FIXED_SIZE);
ADD_PROPERTY(PropertyInfo(Variant::INT, "alpha_cut", PROPERTY_HINT_ENUM, "Disabled,Discard,Opaque Pre-Pass"), "set_alpha_cut_mode", "get_alpha_cut_mode");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_scissor_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_alpha_scissor_threshold", "get_alpha_scissor_threshold");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_scissor_threshold", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_alpha_scissor_threshold", "get_alpha_scissor_threshold");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropic,Linear Mipmap Anisotropic"), "set_texture_filter", "get_texture_filter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "render_priority", PROPERTY_HINT_RANGE, itos(RS::MATERIAL_RENDER_PRIORITY_MIN) + "," + itos(RS::MATERIAL_RENDER_PRIORITY_MAX) + ",1"), "set_render_priority", "get_render_priority");
ADD_PROPERTY(PropertyInfo(Variant::INT, "outline_render_priority", PROPERTY_HINT_RANGE, itos(RS::MATERIAL_RENDER_PRIORITY_MIN) + "," + itos(RS::MATERIAL_RENDER_PRIORITY_MAX) + ",1"), "set_outline_render_priority", "get_outline_render_priority");
@@ -162,9 +164,19 @@ void Label3D::_bind_methods() {
BIND_ENUM_CONSTANT(ALPHA_CUT_OPAQUE_PREPASS);
}
-void Label3D::_validate_property(PropertyInfo &property) const {
- if (property.name == "material_override" || property.name == "material_overlay") {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void Label3D::_validate_property(PropertyInfo &p_property) const {
+ if (
+ p_property.name == "material_override" ||
+ p_property.name == "material_overlay" ||
+ p_property.name == "lod_bias" ||
+ p_property.name == "gi_mode" ||
+ p_property.name == "gi_lightmap_scale") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+
+ if (p_property.name == "cast_shadow" && alpha_cut == ALPHA_CUT_DISABLED) {
+ // Alpha-blended materials can't cast shadows.
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
@@ -174,6 +186,14 @@ void Label3D::_notification(int p_what) {
if (!pending_update) {
_im_update();
}
+ Viewport *viewport = get_viewport();
+ ERR_FAIL_COND(!viewport);
+ viewport->connect("size_changed", callable_mp(this, &Label3D::_font_changed));
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ Viewport *viewport = get_viewport();
+ ERR_FAIL_COND(!viewport);
+ viewport->disconnect("size_changed", callable_mp(this, &Label3D::_font_changed));
} break;
case NOTIFICATION_TRANSLATION_CHANGED: {
String new_text = tr(text);
@@ -422,7 +442,7 @@ void Label3D::_shape() {
TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
}
- Array stt;
+ TypedArray<Vector2i> stt;
if (st_parser == TextServer::STRUCTURED_TEXT_CUSTOM) {
GDVIRTUAL_CALL(_structured_text_parser, st_args, text, stt);
} else {
@@ -715,13 +735,13 @@ Ref<Font> Label3D::_get_font_or_default() const {
}
// Check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
List<StringName> theme_types;
- Theme::get_project_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
+ ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
for (const StringName &E : theme_types) {
- if (Theme::get_project_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
- Ref<Font> f = Theme::get_project_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ Ref<Font> f = ThemeDB::get_singleton()->get_project_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, Callable(const_cast<Label3D *>(this), "_font_changed"));
@@ -734,11 +754,11 @@ Ref<Font> Label3D::_get_font_or_default() const {
// Lastly, fall back on the items defined in the default Theme, if they exist.
{
List<StringName> theme_types;
- Theme::get_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
for (const StringName &E : theme_types) {
- if (Theme::get_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
- Ref<Font> f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ Ref<Font> f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, Callable(const_cast<Label3D *>(this), "_font_changed"));
@@ -749,7 +769,7 @@ Ref<Font> Label3D::_get_font_or_default() const {
}
// If they don't exist, use any type to return the default/empty value.
- Ref<Font> f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
+ Ref<Font> f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, Callable(const_cast<Label3D *>(this), "_font_changed"));
@@ -889,6 +909,7 @@ void Label3D::set_alpha_cut_mode(AlphaCutMode p_mode) {
if (alpha_cut != p_mode) {
alpha_cut = p_mode;
_queue_update();
+ notify_property_list_changed();
}
}
@@ -927,7 +948,12 @@ Label3D::Label3D() {
mesh = RenderingServer::get_singleton()->mesh_create();
+ // Disable shadow casting by default to improve performance and avoid unintended visual artifacts.
set_cast_shadows_setting(SHADOW_CASTING_SETTING_OFF);
+
+ // Label3D can't contribute to GI in any way, so disable it to improve performance.
+ set_gi_mode(GI_MODE_DISABLED);
+
set_base(mesh);
}
diff --git a/scene/3d/label_3d.h b/scene/3d/label_3d.h
index 4498e89517..3c9a758e6e 100644
--- a/scene/3d/label_3d.h
+++ b/scene/3d/label_3d.h
@@ -55,7 +55,7 @@ public:
};
private:
- real_t pixel_size = 0.01;
+ real_t pixel_size = 0.005;
bool flags[FLAG_MAX] = {};
AlphaCutMode alpha_cut = ALPHA_CUT_DISABLED;
float alpha_scissor_threshold = 0.5;
@@ -109,7 +109,7 @@ private:
TextServer::AutowrapMode autowrap_mode = TextServer::AUTOWRAP_OFF;
float width = 500.0;
- int font_size = 16;
+ int font_size = 32;
Ref<Font> font_override;
mutable Ref<Font> theme_font;
Color modulate = Color(1, 1, 1, 1);
@@ -117,7 +117,7 @@ private:
int outline_render_priority = -1;
int render_priority = 0;
- int outline_size = 0;
+ int outline_size = 12;
Color outline_modulate = Color(0, 0, 0, 1);
float line_spacing = 0.f;
@@ -149,7 +149,7 @@ protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _im_update();
void _font_changed();
diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp
index 678c217676..8d96d13f0c 100644
--- a/scene/3d/light_3d.cpp
+++ b/scene/3d/light_3d.cpp
@@ -149,7 +149,7 @@ AABB Light3D::get_aabb() const {
} else if (type == RenderingServer::LIGHT_SPOT) {
real_t len = param[PARAM_RANGE];
- real_t size = Math::tan(Math::deg2rad(param[PARAM_SPOT_ANGLE])) * len;
+ real_t size = Math::tan(Math::deg_to_rad(param[PARAM_SPOT_ANGLE])) * len;
return AABB(Vector3(-size, -size, -len), Vector3(size * 2, size * 2, len));
}
@@ -223,21 +223,19 @@ bool Light3D::is_editor_only() const {
return editor_only;
}
-void Light3D::_validate_property(PropertyInfo &property) const {
- if (!shadow && (property.name == "shadow_bias" || property.name == "shadow_normal_bias" || property.name == "shadow_reverse_cull_face" || property.name == "shadow_transmittance_bias" || property.name == "shadow_fog_fade" || property.name == "shadow_blur" || property.name == "distance_fade_shadow")) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void Light3D::_validate_property(PropertyInfo &p_property) const {
+ if (!shadow && (p_property.name == "shadow_bias" || p_property.name == "shadow_normal_bias" || p_property.name == "shadow_reverse_cull_face" || p_property.name == "shadow_transmittance_bias" || p_property.name == "shadow_fog_fade" || p_property.name == "shadow_opacity" || p_property.name == "shadow_blur" || p_property.name == "distance_fade_shadow")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (get_light_type() != RS::LIGHT_DIRECTIONAL && property.name == "light_angular_distance") {
+ if (get_light_type() != RS::LIGHT_DIRECTIONAL && p_property.name == "light_angular_distance") {
// Angular distance is only used in DirectionalLight3D.
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (!distance_fade_enabled && (property.name == "distance_fade_begin" || property.name == "distance_fade_shadow" || property.name == "distance_fade_length")) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (!distance_fade_enabled && (p_property.name == "distance_fade_begin" || p_property.name == "distance_fade_shadow" || p_property.name == "distance_fade_length")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
-
- VisualInstance3D::_validate_property(property);
}
void Light3D::_bind_methods() {
@@ -299,6 +297,7 @@ void Light3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_reverse_cull_face"), "set_shadow_reverse_cull_face", "get_shadow_reverse_cull_face");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_transmittance_bias", PROPERTY_HINT_RANGE, "-16,16,0.001"), "set_param", "get_param", PARAM_TRANSMITTANCE_BIAS);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_fog_fade", PROPERTY_HINT_RANGE, "0.001,10,0.001"), "set_param", "get_param", PARAM_SHADOW_VOLUMETRIC_FOG_FADE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_opacity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_OPACITY);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_blur", PROPERTY_HINT_RANGE, "0,10,0.001"), "set_param", "get_param", PARAM_SHADOW_BLUR);
ADD_GROUP("Distance Fade", "distance_fade_");
@@ -328,6 +327,7 @@ void Light3D::_bind_methods() {
BIND_ENUM_CONSTANT(PARAM_SHADOW_NORMAL_BIAS);
BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS);
BIND_ENUM_CONSTANT(PARAM_SHADOW_PANCAKE_SIZE);
+ BIND_ENUM_CONSTANT(PARAM_SHADOW_OPACITY);
BIND_ENUM_CONSTANT(PARAM_SHADOW_BLUR);
BIND_ENUM_CONSTANT(PARAM_SHADOW_VOLUMETRIC_FOG_FADE);
BIND_ENUM_CONSTANT(PARAM_TRANSMITTANCE_BIAS);
@@ -375,6 +375,7 @@ Light3D::Light3D(RenderingServer::LightType p_type) {
set_param(PARAM_SHADOW_SPLIT_3_OFFSET, 0.5);
set_param(PARAM_SHADOW_FADE_START, 0.8);
set_param(PARAM_SHADOW_PANCAKE_SIZE, 20.0);
+ set_param(PARAM_SHADOW_OPACITY, 1.0);
set_param(PARAM_SHADOW_BLUR, 1.0);
set_param(PARAM_SHADOW_BIAS, 0.03);
set_param(PARAM_SHADOW_NORMAL_BIAS, 1.0);
@@ -426,29 +427,27 @@ DirectionalLight3D::SkyMode DirectionalLight3D::get_sky_mode() const {
return sky_mode;
}
-void DirectionalLight3D::_validate_property(PropertyInfo &property) const {
- if (shadow_mode == SHADOW_ORTHOGONAL && (property.name == "directional_shadow_split_1" || property.name == "directional_shadow_blend_splits")) {
+void DirectionalLight3D::_validate_property(PropertyInfo &p_property) const {
+ if (shadow_mode == SHADOW_ORTHOGONAL && (p_property.name == "directional_shadow_split_1" || p_property.name == "directional_shadow_blend_splits")) {
// Split 2 and split blending are only used with the PSSM 2 Splits and PSSM 4 Splits shadow modes.
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if ((shadow_mode == SHADOW_ORTHOGONAL || shadow_mode == SHADOW_PARALLEL_2_SPLITS) && (property.name == "directional_shadow_split_2" || property.name == "directional_shadow_split_3")) {
+ if ((shadow_mode == SHADOW_ORTHOGONAL || shadow_mode == SHADOW_PARALLEL_2_SPLITS) && (p_property.name == "directional_shadow_split_2" || p_property.name == "directional_shadow_split_3")) {
// Splits 3 and 4 are only used with the PSSM 4 Splits shadow mode.
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "light_size" || property.name == "light_projector" || property.name == "light_specular") {
+ if (p_property.name == "light_size" || p_property.name == "light_projector" || p_property.name == "light_specular") {
// Not implemented in DirectionalLight3D (`light_size` is replaced by `light_angular_distance`).
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "distance_fade_enabled" || property.name == "distance_fade_begin" || property.name == "distance_fade_shadow" || property.name == "distance_fade_length") {
+ if (p_property.name == "distance_fade_enabled" || p_property.name == "distance_fade_begin" || p_property.name == "distance_fade_shadow" || p_property.name == "distance_fade_length") {
// Not relevant for DirectionalLight3D, as the light LOD system only pertains to point lights.
// For DirectionalLight3D, `directional_shadow_max_distance` can be used instead.
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
}
-
- Light3D::_validate_property(property);
}
void DirectionalLight3D::_bind_methods() {
diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h
index 6ff332df5a..035ba50e42 100644
--- a/scene/3d/light_3d.h
+++ b/scene/3d/light_3d.h
@@ -54,6 +54,7 @@ public:
PARAM_SHADOW_NORMAL_BIAS = RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS,
PARAM_SHADOW_BIAS = RS::LIGHT_PARAM_SHADOW_BIAS,
PARAM_SHADOW_PANCAKE_SIZE = RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE,
+ PARAM_SHADOW_OPACITY = RS::LIGHT_PARAM_SHADOW_OPACITY,
PARAM_SHADOW_BLUR = RS::LIGHT_PARAM_SHADOW_BLUR,
PARAM_SHADOW_VOLUMETRIC_FOG_FADE = RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE,
PARAM_TRANSMITTANCE_BIAS = RS::LIGHT_PARAM_TRANSMITTANCE_BIAS,
@@ -92,7 +93,7 @@ protected:
static void _bind_methods();
void _notification(int p_what);
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
Light3D(RenderingServer::LightType p_type);
@@ -170,7 +171,7 @@ private:
protected:
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_shadow_mode(ShadowMode p_mode);
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index 6b6a2eff9e..7efda6db32 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -1410,17 +1410,16 @@ LightmapGI::GenerateProbes LightmapGI::get_generate_probes() const {
return gen_probes;
}
-void LightmapGI::_validate_property(PropertyInfo &property) const {
- if (property.name == "environment_custom_sky" && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) {
- property.usage = PROPERTY_USAGE_NONE;
+void LightmapGI::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "environment_custom_sky" && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "environment_custom_color" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "environment_custom_color" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "environment_custom_energy" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "environment_custom_energy" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- VisualInstance3D::_validate_property(property);
}
void LightmapGI::_bind_methods() {
diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h
index 85150b833f..87add9facc 100644
--- a/scene/3d/lightmap_gi.h
+++ b/scene/3d/lightmap_gi.h
@@ -216,7 +216,7 @@ private:
void _gen_new_positions_from_octree(const GenProbesOctree *p_cell, float p_cell_size, const Vector<Vector3> &probe_positions, LocalVector<Vector3> &new_probe_positions, HashMap<Vector3i, bool> &positions_used, const AABB &p_bounds);
protected:
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
void _notification(int p_what);
diff --git a/scene/3d/position_3d.cpp b/scene/3d/marker_3d.cpp
index 7dc1b1ace0..3987172561 100644
--- a/scene/3d/position_3d.cpp
+++ b/scene/3d/marker_3d.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* position_3d.cpp */
+/* marker_3d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "position_3d.h"
+#include "marker_3d.h"
-Position3D::Position3D() {
+Marker3D::Marker3D() {
}
diff --git a/scene/3d/position_3d.h b/scene/3d/marker_3d.h
index 5514399e6e..95caa101c5 100644
--- a/scene/3d/position_3d.h
+++ b/scene/3d/marker_3d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* position_3d.h */
+/* marker_3d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,16 +28,16 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef POSITION_3D_H
-#define POSITION_3D_H
+#ifndef MARKER_3D_H
+#define MARKER_3D_H
#include "scene/3d/node_3d.h"
-class Position3D : public Node3D {
- GDCLASS(Position3D, Node3D);
+class Marker3D : public Node3D {
+ GDCLASS(Marker3D, Node3D);
public:
- Position3D();
+ Marker3D();
};
-#endif // POSITION_3D_H
+#endif // MARKER_3D_H
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index 3752713d6a..34e84861a2 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -53,8 +53,8 @@ void NavigationAgent3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_ignore_y", "ignore"), &NavigationAgent3D::set_ignore_y);
ClassDB::bind_method(D_METHOD("get_ignore_y"), &NavigationAgent3D::get_ignore_y);
- ClassDB::bind_method(D_METHOD("set_neighbor_dist", "neighbor_dist"), &NavigationAgent3D::set_neighbor_dist);
- ClassDB::bind_method(D_METHOD("get_neighbor_dist"), &NavigationAgent3D::get_neighbor_dist);
+ ClassDB::bind_method(D_METHOD("set_neighbor_distance", "neighbor_distance"), &NavigationAgent3D::set_neighbor_distance);
+ ClassDB::bind_method(D_METHOD("get_neighbor_distance"), &NavigationAgent3D::get_neighbor_distance);
ClassDB::bind_method(D_METHOD("set_max_neighbors", "max_neighbors"), &NavigationAgent3D::set_max_neighbors);
ClassDB::bind_method(D_METHOD("get_max_neighbors"), &NavigationAgent3D::get_max_neighbors);
@@ -101,7 +101,7 @@ void NavigationAgent3D::_bind_methods() {
ADD_GROUP("Avoidance", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:m"), "set_radius", "get_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "neighbor_dist", PROPERTY_HINT_RANGE, "0.1,10000,0.01,suffix:m"), "set_neighbor_dist", "get_neighbor_dist");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "neighbor_distance", PROPERTY_HINT_RANGE, "0.1,10000,0.01,suffix:m"), "set_neighbor_distance", "get_neighbor_distance");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_neighbors", PROPERTY_HINT_RANGE, "1,10000,1"), "set_max_neighbors", "get_max_neighbors");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_horizon", PROPERTY_HINT_RANGE, "0.01,100,0.01,suffix:s"), "set_time_horizon", "get_time_horizon");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_speed", PROPERTY_HINT_RANGE, "0.1,10000,0.01,suffix:m/s"), "set_max_speed", "get_max_speed");
@@ -179,7 +179,7 @@ void NavigationAgent3D::_notification(int p_what) {
NavigationAgent3D::NavigationAgent3D() {
agent = NavigationServer3D::get_singleton()->agent_create();
- set_neighbor_dist(50.0);
+ set_neighbor_distance(50.0);
set_max_neighbors(10);
set_time_horizon(5.0);
set_radius(1.0);
@@ -291,9 +291,9 @@ void NavigationAgent3D::set_ignore_y(bool p_ignore_y) {
NavigationServer3D::get_singleton()->agent_set_ignore_y(agent, ignore_y);
}
-void NavigationAgent3D::set_neighbor_dist(real_t p_dist) {
- neighbor_dist = p_dist;
- NavigationServer3D::get_singleton()->agent_set_neighbor_dist(agent, neighbor_dist);
+void NavigationAgent3D::set_neighbor_distance(real_t p_distance) {
+ neighbor_distance = p_distance;
+ NavigationServer3D::get_singleton()->agent_set_neighbor_distance(agent, neighbor_distance);
}
void NavigationAgent3D::set_max_neighbors(int p_count) {
diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h
index e05f0287f7..35c1b1175a 100644
--- a/scene/3d/navigation_agent_3d.h
+++ b/scene/3d/navigation_agent_3d.h
@@ -52,7 +52,7 @@ class NavigationAgent3D : public Node {
real_t radius = 0.0;
real_t navigation_height_offset = 0.0;
bool ignore_y = false;
- real_t neighbor_dist = 0.0;
+ real_t neighbor_distance = 0.0;
int max_neighbors = 0;
real_t time_horizon = 0.0;
real_t max_speed = 0.0;
@@ -122,9 +122,9 @@ public:
return ignore_y;
}
- void set_neighbor_dist(real_t p_dist);
- real_t get_neighbor_dist() const {
- return neighbor_dist;
+ void set_neighbor_distance(real_t p_distance);
+ real_t get_neighbor_distance() const {
+ return neighbor_distance;
}
void set_max_neighbors(int p_count);
diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp
index c6eda1f9cd..953e52e591 100644
--- a/scene/3d/navigation_obstacle_3d.cpp
+++ b/scene/3d/navigation_obstacle_3d.cpp
@@ -133,7 +133,7 @@ TypedArray<String> NavigationObstacle3D::get_configuration_warnings() const {
}
if (Object::cast_to<StaticBody3D>(get_parent())) {
- warnings.push_back(RTR("The NavigationObstacle3D is intended for constantly moving bodies like CharacterBody3D or RigidDynamicBody3D as it creates only an RVO avoidance radius and does not follow scene geometry exactly."
+ warnings.push_back(RTR("The NavigationObstacle3D is intended for constantly moving bodies like CharacterBody3D or RigidBody3D as it creates only an RVO avoidance radius and does not follow scene geometry exactly."
"\nNot constantly moving or complete static objects should be (re)baked to a NavigationMesh so agents can not only avoid them but also move along those objects outline at high detail"));
}
@@ -141,7 +141,7 @@ TypedArray<String> NavigationObstacle3D::get_configuration_warnings() const {
}
void NavigationObstacle3D::initialize_agent() {
- NavigationServer3D::get_singleton()->agent_set_neighbor_dist(agent, 0.0);
+ NavigationServer3D::get_singleton()->agent_set_neighbor_distance(agent, 0.0);
NavigationServer3D::get_singleton()->agent_set_max_neighbors(agent, 0);
NavigationServer3D::get_singleton()->agent_set_time_horizon(agent, 0.0);
NavigationServer3D::get_singleton()->agent_set_max_speed(agent, 0.0);
diff --git a/scene/3d/navigation_obstacle_3d.h b/scene/3d/navigation_obstacle_3d.h
index 0316fc37a8..7f6af668b6 100644
--- a/scene/3d/navigation_obstacle_3d.h
+++ b/scene/3d/navigation_obstacle_3d.h
@@ -45,7 +45,7 @@ class NavigationObstacle3D : public Node {
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &p_property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
public:
diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp
index 0abb0e8dea..29ad1ba93d 100644
--- a/scene/3d/navigation_region_3d.cpp
+++ b/scene/3d/navigation_region_3d.cpp
@@ -119,7 +119,7 @@ real_t NavigationRegion3D::get_enter_cost() const {
void NavigationRegion3D::set_travel_cost(real_t p_travel_cost) {
ERR_FAIL_COND_MSG(p_travel_cost < 0.0, "The travel_cost must be positive.");
travel_cost = MAX(p_travel_cost, 0.0);
- NavigationServer3D::get_singleton()->region_set_enter_cost(region, travel_cost);
+ NavigationServer3D::get_singleton()->region_set_travel_cost(region, travel_cost);
}
real_t NavigationRegion3D::get_travel_cost() const {
@@ -363,6 +363,12 @@ NavigationRegion3D::~NavigationRegion3D() {
#ifdef DEBUG_ENABLED
void NavigationRegion3D::_update_debug_mesh() {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ // don't update inside Editor as node 3d gizmo takes care of this
+ // as collisions and selections for Editor Viewport need to be updated
+ return;
+ }
+
if (!NavigationServer3D::get_singleton()->get_debug_enabled()) {
if (debug_instance.is_valid()) {
RS::get_singleton()->instance_set_visible(debug_instance, false);
@@ -418,11 +424,14 @@ void NavigationRegion3D::_update_debug_mesh() {
Ref<StandardMaterial3D> face_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_face_material();
Ref<StandardMaterial3D> line_material = NavigationServer3D::get_singleton_mut()->get_debug_navigation_geometry_edge_material();
+ RandomPCG rand;
Color polygon_color = debug_navigation_geometry_face_color;
for (int i = 0; i < polygon_count; i++) {
if (enabled_geometry_face_random_color) {
- polygon_color = debug_navigation_geometry_face_color * (Color(Math::randf(), Math::randf(), Math::randf()));
+ // Generate the polygon color, slightly randomly modified from the settings one.
+ polygon_color.set_hsv(debug_navigation_geometry_face_color.get_h() + rand.random(-1.0, 1.0) * 0.1, debug_navigation_geometry_face_color.get_s(), debug_navigation_geometry_face_color.get_v() + rand.random(-1.0, 1.0) * 0.2);
+ polygon_color.a = debug_navigation_geometry_face_color.a;
}
Vector<int> polygon = navmesh->get_polygon(i);
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index 1de85d57a3..426a8c1684 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -561,8 +561,8 @@ void Node3D::clear_gizmos() {
#endif
}
-Array Node3D::get_gizmos_bind() const {
- Array ret;
+TypedArray<Node3DGizmo> Node3D::get_gizmos_bind() const {
+ TypedArray<Node3DGizmo> ret;
#ifdef TOOLS_ENABLED
for (int i = 0; i < data.gizmos.size(); i++) {
@@ -879,25 +879,25 @@ NodePath Node3D::get_visibility_parent() const {
return visibility_parent_path;
}
-void Node3D::_validate_property(PropertyInfo &property) const {
- if (data.rotation_edit_mode != ROTATION_EDIT_MODE_BASIS && property.name == "basis") {
- property.usage = 0;
+void Node3D::_validate_property(PropertyInfo &p_property) const {
+ if (data.rotation_edit_mode != ROTATION_EDIT_MODE_BASIS && p_property.name == "basis") {
+ p_property.usage = 0;
}
- if (data.rotation_edit_mode == ROTATION_EDIT_MODE_BASIS && property.name == "scale") {
- property.usage = 0;
+ if (data.rotation_edit_mode == ROTATION_EDIT_MODE_BASIS && p_property.name == "scale") {
+ p_property.usage = 0;
}
- if (data.rotation_edit_mode != ROTATION_EDIT_MODE_QUATERNION && property.name == "quaternion") {
- property.usage = 0;
+ if (data.rotation_edit_mode != ROTATION_EDIT_MODE_QUATERNION && p_property.name == "quaternion") {
+ p_property.usage = 0;
}
- if (data.rotation_edit_mode != ROTATION_EDIT_MODE_EULER && property.name == "rotation") {
- property.usage = 0;
+ if (data.rotation_edit_mode != ROTATION_EDIT_MODE_EULER && p_property.name == "rotation") {
+ p_property.usage = 0;
}
- if (data.rotation_edit_mode != ROTATION_EDIT_MODE_EULER && property.name == "rotation_order") {
- property.usage = 0;
+ if (data.rotation_edit_mode != ROTATION_EDIT_MODE_EULER && p_property.name == "rotation_order") {
+ p_property.usage = 0;
}
}
-bool Node3D::property_can_revert(const String &p_name) {
+bool Node3D::_property_can_revert(const StringName &p_name) const {
if (p_name == "basis") {
return true;
} else if (p_name == "scale") {
@@ -912,47 +912,48 @@ bool Node3D::property_can_revert(const String &p_name) {
return false;
}
-Variant Node3D::property_get_revert(const String &p_name) {
- Variant r_ret;
+bool Node3D::_property_get_revert(const StringName &p_name, Variant &r_property) const {
bool valid = false;
if (p_name == "basis") {
Variant variant = PropertyUtils::get_property_default_value(this, "transform", &valid);
if (valid && variant.get_type() == Variant::Type::TRANSFORM3D) {
- r_ret = Transform3D(variant).get_basis();
+ r_property = Transform3D(variant).get_basis();
} else {
- r_ret = Basis();
+ r_property = Basis();
}
} else if (p_name == "scale") {
Variant variant = PropertyUtils::get_property_default_value(this, "transform", &valid);
if (valid && variant.get_type() == Variant::Type::TRANSFORM3D) {
- r_ret = Transform3D(variant).get_basis().get_scale();
+ r_property = Transform3D(variant).get_basis().get_scale();
} else {
- return Vector3(1.0, 1.0, 1.0);
+ r_property = Vector3(1.0, 1.0, 1.0);
}
} else if (p_name == "quaternion") {
Variant variant = PropertyUtils::get_property_default_value(this, "transform", &valid);
if (valid && variant.get_type() == Variant::Type::TRANSFORM3D) {
- r_ret = Quaternion(Transform3D(variant).get_basis().get_rotation_quaternion());
+ r_property = Quaternion(Transform3D(variant).get_basis().get_rotation_quaternion());
} else {
- return Quaternion();
+ r_property = Quaternion();
}
} else if (p_name == "rotation") {
Variant variant = PropertyUtils::get_property_default_value(this, "transform", &valid);
if (valid && variant.get_type() == Variant::Type::TRANSFORM3D) {
- r_ret = Transform3D(variant).get_basis().get_euler_normalized(data.euler_rotation_order);
+ r_property = Transform3D(variant).get_basis().get_euler_normalized(data.euler_rotation_order);
} else {
- return Vector3();
+ r_property = Vector3();
}
} else if (p_name == "position") {
Variant variant = PropertyUtils::get_property_default_value(this, "transform", &valid);
if (valid) {
- r_ret = Transform3D(variant).get_origin();
+ r_property = Transform3D(variant).get_origin();
} else {
- return Vector3();
+ r_property = Vector3();
}
+ } else {
+ return false;
}
- return r_ret;
+ return true;
}
void Node3D::_bind_methods() {
@@ -1032,9 +1033,6 @@ void Node3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("to_local", "global_point"), &Node3D::to_local);
ClassDB::bind_method(D_METHOD("to_global", "local_point"), &Node3D::to_global);
- ClassDB::bind_method(D_METHOD("property_can_revert", "name"), &Node3D::property_can_revert);
- ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &Node3D::property_get_revert);
-
BIND_CONSTANT(NOTIFICATION_TRANSFORM_CHANGED);
BIND_CONSTANT(NOTIFICATION_ENTER_WORLD);
BIND_CONSTANT(NOTIFICATION_EXIT_WORLD);
@@ -1056,7 +1054,7 @@ void Node3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "global_transform", PROPERTY_HINT_NONE, "suffix:m", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_greater,or_lesser,no_slider,suffix:m", PROPERTY_USAGE_EDITOR), "set_position", "get_position");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians", PROPERTY_USAGE_EDITOR), "set_rotation", "get_rotation");
- ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "quaternion", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_quaternion", "get_quaternion");
+ ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "quaternion", PROPERTY_HINT_HIDE_QUATERNION_EDIT, "", PROPERTY_USAGE_EDITOR), "set_quaternion", "get_quaternion");
ADD_PROPERTY(PropertyInfo(Variant::BASIS, "basis", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_basis", "get_basis");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_LINK, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_edit_mode", PROPERTY_HINT_ENUM, "Euler,Quaternion,Basis"), "set_rotation_edit_mode", "get_rotation_edit_mode");
diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h
index b1e129798d..90c7bc89ef 100644
--- a/scene/3d/node_3d.h
+++ b/scene/3d/node_3d.h
@@ -155,10 +155,10 @@ protected:
void _notification(int p_what);
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
- bool property_can_revert(const String &p_name);
- Variant property_get_revert(const String &p_name);
+ bool _property_can_revert(const StringName &p_name) const;
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
public:
enum {
@@ -216,7 +216,7 @@ public:
void set_subgizmo_selection(Ref<Node3DGizmo> p_gizmo, int p_id, Transform3D p_transform = Transform3D());
void clear_subgizmo_selection();
Vector<Ref<Node3DGizmo>> get_gizmos() const;
- Array get_gizmos_bind() const;
+ TypedArray<Node3DGizmo> get_gizmos_bind() const;
void add_gizmo(Ref<Node3DGizmo> p_gizmo);
void remove_gizmo(Ref<Node3DGizmo> p_gizmo);
void clear_gizmos();
diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp
index 25226ad384..7d79d9b4fd 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -183,8 +183,8 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
return;
}
real_t bi = c->get_bake_interval();
- real_t o_next = offset + bi;
- real_t o_prev = offset - bi;
+ real_t o_next = progress + bi;
+ real_t o_prev = progress - bi;
if (loop) {
o_next = Math::fposmod(o_next, bl);
@@ -198,7 +198,7 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
}
}
- Vector3 pos = c->interpolate_baked(offset, cubic);
+ Vector3 pos = c->interpolate_baked(progress, cubic);
Transform3D t = get_transform();
// Vector3 pos_offset = Vector3(h_offset, v_offset, 0); not used in all cases
// will be replaced by "Vector3(h_offset, v_offset, 0)" where it was formerly used
@@ -217,9 +217,9 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
forward.normalize();
}
- Vector3 up = c->interpolate_baked_up_vector(offset, true);
+ Vector3 up = c->interpolate_baked_up_vector(progress, true);
- if (o_next < offset) {
+ if (o_next < progress) {
Vector3 up1 = c->interpolate_baked_up_vector(o_next, true);
Vector3 axis = up.cross(up1);
@@ -247,12 +247,12 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
// for a discussion about why not Frenet frame.
t.origin = pos;
- if (p_update_xyz_rot && prev_offset != offset) { // Only update rotation if some parameter has changed - i.e. not on addition to scene tree.
+ if (p_update_xyz_rot && prev_offset != progress) { // Only update rotation if some parameter has changed - i.e. not on addition to scene tree.
real_t sample_distance = bi * 0.01;
Vector3 t_prev_pos_a = c->interpolate_baked(prev_offset - sample_distance, cubic);
Vector3 t_prev_pos_b = c->interpolate_baked(prev_offset + sample_distance, cubic);
- Vector3 t_cur_pos_a = c->interpolate_baked(offset - sample_distance, cubic);
- Vector3 t_cur_pos_b = c->interpolate_baked(offset + sample_distance, cubic);
+ Vector3 t_cur_pos_a = c->interpolate_baked(progress - sample_distance, cubic);
+ Vector3 t_cur_pos_b = c->interpolate_baked(progress + sample_distance, cubic);
Vector3 t_prev = (t_prev_pos_a - t_prev_pos_b).normalized();
Vector3 t_cur = (t_cur_pos_a - t_cur_pos_b).normalized();
@@ -277,7 +277,7 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) {
}
// do the additional tilting
- real_t tilt_angle = c->interpolate_baked_tilt(offset);
+ real_t tilt_angle = c->interpolate_baked_tilt(progress);
Vector3 tilt_axis = t_cur; // not sure what tilt is supposed to do, is this correct??
if (likely(!Math::is_zero_approx(Math::abs(tilt_angle)))) {
@@ -330,16 +330,15 @@ bool PathFollow3D::get_cubic_interpolation() const {
return cubic;
}
-void PathFollow3D::_validate_property(PropertyInfo &property) const {
- if (property.name == "offset") {
+void PathFollow3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "offset") {
real_t max = 10000;
if (path && path->get_curve().is_valid()) {
max = path->get_curve()->get_baked_length();
}
- property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater";
+ p_property.hint_string = "0," + rtos(max) + ",0.01,or_lesser,or_greater";
}
- Node3D::_validate_property(property);
}
TypedArray<String> PathFollow3D::get_configuration_warnings() const {
@@ -360,8 +359,8 @@ TypedArray<String> PathFollow3D::get_configuration_warnings() const {
}
void PathFollow3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_offset", "offset"), &PathFollow3D::set_offset);
- ClassDB::bind_method(D_METHOD("get_offset"), &PathFollow3D::get_offset);
+ ClassDB::bind_method(D_METHOD("set_progress", "progress"), &PathFollow3D::set_progress);
+ ClassDB::bind_method(D_METHOD("get_progress"), &PathFollow3D::get_progress);
ClassDB::bind_method(D_METHOD("set_h_offset", "h_offset"), &PathFollow3D::set_h_offset);
ClassDB::bind_method(D_METHOD("get_h_offset"), &PathFollow3D::get_h_offset);
@@ -369,8 +368,8 @@ void PathFollow3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_v_offset", "v_offset"), &PathFollow3D::set_v_offset);
ClassDB::bind_method(D_METHOD("get_v_offset"), &PathFollow3D::get_v_offset);
- ClassDB::bind_method(D_METHOD("set_unit_offset", "unit_offset"), &PathFollow3D::set_unit_offset);
- ClassDB::bind_method(D_METHOD("get_unit_offset"), &PathFollow3D::get_unit_offset);
+ ClassDB::bind_method(D_METHOD("set_progress_ratio", "ratio"), &PathFollow3D::set_progress_ratio);
+ ClassDB::bind_method(D_METHOD("get_progress_ratio"), &PathFollow3D::get_progress_ratio);
ClassDB::bind_method(D_METHOD("set_rotation_mode", "rotation_mode"), &PathFollow3D::set_rotation_mode);
ClassDB::bind_method(D_METHOD("get_rotation_mode"), &PathFollow3D::get_rotation_mode);
@@ -381,8 +380,8 @@ void PathFollow3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_loop", "loop"), &PathFollow3D::set_loop);
ClassDB::bind_method(D_METHOD("has_loop"), &PathFollow3D::has_loop);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "offset", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser,or_greater,suffix:m"), "set_offset", "get_offset");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress", PROPERTY_HINT_RANGE, "0,10000,0.01,or_lesser,or_greater,suffix:m"), "set_progress", "get_progress");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "progress_ratio", PROPERTY_HINT_RANGE, "0,1,0.0001,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_progress_ratio", "get_progress_ratio");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "h_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_h_offset", "get_h_offset");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_v_offset", "get_v_offset");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_mode", PROPERTY_HINT_ENUM, "None,Y,XY,XYZ,Oriented"), "set_rotation_mode", "get_rotation_mode");
@@ -396,22 +395,22 @@ void PathFollow3D::_bind_methods() {
BIND_ENUM_CONSTANT(ROTATION_ORIENTED);
}
-void PathFollow3D::set_offset(real_t p_offset) {
- ERR_FAIL_COND(!isfinite(p_offset));
- prev_offset = offset;
- offset = p_offset;
+void PathFollow3D::set_progress(real_t p_progress) {
+ ERR_FAIL_COND(!isfinite(p_progress));
+ prev_offset = progress;
+ progress = p_progress;
if (path) {
if (path->get_curve().is_valid()) {
real_t path_length = path->get_curve()->get_baked_length();
if (loop && path_length) {
- offset = Math::fposmod(offset, path_length);
- if (!Math::is_zero_approx(p_offset) && Math::is_zero_approx(offset)) {
- offset = path_length;
+ progress = Math::fposmod(progress, path_length);
+ if (!Math::is_zero_approx(p_progress) && Math::is_zero_approx(progress)) {
+ progress = path_length;
}
} else {
- offset = CLAMP(offset, 0, path_length);
+ progress = CLAMP(progress, 0, path_length);
}
}
@@ -441,19 +440,19 @@ real_t PathFollow3D::get_v_offset() const {
return v_offset;
}
-real_t PathFollow3D::get_offset() const {
- return offset;
+real_t PathFollow3D::get_progress() const {
+ return progress;
}
-void PathFollow3D::set_unit_offset(real_t p_unit_offset) {
+void PathFollow3D::set_progress_ratio(real_t p_ratio) {
if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) {
- set_offset(p_unit_offset * path->get_curve()->get_baked_length());
+ set_progress(p_ratio * path->get_curve()->get_baked_length());
}
}
-real_t PathFollow3D::get_unit_offset() const {
+real_t PathFollow3D::get_progress_ratio() const {
if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) {
- return get_offset() / path->get_curve()->get_baked_length();
+ return get_progress() / path->get_curve()->get_baked_length();
} else {
return 0;
}
diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h
index b4cc6db7e3..45fa2c8917 100644
--- a/scene/3d/path_3d.h
+++ b/scene/3d/path_3d.h
@@ -75,7 +75,7 @@ public:
private:
Path3D *path = nullptr;
real_t prev_offset = 0.0; // Offset during the last _update_transform.
- real_t offset = 0.0;
+ real_t progress = 0.0;
real_t h_offset = 0.0;
real_t v_offset = 0.0;
bool cubic = true;
@@ -85,14 +85,14 @@ private:
void _update_transform(bool p_update_xyz_rot = true);
protected:
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
static void _bind_methods();
public:
- void set_offset(real_t p_offset);
- real_t get_offset() const;
+ void set_progress(real_t p_progress);
+ real_t get_progress() const;
void set_h_offset(real_t p_h_offset);
real_t get_h_offset() const;
@@ -100,8 +100,8 @@ public:
void set_v_offset(real_t p_v_offset);
real_t get_v_offset() const;
- void set_unit_offset(real_t p_unit_offset);
- real_t get_unit_offset() const;
+ void set_progress_ratio(real_t p_ratio);
+ real_t get_progress_ratio() const;
void set_loop(bool p_loop);
bool has_loop() const;
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 993608c306..5534bc28f1 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -376,7 +376,7 @@ AnimatableBody3D::AnimatableBody3D() :
PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
}
-void RigidDynamicBody3D::_body_enter_tree(ObjectID p_id) {
+void RigidBody3D::_body_enter_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
@@ -399,7 +399,7 @@ void RigidDynamicBody3D::_body_enter_tree(ObjectID p_id) {
contact_monitor->locked = false;
}
-void RigidDynamicBody3D::_body_exit_tree(ObjectID p_id) {
+void RigidBody3D::_body_exit_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
@@ -420,7 +420,7 @@ void RigidDynamicBody3D::_body_exit_tree(ObjectID p_id) {
contact_monitor->locked = false;
}
-void RigidDynamicBody3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape) {
+void RigidBody3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape) {
bool body_in = p_status == 1;
ObjectID objid = p_instance;
@@ -439,8 +439,8 @@ void RigidDynamicBody3D::_body_inout(int p_status, const RID &p_body, ObjectID p
//E->value.rc=0;
E->value.in_tree = node && node->is_inside_tree();
if (node) {
- node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidDynamicBody3D::_body_enter_tree).bind(objid));
- node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidDynamicBody3D::_body_exit_tree).bind(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody3D::_body_enter_tree).bind(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody3D::_body_exit_tree).bind(objid));
if (E->value.in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_entered, node);
}
@@ -466,8 +466,8 @@ void RigidDynamicBody3D::_body_inout(int p_status, const RID &p_body, ObjectID p
if (E->value.shapes.is_empty()) {
if (node) {
- node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidDynamicBody3D::_body_enter_tree));
- node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidDynamicBody3D::_body_exit_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody3D::_body_enter_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody3D::_body_exit_tree));
if (in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_exited, node);
}
@@ -481,19 +481,19 @@ void RigidDynamicBody3D::_body_inout(int p_status, const RID &p_body, ObjectID p
}
}
-struct _RigidDynamicBodyInOut {
+struct _RigidBodyInOut {
RID rid;
ObjectID id;
int shape = 0;
int local_shape = 0;
};
-void RigidDynamicBody3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) {
- RigidDynamicBody3D *body = (RigidDynamicBody3D *)p_instance;
+void RigidBody3D::_body_state_changed_callback(void *p_instance, PhysicsDirectBodyState3D *p_state) {
+ RigidBody3D *body = (RigidBody3D *)p_instance;
body->_body_state_changed(p_state);
}
-void RigidDynamicBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
+void RigidBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
set_ignore_transform_notification(true);
set_global_transform(p_state->get_transform());
@@ -524,9 +524,9 @@ void RigidDynamicBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state)
}
}
- _RigidDynamicBodyInOut *toadd = (_RigidDynamicBodyInOut *)alloca(p_state->get_contact_count() * sizeof(_RigidDynamicBodyInOut));
- int toadd_count = 0; //state->get_contact_count();
- RigidDynamicBody3D_RemoveAction *toremove = (RigidDynamicBody3D_RemoveAction *)alloca(rc * sizeof(RigidDynamicBody3D_RemoveAction));
+ _RigidBodyInOut *toadd = (_RigidBodyInOut *)alloca(p_state->get_contact_count() * sizeof(_RigidBodyInOut));
+ int toadd_count = 0;
+ RigidBody3D_RemoveAction *toremove = (RigidBody3D_RemoveAction *)alloca(rc * sizeof(RigidBody3D_RemoveAction));
int toremove_count = 0;
//put the ones to add
@@ -537,8 +537,6 @@ void RigidDynamicBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state)
int local_shape = p_state->get_contact_local_shape(i);
int shape = p_state->get_contact_collider_shape(i);
- //bool found=false;
-
HashMap<ObjectID, BodyState>::Iterator E = contact_monitor->body_map.find(obj);
if (!E) {
toadd[toadd_count].rid = rid;
@@ -592,7 +590,7 @@ void RigidDynamicBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state)
}
}
-void RigidDynamicBody3D::_notification(int p_what) {
+void RigidBody3D::_notification(int p_what) {
#ifdef TOOLS_ENABLED
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -610,7 +608,7 @@ void RigidDynamicBody3D::_notification(int p_what) {
#endif
}
-void RigidDynamicBody3D::_apply_body_mode() {
+void RigidBody3D::_apply_body_mode() {
if (freeze) {
switch (freeze_mode) {
case FREEZE_MODE_STATIC: {
@@ -621,13 +619,13 @@ void RigidDynamicBody3D::_apply_body_mode() {
} break;
}
} else if (lock_rotation) {
- set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC_LINEAR);
+ set_body_mode(PhysicsServer3D::BODY_MODE_RIGID_LINEAR);
} else {
- set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC);
+ set_body_mode(PhysicsServer3D::BODY_MODE_RIGID);
}
}
-void RigidDynamicBody3D::set_lock_rotation_enabled(bool p_lock_rotation) {
+void RigidBody3D::set_lock_rotation_enabled(bool p_lock_rotation) {
if (p_lock_rotation == lock_rotation) {
return;
}
@@ -636,11 +634,11 @@ void RigidDynamicBody3D::set_lock_rotation_enabled(bool p_lock_rotation) {
_apply_body_mode();
}
-bool RigidDynamicBody3D::is_lock_rotation_enabled() const {
+bool RigidBody3D::is_lock_rotation_enabled() const {
return lock_rotation;
}
-void RigidDynamicBody3D::set_freeze_enabled(bool p_freeze) {
+void RigidBody3D::set_freeze_enabled(bool p_freeze) {
if (p_freeze == freeze) {
return;
}
@@ -649,11 +647,11 @@ void RigidDynamicBody3D::set_freeze_enabled(bool p_freeze) {
_apply_body_mode();
}
-bool RigidDynamicBody3D::is_freeze_enabled() const {
+bool RigidBody3D::is_freeze_enabled() const {
return freeze;
}
-void RigidDynamicBody3D::set_freeze_mode(FreezeMode p_freeze_mode) {
+void RigidBody3D::set_freeze_mode(FreezeMode p_freeze_mode) {
if (p_freeze_mode == freeze_mode) {
return;
}
@@ -662,21 +660,21 @@ void RigidDynamicBody3D::set_freeze_mode(FreezeMode p_freeze_mode) {
_apply_body_mode();
}
-RigidDynamicBody3D::FreezeMode RigidDynamicBody3D::get_freeze_mode() const {
+RigidBody3D::FreezeMode RigidBody3D::get_freeze_mode() const {
return freeze_mode;
}
-void RigidDynamicBody3D::set_mass(real_t p_mass) {
+void RigidBody3D::set_mass(real_t p_mass) {
ERR_FAIL_COND(p_mass <= 0);
mass = p_mass;
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_MASS, mass);
}
-real_t RigidDynamicBody3D::get_mass() const {
+real_t RigidBody3D::get_mass() const {
return mass;
}
-void RigidDynamicBody3D::set_inertia(const Vector3 &p_inertia) {
+void RigidBody3D::set_inertia(const Vector3 &p_inertia) {
ERR_FAIL_COND(p_inertia.x < 0);
ERR_FAIL_COND(p_inertia.y < 0);
ERR_FAIL_COND(p_inertia.z < 0);
@@ -685,11 +683,11 @@ void RigidDynamicBody3D::set_inertia(const Vector3 &p_inertia) {
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_INERTIA, inertia);
}
-const Vector3 &RigidDynamicBody3D::get_inertia() const {
+const Vector3 &RigidBody3D::get_inertia() const {
return inertia;
}
-void RigidDynamicBody3D::set_center_of_mass_mode(CenterOfMassMode p_mode) {
+void RigidBody3D::set_center_of_mass_mode(CenterOfMassMode p_mode) {
if (center_of_mass_mode == p_mode) {
return;
}
@@ -711,11 +709,11 @@ void RigidDynamicBody3D::set_center_of_mass_mode(CenterOfMassMode p_mode) {
}
}
-RigidDynamicBody3D::CenterOfMassMode RigidDynamicBody3D::get_center_of_mass_mode() const {
+RigidBody3D::CenterOfMassMode RigidBody3D::get_center_of_mass_mode() const {
return center_of_mass_mode;
}
-void RigidDynamicBody3D::set_center_of_mass(const Vector3 &p_center_of_mass) {
+void RigidBody3D::set_center_of_mass(const Vector3 &p_center_of_mass) {
if (center_of_mass == p_center_of_mass) {
return;
}
@@ -726,106 +724,106 @@ void RigidDynamicBody3D::set_center_of_mass(const Vector3 &p_center_of_mass) {
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS, center_of_mass);
}
-const Vector3 &RigidDynamicBody3D::get_center_of_mass() const {
+const Vector3 &RigidBody3D::get_center_of_mass() const {
return center_of_mass;
}
-void RigidDynamicBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
+void RigidBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
if (physics_material_override.is_valid()) {
- if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidDynamicBody3D::_reload_physics_characteristics))) {
- physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidDynamicBody3D::_reload_physics_characteristics));
+ if (physics_material_override->is_connected(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody3D::_reload_physics_characteristics))) {
+ physics_material_override->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody3D::_reload_physics_characteristics));
}
}
physics_material_override = p_physics_material_override;
if (physics_material_override.is_valid()) {
- physics_material_override->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidDynamicBody3D::_reload_physics_characteristics));
+ physics_material_override->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &RigidBody3D::_reload_physics_characteristics));
}
_reload_physics_characteristics();
}
-Ref<PhysicsMaterial> RigidDynamicBody3D::get_physics_material_override() const {
+Ref<PhysicsMaterial> RigidBody3D::get_physics_material_override() const {
return physics_material_override;
}
-void RigidDynamicBody3D::set_gravity_scale(real_t p_gravity_scale) {
+void RigidBody3D::set_gravity_scale(real_t p_gravity_scale) {
gravity_scale = p_gravity_scale;
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE, gravity_scale);
}
-real_t RigidDynamicBody3D::get_gravity_scale() const {
+real_t RigidBody3D::get_gravity_scale() const {
return gravity_scale;
}
-void RigidDynamicBody3D::set_linear_damp_mode(DampMode p_mode) {
+void RigidBody3D::set_linear_damp_mode(DampMode p_mode) {
linear_damp_mode = p_mode;
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_LINEAR_DAMP_MODE, linear_damp_mode);
}
-RigidDynamicBody3D::DampMode RigidDynamicBody3D::get_linear_damp_mode() const {
+RigidBody3D::DampMode RigidBody3D::get_linear_damp_mode() const {
return linear_damp_mode;
}
-void RigidDynamicBody3D::set_angular_damp_mode(DampMode p_mode) {
+void RigidBody3D::set_angular_damp_mode(DampMode p_mode) {
angular_damp_mode = p_mode;
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP_MODE, angular_damp_mode);
}
-RigidDynamicBody3D::DampMode RigidDynamicBody3D::get_angular_damp_mode() const {
+RigidBody3D::DampMode RigidBody3D::get_angular_damp_mode() const {
return angular_damp_mode;
}
-void RigidDynamicBody3D::set_linear_damp(real_t p_linear_damp) {
+void RigidBody3D::set_linear_damp(real_t p_linear_damp) {
ERR_FAIL_COND(p_linear_damp < 0.0);
linear_damp = p_linear_damp;
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_LINEAR_DAMP, linear_damp);
}
-real_t RigidDynamicBody3D::get_linear_damp() const {
+real_t RigidBody3D::get_linear_damp() const {
return linear_damp;
}
-void RigidDynamicBody3D::set_angular_damp(real_t p_angular_damp) {
+void RigidBody3D::set_angular_damp(real_t p_angular_damp) {
ERR_FAIL_COND(p_angular_damp < 0.0);
angular_damp = p_angular_damp;
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP, angular_damp);
}
-real_t RigidDynamicBody3D::get_angular_damp() const {
+real_t RigidBody3D::get_angular_damp() const {
return angular_damp;
}
-void RigidDynamicBody3D::set_axis_velocity(const Vector3 &p_axis) {
+void RigidBody3D::set_axis_velocity(const Vector3 &p_axis) {
Vector3 axis = p_axis.normalized();
linear_velocity -= axis * axis.dot(linear_velocity);
linear_velocity += p_axis;
PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
}
-void RigidDynamicBody3D::set_linear_velocity(const Vector3 &p_velocity) {
+void RigidBody3D::set_linear_velocity(const Vector3 &p_velocity) {
linear_velocity = p_velocity;
PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, linear_velocity);
}
-Vector3 RigidDynamicBody3D::get_linear_velocity() const {
+Vector3 RigidBody3D::get_linear_velocity() const {
return linear_velocity;
}
-void RigidDynamicBody3D::set_angular_velocity(const Vector3 &p_velocity) {
+void RigidBody3D::set_angular_velocity(const Vector3 &p_velocity) {
angular_velocity = p_velocity;
PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, angular_velocity);
}
-Vector3 RigidDynamicBody3D::get_angular_velocity() const {
+Vector3 RigidBody3D::get_angular_velocity() const {
return angular_velocity;
}
-Basis RigidDynamicBody3D::get_inverse_inertia_tensor() const {
+Basis RigidBody3D::get_inverse_inertia_tensor() const {
return inverse_inertia_tensor;
}
-void RigidDynamicBody3D::set_use_custom_integrator(bool p_enable) {
+void RigidBody3D::set_use_custom_integrator(bool p_enable) {
if (custom_integrator == p_enable) {
return;
}
@@ -834,102 +832,108 @@ void RigidDynamicBody3D::set_use_custom_integrator(bool p_enable) {
PhysicsServer3D::get_singleton()->body_set_omit_force_integration(get_rid(), p_enable);
}
-bool RigidDynamicBody3D::is_using_custom_integrator() {
+bool RigidBody3D::is_using_custom_integrator() {
return custom_integrator;
}
-void RigidDynamicBody3D::set_sleeping(bool p_sleeping) {
+void RigidBody3D::set_sleeping(bool p_sleeping) {
sleeping = p_sleeping;
PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_SLEEPING, sleeping);
}
-void RigidDynamicBody3D::set_can_sleep(bool p_active) {
+void RigidBody3D::set_can_sleep(bool p_active) {
can_sleep = p_active;
PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_CAN_SLEEP, p_active);
}
-bool RigidDynamicBody3D::is_able_to_sleep() const {
+bool RigidBody3D::is_able_to_sleep() const {
return can_sleep;
}
-bool RigidDynamicBody3D::is_sleeping() const {
+bool RigidBody3D::is_sleeping() const {
return sleeping;
}
-void RigidDynamicBody3D::set_max_contacts_reported(int p_amount) {
+void RigidBody3D::set_max_contacts_reported(int p_amount) {
max_contacts_reported = p_amount;
PhysicsServer3D::get_singleton()->body_set_max_contacts_reported(get_rid(), p_amount);
}
-int RigidDynamicBody3D::get_max_contacts_reported() const {
+int RigidBody3D::get_max_contacts_reported() const {
return max_contacts_reported;
}
-void RigidDynamicBody3D::apply_central_impulse(const Vector3 &p_impulse) {
+int RigidBody3D::get_contact_count() const {
+ PhysicsDirectBodyState3D *bs = PhysicsServer3D::get_singleton()->body_get_direct_state(get_rid());
+ ERR_FAIL_NULL_V(bs, 0);
+ return bs->get_contact_count();
+}
+
+void RigidBody3D::apply_central_impulse(const Vector3 &p_impulse) {
PhysicsServer3D::get_singleton()->body_apply_central_impulse(get_rid(), p_impulse);
}
-void RigidDynamicBody3D::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) {
+void RigidBody3D::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) {
PhysicsServer3D *singleton = PhysicsServer3D::get_singleton();
singleton->body_apply_impulse(get_rid(), p_impulse, p_position);
}
-void RigidDynamicBody3D::apply_torque_impulse(const Vector3 &p_impulse) {
+void RigidBody3D::apply_torque_impulse(const Vector3 &p_impulse) {
PhysicsServer3D::get_singleton()->body_apply_torque_impulse(get_rid(), p_impulse);
}
-void RigidDynamicBody3D::apply_central_force(const Vector3 &p_force) {
+void RigidBody3D::apply_central_force(const Vector3 &p_force) {
PhysicsServer3D::get_singleton()->body_apply_central_force(get_rid(), p_force);
}
-void RigidDynamicBody3D::apply_force(const Vector3 &p_force, const Vector3 &p_position) {
+void RigidBody3D::apply_force(const Vector3 &p_force, const Vector3 &p_position) {
PhysicsServer3D *singleton = PhysicsServer3D::get_singleton();
singleton->body_apply_force(get_rid(), p_force, p_position);
}
-void RigidDynamicBody3D::apply_torque(const Vector3 &p_torque) {
+void RigidBody3D::apply_torque(const Vector3 &p_torque) {
PhysicsServer3D::get_singleton()->body_apply_torque(get_rid(), p_torque);
}
-void RigidDynamicBody3D::add_constant_central_force(const Vector3 &p_force) {
+void RigidBody3D::add_constant_central_force(const Vector3 &p_force) {
PhysicsServer3D::get_singleton()->body_add_constant_central_force(get_rid(), p_force);
}
-void RigidDynamicBody3D::add_constant_force(const Vector3 &p_force, const Vector3 &p_position) {
+void RigidBody3D::add_constant_force(const Vector3 &p_force, const Vector3 &p_position) {
PhysicsServer3D *singleton = PhysicsServer3D::get_singleton();
singleton->body_add_constant_force(get_rid(), p_force, p_position);
}
-void RigidDynamicBody3D::add_constant_torque(const Vector3 &p_torque) {
+void RigidBody3D::add_constant_torque(const Vector3 &p_torque) {
PhysicsServer3D::get_singleton()->body_add_constant_torque(get_rid(), p_torque);
}
-void RigidDynamicBody3D::set_constant_force(const Vector3 &p_force) {
+void RigidBody3D::set_constant_force(const Vector3 &p_force) {
PhysicsServer3D::get_singleton()->body_set_constant_force(get_rid(), p_force);
}
-Vector3 RigidDynamicBody3D::get_constant_force() const {
+Vector3 RigidBody3D::get_constant_force() const {
return PhysicsServer3D::get_singleton()->body_get_constant_force(get_rid());
}
-void RigidDynamicBody3D::set_constant_torque(const Vector3 &p_torque) {
+void RigidBody3D::set_constant_torque(const Vector3 &p_torque) {
PhysicsServer3D::get_singleton()->body_set_constant_torque(get_rid(), p_torque);
}
-Vector3 RigidDynamicBody3D::get_constant_torque() const {
+Vector3 RigidBody3D::get_constant_torque() const {
return PhysicsServer3D::get_singleton()->body_get_constant_torque(get_rid());
}
-void RigidDynamicBody3D::set_use_continuous_collision_detection(bool p_enable) {
+void RigidBody3D::set_use_continuous_collision_detection(bool p_enable) {
ccd = p_enable;
PhysicsServer3D::get_singleton()->body_set_enable_continuous_collision_detection(get_rid(), p_enable);
}
-bool RigidDynamicBody3D::is_using_continuous_collision_detection() const {
+bool RigidBody3D::is_using_continuous_collision_detection() const {
return ccd;
}
-void RigidDynamicBody3D::set_contact_monitor(bool p_enabled) {
+void RigidBody3D::set_contact_monitor(bool p_enabled) {
if (p_enabled == is_contact_monitor_enabled()) {
return;
}
@@ -943,8 +947,8 @@ void RigidDynamicBody3D::set_contact_monitor(bool p_enabled) {
Node *node = Object::cast_to<Node>(obj);
if (node) {
- node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidDynamicBody3D::_body_enter_tree));
- node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidDynamicBody3D::_body_exit_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody3D::_body_enter_tree));
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody3D::_body_exit_tree));
}
}
@@ -956,14 +960,14 @@ void RigidDynamicBody3D::set_contact_monitor(bool p_enabled) {
}
}
-bool RigidDynamicBody3D::is_contact_monitor_enabled() const {
+bool RigidBody3D::is_contact_monitor_enabled() const {
return contact_monitor != nullptr;
}
-Array RigidDynamicBody3D::get_colliding_bodies() const {
- ERR_FAIL_COND_V(!contact_monitor, Array());
+TypedArray<Node3D> RigidBody3D::get_colliding_bodies() const {
+ ERR_FAIL_COND_V(!contact_monitor, TypedArray<Node3D>());
- Array ret;
+ TypedArray<Node3D> ret;
ret.resize(contact_monitor->body_map.size());
int idx = 0;
for (const KeyValue<ObjectID, BodyState> &E : contact_monitor->body_map) {
@@ -978,105 +982,106 @@ Array RigidDynamicBody3D::get_colliding_bodies() const {
return ret;
}
-TypedArray<String> RigidDynamicBody3D::get_configuration_warnings() const {
+TypedArray<String> RigidBody3D::get_configuration_warnings() const {
Transform3D t = get_transform();
TypedArray<String> warnings = Node::get_configuration_warnings();
if (ABS(t.basis.get_column(0).length() - 1.0) > 0.05 || ABS(t.basis.get_column(1).length() - 1.0) > 0.05 || ABS(t.basis.get_column(2).length() - 1.0) > 0.05) {
- warnings.push_back(RTR("Size changes to RigidDynamicBody will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
+ warnings.push_back(RTR("Size changes to RigidBody will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
}
return warnings;
}
-void RigidDynamicBody3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_mass", "mass"), &RigidDynamicBody3D::set_mass);
- ClassDB::bind_method(D_METHOD("get_mass"), &RigidDynamicBody3D::get_mass);
+void RigidBody3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_mass", "mass"), &RigidBody3D::set_mass);
+ ClassDB::bind_method(D_METHOD("get_mass"), &RigidBody3D::get_mass);
- ClassDB::bind_method(D_METHOD("set_inertia", "inertia"), &RigidDynamicBody3D::set_inertia);
- ClassDB::bind_method(D_METHOD("get_inertia"), &RigidDynamicBody3D::get_inertia);
+ ClassDB::bind_method(D_METHOD("set_inertia", "inertia"), &RigidBody3D::set_inertia);
+ ClassDB::bind_method(D_METHOD("get_inertia"), &RigidBody3D::get_inertia);
- ClassDB::bind_method(D_METHOD("set_center_of_mass_mode", "mode"), &RigidDynamicBody3D::set_center_of_mass_mode);
- ClassDB::bind_method(D_METHOD("get_center_of_mass_mode"), &RigidDynamicBody3D::get_center_of_mass_mode);
+ ClassDB::bind_method(D_METHOD("set_center_of_mass_mode", "mode"), &RigidBody3D::set_center_of_mass_mode);
+ ClassDB::bind_method(D_METHOD("get_center_of_mass_mode"), &RigidBody3D::get_center_of_mass_mode);
- ClassDB::bind_method(D_METHOD("set_center_of_mass", "center_of_mass"), &RigidDynamicBody3D::set_center_of_mass);
- ClassDB::bind_method(D_METHOD("get_center_of_mass"), &RigidDynamicBody3D::get_center_of_mass);
+ ClassDB::bind_method(D_METHOD("set_center_of_mass", "center_of_mass"), &RigidBody3D::set_center_of_mass);
+ ClassDB::bind_method(D_METHOD("get_center_of_mass"), &RigidBody3D::get_center_of_mass);
- ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidDynamicBody3D::set_physics_material_override);
- ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidDynamicBody3D::get_physics_material_override);
+ ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &RigidBody3D::set_physics_material_override);
+ ClassDB::bind_method(D_METHOD("get_physics_material_override"), &RigidBody3D::get_physics_material_override);
- ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidDynamicBody3D::set_linear_velocity);
- ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidDynamicBody3D::get_linear_velocity);
+ ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &RigidBody3D::set_linear_velocity);
+ ClassDB::bind_method(D_METHOD("get_linear_velocity"), &RigidBody3D::get_linear_velocity);
- ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &RigidDynamicBody3D::set_angular_velocity);
- ClassDB::bind_method(D_METHOD("get_angular_velocity"), &RigidDynamicBody3D::get_angular_velocity);
+ ClassDB::bind_method(D_METHOD("set_angular_velocity", "angular_velocity"), &RigidBody3D::set_angular_velocity);
+ ClassDB::bind_method(D_METHOD("get_angular_velocity"), &RigidBody3D::get_angular_velocity);
- ClassDB::bind_method(D_METHOD("get_inverse_inertia_tensor"), &RigidDynamicBody3D::get_inverse_inertia_tensor);
+ ClassDB::bind_method(D_METHOD("get_inverse_inertia_tensor"), &RigidBody3D::get_inverse_inertia_tensor);
- ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidDynamicBody3D::set_gravity_scale);
- ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidDynamicBody3D::get_gravity_scale);
+ ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &RigidBody3D::set_gravity_scale);
+ ClassDB::bind_method(D_METHOD("get_gravity_scale"), &RigidBody3D::get_gravity_scale);
- ClassDB::bind_method(D_METHOD("set_linear_damp_mode", "linear_damp_mode"), &RigidDynamicBody3D::set_linear_damp_mode);
- ClassDB::bind_method(D_METHOD("get_linear_damp_mode"), &RigidDynamicBody3D::get_linear_damp_mode);
+ ClassDB::bind_method(D_METHOD("set_linear_damp_mode", "linear_damp_mode"), &RigidBody3D::set_linear_damp_mode);
+ ClassDB::bind_method(D_METHOD("get_linear_damp_mode"), &RigidBody3D::get_linear_damp_mode);
- ClassDB::bind_method(D_METHOD("set_angular_damp_mode", "angular_damp_mode"), &RigidDynamicBody3D::set_angular_damp_mode);
- ClassDB::bind_method(D_METHOD("get_angular_damp_mode"), &RigidDynamicBody3D::get_angular_damp_mode);
+ ClassDB::bind_method(D_METHOD("set_angular_damp_mode", "angular_damp_mode"), &RigidBody3D::set_angular_damp_mode);
+ ClassDB::bind_method(D_METHOD("get_angular_damp_mode"), &RigidBody3D::get_angular_damp_mode);
- ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &RigidDynamicBody3D::set_linear_damp);
- ClassDB::bind_method(D_METHOD("get_linear_damp"), &RigidDynamicBody3D::get_linear_damp);
+ ClassDB::bind_method(D_METHOD("set_linear_damp", "linear_damp"), &RigidBody3D::set_linear_damp);
+ ClassDB::bind_method(D_METHOD("get_linear_damp"), &RigidBody3D::get_linear_damp);
- ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &RigidDynamicBody3D::set_angular_damp);
- ClassDB::bind_method(D_METHOD("get_angular_damp"), &RigidDynamicBody3D::get_angular_damp);
+ ClassDB::bind_method(D_METHOD("set_angular_damp", "angular_damp"), &RigidBody3D::set_angular_damp);
+ ClassDB::bind_method(D_METHOD("get_angular_damp"), &RigidBody3D::get_angular_damp);
- ClassDB::bind_method(D_METHOD("set_max_contacts_reported", "amount"), &RigidDynamicBody3D::set_max_contacts_reported);
- ClassDB::bind_method(D_METHOD("get_max_contacts_reported"), &RigidDynamicBody3D::get_max_contacts_reported);
+ ClassDB::bind_method(D_METHOD("set_max_contacts_reported", "amount"), &RigidBody3D::set_max_contacts_reported);
+ ClassDB::bind_method(D_METHOD("get_max_contacts_reported"), &RigidBody3D::get_max_contacts_reported);
+ ClassDB::bind_method(D_METHOD("get_contact_count"), &RigidBody3D::get_contact_count);
- ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &RigidDynamicBody3D::set_use_custom_integrator);
- ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &RigidDynamicBody3D::is_using_custom_integrator);
+ ClassDB::bind_method(D_METHOD("set_use_custom_integrator", "enable"), &RigidBody3D::set_use_custom_integrator);
+ ClassDB::bind_method(D_METHOD("is_using_custom_integrator"), &RigidBody3D::is_using_custom_integrator);
- ClassDB::bind_method(D_METHOD("set_contact_monitor", "enabled"), &RigidDynamicBody3D::set_contact_monitor);
- ClassDB::bind_method(D_METHOD("is_contact_monitor_enabled"), &RigidDynamicBody3D::is_contact_monitor_enabled);
+ ClassDB::bind_method(D_METHOD("set_contact_monitor", "enabled"), &RigidBody3D::set_contact_monitor);
+ ClassDB::bind_method(D_METHOD("is_contact_monitor_enabled"), &RigidBody3D::is_contact_monitor_enabled);
- ClassDB::bind_method(D_METHOD("set_use_continuous_collision_detection", "enable"), &RigidDynamicBody3D::set_use_continuous_collision_detection);
- ClassDB::bind_method(D_METHOD("is_using_continuous_collision_detection"), &RigidDynamicBody3D::is_using_continuous_collision_detection);
+ ClassDB::bind_method(D_METHOD("set_use_continuous_collision_detection", "enable"), &RigidBody3D::set_use_continuous_collision_detection);
+ ClassDB::bind_method(D_METHOD("is_using_continuous_collision_detection"), &RigidBody3D::is_using_continuous_collision_detection);
- ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidDynamicBody3D::set_axis_velocity);
+ ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidBody3D::set_axis_velocity);
- ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidDynamicBody3D::apply_central_impulse);
- ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &RigidDynamicBody3D::apply_impulse, Vector3());
- ClassDB::bind_method(D_METHOD("apply_torque_impulse", "impulse"), &RigidDynamicBody3D::apply_torque_impulse);
+ ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &RigidBody3D::apply_central_impulse);
+ ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "position"), &RigidBody3D::apply_impulse, Vector3());
+ ClassDB::bind_method(D_METHOD("apply_torque_impulse", "impulse"), &RigidBody3D::apply_torque_impulse);
- ClassDB::bind_method(D_METHOD("apply_central_force", "force"), &RigidDynamicBody3D::apply_central_force);
- ClassDB::bind_method(D_METHOD("apply_force", "force", "position"), &RigidDynamicBody3D::apply_force, Vector3());
- ClassDB::bind_method(D_METHOD("apply_torque", "torque"), &RigidDynamicBody3D::apply_torque);
+ ClassDB::bind_method(D_METHOD("apply_central_force", "force"), &RigidBody3D::apply_central_force);
+ ClassDB::bind_method(D_METHOD("apply_force", "force", "position"), &RigidBody3D::apply_force, Vector3());
+ ClassDB::bind_method(D_METHOD("apply_torque", "torque"), &RigidBody3D::apply_torque);
- ClassDB::bind_method(D_METHOD("add_constant_central_force", "force"), &RigidDynamicBody3D::add_constant_central_force);
- ClassDB::bind_method(D_METHOD("add_constant_force", "force", "position"), &RigidDynamicBody3D::add_constant_force, Vector3());
- ClassDB::bind_method(D_METHOD("add_constant_torque", "torque"), &RigidDynamicBody3D::add_constant_torque);
+ ClassDB::bind_method(D_METHOD("add_constant_central_force", "force"), &RigidBody3D::add_constant_central_force);
+ ClassDB::bind_method(D_METHOD("add_constant_force", "force", "position"), &RigidBody3D::add_constant_force, Vector3());
+ ClassDB::bind_method(D_METHOD("add_constant_torque", "torque"), &RigidBody3D::add_constant_torque);
- ClassDB::bind_method(D_METHOD("set_constant_force", "force"), &RigidDynamicBody3D::set_constant_force);
- ClassDB::bind_method(D_METHOD("get_constant_force"), &RigidDynamicBody3D::get_constant_force);
+ ClassDB::bind_method(D_METHOD("set_constant_force", "force"), &RigidBody3D::set_constant_force);
+ ClassDB::bind_method(D_METHOD("get_constant_force"), &RigidBody3D::get_constant_force);
- ClassDB::bind_method(D_METHOD("set_constant_torque", "torque"), &RigidDynamicBody3D::set_constant_torque);
- ClassDB::bind_method(D_METHOD("get_constant_torque"), &RigidDynamicBody3D::get_constant_torque);
+ ClassDB::bind_method(D_METHOD("set_constant_torque", "torque"), &RigidBody3D::set_constant_torque);
+ ClassDB::bind_method(D_METHOD("get_constant_torque"), &RigidBody3D::get_constant_torque);
- ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidDynamicBody3D::set_sleeping);
- ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidDynamicBody3D::is_sleeping);
+ ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidBody3D::set_sleeping);
+ ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidBody3D::is_sleeping);
- ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidDynamicBody3D::set_can_sleep);
- ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidDynamicBody3D::is_able_to_sleep);
+ ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidBody3D::set_can_sleep);
+ ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidBody3D::is_able_to_sleep);
- ClassDB::bind_method(D_METHOD("set_lock_rotation_enabled", "lock_rotation"), &RigidDynamicBody3D::set_lock_rotation_enabled);
- ClassDB::bind_method(D_METHOD("is_lock_rotation_enabled"), &RigidDynamicBody3D::is_lock_rotation_enabled);
+ ClassDB::bind_method(D_METHOD("set_lock_rotation_enabled", "lock_rotation"), &RigidBody3D::set_lock_rotation_enabled);
+ ClassDB::bind_method(D_METHOD("is_lock_rotation_enabled"), &RigidBody3D::is_lock_rotation_enabled);
- ClassDB::bind_method(D_METHOD("set_freeze_enabled", "freeze_mode"), &RigidDynamicBody3D::set_freeze_enabled);
- ClassDB::bind_method(D_METHOD("is_freeze_enabled"), &RigidDynamicBody3D::is_freeze_enabled);
+ ClassDB::bind_method(D_METHOD("set_freeze_enabled", "freeze_mode"), &RigidBody3D::set_freeze_enabled);
+ ClassDB::bind_method(D_METHOD("is_freeze_enabled"), &RigidBody3D::is_freeze_enabled);
- ClassDB::bind_method(D_METHOD("set_freeze_mode", "freeze_mode"), &RigidDynamicBody3D::set_freeze_mode);
- ClassDB::bind_method(D_METHOD("get_freeze_mode"), &RigidDynamicBody3D::get_freeze_mode);
+ ClassDB::bind_method(D_METHOD("set_freeze_mode", "freeze_mode"), &RigidBody3D::set_freeze_mode);
+ ClassDB::bind_method(D_METHOD("get_freeze_mode"), &RigidBody3D::get_freeze_mode);
- ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidDynamicBody3D::get_colliding_bodies);
+ ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody3D::get_colliding_bodies);
GDVIRTUAL_BIND(_integrate_forces, "state");
@@ -1089,7 +1094,7 @@ void RigidDynamicBody3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "continuous_cd"), "set_use_continuous_collision_detection", "is_using_continuous_collision_detection");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "contacts_reported", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), "set_max_contacts_reported", "get_max_contacts_reported");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_contacts_reported", PROPERTY_HINT_RANGE, "0,64,1,or_greater"), "set_max_contacts_reported", "get_max_contacts_reported");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "contact_monitor"), "set_contact_monitor", "is_contact_monitor_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleeping", "is_sleeping");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep");
@@ -1124,27 +1129,26 @@ void RigidDynamicBody3D::_bind_methods() {
BIND_ENUM_CONSTANT(DAMP_MODE_REPLACE);
}
-void RigidDynamicBody3D::_validate_property(PropertyInfo &property) const {
+void RigidBody3D::_validate_property(PropertyInfo &p_property) const {
if (center_of_mass_mode != CENTER_OF_MASS_MODE_CUSTOM) {
- if (property.name == "center_of_mass") {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name == "center_of_mass") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
- PhysicsBody3D::_validate_property(property);
}
-RigidDynamicBody3D::RigidDynamicBody3D() :
- PhysicsBody3D(PhysicsServer3D::BODY_MODE_DYNAMIC) {
+RigidBody3D::RigidBody3D() :
+ PhysicsBody3D(PhysicsServer3D::BODY_MODE_RIGID) {
PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
}
-RigidDynamicBody3D::~RigidDynamicBody3D() {
+RigidBody3D::~RigidBody3D() {
if (contact_monitor) {
memdelete(contact_monitor);
}
}
-void RigidDynamicBody3D::_reload_physics_characteristics() {
+void RigidBody3D::_reload_physics_characteristics() {
if (physics_material_override.is_null()) {
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, 0);
PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_FRICTION, 1);
@@ -1177,9 +1181,9 @@ bool CharacterBody3D::move_and_slide() {
if ((collision_state.floor || collision_state.wall) && platform_rid.is_valid()) {
bool excluded = false;
if (collision_state.floor) {
- excluded = (moving_platform_floor_layers & platform_layer) == 0;
+ excluded = (platform_floor_layers & platform_layer) == 0;
} else if (collision_state.wall) {
- excluded = (moving_platform_wall_layers & platform_layer) == 0;
+ excluded = (platform_wall_layers & platform_layer) == 0;
}
if (!excluded) {
//this approach makes sure there is less delay between the actual body velocity and the one we saved
@@ -1231,10 +1235,10 @@ bool CharacterBody3D::move_and_slide() {
// Compute real velocity.
real_velocity = get_position_delta() / delta;
- if (moving_platform_apply_velocity_on_leave != PLATFORM_VEL_ON_LEAVE_NEVER) {
+ if (platform_on_leave != PLATFORM_ON_LEAVE_DO_NOTHING) {
// Add last platform velocity when just left a moving platform.
if (!collision_state.floor && !collision_state.wall) {
- if (moving_platform_apply_velocity_on_leave == PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY && current_platform_velocity.dot(up_direction) < 0) {
+ if (platform_on_leave == PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY && current_platform_velocity.dot(up_direction) < 0) {
current_platform_velocity = current_platform_velocity.slide(up_direction);
}
velocity += current_platform_velocity;
@@ -1854,20 +1858,20 @@ void CharacterBody3D::set_slide_on_ceiling_enabled(bool p_enabled) {
slide_on_ceiling = p_enabled;
}
-uint32_t CharacterBody3D::get_moving_platform_floor_layers() const {
- return moving_platform_floor_layers;
+uint32_t CharacterBody3D::get_platform_floor_layers() const {
+ return platform_floor_layers;
}
-void CharacterBody3D::set_moving_platform_floor_layers(uint32_t p_exclude_layers) {
- moving_platform_floor_layers = p_exclude_layers;
+void CharacterBody3D::set_platform_floor_layers(uint32_t p_exclude_layers) {
+ platform_floor_layers = p_exclude_layers;
}
-uint32_t CharacterBody3D::get_moving_platform_wall_layers() const {
- return moving_platform_wall_layers;
+uint32_t CharacterBody3D::get_platform_wall_layers() const {
+ return platform_wall_layers;
}
-void CharacterBody3D::set_moving_platform_wall_layers(uint32_t p_exclude_layers) {
- moving_platform_wall_layers = p_exclude_layers;
+void CharacterBody3D::set_platform_wall_layers(uint32_t p_exclude_layers) {
+ platform_wall_layers = p_exclude_layers;
}
void CharacterBody3D::set_motion_mode(MotionMode p_mode) {
@@ -1878,12 +1882,12 @@ CharacterBody3D::MotionMode CharacterBody3D::get_motion_mode() const {
return motion_mode;
}
-void CharacterBody3D::set_moving_platform_apply_velocity_on_leave(MovingPlatformApplyVelocityOnLeave p_on_leave_apply_velocity) {
- moving_platform_apply_velocity_on_leave = p_on_leave_apply_velocity;
+void CharacterBody3D::set_platform_on_leave(PlatformOnLeave p_on_leave_apply_velocity) {
+ platform_on_leave = p_on_leave_apply_velocity;
}
-CharacterBody3D::MovingPlatformApplyVelocityOnLeave CharacterBody3D::get_moving_platform_apply_velocity_on_leave() const {
- return moving_platform_apply_velocity_on_leave;
+CharacterBody3D::PlatformOnLeave CharacterBody3D::get_platform_on_leave() const {
+ return platform_on_leave;
}
int CharacterBody3D::get_max_slides() const {
@@ -1948,7 +1952,7 @@ void CharacterBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &CharacterBody3D::set_velocity);
ClassDB::bind_method(D_METHOD("get_velocity"), &CharacterBody3D::get_velocity);
- ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &CharacterBody3D::set_safe_margin);
+ ClassDB::bind_method(D_METHOD("set_safe_margin", "margin"), &CharacterBody3D::set_safe_margin);
ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody3D::get_safe_margin);
ClassDB::bind_method(D_METHOD("is_floor_stop_on_slope_enabled"), &CharacterBody3D::is_floor_stop_on_slope_enabled);
ClassDB::bind_method(D_METHOD("set_floor_stop_on_slope_enabled", "enabled"), &CharacterBody3D::set_floor_stop_on_slope_enabled);
@@ -1959,10 +1963,10 @@ void CharacterBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_slide_on_ceiling_enabled", "enabled"), &CharacterBody3D::set_slide_on_ceiling_enabled);
ClassDB::bind_method(D_METHOD("is_slide_on_ceiling_enabled"), &CharacterBody3D::is_slide_on_ceiling_enabled);
- ClassDB::bind_method(D_METHOD("set_moving_platform_floor_layers", "exclude_layer"), &CharacterBody3D::set_moving_platform_floor_layers);
- ClassDB::bind_method(D_METHOD("get_moving_platform_floor_layers"), &CharacterBody3D::get_moving_platform_floor_layers);
- ClassDB::bind_method(D_METHOD("set_moving_platform_wall_layers", "exclude_layer"), &CharacterBody3D::set_moving_platform_wall_layers);
- ClassDB::bind_method(D_METHOD("get_moving_platform_wall_layers"), &CharacterBody3D::get_moving_platform_wall_layers);
+ ClassDB::bind_method(D_METHOD("set_platform_floor_layers", "exclude_layer"), &CharacterBody3D::set_platform_floor_layers);
+ ClassDB::bind_method(D_METHOD("get_platform_floor_layers"), &CharacterBody3D::get_platform_floor_layers);
+ ClassDB::bind_method(D_METHOD("set_platform_wall_layers", "exclude_layer"), &CharacterBody3D::set_platform_wall_layers);
+ ClassDB::bind_method(D_METHOD("get_platform_wall_layers"), &CharacterBody3D::get_platform_wall_layers);
ClassDB::bind_method(D_METHOD("get_max_slides"), &CharacterBody3D::get_max_slides);
ClassDB::bind_method(D_METHOD("set_max_slides", "max_slides"), &CharacterBody3D::set_max_slides);
@@ -1976,8 +1980,8 @@ void CharacterBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_up_direction", "up_direction"), &CharacterBody3D::set_up_direction);
ClassDB::bind_method(D_METHOD("set_motion_mode", "mode"), &CharacterBody3D::set_motion_mode);
ClassDB::bind_method(D_METHOD("get_motion_mode"), &CharacterBody3D::get_motion_mode);
- ClassDB::bind_method(D_METHOD("set_moving_platform_apply_velocity_on_leave", "on_leave_apply_velocity"), &CharacterBody3D::set_moving_platform_apply_velocity_on_leave);
- ClassDB::bind_method(D_METHOD("get_moving_platform_apply_velocity_on_leave"), &CharacterBody3D::get_moving_platform_apply_velocity_on_leave);
+ ClassDB::bind_method(D_METHOD("set_platform_on_leave", "on_leave_apply_velocity"), &CharacterBody3D::set_platform_on_leave);
+ ClassDB::bind_method(D_METHOD("get_platform_on_leave"), &CharacterBody3D::get_platform_on_leave);
ClassDB::bind_method(D_METHOD("is_on_floor"), &CharacterBody3D::is_on_floor);
ClassDB::bind_method(D_METHOD("is_on_floor_only"), &CharacterBody3D::is_on_floor_only);
@@ -2002,33 +2006,36 @@ void CharacterBody3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "velocity", PROPERTY_HINT_NONE, "suffix:m/s", PROPERTY_USAGE_NO_EDITOR), "set_velocity", "get_velocity");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_slides", "get_max_slides");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wall_min_slide_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians", PROPERTY_USAGE_DEFAULT), "set_wall_min_slide_angle", "get_wall_min_slide_angle");
+
ADD_GROUP("Floor", "floor_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_stop_on_slope"), "set_floor_stop_on_slope_enabled", "is_floor_stop_on_slope_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_constant_speed"), "set_floor_constant_speed_enabled", "is_floor_constant_speed_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "floor_block_on_wall"), "set_floor_block_on_wall_enabled", "is_floor_block_on_wall_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians"), "set_floor_max_angle", "get_floor_max_angle");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_snap_length", PROPERTY_HINT_RANGE, "0,1,0.01,or_greater,suffix:m"), "set_floor_snap_length", "get_floor_snap_length");
- ADD_GROUP("Moving Platform", "moving_platform");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_apply_velocity_on_leave", PROPERTY_HINT_ENUM, "Always,Upward Only,Never", PROPERTY_USAGE_DEFAULT), "set_moving_platform_apply_velocity_on_leave", "get_moving_platform_apply_velocity_on_leave");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_floor_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_floor_layers", "get_moving_platform_floor_layers");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "moving_platform_wall_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_moving_platform_wall_layers", "get_moving_platform_wall_layers");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001,suffix:m"), "set_safe_margin", "get_safe_margin");
+
+ ADD_GROUP("Moving Platform", "platform_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_on_leave", PROPERTY_HINT_ENUM, "Add Velocity,Add Upward Velocity,Do Nothing", PROPERTY_USAGE_DEFAULT), "set_platform_on_leave", "get_platform_on_leave");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_floor_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_platform_floor_layers", "get_platform_floor_layers");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "platform_wall_layers", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_platform_wall_layers", "get_platform_wall_layers");
+
+ ADD_GROUP("Collision", "");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001,suffix:m"), "set_safe_margin", "get_safe_margin");
BIND_ENUM_CONSTANT(MOTION_MODE_GROUNDED);
BIND_ENUM_CONSTANT(MOTION_MODE_FLOATING);
- BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_ALWAYS);
- BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY);
- BIND_ENUM_CONSTANT(PLATFORM_VEL_ON_LEAVE_NEVER);
+ BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_ADD_VELOCITY);
+ BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY);
+ BIND_ENUM_CONSTANT(PLATFORM_ON_LEAVE_DO_NOTHING);
}
-void CharacterBody3D::_validate_property(PropertyInfo &property) const {
+void CharacterBody3D::_validate_property(PropertyInfo &p_property) const {
if (motion_mode == MOTION_MODE_FLOATING) {
- if (property.name.begins_with("floor_") || property.name == "up_direction" || property.name == "slide_on_ceiling") {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name.begins_with("floor_") || p_property.name == "up_direction" || p_property.name == "slide_on_ceiling") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
- PhysicsBody3D::_validate_property(property);
}
CharacterBody3D::CharacterBody3D() :
@@ -2057,6 +2064,10 @@ int KinematicCollision3D::get_collision_count() const {
return result.collision_count;
}
+real_t KinematicCollision3D::get_depth() const {
+ return result.collision_depth;
+}
+
Vector3 KinematicCollision3D::get_position(int p_collision_index) const {
ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, Vector3());
return result.collisions[p_collision_index].position;
@@ -2127,6 +2138,7 @@ Vector3 KinematicCollision3D::get_collider_velocity(int p_collision_index) const
void KinematicCollision3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_travel"), &KinematicCollision3D::get_travel);
ClassDB::bind_method(D_METHOD("get_remainder"), &KinematicCollision3D::get_remainder);
+ ClassDB::bind_method(D_METHOD("get_depth"), &KinematicCollision3D::get_depth);
ClassDB::bind_method(D_METHOD("get_collision_count"), &KinematicCollision3D::get_collision_count);
ClassDB::bind_method(D_METHOD("get_position", "collision_index"), &KinematicCollision3D::get_position, DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_normal", "collision_index"), &KinematicCollision3D::get_normal, DEFVAL(0));
@@ -2272,13 +2284,13 @@ bool PhysicalBone3D::ConeJointData::_set(const StringName &p_name, const Variant
}
if ("joint_constraints/swing_span" == p_name) {
- swing_span = Math::deg2rad(real_t(p_value));
+ swing_span = Math::deg_to_rad(real_t(p_value));
if (j.is_valid()) {
PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN, swing_span);
}
} else if ("joint_constraints/twist_span" == p_name) {
- twist_span = Math::deg2rad(real_t(p_value));
+ twist_span = Math::deg_to_rad(real_t(p_value));
if (j.is_valid()) {
PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN, twist_span);
}
@@ -2314,9 +2326,9 @@ bool PhysicalBone3D::ConeJointData::_get(const StringName &p_name, Variant &r_re
}
if ("joint_constraints/swing_span" == p_name) {
- r_ret = Math::rad2deg(swing_span);
+ r_ret = Math::rad_to_deg(swing_span);
} else if ("joint_constraints/twist_span" == p_name) {
- r_ret = Math::rad2deg(twist_span);
+ r_ret = Math::rad_to_deg(twist_span);
} else if ("joint_constraints/bias" == p_name) {
r_ret = bias;
} else if ("joint_constraints/softness" == p_name) {
@@ -2352,13 +2364,13 @@ bool PhysicalBone3D::HingeJointData::_set(const StringName &p_name, const Varian
}
} else if ("joint_constraints/angular_limit_upper" == p_name) {
- angular_limit_upper = Math::deg2rad(real_t(p_value));
+ angular_limit_upper = Math::deg_to_rad(real_t(p_value));
if (j.is_valid()) {
PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_UPPER, angular_limit_upper);
}
} else if ("joint_constraints/angular_limit_lower" == p_name) {
- angular_limit_lower = Math::deg2rad(real_t(p_value));
+ angular_limit_lower = Math::deg_to_rad(real_t(p_value));
if (j.is_valid()) {
PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HINGE_JOINT_LIMIT_LOWER, angular_limit_lower);
}
@@ -2396,9 +2408,9 @@ bool PhysicalBone3D::HingeJointData::_get(const StringName &p_name, Variant &r_r
if ("joint_constraints/angular_limit_enabled" == p_name) {
r_ret = angular_limit_enabled;
} else if ("joint_constraints/angular_limit_upper" == p_name) {
- r_ret = Math::rad2deg(angular_limit_upper);
+ r_ret = Math::rad_to_deg(angular_limit_upper);
} else if ("joint_constraints/angular_limit_lower" == p_name) {
- r_ret = Math::rad2deg(angular_limit_lower);
+ r_ret = Math::rad_to_deg(angular_limit_lower);
} else if ("joint_constraints/angular_limit_bias" == p_name) {
r_ret = angular_limit_bias;
} else if ("joint_constraints/angular_limit_softness" == p_name) {
@@ -2459,13 +2471,13 @@ bool PhysicalBone3D::SliderJointData::_set(const StringName &p_name, const Varia
}
} else if ("joint_constraints/angular_limit_upper" == p_name) {
- angular_limit_upper = Math::deg2rad(real_t(p_value));
+ angular_limit_upper = Math::deg_to_rad(real_t(p_value));
if (j.is_valid()) {
PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_UPPER, angular_limit_upper);
}
} else if ("joint_constraints/angular_limit_lower" == p_name) {
- angular_limit_lower = Math::deg2rad(real_t(p_value));
+ angular_limit_lower = Math::deg_to_rad(real_t(p_value));
if (j.is_valid()) {
PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SLIDER_JOINT_ANGULAR_LIMIT_LOWER, angular_limit_lower);
}
@@ -2511,9 +2523,9 @@ bool PhysicalBone3D::SliderJointData::_get(const StringName &p_name, Variant &r_
} else if ("joint_constraints/linear_limit_damping" == p_name) {
r_ret = linear_limit_damping;
} else if ("joint_constraints/angular_limit_upper" == p_name) {
- r_ret = Math::rad2deg(angular_limit_upper);
+ r_ret = Math::rad_to_deg(angular_limit_upper);
} else if ("joint_constraints/angular_limit_lower" == p_name) {
- r_ret = Math::rad2deg(angular_limit_lower);
+ r_ret = Math::rad_to_deg(angular_limit_lower);
} else if ("joint_constraints/angular_limit_softness" == p_name) {
r_ret = angular_limit_softness;
} else if ("joint_constraints/angular_limit_restitution" == p_name) {
@@ -2637,13 +2649,13 @@ bool PhysicalBone3D::SixDOFJointData::_set(const StringName &p_name, const Varia
}
} else if ("angular_limit_upper" == var_name) {
- axis_data[axis].angular_limit_upper = Math::deg2rad(real_t(p_value));
+ axis_data[axis].angular_limit_upper = Math::deg_to_rad(real_t(p_value));
if (j.is_valid()) {
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_UPPER_LIMIT, axis_data[axis].angular_limit_upper);
}
} else if ("angular_limit_lower" == var_name) {
- axis_data[axis].angular_limit_lower = Math::deg2rad(real_t(p_value));
+ axis_data[axis].angular_limit_lower = Math::deg_to_rad(real_t(p_value));
if (j.is_valid()) {
PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer3D::G6DOF_JOINT_ANGULAR_LOWER_LIMIT, axis_data[axis].angular_limit_lower);
}
@@ -2753,9 +2765,9 @@ bool PhysicalBone3D::SixDOFJointData::_get(const StringName &p_name, Variant &r_
} else if ("angular_limit_enabled" == var_name) {
r_ret = axis_data[axis].angular_limit_enabled;
} else if ("angular_limit_upper" == var_name) {
- r_ret = Math::rad2deg(axis_data[axis].angular_limit_upper);
+ r_ret = Math::rad_to_deg(axis_data[axis].angular_limit_upper);
} else if ("angular_limit_lower" == var_name) {
- r_ret = Math::rad2deg(axis_data[axis].angular_limit_lower);
+ r_ret = Math::rad_to_deg(axis_data[axis].angular_limit_lower);
} else if ("angular_limit_softness" == var_name) {
r_ret = axis_data[axis].angular_limit_softness;
} else if ("angular_restitution" == var_name) {
@@ -3409,9 +3421,10 @@ void PhysicalBone3D::_start_physics_simulation() {
return;
}
reset_to_rest_position();
- set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC);
+ set_body_mode(PhysicsServer3D::BODY_MODE_RIGID);
PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
+ PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), get_collision_priority());
PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), this, _body_state_changed_callback);
set_as_top_level(true);
_internal_simulate_physics = true;
@@ -3425,10 +3438,12 @@ void PhysicalBone3D::_stop_physics_simulation() {
set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC);
PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
+ PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), get_collision_priority());
} else {
set_body_mode(PhysicsServer3D::BODY_MODE_STATIC);
PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), 0);
PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), 0);
+ PhysicsServer3D::get_singleton()->body_set_collision_priority(get_rid(), 1.0);
}
if (_internal_simulate_physics) {
PhysicsServer3D::get_singleton()->body_set_state_sync_callback(get_rid(), nullptr, nullptr);
diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h
index e4a41be6c0..184d8b00d0 100644
--- a/scene/3d/physics_body_3d.h
+++ b/scene/3d/physics_body_3d.h
@@ -129,8 +129,8 @@ private:
bool is_sync_to_physics_enabled() const;
};
-class RigidDynamicBody3D : public PhysicsBody3D {
- GDCLASS(RigidDynamicBody3D, PhysicsBody3D);
+class RigidBody3D : public PhysicsBody3D {
+ GDCLASS(RigidBody3D, PhysicsBody3D);
public:
enum FreezeMode {
@@ -198,7 +198,7 @@ private:
tagged = false;
}
};
- struct RigidDynamicBody3D_RemoveAction {
+ struct RigidBody3D_RemoveAction {
RID rid;
ObjectID body_id;
ShapePair pair;
@@ -226,7 +226,7 @@ protected:
void _notification(int p_what);
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState3D *)
@@ -300,11 +300,12 @@ public:
void set_max_contacts_reported(int p_amount);
int get_max_contacts_reported() const;
+ int get_contact_count() const;
void set_use_continuous_collision_detection(bool p_enable);
bool is_using_continuous_collision_detection() const;
- Array get_colliding_bodies() const;
+ TypedArray<Node3D> get_colliding_bodies() const;
void apply_central_impulse(const Vector3 &p_impulse);
void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3());
@@ -326,16 +327,16 @@ public:
virtual TypedArray<String> get_configuration_warnings() const override;
- RigidDynamicBody3D();
- ~RigidDynamicBody3D();
+ RigidBody3D();
+ ~RigidBody3D();
private:
void _reload_physics_characteristics();
};
-VARIANT_ENUM_CAST(RigidDynamicBody3D::FreezeMode);
-VARIANT_ENUM_CAST(RigidDynamicBody3D::CenterOfMassMode);
-VARIANT_ENUM_CAST(RigidDynamicBody3D::DampMode);
+VARIANT_ENUM_CAST(RigidBody3D::FreezeMode);
+VARIANT_ENUM_CAST(RigidBody3D::CenterOfMassMode);
+VARIANT_ENUM_CAST(RigidBody3D::DampMode);
class KinematicCollision3D;
@@ -347,10 +348,10 @@ public:
MOTION_MODE_GROUNDED,
MOTION_MODE_FLOATING,
};
- enum MovingPlatformApplyVelocityOnLeave {
- PLATFORM_VEL_ON_LEAVE_ALWAYS,
- PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY,
- PLATFORM_VEL_ON_LEAVE_NEVER,
+ enum PlatformOnLeave {
+ PLATFORM_ON_LEAVE_ADD_VELOCITY,
+ PLATFORM_ON_LEAVE_ADD_UPWARD_VELOCITY,
+ PLATFORM_ON_LEAVE_DO_NOTHING,
};
bool move_and_slide();
@@ -382,7 +383,7 @@ public:
private:
real_t margin = 0.001;
MotionMode motion_mode = MOTION_MODE_GROUNDED;
- MovingPlatformApplyVelocityOnLeave moving_platform_apply_velocity_on_leave = PLATFORM_VEL_ON_LEAVE_ALWAYS;
+ PlatformOnLeave platform_on_leave = PLATFORM_ON_LEAVE_ADD_VELOCITY;
union CollisionState {
uint32_t state = 0;
struct {
@@ -410,11 +411,11 @@ private:
int platform_layer = 0;
RID platform_rid;
ObjectID platform_object_id;
- uint32_t moving_platform_floor_layers = UINT32_MAX;
- uint32_t moving_platform_wall_layers = 0;
+ uint32_t platform_floor_layers = UINT32_MAX;
+ uint32_t platform_wall_layers = 0;
real_t floor_snap_length = 0.1;
- real_t floor_max_angle = Math::deg2rad((real_t)45.0);
- real_t wall_min_slide_angle = Math::deg2rad((real_t)15.0);
+ real_t floor_max_angle = Math::deg_to_rad((real_t)45.0);
+ real_t wall_min_slide_angle = Math::deg_to_rad((real_t)15.0);
Vector3 up_direction = Vector3(0.0, 1.0, 0.0);
Vector3 velocity;
Vector3 floor_normal;
@@ -456,17 +457,17 @@ private:
real_t get_wall_min_slide_angle() const;
void set_wall_min_slide_angle(real_t p_radians);
- uint32_t get_moving_platform_floor_layers() const;
- void set_moving_platform_floor_layers(const uint32_t p_exclude_layer);
+ uint32_t get_platform_floor_layers() const;
+ void set_platform_floor_layers(const uint32_t p_exclude_layer);
- uint32_t get_moving_platform_wall_layers() const;
- void set_moving_platform_wall_layers(const uint32_t p_exclude_layer);
+ uint32_t get_platform_wall_layers() const;
+ void set_platform_wall_layers(const uint32_t p_exclude_layer);
void set_motion_mode(MotionMode p_mode);
MotionMode get_motion_mode() const;
- void set_moving_platform_apply_velocity_on_leave(MovingPlatformApplyVelocityOnLeave p_on_leave_velocity);
- MovingPlatformApplyVelocityOnLeave get_moving_platform_apply_velocity_on_leave() const;
+ void set_platform_on_leave(PlatformOnLeave p_on_leave_velocity);
+ PlatformOnLeave get_platform_on_leave() const;
void _move_and_slide_floating(double p_delta);
void _move_and_slide_grounded(double p_delta, bool p_was_on_floor);
@@ -483,11 +484,11 @@ private:
protected:
void _notification(int p_what);
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
};
VARIANT_ENUM_CAST(CharacterBody3D::MotionMode);
-VARIANT_ENUM_CAST(CharacterBody3D::MovingPlatformApplyVelocityOnLeave);
+VARIANT_ENUM_CAST(CharacterBody3D::PlatformOnLeave);
class KinematicCollision3D : public RefCounted {
GDCLASS(KinematicCollision3D, RefCounted);
@@ -504,6 +505,7 @@ public:
Vector3 get_travel() const;
Vector3 get_remainder() const;
int get_collision_count() const;
+ real_t get_depth() const;
Vector3 get_position(int p_collision_index = 0) const;
Vector3 get_normal(int p_collision_index = 0) const;
real_t get_angle(int p_collision_index = 0, const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const;
diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp
index 2db5ab2d4e..a45ef52452 100644
--- a/scene/3d/ray_cast_3d.cpp
+++ b/scene/3d/ray_cast_3d.cpp
@@ -88,6 +88,10 @@ Object *RayCast3D::get_collider() const {
return ObjectDB::get_instance(against);
}
+RID RayCast3D::get_collider_rid() const {
+ return against_rid;
+}
+
int RayCast3D::get_collider_shape() const {
return against_shape;
}
@@ -224,12 +228,14 @@ void RayCast3D::_update_raycast_state() {
if (dss->intersect_ray(ray_params, rr)) {
collided = true;
against = rr.collider_id;
+ against_rid = rr.rid;
collision_point = rr.position;
collision_normal = rr.normal;
against_shape = rr.shape;
} else {
collided = false;
against = ObjectID();
+ against_rid = RID();
against_shape = 0;
}
}
@@ -302,6 +308,7 @@ void RayCast3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("force_raycast_update"), &RayCast3D::force_raycast_update);
ClassDB::bind_method(D_METHOD("get_collider"), &RayCast3D::get_collider);
+ ClassDB::bind_method(D_METHOD("get_collider_rid"), &RayCast3D::get_collider_rid);
ClassDB::bind_method(D_METHOD("get_collider_shape"), &RayCast3D::get_collider_shape);
ClassDB::bind_method(D_METHOD("get_collision_point"), &RayCast3D::get_collision_point);
ClassDB::bind_method(D_METHOD("get_collision_normal"), &RayCast3D::get_collision_normal);
diff --git a/scene/3d/ray_cast_3d.h b/scene/3d/ray_cast_3d.h
index aa62f6927e..eb5c3ee90a 100644
--- a/scene/3d/ray_cast_3d.h
+++ b/scene/3d/ray_cast_3d.h
@@ -41,6 +41,7 @@ class RayCast3D : public Node3D {
bool enabled = true;
bool collided = false;
ObjectID against;
+ RID against_rid;
int against_shape = 0;
Vector3 collision_point;
Vector3 collision_normal;
@@ -113,6 +114,7 @@ public:
void force_raycast_update();
bool is_colliding() const;
Object *get_collider() const;
+ RID get_collider_rid() const;
int get_collider_shape() const;
Vector3 get_collision_point() const;
Vector3 get_collision_normal() const;
diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp
index 0a9d6cbbeb..bc3cc31963 100644
--- a/scene/3d/reflection_probe.cpp
+++ b/scene/3d/reflection_probe.cpp
@@ -178,13 +178,12 @@ AABB ReflectionProbe::get_aabb() const {
return aabb;
}
-void ReflectionProbe::_validate_property(PropertyInfo &property) const {
- if (property.name == "interior/ambient_color" || property.name == "interior/ambient_color_energy") {
+void ReflectionProbe::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "ambient_color" || p_property.name == "ambient_color_energy") {
if (ambient_mode != AMBIENT_COLOR) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
- VisualInstance3D::_validate_property(property);
}
void ReflectionProbe::_bind_methods() {
diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h
index a161717ece..5a5a3fe0bb 100644
--- a/scene/3d/reflection_probe.h
+++ b/scene/3d/reflection_probe.h
@@ -67,7 +67,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_intensity(float p_intensity);
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index 4c38fccc8b..1bc138704e 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -176,39 +176,37 @@ void Skeleton3D::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-void Skeleton3D::_validate_property(PropertyInfo &property) const {
- PackedStringArray split = property.name.split("/");
+void Skeleton3D::_validate_property(PropertyInfo &p_property) const {
+ PackedStringArray split = p_property.name.split("/");
if (split.size() == 3 && split[0] == "bones") {
if (split[2] == "rest") {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
if (is_show_rest_only()) {
if (split[2] == "enabled") {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
if (split[2] == "position") {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
if (split[2] == "rotation") {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
if (split[2] == "scale") {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
} else if (!is_bone_enabled(split[1].to_int())) {
if (split[2] == "position") {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
if (split[2] == "rotation") {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
if (split[2] == "scale") {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
}
}
-
- Node3D::_validate_property(property);
}
void Skeleton3D::_update_process_order() {
@@ -615,42 +613,6 @@ Vector<int> Skeleton3D::get_bone_children(int p_bone) {
return bones[p_bone].child_bones;
}
-void Skeleton3D::set_bone_children(int p_bone, Vector<int> p_children) {
- const int bone_size = bones.size();
- ERR_FAIL_INDEX(p_bone, bone_size);
- bones.write[p_bone].child_bones = p_children;
-
- process_order_dirty = true;
- rest_dirty = true;
- _make_dirty();
-}
-
-void Skeleton3D::add_bone_child(int p_bone, int p_child) {
- const int bone_size = bones.size();
- ERR_FAIL_INDEX(p_bone, bone_size);
- bones.write[p_bone].child_bones.push_back(p_child);
-
- process_order_dirty = true;
- rest_dirty = true;
- _make_dirty();
-}
-
-void Skeleton3D::remove_bone_child(int p_bone, int p_child) {
- const int bone_size = bones.size();
- ERR_FAIL_INDEX(p_bone, bone_size);
-
- int child_idx = bones[p_bone].child_bones.find(p_child);
- if (child_idx >= 0) {
- bones.write[p_bone].child_bones.remove_at(child_idx);
- } else {
- WARN_PRINT("Cannot remove child bone: Child bone not found.");
- }
-
- process_order_dirty = true;
- rest_dirty = true;
- _make_dirty();
-}
-
Vector<int> Skeleton3D::get_parentless_bones() {
_update_process_order();
return parentless_bones;
@@ -762,6 +724,20 @@ Vector3 Skeleton3D::get_bone_pose_scale(int p_bone) const {
return bones[p_bone].pose_scale;
}
+void Skeleton3D::reset_bone_pose(int p_bone) {
+ const int bone_size = bones.size();
+ ERR_FAIL_INDEX(p_bone, bone_size);
+ set_bone_pose_position(p_bone, bones[p_bone].rest.origin);
+ set_bone_pose_rotation(p_bone, bones[p_bone].rest.basis.get_rotation_quaternion());
+ set_bone_pose_scale(p_bone, bones[p_bone].rest.basis.get_scale());
+}
+
+void Skeleton3D::reset_bone_poses() {
+ for (int i = 0; i < bones.size(); i++) {
+ reset_bone_pose(i);
+ }
+}
+
Transform3D Skeleton3D::get_bone_pose(int p_bone) const {
const int bone_size = bones.size();
ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D());
@@ -1226,9 +1202,6 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("unparent_bone_and_rest", "bone_idx"), &Skeleton3D::unparent_bone_and_rest);
ClassDB::bind_method(D_METHOD("get_bone_children", "bone_idx"), &Skeleton3D::get_bone_children);
- ClassDB::bind_method(D_METHOD("set_bone_children", "bone_idx", "bone_children"), &Skeleton3D::set_bone_children);
- ClassDB::bind_method(D_METHOD("add_bone_child", "bone_idx", "child_bone_idx"), &Skeleton3D::add_bone_child);
- ClassDB::bind_method(D_METHOD("remove_bone_child", "bone_idx", "child_bone_idx"), &Skeleton3D::remove_bone_child);
ClassDB::bind_method(D_METHOD("get_parentless_bones"), &Skeleton3D::get_parentless_bones);
@@ -1252,6 +1225,9 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bone_pose_rotation", "bone_idx"), &Skeleton3D::get_bone_pose_rotation);
ClassDB::bind_method(D_METHOD("get_bone_pose_scale", "bone_idx"), &Skeleton3D::get_bone_pose_scale);
+ ClassDB::bind_method(D_METHOD("reset_bone_pose", "bone_idx"), &Skeleton3D::reset_bone_pose);
+ ClassDB::bind_method(D_METHOD("reset_bone_poses"), &Skeleton3D::reset_bone_poses);
+
ClassDB::bind_method(D_METHOD("is_bone_enabled", "bone_idx"), &Skeleton3D::is_bone_enabled);
ClassDB::bind_method(D_METHOD("set_bone_enabled", "bone_idx", "enabled"), &Skeleton3D::set_bone_enabled, DEFVAL(true));
diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h
index 8b69410a39..79feadf44f 100644
--- a/scene/3d/skeleton_3d.h
+++ b/scene/3d/skeleton_3d.h
@@ -156,7 +156,7 @@ protected:
bool _get(const StringName &p_path, Variant &r_ret) const;
bool _set(const StringName &p_path, const Variant &p_value);
void _get_property_list(List<PropertyInfo> *p_list) const;
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
static void _bind_methods();
@@ -227,6 +227,9 @@ public:
Quaternion get_bone_pose_rotation(int p_bone) const;
Vector3 get_bone_pose_scale(int p_bone) const;
+ void reset_bone_pose(int p_bone);
+ void reset_bone_poses();
+
void clear_bones_global_pose_override();
Transform3D get_bone_global_pose_override(int p_bone) const;
void set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent = false);
diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp
index 2182c5ba11..f0534c8099 100644
--- a/scene/3d/skeleton_ik_3d.cpp
+++ b/scene/3d/skeleton_ik_3d.cpp
@@ -329,8 +329,8 @@ void FabrikInverseKinematic::_update_chain(const Skeleton3D *p_sk, ChainItem *p_
}
}
-void SkeletonIK3D::_validate_property(PropertyInfo &property) const {
- if (property.name == "root_bone" || property.name == "tip_bone") {
+void SkeletonIK3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "root_bone" || p_property.name == "tip_bone") {
if (skeleton) {
String names("--,");
for (int i = 0; i < skeleton->get_bone_count(); i++) {
@@ -340,15 +340,13 @@ void SkeletonIK3D::_validate_property(PropertyInfo &property) const {
names += skeleton->get_bone_name(i);
}
- property.hint = PROPERTY_HINT_ENUM;
- property.hint_string = names;
+ p_property.hint = PROPERTY_HINT_ENUM;
+ p_property.hint_string = names;
} else {
- property.hint = PROPERTY_HINT_NONE;
- property.hint_string = "";
+ p_property.hint = PROPERTY_HINT_NONE;
+ p_property.hint_string = "";
}
}
-
- Node::_validate_property(property);
}
void SkeletonIK3D::_bind_methods() {
diff --git a/scene/3d/skeleton_ik_3d.h b/scene/3d/skeleton_ik_3d.h
index 6ae86a2bf6..097df2c400 100644
--- a/scene/3d/skeleton_ik_3d.h
+++ b/scene/3d/skeleton_ik_3d.h
@@ -137,7 +137,7 @@ class SkeletonIK3D : public Node {
FabrikInverseKinematic::Task *task = nullptr;
protected:
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
virtual void _notification(int p_what);
diff --git a/scene/3d/soft_dynamic_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index d68e7fd527..47858b372c 100644
--- a/scene/3d/soft_dynamic_body_3d.cpp
+++ b/scene/3d/soft_body_3d.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* soft_dynamic_body_3d.cpp */
+/* soft_body_3d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "soft_dynamic_body_3d.h"
+#include "soft_body_3d.h"
#include "scene/3d/physics_body_3d.h"
-SoftDynamicBodyRenderingServerHandler::SoftDynamicBodyRenderingServerHandler() {}
+SoftBodyRenderingServerHandler::SoftBodyRenderingServerHandler() {}
-void SoftDynamicBodyRenderingServerHandler::prepare(RID p_mesh, int p_surface) {
+void SoftBodyRenderingServerHandler::prepare(RID p_mesh, int p_surface) {
clear();
ERR_FAIL_COND(!p_mesh.is_valid());
@@ -56,7 +56,7 @@ void SoftDynamicBodyRenderingServerHandler::prepare(RID p_mesh, int p_surface) {
offset_normal = surface_offsets[RS::ARRAY_NORMAL];
}
-void SoftDynamicBodyRenderingServerHandler::clear() {
+void SoftBodyRenderingServerHandler::clear() {
buffer.resize(0);
stride = 0;
offset_vertices = 0;
@@ -66,48 +66,57 @@ void SoftDynamicBodyRenderingServerHandler::clear() {
mesh = RID();
}
-void SoftDynamicBodyRenderingServerHandler::open() {
+void SoftBodyRenderingServerHandler::open() {
write_buffer = buffer.ptrw();
}
-void SoftDynamicBodyRenderingServerHandler::close() {
+void SoftBodyRenderingServerHandler::close() {
write_buffer = nullptr;
}
-void SoftDynamicBodyRenderingServerHandler::commit_changes() {
+void SoftBodyRenderingServerHandler::commit_changes() {
RS::get_singleton()->mesh_surface_update_vertex_region(mesh, surface, 0, buffer);
}
-void SoftDynamicBodyRenderingServerHandler::set_vertex(int p_vertex_id, const void *p_vector3) {
+void SoftBodyRenderingServerHandler::set_vertex(int p_vertex_id, const void *p_vector3) {
memcpy(&write_buffer[p_vertex_id * stride + offset_vertices], p_vector3, sizeof(float) * 3);
}
-void SoftDynamicBodyRenderingServerHandler::set_normal(int p_vertex_id, const void *p_vector3) {
- memcpy(&write_buffer[p_vertex_id * stride + offset_normal], p_vector3, sizeof(float) * 3);
+void SoftBodyRenderingServerHandler::set_normal(int p_vertex_id, const void *p_vector3) {
+ // Store normal vector in A2B10G10R10 format.
+ Vector3 n;
+ memcpy(&n, p_vector3, sizeof(Vector3));
+ n *= Vector3(0.5, 0.5, 0.5);
+ n += Vector3(0.5, 0.5, 0.5);
+ Vector2 res = n.octahedron_encode();
+ uint32_t value = 0;
+ value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
+ memcpy(&write_buffer[p_vertex_id * stride + offset_normal], &value, sizeof(uint32_t));
}
-void SoftDynamicBodyRenderingServerHandler::set_aabb(const AABB &p_aabb) {
+void SoftBodyRenderingServerHandler::set_aabb(const AABB &p_aabb) {
RS::get_singleton()->mesh_set_custom_aabb(mesh, p_aabb);
}
-SoftDynamicBody3D::PinnedPoint::PinnedPoint() {
+SoftBody3D::PinnedPoint::PinnedPoint() {
}
-SoftDynamicBody3D::PinnedPoint::PinnedPoint(const PinnedPoint &obj_tocopy) {
+SoftBody3D::PinnedPoint::PinnedPoint(const PinnedPoint &obj_tocopy) {
point_index = obj_tocopy.point_index;
spatial_attachment_path = obj_tocopy.spatial_attachment_path;
spatial_attachment = obj_tocopy.spatial_attachment;
offset = obj_tocopy.offset;
}
-void SoftDynamicBody3D::PinnedPoint::operator=(const PinnedPoint &obj) {
+void SoftBody3D::PinnedPoint::operator=(const PinnedPoint &obj) {
point_index = obj.point_index;
spatial_attachment_path = obj.spatial_attachment_path;
spatial_attachment = obj.spatial_attachment;
offset = obj.offset;
}
-void SoftDynamicBody3D::_update_pickable() {
+void SoftBody3D::_update_pickable() {
if (!is_inside_tree()) {
return;
}
@@ -115,7 +124,7 @@ void SoftDynamicBody3D::_update_pickable() {
PhysicsServer3D::get_singleton()->soft_body_set_ray_pickable(physics_rid, pickable);
}
-bool SoftDynamicBody3D::_set(const StringName &p_name, const Variant &p_value) {
+bool SoftBody3D::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name;
String which = name.get_slicec('/', 0);
@@ -132,7 +141,7 @@ bool SoftDynamicBody3D::_set(const StringName &p_name, const Variant &p_value) {
return false;
}
-bool SoftDynamicBody3D::_get(const StringName &p_name, Variant &r_ret) const {
+bool SoftBody3D::_get(const StringName &p_name, Variant &r_ret) const {
String name = p_name;
String which = name.get_slicec('/', 0);
@@ -159,7 +168,7 @@ bool SoftDynamicBody3D::_get(const StringName &p_name, Variant &r_ret) const {
return false;
}
-void SoftDynamicBody3D::_get_property_list(List<PropertyInfo> *p_list) const {
+void SoftBody3D::_get_property_list(List<PropertyInfo> *p_list) const {
const int pinned_points_indices_size = pinned_points.size();
p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, PNAME("pinned_points")));
@@ -172,7 +181,7 @@ void SoftDynamicBody3D::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-bool SoftDynamicBody3D::_set_property_pinned_points_indices(const Array &p_indices) {
+bool SoftBody3D::_set_property_pinned_points_indices(const Array &p_indices) {
const int p_indices_size = p_indices.size();
{ // Remove the pined points on physics server that will be removed by resize
@@ -201,7 +210,7 @@ bool SoftDynamicBody3D::_set_property_pinned_points_indices(const Array &p_indic
return true;
}
-bool SoftDynamicBody3D::_set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value) {
+bool SoftBody3D::_set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value) {
if (pinned_points.size() <= p_item) {
return false;
}
@@ -220,7 +229,7 @@ bool SoftDynamicBody3D::_set_property_pinned_points_attachment(int p_item, const
return true;
}
-bool SoftDynamicBody3D::_get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const {
+bool SoftBody3D::_get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const {
if (pinned_points.size() <= p_item) {
return false;
}
@@ -239,7 +248,7 @@ bool SoftDynamicBody3D::_get_property_pinned_points(int p_item, const String &p_
return true;
}
-void SoftDynamicBody3D::_notification(int p_what) {
+void SoftBody3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_WORLD: {
if (Engine::get_singleton()->is_editor_hint()) {
@@ -304,56 +313,56 @@ void SoftDynamicBody3D::_notification(int p_what) {
}
}
-void SoftDynamicBody3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("get_physics_rid"), &SoftDynamicBody3D::get_physics_rid);
+void SoftBody3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_physics_rid"), &SoftBody3D::get_physics_rid);
- ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &SoftDynamicBody3D::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &SoftDynamicBody3D::get_collision_mask);
+ ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &SoftBody3D::set_collision_mask);
+ ClassDB::bind_method(D_METHOD("get_collision_mask"), &SoftBody3D::get_collision_mask);
- ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &SoftDynamicBody3D::set_collision_layer);
- ClassDB::bind_method(D_METHOD("get_collision_layer"), &SoftDynamicBody3D::get_collision_layer);
+ ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &SoftBody3D::set_collision_layer);
+ ClassDB::bind_method(D_METHOD("get_collision_layer"), &SoftBody3D::get_collision_layer);
- ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &SoftDynamicBody3D::set_collision_mask_value);
- ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &SoftDynamicBody3D::get_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &SoftBody3D::set_collision_mask_value);
+ ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &SoftBody3D::get_collision_mask_value);
- ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &SoftDynamicBody3D::set_collision_layer_value);
- ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &SoftDynamicBody3D::get_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &SoftBody3D::set_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &SoftBody3D::get_collision_layer_value);
- ClassDB::bind_method(D_METHOD("set_parent_collision_ignore", "parent_collision_ignore"), &SoftDynamicBody3D::set_parent_collision_ignore);
- ClassDB::bind_method(D_METHOD("get_parent_collision_ignore"), &SoftDynamicBody3D::get_parent_collision_ignore);
+ ClassDB::bind_method(D_METHOD("set_parent_collision_ignore", "parent_collision_ignore"), &SoftBody3D::set_parent_collision_ignore);
+ ClassDB::bind_method(D_METHOD("get_parent_collision_ignore"), &SoftBody3D::get_parent_collision_ignore);
- ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &SoftDynamicBody3D::set_disable_mode);
- ClassDB::bind_method(D_METHOD("get_disable_mode"), &SoftDynamicBody3D::get_disable_mode);
+ ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &SoftBody3D::set_disable_mode);
+ ClassDB::bind_method(D_METHOD("get_disable_mode"), &SoftBody3D::get_disable_mode);
- ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &SoftDynamicBody3D::get_collision_exceptions);
- ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &SoftDynamicBody3D::add_collision_exception_with);
- ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &SoftDynamicBody3D::remove_collision_exception_with);
+ ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &SoftBody3D::get_collision_exceptions);
+ ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &SoftBody3D::add_collision_exception_with);
+ ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &SoftBody3D::remove_collision_exception_with);
- ClassDB::bind_method(D_METHOD("set_simulation_precision", "simulation_precision"), &SoftDynamicBody3D::set_simulation_precision);
- ClassDB::bind_method(D_METHOD("get_simulation_precision"), &SoftDynamicBody3D::get_simulation_precision);
+ ClassDB::bind_method(D_METHOD("set_simulation_precision", "simulation_precision"), &SoftBody3D::set_simulation_precision);
+ ClassDB::bind_method(D_METHOD("get_simulation_precision"), &SoftBody3D::get_simulation_precision);
- ClassDB::bind_method(D_METHOD("set_total_mass", "mass"), &SoftDynamicBody3D::set_total_mass);
- ClassDB::bind_method(D_METHOD("get_total_mass"), &SoftDynamicBody3D::get_total_mass);
+ ClassDB::bind_method(D_METHOD("set_total_mass", "mass"), &SoftBody3D::set_total_mass);
+ ClassDB::bind_method(D_METHOD("get_total_mass"), &SoftBody3D::get_total_mass);
- ClassDB::bind_method(D_METHOD("set_linear_stiffness", "linear_stiffness"), &SoftDynamicBody3D::set_linear_stiffness);
- ClassDB::bind_method(D_METHOD("get_linear_stiffness"), &SoftDynamicBody3D::get_linear_stiffness);
+ ClassDB::bind_method(D_METHOD("set_linear_stiffness", "linear_stiffness"), &SoftBody3D::set_linear_stiffness);
+ ClassDB::bind_method(D_METHOD("get_linear_stiffness"), &SoftBody3D::get_linear_stiffness);
- ClassDB::bind_method(D_METHOD("set_pressure_coefficient", "pressure_coefficient"), &SoftDynamicBody3D::set_pressure_coefficient);
- ClassDB::bind_method(D_METHOD("get_pressure_coefficient"), &SoftDynamicBody3D::get_pressure_coefficient);
+ ClassDB::bind_method(D_METHOD("set_pressure_coefficient", "pressure_coefficient"), &SoftBody3D::set_pressure_coefficient);
+ ClassDB::bind_method(D_METHOD("get_pressure_coefficient"), &SoftBody3D::get_pressure_coefficient);
- ClassDB::bind_method(D_METHOD("set_damping_coefficient", "damping_coefficient"), &SoftDynamicBody3D::set_damping_coefficient);
- ClassDB::bind_method(D_METHOD("get_damping_coefficient"), &SoftDynamicBody3D::get_damping_coefficient);
+ ClassDB::bind_method(D_METHOD("set_damping_coefficient", "damping_coefficient"), &SoftBody3D::set_damping_coefficient);
+ ClassDB::bind_method(D_METHOD("get_damping_coefficient"), &SoftBody3D::get_damping_coefficient);
- ClassDB::bind_method(D_METHOD("set_drag_coefficient", "drag_coefficient"), &SoftDynamicBody3D::set_drag_coefficient);
- ClassDB::bind_method(D_METHOD("get_drag_coefficient"), &SoftDynamicBody3D::get_drag_coefficient);
+ ClassDB::bind_method(D_METHOD("set_drag_coefficient", "drag_coefficient"), &SoftBody3D::set_drag_coefficient);
+ ClassDB::bind_method(D_METHOD("get_drag_coefficient"), &SoftBody3D::get_drag_coefficient);
- ClassDB::bind_method(D_METHOD("get_point_transform", "point_index"), &SoftDynamicBody3D::get_point_transform);
+ ClassDB::bind_method(D_METHOD("get_point_transform", "point_index"), &SoftBody3D::get_point_transform);
- ClassDB::bind_method(D_METHOD("set_point_pinned", "point_index", "pinned", "attachment_path"), &SoftDynamicBody3D::pin_point, DEFVAL(NodePath()));
- ClassDB::bind_method(D_METHOD("is_point_pinned", "point_index"), &SoftDynamicBody3D::is_point_pinned);
+ ClassDB::bind_method(D_METHOD("set_point_pinned", "point_index", "pinned", "attachment_path"), &SoftBody3D::pin_point, DEFVAL(NodePath()));
+ ClassDB::bind_method(D_METHOD("is_point_pinned", "point_index"), &SoftBody3D::is_point_pinned);
- ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &SoftDynamicBody3D::set_ray_pickable);
- ClassDB::bind_method(D_METHOD("is_ray_pickable"), &SoftDynamicBody3D::is_ray_pickable);
+ ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &SoftBody3D::set_ray_pickable);
+ ClassDB::bind_method(D_METHOD("is_ray_pickable"), &SoftBody3D::is_ray_pickable);
ADD_GROUP("Collision", "collision_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
@@ -375,7 +384,7 @@ void SoftDynamicBody3D::_bind_methods() {
BIND_ENUM_CONSTANT(DISABLE_MODE_KEEP_ACTIVE);
}
-TypedArray<String> SoftDynamicBody3D::get_configuration_warnings() const {
+TypedArray<String> SoftBody3D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (mesh.is_null()) {
@@ -384,13 +393,13 @@ TypedArray<String> SoftDynamicBody3D::get_configuration_warnings() const {
Transform3D t = get_transform();
if ((ABS(t.basis.get_column(0).length() - 1.0) > 0.05 || ABS(t.basis.get_column(1).length() - 1.0) > 0.05 || ABS(t.basis.get_column(2).length() - 1.0) > 0.05)) {
- warnings.push_back(RTR("Size changes to SoftDynamicBody3D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
+ warnings.push_back(RTR("Size changes to SoftBody3D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead."));
}
return warnings;
}
-void SoftDynamicBody3D::_update_physics_server() {
+void SoftBody3D::_update_physics_server() {
if (!simulation_started) {
return;
}
@@ -406,7 +415,7 @@ void SoftDynamicBody3D::_update_physics_server() {
}
}
-void SoftDynamicBody3D::_draw_soft_mesh() {
+void SoftBody3D::_draw_soft_mesh() {
if (mesh.is_null()) {
return;
}
@@ -436,7 +445,7 @@ void SoftDynamicBody3D::_draw_soft_mesh() {
rendering_server_handler->commit_changes();
}
-void SoftDynamicBody3D::_prepare_physics_server() {
+void SoftBody3D::_prepare_physics_server() {
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
if (mesh.is_valid()) {
@@ -456,22 +465,22 @@ void SoftDynamicBody3D::_prepare_physics_server() {
mesh_rid = mesh->get_rid();
}
PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, mesh_rid);
- RS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &SoftDynamicBody3D::_draw_soft_mesh));
+ RS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &SoftBody3D::_draw_soft_mesh));
} else {
PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, RID());
- if (RS::get_singleton()->is_connected("frame_pre_draw", callable_mp(this, &SoftDynamicBody3D::_draw_soft_mesh))) {
- RS::get_singleton()->disconnect("frame_pre_draw", callable_mp(this, &SoftDynamicBody3D::_draw_soft_mesh));
+ if (RS::get_singleton()->is_connected("frame_pre_draw", callable_mp(this, &SoftBody3D::_draw_soft_mesh))) {
+ RS::get_singleton()->disconnect("frame_pre_draw", callable_mp(this, &SoftBody3D::_draw_soft_mesh));
}
}
}
-void SoftDynamicBody3D::_become_mesh_owner() {
+void SoftBody3D::_become_mesh_owner() {
Vector<Ref<Material>> copy_materials;
copy_materials.append_array(surface_override_materials);
ERR_FAIL_COND(!mesh->get_surface_count());
- // Get current mesh array and create new mesh array with necessary flag for SoftDynamicBody
+ // Get current mesh array and create new mesh array with necessary flag for SoftBody
Array surface_arrays = mesh->surface_get_arrays(0);
Array surface_blend_arrays = mesh->surface_get_blend_shape_arrays(0);
Dictionary surface_lods = mesh->surface_get_lods(0);
@@ -493,25 +502,25 @@ void SoftDynamicBody3D::_become_mesh_owner() {
owned_mesh = soft_mesh->get_rid();
}
-void SoftDynamicBody3D::set_collision_mask(uint32_t p_mask) {
+void SoftBody3D::set_collision_mask(uint32_t p_mask) {
collision_mask = p_mask;
PhysicsServer3D::get_singleton()->soft_body_set_collision_mask(physics_rid, p_mask);
}
-uint32_t SoftDynamicBody3D::get_collision_mask() const {
+uint32_t SoftBody3D::get_collision_mask() const {
return collision_mask;
}
-void SoftDynamicBody3D::set_collision_layer(uint32_t p_layer) {
+void SoftBody3D::set_collision_layer(uint32_t p_layer) {
collision_layer = p_layer;
PhysicsServer3D::get_singleton()->soft_body_set_collision_layer(physics_rid, p_layer);
}
-uint32_t SoftDynamicBody3D::get_collision_layer() const {
+uint32_t SoftBody3D::get_collision_layer() const {
return collision_layer;
}
-void SoftDynamicBody3D::set_collision_layer_value(int p_layer_number, bool p_value) {
+void SoftBody3D::set_collision_layer_value(int p_layer_number, bool p_value) {
ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
uint32_t collision_layer = get_collision_layer();
@@ -523,13 +532,13 @@ void SoftDynamicBody3D::set_collision_layer_value(int p_layer_number, bool p_val
set_collision_layer(collision_layer);
}
-bool SoftDynamicBody3D::get_collision_layer_value(int p_layer_number) const {
+bool SoftBody3D::get_collision_layer_value(int p_layer_number) const {
ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
return get_collision_layer() & (1 << (p_layer_number - 1));
}
-void SoftDynamicBody3D::set_collision_mask_value(int p_layer_number, bool p_value) {
+void SoftBody3D::set_collision_mask_value(int p_layer_number, bool p_value) {
ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
uint32_t mask = get_collision_mask();
@@ -541,13 +550,13 @@ void SoftDynamicBody3D::set_collision_mask_value(int p_layer_number, bool p_valu
set_collision_mask(mask);
}
-bool SoftDynamicBody3D::get_collision_mask_value(int p_layer_number) const {
+bool SoftBody3D::get_collision_mask_value(int p_layer_number) const {
ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
return get_collision_mask() & (1 << (p_layer_number - 1));
}
-void SoftDynamicBody3D::set_disable_mode(DisableMode p_mode) {
+void SoftBody3D::set_disable_mode(DisableMode p_mode) {
if (disable_mode == p_mode) {
return;
}
@@ -559,33 +568,33 @@ void SoftDynamicBody3D::set_disable_mode(DisableMode p_mode) {
}
}
-SoftDynamicBody3D::DisableMode SoftDynamicBody3D::get_disable_mode() const {
+SoftBody3D::DisableMode SoftBody3D::get_disable_mode() const {
return disable_mode;
}
-void SoftDynamicBody3D::set_parent_collision_ignore(const NodePath &p_parent_collision_ignore) {
+void SoftBody3D::set_parent_collision_ignore(const NodePath &p_parent_collision_ignore) {
parent_collision_ignore = p_parent_collision_ignore;
}
-const NodePath &SoftDynamicBody3D::get_parent_collision_ignore() const {
+const NodePath &SoftBody3D::get_parent_collision_ignore() const {
return parent_collision_ignore;
}
-void SoftDynamicBody3D::set_pinned_points_indices(Vector<SoftDynamicBody3D::PinnedPoint> p_pinned_points_indices) {
+void SoftBody3D::set_pinned_points_indices(Vector<SoftBody3D::PinnedPoint> p_pinned_points_indices) {
pinned_points = p_pinned_points_indices;
for (int i = pinned_points.size() - 1; 0 <= i; --i) {
pin_point(p_pinned_points_indices[i].point_index, true);
}
}
-Vector<SoftDynamicBody3D::PinnedPoint> SoftDynamicBody3D::get_pinned_points_indices() {
+Vector<SoftBody3D::PinnedPoint> SoftBody3D::get_pinned_points_indices() {
return pinned_points;
}
-Array SoftDynamicBody3D::get_collision_exceptions() {
+TypedArray<PhysicsBody3D> SoftBody3D::get_collision_exceptions() {
List<RID> exceptions;
PhysicsServer3D::get_singleton()->soft_body_get_collision_exceptions(physics_rid, &exceptions);
- Array ret;
+ TypedArray<PhysicsBody3D> ret;
for (const RID &body : exceptions) {
ObjectID instance_id = PhysicsServer3D::get_singleton()->body_get_object_instance_id(body);
Object *obj = ObjectDB::get_instance(instance_id);
@@ -595,77 +604,77 @@ Array SoftDynamicBody3D::get_collision_exceptions() {
return ret;
}
-void SoftDynamicBody3D::add_collision_exception_with(Node *p_node) {
+void SoftBody3D::add_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node);
ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject3Ds.");
PhysicsServer3D::get_singleton()->soft_body_add_collision_exception(physics_rid, collision_object->get_rid());
}
-void SoftDynamicBody3D::remove_collision_exception_with(Node *p_node) {
+void SoftBody3D::remove_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node);
ERR_FAIL_COND_MSG(!collision_object, "Collision exception only works between two CollisionObject3Ds.");
PhysicsServer3D::get_singleton()->soft_body_remove_collision_exception(physics_rid, collision_object->get_rid());
}
-int SoftDynamicBody3D::get_simulation_precision() {
+int SoftBody3D::get_simulation_precision() {
return PhysicsServer3D::get_singleton()->soft_body_get_simulation_precision(physics_rid);
}
-void SoftDynamicBody3D::set_simulation_precision(int p_simulation_precision) {
+void SoftBody3D::set_simulation_precision(int p_simulation_precision) {
PhysicsServer3D::get_singleton()->soft_body_set_simulation_precision(physics_rid, p_simulation_precision);
}
-real_t SoftDynamicBody3D::get_total_mass() {
+real_t SoftBody3D::get_total_mass() {
return PhysicsServer3D::get_singleton()->soft_body_get_total_mass(physics_rid);
}
-void SoftDynamicBody3D::set_total_mass(real_t p_total_mass) {
+void SoftBody3D::set_total_mass(real_t p_total_mass) {
PhysicsServer3D::get_singleton()->soft_body_set_total_mass(physics_rid, p_total_mass);
}
-void SoftDynamicBody3D::set_linear_stiffness(real_t p_linear_stiffness) {
+void SoftBody3D::set_linear_stiffness(real_t p_linear_stiffness) {
PhysicsServer3D::get_singleton()->soft_body_set_linear_stiffness(physics_rid, p_linear_stiffness);
}
-real_t SoftDynamicBody3D::get_linear_stiffness() {
+real_t SoftBody3D::get_linear_stiffness() {
return PhysicsServer3D::get_singleton()->soft_body_get_linear_stiffness(physics_rid);
}
-real_t SoftDynamicBody3D::get_pressure_coefficient() {
+real_t SoftBody3D::get_pressure_coefficient() {
return PhysicsServer3D::get_singleton()->soft_body_get_pressure_coefficient(physics_rid);
}
-void SoftDynamicBody3D::set_pressure_coefficient(real_t p_pressure_coefficient) {
+void SoftBody3D::set_pressure_coefficient(real_t p_pressure_coefficient) {
PhysicsServer3D::get_singleton()->soft_body_set_pressure_coefficient(physics_rid, p_pressure_coefficient);
}
-real_t SoftDynamicBody3D::get_damping_coefficient() {
+real_t SoftBody3D::get_damping_coefficient() {
return PhysicsServer3D::get_singleton()->soft_body_get_damping_coefficient(physics_rid);
}
-void SoftDynamicBody3D::set_damping_coefficient(real_t p_damping_coefficient) {
+void SoftBody3D::set_damping_coefficient(real_t p_damping_coefficient) {
PhysicsServer3D::get_singleton()->soft_body_set_damping_coefficient(physics_rid, p_damping_coefficient);
}
-real_t SoftDynamicBody3D::get_drag_coefficient() {
+real_t SoftBody3D::get_drag_coefficient() {
return PhysicsServer3D::get_singleton()->soft_body_get_drag_coefficient(physics_rid);
}
-void SoftDynamicBody3D::set_drag_coefficient(real_t p_drag_coefficient) {
+void SoftBody3D::set_drag_coefficient(real_t p_drag_coefficient) {
PhysicsServer3D::get_singleton()->soft_body_set_drag_coefficient(physics_rid, p_drag_coefficient);
}
-Vector3 SoftDynamicBody3D::get_point_transform(int p_point_index) {
+Vector3 SoftBody3D::get_point_transform(int p_point_index) {
return PhysicsServer3D::get_singleton()->soft_body_get_point_global_position(physics_rid, p_point_index);
}
-void SoftDynamicBody3D::pin_point_toggle(int p_point_index) {
+void SoftBody3D::pin_point_toggle(int p_point_index) {
pin_point(p_point_index, !(-1 != _has_pinned_point(p_point_index)));
}
-void SoftDynamicBody3D::pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path) {
+void SoftBody3D::pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path) {
_pin_point_on_physics_server(p_point_index, pin);
if (pin) {
_add_pinned_point(p_point_index, p_spatial_attachment_path);
@@ -674,35 +683,35 @@ void SoftDynamicBody3D::pin_point(int p_point_index, bool pin, const NodePath &p
}
}
-bool SoftDynamicBody3D::is_point_pinned(int p_point_index) const {
+bool SoftBody3D::is_point_pinned(int p_point_index) const {
return -1 != _has_pinned_point(p_point_index);
}
-void SoftDynamicBody3D::set_ray_pickable(bool p_ray_pickable) {
+void SoftBody3D::set_ray_pickable(bool p_ray_pickable) {
ray_pickable = p_ray_pickable;
_update_pickable();
}
-bool SoftDynamicBody3D::is_ray_pickable() const {
+bool SoftBody3D::is_ray_pickable() const {
return ray_pickable;
}
-SoftDynamicBody3D::SoftDynamicBody3D() :
+SoftBody3D::SoftBody3D() :
physics_rid(PhysicsServer3D::get_singleton()->soft_body_create()) {
- rendering_server_handler = memnew(SoftDynamicBodyRenderingServerHandler);
+ rendering_server_handler = memnew(SoftBodyRenderingServerHandler);
PhysicsServer3D::get_singleton()->body_attach_object_instance_id(physics_rid, get_instance_id());
}
-SoftDynamicBody3D::~SoftDynamicBody3D() {
+SoftBody3D::~SoftBody3D() {
memdelete(rendering_server_handler);
PhysicsServer3D::get_singleton()->free(physics_rid);
}
-void SoftDynamicBody3D::_make_cache_dirty() {
+void SoftBody3D::_make_cache_dirty() {
pinned_points_cache_dirty = true;
}
-void SoftDynamicBody3D::_update_cache_pin_points_datas() {
+void SoftBody3D::_update_cache_pin_points_datas() {
if (!pinned_points_cache_dirty) {
return;
}
@@ -715,17 +724,17 @@ void SoftDynamicBody3D::_update_cache_pin_points_datas() {
w[i].spatial_attachment = Object::cast_to<Node3D>(get_node(w[i].spatial_attachment_path));
}
if (!w[i].spatial_attachment) {
- ERR_PRINT("Node3D node not defined in the pinned point, this is undefined behavior for SoftDynamicBody3D!");
+ ERR_PRINT("Node3D node not defined in the pinned point, this is undefined behavior for SoftBody3D!");
}
}
}
-void SoftDynamicBody3D::_pin_point_on_physics_server(int p_point_index, bool pin) {
+void SoftBody3D::_pin_point_on_physics_server(int p_point_index, bool pin) {
PhysicsServer3D::get_singleton()->soft_body_pin_point(physics_rid, p_point_index, pin);
}
-void SoftDynamicBody3D::_add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path) {
- SoftDynamicBody3D::PinnedPoint *pinned_point;
+void SoftBody3D::_add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path) {
+ SoftBody3D::PinnedPoint *pinned_point;
if (-1 == _get_pinned_point(p_point_index, pinned_point)) {
// Create new
PinnedPoint pp;
@@ -750,7 +759,7 @@ void SoftDynamicBody3D::_add_pinned_point(int p_point_index, const NodePath &p_s
}
}
-void SoftDynamicBody3D::_reset_points_offsets() {
+void SoftBody3D::_reset_points_offsets() {
if (!Engine::get_singleton()->is_editor_hint()) {
return;
}
@@ -772,25 +781,25 @@ void SoftDynamicBody3D::_reset_points_offsets() {
}
}
-void SoftDynamicBody3D::_remove_pinned_point(int p_point_index) {
+void SoftBody3D::_remove_pinned_point(int p_point_index) {
const int id(_has_pinned_point(p_point_index));
if (-1 != id) {
pinned_points.remove_at(id);
}
}
-int SoftDynamicBody3D::_get_pinned_point(int p_point_index, SoftDynamicBody3D::PinnedPoint *&r_point) const {
+int SoftBody3D::_get_pinned_point(int p_point_index, SoftBody3D::PinnedPoint *&r_point) const {
const int id = _has_pinned_point(p_point_index);
if (-1 == id) {
r_point = nullptr;
return -1;
} else {
- r_point = const_cast<SoftDynamicBody3D::PinnedPoint *>(&pinned_points.ptr()[id]);
+ r_point = const_cast<SoftBody3D::PinnedPoint *>(&pinned_points.ptr()[id]);
return id;
}
}
-int SoftDynamicBody3D::_has_pinned_point(int p_point_index) const {
+int SoftBody3D::_has_pinned_point(int p_point_index) const {
const PinnedPoint *r = pinned_points.ptr();
for (int i = pinned_points.size() - 1; 0 <= i; --i) {
if (p_point_index == r[i].point_index) {
diff --git a/scene/3d/soft_dynamic_body_3d.h b/scene/3d/soft_body_3d.h
index 04f3365f72..40f3d6f1f4 100644
--- a/scene/3d/soft_dynamic_body_3d.h
+++ b/scene/3d/soft_body_3d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* soft_dynamic_body_3d.h */
+/* soft_body_3d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,16 +28,17 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SOFT_DYNAMIC_BODY_3D_H
-#define SOFT_DYNAMIC_BODY_3D_H
+#ifndef SOFT_BODY_3D_H
+#define SOFT_BODY_3D_H
#include "scene/3d/mesh_instance_3d.h"
#include "servers/physics_server_3d.h"
-class SoftDynamicBody3D;
+class PhysicsBody3D;
+class SoftBody3D;
-class SoftDynamicBodyRenderingServerHandler : public PhysicsServer3DRenderingServerHandler {
- friend class SoftDynamicBody3D;
+class SoftBodyRenderingServerHandler : public PhysicsServer3DRenderingServerHandler {
+ friend class SoftBody3D;
RID mesh;
int surface = 0;
@@ -49,7 +50,7 @@ class SoftDynamicBodyRenderingServerHandler : public PhysicsServer3DRenderingSer
uint8_t *write_buffer = nullptr;
private:
- SoftDynamicBodyRenderingServerHandler();
+ SoftBodyRenderingServerHandler();
bool is_ready(RID p_mesh_rid) const { return mesh.is_valid() && mesh == p_mesh_rid; }
void prepare(RID p_mesh_rid, int p_surface);
void clear();
@@ -63,8 +64,8 @@ public:
void set_aabb(const AABB &p_aabb) override;
};
-class SoftDynamicBody3D : public MeshInstance3D {
- GDCLASS(SoftDynamicBody3D, MeshInstance3D);
+class SoftBody3D : public MeshInstance3D {
+ GDCLASS(SoftBody3D, MeshInstance3D);
public:
enum DisableMode {
@@ -84,7 +85,7 @@ public:
};
private:
- SoftDynamicBodyRenderingServerHandler *rendering_server_handler = nullptr;
+ SoftBodyRenderingServerHandler *rendering_server_handler = nullptr;
RID physics_rid;
@@ -168,7 +169,7 @@ public:
void set_drag_coefficient(real_t p_drag_coefficient);
real_t get_drag_coefficient();
- Array get_collision_exceptions();
+ TypedArray<PhysicsBody3D> get_collision_exceptions();
void add_collision_exception_with(Node *p_node);
void remove_collision_exception_with(Node *p_node);
@@ -181,8 +182,8 @@ public:
void set_ray_pickable(bool p_ray_pickable);
bool is_ray_pickable() const;
- SoftDynamicBody3D();
- ~SoftDynamicBody3D();
+ SoftBody3D();
+ ~SoftBody3D();
private:
void _make_cache_dirty();
@@ -197,6 +198,6 @@ private:
int _has_pinned_point(int p_point_index) const;
};
-VARIANT_ENUM_CAST(SoftDynamicBody3D::DisableMode);
+VARIANT_ENUM_CAST(SoftBody3D::DisableMode);
-#endif // SOFT_DYNAMIC_BODY_3D_H
+#endif // SOFT_BODY_3D_H
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index cb6354f7a8..669c3eb7fd 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -377,7 +377,7 @@ SpriteBase3D::SpriteBase3D() {
RS::get_singleton()->material_set_param(material, "uv1_scale", Vector3(1, 1, 1));
RS::get_singleton()->material_set_param(material, "uv2_offset", Vector3(0, 0, 0));
RS::get_singleton()->material_set_param(material, "uv2_scale", Vector3(1, 1, 1));
- RS::get_singleton()->material_set_param(material, "alpha_scissor_threshold", 0.98);
+ RS::get_singleton()->material_set_param(material, "alpha_scissor_threshold", 0.5);
mesh = RenderingServer::get_singleton()->mesh_create();
@@ -562,23 +562,21 @@ void Sprite3D::_draw() {
{
Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
+ Vector2 res = n.octahedron_encode();
uint32_t value = 0;
- value |= CLAMP(int(n.x * 1023.0), 0, 1023);
- value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10;
- value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20;
+ value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
v_normal = value;
}
uint32_t v_tangent;
{
Plane t = tangent;
+ Vector2 res = t.normal.octahedron_tangent_encode(t.d);
uint32_t value = 0;
- value |= CLAMP(int((t.normal.x * 0.5 + 0.5) * 1023.0), 0, 1023);
- value |= CLAMP(int((t.normal.y * 0.5 + 0.5) * 1023.0), 0, 1023) << 10;
- value |= CLAMP(int((t.normal.z * 0.5 + 0.5) * 1023.0), 0, 1023) << 20;
- if (t.d > 0) {
- value |= 3UL << 30;
- }
+ value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
+
v_tangent = value;
}
@@ -751,18 +749,16 @@ Rect2 Sprite3D::get_item_rect() const {
return Rect2(ofs, s);
}
-void Sprite3D::_validate_property(PropertyInfo &property) const {
- if (property.name == "frame") {
- property.hint = PROPERTY_HINT_RANGE;
- property.hint_string = "0," + itos(vframes * hframes - 1) + ",1";
- property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
+void Sprite3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "frame") {
+ p_property.hint = PROPERTY_HINT_RANGE;
+ p_property.hint_string = "0," + itos(vframes * hframes - 1) + ",1";
+ p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
- if (property.name == "frame_coords") {
- property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
+ if (p_property.name == "frame_coords") {
+ p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
-
- SpriteBase3D::_validate_property(property);
}
void Sprite3D::_bind_methods() {
@@ -929,23 +925,20 @@ void AnimatedSprite3D::_draw() {
{
Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
+ Vector2 res = n.octahedron_encode();
uint32_t value = 0;
- value |= CLAMP(int(n.x * 1023.0), 0, 1023);
- value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10;
- value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20;
+ value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
v_normal = value;
}
uint32_t v_tangent;
{
Plane t = tangent;
+ Vector2 res = t.normal.octahedron_tangent_encode(t.d);
uint32_t value = 0;
- value |= CLAMP(int((t.normal.x * 0.5 + 0.5) * 1023.0), 0, 1023);
- value |= CLAMP(int((t.normal.y * 0.5 + 0.5) * 1023.0), 0, 1023) << 10;
- value |= CLAMP(int((t.normal.z * 0.5 + 0.5) * 1023.0), 0, 1023) << 20;
- if (t.d > 0) {
- value |= 3UL << 30;
- }
+ value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
v_tangent = value;
}
@@ -1000,50 +993,51 @@ void AnimatedSprite3D::_draw() {
}
}
-void AnimatedSprite3D::_validate_property(PropertyInfo &property) const {
+void AnimatedSprite3D::_validate_property(PropertyInfo &p_property) const {
if (!frames.is_valid()) {
return;
}
- if (property.name == "animation") {
- property.hint = PROPERTY_HINT_ENUM;
+ if (p_property.name == "animation") {
+ p_property.hint = PROPERTY_HINT_ENUM;
List<StringName> names;
frames->get_animation_list(&names);
names.sort_custom<StringName::AlphCompare>();
bool current_found = false;
+ bool is_first_element = true;
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- if (E->prev()) {
- property.hint_string += ",";
+ for (const StringName &E : names) {
+ if (!is_first_element) {
+ p_property.hint_string += ",";
+ } else {
+ is_first_element = false;
}
- property.hint_string += String(E->get());
- if (animation == E->get()) {
+ p_property.hint_string += String(E);
+ if (animation == E) {
current_found = true;
}
}
if (!current_found) {
- if (property.hint_string.is_empty()) {
- property.hint_string = String(animation);
+ if (p_property.hint_string.is_empty()) {
+ p_property.hint_string = String(animation);
} else {
- property.hint_string = String(animation) + "," + property.hint_string;
+ p_property.hint_string = String(animation) + "," + p_property.hint_string;
}
}
}
- if (property.name == "frame") {
- property.hint = PROPERTY_HINT_RANGE;
+ if (p_property.name == "frame") {
+ p_property.hint = PROPERTY_HINT_RANGE;
if (frames->has_animation(animation) && frames->get_frame_count(animation) > 0) {
- property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1";
+ p_property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1";
} else {
// Avoid an error, `hint_string` is required for `PROPERTY_HINT_RANGE`.
- property.hint_string = "0,0,1";
+ p_property.hint_string = "0,0,1";
}
- property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
+ p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
-
- SpriteBase3D::_validate_property(property);
}
void AnimatedSprite3D::_notification(int p_what) {
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index 6ac85a7bbc..03688cf787 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -174,7 +174,7 @@ protected:
virtual void _draw() override;
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_texture(const Ref<Texture2D> &p_texture);
@@ -229,7 +229,7 @@ protected:
virtual void _draw() override;
static void _bind_methods();
void _notification(int p_what);
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_sprite_frames(const Ref<SpriteFrames> &p_frames);
diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp
index 42ed52c9f2..d61b49eaa7 100644
--- a/scene/3d/vehicle_body_3d.cpp
+++ b/scene/3d/vehicle_body_3d.cpp
@@ -807,7 +807,7 @@ void VehicleBody3D::_update_friction(PhysicsDirectBodyState3D *s) {
}
void VehicleBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
- RigidDynamicBody3D::_body_state_changed(p_state);
+ RigidBody3D::_body_state_changed(p_state);
real_t step = p_state->get_step();
diff --git a/scene/3d/vehicle_body_3d.h b/scene/3d/vehicle_body_3d.h
index 2f3a37af2a..5c4f4beaea 100644
--- a/scene/3d/vehicle_body_3d.h
+++ b/scene/3d/vehicle_body_3d.h
@@ -152,8 +152,8 @@ public:
VehicleWheel3D();
};
-class VehicleBody3D : public RigidDynamicBody3D {
- GDCLASS(VehicleBody3D, RigidDynamicBody3D);
+class VehicleBody3D : public RigidBody3D {
+ GDCLASS(VehicleBody3D, RigidBody3D);
real_t engine_force = 0.0;
real_t brake = 0.0;
diff --git a/scene/3d/velocity_tracker_3d.h b/scene/3d/velocity_tracker_3d.h
index 6b27cdffc2..d3b92ab766 100644
--- a/scene/3d/velocity_tracker_3d.h
+++ b/scene/3d/velocity_tracker_3d.h
@@ -34,8 +34,6 @@
#include "scene/3d/node_3d.h"
class VelocityTracker3D : public RefCounted {
- GDCLASS(VelocityTracker3D, RefCounted);
-
struct PositionHistory {
uint64_t frame = 0;
Vector3 position;
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index e76e85cfef..5af06cff29 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -227,8 +227,8 @@ const StringName *GeometryInstance3D::_instance_uniform_get_remap(const StringNa
StringName *r = instance_uniform_property_remap.getptr(p_name);
if (!r) {
String s = p_name;
- if (s.begins_with("shader_params/")) {
- StringName name = s.replace("shader_params/", "");
+ if (s.begins_with("shader_uniforms/")) {
+ StringName name = s.replace("shader_uniforms/", "");
instance_uniform_property_remap[p_name] = name;
return instance_uniform_property_remap.getptr(p_name);
}
@@ -242,7 +242,7 @@ const StringName *GeometryInstance3D::_instance_uniform_get_remap(const StringNa
bool GeometryInstance3D::_set(const StringName &p_name, const Variant &p_value) {
const StringName *r = _instance_uniform_get_remap(p_name);
if (r) {
- set_shader_instance_uniform(*r, p_value);
+ set_instance_shader_uniform(*r, p_value);
return true;
}
#ifndef DISABLE_DEPRECATED
@@ -262,7 +262,7 @@ bool GeometryInstance3D::_set(const StringName &p_name, const Variant &p_value)
bool GeometryInstance3D::_get(const StringName &p_name, Variant &r_ret) const {
const StringName *r = _instance_uniform_get_remap(p_name);
if (r) {
- r_ret = get_shader_instance_uniform(*r);
+ r_ret = get_instance_shader_uniform(*r);
return true;
}
@@ -271,10 +271,10 @@ bool GeometryInstance3D::_get(const StringName &p_name, Variant &r_ret) const {
void GeometryInstance3D::_get_property_list(List<PropertyInfo> *p_list) const {
List<PropertyInfo> pinfo;
- RS::get_singleton()->instance_geometry_get_shader_parameter_list(get_instance(), &pinfo);
+ RS::get_singleton()->instance_geometry_get_shader_uniform_list(get_instance(), &pinfo);
for (PropertyInfo &pi : pinfo) {
bool has_def_value = false;
- Variant def_value = RS::get_singleton()->instance_geometry_get_shader_parameter_default_value(get_instance(), pi.name);
+ Variant def_value = RS::get_singleton()->instance_geometry_get_shader_uniform_default_value(get_instance(), pi.name);
if (def_value.get_type() != Variant::NIL) {
has_def_value = true;
}
@@ -284,7 +284,7 @@ void GeometryInstance3D::_get_property_list(List<PropertyInfo> *p_list) const {
pi.usage = PROPERTY_USAGE_EDITOR | (has_def_value ? PROPERTY_USAGE_CHECKABLE : PROPERTY_USAGE_NONE); //do not save if not changed
}
- pi.name = "shader_params/" + pi.name;
+ pi.name = "shader_uniforms/" + pi.name;
p_list->push_back(pi);
}
}
@@ -319,24 +319,24 @@ float GeometryInstance3D::get_lod_bias() const {
return lod_bias;
}
-void GeometryInstance3D::set_shader_instance_uniform(const StringName &p_uniform, const Variant &p_value) {
+void GeometryInstance3D::set_instance_shader_uniform(const StringName &p_uniform, const Variant &p_value) {
if (p_value.get_type() == Variant::NIL) {
- Variant def_value = RS::get_singleton()->instance_geometry_get_shader_parameter_default_value(get_instance(), p_uniform);
- RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_uniform, def_value);
+ Variant def_value = RS::get_singleton()->instance_geometry_get_shader_uniform_default_value(get_instance(), p_uniform);
+ RS::get_singleton()->instance_geometry_set_shader_uniform(get_instance(), p_uniform, def_value);
instance_uniforms.erase(p_value);
} else {
instance_uniforms[p_uniform] = p_value;
if (p_value.get_type() == Variant::OBJECT) {
RID tex_id = p_value;
- RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_uniform, tex_id);
+ RS::get_singleton()->instance_geometry_set_shader_uniform(get_instance(), p_uniform, tex_id);
} else {
- RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_uniform, p_value);
+ RS::get_singleton()->instance_geometry_set_shader_uniform(get_instance(), p_uniform, p_value);
}
}
}
-Variant GeometryInstance3D::get_shader_instance_uniform(const StringName &p_uniform) const {
- return RS::get_singleton()->instance_geometry_get_shader_parameter(get_instance(), p_uniform);
+Variant GeometryInstance3D::get_instance_shader_uniform(const StringName &p_uniform) const {
+ return RS::get_singleton()->instance_geometry_get_shader_uniform(get_instance(), p_uniform);
}
void GeometryInstance3D::set_custom_aabb(AABB aabb) {
@@ -434,8 +434,8 @@ void GeometryInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_visibility_range_fade_mode", "mode"), &GeometryInstance3D::set_visibility_range_fade_mode);
ClassDB::bind_method(D_METHOD("get_visibility_range_fade_mode"), &GeometryInstance3D::get_visibility_range_fade_mode);
- ClassDB::bind_method(D_METHOD("set_shader_instance_uniform", "uniform", "value"), &GeometryInstance3D::set_shader_instance_uniform);
- ClassDB::bind_method(D_METHOD("get_shader_instance_uniform", "uniform"), &GeometryInstance3D::get_shader_instance_uniform);
+ ClassDB::bind_method(D_METHOD("set_instance_shader_uniform", "uniform", "value"), &GeometryInstance3D::set_instance_shader_uniform);
+ ClassDB::bind_method(D_METHOD("get_instance_shader_uniform", "uniform"), &GeometryInstance3D::get_instance_shader_uniform);
ClassDB::bind_method(D_METHOD("set_extra_cull_margin", "margin"), &GeometryInstance3D::set_extra_cull_margin);
ClassDB::bind_method(D_METHOD("get_extra_cull_margin"), &GeometryInstance3D::get_extra_cull_margin);
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index 159b14613c..f7cdcbf411 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -178,8 +178,8 @@ public:
void set_lightmap_scale(LightmapScale p_scale);
LightmapScale get_lightmap_scale() const;
- void set_shader_instance_uniform(const StringName &p_uniform, const Variant &p_value);
- Variant get_shader_instance_uniform(const StringName &p_uniform) const;
+ void set_instance_shader_uniform(const StringName &p_uniform, const Variant &p_value);
+ Variant get_instance_shader_uniform(const StringName &p_uniform) const;
void set_custom_aabb(AABB aabb);
diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp
index 42a2a68e2d..9380d1cf32 100644
--- a/scene/3d/voxelizer.cpp
+++ b/scene/3d/voxelizer.cpp
@@ -323,8 +323,8 @@ Vector<Color> Voxelizer::_get_bake_texture(Ref<Image> p_image, const Color &p_co
}
Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material) {
- //this way of obtaining materials is inaccurate and also does not support some compressed formats very well
- Ref<StandardMaterial3D> mat = p_material;
+ // This way of obtaining materials is inaccurate and also does not support some compressed formats very well.
+ Ref<BaseMaterial3D> mat = p_material;
Ref<Material> material = mat; //hack for now
@@ -335,7 +335,7 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material
MaterialCache mc;
if (mat.is_valid()) {
- Ref<Texture2D> albedo_tex = mat->get_texture(StandardMaterial3D::TEXTURE_ALBEDO);
+ Ref<Texture2D> albedo_tex = mat->get_texture(BaseMaterial3D::TEXTURE_ALBEDO);
Ref<Image> img_albedo;
if (albedo_tex.is_valid()) {
@@ -345,7 +345,7 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material
mc.albedo = _get_bake_texture(img_albedo, Color(1, 1, 1), mat->get_albedo()); // no albedo texture, color is additive
}
- Ref<Texture2D> emission_tex = mat->get_texture(StandardMaterial3D::TEXTURE_EMISSION);
+ Ref<Texture2D> emission_tex = mat->get_texture(BaseMaterial3D::TEXTURE_EMISSION);
Color emission_col = mat->get_emission();
float emission_energy = mat->get_emission_energy();
@@ -356,7 +356,7 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material
img_emission = emission_tex->get_image();
}
- if (mat->get_emission_operator() == StandardMaterial3D::EMISSION_OP_ADD) {
+ if (mat->get_emission_operator() == BaseMaterial3D::EMISSION_OP_ADD) {
mc.emission = _get_bake_texture(img_emission, Color(1, 1, 1) * emission_energy, emission_col * emission_energy);
} else {
mc.emission = _get_bake_texture(img_emission, emission_col * emission_energy, Color(0, 0, 0));
diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp
index 40a43043c6..de765d7ccb 100644
--- a/scene/3d/xr_nodes.cpp
+++ b/scene/3d/xr_nodes.cpp
@@ -244,27 +244,25 @@ void XRNode3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("trigger_haptic_pulse", "action_name", "frequency", "amplitude", "duration_sec", "delay_sec"), &XRNode3D::trigger_haptic_pulse);
};
-void XRNode3D::_validate_property(PropertyInfo &property) const {
+void XRNode3D::_validate_property(PropertyInfo &p_property) const {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
- if (property.name == "tracker") {
+ if (p_property.name == "tracker") {
PackedStringArray names = xr_server->get_suggested_tracker_names();
String hint_string;
for (const String &name : names) {
hint_string += name + ",";
}
- property.hint_string = hint_string;
- } else if (property.name == "pose") {
+ p_property.hint_string = hint_string;
+ } else if (p_property.name == "pose") {
PackedStringArray names = xr_server->get_suggested_pose_names(tracker_name);
String hint_string;
for (const String &name : names) {
hint_string += name + ",";
}
- property.hint_string = hint_string;
+ p_property.hint_string = hint_string;
}
-
- Node3D::_validate_property(property);
}
void XRNode3D::set_tracker(const StringName p_tracker_name) {
diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h
index 3079e20dc7..312bef7856 100644
--- a/scene/3d/xr_nodes.h
+++ b/scene/3d/xr_nodes.h
@@ -93,7 +93,7 @@ protected:
void _pose_changed(const Ref<XRPose> &p_pose);
public:
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void set_tracker(const StringName p_tracker_name);
StringName get_tracker() const;
diff --git a/scene/SCsub b/scene/SCsub
index 92288211bb..b4b2d6dd0a 100644
--- a/scene/SCsub
+++ b/scene/SCsub
@@ -17,6 +17,7 @@ SConscript("animation/SCsub")
SConscript("audio/SCsub")
SConscript("resources/SCsub")
SConscript("debugger/SCsub")
+SConscript("theme/SCsub")
# Build it all as a library
lib = env.add_library("scene", env.scene_sources)
diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp
index b42e426f51..f30aea3bdd 100644
--- a/scene/animation/animation_blend_space_1d.cpp
+++ b/scene/animation/animation_blend_space_1d.cpp
@@ -42,15 +42,14 @@ Ref<AnimationNode> AnimationNodeBlendSpace1D::get_child_by_name(const StringName
return get_blend_point_node(p_name.operator String().to_int());
}
-void AnimationNodeBlendSpace1D::_validate_property(PropertyInfo &property) const {
- if (property.name.begins_with("blend_point_")) {
- String left = property.name.get_slicec('/', 0);
+void AnimationNodeBlendSpace1D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name.begins_with("blend_point_")) {
+ String left = p_property.name.get_slicec('/', 0);
int idx = left.get_slicec('_', 2).to_int();
if (idx >= blend_points_used) {
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
- AnimationRootNode::_validate_property(property);
}
void AnimationNodeBlendSpace1D::_tree_changed() {
diff --git a/scene/animation/animation_blend_space_1d.h b/scene/animation/animation_blend_space_1d.h
index 346e8a3a2f..1876ccebc7 100644
--- a/scene/animation/animation_blend_space_1d.h
+++ b/scene/animation/animation_blend_space_1d.h
@@ -65,7 +65,7 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode {
protected:
bool sync = false;
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
public:
diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp
index 6b5851a977..2dc61efb94 100644
--- a/scene/animation/animation_blend_space_2d.cpp
+++ b/scene/animation/animation_blend_space_2d.cpp
@@ -566,18 +566,17 @@ String AnimationNodeBlendSpace2D::get_caption() const {
return "BlendSpace2D";
}
-void AnimationNodeBlendSpace2D::_validate_property(PropertyInfo &property) const {
- if (auto_triangles && property.name == "triangles") {
- property.usage = PROPERTY_USAGE_NONE;
+void AnimationNodeBlendSpace2D::_validate_property(PropertyInfo &p_property) const {
+ if (auto_triangles && p_property.name == "triangles") {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("blend_point_")) {
- String left = property.name.get_slicec('/', 0);
+ if (p_property.name.begins_with("blend_point_")) {
+ String left = p_property.name.get_slicec('/', 0);
int idx = left.get_slicec('_', 2).to_int();
if (idx >= blend_points_used) {
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
- AnimationRootNode::_validate_property(property);
}
void AnimationNodeBlendSpace2D::set_auto_triangles(bool p_enable) {
diff --git a/scene/animation/animation_blend_space_2d.h b/scene/animation/animation_blend_space_2d.h
index 689b96e356..250189f202 100644
--- a/scene/animation/animation_blend_space_2d.h
+++ b/scene/animation/animation_blend_space_2d.h
@@ -90,7 +90,7 @@ protected:
protected:
bool sync = false;
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
public:
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index fe2fb1b7a1..61f068408c 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -47,8 +47,8 @@ void AnimationNodeAnimation::get_parameter_list(List<PropertyInfo> *r_list) cons
r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
}
-void AnimationNodeAnimation::_validate_property(PropertyInfo &property) const {
- if (property.name == "animation" && get_editable_animation_list) {
+void AnimationNodeAnimation::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "animation" && get_editable_animation_list) {
Vector<String> names = get_editable_animation_list();
String anims;
for (int i = 0; i < names.size(); i++) {
@@ -58,8 +58,8 @@ void AnimationNodeAnimation::_validate_property(PropertyInfo &property) const {
anims += String(names[i]);
}
if (!anims.is_empty()) {
- property.hint = PROPERTY_HINT_ENUM;
- property.hint_string = anims;
+ p_property.hint = PROPERTY_HINT_ENUM;
+ p_property.hint_string = anims;
}
}
}
@@ -676,12 +676,20 @@ String AnimationNodeTransition::get_input_caption(int p_input) const {
return inputs[p_input].name;
}
-void AnimationNodeTransition::set_cross_fade_time(float p_fade) {
- xfade = p_fade;
+void AnimationNodeTransition::set_xfade_time(float p_fade) {
+ xfade_time = p_fade;
}
-float AnimationNodeTransition::get_cross_fade_time() const {
- return xfade;
+float AnimationNodeTransition::get_xfade_time() const {
+ return xfade_time;
+}
+
+void AnimationNodeTransition::set_xfade_curve(const Ref<Curve> &p_curve) {
+ xfade_curve = p_curve;
+}
+
+Ref<Curve> AnimationNodeTransition::get_xfade_curve() const {
+ return xfade_curve;
}
void AnimationNodeTransition::set_from_start(bool p_from_start) {
@@ -707,7 +715,7 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_
set_parameter(this->prev, prev_current);
prev = prev_current;
- prev_xfading = xfade;
+ prev_xfading = xfade_time;
time = 0;
switched = true;
}
@@ -734,13 +742,16 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_
time += p_time;
}
- if (inputs[current].auto_advance && rem <= xfade) {
+ if (inputs[current].auto_advance && rem <= xfade_time) {
set_parameter(this->current, (current + 1) % enabled_inputs);
}
} else { // cross-fading from prev to current
- float blend = xfade == 0 ? 0 : (prev_xfading / xfade);
+ float blend = xfade_time == 0 ? 0 : (prev_xfading / xfade_time);
+ if (xfade_curve.is_valid()) {
+ blend = xfade_curve->interpolate(blend);
+ }
if (from_start && !p_seek && switched) { //just switched, seek to start of current
@@ -768,18 +779,16 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_seek_
return rem;
}
-void AnimationNodeTransition::_validate_property(PropertyInfo &property) const {
- if (property.name.begins_with("input_")) {
- String n = property.name.get_slicec('/', 0).get_slicec('_', 1);
+void AnimationNodeTransition::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name.begins_with("input_")) {
+ String n = p_property.name.get_slicec('/', 0).get_slicec('_', 1);
if (n != "count") {
int idx = n.to_int();
if (idx >= enabled_inputs) {
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
}
-
- AnimationNode::_validate_property(property);
}
void AnimationNodeTransition::_bind_methods() {
@@ -792,14 +801,18 @@ void AnimationNodeTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_input_caption", "input", "caption"), &AnimationNodeTransition::set_input_caption);
ClassDB::bind_method(D_METHOD("get_input_caption", "input"), &AnimationNodeTransition::get_input_caption);
- ClassDB::bind_method(D_METHOD("set_cross_fade_time", "time"), &AnimationNodeTransition::set_cross_fade_time);
- ClassDB::bind_method(D_METHOD("get_cross_fade_time"), &AnimationNodeTransition::get_cross_fade_time);
+ ClassDB::bind_method(D_METHOD("set_xfade_time", "time"), &AnimationNodeTransition::set_xfade_time);
+ ClassDB::bind_method(D_METHOD("get_xfade_time"), &AnimationNodeTransition::get_xfade_time);
+
+ ClassDB::bind_method(D_METHOD("set_xfade_curve", "curve"), &AnimationNodeTransition::set_xfade_curve);
+ ClassDB::bind_method(D_METHOD("get_xfade_curve"), &AnimationNodeTransition::get_xfade_curve);
ClassDB::bind_method(D_METHOD("set_from_start", "from_start"), &AnimationNodeTransition::set_from_start);
ClassDB::bind_method(D_METHOD("is_from_start"), &AnimationNodeTransition::is_from_start);
ADD_PROPERTY(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_RANGE, "0,64,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01,suffix:s"), "set_cross_fade_time", "get_cross_fade_time");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01,suffix:s"), "set_xfade_time", "get_xfade_time");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_xfade_curve", "get_xfade_curve");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "from_start"), "set_from_start", "is_from_start");
for (int i = 0; i < MAX_INPUTS; i++) {
diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h
index d35ff04f30..59c074cc80 100644
--- a/scene/animation/animation_blend_tree.h
+++ b/scene/animation/animation_blend_tree.h
@@ -67,7 +67,7 @@ public:
AnimationNodeAnimation();
protected:
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
private:
@@ -297,14 +297,15 @@ class AnimationNodeTransition : public AnimationNodeSync {
StringName current = PNAME("current");
StringName prev_current = "prev_current";
- float xfade = 0.0;
+ float xfade_time = 0.0;
+ Ref<Curve> xfade_curve;
bool from_start = true;
void _update_inputs();
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
virtual void get_parameter_list(List<PropertyInfo> *r_list) const override;
@@ -321,8 +322,11 @@ public:
void set_input_caption(int p_input, const String &p_name);
String get_input_caption(int p_input) const;
- void set_cross_fade_time(float p_fade);
- float get_cross_fade_time() const;
+ void set_xfade_time(float p_fade);
+ float get_xfade_time() const;
+
+ void set_xfade_curve(const Ref<Curve> &p_curve);
+ Ref<Curve> get_xfade_curve() const;
void set_from_start(bool p_from_start);
bool is_from_start() const;
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index 3a45d9f26c..afb52de307 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -98,12 +98,20 @@ NodePath AnimationNodeStateMachineTransition::get_advance_expression_base_node()
void AnimationNodeStateMachineTransition::set_xfade_time(float p_xfade) {
ERR_FAIL_COND(p_xfade < 0);
- xfade = p_xfade;
+ xfade_time = p_xfade;
emit_changed();
}
float AnimationNodeStateMachineTransition::get_xfade_time() const {
- return xfade;
+ return xfade_time;
+}
+
+void AnimationNodeStateMachineTransition::set_xfade_curve(const Ref<Curve> &p_curve) {
+ xfade_curve = p_curve;
+}
+
+Ref<Curve> AnimationNodeStateMachineTransition::get_xfade_curve() const {
+ return xfade_curve;
}
void AnimationNodeStateMachineTransition::set_disabled(bool p_disabled) {
@@ -137,6 +145,9 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_xfade_time", "secs"), &AnimationNodeStateMachineTransition::set_xfade_time);
ClassDB::bind_method(D_METHOD("get_xfade_time"), &AnimationNodeStateMachineTransition::get_xfade_time);
+ ClassDB::bind_method(D_METHOD("set_xfade_curve", "curve"), &AnimationNodeStateMachineTransition::set_xfade_curve);
+ ClassDB::bind_method(D_METHOD("get_xfade_curve"), &AnimationNodeStateMachineTransition::get_xfade_curve);
+
ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &AnimationNodeStateMachineTransition::set_disabled);
ClassDB::bind_method(D_METHOD("is_disabled"), &AnimationNodeStateMachineTransition::is_disabled);
@@ -150,6 +161,7 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_advance_expression_base_node"), &AnimationNodeStateMachineTransition::get_advance_expression_base_node);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,240,0.01,suffix:s"), "set_xfade_time", "get_xfade_time");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_xfade_curve", "get_xfade_curve");
ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,32,1"), "set_priority", "get_priority");
ADD_GROUP("Switch", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "switch_mode", PROPERTY_HINT_ENUM, "Immediate,Sync,At End"), "set_switch_mode", "get_switch_mode");
@@ -391,7 +403,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
bool do_start = (p_seek && p_time == 0) || play_start || current == StringName();
if (do_start) {
- if (p_state_machine->start_node != StringName() && p_seek && p_time == 0) {
+ if (p_state_machine->start_node != StringName() && p_seek && p_time == 0 && current == StringName()) {
current = p_state_machine->start_node;
}
@@ -420,6 +432,9 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
}
}
+ if (current_curve.is_valid()) {
+ fade_blend = current_curve->interpolate(fade_blend);
+ }
float rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_seek_root, fade_blend, AnimationNode::FILTER_IGNORE, true);
if (fading_from != StringName()) {
@@ -450,6 +465,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
if (p_state_machine->transitions[i].local_from == current && p_state_machine->transitions[i].local_to == path[0]) {
next_xfade = p_state_machine->transitions[i].transition->get_xfade_time();
+ current_curve = p_state_machine->transitions[i].transition->get_xfade_curve();
switch_mode = p_state_machine->transitions[i].transition->get_switch_mode();
next = path[0];
}
@@ -504,6 +520,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
tr.to = String(p_state_machine->transitions[auto_advance_to].to).replace_first("../", "");
tr.next = p_state_machine->transitions[auto_advance_to].to;
current_transition = tr;
+ current_curve = p_state_machine->transitions[auto_advance_to].transition->get_xfade_curve();
next_xfade = p_state_machine->transitions[auto_advance_to].transition->get_xfade_time();
switch_mode = p_state_machine->transitions[auto_advance_to].transition->get_switch_mode();
}
@@ -830,20 +847,12 @@ void AnimationNodeStateMachine::rename_node(const StringName &p_name, const Stri
anodesm->state_machine_name = p_new_name;
}
- for (int i = 0; i < transitions.size(); i++) {
- if (transitions[i].local_from == p_name) {
- _rename_transition(transitions[i].from, String(transitions[i].from).replace_first(p_name, p_new_name));
- }
-
- if (transitions[i].local_to == p_name) {
- _rename_transition(transitions[i].to, String(transitions[i].to).replace_first(p_name, p_new_name));
- }
- }
+ _rename_transitions(p_name, p_new_name);
emit_signal("tree_changed");
}
-void AnimationNodeStateMachine::_rename_transition(const StringName &p_name, const StringName &p_new_name) {
+void AnimationNodeStateMachine::_rename_transitions(const StringName &p_name, const StringName &p_new_name) {
if (updating_transitions) {
return;
}
@@ -854,12 +863,16 @@ void AnimationNodeStateMachine::_rename_transition(const StringName &p_name, con
Vector<String> path = String(transitions[i].to).split("/");
if (path.size() > 1) {
if (path[0] == "..") {
- prev_state_machine->_rename_transition(String(state_machine_name) + "/" + p_name, String(state_machine_name) + "/" + p_new_name);
+ prev_state_machine->_rename_transitions(String(state_machine_name) + "/" + p_name, String(state_machine_name) + "/" + p_new_name);
} else {
- ((Ref<AnimationNodeStateMachine>)states[transitions[i].local_to].node)->_rename_transition("../" + p_name, "../" + p_new_name);
+ ((Ref<AnimationNodeStateMachine>)states[transitions[i].local_to].node)->_rename_transitions("../" + p_name, "../" + p_new_name);
}
}
+ if (transitions[i].local_from == p_name) {
+ transitions.write[i].local_from = p_new_name;
+ }
+
transitions.write[i].from = p_new_name;
}
@@ -867,12 +880,16 @@ void AnimationNodeStateMachine::_rename_transition(const StringName &p_name, con
Vector<String> path = String(transitions[i].from).split("/");
if (path.size() > 1) {
if (path[0] == "..") {
- prev_state_machine->_rename_transition(String(state_machine_name) + "/" + p_name, String(state_machine_name) + "/" + p_new_name);
+ prev_state_machine->_rename_transitions(String(state_machine_name) + "/" + p_name, String(state_machine_name) + "/" + p_new_name);
} else {
- ((Ref<AnimationNodeStateMachine>)states[transitions[i].local_from].node)->_rename_transition("../" + p_name, "../" + p_new_name);
+ ((Ref<AnimationNodeStateMachine>)states[transitions[i].local_from].node)->_rename_transitions("../" + p_name, "../" + p_new_name);
}
}
+ if (transitions[i].local_to == p_name) {
+ transitions.write[i].local_to = p_new_name;
+ }
+
transitions.write[i].to = p_new_name;
}
diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h
index d4e58ca3d3..ab78b1afe8 100644
--- a/scene/animation/animation_node_state_machine.h
+++ b/scene/animation/animation_node_state_machine.h
@@ -49,7 +49,8 @@ private:
bool auto_advance = false;
StringName advance_condition;
StringName advance_condition_name;
- float xfade = 0.0;
+ float xfade_time = 0.0;
+ Ref<Curve> xfade_curve;
bool disabled = false;
int priority = 1;
String advance_expression;
@@ -82,6 +83,9 @@ public:
void set_xfade_time(float p_xfade);
float get_xfade_time() const;
+ void set_xfade_curve(const Ref<Curve> &p_curve);
+ Ref<Curve> get_xfade_curve() const;
+
void set_disabled(bool p_disabled);
bool is_disabled() const;
@@ -117,6 +121,7 @@ class AnimationNodeStateMachinePlayback : public Resource {
StringName current;
Transition current_transition;
+ Ref<Curve> current_curve;
bool force_auto_advance = false;
StringName fading_from;
@@ -185,7 +190,7 @@ private:
void _tree_changed();
void _remove_transition(const Ref<AnimationNodeStateMachineTransition> p_transition);
- void _rename_transition(const StringName &p_name, const StringName &p_new_name);
+ void _rename_transitions(const StringName &p_name, const StringName &p_new_name);
bool _can_connect(const StringName &p_name, Vector<AnimationNodeStateMachine *> p_parents = Vector<AnimationNodeStateMachine *>());
StringName _get_shortest_path(const StringName &p_path) const;
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 636c9e26a5..073f61bfdd 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -37,6 +37,7 @@
#ifdef TOOLS_ENABLED
#include "editor/editor_node.h"
+#include "editor/editor_undo_redo_manager.h"
#include "scene/2d/skeleton_2d.h"
void AnimatedValuesBackup::update_skeletons() {
@@ -174,8 +175,8 @@ bool AnimationPlayer::_get(const StringName &p_name, Variant &r_ret) const {
return true;
}
-void AnimationPlayer::_validate_property(PropertyInfo &property) const {
- if (property.name == "current_animation") {
+void AnimationPlayer::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "current_animation") {
List<String> names;
for (const KeyValue<StringName, AnimationData> &E : animation_set) {
@@ -191,10 +192,8 @@ void AnimationPlayer::_validate_property(PropertyInfo &property) const {
hint += E->get();
}
- property.hint_string = hint;
+ p_property.hint_string = hint;
}
-
- Node::_validate_property(property);
}
void AnimationPlayer::_get_property_list(List<PropertyInfo> *p_list) const {
@@ -323,10 +322,8 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
#endif // _3D_DISABLED
- {
- if (!child->is_connected("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed))) {
- child->connect("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed).bind(child), CONNECT_ONESHOT);
- }
+ if (!child->is_connected("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed))) {
+ child->connect("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed).bind(child), CONNECT_ONESHOT);
}
TrackNodeCacheKey key;
@@ -375,7 +372,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
node_cache->init_rot = rest.basis.get_rotation_quaternion();
node_cache->init_scale = rest.basis.get_scale();
} else {
- // no property, just use spatialnode
+ // Not a skeleton, the node can be accessed with the node_3d member.
node_cache->skeleton = nullptr;
}
}
@@ -1154,7 +1151,7 @@ void AnimationPlayer::_animation_update_transforms() {
}
#endif
- static_cast<Node2D *>(pa->object)->set_rotation(Math::deg2rad((double)pa->value_accum));
+ static_cast<Node2D *>(pa->object)->set_rotation(Math::deg_to_rad((double)pa->value_accum));
} break;
case SP_NODE2D_SCALE: {
#ifdef DEBUG_ENABLED
@@ -1504,7 +1501,7 @@ bool AnimationPlayer::has_animation(const StringName &p_name) const {
}
Ref<Animation> AnimationPlayer::get_animation(const StringName &p_name) const {
- ERR_FAIL_COND_V_MSG(!animation_set.has(p_name), Ref<Animation>(), vformat("Animation not found: %s.", p_name));
+ ERR_FAIL_COND_V_MSG(!animation_set.has(p_name), Ref<Animation>(), vformat("Animation not found: \"%s\".", p_name));
const AnimationData &data = animation_set[p_name];
@@ -2048,7 +2045,7 @@ Ref<AnimatedValuesBackup> AnimationPlayer::apply_reset(bool p_user_initiated) {
Ref<AnimatedValuesBackup> new_values = aux_player->backup_animated_values();
old_values->restore();
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
ur->create_action(TTR("Anim Apply Reset"));
ur->add_do_method(new_values.ptr(), "restore");
ur->add_undo_method(old_values.ptr(), "restore");
@@ -2124,7 +2121,7 @@ void AnimationPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_method_call_mode", "mode"), &AnimationPlayer::set_method_call_mode);
ClassDB::bind_method(D_METHOD("get_method_call_mode"), &AnimationPlayer::get_method_call_mode);
- ClassDB::bind_method(D_METHOD("set_movie_quit_on_finish_enabled"), &AnimationPlayer::set_movie_quit_on_finish_enabled);
+ ClassDB::bind_method(D_METHOD("set_movie_quit_on_finish_enabled", "enabled"), &AnimationPlayer::set_movie_quit_on_finish_enabled);
ClassDB::bind_method(D_METHOD("is_movie_quit_on_finish_enabled"), &AnimationPlayer::is_movie_quit_on_finish_enabled);
ClassDB::bind_method(D_METHOD("get_current_animation_position"), &AnimationPlayer::get_current_animation_position);
diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h
index b6d8dab1ed..caf1387ff0 100644
--- a/scene/animation/animation_player.h
+++ b/scene/animation/animation_player.h
@@ -311,7 +311,7 @@ private:
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
void _notification(int p_what);
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 14cf64afad..d06324f0aa 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -399,9 +399,9 @@ void AnimationNode::_set_filters(const Array &p_filters) {
}
}
-void AnimationNode::_validate_property(PropertyInfo &property) const {
- if (!has_filter() && (property.name == "filter_enabled" || property.name == "filters")) {
- property.usage = PROPERTY_USAGE_NONE;
+void AnimationNode::_validate_property(PropertyInfo &p_property) const {
+ if (!has_filter() && (p_property.name == "filter_enabled" || p_property.name == "filters")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
@@ -602,6 +602,8 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
track_value->object = child;
}
+ track_value->is_using_angle = anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE;
+
track_value->subpath = leftover_path;
track_value->object_id = track_value->object->get_instance_id();
@@ -804,6 +806,10 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
default: {
}
}
+ } else if (track_cache_type == Animation::TYPE_VALUE) {
+ // If it has at least one angle interpolation, it also uses angle interpolation for blending.
+ TrackCacheValue *track_value = memnew(TrackCacheValue);
+ track_value->is_using_angle |= anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_LINEAR_ANGLE || anim->track_get_interpolation_type(i) == Animation::INTERPOLATION_CUBIC_ANGLE;
}
track->setup_pass = setup_pass;
@@ -1353,8 +1359,28 @@ void AnimationTree::_process_graph(double p_delta) {
t->value = t->init_value;
}
- Variant::sub(value, t->init_value, value);
- Variant::blend(t->value, value, blend, t->value);
+ // Special case for angle interpolation.
+ if (t->is_using_angle) {
+ // For blending consistency, it prevents rotation of more than 180 degrees from init_value.
+ // This is the same as for Quaternion blends.
+ float rot_a = t->value;
+ float rot_b = value;
+ float rot_init = t->init_value;
+ rot_a = Math::fposmod(rot_a, (float)Math_TAU);
+ rot_b = Math::fposmod(rot_b, (float)Math_TAU);
+ rot_init = Math::fposmod(rot_init, (float)Math_TAU);
+ if (rot_init < Math_PI) {
+ rot_a = rot_a > rot_init + Math_PI ? rot_a - Math_TAU : rot_a;
+ rot_b = rot_b > rot_init + Math_PI ? rot_b - Math_TAU : rot_b;
+ } else {
+ rot_a = rot_a < rot_init - Math_PI ? rot_a + Math_TAU : rot_a;
+ rot_b = rot_b < rot_init - Math_PI ? rot_b + Math_TAU : rot_b;
+ }
+ t->value = Math::fposmod(rot_a + (rot_b - rot_init) * (float)blend, (float)Math_TAU);
+ } else {
+ Variant::sub(value, t->init_value, value);
+ Variant::blend(t->value, value, blend, t->value);
+ }
} else {
if (blend < CMP_EPSILON) {
continue; //nothing to blend
@@ -1528,7 +1554,7 @@ void AnimationTree::_process_graph(double p_delta) {
}
}
- real_t db = Math::linear2db(MAX(blend, 0.00001));
+ real_t db = Math::linear_to_db(MAX(blend, 0.00001));
if (t->object->has_method(SNAME("set_unit_db"))) {
t->object->call(SNAME("set_unit_db"), db);
} else {
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index 99851d140e..ee0c0303dc 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -111,7 +111,7 @@ protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
GDVIRTUAL0RC(Dictionary, _get_child_nodes)
GDVIRTUAL0RC(Array, _get_parameter_list)
@@ -233,6 +233,7 @@ private:
Variant init_value;
Variant value;
Vector<StringName> subpath;
+ bool is_using_angle = false;
TrackCacheValue() { type = Animation::TYPE_VALUE; }
};
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index dbc71cd9e7..7d9f83b7a2 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -479,12 +479,8 @@ Variant Tween::interpolate_variant(Variant p_initial_val, Variant p_delta_val, f
case Variant::QUATERNION: {
Quaternion i = p_initial_val;
Quaternion d = p_delta_val;
- Quaternion r;
-
- APPLY_EQUATION(x);
- APPLY_EQUATION(y);
- APPLY_EQUATION(z);
- APPLY_EQUATION(w);
+ Quaternion r = i * d;
+ r = i.slerp(r, run_equation(p_trans, p_ease, p_time, 0.0, 1.0, p_duration));
return r;
}
diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp
index 04debcab05..04feb0dc6f 100644
--- a/scene/audio/audio_stream_player.cpp
+++ b/scene/audio/audio_stream_player.cpp
@@ -256,7 +256,7 @@ Vector<AudioFrame> AudioStreamPlayer::_get_volume_vector() {
channel_volume_db = AudioFrame(0, 0);
}
- float volume_linear = Math::db2linear(volume_db);
+ float volume_linear = Math::db_to_linear(volume_db);
// Set the volume vector up according to the speaker mode and mix target.
// TODO do we need to scale the volume down when we output to more channels?
@@ -283,8 +283,8 @@ Vector<AudioFrame> AudioStreamPlayer::_get_volume_vector() {
return volume_vector;
}
-void AudioStreamPlayer::_validate_property(PropertyInfo &property) const {
- if (property.name == "bus") {
+void AudioStreamPlayer::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "bus") {
String options;
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
if (i > 0) {
@@ -294,10 +294,8 @@ void AudioStreamPlayer::_validate_property(PropertyInfo &property) const {
options += name;
}
- property.hint_string = options;
+ p_property.hint_string = options;
}
-
- Node::_validate_property(property);
}
void AudioStreamPlayer::_bus_layout_changed() {
diff --git a/scene/audio/audio_stream_player.h b/scene/audio/audio_stream_player.h
index 67e616312a..45a6d7663e 100644
--- a/scene/audio/audio_stream_player.h
+++ b/scene/audio/audio_stream_player.h
@@ -72,7 +72,7 @@ private:
Vector<AudioFrame> _get_volume_vector();
protected:
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/aspect_ratio_container.cpp b/scene/gui/aspect_ratio_container.cpp
index 75f19ac452..e4a79c7aa3 100644
--- a/scene/gui/aspect_ratio_container.cpp
+++ b/scene/gui/aspect_ratio_container.cpp
@@ -51,21 +51,33 @@ Size2 AspectRatioContainer::get_minimum_size() const {
}
void AspectRatioContainer::set_ratio(float p_ratio) {
+ if (ratio == p_ratio) {
+ return;
+ }
ratio = p_ratio;
queue_sort();
}
void AspectRatioContainer::set_stretch_mode(StretchMode p_mode) {
+ if (stretch_mode == p_mode) {
+ return;
+ }
stretch_mode = p_mode;
queue_sort();
}
void AspectRatioContainer::set_alignment_horizontal(AlignmentMode p_alignment_horizontal) {
+ if (alignment_horizontal == p_alignment_horizontal) {
+ return;
+ }
alignment_horizontal = p_alignment_horizontal;
queue_sort();
}
void AspectRatioContainer::set_alignment_vertical(AlignmentMode p_alignment_vertical) {
+ if (alignment_vertical == p_alignment_vertical) {
+ return;
+ }
alignment_vertical = p_alignment_vertical;
queue_sort();
}
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index 776623f7ce..cee7c049a9 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -64,7 +64,10 @@ void BaseButton::gui_input(const Ref<InputEvent> &p_event) {
bool button_masked = mouse_button.is_valid() && (mouse_button_to_mask(mouse_button->get_button_index()) & button_mask) != MouseButton::NONE;
if (button_masked || ui_accept) {
+ was_mouse_pressed = button_masked;
on_action_event(p_event);
+ was_mouse_pressed = false;
+
return;
}
@@ -417,6 +420,10 @@ bool BaseButton::_is_focus_owner_in_shortcut_context() const {
return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_ancestor_of(vp_focus));
}
+bool BaseButton::_was_pressed_by_mouse() const {
+ return was_mouse_pressed;
+}
+
void BaseButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &BaseButton::set_pressed);
ClassDB::bind_method(D_METHOD("is_pressed"), &BaseButton::is_pressed);
@@ -490,8 +497,8 @@ void ButtonGroup::get_buttons(List<BaseButton *> *r_buttons) {
}
}
-Array ButtonGroup::_get_buttons() {
- Array btns;
+TypedArray<BaseButton> ButtonGroup::_get_buttons() {
+ TypedArray<BaseButton> btns;
for (const BaseButton *E : buttons) {
btns.push_back(E);
}
diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h
index 7cf8de6432..c83b08aadf 100644
--- a/scene/gui/base_button.h
+++ b/scene/gui/base_button.h
@@ -49,6 +49,7 @@ private:
MouseButton button_mask = MouseButton::MASK_LEFT;
bool toggle_mode = false;
bool shortcut_in_tooltip = true;
+ bool was_mouse_pressed = false;
bool keep_pressed_outside = false;
Ref<Shortcut> shortcut;
ObjectID shortcut_context;
@@ -81,6 +82,7 @@ protected:
void _notification(int p_what);
bool _is_focus_owner_in_shortcut_context() const;
+ bool _was_pressed_by_mouse() const;
GDVIRTUAL0(_pressed)
GDVIRTUAL1(_toggled, bool)
@@ -151,7 +153,7 @@ protected:
public:
BaseButton *get_pressed_button();
void get_buttons(List<BaseButton *> *r_buttons);
- Array _get_buttons();
+ TypedArray<BaseButton> _get_buttons();
ButtonGroup();
};
diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp
index df695feba8..a56a51a547 100644
--- a/scene/gui/box_container.cpp
+++ b/scene/gui/box_container.cpp
@@ -308,6 +308,9 @@ void BoxContainer::_notification(int p_what) {
}
void BoxContainer::set_alignment(AlignmentMode p_alignment) {
+ if (alignment == p_alignment) {
+ return;
+ }
alignment = p_alignment;
_resort();
}
diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp
index a67f850a86..e163f4355c 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -34,39 +34,12 @@
#include "servers/rendering_server.h"
Size2 Button::get_minimum_size() const {
- Size2 minsize = text_buf->get_size();
- if (clip_text || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
- minsize.width = 0;
+ Ref<Texture2D> _icon = icon;
+ if (_icon.is_null() && has_theme_icon(SNAME("icon"))) {
+ _icon = Control::get_theme_icon(SNAME("icon"));
}
- if (!expand_icon) {
- Ref<Texture2D> _icon;
- if (icon.is_null() && has_theme_icon(SNAME("icon"))) {
- _icon = Control::get_theme_icon(SNAME("icon"));
- } else {
- _icon = icon;
- }
-
- if (!_icon.is_null()) {
- minsize.height = MAX(minsize.height, _icon->get_height());
-
- if (icon_alignment != HORIZONTAL_ALIGNMENT_CENTER) {
- minsize.width += _icon->get_width();
- if (!xl_text.is_empty()) {
- minsize.width += get_theme_constant(SNAME("h_separation"));
- }
- } else {
- minsize.width = MAX(minsize.width, _icon->get_width());
- }
- }
- }
- if (!xl_text.is_empty()) {
- Ref<Font> font = get_theme_font(SNAME("font"));
- float font_height = font->get_height(get_theme_font_size(SNAME("font_size")));
- minsize.height = MAX(font_height, minsize.height);
- }
-
- return get_theme_stylebox(SNAME("normal"))->get_minimum_size() + minsize;
+ return get_minimum_size_for_text_and_icon("", _icon);
}
void Button::_set_internal_margin(Side p_side, float p_value) {
@@ -283,7 +256,8 @@ void Button::_notification(int p_what) {
}
if (icon_region.size.width > 0) {
- draw_texture_rect_region(_icon, icon_region, Rect2(Point2(), _icon->get_size()), color_icon);
+ Rect2 icon_region_rounded = Rect2(icon_region.position.round(), icon_region.size.round());
+ draw_texture_rect(_icon, icon_region_rounded, false, color_icon);
}
}
@@ -352,18 +326,62 @@ void Button::_notification(int p_what) {
}
}
-void Button::_shape() {
+Size2 Button::get_minimum_size_for_text_and_icon(const String &p_text, Ref<Texture2D> p_icon) const {
+ Ref<TextParagraph> paragraph;
+ if (p_text.is_empty()) {
+ paragraph = text_buf;
+ } else {
+ paragraph.instantiate();
+ const_cast<Button *>(this)->_shape(paragraph, p_text);
+ }
+
+ Size2 minsize = paragraph->get_size();
+ if (clip_text || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
+ minsize.width = 0;
+ }
+
+ if (!expand_icon && p_icon.is_valid()) {
+ minsize.height = MAX(minsize.height, p_icon->get_height());
+
+ if (icon_alignment != HORIZONTAL_ALIGNMENT_CENTER) {
+ minsize.width += p_icon->get_width();
+ if (!xl_text.is_empty() || !p_text.is_empty()) {
+ minsize.width += MAX(0, get_theme_constant(SNAME("h_separation")));
+ }
+ } else {
+ minsize.width = MAX(minsize.width, p_icon->get_width());
+ }
+ }
+
+ if (!xl_text.is_empty() || !p_text.is_empty()) {
+ Ref<Font> font = get_theme_font(SNAME("font"));
+ float font_height = font->get_height(get_theme_font_size(SNAME("font_size")));
+ minsize.height = MAX(font_height, minsize.height);
+ }
+
+ return get_theme_stylebox(SNAME("normal"))->get_minimum_size() + minsize;
+}
+
+void Button::_shape(Ref<TextParagraph> p_paragraph, String p_text) {
+ if (p_paragraph.is_null()) {
+ p_paragraph = text_buf;
+ }
+
+ if (p_text.is_empty()) {
+ p_text = xl_text;
+ }
+
Ref<Font> font = get_theme_font(SNAME("font"));
int font_size = get_theme_font_size(SNAME("font_size"));
- text_buf->clear();
+ p_paragraph->clear();
if (text_direction == Control::TEXT_DIRECTION_INHERITED) {
- text_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR);
+ p_paragraph->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR);
} else {
- text_buf->set_direction((TextServer::Direction)text_direction);
+ p_paragraph->set_direction((TextServer::Direction)text_direction);
}
- text_buf->add_string(xl_text, font, font_size, language);
- text_buf->set_text_overrun_behavior(overrun_behavior);
+ p_paragraph->add_string(p_text, font, font_size, language);
+ p_paragraph->set_text_overrun_behavior(overrun_behavior);
}
void Button::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior) {
diff --git a/scene/gui/button.h b/scene/gui/button.h
index 9d8d457f7c..23b5c78166 100644
--- a/scene/gui/button.h
+++ b/scene/gui/button.h
@@ -54,7 +54,7 @@ private:
HorizontalAlignment icon_alignment = HORIZONTAL_ALIGNMENT_LEFT;
float _internal_margin[4] = {};
- void _shape();
+ void _shape(Ref<TextParagraph> p_paragraph = Ref<TextParagraph>(), String p_text = "");
protected:
void _set_internal_margin(Side p_side, float p_value);
@@ -64,6 +64,8 @@ protected:
public:
virtual Size2 get_minimum_size() const override;
+ Size2 get_minimum_size_for_text_and_icon(const String &p_text, Ref<Texture2D> p_icon) const;
+
void set_text(const String &p_text);
String get_text() const;
diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp
index cb80f5b5ef..26edc1f1b0 100644
--- a/scene/gui/check_box.cpp
+++ b/scene/gui/check_box.cpp
@@ -75,7 +75,7 @@ Size2 CheckBox::get_minimum_size() const {
Size2 tex_size = get_icon_size();
minsize.width += tex_size.width;
if (get_text().length() > 0) {
- minsize.width += get_theme_constant(SNAME("h_separation"));
+ minsize.width += MAX(0, get_theme_constant(SNAME("h_separation")));
}
Ref<StyleBox> sb = get_theme_stylebox(SNAME("normal"));
minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(SIDE_TOP) + sb->get_margin(SIDE_BOTTOM));
diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp
index a09873ea4f..b9674ca41e 100644
--- a/scene/gui/check_button.cpp
+++ b/scene/gui/check_button.cpp
@@ -52,7 +52,7 @@ Size2 CheckButton::get_minimum_size() const {
Size2 tex_size = get_icon_size();
minsize.width += tex_size.width;
if (get_text().length() > 0) {
- minsize.width += get_theme_constant(SNAME("h_separation"));
+ minsize.width += MAX(0, get_theme_constant(SNAME("h_separation")));
}
Ref<StyleBox> sb = get_theme_stylebox(SNAME("normal"));
minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(SIDE_TOP) + sb->get_margin(SIDE_BOTTOM));
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index 8968c1cc17..e54ba7ce13 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -1280,8 +1280,8 @@ void CodeEdit::clear_breakpointed_lines() {
}
}
-Array CodeEdit::get_breakpointed_lines() const {
- Array ret;
+PackedInt32Array CodeEdit::get_breakpointed_lines() const {
+ PackedInt32Array ret;
for (int i = 0; i < get_line_count(); i++) {
if (is_line_breakpointed(i)) {
ret.append(i);
@@ -1309,8 +1309,8 @@ void CodeEdit::clear_bookmarked_lines() {
}
}
-Array CodeEdit::get_bookmarked_lines() const {
- Array ret;
+PackedInt32Array CodeEdit::get_bookmarked_lines() const {
+ PackedInt32Array ret;
for (int i = 0; i < get_line_count(); i++) {
if (is_line_bookmarked(i)) {
ret.append(i);
@@ -1338,8 +1338,8 @@ void CodeEdit::clear_executing_lines() {
}
}
-Array CodeEdit::get_executing_lines() const {
- Array ret;
+PackedInt32Array CodeEdit::get_executing_lines() const {
+ PackedInt32Array ret;
for (int i = 0; i < get_line_count(); i++) {
if (is_line_executing(i)) {
ret.append(i);
@@ -2769,7 +2769,7 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
i++;
}
- Array completion_options;
+ TypedArray<Dictionary> completion_options;
GDVIRTUAL_CALL(_filter_code_completion_candidates, completion_options_sources, completion_options);
diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h
index 08bd91a368..2065f3e681 100644
--- a/scene/gui/code_edit.h
+++ b/scene/gui/code_edit.h
@@ -266,7 +266,7 @@ protected:
GDVIRTUAL1(_confirm_code_completion, bool)
GDVIRTUAL1(_request_code_completion, bool)
- GDVIRTUAL1RC(Array, _filter_code_completion_candidates, TypedArray<Dictionary>)
+ GDVIRTUAL1RC(TypedArray<Dictionary>, _filter_code_completion_candidates, TypedArray<Dictionary>)
public:
/* General overrides */
@@ -322,19 +322,19 @@ public:
void set_line_as_breakpoint(int p_line, bool p_breakpointed);
bool is_line_breakpointed(int p_line) const;
void clear_breakpointed_lines();
- Array get_breakpointed_lines() const;
+ PackedInt32Array get_breakpointed_lines() const;
// bookmarks
void set_line_as_bookmarked(int p_line, bool p_bookmarked);
bool is_line_bookmarked(int p_line) const;
void clear_bookmarked_lines();
- Array get_bookmarked_lines() const;
+ PackedInt32Array get_bookmarked_lines() const;
// executing lines
void set_line_as_executing(int p_line, bool p_executing);
bool is_line_executing(int p_line) const;
void clear_executing_lines();
- Array get_executing_lines() const;
+ PackedInt32Array get_executing_lines() const;
/* Line numbers */
void set_draw_line_numbers(bool p_draw);
diff --git a/scene/gui/color_mode.cpp b/scene/gui/color_mode.cpp
index af78d67e5a..ebd86e0937 100644
--- a/scene/gui/color_mode.cpp
+++ b/scene/gui/color_mode.cpp
@@ -159,7 +159,7 @@ void ColorModeHSV::slider_draw(int p_which) {
} else if (p_which == 0) {
Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker"));
slider->draw_set_transform(Point2(), -Math_PI / 2, Size2(1.0, 1.0));
- slider->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(slider->get_size().x, margin)), false, Color(1, 1, 1), true);
+ slider->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(margin, size.x)), false);
return;
} else {
Color s_col;
@@ -306,7 +306,7 @@ void ColorModeOKHSL::slider_draw(int p_which) {
} else if (p_which == 0) {
Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker"));
slider->draw_set_transform(Point2(), -Math_PI / 2, Size2(1.0, 1.0));
- slider->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(slider->get_size().x, margin)), false, Color(1, 1, 1), true);
+ slider->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(margin, size.x)), false);
return;
} else {
Color s_col;
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index e2ead6415a..a417e7b9e2 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -171,6 +171,9 @@ uniform float v = 1.0;
void fragment() {
float x = UV.x - 0.5;
float y = UV.y - 0.5;
+ float h = atan(y, x) / (2.0 * M_PI);
+ float s = sqrt(x * x + y * y) * 2.0;
+ vec3 col = okhsl_to_srgb(vec3(h, s, v));
x += 0.001;
y += 0.001;
float b = float(sqrt(x * x + y * y) < 0.5);
@@ -180,9 +183,6 @@ void fragment() {
float b3 = float(sqrt(x * x + y * y) < 0.5);
x += 0.002;
float b4 = float(sqrt(x * x + y * y) < 0.5);
- float s = sqrt(x * x + y * y);
- float h = atan(y, x) / (2.0*M_PI);
- vec3 col = okhsl_to_srgb(vec3(h, s, v));
COLOR = vec4(col, (b + b2 + b3 + b4) / 4.00);
})");
}
@@ -264,15 +264,7 @@ void ColorPicker::_update_controls() {
void ColorPicker::_set_pick_color(const Color &p_color, bool p_update_sliders) {
color = p_color;
if (color != last_color) {
- if (_get_actual_shape() == SHAPE_OKHSL_CIRCLE) {
- h = color.get_ok_hsl_h();
- s = color.get_ok_hsl_s();
- v = color.get_ok_hsl_l();
- } else {
- h = color.get_h();
- s = color.get_s();
- v = color.get_v();
- }
+ _copy_color_to_hsv();
last_color = color;
}
@@ -300,6 +292,9 @@ bool ColorPicker::is_displaying_old_color() const {
}
void ColorPicker::set_edit_alpha(bool p_show) {
+ if (edit_alpha == p_show) {
+ return;
+ }
edit_alpha = p_show;
_update_controls();
@@ -386,6 +381,26 @@ Vector<float> ColorPicker::get_active_slider_values() {
return values;
}
+void ColorPicker::_copy_color_to_hsv() {
+ if (_get_actual_shape() == SHAPE_OKHSL_CIRCLE) {
+ h = color.get_ok_hsl_h();
+ s = color.get_ok_hsl_s();
+ v = color.get_ok_hsl_l();
+ } else {
+ h = color.get_h();
+ s = color.get_s();
+ v = color.get_v();
+ }
+}
+
+void ColorPicker::_copy_hsv_to_color() {
+ if (_get_actual_shape() == SHAPE_OKHSL_CIRCLE) {
+ color.set_ok_hsl(h, s, v, color.a);
+ } else {
+ color.set_hsv(h, s, v, color.a);
+ }
+}
+
ColorPicker::PickerShapeType ColorPicker::_get_actual_shape() const {
return modes[current_mode]->get_shape_override() != SHAPE_MAX ? modes[current_mode]->get_shape_override() : current_shape;
}
@@ -497,8 +512,13 @@ Color ColorPicker::get_pick_color() const {
void ColorPicker::set_picker_shape(PickerShapeType p_shape) {
ERR_FAIL_INDEX(p_shape, SHAPE_MAX);
+ if (current_shape == p_shape) {
+ return;
+ }
current_shape = p_shape;
+ _copy_color_to_hsv();
+
_update_controls();
_update_color();
}
@@ -516,7 +536,7 @@ void ColorPicker::_add_preset_button(int p_size, const Color &p_color) {
btn_preset->set_preset_color(p_color);
btn_preset->set_custom_minimum_size(Size2(p_size, p_size));
btn_preset->connect("gui_input", callable_mp(this, &ColorPicker::_preset_input).bind(p_color));
- btn_preset->set_tooltip(vformat(RTR("Color: #%s\nLMB: Apply color\nRMB: Remove preset"), p_color.to_html(p_color.a < 1)));
+ btn_preset->set_tooltip_text(vformat(RTR("Color: #%s\nLMB: Apply color\nRMB: Remove preset"), p_color.to_html(p_color.a < 1)));
preset_container->add_child(btn_preset);
}
@@ -640,8 +660,7 @@ void ColorPicker::_sample_input(const Ref<InputEvent> &p_event) {
const Rect2 rect_old = Rect2(Point2(), Size2(sample->get_size().width * 0.5, sample->get_size().height * 0.95));
if (rect_old.has_point(mb->get_position())) {
// Revert to the old color when left-clicking the old color sample.
- color = old_color;
- _update_color();
+ set_pick_color(old_color);
emit_signal(SNAME("color_changed"), color);
}
}
@@ -834,7 +853,7 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) {
} else if (p_which == 2) {
c->draw_rect(Rect2(Point2(), c->get_size()), Color(1, 1, 1));
if (actual_shape == SHAPE_VHS_CIRCLE || actual_shape == SHAPE_OKHSL_CIRCLE) {
- circle_mat->set_shader_param("v", v);
+ circle_mat->set_shader_uniform("v", v);
}
}
}
@@ -887,17 +906,14 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) {
v = 1.0 - (y - c->get_position().y - corner_y) / real_size.y;
}
}
+
changing_color = true;
- if (current_picker == SHAPE_OKHSL_CIRCLE) {
- color.set_ok_hsl(h, s, v, color.a);
- } else {
- color.set_hsv(h, s, v, color.a);
- }
+ _copy_hsv_to_color();
last_color = color;
-
set_pick_color(color);
_update_color();
+
if (!deferred_mode_enabled) {
emit_signal(SNAME("color_changed"), color);
}
@@ -940,14 +956,12 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) {
v = 1.0 - (y - corner_y) / real_size.y;
}
}
- if (current_picker != SHAPE_OKHSL_CIRCLE) {
- color.set_hsv(h, s, v, color.a);
- } else {
- color.set_ok_hsl(h, s, v, color.a);
- }
+
+ _copy_hsv_to_color();
last_color = color;
set_pick_color(color);
_update_color();
+
if (!deferred_mode_enabled) {
emit_signal(SNAME("color_changed"), color);
}
@@ -970,14 +984,12 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) {
} else {
changing_color = false;
}
- if (actual_shape != SHAPE_OKHSL_CIRCLE) {
- color.set_hsv(h, s, v, color.a);
- } else {
- color.set_ok_hsl(h, s, v, color.a);
- }
+
+ _copy_hsv_to_color();
last_color = color;
set_pick_color(color);
_update_color();
+
if (!deferred_mode_enabled) {
emit_signal(SNAME("color_changed"), color);
} else if (!bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) {
@@ -998,15 +1010,11 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) {
h = y / w_edit->get_size().height;
}
- if (actual_shape == SHAPE_OKHSL_CIRCLE) {
- color.set_ok_hsl(h, s, v, color.a);
- } else {
- color.set_hsv(h, s, v, color.a);
- }
-
+ _copy_hsv_to_color();
last_color = color;
set_pick_color(color);
_update_color();
+
if (!deferred_mode_enabled) {
emit_signal(SNAME("color_changed"), color);
}
@@ -1019,7 +1027,6 @@ void ColorPicker::_preset_input(const Ref<InputEvent> &p_event, const Color &p_c
if (bev.is_valid()) {
if (bev->is_pressed() && bev->get_button_index() == MouseButton::LEFT) {
set_pick_color(p_color);
- _update_color();
emit_signal(SNAME("color_changed"), p_color);
} else if (bev->is_pressed() && bev->get_button_index() == MouseButton::RIGHT && presets_enabled) {
erase_preset(p_color);
@@ -1130,6 +1137,9 @@ void ColorPicker::_html_focus_exit() {
}
void ColorPicker::set_presets_enabled(bool p_enabled) {
+ if (presets_enabled == p_enabled) {
+ return;
+ }
presets_enabled = p_enabled;
if (!p_enabled) {
btn_add_preset->set_disabled(true);
@@ -1145,6 +1155,9 @@ bool ColorPicker::are_presets_enabled() const {
}
void ColorPicker::set_presets_visible(bool p_visible) {
+ if (presets_visible == p_visible) {
+ return;
+ }
presets_visible = p_visible;
preset_separator->set_visible(p_visible);
preset_container->set_visible(p_visible);
@@ -1223,7 +1236,7 @@ ColorPicker::ColorPicker() :
btn_pick->set_flat(true);
hb_smpl->add_child(btn_pick);
btn_pick->set_toggle_mode(true);
- btn_pick->set_tooltip(RTR("Pick a color from the editor window."));
+ btn_pick->set_tooltip_text(RTR("Pick a color from the editor window."));
btn_pick->connect("pressed", callable_mp(this, &ColorPicker::_screen_pick_pressed));
VBoxContainer *vbl = memnew(VBoxContainer);
@@ -1263,7 +1276,7 @@ ColorPicker::ColorPicker() :
text_type = memnew(Button);
hhb->add_child(text_type);
text_type->set_text("#");
- text_type->set_tooltip(RTR("Switch between hexadecimal and code values."));
+ text_type->set_tooltip_text(RTR("Switch between hexadecimal and code values."));
if (Engine::get_singleton()->is_editor_hint()) {
text_type->connect("pressed", callable_mp(this, &ColorPicker::_text_type_toggled));
} else {
@@ -1324,7 +1337,7 @@ ColorPicker::ColorPicker() :
btn_add_preset = memnew(Button);
btn_add_preset->set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER);
- btn_add_preset->set_tooltip(RTR("Add current color as a preset."));
+ btn_add_preset->set_tooltip_text(RTR("Add current color as a preset."));
btn_add_preset->connect("pressed", callable_mp(this, &ColorPicker::_add_preset_pressed));
preset_container->add_child(btn_add_preset);
}
@@ -1418,6 +1431,9 @@ void ColorPickerButton::_notification(int p_what) {
}
void ColorPickerButton::set_pick_color(const Color &p_color) {
+ if (color == p_color) {
+ return;
+ }
color = p_color;
if (picker) {
picker->set_pick_color(p_color);
@@ -1431,6 +1447,9 @@ Color ColorPickerButton::get_pick_color() const {
}
void ColorPickerButton::set_edit_alpha(bool p_show) {
+ if (edit_alpha == p_show) {
+ return;
+ }
edit_alpha = p_show;
if (picker) {
picker->set_edit_alpha(p_show);
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index 8e65ee1861..05b760b109 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -156,6 +156,9 @@ private:
float v = 0.0;
Color last_color;
+ void _copy_color_to_hsv();
+ void _copy_hsv_to_color();
+
PickerShapeType _get_actual_shape() const;
void create_slider(GridContainer *gc, int idx);
void _reset_theme();
diff --git a/scene/gui/color_rect.cpp b/scene/gui/color_rect.cpp
index 2955f74a0c..c30fa8461a 100644
--- a/scene/gui/color_rect.cpp
+++ b/scene/gui/color_rect.cpp
@@ -31,6 +31,9 @@
#include "color_rect.h"
void ColorRect::set_color(const Color &p_color) {
+ if (color == p_color) {
+ return;
+ }
color = p_color;
update();
}
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 06aa913eb1..4de16a0a29 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -43,6 +43,7 @@
#include "scene/main/canvas_layer.h"
#include "scene/main/window.h"
#include "scene/scene_string_names.h"
+#include "scene/theme/theme_db.h"
#include "servers/rendering_server.h"
#include "servers/text_server.h"
@@ -193,15 +194,15 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List
List<StringName> sn;
String pf = p_function;
if (pf == "add_theme_color_override" || pf == "has_theme_color" || pf == "has_theme_color_override" || pf == "get_theme_color") {
- Theme::get_default()->get_color_list(get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_color_list(get_class(), &sn);
} else if (pf == "add_theme_style_override" || pf == "has_theme_style" || pf == "has_theme_style_override" || pf == "get_theme_style") {
- Theme::get_default()->get_stylebox_list(get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_stylebox_list(get_class(), &sn);
} else if (pf == "add_theme_font_override" || pf == "has_theme_font" || pf == "has_theme_font_override" || pf == "get_theme_font") {
- Theme::get_default()->get_font_list(get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_font_list(get_class(), &sn);
} else if (pf == "add_theme_font_size_override" || pf == "has_theme_font_size" || pf == "has_theme_font_size_override" || pf == "get_theme_font_size") {
- Theme::get_default()->get_font_size_list(get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_font_size_list(get_class(), &sn);
} else if (pf == "add_theme_constant_override" || pf == "has_theme_constant" || pf == "has_theme_constant_override" || pf == "get_theme_constant") {
- Theme::get_default()->get_constant_list(get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_constant_list(get_class(), &sn);
}
sn.sort_custom<StringName::AlphCompare>();
@@ -252,36 +253,36 @@ bool Control::_set(const StringName &p_name, const Variant &p_value) {
if (name.begins_with("theme_override_icons/")) {
String dname = name.get_slicec('/', 1);
if (data.icon_override.has(dname)) {
- data.icon_override[dname]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.icon_override[dname]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.icon_override.erase(dname);
- notification(NOTIFICATION_THEME_CHANGED);
+ _notify_theme_override_changed();
} else if (name.begins_with("theme_override_styles/")) {
String dname = name.get_slicec('/', 1);
if (data.style_override.has(dname)) {
- data.style_override[dname]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.style_override[dname]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.style_override.erase(dname);
- notification(NOTIFICATION_THEME_CHANGED);
+ _notify_theme_override_changed();
} else if (name.begins_with("theme_override_fonts/")) {
String dname = name.get_slicec('/', 1);
if (data.font_override.has(dname)) {
- data.font_override[dname]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.font_override[dname]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.font_override.erase(dname);
- notification(NOTIFICATION_THEME_CHANGED);
+ _notify_theme_override_changed();
} else if (name.begins_with("theme_override_font_sizes/")) {
String dname = name.get_slicec('/', 1);
data.font_size_override.erase(dname);
- notification(NOTIFICATION_THEME_CHANGED);
+ _notify_theme_override_changed();
} else if (name.begins_with("theme_override_colors/")) {
String dname = name.get_slicec('/', 1);
data.color_override.erase(dname);
- notification(NOTIFICATION_THEME_CHANGED);
+ _notify_theme_override_changed();
} else if (name.begins_with("theme_override_constants/")) {
String dname = name.get_slicec('/', 1);
data.constant_override.erase(dname);
- notification(NOTIFICATION_THEME_CHANGED);
+ _notify_theme_override_changed();
} else {
return false;
}
@@ -344,7 +345,7 @@ bool Control::_get(const StringName &p_name, Variant &r_ret) const {
}
void Control::_get_property_list(List<PropertyInfo> *p_list) const {
- Ref<Theme> theme = Theme::get_default();
+ Ref<Theme> theme = ThemeDB::get_singleton()->get_default_theme();
p_list->push_back(PropertyInfo(Variant::NIL, TTRC("Theme Overrides"), PROPERTY_HINT_NONE, "theme_override_", PROPERTY_USAGE_GROUP));
@@ -422,16 +423,16 @@ void Control::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-void Control::_validate_property(PropertyInfo &property) const {
+void Control::_validate_property(PropertyInfo &p_property) const {
// Update theme type variation options.
- if (property.name == "theme_type_variation") {
+ if (p_property.name == "theme_type_variation") {
List<StringName> names;
// Only the default theme and the project theme are used for the list of options.
// This is an imposed limitation to simplify the logic needed to leverage those options.
- Theme::get_default()->get_type_variation_list(get_class_name(), &names);
- if (Theme::get_project_default().is_valid()) {
- Theme::get_project_default()->get_type_variation_list(get_class_name(), &names);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_variation_list(get_class_name(), &names);
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
+ ThemeDB::get_singleton()->get_project_theme()->get_type_variation_list(get_class_name(), &names);
}
names.sort_custom<StringName::AlphCompare>();
@@ -447,18 +448,18 @@ void Control::_validate_property(PropertyInfo &property) const {
unique_names.append(E);
}
- property.hint_string = hint_string;
+ p_property.hint_string = hint_string;
}
- if (property.name == "mouse_force_pass_scroll_events") {
+ if (p_property.name == "mouse_force_pass_scroll_events") {
// Disable force pass if the control is not stopping the event.
if (data.mouse_filter != MOUSE_FILTER_STOP) {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
}
- if (property.name == "scale") {
- property.hint = PROPERTY_HINT_LINK;
+ if (p_property.name == "scale") {
+ p_property.hint = PROPERTY_HINT_LINK;
}
// Validate which positioning properties should be displayed depending on the parent and the layout mode.
@@ -467,33 +468,33 @@ void Control::_validate_property(PropertyInfo &property) const {
// If there is no parent, display both anchor and container options.
// Set the layout mode to be disabled with the proper value.
- if (property.name == "layout_mode") {
- property.hint_string = "Position,Anchors,Container,Uncontrolled";
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ if (p_property.name == "layout_mode") {
+ p_property.hint_string = "Position,Anchors,Container,Uncontrolled";
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
// Use the layout mode to display or hide advanced anchoring properties.
bool use_custom_anchors = _get_anchors_layout_preset() == -1; // Custom "preset".
- if (!use_custom_anchors && (property.name.begins_with("anchor_") || property.name.begins_with("offset_") || property.name.begins_with("grow_"))) {
- property.usage ^= PROPERTY_USAGE_EDITOR;
+ if (!use_custom_anchors && (p_property.name.begins_with("anchor_") || p_property.name.begins_with("offset_") || p_property.name.begins_with("grow_"))) {
+ p_property.usage ^= PROPERTY_USAGE_EDITOR;
}
} else if (Object::cast_to<Container>(parent_node)) {
// If the parent is a container, display only container-related properties.
- if (property.name.begins_with("anchor_") || property.name.begins_with("offset_") || property.name.begins_with("grow_") || property.name == "anchors_preset" ||
- property.name == "position" || property.name == "rotation" || property.name == "scale" || property.name == "size" || property.name == "pivot_offset") {
- property.usage ^= PROPERTY_USAGE_EDITOR;
+ if (p_property.name.begins_with("anchor_") || p_property.name.begins_with("offset_") || p_property.name.begins_with("grow_") || p_property.name == "anchors_preset" ||
+ p_property.name == "position" || p_property.name == "rotation" || p_property.name == "scale" || p_property.name == "size" || p_property.name == "pivot_offset") {
+ p_property.usage ^= PROPERTY_USAGE_EDITOR;
- } else if (property.name == "layout_mode") {
+ } else if (p_property.name == "layout_mode") {
// Set the layout mode to be disabled with the proper value.
- property.hint_string = "Position,Anchors,Container,Uncontrolled";
- property.usage |= PROPERTY_USAGE_READ_ONLY;
- } else if (property.name == "size_flags_horizontal" || property.name == "size_flags_vertical") {
+ p_property.hint_string = "Position,Anchors,Container,Uncontrolled";
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
+ } else if (p_property.name == "size_flags_horizontal" || p_property.name == "size_flags_vertical") {
// Filter allowed size flags based on the parent container configuration.
Container *parent_container = Object::cast_to<Container>(parent_node);
Vector<int> size_flags;
- if (property.name == "size_flags_horizontal") {
+ if (p_property.name == "size_flags_horizontal") {
size_flags = parent_container->get_allowed_size_flags_horizontal();
- } else if (property.name == "size_flags_vertical") {
+ } else if (p_property.name == "size_flags_vertical") {
size_flags = parent_container->get_allowed_size_flags_vertical();
}
@@ -522,30 +523,30 @@ void Control::_validate_property(PropertyInfo &property) const {
}
if (hint_string.is_empty()) {
- property.hint_string = "";
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.hint_string = "";
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
} else {
- property.hint_string = hint_string;
+ p_property.hint_string = hint_string;
}
}
} else {
// If the parent is NOT a container or not a control at all, display only anchoring-related properties.
- if (property.name.begins_with("size_flags_")) {
- property.usage ^= PROPERTY_USAGE_EDITOR;
+ if (p_property.name.begins_with("size_flags_")) {
+ p_property.usage ^= PROPERTY_USAGE_EDITOR;
- } else if (property.name == "layout_mode") {
+ } else if (p_property.name == "layout_mode") {
// Set the layout mode to be enabled with proper options.
- property.hint_string = "Position,Anchors";
+ p_property.hint_string = "Position,Anchors";
}
// Use the layout mode to display or hide advanced anchoring properties.
bool use_anchors = _get_layout_mode() == LayoutMode::LAYOUT_MODE_ANCHORS;
- if (!use_anchors && property.name == "anchors_preset") {
- property.usage ^= PROPERTY_USAGE_EDITOR;
+ if (!use_anchors && p_property.name == "anchors_preset") {
+ p_property.usage ^= PROPERTY_USAGE_EDITOR;
}
bool use_custom_anchors = use_anchors && _get_anchors_layout_preset() == -1; // Custom "preset".
- if (!use_custom_anchors && (property.name.begins_with("anchor_") || property.name.begins_with("offset_") || property.name.begins_with("grow_"))) {
- property.usage ^= PROPERTY_USAGE_EDITOR;
+ if (!use_custom_anchors && (p_property.name.begins_with("anchor_") || p_property.name.begins_with("offset_") || p_property.name.begins_with("grow_"))) {
+ p_property.usage ^= PROPERTY_USAGE_EDITOR;
}
}
@@ -555,16 +556,36 @@ void Control::_validate_property(PropertyInfo &property) const {
}
bool property_is_managed_by_container = false;
for (unsigned i = 0; i < properties_managed_by_container_count; i++) {
- property_is_managed_by_container = properties_managed_by_container[i] == property.name;
+ property_is_managed_by_container = properties_managed_by_container[i] == p_property.name;
if (property_is_managed_by_container) {
break;
}
}
if (property_is_managed_by_container) {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
}
+bool Control::_property_can_revert(const StringName &p_name) const {
+ if (p_name == "layout_mode" || p_name == "anchors_preset") {
+ return true;
+ }
+
+ return false;
+}
+
+bool Control::_property_get_revert(const StringName &p_name, Variant &r_property) const {
+ if (p_name == "layout_mode") {
+ r_property = _get_default_layout_mode();
+ return true;
+ } else if (p_name == "anchors_preset") {
+ r_property = LayoutPreset::PRESET_TOP_LEFT;
+ return true;
+ }
+
+ return false;
+}
+
// Global relations.
bool Control::is_top_level_control() const {
@@ -703,6 +724,9 @@ real_t Control::get_anchor(Side p_side) const {
void Control::set_offset(Side p_side, real_t p_value) {
ERR_FAIL_INDEX((int)p_side, 4);
+ if (data.offset[p_side] == p_value) {
+ return;
+ }
data.offset[p_side] = p_value;
_size_changed();
@@ -720,6 +744,10 @@ void Control::set_anchor_and_offset(Side p_side, real_t p_anchor, real_t p_pos,
}
void Control::set_begin(const Size2 &p_point) {
+ if (data.offset[0] == p_point.x && data.offset[1] == p_point.y) {
+ return;
+ }
+
data.offset[0] = p_point.x;
data.offset[1] = p_point.y;
_size_changed();
@@ -730,6 +758,10 @@ Size2 Control::get_begin() const {
}
void Control::set_end(const Size2 &p_point) {
+ if (data.offset[2] == p_point.x && data.offset[3] == p_point.y) {
+ return;
+ }
+
data.offset[2] = p_point.x;
data.offset[3] = p_point.y;
_size_changed();
@@ -740,6 +772,10 @@ Size2 Control::get_end() const {
}
void Control::set_h_grow_direction(GrowDirection p_direction) {
+ if (data.h_grow == p_direction) {
+ return;
+ }
+
ERR_FAIL_INDEX((int)p_direction, 3);
data.h_grow = p_direction;
@@ -751,6 +787,10 @@ Control::GrowDirection Control::get_h_grow_direction() const {
}
void Control::set_v_grow_direction(GrowDirection p_direction) {
+ if (data.v_grow == p_direction) {
+ return;
+ }
+
ERR_FAIL_INDEX((int)p_direction, 3);
data.v_grow = p_direction;
@@ -794,24 +834,15 @@ void Control::_compute_offsets(Rect2 p_rect, const real_t p_anchors[4], real_t (
void Control::_set_layout_mode(LayoutMode p_mode) {
bool list_changed = false;
- if (p_mode == LayoutMode::LAYOUT_MODE_POSITION || p_mode == LayoutMode::LAYOUT_MODE_ANCHORS) {
- if ((int)get_meta("_edit_layout_mode", p_mode) != (int)p_mode) {
- list_changed = true;
- }
-
- set_meta("_edit_layout_mode", (int)p_mode);
+ if (data.stored_layout_mode != p_mode) {
+ list_changed = true;
+ data.stored_layout_mode = p_mode;
+ }
- if (p_mode == LayoutMode::LAYOUT_MODE_POSITION) {
- remove_meta("_edit_layout_mode");
- remove_meta("_edit_use_custom_anchors");
- set_anchors_and_offsets_preset(LayoutPreset::PRESET_TOP_LEFT, LayoutPresetMode::PRESET_MODE_KEEP_SIZE);
- set_grow_direction_preset(LayoutPreset::PRESET_TOP_LEFT);
- }
- } else {
- if (has_meta("_edit_layout_mode")) {
- remove_meta("_edit_layout_mode");
- list_changed = true;
- }
+ if (data.stored_layout_mode == LayoutMode::LAYOUT_MODE_POSITION) {
+ data.stored_use_custom_anchors = false;
+ set_anchors_and_offsets_preset(LayoutPreset::PRESET_TOP_LEFT, LayoutPresetMode::PRESET_MODE_KEEP_SIZE);
+ set_grow_direction_preset(LayoutPreset::PRESET_TOP_LEFT);
}
if (list_changed) {
@@ -832,33 +863,43 @@ Control::LayoutMode Control::_get_layout_mode() const {
if (_get_anchors_layout_preset() != (int)LayoutPreset::PRESET_TOP_LEFT) {
return LayoutMode::LAYOUT_MODE_ANCHORS;
}
- // Otherwise check what was saved.
- if (has_meta("_edit_layout_mode")) {
- return (LayoutMode)(int)get_meta("_edit_layout_mode");
+
+ // Otherwise fallback on what's stored.
+ return data.stored_layout_mode;
+}
+
+Control::LayoutMode Control::_get_default_layout_mode() const {
+ Node *parent_node = get_parent_control();
+ // In these modes the property is read-only.
+ if (!parent_node) {
+ return LayoutMode::LAYOUT_MODE_UNCONTROLLED;
+ } else if (Object::cast_to<Container>(parent_node)) {
+ return LayoutMode::LAYOUT_MODE_CONTAINER;
}
- // Or fallback on default.
+
+ // Otherwise fallback on the position mode.
return LayoutMode::LAYOUT_MODE_POSITION;
}
void Control::_set_anchors_layout_preset(int p_preset) {
bool list_changed = false;
- if (get_meta("_edit_layout_mode", LayoutMode::LAYOUT_MODE_ANCHORS).operator int() != LayoutMode::LAYOUT_MODE_ANCHORS) {
+ if (data.stored_layout_mode != LayoutMode::LAYOUT_MODE_ANCHORS) {
list_changed = true;
- set_meta("_edit_layout_mode", LayoutMode::LAYOUT_MODE_ANCHORS);
+ data.stored_layout_mode = LayoutMode::LAYOUT_MODE_ANCHORS;
}
if (p_preset == -1) {
- if (!get_meta("_edit_use_custom_anchors", false)) {
- set_meta("_edit_use_custom_anchors", true);
+ if (!data.stored_use_custom_anchors) {
+ data.stored_use_custom_anchors = true;
notify_property_list_changed();
}
return; // Keep settings as is.
}
- if (get_meta("_edit_use_custom_anchors", true)) {
+ if (data.stored_use_custom_anchors) {
list_changed = true;
- remove_meta("_edit_use_custom_anchors");
+ data.stored_use_custom_anchors = false;
}
LayoutPreset preset = (LayoutPreset)p_preset;
@@ -899,7 +940,7 @@ void Control::_set_anchors_layout_preset(int p_preset) {
int Control::_get_anchors_layout_preset() const {
// If the custom preset was selected by user, use it.
- if ((bool)get_meta("_edit_use_custom_anchors", false)) {
+ if (data.stored_use_custom_anchors) {
return -1;
}
@@ -1406,6 +1447,10 @@ Rect2 Control::get_anchorable_rect() const {
}
void Control::set_scale(const Vector2 &p_scale) {
+ if (data.scale == p_scale) {
+ return;
+ }
+
data.scale = p_scale;
// Avoid having 0 scale values, can lead to errors in physics and rendering.
if (data.scale.x == 0) {
@@ -1423,6 +1468,10 @@ Vector2 Control::get_scale() const {
}
void Control::set_rotation(real_t p_radians) {
+ if (data.rotation == p_radians) {
+ return;
+ }
+
data.rotation = p_radians;
update();
_notify_transform();
@@ -1433,6 +1482,10 @@ real_t Control::get_rotation() const {
}
void Control::set_pivot_offset(const Vector2 &p_pivot) {
+ if (data.pivot_offset == p_pivot) {
+ return;
+ }
+
data.pivot_offset = p_pivot;
update();
_notify_transform();
@@ -2183,6 +2236,9 @@ Control::CursorShape Control::get_cursor_shape(const Point2 &p_pos) const {
}
void Control::set_disable_visibility_clip(bool p_ignore) {
+ if (data.disable_visibility_clip == p_ignore) {
+ return;
+ }
data.disable_visibility_clip = p_ignore;
update();
}
@@ -2192,6 +2248,9 @@ bool Control::is_visibility_clip_disabled() const {
}
void Control::set_clip_contents(bool p_clip) {
+ if (data.clip_contents == p_clip) {
+ return;
+ }
data.clip_contents = p_clip;
update();
}
@@ -2202,66 +2261,75 @@ bool Control::is_clipping_contents() {
// Theming.
-void Control::_propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_assign) {
+void Control::_propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_notify, bool p_assign) {
Control *c = Object::cast_to<Control>(p_at);
-
- if (c && c != p_owner && c->data.theme.is_valid()) { // has a theme, this can't be propagated
- return;
- }
-
Window *w = c == nullptr ? Object::cast_to<Window>(p_at) : nullptr;
- if (w && w != p_owner_window && w->theme.is_valid()) { // has a theme, this can't be propagated
+ if (!c && !w) {
+ // Theme inheritance chains are broken by nodes that aren't Control or Window.
return;
}
- for (int i = 0; i < p_at->get_child_count(); i++) {
- CanvasItem *child = Object::cast_to<CanvasItem>(p_at->get_child(i));
- if (child) {
- _propagate_theme_changed(child, p_owner, p_owner_window, p_assign);
- } else {
- Window *window = Object::cast_to<Window>(p_at->get_child(i));
- if (window) {
- _propagate_theme_changed(window, p_owner, p_owner_window, p_assign);
- }
+ bool assign = p_assign;
+ if (c) {
+ if (c != p_owner && c->data.theme.is_valid()) {
+ // Has a theme, so we don't want to change the theme owner,
+ // but we still want to propagate in case this child has theme items
+ // it inherits from the theme this node uses.
+ // See https://github.com/godotengine/godot/issues/62844.
+ assign = false;
}
- }
- if (c) {
- if (p_assign) {
+ if (assign) {
c->data.theme_owner = p_owner;
c->data.theme_owner_window = p_owner_window;
}
- c->notification(Control::NOTIFICATION_THEME_CHANGED);
- c->emit_signal(SceneStringNames::get_singleton()->theme_changed);
- }
- if (w) {
- if (p_assign) {
+ if (p_notify) {
+ c->notification(Control::NOTIFICATION_THEME_CHANGED);
+ }
+ } else if (w) {
+ if (w != p_owner_window && w->theme.is_valid()) {
+ // Same as above.
+ assign = false;
+ }
+
+ if (assign) {
w->theme_owner = p_owner;
w->theme_owner_window = p_owner_window;
}
- w->notification(Window::NOTIFICATION_THEME_CHANGED);
- w->emit_signal(SceneStringNames::get_singleton()->theme_changed);
+
+ if (p_notify) {
+ w->notification(Window::NOTIFICATION_THEME_CHANGED);
+ }
}
-}
-void Control::_theme_changed() {
- _propagate_theme_changed(this, this, nullptr, false);
+ for (int i = 0; i < p_at->get_child_count(); i++) {
+ _propagate_theme_changed(p_at->get_child(i), p_owner, p_owner_window, p_notify, assign);
+ }
}
-void Control::_theme_property_override_changed() {
- notification(NOTIFICATION_THEME_CHANGED);
- emit_signal(SceneStringNames::get_singleton()->theme_changed);
- update_minimum_size(); // Overrides are likely to affect minimum size.
+void Control::_theme_changed() {
+ if (is_inside_tree()) {
+ _propagate_theme_changed(this, this, nullptr, true, false);
+ }
}
-void Control::_notify_theme_changed() {
- if (!data.bulk_theme_override) {
+void Control::_notify_theme_override_changed() {
+ if (!data.bulk_theme_override && is_inside_tree()) {
notification(NOTIFICATION_THEME_CHANGED);
}
}
+void Control::_invalidate_theme_cache() {
+ data.theme_icon_cache.clear();
+ data.theme_style_cache.clear();
+ data.theme_font_cache.clear();
+ data.theme_font_size_cache.clear();
+ data.theme_color_cache.clear();
+ data.theme_constant_cache.clear();
+}
+
void Control::set_theme(const Ref<Theme> &p_theme) {
if (data.theme == p_theme) {
return;
@@ -2272,28 +2340,25 @@ void Control::set_theme(const Ref<Theme> &p_theme) {
}
data.theme = p_theme;
- if (!p_theme.is_null()) {
- data.theme_owner = this;
- data.theme_owner_window = nullptr;
- _propagate_theme_changed(this, this, nullptr);
- } else {
- Control *parent_c = Object::cast_to<Control>(get_parent());
+ if (data.theme.is_valid()) {
+ _propagate_theme_changed(this, this, nullptr, is_inside_tree(), true);
+ data.theme->connect("changed", callable_mp(this, &Control::_theme_changed), CONNECT_DEFERRED);
+ return;
+ }
- if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) {
- Control::_propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window);
- } else {
- Window *parent_w = cast_to<Window>(get_parent());
- if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) {
- Control::_propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window);
- } else {
- Control::_propagate_theme_changed(this, nullptr, nullptr);
- }
- }
+ Control *parent_c = Object::cast_to<Control>(get_parent());
+ if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) {
+ _propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window, is_inside_tree(), true);
+ return;
}
- if (data.theme.is_valid()) {
- data.theme->connect("changed", callable_mp(this, &Control::_theme_changed), CONNECT_DEFERRED);
+ Window *parent_w = cast_to<Window>(get_parent());
+ if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) {
+ _propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window, is_inside_tree(), true);
+ return;
}
+
+ _propagate_theme_changed(this, nullptr, nullptr, is_inside_tree(), true);
}
Ref<Theme> Control::get_theme() const {
@@ -2301,8 +2366,13 @@ Ref<Theme> Control::get_theme() const {
}
void Control::set_theme_type_variation(const StringName &p_theme_type) {
+ if (data.theme_type_variation == p_theme_type) {
+ return;
+ }
data.theme_type_variation = p_theme_type;
- _propagate_theme_changed(this, data.theme_owner, data.theme_owner_window);
+ if (is_inside_tree()) {
+ notification(NOTIFICATION_THEME_CHANGED);
+ }
}
StringName Control::get_theme_type_variation() const {
@@ -2350,22 +2420,22 @@ T Control::get_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner
}
// Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
for (const StringName &E : p_theme_types) {
- if (Theme::get_project_default()->has_theme_item(p_data_type, p_name, E)) {
- return Theme::get_project_default()->get_theme_item(p_data_type, p_name, E);
+ if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(p_data_type, p_name, E)) {
+ return ThemeDB::get_singleton()->get_project_theme()->get_theme_item(p_data_type, p_name, E);
}
}
}
// Lastly, fall back on the items defined in the default Theme, if they exist.
for (const StringName &E : p_theme_types) {
- if (Theme::get_default()->has_theme_item(p_data_type, p_name, E)) {
- return Theme::get_default()->get_theme_item(p_data_type, p_name, E);
+ if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(p_data_type, p_name, E)) {
+ return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(p_data_type, p_name, E);
}
}
// If they don't exist, use any type to return the default/empty value.
- return Theme::get_default()->get_theme_item(p_data_type, p_name, p_theme_types[0]);
+ return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(p_data_type, p_name, p_theme_types[0]);
}
bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) {
@@ -2406,9 +2476,9 @@ bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_ow
}
// Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
for (const StringName &E : p_theme_types) {
- if (Theme::get_project_default()->has_theme_item(p_data_type, p_name, E)) {
+ if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(p_data_type, p_name, E)) {
return true;
}
}
@@ -2416,7 +2486,7 @@ bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_ow
// Lastly, fall back on the items defined in the default Theme, if they exist.
for (const StringName &E : p_theme_types) {
- if (Theme::get_default()->has_theme_item(p_data_type, p_name, E)) {
+ if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(p_data_type, p_name, E)) {
return true;
}
}
@@ -2425,13 +2495,13 @@ bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_ow
void Control::_get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const {
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
- if (Theme::get_project_default().is_valid() && Theme::get_project_default()->get_type_variation_base(data.theme_type_variation) != StringName()) {
- Theme::get_project_default()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list);
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid() && ThemeDB::get_singleton()->get_project_theme()->get_type_variation_base(data.theme_type_variation) != StringName()) {
+ ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list);
} else {
- Theme::get_default()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list);
}
} else {
- Theme::get_default()->get_type_dependencies(p_theme_type, StringName(), p_list);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(p_theme_type, StringName(), p_list);
}
}
@@ -2443,9 +2513,15 @@ Ref<Texture2D> Control::get_theme_icon(const StringName &p_name, const StringNam
}
}
+ if (data.theme_icon_cache.has(p_theme_type) && data.theme_icon_cache[p_theme_type].has(p_name)) {
+ return data.theme_icon_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<Ref<Texture2D>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
+ Ref<Texture2D> icon = get_theme_item_in_types<Ref<Texture2D>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_ICON, p_name, theme_types);
+ data.theme_icon_cache[p_theme_type][p_name] = icon;
+ return icon;
}
Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2456,9 +2532,15 @@ Ref<StyleBox> Control::get_theme_stylebox(const StringName &p_name, const String
}
}
+ if (data.theme_style_cache.has(p_theme_type) && data.theme_style_cache[p_theme_type].has(p_name)) {
+ return data.theme_style_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<Ref<StyleBox>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
+ Ref<StyleBox> style = get_theme_item_in_types<Ref<StyleBox>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_STYLEBOX, p_name, theme_types);
+ data.theme_style_cache[p_theme_type][p_name] = style;
+ return style;
}
Ref<Font> Control::get_theme_font(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2469,9 +2551,15 @@ Ref<Font> Control::get_theme_font(const StringName &p_name, const StringName &p_
}
}
+ if (data.theme_font_cache.has(p_theme_type) && data.theme_font_cache[p_theme_type].has(p_name)) {
+ return data.theme_font_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<Ref<Font>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
+ Ref<Font> font = get_theme_item_in_types<Ref<Font>>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT, p_name, theme_types);
+ data.theme_font_cache[p_theme_type][p_name] = font;
+ return font;
}
int Control::get_theme_font_size(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2482,9 +2570,15 @@ int Control::get_theme_font_size(const StringName &p_name, const StringName &p_t
}
}
+ if (data.theme_font_size_cache.has(p_theme_type) && data.theme_font_size_cache[p_theme_type].has(p_name)) {
+ return data.theme_font_size_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
+ int font_size = get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_FONT_SIZE, p_name, theme_types);
+ data.theme_font_size_cache[p_theme_type][p_name] = font_size;
+ return font_size;
}
Color Control::get_theme_color(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2495,9 +2589,15 @@ Color Control::get_theme_color(const StringName &p_name, const StringName &p_the
}
}
+ if (data.theme_color_cache.has(p_theme_type) && data.theme_color_cache[p_theme_type].has(p_name)) {
+ return data.theme_color_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<Color>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
+ Color color = get_theme_item_in_types<Color>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_COLOR, p_name, theme_types);
+ data.theme_color_cache[p_theme_type][p_name] = color;
+ return color;
}
int Control::get_theme_constant(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2508,9 +2608,15 @@ int Control::get_theme_constant(const StringName &p_name, const StringName &p_th
}
}
+ if (data.theme_constant_cache.has(p_theme_type) && data.theme_constant_cache[p_theme_type].has(p_name)) {
+ return data.theme_constant_cache[p_theme_type][p_name];
+ }
+
List<StringName> theme_types;
_get_theme_type_dependencies(p_theme_type, &theme_types);
- return get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
+ int constant = get_theme_item_in_types<int>(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
+ data.theme_constant_cache[p_theme_type][p_name] = constant;
+ return constant;
}
bool Control::has_theme_icon(const StringName &p_name, const StringName &p_theme_type) const {
@@ -2591,93 +2697,93 @@ void Control::add_theme_icon_override(const StringName &p_name, const Ref<Textur
ERR_FAIL_COND(!p_icon.is_valid());
if (data.icon_override.has(p_name)) {
- data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.icon_override[p_name] = p_icon;
- data.icon_override[p_name]->connect("changed", callable_mp(this, &Control::_theme_property_override_changed), CONNECT_REFERENCE_COUNTED);
- _notify_theme_changed();
+ data.icon_override[p_name]->connect("changed", callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED);
+ _notify_theme_override_changed();
}
void Control::add_theme_style_override(const StringName &p_name, const Ref<StyleBox> &p_style) {
ERR_FAIL_COND(!p_style.is_valid());
if (data.style_override.has(p_name)) {
- data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.style_override[p_name] = p_style;
- data.style_override[p_name]->connect("changed", callable_mp(this, &Control::_theme_property_override_changed), CONNECT_REFERENCE_COUNTED);
- _notify_theme_changed();
+ data.style_override[p_name]->connect("changed", callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED);
+ _notify_theme_override_changed();
}
void Control::add_theme_font_override(const StringName &p_name, const Ref<Font> &p_font) {
ERR_FAIL_COND(!p_font.is_valid());
if (data.font_override.has(p_name)) {
- data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.font_override[p_name] = p_font;
- data.font_override[p_name]->connect("changed", callable_mp(this, &Control::_theme_property_override_changed), CONNECT_REFERENCE_COUNTED);
- _notify_theme_changed();
+ data.font_override[p_name]->connect("changed", callable_mp(this, &Control::_notify_theme_override_changed), CONNECT_REFERENCE_COUNTED);
+ _notify_theme_override_changed();
}
void Control::add_theme_font_size_override(const StringName &p_name, int p_font_size) {
data.font_size_override[p_name] = p_font_size;
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::add_theme_color_override(const StringName &p_name, const Color &p_color) {
data.color_override[p_name] = p_color;
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::add_theme_constant_override(const StringName &p_name, int p_constant) {
data.constant_override[p_name] = p_constant;
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::remove_theme_icon_override(const StringName &p_name) {
if (data.icon_override.has(p_name)) {
- data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.icon_override.erase(p_name);
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::remove_theme_style_override(const StringName &p_name) {
if (data.style_override.has(p_name)) {
- data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.style_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.style_override.erase(p_name);
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::remove_theme_font_override(const StringName &p_name) {
if (data.font_override.has(p_name)) {
- data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_theme_property_override_changed));
+ data.font_override[p_name]->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
}
data.font_override.erase(p_name);
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::remove_theme_font_size_override(const StringName &p_name) {
data.font_size_override.erase(p_name);
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::remove_theme_color_override(const StringName &p_name) {
data.color_override.erase(p_name);
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
void Control::remove_theme_constant_override(const StringName &p_name) {
data.constant_override.erase(p_name);
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
bool Control::has_theme_icon_override(const StringName &p_name) const {
@@ -2746,17 +2852,17 @@ float Control::fetch_theme_default_base_scale(Control *p_theme_owner, Window *p_
}
// Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_default_base_scale()) {
- return Theme::get_project_default()->get_default_base_scale();
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme()->has_default_base_scale()) {
+ return ThemeDB::get_singleton()->get_project_theme()->get_default_base_scale();
}
}
// Lastly, fall back on the default Theme.
- if (Theme::get_default()->has_default_base_scale()) {
- return Theme::get_default()->get_default_base_scale();
+ if (ThemeDB::get_singleton()->get_default_theme()->has_default_base_scale()) {
+ return ThemeDB::get_singleton()->get_default_theme()->get_default_base_scale();
}
- return Theme::get_fallback_base_scale();
+ return ThemeDB::get_singleton()->get_fallback_base_scale();
}
float Control::get_theme_default_base_scale() const {
@@ -2797,17 +2903,17 @@ Ref<Font> Control::fetch_theme_default_font(Control *p_theme_owner, Window *p_th
}
// Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_default_font()) {
- return Theme::get_project_default()->get_default_font();
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme()->has_default_font()) {
+ return ThemeDB::get_singleton()->get_project_theme()->get_default_font();
}
}
// Lastly, fall back on the default Theme.
- if (Theme::get_default()->has_default_font()) {
- return Theme::get_default()->get_default_font();
+ if (ThemeDB::get_singleton()->get_default_theme()->has_default_font()) {
+ return ThemeDB::get_singleton()->get_default_theme()->get_default_font();
}
- return Theme::get_fallback_font();
+ return ThemeDB::get_singleton()->get_fallback_font();
}
Ref<Font> Control::get_theme_default_font() const {
@@ -2848,17 +2954,17 @@ int Control::fetch_theme_default_font_size(Control *p_theme_owner, Window *p_the
}
// Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_default_font_size()) {
- return Theme::get_project_default()->get_default_font_size();
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme()->has_default_font_size()) {
+ return ThemeDB::get_singleton()->get_project_theme()->get_default_font_size();
}
}
// Lastly, fall back on the default Theme.
- if (Theme::get_default()->has_default_font_size()) {
- return Theme::get_default()->get_default_font_size();
+ if (ThemeDB::get_singleton()->get_default_theme()->has_default_font_size()) {
+ return ThemeDB::get_singleton()->get_default_theme()->get_default_font_size();
}
- return Theme::get_fallback_font_size();
+ return ThemeDB::get_singleton()->get_fallback_font_size();
}
int Control::get_theme_default_font_size() const {
@@ -2875,18 +2981,18 @@ void Control::end_bulk_theme_override() {
ERR_FAIL_COND(!data.bulk_theme_override);
data.bulk_theme_override = false;
- _notify_theme_changed();
+ _notify_theme_override_changed();
}
// Internationalization.
-Array Control::structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
+TypedArray<Vector2i> Control::structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
if (p_parser_type == TextServer::STRUCTURED_TEXT_CUSTOM) {
- Array ret;
+ TypedArray<Vector2i> ret;
if (GDVIRTUAL_CALL(_structured_text_parser, p_args, p_text, ret)) {
return ret;
} else {
- return Array();
+ return TypedArray<Vector2i>();
}
} else {
return TS->parse_structured_text(p_parser_type, p_args, p_text);
@@ -2894,6 +3000,9 @@ Array Control::structured_text_parser(TextServer::StructuredTextParser p_parser_
}
void Control::set_layout_direction(Control::LayoutDirection p_direction) {
+ if (data.layout_dir == p_direction) {
+ return;
+ }
ERR_FAIL_INDEX((int)p_direction, 4);
data.layout_dir = p_direction;
@@ -2954,12 +3063,12 @@ bool Control::is_auto_translating() const {
// Extra properties.
-void Control::set_tooltip(const String &p_tooltip) {
- data.tooltip = p_tooltip;
+void Control::set_tooltip_text(const String &p_hint) {
+ data.tooltip = p_hint;
update_configuration_warnings();
}
-String Control::_get_tooltip() const {
+String Control::get_tooltip_text() const {
return data.tooltip;
}
@@ -2978,35 +3087,28 @@ Control *Control::make_custom_tooltip(const String &p_text) const {
// Base object overrides.
void Control::add_child_notify(Node *p_child) {
- Control *child_c = Object::cast_to<Control>(p_child);
-
- if (child_c && child_c->data.theme.is_null() && (data.theme_owner || data.theme_owner_window)) {
- _propagate_theme_changed(child_c, data.theme_owner, data.theme_owner_window); //need to propagate here, since many controls may require setting up stuff
- }
-
- Window *child_w = Object::cast_to<Window>(p_child);
-
- if (child_w && child_w->theme.is_null() && (data.theme_owner || data.theme_owner_window)) {
- _propagate_theme_changed(child_w, data.theme_owner, data.theme_owner_window); //need to propagate here, since many controls may require setting up stuff
+ // We propagate when this node uses a custom theme, so it can pass it on to its children.
+ if (data.theme_owner || data.theme_owner_window) {
+ // `p_notify` is false here as `NOTIFICATION_THEME_CHANGED` will be handled by `NOTIFICATION_ENTER_TREE`.
+ _propagate_theme_changed(p_child, data.theme_owner, data.theme_owner_window, false, true);
}
}
void Control::remove_child_notify(Node *p_child) {
- Control *child_c = Object::cast_to<Control>(p_child);
-
- if (child_c && (child_c->data.theme_owner || child_c->data.theme_owner_window) && child_c->data.theme.is_null()) {
- _propagate_theme_changed(child_c, nullptr, nullptr);
- }
-
- Window *child_w = Object::cast_to<Window>(p_child);
-
- if (child_w && (child_w->theme_owner || child_w->theme_owner_window) && child_w->theme.is_null()) {
- _propagate_theme_changed(child_w, nullptr, nullptr);
+ // If the removed child isn't inheriting any theme items through this node, then there's no need to propagate.
+ if (data.theme_owner || data.theme_owner_window) {
+ _propagate_theme_changed(p_child, nullptr, nullptr, false, true);
}
}
void Control::_notification(int p_notification) {
switch (p_notification) {
+ case NOTIFICATION_ENTER_TREE: {
+ // Need to defer here, because theme owner information might be set in
+ // add_child_notify, which doesn't get called until right after this.
+ call_deferred(SNAME("notification"), NOTIFICATION_THEME_CHANGED);
+ } break;
+
case NOTIFICATION_POST_ENTER_TREE: {
data.minimum_size_valid = false;
data.is_rtl_dirty = true;
@@ -3029,18 +3131,6 @@ void Control::_notification(int p_notification) {
data.parent_window = Object::cast_to<Window>(get_parent());
data.is_rtl_dirty = true;
- if (data.theme.is_null()) {
- if (data.parent && (data.parent->data.theme_owner || data.parent->data.theme_owner_window)) {
- data.theme_owner = data.parent->data.theme_owner;
- data.theme_owner_window = data.parent->data.theme_owner_window;
- notification(NOTIFICATION_THEME_CHANGED);
- } else if (data.parent_window && (data.parent_window->theme_owner || data.parent_window->theme_owner_window)) {
- data.theme_owner = data.parent_window->theme_owner;
- data.theme_owner_window = data.parent_window->theme_owner_window;
- notification(NOTIFICATION_THEME_CHANGED);
- }
- }
-
CanvasItem *node = this;
bool has_parent_control = false;
@@ -3144,6 +3234,8 @@ void Control::_notification(int p_notification) {
} break;
case NOTIFICATION_THEME_CHANGED: {
+ emit_signal(SceneStringNames::get_singleton()->theme_changed);
+ _invalidate_theme_cache();
update_minimum_size();
update();
} break;
@@ -3164,6 +3256,7 @@ void Control::_notification(int p_notification) {
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
if (is_inside_tree()) {
data.is_rtl_dirty = true;
+ _invalidate_theme_cache();
_size_changed();
}
} break;
@@ -3291,9 +3384,9 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_v_grow_direction", "direction"), &Control::set_v_grow_direction);
ClassDB::bind_method(D_METHOD("get_v_grow_direction"), &Control::get_v_grow_direction);
- ClassDB::bind_method(D_METHOD("set_tooltip", "tooltip"), &Control::set_tooltip);
+ ClassDB::bind_method(D_METHOD("set_tooltip_text", "hint"), &Control::set_tooltip_text);
+ ClassDB::bind_method(D_METHOD("get_tooltip_text"), &Control::get_tooltip_text);
ClassDB::bind_method(D_METHOD("get_tooltip", "at_position"), &Control::get_tooltip, DEFVAL(Point2()));
- ClassDB::bind_method(D_METHOD("_get_tooltip"), &Control::_get_tooltip);
ClassDB::bind_method(D_METHOD("set_default_cursor_shape", "shape"), &Control::set_default_cursor_shape);
ClassDB::bind_method(D_METHOD("get_default_cursor_shape"), &Control::get_default_cursor_shape);
@@ -3340,7 +3433,7 @@ void Control::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_contents"), "set_clip_contents", "is_clipping_contents");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "custom_minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "set_custom_minimum_size", "get_custom_minimum_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_direction", PROPERTY_HINT_ENUM, "Inherited,Locale,Left-to-Right,Right-to-Left"), "set_layout_direction", "get_layout_direction");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_mode", PROPERTY_HINT_ENUM, "Position,Anchors,Container,Uncontrolled", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_mode", PROPERTY_HINT_ENUM, "Position,Anchors,Container,Uncontrolled", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode");
ADD_PROPERTY_DEFAULT("layout_mode", LayoutMode::LAYOUT_MODE_POSITION);
const String anchors_presets_options = "Custom:-1,PresetFullRect:15,"
@@ -3348,7 +3441,7 @@ void Control::_bind_methods() {
"PresetCenterLeft:4,PresetCenterTop:5,PresetCenterRight:6,PresetCenterBottom:7,PresetCenter:8,"
"PresetLeftWide:9,PresetTopWide:10,PresetRightWide:11,PresetBottomWide:12,PresetVCenterWide:13,PresetHCenterWide:14";
- ADD_PROPERTY(PropertyInfo(Variant::INT, "anchors_preset", PROPERTY_HINT_ENUM, anchors_presets_options, PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_anchors_layout_preset", "_get_anchors_layout_preset");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "anchors_preset", PROPERTY_HINT_ENUM, anchors_presets_options, PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_anchors_layout_preset", "_get_anchors_layout_preset");
ADD_PROPERTY_DEFAULT("anchors_preset", -1);
ADD_SUBGROUP_INDENT("Anchor Points", "anchor_", 1);
@@ -3383,8 +3476,8 @@ void Control::_bind_methods() {
ADD_GROUP("Auto Translate", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_translate"), "set_auto_translate", "is_auto_translating");
- ADD_GROUP("Hint", "hint_");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "hint_tooltip", PROPERTY_HINT_MULTILINE_TEXT), "set_tooltip", "_get_tooltip");
+ ADD_GROUP("Tooltip", "tooltip_");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "tooltip_text", PROPERTY_HINT_MULTILINE_TEXT), "set_tooltip_text", "get_tooltip_text");
ADD_GROUP("Focus", "focus_");
ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbor_left", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbor", "get_focus_neighbor", SIDE_LEFT);
@@ -3507,3 +3600,24 @@ void Control::_bind_methods() {
GDVIRTUAL_BIND(_gui_input, "event");
}
+
+Control::~Control() {
+ // Resources need to be disconnected.
+ for (KeyValue<StringName, Ref<Texture2D>> &E : data.icon_override) {
+ E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
+ }
+ for (KeyValue<StringName, Ref<StyleBox>> &E : data.style_override) {
+ E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
+ }
+ for (KeyValue<StringName, Ref<Font>> &E : data.font_override) {
+ E.value->disconnect("changed", callable_mp(this, &Control::_notify_theme_override_changed));
+ }
+
+ // Then override maps can be simply cleared.
+ data.icon_override.clear();
+ data.style_override.clear();
+ data.font_override.clear();
+ data.font_size_override.clear();
+ data.color_override.clear();
+ data.constant_override.clear();
+}
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 9f17eccc3b..6215594ae0 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -170,6 +170,9 @@ private:
// Positioning and sizing.
+ LayoutMode stored_layout_mode = LayoutMode::LAYOUT_MODE_POSITION;
+ bool stored_use_custom_anchors = false;
+
real_t offset[4] = { 0.0, 0.0, 0.0, 0.0 };
real_t anchor[4] = { ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN };
FocusMode focus_mode = FOCUS_NONE;
@@ -229,6 +232,13 @@ private:
Theme::ThemeColorMap color_override;
Theme::ThemeConstantMap constant_override;
+ mutable HashMap<StringName, Theme::ThemeIconMap> theme_icon_cache;
+ mutable HashMap<StringName, Theme::ThemeStyleMap> theme_style_cache;
+ mutable HashMap<StringName, Theme::ThemeFontMap> theme_font_cache;
+ mutable HashMap<StringName, Theme::ThemeFontSizeMap> theme_font_size_cache;
+ mutable HashMap<StringName, Theme::ThemeColorMap> theme_color_cache;
+ mutable HashMap<StringName, Theme::ThemeConstantMap> theme_constant_cache;
+
// Internationalization.
LayoutDirection layout_dir = LAYOUT_DIRECTION_INHERITED;
@@ -268,6 +278,7 @@ private:
void _set_layout_mode(LayoutMode p_mode);
LayoutMode _get_layout_mode() const;
+ LayoutMode _get_default_layout_mode() const;
void _set_anchors_layout_preset(int p_preset);
int _get_anchors_layout_preset() const;
@@ -289,10 +300,10 @@ private:
// Theming.
void _theme_changed();
- void _theme_property_override_changed();
- void _notify_theme_changed();
+ void _notify_theme_override_changed();
+ void _invalidate_theme_cache();
- static void _propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_assign = true);
+ static void _propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_notify, bool p_assign);
template <class T>
static T get_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types);
@@ -301,7 +312,7 @@ private:
// Extra properties.
- String _get_tooltip() const;
+ String get_tooltip_text() const;
protected:
// Dynamic properties.
@@ -309,11 +320,14 @@ protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
+
+ bool _property_can_revert(const StringName &p_name) const;
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
// Internationalization.
- virtual Array structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
+ virtual TypedArray<Vector2i> structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
// Base object overrides.
@@ -326,7 +340,7 @@ protected:
// Exposed virtual methods.
GDVIRTUAL1RC(bool, _has_point, Vector2)
- GDVIRTUAL2RC(Array, _structured_text_parser, Array, String)
+ GDVIRTUAL2RC(TypedArray<Vector2i>, _structured_text_parser, Array, String)
GDVIRTUAL0RC(Vector2, _get_minimum_size)
GDVIRTUAL1RC(Variant, _get_drag_data, Vector2)
@@ -590,11 +604,12 @@ public:
// Extra properties.
- void set_tooltip(const String &p_tooltip);
+ void set_tooltip_text(const String &text);
virtual String get_tooltip(const Point2 &p_pos) const;
virtual Control *make_custom_tooltip(const String &p_text) const;
Control() {}
+ ~Control();
};
VARIANT_ENUM_CAST(Control::FocusMode);
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index 942b7d0bf9..b4e0747ab8 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -130,6 +130,9 @@ String AcceptDialog::get_text() const {
}
void AcceptDialog::set_text(String p_text) {
+ if (label->get_text() == p_text) {
+ return;
+ }
label->set_text(p_text);
child_controls_changed();
if (is_visible()) {
@@ -387,7 +390,7 @@ String ConfirmationDialog::get_cancel_button_text() const {
void ConfirmationDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_cancel_button"), &ConfirmationDialog::get_cancel_button);
- ClassDB::bind_method(D_METHOD("set_cancel_button_text"), &ConfirmationDialog::set_cancel_button_text);
+ ClassDB::bind_method(D_METHOD("set_cancel_button_text", "text"), &ConfirmationDialog::set_cancel_button_text);
ClassDB::bind_method(D_METHOD("get_cancel_button_text"), &ConfirmationDialog::get_cancel_button_text);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "cancel_button_text"), "set_cancel_button_text", "get_cancel_button_text");
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index e26976a402..2a56d6d222 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -163,7 +163,7 @@ Vector<String> FileDialog::get_selected_files() const {
TreeItem *item = tree->get_root();
while ((item = tree->get_next_selected(item))) {
- list.push_back(dir_access->get_current_dir().plus_file(item->get_text(0)));
+ list.push_back(dir_access->get_current_dir().path_join(item->get_text(0)));
};
return list;
@@ -192,7 +192,7 @@ void FileDialog::update_dir() {
}
void FileDialog::_dir_submitted(String p_dir) {
- _change_dir(root_prefix.plus_file(p_dir));
+ _change_dir(root_prefix.path_join(p_dir));
file->set_text("");
_push_history();
}
@@ -202,7 +202,7 @@ void FileDialog::_file_submitted(const String &p_file) {
}
void FileDialog::_save_confirm_pressed() {
- String f = dir_access->get_current_dir().plus_file(file->get_text());
+ String f = dir_access->get_current_dir().path_join(file->get_text());
emit_signal(SNAME("file_selected"), f);
hide();
}
@@ -252,7 +252,7 @@ void FileDialog::_action_pressed() {
Vector<String> files;
while (ti) {
- files.push_back(fbase.plus_file(ti->get_text(0)));
+ files.push_back(fbase.path_join(ti->get_text(0)));
ti = tree->get_next_selected(ti);
}
@@ -265,7 +265,7 @@ void FileDialog::_action_pressed() {
}
String file_text = file->get_text();
- String f = file_text.is_absolute_path() ? file_text : dir_access->get_current_dir().plus_file(file_text);
+ String f = file_text.is_absolute_path() ? file_text : dir_access->get_current_dir().path_join(file_text);
if ((mode == FILE_MODE_OPEN_ANY || mode == FILE_MODE_OPEN_FILE) && dir_access->file_exists(f)) {
emit_signal(SNAME("file_selected"), f);
@@ -278,7 +278,7 @@ void FileDialog::_action_pressed() {
if (item) {
Dictionary d = item->get_metadata(0);
if (d["dir"] && d["name"] != "..") {
- path = path.plus_file(d["name"]);
+ path = path.path_join(d["name"]);
}
}
@@ -598,7 +598,7 @@ void FileDialog::update_file_list() {
ti->set_text(0, files.front()->get());
if (get_icon_func) {
- Ref<Texture2D> icon = get_icon_func(base_dir.plus_file(files.front()->get()));
+ Ref<Texture2D> icon = get_icon_func(base_dir.path_join(files.front()->get()));
ti->set_icon(0, icon);
} else {
ti->set_icon(0, file_icon);
@@ -685,6 +685,9 @@ void FileDialog::add_filter(const String &p_filter, const String &p_description)
}
void FileDialog::set_filters(const Vector<String> &p_filters) {
+ if (filters == p_filters) {
+ return;
+ }
filters = p_filters;
update_filters();
invalidate();
@@ -703,15 +706,19 @@ String FileDialog::get_current_file() const {
}
String FileDialog::get_current_path() const {
- return dir->get_text().plus_file(file->get_text());
+ return dir->get_text().path_join(file->get_text());
}
void FileDialog::set_current_dir(const String &p_dir) {
_change_dir(p_dir);
+
_push_history();
}
void FileDialog::set_current_file(const String &p_file) {
+ if (file->get_text() == p_file) {
+ return;
+ }
file->set_text(p_file);
update_dir();
invalidate();
@@ -764,7 +771,9 @@ bool FileDialog::is_mode_overriding_title() const {
void FileDialog::set_file_mode(FileMode p_mode) {
ERR_FAIL_INDEX((int)p_mode, 5);
-
+ if (mode == p_mode) {
+ return;
+ }
mode = p_mode;
switch (mode) {
case FILE_MODE_OPEN_FILE:
@@ -977,6 +986,9 @@ void FileDialog::_bind_methods() {
}
void FileDialog::set_show_hidden_files(bool p_show) {
+ if (show_hidden_files == p_show) {
+ return;
+ }
show_hidden_files = p_show;
invalidate();
}
@@ -1003,13 +1015,13 @@ FileDialog::FileDialog() {
dir_prev = memnew(Button);
dir_prev->set_flat(true);
- dir_prev->set_tooltip(RTR("Go to previous folder."));
+ dir_prev->set_tooltip_text(RTR("Go to previous folder."));
dir_next = memnew(Button);
dir_next->set_flat(true);
- dir_next->set_tooltip(RTR("Go to next folder."));
+ dir_next->set_tooltip_text(RTR("Go to next folder."));
dir_up = memnew(Button);
dir_up->set_flat(true);
- dir_up->set_tooltip(RTR("Go to parent folder."));
+ dir_up->set_tooltip_text(RTR("Go to parent folder."));
hbc->add_child(dir_prev);
hbc->add_child(dir_next);
hbc->add_child(dir_up);
@@ -1033,7 +1045,7 @@ FileDialog::FileDialog() {
refresh = memnew(Button);
refresh->set_flat(true);
- refresh->set_tooltip(RTR("Refresh files."));
+ refresh->set_tooltip_text(RTR("Refresh files."));
refresh->connect("pressed", callable_mp(this, &FileDialog::update_file_list));
hbc->add_child(refresh);
@@ -1041,7 +1053,7 @@ FileDialog::FileDialog() {
show_hidden->set_flat(true);
show_hidden->set_toggle_mode(true);
show_hidden->set_pressed(is_showing_hidden_files());
- show_hidden->set_tooltip(RTR("Toggle the visibility of hidden files."));
+ show_hidden->set_tooltip_text(RTR("Toggle the visibility of hidden files."));
show_hidden->connect("toggled", callable_mp(this, &FileDialog::set_show_hidden_files));
hbc->add_child(show_hidden);
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 42f434f0ac..00f2e48601 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -607,13 +607,16 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_color = Object::cast_to<GraphNode>(to)->get_connection_input_color(E.to_port);
connecting_target = false;
connecting_to = pos;
- just_disconnected = true;
- emit_signal(SNAME("disconnection_request"), E.from, E.from_port, E.to, E.to_port);
- to = get_node(String(connecting_from)); //maybe it was erased
- if (Object::cast_to<GraphNode>(to)) {
- connecting = true;
- emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, false);
+ if (connecting_type >= 0) {
+ just_disconnected = true;
+
+ emit_signal(SNAME("disconnection_request"), E.from, E.from_port, E.to, E.to_port);
+ to = get_node(String(connecting_from)); //maybe it was erased
+ if (Object::cast_to<GraphNode>(to)) {
+ connecting = true;
+ emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, false);
+ }
}
return;
}
@@ -621,7 +624,6 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
}
}
- connecting = true;
connecting_from = gn->get_name();
connecting_index = j;
connecting_out = true;
@@ -629,8 +631,11 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_color = gn->get_connection_output_color(j);
connecting_target = false;
connecting_to = pos;
- just_disconnected = false;
- emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, true);
+ if (connecting_type >= 0) {
+ connecting = true;
+ just_disconnected = false;
+ emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, true);
+ }
return;
}
}
@@ -657,11 +662,13 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_to = pos;
just_disconnected = true;
- emit_signal(SNAME("disconnection_request"), E.from, E.from_port, E.to, E.to_port);
- fr = get_node(String(connecting_from)); //maybe it was erased
- if (Object::cast_to<GraphNode>(fr)) {
- connecting = true;
- emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, true);
+ if (connecting_type >= 0) {
+ emit_signal(SNAME("disconnection_request"), E.from, E.from_port, E.to, E.to_port);
+ fr = get_node(String(connecting_from)); //maybe it was erased
+ if (Object::cast_to<GraphNode>(fr)) {
+ connecting = true;
+ emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, true);
+ }
}
return;
}
@@ -669,7 +676,6 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
}
}
- connecting = true;
connecting_from = gn->get_name();
connecting_index = j;
connecting_out = false;
@@ -677,8 +683,11 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_color = gn->get_connection_input_color(j);
connecting_target = false;
connecting_to = pos;
- just_disconnected = false;
- emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, false);
+ if (connecting_type >= 0) {
+ connecting = true;
+ just_disconnected = false;
+ emit_signal(SNAME("connection_drag_started"), connecting_from, connecting_index, false);
+ }
return;
}
}
@@ -1127,7 +1136,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
drag_accum += mm->get_relative();
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
- if (gn && gn->is_selected()) {
+ if (gn && gn->is_selected() && gn->is_draggable()) {
Vector2 pos = (gn->get_drag_from() * zoom + drag_accum) / zoom;
// Snapping can be toggled temporarily by holding down Ctrl.
@@ -1166,7 +1175,9 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
} else if (gn->is_selected() && !box_selection_mode_additive) {
emit_signal(SNAME("node_deselected"), gn);
}
- gn->set_selected(box_selection_mode_additive);
+ if (gn->is_selectable()) {
+ gn->set_selected(box_selection_mode_additive);
+ }
} else {
bool select = (previous_selected.find(gn) != nullptr);
if (gn->is_selected() && !select) {
@@ -1174,7 +1185,9 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
} else if (!gn->is_selected() && select) {
emit_signal(SNAME("node_selected"), gn);
}
- gn->set_selected(select);
+ if (gn->is_selectable()) {
+ gn->set_selected(select);
+ }
}
}
@@ -1193,7 +1206,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
continue;
}
- bool select = (previous_selected.find(gn) != nullptr);
+ bool select = (gn->is_selectable() && previous_selected.find(gn) != nullptr);
if (gn->is_selected() && !select) {
emit_signal(SNAME("node_deselected"), gn);
} else if (!gn->is_selected() && select) {
@@ -1285,7 +1298,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
GraphNode *o_gn = Object::cast_to<GraphNode>(get_child(i));
if (o_gn) {
if (o_gn == gn) {
- o_gn->set_selected(true);
+ o_gn->set_selected(o_gn->is_selectable());
} else {
if (o_gn->is_selected()) {
emit_signal(SNAME("node_deselected"), o_gn);
@@ -1296,7 +1309,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
}
}
- gn->set_selected(true);
+ gn->set_selected(gn->is_selectable());
for (int i = 0; i < get_child_count(); i++) {
GraphNode *o_gn = Object::cast_to<GraphNode>(get_child(i));
if (!o_gn) {
@@ -1591,10 +1604,10 @@ void GraphEdit::remove_valid_left_disconnect_type(int p_type) {
valid_left_disconnect_types.erase(p_type);
}
-Array GraphEdit::_get_connection_list() const {
+TypedArray<Dictionary> GraphEdit::_get_connection_list() const {
List<Connection> conns;
get_connection_list(&conns);
- Array arr;
+ TypedArray<Dictionary> arr;
for (const Connection &E : conns) {
Dictionary d;
d["from"] = E.from;
@@ -1640,6 +1653,9 @@ bool GraphEdit::is_valid_connection_type(int p_type, int p_with_type) const {
}
void GraphEdit::set_use_snap(bool p_enable) {
+ if (snap_button->is_pressed() == p_enable) {
+ return;
+ }
snap_button->set_pressed(p_enable);
update();
}
@@ -1683,6 +1699,9 @@ Vector2 GraphEdit::get_minimap_size() const {
}
void GraphEdit::set_minimap_opacity(float p_opacity) {
+ if (minimap->get_modulate().a == p_opacity) {
+ return;
+ }
minimap->set_modulate(Color(1, 1, 1, p_opacity));
minimap->update();
}
@@ -1693,6 +1712,9 @@ float GraphEdit::get_minimap_opacity() const {
}
void GraphEdit::set_minimap_enabled(bool p_enable) {
+ if (minimap_button->is_pressed() == p_enable) {
+ return;
+ }
minimap_button->set_pressed(p_enable);
_minimap_toggled();
minimap->update();
@@ -1702,6 +1724,19 @@ bool GraphEdit::is_minimap_enabled() const {
return minimap_button->is_pressed();
}
+void GraphEdit::set_arrange_nodes_button_hidden(bool p_enable) {
+ arrange_nodes_button_hidden = p_enable;
+ if (arrange_nodes_button_hidden) {
+ layout_button->hide();
+ } else {
+ layout_button->show();
+ }
+}
+
+bool GraphEdit::is_arrange_nodes_button_hidden() const {
+ return arrange_nodes_button_hidden;
+}
+
void GraphEdit::_minimap_toggled() {
if (is_minimap_enabled()) {
minimap->set_visible(true);
@@ -1721,6 +1756,9 @@ float GraphEdit::get_connection_lines_curvature() const {
}
void GraphEdit::set_connection_lines_thickness(float p_thickness) {
+ if (lines_thickness == p_thickness) {
+ return;
+ }
lines_thickness = p_thickness;
update();
}
@@ -1730,6 +1768,9 @@ float GraphEdit::get_connection_lines_thickness() const {
}
void GraphEdit::set_connection_lines_antialiased(bool p_antialiased) {
+ if (lines_antialiased == p_antialiased) {
+ return;
+ }
lines_antialiased = p_antialiased;
update();
}
@@ -1823,7 +1864,20 @@ HashMap<int, Vector<StringName>> GraphEdit::_layering(const HashSet<StringName>
}
if (!selected) {
current_layer++;
+ uint32_t previous_size_z = z.size();
_set_operations(GraphEdit::UNION, z, u);
+ if (z.size() == previous_size_z) {
+ WARN_PRINT("Graph contains cycle(s). The cycle(s) will not be rearranged accurately.");
+ Vector<StringName> t;
+ if (l.has(0)) {
+ t.append_array(l[0]);
+ }
+ for (const StringName &E : p) {
+ t.push_back(E);
+ }
+ l.insert(0, t);
+ break;
+ }
}
selected = false;
}
@@ -2138,7 +2192,7 @@ void GraphEdit::arrange_nodes() {
HashSet<StringName> s;
for (List<Connection>::Element *E = connections.front(); E; E = E->next()) {
GraphNode *p_from = Object::cast_to<GraphNode>(node_names[E->get().from]);
- if (E->get().to == gn->get_name() && p_from->is_selected()) {
+ if (E->get().to == gn->get_name() && p_from->is_selected() && E->get().to != E->get().from) {
if (!s.has(p_from->get_name())) {
s.insert(p_from->get_name());
}
@@ -2315,6 +2369,9 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_minimap_enabled", "enable"), &GraphEdit::set_minimap_enabled);
ClassDB::bind_method(D_METHOD("is_minimap_enabled"), &GraphEdit::is_minimap_enabled);
+ ClassDB::bind_method(D_METHOD("set_arrange_nodes_button_hidden", "enable"), &GraphEdit::set_arrange_nodes_button_hidden);
+ ClassDB::bind_method(D_METHOD("is_arrange_nodes_button_hidden"), &GraphEdit::is_arrange_nodes_button_hidden);
+
ClassDB::bind_method(D_METHOD("set_right_disconnects", "enable"), &GraphEdit::set_right_disconnects);
ClassDB::bind_method(D_METHOD("is_right_disconnects_enabled"), &GraphEdit::is_right_disconnects_enabled);
@@ -2354,6 +2411,9 @@ void GraphEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "minimap_size", PROPERTY_HINT_NONE, "suffix:px"), "set_minimap_size", "get_minimap_size");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "minimap_opacity"), "set_minimap_opacity", "get_minimap_opacity");
+ ADD_GROUP("UI", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "arrange_nodes_button_hidden"), "set_arrange_nodes_button_hidden", "is_arrange_nodes_button_hidden");
+
ADD_SIGNAL(MethodInfo("connection_request", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot")));
ADD_SIGNAL(MethodInfo("disconnection_request", PropertyInfo(Variant::STRING_NAME, "from"), PropertyInfo(Variant::INT, "from_slot"), PropertyInfo(Variant::STRING_NAME, "to"), PropertyInfo(Variant::INT, "to_slot")));
ADD_SIGNAL(MethodInfo("popup_request", PropertyInfo(Variant::VECTOR2, "position")));
@@ -2368,7 +2428,7 @@ void GraphEdit::_bind_methods() {
ADD_SIGNAL(MethodInfo("begin_node_move"));
ADD_SIGNAL(MethodInfo("end_node_move"));
ADD_SIGNAL(MethodInfo("scroll_offset_changed", PropertyInfo(Variant::VECTOR2, "offset")));
- ADD_SIGNAL(MethodInfo("connection_drag_started", PropertyInfo(Variant::STRING, "from"), PropertyInfo(Variant::STRING, "slot"), PropertyInfo(Variant::BOOL, "is_output")));
+ ADD_SIGNAL(MethodInfo("connection_drag_started", PropertyInfo(Variant::STRING, "from"), PropertyInfo(Variant::INT, "slot"), PropertyInfo(Variant::BOOL, "is_output")));
ADD_SIGNAL(MethodInfo("connection_drag_ended"));
BIND_ENUM_CONSTANT(SCROLL_ZOOMS);
@@ -2436,28 +2496,28 @@ GraphEdit::GraphEdit() {
zoom_minus = memnew(Button);
zoom_minus->set_flat(true);
zoom_hb->add_child(zoom_minus);
- zoom_minus->set_tooltip(RTR("Zoom Out"));
+ zoom_minus->set_tooltip_text(RTR("Zoom Out"));
zoom_minus->connect("pressed", callable_mp(this, &GraphEdit::_zoom_minus));
zoom_minus->set_focus_mode(FOCUS_NONE);
zoom_reset = memnew(Button);
zoom_reset->set_flat(true);
zoom_hb->add_child(zoom_reset);
- zoom_reset->set_tooltip(RTR("Zoom Reset"));
+ zoom_reset->set_tooltip_text(RTR("Zoom Reset"));
zoom_reset->connect("pressed", callable_mp(this, &GraphEdit::_zoom_reset));
zoom_reset->set_focus_mode(FOCUS_NONE);
zoom_plus = memnew(Button);
zoom_plus->set_flat(true);
zoom_hb->add_child(zoom_plus);
- zoom_plus->set_tooltip(RTR("Zoom In"));
+ zoom_plus->set_tooltip_text(RTR("Zoom In"));
zoom_plus->connect("pressed", callable_mp(this, &GraphEdit::_zoom_plus));
zoom_plus->set_focus_mode(FOCUS_NONE);
snap_button = memnew(Button);
snap_button->set_flat(true);
snap_button->set_toggle_mode(true);
- snap_button->set_tooltip(RTR("Enable snap and show grid."));
+ snap_button->set_tooltip_text(RTR("Enable snap and show grid."));
snap_button->connect("pressed", callable_mp(this, &GraphEdit::_snap_toggled));
snap_button->set_pressed(true);
snap_button->set_focus_mode(FOCUS_NONE);
@@ -2474,7 +2534,7 @@ GraphEdit::GraphEdit() {
minimap_button = memnew(Button);
minimap_button->set_flat(true);
minimap_button->set_toggle_mode(true);
- minimap_button->set_tooltip(RTR("Enable grid minimap."));
+ minimap_button->set_tooltip_text(RTR("Enable grid minimap."));
minimap_button->connect("pressed", callable_mp(this, &GraphEdit::_minimap_toggled));
minimap_button->set_pressed(true);
minimap_button->set_focus_mode(FOCUS_NONE);
@@ -2483,7 +2543,7 @@ GraphEdit::GraphEdit() {
layout_button = memnew(Button);
layout_button->set_flat(true);
zoom_hb->add_child(layout_button);
- layout_button->set_tooltip(RTR("Arrange nodes."));
+ layout_button->set_tooltip_text(RTR("Arrange nodes."));
layout_button->connect("pressed", callable_mp(this, &GraphEdit::arrange_nodes));
layout_button->set_focus_mode(FOCUS_NONE);
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index cf35aeb8b2..0a0676699f 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -133,6 +133,8 @@ private:
void _pan_callback(Vector2 p_scroll_vec);
void _zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt);
+ bool arrange_nodes_button_hidden = false;
+
bool connecting = false;
String connecting_from;
bool connecting_out = false;
@@ -206,7 +208,7 @@ private:
void _minimap_draw();
void _update_scroll_offset();
- Array _get_connection_list() const;
+ TypedArray<Dictionary> _get_connection_list() const;
bool lines_on_bg = false;
@@ -323,6 +325,9 @@ public:
void set_minimap_enabled(bool p_enable);
bool is_minimap_enabled() const;
+ void set_arrange_nodes_button_hidden(bool p_enable);
+ bool is_arrange_nodes_button_hidden() const;
+
GraphEditFilter *get_top_layer() const { return top_layer; }
GraphEditMinimap *get_minimap() const { return minimap; }
void get_connection_list(List<Connection> *r_connections) const;
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 92016ca42e..b07d401e6b 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -32,9 +32,7 @@
#include "core/string/translation.h"
-#ifdef TOOLS_ENABLED
#include "graph_edit.h"
-#endif
struct _MinSizeCache {
int min_size;
@@ -445,17 +443,16 @@ void GraphNode::_edit_set_position(const Point2 &p_position) {
}
set_position(p_position);
}
+#endif
-void GraphNode::_validate_property(PropertyInfo &property) const {
- Control::_validate_property(property);
+void GraphNode::_validate_property(PropertyInfo &p_property) const {
GraphEdit *graph = Object::cast_to<GraphEdit>(get_parent());
if (graph) {
- if (property.name == "rect_position") {
- property.usage |= PROPERTY_USAGE_READ_ONLY;
+ if (p_property.name == "position") {
+ p_property.usage |= PROPERTY_USAGE_READ_ONLY;
}
}
}
-#endif
void GraphNode::set_slot(int p_idx, bool p_enable_left, int p_type_left, const Color &p_color_left, bool p_enable_right, int p_type_right, const Color &p_color_right, const Ref<Texture2D> &p_custom_left, const Ref<Texture2D> &p_custom_right, bool p_draw_stylebox) {
ERR_FAIL_COND_MSG(p_idx < 0, vformat("Cannot set slot with p_idx (%d) lesser than zero.", p_idx));
@@ -506,6 +503,10 @@ bool GraphNode::is_slot_enabled_left(int p_idx) const {
void GraphNode::set_slot_enabled_left(int p_idx, bool p_enable_left) {
ERR_FAIL_COND_MSG(p_idx < 0, vformat("Cannot set enable_left for the slot with p_idx (%d) lesser than zero.", p_idx));
+ if (slot_info[p_idx].enable_left == p_enable_left) {
+ return;
+ }
+
slot_info[p_idx].enable_left = p_enable_left;
update();
connpos_dirty = true;
@@ -516,6 +517,10 @@ void GraphNode::set_slot_enabled_left(int p_idx, bool p_enable_left) {
void GraphNode::set_slot_type_left(int p_idx, int p_type_left) {
ERR_FAIL_COND_MSG(!slot_info.has(p_idx), vformat("Cannot set type_left for the slot '%d' because it hasn't been enabled.", p_idx));
+ if (slot_info[p_idx].type_left == p_type_left) {
+ return;
+ }
+
slot_info[p_idx].type_left = p_type_left;
update();
connpos_dirty = true;
@@ -533,6 +538,10 @@ int GraphNode::get_slot_type_left(int p_idx) const {
void GraphNode::set_slot_color_left(int p_idx, const Color &p_color_left) {
ERR_FAIL_COND_MSG(!slot_info.has(p_idx), vformat("Cannot set color_left for the slot '%d' because it hasn't been enabled.", p_idx));
+ if (slot_info[p_idx].color_left == p_color_left) {
+ return;
+ }
+
slot_info[p_idx].color_left = p_color_left;
update();
connpos_dirty = true;
@@ -557,6 +566,10 @@ bool GraphNode::is_slot_enabled_right(int p_idx) const {
void GraphNode::set_slot_enabled_right(int p_idx, bool p_enable_right) {
ERR_FAIL_COND_MSG(p_idx < 0, vformat("Cannot set enable_right for the slot with p_idx (%d) lesser than zero.", p_idx));
+ if (slot_info[p_idx].enable_right == p_enable_right) {
+ return;
+ }
+
slot_info[p_idx].enable_right = p_enable_right;
update();
connpos_dirty = true;
@@ -567,6 +580,10 @@ void GraphNode::set_slot_enabled_right(int p_idx, bool p_enable_right) {
void GraphNode::set_slot_type_right(int p_idx, int p_type_right) {
ERR_FAIL_COND_MSG(!slot_info.has(p_idx), vformat("Cannot set type_right for the slot '%d' because it hasn't been enabled.", p_idx));
+ if (slot_info[p_idx].type_right == p_type_right) {
+ return;
+ }
+
slot_info[p_idx].type_right = p_type_right;
update();
connpos_dirty = true;
@@ -584,6 +601,10 @@ int GraphNode::get_slot_type_right(int p_idx) const {
void GraphNode::set_slot_color_right(int p_idx, const Color &p_color_right) {
ERR_FAIL_COND_MSG(!slot_info.has(p_idx), vformat("Cannot set color_right for the slot '%d' because it hasn't been enabled.", p_idx));
+ if (slot_info[p_idx].color_right == p_color_right) {
+ return;
+ }
+
slot_info[p_idx].color_right = p_color_right;
update();
connpos_dirty = true;
@@ -701,6 +722,10 @@ String GraphNode::get_language() const {
}
void GraphNode::set_position_offset(const Vector2 &p_offset) {
+ if (position_offset == p_offset) {
+ return;
+ }
+
position_offset = p_offset;
emit_signal(SNAME("position_offset_changed"));
update();
@@ -711,6 +736,10 @@ Vector2 GraphNode::get_position_offset() const {
}
void GraphNode::set_selected(bool p_selected) {
+ if (selected == p_selected) {
+ return;
+ }
+
selected = p_selected;
update();
}
@@ -732,6 +761,10 @@ Vector2 GraphNode::get_drag_from() {
}
void GraphNode::set_show_close_button(bool p_enable) {
+ if (show_close == p_enable) {
+ return;
+ }
+
show_close = p_enable;
update();
}
@@ -932,6 +965,10 @@ void GraphNode::gui_input(const Ref<InputEvent> &p_ev) {
}
void GraphNode::set_overlay(Overlay p_overlay) {
+ if (overlay == p_overlay) {
+ return;
+ }
+
overlay = p_overlay;
update();
}
@@ -941,6 +978,10 @@ GraphNode::Overlay GraphNode::get_overlay() const {
}
void GraphNode::set_comment(bool p_enable) {
+ if (comment == p_enable) {
+ return;
+ }
+
comment = p_enable;
update();
}
@@ -950,6 +991,10 @@ bool GraphNode::is_comment() const {
}
void GraphNode::set_resizable(bool p_enable) {
+ if (resizable == p_enable) {
+ return;
+ }
+
resizable = p_enable;
update();
}
@@ -958,6 +1003,22 @@ bool GraphNode::is_resizable() const {
return resizable;
}
+void GraphNode::set_draggable(bool p_draggable) {
+ draggable = p_draggable;
+}
+
+bool GraphNode::is_draggable() {
+ return draggable;
+}
+
+void GraphNode::set_selectable(bool p_selectable) {
+ selectable = p_selectable;
+}
+
+bool GraphNode::is_selectable() {
+ return selectable;
+}
+
Vector<int> GraphNode::get_allowed_size_flags_horizontal() const {
Vector<int> flags;
flags.append(SIZE_FILL);
@@ -1019,6 +1080,12 @@ void GraphNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_resizable", "resizable"), &GraphNode::set_resizable);
ClassDB::bind_method(D_METHOD("is_resizable"), &GraphNode::is_resizable);
+ ClassDB::bind_method(D_METHOD("set_draggable", "draggable"), &GraphNode::set_draggable);
+ ClassDB::bind_method(D_METHOD("is_draggable"), &GraphNode::is_draggable);
+
+ ClassDB::bind_method(D_METHOD("set_selectable", "selectable"), &GraphNode::set_selectable);
+ ClassDB::bind_method(D_METHOD("is_selectable"), &GraphNode::is_selectable);
+
ClassDB::bind_method(D_METHOD("set_selected", "selected"), &GraphNode::set_selected);
ClassDB::bind_method(D_METHOD("is_selected"), &GraphNode::is_selected);
@@ -1044,6 +1111,8 @@ void GraphNode::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_position_offset", "get_position_offset");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_close"), "set_show_close_button", "is_close_button_visible");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "resizable"), "set_resizable", "is_resizable");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draggable"), "set_draggable", "is_draggable");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selectable"), "set_selectable", "is_selectable");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selected"), "set_selected", "is_selected");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "comment"), "set_comment", "is_comment");
ADD_PROPERTY(PropertyInfo(Variant::INT, "overlay", PROPERTY_HINT_ENUM, "Disabled,Breakpoint,Position"), "set_overlay", "get_overlay");
@@ -1051,6 +1120,7 @@ void GraphNode::_bind_methods() {
ADD_GROUP("BiDi", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language");
+ ADD_GROUP("", "");
ADD_SIGNAL(MethodInfo("position_offset_changed"));
ADD_SIGNAL(MethodInfo("slot_updated", PropertyInfo(Variant::INT, "idx")));
diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h
index 0651eb5cc9..9c8f926403 100644
--- a/scene/gui/graph_node.h
+++ b/scene/gui/graph_node.h
@@ -67,6 +67,8 @@ private:
Vector2 position_offset;
bool comment = false;
bool resizable = false;
+ bool draggable = true;
+ bool selectable = true;
bool resizing = false;
Vector2 resizing_from;
@@ -101,7 +103,6 @@ private:
#ifdef TOOLS_ENABLED
void _edit_set_position(const Point2 &p_position) override;
- void _validate_property(PropertyInfo &property) const override;
#endif
protected:
@@ -112,6 +113,7 @@ protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ void _validate_property(PropertyInfo &p_property) const;
public:
bool has_point(const Point2 &p_point) const override;
@@ -183,6 +185,12 @@ public:
void set_resizable(bool p_enable);
bool is_resizable() const;
+ void set_draggable(bool p_draggable);
+ bool is_draggable();
+
+ void set_selectable(bool p_selectable);
+ bool is_selectable();
+
virtual Size2 get_minimum_size() const override;
virtual Vector<int> get_allowed_size_flags_horizontal() const override;
diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp
index eaa6943ad2..3163d17846 100644
--- a/scene/gui/grid_container.cpp
+++ b/scene/gui/grid_container.cpp
@@ -246,6 +246,11 @@ void GridContainer::_notification(int p_what) {
void GridContainer::set_columns(int p_columns) {
ERR_FAIL_COND(p_columns < 1);
+
+ if (columns == p_columns) {
+ return;
+ }
+
columns = p_columns;
queue_sort();
update_minimum_size();
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index d0a25972f8..086f729603 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -88,6 +88,10 @@ void ItemList::set_item_text(int p_idx, const String &p_text) {
}
ERR_FAIL_INDEX(p_idx, items.size());
+ if (items[p_idx].text == p_text) {
+ return;
+ }
+
items.write[p_idx].text = p_text;
_shape(p_idx);
update();
@@ -153,6 +157,10 @@ void ItemList::set_item_tooltip(int p_idx, const String &p_tooltip) {
}
ERR_FAIL_INDEX(p_idx, items.size());
+ if (items[p_idx].tooltip == p_tooltip) {
+ return;
+ }
+
items.write[p_idx].tooltip = p_tooltip;
update();
shape_changed = true;
@@ -169,6 +177,10 @@ void ItemList::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) {
}
ERR_FAIL_INDEX(p_idx, items.size());
+ if (items[p_idx].icon == p_icon) {
+ return;
+ }
+
items.write[p_idx].icon = p_icon;
update();
shape_changed = true;
@@ -186,6 +198,10 @@ void ItemList::set_item_icon_transposed(int p_idx, const bool p_transposed) {
}
ERR_FAIL_INDEX(p_idx, items.size());
+ if (items[p_idx].icon_transposed == p_transposed) {
+ return;
+ }
+
items.write[p_idx].icon_transposed = p_transposed;
update();
shape_changed = true;
@@ -203,6 +219,10 @@ void ItemList::set_item_icon_region(int p_idx, const Rect2 &p_region) {
}
ERR_FAIL_INDEX(p_idx, items.size());
+ if (items[p_idx].icon_region == p_region) {
+ return;
+ }
+
items.write[p_idx].icon_region = p_region;
update();
shape_changed = true;
@@ -220,6 +240,10 @@ void ItemList::set_item_icon_modulate(int p_idx, const Color &p_modulate) {
}
ERR_FAIL_INDEX(p_idx, items.size());
+ if (items[p_idx].icon_modulate == p_modulate) {
+ return;
+ }
+
items.write[p_idx].icon_modulate = p_modulate;
update();
}
@@ -236,6 +260,10 @@ void ItemList::set_item_custom_bg_color(int p_idx, const Color &p_custom_bg_colo
}
ERR_FAIL_INDEX(p_idx, items.size());
+ if (items[p_idx].custom_bg == p_custom_bg_color) {
+ return;
+ }
+
items.write[p_idx].custom_bg = p_custom_bg_color;
update();
}
@@ -252,6 +280,10 @@ void ItemList::set_item_custom_fg_color(int p_idx, const Color &p_custom_fg_colo
}
ERR_FAIL_INDEX(p_idx, items.size());
+ if (items[p_idx].custom_fg == p_custom_fg_color) {
+ return;
+ }
+
items.write[p_idx].custom_fg = p_custom_fg_color;
update();
}
@@ -268,6 +300,10 @@ void ItemList::set_item_tag_icon(int p_idx, const Ref<Texture2D> &p_tag_icon) {
}
ERR_FAIL_INDEX(p_idx, items.size());
+ if (items[p_idx].tag_icon == p_tag_icon) {
+ return;
+ }
+
items.write[p_idx].tag_icon = p_tag_icon;
update();
shape_changed = true;
@@ -299,6 +335,10 @@ void ItemList::set_item_disabled(int p_idx, bool p_disabled) {
}
ERR_FAIL_INDEX(p_idx, items.size());
+ if (items[p_idx].disabled == p_disabled) {
+ return;
+ }
+
items.write[p_idx].disabled = p_disabled;
update();
}
@@ -314,6 +354,10 @@ void ItemList::set_item_metadata(int p_idx, const Variant &p_metadata) {
}
ERR_FAIL_INDEX(p_idx, items.size());
+ if (items[p_idx].metadata == p_metadata) {
+ return;
+ }
+
items.write[p_idx].metadata = p_metadata;
update();
shape_changed = true;
@@ -379,6 +423,10 @@ bool ItemList::is_selected(int p_idx) const {
void ItemList::set_current(int p_current) {
ERR_FAIL_INDEX(p_current, items.size());
+ if (current == p_current) {
+ return;
+ }
+
if (select_mode == SELECT_SINGLE) {
select(p_current, true);
} else {
@@ -410,6 +458,11 @@ void ItemList::move_item(int p_from_idx, int p_to_idx) {
void ItemList::set_item_count(int p_count) {
ERR_FAIL_COND(p_count < 0);
+
+ if (items.size() == p_count) {
+ return;
+ }
+
items.resize(p_count);
update();
shape_changed = true;
@@ -445,6 +498,11 @@ void ItemList::clear() {
void ItemList::set_fixed_column_width(int p_size) {
ERR_FAIL_COND(p_size < 0);
+
+ if (fixed_column_width == p_size) {
+ return;
+ }
+
fixed_column_width = p_size;
update();
shape_changed = true;
@@ -455,6 +513,10 @@ int ItemList::get_fixed_column_width() const {
}
void ItemList::set_same_column_width(bool p_enable) {
+ if (same_column_width == p_enable) {
+ return;
+ }
+
same_column_width = p_enable;
update();
shape_changed = true;
@@ -487,6 +549,11 @@ int ItemList::get_max_text_lines() const {
void ItemList::set_max_columns(int p_amount) {
ERR_FAIL_COND(p_amount < 0);
+
+ if (max_columns == p_amount) {
+ return;
+ }
+
max_columns = p_amount;
update();
shape_changed = true;
@@ -497,6 +564,10 @@ int ItemList::get_max_columns() const {
}
void ItemList::set_select_mode(SelectMode p_mode) {
+ if (select_mode == p_mode) {
+ return;
+ }
+
select_mode = p_mode;
update();
}
@@ -526,6 +597,10 @@ ItemList::IconMode ItemList::get_icon_mode() const {
}
void ItemList::set_fixed_icon_size(const Size2 &p_size) {
+ if (fixed_icon_size == p_size) {
+ return;
+ }
+
fixed_icon_size = p_size;
update();
}
@@ -932,11 +1007,7 @@ void ItemList::_notification(int p_what) {
scroll_bar->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -bg->get_margin(SIDE_BOTTOM));
Size2 size = get_size();
-
int width = size.width - bg->get_minimum_size().width;
- if (scroll_bar->is_visible()) {
- width -= mw;
- }
draw_style_box(bg, Rect2(Point2(), size));
@@ -1095,6 +1166,10 @@ void ItemList::_notification(int p_what) {
shape_changed = false;
}
+ if (scroll_bar->is_visible()) {
+ width -= mw;
+ }
+
//ensure_selected_visible needs to be checked before we draw the list.
if (ensure_selected_visible && current >= 0 && current < items.size()) {
Rect2 r = items[current].rect_cache;
@@ -1512,6 +1587,10 @@ void ItemList::set_autoscroll_to_bottom(const bool p_enable) {
}
void ItemList::set_auto_height(bool p_enable) {
+ if (auto_height == p_enable) {
+ return;
+ }
+
auto_height = p_enable;
shape_changed = true;
update();
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index e7f48beb00..fa7d4195cb 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -38,10 +38,12 @@
#include "servers/text_server.h"
void Label::set_autowrap_mode(TextServer::AutowrapMode p_mode) {
- if (autowrap_mode != p_mode) {
- autowrap_mode = p_mode;
- lines_dirty = true;
+ if (autowrap_mode == p_mode) {
+ return;
}
+
+ autowrap_mode = p_mode;
+ lines_dirty = true;
update();
if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
@@ -54,6 +56,10 @@ TextServer::AutowrapMode Label::get_autowrap_mode() const {
}
void Label::set_uppercase(bool p_uppercase) {
+ if (uppercase == p_uppercase) {
+ return;
+ }
+
uppercase = p_uppercase;
dirty = true;
@@ -273,8 +279,8 @@ void Label::_notification(int p_what) {
return; // Nothing new.
}
xl_text = new_text;
- if (percent_visible < 1) {
- visible_chars = get_total_character_count() * percent_visible;
+ if (visible_ratio < 1) {
+ visible_chars = get_total_character_count() * visible_ratio;
}
dirty = true;
@@ -342,7 +348,7 @@ void Label::_notification(int p_what) {
total_h += TS->shaped_text_get_size(lines_rid[i]).y + line_spacing;
total_glyphs += TS->shaped_text_get_glyph_count(lines_rid[i]) + TS->shaped_text_get_ellipsis_glyph_count(lines_rid[i]);
}
- int visible_glyphs = total_glyphs * percent_visible;
+ int visible_glyphs = total_glyphs * visible_ratio;
int processed_glyphs = 0;
total_h += style->get_margin(SIDE_TOP) + style->get_margin(SIDE_BOTTOM);
@@ -608,12 +614,15 @@ int Label::get_visible_line_count() const {
void Label::set_horizontal_alignment(HorizontalAlignment p_alignment) {
ERR_FAIL_INDEX((int)p_alignment, 4);
- if (horizontal_alignment != p_alignment) {
- if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL || p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
- lines_dirty = true; // Reshape lines.
- }
- horizontal_alignment = p_alignment;
+ if (horizontal_alignment == p_alignment) {
+ return;
}
+
+ if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL || p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ lines_dirty = true; // Reshape lines.
+ }
+ horizontal_alignment = p_alignment;
+
update();
}
@@ -623,6 +632,11 @@ HorizontalAlignment Label::get_horizontal_alignment() const {
void Label::set_vertical_alignment(VerticalAlignment p_alignment) {
ERR_FAIL_INDEX((int)p_alignment, 4);
+
+ if (vertical_alignment == p_alignment) {
+ return;
+ }
+
vertical_alignment = p_alignment;
update();
}
@@ -638,8 +652,8 @@ void Label::set_text(const String &p_string) {
text = p_string;
xl_text = atr(p_string);
dirty = true;
- if (percent_visible < 1) {
- visible_chars = get_total_character_count() * percent_visible;
+ if (visible_ratio < 1) {
+ visible_chars = get_total_character_count() * visible_ratio;
}
update();
update_minimum_size();
@@ -689,6 +703,10 @@ TextServer::StructuredTextParser Label::get_structured_text_bidi_override() cons
}
void Label::set_structured_text_bidi_override_options(Array p_args) {
+ if (st_args == p_args) {
+ return;
+ }
+
st_args = p_args;
dirty = true;
update();
@@ -715,6 +733,10 @@ String Label::get_language() const {
}
void Label::set_clip_text(bool p_clip) {
+ if (clip == p_clip) {
+ return;
+ }
+
clip = p_clip;
update();
update_minimum_size();
@@ -725,10 +747,12 @@ bool Label::is_clipping_text() const {
}
void Label::set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior) {
- if (overrun_behavior != p_behavior) {
- overrun_behavior = p_behavior;
- lines_dirty = true;
+ if (overrun_behavior == p_behavior) {
+ return;
}
+
+ overrun_behavior = p_behavior;
+ lines_dirty = true;
update();
if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
update_minimum_size();
@@ -747,9 +771,9 @@ void Label::set_visible_characters(int p_amount) {
if (visible_chars != p_amount) {
visible_chars = p_amount;
if (get_total_character_count() > 0) {
- percent_visible = (float)p_amount / (float)get_total_character_count();
+ visible_ratio = (float)p_amount / (float)get_total_character_count();
} else {
- percent_visible = 1.0;
+ visible_ratio = 1.0;
}
if (visible_chars_behavior == TextServer::VC_CHARS_BEFORE_SHAPING) {
dirty = true;
@@ -762,15 +786,19 @@ int Label::get_visible_characters() const {
return visible_chars;
}
-void Label::set_percent_visible(float p_percent) {
- if (percent_visible != p_percent) {
- if (p_percent < 0 || p_percent >= 1) {
+void Label::set_visible_ratio(float p_ratio) {
+ if (visible_ratio != p_ratio) {
+ if (visible_ratio >= 1.0) {
visible_chars = -1;
- percent_visible = 1;
+ visible_ratio = 1.0;
+ } else if (visible_ratio < 0.0) {
+ visible_chars = 0;
+ visible_ratio = 0.0;
} else {
- visible_chars = get_total_character_count() * p_percent;
- percent_visible = p_percent;
+ visible_chars = get_total_character_count() * p_ratio;
+ visible_ratio = p_ratio;
}
+
if (visible_chars_behavior == TextServer::VC_CHARS_BEFORE_SHAPING) {
dirty = true;
}
@@ -778,8 +806,8 @@ void Label::set_percent_visible(float p_percent) {
}
}
-float Label::get_percent_visible() const {
- return percent_visible;
+float Label::get_visible_ratio() const {
+ return visible_ratio;
}
TextServer::VisibleCharactersBehavior Label::get_visible_characters_behavior() const {
@@ -796,6 +824,11 @@ void Label::set_visible_characters_behavior(TextServer::VisibleCharactersBehavio
void Label::set_lines_skipped(int p_lines) {
ERR_FAIL_COND(p_lines < 0);
+
+ if (lines_skipped == p_lines) {
+ return;
+ }
+
lines_skipped = p_lines;
_update_visible();
update();
@@ -806,6 +839,10 @@ int Label::get_lines_skipped() const {
}
void Label::set_max_lines_visible(int p_lines) {
+ if (max_lines_visible == p_lines) {
+ return;
+ }
+
max_lines_visible = p_lines;
_update_visible();
update();
@@ -852,8 +889,8 @@ void Label::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_visible_characters"), &Label::get_visible_characters);
ClassDB::bind_method(D_METHOD("get_visible_characters_behavior"), &Label::get_visible_characters_behavior);
ClassDB::bind_method(D_METHOD("set_visible_characters_behavior", "behavior"), &Label::set_visible_characters_behavior);
- ClassDB::bind_method(D_METHOD("set_percent_visible", "percent_visible"), &Label::set_percent_visible);
- ClassDB::bind_method(D_METHOD("get_percent_visible"), &Label::get_percent_visible);
+ ClassDB::bind_method(D_METHOD("set_visible_ratio", "ratio"), &Label::set_visible_ratio);
+ ClassDB::bind_method(D_METHOD("get_visible_ratio"), &Label::get_visible_ratio);
ClassDB::bind_method(D_METHOD("set_lines_skipped", "lines_skipped"), &Label::set_lines_skipped);
ClassDB::bind_method(D_METHOD("get_lines_skipped"), &Label::get_lines_skipped);
ClassDB::bind_method(D_METHOD("set_max_lines_visible", "lines_visible"), &Label::set_max_lines_visible);
@@ -871,13 +908,14 @@ void Label::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "is_clipping_text");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_overrun_behavior", PROPERTY_HINT_ENUM, "Trim Nothing,Trim Characters,Trim Words,Ellipsis,Word Ellipsis"), "set_text_overrun_behavior", "get_text_overrun_behavior");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uppercase"), "set_uppercase", "is_uppercase");
+
+ ADD_GROUP("Displayed Text", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "lines_skipped", PROPERTY_HINT_RANGE, "0,999,1"), "set_lines_skipped", "get_lines_skipped");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_lines_visible", PROPERTY_HINT_RANGE, "-1,999,1"), "set_max_lines_visible", "get_max_lines_visible");
-
- // Note: "visible_characters" and "percent_visible" should be set after "text" to be correctly applied.
+ // Note: "visible_characters" and "visible_ratio" should be set after "text" to be correctly applied.
ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters", PROPERTY_HINT_RANGE, "-1,128000,1"), "set_visible_characters", "get_visible_characters");
ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters_behavior", PROPERTY_HINT_ENUM, "Characters Before Shaping,Characters After Shaping,Glyphs (Layout Direction),Glyphs (Left-to-Right),Glyphs (Right-to-Left)"), "set_visible_characters_behavior", "get_visible_characters_behavior");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "percent_visible", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_percent_visible", "get_percent_visible");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visible_ratio", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_visible_ratio", "get_visible_ratio");
ADD_GROUP("BiDi", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
diff --git a/scene/gui/label.h b/scene/gui/label.h
index cab5b36d68..65831cab6e 100644
--- a/scene/gui/label.h
+++ b/scene/gui/label.h
@@ -59,10 +59,9 @@ private:
TextServer::StructuredTextParser st_parser = TextServer::STRUCTURED_TEXT_DEFAULT;
Array st_args;
- float percent_visible = 1.0;
-
TextServer::VisibleCharactersBehavior visible_chars_behavior = TextServer::VC_CHARS_BEFORE_SHAPING;
int visible_chars = -1;
+ float visible_ratio = 1.0;
int lines_skipped = 0;
int max_lines_visible = -1;
@@ -110,22 +109,22 @@ public:
void set_uppercase(bool p_uppercase);
bool is_uppercase() const;
- TextServer::VisibleCharactersBehavior get_visible_characters_behavior() const;
void set_visible_characters_behavior(TextServer::VisibleCharactersBehavior p_behavior);
+ TextServer::VisibleCharactersBehavior get_visible_characters_behavior() const;
void set_visible_characters(int p_amount);
int get_visible_characters() const;
int get_total_character_count() const;
+ void set_visible_ratio(float p_ratio);
+ float get_visible_ratio() const;
+
void set_clip_text(bool p_clip);
bool is_clipping_text() const;
void set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior);
TextServer::OverrunBehavior get_text_overrun_behavior() const;
- void set_percent_visible(float p_percent);
- float get_percent_visible() const;
-
void set_lines_skipped(int p_lines);
int get_lines_skipped() const;
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 39f8f23cd8..34a60b907c 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -607,10 +607,12 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
void LineEdit::set_horizontal_alignment(HorizontalAlignment p_alignment) {
ERR_FAIL_INDEX((int)p_alignment, 4);
- if (alignment != p_alignment) {
- alignment = p_alignment;
- _shape();
+ if (alignment == p_alignment) {
+ return;
}
+
+ alignment = p_alignment;
+ _shape();
update();
}
@@ -716,7 +718,7 @@ void LineEdit::_notification(int p_what) {
case NOTIFICATION_RESIZED: {
_fit_to_width();
- scroll_offset = 0;
+ scroll_offset = 0.0;
set_caret_column(get_caret_column());
} break;
@@ -799,7 +801,7 @@ void LineEdit::_notification(int p_what) {
}
} break;
case HORIZONTAL_ALIGNMENT_CENTER: {
- if (scroll_offset != 0) {
+ if (!Math::is_zero_approx(scroll_offset)) {
x_ofs = style->get_offset().x;
} else {
x_ofs = MAX(style->get_margin(SIDE_LEFT), int(size.width - (text_width)) / 2);
@@ -844,7 +846,7 @@ void LineEdit::_notification(int p_what) {
r_icon->draw(ci, Point2(width - r_icon->get_width() - style->get_margin(SIDE_RIGHT), height / 2 - r_icon->get_height() / 2), color_icon);
if (alignment == HORIZONTAL_ALIGNMENT_CENTER) {
- if (scroll_offset == 0) {
+ if (Math::is_zero_approx(scroll_offset)) {
x_ofs = MAX(style->get_margin(SIDE_LEFT), int(size.width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2);
}
} else {
@@ -1206,7 +1208,7 @@ void LineEdit::set_caret_at_pixel_pos(int p_x) {
}
} break;
case HORIZONTAL_ALIGNMENT_CENTER: {
- if (scroll_offset != 0) {
+ if (!Math::is_zero_approx(scroll_offset)) {
x_ofs = style->get_offset().x;
} else {
x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - (text_width)) / 2);
@@ -1226,7 +1228,7 @@ void LineEdit::set_caret_at_pixel_pos(int p_x) {
if (right_icon.is_valid() || display_clear_icon) {
Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon;
if (alignment == HORIZONTAL_ALIGNMENT_CENTER) {
- if (scroll_offset == 0) {
+ if (Math::is_zero_approx(scroll_offset)) {
x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2);
}
} else {
@@ -1234,11 +1236,11 @@ void LineEdit::set_caret_at_pixel_pos(int p_x) {
}
}
- int ofs = TS->shaped_text_hit_test_position(text_rid, p_x - x_ofs - scroll_offset);
+ int ofs = ceil(TS->shaped_text_hit_test_position(text_rid, p_x - x_ofs - scroll_offset));
set_caret_column(ofs);
}
-Vector2i LineEdit::get_caret_pixel_pos() {
+Vector2 LineEdit::get_caret_pixel_pos() {
Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
bool rtl = is_layout_rtl();
@@ -1254,7 +1256,7 @@ Vector2i LineEdit::get_caret_pixel_pos() {
}
} break;
case HORIZONTAL_ALIGNMENT_CENTER: {
- if (scroll_offset != 0) {
+ if (!Math::is_zero_approx(scroll_offset)) {
x_ofs = style->get_offset().x;
} else {
x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - (text_width)) / 2);
@@ -1274,7 +1276,7 @@ Vector2i LineEdit::get_caret_pixel_pos() {
if (right_icon.is_valid() || display_clear_icon) {
Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon;
if (alignment == HORIZONTAL_ALIGNMENT_CENTER) {
- if (scroll_offset == 0) {
+ if (Math::is_zero_approx(scroll_offset)) {
x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2);
}
} else {
@@ -1282,7 +1284,7 @@ Vector2i LineEdit::get_caret_pixel_pos() {
}
}
- Vector2i ret;
+ Vector2 ret;
CaretInfo caret;
// Get position of the start of caret.
if (ime_text.length() != 0 && ime_selection.x != 0) {
@@ -1425,7 +1427,7 @@ void LineEdit::set_text(String p_text) {
update();
caret_column = 0;
- scroll_offset = 0;
+ scroll_offset = 0.0;
}
void LineEdit::set_text_direction(Control::TextDirection p_text_direction) {
@@ -1513,9 +1515,9 @@ void LineEdit::clear() {
void LineEdit::show_virtual_keyboard() {
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
if (selection.enabled) {
- DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, selection.begin, selection.end);
+ DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), DisplayServer::VirtualKeyboardType(virtual_keyboard_type), max_length, selection.begin, selection.end);
} else {
- DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, caret_column);
+ DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), DisplayServer::VirtualKeyboardType(virtual_keyboard_type), max_length, caret_column);
}
}
}
@@ -1525,6 +1527,10 @@ String LineEdit::get_text() const {
}
void LineEdit::set_placeholder(String p_text) {
+ if (placeholder == p_text) {
+ return;
+ }
+
placeholder = p_text;
placeholder_translated = atr(placeholder);
_shape();
@@ -1549,7 +1555,7 @@ void LineEdit::set_caret_column(int p_column) {
// Fit to window.
if (!is_inside_tree()) {
- scroll_offset = 0;
+ scroll_offset = 0.0;
return;
}
@@ -1568,7 +1574,7 @@ void LineEdit::set_caret_column(int p_column) {
}
} break;
case HORIZONTAL_ALIGNMENT_CENTER: {
- if (scroll_offset != 0) {
+ if (!Math::is_zero_approx(scroll_offset)) {
x_ofs = style->get_offset().x;
} else {
x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - (text_width)) / 2);
@@ -1589,7 +1595,7 @@ void LineEdit::set_caret_column(int p_column) {
if (right_icon.is_valid() || display_clear_icon) {
Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon(SNAME("clear")) : right_icon;
if (alignment == HORIZONTAL_ALIGNMENT_CENTER) {
- if (scroll_offset == 0) {
+ if (Math::is_zero_approx(scroll_offset)) {
x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2);
}
} else {
@@ -1599,12 +1605,12 @@ void LineEdit::set_caret_column(int p_column) {
}
// Note: Use two coordinates to fit IME input range.
- Vector2i primary_catret_offset = get_caret_pixel_pos();
+ Vector2 primary_caret_offset = get_caret_pixel_pos();
- if (MIN(primary_catret_offset.x, primary_catret_offset.y) <= x_ofs) {
- scroll_offset += (x_ofs - MIN(primary_catret_offset.x, primary_catret_offset.y));
- } else if (MAX(primary_catret_offset.x, primary_catret_offset.y) >= ofs_max) {
- scroll_offset += (ofs_max - MAX(primary_catret_offset.x, primary_catret_offset.y));
+ if (MIN(primary_caret_offset.x, primary_caret_offset.y) <= x_ofs) {
+ scroll_offset += x_ofs - MIN(primary_caret_offset.x, primary_caret_offset.y);
+ } else if (MAX(primary_caret_offset.x, primary_caret_offset.y) >= ofs_max) {
+ scroll_offset += ofs_max - MAX(primary_caret_offset.x, primary_caret_offset.y);
}
scroll_offset = MIN(0, scroll_offset);
@@ -1615,14 +1621,14 @@ int LineEdit::get_caret_column() const {
return caret_column;
}
-void LineEdit::set_scroll_offset(int p_pos) {
+void LineEdit::set_scroll_offset(float p_pos) {
scroll_offset = p_pos;
- if (scroll_offset < 0) {
- scroll_offset = 0;
+ if (scroll_offset < 0.0) {
+ scroll_offset = 0.0;
}
}
-int LineEdit::get_scroll_offset() const {
+float LineEdit::get_scroll_offset() const {
return scroll_offset;
}
@@ -1650,7 +1656,7 @@ void LineEdit::clear_internal() {
deselect();
_clear_undo_stack();
caret_column = 0;
- scroll_offset = 0;
+ scroll_offset = 0.0;
undo_text = "";
text = "";
_shape();
@@ -1781,10 +1787,12 @@ bool LineEdit::is_editable() const {
}
void LineEdit::set_secret(bool p_secret) {
- if (pass != p_secret) {
- pass = p_secret;
- _shape();
+ if (pass == p_secret) {
+ return;
}
+
+ pass = p_secret;
+ _shape();
update();
}
@@ -1797,10 +1805,12 @@ void LineEdit::set_secret_character(const String &p_string) {
// It also wouldn't make sense to use multiple characters as the secret character.
ERR_FAIL_COND_MSG(p_string.length() != 1, "Secret character must be exactly one character long (" + itos(p_string.length()) + " characters given).");
- if (secret_character != p_string) {
- secret_character = p_string;
- _shape();
+ if (secret_character == p_string) {
+ return;
}
+
+ secret_character = p_string;
+ _shape();
update();
}
@@ -2040,6 +2050,14 @@ bool LineEdit::is_virtual_keyboard_enabled() const {
return virtual_keyboard_enabled;
}
+void LineEdit::set_virtual_keyboard_type(VirtualKeyboardType p_type) {
+ virtual_keyboard_type = p_type;
+}
+
+LineEdit::VirtualKeyboardType LineEdit::get_virtual_keyboard_type() const {
+ return virtual_keyboard_type;
+}
+
void LineEdit::set_middle_mouse_paste_enabled(bool p_enabled) {
middle_mouse_paste_enabled = p_enabled;
}
@@ -2049,6 +2067,10 @@ bool LineEdit::is_middle_mouse_paste_enabled() const {
}
void LineEdit::set_selecting_enabled(bool p_enabled) {
+ if (selecting_enabled == p_enabled) {
+ return;
+ }
+
selecting_enabled = p_enabled;
if (!selecting_enabled) {
@@ -2061,6 +2083,10 @@ bool LineEdit::is_selecting_enabled() const {
}
void LineEdit::set_deselect_on_focus_loss_enabled(const bool p_enabled) {
+ if (deselect_on_focus_loss_enabled == p_enabled) {
+ return;
+ }
+
deselect_on_focus_loss_enabled = p_enabled;
if (p_enabled && selection.enabled && !has_focus()) {
deselect();
@@ -2216,9 +2242,9 @@ Key LineEdit::_get_menu_action_accelerator(const String &p_action) {
}
}
-void LineEdit::_validate_property(PropertyInfo &property) const {
- if (!caret_blink_enabled && property.name == "caret_blink_speed") {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void LineEdit::_validate_property(PropertyInfo &p_property) const {
+ if (!caret_blink_enabled && p_property.name == "caret_blink_speed") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
@@ -2280,6 +2306,8 @@ void LineEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_context_menu_enabled"), &LineEdit::is_context_menu_enabled);
ClassDB::bind_method(D_METHOD("set_virtual_keyboard_enabled", "enable"), &LineEdit::set_virtual_keyboard_enabled);
ClassDB::bind_method(D_METHOD("is_virtual_keyboard_enabled"), &LineEdit::is_virtual_keyboard_enabled);
+ ClassDB::bind_method(D_METHOD("set_virtual_keyboard_type", "type"), &LineEdit::set_virtual_keyboard_type);
+ ClassDB::bind_method(D_METHOD("get_virtual_keyboard_type"), &LineEdit::get_virtual_keyboard_type);
ClassDB::bind_method(D_METHOD("set_clear_button_enabled", "enable"), &LineEdit::set_clear_button_enabled);
ClassDB::bind_method(D_METHOD("is_clear_button_enabled"), &LineEdit::is_clear_button_enabled);
ClassDB::bind_method(D_METHOD("set_shortcut_keys_enabled", "enable"), &LineEdit::set_shortcut_keys_enabled);
@@ -2329,6 +2357,15 @@ void LineEdit::_bind_methods() {
BIND_ENUM_CONSTANT(MENU_INSERT_SHY);
BIND_ENUM_CONSTANT(MENU_MAX);
+ BIND_ENUM_CONSTANT(KEYBOARD_TYPE_DEFAULT);
+ BIND_ENUM_CONSTANT(KEYBOARD_TYPE_MULTILINE);
+ BIND_ENUM_CONSTANT(KEYBOARD_TYPE_NUMBER);
+ BIND_ENUM_CONSTANT(KEYBOARD_TYPE_NUMBER_DECIMAL);
+ BIND_ENUM_CONSTANT(KEYBOARD_TYPE_PHONE);
+ BIND_ENUM_CONSTANT(KEYBOARD_TYPE_EMAIL_ADDRESS);
+ BIND_ENUM_CONSTANT(KEYBOARD_TYPE_PASSWORD);
+ BIND_ENUM_CONSTANT(KEYBOARD_TYPE_URL);
+
ADD_PROPERTY(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "placeholder_text"), "set_placeholder", "get_placeholder");
ADD_PROPERTY(PropertyInfo(Variant::INT, "alignment", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_horizontal_alignment", "get_horizontal_alignment");
@@ -2339,6 +2376,7 @@ void LineEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_to_text_length"), "set_expand_to_text_length_enabled", "is_expand_to_text_length_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "virtual_keyboard_enabled"), "set_virtual_keyboard_enabled", "is_virtual_keyboard_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "virtual_keyboard_type", PROPERTY_HINT_ENUM, "Default,Multiline,Number,Decimal,Phone,Email,Password,URL"), "set_virtual_keyboard_type", "get_virtual_keyboard_type");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clear_button_enabled"), "set_clear_button_enabled", "is_clear_button_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled"), "set_shortcut_keys_enabled", "is_shortcut_keys_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "middle_mouse_paste_enabled"), "set_middle_mouse_paste_enabled", "is_middle_mouse_paste_enabled");
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index 6aa1694f1f..dabdaa3395 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -70,6 +70,17 @@ public:
MENU_MAX
};
+ enum VirtualKeyboardType {
+ KEYBOARD_TYPE_DEFAULT,
+ KEYBOARD_TYPE_MULTILINE,
+ KEYBOARD_TYPE_NUMBER,
+ KEYBOARD_TYPE_NUMBER_DECIMAL,
+ KEYBOARD_TYPE_PHONE,
+ KEYBOARD_TYPE_EMAIL_ADDRESS,
+ KEYBOARD_TYPE_PASSWORD,
+ KEYBOARD_TYPE_URL
+ };
+
private:
HorizontalAlignment alignment = HORIZONTAL_ALIGNMENT_LEFT;
@@ -84,7 +95,7 @@ private:
String text;
String placeholder;
String placeholder_translated;
- String secret_character = "*";
+ String secret_character = U"•";
String ime_text;
Point2 ime_selection;
@@ -102,7 +113,7 @@ private:
bool caret_mid_grapheme_enabled = true;
int caret_column = 0;
- int scroll_offset = 0;
+ float scroll_offset = 0.0;
int max_length = 0; // 0 for no maximum.
String language;
@@ -120,6 +131,7 @@ private:
bool shortcut_keys_enabled = true;
bool virtual_keyboard_enabled = true;
+ VirtualKeyboardType virtual_keyboard_type = KEYBOARD_TYPE_DEFAULT;
bool middle_mouse_paste_enabled = true;
@@ -141,8 +153,7 @@ private:
struct TextOperation {
int caret_column = 0;
- int scroll_offset = 0;
- int cached_width = 0;
+ float scroll_offset = 0.0;
String text;
};
List<TextOperation> undo_stack;
@@ -180,11 +191,11 @@ private:
void shift_selection_check_post(bool);
void selection_fill_at_caret();
- void set_scroll_offset(int p_pos);
- int get_scroll_offset() const;
+ void set_scroll_offset(float p_pos);
+ float get_scroll_offset() const;
void set_caret_at_pixel_pos(int p_x);
- Vector2i get_caret_pixel_pos();
+ Vector2 get_caret_pixel_pos();
void _reset_caret_blink_timer();
void _toggle_draw_caret();
@@ -209,7 +220,7 @@ protected:
virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
virtual void gui_input(const Ref<InputEvent> &p_event) override;
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_horizontal_alignment(HorizontalAlignment p_alignment);
@@ -311,6 +322,9 @@ public:
void set_virtual_keyboard_enabled(bool p_enable);
bool is_virtual_keyboard_enabled() const;
+ void set_virtual_keyboard_type(VirtualKeyboardType p_type);
+ VirtualKeyboardType get_virtual_keyboard_type() const;
+
void set_middle_mouse_paste_enabled(bool p_enabled);
bool is_middle_mouse_paste_enabled() const;
@@ -335,5 +349,6 @@ public:
};
VARIANT_ENUM_CAST(LineEdit::MenuItems);
+VARIANT_ENUM_CAST(LineEdit::VirtualKeyboardType);
#endif // LINE_EDIT_H
diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp
index 30c0bb3321..ee3f64e0e5 100644
--- a/scene/gui/link_button.cpp
+++ b/scene/gui/link_button.cpp
@@ -109,6 +109,10 @@ String LinkButton::get_language() const {
}
void LinkButton::set_underline_mode(UnderlineMode p_underline_mode) {
+ if (underline_mode == p_underline_mode) {
+ return;
+ }
+
underline_mode = p_underline_mode;
update();
}
diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp
new file mode 100644
index 0000000000..9b7b67d83e
--- /dev/null
+++ b/scene/gui/menu_bar.cpp
@@ -0,0 +1,874 @@
+/*************************************************************************/
+/* menu_bar.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "menu_bar.h"
+
+#include "core/os/keyboard.h"
+#include "scene/main/window.h"
+
+void MenuBar::gui_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+ if (is_native_menu()) {
+ // Handled by OS.
+ return;
+ }
+
+ MutexLock lock(mutex);
+ if (p_event->is_action("ui_left") && p_event->is_pressed()) {
+ int new_sel = selected_menu;
+ int old_sel = (selected_menu < 0) ? 0 : selected_menu;
+ do {
+ new_sel--;
+ if (new_sel < 0) {
+ new_sel = menu_cache.size() - 1;
+ }
+ if (old_sel == new_sel) {
+ return;
+ }
+ } while (menu_cache[new_sel].hidden || menu_cache[new_sel].disabled);
+
+ if (selected_menu != new_sel) {
+ selected_menu = new_sel;
+ focused_menu = selected_menu;
+ if (active_menu >= 0) {
+ get_menu_popup(active_menu)->hide();
+ }
+ _open_popup(selected_menu, true);
+ }
+ return;
+ } else if (p_event->is_action("ui_right") && p_event->is_pressed()) {
+ int new_sel = selected_menu;
+ int old_sel = (selected_menu < 0) ? menu_cache.size() - 1 : selected_menu;
+ do {
+ new_sel++;
+ if (new_sel >= menu_cache.size()) {
+ new_sel = 0;
+ }
+ if (old_sel == new_sel) {
+ return;
+ }
+ } while (menu_cache[new_sel].hidden || menu_cache[new_sel].disabled);
+
+ if (selected_menu != new_sel) {
+ selected_menu = new_sel;
+ focused_menu = selected_menu;
+ if (active_menu >= 0) {
+ get_menu_popup(active_menu)->hide();
+ }
+ _open_popup(selected_menu, true);
+ }
+ return;
+ }
+
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ int old_sel = selected_menu;
+ focused_menu = _get_index_at_point(mm->get_position());
+ if (focused_menu >= 0) {
+ selected_menu = focused_menu;
+ }
+ if (selected_menu != old_sel) {
+ update();
+ }
+ }
+
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid()) {
+ if (mb->is_pressed() && (mb->get_button_index() == MouseButton::LEFT || mb->get_button_index() == MouseButton::RIGHT)) {
+ int index = _get_index_at_point(mb->get_position());
+ if (index >= 0) {
+ _open_popup(index);
+ }
+ }
+ }
+}
+
+void MenuBar::_open_popup(int p_index, bool p_focus_item) {
+ ERR_FAIL_INDEX(p_index, menu_cache.size());
+
+ PopupMenu *pm = get_menu_popup(p_index);
+ if (pm->is_visible()) {
+ pm->hide();
+ return;
+ }
+
+ Rect2 item_rect = _get_menu_item_rect(p_index);
+ Point2 screen_pos = get_screen_position() + item_rect.position * get_viewport()->get_canvas_transform().get_scale();
+ Size2 screen_size = item_rect.size * get_viewport()->get_canvas_transform().get_scale();
+
+ active_menu = p_index;
+
+ pm->set_size(Size2(screen_size.x, 0));
+ screen_pos.y += screen_size.y;
+ if (is_layout_rtl()) {
+ screen_pos.x += screen_size.x - pm->get_size().width;
+ }
+ pm->set_position(screen_pos);
+ pm->set_parent_rect(Rect2(Point2(screen_pos - pm->get_position()), Size2(screen_size.x, screen_pos.y)));
+ pm->popup();
+
+ if (p_focus_item) {
+ for (int i = 0; i < pm->get_item_count(); i++) {
+ if (!pm->is_item_disabled(i)) {
+ pm->set_current_index(i);
+ break;
+ }
+ }
+ }
+
+ update();
+}
+
+void MenuBar::shortcut_input(const Ref<InputEvent> &p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
+ if (is_native_menu()) {
+ return;
+ }
+
+ if (!_is_focus_owner_in_shortcut_context()) {
+ return;
+ }
+
+ if (disable_shortcuts) {
+ return;
+ }
+
+ if (p_event->is_pressed() && !p_event->is_echo() && (Object::cast_to<InputEventKey>(p_event.ptr()) || Object::cast_to<InputEventJoypadButton>(p_event.ptr()) || Object::cast_to<InputEventAction>(*p_event) || Object::cast_to<InputEventShortcut>(*p_event))) {
+ if (!get_parent() || !is_visible_in_tree()) {
+ return;
+ }
+
+ Vector<PopupMenu *> popups = _get_popups();
+ for (int i = 0; i < popups.size(); i++) {
+ if (menu_cache[i].hidden || menu_cache[i].disabled) {
+ continue;
+ }
+ if (popups[i]->activate_item_by_event(p_event, false)) {
+ accept_event();
+ return;
+ }
+ }
+ }
+}
+
+void MenuBar::set_shortcut_context(Node *p_node) {
+ if (p_node != nullptr) {
+ shortcut_context = p_node->get_instance_id();
+ } else {
+ shortcut_context = ObjectID();
+ }
+}
+
+Node *MenuBar::get_shortcut_context() const {
+ Object *ctx_obj = ObjectDB::get_instance(shortcut_context);
+ Node *ctx_node = Object::cast_to<Node>(ctx_obj);
+
+ return ctx_node;
+}
+
+bool MenuBar::_is_focus_owner_in_shortcut_context() const {
+ if (shortcut_context == ObjectID()) {
+ // No context, therefore global - always "in" context.
+ return true;
+ }
+
+ Node *ctx_node = get_shortcut_context();
+ Control *vp_focus = get_viewport() ? get_viewport()->gui_get_focus_owner() : nullptr;
+
+ // If the context is valid and the viewport focus is valid, check if the context is the focus or is a parent of it.
+ return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_ancestor_of(vp_focus));
+}
+
+void MenuBar::_popup_visibility_changed(bool p_visible) {
+ if (!p_visible) {
+ active_menu = -1;
+ focused_menu = -1;
+ set_process_internal(false);
+ update();
+ return;
+ }
+
+ if (switch_on_hover) {
+ Window *window = Object::cast_to<Window>(get_viewport());
+ if (window) {
+ mouse_pos_adjusted = window->get_position();
+
+ if (window->is_embedded()) {
+ Window *window_parent = Object::cast_to<Window>(window->get_parent()->get_viewport());
+ while (window_parent) {
+ if (!window_parent->is_embedded()) {
+ mouse_pos_adjusted += window_parent->get_position();
+ break;
+ }
+
+ window_parent = Object::cast_to<Window>(window_parent->get_parent()->get_viewport());
+ }
+ }
+
+ set_process_internal(true);
+ }
+ }
+}
+
+void MenuBar::_update_submenu(const String &p_menu_name, PopupMenu *p_child) {
+ int count = p_child->get_item_count();
+ global_menus.insert(p_menu_name);
+ for (int i = 0; i < count; i++) {
+ if (p_child->is_item_separator(i)) {
+ DisplayServer::get_singleton()->global_menu_add_separator(p_menu_name);
+ } else if (!p_child->get_item_submenu(i).is_empty()) {
+ Node *n = p_child->get_node(p_child->get_item_submenu(i));
+ ERR_FAIL_COND_MSG(!n, "Item subnode does not exist: " + p_child->get_item_submenu(i) + ".");
+ PopupMenu *pm = Object::cast_to<PopupMenu>(n);
+ ERR_FAIL_COND_MSG(!pm, "Item subnode is not a PopupMenu: " + p_child->get_item_submenu(i) + ".");
+
+ DisplayServer::get_singleton()->global_menu_add_submenu_item(p_menu_name, p_child->get_item_text(i), p_menu_name + "/" + itos(i));
+ _update_submenu(p_menu_name + "/" + itos(i), pm);
+ } else {
+ int index = DisplayServer::get_singleton()->global_menu_add_item(p_menu_name, p_child->get_item_text(i), callable_mp(p_child, &PopupMenu::activate_item), i);
+
+ if (p_child->is_item_checkable(i)) {
+ DisplayServer::get_singleton()->global_menu_set_item_checkable(p_menu_name, index, true);
+ }
+ if (p_child->is_item_radio_checkable(i)) {
+ DisplayServer::get_singleton()->global_menu_set_item_radio_checkable(p_menu_name, index, true);
+ }
+ DisplayServer::get_singleton()->global_menu_set_item_checked(p_menu_name, index, p_child->is_item_checked(i));
+ DisplayServer::get_singleton()->global_menu_set_item_disabled(p_menu_name, index, p_child->is_item_disabled(i));
+ DisplayServer::get_singleton()->global_menu_set_item_max_states(p_menu_name, index, p_child->get_item_max_states(i));
+ DisplayServer::get_singleton()->global_menu_set_item_icon(p_menu_name, index, p_child->get_item_icon(i));
+ DisplayServer::get_singleton()->global_menu_set_item_state(p_menu_name, index, p_child->get_item_state(i));
+ DisplayServer::get_singleton()->global_menu_set_item_indentation_level(p_menu_name, index, p_child->get_item_indent(i));
+ DisplayServer::get_singleton()->global_menu_set_item_tooltip(p_menu_name, index, p_child->get_item_tooltip(i));
+ if (!p_child->is_item_shortcut_disabled(i) && p_child->get_item_shortcut(i).is_valid() && p_child->get_item_shortcut(i)->has_valid_event()) {
+ Array events = p_child->get_item_shortcut(i)->get_events();
+ for (int j = 0; j < events.size(); j++) {
+ Ref<InputEventKey> ie = events[j];
+ if (ie.is_valid()) {
+ DisplayServer::get_singleton()->global_menu_set_item_accelerator(p_menu_name, index, ie->get_keycode_with_modifiers());
+ break;
+ }
+ }
+ } else if (p_child->get_item_accelerator(i) != Key::NONE) {
+ DisplayServer::get_singleton()->global_menu_set_item_accelerator(p_menu_name, i, p_child->get_item_accelerator(i));
+ }
+ }
+ }
+}
+
+bool MenuBar::is_native_menu() const {
+ if (Engine::get_singleton()->is_editor_hint() && is_inside_tree() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()->is_ancestor_of(this) || get_tree()->get_edited_scene_root() == this)) {
+ return false;
+ }
+
+ return (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU) && is_native);
+}
+
+void MenuBar::_clear_menu() {
+ if (!DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU)) {
+ return;
+ }
+
+ // Remove root menu items.
+ int count = DisplayServer::get_singleton()->global_menu_get_item_count("_main");
+ for (int i = count - 1; i >= 0; i--) {
+ if (global_menus.has(DisplayServer::get_singleton()->global_menu_get_item_submenu("_main", i))) {
+ DisplayServer::get_singleton()->global_menu_remove_item("_main", i);
+ }
+ }
+ // Erase submenu contents.
+ for (const String &E : global_menus) {
+ DisplayServer::get_singleton()->global_menu_clear(E);
+ }
+ global_menus.clear();
+}
+
+void MenuBar::_update_menu() {
+ _clear_menu();
+
+ if (!is_visible_in_tree()) {
+ return;
+ }
+
+ int index = start_index;
+ if (is_native_menu()) {
+ Vector<PopupMenu *> popups = _get_popups();
+ String root_name = "MenuBar<" + String::num_int64((uint64_t)this, 16) + ">";
+ for (int i = 0; i < popups.size(); i++) {
+ if (menu_cache[i].hidden) {
+ continue;
+ }
+ String menu_name = String(popups[i]->get_meta("_menu_name", popups[i]->get_name()));
+
+ index = DisplayServer::get_singleton()->global_menu_add_submenu_item("_main", menu_name, root_name + "/" + itos(i), index);
+ if (menu_cache[i].disabled) {
+ DisplayServer::get_singleton()->global_menu_set_item_disabled("_main", index, true);
+ }
+ _update_submenu(root_name + "/" + itos(i), popups[i]);
+ index++;
+ }
+ }
+ update_minimum_size();
+ update();
+}
+
+void MenuBar::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ if (get_menu_count() > 0) {
+ _refresh_menu_names();
+ }
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ _clear_menu();
+ } break;
+ case NOTIFICATION_MOUSE_EXIT: {
+ focused_menu = -1;
+ update();
+ } break;
+ case NOTIFICATION_TRANSLATION_CHANGED:
+ case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
+ case NOTIFICATION_THEME_CHANGED: {
+ for (int i = 0; i < menu_cache.size(); i++) {
+ shape(menu_cache.write[i]);
+ }
+ _update_menu();
+ } break;
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ _update_menu();
+ } break;
+ case NOTIFICATION_DRAW: {
+ if (is_native_menu()) {
+ return;
+ }
+ for (int i = 0; i < menu_cache.size(); i++) {
+ _draw_menu_item(i);
+ }
+ } break;
+ case NOTIFICATION_INTERNAL_PROCESS: {
+ MutexLock lock(mutex);
+
+ Vector2 pos = DisplayServer::get_singleton()->mouse_get_position() - mouse_pos_adjusted - get_global_position();
+ int index = _get_index_at_point(pos);
+ if (index >= 0 && index != active_menu) {
+ selected_menu = index;
+ focused_menu = selected_menu;
+ get_menu_popup(active_menu)->hide();
+ _open_popup(index);
+ }
+ } break;
+ }
+}
+
+int MenuBar::_get_index_at_point(const Point2 &p_point) const {
+ Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
+ int hsep = get_theme_constant(SNAME("h_separation"));
+ int offset = 0;
+ for (int i = 0; i < menu_cache.size(); i++) {
+ if (menu_cache[i].hidden) {
+ continue;
+ }
+ Size2 size = menu_cache[i].text_buf->get_size() + style->get_minimum_size();
+ if (p_point.x > offset && p_point.x < offset + size.x) {
+ if (p_point.y > 0 && p_point.y < size.y) {
+ return i;
+ }
+ }
+ offset += size.x + hsep;
+ }
+ return -1;
+}
+
+Rect2 MenuBar::_get_menu_item_rect(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, menu_cache.size(), Rect2());
+
+ Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
+ int hsep = get_theme_constant(SNAME("h_separation"));
+
+ int offset = 0;
+ for (int i = 0; i < p_index; i++) {
+ if (menu_cache[i].hidden) {
+ continue;
+ }
+ Size2 size = menu_cache[i].text_buf->get_size() + style->get_minimum_size();
+ offset += size.x + hsep;
+ }
+
+ return Rect2(Point2(offset, 0), menu_cache[p_index].text_buf->get_size() + style->get_minimum_size());
+}
+
+void MenuBar::_draw_menu_item(int p_index) {
+ ERR_FAIL_INDEX(p_index, menu_cache.size());
+
+ RID ci = get_canvas_item();
+ bool hovered = (focused_menu == p_index);
+ bool pressed = (active_menu == p_index);
+ bool rtl = is_layout_rtl();
+
+ if (menu_cache[p_index].hidden) {
+ return;
+ }
+
+ Color color;
+ Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
+ Rect2 item_rect = _get_menu_item_rect(p_index);
+
+ if (menu_cache[p_index].disabled) {
+ if (rtl && has_theme_stylebox(SNAME("disabled_mirrored"))) {
+ style = get_theme_stylebox(SNAME("disabled_mirrored"));
+ } else {
+ style = get_theme_stylebox(SNAME("disabled"));
+ }
+ if (!flat) {
+ style->draw(ci, item_rect);
+ }
+ color = get_theme_color(SNAME("font_disabled_color"));
+ } else if (hovered && pressed && has_theme_stylebox("hover_pressed")) {
+ if (rtl && has_theme_stylebox(SNAME("hover_pressed_mirrored"))) {
+ style = get_theme_stylebox(SNAME("hover_pressed_mirrored"));
+ } else {
+ style = get_theme_stylebox(SNAME("hover_pressed"));
+ }
+ if (!flat) {
+ style->draw(ci, item_rect);
+ }
+ if (has_theme_color(SNAME("font_hover_pressed_color"))) {
+ color = get_theme_color(SNAME("font_hover_pressed_color"));
+ }
+ } else if (pressed) {
+ if (rtl && has_theme_stylebox(SNAME("pressed_mirrored"))) {
+ style = get_theme_stylebox(SNAME("pressed_mirrored"));
+ } else {
+ style = get_theme_stylebox(SNAME("pressed"));
+ }
+ if (!flat) {
+ style->draw(ci, item_rect);
+ }
+ if (has_theme_color(SNAME("font_pressed_color"))) {
+ color = get_theme_color(SNAME("font_pressed_color"));
+ } else {
+ color = get_theme_color(SNAME("font_color"));
+ }
+ } else if (hovered) {
+ if (rtl && has_theme_stylebox(SNAME("hover_mirrored"))) {
+ style = get_theme_stylebox(SNAME("hover_mirrored"));
+ } else {
+ style = get_theme_stylebox(SNAME("hover"));
+ }
+ if (!flat) {
+ style->draw(ci, item_rect);
+ }
+ color = get_theme_color(SNAME("font_hover_color"));
+ } else {
+ if (rtl && has_theme_stylebox(SNAME("normal_mirrored"))) {
+ style = get_theme_stylebox(SNAME("normal_mirrored"));
+ } else {
+ style = get_theme_stylebox(SNAME("normal"));
+ }
+ if (!flat) {
+ style->draw(ci, item_rect);
+ }
+ // Focus colors only take precedence over normal state.
+ if (has_focus()) {
+ color = get_theme_color(SNAME("font_focus_color"));
+ } else {
+ color = get_theme_color(SNAME("font_color"));
+ }
+ }
+
+ Point2 text_ofs = item_rect.position + Point2(style->get_margin(SIDE_LEFT), style->get_margin(SIDE_TOP));
+
+ Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
+ int outline_size = get_theme_constant(SNAME("outline_size"));
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ menu_cache[p_index].text_buf->draw_outline(ci, text_ofs, outline_size, font_outline_color);
+ }
+ menu_cache[p_index].text_buf->draw(ci, text_ofs, color);
+}
+
+void MenuBar::shape(Menu &p_menu) {
+ Ref<Font> font = get_theme_font(SNAME("font"));
+ int font_size = get_theme_font_size(SNAME("font_size"));
+
+ p_menu.text_buf->clear();
+ if (text_direction == Control::TEXT_DIRECTION_INHERITED) {
+ p_menu.text_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR);
+ } else {
+ p_menu.text_buf->set_direction((TextServer::Direction)text_direction);
+ }
+ p_menu.text_buf->add_string(p_menu.name, font, font_size, language);
+}
+
+void MenuBar::_refresh_menu_names() {
+ Vector<PopupMenu *> popups = _get_popups();
+ for (int i = 0; i < popups.size(); i++) {
+ if (!popups[i]->has_meta("_menu_name") && String(popups[i]->get_name()) != get_menu_title(i)) {
+ menu_cache.write[i].name = popups[i]->get_name();
+ shape(menu_cache.write[i]);
+ }
+ }
+ _update_menu();
+}
+
+Vector<PopupMenu *> MenuBar::_get_popups() const {
+ Vector<PopupMenu *> popups;
+ for (int i = 0; i < get_child_count(); i++) {
+ PopupMenu *pm = Object::cast_to<PopupMenu>(get_child(i));
+ if (!pm) {
+ continue;
+ }
+ popups.push_back(pm);
+ }
+ return popups;
+}
+
+int MenuBar::get_menu_idx_from_control(PopupMenu *p_child) const {
+ ERR_FAIL_NULL_V(p_child, -1);
+ ERR_FAIL_COND_V(p_child->get_parent() != this, -1);
+
+ Vector<PopupMenu *> popups = _get_popups();
+ for (int i = 0; i < popups.size(); i++) {
+ if (popups[i] == p_child) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+void MenuBar::add_child_notify(Node *p_child) {
+ Control::add_child_notify(p_child);
+
+ PopupMenu *pm = Object::cast_to<PopupMenu>(p_child);
+ if (!pm) {
+ return;
+ }
+ Menu menu = Menu(p_child->get_name());
+ shape(menu);
+
+ menu_cache.push_back(menu);
+ p_child->connect("renamed", callable_mp(this, &MenuBar::_refresh_menu_names));
+ p_child->connect("menu_changed", callable_mp(this, &MenuBar::_update_menu));
+ p_child->connect("about_to_popup", callable_mp(this, &MenuBar::_popup_visibility_changed).bind(true));
+ p_child->connect("popup_hide", callable_mp(this, &MenuBar::_popup_visibility_changed).bind(false));
+
+ _update_menu();
+}
+
+void MenuBar::move_child_notify(Node *p_child) {
+ Control::move_child_notify(p_child);
+
+ PopupMenu *pm = Object::cast_to<PopupMenu>(p_child);
+ if (!pm) {
+ return;
+ }
+
+ int old_idx = -1;
+ String menu_name = String(pm->get_meta("_menu_name", pm->get_name()));
+ // Find the previous menu index of the control.
+ for (int i = 0; i < get_menu_count(); i++) {
+ if (get_menu_title(i) == menu_name) {
+ old_idx = i;
+ break;
+ }
+ }
+ Menu menu = menu_cache[old_idx];
+ menu_cache.remove_at(old_idx);
+ menu_cache.insert(get_menu_idx_from_control(pm), menu);
+
+ _update_menu();
+}
+
+void MenuBar::remove_child_notify(Node *p_child) {
+ Control::remove_child_notify(p_child);
+
+ PopupMenu *pm = Object::cast_to<PopupMenu>(p_child);
+ if (!pm) {
+ return;
+ }
+
+ int idx = get_menu_idx_from_control(pm);
+
+ menu_cache.remove_at(idx);
+
+ p_child->remove_meta("_menu_name");
+ p_child->remove_meta("_menu_tooltip");
+
+ p_child->disconnect("renamed", callable_mp(this, &MenuBar::_refresh_menu_names));
+ p_child->disconnect("menu_changed", callable_mp(this, &MenuBar::_update_menu));
+ p_child->disconnect("about_to_popup", callable_mp(this, &MenuBar::_popup_visibility_changed));
+ p_child->disconnect("popup_hide", callable_mp(this, &MenuBar::_popup_visibility_changed));
+
+ _update_menu();
+}
+
+void MenuBar::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_switch_on_hover", "enable"), &MenuBar::set_switch_on_hover);
+ ClassDB::bind_method(D_METHOD("is_switch_on_hover"), &MenuBar::is_switch_on_hover);
+ ClassDB::bind_method(D_METHOD("set_disable_shortcuts", "disabled"), &MenuBar::set_disable_shortcuts);
+
+ ClassDB::bind_method(D_METHOD("set_prefer_global_menu", "enabled"), &MenuBar::set_prefer_global_menu);
+ ClassDB::bind_method(D_METHOD("is_prefer_global_menu"), &MenuBar::is_prefer_global_menu);
+ ClassDB::bind_method(D_METHOD("is_native_menu"), &MenuBar::is_native_menu);
+
+ ClassDB::bind_method(D_METHOD("get_menu_count"), &MenuBar::get_menu_count);
+
+ ClassDB::bind_method(D_METHOD("set_text_direction", "direction"), &MenuBar::set_text_direction);
+ ClassDB::bind_method(D_METHOD("get_text_direction"), &MenuBar::get_text_direction);
+ ClassDB::bind_method(D_METHOD("set_language", "language"), &MenuBar::set_language);
+ ClassDB::bind_method(D_METHOD("get_language"), &MenuBar::get_language);
+ ClassDB::bind_method(D_METHOD("set_flat", "enabled"), &MenuBar::set_flat);
+ ClassDB::bind_method(D_METHOD("is_flat"), &MenuBar::is_flat);
+ ClassDB::bind_method(D_METHOD("set_start_index", "enabled"), &MenuBar::set_start_index);
+ ClassDB::bind_method(D_METHOD("get_start_index"), &MenuBar::get_start_index);
+
+ ClassDB::bind_method(D_METHOD("set_menu_title", "menu", "title"), &MenuBar::set_menu_title);
+ ClassDB::bind_method(D_METHOD("get_menu_title", "menu"), &MenuBar::get_menu_title);
+
+ ClassDB::bind_method(D_METHOD("set_menu_tooltip", "menu", "tooltip"), &MenuBar::set_menu_tooltip);
+ ClassDB::bind_method(D_METHOD("get_menu_tooltip", "menu"), &MenuBar::get_menu_tooltip);
+
+ ClassDB::bind_method(D_METHOD("set_menu_disabled", "menu", "disabled"), &MenuBar::set_menu_disabled);
+ ClassDB::bind_method(D_METHOD("is_menu_disabled", "menu"), &MenuBar::is_menu_disabled);
+
+ ClassDB::bind_method(D_METHOD("set_menu_hidden", "menu", "hidden"), &MenuBar::set_menu_hidden);
+ ClassDB::bind_method(D_METHOD("is_menu_hidden", "menu"), &MenuBar::is_menu_hidden);
+
+ ClassDB::bind_method(D_METHOD("set_shortcut_context", "node"), &MenuBar::set_shortcut_context);
+ ClassDB::bind_method(D_METHOD("get_shortcut_context"), &MenuBar::get_shortcut_context);
+
+ ClassDB::bind_method(D_METHOD("get_menu_popup", "menu"), &MenuBar::get_menu_popup);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "start_index"), "set_start_index", "get_start_index");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "switch_on_hover"), "set_switch_on_hover", "is_switch_on_hover");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "prefer_global_menu"), "set_prefer_global_menu", "is_prefer_global_menu");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut_context", PROPERTY_HINT_RESOURCE_TYPE, "Node"), "set_shortcut_context", "get_shortcut_context");
+
+ ADD_GROUP("BiDi", "");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language");
+}
+
+void MenuBar::set_switch_on_hover(bool p_enabled) {
+ switch_on_hover = p_enabled;
+}
+
+bool MenuBar::is_switch_on_hover() {
+ return switch_on_hover;
+}
+
+void MenuBar::set_disable_shortcuts(bool p_disabled) {
+ disable_shortcuts = p_disabled;
+}
+
+void MenuBar::set_text_direction(Control::TextDirection p_text_direction) {
+ ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3);
+ if (text_direction != p_text_direction) {
+ text_direction = p_text_direction;
+ _update_menu();
+ }
+}
+
+Control::TextDirection MenuBar::get_text_direction() const {
+ return text_direction;
+}
+
+void MenuBar::set_language(const String &p_language) {
+ if (language != p_language) {
+ language = p_language;
+ _update_menu();
+ }
+}
+
+String MenuBar::get_language() const {
+ return language;
+}
+
+void MenuBar::set_flat(bool p_enabled) {
+ if (flat != p_enabled) {
+ flat = p_enabled;
+ update();
+ }
+}
+
+bool MenuBar::is_flat() const {
+ return flat;
+}
+
+void MenuBar::set_start_index(int p_index) {
+ if (start_index != p_index) {
+ start_index = p_index;
+ _update_menu();
+ }
+}
+
+int MenuBar::get_start_index() const {
+ return start_index;
+}
+
+void MenuBar::set_prefer_global_menu(bool p_enabled) {
+ if (is_native != p_enabled) {
+ if (is_native) {
+ _clear_menu();
+ }
+ is_native = p_enabled;
+ _update_menu();
+ }
+}
+
+bool MenuBar::is_prefer_global_menu() const {
+ return is_native;
+}
+
+Size2 MenuBar::get_minimum_size() const {
+ if (is_native_menu()) {
+ return Size2();
+ }
+
+ Ref<StyleBox> style = get_theme_stylebox(SNAME("normal"));
+
+ Vector2 size;
+ for (int i = 0; i < menu_cache.size(); i++) {
+ if (menu_cache[i].hidden) {
+ continue;
+ }
+ Size2 sz = menu_cache[i].text_buf->get_size() + style->get_minimum_size();
+ size.y = MAX(size.y, sz.y);
+ size.x += sz.x;
+ }
+ if (menu_cache.size() > 1) {
+ size.x += get_theme_constant(SNAME("h_separation")) * (menu_cache.size() - 1);
+ }
+ return size;
+}
+
+int MenuBar::get_menu_count() const {
+ return menu_cache.size();
+}
+
+void MenuBar::set_menu_title(int p_menu, const String &p_title) {
+ ERR_FAIL_INDEX(p_menu, menu_cache.size());
+ PopupMenu *pm = get_menu_popup(p_menu);
+ if (p_title == pm->get_name()) {
+ pm->remove_meta("_menu_name");
+ } else {
+ pm->set_meta("_menu_name", p_title);
+ }
+ menu_cache.write[p_menu].name = p_title;
+ shape(menu_cache.write[p_menu]);
+ _update_menu();
+}
+
+String MenuBar::get_menu_title(int p_menu) const {
+ ERR_FAIL_INDEX_V(p_menu, menu_cache.size(), String());
+ return menu_cache[p_menu].name;
+}
+
+void MenuBar::set_menu_tooltip(int p_menu, const String &p_tooltip) {
+ ERR_FAIL_INDEX(p_menu, menu_cache.size());
+ PopupMenu *pm = get_menu_popup(p_menu);
+ pm->set_meta("_menu_tooltip", p_tooltip);
+ menu_cache.write[p_menu].name = p_tooltip;
+}
+
+String MenuBar::get_menu_tooltip(int p_menu) const {
+ ERR_FAIL_INDEX_V(p_menu, menu_cache.size(), String());
+ return menu_cache[p_menu].tooltip;
+}
+
+void MenuBar::set_menu_disabled(int p_menu, bool p_disabled) {
+ ERR_FAIL_INDEX(p_menu, menu_cache.size());
+ menu_cache.write[p_menu].disabled = p_disabled;
+ _update_menu();
+}
+
+bool MenuBar::is_menu_disabled(int p_menu) const {
+ ERR_FAIL_INDEX_V(p_menu, menu_cache.size(), false);
+ return menu_cache[p_menu].disabled;
+}
+
+void MenuBar::set_menu_hidden(int p_menu, bool p_hidden) {
+ ERR_FAIL_INDEX(p_menu, menu_cache.size());
+ menu_cache.write[p_menu].hidden = p_hidden;
+ _update_menu();
+}
+
+bool MenuBar::is_menu_hidden(int p_menu) const {
+ ERR_FAIL_INDEX_V(p_menu, menu_cache.size(), false);
+ return menu_cache[p_menu].hidden;
+}
+
+PopupMenu *MenuBar::get_menu_popup(int p_idx) const {
+ Vector<PopupMenu *> controls = _get_popups();
+ if (p_idx >= 0 && p_idx < controls.size()) {
+ return controls[p_idx];
+ } else {
+ return nullptr;
+ }
+}
+
+String MenuBar::get_tooltip(const Point2 &p_pos) const {
+ int index = _get_index_at_point(p_pos);
+ if (index >= 0 && index < menu_cache.size()) {
+ return menu_cache[index].tooltip;
+ } else {
+ return String();
+ }
+}
+
+void MenuBar::get_translatable_strings(List<String> *p_strings) const {
+ Vector<PopupMenu *> popups = _get_popups();
+ for (int i = 0; i < popups.size(); i++) {
+ PopupMenu *pm = popups[i];
+
+ if (!pm->has_meta("_menu_name") && !pm->has_meta("_menu_tooltip")) {
+ continue;
+ }
+
+ String name = pm->get_meta("_menu_name");
+ if (!name.is_empty()) {
+ p_strings->push_back(name);
+ }
+
+ String tooltip = pm->get_meta("_menu_tooltip");
+ if (!tooltip.is_empty()) {
+ p_strings->push_back(tooltip);
+ }
+ }
+}
+
+MenuBar::MenuBar() {
+ set_process_shortcut_input(true);
+}
+
+MenuBar::~MenuBar() {
+}
diff --git a/scene/gui/menu_bar.h b/scene/gui/menu_bar.h
new file mode 100644
index 0000000000..b7d9933ab2
--- /dev/null
+++ b/scene/gui/menu_bar.h
@@ -0,0 +1,156 @@
+/*************************************************************************/
+/* menu_bar.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef MENU_BAR_H
+#define MENU_BAR_H
+
+#include "scene/gui/button.h"
+#include "scene/gui/popup_menu.h"
+
+class MenuBar : public Control {
+ GDCLASS(MenuBar, Control);
+
+ Mutex mutex;
+
+ bool switch_on_hover = true;
+ bool disable_shortcuts = false;
+ bool is_native = true;
+ bool flat = false;
+ int start_index = -1;
+
+ String language;
+ TextDirection text_direction = TEXT_DIRECTION_AUTO;
+
+ struct Menu {
+ String name;
+ String tooltip;
+
+ Ref<TextLine> text_buf;
+ bool hidden = false;
+ bool disabled = false;
+
+ Menu(const String &p_name) {
+ name = p_name;
+ text_buf.instantiate();
+ }
+
+ Menu() {
+ text_buf.instantiate();
+ }
+ };
+ Vector<Menu> menu_cache;
+ HashSet<String> global_menus;
+
+ int focused_menu = -1;
+ int selected_menu = -1;
+ int active_menu = -1;
+
+ Vector2i mouse_pos_adjusted;
+ ObjectID shortcut_context;
+
+ int _get_index_at_point(const Point2 &p_point) const;
+ Rect2 _get_menu_item_rect(int p_index) const;
+ void _draw_menu_item(int p_index);
+
+ void shape(Menu &p_menu);
+ void _refresh_menu_names();
+ Vector<PopupMenu *> _get_popups() const;
+ int get_menu_idx_from_control(PopupMenu *p_child) const;
+
+ void _open_popup(int p_index, bool p_focus_item = false);
+ void _popup_visibility_changed(bool p_visible);
+ void _update_submenu(const String &p_menu_name, PopupMenu *p_child);
+ void _clear_menu();
+ void _update_menu();
+
+ bool _is_focus_owner_in_shortcut_context() const;
+
+protected:
+ virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
+
+ void _notification(int p_what);
+ virtual void add_child_notify(Node *p_child) override;
+ virtual void move_child_notify(Node *p_child) override;
+ virtual void remove_child_notify(Node *p_child) override;
+ static void _bind_methods();
+
+public:
+ virtual void gui_input(const Ref<InputEvent> &p_event) override;
+
+ void set_switch_on_hover(bool p_enabled);
+ bool is_switch_on_hover();
+ void set_disable_shortcuts(bool p_disabled);
+
+ void set_prefer_global_menu(bool p_enabled);
+ bool is_prefer_global_menu() const;
+
+ bool is_native_menu() const;
+
+ virtual Size2 get_minimum_size() const override;
+
+ int get_menu_count() const;
+
+ void set_text_direction(TextDirection p_text_direction);
+ TextDirection get_text_direction() const;
+
+ void set_language(const String &p_language);
+ String get_language() const;
+
+ void set_start_index(int p_index);
+ int get_start_index() const;
+
+ void set_flat(bool p_enabled);
+ bool is_flat() const;
+
+ void set_menu_title(int p_menu, const String &p_title);
+ String get_menu_title(int p_menu) const;
+
+ void set_menu_tooltip(int p_menu, const String &p_tooltip);
+ String get_menu_tooltip(int p_menu) const;
+
+ void set_menu_disabled(int p_menu, bool p_disabled);
+ bool is_menu_disabled(int p_menu) const;
+
+ void set_menu_hidden(int p_menu, bool p_hidden);
+ bool is_menu_hidden(int p_menu) const;
+
+ void set_shortcut_context(Node *p_node);
+ Node *get_shortcut_context() const;
+
+ PopupMenu *get_menu_popup(int p_menu) const;
+
+ virtual void get_translatable_strings(List<String> *p_strings) const override;
+ virtual String get_tooltip(const Point2 &p_pos) const override;
+
+ MenuBar();
+ ~MenuBar();
+};
+
+#endif // MENU_BAR_H
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index 069a31d9d2..f779f87ae7 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -86,6 +86,11 @@ void MenuButton::_popup_visibility_changed(bool p_visible) {
}
void MenuButton::pressed() {
+ if (popup->is_visible()) {
+ popup->hide();
+ return;
+ }
+
emit_signal(SNAME("about_to_popup"));
Size2 size = get_size() * get_viewport()->get_canvas_transform().get_scale();
@@ -98,11 +103,14 @@ void MenuButton::pressed() {
popup->set_position(gp);
popup->set_parent_rect(Rect2(Point2(gp - popup->get_position()), size));
- // If not triggered by the mouse, start the popup with its first item selected.
- if (popup->get_item_count() > 0 &&
- ((get_action_mode() == ActionMode::ACTION_MODE_BUTTON_PRESS && Input::get_singleton()->is_action_just_pressed("ui_accept")) ||
- (get_action_mode() == ActionMode::ACTION_MODE_BUTTON_RELEASE && Input::get_singleton()->is_action_just_released("ui_accept")))) {
- popup->set_current_index(0);
+ // If not triggered by the mouse, start the popup with its first enabled item focused.
+ if (!_was_pressed_by_mouse()) {
+ for (int i = 0; i < popup->get_item_count(); i++) {
+ if (!popup->is_item_disabled(i)) {
+ popup->set_current_index(i);
+ break;
+ }
+ }
}
popup->popup();
@@ -126,6 +134,11 @@ bool MenuButton::is_switch_on_hover() {
void MenuButton::set_item_count(int p_count) {
ERR_FAIL_COND(p_count < 0);
+
+ if (popup->get_item_count() == p_count) {
+ return;
+ }
+
popup->set_item_count(p_count);
notify_property_list_changed();
}
@@ -153,7 +166,10 @@ void MenuButton::_notification(int p_what) {
if (menu_btn_other && menu_btn_other != this && menu_btn_other->is_switch_on_hover() && !menu_btn_other->is_disabled() &&
(get_parent()->is_ancestor_of(menu_btn_other) || menu_btn_other->get_parent()->is_ancestor_of(popup))) {
popup->hide();
+
menu_btn_other->pressed();
+ // As the popup wasn't triggered by a mouse click, the item focus needs to be removed manually.
+ menu_btn_other->get_popup()->set_current_index(-1);
}
} break;
}
diff --git a/scene/gui/nine_patch_rect.cpp b/scene/gui/nine_patch_rect.cpp
index 8fee10b19a..a7e86dd5de 100644
--- a/scene/gui/nine_patch_rect.cpp
+++ b/scene/gui/nine_patch_rect.cpp
@@ -105,6 +105,11 @@ Ref<Texture2D> NinePatchRect::get_texture() const {
void NinePatchRect::set_patch_margin(Side p_side, int p_size) {
ERR_FAIL_INDEX((int)p_side, 4);
+
+ if (margin[p_side] == p_size) {
+ return;
+ }
+
margin[p_side] = p_size;
update();
update_minimum_size();
@@ -130,6 +135,10 @@ Rect2 NinePatchRect::get_region_rect() const {
}
void NinePatchRect::set_draw_center(bool p_enabled) {
+ if (draw_center == p_enabled) {
+ return;
+ }
+
draw_center = p_enabled;
update();
}
@@ -139,6 +148,10 @@ bool NinePatchRect::is_draw_center_enabled() const {
}
void NinePatchRect::set_h_axis_stretch_mode(AxisStretchMode p_mode) {
+ if (axis_h == p_mode) {
+ return;
+ }
+
axis_h = p_mode;
update();
}
@@ -148,6 +161,10 @@ NinePatchRect::AxisStretchMode NinePatchRect::get_h_axis_stretch_mode() const {
}
void NinePatchRect::set_v_axis_stretch_mode(AxisStretchMode p_mode) {
+ if (axis_v == p_mode) {
+ return;
+ }
+
axis_v = p_mode;
update();
}
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index a10ec1db06..a87c46e8ac 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -35,14 +35,19 @@
static const int NONE_SELECTED = -1;
Size2 OptionButton::get_minimum_size() const {
- Size2 minsize = Button::get_minimum_size();
+ Size2 minsize;
+ if (fit_to_longest_item) {
+ minsize = _cached_size;
+ } else {
+ minsize = Button::get_minimum_size();
+ }
if (has_theme_icon(SNAME("arrow"))) {
const Size2 padding = get_theme_stylebox(SNAME("normal"))->get_minimum_size();
const Size2 arrow_size = Control::get_theme_icon(SNAME("arrow"))->get_size();
Size2 content_size = minsize - padding;
- content_size.width += arrow_size.width + get_theme_constant(SNAME("h_separation"));
+ content_size.width += arrow_size.width + MAX(0, get_theme_constant(SNAME("h_separation")));
content_size.height = MAX(content_size.height, arrow_size.height);
minsize = content_size + padding;
@@ -69,6 +74,9 @@ void OptionButton::_notification(int p_what) {
case DRAW_HOVER:
clr = get_theme_color(SNAME("font_hover_color"));
break;
+ case DRAW_HOVER_PRESSED:
+ clr = get_theme_color(SNAME("font_hover_pressed_color"));
+ break;
case DRAW_DISABLED:
clr = get_theme_color(SNAME("font_disabled_color"));
break;
@@ -107,6 +115,7 @@ void OptionButton::_notification(int p_what) {
_set_internal_margin(SIDE_RIGHT, Control::get_theme_icon(SNAME("arrow"))->get_width());
}
}
+ _refresh_size_cache();
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -135,6 +144,10 @@ bool OptionButton::_set(const StringName &p_name, const Variant &p_value) {
_select(idx, false);
}
+ if (property == "text" || property == "icon") {
+ _queue_refresh_cache();
+ }
+
return valid;
}
return false;
@@ -185,17 +198,33 @@ void OptionButton::_selected(int p_which) {
}
void OptionButton::pressed() {
+ if (popup->is_visible()) {
+ popup->hide();
+ return;
+ }
+
Size2 size = get_size() * get_viewport()->get_canvas_transform().get_scale();
popup->set_position(get_screen_position() + Size2(0, size.height * get_global_transform().get_scale().y));
popup->set_size(Size2(size.width, 0));
- // If not triggered by the mouse, start the popup with the checked item selected.
- if (popup->get_item_count() > 0) {
- if ((get_action_mode() == ActionMode::ACTION_MODE_BUTTON_PRESS && Input::get_singleton()->is_action_just_pressed("ui_accept")) ||
- (get_action_mode() == ActionMode::ACTION_MODE_BUTTON_RELEASE && Input::get_singleton()->is_action_just_released("ui_accept"))) {
- popup->set_current_index(current > -1 ? current : 0);
+ // If not triggered by the mouse, start the popup with the checked item (or the first enabled one) focused.
+ if (current != NONE_SELECTED && !popup->is_item_disabled(current)) {
+ if (!_was_pressed_by_mouse()) {
+ popup->set_current_index(current);
} else {
- popup->scroll_to_item(current > -1 ? current : 0);
+ popup->scroll_to_item(current);
+ }
+ } else {
+ for (int i = 0; i < popup->get_item_count(); i++) {
+ if (!popup->is_item_disabled(i)) {
+ if (!_was_pressed_by_mouse()) {
+ popup->set_current_index(i);
+ } else {
+ popup->scroll_to_item(i);
+ }
+
+ break;
+ }
}
}
@@ -208,6 +237,7 @@ void OptionButton::add_icon_item(const Ref<Texture2D> &p_icon, const String &p_l
if (first_selectable) {
select(get_item_count() - 1);
}
+ _queue_refresh_cache();
}
void OptionButton::add_item(const String &p_label, int p_id) {
@@ -216,6 +246,7 @@ void OptionButton::add_item(const String &p_label, int p_id) {
if (first_selectable) {
select(get_item_count() - 1);
}
+ _queue_refresh_cache();
}
void OptionButton::set_item_text(int p_idx, const String &p_text) {
@@ -224,6 +255,7 @@ void OptionButton::set_item_text(int p_idx, const String &p_text) {
if (current == p_idx) {
set_text(p_text);
}
+ _queue_refresh_cache();
}
void OptionButton::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) {
@@ -232,6 +264,7 @@ void OptionButton::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) {
if (current == p_idx) {
set_icon(p_icon);
}
+ _queue_refresh_cache();
}
void OptionButton::set_item_id(int p_idx, int p_id) {
@@ -301,6 +334,7 @@ void OptionButton::set_item_count(int p_count) {
}
}
+ _refresh_size_cache();
notify_property_list_changed();
}
@@ -333,6 +367,19 @@ int OptionButton::get_item_count() const {
return popup->get_item_count();
}
+void OptionButton::set_fit_to_longest_item(bool p_fit) {
+ if (p_fit == fit_to_longest_item) {
+ return;
+ }
+ fit_to_longest_item = p_fit;
+
+ _refresh_size_cache();
+}
+
+bool OptionButton::is_fit_to_longest_item() const {
+ return fit_to_longest_item;
+}
+
void OptionButton::add_separator(const String &p_text) {
popup->add_separator(p_text);
}
@@ -341,6 +388,7 @@ void OptionButton::clear() {
popup->clear();
set_text("");
current = NONE_SELECTED;
+ _refresh_size_cache();
}
void OptionButton::_select(int p_which, bool p_emit) {
@@ -380,6 +428,29 @@ void OptionButton::_select_int(int p_which) {
_select(p_which, false);
}
+void OptionButton::_refresh_size_cache() {
+ cache_refresh_pending = false;
+
+ if (!fit_to_longest_item) {
+ return;
+ }
+
+ _cached_size = Vector2();
+ for (int i = 0; i < get_item_count(); i++) {
+ _cached_size = _cached_size.max(get_minimum_size_for_text_and_icon(get_item_text(i), get_item_icon(i)));
+ }
+ update_minimum_size();
+}
+
+void OptionButton::_queue_refresh_cache() {
+ if (cache_refresh_pending) {
+ return;
+ }
+ cache_refresh_pending = true;
+
+ callable_mp(this, &OptionButton::_refresh_size_cache).call_deferredp(nullptr, 0);
+}
+
void OptionButton::select(int p_idx) {
_select(p_idx, false);
}
@@ -405,6 +476,7 @@ void OptionButton::remove_item(int p_idx) {
if (current == p_idx) {
_select(NONE_SELECTED);
}
+ _queue_refresh_cache();
}
PopupMenu *OptionButton::get_popup() const {
@@ -415,9 +487,9 @@ void OptionButton::get_translatable_strings(List<String> *p_strings) const {
popup->get_translatable_strings(p_strings);
}
-void OptionButton::_validate_property(PropertyInfo &property) const {
- if (property.name == "text" || property.name == "icon") {
- property.usage = PROPERTY_USAGE_NONE;
+void OptionButton::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "text" || p_property.name == "icon") {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
@@ -445,7 +517,7 @@ void OptionButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_selected_id"), &OptionButton::get_selected_id);
ClassDB::bind_method(D_METHOD("get_selected_metadata"), &OptionButton::get_selected_metadata);
ClassDB::bind_method(D_METHOD("remove_item", "idx"), &OptionButton::remove_item);
- ClassDB::bind_method(D_METHOD("_select_int"), &OptionButton::_select_int);
+ ClassDB::bind_method(D_METHOD("_select_int", "idx"), &OptionButton::_select_int);
ClassDB::bind_method(D_METHOD("get_popup"), &OptionButton::get_popup);
@@ -453,10 +525,13 @@ void OptionButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_item_count"), &OptionButton::get_item_count);
ClassDB::bind_method(D_METHOD("has_selectable_items"), &OptionButton::has_selectable_items);
ClassDB::bind_method(D_METHOD("get_selectable_item", "from_last"), &OptionButton::get_selectable_item, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("set_fit_to_longest_item", "fit"), &OptionButton::set_fit_to_longest_item);
+ ClassDB::bind_method(D_METHOD("is_fit_to_longest_item"), &OptionButton::is_fit_to_longest_item);
// "selected" property must come after "item_count", otherwise GH-10213 occurs.
ADD_ARRAY_COUNT("Items", "item_count", "set_item_count", "get_item_count", "popup/item_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "selected"), "_select_int", "get_selected");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fit_to_longest_item"), "set_fit_to_longest_item", "is_fit_to_longest_item");
ADD_SIGNAL(MethodInfo("item_selected", PropertyInfo(Variant::INT, "index")));
ADD_SIGNAL(MethodInfo("item_focused", PropertyInfo(Variant::INT, "index")));
}
@@ -482,6 +557,7 @@ OptionButton::OptionButton(const String &p_text) :
popup->connect("index_pressed", callable_mp(this, &OptionButton::_selected));
popup->connect("id_focused", callable_mp(this, &OptionButton::_focused));
popup->connect("popup_hide", callable_mp((BaseButton *)this, &BaseButton::set_pressed).bind(false));
+ _refresh_size_cache();
}
OptionButton::~OptionButton() {
diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h
index 5665296699..cd709b8f5f 100644
--- a/scene/gui/option_button.h
+++ b/scene/gui/option_button.h
@@ -39,11 +39,16 @@ class OptionButton : public Button {
PopupMenu *popup = nullptr;
int current = -1;
+ bool fit_to_longest_item = true;
+ Vector2 _cached_size;
+ bool cache_refresh_pending = false;
void _focused(int p_which);
void _selected(int p_which);
void _select(int p_which, bool p_emit = false);
void _select_int(int p_which);
+ void _refresh_size_cache();
+ void _queue_refresh_cache();
virtual void pressed() override;
@@ -53,7 +58,7 @@ protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
public:
@@ -85,6 +90,8 @@ public:
void set_item_count(int p_count);
int get_item_count() const;
+ void set_fit_to_longest_item(bool p_fit);
+ bool is_fit_to_longest_item() const;
void add_separator(const String &p_text = "");
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 928bab8842..c8bb9fd530 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -36,6 +36,7 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
#include "core/string/translation.h"
+#include "scene/gui/menu_bar.h"
String PopupMenu::_get_accel_text(const Item &p_item) const {
if (p_item.shortcut.is_valid()) {
@@ -66,7 +67,7 @@ Size2 PopupMenu::_get_contents_minimum_size() const {
size.height = _get_item_height(i);
icon_w = MAX(icon_size.width, icon_w);
- size.width += items[i].h_ofs;
+ size.width += items[i].indent * get_theme_constant(SNAME("indent"));
if (items[i].checkable_type && !items[i].separator) {
has_check = true;
@@ -215,9 +216,14 @@ void PopupMenu::_activate_submenu(int p_over, bool p_by_keyboard) {
submenu_pum->activated_by_keyboard = p_by_keyboard;
- // If not triggered by the mouse, start the popup with its first item selected.
- if (submenu_pum->get_item_count() > 0 && p_by_keyboard) {
- submenu_pum->set_current_index(0);
+ // If not triggered by the mouse, start the popup with its first enabled item focused.
+ if (p_by_keyboard) {
+ for (int i = 0; i < submenu_pum->get_item_count(); i++) {
+ if (!submenu_pum->is_item_disabled(i)) {
+ submenu_pum->set_current_index(i);
+ break;
+ }
+ }
}
submenu_pum->popup();
@@ -277,89 +283,104 @@ void PopupMenu::_submenu_timeout() {
void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
- if (p_event->is_action("ui_down") && p_event->is_pressed()) {
- int search_from = mouse_over + 1;
- if (search_from >= items.size()) {
- search_from = 0;
- }
-
- bool match_found = false;
- for (int i = search_from; i < items.size(); i++) {
- if (!items[i].separator && !items[i].disabled) {
- mouse_over = i;
- emit_signal(SNAME("id_focused"), i);
- scroll_to_item(i);
- control->update();
- set_input_as_handled();
- match_found = true;
- break;
+ if (!items.is_empty()) {
+ if (p_event->is_action("ui_down") && p_event->is_pressed()) {
+ int search_from = mouse_over + 1;
+ if (search_from >= items.size()) {
+ search_from = 0;
}
- }
- if (!match_found) {
- // If the last item is not selectable, try re-searching from the start.
- for (int i = 0; i < search_from; i++) {
+ bool match_found = false;
+ for (int i = search_from; i < items.size(); i++) {
if (!items[i].separator && !items[i].disabled) {
mouse_over = i;
emit_signal(SNAME("id_focused"), i);
scroll_to_item(i);
control->update();
set_input_as_handled();
+ match_found = true;
break;
}
}
- }
- } else if (p_event->is_action("ui_up") && p_event->is_pressed()) {
- int search_from = mouse_over - 1;
- if (search_from < 0) {
- search_from = items.size() - 1;
- }
- bool match_found = false;
- for (int i = search_from; i >= 0; i--) {
- if (!items[i].separator && !items[i].disabled) {
- mouse_over = i;
- emit_signal(SNAME("id_focused"), i);
- scroll_to_item(i);
- control->update();
- set_input_as_handled();
- match_found = true;
- break;
+ if (!match_found) {
+ // If the last item is not selectable, try re-searching from the start.
+ for (int i = 0; i < search_from; i++) {
+ if (!items[i].separator && !items[i].disabled) {
+ mouse_over = i;
+ emit_signal(SNAME("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()) {
+ int search_from = mouse_over - 1;
+ if (search_from < 0) {
+ search_from = items.size() - 1;
}
- }
- if (!match_found) {
- // If the first item is not selectable, try re-searching from the end.
- for (int i = items.size() - 1; i >= search_from; i--) {
+ bool match_found = false;
+ for (int i = search_from; i >= 0; i--) {
if (!items[i].separator && !items[i].disabled) {
mouse_over = i;
emit_signal(SNAME("id_focused"), i);
scroll_to_item(i);
control->update();
set_input_as_handled();
+ match_found = true;
break;
}
}
- }
- } else if (p_event->is_action("ui_left") && p_event->is_pressed()) {
- Node *n = get_parent();
- if (n && Object::cast_to<PopupMenu>(n)) {
- hide();
- set_input_as_handled();
- }
- } else if (p_event->is_action("ui_right") && p_event->is_pressed()) {
- if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && !items[mouse_over].submenu.is_empty() && submenu_over != mouse_over) {
- _activate_submenu(mouse_over, true);
- set_input_as_handled();
- }
- } else if (p_event->is_action("ui_accept") && p_event->is_pressed()) {
- if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator) {
- if (!items[mouse_over].submenu.is_empty() && submenu_over != mouse_over) {
+
+ if (!match_found) {
+ // If the first item is not selectable, try re-searching from the end.
+ for (int i = items.size() - 1; i >= search_from; i--) {
+ if (!items[i].separator && !items[i].disabled) {
+ mouse_over = i;
+ emit_signal(SNAME("id_focused"), i);
+ scroll_to_item(i);
+ control->update();
+ set_input_as_handled();
+ break;
+ }
+ }
+ }
+ } else if (p_event->is_action("ui_left") && p_event->is_pressed()) {
+ Node *n = get_parent();
+ if (n) {
+ if (Object::cast_to<PopupMenu>(n)) {
+ hide();
+ set_input_as_handled();
+ } else if (Object::cast_to<MenuBar>(n)) {
+ Object::cast_to<MenuBar>(n)->gui_input(p_event);
+ set_input_as_handled();
+ return;
+ }
+ }
+ } else if (p_event->is_action("ui_right") && p_event->is_pressed()) {
+ if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && !items[mouse_over].submenu.is_empty() && submenu_over != mouse_over) {
_activate_submenu(mouse_over, true);
+ set_input_as_handled();
} else {
- activate_item(mouse_over);
+ Node *n = get_parent();
+ if (n && Object::cast_to<MenuBar>(n)) {
+ Object::cast_to<MenuBar>(n)->gui_input(p_event);
+ set_input_as_handled();
+ return;
+ }
+ }
+ } else if (p_event->is_action("ui_accept") && p_event->is_pressed()) {
+ if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator) {
+ if (!items[mouse_over].submenu.is_empty() && submenu_over != mouse_over) {
+ _activate_submenu(mouse_over, true);
+ } else {
+ activate_item(mouse_over);
+ }
+ set_input_as_handled();
}
- set_input_as_handled();
}
}
@@ -513,9 +534,9 @@ void PopupMenu::_draw_items() {
bool rtl = control->is_layout_rtl();
Ref<StyleBox> style = get_theme_stylebox(SNAME("panel"));
Ref<StyleBox> hover = get_theme_stylebox(SNAME("hover"));
- // In Item::checkable_type enum order (less the non-checkable member).
- Ref<Texture2D> check[] = { get_theme_icon(SNAME("checked")), get_theme_icon(SNAME("radio_checked")) };
- Ref<Texture2D> uncheck[] = { get_theme_icon(SNAME("unchecked")), get_theme_icon(SNAME("radio_unchecked")) };
+ // In Item::checkable_type enum order (less the non-checkable member), with disabled repeated at the end.
+ Ref<Texture2D> check[] = { get_theme_icon(SNAME("checked")), get_theme_icon(SNAME("radio_checked")), get_theme_icon(SNAME("checked_disabled")), get_theme_icon(SNAME("radio_checked_disabled")) };
+ Ref<Texture2D> uncheck[] = { get_theme_icon(SNAME("unchecked")), get_theme_icon(SNAME("radio_unchecked")), get_theme_icon(SNAME("unchecked_disabled")), get_theme_icon(SNAME("radio_unchecked_disabled")) };
Ref<Texture2D> submenu;
if (rtl) {
submenu = get_theme_icon(SNAME("submenu_mirrored"));
@@ -558,7 +579,11 @@ void PopupMenu::_draw_items() {
float check_ofs = 0.0;
if (has_check) {
- check_ofs = MAX(get_theme_icon(SNAME("checked"))->get_width(), get_theme_icon(SNAME("radio_checked"))->get_width()) + hseparation;
+ for (int i = 0; i < 4; i++) {
+ check_ofs = MAX(check_ofs, check[i]->get_width());
+ check_ofs = MAX(check_ofs, uncheck[i]->get_width());
+ }
+ check_ofs += hseparation;
}
Point2 ofs = Point2();
@@ -585,7 +610,7 @@ void PopupMenu::_draw_items() {
String text = items[i].xl_text;
// Separator
- item_ofs.x += items[i].h_ofs;
+ item_ofs.x += items[i].indent * get_theme_constant(SNAME("indent"));
if (items[i].separator) {
if (!text.is_empty() || !items[i].icon.is_null()) {
int content_size = items[i].text_buf->get_size().width + hseparation * 2;
@@ -620,7 +645,8 @@ void PopupMenu::_draw_items() {
// Checkboxes
if (items[i].checkable_type && !items[i].separator) {
- Texture2D *icon = (items[i].checked ? check[items[i].checkable_type - 1] : uncheck[items[i].checkable_type - 1]).ptr();
+ int disabled = int(items[i].disabled) * 2;
+ Texture2D *icon = (items[i].checked ? check[items[i].checkable_type - 1 + disabled] : uncheck[items[i].checkable_type - 1 + disabled]).ptr();
if (rtl) {
icon->draw(ci, Size2(control->get_size().width - item_ofs.x - icon->get_width(), item_ofs.y) + Point2(0, Math::floor((h - icon->get_height()) / 2.0)), icon_color);
} else {
@@ -769,6 +795,32 @@ void PopupMenu::_shape_item(int p_item) {
}
}
+void PopupMenu::_menu_changed() {
+ emit_signal(SNAME("menu_changed"));
+}
+
+void PopupMenu::add_child_notify(Node *p_child) {
+ Window::add_child_notify(p_child);
+
+ PopupMenu *pm = Object::cast_to<PopupMenu>(p_child);
+ if (!pm) {
+ return;
+ }
+ p_child->connect("menu_changed", callable_mp(this, &PopupMenu::_menu_changed));
+ _menu_changed();
+}
+
+void PopupMenu::remove_child_notify(Node *p_child) {
+ Window::remove_child_notify(p_child);
+
+ PopupMenu *pm = Object::cast_to<PopupMenu>(p_child);
+ if (!pm) {
+ return;
+ }
+ p_child->disconnect("menu_changed", callable_mp(this, &PopupMenu::_menu_changed));
+ _menu_changed();
+}
+
void PopupMenu::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -790,6 +842,7 @@ void PopupMenu::_notification(int p_what) {
}
child_controls_changed();
+ _menu_changed();
control->update();
} break;
@@ -884,6 +937,7 @@ void PopupMenu::add_item(const String &p_label, int p_id, Key p_accel) {
control->update();
child_controls_changed();
notify_property_list_changed();
+ _menu_changed();
}
void PopupMenu::add_icon_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id, Key p_accel) {
@@ -895,6 +949,7 @@ void PopupMenu::add_icon_item(const Ref<Texture2D> &p_icon, const String &p_labe
control->update();
child_controls_changed();
notify_property_list_changed();
+ _menu_changed();
}
void PopupMenu::add_check_item(const String &p_label, int p_id, Key p_accel) {
@@ -905,6 +960,7 @@ void PopupMenu::add_check_item(const String &p_label, int p_id, Key p_accel) {
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::add_icon_check_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id, Key p_accel) {
@@ -926,6 +982,7 @@ void PopupMenu::add_radio_check_item(const String &p_label, int p_id, Key p_acce
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::add_icon_radio_check_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id, Key p_accel) {
@@ -937,6 +994,7 @@ void PopupMenu::add_icon_radio_check_item(const Ref<Texture2D> &p_icon, const St
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int p_default_state, int p_id, Key p_accel) {
@@ -948,6 +1006,7 @@ void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
#define ITEM_SETUP_WITH_SHORTCUT(p_shortcut, p_id, p_global) \
@@ -966,6 +1025,7 @@ void PopupMenu::add_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bool p_g
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) {
@@ -976,6 +1036,7 @@ void PopupMenu::add_icon_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortc
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::add_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) {
@@ -986,6 +1047,7 @@ void PopupMenu::add_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bo
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) {
@@ -997,6 +1059,7 @@ void PopupMenu::add_icon_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::add_radio_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) {
@@ -1007,6 +1070,7 @@ void PopupMenu::add_radio_check_shortcut(const Ref<Shortcut> &p_shortcut, int p_
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, const Ref<Shortcut> &p_shortcut, int p_id, bool p_global) {
@@ -1018,6 +1082,7 @@ void PopupMenu::add_icon_radio_check_shortcut(const Ref<Texture2D> &p_icon, cons
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu, int p_id) {
@@ -1030,6 +1095,7 @@ void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu,
_shape_item(items.size() - 1);
control->update();
child_controls_changed();
+ _menu_changed();
}
#undef ITEM_SETUP_WITH_ACCEL
@@ -1052,6 +1118,7 @@ void PopupMenu::set_item_text(int p_idx, const String &p_text) {
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::set_item_text_direction(int p_item, Control::TextDirection p_text_direction) {
@@ -1084,10 +1151,16 @@ void PopupMenu::set_item_icon(int p_idx, const Ref<Texture2D> &p_icon) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
+
+ if (items[p_idx].icon == p_icon) {
+ return;
+ }
+
items.write[p_idx].icon = p_icon;
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::set_item_checked(int p_idx, bool p_checked) {
@@ -1096,10 +1169,15 @@ void PopupMenu::set_item_checked(int p_idx, bool p_checked) {
}
ERR_FAIL_INDEX(p_idx, items.size());
+ if (items[p_idx].checked == p_checked) {
+ return;
+ }
+
items.write[p_idx].checked = p_checked;
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::set_item_id(int p_idx, int p_id) {
@@ -1107,10 +1185,16 @@ void PopupMenu::set_item_id(int p_idx, int p_id) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
+
+ if (items[p_idx].id == p_id) {
+ return;
+ }
+
items.write[p_idx].id = p_id;
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::set_item_accelerator(int p_idx, Key p_accel) {
@@ -1118,11 +1202,17 @@ void PopupMenu::set_item_accelerator(int p_idx, Key p_accel) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
+
+ if (items[p_idx].accel == p_accel) {
+ return;
+ }
+
items.write[p_idx].accel = p_accel;
items.write[p_idx].dirty = true;
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) {
@@ -1130,9 +1220,15 @@ void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
+
+ if (items[p_idx].metadata == p_meta) {
+ return;
+ }
+
items.write[p_idx].metadata = p_meta;
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) {
@@ -1140,9 +1236,15 @@ void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
+
+ if (items[p_idx].disabled == p_disabled) {
+ return;
+ }
+
items.write[p_idx].disabled = p_disabled;
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) {
@@ -1150,9 +1252,15 @@ void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
+
+ if (items[p_idx].submenu == p_submenu) {
+ return;
+ }
+
items.write[p_idx].submenu = p_submenu;
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::toggle_item_checked(int p_idx) {
@@ -1160,6 +1268,7 @@ void PopupMenu::toggle_item_checked(int p_idx) {
items.write[p_idx].checked = !items[p_idx].checked;
control->update();
child_controls_changed();
+ _menu_changed();
}
String PopupMenu::get_item_text(int p_idx) const {
@@ -1242,9 +1351,14 @@ Ref<Shortcut> PopupMenu::get_item_shortcut(int p_idx) const {
return items[p_idx].shortcut;
}
-int PopupMenu::get_item_horizontal_offset(int p_idx) const {
+int PopupMenu::get_item_indent(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, items.size(), 0);
- return items[p_idx].h_ofs;
+ return items[p_idx].indent;
+}
+
+int PopupMenu::get_item_max_states(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, items.size(), -1);
+ return items[p_idx].max_states;
}
int PopupMenu::get_item_state(int p_idx) const {
@@ -1257,6 +1371,11 @@ void PopupMenu::set_item_as_separator(int p_idx, bool p_separator) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
+
+ if (items[p_idx].separator == p_separator) {
+ return;
+ }
+
items.write[p_idx].separator = p_separator;
control->update();
}
@@ -1271,8 +1390,15 @@ void PopupMenu::set_item_as_checkable(int p_idx, bool p_checkable) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
+
+ int type = (int)(p_checkable ? Item::CHECKABLE_TYPE_CHECK_BOX : Item::CHECKABLE_TYPE_NONE);
+ if (type == items[p_idx].checkable_type) {
+ return;
+ }
+
items.write[p_idx].checkable_type = p_checkable ? Item::CHECKABLE_TYPE_CHECK_BOX : Item::CHECKABLE_TYPE_NONE;
control->update();
+ _menu_changed();
}
void PopupMenu::set_item_as_radio_checkable(int p_idx, bool p_radio_checkable) {
@@ -1280,8 +1406,15 @@ void PopupMenu::set_item_as_radio_checkable(int p_idx, bool p_radio_checkable) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
+
+ int type = (int)(p_radio_checkable ? Item::CHECKABLE_TYPE_RADIO_BUTTON : Item::CHECKABLE_TYPE_NONE);
+ if (type == items[p_idx].checkable_type) {
+ return;
+ }
+
items.write[p_idx].checkable_type = p_radio_checkable ? Item::CHECKABLE_TYPE_RADIO_BUTTON : Item::CHECKABLE_TYPE_NONE;
control->update();
+ _menu_changed();
}
void PopupMenu::set_item_tooltip(int p_idx, const String &p_tooltip) {
@@ -1289,8 +1422,14 @@ void PopupMenu::set_item_tooltip(int p_idx, const String &p_tooltip) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
+
+ if (items[p_idx].tooltip == p_tooltip) {
+ return;
+ }
+
items.write[p_idx].tooltip = p_tooltip;
control->update();
+ _menu_changed();
}
void PopupMenu::set_item_shortcut(int p_idx, const Ref<Shortcut> &p_shortcut, bool p_global) {
@@ -1298,6 +1437,11 @@ void PopupMenu::set_item_shortcut(int p_idx, const Ref<Shortcut> &p_shortcut, bo
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
+
+ if (items[p_idx].shortcut == p_shortcut && items[p_idx].shortcut_is_global == p_global && items[p_idx].shortcut.is_valid() == p_shortcut.is_valid()) {
+ return;
+ }
+
if (items[p_idx].shortcut.is_valid()) {
_unref_shortcut(items[p_idx].shortcut);
}
@@ -1310,16 +1454,23 @@ void PopupMenu::set_item_shortcut(int p_idx, const Ref<Shortcut> &p_shortcut, bo
}
control->update();
+ _menu_changed();
}
-void PopupMenu::set_item_horizontal_offset(int p_idx, int p_offset) {
+void PopupMenu::set_item_indent(int p_idx, int p_indent) {
if (p_idx < 0) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
- items.write[p_idx].h_ofs = p_offset;
+
+ if (items.write[p_idx].indent == p_indent) {
+ return;
+ }
+ items.write[p_idx].indent = p_indent;
+
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::set_item_multistate(int p_idx, int p_state) {
@@ -1327,8 +1478,14 @@ void PopupMenu::set_item_multistate(int p_idx, int p_state) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
+
+ if (items[p_idx].state == p_state) {
+ return;
+ }
+
items.write[p_idx].state = p_state;
control->update();
+ _menu_changed();
}
void PopupMenu::set_item_shortcut_disabled(int p_idx, bool p_disabled) {
@@ -1336,8 +1493,14 @@ void PopupMenu::set_item_shortcut_disabled(int p_idx, bool p_disabled) {
p_idx += get_item_count();
}
ERR_FAIL_INDEX(p_idx, items.size());
+
+ if (items[p_idx].shortcut_is_disabled == p_disabled) {
+ return;
+ }
+
items.write[p_idx].shortcut_is_disabled = p_disabled;
control->update();
+ _menu_changed();
}
void PopupMenu::toggle_item_multistate(int p_idx) {
@@ -1352,6 +1515,7 @@ void PopupMenu::toggle_item_multistate(int p_idx) {
}
control->update();
+ _menu_changed();
}
bool PopupMenu::is_item_checkable(int p_idx) const {
@@ -1364,15 +1528,30 @@ bool PopupMenu::is_item_radio_checkable(int p_idx) const {
return items[p_idx].checkable_type == Item::CHECKABLE_TYPE_RADIO_BUTTON;
}
+bool PopupMenu::is_item_shortcut_global(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, items.size(), false);
+ return items[p_idx].shortcut_is_global;
+}
+
bool PopupMenu::is_item_shortcut_disabled(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, items.size(), false);
return items[p_idx].shortcut_is_disabled;
}
void PopupMenu::set_current_index(int p_idx) {
- ERR_FAIL_INDEX(p_idx, items.size());
+ if (p_idx != -1) {
+ ERR_FAIL_INDEX(p_idx, items.size());
+ }
+
+ if (mouse_over == p_idx) {
+ return;
+ }
+
mouse_over = p_idx;
- scroll_to_item(mouse_over);
+ if (mouse_over != -1) {
+ scroll_to_item(mouse_over);
+ }
+
control->update();
}
@@ -1383,6 +1562,11 @@ int PopupMenu::get_current_index() const {
void PopupMenu::set_item_count(int p_count) {
ERR_FAIL_COND(p_count < 0);
int prev_size = items.size();
+
+ if (prev_size == p_count) {
+ return;
+ }
+
items.resize(p_count);
if (prev_size < p_count) {
@@ -1394,6 +1578,7 @@ void PopupMenu::set_item_count(int p_count) {
control->update();
child_controls_changed();
notify_property_list_changed();
+ _menu_changed();
}
int PopupMenu::get_item_count() const {
@@ -1535,6 +1720,7 @@ void PopupMenu::remove_item(int p_idx) {
items.remove_at(p_idx);
control->update();
child_controls_changed();
+ _menu_changed();
}
void PopupMenu::add_separator(const String &p_text, int p_id) {
@@ -1547,6 +1733,7 @@ void PopupMenu::add_separator(const String &p_text, int p_id) {
}
items.push_back(sep);
control->update();
+ _menu_changed();
}
void PopupMenu::clear() {
@@ -1560,6 +1747,7 @@ void PopupMenu::clear() {
control->update();
child_controls_changed();
notify_property_list_changed();
+ _menu_changed();
}
void PopupMenu::_ref_shortcut(Ref<Shortcut> p_sc) {
@@ -1834,7 +2022,7 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_item_as_radio_checkable", "index", "enable"), &PopupMenu::set_item_as_radio_checkable);
ClassDB::bind_method(D_METHOD("set_item_tooltip", "index", "tooltip"), &PopupMenu::set_item_tooltip);
ClassDB::bind_method(D_METHOD("set_item_shortcut", "index", "shortcut", "global"), &PopupMenu::set_item_shortcut, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("set_item_horizontal_offset", "index", "offset"), &PopupMenu::set_item_horizontal_offset);
+ ClassDB::bind_method(D_METHOD("set_item_indent", "index", "indent"), &PopupMenu::set_item_indent);
ClassDB::bind_method(D_METHOD("set_item_multistate", "index", "state"), &PopupMenu::set_item_multistate);
ClassDB::bind_method(D_METHOD("set_item_shortcut_disabled", "index", "disabled"), &PopupMenu::set_item_shortcut_disabled);
@@ -1858,7 +2046,7 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_item_shortcut_disabled", "index"), &PopupMenu::is_item_shortcut_disabled);
ClassDB::bind_method(D_METHOD("get_item_tooltip", "index"), &PopupMenu::get_item_tooltip);
ClassDB::bind_method(D_METHOD("get_item_shortcut", "index"), &PopupMenu::get_item_shortcut);
- ClassDB::bind_method(D_METHOD("get_item_horizontal_offset", "index"), &PopupMenu::get_item_horizontal_offset);
+ ClassDB::bind_method(D_METHOD("get_item_indent", "index"), &PopupMenu::get_item_indent);
ClassDB::bind_method(D_METHOD("set_current_index", "index"), &PopupMenu::set_current_index);
ClassDB::bind_method(D_METHOD("get_current_index"), &PopupMenu::get_current_index);
@@ -1898,6 +2086,7 @@ void PopupMenu::_bind_methods() {
ADD_SIGNAL(MethodInfo("id_pressed", PropertyInfo(Variant::INT, "id")));
ADD_SIGNAL(MethodInfo("id_focused", PropertyInfo(Variant::INT, "id")));
ADD_SIGNAL(MethodInfo("index_pressed", PropertyInfo(Variant::INT, "index")));
+ ADD_SIGNAL(MethodInfo("menu_changed"));
}
void PopupMenu::popup(const Rect2 &p_bounds) {
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index e203793c2e..d3ad0762e4 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -68,7 +68,7 @@ class PopupMenu : public Popup {
Key accel = Key::NONE;
int _ofs_cache = 0;
int _height_cache = 0;
- int h_ofs = 0;
+ int indent = 0;
Ref<Shortcut> shortcut;
bool shortcut_is_global = false;
bool shortcut_is_disabled = false;
@@ -134,8 +134,11 @@ class PopupMenu : public Popup {
void _minimum_lifetime_timeout();
void _close_pressed();
+ void _menu_changed();
protected:
+ virtual void add_child_notify(Node *p_child) override;
+ virtual void remove_child_notify(Node *p_child) override;
void _notification(int p_what);
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -183,7 +186,7 @@ public:
void set_item_as_radio_checkable(int p_idx, bool p_radio_checkable);
void set_item_tooltip(int p_idx, const String &p_tooltip);
void set_item_shortcut(int p_idx, const Ref<Shortcut> &p_shortcut, bool p_global = false);
- void set_item_horizontal_offset(int p_idx, int p_offset);
+ void set_item_indent(int p_idx, int p_indent);
void set_item_multistate(int p_idx, int p_state);
void toggle_item_multistate(int p_idx);
void set_item_shortcut_disabled(int p_idx, bool p_disabled);
@@ -206,9 +209,11 @@ public:
bool is_item_checkable(int p_idx) const;
bool is_item_radio_checkable(int p_idx) const;
bool is_item_shortcut_disabled(int p_idx) const;
+ bool is_item_shortcut_global(int p_idx) const;
String get_item_tooltip(int p_idx) const;
Ref<Shortcut> get_item_shortcut(int p_idx) const;
- int get_item_horizontal_offset(int p_idx) const;
+ int get_item_indent(int p_idx) const;
+ int get_item_max_states(int p_idx) const;
int get_item_state(int p_idx) const;
void set_current_index(int p_idx);
diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp
index fae6688452..0fb1f27802 100644
--- a/scene/gui/range.cpp
+++ b/scene/gui/range.cpp
@@ -106,6 +106,10 @@ void Range::set_value(double p_val) {
}
void Range::set_min(double p_min) {
+ if (shared->min == p_min) {
+ return;
+ }
+
shared->min = p_min;
set_value(shared->val);
_validate_values();
@@ -116,6 +120,10 @@ void Range::set_min(double p_min) {
}
void Range::set_max(double p_max) {
+ if (shared->max == p_max) {
+ return;
+ }
+
shared->max = p_max;
set_value(shared->val);
_validate_values();
@@ -124,11 +132,19 @@ void Range::set_max(double p_max) {
}
void Range::set_step(double p_step) {
+ if (shared->step == p_step) {
+ return;
+ }
+
shared->step = p_step;
shared->emit_changed("step");
}
void Range::set_page(double p_page) {
+ if (shared->page == p_page) {
+ return;
+ }
+
shared->page = p_page;
set_value(shared->val);
_validate_values();
@@ -300,6 +316,10 @@ bool Range::is_using_rounded_values() const {
}
void Range::set_exp_ratio(bool p_enable) {
+ if (shared->exp_ratio == p_enable) {
+ return;
+ }
+
shared->exp_ratio = p_enable;
update_configuration_warnings();
diff --git a/scene/gui/reference_rect.cpp b/scene/gui/reference_rect.cpp
index 5190a5a7d2..05dfe4b118 100644
--- a/scene/gui/reference_rect.cpp
+++ b/scene/gui/reference_rect.cpp
@@ -46,6 +46,10 @@ void ReferenceRect::_notification(int p_what) {
}
void ReferenceRect::set_border_color(const Color &p_color) {
+ if (border_color == p_color) {
+ return;
+ }
+
border_color = p_color;
update();
}
@@ -55,7 +59,12 @@ Color ReferenceRect::get_border_color() const {
}
void ReferenceRect::set_border_width(float p_width) {
- border_width = MAX(0.0, p_width);
+ float width_max = MAX(0.0, p_width);
+ if (border_width == width_max) {
+ return;
+ }
+
+ border_width = width_max;
update();
}
@@ -64,6 +73,10 @@ float ReferenceRect::get_border_width() const {
}
void ReferenceRect::set_editor_only(const bool &p_enabled) {
+ if (editor_only == p_enabled) {
+ return;
+ }
+
editor_only = p_enabled;
update();
}
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 8e424977c4..8ce8663091 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -742,7 +742,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
bool trim_glyphs_ltr = (visible_characters >= 0) && ((visible_chars_behavior == TextServer::VC_GLYPHS_LTR) || ((visible_chars_behavior == TextServer::VC_GLYPHS_AUTO) && !lrtl));
bool trim_glyphs_rtl = (visible_characters >= 0) && ((visible_chars_behavior == TextServer::VC_GLYPHS_RTL) || ((visible_chars_behavior == TextServer::VC_GLYPHS_AUTO) && lrtl));
int total_glyphs = (trim_glyphs_ltr || trim_glyphs_rtl) ? get_total_glyph_count() : 0;
- int visible_glyphs = total_glyphs * percent_visible;
+ int visible_glyphs = total_glyphs * visible_ratio;
Vector<int> list_index;
Vector<ItemList *> list_items;
@@ -821,17 +821,18 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
off.y += line_spacing;
}
- RID rid = l.text_buf->get_line_rid(line);
if (p_ofs.y + off.y >= ctrl_size.height) {
break;
}
- if (p_ofs.y + off.y + TS->shaped_text_get_size(rid).y <= 0) {
- off.y += TS->shaped_text_get_size(rid).y;
+
+ const Size2 line_size = l.text_buf->get_line_size(line);
+ if (p_ofs.y + off.y + line_size.y <= 0) {
+ off.y += line_size.y;
continue;
}
float width = l.text_buf->get_width();
- float length = TS->shaped_text_get_width(rid);
+ float length = line_size.x;
// Draw line.
line_count++;
@@ -874,6 +875,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
}
}
+ RID rid = l.text_buf->get_line_rid(line);
//draw_rect(Rect2(p_ofs + off, TS->shaped_text_get_size(rid)), Color(1,0,0), false, 2); //DEBUG_RECTS
off.y += TS->shaped_text_get_ascent(rid);
@@ -1344,7 +1346,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
return line_count;
}
-void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame, int *r_click_line, Item **r_click_item, int *r_click_char, bool *r_outside) {
+void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame, int *r_click_line, Item **r_click_item, int *r_click_char, bool *r_outside, bool p_meta) {
if (r_click_item) {
*r_click_item = nullptr;
}
@@ -1367,7 +1369,7 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item
Point2 ofs = text_rect.get_position() + Vector2(0, main->lines[from_line].offset.y - vofs);
while (ofs.y < size.height && from_line < to_line) {
MutexLock lock(main->lines[from_line].text_buf->get_mutex());
- _find_click_in_line(p_frame, from_line, ofs, text_rect.size.x, p_click, r_click_frame, r_click_line, r_click_item, r_click_char);
+ _find_click_in_line(p_frame, from_line, ofs, text_rect.size.x, p_click, r_click_frame, r_click_line, r_click_item, r_click_char, false, p_meta);
ofs.y += main->lines[from_line].text_buf->get_size().y + main->lines[from_line].text_buf->get_line_count() * get_theme_constant(SNAME("line_separation"));
if (((r_click_item != nullptr) && ((*r_click_item) != nullptr)) || ((r_click_frame != nullptr) && ((*r_click_frame) != nullptr))) {
if (r_outside != nullptr) {
@@ -1379,7 +1381,7 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item
}
}
-float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame, int *r_click_line, Item **r_click_item, int *r_click_char, bool p_table) {
+float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame, int *r_click_line, Item **r_click_item, int *r_click_char, bool p_table, bool p_meta) {
Vector2 off;
bool line_clicked = false;
@@ -1477,7 +1479,7 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
}
if (crect.has_point(p_click)) {
for (int j = 0; j < (int)frame->lines.size(); j++) {
- _find_click_in_line(frame, j, rect.position + Vector2(0, frame->lines[j].offset.y), rect.size.x, p_click, &table_click_frame, &table_click_line, &table_click_item, &table_click_char, true);
+ _find_click_in_line(frame, j, rect.position + Vector2(0, frame->lines[j].offset.y), rect.size.x, p_click, &table_click_frame, &table_click_line, &table_click_item, &table_click_char, true, p_meta);
if (table_click_frame && table_click_item) {
// Save cell detected cell hit data.
table_range = Vector2i(INT32_MAX, 0);
@@ -1510,7 +1512,15 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V
if (p_click.y >= rect.position.y && p_click.y <= rect.position.y + rect.size.y) {
if ((!rtl && p_click.x >= rect.position.x) || (rtl && p_click.x <= rect.position.x + rect.size.x)) {
- char_pos = TS->shaped_text_hit_test_position(rid, p_click.x - rect.position.x);
+ if (p_meta) {
+ int64_t glyph_idx = TS->shaped_text_hit_test_grapheme(rid, p_click.x - rect.position.x);
+ if (glyph_idx >= 0) {
+ const Glyph *glyphs = TS->shaped_text_get_glyphs(rid);
+ char_pos = glyphs[glyph_idx].start;
+ }
+ } else {
+ char_pos = TS->shaped_text_hit_test_position(rid, p_click.x - rect.position.x);
+ }
}
line_clicked = true;
text_rect_begin = rtl ? rect.position.x + rect.size.x : rect.position.x;
@@ -1823,7 +1833,7 @@ Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const
Item *item = nullptr;
bool outside = true;
- const_cast<RichTextLabel *>(this)->_find_click(main, p_pos, nullptr, nullptr, &item, nullptr, &outside);
+ const_cast<RichTextLabel *>(this)->_find_click(main, p_pos, nullptr, nullptr, &item, nullptr, &outside, true);
if (item && !outside && const_cast<RichTextLabel *>(this)->_find_meta(item, nullptr)) {
return CURSOR_POINTING_HAND;
@@ -1848,7 +1858,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
selection.drag_attempt = false;
- _find_click(main, b->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside);
+ _find_click(main, b->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside, false);
if (c_item != nullptr) {
if (selection.enabled) {
selection.click_frame = c_frame;
@@ -1886,7 +1896,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
selection.drag_attempt = false;
- _find_click(main, b->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside);
+ _find_click(main, b->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside, false);
if (c_frame) {
const Line &l = c_frame->lines[c_line];
@@ -1936,7 +1946,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
Item *c_item = nullptr;
bool outside = true;
- _find_click(main, b->get_position(), nullptr, nullptr, &c_item, nullptr, &outside);
+ _find_click(main, b->get_position(), nullptr, nullptr, &c_item, nullptr, &outside, true);
if (c_item) {
Variant meta;
@@ -2042,7 +2052,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
int c_index = 0;
bool outside;
- _find_click(main, m->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside);
+ _find_click(main, m->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside, false);
if (selection.click_item && c_item) {
selection.from_frame = selection.click_frame;
selection.from_line = selection.click_line;
@@ -2100,7 +2110,7 @@ String RichTextLabel::get_tooltip(const Point2 &p_pos) const {
Item *c_item = nullptr;
bool outside;
- const_cast<RichTextLabel *>(this)->_find_click(main, p_pos, nullptr, nullptr, &c_item, nullptr, &outside);
+ const_cast<RichTextLabel *>(this)->_find_click(main, p_pos, nullptr, nullptr, &c_item, nullptr, &outside, true);
String description;
if (c_item && !outside && const_cast<RichTextLabel *>(this)->_find_hint(c_item, &description)) {
@@ -3368,6 +3378,10 @@ void RichTextLabel::clear() {
}
void RichTextLabel::set_tab_size(int p_spaces) {
+ if (tab_size == p_spaces) {
+ return;
+ }
+
_stop_thread();
tab_size = p_spaces;
@@ -3391,6 +3405,10 @@ bool RichTextLabel::is_fit_content_height_enabled() const {
}
void RichTextLabel::set_meta_underline(bool p_underline) {
+ if (underline_meta == p_underline) {
+ return;
+ }
+
underline_meta = p_underline;
update();
}
@@ -4318,6 +4336,8 @@ void RichTextLabel::append_text(const String &p_bbcode) {
}
void RichTextLabel::scroll_to_paragraph(int p_paragraph) {
+ _validate_line_caches();
+
if (p_paragraph <= 0) {
vscroll->set_value(0);
} else if (p_paragraph >= main->first_invalid_line.load()) {
@@ -4339,6 +4359,8 @@ int RichTextLabel::get_visible_paragraph_count() const {
}
void RichTextLabel::scroll_to_line(int p_line) {
+ _validate_line_caches();
+
if (p_line <= 0) {
vscroll->set_value(0);
return;
@@ -4403,6 +4425,10 @@ int RichTextLabel::get_visible_line_count() const {
}
void RichTextLabel::set_selection_enabled(bool p_enabled) {
+ if (selection.enabled == p_enabled) {
+ return;
+ }
+
selection.enabled = p_enabled;
if (!p_enabled) {
if (selection.active) {
@@ -4415,6 +4441,10 @@ void RichTextLabel::set_selection_enabled(bool p_enabled) {
}
void RichTextLabel::set_deselect_on_focus_loss_enabled(const bool p_enabled) {
+ if (deselect_on_focus_loss_enabled == p_enabled) {
+ return;
+ }
+
deselect_on_focus_loss_enabled = p_enabled;
if (p_enabled && selection.active && !has_focus()) {
deselect();
@@ -4782,6 +4812,10 @@ int RichTextLabel::get_selection_to() const {
}
void RichTextLabel::set_text(const String &p_bbcode) {
+ if (text == p_bbcode) {
+ return;
+ }
+
text = p_bbcode;
if (use_bbcode) {
parse_bbcode(p_bbcode);
@@ -4906,27 +4940,31 @@ TextServer::AutowrapMode RichTextLabel::get_autowrap_mode() const {
return autowrap_mode;
}
-void RichTextLabel::set_percent_visible(float p_percent) {
- if (percent_visible != p_percent) {
+void RichTextLabel::set_visible_ratio(float p_ratio) {
+ if (visible_ratio != p_ratio) {
_stop_thread();
- if (p_percent < 0 || p_percent >= 1) {
+ if (visible_ratio >= 1.0) {
visible_characters = -1;
- percent_visible = 1;
+ visible_ratio = 1.0;
+ } else if (visible_ratio < 0.0) {
+ visible_characters = 0;
+ visible_ratio = 0.0;
} else {
- visible_characters = get_total_character_count() * p_percent;
- percent_visible = p_percent;
+ visible_characters = get_total_character_count() * p_ratio;
+ visible_ratio = p_ratio;
}
+
if (visible_chars_behavior == TextServer::VC_CHARS_BEFORE_SHAPING) {
- main->first_invalid_line.store(0); //invalidate ALL
+ main->first_invalid_line.store(0); // Invalidate ALL.
_validate_line_caches();
}
update();
}
}
-float RichTextLabel::get_percent_visible() const {
- return percent_visible;
+float RichTextLabel::get_visible_ratio() const {
+ return visible_ratio;
}
void RichTextLabel::set_effects(Array p_effects) {
@@ -4952,6 +4990,8 @@ void RichTextLabel::install_effect(const Variant effect) {
}
int RichTextLabel::get_content_height() const {
+ const_cast<RichTextLabel *>(this)->_validate_line_caches();
+
int total_height = 0;
int to_line = main->first_invalid_line.load();
if (to_line) {
@@ -4962,6 +5002,8 @@ int RichTextLabel::get_content_height() const {
}
int RichTextLabel::get_content_width() const {
+ const_cast<RichTextLabel *>(this)->_validate_line_caches();
+
int total_width = 0;
int to_line = main->first_invalid_line.load();
for (int i = 0; i < to_line; i++) {
@@ -5097,8 +5139,8 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_visible_characters_behavior"), &RichTextLabel::get_visible_characters_behavior);
ClassDB::bind_method(D_METHOD("set_visible_characters_behavior", "behavior"), &RichTextLabel::set_visible_characters_behavior);
- ClassDB::bind_method(D_METHOD("set_percent_visible", "percent_visible"), &RichTextLabel::set_percent_visible);
- ClassDB::bind_method(D_METHOD("get_percent_visible"), &RichTextLabel::get_percent_visible);
+ ClassDB::bind_method(D_METHOD("set_visible_ratio", "ratio"), &RichTextLabel::set_visible_ratio);
+ ClassDB::bind_method(D_METHOD("get_visible_ratio"), &RichTextLabel::get_visible_ratio);
ClassDB::bind_method(D_METHOD("get_character_line", "character"), &RichTextLabel::get_character_line);
ClassDB::bind_method(D_METHOD("get_character_paragraph", "character"), &RichTextLabel::get_character_paragraph);
@@ -5130,30 +5172,35 @@ void RichTextLabel::_bind_methods() {
// Note: set "bbcode_enabled" first, to avoid unnecessary "text" resets.
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bbcode_enabled"), "set_use_bbcode", "is_using_bbcode");
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "threaded"), "set_threaded", "is_threaded");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "progress_bar_delay", PROPERTY_HINT_NONE, "suffix:ms"), "set_progress_bar_delay", "get_progress_bar_delay");
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_size", PROPERTY_HINT_RANGE, "0,24,1"), "set_tab_size", "get_tab_size");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT), "set_text", "get_text");
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fit_content_height"), "set_fit_content_height", "is_fit_content_height_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_active"), "set_scroll_active", "is_scroll_active");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_following"), "set_scroll_follow", "is_scroll_following");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selection_enabled"), "set_selection_enabled", "is_selection_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deselect_on_focus_loss_enabled"), "set_deselect_on_focus_loss_enabled", "is_deselect_on_focus_loss_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "autowrap_mode", PROPERTY_HINT_ENUM, "Off,Arbitrary,Word,Word (Smart)"), "set_autowrap_mode", "get_autowrap_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_size", PROPERTY_HINT_RANGE, "0,24,1"), "set_tab_size", "get_tab_size");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled"), "set_shortcut_keys_enabled", "is_shortcut_keys_enabled");
+
+ ADD_GROUP("Markup", "");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "custom_effects", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "RichTextEffect"), (PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE)), "set_effects", "get_effects");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "meta_underlined"), "set_meta_underline", "is_meta_underlined");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hint_underlined"), "set_hint_underline", "is_hint_underlined");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "autowrap_mode", PROPERTY_HINT_ENUM, "Off,Arbitrary,Word,Word (Smart)"), "set_autowrap_mode", "get_autowrap_mode");
- // Note: "visible_characters" and "percent_visible" should be set after "text" to be correctly applied.
+ ADD_GROUP("Threading", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "threaded"), "set_threaded", "is_threaded");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "progress_bar_delay", PROPERTY_HINT_NONE, "suffix:ms"), "set_progress_bar_delay", "get_progress_bar_delay");
+
+ ADD_GROUP("Text Selection", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selection_enabled"), "set_selection_enabled", "is_selection_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deselect_on_focus_loss_enabled"), "set_deselect_on_focus_loss_enabled", "is_deselect_on_focus_loss_enabled");
+
+ ADD_GROUP("Displayed Text", "");
+ // Note: "visible_characters" and "visible_ratio" should be set after "text" to be correctly applied.
ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters", PROPERTY_HINT_RANGE, "-1,128000,1"), "set_visible_characters", "get_visible_characters");
ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters_behavior", PROPERTY_HINT_ENUM, "Characters Before Shaping,Characters After Shaping,Glyphs (Layout Direction),Glyphs (Left-to-Right),Glyphs (Right-to-Left)"), "set_visible_characters_behavior", "get_visible_characters_behavior");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "percent_visible", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_percent_visible", "get_percent_visible");
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled"), "set_shortcut_keys_enabled", "is_shortcut_keys_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visible_ratio", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_visible_ratio", "get_visible_ratio");
ADD_GROUP("BiDi", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
@@ -5222,11 +5269,11 @@ void RichTextLabel::set_visible_characters(int p_visible) {
visible_characters = p_visible;
if (p_visible == -1) {
- percent_visible = 1;
+ visible_ratio = 1;
} else {
int total_char_count = get_total_character_count();
if (total_char_count > 0) {
- percent_visible = (float)p_visible / (float)total_char_count;
+ visible_ratio = (float)p_visible / (float)total_char_count;
}
}
if (visible_chars_behavior == TextServer::VC_CHARS_BEFORE_SHAPING) {
@@ -5310,6 +5357,10 @@ int RichTextLabel::get_total_glyph_count() const {
}
void RichTextLabel::set_fixed_size_to_width(int p_width) {
+ if (fixed_width == p_width) {
+ return;
+ }
+
fixed_width = p_width;
update_minimum_size();
}
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index e5f0469c01..79f9c62539 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -440,11 +440,11 @@ private:
void _menu_option(int p_option);
int visible_characters = -1;
- float percent_visible = 1.0;
+ float visible_ratio = 1.0;
TextServer::VisibleCharactersBehavior visible_chars_behavior = TextServer::VC_CHARS_BEFORE_SHAPING;
bool _is_click_inside_selection() const;
- void _find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr);
+ void _find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr, bool p_meta = false);
String _get_line_text(ItemFrame *p_frame, int p_line, Selection p_sel) const;
bool _search_line(ItemFrame *p_frame, int p_line, const String &p_string, int p_char_idx, bool p_reverse_search);
@@ -455,7 +455,7 @@ private:
void _update_line_font(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size);
int _draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_shadow_color, int p_shadow_outline_size, const Point2 &p_shadow_ofs, int &r_processed_glyphs);
- float _find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool p_table = false);
+ float _find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool p_table = false, bool p_meta = false);
String _roman(int p_num, bool p_capitalize) const;
String _letters(int p_num, bool p_capitalize) const;
@@ -660,8 +660,8 @@ public:
int get_total_character_count() const;
int get_total_glyph_count() const;
- void set_percent_visible(float p_percent);
- float get_percent_visible() const;
+ void set_visible_ratio(float p_ratio);
+ float get_visible_ratio() const;
TextServer::VisibleCharactersBehavior get_visible_characters_behavior() const;
void set_visible_characters_behavior(TextServer::VisibleCharactersBehavior p_behavior);
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index 9efab27e3a..8fd547813d 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -37,7 +37,10 @@
Size2 ScrollContainer::get_minimum_size() const {
Ref<StyleBox> sb = get_theme_stylebox(SNAME("bg"));
Size2 min_size;
- Size2 content_min_size;
+
+ // Calculated in this function, as it needs to traverse all child controls once to calculate;
+ // and needs to be calculated before being used by update_scrollbars().
+ largest_child_min_size = Size2();
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
@@ -50,25 +53,27 @@ Size2 ScrollContainer::get_minimum_size() const {
if (c == h_scroll || c == v_scroll) {
continue;
}
- Size2 minsize = c->get_combined_minimum_size();
- content_min_size.x = MAX(content_min_size.x, minsize.x);
- content_min_size.y = MAX(content_min_size.y, minsize.y);
+ Size2 child_min_size = c->get_combined_minimum_size();
+
+ largest_child_min_size.x = MAX(largest_child_min_size.x, child_min_size.x);
+ largest_child_min_size.y = MAX(largest_child_min_size.y, child_min_size.y);
}
if (horizontal_scroll_mode == SCROLL_MODE_DISABLED) {
- min_size.x = MAX(min_size.x, content_min_size.x);
+ min_size.x = MAX(min_size.x, largest_child_min_size.x);
}
if (vertical_scroll_mode == SCROLL_MODE_DISABLED) {
- min_size.y = MAX(min_size.y, content_min_size.y);
+ min_size.y = MAX(min_size.y, largest_child_min_size.y);
}
- bool h_scroll_show = horizontal_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || (horizontal_scroll_mode == SCROLL_MODE_AUTO && content_min_size.x > min_size.x);
- bool v_scroll_show = vertical_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || (vertical_scroll_mode == SCROLL_MODE_AUTO && content_min_size.y > min_size.y);
- if (h_scroll_show) {
+ bool h_scroll_show = horizontal_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || (horizontal_scroll_mode == SCROLL_MODE_AUTO && largest_child_min_size.x > min_size.x);
+ bool v_scroll_show = vertical_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || (vertical_scroll_mode == SCROLL_MODE_AUTO && largest_child_min_size.y > min_size.y);
+
+ if (h_scroll_show && h_scroll->get_parent() == this) {
min_size.y += h_scroll->get_minimum_size().y;
}
- if (v_scroll_show) {
+ if (v_scroll_show && v_scroll->get_parent() == this) {
min_size.x += v_scroll->get_minimum_size().x;
}
@@ -261,8 +266,8 @@ void ScrollContainer::ensure_control_visible(Control *p_control) {
set_v_scroll(get_v_scroll() + (diff.y - global_rect.position.y));
}
-void ScrollContainer::_update_dimensions() {
- child_max_size = Size2(0, 0);
+void ScrollContainer::_reposition_children() {
+ update_scrollbars();
Size2 size = get_size();
Point2 ofs;
@@ -291,25 +296,13 @@ void ScrollContainer::_update_dimensions() {
continue;
}
Size2 minsize = c->get_combined_minimum_size();
- child_max_size.x = MAX(child_max_size.x, minsize.x);
- child_max_size.y = MAX(child_max_size.y, minsize.y);
Rect2 r = Rect2(-Size2(get_h_scroll(), get_v_scroll()), minsize);
- if (horizontal_scroll_mode == SCROLL_MODE_DISABLED || (!h_scroll->is_visible_in_tree() && c->get_h_size_flags() & SIZE_EXPAND)) {
- r.position.x = 0;
- if (c->get_h_size_flags() & SIZE_EXPAND) {
- r.size.width = MAX(size.width, minsize.width);
- } else {
- r.size.width = minsize.width;
- }
+ if (c->get_h_size_flags() & SIZE_EXPAND) {
+ r.size.width = MAX(size.width, minsize.width);
}
- if (vertical_scroll_mode == SCROLL_MODE_DISABLED || (!v_scroll->is_visible_in_tree() && c->get_v_size_flags() & SIZE_EXPAND)) {
- r.position.y = 0;
- if (c->get_v_size_flags() & SIZE_EXPAND) {
- r.size.height = MAX(size.height, minsize.height);
- } else {
- r.size.height = minsize.height;
- }
+ if (c->get_v_size_flags() & SIZE_EXPAND) {
+ r.size.height = MAX(size.height, minsize.height);
}
r.position += ofs;
if (rtl && v_scroll->is_visible_in_tree() && v_scroll->get_parent() == this) {
@@ -319,7 +312,6 @@ void ScrollContainer::_update_dimensions() {
fit_child_in_rect(c, r);
}
- update_scrollbars();
update();
}
@@ -337,18 +329,16 @@ void ScrollContainer::_notification(int p_what) {
Viewport *viewport = get_viewport();
ERR_FAIL_COND(!viewport);
viewport->connect("gui_focus_changed", callable_mp(this, &ScrollContainer::_gui_focus_changed));
- _update_dimensions();
+ _reposition_children();
} break;
case NOTIFICATION_SORT_CHILDREN: {
- _update_dimensions();
+ _reposition_children();
} break;
case NOTIFICATION_DRAW: {
Ref<StyleBox> sb = get_theme_stylebox(SNAME("bg"));
draw_style_box(sb, Rect2(Vector2(), get_size()));
-
- update_scrollbars();
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
@@ -426,36 +416,25 @@ void ScrollContainer::update_scrollbars() {
Ref<StyleBox> sb = get_theme_stylebox(SNAME("bg"));
size -= sb->get_minimum_size();
- Size2 hmin;
- Size2 vmin;
- if (horizontal_scroll_mode != SCROLL_MODE_DISABLED) {
- hmin = h_scroll->get_combined_minimum_size();
- }
- if (vertical_scroll_mode != SCROLL_MODE_DISABLED) {
- vmin = v_scroll->get_combined_minimum_size();
- }
-
- Size2 min = child_max_size;
+ Size2 hmin = h_scroll->get_combined_minimum_size();
+ Size2 vmin = v_scroll->get_combined_minimum_size();
- bool hide_scroll_h = horizontal_scroll_mode != SCROLL_MODE_SHOW_ALWAYS && (horizontal_scroll_mode == SCROLL_MODE_DISABLED || horizontal_scroll_mode == SCROLL_MODE_SHOW_NEVER || (horizontal_scroll_mode == SCROLL_MODE_AUTO && min.width <= size.width));
- bool hide_scroll_v = vertical_scroll_mode != SCROLL_MODE_SHOW_ALWAYS && (vertical_scroll_mode == SCROLL_MODE_DISABLED || vertical_scroll_mode == SCROLL_MODE_SHOW_NEVER || (vertical_scroll_mode == SCROLL_MODE_AUTO && min.height <= size.height));
+ h_scroll->set_visible(horizontal_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || (horizontal_scroll_mode == SCROLL_MODE_AUTO && largest_child_min_size.width > size.width));
+ v_scroll->set_visible(vertical_scroll_mode == SCROLL_MODE_SHOW_ALWAYS || (vertical_scroll_mode == SCROLL_MODE_AUTO && largest_child_min_size.height > size.height));
- h_scroll->set_max(min.width);
- h_scroll->set_page(size.width - (hide_scroll_v ? 0 : vmin.width));
- h_scroll->set_visible(!hide_scroll_h);
+ h_scroll->set_max(largest_child_min_size.width);
+ h_scroll->set_page((v_scroll->is_visible() && v_scroll->get_parent() == this) ? size.width - vmin.width : size.width);
- v_scroll->set_max(min.height);
- v_scroll->set_page(size.height - (hide_scroll_h ? 0 : hmin.height));
- v_scroll->set_visible(!hide_scroll_v);
+ v_scroll->set_max(largest_child_min_size.height);
+ v_scroll->set_page((h_scroll->is_visible() && h_scroll->get_parent() == this) ? size.height - hmin.height : size.height);
// Avoid scrollbar overlapping.
- h_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, hide_scroll_v ? 0 : -vmin.width);
- v_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, hide_scroll_h ? 0 : -hmin.height);
+ h_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, (v_scroll->is_visible() && v_scroll->get_parent() == this) ? -vmin.width : 0);
+ v_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, (h_scroll->is_visible() && h_scroll->get_parent() == this) ? -hmin.height : 0);
}
void ScrollContainer::_scroll_moved(float) {
queue_sort();
- update();
};
void ScrollContainer::set_h_scroll(int p_pos) {
diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h
index 7c8690538d..bfa74cfd0f 100644
--- a/scene/gui/scroll_container.h
+++ b/scene/gui/scroll_container.h
@@ -50,7 +50,7 @@ private:
HScrollBar *h_scroll = nullptr;
VScrollBar *v_scroll = nullptr;
- Size2 child_max_size;
+ mutable Size2 largest_child_min_size; // The largest one among the min sizes of all available child controls.
void update_scrollbars();
@@ -75,7 +75,7 @@ protected:
Size2 get_minimum_size() const override;
void _gui_focus_changed(Control *p_control);
- void _update_dimensions();
+ void _reposition_children();
void _notification(int p_what);
void _scroll_moved(float);
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index 64c07007dc..2695ad1f14 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -227,6 +227,10 @@ double Slider::get_custom_step() const {
}
void Slider::set_ticks(int p_count) {
+ if (ticks == p_count) {
+ return;
+ }
+
ticks = p_count;
update();
}
@@ -240,11 +244,19 @@ bool Slider::get_ticks_on_borders() const {
}
void Slider::set_ticks_on_borders(bool _tob) {
+ if (ticks_on_borders == _tob) {
+ return;
+ }
+
ticks_on_borders = _tob;
update();
}
void Slider::set_editable(bool p_editable) {
+ if (editable == p_editable) {
+ return;
+ }
+
editable = p_editable;
update();
}
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index b7bef37e17..65c4a09c84 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -41,12 +41,16 @@ Size2 SpinBox::get_minimum_size() const {
void SpinBox::_value_changed(double p_value) {
String value = TS->format_number(String::num(get_value(), Math::range_step_decimals(get_step())));
- if (!prefix.is_empty()) {
- value = prefix + " " + value;
- }
- if (!suffix.is_empty()) {
- value += " " + suffix;
+
+ if (!line_edit->has_focus()) {
+ if (!prefix.is_empty()) {
+ value = prefix + " " + value;
+ }
+ if (!suffix.is_empty()) {
+ value += " " + suffix;
+ }
}
+
line_edit->set_text(value);
Range::_value_changed(p_value);
}
@@ -88,7 +92,8 @@ void SpinBox::_line_edit_input(const Ref<InputEvent> &p_event) {
void SpinBox::_range_click_timeout() {
if (!drag.enabled && Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) {
bool up = get_local_mouse_position().y < (get_size().height / 2);
- set_value(get_value() + (up ? get_step() : -get_step()));
+ double step = get_custom_arrow_step() != 0.0 ? get_custom_arrow_step() : get_step();
+ set_value(get_value() + (up ? step : -step));
if (range_click_timer->is_one_shot()) {
range_click_timer->set_wait_time(0.075);
@@ -104,8 +109,9 @@ void SpinBox::_range_click_timeout() {
void SpinBox::_release_mouse() {
if (drag.enabled) {
drag.enabled = false;
- Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
+ Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_HIDDEN);
warp_mouse(drag.capture_pos);
+ Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
}
}
@@ -118,6 +124,8 @@ void SpinBox::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
+ double step = get_custom_arrow_step() != 0.0 ? get_custom_arrow_step() : get_step();
+
if (mb.is_valid() && mb->is_pressed()) {
bool up = mb->get_position().y < (get_size().height / 2);
@@ -125,7 +133,7 @@ void SpinBox::gui_input(const Ref<InputEvent> &p_event) {
case MouseButton::LEFT: {
line_edit->grab_focus();
- set_value(get_value() + (up ? get_step() : -get_step()));
+ set_value(get_value() + (up ? step : -step));
range_click_timer->set_wait_time(0.6);
range_click_timer->set_one_shot(true);
@@ -140,13 +148,13 @@ void SpinBox::gui_input(const Ref<InputEvent> &p_event) {
} break;
case MouseButton::WHEEL_UP: {
if (line_edit->has_focus()) {
- set_value(get_value() + get_step() * mb->get_factor());
+ set_value(get_value() + step * mb->get_factor());
accept_event();
}
} break;
case MouseButton::WHEEL_DOWN: {
if (line_edit->has_focus()) {
- set_value(get_value() - get_step() * mb->get_factor());
+ set_value(get_value() - step * mb->get_factor());
accept_event();
}
} break;
@@ -168,7 +176,7 @@ void SpinBox::gui_input(const Ref<InputEvent> &p_event) {
if (drag.enabled) {
drag.diff_y += mm->get_relative().y;
double diff_y = -0.01 * Math::pow(ABS(drag.diff_y), 1.8) * SIGN(drag.diff_y);
- set_value(CLAMP(drag.base_val + get_step() * diff_y, get_min(), get_max()));
+ set_value(CLAMP(drag.base_val + step * diff_y, get_min(), get_max()));
} else if (drag.allowed && drag.capture_pos.distance_to(mm->get_position()) > 2) {
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
drag.enabled = true;
@@ -178,8 +186,14 @@ void SpinBox::gui_input(const Ref<InputEvent> &p_event) {
}
}
+void SpinBox::_line_edit_focus_enter() {
+ int col = line_edit->get_caret_column();
+ _value_changed(0); // Update the LineEdit's text.
+ line_edit->set_caret_column(col);
+}
+
void SpinBox::_line_edit_focus_exit() {
- // discontinue because the focus_exit was caused by right-click context menu
+ // Discontinue because the focus_exit was caused by right-click context menu.
if (line_edit->is_menu_visible()) {
return;
}
@@ -247,6 +261,10 @@ HorizontalAlignment SpinBox::get_horizontal_alignment() const {
}
void SpinBox::set_suffix(const String &p_suffix) {
+ if (suffix == p_suffix) {
+ return;
+ }
+
suffix = p_suffix;
_value_changed(0);
}
@@ -256,6 +274,10 @@ String SpinBox::get_suffix() const {
}
void SpinBox::set_prefix(const String &p_prefix) {
+ if (prefix == p_prefix) {
+ return;
+ }
+
prefix = p_prefix;
_value_changed(0);
}
@@ -294,6 +316,14 @@ void SpinBox::apply() {
_text_submitted(line_edit->get_text());
}
+void SpinBox::set_custom_arrow_step(double p_custom_arrow_step) {
+ custom_arrow_step = p_custom_arrow_step;
+}
+
+double SpinBox::get_custom_arrow_step() const {
+ return custom_arrow_step;
+}
+
void SpinBox::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_horizontal_alignment", "alignment"), &SpinBox::set_horizontal_alignment);
ClassDB::bind_method(D_METHOD("get_horizontal_alignment"), &SpinBox::get_horizontal_alignment);
@@ -302,6 +332,8 @@ void SpinBox::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_prefix", "prefix"), &SpinBox::set_prefix);
ClassDB::bind_method(D_METHOD("get_prefix"), &SpinBox::get_prefix);
ClassDB::bind_method(D_METHOD("set_editable", "enabled"), &SpinBox::set_editable);
+ ClassDB::bind_method(D_METHOD("set_custom_arrow_step", "arrow_step"), &SpinBox::set_custom_arrow_step);
+ ClassDB::bind_method(D_METHOD("get_custom_arrow_step"), &SpinBox::get_custom_arrow_step);
ClassDB::bind_method(D_METHOD("is_editable"), &SpinBox::is_editable);
ClassDB::bind_method(D_METHOD("set_update_on_text_changed", "enabled"), &SpinBox::set_update_on_text_changed);
ClassDB::bind_method(D_METHOD("get_update_on_text_changed"), &SpinBox::get_update_on_text_changed);
@@ -313,6 +345,7 @@ void SpinBox::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "update_on_text_changed"), "set_update_on_text_changed", "get_update_on_text_changed");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "prefix"), "set_prefix", "get_prefix");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "suffix"), "set_suffix", "get_suffix");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "custom_arrow_step"), "set_custom_arrow_step", "get_custom_arrow_step");
}
SpinBox::SpinBox() {
@@ -324,6 +357,7 @@ SpinBox::SpinBox() {
line_edit->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_LEFT);
line_edit->connect("text_submitted", callable_mp(this, &SpinBox::_text_submitted), CONNECT_DEFERRED);
+ line_edit->connect("focus_entered", callable_mp(this, &SpinBox::_line_edit_focus_enter), CONNECT_DEFERRED);
line_edit->connect("focus_exited", callable_mp(this, &SpinBox::_line_edit_focus_exit), CONNECT_DEFERRED);
line_edit->connect("gui_input", callable_mp(this, &SpinBox::_line_edit_input));
diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h
index 1b1abbcf8e..3fcb85ac99 100644
--- a/scene/gui/spin_box.h
+++ b/scene/gui/spin_box.h
@@ -52,6 +52,7 @@ class SpinBox : public Range {
String prefix;
String suffix;
+ double custom_arrow_step = 0.0;
void _line_edit_input(const Ref<InputEvent> &p_event);
@@ -63,6 +64,7 @@ class SpinBox : public Range {
double diff_y = 0.0;
} drag;
+ void _line_edit_focus_enter();
void _line_edit_focus_exit();
inline void _adjust_width_for_icon(const Ref<Texture2D> &icon);
@@ -95,6 +97,8 @@ public:
bool get_update_on_text_changed() const;
void apply();
+ void set_custom_arrow_step(const double p_custom_arrow_step);
+ double get_custom_arrow_step() const;
SpinBox();
};
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index d7aa516ee6..3e60db0846 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -95,7 +95,7 @@ void SplitContainer::_resort() {
no_offset_middle_sep = ms_first[axis];
}
- // Compute the final middle separation
+ // Compute the final middle separation.
middle_sep = no_offset_middle_sep;
if (!collapsed) {
int clamped_split_offset = CLAMP(split_offset, ms_first[axis] - no_offset_middle_sep, (get_size()[axis] - ms_second[axis] - sep) - no_offset_middle_sep);
@@ -327,6 +327,10 @@ void SplitContainer::set_collapsed(bool p_collapsed) {
}
void SplitContainer::set_dragger_visibility(DraggerVisibility p_visibility) {
+ if (dragger_visibility == p_visibility) {
+ return;
+ }
+
dragger_visibility = p_visibility;
queue_sort();
update();
diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp
index 68281b6a72..869683e427 100644
--- a/scene/gui/subviewport_container.cpp
+++ b/scene/gui/subviewport_container.cpp
@@ -53,6 +53,10 @@ Size2 SubViewportContainer::get_minimum_size() const {
}
void SubViewportContainer::set_stretch(bool p_enable) {
+ if (stretch == p_enable) {
+ return;
+ }
+
stretch = p_enable;
update_minimum_size();
queue_sort();
diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp
index d36a364677..e0739f909f 100644
--- a/scene/gui/tab_bar.cpp
+++ b/scene/gui/tab_bar.cpp
@@ -634,6 +634,11 @@ bool TabBar::get_offset_buttons_visible() const {
void TabBar::set_tab_title(int p_tab, const String &p_title) {
ERR_FAIL_INDEX(p_tab, tabs.size());
+
+ if (tabs[p_tab].text == p_title) {
+ return;
+ }
+
tabs.write[p_tab].text = p_title;
_shape(p_tab);
@@ -690,6 +695,11 @@ String TabBar::get_tab_language(int p_tab) const {
void TabBar::set_tab_icon(int p_tab, const Ref<Texture2D> &p_icon) {
ERR_FAIL_INDEX(p_tab, tabs.size());
+
+ if (tabs[p_tab].icon == p_icon) {
+ return;
+ }
+
tabs.write[p_tab].icon = p_icon;
_update_cache();
@@ -708,6 +718,11 @@ Ref<Texture2D> TabBar::get_tab_icon(int p_tab) const {
void TabBar::set_tab_disabled(int p_tab, bool p_disabled) {
ERR_FAIL_INDEX(p_tab, tabs.size());
+
+ if (tabs[p_tab].disabled == p_disabled) {
+ return;
+ }
+
tabs.write[p_tab].disabled = p_disabled;
_update_cache();
@@ -726,6 +741,11 @@ bool TabBar::is_tab_disabled(int p_tab) const {
void TabBar::set_tab_hidden(int p_tab, bool p_hidden) {
ERR_FAIL_INDEX(p_tab, tabs.size());
+
+ if (tabs[p_tab].hidden == p_hidden) {
+ return;
+ }
+
tabs.write[p_tab].hidden = p_hidden;
_update_cache();
@@ -744,6 +764,11 @@ bool TabBar::is_tab_hidden(int p_tab) const {
void TabBar::set_tab_button_icon(int p_tab, const Ref<Texture2D> &p_icon) {
ERR_FAIL_INDEX(p_tab, tabs.size());
+
+ if (tabs[p_tab].right_button == p_icon) {
+ return;
+ }
+
tabs.write[p_tab].right_button = p_icon;
_update_cache();
@@ -1155,6 +1180,11 @@ int TabBar::get_tab_idx_at_point(const Point2 &p_point) const {
void TabBar::set_tab_alignment(AlignmentMode p_alignment) {
ERR_FAIL_INDEX(p_alignment, ALIGNMENT_MAX);
+
+ if (tab_alignment == p_alignment) {
+ return;
+ }
+
tab_alignment = p_alignment;
_update_cache();
@@ -1374,6 +1404,11 @@ Rect2 TabBar::get_tab_rect(int p_tab) const {
void TabBar::set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy) {
ERR_FAIL_INDEX(p_policy, CLOSE_BUTTON_MAX);
+
+ if (cb_displaypolicy == p_policy) {
+ return;
+ }
+
cb_displaypolicy = p_policy;
_update_cache();
@@ -1391,6 +1426,11 @@ TabBar::CloseButtonDisplayPolicy TabBar::get_tab_close_display_policy() const {
void TabBar::set_max_tab_width(int p_width) {
ERR_FAIL_COND(p_width < 0);
+
+ if (max_width == p_width) {
+ return;
+ }
+
max_width = p_width;
_update_cache();
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 12f91a9873..10a6d18330 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -618,6 +618,10 @@ int TabContainer::get_tab_idx_from_control(Control *p_child) const {
}
void TabContainer::set_tab_alignment(TabBar::AlignmentMode p_alignment) {
+ if (tab_bar->get_tab_alignment() == p_alignment) {
+ return;
+ }
+
tab_bar->set_tab_alignment(p_alignment);
_update_margins();
}
@@ -679,6 +683,10 @@ void TabContainer::set_tab_title(int p_tab, const String &p_title) {
Control *child = get_tab_control(p_tab);
ERR_FAIL_COND(!child);
+ if (tab_bar->get_tab_title(p_tab) == p_title) {
+ return;
+ }
+
tab_bar->set_tab_title(p_tab, p_title);
if (p_title == child->get_name()) {
@@ -698,6 +706,10 @@ String TabContainer::get_tab_title(int p_tab) const {
}
void TabContainer::set_tab_icon(int p_tab, const Ref<Texture2D> &p_icon) {
+ if (tab_bar->get_tab_icon(p_tab) == p_icon) {
+ return;
+ }
+
tab_bar->set_tab_icon(p_tab, p_icon);
_update_margins();
@@ -709,6 +721,10 @@ Ref<Texture2D> TabContainer::get_tab_icon(int p_tab) const {
}
void TabContainer::set_tab_disabled(int p_tab, bool p_disabled) {
+ if (tab_bar->is_tab_disabled(p_tab) == p_disabled) {
+ return;
+ }
+
tab_bar->set_tab_disabled(p_tab, p_disabled);
_update_margins();
@@ -725,6 +741,10 @@ void TabContainer::set_tab_hidden(int p_tab, bool p_hidden) {
Control *child = get_tab_control(p_tab);
ERR_FAIL_COND(!child);
+ if (tab_bar->is_tab_hidden(p_tab) == p_hidden) {
+ return;
+ }
+
tab_bar->set_tab_hidden(p_tab, p_hidden);
child->hide();
@@ -811,7 +831,11 @@ void TabContainer::set_popup(Node *p_popup) {
bool had_popup = get_popup();
Popup *popup = Object::cast_to<Popup>(p_popup);
- popup_obj_id = popup ? popup->get_instance_id() : ObjectID();
+ ObjectID popup_id = popup ? popup->get_instance_id() : ObjectID();
+ if (popup_obj_id == popup_id) {
+ return;
+ }
+ popup_obj_id = popup_id;
if (had_popup != bool(popup)) {
update();
@@ -855,6 +879,10 @@ int TabContainer::get_tabs_rearrange_group() const {
}
void TabContainer::set_use_hidden_tabs_for_min_size(bool p_use_hidden_tabs) {
+ if (use_hidden_tabs_for_min_size == p_use_hidden_tabs) {
+ return;
+ }
+
use_hidden_tabs_for_min_size = p_use_hidden_tabs;
update_minimum_size();
}
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 4bc8b8e197..097eb1fd95 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1466,7 +1466,7 @@ void TextEdit::_notification(int p_what) {
caret_end = caret_start + post_text.length();
}
- DisplayServer::get_singleton()->virtual_keyboard_show(get_text(), get_global_rect(), true, -1, caret_start, caret_end);
+ DisplayServer::get_singleton()->virtual_keyboard_show(get_text(), get_global_rect(), DisplayServer::KEYBOARD_TYPE_MULTILINE, -1, caret_start, caret_end);
}
} break;
@@ -2889,6 +2889,10 @@ TextServer::StructuredTextParser TextEdit::get_structured_text_bidi_override() c
}
void TextEdit::set_structured_text_bidi_override_options(Array p_args) {
+ if (st_args == p_args) {
+ return;
+ }
+
st_args = p_args;
for (int i = 0; i < text.size(); i++) {
text.set(i, text[i], structured_text_parser(st_parser, st_args, text[i]));
@@ -2917,6 +2921,10 @@ int TextEdit::get_tab_size() const {
// User controls
void TextEdit::set_overtype_mode_enabled(const bool p_enabled) {
+ if (overtype_mode == p_enabled) {
+ return;
+ }
+
overtype_mode = p_enabled;
update();
}
@@ -3036,6 +3044,10 @@ int TextEdit::get_line_count() const {
}
void TextEdit::set_placeholder(const String &p_text) {
+ if (placeholder_text == p_text) {
+ return;
+ }
+
placeholder_text = p_text;
_update_placeholder();
update();
@@ -3945,6 +3957,10 @@ bool TextEdit::is_mouse_over_selection(bool p_edges) const {
/* Caret */
void TextEdit::set_caret_type(CaretType p_type) {
+ if (caret_type == p_type) {
+ return;
+ }
+
caret_type = p_type;
update();
}
@@ -3954,6 +3970,10 @@ TextEdit::CaretType TextEdit::get_caret_type() const {
}
void TextEdit::set_caret_blink_enabled(const bool p_enabled) {
+ if (caret_blink_enabled == p_enabled) {
+ return;
+ }
+
caret_blink_enabled = p_enabled;
if (has_focus()) {
@@ -4114,6 +4134,10 @@ String TextEdit::get_word_under_caret() const {
/* Selection. */
void TextEdit::set_selecting_enabled(const bool p_enabled) {
+ if (selecting_enabled == p_enabled) {
+ return;
+ }
+
selecting_enabled = p_enabled;
if (!selecting_enabled) {
@@ -4126,6 +4150,10 @@ bool TextEdit::is_selecting_enabled() const {
}
void TextEdit::set_deselect_on_focus_loss_enabled(const bool p_enabled) {
+ if (deselect_on_focus_loss_enabled == p_enabled) {
+ return;
+ }
+
deselect_on_focus_loss_enabled = p_enabled;
if (p_enabled && selection.active && !has_focus()) {
deselect();
@@ -4431,6 +4459,10 @@ bool TextEdit::is_smooth_scroll_enabled() const {
}
void TextEdit::set_scroll_past_end_of_file_enabled(const bool p_enabled) {
+ if (scroll_past_end_of_file_enabled == p_enabled) {
+ return;
+ }
+
scroll_past_end_of_file_enabled = p_enabled;
update();
}
@@ -4714,10 +4746,12 @@ void TextEdit::center_viewport_to_caret() {
/* Minimap */
void TextEdit::set_draw_minimap(bool p_enabled) {
- if (draw_minimap != p_enabled) {
- draw_minimap = p_enabled;
- _update_wrap_at_column();
+ if (draw_minimap == p_enabled) {
+ return;
}
+
+ draw_minimap = p_enabled;
+ _update_wrap_at_column();
update();
}
@@ -4726,10 +4760,12 @@ bool TextEdit::is_drawing_minimap() const {
}
void TextEdit::set_minimap_width(int p_minimap_width) {
- if (minimap_width != p_minimap_width) {
- minimap_width = p_minimap_width;
- _update_wrap_at_column();
+ if (minimap_width == p_minimap_width) {
+ return;
}
+
+ minimap_width = p_minimap_width;
+ _update_wrap_at_column();
update();
}
@@ -4780,6 +4816,11 @@ String TextEdit::get_gutter_name(int p_gutter) const {
void TextEdit::set_gutter_type(int p_gutter, GutterType p_type) {
ERR_FAIL_INDEX(p_gutter, gutters.size());
+
+ if (gutters[p_gutter].type == p_type) {
+ return;
+ }
+
gutters.write[p_gutter].type = p_type;
update();
}
@@ -4823,6 +4864,11 @@ bool TextEdit::is_gutter_drawn(int p_gutter) const {
void TextEdit::set_gutter_clickable(int p_gutter, bool p_clickable) {
ERR_FAIL_INDEX(p_gutter, gutters.size());
+
+ if (gutters[p_gutter].clickable == p_clickable) {
+ return;
+ }
+
gutters.write[p_gutter].clickable = p_clickable;
update();
}
@@ -4878,6 +4924,10 @@ void TextEdit::merge_gutters(int p_from_line, int p_to_line) {
void TextEdit::set_gutter_custom_draw(int p_gutter, const Callable &p_draw_callback) {
ERR_FAIL_INDEX(p_gutter, gutters.size());
+ if (gutters[p_gutter].custom_draw_callback == p_draw_callback) {
+ return;
+ }
+
gutters.write[p_gutter].custom_draw_callback = p_draw_callback;
update();
}
@@ -4898,6 +4948,11 @@ Variant TextEdit::get_line_gutter_metadata(int p_line, int p_gutter) const {
void TextEdit::set_line_gutter_text(int p_line, int p_gutter, const String &p_text) {
ERR_FAIL_INDEX(p_line, text.size());
ERR_FAIL_INDEX(p_gutter, gutters.size());
+
+ if (text.get_line_gutter_text(p_line, p_gutter) == p_text) {
+ return;
+ }
+
text.set_line_gutter_text(p_line, p_gutter, p_text);
update();
}
@@ -4911,6 +4966,11 @@ String TextEdit::get_line_gutter_text(int p_line, int p_gutter) const {
void TextEdit::set_line_gutter_icon(int p_line, int p_gutter, const Ref<Texture2D> &p_icon) {
ERR_FAIL_INDEX(p_line, text.size());
ERR_FAIL_INDEX(p_gutter, gutters.size());
+
+ if (text.get_line_gutter_icon(p_line, p_gutter) == p_icon) {
+ return;
+ }
+
text.set_line_gutter_icon(p_line, p_gutter, p_icon);
update();
}
@@ -4924,6 +4984,11 @@ Ref<Texture2D> TextEdit::get_line_gutter_icon(int p_line, int p_gutter) const {
void TextEdit::set_line_gutter_item_color(int p_line, int p_gutter, const Color &p_color) {
ERR_FAIL_INDEX(p_line, text.size());
ERR_FAIL_INDEX(p_gutter, gutters.size());
+
+ if (text.get_line_gutter_item_color(p_line, p_gutter) == p_color) {
+ return;
+ }
+
text.set_line_gutter_item_color(p_line, p_gutter, p_color);
update();
}
@@ -4949,6 +5014,11 @@ bool TextEdit::is_line_gutter_clickable(int p_line, int p_gutter) const {
// Line style
void TextEdit::set_line_background_color(int p_line, const Color &p_color) {
ERR_FAIL_INDEX(p_line, text.size());
+
+ if (text.get_line_background_color(p_line) == p_color) {
+ return;
+ }
+
text.set_line_background_color(p_line, p_color);
update();
}
@@ -4960,6 +5030,10 @@ Color TextEdit::get_line_background_color(int p_line) const {
/* Syntax Highlighting. */
void TextEdit::set_syntax_highlighter(Ref<SyntaxHighlighter> p_syntax_highlighter) {
+ if (syntax_highlighter == p_syntax_highlighter && syntax_highlighter.is_valid() == p_syntax_highlighter.is_valid()) {
+ return;
+ }
+
syntax_highlighter = p_syntax_highlighter;
if (syntax_highlighter.is_valid()) {
syntax_highlighter->set_text_edit(this);
@@ -4973,6 +5047,10 @@ Ref<SyntaxHighlighter> TextEdit::get_syntax_highlighter() const {
/* Visual. */
void TextEdit::set_highlight_current_line(bool p_enabled) {
+ if (highlight_current_line == p_enabled) {
+ return;
+ }
+
highlight_current_line = p_enabled;
update();
}
@@ -4982,6 +5060,10 @@ bool TextEdit::is_highlight_current_line_enabled() const {
}
void TextEdit::set_highlight_all_occurrences(const bool p_enabled) {
+ if (highlight_all_occurrences == p_enabled) {
+ return;
+ }
+
highlight_all_occurrences = p_enabled;
update();
}
@@ -5008,6 +5090,10 @@ bool TextEdit::get_draw_control_chars() const {
}
void TextEdit::set_draw_tabs(bool p_enabled) {
+ if (draw_tabs == p_enabled) {
+ return;
+ }
+
draw_tabs = p_enabled;
update();
}
@@ -5017,6 +5103,10 @@ bool TextEdit::is_drawing_tabs() const {
}
void TextEdit::set_draw_spaces(bool p_enabled) {
+ if (draw_spaces == p_enabled) {
+ return;
+ }
+
draw_spaces = p_enabled;
update();
}
@@ -5294,7 +5384,7 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_v_scroll_speed", "speed"), &TextEdit::set_v_scroll_speed);
ClassDB::bind_method(D_METHOD("get_v_scroll_speed"), &TextEdit::get_v_scroll_speed);
- ClassDB::bind_method(D_METHOD("set_fit_content_height_enabled"), &TextEdit::set_fit_content_height_enabled);
+ ClassDB::bind_method(D_METHOD("set_fit_content_height_enabled", "enabled"), &TextEdit::set_fit_content_height_enabled);
ClassDB::bind_method(D_METHOD("is_fit_content_height_enabled"), &TextEdit::is_fit_content_height_enabled);
ClassDB::bind_method(D_METHOD("get_scroll_pos_for_line", "line", "wrap_index"), &TextEdit::get_scroll_pos_for_line, DEFVAL(0));
@@ -5462,6 +5552,10 @@ void TextEdit::_bind_methods() {
/* Internal API for CodeEdit. */
// Line hiding.
void TextEdit::_set_hiding_enabled(bool p_enabled) {
+ if (hiding_enabled == p_enabled) {
+ return;
+ }
+
if (!p_enabled) {
_unhide_all_lines();
}
@@ -5488,6 +5582,11 @@ void TextEdit::_unhide_all_lines() {
void TextEdit::_set_line_as_hidden(int p_line, bool p_hidden) {
ERR_FAIL_INDEX(p_line, text.size());
+
+ if (text.is_hidden(p_line) == p_hidden) {
+ return;
+ }
+
if (_is_hiding_enabled() || !p_hidden) {
text.set_hidden(p_line, p_hidden);
}
@@ -5496,6 +5595,10 @@ void TextEdit::_set_line_as_hidden(int p_line, bool p_hidden) {
// Symbol lookup.
void TextEdit::_set_symbol_lookup_word(const String &p_symbol) {
+ if (lookup_symbol_word == p_symbol) {
+ return;
+ }
+
lookup_symbol_word = p_symbol;
update();
}
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 6711cf8c7f..f97f99075c 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -195,6 +195,9 @@ private:
void set(int p_line, const String &p_text, const Array &p_bidi_override);
void set_hidden(int p_line, bool p_hidden) {
+ if (text[p_line].hidden == p_hidden) {
+ return;
+ }
text.write[p_line].hidden = p_hidden;
if (!p_hidden && text[p_line].width > max_width) {
max_width = text[p_line].width;
diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp
index 26acfaaa70..916bb2981e 100644
--- a/scene/gui/texture_button.cpp
+++ b/scene/gui/texture_button.cpp
@@ -294,29 +294,48 @@ void TextureButton::_bind_methods() {
}
void TextureButton::set_normal_texture(const Ref<Texture2D> &p_normal) {
+ if (normal == p_normal) {
+ return;
+ }
+
normal = p_normal;
update();
update_minimum_size();
}
void TextureButton::set_pressed_texture(const Ref<Texture2D> &p_pressed) {
+ if (pressed == p_pressed) {
+ return;
+ }
+
pressed = p_pressed;
update();
update_minimum_size();
}
void TextureButton::set_hover_texture(const Ref<Texture2D> &p_hover) {
+ if (hover == p_hover) {
+ return;
+ }
+
hover = p_hover;
update();
update_minimum_size();
}
void TextureButton::set_disabled_texture(const Ref<Texture2D> &p_disabled) {
+ if (disabled == p_disabled) {
+ return;
+ }
+
disabled = p_disabled;
update();
}
void TextureButton::set_click_mask(const Ref<BitMap> &p_click_mask) {
+ if (click_mask == p_click_mask) {
+ return;
+ }
click_mask = p_click_mask;
update();
update_minimum_size();
@@ -355,12 +374,20 @@ bool TextureButton::get_ignore_texture_size() const {
}
void TextureButton::set_ignore_texture_size(bool p_ignore) {
+ if (ignore_texture_size == p_ignore) {
+ return;
+ }
+
ignore_texture_size = p_ignore;
update_minimum_size();
update();
}
void TextureButton::set_stretch_mode(StretchMode p_stretch_mode) {
+ if (stretch_mode == p_stretch_mode) {
+ return;
+ }
+
stretch_mode = p_stretch_mode;
update();
}
@@ -370,6 +397,10 @@ TextureButton::StretchMode TextureButton::get_stretch_mode() const {
}
void TextureButton::set_flip_h(bool p_flip) {
+ if (hflip == p_flip) {
+ return;
+ }
+
hflip = p_flip;
update();
}
@@ -379,6 +410,10 @@ bool TextureButton::is_flipped_h() const {
}
void TextureButton::set_flip_v(bool p_flip) {
+ if (vflip == p_flip) {
+ return;
+ }
+
vflip = p_flip;
update();
}
diff --git a/scene/gui/texture_progress_bar.cpp b/scene/gui/texture_progress_bar.cpp
index 94e0a6f226..2a9e1a8990 100644
--- a/scene/gui/texture_progress_bar.cpp
+++ b/scene/gui/texture_progress_bar.cpp
@@ -33,6 +33,10 @@
#include "core/config/engine.h"
void TextureProgressBar::set_under_texture(const Ref<Texture2D> &p_texture) {
+ if (under == p_texture) {
+ return;
+ }
+
under = p_texture;
update();
update_minimum_size();
@@ -43,6 +47,10 @@ Ref<Texture2D> TextureProgressBar::get_under_texture() const {
}
void TextureProgressBar::set_over_texture(const Ref<Texture2D> &p_texture) {
+ if (over == p_texture) {
+ return;
+ }
+
over = p_texture;
update();
if (under.is_null()) {
@@ -56,6 +64,11 @@ Ref<Texture2D> TextureProgressBar::get_over_texture() const {
void TextureProgressBar::set_stretch_margin(Side p_side, int p_size) {
ERR_FAIL_INDEX((int)p_side, 4);
+
+ if (stretch_margin[p_side] == p_size) {
+ return;
+ }
+
stretch_margin[p_side] = p_size;
update();
update_minimum_size();
@@ -67,6 +80,10 @@ int TextureProgressBar::get_stretch_margin(Side p_side) const {
}
void TextureProgressBar::set_nine_patch_stretch(bool p_stretch) {
+ if (nine_patch_stretch == p_stretch) {
+ return;
+ }
+
nine_patch_stretch = p_stretch;
update();
update_minimum_size();
@@ -91,6 +108,10 @@ Size2 TextureProgressBar::get_minimum_size() const {
}
void TextureProgressBar::set_progress_texture(const Ref<Texture2D> &p_texture) {
+ if (progress == p_texture) {
+ return;
+ }
+
progress = p_texture;
update();
update_minimum_size();
@@ -101,6 +122,10 @@ Ref<Texture2D> TextureProgressBar::get_progress_texture() const {
}
void TextureProgressBar::set_progress_offset(Point2 p_offset) {
+ if (progress_offset == p_offset) {
+ return;
+ }
+
progress_offset = p_offset;
update();
}
@@ -110,6 +135,10 @@ Point2 TextureProgressBar::get_progress_offset() const {
}
void TextureProgressBar::set_tint_under(const Color &p_tint) {
+ if (tint_under == p_tint) {
+ return;
+ }
+
tint_under = p_tint;
update();
}
@@ -119,6 +148,10 @@ Color TextureProgressBar::get_tint_under() const {
}
void TextureProgressBar::set_tint_progress(const Color &p_tint) {
+ if (tint_progress == p_tint) {
+ return;
+ }
+
tint_progress = p_tint;
update();
}
@@ -128,6 +161,10 @@ Color TextureProgressBar::get_tint_progress() const {
}
void TextureProgressBar::set_tint_over(const Color &p_tint) {
+ if (tint_over == p_tint) {
+ return;
+ }
+
tint_over = p_tint;
update();
}
@@ -548,6 +585,11 @@ void TextureProgressBar::_notification(int p_what) {
void TextureProgressBar::set_fill_mode(int p_fill) {
ERR_FAIL_INDEX(p_fill, FILL_MODE_MAX);
+
+ if (mode == (FillMode)p_fill) {
+ return;
+ }
+
mode = (FillMode)p_fill;
update();
}
@@ -563,6 +605,11 @@ void TextureProgressBar::set_radial_initial_angle(float p_angle) {
while (p_angle < 0) {
p_angle += 360;
}
+
+ if (rad_init_angle == p_angle) {
+ return;
+ }
+
rad_init_angle = p_angle;
update();
}
@@ -572,7 +619,13 @@ float TextureProgressBar::get_radial_initial_angle() {
}
void TextureProgressBar::set_fill_degrees(float p_angle) {
- rad_max_degrees = CLAMP(p_angle, 0, 360);
+ float angle_clamped = CLAMP(p_angle, 0, 360);
+
+ if (rad_max_degrees == angle_clamped) {
+ return;
+ }
+
+ rad_max_degrees = angle_clamped;
update();
}
@@ -581,6 +634,10 @@ float TextureProgressBar::get_fill_degrees() {
}
void TextureProgressBar::set_radial_center_offset(const Point2 &p_off) {
+ if (rad_center_off == p_off) {
+ return;
+ }
+
rad_center_off = p_off;
update();
}
diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp
index ecdf55caf0..4dd1c74c12 100644
--- a/scene/gui/texture_rect.cpp
+++ b/scene/gui/texture_rect.cpp
@@ -179,6 +179,10 @@ Ref<Texture2D> TextureRect::get_texture() const {
}
void TextureRect::set_ignore_texture_size(bool p_ignore) {
+ if (ignore_texture_size == p_ignore) {
+ return;
+ }
+
ignore_texture_size = p_ignore;
update();
update_minimum_size();
@@ -189,6 +193,10 @@ bool TextureRect::get_ignore_texture_size() const {
}
void TextureRect::set_stretch_mode(StretchMode p_mode) {
+ if (stretch_mode == p_mode) {
+ return;
+ }
+
stretch_mode = p_mode;
update();
}
@@ -198,6 +206,10 @@ TextureRect::StretchMode TextureRect::get_stretch_mode() const {
}
void TextureRect::set_flip_h(bool p_flip) {
+ if (hflip == p_flip) {
+ return;
+ }
+
hflip = p_flip;
update();
}
@@ -207,6 +219,10 @@ bool TextureRect::is_flipped_h() const {
}
void TextureRect::set_flip_v(bool p_flip) {
+ if (vflip == p_flip) {
+ return;
+ }
+
vflip = p_flip;
update();
}
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 1eb6c5a554..2b19ee4d0b 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -141,6 +141,10 @@ void TreeItem::_change_tree(Tree *p_tree) {
void TreeItem::set_cell_mode(int p_column, TreeCellMode p_mode) {
ERR_FAIL_INDEX(p_column, cells.size());
+ if (cells[p_column].mode == p_mode) {
+ return;
+ }
+
Cell &c = cells.write[p_column];
c.mode = p_mode;
c.min = 0;
@@ -166,6 +170,10 @@ TreeItem::TreeCellMode TreeItem::get_cell_mode(int p_column) const {
void TreeItem::set_checked(int p_column, bool p_checked) {
ERR_FAIL_INDEX(p_column, cells.size());
+ if (cells[p_column].checked == p_checked) {
+ return;
+ }
+
cells.write[p_column].checked = p_checked;
cells.write[p_column].indeterminate = false;
cells.write[p_column].cached_minimum_size_dirty = true;
@@ -259,6 +267,11 @@ void TreeItem::_propagate_check_through_parents(int p_column, bool p_emit_signal
void TreeItem::set_text(int p_column, String p_text) {
ERR_FAIL_INDEX(p_column, cells.size());
+
+ if (cells[p_column].text == p_text) {
+ return;
+ }
+
cells.write[p_column].text = p_text;
cells.write[p_column].dirty = true;
@@ -290,11 +303,14 @@ String TreeItem::get_text(int p_column) const {
void TreeItem::set_text_direction(int p_column, Control::TextDirection p_text_direction) {
ERR_FAIL_INDEX(p_column, cells.size());
ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3);
- if (cells[p_column].text_direction != p_text_direction) {
- cells.write[p_column].text_direction = p_text_direction;
- cells.write[p_column].dirty = true;
- _changed_notify(p_column);
+
+ if (cells[p_column].text_direction == p_text_direction) {
+ return;
}
+
+ cells.write[p_column].text_direction = p_text_direction;
+ cells.write[p_column].dirty = true;
+ _changed_notify(p_column);
cells.write[p_column].cached_minimum_size_dirty = true;
}
@@ -323,6 +339,10 @@ TextServer::StructuredTextParser TreeItem::get_structured_text_bidi_override(int
void TreeItem::set_structured_text_bidi_override_options(int p_column, Array p_args) {
ERR_FAIL_INDEX(p_column, cells.size());
+ if (cells[p_column].st_args == p_args) {
+ return;
+ }
+
cells.write[p_column].st_args = p_args;
cells.write[p_column].dirty = true;
cells.write[p_column].cached_minimum_size_dirty = true;
@@ -355,6 +375,10 @@ String TreeItem::get_language(int p_column) const {
void TreeItem::set_suffix(int p_column, String p_suffix) {
ERR_FAIL_INDEX(p_column, cells.size());
+ if (cells[p_column].suffix == p_suffix) {
+ return;
+ }
+
cells.write[p_column].suffix = p_suffix;
cells.write[p_column].cached_minimum_size_dirty = true;
@@ -369,6 +393,10 @@ String TreeItem::get_suffix(int p_column) const {
void TreeItem::set_icon(int p_column, const Ref<Texture2D> &p_icon) {
ERR_FAIL_INDEX(p_column, cells.size());
+ if (cells[p_column].icon == p_icon) {
+ return;
+ }
+
cells.write[p_column].icon = p_icon;
cells.write[p_column].cached_minimum_size_dirty = true;
@@ -383,6 +411,10 @@ Ref<Texture2D> TreeItem::get_icon(int p_column) const {
void TreeItem::set_icon_region(int p_column, const Rect2 &p_icon_region) {
ERR_FAIL_INDEX(p_column, cells.size());
+ if (cells[p_column].icon_region == p_icon_region) {
+ return;
+ }
+
cells.write[p_column].icon_region = p_icon_region;
cells.write[p_column].cached_minimum_size_dirty = true;
@@ -396,6 +428,11 @@ Rect2 TreeItem::get_icon_region(int p_column) const {
void TreeItem::set_icon_modulate(int p_column, const Color &p_modulate) {
ERR_FAIL_INDEX(p_column, cells.size());
+
+ if (cells[p_column].icon_color == p_modulate) {
+ return;
+ }
+
cells.write[p_column].icon_color = p_modulate;
_changed_notify(p_column);
}
@@ -408,6 +445,10 @@ Color TreeItem::get_icon_modulate(int p_column) const {
void TreeItem::set_icon_max_width(int p_column, int p_max) {
ERR_FAIL_INDEX(p_column, cells.size());
+ if (cells[p_column].icon_max_w == p_max) {
+ return;
+ }
+
cells.write[p_column].icon_max_w = p_max;
cells.write[p_column].cached_minimum_size_dirty = true;
@@ -432,6 +473,10 @@ void TreeItem::set_range(int p_column, double p_value) {
p_value = cells[p_column].max;
}
+ if (cells[p_column].val == p_value) {
+ return;
+ }
+
cells.write[p_column].val = p_value;
cells.write[p_column].dirty = true;
_changed_notify(p_column);
@@ -449,6 +494,11 @@ bool TreeItem::is_range_exponential(int p_column) const {
void TreeItem::set_range_config(int p_column, double p_min, double p_max, double p_step, bool p_exp) {
ERR_FAIL_INDEX(p_column, cells.size());
+
+ if (cells[p_column].min == p_min && cells[p_column].max == p_max && cells[p_column].step == p_step && cells[p_column].expr == p_exp) {
+ return;
+ }
+
cells.write[p_column].min = p_min;
cells.write[p_column].max = p_max;
cells.write[p_column].step = p_step;
@@ -537,6 +587,10 @@ void TreeItem::uncollapse_tree() {
}
void TreeItem::set_custom_minimum_height(int p_height) {
+ if (custom_min_height == p_height) {
+ return;
+ }
+
custom_min_height = p_height;
for (Cell &c : cells) {
@@ -748,9 +802,10 @@ int TreeItem::get_child_count() {
return children_cache.size();
}
-Array TreeItem::get_children() {
+TypedArray<TreeItem> TreeItem::get_children() {
+ // Don't need to explicitly create children cache, because get_child_count creates it.
int size = get_child_count();
- Array arr;
+ TypedArray<TreeItem> arr;
arr.resize(size);
for (int i = 0; i < size; i++) {
arr[i] = children_cache[i];
@@ -770,6 +825,22 @@ int TreeItem::get_index() {
return idx - 1;
}
+#ifdef DEV_ENABLED
+void TreeItem::validate_cache() const {
+ if (!parent || parent->children_cache.is_empty()) {
+ return;
+ }
+ TreeItem *scan = parent->first_child;
+ int index = 0;
+ while (scan) {
+ DEV_ASSERT(parent->children_cache[index] == scan);
+ ++index;
+ scan = scan->get_next();
+ }
+ DEV_ASSERT(index == parent->children_cache.size());
+}
+#endif
+
void TreeItem::move_before(TreeItem *p_item) {
ERR_FAIL_NULL(p_item);
ERR_FAIL_COND(is_root);
@@ -797,7 +868,11 @@ void TreeItem::move_before(TreeItem *p_item) {
parent->children_cache.clear();
} else {
parent->first_child = this;
- parent->children_cache.insert(0, this);
+ // If the cache is empty, it has not been built but there
+ // are items in the tree (note p_item != nullptr,) so we cannot update it.
+ if (!parent->children_cache.is_empty()) {
+ parent->children_cache.insert(0, this);
+ }
}
prev = item_prev;
@@ -807,6 +882,8 @@ void TreeItem::move_before(TreeItem *p_item) {
if (tree && old_tree == tree) {
tree->update();
}
+
+ validate_cache();
}
void TreeItem::move_after(TreeItem *p_item) {
@@ -839,12 +916,17 @@ void TreeItem::move_after(TreeItem *p_item) {
if (next) {
parent->children_cache.clear();
} else {
- parent->children_cache.append(this);
+ // If the cache is empty, it has not been built but there
+ // are items in the tree (note p_item != nullptr,) so we cannot update it.
+ if (!parent->children_cache.is_empty()) {
+ parent->children_cache.append(this);
+ }
}
if (tree && old_tree == tree) {
tree->update();
}
+ validate_cache();
}
void TreeItem::remove_child(TreeItem *p_item) {
@@ -859,6 +941,7 @@ void TreeItem::remove_child(TreeItem *p_item) {
if (tree) {
tree->update();
}
+ validate_cache();
}
void TreeItem::set_selectable(int p_column, bool p_selectable) {
@@ -884,6 +967,9 @@ void TreeItem::set_as_cursor(int p_column) {
if (tree->select_mode != Tree::SELECT_MULTI) {
return;
}
+ if (tree->selected_col == p_column) {
+ return;
+ }
tree->selected_item = this;
tree->selected_col = p_column;
tree->update();
@@ -961,6 +1047,11 @@ void TreeItem::set_button(int p_column, int p_idx, const Ref<Texture2D> &p_butto
ERR_FAIL_COND(p_button.is_null());
ERR_FAIL_INDEX(p_column, cells.size());
ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size());
+
+ if (cells[p_column].buttons[p_idx].texture == p_button) {
+ return;
+ }
+
cells.write[p_column].buttons.write[p_idx].texture = p_button;
cells.write[p_column].cached_minimum_size_dirty = true;
@@ -970,6 +1061,11 @@ void TreeItem::set_button(int p_column, int p_idx, const Ref<Texture2D> &p_butto
void TreeItem::set_button_color(int p_column, int p_idx, const Color &p_color) {
ERR_FAIL_INDEX(p_column, cells.size());
ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size());
+
+ if (cells[p_column].buttons[p_idx].color == p_color) {
+ return;
+ }
+
cells.write[p_column].buttons.write[p_idx].color = p_color;
_changed_notify(p_column);
}
@@ -978,6 +1074,10 @@ void TreeItem::set_button_disabled(int p_column, int p_idx, bool p_disabled) {
ERR_FAIL_INDEX(p_column, cells.size());
ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size());
+ if (cells[p_column].buttons[p_idx].disabled == p_disabled) {
+ return;
+ }
+
cells.write[p_column].buttons.write[p_idx].disabled = p_disabled;
cells.write[p_column].cached_minimum_size_dirty = true;
@@ -994,6 +1094,10 @@ bool TreeItem::is_button_disabled(int p_column, int p_idx) const {
void TreeItem::set_editable(int p_column, bool p_editable) {
ERR_FAIL_INDEX(p_column, cells.size());
+ if (cells[p_column].editable == p_editable) {
+ return;
+ }
+
cells.write[p_column].editable = p_editable;
cells.write[p_column].cached_minimum_size_dirty = true;
@@ -1007,6 +1111,11 @@ bool TreeItem::is_editable(int p_column) {
void TreeItem::set_custom_color(int p_column, const Color &p_color) {
ERR_FAIL_INDEX(p_column, cells.size());
+
+ if (cells[p_column].custom_color == true) {
+ return;
+ }
+
cells.write[p_column].custom_color = true;
cells.write[p_column].color = p_color;
_changed_notify(p_column);
@@ -1063,6 +1172,11 @@ String TreeItem::get_tooltip(int p_column) const {
void TreeItem::set_custom_bg_color(int p_column, const Color &p_color, bool p_bg_outline) {
ERR_FAIL_INDEX(p_column, cells.size());
+
+ if (cells[p_column].custom_bg_color && cells[p_column].custom_bg_outline == p_bg_outline && cells[p_column].bg_color == p_color) {
+ return;
+ }
+
cells.write[p_column].custom_bg_color = true;
cells.write[p_column].custom_bg_outline = p_bg_outline;
cells.write[p_column].bg_color = p_color;
@@ -1099,6 +1213,10 @@ bool TreeItem::is_custom_set_as_button(int p_column) const {
void TreeItem::set_text_alignment(int p_column, HorizontalAlignment p_alignment) {
ERR_FAIL_INDEX(p_column, cells.size());
+ if (cells[p_column].text_alignment == p_alignment) {
+ return;
+ }
+
cells.write[p_column].text_alignment = p_alignment;
cells.write[p_column].cached_minimum_size_dirty = true;
@@ -1113,6 +1231,10 @@ HorizontalAlignment TreeItem::get_text_alignment(int p_column) const {
void TreeItem::set_expand_right(int p_column, bool p_enable) {
ERR_FAIL_INDEX(p_column, cells.size());
+ if (cells[p_column].expand_right == p_enable) {
+ return;
+ }
+
cells.write[p_column].expand_right = p_enable;
cells.write[p_column].cached_minimum_size_dirty = true;
@@ -1125,6 +1247,10 @@ bool TreeItem::get_expand_right(int p_column) const {
}
void TreeItem::set_disable_folding(bool p_disable) {
+ if (disable_folding == p_disable) {
+ return;
+ }
+
disable_folding = p_disable;
for (Cell &c : cells) {
@@ -1396,6 +1522,7 @@ TreeItem::TreeItem(Tree *p_tree) {
TreeItem::~TreeItem() {
_unlink_from_tree();
+ validate_cache();
prev = nullptr;
clear_children();
_change_tree(nullptr);
@@ -3310,7 +3437,8 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
bool rtl = is_layout_rtl();
if (!mb->is_pressed()) {
- if (mb->get_button_index() == MouseButton::LEFT) {
+ if (mb->get_button_index() == MouseButton::LEFT ||
+ mb->get_button_index() == MouseButton::RIGHT) {
Point2 pos = mb->get_position();
if (rtl) {
pos.x = get_size().width - pos.x;
@@ -3324,14 +3452,16 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
int len = 0;
for (int i = 0; i < columns.size(); i++) {
len += get_column_width(i);
- if (pos.x < len) {
- emit_signal(SNAME("column_title_pressed"), i);
+ if (pos.x < static_cast<real_t>(len)) {
+ emit_signal(SNAME("column_title_clicked"), i, mb->get_button_index());
break;
}
}
}
}
+ }
+ if (mb->get_button_index() == MouseButton::LEFT) {
if (single_select_defer) {
select_single_item(single_select_defer, root, single_select_defer_column);
single_select_defer = nullptr;
@@ -3419,18 +3549,15 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
pos.y -= _get_title_button_height();
if (pos.y < 0) {
- if (mb->get_button_index() == MouseButton::LEFT) {
- pos.x += cache.offset.x;
- int len = 0;
- for (int i = 0; i < columns.size(); i++) {
- len += get_column_width(i);
- if (pos.x < len) {
- cache.click_type = Cache::CLICK_TITLE;
- cache.click_index = i;
- //cache.click_id=;
- update();
- break;
- }
+ pos.x += cache.offset.x;
+ int len = 0;
+ for (int i = 0; i < columns.size(); i++) {
+ len += get_column_width(i);
+ if (pos.x < static_cast<real_t>(len)) {
+ cache.click_type = Cache::CLICK_TITLE;
+ cache.click_index = i;
+ update();
+ break;
}
}
break;
@@ -3591,12 +3718,17 @@ bool Tree::edit_selected() {
} else if (c.mode == TreeItem::CELL_MODE_STRING || c.mode == TreeItem::CELL_MODE_RANGE) {
Rect2 popup_rect;
- Vector2 ofs(0, (text_editor->get_size().height - rect.size.height) / 2);
+ Vector2 ofs(0, Math::floor((text_editor->get_size().height - rect.size.height) / 2)); // "floor()" centers vertically.
Point2i textedpos = get_screen_position() + rect.position - ofs;
cache.text_editor_position = textedpos;
popup_rect.position = textedpos;
popup_rect.size = rect.size;
+
+ // Account for icon.
+ popup_rect.position.x += c.get_icon_size().x;
+ popup_rect.size.x -= c.get_icon_size().x;
+
text_editor->clear();
text_editor->set_text(c.mode == TreeItem::CELL_MODE_STRING ? c.text : String::num(c.val, Math::range_step_decimals(c.step)));
text_editor->select_all();
@@ -4068,6 +4200,10 @@ void Tree::clear() {
};
void Tree::set_hide_root(bool p_enabled) {
+ if (hide_root == p_enabled) {
+ return;
+ }
+
hide_root = p_enabled;
update();
}
@@ -4079,6 +4215,10 @@ bool Tree::is_root_hidden() const {
void Tree::set_column_custom_minimum_width(int p_column, int p_min_width) {
ERR_FAIL_INDEX(p_column, columns.size());
+ if (columns[p_column].custom_min_width == p_min_width) {
+ return;
+ }
+
if (p_min_width < 0) {
return;
}
@@ -4089,12 +4229,21 @@ void Tree::set_column_custom_minimum_width(int p_column, int p_min_width) {
void Tree::set_column_expand(int p_column, bool p_expand) {
ERR_FAIL_INDEX(p_column, columns.size());
+ if (columns[p_column].expand == p_expand) {
+ return;
+ }
+
columns.write[p_column].expand = p_expand;
update();
}
void Tree::set_column_expand_ratio(int p_column, int p_ratio) {
ERR_FAIL_INDEX(p_column, columns.size());
+
+ if (columns[p_column].expand_ratio == p_ratio) {
+ return;
+ }
+
columns.write[p_column].expand_ratio = p_ratio;
update();
}
@@ -4102,6 +4251,10 @@ void Tree::set_column_expand_ratio(int p_column, int p_ratio) {
void Tree::set_column_clip_content(int p_column, bool p_fit) {
ERR_FAIL_INDEX(p_column, columns.size());
+ if (columns[p_column].clip_content == p_fit) {
+ return;
+ }
+
columns.write[p_column].clip_content = p_fit;
update();
}
@@ -4424,6 +4577,10 @@ Rect2 Tree::get_item_rect(TreeItem *p_item, int p_column, int p_button) const {
}
void Tree::set_column_titles_visible(bool p_show) {
+ if (show_column_titles == p_show) {
+ return;
+ }
+
show_column_titles = p_show;
update();
}
@@ -4434,6 +4591,11 @@ bool Tree::are_column_titles_visible() const {
void Tree::set_column_title(int p_column, const String &p_title) {
ERR_FAIL_INDEX(p_column, columns.size());
+
+ if (columns[p_column].title == p_title) {
+ return;
+ }
+
if (cache.font.is_null()) { // avoid a strange case that may corrupt stuff
update_cache();
}
@@ -4515,6 +4677,10 @@ void Tree::scroll_to_item(TreeItem *p_item, bool p_center_on_item) {
}
void Tree::set_h_scroll_enabled(bool p_enable) {
+ if (h_scroll_enabled == p_enable) {
+ return;
+ }
+
h_scroll_enabled = p_enable;
update_minimum_size();
}
@@ -4524,6 +4690,10 @@ bool Tree::is_h_scroll_enabled() const {
}
void Tree::set_v_scroll_enabled(bool p_enable) {
+ if (v_scroll_enabled == p_enable) {
+ return;
+ }
+
v_scroll_enabled = p_enable;
update_minimum_size();
}
@@ -4852,6 +5022,10 @@ void Tree::set_cursor_can_exit_tree(bool p_enable) {
}
void Tree::set_hide_folding(bool p_hide) {
+ if (hide_folding == p_hide) {
+ return;
+ }
+
hide_folding = p_hide;
update();
}
@@ -4997,7 +5171,7 @@ void Tree::_bind_methods() {
ADD_SIGNAL(MethodInfo("button_clicked", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"), PropertyInfo(Variant::INT, "column"), PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::INT, "mouse_button_index")));
ADD_SIGNAL(MethodInfo("custom_popup_edited", PropertyInfo(Variant::BOOL, "arrow_clicked")));
ADD_SIGNAL(MethodInfo("item_activated"));
- ADD_SIGNAL(MethodInfo("column_title_pressed", PropertyInfo(Variant::INT, "column")));
+ ADD_SIGNAL(MethodInfo("column_title_clicked", PropertyInfo(Variant::INT, "column"), PropertyInfo(Variant::INT, "mouse_button_index")));
ADD_SIGNAL(MethodInfo("nothing_selected"));
BIND_ENUM_CONSTANT(SELECT_SINGLE);
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index f0819e2980..7f9c00b1b9 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -339,9 +339,16 @@ public:
TreeItem *get_child(int p_idx);
int get_visible_child_count();
int get_child_count();
- Array get_children();
+ TypedArray<TreeItem> get_children();
int get_index();
+#ifdef DEV_ENABLED
+ // This debugging code can be removed once the current refactoring of this class is complete.
+ void validate_cache() const;
+#else
+ void validate_cache() const {}
+#endif
+
void move_before(TreeItem *p_item);
void move_after(TreeItem *p_item);
diff --git a/scene/gui/video_stream_player.cpp b/scene/gui/video_stream_player.cpp
index f20a2ad67b..4024d4c80e 100644
--- a/scene/gui/video_stream_player.cpp
+++ b/scene/gui/video_stream_player.cpp
@@ -208,6 +208,10 @@ Size2 VideoStreamPlayer::get_minimum_size() const {
}
void VideoStreamPlayer::set_expand(bool p_expand) {
+ if (expand == p_expand) {
+ return;
+ }
+
expand = p_expand;
update();
update_minimum_size();
@@ -306,6 +310,10 @@ bool VideoStreamPlayer::is_playing() const {
}
void VideoStreamPlayer::set_paused(bool p_paused) {
+ if (paused == p_paused) {
+ return;
+ }
+
paused = p_paused;
if (!p_paused && !can_process()) {
paused_from_tree = true;
@@ -354,7 +362,7 @@ void VideoStreamPlayer::set_volume_db(float p_db) {
if (p_db < -79) {
set_volume(0);
} else {
- set_volume(Math::db2linear(p_db));
+ set_volume(Math::db_to_linear(p_db));
}
}
@@ -362,7 +370,7 @@ float VideoStreamPlayer::get_volume_db() const {
if (volume == 0) {
return -80;
} else {
- return Math::linear2db(volume);
+ return Math::linear_to_db(volume);
}
}
diff --git a/scene/gui/video_stream_player.h b/scene/gui/video_stream_player.h
index 913e7905b6..9974eb8488 100644
--- a/scene/gui/video_stream_player.h
+++ b/scene/gui/video_stream_player.h
@@ -79,7 +79,7 @@ class VideoStreamPlayer : public Control {
protected:
static void _bind_methods();
void _notification(int p_notification);
- void _validate_property(PropertyInfo &p_property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
Size2 get_minimum_size() const override;
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index ce204c6aeb..515f4d88a6 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -587,6 +587,12 @@ void CanvasItem::draw_msdf_texture_rect_region(const Ref<Texture2D> &p_texture,
RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(canvas_item, p_rect, p_texture->get_rid(), p_src_rect, p_modulate, p_outline, p_pixel_range);
}
+void CanvasItem::draw_lcd_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate) {
+ ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
+ ERR_FAIL_COND(p_texture.is_null());
+ RenderingServer::get_singleton()->canvas_item_add_lcd_texture_rect_region(canvas_item, p_rect, p_texture->get_rid(), p_src_rect, p_modulate);
+}
+
void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
@@ -919,6 +925,7 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture", "rect", "tile", "modulate", "transpose"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_texture_rect_region", "texture", "rect", "src_rect", "modulate", "transpose", "clip_uv"), &CanvasItem::draw_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false), DEFVAL(true));
ClassDB::bind_method(D_METHOD("draw_msdf_texture_rect_region", "texture", "rect", "src_rect", "modulate", "outline", "pixel_range"), &CanvasItem::draw_msdf_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(0.0), DEFVAL(4.0));
+ ClassDB::bind_method(D_METHOD("draw_lcd_texture_rect_region", "texture", "rect", "src_rect", "modulate"), &CanvasItem::draw_lcd_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)));
ClassDB::bind_method(D_METHOD("draw_style_box", "style_box", "rect"), &CanvasItem::draw_style_box);
ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture", "width"), &CanvasItem::draw_primitive, DEFVAL(Ref<Texture2D>()), DEFVAL(1.0));
ClassDB::bind_method(D_METHOD("draw_polygon", "points", "colors", "uvs", "texture"), &CanvasItem::draw_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>()));
@@ -986,7 +993,7 @@ void CanvasItem::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask");
ADD_GROUP("Texture", "texture_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Aniso.,Linear Mipmap Aniso."), "set_texture_filter", "get_texture_filter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropic,Linear Mipmap Anisotropic"), "set_texture_filter", "get_texture_filter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Inherit,Disabled,Enabled,Mirror"), "set_texture_repeat", "get_texture_repeat");
ADD_GROUP("Material", "");
@@ -1326,7 +1333,7 @@ void CanvasTexture::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "specular_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_specular_color", "get_specular_color");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "specular_shininess", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_specular_shininess", "get_specular_shininess");
ADD_GROUP("Texture", "texture_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Aniso.,Linear Mipmap Aniso."), "set_texture_filter", "get_texture_filter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropic,Linear Mipmap Anisotropic"), "set_texture_filter", "get_texture_filter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Inherit,Disabled,Enabled,Mirror"), "set_texture_repeat", "get_texture_repeat");
}
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index 38e0be1683..1e0d4552ce 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -226,6 +226,7 @@ public:
void draw_texture_rect(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false);
void draw_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = false);
void draw_msdf_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), double p_outline = 0.0, double p_pixel_range = 4.0);
+ void draw_lcd_texture_rect_region(const Ref<Texture2D> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1));
void draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect);
void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture = Ref<Texture2D>(), real_t p_width = 1);
void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture2D> p_texture = Ref<Texture2D>());
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp
index 3a071ef542..4890db995a 100644
--- a/scene/main/canvas_layer.cpp
+++ b/scene/main/canvas_layer.cpp
@@ -286,9 +286,9 @@ void CanvasLayer::_update_follow_viewport(bool p_force_exit) {
}
}
-void CanvasLayer::_validate_property(PropertyInfo &property) const {
- if (!follow_viewport && property.name == "follow_viewport_scale") {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void CanvasLayer::_validate_property(PropertyInfo &p_property) const {
+ if (!follow_viewport && p_property.name == "follow_viewport_scale") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
@@ -335,7 +335,7 @@ void CanvasLayer::_bind_methods() {
ADD_GROUP("", "");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", PROPERTY_USAGE_NONE), "set_custom_viewport", "get_custom_viewport");
ADD_GROUP("Follow Viewport", "follow_viewport");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_viewport_enable"), "set_follow_viewport", "is_following_viewport");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_viewport_enabled"), "set_follow_viewport", "is_following_viewport");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "follow_viewport_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001,or_greater,or_lesser"), "set_follow_viewport_scale", "get_follow_viewport_scale");
ADD_SIGNAL(MethodInfo("visibility_changed"));
diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h
index 2493675b31..74b5ebd453 100644
--- a/scene/main/canvas_layer.h
+++ b/scene/main/canvas_layer.h
@@ -64,7 +64,7 @@ class CanvasLayer : public Node {
protected:
void _notification(int p_what);
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_layer(int p_xform);
diff --git a/scene/main/multiplayer_api.cpp b/scene/main/multiplayer_api.cpp
index 95574042a8..2d2103f031 100644
--- a/scene/main/multiplayer_api.cpp
+++ b/scene/main/multiplayer_api.cpp
@@ -59,18 +59,18 @@ Ref<MultiplayerAPI> MultiplayerAPI::create_default_interface() {
// The variant is compressed and encoded; The first byte contains all the meta
// information and the format is:
-// - The first LSB 5 bits are used for the variant type.
+// - The first LSB 6 bits are used for the variant type.
// - The next two bits are used to store the encoding mode.
-// - The most significant is used to store the boolean value.
-#define VARIANT_META_TYPE_MASK 0x1F
-#define VARIANT_META_EMODE_MASK 0x60
+// - Boolean values uses the encoding mode to store the value.
+#define VARIANT_META_TYPE_MASK 0x3F
+#define VARIANT_META_EMODE_MASK 0xC0
#define VARIANT_META_BOOL_MASK 0x80
-#define ENCODE_8 0 << 5
-#define ENCODE_16 1 << 5
-#define ENCODE_32 2 << 5
-#define ENCODE_64 3 << 5
+#define ENCODE_8 0 << 6
+#define ENCODE_16 1 << 6
+#define ENCODE_32 2 << 6
+#define ENCODE_64 3 << 6
Error MultiplayerAPI::encode_and_compress_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bool p_allow_object_decoding) {
- // Unreachable because `VARIANT_MAX` == 27 and `ENCODE_VARIANT_MASK` == 31
+ // Unreachable because `VARIANT_MAX` == 38 and `ENCODE_VARIANT_MASK` == 77
CRASH_COND(p_variant.get_type() > VARIANT_META_TYPE_MASK);
uint8_t *buf = r_buffer;
@@ -80,9 +80,9 @@ Error MultiplayerAPI::encode_and_compress_variant(const Variant &p_variant, uint
switch (p_variant.get_type()) {
case Variant::BOOL: {
if (buf) {
- // We still have 1 free bit in the meta, so let's use it.
+ // We don't use encode_mode for booleans, so we can use it to store the value.
buf[0] = (p_variant.operator bool()) ? (1 << 7) : 0;
- buf[0] |= encode_mode | p_variant.get_type();
+ buf[0] |= p_variant.get_type();
}
r_len += 1;
} break;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 5c94c15a74..4b28e4076f 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -653,21 +653,6 @@ Error Node::_rpc_id_bind(const Variant **p_args, int p_argcount, Callable::CallE
return err;
}
-template <typename... VarArgs>
-Error Node::rpc(const StringName &p_method, VarArgs... p_args) {
- return rpc_id(0, p_method, p_args...);
-}
-
-template <typename... VarArgs>
-Error Node::rpc_id(int p_peer_id, const StringName &p_method, VarArgs... p_args) {
- Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
- const Variant *argptrs[sizeof...(p_args) + 1];
- for (uint32_t i = 0; i < sizeof...(p_args); i++) {
- argptrs[i] = &args[i];
- }
- return rpcp(p_peer_id, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
-}
-
Error Node::rpcp(int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount) {
ERR_FAIL_COND_V(!is_inside_tree(), ERR_UNCONFIGURED);
return get_multiplayer()->rpcp(this, p_peer_id, p_method, p_arg, p_argcount);
@@ -963,6 +948,21 @@ String Node::validate_child_name(Node *p_child) {
}
#endif
+String Node::adjust_name_casing(const String &p_name) {
+ switch (GLOBAL_GET("editor/node_naming/name_casing").operator int()) {
+ case NAME_CASING_PASCAL_CASE:
+ return p_name.capitalize().replace(" ", "");
+ case NAME_CASING_CAMEL_CASE: {
+ String name = p_name.capitalize().replace(" ", "");
+ name[0] = name.to_lower()[0];
+ return name;
+ }
+ case NAME_CASING_SNAKE_CASE:
+ return p_name.capitalize().replace(" ", "_").to_lower();
+ }
+ return p_name;
+}
+
void Node::_validate_child_name(Node *p_child, bool p_force_human_readable) {
/* Make sure the name is unique */
@@ -1036,19 +1036,8 @@ void Node::_generate_serial_child_name(const Node *p_child, StringName &name) co
//no name and a new name is needed, create one.
name = p_child->get_class();
- // Adjust casing according to project setting. The current type name is expected to be in PascalCase.
- switch (ProjectSettings::get_singleton()->get("editor/node_naming/name_casing").operator int()) {
- case NAME_CASING_PASCAL_CASE:
- break;
- case NAME_CASING_CAMEL_CASE: {
- String n = name;
- n[0] = n.to_lower()[0];
- name = n;
- } break;
- case NAME_CASING_SNAKE_CASE:
- name = String(name).camelcase_to_underscore(true);
- break;
- }
+ // Adjust casing according to project setting.
+ name = adjust_name_casing(name);
}
//quickly test if proposed name exists
@@ -1793,8 +1782,8 @@ void Node::remove_from_group(const StringName &p_identifier) {
data.grouped.remove(E);
}
-Array Node::_get_groups() const {
- Array groups;
+TypedArray<StringName> Node::_get_groups() const {
+ TypedArray<StringName> groups;
List<GroupInfo> gi;
get_groups(&gi);
for (const GroupInfo &E : gi) {
diff --git a/scene/main/node.h b/scene/main/node.h
index 13ca3abcd6..ae6a997579 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -181,7 +181,7 @@ private:
Node *_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap = nullptr) const;
TypedArray<Node> _get_children(bool p_include_internal = true) const;
- Array _get_groups() const;
+ TypedArray<StringName> _get_groups() const;
Error _rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
Error _rpc_id_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
@@ -459,6 +459,7 @@ public:
#ifdef TOOLS_ENABLED
String validate_child_name(Node *p_child);
#endif
+ static String adjust_name_casing(const String &p_name);
void queue_delete();
@@ -512,4 +513,22 @@ VARIANT_ENUM_CAST(Node::DuplicateFlags);
typedef HashSet<Node *, Node::Comparator> NodeSet;
+// Template definitions must be in the header so they are always fully initialized before their usage.
+// See this StackOverflow question for more information: https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file
+
+template <typename... VarArgs>
+Error Node::rpc(const StringName &p_method, VarArgs... p_args) {
+ return rpc_id(0, p_method, p_args...);
+}
+
+template <typename... VarArgs>
+Error Node::rpc_id(int p_peer_id, const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ return rpcp(p_peer_id, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+}
+
#endif // NODE_H
diff --git a/scene/main/resource_preloader.cpp b/scene/main/resource_preloader.cpp
index 5512d0a84e..a9b0285723 100644
--- a/scene/main/resource_preloader.cpp
+++ b/scene/main/resource_preloader.cpp
@@ -138,7 +138,7 @@ void ResourcePreloader::get_resource_list(List<StringName> *p_list) {
}
void ResourcePreloader::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_set_resources"), &ResourcePreloader::_set_resources);
+ ClassDB::bind_method(D_METHOD("_set_resources", "resources"), &ResourcePreloader::_set_resources);
ClassDB::bind_method(D_METHOD("_get_resources"), &ResourcePreloader::_get_resources);
ClassDB::bind_method(D_METHOD("add_resource", "name", "resource"), &ResourcePreloader::add_resource);
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 644fb3e9cc..e91e2f5c92 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -1000,8 +1000,8 @@ int64_t SceneTree::get_frame() const {
return current_frame;
}
-Array SceneTree::_get_nodes_in_group(const StringName &p_group) {
- Array ret;
+TypedArray<Node> SceneTree::_get_nodes_in_group(const StringName &p_group) {
+ TypedArray<Node> ret;
HashMap<StringName, Group>::Iterator E = group_map.find(p_group);
if (!E) {
return ret;
@@ -1171,8 +1171,8 @@ Ref<Tween> SceneTree::create_tween() {
return tween;
}
-Array SceneTree::get_processed_tweens() {
- Array ret;
+TypedArray<Tween> SceneTree::get_processed_tweens() {
+ TypedArray<Tween> ret;
ret.resize(tweens.size());
int i = 0;
@@ -1370,9 +1370,9 @@ void SceneTree::get_argument_options(const StringName &p_function, int p_idx, Li
}
if (dir_access->dir_exists(filename)) {
- directories.push_back(dir_access->get_current_dir().plus_file(filename));
+ directories.push_back(dir_access->get_current_dir().path_join(filename));
} else if (filename.ends_with(".tscn") || filename.ends_with(".scn")) {
- r_options->push_back("\"" + dir_access->get_current_dir().plus_file(filename) + "\"");
+ r_options->push_back("\"" + dir_access->get_current_dir().path_join(filename) + "\"");
}
filename = dir_access->get_next();
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index a512feacc8..e66363ab33 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -141,7 +141,7 @@ private:
_FORCE_INLINE_ void _update_group_order(Group &g, bool p_use_priority = false);
- Array _get_nodes_in_group(const StringName &p_group);
+ TypedArray<Node> _get_nodes_in_group(const StringName &p_group);
Node *current_scene = nullptr;
@@ -367,7 +367,7 @@ public:
Ref<SceneTreeTimer> create_timer(double p_delay_sec, bool p_process_always = true);
Ref<Tween> create_tween();
- Array get_processed_tweens();
+ TypedArray<Tween> get_processed_tweens();
//used by Main::start, don't use otherwise
void add_current_scene(Node *p_current);
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 4dd4c8419c..a5a4e29186 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -798,6 +798,7 @@ void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override,
RS::get_singleton()->viewport_set_size(viewport, 0, 0);
}
_update_global_transform();
+ update_configuration_warnings();
update_canvas_items();
@@ -1103,7 +1104,7 @@ Vector2 Viewport::get_mouse_position() const {
void Viewport::warp_mouse(const Vector2 &p_position) {
Transform2D xform = get_screen_transform();
- Vector2 gpos = xform.xform(p_position).round();
+ Vector2 gpos = xform.xform(p_position);
Input::get_singleton()->warp_mouse(gpos);
}
@@ -1708,15 +1709,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
is_tooltip_shown = true;
}
} else {
- Variant t = gui.tooltip_popup->call("get_tooltip_text");
-
- if (t.get_type() == Variant::STRING) {
- if (tooltip == String(t)) {
- is_tooltip_shown = true;
- }
- } else {
- is_tooltip_shown = true; // Nothing to compare against, likely using custom control, so if it changes there is nothing we can do.
- }
+ is_tooltip_shown = true; // Nothing to compare against, likely using custom control, so if it changes there is nothing we can do.
}
} else {
_gui_cancel_tooltip();
@@ -1875,7 +1868,9 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
}
- DisplayServer::get_singleton()->cursor_set_shape(ds_cursor_shape);
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CURSOR_SHAPE)) {
+ DisplayServer::get_singleton()->cursor_set_shape(ds_cursor_shape);
+ }
}
Ref<InputEventScreenTouch> touch_event = p_event;
@@ -2498,17 +2493,20 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
if (gui.subwindow_drag == SUB_WINDOW_DRAG_RESIZE) {
Vector2i diff = mm->get_position() - gui.subwindow_drag_from;
Size2i min_size = gui.subwindow_focused->get_min_size();
+
+ Size2i min_size_adjusted = min_size;
if (gui.subwindow_focused->is_wrapping_controls()) {
Size2i cms = gui.subwindow_focused->get_contents_minimum_size();
- min_size.x = MAX(cms.x, min_size.x);
- min_size.y = MAX(cms.y, min_size.y);
+ min_size_adjusted.x = MAX(cms.x, min_size.x);
+ min_size_adjusted.y = MAX(cms.y, min_size.y);
}
- min_size.x = MAX(min_size.x, 1);
- min_size.y = MAX(min_size.y, 1);
+
+ min_size_adjusted.x = MAX(min_size_adjusted.x, 1);
+ min_size_adjusted.y = MAX(min_size_adjusted.y, 1);
Rect2i r = gui.subwindow_resize_from_rect;
- Size2i limit = r.size - min_size;
+ Size2i limit = r.size - min_size_adjusted;
switch (gui.subwindow_resize_mode) {
case SUB_WINDOW_RESIZE_TOP_LEFT: {
@@ -2563,6 +2561,19 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
}
}
+ Size2i max_size = gui.subwindow_focused->get_max_size();
+ if ((max_size.x > 0 || max_size.y > 0) && (max_size.x >= min_size.x && max_size.y >= min_size.y)) {
+ max_size.x = MAX(max_size.x, 1);
+ max_size.y = MAX(max_size.y, 1);
+
+ if (r.size.x > max_size.x) {
+ r.size.x = max_size.x;
+ }
+ if (r.size.y > max_size.y) {
+ r.size.y = max_size.y;
+ }
+ }
+
gui.subwindow_focused->_rect_changed_callback(r);
}
@@ -2600,7 +2611,7 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
Ref<Texture2D> close_icon = sw.window->get_theme_icon(SNAME("close"));
Rect2 close_rect;
- close_rect.position = Vector2(r.position.x + r.size.x - close_v_ofs, r.position.y - close_h_ofs);
+ close_rect.position = Vector2(r.position.x + r.size.x - close_h_ofs, r.position.y - close_v_ofs);
close_rect.size = close_icon->get_size();
if (gui.subwindow_focused != sw.window) {
@@ -2668,7 +2679,9 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
DisplayServer::CURSOR_FDIAGSIZE
};
- DisplayServer::get_singleton()->cursor_set_shape(shapes[resize]);
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CURSOR_SHAPE)) {
+ DisplayServer::get_singleton()->cursor_set_shape(shapes[resize]);
+ }
return true; // Reserved for showing the resize cursor.
}
@@ -2833,8 +2846,8 @@ Variant Viewport::gui_get_drag_data() const {
TypedArray<String> Viewport::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
- if (size.x == 0 || size.y == 0) {
- warnings.push_back(RTR("Viewport size must be greater than 0 to render anything."));
+ if (size.x <= 1 || size.y <= 1) {
+ warnings.push_back(RTR("The Viewport size must be greater than or equal to 2 pixels on both dimensions to render anything."));
}
return warnings;
}
@@ -3937,9 +3950,9 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(VRS_MAX);
}
-void Viewport::_validate_property(PropertyInfo &property) const {
- if (vrs_mode != VRS_TEXTURE && (property.name == "vrs_texture")) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void Viewport::_validate_property(PropertyInfo &p_property) const {
+ if (vrs_mode != VRS_TEXTURE && (p_property.name == "vrs_texture")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 4221baff06..83083cd65a 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -563,7 +563,7 @@ public:
bool is_input_disabled() const;
Vector2 get_mouse_position() const;
- void warp_mouse(const Vector2 &p_position);
+ virtual void warp_mouse(const Vector2 &p_position);
void set_physics_object_picking(bool p_enable);
bool get_physics_object_picking();
@@ -709,7 +709,7 @@ public:
bool is_using_xr();
#endif // _3D_DISABLED
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
Viewport();
~Viewport();
};
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index bd72858ae6..5328ae7b8c 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -35,6 +35,7 @@
#include "core/string/translation.h"
#include "scene/gui/control.h"
#include "scene/scene_string_names.h"
+#include "scene/theme/theme_db.h"
void Window::set_title(const String &p_title) {
title = p_title;
@@ -242,8 +243,8 @@ void Window::_make_window() {
window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), vsync_mode, f, Rect2i(position, size));
ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID);
DisplayServer::get_singleton()->window_set_current_screen(current_screen, window_id);
- DisplayServer::get_singleton()->window_set_max_size(max_size, window_id);
- DisplayServer::get_singleton()->window_set_min_size(min_size, window_id);
+ DisplayServer::get_singleton()->window_set_max_size(Size2i(), window_id);
+ DisplayServer::get_singleton()->window_set_min_size(Size2i(), window_id);
String tr_title = atr(title);
#ifdef DEBUG_ENABLED
if (window_id == DisplayServer::MAIN_WINDOW_ID) {
@@ -349,7 +350,9 @@ void Window::_event_callback(DisplayServer::WindowEvent p_event) {
_propagate_window_notification(this, NOTIFICATION_WM_MOUSE_ENTER);
emit_signal(SNAME("mouse_entered"));
notification(NOTIFICATION_VP_MOUSE_ENTER);
- DisplayServer::get_singleton()->cursor_set_shape(DisplayServer::CURSOR_ARROW); //restore cursor shape
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CURSOR_SHAPE)) {
+ DisplayServer::get_singleton()->cursor_set_shape(DisplayServer::CURSOR_ARROW); //restore cursor shape
+ }
} break;
case DisplayServer::WINDOW_EVENT_MOUSE_EXIT: {
notification(NOTIFICATION_VP_MOUSE_EXIT);
@@ -596,20 +599,43 @@ void Window::_update_window_size() {
size.x = MAX(size_limit.x, size.x);
size.y = MAX(size_limit.y, size.y);
- if (max_size.x > 0 && max_size.x > min_size.x && size.x > max_size.x) {
- size.x = max_size.x;
- }
+ bool reset_min_first = false;
- if (max_size.y > 0 && max_size.y > min_size.y && size.y > max_size.y) {
- size.y = max_size.y;
+ bool max_size_valid = false;
+ if ((max_size.x > 0 || max_size.y > 0) && (max_size.x >= min_size.x && max_size.y >= min_size.y)) {
+ max_size_valid = true;
+
+ if (size.x > max_size.x) {
+ size.x = max_size.x;
+ }
+ if (size_limit.x > max_size.x) {
+ size_limit.x = max_size.x;
+ reset_min_first = true;
+ }
+
+ if (size.y > max_size.y) {
+ size.y = max_size.y;
+ }
+ if (size_limit.y > max_size.y) {
+ size_limit.y = max_size.y;
+ reset_min_first = true;
+ }
}
if (embedder) {
+ size.x = MAX(size.x, 1);
+ size.y = MAX(size.y, 1);
+
embedder->_sub_window_update(this);
} else if (window_id != DisplayServer::INVALID_WINDOW_ID) {
+ if (reset_min_first && wrap_controls) {
+ // Avoid an error if setting max_size to a value between min_size and the previous size_limit.
+ DisplayServer::get_singleton()->window_set_min_size(Size2i(), window_id);
+ }
+
DisplayServer::get_singleton()->window_set_size(size, window_id);
+ DisplayServer::get_singleton()->window_set_max_size(max_size_valid ? max_size : Size2i(), window_id);
DisplayServer::get_singleton()->window_set_min_size(size_limit, window_id);
- DisplayServer::get_singleton()->window_set_max_size(max_size, window_id);
}
//update the viewport
@@ -823,21 +849,13 @@ void Window::_notification(int p_what) {
RS::get_singleton()->viewport_set_active(get_viewport_rid(), true);
}
- if (theme.is_null()) {
- Control *parent_c = cast_to<Control>(get_parent());
- if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) {
- theme_owner = parent_c->data.theme_owner;
- theme_owner_window = parent_c->data.theme_owner_window;
- notification(NOTIFICATION_THEME_CHANGED);
- } else {
- Window *parent_w = cast_to<Window>(get_parent());
- if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) {
- theme_owner = parent_w->theme_owner;
- theme_owner_window = parent_w->theme_owner_window;
- notification(NOTIFICATION_THEME_CHANGED);
- }
- }
- }
+ // Need to defer here, because theme owner information might be set in
+ // add_child_notify, which doesn't get called until right after this.
+ call_deferred(SNAME("notification"), NOTIFICATION_THEME_CHANGED);
+ } break;
+
+ case NOTIFICATION_THEME_CHANGED: {
+ emit_signal(SceneStringNames::get_singleton()->theme_changed);
} break;
case NOTIFICATION_READY: {
@@ -949,10 +967,24 @@ DisplayServer::WindowID Window::get_window_id() const {
return window_id;
}
+void Window::warp_mouse(const Vector2 &p_position) {
+ Transform2D xform = get_screen_transform();
+ Vector2 gpos = xform.xform(p_position);
+
+ if (transient_parent && !transient_parent->is_embedding_subwindows()) {
+ Transform2D window_trans = Transform2D().translated(get_position() + (transient_parent->get_visible_rect().size - transient_parent->get_real_size()));
+ gpos = window_trans.xform(gpos);
+ }
+
+ Input::get_singleton()->warp_mouse(gpos);
+}
+
void Window::set_wrap_controls(bool p_enable) {
wrap_controls = p_enable;
if (wrap_controls) {
child_controls_changed();
+ } else {
+ _update_window_size();
}
}
@@ -1223,16 +1255,10 @@ Rect2i Window::get_usable_parent_rect() const {
}
void Window::add_child_notify(Node *p_child) {
- Control *child_c = Object::cast_to<Control>(p_child);
-
- if (child_c && child_c->data.theme.is_null() && (theme_owner || theme_owner_window)) {
- Control::_propagate_theme_changed(child_c, theme_owner, theme_owner_window); //need to propagate here, since many controls may require setting up stuff
- }
-
- Window *child_w = Object::cast_to<Window>(p_child);
-
- if (child_w && child_w->theme.is_null() && (theme_owner || theme_owner_window)) {
- Control::_propagate_theme_changed(child_w, theme_owner, theme_owner_window); //need to propagate here, since many controls may require setting up stuff
+ // We propagate when this node uses a custom theme, so it can pass it on to its children.
+ if (theme_owner || theme_owner_window) {
+ // `p_notify` is false here as `NOTIFICATION_THEME_CHANGED` will be handled by `NOTIFICATION_ENTER_TREE`.
+ Control::_propagate_theme_changed(this, theme_owner, theme_owner_window, false, true);
}
if (is_inside_tree() && wrap_controls) {
@@ -1241,16 +1267,9 @@ void Window::add_child_notify(Node *p_child) {
}
void Window::remove_child_notify(Node *p_child) {
- Control *child_c = Object::cast_to<Control>(p_child);
-
- if (child_c && (child_c->data.theme_owner || child_c->data.theme_owner_window) && child_c->data.theme.is_null()) {
- Control::_propagate_theme_changed(child_c, nullptr, nullptr);
- }
-
- Window *child_w = Object::cast_to<Window>(p_child);
-
- if (child_w && (child_w->theme_owner || child_w->theme_owner_window) && child_w->theme.is_null()) {
- Control::_propagate_theme_changed(child_w, nullptr, nullptr);
+ // If the removed child isn't inheriting any theme items through this node, then there's no need to propagate.
+ if (theme_owner || theme_owner_window) {
+ Control::_propagate_theme_changed(this, nullptr, nullptr, false, true);
}
if (is_inside_tree() && wrap_controls) {
@@ -1263,34 +1282,47 @@ void Window::set_theme(const Ref<Theme> &p_theme) {
return;
}
+ if (theme.is_valid()) {
+ theme->disconnect("changed", callable_mp(this, &Window::_theme_changed));
+ }
+
theme = p_theme;
+ if (theme.is_valid()) {
+ Control::_propagate_theme_changed(this, nullptr, this, is_inside_tree(), true);
+ theme->connect("changed", callable_mp(this, &Window::_theme_changed), CONNECT_DEFERRED);
+ return;
+ }
- if (!p_theme.is_null()) {
- theme_owner = nullptr;
- theme_owner_window = this;
- Control::_propagate_theme_changed(this, nullptr, this);
- } else {
- Control *parent_c = cast_to<Control>(get_parent());
- if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) {
- Control::_propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window);
- } else {
- Window *parent_w = cast_to<Window>(get_parent());
- if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) {
- Control::_propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window);
- } else {
- Control::_propagate_theme_changed(this, nullptr, nullptr);
- }
- }
+ Control *parent_c = Object::cast_to<Control>(get_parent());
+ if (parent_c && (parent_c->data.theme_owner || parent_c->data.theme_owner_window)) {
+ Control::_propagate_theme_changed(this, parent_c->data.theme_owner, parent_c->data.theme_owner_window, is_inside_tree(), true);
+ return;
+ }
+
+ Window *parent_w = cast_to<Window>(get_parent());
+ if (parent_w && (parent_w->theme_owner || parent_w->theme_owner_window)) {
+ Control::_propagate_theme_changed(this, parent_w->theme_owner, parent_w->theme_owner_window, is_inside_tree(), true);
+ return;
}
+
+ Control::_propagate_theme_changed(this, nullptr, nullptr, is_inside_tree(), true);
}
Ref<Theme> Window::get_theme() const {
return theme;
}
+void Window::_theme_changed() {
+ if (is_inside_tree()) {
+ Control::_propagate_theme_changed(this, nullptr, this, true, false);
+ }
+}
+
void Window::set_theme_type_variation(const StringName &p_theme_type) {
theme_type_variation = p_theme_type;
- Control::_propagate_theme_changed(this, theme_owner, theme_owner_window);
+ if (is_inside_tree()) {
+ notification(NOTIFICATION_THEME_CHANGED);
+ }
}
StringName Window::get_theme_type_variation() const {
@@ -1299,13 +1331,13 @@ StringName Window::get_theme_type_variation() const {
void Window::_get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const {
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) {
- if (Theme::get_project_default().is_valid() && Theme::get_project_default()->get_type_variation_base(theme_type_variation) != StringName()) {
- Theme::get_project_default()->get_type_dependencies(get_class_name(), theme_type_variation, p_list);
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid() && ThemeDB::get_singleton()->get_project_theme()->get_type_variation_base(theme_type_variation) != StringName()) {
+ ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), theme_type_variation, p_list);
} else {
- Theme::get_default()->get_type_dependencies(get_class_name(), theme_type_variation, p_list);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), theme_type_variation, p_list);
}
} else {
- Theme::get_default()->get_type_dependencies(p_theme_type, StringName(), p_list);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(p_theme_type, StringName(), p_list);
}
}
@@ -1485,15 +1517,15 @@ bool Window::is_auto_translating() const {
return auto_translate;
}
-void Window::_validate_property(PropertyInfo &property) const {
- if (property.name == "theme_type_variation") {
+void Window::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "theme_type_variation") {
List<StringName> names;
// Only the default theme and the project theme are used for the list of options.
// This is an imposed limitation to simplify the logic needed to leverage those options.
- Theme::get_default()->get_type_variation_list(get_class_name(), &names);
- if (Theme::get_project_default().is_valid()) {
- Theme::get_project_default()->get_type_variation_list(get_class_name(), &names);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_variation_list(get_class_name(), &names);
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
+ ThemeDB::get_singleton()->get_project_theme()->get_type_variation_list(get_class_name(), &names);
}
names.sort_custom<StringName::AlphCompare>();
@@ -1509,7 +1541,7 @@ void Window::_validate_property(PropertyInfo &property) const {
unique_names.append(E);
}
- property.hint_string = hint_string;
+ p_property.hint_string = hint_string;
}
}
@@ -1654,6 +1686,7 @@ void Window::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "transparent"), "set_flag", "get_flag", FLAG_TRANSPARENT);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "unfocusable"), "set_flag", "get_flag", FLAG_NO_FOCUS);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "popup_window"), "set_flag", "get_flag", FLAG_POPUP);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "extend_to_title"), "set_flag", "get_flag", FLAG_EXTEND_TO_TITLE);
ADD_GROUP("Limits", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "min_size", PROPERTY_HINT_NONE, "suffix:px"), "set_min_size", "get_min_size");
@@ -1685,6 +1718,7 @@ void Window::_bind_methods() {
ADD_SIGNAL(MethodInfo("theme_changed"));
BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED);
+ BIND_CONSTANT(NOTIFICATION_THEME_CHANGED);
BIND_ENUM_CONSTANT(MODE_WINDOWED);
BIND_ENUM_CONSTANT(MODE_MINIMIZED);
@@ -1698,6 +1732,7 @@ void Window::_bind_methods() {
BIND_ENUM_CONSTANT(FLAG_TRANSPARENT);
BIND_ENUM_CONSTANT(FLAG_NO_FOCUS);
BIND_ENUM_CONSTANT(FLAG_POPUP);
+ BIND_ENUM_CONSTANT(FLAG_EXTEND_TO_TITLE);
BIND_ENUM_CONSTANT(FLAG_MAX);
BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_DISABLED);
diff --git a/scene/main/window.h b/scene/main/window.h
index c060f1d79d..a5b6b26104 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -56,6 +56,7 @@ public:
FLAG_TRANSPARENT = DisplayServer::WINDOW_FLAG_TRANSPARENT,
FLAG_NO_FOCUS = DisplayServer::WINDOW_FLAG_NO_FOCUS,
FLAG_POPUP = DisplayServer::WINDOW_FLAG_POPUP,
+ FLAG_EXTEND_TO_TITLE = DisplayServer::WINDOW_FLAG_EXTEND_TO_TITLE,
FLAG_MAX = DisplayServer::WINDOW_FLAG_MAX,
};
@@ -158,7 +159,7 @@ protected:
virtual Size2 _get_contents_minimum_size() const;
static void _bind_methods();
void _notification(int p_what);
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
virtual void add_child_notify(Node *p_child) override;
virtual void remove_child_notify(Node *p_child) override;
@@ -239,6 +240,8 @@ public:
void set_use_font_oversampling(bool p_oversampling);
bool is_using_font_oversampling() const;
+ void warp_mouse(const Vector2 &p_position) override;
+
void set_wrap_controls(bool p_enable);
bool is_wrapping_controls() const;
void child_controls_changed();
@@ -253,6 +256,7 @@ public:
void set_theme(const Ref<Theme> &p_theme);
Ref<Theme> get_theme() const;
+ void _theme_changed();
void set_theme_type_variation(const StringName &p_theme_type);
StringName get_theme_type_variation() const;
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 0878a9f78f..6c7bc552bf 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -50,6 +50,7 @@
#include "scene/2d/light_2d.h"
#include "scene/2d/light_occluder_2d.h"
#include "scene/2d/line_2d.h"
+#include "scene/2d/marker_2d.h"
#include "scene/2d/mesh_instance_2d.h"
#include "scene/2d/multimesh_instance_2d.h"
#include "scene/2d/navigation_agent_2d.h"
@@ -60,7 +61,6 @@
#include "scene/2d/physical_bone_2d.h"
#include "scene/2d/physics_body_2d.h"
#include "scene/2d/polygon_2d.h"
-#include "scene/2d/position_2d.h"
#include "scene/2d/ray_cast_2d.h"
#include "scene/2d/remote_transform_2d.h"
#include "scene/2d/shape_cast_2d.h"
@@ -100,6 +100,7 @@
#include "scene/gui/line_edit.h"
#include "scene/gui/link_button.h"
#include "scene/gui/margin_container.h"
+#include "scene/gui/menu_bar.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/nine_patch_rect.h"
#include "scene/gui/option_button.h"
@@ -157,11 +158,11 @@
#include "scene/resources/immediate_mesh.h"
#include "scene/resources/label_settings.h"
#include "scene/resources/material.h"
-#include "scene/resources/mesh.h"
#include "scene/resources/mesh_data_tool.h"
+#include "scene/resources/multimesh.h"
#include "scene/resources/navigation_mesh.h"
#include "scene/resources/packed_scene.h"
-#include "scene/resources/particles_material.h"
+#include "scene/resources/particle_process_material.h"
#include "scene/resources/physics_material.h"
#include "scene/resources/polygon_path_finder.h"
#include "scene/resources/primitive_meshes.h"
@@ -192,12 +193,14 @@
#include "scene/resources/sky.h"
#include "scene/resources/sky_material.h"
#include "scene/resources/sphere_shape_3d.h"
+#include "scene/resources/style_box.h"
#include "scene/resources/surface_tool.h"
#include "scene/resources/syntax_highlighter.h"
#include "scene/resources/text_file.h"
#include "scene/resources/text_line.h"
#include "scene/resources/text_paragraph.h"
#include "scene/resources/texture.h"
+#include "scene/resources/theme.h"
#include "scene/resources/tile_set.h"
#include "scene/resources/video_stream.h"
#include "scene/resources/visual_shader.h"
@@ -209,6 +212,7 @@
#include "scene/resources/world_boundary_shape_2d.h"
#include "scene/resources/world_boundary_shape_3d.h"
#include "scene/scene_string_names.h"
+#include "scene/theme/theme_db.h"
#include "scene/main/shader_globals_override.h"
@@ -231,6 +235,7 @@
#include "scene/3d/light_3d.h"
#include "scene/3d/lightmap_gi.h"
#include "scene/3d/lightmap_probe.h"
+#include "scene/3d/marker_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/multimesh_instance_3d.h"
#include "scene/3d/navigation_agent_3d.h"
@@ -240,14 +245,13 @@
#include "scene/3d/occluder_instance_3d.h"
#include "scene/3d/path_3d.h"
#include "scene/3d/physics_body_3d.h"
-#include "scene/3d/position_3d.h"
#include "scene/3d/ray_cast_3d.h"
#include "scene/3d/reflection_probe.h"
#include "scene/3d/remote_transform_3d.h"
#include "scene/3d/shape_cast_3d.h"
#include "scene/3d/skeleton_3d.h"
#include "scene/3d/skeleton_ik_3d.h"
-#include "scene/3d/soft_dynamic_body_3d.h"
+#include "scene/3d/soft_body_3d.h"
#include "scene/3d/spring_arm_3d.h"
#include "scene/3d/sprite_3d.h"
#include "scene/3d/vehicle_body_3d.h"
@@ -259,7 +263,7 @@
#include "scene/resources/fog_material.h"
#include "scene/resources/importer_mesh.h"
#include "scene/resources/mesh_library.h"
-#endif
+#endif // _3D_DISABLED
static Ref<ResourceFormatSaverText> resource_saver_text;
static Ref<ResourceFormatLoaderText> resource_loader_text;
@@ -351,6 +355,7 @@ void register_scene_types() {
GDREGISTER_CLASS(VSlider);
GDREGISTER_CLASS(Popup);
GDREGISTER_CLASS(PopupPanel);
+ GDREGISTER_CLASS(MenuBar);
GDREGISTER_CLASS(MenuButton);
GDREGISTER_CLASS(CheckBox);
GDREGISTER_CLASS(CheckButton);
@@ -522,10 +527,8 @@ void register_scene_types() {
GDREGISTER_CLASS(GPUParticlesAttractorSphere3D);
GDREGISTER_CLASS(GPUParticlesAttractorVectorField3D);
GDREGISTER_CLASS(CPUParticles3D);
- GDREGISTER_CLASS(Position3D);
-
+ GDREGISTER_CLASS(Marker3D);
GDREGISTER_CLASS(RootMotionView);
- ClassDB::set_class_enabled("RootMotionView", false); // disabled by default, enabled by editor
OS::get_singleton()->yield(); // may take time to init
@@ -533,13 +536,13 @@ void register_scene_types() {
GDREGISTER_ABSTRACT_CLASS(PhysicsBody3D);
GDREGISTER_CLASS(StaticBody3D);
GDREGISTER_CLASS(AnimatableBody3D);
- GDREGISTER_CLASS(RigidDynamicBody3D);
+ GDREGISTER_CLASS(RigidBody3D);
GDREGISTER_CLASS(KinematicCollision3D);
GDREGISTER_CLASS(CharacterBody3D);
GDREGISTER_CLASS(SpringArm3D);
GDREGISTER_CLASS(PhysicalBone3D);
- GDREGISTER_CLASS(SoftDynamicBody3D);
+ GDREGISTER_CLASS(SoftBody3D);
GDREGISTER_CLASS(SkeletonIK3D);
GDREGISTER_CLASS(BoneAttachment3D);
@@ -575,7 +578,7 @@ void register_scene_types() {
GDREGISTER_CLASS(NavigationObstacle3D);
OS::get_singleton()->yield(); // may take time to init
-#endif
+#endif // _3D_DISABLED
/* REGISTER SHADER */
@@ -611,6 +614,7 @@ void register_scene_types() {
GDREGISTER_CLASS(VisualShaderNodeColorFunc);
GDREGISTER_CLASS(VisualShaderNodeTransformFunc);
GDREGISTER_CLASS(VisualShaderNodeUVFunc);
+ GDREGISTER_CLASS(VisualShaderNodeUVPolarCoord);
GDREGISTER_CLASS(VisualShaderNodeDotProduct);
GDREGISTER_CLASS(VisualShaderNodeVectorLen);
GDREGISTER_CLASS(VisualShaderNodeDeterminant);
@@ -649,6 +653,7 @@ void register_scene_types() {
GDREGISTER_CLASS(VisualShaderNodeTexture2DArrayUniform);
GDREGISTER_CLASS(VisualShaderNodeTexture3DUniform);
GDREGISTER_CLASS(VisualShaderNodeCubemapUniform);
+ GDREGISTER_CLASS(VisualShaderNodeLinearSceneDepth);
GDREGISTER_CLASS(VisualShaderNodeIf);
GDREGISTER_CLASS(VisualShaderNodeSwitch);
GDREGISTER_CLASS(VisualShaderNodeFresnel);
@@ -658,6 +663,10 @@ void register_scene_types() {
GDREGISTER_CLASS(VisualShaderNodeCompare);
GDREGISTER_CLASS(VisualShaderNodeMultiplyAdd);
GDREGISTER_CLASS(VisualShaderNodeBillboard);
+ GDREGISTER_CLASS(VisualShaderNodeDistanceFade);
+ GDREGISTER_CLASS(VisualShaderNodeProximityFade);
+ GDREGISTER_CLASS(VisualShaderNodeRandomRange);
+ GDREGISTER_CLASS(VisualShaderNodeRemap);
GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeVarying);
GDREGISTER_CLASS(VisualShaderNodeVaryingSetter);
GDREGISTER_CLASS(VisualShaderNodeVaryingGetter);
@@ -696,7 +705,7 @@ void register_scene_types() {
GDREGISTER_CLASS(Sprite2D);
GDREGISTER_CLASS(SpriteFrames);
GDREGISTER_CLASS(AnimatedSprite2D);
- GDREGISTER_CLASS(Position2D);
+ GDREGISTER_CLASS(Marker2D);
GDREGISTER_CLASS(Line2D);
GDREGISTER_CLASS(MeshInstance2D);
GDREGISTER_CLASS(MultiMeshInstance2D);
@@ -704,7 +713,7 @@ void register_scene_types() {
GDREGISTER_ABSTRACT_CLASS(PhysicsBody2D);
GDREGISTER_CLASS(StaticBody2D);
GDREGISTER_CLASS(AnimatableBody2D);
- GDREGISTER_CLASS(RigidDynamicBody2D);
+ GDREGISTER_CLASS(RigidBody2D);
GDREGISTER_CLASS(CharacterBody2D);
GDREGISTER_CLASS(KinematicCollision2D);
GDREGISTER_CLASS(Area2D);
@@ -761,13 +770,9 @@ void register_scene_types() {
/* REGISTER RESOURCES */
GDREGISTER_ABSTRACT_CLASS(Shader);
- GDREGISTER_CLASS(ParticlesMaterial);
- SceneTree::add_idle_callback(ParticlesMaterial::flush_changes);
- ParticlesMaterial::init_shaders();
-
- GDREGISTER_CLASS(ProceduralSkyMaterial);
- GDREGISTER_CLASS(PanoramaSkyMaterial);
- GDREGISTER_CLASS(PhysicalSkyMaterial);
+ GDREGISTER_CLASS(ParticleProcessMaterial);
+ SceneTree::add_idle_callback(ParticleProcessMaterial::flush_changes);
+ ParticleProcessMaterial::init_shaders();
GDREGISTER_VIRTUAL_CLASS(Mesh);
GDREGISTER_CLASS(ArrayMesh);
@@ -784,9 +789,9 @@ void register_scene_types() {
GDREGISTER_CLASS(CylinderMesh);
GDREGISTER_CLASS(PlaneMesh);
GDREGISTER_CLASS(PrismMesh);
- GDREGISTER_CLASS(QuadMesh);
GDREGISTER_CLASS(SphereMesh);
GDREGISTER_CLASS(TextMesh);
+ GDREGISTER_CLASS(TorusMesh);
GDREGISTER_CLASS(TubeTrailMesh);
GDREGISTER_CLASS(RibbonTrailMesh);
GDREGISTER_CLASS(PointMesh);
@@ -795,6 +800,9 @@ void register_scene_types() {
GDREGISTER_CLASS(StandardMaterial3D);
GDREGISTER_CLASS(ORMMaterial3D);
GDREGISTER_CLASS(PlaceholderMaterial);
+ GDREGISTER_CLASS(ProceduralSkyMaterial);
+ GDREGISTER_CLASS(PanoramaSkyMaterial);
+ GDREGISTER_CLASS(PhysicalSkyMaterial);
SceneTree::add_idle_callback(BaseMaterial3D::flush_changes);
BaseMaterial3D::init_shaders();
@@ -823,9 +831,7 @@ void register_scene_types() {
ClassDB::register_class<SkeletonModification3DStackHolder>();
OS::get_singleton()->yield(); // may take time to init
-
- GDREGISTER_CLASS(VelocityTracker3D);
-#endif
+#endif // _3D_DISABLED
GDREGISTER_CLASS(PhysicsMaterial);
GDREGISTER_CLASS(World3D);
@@ -844,7 +850,6 @@ void register_scene_types() {
GDREGISTER_CLASS(CurveXYZTexture);
GDREGISTER_CLASS(GradientTexture1D);
GDREGISTER_CLASS(GradientTexture2D);
- GDREGISTER_CLASS(ProxyTexture);
GDREGISTER_CLASS(AnimatedTexture);
GDREGISTER_CLASS(CameraTexture);
GDREGISTER_VIRTUAL_CLASS(TextureLayered);
@@ -946,6 +951,7 @@ void register_scene_types() {
ClassDB::add_compatibility_class("Navigation3D", "Node3D");
ClassDB::add_compatibility_class("Navigation2D", "Node2D");
ClassDB::add_compatibility_class("OpenSimplexNoise", "FastNoiseLite");
+ ClassDB::add_compatibility_class("QuadMesh", "PlaneMesh");
ClassDB::add_compatibility_class("ToolButton", "Button");
ClassDB::add_compatibility_class("YSort", "Node2D");
// Portal and room occlusion was replaced by raster occlusion (OccluderInstance3D node).
@@ -1022,6 +1028,7 @@ void register_scene_types() {
ClassDB::add_compatibility_class("PanoramaSky", "Sky");
ClassDB::add_compatibility_class("Particles", "GPUParticles3D");
ClassDB::add_compatibility_class("Particles2D", "GPUParticles2D");
+ ClassDB::add_compatibility_class("ParticlesMaterial", "ParticleProcessMaterial");
ClassDB::add_compatibility_class("Path", "Path3D");
ClassDB::add_compatibility_class("PathFollow", "PathFollow3D");
ClassDB::add_compatibility_class("PhysicalBone", "PhysicalBone3D");
@@ -1037,23 +1044,26 @@ void register_scene_types() {
ClassDB::add_compatibility_class("PhysicsShapeQueryParameters", "PhysicsShapeQueryParameters3D");
ClassDB::add_compatibility_class("PinJoint", "PinJoint3D");
ClassDB::add_compatibility_class("PlaneShape", "WorldBoundaryShape3D");
+ ClassDB::add_compatibility_class("Position2D", "Marker2D");
+ ClassDB::add_compatibility_class("Position3D", "Marker3D");
ClassDB::add_compatibility_class("ProceduralSky", "Sky");
ClassDB::add_compatibility_class("RayCast", "RayCast3D");
ClassDB::add_compatibility_class("RayShape", "SeparationRayShape3D");
ClassDB::add_compatibility_class("RayShape2D", "SeparationRayShape2D");
ClassDB::add_compatibility_class("RemoteTransform", "RemoteTransform3D");
- ClassDB::add_compatibility_class("RigidBody", "RigidDynamicBody3D");
- ClassDB::add_compatibility_class("RigidBody2D", "RigidDynamicBody2D");
+ ClassDB::add_compatibility_class("RigidBody", "RigidBody3D");
+ ClassDB::add_compatibility_class("RigidDynamicBody2D", "RigidBody2D");
+ ClassDB::add_compatibility_class("RigidDynamicBody3D", "RigidBody3D");
ClassDB::add_compatibility_class("Shape", "Shape3D");
ClassDB::add_compatibility_class("ShortCut", "Shortcut");
ClassDB::add_compatibility_class("Skeleton", "Skeleton3D");
ClassDB::add_compatibility_class("SkeletonIK", "SkeletonIK3D");
ClassDB::add_compatibility_class("SliderJoint", "SliderJoint3D");
- ClassDB::add_compatibility_class("SoftBody", "SoftDynamicBody3D");
+ ClassDB::add_compatibility_class("SoftBody", "SoftBody3D");
+ ClassDB::add_compatibility_class("SoftDynamicBody3D", "SoftBody3D");
ClassDB::add_compatibility_class("Spatial", "Node3D");
ClassDB::add_compatibility_class("SpatialGizmo", "Node3DGizmo");
ClassDB::add_compatibility_class("SpatialMaterial", "StandardMaterial3D");
- ClassDB::add_compatibility_class("SpatialVelocityTracker", "VelocityTracker3D");
ClassDB::add_compatibility_class("SphereShape", "SphereShape3D");
ClassDB::add_compatibility_class("SpotLight", "SpotLight3D");
ClassDB::add_compatibility_class("SpringArm", "SpringArm3D");
@@ -1123,58 +1133,8 @@ void register_scene_types() {
SceneDebugger::initialize();
}
-void initialize_theme() {
- // Allow creating the default theme at a different scale to suit higher/lower base resolutions.
- float default_theme_scale = GLOBAL_DEF("gui/theme/default_theme_scale", 1.0);
- ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_theme_scale", PropertyInfo(Variant::FLOAT, "gui/theme/default_theme_scale", PROPERTY_HINT_RANGE, "0.5,8,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
-
- String theme_path = GLOBAL_DEF_RST("gui/theme/custom", "");
- ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom", PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
-
- String font_path = GLOBAL_DEF_RST("gui/theme/custom_font", "");
- ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom_font", PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
-
- bool font_antialiased = (bool)GLOBAL_DEF_RST("gui/theme/default_font_antialiased", true);
- ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_antialiased", PropertyInfo(Variant::BOOL, "gui/theme/default_font_antialiased", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
-
- TextServer::Hinting font_hinting = (TextServer::Hinting)(int)GLOBAL_DEF_RST("gui/theme/default_font_hinting", TextServer::HINTING_LIGHT);
- ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_hinting", PropertyInfo(Variant::INT, "gui/theme/default_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
-
- TextServer::SubpixelPositioning font_subpixel_positioning = (TextServer::SubpixelPositioning)(int)GLOBAL_DEF_RST("gui/theme/default_font_subpixel_positioning", TextServer::SUBPIXEL_POSITIONING_AUTO);
- ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_subpixel_positioning", PropertyInfo(Variant::INT, "gui/theme/default_font_subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One half of a pixel,One quarter of a pixel", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
-
- const bool font_msdf = GLOBAL_DEF_RST("gui/theme/default_font_multichannel_signed_distance_field", false);
- const bool font_generate_mipmaps = GLOBAL_DEF_RST("gui/theme/default_font_generate_mipmaps", false);
-
- Ref<Font> font;
- if (!font_path.is_empty()) {
- font = ResourceLoader::load(font_path);
- if (!font.is_valid()) {
- ERR_PRINT("Error loading custom font '" + font_path + "'");
- }
- }
-
- // Always make the default theme to avoid invalid default font/icon/style in the given theme.
- if (RenderingServer::get_singleton()) {
- make_default_theme(default_theme_scale, font, font_subpixel_positioning, font_hinting, font_antialiased, font_msdf, font_generate_mipmaps);
- }
-
- if (!theme_path.is_empty()) {
- Ref<Theme> theme = ResourceLoader::load(theme_path);
- if (theme.is_valid()) {
- Theme::set_project_default(theme);
- if (font.is_valid()) {
- Theme::set_fallback_font(font);
- }
- } else {
- ERR_PRINT("Error loading custom theme '" + theme_path + "'");
- }
- }
-}
-
void unregister_scene_types() {
SceneDebugger::deinitialize();
- clear_default_theme();
ResourceLoader::remove_resource_format_loader(resource_loader_texture_layered);
resource_loader_texture_layered.unref();
@@ -1206,14 +1166,19 @@ void unregister_scene_types() {
// StandardMaterial3D is not initialised when 3D is disabled, so it shouldn't be cleaned up either
#ifndef _3D_DISABLED
BaseMaterial3D::finish_shaders();
-#endif // _3D_DISABLED
-
PhysicalSkyMaterial::cleanup_shader();
PanoramaSkyMaterial::cleanup_shader();
ProceduralSkyMaterial::cleanup_shader();
+#endif // _3D_DISABLED
- ParticlesMaterial::finish_shaders();
+ ParticleProcessMaterial::finish_shaders();
CanvasItemMaterial::finish_shaders();
ColorPicker::finish_shaders();
SceneStringNames::free();
}
+
+void register_scene_singletons() {
+ GDREGISTER_CLASS(ThemeDB);
+
+ Engine::get_singleton()->add_singleton(Engine::Singleton("ThemeDB", ThemeDB::get_singleton()));
+}
diff --git a/scene/register_scene_types.h b/scene/register_scene_types.h
index dce8713976..cb3249c5d7 100644
--- a/scene/register_scene_types.h
+++ b/scene/register_scene_types.h
@@ -33,7 +33,6 @@
void register_scene_types();
void unregister_scene_types();
-
-void initialize_theme();
+void register_scene_singletons();
#endif // REGISTER_SCENE_TYPES_H
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 69b30b72b0..9d5bc18c96 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -313,29 +313,37 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
Dictionary d = p_value;
ERR_FAIL_COND_V(!d.has("times"), false);
ERR_FAIL_COND_V(!d.has("points"), false);
-
Vector<real_t> times = d["times"];
Vector<real_t> values = d["points"];
+#ifdef TOOLS_ENABLED
+ ERR_FAIL_COND_V(!d.has("handle_modes"), false);
+ Vector<int> handle_modes = d["handle_modes"];
+#endif // TOOLS_ENABLED
- ERR_FAIL_COND_V(times.size() * 6 != values.size(), false);
+ ERR_FAIL_COND_V(times.size() * 5 != values.size(), false);
if (times.size()) {
int valcount = times.size();
const real_t *rt = times.ptr();
const real_t *rv = values.ptr();
+#ifdef TOOLS_ENABLED
+ const int *rh = handle_modes.ptr();
+#endif // TOOLS_ENABLED
bt->values.resize(valcount);
for (int i = 0; i < valcount; i++) {
bt->values.write[i].time = rt[i];
bt->values.write[i].transition = 0; //unused in bezier
- bt->values.write[i].value.value = rv[i * 6 + 0];
- bt->values.write[i].value.in_handle.x = rv[i * 6 + 1];
- bt->values.write[i].value.in_handle.y = rv[i * 6 + 2];
- bt->values.write[i].value.out_handle.x = rv[i * 6 + 3];
- bt->values.write[i].value.out_handle.y = rv[i * 6 + 4];
- bt->values.write[i].value.handle_mode = static_cast<HandleMode>((int)rv[i * 6 + 5]);
+ bt->values.write[i].value.value = rv[i * 5 + 0];
+ bt->values.write[i].value.in_handle.x = rv[i * 5 + 1];
+ bt->values.write[i].value.in_handle.y = rv[i * 5 + 2];
+ bt->values.write[i].value.out_handle.x = rv[i * 5 + 3];
+ bt->values.write[i].value.out_handle.y = rv[i * 5 + 4];
+#ifdef TOOLS_ENABLED
+ bt->values.write[i].value.handle_mode = static_cast<HandleMode>(rh[i]);
+#endif // TOOLS_ENABLED
}
}
@@ -699,28 +707,39 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const {
int kk = bt->values.size();
key_times.resize(kk);
- key_points.resize(kk * 6);
+ key_points.resize(kk * 5);
real_t *wti = key_times.ptrw();
real_t *wpo = key_points.ptrw();
+#ifdef TOOLS_ENABLED
+ Vector<int> handle_modes;
+ handle_modes.resize(kk);
+ int *whm = handle_modes.ptrw();
+#endif // TOOLS_ENABLED
+
int idx = 0;
const TKey<BezierKey> *vls = bt->values.ptr();
for (int i = 0; i < kk; i++) {
wti[idx] = vls[i].time;
- wpo[idx * 6 + 0] = vls[i].value.value;
- wpo[idx * 6 + 1] = vls[i].value.in_handle.x;
- wpo[idx * 6 + 2] = vls[i].value.in_handle.y;
- wpo[idx * 6 + 3] = vls[i].value.out_handle.x;
- wpo[idx * 6 + 4] = vls[i].value.out_handle.y;
- wpo[idx * 6 + 5] = (double)vls[i].value.handle_mode;
+ wpo[idx * 5 + 0] = vls[i].value.value;
+ wpo[idx * 5 + 1] = vls[i].value.in_handle.x;
+ wpo[idx * 5 + 2] = vls[i].value.in_handle.y;
+ wpo[idx * 5 + 3] = vls[i].value.out_handle.x;
+ wpo[idx * 5 + 4] = vls[i].value.out_handle.y;
+#ifdef TOOLS_ENABLED
+ whm[idx] = static_cast<int>(vls[i].value.handle_mode);
+#endif // TOOLS_ENABLED
idx++;
}
d["times"] = key_times;
d["points"] = key_points;
+#ifdef TOOLS_ENABLED
+ d["handle_modes"] = handle_modes;
+#endif // TOOLS_ENABLED
r_ret = d;
@@ -967,7 +986,6 @@ int Animation::find_track(const NodePath &p_path, const TrackType p_type) const
void Animation::track_set_interpolation_type(int p_track, InterpolationType p_interp) {
ERR_FAIL_INDEX(p_track, tracks.size());
- ERR_FAIL_INDEX(p_interp, 3);
tracks[p_track]->interpolation = p_interp;
emit_changed();
}
@@ -1627,7 +1645,7 @@ int Animation::track_insert_key(int p_track, double p_time, const Variant &p_key
BezierTrack *bt = static_cast<BezierTrack *>(t);
Array arr = p_key;
- ERR_FAIL_COND_V(arr.size() != 6, -1);
+ ERR_FAIL_COND_V(arr.size() != 5, -1);
TKey<BezierKey> k;
k.time = p_time;
@@ -1636,9 +1654,16 @@ int Animation::track_insert_key(int p_track, double p_time, const Variant &p_key
k.value.in_handle.y = arr[2];
k.value.out_handle.x = arr[3];
k.value.out_handle.y = arr[4];
- k.value.handle_mode = static_cast<HandleMode>((int)arr[5]);
ret = _insert(p_time, bt->values, k);
+ Vector<int> key_neighborhood;
+ key_neighborhood.push_back(ret);
+ if (ret > 0) {
+ key_neighborhood.push_back(ret - 1);
+ }
+ if (ret < track_get_key_count(p_track) - 1) {
+ key_neighborhood.push_back(ret + 1);
+ }
} break;
case TYPE_AUDIO: {
AudioTrack *at = static_cast<AudioTrack *>(t);
@@ -1777,13 +1802,12 @@ Variant Animation::track_get_key_value(int p_track, int p_key_idx) const {
ERR_FAIL_INDEX_V(p_key_idx, bt->values.size(), Variant());
Array arr;
- arr.resize(6);
+ arr.resize(5);
arr[0] = bt->values[p_key_idx].value.value;
arr[1] = bt->values[p_key_idx].value.in_handle.x;
arr[2] = bt->values[p_key_idx].value.in_handle.y;
arr[3] = bt->values[p_key_idx].value.out_handle.x;
arr[4] = bt->values[p_key_idx].value.out_handle.y;
- arr[5] = (double)bt->values[p_key_idx].value.handle_mode;
return arr;
} break;
@@ -2152,14 +2176,13 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p
ERR_FAIL_INDEX(p_key_idx, bt->values.size());
Array arr = p_value;
- ERR_FAIL_COND(arr.size() != 6);
+ ERR_FAIL_COND(arr.size() != 5);
bt->values.write[p_key_idx].value.value = arr[0];
bt->values.write[p_key_idx].value.in_handle.x = arr[1];
bt->values.write[p_key_idx].value.in_handle.y = arr[2];
bt->values.write[p_key_idx].value.out_handle.x = arr[3];
bt->values.write[p_key_idx].value.out_handle.y = arr[4];
- bt->values.write[p_key_idx].value.handle_mode = static_cast<HandleMode>((int)arr[5]);
} break;
case TYPE_AUDIO: {
@@ -2283,6 +2306,8 @@ int Animation::_find(const Vector<K> &p_keys, double p_time, bool p_backward) co
return middle;
}
+// Linear interpolation for anytype.
+
Vector3 Animation::_interpolate(const Vector3 &p_a, const Vector3 &p_b, real_t p_c) const {
return p_a.lerp(p_b, p_c);
}
@@ -2298,18 +2323,33 @@ Variant Animation::_interpolate(const Variant &p_a, const Variant &p_b, real_t p
}
real_t Animation::_interpolate(const real_t &p_a, const real_t &p_b, real_t p_c) const {
- return p_a * (1.0 - p_c) + p_b * p_c;
+ return Math::lerp(p_a, p_b, p_c);
}
-Vector3 Animation::_cubic_interpolate(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c) const {
- return p_a.cubic_interpolate(p_b, p_pre_a, p_post_b, p_c);
+Variant Animation::_interpolate_angle(const Variant &p_a, const Variant &p_b, real_t p_c) const {
+ Variant::Type type_a = p_a.get_type();
+ Variant::Type type_b = p_b.get_type();
+ uint32_t vformat = 1 << type_a;
+ vformat |= 1 << type_b;
+ if (vformat == ((1 << Variant::INT) | (1 << Variant::FLOAT)) || vformat == (1 << Variant::FLOAT)) {
+ real_t a = p_a;
+ real_t b = p_b;
+ return Math::fposmod((float)Math::lerp_angle(a, b, p_c), (float)Math_TAU);
+ }
+ return _interpolate(p_a, p_b, p_c);
+}
+
+// Cubic interpolation for anytype.
+
+Vector3 Animation::_cubic_interpolate_in_time(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const {
+ return p_a.cubic_interpolate_in_time(p_b, p_pre_a, p_post_b, p_c, p_b_t, p_pre_a_t, p_post_b_t);
}
-Quaternion Animation::_cubic_interpolate(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, real_t p_c) const {
- return p_a.spherical_cubic_interpolate(p_b, p_pre_a, p_post_b, p_c);
+Quaternion Animation::_cubic_interpolate_in_time(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const {
+ return p_a.spherical_cubic_interpolate_in_time(p_b, p_pre_a, p_post_b, p_c, p_b_t, p_pre_a_t, p_post_b_t);
}
-Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c) const {
+Variant Animation::_cubic_interpolate_in_time(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const {
Variant::Type type_a = p_a.get_type();
Variant::Type type_b = p_b.get_type();
Variant::Type type_pa = p_pre_a.get_type();
@@ -2329,7 +2369,7 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a
real_t pa = p_pre_a;
real_t pb = p_post_b;
- return Math::cubic_interpolate(a, b, pa, pb, p_c);
+ return Math::cubic_interpolate_in_time(a, b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t);
} else if ((vformat & (vformat - 1))) {
return p_a; //can't interpolate, mix of types
}
@@ -2341,7 +2381,7 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a
Vector2 pa = p_pre_a;
Vector2 pb = p_post_b;
- return a.cubic_interpolate(b, pa, pb, p_c);
+ return a.cubic_interpolate_in_time(b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t);
}
case Variant::RECT2: {
Rect2 a = p_a;
@@ -2350,8 +2390,8 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a
Rect2 pb = p_post_b;
return Rect2(
- a.position.cubic_interpolate(b.position, pa.position, pb.position, p_c),
- a.size.cubic_interpolate(b.size, pa.size, pb.size, p_c));
+ a.position.cubic_interpolate_in_time(b.position, pa.position, pb.position, p_c, p_b_t, p_pre_a_t, p_post_b_t),
+ a.size.cubic_interpolate_in_time(b.size, pa.size, pb.size, p_c, p_b_t, p_pre_a_t, p_post_b_t));
}
case Variant::VECTOR3: {
Vector3 a = p_a;
@@ -2359,7 +2399,7 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a
Vector3 pa = p_pre_a;
Vector3 pb = p_post_b;
- return a.cubic_interpolate(b, pa, pb, p_c);
+ return a.cubic_interpolate_in_time(b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t);
}
case Variant::QUATERNION: {
Quaternion a = p_a;
@@ -2367,7 +2407,7 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a
Quaternion pa = p_pre_a;
Quaternion pb = p_post_b;
- return a.spherical_cubic_interpolate(b, pa, pb, p_c);
+ return a.spherical_cubic_interpolate_in_time(b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t);
}
case Variant::AABB: {
AABB a = p_a;
@@ -2376,8 +2416,8 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a
AABB pb = p_post_b;
return AABB(
- a.position.cubic_interpolate(b.position, pa.position, pb.position, p_c),
- a.size.cubic_interpolate(b.size, pa.size, pb.size, p_c));
+ a.position.cubic_interpolate_in_time(b.position, pa.position, pb.position, p_c, p_b_t, p_pre_a_t, p_post_b_t),
+ a.size.cubic_interpolate_in_time(b.size, pa.size, pb.size, p_c, p_b_t, p_pre_a_t, p_post_b_t));
}
default: {
return _interpolate(p_a, p_b, p_c);
@@ -2385,7 +2425,26 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a
}
}
-real_t Animation::_cubic_interpolate(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c) const {
+real_t Animation::_cubic_interpolate_in_time(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const {
+ return Math::cubic_interpolate_in_time(p_a, p_b, p_pre_a, p_post_b, p_c, p_b_t, p_pre_a_t, p_post_b_t);
+}
+
+Variant Animation::_cubic_interpolate_angle_in_time(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const {
+ Variant::Type type_a = p_a.get_type();
+ Variant::Type type_b = p_b.get_type();
+ Variant::Type type_pa = p_pre_a.get_type();
+ Variant::Type type_pb = p_post_b.get_type();
+ uint32_t vformat = 1 << type_a;
+ vformat |= 1 << type_b;
+ vformat |= 1 << type_pa;
+ vformat |= 1 << type_pb;
+ if (vformat == ((1 << Variant::INT) | (1 << Variant::FLOAT)) || vformat == (1 << Variant::FLOAT)) {
+ real_t a = p_a;
+ real_t b = p_b;
+ real_t pa = p_pre_a;
+ real_t pb = p_post_b;
+ return Math::fposmod((float)Math::cubic_interpolate_angle_in_time(a, b, pa, pb, p_c, p_b_t, p_pre_a_t, p_post_b_t), (float)Math_TAU);
+ }
return _interpolate(p_a, p_b, p_c);
}
@@ -2568,26 +2627,70 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, double p_time, Interpol
case INTERPOLATION_LINEAR: {
return _interpolate(p_keys[idx].value, p_keys[next].value, c);
} break;
- case INTERPOLATION_CUBIC: {
- int pre = idx - 1;
- if (pre < 0) {
- if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
- pre = len - 1;
- } else {
- pre = 0;
+ case INTERPOLATION_LINEAR_ANGLE: {
+ return _interpolate_angle(p_keys[idx].value, p_keys[next].value, c);
+ } break;
+ case INTERPOLATION_CUBIC:
+ case INTERPOLATION_CUBIC_ANGLE: {
+ int pre = 0;
+ int post = 0;
+ if (!p_backward) {
+ pre = idx - 1;
+ if (pre < 0) {
+ if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
+ pre = len - 1;
+ } else {
+ pre = 0;
+ }
}
- }
- int post = next + 1;
- if (post >= len) {
- if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
- post = 0;
- } else {
- post = next;
+ post = next + 1;
+ if (post >= len) {
+ if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
+ post = 0;
+ } else {
+ post = next;
+ }
+ }
+ } else {
+ pre = idx + 1;
+ if (pre >= len) {
+ if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
+ pre = 0;
+ } else {
+ pre = idx;
+ }
+ }
+ post = next - 1;
+ if (post < 0) {
+ if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
+ post = len - 1;
+ } else {
+ post = 0;
+ }
}
}
- return _cubic_interpolate(p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c);
+ real_t pre_t = 0.0;
+ real_t to_t = 0.0;
+ real_t post_t = 0.0;
+ if (loop_mode == LOOP_LINEAR && p_loop_wrap) {
+ pre_t = pre > idx ? -length + p_keys[pre].time - p_keys[idx].time : p_keys[pre].time - p_keys[idx].time;
+ to_t = next < idx ? length + p_keys[next].time - p_keys[idx].time : p_keys[next].time - p_keys[idx].time;
+ post_t = next < idx || post <= idx ? length + p_keys[post].time - p_keys[idx].time : p_keys[post].time - p_keys[idx].time;
+ } else {
+ pre_t = p_keys[pre].time - p_keys[idx].time;
+ to_t = p_keys[next].time - p_keys[idx].time;
+ post_t = p_keys[post].time - p_keys[idx].time;
+ }
+ if (p_interp == INTERPOLATION_CUBIC_ANGLE) {
+ return _cubic_interpolate_angle_in_time(
+ p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c,
+ pre_t, to_t, post_t);
+ }
+ return _cubic_interpolate_in_time(
+ p_keys[pre].value, p_keys[idx].value, p_keys[next].value, p_keys[post].value, c,
+ pre_t, to_t, post_t);
} break;
default:
return p_keys[idx].value;
@@ -3215,7 +3318,7 @@ StringName Animation::method_track_get_name(int p_track, int p_key_idx) const {
return pm->methods[p_key_idx].method;
}
-int Animation::bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const HandleMode p_handle_mode) {
+int Animation::bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle) {
ERR_FAIL_INDEX_V(p_track, tracks.size(), -1);
Track *t = tracks[p_track];
ERR_FAIL_COND_V(t->type != TYPE_BEZIER, -1);
@@ -3233,7 +3336,6 @@ int Animation::bezier_track_insert_key(int p_track, double p_time, real_t p_valu
if (k.value.out_handle.x < 0) {
k.value.out_handle.x = 0;
}
- k.value.handle_mode = p_handle_mode;
int key = _insert(p_time, bt->values, k);
@@ -3242,30 +3344,6 @@ int Animation::bezier_track_insert_key(int p_track, double p_time, real_t p_valu
return key;
}
-void Animation::bezier_track_set_key_handle_mode(int p_track, int p_index, HandleMode p_mode, double p_balanced_value_time_ratio) {
- ERR_FAIL_INDEX(p_track, tracks.size());
- Track *t = tracks[p_track];
- ERR_FAIL_COND(t->type != TYPE_BEZIER);
-
- BezierTrack *bt = static_cast<BezierTrack *>(t);
-
- ERR_FAIL_INDEX(p_index, bt->values.size());
-
- bt->values.write[p_index].value.handle_mode = p_mode;
-
- if (p_mode == HANDLE_MODE_BALANCED) {
- Transform2D xform;
- xform.set_scale(Vector2(1.0, 1.0 / p_balanced_value_time_ratio));
-
- Vector2 vec_in = xform.xform(bt->values[p_index].value.in_handle);
- Vector2 vec_out = xform.xform(bt->values[p_index].value.out_handle);
-
- bt->values.write[p_index].value.in_handle = xform.affine_inverse().xform(-vec_out.normalized() * vec_in.length());
- }
-
- emit_changed();
-}
-
void Animation::bezier_track_set_key_value(int p_track, int p_index, real_t p_value) {
ERR_FAIL_INDEX(p_track, tracks.size());
Track *t = tracks[p_track];
@@ -3276,10 +3354,11 @@ void Animation::bezier_track_set_key_value(int p_track, int p_index, real_t p_va
ERR_FAIL_INDEX(p_index, bt->values.size());
bt->values.write[p_index].value.value = p_value;
+
emit_changed();
}
-void Animation::bezier_track_set_key_in_handle(int p_track, int p_index, const Vector2 &p_handle, double p_balanced_value_time_ratio) {
+void Animation::bezier_track_set_key_in_handle(int p_track, int p_index, const Vector2 &p_handle, real_t p_balanced_value_time_ratio) {
ERR_FAIL_INDEX(p_track, tracks.size());
Track *t = tracks[p_track];
ERR_FAIL_COND(t->type != TYPE_BEZIER);
@@ -3294,7 +3373,11 @@ void Animation::bezier_track_set_key_in_handle(int p_track, int p_index, const V
}
bt->values.write[p_index].value.in_handle = in_handle;
- if (bt->values[p_index].value.handle_mode == HANDLE_MODE_BALANCED) {
+#ifdef TOOLS_ENABLED
+ if (bt->values[p_index].value.handle_mode == HANDLE_MODE_LINEAR) {
+ bt->values.write[p_index].value.in_handle = Vector2();
+ bt->values.write[p_index].value.out_handle = Vector2();
+ } else if (bt->values[p_index].value.handle_mode == HANDLE_MODE_BALANCED) {
Transform2D xform;
xform.set_scale(Vector2(1.0, 1.0 / p_balanced_value_time_ratio));
@@ -3302,12 +3385,15 @@ void Animation::bezier_track_set_key_in_handle(int p_track, int p_index, const V
Vector2 vec_in = xform.xform(in_handle);
bt->values.write[p_index].value.out_handle = xform.affine_inverse().xform(-vec_in.normalized() * vec_out.length());
+ } else if (bt->values[p_index].value.handle_mode == HANDLE_MODE_MIRRORED) {
+ bt->values.write[p_index].value.out_handle = -in_handle;
}
+#endif // TOOLS_ENABLED
emit_changed();
}
-void Animation::bezier_track_set_key_out_handle(int p_track, int p_index, const Vector2 &p_handle, double p_balanced_value_time_ratio) {
+void Animation::bezier_track_set_key_out_handle(int p_track, int p_index, const Vector2 &p_handle, real_t p_balanced_value_time_ratio) {
ERR_FAIL_INDEX(p_track, tracks.size());
Track *t = tracks[p_track];
ERR_FAIL_COND(t->type != TYPE_BEZIER);
@@ -3322,7 +3408,11 @@ void Animation::bezier_track_set_key_out_handle(int p_track, int p_index, const
}
bt->values.write[p_index].value.out_handle = out_handle;
- if (bt->values[p_index].value.handle_mode == HANDLE_MODE_BALANCED) {
+#ifdef TOOLS_ENABLED
+ if (bt->values[p_index].value.handle_mode == HANDLE_MODE_LINEAR) {
+ bt->values.write[p_index].value.in_handle = Vector2();
+ bt->values.write[p_index].value.out_handle = Vector2();
+ } else if (bt->values[p_index].value.handle_mode == HANDLE_MODE_BALANCED) {
Transform2D xform;
xform.set_scale(Vector2(1.0, 1.0 / p_balanced_value_time_ratio));
@@ -3330,7 +3420,10 @@ void Animation::bezier_track_set_key_out_handle(int p_track, int p_index, const
Vector2 vec_out = xform.xform(out_handle);
bt->values.write[p_index].value.in_handle = xform.affine_inverse().xform(-vec_out.normalized() * vec_in.length());
+ } else if (bt->values[p_index].value.handle_mode == HANDLE_MODE_MIRRORED) {
+ bt->values.write[p_index].value.in_handle = -out_handle;
}
+#endif // TOOLS_ENABLED
emit_changed();
}
@@ -3347,18 +3440,6 @@ real_t Animation::bezier_track_get_key_value(int p_track, int p_index) const {
return bt->values[p_index].value.value;
}
-int Animation::bezier_track_get_key_handle_mode(int p_track, int p_index) const {
- ERR_FAIL_INDEX_V(p_track, tracks.size(), 0);
- Track *t = tracks[p_track];
- ERR_FAIL_COND_V(t->type != TYPE_BEZIER, 0);
-
- BezierTrack *bt = static_cast<BezierTrack *>(t);
-
- ERR_FAIL_INDEX_V(p_index, bt->values.size(), 0);
-
- return bt->values[p_index].value.handle_mode;
-}
-
Vector2 Animation::bezier_track_get_key_in_handle(int p_track, int p_index) const {
ERR_FAIL_INDEX_V(p_track, tracks.size(), Vector2());
Track *t = tracks[p_track];
@@ -3383,6 +3464,109 @@ Vector2 Animation::bezier_track_get_key_out_handle(int p_track, int p_index) con
return bt->values[p_index].value.out_handle;
}
+#ifdef TOOLS_ENABLED
+void Animation::bezier_track_set_key_handle_mode(int p_track, int p_index, HandleMode p_mode, HandleSetMode p_set_mode) {
+ ERR_FAIL_INDEX(p_track, tracks.size());
+ Track *t = tracks[p_track];
+ ERR_FAIL_COND(t->type != TYPE_BEZIER);
+
+ BezierTrack *bt = static_cast<BezierTrack *>(t);
+
+ ERR_FAIL_INDEX(p_index, bt->values.size());
+
+ bt->values.write[p_index].value.handle_mode = p_mode;
+
+ switch (p_mode) {
+ case HANDLE_MODE_LINEAR: {
+ bt->values.write[p_index].value.in_handle = Vector2(0, 0);
+ bt->values.write[p_index].value.out_handle = Vector2(0, 0);
+ } break;
+ case HANDLE_MODE_BALANCED:
+ case HANDLE_MODE_MIRRORED: {
+ int prev_key = MAX(0, p_index - 1);
+ int next_key = MIN(bt->values.size() - 1, p_index + 1);
+ if (prev_key == next_key) {
+ break; // Exists only one key.
+ }
+ real_t in_handle_x = 0;
+ real_t in_handle_y = 0;
+ real_t out_handle_x = 0;
+ real_t out_handle_y = 0;
+ if (p_mode == HANDLE_MODE_BALANCED) {
+ // Note:
+ // If p_set_mode == HANDLE_SET_MODE_NONE, I don't know if it should change the Tangent implicitly.
+ // At the least, we need to avoid corrupting the handles when loading animation from the resource.
+ // However, changes made by the Inspector do not go through the BezierEditor,
+ // so if you change from Free to Balanced or Mirrored in Inspector, there is no guarantee that
+ // it is Balanced or Mirrored until there is a handle operation.
+ if (p_set_mode == HANDLE_SET_MODE_RESET) {
+ real_t handle_length = 1.0 / 3.0;
+ in_handle_x = (bt->values[prev_key].time - bt->values[p_index].time) * handle_length;
+ in_handle_y = 0;
+ out_handle_x = (bt->values[next_key].time - bt->values[p_index].time) * handle_length;
+ out_handle_y = 0;
+ bt->values.write[p_index].value.in_handle = Vector2(in_handle_x, in_handle_y);
+ bt->values.write[p_index].value.out_handle = Vector2(out_handle_x, out_handle_y);
+ } else if (p_set_mode == HANDLE_SET_MODE_AUTO) {
+ real_t handle_length = 1.0 / 6.0;
+ real_t tangent = (bt->values[next_key].value.value - bt->values[prev_key].value.value) / (bt->values[next_key].time - bt->values[prev_key].time);
+ in_handle_x = (bt->values[prev_key].time - bt->values[p_index].time) * handle_length;
+ in_handle_y = in_handle_x * tangent;
+ out_handle_x = (bt->values[next_key].time - bt->values[p_index].time) * handle_length;
+ out_handle_y = out_handle_x * tangent;
+ bt->values.write[p_index].value.in_handle = Vector2(in_handle_x, in_handle_y);
+ bt->values.write[p_index].value.out_handle = Vector2(out_handle_x, out_handle_y);
+ }
+ } else {
+ real_t handle_length = 1.0 / 4.0;
+ real_t prev_interval = Math::abs(bt->values[p_index].time - bt->values[prev_key].time);
+ real_t next_interval = Math::abs(bt->values[p_index].time - bt->values[next_key].time);
+ real_t min_time = 0;
+ if (Math::is_zero_approx(prev_interval)) {
+ min_time = next_interval;
+ } else if (Math::is_zero_approx(next_interval)) {
+ min_time = prev_interval;
+ } else {
+ min_time = MIN(prev_interval, next_interval);
+ }
+ if (p_set_mode == HANDLE_SET_MODE_RESET) {
+ in_handle_x = -min_time * handle_length;
+ in_handle_y = 0;
+ out_handle_x = min_time * handle_length;
+ out_handle_y = 0;
+ bt->values.write[p_index].value.in_handle = Vector2(in_handle_x, in_handle_y);
+ bt->values.write[p_index].value.out_handle = Vector2(out_handle_x, out_handle_y);
+ } else if (p_set_mode == HANDLE_SET_MODE_AUTO) {
+ real_t tangent = (bt->values[next_key].value.value - bt->values[prev_key].value.value) / min_time;
+ in_handle_x = -min_time * handle_length;
+ in_handle_y = in_handle_x * tangent;
+ out_handle_x = min_time * handle_length;
+ out_handle_y = out_handle_x * tangent;
+ bt->values.write[p_index].value.in_handle = Vector2(in_handle_x, in_handle_y);
+ bt->values.write[p_index].value.out_handle = Vector2(out_handle_x, out_handle_y);
+ }
+ }
+ } break;
+ default: {
+ } break;
+ }
+
+ emit_changed();
+}
+
+Animation::HandleMode Animation::bezier_track_get_key_handle_mode(int p_track, int p_index) const {
+ ERR_FAIL_INDEX_V(p_track, tracks.size(), HANDLE_MODE_FREE);
+ Track *t = tracks[p_track];
+ ERR_FAIL_COND_V(t->type != TYPE_BEZIER, HANDLE_MODE_FREE);
+
+ BezierTrack *bt = static_cast<BezierTrack *>(t);
+
+ ERR_FAIL_INDEX_V(p_index, bt->values.size(), HANDLE_MODE_FREE);
+
+ return bt->values[p_index].value.handle_mode;
+}
+#endif // TOOLS_ENABLED
+
real_t Animation::bezier_track_interpolate(int p_track, double p_time) const {
//this uses a different interpolation scheme
ERR_FAIL_INDEX_V(p_track, tracks.size(), 0);
@@ -3779,7 +3963,7 @@ void Animation::_bind_methods() {
ClassDB::bind_method(D_METHOD("method_track_get_name", "track_idx", "key_idx"), &Animation::method_track_get_name);
ClassDB::bind_method(D_METHOD("method_track_get_params", "track_idx", "key_idx"), &Animation::method_track_get_params);
- ClassDB::bind_method(D_METHOD("bezier_track_insert_key", "track_idx", "time", "value", "in_handle", "out_handle", "handle_mode"), &Animation::bezier_track_insert_key, DEFVAL(Vector2()), DEFVAL(Vector2()), DEFVAL(Animation::HandleMode::HANDLE_MODE_BALANCED));
+ ClassDB::bind_method(D_METHOD("bezier_track_insert_key", "track_idx", "time", "value", "in_handle", "out_handle"), &Animation::bezier_track_insert_key, DEFVAL(Vector2()), DEFVAL(Vector2()));
ClassDB::bind_method(D_METHOD("bezier_track_set_key_value", "track_idx", "key_idx", "value"), &Animation::bezier_track_set_key_value);
ClassDB::bind_method(D_METHOD("bezier_track_set_key_in_handle", "track_idx", "key_idx", "in_handle", "balanced_value_time_ratio"), &Animation::bezier_track_set_key_in_handle, DEFVAL(1.0));
@@ -3799,9 +3983,6 @@ void Animation::_bind_methods() {
ClassDB::bind_method(D_METHOD("audio_track_get_key_start_offset", "track_idx", "key_idx"), &Animation::audio_track_get_key_start_offset);
ClassDB::bind_method(D_METHOD("audio_track_get_key_end_offset", "track_idx", "key_idx"), &Animation::audio_track_get_key_end_offset);
- ClassDB::bind_method(D_METHOD("bezier_track_set_key_handle_mode", "track_idx", "key_idx", "key_handle_mode", "balanced_value_time_ratio"), &Animation::bezier_track_set_key_handle_mode, DEFVAL(1.0));
- ClassDB::bind_method(D_METHOD("bezier_track_get_key_handle_mode", "track_idx", "key_idx"), &Animation::bezier_track_get_key_handle_mode);
-
ClassDB::bind_method(D_METHOD("animation_track_insert_key", "track_idx", "time", "animation"), &Animation::animation_track_insert_key);
ClassDB::bind_method(D_METHOD("animation_track_set_key_animation", "track_idx", "key_idx", "animation"), &Animation::animation_track_set_key_animation);
ClassDB::bind_method(D_METHOD("animation_track_get_key_animation", "track_idx", "key_idx"), &Animation::animation_track_get_key_animation);
@@ -3839,6 +4020,8 @@ void Animation::_bind_methods() {
BIND_ENUM_CONSTANT(INTERPOLATION_NEAREST);
BIND_ENUM_CONSTANT(INTERPOLATION_LINEAR);
BIND_ENUM_CONSTANT(INTERPOLATION_CUBIC);
+ BIND_ENUM_CONSTANT(INTERPOLATION_LINEAR_ANGLE);
+ BIND_ENUM_CONSTANT(INTERPOLATION_CUBIC_ANGLE);
BIND_ENUM_CONSTANT(UPDATE_CONTINUOUS);
BIND_ENUM_CONSTANT(UPDATE_DISCRETE);
@@ -3848,9 +4031,6 @@ void Animation::_bind_methods() {
BIND_ENUM_CONSTANT(LOOP_NONE);
BIND_ENUM_CONSTANT(LOOP_LINEAR);
BIND_ENUM_CONSTANT(LOOP_PINGPONG);
-
- BIND_ENUM_CONSTANT(HANDLE_MODE_FREE);
- BIND_ENUM_CONSTANT(HANDLE_MODE_BALANCED);
}
void Animation::clear() {
@@ -3868,316 +4048,369 @@ void Animation::clear() {
emit_signal(SceneStringNames::get_singleton()->tracks_changed);
}
-bool Animation::_position_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_allowed_linear_err, real_t p_allowed_angular_error, const Vector3 &p_norm) {
- const Vector3 &v0 = t0.value;
- const Vector3 &v1 = t1.value;
- const Vector3 &v2 = t2.value;
-
- if (v0.is_equal_approx(v2)) {
- //0 and 2 are close, let's see if 1 is close
- if (!v0.is_equal_approx(v1)) {
- //not close, not optimizable
- return false;
- }
-
- } else {
- Vector3 pd = (v2 - v0);
- real_t d0 = pd.dot(v0);
- real_t d1 = pd.dot(v1);
- real_t d2 = pd.dot(v2);
- if (d1 < d0 || d1 > d2) {
- return false;
- }
-
- Vector3 s[2] = { v0, v2 };
- real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1);
-
- if (d > pd.length() * p_allowed_linear_err) {
- return false; //beyond allowed error for collinearity
- }
-
- if (p_norm != Vector3() && Math::acos(pd.normalized().dot(p_norm)) > p_allowed_angular_error) {
- return false;
+bool Animation::_float_track_optimize_key(const TKey<float> t0, const TKey<float> t1, const TKey<float> t2, real_t p_allowed_velocity_err, real_t p_allowed_precision_error) {
+ // Remove overlapping keys.
+ if (Math::is_equal_approx(t0.time, t1.time) || Math::is_equal_approx(t1.time, t2.time)) {
+ return true;
+ }
+ if (abs(t0.value - t1.value) < p_allowed_precision_error && abs(t1.value - t2.value) < p_allowed_precision_error) {
+ return true;
+ }
+ // Calc velocities.
+ double v0 = (t1.value - t0.value) / (t1.time - t0.time);
+ double v1 = (t2.value - t1.value) / (t2.time - t1.time);
+ // Avoid zero div but check equality.
+ if (abs(v0 - v1) < p_allowed_precision_error) {
+ return true;
+ } else if (abs(v0) < p_allowed_precision_error || abs(v1) < p_allowed_precision_error) {
+ return false;
+ }
+ if (!signbit(v0 * v1)) {
+ v0 = abs(v0);
+ v1 = abs(v1);
+ double ratio = v0 < v1 ? v0 / v1 : v1 / v0;
+ if (ratio >= 1.0 - p_allowed_velocity_err) {
+ return true;
}
}
-
- return true;
+ return false;
}
-bool Animation::_rotation_track_optimize_key(const TKey<Quaternion> &t0, const TKey<Quaternion> &t1, const TKey<Quaternion> &t2, real_t p_allowed_angular_error, float p_max_optimizable_angle) {
- const Quaternion &q0 = t0.value;
- const Quaternion &q1 = t1.value;
- const Quaternion &q2 = t2.value;
-
- //localize both to rotation from q0
-
- if (q0.is_equal_approx(q2)) {
- if (!q0.is_equal_approx(q1)) {
- return false;
- }
-
- } else {
- Quaternion r02 = (q0.inverse() * q2).normalized();
- Quaternion r01 = (q0.inverse() * q1).normalized();
-
- Vector3 v02, v01;
- real_t a02, a01;
-
- r02.get_axis_angle(v02, a02);
- r01.get_axis_angle(v01, a01);
-
- if (Math::abs(a02) > p_max_optimizable_angle) {
- return false;
- }
-
- if (v01.dot(v02) < 0) {
- //make sure both rotations go the same way to compare
- v02 = -v02;
- a02 = -a02;
- }
-
- real_t err_01 = Math::acos(v01.normalized().dot(v02.normalized())) / Math_PI;
- if (err_01 > p_allowed_angular_error) {
- //not rotating in the same axis
- return false;
- }
-
- if (a01 * a02 < 0) {
- //not rotating in the same direction
- return false;
- }
-
- real_t tr = a01 / a02;
- if (tr < 0 || tr > 1) {
- return false; //rotating too much or too less
+bool Animation::_vector2_track_optimize_key(const TKey<Vector2> t0, const TKey<Vector2> t1, const TKey<Vector2> t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error) {
+ // Remove overlapping keys.
+ if (Math::is_equal_approx(t0.time, t1.time) || Math::is_equal_approx(t1.time, t2.time)) {
+ return true;
+ }
+ if ((t0.value - t1.value).length() < p_allowed_precision_error && (t1.value - t2.value).length() < p_allowed_precision_error) {
+ return true;
+ }
+ // Calc velocities.
+ Vector2 vc0 = (t1.value - t0.value) / (t1.time - t0.time);
+ Vector2 vc1 = (t2.value - t1.value) / (t2.time - t1.time);
+ double v0 = vc0.length();
+ double v1 = vc1.length();
+ // Avoid zero div but check equality.
+ if (abs(v0 - v1) < p_allowed_precision_error) {
+ return true;
+ } else if (abs(v0) < p_allowed_precision_error || abs(v1) < p_allowed_precision_error) {
+ return false;
+ }
+ // Check axis.
+ if (vc0.normalized().dot(vc1.normalized()) >= 1.0 - p_allowed_angular_error * 2.0) {
+ v0 = abs(v0);
+ v1 = abs(v1);
+ double ratio = v0 < v1 ? v0 / v1 : v1 / v0;
+ if (ratio >= 1.0 - p_allowed_velocity_err) {
+ return true;
}
}
-
- return true;
+ return false;
}
-bool Animation::_scale_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_allowed_linear_error) {
- const Vector3 &v0 = t0.value;
- const Vector3 &v1 = t1.value;
- const Vector3 &v2 = t2.value;
-
- if (v0.is_equal_approx(v2)) {
- //0 and 2 are close, let's see if 1 is close
- if (!v0.is_equal_approx(v1)) {
- //not close, not optimizable
- return false;
- }
-
- } else {
- Vector3 pd = (v2 - v0);
- real_t d0 = pd.dot(v0);
- real_t d1 = pd.dot(v1);
- real_t d2 = pd.dot(v2);
- if (d1 < d0 || d1 > d2) {
- return false; //beyond segment range
- }
-
- Vector3 s[2] = { v0, v2 };
- real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1);
-
- if (d > pd.length() * p_allowed_linear_error) {
- return false; //beyond allowed error for colinearity
+bool Animation::_vector3_track_optimize_key(const TKey<Vector3> t0, const TKey<Vector3> t1, const TKey<Vector3> t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error) {
+ // Remove overlapping keys.
+ if (Math::is_equal_approx(t0.time, t1.time) || Math::is_equal_approx(t1.time, t2.time)) {
+ return true;
+ }
+ if ((t0.value - t1.value).length() < p_allowed_precision_error && (t1.value - t2.value).length() < p_allowed_precision_error) {
+ return true;
+ }
+ // Calc velocities.
+ Vector3 vc0 = (t1.value - t0.value) / (t1.time - t0.time);
+ Vector3 vc1 = (t2.value - t1.value) / (t2.time - t1.time);
+ double v0 = vc0.length();
+ double v1 = vc1.length();
+ // Avoid zero div but check equality.
+ if (abs(v0 - v1) < p_allowed_precision_error) {
+ return true;
+ } else if (abs(v0) < p_allowed_precision_error || abs(v1) < p_allowed_precision_error) {
+ return false;
+ }
+ // Check axis.
+ if (vc0.normalized().dot(vc1.normalized()) >= 1.0 - p_allowed_angular_error * 2.0) {
+ v0 = abs(v0);
+ v1 = abs(v1);
+ double ratio = v0 < v1 ? v0 / v1 : v1 / v0;
+ if (ratio >= 1.0 - p_allowed_velocity_err) {
+ return true;
}
}
-
- return true;
+ return false;
}
-bool Animation::_blend_shape_track_optimize_key(const TKey<float> &t0, const TKey<float> &t1, const TKey<float> &t2, real_t p_allowed_unit_error) {
- float v0 = t0.value;
- float v1 = t1.value;
- float v2 = t2.value;
-
- if (Math::is_equal_approx(v1, v2, (float)p_allowed_unit_error)) {
- //0 and 2 are close, let's see if 1 is close
- if (!Math::is_equal_approx(v0, v1, (float)p_allowed_unit_error)) {
- //not close, not optimizable
- return false;
+bool Animation::_quaternion_track_optimize_key(const TKey<Quaternion> t0, const TKey<Quaternion> t1, const TKey<Quaternion> t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error) {
+ // Remove overlapping keys.
+ if (Math::is_equal_approx(t0.time, t1.time) || Math::is_equal_approx(t1.time, t2.time)) {
+ return true;
+ }
+ if ((t0.value - t1.value).length() < p_allowed_precision_error && (t1.value - t2.value).length() < p_allowed_precision_error) {
+ return true;
+ }
+ // Check axis.
+ Quaternion q0 = t0.value * t1.value * t0.value.inverse();
+ Quaternion q1 = t1.value * t2.value * t1.value.inverse();
+ if (q0.get_axis().dot(q1.get_axis()) >= 1.0 - p_allowed_angular_error * 2.0) {
+ double a0 = Math::acos(t0.value.dot(t1.value));
+ double a1 = Math::acos(t1.value.dot(t2.value));
+ if (a0 + a1 >= Math_PI) {
+ return false; // Rotation is more than 180 deg, keep key.
}
- } else {
- /*
- TODO eventually discuss a way to optimize these better.
- float pd = (v2 - v0);
- real_t d0 = pd.dot(v0);
- real_t d1 = pd.dot(v1);
- real_t d2 = pd.dot(v2);
- if (d1 < d0 || d1 > d2) {
- return false; //beyond segment range
+ // Calc velocities.
+ double v0 = a0 / (t1.time - t0.time);
+ double v1 = a1 / (t2.time - t1.time);
+ // Avoid zero div but check equality.
+ if (abs(v0 - v1) < p_allowed_precision_error) {
+ return true;
+ } else if (abs(v0) < p_allowed_precision_error || abs(v1) < p_allowed_precision_error) {
+ return false;
}
-
- float s[2] = { v0, v2 };
- real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1);
-
- if (d > pd.length() * p_allowed_linear_error) {
- return false; //beyond allowed error for colinearity
+ double ratio = v0 < v1 ? v0 / v1 : v1 / v0;
+ if (ratio >= 1.0 - p_allowed_velocity_err) {
+ return true;
}
-*/
}
-
- return true;
+ return false;
}
-void Animation::_position_track_optimize(int p_idx, real_t p_allowed_linear_err, real_t p_allowed_angular_err) {
+void Animation::_position_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) {
ERR_FAIL_INDEX(p_idx, tracks.size());
ERR_FAIL_COND(tracks[p_idx]->type != TYPE_POSITION_3D);
PositionTrack *tt = static_cast<PositionTrack *>(tracks[p_idx]);
- bool prev_erased = false;
- TKey<Vector3> first_erased;
- Vector3 norm;
-
- for (int i = 1; i < tt->positions.size() - 1; i++) {
- TKey<Vector3> &t0 = tt->positions.write[i - 1];
- TKey<Vector3> &t1 = tt->positions.write[i];
- TKey<Vector3> &t2 = tt->positions.write[i + 1];
-
- bool erase = _position_track_optimize_key(t0, t1, t2, p_allowed_linear_err, p_allowed_angular_err, norm);
- if (erase && !prev_erased) {
- norm = (t2.value - t1.value).normalized();
- }
-
- if (prev_erased && !_position_track_optimize_key(t0, first_erased, t2, p_allowed_linear_err, p_allowed_angular_err, norm)) {
- //avoid error to go beyond first erased key
- erase = false;
- }
+ int i = 0;
+ while (i < tt->positions.size() - 2) {
+ TKey<Vector3> t0 = tt->positions[i];
+ TKey<Vector3> t1 = tt->positions[i + 1];
+ TKey<Vector3> t2 = tt->positions[i + 2];
+ bool erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error);
if (erase) {
- if (!prev_erased) {
- first_erased = t1;
- prev_erased = true;
- }
-
- tt->positions.remove_at(i);
- i--;
-
+ tt->positions.remove_at(i + 1);
} else {
- prev_erased = false;
- norm = Vector3();
+ i++;
+ }
+ }
+
+ if (tt->positions.size() == 2) {
+ if ((tt->positions[0].value - tt->positions[1].value).length() < p_allowed_precision_error) {
+ tt->positions.remove_at(1);
}
}
}
-void Animation::_rotation_track_optimize(int p_idx, real_t p_allowed_angular_err, real_t p_max_optimizable_angle) {
+void Animation::_rotation_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) {
ERR_FAIL_INDEX(p_idx, tracks.size());
ERR_FAIL_COND(tracks[p_idx]->type != TYPE_ROTATION_3D);
- RotationTrack *tt = static_cast<RotationTrack *>(tracks[p_idx]);
- bool prev_erased = false;
- TKey<Quaternion> first_erased;
-
- for (int i = 1; i < tt->rotations.size() - 1; i++) {
- TKey<Quaternion> &t0 = tt->rotations.write[i - 1];
- TKey<Quaternion> &t1 = tt->rotations.write[i];
- TKey<Quaternion> &t2 = tt->rotations.write[i + 1];
+ RotationTrack *rt = static_cast<RotationTrack *>(tracks[p_idx]);
- bool erase = _rotation_track_optimize_key(t0, t1, t2, p_allowed_angular_err, p_max_optimizable_angle);
-
- if (prev_erased && !_rotation_track_optimize_key(t0, first_erased, t2, p_allowed_angular_err, p_max_optimizable_angle)) {
- //avoid error to go beyond first erased key
- erase = false;
- }
+ int i = 0;
+ while (i < rt->rotations.size() - 2) {
+ TKey<Quaternion> t0 = rt->rotations[i];
+ TKey<Quaternion> t1 = rt->rotations[i + 1];
+ TKey<Quaternion> t2 = rt->rotations[i + 2];
+ bool erase = _quaternion_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error);
if (erase) {
- if (!prev_erased) {
- first_erased = t1;
- prev_erased = true;
- }
-
- tt->rotations.remove_at(i);
- i--;
-
+ rt->rotations.remove_at(i + 1);
} else {
- prev_erased = false;
+ i++;
+ }
+ }
+
+ if (rt->rotations.size() == 2) {
+ if ((rt->rotations[0].value - rt->rotations[1].value).length() < p_allowed_precision_error) {
+ rt->rotations.remove_at(1);
}
}
}
-void Animation::_scale_track_optimize(int p_idx, real_t p_allowed_linear_err) {
+void Animation::_scale_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) {
ERR_FAIL_INDEX(p_idx, tracks.size());
ERR_FAIL_COND(tracks[p_idx]->type != TYPE_SCALE_3D);
- ScaleTrack *tt = static_cast<ScaleTrack *>(tracks[p_idx]);
- bool prev_erased = false;
- TKey<Vector3> first_erased;
-
- for (int i = 1; i < tt->scales.size() - 1; i++) {
- TKey<Vector3> &t0 = tt->scales.write[i - 1];
- TKey<Vector3> &t1 = tt->scales.write[i];
- TKey<Vector3> &t2 = tt->scales.write[i + 1];
+ ScaleTrack *st = static_cast<ScaleTrack *>(tracks[p_idx]);
- bool erase = _scale_track_optimize_key(t0, t1, t2, p_allowed_linear_err);
-
- if (prev_erased && !_scale_track_optimize_key(t0, first_erased, t2, p_allowed_linear_err)) {
- //avoid error to go beyond first erased key
- erase = false;
- }
+ int i = 0;
+ while (i < st->scales.size() - 2) {
+ TKey<Vector3> t0 = st->scales[i];
+ TKey<Vector3> t1 = st->scales[i + 1];
+ TKey<Vector3> t2 = st->scales[i + 2];
+ bool erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error);
if (erase) {
- if (!prev_erased) {
- first_erased = t1;
- prev_erased = true;
- }
-
- tt->scales.remove_at(i);
- i--;
-
+ st->scales.remove_at(i + 1);
} else {
- prev_erased = false;
+ i++;
+ }
+ }
+
+ if (st->scales.size() == 2) {
+ if ((st->scales[0].value - st->scales[1].value).length() < p_allowed_precision_error) {
+ st->scales.remove_at(1);
}
}
}
-void Animation::_blend_shape_track_optimize(int p_idx, real_t p_allowed_linear_err) {
+void Animation::_blend_shape_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_precision_error) {
ERR_FAIL_INDEX(p_idx, tracks.size());
ERR_FAIL_COND(tracks[p_idx]->type != TYPE_BLEND_SHAPE);
- BlendShapeTrack *tt = static_cast<BlendShapeTrack *>(tracks[p_idx]);
- bool prev_erased = false;
- TKey<float> first_erased;
- first_erased.value = 0.0;
+ BlendShapeTrack *bst = static_cast<BlendShapeTrack *>(tracks[p_idx]);
- for (int i = 1; i < tt->blend_shapes.size() - 1; i++) {
- TKey<float> &t0 = tt->blend_shapes.write[i - 1];
- TKey<float> &t1 = tt->blend_shapes.write[i];
- TKey<float> &t2 = tt->blend_shapes.write[i + 1];
+ int i = 0;
+ while (i < bst->blend_shapes.size() - 2) {
+ TKey<float> t0 = bst->blend_shapes[i];
+ TKey<float> t1 = bst->blend_shapes[i + 1];
+ TKey<float> t2 = bst->blend_shapes[i + 2];
- bool erase = _blend_shape_track_optimize_key(t0, t1, t2, p_allowed_linear_err);
-
- if (prev_erased && !_blend_shape_track_optimize_key(t0, first_erased, t2, p_allowed_linear_err)) {
- //avoid error to go beyond first erased key
- erase = false;
+ bool erase = _float_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_precision_error);
+ if (erase) {
+ bst->blend_shapes.remove_at(i + 1);
+ } else {
+ i++;
}
+ }
- if (erase) {
- if (!prev_erased) {
- first_erased = t1;
- prev_erased = true;
- }
+ if (bst->blend_shapes.size() == 2) {
+ if (abs(bst->blend_shapes[0].value - bst->blend_shapes[1].value) < p_allowed_precision_error) {
+ bst->blend_shapes.remove_at(1);
+ }
+ }
+}
- tt->blend_shapes.remove_at(i);
- i--;
+void Animation::_value_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) {
+ ERR_FAIL_INDEX(p_idx, tracks.size());
+ ERR_FAIL_COND(tracks[p_idx]->type != TYPE_VALUE);
+ ValueTrack *vt = static_cast<ValueTrack *>(tracks[p_idx]);
+ if (vt->values.size() == 0) {
+ return;
+ }
+ Variant::Type type = vt->values[0].value.get_type();
+
+ // Special case for angle interpolation.
+ bool is_using_angle = vt->interpolation == Animation::INTERPOLATION_LINEAR_ANGLE || vt->interpolation == Animation::INTERPOLATION_CUBIC_ANGLE;
+ int i = 0;
+ while (i < vt->values.size() - 2) {
+ bool erase = false;
+ switch (type) {
+ case Variant::FLOAT: {
+ TKey<float> t0;
+ TKey<float> t1;
+ TKey<float> t2;
+ t0.time = vt->values[i].time;
+ t1.time = vt->values[i + 1].time;
+ t2.time = vt->values[i + 2].time;
+ t0.value = vt->values[i].value;
+ t1.value = vt->values[i + 1].value;
+ t2.value = vt->values[i + 2].value;
+ if (is_using_angle) {
+ float diff1 = fmod(t1.value - t0.value, Math_TAU);
+ t1.value = t0.value + fmod(2.0 * diff1, Math_TAU) - diff1;
+ float diff2 = fmod(t2.value - t1.value, Math_TAU);
+ t2.value = t1.value + fmod(2.0 * diff2, Math_TAU) - diff2;
+ if (abs(abs(diff1) + abs(diff2)) >= Math_PI) {
+ break; // Rotation is more than 180 deg, keep key.
+ }
+ }
+ erase = _float_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_precision_error);
+ } break;
+ case Variant::VECTOR2: {
+ TKey<Vector2> t0;
+ TKey<Vector2> t1;
+ TKey<Vector2> t2;
+ t0.time = vt->values[i].time;
+ t1.time = vt->values[i + 1].time;
+ t2.time = vt->values[i + 2].time;
+ t0.value = vt->values[i].value;
+ t1.value = vt->values[i + 1].value;
+ t2.value = vt->values[i + 2].value;
+ erase = _vector2_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error);
+ } break;
+ case Variant::VECTOR3: {
+ TKey<Vector3> t0;
+ TKey<Vector3> t1;
+ TKey<Vector3> t2;
+ t0.time = vt->values[i].time;
+ t1.time = vt->values[i + 1].time;
+ t2.time = vt->values[i + 2].time;
+ t0.value = vt->values[i].value;
+ t1.value = vt->values[i + 1].value;
+ t2.value = vt->values[i + 2].value;
+ erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error);
+ } break;
+ case Variant::QUATERNION: {
+ TKey<Quaternion> t0;
+ TKey<Quaternion> t1;
+ TKey<Quaternion> t2;
+ t0.time = vt->values[i].time;
+ t1.time = vt->values[i + 1].time;
+ t2.time = vt->values[i + 2].time;
+ t0.value = vt->values[i].value;
+ t1.value = vt->values[i + 1].value;
+ t2.value = vt->values[i + 2].value;
+ erase = _quaternion_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error);
+ } break;
+ default: {
+ } break;
+ }
+ if (erase) {
+ vt->values.remove_at(i + 1);
} else {
- prev_erased = false;
+ i++;
+ }
+ }
+
+ if (vt->values.size() == 2) {
+ bool single_key = false;
+ switch (type) {
+ case Variant::FLOAT: {
+ float val_0 = vt->values[0].value;
+ float val_1 = vt->values[1].value;
+ if (is_using_angle) {
+ float diff1 = fmod(val_1 - val_0, Math_TAU);
+ val_1 = val_0 + fmod(2.0 * diff1, Math_TAU) - diff1;
+ }
+ single_key = abs(val_0 - val_1) < p_allowed_precision_error;
+ } break;
+ case Variant::VECTOR2: {
+ Vector2 val_0 = vt->values[0].value;
+ Vector2 val_1 = vt->values[1].value;
+ single_key = (val_0 - val_1).length() < p_allowed_precision_error;
+ } break;
+ case Variant::VECTOR3: {
+ Vector3 val_0 = vt->values[0].value;
+ Vector3 val_1 = vt->values[1].value;
+ single_key = (val_0 - val_1).length() < p_allowed_precision_error;
+ } break;
+ case Variant::QUATERNION: {
+ Quaternion val_0 = vt->values[0].value;
+ Quaternion val_1 = vt->values[1].value;
+ single_key = (val_0 - val_1).length() < p_allowed_precision_error;
+ } break;
+ default: {
+ } break;
+ }
+ if (single_key) {
+ vt->values.remove_at(1);
}
}
}
-void Animation::optimize(real_t p_allowed_linear_err, real_t p_allowed_angular_err, real_t p_max_optimizable_angle) {
+void Animation::optimize(real_t p_allowed_velocity_err, real_t p_allowed_angular_err, int p_precision) {
+ real_t precision = Math::pow(0.1, p_precision);
for (int i = 0; i < tracks.size(); i++) {
if (track_is_compressed(i)) {
continue; //not possible to optimize compressed track
}
if (tracks[i]->type == TYPE_POSITION_3D) {
- _position_track_optimize(i, p_allowed_linear_err, p_allowed_angular_err);
+ _position_track_optimize(i, p_allowed_velocity_err, p_allowed_angular_err, precision);
} else if (tracks[i]->type == TYPE_ROTATION_3D) {
- _rotation_track_optimize(i, p_allowed_angular_err, p_max_optimizable_angle);
+ _rotation_track_optimize(i, p_allowed_velocity_err, p_allowed_angular_err, precision);
} else if (tracks[i]->type == TYPE_SCALE_3D) {
- _scale_track_optimize(i, p_allowed_linear_err);
+ _scale_track_optimize(i, p_allowed_velocity_err, p_allowed_angular_err, precision);
} else if (tracks[i]->type == TYPE_BLEND_SHAPE) {
- _blend_shape_track_optimize(i, p_allowed_linear_err);
+ _blend_shape_track_optimize(i, p_allowed_velocity_err, precision);
+ } else if (tracks[i]->type == TYPE_VALUE) {
+ _value_track_optimize(i, p_allowed_velocity_err, p_allowed_angular_err, precision);
}
}
}
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index bf9f786a0d..46a88df130 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -56,7 +56,9 @@ public:
enum InterpolationType {
INTERPOLATION_NEAREST,
INTERPOLATION_LINEAR,
- INTERPOLATION_CUBIC
+ INTERPOLATION_CUBIC,
+ INTERPOLATION_LINEAR_ANGLE,
+ INTERPOLATION_CUBIC_ANGLE,
};
enum UpdateMode {
@@ -72,10 +74,19 @@ public:
LOOP_PINGPONG,
};
+#ifdef TOOLS_ENABLED
enum HandleMode {
HANDLE_MODE_FREE,
+ HANDLE_MODE_LINEAR,
HANDLE_MODE_BALANCED,
+ HANDLE_MODE_MIRRORED,
};
+ enum HandleSetMode {
+ HANDLE_SET_MODE_NONE,
+ HANDLE_SET_MODE_RESET,
+ HANDLE_SET_MODE_AUTO,
+ };
+#endif // TOOLS_ENABLED
private:
struct Track {
@@ -165,8 +176,10 @@ private:
struct BezierKey {
Vector2 in_handle; //relative (x always <0)
Vector2 out_handle; //relative (x always >0)
- HandleMode handle_mode = HANDLE_MODE_BALANCED;
real_t value = 0.0;
+#ifdef TOOLS_ENABLED
+ HandleMode handle_mode = HANDLE_MODE_FREE;
+#endif // TOOLS_ENABLED
};
struct BezierTrack : public Track {
@@ -225,11 +238,13 @@ private:
_FORCE_INLINE_ Quaternion _interpolate(const Quaternion &p_a, const Quaternion &p_b, real_t p_c) const;
_FORCE_INLINE_ Variant _interpolate(const Variant &p_a, const Variant &p_b, real_t p_c) const;
_FORCE_INLINE_ real_t _interpolate(const real_t &p_a, const real_t &p_b, real_t p_c) const;
+ _FORCE_INLINE_ Variant _interpolate_angle(const Variant &p_a, const Variant &p_b, real_t p_c) const;
- _FORCE_INLINE_ Vector3 _cubic_interpolate(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c) const;
- _FORCE_INLINE_ Quaternion _cubic_interpolate(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, real_t p_c) const;
- _FORCE_INLINE_ Variant _cubic_interpolate(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c) const;
- _FORCE_INLINE_ real_t _cubic_interpolate(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c) const;
+ _FORCE_INLINE_ Vector3 _cubic_interpolate_in_time(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const;
+ _FORCE_INLINE_ Quaternion _cubic_interpolate_in_time(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const;
+ _FORCE_INLINE_ Variant _cubic_interpolate_in_time(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const;
+ _FORCE_INLINE_ real_t _cubic_interpolate_in_time(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const;
+ _FORCE_INLINE_ Variant _cubic_interpolate_angle_in_time(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const;
template <class T>
_FORCE_INLINE_ T _interpolate(const Vector<TKey<T>> &p_keys, double p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok, bool p_backward = false) const;
@@ -351,15 +366,16 @@ private:
return idxr;
}
- bool _position_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_alowed_linear_err, real_t p_allowed_angular_error, const Vector3 &p_norm);
- bool _rotation_track_optimize_key(const TKey<Quaternion> &t0, const TKey<Quaternion> &t1, const TKey<Quaternion> &t2, real_t p_allowed_angular_error, float p_max_optimizable_angle);
- bool _scale_track_optimize_key(const TKey<Vector3> &t0, const TKey<Vector3> &t1, const TKey<Vector3> &t2, real_t p_allowed_linear_error);
- bool _blend_shape_track_optimize_key(const TKey<float> &t0, const TKey<float> &t1, const TKey<float> &t2, real_t p_allowed_unit_error);
+ bool _float_track_optimize_key(const TKey<float> t0, const TKey<float> t1, const TKey<float> t2, real_t p_allowed_velocity_err, real_t p_allowed_precision_error);
+ bool _vector2_track_optimize_key(const TKey<Vector2> t0, const TKey<Vector2> t1, const TKey<Vector2> t2, real_t p_alowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error);
+ bool _vector3_track_optimize_key(const TKey<Vector3> t0, const TKey<Vector3> t1, const TKey<Vector3> t2, real_t p_alowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error);
+ bool _quaternion_track_optimize_key(const TKey<Quaternion> t0, const TKey<Quaternion> t1, const TKey<Quaternion> t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error);
- void _position_track_optimize(int p_idx, real_t p_allowed_linear_err, real_t p_allowed_angular_err);
- void _rotation_track_optimize(int p_idx, real_t p_allowed_angular_err, real_t p_max_optimizable_angle);
- void _scale_track_optimize(int p_idx, real_t p_allowed_linear_err);
- void _blend_shape_track_optimize(int p_idx, real_t p_allowed_unit_error);
+ void _position_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error);
+ void _rotation_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error);
+ void _scale_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error);
+ void _blend_shape_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_precision_error);
+ void _value_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error);
protected:
bool _set(const StringName &p_name, const Variant &p_value);
@@ -424,15 +440,17 @@ public:
void track_set_interpolation_type(int p_track, InterpolationType p_interp);
InterpolationType track_get_interpolation_type(int p_track) const;
- int bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const HandleMode p_handle_mode = HandleMode::HANDLE_MODE_BALANCED);
- void bezier_track_set_key_handle_mode(int p_track, int p_index, HandleMode p_mode, double p_balanced_value_time_ratio = 1.0);
+ int bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle);
void bezier_track_set_key_value(int p_track, int p_index, real_t p_value);
- void bezier_track_set_key_in_handle(int p_track, int p_index, const Vector2 &p_handle, double p_balanced_value_time_ratio = 1.0);
- void bezier_track_set_key_out_handle(int p_track, int p_index, const Vector2 &p_handle, double p_balanced_value_time_ratio = 1.0);
+ void bezier_track_set_key_in_handle(int p_track, int p_index, const Vector2 &p_handle, real_t p_balanced_value_time_ratio = 1.0);
+ void bezier_track_set_key_out_handle(int p_track, int p_index, const Vector2 &p_handle, real_t p_balanced_value_time_ratio = 1.0);
real_t bezier_track_get_key_value(int p_track, int p_index) const;
- int bezier_track_get_key_handle_mode(int p_track, int p_index) const;
Vector2 bezier_track_get_key_in_handle(int p_track, int p_index) const;
Vector2 bezier_track_get_key_out_handle(int p_track, int p_index) const;
+#ifdef TOOLS_ENABLED
+ void bezier_track_set_key_handle_mode(int p_track, int p_index, HandleMode p_mode, HandleSetMode p_set_mode = HANDLE_SET_MODE_NONE);
+ HandleMode bezier_track_get_key_handle_mode(int p_track, int p_index) const;
+#endif // TOOLS_ENABLED
real_t bezier_track_interpolate(int p_track, double p_time) const;
@@ -475,7 +493,7 @@ public:
void clear();
- void optimize(real_t p_allowed_linear_err = 0.05, real_t p_allowed_angular_err = 0.01, real_t p_max_optimizable_angle = Math_PI * 0.125);
+ void optimize(real_t p_allowed_velocity_err = 0.01, real_t p_allowed_angular_err = 0.01, int p_precision = 3);
void compress(uint32_t p_page_size = 8192, uint32_t p_fps = 120, float p_split_tolerance = 4.0); // 4.0 seems to be the split tolerance sweet spot from many tests
Animation();
@@ -485,7 +503,10 @@ public:
VARIANT_ENUM_CAST(Animation::TrackType);
VARIANT_ENUM_CAST(Animation::InterpolationType);
VARIANT_ENUM_CAST(Animation::UpdateMode);
-VARIANT_ENUM_CAST(Animation::HandleMode);
VARIANT_ENUM_CAST(Animation::LoopMode);
+#ifdef TOOLS_ENABLED
+VARIANT_ENUM_CAST(Animation::HandleMode);
+VARIANT_ENUM_CAST(Animation::HandleSetMode);
+#endif // TOOLS_ENABLED
#endif // ANIMATION_H
diff --git a/scene/resources/animation_library.cpp b/scene/resources/animation_library.cpp
index 5f725b2fbe..427d418551 100644
--- a/scene/resources/animation_library.cpp
+++ b/scene/resources/animation_library.cpp
@@ -85,7 +85,7 @@ bool AnimationLibrary::has_animation(const StringName &p_name) const {
}
Ref<Animation> AnimationLibrary::get_animation(const StringName &p_name) const {
- ERR_FAIL_COND_V(!animations.has(p_name), Ref<Animation>());
+ ERR_FAIL_COND_V_MSG(!animations.has(p_name), Ref<Animation>(), vformat("Animation not found: \"%s\".", p_name));
return animations[p_name];
}
diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp
index 1ff72825ac..9b1adde00a 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -31,6 +31,7 @@
#include "bit_map.h"
#include "core/io/image_loader.h"
+#include "core/variant/typed_array.h"
void BitMap::create(const Size2 &p_size) {
ERR_FAIL_COND(p_size.width < 1);
@@ -576,12 +577,12 @@ void BitMap::shrink_mask(int p_pixels, const Rect2 &p_rect) {
grow_mask(-p_pixels, p_rect);
}
-Array BitMap::_opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const {
+TypedArray<PackedVector2Array> BitMap::_opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const {
Vector<Vector<Vector2>> result = clip_opaque_to_polygons(p_rect, p_epsilon);
// Convert result to bindable types
- Array result_array;
+ TypedArray<PackedVector2Array> result_array;
result_array.resize(result.size());
for (int i = 0; i < result.size(); i++) {
const Vector<Vector2> &polygon = result[i];
@@ -669,7 +670,7 @@ void BitMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_size"), &BitMap::get_size);
ClassDB::bind_method(D_METHOD("resize", "new_size"), &BitMap::resize);
- ClassDB::bind_method(D_METHOD("_set_data"), &BitMap::_set_data);
+ ClassDB::bind_method(D_METHOD("_set_data", "data"), &BitMap::_set_data);
ClassDB::bind_method(D_METHOD("_get_data"), &BitMap::_get_data);
ClassDB::bind_method(D_METHOD("grow_mask", "pixels", "rect"), &BitMap::grow_mask);
diff --git a/scene/resources/bit_map.h b/scene/resources/bit_map.h
index 0d0d779c32..d8507dfa8b 100644
--- a/scene/resources/bit_map.h
+++ b/scene/resources/bit_map.h
@@ -35,6 +35,9 @@
#include "core/io/resource.h"
#include "core/io/resource_loader.h"
+template <typename T>
+class TypedArray;
+
class BitMap : public Resource {
GDCLASS(BitMap, Resource);
OBJ_SAVE_TYPE(BitMap);
@@ -45,7 +48,7 @@ class BitMap : public Resource {
Vector<Vector2> _march_square(const Rect2i &rect, const Point2i &start) const;
- Array _opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const;
+ TypedArray<PackedVector2Array> _opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) const;
protected:
void _set_data(const Dictionary &p_d);
diff --git a/scene/resources/bone_map.cpp b/scene/resources/bone_map.cpp
index aff917b2d4..dfaf82f36a 100644
--- a/scene/resources/bone_map.cpp
+++ b/scene/resources/bone_map.cpp
@@ -82,9 +82,13 @@ StringName BoneMap::get_skeleton_bone_name(StringName p_profile_bone_name) const
return bone_map.get(p_profile_bone_name);
}
-void BoneMap::set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name) {
+void BoneMap::_set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name) {
ERR_FAIL_COND(!bone_map.has(p_profile_bone_name));
bone_map.insert(p_profile_bone_name, p_skeleton_bone_name);
+}
+
+void BoneMap::set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name) {
+ _set_skeleton_bone_name(p_profile_bone_name, p_skeleton_bone_name);
emit_signal("bone_map_updated");
}
@@ -168,7 +172,9 @@ void BoneMap::_bind_methods() {
}
void BoneMap::_validate_property(PropertyInfo &property) const {
- //
+ if (property.name == "bonemap" || property.name == "profile") {
+ property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
}
BoneMap::BoneMap() {
diff --git a/scene/resources/bone_map.h b/scene/resources/bone_map.h
index 17452dfc73..a07a776e27 100644
--- a/scene/resources/bone_map.h
+++ b/scene/resources/bone_map.h
@@ -45,14 +45,11 @@ class BoneMap : public Resource {
protected:
bool _get(const StringName &p_path, Variant &r_ret) const;
bool _set(const StringName &p_path, const Variant &p_value);
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
static void _bind_methods();
public:
- int get_profile_type() const;
- void set_profile_type(const int p_profile_type);
-
Ref<SkeletonProfile> get_profile() const;
void set_profile(const Ref<SkeletonProfile> &p_profile);
@@ -60,6 +57,7 @@ public:
StringName get_skeleton_bone_name(StringName p_profile_bone_name) const;
void set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name);
+ void _set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name); // Avoid to emit signal for editor.
StringName find_profile_bone_name(StringName p_skeleton_bone_name) const;
diff --git a/scene/resources/camera_effects.cpp b/scene/resources/camera_effects.cpp
index 97617adbae..0b11366591 100644
--- a/scene/resources/camera_effects.cpp
+++ b/scene/resources/camera_effects.cpp
@@ -145,11 +145,11 @@ void CameraEffects::_update_override_exposure() {
// Private methods, constructor and destructor
-void CameraEffects::_validate_property(PropertyInfo &property) const {
- if ((!dof_blur_far_enabled && (property.name == "dof_blur_far_distance" || property.name == "dof_blur_far_transition")) ||
- (!dof_blur_near_enabled && (property.name == "dof_blur_near_distance" || property.name == "dof_blur_near_transition")) ||
- (!override_exposure_enabled && property.name == "override_exposure")) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void CameraEffects::_validate_property(PropertyInfo &p_property) const {
+ if ((!dof_blur_far_enabled && (p_property.name == "dof_blur_far_distance" || p_property.name == "dof_blur_far_transition")) ||
+ (!dof_blur_near_enabled && (p_property.name == "dof_blur_near_distance" || p_property.name == "dof_blur_near_transition")) ||
+ (!override_exposure_enabled && p_property.name == "override_exposure")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
diff --git a/scene/resources/camera_effects.h b/scene/resources/camera_effects.h
index 85ae64cdf5..7353931d16 100644
--- a/scene/resources/camera_effects.h
+++ b/scene/resources/camera_effects.h
@@ -59,7 +59,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
virtual RID get_rid() const override;
diff --git a/scene/resources/canvas_item_material.cpp b/scene/resources/canvas_item_material.cpp
index aa6cc4aded..b16059c218 100644
--- a/scene/resources/canvas_item_material.cpp
+++ b/scene/resources/canvas_item_material.cpp
@@ -227,9 +227,9 @@ bool CanvasItemMaterial::get_particles_anim_loop() const {
return particles_anim_loop;
}
-void CanvasItemMaterial::_validate_property(PropertyInfo &property) const {
- if (property.name.begins_with("particles_anim_") && !particles_animation) {
- property.usage = PROPERTY_USAGE_NONE;
+void CanvasItemMaterial::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name.begins_with("particles_anim_") && !particles_animation) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
diff --git a/scene/resources/canvas_item_material.h b/scene/resources/canvas_item_material.h
index 160c67d6b1..7eaf5051d4 100644
--- a/scene/resources/canvas_item_material.h
+++ b/scene/resources/canvas_item_material.h
@@ -117,7 +117,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_blend_mode(BlendMode p_blend_mode);
diff --git a/scene/resources/capsule_shape_3d.cpp b/scene/resources/capsule_shape_3d.cpp
index 214004824f..b0454004a0 100644
--- a/scene/resources/capsule_shape_3d.cpp
+++ b/scene/resources/capsule_shape_3d.cpp
@@ -40,8 +40,8 @@ Vector<Vector3> CapsuleShape3D::get_debug_mesh_lines() const {
Vector3 d(0, height * 0.5 - radius, 0);
for (int i = 0; i < 360; i++) {
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 1);
+ float ra = Math::deg_to_rad((float)i);
+ float rb = Math::deg_to_rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index da26a0261f..ee53578517 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -763,7 +763,7 @@ void Curve2D::_bake_segment2d(RBMap<real_t, Vector2> &r_bake, real_t p_begin, re
Vector2 nb = (end - mid).normalized();
real_t dp = na.dot(nb);
- if (dp < Math::cos(Math::deg2rad(p_tol))) {
+ if (dp < Math::cos(Math::deg_to_rad(p_tol))) {
r_bake[mp] = mid;
}
@@ -1167,7 +1167,7 @@ void Curve2D::_get_property_list(List<PropertyInfo> *p_list) const {
void Curve2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_count"), &Curve2D::get_point_count);
ClassDB::bind_method(D_METHOD("set_point_count", "count"), &Curve2D::set_point_count);
- ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "at_position"), &Curve2D::add_point, DEFVAL(Vector2()), DEFVAL(Vector2()), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "index"), &Curve2D::add_point, DEFVAL(Vector2()), DEFVAL(Vector2()), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("set_point_position", "idx", "position"), &Curve2D::set_point_position);
ClassDB::bind_method(D_METHOD("get_point_position", "idx"), &Curve2D::get_point_position);
ClassDB::bind_method(D_METHOD("set_point_in", "idx", "position"), &Curve2D::set_point_in);
@@ -1190,7 +1190,7 @@ void Curve2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("tessellate", "max_stages", "tolerance_degrees"), &Curve2D::tessellate, DEFVAL(5), DEFVAL(4));
ClassDB::bind_method(D_METHOD("_get_data"), &Curve2D::_get_data);
- ClassDB::bind_method(D_METHOD("_set_data"), &Curve2D::_set_data);
+ ClassDB::bind_method(D_METHOD("_set_data", "data"), &Curve2D::_set_data);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bake_interval", PROPERTY_HINT_RANGE, "0.01,512,0.01"), "set_bake_interval", "get_bake_interval");
ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
@@ -1352,7 +1352,7 @@ void Curve3D::_bake_segment3d(RBMap<real_t, Vector3> &r_bake, real_t p_begin, re
Vector3 nb = (end - mid).normalized();
real_t dp = na.dot(nb);
- if (dp < Math::cos(Math::deg2rad(p_tol))) {
+ if (dp < Math::cos(Math::deg_to_rad(p_tol))) {
r_bake[mp] = mid;
}
if (p_depth < p_max_depth) {
@@ -1972,7 +1972,7 @@ void Curve3D::_get_property_list(List<PropertyInfo> *p_list) const {
void Curve3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_count"), &Curve3D::get_point_count);
ClassDB::bind_method(D_METHOD("set_point_count", "count"), &Curve3D::set_point_count);
- ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "at_position"), &Curve3D::add_point, DEFVAL(Vector3()), DEFVAL(Vector3()), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("add_point", "position", "in", "out", "index"), &Curve3D::add_point, DEFVAL(Vector3()), DEFVAL(Vector3()), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("set_point_position", "idx", "position"), &Curve3D::set_point_position);
ClassDB::bind_method(D_METHOD("get_point_position", "idx"), &Curve3D::get_point_position);
ClassDB::bind_method(D_METHOD("set_point_tilt", "idx", "tilt"), &Curve3D::set_point_tilt);
@@ -2002,7 +2002,7 @@ void Curve3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("tessellate", "max_stages", "tolerance_degrees"), &Curve3D::tessellate, DEFVAL(5), DEFVAL(4));
ClassDB::bind_method(D_METHOD("_get_data"), &Curve3D::_get_data);
- ClassDB::bind_method(D_METHOD("_set_data"), &Curve3D::_set_data);
+ ClassDB::bind_method(D_METHOD("_set_data", "data"), &Curve3D::_set_data);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bake_interval", PROPERTY_HINT_RANGE, "0.01,512,0.01"), "set_bake_interval", "get_bake_interval");
ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
diff --git a/scene/resources/cylinder_shape_3d.cpp b/scene/resources/cylinder_shape_3d.cpp
index 345df5ffed..a5951db8ea 100644
--- a/scene/resources/cylinder_shape_3d.cpp
+++ b/scene/resources/cylinder_shape_3d.cpp
@@ -40,8 +40,8 @@ Vector<Vector3> CylinderShape3D::get_debug_mesh_lines() const {
Vector3 d(0, height * 0.5, 0);
for (int i = 0; i < 360; i++) {
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 1);
+ float ra = Math::deg_to_rad((float)i);
+ float rb = Math::deg_to_rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * radius;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * radius;
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 520a0a04ed..410f35e597 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -35,6 +35,7 @@
#include "default_theme_icons.gen.h"
#include "scene/resources/font.h"
#include "scene/resources/theme.h"
+#include "scene/theme/theme_db.h"
#include "servers/text_server.h"
#include "modules/modules_enabled.gen.h" // For svg.
@@ -84,7 +85,7 @@ static Ref<ImageTexture> generate_icon(int p_index) {
// with integer scales.
const bool upsample = !Math::is_equal_approx(Math::round(scale), scale);
ImageLoaderSVG img_loader;
- img_loader.create_image_from_string(img, default_theme_icons_sources[p_index], scale, upsample, false);
+ img_loader.create_image_from_string(img, default_theme_icons_sources[p_index], scale, upsample, HashMap<Color, Color>());
#endif
return ImageTexture::create_from_image(img);
@@ -177,6 +178,27 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("h_separation", "Button", 2 * scale);
+ // MenuBar
+ theme->set_stylebox("normal", "MenuBar", button_normal);
+ theme->set_stylebox("hover", "MenuBar", button_hover);
+ theme->set_stylebox("pressed", "MenuBar", button_pressed);
+ theme->set_stylebox("disabled", "MenuBar", button_disabled);
+ theme->set_stylebox("focus", "MenuBar", focus);
+
+ theme->set_font("font", "MenuBar", Ref<Font>());
+ theme->set_font_size("font_size", "MenuBar", -1);
+ theme->set_constant("outline_size", "MenuBar", 0 * scale);
+
+ theme->set_color("font_color", "MenuBar", control_font_color);
+ theme->set_color("font_pressed_color", "MenuBar", control_font_pressed_color);
+ theme->set_color("font_hover_color", "MenuBar", control_font_hover_color);
+ theme->set_color("font_focus_color", "MenuBar", control_font_focus_color);
+ theme->set_color("font_hover_pressed_color", "MenuBar", control_font_pressed_color);
+ theme->set_color("font_disabled_color", "MenuBar", control_font_disabled_color);
+ theme->set_color("font_outline_color", "MenuBar", Color(1, 1, 1));
+
+ theme->set_constant("h_separation", "MenuBar", 4 * scale);
+
// LinkButton
theme->set_stylebox("focus", "LinkButton", focus);
@@ -224,6 +246,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color", "OptionButton", control_font_color);
theme->set_color("font_pressed_color", "OptionButton", control_font_pressed_color);
theme->set_color("font_hover_color", "OptionButton", control_font_hover_color);
+ theme->set_color("font_hover_pressed_color", "OptionButton", control_font_pressed_color);
theme->set_color("font_focus_color", "OptionButton", control_font_focus_color);
theme->set_color("font_disabled_color", "OptionButton", control_font_disabled_color);
theme->set_color("font_outline_color", "OptionButton", Color(1, 1, 1));
@@ -231,6 +254,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("h_separation", "OptionButton", 2 * scale);
theme->set_constant("arrow_margin", "OptionButton", 4 * scale);
theme->set_constant("outline_size", "OptionButton", 0);
+ theme->set_constant("modulate_arrow", "OptionButton", false);
// MenuButton
@@ -644,9 +668,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("labeled_separator_right", "PopupMenu", separator_horizontal);
theme->set_icon("checked", "PopupMenu", icons["checked"]);
+ theme->set_icon("checked_disabled", "PopupMenu", icons["checked"]);
theme->set_icon("unchecked", "PopupMenu", icons["unchecked"]);
+ theme->set_icon("unchecked_disabled", "PopupMenu", icons["unchecked"]);
theme->set_icon("radio_checked", "PopupMenu", icons["radio_checked"]);
+ theme->set_icon("radio_checked_disabled", "PopupMenu", icons["radio_checked"]);
theme->set_icon("radio_unchecked", "PopupMenu", icons["radio_unchecked"]);
+ theme->set_icon("radio_unchecked_disabled", "PopupMenu", icons["radio_unchecked"]);
theme->set_icon("submenu", "PopupMenu", icons["popup_menu_arrow_right"]);
theme->set_icon("submenu_mirrored", "PopupMenu", icons["popup_menu_arrow_left"]);
@@ -663,6 +691,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_outline_color", "PopupMenu", Color(1, 1, 1));
theme->set_color("font_separator_outline_color", "PopupMenu", Color(1, 1, 1));
+ theme->set_constant("indent", "PopupMenu", 10 * scale);
theme->set_constant("h_separation", "PopupMenu", 4 * scale);
theme->set_constant("v_separation", "PopupMenu", 4 * scale);
theme->set_constant("outline_size", "PopupMenu", 0);
@@ -703,6 +732,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("resizer_color", "GraphNode", control_font_color);
theme->set_constant("separation", "GraphNode", 2 * scale);
theme->set_constant("title_offset", "GraphNode", 26 * scale);
+ theme->set_constant("title_h_offset", "GraphNode", 0);
theme->set_constant("close_offset", "GraphNode", 22 * scale);
theme->set_constant("close_h_offset", "GraphNode", 22 * scale);
theme->set_constant("port_offset", "GraphNode", 0);
@@ -741,7 +771,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_selected_color", "Tree", control_font_pressed_color);
theme->set_color("font_outline_color", "Tree", Color(1, 1, 1));
theme->set_color("guide_color", "Tree", Color(0.7, 0.7, 0.7, 0.25));
- theme->set_color("drop_position_color", "Tree", Color(1, 0.3, 0.2));
+ theme->set_color("drop_position_color", "Tree", Color(1, 1, 1));
theme->set_color("relationship_line_color", "Tree", Color(0.27, 0.27, 0.27));
theme->set_color("parent_hl_line_color", "Tree", Color(0.27, 0.27, 0.27));
theme->set_color("children_hl_line_color", "Tree", Color(0.27, 0.27, 0.27));
@@ -776,7 +806,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color", "ItemList", control_font_lower_color);
theme->set_color("font_selected_color", "ItemList", control_font_pressed_color);
theme->set_color("font_outline_color", "ItemList", Color(1, 1, 1));
- theme->set_color("guide_color", "ItemList", Color(0, 0, 0, 0.1));
+ theme->set_color("guide_color", "ItemList", Color(0.7, 0.7, 0.7, 0.25));
theme->set_stylebox("selected", "ItemList", make_flat_stylebox(style_selected_color));
theme->set_stylebox("selected_focus", "ItemList", make_flat_stylebox(style_selected_color));
theme->set_stylebox("cursor", "ItemList", focus);
@@ -1024,7 +1054,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
default_style = make_flat_stylebox(Color(1, 0.365, 0.365), 4, 4, 4, 4, 0, false, 2);
}
-void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPositioning p_font_subpixel, TextServer::Hinting p_font_hinting, bool p_font_antialiased, bool p_font_msdf, bool p_font_generate_mipmaps) {
+void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPositioning p_font_subpixel, TextServer::Hinting p_font_hinting, TextServer::FontAntialiasing p_font_antialiasing, bool p_font_msdf, bool p_font_generate_mipmaps) {
Ref<Theme> t;
t.instantiate();
@@ -1048,7 +1078,7 @@ void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPos
dynamic_font->set_data_ptr(_font_OpenSans_SemiBold, _font_OpenSans_SemiBold_size);
dynamic_font->set_subpixel_positioning(p_font_subpixel);
dynamic_font->set_hinting(p_font_hinting);
- dynamic_font->set_antialiased(p_font_antialiased);
+ dynamic_font->set_antialiasing(p_font_antialiasing);
dynamic_font->set_multichannel_signed_distance_field(p_font_msdf);
dynamic_font->set_generate_mipmaps(p_font_generate_mipmaps);
@@ -1072,18 +1102,11 @@ void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPos
fill_default_theme(t, default_font, bold_font, bold_italics_font, italics_font, default_icon, default_style, default_scale);
- Theme::set_default(t);
- Theme::set_fallback_base_scale(default_scale);
- Theme::set_fallback_icon(default_icon);
- Theme::set_fallback_style(default_style);
- Theme::set_fallback_font(default_font);
- Theme::set_fallback_font_size(default_font_size * default_scale);
-}
+ ThemeDB::get_singleton()->set_default_theme(t);
-void clear_default_theme() {
- Theme::set_project_default(nullptr);
- Theme::set_default(nullptr);
- Theme::set_fallback_icon(nullptr);
- Theme::set_fallback_style(nullptr);
- Theme::set_fallback_font(nullptr);
+ ThemeDB::get_singleton()->set_fallback_base_scale(default_scale);
+ ThemeDB::get_singleton()->set_fallback_icon(default_icon);
+ ThemeDB::get_singleton()->set_fallback_stylebox(default_style);
+ ThemeDB::get_singleton()->set_fallback_font(default_font);
+ ThemeDB::get_singleton()->set_fallback_font_size(default_font_size * default_scale);
}
diff --git a/scene/resources/default_theme/default_theme.h b/scene/resources/default_theme/default_theme.h
index 9b070a90cc..003934ce90 100644
--- a/scene/resources/default_theme/default_theme.h
+++ b/scene/resources/default_theme/default_theme.h
@@ -36,7 +36,6 @@
const int default_font_size = 16;
void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<Font> &bold_font, const Ref<Font> &bold_italics_font, const Ref<Font> &italics_font, Ref<Texture2D> &default_icon, Ref<StyleBox> &default_style, float p_scale);
-void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPositioning p_font_subpixel = TextServer::SUBPIXEL_POSITIONING_AUTO, TextServer::Hinting p_font_hinting = TextServer::HINTING_LIGHT, bool p_font_antialiased = true, bool p_font_msdf = false, bool p_font_generate_mipmaps = false);
-void clear_default_theme();
+void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPositioning p_font_subpixel = TextServer::SUBPIXEL_POSITIONING_AUTO, TextServer::Hinting p_font_hinting = TextServer::HINTING_LIGHT, TextServer::FontAntialiasing p_font_antialiased = TextServer::FONT_ANTIALIASING_GRAY, bool p_font_msdf = false, bool p_font_generate_mipmaps = false);
#endif // DEFAULT_THEME_H
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index a8d4903dad..f7a7818b3b 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -1037,46 +1037,46 @@ void Environment::_update_adjustment() {
// Private methods, constructor and destructor
-void Environment::_validate_property(PropertyInfo &property) const {
- if (property.name == "sky" || property.name == "sky_custom_fov" || property.name == "sky_rotation" || property.name == "ambient_light/sky_contribution") {
+void Environment::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "sky" || p_property.name == "sky_custom_fov" || p_property.name == "sky_rotation" || p_property.name == "ambient_light_sky_contribution") {
if (bg_mode != BG_SKY && ambient_source != AMBIENT_SOURCE_SKY && reflection_source != REFLECTION_SOURCE_SKY) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
- if (property.name == "fog_aerial_perspective") {
+ if (p_property.name == "fog_aerial_perspective") {
if (bg_mode != BG_SKY) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
- if (property.name == "tonemap_white" && tone_mapper == TONE_MAPPER_LINEAR) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name == "tonemap_white" && tone_mapper == TONE_MAPPER_LINEAR) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "glow_intensity" && glow_blend_mode == GLOW_BLEND_MODE_MIX) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name == "glow_intensity" && glow_blend_mode == GLOW_BLEND_MODE_MIX) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "glow_mix" && glow_blend_mode != GLOW_BLEND_MODE_MIX) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name == "glow_mix" && glow_blend_mode != GLOW_BLEND_MODE_MIX) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "background_color") {
+ if (p_property.name == "background_color") {
if (bg_mode != BG_COLOR && ambient_source != AMBIENT_SOURCE_COLOR) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
- if (property.name == "background_canvas_max_layer") {
+ if (p_property.name == "background_canvas_max_layer") {
if (bg_mode != BG_CANVAS) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
- if (property.name == "background_camera_feed_id") {
+ if (p_property.name == "background_camera_feed_id") {
if (bg_mode != BG_CAMERA_FEED) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
@@ -1107,8 +1107,8 @@ void Environment::_validate_property(PropertyInfo &property) const {
String prefix = String(*prefixes);
String enabled = prefix + "enabled";
- if (property.name.begins_with(prefix) && property.name != enabled && !bool(get(enabled))) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name.begins_with(prefix) && p_property.name != enabled && !bool(get(enabled))) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
return;
}
@@ -1120,8 +1120,8 @@ void Environment::_validate_property(PropertyInfo &property) const {
while (*prefixes) {
String prefix = String(*prefixes);
- if (property.name.begins_with(prefix)) {
- property.usage = PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL;
+ if (p_property.name.begins_with(prefix)) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
return;
}
@@ -1249,8 +1249,8 @@ void Environment::_bind_methods() {
ADD_GROUP("SSR", "ssr_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ssr_enabled"), "set_ssr_enabled", "is_ssr_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "ssr_max_steps", PROPERTY_HINT_RANGE, "1,512,1"), "set_ssr_max_steps", "get_ssr_max_steps");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssr_fade_in", PROPERTY_HINT_EXP_EASING), "set_ssr_fade_in", "get_ssr_fade_in");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssr_fade_out", PROPERTY_HINT_EXP_EASING), "set_ssr_fade_out", "get_ssr_fade_out");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssr_fade_in", PROPERTY_HINT_EXP_EASING, "positive_only"), "set_ssr_fade_in", "get_ssr_fade_in");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssr_fade_out", PROPERTY_HINT_EXP_EASING, "positive_only"), "set_ssr_fade_out", "get_ssr_fade_out");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssr_depth_tolerance", PROPERTY_HINT_RANGE, "0.01,128,0.1"), "set_ssr_depth_tolerance", "get_ssr_depth_tolerance");
// SSAO
@@ -1277,7 +1277,7 @@ void Environment::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ssao_enabled"), "set_ssao_enabled", "is_ssao_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_radius", PROPERTY_HINT_RANGE, "0.01,16,0.01,or_greater"), "set_ssao_radius", "get_ssao_radius");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_intensity", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_ssao_intensity", "get_ssao_intensity");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_power", PROPERTY_HINT_EXP_EASING), "set_ssao_power", "get_ssao_power");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_power", PROPERTY_HINT_EXP_EASING, "positive_only"), "set_ssao_power", "get_ssao_power");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_detail", PROPERTY_HINT_RANGE, "0,5,0.01"), "set_ssao_detail", "get_ssao_detail");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_horizon", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ssao_horizon", "get_ssao_horizon");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_sharpness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ssao_sharpness", "get_ssao_sharpness");
@@ -1337,8 +1337,10 @@ void Environment::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_bounce_feedback", PROPERTY_HINT_RANGE, "0,1.99,0.01"), "set_sdfgi_bounce_feedback", "get_sdfgi_bounce_feedback");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sdfgi_cascades", PROPERTY_HINT_RANGE, "1,8,1"), "set_sdfgi_cascades", "get_sdfgi_cascades");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_min_cell_size", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_sdfgi_min_cell_size", "get_sdfgi_min_cell_size");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_cascade0_distance", PROPERTY_HINT_RANGE, "0.1,16384,0.1,or_greater"), "set_sdfgi_cascade0_distance", "get_sdfgi_cascade0_distance");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_max_distance", PROPERTY_HINT_RANGE, "0.1,16384,0.1,or_greater"), "set_sdfgi_max_distance", "get_sdfgi_max_distance");
+ // Don't store the values of `sdfgi_cascade0_distance` and `sdfgi_max_distance`
+ // as they're derived from `sdfgi_min_cell_size`.
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_cascade0_distance", PROPERTY_HINT_RANGE, "0.1,16384,0.1,or_greater", PROPERTY_USAGE_EDITOR), "set_sdfgi_cascade0_distance", "get_sdfgi_cascade0_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_max_distance", PROPERTY_HINT_RANGE, "0.1,16384,0.1,or_greater", PROPERTY_USAGE_EDITOR), "set_sdfgi_max_distance", "get_sdfgi_max_distance");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sdfgi_y_scale", PROPERTY_HINT_ENUM, "50% (Compact),75% (Balanced),100% (Sparse)"), "set_sdfgi_y_scale", "get_sdfgi_y_scale");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_energy"), "set_sdfgi_energy", "get_sdfgi_energy");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_normal_bias"), "set_sdfgi_normal_bias", "get_sdfgi_normal_bias");
@@ -1462,7 +1464,7 @@ void Environment::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_gi_inject", PROPERTY_HINT_RANGE, "0.0,16,0.01,exp"), "set_volumetric_fog_gi_inject", "get_volumetric_fog_gi_inject");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_anisotropy", PROPERTY_HINT_RANGE, "-0.9,0.9,0.01"), "set_volumetric_fog_anisotropy", "get_volumetric_fog_anisotropy");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_length", PROPERTY_HINT_RANGE, "0,1024,0.01,or_greater"), "set_volumetric_fog_length", "get_volumetric_fog_length");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_detail_spread", PROPERTY_HINT_EXP_EASING), "set_volumetric_fog_detail_spread", "get_volumetric_fog_detail_spread");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_detail_spread", PROPERTY_HINT_EXP_EASING, "positive_only"), "set_volumetric_fog_detail_spread", "get_volumetric_fog_detail_spread");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_ambient_inject", PROPERTY_HINT_RANGE, "0.0,16,0.01,exp"), "set_volumetric_fog_ambient_inject", "get_volumetric_fog_ambient_inject");
ADD_SUBGROUP("Temporal Reprojection", "volumetric_fog_temporal_reprojection_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "volumetric_fog_temporal_reprojection_enabled"), "set_volumetric_fog_temporal_reprojection_enabled", "is_volumetric_fog_temporal_reprojection_enabled");
diff --git a/scene/resources/environment.h b/scene/resources/environment.h
index b71fe8904a..d39cb1acd8 100644
--- a/scene/resources/environment.h
+++ b/scene/resources/environment.h
@@ -175,10 +175,10 @@ private:
// Fog
bool fog_enabled = false;
- Color fog_light_color = Color(0.5, 0.6, 0.7);
+ Color fog_light_color = Color(0.518, 0.553, 0.608);
float fog_light_energy = 1.0;
float fog_sun_scatter = 0.0;
- float fog_density = 0.001;
+ float fog_density = 0.01;
float fog_height = 0.0;
float fog_height_density = 0.0; //can be negative to invert effect
float fog_aerial_perspective = 0.0;
@@ -194,8 +194,8 @@ private:
float volumetric_fog_anisotropy = 0.2;
float volumetric_fog_length = 64.0;
float volumetric_fog_detail_spread = 2.0;
- float volumetric_fog_gi_inject = 0.0;
- float volumetric_fog_ambient_inject = false;
+ float volumetric_fog_gi_inject = 1.0;
+ float volumetric_fog_ambient_inject = 0.0;
bool volumetric_fog_temporal_reproject = true;
float volumetric_fog_temporal_reproject_amount = 0.9;
void _update_volumetric_fog();
@@ -211,7 +211,7 @@ private:
protected:
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
#ifndef DISABLE_DEPRECATED
// Kept for compatibility from 3.x to 4.0.
bool _set(const StringName &p_name, const Variant &p_value);
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 619036d296..189d8d5502 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -39,6 +39,7 @@
#include "scene/resources/text_line.h"
#include "scene/resources/text_paragraph.h"
#include "scene/resources/theme.h"
+#include "scene/theme/theme_db.h"
/*************************************************************************/
/* Font */
@@ -576,7 +577,7 @@ _FORCE_INLINE_ void FontFile::_ensure_rid(int p_cache_index) const {
if (unlikely(!cache[p_cache_index].is_valid())) {
cache.write[p_cache_index] = TS->create_font();
TS->font_set_data_ptr(cache[p_cache_index], data_ptr, data_size);
- TS->font_set_antialiased(cache[p_cache_index], antialiased);
+ TS->font_set_antialiasing(cache[p_cache_index], antialiasing);
TS->font_set_generate_mipmaps(cache[p_cache_index], mipmaps);
TS->font_set_multichannel_signed_distance_field(cache[p_cache_index], msdf);
TS->font_set_msdf_pixel_range(cache[p_cache_index], msdf_pixel_range);
@@ -875,8 +876,8 @@ void FontFile::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_font_style_name", "name"), &FontFile::set_font_style_name);
ClassDB::bind_method(D_METHOD("set_font_style", "style"), &FontFile::set_font_style);
- ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &FontFile::set_antialiased);
- ClassDB::bind_method(D_METHOD("is_antialiased"), &FontFile::is_antialiased);
+ ClassDB::bind_method(D_METHOD("set_antialiasing", "antialiasing"), &FontFile::set_antialiasing);
+ ClassDB::bind_method(D_METHOD("get_antialiasing"), &FontFile::get_antialiasing);
ClassDB::bind_method(D_METHOD("set_generate_mipmaps", "generate_mipmaps"), &FontFile::set_generate_mipmaps);
ClassDB::bind_method(D_METHOD("get_generate_mipmaps"), &FontFile::get_generate_mipmaps);
@@ -996,7 +997,7 @@ void FontFile::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_data", "get_data");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_mipmaps", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_generate_mipmaps", "get_generate_mipmaps");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_antialiased", "is_antialiased");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD sub-pixel", PROPERTY_USAGE_STORAGE), "set_antialiasing", "get_antialiasing");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "font_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_name", "get_font_name");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "style_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE), "set_font_style_name", "get_font_style_name");
ADD_PROPERTY(PropertyInfo(Variant::INT, "font_style", PROPERTY_HINT_FLAGS, "Bold,Italic,Fixed Size", PROPERTY_USAGE_STORAGE), "set_font_style", "get_font_style");
@@ -1267,7 +1268,7 @@ void FontFile::_get_property_list(List<PropertyInfo> *p_list) const {
}
for (int i = 0; i < cache.size(); i++) {
String prefix = "cache/" + itos(i) + "/";
- Array sizes = get_size_cache_list(i);
+ TypedArray<Vector2i> sizes = get_size_cache_list(i);
p_list->push_back(PropertyInfo(Variant::DICTIONARY, prefix + "variation_coordinates", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
p_list->push_back(PropertyInfo(Variant::INT, "face_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
p_list->push_back(PropertyInfo(Variant::FLOAT, "embolden", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
@@ -1289,7 +1290,7 @@ void FontFile::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, prefix_sz + "textures/" + itos(k) + "/offsets", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
p_list->push_back(PropertyInfo(Variant::OBJECT, prefix_sz + "textures/" + itos(k) + "/image", PROPERTY_HINT_RESOURCE_TYPE, "Image", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT));
}
- Array glyphs = get_glyph_list(i, sz);
+ PackedInt32Array glyphs = get_glyph_list(i, sz);
for (int k = 0; k < glyphs.size(); k++) {
const int32_t &gl = glyphs[k];
if (sz.y == 0) {
@@ -1301,7 +1302,7 @@ void FontFile::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::INT, prefix_sz + "glyphs/" + itos(gl) + "/texture_idx", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
}
if (sz.y == 0) {
- Array kerning_map = get_kerning_list(i, sz.x);
+ TypedArray<Vector2i> kerning_map = get_kerning_list(i, sz.x);
for (int k = 0; k < kerning_map.size(); k++) {
const Vector2i &gl_pair = kerning_map[k];
p_list->push_back(PropertyInfo(Variant::VECTOR2, prefix_sz + "kerning_overrides/" + itos(gl_pair.x) + "/" + itos(gl_pair.y), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE));
@@ -1318,7 +1319,7 @@ void FontFile::reset_state() {
data_size = 0;
cache.clear();
- antialiased = true;
+ antialiasing = TextServer::FONT_ANTIALIASING_GRAY;
mipmaps = false;
msdf = false;
force_autohinter = false;
@@ -1337,7 +1338,7 @@ void FontFile::reset_state() {
Error FontFile::load_bitmap_font(const String &p_path) {
reset_state();
- antialiased = false;
+ antialiasing = TextServer::FONT_ANTIALIASING_NONE;
mipmaps = false;
msdf = false;
force_autohinter = false;
@@ -1426,7 +1427,7 @@ Error FontFile::load_bitmap_font(const String &p_path) {
while (!f->eof_reached() && f->get_position() <= off + block_size) {
if (c == '\0') {
String base_dir = p_path.get_base_dir();
- String file = base_dir.plus_file(String::utf8(cs.ptr(), cs.length()));
+ String file = base_dir.path_join(String::utf8(cs.ptr(), cs.length()));
if (RenderingServer::get_singleton() != nullptr) {
Ref<Image> img;
img.instantiate();
@@ -1659,7 +1660,7 @@ Error FontFile::load_bitmap_font(const String &p_path) {
}
if (keys.has("file")) {
String base_dir = p_path.get_base_dir();
- String file = base_dir.plus_file(keys["file"]);
+ String file = base_dir.path_join(keys["file"]);
if (RenderingServer::get_singleton() != nullptr) {
Ref<Image> img;
img.instantiate();
@@ -1817,11 +1818,9 @@ void FontFile::set_data_ptr(const uint8_t *p_data, size_t p_size) {
data_ptr = p_data;
data_size = p_size;
- if (data_ptr != nullptr) {
- for (int i = 0; i < cache.size(); i++) {
- if (cache[i].is_valid()) {
- TS->font_set_data_ptr(cache[i], data_ptr, data_size);
- }
+ for (int i = 0; i < cache.size(); i++) {
+ if (cache[i].is_valid()) {
+ TS->font_set_data_ptr(cache[i], data_ptr, data_size);
}
}
}
@@ -1831,11 +1830,9 @@ void FontFile::set_data(const PackedByteArray &p_data) {
data_ptr = data.ptr();
data_size = data.size();
- if (data_ptr != nullptr) {
- for (int i = 0; i < cache.size(); i++) {
- if (cache[i].is_valid()) {
- TS->font_set_data_ptr(cache[i], data_ptr, data_size);
- }
+ for (int i = 0; i < cache.size(); i++) {
+ if (cache[i].is_valid()) {
+ TS->font_set_data_ptr(cache[i], data_ptr, data_size);
}
}
}
@@ -1864,19 +1861,19 @@ void FontFile::set_font_style(BitField<TextServer::FontStyle> p_style) {
TS->font_set_style(cache[0], p_style);
}
-void FontFile::set_antialiased(bool p_antialiased) {
- if (antialiased != p_antialiased) {
- antialiased = p_antialiased;
+void FontFile::set_antialiasing(TextServer::FontAntialiasing p_antialiasing) {
+ if (antialiasing != p_antialiasing) {
+ antialiasing = p_antialiasing;
for (int i = 0; i < cache.size(); i++) {
_ensure_rid(i);
- TS->font_set_antialiased(cache[i], antialiased);
+ TS->font_set_antialiasing(cache[i], antialiasing);
}
emit_changed();
}
}
-bool FontFile::is_antialiased() const {
- return antialiased;
+TextServer::FontAntialiasing FontFile::get_antialiasing() const {
+ return antialiasing;
}
void FontFile::set_generate_mipmaps(bool p_generate_mipmaps) {
@@ -2089,7 +2086,7 @@ void FontFile::remove_cache(int p_cache_index) {
emit_changed();
}
-Array FontFile::get_size_cache_list(int p_cache_index) const {
+TypedArray<Vector2i> FontFile::get_size_cache_list(int p_cache_index) const {
ERR_FAIL_COND_V(p_cache_index < 0, Array());
_ensure_rid(p_cache_index);
return TS->font_get_size_cache_list(cache[p_cache_index]);
@@ -2260,8 +2257,8 @@ PackedInt32Array FontFile::get_texture_offsets(int p_cache_index, const Vector2i
return TS->font_get_texture_offsets(cache[p_cache_index], p_size, p_texture_index);
}
-Array FontFile::get_glyph_list(int p_cache_index, const Vector2i &p_size) const {
- ERR_FAIL_COND_V(p_cache_index < 0, Array());
+PackedInt32Array FontFile::get_glyph_list(int p_cache_index, const Vector2i &p_size) const {
+ ERR_FAIL_COND_V(p_cache_index < 0, PackedInt32Array());
_ensure_rid(p_cache_index);
return TS->font_get_glyph_list(cache[p_cache_index], p_size);
}
@@ -2338,7 +2335,7 @@ int FontFile::get_glyph_texture_idx(int p_cache_index, const Vector2i &p_size, i
return TS->font_get_glyph_texture_idx(cache[p_cache_index], p_size, p_glyph);
}
-Array FontFile::get_kerning_list(int p_cache_index, int p_size) const {
+TypedArray<Vector2i> FontFile::get_kerning_list(int p_cache_index, int p_size) const {
ERR_FAIL_COND_V(p_cache_index < 0, Array());
_ensure_rid(p_cache_index);
return TS->font_get_kerning_list(cache[p_cache_index], p_size);
@@ -2556,13 +2553,13 @@ Ref<Font> FontVariation::_get_base_font_or_default() const {
}
// Check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
List<StringName> theme_types;
- Theme::get_project_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
+ ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
for (const StringName &E : theme_types) {
- if (Theme::get_project_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
- Ref<Font> f = Theme::get_project_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ Ref<Font> f = ThemeDB::get_singleton()->get_project_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
@@ -2573,13 +2570,13 @@ Ref<Font> FontVariation::_get_base_font_or_default() const {
}
// Lastly, fall back on the items defined in the default Theme, if they exist.
- if (Theme::get_default().is_valid()) {
+ if (ThemeDB::get_singleton()->get_default_theme().is_valid()) {
List<StringName> theme_types;
- Theme::get_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
for (const StringName &E : theme_types) {
- if (Theme::get_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
- Ref<Font> f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ Ref<Font> f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
@@ -2589,7 +2586,7 @@ Ref<Font> FontVariation::_get_base_font_or_default() const {
}
// If they don't exist, use any type to return the default/empty value.
- Ref<Font> f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
+ Ref<Font> f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
@@ -2699,8 +2696,8 @@ FontVariation::~FontVariation() {
/*************************************************************************/
void SystemFont::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &SystemFont::set_antialiased);
- ClassDB::bind_method(D_METHOD("is_antialiased"), &SystemFont::is_antialiased);
+ ClassDB::bind_method(D_METHOD("set_antialiasing", "antialiasing"), &SystemFont::set_antialiasing);
+ ClassDB::bind_method(D_METHOD("get_antialiasing"), &SystemFont::get_antialiasing);
ClassDB::bind_method(D_METHOD("set_generate_mipmaps", "generate_mipmaps"), &SystemFont::set_generate_mipmaps);
ClassDB::bind_method(D_METHOD("get_generate_mipmaps"), &SystemFont::get_generate_mipmaps);
@@ -2714,6 +2711,9 @@ void SystemFont::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_subpixel_positioning", "subpixel_positioning"), &SystemFont::set_subpixel_positioning);
ClassDB::bind_method(D_METHOD("get_subpixel_positioning"), &SystemFont::get_subpixel_positioning);
+ ClassDB::bind_method(D_METHOD("set_multichannel_signed_distance_field", "msdf"), &SystemFont::set_multichannel_signed_distance_field);
+ ClassDB::bind_method(D_METHOD("is_multichannel_signed_distance_field"), &SystemFont::is_multichannel_signed_distance_field);
+
ClassDB::bind_method(D_METHOD("set_oversampling", "oversampling"), &SystemFont::set_oversampling);
ClassDB::bind_method(D_METHOD("get_oversampling"), &SystemFont::get_oversampling);
@@ -2724,11 +2724,12 @@ void SystemFont::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "font_names"), "set_font_names", "get_font_names");
ADD_PROPERTY(PropertyInfo(Variant::INT, "font_style", PROPERTY_HINT_FLAGS, "Bold,Italic"), "set_font_style", "get_font_style");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased"), "set_antialiased", "is_antialiased");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD sub-pixel", PROPERTY_USAGE_STORAGE), "set_antialiasing", "get_antialiasing");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_mipmaps"), "set_generate_mipmaps", "get_generate_mipmaps");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "force_autohinter"), "set_force_autohinter", "is_force_autohinter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), "set_hinting", "get_hinting");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One half of a pixel,One quarter of a pixel"), "set_subpixel_positioning", "get_subpixel_positioning");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field"), "set_multichannel_signed_distance_field", "is_multichannel_signed_distance_field");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_RANGE, "0,10,0.1"), "set_oversampling", "get_oversampling");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Font")), "set_fallbacks", "get_fallbacks");
}
@@ -2800,14 +2801,17 @@ void SystemFont::_update_base_font() {
}
// Apply font rendering settings.
- file->set_antialiased(antialiased);
+ file->set_antialiasing(antialiasing);
file->set_generate_mipmaps(mipmaps);
file->set_force_autohinter(force_autohinter);
file->set_hinting(hinting);
file->set_subpixel_positioning(subpixel_positioning);
+ file->set_multichannel_signed_distance_field(msdf);
file->set_oversampling(oversampling);
base_font = file;
+
+ break;
}
if (base_font.is_valid()) {
@@ -2834,12 +2838,13 @@ void SystemFont::reset_state() {
ftr_weight = 0;
ftr_italic = 0;
style = 0;
- antialiased = true;
+ antialiasing = TextServer::FONT_ANTIALIASING_GRAY;
mipmaps = false;
force_autohinter = false;
hinting = TextServer::HINTING_LIGHT;
subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_DISABLED;
oversampling = 0.f;
+ msdf = false;
Font::reset_state();
}
@@ -2855,13 +2860,13 @@ Ref<Font> SystemFont::_get_base_font_or_default() const {
}
// Check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
List<StringName> theme_types;
- Theme::get_project_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
+ ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
for (const StringName &E : theme_types) {
- if (Theme::get_project_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
- Ref<Font> f = Theme::get_project_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ Ref<Font> f = ThemeDB::get_singleton()->get_project_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<SystemFont *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
@@ -2872,13 +2877,13 @@ Ref<Font> SystemFont::_get_base_font_or_default() const {
}
// Lastly, fall back on the items defined in the default Theme, if they exist.
- if (Theme::get_default().is_valid()) {
+ if (ThemeDB::get_singleton()->get_default_theme().is_valid()) {
List<StringName> theme_types;
- Theme::get_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
for (const StringName &E : theme_types) {
- if (Theme::get_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
- Ref<Font> f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ Ref<Font> f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<SystemFont *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
@@ -2888,7 +2893,7 @@ Ref<Font> SystemFont::_get_base_font_or_default() const {
}
// If they don't exist, use any type to return the default/empty value.
- Ref<Font> f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
+ Ref<Font> f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<SystemFont *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
@@ -2899,18 +2904,18 @@ Ref<Font> SystemFont::_get_base_font_or_default() const {
return Ref<Font>();
}
-void SystemFont::set_antialiased(bool p_antialiased) {
- if (antialiased != p_antialiased) {
- antialiased = p_antialiased;
+void SystemFont::set_antialiasing(TextServer::FontAntialiasing p_antialiasing) {
+ if (antialiasing != p_antialiasing) {
+ antialiasing = p_antialiasing;
if (base_font.is_valid()) {
- base_font->set_antialiased(antialiased);
+ base_font->set_antialiasing(antialiasing);
}
emit_changed();
}
}
-bool SystemFont::is_antialiased() const {
- return antialiased;
+TextServer::FontAntialiasing SystemFont::get_antialiasing() const {
+ return antialiasing;
}
void SystemFont::set_generate_mipmaps(bool p_generate_mipmaps) {
@@ -2969,6 +2974,20 @@ TextServer::SubpixelPositioning SystemFont::get_subpixel_positioning() const {
return subpixel_positioning;
}
+void SystemFont::set_multichannel_signed_distance_field(bool p_msdf) {
+ if (msdf != p_msdf) {
+ msdf = p_msdf;
+ if (base_font.is_valid()) {
+ base_font->set_multichannel_signed_distance_field(msdf);
+ }
+ emit_changed();
+ }
+}
+
+bool SystemFont::is_multichannel_signed_distance_field() const {
+ return msdf;
+}
+
void SystemFont::set_oversampling(real_t p_oversampling) {
if (oversampling != p_oversampling) {
oversampling = p_oversampling;
diff --git a/scene/resources/font.h b/scene/resources/font.h
index 260b4e521f..5cf596b41d 100644
--- a/scene/resources/font.h
+++ b/scene/resources/font.h
@@ -141,7 +141,7 @@ class FontFile : public Font {
size_t data_size = 0;
PackedByteArray data;
- bool antialiased = true;
+ TextServer::FontAntialiasing antialiasing = TextServer::FONT_ANTIALIASING_GRAY;
bool mipmaps = false;
bool msdf = false;
int msdf_pixel_range = 16;
@@ -192,8 +192,8 @@ public:
virtual void set_font_style_name(const String &p_name);
virtual void set_font_style(BitField<TextServer::FontStyle> p_style);
- virtual void set_antialiased(bool p_antialiased);
- virtual bool is_antialiased() const;
+ virtual void set_antialiasing(TextServer::FontAntialiasing p_antialiasing);
+ virtual TextServer::FontAntialiasing get_antialiasing() const;
virtual void set_generate_mipmaps(bool p_generate_mipmaps);
virtual bool get_generate_mipmaps() const;
@@ -230,7 +230,7 @@ public:
virtual void clear_cache();
virtual void remove_cache(int p_cache_index);
- virtual Array get_size_cache_list(int p_cache_index) const;
+ virtual TypedArray<Vector2i> get_size_cache_list(int p_cache_index) const;
virtual void clear_size_cache(int p_cache_index);
virtual void remove_size_cache(int p_cache_index, const Vector2i &p_size);
@@ -271,7 +271,7 @@ public:
virtual void set_texture_offsets(int p_cache_index, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset);
virtual PackedInt32Array get_texture_offsets(int p_cache_index, const Vector2i &p_size, int p_texture_index) const;
- virtual Array get_glyph_list(int p_cache_index, const Vector2i &p_size) const;
+ virtual PackedInt32Array get_glyph_list(int p_cache_index, const Vector2i &p_size) const;
virtual void clear_glyphs(int p_cache_index, const Vector2i &p_size);
virtual void remove_glyph(int p_cache_index, const Vector2i &p_size, int32_t p_glyph);
@@ -290,7 +290,7 @@ public:
virtual void set_glyph_texture_idx(int p_cache_index, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx);
virtual int get_glyph_texture_idx(int p_cache_index, const Vector2i &p_size, int32_t p_glyph) const;
- virtual Array get_kerning_list(int p_cache_index, int p_size) const;
+ virtual TypedArray<Vector2i> get_kerning_list(int p_cache_index, int p_size) const;
virtual void clear_kerning_map(int p_cache_index, int p_size);
virtual void remove_kerning(int p_cache_index, int p_size, const Vector2i &p_glyph_pair);
@@ -398,12 +398,13 @@ class SystemFont : public Font {
int ftr_weight = 0;
int ftr_italic = 0;
- bool antialiased = true;
+ TextServer::FontAntialiasing antialiasing = TextServer::FONT_ANTIALIASING_GRAY;
bool mipmaps = false;
bool force_autohinter = false;
TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
TextServer::SubpixelPositioning subpixel_positioning = TextServer::SUBPIXEL_POSITIONING_AUTO;
real_t oversampling = 0.f;
+ bool msdf = false;
protected:
static void _bind_methods();
@@ -416,8 +417,8 @@ protected:
public:
virtual Ref<Font> _get_base_font_or_default() const;
- virtual void set_antialiased(bool p_antialiased);
- virtual bool is_antialiased() const;
+ virtual void set_antialiasing(TextServer::FontAntialiasing p_antialiasing);
+ virtual TextServer::FontAntialiasing get_antialiasing() const;
virtual void set_generate_mipmaps(bool p_generate_mipmaps);
virtual bool get_generate_mipmaps() const;
@@ -434,6 +435,9 @@ public:
virtual void set_oversampling(real_t p_oversampling);
virtual real_t get_oversampling() const;
+ virtual void set_multichannel_signed_distance_field(bool p_msdf);
+ virtual bool is_multichannel_signed_distance_field() const;
+
virtual void set_font_names(const PackedStringArray &p_names);
virtual PackedStringArray get_font_names() const;
diff --git a/scene/resources/immediate_mesh.cpp b/scene/resources/immediate_mesh.cpp
index 044477e744..90cc3ea5f4 100644
--- a/scene/resources/immediate_mesh.cpp
+++ b/scene/resources/immediate_mesh.cpp
@@ -340,8 +340,8 @@ Array ImmediateMesh::surface_get_arrays(int p_surface) const {
ERR_FAIL_INDEX_V(p_surface, int(surfaces.size()), Array());
return RS::get_singleton()->mesh_surface_get_arrays(mesh, p_surface);
}
-Array ImmediateMesh::surface_get_blend_shape_arrays(int p_surface) const {
- return Array();
+TypedArray<Array> ImmediateMesh::surface_get_blend_shape_arrays(int p_surface) const {
+ return TypedArray<Array>();
}
Dictionary ImmediateMesh::surface_get_lods(int p_surface) const {
return Dictionary();
diff --git a/scene/resources/immediate_mesh.h b/scene/resources/immediate_mesh.h
index de10fdbfbe..0dad62f555 100644
--- a/scene/resources/immediate_mesh.h
+++ b/scene/resources/immediate_mesh.h
@@ -97,7 +97,7 @@ public:
virtual int surface_get_array_len(int p_idx) const override;
virtual int surface_get_array_index_len(int p_idx) const override;
virtual Array surface_get_arrays(int p_surface) const override;
- virtual Array surface_get_blend_shape_arrays(int p_surface) const override;
+ virtual TypedArray<Array> surface_get_blend_shape_arrays(int p_surface) const override;
virtual Dictionary surface_get_lods(int p_surface) const override;
virtual uint32_t surface_get_format(int p_idx) const override;
virtual PrimitiveType surface_get_primitive_type(int p_idx) const override;
diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp
index 293fdd6f05..3638d1862c 100644
--- a/scene/resources/importer_mesh.cpp
+++ b/scene/resources/importer_mesh.cpp
@@ -301,9 +301,9 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
}
}
- float normal_merge_threshold = Math::cos(Math::deg2rad(p_normal_merge_angle));
- float normal_pre_split_threshold = Math::cos(Math::deg2rad(MIN(180.0f, p_normal_split_angle * 2.0f)));
- float normal_split_threshold = Math::cos(Math::deg2rad(p_normal_split_angle));
+ float normal_merge_threshold = Math::cos(Math::deg_to_rad(p_normal_merge_angle));
+ float normal_pre_split_threshold = Math::cos(Math::deg_to_rad(MIN(180.0f, p_normal_split_angle * 2.0f)));
+ float normal_split_threshold = Math::cos(Math::deg_to_rad(p_normal_split_angle));
const Vector3 *normals_ptr = normals.ptr();
HashMap<Vector3, LocalVector<Pair<int, int>>> unique_vertices;
diff --git a/scene/resources/label_settings.h b/scene/resources/label_settings.h
index d2644a7484..062d499d50 100644
--- a/scene/resources/label_settings.h
+++ b/scene/resources/label_settings.h
@@ -39,17 +39,17 @@
class LabelSettings : public Resource {
GDCLASS(LabelSettings, Resource);
- real_t line_spacing = 0;
+ real_t line_spacing = 3;
Ref<Font> font;
int font_size = Font::DEFAULT_FONT_SIZE;
- Color font_color = Color(0.875, 0.875, 0.875);
+ Color font_color = Color(1, 1, 1);
int outline_size = 0;
Color outline_color = Color(1, 1, 1);
- int shadow_size = 0;
- Color shadow_color = Color(1, 1, 1);
+ int shadow_size = 1;
+ Color shadow_color = Color(0, 0, 0, 0);
Vector2 shadow_offset = Vector2(1, 1);
void _font_changed();
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index fa3f3476e8..32ddef1693 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -71,12 +71,12 @@ RID Material::get_rid() const {
return material;
}
-void Material::_validate_property(PropertyInfo &property) const {
- if (!_can_do_next_pass() && property.name == "next_pass") {
- property.usage = PROPERTY_USAGE_NONE;
+void Material::_validate_property(PropertyInfo &p_property) const {
+ if (!_can_do_next_pass() && p_property.name == "next_pass") {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (!_can_use_render_priority() && property.name == "render_priority") {
- property.usage = PROPERTY_USAGE_NONE;
+ if (!_can_use_render_priority() && p_property.name == "render_priority") {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
@@ -154,18 +154,18 @@ Material::~Material() {
bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) {
if (shader.is_valid()) {
- StringName pr = shader->remap_param(p_name);
+ StringName pr = shader->remap_uniform(p_name);
if (!pr) {
String n = p_name;
if (n.find("param/") == 0) { //backwards compatibility
pr = n.substr(6, n.length());
}
- if (n.find("shader_param/") == 0) { //backwards compatibility
- pr = n.replace_first("shader_param/", "");
+ if (n.find("shader_uniform/") == 0) { //backwards compatibility
+ pr = n.replace_first("shader_uniform/", "");
}
}
if (pr) {
- set_shader_param(pr, p_value);
+ set_shader_uniform(pr, p_value);
return true;
}
}
@@ -175,14 +175,14 @@ bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) {
bool ShaderMaterial::_get(const StringName &p_name, Variant &r_ret) const {
if (shader.is_valid()) {
- StringName pr = shader->remap_param(p_name);
+ StringName pr = shader->remap_uniform(p_name);
if (!pr) {
String n = p_name;
if (n.find("param/") == 0) { //backwards compatibility
pr = n.substr(6, n.length());
}
- if (n.find("shader_param/") == 0) { //backwards compatibility
- pr = n.replace_first("shader_param/", "");
+ if (n.find("shader_uniform/") == 0) { //backwards compatibility
+ pr = n.replace_first("shader_uniform/", "");
}
}
@@ -203,7 +203,7 @@ bool ShaderMaterial::_get(const StringName &p_name, Variant &r_ret) const {
void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
if (!shader.is_null()) {
List<PropertyInfo> list;
- shader->get_param_list(&list, true);
+ shader->get_shader_uniform_list(&list, true);
HashMap<String, HashMap<String, List<PropertyInfo>>> groups;
{
@@ -233,7 +233,7 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
if (!groups.has(last_group)) {
PropertyInfo info;
info.usage = PROPERTY_USAGE_GROUP;
- info.name = last_group;
+ info.name = last_group.capitalize();
List<PropertyInfo> none_subgroup;
none_subgroup.push_back(info);
@@ -247,7 +247,7 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
if (!groups[last_group].has(last_subgroup)) {
PropertyInfo info;
info.usage = PROPERTY_USAGE_SUBGROUP;
- info.name = last_subgroup;
+ info.name = last_subgroup.capitalize();
List<PropertyInfo> subgroup;
subgroup.push_back(info);
@@ -297,9 +297,9 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-bool ShaderMaterial::property_can_revert(const String &p_name) {
+bool ShaderMaterial::_property_can_revert(const StringName &p_name) const {
if (shader.is_valid()) {
- StringName pr = shader->remap_param(p_name);
+ StringName pr = shader->remap_uniform(p_name);
if (pr) {
Variant default_value = RenderingServer::get_singleton()->shader_get_param_default(shader->get_rid(), pr);
Variant current_value;
@@ -310,15 +310,15 @@ bool ShaderMaterial::property_can_revert(const String &p_name) {
return false;
}
-Variant ShaderMaterial::property_get_revert(const String &p_name) {
- Variant r_ret;
+bool ShaderMaterial::_property_get_revert(const StringName &p_name, Variant &r_property) const {
if (shader.is_valid()) {
- StringName pr = shader->remap_param(p_name);
+ StringName pr = shader->remap_uniform(p_name);
if (pr) {
- r_ret = RenderingServer::get_singleton()->shader_get_param_default(shader->get_rid(), pr);
+ r_property = RenderingServer::get_singleton()->shader_get_param_default(shader->get_rid(), pr);
+ return true;
}
}
- return r_ret;
+ return false;
}
void ShaderMaterial::set_shader(const Ref<Shader> &p_shader) {
@@ -349,7 +349,7 @@ Ref<Shader> ShaderMaterial::get_shader() const {
return shader;
}
-void ShaderMaterial::set_shader_param(const StringName &p_param, const Variant &p_value) {
+void ShaderMaterial::set_shader_uniform(const StringName &p_param, const Variant &p_value) {
if (p_value.get_type() == Variant::NIL) {
param_cache.erase(p_param);
RS::get_singleton()->material_set_param(_get_material(), p_param, Variant());
@@ -369,7 +369,7 @@ void ShaderMaterial::set_shader_param(const StringName &p_param, const Variant &
}
}
-Variant ShaderMaterial::get_shader_param(const StringName &p_param) const {
+Variant ShaderMaterial::get_shader_uniform(const StringName &p_param) const {
if (param_cache.has(p_param)) {
return param_cache[p_param];
} else {
@@ -384,22 +384,20 @@ void ShaderMaterial::_shader_changed() {
void ShaderMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_shader", "shader"), &ShaderMaterial::set_shader);
ClassDB::bind_method(D_METHOD("get_shader"), &ShaderMaterial::get_shader);
- ClassDB::bind_method(D_METHOD("set_shader_param", "param", "value"), &ShaderMaterial::set_shader_param);
- ClassDB::bind_method(D_METHOD("get_shader_param", "param"), &ShaderMaterial::get_shader_param);
- ClassDB::bind_method(D_METHOD("property_can_revert", "name"), &ShaderMaterial::property_can_revert);
- ClassDB::bind_method(D_METHOD("property_get_revert", "name"), &ShaderMaterial::property_get_revert);
+ ClassDB::bind_method(D_METHOD("set_shader_uniform", "param", "value"), &ShaderMaterial::set_shader_uniform);
+ ClassDB::bind_method(D_METHOD("get_shader_uniform", "param"), &ShaderMaterial::get_shader_uniform);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shader", PROPERTY_HINT_RESOURCE_TYPE, "Shader"), "set_shader", "get_shader");
}
void ShaderMaterial::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
String f = p_function.operator String();
- if ((f == "get_shader_param" || f == "set_shader_param") && p_idx == 0) {
+ if ((f == "get_shader_uniform" || f == "set_shader_uniform") && p_idx == 0) {
if (shader.is_valid()) {
List<PropertyInfo> pl;
- shader->get_param_list(&pl);
+ shader->get_shader_uniform_list(&pl);
for (const PropertyInfo &E : pl) {
- r_options->push_back(E.name.replace_first("shader_param/", "").quote());
+ r_options->push_back(E.name.replace_first("shader_uniform/", "").quote());
}
}
}
@@ -1067,7 +1065,8 @@ void BaseMaterial3D::_update_shader() {
code += " float num_layers = mix(float(heightmap_max_layers),float(heightmap_min_layers), abs(dot(vec3(0.0, 0.0, 1.0), view_dir)));\n";
code += " float layer_depth = 1.0 / num_layers;\n";
code += " float current_layer_depth = 0.0;\n";
- code += " vec2 P = view_dir.xy * heightmap_scale;\n";
+ // Multiply the heightmap scale by 0.01 to improve heightmap scale usability.
+ code += " vec2 P = view_dir.xy * heightmap_scale * 0.01;\n";
code += " vec2 delta = P / num_layers;\n";
code += " vec2 ofs = base_uv;\n";
if (flags[FLAG_INVERT_HEIGHTMAP]) {
@@ -1103,7 +1102,8 @@ void BaseMaterial3D::_update_shader() {
}
// Use offset limiting to improve the appearance of non-deep parallax.
// This reduces the impression of depth, but avoids visible warping in the distance.
- code += " vec2 ofs = base_uv - view_dir.xy * depth * heightmap_scale;\n";
+ // Multiply the heightmap scale by 0.01 to improve heightmap scale usability.
+ code += " vec2 ofs = base_uv - view_dir.xy * depth * heightmap_scale * 0.01;\n";
}
code += " base_uv=ofs;\n";
@@ -1276,38 +1276,21 @@ void BaseMaterial3D::_update_shader() {
if ((distance_fade == DISTANCE_FADE_OBJECT_DITHER || distance_fade == DISTANCE_FADE_PIXEL_DITHER)) {
if (!RenderingServer::get_singleton()->is_low_end()) {
code += " {\n";
+
if (distance_fade == DISTANCE_FADE_OBJECT_DITHER) {
code += " float fade_distance = abs((VIEW_MATRIX * MODEL_MATRIX[3]).z);\n";
} else {
- code += " float fade_distance=-VERTEX.z;\n";
+ code += " float fade_distance = -VERTEX.z;\n";
}
+ // Use interleaved gradient noise, which is fast but still looks good.
+ code += " const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f);";
+ code += " float fade = clamp(smoothstep(distance_fade_min, distance_fade_max, fade_distance), 0.0, 1.0);\n";
+ // Use a hard cap to prevent a few stray pixels from remaining when past the fade-out distance.
+ code += " if (fade < 0.001 || fade < fract(magic.z * fract(dot(FRAGCOORD.xy, magic.xy)))) {\n";
+ code += " discard;\n";
+ code += " }\n";
- code += " float fade=clamp(smoothstep(distance_fade_min,distance_fade_max,fade_distance),0.0,1.0);\n";
- code += " int x = int(FRAGCOORD.x) % 4;\n";
- code += " int y = int(FRAGCOORD.y) % 4;\n";
- code += " int index = x + y * 4;\n";
- code += " float limit = 0.0;\n\n";
- code += " if (x < 8) {\n";
- code += " if (index == 0) limit = 0.0625;\n";
- code += " if (index == 1) limit = 0.5625;\n";
- code += " if (index == 2) limit = 0.1875;\n";
- code += " if (index == 3) limit = 0.6875;\n";
- code += " if (index == 4) limit = 0.8125;\n";
- code += " if (index == 5) limit = 0.3125;\n";
- code += " if (index == 6) limit = 0.9375;\n";
- code += " if (index == 7) limit = 0.4375;\n";
- code += " if (index == 8) limit = 0.25;\n";
- code += " if (index == 9) limit = 0.75;\n";
- code += " if (index == 10) limit = 0.125;\n";
- code += " if (index == 11) limit = 0.625;\n";
- code += " if (index == 12) limit = 1.0;\n";
- code += " if (index == 13) limit = 0.5;\n";
- code += " if (index == 14) limit = 0.875;\n";
- code += " if (index == 15) limit = 0.375;\n";
- code += " }\n\n";
- code += " if (fade < limit)\n";
- code += " discard;\n";
code += " }\n\n";
}
@@ -1884,61 +1867,61 @@ void BaseMaterial3D::_validate_high_end(const String &text, PropertyInfo &proper
}
}
-void BaseMaterial3D::_validate_property(PropertyInfo &property) const {
- _validate_feature("normal", FEATURE_NORMAL_MAPPING, property);
- _validate_feature("emission", FEATURE_EMISSION, property);
- _validate_feature("rim", FEATURE_RIM, property);
- _validate_feature("clearcoat", FEATURE_CLEARCOAT, property);
- _validate_feature("anisotropy", FEATURE_ANISOTROPY, property);
- _validate_feature("ao", FEATURE_AMBIENT_OCCLUSION, property);
- _validate_feature("heightmap", FEATURE_HEIGHT_MAPPING, property);
- _validate_feature("subsurf_scatter", FEATURE_SUBSURFACE_SCATTERING, property);
- _validate_feature("backlight", FEATURE_BACKLIGHT, property);
- _validate_feature("refraction", FEATURE_REFRACTION, property);
- _validate_feature("detail", FEATURE_DETAIL, property);
+void BaseMaterial3D::_validate_property(PropertyInfo &p_property) const {
+ _validate_feature("normal", FEATURE_NORMAL_MAPPING, p_property);
+ _validate_feature("emission", FEATURE_EMISSION, p_property);
+ _validate_feature("rim", FEATURE_RIM, p_property);
+ _validate_feature("clearcoat", FEATURE_CLEARCOAT, p_property);
+ _validate_feature("anisotropy", FEATURE_ANISOTROPY, p_property);
+ _validate_feature("ao", FEATURE_AMBIENT_OCCLUSION, p_property);
+ _validate_feature("heightmap", FEATURE_HEIGHT_MAPPING, p_property);
+ _validate_feature("subsurf_scatter", FEATURE_SUBSURFACE_SCATTERING, p_property);
+ _validate_feature("backlight", FEATURE_BACKLIGHT, p_property);
+ _validate_feature("refraction", FEATURE_REFRACTION, p_property);
+ _validate_feature("detail", FEATURE_DETAIL, p_property);
- _validate_high_end("refraction", property);
- _validate_high_end("subsurf_scatter", property);
- _validate_high_end("heightmap", property);
+ _validate_high_end("refraction", p_property);
+ _validate_high_end("subsurf_scatter", p_property);
+ _validate_high_end("heightmap", p_property);
- if (property.name.begins_with("particles_anim_") && billboard_mode != BILLBOARD_PARTICLES) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("particles_anim_") && billboard_mode != BILLBOARD_PARTICLES) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "billboard_keep_scale" && billboard_mode == BILLBOARD_DISABLED) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == "billboard_keep_scale" && billboard_mode == BILLBOARD_DISABLED) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "grow_amount" && !grow_enabled) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == "grow_amount" && !grow_enabled) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "point_size" && !flags[FLAG_USE_POINT_SIZE]) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == "point_size" && !flags[FLAG_USE_POINT_SIZE]) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "proximity_fade_distance" && !proximity_fade_enabled) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == "proximity_fade_distance" && !proximity_fade_enabled) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "msdf_pixel_range" && !flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == "msdf_pixel_range" && !flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if (property.name == "msdf_outline_size" && !flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == "msdf_outline_size" && !flags[FLAG_ALBEDO_TEXTURE_MSDF]) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if ((property.name == "distance_fade_max_distance" || property.name == "distance_fade_min_distance") && distance_fade == DISTANCE_FADE_DISABLED) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if ((p_property.name == "distance_fade_max_distance" || p_property.name == "distance_fade_min_distance") && distance_fade == DISTANCE_FADE_DISABLED) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if ((property.name == "uv1_triplanar_sharpness" || property.name == "uv1_world_triplanar") && !flags[FLAG_UV1_USE_TRIPLANAR]) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if ((p_property.name == "uv1_triplanar_sharpness" || p_property.name == "uv1_world_triplanar") && !flags[FLAG_UV1_USE_TRIPLANAR]) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
- if ((property.name == "uv2_triplanar_sharpness" || property.name == "uv2_world_triplanar") && !flags[FLAG_UV2_USE_TRIPLANAR]) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if ((p_property.name == "uv2_triplanar_sharpness" || p_property.name == "uv2_world_triplanar") && !flags[FLAG_UV2_USE_TRIPLANAR]) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
// you can only enable anti-aliasing (in materials) on alpha scissor and alpha hash
@@ -1947,96 +1930,96 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const {
const bool alpha_aa_enabled = (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) && can_select_aa;
// alpha scissor slider isn't needed when alpha antialiasing is enabled
- if (property.name == "alpha_scissor_threshold" && transparency != TRANSPARENCY_ALPHA_SCISSOR) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "alpha_scissor_threshold" && transparency != TRANSPARENCY_ALPHA_SCISSOR) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
// alpha hash scale slider is only needed if transparency is alpha hash
- if (property.name == "alpha_hash_scale" && transparency != TRANSPARENCY_ALPHA_HASH) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "alpha_hash_scale" && transparency != TRANSPARENCY_ALPHA_HASH) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "alpha_antialiasing_mode" && !can_select_aa) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "alpha_antialiasing_mode" && !can_select_aa) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
// we can't choose an antialiasing mode if alpha isn't possible
- if (property.name == "alpha_antialiasing_edge" && !alpha_aa_enabled) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "alpha_antialiasing_edge" && !alpha_aa_enabled) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "blend_mode" && alpha_aa_enabled) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "blend_mode" && alpha_aa_enabled) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if ((property.name == "heightmap_min_layers" || property.name == "heightmap_max_layers") && !deep_parallax) {
- property.usage = PROPERTY_USAGE_NONE;
+ if ((p_property.name == "heightmap_min_layers" || p_property.name == "heightmap_max_layers") && !deep_parallax) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (flags[FLAG_SUBSURFACE_MODE_SKIN] && (property.name == "subsurf_scatter_transmittance_color" || property.name == "subsurf_scatter_transmittance_texture")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (flags[FLAG_SUBSURFACE_MODE_SKIN] && (p_property.name == "subsurf_scatter_transmittance_color" || p_property.name == "subsurf_scatter_transmittance_texture")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
if (orm) {
- if (property.name == "shading_mode") {
+ if (p_property.name == "shading_mode") {
// Vertex not supported in ORM mode, since no individual roughness.
- property.hint_string = "Unshaded,Per-Pixel";
+ p_property.hint_string = "Unshaded,Per-Pixel";
}
- if (property.name.begins_with("roughness") || property.name.begins_with("metallic") || property.name.begins_with("ao_texture")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("roughness") || p_property.name.begins_with("metallic") || p_property.name.begins_with("ao_texture")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
} else {
- if (property.name == "orm_texture") {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "orm_texture") {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
if (shading_mode != SHADING_MODE_PER_PIXEL) {
if (shading_mode != SHADING_MODE_PER_VERTEX) {
//these may still work per vertex
- if (property.name.begins_with("ao")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("ao")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("emission")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("emission")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("metallic")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("metallic")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("rim")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("rim")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("roughness")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("roughness")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("subsurf_scatter")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("subsurf_scatter")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
//these definitely only need per pixel
- if (property.name.begins_with("anisotropy")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("anisotropy")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("clearcoat")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("clearcoat")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("normal")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("normal")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("backlight")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("backlight")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("transmittance")) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("transmittance")) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
}
@@ -2069,8 +2052,9 @@ Vector3 BaseMaterial3D::get_uv1_offset() const {
}
void BaseMaterial3D::set_uv1_triplanar_blend_sharpness(float p_sharpness) {
- uv1_triplanar_sharpness = p_sharpness;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->uv1_blend_sharpness, p_sharpness);
+ // Negative values or values higher than 150 can result in NaNs, leading to broken rendering.
+ uv1_triplanar_sharpness = CLAMP(p_sharpness, 0.0, 150.0);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->uv1_blend_sharpness, uv1_triplanar_sharpness);
}
float BaseMaterial3D::get_uv1_triplanar_blend_sharpness() const {
@@ -2096,8 +2080,9 @@ Vector3 BaseMaterial3D::get_uv2_offset() const {
}
void BaseMaterial3D::set_uv2_triplanar_blend_sharpness(float p_sharpness) {
- uv2_triplanar_sharpness = p_sharpness;
- RS::get_singleton()->material_set_param(_get_material(), shader_names->uv2_blend_sharpness, p_sharpness);
+ // Negative values or values higher than 150 can result in NaNs, leading to broken rendering.
+ uv2_triplanar_sharpness = CLAMP(p_sharpness, 0.0, 150.0);
+ RS::get_singleton()->material_set_param(_get_material(), shader_names->uv2_blend_sharpness, uv2_triplanar_sharpness);
}
float BaseMaterial3D::get_uv2_triplanar_blend_sharpness() const {
@@ -2654,7 +2639,7 @@ void BaseMaterial3D::_bind_methods() {
ADD_GROUP("Transparency", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "transparency", PROPERTY_HINT_ENUM, "Disabled,Alpha,Alpha Scissor,Alpha Hash,Depth Pre-Pass"), "set_transparency", "get_transparency");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_scissor_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_alpha_scissor_threshold", "get_alpha_scissor_threshold");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_scissor_threshold", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_alpha_scissor_threshold", "get_alpha_scissor_threshold");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_hash_scale", PROPERTY_HINT_RANGE, "0,2,0.01"), "set_alpha_hash_scale", "get_alpha_hash_scale");
ADD_PROPERTY(PropertyInfo(Variant::INT, "alpha_antialiasing_mode", PROPERTY_HINT_ENUM, "Disabled,Alpha Edge Blend,Alpha Edge Clip"), "set_alpha_antialiasing", "get_alpha_antialiasing");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "alpha_antialiasing_edge", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_alpha_antialiasing_edge", "get_alpha_antialiasing_edge");
@@ -2965,7 +2950,7 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
set_clearcoat(1);
set_clearcoat_roughness(0.5);
set_anisotropy(0);
- set_heightmap_scale(0.05);
+ set_heightmap_scale(5.0);
set_subsurface_scattering_strength(0);
set_backlight(Color(0, 0, 0));
set_transmittance_color(Color(1, 1, 1, 1));
@@ -2986,7 +2971,9 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
set_transparency(TRANSPARENCY_DISABLED);
set_alpha_antialiasing(ALPHA_ANTIALIASING_OFF);
- set_alpha_scissor_threshold(0.05);
+ // Alpha scissor threshold of 0.5 matches the glTF specification and Label3D default.
+ // <https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#_material_alphacutoff>
+ set_alpha_scissor_threshold(0.5);
set_alpha_hash_scale(1.0);
set_alpha_antialiasing_edge(0.3);
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 8c04817c6b..c6be1b8766 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -54,7 +54,7 @@ protected:
virtual bool _can_do_next_pass() const;
virtual bool _can_use_render_priority() const;
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
GDVIRTUAL0RC(RID, _get_shader_rid)
GDVIRTUAL0RC(Shader::Mode, _get_shader_mode)
@@ -99,8 +99,8 @@ protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
- bool property_can_revert(const String &p_name);
- Variant property_get_revert(const String &p_name);
+ bool _property_can_revert(const StringName &p_name) const;
+ bool _property_get_revert(const StringName &p_name, Variant &r_property) const;
static void _bind_methods();
@@ -115,8 +115,8 @@ public:
void set_shader(const Ref<Shader> &p_shader);
Ref<Shader> get_shader() const;
- void set_shader_param(const StringName &p_param, const Variant &p_value);
- Variant get_shader_param(const StringName &p_param) const;
+ void set_shader_uniform(const StringName &p_param, const Variant &p_value);
+ Variant get_shader_uniform(const StringName &p_param) const;
virtual Shader::Mode get_shader_mode() const override;
@@ -553,7 +553,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
virtual bool _can_do_next_pass() const override { return true; }
virtual bool _can_use_render_priority() const override { return true; }
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index ec9db89794..7f318af899 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -32,11 +32,10 @@
#include "core/math/convex_hull.h"
#include "core/templates/pair.h"
+#include "scene/resources/surface_tool.h"
+
#include "scene/resources/concave_polygon_shape_3d.h"
#include "scene/resources/convex_polygon_shape_3d.h"
-#include "surface_tool.h"
-
-#include <stdlib.h>
Mesh::ConvexDecompositionFunc Mesh::convex_decomposition_function = nullptr;
@@ -72,13 +71,13 @@ Array Mesh::surface_get_arrays(int p_surface) const {
return Array();
}
-Array Mesh::surface_get_blend_shape_arrays(int p_surface) const {
- Array ret;
+TypedArray<Array> Mesh::surface_get_blend_shape_arrays(int p_surface) const {
+ TypedArray<Array> ret;
if (GDVIRTUAL_REQUIRED_CALL(_surface_get_blend_shape_arrays, p_surface, ret)) {
return ret;
}
- return Array();
+ return TypedArray<Array>();
}
Dictionary Mesh::surface_get_lods(int p_surface) const {
@@ -201,7 +200,9 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
continue;
}
int len = (surface_get_format(i) & ARRAY_FORMAT_INDEX) ? surface_get_array_index_len(i) : surface_get_array_len(i);
- if ((primitive == PRIMITIVE_TRIANGLES && (len == 0 || (len % 3) != 0)) || (primitive == PRIMITIVE_TRIANGLE_STRIP && len < 3)) {
+ if ((primitive == PRIMITIVE_TRIANGLES && (len == 0 || (len % 3) != 0)) ||
+ (primitive == PRIMITIVE_TRIANGLE_STRIP && len < 3) ||
+ (surface_get_format(i) & ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY)) {
// Error was already shown, just skip (including zero).
continue;
}
@@ -211,6 +212,7 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
int vc = surface_get_array_len(i);
Vector<Vector3> vertices = a[ARRAY_VERTEX];
+ ERR_FAIL_COND_V(vertices.is_empty(), Ref<TriangleMesh>());
const Vector3 *vr = vertices.ptr();
int32_t from_index = widx / 3;
@@ -863,27 +865,6 @@ static Mesh::PrimitiveType _old_primitives[7] = {
};
#endif // DISABLE_DEPRECATED
-// Convert Octahedron-mapped normalized vector back to Cartesian
-// Assumes normalized format (elements of v within range [-1, 1])
-Vector3 _oct_to_norm(const Vector2 v) {
- Vector3 res(v.x, v.y, 1 - (Math::absf(v.x) + Math::absf(v.y)));
- float t = MAX(-res.z, 0.0f);
- res.x += t * -SIGN(res.x);
- res.y += t * -SIGN(res.y);
- return res.normalized();
-}
-
-// Convert Octahedron-mapped normalized tangent vector back to Cartesian
-// out_sign provides the direction for the original cartesian tangent
-// Assumes normalized format (elements of v within range [-1, 1])
-Vector3 _oct_to_tangent(const Vector2 v, float *out_sign) {
- Vector2 v_decompressed = v;
- v_decompressed.y = Math::absf(v_decompressed.y) * 2 - 1;
- Vector3 res = _oct_to_norm(v_decompressed);
- *out_sign = SIGN(v[1]);
- return res;
-}
-
void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_format, uint32_t p_new_format, uint32_t p_elements, Vector<uint8_t> &vertex_data, Vector<uint8_t> &attribute_data, Vector<uint8_t> &skin_data) {
uint32_t dst_vertex_stride;
uint32_t dst_attribute_stride;
@@ -954,127 +935,93 @@ void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_forma
if ((p_old_format & OLD_ARRAY_COMPRESS_NORMAL) && (p_old_format & OLD_ARRAY_FORMAT_TANGENT) && (p_old_format & OLD_ARRAY_COMPRESS_TANGENT)) {
for (uint32_t i = 0; i < p_elements; i++) {
const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
- const Vector2 src_vec(src[0] / 127.0f, src[1] / 127.0f);
-
- const Vector3 res = _oct_to_norm(src_vec) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
- *dst = 0;
- *dst |= CLAMP(int(res.x * 1023.0f), 0, 1023);
- *dst |= CLAMP(int(res.y * 1023.0f), 0, 1023) << 10;
- *dst |= CLAMP(int(res.z * 1023.0f), 0, 1023) << 20;
+ int16_t *dst = (int16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+
+ dst[0] = (int16_t)CLAMP(src[0] / 127.0f * 32767, -32768, 32767);
+ dst[1] = (int16_t)CLAMP(src[1] / 127.0f * 32767, -32768, 32767);
}
- src_offset += sizeof(int8_t) * 2;
+ src_offset += sizeof(int16_t) * 2;
} else {
for (uint32_t i = 0; i < p_elements; i++) {
const int16_t *src = (const int16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
- const Vector2 src_vec(src[0] / 32767.0f, src[1] / 32767.0f);
-
- const Vector3 res = _oct_to_norm(src_vec) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
- *dst = 0;
- *dst |= CLAMP(int(res.x * 1023.0f), 0, 1023);
- *dst |= CLAMP(int(res.y * 1023.0f), 0, 1023) << 10;
- *dst |= CLAMP(int(res.z * 1023.0f), 0, 1023) << 20;
+ int16_t *dst = (int16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+
+ dst[0] = src[0];
+ dst[1] = src[1];
}
src_offset += sizeof(int16_t) * 2;
}
} else { // No Octahedral compression
if (p_old_format & OLD_ARRAY_COMPRESS_NORMAL) {
- const float multiplier = 1.f / 127.f * 1023.0f;
-
for (uint32_t i = 0; i < p_elements; i++) {
const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+ const Vector3 original_normal(src[0], src[1], src[2]);
+ Vector2 res = original_normal.octahedron_encode();
- *dst = 0;
- *dst |= CLAMP(int(src[0] * multiplier), 0, 1023);
- *dst |= CLAMP(int(src[1] * multiplier), 0, 1023) << 10;
- *dst |= CLAMP(int(src[2] * multiplier), 0, 1023) << 20;
+ uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+ dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
}
- src_offset += sizeof(uint32_t);
+ src_offset += sizeof(uint16_t) * 2;
} else {
for (uint32_t i = 0; i < p_elements; i++) {
const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+ const Vector3 original_normal(src[0], src[1], src[2]);
+ Vector2 res = original_normal.octahedron_encode();
- *dst = 0;
- *dst |= CLAMP(int(src[0] * 1023.0), 0, 1023);
- *dst |= CLAMP(int(src[1] * 1023.0), 0, 1023) << 10;
- *dst |= CLAMP(int(src[2] * 1023.0), 0, 1023) << 20;
+ uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+ dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
}
- src_offset += sizeof(float) * 3;
+ src_offset += sizeof(uint16_t) * 2;
}
}
} break;
case OLD_ARRAY_TANGENT: {
if (p_old_format & OLD_ARRAY_FLAG_USE_OCTAHEDRAL_COMPRESSION) {
- if (p_old_format & OLD_ARRAY_COMPRESS_TANGENT) { // int8
+ if (p_old_format & OLD_ARRAY_COMPRESS_TANGENT) { // int8 SNORM -> uint16 UNORM
for (uint32_t i = 0; i < p_elements; i++) {
const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
- const Vector2 src_vec(src[0] / 127.0f, src[1] / 127.0f);
- float out_sign;
- const Vector3 res = _oct_to_tangent(src_vec, &out_sign) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
-
- *dst = 0;
- *dst |= CLAMP(int(res.x * 1023.0), 0, 1023);
- *dst |= CLAMP(int(res.y * 1023.0), 0, 1023) << 10;
- *dst |= CLAMP(int(res.z * 1023.0), 0, 1023) << 20;
- if (out_sign > 0) {
- *dst |= 3 << 30;
- }
+ uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
+
+ dst[0] = (uint16_t)CLAMP((src[0] / 127.0f * .5f + .5f) * 65535, 0, 65535);
+ dst[1] = (uint16_t)CLAMP((src[1] / 127.0f * .5f + .5f) * 65535, 0, 65535);
}
- src_offset += sizeof(int8_t) * 2;
- } else { // int16
+ src_offset += sizeof(uint16_t) * 2;
+ } else { // int16 SNORM -> uint16 UNORM
for (uint32_t i = 0; i < p_elements; i++) {
const int16_t *src = (const int16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
- const Vector2 src_vec(src[0] / 32767.0f, src[1] / 32767.0f);
- float out_sign;
- Vector3 res = _oct_to_tangent(src_vec, &out_sign) * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
-
- *dst = 0;
- *dst |= CLAMP(int(res.x * 1023.0), 0, 1023);
- *dst |= CLAMP(int(res.y * 1023.0), 0, 1023) << 10;
- *dst |= CLAMP(int(res.z * 1023.0), 0, 1023) << 20;
- if (out_sign > 0) {
- *dst |= 3 << 30;
- }
+ uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
+
+ dst[0] = (uint16_t)CLAMP((src[0] / 32767.0f * .5f + .5f) * 65535, 0, 65535);
+ dst[1] = (uint16_t)CLAMP((src[1] / 32767.0f * .5f + .5f) * 65535, 0, 65535);
}
- src_offset += sizeof(int16_t) * 2;
+ src_offset += sizeof(uint16_t) * 2;
}
} else { // No Octahedral compression
if (p_old_format & OLD_ARRAY_COMPRESS_TANGENT) {
- const float multiplier = 1.f / 127.f * 1023.0f;
-
for (uint32_t i = 0; i < p_elements; i++) {
const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
-
- *dst = 0;
- *dst |= CLAMP(int(src[0] * multiplier), 0, 1023);
- *dst |= CLAMP(int(src[1] * multiplier), 0, 1023) << 10;
- *dst |= CLAMP(int(src[2] * multiplier), 0, 1023) << 20;
- if (src[3] > 0) {
- *dst |= 3 << 30;
- }
+ const Vector3 original_tangent(src[0], src[1], src[2]);
+ Vector2 res = original_tangent.octahedron_tangent_encode(src[3]);
+
+ uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+ dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
}
- src_offset += sizeof(uint32_t);
+ src_offset += sizeof(uint16_t) * 2;
} else {
for (uint32_t i = 0; i < p_elements; i++) {
const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset];
- uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]];
-
- *dst = 0;
- *dst |= CLAMP(int(src[0] * 1023.0), 0, 1023);
- *dst |= CLAMP(int(src[1] * 1023.0), 0, 1023) << 10;
- *dst |= CLAMP(int(src[2] * 1023.0), 0, 1023) << 20;
- if (src[3] > 0) {
- *dst |= 3 << 30;
- }
+ const Vector3 original_tangent(src[0], src[1], src[2]);
+ Vector2 res = original_tangent.octahedron_tangent_encode(src[3]);
+
+ uint16_t *dst = (uint16_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]];
+ dst[0] = (uint16_t)CLAMP(res.x * 65535, 0, 65535);
+ dst[1] = (uint16_t)CLAMP(res.y * 65535, 0, 65535);
}
- src_offset += sizeof(float) * 4;
+ src_offset += sizeof(uint16_t) * 2;
}
}
} break;
@@ -1693,8 +1640,8 @@ Array ArrayMesh::surface_get_arrays(int p_surface) const {
return RenderingServer::get_singleton()->mesh_surface_get_arrays(mesh, p_surface);
}
-Array ArrayMesh::surface_get_blend_shape_arrays(int p_surface) const {
- ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array());
+TypedArray<Array> ArrayMesh::surface_get_blend_shape_arrays(int p_surface) const {
+ ERR_FAIL_INDEX_V(p_surface, surfaces.size(), TypedArray<Array>());
return RenderingServer::get_singleton()->mesh_surface_get_blend_shape_arrays(mesh, p_surface);
}
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index 142373ce7f..fd3c2c4fa4 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -63,7 +63,7 @@ protected:
GDVIRTUAL1RC(int, _surface_get_array_len, int)
GDVIRTUAL1RC(int, _surface_get_array_index_len, int)
GDVIRTUAL1RC(Array, _surface_get_arrays, int)
- GDVIRTUAL1RC(Array, _surface_get_blend_shape_arrays, int)
+ GDVIRTUAL1RC(TypedArray<Array>, _surface_get_blend_shape_arrays, int)
GDVIRTUAL1RC(Dictionary, _surface_get_lods, int)
GDVIRTUAL1RC(uint32_t, _surface_get_format, int)
GDVIRTUAL1RC(uint32_t, _surface_get_primitive_type, int)
@@ -144,13 +144,14 @@ public:
ARRAY_FLAG_USE_DYNAMIC_UPDATE = RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE,
ARRAY_FLAG_USE_8_BONE_WEIGHTS = RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS,
+ ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY = RS::ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY,
};
virtual int get_surface_count() const;
virtual int surface_get_array_len(int p_idx) const;
virtual int surface_get_array_index_len(int p_idx) const;
virtual Array surface_get_arrays(int p_surface) const;
- virtual Array surface_get_blend_shape_arrays(int p_surface) const;
+ virtual TypedArray<Array> surface_get_blend_shape_arrays(int p_surface) const;
virtual Dictionary surface_get_lods(int p_surface) const;
virtual uint32_t surface_get_format(int p_idx) const;
virtual PrimitiveType surface_get_primitive_type(int p_idx) const;
@@ -168,9 +169,6 @@ public:
void generate_debug_mesh_lines(Vector<Vector3> &r_lines);
void generate_debug_mesh_indices(Vector<Vector3> &r_points);
- Ref<Shape3D> create_trimesh_shape() const;
- Ref<Shape3D> create_convex_shape(bool p_clean = true, bool p_simplify = false) const;
-
Ref<Mesh> create_outline(float p_margin) const;
void set_lightmap_size_hint(const Size2i &p_size);
@@ -213,6 +211,8 @@ public:
static ConvexDecompositionFunc convex_decomposition_function;
Vector<Ref<Shape3D>> convex_decompose(const ConvexDecompositionSettings &p_settings) const;
+ Ref<Shape3D> create_convex_shape(bool p_clean = true, bool p_simplify = false) const;
+ Ref<Shape3D> create_trimesh_shape() const;
virtual int get_builtin_bind_pose_count() const;
virtual Transform3D get_builtin_bind_pose(int p_index) const;
@@ -270,7 +270,7 @@ public:
void add_surface(uint32_t p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, const Vector<uint8_t> &p_attribute_array, const Vector<uint8_t> &p_skin_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<uint8_t> &p_blend_shape_data = Vector<uint8_t>(), const Vector<AABB> &p_bone_aabbs = Vector<AABB>(), const Vector<RS::SurfaceData::LOD> &p_lods = Vector<RS::SurfaceData::LOD>());
Array surface_get_arrays(int p_surface) const override;
- Array surface_get_blend_shape_arrays(int p_surface) const override;
+ TypedArray<Array> surface_get_blend_shape_arrays(int p_surface) const override;
Dictionary surface_get_lods(int p_surface) const override;
void add_blend_shape(const StringName &p_name);
@@ -345,7 +345,7 @@ public:
virtual int surface_get_array_len(int p_idx) const override { return 0; }
virtual int surface_get_array_index_len(int p_idx) const override { return 0; }
virtual Array surface_get_arrays(int p_surface) const override { return Array(); }
- virtual Array surface_get_blend_shape_arrays(int p_surface) const override { return Array(); }
+ virtual TypedArray<Array> surface_get_blend_shape_arrays(int p_surface) const override { return TypedArray<Array>(); }
virtual Dictionary surface_get_lods(int p_surface) const override { return Dictionary(); }
virtual uint32_t surface_get_format(int p_idx) const override { return 0; }
virtual PrimitiveType surface_get_primitive_type(int p_idx) const override { return PRIMITIVE_TRIANGLES; }
diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h
index 4105bd6960..79acb41c4e 100644
--- a/scene/resources/mesh_library.h
+++ b/scene/resources/mesh_library.h
@@ -33,8 +33,8 @@
#include "core/io/resource.h"
#include "core/templates/rb_map.h"
-#include "mesh.h"
#include "scene/3d/navigation_region_3d.h"
+#include "scene/resources/mesh.h"
#include "shape_3d.h"
class MeshLibrary : public Resource {
diff --git a/scene/resources/multimesh.cpp b/scene/resources/multimesh.cpp
index e5fc61ade5..ff4a7a4560 100644
--- a/scene/resources/multimesh.cpp
+++ b/scene/resources/multimesh.cpp
@@ -340,13 +340,13 @@ void MultiMesh::_bind_methods() {
#ifndef DISABLE_DEPRECATED
// Kept for compatibility from 3.x to 4.0.
- ClassDB::bind_method(D_METHOD("_set_transform_array"), &MultiMesh::_set_transform_array);
+ ClassDB::bind_method(D_METHOD("_set_transform_array", "array"), &MultiMesh::_set_transform_array);
ClassDB::bind_method(D_METHOD("_get_transform_array"), &MultiMesh::_get_transform_array);
- ClassDB::bind_method(D_METHOD("_set_transform_2d_array"), &MultiMesh::_set_transform_2d_array);
+ ClassDB::bind_method(D_METHOD("_set_transform_2d_array", "array"), &MultiMesh::_set_transform_2d_array);
ClassDB::bind_method(D_METHOD("_get_transform_2d_array"), &MultiMesh::_get_transform_2d_array);
- ClassDB::bind_method(D_METHOD("_set_color_array"), &MultiMesh::_set_color_array);
+ ClassDB::bind_method(D_METHOD("_set_color_array", "array"), &MultiMesh::_set_color_array);
ClassDB::bind_method(D_METHOD("_get_color_array"), &MultiMesh::_get_color_array);
- ClassDB::bind_method(D_METHOD("_set_custom_data_array"), &MultiMesh::_set_custom_data_array);
+ ClassDB::bind_method(D_METHOD("_set_custom_data_array", "array"), &MultiMesh::_set_custom_data_array);
ClassDB::bind_method(D_METHOD("_get_custom_data_array"), &MultiMesh::_get_custom_data_array);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "transform_array", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "_set_transform_array", "_get_transform_array");
diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp
index ac5493efdc..6c9c8ffdba 100644
--- a/scene/resources/navigation_mesh.cpp
+++ b/scene/resources/navigation_mesh.cpp
@@ -614,8 +614,10 @@ void NavigationMesh::_bind_methods() {
ADD_GROUP("Geometry", "geometry_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_parsed_geometry_type", PROPERTY_HINT_ENUM, "Mesh Instances,Static Colliders,Both"), "set_parsed_geometry_type", "get_parsed_geometry_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+ ADD_PROPERTY_DEFAULT("geometry_collision_mask", 0xFFFFFFFF);
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry_source_geometry_mode", PROPERTY_HINT_ENUM, "NavMesh Children, Group With Children, Group Explicit"), "set_source_geometry_mode", "get_source_geometry_mode");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "geometry_source_group_name"), "set_source_group_name", "get_source_group_name");
+ ADD_PROPERTY_DEFAULT("geometry_source_group_name", StringName("navmesh"));
ADD_GROUP("Cells", "cell_");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_size", PROPERTY_HINT_RANGE, "0.01,500.0,0.01,or_greater,suffix:m"), "set_cell_size", "get_cell_size");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_height", PROPERTY_HINT_RANGE, "0.01,500.0,0.01,or_greater,suffix:m"), "set_cell_height", "get_cell_height");
@@ -658,17 +660,17 @@ void NavigationMesh::_bind_methods() {
BIND_ENUM_CONSTANT(SOURCE_GEOMETRY_MAX);
}
-void NavigationMesh::_validate_property(PropertyInfo &property) const {
- if (property.name == "geometry/collision_mask") {
+void NavigationMesh::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "geometry_collision_mask") {
if (parsed_geometry_type == PARSED_GEOMETRY_MESH_INSTANCES) {
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
return;
}
}
- if (property.name == "geometry/source_group_name") {
+ if (p_property.name == "geometry_source_group_name") {
if (source_geometry_mode == SOURCE_GEOMETRY_NAVMESH_CHILDREN) {
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
return;
}
}
diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h
index 79d8962d24..c66025dc6d 100644
--- a/scene/resources/navigation_mesh.h
+++ b/scene/resources/navigation_mesh.h
@@ -33,8 +33,6 @@
#include "scene/resources/mesh.h"
-class Mesh;
-
class NavigationMesh : public Resource {
GDCLASS(NavigationMesh, Resource);
@@ -60,7 +58,7 @@ class NavigationMesh : public Resource {
protected:
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
#ifndef DISABLE_DEPRECATED
bool _set(const StringName &p_name, const Variant &p_value);
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 0137c8cd2a..e0bedad595 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -279,25 +279,36 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
Ref<Resource> res = value;
if (res.is_valid()) {
if (res->is_local_to_scene()) {
- HashMap<Ref<Resource>, Ref<Resource>>::Iterator E = resources_local_to_scene.find(res);
-
- if (E) {
- value = E->value;
+ // In a situation where a local-to-scene resource is used in a child node of a non-editable instance,
+ // we need to avoid the parent scene from overriding the resource potentially also used in the root
+ // of the instantiated scene. That would to the instance having two different instances of the resource.
+ // Since at this point it's too late to propagate the resource instance in the parent scene to all the relevant
+ // nodes in the instance (and that would require very complex bookkepping), what we do instead is
+ // tampering the resource object already there with the values from the node in the parent scene and
+ // then tell this node to reference that resource.
+ if (n.instance >= 0) {
+ Ref<Resource> node_res = node->get(snames[nprops[j].name]);
+ if (node_res.is_valid()) {
+ node_res->copy_from(res);
+ node_res->configure_for_local_scene(node, resources_local_to_scene);
+ value = node_res;
+ }
} else {
+ HashMap<Ref<Resource>, Ref<Resource>>::Iterator E = resources_local_to_scene.find(res);
Node *base = i == 0 ? node : ret_nodes[0];
-
- if (p_edit_state == GEN_EDIT_STATE_MAIN || p_edit_state == GEN_EDIT_STATE_MAIN_INHERITED) {
- //for the main scene, use the resource as is
- res->configure_for_local_scene(base, resources_local_to_scene);
- resources_local_to_scene[res] = res;
-
+ if (E) {
+ value = E->value;
} else {
- //for instances, a copy must be made
- Node *base2 = i == 0 ? node : ret_nodes[0];
- Ref<Resource> local_dupe = res->duplicate_for_local_scene(base2, resources_local_to_scene);
- resources_local_to_scene[res] = local_dupe;
- res = local_dupe;
- value = local_dupe;
+ if (p_edit_state == GEN_EDIT_STATE_MAIN) {
+ //for the main scene, use the resource as is
+ res->configure_for_local_scene(base, resources_local_to_scene);
+ resources_local_to_scene[res] = res;
+ } else {
+ //for instances, a copy must be made
+ Ref<Resource> local_dupe = res->duplicate_for_local_scene(base, resources_local_to_scene);
+ resources_local_to_scene[res] = local_dupe;
+ value = local_dupe;
+ }
}
}
//must make a copy, because this res is local to scene
@@ -398,7 +409,9 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
}
for (KeyValue<Ref<Resource>, Ref<Resource>> &E : resources_local_to_scene) {
- E.value->setup_local_to_scene();
+ if (E.value->get_local_scene() == ret_nodes[0]) {
+ E.value->setup_local_to_scene();
+ }
}
//do connections
@@ -1779,7 +1792,7 @@ void PackedScene::_bind_methods() {
ClassDB::bind_method(D_METHOD("pack", "path"), &PackedScene::pack);
ClassDB::bind_method(D_METHOD("instantiate", "edit_state"), &PackedScene::instantiate, DEFVAL(GEN_EDIT_STATE_DISABLED));
ClassDB::bind_method(D_METHOD("can_instantiate"), &PackedScene::can_instantiate);
- ClassDB::bind_method(D_METHOD("_set_bundled_scene"), &PackedScene::_set_bundled_scene);
+ ClassDB::bind_method(D_METHOD("_set_bundled_scene", "scene"), &PackedScene::_set_bundled_scene);
ClassDB::bind_method(D_METHOD("_get_bundled_scene"), &PackedScene::_get_bundled_scene);
ClassDB::bind_method(D_METHOD("get_state"), &PackedScene::get_state);
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particle_process_material.cpp
index 7a49b9b515..ed19101de4 100644
--- a/scene/resources/particles_material.cpp
+++ b/scene/resources/particle_process_material.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* particles_material.cpp */
+/* particle_process_material.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,17 +28,17 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "particles_material.h"
+#include "particle_process_material.h"
#include "core/version.h"
-Mutex ParticlesMaterial::material_mutex;
-SelfList<ParticlesMaterial>::List *ParticlesMaterial::dirty_materials = nullptr;
-HashMap<ParticlesMaterial::MaterialKey, ParticlesMaterial::ShaderData, ParticlesMaterial::MaterialKey> ParticlesMaterial::shader_map;
-ParticlesMaterial::ShaderNames *ParticlesMaterial::shader_names = nullptr;
+Mutex ParticleProcessMaterial::material_mutex;
+SelfList<ParticleProcessMaterial>::List *ParticleProcessMaterial::dirty_materials = nullptr;
+HashMap<ParticleProcessMaterial::MaterialKey, ParticleProcessMaterial::ShaderData, ParticleProcessMaterial::MaterialKey> ParticleProcessMaterial::shader_map;
+ParticleProcessMaterial::ShaderNames *ParticleProcessMaterial::shader_names = nullptr;
-void ParticlesMaterial::init_shaders() {
- dirty_materials = memnew(SelfList<ParticlesMaterial>::List);
+void ParticleProcessMaterial::init_shaders() {
+ dirty_materials = memnew(SelfList<ParticleProcessMaterial>::List);
shader_names = memnew(ShaderNames);
@@ -98,6 +98,17 @@ void ParticlesMaterial::init_shaders() {
shader_names->emission_ring_radius = "emission_ring_radius";
shader_names->emission_ring_inner_radius = "emission_ring_inner_radius";
+ shader_names->turbulence_enabled = "turbulence_enabled";
+ shader_names->turbulence_noise_strength = "turbulence_noise_strength";
+ shader_names->turbulence_noise_scale = "turbulence_noise_scale";
+ shader_names->turbulence_noise_speed = "turbulence_noise_speed";
+ shader_names->turbulence_noise_speed_random = "turbulence_noise_speed_random";
+ shader_names->turbulence_influence_over_life = "turbulence_influence_over_life";
+ shader_names->turbulence_influence_min = "turbulence_influence_min";
+ shader_names->turbulence_influence_max = "turbulence_influence_max";
+ shader_names->turbulence_initial_displacement_min = "turbulence_initial_displacement_min";
+ shader_names->turbulence_initial_displacement_max = "turbulence_initial_displacement_max";
+
shader_names->gravity = "gravity";
shader_names->lifetime_randomness = "lifetime_randomness";
@@ -110,14 +121,14 @@ void ParticlesMaterial::init_shaders() {
shader_names->collision_bounce = "collision_bounce";
}
-void ParticlesMaterial::finish_shaders() {
+void ParticleProcessMaterial::finish_shaders() {
memdelete(dirty_materials);
dirty_materials = nullptr;
memdelete(shader_names);
}
-void ParticlesMaterial::_update_shader() {
+void ParticleProcessMaterial::_update_shader() {
dirty_materials->remove(&element);
MaterialKey mk = _compute_key();
@@ -141,11 +152,10 @@ void ParticlesMaterial::_update_shader() {
shader_map[mk].users++;
return;
}
-
//must create a shader!
// Add a comment to describe the shader origin (useful when converting to ShaderMaterial).
- String code = "// NOTE: Shader automatically converted from " VERSION_NAME " " VERSION_FULL_CONFIG "'s ParticlesMaterial.\n\n";
+ String code = "// NOTE: Shader automatically converted from " VERSION_NAME " " VERSION_FULL_CONFIG "'s ParticleProcessMaterial.\n\n";
code += "shader_type particles;\n";
@@ -277,11 +287,82 @@ void ParticlesMaterial::_update_shader() {
code += "uniform sampler2D anim_offset_texture : repeat_disable;\n";
}
- if (collision_enabled) {
+ if (collision_mode == COLLISION_RIGID) {
code += "uniform float collision_friction;\n";
code += "uniform float collision_bounce;\n";
}
+ if (turbulence_enabled) {
+ code += "uniform float turbulence_noise_strength;\n";
+ code += "uniform float turbulence_noise_scale;\n";
+ code += "uniform float turbulence_influence_min;\n";
+ code += "uniform float turbulence_influence_max;\n";
+ code += "uniform float turbulence_initial_displacement_min;\n";
+ code += "uniform float turbulence_initial_displacement_max;\n";
+ code += "uniform float turbulence_noise_speed_random;\n";
+ code += "uniform vec3 turbulence_noise_speed = vec3(1.0, 1.0, 1.0);\n";
+ if (tex_parameters[PARAM_TURB_INFLUENCE_OVER_LIFE].is_valid()) {
+ code += "uniform sampler2D turbulence_influence_over_life;\n";
+ }
+ if (turbulence_color_ramp.is_valid()) {
+ code += "uniform sampler2D turbulence_color_ramp;\n";
+ }
+ code += "\n";
+
+ //functions for 3D noise / turbulence
+ code += "\n\n";
+ code += "// 3D Noise with friendly permission by Inigo Quilez\n";
+ code += "vec3 hash_noise( vec3 p ) {\n";
+ code += " p *= mat3(vec3(127.1, 311.7, -53.7), vec3(269.5, 183.3, 77.1), vec3(-301.7, 27.3, 215.3));\n";
+ code += " return 2.0 * fract(fract(p)*4375.55) -1.;\n";
+ code += "}\n";
+ code += "\n";
+ code += "float noise( vec3 p) {\n";
+ code += " vec3 i = floor(p);;\n";
+ code += " vec3 f = fract(p);\n ";
+ code += " vec3 u = f * f * (3.0 - 2.0 * f);\n";
+ code += "\n";
+ code += " return 2.0*mix( mix( mix( dot( hash_noise( i + vec3(0.0,0.0,0.0) ), f - vec3(0.0,0.0,0.0) ), dot( hash_noise( i + vec3(1.0,0.0,0.0) ), f - vec3(1.0,0.0,0.0) ), u.x),\n";
+ code += " mix( dot( hash_noise( i + vec3(0.0,1.0,0.0) ), f - vec3(0.0,1.0,0.0) ), dot( hash_noise( i + vec3(1.0,1.0,0.0) ), f - vec3(1.0,1.0,0.0) ), u.x), u.y),\n";
+ code += " mix( mix( dot( hash_noise( i + vec3(0.0,0.0,1.0) ), f - vec3(0.0,0.0,1.0) ), dot( hash_noise( i + vec3(1.0,0.0,1.0) ), f - vec3(1.0,0.0,1.0) ), u.x),\n";
+ code += " mix( dot( hash_noise( i + vec3(0.0,1.0,1.0) ), f - vec3(0.0,1.0,1.0) ), dot( hash_noise( i + vec3(1.0,1.0,1.0) ), f - vec3(1.0,1.0,1.0) ), u.x), u.y), u.z);\n";
+ code += "}\n\n";
+ code += "// Curl 3D and noise_3d function with friendly permission by Isaac Cohen\n";
+ code += "vec3 noise_3d(vec3 p) {\n";
+ code += " float s = noise(p);\n";
+ code += " float s1 = noise(vec3(p.y - 19.1, p.z + 33.4, p.x + 47.2));\n";
+ code += " float s2 = noise(vec3(p.z + 74.2, p.x - 124.5, p.y + 99.4));\n";
+ code += " vec3 c = vec3(s, s1, s2);\n";
+ code += " return c;\n";
+ code += "}\n\n";
+ code += "vec3 curl_3d(vec3 p, float c) {\n";
+ code += " float epsilon = 0.001 + c;\n";
+ code += " vec3 dx = vec3(epsilon, 0.0, 0.0);\n";
+ code += " vec3 dy = vec3(0.0, epsilon, 0.0);\n";
+ code += " vec3 dz = vec3(0.0, 0.0, epsilon);\n";
+ code += " vec3 x0 = noise_3d(p - dx).xyz;\n";
+ code += " vec3 x1 = noise_3d(p + dx).xyz;\n";
+ code += " vec3 y0 = noise_3d(p - dy).xyz;\n";
+ code += " vec3 y1 = noise_3d(p + dy).xyz;\n";
+ code += " vec3 z0 = noise_3d(p - dz).xyz;\n";
+ code += " vec3 z1 = noise_3d(p + dz).xyz;\n";
+ code += " float x = y1.z - y0.z - z1.y + z0.y;\n";
+ code += " float y = z1.x - z0.x - x1.z + x0.z;\n";
+ code += " float z = x1.y - x0.y - y1.x + y0.x;\n";
+ code += " float divisor = 1.0 / (2.0 * epsilon);\n";
+ code += " return vec3(normalize(vec3(x, y, z) * divisor));\n";
+ code += "}\n";
+ code += "vec3 get_noise_direction(vec3 pos, vec3 emission_pos, vec3 time_noise) {\n";
+ code += " float adj_contrast = max((turbulence_noise_strength - 1.0), 0.0) * 70.0;\n";
+ code += " vec3 noise_time = (vec3(TIME) * turbulence_noise_speed) + time_noise;\n";
+ code += " vec3 noise_pos = (pos * turbulence_noise_scale) - emission_pos;\n";
+ code += " vec3 diff = pos - emission_pos;\n";
+ code += " vec3 noise_direction = curl_3d(noise_pos + noise_time - diff, adj_contrast);\n";
+ code += " noise_direction = mix(0.9 * noise_direction, noise_direction, turbulence_noise_strength - 9.0);\n";
+ code += " return noise_direction;\n";
+ code += "}\n";
+ }
+
//need a random function
code += "\n\n";
code += "float rand_from_seed(inout uint seed) {\n";
@@ -463,8 +544,18 @@ void ParticlesMaterial::_update_shader() {
break;
}
}
-
code += " if (RESTART_VELOCITY) VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n";
+ // Apply noise/turbulence: initial displacement.
+ if (turbulence_enabled) {
+ if (get_turbulence_noise_speed_random() >= 0.0) {
+ code += " vec3 time_noise = noise_3d( vec3(TIME) * turbulence_noise_speed_random ) * -turbulence_noise_speed;\n";
+ } else {
+ code += " const vec3 time_noise = vec3(0.0);\n";
+ }
+ code += " vec3 noise_direction = get_noise_direction(TRANSFORM[3].xyz, EMISSION_TRANSFORM[3].xyz, time_noise);\n";
+ code += " float turb_init_displacement = mix(turbulence_initial_displacement_min, turbulence_initial_displacement_max, rand_from_seed(alt_seed));";
+ code += " TRANSFORM[3].xyz += noise_direction * turb_init_displacement;\n";
+ }
code += " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n";
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
code += " VELOCITY.z = 0.0;\n";
@@ -483,7 +574,6 @@ void ParticlesMaterial::_update_shader() {
if (color_initial_ramp.is_valid()) {
code += " float color_initial_rand = rand_from_seed(alt_seed);\n";
}
-
code += " float pi = 3.14159;\n";
code += " float degree_to_rad = pi / 180.0;\n";
code += "\n";
@@ -570,7 +660,7 @@ void ParticlesMaterial::_update_shader() {
code += " vec3 diff = pos - org;\n";
code += " force += length(diff) > 0.0 ? normalize(diff) * tex_radial_accel * mix(radial_accel_min, radial_accel_max, rand_from_seed(alt_seed)) : vec3(0.0);\n";
code += " // apply tangential acceleration;\n";
- code += " float tangent_accel_val = tex_tangent_accel * mix(tangent_accel_min, tangent_accel_max, rand_from_seed(alt_seed))\n;";
+ code += " float tangent_accel_val = tex_tangent_accel * mix(tangent_accel_min, tangent_accel_max, rand_from_seed(alt_seed));\n";
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
code += " force += length(diff.yx) > 0.0 ? vec3(normalize(diff.yx * vec2(-1.0, 1.0)), 0.0) * tangent_accel_val : vec3(0.0);\n";
@@ -584,6 +674,43 @@ void ParticlesMaterial::_update_shader() {
code += " // apply attractor forces\n";
code += " VELOCITY += force * DELTA;\n";
+
+ if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
+ code += " VELOCITY = normalize(VELOCITY) * tex_linear_velocity;\n";
+ }
+
+ // Apply noise/turbulence.
+ if (turbulence_enabled) {
+ code += " // apply turbulence\n";
+ if (tex_parameters[PARAM_TURB_INFLUENCE_OVER_LIFE].is_valid()) {
+ code += " float turbulence_influence = textureLod(turbulence_influence_over_life, vec2(tv, 0.0), 0.0).r;\n";
+ } else {
+ code += " const float turbulence_influence = 1.0;\n";
+ }
+ code += " \n";
+ if (get_turbulence_noise_speed_random() >= 0.0) {
+ code += " vec3 time_noise = noise_3d( vec3(TIME) * turbulence_noise_speed_random ) * -turbulence_noise_speed;\n";
+ } else {
+ code += " const vec3 time_noise = vec3(0.0);\n";
+ }
+ code += " vec3 noise_direction = get_noise_direction(TRANSFORM[3].xyz, EMISSION_TRANSFORM[3].xyz, time_noise);\n";
+ // If collision happened, turbulence is no longer applied.
+ // We don't need this check when the collision mode is "hide on contact",
+ // as the particle will be hidden anyway.
+ String extra_tab = "";
+ if (collision_mode != COLLISION_RIGID) {
+ code += " if (!COLLIDED) {\n";
+ extra_tab = " ";
+ }
+ code += extra_tab + " \n";
+ code += extra_tab + " float vel_mag = length(VELOCITY);\n";
+ code += extra_tab + " float vel_infl = clamp(mix(turbulence_influence_min, turbulence_influence_max, rand_from_seed(alt_seed)) * turbulence_influence, 0.0, 1.0);\n";
+ code += extra_tab + " VELOCITY = mix(VELOCITY, normalize(noise_direction) * vel_mag * (1.0 + (1.0 - vel_infl) * 0.2), vel_infl);\n";
+ if (collision_mode != COLLISION_RIGID) {
+ code += " }";
+ }
+ }
+ code += " \n";
code += " // orbit velocity\n";
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
code += " float orbit_amount = tex_orbit_velocity * mix(orbit_velocity_min, orbit_velocity_max, rand_from_seed(alt_seed));\n";
@@ -595,9 +722,6 @@ void ParticlesMaterial::_update_shader() {
code += " }\n";
}
- if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
- code += " VELOCITY = normalize(VELOCITY) * tex_linear_velocity;\n";
- }
code += " float dmp = mix(damping_min, damping_max, rand_from_seed(alt_seed));\n";
code += " if (dmp * tex_damping > 0.0) {\n";
code += " float v = length(VELOCITY);\n";
@@ -701,24 +825,46 @@ void ParticlesMaterial::_update_shader() {
code += " TRANSFORM[3] = origin;\n";
}
}
- //scale by scale
+
+ if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
+ code += " TRANSFORM[3].z = 0.0;\n";
+ }
+
+ if (collision_mode == COLLISION_RIGID) {
+ code += " if (COLLIDED) {\n";
+ code += " if (length(VELOCITY) > 3.0) {\n";
+ code += " TRANSFORM[3].xyz += COLLISION_NORMAL * COLLISION_DEPTH;\n";
+ code += " VELOCITY -= COLLISION_NORMAL * dot(COLLISION_NORMAL, VELOCITY) * (1.0 + collision_bounce);\n";
+ code += " VELOCITY = mix(VELOCITY,vec3(0.0),clamp(collision_friction, 0.0, 1.0));\n";
+ code += " } else {\n";
+ code += " VELOCITY = vec3(0.0);\n";
+ // If turbulence is enabled, set the noise direction to up so the turbulence color is "neutral"
+ if (turbulence_enabled) {
+ code += " noise_direction = vec3(1.0, 0.0, 0.0);\n";
+ }
+ code += " }\n";
+ code += " }\n";
+ }
+
+ // scale by scale
code += " float base_scale = mix(scale_min, scale_max, scale_rand);\n";
code += " base_scale = sign(base_scale) * max(abs(base_scale), 0.001);\n";
-
code += " TRANSFORM[0].xyz *= base_scale * sign(tex_scale.r) * max(abs(tex_scale.r), 0.001);\n";
code += " TRANSFORM[1].xyz *= base_scale * sign(tex_scale.g) * max(abs(tex_scale.g), 0.001);\n";
code += " TRANSFORM[2].xyz *= base_scale * sign(tex_scale.b) * max(abs(tex_scale.b), 0.001);\n";
- if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- code += " VELOCITY.z = 0.0;\n";
- code += " TRANSFORM[3].z = 0.0;\n";
- }
- if (collision_enabled) {
+
+ if (collision_mode == COLLISION_RIGID) {
code += " if (COLLIDED) {\n";
code += " TRANSFORM[3].xyz+=COLLISION_NORMAL * COLLISION_DEPTH;\n";
code += " VELOCITY -= COLLISION_NORMAL * dot(COLLISION_NORMAL, VELOCITY) * (1.0 + collision_bounce);\n";
code += " VELOCITY = mix(VELOCITY,vec3(0.0),collision_friction * DELTA * 100.0);\n";
code += " }\n";
+ } else if (collision_mode == COLLISION_HIDE_ON_CONTACT) {
+ code += " if (COLLIDED) {\n";
+ code += " ACTIVE = false;\n";
+ code += " }\n";
}
+
if (sub_emitter_mode != SUB_EMITTER_DISABLED) {
code += " int emit_count = 0;\n";
switch (sub_emitter_mode) {
@@ -762,7 +908,7 @@ void ParticlesMaterial::_update_shader() {
RS::get_singleton()->material_set_shader(_get_material(), shader_data.shader);
}
-void ParticlesMaterial::flush_changes() {
+void ParticleProcessMaterial::flush_changes() {
MutexLock lock(material_mutex);
while (dirty_materials->first()) {
@@ -770,7 +916,7 @@ void ParticlesMaterial::flush_changes() {
}
}
-void ParticlesMaterial::_queue_shader_change() {
+void ParticleProcessMaterial::_queue_shader_change() {
MutexLock lock(material_mutex);
if (is_initialized && !element.in_list()) {
@@ -778,40 +924,40 @@ void ParticlesMaterial::_queue_shader_change() {
}
}
-bool ParticlesMaterial::_is_shader_dirty() const {
+bool ParticleProcessMaterial::_is_shader_dirty() const {
MutexLock lock(material_mutex);
return element.in_list();
}
-void ParticlesMaterial::set_direction(Vector3 p_direction) {
+void ParticleProcessMaterial::set_direction(Vector3 p_direction) {
direction = p_direction;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->direction, direction);
}
-Vector3 ParticlesMaterial::get_direction() const {
+Vector3 ParticleProcessMaterial::get_direction() const {
return direction;
}
-void ParticlesMaterial::set_spread(float p_spread) {
+void ParticleProcessMaterial::set_spread(float p_spread) {
spread = p_spread;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->spread, p_spread);
}
-float ParticlesMaterial::get_spread() const {
+float ParticleProcessMaterial::get_spread() const {
return spread;
}
-void ParticlesMaterial::set_flatness(float p_flatness) {
+void ParticleProcessMaterial::set_flatness(float p_flatness) {
flatness = p_flatness;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->flatness, p_flatness);
}
-float ParticlesMaterial::get_flatness() const {
+float ParticleProcessMaterial::get_flatness() const {
return flatness;
}
-void ParticlesMaterial::set_param_min(Parameter p_param, float p_value) {
+void ParticleProcessMaterial::set_param_min(Parameter p_param, float p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
params_min[p_param] = p_value;
@@ -856,18 +1002,27 @@ void ParticlesMaterial::set_param_min(Parameter p_param, float p_value) {
case PARAM_ANIM_OFFSET: {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_min, p_value);
} break;
+ case PARAM_TURB_VEL_INFLUENCE: {
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_influence_min, p_value);
+ } break;
+ case PARAM_TURB_INIT_DISPLACEMENT: {
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_initial_displacement_min, p_value);
+ } break;
+ case PARAM_TURB_INFLUENCE_OVER_LIFE: {
+ // Can't happen, but silences warning
+ } break;
case PARAM_MAX:
break; // Can't happen, but silences warning
}
}
-float ParticlesMaterial::get_param_min(Parameter p_param) const {
+float ParticleProcessMaterial::get_param_min(Parameter p_param) const {
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
return params_min[p_param];
}
-void ParticlesMaterial::set_param_max(Parameter p_param, float p_value) {
+void ParticleProcessMaterial::set_param_max(Parameter p_param, float p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
params_max[p_param] = p_value;
@@ -912,12 +1067,21 @@ void ParticlesMaterial::set_param_max(Parameter p_param, float p_value) {
case PARAM_ANIM_OFFSET: {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_max, p_value);
} break;
+ case PARAM_TURB_VEL_INFLUENCE: {
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_influence_max, p_value);
+ } break;
+ case PARAM_TURB_INIT_DISPLACEMENT: {
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_initial_displacement_max, p_value);
+ } break;
+ case PARAM_TURB_INFLUENCE_OVER_LIFE: {
+ // Can't happen, but silences warning
+ } break;
case PARAM_MAX:
break; // Can't happen, but silences warning
}
}
-float ParticlesMaterial::get_param_max(Parameter p_param) const {
+float ParticleProcessMaterial::get_param_max(Parameter p_param) const {
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
return params_max[p_param];
@@ -932,7 +1096,7 @@ static void _adjust_curve_range(const Ref<Texture2D> &p_texture, float p_min, fl
curve_tex->ensure_default_setup(p_min, p_max);
}
-void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture2D> &p_texture) {
+void ParticleProcessMaterial::set_param_texture(Parameter p_param, const Ref<Texture2D> &p_texture) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
tex_parameters[p_param] = p_texture;
@@ -986,6 +1150,16 @@ void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture2D
case PARAM_ANIM_OFFSET: {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, tex_rid);
} break;
+ case PARAM_TURB_INFLUENCE_OVER_LIFE: {
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_influence_over_life, tex_rid);
+ _adjust_curve_range(p_texture, 0, 1);
+ } break;
+ case PARAM_TURB_VEL_INFLUENCE: {
+ // Can't happen, but silences warning
+ } break;
+ case PARAM_TURB_INIT_DISPLACEMENT: {
+ // Can't happen, but silences warning
+ } break;
case PARAM_MAX:
break; // Can't happen, but silences warning
}
@@ -993,22 +1167,22 @@ void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture2D
_queue_shader_change();
}
-Ref<Texture2D> ParticlesMaterial::get_param_texture(Parameter p_param) const {
+Ref<Texture2D> ParticleProcessMaterial::get_param_texture(Parameter p_param) const {
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, Ref<Texture2D>());
return tex_parameters[p_param];
}
-void ParticlesMaterial::set_color(const Color &p_color) {
+void ParticleProcessMaterial::set_color(const Color &p_color) {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color, p_color);
color = p_color;
}
-Color ParticlesMaterial::get_color() const {
+Color ParticleProcessMaterial::get_color() const {
return color;
}
-void ParticlesMaterial::set_color_ramp(const Ref<Texture2D> &p_texture) {
+void ParticleProcessMaterial::set_color_ramp(const Ref<Texture2D> &p_texture) {
color_ramp = p_texture;
RID tex_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color_ramp, tex_rid);
@@ -1016,11 +1190,11 @@ void ParticlesMaterial::set_color_ramp(const Ref<Texture2D> &p_texture) {
notify_property_list_changed();
}
-Ref<Texture2D> ParticlesMaterial::get_color_ramp() const {
+Ref<Texture2D> ParticleProcessMaterial::get_color_ramp() const {
return color_ramp;
}
-void ParticlesMaterial::set_color_initial_ramp(const Ref<Texture2D> &p_texture) {
+void ParticleProcessMaterial::set_color_initial_ramp(const Ref<Texture2D> &p_texture) {
color_initial_ramp = p_texture;
RID tex_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color_initial_ramp, tex_rid);
@@ -1028,11 +1202,11 @@ void ParticlesMaterial::set_color_initial_ramp(const Ref<Texture2D> &p_texture)
notify_property_list_changed();
}
-Ref<Texture2D> ParticlesMaterial::get_color_initial_ramp() const {
+Ref<Texture2D> ParticleProcessMaterial::get_color_initial_ramp() const {
return color_initial_ramp;
}
-void ParticlesMaterial::set_particle_flag(ParticleFlags p_particle_flag, bool p_enable) {
+void ParticleProcessMaterial::set_particle_flag(ParticleFlags p_particle_flag, bool p_enable) {
ERR_FAIL_INDEX(p_particle_flag, PARTICLE_FLAG_MAX);
particle_flags[p_particle_flag] = p_enable;
_queue_shader_change();
@@ -1041,117 +1215,165 @@ void ParticlesMaterial::set_particle_flag(ParticleFlags p_particle_flag, bool p_
}
}
-bool ParticlesMaterial::get_particle_flag(ParticleFlags p_particle_flag) const {
+bool ParticleProcessMaterial::get_particle_flag(ParticleFlags p_particle_flag) const {
ERR_FAIL_INDEX_V(p_particle_flag, PARTICLE_FLAG_MAX, false);
return particle_flags[p_particle_flag];
}
-void ParticlesMaterial::set_emission_shape(EmissionShape p_shape) {
+void ParticleProcessMaterial::set_emission_shape(EmissionShape p_shape) {
ERR_FAIL_INDEX(p_shape, EMISSION_SHAPE_MAX);
emission_shape = p_shape;
notify_property_list_changed();
_queue_shader_change();
}
-void ParticlesMaterial::set_emission_sphere_radius(real_t p_radius) {
+void ParticleProcessMaterial::set_emission_sphere_radius(real_t p_radius) {
emission_sphere_radius = p_radius;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_sphere_radius, p_radius);
}
-void ParticlesMaterial::set_emission_box_extents(Vector3 p_extents) {
+void ParticleProcessMaterial::set_emission_box_extents(Vector3 p_extents) {
emission_box_extents = p_extents;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_box_extents, p_extents);
}
-void ParticlesMaterial::set_emission_point_texture(const Ref<Texture2D> &p_points) {
+void ParticleProcessMaterial::set_emission_point_texture(const Ref<Texture2D> &p_points) {
emission_point_texture = p_points;
RID tex_rid = p_points.is_valid() ? p_points->get_rid() : RID();
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, tex_rid);
}
-void ParticlesMaterial::set_emission_normal_texture(const Ref<Texture2D> &p_normals) {
+void ParticleProcessMaterial::set_emission_normal_texture(const Ref<Texture2D> &p_normals) {
emission_normal_texture = p_normals;
RID tex_rid = p_normals.is_valid() ? p_normals->get_rid() : RID();
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, tex_rid);
}
-void ParticlesMaterial::set_emission_color_texture(const Ref<Texture2D> &p_colors) {
+void ParticleProcessMaterial::set_emission_color_texture(const Ref<Texture2D> &p_colors) {
emission_color_texture = p_colors;
RID tex_rid = p_colors.is_valid() ? p_colors->get_rid() : RID();
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, tex_rid);
_queue_shader_change();
}
-void ParticlesMaterial::set_emission_point_count(int p_count) {
+void ParticleProcessMaterial::set_emission_point_count(int p_count) {
emission_point_count = p_count;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_point_count, p_count);
}
-void ParticlesMaterial::set_emission_ring_axis(Vector3 p_axis) {
+void ParticleProcessMaterial::set_emission_ring_axis(Vector3 p_axis) {
emission_ring_axis = p_axis;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_ring_axis, p_axis);
}
-void ParticlesMaterial::set_emission_ring_height(real_t p_height) {
+void ParticleProcessMaterial::set_emission_ring_height(real_t p_height) {
emission_ring_height = p_height;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_ring_height, p_height);
}
-void ParticlesMaterial::set_emission_ring_radius(real_t p_radius) {
+void ParticleProcessMaterial::set_emission_ring_radius(real_t p_radius) {
emission_ring_radius = p_radius;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_ring_radius, p_radius);
}
-void ParticlesMaterial::set_emission_ring_inner_radius(real_t p_radius) {
+void ParticleProcessMaterial::set_emission_ring_inner_radius(real_t p_radius) {
emission_ring_inner_radius = p_radius;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_ring_inner_radius, p_radius);
}
-ParticlesMaterial::EmissionShape ParticlesMaterial::get_emission_shape() const {
+ParticleProcessMaterial::EmissionShape ParticleProcessMaterial::get_emission_shape() const {
return emission_shape;
}
-real_t ParticlesMaterial::get_emission_sphere_radius() const {
+real_t ParticleProcessMaterial::get_emission_sphere_radius() const {
return emission_sphere_radius;
}
-Vector3 ParticlesMaterial::get_emission_box_extents() const {
+Vector3 ParticleProcessMaterial::get_emission_box_extents() const {
return emission_box_extents;
}
-Ref<Texture2D> ParticlesMaterial::get_emission_point_texture() const {
+Ref<Texture2D> ParticleProcessMaterial::get_emission_point_texture() const {
return emission_point_texture;
}
-Ref<Texture2D> ParticlesMaterial::get_emission_normal_texture() const {
+Ref<Texture2D> ParticleProcessMaterial::get_emission_normal_texture() const {
return emission_normal_texture;
}
-Ref<Texture2D> ParticlesMaterial::get_emission_color_texture() const {
+Ref<Texture2D> ParticleProcessMaterial::get_emission_color_texture() const {
return emission_color_texture;
}
-int ParticlesMaterial::get_emission_point_count() const {
+int ParticleProcessMaterial::get_emission_point_count() const {
return emission_point_count;
}
-Vector3 ParticlesMaterial::get_emission_ring_axis() const {
+Vector3 ParticleProcessMaterial::get_emission_ring_axis() const {
return emission_ring_axis;
}
-real_t ParticlesMaterial::get_emission_ring_height() const {
+real_t ParticleProcessMaterial::get_emission_ring_height() const {
return emission_ring_height;
}
-real_t ParticlesMaterial::get_emission_ring_radius() const {
+real_t ParticleProcessMaterial::get_emission_ring_radius() const {
return emission_ring_radius;
}
-real_t ParticlesMaterial::get_emission_ring_inner_radius() const {
+real_t ParticleProcessMaterial::get_emission_ring_inner_radius() const {
return emission_ring_inner_radius;
}
-void ParticlesMaterial::set_gravity(const Vector3 &p_gravity) {
+void ParticleProcessMaterial::set_turbulence_enabled(const bool p_turbulence_enabled) {
+ turbulence_enabled = p_turbulence_enabled;
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_enabled, turbulence_enabled);
+ _queue_shader_change();
+ notify_property_list_changed();
+}
+
+bool ParticleProcessMaterial::get_turbulence_enabled() const {
+ return turbulence_enabled;
+}
+
+void ParticleProcessMaterial::set_turbulence_noise_strength(float p_turbulence_noise_strength) {
+ turbulence_noise_strength = p_turbulence_noise_strength;
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_strength, p_turbulence_noise_strength);
+}
+
+float ParticleProcessMaterial::get_turbulence_noise_strength() const {
+ return turbulence_noise_strength;
+}
+
+void ParticleProcessMaterial::set_turbulence_noise_scale(float p_turbulence_noise_scale) {
+ turbulence_noise_scale = p_turbulence_noise_scale;
+ float shader_turbulence_noise_scale = (pow(p_turbulence_noise_scale, 0.25) * 5.6234 / 10.0) * 4.0 - 3.0;
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_scale, shader_turbulence_noise_scale);
+}
+
+float ParticleProcessMaterial::get_turbulence_noise_scale() const {
+ return turbulence_noise_scale;
+}
+
+void ParticleProcessMaterial::set_turbulence_noise_speed_random(float p_turbulence_noise_speed_random) {
+ turbulence_noise_speed_random = p_turbulence_noise_speed_random;
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_speed_random, p_turbulence_noise_speed_random);
+}
+
+float ParticleProcessMaterial::get_turbulence_noise_speed_random() const {
+ return turbulence_noise_speed_random;
+}
+
+void ParticleProcessMaterial::set_turbulence_noise_speed(const Vector3 &p_turbulence_noise_speed) {
+ turbulence_noise_speed = p_turbulence_noise_speed;
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->turbulence_noise_speed, turbulence_noise_speed);
+}
+
+Vector3 ParticleProcessMaterial::get_turbulence_noise_speed() const {
+ return turbulence_noise_speed;
+}
+
+void ParticleProcessMaterial::set_gravity(const Vector3 &p_gravity) {
gravity = p_gravity;
Vector3 gset = gravity;
if (gset == Vector3()) {
@@ -1160,243 +1382,281 @@ void ParticlesMaterial::set_gravity(const Vector3 &p_gravity) {
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->gravity, gset);
}
-Vector3 ParticlesMaterial::get_gravity() const {
+Vector3 ParticleProcessMaterial::get_gravity() const {
return gravity;
}
-void ParticlesMaterial::set_lifetime_randomness(double p_lifetime) {
+void ParticleProcessMaterial::set_lifetime_randomness(double p_lifetime) {
lifetime_randomness = p_lifetime;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->lifetime_randomness, lifetime_randomness);
}
-double ParticlesMaterial::get_lifetime_randomness() const {
+double ParticleProcessMaterial::get_lifetime_randomness() const {
return lifetime_randomness;
}
-RID ParticlesMaterial::get_shader_rid() const {
+RID ParticleProcessMaterial::get_shader_rid() const {
ERR_FAIL_COND_V(!shader_map.has(current_key), RID());
return shader_map[current_key].shader;
}
-void ParticlesMaterial::_validate_property(PropertyInfo &property) const {
- if (property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) {
- property.usage = PROPERTY_USAGE_NONE;
+void ParticleProcessMaterial::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "emission_sphere_radius" && (emission_shape != EMISSION_SHAPE_SPHERE && emission_shape != EMISSION_SHAPE_SPHERE_SURFACE)) {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+
+ if (p_property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+
+ if ((p_property.name == "emission_point_texture" || p_property.name == "emission_color_texture") && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "emission_normal_texture" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "emission_point_count" && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "emission_normal_texture" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("emission_ring_") && emission_shape != EMISSION_SHAPE_RING) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "emission_point_count" && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "sub_emitter_frequency" && sub_emitter_mode != SUB_EMITTER_CONSTANT) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("emission_ring_") && emission_shape != EMISSION_SHAPE_RING) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "sub_emitter_amount_at_end" && sub_emitter_mode != SUB_EMITTER_AT_END) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name == "sub_emitter_frequency" && sub_emitter_mode != SUB_EMITTER_CONSTANT) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+
+ if (!turbulence_enabled) {
+ if (p_property.name == "turbulence_noise_strength" ||
+ p_property.name == "turbulence_noise_scale" ||
+ p_property.name == "turbulence_noise_speed" ||
+ p_property.name == "turbulence_noise_speed_random" ||
+ p_property.name == "turbulence_influence_over_life" ||
+ p_property.name == "turbulence_influence_min" ||
+ p_property.name == "turbulence_influence_max" ||
+ p_property.name == "turbulence_initial_displacement_min" ||
+ p_property.name == "turbulence_initial_displacement_max") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
}
- if (property.name == "sub_emitter_amount_at_end" && sub_emitter_mode != SUB_EMITTER_AT_END) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "collision_friction" && collision_mode != COLLISION_RIGID) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
- if (property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- property.usage = PROPERTY_USAGE_NONE;
+ if (p_property.name == "collision_bounce" && collision_mode != COLLISION_RIGID) {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
-void ParticlesMaterial::set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode) {
+void ParticleProcessMaterial::set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode) {
sub_emitter_mode = p_sub_emitter_mode;
_queue_shader_change();
notify_property_list_changed();
}
-ParticlesMaterial::SubEmitterMode ParticlesMaterial::get_sub_emitter_mode() const {
+ParticleProcessMaterial::SubEmitterMode ParticleProcessMaterial::get_sub_emitter_mode() const {
return sub_emitter_mode;
}
-void ParticlesMaterial::set_sub_emitter_frequency(double p_frequency) {
+void ParticleProcessMaterial::set_sub_emitter_frequency(double p_frequency) {
sub_emitter_frequency = p_frequency;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_frequency, 1.0 / p_frequency); //pass delta instead of frequency, since its easier to compute
}
-double ParticlesMaterial::get_sub_emitter_frequency() const {
+double ParticleProcessMaterial::get_sub_emitter_frequency() const {
return sub_emitter_frequency;
}
-void ParticlesMaterial::set_sub_emitter_amount_at_end(int p_amount) {
+void ParticleProcessMaterial::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 {
+int ParticleProcessMaterial::get_sub_emitter_amount_at_end() const {
return sub_emitter_amount_at_end;
}
-void ParticlesMaterial::set_sub_emitter_keep_velocity(bool p_enable) {
+void ParticleProcessMaterial::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 {
+bool ParticleProcessMaterial::get_sub_emitter_keep_velocity() const {
return sub_emitter_keep_velocity;
}
-void ParticlesMaterial::set_attractor_interaction_enabled(bool p_enable) {
+void ParticleProcessMaterial::set_attractor_interaction_enabled(bool p_enable) {
attractor_interaction_enabled = p_enable;
_queue_shader_change();
}
-bool ParticlesMaterial::is_attractor_interaction_enabled() const {
+bool ParticleProcessMaterial::is_attractor_interaction_enabled() const {
return attractor_interaction_enabled;
}
-void ParticlesMaterial::set_collision_enabled(bool p_enabled) {
- collision_enabled = p_enabled;
+void ParticleProcessMaterial::set_collision_mode(CollisionMode p_collision_mode) {
+ collision_mode = p_collision_mode;
_queue_shader_change();
+ notify_property_list_changed();
}
-bool ParticlesMaterial::is_collision_enabled() const {
- return collision_enabled;
+ParticleProcessMaterial::CollisionMode ParticleProcessMaterial::get_collision_mode() const {
+ return collision_mode;
}
-void ParticlesMaterial::set_collision_use_scale(bool p_scale) {
+void ParticleProcessMaterial::set_collision_use_scale(bool p_scale) {
collision_scale = p_scale;
_queue_shader_change();
}
-bool ParticlesMaterial::is_collision_using_scale() const {
+bool ParticleProcessMaterial::is_collision_using_scale() const {
return collision_scale;
}
-void ParticlesMaterial::set_collision_friction(float p_friction) {
+void ParticleProcessMaterial::set_collision_friction(float p_friction) {
collision_friction = p_friction;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->collision_friction, p_friction);
}
-float ParticlesMaterial::get_collision_friction() const {
+float ParticleProcessMaterial::get_collision_friction() const {
return collision_friction;
}
-void ParticlesMaterial::set_collision_bounce(float p_bounce) {
+void ParticleProcessMaterial::set_collision_bounce(float p_bounce) {
collision_bounce = p_bounce;
RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->collision_bounce, p_bounce);
}
-float ParticlesMaterial::get_collision_bounce() const {
+float ParticleProcessMaterial::get_collision_bounce() const {
return collision_bounce;
}
-Shader::Mode ParticlesMaterial::get_shader_mode() const {
+Shader::Mode ParticleProcessMaterial::get_shader_mode() const {
return Shader::MODE_PARTICLES;
}
-void ParticlesMaterial::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_direction", "degrees"), &ParticlesMaterial::set_direction);
- ClassDB::bind_method(D_METHOD("get_direction"), &ParticlesMaterial::get_direction);
+void ParticleProcessMaterial::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_direction", "degrees"), &ParticleProcessMaterial::set_direction);
+ ClassDB::bind_method(D_METHOD("get_direction"), &ParticleProcessMaterial::get_direction);
+
+ ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &ParticleProcessMaterial::set_spread);
+ ClassDB::bind_method(D_METHOD("get_spread"), &ParticleProcessMaterial::get_spread);
+
+ ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &ParticleProcessMaterial::set_flatness);
+ ClassDB::bind_method(D_METHOD("get_flatness"), &ParticleProcessMaterial::get_flatness);
+
+ ClassDB::bind_method(D_METHOD("set_param_min", "param", "value"), &ParticleProcessMaterial::set_param_min);
+ ClassDB::bind_method(D_METHOD("get_param_min", "param"), &ParticleProcessMaterial::get_param_min);
+
+ ClassDB::bind_method(D_METHOD("set_param_max", "param", "value"), &ParticleProcessMaterial::set_param_max);
+ ClassDB::bind_method(D_METHOD("get_param_max", "param"), &ParticleProcessMaterial::get_param_max);
+
+ ClassDB::bind_method(D_METHOD("set_param_texture", "param", "texture"), &ParticleProcessMaterial::set_param_texture);
+ ClassDB::bind_method(D_METHOD("get_param_texture", "param"), &ParticleProcessMaterial::get_param_texture);
- ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &ParticlesMaterial::set_spread);
- ClassDB::bind_method(D_METHOD("get_spread"), &ParticlesMaterial::get_spread);
+ ClassDB::bind_method(D_METHOD("set_color", "color"), &ParticleProcessMaterial::set_color);
+ ClassDB::bind_method(D_METHOD("get_color"), &ParticleProcessMaterial::get_color);
- ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &ParticlesMaterial::set_flatness);
- ClassDB::bind_method(D_METHOD("get_flatness"), &ParticlesMaterial::get_flatness);
+ ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &ParticleProcessMaterial::set_color_ramp);
+ ClassDB::bind_method(D_METHOD("get_color_ramp"), &ParticleProcessMaterial::get_color_ramp);
- ClassDB::bind_method(D_METHOD("set_param_min", "param", "value"), &ParticlesMaterial::set_param_min);
- ClassDB::bind_method(D_METHOD("get_param_min", "param"), &ParticlesMaterial::get_param_min);
+ ClassDB::bind_method(D_METHOD("set_color_initial_ramp", "ramp"), &ParticleProcessMaterial::set_color_initial_ramp);
+ ClassDB::bind_method(D_METHOD("get_color_initial_ramp"), &ParticleProcessMaterial::get_color_initial_ramp);
- ClassDB::bind_method(D_METHOD("set_param_max", "param", "value"), &ParticlesMaterial::set_param_max);
- ClassDB::bind_method(D_METHOD("get_param_max", "param"), &ParticlesMaterial::get_param_max);
+ ClassDB::bind_method(D_METHOD("set_particle_flag", "particle_flag", "enable"), &ParticleProcessMaterial::set_particle_flag);
+ ClassDB::bind_method(D_METHOD("get_particle_flag", "particle_flag"), &ParticleProcessMaterial::get_particle_flag);
- ClassDB::bind_method(D_METHOD("set_param_texture", "param", "texture"), &ParticlesMaterial::set_param_texture);
- ClassDB::bind_method(D_METHOD("get_param_texture", "param"), &ParticlesMaterial::get_param_texture);
+ ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &ParticleProcessMaterial::set_emission_shape);
+ ClassDB::bind_method(D_METHOD("get_emission_shape"), &ParticleProcessMaterial::get_emission_shape);
- ClassDB::bind_method(D_METHOD("set_color", "color"), &ParticlesMaterial::set_color);
- ClassDB::bind_method(D_METHOD("get_color"), &ParticlesMaterial::get_color);
+ ClassDB::bind_method(D_METHOD("set_emission_sphere_radius", "radius"), &ParticleProcessMaterial::set_emission_sphere_radius);
+ ClassDB::bind_method(D_METHOD("get_emission_sphere_radius"), &ParticleProcessMaterial::get_emission_sphere_radius);
- ClassDB::bind_method(D_METHOD("set_color_ramp", "ramp"), &ParticlesMaterial::set_color_ramp);
- ClassDB::bind_method(D_METHOD("get_color_ramp"), &ParticlesMaterial::get_color_ramp);
+ ClassDB::bind_method(D_METHOD("set_emission_box_extents", "extents"), &ParticleProcessMaterial::set_emission_box_extents);
+ ClassDB::bind_method(D_METHOD("get_emission_box_extents"), &ParticleProcessMaterial::get_emission_box_extents);
- ClassDB::bind_method(D_METHOD("set_color_initial_ramp", "ramp"), &ParticlesMaterial::set_color_initial_ramp);
- ClassDB::bind_method(D_METHOD("get_color_initial_ramp"), &ParticlesMaterial::get_color_initial_ramp);
+ ClassDB::bind_method(D_METHOD("set_emission_point_texture", "texture"), &ParticleProcessMaterial::set_emission_point_texture);
+ ClassDB::bind_method(D_METHOD("get_emission_point_texture"), &ParticleProcessMaterial::get_emission_point_texture);
- ClassDB::bind_method(D_METHOD("set_particle_flag", "particle_flag", "enable"), &ParticlesMaterial::set_particle_flag);
- ClassDB::bind_method(D_METHOD("get_particle_flag", "particle_flag"), &ParticlesMaterial::get_particle_flag);
+ ClassDB::bind_method(D_METHOD("set_emission_normal_texture", "texture"), &ParticleProcessMaterial::set_emission_normal_texture);
+ ClassDB::bind_method(D_METHOD("get_emission_normal_texture"), &ParticleProcessMaterial::get_emission_normal_texture);
- ClassDB::bind_method(D_METHOD("set_emission_shape", "shape"), &ParticlesMaterial::set_emission_shape);
- ClassDB::bind_method(D_METHOD("get_emission_shape"), &ParticlesMaterial::get_emission_shape);
+ ClassDB::bind_method(D_METHOD("set_emission_color_texture", "texture"), &ParticleProcessMaterial::set_emission_color_texture);
+ ClassDB::bind_method(D_METHOD("get_emission_color_texture"), &ParticleProcessMaterial::get_emission_color_texture);
- ClassDB::bind_method(D_METHOD("set_emission_sphere_radius", "radius"), &ParticlesMaterial::set_emission_sphere_radius);
- ClassDB::bind_method(D_METHOD("get_emission_sphere_radius"), &ParticlesMaterial::get_emission_sphere_radius);
+ ClassDB::bind_method(D_METHOD("set_emission_point_count", "point_count"), &ParticleProcessMaterial::set_emission_point_count);
+ ClassDB::bind_method(D_METHOD("get_emission_point_count"), &ParticleProcessMaterial::get_emission_point_count);
- ClassDB::bind_method(D_METHOD("set_emission_box_extents", "extents"), &ParticlesMaterial::set_emission_box_extents);
- ClassDB::bind_method(D_METHOD("get_emission_box_extents"), &ParticlesMaterial::get_emission_box_extents);
+ ClassDB::bind_method(D_METHOD("set_emission_ring_axis", "axis"), &ParticleProcessMaterial::set_emission_ring_axis);
+ ClassDB::bind_method(D_METHOD("get_emission_ring_axis"), &ParticleProcessMaterial::get_emission_ring_axis);
- ClassDB::bind_method(D_METHOD("set_emission_point_texture", "texture"), &ParticlesMaterial::set_emission_point_texture);
- ClassDB::bind_method(D_METHOD("get_emission_point_texture"), &ParticlesMaterial::get_emission_point_texture);
+ ClassDB::bind_method(D_METHOD("set_emission_ring_height", "height"), &ParticleProcessMaterial::set_emission_ring_height);
+ ClassDB::bind_method(D_METHOD("get_emission_ring_height"), &ParticleProcessMaterial::get_emission_ring_height);
- ClassDB::bind_method(D_METHOD("set_emission_normal_texture", "texture"), &ParticlesMaterial::set_emission_normal_texture);
- ClassDB::bind_method(D_METHOD("get_emission_normal_texture"), &ParticlesMaterial::get_emission_normal_texture);
+ ClassDB::bind_method(D_METHOD("set_emission_ring_radius", "radius"), &ParticleProcessMaterial::set_emission_ring_radius);
+ ClassDB::bind_method(D_METHOD("get_emission_ring_radius"), &ParticleProcessMaterial::get_emission_ring_radius);
- ClassDB::bind_method(D_METHOD("set_emission_color_texture", "texture"), &ParticlesMaterial::set_emission_color_texture);
- ClassDB::bind_method(D_METHOD("get_emission_color_texture"), &ParticlesMaterial::get_emission_color_texture);
+ ClassDB::bind_method(D_METHOD("set_emission_ring_inner_radius", "inner_radius"), &ParticleProcessMaterial::set_emission_ring_inner_radius);
+ ClassDB::bind_method(D_METHOD("get_emission_ring_inner_radius"), &ParticleProcessMaterial::get_emission_ring_inner_radius);
- 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("get_turbulence_enabled"), &ParticleProcessMaterial::get_turbulence_enabled);
+ ClassDB::bind_method(D_METHOD("set_turbulence_enabled", "turbulence_enabled"), &ParticleProcessMaterial::set_turbulence_enabled);
- ClassDB::bind_method(D_METHOD("set_emission_ring_axis", "axis"), &ParticlesMaterial::set_emission_ring_axis);
- ClassDB::bind_method(D_METHOD("get_emission_ring_axis"), &ParticlesMaterial::get_emission_ring_axis);
+ ClassDB::bind_method(D_METHOD("get_turbulence_noise_strength"), &ParticleProcessMaterial::get_turbulence_noise_strength);
+ ClassDB::bind_method(D_METHOD("set_turbulence_noise_strength", "turbulence_noise_strength"), &ParticleProcessMaterial::set_turbulence_noise_strength);
- ClassDB::bind_method(D_METHOD("set_emission_ring_height", "height"), &ParticlesMaterial::set_emission_ring_height);
- ClassDB::bind_method(D_METHOD("get_emission_ring_height"), &ParticlesMaterial::get_emission_ring_height);
+ ClassDB::bind_method(D_METHOD("get_turbulence_noise_scale"), &ParticleProcessMaterial::get_turbulence_noise_scale);
+ ClassDB::bind_method(D_METHOD("set_turbulence_noise_scale", "turbulence_noise_scale"), &ParticleProcessMaterial::set_turbulence_noise_scale);
- ClassDB::bind_method(D_METHOD("set_emission_ring_radius", "radius"), &ParticlesMaterial::set_emission_ring_radius);
- ClassDB::bind_method(D_METHOD("get_emission_ring_radius"), &ParticlesMaterial::get_emission_ring_radius);
+ ClassDB::bind_method(D_METHOD("get_turbulence_noise_speed_random"), &ParticleProcessMaterial::get_turbulence_noise_speed_random);
+ ClassDB::bind_method(D_METHOD("set_turbulence_noise_speed_random", "turbulence_noise_speed_random"), &ParticleProcessMaterial::set_turbulence_noise_speed_random);
- ClassDB::bind_method(D_METHOD("set_emission_ring_inner_radius", "inner_radius"), &ParticlesMaterial::set_emission_ring_inner_radius);
- ClassDB::bind_method(D_METHOD("get_emission_ring_inner_radius"), &ParticlesMaterial::get_emission_ring_inner_radius);
+ ClassDB::bind_method(D_METHOD("get_turbulence_noise_speed"), &ParticleProcessMaterial::get_turbulence_noise_speed);
+ ClassDB::bind_method(D_METHOD("set_turbulence_noise_speed", "turbulence_noise_speed"), &ParticleProcessMaterial::set_turbulence_noise_speed);
- 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("get_gravity"), &ParticleProcessMaterial::get_gravity);
+ ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &ParticleProcessMaterial::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("set_lifetime_randomness", "randomness"), &ParticleProcessMaterial::set_lifetime_randomness);
+ ClassDB::bind_method(D_METHOD("get_lifetime_randomness"), &ParticleProcessMaterial::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_mode"), &ParticleProcessMaterial::get_sub_emitter_mode);
+ ClassDB::bind_method(D_METHOD("set_sub_emitter_mode", "mode"), &ParticleProcessMaterial::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_frequency"), &ParticleProcessMaterial::get_sub_emitter_frequency);
+ ClassDB::bind_method(D_METHOD("set_sub_emitter_frequency", "hz"), &ParticleProcessMaterial::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_amount_at_end"), &ParticleProcessMaterial::get_sub_emitter_amount_at_end);
+ ClassDB::bind_method(D_METHOD("set_sub_emitter_amount_at_end", "amount"), &ParticleProcessMaterial::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);
+ ClassDB::bind_method(D_METHOD("get_sub_emitter_keep_velocity"), &ParticleProcessMaterial::get_sub_emitter_keep_velocity);
+ ClassDB::bind_method(D_METHOD("set_sub_emitter_keep_velocity", "enable"), &ParticleProcessMaterial::set_sub_emitter_keep_velocity);
- ClassDB::bind_method(D_METHOD("set_attractor_interaction_enabled", "enabled"), &ParticlesMaterial::set_attractor_interaction_enabled);
- ClassDB::bind_method(D_METHOD("is_attractor_interaction_enabled"), &ParticlesMaterial::is_attractor_interaction_enabled);
+ ClassDB::bind_method(D_METHOD("set_attractor_interaction_enabled", "enabled"), &ParticleProcessMaterial::set_attractor_interaction_enabled);
+ ClassDB::bind_method(D_METHOD("is_attractor_interaction_enabled"), &ParticleProcessMaterial::is_attractor_interaction_enabled);
- ClassDB::bind_method(D_METHOD("set_collision_enabled", "enabled"), &ParticlesMaterial::set_collision_enabled);
- ClassDB::bind_method(D_METHOD("is_collision_enabled"), &ParticlesMaterial::is_collision_enabled);
+ ClassDB::bind_method(D_METHOD("set_collision_mode", "mode"), &ParticleProcessMaterial::set_collision_mode);
+ ClassDB::bind_method(D_METHOD("get_collision_mode"), &ParticleProcessMaterial::get_collision_mode);
- ClassDB::bind_method(D_METHOD("set_collision_use_scale", "radius"), &ParticlesMaterial::set_collision_use_scale);
- ClassDB::bind_method(D_METHOD("is_collision_using_scale"), &ParticlesMaterial::is_collision_using_scale);
+ ClassDB::bind_method(D_METHOD("set_collision_use_scale", "radius"), &ParticleProcessMaterial::set_collision_use_scale);
+ ClassDB::bind_method(D_METHOD("is_collision_using_scale"), &ParticleProcessMaterial::is_collision_using_scale);
- ClassDB::bind_method(D_METHOD("set_collision_friction", "friction"), &ParticlesMaterial::set_collision_friction);
- ClassDB::bind_method(D_METHOD("get_collision_friction"), &ParticlesMaterial::get_collision_friction);
+ ClassDB::bind_method(D_METHOD("set_collision_friction", "friction"), &ParticleProcessMaterial::set_collision_friction);
+ ClassDB::bind_method(D_METHOD("get_collision_friction"), &ParticleProcessMaterial::get_collision_friction);
- ClassDB::bind_method(D_METHOD("set_collision_bounce", "bounce"), &ParticlesMaterial::set_collision_bounce);
- ClassDB::bind_method(D_METHOD("get_collision_bounce"), &ParticlesMaterial::get_collision_bounce);
+ ClassDB::bind_method(D_METHOD("set_collision_bounce", "bounce"), &ParticleProcessMaterial::set_collision_bounce);
+ ClassDB::bind_method(D_METHOD("get_collision_bounce"), &ParticleProcessMaterial::get_collision_bounce);
ADD_GROUP("Time", "");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime_randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_lifetime_randomness", "get_lifetime_randomness");
@@ -1413,7 +1673,7 @@ void ParticlesMaterial::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_height"), "set_emission_ring_height", "get_emission_ring_height");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_radius"), "set_emission_ring_radius", "get_emission_ring_radius");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_ring_inner_radius"), "set_emission_ring_inner_radius", "get_emission_ring_inner_radius");
- ADD_GROUP("ParticleFlags", "particle_flag_");
+ ADD_GROUP("Particle Flags", "particle_flag_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_align_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_rotate_y"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_ROTATE_Y);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "particle_flag_disable_z"), "set_particle_flag", "get_particle_flag", PARTICLE_FLAG_DISABLE_Z);
@@ -1467,6 +1727,19 @@ void ParticlesMaterial::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_min", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_min", "get_param_min", PARAM_HUE_VARIATION);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_max", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_max", "get_param_max", PARAM_HUE_VARIATION);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_HUE_VARIATION);
+
+ ADD_GROUP("Turbulence", "turbulence_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "turbulence_enabled"), "set_turbulence_enabled", "get_turbulence_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbulence_noise_strength", PROPERTY_HINT_RANGE, "0,20,0.01"), "set_turbulence_noise_strength", "get_turbulence_noise_strength");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbulence_noise_scale", PROPERTY_HINT_RANGE, "0,10,0.01"), "set_turbulence_noise_scale", "get_turbulence_noise_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "turbulence_noise_speed"), "set_turbulence_noise_speed", "get_turbulence_noise_speed");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "turbulence_noise_speed_random", PROPERTY_HINT_RANGE, "0,10,0.01"), "set_turbulence_noise_speed_random", "get_turbulence_noise_speed_random");
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "turbulence_influence_min", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_min", "get_param_min", PARAM_TURB_VEL_INFLUENCE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "turbulence_influence_max", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_max", "get_param_max", PARAM_TURB_VEL_INFLUENCE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "turbulence_initial_displacement_min", PROPERTY_HINT_RANGE, "-100,100,0.1"), "set_param_min", "get_param_min", PARAM_TURB_INIT_DISPLACEMENT);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "turbulence_initial_displacement_max", PROPERTY_HINT_RANGE, "-100,100,0.1"), "set_param_max", "get_param_max", PARAM_TURB_INIT_DISPLACEMENT);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "turbulence_influence_over_life", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TURB_INFLUENCE_OVER_LIFE);
+
ADD_GROUP("Animation", "anim_");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED);
@@ -1484,7 +1757,7 @@ void ParticlesMaterial::_bind_methods() {
ADD_GROUP("Attractor Interaction", "attractor_interaction_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "attractor_interaction_enabled"), "set_attractor_interaction_enabled", "is_attractor_interaction_enabled");
ADD_GROUP("Collision", "collision_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_enabled"), "set_collision_enabled", "is_collision_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mode", PROPERTY_HINT_ENUM, "Disabled,Rigid,Hide On Contact"), "set_collision_mode", "get_collision_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_friction", "get_collision_friction");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_collision_bounce", "get_collision_bounce");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_use_scale"), "set_collision_use_scale", "is_collision_using_scale");
@@ -1517,14 +1790,23 @@ void ParticlesMaterial::_bind_methods() {
BIND_ENUM_CONSTANT(EMISSION_SHAPE_RING);
BIND_ENUM_CONSTANT(EMISSION_SHAPE_MAX);
+ BIND_ENUM_CONSTANT(PARAM_TURB_VEL_INFLUENCE);
+ BIND_ENUM_CONSTANT(PARAM_TURB_INIT_DISPLACEMENT);
+ BIND_ENUM_CONSTANT(PARAM_TURB_INFLUENCE_OVER_LIFE);
+
BIND_ENUM_CONSTANT(SUB_EMITTER_DISABLED);
BIND_ENUM_CONSTANT(SUB_EMITTER_CONSTANT);
BIND_ENUM_CONSTANT(SUB_EMITTER_AT_END);
BIND_ENUM_CONSTANT(SUB_EMITTER_AT_COLLISION);
BIND_ENUM_CONSTANT(SUB_EMITTER_MAX);
+
+ BIND_ENUM_CONSTANT(COLLISION_DISABLED);
+ BIND_ENUM_CONSTANT(COLLISION_RIGID);
+ BIND_ENUM_CONSTANT(COLLISION_HIDE_ON_CONTACT);
+ BIND_ENUM_CONSTANT(COLLISION_MAX);
}
-ParticlesMaterial::ParticlesMaterial() :
+ParticleProcessMaterial::ParticleProcessMaterial() :
element(this) {
set_direction(Vector3(1, 0, 0));
set_spread(45);
@@ -1560,6 +1842,17 @@ ParticlesMaterial::ParticlesMaterial() :
set_emission_ring_height(1);
set_emission_ring_radius(1);
set_emission_ring_inner_radius(0);
+
+ set_turbulence_enabled(false);
+ set_turbulence_noise_speed(Vector3(0.5, 0.5, 0.5));
+ set_turbulence_noise_strength(1);
+ set_turbulence_noise_scale(9);
+ set_turbulence_noise_speed_random(0);
+ set_param_min(PARAM_TURB_VEL_INFLUENCE, 0.1);
+ set_param_max(PARAM_TURB_VEL_INFLUENCE, 0.1);
+ set_param_min(PARAM_TURB_INIT_DISPLACEMENT, 0.0);
+ set_param_max(PARAM_TURB_INIT_DISPLACEMENT, 0.0);
+
set_gravity(Vector3(0, -9.8, 0));
set_lifetime_randomness(0);
@@ -1569,7 +1862,7 @@ ParticlesMaterial::ParticlesMaterial() :
set_sub_emitter_keep_velocity(false);
set_attractor_interaction_enabled(true);
- set_collision_enabled(false);
+ set_collision_mode(COLLISION_DISABLED);
set_collision_bounce(0.0);
set_collision_friction(0.0);
set_collision_use_scale(false);
@@ -1586,7 +1879,7 @@ ParticlesMaterial::ParticlesMaterial() :
_queue_shader_change();
}
-ParticlesMaterial::~ParticlesMaterial() {
+ParticleProcessMaterial::~ParticleProcessMaterial() {
MutexLock lock(material_mutex);
if (shader_map.has(current_key)) {
diff --git a/scene/resources/particles_material.h b/scene/resources/particle_process_material.h
index af45593f38..fe4741d6e5 100644
--- a/scene/resources/particles_material.h
+++ b/scene/resources/particle_process_material.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* particles_material.h */
+/* particle_process_material.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -31,8 +31,8 @@
#include "core/templates/rid.h"
#include "scene/resources/material.h"
-#ifndef PARTICLES_MATERIAL_H
-#define PARTICLES_MATERIAL_H
+#ifndef PARTICLE_PROCESS_MATERIAL_H
+#define PARTICLE_PROCESS_MATERIAL_H
/*
TODO:
@@ -41,8 +41,8 @@
-Proper trails
*/
-class ParticlesMaterial : public Material {
- GDCLASS(ParticlesMaterial, Material);
+class ParticleProcessMaterial : public Material {
+ GDCLASS(ParticleProcessMaterial, Material);
public:
enum Parameter {
@@ -58,6 +58,9 @@ public:
PARAM_HUE_VARIATION,
PARAM_ANIM_SPEED,
PARAM_ANIM_OFFSET,
+ PARAM_TURB_INFLUENCE_OVER_LIFE,
+ PARAM_TURB_VEL_INFLUENCE,
+ PARAM_TURB_INIT_DISPLACEMENT,
PARAM_MAX
};
@@ -90,6 +93,14 @@ public:
SUB_EMITTER_MAX
};
+ // When extending, make sure not to overflow the size of the MaterialKey below.
+ enum CollisionMode {
+ COLLISION_DISABLED,
+ COLLISION_RIGID,
+ COLLISION_HIDE_ON_CONTACT,
+ COLLISION_MAX
+ };
+
private:
union MaterialKey {
// The bit size of the struct must be kept below or equal to 32 bits.
@@ -103,11 +114,12 @@ private:
uint32_t has_emission_color : 1;
uint32_t sub_emitter : 2;
uint32_t attractor_enabled : 1;
- uint32_t collision_enabled : 1;
+ uint32_t collision_mode : 2;
uint32_t collision_scale : 1;
+ uint32_t turbulence_enabled : 1;
};
- uint32_t key = 0;
+ uint64_t key = 0;
static uint32_t hash(const MaterialKey &p_key) {
return hash_murmur3_one_32(p_key.key);
@@ -149,15 +161,16 @@ private:
mk.emission_shape = emission_shape;
mk.has_emission_color = emission_shape >= EMISSION_SHAPE_POINTS && emission_color_texture.is_valid();
mk.sub_emitter = sub_emitter_mode;
- mk.collision_enabled = collision_enabled;
+ mk.collision_mode = collision_mode;
mk.attractor_enabled = attractor_interaction_enabled;
mk.collision_scale = collision_scale;
+ mk.turbulence_enabled = turbulence_enabled;
return mk;
}
static Mutex material_mutex;
- static SelfList<ParticlesMaterial>::List *dirty_materials;
+ static SelfList<ParticleProcessMaterial>::List *dirty_materials;
struct ShaderNames {
StringName direction;
@@ -216,6 +229,17 @@ private:
StringName emission_ring_radius;
StringName emission_ring_inner_radius;
+ StringName turbulence_enabled;
+ StringName turbulence_noise_strength;
+ StringName turbulence_noise_scale;
+ StringName turbulence_noise_speed;
+ StringName turbulence_noise_speed_random;
+ StringName turbulence_influence_over_life;
+ StringName turbulence_influence_min;
+ StringName turbulence_influence_max;
+ StringName turbulence_initial_displacement_min;
+ StringName turbulence_initial_displacement_max;
+
StringName gravity;
StringName lifetime_randomness;
@@ -230,7 +254,7 @@ private:
static ShaderNames *shader_names;
- SelfList<ParticlesMaterial> element;
+ SelfList<ParticleProcessMaterial> element;
void _update_shader();
_FORCE_INLINE_ void _queue_shader_change();
@@ -243,6 +267,7 @@ private:
float params_min[PARAM_MAX];
float params_max[PARAM_MAX];
+ float params[PARAM_MAX];
Ref<Texture2D> tex_parameters[PARAM_MAX];
Color color;
@@ -265,6 +290,13 @@ private:
bool anim_loop = false;
+ bool turbulence_enabled;
+ Vector3 turbulence_noise_speed;
+ Ref<Texture2D> turbulence_color_ramp;
+ float turbulence_noise_strength = 0.0f;
+ float turbulence_noise_scale = 0.0f;
+ float turbulence_noise_speed_random = 0.0f;
+
Vector3 gravity;
double lifetime_randomness = 0.0;
@@ -276,14 +308,14 @@ private:
//do not save emission points here
bool attractor_interaction_enabled = false;
- bool collision_enabled = false;
+ CollisionMode collision_mode;
bool collision_scale = false;
float collision_friction = 0.0f;
float collision_bounce = 0.0f;
protected:
static void _bind_methods();
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_direction(Vector3 p_direction);
@@ -340,6 +372,18 @@ public:
real_t get_emission_ring_inner_radius() const;
int get_emission_point_count() const;
+ void set_turbulence_enabled(bool p_turbulence_enabled);
+ void set_turbulence_noise_strength(float p_turbulence_noise_strength);
+ void set_turbulence_noise_scale(float p_turbulence_noise_scale);
+ void set_turbulence_noise_speed_random(float p_turbulence_noise_speed_random);
+ void set_turbulence_noise_speed(const Vector3 &p_turbulence_noise_speed);
+
+ bool get_turbulence_enabled() const;
+ float get_turbulence_noise_strength() const;
+ float get_turbulence_noise_scale() const;
+ float get_turbulence_noise_speed_random() const;
+ Vector3 get_turbulence_noise_speed() const;
+
void set_gravity(const Vector3 &p_gravity);
Vector3 get_gravity() const;
@@ -349,8 +393,8 @@ public:
void set_attractor_interaction_enabled(bool p_enable);
bool is_attractor_interaction_enabled() const;
- void set_collision_enabled(bool p_enabled);
- bool is_collision_enabled() const;
+ void set_collision_mode(CollisionMode p_collision_mode);
+ CollisionMode get_collision_mode() const;
void set_collision_use_scale(bool p_scale);
bool is_collision_using_scale() const;
@@ -381,13 +425,14 @@ public:
virtual Shader::Mode get_shader_mode() const override;
- ParticlesMaterial();
- ~ParticlesMaterial();
+ ParticleProcessMaterial();
+ ~ParticleProcessMaterial();
};
-VARIANT_ENUM_CAST(ParticlesMaterial::Parameter)
-VARIANT_ENUM_CAST(ParticlesMaterial::ParticleFlags)
-VARIANT_ENUM_CAST(ParticlesMaterial::EmissionShape)
-VARIANT_ENUM_CAST(ParticlesMaterial::SubEmitterMode)
+VARIANT_ENUM_CAST(ParticleProcessMaterial::Parameter)
+VARIANT_ENUM_CAST(ParticleProcessMaterial::ParticleFlags)
+VARIANT_ENUM_CAST(ParticleProcessMaterial::EmissionShape)
+VARIANT_ENUM_CAST(ParticleProcessMaterial::SubEmitterMode)
+VARIANT_ENUM_CAST(ParticleProcessMaterial::CollisionMode)
-#endif // PARTICLES_MATERIAL_H
+#endif // PARTICLE_PROCESS_MATERIAL_H
diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp
index 29135e30c9..5e18671c11 100644
--- a/scene/resources/polygon_path_finder.cpp
+++ b/scene/resources/polygon_path_finder.cpp
@@ -553,7 +553,7 @@ void PolygonPathFinder::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_penalty", "idx"), &PolygonPathFinder::get_point_penalty);
ClassDB::bind_method(D_METHOD("get_bounds"), &PolygonPathFinder::get_bounds);
- ClassDB::bind_method(D_METHOD("_set_data"), &PolygonPathFinder::_set_data);
+ ClassDB::bind_method(D_METHOD("_set_data", "data"), &PolygonPathFinder::_set_data);
ClassDB::bind_method(D_METHOD("_get_data"), &PolygonPathFinder::_get_data);
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index 68441afb1c..fc5cf2a028 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -32,6 +32,7 @@
#include "core/core_string_names.h"
#include "scene/resources/theme.h"
+#include "scene/theme/theme_db.h"
#include "servers/rendering_server.h"
#include "thirdparty/misc/clipper.hpp"
#include "thirdparty/misc/polypartition.h"
@@ -152,8 +153,8 @@ Dictionary PrimitiveMesh::surface_get_lods(int p_surface) const {
return Dictionary(); //not really supported
}
-Array PrimitiveMesh::surface_get_blend_shape_arrays(int p_surface) const {
- return Array(); //not really supported
+TypedArray<Array> PrimitiveMesh::surface_get_blend_shape_arrays(int p_surface) const {
+ return TypedArray<Array>(); //not really supported
}
uint32_t PrimitiveMesh::surface_get_format(int p_idx) const {
@@ -990,6 +991,13 @@ void PlaneMesh::_create_mesh_array(Array &p_arr) const {
Size2 start_pos = size * -0.5;
+ Vector3 normal = Vector3(0.0, 1.0, 0.0);
+ if (orientation == FACE_X) {
+ normal = Vector3(1.0, 0.0, 0.0);
+ } else if (orientation == FACE_Z) {
+ normal = Vector3(0.0, 0.0, 1.0);
+ }
+
Vector<Vector3> points;
Vector<Vector3> normals;
Vector<float> tangents;
@@ -1015,8 +1023,14 @@ void PlaneMesh::_create_mesh_array(Array &p_arr) const {
u /= (subdivide_w + 1.0);
v /= (subdivide_d + 1.0);
- points.push_back(Vector3(-x, 0.0, -z) + center_offset);
- normals.push_back(Vector3(0.0, 1.0, 0.0));
+ if (orientation == FACE_X) {
+ points.push_back(Vector3(0.0, z, x) + center_offset);
+ } else if (orientation == FACE_Y) {
+ points.push_back(Vector3(-x, 0.0, -z) + center_offset);
+ } else if (orientation == FACE_Z) {
+ points.push_back(Vector3(-x, z, 0.0) + center_offset);
+ }
+ normals.push_back(normal);
ADD_TANGENT(1.0, 0.0, 0.0, 1.0);
uvs.push_back(Vector2(1.0 - u, 1.0 - v)); /* 1.0 - uv to match orientation with Quad */
point++;
@@ -1053,13 +1067,22 @@ void PlaneMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_subdivide_width"), &PlaneMesh::get_subdivide_width);
ClassDB::bind_method(D_METHOD("set_subdivide_depth", "subdivide"), &PlaneMesh::set_subdivide_depth);
ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &PlaneMesh::get_subdivide_depth);
+
ClassDB::bind_method(D_METHOD("set_center_offset", "offset"), &PlaneMesh::set_center_offset);
ClassDB::bind_method(D_METHOD("get_center_offset"), &PlaneMesh::get_center_offset);
+ ClassDB::bind_method(D_METHOD("set_orientation", "orientation"), &PlaneMesh::set_orientation);
+ ClassDB::bind_method(D_METHOD("get_orientation"), &PlaneMesh::get_orientation);
+
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "suffix:m"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_center_offset", "get_center_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "orientation", PROPERTY_HINT_ENUM, "Face X, Face Y, Face Z"), "set_orientation", "get_orientation");
+
+ BIND_ENUM_CONSTANT(FACE_X)
+ BIND_ENUM_CONSTANT(FACE_Y)
+ BIND_ENUM_CONSTANT(FACE_Z)
}
void PlaneMesh::set_size(const Size2 &p_size) {
@@ -1098,6 +1121,15 @@ Vector3 PlaneMesh::get_center_offset() const {
return center_offset;
}
+void PlaneMesh::set_orientation(const Orientation p_orientation) {
+ orientation = p_orientation;
+ _request_update();
+}
+
+PlaneMesh::Orientation PlaneMesh::get_orientation() const {
+ return orientation;
+}
+
PlaneMesh::PlaneMesh() {}
/**
@@ -1381,98 +1413,6 @@ int PrismMesh::get_subdivide_depth() const {
PrismMesh::PrismMesh() {}
/**
- QuadMesh
-*/
-
-void QuadMesh::_create_mesh_array(Array &p_arr) const {
- Vector<Vector3> faces;
- Vector<Vector3> normals;
- Vector<float> tangents;
- Vector<Vector2> uvs;
-
- faces.resize(6);
- normals.resize(6);
- tangents.resize(6 * 4);
- uvs.resize(6);
-
- Vector2 _size = Vector2(size.x / 2.0f, size.y / 2.0f);
-
- Vector3 quad_faces[4] = {
- Vector3(-_size.x, -_size.y, 0) + center_offset,
- Vector3(-_size.x, _size.y, 0) + center_offset,
- Vector3(_size.x, _size.y, 0) + center_offset,
- Vector3(_size.x, -_size.y, 0) + center_offset,
- };
-
- static const int indices[6] = {
- 0, 1, 2,
- 0, 2, 3
- };
-
- for (int i = 0; i < 6; i++) {
- int j = indices[i];
- faces.set(i, quad_faces[j]);
- normals.set(i, Vector3(0, 0, 1));
- tangents.set(i * 4 + 0, 1.0);
- tangents.set(i * 4 + 1, 0.0);
- tangents.set(i * 4 + 2, 0.0);
- tangents.set(i * 4 + 3, 1.0);
-
- static const Vector2 quad_uv[4] = {
- Vector2(0, 1),
- Vector2(0, 0),
- Vector2(1, 0),
- Vector2(1, 1),
- };
-
- uvs.set(i, quad_uv[j]);
- }
-
- p_arr[RS::ARRAY_VERTEX] = faces;
- p_arr[RS::ARRAY_NORMAL] = normals;
- p_arr[RS::ARRAY_TANGENT] = tangents;
- p_arr[RS::ARRAY_TEX_UV] = uvs;
-}
-
-void QuadMesh::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_size", "size"), &QuadMesh::set_size);
- ClassDB::bind_method(D_METHOD("get_size"), &QuadMesh::get_size);
- ClassDB::bind_method(D_METHOD("set_center_offset", "center_offset"), &QuadMesh::set_center_offset);
- ClassDB::bind_method(D_METHOD("get_center_offset"), &QuadMesh::get_center_offset);
-
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "suffix:m"), "set_size", "get_size");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset", PROPERTY_HINT_NONE, "suffix:m"), "set_center_offset", "get_center_offset");
-}
-
-uint32_t QuadMesh::surface_get_format(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, 1, 0);
-
- return RS::ARRAY_FORMAT_VERTEX | RS::ARRAY_FORMAT_NORMAL | RS::ARRAY_FORMAT_TANGENT | RS::ARRAY_FORMAT_TEX_UV;
-}
-
-QuadMesh::QuadMesh() {
- primitive_type = PRIMITIVE_TRIANGLES;
-}
-
-void QuadMesh::set_size(const Size2 &p_size) {
- size = p_size;
- _request_update();
-}
-
-Size2 QuadMesh::get_size() const {
- return size;
-}
-
-void QuadMesh::set_center_offset(Vector3 p_center_offset) {
- center_offset = p_center_offset;
- _request_update();
-}
-
-Vector3 QuadMesh::get_center_offset() const {
- return center_offset;
-}
-
-/**
SphereMesh
*/
@@ -1622,6 +1562,134 @@ bool SphereMesh::get_is_hemisphere() const {
SphereMesh::SphereMesh() {}
/**
+ TorusMesh
+*/
+
+void TorusMesh::_create_mesh_array(Array &p_arr) const {
+ // set our bounding box
+
+ Vector<Vector3> points;
+ Vector<Vector3> normals;
+ Vector<float> tangents;
+ Vector<Vector2> uvs;
+ Vector<int> indices;
+
+#define ADD_TANGENT(m_x, m_y, m_z, m_d) \
+ tangents.push_back(m_x); \
+ tangents.push_back(m_y); \
+ tangents.push_back(m_z); \
+ tangents.push_back(m_d);
+
+ ERR_FAIL_COND_MSG(inner_radius == outer_radius, "Inner radius and outer radius cannot be the same.");
+
+ float min_radius = inner_radius;
+ float max_radius = outer_radius;
+
+ if (min_radius > max_radius) {
+ SWAP(min_radius, max_radius);
+ }
+
+ float radius = (max_radius - min_radius) * 0.5;
+
+ for (int i = 0; i <= rings; i++) {
+ int prevrow = (i - 1) * (ring_segments + 1);
+ int thisrow = i * (ring_segments + 1);
+ float inci = float(i) / rings;
+ float angi = inci * Math_TAU;
+
+ Vector2 normali = Vector2(-Math::sin(angi), -Math::cos(angi));
+
+ for (int j = 0; j <= ring_segments; j++) {
+ float incj = float(j) / ring_segments;
+ float angj = incj * Math_TAU;
+
+ Vector2 normalj = Vector2(-Math::cos(angj), Math::sin(angj));
+ Vector2 normalk = normalj * radius + Vector2(min_radius + radius, 0);
+
+ points.push_back(Vector3(normali.x * normalk.x, normalk.y, normali.y * normalk.x));
+ normals.push_back(Vector3(normali.x * normalj.x, normalj.y, normali.y * normalj.x));
+ ADD_TANGENT(-Math::cos(angi), 0.0, Math::sin(angi), 1.0);
+ uvs.push_back(Vector2(inci, incj));
+
+ if (i > 0 && j > 0) {
+ indices.push_back(thisrow + j - 1);
+ indices.push_back(prevrow + j);
+ indices.push_back(prevrow + j - 1);
+
+ indices.push_back(thisrow + j - 1);
+ indices.push_back(thisrow + j);
+ indices.push_back(prevrow + j);
+ }
+ }
+ }
+
+ p_arr[RS::ARRAY_VERTEX] = points;
+ p_arr[RS::ARRAY_NORMAL] = normals;
+ p_arr[RS::ARRAY_TANGENT] = tangents;
+ p_arr[RS::ARRAY_TEX_UV] = uvs;
+ p_arr[RS::ARRAY_INDEX] = indices;
+}
+
+void TorusMesh::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_inner_radius", "radius"), &TorusMesh::set_inner_radius);
+ ClassDB::bind_method(D_METHOD("get_inner_radius"), &TorusMesh::get_inner_radius);
+
+ ClassDB::bind_method(D_METHOD("set_outer_radius", "radius"), &TorusMesh::set_outer_radius);
+ ClassDB::bind_method(D_METHOD("get_outer_radius"), &TorusMesh::get_outer_radius);
+
+ ClassDB::bind_method(D_METHOD("set_rings", "rings"), &TorusMesh::set_rings);
+ ClassDB::bind_method(D_METHOD("get_rings"), &TorusMesh::get_rings);
+
+ ClassDB::bind_method(D_METHOD("set_ring_segments", "rings"), &TorusMesh::set_ring_segments);
+ ClassDB::bind_method(D_METHOD("get_ring_segments"), &TorusMesh::get_ring_segments);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inner_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_inner_radius", "get_inner_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "outer_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_outer_radius", "get_outer_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "3,128,1"), "set_rings", "get_rings");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "ring_segments", PROPERTY_HINT_RANGE, "3,64,1"), "set_ring_segments", "get_ring_segments");
+}
+
+void TorusMesh::set_inner_radius(const float p_inner_radius) {
+ inner_radius = p_inner_radius;
+ _request_update();
+}
+
+float TorusMesh::get_inner_radius() const {
+ return inner_radius;
+}
+
+void TorusMesh::set_outer_radius(const float p_outer_radius) {
+ outer_radius = p_outer_radius;
+ _request_update();
+}
+
+float TorusMesh::get_outer_radius() const {
+ return outer_radius;
+}
+
+void TorusMesh::set_rings(const int p_rings) {
+ ERR_FAIL_COND(p_rings < 3);
+ rings = p_rings;
+ _request_update();
+}
+
+int TorusMesh::get_rings() const {
+ return rings;
+}
+
+void TorusMesh::set_ring_segments(const int p_ring_segments) {
+ ERR_FAIL_COND(p_ring_segments < 3);
+ ring_segments = p_ring_segments;
+ _request_update();
+}
+
+int TorusMesh::get_ring_segments() const {
+ return ring_segments;
+}
+
+TorusMesh::TorusMesh() {}
+
+/**
PointMesh
*/
@@ -2391,9 +2459,7 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
dirty_text = false;
dirty_font = false;
- if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) {
- TS->shaped_text_fit_to_width(text_rid, width, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA);
- }
+ dirty_lines = true;
} else if (dirty_font) {
int spans = TS->shaped_get_span_count(text_rid);
for (int i = 0; i < spans; i++) {
@@ -2404,81 +2470,138 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
}
dirty_font = false;
+ dirty_lines = true;
+ }
+
+ if (dirty_lines) {
+ for (int i = 0; i < lines_rid.size(); i++) {
+ TS->free_rid(lines_rid[i]);
+ }
+ lines_rid.clear();
+
+ BitField<TextServer::LineBreakFlag> autowrap_flags = TextServer::BREAK_MANDATORY;
+ switch (autowrap_mode) {
+ case TextServer::AUTOWRAP_WORD_SMART:
+ autowrap_flags = TextServer::BREAK_WORD_BOUND | TextServer::BREAK_ADAPTIVE | TextServer::BREAK_MANDATORY;
+ break;
+ case TextServer::AUTOWRAP_WORD:
+ autowrap_flags = TextServer::BREAK_WORD_BOUND | TextServer::BREAK_MANDATORY;
+ break;
+ case TextServer::AUTOWRAP_ARBITRARY:
+ autowrap_flags = TextServer::BREAK_GRAPHEME_BOUND | TextServer::BREAK_MANDATORY;
+ break;
+ case TextServer::AUTOWRAP_OFF:
+ break;
+ }
+ PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(text_rid, width, 0, autowrap_flags);
+
+ float max_line_w = 0.0;
+ for (int i = 0; i < line_breaks.size(); i = i + 2) {
+ RID line = TS->shaped_text_substr(text_rid, line_breaks[i], line_breaks[i + 1] - line_breaks[i]);
+ max_line_w = MAX(max_line_w, TS->shaped_text_get_width(line));
+ lines_rid.push_back(line);
+ }
+
if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) {
- TS->shaped_text_fit_to_width(text_rid, width, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA);
+ for (int i = 0; i < lines_rid.size() - 1; i++) {
+ TS->shaped_text_fit_to_width(lines_rid[i], (width > 0) ? width : max_line_w, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA);
+ }
}
+ dirty_lines = false;
+ }
+
+ float total_h = 0.0;
+ for (int i = 0; i < lines_rid.size(); i++) {
+ total_h += (TS->shaped_text_get_size(lines_rid[i]).y + line_spacing) * pixel_size;
}
- Vector2 offset;
- const Glyph *glyphs = TS->shaped_text_get_glyphs(text_rid);
- int gl_size = TS->shaped_text_get_glyph_count(text_rid);
- float line_width = TS->shaped_text_get_width(text_rid) * pixel_size;
-
- switch (horizontal_alignment) {
- case HORIZONTAL_ALIGNMENT_LEFT:
- offset.x = 0.0;
- break;
- case HORIZONTAL_ALIGNMENT_FILL:
- case HORIZONTAL_ALIGNMENT_CENTER: {
- offset.x = -line_width / 2.0;
+ float vbegin = 0.0;
+ switch (vertical_alignment) {
+ case VERTICAL_ALIGNMENT_FILL:
+ case VERTICAL_ALIGNMENT_TOP: {
+ // Nothing.
} break;
- case HORIZONTAL_ALIGNMENT_RIGHT: {
- offset.x = -line_width;
+ case VERTICAL_ALIGNMENT_CENTER: {
+ vbegin = (total_h - line_spacing * pixel_size) / 2.0;
+ } break;
+ case VERTICAL_ALIGNMENT_BOTTOM: {
+ vbegin = (total_h - line_spacing * pixel_size);
} break;
}
- bool has_depth = !Math::is_zero_approx(depth);
-
- // Generate glyph data, precalculate size of the arrays and mesh bounds for UV.
- int64_t p_size = 0;
- int64_t i_size = 0;
+ Vector<Vector3> vertices;
+ Vector<Vector3> normals;
+ Vector<float> tangents;
+ Vector<Vector2> uvs;
+ Vector<int32_t> indices;
Vector2 min_p = Vector2(INFINITY, INFINITY);
Vector2 max_p = Vector2(-INFINITY, -INFINITY);
- Vector2 offset_pre = offset;
- for (int i = 0; i < gl_size; i++) {
- if (glyphs[i].index == 0) {
- offset.x += glyphs[i].advance * pixel_size * glyphs[i].repeat;
- continue;
+ int32_t p_size = 0;
+ int32_t i_size = 0;
+
+ Vector2 offset = Vector2(0, vbegin + lbl_offset.y * pixel_size);
+ for (int i = 0; i < lines_rid.size(); i++) {
+ const Glyph *glyphs = TS->shaped_text_get_glyphs(lines_rid[i]);
+ int gl_size = TS->shaped_text_get_glyph_count(lines_rid[i]);
+ float line_width = TS->shaped_text_get_width(lines_rid[i]) * pixel_size;
+
+ switch (horizontal_alignment) {
+ case HORIZONTAL_ALIGNMENT_LEFT:
+ offset.x = 0.0;
+ break;
+ case HORIZONTAL_ALIGNMENT_FILL:
+ case HORIZONTAL_ALIGNMENT_CENTER: {
+ offset.x = -line_width / 2.0;
+ } break;
+ case HORIZONTAL_ALIGNMENT_RIGHT: {
+ offset.x = -line_width;
+ } break;
}
- if (glyphs[i].font_rid != RID()) {
- GlyphMeshKey key = GlyphMeshKey(glyphs[i].font_rid.get_id(), glyphs[i].index);
- _generate_glyph_mesh_data(key, glyphs[i]);
- GlyphMeshData &gl_data = cache[key];
-
- p_size += glyphs[i].repeat * gl_data.triangles.size() * ((has_depth) ? 2 : 1);
- i_size += glyphs[i].repeat * gl_data.triangles.size() * ((has_depth) ? 2 : 1);
-
- if (has_depth) {
- for (int j = 0; j < gl_data.contours.size(); j++) {
- p_size += glyphs[i].repeat * gl_data.contours[j].size() * 4;
- i_size += glyphs[i].repeat * gl_data.contours[j].size() * 6;
- }
- }
+ offset.x += lbl_offset.x * pixel_size;
+ offset.y -= TS->shaped_text_get_ascent(lines_rid[i]) * pixel_size;
- for (int j = 0; j < glyphs[i].repeat; j++) {
- min_p.x = MIN(gl_data.min_p.x + offset_pre.x, min_p.x);
- min_p.y = MIN(gl_data.min_p.y + offset_pre.y, min_p.y);
- max_p.x = MAX(gl_data.max_p.x + offset_pre.x, max_p.x);
- max_p.y = MAX(gl_data.max_p.y + offset_pre.y, max_p.y);
+ bool has_depth = !Math::is_zero_approx(depth);
- offset_pre.x += glyphs[i].advance * pixel_size;
+ for (int j = 0; j < gl_size; j++) {
+ if (glyphs[j].index == 0) {
+ offset.x += glyphs[j].advance * pixel_size * glyphs[j].repeat;
+ continue;
}
- } else {
- p_size += glyphs[i].repeat * 4;
- i_size += glyphs[i].repeat * 6;
+ if (glyphs[j].font_rid != RID()) {
+ GlyphMeshKey key = GlyphMeshKey(glyphs[j].font_rid.get_id(), glyphs[j].index);
+ _generate_glyph_mesh_data(key, glyphs[j]);
+ GlyphMeshData &gl_data = cache[key];
+
+ p_size += glyphs[j].repeat * gl_data.triangles.size() * ((has_depth) ? 2 : 1);
+ i_size += glyphs[j].repeat * gl_data.triangles.size() * ((has_depth) ? 2 : 1);
- offset_pre.x += glyphs[i].advance * pixel_size * glyphs[i].repeat;
+ if (has_depth) {
+ for (int k = 0; k < gl_data.contours.size(); k++) {
+ p_size += glyphs[j].repeat * gl_data.contours[k].size() * 4;
+ i_size += glyphs[j].repeat * gl_data.contours[k].size() * 6;
+ }
+ }
+
+ for (int r = 0; r < glyphs[j].repeat; r++) {
+ min_p.x = MIN(gl_data.min_p.x + offset.x, min_p.x);
+ min_p.y = MIN(gl_data.min_p.y - offset.y, min_p.y);
+ max_p.x = MAX(gl_data.max_p.x + offset.x, max_p.x);
+ max_p.y = MAX(gl_data.max_p.y - offset.y, max_p.y);
+
+ offset.x += glyphs[j].advance * pixel_size;
+ }
+ } else {
+ p_size += glyphs[j].repeat * 4;
+ i_size += glyphs[j].repeat * 6;
+
+ offset.x += glyphs[j].advance * pixel_size * glyphs[j].repeat;
+ }
}
+ offset.y -= (TS->shaped_text_get_descent(lines_rid[i]) + line_spacing) * pixel_size;
}
- Vector<Vector3> vertices;
- Vector<Vector3> normals;
- Vector<float> tangents;
- Vector<Vector2> uvs;
- Vector<int32_t> indices;
-
vertices.resize(p_size);
normals.resize(p_size);
uvs.resize(p_size);
@@ -2494,149 +2617,176 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
// Generate mesh.
int32_t p_idx = 0;
int32_t i_idx = 0;
- for (int i = 0; i < gl_size; i++) {
- if (glyphs[i].index == 0) {
- offset.x += glyphs[i].advance * pixel_size * glyphs[i].repeat;
- continue;
+
+ offset = Vector2(0, vbegin + lbl_offset.y * pixel_size);
+ for (int i = 0; i < lines_rid.size(); i++) {
+ const Glyph *glyphs = TS->shaped_text_get_glyphs(lines_rid[i]);
+ int gl_size = TS->shaped_text_get_glyph_count(lines_rid[i]);
+ float line_width = TS->shaped_text_get_width(lines_rid[i]) * pixel_size;
+
+ switch (horizontal_alignment) {
+ case HORIZONTAL_ALIGNMENT_LEFT:
+ offset.x = 0.0;
+ break;
+ case HORIZONTAL_ALIGNMENT_FILL:
+ case HORIZONTAL_ALIGNMENT_CENTER: {
+ offset.x = -line_width / 2.0;
+ } break;
+ case HORIZONTAL_ALIGNMENT_RIGHT: {
+ offset.x = -line_width;
+ } break;
}
- if (glyphs[i].font_rid != RID()) {
- GlyphMeshKey key = GlyphMeshKey(glyphs[i].font_rid.get_id(), glyphs[i].index);
- _generate_glyph_mesh_data(key, glyphs[i]);
- const GlyphMeshData &gl_data = cache[key];
-
- int64_t ts = gl_data.triangles.size();
- const Vector2 *ts_ptr = gl_data.triangles.ptr();
-
- for (int j = 0; j < glyphs[i].repeat; j++) {
- for (int k = 0; k < ts; k += 3) {
- // Add front face.
- for (int l = 0; l < 3; l++) {
- Vector3 point = Vector3(ts_ptr[k + l].x + offset.x, -ts_ptr[k + l].y + offset.y, depth / 2.0);
- vertices_ptr[p_idx] = point;
- normals_ptr[p_idx] = Vector3(0.0, 0.0, 1.0);
- if (has_depth) {
- uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -min_p.y, -max_p.y, real_t(0.0), real_t(0.4)));
- } else {
- uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -min_p.y, -max_p.y, real_t(0.0), real_t(1.0)));
- }
- tangents_ptr[p_idx * 4 + 0] = 1.0;
- tangents_ptr[p_idx * 4 + 1] = 0.0;
- tangents_ptr[p_idx * 4 + 2] = 0.0;
- tangents_ptr[p_idx * 4 + 3] = 1.0;
- indices_ptr[i_idx++] = p_idx;
- p_idx++;
- }
- if (has_depth) {
- // Add back face.
- for (int l = 2; l >= 0; l--) {
- Vector3 point = Vector3(ts_ptr[k + l].x + offset.x, -ts_ptr[k + l].y + offset.y, -depth / 2.0);
+ offset.x += lbl_offset.x * pixel_size;
+ offset.y -= TS->shaped_text_get_ascent(lines_rid[i]) * pixel_size;
+
+ bool has_depth = !Math::is_zero_approx(depth);
+
+ // Generate glyph data, precalculate size of the arrays and mesh bounds for UV.
+ for (int j = 0; j < gl_size; j++) {
+ if (glyphs[j].index == 0) {
+ offset.x += glyphs[j].advance * pixel_size * glyphs[j].repeat;
+ continue;
+ }
+ if (glyphs[j].font_rid != RID()) {
+ GlyphMeshKey key = GlyphMeshKey(glyphs[j].font_rid.get_id(), glyphs[j].index);
+ _generate_glyph_mesh_data(key, glyphs[j]);
+ const GlyphMeshData &gl_data = cache[key];
+
+ int64_t ts = gl_data.triangles.size();
+ const Vector2 *ts_ptr = gl_data.triangles.ptr();
+
+ for (int r = 0; r < glyphs[j].repeat; r++) {
+ for (int k = 0; k < ts; k += 3) {
+ // Add front face.
+ for (int l = 0; l < 3; l++) {
+ Vector3 point = Vector3(ts_ptr[k + l].x + offset.x, -ts_ptr[k + l].y + offset.y, depth / 2.0);
vertices_ptr[p_idx] = point;
- normals_ptr[p_idx] = Vector3(0.0, 0.0, -1.0);
- uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -min_p.y, -max_p.y, real_t(0.4), real_t(0.8)));
- tangents_ptr[p_idx * 4 + 0] = -1.0;
+ normals_ptr[p_idx] = Vector3(0.0, 0.0, 1.0);
+ if (has_depth) {
+ uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -max_p.y, -min_p.y, real_t(0.4), real_t(0.0)));
+ } else {
+ uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -max_p.y, -min_p.y, real_t(1.0), real_t(0.0)));
+ }
+ tangents_ptr[p_idx * 4 + 0] = 1.0;
tangents_ptr[p_idx * 4 + 1] = 0.0;
tangents_ptr[p_idx * 4 + 2] = 0.0;
tangents_ptr[p_idx * 4 + 3] = 1.0;
indices_ptr[i_idx++] = p_idx;
p_idx++;
}
- }
- }
- // Add sides.
- if (has_depth) {
- for (int k = 0; k < gl_data.contours.size(); k++) {
- int64_t ps = gl_data.contours[k].size();
- const ContourPoint *ps_ptr = gl_data.contours[k].ptr();
- const ContourInfo &ps_info = gl_data.contours_info[k];
- real_t length = 0.0;
- for (int l = 0; l < ps; l++) {
- int prev = (l == 0) ? (ps - 1) : (l - 1);
- int next = (l + 1 == ps) ? 0 : (l + 1);
- Vector2 d1;
- Vector2 d2 = (ps_ptr[next].point - ps_ptr[l].point).normalized();
- if (ps_ptr[l].sharp) {
- d1 = d2;
- } else {
- d1 = (ps_ptr[l].point - ps_ptr[prev].point).normalized();
+ if (has_depth) {
+ // Add back face.
+ for (int l = 2; l >= 0; l--) {
+ Vector3 point = Vector3(ts_ptr[k + l].x + offset.x, -ts_ptr[k + l].y + offset.y, -depth / 2.0);
+ vertices_ptr[p_idx] = point;
+ normals_ptr[p_idx] = Vector3(0.0, 0.0, -1.0);
+ uvs_ptr[p_idx] = Vector2(Math::range_lerp(point.x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(point.y, -max_p.y, -min_p.y, real_t(0.8), real_t(0.4)));
+ tangents_ptr[p_idx * 4 + 0] = -1.0;
+ tangents_ptr[p_idx * 4 + 1] = 0.0;
+ tangents_ptr[p_idx * 4 + 2] = 0.0;
+ tangents_ptr[p_idx * 4 + 3] = 1.0;
+ indices_ptr[i_idx++] = p_idx;
+ p_idx++;
}
- real_t seg_len = (ps_ptr[next].point - ps_ptr[l].point).length();
-
- Vector3 quad_faces[4] = {
- Vector3(ps_ptr[l].point.x + offset.x, -ps_ptr[l].point.y + offset.y, -depth / 2.0),
- Vector3(ps_ptr[next].point.x + offset.x, -ps_ptr[next].point.y + offset.y, -depth / 2.0),
- Vector3(ps_ptr[l].point.x + offset.x, -ps_ptr[l].point.y + offset.y, depth / 2.0),
- Vector3(ps_ptr[next].point.x + offset.x, -ps_ptr[next].point.y + offset.y, depth / 2.0),
- };
- for (int m = 0; m < 4; m++) {
- const Vector2 &d = ((m % 2) == 0) ? d1 : d2;
- real_t u_pos = ((m % 2) == 0) ? length : length + seg_len;
- vertices_ptr[p_idx + m] = quad_faces[m];
- normals_ptr[p_idx + m] = Vector3(d.y, d.x, 0.0);
- if (m < 2) {
- uvs_ptr[p_idx + m] = Vector2(Math::range_lerp(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.8 : 0.9);
+ }
+ }
+ // Add sides.
+ if (has_depth) {
+ for (int k = 0; k < gl_data.contours.size(); k++) {
+ int64_t ps = gl_data.contours[k].size();
+ const ContourPoint *ps_ptr = gl_data.contours[k].ptr();
+ const ContourInfo &ps_info = gl_data.contours_info[k];
+ real_t length = 0.0;
+ for (int l = 0; l < ps; l++) {
+ int prev = (l == 0) ? (ps - 1) : (l - 1);
+ int next = (l + 1 == ps) ? 0 : (l + 1);
+ Vector2 d1;
+ Vector2 d2 = (ps_ptr[next].point - ps_ptr[l].point).normalized();
+ if (ps_ptr[l].sharp) {
+ d1 = d2;
} else {
- uvs_ptr[p_idx + m] = Vector2(Math::range_lerp(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.9 : 1.0);
+ d1 = (ps_ptr[l].point - ps_ptr[prev].point).normalized();
+ }
+ real_t seg_len = (ps_ptr[next].point - ps_ptr[l].point).length();
+
+ Vector3 quad_faces[4] = {
+ Vector3(ps_ptr[l].point.x + offset.x, -ps_ptr[l].point.y + offset.y, -depth / 2.0),
+ Vector3(ps_ptr[next].point.x + offset.x, -ps_ptr[next].point.y + offset.y, -depth / 2.0),
+ Vector3(ps_ptr[l].point.x + offset.x, -ps_ptr[l].point.y + offset.y, depth / 2.0),
+ Vector3(ps_ptr[next].point.x + offset.x, -ps_ptr[next].point.y + offset.y, depth / 2.0),
+ };
+ for (int m = 0; m < 4; m++) {
+ const Vector2 &d = ((m % 2) == 0) ? d1 : d2;
+ real_t u_pos = ((m % 2) == 0) ? length : length + seg_len;
+ vertices_ptr[p_idx + m] = quad_faces[m];
+ normals_ptr[p_idx + m] = Vector3(d.y, d.x, 0.0);
+ if (m < 2) {
+ uvs_ptr[p_idx + m] = Vector2(Math::range_lerp(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.8 : 0.9);
+ } else {
+ uvs_ptr[p_idx + m] = Vector2(Math::range_lerp(u_pos, 0, ps_info.length, real_t(0.0), real_t(1.0)), (ps_info.ccw) ? 0.9 : 1.0);
+ }
+ tangents_ptr[(p_idx + m) * 4 + 0] = d.x;
+ tangents_ptr[(p_idx + m) * 4 + 1] = -d.y;
+ tangents_ptr[(p_idx + m) * 4 + 2] = 0.0;
+ tangents_ptr[(p_idx + m) * 4 + 3] = 1.0;
}
- tangents_ptr[(p_idx + m) * 4 + 0] = d.x;
- tangents_ptr[(p_idx + m) * 4 + 1] = -d.y;
- tangents_ptr[(p_idx + m) * 4 + 2] = 0.0;
- tangents_ptr[(p_idx + m) * 4 + 3] = 1.0;
- }
- indices_ptr[i_idx++] = p_idx;
- indices_ptr[i_idx++] = p_idx + 1;
- indices_ptr[i_idx++] = p_idx + 2;
+ indices_ptr[i_idx++] = p_idx;
+ indices_ptr[i_idx++] = p_idx + 1;
+ indices_ptr[i_idx++] = p_idx + 2;
- indices_ptr[i_idx++] = p_idx + 1;
- indices_ptr[i_idx++] = p_idx + 3;
- indices_ptr[i_idx++] = p_idx + 2;
+ indices_ptr[i_idx++] = p_idx + 1;
+ indices_ptr[i_idx++] = p_idx + 3;
+ indices_ptr[i_idx++] = p_idx + 2;
- length += seg_len;
- p_idx += 4;
+ length += seg_len;
+ p_idx += 4;
+ }
}
}
+ offset.x += glyphs[j].advance * pixel_size;
}
- offset.x += glyphs[i].advance * pixel_size;
- }
- } else {
- // Add fallback quad for missing glyphs.
- for (int j = 0; j < glyphs[i].repeat; j++) {
- Size2 sz = TS->get_hex_code_box_size(glyphs[i].font_size, glyphs[i].index) * pixel_size;
- Vector3 quad_faces[4] = {
- Vector3(offset.x, offset.y, 0.0),
- Vector3(offset.x, sz.y + offset.y, 0.0),
- Vector3(sz.x + offset.x, sz.y + offset.y, 0.0),
- Vector3(sz.x + offset.x, offset.y, 0.0),
- };
- for (int k = 0; k < 4; k++) {
- vertices_ptr[p_idx + k] = quad_faces[k];
- normals_ptr[p_idx + k] = Vector3(0.0, 0.0, 1.0);
- if (has_depth) {
- uvs_ptr[p_idx + k] = Vector2(Math::range_lerp(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(quad_faces[k].y, -min_p.y, -max_p.y, real_t(0.0), real_t(0.4)));
- } else {
- uvs_ptr[p_idx + k] = Vector2(Math::range_lerp(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(quad_faces[k].y, -min_p.y, -max_p.y, real_t(0.0), real_t(1.0)));
+ } else {
+ // Add fallback quad for missing glyphs.
+ for (int r = 0; r < glyphs[j].repeat; r++) {
+ Size2 sz = TS->get_hex_code_box_size(glyphs[j].font_size, glyphs[j].index) * pixel_size;
+ Vector3 quad_faces[4] = {
+ Vector3(offset.x, offset.y, 0.0),
+ Vector3(offset.x, sz.y + offset.y, 0.0),
+ Vector3(sz.x + offset.x, sz.y + offset.y, 0.0),
+ Vector3(sz.x + offset.x, offset.y, 0.0),
+ };
+ for (int k = 0; k < 4; k++) {
+ vertices_ptr[p_idx + k] = quad_faces[k];
+ normals_ptr[p_idx + k] = Vector3(0.0, 0.0, 1.0);
+ if (has_depth) {
+ uvs_ptr[p_idx + k] = Vector2(Math::range_lerp(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(quad_faces[k].y, -max_p.y, -min_p.y, real_t(0.4), real_t(0.0)));
+ } else {
+ uvs_ptr[p_idx + k] = Vector2(Math::range_lerp(quad_faces[k].x, min_p.x, max_p.x, real_t(0.0), real_t(1.0)), Math::range_lerp(quad_faces[k].y, -max_p.y, -min_p.y, real_t(1.0), real_t(0.0)));
+ }
+ tangents_ptr[(p_idx + k) * 4 + 0] = 1.0;
+ tangents_ptr[(p_idx + k) * 4 + 1] = 0.0;
+ tangents_ptr[(p_idx + k) * 4 + 2] = 0.0;
+ tangents_ptr[(p_idx + k) * 4 + 3] = 1.0;
}
- tangents_ptr[(p_idx + k) * 4 + 0] = 1.0;
- tangents_ptr[(p_idx + k) * 4 + 1] = 0.0;
- tangents_ptr[(p_idx + k) * 4 + 2] = 0.0;
- tangents_ptr[(p_idx + k) * 4 + 3] = 1.0;
- }
- indices_ptr[i_idx++] = p_idx;
- indices_ptr[i_idx++] = p_idx + 1;
- indices_ptr[i_idx++] = p_idx + 2;
+ indices_ptr[i_idx++] = p_idx;
+ indices_ptr[i_idx++] = p_idx + 1;
+ indices_ptr[i_idx++] = p_idx + 2;
- indices_ptr[i_idx++] = p_idx + 0;
- indices_ptr[i_idx++] = p_idx + 2;
- indices_ptr[i_idx++] = p_idx + 3;
- p_idx += 4;
+ indices_ptr[i_idx++] = p_idx + 0;
+ indices_ptr[i_idx++] = p_idx + 2;
+ indices_ptr[i_idx++] = p_idx + 3;
+ p_idx += 4;
- offset.x += glyphs[i].advance * pixel_size;
+ offset.x += glyphs[j].advance * pixel_size;
+ }
}
}
+ offset.y -= (TS->shaped_text_get_descent(lines_rid[i]) + line_spacing) * pixel_size;
}
- if (p_size == 0) {
+ if (indices.is_empty()) {
// If empty, add single triangle to suppress errors.
vertices.push_back(Vector3());
normals.push_back(Vector3());
@@ -2661,6 +2811,9 @@ void TextMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_horizontal_alignment", "alignment"), &TextMesh::set_horizontal_alignment);
ClassDB::bind_method(D_METHOD("get_horizontal_alignment"), &TextMesh::get_horizontal_alignment);
+ ClassDB::bind_method(D_METHOD("set_vertical_alignment", "alignment"), &TextMesh::set_vertical_alignment);
+ ClassDB::bind_method(D_METHOD("get_vertical_alignment"), &TextMesh::get_vertical_alignment);
+
ClassDB::bind_method(D_METHOD("set_text", "text"), &TextMesh::set_text);
ClassDB::bind_method(D_METHOD("get_text"), &TextMesh::get_text);
@@ -2670,6 +2823,12 @@ void TextMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_font_size", "font_size"), &TextMesh::set_font_size);
ClassDB::bind_method(D_METHOD("get_font_size"), &TextMesh::get_font_size);
+ ClassDB::bind_method(D_METHOD("set_line_spacing", "line_spacing"), &TextMesh::set_line_spacing);
+ ClassDB::bind_method(D_METHOD("get_line_spacing"), &TextMesh::get_line_spacing);
+
+ ClassDB::bind_method(D_METHOD("set_autowrap_mode", "autowrap_mode"), &TextMesh::set_autowrap_mode);
+ ClassDB::bind_method(D_METHOD("get_autowrap_mode"), &TextMesh::get_autowrap_mode);
+
ClassDB::bind_method(D_METHOD("set_depth", "depth"), &TextMesh::set_depth);
ClassDB::bind_method(D_METHOD("get_depth"), &TextMesh::get_depth);
@@ -2679,6 +2838,9 @@ void TextMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pixel_size", "pixel_size"), &TextMesh::set_pixel_size);
ClassDB::bind_method(D_METHOD("get_pixel_size"), &TextMesh::get_pixel_size);
+ ClassDB::bind_method(D_METHOD("set_offset", "offset"), &TextMesh::set_offset);
+ ClassDB::bind_method(D_METHOD("get_offset"), &TextMesh::get_offset);
+
ClassDB::bind_method(D_METHOD("set_curve_step", "curve_step"), &TextMesh::set_curve_step);
ClassDB::bind_method(D_METHOD("get_curve_step"), &TextMesh::get_curve_step);
@@ -2701,17 +2863,21 @@ void TextMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("_request_update"), &TextMesh::_request_update);
ADD_GROUP("Text", "");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT, ""), "set_text", "get_text");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_font", "get_font");
ADD_PROPERTY(PropertyInfo(Variant::INT, "font_size", PROPERTY_HINT_RANGE, "1,256,1,or_greater,suffix:px"), "set_font_size", "get_font_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "horizontal_alignment", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_horizontal_alignment", "get_horizontal_alignment");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "vertical_alignment", PROPERTY_HINT_ENUM, "Top,Center,Bottom"), "set_vertical_alignment", "get_vertical_alignment");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uppercase"), "set_uppercase", "is_uppercase");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "line_spacing", PROPERTY_HINT_NONE, "suffix:px"), "set_line_spacing", "get_line_spacing");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "autowrap_mode", PROPERTY_HINT_ENUM, "Off,Arbitrary,Word,Word (Smart)"), "set_autowrap_mode", "get_autowrap_mode");
ADD_GROUP("Mesh", "");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pixel_size", PROPERTY_HINT_RANGE, "0.0001,128,0.0001,suffix:m"), "set_pixel_size", "get_pixel_size");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "curve_step", PROPERTY_HINT_RANGE, "0.1,10,0.1,suffix:px"), "set_curve_step", "get_curve_step");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth", PROPERTY_HINT_RANGE, "0.0,100.0,0.001,or_greater,suffix:m"), "set_depth", "get_depth");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "width", PROPERTY_HINT_NONE, "suffix:m"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset", PROPERTY_HINT_NONE, "suffix:px"), "set_offset", "get_offset");
ADD_GROUP("BiDi", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left"), "set_text_direction", "get_text_direction");
@@ -2740,6 +2906,11 @@ TextMesh::TextMesh() {
}
TextMesh::~TextMesh() {
+ for (int i = 0; i < lines_rid.size(); i++) {
+ TS->free_rid(lines_rid[i]);
+ }
+ lines_rid.clear();
+
TS->free_rid(text_rid);
}
@@ -2747,7 +2918,7 @@ void TextMesh::set_horizontal_alignment(HorizontalAlignment p_alignment) {
ERR_FAIL_INDEX((int)p_alignment, 4);
if (horizontal_alignment != p_alignment) {
if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL || p_alignment == HORIZONTAL_ALIGNMENT_FILL) {
- dirty_text = true;
+ dirty_lines = true;
}
horizontal_alignment = p_alignment;
_request_update();
@@ -2758,6 +2929,18 @@ HorizontalAlignment TextMesh::get_horizontal_alignment() const {
return horizontal_alignment;
}
+void TextMesh::set_vertical_alignment(VerticalAlignment p_alignment) {
+ ERR_FAIL_INDEX((int)p_alignment, 4);
+ if (vertical_alignment != p_alignment) {
+ vertical_alignment = p_alignment;
+ _request_update();
+ }
+}
+
+VerticalAlignment TextMesh::get_vertical_alignment() const {
+ return vertical_alignment;
+}
+
void TextMesh::set_text(const String &p_string) {
if (text != p_string) {
text = p_string;
@@ -2802,13 +2985,13 @@ Ref<Font> TextMesh::_get_font_or_default() const {
}
// Check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
List<StringName> theme_types;
- Theme::get_project_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
+ ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
for (const StringName &E : theme_types) {
- if (Theme::get_project_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
- return Theme::get_project_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ return ThemeDB::get_singleton()->get_project_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
}
}
}
@@ -2816,17 +2999,17 @@ Ref<Font> TextMesh::_get_font_or_default() const {
// Lastly, fall back on the items defined in the default Theme, if they exist.
{
List<StringName> theme_types;
- Theme::get_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
for (const StringName &E : theme_types) {
- if (Theme::get_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
- return Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
}
}
}
// If they don't exist, use any type to return the default/empty value.
- return Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
+ return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
}
void TextMesh::set_font_size(int p_size) {
@@ -2842,6 +3025,29 @@ int TextMesh::get_font_size() const {
return font_size;
}
+void TextMesh::set_line_spacing(float p_line_spacing) {
+ if (line_spacing != p_line_spacing) {
+ line_spacing = p_line_spacing;
+ _request_update();
+ }
+}
+
+float TextMesh::get_line_spacing() const {
+ return line_spacing;
+}
+
+void TextMesh::set_autowrap_mode(TextServer::AutowrapMode p_mode) {
+ if (autowrap_mode != p_mode) {
+ autowrap_mode = p_mode;
+ dirty_lines = true;
+ _request_update();
+ }
+}
+
+TextServer::AutowrapMode TextMesh::get_autowrap_mode() const {
+ return autowrap_mode;
+}
+
void TextMesh::set_depth(real_t p_depth) {
if (depth != p_depth) {
depth = MAX(p_depth, 0.0);
@@ -2856,9 +3062,7 @@ real_t TextMesh::get_depth() const {
void TextMesh::set_width(real_t p_width) {
if (width != p_width) {
width = p_width;
- if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) {
- dirty_text = true;
- }
+ dirty_lines = true;
_request_update();
}
}
@@ -2879,6 +3083,17 @@ real_t TextMesh::get_pixel_size() const {
return pixel_size;
}
+void TextMesh::set_offset(const Point2 &p_offset) {
+ if (lbl_offset != p_offset) {
+ lbl_offset = p_offset;
+ _request_update();
+ }
+}
+
+Point2 TextMesh::get_offset() const {
+ return lbl_offset;
+}
+
void TextMesh::set_curve_step(real_t p_step) {
if (curve_step != p_step) {
curve_step = CLAMP(p_step, 0.1, 10.0);
diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h
index ec124e379f..280477ebfa 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -75,7 +75,7 @@ public:
virtual int surface_get_array_len(int p_idx) const override;
virtual int surface_get_array_index_len(int p_idx) const override;
virtual Array surface_get_arrays(int p_surface) const override;
- virtual Array surface_get_blend_shape_arrays(int p_surface) const override;
+ virtual TypedArray<Array> surface_get_blend_shape_arrays(int p_surface) const override;
virtual Dictionary surface_get_lods(int p_surface) const override;
virtual uint32_t surface_get_format(int p_idx) const override;
virtual Mesh::PrimitiveType surface_get_primitive_type(int p_idx) const override;
@@ -217,17 +217,25 @@ public:
CylinderMesh();
};
-/**
- Similar to quadmesh but with tessellation support
+/*
+ A flat rectangle, can be used as quad or heightmap.
*/
class PlaneMesh : public PrimitiveMesh {
GDCLASS(PlaneMesh, PrimitiveMesh);
+public:
+ enum Orientation {
+ FACE_X,
+ FACE_Y,
+ FACE_Z,
+ };
+
private:
Size2 size = Size2(2.0, 2.0);
int subdivide_w = 0;
int subdivide_d = 0;
Vector3 center_offset;
+ Orientation orientation = FACE_Y;
protected:
static void _bind_methods();
@@ -246,9 +254,14 @@ public:
void set_center_offset(const Vector3 p_offset);
Vector3 get_center_offset() const;
+ void set_orientation(const Orientation p_orientation);
+ Orientation get_orientation() const;
+
PlaneMesh();
};
+VARIANT_ENUM_CAST(PlaneMesh::Orientation)
+
/**
A prism shapen, handy for ramps, triangles, etc.
*/
@@ -286,33 +299,6 @@ public:
};
/**
- Our original quadmesh...
-*/
-
-class QuadMesh : public PrimitiveMesh {
- GDCLASS(QuadMesh, PrimitiveMesh);
-
-private:
- Size2 size = Size2(1.0, 1.0);
- Vector3 center_offset;
-
-protected:
- static void _bind_methods();
- virtual void _create_mesh_array(Array &p_arr) const override;
-
-public:
- virtual uint32_t surface_get_format(int p_idx) const override;
-
- QuadMesh();
-
- void set_size(const Size2 &p_size);
- Size2 get_size() const;
-
- void set_center_offset(const Vector3 p_offset);
- Vector3 get_center_offset() const;
-};
-
-/**
A sphere..
*/
class SphereMesh : public PrimitiveMesh {
@@ -351,6 +337,38 @@ public:
};
/**
+ Big donut
+*/
+class TorusMesh : public PrimitiveMesh {
+ GDCLASS(TorusMesh, PrimitiveMesh);
+
+private:
+ float inner_radius = 0.5;
+ float outer_radius = 1.0;
+ int rings = 64;
+ int ring_segments = 32;
+
+protected:
+ static void _bind_methods();
+ virtual void _create_mesh_array(Array &p_arr) const override;
+
+public:
+ void set_inner_radius(const float p_inner_radius);
+ float get_inner_radius() const;
+
+ void set_outer_radius(const float p_outer_radius);
+ float get_outer_radius() const;
+
+ void set_rings(const int p_rings);
+ int get_rings() const;
+
+ void set_ring_segments(const int p_ring_segments);
+ int get_ring_segments() const;
+
+ TorusMesh();
+};
+
+/**
A single point for use in particle systems
*/
@@ -516,14 +534,21 @@ private:
mutable HashMap<GlyphMeshKey, GlyphMeshData, GlyphMeshKeyHasher> cache;
RID text_rid;
+ mutable Vector<RID> lines_rid;
+
String text;
String xl_text;
int font_size = 16;
Ref<Font> font_override;
+
+ TextServer::AutowrapMode autowrap_mode = TextServer::AUTOWRAP_OFF;
float width = 500.0;
+ float line_spacing = 0.f;
+ Point2 lbl_offset;
HorizontalAlignment horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER;
+ VerticalAlignment vertical_alignment = VERTICAL_ALIGNMENT_CENTER;
bool uppercase = false;
String language;
TextServer::Direction text_direction = TextServer::DIRECTION_AUTO;
@@ -534,6 +559,7 @@ private:
real_t pixel_size = 0.01;
real_t curve_step = 0.5;
+ mutable bool dirty_lines = true;
mutable bool dirty_text = true;
mutable bool dirty_font = true;
mutable bool dirty_cache = true;
@@ -556,6 +582,9 @@ public:
void set_horizontal_alignment(HorizontalAlignment p_alignment);
HorizontalAlignment get_horizontal_alignment() const;
+ void set_vertical_alignment(VerticalAlignment p_alignment);
+ VerticalAlignment get_vertical_alignment() const;
+
void set_text(const String &p_string);
String get_text() const;
@@ -566,6 +595,12 @@ public:
void set_font_size(int p_size);
int get_font_size() const;
+ void set_line_spacing(float p_size);
+ float get_line_spacing() const;
+
+ void set_autowrap_mode(TextServer::AutowrapMode p_mode);
+ TextServer::AutowrapMode get_autowrap_mode() const;
+
void set_text_direction(TextServer::Direction p_text_direction);
TextServer::Direction get_text_direction() const;
@@ -592,6 +627,9 @@ public:
void set_pixel_size(real_t p_amount);
real_t get_pixel_size() const;
+
+ void set_offset(const Point2 &p_offset);
+ Point2 get_offset() const;
};
VARIANT_ENUM_CAST(RibbonTrailMesh::Shape)
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 2b1d91e4ef..0d798d2e27 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -451,7 +451,7 @@ Error ResourceLoaderText::load() {
if (!path.contains("://") && path.is_relative_path()) {
// path is relative to file being loaded, so convert to a resource path
- path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path));
+ path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().path_join(path));
}
if (remaps.has(path)) {
@@ -861,7 +861,7 @@ void ResourceLoaderText::get_dependencies(Ref<FileAccess> p_f, List<String> *p_d
if (!using_uid && !path.contains("://") && path.is_relative_path()) {
// path is relative to file being loaded, so convert to a resource path
- path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path));
+ path = ProjectSettings::get_singleton()->localize_path(local_path.get_base_dir().path_join(path));
}
if (p_add_types) {
@@ -938,7 +938,7 @@ Error ResourceLoaderText::rename_dependencies(Ref<FileAccess> p_f, const String
}
bool relative = false;
if (!path.begins_with("res://")) {
- path = base_path.plus_file(path).simplify_path();
+ path = base_path.path_join(path).simplify_path();
relative = true;
}
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 18fd6c8d25..48d06934e3 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -82,7 +82,7 @@ void Shader::set_code(const String &p_code) {
// 1) Need to keep track of include dependencies at resource level
// 2) Server does not do interaction with Resource filetypes, this is a scene level feature.
ShaderPreprocessor preprocessor;
- preprocessor.preprocess(p_code, pp_code, nullptr, nullptr, &new_include_dependencies);
+ preprocessor.preprocess(p_code, "", pp_code, nullptr, nullptr, nullptr, &new_include_dependencies);
}
// This ensures previous include resources are not freed and then re-loaded during parse (which would make compiling slower)
@@ -103,11 +103,11 @@ String Shader::get_code() const {
return code;
}
-void Shader::get_param_list(List<PropertyInfo> *p_params, bool p_get_groups) const {
+void Shader::get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_groups) const {
_update_shader();
List<PropertyInfo> local;
- RenderingServer::get_singleton()->shader_get_param_list(shader, &local);
+ RenderingServer::get_singleton()->shader_get_shader_uniform_list(shader, &local);
params_cache.clear();
params_cache_dirty = false;
@@ -176,8 +176,8 @@ bool Shader::is_text_shader() const {
return true;
}
-bool Shader::has_param(const StringName &p_param) const {
- return params_cache.has("shader_param/" + p_param);
+bool Shader::has_uniform(const StringName &p_param) const {
+ return params_cache.has("shader_uniform/" + p_param);
}
void Shader::_update_shader() const {
@@ -192,7 +192,7 @@ void Shader::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_default_texture_param", "param", "texture", "index"), &Shader::set_default_texture_param, DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_default_texture_param", "param", "index"), &Shader::get_default_texture_param, DEFVAL(0));
- ClassDB::bind_method(D_METHOD("has_param", "name"), &Shader::has_param);
+ ClassDB::bind_method(D_METHOD("has_uniform", "name"), &Shader::has_uniform);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "code", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_code", "get_code");
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index 082b37d355..abc953de5f 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -78,21 +78,21 @@ public:
void set_code(const String &p_code);
String get_code() const;
- void get_param_list(List<PropertyInfo> *p_params, bool p_get_groups = false) const;
- bool has_param(const StringName &p_param) const;
+ void get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_groups = false) const;
+ bool has_uniform(const StringName &p_param) const;
- void set_default_texture_param(const StringName &p_param, const Ref<Texture2D> &p_texture, int p_index = 0);
- Ref<Texture2D> get_default_texture_param(const StringName &p_param, int p_index = 0) const;
+ void set_default_texture_param(const StringName &p_uniform, const Ref<Texture2D> &p_texture, int p_index = 0);
+ Ref<Texture2D> get_default_texture_param(const StringName &p_uniform, int p_index = 0) const;
void get_default_texture_param_list(List<StringName> *r_textures) const;
virtual bool is_text_shader() const;
- _FORCE_INLINE_ StringName remap_param(const StringName &p_param) const {
+ _FORCE_INLINE_ StringName remap_uniform(const StringName &p_uniform) const {
if (params_cache_dirty) {
- get_param_list(nullptr);
+ get_shader_uniform_list(nullptr);
}
- const HashMap<StringName, StringName>::Iterator E = params_cache.find(p_param);
+ const HashMap<StringName, StringName>::Iterator E = params_cache.find(p_uniform);
if (E) {
return E->value;
}
diff --git a/scene/resources/shader_include.cpp b/scene/resources/shader_include.cpp
index 42435fe3c7..fe628dd323 100644
--- a/scene/resources/shader_include.cpp
+++ b/scene/resources/shader_include.cpp
@@ -47,7 +47,7 @@ void ShaderInclude::set_code(const String &p_code) {
{
String pp_code;
ShaderPreprocessor preprocessor;
- preprocessor.preprocess(p_code, pp_code, nullptr, nullptr, &new_dependencies);
+ preprocessor.preprocess(p_code, "", pp_code, nullptr, nullptr, nullptr, &new_dependencies);
}
// This ensures previous include resources are not freed and then re-loaded during parse (which would make compiling slower)
diff --git a/scene/resources/shape_2d.cpp b/scene/resources/shape_2d.cpp
index 16ef45829f..fe43f345d4 100644
--- a/scene/resources/shape_2d.cpp
+++ b/scene/resources/shape_2d.cpp
@@ -59,39 +59,39 @@ bool Shape2D::collide(const Transform2D &p_local_xform, const Ref<Shape2D> &p_sh
return PhysicsServer2D::get_singleton()->shape_collide(get_rid(), p_local_xform, Vector2(), p_shape->get_rid(), p_shape_xform, Vector2(), nullptr, 0, r);
}
-Array Shape2D::collide_with_motion_and_get_contacts(const Transform2D &p_local_xform, const Vector2 &p_local_motion, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform, const Vector2 &p_shape_motion) {
- ERR_FAIL_COND_V(p_shape.is_null(), Array());
+PackedVector2Array Shape2D::collide_with_motion_and_get_contacts(const Transform2D &p_local_xform, const Vector2 &p_local_motion, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform, const Vector2 &p_shape_motion) {
+ ERR_FAIL_COND_V(p_shape.is_null(), PackedVector2Array());
const int max_contacts = 16;
Vector2 result[max_contacts * 2];
int contacts = 0;
if (!PhysicsServer2D::get_singleton()->shape_collide(get_rid(), p_local_xform, p_local_motion, p_shape->get_rid(), p_shape_xform, p_shape_motion, result, max_contacts, contacts)) {
- return Array();
+ return PackedVector2Array();
}
- Array results;
+ PackedVector2Array results;
results.resize(contacts * 2);
for (int i = 0; i < contacts * 2; i++) {
- results[i] = result[i];
+ results.write[i] = result[i];
}
return results;
}
-Array Shape2D::collide_and_get_contacts(const Transform2D &p_local_xform, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform) {
- ERR_FAIL_COND_V(p_shape.is_null(), Array());
+PackedVector2Array Shape2D::collide_and_get_contacts(const Transform2D &p_local_xform, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform) {
+ ERR_FAIL_COND_V(p_shape.is_null(), PackedVector2Array());
const int max_contacts = 16;
Vector2 result[max_contacts * 2];
int contacts = 0;
if (!PhysicsServer2D::get_singleton()->shape_collide(get_rid(), p_local_xform, Vector2(), p_shape->get_rid(), p_shape_xform, Vector2(), result, max_contacts, contacts)) {
- return Array();
+ return PackedVector2Array();
}
- Array results;
+ PackedVector2Array results;
results.resize(contacts * 2);
for (int i = 0; i < contacts * 2; i++) {
- results[i] = result[i];
+ results.write[i] = result[i];
}
return results;
diff --git a/scene/resources/shape_2d.h b/scene/resources/shape_2d.h
index e9dc10eeae..a15aecee93 100644
--- a/scene/resources/shape_2d.h
+++ b/scene/resources/shape_2d.h
@@ -53,8 +53,8 @@ public:
bool collide_with_motion(const Transform2D &p_local_xform, const Vector2 &p_local_motion, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform, const Vector2 &p_shape_motion);
bool collide(const Transform2D &p_local_xform, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform);
- Array collide_with_motion_and_get_contacts(const Transform2D &p_local_xform, const Vector2 &p_local_motion, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform, const Vector2 &p_shape_motion);
- Array collide_and_get_contacts(const Transform2D &p_local_xform, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform);
+ PackedVector2Array collide_with_motion_and_get_contacts(const Transform2D &p_local_xform, const Vector2 &p_local_motion, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform, const Vector2 &p_shape_motion);
+ PackedVector2Array collide_and_get_contacts(const Transform2D &p_local_xform, const Ref<Shape2D> &p_shape, const Transform2D &p_shape_xform);
virtual void draw(const RID &p_to_rid, const Color &p_color) {}
virtual Rect2 get_rect() const { return Rect2(); }
diff --git a/scene/resources/skeleton_modification_2d_ccdik.cpp b/scene/resources/skeleton_modification_2d_ccdik.cpp
index 7adaf1452c..96961a1fe4 100644
--- a/scene/resources/skeleton_modification_2d_ccdik.cpp
+++ b/scene/resources/skeleton_modification_2d_ccdik.cpp
@@ -52,9 +52,9 @@ bool SkeletonModification2DCCDIK::_set(const StringName &p_path, const Variant &
} else if (what == "enable_constraint") {
set_ccdik_joint_enable_constraint(which, p_value);
} else if (what == "constraint_angle_min") {
- set_ccdik_joint_constraint_angle_min(which, Math::deg2rad(float(p_value)));
+ set_ccdik_joint_constraint_angle_min(which, Math::deg_to_rad(float(p_value)));
} else if (what == "constraint_angle_max") {
- set_ccdik_joint_constraint_angle_max(which, Math::deg2rad(float(p_value)));
+ set_ccdik_joint_constraint_angle_max(which, Math::deg_to_rad(float(p_value)));
} else if (what == "constraint_angle_invert") {
set_ccdik_joint_constraint_angle_invert(which, p_value);
} else if (what == "constraint_in_localspace") {
@@ -96,9 +96,9 @@ bool SkeletonModification2DCCDIK::_get(const StringName &p_path, Variant &r_ret)
} else if (what == "enable_constraint") {
r_ret = get_ccdik_joint_enable_constraint(which);
} else if (what == "constraint_angle_min") {
- r_ret = Math::rad2deg(get_ccdik_joint_constraint_angle_min(which));
+ r_ret = Math::rad_to_deg(get_ccdik_joint_constraint_angle_min(which));
} else if (what == "constraint_angle_max") {
- r_ret = Math::rad2deg(get_ccdik_joint_constraint_angle_max(which));
+ r_ret = Math::rad_to_deg(get_ccdik_joint_constraint_angle_max(which));
} else if (what == "constraint_angle_invert") {
r_ret = get_ccdik_joint_constraint_angle_invert(which);
} else if (what == "constraint_in_localspace") {
diff --git a/scene/resources/skeleton_modification_2d_lookat.cpp b/scene/resources/skeleton_modification_2d_lookat.cpp
index 23e1c579dc..d3cfffb1de 100644
--- a/scene/resources/skeleton_modification_2d_lookat.cpp
+++ b/scene/resources/skeleton_modification_2d_lookat.cpp
@@ -41,15 +41,15 @@ bool SkeletonModification2DLookAt::_set(const StringName &p_path, const Variant
if (path.begins_with("enable_constraint")) {
set_enable_constraint(p_value);
} else if (path.begins_with("constraint_angle_min")) {
- set_constraint_angle_min(Math::deg2rad(float(p_value)));
+ set_constraint_angle_min(Math::deg_to_rad(float(p_value)));
} else if (path.begins_with("constraint_angle_max")) {
- set_constraint_angle_max(Math::deg2rad(float(p_value)));
+ set_constraint_angle_max(Math::deg_to_rad(float(p_value)));
} else if (path.begins_with("constraint_angle_invert")) {
set_constraint_angle_invert(p_value);
} else if (path.begins_with("constraint_in_localspace")) {
set_constraint_in_localspace(p_value);
} else if (path.begins_with("additional_rotation")) {
- set_additional_rotation(Math::deg2rad(float(p_value)));
+ set_additional_rotation(Math::deg_to_rad(float(p_value)));
}
#ifdef TOOLS_ENABLED
@@ -67,15 +67,15 @@ bool SkeletonModification2DLookAt::_get(const StringName &p_path, Variant &r_ret
if (path.begins_with("enable_constraint")) {
r_ret = get_enable_constraint();
} else if (path.begins_with("constraint_angle_min")) {
- r_ret = Math::rad2deg(get_constraint_angle_min());
+ r_ret = Math::rad_to_deg(get_constraint_angle_min());
} else if (path.begins_with("constraint_angle_max")) {
- r_ret = Math::rad2deg(get_constraint_angle_max());
+ r_ret = Math::rad_to_deg(get_constraint_angle_max());
} else if (path.begins_with("constraint_angle_invert")) {
r_ret = get_constraint_angle_invert();
} else if (path.begins_with("constraint_in_localspace")) {
r_ret = get_constraint_in_localspace();
} else if (path.begins_with("additional_rotation")) {
- r_ret = Math::rad2deg(get_additional_rotation());
+ r_ret = Math::rad_to_deg(get_additional_rotation());
}
#ifdef TOOLS_ENABLED
diff --git a/scene/resources/skeleton_modification_3d_ccdik.cpp b/scene/resources/skeleton_modification_3d_ccdik.cpp
index f19be47db2..3251ee4189 100644
--- a/scene/resources/skeleton_modification_3d_ccdik.cpp
+++ b/scene/resources/skeleton_modification_3d_ccdik.cpp
@@ -50,9 +50,9 @@ bool SkeletonModification3DCCDIK::_set(const StringName &p_path, const Variant &
} else if (what == "enable_joint_constraint") {
set_ccdik_joint_enable_constraint(which, p_value);
} else if (what == "joint_constraint_angle_min") {
- set_ccdik_joint_constraint_angle_min(which, Math::deg2rad(real_t(p_value)));
+ set_ccdik_joint_constraint_angle_min(which, Math::deg_to_rad(real_t(p_value)));
} else if (what == "joint_constraint_angle_max") {
- set_ccdik_joint_constraint_angle_max(which, Math::deg2rad(real_t(p_value)));
+ set_ccdik_joint_constraint_angle_max(which, Math::deg_to_rad(real_t(p_value)));
} else if (what == "joint_constraint_angles_invert") {
set_ccdik_joint_constraint_invert(which, p_value);
}
@@ -79,9 +79,9 @@ bool SkeletonModification3DCCDIK::_get(const StringName &p_path, Variant &r_ret)
} else if (what == "enable_joint_constraint") {
r_ret = get_ccdik_joint_enable_constraint(which);
} else if (what == "joint_constraint_angle_min") {
- r_ret = Math::rad2deg(get_ccdik_joint_constraint_angle_min(which));
+ r_ret = Math::rad_to_deg(get_ccdik_joint_constraint_angle_min(which));
} else if (what == "joint_constraint_angle_max") {
- r_ret = Math::rad2deg(get_ccdik_joint_constraint_angle_max(which));
+ r_ret = Math::rad_to_deg(get_ccdik_joint_constraint_angle_max(which));
} else if (what == "joint_constraint_angles_invert") {
r_ret = get_ccdik_joint_constraint_invert(which);
}
diff --git a/scene/resources/skeleton_modification_3d_ccdik.h b/scene/resources/skeleton_modification_3d_ccdik.h
index 7098794038..1fe53e94b6 100644
--- a/scene/resources/skeleton_modification_3d_ccdik.h
+++ b/scene/resources/skeleton_modification_3d_ccdik.h
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef SKELETON_MODIFICATION_3D_CCDIK_H
+#define SKELETON_MODIFICATION_3D_CCDIK_H
+
#include "core/templates/local_vector.h"
#include "scene/3d/skeleton_3d.h"
#include "scene/resources/skeleton_modification_3d.h"
-#ifndef SKELETON_MODIFICATION_3D_CCDIK_H
-#define SKELETON_MODIFICATION_3D_CCDIK_H
-
class SkeletonModification3DCCDIK : public SkeletonModification3D {
GDCLASS(SkeletonModification3DCCDIK, SkeletonModification3D);
diff --git a/scene/resources/skeleton_modification_3d_fabrik.cpp b/scene/resources/skeleton_modification_3d_fabrik.cpp
index b62dda3f4f..4099208f44 100644
--- a/scene/resources/skeleton_modification_3d_fabrik.cpp
+++ b/scene/resources/skeleton_modification_3d_fabrik.cpp
@@ -58,7 +58,7 @@ bool SkeletonModification3DFABRIK::_set(const StringName &p_path, const Variant
} else if (what == "use_target_basis") {
set_fabrik_joint_use_target_basis(which, p_value);
} else if (what == "roll") {
- set_fabrik_joint_roll(which, Math::deg2rad(real_t(p_value)));
+ set_fabrik_joint_roll(which, Math::deg_to_rad(real_t(p_value)));
}
return true;
}
@@ -91,7 +91,7 @@ bool SkeletonModification3DFABRIK::_get(const StringName &p_path, Variant &r_ret
} else if (what == "use_target_basis") {
r_ret = get_fabrik_joint_use_target_basis(which);
} else if (what == "roll") {
- r_ret = Math::rad2deg(get_fabrik_joint_roll(which));
+ r_ret = Math::rad_to_deg(get_fabrik_joint_roll(which));
}
return true;
}
diff --git a/scene/resources/skeleton_modification_3d_fabrik.h b/scene/resources/skeleton_modification_3d_fabrik.h
index 3d66bb6d99..e2e490d636 100644
--- a/scene/resources/skeleton_modification_3d_fabrik.h
+++ b/scene/resources/skeleton_modification_3d_fabrik.h
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef SKELETON_MODIFICATION_3D_FABRIK_H
+#define SKELETON_MODIFICATION_3D_FABRIK_H
+
#include "core/templates/local_vector.h"
#include "scene/3d/skeleton_3d.h"
#include "scene/resources/skeleton_modification_3d.h"
-#ifndef SKELETON_MODIFICATION_3D_FABRIK_H
-#define SKELETON_MODIFICATION_3D_FABRIK_H
-
class SkeletonModification3DFABRIK : public SkeletonModification3D {
GDCLASS(SkeletonModification3DFABRIK, SkeletonModification3D);
diff --git a/scene/resources/skeleton_modification_3d_jiggle.cpp b/scene/resources/skeleton_modification_3d_jiggle.cpp
index 3e36c241f7..64f26f3fda 100644
--- a/scene/resources/skeleton_modification_3d_jiggle.cpp
+++ b/scene/resources/skeleton_modification_3d_jiggle.cpp
@@ -58,7 +58,7 @@ bool SkeletonModification3DJiggle::_set(const StringName &p_path, const Variant
} else if (what == "gravity") {
set_jiggle_joint_gravity(which, p_value);
} else if (what == "roll") {
- set_jiggle_joint_roll(which, Math::deg2rad(real_t(p_value)));
+ set_jiggle_joint_roll(which, Math::deg_to_rad(real_t(p_value)));
}
return true;
} else {
@@ -98,7 +98,7 @@ bool SkeletonModification3DJiggle::_get(const StringName &p_path, Variant &r_ret
} else if (what == "gravity") {
r_ret = get_jiggle_joint_gravity(which);
} else if (what == "roll") {
- r_ret = Math::rad2deg(get_jiggle_joint_roll(which));
+ r_ret = Math::rad_to_deg(get_jiggle_joint_roll(which));
}
return true;
} else {
diff --git a/scene/resources/skeleton_modification_3d_jiggle.h b/scene/resources/skeleton_modification_3d_jiggle.h
index f41ffcd58d..bd1ee51d93 100644
--- a/scene/resources/skeleton_modification_3d_jiggle.h
+++ b/scene/resources/skeleton_modification_3d_jiggle.h
@@ -28,13 +28,13 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#ifndef SKELETON_MODIFICATION_3D_JIGGLE_H
+#define SKELETON_MODIFICATION_3D_JIGGLE_H
+
#include "core/templates/local_vector.h"
#include "scene/3d/skeleton_3d.h"
#include "scene/resources/skeleton_modification_3d.h"
-#ifndef SKELETON_MODIFICATION_3D_JIGGLE_H
-#define SKELETON_MODIFICATION_3D_JIGGLE_H
-
class SkeletonModification3DJiggle : public SkeletonModification3D {
GDCLASS(SkeletonModification3DJiggle, SkeletonModification3D);
diff --git a/scene/resources/skeleton_modification_3d_lookat.cpp b/scene/resources/skeleton_modification_3d_lookat.cpp
index 3e8c1e3a77..69167cb308 100644
--- a/scene/resources/skeleton_modification_3d_lookat.cpp
+++ b/scene/resources/skeleton_modification_3d_lookat.cpp
@@ -39,9 +39,9 @@ bool SkeletonModification3DLookAt::_set(const StringName &p_path, const Variant
set_lock_rotation_plane(p_value);
} else if (p_path == "additional_rotation") {
Vector3 tmp = p_value;
- tmp.x = Math::deg2rad(tmp.x);
- tmp.y = Math::deg2rad(tmp.y);
- tmp.z = Math::deg2rad(tmp.z);
+ tmp.x = Math::deg_to_rad(tmp.x);
+ tmp.y = Math::deg_to_rad(tmp.y);
+ tmp.z = Math::deg_to_rad(tmp.z);
set_additional_rotation(tmp);
}
@@ -55,9 +55,9 @@ bool SkeletonModification3DLookAt::_get(const StringName &p_path, Variant &r_ret
r_ret = get_lock_rotation_plane();
} else if (p_path == "additional_rotation") {
Vector3 tmp = get_additional_rotation();
- tmp.x = Math::rad2deg(tmp.x);
- tmp.y = Math::rad2deg(tmp.y);
- tmp.z = Math::rad2deg(tmp.z);
+ tmp.x = Math::rad_to_deg(tmp.x);
+ tmp.y = Math::rad_to_deg(tmp.y);
+ tmp.z = Math::rad_to_deg(tmp.z);
r_ret = tmp;
}
diff --git a/scene/resources/skeleton_modification_3d_lookat.h b/scene/resources/skeleton_modification_3d_lookat.h
index 4e5714b5dc..cea63fc34f 100644
--- a/scene/resources/skeleton_modification_3d_lookat.h
+++ b/scene/resources/skeleton_modification_3d_lookat.h
@@ -28,12 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
#ifndef SKELETON_MODIFICATION_3D_LOOKAT_H
#define SKELETON_MODIFICATION_3D_LOOKAT_H
+#include "scene/3d/skeleton_3d.h"
+#include "scene/resources/skeleton_modification_3d.h"
+
class SkeletonModification3DLookAt : public SkeletonModification3D {
GDCLASS(SkeletonModification3DLookAt, SkeletonModification3D);
diff --git a/scene/resources/skeleton_modification_3d_stackholder.h b/scene/resources/skeleton_modification_3d_stackholder.h
index ae22099158..2071de5457 100644
--- a/scene/resources/skeleton_modification_3d_stackholder.h
+++ b/scene/resources/skeleton_modification_3d_stackholder.h
@@ -28,12 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
#ifndef SKELETON_MODIFICATION_3D_STACKHOLDER_H
#define SKELETON_MODIFICATION_3D_STACKHOLDER_H
+#include "scene/3d/skeleton_3d.h"
+#include "scene/resources/skeleton_modification_3d.h"
+
class SkeletonModification3DStackHolder : public SkeletonModification3D {
GDCLASS(SkeletonModification3DStackHolder, SkeletonModification3D);
diff --git a/scene/resources/skeleton_modification_3d_twoboneik.cpp b/scene/resources/skeleton_modification_3d_twoboneik.cpp
index acc5ff716c..366fcc30b7 100644
--- a/scene/resources/skeleton_modification_3d_twoboneik.cpp
+++ b/scene/resources/skeleton_modification_3d_twoboneik.cpp
@@ -54,13 +54,13 @@ bool SkeletonModification3DTwoBoneIK::_set(const StringName &p_path, const Varia
} else if (path == "joint_one/bone_idx") {
set_joint_one_bone_idx(p_value);
} else if (path == "joint_one/roll") {
- set_joint_one_roll(Math::deg2rad(real_t(p_value)));
+ set_joint_one_roll(Math::deg_to_rad(real_t(p_value)));
} else if (path == "joint_two/bone_name") {
set_joint_two_bone_name(p_value);
} else if (path == "joint_two/bone_idx") {
set_joint_two_bone_idx(p_value);
} else if (path == "joint_two/roll") {
- set_joint_two_roll(Math::deg2rad(real_t(p_value)));
+ set_joint_two_roll(Math::deg_to_rad(real_t(p_value)));
}
return true;
@@ -88,13 +88,13 @@ bool SkeletonModification3DTwoBoneIK::_get(const StringName &p_path, Variant &r_
} else if (path == "joint_one/bone_idx") {
r_ret = get_joint_one_bone_idx();
} else if (path == "joint_one/roll") {
- r_ret = Math::rad2deg(get_joint_one_roll());
+ r_ret = Math::rad_to_deg(get_joint_one_roll());
} else if (path == "joint_two/bone_name") {
r_ret = get_joint_two_bone_name();
} else if (path == "joint_two/bone_idx") {
r_ret = get_joint_two_bone_idx();
} else if (path == "joint_two/roll") {
- r_ret = Math::rad2deg(get_joint_two_roll());
+ r_ret = Math::rad_to_deg(get_joint_two_roll());
}
return true;
diff --git a/scene/resources/skeleton_modification_3d_twoboneik.h b/scene/resources/skeleton_modification_3d_twoboneik.h
index 57e8237511..7bd7c8291d 100644
--- a/scene/resources/skeleton_modification_3d_twoboneik.h
+++ b/scene/resources/skeleton_modification_3d_twoboneik.h
@@ -28,12 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
#ifndef SKELETON_MODIFICATION_3D_TWOBONEIK_H
#define SKELETON_MODIFICATION_3D_TWOBONEIK_H
+#include "scene/3d/skeleton_3d.h"
+#include "scene/resources/skeleton_modification_3d.h"
+
class SkeletonModification3DTwoBoneIK : public SkeletonModification3D {
GDCLASS(SkeletonModification3DTwoBoneIK, SkeletonModification3D);
diff --git a/scene/resources/skeleton_profile.cpp b/scene/resources/skeleton_profile.cpp
index bfb4bb6e2b..1367ea86dd 100644
--- a/scene/resources/skeleton_profile.cpp
+++ b/scene/resources/skeleton_profile.cpp
@@ -121,26 +121,26 @@ bool SkeletonProfile::_get(const StringName &p_path, Variant &r_ret) const {
return true;
}
-void SkeletonProfile::_validate_property(PropertyInfo &property) const {
+void SkeletonProfile::_validate_property(PropertyInfo &p_property) const {
if (is_read_only) {
- if (property.name == ("group_size") || property.name == ("bone_size") || property.name == ("root_bone") || property.name == ("scale_base_bone")) {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+ if (p_property.name == ("group_size") || p_property.name == ("bone_size") || p_property.name == ("root_bone") || p_property.name == ("scale_base_bone")) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
return;
}
}
- if (property.name == ("root_bone") || property.name == ("scale_base_bone")) {
+ if (p_property.name == ("root_bone") || p_property.name == ("scale_base_bone")) {
String hint = "";
for (int i = 0; i < bones.size(); i++) {
hint += i == 0 ? String(bones[i].bone_name) : "," + String(bones[i].bone_name);
}
- property.hint_string = hint;
+ p_property.hint_string = hint;
}
- PackedStringArray split = property.name.split("/");
+ PackedStringArray split = p_property.name.split("/");
if (split.size() == 3 && split[0] == "bones") {
if (split[2] == "bone_tail" && get_tail_direction(split[1].to_int()) != TAIL_DIRECTION_SPECIFIC_CHILD) {
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
}
@@ -506,7 +506,7 @@ SkeletonProfileHumanoid::SkeletonProfileHumanoid() {
bones.write[5].reference_pose = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0);
bones.write[5].handle_offset = Vector2(0.5, 0.23);
bones.write[5].group = "Body";
- bones.write[5].require = true;
+ bones.write[5].require = false;
bones.write[6].bone_name = "Head";
bones.write[6].bone_parent = "Neck";
diff --git a/scene/resources/skeleton_profile.h b/scene/resources/skeleton_profile.h
index 84dfca458e..66344d954d 100644
--- a/scene/resources/skeleton_profile.h
+++ b/scene/resources/skeleton_profile.h
@@ -72,7 +72,7 @@ protected:
bool _get(const StringName &p_path, Variant &r_ret) const;
bool _set(const StringName &p_path, const Variant &p_value);
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
static void _bind_methods();
diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp
index 5d1a223cc7..737c50e570 100644
--- a/scene/resources/sky_material.cpp
+++ b/scene/resources/sky_material.cpp
@@ -128,7 +128,7 @@ float ProceduralSkyMaterial::get_ground_energy() const {
void ProceduralSkyMaterial::set_sun_angle_max(float p_angle) {
sun_angle_max = p_angle;
- RS::get_singleton()->material_set_param(_get_material(), "sun_angle_max", Math::deg2rad(sun_angle_max));
+ RS::get_singleton()->material_set_param(_get_material(), "sun_angle_max", Math::deg_to_rad(sun_angle_max));
}
float ProceduralSkyMaterial::get_sun_angle_max() const {
diff --git a/scene/resources/sphere_shape_3d.cpp b/scene/resources/sphere_shape_3d.cpp
index 92efe3ce6f..340d0fe370 100644
--- a/scene/resources/sphere_shape_3d.cpp
+++ b/scene/resources/sphere_shape_3d.cpp
@@ -38,8 +38,8 @@ Vector<Vector3> SphereShape3D::get_debug_mesh_lines() const {
Vector<Vector3> points;
for (int i = 0; i <= 360; i++) {
- float ra = Math::deg2rad((float)i);
- float rb = Math::deg2rad((float)i + 1);
+ float ra = Math::deg_to_rad((float)i);
+ float rb = Math::deg_to_rad((float)i + 1);
Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
diff --git a/scene/resources/sprite_frames.cpp b/scene/resources/sprite_frames.cpp
index 55c9d7397d..3533e86c3a 100644
--- a/scene/resources/sprite_frames.cpp
+++ b/scene/resources/sprite_frames.cpp
@@ -207,7 +207,7 @@ void SpriteFrames::_bind_methods() {
// `animations` property is for serialization.
- ClassDB::bind_method(D_METHOD("_set_animations"), &SpriteFrames::_set_animations);
+ ClassDB::bind_method(D_METHOD("_set_animations", "animations"), &SpriteFrames::_set_animations);
ClassDB::bind_method(D_METHOD("_get_animations"), &SpriteFrames::_get_animations);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_animations", "_get_animations");
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index a53c299d00..ff5210f1b3 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -842,9 +842,9 @@ float StyleBoxFlat::get_style_margin(Side p_side) const {
return border_width[p_side];
}
-void StyleBoxFlat::_validate_property(PropertyInfo &property) const {
- if (!anti_aliased && property.name == "anti_aliasing_size") {
- property.usage = PROPERTY_USAGE_NO_EDITOR;
+void StyleBoxFlat::_validate_property(PropertyInfo &p_property) const {
+ if (!anti_aliased && p_property.name == "anti_aliasing_size") {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
}
diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h
index 9f4f69d3ba..88db4f5fbd 100644
--- a/scene/resources/style_box.h
+++ b/scene/resources/style_box.h
@@ -166,7 +166,7 @@ class StyleBoxFlat : public StyleBox {
protected:
virtual float get_style_margin(Side p_side) const override;
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_bg_color(const Color &p_color);
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 05ed9238b8..25f5006c4f 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -35,8 +35,8 @@
#include "core/io/marshalls.h"
#include "core/math/geometry_2d.h"
#include "core/os/os.h"
-#include "mesh.h"
#include "scene/resources/bit_map.h"
+#include "scene/resources/mesh.h"
#include "servers/camera/camera_feed.h"
int Texture2D::get_width() const {
int ret;
@@ -1038,7 +1038,7 @@ void CompressedTexture2D::reload_from_file() {
load(path);
}
-void CompressedTexture2D::_validate_property(PropertyInfo &property) const {
+void CompressedTexture2D::_validate_property(PropertyInfo &p_property) const {
}
void CompressedTexture2D::_bind_methods() {
@@ -1394,7 +1394,7 @@ void CompressedTexture3D::reload_from_file() {
load(path);
}
-void CompressedTexture3D::_validate_property(PropertyInfo &property) const {
+void CompressedTexture3D::_validate_property(PropertyInfo &p_property) const {
}
void CompressedTexture3D::_bind_methods() {
@@ -2537,13 +2537,6 @@ void GradientTexture2D::_bind_methods() {
//////////////////////////////////////
-void ProxyTexture::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_base", "base"), &ProxyTexture::set_base);
- ClassDB::bind_method(D_METHOD("get_base"), &ProxyTexture::get_base);
-
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "base", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_base", "get_base");
-}
-
void ProxyTexture::set_base(const Ref<Texture2D> &p_texture) {
ERR_FAIL_COND(p_texture == this);
@@ -2796,12 +2789,12 @@ bool AnimatedTexture::is_pixel_opaque(int p_x, int p_y) const {
return true;
}
-void AnimatedTexture::_validate_property(PropertyInfo &property) const {
- String prop = property.name;
+void AnimatedTexture::_validate_property(PropertyInfo &p_property) const {
+ String prop = p_property.name;
if (prop.begins_with("frame_")) {
int frame = prop.get_slicec('/', 0).get_slicec('_', 1).to_int();
if (frame >= frame_count) {
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
}
@@ -3221,7 +3214,7 @@ void CompressedTextureLayered::reload_from_file() {
load(path);
}
-void CompressedTextureLayered::_validate_property(PropertyInfo &property) const {
+void CompressedTextureLayered::_validate_property(PropertyInfo &p_property) const {
}
void CompressedTextureLayered::_bind_methods() {
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 36b193c5d4..133b312d27 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -251,7 +251,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
static Ref<Image> load_image_from_file(Ref<FileAccess> p_file, int p_size_limit);
@@ -506,7 +506,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
Image::Format get_format() const override;
@@ -651,7 +651,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
Image::Format get_format() const override;
@@ -883,8 +883,6 @@ VARIANT_ENUM_CAST(GradientTexture2D::Fill);
VARIANT_ENUM_CAST(GradientTexture2D::Repeat);
class ProxyTexture : public Texture2D {
- GDCLASS(ProxyTexture, Texture2D);
-
private:
mutable RID proxy_ph;
mutable RID proxy;
@@ -942,7 +940,7 @@ private:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
void set_frames(int p_frames);
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp
index 3f6eec8497..3321392821 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -31,17 +31,7 @@
#include "theme.h"
#include "core/string/print_string.h"
-
-// Universal Theme resources used when no other theme has the item.
-Ref<Theme> Theme::default_theme;
-Ref<Theme> Theme::project_default_theme;
-
-// Universal default values, final fallback for every theme.
-float Theme::fallback_base_scale = 1.0;
-Ref<Texture2D> Theme::fallback_icon;
-Ref<StyleBox> Theme::fallback_style;
-Ref<Font> Theme::fallback_font;
-int Theme::fallback_font_size = 16;
+#include "scene/theme/theme_db.h"
// Dynamic properties.
bool Theme::_set(const StringName &p_name, const Variant &p_value) {
@@ -185,64 +175,7 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-// Universal fallback Theme resources.
-Ref<Theme> Theme::get_default() {
- return default_theme;
-}
-
-void Theme::set_default(const Ref<Theme> &p_default) {
- default_theme = p_default;
-}
-
-Ref<Theme> Theme::get_project_default() {
- return project_default_theme;
-}
-
-void Theme::set_project_default(const Ref<Theme> &p_project_default) {
- project_default_theme = p_project_default;
-}
-
-// Universal fallback values for theme item types.
-void Theme::set_fallback_base_scale(float p_base_scale) {
- fallback_base_scale = p_base_scale;
-}
-
-void Theme::set_fallback_icon(const Ref<Texture2D> &p_icon) {
- fallback_icon = p_icon;
-}
-
-void Theme::set_fallback_style(const Ref<StyleBox> &p_style) {
- fallback_style = p_style;
-}
-
-void Theme::set_fallback_font(const Ref<Font> &p_font) {
- fallback_font = p_font;
-}
-
-void Theme::set_fallback_font_size(int p_font_size) {
- fallback_font_size = p_font_size;
-}
-
-float Theme::get_fallback_base_scale() {
- return fallback_base_scale;
-}
-
-Ref<Texture2D> Theme::get_fallback_icon() {
- return fallback_icon;
-}
-
-Ref<StyleBox> Theme::get_fallback_style() {
- return fallback_style;
-}
-
-Ref<Font> Theme::get_fallback_font() {
- return fallback_font;
-}
-
-int Theme::get_fallback_font_size() {
- return fallback_font_size;
-}
-
+// Static helpers.
bool Theme::is_valid_type_name(const String &p_name) {
for (int i = 0; i < p_name.length(); i++) {
if (!is_ascii_identifier_char(p_name[i])) {
@@ -351,7 +284,7 @@ Ref<Texture2D> Theme::get_icon(const StringName &p_name, const StringName &p_the
if (icon_map.has(p_theme_type) && icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()) {
return icon_map[p_theme_type][p_name];
} else {
- return fallback_icon;
+ return ThemeDB::get_singleton()->get_fallback_icon();
}
}
@@ -461,7 +394,7 @@ Ref<StyleBox> Theme::get_stylebox(const StringName &p_name, const StringName &p_
if (style_map.has(p_theme_type) && style_map[p_theme_type].has(p_name) && style_map[p_theme_type][p_name].is_valid()) {
return style_map[p_theme_type][p_name];
} else {
- return fallback_style;
+ return ThemeDB::get_singleton()->get_fallback_stylebox();
}
}
@@ -573,7 +506,7 @@ Ref<Font> Theme::get_font(const StringName &p_name, const StringName &p_theme_ty
} else if (has_default_font()) {
return default_font;
} else {
- return fallback_font;
+ return ThemeDB::get_singleton()->get_fallback_font();
}
}
@@ -676,7 +609,7 @@ int Theme::get_font_size(const StringName &p_name, const StringName &p_theme_typ
} else if (has_default_font_size()) {
return default_font_size;
} else {
- return fallback_font_size;
+ return ThemeDB::get_singleton()->get_fallback_font_size();
}
}
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index a2aca5e61f..ed1dc7c938 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -102,17 +102,6 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
- // Universal Theme resources used when no other theme has the item.
- static Ref<Theme> default_theme;
- static Ref<Theme> project_default_theme;
-
- // Universal default values, final fallback for every theme.
- static float fallback_base_scale;
- static Ref<Texture2D> fallback_icon;
- static Ref<StyleBox> fallback_style;
- static Ref<Font> fallback_font;
- static int fallback_font_size;
-
// Default values configurable for each individual theme.
float default_base_scale = 0.0;
Ref<Font> default_font;
@@ -126,24 +115,6 @@ protected:
virtual void reset_state() override;
public:
- static Ref<Theme> get_default();
- static void set_default(const Ref<Theme> &p_default);
-
- static Ref<Theme> get_project_default();
- static void set_project_default(const Ref<Theme> &p_project_default);
-
- static void set_fallback_base_scale(float p_base_scale);
- static void set_fallback_icon(const Ref<Texture2D> &p_icon);
- static void set_fallback_style(const Ref<StyleBox> &p_style);
- static void set_fallback_font(const Ref<Font> &p_font);
- static void set_fallback_font_size(int p_font_size);
-
- static float get_fallback_base_scale();
- static Ref<Texture2D> get_fallback_icon();
- static Ref<StyleBox> get_fallback_style();
- static Ref<Font> get_fallback_font();
- static int get_fallback_font_size();
-
static bool is_valid_type_name(const String &p_name);
static bool is_valid_item_name(const String &p_name);
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index b0b9f1228f..552d856034 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -3302,11 +3302,11 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-void TileSet::_validate_property(PropertyInfo &property) const {
- if (property.name == "tile_layout" && tile_shape == TILE_SHAPE_SQUARE) {
- property.usage ^= PROPERTY_USAGE_READ_ONLY;
- } else if (property.name == "tile_offset_axis" && tile_shape == TILE_SHAPE_SQUARE) {
- property.usage ^= PROPERTY_USAGE_READ_ONLY;
+void TileSet::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "tile_layout" && tile_shape == TILE_SHAPE_SQUARE) {
+ p_property.usage ^= PROPERTY_USAGE_READ_ONLY;
+ } else if (p_property.name == "tile_offset_axis" && tile_shape == TILE_SHAPE_SQUARE) {
+ p_property.usage ^= PROPERTY_USAGE_READ_ONLY;
}
}
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index 6ea3889fce..4c0823cdf2 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -295,7 +295,7 @@ protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
- virtual void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
private:
// --- TileSet data ---
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 5e0627a7d9..90f1a1bff1 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -1036,11 +1036,11 @@ void VisualShader::disconnect_nodes(Type p_type, int p_from_node, int p_from_por
}
}
-Array VisualShader::_get_node_connections(Type p_type) const {
+TypedArray<Dictionary> VisualShader::_get_node_connections(Type p_type) const {
ERR_FAIL_INDEX_V(p_type, TYPE_MAX, Array());
const Graph *g = &graph[p_type];
- Array ret;
+ TypedArray<Dictionary> ret;
for (const Connection &E : g->connections) {
Dictionary d;
d["from_node"] = E.from_node;
@@ -1698,13 +1698,13 @@ Error VisualShader::_write_node(Type type, StringBuilder *global_code, StringBui
inputs[i] = "(" + src_var + " ? 1.0 : 0.0)";
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_2D: {
- inputs[i] = "dot(" + src_var + ", vec2(0.5, 0.5))";
+ inputs[i] = src_var + ".x";
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_3D: {
- inputs[i] = "dot(" + src_var + ", vec3(0.333333, 0.333333, 0.333333))";
+ inputs[i] = src_var + ".x";
} break;
case VisualShaderNode::PORT_TYPE_VECTOR_4D: {
- inputs[i] = "dot(" + src_var + ", vec4(0.25, 0.25, 0.25, 0.25))";
+ inputs[i] = src_var + ".x";
} break;
default:
break;
@@ -2214,6 +2214,12 @@ void VisualShader::_update_shader() const {
case VaryingType::VARYING_TYPE_FLOAT:
global_code += "float ";
break;
+ case VaryingType::VARYING_TYPE_INT:
+ if (E.value.mode == VaryingMode::VARYING_MODE_VERTEX_TO_FRAG_LIGHT) {
+ global_code += "flat ";
+ }
+ global_code += "int ";
+ break;
case VaryingType::VARYING_TYPE_VECTOR_2D:
global_code += "vec2 ";
break;
@@ -2223,8 +2229,11 @@ void VisualShader::_update_shader() const {
case VaryingType::VARYING_TYPE_VECTOR_4D:
global_code += "vec4 ";
break;
- case VaryingType::VARYING_TYPE_COLOR:
- global_code += "vec4 ";
+ case VaryingType::VARYING_TYPE_BOOLEAN:
+ if (E.value.mode == VaryingMode::VARYING_MODE_VERTEX_TO_FRAG_LIGHT) {
+ global_code += "flat ";
+ }
+ global_code += "bool ";
break;
case VaryingType::VARYING_TYPE_TRANSFORM:
global_code += "mat4 ";
@@ -2277,6 +2286,9 @@ void VisualShader::_update_shader() const {
case VaryingType::VARYING_TYPE_FLOAT:
code2 += "0.0";
break;
+ case VaryingType::VARYING_TYPE_INT:
+ code2 += "0";
+ break;
case VaryingType::VARYING_TYPE_VECTOR_2D:
code2 += "vec2(0.0)";
break;
@@ -2286,8 +2298,8 @@ void VisualShader::_update_shader() const {
case VaryingType::VARYING_TYPE_VECTOR_4D:
code2 += "vec4(0.0)";
break;
- case VaryingType::VARYING_TYPE_COLOR:
- code2 += "vec4(0.0)";
+ case VaryingType::VARYING_TYPE_BOOLEAN:
+ code2 += "false";
break;
case VaryingType::VARYING_TYPE_TRANSFORM:
code2 += "mat4(1.0)";
@@ -2585,10 +2597,11 @@ void VisualShader::_bind_methods() {
BIND_ENUM_CONSTANT(VARYING_MODE_MAX);
BIND_ENUM_CONSTANT(VARYING_TYPE_FLOAT);
+ BIND_ENUM_CONSTANT(VARYING_TYPE_INT);
BIND_ENUM_CONSTANT(VARYING_TYPE_VECTOR_2D);
BIND_ENUM_CONSTANT(VARYING_TYPE_VECTOR_3D);
BIND_ENUM_CONSTANT(VARYING_TYPE_VECTOR_4D);
- BIND_ENUM_CONSTANT(VARYING_TYPE_COLOR);
+ BIND_ENUM_CONSTANT(VARYING_TYPE_BOOLEAN);
BIND_ENUM_CONSTANT(VARYING_TYPE_TRANSFORM);
BIND_ENUM_CONSTANT(VARYING_TYPE_MAX);
@@ -2647,6 +2660,10 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_index", "VIEW_INDEX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_mono_left", "VIEW_MONO_LEFT" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_right", "VIEW_RIGHT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_world", "NODE_POSITION_WORLD" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_position_world", "CAMERA_POSITION_WORLD" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_direction_world", "CAMERA_DIRECTION_WORLD" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_view", "NODE_POSITION_VIEW" },
// Node3D, Fragment
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
@@ -2675,6 +2692,10 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_index", "VIEW_INDEX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_mono_left", "VIEW_MONO_LEFT" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_right", "VIEW_RIGHT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_world", "NODE_POSITION_WORLD" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_position_world", "CAMERA_POSITION_WORLD" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "camera_direction_world", "CAMERA_DIRECTION_WORLD" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "node_position_view", "NODE_POSITION_VIEW" },
// Node3D, Light
{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fragcoord", "FRAGCOORD" },
@@ -3145,8 +3166,8 @@ String VisualShaderNodeInput::get_input_index_name(int p_index) const {
return "";
}
-void VisualShaderNodeInput::_validate_property(PropertyInfo &property) const {
- if (property.name == "input_name") {
+void VisualShaderNodeInput::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "input_name") {
String port_list;
int idx = 0;
@@ -3164,7 +3185,7 @@ void VisualShaderNodeInput::_validate_property(PropertyInfo &property) const {
if (port_list.is_empty()) {
port_list = RTR("None");
}
- property.hint_string = port_list;
+ p_property.hint_string = port_list;
}
}
@@ -4624,21 +4645,23 @@ void VisualShaderNodeVarying::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_varying_type"), &VisualShaderNodeVarying::get_varying_type);
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "varying_name"), "set_varying_name", "get_varying_name");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "varying_type", PROPERTY_HINT_ENUM, "Float,Vector,Transform"), "set_varying_type", "get_varying_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "varying_type", PROPERTY_HINT_ENUM, "Float,Int,Vector2,Vector3,Vector4,Boolean,Transform"), "set_varying_type", "get_varying_type");
}
String VisualShaderNodeVarying::get_type_str() const {
switch (varying_type) {
case VisualShader::VARYING_TYPE_FLOAT:
return "float";
+ case VisualShader::VARYING_TYPE_INT:
+ return "int";
case VisualShader::VARYING_TYPE_VECTOR_2D:
return "vec2";
case VisualShader::VARYING_TYPE_VECTOR_3D:
return "vec3";
case VisualShader::VARYING_TYPE_VECTOR_4D:
return "vec4";
- case VisualShader::VARYING_TYPE_COLOR:
- return "vec4";
+ case VisualShader::VARYING_TYPE_BOOLEAN:
+ return "bool";
case VisualShader::VARYING_TYPE_TRANSFORM:
return "mat4";
default:
@@ -4649,17 +4672,16 @@ String VisualShaderNodeVarying::get_type_str() const {
VisualShaderNodeVarying::PortType VisualShaderNodeVarying::get_port_type(VisualShader::VaryingType p_type, int p_port) const {
switch (p_type) {
+ case VisualShader::VARYING_TYPE_INT:
+ return PORT_TYPE_SCALAR_INT;
case VisualShader::VARYING_TYPE_VECTOR_2D:
return PORT_TYPE_VECTOR_2D;
case VisualShader::VARYING_TYPE_VECTOR_3D:
return PORT_TYPE_VECTOR_3D;
case VisualShader::VARYING_TYPE_VECTOR_4D:
return PORT_TYPE_VECTOR_4D;
- case VisualShader::VARYING_TYPE_COLOR:
- if (p_port == 1) {
- break; // scalar
- }
- return PORT_TYPE_VECTOR_3D;
+ case VisualShader::VARYING_TYPE_BOOLEAN:
+ return PORT_TYPE_BOOLEAN;
case VisualShader::VARYING_TYPE_TRANSFORM:
return PORT_TYPE_TRANSFORM;
default:
@@ -4703,9 +4725,6 @@ String VisualShaderNodeVaryingSetter::get_caption() const {
}
int VisualShaderNodeVaryingSetter::get_input_port_count() const {
- if (varying_type == VisualShader::VARYING_TYPE_COLOR) {
- return 2;
- }
return 1;
}
@@ -4714,13 +4733,6 @@ VisualShaderNodeVaryingSetter::PortType VisualShaderNodeVaryingSetter::get_input
}
String VisualShaderNodeVaryingSetter::get_input_port_name(int p_port) const {
- if (varying_type == VisualShader::VARYING_TYPE_COLOR) {
- if (p_port == 0) {
- return "color";
- } else {
- return "alpha";
- }
- }
return "";
}
@@ -4736,20 +4748,12 @@ String VisualShaderNodeVaryingSetter::get_output_port_name(int p_port) const {
return "";
}
-String VisualShaderNodeVaryingSetter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- return vformat("varying %s %s;\n", get_type_str(), varying_name);
-}
-
String VisualShaderNodeVaryingSetter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
String code;
if (varying_name == "[None]") {
return code;
}
- if (varying_type == VisualShader::VARYING_TYPE_COLOR) {
- code += vformat(" %s = vec4(%s, %s);\n", varying_name, p_input_vars[0], p_input_vars[1]);
- } else {
- code += vformat(" %s = %s;\n", varying_name, p_input_vars[0]);
- }
+ code += vformat(" %s = %s;\n", varying_name, p_input_vars[0]);
return code;
}
@@ -4775,9 +4779,6 @@ String VisualShaderNodeVaryingGetter::get_input_port_name(int p_port) const {
}
int VisualShaderNodeVaryingGetter::get_output_port_count() const {
- if (varying_type == VisualShader::VARYING_TYPE_COLOR) {
- return 2;
- }
return 1;
}
@@ -4786,13 +4787,6 @@ VisualShaderNodeVaryingGetter::PortType VisualShaderNodeVaryingGetter::get_outpu
}
String VisualShaderNodeVaryingGetter::get_output_port_name(int p_port) const {
- if (varying_type == VisualShader::VARYING_TYPE_COLOR) {
- if (p_port == 0) {
- return "color";
- } else {
- return "alpha";
- }
- }
return "";
}
@@ -4809,6 +4803,9 @@ String VisualShaderNodeVaryingGetter::generate_code(Shader::Mode p_mode, VisualS
case VisualShader::VARYING_TYPE_FLOAT:
from = "0.0";
break;
+ case VisualShader::VARYING_TYPE_INT:
+ from = "0";
+ break;
case VisualShader::VARYING_TYPE_VECTOR_2D:
from = "vec2(0.0)";
break;
@@ -4818,9 +4815,8 @@ String VisualShaderNodeVaryingGetter::generate_code(Shader::Mode p_mode, VisualS
case VisualShader::VARYING_TYPE_VECTOR_4D:
from = "vec4(0.0)";
break;
- case VisualShader::VARYING_TYPE_COLOR:
- from = "vec3(0.0)";
- from2 = "0.0";
+ case VisualShader::VARYING_TYPE_BOOLEAN:
+ from = "false";
break;
case VisualShader::VARYING_TYPE_TRANSFORM:
from = "mat4(1.0)";
@@ -4828,16 +4824,6 @@ String VisualShaderNodeVaryingGetter::generate_code(Shader::Mode p_mode, VisualS
default:
break;
}
- } else if (varying_type == VisualShader::VARYING_TYPE_COLOR) {
- from = varying_name + ".rgb";
- from2 = varying_name + ".a";
- }
-
- if (varying_type == VisualShader::VARYING_TYPE_COLOR) {
- String code;
- code += vformat(" %s = %s;\n", p_output_vars[0], from);
- code += vformat(" %s = %s;\n", p_output_vars[1], from2);
- return code;
}
return vformat(" %s = %s;\n", p_output_vars[0], from);
}
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 7ca4e5fc4a..09a3917a16 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -79,10 +79,11 @@ public:
enum VaryingType {
VARYING_TYPE_FLOAT,
+ VARYING_TYPE_INT,
VARYING_TYPE_VECTOR_2D,
VARYING_TYPE_VECTOR_3D,
VARYING_TYPE_VECTOR_4D,
- VARYING_TYPE_COLOR,
+ VARYING_TYPE_BOOLEAN,
VARYING_TYPE_TRANSFORM,
VARYING_TYPE_MAX,
};
@@ -132,7 +133,7 @@ private:
Shader::Mode shader_mode = Shader::MODE_SPATIAL;
mutable String previous_code;
- Array _get_node_connections(Type p_type) const;
+ TypedArray<Dictionary> _get_node_connections(Type p_type) const;
Vector2 graph_offset;
@@ -428,7 +429,7 @@ public:
protected:
static void _bind_methods();
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
public:
virtual int get_input_port_count() const override;
@@ -828,7 +829,6 @@ public:
virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
- virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
VisualShaderNodeVaryingSetter();
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index b8667f07fe..3b2b58516d 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -1015,7 +1015,7 @@ Vector<StringName> VisualShaderNodeCurveTexture::get_editable_properties() const
}
String VisualShaderNodeCurveTexture::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- return "uniform sampler2D " + make_unique_id(p_type, p_id, "curve") + ";\n";
+ return "uniform sampler2D " + make_unique_id(p_type, p_id, "curve") + " : repeat_disable;\n";
}
String VisualShaderNodeCurveTexture::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
@@ -1606,6 +1606,51 @@ VisualShaderNodeCubemap::VisualShaderNodeCubemap() {
simple_decl = false;
}
+////////////// Linear Depth
+
+String VisualShaderNodeLinearSceneDepth::get_caption() const {
+ return "LinearSceneDepth";
+}
+
+int VisualShaderNodeLinearSceneDepth::get_input_port_count() const {
+ return 0;
+}
+
+VisualShaderNodeLinearSceneDepth::PortType VisualShaderNodeLinearSceneDepth::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeLinearSceneDepth::get_input_port_name(int p_port) const {
+ return "";
+}
+
+int VisualShaderNodeLinearSceneDepth::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeLinearSceneDepth::PortType VisualShaderNodeLinearSceneDepth::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeLinearSceneDepth::get_output_port_name(int p_port) const {
+ return "linear depth";
+}
+
+String VisualShaderNodeLinearSceneDepth::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+
+ code += " float _log_depth = texture(DEPTH_TEXTURE, SCREEN_UV).x;\n";
+ code += " vec3 _depth_ndc = vec3(SCREEN_UV * 2.0 - 1.0, _log_depth);\n";
+ code += " vec4 _depth_view = INV_PROJECTION_MATRIX * vec4(_depth_ndc, 1.0);\n";
+ code += " _depth_view.xyz /= _depth_view.w;";
+ code += vformat(" %s = -_depth_view.z;", p_output_vars[0]);
+
+ return code;
+}
+
+VisualShaderNodeLinearSceneDepth::VisualShaderNodeLinearSceneDepth() {
+}
+
////////////// Float Op
String VisualShaderNodeFloatOp::get_caption() const {
@@ -1901,13 +1946,7 @@ String VisualShaderNodeVectorOp::generate_code(Shader::Mode p_mode, VisualShader
code += "atan(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
break;
case OP_REFLECT:
- if (op_type == OP_TYPE_VECTOR_2D) { // Not supported.
- code += "vec2(0.0);\n";
- } else if (op_type == OP_TYPE_VECTOR_4D) { // Not supported.
- code += "vec4(0.0);\n";
- } else {
- code += "reflect(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
- }
+ code += "reflect(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
break;
case OP_STEP:
code += "step(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
@@ -1967,7 +2006,7 @@ String VisualShaderNodeVectorOp::get_warning(Shader::Mode p_mode, VisualShader::
bool invalid_type = false;
if (op_type == OP_TYPE_VECTOR_2D || op_type == OP_TYPE_VECTOR_4D) {
- if (op == OP_CROSS || op == OP_REFLECT) {
+ if (op == OP_CROSS) {
invalid_type = true;
}
}
@@ -3096,6 +3135,107 @@ VisualShaderNodeUVFunc::VisualShaderNodeUVFunc() {
set_input_port_default_value(2, Vector2()); // offset
}
+////////////// UV PolarCoord
+
+String VisualShaderNodeUVPolarCoord::get_caption() const {
+ return "UVPolarCoord";
+}
+
+int VisualShaderNodeUVPolarCoord::get_input_port_count() const {
+ return 4;
+}
+
+VisualShaderNodeUVPolarCoord::PortType VisualShaderNodeUVPolarCoord::get_input_port_type(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_VECTOR_2D; // uv
+ case 1:
+ return PORT_TYPE_VECTOR_2D; // center
+ case 2:
+ return PORT_TYPE_SCALAR; // zoom
+ case 3:
+ return PORT_TYPE_SCALAR; // repeat
+ default:
+ break;
+ }
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeUVPolarCoord::get_input_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "uv";
+ case 1:
+ return "scale";
+ case 2:
+ return "zoom strength";
+ case 3:
+ return "repeat";
+ default:
+ break;
+ }
+ return "";
+}
+
+bool VisualShaderNodeUVPolarCoord::is_input_port_default(int p_port, Shader::Mode p_mode) const {
+ if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) {
+ if (p_port == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+int VisualShaderNodeUVPolarCoord::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeUVPolarCoord::PortType VisualShaderNodeUVPolarCoord::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR_2D;
+}
+
+String VisualShaderNodeUVPolarCoord::get_output_port_name(int p_port) const {
+ return "uv";
+}
+
+String VisualShaderNodeUVPolarCoord::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+
+ String uv;
+ if (p_input_vars[0].is_empty()) {
+ if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) {
+ uv = "UV";
+ } else {
+ uv = "vec2(0.0)";
+ }
+ } else {
+ uv = vformat("%s", p_input_vars[0]);
+ }
+ String center = vformat("%s", p_input_vars[1]);
+ String zoom = vformat("%s", p_input_vars[2]);
+ String repeat = vformat("%s", p_input_vars[3]);
+
+ if (p_mode == Shader::MODE_CANVAS_ITEM) {
+ code += vformat(" vec2 __dir = %s - %s;\n", uv, center);
+ code += " float __radius = length(__dir) * 2.0;\n";
+ code += " float __angle = atan(__dir.y, __dir.x) * 1.0/(PI * 2.0);\n";
+ code += vformat(" %s = mod(vec2(__radius * %s, __angle * %s), 1.0);\n", p_output_vars[0], zoom, repeat);
+ } else {
+ code += vformat(" vec2 __dir = %s - %s;\n", uv, center);
+ code += " float __radius = length(__dir) * 2.0;\n";
+ code += " float __angle = atan(__dir.y, __dir.x) * 1.0/(PI * 2.0);\n";
+ code += vformat(" %s = vec2(__radius * %s, __angle * %s);\n", p_output_vars[0], zoom, repeat);
+ }
+
+ return code;
+}
+
+VisualShaderNodeUVPolarCoord::VisualShaderNodeUVPolarCoord() {
+ set_input_port_default_value(1, Vector2(0.5, 0.5)); // center
+ set_input_port_default_value(2, 1.0); // zoom
+ set_input_port_default_value(3, 1.0); // repeat
+}
+
////////////// Dot Product
String VisualShaderNodeDotProduct::get_caption() const {
@@ -4006,14 +4146,6 @@ int VisualShaderNodeVectorRefract::get_input_port_count() const {
return 3;
}
-VisualShaderNodeVectorRefract::PortType VisualShaderNodeVectorRefract::get_input_port_type(int p_port) const {
- if (p_port == 2) {
- return PORT_TYPE_SCALAR;
- }
-
- return PORT_TYPE_VECTOR_3D;
-}
-
String VisualShaderNodeVectorRefract::get_input_port_name(int p_port) const {
switch (p_port) {
case 0:
@@ -4030,10 +4162,6 @@ int VisualShaderNodeVectorRefract::get_output_port_count() const {
return 1;
}
-VisualShaderNodeVectorRefract::PortType VisualShaderNodeVectorRefract::get_output_port_type(int p_port) const {
- return PORT_TYPE_VECTOR_3D;
-}
-
String VisualShaderNodeVectorRefract::get_output_port_name(int p_port) const {
return "";
}
@@ -4042,6 +4170,31 @@ String VisualShaderNodeVectorRefract::generate_code(Shader::Mode p_mode, VisualS
return " " + p_output_vars[0] + " = refract(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n";
}
+void VisualShaderNodeVectorRefract::set_op_type(OpType p_op_type) {
+ ERR_FAIL_INDEX(int(p_op_type), int(OP_TYPE_MAX));
+ if (op_type == p_op_type) {
+ return;
+ }
+ switch (p_op_type) {
+ case OP_TYPE_VECTOR_2D: {
+ set_input_port_default_value(0, Vector2(), get_input_port_default_value(0));
+ set_input_port_default_value(1, Vector2(), get_input_port_default_value(1));
+ } break;
+ case OP_TYPE_VECTOR_3D: {
+ set_input_port_default_value(0, Vector3(), get_input_port_default_value(0));
+ set_input_port_default_value(1, Vector3(), get_input_port_default_value(1));
+ } break;
+ case OP_TYPE_VECTOR_4D: {
+ set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0));
+ set_input_port_default_value(1, Quaternion(), get_input_port_default_value(1));
+ } break;
+ default:
+ break;
+ }
+ op_type = p_op_type;
+ emit_changed();
+}
+
VisualShaderNodeVectorRefract::VisualShaderNodeVectorRefract() {
set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0));
set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0));
@@ -5581,12 +5734,16 @@ String get_sampler_hint(VisualShaderNodeTextureUniform::TextureType p_texture_ty
case VisualShaderNodeTextureUniform::TYPE_DATA:
if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_BLACK) {
type_code = "hint_default_black";
+ } else if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_TRANSPARENT) {
+ type_code = "hint_default_transparent";
}
break;
case VisualShaderNodeTextureUniform::TYPE_COLOR:
type_code = "source_color";
if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_BLACK) {
type_code += ", hint_default_black";
+ } else if (p_color_default == VisualShaderNodeTextureUniform::COLOR_DEFAULT_TRANSPARENT) {
+ type_code += ", hint_default_transparent";
}
break;
case VisualShaderNodeTextureUniform::TYPE_NORMAL_MAP:
@@ -5812,7 +5969,7 @@ void VisualShaderNodeTextureUniform::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_texture_repeat"), &VisualShaderNodeTextureUniform::get_texture_repeat);
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normal Map,Anisotropic"), "set_texture_type", "get_texture_type");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "color_default", PROPERTY_HINT_ENUM, "White,Black"), "set_color_default", "get_color_default");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "color_default", PROPERTY_HINT_ENUM, "White,Black,Transparent"), "set_color_default", "get_color_default");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Default,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropic,Linear Mipmap Anisotropic"), "set_texture_filter", "get_texture_filter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Default,Enabled,Disabled"), "set_texture_repeat", "get_texture_repeat");
@@ -5824,6 +5981,7 @@ void VisualShaderNodeTextureUniform::_bind_methods() {
BIND_ENUM_CONSTANT(COLOR_DEFAULT_WHITE);
BIND_ENUM_CONSTANT(COLOR_DEFAULT_BLACK);
+ BIND_ENUM_CONSTANT(COLOR_DEFAULT_TRANSPARENT);
BIND_ENUM_CONSTANT(COLOR_DEFAULT_MAX);
BIND_ENUM_CONSTANT(FILTER_DEFAULT);
@@ -6818,23 +6976,23 @@ void VisualShaderNodeMultiplyAdd::set_op_type(OpType p_op_type) {
switch (p_op_type) {
case OP_TYPE_SCALAR: {
set_input_port_default_value(0, 0.0, get_input_port_default_value(0));
- set_input_port_default_value(1, 0.0, get_input_port_default_value(1));
+ set_input_port_default_value(1, 1.0, get_input_port_default_value(1));
set_input_port_default_value(2, 0.0, get_input_port_default_value(2));
} break;
case OP_TYPE_VECTOR_2D: {
set_input_port_default_value(0, Vector2(), get_input_port_default_value(0));
- set_input_port_default_value(1, Vector2(), get_input_port_default_value(1));
+ set_input_port_default_value(1, Vector2(1.0, 1.0), get_input_port_default_value(1));
set_input_port_default_value(2, Vector2(), get_input_port_default_value(2));
} break;
case OP_TYPE_VECTOR_3D: {
set_input_port_default_value(0, Vector3(), get_input_port_default_value(0));
- set_input_port_default_value(1, Vector3(), get_input_port_default_value(1));
+ set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0), get_input_port_default_value(1));
set_input_port_default_value(2, Vector3(), get_input_port_default_value(2));
} break;
case OP_TYPE_VECTOR_4D: {
- set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0));
- set_input_port_default_value(1, Quaternion(), get_input_port_default_value(1));
- set_input_port_default_value(2, Quaternion(), get_input_port_default_value(2));
+ set_input_port_default_value(0, Vector4(), get_input_port_default_value(0));
+ set_input_port_default_value(1, Vector4(1.0, 1.0, 1.0, 1.0), get_input_port_default_value(1));
+ set_input_port_default_value(2, Vector4(), get_input_port_default_value(2));
} break;
default:
break;
@@ -6868,7 +7026,7 @@ void VisualShaderNodeMultiplyAdd::_bind_methods() {
VisualShaderNodeMultiplyAdd::VisualShaderNodeMultiplyAdd() {
set_input_port_default_value(0, 0.0);
- set_input_port_default_value(1, 0.0);
+ set_input_port_default_value(1, 1.0);
set_input_port_default_value(2, 0.0);
}
@@ -6998,3 +7156,261 @@ void VisualShaderNodeBillboard::_bind_methods() {
VisualShaderNodeBillboard::VisualShaderNodeBillboard() {
simple_decl = false;
}
+
+////////////// DistanceFade
+
+String VisualShaderNodeDistanceFade::get_caption() const {
+ return "DistanceFade";
+}
+
+int VisualShaderNodeDistanceFade::get_input_port_count() const {
+ return 2;
+}
+
+VisualShaderNodeDistanceFade::PortType VisualShaderNodeDistanceFade::get_input_port_type(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_SCALAR;
+ case 1:
+ return PORT_TYPE_SCALAR;
+ }
+
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeDistanceFade::get_input_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "min";
+ case 1:
+ return "max";
+ }
+
+ return "";
+}
+
+int VisualShaderNodeDistanceFade::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeDistanceFade::PortType VisualShaderNodeDistanceFade::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeDistanceFade::get_output_port_name(int p_port) const {
+ return "amount";
+}
+
+String VisualShaderNodeDistanceFade::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+ code += vformat(" %s = clamp(smoothstep(%s, %s,-VERTEX.z),0.0,1.0);\n", p_output_vars[0], p_input_vars[0], p_input_vars[1]);
+ return code;
+}
+
+VisualShaderNodeDistanceFade::VisualShaderNodeDistanceFade() {
+ set_input_port_default_value(0, 0.0);
+ set_input_port_default_value(1, 10.0);
+}
+
+////////////// ProximityFade
+
+String VisualShaderNodeProximityFade::get_caption() const {
+ return "ProximityFade";
+}
+
+int VisualShaderNodeProximityFade::get_input_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeProximityFade::PortType VisualShaderNodeProximityFade::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeProximityFade::get_input_port_name(int p_port) const {
+ return "distance";
+}
+
+int VisualShaderNodeProximityFade::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeProximityFade::PortType VisualShaderNodeProximityFade::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeProximityFade::get_output_port_name(int p_port) const {
+ return "fade";
+}
+
+String VisualShaderNodeProximityFade::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+
+ String proximity_fade_distance = vformat("%s", p_input_vars[0]);
+ code += " float __depth_tex = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).r;\n";
+ code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, __depth_tex, 1.0);\n";
+ code += " __depth_world_pos.xyz /= __depth_world_pos.z;\n";
+ code += vformat(" %s = clamp(1.0 - smoothstep(__depth_world_pos.z + %s, __depth_world_pos.z, VERTEX.z), 0.0, 1.0);\n", p_output_vars[0], p_input_vars[0]);
+
+ return code;
+}
+
+VisualShaderNodeProximityFade::VisualShaderNodeProximityFade() {
+ set_input_port_default_value(0, 1.0);
+}
+
+////////////// Random Range
+
+String VisualShaderNodeRandomRange::get_caption() const {
+ return "RandomRange";
+}
+
+int VisualShaderNodeRandomRange::get_input_port_count() const {
+ return 3;
+}
+
+VisualShaderNodeRandomRange::PortType VisualShaderNodeRandomRange::get_input_port_type(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_VECTOR_3D;
+ case 1:
+ return PORT_TYPE_SCALAR;
+ case 2:
+ return PORT_TYPE_SCALAR;
+ default:
+ break;
+ }
+
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeRandomRange::get_input_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "seed";
+ case 1:
+ return "min";
+ case 2:
+ return "max";
+ default:
+ break;
+ }
+
+ return "";
+}
+
+int VisualShaderNodeRandomRange::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeRandomRange::PortType VisualShaderNodeRandomRange::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeRandomRange::get_output_port_name(int p_port) const {
+ return "value";
+}
+
+String VisualShaderNodeRandomRange::generate_global_per_node(Shader::Mode p_mode, int p_id) const {
+ String code;
+
+ code += "\n\n";
+ code += "// 3D Noise with friendly permission by Inigo Quilez\n";
+ code += "vec3 hash_noise_range( vec3 p ) {\n";
+ code += " p *= mat3(vec3(127.1, 311.7, -53.7), vec3(269.5, 183.3, 77.1), vec3(-301.7, 27.3, 215.3));\n";
+ code += " return 2.0 * fract(fract(p)*4375.55) -1.;\n";
+ code += "}\n";
+ code += "\n";
+
+ return code;
+}
+
+String VisualShaderNodeRandomRange::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+
+ code += vformat(" %s = mix(%s, %s, hash_noise_range(%s).x);\n", p_output_vars[0], p_input_vars[1], p_input_vars[2], p_input_vars[0]);
+
+ return code;
+}
+
+VisualShaderNodeRandomRange::VisualShaderNodeRandomRange() {
+ set_input_port_default_value(0, Vector3(1.0, 1.0, 1.0));
+ set_input_port_default_value(1, 0.0);
+ set_input_port_default_value(2, 1.0);
+}
+
+////////////// Remap
+
+String VisualShaderNodeRemap::get_caption() const {
+ return "Remap";
+}
+
+int VisualShaderNodeRemap::get_input_port_count() const {
+ return 5;
+}
+
+VisualShaderNodeRemap::PortType VisualShaderNodeRemap::get_input_port_type(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_SCALAR;
+ case 1:
+ return PORT_TYPE_SCALAR;
+ case 2:
+ return PORT_TYPE_SCALAR;
+ case 3:
+ return PORT_TYPE_SCALAR;
+ case 4:
+ return PORT_TYPE_SCALAR;
+ default:
+ break;
+ }
+
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeRemap::get_input_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "value";
+ case 1:
+ return "input min";
+ case 2:
+ return "input max";
+ case 3:
+ return "output min";
+ case 4:
+ return "output max";
+ default:
+ break;
+ }
+
+ return "";
+}
+
+int VisualShaderNodeRemap::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeRemap::PortType VisualShaderNodeRemap::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeRemap::get_output_port_name(int p_port) const {
+ return "value";
+}
+
+String VisualShaderNodeRemap::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+
+ code += vformat(" float _input_range = %s - %s;\n", p_input_vars[2], p_input_vars[1]);
+ code += vformat(" float _output_range = %s - %s;\n", p_input_vars[4], p_input_vars[3]);
+ code += vformat(" %s = %s + _output_range * ((%s - %s) / _input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]);
+
+ return code;
+}
+
+VisualShaderNodeRemap::VisualShaderNodeRemap() {
+ set_input_port_default_value(1, 0.0);
+ set_input_port_default_value(2, 1.0);
+ set_input_port_default_value(3, 0.0);
+ set_input_port_default_value(4, 1.0);
+}
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index 1eb7b7240f..c603a10eae 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -622,6 +622,27 @@ VARIANT_ENUM_CAST(VisualShaderNodeCubemap::TextureType)
VARIANT_ENUM_CAST(VisualShaderNodeCubemap::Source)
///////////////////////////////////////
+
+class VisualShaderNodeLinearSceneDepth : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeLinearSceneDepth, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeLinearSceneDepth();
+};
+
+///////////////////////////////////////
/// OPS
///////////////////////////////////////
@@ -1231,6 +1252,30 @@ public:
VARIANT_ENUM_CAST(VisualShaderNodeUVFunc::Function)
///////////////////////////////////////
+/// UV POLARCOORD
+///////////////////////////////////////
+
+class VisualShaderNodeUVPolarCoord : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeUVPolarCoord, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+ virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeUVPolarCoord();
+};
+
+///////////////////////////////////////
/// DOT
///////////////////////////////////////
@@ -1564,21 +1609,20 @@ public:
/// REFRACT
///////////////////////////////////////
-class VisualShaderNodeVectorRefract : public VisualShaderNode {
- GDCLASS(VisualShaderNodeVectorRefract, VisualShaderNode);
+class VisualShaderNodeVectorRefract : public VisualShaderNodeVectorBase {
+ GDCLASS(VisualShaderNodeVectorRefract, VisualShaderNodeVectorBase);
public:
virtual String get_caption() const override;
virtual int get_input_port_count() const override;
- virtual PortType get_input_port_type(int p_port) const override;
virtual String get_input_port_name(int p_port) const override;
virtual int get_output_port_count() const override;
- virtual PortType get_output_port_type(int p_port) const override;
virtual String get_output_port_name(int p_port) const override;
virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+ virtual void set_op_type(OpType p_op_type) override;
VisualShaderNodeVectorRefract();
};
@@ -2131,6 +2175,7 @@ public:
enum ColorDefault {
COLOR_DEFAULT_WHITE,
COLOR_DEFAULT_BLACK,
+ COLOR_DEFAULT_TRANSPARENT,
COLOR_DEFAULT_MAX,
};
@@ -2574,4 +2619,85 @@ public:
VARIANT_ENUM_CAST(VisualShaderNodeBillboard::BillboardType)
+///////////////////////////////////////
+/// DistanceFade
+///////////////////////////////////////
+
+class VisualShaderNodeDistanceFade : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeDistanceFade, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeDistanceFade();
+};
+
+class VisualShaderNodeProximityFade : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeProximityFade, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeProximityFade();
+};
+
+class VisualShaderNodeRandomRange : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeRandomRange, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_global_per_node(Shader::Mode p_mode, int p_id) const override;
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeRandomRange();
+};
+
+class VisualShaderNodeRemap : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeRemap, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeRemap();
+};
+
#endif // VISUAL_SHADER_NODES_H
diff --git a/scene/theme/SCsub b/scene/theme/SCsub
new file mode 100644
index 0000000000..fc61250247
--- /dev/null
+++ b/scene/theme/SCsub
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.scene_sources, "*.cpp")
diff --git a/scene/theme/theme_db.cpp b/scene/theme/theme_db.cpp
new file mode 100644
index 0000000000..d6e892cd93
--- /dev/null
+++ b/scene/theme/theme_db.cpp
@@ -0,0 +1,237 @@
+/*************************************************************************/
+/* theme_db.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "theme_db.h"
+
+#include "core/config/project_settings.h"
+#include "core/io/resource_loader.h"
+#include "scene/resources/default_theme/default_theme.h"
+#include "scene/resources/font.h"
+#include "scene/resources/style_box.h"
+#include "scene/resources/texture.h"
+#include "scene/resources/theme.h"
+#include "servers/text_server.h"
+
+// Default engine theme creation and configuration.
+void ThemeDB::initialize_theme() {
+ // Allow creating the default theme at a different scale to suit higher/lower base resolutions.
+ float default_theme_scale = GLOBAL_DEF("gui/theme/default_theme_scale", 1.0);
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_theme_scale", PropertyInfo(Variant::FLOAT, "gui/theme/default_theme_scale", PROPERTY_HINT_RANGE, "0.5,8,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
+
+ String theme_path = GLOBAL_DEF_RST("gui/theme/custom", "");
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom", PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
+
+ String font_path = GLOBAL_DEF_RST("gui/theme/custom_font", "");
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom_font", PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
+
+ TextServer::FontAntialiasing font_antialiasing = (TextServer::FontAntialiasing)(int)GLOBAL_DEF_RST("gui/theme/default_font_antialiasing", 1);
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_antialiasing", PropertyInfo(Variant::INT, "gui/theme/default_font_antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD sub-pixel", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
+
+ TextServer::Hinting font_hinting = (TextServer::Hinting)(int)GLOBAL_DEF_RST("gui/theme/default_font_hinting", TextServer::HINTING_LIGHT);
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_hinting", PropertyInfo(Variant::INT, "gui/theme/default_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
+
+ TextServer::SubpixelPositioning font_subpixel_positioning = (TextServer::SubpixelPositioning)(int)GLOBAL_DEF_RST("gui/theme/default_font_subpixel_positioning", TextServer::SUBPIXEL_POSITIONING_AUTO);
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_subpixel_positioning", PropertyInfo(Variant::INT, "gui/theme/default_font_subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One half of a pixel,One quarter of a pixel", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
+
+ const bool font_msdf = GLOBAL_DEF_RST("gui/theme/default_font_multichannel_signed_distance_field", false);
+ const bool font_generate_mipmaps = GLOBAL_DEF_RST("gui/theme/default_font_generate_mipmaps", false);
+
+ GLOBAL_DEF_RST("gui/theme/lcd_subpixel_layout", 1);
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/lcd_subpixel_layout", PropertyInfo(Variant::INT, "gui/theme/lcd_subpixel_layout", PROPERTY_HINT_ENUM, "Disabled,Horizontal RGB,Horizontal BGR,Vertical RGB,Vertical BGR"));
+ ProjectSettings::get_singleton()->set_restart_if_changed("gui/theme/lcd_subpixel_layout", false);
+
+ Ref<Font> font;
+ if (!font_path.is_empty()) {
+ font = ResourceLoader::load(font_path);
+ if (!font.is_valid()) {
+ ERR_PRINT("Error loading custom font '" + font_path + "'");
+ }
+ }
+
+ // Always make the default theme to avoid invalid default font/icon/style in the given theme.
+ if (RenderingServer::get_singleton()) {
+ make_default_theme(default_theme_scale, font, font_subpixel_positioning, font_hinting, font_antialiasing, font_msdf, font_generate_mipmaps);
+ }
+
+ if (!theme_path.is_empty()) {
+ Ref<Theme> theme = ResourceLoader::load(theme_path);
+ if (theme.is_valid()) {
+ set_project_theme(theme);
+ if (font.is_valid()) {
+ set_fallback_font(font);
+ }
+ } else {
+ ERR_PRINT("Error loading custom theme '" + theme_path + "'");
+ }
+ }
+}
+
+void ThemeDB::initialize_theme_noproject() {
+ if (RenderingServer::get_singleton()) {
+ make_default_theme(1.0, Ref<Font>());
+ }
+}
+
+// Universal fallback Theme resources.
+
+void ThemeDB::set_default_theme(const Ref<Theme> &p_default) {
+ default_theme = p_default;
+}
+
+Ref<Theme> ThemeDB::get_default_theme() {
+ return default_theme;
+}
+
+void ThemeDB::set_project_theme(const Ref<Theme> &p_project_default) {
+ project_theme = p_project_default;
+}
+
+Ref<Theme> ThemeDB::get_project_theme() {
+ return project_theme;
+}
+
+// Universal fallback values for theme item types.
+
+void ThemeDB::set_fallback_base_scale(float p_base_scale) {
+ if (fallback_base_scale == p_base_scale) {
+ return;
+ }
+
+ fallback_base_scale = p_base_scale;
+ emit_signal(SNAME("fallback_changed"));
+}
+
+float ThemeDB::get_fallback_base_scale() {
+ return fallback_base_scale;
+}
+
+void ThemeDB::set_fallback_font(const Ref<Font> &p_font) {
+ if (fallback_font == p_font) {
+ return;
+ }
+
+ fallback_font = p_font;
+ emit_signal(SNAME("fallback_changed"));
+}
+
+Ref<Font> ThemeDB::get_fallback_font() {
+ return fallback_font;
+}
+
+void ThemeDB::set_fallback_font_size(int p_font_size) {
+ if (fallback_font_size == p_font_size) {
+ return;
+ }
+
+ fallback_font_size = p_font_size;
+ emit_signal(SNAME("fallback_changed"));
+}
+
+int ThemeDB::get_fallback_font_size() {
+ return fallback_font_size;
+}
+
+void ThemeDB::set_fallback_icon(const Ref<Texture2D> &p_icon) {
+ if (fallback_icon == p_icon) {
+ return;
+ }
+
+ fallback_icon = p_icon;
+ emit_signal(SNAME("fallback_changed"));
+}
+
+Ref<Texture2D> ThemeDB::get_fallback_icon() {
+ return fallback_icon;
+}
+
+void ThemeDB::set_fallback_stylebox(const Ref<StyleBox> &p_stylebox) {
+ if (fallback_stylebox == p_stylebox) {
+ return;
+ }
+
+ fallback_stylebox = p_stylebox;
+ emit_signal(SNAME("fallback_changed"));
+}
+
+Ref<StyleBox> ThemeDB::get_fallback_stylebox() {
+ return fallback_stylebox;
+}
+
+// Object methods.
+void ThemeDB::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_default_theme"), &ThemeDB::get_default_theme);
+ ClassDB::bind_method(D_METHOD("get_project_theme"), &ThemeDB::get_project_theme);
+
+ ClassDB::bind_method(D_METHOD("set_fallback_base_scale", "base_scale"), &ThemeDB::set_fallback_base_scale);
+ ClassDB::bind_method(D_METHOD("get_fallback_base_scale"), &ThemeDB::get_fallback_base_scale);
+ ClassDB::bind_method(D_METHOD("set_fallback_font", "font"), &ThemeDB::set_fallback_font);
+ ClassDB::bind_method(D_METHOD("get_fallback_font"), &ThemeDB::get_fallback_font);
+ ClassDB::bind_method(D_METHOD("set_fallback_font_size", "font_size"), &ThemeDB::set_fallback_font_size);
+ ClassDB::bind_method(D_METHOD("get_fallback_font_size"), &ThemeDB::get_fallback_font_size);
+ ClassDB::bind_method(D_METHOD("set_fallback_icon", "icon"), &ThemeDB::set_fallback_icon);
+ ClassDB::bind_method(D_METHOD("get_fallback_icon"), &ThemeDB::get_fallback_icon);
+ ClassDB::bind_method(D_METHOD("set_fallback_stylebox", "stylebox"), &ThemeDB::set_fallback_stylebox);
+ ClassDB::bind_method(D_METHOD("get_fallback_stylebox"), &ThemeDB::get_fallback_stylebox);
+
+ ADD_GROUP("Fallback values", "fallback_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fallback_base_scale", PROPERTY_HINT_RANGE, "0.0,2.0,0.01,or_greater"), "set_fallback_base_scale", "get_fallback_base_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_font", PROPERTY_HINT_RESOURCE_TYPE, "Font", PROPERTY_USAGE_NONE), "set_fallback_font", "get_fallback_font");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "fallback_font_size", PROPERTY_HINT_RANGE, "0,256,1,or_greater,suffix:px"), "set_fallback_font_size", "get_fallback_font_size");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_NONE), "set_fallback_icon", "get_fallback_icon");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_stylebox", PROPERTY_HINT_RESOURCE_TYPE, "StyleBox", PROPERTY_USAGE_NONE), "set_fallback_stylebox", "get_fallback_stylebox");
+
+ ADD_SIGNAL(MethodInfo("fallback_changed"));
+}
+
+// Memory management, reference, and initialization
+ThemeDB *ThemeDB::singleton = nullptr;
+
+ThemeDB *ThemeDB::get_singleton() {
+ return singleton;
+}
+
+ThemeDB::ThemeDB() {
+ singleton = this;
+
+ // Universal default values, final fallback for every theme.
+ fallback_base_scale = 1.0;
+ fallback_font_size = 16;
+}
+
+ThemeDB::~ThemeDB() {
+ default_theme.unref();
+ project_theme.unref();
+
+ fallback_font.unref();
+ fallback_icon.unref();
+ fallback_stylebox.unref();
+
+ singleton = nullptr;
+}
diff --git a/modules/websocket/emws_server.h b/scene/theme/theme_db.h
index 14a9449605..aace33d82c 100644
--- a/modules/websocket/emws_server.h
+++ b/scene/theme/theme_db.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* emws_server.h */
+/* theme_db.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,37 +28,68 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef EMWS_SERVER_H
-#define EMWS_SERVER_H
-
-#ifdef JAVASCRIPT_ENABLED
+#ifndef THEME_DB_H
+#define THEME_DB_H
+#include "core/object/class_db.h"
#include "core/object/ref_counted.h"
-#include "emws_peer.h"
-#include "websocket_server.h"
-class EMWSServer : public WebSocketServer {
- GDCIIMPL(EMWSServer, WebSocketServer);
+class Font;
+class StyleBox;
+class Texture2D;
+class Theme;
+
+class ThemeDB : public Object {
+ GDCLASS(ThemeDB, Object);
+
+ static ThemeDB *singleton;
+
+ // Universal Theme resources used when no other theme has the item.
+ Ref<Theme> default_theme;
+ Ref<Theme> project_theme;
+
+ // Universal default values, final fallback for every theme.
+ float fallback_base_scale;
+ Ref<Font> fallback_font;
+ int fallback_font_size;
+ Ref<Texture2D> fallback_icon;
+ Ref<StyleBox> fallback_stylebox;
+
+protected:
+ static void _bind_methods();
public:
- Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) override;
- void set_extra_headers(const Vector<String> &p_headers) override;
- Error listen(int p_port, Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false) override;
- void stop() override;
- bool is_listening() const override;
- bool has_peer(int p_id) const override;
- Ref<WebSocketPeer> get_peer(int p_id) const override;
- IPAddress get_peer_address(int p_peer_id) const override;
- int get_peer_port(int p_peer_id) const override;
- void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "") override;
- int get_max_packet_size() const override;
- virtual void poll() override;
- virtual Vector<String> get_protocols() const;
-
- EMWSServer();
- ~EMWSServer();
-};
+ void initialize_theme();
+ void initialize_theme_noproject();
+
+ // Universal Theme resources
+
+ void set_default_theme(const Ref<Theme> &p_default);
+ Ref<Theme> get_default_theme();
-#endif
+ void set_project_theme(const Ref<Theme> &p_project_default);
+ Ref<Theme> get_project_theme();
+
+ // Universal default values.
+
+ void set_fallback_base_scale(float p_base_scale);
+ float get_fallback_base_scale();
+
+ void set_fallback_font(const Ref<Font> &p_font);
+ Ref<Font> get_fallback_font();
+
+ void set_fallback_font_size(int p_font_size);
+ int get_fallback_font_size();
+
+ void set_fallback_icon(const Ref<Texture2D> &p_icon);
+ Ref<Texture2D> get_fallback_icon();
+
+ void set_fallback_stylebox(const Ref<StyleBox> &p_stylebox);
+ Ref<StyleBox> get_fallback_stylebox();
+
+ static ThemeDB *get_singleton();
+ ThemeDB();
+ ~ThemeDB();
+};
-#endif // EMWS_SERVER_H
+#endif // THEME_DB_H
diff --git a/servers/audio/audio_driver_dummy.cpp b/servers/audio/audio_driver_dummy.cpp
index 60eb657923..729f278d4b 100644
--- a/servers/audio/audio_driver_dummy.cpp
+++ b/servers/audio/audio_driver_dummy.cpp
@@ -36,9 +36,8 @@
AudioDriverDummy *AudioDriverDummy::singleton = nullptr;
Error AudioDriverDummy::init() {
- active = false;
- thread_exited = false;
- exit_thread = false;
+ active.clear();
+ exit_thread.clear();
samples_in = nullptr;
if (mix_rate == -1) {
@@ -60,23 +59,23 @@ void AudioDriverDummy::thread_func(void *p_udata) {
uint64_t usdelay = (ad->buffer_frames / float(ad->mix_rate)) * 1000000;
- while (!ad->exit_thread) {
- if (ad->active) {
+ while (!ad->exit_thread.is_set()) {
+ if (ad->active.is_set()) {
ad->lock();
+ ad->start_counting_ticks();
ad->audio_server_process(ad->buffer_frames, ad->samples_in);
+ ad->stop_counting_ticks();
ad->unlock();
};
OS::get_singleton()->delay_usec(usdelay);
};
-
- ad->thread_exited = true;
};
void AudioDriverDummy::start() {
- active = true;
+ active.set();
};
int AudioDriverDummy::get_mix_rate() const {
@@ -113,7 +112,7 @@ uint32_t AudioDriverDummy::get_channels() const {
}
void AudioDriverDummy::mix_audio(int p_frames, int32_t *p_buffer) {
- ERR_FAIL_COND(!active); // If not active, should not mix.
+ ERR_FAIL_COND(!active.is_set()); // If not active, should not mix.
ERR_FAIL_COND(use_threads == true); // If using threads, this will not work well.
uint32_t todo = p_frames;
@@ -136,7 +135,7 @@ void AudioDriverDummy::mix_audio(int p_frames, int32_t *p_buffer) {
void AudioDriverDummy::finish() {
if (use_threads) {
- exit_thread = true;
+ exit_thread.set();
thread.wait_to_finish();
}
diff --git a/servers/audio/audio_driver_dummy.h b/servers/audio/audio_driver_dummy.h
index 8f47e64d8b..46dd2e1439 100644
--- a/servers/audio/audio_driver_dummy.h
+++ b/servers/audio/audio_driver_dummy.h
@@ -35,6 +35,7 @@
#include "core/os/mutex.h"
#include "core/os/thread.h"
+#include "core/templates/safe_refcount.h"
class AudioDriverDummy : public AudioDriver {
Thread thread;
@@ -50,9 +51,8 @@ class AudioDriverDummy : public AudioDriver {
int channels;
- bool active;
- bool thread_exited;
- mutable bool exit_thread;
+ SafeFlag active;
+ SafeFlag exit_thread;
bool use_threads = true;
diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp
index 80485845c9..4252131161 100644
--- a/servers/audio/audio_stream.cpp
+++ b/servers/audio/audio_stream.cpp
@@ -782,7 +782,7 @@ void AudioStreamPlaybackRandomizer::start(float p_from_pos) {
float range_to = randomizer->random_volume_offset_db;
float volume_offset_db = range_from + Math::randf() * (range_to - range_from);
- volume_scale = Math::db2linear(volume_offset_db);
+ volume_scale = Math::db_to_linear(volume_offset_db);
}
if (playing.is_valid()) {
diff --git a/servers/audio/effects/audio_effect_amplify.cpp b/servers/audio/effects/audio_effect_amplify.cpp
index 87d46f8bbe..2889562173 100644
--- a/servers/audio/effects/audio_effect_amplify.cpp
+++ b/servers/audio/effects/audio_effect_amplify.cpp
@@ -33,8 +33,8 @@
void AudioEffectAmplifyInstance::process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) {
//multiply volume interpolating to avoid clicks if this changes
float volume_db = base->volume_db;
- float vol = Math::db2linear(mix_volume_db);
- float vol_inc = (Math::db2linear(volume_db) - vol) / float(p_frame_count);
+ float vol = Math::db_to_linear(mix_volume_db);
+ float vol_inc = (Math::db_to_linear(volume_db) - vol) / float(p_frame_count);
for (int i = 0; i < p_frame_count; i++) {
p_dst_frames[i] = p_src_frames[i] * vol;
diff --git a/servers/audio/effects/audio_effect_chorus.cpp b/servers/audio/effects/audio_effect_chorus.cpp
index e5434eac02..69b416f5f7 100644
--- a/servers/audio/effects/audio_effect_chorus.cpp
+++ b/servers/audio/effects/audio_effect_chorus.cpp
@@ -95,7 +95,7 @@ void AudioEffectChorusInstance::_process_chunk(const AudioFrame *p_src_frames, A
//vol modifier
- AudioFrame vol_modifier = AudioFrame(base->wet, base->wet) * Math::db2linear(v.level);
+ AudioFrame vol_modifier = AudioFrame(base->wet, base->wet) * Math::db_to_linear(v.level);
vol_modifier.l *= CLAMP(1.0 - v.pan, 0, 1);
vol_modifier.r *= CLAMP(1.0 + v.pan, 0, 1);
@@ -272,11 +272,11 @@ float AudioEffectChorus::get_dry() const {
return dry;
}
-void AudioEffectChorus::_validate_property(PropertyInfo &property) const {
- if (property.name.begins_with("voice/")) {
- int voice_idx = property.name.get_slice("/", 1).to_int();
+void AudioEffectChorus::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name.begins_with("voice/")) {
+ int voice_idx = p_property.name.get_slice("/", 1).to_int();
if (voice_idx > voice_count) {
- property.usage = PROPERTY_USAGE_NONE;
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
}
diff --git a/servers/audio/effects/audio_effect_chorus.h b/servers/audio/effects/audio_effect_chorus.h
index 72b495f7f9..dd4b431e7a 100644
--- a/servers/audio/effects/audio_effect_chorus.h
+++ b/servers/audio/effects/audio_effect_chorus.h
@@ -96,7 +96,7 @@ private:
float dry;
protected:
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
diff --git a/servers/audio/effects/audio_effect_compressor.cpp b/servers/audio/effects/audio_effect_compressor.cpp
index ee71a6dba7..43b210e450 100644
--- a/servers/audio/effects/audio_effect_compressor.cpp
+++ b/servers/audio/effects/audio_effect_compressor.cpp
@@ -32,7 +32,7 @@
#include "servers/audio_server.h"
void AudioEffectCompressorInstance::process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) {
- float threshold = Math::db2linear(base->threshold);
+ float threshold = Math::db_to_linear(base->threshold);
float sample_rate = AudioServer::get_singleton()->get_mix_rate();
float ratatcoef = exp(-1 / (0.00001f * sample_rate));
@@ -42,7 +42,7 @@ void AudioEffectCompressorInstance::process(const AudioFrame *p_src_frames, Audi
float atcoef = exp(-1 / (attime * sample_rate));
float relcoef = exp(-1 / (reltime * sample_rate));
- float makeup = Math::db2linear(base->gain);
+ float makeup = Math::db_to_linear(base->gain);
float mix = base->mix;
float gr_meter_decay = exp(1 / (1 * sample_rate));
@@ -64,7 +64,7 @@ void AudioEffectCompressorInstance::process(const AudioFrame *p_src_frames, Audi
float peak = MAX(s.l, s.r);
- float overdb = 2.08136898f * Math::linear2db(peak / threshold);
+ float overdb = 2.08136898f * Math::linear_to_db(peak / threshold);
if (overdb < 0.0) { //we only care about what goes over to compress
overdb = 0.0;
@@ -94,7 +94,7 @@ void AudioEffectCompressorInstance::process(const AudioFrame *p_src_frames, Audi
}
float gr = -overdb * (cratio - 1) / cratio;
- float grv = Math::db2linear(gr);
+ float grv = Math::db_to_linear(gr);
runmax = maxover + relcoef * (runmax - maxover); // highest peak for setting att/rel decays in reltime
maxover = runmax;
@@ -184,15 +184,15 @@ StringName AudioEffectCompressor::get_sidechain() const {
return sidechain;
}
-void AudioEffectCompressor::_validate_property(PropertyInfo &property) const {
- if (property.name == "sidechain") {
+void AudioEffectCompressor::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "sidechain") {
String buses = "";
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
buses += ",";
buses += AudioServer::get_singleton()->get_bus_name(i);
}
- property.hint_string = buses;
+ p_property.hint_string = buses;
}
}
diff --git a/servers/audio/effects/audio_effect_compressor.h b/servers/audio/effects/audio_effect_compressor.h
index 998bd3c978..886255b958 100644
--- a/servers/audio/effects/audio_effect_compressor.h
+++ b/servers/audio/effects/audio_effect_compressor.h
@@ -61,7 +61,7 @@ class AudioEffectCompressor : public AudioEffect {
StringName sidechain;
protected:
- void _validate_property(PropertyInfo &property) const override;
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
public:
diff --git a/servers/audio/effects/audio_effect_delay.cpp b/servers/audio/effects/audio_effect_delay.cpp
index 80e7a8223c..f71ff05b23 100644
--- a/servers/audio/effects/audio_effect_delay.cpp
+++ b/servers/audio/effects/audio_effect_delay.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "audio_effect_delay.h"
+
#include "core/math/math_funcs.h"
#include "servers/audio_server.h"
@@ -52,13 +53,13 @@ void AudioEffectDelayInstance::_process_chunk(const AudioFrame *p_src_frames, Au
float mix_rate = AudioServer::get_singleton()->get_mix_rate();
- float tap_1_level_f = base->tap_1_active ? Math::db2linear(base->tap_1_level) : 0.0;
+ float tap_1_level_f = base->tap_1_active ? Math::db_to_linear(base->tap_1_level) : 0.0;
int tap_1_delay_frames = int((base->tap_1_delay_ms / 1000.0) * mix_rate);
- float tap_2_level_f = base->tap_2_active ? Math::db2linear(base->tap_2_level) : 0.0;
+ float tap_2_level_f = base->tap_2_active ? Math::db_to_linear(base->tap_2_level) : 0.0;
int tap_2_delay_frames = int((base->tap_2_delay_ms / 1000.0) * mix_rate);
- float feedback_level_f = base->feedback_active ? Math::db2linear(base->feedback_level) : 0.0;
+ float feedback_level_f = base->feedback_active ? Math::db_to_linear(base->feedback_level) : 0.0;
unsigned int feedback_delay_frames = int((base->feedback_delay_ms / 1000.0) * mix_rate);
AudioFrame tap1_vol = AudioFrame(tap_1_level_f, tap_1_level_f);
@@ -286,37 +287,21 @@ void AudioEffectDelay::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dry", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dry", "get_dry");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tap1/active"), "set_tap1_active", "is_tap1_active");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap1/delay_ms", PROPERTY_HINT_RANGE, "0,1500,1,suffix:ms"), "set_tap1_delay_ms", "get_tap1_delay_ms");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap1/level_db", PROPERTY_HINT_RANGE, "-60,0,0.01,suffix:dB"), "set_tap1_level_db", "get_tap1_level_db");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap1/pan", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_tap1_pan", "get_tap1_pan");
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tap2/active"), "set_tap2_active", "is_tap2_active");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap2/delay_ms", PROPERTY_HINT_RANGE, "0,1500,1,suffix:ms"), "set_tap2_delay_ms", "get_tap2_delay_ms");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap2/level_db", PROPERTY_HINT_RANGE, "-60,0,0.01,suffix:dB"), "set_tap2_level_db", "get_tap2_level_db");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap2/pan", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_tap2_pan", "get_tap2_pan");
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "feedback/active"), "set_feedback_active", "is_feedback_active");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "feedback/delay_ms", PROPERTY_HINT_RANGE, "0,1500,1,suffix:ms"), "set_feedback_delay_ms", "get_feedback_delay_ms");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "feedback/level_db", PROPERTY_HINT_RANGE, "-60,0,0.01,suffix:dB"), "set_feedback_level_db", "get_feedback_level_db");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "feedback/lowpass", PROPERTY_HINT_RANGE, "1,16000,1"), "set_feedback_lowpass", "get_feedback_lowpass");
-}
-
-AudioEffectDelay::AudioEffectDelay() {
- tap_1_active = true;
- tap_1_delay_ms = 250;
- tap_1_level = -6;
- tap_1_pan = 0.2;
-
- tap_2_active = true;
- tap_2_delay_ms = 500;
- tap_2_level = -12;
- tap_2_pan = -0.4;
-
- feedback_active = false;
- feedback_delay_ms = 340;
- feedback_level = -6;
- feedback_lowpass = 16000;
-
- dry = 1.0;
+ ADD_GROUP("Tap 1", "tap1_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tap1_active"), "set_tap1_active", "is_tap1_active");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap1_delay_ms", PROPERTY_HINT_RANGE, "0,1500,1,suffix:ms"), "set_tap1_delay_ms", "get_tap1_delay_ms");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap1_level_db", PROPERTY_HINT_RANGE, "-60,0,0.01,suffix:dB"), "set_tap1_level_db", "get_tap1_level_db");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap1_pan", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_tap1_pan", "get_tap1_pan");
+
+ ADD_GROUP("Tap 2", "tap2_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tap2_active"), "set_tap2_active", "is_tap2_active");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap2_delay_ms", PROPERTY_HINT_RANGE, "0,1500,1,suffix:ms"), "set_tap2_delay_ms", "get_tap2_delay_ms");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap2_level_db", PROPERTY_HINT_RANGE, "-60,0,0.01,suffix:dB"), "set_tap2_level_db", "get_tap2_level_db");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tap2_pan", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_tap2_pan", "get_tap2_pan");
+
+ ADD_GROUP("Feedback", "feedback_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "feedback_active"), "set_feedback_active", "is_feedback_active");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "feedback_delay_ms", PROPERTY_HINT_RANGE, "0,1500,1,suffix:ms"), "set_feedback_delay_ms", "get_feedback_delay_ms");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "feedback_level_db", PROPERTY_HINT_RANGE, "-60,0,0.01,suffix:dB"), "set_feedback_level_db", "get_feedback_level_db");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "feedback_lowpass", PROPERTY_HINT_RANGE, "1,16000,1"), "set_feedback_lowpass", "get_feedback_lowpass");
}
diff --git a/servers/audio/effects/audio_effect_delay.h b/servers/audio/effects/audio_effect_delay.h
index 137a4e7dbe..020d45e79b 100644
--- a/servers/audio/effects/audio_effect_delay.h
+++ b/servers/audio/effects/audio_effect_delay.h
@@ -37,6 +37,7 @@ class AudioEffectDelay;
class AudioEffectDelayInstance : public AudioEffectInstance {
GDCLASS(AudioEffectDelayInstance, AudioEffectInstance);
+
friend class AudioEffectDelay;
Ref<AudioEffectDelay> base;
@@ -66,22 +67,22 @@ class AudioEffectDelay : public AudioEffect {
MAX_TAPS = 2
};
- float dry;
+ float dry = 1.0f;
- bool tap_1_active;
- float tap_1_delay_ms;
- float tap_1_level;
- float tap_1_pan;
+ bool tap_1_active = true;
+ float tap_1_delay_ms = 250.0f;
+ float tap_1_level = -6.0f;
+ float tap_1_pan = 0.2f;
- bool tap_2_active;
- float tap_2_delay_ms;
- float tap_2_level;
- float tap_2_pan;
+ bool tap_2_active = true;
+ float tap_2_delay_ms = 500.0f;
+ float tap_2_level = -12.0f;
+ float tap_2_pan = -0.4f;
- bool feedback_active;
- float feedback_delay_ms;
- float feedback_level;
- float feedback_lowpass;
+ bool feedback_active = false;
+ float feedback_delay_ms = 340.0f;
+ float feedback_level = -6.0f;
+ float feedback_lowpass = 16000.0f;
protected:
static void _bind_methods();
@@ -128,7 +129,7 @@ public:
Ref<AudioEffectInstance> instantiate() override;
- AudioEffectDelay();
+ AudioEffectDelay() {}
};
#endif // AUDIO_EFFECT_DELAY_H
diff --git a/servers/audio/effects/audio_effect_distortion.cpp b/servers/audio/effects/audio_effect_distortion.cpp
index 6820d796a4..5987ed7bb2 100644
--- a/servers/audio/effects/audio_effect_distortion.cpp
+++ b/servers/audio/effects/audio_effect_distortion.cpp
@@ -41,8 +41,8 @@ void AudioEffectDistortionInstance::process(const AudioFrame *p_src_frames, Audi
float lpf_ic = 1.0 - lpf_c;
float drive_f = base->drive;
- float pregain_f = Math::db2linear(base->pre_gain);
- float postgain_f = Math::db2linear(base->post_gain);
+ float pregain_f = Math::db_to_linear(base->pre_gain);
+ float postgain_f = Math::db_to_linear(base->post_gain);
float atan_mult = pow(10, drive_f * drive_f * 3.0) - 1.0 + 0.001;
float atan_div = 1.0 / (atanf(atan_mult) * (1.0 + drive_f * 8));
diff --git a/servers/audio/effects/audio_effect_eq.cpp b/servers/audio/effects/audio_effect_eq.cpp
index 500abd3a6f..14ece8d93e 100644
--- a/servers/audio/effects/audio_effect_eq.cpp
+++ b/servers/audio/effects/audio_effect_eq.cpp
@@ -38,7 +38,7 @@ void AudioEffectEQInstance::process(const AudioFrame *p_src_frames, AudioFrame *
EQ::BandProcess *proc_r = bands[1].ptrw();
float *bgain = gains.ptrw();
for (int i = 0; i < band_count; i++) {
- bgain[i] = Math::db2linear(base->gain[i]);
+ bgain[i] = Math::db_to_linear(base->gain[i]);
}
for (int i = 0; i < p_frame_count; i++) {
diff --git a/servers/audio/effects/audio_effect_filter.h b/servers/audio/effects/audio_effect_filter.h
index a40af2f13c..1510ee2af7 100644
--- a/servers/audio/effects/audio_effect_filter.h
+++ b/servers/audio/effects/audio_effect_filter.h
@@ -98,9 +98,9 @@ VARIANT_ENUM_CAST(AudioEffectFilter::FilterDB)
class AudioEffectLowPassFilter : public AudioEffectFilter {
GDCLASS(AudioEffectLowPassFilter, AudioEffectFilter);
- void _validate_property(PropertyInfo &property) const override {
- if (property.name == "gain") {
- property.usage = PROPERTY_USAGE_NONE;
+ void _validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "gain") {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
@@ -111,9 +111,9 @@ public:
class AudioEffectHighPassFilter : public AudioEffectFilter {
GDCLASS(AudioEffectHighPassFilter, AudioEffectFilter);
- void _validate_property(PropertyInfo &property) const override {
- if (property.name == "gain") {
- property.usage = PROPERTY_USAGE_NONE;
+ void _validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "gain") {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
@@ -124,9 +124,9 @@ public:
class AudioEffectBandPassFilter : public AudioEffectFilter {
GDCLASS(AudioEffectBandPassFilter, AudioEffectFilter);
- void _validate_property(PropertyInfo &property) const override {
- if (property.name == "gain") {
- property.usage = PROPERTY_USAGE_NONE;
+ void _validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "gain") {
+ p_property.usage = PROPERTY_USAGE_NONE;
}
}
diff --git a/servers/audio/effects/audio_effect_limiter.cpp b/servers/audio/effects/audio_effect_limiter.cpp
index 7bcd68d48b..99653cf5b6 100644
--- a/servers/audio/effects/audio_effect_limiter.cpp
+++ b/servers/audio/effects/audio_effect_limiter.cpp
@@ -32,11 +32,11 @@
void AudioEffectLimiterInstance::process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) {
float threshdb = base->threshold;
- float ceiling = Math::db2linear(base->ceiling);
+ float ceiling = Math::db_to_linear(base->ceiling);
float ceildb = base->ceiling;
- float makeup = Math::db2linear(ceildb - threshdb);
+ float makeup = Math::db_to_linear(ceildb - threshdb);
float sc = -base->soft_clip;
- float scv = Math::db2linear(sc);
+ float scv = Math::db_to_linear(sc);
float peakdb = ceildb + 25;
float scmult = Math::abs((ceildb - sc) / (peakdb - sc));
@@ -49,14 +49,14 @@ void AudioEffectLimiterInstance::process(const AudioFrame *p_src_frames, AudioFr
float sign1 = (spl1 < 0.0 ? -1.0 : 1.0);
float abs0 = Math::abs(spl0);
float abs1 = Math::abs(spl1);
- float overdb0 = Math::linear2db(abs0) - ceildb;
- float overdb1 = Math::linear2db(abs1) - ceildb;
+ float overdb0 = Math::linear_to_db(abs0) - ceildb;
+ float overdb1 = Math::linear_to_db(abs1) - ceildb;
if (abs0 > scv) {
- spl0 = sign0 * (scv + Math::db2linear(overdb0 * scmult));
+ spl0 = sign0 * (scv + Math::db_to_linear(overdb0 * scmult));
}
if (abs1 > scv) {
- spl1 = sign1 * (scv + Math::db2linear(overdb1 * scmult));
+ spl1 = sign1 * (scv + Math::db_to_linear(overdb1 * scmult));
}
spl0 = MIN(ceiling, Math::abs(spl0)) * (spl0 < 0.0 ? -1.0 : 1.0);
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index 9052f8e05e..1254a6740a 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -144,8 +144,8 @@ int AudioDriver::get_total_channels_by_speaker_mode(AudioDriver::SpeakerMode p_m
ERR_FAIL_V(2);
}
-Array AudioDriver::get_device_list() {
- Array list;
+PackedStringArray AudioDriver::get_device_list() {
+ PackedStringArray list;
list.push_back("Default");
@@ -156,8 +156,8 @@ String AudioDriver::get_device() {
return "Default";
}
-Array AudioDriver::capture_get_device_list() {
- Array list;
+PackedStringArray AudioDriver::capture_get_device_list() {
+ PackedStringArray list;
list.push_back("Default");
@@ -547,7 +547,7 @@ void AudioServer::_mix_step() {
AudioFrame peak = AudioFrame(0, 0);
- float volume = Math::db2linear(bus->volume_db);
+ float volume = Math::db_to_linear(bus->volume_db);
if (solo_mode) {
if (!bus->soloed) {
@@ -573,12 +573,12 @@ void AudioServer::_mix_step() {
}
}
- bus->channels.write[k].peak_volume = AudioFrame(Math::linear2db(peak.l + AUDIO_PEAK_OFFSET), Math::linear2db(peak.r + AUDIO_PEAK_OFFSET));
+ bus->channels.write[k].peak_volume = AudioFrame(Math::linear_to_db(peak.l + AUDIO_PEAK_OFFSET), Math::linear_to_db(peak.r + AUDIO_PEAK_OFFSET));
if (!bus->channels[k].used) {
//see if any audio is contained, because channel was not used
- if (MAX(peak.r, peak.l) > Math::db2linear(channel_disable_threshold_db)) {
+ if (MAX(peak.r, peak.l) > Math::db_to_linear(channel_disable_threshold_db)) {
bus->channels.write[k].last_mix_with_audio = mix_frames;
} else if (mix_frames - bus->channels[k].last_mix_with_audio > channel_disable_frames) {
bus->channels.write[k].active = false;
@@ -1637,7 +1637,7 @@ Ref<AudioBusLayout> AudioServer::generate_bus_layout() const {
return state;
}
-Array AudioServer::get_device_list() {
+PackedStringArray AudioServer::get_device_list() {
return AudioDriver::get_singleton()->get_device_list();
}
@@ -1649,7 +1649,7 @@ void AudioServer::set_device(String device) {
AudioDriver::get_singleton()->set_device(device);
}
-Array AudioServer::capture_get_device_list() {
+PackedStringArray AudioServer::capture_get_device_list() {
return AudioDriver::get_singleton()->capture_get_device_list();
}
diff --git a/servers/audio_server.h b/servers/audio_server.h
index 5613267909..588107c25d 100644
--- a/servers/audio_server.h
+++ b/servers/audio_server.h
@@ -94,7 +94,7 @@ public:
virtual void start() = 0;
virtual int get_mix_rate() const = 0;
virtual SpeakerMode get_speaker_mode() const = 0;
- virtual Array get_device_list();
+ virtual PackedStringArray get_device_list();
virtual String get_device();
virtual void set_device(String device) {}
virtual void lock() = 0;
@@ -105,7 +105,7 @@ public:
virtual Error capture_stop() { return FAILED; }
virtual void capture_set_device(const String &p_name) {}
virtual String capture_get_device() { return "Default"; }
- virtual Array capture_get_device_list(); // TODO: convert this and get_device_list to PackedStringArray
+ virtual PackedStringArray capture_get_device_list();
virtual float get_latency() { return 0; }
@@ -419,11 +419,11 @@ public:
void set_bus_layout(const Ref<AudioBusLayout> &p_bus_layout);
Ref<AudioBusLayout> generate_bus_layout() const;
- Array get_device_list();
+ PackedStringArray get_device_list();
String get_device();
void set_device(String device);
- Array capture_get_device_list();
+ PackedStringArray capture_get_device_list();
String capture_get_device();
void capture_set_device(const String &p_name);
diff --git a/servers/camera_server.cpp b/servers/camera_server.cpp
index 91df3afadd..b83b41a571 100644
--- a/servers/camera_server.cpp
+++ b/servers/camera_server.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "camera_server.h"
+#include "core/variant/typed_array.h"
#include "rendering_server.h"
#include "servers/camera/camera_feed.h"
@@ -143,8 +144,8 @@ int CameraServer::get_feed_count() {
return feeds.size();
};
-Array CameraServer::get_feeds() {
- Array return_feeds;
+TypedArray<CameraFeed> CameraServer::get_feeds() {
+ TypedArray<CameraFeed> return_feeds;
int cc = get_feed_count();
return_feeds.resize(cc);
diff --git a/servers/camera_server.h b/servers/camera_server.h
index b70938c34f..c6fb906b3c 100644
--- a/servers/camera_server.h
+++ b/servers/camera_server.h
@@ -43,6 +43,8 @@
**/
class CameraFeed;
+template <typename T>
+class TypedArray;
class CameraServer : public Object {
GDCLASS(CameraServer, Object);
@@ -100,7 +102,7 @@ public:
// Get our feeds.
Ref<CameraFeed> get_feed(int p_index);
int get_feed_count();
- Array get_feeds();
+ TypedArray<CameraFeed> get_feeds();
// Intended for use with custom CameraServer implementation.
RID feed_texture(int p_id, FeedImage p_texture);
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index e9bc28873b..22f42ca343 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -44,40 +44,49 @@ DisplayServer::DisplayServerCreate DisplayServer::server_create_functions[Displa
int DisplayServer::server_create_count = 1;
-void DisplayServer::global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
+int DisplayServer::global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
WARN_PRINT("Global menus not supported by this display server.");
+ return -1;
}
-void DisplayServer::global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
+int DisplayServer::global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
WARN_PRINT("Global menus not supported by this display server.");
+ return -1;
}
-void DisplayServer::global_menu_add_icon_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
+int DisplayServer::global_menu_add_icon_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
WARN_PRINT("Global menus not supported by this display server.");
+ return -1;
}
-void DisplayServer::global_menu_add_icon_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
+int DisplayServer::global_menu_add_icon_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
WARN_PRINT("Global menus not supported by this display server.");
+ return -1;
}
-void DisplayServer::global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
+int DisplayServer::global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
WARN_PRINT("Global menus not supported by this display server.");
+ return -1;
}
-void DisplayServer::global_menu_add_icon_radio_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
+int DisplayServer::global_menu_add_icon_radio_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
WARN_PRINT("Global menus not supported by this display server.");
+ return -1;
}
-void DisplayServer::global_menu_add_multistate_item(const String &p_menu_root, const String &p_label, int p_max_states, int p_default_state, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
+int DisplayServer::global_menu_add_multistate_item(const String &p_menu_root, const String &p_label, int p_max_states, int p_default_state, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
WARN_PRINT("Global menus not supported by this display server.");
+ return -1;
}
-void DisplayServer::global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu, int p_index) {
+int DisplayServer::global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu, int p_index) {
WARN_PRINT("Global menus not supported by this display server.");
+ return -1;
}
-void DisplayServer::global_menu_add_separator(const String &p_menu_root, int p_index) {
+int DisplayServer::global_menu_add_separator(const String &p_menu_root, int p_index) {
WARN_PRINT("Global menus not supported by this display server.");
+ return -1;
}
int DisplayServer::global_menu_get_item_index_from_text(const String &p_menu_root, const String &p_text) const {
@@ -159,6 +168,11 @@ Ref<Texture2D> DisplayServer::global_menu_get_item_icon(const String &p_menu_roo
return Ref<Texture2D>();
}
+int DisplayServer::global_menu_get_item_indentation_level(const String &p_menu_root, int p_idx) const {
+ WARN_PRINT("Global menus not supported by this display server.");
+ return 0;
+}
+
void DisplayServer::global_menu_set_item_checked(const String &p_menu_root, int p_idx, bool p_checked) {
WARN_PRINT("Global menus not supported by this display server.");
}
@@ -207,6 +221,10 @@ void DisplayServer::global_menu_set_item_icon(const String &p_menu_root, int p_i
WARN_PRINT("Global menus not supported by this display server.");
}
+void DisplayServer::global_menu_set_item_indentation_level(const String &p_menu_root, int p_idx, int p_level) {
+ WARN_PRINT("Global menus not supported by this display server.");
+}
+
int DisplayServer::global_menu_get_item_count(const String &p_menu_root) const {
WARN_PRINT("Global menus not supported by this display server.");
return 0;
@@ -238,14 +256,14 @@ void DisplayServer::tts_resume() {
WARN_PRINT("TTS is not supported by this display server.");
}
-Array DisplayServer::tts_get_voices() const {
+TypedArray<Dictionary> DisplayServer::tts_get_voices() const {
WARN_PRINT("TTS is not supported by this display server.");
- return Array();
+ return TypedArray<Dictionary>();
}
PackedStringArray DisplayServer::tts_get_voices_for_language(const String &p_language) const {
PackedStringArray ret;
- Array voices = tts_get_voices();
+ TypedArray<Dictionary> voices = tts_get_voices();
for (int i = 0; i < voices.size(); i++) {
const Dictionary &voice = voices[i];
if (voice.has("id") && voice.has("language") && voice["language"].operator String().begins_with(p_language)) {
@@ -400,7 +418,7 @@ String DisplayServer::ime_get_text() const {
ERR_FAIL_V_MSG(String(), "IME or NOTIFICATION_WM_IME_UPDATEnot supported by this display server.");
}
-void DisplayServer::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) {
+void DisplayServer::virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, VirtualKeyboardType p_type, int p_max_length, int p_cursor_start, int p_cursor_end) {
WARN_PRINT("Virtual keyboard not supported by this display server.");
}
@@ -494,11 +512,11 @@ int64_t DisplayServer::window_get_native_handle(HandleType p_handle_type, Window
}
void DisplayServer::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
- WARN_PRINT("Changing the VSync mode is not supported by this display server.");
+ WARN_PRINT("Changing the V-Sync mode is not supported by this display server.");
}
DisplayServer::VSyncMode DisplayServer::window_get_vsync_mode(WindowID p_window) const {
- WARN_PRINT("Changing the VSync mode is not supported by this display server.");
+ WARN_PRINT("Changing the V-Sync mode is not supported by this display server.");
return VSyncMode::VSYNC_ENABLED;
}
@@ -535,6 +553,7 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("global_menu_get_item_state", "menu_root", "idx"), &DisplayServer::global_menu_get_item_state);
ClassDB::bind_method(D_METHOD("global_menu_get_item_max_states", "menu_root", "idx"), &DisplayServer::global_menu_get_item_max_states);
ClassDB::bind_method(D_METHOD("global_menu_get_item_icon", "menu_root", "idx"), &DisplayServer::global_menu_get_item_icon);
+ ClassDB::bind_method(D_METHOD("global_menu_get_item_indentation_level", "menu_root", "idx"), &DisplayServer::global_menu_get_item_indentation_level);
ClassDB::bind_method(D_METHOD("global_menu_set_item_checked", "menu_root", "idx", "checked"), &DisplayServer::global_menu_set_item_checked);
ClassDB::bind_method(D_METHOD("global_menu_set_item_checkable", "menu_root", "idx", "checkable"), &DisplayServer::global_menu_set_item_checkable);
@@ -549,6 +568,7 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("global_menu_set_item_state", "menu_root", "idx", "state"), &DisplayServer::global_menu_set_item_state);
ClassDB::bind_method(D_METHOD("global_menu_set_item_max_states", "menu_root", "idx", "max_states"), &DisplayServer::global_menu_set_item_max_states);
ClassDB::bind_method(D_METHOD("global_menu_set_item_icon", "menu_root", "idx", "icon"), &DisplayServer::global_menu_set_item_icon);
+ ClassDB::bind_method(D_METHOD("global_menu_set_item_indentation_level", "menu_root", "idx", "level"), &DisplayServer::global_menu_set_item_indentation_level);
ClassDB::bind_method(D_METHOD("global_menu_remove_item", "menu_root", "idx"), &DisplayServer::global_menu_remove_item);
ClassDB::bind_method(D_METHOD("global_menu_clear", "menu_root"), &DisplayServer::global_menu_clear);
@@ -643,6 +663,8 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("window_set_flag", "flag", "enabled", "window_id"), &DisplayServer::window_set_flag, DEFVAL(MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("window_get_flag", "flag", "window_id"), &DisplayServer::window_get_flag, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_get_safe_title_margins", "window_id"), &DisplayServer::window_get_safe_title_margins, DEFVAL(MAIN_WINDOW_ID));
+
ClassDB::bind_method(D_METHOD("window_request_attention", "window_id"), &DisplayServer::window_request_attention, DEFVAL(MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("window_move_to_foreground", "window_id"), &DisplayServer::window_move_to_foreground, DEFVAL(MAIN_WINDOW_ID));
@@ -657,10 +679,13 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("window_set_vsync_mode", "vsync_mode", "window_id"), &DisplayServer::window_set_vsync_mode, DEFVAL(MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("window_get_vsync_mode", "window_id"), &DisplayServer::window_get_vsync_mode, DEFVAL(MAIN_WINDOW_ID));
+ ClassDB::bind_method(D_METHOD("window_maximize_on_title_dbl_click"), &DisplayServer::window_maximize_on_title_dbl_click);
+ ClassDB::bind_method(D_METHOD("window_minimize_on_title_dbl_click"), &DisplayServer::window_minimize_on_title_dbl_click);
+
ClassDB::bind_method(D_METHOD("ime_get_selection"), &DisplayServer::ime_get_selection);
ClassDB::bind_method(D_METHOD("ime_get_text"), &DisplayServer::ime_get_text);
- ClassDB::bind_method(D_METHOD("virtual_keyboard_show", "existing_text", "position", "multiline", "max_length", "cursor_start", "cursor_end"), &DisplayServer::virtual_keyboard_show, DEFVAL(Rect2()), DEFVAL(false), DEFVAL(-1), DEFVAL(-1), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("virtual_keyboard_show", "existing_text", "position", "type", "max_length", "cursor_start", "cursor_end"), &DisplayServer::virtual_keyboard_show, DEFVAL(Rect2()), DEFVAL(KEYBOARD_TYPE_DEFAULT), DEFVAL(-1), DEFVAL(-1), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("virtual_keyboard_hide"), &DisplayServer::virtual_keyboard_hide);
ClassDB::bind_method(D_METHOD("virtual_keyboard_get_height"), &DisplayServer::virtual_keyboard_get_height);
@@ -713,6 +738,7 @@ void DisplayServer::_bind_methods() {
BIND_ENUM_CONSTANT(FEATURE_SWAP_BUFFERS);
BIND_ENUM_CONSTANT(FEATURE_CLIPBOARD_PRIMARY);
BIND_ENUM_CONSTANT(FEATURE_TEXT_TO_SPEECH);
+ BIND_ENUM_CONSTANT(FEATURE_EXTEND_TO_TITLE);
BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
@@ -732,6 +758,15 @@ void DisplayServer::_bind_methods() {
BIND_ENUM_CONSTANT(SCREEN_SENSOR_PORTRAIT);
BIND_ENUM_CONSTANT(SCREEN_SENSOR);
+ BIND_ENUM_CONSTANT(KEYBOARD_TYPE_DEFAULT);
+ BIND_ENUM_CONSTANT(KEYBOARD_TYPE_MULTILINE);
+ BIND_ENUM_CONSTANT(KEYBOARD_TYPE_NUMBER);
+ BIND_ENUM_CONSTANT(KEYBOARD_TYPE_NUMBER_DECIMAL);
+ BIND_ENUM_CONSTANT(KEYBOARD_TYPE_PHONE);
+ BIND_ENUM_CONSTANT(KEYBOARD_TYPE_EMAIL_ADDRESS);
+ BIND_ENUM_CONSTANT(KEYBOARD_TYPE_PASSWORD);
+ BIND_ENUM_CONSTANT(KEYBOARD_TYPE_URL);
+
BIND_ENUM_CONSTANT(CURSOR_ARROW);
BIND_ENUM_CONSTANT(CURSOR_IBEAM);
BIND_ENUM_CONSTANT(CURSOR_POINTING_HAND);
@@ -763,6 +798,7 @@ void DisplayServer::_bind_methods() {
BIND_ENUM_CONSTANT(WINDOW_FLAG_TRANSPARENT);
BIND_ENUM_CONSTANT(WINDOW_FLAG_NO_FOCUS);
BIND_ENUM_CONSTANT(WINDOW_FLAG_POPUP);
+ BIND_ENUM_CONSTANT(WINDOW_FLAG_EXTEND_TO_TITLE);
BIND_ENUM_CONSTANT(WINDOW_FLAG_MAX);
BIND_ENUM_CONSTANT(WINDOW_EVENT_MOUSE_ENTER);
diff --git a/servers/display_server.h b/servers/display_server.h
index 7a15df2f92..0b162fe491 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -122,20 +122,21 @@ public:
FEATURE_KEEP_SCREEN_ON,
FEATURE_CLIPBOARD_PRIMARY,
FEATURE_TEXT_TO_SPEECH,
+ FEATURE_EXTEND_TO_TITLE,
};
virtual bool has_feature(Feature p_feature) const = 0;
virtual String get_name() const = 0;
- virtual void global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1);
- virtual void global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1);
- virtual void global_menu_add_icon_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1);
- virtual void global_menu_add_icon_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1);
- virtual void global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1);
- virtual void global_menu_add_icon_radio_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1);
- virtual void global_menu_add_multistate_item(const String &p_menu_root, const String &p_label, int p_max_states, int p_default_state, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1);
- virtual void global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu, int p_index = -1);
- virtual void global_menu_add_separator(const String &p_menu_root, int p_index = -1);
+ virtual int global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1);
+ virtual int global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1);
+ virtual int global_menu_add_icon_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1);
+ virtual int global_menu_add_icon_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1);
+ virtual int global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1);
+ virtual int global_menu_add_icon_radio_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1);
+ virtual int global_menu_add_multistate_item(const String &p_menu_root, const String &p_label, int p_max_states, int p_default_state, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1);
+ virtual int global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu, int p_index = -1);
+ virtual int global_menu_add_separator(const String &p_menu_root, int p_index = -1);
virtual int global_menu_get_item_index_from_text(const String &p_menu_root, const String &p_text) const;
virtual int global_menu_get_item_index_from_tag(const String &p_menu_root, const Variant &p_tag) const;
@@ -153,6 +154,7 @@ public:
virtual int global_menu_get_item_state(const String &p_menu_root, int p_idx) const;
virtual int global_menu_get_item_max_states(const String &p_menu_root, int p_idx) const;
virtual Ref<Texture2D> global_menu_get_item_icon(const String &p_menu_root, int p_idx) const;
+ virtual int global_menu_get_item_indentation_level(const String &p_menu_root, int p_idx) const;
virtual void global_menu_set_item_checked(const String &p_menu_root, int p_idx, bool p_checked);
virtual void global_menu_set_item_checkable(const String &p_menu_root, int p_idx, bool p_checkable);
@@ -167,6 +169,7 @@ public:
virtual void global_menu_set_item_state(const String &p_menu_root, int p_idx, int p_state);
virtual void global_menu_set_item_max_states(const String &p_menu_root, int p_idx, int p_max_states);
virtual void global_menu_set_item_icon(const String &p_menu_root, int p_idx, const Ref<Texture2D> &p_icon);
+ virtual void global_menu_set_item_indentation_level(const String &p_menu_root, int p_idx, int p_level);
virtual int global_menu_get_item_count(const String &p_menu_root) const;
@@ -196,7 +199,7 @@ private:
public:
virtual bool tts_is_speaking() const;
virtual bool tts_is_paused() const;
- virtual Array tts_get_voices() const;
+ virtual TypedArray<Dictionary> tts_get_voices() const;
virtual PackedStringArray tts_get_voices_for_language(const String &p_language) const;
virtual void tts_speak(const String &p_text, const String &p_voice, int p_volume = 50, float p_pitch = 1.f, float p_rate = 1.f, int p_utterance_id = 0, bool p_interrupt = false);
@@ -228,7 +231,7 @@ public:
virtual void clipboard_set_primary(const String &p_text);
virtual String clipboard_get_primary() const;
- virtual Array get_display_cutouts() const { return Array(); }
+ virtual TypedArray<Rect2> get_display_cutouts() const { return TypedArray<Rect2>(); }
virtual Rect2i get_display_safe_area() const { return screen_get_usable_rect(); }
enum {
@@ -287,6 +290,7 @@ public:
WINDOW_FLAG_TRANSPARENT,
WINDOW_FLAG_NO_FOCUS,
WINDOW_FLAG_POPUP,
+ WINDOW_FLAG_EXTEND_TO_TITLE,
WINDOW_FLAG_MAX,
};
@@ -298,6 +302,7 @@ public:
WINDOW_FLAG_TRANSPARENT_BIT = (1 << WINDOW_FLAG_TRANSPARENT),
WINDOW_FLAG_NO_FOCUS_BIT = (1 << WINDOW_FLAG_NO_FOCUS),
WINDOW_FLAG_POPUP_BIT = (1 << WINDOW_FLAG_POPUP),
+ WINDOW_FLAG_EXTEND_TO_TITLE_BIT = (1 << WINDOW_FLAG_EXTEND_TO_TITLE),
};
virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
@@ -369,6 +374,8 @@ public:
virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) = 0;
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) = 0;
+ virtual Vector2i window_get_safe_title_margins(WindowID p_window = MAIN_WINDOW_ID) const { return Vector2i(); };
+
virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const = 0;
virtual bool can_any_window_draw() const = 0;
@@ -376,13 +383,27 @@ public:
virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID);
virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID);
+ virtual bool window_maximize_on_title_dbl_click() const { return false; }
+ virtual bool window_minimize_on_title_dbl_click() const { return false; }
+
// necessary for GL focus, may be able to use one of the existing functions for this, not sure yet
virtual void gl_window_make_current(DisplayServer::WindowID p_window_id);
virtual Point2i ime_get_selection() const;
virtual String ime_get_text() const;
- virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_length = -1, int p_cursor_start = -1, int p_cursor_end = -1);
+ enum VirtualKeyboardType {
+ KEYBOARD_TYPE_DEFAULT,
+ KEYBOARD_TYPE_MULTILINE,
+ KEYBOARD_TYPE_NUMBER,
+ KEYBOARD_TYPE_NUMBER_DECIMAL,
+ KEYBOARD_TYPE_PHONE,
+ KEYBOARD_TYPE_EMAIL_ADDRESS,
+ KEYBOARD_TYPE_PASSWORD,
+ KEYBOARD_TYPE_URL
+ };
+
+ virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), VirtualKeyboardType p_type = KEYBOARD_TYPE_DEFAULT, int p_max_length = -1, int p_cursor_start = -1, int p_cursor_end = -1);
virtual void virtual_keyboard_hide();
// returns height of the currently shown virtual keyboard (0 if keyboard is hidden)
@@ -467,6 +488,7 @@ VARIANT_ENUM_CAST(DisplayServer::ScreenOrientation)
VARIANT_ENUM_CAST(DisplayServer::WindowMode)
VARIANT_ENUM_CAST(DisplayServer::WindowFlags)
VARIANT_ENUM_CAST(DisplayServer::HandleType)
+VARIANT_ENUM_CAST(DisplayServer::VirtualKeyboardType);
VARIANT_ENUM_CAST(DisplayServer::CursorShape)
VARIANT_ENUM_CAST(DisplayServer::VSyncMode)
VARIANT_ENUM_CAST(DisplayServer::TTSUtteranceEvent)
diff --git a/servers/extensions/physics_server_3d_extension.cpp b/servers/extensions/physics_server_3d_extension.cpp
index 3694dcdb9a..7d797bf611 100644
--- a/servers/extensions/physics_server_3d_extension.cpp
+++ b/servers/extensions/physics_server_3d_extension.cpp
@@ -196,6 +196,9 @@ void PhysicsServer3DExtension::_bind_methods() {
GDVIRTUAL_BIND(_body_set_collision_mask, "body", "mask");
GDVIRTUAL_BIND(_body_get_collision_mask, "body");
+ GDVIRTUAL_BIND(_body_set_collision_priority, "body", "priority");
+ GDVIRTUAL_BIND(_body_get_collision_priority, "body");
+
GDVIRTUAL_BIND(_body_add_shape, "body", "shape", "transform", "disabled");
GDVIRTUAL_BIND(_body_set_shape, "body", "shape_idx", "shape");
GDVIRTUAL_BIND(_body_set_shape_transform, "body", "shape_idx", "transform");
diff --git a/servers/extensions/physics_server_3d_extension.h b/servers/extensions/physics_server_3d_extension.h
index c4b4a00eaf..3200438253 100644
--- a/servers/extensions/physics_server_3d_extension.h
+++ b/servers/extensions/physics_server_3d_extension.h
@@ -319,6 +319,9 @@ public:
EXBIND2(body_set_collision_mask, RID, uint32_t)
EXBIND1RC(uint32_t, body_get_collision_mask, RID)
+ EXBIND2(body_set_collision_priority, RID, real_t)
+ EXBIND1RC(real_t, body_get_collision_priority, RID)
+
EXBIND2(body_set_user_flags, RID, uint32_t)
EXBIND1RC(uint32_t, body_get_user_flags, RID)
diff --git a/servers/movie_writer/movie_writer.cpp b/servers/movie_writer/movie_writer.cpp
index 40b2b2539e..2164dca29e 100644
--- a/servers/movie_writer/movie_writer.cpp
+++ b/servers/movie_writer/movie_writer.cpp
@@ -191,7 +191,7 @@ void MovieWriter::end() {
if (movie_path.is_relative_path()) {
// Print absolute path to make finding the file easier,
// and to make it clickable in terminal emulators that support this.
- movie_path = ProjectSettings::get_singleton()->globalize_path("res://").plus_file(movie_path);
+ movie_path = ProjectSettings::get_singleton()->globalize_path("res://").path_join(movie_path);
}
print_line(vformat("Done recording movie at path: %s", movie_path));
diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp
index 5e9f1c824a..0f73df8894 100644
--- a/servers/navigation_server_2d.cpp
+++ b/servers/navigation_server_2d.cpp
@@ -158,12 +158,53 @@ void NavigationServer2D::_emit_map_changed(RID p_map) {
emit_signal(SNAME("map_changed"), p_map);
}
+#ifdef DEBUG_ENABLED
+void NavigationServer2D::set_debug_enabled(bool p_enabled) {
+ NavigationServer3D::get_singleton_mut()->set_debug_enabled(p_enabled);
+}
+bool NavigationServer2D::get_debug_enabled() const {
+ return NavigationServer3D::get_singleton()->get_debug_enabled();
+}
+
+void NavigationServer2D::set_debug_navigation_edge_connection_color(const Color &p_color) {
+ NavigationServer3D::get_singleton_mut()->set_debug_navigation_edge_connection_color(p_color);
+}
+
+Color NavigationServer2D::get_debug_navigation_edge_connection_color() const {
+ return NavigationServer3D::get_singleton()->get_debug_navigation_edge_connection_color();
+}
+
+void NavigationServer2D::set_debug_navigation_geometry_face_color(const Color &p_color) {
+ NavigationServer3D::get_singleton_mut()->set_debug_navigation_geometry_face_color(p_color);
+}
+
+Color NavigationServer2D::get_debug_navigation_geometry_face_color() const {
+ return NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_color();
+}
+
+void NavigationServer2D::set_debug_navigation_geometry_face_disabled_color(const Color &p_color) {
+ NavigationServer3D::get_singleton_mut()->set_debug_navigation_geometry_face_disabled_color(p_color);
+}
+
+Color NavigationServer2D::get_debug_navigation_geometry_face_disabled_color() const {
+ return NavigationServer3D::get_singleton()->get_debug_navigation_geometry_face_disabled_color();
+}
+
+void NavigationServer2D::set_debug_navigation_enable_edge_connections(const bool p_value) {
+ NavigationServer3D::get_singleton_mut()->set_debug_navigation_enable_edge_connections(p_value);
+}
+
+bool NavigationServer2D::get_debug_navigation_enable_edge_connections() const {
+ return NavigationServer3D::get_singleton()->get_debug_navigation_enable_edge_connections();
+}
+#endif // DEBUG_ENABLED
+
void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_maps"), &NavigationServer2D::get_maps);
ClassDB::bind_method(D_METHOD("map_create"), &NavigationServer2D::map_create);
ClassDB::bind_method(D_METHOD("map_set_active", "map", "active"), &NavigationServer2D::map_set_active);
- ClassDB::bind_method(D_METHOD("map_is_active", "nap"), &NavigationServer2D::map_is_active);
+ ClassDB::bind_method(D_METHOD("map_is_active", "map"), &NavigationServer2D::map_is_active);
ClassDB::bind_method(D_METHOD("map_set_cell_size", "map", "cell_size"), &NavigationServer2D::map_set_cell_size);
ClassDB::bind_method(D_METHOD("map_get_cell_size", "map"), &NavigationServer2D::map_get_cell_size);
ClassDB::bind_method(D_METHOD("map_set_edge_connection_margin", "map", "margin"), &NavigationServer2D::map_set_edge_connection_margin);
@@ -196,7 +237,7 @@ void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("agent_create"), &NavigationServer2D::agent_create);
ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &NavigationServer2D::agent_set_map);
ClassDB::bind_method(D_METHOD("agent_get_map", "agent"), &NavigationServer2D::agent_get_map);
- ClassDB::bind_method(D_METHOD("agent_set_neighbor_dist", "agent", "dist"), &NavigationServer2D::agent_set_neighbor_dist);
+ ClassDB::bind_method(D_METHOD("agent_set_neighbor_distance", "agent", "distance"), &NavigationServer2D::agent_set_neighbor_distance);
ClassDB::bind_method(D_METHOD("agent_set_max_neighbors", "agent", "count"), &NavigationServer2D::agent_set_max_neighbors);
ClassDB::bind_method(D_METHOD("agent_set_time_horizon", "agent", "time"), &NavigationServer2D::agent_set_time_horizon);
ClassDB::bind_method(D_METHOD("agent_set_radius", "agent", "radius"), &NavigationServer2D::agent_set_radius);
@@ -222,11 +263,11 @@ NavigationServer2D::~NavigationServer2D() {
singleton = nullptr;
}
-Array FORWARD_0_C(get_maps);
+TypedArray<RID> FORWARD_0_C(get_maps);
-Array FORWARD_1_C(map_get_regions, RID, p_map, rid_to_rid);
+TypedArray<RID> FORWARD_1_C(map_get_regions, RID, p_map, rid_to_rid);
-Array FORWARD_1_C(map_get_agents, RID, p_map, rid_to_rid);
+TypedArray<RID> FORWARD_1_C(map_get_agents, RID, p_map, rid_to_rid);
RID FORWARD_1_C(region_get_map, RID, p_region, rid_to_rid);
@@ -282,7 +323,7 @@ RID NavigationServer2D::agent_create() const {
void FORWARD_2_C(agent_set_map, RID, p_agent, RID, p_map, rid_to_rid, rid_to_rid);
-void FORWARD_2_C(agent_set_neighbor_dist, RID, p_agent, real_t, p_dist, rid_to_rid, real_to_real);
+void FORWARD_2_C(agent_set_neighbor_distance, RID, p_agent, real_t, p_dist, rid_to_rid, real_to_real);
void FORWARD_2_C(agent_set_max_neighbors, RID, p_agent, int, p_count, rid_to_rid, int_to_int);
diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h
index 1b15c7ff37..5e96466d66 100644
--- a/servers/navigation_server_2d.h
+++ b/servers/navigation_server_2d.h
@@ -53,7 +53,7 @@ public:
/// MUST be used in single thread!
static NavigationServer2D *get_singleton_mut() { return singleton; }
- virtual Array get_maps() const;
+ virtual TypedArray<RID> get_maps() const;
/// Create a new map.
virtual RID map_create() const;
@@ -82,8 +82,8 @@ public:
virtual Vector2 map_get_closest_point(RID p_map, const Vector2 &p_point) const;
virtual RID map_get_closest_point_owner(RID p_map, const Vector2 &p_point) const;
- virtual Array map_get_regions(RID p_map) const;
- virtual Array map_get_agents(RID p_map) const;
+ virtual TypedArray<RID> map_get_regions(RID p_map) const;
+ virtual TypedArray<RID> map_get_agents(RID p_map) const;
virtual void map_force_update(RID p_map);
@@ -133,7 +133,7 @@ public:
/// time of the simulation. If the number is too
/// low, the simulation will not be safe.
/// Must be non-negative.
- virtual void agent_set_neighbor_dist(RID p_agent, real_t p_dist) const;
+ virtual void agent_set_neighbor_distance(RID p_agent, real_t p_distance) const;
/// The maximum number of other agents this
/// agent takes into account in the navigation.
@@ -184,6 +184,23 @@ public:
NavigationServer2D();
virtual ~NavigationServer2D();
+
+#ifdef DEBUG_ENABLED
+ void set_debug_enabled(bool p_enabled);
+ bool get_debug_enabled() const;
+
+ void set_debug_navigation_edge_connection_color(const Color &p_color);
+ Color get_debug_navigation_edge_connection_color() const;
+
+ void set_debug_navigation_geometry_face_color(const Color &p_color);
+ Color get_debug_navigation_geometry_face_color() const;
+
+ void set_debug_navigation_geometry_face_disabled_color(const Color &p_color);
+ Color get_debug_navigation_geometry_face_disabled_color() const;
+
+ void set_debug_navigation_enable_edge_connections(const bool p_value);
+ bool get_debug_navigation_enable_edge_connections() const;
+#endif // DEBUG_ENABLED
};
#endif // NAVIGATION_SERVER_2D_H
diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp
index 52855c5931..466b74bc64 100644
--- a/servers/navigation_server_3d.cpp
+++ b/servers/navigation_server_3d.cpp
@@ -41,7 +41,7 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_create"), &NavigationServer3D::map_create);
ClassDB::bind_method(D_METHOD("map_set_active", "map", "active"), &NavigationServer3D::map_set_active);
- ClassDB::bind_method(D_METHOD("map_is_active", "nap"), &NavigationServer3D::map_is_active);
+ ClassDB::bind_method(D_METHOD("map_is_active", "map"), &NavigationServer3D::map_is_active);
ClassDB::bind_method(D_METHOD("map_set_up", "map", "up"), &NavigationServer3D::map_set_up);
ClassDB::bind_method(D_METHOD("map_get_up", "map"), &NavigationServer3D::map_get_up);
ClassDB::bind_method(D_METHOD("map_set_cell_size", "map", "cell_size"), &NavigationServer3D::map_set_cell_size);
@@ -79,7 +79,7 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("agent_create"), &NavigationServer3D::agent_create);
ClassDB::bind_method(D_METHOD("agent_set_map", "agent", "map"), &NavigationServer3D::agent_set_map);
ClassDB::bind_method(D_METHOD("agent_get_map", "agent"), &NavigationServer3D::agent_get_map);
- ClassDB::bind_method(D_METHOD("agent_set_neighbor_dist", "agent", "dist"), &NavigationServer3D::agent_set_neighbor_dist);
+ ClassDB::bind_method(D_METHOD("agent_set_neighbor_distance", "agent", "distance"), &NavigationServer3D::agent_set_neighbor_distance);
ClassDB::bind_method(D_METHOD("agent_set_max_neighbors", "agent", "count"), &NavigationServer3D::agent_set_max_neighbors);
ClassDB::bind_method(D_METHOD("agent_set_time_horizon", "agent", "time"), &NavigationServer3D::agent_set_time_horizon);
ClassDB::bind_method(D_METHOD("agent_set_radius", "agent", "radius"), &NavigationServer3D::agent_set_radius);
@@ -123,6 +123,12 @@ NavigationServer3D::NavigationServer3D() {
debug_navigation_enable_edge_lines = GLOBAL_DEF("debug/shapes/navigation/enable_edge_lines", true);
debug_navigation_enable_edge_lines_xray = GLOBAL_DEF("debug/shapes/navigation/enable_edge_lines_xray", true);
debug_navigation_enable_geometry_face_random_color = GLOBAL_DEF("debug/shapes/navigation/enable_geometry_face_random_color", true);
+
+ if (Engine::get_singleton()->is_editor_hint()) {
+ // enable NavigationServer3D when in Editor or else navmesh edge connections are invisible
+ // on runtime tests SceneTree has "Visible Navigation" set and main iteration takes care of this
+ set_debug_enabled(true);
+ }
#endif // DEBUG_ENABLED
}
diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h
index f24c0117d1..3213da3d84 100644
--- a/servers/navigation_server_3d.h
+++ b/servers/navigation_server_3d.h
@@ -56,7 +56,7 @@ public:
/// MUST be used in single thread!
static NavigationServer3D *get_singleton_mut();
- virtual Array get_maps() const = 0;
+ virtual TypedArray<RID> get_maps() const = 0;
/// Create a new map.
virtual RID map_create() const = 0;
@@ -93,8 +93,8 @@ public:
virtual Vector3 map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const = 0;
virtual RID map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const = 0;
- virtual Array map_get_regions(RID p_map) const = 0;
- virtual Array map_get_agents(RID p_map) const = 0;
+ virtual TypedArray<RID> map_get_regions(RID p_map) const = 0;
+ virtual TypedArray<RID> map_get_agents(RID p_map) const = 0;
virtual void map_force_update(RID p_map) = 0;
@@ -147,7 +147,7 @@ public:
/// time of the simulation. If the number is too
/// low, the simulation will not be safe.
/// Must be non-negative.
- virtual void agent_set_neighbor_dist(RID p_agent, real_t p_dist) const = 0;
+ virtual void agent_set_neighbor_distance(RID p_agent, real_t p_distance) const = 0;
/// The maximum number of other agents this
/// agent takes into account in the navigation.
diff --git a/servers/physics_2d/godot_area_2d.cpp b/servers/physics_2d/godot_area_2d.cpp
index 96c8dfc69e..af90f96438 100644
--- a/servers/physics_2d/godot_area_2d.cpp
+++ b/servers/physics_2d/godot_area_2d.cpp
@@ -248,6 +248,10 @@ void GodotArea2D::call_queries() {
Callable::CallError ce;
Variant ret;
monitor_callback.callp((const Variant **)resptr, 5, ret, ce);
+
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT_ONCE("Error calling event callback method " + Variant::get_callable_error_text(monitor_callback, (const Variant **)resptr, 5, ce));
+ }
}
} else {
monitored_bodies.clear();
@@ -286,6 +290,10 @@ void GodotArea2D::call_queries() {
Callable::CallError ce;
Variant ret;
area_monitor_callback.callp((const Variant **)resptr, 5, ret, ce);
+
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT_ONCE("Error calling event callback method " + Variant::get_callable_error_text(area_monitor_callback, (const Variant **)resptr, 5, ce));
+ }
}
} else {
monitored_areas.clear();
diff --git a/servers/physics_2d/godot_body_2d.cpp b/servers/physics_2d/godot_body_2d.cpp
index 268beb1a55..ef6a6b1ae2 100644
--- a/servers/physics_2d/godot_body_2d.cpp
+++ b/servers/physics_2d/godot_body_2d.cpp
@@ -44,7 +44,7 @@ void GodotBody2D::update_mass_properties() {
//update shapes and motions
switch (mode) {
- case PhysicsServer2D::BODY_MODE_DYNAMIC: {
+ case PhysicsServer2D::BODY_MODE_RIGID: {
real_t total_area = 0;
for (int i = 0; i < get_shape_count(); i++) {
if (is_shape_disabled(i)) {
@@ -113,7 +113,7 @@ void GodotBody2D::update_mass_properties() {
_inv_inertia = 0;
_inv_mass = 0;
} break;
- case PhysicsServer2D::BODY_MODE_DYNAMIC_LINEAR: {
+ case PhysicsServer2D::BODY_MODE_RIGID_LINEAR: {
_inv_inertia = 0;
_inv_mass = 1.0 / mass;
@@ -160,7 +160,7 @@ void GodotBody2D::set_param(PhysicsServer2D::BodyParameter p_param, const Varian
real_t mass_value = p_value;
ERR_FAIL_COND(mass_value <= 0);
mass = mass_value;
- if (mode >= PhysicsServer2D::BODY_MODE_DYNAMIC) {
+ if (mode >= PhysicsServer2D::BODY_MODE_RIGID) {
_mass_properties_changed();
}
} break;
@@ -168,13 +168,13 @@ void GodotBody2D::set_param(PhysicsServer2D::BodyParameter p_param, const Varian
real_t inertia_value = p_value;
if (inertia_value <= 0.0) {
calculate_inertia = true;
- if (mode == PhysicsServer2D::BODY_MODE_DYNAMIC) {
+ if (mode == PhysicsServer2D::BODY_MODE_RIGID) {
_mass_properties_changed();
}
} else {
calculate_inertia = false;
inertia = inertia_value;
- if (mode == PhysicsServer2D::BODY_MODE_DYNAMIC) {
+ if (mode == PhysicsServer2D::BODY_MODE_RIGID) {
_inv_inertia = 1.0 / inertia;
}
}
@@ -267,7 +267,7 @@ void GodotBody2D::set_mode(PhysicsServer2D::BodyMode p_mode) {
first_time_kinematic = true;
}
} break;
- case PhysicsServer2D::BODY_MODE_DYNAMIC: {
+ case PhysicsServer2D::BODY_MODE_RIGID: {
_inv_mass = mass > 0 ? (1.0 / mass) : 0;
if (!calculate_inertia) {
_inv_inertia = 1.0 / inertia;
@@ -277,7 +277,7 @@ void GodotBody2D::set_mode(PhysicsServer2D::BodyMode p_mode) {
set_active(true);
} break;
- case PhysicsServer2D::BODY_MODE_DYNAMIC_LINEAR: {
+ case PhysicsServer2D::BODY_MODE_RIGID_LINEAR: {
_inv_mass = mass > 0 ? (1.0 / mass) : 0;
_inv_inertia = 0;
angular_velocity = 0;
@@ -358,7 +358,7 @@ void GodotBody2D::set_state(PhysicsServer2D::BodyState p_state, const Variant &p
} break;
case PhysicsServer2D::BODY_STATE_CAN_SLEEP: {
can_sleep = p_variant;
- if (mode >= PhysicsServer2D::BODY_MODE_DYNAMIC && !active && !can_sleep) {
+ if (mode >= PhysicsServer2D::BODY_MODE_RIGID && !active && !can_sleep) {
set_active(true);
}
@@ -661,7 +661,7 @@ void GodotBody2D::wakeup_neighbours() {
continue;
}
GodotBody2D *b = n[i];
- if (b->mode < PhysicsServer2D::BODY_MODE_DYNAMIC) {
+ if (b->mode < PhysicsServer2D::BODY_MODE_RIGID) {
continue;
}
diff --git a/servers/physics_2d/godot_body_2d.h b/servers/physics_2d/godot_body_2d.h
index 4b87a69d5c..409940d4f8 100644
--- a/servers/physics_2d/godot_body_2d.h
+++ b/servers/physics_2d/godot_body_2d.h
@@ -42,7 +42,7 @@ class GodotConstraint2D;
class GodotPhysicsDirectBodyState2D;
class GodotBody2D : public GodotCollisionObject2D {
- PhysicsServer2D::BodyMode mode = PhysicsServer2D::BODY_MODE_DYNAMIC;
+ PhysicsServer2D::BodyMode mode = PhysicsServer2D::BODY_MODE_RIGID;
Vector2 biased_linear_velocity;
real_t biased_angular_velocity = 0.0;
diff --git a/servers/physics_2d/godot_collision_object_2d.h b/servers/physics_2d/godot_collision_object_2d.h
index 1a683a7b0f..7965e8a94d 100644
--- a/servers/physics_2d/godot_collision_object_2d.h
+++ b/servers/physics_2d/godot_collision_object_2d.h
@@ -70,6 +70,7 @@ private:
Transform2D inv_transform;
uint32_t collision_mask = 1;
uint32_t collision_layer = 1;
+ real_t collision_priority = 1.0;
bool _static = true;
SelfList<GodotCollisionObject2D> pending_shape_update_list;
@@ -166,6 +167,13 @@ public:
}
_FORCE_INLINE_ uint32_t get_collision_layer() const { return collision_layer; }
+ _FORCE_INLINE_ void set_collision_priority(real_t p_priority) {
+ ERR_FAIL_COND_MSG(p_priority <= 0, "Priority must be greater than 0.");
+ collision_priority = p_priority;
+ _shape_changed();
+ }
+ _FORCE_INLINE_ real_t get_collision_priority() const { return collision_priority; }
+
void remove_shape(GodotShape2D *p_shape) override;
void remove_shape(int p_index);
diff --git a/servers/physics_2d/godot_physics_server_2d.cpp b/servers/physics_2d/godot_physics_server_2d.cpp
index 99e68de07c..c728dccd4f 100644
--- a/servers/physics_2d/godot_physics_server_2d.cpp
+++ b/servers/physics_2d/godot_physics_server_2d.cpp
@@ -718,6 +718,20 @@ uint32_t GodotPhysicsServer2D::body_get_collision_mask(RID p_body) const {
return body->get_collision_mask();
}
+void GodotPhysicsServer2D::body_set_collision_priority(RID p_body, real_t p_priority) {
+ GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_collision_priority(p_priority);
+}
+
+real_t GodotPhysicsServer2D::body_get_collision_priority(RID p_body) const {
+ const GodotBody2D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_collision_priority();
+}
+
void GodotPhysicsServer2D::body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) {
GodotBody2D *body = body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
diff --git a/servers/physics_2d/godot_physics_server_2d.h b/servers/physics_2d/godot_physics_server_2d.h
index 2af6e5c97c..20e492d87a 100644
--- a/servers/physics_2d/godot_physics_server_2d.h
+++ b/servers/physics_2d/godot_physics_server_2d.h
@@ -199,6 +199,9 @@ public:
virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) override;
virtual uint32_t body_get_collision_mask(RID p_body) const override;
+ virtual void body_set_collision_priority(RID p_body, real_t p_priority) override;
+ virtual real_t body_get_collision_priority(RID p_body) const override;
+
virtual void body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) override;
virtual Variant body_get_param(RID p_body, BodyParameter p_param) const override;
diff --git a/servers/physics_2d/godot_space_2d.cpp b/servers/physics_2d/godot_space_2d.cpp
index 166ec3049e..afcc5af951 100644
--- a/servers/physics_2d/godot_space_2d.cpp
+++ b/servers/physics_2d/godot_space_2d.cpp
@@ -594,6 +594,7 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D::
const int max_results = 32;
int recover_attempts = 4;
Vector2 sr[max_results * 2];
+ real_t priorities[max_results];
do {
GodotPhysicsServer2D::CollCbkData cbk;
@@ -606,6 +607,7 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D::
GodotPhysicsServer2D::CollCbkData *cbkptr = &cbk;
GodotCollisionSolver2D::CallbackResult cbkres = GodotPhysicsServer2D::_shape_col_cbk;
+ int priority_amount = 0;
bool collided = false;
@@ -641,7 +643,7 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D::
if (col_obj->get_type() == GodotCollisionObject2D::TYPE_BODY) {
const GodotBody2D *b = static_cast<const GodotBody2D *>(col_obj);
- if (b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_DYNAMIC) {
+ if (b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_RIGID) {
//fix for moving platforms (kinematic and dynamic), margin is increased by how much it moved in the given direction
Vector2 lv = b->get_linear_velocity();
//compute displacement from linear velocity
@@ -664,6 +666,10 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D::
if (GodotCollisionSolver2D::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, nullptr, margin)) {
did_collide = cbk.passed > current_passed; //more passed, so collision actually existed
}
+ while (cbk.amount > priority_amount) {
+ priorities[priority_amount] = col_obj->get_collision_priority();
+ priority_amount++;
+ }
if (!did_collide && cbk.invalid_by_dir > 0) {
//this shape must be excluded
@@ -686,6 +692,12 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D::
break;
}
+ real_t inv_total_weight = 0.0;
+ for (int i = 0; i < cbk.amount; i++) {
+ inv_total_weight += priorities[i];
+ }
+ inv_total_weight = Math::is_zero_approx(inv_total_weight) ? 1.0 : (real_t)cbk.amount / inv_total_weight;
+
recovered = true;
Vector2 recover_motion;
@@ -701,7 +713,7 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D::
real_t depth = n.dot(a + recover_motion) - d;
if (depth > min_contact_depth + CMP_EPSILON) {
// Only recover if there is penetration.
- recover_motion -= n * (depth - min_contact_depth) * 0.4;
+ recover_motion -= n * (depth - min_contact_depth) * 0.4 * priorities[i] * inv_total_weight;
}
}
@@ -936,7 +948,7 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D::
if (col_obj->get_type() == GodotCollisionObject2D::TYPE_BODY) {
const GodotBody2D *b = static_cast<const GodotBody2D *>(col_obj);
- if (b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_DYNAMIC) {
+ if (b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_RIGID) {
//fix for moving platforms (kinematic and dynamic), margin is increased by how much it moved in the given direction
Vector2 lv = b->get_linear_velocity();
//compute displacement from linear velocity
@@ -1206,7 +1218,7 @@ GodotPhysicsDirectSpaceState2D *GodotSpace2D::get_direct_state() {
GodotSpace2D::GodotSpace2D() {
body_linear_velocity_sleep_threshold = GLOBAL_DEF("physics/2d/sleep_threshold_linear", 2.0);
- body_angular_velocity_sleep_threshold = GLOBAL_DEF("physics/2d/sleep_threshold_angular", Math::deg2rad(8.0));
+ body_angular_velocity_sleep_threshold = GLOBAL_DEF("physics/2d/sleep_threshold_angular", Math::deg_to_rad(8.0));
body_time_to_sleep = GLOBAL_DEF("physics/2d/time_before_sleep", 0.5);
ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/time_before_sleep", PropertyInfo(Variant::FLOAT, "physics/2d/time_before_sleep", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater"));
diff --git a/servers/physics_2d/godot_step_2d.cpp b/servers/physics_2d/godot_step_2d.cpp
index 0603458acd..46718c8819 100644
--- a/servers/physics_2d/godot_step_2d.cpp
+++ b/servers/physics_2d/godot_step_2d.cpp
@@ -42,7 +42,7 @@ void GodotStep2D::_populate_island(GodotBody2D *p_body, LocalVector<GodotBody2D
p_body->set_island_step(_step);
if (p_body->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) {
- // Only dynamic bodies are tested for activation.
+ // Only rigid bodies are tested for activation.
p_body_island.push_back(p_body);
}
diff --git a/servers/physics_3d/godot_area_3d.cpp b/servers/physics_3d/godot_area_3d.cpp
index fdb9f42b40..9765d0bf58 100644
--- a/servers/physics_3d/godot_area_3d.cpp
+++ b/servers/physics_3d/godot_area_3d.cpp
@@ -277,6 +277,10 @@ void GodotArea3D::call_queries() {
Callable::CallError ce;
Variant ret;
monitor_callback.callp((const Variant **)resptr, 5, ret, ce);
+
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT_ONCE("Error calling monitor callback method " + Variant::get_callable_error_text(monitor_callback, (const Variant **)resptr, 5, ce));
+ }
}
} else {
monitored_bodies.clear();
@@ -315,6 +319,10 @@ void GodotArea3D::call_queries() {
Callable::CallError ce;
Variant ret;
area_monitor_callback.callp((const Variant **)resptr, 5, ret, ce);
+
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT_ONCE("Error calling area monitor callback method " + Variant::get_callable_error_text(area_monitor_callback, (const Variant **)resptr, 5, ce));
+ }
}
} else {
monitored_areas.clear();
diff --git a/servers/physics_3d/godot_body_3d.cpp b/servers/physics_3d/godot_body_3d.cpp
index 4c89106839..b632f7f461 100644
--- a/servers/physics_3d/godot_body_3d.cpp
+++ b/servers/physics_3d/godot_body_3d.cpp
@@ -56,7 +56,7 @@ void GodotBody3D::update_mass_properties() {
// Update shapes and motions.
switch (mode) {
- case PhysicsServer3D::BODY_MODE_DYNAMIC: {
+ case PhysicsServer3D::BODY_MODE_RIGID: {
real_t total_area = 0;
for (int i = 0; i < get_shape_count(); i++) {
if (is_shape_disabled(i)) {
@@ -154,7 +154,7 @@ void GodotBody3D::update_mass_properties() {
_inv_inertia = Vector3();
_inv_mass = 0;
} break;
- case PhysicsServer3D::BODY_MODE_DYNAMIC_LINEAR: {
+ case PhysicsServer3D::BODY_MODE_RIGID_LINEAR: {
_inv_inertia_tensor.set_zero();
_inv_mass = 1.0 / mass;
@@ -201,7 +201,7 @@ void GodotBody3D::set_param(PhysicsServer3D::BodyParameter p_param, const Varian
real_t mass_value = p_value;
ERR_FAIL_COND(mass_value <= 0);
mass = mass_value;
- if (mode >= PhysicsServer3D::BODY_MODE_DYNAMIC) {
+ if (mode >= PhysicsServer3D::BODY_MODE_RIGID) {
_mass_properties_changed();
}
} break;
@@ -209,12 +209,12 @@ void GodotBody3D::set_param(PhysicsServer3D::BodyParameter p_param, const Varian
inertia = p_value;
if ((inertia.x <= 0.0) || (inertia.y <= 0.0) || (inertia.z <= 0.0)) {
calculate_inertia = true;
- if (mode == PhysicsServer3D::BODY_MODE_DYNAMIC) {
+ if (mode == PhysicsServer3D::BODY_MODE_RIGID) {
_mass_properties_changed();
}
} else {
calculate_inertia = false;
- if (mode == PhysicsServer3D::BODY_MODE_DYNAMIC) {
+ if (mode == PhysicsServer3D::BODY_MODE_RIGID) {
principal_inertia_axes_local = Basis();
_inv_inertia = inertia.inverse();
_update_transform_dependent();
@@ -263,7 +263,7 @@ Variant GodotBody3D::get_param(PhysicsServer3D::BodyParameter p_param) const {
return mass;
} break;
case PhysicsServer3D::BODY_PARAM_INERTIA: {
- if (mode == PhysicsServer3D::BODY_MODE_DYNAMIC) {
+ if (mode == PhysicsServer3D::BODY_MODE_RIGID) {
return _inv_inertia.inverse();
} else {
return Vector3();
@@ -315,7 +315,7 @@ void GodotBody3D::set_mode(PhysicsServer3D::BodyMode p_mode) {
_update_transform_dependent();
} break;
- case PhysicsServer3D::BODY_MODE_DYNAMIC: {
+ case PhysicsServer3D::BODY_MODE_RIGID: {
_inv_mass = mass > 0 ? (1.0 / mass) : 0;
if (!calculate_inertia) {
principal_inertia_axes_local = Basis();
@@ -327,7 +327,7 @@ void GodotBody3D::set_mode(PhysicsServer3D::BodyMode p_mode) {
set_active(true);
} break;
- case PhysicsServer3D::BODY_MODE_DYNAMIC_LINEAR: {
+ case PhysicsServer3D::BODY_MODE_RIGID_LINEAR: {
_inv_mass = mass > 0 ? (1.0 / mass) : 0;
_inv_inertia = Vector3();
angular_velocity = Vector3();
@@ -407,7 +407,7 @@ void GodotBody3D::set_state(PhysicsServer3D::BodyState p_state, const Variant &p
} break;
case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
can_sleep = p_variant;
- if (mode >= PhysicsServer3D::BODY_MODE_DYNAMIC && !active && !can_sleep) {
+ if (mode >= PhysicsServer3D::BODY_MODE_RIGID && !active && !can_sleep) {
set_active(true);
}
@@ -744,7 +744,7 @@ void GodotBody3D::wakeup_neighbours() {
continue;
}
GodotBody3D *b = n[i];
- if (b->mode < PhysicsServer3D::BODY_MODE_DYNAMIC) {
+ if (b->mode < PhysicsServer3D::BODY_MODE_RIGID) {
continue;
}
diff --git a/servers/physics_3d/godot_body_3d.h b/servers/physics_3d/godot_body_3d.h
index 93bd5a0071..2153ca4e91 100644
--- a/servers/physics_3d/godot_body_3d.h
+++ b/servers/physics_3d/godot_body_3d.h
@@ -40,7 +40,7 @@ class GodotConstraint3D;
class GodotPhysicsDirectBodyState3D;
class GodotBody3D : public GodotCollisionObject3D {
- PhysicsServer3D::BodyMode mode = PhysicsServer3D::BODY_MODE_DYNAMIC;
+ PhysicsServer3D::BodyMode mode = PhysicsServer3D::BODY_MODE_RIGID;
Vector3 linear_velocity;
Vector3 angular_velocity;
diff --git a/servers/physics_3d/godot_collision_object_3d.h b/servers/physics_3d/godot_collision_object_3d.h
index 0f09f21962..2d342f65f3 100644
--- a/servers/physics_3d/godot_collision_object_3d.h
+++ b/servers/physics_3d/godot_collision_object_3d.h
@@ -59,6 +59,7 @@ private:
ObjectID instance_id;
uint32_t collision_layer = 1;
uint32_t collision_mask = 1;
+ real_t collision_priority = 1.0;
struct Shape {
Transform3D xform;
@@ -165,6 +166,13 @@ public:
}
_FORCE_INLINE_ uint32_t get_collision_mask() const { return collision_mask; }
+ _FORCE_INLINE_ void set_collision_priority(real_t p_priority) {
+ ERR_FAIL_COND_MSG(p_priority <= 0, "Priority must be greater than 0.");
+ collision_priority = p_priority;
+ _shape_changed();
+ }
+ _FORCE_INLINE_ real_t get_collision_priority() const { return collision_priority; }
+
_FORCE_INLINE_ bool collides_with(GodotCollisionObject3D *p_other) const {
return p_other->collision_layer & collision_mask;
}
diff --git a/servers/physics_3d/godot_collision_solver_3d.cpp b/servers/physics_3d/godot_collision_solver_3d.cpp
index b2d3e4d876..094d77a582 100644
--- a/servers/physics_3d/godot_collision_solver_3d.cpp
+++ b/servers/physics_3d/godot_collision_solver_3d.cpp
@@ -38,7 +38,7 @@
#define collision_solver sat_calculate_penetration
//#define collision_solver gjk_epa_calculate_penetration
-bool GodotCollisionSolver3D::solve_static_world_boundary(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) {
+bool GodotCollisionSolver3D::solve_static_world_boundary(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin) {
const GodotWorldBoundaryShape3D *world_boundary = static_cast<const GodotWorldBoundaryShape3D *>(p_shape_A);
if (p_shape_B->get_type() == PhysicsServer3D::SHAPE_WORLD_BOUNDARY) {
return false;
@@ -70,6 +70,7 @@ bool GodotCollisionSolver3D::solve_static_world_boundary(const GodotShape3D *p_s
bool found = false;
for (int i = 0; i < support_count; i++) {
+ supports[i] += p_margin * supports[i].normalized();
supports[i] = p_transform_B.xform(supports[i]);
if (p.distance_to(supports[i]) >= 0) {
continue;
@@ -379,9 +380,9 @@ bool GodotCollisionSolver3D::solve_static(const GodotShape3D *p_shape_A, const T
}
if (swap) {
- return solve_static_world_boundary(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true);
+ return solve_static_world_boundary(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true, p_margin_A);
} else {
- return solve_static_world_boundary(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false);
+ return solve_static_world_boundary(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false, p_margin_B);
}
} else if (type_A == PhysicsServer3D::SHAPE_SEPARATION_RAY) {
@@ -456,8 +457,17 @@ bool GodotCollisionSolver3D::solve_distance_world_boundary(const GodotShape3D *p
Vector3 supports[max_supports];
int support_count;
GodotShape3D::FeatureType support_type;
+ Vector3 support_direction = p_transform_B.basis.xform_inv(-p.normal).normalized();
- p_shape_B->get_supports(p_transform_B.basis.xform_inv(-p.normal).normalized(), max_supports, supports, support_count, support_type);
+ p_shape_B->get_supports(support_direction, max_supports, supports, support_count, support_type);
+
+ if (support_count == 0) { // This is a poor man's way to detect shapes that don't implement get_supports, such as GodotMotionShape3D.
+ Vector3 support_B = p_transform_B.xform(p_shape_B->get_support(support_direction));
+ r_point_A = p.project(support_B);
+ r_point_B = support_B;
+ bool collided = p.distance_to(support_B) <= 0;
+ return collided;
+ }
if (support_type == GodotShape3D::FEATURE_CIRCLE) {
ERR_FAIL_COND_V(support_count != 3, false);
diff --git a/servers/physics_3d/godot_collision_solver_3d.h b/servers/physics_3d/godot_collision_solver_3d.h
index a6a0ebfead..e7d67903e9 100644
--- a/servers/physics_3d/godot_collision_solver_3d.h
+++ b/servers/physics_3d/godot_collision_solver_3d.h
@@ -42,7 +42,7 @@ private:
static void soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
static bool soft_body_concave_callback(void *p_userdata, GodotShape3D *p_convex);
static bool concave_callback(void *p_userdata, GodotShape3D *p_convex);
- static bool solve_static_world_boundary(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
+ static bool solve_static_world_boundary(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin = 0);
static bool solve_separation_ray(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin = 0);
static bool solve_soft_body(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
static bool solve_concave(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin_A = 0, real_t p_margin_B = 0);
diff --git a/servers/physics_3d/godot_physics_server_3d.cpp b/servers/physics_3d/godot_physics_server_3d.cpp
index b735283ebe..9c1535f561 100644
--- a/servers/physics_3d/godot_physics_server_3d.cpp
+++ b/servers/physics_3d/godot_physics_server_3d.cpp
@@ -593,6 +593,20 @@ uint32_t GodotPhysicsServer3D::body_get_collision_mask(RID p_body) const {
return body->get_collision_mask();
}
+void GodotPhysicsServer3D::body_set_collision_priority(RID p_body, real_t p_priority) {
+ GodotBody3D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND(!body);
+
+ body->set_collision_priority(p_priority);
+}
+
+real_t GodotPhysicsServer3D::body_get_collision_priority(RID p_body) const {
+ const GodotBody3D *body = body_owner.get_or_null(p_body);
+ ERR_FAIL_COND_V(!body, 0);
+
+ return body->get_collision_priority();
+}
+
void GodotPhysicsServer3D::body_attach_object_instance_id(RID p_body, ObjectID p_id) {
GodotBody3D *body = body_owner.get_or_null(p_body);
if (body) {
diff --git a/servers/physics_3d/godot_physics_server_3d.h b/servers/physics_3d/godot_physics_server_3d.h
index 1d57451925..b429f23a0c 100644
--- a/servers/physics_3d/godot_physics_server_3d.h
+++ b/servers/physics_3d/godot_physics_server_3d.h
@@ -192,6 +192,9 @@ public:
virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) override;
virtual uint32_t body_get_collision_mask(RID p_body) const override;
+ virtual void body_set_collision_priority(RID p_body, real_t p_priority) override;
+ virtual real_t body_get_collision_priority(RID p_body) const override;
+
virtual void body_set_user_flags(RID p_body, uint32_t p_flags) override;
virtual uint32_t body_get_user_flags(RID p_body) const override;
diff --git a/servers/physics_3d/godot_space_3d.cpp b/servers/physics_3d/godot_space_3d.cpp
index 533d7605ce..76d59202c9 100644
--- a/servers/physics_3d/godot_space_3d.cpp
+++ b/servers/physics_3d/godot_space_3d.cpp
@@ -701,6 +701,7 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
const int max_results = 32;
int recover_attempts = 4;
Vector3 sr[max_results * 2];
+ real_t priorities[max_results];
do {
GodotPhysicsServer3D::CollCbkData cbk;
@@ -710,6 +711,7 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
GodotPhysicsServer3D::CollCbkData *cbkptr = &cbk;
GodotCollisionSolver3D::CallbackResult cbkres = GodotPhysicsServer3D::_shape_col_cbk;
+ int priority_amount = 0;
bool collided = false;
@@ -737,6 +739,10 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
if (GodotCollisionSolver3D::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, nullptr, margin)) {
collided = cbk.amount > 0;
}
+ while (cbk.amount > priority_amount) {
+ priorities[priority_amount] = col_obj->get_collision_priority();
+ priority_amount++;
+ }
}
}
@@ -744,6 +750,12 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
break;
}
+ real_t inv_total_weight = 0.0;
+ for (int i = 0; i < cbk.amount; i++) {
+ inv_total_weight += priorities[i];
+ }
+ inv_total_weight = Math::is_zero_approx(inv_total_weight) ? 1.0 : (real_t)cbk.amount / inv_total_weight;
+
recovered = true;
Vector3 recover_motion;
@@ -759,7 +771,7 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
real_t depth = n.dot(a + recover_motion) - d;
if (depth > min_contact_depth + CMP_EPSILON) {
// Only recover if there is penetration.
- recover_motion -= n * (depth - min_contact_depth) * 0.4;
+ recover_motion -= n * (depth - min_contact_depth) * 0.4 * priorities[i] * inv_total_weight;
}
}
@@ -989,6 +1001,7 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
r_result->collision_unsafe_fraction = unsafe;
r_result->collision_count = rcd.result_count;
+ r_result->collision_depth = rcd.best_result.len;
}
collided = true;
@@ -1002,6 +1015,7 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::
r_result->collision_safe_fraction = 1.0;
r_result->collision_unsafe_fraction = 1.0;
+ r_result->collision_depth = 0.0;
}
return collided;
@@ -1235,7 +1249,7 @@ GodotPhysicsDirectSpaceState3D *GodotSpace3D::get_direct_state() {
GodotSpace3D::GodotSpace3D() {
body_linear_velocity_sleep_threshold = GLOBAL_DEF("physics/3d/sleep_threshold_linear", 0.1);
- body_angular_velocity_sleep_threshold = GLOBAL_DEF("physics/3d/sleep_threshold_angular", Math::deg2rad(8.0));
+ body_angular_velocity_sleep_threshold = GLOBAL_DEF("physics/3d/sleep_threshold_angular", Math::deg_to_rad(8.0));
body_time_to_sleep = GLOBAL_DEF("physics/3d/time_before_sleep", 0.5);
ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/time_before_sleep", PropertyInfo(Variant::FLOAT, "physics/3d/time_before_sleep", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater"));
diff --git a/servers/physics_3d/godot_step_3d.cpp b/servers/physics_3d/godot_step_3d.cpp
index f384c829a4..bfedcd29c0 100644
--- a/servers/physics_3d/godot_step_3d.cpp
+++ b/servers/physics_3d/godot_step_3d.cpp
@@ -44,7 +44,7 @@ void GodotStep3D::_populate_island(GodotBody3D *p_body, LocalVector<GodotBody3D
p_body->set_island_step(_step);
if (p_body->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC) {
- // Only dynamic bodies are tested for activation.
+ // Only rigid bodies are tested for activation.
p_body_island.push_back(p_body);
}
diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp
index 41aae36785..ca9c9c8fc4 100644
--- a/servers/physics_server_2d.cpp
+++ b/servers/physics_server_2d.cpp
@@ -32,6 +32,7 @@
#include "core/config/project_settings.h"
#include "core/string/print_string.h"
+#include "core/variant/typed_array.h"
PhysicsServer2D *PhysicsServer2D::singleton = nullptr;
@@ -147,6 +148,16 @@ PhysicsDirectBodyState2D::PhysicsDirectBodyState2D() {}
///////////////////////////////////////////////////////
+Ref<PhysicsRayQueryParameters2D> PhysicsRayQueryParameters2D::create(Vector2 p_from, Vector2 p_to, uint32_t p_mask, const Vector<RID> &p_exclude) {
+ Ref<PhysicsRayQueryParameters2D> params;
+ params.instantiate();
+ params->set_from(p_from);
+ params->set_to(p_to);
+ params->set_collision_mask(p_mask);
+ params->set_exclude(p_exclude);
+ return params;
+}
+
void PhysicsRayQueryParameters2D::set_exclude(const Vector<RID> &p_exclude) {
parameters.exclude.clear();
for (int i = 0; i < p_exclude.size(); i++) {
@@ -165,6 +176,8 @@ Vector<RID> PhysicsRayQueryParameters2D::get_exclude() const {
}
void PhysicsRayQueryParameters2D::_bind_methods() {
+ ClassDB::bind_static_method("PhysicsRayQueryParameters2D", D_METHOD("create", "from", "to", "collision_mask", "exclude"), &PhysicsRayQueryParameters2D::create, DEFVAL(UINT32_MAX), DEFVAL(Vector<RID>()));
+
ClassDB::bind_method(D_METHOD("set_from", "from"), &PhysicsRayQueryParameters2D::set_from);
ClassDB::bind_method(D_METHOD("get_from"), &PhysicsRayQueryParameters2D::get_from);
@@ -335,7 +348,7 @@ Dictionary PhysicsDirectSpaceState2D::_intersect_ray(const Ref<PhysicsRayQueryPa
return d;
}
-Array PhysicsDirectSpaceState2D::_intersect_point(const Ref<PhysicsPointQueryParameters2D> &p_point_query, int p_max_results) {
+TypedArray<Dictionary> PhysicsDirectSpaceState2D::_intersect_point(const Ref<PhysicsPointQueryParameters2D> &p_point_query, int p_max_results) {
ERR_FAIL_COND_V(p_point_query.is_null(), Array());
Vector<ShapeResult> ret;
@@ -344,10 +357,10 @@ Array PhysicsDirectSpaceState2D::_intersect_point(const Ref<PhysicsPointQueryPar
int rc = intersect_point(p_point_query->get_parameters(), ret.ptrw(), ret.size());
if (rc == 0) {
- return Array();
+ return TypedArray<Dictionary>();
}
- Array r;
+ TypedArray<Dictionary> r;
r.resize(rc);
for (int i = 0; i < rc; i++) {
Dictionary d;
@@ -360,13 +373,13 @@ Array PhysicsDirectSpaceState2D::_intersect_point(const Ref<PhysicsPointQueryPar
return r;
}
-Array PhysicsDirectSpaceState2D::_intersect_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results) {
- ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array());
+TypedArray<Dictionary> PhysicsDirectSpaceState2D::_intersect_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results) {
+ ERR_FAIL_COND_V(!p_shape_query.is_valid(), TypedArray<Dictionary>());
Vector<ShapeResult> sr;
sr.resize(p_max_results);
int rc = intersect_shape(p_shape_query->get_parameters(), sr.ptrw(), sr.size());
- Array ret;
+ TypedArray<Dictionary> ret;
ret.resize(rc);
for (int i = 0; i < rc; i++) {
Dictionary d;
@@ -380,22 +393,22 @@ Array PhysicsDirectSpaceState2D::_intersect_shape(const Ref<PhysicsShapeQueryPar
return ret;
}
-Array PhysicsDirectSpaceState2D::_cast_motion(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query) {
- ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array());
+Vector<real_t> PhysicsDirectSpaceState2D::_cast_motion(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query) {
+ ERR_FAIL_COND_V(!p_shape_query.is_valid(), Vector<real_t>());
real_t closest_safe, closest_unsafe;
bool res = cast_motion(p_shape_query->get_parameters(), closest_safe, closest_unsafe);
if (!res) {
- return Array();
+ return Vector<real_t>();
}
- Array ret;
+ Vector<real_t> ret;
ret.resize(2);
- ret[0] = closest_safe;
- ret[1] = closest_unsafe;
+ ret.write[0] = closest_safe;
+ ret.write[1] = closest_unsafe;
return ret;
}
-Array PhysicsDirectSpaceState2D::_collide_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results) {
+TypedArray<PackedVector2Array> PhysicsDirectSpaceState2D::_collide_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results) {
ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array());
Vector<Vector2> ret;
@@ -403,9 +416,9 @@ Array PhysicsDirectSpaceState2D::_collide_shape(const Ref<PhysicsShapeQueryParam
int rc = 0;
bool res = collide_shape(p_shape_query->get_parameters(), ret.ptrw(), p_max_results, rc);
if (!res) {
- return Array();
+ return TypedArray<PackedVector2Array>();
}
- Array r;
+ TypedArray<PackedVector2Array> r;
r.resize(rc * 2);
for (int i = 0; i < rc * 2; i++) {
r[i] = ret[i];
@@ -694,6 +707,9 @@ void PhysicsServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_set_collision_mask", "body", "mask"), &PhysicsServer2D::body_set_collision_mask);
ClassDB::bind_method(D_METHOD("body_get_collision_mask", "body"), &PhysicsServer2D::body_get_collision_mask);
+ ClassDB::bind_method(D_METHOD("body_set_collision_priority", "body", "priority"), &PhysicsServer2D::body_set_collision_priority);
+ ClassDB::bind_method(D_METHOD("body_get_collision_priority", "body"), &PhysicsServer2D::body_get_collision_priority);
+
ClassDB::bind_method(D_METHOD("body_set_param", "body", "param", "value"), &PhysicsServer2D::body_set_param);
ClassDB::bind_method(D_METHOD("body_get_param", "body", "param"), &PhysicsServer2D::body_get_param);
@@ -801,8 +817,8 @@ void PhysicsServer2D::_bind_methods() {
BIND_ENUM_CONSTANT(BODY_MODE_STATIC);
BIND_ENUM_CONSTANT(BODY_MODE_KINEMATIC);
- BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC);
- BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC_LINEAR);
+ BIND_ENUM_CONSTANT(BODY_MODE_RIGID);
+ BIND_ENUM_CONSTANT(BODY_MODE_RIGID_LINEAR);
BIND_ENUM_CONSTANT(BODY_PARAM_BOUNCE);
BIND_ENUM_CONSTANT(BODY_PARAM_FRICTION);
diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h
index 7a821c64e6..071ff5ffe9 100644
--- a/servers/physics_server_2d.h
+++ b/servers/physics_server_2d.h
@@ -36,6 +36,8 @@
#include "core/object/ref_counted.h"
class PhysicsDirectSpaceState2D;
+template <typename T>
+class TypedArray;
class PhysicsDirectBodyState2D : public Object {
GDCLASS(PhysicsDirectBodyState2D, Object);
@@ -114,10 +116,10 @@ class PhysicsDirectSpaceState2D : public Object {
GDCLASS(PhysicsDirectSpaceState2D, Object);
Dictionary _intersect_ray(const Ref<PhysicsRayQueryParameters2D> &p_ray_query);
- Array _intersect_point(const Ref<PhysicsPointQueryParameters2D> &p_point_query, int p_max_results = 32);
- Array _intersect_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results = 32);
- Array _cast_motion(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query);
- Array _collide_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results = 32);
+ TypedArray<Dictionary> _intersect_point(const Ref<PhysicsPointQueryParameters2D> &p_point_query, int p_max_results = 32);
+ TypedArray<Dictionary> _intersect_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results = 32);
+ Vector<real_t> _cast_motion(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query);
+ TypedArray<PackedVector2Array> _collide_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results = 32);
Dictionary _get_rest_info(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query);
protected:
@@ -346,8 +348,8 @@ public:
enum BodyMode {
BODY_MODE_STATIC,
BODY_MODE_KINEMATIC,
- BODY_MODE_DYNAMIC,
- BODY_MODE_DYNAMIC_LINEAR,
+ BODY_MODE_RIGID,
+ BODY_MODE_RIGID_LINEAR,
};
virtual RID body_create() = 0;
@@ -393,6 +395,9 @@ public:
virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) = 0;
virtual uint32_t body_get_collision_mask(RID p_body) const = 0;
+ virtual void body_set_collision_priority(RID p_body, real_t p_priority) = 0;
+ virtual real_t body_get_collision_priority(RID p_body) const = 0;
+
// common body variables
enum BodyParameter {
BODY_PARAM_BOUNCE,
@@ -605,6 +610,7 @@ protected:
static void _bind_methods();
public:
+ static Ref<PhysicsRayQueryParameters2D> create(Vector2 p_from, Vector2 p_to, uint32_t p_mask, const Vector<RID> &p_exclude);
const PhysicsDirectSpaceState2D::RayParameters &get_parameters() const { return parameters; }
void set_from(const Vector2 &p_from) { parameters.from = p_from; }
diff --git a/servers/physics_server_2d_wrap_mt.h b/servers/physics_server_2d_wrap_mt.h
index ddb071f603..d080aac438 100644
--- a/servers/physics_server_2d_wrap_mt.h
+++ b/servers/physics_server_2d_wrap_mt.h
@@ -205,6 +205,9 @@ public:
FUNC2(body_set_collision_mask, RID, uint32_t);
FUNC1RC(uint32_t, body_get_collision_mask, RID);
+ FUNC2(body_set_collision_priority, RID, real_t);
+ FUNC1RC(real_t, body_get_collision_priority, RID);
+
FUNC3(body_set_param, RID, BodyParameter, const Variant &);
FUNC2RC(Variant, body_get_param, RID, BodyParameter);
diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp
index a606d055f7..fc32e1f665 100644
--- a/servers/physics_server_3d.cpp
+++ b/servers/physics_server_3d.cpp
@@ -32,6 +32,7 @@
#include "core/config/project_settings.h"
#include "core/string/print_string.h"
+#include "core/variant/typed_array.h"
void PhysicsServer3DRenderingServerHandler::set_vertex(int p_vertex_id, const void *p_vector3) {
GDVIRTUAL_REQUIRED_CALL(_set_vertex, p_vertex_id, p_vector3);
@@ -184,6 +185,8 @@ Vector<RID> PhysicsRayQueryParameters3D::get_exclude() const {
}
void PhysicsRayQueryParameters3D::_bind_methods() {
+ ClassDB::bind_static_method("PhysicsRayQueryParameters3D", D_METHOD("create", "from", "to", "collision_mask", "exclude"), &PhysicsRayQueryParameters3D::create, DEFVAL(UINT32_MAX), DEFVAL(Vector<RID>()));
+
ClassDB::bind_method(D_METHOD("set_from", "from"), &PhysicsRayQueryParameters3D::set_from);
ClassDB::bind_method(D_METHOD("get_from"), &PhysicsRayQueryParameters3D::get_from);
@@ -220,6 +223,16 @@ void PhysicsRayQueryParameters3D::_bind_methods() {
///////////////////////////////////////////////////////
+Ref<PhysicsRayQueryParameters3D> PhysicsRayQueryParameters3D::create(Vector3 p_from, Vector3 p_to, uint32_t p_mask, const Vector<RID> &p_exclude) {
+ Ref<PhysicsRayQueryParameters3D> params;
+ params.instantiate();
+ params->set_from(p_from);
+ params->set_to(p_to);
+ params->set_collision_mask(p_mask);
+ params->set_exclude(p_exclude);
+ return params;
+}
+
void PhysicsPointQueryParameters3D::set_exclude(const Vector<RID> &p_exclude) {
parameters.exclude.clear();
for (int i = 0; i < p_exclude.size(); i++) {
@@ -354,8 +367,8 @@ Dictionary PhysicsDirectSpaceState3D::_intersect_ray(const Ref<PhysicsRayQueryPa
return d;
}
-Array PhysicsDirectSpaceState3D::_intersect_point(const Ref<PhysicsPointQueryParameters3D> &p_point_query, int p_max_results) {
- ERR_FAIL_COND_V(p_point_query.is_null(), Array());
+TypedArray<Dictionary> PhysicsDirectSpaceState3D::_intersect_point(const Ref<PhysicsPointQueryParameters3D> &p_point_query, int p_max_results) {
+ ERR_FAIL_COND_V(p_point_query.is_null(), TypedArray<Dictionary>());
Vector<ShapeResult> ret;
ret.resize(p_max_results);
@@ -363,10 +376,10 @@ Array PhysicsDirectSpaceState3D::_intersect_point(const Ref<PhysicsPointQueryPar
int rc = intersect_point(p_point_query->get_parameters(), ret.ptrw(), ret.size());
if (rc == 0) {
- return Array();
+ return TypedArray<Dictionary>();
}
- Array r;
+ TypedArray<Dictionary> r;
r.resize(rc);
for (int i = 0; i < rc; i++) {
Dictionary d;
@@ -379,13 +392,13 @@ Array PhysicsDirectSpaceState3D::_intersect_point(const Ref<PhysicsPointQueryPar
return r;
}
-Array PhysicsDirectSpaceState3D::_intersect_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results) {
- ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array());
+TypedArray<Dictionary> PhysicsDirectSpaceState3D::_intersect_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results) {
+ ERR_FAIL_COND_V(!p_shape_query.is_valid(), TypedArray<Dictionary>());
Vector<ShapeResult> sr;
sr.resize(p_max_results);
int rc = intersect_shape(p_shape_query->get_parameters(), sr.ptrw(), sr.size());
- Array ret;
+ TypedArray<Dictionary> ret;
ret.resize(rc);
for (int i = 0; i < rc; i++) {
Dictionary d;
@@ -399,22 +412,22 @@ Array PhysicsDirectSpaceState3D::_intersect_shape(const Ref<PhysicsShapeQueryPar
return ret;
}
-Array PhysicsDirectSpaceState3D::_cast_motion(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query) {
- ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array());
+Vector<real_t> PhysicsDirectSpaceState3D::_cast_motion(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query) {
+ ERR_FAIL_COND_V(!p_shape_query.is_valid(), Vector<real_t>());
real_t closest_safe = 1.0f, closest_unsafe = 1.0f;
bool res = cast_motion(p_shape_query->get_parameters(), closest_safe, closest_unsafe);
if (!res) {
- return Array();
+ return Vector<real_t>();
}
- Array ret;
+ Vector<real_t> ret;
ret.resize(2);
- ret[0] = closest_safe;
- ret[1] = closest_unsafe;
+ ret.write[0] = closest_safe;
+ ret.write[1] = closest_unsafe;
return ret;
}
-Array PhysicsDirectSpaceState3D::_collide_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results) {
+TypedArray<PackedVector2Array> PhysicsDirectSpaceState3D::_collide_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results) {
ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array());
Vector<Vector3> ret;
@@ -422,9 +435,9 @@ Array PhysicsDirectSpaceState3D::_collide_shape(const Ref<PhysicsShapeQueryParam
int rc = 0;
bool res = collide_shape(p_shape_query->get_parameters(), ret.ptrw(), p_max_results, rc);
if (!res) {
- return Array();
+ return TypedArray<PackedVector2Array>();
}
- Array r;
+ TypedArray<PackedVector2Array> r;
r.resize(rc * 2);
for (int i = 0; i < rc * 2; i++) {
r[i] = ret[i];
@@ -738,6 +751,9 @@ void PhysicsServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_set_collision_mask", "body", "mask"), &PhysicsServer3D::body_set_collision_mask);
ClassDB::bind_method(D_METHOD("body_get_collision_mask", "body"), &PhysicsServer3D::body_get_collision_mask);
+ ClassDB::bind_method(D_METHOD("body_set_collision_priority", "body", "priority"), &PhysicsServer3D::body_set_collision_priority);
+ ClassDB::bind_method(D_METHOD("body_get_collision_priority", "body"), &PhysicsServer3D::body_get_collision_priority);
+
ClassDB::bind_method(D_METHOD("body_add_shape", "body", "shape", "transform", "disabled"), &PhysicsServer3D::body_add_shape, DEFVAL(Transform3D()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("body_set_shape", "body", "shape_idx", "shape"), &PhysicsServer3D::body_set_shape);
ClassDB::bind_method(D_METHOD("body_set_shape_transform", "body", "shape_idx", "transform"), &PhysicsServer3D::body_set_shape_transform);
@@ -972,8 +988,8 @@ void PhysicsServer3D::_bind_methods() {
BIND_ENUM_CONSTANT(BODY_MODE_STATIC);
BIND_ENUM_CONSTANT(BODY_MODE_KINEMATIC);
- BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC);
- BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC_LINEAR);
+ BIND_ENUM_CONSTANT(BODY_MODE_RIGID);
+ BIND_ENUM_CONSTANT(BODY_MODE_RIGID_LINEAR);
BIND_ENUM_CONSTANT(BODY_PARAM_BOUNCE);
BIND_ENUM_CONSTANT(BODY_PARAM_FRICTION);
diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h
index 86a41d96ef..6237ed67aa 100644
--- a/servers/physics_server_3d.h
+++ b/servers/physics_server_3d.h
@@ -38,6 +38,8 @@
#include "core/variant/native_ptr.h"
class PhysicsDirectSpaceState3D;
+template <typename T>
+class TypedArray;
class PhysicsDirectBodyState3D : public Object {
GDCLASS(PhysicsDirectBodyState3D, Object);
@@ -120,10 +122,10 @@ class PhysicsDirectSpaceState3D : public Object {
private:
Dictionary _intersect_ray(const Ref<PhysicsRayQueryParameters3D> &p_ray_query);
- Array _intersect_point(const Ref<PhysicsPointQueryParameters3D> &p_point_query, int p_max_results = 32);
- Array _intersect_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results = 32);
- Array _cast_motion(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query);
- Array _collide_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results = 32);
+ TypedArray<Dictionary> _intersect_point(const Ref<PhysicsPointQueryParameters3D> &p_point_query, int p_max_results = 32);
+ TypedArray<Dictionary> _intersect_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results = 32);
+ Vector<real_t> _cast_motion(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query);
+ TypedArray<PackedVector2Array> _collide_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results = 32);
Dictionary _get_rest_info(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query);
protected:
@@ -379,8 +381,8 @@ public:
enum BodyMode {
BODY_MODE_STATIC,
BODY_MODE_KINEMATIC,
- BODY_MODE_DYNAMIC,
- BODY_MODE_DYNAMIC_LINEAR,
+ BODY_MODE_RIGID,
+ BODY_MODE_RIGID_LINEAR,
};
enum BodyDampMode {
@@ -421,6 +423,9 @@ public:
virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) = 0;
virtual uint32_t body_get_collision_mask(RID p_body) const = 0;
+ virtual void body_set_collision_priority(RID p_body, real_t p_priority) = 0;
+ virtual real_t body_get_collision_priority(RID p_body) const = 0;
+
virtual void body_set_user_flags(RID p_body, uint32_t p_flags) = 0;
virtual uint32_t body_get_user_flags(RID p_body) const = 0;
@@ -550,6 +555,7 @@ public:
struct MotionResult {
Vector3 travel;
Vector3 remainder;
+ real_t collision_depth = 0.0;
real_t collision_safe_fraction = 0.0;
real_t collision_unsafe_fraction = 0.0;
@@ -816,6 +822,7 @@ protected:
static void _bind_methods();
public:
+ static Ref<PhysicsRayQueryParameters3D> create(Vector3 p_from, Vector3 p_to, uint32_t p_mask, const Vector<RID> &p_exclude);
const PhysicsDirectSpaceState3D::RayParameters &get_parameters() const { return parameters; }
void set_from(const Vector3 &p_from) { parameters.from = p_from; }
diff --git a/servers/physics_server_3d_wrap_mt.h b/servers/physics_server_3d_wrap_mt.h
index d4a4ad3132..ed4546b240 100644
--- a/servers/physics_server_3d_wrap_mt.h
+++ b/servers/physics_server_3d_wrap_mt.h
@@ -202,6 +202,9 @@ public:
FUNC2(body_set_collision_mask, RID, uint32_t);
FUNC1RC(uint32_t, body_get_collision_mask, RID);
+ FUNC2(body_set_collision_priority, RID, real_t);
+ FUNC1RC(real_t, body_get_collision_priority, RID);
+
FUNC2(body_set_user_flags, RID, uint32_t);
FUNC1RC(uint32_t, body_get_user_flags, RID);
diff --git a/servers/rendering/dummy/storage/material_storage.h b/servers/rendering/dummy/storage/material_storage.h
index 55c42330cf..e25a2ac3a9 100644
--- a/servers/rendering/dummy/storage/material_storage.h
+++ b/servers/rendering/dummy/storage/material_storage.h
@@ -66,7 +66,7 @@ public:
virtual void shader_set_path_hint(RID p_shader, const String &p_code) override {}
virtual String shader_get_code(RID p_shader) const override { return ""; }
- virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const override {}
+ virtual void shader_get_shader_uniform_list(RID p_shader, List<PropertyInfo> *p_param_list) const override {}
virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture, int p_index) override {}
virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name, int p_index) const override { return RID(); }
@@ -89,7 +89,7 @@ public:
virtual bool material_is_animated(RID p_material) override { return false; }
virtual bool material_casts_shadows(RID p_material) override { return false; }
- virtual void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) override {}
+ virtual void material_get_instance_shader_uniforms(RID p_material, List<InstanceShaderParam> *r_parameters) override {}
virtual void material_update_dependency(RID p_material, DependencyTracker *p_instance) override {}
};
diff --git a/servers/rendering/dummy/storage/mesh_storage.h b/servers/rendering/dummy/storage/mesh_storage.h
index 8dfcd978ac..aab5145982 100644
--- a/servers/rendering/dummy/storage/mesh_storage.h
+++ b/servers/rendering/dummy/storage/mesh_storage.h
@@ -37,17 +37,44 @@
namespace RendererDummy {
class MeshStorage : public RendererMeshStorage {
+private:
+ struct DummyMesh : public RID {
+ Vector<RS::SurfaceData> surfaces;
+ int blend_shape_count;
+ RS::BlendShapeMode blend_shape_mode;
+ PackedFloat32Array blend_shape_values;
+ };
+
+ mutable RID_Owner<DummyMesh> mesh_owner;
+
public:
/* MESH API */
- virtual RID mesh_allocate() override { return RID(); }
- virtual void mesh_initialize(RID p_rid) override {}
+ virtual RID mesh_allocate() override {
+ return mesh_owner.allocate_rid();
+ }
+
+ virtual void mesh_initialize(RID p_rid) override {
+ mesh_owner.initialize_rid(p_rid, DummyMesh());
+ }
virtual void mesh_free(RID p_rid) override {}
virtual void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) override {}
virtual bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) override { return false; }
- virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) override {}
+ virtual void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) override {
+ DummyMesh *m = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND(!m);
+ m->surfaces.push_back(RS::SurfaceData());
+ RS::SurfaceData *s = &m->surfaces.write[m->surfaces.size() - 1];
+ s->format = p_surface.format;
+ s->primitive = p_surface.primitive;
+ s->vertex_data = p_surface.vertex_data;
+ s->attribute_data = p_surface.attribute_data;
+ s->vertex_count = p_surface.vertex_count;
+ s->index_data = p_surface.index_data;
+ s->index_count = p_surface.index_count;
+ }
virtual int mesh_get_blend_shape_count(RID p_mesh) const override { return 0; }
@@ -61,8 +88,19 @@ public:
virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) override {}
virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const override { return RID(); }
- virtual RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const override { return RS::SurfaceData(); }
- virtual int mesh_get_surface_count(RID p_mesh) const override { return 0; }
+ virtual RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const override {
+ DummyMesh *m = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND_V(!m, RS::SurfaceData());
+ RS::SurfaceData s = m->surfaces[p_surface];
+ return s;
+ }
+
+ virtual int mesh_get_surface_count(RID p_mesh) const override {
+ DummyMesh *m = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND_V(!m, 0);
+ print_line(m->surfaces.size());
+ return m->surfaces.size();
+ }
virtual void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) override {}
virtual AABB mesh_get_custom_aabb(RID p_mesh) const override { return AABB(); }
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index 6da48fde9c..aa9772a483 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -605,9 +605,13 @@ void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from,
}
if (p_antialiased) {
- float border_size = 2.0;
- if (p_width < border_size) {
- border_size = p_width;
+ // Use the same antialiasing feather size as StyleBoxFlat's default
+ // (but doubled, as it's specified for both sides here).
+ // This value is empirically determined to provide good antialiasing quality
+ // while not making lines appear too soft.
+ float border_size = 1.25f;
+ if (p_width < 1.0f) {
+ border_size *= p_width;
}
Vector2 dir2 = diff.normalized();
@@ -774,9 +778,13 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point
Color *colors_ptr = colors.ptrw();
if (p_antialiased) {
- float border_size = 2.0;
- if (p_width < border_size) {
- border_size = p_width;
+ // Use the same antialiasing feather size as StyleBoxFlat's default
+ // (but doubled, as it's specified for both sides here).
+ // This value is empirically determined to provide good antialiasing quality
+ // while not making lines appear too soft.
+ float border_size = 1.25f;
+ if (p_width < 1.0f) {
+ border_size *= p_width;
}
Color color2 = Color(1, 1, 1, 0);
@@ -1175,6 +1183,38 @@ void RendererCanvasCull::canvas_item_add_msdf_texture_rect_region(RID p_item, co
rect->px_range = p_px_range;
}
+void RendererCanvasCull::canvas_item_add_lcd_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate) {
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
+ ERR_FAIL_COND(!canvas_item);
+
+ Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>();
+ ERR_FAIL_COND(!rect);
+ rect->modulate = p_modulate;
+ rect->rect = p_rect;
+
+ rect->texture = p_texture;
+
+ rect->source = p_src_rect;
+ rect->flags = RendererCanvasRender::CANVAS_RECT_REGION | RendererCanvasRender::CANVAS_RECT_LCD;
+
+ if (p_rect.size.x < 0) {
+ rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_H;
+ rect->rect.size.x = -rect->rect.size.x;
+ }
+ if (p_src_rect.size.x < 0) {
+ rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_H;
+ rect->source.size.x = -rect->source.size.x;
+ }
+ if (p_rect.size.y < 0) {
+ rect->flags |= RendererCanvasRender::CANVAS_RECT_FLIP_V;
+ rect->rect.size.y = -rect->rect.size.y;
+ }
+ if (p_src_rect.size.y < 0) {
+ rect->flags ^= RendererCanvasRender::CANVAS_RECT_FLIP_V;
+ rect->source.size.y = -rect->source.size.y;
+ }
+}
+
void RendererCanvasCull::canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) {
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h
index e8c54310c9..0d6a4006f8 100644
--- a/servers/rendering/renderer_canvas_cull.h
+++ b/servers/rendering/renderer_canvas_cull.h
@@ -225,6 +225,7 @@ public:
void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false);
void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = false);
void canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, float p_px_range = 1.0);
+ void canvas_item_add_lcd_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1));
void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, RS::NinePatchAxisMode p_x_axis_mode = RS::NINE_PATCH_STRETCH, RS::NinePatchAxisMode p_y_axis_mode = RS::NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1));
void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0);
void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID());
diff --git a/servers/rendering/renderer_canvas_render.h b/servers/rendering/renderer_canvas_render.h
index 11a7d34291..6791ed9626 100644
--- a/servers/rendering/renderer_canvas_render.h
+++ b/servers/rendering/renderer_canvas_render.h
@@ -46,6 +46,7 @@ public:
CANVAS_RECT_CLIP_UV = 32,
CANVAS_RECT_IS_GROUP = 64,
CANVAS_RECT_MSDF = 128,
+ CANVAS_RECT_LCD = 256,
};
struct Light {
@@ -193,7 +194,7 @@ public:
Rect2 rect;
Color modulate;
Rect2 source;
- uint8_t flags;
+ uint16_t flags;
float outline;
float px_range;
diff --git a/servers/rendering/renderer_geometry_instance.cpp b/servers/rendering/renderer_geometry_instance.cpp
index 3a9bab022c..675659f4c8 100644
--- a/servers/rendering/renderer_geometry_instance.cpp
+++ b/servers/rendering/renderer_geometry_instance.cpp
@@ -117,8 +117,8 @@ void RenderGeometryInstanceBase::set_use_dynamic_gi(bool p_enable) {
_mark_dirty();
}
-void RenderGeometryInstanceBase::set_instance_shader_parameters_offset(int32_t p_offset) {
- shader_parameters_offset = p_offset;
+void RenderGeometryInstanceBase::set_instance_shader_uniforms_offset(int32_t p_offset) {
+ shader_uniforms_offset = p_offset;
_mark_dirty();
}
diff --git a/servers/rendering/renderer_geometry_instance.h b/servers/rendering/renderer_geometry_instance.h
index 279566d5c9..fecb9878c2 100644
--- a/servers/rendering/renderer_geometry_instance.h
+++ b/servers/rendering/renderer_geometry_instance.h
@@ -59,7 +59,7 @@ public:
virtual void set_use_dynamic_gi(bool p_enable) = 0;
virtual void set_use_lightmap(RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) = 0;
virtual void set_lightmap_capture(const Color *p_sh9) = 0;
- virtual void set_instance_shader_parameters_offset(int32_t p_offset) = 0;
+ virtual void set_instance_shader_uniforms_offset(int32_t p_offset) = 0;
virtual void set_cast_double_sided_shadows(bool p_enable) = 0;
virtual Transform3D get_transform() = 0;
@@ -104,7 +104,7 @@ public:
float parent_fade_alpha = 1.0;
float force_alpha = 1.0;
- int32_t shader_parameters_offset = -1;
+ int32_t shader_uniforms_offset = -1;
struct Data {
//data used less often goes into regular heap
@@ -140,7 +140,7 @@ public:
virtual void set_transparency(float p_transparency) override;
virtual void set_use_baked_light(bool p_enable) override;
virtual void set_use_dynamic_gi(bool p_enable) override;
- virtual void set_instance_shader_parameters_offset(int32_t p_offset) override;
+ virtual void set_instance_shader_uniforms_offset(int32_t p_offset) override;
virtual void set_cast_double_sided_shadows(bool p_enable) override;
virtual Transform3D get_transform() override;
diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.h b/servers/rendering/renderer_rd/cluster_builder_rd.h
index 17ca1986c6..ef17ceb98c 100644
--- a/servers/rendering/renderer_rd/cluster_builder_rd.h
+++ b/servers/rendering/renderer_rd/cluster_builder_rd.h
@@ -269,7 +269,7 @@ public:
//spot
radius *= shared->cone_overfit; // overfit icosphere
- real_t len = Math::tan(Math::deg2rad(p_spot_aperture)) * radius;
+ real_t len = Math::tan(Math::deg_to_rad(p_spot_aperture)) * radius;
//approximate, probably better to use a cone support function
float max_d = -1e20;
float min_d = 1e20;
@@ -293,7 +293,7 @@ public:
float dist = base_plane.distance_to(Vector3());
if (dist >= 0 && dist < radius) {
//inside, check angle
- float angle = Math::rad2deg(Math::acos((-xform.origin.normalized()).dot(-xform.basis.get_column(Vector3::AXIS_Z))));
+ float angle = Math::rad_to_deg(Math::acos((-xform.origin.normalized()).dot(-xform.basis.get_column(Vector3::AXIS_Z))));
e.touches_near = angle < p_spot_aperture * 1.05; //overfit aperture a little due to cone overfit
} else {
e.touches_near = false;
diff --git a/servers/rendering/renderer_rd/effects/ss_effects.cpp b/servers/rendering/renderer_rd/effects/ss_effects.cpp
index 0f896a8aa7..874409b885 100644
--- a/servers/rendering/renderer_rd/effects/ss_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/ss_effects.cpp
@@ -1604,7 +1604,7 @@ void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const R
ScreenSpaceReflectionFilterPushConstant push_constant;
push_constant.view_index = v;
push_constant.orthogonal = p_projections[v].is_orthogonal();
- push_constant.edge_tolerance = Math::sin(Math::deg2rad(15.0));
+ push_constant.edge_tolerance = Math::sin(Math::deg_to_rad(15.0));
push_constant.proj_info[0] = -2.0f / (p_screen_size.width * p_projections[v].matrix[0][0]);
push_constant.proj_info[1] = -2.0f / (p_screen_size.height * p_projections[v].matrix[1][1]);
push_constant.proj_info[2] = (1.0f - p_projections[v].matrix[0][2]) / p_projections[v].matrix[0][0];
diff --git a/servers/rendering/renderer_rd/effects/vrs.cpp b/servers/rendering/renderer_rd/effects/vrs.cpp
index fa0b99fef9..68cfd43d90 100644
--- a/servers/rendering/renderer_rd/effects/vrs.cpp
+++ b/servers/rendering/renderer_rd/effects/vrs.cpp
@@ -146,10 +146,11 @@ void VRS::update_vrs_texture(RID p_vrs_fb, RID p_render_target) {
if (vrs_mode == RS::VIEWPORT_VRS_TEXTURE) {
RID vrs_texture = texture_storage->render_target_get_vrs_texture(p_render_target);
if (vrs_texture.is_valid()) {
- Texture *texture = texture_storage->get_texture(vrs_texture);
- if (texture) {
+ RID rd_texture = texture_storage->texture_get_rd_texture(vrs_texture);
+ int layers = texture_storage->texture_get_layers(vrs_texture);
+ if (rd_texture.is_valid()) {
// Copy into our density buffer
- copy_vrs(texture->rd_texture, p_vrs_fb, texture->layers > 1);
+ copy_vrs(rd_texture, p_vrs_fb, layers > 1);
}
}
} else if (vrs_mode == RS::VIEWPORT_VRS_XR) {
@@ -157,10 +158,12 @@ void VRS::update_vrs_texture(RID p_vrs_fb, RID p_render_target) {
if (interface.is_valid()) {
RID vrs_texture = interface->get_vrs_texture();
if (vrs_texture.is_valid()) {
- Texture *texture = texture_storage->get_texture(vrs_texture);
- if (texture) {
+ RID rd_texture = texture_storage->texture_get_rd_texture(vrs_texture);
+ int layers = texture_storage->texture_get_layers(vrs_texture);
+
+ if (rd_texture.is_valid()) {
// Copy into our density buffer
- copy_vrs(texture->rd_texture, p_vrs_fb, texture->layers > 1);
+ copy_vrs(rd_texture, p_vrs_fb, layers > 1);
}
}
}
diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp
index fba04c0db4..257b67cf04 100644
--- a/servers/rendering/renderer_rd/environment/fog.cpp
+++ b/servers/rendering/renderer_rd/environment/fog.cpp
@@ -145,23 +145,23 @@ Fog::FogMaterialData::~FogMaterialData() {
free_parameters_uniform_set(uniform_set);
}
-RendererRD::ShaderData *Fog::_create_fog_shader_func() {
+RendererRD::MaterialStorage::ShaderData *Fog::_create_fog_shader_func() {
FogShaderData *shader_data = memnew(FogShaderData);
return shader_data;
}
-RendererRD::ShaderData *Fog::_create_fog_shader_funcs() {
+RendererRD::MaterialStorage::ShaderData *Fog::_create_fog_shader_funcs() {
return Fog::get_singleton()->_create_fog_shader_func();
};
-RendererRD::MaterialData *Fog::_create_fog_material_func(FogShaderData *p_shader) {
+RendererRD::MaterialStorage::MaterialData *Fog::_create_fog_material_func(FogShaderData *p_shader) {
FogMaterialData *material_data = memnew(FogMaterialData);
material_data->shader_data = p_shader;
//update will happen later anyway so do nothing.
return material_data;
}
-RendererRD::MaterialData *Fog::_create_fog_material_funcs(RendererRD::ShaderData *p_shader) {
+RendererRD::MaterialStorage::MaterialData *Fog::_create_fog_material_funcs(RendererRD::MaterialStorage::ShaderData *p_shader) {
return Fog::get_singleton()->_create_fog_material_func(static_cast<FogShaderData *>(p_shader));
};
@@ -190,8 +190,8 @@ void Fog::init_fog_shader(uint32_t p_max_directional_lights, int p_roughness_lay
volumetric_fog_modes.push_back("");
volumetric_fog.shader.initialize(volumetric_fog_modes);
- material_storage->shader_set_data_request_function(RendererRD::SHADER_TYPE_FOG, _create_fog_shader_funcs);
- material_storage->material_set_data_request_function(RendererRD::SHADER_TYPE_FOG, _create_fog_material_funcs);
+ material_storage->shader_set_data_request_function(RendererRD::MaterialStorage::SHADER_TYPE_FOG, _create_fog_shader_funcs);
+ material_storage->material_set_data_request_function(RendererRD::MaterialStorage::SHADER_TYPE_FOG, _create_fog_material_funcs);
volumetric_fog.volume_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(VolumetricFogShader::VolumeUBO));
}
@@ -246,7 +246,7 @@ ALBEDO = vec3(1.0);
material_storage->material_initialize(volumetric_fog.default_material);
material_storage->material_set_shader(volumetric_fog.default_material, volumetric_fog.default_shader);
- FogMaterialData *md = static_cast<FogMaterialData *>(material_storage->material_get_data(volumetric_fog.default_material, RendererRD::SHADER_TYPE_FOG));
+ FogMaterialData *md = static_cast<FogMaterialData *>(material_storage->material_get_data(volumetric_fog.default_material, RendererRD::MaterialStorage::SHADER_TYPE_FOG));
volumetric_fog.default_shader_rd = volumetric_fog.shader.version_get_shader(md->shader_data->version, 0);
Vector<RD::Uniform> uniforms;
@@ -378,7 +378,7 @@ void Fog::FogShaderData::set_default_texture_param(const StringName &p_name, RID
}
}
-void Fog::FogShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+void Fog::FogShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
RBMap<int, StringName> order;
for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
@@ -500,7 +500,7 @@ Fog::VolumetricFog::VolumetricFog(const Vector3i &fog_size, RID p_sky_shader) {
fog_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(fog_map, "Fog map");
-#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
Vector<uint8_t> dm;
dm.resize(fog_size.x * fog_size.y * fog_size.z * 4);
dm.fill(0);
@@ -643,7 +643,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
{
RD::Uniform u;
-#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
#else
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
@@ -663,7 +663,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
{
RD::Uniform u;
-#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
#else
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
@@ -675,7 +675,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
{
RD::Uniform u;
-#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
#else
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
@@ -701,7 +701,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
FogMaterialData *material = nullptr;
if (fog_material.is_valid()) {
- material = static_cast<FogMaterialData *>(material_storage->material_get_data(fog_material, RendererRD::SHADER_TYPE_FOG));
+ material = static_cast<FogMaterialData *>(material_storage->material_get_data(fog_material, RendererRD::MaterialStorage::SHADER_TYPE_FOG));
if (!material || !material->shader_data->valid) {
material = nullptr;
}
@@ -709,7 +709,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
if (!material) {
fog_material = volumetric_fog.default_material;
- material = static_cast<FogMaterialData *>(material_storage->material_get_data(fog_material, RendererRD::SHADER_TYPE_FOG));
+ material = static_cast<FogMaterialData *>(material_storage->material_get_data(fog_material, RendererRD::MaterialStorage::SHADER_TYPE_FOG));
}
ERR_FAIL_COND(!material);
@@ -805,7 +805,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 1;
if (p_settings.shadow_atlas_depth.is_null()) {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_BLACK));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK));
} else {
u.append_id(p_settings.shadow_atlas_depth);
}
@@ -821,7 +821,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
if (p_settings.directional_shadow_depth.is_valid()) {
u.append_id(p_settings.directional_shadow_depth);
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_BLACK));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK));
}
uniforms.push_back(u);
copy_uniforms.push_back(u);
@@ -949,7 +949,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
}
{
RD::Uniform u;
-#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
#else
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
@@ -960,7 +960,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
}
{
RD::Uniform u;
-#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
#else
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
@@ -972,7 +972,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
{
RD::Uniform u;
-#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+#if defined(MACOS_ENABLED) || defined(IOS_ENABLED)
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
#else
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
@@ -986,7 +986,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 19;
- RID radiance_texture = texture_storage->texture_rd_get_default(p_settings.is_using_radiance_cubemap_array ? RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
+ RID radiance_texture = texture_storage->texture_rd_get_default(p_settings.is_using_radiance_cubemap_array ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
RID sky_texture = RendererSceneRenderRD::get_singleton()->environment_get_sky(p_settings.env).is_valid() ? p_settings.sky->sky_get_radiance_texture_rd(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_settings.env)) : RID();
u.append_id(sky_texture.is_valid() ? sky_texture : radiance_texture);
uniforms.push_back(u);
diff --git a/servers/rendering/renderer_rd/environment/fog.h b/servers/rendering/renderer_rd/environment/fog.h
index e777a1d383..171f9f3b88 100644
--- a/servers/rendering/renderer_rd/environment/fog.h
+++ b/servers/rendering/renderer_rd/environment/fog.h
@@ -180,7 +180,7 @@ private:
Vector3i _point_get_position_in_froxel_volume(const Vector3 &p_point, float fog_end, const Vector2 &fog_near_size, const Vector2 &fog_far_size, float volumetric_fog_detail_spread, const Vector3 &fog_size, const Transform3D &p_cam_transform);
- struct FogShaderData : public RendererRD::ShaderData {
+ struct FogShaderData : public RendererRD::MaterialStorage::ShaderData {
bool valid = false;
RID version;
@@ -200,7 +200,7 @@ private:
virtual void set_path_hint(const String &p_hint);
virtual void set_code(const String &p_Code);
virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
- virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
virtual bool is_param_texture(const StringName &p_param) const;
virtual bool is_animated() const;
@@ -212,7 +212,7 @@ private:
virtual ~FogShaderData();
};
- struct FogMaterialData : public RendererRD::MaterialData {
+ struct FogMaterialData : public RendererRD::MaterialStorage::MaterialData {
FogShaderData *shader_data = nullptr;
RID uniform_set;
bool uniform_set_updated;
@@ -223,11 +223,11 @@ private:
virtual ~FogMaterialData();
};
- RendererRD::ShaderData *_create_fog_shader_func();
- static RendererRD::ShaderData *_create_fog_shader_funcs();
+ RendererRD::MaterialStorage::ShaderData *_create_fog_shader_func();
+ static RendererRD::MaterialStorage::ShaderData *_create_fog_shader_funcs();
- RendererRD::MaterialData *_create_fog_material_func(FogShaderData *p_shader);
- static RendererRD::MaterialData *_create_fog_material_funcs(RendererRD::ShaderData *p_shader);
+ RendererRD::MaterialStorage::MaterialData *_create_fog_material_func(FogShaderData *p_shader);
+ static RendererRD::MaterialStorage::MaterialData *_create_fog_material_funcs(RendererRD::MaterialStorage::ShaderData *p_shader);
public:
static Fog *get_singleton() { return singleton; }
diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp
index 7b4f61bd17..66e984174c 100644
--- a/servers/rendering/renderer_rd/environment/gi.cpp
+++ b/servers/rendering/renderer_rd/environment/gi.cpp
@@ -734,7 +734,7 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re
if (j < cascades.size()) {
u.append_id(cascades[j].sdf_tex);
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE));
}
}
uniforms.push_back(u);
@@ -978,7 +978,7 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re
if (j < cascades.size()) {
u.append_id(cascades[j].sdf_tex);
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE));
}
}
uniforms.push_back(u);
@@ -991,7 +991,7 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re
if (j < cascades.size()) {
u.append_id(cascades[j].light_tex);
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE));
}
}
uniforms.push_back(u);
@@ -1004,7 +1004,7 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re
if (j < cascades.size()) {
u.append_id(cascades[j].light_aniso_0_tex);
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE));
}
}
uniforms.push_back(u);
@@ -1017,7 +1017,7 @@ void GI::SDFGI::create(RID p_env, const Vector3 &p_world_position, uint32_t p_re
if (j < cascades.size()) {
u.append_id(cascades[j].light_aniso_1_tex);
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE));
}
}
uniforms.push_back(u);
@@ -1140,6 +1140,7 @@ void GI::SDFGI::erase() {
RD::get_singleton()->free(lightprobe_data);
RD::get_singleton()->free(lightprobe_history_scroll);
+ RD::get_singleton()->free(lightprobe_average_scroll);
RD::get_singleton()->free(occlusion_data);
RD::get_singleton()->free(ambient_texture);
@@ -1498,7 +1499,7 @@ void GI::SDFGI::debug_draw(uint32_t p_view_count, const Projection *p_projection
if (i < cascades.size()) {
u.append_id(cascades[i].sdf_tex);
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE));
}
}
uniforms.push_back(u);
@@ -1511,7 +1512,7 @@ void GI::SDFGI::debug_draw(uint32_t p_view_count, const Projection *p_projection
if (i < cascades.size()) {
u.append_id(cascades[i].light_tex);
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE));
}
}
uniforms.push_back(u);
@@ -1524,7 +1525,7 @@ void GI::SDFGI::debug_draw(uint32_t p_view_count, const Projection *p_projection
if (i < cascades.size()) {
u.append_id(cascades[i].light_aniso_0_tex);
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE));
}
}
uniforms.push_back(u);
@@ -1537,7 +1538,7 @@ void GI::SDFGI::debug_draw(uint32_t p_view_count, const Projection *p_projection
if (i < cascades.size()) {
u.append_id(cascades[i].light_aniso_1_tex);
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE));
}
}
uniforms.push_back(u);
@@ -1591,34 +1592,24 @@ void GI::SDFGI::debug_draw(uint32_t p_view_count, const Projection *p_projection
push_constant.max_cascades = cascades.size();
push_constant.screen_size[0] = p_width;
push_constant.screen_size[1] = p_height;
- push_constant.probe_axis_size = probe_axis_count;
- push_constant.use_occlusion = uses_occlusion;
push_constant.y_mult = y_mult;
push_constant.z_near = -p_projections[v].get_z_near();
- push_constant.cam_transform[0] = p_transform.basis.rows[0][0];
- push_constant.cam_transform[1] = p_transform.basis.rows[1][0];
- push_constant.cam_transform[2] = p_transform.basis.rows[2][0];
- push_constant.cam_transform[3] = 0;
- push_constant.cam_transform[4] = p_transform.basis.rows[0][1];
- push_constant.cam_transform[5] = p_transform.basis.rows[1][1];
- push_constant.cam_transform[6] = p_transform.basis.rows[2][1];
- push_constant.cam_transform[7] = 0;
- push_constant.cam_transform[8] = p_transform.basis.rows[0][2];
- push_constant.cam_transform[9] = p_transform.basis.rows[1][2];
- push_constant.cam_transform[10] = p_transform.basis.rows[2][2];
- push_constant.cam_transform[11] = 0;
- push_constant.cam_transform[12] = p_transform.origin.x;
- push_constant.cam_transform[13] = p_transform.origin.y;
- push_constant.cam_transform[14] = p_transform.origin.z;
- push_constant.cam_transform[15] = 1;
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ push_constant.cam_basis[i][j] = p_transform.basis.rows[j][i];
+ }
+ }
+ push_constant.cam_origin[0] = p_transform.origin[0];
+ push_constant.cam_origin[1] = p_transform.origin[1];
+ push_constant.cam_origin[2] = p_transform.origin[2];
// need to properly unproject for asymmetric projection matrices in stereo..
Projection inv_projection = p_projections[v].inverse();
for (int i = 0; i < 4; i++) {
- for (int j = 0; j < 4; j++) {
- push_constant.inv_projection[i * 4 + j] = inv_projection.matrix[i][j];
+ for (int j = 0; j < 3; j++) {
+ push_constant.inv_projection[j][i] = inv_projection.matrix[i][j];
}
}
@@ -1933,7 +1924,7 @@ void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_r
lights[idx].has_shadow = RSG::light_storage->light_has_shadow(li->light);
lights[idx].attenuation = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION);
lights[idx].radius = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE);
- lights[idx].cos_spot_angle = Math::cos(Math::deg2rad(RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)));
+ lights[idx].cos_spot_angle = Math::cos(Math::deg_to_rad(RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)));
lights[idx].inv_spot_attenuation = 1.0f / RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
idx++;
@@ -2371,7 +2362,7 @@ void GI::SDFGI::render_static_lights(RID p_render_buffers, uint32_t p_cascade_co
lights[idx].has_shadow = RSG::light_storage->light_has_shadow(li->light);
lights[idx].attenuation = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION);
lights[idx].radius = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE);
- lights[idx].cos_spot_angle = Math::cos(Math::deg2rad(RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)));
+ lights[idx].cos_spot_angle = Math::cos(Math::deg_to_rad(RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)));
lights[idx].inv_spot_attenuation = 1.0f / RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
idx++;
@@ -2437,18 +2428,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
if (last_probe_data_version != data_version) {
//need to re-create everything
- if (texture.is_valid()) {
- RD::get_singleton()->free(texture);
- RD::get_singleton()->free(write_buffer);
- mipmaps.clear();
- }
-
- for (int i = 0; i < dynamic_maps.size(); i++) {
- RD::get_singleton()->free(dynamic_maps[i].texture);
- RD::get_singleton()->free(dynamic_maps[i].depth);
- }
-
- dynamic_maps.clear();
+ free_resources();
Vector3i octree_size = gi->voxel_gi_get_octree_size(probe);
@@ -2820,7 +2800,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
l.color[1] = color.g;
l.color[2] = color.b;
- l.cos_spot_angle = Math::cos(Math::deg2rad(RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE)));
+ l.cos_spot_angle = Math::cos(Math::deg_to_rad(RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE)));
l.inv_spot_attenuation = 1.0f / RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
Transform3D xform = p_scene_render->light_instance_get_base_transform(light_instance);
@@ -3140,6 +3120,37 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
last_probe_version = gi->voxel_gi_get_version(probe);
}
+void GI::VoxelGIInstance::free_resources() {
+ if (texture.is_valid()) {
+ RD::get_singleton()->free(texture);
+ RD::get_singleton()->free(write_buffer);
+
+ texture = RID();
+ write_buffer = RID();
+ mipmaps.clear();
+ }
+
+ for (int i = 0; i < dynamic_maps.size(); i++) {
+ RD::get_singleton()->free(dynamic_maps[i].texture);
+ RD::get_singleton()->free(dynamic_maps[i].depth);
+
+ // these only exist on the first level...
+ if (dynamic_maps[i].fb_depth.is_valid()) {
+ RD::get_singleton()->free(dynamic_maps[i].fb_depth);
+ }
+ if (dynamic_maps[i].albedo.is_valid()) {
+ RD::get_singleton()->free(dynamic_maps[i].albedo);
+ }
+ if (dynamic_maps[i].normal.is_valid()) {
+ RD::get_singleton()->free(dynamic_maps[i].normal);
+ }
+ if (dynamic_maps[i].orm.is_valid()) {
+ RD::get_singleton()->free(dynamic_maps[i].orm);
+ }
+ }
+ dynamic_maps.clear();
+}
+
void GI::VoxelGIInstance::debug(RD::DrawListID p_draw_list, RID p_framebuffer, const Projection &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) {
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
@@ -3353,9 +3364,9 @@ void GI::init(SkyRD *p_sky) {
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 0;
if (p_sky->sky_use_cubemap_array) {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_WHITE));
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_WHITE));
}
uniforms.push_back(u);
}
@@ -3550,7 +3561,7 @@ void GI::setup_voxel_gi_instances(RID p_render_buffers, const Transform3D &p_tra
}
if (texture == RID()) {
- texture = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
}
if (texture != rb->rbgi.voxel_gi_textures[i]) {
@@ -3761,7 +3772,7 @@ void GI::process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices,
if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
u.append_id(rb->sdfgi->cascades[j].sdf_tex);
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE));
}
}
uniforms.push_back(u);
@@ -3774,7 +3785,7 @@ void GI::process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices,
if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
u.append_id(rb->sdfgi->cascades[j].light_tex);
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE));
}
}
uniforms.push_back(u);
@@ -3787,7 +3798,7 @@ void GI::process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices,
if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
u.append_id(rb->sdfgi->cascades[j].light_aniso_0_tex);
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE));
}
}
uniforms.push_back(u);
@@ -3800,7 +3811,7 @@ void GI::process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices,
if (rb->sdfgi && j < rb->sdfgi->cascades.size()) {
u.append_id(rb->sdfgi->cascades[j].light_aniso_1_tex);
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE));
}
}
uniforms.push_back(u);
@@ -3812,7 +3823,7 @@ void GI::process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices,
if (rb->sdfgi) {
u.append_id(rb->sdfgi->occlusion_texture);
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE));
}
uniforms.push_back(u);
}
@@ -3854,7 +3865,7 @@ void GI::process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices,
if (rb->sdfgi) {
u.append_id(rb->sdfgi->lightprobe_texture);
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE));
}
uniforms.push_back(u);
}
@@ -3876,7 +3887,7 @@ void GI::process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices,
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 14;
- RID buffer = p_voxel_gi_buffer.is_valid() ? p_voxel_gi_buffer : texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_BLACK);
+ RID buffer = p_voxel_gi_buffer.is_valid() ? p_voxel_gi_buffer : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
u.append_id(buffer);
uniforms.push_back(u);
}
@@ -3914,7 +3925,7 @@ void GI::process_gi(RID p_render_buffers, const RID *p_normal_roughness_slices,
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
u.binding = 19;
- RID buffer = p_vrs_slices[v].is_valid() ? p_vrs_slices[v] : texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_VRS);
+ RID buffer = p_vrs_slices[v].is_valid() ? p_vrs_slices[v] : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_VRS);
u.append_id(buffer);
uniforms.push_back(u);
}
@@ -3946,6 +3957,12 @@ RID GI::voxel_gi_instance_create(RID p_base) {
return rid;
}
+void GI::voxel_gi_instance_free(RID p_rid) {
+ GI::VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_rid);
+ voxel_gi->free_resources();
+ voxel_gi_instance_owner.free(p_rid);
+}
+
void GI::voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) {
VoxelGIInstance *voxel_gi = get_probe_instance(p_probe);
ERR_FAIL_COND(!voxel_gi);
diff --git a/servers/rendering/renderer_rd/environment/gi.h b/servers/rendering/renderer_rd/environment/gi.h
index d4d4182950..8860445c3b 100644
--- a/servers/rendering/renderer_rd/environment/gi.h
+++ b/servers/rendering/renderer_rd/environment/gi.h
@@ -232,16 +232,13 @@ private:
uint32_t max_cascades;
int32_t screen_size[2];
- uint32_t use_occlusion;
float y_mult;
- uint32_t probe_axis_size;
float z_near;
- float reserved1;
- float reserved2;
- float cam_transform[16];
- float inv_projection[16];
+ float inv_projection[3][4];
+ float cam_basis[3][3];
+ float cam_origin[3];
};
SdfgiDebugShaderRD debug;
@@ -472,6 +469,7 @@ public:
void update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render);
void debug(RD::DrawListID p_draw_list, RID p_framebuffer, const Projection &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);
+ void free_resources();
};
mutable RID_Owner<VoxelGIInstance> voxel_gi_instance_owner;
@@ -486,6 +484,12 @@ public:
return voxel_gi->texture;
};
+ bool voxel_gi_instance_owns(RID p_rid) const {
+ return voxel_gi_instance_owner.owns(p_rid);
+ }
+
+ void voxel_gi_instance_free(RID p_rid);
+
RS::VoxelGIQuality voxel_gi_quality = RS::VOXEL_GI_QUALITY_LOW;
/* SDFGI */
diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp
index 228d2673f2..1d6b158d65 100644
--- a/servers/rendering/renderer_rd/environment/sky.cpp
+++ b/servers/rendering/renderer_rd/environment/sky.cpp
@@ -114,12 +114,16 @@ void SkyRD::SkyShaderData::set_code(const String &p_code) {
for (int i = 0; i < gen_code.defines.size(); i++) {
print_line(gen_code.defines[i]);
}
+
+ HashMap<String, String>::Iterator el = gen_code.code.begin();
+ while (el) {
+ print_line("\n**code " + el->key + ":\n" + el->value);
+ ++el;
+ }
+
print_line("\n**uniforms:\n" + gen_code.uniforms);
- // print_line("\n**vertex_globals:\n" + gen_code.vertex_global);
- // print_line("\n**vertex_code:\n" + gen_code.vertex);
- print_line("\n**fragment_globals:\n" + gen_code.fragment_global);
- print_line("\n**fragment_code:\n" + gen_code.fragment);
- print_line("\n**light_code:\n" + gen_code.light);
+ print_line("\n**vertex_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX]);
+ print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
#endif
scene_singleton->sky.sky_shader.shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines);
@@ -164,7 +168,7 @@ void SkyRD::SkyShaderData::set_default_texture_param(const StringName &p_name, R
}
}
-void SkyRD::SkyShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+void SkyRD::SkyShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
HashMap<int, StringName> order;
for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
@@ -655,7 +659,7 @@ RID SkyRD::Sky::get_textures(SkyTextureSetVersion p_version, RID p_default_shade
if (radiance.is_valid() && p_version <= SKY_TEXTURE_SET_QUARTER_RES) {
u.append_id(radiance);
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
}
uniforms.push_back(u);
}
@@ -671,9 +675,9 @@ RID SkyRD::Sky::get_textures(SkyTextureSetVersion p_version, RID p_default_shade
}
} else {
if (p_version < SKY_TEXTURE_SET_CUBEMAP) {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_WHITE));
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
}
}
uniforms.push_back(u);
@@ -690,9 +694,9 @@ RID SkyRD::Sky::get_textures(SkyTextureSetVersion p_version, RID p_default_shade
}
} else {
if (p_version < SKY_TEXTURE_SET_CUBEMAP) {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_WHITE));
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
}
}
uniforms.push_back(u);
@@ -789,24 +793,24 @@ Ref<Image> SkyRD::Sky::bake_panorama(float p_energy, int p_roughness_layers, con
////////////////////////////////////////////////////////////////////////////////
// SkyRD
-RendererRD::ShaderData *SkyRD::_create_sky_shader_func() {
+RendererRD::MaterialStorage::ShaderData *SkyRD::_create_sky_shader_func() {
SkyShaderData *shader_data = memnew(SkyShaderData);
return shader_data;
}
-RendererRD::ShaderData *SkyRD::_create_sky_shader_funcs() {
+RendererRD::MaterialStorage::ShaderData *SkyRD::_create_sky_shader_funcs() {
// !BAS! Why isn't _create_sky_shader_func not just static too?
return static_cast<RendererSceneRenderRD *>(RendererSceneRenderRD::singleton)->sky._create_sky_shader_func();
};
-RendererRD::MaterialData *SkyRD::_create_sky_material_func(SkyShaderData *p_shader) {
+RendererRD::MaterialStorage::MaterialData *SkyRD::_create_sky_material_func(SkyShaderData *p_shader) {
SkyMaterialData *material_data = memnew(SkyMaterialData);
material_data->shader_data = p_shader;
//update will happen later anyway so do nothing.
return material_data;
}
-RendererRD::MaterialData *SkyRD::_create_sky_material_funcs(RendererRD::ShaderData *p_shader) {
+RendererRD::MaterialStorage::MaterialData *SkyRD::_create_sky_material_funcs(RendererRD::MaterialStorage::ShaderData *p_shader) {
// !BAS! same here, we could just make _create_sky_material_func static?
return static_cast<RendererSceneRenderRD *>(RendererSceneRenderRD::singleton)->sky._create_sky_material_func(static_cast<SkyShaderData *>(p_shader));
};
@@ -855,8 +859,8 @@ void SkyRD::init() {
}
// register our shader funds
- material_storage->shader_set_data_request_function(RendererRD::SHADER_TYPE_SKY, _create_sky_shader_funcs);
- material_storage->material_set_data_request_function(RendererRD::SHADER_TYPE_SKY, _create_sky_material_funcs);
+ material_storage->shader_set_data_request_function(RendererRD::MaterialStorage::SHADER_TYPE_SKY, _create_sky_shader_funcs);
+ material_storage->material_set_data_request_function(RendererRD::MaterialStorage::SHADER_TYPE_SKY, _create_sky_material_funcs);
{
ShaderCompiler::DefaultIdentifierActions actions;
@@ -937,7 +941,7 @@ void sky() {
material_storage->material_set_shader(sky_shader.default_material, sky_shader.default_shader);
- SkyMaterialData *md = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_shader.default_material, RendererRD::SHADER_TYPE_SKY));
+ SkyMaterialData *md = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_shader.default_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
sky_shader.default_shader_rd = sky_shader.shader.version_get_shader(md->shader_data->version, SKY_VERSION_BACKGROUND);
sky_scene_state.uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SkySceneState::UBO));
@@ -999,7 +1003,7 @@ void sky() {
RD::Uniform u;
u.binding = 0;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID vfog = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ RID vfog = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
u.append_id(vfog);
uniforms.push_back(u);
}
@@ -1033,21 +1037,21 @@ void sky() {
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 0;
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 1;
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_WHITE));
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 2;
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_WHITE));
uniforms.push_back(u);
}
@@ -1080,7 +1084,7 @@ SkyRD::~SkyRD() {
// cleanup anything created in init...
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
- SkyMaterialData *md = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_shader.default_material, RendererRD::SHADER_TYPE_SKY));
+ SkyMaterialData *md = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_shader.default_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
sky_shader.shader.version_free(md->shader_data->version);
RD::get_singleton()->free(sky_scene_state.directional_light_buffer);
RD::get_singleton()->free(sky_scene_state.uniform_buffer);
@@ -1122,7 +1126,7 @@ void SkyRD::setup(RID p_env, RID p_render_buffers, const PagedArray<RID> &p_ligh
sky_material = sky_get_material(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));
if (sky_material.is_valid()) {
- material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY));
+ material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
if (!material || !material->shader_data->valid) {
material = nullptr;
}
@@ -1130,7 +1134,7 @@ void SkyRD::setup(RID p_env, RID p_render_buffers, const PagedArray<RID> &p_ligh
if (!material) {
sky_material = sky_shader.default_material;
- material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY));
+ material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
}
ERR_FAIL_COND(!material);
@@ -1228,7 +1232,7 @@ void SkyRD::setup(RID p_env, RID p_render_buffers, const PagedArray<RID> &p_ligh
// I know tan(0) is 0, but let's not risk it with numerical precision.
// technically this will keep expanding until reaching the sun, but all we care
// is expand until we reach the radius of the near plane (there can't be more occluders than that)
- angular_diameter = Math::tan(Math::deg2rad(angular_diameter));
+ angular_diameter = Math::tan(Math::deg_to_rad(angular_diameter));
} else {
angular_diameter = 0.0;
}
@@ -1330,7 +1334,7 @@ void SkyRD::update(RID p_env, const Projection &p_projection, const Transform3D
SkyMaterialData *material = nullptr;
if (sky_material.is_valid()) {
- material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY));
+ material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
if (!material || !material->shader_data->valid) {
material = nullptr;
}
@@ -1338,7 +1342,7 @@ void SkyRD::update(RID p_env, const Projection &p_projection, const Transform3D
if (!material) {
sky_material = sky_shader.default_material;
- material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY));
+ material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
}
ERR_FAIL_COND(!material);
@@ -1506,7 +1510,7 @@ void SkyRD::draw(RID p_env, bool p_can_continue_color, bool p_can_continue_depth
sky_material = sky_get_material(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));
if (sky_material.is_valid()) {
- material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY));
+ material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
if (!material || !material->shader_data->valid) {
material = nullptr;
}
@@ -1514,13 +1518,13 @@ void SkyRD::draw(RID p_env, bool p_can_continue_color, bool p_can_continue_depth
if (!material) {
sky_material = sky_shader.default_material;
- material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY));
+ material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
}
}
if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
sky_material = sky_scene_state.fog_material;
- material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY));
+ material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
}
ERR_FAIL_COND(!material);
@@ -1610,7 +1614,7 @@ void SkyRD::update_res_buffers(RID p_env, uint32_t p_view_count, const Projectio
sky_material = sky_get_material(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));
if (sky_material.is_valid()) {
- material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY));
+ material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
if (!material || !material->shader_data->valid) {
material = nullptr;
}
@@ -1618,7 +1622,7 @@ void SkyRD::update_res_buffers(RID p_env, uint32_t p_view_count, const Projectio
if (!material) {
sky_material = sky_shader.default_material;
- material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY));
+ material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
}
ERR_FAIL_COND(!material);
@@ -1698,7 +1702,7 @@ void SkyRD::draw(RD::DrawListID p_draw_list, RID p_env, RID p_fb, uint32_t p_vie
sky_material = sky_get_material(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));
if (sky_material.is_valid()) {
- material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY));
+ material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
if (!material || !material->shader_data->valid) {
material = nullptr;
}
@@ -1706,13 +1710,13 @@ void SkyRD::draw(RD::DrawListID p_draw_list, RID p_env, RID p_fb, uint32_t p_vie
if (!material) {
sky_material = sky_shader.default_material;
- material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY));
+ material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
}
}
if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
sky_material = sky_scene_state.fog_material;
- material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::SHADER_TYPE_SKY));
+ material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
}
ERR_FAIL_COND(!material);
diff --git a/servers/rendering/renderer_rd/environment/sky.h b/servers/rendering/renderer_rd/environment/sky.h
index 5402705918..080165c112 100644
--- a/servers/rendering/renderer_rd/environment/sky.h
+++ b/servers/rendering/renderer_rd/environment/sky.h
@@ -107,7 +107,7 @@ private:
// 128 is the max size of a push constant. We can replace "pad" but we can't add any more.
};
- struct SkyShaderData : public RendererRD::ShaderData {
+ struct SkyShaderData : public RendererRD::MaterialStorage::ShaderData {
bool valid = false;
RID version;
@@ -131,7 +131,7 @@ private:
virtual void set_code(const String &p_Code);
virtual void set_path_hint(const String &p_hint);
virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
- virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
virtual bool is_param_texture(const StringName &p_param) const;
virtual bool is_animated() const;
@@ -231,7 +231,7 @@ public:
RID default_shader_rd;
} sky_shader;
- struct SkyMaterialData : public RendererRD::MaterialData {
+ struct SkyMaterialData : public RendererRD::MaterialStorage::MaterialData {
SkyShaderData *shader_data = nullptr;
RID uniform_set;
bool uniform_set_updated;
@@ -285,11 +285,11 @@ public:
mutable RID_Owner<Sky, true> sky_owner;
int roughness_layers;
- RendererRD::ShaderData *_create_sky_shader_func();
- static RendererRD::ShaderData *_create_sky_shader_funcs();
+ RendererRD::MaterialStorage::ShaderData *_create_sky_shader_func();
+ static RendererRD::MaterialStorage::ShaderData *_create_sky_shader_funcs();
- RendererRD::MaterialData *_create_sky_material_func(SkyShaderData *p_shader);
- static RendererRD::MaterialData *_create_sky_material_funcs(RendererRD::ShaderData *p_shader);
+ RendererRD::MaterialStorage::MaterialData *_create_sky_material_func(SkyShaderData *p_shader);
+ static RendererRD::MaterialStorage::MaterialData *_create_sky_material_funcs(RendererRD::MaterialStorage::ShaderData *p_shader);
SkyRD();
void init();
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 6f200220f0..8754e90647 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -1076,7 +1076,7 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, i
instance_data.flags = inst->flags_cache;
instance_data.gi_offset = inst->gi_offset_cache;
instance_data.layer_mask = inst->layer_mask;
- instance_data.instance_uniforms_ofs = uint32_t(inst->shader_parameters_offset);
+ instance_data.instance_uniforms_ofs = uint32_t(inst->shader_uniforms_offset);
instance_data.lightmap_uv_scale[0] = inst->lightmap_uv_scale.position.x;
instance_data.lightmap_uv_scale[1] = inst->lightmap_uv_scale.position.y;
instance_data.lightmap_uv_scale[2] = inst->lightmap_uv_scale.size.x;
@@ -2265,15 +2265,18 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
case RS::DECAL_FILTER_NEAREST: {
sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
- case RS::DECAL_FILTER_NEAREST_MIPMAPS: {
- sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
case RS::DECAL_FILTER_LINEAR: {
sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
+ case RS::DECAL_FILTER_NEAREST_MIPMAPS: {
+ sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
case RS::DECAL_FILTER_LINEAR_MIPMAPS: {
sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
+ case RS::DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
+ sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
case RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
@@ -2292,15 +2295,18 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
case RS::LIGHT_PROJECTOR_FILTER_NEAREST: {
sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
- case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: {
- sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
case RS::LIGHT_PROJECTOR_FILTER_LINEAR: {
sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: {
+ sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS: {
sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
+ sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
@@ -2433,7 +2439,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
if (p_radiance_texture.is_valid()) {
radiance_texture = p_radiance_texture;
} else {
- radiance_texture = texture_storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
+ radiance_texture = texture_storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
}
RD::Uniform u;
u.binding = 2;
@@ -2450,7 +2456,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
if (ref_texture.is_valid()) {
u.append_id(ref_texture);
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK));
}
uniforms.push_back(u);
}
@@ -2464,7 +2470,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
texture = shadow_atlas_get_texture(p_render_data->shadow_atlas);
}
if (!texture.is_valid()) {
- texture = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_DEPTH);
+ texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
}
u.append_id(texture);
uniforms.push_back(u);
@@ -2476,7 +2482,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
if (p_use_directional_shadow_atlas && directional_shadow_get_texture().is_valid()) {
u.append_id(directional_shadow_get_texture());
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_DEPTH));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH));
}
uniforms.push_back(u);
}
@@ -2485,7 +2491,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
u.binding = 6;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID default_tex = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
+ RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) {
if (p_render_data && i < p_render_data->lightmaps->size()) {
RID base = lightmap_instance_get_lightmap((*p_render_data->lightmaps)[i]);
@@ -2503,7 +2509,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
u.binding = 7;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID default_tex = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
for (int i = 0; i < MAX_VOXEL_GI_INSTANCESS; i++) {
if (p_render_data && i < (int)p_render_data->voxel_gi_instances->size()) {
RID tex = gi.voxel_gi_instance_get_texture((*p_render_data->voxel_gi_instances)[i]);
@@ -2533,7 +2539,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
u.binding = 9;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID dbt = rb ? render_buffers_get_back_depth_texture(p_render_data->render_buffers) : RID();
- RID texture = (dbt.is_valid()) ? dbt : texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_DEPTH);
+ RID texture = (dbt.is_valid()) ? dbt : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
u.append_id(texture);
uniforms.push_back(u);
}
@@ -2542,7 +2548,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
u.binding = 10;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID bbt = rb ? render_buffers_get_back_buffer_texture(p_render_data->render_buffers) : RID();
- RID texture = bbt.is_valid() ? bbt : texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_BLACK);
+ RID texture = bbt.is_valid() ? bbt : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
u.append_id(texture);
uniforms.push_back(u);
}
@@ -2552,7 +2558,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
u.binding = 11;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID texture = rb && rb->normal_roughness_buffer.is_valid() ? rb->normal_roughness_buffer : texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_NORMAL);
+ RID texture = rb && rb->normal_roughness_buffer.is_valid() ? rb->normal_roughness_buffer : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_NORMAL);
u.append_id(texture);
uniforms.push_back(u);
}
@@ -2562,7 +2568,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
u.binding = 12;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID aot = rb ? render_buffers_get_ao_texture(p_render_data->render_buffers) : RID();
- RID texture = aot.is_valid() ? aot : texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_BLACK);
+ RID texture = aot.is_valid() ? aot : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
u.append_id(texture);
uniforms.push_back(u);
}
@@ -2572,7 +2578,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
u.binding = 13;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID ambient_buffer = rb ? render_buffers_get_gi_ambient_texture(p_render_data->render_buffers) : RID();
- RID texture = ambient_buffer.is_valid() ? ambient_buffer : texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_BLACK);
+ RID texture = ambient_buffer.is_valid() ? ambient_buffer : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
u.append_id(texture);
uniforms.push_back(u);
}
@@ -2582,7 +2588,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
u.binding = 14;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID reflection_buffer = rb ? render_buffers_get_gi_reflection_texture(p_render_data->render_buffers) : RID();
- RID texture = reflection_buffer.is_valid() ? reflection_buffer : texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_BLACK);
+ RID texture = reflection_buffer.is_valid() ? reflection_buffer : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
u.append_id(texture);
uniforms.push_back(u);
}
@@ -2594,7 +2600,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
if (rb && render_buffers_is_sdfgi_enabled(p_render_data->render_buffers)) {
t = render_buffers_get_sdfgi_irradiance_probes(p_render_data->render_buffers);
} else {
- t = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
+ t = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
}
u.append_id(t);
uniforms.push_back(u);
@@ -2606,7 +2612,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
if (rb && render_buffers_is_sdfgi_enabled(p_render_data->render_buffers)) {
u.append_id(render_buffers_get_sdfgi_occlusion_texture(p_render_data->render_buffers));
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE));
}
uniforms.push_back(u);
}
@@ -2625,10 +2631,10 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
if (rb && render_buffers_has_volumetric_fog(p_render_data->render_buffers)) {
vfog = render_buffers_get_volumetric_fog_texture(p_render_data->render_buffers);
if (vfog.is_null()) {
- vfog = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ vfog = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
}
} else {
- vfog = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ vfog = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
}
u.append_id(vfog);
uniforms.push_back(u);
@@ -2638,7 +2644,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
u.binding = 19;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID ssil = rb ? render_buffers_get_ssil_texture(p_render_data->render_buffers) : RID();
- RID texture = ssil.is_valid() ? ssil : texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_BLACK);
+ RID texture = ssil.is_valid() ? ssil : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
u.append_id(texture);
uniforms.push_back(u);
}
@@ -2662,12 +2668,16 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
RD::Uniform u;
u.binding = 1;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.append_id(scene_state.instance_buffer[RENDER_LIST_SECONDARY]);
+ RID instance_buffer = scene_state.instance_buffer[RENDER_LIST_SECONDARY];
+ if (instance_buffer == RID()) {
+ instance_buffer = scene_shader.default_vec4_xform_buffer; // any buffer will do since its not used
+ }
+ u.append_id(instance_buffer);
uniforms.push_back(u);
}
{
// No radiance texture.
- RID radiance_texture = texture_storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
+ RID radiance_texture = texture_storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
RD::Uniform u;
u.binding = 2;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
@@ -2677,7 +2687,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
{
// No reflection atlas.
- RID ref_texture = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK);
+ RID ref_texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK);
RD::Uniform u;
u.binding = 3;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
@@ -2690,7 +2700,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
RD::Uniform u;
u.binding = 4;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID texture = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_DEPTH);
+ RID texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
u.append_id(texture);
uniforms.push_back(u);
}
@@ -2700,7 +2710,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
RD::Uniform u;
u.binding = 5;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID texture = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_DEPTH);
+ RID texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
u.append_id(texture);
uniforms.push_back(u);
}
@@ -2711,7 +2721,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
u.binding = 6;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID default_tex = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
+ RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) {
u.append_id(default_tex);
}
@@ -2725,7 +2735,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
u.binding = 7;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID default_tex = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
for (int i = 0; i < MAX_VOXEL_GI_INSTANCESS; i++) {
u.append_id(default_tex);
}
@@ -2860,7 +2870,7 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet
void *surface_shadow = nullptr;
if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_position && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass && !p_material->shader_data->uses_alpha_clip && p_material->shader_data->cull_mode == SceneShaderForwardClustered::ShaderData::CULL_BACK) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
- material_shadow = static_cast<SceneShaderForwardClustered::MaterialData *>(RendererRD::MaterialStorage::get_singleton()->material_get_data(scene_shader.default_material, RendererRD::SHADER_TYPE_3D));
+ material_shadow = static_cast<SceneShaderForwardClustered::MaterialData *>(RendererRD::MaterialStorage::get_singleton()->material_get_data(scene_shader.default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
RID shadow_mesh = mesh_storage->mesh_get_shadow_mesh(p_mesh);
@@ -2921,7 +2931,7 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material_chain(
while (material->next_pass.is_valid()) {
RID next_pass = material->next_pass;
- material = static_cast<SceneShaderForwardClustered::MaterialData *>(material_storage->material_get_data(next_pass, RendererRD::SHADER_TYPE_3D));
+ material = static_cast<SceneShaderForwardClustered::MaterialData *>(material_storage->material_get_data(next_pass, RendererRD::MaterialStorage::SHADER_TYPE_3D));
if (!material || !material->shader_data->valid) {
break;
}
@@ -2941,7 +2951,7 @@ void RenderForwardClustered::_geometry_instance_add_surface(GeometryInstanceForw
SceneShaderForwardClustered::MaterialData *material = nullptr;
if (m_src.is_valid()) {
- material = static_cast<SceneShaderForwardClustered::MaterialData *>(material_storage->material_get_data(m_src, RendererRD::SHADER_TYPE_3D));
+ material = static_cast<SceneShaderForwardClustered::MaterialData *>(material_storage->material_get_data(m_src, RendererRD::MaterialStorage::SHADER_TYPE_3D));
if (!material || !material->shader_data->valid) {
material = nullptr;
}
@@ -2952,7 +2962,7 @@ void RenderForwardClustered::_geometry_instance_add_surface(GeometryInstanceForw
material_storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker);
}
} else {
- material = static_cast<SceneShaderForwardClustered::MaterialData *>(material_storage->material_get_data(scene_shader.default_material, RendererRD::SHADER_TYPE_3D));
+ material = static_cast<SceneShaderForwardClustered::MaterialData *>(material_storage->material_get_data(scene_shader.default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
m_src = scene_shader.default_material;
}
@@ -2963,7 +2973,7 @@ void RenderForwardClustered::_geometry_instance_add_surface(GeometryInstanceForw
if (ginstance->data->material_overlay.is_valid()) {
m_src = ginstance->data->material_overlay;
- material = static_cast<SceneShaderForwardClustered::MaterialData *>(material_storage->material_get_data(m_src, RendererRD::SHADER_TYPE_3D));
+ material = static_cast<SceneShaderForwardClustered::MaterialData *>(material_storage->material_get_data(m_src, RendererRD::MaterialStorage::SHADER_TYPE_3D));
if (material && material->shader_data->valid) {
if (ginstance->data->dirty_dependencies) {
material_storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker);
@@ -3271,12 +3281,18 @@ void RenderForwardClustered::_update_shader_quality_settings() {
sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
sc.constant_id = SPEC_CONSTANT_DECAL_FILTER;
- sc.bool_value = decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS || decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS || decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
+ sc.bool_value = decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS ||
+ decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS ||
+ decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC ||
+ decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
spec_constants.push_back(sc);
sc.constant_id = SPEC_CONSTANT_PROJECTOR_FILTER;
- sc.bool_value = light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS || light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS || light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
+ sc.bool_value = light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS ||
+ light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS ||
+ light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC ||
+ light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
spec_constants.push_back(sc);
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
index c84a4469ae..0911ee595f 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -150,6 +150,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
depth_draw = DepthDraw(depth_drawi);
depth_test = DepthTest(depth_testi);
cull_mode = Cull(cull_modei);
+ uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
#if 0
print_line("**compiling shader:");
@@ -158,11 +159,10 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
print_line(gen_code.defines[i]);
}
- RBMap<String, String>::Element *el = gen_code.code.front();
+ HashMap<String, String>::Iterator el = gen_code.code.begin();
while (el) {
- print_line("\n**code " + el->key() + ":\n" + el->value());
-
- el = el->next();
+ print_line("\n**code " + el->key + ":\n" + el->value);
+ ++el;
}
print_line("\n**uniforms:\n" + gen_code.uniforms);
@@ -392,11 +392,15 @@ void SceneShaderForwardClustered::ShaderData::set_default_texture_param(const St
}
}
-void SceneShaderForwardClustered::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+void SceneShaderForwardClustered::ShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
HashMap<int, StringName> order;
for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL ||
+ E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE ||
+ E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE ||
+ E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
+ // Don't expose any of these.
continue;
}
@@ -488,7 +492,7 @@ SceneShaderForwardClustered::ShaderData::~ShaderData() {
}
}
-RendererRD::ShaderData *SceneShaderForwardClustered::_create_shader_func() {
+RendererRD::MaterialStorage::ShaderData *SceneShaderForwardClustered::_create_shader_func() {
ShaderData *shader_data = memnew(ShaderData);
singleton->shader_list.add(&shader_data->shader_list_element);
return shader_data;
@@ -512,7 +516,7 @@ SceneShaderForwardClustered::MaterialData::~MaterialData() {
free_parameters_uniform_set(uniform_set);
}
-RendererRD::MaterialData *SceneShaderForwardClustered::_create_material_func(ShaderData *p_shader) {
+RendererRD::MaterialStorage::MaterialData *SceneShaderForwardClustered::_create_material_func(ShaderData *p_shader) {
MaterialData *material_data = memnew(MaterialData);
material_data->shader_data = p_shader;
//update will happen later anyway so do nothing.
@@ -610,8 +614,8 @@ void SceneShaderForwardClustered::init(const String p_defines) {
valid_color_pass_pipelines.insert(PIPELINE_COLOR_PASS_FLAG_MOTION_VECTORS);
- material_storage->shader_set_data_request_function(RendererRD::SHADER_TYPE_3D, _create_shader_funcs);
- material_storage->material_set_data_request_function(RendererRD::SHADER_TYPE_3D, _create_material_funcs);
+ material_storage->shader_set_data_request_function(RendererRD::MaterialStorage::SHADER_TYPE_3D, _create_shader_funcs);
+ material_storage->material_set_data_request_function(RendererRD::MaterialStorage::SHADER_TYPE_3D, _create_material_funcs);
{
//shader compiler
@@ -693,6 +697,11 @@ void SceneShaderForwardClustered::init(const String p_defines) {
actions.renames["CUSTOM3"] = "custom3_attrib";
actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
+ actions.renames["NODE_POSITION_WORLD"] = "model_matrix[3].xyz";
+ actions.renames["CAMERA_POSITION_WORLD"] = "scene_data.inv_view_matrix[3].xyz";
+ actions.renames["CAMERA_DIRECTION_WORLD"] = "scene_data.view_matrix[3].xyz";
+ actions.renames["NODE_POSITION_VIEW"] = "(model_matrix * scene_data.view_matrix)[3].xyz";
+
actions.renames["VIEW_INDEX"] = "ViewIndex";
actions.renames["VIEW_MONO_LEFT"] = "0";
actions.renames["VIEW_RIGHT"] = "1";
@@ -817,7 +826,7 @@ void fragment() {
material_storage->material_initialize(default_material);
material_storage->material_set_shader(default_material, default_shader);
- MaterialData *md = static_cast<MaterialData *>(material_storage->material_get_data(default_material, RendererRD::SHADER_TYPE_3D));
+ MaterialData *md = static_cast<MaterialData *>(material_storage->material_get_data(default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
default_shader_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS);
default_shader_sdfgi_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_DEPTH_PASS_WITH_SDF);
@@ -845,7 +854,7 @@ void fragment() {
material_storage->material_initialize(overdraw_material);
material_storage->material_set_shader(overdraw_material, overdraw_material_shader);
- MaterialData *md = static_cast<MaterialData *>(material_storage->material_get_data(overdraw_material, RendererRD::SHADER_TYPE_3D));
+ MaterialData *md = static_cast<MaterialData *>(material_storage->material_get_data(overdraw_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
overdraw_material_shader_ptr = md->shader_data;
overdraw_material_uniform_set = md->uniform_set;
}
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
index fb001d6933..d6b526fa4a 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
@@ -93,7 +93,7 @@ public:
SHADER_SPECIALIZATION_DIRECTIONAL_SOFT_SHADOWS = 1 << 3,
};
- struct ShaderData : public RendererRD::ShaderData {
+ struct ShaderData : public RendererRD::MaterialStorage::ShaderData {
enum BlendMode { //used internally
BLEND_MODE_MIX,
BLEND_MODE_ADD,
@@ -174,6 +174,7 @@ public:
bool uses_time = false;
bool writes_modelview_or_projection = false;
bool uses_world_coordinates = false;
+ bool uses_screen_texture_mipmaps = false;
Cull cull_mode = CULL_DISABLED;
uint64_t last_pass = 0;
@@ -182,7 +183,7 @@ public:
virtual void set_code(const String &p_Code);
virtual void set_path_hint(const String &p_path);
virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
- virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
virtual bool is_param_texture(const StringName &p_param) const;
@@ -198,12 +199,12 @@ public:
SelfList<ShaderData>::List shader_list;
- RendererRD::ShaderData *_create_shader_func();
- static RendererRD::ShaderData *_create_shader_funcs() {
+ RendererRD::MaterialStorage::ShaderData *_create_shader_func();
+ static RendererRD::MaterialStorage::ShaderData *_create_shader_funcs() {
return static_cast<SceneShaderForwardClustered *>(singleton)->_create_shader_func();
}
- struct MaterialData : public RendererRD::MaterialData {
+ struct MaterialData : public RendererRD::MaterialStorage::MaterialData {
ShaderData *shader_data = nullptr;
RID uniform_set;
uint64_t last_pass = 0;
@@ -216,8 +217,8 @@ public:
virtual ~MaterialData();
};
- RendererRD::MaterialData *_create_material_func(ShaderData *p_shader);
- static RendererRD::MaterialData *_create_material_funcs(RendererRD::ShaderData *p_shader) {
+ RendererRD::MaterialStorage::MaterialData *_create_material_func(ShaderData *p_shader);
+ static RendererRD::MaterialStorage::MaterialData *_create_material_funcs(RendererRD::MaterialStorage::ShaderData *p_shader) {
return static_cast<SceneShaderForwardClustered *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
}
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index a179688487..ffd47cc163 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -337,7 +337,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
if (p_radiance_texture.is_valid()) {
radiance_texture = p_radiance_texture;
} else {
- radiance_texture = texture_storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
+ radiance_texture = texture_storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
}
RD::Uniform u;
u.binding = 2;
@@ -354,7 +354,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
if (ref_texture.is_valid()) {
u.append_id(ref_texture);
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK));
}
uniforms.push_back(u);
}
@@ -368,7 +368,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
texture = shadow_atlas_get_texture(p_render_data->shadow_atlas);
}
if (!texture.is_valid()) {
- texture = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_DEPTH);
+ texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
}
u.append_id(texture);
uniforms.push_back(u);
@@ -380,7 +380,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
if (p_use_directional_shadow_atlas && directional_shadow_get_texture().is_valid()) {
u.append_id(directional_shadow_get_texture());
} else {
- u.append_id(texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_DEPTH));
+ u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH));
}
uniforms.push_back(u);
}
@@ -391,7 +391,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
u.binding = 6;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID default_tex = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
+ RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) {
if (p_render_data && i < p_render_data->lightmaps->size()) {
RID base = lightmap_instance_get_lightmap((*p_render_data->lightmaps)[i]);
@@ -412,7 +412,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
u.binding = 7;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.ids.resize(MAX_VOXEL_GI_INSTANCESS);
- RID default_tex = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
for (int i = 0; i < MAX_VOXEL_GI_INSTANCESS; i++) {
if (i < (int)p_voxel_gi_instances.size()) {
RID tex = gi.voxel_gi_instance_get_texture(p_voxel_gi_instances[i]);
@@ -443,7 +443,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
u.binding = 9;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID dbt = rb ? render_buffers_get_back_depth_texture(p_render_data->render_buffers) : RID();
- RID texture = (dbt.is_valid()) ? dbt : texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_DEPTH);
+ RID texture = (dbt.is_valid()) ? dbt : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
u.append_id(texture);
uniforms.push_back(u);
}
@@ -452,7 +452,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
u.binding = 10;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID bbt = rb ? render_buffers_get_back_buffer_texture(p_render_data->render_buffers) : RID();
- RID texture = bbt.is_valid() ? bbt : texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_BLACK);
+ RID texture = bbt.is_valid() ? bbt : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
u.append_id(texture);
uniforms.push_back(u);
}
@@ -1214,15 +1214,18 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
case RS::DECAL_FILTER_NEAREST: {
sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
- case RS::DECAL_FILTER_NEAREST_MIPMAPS: {
- sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
case RS::DECAL_FILTER_LINEAR: {
sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
+ case RS::DECAL_FILTER_NEAREST_MIPMAPS: {
+ sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
case RS::DECAL_FILTER_LINEAR_MIPMAPS: {
sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
+ case RS::DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
+ sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
case RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
@@ -1241,15 +1244,18 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
case RS::LIGHT_PROJECTOR_FILTER_NEAREST: {
sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
- case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: {
- sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
case RS::LIGHT_PROJECTOR_FILTER_LINEAR: {
sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: {
+ sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS: {
sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
+ sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
@@ -1897,7 +1903,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
push_constant.flags = inst->flags_cache;
push_constant.gi_offset = inst->gi_offset_cache;
push_constant.layer_mask = inst->layer_mask;
- push_constant.instance_uniforms_ofs = uint32_t(inst->shader_parameters_offset);
+ push_constant.instance_uniforms_ofs = uint32_t(inst->shader_uniforms_offset);
if (p_params->pass_mode == PASS_MODE_DEPTH_MATERIAL) {
// abuse lightmap_uv_scale[0] here, should not be needed here
@@ -2227,7 +2233,7 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryI
void *surface_shadow = nullptr;
if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass && !p_material->shader_data->uses_alpha_clip) {
flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL;
- material_shadow = static_cast<SceneShaderForwardMobile::MaterialData *>(RendererRD::MaterialStorage::get_singleton()->material_get_data(scene_shader.default_material, RendererRD::SHADER_TYPE_3D));
+ material_shadow = static_cast<SceneShaderForwardMobile::MaterialData *>(RendererRD::MaterialStorage::get_singleton()->material_get_data(scene_shader.default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
RID shadow_mesh = mesh_storage->mesh_get_shadow_mesh(p_mesh);
@@ -2286,7 +2292,7 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material_chain(Geo
while (material->next_pass.is_valid()) {
RID next_pass = material->next_pass;
- material = static_cast<SceneShaderForwardMobile::MaterialData *>(material_storage->material_get_data(next_pass, RendererRD::SHADER_TYPE_3D));
+ material = static_cast<SceneShaderForwardMobile::MaterialData *>(material_storage->material_get_data(next_pass, RendererRD::MaterialStorage::SHADER_TYPE_3D));
if (!material || !material->shader_data->valid) {
break;
}
@@ -2306,7 +2312,7 @@ void RenderForwardMobile::_geometry_instance_add_surface(GeometryInstanceForward
SceneShaderForwardMobile::MaterialData *material = nullptr;
if (m_src.is_valid()) {
- material = static_cast<SceneShaderForwardMobile::MaterialData *>(material_storage->material_get_data(m_src, RendererRD::SHADER_TYPE_3D));
+ material = static_cast<SceneShaderForwardMobile::MaterialData *>(material_storage->material_get_data(m_src, RendererRD::MaterialStorage::SHADER_TYPE_3D));
if (!material || !material->shader_data->valid) {
material = nullptr;
}
@@ -2317,7 +2323,7 @@ void RenderForwardMobile::_geometry_instance_add_surface(GeometryInstanceForward
material_storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker);
}
} else {
- material = static_cast<SceneShaderForwardMobile::MaterialData *>(material_storage->material_get_data(scene_shader.default_material, RendererRD::SHADER_TYPE_3D));
+ material = static_cast<SceneShaderForwardMobile::MaterialData *>(material_storage->material_get_data(scene_shader.default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
m_src = scene_shader.default_material;
}
@@ -2328,7 +2334,7 @@ void RenderForwardMobile::_geometry_instance_add_surface(GeometryInstanceForward
if (ginstance->data->material_overlay.is_valid()) {
m_src = ginstance->data->material_overlay;
- material = static_cast<SceneShaderForwardMobile::MaterialData *>(material_storage->material_get_data(m_src, RendererRD::SHADER_TYPE_3D));
+ material = static_cast<SceneShaderForwardMobile::MaterialData *>(material_storage->material_get_data(m_src, RendererRD::MaterialStorage::SHADER_TYPE_3D));
if (material && material->shader_data->valid) {
if (ginstance->data->dirty_dependencies) {
material_storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker);
@@ -2558,12 +2564,18 @@ void RenderForwardMobile::_update_shader_quality_settings() {
sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
sc.constant_id = SPEC_CONSTANT_DECAL_USE_MIPMAPS;
- sc.bool_value = decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS || decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS || decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
+ sc.bool_value = decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS ||
+ decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS ||
+ decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC ||
+ decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
spec_constants.push_back(sc);
sc.constant_id = SPEC_CONSTANT_PROJECTOR_USE_MIPMAPS;
- sc.bool_value = light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS || light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS || light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
+ sc.bool_value = light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS ||
+ light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS ||
+ light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC ||
+ light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
spec_constants.push_back(sc);
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
index c6eac298e7..85c9e1db2a 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
@@ -158,11 +158,10 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
print_line(gen_code.defines[i]);
}
- RBMap<String, String>::Element * el = gen_code.code.front();
+ HashMap<String, String>::Iterator el = gen_code.code.begin();
while (el) {
- print_line("\n**code " + el->key() + ":\n" + el->value());
-
- el = el->next();
+ print_line("\n**code " + el->key + ":\n" + el->value);
+ ++el;
}
print_line("\n**uniforms:\n" + gen_code.uniforms);
@@ -349,11 +348,14 @@ void SceneShaderForwardMobile::ShaderData::set_default_texture_param(const Strin
}
}
-void SceneShaderForwardMobile::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+void SceneShaderForwardMobile::ShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
HashMap<int, StringName> order;
for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL ||
+ E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE ||
+ E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE ||
+ E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
continue;
}
@@ -445,7 +447,7 @@ SceneShaderForwardMobile::ShaderData::~ShaderData() {
}
}
-RendererRD::ShaderData *SceneShaderForwardMobile::_create_shader_func() {
+RendererRD::MaterialStorage::ShaderData *SceneShaderForwardMobile::_create_shader_func() {
ShaderData *shader_data = memnew(ShaderData);
singleton->shader_list.add(&shader_data->shader_list_element);
return shader_data;
@@ -469,7 +471,7 @@ SceneShaderForwardMobile::MaterialData::~MaterialData() {
free_parameters_uniform_set(uniform_set);
}
-RendererRD::MaterialData *SceneShaderForwardMobile::_create_material_func(ShaderData *p_shader) {
+RendererRD::MaterialStorage::MaterialData *SceneShaderForwardMobile::_create_material_func(ShaderData *p_shader) {
MaterialData *material_data = memnew(MaterialData);
material_data->shader_data = p_shader;
//update will happen later anyway so do nothing.
@@ -512,8 +514,8 @@ void SceneShaderForwardMobile::init(const String p_defines) {
}
}
- material_storage->shader_set_data_request_function(RendererRD::SHADER_TYPE_3D, _create_shader_funcs);
- material_storage->material_set_data_request_function(RendererRD::SHADER_TYPE_3D, _create_material_funcs);
+ material_storage->shader_set_data_request_function(RendererRD::MaterialStorage::SHADER_TYPE_3D, _create_shader_funcs);
+ material_storage->material_set_data_request_function(RendererRD::MaterialStorage::SHADER_TYPE_3D, _create_material_funcs);
{
//shader compiler
@@ -595,6 +597,11 @@ void SceneShaderForwardMobile::init(const String p_defines) {
actions.renames["CUSTOM3"] = "custom3_attrib";
actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB";
+ actions.renames["NODE_POSITION_WORLD"] = "model_matrix[3].xyz";
+ actions.renames["CAMERA_POSITION_WORLD"] = "scene_data.inv_view_matrix[3].xyz";
+ actions.renames["CAMERA_DIRECTION_WORLD"] = "scene_data.view_matrix[3].xyz";
+ actions.renames["NODE_POSITION_VIEW"] = "(model_matrix * scene_data.view_matrix)[3].xyz";
+
actions.renames["VIEW_INDEX"] = "ViewIndex";
actions.renames["VIEW_MONO_LEFT"] = "0";
actions.renames["VIEW_RIGHT"] = "1";
@@ -716,7 +723,7 @@ void fragment() {
material_storage->material_initialize(default_material);
material_storage->material_set_shader(default_material, default_shader);
- MaterialData *md = static_cast<MaterialData *>(material_storage->material_get_data(default_material, RendererRD::SHADER_TYPE_3D));
+ MaterialData *md = static_cast<MaterialData *>(material_storage->material_get_data(default_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
default_shader_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS);
default_material_shader_ptr = md->shader_data;
@@ -743,7 +750,7 @@ void fragment() {
material_storage->material_initialize(overdraw_material);
material_storage->material_set_shader(overdraw_material, overdraw_material_shader);
- MaterialData *md = static_cast<MaterialData *>(material_storage->material_get_data(overdraw_material, RendererRD::SHADER_TYPE_3D));
+ MaterialData *md = static_cast<MaterialData *>(material_storage->material_get_data(overdraw_material, RendererRD::MaterialStorage::SHADER_TYPE_3D));
overdraw_material_shader_ptr = md->shader_data;
overdraw_material_uniform_set = md->uniform_set;
}
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
index 0dbed0b07a..e208334547 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
@@ -55,7 +55,7 @@ public:
SHADER_VERSION_MAX
};
- struct ShaderData : public RendererRD::ShaderData {
+ struct ShaderData : public RendererRD::MaterialStorage::ShaderData {
enum BlendMode { //used internally
BLEND_MODE_MIX,
BLEND_MODE_ADD,
@@ -142,7 +142,7 @@ public:
virtual void set_path_hint(const String &p_path);
virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
- virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
virtual bool is_param_texture(const StringName &p_param) const;
@@ -157,12 +157,12 @@ public:
virtual ~ShaderData();
};
- RendererRD::ShaderData *_create_shader_func();
- static RendererRD::ShaderData *_create_shader_funcs() {
+ RendererRD::MaterialStorage::ShaderData *_create_shader_func();
+ static RendererRD::MaterialStorage::ShaderData *_create_shader_funcs() {
return static_cast<SceneShaderForwardMobile *>(singleton)->_create_shader_func();
}
- struct MaterialData : public RendererRD::MaterialData {
+ struct MaterialData : public RendererRD::MaterialStorage::MaterialData {
ShaderData *shader_data = nullptr;
RID uniform_set;
uint64_t last_pass = 0;
@@ -177,8 +177,8 @@ public:
SelfList<ShaderData>::List shader_list;
- RendererRD::MaterialData *_create_material_func(ShaderData *p_shader);
- static RendererRD::MaterialData *_create_material_funcs(RendererRD::ShaderData *p_shader) {
+ RendererRD::MaterialStorage::MaterialData *_create_material_func(ShaderData *p_shader);
+ static RendererRD::MaterialStorage::MaterialData *_create_material_funcs(RendererRD::MaterialStorage::ShaderData *p_shader) {
return static_cast<SceneShaderForwardMobile *>(singleton)->_create_material_func(static_cast<ShaderData *>(p_shader));
}
diff --git a/modules/mono/glue/rid_glue.cpp b/servers/rendering/renderer_rd/framebuffer_cache_rd.cpp
index 3e09564539..9baa86a32d 100644
--- a/modules/mono/glue/rid_glue.cpp
+++ b/servers/rendering/renderer_rd/framebuffer_cache_rd.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* rid_glue.cpp */
+/* framebuffer_cache_rd.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,37 +28,37 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef MONO_GLUE_ENABLED
+#include "framebuffer_cache_rd.h"
-#include "core/io/resource.h"
-#include "core/object/class_db.h"
-#include "core/templates/rid.h"
+FramebufferCacheRD *FramebufferCacheRD::singleton = nullptr;
-#include "../mono_gd/gd_mono_marshal.h"
-
-RID *godot_icall_RID_Ctor(Object *p_from) {
- Resource *res_from = Object::cast_to<Resource>(p_from);
+void FramebufferCacheRD::_invalidate(Cache *p_cache) {
+ if (p_cache->prev) {
+ p_cache->prev->next = p_cache->next;
+ } else {
+ // At beginning of table
+ uint32_t table_idx = p_cache->hash % HASH_TABLE_SIZE;
+ hash_table[table_idx] = p_cache->next;
+ }
- if (res_from) {
- return memnew(RID(res_from->get_rid()));
+ if (p_cache->next) {
+ p_cache->next->prev = p_cache->prev;
}
- return memnew(RID);
+ cache_allocator.free(p_cache);
+ cache_instances_used--;
}
-
-void godot_icall_RID_Dtor(RID *p_ptr) {
- ERR_FAIL_NULL(p_ptr);
- memdelete(p_ptr);
+void FramebufferCacheRD::_framebuffer_invalidation_callback(void *p_userdata) {
+ singleton->_invalidate(reinterpret_cast<Cache *>(p_userdata));
}
-uint32_t godot_icall_RID_get_id(RID *p_ptr) {
- return p_ptr->get_id();
+FramebufferCacheRD::FramebufferCacheRD() {
+ ERR_FAIL_COND(singleton != nullptr);
+ singleton = this;
}
-void godot_register_rid_icalls() {
- GDMonoUtils::add_internal_call("Godot.RID::godot_icall_RID_Ctor", godot_icall_RID_Ctor);
- GDMonoUtils::add_internal_call("Godot.RID::godot_icall_RID_Dtor", godot_icall_RID_Dtor);
- GDMonoUtils::add_internal_call("Godot.RID::godot_icall_RID_get_id", godot_icall_RID_get_id);
+FramebufferCacheRD::~FramebufferCacheRD() {
+ if (cache_instances_used > 0) {
+ ERR_PRINT("At exit: " + itos(cache_instances_used) + " framebuffer cache instance(s) still in use.");
+ }
}
-
-#endif // MONO_GLUE_ENABLED
diff --git a/servers/rendering/renderer_rd/framebuffer_cache_rd.h b/servers/rendering/renderer_rd/framebuffer_cache_rd.h
new file mode 100644
index 0000000000..f360e0fc6b
--- /dev/null
+++ b/servers/rendering/renderer_rd/framebuffer_cache_rd.h
@@ -0,0 +1,310 @@
+/*************************************************************************/
+/* framebuffer_cache_rd.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef FRAMEBUFFER_CACHE_RD_H
+#define FRAMEBUFFER_CACHE_RD_H
+
+#include "core/templates/local_vector.h"
+#include "core/templates/paged_allocator.h"
+#include "servers/rendering/rendering_device.h"
+
+class FramebufferCacheRD : public Object {
+ GDCLASS(FramebufferCacheRD, Object)
+
+ struct Cache {
+ Cache *prev = nullptr;
+ Cache *next = nullptr;
+ uint32_t hash = 0;
+ RID cache;
+ LocalVector<RID> textures;
+ LocalVector<RD::FramebufferPass> passes;
+ uint32_t views = 0;
+ };
+
+ PagedAllocator<Cache> cache_allocator;
+
+ enum {
+ HASH_TABLE_SIZE = 16381 // Prime
+ };
+
+ Cache *hash_table[HASH_TABLE_SIZE] = {};
+
+ static _FORCE_INLINE_ uint32_t _hash_pass(const RD::FramebufferPass &p, uint32_t h) {
+ h = hash_murmur3_one_32(p.depth_attachment, h);
+ h = hash_murmur3_one_32(p.vrs_attachment, h);
+
+ h = hash_murmur3_one_32(p.color_attachments.size(), h);
+ for (int i = 0; i < p.color_attachments.size(); i++) {
+ h = hash_murmur3_one_32(p.color_attachments[i], h);
+ }
+
+ h = hash_murmur3_one_32(p.resolve_attachments.size(), h);
+ for (int i = 0; i < p.resolve_attachments.size(); i++) {
+ h = hash_murmur3_one_32(p.resolve_attachments[i], h);
+ }
+
+ h = hash_murmur3_one_32(p.preserve_attachments.size(), h);
+ for (int i = 0; i < p.preserve_attachments.size(); i++) {
+ h = hash_murmur3_one_32(p.preserve_attachments[i], h);
+ }
+
+ return h;
+ }
+
+ static _FORCE_INLINE_ bool _compare_pass(const RD::FramebufferPass &a, const RD::FramebufferPass &b) {
+ if (a.depth_attachment != b.depth_attachment) {
+ return false;
+ }
+
+ if (a.vrs_attachment != b.vrs_attachment) {
+ return false;
+ }
+
+ if (a.color_attachments.size() != b.color_attachments.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < a.color_attachments.size(); i++) {
+ if (a.color_attachments[i] != b.color_attachments[i]) {
+ return false;
+ }
+ }
+
+ if (a.resolve_attachments.size() != b.resolve_attachments.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < a.resolve_attachments.size(); i++) {
+ if (a.resolve_attachments[i] != b.resolve_attachments[i]) {
+ return false;
+ }
+ }
+
+ if (a.preserve_attachments.size() != b.preserve_attachments.size()) {
+ return false;
+ }
+
+ for (int i = 0; i < a.preserve_attachments.size(); i++) {
+ if (a.preserve_attachments[i] != b.preserve_attachments[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ _FORCE_INLINE_ uint32_t _hash_rids(uint32_t h, const RID &arg) {
+ return hash_murmur3_one_64(arg.get_id(), h);
+ }
+
+ template <typename... Args>
+ uint32_t _hash_rids(uint32_t h, const RID &arg, Args... args) {
+ h = hash_murmur3_one_64(arg.get_id(), h);
+ return _hash_rids(h, args...);
+ }
+
+ _FORCE_INLINE_ bool _compare_args(uint32_t idx, const LocalVector<RID> &textures, const RID &arg) {
+ return textures[idx] == arg;
+ }
+
+ template <typename... Args>
+ _FORCE_INLINE_ bool _compare_args(uint32_t idx, const LocalVector<RID> &textures, const RID &arg, Args... args) {
+ if (textures[idx] != arg) {
+ return false;
+ }
+ return _compare_args(idx + 1, textures, args...);
+ }
+
+ _FORCE_INLINE_ void _create_args(Vector<RID> &textures, const RID &arg) {
+ textures.push_back(arg);
+ }
+
+ template <typename... Args>
+ _FORCE_INLINE_ void _create_args(Vector<RID> &textures, const RID &arg, Args... args) {
+ textures.push_back(arg);
+ _create_args(textures, args...);
+ }
+
+ static FramebufferCacheRD *singleton;
+
+ uint32_t cache_instances_used = 0;
+
+ void _invalidate(Cache *p_cache);
+ static void _framebuffer_invalidation_callback(void *p_userdata);
+
+ RID _allocate_from_data(uint32_t p_views, uint32_t p_hash, uint32_t p_table_idx, const Vector<RID> &p_textures, const Vector<RD::FramebufferPass> &p_passes) {
+ RID rid;
+ if (p_passes.size()) {
+ rid = RD::get_singleton()->framebuffer_create_multipass(p_textures, p_passes, RD::INVALID_ID, p_views);
+ } else {
+ rid = RD::get_singleton()->framebuffer_create(p_textures, RD::INVALID_ID, p_views);
+ }
+
+ ERR_FAIL_COND_V(rid.is_null(), rid);
+
+ Cache *c = cache_allocator.alloc();
+ c->views = p_views;
+ c->cache = rid;
+ c->hash = p_hash;
+ c->textures.resize(p_textures.size());
+ for (uint32_t i = 0; i < c->textures.size(); i++) {
+ c->textures[i] = p_textures[i];
+ }
+ c->passes.resize(p_passes.size());
+ for (uint32_t i = 0; i < c->passes.size(); i++) {
+ c->passes[i] = p_passes[i];
+ }
+ c->prev = nullptr;
+ c->next = hash_table[p_table_idx];
+ if (hash_table[p_table_idx]) {
+ hash_table[p_table_idx]->prev = c;
+ }
+ hash_table[p_table_idx] = c;
+
+ RD::get_singleton()->framebuffer_set_invalidation_callback(rid, _framebuffer_invalidation_callback, c);
+
+ cache_instances_used++;
+
+ return rid;
+ }
+
+public:
+ template <typename... Args>
+ RID get_cache(Args... args) {
+ uint32_t h = hash_murmur3_one_32(1); //1 view
+ h = hash_murmur3_one_32(sizeof...(Args), h);
+ h = _hash_args(h, args...);
+ h = hash_murmur3_one_32(0, h); // 0 passes
+ h = hash_fmix32(h);
+
+ uint32_t table_idx = h % HASH_TABLE_SIZE;
+ {
+ const Cache *c = hash_table[table_idx];
+
+ while (c) {
+ if (c->hash == h && c->passes.size() == 0 && c->textures.size() == sizeof...(Args) && c->views == 1 && _compare_args(0, c->textures, args...)) {
+ return c->cache;
+ }
+ c = c->next;
+ }
+ }
+
+ // Not in cache, create:
+
+ Vector<RID> textures;
+ _create_args(textures, args...);
+
+ return _allocate_from_data(1, h, table_idx, textures, Vector<RD::FramebufferPass>());
+ }
+
+ template <typename... Args>
+ RID get_cache_multiview(uint32_t p_views, Args... args) {
+ uint32_t h = hash_murmur3_one_32(p_views);
+ h = hash_murmur3_one_32(sizeof...(Args), h);
+ h = _hash_args(h, args...);
+ h = hash_murmur3_one_32(0, h); // 0 passes
+ h = hash_fmix32(h);
+
+ uint32_t table_idx = h % HASH_TABLE_SIZE;
+ {
+ const Cache *c = hash_table[table_idx];
+
+ while (c) {
+ if (c->hash == h && c->passes.size() == 0 && c->textures.size() == sizeof...(Args) && c->views == p_views && _compare_args(0, c->textures, args...)) {
+ return c->cache;
+ }
+ c = c->next;
+ }
+ }
+
+ // Not in cache, create:
+
+ Vector<RID> textures;
+ _create_args(textures, args...);
+
+ return _allocate_from_data(p_views, h, table_idx, textures, Vector<RD::FramebufferPass>());
+ }
+
+ RID get_cache_multipass(const Vector<RID> &p_textures, const Vector<RD::FramebufferPass> &p_passes, uint32_t p_views = 1) {
+ uint32_t h = hash_murmur3_one_32(p_views);
+ h = hash_murmur3_one_32(p_textures.size());
+ for (int i = 0; i < p_textures.size(); i++) {
+ h = hash_murmur3_one_64(p_textures[i].get_id(), h);
+ }
+ h = hash_murmur3_one_32(p_passes.size());
+ for (int i = 0; i < p_passes.size(); i++) {
+ h = _hash_pass(p_passes[i], h);
+ }
+
+ h = hash_fmix32(h);
+
+ uint32_t table_idx = h % HASH_TABLE_SIZE;
+ {
+ const Cache *c = hash_table[table_idx];
+
+ while (c) {
+ if (c->hash == h && c->views == p_views && c->textures.size() == (uint32_t)p_textures.size() && c->passes.size() == (uint32_t)p_passes.size()) {
+ bool all_ok = true;
+
+ for (int i = 0; i < p_textures.size(); i++) {
+ if (p_textures[i] != c->textures[i]) {
+ all_ok = false;
+ break;
+ }
+ }
+
+ if (all_ok) {
+ for (int i = 0; i < p_passes.size(); i++) {
+ if (!_compare_pass(p_passes[i], c->passes[i])) {
+ all_ok = false;
+ break;
+ }
+ }
+ }
+
+ if (all_ok) {
+ return c->cache;
+ }
+ }
+ c = c->next;
+ }
+ }
+
+ // Not in cache, create:
+ return _allocate_from_data(p_views, h, table_idx, p_textures, p_passes);
+ }
+
+ static FramebufferCacheRD *get_singleton() { return singleton; }
+
+ FramebufferCacheRD();
+ ~FramebufferCacheRD();
+};
+
+#endif // FRAMEBUFFER_CACHE_RD_H
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 0b59ca6931..7102f1f0ff 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -192,7 +192,7 @@ RendererCanvasRender::PolygonID RendererCanvasRenderRD::request_polygon(const Ve
vd.stride = 0;
descriptions.write[1] = vd;
- buffers.write[1] = mesh_storage->mesh_get_default_rd_buffer(RendererRD::DEFAULT_RD_BUFFER_COLOR);
+ buffers.write[1] = mesh_storage->mesh_get_default_rd_buffer(RendererRD::MeshStorage::DEFAULT_RD_BUFFER_COLOR);
}
//uvs
@@ -220,7 +220,7 @@ RendererCanvasRender::PolygonID RendererCanvasRenderRD::request_polygon(const Ve
vd.stride = 0;
descriptions.write[2] = vd;
- buffers.write[2] = mesh_storage->mesh_get_default_rd_buffer(RendererRD::DEFAULT_RD_BUFFER_TEX_UV);
+ buffers.write[2] = mesh_storage->mesh_get_default_rd_buffer(RendererRD::MeshStorage::DEFAULT_RD_BUFFER_TEX_UV);
}
//bones
@@ -253,7 +253,7 @@ RendererCanvasRender::PolygonID RendererCanvasRenderRD::request_polygon(const Ve
vd.stride = 0;
descriptions.write[3] = vd;
- buffers.write[3] = mesh_storage->mesh_get_default_rd_buffer(RendererRD::DEFAULT_RD_BUFFER_BONES);
+ buffers.write[3] = mesh_storage->mesh_get_default_rd_buffer(RendererRD::MeshStorage::DEFAULT_RD_BUFFER_BONES);
}
//weights
@@ -286,7 +286,7 @@ RendererCanvasRender::PolygonID RendererCanvasRenderRD::request_polygon(const Ve
vd.stride = 0;
descriptions.write[4] = vd;
- buffers.write[4] = mesh_storage->mesh_get_default_rd_buffer(RendererRD::DEFAULT_RD_BUFFER_WEIGHTS);
+ buffers.write[4] = mesh_storage->mesh_get_default_rd_buffer(RendererRD::MeshStorage::DEFAULT_RD_BUFFER_WEIGHTS);
}
//check that everything is as it should be
@@ -494,7 +494,11 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
}
//bind pipeline
- {
+ if (rect->flags & CANVAS_RECT_LCD) {
+ RID pipeline = pipeline_variants->variants[light_mode][PIPELINE_VARIANT_QUAD_LCD_BLEND].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format);
+ RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
+ RD::get_singleton()->draw_list_set_blend_constants(p_draw_list, rect->modulate);
+ } else {
RID pipeline = pipeline_variants->variants[light_mode][PIPELINE_VARIANT_QUAD].get_render_pipeline(RD::INVALID_ID, p_framebuffer_format);
RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
}
@@ -556,6 +560,8 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
push_constant.msdf[1] = rect->outline; // Outline size.
push_constant.msdf[2] = 0.f; // Reserved.
push_constant.msdf[3] = 0.f; // Reserved.
+ } else if (rect->flags & CANVAS_RECT_LCD) {
+ push_constant.flags |= FLAGS_USE_LCD;
}
push_constant.modulation[0] = rect->modulate.r * base_color.r;
@@ -988,7 +994,7 @@ RID RendererCanvasRenderRD::_create_base_uniform_set(RID p_to_render_target, boo
} else {
screen = texture_storage->render_target_get_rd_backbuffer(p_to_render_target);
if (screen.is_null()) { //unallocated backbuffer
- screen = RendererRD::TextureStorage::get_singleton()->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE);
+ screen = RendererRD::TextureStorage::get_singleton()->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_WHITE);
}
}
u.append_id(screen);
@@ -1115,7 +1121,7 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co
if (material != prev_material) {
CanvasMaterialData *material_data = nullptr;
if (material.is_valid()) {
- material_data = static_cast<CanvasMaterialData *>(material_storage->material_get_data(material, RendererRD::SHADER_TYPE_2D));
+ material_data = static_cast<CanvasMaterialData *>(material_storage->material_get_data(material, RendererRD::MaterialStorage::SHADER_TYPE_2D));
}
if (material_data) {
@@ -1361,6 +1367,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
Item *ci = p_item_list;
Rect2 back_buffer_rect;
bool backbuffer_copy = false;
+ bool backbuffer_gen_mipmaps = false;
Item *canvas_group_owner = nullptr;
@@ -1383,12 +1390,13 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
RID material = ci->material_owner == nullptr ? ci->material : ci->material_owner->material;
if (material.is_valid()) {
- CanvasMaterialData *md = static_cast<CanvasMaterialData *>(material_storage->material_get_data(material, RendererRD::SHADER_TYPE_2D));
+ CanvasMaterialData *md = static_cast<CanvasMaterialData *>(material_storage->material_get_data(material, RendererRD::MaterialStorage::SHADER_TYPE_2D));
if (md && md->shader_data->valid) {
if (md->shader_data->uses_screen_texture && canvas_group_owner == nullptr) {
if (!material_screen_texture_found) {
backbuffer_copy = true;
back_buffer_rect = Rect2();
+ backbuffer_gen_mipmaps = md->shader_data->uses_screen_texture_mipmaps;
}
}
@@ -1474,9 +1482,10 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
item_count = 0;
- texture_storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect, true);
+ texture_storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect, backbuffer_gen_mipmaps);
backbuffer_copy = false;
+ backbuffer_gen_mipmaps = false;
material_screen_texture_found = true; //after a backbuffer copy, screen texture makes no further copies
}
@@ -1591,7 +1600,7 @@ void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index,
real_t farp = p_far;
real_t aspect = 1.0;
- real_t ymax = nearp * Math::tan(Math::deg2rad(fov * 0.5));
+ real_t ymax = nearp * Math::tan(Math::deg_to_rad(fov * 0.5));
real_t ymin = -ymax;
real_t xmin = ymin * aspect;
real_t xmax = ymax * aspect;
@@ -1956,8 +1965,8 @@ void RendererCanvasRenderRD::occluder_polygon_set_shape(RID p_occluder, const Ve
} else {
//update existing
- RD::get_singleton()->buffer_update(oc->vertex_buffer, 0, sizeof(real_t) * 2 * p_points.size(), p_points.ptr());
- RD::get_singleton()->buffer_update(oc->index_buffer, 0, sdf_indices.size() * sizeof(int32_t), sdf_indices.ptr());
+ RD::get_singleton()->buffer_update(oc->sdf_vertex_buffer, 0, sizeof(real_t) * 2 * p_points.size(), p_points.ptr());
+ RD::get_singleton()->buffer_update(oc->sdf_index_buffer, 0, sdf_indices.size() * sizeof(int32_t), sdf_indices.ptr());
}
}
}
@@ -1980,6 +1989,7 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) {
ubo_size = 0;
uniforms.clear();
uses_screen_texture = false;
+ uses_screen_texture_mipmaps = false;
uses_sdf = false;
uses_time = false;
@@ -1990,7 +2000,6 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) {
ShaderCompiler::GeneratedCode gen_code;
int blend_mode = BLEND_MODE_MIX;
- uses_screen_texture = false;
ShaderCompiler::IdentifierActions actions;
actions.entry_point_stages["vertex"] = ShaderCompiler::STAGE_VERTEX;
@@ -2015,6 +2024,8 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) {
Error err = canvas_singleton->shader.compiler.compile(RS::SHADER_CANVAS_ITEM, code, &actions, path, gen_code);
ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
+ uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
+
if (version.is_null()) {
version = canvas_singleton->shader.canvas_shader.version_create();
}
@@ -2025,12 +2036,16 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) {
for (int i = 0; i < gen_code.defines.size(); i++) {
print_line(gen_code.defines[i]);
}
+
+ HashMap<String, String>::Iterator el = gen_code.code.begin();
+ while (el) {
+ print_line("\n**code " + el->key + ":\n" + el->value);
+ ++el;
+ }
+
print_line("\n**uniforms:\n" + gen_code.uniforms);
- print_line("\n**vertex_globals:\n" + gen_code.vertex_global);
- print_line("\n**vertex_code:\n" + gen_code.vertex);
- print_line("\n**fragment_globals:\n" + gen_code.fragment_global);
- print_line("\n**fragment_code:\n" + gen_code.fragment);
- print_line("\n**light_code:\n" + gen_code.light);
+ print_line("\n**vertex_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX]);
+ print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
#endif
canvas_singleton->shader.canvas_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines);
ERR_FAIL_COND(!canvas_singleton->shader.canvas_shader.version_is_valid(version));
@@ -2104,6 +2119,18 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) {
RD::PipelineColorBlendState blend_state;
blend_state.attachments.push_back(attachment);
+ RD::PipelineColorBlendState::Attachment attachment_lcd;
+ attachment_lcd.enable_blend = true;
+ attachment_lcd.alpha_blend_op = RD::BLEND_OP_ADD;
+ attachment_lcd.color_blend_op = RD::BLEND_OP_ADD;
+ attachment_lcd.src_color_blend_factor = RD::BLEND_FACTOR_CONSTANT_COLOR;
+ attachment_lcd.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
+ attachment_lcd.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ attachment_lcd.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+
+ RD::PipelineColorBlendState blend_state_lcd;
+ blend_state_lcd.attachments.push_back(attachment_lcd);
+
//update pipelines
for (int i = 0; i < PIPELINE_LIGHT_MODE_MAX; i++) {
@@ -2119,10 +2146,12 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) {
RD::RENDER_PRIMITIVE_LINES,
RD::RENDER_PRIMITIVE_LINESTRIPS,
RD::RENDER_PRIMITIVE_POINTS,
+ RD::RENDER_PRIMITIVE_TRIANGLES,
};
ShaderVariant shader_variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX] = {
- { //non lit
+ {
+ //non lit
SHADER_VARIANT_QUAD,
SHADER_VARIANT_NINEPATCH,
SHADER_VARIANT_PRIMITIVE,
@@ -2132,8 +2161,11 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) {
SHADER_VARIANT_ATTRIBUTES,
SHADER_VARIANT_ATTRIBUTES,
SHADER_VARIANT_ATTRIBUTES,
- SHADER_VARIANT_ATTRIBUTES_POINTS },
- { //lit
+ SHADER_VARIANT_ATTRIBUTES_POINTS,
+ SHADER_VARIANT_QUAD,
+ },
+ {
+ //lit
SHADER_VARIANT_QUAD_LIGHT,
SHADER_VARIANT_NINEPATCH_LIGHT,
SHADER_VARIANT_PRIMITIVE_LIGHT,
@@ -2143,11 +2175,17 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) {
SHADER_VARIANT_ATTRIBUTES_LIGHT,
SHADER_VARIANT_ATTRIBUTES_LIGHT,
SHADER_VARIANT_ATTRIBUTES_LIGHT,
- SHADER_VARIANT_ATTRIBUTES_POINTS_LIGHT },
+ SHADER_VARIANT_ATTRIBUTES_POINTS_LIGHT,
+ SHADER_VARIANT_QUAD_LIGHT,
+ },
};
RID shader_variant = canvas_singleton->shader.canvas_shader.version_get_shader(version, shader_variants[i][j]);
- pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0);
+ if (j == PIPELINE_VARIANT_QUAD_LCD_BLEND) {
+ pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state_lcd, RD::DYNAMIC_STATE_BLEND_CONSTANTS);
+ } else {
+ pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0);
+ }
}
}
@@ -2171,11 +2209,15 @@ void RendererCanvasRenderRD::CanvasShaderData::set_default_texture_param(const S
}
}
-void RendererCanvasRenderRD::CanvasShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+void RendererCanvasRenderRD::CanvasShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
HashMap<int, StringName> order;
for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
- if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL ||
+ E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE ||
+ E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE ||
+ E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
+ // Don't expose any of these.
continue;
}
if (E.value.texture_order >= 0) {
@@ -2261,7 +2303,7 @@ RendererCanvasRenderRD::CanvasShaderData::~CanvasShaderData() {
}
}
-RendererRD::ShaderData *RendererCanvasRenderRD::_create_shader_func() {
+RendererRD::MaterialStorage::ShaderData *RendererCanvasRenderRD::_create_shader_func() {
CanvasShaderData *shader_data = memnew(CanvasShaderData);
return shader_data;
}
@@ -2276,7 +2318,7 @@ RendererCanvasRenderRD::CanvasMaterialData::~CanvasMaterialData() {
free_parameters_uniform_set(uniform_set);
}
-RendererRD::MaterialData *RendererCanvasRenderRD::_create_material_func(CanvasShaderData *p_shader) {
+RendererRD::MaterialStorage::MaterialData *RendererCanvasRenderRD::_create_material_func(CanvasShaderData *p_shader) {
CanvasMaterialData *material_data = memnew(CanvasMaterialData);
material_data->shader_data = p_shader;
//update will happen later anyway so do nothing.
@@ -2350,6 +2392,18 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
blend_state.attachments.push_back(blend_attachment);
+ RD::PipelineColorBlendState::Attachment attachment_lcd;
+ attachment_lcd.enable_blend = true;
+ attachment_lcd.alpha_blend_op = RD::BLEND_OP_ADD;
+ attachment_lcd.color_blend_op = RD::BLEND_OP_ADD;
+ attachment_lcd.src_color_blend_factor = RD::BLEND_FACTOR_CONSTANT_COLOR;
+ attachment_lcd.dst_color_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
+ attachment_lcd.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+ attachment_lcd.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
+
+ RD::PipelineColorBlendState blend_state_lcd;
+ blend_state_lcd.attachments.push_back(attachment_lcd);
+
for (int i = 0; i < PIPELINE_LIGHT_MODE_MAX; i++) {
for (int j = 0; j < PIPELINE_VARIANT_MAX; j++) {
RD::RenderPrimitive primitive[PIPELINE_VARIANT_MAX] = {
@@ -2363,10 +2417,12 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
RD::RENDER_PRIMITIVE_LINES,
RD::RENDER_PRIMITIVE_LINESTRIPS,
RD::RENDER_PRIMITIVE_POINTS,
+ RD::RENDER_PRIMITIVE_TRIANGLES,
};
ShaderVariant shader_variants[PIPELINE_LIGHT_MODE_MAX][PIPELINE_VARIANT_MAX] = {
- { //non lit
+ {
+ //non lit
SHADER_VARIANT_QUAD,
SHADER_VARIANT_NINEPATCH,
SHADER_VARIANT_PRIMITIVE,
@@ -2376,8 +2432,11 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
SHADER_VARIANT_ATTRIBUTES,
SHADER_VARIANT_ATTRIBUTES,
SHADER_VARIANT_ATTRIBUTES,
- SHADER_VARIANT_ATTRIBUTES_POINTS },
- { //lit
+ SHADER_VARIANT_ATTRIBUTES_POINTS,
+ SHADER_VARIANT_QUAD,
+ },
+ {
+ //lit
SHADER_VARIANT_QUAD_LIGHT,
SHADER_VARIANT_NINEPATCH_LIGHT,
SHADER_VARIANT_PRIMITIVE_LIGHT,
@@ -2387,11 +2446,17 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
SHADER_VARIANT_ATTRIBUTES_LIGHT,
SHADER_VARIANT_ATTRIBUTES_LIGHT,
SHADER_VARIANT_ATTRIBUTES_LIGHT,
- SHADER_VARIANT_ATTRIBUTES_POINTS_LIGHT },
+ SHADER_VARIANT_ATTRIBUTES_POINTS_LIGHT,
+ SHADER_VARIANT_QUAD_LIGHT,
+ },
};
RID shader_variant = shader.canvas_shader.version_get_shader(shader.default_version, shader_variants[i][j]);
- shader.pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0);
+ if (j == PIPELINE_VARIANT_QUAD_LCD_BLEND) {
+ shader.pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state_lcd, RD::DYNAMIC_STATE_BLEND_CONSTANTS);
+ } else {
+ shader.pipeline_variants.variants[i][j].setup(shader_variant, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0);
+ }
}
}
}
@@ -2629,8 +2694,8 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
state.shadow_texture_size = GLOBAL_GET("rendering/2d/shadow_atlas/size");
//create functions for shader and material
- material_storage->shader_set_data_request_function(RendererRD::SHADER_TYPE_2D, _create_shader_funcs);
- material_storage->material_set_data_request_function(RendererRD::SHADER_TYPE_2D, _create_material_funcs);
+ material_storage->shader_set_data_request_function(RendererRD::MaterialStorage::SHADER_TYPE_2D, _create_shader_funcs);
+ material_storage->material_set_data_request_function(RendererRD::MaterialStorage::SHADER_TYPE_2D, _create_material_funcs);
state.time = 0;
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
index 1c0567b677..54077a5b9a 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
@@ -85,6 +85,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
FLAGS_DEFAULT_SPECULAR_MAP_USED = (1 << 27),
FLAGS_USE_MSDF = (1 << 28),
+ FLAGS_USE_LCD = (1 << 29),
};
enum {
@@ -122,6 +123,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
PIPELINE_VARIANT_ATTRIBUTE_LINES,
PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP,
PIPELINE_VARIANT_ATTRIBUTE_POINTS,
+ PIPELINE_VARIANT_QUAD_LCD_BLEND,
PIPELINE_VARIANT_MAX
};
enum PipelineLightMode {
@@ -149,7 +151,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
ShaderCompiler compiler;
} shader;
- struct CanvasShaderData : public RendererRD::ShaderData {
+ struct CanvasShaderData : public RendererRD::MaterialStorage::ShaderData {
enum BlendMode { //used internally
BLEND_MODE_MIX,
BLEND_MODE_ADD,
@@ -174,13 +176,14 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
HashMap<StringName, HashMap<int, RID>> default_texture_params;
bool uses_screen_texture = false;
+ bool uses_screen_texture_mipmaps = false;
bool uses_sdf = false;
bool uses_time = false;
virtual void set_code(const String &p_Code);
virtual void set_path_hint(const String &p_path);
virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
- virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
virtual bool is_param_texture(const StringName &p_param) const;
@@ -193,12 +196,12 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
virtual ~CanvasShaderData();
};
- RendererRD::ShaderData *_create_shader_func();
- static RendererRD::ShaderData *_create_shader_funcs() {
+ RendererRD::MaterialStorage::ShaderData *_create_shader_func();
+ static RendererRD::MaterialStorage::ShaderData *_create_shader_funcs() {
return static_cast<RendererCanvasRenderRD *>(singleton)->_create_shader_func();
}
- struct CanvasMaterialData : public RendererRD::MaterialData {
+ struct CanvasMaterialData : public RendererRD::MaterialStorage::MaterialData {
CanvasShaderData *shader_data = nullptr;
RID uniform_set;
@@ -208,8 +211,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
virtual ~CanvasMaterialData();
};
- RendererRD::MaterialData *_create_material_func(CanvasShaderData *p_shader);
- static RendererRD::MaterialData *_create_material_funcs(RendererRD::ShaderData *p_shader) {
+ RendererRD::MaterialStorage::MaterialData *_create_material_func(CanvasShaderData *p_shader);
+ static RendererRD::MaterialStorage::MaterialData *_create_material_funcs(RendererRD::MaterialStorage::ShaderData *p_shader) {
return static_cast<RendererCanvasRenderRD *>(singleton)->_create_material_func(static_cast<CanvasShaderData *>(p_shader));
}
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
index a61172c8f5..e7abcf5674 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
@@ -249,6 +249,7 @@ RendererCompositorRD *RendererCompositorRD::singleton = nullptr;
RendererCompositorRD::RendererCompositorRD() {
uniform_set_cache = memnew(UniformSetCacheRD);
+ framebuffer_cache = memnew(FramebufferCacheRD);
{
String shader_cache_dir = Engine::get_singleton()->get_shader_cache_path();
@@ -266,7 +267,7 @@ RendererCompositorRD::RendererCompositorRD() {
if (err != OK) {
ERR_PRINT("Can't create shader cache folder, no shader caching will happen: " + shader_cache_dir);
} else {
- shader_cache_dir = shader_cache_dir.plus_file("shader_cache");
+ shader_cache_dir = shader_cache_dir.path_join("shader_cache");
bool shader_cache_enabled = GLOBAL_GET("rendering/shader_compiler/shader_cache/enabled");
if (!Engine::get_singleton()->is_editor_hint() && !shader_cache_enabled) {
@@ -316,5 +317,6 @@ RendererCompositorRD::RendererCompositorRD() {
RendererCompositorRD::~RendererCompositorRD() {
memdelete(uniform_set_cache);
+ memdelete(framebuffer_cache);
ShaderRD::set_shader_cache_dir(String());
}
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h
index 564c26bfe4..a28335f800 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.h
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h
@@ -37,6 +37,7 @@
#include "servers/rendering/renderer_rd/environment/fog.h"
#include "servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h"
#include "servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h"
+#include "servers/rendering/renderer_rd/framebuffer_cache_rd.h"
#include "servers/rendering/renderer_rd/renderer_canvas_render_rd.h"
#include "servers/rendering/renderer_rd/shaders/blit.glsl.gen.h"
#include "servers/rendering/renderer_rd/storage_rd/light_storage.h"
@@ -50,6 +51,7 @@
class RendererCompositorRD : public RendererCompositor {
protected:
UniformSetCacheRD *uniform_set_cache = nullptr;
+ FramebufferCacheRD *framebuffer_cache = nullptr;
RendererCanvasRenderRD *canvas = nullptr;
RendererRD::Utilities *utilities = nullptr;
RendererRD::LightStorage *light_storage = nullptr;
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index cf231fa4ef..7adc36c57c 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -2007,7 +2007,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
tonemap.exposure_texture = rb->luminance.current;
tonemap.auto_exposure_grey = environment_get_auto_exp_scale(p_render_data->environment);
} else {
- tonemap.exposure_texture = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE);
+ tonemap.exposure_texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_WHITE);
}
if (can_use_effects && p_render_data->environment.is_valid() && environment_get_glow_enabled(p_render_data->environment)) {
@@ -2026,12 +2026,12 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
tonemap.glow_map = texture_storage->texture_get_rd_texture(environment_get_glow_map(p_render_data->environment));
} else {
tonemap.glow_map_strength = 0.0f;
- tonemap.glow_map = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE);
+ tonemap.glow_map = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_WHITE);
}
} else {
- tonemap.glow_texture = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_BLACK);
- tonemap.glow_map = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE);
+ tonemap.glow_texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
+ tonemap.glow_map = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_WHITE);
}
if (rb->screen_space_aa == RS::VIEWPORT_SCREEN_SPACE_AA_FXAA) {
@@ -2053,7 +2053,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
tonemap.use_color_correction = false;
tonemap.use_1d_color_correction = false;
- tonemap.color_correction_texture = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ tonemap.color_correction_texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
if (can_use_effects && p_render_data->environment.is_valid()) {
tonemap.use_bcs = environment_get_adjustments_enabled(p_render_data->environment);
@@ -2123,14 +2123,14 @@ void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_fr
}
tonemap.use_glow = false;
- tonemap.glow_texture = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_BLACK);
- tonemap.glow_map = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE);
+ tonemap.glow_texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
+ tonemap.glow_map = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_WHITE);
tonemap.use_auto_exposure = false;
- tonemap.exposure_texture = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_WHITE);
+ tonemap.exposure_texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_WHITE);
tonemap.use_color_correction = false;
tonemap.use_1d_color_correction = false;
- tonemap.color_correction_texture = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_3D_WHITE);
+ tonemap.color_correction_texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
if (can_use_effects && p_render_data->environment.is_valid()) {
tonemap.use_bcs = environment_get_adjustments_enabled(p_render_data->environment);
@@ -2174,7 +2174,7 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID
RID shadow_atlas_texture = shadow_atlas_get_texture(p_shadow_atlas);
if (shadow_atlas_texture.is_null()) {
- shadow_atlas_texture = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_BLACK);
+ shadow_atlas_texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
}
Size2 rtsize = texture_storage->render_target_get_size(rb->render_target);
@@ -2459,8 +2459,20 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
p_internal_width = p_width;
}
- const float texture_mipmap_bias = -log2f(p_width / p_internal_width) + p_texture_mipmap_bias;
- material_storage->sampler_rd_configure_custom(texture_mipmap_bias);
+ if (p_use_taa) {
+ // Use negative mipmap LOD bias when TAA is enabled to compensate for loss of sharpness.
+ // This restores sharpness in still images to be roughly at the same level as without TAA,
+ // but moving scenes will still be blurrier.
+ p_texture_mipmap_bias -= 0.5;
+ }
+
+ if (p_screen_space_aa == RS::VIEWPORT_SCREEN_SPACE_AA_FXAA) {
+ // Use negative mipmap LOD bias when FXAA is enabled to compensate for loss of sharpness.
+ // If both TAA and FXAA are enabled, combine their negative LOD biases together.
+ p_texture_mipmap_bias -= 0.25;
+ }
+
+ material_storage->sampler_rd_configure_custom(p_texture_mipmap_bias);
update_uniform_sets();
RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
@@ -2863,20 +2875,22 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
float size = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
- light_data.size = 1.0 - Math::cos(Math::deg2rad(size)); //angle to cosine offset
+ light_data.size = 1.0 - Math::cos(Math::deg_to_rad(size)); //angle to cosine offset
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_PSSM_SPLITS) {
WARN_PRINT_ONCE("The DirectionalLight3D PSSM splits debug draw mode is not reimplemented yet.");
}
- light_data.shadow_enabled = p_using_shadows && light_storage->light_has_shadow(base);
+ light_data.shadow_opacity = (p_using_shadows && light_storage->light_has_shadow(base))
+ ? light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_OPACITY)
+ : 0.0;
float angular_diameter = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE);
if (angular_diameter > 0.0) {
// I know tan(0) is 0, but let's not risk it with numerical precision.
// technically this will keep expanding until reaching the sun, but all we care
// is expand until we reach the radius of the near plane (there can't be more occluders than that)
- angular_diameter = Math::tan(Math::deg2rad(angular_diameter));
+ angular_diameter = Math::tan(Math::deg_to_rad(angular_diameter));
if (light_storage->light_has_shadow(base) && light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR) > 0.0) {
// Only enable PCSS-like soft shadows if blurring is enabled.
// Otherwise, performance would decrease with no visual difference.
@@ -2886,7 +2900,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
angular_diameter = 0.0;
}
- if (light_data.shadow_enabled) {
+ if (light_data.shadow_opacity > 0.001) {
RS::LightDirectionalShadowMode smode = light_storage->light_directional_get_shadow_mode(base);
int limit = smode == RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL ? 0 : (smode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS ? 1 : 3);
@@ -3040,19 +3054,26 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
// Reuse fade begin, fade length and distance for shadow LOD determination later.
float fade_begin = 0.0;
+ float fade_shadow = 0.0;
float fade_length = 0.0;
real_t distance = 0.0;
float fade = 1.0;
+ float shadow_opacity_fade = 1.0;
if (light_storage->light_is_distance_fade_enabled(li->light)) {
fade_begin = light_storage->light_get_distance_fade_begin(li->light);
+ fade_shadow = light_storage->light_get_distance_fade_shadow(li->light);
fade_length = light_storage->light_get_distance_fade_length(li->light);
distance = camera_plane.distance_to(li->transform.origin);
+ // Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player.
if (distance > fade_begin) {
- // Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player.
fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - fade_begin) / fade_length);
}
+
+ if (distance > fade_shadow) {
+ shadow_opacity_fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - fade_shadow) / fade_length);
+ }
}
float energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI * fade;
@@ -3084,7 +3105,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
light_data.inv_spot_attenuation = 1.0f / light_storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ATTENUATION);
float spot_angle = light_storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ANGLE);
- light_data.cos_spot_angle = Math::cos(Math::deg2rad(spot_angle));
+ light_data.cos_spot_angle = Math::cos(Math::deg_to_rad(spot_angle));
light_data.mask = light_storage->light_get_cull_mask(base);
@@ -3116,11 +3137,15 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
light_data.projector_rect[3] = 0;
}
- const bool needs_shadow = shadow_atlas && shadow_atlas->shadow_owners.has(li->self);
+ const bool needs_shadow =
+ shadow_atlas &&
+ shadow_atlas->shadow_owners.has(li->self) &&
+ p_using_shadows &&
+ light_storage->light_has_shadow(base);
bool in_shadow_range = true;
if (needs_shadow && light_storage->light_is_distance_fade_enabled(li->light)) {
- if (distance > light_storage->light_get_distance_fade_shadow(li->light)) {
+ if (distance > light_storage->light_get_distance_fade_shadow(li->light) + light_storage->light_get_distance_fade_length(li->light)) {
// Out of range, don't draw shadows to improve performance.
in_shadow_range = false;
}
@@ -3129,7 +3154,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
if (needs_shadow && in_shadow_range) {
// fill in the shadow information
- light_data.shadow_enabled = true;
+ light_data.shadow_opacity = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_OPACITY) * shadow_opacity_fade;
float shadow_texel_size = light_instance_get_shadow_texel_size(li->self, p_shadow_atlas);
light_data.shadow_normal_bias = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size * 10.0;
@@ -3181,7 +3206,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
// Only enable PCSS-like soft shadows if blurring is enabled.
// Otherwise, performance would decrease with no visual difference.
Projection cm = li->shadow_transform[0].camera;
- float half_np = cm.get_z_near() * Math::tan(Math::deg2rad(spot_angle));
+ float half_np = cm.get_z_near() * Math::tan(Math::deg_to_rad(spot_angle));
light_data.soft_shadow_size = (size * 0.5 / radius) / (half_np / cm.get_z_near()) * rect.size.width;
} else {
light_data.soft_shadow_size = 0.0;
@@ -3189,7 +3214,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
}
}
} else {
- light_data.shadow_enabled = false;
+ light_data.shadow_opacity = 0.0;
}
li->cull_mask = light_storage->light_get_cull_mask(base);
@@ -3637,7 +3662,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
if (p_render_data->render_buffers.is_valid()) {
bool directional_shadows = false;
for (uint32_t i = 0; i < directional_light_count; i++) {
- if (cluster.directional_lights[i].shadow_enabled) {
+ if (cluster.directional_lights[i].shadow_opacity > 0.001) {
directional_shadows = true;
break;
}
@@ -4079,19 +4104,8 @@ bool RendererSceneRenderRD::free(RID p_rid) {
decal_instance_owner.free(p_rid);
} else if (lightmap_instance_owner.owns(p_rid)) {
lightmap_instance_owner.free(p_rid);
- } else if (gi.voxel_gi_instance_owner.owns(p_rid)) {
- RendererRD::GI::VoxelGIInstance *voxel_gi = gi.voxel_gi_instance_owner.get_or_null(p_rid);
- if (voxel_gi->texture.is_valid()) {
- RD::get_singleton()->free(voxel_gi->texture);
- RD::get_singleton()->free(voxel_gi->write_buffer);
- }
-
- for (int i = 0; i < voxel_gi->dynamic_maps.size(); i++) {
- RD::get_singleton()->free(voxel_gi->dynamic_maps[i].texture);
- RD::get_singleton()->free(voxel_gi->dynamic_maps[i].depth);
- }
-
- gi.voxel_gi_instance_owner.free(p_rid);
+ } else if (gi.voxel_gi_instance_owns(p_rid)) {
+ gi.voxel_gi_instance_free(p_rid);
} else if (sky.sky_owner.owns(p_rid)) {
sky.update_dirty_skys();
sky.free_sky(p_rid);
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index 09ec2a9efd..22e9ead243 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -608,7 +608,7 @@ private:
float inv_spot_attenuation;
float cos_spot_angle;
float specular_amount;
- uint32_t shadow_enabled;
+ float shadow_opacity;
float atlas_rect[4]; // in omni, used for atlas uv, in spot, used for projector uv
float shadow_matrix[16];
@@ -633,7 +633,7 @@ private:
float softshadow_angle;
float soft_shadow_scale;
uint32_t blend_splits;
- uint32_t shadow_enabled;
+ float shadow_opacity;
float fade_from;
float fade_to;
uint32_t pad[2];
diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp
index c9b6d09d4c..0f2dea6fe9 100644
--- a/servers/rendering/renderer_rd/shader_rd.cpp
+++ b/servers/rendering/renderer_rd/shader_rd.cpp
@@ -380,7 +380,7 @@ static const uint32_t cache_file_version = 2;
bool ShaderRD::_load_from_cache(Version *p_version) {
String sha1 = _version_get_sha1(p_version);
- String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache";
+ String path = shader_cache_dir.path_join(name).path_join(base_sha256).path_join(sha1) + ".cache";
Ref<FileAccess> f = FileAccess::open(path, FileAccess::READ);
if (f.is_null()) {
@@ -443,7 +443,7 @@ bool ShaderRD::_load_from_cache(Version *p_version) {
void ShaderRD::_save_to_cache(Version *p_version) {
String sha1 = _version_get_sha1(p_version);
- String path = shader_cache_dir.plus_file(name).plus_file(base_sha256).plus_file(sha1) + ".cache";
+ String path = shader_cache_dir.path_join(name).path_join(base_sha256).path_join(sha1) + ".cache";
Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE);
ERR_FAIL_COND(f.is_null());
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index f8e9020f9f..459d798a80 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -509,7 +509,13 @@ void main() {
float a = clamp(d * px_size + 0.5, 0.0, 1.0);
color.a = a * color.a;
}
-
+ } else if (bool(draw_data.flags & FLAGS_USE_LCD)) {
+ vec4 lcd_sample = texture(sampler2D(color_texture, texture_sampler), uv);
+ if (lcd_sample.a == 1.0) {
+ color.rgb = lcd_sample.rgb * color.a;
+ } else {
+ color = vec4(0.0, 0.0, 0.0, 0.0);
+ }
} else {
#else
{
diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
index 2ea6965c09..1b627a3e81 100644
--- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
@@ -25,6 +25,7 @@
#define FLAGS_DEFAULT_SPECULAR_MAP_USED (1 << 27)
#define FLAGS_USE_MSDF (1 << 28)
+#define FLAGS_USE_LCD (1 << 29)
#define SAMPLER_NEAREST_CLAMP 0
#define SAMPLER_LINEAR_CLAMP 1
diff --git a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl
index 0438671dd2..0b43af7738 100644
--- a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl
@@ -30,7 +30,7 @@ layout(set = 1, binding = 0) uniform sampler2D source_bokeh;
#ifdef MODE_GEN_BLUR_SIZE
float get_depth_at_pos(vec2 uv) {
- float depth = textureLod(source_depth, uv, 0.0).x;
+ float depth = textureLod(source_depth, uv, 0.0).x * 2.0 - 1.0;
if (params.orthogonal) {
depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0;
} else {
diff --git a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl
index a3b3938ee9..a06cacfabe 100644
--- a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl
@@ -52,7 +52,7 @@ layout(set = 2, binding = 0) uniform sampler2D original_weight;
#ifdef MODE_GEN_BLUR_SIZE
float get_depth_at_pos(vec2 uv) {
- float depth = textureLod(source_depth, uv, 0.0).x;
+ float depth = textureLod(source_depth, uv, 0.0).x * 2.0 - 1.0;
if (params.orthogonal) {
depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0;
} else {
diff --git a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
index d85ab3af2e..246ef81cb2 100644
--- a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
@@ -182,17 +182,18 @@ void main() {
if (found) {
float margin_blend = 1.0;
- vec2 margin = vec2((params.screen_size.x + params.screen_size.y) * 0.5 * 0.05); // make a uniform margin
- if (any(bvec4(lessThan(pos, -margin), greaterThan(pos, params.screen_size + margin)))) {
- // clip outside screen + margin
+ vec2 margin = vec2((params.screen_size.x + params.screen_size.y) * 0.05); // make a uniform margin
+ if (any(bvec4(lessThan(pos, vec2(0.0, 0.0)), greaterThan(pos, params.screen_size)))) {
+ // clip at the screen edges
imageStore(ssr_image, ssC, vec4(0.0));
return;
}
{
- //blend fading out towards external margin
- vec2 margin_grad = mix(pos - params.screen_size, -pos, lessThan(pos, vec2(0.0)));
- margin_blend = 1.0 - smoothstep(0.0, margin.x, max(margin_grad.x, margin_grad.y));
+ //blend fading out towards inner margin
+ // 0.5 = midpoint of reflection
+ vec2 margin_grad = mix(params.screen_size - pos, pos, lessThan(pos, params.screen_size * 0.5));
+ margin_blend = smoothstep(0.0, margin.x * margin.y, margin_grad.x * margin_grad.y);
//margin_blend = 1.0;
}
diff --git a/servers/rendering/renderer_rd/shaders/environment/sdfgi_debug.glsl b/servers/rendering/renderer_rd/shaders/environment/sdfgi_debug.glsl
index af5f7d0a58..9640d30e78 100644
--- a/servers/rendering/renderer_rd/shaders/environment/sdfgi_debug.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/sdfgi_debug.glsl
@@ -37,16 +37,14 @@ layout(push_constant, std430) uniform Params {
uint max_cascades;
ivec2 screen_size;
- bool use_occlusion;
float y_mult;
- int probe_axis_size;
float z_near;
- float reserved1;
- float reserved2;
- mat4 cam_transform;
- mat4 inv_projection;
+ mat3x4 inv_projection;
+ // We pack these more tightly than mat3 and vec3, which will require some reconstruction trickery.
+ float cam_basis[3][3];
+ float cam_origin[3];
}
params;
@@ -82,13 +80,21 @@ void main() {
vec3 ray_pos;
vec3 ray_dir;
{
- ray_pos = params.cam_transform[3].xyz;
+ ray_pos = vec3(params.cam_origin[0], params.cam_origin[1], params.cam_origin[2]);
ray_dir.xy = ((vec2(screen_pos) / vec2(params.screen_size)) * 2.0 - 1.0);
ray_dir.z = params.z_near;
- ray_dir = (params.inv_projection * vec4(ray_dir, 1.0)).xyz;
- ray_dir = normalize(mat3(params.cam_transform) * ray_dir);
+ ray_dir = (vec4(ray_dir, 1.0) * mat4(params.inv_projection)).xyz;
+
+ mat3 cam_basis;
+ {
+ vec3 c0 = vec3(params.cam_basis[0][0], params.cam_basis[0][1], params.cam_basis[0][2]);
+ vec3 c1 = vec3(params.cam_basis[1][0], params.cam_basis[1][1], params.cam_basis[1][2]);
+ vec3 c2 = vec3(params.cam_basis[2][0], params.cam_basis[2][1], params.cam_basis[2][2]);
+ cam_basis = mat3(c0, c1, c2);
+ }
+ ray_dir = normalize(cam_basis * ray_dir);
}
ray_pos.y *= params.y_mult;
diff --git a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
index e74cfad65c..6f79b9e771 100644
--- a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
@@ -377,7 +377,7 @@ void main() {
for (uint i = 0; i < params.directional_light_count; i++) {
vec3 shadow_attenuation = vec3(1.0);
- if (directional_lights.data[i].shadow_enabled) {
+ if (directional_lights.data[i].shadow_opacity > 0.001) {
float depth_z = -view_pos.z;
vec4 pssm_coord;
@@ -486,7 +486,7 @@ void main() {
vec3 light = omni_lights.data[light_index].color;
- if (omni_lights.data[light_index].shadow_enabled) {
+ if (omni_lights.data[light_index].shadow_opacity > 0.001) {
//has shadow
vec4 uv_rect = omni_lights.data[light_index].atlas_rect;
vec2 flip_offset = omni_lights.data[light_index].direction.xy;
@@ -572,7 +572,7 @@ void main() {
vec3 light = spot_lights.data[light_index].color;
- if (spot_lights.data[light_index].shadow_enabled) {
+ if (spot_lights.data[light_index].shadow_opacity > 0.001) {
//has shadow
vec4 uv_rect = spot_lights.data[light_index].atlas_rect;
vec2 flip_offset = spot_lights.data[light_index].direction.xy;
diff --git a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
index 61c8488a05..799f7087b6 100644
--- a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
@@ -15,7 +15,7 @@ struct LightData { //this structure needs to be as packed as possible
mediump float cone_attenuation;
mediump float cone_angle;
mediump float specular_amount;
- bool shadow_enabled;
+ mediump float shadow_opacity;
highp vec4 atlas_rect; // rect in the shadow atlas
highp mat4 shadow_matrix;
@@ -60,7 +60,7 @@ struct DirectionalLightData {
highp float softshadow_angle;
highp float soft_shadow_scale;
bool blend_splits;
- bool shadow_enabled;
+ mediump float shadow_opacity;
highp float fade_from;
highp float fade_to;
uvec2 pad;
diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl
index 4369bddc83..fb5759bc17 100644
--- a/servers/rendering/renderer_rd/shaders/particles.glsl
+++ b/servers/rendering/renderer_rd/shaders/particles.glsl
@@ -458,11 +458,11 @@ void main() {
} break;
case ATTRACTOR_TYPE_VECTOR_FIELD: {
- vec3 uvw_pos = (local_pos / FRAME.attractors[i].extents) * 2.0 - 1.0;
+ vec3 uvw_pos = (local_pos / FRAME.attractors[i].extents + 1.0) * 0.5;
if (any(lessThan(uvw_pos, vec3(0.0))) || any(greaterThan(uvw_pos, vec3(1.0)))) {
continue;
}
- vec3 s = texture(sampler3D(sdf_vec_textures[FRAME.attractors[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).xyz;
+ vec3 s = texture(sampler3D(sdf_vec_textures[FRAME.attractors[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos).xyz * 2.0 - 1.0;
dir = mat3(FRAME.attractors[i].transform) * safe_normalize(s); //revert direction
amount = length(s);
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
index 360ece7f32..6b4e4a5a16 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
@@ -15,11 +15,11 @@ layout(location = 0) in vec3 vertex_attrib;
//only for pure render depth when normal is not used
#ifdef NORMAL_USED
-layout(location = 1) in vec3 normal_attrib;
+layout(location = 1) in vec2 normal_attrib;
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-layout(location = 2) in vec4 tangent_attrib;
+layout(location = 2) in vec2 tangent_attrib;
#endif
#if defined(COLOR_USED)
@@ -58,6 +58,13 @@ layout(location = 10) in uvec4 bone_attrib;
layout(location = 11) in vec4 weight_attrib;
#endif
+vec3 oct_to_vec3(vec2 e) {
+ vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));
+ float t = max(-v.z, 0.0);
+ v.xy += t * -sign(v.xy);
+ return v;
+}
+
/* Varyings */
layout(location = 0) out vec3 vertex_interp;
@@ -231,12 +238,13 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in SceneData sc
vec3 vertex = vertex_attrib;
#ifdef NORMAL_USED
- vec3 normal = normal_attrib * 2.0 - 1.0;
+ vec3 normal = oct_to_vec3(normal_attrib * 2.0 - 1.0);
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
- vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0;
- float binormalf = tangent_attrib.a * 2.0 - 1.0;
+ vec2 signed_tangent_attrib = tangent_attrib * 2.0 - 1.0;
+ vec3 tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0));
+ float binormalf = sign(signed_tangent_attrib.y);
vec3 binormal = normalize(cross(normal, tangent) * binormalf);
#endif
@@ -988,8 +996,10 @@ void fragment_shader(in SceneData scene_data) {
vec3 anisotropic_normal = cross(anisotropic_tangent, anisotropic_direction);
vec3 bent_normal = normalize(mix(normal, anisotropic_normal, abs(anisotropy) * clamp(5.0 * roughness, 0.0, 1.0)));
vec3 ref_vec = reflect(-view, bent_normal);
+ ref_vec = mix(ref_vec, bent_normal, roughness * roughness);
#else
vec3 ref_vec = reflect(-view, normal);
+ ref_vec = mix(ref_vec, normal, roughness * roughness);
#endif
float horizon = min(1.0 + dot(ref_vec, normal), 1.0);
@@ -1046,6 +1056,7 @@ void fragment_shader(in SceneData scene_data) {
ambient_light *= attenuation;
specular_light *= attenuation;
+ ref_vec = mix(ref_vec, n, clearcoat_roughness * clearcoat_roughness);
float horizon = min(1.0 + dot(ref_vec, normal), 1.0);
ref_vec = scene_data.radiance_inverse_xform * ref_vec;
float roughness_lod = mix(0.001, 0.1, clearcoat_roughness) * MAX_ROUGHNESS_LOD;
@@ -1203,6 +1214,7 @@ void fragment_shader(in SceneData scene_data) {
uint index1 = instances.data[instance_index].gi_offset & 0xFFFF;
vec3 ref_vec = normalize(reflect(-view, normal));
+ ref_vec = mix(ref_vec, normal, roughness * roughness);
//find arbitrary tangent and bitangent, then build a matrix
vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
vec3 tangent = normalize(cross(v0, normal));
@@ -1302,6 +1314,18 @@ void fragment_shader(in SceneData scene_data) {
item_to = subgroupBroadcastFirst(subgroupMax(item_to));
#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ // https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy
+ vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent;
+ vec3 anisotropic_tangent = cross(anisotropic_direction, view);
+ vec3 anisotropic_normal = cross(anisotropic_tangent, anisotropic_direction);
+ vec3 bent_normal = normalize(mix(normal, anisotropic_normal, abs(anisotropy) * clamp(5.0 * roughness, 0.0, 1.0)));
+#else
+ vec3 bent_normal = normal;
+#endif
+ vec3 ref_vec = normalize(reflect(-view, bent_normal));
+ ref_vec = mix(ref_vec, bent_normal, roughness * roughness);
+
for (uint i = item_from; i < item_to; i++) {
uint mask = cluster_buffer.data[cluster_reflection_offset + i];
mask &= cluster_get_range_clip_mask(i, item_min, item_max);
@@ -1324,16 +1348,8 @@ void fragment_shader(in SceneData scene_data) {
if (!bool(reflections.data[reflection_index].mask & instances.data[instance_index].layer_mask)) {
continue; //not masked
}
-#ifdef LIGHT_ANISOTROPY_USED
- // https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy
- vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent;
- vec3 anisotropic_tangent = cross(anisotropic_direction, view);
- vec3 anisotropic_normal = cross(anisotropic_tangent, anisotropic_direction);
- vec3 bent_normal = normalize(mix(normal, anisotropic_normal, abs(anisotropy) * clamp(5.0 * roughness, 0.0, 1.0)));
-#else
- vec3 bent_normal = normal;
-#endif
- reflection_process(reflection_index, view, vertex, bent_normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum);
+
+ reflection_process(reflection_index, vertex, ref_vec, normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum);
}
}
@@ -1381,7 +1397,7 @@ void fragment_shader(in SceneData scene_data) {
float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y;
vec2 env = vec2(-1.04, 1.04) * a004 + r.zw;
- specular_light *= env.x * f0 + env.y;
+ specular_light *= env.x * f0 + env.y * clamp(50.0 * f0.g, 0.0, 1.0);
#endif
}
@@ -1417,7 +1433,7 @@ void fragment_shader(in SceneData scene_data) {
float shadow = 1.0;
- if (directional_lights.data[i].shadow_enabled) {
+ if (directional_lights.data[i].shadow_opacity > 0.001) {
float depth_z = -vertex.z;
vec3 light_dir = directional_lights.data[i].direction;
vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp))));
@@ -1626,7 +1642,7 @@ void fragment_shader(in SceneData scene_data) {
#ifdef LIGHT_TRANSMITTANCE_USED
float transmittance_z = transmittance_depth;
- if (directional_lights.data[i].shadow_enabled) {
+ if (directional_lights.data[i].shadow_opacity > 0.001) {
float depth_z = -vertex.z;
if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
@@ -1681,6 +1697,8 @@ void fragment_shader(in SceneData scene_data) {
} else {
shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0;
}
+
+ shadow = shadow * directional_lights.data[i].shadow_opacity + 1.0 - directional_lights.data[i].shadow_opacity;
#endif
blur_shadow(shadow);
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
index c92b29b14a..7299bb0576 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
@@ -199,7 +199,10 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte
#endif // LIGHT_ANISOTROPY_USED
// F
float cLdotH5 = SchlickFresnel(cLdotH);
- vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0);
+ // Calculate Fresnel using specular occlusion term from Filament:
+ // https://google.github.io/filament/Filament.html#lighting/occlusion/specularocclusion
+ float f90 = clamp(dot(f0, vec3(50.0 * 0.33)), 0.0, 1.0);
+ vec3 F = f0 + (f90 - f0) * cLdotH5;
vec3 specular_brdf_NL = cNdotL * D * F * G;
@@ -392,7 +395,7 @@ float get_omni_attenuation(float distance, float inv_range, float decay) {
float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
#ifndef SHADOWS_DISABLED
- if (omni_lights.data[idx].shadow_enabled) {
+ if (omni_lights.data[idx].shadow_opacity > 0.001) {
// there is a shadowmap
vec2 texel_size = scene_data_block.data.shadow_atlas_pixel_size;
vec4 base_uv_rect = omni_lights.data[idx].atlas_rect;
@@ -495,6 +498,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
}
shadow /= float(sc_penumbra_shadow_samples);
+ shadow = mix(1.0, shadow, omni_lights.data[idx].shadow_opacity);
} else {
//no blockers found, so no shadow
@@ -513,7 +517,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
vec2 pos = shadow_sample.xy / shadow_sample.z;
float depth = shadow_len - omni_lights.data[idx].shadow_bias;
depth *= omni_lights.data[idx].inv_radius;
- shadow = sample_omni_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale / shadow_sample.z, pos, uv_rect, flip_offset, depth);
+ shadow = mix(1.0, sample_omni_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale / shadow_sample.z, pos, uv_rect, flip_offset, depth), omni_lights.data[idx].shadow_opacity);
}
return shadow;
@@ -671,7 +675,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
#ifndef SHADOWS_DISABLED
- if (spot_lights.data[idx].shadow_enabled) {
+ if (spot_lights.data[idx].shadow_opacity > 0.001) {
vec3 light_rel_vec = spot_lights.data[idx].position - vertex;
float light_length = length(light_rel_vec);
vec3 spot_dir = spot_lights.data[idx].direction;
@@ -732,6 +736,7 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
}
shadow /= float(sc_penumbra_shadow_samples);
+ shadow = mix(1.0, shadow, spot_lights.data[idx].shadow_opacity);
} else {
//no blockers found, so no shadow
@@ -740,7 +745,7 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
} else {
//hard shadow
vec3 shadow_uv = vec3(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z);
- shadow = sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data_block.data.shadow_atlas_pixel_size, shadow_uv);
+ shadow = mix(1.0, sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data_block.data.shadow_atlas_pixel_size, shadow_uv), spot_lights.data[idx].shadow_opacity);
}
return shadow;
@@ -869,7 +874,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
diffuse_light, specular_light);
}
-void reflection_process(uint ref_index, vec3 view, vec3 vertex, vec3 normal, float roughness, vec3 ambient_light, vec3 specular_light, inout vec4 ambient_accum, inout vec4 reflection_accum) {
+void reflection_process(uint ref_index, vec3 vertex, vec3 ref_vec, vec3 normal, float roughness, vec3 ambient_light, vec3 specular_light, inout vec4 ambient_accum, inout vec4 reflection_accum) {
vec3 box_extents = reflections.data[ref_index].box_extents;
vec3 local_pos = (reflections.data[ref_index].local_matrix * vec4(vertex, 1.0)).xyz;
@@ -877,8 +882,6 @@ void reflection_process(uint ref_index, vec3 view, vec3 vertex, vec3 normal, flo
return;
}
- vec3 ref_vec = normalize(reflect(-view, normal));
-
vec3 inner_pos = abs(local_pos / box_extents);
float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z));
//make blend more rounded
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
index 26d0de46c2..0960533917 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
@@ -16,11 +16,11 @@ layout(location = 0) in vec3 vertex_attrib;
//only for pure render depth when normal is not used
#ifdef NORMAL_USED
-layout(location = 1) in vec3 normal_attrib;
+layout(location = 1) in vec2 normal_attrib;
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-layout(location = 2) in vec4 tangent_attrib;
+layout(location = 2) in vec2 tangent_attrib;
#endif
#if defined(COLOR_USED)
@@ -59,6 +59,13 @@ layout(location = 10) in uvec4 bone_attrib;
layout(location = 11) in vec4 weight_attrib;
#endif
+vec3 oct_to_vec3(vec2 e) {
+ vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));
+ float t = max(-v.z, 0.0);
+ v.xy += t * -sign(v.xy);
+ return v;
+}
+
/* Varyings */
layout(location = 0) highp out vec3 vertex_interp;
@@ -229,12 +236,13 @@ void main() {
vec3 vertex = vertex_attrib;
#ifdef NORMAL_USED
- vec3 normal = normal_attrib * 2.0 - 1.0;
+ vec3 normal = oct_to_vec3(normal_attrib * 2.0 - 1.0);
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
- vec3 tangent = tangent_attrib.xyz * 2.0 - 1.0;
- float binormalf = tangent_attrib.a * 2.0 - 1.0;
+ vec3 signed_tangent_attrib = tangent_attrib * 2.0 - 1.0;
+ vec3 tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0));
+ float binormalf = sign(signed_tangent_attrib.y);
vec3 binormal = normalize(cross(normal, tangent) * binormalf);
#endif
@@ -889,8 +897,10 @@ void main() {
vec3 anisotropic_normal = cross(anisotropic_tangent, anisotropic_direction);
vec3 bent_normal = normalize(mix(normal, anisotropic_normal, abs(anisotropy) * clamp(5.0 * roughness, 0.0, 1.0)));
vec3 ref_vec = reflect(-view, bent_normal);
+ ref_vec = mix(ref_vec, bent_normal, roughness * roughness);
#else
vec3 ref_vec = reflect(-view, normal);
+ ref_vec = mix(ref_vec, normal, roughness * roughness);
#endif
float horizon = min(1.0 + dot(ref_vec, normal), 1.0);
ref_vec = scene_data.radiance_inverse_xform * ref_vec;
@@ -940,6 +950,7 @@ void main() {
vec3 n = normalize(normal_interp); // We want to use geometric normal, not normal_map
float NoV = max(dot(n, view), 0.0001);
vec3 ref_vec = reflect(-view, n);
+ ref_vec = mix(ref_vec, n, clearcoat_roughness * clearcoat_roughness);
// The clear coat layer assumes an IOR of 1.5 (4% reflectance)
float Fc = clearcoat * (0.04 + 0.96 * SchlickFresnel(NoV));
float attenuation = 1.0 - Fc;
@@ -1036,6 +1047,19 @@ void main() {
vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0);
uint reflection_indices = draw_call.reflection_probes.x;
+
+#ifdef LIGHT_ANISOTROPY_USED
+ // https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy
+ vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent;
+ vec3 anisotropic_tangent = cross(anisotropic_direction, view);
+ vec3 anisotropic_normal = cross(anisotropic_tangent, anisotropic_direction);
+ vec3 bent_normal = normalize(mix(normal, anisotropic_normal, abs(anisotropy) * clamp(5.0 * roughness, 0.0, 1.0)));
+#else
+ vec3 bent_normal = normal;
+#endif
+ vec3 ref_vec = normalize(reflect(-view, bent_normal));
+ ref_vec = mix(ref_vec, bent_normal, roughness * roughness);
+
for (uint i = 0; i < 8; i++) {
uint reflection_index = reflection_indices & 0xFF;
if (i == 4) {
@@ -1047,16 +1071,8 @@ void main() {
if (reflection_index == 0xFF) {
break;
}
-#ifdef LIGHT_ANISOTROPY_USED
- // https://google.github.io/filament/Filament.html#lighting/imagebasedlights/anisotropy
- vec3 anisotropic_direction = anisotropy >= 0.0 ? binormal : tangent;
- vec3 anisotropic_tangent = cross(anisotropic_direction, view);
- vec3 anisotropic_normal = cross(anisotropic_tangent, anisotropic_direction);
- vec3 bent_normal = normalize(mix(normal, anisotropic_normal, abs(anisotropy) * clamp(5.0 * roughness, 0.0, 1.0)));
-#else
- vec3 bent_normal = normal;
-#endif
- reflection_process(reflection_index, view, vertex, bent_normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum);
+
+ reflection_process(reflection_index, vertex, ref_vec, bent_normal, roughness, ambient_light, specular_light, ambient_accum, reflection_accum);
}
if (reflection_accum.a > 0.0) {
@@ -1134,7 +1150,7 @@ void main() {
#ifdef USE_SOFT_SHADOWS
//version with soft shadows, more expensive
- if (directional_lights.data[i].shadow_enabled) {
+ if (directional_lights.data[i].shadow_opacity > 0.001) {
float depth_z = -vertex.z;
vec4 pssm_coord;
@@ -1286,7 +1302,7 @@ void main() {
#else
// Soft shadow disabled version
- if (directional_lights.data[i].shadow_enabled) {
+ if (directional_lights.data[i].shadow_opacity > 0.001) {
float depth_z = -vertex.z;
vec4 pssm_coord;
diff --git a/servers/rendering/renderer_rd/shaders/skeleton.glsl b/servers/rendering/renderer_rd/shaders/skeleton.glsl
index a893a66c94..75bea9300b 100644
--- a/servers/rendering/renderer_rd/shaders/skeleton.glsl
+++ b/servers/rendering/renderer_rd/shaders/skeleton.glsl
@@ -54,14 +54,54 @@ layout(push_constant, std430) uniform Params {
}
params;
-vec4 decode_abgr_2_10_10_10(uint base) {
- uvec4 abgr_2_10_10_10 = (uvec4(base) >> uvec4(0, 10, 20, 30)) & uvec4(0x3FF, 0x3FF, 0x3FF, 0x3);
- return vec4(abgr_2_10_10_10) / vec4(1023.0, 1023.0, 1023.0, 3.0) * 2.0 - 1.0;
+vec2 uint_to_vec2(uint base) {
+ uvec2 decode = (uvec2(base) >> uvec2(0, 16)) & uvec2(0xFFFF, 0xFFFF);
+ return vec2(decode) / vec2(65535.0, 65535.0) * 2.0 - 1.0;
}
-uint encode_abgr_2_10_10_10(vec4 base) {
- uvec4 abgr_2_10_10_10 = uvec4(clamp(ivec4((base * 0.5 + 0.5) * vec4(1023.0, 1023.0, 1023.0, 3.0)), ivec4(0), ivec4(0x3FF, 0x3FF, 0x3FF, 0x3))) << uvec4(0, 10, 20, 30);
- return abgr_2_10_10_10.x | abgr_2_10_10_10.y | abgr_2_10_10_10.z | abgr_2_10_10_10.w;
+vec3 oct_to_vec3(vec2 oct) {
+ vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));
+ float t = max(-v.z, 0.0);
+ v.xy += t * -sign(v.xy);
+ return v;
+}
+
+vec3 decode_uint_oct_to_norm(uint base) {
+ return oct_to_vec3(uint_to_vec2(base));
+}
+
+vec4 decode_uint_oct_to_tang(uint base) {
+ vec2 oct_sign_encoded = uint_to_vec2(base);
+ // Binormal sign encoded in y component
+ vec2 oct = vec2(oct_sign_encoded.x, abs(oct_sign_encoded.y) * 2.0 - 1.0);
+ return vec4(oct_to_vec3(oct), sign(oct_sign_encoded.y));
+}
+
+vec2 signNotZero(vec2 v) {
+ return mix(vec2(-1.0), vec2(1.0), greaterThanEqual(v.xy, vec2(0.0)));
+}
+
+uint vec2_to_uint(vec2 base) {
+ uvec2 enc = uvec2(clamp(ivec2(base * vec2(65535, 65535)), ivec2(0), ivec2(0xFFFF, 0xFFFF))) << uvec2(0, 16);
+ return enc.x | enc.y;
+}
+
+vec2 vec3_to_oct(vec3 e) {
+ e /= abs(e.x) + abs(e.y) + abs(e.z);
+ vec2 oct = e.z >= 0.0f ? e.xy : (vec2(1.0f) - abs(e.yx)) * signNotZero(e.xy);
+ return oct * 0.5f + 0.5f;
+}
+
+uint encode_norm_to_uint_oct(vec3 base) {
+ return vec2_to_uint(vec3_to_oct(base));
+}
+
+uint encode_tang_to_uint_oct(vec4 base) {
+ vec2 oct = vec3_to_oct(base.xyz);
+ // Encode binormal sign in y component
+ oct.y = oct.y * 0.5f + 0.5f;
+ oct.y = base.w >= 0.0f ? oct.y : 1 - oct.y;
+ return vec2_to_uint(oct);
}
void main() {
@@ -131,12 +171,12 @@ void main() {
src_offset += 3;
if (params.has_normal) {
- normal = decode_abgr_2_10_10_10(src_vertices.data[src_offset]).rgb;
+ normal = decode_uint_oct_to_norm(src_vertices.data[src_offset]);
src_offset++;
}
if (params.has_tangent) {
- tangent = decode_abgr_2_10_10_10(src_vertices.data[src_offset]);
+ tangent = decode_uint_oct_to_tang(src_vertices.data[src_offset]);
}
if (params.has_blend_shape) {
@@ -155,12 +195,12 @@ void main() {
base_offset += 3;
if (params.has_normal) {
- blend_normal += decode_abgr_2_10_10_10(src_blend_shapes.data[base_offset]).rgb * w;
+ blend_normal += decode_uint_oct_to_norm(src_blend_shapes.data[base_offset]) * w;
base_offset++;
}
if (params.has_tangent) {
- blend_tangent += decode_abgr_2_10_10_10(src_blend_shapes.data[base_offset]).rgb * w;
+ blend_tangent += decode_uint_oct_to_tang(src_blend_shapes.data[base_offset]).rgb * w;
}
blend_total += w;
@@ -234,12 +274,12 @@ void main() {
dst_offset += 3;
if (params.has_normal) {
- dst_vertices.data[dst_offset] = encode_abgr_2_10_10_10(vec4(normal, 0.0));
+ dst_vertices.data[dst_offset] = encode_norm_to_uint_oct(normal);
dst_offset++;
}
if (params.has_tangent) {
- dst_vertices.data[dst_offset] = encode_abgr_2_10_10_10(tangent);
+ dst_vertices.data[dst_offset] = encode_tang_to_uint_oct(tangent);
}
#endif
diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
index e65f676785..7b58cc08dd 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
@@ -56,7 +56,7 @@ LightStorage::LightStorage() {
}
for (int i = 0; i < lightmap_textures.size(); i++) {
- lightmap_textures.write[i] = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
+ lightmap_textures.write[i] = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
}
}
@@ -88,6 +88,7 @@ void LightStorage::_light_initialize(RID p_light, RS::LightType p_type) {
light.param[RS::LIGHT_PARAM_SHADOW_FADE_START] = 0.8;
light.param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 1.0;
light.param[RS::LIGHT_PARAM_SHADOW_BIAS] = 0.02;
+ light.param[RS::LIGHT_PARAM_SHADOW_OPACITY] = 1.0;
light.param[RS::LIGHT_PARAM_SHADOW_BLUR] = 0;
light.param[RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE] = 20.0;
light.param[RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE] = 0.1;
@@ -351,7 +352,7 @@ AABB LightStorage::light_get_aabb(RID p_light) const {
switch (light->type) {
case RS::LIGHT_SPOT: {
float len = light->param[RS::LIGHT_PARAM_RANGE];
- float size = Math::tan(Math::deg2rad(light->param[RS::LIGHT_PARAM_SPOT_ANGLE])) * len;
+ float size = Math::tan(Math::deg_to_rad(light->param[RS::LIGHT_PARAM_SPOT_ANGLE])) * len;
return AABB(Vector3(-size, -size, -len), Vector3(size * 2, size * 2, len));
};
case RS::LIGHT_OMNI: {
@@ -366,6 +367,13 @@ AABB LightStorage::light_get_aabb(RID p_light) const {
ERR_FAIL_V(AABB());
}
+Dependency *LightStorage::light_get_dependency(RID p_light) const {
+ Light *light = light_owner.get_or_null(p_light);
+ ERR_FAIL_NULL_V(light, nullptr);
+
+ return &light->dependency;
+}
+
/* REFLECTION PROBE */
RID LightStorage::reflection_probe_allocate() {
@@ -601,6 +609,13 @@ float LightStorage::reflection_probe_get_ambient_color_energy(RID p_probe) const
return reflection_probe->ambient_color_energy;
}
+Dependency *LightStorage::reflection_probe_get_dependency(RID p_probe) const {
+ ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
+ ERR_FAIL_NULL_V(reflection_probe, nullptr);
+
+ return &reflection_probe->dependency;
+}
+
/* LIGHTMAP API */
RID LightStorage::lightmap_allocate() {
@@ -628,17 +643,17 @@ void LightStorage::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_use
//erase lightmap users
if (lm->light_texture.is_valid()) {
- RendererRD::Texture *t = RendererRD::TextureStorage::get_singleton()->get_texture(lm->light_texture);
+ RendererRD::TextureStorage::Texture *t = RendererRD::TextureStorage::get_singleton()->get_texture(lm->light_texture);
if (t) {
t->lightmap_users.erase(p_lightmap);
}
}
- RendererRD::Texture *t = RendererRD::TextureStorage::get_singleton()->get_texture(p_light);
+ RendererRD::TextureStorage::Texture *t = RendererRD::TextureStorage::get_singleton()->get_texture(p_light);
lm->light_texture = p_light;
lm->uses_spherical_harmonics = p_uses_spherical_haromics;
- RID default_2d_array = texture_storage->texture_rd_get_default(RendererRD::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
+ RID default_2d_array = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
if (!t) {
if (using_lightmap_array) {
if (lm->array_index >= 0) {
@@ -725,6 +740,13 @@ void LightStorage::lightmap_set_probe_capture_update_speed(float p_speed) {
lightmap_probe_capture_update_speed = p_speed;
}
+Dependency *LightStorage::lightmap_get_dependency(RID p_lightmap) const {
+ Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
+ ERR_FAIL_NULL_V(lm, nullptr);
+
+ return &lm->dependency;
+}
+
void LightStorage::lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) {
Lightmap *lm = lightmap_owner.get_or_null(p_lightmap);
ERR_FAIL_COND(!lm);
diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h
index 2fb8f92fff..3e3246e8e9 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h
@@ -39,87 +39,81 @@
namespace RendererRD {
-/* LIGHT */
-
-struct Light {
- RS::LightType type;
- float param[RS::LIGHT_PARAM_MAX];
- Color color = Color(1, 1, 1, 1);
- RID projector;
- bool shadow = false;
- bool negative = false;
- bool reverse_cull = false;
- RS::LightBakeMode bake_mode = RS::LIGHT_BAKE_DYNAMIC;
- uint32_t max_sdfgi_cascade = 2;
- uint32_t cull_mask = 0xFFFFFFFF;
- bool distance_fade = false;
- real_t distance_fade_begin = 40.0;
- real_t distance_fade_shadow = 50.0;
- real_t distance_fade_length = 10.0;
- RS::LightOmniShadowMode omni_shadow_mode = RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID;
- RS::LightDirectionalShadowMode directional_shadow_mode = RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL;
- bool directional_blend_splits = false;
- RS::LightDirectionalSkyMode directional_sky_mode = RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_AND_SKY;
- uint64_t version = 0;
-
- Dependency dependency;
-};
-
-/* REFLECTION PROBE */
-
-struct ReflectionProbe {
- RS::ReflectionProbeUpdateMode update_mode = RS::REFLECTION_PROBE_UPDATE_ONCE;
- int resolution = 256;
- float intensity = 1.0;
- RS::ReflectionProbeAmbientMode ambient_mode = RS::REFLECTION_PROBE_AMBIENT_ENVIRONMENT;
- Color ambient_color;
- float ambient_color_energy = 1.0;
- float max_distance = 0;
- Vector3 extents = Vector3(1, 1, 1);
- Vector3 origin_offset;
- bool interior = false;
- bool box_projection = false;
- bool enable_shadows = false;
- uint32_t cull_mask = (1 << 20) - 1;
- float mesh_lod_threshold = 0.01;
-
- Dependency dependency;
-};
-
-/* LIGHTMAP */
-
-struct Lightmap {
- RID light_texture;
- bool uses_spherical_harmonics = false;
- bool interior = false;
- AABB bounds = AABB(Vector3(), Vector3(1, 1, 1));
- int32_t array_index = -1; //unassigned
- PackedVector3Array points;
- PackedColorArray point_sh;
- PackedInt32Array tetrahedra;
- PackedInt32Array bsp_tree;
-
- struct BSP {
- static const int32_t EMPTY_LEAF = INT32_MIN;
- float plane[4];
- int32_t over = EMPTY_LEAF, under = EMPTY_LEAF;
- };
-
- Dependency dependency;
-};
-
class LightStorage : public RendererLightStorage {
private:
static LightStorage *singleton;
/* LIGHT */
+ struct Light {
+ RS::LightType type;
+ float param[RS::LIGHT_PARAM_MAX];
+ Color color = Color(1, 1, 1, 1);
+ RID projector;
+ bool shadow = false;
+ bool negative = false;
+ bool reverse_cull = false;
+ RS::LightBakeMode bake_mode = RS::LIGHT_BAKE_DYNAMIC;
+ uint32_t max_sdfgi_cascade = 2;
+ uint32_t cull_mask = 0xFFFFFFFF;
+ bool distance_fade = false;
+ real_t distance_fade_begin = 40.0;
+ real_t distance_fade_shadow = 50.0;
+ real_t distance_fade_length = 10.0;
+ RS::LightOmniShadowMode omni_shadow_mode = RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID;
+ RS::LightDirectionalShadowMode directional_shadow_mode = RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL;
+ bool directional_blend_splits = false;
+ RS::LightDirectionalSkyMode directional_sky_mode = RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_AND_SKY;
+ uint64_t version = 0;
+
+ Dependency dependency;
+ };
+
mutable RID_Owner<Light, true> light_owner;
/* REFLECTION PROBE */
+
+ struct ReflectionProbe {
+ RS::ReflectionProbeUpdateMode update_mode = RS::REFLECTION_PROBE_UPDATE_ONCE;
+ int resolution = 256;
+ float intensity = 1.0;
+ RS::ReflectionProbeAmbientMode ambient_mode = RS::REFLECTION_PROBE_AMBIENT_ENVIRONMENT;
+ Color ambient_color;
+ float ambient_color_energy = 1.0;
+ float max_distance = 0;
+ Vector3 extents = Vector3(1, 1, 1);
+ Vector3 origin_offset;
+ bool interior = false;
+ bool box_projection = false;
+ bool enable_shadows = false;
+ uint32_t cull_mask = (1 << 20) - 1;
+ float mesh_lod_threshold = 0.01;
+
+ Dependency dependency;
+ };
mutable RID_Owner<ReflectionProbe, true> reflection_probe_owner;
/* LIGHTMAP */
+ struct Lightmap {
+ RID light_texture;
+ bool uses_spherical_harmonics = false;
+ bool interior = false;
+ AABB bounds = AABB(Vector3(), Vector3(1, 1, 1));
+ int32_t array_index = -1; //unassigned
+ PackedVector3Array points;
+ PackedColorArray point_sh;
+ PackedInt32Array tetrahedra;
+ PackedInt32Array bsp_tree;
+
+ struct BSP {
+ static const int32_t EMPTY_LEAF = INT32_MIN;
+ float plane[4];
+ int32_t over = EMPTY_LEAF, under = EMPTY_LEAF;
+ };
+
+ Dependency dependency;
+ };
+
bool using_lightmap_array;
Vector<RID> lightmap_textures;
uint64_t lightmap_array_version = 0;
@@ -135,7 +129,6 @@ public:
/* LIGHT */
- Light *get_light(RID p_rid) { return light_owner.get_or_null(p_rid); };
bool owns_light(RID p_rid) { return light_owner.owns(p_rid); };
void _light_initialize(RID p_rid, RS::LightType p_type);
@@ -268,9 +261,10 @@ public:
virtual uint32_t light_get_max_sdfgi_cascade(RID p_light) override;
virtual uint64_t light_get_version(RID p_light) const override;
+ Dependency *light_get_dependency(RID p_light) const;
+
/* REFLECTION PROBE */
- ReflectionProbe *get_reflection_probe(RID p_rid) { return reflection_probe_owner.get_or_null(p_rid); };
bool owns_reflection_probe(RID p_rid) { return reflection_probe_owner.owns(p_rid); };
virtual RID reflection_probe_allocate() override;
@@ -310,9 +304,10 @@ public:
Color reflection_probe_get_ambient_color(RID p_probe) const;
float reflection_probe_get_ambient_color_energy(RID p_probe) const;
+ Dependency *reflection_probe_get_dependency(RID p_probe) const;
+
/* LIGHTMAP */
- Lightmap *get_lightmap(RID p_rid) { return lightmap_owner.get_or_null(p_rid); };
bool owns_lightmap(RID p_rid) { return lightmap_owner.owns(p_rid); };
virtual RID lightmap_allocate() override;
@@ -332,6 +327,8 @@ public:
virtual void lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) override;
virtual void lightmap_set_probe_capture_update_speed(float p_speed) override;
+ Dependency *lightmap_get_dependency(RID p_lightmap) const;
+
virtual float lightmap_get_probe_capture_update_speed() const override {
return lightmap_probe_capture_update_speed;
}
diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
index 815b7a1fda..fa8406e7a1 100644
--- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
@@ -926,9 +926,9 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type,
}
///////////////////////////////////////////////////////////////////////////
-// MaterialData
+// MaterialStorage::MaterialData
-void MaterialData::update_uniform_buffer(const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const HashMap<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color) {
+void MaterialStorage::MaterialData::update_uniform_buffer(const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const HashMap<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color) {
MaterialStorage *material_storage = MaterialStorage::get_singleton();
bool uses_global_buffer = false;
@@ -941,6 +941,12 @@ void MaterialData::update_uniform_buffer(const HashMap<StringName, ShaderLanguag
continue; //instance uniforms don't appear in the buffer
}
+ if (E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE ||
+ E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE ||
+ E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
+ continue;
+ }
+
if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) {
//this is a global variable, get the index to it
GlobalShaderUniforms::Variable *gv = material_storage->global_shader_uniforms.variables.getptr(E.key);
@@ -1007,7 +1013,7 @@ void MaterialData::update_uniform_buffer(const HashMap<StringName, ShaderLanguag
}
}
-MaterialData::~MaterialData() {
+MaterialStorage::MaterialData::~MaterialData() {
MaterialStorage *material_storage = MaterialStorage::get_singleton();
if (global_buffer_E) {
@@ -1033,14 +1039,14 @@ MaterialData::~MaterialData() {
}
}
-void MaterialData::update_textures(const HashMap<StringName, Variant> &p_parameters, const HashMap<StringName, HashMap<int, RID>> &p_default_textures, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color) {
+void MaterialStorage::MaterialData::update_textures(const HashMap<StringName, Variant> &p_parameters, const HashMap<StringName, HashMap<int, RID>> &p_default_textures, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color) {
TextureStorage *texture_storage = TextureStorage::get_singleton();
MaterialStorage *material_storage = MaterialStorage::get_singleton();
#ifdef TOOLS_ENABLED
- Texture *roughness_detect_texture = nullptr;
+ TextureStorage::Texture *roughness_detect_texture = nullptr;
RS::TextureDetectRoughnessChannel roughness_channel = RS::TEXTURE_DETECT_ROUGHNESS_R;
- Texture *normal_detect_texture = nullptr;
+ TextureStorage::Texture *normal_detect_texture = nullptr;
#endif
bool uses_global_textures = false;
@@ -1052,6 +1058,12 @@ void MaterialData::update_textures(const HashMap<StringName, Variant> &p_paramet
Vector<RID> textures;
+ if (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE ||
+ p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE ||
+ p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
+ continue;
+ }
+
if (p_texture_uniforms[i].global) {
uses_global_textures = true;
@@ -1123,19 +1135,22 @@ void MaterialData::update_textures(const HashMap<StringName, Variant> &p_paramet
case ShaderLanguage::TYPE_SAMPLER2D: {
switch (p_texture_uniforms[i].hint) {
case ShaderLanguage::ShaderNode::Uniform::HINT_DEFAULT_BLACK: {
- rd_texture = texture_storage->texture_rd_get_default(DEFAULT_RD_TEXTURE_BLACK);
+ rd_texture = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
+ } break;
+ case ShaderLanguage::ShaderNode::Uniform::HINT_DEFAULT_TRANSPARENT: {
+ rd_texture = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_TRANSPARENT);
} break;
case ShaderLanguage::ShaderNode::Uniform::HINT_ANISOTROPY: {
- rd_texture = texture_storage->texture_rd_get_default(DEFAULT_RD_TEXTURE_ANISO);
+ rd_texture = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_ANISO);
} break;
case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: {
- rd_texture = texture_storage->texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL);
+ rd_texture = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_NORMAL);
} break;
case ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL: {
- rd_texture = texture_storage->texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL);
+ rd_texture = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_NORMAL);
} break;
default: {
- rd_texture = texture_storage->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
+ rd_texture = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_WHITE);
} break;
}
} break;
@@ -1143,27 +1158,27 @@ void MaterialData::update_textures(const HashMap<StringName, Variant> &p_paramet
case ShaderLanguage::TYPE_SAMPLERCUBE: {
switch (p_texture_uniforms[i].hint) {
case ShaderLanguage::ShaderNode::Uniform::HINT_DEFAULT_BLACK: {
- rd_texture = texture_storage->texture_rd_get_default(DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
+ rd_texture = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
} break;
default: {
- rd_texture = texture_storage->texture_rd_get_default(DEFAULT_RD_TEXTURE_CUBEMAP_WHITE);
+ rd_texture = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_WHITE);
} break;
}
} break;
case ShaderLanguage::TYPE_SAMPLERCUBEARRAY: {
- rd_texture = texture_storage->texture_rd_get_default(DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK);
+ rd_texture = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK);
} break;
case ShaderLanguage::TYPE_ISAMPLER3D:
case ShaderLanguage::TYPE_USAMPLER3D:
case ShaderLanguage::TYPE_SAMPLER3D: {
- rd_texture = texture_storage->texture_rd_get_default(DEFAULT_RD_TEXTURE_3D_WHITE);
+ rd_texture = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
} break;
case ShaderLanguage::TYPE_ISAMPLER2DARRAY:
case ShaderLanguage::TYPE_USAMPLER2DARRAY:
case ShaderLanguage::TYPE_SAMPLER2DARRAY: {
- rd_texture = texture_storage->texture_rd_get_default(DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
+ rd_texture = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
} break;
default: {
@@ -1185,7 +1200,7 @@ void MaterialData::update_textures(const HashMap<StringName, Variant> &p_paramet
bool srgb = p_use_linear_color && p_texture_uniforms[i].use_color;
for (int j = 0; j < textures.size(); j++) {
- Texture *tex = TextureStorage::get_singleton()->get_texture(textures[j]);
+ TextureStorage::Texture *tex = TextureStorage::get_singleton()->get_texture(textures[j]);
if (tex) {
rd_texture = (srgb && tex->rd_texture_srgb.is_valid()) ? tex->rd_texture_srgb : tex->rd_texture;
@@ -1207,7 +1222,7 @@ void MaterialData::update_textures(const HashMap<StringName, Variant> &p_paramet
#endif
}
if (rd_texture.is_null()) {
- rd_texture = texture_storage->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
+ rd_texture = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_WHITE);
}
#ifdef TOOLS_ENABLED
if (roughness_detect_texture && normal_detect_texture && !normal_detect_texture->path.is_empty()) {
@@ -1248,14 +1263,14 @@ void MaterialData::update_textures(const HashMap<StringName, Variant> &p_paramet
}
}
-void MaterialData::free_parameters_uniform_set(RID p_uniform_set) {
+void MaterialStorage::MaterialData::free_parameters_uniform_set(RID p_uniform_set) {
if (p_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(p_uniform_set)) {
RD::get_singleton()->uniform_set_set_invalidation_callback(p_uniform_set, nullptr, nullptr);
RD::get_singleton()->free(p_uniform_set);
}
}
-bool MaterialData::update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, uint32_t p_barrier) {
+bool MaterialStorage::MaterialData::update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, uint32_t p_barrier) {
if ((uint32_t)ubo_data.size() != p_ubo_size) {
p_uniform_dirty = true;
if (uniform_buffer.is_valid()) {
@@ -1304,7 +1319,7 @@ bool MaterialData::update_parameters_uniform_set(const HashMap<StringName, Varia
update_textures(p_parameters, p_default_texture_params, p_texture_uniforms, texture_cache.ptrw(), true);
}
- if (p_ubo_size == 0 && p_texture_uniforms.size() == 0) {
+ if (p_ubo_size == 0 && (p_texture_uniforms.size() == 0)) {
// This material does not require an uniform set, so don't create it.
return false;
}
@@ -2209,11 +2224,14 @@ void MaterialStorage::global_shader_uniforms_instance_update(RID p_instance, int
ShaderLanguage::TYPE_VEC3, // vec3
ShaderLanguage::TYPE_IVEC3, //vec3i
ShaderLanguage::TYPE_MAX, //xform2d not supported here
+ ShaderLanguage::TYPE_VEC4, //vec4
+ ShaderLanguage::TYPE_IVEC4, //vec4i
ShaderLanguage::TYPE_VEC4, //plane
ShaderLanguage::TYPE_VEC4, //quat
ShaderLanguage::TYPE_MAX, //aabb not supported here
ShaderLanguage::TYPE_MAX, //basis not supported here
ShaderLanguage::TYPE_MAX, //xform not supported here
+ ShaderLanguage::TYPE_MAX, //projection not supported here
ShaderLanguage::TYPE_VEC4 //color
};
@@ -2400,11 +2418,11 @@ String MaterialStorage::shader_get_code(RID p_shader) const {
return shader->code;
}
-void MaterialStorage::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const {
+void MaterialStorage::shader_get_shader_uniform_list(RID p_shader, List<PropertyInfo> *p_param_list) const {
Shader *shader = shader_owner.get_or_null(p_shader);
ERR_FAIL_COND(!shader);
if (shader->data) {
- return shader->data->get_param_list(p_param_list);
+ return shader->data->get_shader_uniform_list(p_param_list);
}
}
@@ -2577,6 +2595,15 @@ void MaterialStorage::material_set_shader(RID p_material, RID p_shader) {
_material_queue_update(material, true, true);
}
+MaterialStorage::ShaderData *MaterialStorage::material_get_shader_data(RID p_material) {
+ const MaterialStorage::Material *material = MaterialStorage::get_singleton()->get_material(p_material);
+ if (material && material->shader && material->shader->data) {
+ return material->shader->data;
+ }
+
+ return nullptr;
+}
+
void MaterialStorage::material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) {
Material *material = material_owner.get_or_null(p_material);
ERR_FAIL_COND(!material);
@@ -2657,14 +2684,14 @@ bool MaterialStorage::material_casts_shadows(RID p_material) {
return true; //by default everything casts shadows
}
-void MaterialStorage::material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) {
+void MaterialStorage::material_get_instance_shader_uniforms(RID p_material, List<InstanceShaderParam> *r_parameters) {
Material *material = material_owner.get_or_null(p_material);
ERR_FAIL_COND(!material);
if (material->shader && material->shader->data) {
material->shader->data->get_instance_param_list(r_parameters);
if (material->next_pass.is_valid()) {
- material_get_instance_shader_parameters(material->next_pass, r_parameters);
+ material_get_instance_shader_uniforms(material->next_pass, r_parameters);
}
}
}
@@ -2678,12 +2705,12 @@ void MaterialStorage::material_update_dependency(RID p_material, DependencyTrack
}
}
-void MaterialStorage::material_set_data_request_function(ShaderType p_shader_type, MaterialDataRequestFunction p_function) {
+void MaterialStorage::material_set_data_request_function(ShaderType p_shader_type, MaterialStorage::MaterialDataRequestFunction p_function) {
ERR_FAIL_INDEX(p_shader_type, SHADER_TYPE_MAX);
material_data_request_func[p_shader_type] = p_function;
}
-MaterialDataRequestFunction MaterialStorage::material_get_data_request_function(ShaderType p_shader_type) {
+MaterialStorage::MaterialDataRequestFunction MaterialStorage::material_get_data_request_function(ShaderType p_shader_type) {
ERR_FAIL_INDEX_V(p_shader_type, SHADER_TYPE_MAX, nullptr);
return material_data_request_func[p_shader_type];
}
diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.h b/servers/rendering/renderer_rd/storage_rd/material_storage.h
index ad40a86dd0..dbf7a92e23 100644
--- a/servers/rendering/renderer_rd/storage_rd/material_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/material_storage.h
@@ -42,161 +42,62 @@
namespace RendererRD {
-class MaterialStorage;
-
-/* SHADER Structs */
-
-enum ShaderType {
- SHADER_TYPE_2D,
- SHADER_TYPE_3D,
- SHADER_TYPE_PARTICLES,
- SHADER_TYPE_SKY,
- SHADER_TYPE_FOG,
- SHADER_TYPE_MAX
-};
-
-struct ShaderData {
- virtual void set_code(const String &p_Code) = 0;
- virtual void set_path_hint(const String &p_hint) = 0;
- virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) = 0;
- virtual void get_param_list(List<PropertyInfo> *p_param_list) const = 0;
-
- virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const = 0;
- virtual bool is_param_texture(const StringName &p_param) const = 0;
- virtual bool is_animated() const = 0;
- virtual bool casts_shadows() const = 0;
- virtual Variant get_default_parameter(const StringName &p_parameter) const = 0;
- virtual RS::ShaderNativeSourceCode get_native_source_code() const { return RS::ShaderNativeSourceCode(); }
-
- virtual ~ShaderData() {}
-};
-
-typedef ShaderData *(*ShaderDataRequestFunction)();
-
-struct Material;
-
-struct Shader {
- ShaderData *data = nullptr;
- String code;
- String path_hint;
- ShaderType type;
- HashMap<StringName, HashMap<int, RID>> default_texture_parameter;
- HashSet<Material *> owners;
-};
-
-/* Material structs */
-
-struct MaterialData {
- void update_uniform_buffer(const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const HashMap<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color);
- void update_textures(const HashMap<StringName, Variant> &p_parameters, const HashMap<StringName, HashMap<int, RID>> &p_default_textures, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color);
-
- virtual void set_render_priority(int p_priority) = 0;
- virtual void set_next_pass(RID p_pass) = 0;
- virtual bool update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) = 0;
- virtual ~MaterialData();
-
- //to be used internally by update_parameters, in the most common configuration of material parameters
- bool update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, uint32_t p_barrier = RD::BARRIER_MASK_ALL);
- void free_parameters_uniform_set(RID p_uniform_set);
-
-private:
- friend class MaterialStorage;
- RID self;
- List<RID>::Element *global_buffer_E = nullptr;
- List<RID>::Element *global_texture_E = nullptr;
- uint64_t global_textures_pass = 0;
- HashMap<StringName, uint64_t> used_global_textures;
-
- //internally by update_parameters_uniform_set
- Vector<uint8_t> ubo_data;
- RID uniform_buffer;
- Vector<RID> texture_cache;
-};
-
-typedef MaterialData *(*MaterialDataRequestFunction)(ShaderData *);
-
-struct Material {
- RID self;
- MaterialData *data = nullptr;
- Shader *shader = nullptr;
- //shortcut to shader data and type
- ShaderType shader_type = SHADER_TYPE_MAX;
- uint32_t shader_id = 0;
- bool uniform_dirty = false;
- bool texture_dirty = false;
- HashMap<StringName, Variant> params;
- int32_t priority = 0;
- RID next_pass;
- SelfList<Material> update_element;
-
- Dependency dependency;
-
- Material() :
- update_element(this) {}
-};
-
-/* Global shader uniform structs */
-struct GlobalShaderUniforms {
- enum {
- BUFFER_DIRTY_REGION_SIZE = 1024
- };
- struct Variable {
- HashSet<RID> texture_materials; // materials using this
-
- RS::GlobalShaderUniformType type;
- Variant value;
- Variant override;
- int32_t buffer_index; //for vectors
- int32_t buffer_elements; //for vectors
+class MaterialStorage : public RendererMaterialStorage {
+public:
+ enum ShaderType {
+ SHADER_TYPE_2D,
+ SHADER_TYPE_3D,
+ SHADER_TYPE_PARTICLES,
+ SHADER_TYPE_SKY,
+ SHADER_TYPE_FOG,
+ SHADER_TYPE_MAX
};
- HashMap<StringName, Variable> variables;
-
- struct Value {
- float x;
- float y;
- float z;
- float w;
- };
+ struct ShaderData {
+ virtual void set_code(const String &p_Code) = 0;
+ virtual void set_path_hint(const String &p_hint) = 0;
+ virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) = 0;
+ virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const = 0;
- struct ValueInt {
- int32_t x;
- int32_t y;
- int32_t z;
- int32_t w;
- };
+ virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const = 0;
+ virtual bool is_param_texture(const StringName &p_param) const = 0;
+ virtual bool is_animated() const = 0;
+ virtual bool casts_shadows() const = 0;
+ virtual Variant get_default_parameter(const StringName &p_parameter) const = 0;
+ virtual RS::ShaderNativeSourceCode get_native_source_code() const { return RS::ShaderNativeSourceCode(); }
- struct ValueUInt {
- uint32_t x;
- uint32_t y;
- uint32_t z;
- uint32_t w;
+ virtual ~ShaderData() {}
};
- struct ValueUsage {
- uint32_t elements = 0;
- };
+ struct MaterialData {
+ void update_uniform_buffer(const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const HashMap<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color);
+ void update_textures(const HashMap<StringName, Variant> &p_parameters, const HashMap<StringName, HashMap<int, RID>> &p_default_textures, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color);
- List<RID> materials_using_buffer;
- List<RID> materials_using_texture;
+ virtual void set_render_priority(int p_priority) = 0;
+ virtual void set_next_pass(RID p_pass) = 0;
+ virtual bool update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) = 0;
+ virtual ~MaterialData();
- RID buffer;
- Value *buffer_values = nullptr;
- ValueUsage *buffer_usage = nullptr;
- bool *buffer_dirty_regions = nullptr;
- uint32_t buffer_dirty_region_count = 0;
+ //to be used internally by update_parameters, in the most common configuration of material parameters
+ bool update_parameters_uniform_set(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const HashMap<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompiler::GeneratedCode::Texture> &p_texture_uniforms, const HashMap<StringName, HashMap<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, uint32_t p_barrier = RD::BARRIER_MASK_ALL);
+ void free_parameters_uniform_set(RID p_uniform_set);
- uint32_t buffer_size;
+ private:
+ friend class MaterialStorage;
- bool must_update_texture_materials = false;
- bool must_update_buffer_materials = false;
+ RID self;
+ List<RID>::Element *global_buffer_E = nullptr;
+ List<RID>::Element *global_texture_E = nullptr;
+ uint64_t global_textures_pass = 0;
+ HashMap<StringName, uint64_t> used_global_textures;
- HashMap<RID, int32_t> instance_buffer_pos;
-};
+ //internally by update_parameters_uniform_set
+ Vector<uint8_t> ubo_data;
+ RID uniform_buffer;
+ Vector<RID> texture_cache;
+ };
-class MaterialStorage : public RendererMaterialStorage {
private:
- friend struct MaterialData;
static MaterialStorage *singleton;
/* Samplers */
@@ -211,7 +112,63 @@ private:
/* GLOBAL SHADER UNIFORM API */
- GlobalShaderUniforms global_shader_uniforms;
+ struct GlobalShaderUniforms {
+ enum {
+ BUFFER_DIRTY_REGION_SIZE = 1024
+ };
+ struct Variable {
+ HashSet<RID> texture_materials; // materials using this
+
+ RS::GlobalShaderUniformType type;
+ Variant value;
+ Variant override;
+ int32_t buffer_index; //for vectors
+ int32_t buffer_elements; //for vectors
+ };
+
+ HashMap<StringName, Variable> variables;
+
+ struct Value {
+ float x;
+ float y;
+ float z;
+ float w;
+ };
+
+ struct ValueInt {
+ int32_t x;
+ int32_t y;
+ int32_t z;
+ int32_t w;
+ };
+
+ struct ValueUInt {
+ uint32_t x;
+ uint32_t y;
+ uint32_t z;
+ uint32_t w;
+ };
+
+ struct ValueUsage {
+ uint32_t elements = 0;
+ };
+
+ List<RID> materials_using_buffer;
+ List<RID> materials_using_texture;
+
+ RID buffer;
+ Value *buffer_values = nullptr;
+ ValueUsage *buffer_usage = nullptr;
+ bool *buffer_dirty_regions = nullptr;
+ uint32_t buffer_dirty_region_count = 0;
+
+ uint32_t buffer_size;
+
+ bool must_update_texture_materials = false;
+ bool must_update_buffer_materials = false;
+
+ HashMap<RID, int32_t> instance_buffer_pos;
+ } global_shader_uniforms;
int32_t _global_shader_uniform_allocate(uint32_t p_elements);
void _global_shader_uniform_store_in_buffer(int32_t p_index, RS::GlobalShaderUniformType p_type, const Variant &p_value);
@@ -219,12 +176,50 @@ private:
/* SHADER API */
+ struct Material;
+
+ struct Shader {
+ ShaderData *data = nullptr;
+ String code;
+ String path_hint;
+ ShaderType type;
+ HashMap<StringName, HashMap<int, RID>> default_texture_parameter;
+ HashSet<Material *> owners;
+ };
+
+ typedef ShaderData *(*ShaderDataRequestFunction)();
ShaderDataRequestFunction shader_data_request_func[SHADER_TYPE_MAX];
+
mutable RID_Owner<Shader, true> shader_owner;
+ Shader *get_shader(RID p_rid) { return shader_owner.get_or_null(p_rid); }
/* MATERIAL API */
+
+ typedef MaterialData *(*MaterialDataRequestFunction)(ShaderData *);
+
+ struct Material {
+ RID self;
+ MaterialData *data = nullptr;
+ Shader *shader = nullptr;
+ //shortcut to shader data and type
+ ShaderType shader_type = SHADER_TYPE_MAX;
+ uint32_t shader_id = 0;
+ bool uniform_dirty = false;
+ bool texture_dirty = false;
+ HashMap<StringName, Variant> params;
+ int32_t priority = 0;
+ RID next_pass;
+ SelfList<Material> update_element;
+
+ Dependency dependency;
+
+ Material() :
+ update_element(this) {}
+ };
+
MaterialDataRequestFunction material_data_request_func[SHADER_TYPE_MAX];
mutable RID_Owner<Material, true> material_owner;
+ Material *get_material(RID p_rid) { return material_owner.get_or_null(p_rid); };
SelfList<Material>::List material_update_list;
@@ -358,7 +353,6 @@ public:
/* SHADER API */
- Shader *get_shader(RID p_rid) { return shader_owner.get_or_null(p_rid); };
bool owns_shader(RID p_rid) { return shader_owner.owns(p_rid); };
virtual RID shader_allocate() override;
@@ -368,7 +362,7 @@ public:
virtual void shader_set_code(RID p_shader, const String &p_code) override;
virtual void shader_set_path_hint(RID p_shader, const String &p_path) override;
virtual String shader_get_code(RID p_shader) const override;
- virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const override;
+ virtual void shader_get_shader_uniform_list(RID p_shader, List<PropertyInfo> *p_param_list) const override;
virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture, int p_index) override;
virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name, int p_index) const override;
@@ -379,7 +373,6 @@ public:
/* MATERIAL API */
- Material *get_material(RID p_rid) { return material_owner.get_or_null(p_rid); };
bool owns_material(RID p_rid) { return material_owner.owns(p_rid); };
void _material_queue_update(Material *material, bool p_uniform, bool p_texture);
@@ -390,6 +383,7 @@ public:
virtual void material_free(RID p_rid) override;
virtual void material_set_shader(RID p_material, RID p_shader) override;
+ ShaderData *material_get_shader_data(RID p_material);
virtual void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) override;
virtual Variant material_get_param(RID p_material, const StringName &p_param) const override;
@@ -400,7 +394,7 @@ public:
virtual bool material_is_animated(RID p_material) override;
virtual bool material_casts_shadows(RID p_material) override;
- virtual void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) override;
+ virtual void material_get_instance_shader_uniforms(RID p_material, List<InstanceShaderParam> *r_parameters) override;
virtual void material_update_dependency(RID p_material, DependencyTracker *p_instance) override;
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
index 3875eb6615..49d7198ec2 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
@@ -327,8 +327,10 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
bool use_as_storage = (p_surface.skin_data.size() || mesh->blend_shape_count > 0);
- s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.vertex_data.size(), p_surface.vertex_data, use_as_storage);
- s->vertex_buffer_size = p_surface.vertex_data.size();
+ if (p_surface.vertex_data.size()) {
+ s->vertex_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.vertex_data.size(), p_surface.vertex_data, use_as_storage);
+ s->vertex_buffer_size = p_surface.vertex_data.size();
+ }
if (p_surface.attribute_data.size()) {
s->attribute_buffer = RD::get_singleton()->vertex_buffer_create(p_surface.attribute_data.size(), p_surface.attribute_data);
@@ -345,7 +347,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
}
if (p_surface.index_count) {
- bool is_index_16 = p_surface.vertex_count <= 65536;
+ bool is_index_16 = p_surface.vertex_count <= 65536 && p_surface.vertex_count > 0;
s->index_buffer = RD::get_singleton()->index_buffer_create(p_surface.index_count, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, p_surface.index_data, false);
s->index_count = p_surface.index_count;
@@ -364,6 +366,8 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
}
}
+ ERR_FAIL_COND_MSG(!p_surface.index_count && !p_surface.vertex_count, "Meshes must contain a vertex array, an index array, or both");
+
s->aabb = p_surface.aabb;
s->bone_aabbs = p_surface.bone_aabbs; //only really useful for returning them.
@@ -377,7 +381,11 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
RD::Uniform u;
u.binding = 0;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.append_id(s->vertex_buffer);
+ if (s->vertex_buffer.is_valid()) {
+ u.append_id(s->vertex_buffer);
+ } else {
+ u.append_id(default_rd_storage_buffer);
+ }
uniforms.push_back(u);
}
{
@@ -416,7 +424,10 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
mesh->bone_aabbs.resize(p_surface.bone_aabbs.size());
}
for (int i = 0; i < p_surface.bone_aabbs.size(); i++) {
- mesh->bone_aabbs.write[i].merge_with(p_surface.bone_aabbs[i]);
+ const AABB &bone = p_surface.bone_aabbs[i];
+ if (!bone.has_no_volume()) {
+ mesh->bone_aabbs.write[i].merge_with(bone);
+ }
}
mesh->aabb.merge_with(p_surface.aabb);
}
@@ -467,6 +478,7 @@ void MeshStorage::mesh_surface_update_vertex_region(RID p_mesh, int p_surface, i
ERR_FAIL_COND(!mesh);
ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
ERR_FAIL_COND(p_data.size() == 0);
+ ERR_FAIL_COND(mesh->surfaces[p_surface]->vertex_buffer.is_null());
uint64_t data_size = p_data.size();
const uint8_t *r = p_data.ptr();
@@ -524,7 +536,9 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const {
RS::SurfaceData sd;
sd.format = s.format;
- sd.vertex_data = RD::get_singleton()->buffer_get_data(s.vertex_buffer);
+ if (s.vertex_buffer.is_valid()) {
+ sd.vertex_data = RD::get_singleton()->buffer_get_data(s.vertex_buffer);
+ }
if (s.attribute_buffer.is_valid()) {
sd.attribute_data = RD::get_singleton()->buffer_get_data(s.attribute_buffer);
}
@@ -702,7 +716,9 @@ void MeshStorage::mesh_clear(RID p_mesh) {
ERR_FAIL_COND(!mesh);
for (uint32_t i = 0; i < mesh->surface_count; i++) {
Mesh::Surface &s = *mesh->surfaces[i];
- RD::get_singleton()->free(s.vertex_buffer); //clears arrays as dependency automatically, including all versions
+ if (s.vertex_buffer.is_valid()) {
+ RD::get_singleton()->free(s.vertex_buffer); //clears arrays as dependency automatically, including all versions
+ }
if (s.attribute_buffer.is_valid()) {
RD::get_singleton()->free(s.attribute_buffer);
}
@@ -758,6 +774,13 @@ bool MeshStorage::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) {
return mesh->blend_shape_count > 0 || (mesh->has_bone_weights && p_has_skeleton);
}
+Dependency *MeshStorage::mesh_get_dependency(RID p_mesh) const {
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND_V(!mesh, nullptr);
+
+ return &mesh->dependency;
+}
+
/* MESH INSTANCE */
RID MeshStorage::mesh_instance_create(RID p_base) {
@@ -841,7 +864,7 @@ void MeshStorage::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint3
}
MeshInstance::Surface s;
- if (mesh->blend_shape_count > 0 || (mesh->surfaces[p_surface]->format & RS::ARRAY_FORMAT_BONES)) {
+ if ((mesh->blend_shape_count > 0 || (mesh->surfaces[p_surface]->format & RS::ARRAY_FORMAT_BONES)) && mesh->surfaces[p_surface]->vertex_buffer_size > 0) {
//surface warrants transform
s.vertex_buffer = RD::get_singleton()->vertex_buffer_create(mesh->surfaces[p_surface]->vertex_buffer_size, Vector<uint8_t>(), true);
@@ -1050,10 +1073,9 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
} break;
case RS::ARRAY_NORMAL: {
vd.offset = stride;
+ vd.format = RD::DATA_FORMAT_R16G16_UNORM;
+ stride += sizeof(uint16_t) * 2;
- vd.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32;
-
- stride += sizeof(uint32_t);
if (mis) {
buffer = mis->vertex_buffer;
} else {
@@ -1062,9 +1084,9 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
} break;
case RS::ARRAY_TANGENT: {
vd.offset = stride;
+ vd.format = RD::DATA_FORMAT_R16G16_UNORM;
+ stride += sizeof(uint16_t) * 2;
- vd.format = RD::DATA_FORMAT_A2B10G10R10_UNORM_PACK32;
- stride += sizeof(uint32_t);
if (mis) {
buffer = mis->vertex_buffer;
} else {
@@ -1473,6 +1495,13 @@ RID MeshStorage::multimesh_get_mesh(RID p_multimesh) const {
return multimesh->mesh;
}
+Dependency *MeshStorage::multimesh_get_dependency(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, nullptr);
+
+ return &multimesh->dependency;
+}
+
Transform3D MeshStorage::multimesh_instance_get_transform(RID p_multimesh, int p_index) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_COND_V(!multimesh, Transform3D());
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
index 396fe9b6a6..5c0d019c15 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
@@ -40,240 +40,151 @@
namespace RendererRD {
-/* Mesh */
-
-enum DefaultRDBuffer {
- DEFAULT_RD_BUFFER_VERTEX,
- DEFAULT_RD_BUFFER_NORMAL,
- DEFAULT_RD_BUFFER_TANGENT,
- DEFAULT_RD_BUFFER_COLOR,
- DEFAULT_RD_BUFFER_TEX_UV,
- DEFAULT_RD_BUFFER_TEX_UV2,
- DEFAULT_RD_BUFFER_CUSTOM0,
- DEFAULT_RD_BUFFER_CUSTOM1,
- DEFAULT_RD_BUFFER_CUSTOM2,
- DEFAULT_RD_BUFFER_CUSTOM3,
- DEFAULT_RD_BUFFER_BONES,
- DEFAULT_RD_BUFFER_WEIGHTS,
- DEFAULT_RD_BUFFER_MAX,
-};
+class MeshStorage : public RendererMeshStorage {
+public:
+ enum DefaultRDBuffer {
+ DEFAULT_RD_BUFFER_VERTEX,
+ DEFAULT_RD_BUFFER_NORMAL,
+ DEFAULT_RD_BUFFER_TANGENT,
+ DEFAULT_RD_BUFFER_COLOR,
+ DEFAULT_RD_BUFFER_TEX_UV,
+ DEFAULT_RD_BUFFER_TEX_UV2,
+ DEFAULT_RD_BUFFER_CUSTOM0,
+ DEFAULT_RD_BUFFER_CUSTOM1,
+ DEFAULT_RD_BUFFER_CUSTOM2,
+ DEFAULT_RD_BUFFER_CUSTOM3,
+ DEFAULT_RD_BUFFER_BONES,
+ DEFAULT_RD_BUFFER_WEIGHTS,
+ DEFAULT_RD_BUFFER_MAX,
+ };
-struct MeshInstance;
-
-struct Mesh {
- struct Surface {
- RS::PrimitiveType primitive = RS::PRIMITIVE_POINTS;
- uint32_t format = 0;
-
- RID vertex_buffer;
- RID attribute_buffer;
- RID skin_buffer;
- uint32_t vertex_count = 0;
- uint32_t vertex_buffer_size = 0;
- uint32_t skin_buffer_size = 0;
-
- // A different pipeline needs to be allocated
- // depending on the inputs available in the
- // material.
- // There are never that many geometry/material
- // combinations, so a simple array is the most
- // cache-efficient structure.
-
- struct Version {
- uint32_t input_mask = 0;
- RD::VertexFormatID vertex_format = 0;
- RID vertex_array;
- };
+private:
+ static MeshStorage *singleton;
- SpinLock version_lock; //needed to access versions
- Version *versions = nullptr; //allocated on demand
- uint32_t version_count = 0;
+ RID default_rd_storage_buffer;
- RID index_buffer;
- RID index_array;
- uint32_t index_count = 0;
+ /* Mesh */
- struct LOD {
- float edge_length = 0.0;
- uint32_t index_count = 0;
- RID index_buffer;
- RID index_array;
- };
+ RID mesh_default_rd_buffers[DEFAULT_RD_BUFFER_MAX];
- LOD *lods = nullptr;
- uint32_t lod_count = 0;
+ struct MeshInstance;
+
+ struct Mesh {
+ struct Surface {
+ RS::PrimitiveType primitive = RS::PRIMITIVE_POINTS;
+ uint32_t format = 0;
+
+ RID vertex_buffer;
+ RID attribute_buffer;
+ RID skin_buffer;
+ uint32_t vertex_count = 0;
+ uint32_t vertex_buffer_size = 0;
+ uint32_t skin_buffer_size = 0;
+
+ // A different pipeline needs to be allocated
+ // depending on the inputs available in the
+ // material.
+ // There are never that many geometry/material
+ // combinations, so a simple array is the most
+ // cache-efficient structure.
+
+ struct Version {
+ uint32_t input_mask = 0;
+ RD::VertexFormatID vertex_format = 0;
+ RID vertex_array;
+ };
+
+ SpinLock version_lock; //needed to access versions
+ Version *versions = nullptr; //allocated on demand
+ uint32_t version_count = 0;
- AABB aabb;
+ RID index_buffer;
+ RID index_array;
+ uint32_t index_count = 0;
- Vector<AABB> bone_aabbs;
+ struct LOD {
+ float edge_length = 0.0;
+ uint32_t index_count = 0;
+ RID index_buffer;
+ RID index_array;
+ };
- RID blend_shape_buffer;
+ LOD *lods = nullptr;
+ uint32_t lod_count = 0;
- RID material;
+ AABB aabb;
- uint32_t render_index = 0;
- uint64_t render_pass = 0;
+ Vector<AABB> bone_aabbs;
- uint32_t multimesh_render_index = 0;
- uint64_t multimesh_render_pass = 0;
+ RID blend_shape_buffer;
- uint32_t particles_render_index = 0;
- uint64_t particles_render_pass = 0;
+ RID material;
- RID uniform_set;
- };
+ uint32_t render_index = 0;
+ uint64_t render_pass = 0;
- uint32_t blend_shape_count = 0;
- RS::BlendShapeMode blend_shape_mode = RS::BLEND_SHAPE_MODE_NORMALIZED;
+ uint32_t multimesh_render_index = 0;
+ uint64_t multimesh_render_pass = 0;
- Surface **surfaces = nullptr;
- uint32_t surface_count = 0;
+ uint32_t particles_render_index = 0;
+ uint64_t particles_render_pass = 0;
- Vector<AABB> bone_aabbs;
+ RID uniform_set;
+ };
- bool has_bone_weights = false;
+ uint32_t blend_shape_count = 0;
+ RS::BlendShapeMode blend_shape_mode = RS::BLEND_SHAPE_MODE_NORMALIZED;
- AABB aabb;
- AABB custom_aabb;
+ Surface **surfaces = nullptr;
+ uint32_t surface_count = 0;
- Vector<RID> material_cache;
+ Vector<AABB> bone_aabbs;
- List<MeshInstance *> instances;
+ bool has_bone_weights = false;
- RID shadow_mesh;
- HashSet<Mesh *> shadow_owners;
+ AABB aabb;
+ AABB custom_aabb;
- Dependency dependency;
-};
+ Vector<RID> material_cache;
-/* Mesh Instance */
+ List<MeshInstance *> instances;
-struct MeshInstance {
- Mesh *mesh = nullptr;
- RID skeleton;
- struct Surface {
- RID vertex_buffer;
- RID uniform_set;
+ RID shadow_mesh;
+ HashSet<Mesh *> shadow_owners;
- Mesh::Surface::Version *versions = nullptr; //allocated on demand
- uint32_t version_count = 0;
+ Dependency dependency;
};
- LocalVector<Surface> surfaces;
- LocalVector<float> blend_weights;
-
- RID blend_weights_buffer;
- List<MeshInstance *>::Element *I = nullptr; //used to erase itself
- uint64_t skeleton_version = 0;
- bool dirty = false;
- bool weights_dirty = false;
- SelfList<MeshInstance> weight_update_list;
- SelfList<MeshInstance> array_update_list;
- MeshInstance() :
- weight_update_list(this), array_update_list(this) {}
-};
-
-/* MultiMesh */
-
-struct MultiMesh {
- RID mesh;
- int instances = 0;
- RS::MultimeshTransformFormat xform_format = RS::MULTIMESH_TRANSFORM_3D;
- bool uses_colors = false;
- bool uses_custom_data = false;
- int visible_instances = -1;
- AABB aabb;
- bool aabb_dirty = false;
- bool buffer_set = false;
- uint32_t stride_cache = 0;
- uint32_t color_offset_cache = 0;
- uint32_t custom_data_offset_cache = 0;
-
- Vector<float> data_cache; //used if individual setting is used
- bool *data_cache_dirty_regions = nullptr;
- uint32_t data_cache_used_dirty_regions = 0;
-
- RID buffer; //storage buffer
- RID uniform_set_3d;
- RID uniform_set_2d;
-
- bool dirty = false;
- MultiMesh *dirty_list = nullptr;
-
- Dependency dependency;
-};
-/* Skeleton */
-
-struct SkeletonShader {
- struct PushConstant {
- uint32_t has_normal;
- uint32_t has_tangent;
- uint32_t has_skeleton;
- uint32_t has_blend_shape;
+ mutable RID_Owner<Mesh, true> mesh_owner;
- uint32_t vertex_count;
- uint32_t vertex_stride;
- uint32_t skin_stride;
- uint32_t skin_weight_offset;
+ /* Mesh Instance API */
- uint32_t blend_shape_count;
- uint32_t normalized_blend_shapes;
- uint32_t pad0;
- uint32_t pad1;
- };
+ struct MeshInstance {
+ Mesh *mesh = nullptr;
+ RID skeleton;
+ struct Surface {
+ RID vertex_buffer;
+ RID uniform_set;
- enum {
- UNIFORM_SET_INSTANCE = 0,
- UNIFORM_SET_SURFACE = 1,
- UNIFORM_SET_SKELETON = 2,
- };
- enum {
- SHADER_MODE_2D,
- SHADER_MODE_3D,
- SHADER_MODE_MAX
+ Mesh::Surface::Version *versions = nullptr; //allocated on demand
+ uint32_t version_count = 0;
+ };
+ LocalVector<Surface> surfaces;
+ LocalVector<float> blend_weights;
+
+ RID blend_weights_buffer;
+ List<MeshInstance *>::Element *I = nullptr; //used to erase itself
+ uint64_t skeleton_version = 0;
+ bool dirty = false;
+ bool weights_dirty = false;
+ SelfList<MeshInstance> weight_update_list;
+ SelfList<MeshInstance> array_update_list;
+ MeshInstance() :
+ weight_update_list(this), array_update_list(this) {}
};
- SkeletonShaderRD shader;
- RID version;
- RID version_shader[SHADER_MODE_MAX];
- RID pipeline[SHADER_MODE_MAX];
-
- RID default_skeleton_uniform_set;
-};
-
-struct Skeleton {
- bool use_2d = false;
- int size = 0;
- Vector<float> data;
- RID buffer;
-
- bool dirty = false;
- Skeleton *dirty_list = nullptr;
- Transform2D base_transform_2d;
-
- RID uniform_set_3d;
- RID uniform_set_mi;
-
- uint64_t version = 1;
-
- Dependency dependency;
-};
-
-class MeshStorage : public RendererMeshStorage {
-private:
- static MeshStorage *singleton;
-
- RID mesh_default_rd_buffers[DEFAULT_RD_BUFFER_MAX];
- RID default_rd_storage_buffer;
-
- /* Mesh */
-
- mutable RID_Owner<Mesh, true> mesh_owner;
-
void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, MeshInstance::Surface *mis = nullptr);
- /* Mesh Instance API */
-
void _mesh_instance_clear(MeshInstance *mi);
void _mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface);
@@ -284,6 +195,34 @@ private:
/* MultiMesh */
+ struct MultiMesh {
+ RID mesh;
+ int instances = 0;
+ RS::MultimeshTransformFormat xform_format = RS::MULTIMESH_TRANSFORM_3D;
+ bool uses_colors = false;
+ bool uses_custom_data = false;
+ int visible_instances = -1;
+ AABB aabb;
+ bool aabb_dirty = false;
+ bool buffer_set = false;
+ uint32_t stride_cache = 0;
+ uint32_t color_offset_cache = 0;
+ uint32_t custom_data_offset_cache = 0;
+
+ Vector<float> data_cache; //used if individual setting is used
+ bool *data_cache_dirty_regions = nullptr;
+ uint32_t data_cache_used_dirty_regions = 0;
+
+ RID buffer; //storage buffer
+ RID uniform_set_3d;
+ RID uniform_set_2d;
+
+ bool dirty = false;
+ MultiMesh *dirty_list = nullptr;
+
+ Dependency dependency;
+ };
+
mutable RID_Owner<MultiMesh, true> multimesh_owner;
MultiMesh *multimesh_dirty_list = nullptr;
@@ -295,7 +234,60 @@ private:
/* Skeleton */
- SkeletonShader skeleton_shader;
+ struct SkeletonShader {
+ struct PushConstant {
+ uint32_t has_normal;
+ uint32_t has_tangent;
+ uint32_t has_skeleton;
+ uint32_t has_blend_shape;
+
+ uint32_t vertex_count;
+ uint32_t vertex_stride;
+ uint32_t skin_stride;
+ uint32_t skin_weight_offset;
+
+ uint32_t blend_shape_count;
+ uint32_t normalized_blend_shapes;
+ uint32_t pad0;
+ uint32_t pad1;
+ };
+
+ enum {
+ UNIFORM_SET_INSTANCE = 0,
+ UNIFORM_SET_SURFACE = 1,
+ UNIFORM_SET_SKELETON = 2,
+ };
+ enum {
+ SHADER_MODE_2D,
+ SHADER_MODE_3D,
+ SHADER_MODE_MAX
+ };
+
+ SkeletonShaderRD shader;
+ RID version;
+ RID version_shader[SHADER_MODE_MAX];
+ RID pipeline[SHADER_MODE_MAX];
+
+ RID default_skeleton_uniform_set;
+ } skeleton_shader;
+
+ struct Skeleton {
+ bool use_2d = false;
+ int size = 0;
+ Vector<float> data;
+ RID buffer;
+
+ bool dirty = false;
+ Skeleton *dirty_list = nullptr;
+ Transform2D base_transform_2d;
+
+ RID uniform_set_3d;
+ RID uniform_set_mi;
+
+ uint64_t version = 1;
+
+ Dependency dependency;
+ };
mutable RID_Owner<Skeleton, true> skeleton_owner;
@@ -309,11 +301,10 @@ public:
MeshStorage();
virtual ~MeshStorage();
- RID get_default_rd_storage_buffer() { return default_rd_storage_buffer; }
+ RID get_default_rd_storage_buffer() const { return default_rd_storage_buffer; }
/* MESH API */
- Mesh *get_mesh(RID p_rid) { return mesh_owner.get_or_null(p_rid); };
bool owns_mesh(RID p_rid) { return mesh_owner.owns(p_rid); };
virtual RID mesh_allocate() override;
@@ -542,10 +533,11 @@ public:
return s->particles_render_index;
}
+ Dependency *mesh_get_dependency(RID p_mesh) const;
+
/* MESH INSTANCE API */
- MeshInstance *get_mesh_instance(RID p_rid) { return mesh_instance_owner.get_or_null(p_rid); };
- bool owns_mesh_instance(RID p_rid) { return mesh_instance_owner.owns(p_rid); };
+ bool owns_mesh_instance(RID p_rid) const { return mesh_instance_owner.owns(p_rid); };
virtual RID mesh_instance_create(RID p_base) override;
virtual void mesh_instance_free(RID p_rid) override;
@@ -556,7 +548,6 @@ public:
/* MULTIMESH API */
- MultiMesh *get_multimesh(RID p_rid) { return multimesh_owner.get_or_null(p_rid); };
bool owns_multimesh(RID p_rid) { return multimesh_owner.owns(p_rid); };
virtual RID multimesh_allocate() override;
@@ -654,10 +645,11 @@ public:
return multimesh->uniform_set_2d;
}
+ Dependency *multimesh_get_dependency(RID p_multimesh) const;
+
/* SKELETON API */
- Skeleton *get_skeleton(RID p_rid) { return skeleton_owner.get_or_null(p_rid); };
- bool owns_skeleton(RID p_rid) { return skeleton_owner.owns(p_rid); };
+ bool owns_skeleton(RID p_rid) const { return skeleton_owner.owns(p_rid); };
virtual RID skeleton_allocate() override;
virtual void skeleton_initialize(RID p_skeleton) override;
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
index 1e5511eeda..022b027644 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
@@ -54,8 +54,8 @@ ParticlesStorage::ParticlesStorage() {
particles_modes.push_back("");
particles_shader.shader.initialize(particles_modes, String());
}
- MaterialStorage::get_singleton()->shader_set_data_request_function(SHADER_TYPE_PARTICLES, _create_particles_shader_funcs);
- MaterialStorage::get_singleton()->material_set_data_request_function(SHADER_TYPE_PARTICLES, _create_particles_material_funcs);
+ MaterialStorage::get_singleton()->shader_set_data_request_function(MaterialStorage::SHADER_TYPE_PARTICLES, _create_particles_shader_funcs);
+ MaterialStorage::get_singleton()->material_set_data_request_function(MaterialStorage::SHADER_TYPE_PARTICLES, _create_particles_material_funcs);
{
ShaderCompiler::DefaultIdentifierActions actions;
@@ -134,7 +134,7 @@ void process() {
material_storage->material_initialize(particles_shader.default_material);
material_storage->material_set_shader(particles_shader.default_material, particles_shader.default_shader);
- ParticlesMaterialData *md = static_cast<ParticlesMaterialData *>(material_storage->material_get_data(particles_shader.default_material, SHADER_TYPE_PARTICLES));
+ ParticleProcessMaterialData *md = static_cast<ParticleProcessMaterialData *>(material_storage->material_get_data(particles_shader.default_material, MaterialStorage::SHADER_TYPE_PARTICLES));
particles_shader.default_shader_rd = particles_shader.shader.version_get_shader(md->shader_data->version, 0);
Vector<RD::Uniform> uniforms;
@@ -987,14 +987,13 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
for (uint32_t i = 0; i < ParticlesFrameParams::MAX_3D_TEXTURES; i++) {
RID rd_tex;
if (i < collision_3d_textures_used) {
- Texture *t = TextureStorage::get_singleton()->get_texture(collision_3d_textures[i]);
- if (t && t->type == Texture::TYPE_3D) {
- rd_tex = t->rd_texture;
+ if (TextureStorage::get_singleton()->texture_get_type(collision_3d_textures[i]) == TextureStorage::TYPE_3D) {
+ rd_tex = TextureStorage::get_singleton()->texture_get_rd_texture(collision_3d_textures[i]);
}
}
if (rd_tex == RID()) {
- rd_tex = texture_storage->texture_rd_get_default(DEFAULT_RD_TEXTURE_3D_WHITE);
+ rd_tex = texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
}
u.append_id(rd_tex);
}
@@ -1007,7 +1006,7 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
if (collision_heightmap_texture.is_valid()) {
u.append_id(collision_heightmap_texture);
} else {
- u.append_id(texture_storage->texture_rd_get_default(DEFAULT_RD_TEXTURE_BLACK));
+ u.append_id(texture_storage->texture_rd_get_default(TextureStorage::DEFAULT_RD_TEXTURE_BLACK));
}
uniforms.push_back(u);
}
@@ -1073,9 +1072,9 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
RD::get_singleton()->buffer_update(p_particles->frame_params_buffer, 0, sizeof(ParticlesFrameParams) * p_particles->trail_params.size(), p_particles->trail_params.ptr());
- ParticlesMaterialData *m = static_cast<ParticlesMaterialData *>(material_storage->material_get_data(p_particles->process_material, SHADER_TYPE_PARTICLES));
+ ParticleProcessMaterialData *m = static_cast<ParticleProcessMaterialData *>(material_storage->material_get_data(p_particles->process_material, MaterialStorage::SHADER_TYPE_PARTICLES));
if (!m) {
- m = static_cast<ParticlesMaterialData *>(material_storage->material_get_data(particles_shader.default_material, SHADER_TYPE_PARTICLES));
+ m = static_cast<ParticleProcessMaterialData *>(material_storage->material_get_data(particles_shader.default_material, MaterialStorage::SHADER_TYPE_PARTICLES));
}
ERR_FAIL_COND(!m);
@@ -1228,10 +1227,10 @@ void ParticlesStorage::particles_set_view_axis(RID p_particles, const Vector3 &p
void ParticlesStorage::_particles_update_buffers(Particles *particles) {
uint32_t userdata_count = 0;
- const Material *material = MaterialStorage::get_singleton()->get_material(particles->process_material);
- if (material && material->shader && material->shader->data) {
- const ParticlesShaderData *shader_data = static_cast<const ParticlesShaderData *>(material->shader->data);
- userdata_count = shader_data->userdata_count;
+ MaterialStorage::ShaderData *shader_data = MaterialStorage::get_singleton()->material_get_shader_data(particles->process_material);
+ if (shader_data) {
+ const ParticlesShaderData *particle_shader_data = static_cast<const ParticlesShaderData *>(shader_data);
+ userdata_count = particle_shader_data->userdata_count;
}
if (userdata_count != particles->userdata_count) {
@@ -1503,6 +1502,13 @@ void ParticlesStorage::update_particles() {
}
}
+Dependency *ParticlesStorage::particles_get_dependency(RID p_particles) const {
+ Particles *particles = particles_owner.get_or_null(p_particles);
+ ERR_FAIL_NULL_V(particles, nullptr);
+
+ return &particles->dependency;
+}
+
bool ParticlesStorage::particles_is_inactive(RID p_particles) const {
ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer.");
const Particles *particles = particles_owner.get_or_null(p_particles);
@@ -1597,7 +1603,7 @@ void ParticlesStorage::ParticlesShaderData::set_default_texture_param(const Stri
}
}
-void ParticlesStorage::ParticlesShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+void ParticlesStorage::ParticlesShaderData::get_shader_uniform_list(List<PropertyInfo> *p_param_list) const {
HashMap<int, StringName> order;
for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
@@ -1685,21 +1691,21 @@ ParticlesStorage::ParticlesShaderData::~ParticlesShaderData() {
}
}
-ShaderData *ParticlesStorage::_create_particles_shader_func() {
+MaterialStorage::ShaderData *ParticlesStorage::_create_particles_shader_func() {
ParticlesShaderData *shader_data = memnew(ParticlesShaderData);
return shader_data;
}
-bool ParticlesStorage::ParticlesMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+bool ParticlesStorage::ParticleProcessMaterialData::update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, ParticlesStorage::get_singleton()->particles_shader.shader.version_get_shader(shader_data->version, 0), 3);
}
-ParticlesStorage::ParticlesMaterialData::~ParticlesMaterialData() {
+ParticlesStorage::ParticleProcessMaterialData::~ParticleProcessMaterialData() {
free_parameters_uniform_set(uniform_set);
}
-MaterialData *ParticlesStorage::_create_particles_material_func(ParticlesShaderData *p_shader) {
- ParticlesMaterialData *material_data = memnew(ParticlesMaterialData);
+MaterialStorage::MaterialData *ParticlesStorage::_create_particles_material_func(ParticlesShaderData *p_shader) {
+ ParticleProcessMaterialData *material_data = memnew(ParticleProcessMaterialData);
material_data->shader_data = p_shader;
//update will happen later anyway so do nothing.
return material_data;
@@ -1884,6 +1890,15 @@ bool ParticlesStorage::particles_collision_is_heightfield(RID p_particles_collis
return particles_collision->type == RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE;
}
+Dependency *ParticlesStorage::particles_collision_get_dependency(RID p_particles_collision) const {
+ ParticlesCollision *pc = particles_collision_owner.get_or_null(p_particles_collision);
+ ERR_FAIL_NULL_V(pc, nullptr);
+
+ return &pc->dependency;
+}
+
+/* Particles collision instance */
+
RID ParticlesStorage::particles_collision_instance_create(RID p_collision) {
ParticlesCollisionInstance pci;
pci.collision = p_collision;
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
index 75f995deeb..299fdc6ec8 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
@@ -43,231 +43,203 @@
namespace RendererRD {
-/* PARTICLES */
-
-struct ParticleData {
- float xform[16];
- float velocity[3];
- uint32_t active;
- float color[4];
- float custom[3];
- float lifetime;
-};
+class ParticlesStorage : public RendererParticlesStorage {
+private:
+ static ParticlesStorage *singleton;
-struct ParticlesFrameParams {
- enum {
- MAX_ATTRACTORS = 32,
- MAX_COLLIDERS = 32,
- MAX_3D_TEXTURES = 7
- };
+ /* PARTICLES */
- enum AttractorType {
- ATTRACTOR_TYPE_SPHERE,
- ATTRACTOR_TYPE_BOX,
- ATTRACTOR_TYPE_VECTOR_FIELD,
+ struct ParticleData {
+ float xform[16];
+ float velocity[3];
+ uint32_t active;
+ float color[4];
+ float custom[3];
+ float lifetime;
};
- struct Attractor {
- float transform[16];
- float extents[3]; //exents or radius
- uint32_t type;
+ struct ParticlesFrameParams {
+ enum {
+ MAX_ATTRACTORS = 32,
+ MAX_COLLIDERS = 32,
+ MAX_3D_TEXTURES = 7
+ };
- uint32_t texture_index; //texture index for vector field
- float strength;
- float attenuation;
- float directionality;
- };
+ enum AttractorType {
+ ATTRACTOR_TYPE_SPHERE,
+ ATTRACTOR_TYPE_BOX,
+ ATTRACTOR_TYPE_VECTOR_FIELD,
+ };
- enum CollisionType {
- COLLISION_TYPE_SPHERE,
- COLLISION_TYPE_BOX,
- COLLISION_TYPE_SDF,
- COLLISION_TYPE_HEIGHT_FIELD,
- COLLISION_TYPE_2D_SDF,
+ struct Attractor {
+ float transform[16];
+ float extents[3]; //exents or radius
+ uint32_t type;
- };
+ uint32_t texture_index; //texture index for vector field
+ float strength;
+ float attenuation;
+ float directionality;
+ };
- struct Collider {
- float transform[16];
- float extents[3]; //exents or radius
- uint32_t type;
+ enum CollisionType {
+ COLLISION_TYPE_SPHERE,
+ COLLISION_TYPE_BOX,
+ COLLISION_TYPE_SDF,
+ COLLISION_TYPE_HEIGHT_FIELD,
+ COLLISION_TYPE_2D_SDF,
- uint32_t texture_index; //texture index for vector field
- real_t scale;
- uint32_t pad[2];
- };
+ };
- uint32_t emitting;
- float system_phase;
- float prev_system_phase;
- uint32_t cycle;
+ struct Collider {
+ float transform[16];
+ float extents[3]; //exents or radius
+ uint32_t type;
- real_t explosiveness;
- real_t randomness;
- float time;
- float delta;
+ uint32_t texture_index; //texture index for vector field
+ real_t scale;
+ uint32_t pad[2];
+ };
- uint32_t frame;
- uint32_t pad0;
- uint32_t pad1;
- uint32_t pad2;
+ uint32_t emitting;
+ float system_phase;
+ float prev_system_phase;
+ uint32_t cycle;
- uint32_t random_seed;
- uint32_t attractor_count;
- uint32_t collider_count;
- float particle_size;
+ real_t explosiveness;
+ real_t randomness;
+ float time;
+ float delta;
- float emission_transform[16];
+ uint32_t frame;
+ uint32_t pad0;
+ uint32_t pad1;
+ uint32_t pad2;
- Attractor attractors[MAX_ATTRACTORS];
- Collider colliders[MAX_COLLIDERS];
-};
+ uint32_t random_seed;
+ uint32_t attractor_count;
+ uint32_t collider_count;
+ float particle_size;
-struct ParticleEmissionBufferData {
-};
+ float emission_transform[16];
-struct ParticleEmissionBuffer {
- struct Data {
- float xform[16];
- float velocity[3];
- uint32_t flags;
- float color[4];
- float custom[4];
+ Attractor attractors[MAX_ATTRACTORS];
+ Collider colliders[MAX_COLLIDERS];
};
- 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 {
- RS::ParticlesMode mode = RS::PARTICLES_MODE_3D;
- bool inactive = true;
- double inactive_time = 0.0;
- bool emitting = false;
- bool one_shot = false;
- int amount = 0;
- double lifetime = 1.0;
- double pre_process_time = 0.0;
- real_t explosiveness = 0.0;
- real_t randomness = 0.0;
- bool restart_request = false;
- AABB custom_aabb = AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8));
- bool use_local_coords = true;
- bool has_collision_cache = false;
-
- bool has_sdf_collision = false;
- Transform2D sdf_collision_transform;
- Rect2 sdf_collision_to_screen;
- RID sdf_collision_texture;
-
- RID process_material;
- uint32_t frame_counter = 0;
- RS::ParticlesTransformAlign transform_align = RS::PARTICLES_TRANSFORM_ALIGN_DISABLED;
-
- RS::ParticlesDrawOrder draw_order = RS::PARTICLES_DRAW_ORDER_INDEX;
-
- Vector<RID> draw_passes;
- Vector<Transform3D> trail_bind_poses;
- bool trail_bind_poses_dirty = false;
- RID trail_bind_pose_buffer;
- RID trail_bind_pose_uniform_set;
-
- RID particle_buffer;
- RID particle_instance_buffer;
- RID frame_params_buffer;
-
- uint32_t userdata_count = 0;
-
- RID particles_material_uniform_set;
- RID particles_copy_uniform_set;
- RID particles_transforms_buffer_uniform_set;
- RID collision_textures_uniform_set;
-
- RID collision_3d_textures[ParticlesFrameParams::MAX_3D_TEXTURES];
- uint32_t collision_3d_textures_used = 0;
- RID collision_heightmap_texture;
+ struct ParticleEmissionBufferData {
+ };
- RID particles_sort_buffer;
- RID particles_sort_uniform_set;
+ struct ParticleEmissionBuffer {
+ struct Data {
+ float xform[16];
+ float velocity[3];
+ uint32_t flags;
+ float color[4];
+ float custom[4];
+ };
- bool dirty = false;
- Particles *update_list = nullptr;
+ 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++
+ };
- RID sub_emitter;
+ struct Particles {
+ RS::ParticlesMode mode = RS::PARTICLES_MODE_3D;
+ bool inactive = true;
+ double inactive_time = 0.0;
+ bool emitting = false;
+ bool one_shot = false;
+ int amount = 0;
+ double lifetime = 1.0;
+ double pre_process_time = 0.0;
+ real_t explosiveness = 0.0;
+ real_t randomness = 0.0;
+ bool restart_request = false;
+ AABB custom_aabb = AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8));
+ bool use_local_coords = false;
+ bool has_collision_cache = false;
+
+ bool has_sdf_collision = false;
+ Transform2D sdf_collision_transform;
+ Rect2 sdf_collision_to_screen;
+ RID sdf_collision_texture;
+
+ RID process_material;
+ uint32_t frame_counter = 0;
+ RS::ParticlesTransformAlign transform_align = RS::PARTICLES_TRANSFORM_ALIGN_DISABLED;
+
+ RS::ParticlesDrawOrder draw_order = RS::PARTICLES_DRAW_ORDER_INDEX;
+
+ Vector<RID> draw_passes;
+ Vector<Transform3D> trail_bind_poses;
+ bool trail_bind_poses_dirty = false;
+ RID trail_bind_pose_buffer;
+ RID trail_bind_pose_uniform_set;
+
+ RID particle_buffer;
+ RID particle_instance_buffer;
+ RID frame_params_buffer;
- double phase = 0.0;
- double prev_phase = 0.0;
- uint64_t prev_ticks = 0;
- uint32_t random_seed = 0;
+ uint32_t userdata_count = 0;
- uint32_t cycle_number = 0;
+ RID particles_material_uniform_set;
+ RID particles_copy_uniform_set;
+ RID particles_transforms_buffer_uniform_set;
+ RID collision_textures_uniform_set;
- double speed_scale = 1.0;
+ RID collision_3d_textures[ParticlesFrameParams::MAX_3D_TEXTURES];
+ uint32_t collision_3d_textures_used = 0;
+ RID collision_heightmap_texture;
- int fixed_fps = 30;
- bool interpolate = true;
- bool fractional_delta = false;
- double frame_remainder = 0;
- real_t collision_base_size = 0.01;
+ RID particles_sort_buffer;
+ RID particles_sort_uniform_set;
- bool clear = true;
+ bool dirty = false;
+ Particles *update_list = nullptr;
- bool force_sub_emit = false;
+ RID sub_emitter;
- Transform3D emission_transform;
+ double phase = 0.0;
+ double prev_phase = 0.0;
+ uint64_t prev_ticks = 0;
+ uint32_t random_seed = 0;
- Vector<uint8_t> emission_buffer_data;
+ uint32_t cycle_number = 0;
- ParticleEmissionBuffer *emission_buffer = nullptr;
- RID emission_storage_buffer;
+ double speed_scale = 1.0;
- HashSet<RID> collisions;
+ int fixed_fps = 30;
+ bool interpolate = true;
+ bool fractional_delta = false;
+ double frame_remainder = 0;
+ real_t collision_base_size = 0.01;
- Dependency dependency;
+ bool clear = true;
- double trail_length = 1.0;
- bool trails_enabled = false;
- LocalVector<ParticlesFrameParams> frame_history;
- LocalVector<ParticlesFrameParams> trail_params;
+ bool force_sub_emit = false;
- Particles() {
- }
-};
+ Transform3D emission_transform;
-/* Particles Collision */
+ Vector<uint8_t> emission_buffer_data;
-struct ParticlesCollision {
- RS::ParticlesCollisionType type = RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT;
- uint32_t cull_mask = 0xFFFFFFFF;
- float radius = 1.0;
- Vector3 extents = Vector3(1, 1, 1);
- float attractor_strength = 1.0;
- float attractor_attenuation = 1.0;
- float attractor_directionality = 0.0;
- RID field_texture;
- RID heightfield_texture;
- RID heightfield_fb;
- Size2i heightfield_fb_size;
+ ParticleEmissionBuffer *emission_buffer = nullptr;
+ RID emission_storage_buffer;
- RS::ParticlesCollisionHeightfieldResolution heightfield_resolution = RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_1024;
+ HashSet<RID> collisions;
- Dependency dependency;
-};
+ Dependency dependency;
-struct ParticlesCollisionInstance {
- RID collision;
- Transform3D transform;
- bool active = false;
-};
+ double trail_length = 1.0;
+ bool trails_enabled = false;
+ LocalVector<ParticlesFrameParams> frame_history;
+ LocalVector<ParticlesFrameParams> trail_params;
-class ParticlesStorage : public RendererParticlesStorage {
-private:
- static ParticlesStorage *singleton;
-
- /* PARTICLES */
+ Particles() {
+ }
+ };
void _particles_process(Particles *p_particles, double p_delta);
void _particles_allocate_emission_buffer(Particles *particles);
@@ -340,7 +312,7 @@ private:
/* Particle Shader */
- struct ParticlesShaderData : public ShaderData {
+ struct ParticlesShaderData : public MaterialStorage::ShaderData {
bool valid = false;
RID version;
bool uses_collision = false;
@@ -365,7 +337,7 @@ private:
virtual void set_code(const String &p_Code);
virtual void set_path_hint(const String &p_hint);
virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
- virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_shader_uniform_list(List<PropertyInfo> *p_param_list) const;
virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
virtual bool is_param_texture(const StringName &p_param) const;
virtual bool is_animated() const;
@@ -377,28 +349,52 @@ private:
virtual ~ParticlesShaderData();
};
- ShaderData *_create_particles_shader_func();
- static ShaderData *_create_particles_shader_funcs() {
+ MaterialStorage::ShaderData *_create_particles_shader_func();
+ static MaterialStorage::ShaderData *_create_particles_shader_funcs() {
return ParticlesStorage::get_singleton()->_create_particles_shader_func();
}
- struct ParticlesMaterialData : public MaterialData {
+ struct ParticleProcessMaterialData : public MaterialStorage::MaterialData {
ParticlesShaderData *shader_data = nullptr;
RID uniform_set;
virtual void set_render_priority(int p_priority) {}
virtual void set_next_pass(RID p_pass) {}
virtual bool update_parameters(const HashMap<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
- virtual ~ParticlesMaterialData();
+ virtual ~ParticleProcessMaterialData();
};
- MaterialData *_create_particles_material_func(ParticlesShaderData *p_shader);
- static MaterialData *_create_particles_material_funcs(ShaderData *p_shader) {
+ MaterialStorage::MaterialData *_create_particles_material_func(ParticlesShaderData *p_shader);
+ static MaterialStorage::MaterialData *_create_particles_material_funcs(MaterialStorage::ShaderData *p_shader) {
return ParticlesStorage::get_singleton()->_create_particles_material_func(static_cast<ParticlesShaderData *>(p_shader));
}
/* Particles Collision */
+ struct ParticlesCollision {
+ RS::ParticlesCollisionType type = RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT;
+ uint32_t cull_mask = 0xFFFFFFFF;
+ float radius = 1.0;
+ Vector3 extents = Vector3(1, 1, 1);
+ float attractor_strength = 1.0;
+ float attractor_attenuation = 1.0;
+ float attractor_directionality = 0.0;
+ RID field_texture;
+ RID heightfield_texture;
+ RID heightfield_fb;
+ Size2i heightfield_fb_size;
+
+ RS::ParticlesCollisionHeightfieldResolution heightfield_resolution = RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_1024;
+
+ Dependency dependency;
+ };
+
+ struct ParticlesCollisionInstance {
+ RID collision;
+ Transform3D transform;
+ bool active = false;
+ };
+
mutable RID_Owner<ParticlesCollision, true> particles_collision_owner;
mutable RID_Owner<ParticlesCollisionInstance> particles_collision_instance_owner;
@@ -411,7 +407,6 @@ public:
/* PARTICLES */
- Particles *get_particles(RID p_rid) { return particles_owner.get_or_null(p_rid); }
bool owns_particles(RID p_rid) { return particles_owner.owns(p_rid); }
virtual RID particles_allocate() override;
@@ -526,9 +521,10 @@ public:
virtual void update_particles() override;
+ Dependency *particles_get_dependency(RID p_particles) const;
+
/* Particles Collision */
- ParticlesCollision *get_particles_collision(RID p_rid) { return particles_collision_owner.get_or_null(p_rid); }
bool owns_particles_collision(RID p_rid) { return particles_collision_owner.owns(p_rid); }
virtual RID particles_collision_allocate() override;
@@ -550,8 +546,9 @@ public:
virtual bool particles_collision_is_heightfield(RID p_particles_collision) const override;
virtual RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const override;
+ Dependency *particles_collision_get_dependency(RID p_particles) const;
+
//used from 2D and 3D
- ParticlesCollisionInstance *get_particles_collision_instance(RID p_rid) { return particles_collision_instance_owner.get_or_null(p_rid); }
bool owns_particles_collision_instance(RID p_rid) { return particles_collision_instance_owner.owns(p_rid); }
virtual RID particles_collision_instance_create(RID p_collision) override;
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index 6d7ea5184a..84427e1c93 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
@@ -35,9 +35,9 @@
using namespace RendererRD;
///////////////////////////////////////////////////////////////////////////
-// CanvasTexture
+// TextureStorage::CanvasTexture
-void CanvasTexture::clear_sets() {
+void TextureStorage::CanvasTexture::clear_sets() {
if (cleared_cache) {
return;
}
@@ -52,14 +52,14 @@ void CanvasTexture::clear_sets() {
cleared_cache = true;
}
-CanvasTexture::~CanvasTexture() {
+TextureStorage::CanvasTexture::~CanvasTexture() {
clear_sets();
}
///////////////////////////////////////////////////////////////////////////
-// Texture
+// TextureStorage::Texture
-void Texture::cleanup() {
+void TextureStorage::Texture::cleanup() {
if (RD::get_singleton()->texture_is_valid(rd_texture_srgb)) {
//erase this first, as it's a dependency of the one below
RD::get_singleton()->free(rd_texture_srgb);
@@ -96,6 +96,7 @@ TextureStorage::TextureStorage() {
Vector<uint8_t> pv;
pv.resize(16 * 4);
for (int i = 0; i < 16; i++) {
+ // Opaque white.
pv.set(i * 4 + 0, 255);
pv.set(i * 4 + 1, 255);
pv.set(i * 4 + 2, 255);
@@ -109,6 +110,7 @@ TextureStorage::TextureStorage() {
}
for (int i = 0; i < 16; i++) {
+ // Opaque black.
pv.set(i * 4 + 0, 0);
pv.set(i * 4 + 1, 0);
pv.set(i * 4 + 2, 0);
@@ -122,6 +124,21 @@ TextureStorage::TextureStorage() {
}
for (int i = 0; i < 16; i++) {
+ // Transparent black.
+ pv.set(i * 4 + 0, 0);
+ pv.set(i * 4 + 1, 0);
+ pv.set(i * 4 + 2, 0);
+ pv.set(i * 4 + 3, 0);
+ }
+
+ {
+ Vector<Vector<uint8_t>> vpv;
+ vpv.push_back(pv);
+ default_rd_textures[DEFAULT_RD_TEXTURE_TRANSPARENT] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ }
+
+ for (int i = 0; i < 16; i++) {
+ // Opaque normal map "flat" color.
pv.set(i * 4 + 0, 128);
pv.set(i * 4 + 1, 128);
pv.set(i * 4 + 2, 255);
@@ -135,6 +152,7 @@ TextureStorage::TextureStorage() {
}
for (int i = 0; i < 16; i++) {
+ // Opaque flowmap "flat" color.
pv.set(i * 4 + 0, 255);
pv.set(i * 4 + 1, 128);
pv.set(i * 4 + 2, 255);
@@ -398,7 +416,10 @@ TextureStorage::TextureStorage() {
tformat.format = RD::DATA_FORMAT_R8_UINT;
tformat.width = 4;
tformat.height = 4;
- tformat.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_VRS_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
+ tformat.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
+ if (RD::get_singleton()->has_feature(RD::SUPPORTS_ATTACHMENT_VRS)) {
+ tformat.usage_bits |= RD::TEXTURE_USAGE_VRS_ATTACHMENT_BIT;
+ }
tformat.texture_type = RD::TEXTURE_TYPE_2D;
Vector<uint8_t> pv;
@@ -534,7 +555,7 @@ bool TextureStorage::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasIte
ct = t->canvas_texture;
} else {
- ct = get_canvas_texture(p_texture);
+ ct = canvas_texture_owner.get_or_null(p_texture);
}
if (!ct) {
@@ -657,7 +678,7 @@ void TextureStorage::texture_2d_initialize(RID p_texture, const Ref<Image> &p_im
Texture texture;
- texture.type = Texture::TYPE_2D;
+ texture.type = TextureStorage::TYPE_2D;
texture.width = p_image->get_width();
texture.height = p_image->get_height();
@@ -753,7 +774,7 @@ void TextureStorage::texture_2d_layered_initialize(RID p_texture, const Vector<R
Texture texture;
- texture.type = Texture::TYPE_LAYERED;
+ texture.type = TextureStorage::TYPE_LAYERED;
texture.layered_type = p_layered_type;
texture.width = p_layers[0]->get_width();
@@ -883,7 +904,7 @@ void TextureStorage::texture_3d_initialize(RID p_texture, Image::Format p_format
Texture texture;
- texture.type = Texture::TYPE_3D;
+ texture.type = TextureStorage::TYPE_3D;
texture.width = p_width;
texture.height = p_height;
texture.depth = p_depth;
@@ -975,7 +996,7 @@ void TextureStorage::_texture_2d_update(RID p_texture, const Ref<Image> &p_image
ERR_FAIL_COND(p_image->get_width() != tex->width || p_image->get_height() != tex->height);
ERR_FAIL_COND(p_image->get_format() != tex->format);
- if (tex->type == Texture::TYPE_LAYERED) {
+ if (tex->type == TextureStorage::TYPE_LAYERED) {
ERR_FAIL_INDEX(p_layer, tex->layers);
}
@@ -995,7 +1016,7 @@ void TextureStorage::texture_2d_update(RID p_texture, const Ref<Image> &p_image,
void TextureStorage::texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) {
Texture *tex = texture_owner.get_or_null(p_texture);
ERR_FAIL_COND(!tex);
- ERR_FAIL_COND(tex->type != Texture::TYPE_3D);
+ ERR_FAIL_COND(tex->type != TextureStorage::TYPE_3D);
Image::Image3DValidateError verr = Image::validate_3d_image(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps > 1, p_data);
if (verr != Image::VALIDATE_3D_OK) {
@@ -1167,7 +1188,7 @@ Ref<Image> TextureStorage::texture_2d_layer_get(RID p_texture, int p_layer) cons
Vector<Ref<Image>> TextureStorage::texture_3d_get(RID p_texture) const {
Texture *tex = texture_owner.get_or_null(p_texture);
ERR_FAIL_COND_V(!tex, Vector<Ref<Image>>());
- ERR_FAIL_COND_V(tex->type != Texture::TYPE_3D, Vector<Ref<Image>>());
+ ERR_FAIL_COND_V(tex->type != TextureStorage::TYPE_3D, Vector<Ref<Image>>());
Vector<uint8_t> all_data = RD::get_singleton()->texture_get_data(tex->rd_texture, 0);
@@ -1243,7 +1264,7 @@ void TextureStorage::texture_replace(RID p_texture, RID p_by_texture) {
void TextureStorage::texture_set_size_override(RID p_texture, int p_width, int p_height) {
Texture *tex = texture_owner.get_or_null(p_texture);
ERR_FAIL_COND(!tex);
- ERR_FAIL_COND(tex->type != Texture::TYPE_2D);
+ ERR_FAIL_COND(tex->type != TextureStorage::TYPE_2D);
tex->width_2d = p_width;
tex->height_2d = p_height;
@@ -1855,6 +1876,13 @@ AABB TextureStorage::decal_get_aabb(RID p_decal) const {
return AABB(-decal->extents, decal->extents * 2.0);
}
+Dependency *TextureStorage::decal_get_dependency(RID p_decal) {
+ Decal *decal = decal_owner.get_or_null(p_decal);
+ ERR_FAIL_COND_V(!decal, nullptr);
+
+ return &decal->dependency;
+}
+
void TextureStorage::update_decal_atlas() {
RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton();
ERR_FAIL_NULL(copy_effects);
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
index 1eb4a283ca..682c951f63 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
@@ -38,248 +38,133 @@
namespace RendererRD {
-enum DefaultRDTexture {
- DEFAULT_RD_TEXTURE_WHITE,
- DEFAULT_RD_TEXTURE_BLACK,
- DEFAULT_RD_TEXTURE_NORMAL,
- DEFAULT_RD_TEXTURE_ANISO,
- DEFAULT_RD_TEXTURE_DEPTH,
- DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER,
- DEFAULT_RD_TEXTURE_CUBEMAP_BLACK,
- DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK,
- DEFAULT_RD_TEXTURE_CUBEMAP_WHITE,
- DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_WHITE,
- DEFAULT_RD_TEXTURE_3D_WHITE,
- DEFAULT_RD_TEXTURE_3D_BLACK,
- DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE,
- DEFAULT_RD_TEXTURE_2D_UINT,
- DEFAULT_RD_TEXTURE_VRS,
- DEFAULT_RD_TEXTURE_MAX
-};
+class LightStorage;
+class MaterialStorage;
-class CanvasTexture {
+class TextureStorage : public RendererTextureStorage {
public:
- RID diffuse;
- RID normal_map;
- RID specular;
- Color specular_color = Color(1, 1, 1, 1);
- float shininess = 1.0;
-
- RS::CanvasItemTextureFilter texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;
- RS::CanvasItemTextureRepeat texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;
- RID uniform_sets[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
-
- Size2i size_cache = Size2i(1, 1);
- bool use_normal_cache = false;
- bool use_specular_cache = false;
- bool cleared_cache = true;
-
- void clear_sets();
- ~CanvasTexture();
-};
+ enum DefaultRDTexture {
+ DEFAULT_RD_TEXTURE_WHITE,
+ DEFAULT_RD_TEXTURE_BLACK,
+ DEFAULT_RD_TEXTURE_TRANSPARENT,
+ DEFAULT_RD_TEXTURE_NORMAL,
+ DEFAULT_RD_TEXTURE_ANISO,
+ DEFAULT_RD_TEXTURE_DEPTH,
+ DEFAULT_RD_TEXTURE_MULTIMESH_BUFFER,
+ DEFAULT_RD_TEXTURE_CUBEMAP_BLACK,
+ DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK,
+ DEFAULT_RD_TEXTURE_CUBEMAP_WHITE,
+ DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_WHITE,
+ DEFAULT_RD_TEXTURE_3D_WHITE,
+ DEFAULT_RD_TEXTURE_3D_BLACK,
+ DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE,
+ DEFAULT_RD_TEXTURE_2D_UINT,
+ DEFAULT_RD_TEXTURE_VRS,
+ DEFAULT_RD_TEXTURE_MAX
+ };
-class Texture {
-public:
- enum Type {
+ enum TextureType {
TYPE_2D,
TYPE_LAYERED,
TYPE_3D
};
- Type type;
- RS::TextureLayeredType layered_type = RS::TEXTURE_LAYERED_2D_ARRAY;
-
- RenderingDevice::TextureType rd_type;
- RID rd_texture;
- RID rd_texture_srgb;
- RenderingDevice::DataFormat rd_format;
- RenderingDevice::DataFormat rd_format_srgb;
-
- RD::TextureView rd_view;
-
- Image::Format format;
- Image::Format validated_format;
-
- int width;
- int height;
- int depth;
- int layers;
- int mipmaps;
-
- int height_2d;
- int width_2d;
-
- struct BufferSlice3D {
- Size2i size;
- uint32_t offset = 0;
- uint32_t buffer_size = 0;
- };
- Vector<BufferSlice3D> buffer_slices_3d;
- uint32_t buffer_size_3d = 0;
-
- bool is_render_target;
- bool is_proxy;
-
- Ref<Image> image_cache_2d;
- String path;
-
- RID proxy_to;
- Vector<RID> proxies;
-
- HashSet<RID> lightmap_users;
-
- RS::TextureDetectCallback detect_3d_callback = nullptr;
- void *detect_3d_callback_ud = nullptr;
-
- RS::TextureDetectCallback detect_normal_callback = nullptr;
- void *detect_normal_callback_ud = nullptr;
+private:
+ friend class LightStorage;
+ friend class MaterialStorage;
- RS::TextureDetectRoughnessCallback detect_roughness_callback = nullptr;
- void *detect_roughness_callback_ud = nullptr;
+ static TextureStorage *singleton;
- CanvasTexture *canvas_texture = nullptr;
+ RID default_rd_textures[DEFAULT_RD_TEXTURE_MAX];
- void cleanup();
-};
+ /* Canvas Texture API */
-struct DecalAtlas {
- struct Texture {
- int panorama_to_dp_users;
- int users;
- Rect2 uv_rect;
+ class CanvasTexture {
+ public:
+ RID diffuse;
+ RID normal_map;
+ RID specular;
+ Color specular_color = Color(1, 1, 1, 1);
+ float shininess = 1.0;
+
+ RS::CanvasItemTextureFilter texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;
+ RS::CanvasItemTextureRepeat texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;
+ RID uniform_sets[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
+
+ Size2i size_cache = Size2i(1, 1);
+ bool use_normal_cache = false;
+ bool use_specular_cache = false;
+ bool cleared_cache = true;
+
+ void clear_sets();
+ ~CanvasTexture();
};
- struct SortItem {
- RID texture;
- Size2i pixel_size;
- Size2i size;
- Point2i pos;
-
- bool operator<(const SortItem &p_item) const {
- //sort larger to smaller
- if (size.height == p_item.size.height) {
- return size.width > p_item.size.width;
- } else {
- return size.height > p_item.size.height;
- }
- }
- };
+ RID_Owner<CanvasTexture, true> canvas_texture_owner;
- HashMap<RID, Texture> textures;
- bool dirty = true;
- int mipmaps = 5;
+ /* Texture API */
- RID texture;
- RID texture_srgb;
- struct MipMap {
- RID fb;
- RID texture;
- Size2i size;
- };
- Vector<MipMap> texture_mipmaps;
+ class Texture {
+ public:
+ TextureType type;
+ RS::TextureLayeredType layered_type = RS::TEXTURE_LAYERED_2D_ARRAY;
- Size2i size;
-};
+ RenderingDevice::TextureType rd_type;
+ RID rd_texture;
+ RID rd_texture_srgb;
+ RenderingDevice::DataFormat rd_format;
+ RenderingDevice::DataFormat rd_format_srgb;
-struct Decal {
- Vector3 extents = Vector3(1, 1, 1);
- RID textures[RS::DECAL_TEXTURE_MAX];
- float emission_energy = 1.0;
- float albedo_mix = 1.0;
- Color modulate = Color(1, 1, 1, 1);
- uint32_t cull_mask = (1 << 20) - 1;
- float upper_fade = 0.3;
- float lower_fade = 0.3;
- bool distance_fade = false;
- float distance_fade_begin = 40.0;
- float distance_fade_length = 10.0;
- float normal_fade = 0.0;
-
- Dependency dependency;
-};
+ RD::TextureView rd_view;
-struct RenderTarget {
- Size2i size;
- uint32_t view_count;
- RID framebuffer;
- RID color;
+ Image::Format format;
+ Image::Format validated_format;
- //used for retrieving from CPU
- RD::DataFormat color_format = RD::DATA_FORMAT_R4G4_UNORM_PACK8;
- RD::DataFormat color_format_srgb = RD::DATA_FORMAT_R4G4_UNORM_PACK8;
- Image::Format image_format = Image::FORMAT_L8;
+ int width;
+ int height;
+ int depth;
+ int layers;
+ int mipmaps;
- bool is_transparent = false;
+ int height_2d;
+ int width_2d;
- bool sdf_enabled = false;
+ struct BufferSlice3D {
+ Size2i size;
+ uint32_t offset = 0;
+ uint32_t buffer_size = 0;
+ };
+ Vector<BufferSlice3D> buffer_slices_3d;
+ uint32_t buffer_size_3d = 0;
- RID backbuffer; //used for effects
- RID backbuffer_fb;
- RID backbuffer_mipmap0;
+ bool is_render_target;
+ bool is_proxy;
- Vector<RID> backbuffer_mipmaps;
+ Ref<Image> image_cache_2d;
+ String path;
- RID framebuffer_uniform_set;
- RID backbuffer_uniform_set;
+ RID proxy_to;
+ Vector<RID> proxies;
- RID sdf_buffer_write;
- RID sdf_buffer_write_fb;
- RID sdf_buffer_process[2];
- RID sdf_buffer_read;
- RID sdf_buffer_process_uniform_sets[2];
- RS::ViewportSDFOversize sdf_oversize = RS::VIEWPORT_SDF_OVERSIZE_120_PERCENT;
- RS::ViewportSDFScale sdf_scale = RS::VIEWPORT_SDF_SCALE_50_PERCENT;
- Size2i process_size;
+ HashSet<RID> lightmap_users;
- // VRS
- RS::ViewportVRSMode vrs_mode = RS::VIEWPORT_VRS_DISABLED;
- RID vrs_texture;
+ RS::TextureDetectCallback detect_3d_callback = nullptr;
+ void *detect_3d_callback_ud = nullptr;
- //texture generated for this owner (nor RD).
- RID texture;
- bool was_used;
+ RS::TextureDetectCallback detect_normal_callback = nullptr;
+ void *detect_normal_callback_ud = nullptr;
- //clear request
- bool clear_requested;
- Color clear_color;
-};
+ RS::TextureDetectRoughnessCallback detect_roughness_callback = nullptr;
+ void *detect_roughness_callback_ud = nullptr;
-struct RenderTargetSDF {
- enum {
- SHADER_LOAD,
- SHADER_LOAD_SHRINK,
- SHADER_PROCESS,
- SHADER_PROCESS_OPTIMIZED,
- SHADER_STORE,
- SHADER_STORE_SHRINK,
- SHADER_MAX
- };
+ CanvasTexture *canvas_texture = nullptr;
- struct PushConstant {
- int32_t size[2];
- int32_t stride;
- int32_t shift;
- int32_t base_size[2];
- int32_t pad[2];
+ void cleanup();
};
- CanvasSdfShaderRD shader;
- RID shader_version;
- RID pipelines[SHADER_MAX];
-};
-
-class TextureStorage : public RendererTextureStorage {
-private:
- static TextureStorage *singleton;
-
- /* Canvas Texture API */
-
- RID_Owner<RendererRD::CanvasTexture, true> canvas_texture_owner;
-
- /* Texture API */
-
//textures can be created from threads, so this RID_Owner is thread safe
mutable RID_Owner<Texture, true> texture_owner;
+ Texture *get_texture(RID p_rid) { return texture_owner.get_or_null(p_rid); };
struct TextureToRDFormat {
RD::DataFormat format;
@@ -303,13 +188,115 @@ private:
/* DECAL API */
- DecalAtlas decal_atlas;
+ struct DecalAtlas {
+ struct Texture {
+ int panorama_to_dp_users;
+ int users;
+ Rect2 uv_rect;
+ };
+
+ struct SortItem {
+ RID texture;
+ Size2i pixel_size;
+ Size2i size;
+ Point2i pos;
+
+ bool operator<(const SortItem &p_item) const {
+ //sort larger to smaller
+ if (size.height == p_item.size.height) {
+ return size.width > p_item.size.width;
+ } else {
+ return size.height > p_item.size.height;
+ }
+ }
+ };
+
+ HashMap<RID, Texture> textures;
+ bool dirty = true;
+ int mipmaps = 5;
+
+ RID texture;
+ RID texture_srgb;
+ struct MipMap {
+ RID fb;
+ RID texture;
+ Size2i size;
+ };
+ Vector<MipMap> texture_mipmaps;
+
+ Size2i size;
+ } decal_atlas;
+
+ struct Decal {
+ Vector3 extents = Vector3(1, 1, 1);
+ RID textures[RS::DECAL_TEXTURE_MAX];
+ float emission_energy = 1.0;
+ float albedo_mix = 1.0;
+ Color modulate = Color(1, 1, 1, 1);
+ uint32_t cull_mask = (1 << 20) - 1;
+ float upper_fade = 0.3;
+ float lower_fade = 0.3;
+ bool distance_fade = false;
+ float distance_fade_begin = 40.0;
+ float distance_fade_length = 10.0;
+ float normal_fade = 0.0;
+
+ Dependency dependency;
+ };
mutable RID_Owner<Decal, true> decal_owner;
+ Decal *get_decal(RID p_rid) const { return decal_owner.get_or_null(p_rid); };
/* RENDER TARGET API */
+ struct RenderTarget {
+ Size2i size;
+ uint32_t view_count;
+ RID framebuffer;
+ RID color;
+
+ //used for retrieving from CPU
+ RD::DataFormat color_format = RD::DATA_FORMAT_R4G4_UNORM_PACK8;
+ RD::DataFormat color_format_srgb = RD::DATA_FORMAT_R4G4_UNORM_PACK8;
+ Image::Format image_format = Image::FORMAT_L8;
+
+ bool is_transparent = false;
+
+ bool sdf_enabled = false;
+
+ RID backbuffer; //used for effects
+ RID backbuffer_fb;
+ RID backbuffer_mipmap0;
+
+ Vector<RID> backbuffer_mipmaps;
+
+ RID framebuffer_uniform_set;
+ RID backbuffer_uniform_set;
+
+ RID sdf_buffer_write;
+ RID sdf_buffer_write_fb;
+ RID sdf_buffer_process[2];
+ RID sdf_buffer_read;
+ RID sdf_buffer_process_uniform_sets[2];
+ RS::ViewportSDFOversize sdf_oversize = RS::VIEWPORT_SDF_OVERSIZE_120_PERCENT;
+ RS::ViewportSDFScale sdf_scale = RS::VIEWPORT_SDF_SCALE_50_PERCENT;
+ Size2i process_size;
+
+ // VRS
+ RS::ViewportVRSMode vrs_mode = RS::VIEWPORT_VRS_DISABLED;
+ RID vrs_texture;
+
+ //texture generated for this owner (nor RD).
+ RID texture;
+ bool was_used;
+
+ //clear request
+ bool clear_requested;
+ Color clear_color;
+ };
+
mutable RID_Owner<RenderTarget> render_target_owner;
+ RenderTarget *get_render_target(RID p_rid) const { return render_target_owner.get_or_null(p_rid); };
void _clear_render_target(RenderTarget *rt);
void _update_render_target(RenderTarget *rt);
@@ -318,13 +305,33 @@ private:
void _render_target_clear_sdf(RenderTarget *rt);
Rect2i _render_target_get_sdf_rect(const RenderTarget *rt) const;
- RenderTargetSDF rt_sdf;
+ struct RenderTargetSDF {
+ enum {
+ SHADER_LOAD,
+ SHADER_LOAD_SHRINK,
+ SHADER_PROCESS,
+ SHADER_PROCESS_OPTIMIZED,
+ SHADER_STORE,
+ SHADER_STORE_SHRINK,
+ SHADER_MAX
+ };
+
+ struct PushConstant {
+ int32_t size[2];
+ int32_t stride;
+ int32_t shift;
+ int32_t base_size[2];
+ int32_t pad[2];
+ };
+
+ CanvasSdfShaderRD shader;
+ RID shader_version;
+ RID pipelines[SHADER_MAX];
+ } rt_sdf;
public:
static TextureStorage *get_singleton();
- RID default_rd_textures[DEFAULT_RD_TEXTURE_MAX];
-
_FORCE_INLINE_ RID texture_rd_get_default(DefaultRDTexture p_texture) {
return default_rd_textures[p_texture];
}
@@ -334,7 +341,6 @@ public:
/* Canvas Texture API */
- CanvasTexture *get_canvas_texture(RID p_rid) { return canvas_texture_owner.get_or_null(p_rid); };
bool owns_canvas_texture(RID p_rid) { return canvas_texture_owner.owns(p_rid); };
virtual RID canvas_texture_allocate() override;
@@ -351,8 +357,7 @@ public:
/* Texture API */
- Texture *get_texture(RID p_rid) { return texture_owner.get_or_null(p_rid); };
- bool owns_texture(RID p_rid) { return texture_owner.owns(p_rid); };
+ bool owns_texture(RID p_rid) const { return texture_owner.owns(p_rid); };
virtual bool can_create_resources_async() const override;
@@ -394,12 +399,29 @@ public:
virtual Size2 texture_size_with_proxy(RID p_proxy) override;
//internal usage
+ _FORCE_INLINE_ TextureType texture_get_type(RID p_texture) {
+ RendererRD::TextureStorage::Texture *tex = texture_owner.get_or_null(p_texture);
+ if (tex == nullptr) {
+ return TYPE_2D;
+ }
+
+ return tex->type;
+ }
+
+ _FORCE_INLINE_ int texture_get_layers(RID p_texture) {
+ RendererRD::TextureStorage::Texture *tex = texture_owner.get_or_null(p_texture);
+ if (tex == nullptr) {
+ return 1;
+ }
+
+ return tex->layers;
+ }
_FORCE_INLINE_ RID texture_get_rd_texture(RID p_texture, bool p_srgb = false) {
if (p_texture.is_null()) {
return RID();
}
- RendererRD::Texture *tex = texture_owner.get_or_null(p_texture);
+ RendererRD::TextureStorage::Texture *tex = texture_owner.get_or_null(p_texture);
if (!tex) {
return RID();
@@ -411,7 +433,7 @@ public:
if (p_texture.is_null()) {
return Size2i();
}
- RendererRD::Texture *tex = texture_owner.get_or_null(p_texture);
+ RendererRD::TextureStorage::Texture *tex = texture_owner.get_or_null(p_texture);
if (!tex) {
return Size2i();
@@ -423,8 +445,7 @@ public:
void update_decal_atlas();
- Decal *get_decal(RID p_rid) { return decal_owner.get_or_null(p_rid); };
- bool owns_decal(RID p_rid) { return decal_owner.owns(p_rid); };
+ bool owns_decal(RID p_rid) const { return decal_owner.owns(p_rid); };
RID decal_atlas_get_texture() const;
RID decal_atlas_get_texture_srgb() const;
@@ -518,11 +539,11 @@ public:
}
virtual AABB decal_get_aabb(RID p_decal) const override;
+ Dependency *decal_get_dependency(RID p_decal);
/* RENDER TARGET API */
- RenderTarget *get_render_target(RID p_rid) { return render_target_owner.get_or_null(p_rid); };
- bool owns_render_target(RID p_rid) { return render_target_owner.owns(p_rid); };
+ bool owns_render_target(RID p_rid) const { return render_target_owner.owns(p_rid); };
virtual RID render_target_create() override;
virtual void render_target_free(RID p_rid) override;
diff --git a/servers/rendering/renderer_rd/storage_rd/utilities.cpp b/servers/rendering/renderer_rd/storage_rd/utilities.cpp
index ce64d3c69e..fcef2f24bf 100644
--- a/servers/rendering/renderer_rd/storage_rd/utilities.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/utilities.cpp
@@ -138,35 +138,37 @@ bool Utilities::free(RID p_rid) {
void Utilities::base_update_dependency(RID p_base, DependencyTracker *p_instance) {
if (MeshStorage::get_singleton()->owns_mesh(p_base)) {
- Mesh *mesh = MeshStorage::get_singleton()->get_mesh(p_base);
- p_instance->update_dependency(&mesh->dependency);
+ Dependency *dependency = MeshStorage::get_singleton()->mesh_get_dependency(p_base);
+ p_instance->update_dependency(dependency);
} else if (MeshStorage::get_singleton()->owns_multimesh(p_base)) {
- MultiMesh *multimesh = MeshStorage::get_singleton()->get_multimesh(p_base);
- p_instance->update_dependency(&multimesh->dependency);
- if (multimesh->mesh.is_valid()) {
- base_update_dependency(multimesh->mesh, p_instance);
+ Dependency *dependency = MeshStorage::get_singleton()->multimesh_get_dependency(p_base);
+ p_instance->update_dependency(dependency);
+
+ RID mesh = MeshStorage::get_singleton()->multimesh_get_mesh(p_base);
+ if (mesh.is_valid()) {
+ base_update_dependency(mesh, p_instance);
}
} else if (LightStorage::get_singleton()->owns_reflection_probe(p_base)) {
- ReflectionProbe *rp = LightStorage::get_singleton()->get_reflection_probe(p_base);
- p_instance->update_dependency(&rp->dependency);
+ Dependency *dependency = LightStorage::get_singleton()->reflection_probe_get_dependency(p_base);
+ p_instance->update_dependency(dependency);
} else if (TextureStorage::get_singleton()->owns_decal(p_base)) {
- Decal *decal = TextureStorage::get_singleton()->get_decal(p_base);
- p_instance->update_dependency(&decal->dependency);
+ Dependency *dependency = TextureStorage::get_singleton()->decal_get_dependency(p_base);
+ p_instance->update_dependency(dependency);
} else if (GI::get_singleton()->owns_voxel_gi(p_base)) {
GI::VoxelGI *gip = GI::get_singleton()->get_voxel_gi(p_base);
p_instance->update_dependency(&gip->dependency);
} else if (LightStorage::get_singleton()->owns_lightmap(p_base)) {
- Lightmap *lm = LightStorage::get_singleton()->get_lightmap(p_base);
- p_instance->update_dependency(&lm->dependency);
+ Dependency *dependency = LightStorage::get_singleton()->lightmap_get_dependency(p_base);
+ p_instance->update_dependency(dependency);
} else if (LightStorage::get_singleton()->owns_light(p_base)) {
- Light *l = LightStorage::get_singleton()->get_light(p_base);
- p_instance->update_dependency(&l->dependency);
+ Dependency *dependency = LightStorage::get_singleton()->light_get_dependency(p_base);
+ p_instance->update_dependency(dependency);
} else if (ParticlesStorage::get_singleton()->owns_particles(p_base)) {
- Particles *p = ParticlesStorage::get_singleton()->get_particles(p_base);
- p_instance->update_dependency(&p->dependency);
+ Dependency *dependency = ParticlesStorage::get_singleton()->particles_get_dependency(p_base);
+ p_instance->update_dependency(dependency);
} else if (ParticlesStorage::get_singleton()->owns_particles_collision(p_base)) {
- ParticlesCollision *pc = ParticlesStorage::get_singleton()->get_particles_collision(p_base);
- p_instance->update_dependency(&pc->dependency);
+ Dependency *dependency = ParticlesStorage::get_singleton()->particles_collision_get_dependency(p_base);
+ p_instance->update_dependency(dependency);
} else if (Fog::get_singleton()->owns_fog_volume(p_base)) {
Fog::FogVolume *fv = Fog::get_singleton()->get_fog_volume(p_base);
p_instance->update_dependency(&fv->dependency);
@@ -288,9 +290,14 @@ bool Utilities::has_os_feature(const String &p_feature) const {
return true;
}
+#if !defined(ANDROID_ENABLED) && !defined(IOS_ENABLED)
+ // Some Android devices report support for S3TC but we don't expect that and don't export the textures.
+ // This could be fixed but so few devices support it that it doesn't seem useful (and makes bigger APKs).
+ // For good measure we do the same hack for iOS, just in case.
if (p_feature == "s3tc" && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC1_RGB_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT)) {
return true;
}
+#endif
if (p_feature == "bptc" && RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_BC7_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT)) {
return true;
diff --git a/servers/rendering/renderer_rd/uniform_set_cache_rd.h b/servers/rendering/renderer_rd/uniform_set_cache_rd.h
index abf110730b..bca8b02178 100644
--- a/servers/rendering/renderer_rd/uniform_set_cache_rd.h
+++ b/servers/rendering/renderer_rd/uniform_set_cache_rd.h
@@ -163,7 +163,7 @@ public:
const Cache *c = hash_table[table_idx];
while (c) {
- if (c->hash == h && c->set == p_set && c->shader == p_shader && _compare_args(0, c->uniforms, args...)) {
+ if (c->hash == h && c->set == p_set && c->shader == p_shader && sizeof...(Args) == c->uniforms.size() && _compare_args(0, c->uniforms, args...)) {
return c->cache;
}
c = c->next;
@@ -193,7 +193,7 @@ public:
const Cache *c = hash_table[table_idx];
while (c) {
- if (c->hash == h && c->set == p_set && c->shader == p_shader) {
+ if (c->hash == h && c->set == p_set && c->shader == p_shader && (uint32_t)p_uniforms.size() == c->uniforms.size()) {
bool all_ok = true;
for (int i = 0; i < p_uniforms.size(); i++) {
if (!_compare_uniform(p_uniforms[i], c->uniforms[i])) {
diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/renderer_scene.h
index 852fe89cd0..ba6fb71e67 100644
--- a/servers/rendering/renderer_scene.h
+++ b/servers/rendering/renderer_scene.h
@@ -100,10 +100,10 @@ public:
virtual void instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin, RS::VisibilityRangeFadeMode p_fade_mode) = 0;
virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index) = 0;
virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) = 0;
- virtual void instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value) = 0;
- virtual void instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const = 0;
- virtual Variant instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const = 0;
- virtual Variant instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const = 0;
+ virtual void instance_geometry_set_shader_uniform(RID p_instance, const StringName &p_parameter, const Variant &p_value) = 0;
+ virtual void instance_geometry_get_shader_uniform_list(RID p_instance, List<PropertyInfo> *p_parameters) const = 0;
+ virtual Variant instance_geometry_get_shader_uniform(RID p_instance, const StringName &p_parameter) const = 0;
+ virtual Variant instance_geometry_get_shader_uniform_default_value(RID p_instance, const StringName &p_parameter) const = 0;
virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) = 0;
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index 368bbb63f5..80c4ecea2d 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -506,7 +506,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
}
if (instance->mesh_instance.is_valid()) {
- RSG::mesh_storage->mesh_free(instance->mesh_instance);
+ RSG::mesh_storage->mesh_instance_free(instance->mesh_instance);
instance->mesh_instance = RID();
// no need to set instance data flag here, as it was freed above
}
@@ -1423,62 +1423,62 @@ void RendererSceneCull::instance_geometry_set_lod_bias(RID p_instance, float p_l
}
}
-void RendererSceneCull::instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value) {
+void RendererSceneCull::instance_geometry_set_shader_uniform(RID p_instance, const StringName &p_parameter, const Variant &p_value) {
Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
ERR_FAIL_COND(p_value.get_type() == Variant::OBJECT);
- HashMap<StringName, Instance::InstanceShaderParameter>::Iterator E = instance->instance_shader_parameters.find(p_parameter);
+ HashMap<StringName, Instance::InstanceShaderParameter>::Iterator E = instance->instance_shader_uniforms.find(p_parameter);
if (!E) {
Instance::InstanceShaderParameter isp;
isp.index = -1;
isp.info = PropertyInfo();
isp.value = p_value;
- instance->instance_shader_parameters[p_parameter] = isp;
+ instance->instance_shader_uniforms[p_parameter] = isp;
} else {
E->value.value = p_value;
- if (E->value.index >= 0 && instance->instance_allocated_shader_parameters) {
+ if (E->value.index >= 0 && instance->instance_allocated_shader_uniforms) {
//update directly
RSG::material_storage->global_shader_uniforms_instance_update(p_instance, E->value.index, p_value);
}
}
}
-Variant RendererSceneCull::instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const {
+Variant RendererSceneCull::instance_geometry_get_shader_uniform(RID p_instance, const StringName &p_parameter) const {
const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.get_or_null(p_instance);
ERR_FAIL_COND_V(!instance, Variant());
- if (instance->instance_shader_parameters.has(p_parameter)) {
- return instance->instance_shader_parameters[p_parameter].value;
+ if (instance->instance_shader_uniforms.has(p_parameter)) {
+ return instance->instance_shader_uniforms[p_parameter].value;
}
return Variant();
}
-Variant RendererSceneCull::instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const {
+Variant RendererSceneCull::instance_geometry_get_shader_uniform_default_value(RID p_instance, const StringName &p_parameter) const {
const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.get_or_null(p_instance);
ERR_FAIL_COND_V(!instance, Variant());
- if (instance->instance_shader_parameters.has(p_parameter)) {
- return instance->instance_shader_parameters[p_parameter].default_value;
+ if (instance->instance_shader_uniforms.has(p_parameter)) {
+ return instance->instance_shader_uniforms[p_parameter].default_value;
}
return Variant();
}
-void RendererSceneCull::instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const {
+void RendererSceneCull::instance_geometry_get_shader_uniform_list(RID p_instance, List<PropertyInfo> *p_parameters) const {
const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.get_or_null(p_instance);
ERR_FAIL_COND(!instance);
const_cast<RendererSceneCull *>(this)->update_dirty_instances();
Vector<StringName> names;
- for (const KeyValue<StringName, Instance::InstanceShaderParameter> &E : instance->instance_shader_parameters) {
+ for (const KeyValue<StringName, Instance::InstanceShaderParameter> &E : instance->instance_shader_uniforms) {
names.push_back(E.key);
}
names.sort_custom<StringName::AlphCompare>();
for (int i = 0; i < names.size(); i++) {
- PropertyInfo pinfo = instance->instance_shader_parameters[names[i]].info;
+ PropertyInfo pinfo = instance->instance_shader_uniforms[names[i]].info;
p_parameters->push_back(pinfo);
}
}
@@ -2146,7 +2146,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
if (soft_shadow_angle > 0.0) {
float z_range = (z_vec.dot(center) + radius + pancake_size) - z_min_cam;
- soft_shadow_expand = Math::tan(Math::deg2rad(soft_shadow_angle)) * z_range;
+ soft_shadow_expand = Math::tan(Math::deg_to_rad(soft_shadow_angle)) * z_range;
x_max += soft_shadow_expand;
y_max += soft_shadow_expand;
@@ -3125,8 +3125,8 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
float radius = RSG::light_storage->light_get_param(ins->base, RS::LIGHT_PARAM_RANGE);
float angle = RSG::light_storage->light_get_param(ins->base, RS::LIGHT_PARAM_SPOT_ANGLE);
- float w = radius * Math::sin(Math::deg2rad(angle));
- float d = radius * Math::cos(Math::deg2rad(angle));
+ float w = radius * Math::sin(Math::deg_to_rad(angle));
+ float d = radius * Math::cos(Math::deg_to_rad(angle));
Vector3 base = ins->transform.origin - ins->transform.basis.get_column(2).normalized() * d;
@@ -3642,9 +3642,9 @@ void RendererSceneCull::render_particle_colliders() {
}
}
-void RendererSceneCull::_update_instance_shader_parameters_from_material(HashMap<StringName, Instance::InstanceShaderParameter> &isparams, const HashMap<StringName, Instance::InstanceShaderParameter> &existing_isparams, RID p_material) {
+void RendererSceneCull::_update_instance_shader_uniforms_from_material(HashMap<StringName, Instance::InstanceShaderParameter> &isparams, const HashMap<StringName, Instance::InstanceShaderParameter> &existing_isparams, RID p_material) {
List<RendererMaterialStorage::InstanceShaderParam> plist;
- RSG::material_storage->material_get_instance_shader_parameters(p_material, &plist);
+ RSG::material_storage->material_get_instance_shader_uniforms(p_material, &plist);
for (const RendererMaterialStorage::InstanceShaderParam &E : plist) {
StringName name = E.info.name;
if (isparams.has(name)) {
@@ -3724,7 +3724,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
can_cast_shadows = false;
}
is_animated = RSG::material_storage->material_is_animated(p_instance->material_override);
- _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, p_instance->material_override);
+ _update_instance_shader_uniforms_from_material(isparams, p_instance->instance_shader_uniforms, p_instance->material_override);
} else {
if (p_instance->base_type == RS::INSTANCE_MESH) {
RID mesh = p_instance->base;
@@ -3746,7 +3746,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
is_animated = true;
}
- _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat);
+ _update_instance_shader_uniforms_from_material(isparams, p_instance->instance_shader_uniforms, mat);
RSG::material_storage->material_update_dependency(mat, &p_instance->dependency_tracker);
}
@@ -3777,7 +3777,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
is_animated = true;
}
- _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat);
+ _update_instance_shader_uniforms_from_material(isparams, p_instance->instance_shader_uniforms, mat);
RSG::material_storage->material_update_dependency(mat, &p_instance->dependency_tracker);
}
@@ -3815,7 +3815,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
is_animated = true;
}
- _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat);
+ _update_instance_shader_uniforms_from_material(isparams, p_instance->instance_shader_uniforms, mat);
RSG::material_storage->material_update_dependency(mat, &p_instance->dependency_tracker);
}
@@ -3831,7 +3831,7 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
if (p_instance->material_overlay.is_valid()) {
can_cast_shadows = can_cast_shadows || RSG::material_storage->material_casts_shadows(p_instance->material_overlay);
is_animated = is_animated || RSG::material_storage->material_is_animated(p_instance->material_overlay);
- _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, p_instance->material_overlay);
+ _update_instance_shader_uniforms_from_material(isparams, p_instance->instance_shader_uniforms, p_instance->material_overlay);
}
if (can_cast_shadows != geom->can_cast_shadows) {
@@ -3845,23 +3845,23 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) {
}
geom->material_is_animated = is_animated;
- p_instance->instance_shader_parameters = isparams;
+ p_instance->instance_shader_uniforms = isparams;
- if (p_instance->instance_allocated_shader_parameters != (p_instance->instance_shader_parameters.size() > 0)) {
- p_instance->instance_allocated_shader_parameters = (p_instance->instance_shader_parameters.size() > 0);
- if (p_instance->instance_allocated_shader_parameters) {
- p_instance->instance_allocated_shader_parameters_offset = RSG::material_storage->global_shader_uniforms_instance_allocate(p_instance->self);
- geom->geometry_instance->set_instance_shader_parameters_offset(p_instance->instance_allocated_shader_parameters_offset);
+ if (p_instance->instance_allocated_shader_uniforms != (p_instance->instance_shader_uniforms.size() > 0)) {
+ p_instance->instance_allocated_shader_uniforms = (p_instance->instance_shader_uniforms.size() > 0);
+ if (p_instance->instance_allocated_shader_uniforms) {
+ p_instance->instance_allocated_shader_uniforms_offset = RSG::material_storage->global_shader_uniforms_instance_allocate(p_instance->self);
+ geom->geometry_instance->set_instance_shader_uniforms_offset(p_instance->instance_allocated_shader_uniforms_offset);
- for (const KeyValue<StringName, Instance::InstanceShaderParameter> &E : p_instance->instance_shader_parameters) {
+ for (const KeyValue<StringName, Instance::InstanceShaderParameter> &E : p_instance->instance_shader_uniforms) {
if (E.value.value.get_type() != Variant::NIL) {
RSG::material_storage->global_shader_uniforms_instance_update(p_instance->self, E.value.index, E.value.value);
}
}
} else {
RSG::material_storage->global_shader_uniforms_instance_free(p_instance->self);
- p_instance->instance_allocated_shader_parameters_offset = -1;
- geom->geometry_instance->set_instance_shader_parameters_offset(-1);
+ p_instance->instance_allocated_shader_uniforms_offset = -1;
+ geom->geometry_instance->set_instance_shader_uniforms_offset(-1);
}
}
}
@@ -3953,7 +3953,7 @@ bool RendererSceneCull::free(RID p_rid) {
instance_geometry_set_material_overlay(p_rid, RID());
instance_attach_skeleton(p_rid, RID());
- if (instance->instance_allocated_shader_parameters) {
+ if (instance->instance_allocated_shader_uniforms) {
//free the used shader parameters
RSG::material_storage->global_shader_uniforms_instance_free(instance->self);
}
diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h
index 3a2b0a0fdf..540fb0e27a 100644
--- a/servers/rendering/renderer_scene_cull.h
+++ b/servers/rendering/renderer_scene_cull.h
@@ -426,9 +426,9 @@ public:
PropertyInfo info;
};
- HashMap<StringName, InstanceShaderParameter> instance_shader_parameters;
- bool instance_allocated_shader_parameters = false;
- int32_t instance_allocated_shader_parameters_offset = -1;
+ HashMap<StringName, InstanceShaderParameter> instance_shader_uniforms;
+ bool instance_allocated_shader_uniforms = false;
+ int32_t instance_allocated_shader_uniforms_offset = -1;
//
@@ -967,12 +967,12 @@ public:
virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index);
virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias);
- void _update_instance_shader_parameters_from_material(HashMap<StringName, Instance::InstanceShaderParameter> &isparams, const HashMap<StringName, Instance::InstanceShaderParameter> &existing_isparams, RID p_material);
+ void _update_instance_shader_uniforms_from_material(HashMap<StringName, Instance::InstanceShaderParameter> &isparams, const HashMap<StringName, Instance::InstanceShaderParameter> &existing_isparams, RID p_material);
- virtual void instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value);
- virtual void instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const;
- virtual Variant instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const;
- virtual Variant instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const;
+ virtual void instance_geometry_set_shader_uniform(RID p_instance, const StringName &p_parameter, const Variant &p_value);
+ virtual void instance_geometry_get_shader_uniform_list(RID p_instance, List<PropertyInfo> *p_parameters) const;
+ virtual Variant instance_geometry_get_shader_uniform(RID p_instance, const StringName &p_parameter) const;
+ virtual Variant instance_geometry_get_shader_uniform_default_value(RID p_instance, const StringName &p_parameter) const;
_FORCE_INLINE_ void _update_instance(Instance *p_instance);
_FORCE_INLINE_ void _update_instance_aabb(Instance *p_instance);
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index 118bf532b3..bfb81925bc 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -72,6 +72,41 @@ static Transform2D _canvas_get_transform(RendererViewport::Viewport *p_viewport,
return xf;
}
+Vector<RendererViewport::Viewport *> RendererViewport::_sort_active_viewports() {
+ // We need to sort the viewports in a "topological order",
+ // children first and parents last, we use the Kahn's algorithm to achieve that.
+
+ Vector<Viewport *> result;
+ List<Viewport *> nodes;
+
+ for (Viewport *viewport : active_viewports) {
+ if (viewport->parent.is_valid()) {
+ continue;
+ }
+
+ nodes.push_back(viewport);
+ }
+
+ while (!nodes.is_empty()) {
+ Viewport *node = nodes[0];
+ nodes.pop_front();
+
+ result.insert(0, node);
+
+ for (Viewport *child : active_viewports) {
+ if (child->parent != node->self) {
+ continue;
+ }
+
+ if (!nodes.find(child)) {
+ nodes.push_back(child);
+ }
+ }
+ }
+
+ return result;
+}
+
void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
if (p_viewport->render_buffers.is_valid()) {
if (p_viewport->size.width == 0 || p_viewport->size.height == 0) {
@@ -138,7 +173,11 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
p_viewport->internal_size = Size2(render_width, render_height);
- RSG::scene->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, render_width, render_height, width, height, p_viewport->fsr_sharpness, p_viewport->texture_mipmap_bias, p_viewport->msaa, p_viewport->screen_space_aa, p_viewport->use_taa, p_viewport->use_debanding, p_viewport->get_view_count());
+ // At resolution scales lower than 1.0, use negative texture mipmap bias
+ // to compensate for the loss of sharpness.
+ const float texture_mipmap_bias = log2f(MIN(scaling_3d_scale, 1.0)) + p_viewport->texture_mipmap_bias;
+
+ RSG::scene->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, render_width, render_height, width, height, p_viewport->fsr_sharpness, texture_mipmap_bias, p_viewport->msaa, p_viewport->screen_space_aa, p_viewport->use_taa, p_viewport->use_debanding, p_viewport->get_view_count());
}
}
}
@@ -544,8 +583,10 @@ void RendererViewport::draw_viewports() {
set_default_clear_color(GLOBAL_GET("rendering/environment/defaults/default_clear_color"));
}
- //sort viewports
- active_viewports.sort_custom<ViewportSort>();
+ if (sorted_active_viewports_dirty) {
+ sorted_active_viewports = _sort_active_viewports();
+ sorted_active_viewports_dirty = false;
+ }
HashMap<DisplayServer::WindowID, Vector<BlitToScreen>> blit_to_screen_list;
//draw viewports
@@ -554,9 +595,9 @@ void RendererViewport::draw_viewports() {
//determine what is visible
draw_viewports_pass++;
- for (int i = active_viewports.size() - 1; i >= 0; i--) { //to compute parent dependency, must go in reverse draw order
+ for (int i = sorted_active_viewports.size() - 1; i >= 0; i--) { //to compute parent dependency, must go in reverse draw order
- Viewport *vp = active_viewports[i];
+ Viewport *vp = sorted_active_viewports[i];
if (vp->update_mode == RS::VIEWPORT_UPDATE_DISABLED) {
continue;
@@ -617,8 +658,8 @@ void RendererViewport::draw_viewports() {
int objects_drawn = 0;
int draw_calls_used = 0;
- for (int i = 0; i < active_viewports.size(); i++) {
- Viewport *vp = active_viewports[i];
+ for (int i = 0; i < sorted_active_viewports.size(); i++) {
+ Viewport *vp = sorted_active_viewports[i];
if (vp->last_pass != draw_viewports_pass) {
continue; //should not draw
@@ -810,6 +851,8 @@ void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) {
} else {
active_viewports.erase(viewport);
}
+
+ sorted_active_viewports_dirty = true;
}
void RendererViewport::viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) {
@@ -1239,6 +1282,7 @@ bool RendererViewport::free(RID p_rid) {
viewport_set_scenario(p_rid, RID());
active_viewports.erase(viewport);
+ sorted_active_viewports_dirty = true;
if (viewport->use_occlusion_culling) {
RendererSceneOcclusionCull::get_singleton()->remove_buffer(p_rid);
diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h
index 5e37c96336..ab4893a908 100644
--- a/servers/rendering/renderer_viewport.h
+++ b/servers/rendering/renderer_viewport.h
@@ -185,25 +185,16 @@ public:
mutable RID_Owner<Viewport, true> viewport_owner;
- struct ViewportSort {
- _FORCE_INLINE_ bool operator()(const Viewport *p_left, const Viewport *p_right) const {
- bool left_to_screen = p_left->viewport_to_screen_rect.size != Size2();
- bool right_to_screen = p_right->viewport_to_screen_rect.size != Size2();
-
- if (left_to_screen == right_to_screen) {
- return p_right->parent == p_left->self;
- }
- return (right_to_screen ? 0 : 1) < (left_to_screen ? 0 : 1);
- }
- };
-
Vector<Viewport *> active_viewports;
+ Vector<Viewport *> sorted_active_viewports;
+ bool sorted_active_viewports_dirty = false;
int total_objects_drawn = 0;
int total_vertices_drawn = 0;
int total_draw_calls_used = 0;
private:
+ Vector<Viewport *> _sort_active_viewports();
void _configure_3d_render_buffers(Viewport *p_viewport);
void _draw_3d(Viewport *p_viewport);
void _draw_viewport(Viewport *p_viewport);
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index 0b76bb3051..2fefdbff52 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -387,6 +387,7 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("framebuffer_create_multipass", "textures", "passes", "validate_with_format", "view_count"), &RenderingDevice::_framebuffer_create_multipass, DEFVAL(INVALID_FORMAT_ID), DEFVAL(1));
ClassDB::bind_method(D_METHOD("framebuffer_create_empty", "size", "samples", "validate_with_format"), &RenderingDevice::framebuffer_create_empty, DEFVAL(TEXTURE_SAMPLES_1), DEFVAL(INVALID_FORMAT_ID));
ClassDB::bind_method(D_METHOD("framebuffer_get_format", "framebuffer"), &RenderingDevice::framebuffer_get_format);
+ ClassDB::bind_method(D_METHOD("framebuffer_is_valid", "framebuffer"), &RenderingDevice::framebuffer_is_valid);
ClassDB::bind_method(D_METHOD("sampler_create", "state"), &RenderingDevice::_sampler_create);
@@ -428,6 +429,7 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_list_begin", "framebuffer", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::draw_list_begin, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray<RID>()));
ClassDB::bind_method(D_METHOD("draw_list_begin_split", "framebuffer", "splits", "initial_color_action", "final_color_action", "initial_depth_action", "final_depth_action", "clear_color_values", "clear_depth", "clear_stencil", "region", "storage_textures"), &RenderingDevice::_draw_list_begin_split, DEFVAL(Vector<Color>()), DEFVAL(1.0), DEFVAL(0), DEFVAL(Rect2()), DEFVAL(TypedArray<RID>()));
+ ClassDB::bind_method(D_METHOD("draw_list_set_blend_constants", "draw_list", "color"), &RenderingDevice::draw_list_set_blend_constants);
ClassDB::bind_method(D_METHOD("draw_list_bind_render_pipeline", "draw_list", "render_pipeline"), &RenderingDevice::draw_list_bind_render_pipeline);
ClassDB::bind_method(D_METHOD("draw_list_bind_uniform_set", "draw_list", "uniform_set", "set_index"), &RenderingDevice::draw_list_bind_uniform_set);
ClassDB::bind_method(D_METHOD("draw_list_bind_vertex_array", "draw_list", "vertex_array"), &RenderingDevice::draw_list_bind_vertex_array);
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index 03aa6f7644..6dadcab383 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -129,6 +129,8 @@ public:
typedef Vector<uint8_t> (*ShaderCompileToSPIRVFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, const RenderingDevice *p_render_device);
typedef Vector<uint8_t> (*ShaderCacheFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language);
+ typedef void (*InvalidationCallback)(void *);
+
private:
static ShaderCompileToSPIRVFunction compile_to_spirv_function;
static ShaderCacheFunction cache_function;
@@ -547,13 +549,15 @@ public:
int32_t vrs_attachment = ATTACHMENT_UNUSED; // density map for VRS, only used if supported
};
- virtual FramebufferFormatID framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, Vector<FramebufferPass> &p_passes, uint32_t p_view_count = 1) = 0;
+ virtual FramebufferFormatID framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, uint32_t p_view_count = 1) = 0;
virtual FramebufferFormatID framebuffer_format_create_empty(TextureSamples p_samples = TEXTURE_SAMPLES_1) = 0;
virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format, uint32_t p_pass = 0) = 0;
virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1) = 0;
- virtual RID framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1) = 0;
+ virtual RID framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, const Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1) = 0;
virtual RID framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples = TEXTURE_SAMPLES_1, FramebufferFormatID p_format_check = INVALID_ID) = 0;
+ virtual bool framebuffer_is_valid(RID p_framebuffer) const = 0;
+ virtual void framebuffer_set_invalidation_callback(RID p_framebuffer, InvalidationCallback p_callback, void *p_userdata) = 0;
virtual FramebufferFormatID framebuffer_get_format(RID p_framebuffer) = 0;
@@ -793,8 +797,7 @@ public:
virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) = 0;
virtual bool uniform_set_is_valid(RID p_uniform_set) = 0;
- typedef void (*UniformSetInvalidatedCallback)(void *);
- virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, UniformSetInvalidatedCallback p_callback, void *p_userdata) = 0;
+ virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, InvalidationCallback p_callback, void *p_userdata) = 0;
virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0;
virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0;
@@ -1126,6 +1129,7 @@ public:
virtual DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>()) = 0;
virtual Error draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, DrawListID *r_split_ids, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const Vector<RID> &p_storage_textures = Vector<RID>()) = 0;
+ virtual void draw_list_set_blend_constants(DrawListID p_list, const Color &p_color) = 0;
virtual void draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline) = 0;
virtual void draw_list_bind_uniform_set(DrawListID p_list, RID p_uniform_set, uint32_t p_index) = 0;
virtual void draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array) = 0;
diff --git a/servers/rendering/rendering_device_binds.h b/servers/rendering/rendering_device_binds.h
index 8bdd3deea1..a56b7eb241 100644
--- a/servers/rendering/rendering_device_binds.h
+++ b/servers/rendering/rendering_device_binds.h
@@ -443,8 +443,8 @@ public:
void add_id(const RID &p_id) { base.append_id(p_id); }
void clear_ids() { base.clear_ids(); }
- Array get_ids() const {
- Array ids;
+ TypedArray<RID> get_ids() const {
+ TypedArray<RID> ids;
for (uint32_t i = 0; i < base.get_id_count(); i++) {
ids.push_back(base.get_id(i));
}
@@ -452,7 +452,7 @@ public:
}
protected:
- void _set_ids(const Array &p_ids) {
+ void _set_ids(const TypedArray<RID> &p_ids) {
base.clear_ids();
for (int i = 0; i < p_ids.size(); i++) {
RID id = p_ids[i];
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index 21a94b88f2..9b174d5879 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -227,7 +227,7 @@ public:
FUNC2(shader_set_path_hint, RID, const String &)
FUNC1RC(String, shader_get_code, RID)
- FUNC2SC(shader_get_param_list, RID, List<PropertyInfo> *)
+ FUNC2SC(shader_get_shader_uniform_list, RID, List<PropertyInfo> *)
FUNC4(shader_set_default_texture_param, RID, const StringName &, RID, int)
FUNC3RC(RID, shader_get_default_texture_param, RID, const StringName &, int)
@@ -773,10 +773,10 @@ public:
FUNC4(instance_geometry_set_lightmap, RID, RID, const Rect2 &, int)
FUNC2(instance_geometry_set_lod_bias, RID, float)
FUNC2(instance_geometry_set_transparency, RID, float)
- FUNC3(instance_geometry_set_shader_parameter, RID, const StringName &, const Variant &)
- FUNC2RC(Variant, instance_geometry_get_shader_parameter, RID, const StringName &)
- FUNC2RC(Variant, instance_geometry_get_shader_parameter_default_value, RID, const StringName &)
- FUNC2C(instance_geometry_get_shader_parameter_list, RID, List<PropertyInfo> *)
+ FUNC3(instance_geometry_set_shader_uniform, RID, const StringName &, const Variant &)
+ FUNC2RC(Variant, instance_geometry_get_shader_uniform, RID, const StringName &)
+ FUNC2RC(Variant, instance_geometry_get_shader_uniform_default_value, RID, const StringName &)
+ FUNC2C(instance_geometry_get_shader_uniform_list, RID, List<PropertyInfo> *)
FUNC3R(TypedArray<Image>, bake_render_uv2, RID, const Vector<RID> &, const Size2i &)
@@ -831,6 +831,7 @@ public:
FUNC6(canvas_item_add_texture_rect, RID, const Rect2 &, RID, bool, const Color &, bool)
FUNC7(canvas_item_add_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, bool, bool)
FUNC7(canvas_item_add_msdf_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, int, float)
+ FUNC5(canvas_item_add_lcd_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &)
FUNC10(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &)
FUNC6(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float)
FUNC5(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID)
diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp
index 7637eae4a6..f14350305a 100644
--- a/servers/rendering/shader_compiler.cpp
+++ b/servers/rendering/shader_compiler.cpp
@@ -498,6 +498,11 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
for (const KeyValue<StringName, SL::ShaderNode::Uniform> &E : pnode->uniforms) {
if (SL::is_sampler_type(E.value.type)) {
+ if (E.value.hint == SL::ShaderNode::Uniform::HINT_SCREEN_TEXTURE ||
+ E.value.hint == SL::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE ||
+ E.value.hint == SL::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
+ continue; // Don't create uniforms in the generated code for these.
+ }
max_texture_uniforms++;
} else {
if (E.value.scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) {
@@ -537,6 +542,13 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
p_actions.uniforms->insert(uniform_name, uniform);
continue; // Instances are indexed directly, don't need index uniforms.
}
+
+ if (uniform.hint == SL::ShaderNode::Uniform::HINT_SCREEN_TEXTURE ||
+ uniform.hint == SL::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE ||
+ uniform.hint == SL::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
+ continue; // Don't create uniforms in the generated code for these.
+ }
+
if (SL::is_sampler_type(uniform.type)) {
// Texture layouts are different for OpenGL GLSL and Vulkan GLSL
if (!RS::get_singleton()->is_low_end()) {
@@ -892,12 +904,39 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
if (p_default_actions.renames.has(vnode->name)) {
code = p_default_actions.renames[vnode->name];
+ if (vnode->name == "SCREEN_TEXTURE") {
+ r_gen_code.uses_screen_texture_mipmaps = true;
+ }
} else {
if (shader->uniforms.has(vnode->name)) {
//its a uniform!
const ShaderLanguage::ShaderNode::Uniform &u = shader->uniforms[vnode->name];
if (u.texture_order >= 0) {
- code = _mkid(vnode->name); //texture, use as is
+ StringName name = vnode->name;
+ if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE) {
+ name = "SCREEN_TEXTURE";
+ if (u.filter >= ShaderLanguage::FILTER_NEAREST_MIPMAP) {
+ r_gen_code.uses_screen_texture_mipmaps = true;
+ }
+ } else if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE) {
+ name = "NORMAL_ROUGHNESS_TEXTURE";
+ } else if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
+ name = "DEPTH_TEXTURE";
+ } else {
+ name = _mkid(vnode->name); //texture, use as is
+ }
+
+ if (p_default_actions.renames.has(name)) {
+ code = p_default_actions.renames[name];
+ } else {
+ code = name;
+ }
+
+ if (p_actions.usage_flag_pointers.has(name) && !used_flag_pointers.has(name)) {
+ *p_actions.usage_flag_pointers[name] = true;
+ used_flag_pointers.insert(name);
+ }
+
} else {
//a scalar or vector
if (u.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) {
@@ -1155,6 +1194,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
}
if (correct_texture_uniform) {
+ //TODO Needs to detect screen_texture hint as well
is_screen_texture = (texture_uniform == "SCREEN_TEXTURE");
String sampler_name;
@@ -1404,6 +1444,7 @@ Error ShaderCompiler::compile(RS::ShaderMode p_mode, const String &p_code, Ident
r_gen_code.uses_fragment_time = false;
r_gen_code.uses_vertex_time = false;
r_gen_code.uses_global_textures = false;
+ r_gen_code.uses_screen_texture_mipmaps = false;
used_name_defines.clear();
used_rmode_defines.clear();
@@ -1434,8 +1475,11 @@ void ShaderCompiler::initialize(DefaultIdentifierActions p_actions) {
texture_functions.insert("textureLod");
texture_functions.insert("textureProjLod");
texture_functions.insert("textureGrad");
+ texture_functions.insert("textureProjGrad");
texture_functions.insert("textureGather");
texture_functions.insert("textureSize");
+ texture_functions.insert("textureQueryLod");
+ texture_functions.insert("textureQueryLevels");
texture_functions.insert("texelFetch");
}
diff --git a/servers/rendering/shader_compiler.h b/servers/rendering/shader_compiler.h
index 06f42e9f0f..1ad43daf5f 100644
--- a/servers/rendering/shader_compiler.h
+++ b/servers/rendering/shader_compiler.h
@@ -80,6 +80,7 @@ public:
bool uses_global_textures;
bool uses_fragment_time;
bool uses_vertex_time;
+ bool uses_screen_texture_mipmaps;
};
struct DefaultIdentifierActions {
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index 2dd0f7006b..2bbc5e4dfb 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -195,10 +195,14 @@ const char *ShaderLanguage::token_names[TK_MAX] = {
"SOURCE_COLOR",
"HINT_DEFAULT_WHITE_TEXTURE",
"HINT_DEFAULT_BLACK_TEXTURE",
+ "HINT_DEFAULT_TRANSPARENT_TEXTURE",
"HINT_NORMAL_TEXTURE",
"HINT_ANISOTROPY_TEXTURE",
"HINT_RANGE",
"HINT_INSTANCE_INDEX",
+ "HINT_SCREEN_TEXTURE",
+ "HINT_NORMAL_ROUGHNESS_TEXTURE",
+ "HINT_DEPTH_TEXTURE",
"FILTER_NEAREST",
"FILTER_LINEAR",
"FILTER_NEAREST_MIPMAP",
@@ -354,6 +358,7 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
{ TK_HINT_NORMAL_TEXTURE, "hint_normal", CF_UNSPECIFIED, {}, {} },
{ TK_HINT_DEFAULT_WHITE_TEXTURE, "hint_default_white", CF_UNSPECIFIED, {}, {} },
{ TK_HINT_DEFAULT_BLACK_TEXTURE, "hint_default_black", CF_UNSPECIFIED, {}, {} },
+ { TK_HINT_DEFAULT_TRANSPARENT_TEXTURE, "hint_default_transparent", CF_UNSPECIFIED, {}, {} },
{ TK_HINT_ANISOTROPY_TEXTURE, "hint_anisotropy", CF_UNSPECIFIED, {}, {} },
{ TK_HINT_ROUGHNESS_R, "hint_roughness_r", CF_UNSPECIFIED, {}, {} },
{ TK_HINT_ROUGHNESS_G, "hint_roughness_g", CF_UNSPECIFIED, {}, {} },
@@ -361,6 +366,10 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = {
{ TK_HINT_ROUGHNESS_A, "hint_roughness_a", CF_UNSPECIFIED, {}, {} },
{ TK_HINT_ROUGHNESS_NORMAL_TEXTURE, "hint_roughness_normal", CF_UNSPECIFIED, {}, {} },
{ TK_HINT_ROUGHNESS_GRAY, "hint_roughness_gray", CF_UNSPECIFIED, {}, {} },
+ { TK_HINT_SCREEN_TEXTURE, "hint_screen_texture", CF_UNSPECIFIED, {}, {} },
+ { TK_HINT_NORMAL_ROUGHNESS_TEXTURE, "hint_normal_roughness_texture", CF_UNSPECIFIED, {}, {} },
+ { TK_HINT_DEPTH_TEXTURE, "hint_depth_texture", CF_UNSPECIFIED, {}, {} },
+
{ TK_FILTER_NEAREST, "filter_nearest", CF_UNSPECIFIED, {}, {} },
{ TK_FILTER_LINEAR, "filter_linear", CF_UNSPECIFIED, {}, {} },
{ TK_FILTER_NEAREST_MIPMAP, "filter_nearest_mipmap", CF_UNSPECIFIED, {}, {} },
@@ -1088,9 +1097,21 @@ String ShaderLanguage::get_uniform_hint_name(ShaderNode::Uniform::Hint p_hint) {
case ShaderNode::Uniform::HINT_DEFAULT_WHITE: {
result = "hint_default_white";
} break;
+ case ShaderNode::Uniform::HINT_DEFAULT_TRANSPARENT: {
+ result = "hint_default_transparent";
+ } break;
case ShaderNode::Uniform::HINT_ANISOTROPY: {
result = "hint_anisotropy";
} break;
+ case ShaderNode::Uniform::HINT_SCREEN_TEXTURE: {
+ result = "hint_screen_texture";
+ } break;
+ case ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE: {
+ result = "hint_normal_roughness_texture";
+ } break;
+ case ShaderNode::Uniform::HINT_DEPTH_TEXTURE: {
+ result = "hint_depth_texture";
+ } break;
default:
break;
}
@@ -2458,11 +2479,15 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
// reflect
+ { "reflect", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "I", "N" }, TAG_GLOBAL, false },
{ "reflect", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "I", "N" }, TAG_GLOBAL, false },
+ { "reflect", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "I", "N" }, TAG_GLOBAL, false },
// refract
+ { "refract", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "I", "N", "eta" }, TAG_GLOBAL, false },
{ "refract", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "I", "N", "eta" }, TAG_GLOBAL, false },
+ { "refract", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "I", "N", "eta" }, TAG_GLOBAL, false },
// faceforward
@@ -2723,6 +2748,18 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
{ "textureGrad", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, false },
{ "textureGrad", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, false },
+ // textureProjGrad
+
+ { "textureProjGrad", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, false },
+ { "textureProjGrad", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, false },
+ { "textureProjGrad", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, false },
+ { "textureProjGrad", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC4, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, false },
+ { "textureProjGrad", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, false },
+ { "textureProjGrad", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC4, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, false },
+ { "textureProjGrad", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC4, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, false },
+ { "textureProjGrad", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, false },
+ { "textureProjGrad", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, false },
+
// textureGather
{ "textureGather", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, false },
@@ -2740,6 +2777,32 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = {
{ "textureGather", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, false },
{ "textureGather", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "comp" }, TAG_GLOBAL, false },
+ // textureQueryLod
+
+ { "textureQueryLod", TYPE_VEC2, { TYPE_SAMPLER2D, TYPE_VEC2 }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureQueryLod", TYPE_VEC2, { TYPE_ISAMPLER2D, TYPE_VEC2 }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureQueryLod", TYPE_VEC2, { TYPE_USAMPLER2D, TYPE_VEC2 }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureQueryLod", TYPE_VEC2, { TYPE_SAMPLER2DARRAY, TYPE_VEC2 }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureQueryLod", TYPE_VEC2, { TYPE_ISAMPLER2DARRAY, TYPE_VEC2 }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureQueryLod", TYPE_VEC2, { TYPE_USAMPLER2DARRAY, TYPE_VEC2 }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureQueryLod", TYPE_VEC2, { TYPE_SAMPLER3D, TYPE_VEC3 }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureQueryLod", TYPE_VEC2, { TYPE_ISAMPLER3D, TYPE_VEC3 }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureQueryLod", TYPE_VEC2, { TYPE_USAMPLER3D, TYPE_VEC3 }, { "sampler", "coords" }, TAG_GLOBAL, true },
+ { "textureQueryLod", TYPE_VEC2, { TYPE_SAMPLERCUBE, TYPE_VEC3 }, { "sampler", "coords" }, TAG_GLOBAL, true },
+
+ // textureQueryLevels
+
+ { "textureQueryLevels", TYPE_INT, { TYPE_SAMPLER2D }, { "sampler" }, TAG_GLOBAL, true },
+ { "textureQueryLevels", TYPE_INT, { TYPE_ISAMPLER2D }, { "sampler" }, TAG_GLOBAL, true },
+ { "textureQueryLevels", TYPE_INT, { TYPE_USAMPLER2D }, { "sampler" }, TAG_GLOBAL, true },
+ { "textureQueryLevels", TYPE_INT, { TYPE_SAMPLER2DARRAY }, { "sampler" }, TAG_GLOBAL, true },
+ { "textureQueryLevels", TYPE_INT, { TYPE_ISAMPLER2DARRAY }, { "sampler" }, TAG_GLOBAL, true },
+ { "textureQueryLevels", TYPE_INT, { TYPE_USAMPLER2DARRAY }, { "sampler" }, TAG_GLOBAL, true },
+ { "textureQueryLevels", TYPE_INT, { TYPE_SAMPLER3D }, { "sampler" }, TAG_GLOBAL, true },
+ { "textureQueryLevels", TYPE_INT, { TYPE_ISAMPLER3D }, { "sampler" }, TAG_GLOBAL, true },
+ { "textureQueryLevels", TYPE_INT, { TYPE_USAMPLER3D }, { "sampler" }, TAG_GLOBAL, true },
+ { "textureQueryLevels", TYPE_INT, { TYPE_SAMPLERCUBE }, { "sampler" }, TAG_GLOBAL, true },
+
// dFdx
{ "dFdx", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "p" }, TAG_GLOBAL, false },
@@ -5314,6 +5377,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
_set_tkpos(prev_pos);
+ ShaderNode::Varying &var = shader->varyings[identifier];
String error;
if (is_token_operator_assign(next_token.type)) {
if (!_validate_varying_assign(shader->varyings[identifier], &error)) {
@@ -5321,8 +5385,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
return nullptr;
}
} else {
- ShaderNode::Varying &var = shader->varyings[identifier];
-
switch (var.stage) {
case ShaderNode::Varying::STAGE_VERTEX:
if (current_function == varying_function_names.fragment || current_function == varying_function_names.light) {
@@ -5338,6 +5400,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
break;
}
}
+
+ if ((var.stage != ShaderNode::Varying::STAGE_FRAGMENT && var.stage != ShaderNode::Varying::STAGE_FRAGMENT_TO_LIGHT) && var.type < TYPE_FLOAT && var.interpolation != INTERPOLATION_FLAT) {
+ _set_tkpos(var.tkpos);
+ _set_error(RTR("Varying with integer data type must be declared with `flat` interpolation qualifier."));
+ return nullptr;
+ }
}
if (ident_type == IDENTIFIER_FUNCTION) {
@@ -7153,9 +7221,12 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
if (!n) {
return ERR_PARSE_ERROR;
}
- if (n->get_datatype() != TYPE_INT) {
- _set_error(RTR("Expected an integer expression."));
- return ERR_PARSE_ERROR;
+ {
+ const ShaderLanguage::DataType switch_type = n->get_datatype();
+ if (switch_type != TYPE_INT && switch_type != TYPE_UINT) {
+ _set_error(RTR("Expected an integer expression."));
+ return ERR_PARSE_ERROR;
+ }
}
tk = _get_token();
if (tk.type != TK_PARENTHESIS_CLOSE) {
@@ -8233,8 +8304,8 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
return ERR_PARSE_ERROR;
}
- if (!is_uniform && (type < TYPE_FLOAT || type > TYPE_MAT4)) {
- _set_error(RTR("Invalid type for varying, only 'float', 'vec2', 'vec3', 'vec4', 'mat2', 'mat3', 'mat4', or arrays of these types are allowed."));
+ if (!is_uniform && type > TYPE_MAT4) {
+ _set_error(RTR("Invalid data type for varying."));
return ERR_PARSE_ERROR;
}
@@ -8410,6 +8481,9 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
case TK_HINT_DEFAULT_WHITE_TEXTURE: {
new_hint = ShaderNode::Uniform::HINT_DEFAULT_WHITE;
} break;
+ case TK_HINT_DEFAULT_TRANSPARENT_TEXTURE: {
+ new_hint = ShaderNode::Uniform::HINT_DEFAULT_TRANSPARENT;
+ } break;
case TK_HINT_NORMAL_TEXTURE: {
new_hint = ShaderNode::Uniform::HINT_NORMAL;
} break;
@@ -8552,6 +8626,15 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
return ERR_PARSE_ERROR;
}
} break;
+ case TK_HINT_SCREEN_TEXTURE: {
+ new_hint = ShaderNode::Uniform::HINT_SCREEN_TEXTURE;
+ } break;
+ case TK_HINT_NORMAL_ROUGHNESS_TEXTURE: {
+ new_hint = ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE;
+ } break;
+ case TK_HINT_DEPTH_TEXTURE: {
+ new_hint = ShaderNode::Uniform::HINT_DEPTH_TEXTURE;
+ } break;
case TK_FILTER_NEAREST: {
new_filter = FILTER_NEAREST;
} break;
@@ -8576,6 +8659,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
case TK_REPEAT_ENABLE: {
new_repeat = REPEAT_ENABLE;
} break;
+
default:
break;
}
@@ -8600,9 +8684,9 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
if (new_filter != FILTER_DEFAULT) {
if (uniform.filter != FILTER_DEFAULT) {
if (uniform.filter == new_filter) {
- _set_error(vformat(RTR("Duplicated hint: '%s'."), get_texture_filter_name(new_filter)));
+ _set_error(vformat(RTR("Duplicated filter mode: '%s'."), get_texture_filter_name(new_filter)));
} else {
- _set_error(vformat(RTR("Redefinition of hint: '%s'. The filter mode has already been set to '%s'."), get_texture_filter_name(new_filter), get_texture_filter_name(uniform.filter)));
+ _set_error(vformat(RTR("Redefinition of filter mode: '%s'. The filter mode has already been set to '%s'."), get_texture_filter_name(new_filter), get_texture_filter_name(uniform.filter)));
}
return ERR_PARSE_ERROR;
} else {
@@ -8613,9 +8697,9 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
if (new_repeat != REPEAT_DEFAULT) {
if (uniform.repeat != REPEAT_DEFAULT) {
if (uniform.repeat == new_repeat) {
- _set_error(vformat(RTR("Duplicated hint: '%s'."), get_texture_repeat_name(new_repeat)));
+ _set_error(vformat(RTR("Duplicated repeat mode: '%s'."), get_texture_repeat_name(new_repeat)));
} else {
- _set_error(vformat(RTR("Redefinition of hint: '%s'. The repeat mode has already been set to '%s'."), get_texture_repeat_name(new_repeat), get_texture_repeat_name(uniform.repeat)));
+ _set_error(vformat(RTR("Redefinition of repeat mode: '%s'. The repeat mode has already been set to '%s'."), get_texture_repeat_name(new_repeat), get_texture_repeat_name(uniform.repeat)));
}
return ERR_PARSE_ERROR;
} else {
@@ -10248,6 +10332,7 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
options.push_back("hint_anisotropy");
options.push_back("hint_default_black");
options.push_back("hint_default_white");
+ options.push_back("hint_default_transparent");
options.push_back("hint_normal");
options.push_back("hint_roughness_a");
options.push_back("hint_roughness_b");
@@ -10255,6 +10340,9 @@ Error ShaderLanguage::complete(const String &p_code, const ShaderCompileInfo &p_
options.push_back("hint_roughness_gray");
options.push_back("hint_roughness_normal");
options.push_back("hint_roughness_r");
+ options.push_back("hint_screen_texture");
+ options.push_back("hint_normal_roughness_texture");
+ options.push_back("hint_depth_texture");
options.push_back("source_color");
options.push_back("repeat_enable");
options.push_back("repeat_disable");
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index 09160e2949..75b713d167 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -164,6 +164,7 @@ public:
TK_RENDER_MODE,
TK_HINT_DEFAULT_WHITE_TEXTURE,
TK_HINT_DEFAULT_BLACK_TEXTURE,
+ TK_HINT_DEFAULT_TRANSPARENT_TEXTURE,
TK_HINT_NORMAL_TEXTURE,
TK_HINT_ROUGHNESS_NORMAL_TEXTURE,
TK_HINT_ROUGHNESS_R,
@@ -175,6 +176,9 @@ public:
TK_HINT_SOURCE_COLOR,
TK_HINT_RANGE,
TK_HINT_INSTANCE_INDEX,
+ TK_HINT_SCREEN_TEXTURE,
+ TK_HINT_NORMAL_ROUGHNESS_TEXTURE,
+ TK_HINT_DEPTH_TEXTURE,
TK_FILTER_NEAREST,
TK_FILTER_LINEAR,
TK_FILTER_NEAREST_MIPMAP,
@@ -664,7 +668,11 @@ public:
HINT_ROUGHNESS_GRAY,
HINT_DEFAULT_BLACK,
HINT_DEFAULT_WHITE,
+ HINT_DEFAULT_TRANSPARENT,
HINT_ANISOTROPY,
+ HINT_SCREEN_TEXTURE,
+ HINT_NORMAL_ROUGHNESS_TEXTURE,
+ HINT_DEPTH_TEXTURE,
HINT_MAX
};
diff --git a/servers/rendering/shader_preprocessor.cpp b/servers/rendering/shader_preprocessor.cpp
index a7b274b3e2..3766477070 100644
--- a/servers/rendering/shader_preprocessor.cpp
+++ b/servers/rendering/shader_preprocessor.cpp
@@ -349,6 +349,8 @@ void ShaderPreprocessor::process_directive(Tokenizer *p_tokenizer) {
process_ifdef(p_tokenizer);
} else if (directive == "ifndef") {
process_ifndef(p_tokenizer);
+ } else if (directive == "elif") {
+ process_elif(p_tokenizer);
} else if (directive == "else") {
process_else(p_tokenizer);
} else if (directive == "endif") {
@@ -415,24 +417,88 @@ void ShaderPreprocessor::process_define(Tokenizer *p_tokenizer) {
}
}
+void ShaderPreprocessor::process_elif(Tokenizer *p_tokenizer) {
+ const int line = p_tokenizer->get_line();
+
+ if (state->current_branch == nullptr || state->current_branch->else_defined) {
+ set_error(RTR("Unmatched elif."), line);
+ return;
+ }
+ if (state->previous_region != nullptr) {
+ state->previous_region->to_line = line - 1;
+ }
+
+ String body = tokens_to_string(p_tokenizer->advance('\n')).strip_edges();
+ if (body.is_empty()) {
+ set_error(RTR("Missing condition."), line);
+ return;
+ }
+
+ Error error = expand_condition(body, line, body);
+ if (error != OK) {
+ return;
+ }
+
+ error = expand_macros(body, line, body);
+ if (error != OK) {
+ return;
+ }
+
+ Expression expression;
+ Vector<String> names;
+ error = expression.parse(body, names);
+ if (error != OK) {
+ set_error(expression.get_error_text(), line);
+ return;
+ }
+
+ Variant v = expression.execute(Array(), nullptr, false);
+ if (v.get_type() == Variant::NIL) {
+ set_error(RTR("Condition evaluation error."), line);
+ return;
+ }
+
+ bool skip = false;
+ for (int i = 0; i < state->current_branch->conditions.size(); i++) {
+ if (state->current_branch->conditions[i]) {
+ skip = true;
+ break;
+ }
+ }
+
+ bool success = !skip && v.booleanize();
+ start_branch_condition(p_tokenizer, success, true);
+
+ if (state->save_regions) {
+ add_region(line + 1, success, state->previous_region->parent);
+ }
+}
+
void ShaderPreprocessor::process_else(Tokenizer *p_tokenizer) {
- if (state->skip_stack_else.is_empty()) {
- set_error(RTR("Unmatched else."), p_tokenizer->get_line());
+ const int line = p_tokenizer->get_line();
+
+ if (state->current_branch == nullptr || state->current_branch->else_defined) {
+ set_error(RTR("Unmatched else."), line);
return;
}
- p_tokenizer->advance('\n');
+ if (state->previous_region != nullptr) {
+ state->previous_region->to_line = line - 1;
+ }
- bool skip = state->skip_stack_else[state->skip_stack_else.size() - 1];
- state->skip_stack_else.remove_at(state->skip_stack_else.size() - 1);
+ p_tokenizer->advance('\n');
- Vector<SkippedCondition *> vec = state->skipped_conditions[state->current_include];
- int index = vec.size() - 1;
- if (index >= 0) {
- SkippedCondition *cond = vec[index];
- if (cond->end_line == -1) {
- cond->end_line = p_tokenizer->get_line();
+ bool skip = false;
+ for (int i = 0; i < state->current_branch->conditions.size(); i++) {
+ if (state->current_branch->conditions[i]) {
+ skip = true;
+ break;
}
}
+ state->current_branch->else_defined = true;
+
+ if (state->save_regions) {
+ add_region(line + 1, !skip, state->previous_region->parent);
+ }
if (skip) {
Vector<String> ends;
@@ -447,21 +513,19 @@ void ShaderPreprocessor::process_endif(Tokenizer *p_tokenizer) {
set_error(RTR("Unmatched endif."), p_tokenizer->get_line());
return;
}
-
- Vector<SkippedCondition *> vec = state->skipped_conditions[state->current_include];
- int index = vec.size() - 1;
- if (index >= 0) {
- SkippedCondition *cond = vec[index];
- if (cond->end_line == -1) {
- cond->end_line = p_tokenizer->get_line();
- }
+ if (state->previous_region != nullptr) {
+ state->previous_region->to_line = p_tokenizer->get_line() - 1;
+ state->previous_region = state->previous_region->parent;
}
p_tokenizer->advance('\n');
+
+ state->current_branch = state->current_branch->parent;
+ state->branches.pop_back();
}
void ShaderPreprocessor::process_if(Tokenizer *p_tokenizer) {
- int line = p_tokenizer->get_line();
+ const int line = p_tokenizer->get_line();
String body = tokens_to_string(p_tokenizer->advance('\n')).strip_edges();
if (body.is_empty()) {
@@ -469,7 +533,12 @@ void ShaderPreprocessor::process_if(Tokenizer *p_tokenizer) {
return;
}
- Error error = expand_macros(body, line, body);
+ Error error = expand_condition(body, line, body);
+ if (error != OK) {
+ return;
+ }
+
+ error = expand_macros(body, line, body);
if (error != OK) {
return;
}
@@ -490,6 +559,10 @@ void ShaderPreprocessor::process_if(Tokenizer *p_tokenizer) {
bool success = v.booleanize();
start_branch_condition(p_tokenizer, success);
+
+ if (state->save_regions) {
+ add_region(line + 1, success, state->previous_region);
+ }
}
void ShaderPreprocessor::process_ifdef(Tokenizer *p_tokenizer) {
@@ -510,6 +583,10 @@ void ShaderPreprocessor::process_ifdef(Tokenizer *p_tokenizer) {
bool success = state->defines.has(label);
start_branch_condition(p_tokenizer, success);
+
+ if (state->save_regions) {
+ add_region(line + 1, success, state->previous_region);
+ }
}
void ShaderPreprocessor::process_ifndef(Tokenizer *p_tokenizer) {
@@ -530,6 +607,10 @@ void ShaderPreprocessor::process_ifndef(Tokenizer *p_tokenizer) {
bool success = !state->defines.has(label);
start_branch_condition(p_tokenizer, success);
+
+ if (state->save_regions) {
+ add_region(line + 1, success, state->previous_region);
+ }
}
void ShaderPreprocessor::process_include(Tokenizer *p_tokenizer) {
@@ -594,15 +675,15 @@ void ShaderPreprocessor::process_include(Tokenizer *p_tokenizer) {
return;
}
- String old_include = state->current_include;
- state->current_include = real_path;
+ String old_filename = state->current_filename;
+ state->current_filename = real_path;
ShaderPreprocessor processor;
int prev_condition_depth = state->condition_depth;
state->condition_depth = 0;
FilePosition fp;
- fp.file = state->current_include;
+ fp.file = state->current_filename;
fp.line = line;
state->include_positions.push_back(fp);
@@ -614,7 +695,7 @@ void ShaderPreprocessor::process_include(Tokenizer *p_tokenizer) {
// Reset to last include if there are no errors. We want to use this as context.
if (state->error.is_empty()) {
- state->current_include = old_include;
+ state->current_filename = old_filename;
state->include_positions.pop_back();
} else {
return;
@@ -668,24 +749,28 @@ void ShaderPreprocessor::process_undef(Tokenizer *p_tokenizer) {
state->defines.erase(label);
}
-void ShaderPreprocessor::start_branch_condition(Tokenizer *p_tokenizer, bool p_success) {
- state->condition_depth++;
+void ShaderPreprocessor::add_region(int p_line, bool p_enabled, Region *p_parent_region) {
+ Region region;
+ region.file = state->current_filename;
+ region.enabled = p_enabled;
+ region.from_line = p_line;
+ region.parent = p_parent_region;
+ state->previous_region = &state->regions[region.file].push_back(region)->get();
+}
- if (p_success) {
- state->skip_stack_else.push_back(true);
+void ShaderPreprocessor::start_branch_condition(Tokenizer *p_tokenizer, bool p_success, bool p_continue) {
+ if (!p_continue) {
+ state->condition_depth++;
+ state->current_branch = &state->branches.push_back(Branch(p_success, state->current_branch))->get();
} else {
- SkippedCondition *cond = memnew(SkippedCondition());
- cond->start_line = p_tokenizer->get_line();
- state->skipped_conditions[state->current_include].push_back(cond);
-
+ state->current_branch->conditions.push_back(p_success);
+ }
+ if (!p_success) {
Vector<String> ends;
+ ends.push_back("elif");
ends.push_back("else");
ends.push_back("endif");
- if (next_directive(p_tokenizer, ends) == "else") {
- state->skip_stack_else.push_back(false);
- } else {
- state->skip_stack_else.push_back(true);
- }
+ next_directive(p_tokenizer, ends);
}
}
@@ -702,47 +787,173 @@ void ShaderPreprocessor::expand_output_macros(int p_start, int p_line_number) {
add_to_output(line);
}
-Error ShaderPreprocessor::expand_macros(const String &p_string, int p_line, String &r_expanded) {
- Vector<Pair<String, Define *>> active_defines;
- active_defines.resize(state->defines.size());
- int index = 0;
- for (const RBMap<String, Define *>::Element *E = state->defines.front(); E; E = E->next()) {
- active_defines.set(index++, Pair<String, Define *>(E->key(), E->get()));
+Error ShaderPreprocessor::expand_condition(const String &p_string, int p_line, String &r_expanded) {
+ // Checks bracket count to be even + check the cursor position.
+ {
+ int bracket_start_count = 0;
+ int bracket_end_count = 0;
+
+ for (int i = 0; i < p_string.size(); i++) {
+ switch (p_string[i]) {
+ case CURSOR:
+ state->completion_type = COMPLETION_TYPE_CONDITION;
+ break;
+ case '(':
+ bracket_start_count++;
+ break;
+ case ')':
+ bracket_end_count++;
+ break;
+ }
+ }
+ if (bracket_start_count > bracket_end_count) {
+ _set_expected_error(")", p_line);
+ return FAILED;
+ }
+ if (bracket_end_count > bracket_start_count) {
+ _set_expected_error("(", p_line);
+ return FAILED;
+ }
}
- return expand_macros(p_string, p_line, active_defines, r_expanded);
+ String result = p_string;
+
+ int index = 0;
+ int index_start = 0;
+ int index_end = 0;
+
+ while (find_match(result, "defined", index, index_start)) {
+ bool open_bracket = false;
+ bool found_word = false;
+ bool word_completed = false;
+
+ LocalVector<char32_t> text;
+ int post_bracket_index = -1;
+ int size = result.size();
+
+ for (int i = (index_start - 1); i < size; i++) {
+ char32_t c = result[i];
+ if (c == 0) {
+ if (found_word) {
+ word_completed = true;
+ }
+ break;
+ }
+ char32_t cs[] = { c, '\0' };
+ String s = String(cs);
+ bool is_space = is_char_space(c);
+
+ if (word_completed) {
+ if (c == ')') {
+ continue;
+ }
+ if (c == '|' || c == '&') {
+ if (open_bracket) {
+ _set_unexpected_token_error(s, p_line);
+ return FAILED;
+ }
+ break;
+ } else if (!is_space) {
+ _set_unexpected_token_error(s, p_line);
+ return FAILED;
+ }
+ } else if (is_space) {
+ if (found_word && !open_bracket) {
+ index_end = i;
+ word_completed = true;
+ }
+ } else if (c == '(') {
+ if (open_bracket) {
+ _set_unexpected_token_error(s, p_line);
+ return FAILED;
+ }
+ open_bracket = true;
+ } else if (c == ')') {
+ if (open_bracket) {
+ if (!found_word) {
+ _set_unexpected_token_error(s, p_line);
+ return FAILED;
+ }
+ open_bracket = false;
+ post_bracket_index = i + 1;
+ } else {
+ index_end = i;
+ }
+ word_completed = true;
+ } else if (is_char_word(c)) {
+ text.push_back(c);
+ found_word = true;
+ } else {
+ _set_unexpected_token_error(s, p_line);
+ return FAILED;
+ }
+ }
+
+ if (word_completed) {
+ if (open_bracket) {
+ _set_expected_error(")", p_line);
+ return FAILED;
+ }
+ if (post_bracket_index != -1) {
+ index_end = post_bracket_index;
+ }
+
+ String body = state->defines.has(vector_to_string(text)) ? "true" : "false";
+ String temp = result;
+
+ result = result.substr(0, index) + body;
+ index_start = result.length();
+ if (index_end > 0) {
+ result += temp.substr(index_end);
+ }
+ } else {
+ set_error(RTR("Invalid macro name."), p_line);
+ return FAILED;
+ }
+ }
+ r_expanded = result;
+ return OK;
}
-Error ShaderPreprocessor::expand_macros(const String &p_string, int p_line, Vector<Pair<String, Define *>> p_defines, String &r_expanded) {
- r_expanded = p_string;
- // When expanding macros we must only evaluate them once.
- // Later we continue expanding but with the already
- // evaluated macros removed.
- for (int i = 0; i < p_defines.size(); i++) {
- Pair<String, Define *> define_pair = p_defines[i];
-
- Error error = expand_macros_once(r_expanded, p_line, define_pair, r_expanded);
- if (error != OK) {
- return error;
+Error ShaderPreprocessor::expand_macros(const String &p_string, int p_line, String &r_expanded) {
+ String iterative = p_string;
+ int pass_count = 0;
+ bool expanded = true;
+
+ while (expanded) {
+ expanded = false;
+
+ // As long as we find something to expand, keep going.
+ for (const RBMap<String, Define *>::Element *E = state->defines.front(); E; E = E->next()) {
+ if (expand_macros_once(iterative, p_line, E, iterative)) {
+ expanded = true;
+ }
}
- // Remove expanded macro and recursively replace remaining.
- p_defines.remove_at(i);
- return expand_macros(r_expanded, p_line, p_defines, r_expanded);
+ pass_count++;
+ if (pass_count > 50) {
+ set_error(RTR("Macro expansion limit exceeded."), p_line);
+ break;
+ }
}
+ r_expanded = iterative;
+
+ if (!state->error.is_empty()) {
+ return FAILED;
+ }
return OK;
}
-Error ShaderPreprocessor::expand_macros_once(const String &p_line, int p_line_number, Pair<String, Define *> p_define_pair, String &r_expanded) {
+bool ShaderPreprocessor::expand_macros_once(const String &p_line, int p_line_number, const RBMap<String, Define *>::Element *p_define_pair, String &r_expanded) {
String result = p_line;
- const String &key = p_define_pair.first;
- const Define *define = p_define_pair.second;
+ const String &key = p_define_pair->key();
+ const Define *define = p_define_pair->value();
int index_start = 0;
int index = 0;
- while (find_match(result, key, index, index_start)) {
+ if (find_match(result, key, index, index_start)) {
String body = define->body;
if (define->arguments.size() > 0) {
// Complex macro with arguments.
@@ -750,14 +961,14 @@ Error ShaderPreprocessor::expand_macros_once(const String &p_line, int p_line_nu
int args_end = p_line.find(")", args_start);
if (args_start == -1 || args_end == -1) {
set_error(RTR("Missing macro argument parenthesis."), p_line_number);
- return FAILED;
+ return false;
}
String values = result.substr(args_start + 1, args_end - (args_start + 1));
Vector<String> args = values.split(",");
if (args.size() != define->arguments.size()) {
set_error(RTR("Invalid macro argument count."), p_line_number);
- return FAILED;
+ return false;
}
// Insert macro arguments into the body.
@@ -779,11 +990,13 @@ Error ShaderPreprocessor::expand_macros_once(const String &p_line, int p_line_nu
// Manually reset index_start to where the body value of the define finishes.
// This ensures we don't skip another instance of this macro in the string.
index_start = index + body.length() + 1;
- break;
}
+
+ r_expanded = result;
+ return true;
}
- r_expanded = result;
- return OK;
+
+ return false;
}
bool ShaderPreprocessor::find_match(const String &p_string, const String &p_value, int &r_index, int &r_index_start) {
@@ -874,12 +1087,6 @@ void ShaderPreprocessor::clear() {
memdelete(E->get());
}
- for (const RBMap<String, Vector<SkippedCondition *>>::Element *E = state->skipped_conditions.front(); E; E = E->next()) {
- for (SkippedCondition *condition : E->get()) {
- memdelete(condition);
- }
- }
-
memdelete(state);
}
state_owner = false;
@@ -969,8 +1176,12 @@ Error ShaderPreprocessor::preprocess(State *p_state, const String &p_code, Strin
return OK;
}
-Error ShaderPreprocessor::preprocess(const String &p_code, String &r_result, String *r_error_text, List<FilePosition> *r_error_position, HashSet<Ref<ShaderInclude>> *r_includes, List<ScriptLanguage::CodeCompletionOption> *r_completion_options, IncludeCompletionFunction p_include_completion_func) {
+Error ShaderPreprocessor::preprocess(const String &p_code, const String &p_filename, String &r_result, String *r_error_text, List<FilePosition> *r_error_position, List<Region> *r_regions, HashSet<Ref<ShaderInclude>> *r_includes, List<ScriptLanguage::CodeCompletionOption> *r_completion_options, IncludeCompletionFunction p_include_completion_func) {
State pp_state;
+ if (!p_filename.is_empty()) {
+ pp_state.current_filename = p_filename;
+ pp_state.save_regions = r_regions != nullptr;
+ }
Error err = preprocess(&pp_state, p_code, r_result);
if (err != OK) {
if (r_error_text) {
@@ -980,6 +1191,9 @@ Error ShaderPreprocessor::preprocess(const String &p_code, String &r_result, Str
*r_error_position = pp_state.include_positions;
}
}
+ if (r_regions) {
+ *r_regions = pp_state.regions[p_filename];
+ }
if (r_includes) {
*r_includes = pp_state.shader_includes;
}
@@ -988,7 +1202,7 @@ Error ShaderPreprocessor::preprocess(const String &p_code, String &r_result, Str
switch (pp_state.completion_type) {
case COMPLETION_TYPE_DIRECTIVE: {
List<String> options;
- get_keyword_list(&options, true);
+ get_keyword_list(&options, true, true);
for (const String &E : options) {
ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
@@ -1007,6 +1221,11 @@ Error ShaderPreprocessor::preprocess(const String &p_code, String &r_result, Str
}
} break;
+ case COMPLETION_TYPE_CONDITION: {
+ ScriptLanguage::CodeCompletionOption option("defined", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
+ r_completion_options->push_back(option);
+
+ } break;
case COMPLETION_TYPE_INCLUDE_PATH: {
if (p_include_completion_func && r_completion_options) {
p_include_completion_func(r_completion_options);
@@ -1020,8 +1239,12 @@ Error ShaderPreprocessor::preprocess(const String &p_code, String &r_result, Str
return err;
}
-void ShaderPreprocessor::get_keyword_list(List<String> *r_keywords, bool p_include_shader_keywords) {
+void ShaderPreprocessor::get_keyword_list(List<String> *r_keywords, bool p_include_shader_keywords, bool p_ignore_context_keywords) {
r_keywords->push_back("define");
+ if (!p_ignore_context_keywords) {
+ r_keywords->push_back("defined");
+ }
+ r_keywords->push_back("elif");
if (p_include_shader_keywords) {
r_keywords->push_back("else");
}
diff --git a/servers/rendering/shader_preprocessor.h b/servers/rendering/shader_preprocessor.h
index a93fb680dd..b4e7c7199f 100644
--- a/servers/rendering/shader_preprocessor.h
+++ b/servers/rendering/shader_preprocessor.h
@@ -50,6 +50,7 @@ public:
COMPLETION_TYPE_DIRECTIVE,
COMPLETION_TYPE_PRAGMA_DIRECTIVE,
COMPLETION_TYPE_PRAGMA,
+ COMPLETION_TYPE_CONDITION,
COMPLETION_TYPE_INCLUDE_PATH,
};
@@ -58,6 +59,14 @@ public:
int line = 0;
};
+ struct Region {
+ String file;
+ int from_line = -1;
+ int to_line = -1;
+ bool enabled = false;
+ Region *parent = nullptr;
+ };
+
private:
struct Token {
char32_t text;
@@ -122,23 +131,34 @@ private:
String body;
};
- struct SkippedCondition {
- int start_line = -1;
- int end_line = -1;
+ struct Branch {
+ Vector<bool> conditions;
+ Branch *parent = nullptr;
+ bool else_defined = false;
+
+ Branch() {}
+
+ Branch(bool p_condition, Branch *p_parent) :
+ parent(p_parent) {
+ conditions.push_back(p_condition);
+ }
};
struct State {
RBMap<String, Define *> defines;
- Vector<bool> skip_stack_else;
+ List<Branch> branches;
+ Branch *current_branch = nullptr;
int condition_depth = 0;
RBSet<String> includes;
List<uint64_t> cyclic_include_hashes; // Holds code hash of includes.
int include_depth = 0;
- String current_include;
+ String current_filename;
String current_shader_type;
String error;
List<FilePosition> include_positions;
- RBMap<String, Vector<SkippedCondition *>> skipped_conditions;
+ bool save_regions = false;
+ RBMap<String, List<Region>> regions;
+ Region *previous_region = nullptr;
bool disabled = false;
CompletionType completion_type = COMPLETION_TYPE_NONE;
HashSet<Ref<ShaderInclude>> shader_includes;
@@ -156,8 +176,17 @@ private:
static String vector_to_string(const LocalVector<char32_t> &p_v, int p_start = 0, int p_end = -1);
static String tokens_to_string(const LocalVector<Token> &p_tokens);
+ void _set_expected_error(const String &p_what, int p_line) {
+ set_error(vformat(RTR("Expected a '%s'."), p_what), p_line);
+ }
+
+ void _set_unexpected_token_error(const String &p_what, int p_line) {
+ set_error(vformat(RTR("Unexpected token '%s'."), p_what), p_line);
+ }
+
void process_directive(Tokenizer *p_tokenizer);
void process_define(Tokenizer *p_tokenizer);
+ void process_elif(Tokenizer *p_tokenizer);
void process_else(Tokenizer *p_tokenizer);
void process_endif(Tokenizer *p_tokenizer);
void process_if(Tokenizer *p_tokenizer);
@@ -167,12 +196,13 @@ private:
void process_pragma(Tokenizer *p_tokenizer);
void process_undef(Tokenizer *p_tokenizer);
- void start_branch_condition(Tokenizer *p_tokenizer, bool p_success);
+ void add_region(int p_line, bool p_enabled, Region *p_parent_region);
+ void start_branch_condition(Tokenizer *p_tokenizer, bool p_success, bool p_continue = false);
+ Error expand_condition(const String &p_string, int p_line, String &r_result);
void expand_output_macros(int p_start, int p_line);
Error expand_macros(const String &p_string, int p_line, String &r_result);
- Error expand_macros(const String &p_string, int p_line, Vector<Pair<String, Define *>> p_defines, String &r_result);
- Error expand_macros_once(const String &p_line, int p_line_number, Pair<String, Define *> p_define_pair, String &r_expanded);
+ bool expand_macros_once(const String &p_line, int p_line_number, const RBMap<String, Define *>::Element *p_define_pair, String &r_expanded);
bool find_match(const String &p_string, const String &p_value, int &r_index, int &r_index_start);
String next_directive(Tokenizer *p_tokenizer, const Vector<String> &p_directives);
@@ -188,9 +218,9 @@ private:
public:
typedef void (*IncludeCompletionFunction)(List<ScriptLanguage::CodeCompletionOption> *);
- Error preprocess(const String &p_code, String &r_result, String *r_error_text = nullptr, List<FilePosition> *r_error_position = nullptr, HashSet<Ref<ShaderInclude>> *r_includes = nullptr, List<ScriptLanguage::CodeCompletionOption> *r_completion_options = nullptr, IncludeCompletionFunction p_include_completion_func = nullptr);
+ Error preprocess(const String &p_code, const String &p_filename, String &r_result, String *r_error_text = nullptr, List<FilePosition> *r_error_position = nullptr, List<Region> *r_regions = nullptr, HashSet<Ref<ShaderInclude>> *r_includes = nullptr, List<ScriptLanguage::CodeCompletionOption> *r_completion_options = nullptr, IncludeCompletionFunction p_include_completion_func = nullptr);
- static void get_keyword_list(List<String> *r_keywords, bool p_include_shader_keywords);
+ static void get_keyword_list(List<String> *r_keywords, bool p_include_shader_keywords, bool p_ignore_context_keywords = false);
static void get_pragma_list(List<String> *r_pragmas);
ShaderPreprocessor();
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index 5772179d68..43c483a00d 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -97,6 +97,11 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL);
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["NODE_POSITION_WORLD"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_POSITION_WORLD"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["CAMERA_DIRECTION_WORLD"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["NODE_POSITION_VIEW"] = ShaderLanguage::TYPE_VEC3;
+
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEW_INDEX"] = constt(ShaderLanguage::TYPE_INT);
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEW_MONO_LEFT"] = constt(ShaderLanguage::TYPE_INT);
shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEW_RIGHT"] = constt(ShaderLanguage::TYPE_INT);
@@ -139,6 +144,11 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NODE_POSITION_WORLD"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CAMERA_POSITION_WORLD"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["CAMERA_DIRECTION_WORLD"] = ShaderLanguage::TYPE_VEC3;
+ shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NODE_POSITION_VIEW"] = ShaderLanguage::TYPE_VEC3;
+
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_INDEX"] = constt(ShaderLanguage::TYPE_INT);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_MONO_LEFT"] = constt(ShaderLanguage::TYPE_INT);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_RIGHT"] = constt(ShaderLanguage::TYPE_INT);
diff --git a/servers/rendering/storage/environment_storage.h b/servers/rendering/storage/environment_storage.h
index bd1c17deec..29bba86930 100644
--- a/servers/rendering/storage/environment_storage.h
+++ b/servers/rendering/storage/environment_storage.h
@@ -67,10 +67,10 @@ private:
// Fog
bool fog_enabled = false;
- Color fog_light_color = Color(0.5, 0.6, 0.7);
+ Color fog_light_color = Color(0.518, 0.553, 0.608);
float fog_light_energy = 1.0;
float fog_sun_scatter = 0.0;
- float fog_density = 0.001;
+ float fog_density = 0.01;
float fog_height = 0.0;
float fog_height_density = 0.0; //can be negative to invert effect
float fog_aerial_perspective = 0.0;
@@ -84,10 +84,10 @@ private:
float volumetric_fog_anisotropy = 0.2;
float volumetric_fog_length = 64.0;
float volumetric_fog_detail_spread = 2.0;
- float volumetric_fog_gi_inject = 0.0;
+ float volumetric_fog_gi_inject = 1.0;
+ float volumetric_fog_ambient_inject = 0.0;
bool volumetric_fog_temporal_reprojection = true;
float volumetric_fog_temporal_reprojection_amount = 0.9;
- float volumetric_fog_ambient_inject = 0.0;
// Glow
bool glow_enabled = false;
diff --git a/servers/rendering/storage/material_storage.h b/servers/rendering/storage/material_storage.h
index 6347b22240..ad8e3e79bf 100644
--- a/servers/rendering/storage/material_storage.h
+++ b/servers/rendering/storage/material_storage.h
@@ -63,7 +63,7 @@ public:
virtual void shader_set_code(RID p_shader, const String &p_code) = 0;
virtual void shader_set_path_hint(RID p_shader, const String &p_path) = 0;
virtual String shader_get_code(RID p_shader) const = 0;
- virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const = 0;
+ virtual void shader_get_shader_uniform_list(RID p_shader, List<PropertyInfo> *p_param_list) const = 0;
virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture, int p_index) = 0;
virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name, int p_index) const = 0;
@@ -94,7 +94,7 @@ public:
Variant default_value;
};
- virtual void material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) = 0;
+ virtual void material_get_instance_shader_uniforms(RID p_material, List<InstanceShaderParam> *r_parameters) = 0;
virtual void material_update_dependency(RID p_material, DependencyTracker *p_instance) = 0;
};
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index bb76281782..30b6faa360 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -31,6 +31,7 @@
#include "rendering_server.h"
#include "core/config/project_settings.h"
+#include "core/variant/typed_array.h"
#include "servers/rendering/rendering_server_globals.h"
#include "servers/rendering/shader_language.h"
@@ -69,44 +70,44 @@ Array RenderingServer::_texture_debug_usage_bind() {
return arr;
}
-static Array to_array(const Vector<ObjectID> &ids) {
- Array a;
+static PackedInt64Array to_int_array(const Vector<ObjectID> &ids) {
+ PackedInt64Array a;
a.resize(ids.size());
for (int i = 0; i < ids.size(); ++i) {
- a[i] = ids[i];
+ a.write[i] = ids[i];
}
return a;
}
-Array RenderingServer::_instances_cull_aabb_bind(const AABB &p_aabb, RID p_scenario) const {
+PackedInt64Array RenderingServer::_instances_cull_aabb_bind(const AABB &p_aabb, RID p_scenario) const {
if (RSG::threaded) {
WARN_PRINT_ONCE("Using this function with a threaded renderer hurts performance, as it causes a server stall.");
}
Vector<ObjectID> ids = instances_cull_aabb(p_aabb, p_scenario);
- return to_array(ids);
+ return to_int_array(ids);
}
-Array RenderingServer::_instances_cull_ray_bind(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario) const {
+PackedInt64Array RenderingServer::_instances_cull_ray_bind(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario) const {
if (RSG::threaded) {
WARN_PRINT_ONCE("Using this function with a threaded renderer hurts performance, as it causes a server stall.");
}
Vector<ObjectID> ids = instances_cull_ray(p_from, p_to, p_scenario);
- return to_array(ids);
+ return to_int_array(ids);
}
-Array RenderingServer::_instances_cull_convex_bind(const Array &p_convex, RID p_scenario) const {
+PackedInt64Array RenderingServer::_instances_cull_convex_bind(const Array &p_convex, RID p_scenario) const {
if (RSG::threaded) {
WARN_PRINT_ONCE("Using this function with a threaded renderer hurts performance, as it causes a server stall.");
}
Vector<Plane> planes;
for (int i = 0; i < p_convex.size(); ++i) {
Variant v = p_convex[i];
- ERR_FAIL_COND_V(v.get_type() != Variant::PLANE, Array());
+ ERR_FAIL_COND_V(v.get_type() != Variant::PLANE, PackedInt64Array());
planes.push_back(v);
}
Vector<ObjectID> ids = instances_cull_convex(planes, p_scenario);
- return to_array(ids);
+ return to_int_array(ids);
}
RID RenderingServer::get_test_texture() {
@@ -398,16 +399,14 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
const Vector3 *src = array.ptr();
for (int i = 0; i < p_vertex_array_len; i++) {
- Vector3 n = src[i] * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
-
- uint32_t value = 0;
- value |= CLAMP(int(n.x * 1023.0), 0, 1023);
- value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10;
- value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20;
+ Vector2 res = src[i].octahedron_encode();
+ int16_t vector[2] = {
+ (int16_t)CLAMP(res.x * 65535, 0, 65535),
+ (int16_t)CLAMP(res.y * 65535, 0, 65535),
+ };
- memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4);
+ memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, 4);
}
-
} break;
case RS::ARRAY_TANGENT: {
@@ -416,33 +415,32 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
if (type == Variant::PACKED_FLOAT32_ARRAY) {
Vector<float> array = p_arrays[ai];
ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER);
- const float *src = array.ptr();
+ const float *src_ptr = array.ptr();
for (int i = 0; i < p_vertex_array_len; i++) {
- uint32_t value = 0;
- value |= CLAMP(int((src[i * 4 + 0] * 0.5 + 0.5) * 1023.0), 0, 1023);
- value |= CLAMP(int((src[i * 4 + 1] * 0.5 + 0.5) * 1023.0), 0, 1023) << 10;
- value |= CLAMP(int((src[i * 4 + 2] * 0.5 + 0.5) * 1023.0), 0, 1023) << 20;
- if (src[i * 4 + 3] > 0) {
- value |= 3UL << 30;
- }
-
- memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4);
+ const Vector3 src(src_ptr[i * 4 + 0], src_ptr[i * 4 + 1], src_ptr[i * 4 + 2]);
+ Vector2 res = src.octahedron_tangent_encode(src_ptr[i * 4 + 3]);
+ int16_t vector[2] = {
+ (int16_t)CLAMP(res.x * 65535, 0, 65535),
+ (int16_t)CLAMP(res.y * 65535, 0, 65535),
+ };
+
+ memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, 4);
}
} else { // PACKED_FLOAT64_ARRAY
Vector<double> array = p_arrays[ai];
ERR_FAIL_COND_V(array.size() != p_vertex_array_len * 4, ERR_INVALID_PARAMETER);
- const double *src = array.ptr();
+ const double *src_ptr = array.ptr();
for (int i = 0; i < p_vertex_array_len; i++) {
- uint32_t value = 0;
- value |= CLAMP(int((src[i * 4 + 0] * 0.5 + 0.5) * 1023.0), 0, 1023);
- value |= CLAMP(int((src[i * 4 + 1] * 0.5 + 0.5) * 1023.0), 0, 1023) << 10;
- value |= CLAMP(int((src[i * 4 + 2] * 0.5 + 0.5) * 1023.0), 0, 1023) << 20;
- if (src[i * 4 + 3] > 0) {
- value |= 3UL << 30;
- }
- memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4);
+ const Vector3 src(src_ptr[i * 4 + 0], src_ptr[i * 4 + 1], src_ptr[i * 4 + 2]);
+ Vector2 res = src.octahedron_tangent_encode(src_ptr[i * 4 + 3]);
+ int16_t vector[2] = {
+ (int16_t)CLAMP(res.x * 65535, 0, 65535),
+ (int16_t)CLAMP(res.y * 65535, 0, 65535),
+ };
+
+ memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], vector, 4);
}
}
} break;
@@ -627,7 +625,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
const int *src = indices.ptr();
for (int i = 0; i < p_index_array_len; i++) {
- if (p_vertex_array_len < (1 << 16)) {
+ if (p_vertex_array_len < (1 << 16) && p_vertex_array_len > 0) {
uint16_t v = src[i];
memcpy(&iw[i * 2], &v, 2);
@@ -836,9 +834,8 @@ void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, i
break;
}
/* determine whether using 16 or 32 bits indices */
- if (p_vertex_len >= (1 << 16)) {
+ if (p_vertex_len >= (1 << 16) || p_vertex_len == 0) {
elem_size = 4;
-
} else {
elem_size = 2;
}
@@ -909,8 +906,6 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa
}
}
- ERR_FAIL_COND_V((format & RS::ARRAY_FORMAT_VERTEX) == 0, ERR_INVALID_PARAMETER); // Mandatory
-
if (p_blend_shapes.size()) {
// Validate format for morphs.
for (int i = 0; i < p_blend_shapes.size(); i++) {
@@ -944,6 +939,12 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa
uint32_t mask = (1 << ARRAY_MAX) - 1;
format |= (~mask) & p_compress_format; // Make the full format.
+ if ((format & RS::ARRAY_FORMAT_VERTEX) == 0 && !(format & RS::ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY)) {
+ ERR_PRINT("Mesh created without vertex array. This mesh will not be visible with the default shader. If using an empty vertex array is intentional, create the mesh with the ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY flag to silence this error.");
+ // Set the flag here after warning to suppress errors down the pipeline.
+ format |= RS::ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY;
+ }
+
int vertex_array_size = vertex_element_size * array_len;
int attrib_array_size = attrib_element_size * array_len;
int skin_array_size = skin_element_size * array_len;
@@ -1337,7 +1338,7 @@ Dictionary RenderingServer::mesh_surface_get_lods(RID p_mesh, int p_surface) con
return ret;
}
-Array RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_surface) const {
+TypedArray<Array> RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_surface) const {
SurfaceData sd = mesh_get_surface(p_mesh, p_surface);
ERR_FAIL_COND_V(sd.vertex_count == 0, Array());
@@ -1359,7 +1360,7 @@ Array RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_sur
ERR_FAIL_COND_V(blend_shape_count != (uint32_t)mesh_get_blend_shape_count(p_mesh), Array());
- Array blend_shape_array;
+ TypedArray<Array> blend_shape_array;
blend_shape_array.resize(mesh_get_blend_shape_count(p_mesh));
for (uint32_t i = 0; i < blend_shape_count; i++) {
Vector<uint8_t> bs_data = blend_shape_data.slice(i * divisor, (i + 1) * divisor);
@@ -1369,7 +1370,7 @@ Array RenderingServer::mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_sur
return blend_shape_array;
} else {
- return Array();
+ return TypedArray<Array>();
}
}
@@ -1378,7 +1379,7 @@ Array RenderingServer::mesh_create_arrays_from_surface_data(const SurfaceData &p
Vector<uint8_t> attrib_data = p_data.attribute_data;
Vector<uint8_t> skin_data = p_data.skin_data;
- ERR_FAIL_COND_V(vertex_data.size() == 0, Array());
+ ERR_FAIL_COND_V(vertex_data.size() == 0 && (p_data.format & RS::ARRAY_FORMAT_VERTEX), Array());
int vertex_len = p_data.vertex_count;
Vector<uint8_t> index_data = p_data.index_data;
@@ -1500,9 +1501,9 @@ TypedArray<Image> RenderingServer::_texture_3d_get(RID p_texture) const {
return ret;
}
-TypedArray<Dictionary> RenderingServer::_shader_get_param_list(RID p_shader) const {
+TypedArray<Dictionary> RenderingServer::_shader_get_shader_uniform_list(RID p_shader) const {
List<PropertyInfo> l;
- shader_get_param_list(p_shader, &l);
+ shader_get_shader_uniform_list(p_shader, &l);
return convert_property_list(&l);
}
@@ -1625,9 +1626,9 @@ Dictionary RenderingServer::_mesh_get_surface(RID p_mesh, int p_idx) {
return d;
}
-Array RenderingServer::_instance_geometry_get_shader_parameter_list(RID p_instance) const {
+TypedArray<Dictionary> RenderingServer::_instance_geometry_get_shader_uniform_list(RID p_instance) const {
List<PropertyInfo> params;
- instance_geometry_get_shader_parameter_list(p_instance, &params);
+ instance_geometry_get_shader_uniform_list(p_instance, &params);
return convert_property_list(&params);
}
@@ -1701,7 +1702,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("shader_set_code", "shader", "code"), &RenderingServer::shader_set_code);
ClassDB::bind_method(D_METHOD("shader_set_path_hint", "shader", "path"), &RenderingServer::shader_set_path_hint);
ClassDB::bind_method(D_METHOD("shader_get_code", "shader"), &RenderingServer::shader_get_code);
- ClassDB::bind_method(D_METHOD("shader_get_param_list", "shader"), &RenderingServer::_shader_get_param_list);
+ ClassDB::bind_method(D_METHOD("shader_get_shader_uniform_list", "shader"), &RenderingServer::_shader_get_shader_uniform_list);
ClassDB::bind_method(D_METHOD("shader_get_param_default", "shader", "param"), &RenderingServer::shader_get_param_default);
ClassDB::bind_method(D_METHOD("shader_set_default_texture_param", "shader", "param", "texture", "index"), &RenderingServer::shader_set_default_texture_param, DEFVAL(0));
@@ -1885,9 +1886,10 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("light_projectors_set_filter", "filter"), &RenderingServer::light_projectors_set_filter);
BIND_ENUM_CONSTANT(LIGHT_PROJECTOR_FILTER_NEAREST);
- BIND_ENUM_CONSTANT(LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS);
BIND_ENUM_CONSTANT(LIGHT_PROJECTOR_FILTER_LINEAR);
+ BIND_ENUM_CONSTANT(LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS);
BIND_ENUM_CONSTANT(LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS);
+ BIND_ENUM_CONSTANT(LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC);
BIND_ENUM_CONSTANT(LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC);
BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL);
@@ -1910,6 +1912,7 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_NORMAL_BIAS);
BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_BIAS);
BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_PANCAKE_SIZE);
+ BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_OPACITY);
BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_BLUR);
BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE);
BIND_ENUM_CONSTANT(LIGHT_PARAM_TRANSMITTANCE_BIAS);
@@ -1989,9 +1992,10 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(DECAL_TEXTURE_MAX);
BIND_ENUM_CONSTANT(DECAL_FILTER_NEAREST);
- BIND_ENUM_CONSTANT(DECAL_FILTER_NEAREST_MIPMAPS);
BIND_ENUM_CONSTANT(DECAL_FILTER_LINEAR);
+ BIND_ENUM_CONSTANT(DECAL_FILTER_NEAREST_MIPMAPS);
BIND_ENUM_CONSTANT(DECAL_FILTER_LINEAR_MIPMAPS);
+ BIND_ENUM_CONSTANT(DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC);
BIND_ENUM_CONSTANT(DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC);
/* GI API (affects VoxelGI and SDFGI) */
@@ -2482,10 +2486,10 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("instance_geometry_set_lightmap", "instance", "lightmap", "lightmap_uv_scale", "lightmap_slice"), &RenderingServer::instance_geometry_set_lightmap);
ClassDB::bind_method(D_METHOD("instance_geometry_set_lod_bias", "instance", "lod_bias"), &RenderingServer::instance_geometry_set_lod_bias);
- ClassDB::bind_method(D_METHOD("instance_geometry_set_shader_parameter", "instance", "parameter", "value"), &RenderingServer::instance_geometry_set_shader_parameter);
- ClassDB::bind_method(D_METHOD("instance_geometry_get_shader_parameter", "instance", "parameter"), &RenderingServer::instance_geometry_get_shader_parameter);
- ClassDB::bind_method(D_METHOD("instance_geometry_get_shader_parameter_default_value", "instance", "parameter"), &RenderingServer::instance_geometry_get_shader_parameter_default_value);
- ClassDB::bind_method(D_METHOD("instance_geometry_get_shader_parameter_list", "instance"), &RenderingServer::_instance_geometry_get_shader_parameter_list);
+ ClassDB::bind_method(D_METHOD("instance_geometry_set_shader_uniform", "instance", "parameter", "value"), &RenderingServer::instance_geometry_set_shader_uniform);
+ ClassDB::bind_method(D_METHOD("instance_geometry_get_shader_uniform", "instance", "parameter"), &RenderingServer::instance_geometry_get_shader_uniform);
+ ClassDB::bind_method(D_METHOD("instance_geometry_get_shader_uniform_default_value", "instance", "parameter"), &RenderingServer::instance_geometry_get_shader_uniform_default_value);
+ ClassDB::bind_method(D_METHOD("instance_geometry_get_shader_uniform_list", "instance"), &RenderingServer::_instance_geometry_get_shader_uniform_list);
ClassDB::bind_method(D_METHOD("instances_cull_aabb", "aabb", "scenario"), &RenderingServer::_instances_cull_aabb_bind, DEFVAL(RID()));
ClassDB::bind_method(D_METHOD("instances_cull_ray", "from", "to", "scenario"), &RenderingServer::_instances_cull_ray_bind, DEFVAL(RID()));
@@ -2576,6 +2580,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("canvas_item_add_circle", "item", "pos", "radius", "color"), &RenderingServer::canvas_item_add_circle);
ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect", "item", "rect", "texture", "tile", "modulate", "transpose"), &RenderingServer::canvas_item_add_texture_rect, DEFVAL(false), DEFVAL(Color(1, 1, 1)), DEFVAL(false));
ClassDB::bind_method(D_METHOD("canvas_item_add_msdf_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate", "outline_size", "px_range"), &RenderingServer::canvas_item_add_msdf_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("canvas_item_add_lcd_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate"), &RenderingServer::canvas_item_add_lcd_texture_rect_region);
ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate", "transpose", "clip_uv"), &RenderingServer::canvas_item_add_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(true));
ClassDB::bind_method(D_METHOD("canvas_item_add_nine_patch", "item", "rect", "source", "texture", "topleft", "bottomright", "x_axis_mode", "y_axis_mode", "draw_center", "modulate"), &RenderingServer::canvas_item_add_nine_patch, DEFVAL(NINE_PATCH_STRETCH), DEFVAL(NINE_PATCH_STRETCH), DEFVAL(true), DEFVAL(Color(1, 1, 1)));
ClassDB::bind_method(D_METHOD("canvas_item_add_primitive", "item", "points", "colors", "uvs", "texture", "width"), &RenderingServer::canvas_item_add_primitive, DEFVAL(1.0));
@@ -2956,9 +2961,9 @@ void RenderingServer::init() {
PROPERTY_HINT_RANGE, "-2,2,0.001"));
GLOBAL_DEF("rendering/textures/decals/filter", DECAL_FILTER_LINEAR_MIPMAPS);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/textures/decals/filter", PropertyInfo(Variant::INT, "rendering/textures/decals/filter", PROPERTY_HINT_ENUM, "Nearest (Fast),Nearest+Mipmaps,Linear,Linear+Mipmaps,Linear+Mipmaps Anisotropic (Slow)"));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/textures/decals/filter", PropertyInfo(Variant::INT, "rendering/textures/decals/filter", PROPERTY_HINT_ENUM, "Nearest (Fast),Linear (Fast),Nearest Mipmap (Fast),Linear Mipmap (Fast),Nearest Mipmap Anisotropic (Average),Linear Mipmap Anisotropic (Average)"));
GLOBAL_DEF("rendering/textures/light_projectors/filter", LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/textures/light_projectors/filter", PropertyInfo(Variant::INT, "rendering/textures/light_projectors/filter", PROPERTY_HINT_ENUM, "Nearest (Fast),Nearest+Mipmaps,Linear,Linear+Mipmaps,Linear+Mipmaps Anisotropic (Slow)"));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/textures/light_projectors/filter", PropertyInfo(Variant::INT, "rendering/textures/light_projectors/filter", PROPERTY_HINT_ENUM, "Nearest (Fast),Linear (Fast),Nearest Mipmap (Fast),Linear Mipmap (Fast),Nearest Mipmap Anisotropic (Average),Linear Mipmap Anisotropic (Average)"));
GLOBAL_DEF_RST("rendering/occlusion_culling/occlusion_rays_per_thread", 512);
GLOBAL_DEF_RST("rendering/occlusion_culling/bvh_build_quality", 2);
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 1f2012ac8d..56295a2c5f 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -42,6 +42,9 @@
#include "servers/display_server.h"
#include "servers/rendering/rendering_device.h"
+template <typename T>
+class TypedArray;
+
class RenderingServer : public Object {
GDCLASS(RenderingServer, Object);
@@ -170,7 +173,7 @@ public:
virtual void shader_set_code(RID p_shader, const String &p_code) = 0;
virtual void shader_set_path_hint(RID p_shader, const String &p_path) = 0;
virtual String shader_get_code(RID p_shader) const = 0;
- virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const = 0;
+ virtual void shader_get_shader_uniform_list(RID p_shader, List<PropertyInfo> *p_param_list) const = 0;
virtual Variant shader_get_param_default(RID p_shader, const StringName &p_param) const = 0;
virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture, int p_index = 0) = 0;
@@ -244,7 +247,7 @@ public:
enum ArrayFormat {
/* ARRAY FORMAT FLAGS */
- ARRAY_FORMAT_VERTEX = 1 << ARRAY_VERTEX, // Mandatory
+ ARRAY_FORMAT_VERTEX = 1 << ARRAY_VERTEX,
ARRAY_FORMAT_NORMAL = 1 << ARRAY_NORMAL,
ARRAY_FORMAT_TANGENT = 1 << ARRAY_TANGENT,
ARRAY_FORMAT_COLOR = 1 << ARRAY_COLOR,
@@ -262,17 +265,19 @@ public:
ARRAY_FORMAT_CUSTOM_BASE = (ARRAY_INDEX + 1),
ARRAY_FORMAT_CUSTOM_BITS = 3,
+ ARRAY_FORMAT_CUSTOM_MASK = 0x7,
ARRAY_FORMAT_CUSTOM0_SHIFT = (ARRAY_FORMAT_CUSTOM_BASE + 0),
ARRAY_FORMAT_CUSTOM1_SHIFT = (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS),
ARRAY_FORMAT_CUSTOM2_SHIFT = (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * 2),
ARRAY_FORMAT_CUSTOM3_SHIFT = (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * 3),
- ARRAY_FORMAT_CUSTOM_MASK = 0x7,
ARRAY_COMPRESS_FLAGS_BASE = (ARRAY_INDEX + 1 + 12),
ARRAY_FLAG_USE_2D_VERTICES = 1 << (ARRAY_COMPRESS_FLAGS_BASE + 0),
ARRAY_FLAG_USE_DYNAMIC_UPDATE = 1 << (ARRAY_COMPRESS_FLAGS_BASE + 1),
ARRAY_FLAG_USE_8_BONE_WEIGHTS = 1 << (ARRAY_COMPRESS_FLAGS_BASE + 2),
+
+ ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY = 1 << (ARRAY_INDEX + 1 + 15),
};
enum PrimitiveType {
@@ -323,7 +328,7 @@ public:
virtual Error mesh_create_surface_data_from_arrays(SurfaceData *r_surface_data, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = 0);
Array mesh_create_arrays_from_surface_data(const SurfaceData &p_data) const;
Array mesh_surface_get_arrays(RID p_mesh, int p_surface) const;
- Array mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_surface) const;
+ TypedArray<Array> mesh_surface_get_blend_shape_arrays(RID p_mesh, int p_surface) const;
Dictionary mesh_surface_get_lods(RID p_mesh, int p_surface) const;
virtual void mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), uint32_t p_compress_format = 0);
@@ -425,6 +430,7 @@ public:
LIGHT_PARAM_SHADOW_NORMAL_BIAS,
LIGHT_PARAM_SHADOW_BIAS,
LIGHT_PARAM_SHADOW_PANCAKE_SIZE,
+ LIGHT_PARAM_SHADOW_OPACITY,
LIGHT_PARAM_SHADOW_BLUR,
LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE,
LIGHT_PARAM_TRANSMITTANCE_BIAS,
@@ -495,9 +501,10 @@ public:
enum LightProjectorFilter {
LIGHT_PROJECTOR_FILTER_NEAREST,
- LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS,
LIGHT_PROJECTOR_FILTER_LINEAR,
+ LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS,
LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS,
+ LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC,
LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC,
};
@@ -557,9 +564,10 @@ public:
enum DecalFilter {
DECAL_FILTER_NEAREST,
- DECAL_FILTER_NEAREST_MIPMAPS,
DECAL_FILTER_LINEAR,
+ DECAL_FILTER_NEAREST_MIPMAPS,
DECAL_FILTER_LINEAR_MIPMAPS,
+ DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC,
DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC,
};
@@ -1208,9 +1216,9 @@ public:
virtual Vector<ObjectID> instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const = 0;
virtual Vector<ObjectID> instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario = RID()) const = 0;
- Array _instances_cull_aabb_bind(const AABB &p_aabb, RID p_scenario = RID()) const;
- Array _instances_cull_ray_bind(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const;
- Array _instances_cull_convex_bind(const Array &p_convex, RID p_scenario = RID()) const;
+ PackedInt64Array _instances_cull_aabb_bind(const AABB &p_aabb, RID p_scenario = RID()) const;
+ PackedInt64Array _instances_cull_ray_bind(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const;
+ PackedInt64Array _instances_cull_convex_bind(const Array &p_convex, RID p_scenario = RID()) const;
enum InstanceFlags {
INSTANCE_FLAG_USE_BAKED_LIGHT,
@@ -1242,10 +1250,10 @@ public:
virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) = 0;
virtual void instance_geometry_set_transparency(RID p_instance, float p_transparency) = 0;
- virtual void instance_geometry_set_shader_parameter(RID p_instance, const StringName &, const Variant &p_value) = 0;
- virtual Variant instance_geometry_get_shader_parameter(RID p_instance, const StringName &) const = 0;
- virtual Variant instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &) const = 0;
- virtual void instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const = 0;
+ virtual void instance_geometry_set_shader_uniform(RID p_instance, const StringName &, const Variant &p_value) = 0;
+ virtual Variant instance_geometry_get_shader_uniform(RID p_instance, const StringName &) const = 0;
+ virtual Variant instance_geometry_get_shader_uniform_default_value(RID p_instance, const StringName &) const = 0;
+ virtual void instance_geometry_get_shader_uniform_list(RID p_instance, List<PropertyInfo> *p_parameters) const = 0;
/* Bake 3D objects */
@@ -1318,6 +1326,7 @@ public:
virtual void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) = 0;
virtual void canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = false) = 0;
virtual void canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, float p_px_range = 1.0) = 0;
+ virtual void canvas_item_add_lcd_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1)) = 0;
virtual void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, NinePatchAxisMode p_x_axis_mode = NINE_PATCH_STRETCH, NinePatchAxisMode p_y_axis_mode = NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1)) = 0;
virtual void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0) = 0;
virtual void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID()) = 0;
@@ -1569,11 +1578,11 @@ private:
RID _texture_3d_create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const TypedArray<Image> &p_data);
void _texture_3d_update(RID p_texture, const TypedArray<Image> &p_data);
TypedArray<Image> _texture_3d_get(RID p_texture) const;
- TypedArray<Dictionary> _shader_get_param_list(RID p_shader) const;
+ TypedArray<Dictionary> _shader_get_shader_uniform_list(RID p_shader) const;
RID _mesh_create_from_surfaces(const TypedArray<Dictionary> &p_surfaces, int p_blend_shape_count);
void _mesh_add_surface(RID p_mesh, const Dictionary &p_surface);
Dictionary _mesh_get_surface(RID p_mesh, int p_idx);
- Array _instance_geometry_get_shader_parameter_list(RID p_instance) const;
+ TypedArray<Dictionary> _instance_geometry_get_shader_uniform_list(RID p_instance) const;
TypedArray<Image> _bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size);
void _particles_set_trail_bind_poses(RID p_particles, const TypedArray<Transform3D> &p_bind_poses);
};
diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp
index 47598abce7..74ae2bfff0 100644
--- a/servers/text/text_server_extension.cpp
+++ b/servers/text/text_server_extension.cpp
@@ -69,8 +69,8 @@ void TextServerExtension::_bind_methods() {
GDVIRTUAL_BIND(font_set_style_name, "font_rid", "name_style");
GDVIRTUAL_BIND(font_get_style_name, "font_rid");
- GDVIRTUAL_BIND(font_set_antialiased, "font_rid", "antialiased");
- GDVIRTUAL_BIND(font_is_antialiased, "font_rid");
+ GDVIRTUAL_BIND(font_set_antialiasing, "font_rid", "antialiasing");
+ GDVIRTUAL_BIND(font_get_antialiasing, "font_rid");
GDVIRTUAL_BIND(font_set_generate_mipmaps, "font_rid", "generate_mipmaps");
GDVIRTUAL_BIND(font_get_generate_mipmaps, "font_rid");
@@ -297,9 +297,13 @@ void TextServerExtension::_bind_methods() {
GDVIRTUAL_BIND(percent_sign, "language");
GDVIRTUAL_BIND(strip_diacritics, "string");
+ GDVIRTUAL_BIND(is_valid_identifier, "string");
GDVIRTUAL_BIND(string_get_word_breaks, "string", "language");
+ GDVIRTUAL_BIND(is_confusable, "string", "dict");
+ GDVIRTUAL_BIND(spoof_check, "string");
+
GDVIRTUAL_BIND(string_to_upper, "string", "language");
GDVIRTUAL_BIND(string_to_lower, "string", "language");
@@ -474,16 +478,16 @@ String TextServerExtension::font_get_name(const RID &p_font_rid) const {
return String();
}
-void TextServerExtension::font_set_antialiased(const RID &p_font_rid, bool p_antialiased) {
- GDVIRTUAL_CALL(font_set_antialiased, p_font_rid, p_antialiased);
+void TextServerExtension::font_set_antialiasing(RID p_font_rid, TextServer::FontAntialiasing p_antialiasing) {
+ GDVIRTUAL_CALL(font_set_antialiasing, p_font_rid, p_antialiasing);
}
-bool TextServerExtension::font_is_antialiased(const RID &p_font_rid) const {
- bool ret;
- if (GDVIRTUAL_CALL(font_is_antialiased, p_font_rid, ret)) {
+TextServer::FontAntialiasing TextServerExtension::font_get_antialiasing(RID p_font_rid) const {
+ TextServer::FontAntialiasing ret;
+ if (GDVIRTUAL_CALL(font_get_antialiasing, p_font_rid, ret)) {
return ret;
}
- return false;
+ return TextServer::FONT_ANTIALIASING_NONE;
}
void TextServerExtension::font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) {
@@ -630,12 +634,12 @@ double TextServerExtension::font_get_oversampling(const RID &p_font_rid) const {
return 0.0;
}
-Array TextServerExtension::font_get_size_cache_list(const RID &p_font_rid) const {
- Array ret;
+TypedArray<Vector2i> TextServerExtension::font_get_size_cache_list(const RID &p_font_rid) const {
+ TypedArray<Vector2i> ret;
if (GDVIRTUAL_CALL(font_get_size_cache_list, p_font_rid, ret)) {
return ret;
}
- return Array();
+ return TypedArray<Vector2i>();
}
void TextServerExtension::font_clear_size_cache(const RID &p_font_rid) {
@@ -746,12 +750,12 @@ PackedInt32Array TextServerExtension::font_get_texture_offsets(const RID &p_font
return PackedInt32Array();
}
-Array TextServerExtension::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {
- Array ret;
+PackedInt32Array TextServerExtension::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const {
+ PackedInt32Array ret;
if (GDVIRTUAL_CALL(font_get_glyph_list, p_font_rid, p_size, ret)) {
return ret;
}
- return Array();
+ return PackedInt32Array();
}
void TextServerExtension::font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) {
@@ -846,12 +850,12 @@ Dictionary TextServerExtension::font_get_glyph_contours(const RID &p_font_rid, i
return Dictionary();
}
-Array TextServerExtension::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const {
- Array ret;
+TypedArray<Vector2i> TextServerExtension::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const {
+ TypedArray<Vector2i> ret;
if (GDVIRTUAL_CALL(font_get_kerning_list, p_font_rid, p_size, ret)) {
return ret;
}
- return Array();
+ return TypedArray<Vector2i>();
}
void TextServerExtension::font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) {
@@ -1498,6 +1502,14 @@ String TextServerExtension::percent_sign(const String &p_language) const {
return "%";
}
+bool TextServerExtension::is_valid_identifier(const String &p_string) const {
+ bool ret;
+ if (GDVIRTUAL_CALL(is_valid_identifier, p_string, ret)) {
+ return ret;
+ }
+ return TextServer::is_valid_identifier(p_string);
+}
+
String TextServerExtension::strip_diacritics(const String &p_string) const {
String ret;
if (GDVIRTUAL_CALL(strip_diacritics, p_string, ret)) {
@@ -1522,12 +1534,12 @@ String TextServerExtension::string_to_lower(const String &p_string, const String
return p_string;
}
-Array TextServerExtension::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
- Array ret;
+TypedArray<Vector2i> TextServerExtension::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
+ TypedArray<Vector2i> ret;
if (GDVIRTUAL_CALL(parse_structured_text, p_parser_type, p_args, p_text, ret)) {
return ret;
}
- return Array();
+ return TypedArray<Vector2i>();
}
PackedInt32Array TextServerExtension::string_get_word_breaks(const String &p_string, const String &p_language) const {
@@ -1538,6 +1550,22 @@ PackedInt32Array TextServerExtension::string_get_word_breaks(const String &p_str
return PackedInt32Array();
}
+int TextServerExtension::is_confusable(const String &p_string, const PackedStringArray &p_dict) const {
+ int ret;
+ if (GDVIRTUAL_CALL(is_confusable, p_string, p_dict, ret)) {
+ return ret;
+ }
+ return TextServer::is_confusable(p_string, p_dict);
+}
+
+bool TextServerExtension::spoof_check(const String &p_string) const {
+ bool ret;
+ if (GDVIRTUAL_CALL(spoof_check, p_string, ret)) {
+ return ret;
+ }
+ return TextServer::spoof_check(p_string);
+}
+
TextServerExtension::TextServerExtension() {
//NOP
}
diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h
index 571753ea67..6a2c199898 100644
--- a/servers/text/text_server_extension.h
+++ b/servers/text/text_server_extension.h
@@ -35,6 +35,7 @@
#include "core/object/script_language.h"
#include "core/os/thread_safe.h"
#include "core/variant/native_ptr.h"
+#include "core/variant/typed_array.h"
#include "servers/text_server.h"
class TextServerExtension : public TextServer {
@@ -107,10 +108,10 @@ public:
GDVIRTUAL2(font_set_style_name, RID, const String &);
GDVIRTUAL1RC(String, font_get_style_name, RID);
- virtual void font_set_antialiased(const RID &p_font_rid, bool p_antialiased) override;
- virtual bool font_is_antialiased(const RID &p_font_rid) const override;
- GDVIRTUAL2(font_set_antialiased, RID, bool);
- GDVIRTUAL1RC(bool, font_is_antialiased, RID);
+ virtual void font_set_antialiasing(RID p_font_rid, TextServer::FontAntialiasing p_antialiasing) override;
+ virtual TextServer::FontAntialiasing font_get_antialiasing(RID p_font_rid) const override;
+ GDVIRTUAL2(font_set_antialiasing, RID, TextServer::FontAntialiasing);
+ GDVIRTUAL1RC(TextServer::FontAntialiasing, font_get_antialiasing, RID);
virtual void font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) override;
virtual bool font_get_generate_mipmaps(const RID &p_font_rid) const override;
@@ -172,10 +173,10 @@ public:
GDVIRTUAL2(font_set_oversampling, RID, double);
GDVIRTUAL1RC(double, font_get_oversampling, RID);
- virtual Array font_get_size_cache_list(const RID &p_font_rid) const override;
+ virtual TypedArray<Vector2i> font_get_size_cache_list(const RID &p_font_rid) const override;
virtual void font_clear_size_cache(const RID &p_font_rid) override;
virtual void font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) override;
- GDVIRTUAL1RC(Array, font_get_size_cache_list, RID);
+ GDVIRTUAL1RC(TypedArray<Vector2i>, font_get_size_cache_list, RID);
GDVIRTUAL1(font_clear_size_cache, RID);
GDVIRTUAL2(font_remove_size_cache, RID, const Vector2i &);
@@ -221,10 +222,10 @@ public:
GDVIRTUAL4(font_set_texture_offsets, RID, const Vector2i &, int64_t, const PackedInt32Array &);
GDVIRTUAL3RC(PackedInt32Array, font_get_texture_offsets, RID, const Vector2i &, int64_t);
- virtual Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const override;
+ virtual PackedInt32Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const override;
virtual void font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) override;
virtual void font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) override;
- GDVIRTUAL2RC(Array, font_get_glyph_list, RID, const Vector2i &);
+ GDVIRTUAL2RC(PackedInt32Array, font_get_glyph_list, RID, const Vector2i &);
GDVIRTUAL2(font_clear_glyphs, RID, const Vector2i &);
GDVIRTUAL3(font_remove_glyph, RID, const Vector2i &, int64_t);
@@ -262,10 +263,10 @@ public:
virtual Dictionary font_get_glyph_contours(const RID &p_font, int64_t p_size, int64_t p_index) const override;
GDVIRTUAL3RC(Dictionary, font_get_glyph_contours, RID, int64_t, int64_t);
- virtual Array font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const override;
+ virtual TypedArray<Vector2i> font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const override;
virtual void font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) override;
virtual void font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) override;
- GDVIRTUAL2RC(Array, font_get_kerning_list, RID, int64_t);
+ GDVIRTUAL2RC(TypedArray<Vector2i>, font_get_kerning_list, RID, int64_t);
GDVIRTUAL2(font_clear_kerning_map, RID, int64_t);
GDVIRTUAL3(font_remove_kerning, RID, int64_t, const Vector2i &);
@@ -496,13 +497,21 @@ public:
virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const override;
GDVIRTUAL2RC(PackedInt32Array, string_get_word_breaks, const String &, const String &);
+ virtual bool is_valid_identifier(const String &p_string) const override;
+ GDVIRTUAL1RC(bool, is_valid_identifier, const String &);
+
virtual String string_to_upper(const String &p_string, const String &p_language = "") const override;
virtual String string_to_lower(const String &p_string, const String &p_language = "") const override;
GDVIRTUAL2RC(String, string_to_upper, const String &, const String &);
GDVIRTUAL2RC(String, string_to_lower, const String &, const String &);
- Array parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
- GDVIRTUAL3RC(Array, parse_structured_text, StructuredTextParser, const Array &, const String &);
+ TypedArray<Vector2i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
+ GDVIRTUAL3RC(TypedArray<Vector2i>, parse_structured_text, StructuredTextParser, const Array &, const String &);
+
+ virtual int is_confusable(const String &p_string, const PackedStringArray &p_dict) const override;
+ virtual bool spoof_check(const String &p_string) const override;
+ GDVIRTUAL2RC(int, is_confusable, const String &, const PackedStringArray &);
+ GDVIRTUAL1RC(bool, spoof_check, const String &);
TextServerExtension();
~TextServerExtension();
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index 4a6b03d943..393160fe9e 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "servers/text_server.h"
+#include "core/variant/typed_array.h"
#include "servers/rendering_server.h"
TextServerManager *TextServerManager::singleton = nullptr;
@@ -103,8 +104,8 @@ Ref<TextServer> TextServerManager::find_interface(const String &p_name) const {
return interfaces[idx];
}
-Array TextServerManager::get_interfaces() const {
- Array ret;
+TypedArray<Dictionary> TextServerManager::get_interfaces() const {
+ TypedArray<Dictionary> ret;
for (int i = 0; i < interfaces.size(); i++) {
Dictionary iface_info;
@@ -222,8 +223,8 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("font_set_style_name", "font_rid", "name"), &TextServer::font_set_style_name);
ClassDB::bind_method(D_METHOD("font_get_style_name", "font_rid"), &TextServer::font_get_style_name);
- ClassDB::bind_method(D_METHOD("font_set_antialiased", "font_rid", "antialiased"), &TextServer::font_set_antialiased);
- ClassDB::bind_method(D_METHOD("font_is_antialiased", "font_rid"), &TextServer::font_is_antialiased);
+ ClassDB::bind_method(D_METHOD("font_set_antialiasing", "font_rid", "antialiasing"), &TextServer::font_set_antialiasing);
+ ClassDB::bind_method(D_METHOD("font_get_antialiasing", "font_rid"), &TextServer::font_get_antialiasing);
ClassDB::bind_method(D_METHOD("font_set_generate_mipmaps", "font_rid", "generate_mipmaps"), &TextServer::font_set_generate_mipmaps);
ClassDB::bind_method(D_METHOD("font_get_generate_mipmaps", "font_rid"), &TextServer::font_get_generate_mipmaps);
@@ -446,13 +447,28 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("string_get_word_breaks", "string", "language"), &TextServer::string_get_word_breaks, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("is_confusable", "string", "dict"), &TextServer::is_confusable);
+ ClassDB::bind_method(D_METHOD("spoof_check", "string"), &TextServer::spoof_check);
+
ClassDB::bind_method(D_METHOD("strip_diacritics", "string"), &TextServer::strip_diacritics);
+ ClassDB::bind_method(D_METHOD("is_valid_identifier", "string"), &TextServer::is_valid_identifier);
ClassDB::bind_method(D_METHOD("string_to_upper", "string", "language"), &TextServer::string_to_upper, DEFVAL(""));
ClassDB::bind_method(D_METHOD("string_to_lower", "string", "language"), &TextServer::string_to_lower, DEFVAL(""));
ClassDB::bind_method(D_METHOD("parse_structured_text", "parser_type", "args", "text"), &TextServer::parse_structured_text);
+ /* Font AA */
+ BIND_ENUM_CONSTANT(FONT_ANTIALIASING_NONE);
+ BIND_ENUM_CONSTANT(FONT_ANTIALIASING_GRAY);
+ BIND_ENUM_CONSTANT(FONT_ANTIALIASING_LCD);
+
+ BIND_ENUM_CONSTANT(FONT_LCD_SUBPIXEL_LAYOUT_NONE);
+ BIND_ENUM_CONSTANT(FONT_LCD_SUBPIXEL_LAYOUT_HRGB);
+ BIND_ENUM_CONSTANT(FONT_LCD_SUBPIXEL_LAYOUT_HBGR);
+ BIND_ENUM_CONSTANT(FONT_LCD_SUBPIXEL_LAYOUT_VRGB);
+ BIND_ENUM_CONSTANT(FONT_LCD_SUBPIXEL_LAYOUT_VBGR);
+
/* Direction */
BIND_ENUM_CONSTANT(DIRECTION_AUTO);
BIND_ENUM_CONSTANT(DIRECTION_LTR);
@@ -517,6 +533,7 @@ void TextServer::_bind_methods() {
BIND_BITFIELD_FLAG(GRAPHEME_IS_PUNCTUATION);
BIND_BITFIELD_FLAG(GRAPHEME_IS_UNDERSCORE);
BIND_BITFIELD_FLAG(GRAPHEME_IS_CONNECTED);
+ BIND_BITFIELD_FLAG(GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL);
/* Hinting */
BIND_ENUM_CONSTANT(HINTING_NONE);
@@ -545,6 +562,8 @@ void TextServer::_bind_methods() {
BIND_ENUM_CONSTANT(FEATURE_FONT_VARIABLE);
BIND_ENUM_CONSTANT(FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION);
BIND_ENUM_CONSTANT(FEATURE_USE_SUPPORT_DATA);
+ BIND_ENUM_CONSTANT(FEATURE_UNICODE_IDENTIFIERS);
+ BIND_ENUM_CONSTANT(FEATURE_UNICODE_SECURITY);
/* FT Contour Point Types */
BIND_ENUM_CONSTANT(CONTOUR_CURVE_TAG_ON);
@@ -1578,8 +1597,8 @@ String TextServer::strip_diacritics(const String &p_string) const {
return result;
}
-Array TextServer::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
- Array ret;
+TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
+ TypedArray<Vector2i> ret;
switch (p_parser_type) {
case STRUCTURED_TEXT_URI: {
int prev = 0;
@@ -1620,7 +1639,7 @@ Array TextServer::parse_structured_text(StructuredTextParser p_parser_type, cons
ret.push_back(Vector2i(prev, i));
ret.push_back(Vector2i(i, i + 1));
prev = i + 1;
- } else if (!local & (p_text[i] == '.')) { // Add each dot separated "domain" part as context.
+ } else if (!local && (p_text[i] == '.')) { // Add each dot separated "domain" part as context.
if (prev != i) {
ret.push_back(Vector2i(prev, i));
}
@@ -1655,8 +1674,8 @@ Array TextServer::parse_structured_text(StructuredTextParser p_parser_type, cons
return ret;
}
-Array TextServer::_shaped_text_get_glyphs_wrapper(const RID &p_shaped) const {
- Array ret;
+TypedArray<Dictionary> TextServer::_shaped_text_get_glyphs_wrapper(const RID &p_shaped) const {
+ TypedArray<Dictionary> ret;
const Glyph *glyphs = shaped_text_get_glyphs(p_shaped);
int gl_size = shaped_text_get_glyph_count(p_shaped);
@@ -1680,7 +1699,7 @@ Array TextServer::_shaped_text_get_glyphs_wrapper(const RID &p_shaped) const {
return ret;
}
-Array TextServer::_shaped_text_sort_logical_wrapper(const RID &p_shaped) {
+TypedArray<Dictionary> TextServer::_shaped_text_sort_logical_wrapper(const RID &p_shaped) {
Array ret;
const Glyph *glyphs = shaped_text_sort_logical(p_shaped);
@@ -1705,8 +1724,8 @@ Array TextServer::_shaped_text_sort_logical_wrapper(const RID &p_shaped) {
return ret;
}
-Array TextServer::_shaped_text_get_ellipsis_glyphs_wrapper(const RID &p_shaped) const {
- Array ret;
+TypedArray<Dictionary> TextServer::_shaped_text_get_ellipsis_glyphs_wrapper(const RID &p_shaped) const {
+ TypedArray<Dictionary> ret;
const Glyph *glyphs = shaped_text_get_ellipsis_glyphs(p_shaped);
int gl_size = shaped_text_get_ellipsis_glyph_count(p_shaped);
@@ -1730,6 +1749,26 @@ Array TextServer::_shaped_text_get_ellipsis_glyphs_wrapper(const RID &p_shaped)
return ret;
}
+bool TextServer::is_valid_identifier(const String &p_string) const {
+ const char32_t *str = p_string.ptr();
+ int len = p_string.length();
+
+ if (len == 0) {
+ return false; // Empty string.
+ }
+
+ if (!is_unicode_identifier_start(str[0])) {
+ return false;
+ }
+
+ for (int i = 1; i < len; i++) {
+ if (!is_unicode_identifier_continue(str[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
TextServer::TextServer() {
_init_diacritics_map();
}
diff --git a/servers/text_server.h b/servers/text_server.h
index f6ab165bfc..9304771d1b 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -37,6 +37,9 @@
#include "core/variant/native_ptr.h"
#include "core/variant/variant.h"
+template <typename T>
+class TypedArray;
+
struct Glyph;
struct CaretInfo;
@@ -44,6 +47,21 @@ class TextServer : public RefCounted {
GDCLASS(TextServer, RefCounted);
public:
+ enum FontAntialiasing {
+ FONT_ANTIALIASING_NONE,
+ FONT_ANTIALIASING_GRAY,
+ FONT_ANTIALIASING_LCD,
+ };
+
+ enum FontLCDSubpixelLayout {
+ FONT_LCD_SUBPIXEL_LAYOUT_NONE,
+ FONT_LCD_SUBPIXEL_LAYOUT_HRGB,
+ FONT_LCD_SUBPIXEL_LAYOUT_HBGR,
+ FONT_LCD_SUBPIXEL_LAYOUT_VRGB,
+ FONT_LCD_SUBPIXEL_LAYOUT_VBGR,
+ FONT_LCD_SUBPIXEL_LAYOUT_MAX,
+ };
+
enum Direction {
DIRECTION_AUTO,
DIRECTION_LTR,
@@ -116,6 +134,7 @@ public:
GRAPHEME_IS_PUNCTUATION = 1 << 8, // Punctuation, except underscore (can be used as word break, but not line break or justifiction).
GRAPHEME_IS_UNDERSCORE = 1 << 9, // Underscore (can be used as word break).
GRAPHEME_IS_CONNECTED = 1 << 10, // Connected to previous grapheme.
+ GRAPHEME_IS_SAFE_TO_INSERT_TATWEEL = 1 << 11, // It is safe to insert a U+0640 before this grapheme for elongation.
};
enum Hinting {
@@ -148,6 +167,8 @@ public:
FEATURE_FONT_VARIABLE = 1 << 10,
FEATURE_CONTEXT_SENSITIVE_CASE_CONVERSION = 1 << 11,
FEATURE_USE_SUPPORT_DATA = 1 << 12,
+ FEATURE_UNICODE_IDENTIFIERS = 1 << 13,
+ FEATURE_UNICODE_SECURITY = 1 << 14,
};
enum ContourPointTag {
@@ -227,8 +248,8 @@ public:
virtual void font_set_style_name(const RID &p_font_rid, const String &p_name) = 0;
virtual String font_get_style_name(const RID &p_font_rid) const = 0;
- virtual void font_set_antialiased(const RID &p_font_rid, bool p_antialiased) = 0;
- virtual bool font_is_antialiased(const RID &p_font_rid) const = 0;
+ virtual void font_set_antialiasing(RID p_font_rid, FontAntialiasing p_antialiasing) = 0;
+ virtual FontAntialiasing font_get_antialiasing(RID p_font_rid) const = 0;
virtual void font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) = 0;
virtual bool font_get_generate_mipmaps(const RID &p_font_rid) const = 0;
@@ -266,7 +287,7 @@ public:
virtual void font_set_oversampling(const RID &p_font_rid, double p_oversampling) = 0;
virtual double font_get_oversampling(const RID &p_font_rid) const = 0;
- virtual Array font_get_size_cache_list(const RID &p_font_rid) const = 0;
+ virtual TypedArray<Vector2i> font_get_size_cache_list(const RID &p_font_rid) const = 0;
virtual void font_clear_size_cache(const RID &p_font_rid) = 0;
virtual void font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) = 0;
@@ -295,7 +316,7 @@ public:
virtual void font_set_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const PackedInt32Array &p_offset) = 0;
virtual PackedInt32Array font_get_texture_offsets(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const = 0;
- virtual Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const = 0;
+ virtual PackedInt32Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const = 0;
virtual void font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) = 0;
virtual void font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) = 0;
@@ -318,7 +339,7 @@ public:
virtual Dictionary font_get_glyph_contours(const RID &p_font, int64_t p_size, int64_t p_index) const = 0;
- virtual Array font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const = 0;
+ virtual TypedArray<Vector2i> font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const = 0;
virtual void font_clear_kerning_map(const RID &p_font_rid, int64_t p_size) = 0;
virtual void font_remove_kerning(const RID &p_font_rid, int64_t p_size, const Vector2i &p_glyph_pair) = 0;
@@ -408,9 +429,9 @@ public:
virtual bool shaped_text_is_ready(const RID &p_shaped) const = 0;
virtual const Glyph *shaped_text_get_glyphs(const RID &p_shaped) const = 0;
- Array _shaped_text_get_glyphs_wrapper(const RID &p_shaped) const;
+ TypedArray<Dictionary> _shaped_text_get_glyphs_wrapper(const RID &p_shaped) const;
virtual const Glyph *shaped_text_sort_logical(const RID &p_shaped) = 0;
- Array _shaped_text_sort_logical_wrapper(const RID &p_shaped);
+ TypedArray<Dictionary> _shaped_text_sort_logical_wrapper(const RID &p_shaped);
virtual int64_t shaped_text_get_glyph_count(const RID &p_shaped) const = 0;
virtual Vector2i shaped_text_get_range(const RID &p_shaped) const = 0;
@@ -422,7 +443,7 @@ public:
virtual int64_t shaped_text_get_trim_pos(const RID &p_shaped) const = 0;
virtual int64_t shaped_text_get_ellipsis_pos(const RID &p_shaped) const = 0;
virtual const Glyph *shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const = 0;
- Array _shaped_text_get_ellipsis_glyphs_wrapper(const RID &p_shaped) const;
+ TypedArray<Dictionary> _shaped_text_get_ellipsis_glyphs_wrapper(const RID &p_shaped) const;
virtual int64_t shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const = 0;
virtual void shaped_text_overrun_trim_to_width(const RID &p_shaped, double p_width, BitField<TextServer::TextOverrunFlag> p_trim_flags) = 0;
@@ -463,13 +484,17 @@ public:
// String functions.
virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const = 0;
+ virtual int is_confusable(const String &p_string, const PackedStringArray &p_dict) const { return -1; };
+ virtual bool spoof_check(const String &p_string) const { return false; };
+
virtual String strip_diacritics(const String &p_string) const;
+ virtual bool is_valid_identifier(const String &p_string) const;
// Other string operations.
virtual String string_to_upper(const String &p_string, const String &p_language = "") const = 0;
virtual String string_to_lower(const String &p_string, const String &p_language = "") const = 0;
- Array parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
+ TypedArray<Vector2i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
TextServer();
~TextServer();
@@ -531,7 +556,7 @@ public:
int get_interface_count() const;
Ref<TextServer> get_interface(int p_index) const;
Ref<TextServer> find_interface(const String &p_name) const;
- Array get_interfaces() const;
+ TypedArray<Dictionary> get_interfaces() const;
_FORCE_INLINE_ Ref<TextServer> get_primary_interface() const {
return primary_interface;
@@ -562,6 +587,8 @@ VARIANT_ENUM_CAST(TextServer::ContourPointTag);
VARIANT_ENUM_CAST(TextServer::SpacingType);
VARIANT_BITFIELD_CAST(TextServer::FontStyle);
VARIANT_ENUM_CAST(TextServer::StructuredTextParser);
+VARIANT_ENUM_CAST(TextServer::FontAntialiasing);
+VARIANT_ENUM_CAST(TextServer::FontLCDSubpixelLayout);
GDVIRTUAL_NATIVE_PTR(Glyph);
GDVIRTUAL_NATIVE_PTR(CaretInfo);
diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp
index 990281d96d..e26212ada1 100644
--- a/servers/xr_server.cpp
+++ b/servers/xr_server.cpp
@@ -226,7 +226,7 @@ Ref<XRInterface> XRServer::find_interface(const String &p_name) const {
return interfaces[idx];
};
-Array XRServer::get_interfaces() const {
+TypedArray<Dictionary> XRServer::get_interfaces() const {
Array ret;
for (int i = 0; i < interfaces.size(); i++) {
diff --git a/servers/xr_server.h b/servers/xr_server.h
index 74128bfb54..57e42deccb 100644
--- a/servers/xr_server.h
+++ b/servers/xr_server.h
@@ -157,7 +157,7 @@ public:
int get_interface_count() const;
Ref<XRInterface> get_interface(int p_index) const;
Ref<XRInterface> find_interface(const String &p_name) const;
- Array get_interfaces() const;
+ TypedArray<Dictionary> get_interfaces() const;
/*
note, more then one interface can technically be active, especially on mobile, but only one interface is used for
diff --git a/tests/core/input/test_input_event_key.h b/tests/core/input/test_input_event_key.h
new file mode 100644
index 0000000000..5d4ca55a35
--- /dev/null
+++ b/tests/core/input/test_input_event_key.h
@@ -0,0 +1,294 @@
+/*************************************************************************/
+/* test_input_event_key.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_INPUT_EVENT_KEY_H
+#define TEST_INPUT_EVENT_KEY_H
+
+#include "core/input/input_event.h"
+#include "core/os/keyboard.h"
+
+#include "tests/test_macros.h"
+
+namespace TestInputEventKey {
+
+TEST_CASE("[InputEventKey] Key correctly registers being pressed") {
+ InputEventKey key;
+ key.set_pressed(true);
+ CHECK(key.is_pressed() == true);
+
+ key.set_pressed(false);
+ CHECK(key.is_pressed() == false);
+}
+
+TEST_CASE("[InputEventKey] Key correctly stores and retrieves keycode") {
+ InputEventKey key;
+
+ key.set_keycode(Key::ENTER);
+ CHECK(key.get_keycode() == Key::ENTER);
+ CHECK(key.get_keycode() != Key::PAUSE);
+
+ key.set_physical_keycode(Key::BACKSPACE);
+ CHECK(key.get_physical_keycode() == Key::BACKSPACE);
+ CHECK(key.get_physical_keycode() != Key::PAUSE);
+}
+
+TEST_CASE("[InputEventKey] Key correctly stores and retrieves keycode with modifiers") {
+ InputEventKey key;
+
+ key.set_keycode(Key::ENTER);
+ key.set_ctrl_pressed(true);
+
+ CHECK(key.get_keycode_with_modifiers() == (Key::ENTER | KeyModifierMask::CTRL));
+ CHECK(key.get_keycode_with_modifiers() != (Key::ENTER | KeyModifierMask::SHIFT));
+ CHECK(key.get_keycode_with_modifiers() != Key::ENTER);
+
+ key.set_physical_keycode(Key::SPACE);
+ key.set_ctrl_pressed(true);
+
+ CHECK(key.get_physical_keycode_with_modifiers() == (Key::SPACE | KeyModifierMask::CTRL));
+ CHECK(key.get_physical_keycode_with_modifiers() != (Key::SPACE | KeyModifierMask::SHIFT));
+ CHECK(key.get_physical_keycode_with_modifiers() != Key::SPACE);
+}
+
+TEST_CASE("[InputEventKey] Key correctly stores and retrieves unicode") {
+ InputEventKey key;
+
+ key.set_unicode('x');
+ CHECK(key.get_unicode() == 'x');
+ CHECK(key.get_unicode() != 'y');
+}
+
+TEST_CASE("[InputEventKey] Key correctly stores and checks echo") {
+ InputEventKey key;
+
+ key.set_echo(true);
+ CHECK(key.is_echo() == true);
+
+ key.set_echo(false);
+ CHECK(key.is_echo() == false);
+}
+
+TEST_CASE("[InputEventKey] Key correctly converts itself to text") {
+ InputEventKey none_key;
+
+ // These next three tests test the functionality of getting a key that is set to None
+ // as text. These cases are a bit weird, since None has no textual representation
+ // (find_keycode_name(Key::NONE) results in a nullptr). Thus, these tests look weird
+ // with only (Physical) or a lonely modifier with (Physical) but (as far as I
+ // understand the code, that is intended behaviour.
+
+ // Key is None without a physical key.
+ none_key.set_keycode(Key::NONE);
+ CHECK(none_key.as_text() == " (Physical)");
+
+ // Key is none and has modifiers.
+ none_key.set_ctrl_pressed(true);
+ CHECK(none_key.as_text() == "Ctrl+ (Physical)");
+
+ // Key is None WITH a physical key AND modifiers.
+ none_key.set_physical_keycode(Key::ENTER);
+ CHECK(none_key.as_text() == "Ctrl+Enter (Physical)");
+
+ InputEventKey none_key2;
+
+ // Key is None without modifers with a physical key.
+ none_key2.set_keycode(Key::NONE);
+ none_key2.set_physical_keycode(Key::ENTER);
+
+ CHECK(none_key2.as_text() == "Enter (Physical)");
+
+ InputEventKey key;
+
+ // Key has keycode.
+ key.set_keycode(Key::SPACE);
+ CHECK(key.as_text() != "");
+ CHECK(key.as_text() == "Space");
+
+ // Key has keycode and modifiers.
+ key.set_ctrl_pressed(true);
+ CHECK(key.as_text() != "Space");
+ CHECK(key.as_text() == "Ctrl+Space");
+
+ // Since the keycode is set to Key::NONE upon initialization of the
+ // InputEventKey and you can only update it with another Key, the keycode
+ // cannot be empty, so the kc.is_empty() case cannot be tested.
+}
+
+TEST_CASE("[InputEventKey] Key correctly converts its state to a string representation") {
+ InputEventKey none_key;
+
+ // Set physical to true.
+ CHECK(none_key.to_string() == "InputEventKey: keycode=0 (), mods=none, physical=true, pressed=false, echo=false");
+ // Set physical key to Escape.
+ none_key.set_physical_keycode(Key::ESCAPE);
+ CHECK(none_key.to_string() == "InputEventKey: keycode=16777217 (Escape), mods=none, physical=true, pressed=false, echo=false");
+
+ InputEventKey key;
+
+ // Set physical to None, set keycode to Space.
+ key.set_keycode(Key::SPACE);
+ CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=none, physical=false, pressed=false, echo=false");
+
+ // Set pressed to true.
+ key.set_pressed(true);
+ CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=none, physical=false, pressed=true, echo=false");
+
+ // set echo to true.
+ key.set_echo(true);
+ CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=none, physical=false, pressed=true, echo=true");
+
+ // Press Ctrl and Alt.
+ key.set_ctrl_pressed(true);
+ key.set_alt_pressed(true);
+ CHECK(key.to_string() == "InputEventKey: keycode=32 (Space), mods=Ctrl+Alt, physical=false, pressed=true, echo=true");
+}
+
+TEST_CASE("[InputEventKey] Key is correctly converted to reference") {
+ InputEventKey base_key;
+ Ref<InputEventKey> key_ref = base_key.create_reference(Key::ENTER);
+
+ CHECK(key_ref->get_keycode() == Key::ENTER);
+}
+
+TEST_CASE("[InputEventKey] Keys are correctly matched based on action") {
+ bool pressed = false;
+ float strength, raw_strength = 0.0;
+
+ InputEventKey key;
+
+ // Nullptr.
+ CHECK_MESSAGE(key.action_match(nullptr, false, 0.0f, &pressed, &strength, &raw_strength) == false, "nullptr as key reference should result in false");
+
+ // Match on keycode.
+ key.set_keycode(Key::SPACE);
+ Ref<InputEventKey> match = key.create_reference(Key::SPACE);
+ Ref<InputEventKey> no_match = key.create_reference(Key::ENTER);
+
+ CHECK(key.action_match(match, false, 0.0f, &pressed, &strength, &raw_strength) == true);
+ CHECK(key.action_match(no_match, false, 0.0f, &pressed, &strength, &raw_strength) == false);
+
+ // Check that values are correctly transferred to the pointers.
+ CHECK(pressed == false);
+ CHECK(strength < 0.5);
+ CHECK(raw_strength < 0.5);
+
+ match->set_pressed(true);
+ key.action_match(match, false, 0.0f, &pressed, &strength, &raw_strength);
+
+ CHECK(pressed == true);
+ CHECK(strength > 0.5);
+ CHECK(raw_strength > 0.5);
+
+ // Tests when keycode is None: Then you rely on physical keycode.
+ InputEventKey none_key;
+ none_key.set_physical_keycode(Key::SPACE);
+
+ Ref<InputEventKey> match_none = none_key.create_reference(Key::NONE);
+ match_none->set_physical_keycode(Key::SPACE);
+
+ Ref<InputEventKey> no_match_none = none_key.create_reference(Key::NONE);
+ no_match_none->set_physical_keycode(Key::ENTER);
+
+ CHECK(none_key.action_match(match_none, false, 0.0f, &pressed, &strength, &raw_strength) == true);
+ CHECK(none_key.action_match(no_match_none, false, 0.0f, &pressed, &strength, &raw_strength) == false);
+
+ // Test exact match.
+ InputEventKey key2, ref_key;
+ key2.set_keycode(Key::SPACE);
+
+ Ref<InputEventKey> match2 = ref_key.create_reference(Key::SPACE);
+
+ // Now both press Ctrl and Shift.
+ key2.set_ctrl_pressed(true);
+ key2.set_shift_pressed(true);
+
+ match2->set_ctrl_pressed(true);
+ match2->set_shift_pressed(true);
+
+ // Now they should match.
+ bool exact_match = true;
+ CHECK(key2.action_match(match2, exact_match, 0.0f, &pressed, &strength, &raw_strength) == true);
+
+ // Modify matching key such that it does no longer match in terms of modifiers: Shift
+ // is no longer pressed.
+ match2->set_shift_pressed(false);
+ CHECK(match2->is_shift_pressed() == false);
+ CHECK(key2.action_match(match2, exact_match, 0.0f, &pressed, &strength, &raw_strength) == false);
+}
+
+TEST_CASE("[IsMatch] Keys are correctly matched") {
+ // Key with NONE as keycode.
+ InputEventKey key;
+ key.set_keycode(Key::NONE);
+ key.set_physical_keycode(Key::SPACE);
+
+ // Nullptr.
+ CHECK(key.is_match(nullptr, false) == false);
+
+ Ref<InputEventKey> none_ref = key.create_reference(Key::NONE);
+
+ none_ref->set_physical_keycode(Key::SPACE);
+ CHECK(key.is_match(none_ref, false) == true);
+
+ none_ref->set_physical_keycode(Key::ENTER);
+ CHECK(key.is_match(none_ref, false) == false);
+
+ none_ref->set_physical_keycode(Key::SPACE);
+
+ key.set_ctrl_pressed(true);
+ none_ref->set_ctrl_pressed(false);
+ CHECK(key.is_match(none_ref, true) == false);
+
+ none_ref->set_ctrl_pressed(true);
+ CHECK(key.is_match(none_ref, true) == true);
+
+ // Ref with actual keycode.
+ InputEventKey key2;
+ key2.set_keycode(Key::SPACE);
+
+ Ref<InputEventKey> match = key2.create_reference(Key::SPACE);
+ Ref<InputEventKey> no_match = key2.create_reference(Key::ENTER);
+
+ CHECK(key2.is_match(match, false) == true);
+ CHECK(key2.is_match(no_match, false) == false);
+
+ // Now the keycode is the same, but the modifiers differ.
+ no_match->set_keycode(Key::SPACE);
+
+ key2.set_ctrl_pressed(true);
+ match->set_ctrl_pressed(true);
+ no_match->set_shift_pressed(true);
+
+ CHECK(key2.is_match(match, true) == true);
+ CHECK(key2.is_match(no_match, true) == false);
+}
+} // namespace TestInputEventKey
+
+#endif // TEST_INPUT_EVENT_KEY_H
diff --git a/tests/core/input/test_shortcut.h b/tests/core/input/test_shortcut.h
new file mode 100644
index 0000000000..93edc685ad
--- /dev/null
+++ b/tests/core/input/test_shortcut.h
@@ -0,0 +1,235 @@
+/*************************************************************************/
+/* test_shortcut.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_SHORTCUT_H
+#define TEST_SHORTCUT_H
+
+#include "core/input/input_event.h"
+#include "core/input/shortcut.h"
+#include "core/io/config_file.h"
+#include "core/object/ref_counted.h"
+#include "core/os/keyboard.h"
+#include "core/os/os.h"
+
+#include "tests/test_macros.h"
+
+namespace TestShortcut {
+
+TEST_CASE("[Shortcut] Empty shortcut should have no valid events and text equal to None") {
+ Shortcut s;
+
+ CHECK(s.get_as_text() == "None");
+ CHECK(s.has_valid_event() == false);
+}
+
+TEST_CASE("[Shortcut] Setting and getting an event should result in the same event as the input") {
+ Ref<InputEventKey> k1;
+ Ref<InputEventKey> k2;
+ k1.instantiate();
+ k2.instantiate();
+
+ k1->set_keycode(Key::ENTER);
+ k2->set_keycode(Key::BACKSPACE);
+
+ // Cast to InputEvent so the internal code recognizes the objects.
+ Ref<InputEvent> e1 = k1;
+ Ref<InputEvent> e2 = k2;
+
+ Array input_array;
+ input_array.append(e1);
+ input_array.append(e2);
+
+ Shortcut s;
+ s.set_events(input_array);
+
+ // Get result, read it out, check whether it equals the input.
+ Array result_array = s.get_events();
+ Ref<InputEventKey> result1 = result_array.front();
+ Ref<InputEventKey> result2 = result_array.back();
+
+ CHECK(result1->get_keycode() == k1->get_keycode());
+ CHECK(result2->get_keycode() == k2->get_keycode());
+}
+
+TEST_CASE("[Shortcut] 'set_events_list' should result in the same events as the input") {
+ Ref<InputEventKey> k1;
+ Ref<InputEventKey> k2;
+ k1.instantiate();
+ k2.instantiate();
+
+ k1->set_keycode(Key::ENTER);
+ k2->set_keycode(Key::BACKSPACE);
+
+ // Cast to InputEvent so the set_events_list() method recognizes the objects.
+ Ref<InputEvent> e1 = k1;
+ Ref<InputEvent> e2 = k2;
+
+ List<Ref<InputEvent>> list;
+ list.push_back(e1);
+ list.push_back(e2);
+
+ Shortcut s;
+ s.set_events_list(&list);
+
+ // Get result, read it out, check whether it equals the input.
+ Array result_array = s.get_events();
+ Ref<InputEventKey> result1 = result_array.front();
+ Ref<InputEventKey> result2 = result_array.back();
+
+ CHECK(result1->get_keycode() == k1->get_keycode());
+ CHECK(result2->get_keycode() == k2->get_keycode());
+}
+
+TEST_CASE("[Shortcut] 'matches_event' should correctly match the same event") {
+ Ref<InputEventKey> original; // The one we compare with.
+ Ref<InputEventKey> similar_but_not_equal; // Same keycode, different event.
+ Ref<InputEventKey> different; // Different event, different keycode.
+ Ref<InputEventKey> copy; // Copy of original event.
+
+ original.instantiate();
+ similar_but_not_equal.instantiate();
+ different.instantiate();
+ copy.instantiate();
+
+ original->set_keycode(Key::ENTER);
+ similar_but_not_equal->set_keycode(Key::ENTER);
+ similar_but_not_equal->set_keycode(Key::ESCAPE);
+ copy = original;
+
+ // Only the copy is really the same, so only that one should match.
+ // The rest should not match.
+
+ Ref<InputEvent> e_original = original;
+
+ Ref<InputEvent> e_similar_but_not_equal = similar_but_not_equal;
+ Ref<InputEvent> e_different = different;
+ Ref<InputEvent> e_copy = copy;
+
+ Array a;
+ a.append(e_original);
+ Shortcut s;
+ s.set_events(a);
+
+ CHECK(s.matches_event(e_similar_but_not_equal) == false);
+ CHECK(s.matches_event(e_different) == false);
+
+ CHECK(s.matches_event(e_copy) == true);
+}
+
+TEST_CASE("[Shortcut] 'get_as_text' text representation should be correct") {
+ Ref<InputEventKey> same;
+ // k2 will not go into the shortcut but only be used to compare.
+ Ref<InputEventKey> different;
+
+ same.instantiate();
+ different.instantiate();
+
+ same->set_keycode(Key::ENTER);
+ different->set_keycode(Key::ESCAPE);
+
+ Ref<InputEvent> key_event1 = same;
+
+ Array a;
+ a.append(key_event1);
+ Shortcut s;
+ s.set_events(a);
+
+ CHECK(s.get_as_text() == same->as_text());
+ CHECK(s.get_as_text() != different->as_text());
+}
+
+TEST_CASE("[Shortcut] Event validity should be correctly checked.") {
+ Ref<InputEventKey> valid;
+ // k2 will not go into the shortcut but only be used to compare.
+ Ref<InputEventKey> invalid = nullptr;
+
+ valid.instantiate();
+ valid->set_keycode(Key::ENTER);
+
+ Ref<InputEvent> valid_event = valid;
+ Ref<InputEvent> invalid_event = invalid;
+
+ Array a;
+ a.append(invalid_event);
+ a.append(valid_event);
+
+ Shortcut s;
+ s.set_events(a);
+
+ CHECK(s.has_valid_event() == true);
+
+ Array b;
+ b.append(invalid_event);
+
+ Shortcut shortcut_with_invalid_event;
+ shortcut_with_invalid_event.set_events(b);
+
+ CHECK(shortcut_with_invalid_event.has_valid_event() == false);
+}
+
+TEST_CASE("[Shortcut] Equal arrays should be recognized as such.") {
+ Ref<InputEventKey> k1;
+ // k2 will not go into the shortcut but only be used to compare.
+ Ref<InputEventKey> k2;
+
+ k1.instantiate();
+ k2.instantiate();
+
+ k1->set_keycode(Key::ENTER);
+ k2->set_keycode(Key::ESCAPE);
+
+ Ref<InputEvent> key_event1 = k1;
+ Ref<InputEvent> key_event2 = k2;
+
+ Array same;
+ same.append(key_event1);
+
+ Array same_as_same;
+ same_as_same.append(key_event1);
+
+ Array different1;
+ different1.append(key_event2);
+
+ Array different2;
+ different2.append(key_event1);
+ different2.append(key_event2);
+
+ Array different3;
+
+ Shortcut s;
+
+ CHECK(s.is_event_array_equal(same, same_as_same) == true);
+ CHECK(s.is_event_array_equal(same, different1) == false);
+ CHECK(s.is_event_array_equal(same, different2) == false);
+ CHECK(s.is_event_array_equal(same, different3) == false);
+}
+} // namespace TestShortcut
+
+#endif // TEST_SHORTCUT_H
diff --git a/tests/core/io/test_config_file.h b/tests/core/io/test_config_file.h
index 355aca479e..666719febb 100644
--- a/tests/core/io/test_config_file.h
+++ b/tests/core/io/test_config_file.h
@@ -127,7 +127,7 @@ TEST_CASE("[ConfigFile] Saving file") {
config_file.set_value("quoted", "a=b", 7);
#ifdef WINDOWS_ENABLED
- const String config_path = OS::get_singleton()->get_environment("TEMP").plus_file("config.ini");
+ const String config_path = OS::get_singleton()->get_environment("TEMP").path_join("config.ini");
#else
const String config_path = "/tmp/config.ini";
#endif
diff --git a/tests/core/io/test_file_access.h b/tests/core/io/test_file_access.h
index f0e1cceacf..aab62955cb 100644
--- a/tests/core/io/test_file_access.h
+++ b/tests/core/io/test_file_access.h
@@ -78,6 +78,29 @@ TEST_CASE("[FileAccess] CSV read") {
CHECK(row5[1] == "tab separated");
CHECK(row5[2] == "lines, good?");
}
+
+TEST_CASE("[FileAccess] Get as UTF-8 String") {
+ Ref<FileAccess> f_lf = FileAccess::open(TestUtils::get_data_path("line_endings_lf.test.txt"), FileAccess::READ);
+ String s_lf = f_lf->get_as_utf8_string();
+ f_lf->seek(0);
+ String s_lf_nocr = f_lf->get_as_utf8_string(true);
+ CHECK(s_lf == "Hello darkness\nMy old friend\nI've come to talk\nWith you again\n");
+ CHECK(s_lf_nocr == "Hello darkness\nMy old friend\nI've come to talk\nWith you again\n");
+
+ Ref<FileAccess> f_crlf = FileAccess::open(TestUtils::get_data_path("line_endings_crlf.test.txt"), FileAccess::READ);
+ String s_crlf = f_crlf->get_as_utf8_string();
+ f_crlf->seek(0);
+ String s_crlf_nocr = f_crlf->get_as_utf8_string(true);
+ CHECK(s_crlf == "Hello darkness\r\nMy old friend\r\nI've come to talk\r\nWith you again\r\n");
+ CHECK(s_crlf_nocr == "Hello darkness\nMy old friend\nI've come to talk\nWith you again\n");
+
+ Ref<FileAccess> f_cr = FileAccess::open(TestUtils::get_data_path("line_endings_cr.test.txt"), FileAccess::READ);
+ String s_cr = f_cr->get_as_utf8_string();
+ f_cr->seek(0);
+ String s_cr_nocr = f_cr->get_as_utf8_string(true);
+ CHECK(s_cr == "Hello darkness\rMy old friend\rI've come to talk\rWith you again\r");
+ CHECK(s_cr_nocr == "Hello darknessMy old friendI've come to talkWith you again");
+}
} // namespace TestFileAccess
#endif // TEST_FILE_ACCESS_H
diff --git a/tests/core/io/test_image.h b/tests/core/io/test_image.h
index 36e6b83bfd..38b616cda0 100644
--- a/tests/core/io/test_image.h
+++ b/tests/core/io/test_image.h
@@ -78,8 +78,8 @@ TEST_CASE("[Image] Instantiation") {
TEST_CASE("[Image] Saving and loading") {
Ref<Image> image = memnew(Image(4, 4, false, Image::FORMAT_RGBA8));
- const String save_path_png = OS::get_singleton()->get_cache_path().plus_file("image.png");
- const String save_path_exr = OS::get_singleton()->get_cache_path().plus_file("image.exr");
+ const String save_path_png = OS::get_singleton()->get_cache_path().path_join("image.png");
+ const String save_path_exr = OS::get_singleton()->get_cache_path().path_join("image.exr");
// Save PNG
Error err;
diff --git a/tests/core/io/test_marshalls.h b/tests/core/io/test_marshalls.h
index 546a2e9358..7490df2b2c 100644
--- a/tests/core/io/test_marshalls.h
+++ b/tests/core/io/test_marshalls.h
@@ -254,11 +254,13 @@ TEST_CASE("[Marshalls] Invalid data Variant decoding") {
uint8_t some_buffer[1] = { 0x00 };
uint8_t out_of_range_type_buffer[4] = { 0xff }; // Greater than Variant::VARIANT_MAX
+ ERR_PRINT_OFF;
CHECK(decode_variant(variant, some_buffer, /* less than 4 */ 1, &r_len) == ERR_INVALID_DATA);
CHECK(r_len == 0);
CHECK(decode_variant(variant, out_of_range_type_buffer, 4, &r_len) == ERR_INVALID_DATA);
CHECK(r_len == 0);
+ ERR_PRINT_ON;
}
TEST_CASE("[Marshalls] NIL Variant decoding") {
diff --git a/tests/core/io/test_pck_packer.h b/tests/core/io/test_pck_packer.h
index d21fbdaf50..8d0e5c402a 100644
--- a/tests/core/io/test_pck_packer.h
+++ b/tests/core/io/test_pck_packer.h
@@ -42,7 +42,7 @@ namespace TestPCKPacker {
TEST_CASE("[PCKPacker] Pack an empty PCK file") {
PCKPacker pck_packer;
- const String output_pck_path = OS::get_singleton()->get_cache_path().plus_file("output_empty.pck");
+ const String output_pck_path = OS::get_singleton()->get_cache_path().path_join("output_empty.pck");
CHECK_MESSAGE(
pck_packer.pck_start(output_pck_path) == OK,
"Starting a PCK file should return an OK error code.");
@@ -66,7 +66,7 @@ TEST_CASE("[PCKPacker] Pack an empty PCK file") {
TEST_CASE("[PCKPacker] Pack empty with zero alignment invalid") {
PCKPacker pck_packer;
- const String output_pck_path = OS::get_singleton()->get_cache_path().plus_file("output_empty.pck");
+ const String output_pck_path = OS::get_singleton()->get_cache_path().path_join("output_empty.pck");
ERR_PRINT_OFF;
CHECK_MESSAGE(pck_packer.pck_start(output_pck_path, 0) != OK, "PCK with zero alignment should fail.");
ERR_PRINT_ON;
@@ -74,7 +74,7 @@ TEST_CASE("[PCKPacker] Pack empty with zero alignment invalid") {
TEST_CASE("[PCKPacker] Pack empty with invalid key") {
PCKPacker pck_packer;
- const String output_pck_path = OS::get_singleton()->get_cache_path().plus_file("output_empty.pck");
+ const String output_pck_path = OS::get_singleton()->get_cache_path().path_join("output_empty.pck");
ERR_PRINT_OFF;
CHECK_MESSAGE(pck_packer.pck_start(output_pck_path, 32, "") != OK, "PCK with invalid key should fail.");
ERR_PRINT_ON;
@@ -82,7 +82,7 @@ TEST_CASE("[PCKPacker] Pack empty with invalid key") {
TEST_CASE("[PCKPacker] Pack a PCK file with some files and directories") {
PCKPacker pck_packer;
- const String output_pck_path = OS::get_singleton()->get_cache_path().plus_file("output_with_files.pck");
+ const String output_pck_path = OS::get_singleton()->get_cache_path().path_join("output_with_files.pck");
CHECK_MESSAGE(
pck_packer.pck_start(output_pck_path) == OK,
"Starting a PCK file should return an OK error code.");
@@ -90,16 +90,16 @@ TEST_CASE("[PCKPacker] Pack a PCK file with some files and directories") {
const String base_dir = OS::get_singleton()->get_executable_path().get_base_dir();
CHECK_MESSAGE(
- pck_packer.add_file("version.py", base_dir.plus_file("../version.py"), "version.py") == OK,
+ pck_packer.add_file("version.py", base_dir.path_join("../version.py"), "version.py") == OK,
"Adding a file to the PCK should return an OK error code.");
CHECK_MESSAGE(
- pck_packer.add_file("some/directories with spaces/to/create/icon.png", base_dir.plus_file("../icon.png")) == OK,
+ pck_packer.add_file("some/directories with spaces/to/create/icon.png", base_dir.path_join("../icon.png")) == OK,
"Adding a file to a new subdirectory in the PCK should return an OK error code.");
CHECK_MESSAGE(
- pck_packer.add_file("some/directories with spaces/to/create/icon.svg", base_dir.plus_file("../icon.svg")) == OK,
+ pck_packer.add_file("some/directories with spaces/to/create/icon.svg", base_dir.path_join("../icon.svg")) == OK,
"Adding a file to an existing subdirectory in the PCK should return an OK error code.");
CHECK_MESSAGE(
- pck_packer.add_file("some/directories with spaces/to/create/icon.png", base_dir.plus_file("../logo.png")) == OK,
+ pck_packer.add_file("some/directories with spaces/to/create/icon.png", base_dir.path_join("../logo.png")) == OK,
"Overriding a non-flushed file to an existing subdirectory in the PCK should return an OK error code.");
CHECK_MESSAGE(
pck_packer.flush() == OK,
diff --git a/tests/core/io/test_resource.h b/tests/core/io/test_resource.h
index c880ca7d2a..2457e06ade 100644
--- a/tests/core/io/test_resource.h
+++ b/tests/core/io/test_resource.h
@@ -74,8 +74,8 @@ TEST_CASE("[Resource] Saving and loading") {
Ref<Resource> child_resource = memnew(Resource);
child_resource->set_name("I'm a child resource");
resource->set_meta("other_resource", child_resource);
- const String save_path_binary = OS::get_singleton()->get_cache_path().plus_file("resource.res");
- const String save_path_text = OS::get_singleton()->get_cache_path().plus_file("resource.tres");
+ const String save_path_binary = OS::get_singleton()->get_cache_path().path_join("resource.res");
+ const String save_path_text = OS::get_singleton()->get_cache_path().path_join("resource.tres");
ResourceSaver::save(resource, save_path_binary);
ResourceSaver::save(resource, save_path_text);
diff --git a/tests/core/math/test_aabb.h b/tests/core/math/test_aabb.h
index 526972a82f..447420fc12 100644
--- a/tests/core/math/test_aabb.h
+++ b/tests/core/math/test_aabb.h
@@ -299,34 +299,28 @@ TEST_CASE("[AABB] Get longest/shortest axis") {
"get_shortest_axis_size() should return the expected value.");
}
-#ifndef _MSC_VER
-#warning Support tests need to be re-done
-#endif
-
-/* Support function was actually broken. As it was fixed, the tests now fail. Tests need to be re-done.
-
TEST_CASE("[AABB] Get support") {
const AABB aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 5, 6));
CHECK_MESSAGE(
- aabb.get_support(Vector3(1, 0, 0)).is_equal_approx(Vector3(-1.5, 7, 3.5)),
+ aabb.get_support(Vector3(1, 0, 0)).is_equal_approx(Vector3(2.5, 2, -2.5)),
"get_support() should return the expected value.");
CHECK_MESSAGE(
- aabb.get_support(Vector3(0.5, 1, 0)).is_equal_approx(Vector3(-1.5, 2, 3.5)),
+ aabb.get_support(Vector3(0.5, 1, 0)).is_equal_approx(Vector3(2.5, 7, -2.5)),
"get_support() should return the expected value.");
CHECK_MESSAGE(
- aabb.get_support(Vector3(0.5, 1, -400)).is_equal_approx(Vector3(-1.5, 2, 3.5)),
+ aabb.get_support(Vector3(0.5, 1, -400)).is_equal_approx(Vector3(2.5, 7, -2.5)),
"get_support() should return the expected value.");
CHECK_MESSAGE(
- aabb.get_support(Vector3(0, -1, 0)).is_equal_approx(Vector3(2.5, 7, 3.5)),
+ aabb.get_support(Vector3(0, -1, 0)).is_equal_approx(Vector3(-1.5, 2, -2.5)),
"get_support() should return the expected value.");
CHECK_MESSAGE(
- aabb.get_support(Vector3(0, -0.1, 0)).is_equal_approx(Vector3(2.5, 7, 3.5)),
+ aabb.get_support(Vector3(0, -0.1, 0)).is_equal_approx(Vector3(-1.5, 2, -2.5)),
"get_support() should return the expected value.");
CHECK_MESSAGE(
- aabb.get_support(Vector3()).is_equal_approx(Vector3(2.5, 7, 3.5)),
+ aabb.get_support(Vector3()).is_equal_approx(Vector3(-1.5, 2, -2.5)),
"get_support() should return the expected value with a null vector.");
}
-*/
+
TEST_CASE("[AABB] Grow") {
const AABB aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 5, 6));
CHECK_MESSAGE(
diff --git a/tests/core/math/test_quaternion.h b/tests/core/math/test_quaternion.h
new file mode 100644
index 0000000000..1b80ffba0b
--- /dev/null
+++ b/tests/core/math/test_quaternion.h
@@ -0,0 +1,389 @@
+/*************************************************************************/
+/* test_quaternion.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_QUATERNION_H
+#define TEST_QUATERNION_H
+
+#include "core/math/math_defs.h"
+#include "core/math/math_funcs.h"
+#include "core/math/quaternion.h"
+#include "core/math/vector3.h"
+
+#include "tests/test_macros.h"
+
+namespace TestQuaternion {
+
+Quaternion quat_euler_yxz_deg(Vector3 angle) {
+ double yaw = Math::deg_to_rad(angle[1]);
+ double pitch = Math::deg_to_rad(angle[0]);
+ double roll = Math::deg_to_rad(angle[2]);
+
+ // Generate YXZ (Z-then-X-then-Y) Quaternion using single-axis Euler
+ // constructor and quaternion product, both tested separately.
+ Quaternion q_y(Vector3(0.0, yaw, 0.0));
+ Quaternion q_p(Vector3(pitch, 0.0, 0.0));
+ Quaternion q_r(Vector3(0.0, 0.0, roll));
+ // Roll-Z is followed by Pitch-X, then Yaw-Y.
+ Quaternion q_yxz = q_y * q_p * q_r;
+
+ return q_yxz;
+}
+
+TEST_CASE("[Quaternion] Default Construct") {
+ Quaternion q;
+
+ CHECK(q[0] == 0.0);
+ CHECK(q[1] == 0.0);
+ CHECK(q[2] == 0.0);
+ CHECK(q[3] == 1.0);
+}
+
+TEST_CASE("[Quaternion] Construct x,y,z,w") {
+ // Values are taken from actual use in another project & are valid (except roundoff error).
+ Quaternion q(0.2391, 0.099, 0.3696, 0.8924);
+
+ CHECK(q[0] == doctest::Approx(0.2391));
+ CHECK(q[1] == doctest::Approx(0.099));
+ CHECK(q[2] == doctest::Approx(0.3696));
+ CHECK(q[3] == doctest::Approx(0.8924));
+}
+
+TEST_CASE("[Quaternion] Construct AxisAngle 1") {
+ // Easy to visualize: 120 deg about X-axis.
+ Quaternion q(Vector3(1.0, 0.0, 0.0), Math::deg_to_rad(120.0));
+
+ // 0.866 isn't close enough; doctest::Approx doesn't cut much slack!
+ CHECK(q[0] == doctest::Approx(0.866025)); // Sine of half the angle.
+ CHECK(q[1] == doctest::Approx(0.0));
+ CHECK(q[2] == doctest::Approx(0.0));
+ CHECK(q[3] == doctest::Approx(0.5)); // Cosine of half the angle.
+}
+
+TEST_CASE("[Quaternion] Construct AxisAngle 2") {
+ // Easy to visualize: 30 deg about Y-axis.
+ Quaternion q(Vector3(0.0, 1.0, 0.0), Math::deg_to_rad(30.0));
+
+ CHECK(q[0] == doctest::Approx(0.0));
+ CHECK(q[1] == doctest::Approx(0.258819)); // Sine of half the angle.
+ CHECK(q[2] == doctest::Approx(0.0));
+ CHECK(q[3] == doctest::Approx(0.965926)); // Cosine of half the angle.
+}
+
+TEST_CASE("[Quaternion] Construct AxisAngle 3") {
+ // Easy to visualize: 60 deg about Z-axis.
+ Quaternion q(Vector3(0.0, 0.0, 1.0), Math::deg_to_rad(60.0));
+
+ CHECK(q[0] == doctest::Approx(0.0));
+ CHECK(q[1] == doctest::Approx(0.0));
+ CHECK(q[2] == doctest::Approx(0.5)); // Sine of half the angle.
+ CHECK(q[3] == doctest::Approx(0.866025)); // Cosine of half the angle.
+}
+
+TEST_CASE("[Quaternion] Construct AxisAngle 4") {
+ // More complex & hard to visualize, so test w/ data from online calculator.
+ Vector3 axis(1.0, 2.0, 0.5);
+ Quaternion q(axis.normalized(), Math::deg_to_rad(35.0));
+
+ CHECK(q[0] == doctest::Approx(0.131239));
+ CHECK(q[1] == doctest::Approx(0.262478));
+ CHECK(q[2] == doctest::Approx(0.0656194));
+ CHECK(q[3] == doctest::Approx(0.953717));
+}
+
+TEST_CASE("[Quaternion] Construct from Quaternion") {
+ Vector3 axis(1.0, 2.0, 0.5);
+ Quaternion q_src(axis.normalized(), Math::deg_to_rad(35.0));
+ Quaternion q(q_src);
+
+ CHECK(q[0] == doctest::Approx(0.131239));
+ CHECK(q[1] == doctest::Approx(0.262478));
+ CHECK(q[2] == doctest::Approx(0.0656194));
+ CHECK(q[3] == doctest::Approx(0.953717));
+}
+
+TEST_CASE("[Quaternion] Construct Euler SingleAxis") {
+ double yaw = Math::deg_to_rad(45.0);
+ double pitch = Math::deg_to_rad(30.0);
+ double roll = Math::deg_to_rad(10.0);
+
+ Vector3 euler_y(0.0, yaw, 0.0);
+ Quaternion q_y(euler_y);
+ CHECK(q_y[0] == doctest::Approx(0.0));
+ CHECK(q_y[1] == doctest::Approx(0.382684));
+ CHECK(q_y[2] == doctest::Approx(0.0));
+ CHECK(q_y[3] == doctest::Approx(0.923879));
+
+ Vector3 euler_p(pitch, 0.0, 0.0);
+ Quaternion q_p(euler_p);
+ CHECK(q_p[0] == doctest::Approx(0.258819));
+ CHECK(q_p[1] == doctest::Approx(0.0));
+ CHECK(q_p[2] == doctest::Approx(0.0));
+ CHECK(q_p[3] == doctest::Approx(0.965926));
+
+ Vector3 euler_r(0.0, 0.0, roll);
+ Quaternion q_r(euler_r);
+ CHECK(q_r[0] == doctest::Approx(0.0));
+ CHECK(q_r[1] == doctest::Approx(0.0));
+ CHECK(q_r[2] == doctest::Approx(0.0871558));
+ CHECK(q_r[3] == doctest::Approx(0.996195));
+}
+
+TEST_CASE("[Quaternion] Construct Euler YXZ dynamic axes") {
+ double yaw = Math::deg_to_rad(45.0);
+ double pitch = Math::deg_to_rad(30.0);
+ double roll = Math::deg_to_rad(10.0);
+
+ // Generate YXZ comparision data (Z-then-X-then-Y) using single-axis Euler
+ // constructor and quaternion product, both tested separately.
+ Vector3 euler_y(0.0, yaw, 0.0);
+ Quaternion q_y(euler_y);
+ Vector3 euler_p(pitch, 0.0, 0.0);
+ Quaternion q_p(euler_p);
+ Vector3 euler_r(0.0, 0.0, roll);
+ Quaternion q_r(euler_r);
+
+ // Roll-Z is followed by Pitch-X.
+ Quaternion check_xz = q_p * q_r;
+ // Then Yaw-Y follows both.
+ Quaternion check_yxz = q_y * check_xz;
+
+ // Test construction from YXZ Euler angles.
+ Vector3 euler_yxz(pitch, yaw, roll);
+ Quaternion q(euler_yxz);
+ CHECK(q[0] == doctest::Approx(check_yxz[0]));
+ CHECK(q[1] == doctest::Approx(check_yxz[1]));
+ CHECK(q[2] == doctest::Approx(check_yxz[2]));
+ CHECK(q[3] == doctest::Approx(check_yxz[3]));
+
+ // Sneak in a test of is_equal_approx.
+ CHECK(q.is_equal_approx(check_yxz));
+}
+
+TEST_CASE("[Quaternion] Construct Basis Euler") {
+ double yaw = Math::deg_to_rad(45.0);
+ double pitch = Math::deg_to_rad(30.0);
+ double roll = Math::deg_to_rad(10.0);
+ Vector3 euler_yxz(pitch, yaw, roll);
+ Quaternion q_yxz(euler_yxz);
+ Basis basis_axes(euler_yxz);
+ Quaternion q(basis_axes);
+ CHECK(q.is_equal_approx(q_yxz));
+}
+
+TEST_CASE("[Quaternion] Construct Basis Axes") {
+ // Arbitrary Euler angles.
+ Vector3 euler_yxz(Math::deg_to_rad(31.41), Math::deg_to_rad(-49.16), Math::deg_to_rad(12.34));
+ // Basis vectors from online calculation of rotation matrix.
+ Vector3 i_unit(0.5545787, 0.1823950, 0.8118957);
+ Vector3 j_unit(-0.5249245, 0.8337420, 0.1712555);
+ Vector3 k_unit(-0.6456754, -0.5211586, 0.5581192);
+ // Quaternion from online calculation.
+ Quaternion q_calc(0.2016913, -0.4245716, 0.206033, 0.8582598);
+ // Quaternion from local calculation.
+ Quaternion q_local = quat_euler_yxz_deg(Vector3(31.41, -49.16, 12.34));
+ // Quaternion from Euler angles constructor.
+ Quaternion q_euler(euler_yxz);
+ CHECK(q_calc.is_equal_approx(q_local));
+ CHECK(q_local.is_equal_approx(q_euler));
+
+ // Calculate Basis and construct Quaternion.
+ // When this is written, C++ Basis class does not construct from basis vectors.
+ // This is by design, but may be subject to change.
+ // Workaround by constructing Basis from Euler angles.
+ // basis_axes = Basis(i_unit, j_unit, k_unit);
+ Basis basis_axes(euler_yxz);
+ Quaternion q(basis_axes);
+
+ CHECK(basis_axes.get_column(0).is_equal_approx(i_unit));
+ CHECK(basis_axes.get_column(1).is_equal_approx(j_unit));
+ CHECK(basis_axes.get_column(2).is_equal_approx(k_unit));
+
+ CHECK(q.is_equal_approx(q_calc));
+ CHECK_FALSE(q.inverse().is_equal_approx(q_calc));
+ CHECK(q.is_equal_approx(q_local));
+ CHECK(q.is_equal_approx(q_euler));
+ CHECK(q[0] == doctest::Approx(0.2016913));
+ CHECK(q[1] == doctest::Approx(-0.4245716));
+ CHECK(q[2] == doctest::Approx(0.206033));
+ CHECK(q[3] == doctest::Approx(0.8582598));
+}
+
+TEST_CASE("[Quaternion] Product (book)") {
+ // Example from "Quaternions and Rotation Sequences" by Jack Kuipers, p. 108.
+ Quaternion p(1.0, -2.0, 1.0, 3.0);
+ Quaternion q(-1.0, 2.0, 3.0, 2.0);
+
+ Quaternion pq = p * q;
+ CHECK(pq[0] == doctest::Approx(-9.0));
+ CHECK(pq[1] == doctest::Approx(-2.0));
+ CHECK(pq[2] == doctest::Approx(11.0));
+ CHECK(pq[3] == doctest::Approx(8.0));
+}
+
+TEST_CASE("[Quaternion] Product") {
+ double yaw = Math::deg_to_rad(45.0);
+ double pitch = Math::deg_to_rad(30.0);
+ double roll = Math::deg_to_rad(10.0);
+
+ Vector3 euler_y(0.0, yaw, 0.0);
+ Quaternion q_y(euler_y);
+ CHECK(q_y[0] == doctest::Approx(0.0));
+ CHECK(q_y[1] == doctest::Approx(0.382684));
+ CHECK(q_y[2] == doctest::Approx(0.0));
+ CHECK(q_y[3] == doctest::Approx(0.923879));
+
+ Vector3 euler_p(pitch, 0.0, 0.0);
+ Quaternion q_p(euler_p);
+ CHECK(q_p[0] == doctest::Approx(0.258819));
+ CHECK(q_p[1] == doctest::Approx(0.0));
+ CHECK(q_p[2] == doctest::Approx(0.0));
+ CHECK(q_p[3] == doctest::Approx(0.965926));
+
+ Vector3 euler_r(0.0, 0.0, roll);
+ Quaternion q_r(euler_r);
+ CHECK(q_r[0] == doctest::Approx(0.0));
+ CHECK(q_r[1] == doctest::Approx(0.0));
+ CHECK(q_r[2] == doctest::Approx(0.0871558));
+ CHECK(q_r[3] == doctest::Approx(0.996195));
+
+ // Test ZYX dynamic-axes since test data is available online.
+ // Rotate first about X axis, then new Y axis, then new Z axis.
+ // (Godot uses YXZ Yaw-Pitch-Roll order).
+ Quaternion q_yp = q_y * q_p;
+ CHECK(q_yp[0] == doctest::Approx(0.239118));
+ CHECK(q_yp[1] == doctest::Approx(0.369644));
+ CHECK(q_yp[2] == doctest::Approx(-0.099046));
+ CHECK(q_yp[3] == doctest::Approx(0.892399));
+
+ Quaternion q_ryp = q_r * q_yp;
+ CHECK(q_ryp[0] == doctest::Approx(0.205991));
+ CHECK(q_ryp[1] == doctest::Approx(0.389078));
+ CHECK(q_ryp[2] == doctest::Approx(-0.0208912));
+ CHECK(q_ryp[3] == doctest::Approx(0.897636));
+}
+
+TEST_CASE("[Quaternion] xform unit vectors") {
+ // Easy to visualize: 120 deg about X-axis.
+ // Transform the i, j, & k unit vectors.
+ Quaternion q(Vector3(1.0, 0.0, 0.0), Math::deg_to_rad(120.0));
+ Vector3 i_t = q.xform(Vector3(1.0, 0.0, 0.0));
+ Vector3 j_t = q.xform(Vector3(0.0, 1.0, 0.0));
+ Vector3 k_t = q.xform(Vector3(0.0, 0.0, 1.0));
+ //
+ CHECK(i_t.is_equal_approx(Vector3(1.0, 0.0, 0.0)));
+ CHECK(j_t.is_equal_approx(Vector3(0.0, -0.5, 0.866025)));
+ CHECK(k_t.is_equal_approx(Vector3(0.0, -0.866025, -0.5)));
+ CHECK(i_t.length_squared() == doctest::Approx(1.0));
+ CHECK(j_t.length_squared() == doctest::Approx(1.0));
+ CHECK(k_t.length_squared() == doctest::Approx(1.0));
+
+ // Easy to visualize: 30 deg about Y-axis.
+ q = Quaternion(Vector3(0.0, 1.0, 0.0), Math::deg_to_rad(30.0));
+ i_t = q.xform(Vector3(1.0, 0.0, 0.0));
+ j_t = q.xform(Vector3(0.0, 1.0, 0.0));
+ k_t = q.xform(Vector3(0.0, 0.0, 1.0));
+ //
+ CHECK(i_t.is_equal_approx(Vector3(0.866025, 0.0, -0.5)));
+ CHECK(j_t.is_equal_approx(Vector3(0.0, 1.0, 0.0)));
+ CHECK(k_t.is_equal_approx(Vector3(0.5, 0.0, 0.866025)));
+ CHECK(i_t.length_squared() == doctest::Approx(1.0));
+ CHECK(j_t.length_squared() == doctest::Approx(1.0));
+ CHECK(k_t.length_squared() == doctest::Approx(1.0));
+
+ // Easy to visualize: 60 deg about Z-axis.
+ q = Quaternion(Vector3(0.0, 0.0, 1.0), Math::deg_to_rad(60.0));
+ i_t = q.xform(Vector3(1.0, 0.0, 0.0));
+ j_t = q.xform(Vector3(0.0, 1.0, 0.0));
+ k_t = q.xform(Vector3(0.0, 0.0, 1.0));
+ //
+ CHECK(i_t.is_equal_approx(Vector3(0.5, 0.866025, 0.0)));
+ CHECK(j_t.is_equal_approx(Vector3(-0.866025, 0.5, 0.0)));
+ CHECK(k_t.is_equal_approx(Vector3(0.0, 0.0, 1.0)));
+ CHECK(i_t.length_squared() == doctest::Approx(1.0));
+ CHECK(j_t.length_squared() == doctest::Approx(1.0));
+ CHECK(k_t.length_squared() == doctest::Approx(1.0));
+}
+
+TEST_CASE("[Quaternion] xform vector") {
+ // Arbitrary quaternion rotates an arbitrary vector.
+ Vector3 euler_yzx(Math::deg_to_rad(31.41), Math::deg_to_rad(-49.16), Math::deg_to_rad(12.34));
+ Basis basis_axes(euler_yzx);
+ Quaternion q(basis_axes);
+
+ Vector3 v_arb(3.0, 4.0, 5.0);
+ Vector3 v_rot = q.xform(v_arb);
+ Vector3 v_compare = basis_axes.xform(v_arb);
+
+ CHECK(v_rot.length_squared() == doctest::Approx(v_arb.length_squared()));
+ CHECK(v_rot.is_equal_approx(v_compare));
+}
+
+// Test vector xform for a single combination of Quaternion and Vector.
+void test_quat_vec_rotate(Vector3 euler_yzx, Vector3 v_in) {
+ Basis basis_axes(euler_yzx);
+ Quaternion q(basis_axes);
+
+ Vector3 v_rot = q.xform(v_in);
+ Vector3 v_compare = basis_axes.xform(v_in);
+
+ CHECK(v_rot.length_squared() == doctest::Approx(v_in.length_squared()));
+ CHECK(v_rot.is_equal_approx(v_compare));
+}
+
+TEST_CASE("[Stress][Quaternion] Many vector xforms") {
+ // Many arbitrary quaternions rotate many arbitrary vectors.
+ // For each trial, check that rotation by Quaternion yields same result as
+ // rotation by Basis.
+ const int STEPS = 100; // Number of test steps in each dimension
+ const double delta = 2.0 * Math_PI / STEPS; // Angle increment per step
+ const double delta_vec = 20.0 / STEPS; // Vector increment per step
+ Vector3 vec_arb(1.0, 1.0, 1.0);
+ double x_angle = -Math_PI;
+ double y_angle = -Math_PI;
+ double z_angle = -Math_PI;
+ for (double i = 0; i < STEPS; ++i) {
+ vec_arb[0] = -10.0 + i * delta_vec;
+ x_angle = i * delta - Math_PI;
+ for (double j = 0; j < STEPS; ++j) {
+ vec_arb[1] = -10.0 + j * delta_vec;
+ y_angle = j * delta - Math_PI;
+ for (double k = 0; k < STEPS; ++k) {
+ vec_arb[2] = -10.0 + k * delta_vec;
+ z_angle = k * delta - Math_PI;
+ Vector3 euler_yzx(x_angle, y_angle, z_angle);
+ test_quat_vec_rotate(euler_yzx, vec_arb);
+ }
+ }
+ }
+}
+
+} // namespace TestQuaternion
+
+#endif // TEST_QUATERNION_H
diff --git a/modules/mono/glue/callable_glue.cpp b/tests/core/math/test_transform_2d.h
index 521dc3dff7..697bf63fc5 100644
--- a/modules/mono/glue/callable_glue.cpp
+++ b/tests/core/math/test_transform_2d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* callable_glue.cpp */
+/* test_transform_2d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,52 +28,61 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef MONO_GLUE_ENABLED
+#ifndef TEST_TRANSFORM_2D_H
+#define TEST_TRANSFORM_2D_H
-#include "../mono_gd/gd_mono_marshal.h"
-#include "arguments_vector.h"
+#include "core/math/transform_2d.h"
-MonoObject *godot_icall_Callable_Call(GDMonoMarshal::M_Callable *p_callable, MonoArray *p_args) {
- Callable callable = GDMonoMarshal::managed_to_callable(*p_callable);
+#include "tests/test_macros.h"
- int argc = mono_array_length(p_args);
+namespace TestTransform2D {
- ArgumentsVector<Variant> arg_store(argc);
- ArgumentsVector<const Variant *> args(argc);
+Transform2D create_dummy_transform() {
+ return Transform2D(Vector2(1, 2), Vector2(3, 4), Vector2(5, 6));
+}
+
+Transform2D identity() {
+ return Transform2D();
+}
- for (int i = 0; i < argc; i++) {
- MonoObject *elem = mono_array_get(p_args, MonoObject *, i);
- arg_store.set(i, GDMonoMarshal::mono_object_to_variant(elem));
- args.set(i, &arg_store.get(i));
- }
+TEST_CASE("[Transform2D] translation") {
+ Vector2 offset = Vector2(1, 2);
- Variant result;
- Callable::CallError error;
- callable.callp(args.ptr(), argc, result, error);
+ // Both versions should give the same result applied to identity.
+ CHECK(identity().translated(offset) == identity().translated_local(offset));
- return GDMonoMarshal::variant_to_mono_object(result);
+ // Check both versions against left and right multiplications.
+ Transform2D orig = create_dummy_transform();
+ Transform2D T = identity().translated(offset);
+ CHECK(orig.translated(offset) == T * orig);
+ CHECK(orig.translated_local(offset) == orig * T);
}
-void godot_icall_Callable_CallDeferred(GDMonoMarshal::M_Callable *p_callable, MonoArray *p_args) {
- Callable callable = GDMonoMarshal::managed_to_callable(*p_callable);
+TEST_CASE("[Transform2D] scaling") {
+ Vector2 scaling = Vector2(1, 2);
- int argc = mono_array_length(p_args);
+ // Both versions should give the same result applied to identity.
+ CHECK(identity().scaled(scaling) == identity().scaled_local(scaling));
- ArgumentsVector<Variant> arg_store(argc);
- ArgumentsVector<const Variant *> args(argc);
+ // Check both versions against left and right multiplications.
+ Transform2D orig = create_dummy_transform();
+ Transform2D S = identity().scaled(scaling);
+ CHECK(orig.scaled(scaling) == S * orig);
+ CHECK(orig.scaled_local(scaling) == orig * S);
+}
- for (int i = 0; i < argc; i++) {
- MonoObject *elem = mono_array_get(p_args, MonoObject *, i);
- arg_store.set(i, GDMonoMarshal::mono_object_to_variant(elem));
- args.set(i, &arg_store.get(i));
- }
+TEST_CASE("[Transform2D] rotation") {
+ real_t phi = 1.0;
- callable.call_deferredp(args.ptr(), argc);
-}
+ // Both versions should give the same result applied to identity.
+ CHECK(identity().rotated(phi) == identity().rotated_local(phi));
-void godot_register_callable_icalls() {
- GDMonoUtils::add_internal_call("Godot.Callable::godot_icall_Callable_Call", godot_icall_Callable_Call);
- GDMonoUtils::add_internal_call("Godot.Callable::godot_icall_Callable_CallDeferred", godot_icall_Callable_CallDeferred);
+ // Check both versions against left and right multiplications.
+ Transform2D orig = create_dummy_transform();
+ Transform2D R = identity().rotated(phi);
+ CHECK(orig.rotated(phi) == R * orig);
+ CHECK(orig.rotated_local(phi) == orig * R);
}
+} // namespace TestTransform2D
-#endif // MONO_GLUE_ENABLED
+#endif // TEST_TRANSFORM_2D_H
diff --git a/modules/mono/mono_gd/gd_mono_wasm_m2n.cpp b/tests/core/math/test_transform_3d.h
index dbfca2dc0c..da166b43f7 100644
--- a/modules/mono/mono_gd/gd_mono_wasm_m2n.cpp
+++ b/tests/core/math/test_transform_3d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* gd_mono_wasm_m2n.cpp */
+/* test_transform_3d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,52 +28,62 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "gd_mono_wasm_m2n.h"
+#ifndef TEST_TRANSFORM_3D_H
+#define TEST_TRANSFORM_3D_H
-#ifdef JAVASCRIPT_ENABLED
+#include "core/math/transform_3d.h"
-#include "core/templates/oa_hash_map.h"
+#include "tests/test_macros.h"
-typedef mono_bool (*GodotMonoM2nIcallTrampolineDispatch)(const char *cookie, void *target_func, Mono_InterpMethodArguments *margs);
+namespace TestTransform3D {
-// This extern function is implemented in our patched version of Mono
-MONO_API void godot_mono_register_m2n_icall_trampoline_dispatch_hook(GodotMonoM2nIcallTrampolineDispatch hook);
+Transform3D create_dummy_transform() {
+ return Transform3D(Basis(Vector3(1, 2, 3), Vector3(4, 5, 6), Vector3(7, 8, 9)), Vector3(10, 11, 12));
+}
-namespace GDMonoWasmM2n {
+Transform3D identity() {
+ return Transform3D();
+}
-struct HashMapCookieComparator {
- static bool compare(const char *p_lhs, const char *p_rhs) {
- return strcmp(p_lhs, p_rhs) == 0;
- }
-};
+TEST_CASE("[Transform3D] translation") {
+ Vector3 offset = Vector3(1, 2, 3);
-// The default hasher supports 'const char *' C Strings, but we need a custom comparator
-OAHashMap<const char *, TrampolineFunc, HashMapHasherDefault, HashMapCookieComparator> trampolines;
+ // Both versions should give the same result applied to identity.
+ CHECK(identity().translated(offset) == identity().translated_local(offset));
-void set_trampoline(const char *cookies, GDMonoWasmM2n::TrampolineFunc trampoline_func) {
- trampolines.set(cookies, trampoline_func);
+ // Check both versions against left and right multiplications.
+ Transform3D orig = create_dummy_transform();
+ Transform3D T = identity().translated(offset);
+ CHECK(orig.translated(offset) == T * orig);
+ CHECK(orig.translated_local(offset) == orig * T);
}
-mono_bool trampoline_dispatch_hook(const char *cookie, void *target_func, Mono_InterpMethodArguments *margs) {
- TrampolineFunc *trampoline_func = trampolines.lookup_ptr(cookie);
+TEST_CASE("[Transform3D] scaling") {
+ Vector3 scaling = Vector3(1, 2, 3);
- if (!trampoline_func) {
- return false;
- }
+ // Both versions should give the same result applied to identity.
+ CHECK(identity().scaled(scaling) == identity().scaled_local(scaling));
- (*trampoline_func)(target_func, margs);
- return true;
+ // Check both versions against left and right multiplications.
+ Transform3D orig = create_dummy_transform();
+ Transform3D S = identity().scaled(scaling);
+ CHECK(orig.scaled(scaling) == S * orig);
+ CHECK(orig.scaled_local(scaling) == orig * S);
}
-bool initialized = false;
+TEST_CASE("[Transform3D] rotation") {
+ Vector3 axis = Vector3(1, 2, 3).normalized();
+ real_t phi = 1.0;
+
+ // Both versions should give the same result applied to identity.
+ CHECK(identity().rotated(axis, phi) == identity().rotated_local(axis, phi));
-void lazy_initialize() {
- // Doesn't need to be thread safe
- if (!initialized) {
- initialized = true;
- godot_mono_register_m2n_icall_trampoline_dispatch_hook(&trampoline_dispatch_hook);
- }
+ // Check both versions against left and right multiplications.
+ Transform3D orig = create_dummy_transform();
+ Transform3D R = identity().rotated(axis, phi);
+ CHECK(orig.rotated(axis, phi) == R * orig);
+ CHECK(orig.rotated_local(axis, phi) == orig * R);
}
-} // namespace GDMonoWasmM2n
+} // namespace TestTransform3D
-#endif
+#endif // TEST_TRANSFORM_3D_H
diff --git a/tests/core/math/test_vector4.h b/tests/core/math/test_vector4.h
new file mode 100644
index 0000000000..ccf991401b
--- /dev/null
+++ b/tests/core/math/test_vector4.h
@@ -0,0 +1,315 @@
+/*************************************************************************/
+/* test_vector4.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_VECTOR4_H
+#define TEST_VECTOR4_H
+
+#include "core/math/vector4.h"
+#include "tests/test_macros.h"
+
+#define Math_SQRT3 1.7320508075688772935274463415059
+
+namespace TestVector4 {
+
+TEST_CASE("[Vector4] Axis methods") {
+ Vector4 vector = Vector4(1.2, 3.4, 5.6, -0.9);
+ CHECK_MESSAGE(
+ vector.max_axis_index() == Vector4::Axis::AXIS_Z,
+ "Vector4 max_axis_index should work as expected.");
+ CHECK_MESSAGE(
+ vector.min_axis_index() == Vector4::Axis::AXIS_W,
+ "Vector4 min_axis_index should work as expected.");
+ CHECK_MESSAGE(
+ vector.get_axis(vector.max_axis_index()) == (real_t)5.6,
+ "Vector4 get_axis should work as expected.");
+ CHECK_MESSAGE(
+ vector[vector.min_axis_index()] == (real_t)-0.9,
+ "Vector4 array operator should work as expected.");
+
+ vector.set_axis(Vector4::Axis::AXIS_Y, 4.7);
+ CHECK_MESSAGE(
+ vector.get_axis(Vector4::Axis::AXIS_Y) == (real_t)4.7,
+ "Vector4 set_axis should work as expected.");
+ vector[Vector4::Axis::AXIS_Y] = 3.7;
+ CHECK_MESSAGE(
+ vector[Vector4::Axis::AXIS_Y] == (real_t)3.7,
+ "Vector4 array operator setter should work as expected.");
+}
+
+TEST_CASE("[Vector4] Interpolation methods") {
+ const Vector4 vector1 = Vector4(1, 2, 3, 4);
+ const Vector4 vector2 = Vector4(4, 5, 6, 7);
+ CHECK_MESSAGE(
+ vector1.lerp(vector2, 0.5) == Vector4(2.5, 3.5, 4.5, 5.5),
+ "Vector4 lerp should work as expected.");
+ CHECK_MESSAGE(
+ vector1.lerp(vector2, 1.0 / 3.0).is_equal_approx(Vector4(2, 3, 4, 5)),
+ "Vector4 lerp should work as expected.");
+ CHECK_MESSAGE(
+ vector1.cubic_interpolate(vector2, Vector4(), Vector4(7, 7, 7, 7), 0.5) == Vector4(2.375, 3.5, 4.625, 5.75),
+ "Vector4 cubic_interpolate should work as expected.");
+ CHECK_MESSAGE(
+ vector1.cubic_interpolate(vector2, Vector4(), Vector4(7, 7, 7, 7), 1.0 / 3.0).is_equal_approx(Vector4(1.851851940155029297, 2.962963104248046875, 4.074074268341064453, 5.185185185185)),
+ "Vector4 cubic_interpolate should work as expected.");
+}
+
+TEST_CASE("[Vector4] Length methods") {
+ const Vector4 vector1 = Vector4(10, 10, 10, 10);
+ const Vector4 vector2 = Vector4(20, 30, 40, 50);
+ CHECK_MESSAGE(
+ vector1.length_squared() == 400,
+ "Vector4 length_squared should work as expected and return exact result.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(vector1.length(), 20),
+ "Vector4 length should work as expected.");
+ CHECK_MESSAGE(
+ vector2.length_squared() == 5400,
+ "Vector4 length_squared should work as expected and return exact result.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(vector2.length(), (real_t)73.484692283495),
+ "Vector4 length should work as expected.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(vector1.distance_to(vector2), (real_t)54.772255750517),
+ "Vector4 distance_to should work as expected.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(vector1.distance_squared_to(vector2), 3000),
+ "Vector4 distance_squared_to should work as expected.");
+}
+
+TEST_CASE("[Vector4] Limiting methods") {
+ const Vector4 vector = Vector4(10, 10, 10, 10);
+ CHECK_MESSAGE(
+ Vector4(-5, 5, 15, -15).clamp(Vector4(), vector) == Vector4(0, 5, 10, 0),
+ "Vector4 clamp should work as expected.");
+ CHECK_MESSAGE(
+ vector.clamp(Vector4(0, 10, 15, 18), Vector4(5, 10, 20, 25)) == Vector4(5, 10, 15, 18),
+ "Vector4 clamp should work as expected.");
+}
+
+TEST_CASE("[Vector4] Normalization methods") {
+ CHECK_MESSAGE(
+ Vector4(1, 0, 0, 0).is_normalized() == true,
+ "Vector4 is_normalized should return true for a normalized vector.");
+ CHECK_MESSAGE(
+ Vector4(1, 1, 1, 1).is_normalized() == false,
+ "Vector4 is_normalized should return false for a non-normalized vector.");
+ CHECK_MESSAGE(
+ Vector4(1, 0, 0, 0).normalized() == Vector4(1, 0, 0, 0),
+ "Vector4 normalized should return the same vector for a normalized vector.");
+ CHECK_MESSAGE(
+ Vector4(1, 1, 0, 0).normalized().is_equal_approx(Vector4(Math_SQRT12, Math_SQRT12, 0, 0)),
+ "Vector4 normalized should work as expected.");
+ CHECK_MESSAGE(
+ Vector4(1, 1, 1, 1).normalized().is_equal_approx(Vector4(0.5, 0.5, 0.5, 0.5)),
+ "Vector4 normalized should work as expected.");
+}
+
+TEST_CASE("[Vector4] Operators") {
+ const Vector4 decimal1 = Vector4(2.3, 4.9, 7.8, 3.2);
+ const Vector4 decimal2 = Vector4(1.2, 3.4, 5.6, 1.7);
+ const Vector4 power1 = Vector4(0.75, 1.5, 0.625, 0.125);
+ const Vector4 power2 = Vector4(0.5, 0.125, 0.25, 0.75);
+ const Vector4 int1 = Vector4(4, 5, 9, 2);
+ const Vector4 int2 = Vector4(1, 2, 3, 1);
+
+ CHECK_MESSAGE(
+ -decimal1 == Vector4(-2.3, -4.9, -7.8, -3.2),
+ "Vector4 change of sign should work as expected.");
+ CHECK_MESSAGE(
+ (decimal1 + decimal2).is_equal_approx(Vector4(3.5, 8.3, 13.4, 4.9)),
+ "Vector4 addition should behave as expected.");
+ CHECK_MESSAGE(
+ (power1 + power2) == Vector4(1.25, 1.625, 0.875, 0.875),
+ "Vector4 addition with powers of two should give exact results.");
+ CHECK_MESSAGE(
+ (int1 + int2) == Vector4(5, 7, 12, 3),
+ "Vector4 addition with integers should give exact results.");
+
+ CHECK_MESSAGE(
+ (decimal1 - decimal2).is_equal_approx(Vector4(1.1, 1.5, 2.2, 1.5)),
+ "Vector4 subtraction should behave as expected.");
+ CHECK_MESSAGE(
+ (power1 - power2) == Vector4(0.25, 1.375, 0.375, -0.625),
+ "Vector4 subtraction with powers of two should give exact results.");
+ CHECK_MESSAGE(
+ (int1 - int2) == Vector4(3, 3, 6, 1),
+ "Vector4 subtraction with integers should give exact results.");
+
+ CHECK_MESSAGE(
+ (decimal1 * decimal2).is_equal_approx(Vector4(2.76, 16.66, 43.68, 5.44)),
+ "Vector4 multiplication should behave as expected.");
+ CHECK_MESSAGE(
+ (power1 * power2) == Vector4(0.375, 0.1875, 0.15625, 0.09375),
+ "Vector4 multiplication with powers of two should give exact results.");
+ CHECK_MESSAGE(
+ (int1 * int2) == Vector4(4, 10, 27, 2),
+ "Vector4 multiplication with integers should give exact results.");
+
+ CHECK_MESSAGE(
+ (decimal1 / decimal2).is_equal_approx(Vector4(1.91666666666666666, 1.44117647058823529, 1.39285714285714286, 1.88235294118)),
+ "Vector4 division should behave as expected.");
+ CHECK_MESSAGE(
+ (power1 / power2) == Vector4(1.5, 12.0, 2.5, 1.0 / 6.0),
+ "Vector4 division with powers of two should give exact results.");
+ CHECK_MESSAGE(
+ (int1 / int2) == Vector4(4, 2.5, 3, 2),
+ "Vector4 division with integers should give exact results.");
+
+ CHECK_MESSAGE(
+ (decimal1 * 2).is_equal_approx(Vector4(4.6, 9.8, 15.6, 6.4)),
+ "Vector4 multiplication should behave as expected.");
+ CHECK_MESSAGE(
+ (power1 * 2) == Vector4(1.5, 3, 1.25, 0.25),
+ "Vector4 multiplication with powers of two should give exact results.");
+ CHECK_MESSAGE(
+ (int1 * 2) == Vector4(8, 10, 18, 4),
+ "Vector4 multiplication with integers should give exact results.");
+
+ CHECK_MESSAGE(
+ (decimal1 / 2).is_equal_approx(Vector4(1.15, 2.45, 3.9, 1.6)),
+ "Vector4 division should behave as expected.");
+ CHECK_MESSAGE(
+ (power1 / 2) == Vector4(0.375, 0.75, 0.3125, 0.0625),
+ "Vector4 division with powers of two should give exact results.");
+ CHECK_MESSAGE(
+ (int1 / 2) == Vector4(2, 2.5, 4.5, 1),
+ "Vector4 division with integers should give exact results.");
+
+ CHECK_MESSAGE(
+ ((String)decimal1) == "(2.3, 4.9, 7.8, 3.2)",
+ "Vector4 cast to String should work as expected.");
+ CHECK_MESSAGE(
+ ((String)decimal2) == "(1.2, 3.4, 5.6, 1.7)",
+ "Vector4 cast to String should work as expected.");
+ CHECK_MESSAGE(
+ ((String)Vector4(9.7, 9.8, 9.9, -1.8)) == "(9.7, 9.8, 9.9, -1.8)",
+ "Vector4 cast to String should work as expected.");
+#ifdef REAL_T_IS_DOUBLE
+ CHECK_MESSAGE(
+ ((String)Vector4(Math_E, Math_SQRT2, Math_SQRT3, Math_SQRT3)) == "(2.71828182845905, 1.4142135623731, 1.73205080756888, 1.73205080756888)",
+ "Vector4 cast to String should print the correct amount of digits for real_t = double.");
+#else
+ CHECK_MESSAGE(
+ ((String)Vector4(Math_E, Math_SQRT2, Math_SQRT3, Math_SQRT3)) == "(2.718282, 1.414214, 1.732051, 1.732051)",
+ "Vector4 cast to String should print the correct amount of digits for real_t = float.");
+#endif // REAL_T_IS_DOUBLE
+}
+
+TEST_CASE("[Vector4] Other methods") {
+ const Vector4 vector = Vector4(1.2, 3.4, 5.6, 1.6);
+ CHECK_MESSAGE(
+ vector.direction_to(Vector4()).is_equal_approx(-vector.normalized()),
+ "Vector4 direction_to should work as expected.");
+ CHECK_MESSAGE(
+ Vector4(1, 1, 1, 1).direction_to(Vector4(2, 2, 2, 2)).is_equal_approx(Vector4(0.5, 0.5, 0.5, 0.5)),
+ "Vector4 direction_to should work as expected.");
+ CHECK_MESSAGE(
+ vector.inverse().is_equal_approx(Vector4(1 / 1.2, 1 / 3.4, 1 / 5.6, 1 / 1.6)),
+ "Vector4 inverse should work as expected.");
+ CHECK_MESSAGE(
+ vector.posmod(2).is_equal_approx(Vector4(1.2, 1.4, 1.6, 1.6)),
+ "Vector4 posmod should work as expected.");
+ CHECK_MESSAGE(
+ (-vector).posmod(2).is_equal_approx(Vector4(0.8, 0.6, 0.4, 0.4)),
+ "Vector4 posmod should work as expected.");
+ CHECK_MESSAGE(
+ vector.posmodv(Vector4(1, 2, 3, 4)).is_equal_approx(Vector4(0.2, 1.4, 2.6, 1.6)),
+ "Vector4 posmodv should work as expected.");
+ CHECK_MESSAGE(
+ (-vector).posmodv(Vector4(2, 3, 4, 5)).is_equal_approx(Vector4(0.8, 2.6, 2.4, 3.4)),
+ "Vector4 posmodv should work as expected.");
+ CHECK_MESSAGE(
+ vector.snapped(Vector4(1, 1, 1, 1)) == Vector4(1, 3, 6, 2),
+ "Vector4 snapped to integers should be the same as rounding.");
+ CHECK_MESSAGE(
+ vector.snapped(Vector4(0.25, 0.25, 0.25, 0.25)) == Vector4(1.25, 3.5, 5.5, 1.5),
+ "Vector4 snapped to 0.25 should give exact results.");
+}
+
+TEST_CASE("[Vector4] Rounding methods") {
+ const Vector4 vector1 = Vector4(1.2, 3.4, 5.6, 1.6);
+ const Vector4 vector2 = Vector4(1.2, -3.4, -5.6, -1.6);
+ CHECK_MESSAGE(
+ vector1.abs() == vector1,
+ "Vector4 abs should work as expected.");
+ CHECK_MESSAGE(
+ vector2.abs() == vector1,
+ "Vector4 abs should work as expected.");
+ CHECK_MESSAGE(
+ vector1.ceil() == Vector4(2, 4, 6, 2),
+ "Vector4 ceil should work as expected.");
+ CHECK_MESSAGE(
+ vector2.ceil() == Vector4(2, -3, -5, -1),
+ "Vector4 ceil should work as expected.");
+
+ CHECK_MESSAGE(
+ vector1.floor() == Vector4(1, 3, 5, 1),
+ "Vector4 floor should work as expected.");
+ CHECK_MESSAGE(
+ vector2.floor() == Vector4(1, -4, -6, -2),
+ "Vector4 floor should work as expected.");
+
+ CHECK_MESSAGE(
+ vector1.round() == Vector4(1, 3, 6, 2),
+ "Vector4 round should work as expected.");
+ CHECK_MESSAGE(
+ vector2.round() == Vector4(1, -3, -6, -2),
+ "Vector4 round should work as expected.");
+
+ CHECK_MESSAGE(
+ vector1.sign() == Vector4(1, 1, 1, 1),
+ "Vector4 sign should work as expected.");
+ CHECK_MESSAGE(
+ vector2.sign() == Vector4(1, -1, -1, -1),
+ "Vector4 sign should work as expected.");
+}
+
+TEST_CASE("[Vector4] Linear algebra methods") {
+ const Vector4 vector_x = Vector4(1, 0, 0, 0);
+ const Vector4 vector_y = Vector4(0, 1, 0, 0);
+ const Vector4 vector1 = Vector4(1.7, 2.3, 1, 9.1);
+ const Vector4 vector2 = Vector4(-8.2, -16, 3, 2.4);
+
+ CHECK_MESSAGE(
+ vector_x.dot(vector_y) == 0.0,
+ "Vector4 dot product of perpendicular vectors should be zero.");
+ CHECK_MESSAGE(
+ vector_x.dot(vector_x) == 1.0,
+ "Vector4 dot product of identical unit vectors should be one.");
+ CHECK_MESSAGE(
+ (vector_x * 10).dot(vector_x * 10) == 100.0,
+ "Vector4 dot product of same direction vectors should behave as expected.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx((vector1 * 2).dot(vector2 * 4), (real_t)-25.9 * 8),
+ "Vector4 dot product should work as expected.");
+}
+} // namespace TestVector4
+
+#endif // TEST_VECTOR4_H
diff --git a/tests/core/math/test_vector4i.h b/tests/core/math/test_vector4i.h
new file mode 100644
index 0000000000..ac63001b24
--- /dev/null
+++ b/tests/core/math/test_vector4i.h
@@ -0,0 +1,148 @@
+/*************************************************************************/
+/* test_vector4i.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_VECTOR4I_H
+#define TEST_VECTOR4I_H
+
+#include "core/math/vector4i.h"
+#include "tests/test_macros.h"
+
+namespace TestVector4i {
+
+TEST_CASE("[Vector4i] Axis methods") {
+ Vector4i vector = Vector4i(1, 2, 3, 4);
+ CHECK_MESSAGE(
+ vector.max_axis_index() == Vector4i::Axis::AXIS_W,
+ "Vector4i max_axis_index should work as expected.");
+ CHECK_MESSAGE(
+ vector.min_axis_index() == Vector4i::Axis::AXIS_X,
+ "Vector4i min_axis_index should work as expected.");
+ CHECK_MESSAGE(
+ vector.get_axis(vector.max_axis_index()) == 4,
+ "Vector4i get_axis should work as expected.");
+ CHECK_MESSAGE(
+ vector[vector.min_axis_index()] == 1,
+ "Vector4i array operator should work as expected.");
+
+ vector.set_axis(Vector4i::Axis::AXIS_Y, 5);
+ CHECK_MESSAGE(
+ vector.get_axis(Vector4i::Axis::AXIS_Y) == 5,
+ "Vector4i set_axis should work as expected.");
+ vector[Vector4i::Axis::AXIS_Y] = 5;
+ CHECK_MESSAGE(
+ vector[Vector4i::Axis::AXIS_Y] == 5,
+ "Vector4i array operator setter should work as expected.");
+}
+
+TEST_CASE("[Vector4i] Clamp method") {
+ const Vector4i vector = Vector4i(10, 10, 10, 10);
+ CHECK_MESSAGE(
+ Vector4i(-5, 5, 15, INT_MAX).clamp(Vector4i(), vector) == Vector4i(0, 5, 10, 10),
+ "Vector4i clamp should work as expected.");
+ CHECK_MESSAGE(
+ vector.clamp(Vector4i(0, 10, 15, -10), Vector4i(5, 10, 20, -5)) == Vector4i(5, 10, 15, -5),
+ "Vector4i clamp should work as expected.");
+}
+
+TEST_CASE("[Vector4i] Length methods") {
+ const Vector4i vector1 = Vector4i(10, 10, 10, 10);
+ const Vector4i vector2 = Vector4i(20, 30, 40, 50);
+ CHECK_MESSAGE(
+ vector1.length_squared() == 400,
+ "Vector4i length_squared should work as expected and return exact result.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(vector1.length(), 20),
+ "Vector4i length should work as expected.");
+ CHECK_MESSAGE(
+ vector2.length_squared() == 5400,
+ "Vector4i length_squared should work as expected and return exact result.");
+ CHECK_MESSAGE(
+ Math::is_equal_approx(vector2.length(), 73.4846922835),
+ "Vector4i length should work as expected.");
+}
+
+TEST_CASE("[Vector4i] Operators") {
+ const Vector4i vector1 = Vector4i(4, 5, 9, 2);
+ const Vector4i vector2 = Vector4i(1, 2, 3, 4);
+
+ CHECK_MESSAGE(
+ -vector1 == Vector4i(-4, -5, -9, -2),
+ "Vector4i change of sign should work as expected.");
+ CHECK_MESSAGE(
+ (vector1 + vector2) == Vector4i(5, 7, 12, 6),
+ "Vector4i addition with integers should give exact results.");
+ CHECK_MESSAGE(
+ (vector1 - vector2) == Vector4i(3, 3, 6, -2),
+ "Vector4i subtraction with integers should give exact results.");
+ CHECK_MESSAGE(
+ (vector1 * vector2) == Vector4i(4, 10, 27, 8),
+ "Vector4i multiplication with integers should give exact results.");
+ CHECK_MESSAGE(
+ (vector1 / vector2) == Vector4i(4, 2, 3, 0),
+ "Vector4i division with integers should give exact results.");
+
+ CHECK_MESSAGE(
+ (vector1 * 2) == Vector4i(8, 10, 18, 4),
+ "Vector4i multiplication with integers should give exact results.");
+ CHECK_MESSAGE(
+ (vector1 / 2) == Vector4i(2, 2, 4, 1),
+ "Vector4i division with integers should give exact results.");
+
+ CHECK_MESSAGE(
+ ((Vector4)vector1) == Vector4(4, 5, 9, 2),
+ "Vector4i cast to Vector4 should work as expected.");
+ CHECK_MESSAGE(
+ ((Vector4)vector2) == Vector4(1, 2, 3, 4),
+ "Vector4i cast to Vector4 should work as expected.");
+ CHECK_MESSAGE(
+ Vector4i(Vector4(1.1, 2.9, 3.9, 100.5)) == Vector4i(1, 2, 3, 100),
+ "Vector4i constructed from Vector4 should work as expected.");
+}
+
+TEST_CASE("[Vector4i] Abs and sign methods") {
+ const Vector4i vector1 = Vector4i(1, 3, 5, 7);
+ const Vector4i vector2 = Vector4i(1, -3, -5, 7);
+ CHECK_MESSAGE(
+ vector1.abs() == vector1,
+ "Vector4i abs should work as expected.");
+ CHECK_MESSAGE(
+ vector2.abs() == vector1,
+ "Vector4i abs should work as expected.");
+
+ CHECK_MESSAGE(
+ vector1.sign() == Vector4i(1, 1, 1, 1),
+ "Vector4i sign should work as expected.");
+ CHECK_MESSAGE(
+ vector2.sign() == Vector4i(1, -1, -1, 1),
+ "Vector4i sign should work as expected.");
+}
+} // namespace TestVector4i
+
+#endif // TEST_VECTOR4I_H
diff --git a/tests/core/object/test_class_db.h b/tests/core/object/test_class_db.h
index c7535426df..208923edb9 100644
--- a/tests/core/object/test_class_db.h
+++ b/tests/core/object/test_class_db.h
@@ -71,6 +71,7 @@ struct ArgumentData {
String name;
bool has_defval = false;
Variant defval;
+ int position;
};
struct MethodData {
@@ -371,6 +372,39 @@ void validate_property(const Context &p_context, const ExposedClass &p_class, co
}
}
+void validate_argument(const Context &p_context, const ExposedClass &p_class, const String &p_owner_name, const String &p_owner_type, const ArgumentData &p_arg) {
+ TEST_COND((p_arg.name.is_empty() || p_arg.name.begins_with("_unnamed_arg")),
+ vformat("Unnamed argument in position %d of %s '%s.%s'.", p_arg.position, p_owner_type, p_class.name, p_owner_name));
+
+ const ExposedClass *arg_class = p_context.find_exposed_class(p_arg.type);
+ if (arg_class) {
+ TEST_COND(arg_class->is_singleton,
+ vformat("Argument type is a singleton: '%s' of %s '%s.%s'.", p_arg.name, p_owner_type, p_class.name, p_owner_name));
+
+ if (p_class.api_type == ClassDB::API_CORE) {
+ TEST_COND(arg_class->api_type == ClassDB::API_EDITOR,
+ vformat("Argument '%s' of %s '%s.%s' has type '%s' from the editor API. Core API cannot have dependencies on the editor API.",
+ p_arg.name, p_owner_type, p_class.name, p_owner_name, arg_class->name));
+ }
+ } else {
+ // Look for types that don't inherit Object.
+ TEST_FAIL_COND(!p_context.has_type(p_arg.type),
+ vformat("Argument type '%s' not found: '%s' of %s '%s.%s'.", p_arg.type.name, p_arg.name, p_owner_type, p_class.name, p_owner_name));
+ }
+
+ if (p_arg.has_defval) {
+ String type_error_msg;
+ bool arg_defval_assignable_to_type = arg_default_value_is_assignable_to_type(p_context, p_arg.defval, p_arg.type, &type_error_msg);
+
+ String err_msg = vformat("Invalid default value for parameter '%s' of %s '%s.%s'.", p_arg.name, p_owner_type, p_class.name, p_owner_name);
+ if (!type_error_msg.is_empty()) {
+ err_msg += " " + type_error_msg;
+ }
+
+ TEST_COND(!arg_defval_assignable_to_type, err_msg.utf8().get_data());
+ }
+}
+
void validate_method(const Context &p_context, const ExposedClass &p_class, const MethodData &p_method) {
if (p_method.return_type.name != StringName()) {
const ExposedClass *return_class = p_context.find_exposed_class(p_method.return_type);
@@ -392,54 +426,14 @@ void validate_method(const Context &p_context, const ExposedClass &p_class, cons
for (const ArgumentData &F : p_method.arguments) {
const ArgumentData &arg = F;
-
- const ExposedClass *arg_class = p_context.find_exposed_class(arg.type);
- if (arg_class) {
- TEST_COND(arg_class->is_singleton,
- "Argument type is a singleton: '", arg.name, "' of method '", p_class.name, ".", p_method.name, "'.");
-
- if (p_class.api_type == ClassDB::API_CORE) {
- TEST_COND(arg_class->api_type == ClassDB::API_EDITOR,
- "Argument '", arg.name, "' of method '", p_class.name, ".", p_method.name, "' has type '",
- arg_class->name, "' from the editor API. Core API cannot have dependencies on the editor API.");
- }
- } else {
- // Look for types that don't inherit Object
- TEST_FAIL_COND(!p_context.has_type(arg.type),
- "Argument type '", arg.type.name, "' not found: '", arg.name, "' of method", p_class.name, ".", p_method.name, "'.");
- }
-
- if (arg.has_defval) {
- String type_error_msg;
- bool arg_defval_assignable_to_type = arg_default_value_is_assignable_to_type(p_context, arg.defval, arg.type, &type_error_msg);
- String err_msg = vformat("Invalid default value for parameter '%s' of method '%s.%s'.", arg.name, p_class.name, p_method.name);
- if (!type_error_msg.is_empty()) {
- err_msg += " " + type_error_msg;
- }
- TEST_COND(!arg_defval_assignable_to_type, err_msg.utf8().get_data());
- }
+ validate_argument(p_context, p_class, p_method.name, "method", arg);
}
}
void validate_signal(const Context &p_context, const ExposedClass &p_class, const SignalData &p_signal) {
for (const ArgumentData &F : p_signal.arguments) {
const ArgumentData &arg = F;
-
- const ExposedClass *arg_class = p_context.find_exposed_class(arg.type);
- if (arg_class) {
- TEST_COND(arg_class->is_singleton,
- "Argument class is a singleton: '", arg.name, "' of signal '", p_class.name, ".", p_signal.name, "'.");
-
- if (p_class.api_type == ClassDB::API_CORE) {
- TEST_COND(arg_class->api_type == ClassDB::API_EDITOR,
- "Argument '", arg.name, "' of signal '", p_class.name, ".", p_signal.name, "' has type '",
- arg_class->name, "' from the editor API. Core API cannot have dependencies on the editor API.");
- }
- } else {
- // Look for types that don't inherit Object
- TEST_FAIL_COND(!p_context.has_type(arg.type),
- "Argument type '", arg.type.name, "' not found: '", arg.name, "' of signal", p_class.name, ".", p_signal.name, "'.");
- }
+ validate_argument(p_context, p_class, p_signal.name, "signal", arg);
}
}
@@ -493,13 +487,13 @@ void add_exposed_classes(Context &r_context) {
}
if (!ClassDB::is_class_exposed(class_name)) {
- MESSAGE(vformat("Ignoring class '%s' because it's not exposed.", class_name).utf8().get_data());
+ MESSAGE(vformat("Ignoring class '%s' because it's not exposed.", class_name));
class_list.pop_front();
continue;
}
if (!ClassDB::is_class_enabled(class_name)) {
- MESSAGE(vformat("Ignoring class '%s' because it's not enabled.", class_name).utf8().get_data());
+ MESSAGE(vformat("Ignoring class '%s' because it's not enabled.", class_name));
class_list.pop_front();
continue;
}
@@ -625,6 +619,7 @@ void add_exposed_classes(Context &r_context) {
ArgumentData arg;
arg.name = orig_arg_name;
+ arg.position = i;
if (arg_info.type == Variant::INT && arg_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) {
arg.type.name = arg_info.class_name;
@@ -693,6 +688,7 @@ void add_exposed_classes(Context &r_context) {
ArgumentData arg;
arg.name = orig_arg_name;
+ arg.position = i;
if (arg_info.type == Variant::INT && arg_info.usage & (PROPERTY_USAGE_CLASS_IS_ENUM | PROPERTY_USAGE_CLASS_IS_BITFIELD)) {
arg.type.name = arg_info.class_name;
@@ -841,7 +837,7 @@ TEST_SUITE("[ClassDB]") {
add_builtin_types(context);
add_global_enums(context);
- SUBCASE("[ClassDB] Find exposed class") {
+ SUBCASE("[ClassDB] Validate exposed classes") {
const ExposedClass *object_class = context.find_exposed_class(context.names_cache.object_class);
TEST_FAIL_COND(!object_class, "Object class not found.");
TEST_FAIL_COND(object_class->base != StringName(),
diff --git a/tests/core/object/test_method_bind.h b/tests/core/object/test_method_bind.h
index 350a08b6e2..2fe0c264a1 100644
--- a/tests/core/object/test_method_bind.h
+++ b/tests/core/object/test_method_bind.h
@@ -155,7 +155,6 @@ public:
TEST_CASE("[MethodBind] check all method binds") {
MethodBindTester *mbt = memnew(MethodBindTester);
- print_line("testing method bind");
mbt->run_tests();
CHECK(mbt->test_valid[MethodBindTester::TEST_METHOD]);
diff --git a/tests/core/object/test_object.h b/tests/core/object/test_object.h
index 88a3e4ccad..f5c5de7fdf 100644
--- a/tests/core/object/test_object.h
+++ b/tests/core/object/test_object.h
@@ -82,6 +82,12 @@ public:
Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid) const override {
return Variant::PACKED_FLOAT32_ARRAY;
}
+ bool property_can_revert(const StringName &p_name) const override {
+ return false;
+ };
+ bool property_get_revert(const StringName &p_name, Variant &r_ret) const override {
+ return false;
+ };
void get_method_list(List<MethodInfo> *p_list) const override {
}
bool has_method(const StringName &p_method) const override {
diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h
index 0c5704d6c9..2cd837bcc9 100644
--- a/tests/core/string/test_string.h
+++ b/tests/core/string/test_string.h
@@ -152,6 +152,20 @@ TEST_CASE("[String] UTF16 with BOM") {
CHECK(String::utf16(cs) == s);
}
+TEST_CASE("[String] UTF8 with CR") {
+ const String base = U"Hello darkness\r\nMy old friend\nI've come to talk\rWith you again";
+
+ String keep_cr;
+ Error err = keep_cr.parse_utf8(base.utf8().get_data());
+ CHECK(err == OK);
+ CHECK(keep_cr == base);
+
+ String no_cr;
+ err = no_cr.parse_utf8(base.utf8().get_data(), -1, true); // Skip CR.
+ CHECK(err == OK);
+ CHECK(no_cr == base.replace("\r", ""));
+}
+
TEST_CASE("[String] Invalid UTF8 (non-standard)") {
ERR_PRINT_OFF
static const uint8_t u8str[] = { 0x45, 0xE3, 0x81, 0x8A, 0xE3, 0x82, 0x88, 0xE3, 0x81, 0x86, 0xF0, 0x9F, 0x8E, 0xA4, 0xF0, 0x82, 0x82, 0xAC, 0xED, 0xA0, 0x81, 0 };
@@ -605,7 +619,7 @@ TEST_CASE("[String] sprintf") {
output = format.sprintf(args, &error);
REQUIRE(error == false);
CHECK(output == String("fish % frog"));
- //////// INTS
+ ///// Ints
// Int
format = "fish %d frog";
@@ -683,7 +697,9 @@ TEST_CASE("[String] sprintf") {
format = "fish %-05d frog";
args.clear();
args.push_back(-5);
+ ERR_PRINT_OFF; // Silence warning about 0 ignored.
output = format.sprintf(args, &error);
+ ERR_PRINT_ON;
REQUIRE(error == false);
CHECK(output == String("fish -5 frog"));
@@ -711,7 +727,7 @@ TEST_CASE("[String] sprintf") {
REQUIRE(error == false);
CHECK(output == String("fish 143 frog"));
- ////// REALS
+ ///// Reals
// Real
format = "fish %f frog";
@@ -721,7 +737,7 @@ TEST_CASE("[String] sprintf") {
REQUIRE(error == false);
CHECK(output == String("fish 99.990000 frog"));
- // Real left-padded
+ // Real left-padded.
format = "fish %11f frog";
args.clear();
args.push_back(99.99);
@@ -729,7 +745,7 @@ TEST_CASE("[String] sprintf") {
REQUIRE(error == false);
CHECK(output == String("fish 99.990000 frog"));
- // Real right-padded
+ // Real right-padded.
format = "fish %-11f frog";
args.clear();
args.push_back(99.99);
@@ -753,7 +769,7 @@ TEST_CASE("[String] sprintf") {
REQUIRE(error == false);
CHECK(output == String("fish +99.990000 frog"));
- // Real with 1 decimals.
+ // Real with 1 decimal.
format = "fish %.1f frog";
args.clear();
args.push_back(99.99);
@@ -781,11 +797,103 @@ TEST_CASE("[String] sprintf") {
format = "fish %-011f frog";
args.clear();
args.push_back(-99.99);
+ ERR_PRINT_OFF; // Silence warning about 0 ignored.
output = format.sprintf(args, &error);
+ ERR_PRINT_ON;
REQUIRE(error == false);
CHECK(output == String("fish -99.990000 frog"));
- /////// Strings.
+ ///// Vectors
+
+ // Vector2
+ format = "fish %v frog";
+ args.clear();
+ args.push_back(Variant(Vector2(19.99, 1.00)));
+ output = format.sprintf(args, &error);
+ REQUIRE(error == false);
+ CHECK(output == String("fish (19.990000, 1.000000) frog"));
+
+ // Vector3
+ format = "fish %v frog";
+ args.clear();
+ args.push_back(Variant(Vector3(19.99, 1.00, -2.05)));
+ output = format.sprintf(args, &error);
+ REQUIRE(error == false);
+ CHECK(output == String("fish (19.990000, 1.000000, -2.050000) frog"));
+
+ // Vector4
+ format = "fish %v frog";
+ args.clear();
+ args.push_back(Variant(Vector4(19.99, 1.00, -2.05, 5.5)));
+ output = format.sprintf(args, &error);
+ REQUIRE(error == false);
+ CHECK(output == String("fish (19.990000, 1.000000, -2.050000, 5.500000) frog"));
+
+ // Vector with negative values.
+ format = "fish %v frog";
+ args.clear();
+ args.push_back(Variant(Vector2(-19.99, -1.00)));
+ output = format.sprintf(args, &error);
+ REQUIRE(error == false);
+ CHECK(output == String("fish (-19.990000, -1.000000) frog"));
+
+ // Vector left-padded.
+ format = "fish %11v frog";
+ args.clear();
+ args.push_back(Variant(Vector3(19.99, 1.00, -2.05)));
+ output = format.sprintf(args, &error);
+ REQUIRE(error == false);
+ CHECK(output == String("fish ( 19.990000, 1.000000, -2.050000) frog"));
+
+ // Vector right-padded.
+ format = "fish %-11v frog";
+ args.clear();
+ args.push_back(Variant(Vector3(19.99, 1.00, -2.05)));
+ output = format.sprintf(args, &error);
+ REQUIRE(error == false);
+ CHECK(output == String("fish (19.990000 , 1.000000 , -2.050000 ) frog"));
+
+ // Vector left-padded with zeros.
+ format = "fish %011v frog";
+ args.clear();
+ args.push_back(Variant(Vector3(19.99, 1.00, -2.05)));
+ output = format.sprintf(args, &error);
+ REQUIRE(error == false);
+ CHECK(output == String("fish (0019.990000, 0001.000000, -002.050000) frog"));
+
+ // Vector given Vector3i.
+ format = "fish %v frog";
+ args.clear();
+ args.push_back(Variant(Vector3i(19, 1, -2)));
+ output = format.sprintf(args, &error);
+ REQUIRE(error == false);
+ CHECK(output == String("fish (19.000000, 1.000000, -2.000000) frog"));
+
+ // Vector with 1 decimal.
+ format = "fish %.1v frog";
+ args.clear();
+ args.push_back(Variant(Vector3(19.99, 1.00, -2.05)));
+ output = format.sprintf(args, &error);
+ REQUIRE(error == false);
+ CHECK(output == String("fish (20.0, 1.0, -2.0) frog"));
+
+ // Vector with 12 decimals.
+ format = "fish %.12v frog";
+ args.clear();
+ args.push_back(Variant(Vector3(19.00, 1.00, -2.00)));
+ output = format.sprintf(args, &error);
+ REQUIRE(error == false);
+ CHECK(output == String("fish (19.000000000000, 1.000000000000, -2.000000000000) frog"));
+
+ // Vector with no decimals.
+ format = "fish %.v frog";
+ args.clear();
+ args.push_back(Variant(Vector3(19.99, 1.00, -2.05)));
+ output = format.sprintf(args, &error);
+ REQUIRE(error == false);
+ CHECK(output == String("fish (20, 1, -2) frog"));
+
+ ///// Strings
// String
format = "fish %s frog";
@@ -795,7 +903,7 @@ TEST_CASE("[String] sprintf") {
REQUIRE(error == false);
CHECK(output == String("fish cheese frog"));
- // String left-padded
+ // String left-padded.
format = "fish %10s frog";
args.clear();
args.push_back("cheese");
@@ -803,7 +911,7 @@ TEST_CASE("[String] sprintf") {
REQUIRE(error == false);
CHECK(output == String("fish cheese frog"));
- // String right-padded
+ // String right-padded.
format = "fish %-10s frog";
args.clear();
args.push_back("cheese");
@@ -831,7 +939,7 @@ TEST_CASE("[String] sprintf") {
///// Dynamic width
- // String dynamic width
+ // String dynamic width.
format = "fish %*s frog";
args.clear();
args.push_back(10);
@@ -840,7 +948,7 @@ TEST_CASE("[String] sprintf") {
REQUIRE(error == false);
REQUIRE(output == String("fish cheese frog"));
- // Int dynamic width
+ // Int dynamic width.
format = "fish %*d frog";
args.clear();
args.push_back(10);
@@ -849,7 +957,7 @@ TEST_CASE("[String] sprintf") {
REQUIRE(error == false);
REQUIRE(output == String("fish 99 frog"));
- // Float dynamic width
+ // Float dynamic width.
format = "fish %*.*f frog";
args.clear();
args.push_back(10);
@@ -886,7 +994,7 @@ TEST_CASE("[String] sprintf") {
REQUIRE(error);
CHECK(output == "incomplete format");
- // Bad character in format string
+ // Bad character in format string.
format = "fish %&f frog";
args.clear();
args.push_back("cheese");
@@ -902,14 +1010,14 @@ TEST_CASE("[String] sprintf") {
REQUIRE(error);
CHECK(output == "too many decimal points in format");
- // * not a number
+ // * not a number or vector.
format = "fish %*f frog";
args.clear();
args.push_back("cheese");
args.push_back(99.99);
output = format.sprintf(args, &error);
REQUIRE(error);
- CHECK(output == "* wants number");
+ CHECK(output == "* wants number or vector");
// Character too long.
format = "fish %c frog";
@@ -1251,7 +1359,7 @@ TEST_CASE("[String] Path functions") {
CHECK(String(path[i]).get_file() == file[i]);
CHECK(String(path[i]).is_absolute_path() == abs[i]);
CHECK(String(path[i]).is_relative_path() != abs[i]);
- CHECK(String(path[i]).simplify_path().get_base_dir().plus_file(file[i]) == String(path[i]).simplify_path());
+ CHECK(String(path[i]).simplify_path().get_base_dir().path_join(file[i]) == String(path[i]).simplify_path());
}
static const char *file_name[3] = { "test.tscn", "test://.xscn", "?tes*t.scn" };
diff --git a/tests/core/templates/test_hash_set.h b/tests/core/templates/test_hash_set.h
index 3b9a800641..dad149604b 100644
--- a/tests/core/templates/test_hash_set.h
+++ b/tests/core/templates/test_hash_set.h
@@ -38,7 +38,6 @@
namespace TestHashSet {
TEST_CASE("[HashSet] Insert element") {
- print_line("SMALL BEGIN MEM: ", Memory::get_mem_usage());
HashSet<int> set;
HashSet<int>::Iterator e = set.insert(42);
@@ -47,7 +46,6 @@ TEST_CASE("[HashSet] Insert element") {
CHECK(set.has(42));
CHECK(set.find(42));
set.reset();
- print_line("SMALL END MEM: ", Memory::get_mem_usage());
}
TEST_CASE("[HashSet] Insert existing element") {
diff --git a/modules/websocket/emws_server.cpp b/tests/core/templates/test_rid.h
index 2033098cad..8d4dd0703b 100644
--- a/modules/websocket/emws_server.cpp
+++ b/tests/core/templates/test_rid.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* emws_server.cpp */
+/* test_rid.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,65 +28,74 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifdef JAVASCRIPT_ENABLED
+#ifndef TEST_RID_H
+#define TEST_RID_H
-#include "emws_server.h"
-#include "core/os/os.h"
+#include "core/templates/rid.h"
-void EMWSServer::set_extra_headers(const Vector<String> &p_headers) {
-}
+#include "tests/test_macros.h"
-Error EMWSServer::listen(int p_port, Vector<String> p_protocols, bool gd_mp_api) {
- return FAILED;
-}
+namespace TestRID {
+TEST_CASE("[RID] Default Constructor") {
+ RID rid;
-bool EMWSServer::is_listening() const {
- return false;
+ CHECK(rid.get_id() == 0);
}
-void EMWSServer::stop() {
-}
+TEST_CASE("[RID] Factory method") {
+ RID rid = RID::from_uint64(1);
-bool EMWSServer::has_peer(int p_id) const {
- return false;
+ CHECK(rid.get_id() == 1);
}
-Ref<WebSocketPeer> EMWSServer::get_peer(int p_id) const {
- return nullptr;
-}
+TEST_CASE("[RID] Operators") {
+ RID rid = RID::from_uint64(1);
-Vector<String> EMWSServer::get_protocols() const {
- Vector<String> out;
+ RID rid_zero = RID::from_uint64(0);
+ RID rid_one = RID::from_uint64(1);
+ RID rid_two = RID::from_uint64(2);
- return out;
-}
+ CHECK_FALSE(rid == rid_zero);
+ CHECK(rid == rid_one);
+ CHECK_FALSE(rid == rid_two);
-IPAddress EMWSServer::get_peer_address(int p_peer_id) const {
- return IPAddress();
-}
+ CHECK_FALSE(rid < rid_zero);
+ CHECK_FALSE(rid < rid_one);
+ CHECK(rid < rid_two);
-int EMWSServer::get_peer_port(int p_peer_id) const {
- return 0;
-}
+ CHECK_FALSE(rid <= rid_zero);
+ CHECK(rid <= rid_one);
+ CHECK(rid <= rid_two);
-void EMWSServer::disconnect_peer(int p_peer_id, int p_code, String p_reason) {
-}
+ CHECK(rid > rid_zero);
+ CHECK_FALSE(rid > rid_one);
+ CHECK_FALSE(rid > rid_two);
-void EMWSServer::poll() {
-}
+ CHECK(rid >= rid_zero);
+ CHECK(rid >= rid_one);
+ CHECK_FALSE(rid >= rid_two);
-int EMWSServer::get_max_packet_size() const {
- return 0;
+ CHECK(rid != rid_zero);
+ CHECK_FALSE(rid != rid_one);
+ CHECK(rid != rid_two);
}
-Error EMWSServer::set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) {
- return OK;
-}
+TEST_CASE("[RID] 'is_valid' & 'is_null'") {
+ RID rid_zero = RID::from_uint64(0);
+ RID rid_one = RID::from_uint64(1);
+
+ CHECK_FALSE(rid_zero.is_valid());
+ CHECK(rid_zero.is_null());
-EMWSServer::EMWSServer() {
+ CHECK(rid_one.is_valid());
+ CHECK_FALSE(rid_one.is_null());
}
-EMWSServer::~EMWSServer() {
+TEST_CASE("[RID] 'get_local_index'") {
+ CHECK(RID::from_uint64(1).get_local_index() == 1);
+ CHECK(RID::from_uint64(4'294'967'295).get_local_index() == 4'294'967'295);
+ CHECK(RID::from_uint64(4'294'967'297).get_local_index() == 1);
}
+} // namespace TestRID
-#endif // JAVASCRIPT_ENABLED
+#endif // TEST_RID_H
diff --git a/tests/core/templates/test_vector.h b/tests/core/templates/test_vector.h
index f27d6a332e..3fc9264f5a 100644
--- a/tests/core/templates/test_vector.h
+++ b/tests/core/templates/test_vector.h
@@ -291,8 +291,10 @@ TEST_CASE("[Vector] Slice") {
CHECK(slice6[1] == 3);
CHECK(slice6[2] == 4);
+ ERR_PRINT_OFF;
Vector<int> slice7 = vector.slice(5, 1);
- CHECK(slice7.size() == 0);
+ CHECK(slice7.size() == 0); // Expected to fail.
+ ERR_PRINT_ON;
}
TEST_CASE("[Vector] Find, has") {
diff --git a/tests/core/variant/test_variant.h b/tests/core/variant/test_variant.h
index 916686d7c1..d6799928b4 100644
--- a/tests/core/variant/test_variant.h
+++ b/tests/core/variant/test_variant.h
@@ -719,6 +719,7 @@ TEST_CASE("[Variant] Assignment To Color from Bool,Int,Float,String,Vec2,Vec2i,V
vec3i_v = col_v;
CHECK(vec3i_v.get_type() == Variant::COLOR);
}
+
TEST_CASE("[Variant] Writer and parser array") {
Array a = build_array(1, String("hello"), build_array(Variant()));
String a_str;
@@ -911,6 +912,67 @@ TEST_CASE("[Variant] Nested dictionary comparison") {
CHECK_FALSE(v_d1 == v_d_other_val);
}
+struct ArgumentData {
+ Variant::Type type;
+ String name;
+ bool has_defval = false;
+ Variant defval;
+ int position;
+};
+
+struct MethodData {
+ StringName name;
+ Variant::Type return_type;
+ List<ArgumentData> arguments;
+ bool is_virtual = false;
+ bool is_vararg = false;
+};
+
+TEST_CASE("[Variant] Utility functions") {
+ List<MethodData> functions;
+
+ List<StringName> function_names;
+ Variant::get_utility_function_list(&function_names);
+ function_names.sort_custom<StringName::AlphCompare>();
+
+ for (const StringName &E : function_names) {
+ MethodData md;
+ md.name = E;
+
+ // Utility function's return type.
+ if (Variant::has_utility_function_return_value(E)) {
+ md.return_type = Variant::get_utility_function_return_type(E);
+ }
+
+ // Utility function's arguments.
+ if (Variant::is_utility_function_vararg(E)) {
+ md.is_vararg = true;
+ } else {
+ for (int i = 0; i < Variant::get_utility_function_argument_count(E); i++) {
+ ArgumentData arg;
+ arg.type = Variant::get_utility_function_argument_type(E, i);
+ arg.name = Variant::get_utility_function_argument_name(E, i);
+ arg.position = i;
+
+ md.arguments.push_back(arg);
+ }
+ }
+
+ functions.push_back(md);
+ }
+
+ SUBCASE("[Variant] Validate utility functions") {
+ for (const MethodData &E : functions) {
+ for (const ArgumentData &F : E.arguments) {
+ const ArgumentData &arg = F;
+
+ TEST_COND((arg.name.is_empty() || arg.name.begins_with("_unnamed_arg")),
+ vformat("Unnamed argument in position %d of function '%s'.", arg.position, E.name));
+ }
+ }
+ }
+}
+
} // namespace TestVariant
#endif // TEST_VARIANT_H
diff --git a/tests/create_test.py b/tests/create_test.py
new file mode 100644
index 0000000000..5a0439084f
--- /dev/null
+++ b/tests/create_test.py
@@ -0,0 +1,132 @@
+#!/usr/bin/env python3
+
+import argparse
+import os
+import re
+import sys
+from subprocess import call
+
+
+def main():
+ # Change to the directory where the script is located,
+ # so that the script can be run from any location.
+ os.chdir(os.path.dirname(os.path.realpath(__file__)))
+
+ parser = argparse.ArgumentParser(description="Creates a new unit test file.")
+ parser.add_argument("name", type=str, help="The unit test name in PascalCase notation")
+ parser.add_argument(
+ "path",
+ type=str,
+ nargs="?",
+ help="The path to the unit test file relative to the tests folder (default: .)",
+ default=".",
+ )
+ parser.add_argument(
+ "-i",
+ "--invasive",
+ action="store_true",
+ help="if set, the script will automatically insert the include directive in test_main.cpp. Use with caution!",
+ )
+ args = parser.parse_args()
+
+ snake_case_regex = re.compile(r"(?<!^)(?=[A-Z])")
+ name_snake_case = snake_case_regex.sub("_", args.name).lower()
+
+ file_path = os.path.normpath(os.path.join(args.path, f"test_{name_snake_case}.h"))
+
+ print(file_path)
+ if os.path.isfile(file_path):
+ print(f'ERROR: The file "{file_path}" already exists.')
+ sys.exit(1)
+ with open(file_path, "w") as file:
+ file.write(
+ """/*************************************************************************/
+/* test_{name_snake_case}.h {padding} */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_{name_upper_snake_case}_H
+#define TEST_{name_upper_snake_case}_H
+
+#include "tests/test_macros.h"
+
+namespace Test{name_pascal_case} {{
+
+TEST_CASE("[{name_pascal_case}] Example test case") {{
+ // TODO: Remove this comment and write your test code here.
+}}
+
+}} // namespace Test{name_pascal_case}
+
+#endif // TEST_{name_upper_snake_case}_H
+""".format(
+ name_snake_case=name_snake_case,
+ # Capitalize the first letter but keep capitalization for the rest of the string.
+ # This is done in case the user passes a camelCase string instead of PascalCase.
+ name_pascal_case=args.name[0].upper() + args.name[1:],
+ name_upper_snake_case=name_snake_case.upper(),
+ # The padding length depends on the test name length.
+ padding=" " * (60 - len(name_snake_case)),
+ )
+ )
+
+ # Print an absolute path so it can be Ctrl + clicked in some IDEs and terminal emulators.
+ print("Test header file created:")
+ print(os.path.abspath(file_path))
+
+ if args.invasive:
+ print("Trying to insert include directive in test_main.cpp...")
+ with open("test_main.cpp", "r") as file:
+ contents = file.read()
+ match = re.search(r'#include "tests.*\n', contents)
+
+ if match:
+ new_string = contents[: match.start()] + f'#include "tests/{file_path}"\n' + contents[match.start() :]
+
+ with open("test_main.cpp", "w") as file:
+ file.write(new_string)
+ print("Done.")
+ # Use clang format to sort include directives afster insertion.
+ clang_format_args = ["clang-format", "test_main.cpp", "-i"]
+ retcode = call(clang_format_args)
+ if retcode != 0:
+ print(
+ "Include directives in test_main.cpp could not be sorted automatically using clang-format. Please sort them manually."
+ )
+ else:
+ print("Could not find a valid position in test_main.cpp to insert the include directive.")
+
+ else:
+ print("\nRemember to #include the new test header in this file (following alphabetical order):")
+ print(os.path.abspath("test_main.cpp"))
+ print("Insert the following line in the appropriate place:")
+ print(f'#include "tests/{file_path}"')
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/data/line_endings_cr.test.txt b/tests/data/line_endings_cr.test.txt
new file mode 100644
index 0000000000..556154bb25
--- /dev/null
+++ b/tests/data/line_endings_cr.test.txt
@@ -0,0 +1 @@
+Hello darkness My old friend I've come to talk With you again \ No newline at end of file
diff --git a/tests/data/line_endings_crlf.test.txt b/tests/data/line_endings_crlf.test.txt
new file mode 100644
index 0000000000..a3cbe55b7f
--- /dev/null
+++ b/tests/data/line_endings_crlf.test.txt
@@ -0,0 +1,4 @@
+Hello darkness
+My old friend
+I've come to talk
+With you again
diff --git a/tests/data/line_endings_lf.test.txt b/tests/data/line_endings_lf.test.txt
new file mode 100644
index 0000000000..0aabcd911e
--- /dev/null
+++ b/tests/data/line_endings_lf.test.txt
@@ -0,0 +1,4 @@
+Hello darkness
+My old friend
+I've come to talk
+With you again
diff --git a/tests/python_build/conftest.py b/tests/python_build/conftest.py
new file mode 100644
index 0000000000..617230926a
--- /dev/null
+++ b/tests/python_build/conftest.py
@@ -0,0 +1,26 @@
+import os
+import sys
+from pathlib import Path
+
+import pytest
+
+CWD = Path(__file__).parent
+ROOT = CWD.parent.parent
+# append directory with build files to sys.path to import them
+sys.path.append(str(ROOT))
+
+
+@pytest.fixture
+def shader_files(request):
+ shader_path = request.param
+
+ res = {
+ "path_input": str(CWD / "fixtures" / f"{shader_path}.glsl"),
+ "path_output": str(CWD / "fixtures" / f"{shader_path}.glsl.gen.h"),
+ "path_expected_full": str(CWD / "fixtures" / f"{shader_path}_expected_full.glsl"),
+ "path_expected_parts": str(CWD / "fixtures" / f"{shader_path}_expected_parts.json"),
+ }
+ yield res
+
+ if not os.getenv("PYTEST_KEEP_GENERATED_FILES"):
+ os.remove(res["path_output"])
diff --git a/tests/python_build/fixtures/gles3/_included.glsl b/tests/python_build/fixtures/gles3/_included.glsl
new file mode 100644
index 0000000000..adf5f702d3
--- /dev/null
+++ b/tests/python_build/fixtures/gles3/_included.glsl
@@ -0,0 +1 @@
+#define M_PI 3.14159265359
diff --git a/tests/python_build/fixtures/gles3/vertex_fragment.glsl b/tests/python_build/fixtures/gles3/vertex_fragment.glsl
new file mode 100644
index 0000000000..3004e22f25
--- /dev/null
+++ b/tests/python_build/fixtures/gles3/vertex_fragment.glsl
@@ -0,0 +1,34 @@
+#include "_included.glsl"
+
+#[modes]
+
+mode_ninepatch = #define USE_NINEPATCH
+
+#[specializations]
+
+DISABLE_LIGHTING = false
+
+#[vertex]
+
+precision highp float;
+precision highp int;
+
+layout(location = 0) in highp vec3 vertex;
+
+out highp vec4 position_interp;
+
+void main() {
+ position_interp = vec4(vertex.x,1,0,1);
+}
+
+#[fragment]
+
+precision highp float;
+precision highp int;
+
+in highp vec4 position_interp;
+
+void main() {
+ highp float depth = ((position_interp.z / position_interp.w) + 1.0);
+ frag_color = vec4(depth);
+}
diff --git a/tests/python_build/fixtures/gles3/vertex_fragment_expected_full.glsl b/tests/python_build/fixtures/gles3/vertex_fragment_expected_full.glsl
new file mode 100644
index 0000000000..7bf56e73cd
--- /dev/null
+++ b/tests/python_build/fixtures/gles3/vertex_fragment_expected_full.glsl
@@ -0,0 +1,50 @@
+/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */
+#ifndef VERTEX_FRAGMENT_GLSL_GEN_HGLES3_GLES3
+#define VERTEX_FRAGMENT_GLSL_GEN_HGLES3_GLES3
+
+
+#include "drivers/gles3/shader_gles3.h"
+
+
+class VertexFragmentShaderGLES3 : public ShaderGLES3 {
+
+public:
+
+ enum ShaderVariant {
+ MODE_NINEPATCH,
+ };
+
+ enum Specializations {
+ DISABLE_LIGHTING=1,
+ };
+
+ _FORCE_INLINE_ void version_bind_shader(RID p_version,ShaderVariant p_variant,uint64_t p_specialization=0) { _version_bind_shader(p_version,p_variant,p_specialization); }
+
+protected:
+
+ virtual void _init() override {
+
+ static const char **_uniform_strings=nullptr;
+ static const char* _variant_defines[]={
+ "#define USE_NINEPATCH",
+ };
+
+ static TexUnitPair *_texunit_pairs=nullptr;
+ static UBOPair *_ubo_pairs=nullptr;
+ static Specialization _spec_pairs[]={
+ {"DISABLE_LIGHTING",false},
+ };
+
+ static const char _vertex_code[]={
+10,112,114,101,99,105,115,105,111,110,32,104,105,103,104,112,32,102,108,111,97,116,59,10,112,114,101,99,105,115,105,111,110,32,104,105,103,104,112,32,105,110,116,59,10,10,108,97,121,111,117,116,40,108,111,99,97,116,105,111,110,32,61,32,48,41,32,105,110,32,104,105,103,104,112,32,118,101,99,51,32,118,101,114,116,101,120,59,10,10,111,117,116,32,104,105,103,104,112,32,118,101,99,52,32,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,32,61,32,118,101,99,52,40,118,101,114,116,101,120,46,120,44,49,44,48,44,49,41,59,10,125,10,10, 0};
+
+ static const char _fragment_code[]={
+10,112,114,101,99,105,115,105,111,110,32,104,105,103,104,112,32,102,108,111,97,116,59,10,112,114,101,99,105,115,105,111,110,32,104,105,103,104,112,32,105,110,116,59,10,10,105,110,32,104,105,103,104,112,32,118,101,99,52,32,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,104,105,103,104,112,32,102,108,111,97,116,32,100,101,112,116,104,32,61,32,40,40,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,46,122,32,47,32,112,111,115,105,116,105,111,110,95,105,110,116,101,114,112,46,119,41,32,43,32,49,46,48,41,59,10,9,102,114,97,103,95,99,111,108,111,114,32,61,32,118,101,99,52,40,100,101,112,116,104,41,59,10,125,10, 0};
+
+ _setup(_vertex_code,_fragment_code,"VertexFragmentShaderGLES3",0,_uniform_strings,0,_ubo_pairs,0,_texunit_pairs,1,_spec_pairs,1,_variant_defines);
+ }
+
+};
+
+#endif
+
diff --git a/tests/python_build/fixtures/gles3/vertex_fragment_expected_parts.json b/tests/python_build/fixtures/gles3/vertex_fragment_expected_parts.json
new file mode 100644
index 0000000000..eaeb5981c0
--- /dev/null
+++ b/tests/python_build/fixtures/gles3/vertex_fragment_expected_parts.json
@@ -0,0 +1,52 @@
+{
+ "vertex_lines": [
+ "",
+ "precision highp float;",
+ "precision highp int;",
+ "",
+ "layout(location = 0) in highp vec3 vertex;",
+ "",
+ "out highp vec4 position_interp;",
+ "",
+ "void main() {",
+ "\tposition_interp = vec4(vertex.x,1,0,1);",
+ "}",
+ ""
+ ],
+ "fragment_lines": [
+ "",
+ "precision highp float;",
+ "precision highp int;",
+ "",
+ "in highp vec4 position_interp;",
+ "",
+ "void main() {",
+ "\thighp float depth = ((position_interp.z / position_interp.w) + 1.0);",
+ "\tfrag_color = vec4(depth);",
+ "}"
+ ],
+ "uniforms": [],
+ "fbos": [],
+ "texunits": [],
+ "texunit_names": [],
+ "ubos": [],
+ "ubo_names": [],
+ "vertex_included_files": [],
+ "fragment_included_files": [],
+ "reading": "fragment",
+ "line_offset": 33,
+ "vertex_offset": 10,
+ "fragment_offset": 23,
+ "variant_defines": [
+ "#define USE_NINEPATCH"
+ ],
+ "variant_names": [
+ "MODE_NINEPATCH"
+ ],
+ "specialization_names": [
+ "DISABLE_LIGHTING"
+ ],
+ "specialization_values": [
+ " false\n"
+ ]
+}
diff --git a/tests/python_build/fixtures/glsl/_included.glsl b/tests/python_build/fixtures/glsl/_included.glsl
new file mode 100644
index 0000000000..adf5f702d3
--- /dev/null
+++ b/tests/python_build/fixtures/glsl/_included.glsl
@@ -0,0 +1 @@
+#define M_PI 3.14159265359
diff --git a/tests/python_build/fixtures/glsl/compute.glsl b/tests/python_build/fixtures/glsl/compute.glsl
new file mode 100644
index 0000000000..e81f48d463
--- /dev/null
+++ b/tests/python_build/fixtures/glsl/compute.glsl
@@ -0,0 +1,12 @@
+#[compute]
+
+#version 450
+
+#VERSION_DEFINES
+
+
+#include "_included.glsl"
+
+void main() {
+ vec3 static_light = vec3(0, 1, 0);
+}
diff --git a/tests/python_build/fixtures/glsl/compute_expected_full.glsl b/tests/python_build/fixtures/glsl/compute_expected_full.glsl
new file mode 100644
index 0000000000..b937d732c8
--- /dev/null
+++ b/tests/python_build/fixtures/glsl/compute_expected_full.glsl
@@ -0,0 +1,8 @@
+/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */
+#ifndef COMPUTE_SHADER_GLSL_RAW_H
+#define COMPUTE_SHADER_GLSL_RAW_H
+
+static const char compute_shader_glsl[] = {
+ 35,91,99,111,109,112,117,116,101,93,10,10,35,118,101,114,115,105,111,110,32,52,53,48,10,10,35,86,69,82,83,73,79,78,95,68,69,70,73,78,69,83,10,10,10,35,100,101,102,105,110,101,32,77,95,80,73,32,51,46,49,52,49,53,57,50,54,53,51,53,57,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,118,101,99,51,32,115,116,97,116,105,99,95,108,105,103,104,116,32,61,32,118,101,99,51,40,48,44,32,49,44,32,48,41,59,10,125,10,0
+};
+#endif
diff --git a/tests/python_build/fixtures/glsl/compute_expected_parts.json b/tests/python_build/fixtures/glsl/compute_expected_parts.json
new file mode 100644
index 0000000000..025c568ae0
--- /dev/null
+++ b/tests/python_build/fixtures/glsl/compute_expected_parts.json
@@ -0,0 +1,3 @@
+{
+ "code": "#[compute]\n\n#version 450\n\n#VERSION_DEFINES\n\n\n#define M_PI 3.14159265359\n\nvoid main() {\n\tvec3 static_light = vec3(0, 1, 0);\n}\n"
+}
diff --git a/tests/python_build/fixtures/glsl/vertex_fragment.glsl b/tests/python_build/fixtures/glsl/vertex_fragment.glsl
new file mode 100644
index 0000000000..0bdce783d7
--- /dev/null
+++ b/tests/python_build/fixtures/glsl/vertex_fragment.glsl
@@ -0,0 +1,32 @@
+#[versions]
+
+lines = "#define MODE_LINES";
+
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+layout(location = 0) out vec3 uv_interp;
+
+void main() {
+
+#ifdef MODE_LINES
+ uv_interp = vec3(0,0,1);
+#endif
+}
+
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "_included.glsl"
+
+layout(location = 0) out vec4 dst_color;
+
+void main() {
+ dst_color = vec4(1,1,0,0);
+}
diff --git a/tests/python_build/fixtures/glsl/vertex_fragment_expected_full.glsl b/tests/python_build/fixtures/glsl/vertex_fragment_expected_full.glsl
new file mode 100644
index 0000000000..3f53a17fac
--- /dev/null
+++ b/tests/python_build/fixtures/glsl/vertex_fragment_expected_full.glsl
@@ -0,0 +1,8 @@
+/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */
+#ifndef VERTEX_FRAGMENT_SHADER_GLSL_RAW_H
+#define VERTEX_FRAGMENT_SHADER_GLSL_RAW_H
+
+static const char vertex_fragment_shader_glsl[] = {
+ 35,91,118,101,114,115,105,111,110,115,93,10,10,108,105,110,101,115,32,61,32,34,35,100,101,102,105,110,101,32,77,79,68,69,95,76,73,78,69,83,34,59,10,10,35,91,118,101,114,116,101,120,93,10,10,35,118,101,114,115,105,111,110,32,52,53,48,10,10,35,86,69,82,83,73,79,78,95,68,69,70,73,78,69,83,10,10,108,97,121,111,117,116,40,108,111,99,97,116,105,111,110,32,61,32,48,41,32,111,117,116,32,118,101,99,51,32,117,118,95,105,110,116,101,114,112,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,10,35,105,102,100,101,102,32,77,79,68,69,95,76,73,78,69,83,10,9,117,118,95,105,110,116,101,114,112,32,61,32,118,101,99,51,40,48,44,48,44,49,41,59,10,35,101,110,100,105,102,10,125,10,10,35,91,102,114,97,103,109,101,110,116,93,10,10,35,118,101,114,115,105,111,110,32,52,53,48,10,10,35,86,69,82,83,73,79,78,95,68,69,70,73,78,69,83,10,10,35,100,101,102,105,110,101,32,77,95,80,73,32,51,46,49,52,49,53,57,50,54,53,51,53,57,10,10,108,97,121,111,117,116,40,108,111,99,97,116,105,111,110,32,61,32,48,41,32,111,117,116,32,118,101,99,52,32,100,115,116,95,99,111,108,111,114,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,100,115,116,95,99,111,108,111,114,32,61,32,118,101,99,52,40,49,44,49,44,48,44,48,41,59,10,125,10,0
+};
+#endif
diff --git a/tests/python_build/fixtures/glsl/vertex_fragment_expected_parts.json b/tests/python_build/fixtures/glsl/vertex_fragment_expected_parts.json
new file mode 100644
index 0000000000..38312367a0
--- /dev/null
+++ b/tests/python_build/fixtures/glsl/vertex_fragment_expected_parts.json
@@ -0,0 +1,3 @@
+{
+ "code": "#[versions]\n\nlines = \"#define MODE_LINES\";\n\n#[vertex]\n\n#version 450\n\n#VERSION_DEFINES\n\nlayout(location = 0) out vec3 uv_interp;\n\nvoid main() {\n\n#ifdef MODE_LINES\n\tuv_interp = vec3(0,0,1);\n#endif\n}\n\n#[fragment]\n\n#version 450\n\n#VERSION_DEFINES\n\n#define M_PI 3.14159265359\n\nlayout(location = 0) out vec4 dst_color;\n\nvoid main() {\n\tdst_color = vec4(1,1,0,0);\n}\n"
+}
diff --git a/tests/python_build/fixtures/rd_glsl/_included.glsl b/tests/python_build/fixtures/rd_glsl/_included.glsl
new file mode 100644
index 0000000000..adf5f702d3
--- /dev/null
+++ b/tests/python_build/fixtures/rd_glsl/_included.glsl
@@ -0,0 +1 @@
+#define M_PI 3.14159265359
diff --git a/tests/python_build/fixtures/rd_glsl/compute.glsl b/tests/python_build/fixtures/rd_glsl/compute.glsl
new file mode 100644
index 0000000000..66fbbeb401
--- /dev/null
+++ b/tests/python_build/fixtures/rd_glsl/compute.glsl
@@ -0,0 +1,13 @@
+#[compute]
+
+#version 450
+
+#VERSION_DEFINES
+
+#define BLOCK_SIZE 8
+
+#include "_included.glsl"
+
+void main() {
+ uint t = BLOCK_SIZE + 1;
+}
diff --git a/tests/python_build/fixtures/rd_glsl/compute_expected_full.glsl b/tests/python_build/fixtures/rd_glsl/compute_expected_full.glsl
new file mode 100644
index 0000000000..b59923e28a
--- /dev/null
+++ b/tests/python_build/fixtures/rd_glsl/compute_expected_full.glsl
@@ -0,0 +1,20 @@
+/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */
+#ifndef COMPUTE_GLSL_GEN_H_RD
+#define COMPUTE_GLSL_GEN_H_RD
+
+#include "servers/rendering/renderer_rd/shader_rd.h"
+
+class ComputeShaderRD : public ShaderRD {
+
+public:
+
+ ComputeShaderRD() {
+
+ static const char _compute_code[] = {
+10,35,118,101,114,115,105,111,110,32,52,53,48,10,10,35,86,69,82,83,73,79,78,95,68,69,70,73,78,69,83,10,10,35,100,101,102,105,110,101,32,66,76,79,67,75,95,83,73,90,69,32,56,10,10,35,100,101,102,105,110,101,32,77,95,80,73,32,51,46,49,52,49,53,57,50,54,53,51,53,57,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,117,105,110,116,32,116,32,61,32,66,76,79,67,75,95,83,73,90,69,32,43,32,49,59,10,125,10,0
+ };
+ setup(nullptr, nullptr, _compute_code, "ComputeShaderRD");
+ }
+};
+
+#endif
diff --git a/tests/python_build/fixtures/rd_glsl/compute_expected_parts.json b/tests/python_build/fixtures/rd_glsl/compute_expected_parts.json
new file mode 100644
index 0000000000..26ba9e4fc4
--- /dev/null
+++ b/tests/python_build/fixtures/rd_glsl/compute_expected_parts.json
@@ -0,0 +1,28 @@
+{
+ "vertex_lines": [],
+ "fragment_lines": [],
+ "compute_lines": [
+ "",
+ "#version 450",
+ "",
+ "#VERSION_DEFINES",
+ "",
+ "#define BLOCK_SIZE 8",
+ "",
+ "#define M_PI 3.14159265359",
+ "",
+ "void main() {",
+ "\tuint t = BLOCK_SIZE + 1;",
+ "}"
+ ],
+ "vertex_included_files": [],
+ "fragment_included_files": [],
+ "compute_included_files": [
+ "tests/python_build/fixtures/rd_glsl/_included.glsl"
+ ],
+ "reading": "compute",
+ "line_offset": 13,
+ "vertex_offset": 0,
+ "fragment_offset": 0,
+ "compute_offset": 1
+}
diff --git a/tests/python_build/fixtures/rd_glsl/vertex_fragment.glsl b/tests/python_build/fixtures/rd_glsl/vertex_fragment.glsl
new file mode 100644
index 0000000000..27be08a857
--- /dev/null
+++ b/tests/python_build/fixtures/rd_glsl/vertex_fragment.glsl
@@ -0,0 +1,25 @@
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "_included.glsl"
+
+layout(location = 0) out vec2 uv_interp;
+
+void main() {
+ uv_interp = vec2(0, 1);
+}
+
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+layout(location = 0) in vec2 uv_interp;
+
+void main() {
+ uv_interp = vec2(1, 0);
+}
diff --git a/tests/python_build/fixtures/rd_glsl/vertex_fragment_expected_full.glsl b/tests/python_build/fixtures/rd_glsl/vertex_fragment_expected_full.glsl
new file mode 100644
index 0000000000..ff804dbf89
--- /dev/null
+++ b/tests/python_build/fixtures/rd_glsl/vertex_fragment_expected_full.glsl
@@ -0,0 +1,23 @@
+/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */
+#ifndef VERTEX_FRAGMENT_GLSL_GEN_H_RD
+#define VERTEX_FRAGMENT_GLSL_GEN_H_RD
+
+#include "servers/rendering/renderer_rd/shader_rd.h"
+
+class VertexFragmentShaderRD : public ShaderRD {
+
+public:
+
+ VertexFragmentShaderRD() {
+
+ static const char _vertex_code[] = {
+10,35,118,101,114,115,105,111,110,32,52,53,48,10,10,35,86,69,82,83,73,79,78,95,68,69,70,73,78,69,83,10,10,35,100,101,102,105,110,101,32,77,95,80,73,32,51,46,49,52,49,53,57,50,54,53,51,53,57,10,10,108,97,121,111,117,116,40,108,111,99,97,116,105,111,110,32,61,32,48,41,32,111,117,116,32,118,101,99,50,32,117,118,95,105,110,116,101,114,112,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,117,118,95,105,110,116,101,114,112,32,61,32,118,101,99,50,40,48,44,32,49,41,59,10,125,10,10,0
+ };
+ static const char _fragment_code[] = {
+10,35,118,101,114,115,105,111,110,32,52,53,48,10,10,35,86,69,82,83,73,79,78,95,68,69,70,73,78,69,83,10,10,108,97,121,111,117,116,40,108,111,99,97,116,105,111,110,32,61,32,48,41,32,105,110,32,118,101,99,50,32,117,118,95,105,110,116,101,114,112,59,10,10,118,111,105,100,32,109,97,105,110,40,41,32,123,10,9,117,118,95,105,110,116,101,114,112,32,61,32,118,101,99,50,40,49,44,32,48,41,59,10,125,10,0
+ };
+ setup(_vertex_code, _fragment_code, nullptr, "VertexFragmentShaderRD");
+ }
+};
+
+#endif
diff --git a/tests/python_build/fixtures/rd_glsl/vertex_fragment_expected_parts.json b/tests/python_build/fixtures/rd_glsl/vertex_fragment_expected_parts.json
new file mode 100644
index 0000000000..dbf833edea
--- /dev/null
+++ b/tests/python_build/fixtures/rd_glsl/vertex_fragment_expected_parts.json
@@ -0,0 +1,40 @@
+{
+ "vertex_lines": [
+ "",
+ "#version 450",
+ "",
+ "#VERSION_DEFINES",
+ "",
+ "#define M_PI 3.14159265359",
+ "",
+ "layout(location = 0) out vec2 uv_interp;",
+ "",
+ "void main() {",
+ "\tuv_interp = vec2(0, 1);",
+ "}",
+ ""
+ ],
+ "fragment_lines": [
+ "",
+ "#version 450",
+ "",
+ "#VERSION_DEFINES",
+ "",
+ "layout(location = 0) in vec2 uv_interp;",
+ "",
+ "void main() {",
+ "\tuv_interp = vec2(1, 0);",
+ "}"
+ ],
+ "compute_lines": [],
+ "vertex_included_files": [
+ "tests/python_build/fixtures/rd_glsl/_included.glsl"
+ ],
+ "fragment_included_files": [],
+ "compute_included_files": [],
+ "reading": "fragment",
+ "line_offset": 25,
+ "vertex_offset": 1,
+ "fragment_offset": 15,
+ "compute_offset": 0
+}
diff --git a/tests/python_build/test_gles3_builder.py b/tests/python_build/test_gles3_builder.py
new file mode 100644
index 0000000000..861e0b84c4
--- /dev/null
+++ b/tests/python_build/test_gles3_builder.py
@@ -0,0 +1,31 @@
+import json
+
+import pytest
+
+from gles3_builders import build_gles3_header, GLES3HeaderStruct
+
+
+@pytest.mark.parametrize(
+ ["shader_files", "builder", "header_struct"],
+ [
+ ("gles3/vertex_fragment", build_gles3_header, GLES3HeaderStruct),
+ ],
+ indirect=["shader_files"],
+)
+def test_gles3_builder(shader_files, builder, header_struct):
+ header = header_struct()
+
+ builder(shader_files["path_input"], "drivers/gles3/shader_gles3.h", "GLES3", header_data=header)
+
+ with open(shader_files["path_expected_parts"], "r") as f:
+ expected_parts = json.load(f)
+ assert expected_parts == header.__dict__
+
+ with open(shader_files["path_output"], "r") as f:
+ actual_output = f.read()
+ assert actual_output
+
+ with open(shader_files["path_expected_full"], "r") as f:
+ expected_output = f.read()
+
+ assert actual_output == expected_output
diff --git a/tests/python_build/test_glsl_builder.py b/tests/python_build/test_glsl_builder.py
new file mode 100644
index 0000000000..b9dcef48ac
--- /dev/null
+++ b/tests/python_build/test_glsl_builder.py
@@ -0,0 +1,37 @@
+import json
+
+import pytest
+
+from glsl_builders import build_raw_header, RAWHeaderStruct, build_rd_header, RDHeaderStruct
+
+
+@pytest.mark.parametrize(
+ [
+ "shader_files",
+ "builder",
+ "header_struct",
+ ],
+ [
+ ("glsl/vertex_fragment", build_raw_header, RAWHeaderStruct),
+ ("glsl/compute", build_raw_header, RAWHeaderStruct),
+ ("rd_glsl/vertex_fragment", build_rd_header, RDHeaderStruct),
+ ("rd_glsl/compute", build_rd_header, RDHeaderStruct),
+ ],
+ indirect=["shader_files"],
+)
+def test_glsl_builder(shader_files, builder, header_struct):
+ header = header_struct()
+ builder(shader_files["path_input"], header_data=header)
+
+ with open(shader_files["path_expected_parts"], "r") as f:
+ expected_parts = json.load(f)
+ assert expected_parts == header.__dict__
+
+ with open(shader_files["path_output"], "r") as f:
+ actual_output = f.read()
+ assert actual_output
+
+ with open(shader_files["path_expected_full"], "r") as f:
+ expected_output = f.read()
+
+ assert actual_output == expected_output
diff --git a/tests/scene/test_audio_stream_wav.h b/tests/scene/test_audio_stream_wav.h
new file mode 100644
index 0000000000..cf369c115b
--- /dev/null
+++ b/tests/scene/test_audio_stream_wav.h
@@ -0,0 +1,243 @@
+/*************************************************************************/
+/* test_audio_stream_wav.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_AUDIO_STREAM_WAV_H
+#define TEST_AUDIO_STREAM_WAV_H
+
+#include "core/math/math_defs.h"
+#include "core/math/math_funcs.h"
+#include "scene/resources/audio_stream_wav.h"
+
+#include "tests/test_macros.h"
+
+#ifdef TOOLS_ENABLED
+#include "core/io/resource_loader.h"
+#include "editor/import/resource_importer_wav.h"
+#endif
+
+namespace TestAudioStreamWAV {
+
+// Default wav rate for test cases.
+constexpr float WAV_RATE = 44100;
+/* Default wav count for test cases. 1 second of audio is used so that the file can be listened
+to manually if needed. */
+constexpr int WAV_COUNT = WAV_RATE;
+
+float gen_wav(float frequency, float wav_rate, int wav_number) {
+ // formula for generating a sin wave with given frequency.
+ return Math::sin((Math_TAU * frequency / wav_rate) * wav_number);
+}
+
+/* Generates a 440Hz sin wave in channel 0 (mono channel or left stereo channel)
+ * and a 261.63Hz wave in channel 1 (right stereo channel).
+ * These waves correspond to the music notes A4 and C4 respectively.
+ */
+Vector<uint8_t> gen_pcm8_test(float wav_rate, int wav_count, bool stereo) {
+ Vector<uint8_t> buffer;
+ buffer.resize(stereo ? wav_count * 2 : wav_count);
+
+ uint8_t *write_ptr = buffer.ptrw();
+ for (int i = 0; i < buffer.size(); i++) {
+ float wav;
+ if (stereo) {
+ if (i % 2 == 0) {
+ wav = gen_wav(440, wav_rate, i / 2);
+ } else {
+ wav = gen_wav(261.63, wav_rate, i / 2);
+ }
+ } else {
+ wav = gen_wav(440, wav_rate, i);
+ }
+
+ // Map sin wave to full range of 8-bit values.
+ uint8_t wav_8bit = Math::fast_ftoi(((wav + 1) / 2) * UINT8_MAX);
+ // Unlike the .wav format, AudioStreamWAV expects signed 8-bit wavs.
+ uint8_t wav_8bit_signed = wav_8bit - (INT8_MAX + 1);
+ write_ptr[i] = wav_8bit_signed;
+ }
+
+ return buffer;
+}
+
+// Same as gen_pcm8_test but with 16-bit wavs.
+Vector<uint8_t> gen_pcm16_test(float wav_rate, int wav_count, bool stereo) {
+ Vector<uint8_t> buffer;
+ buffer.resize(stereo ? wav_count * 4 : wav_count * 2);
+
+ uint8_t *write_ptr = buffer.ptrw();
+ for (int i = 0; i < buffer.size() / 2; i++) {
+ float wav;
+ if (stereo) {
+ if (i % 2 == 0) {
+ wav = gen_wav(440, wav_rate, i / 2);
+ } else {
+ wav = gen_wav(261.63, wav_rate, i / 2);
+ }
+ } else {
+ wav = gen_wav(440, wav_rate, i);
+ }
+
+ // Map sin wave to full range of 16-bit values.
+ uint16_t wav_16bit = Math::fast_ftoi(((wav + 1) / 2) * UINT16_MAX);
+ // The .wav format expects wavs larger than 8 bits to be signed.
+ uint16_t wav_16bit_signed = wav_16bit - (INT16_MAX + 1);
+ encode_uint16(wav_16bit_signed, write_ptr + (i * 2));
+ }
+
+ return buffer;
+}
+
+void run_test(String file_name, AudioStreamWAV::Format data_format, bool stereo, float wav_rate, float wav_count) {
+ String save_path = OS::get_singleton()->get_cache_path().path_join(file_name);
+
+ Vector<uint8_t> test_data;
+ if (data_format == AudioStreamWAV::FORMAT_8_BITS) {
+ test_data = gen_pcm8_test(wav_rate, wav_count, stereo);
+ } else {
+ test_data = gen_pcm16_test(wav_rate, wav_count, stereo);
+ }
+
+ Ref<AudioStreamWAV> stream = memnew(AudioStreamWAV);
+ stream->set_mix_rate(wav_rate);
+ CHECK(stream->get_mix_rate() == wav_rate);
+
+ stream->set_format(data_format);
+ CHECK(stream->get_format() == data_format);
+
+ stream->set_stereo(stereo);
+ CHECK(stream->is_stereo() == stereo);
+
+ stream->set_data(test_data);
+ CHECK(stream->get_data() == test_data);
+
+ SUBCASE("Stream length is computed properly") {
+ CHECK(Math::is_equal_approx(stream->get_length(), wav_count / wav_rate));
+ }
+
+ SUBCASE("Stream can be saved as .wav") {
+ REQUIRE(stream->save_to_wav(save_path) == OK);
+
+ Error error;
+ Ref<FileAccess> wav_file = FileAccess::open(save_path, FileAccess::READ, &error);
+ REQUIRE(error == OK);
+
+#if TOOLS_ENABLED
+ // The WAV importer can be used if enabled to check that the saved file is valid.
+ Ref<ResourceImporterWAV> wav_importer = memnew(ResourceImporterWAV);
+
+ List<ResourceImporter::ImportOption> options_list;
+ wav_importer->get_import_options("", &options_list);
+
+ HashMap<StringName, Variant> options_map;
+ for (const ResourceImporter::ImportOption &E : options_list) {
+ options_map[E.option.name] = E.default_value;
+ }
+
+ REQUIRE(wav_importer->import(save_path, save_path, options_map, nullptr) == OK);
+
+ String load_path = save_path + "." + wav_importer->get_save_extension();
+ Ref<AudioStreamWAV> loaded_stream = ResourceLoader::load(load_path, "AudioStreamWAV", ResourceFormatImporter::CACHE_MODE_IGNORE, &error);
+ REQUIRE(error == OK);
+
+ CHECK(loaded_stream->get_format() == stream->get_format());
+ CHECK(loaded_stream->get_loop_mode() == stream->get_loop_mode());
+ CHECK(loaded_stream->get_loop_begin() == stream->get_loop_begin());
+ CHECK(loaded_stream->get_loop_end() == stream->get_loop_end());
+ CHECK(loaded_stream->get_mix_rate() == stream->get_mix_rate());
+ CHECK(loaded_stream->is_stereo() == stream->is_stereo());
+ CHECK(loaded_stream->get_length() == stream->get_length());
+ CHECK(loaded_stream->is_monophonic() == stream->is_monophonic());
+ CHECK(loaded_stream->get_data() == stream->get_data());
+#endif
+ }
+}
+
+TEST_CASE("[AudioStreamWAV] Mono PCM8 format") {
+ run_test("test_pcm8_mono.wav", AudioStreamWAV::FORMAT_8_BITS, false, WAV_RATE, WAV_COUNT);
+}
+
+TEST_CASE("[AudioStreamWAV] Mono PCM16 format") {
+ run_test("test_pcm16_mono.wav", AudioStreamWAV::FORMAT_16_BITS, false, WAV_RATE, WAV_COUNT);
+}
+
+TEST_CASE("[AudioStreamWAV] Stereo PCM8 format") {
+ run_test("test_pcm8_stereo.wav", AudioStreamWAV::FORMAT_8_BITS, true, WAV_RATE, WAV_COUNT);
+}
+
+TEST_CASE("[AudioStreamWAV] Stereo PCM16 format") {
+ run_test("test_pcm16_stereo.wav", AudioStreamWAV::FORMAT_16_BITS, true, WAV_RATE, WAV_COUNT);
+}
+
+TEST_CASE("[AudioStreamWAV] Alternate mix rate") {
+ run_test("test_pcm16_stereo_38000Hz.wav", AudioStreamWAV::FORMAT_16_BITS, true, 38000, 38000);
+}
+
+TEST_CASE("[AudioStreamWAV] save_to_wav() adds '.wav' file extension automatically") {
+ String save_path = OS::get_singleton()->get_cache_path().path_join("test_wav_extension");
+ Vector<uint8_t> test_data = gen_pcm8_test(WAV_RATE, WAV_COUNT, false);
+ Ref<AudioStreamWAV> stream = memnew(AudioStreamWAV);
+ stream->set_data(test_data);
+
+ REQUIRE(stream->save_to_wav(save_path) == OK);
+ Error error;
+ Ref<FileAccess> wav_file = FileAccess::open(save_path + ".wav", FileAccess::READ, &error);
+ CHECK(error == OK);
+}
+
+TEST_CASE("[AudioStreamWAV] Default values") {
+ Ref<AudioStreamWAV> stream = memnew(AudioStreamWAV);
+ CHECK(stream->get_format() == AudioStreamWAV::FORMAT_8_BITS);
+ CHECK(stream->get_loop_mode() == AudioStreamWAV::LOOP_DISABLED);
+ CHECK(stream->get_loop_begin() == 0);
+ CHECK(stream->get_loop_end() == 0);
+ CHECK(stream->get_mix_rate() == 44100);
+ CHECK(stream->is_stereo() == false);
+ CHECK(stream->get_length() == 0);
+ CHECK(stream->is_monophonic() == false);
+ CHECK(stream->get_data() == Vector<uint8_t>{});
+ CHECK(stream->get_stream_name() == "");
+}
+
+TEST_CASE("[AudioStreamWAV] Save empty file") {
+ run_test("test_empty.wav", AudioStreamWAV::FORMAT_8_BITS, false, WAV_RATE, 0);
+}
+
+TEST_CASE("[AudioStreamWAV] Saving IMA ADPCM is not supported") {
+ String save_path = OS::get_singleton()->get_cache_path().path_join("test_adpcm.wav");
+ Ref<AudioStreamWAV> stream = memnew(AudioStreamWAV);
+ stream->set_format(AudioStreamWAV::FORMAT_IMA_ADPCM);
+ ERR_PRINT_OFF;
+ CHECK(stream->save_to_wav(save_path) == ERR_UNAVAILABLE);
+ ERR_PRINT_ON;
+}
+
+} // namespace TestAudioStreamWAV
+
+#endif // TEST_AUDIO_STREAM_WAV_H
diff --git a/tests/scene/test_code_edit.h b/tests/scene/test_code_edit.h
index 7605f24cf8..4fc88f398f 100644
--- a/tests/scene/test_code_edit.h
+++ b/tests/scene/test_code_edit.h
@@ -74,7 +74,7 @@ TEST_CASE("[SceneTree][CodeEdit] line gutters") {
code_edit->set_line_as_breakpoint(0, true);
CHECK(code_edit->is_line_breakpointed(0));
- CHECK(code_edit->get_breakpointed_lines()[0] == Variant(0));
+ CHECK(code_edit->get_breakpointed_lines()[0] == 0);
SIGNAL_CHECK("breakpoint_toggled", args);
code_edit->set_line_as_breakpoint(0, false);
@@ -451,7 +451,7 @@ TEST_CASE("[SceneTree][CodeEdit] line gutters") {
ERR_PRINT_ON;
code_edit->set_line_as_bookmarked(0, true);
- CHECK(code_edit->get_bookmarked_lines()[0] == Variant(0));
+ CHECK(code_edit->get_bookmarked_lines()[0] == 0);
CHECK(code_edit->is_line_bookmarked(0));
code_edit->set_line_as_bookmarked(0, false);
@@ -657,7 +657,7 @@ TEST_CASE("[SceneTree][CodeEdit] line gutters") {
ERR_PRINT_ON;
code_edit->set_line_as_executing(0, true);
- CHECK(code_edit->get_executing_lines()[0] == Variant(0));
+ CHECK(code_edit->get_executing_lines()[0] == 0);
CHECK(code_edit->is_line_executing(0));
code_edit->set_line_as_executing(0, false);
diff --git a/tests/scene/test_path_follow_2d.h b/tests/scene/test_path_follow_2d.h
index abd12fe862..57261116a2 100644
--- a/tests/scene/test_path_follow_2d.h
+++ b/tests/scene/test_path_follow_2d.h
@@ -37,7 +37,7 @@
namespace TestPathFollow2D {
-TEST_CASE("[PathFollow2D] Sampling with unit offset") {
+TEST_CASE("[PathFollow2D] Sampling with progress ratio") {
const Ref<Curve2D> &curve = memnew(Curve2D());
curve->add_point(Vector2(0, 0));
curve->add_point(Vector2(100, 0));
@@ -49,37 +49,37 @@ TEST_CASE("[PathFollow2D] Sampling with unit offset") {
const PathFollow2D *path_follow_2d = memnew(PathFollow2D);
path->add_child(path_follow_2d);
- path_follow_2d->set_unit_offset(0);
+ path_follow_2d->set_progress_ratio(0);
CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 0)));
- path_follow_2d->set_unit_offset(0.125);
+ path_follow_2d->set_progress_ratio(0.125);
CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 0)));
- path_follow_2d->set_unit_offset(0.25);
+ path_follow_2d->set_progress_ratio(0.25);
CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 0)));
- path_follow_2d->set_unit_offset(0.375);
+ path_follow_2d->set_progress_ratio(0.375);
CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 50)));
- path_follow_2d->set_unit_offset(0.5);
+ path_follow_2d->set_progress_ratio(0.5);
CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 100)));
- path_follow_2d->set_unit_offset(0.625);
+ path_follow_2d->set_progress_ratio(0.625);
CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 100)));
- path_follow_2d->set_unit_offset(0.75);
+ path_follow_2d->set_progress_ratio(0.75);
CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 100)));
- path_follow_2d->set_unit_offset(0.875);
+ path_follow_2d->set_progress_ratio(0.875);
CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 50)));
- path_follow_2d->set_unit_offset(1);
+ path_follow_2d->set_progress_ratio(1);
CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 0)));
memdelete(path);
}
-TEST_CASE("[PathFollow2D] Sampling with offset") {
+TEST_CASE("[PathFollow2D] Sampling with progress") {
const Ref<Curve2D> &curve = memnew(Curve2D());
curve->add_point(Vector2(0, 0));
curve->add_point(Vector2(100, 0));
@@ -91,31 +91,31 @@ TEST_CASE("[PathFollow2D] Sampling with offset") {
const PathFollow2D *path_follow_2d = memnew(PathFollow2D);
path->add_child(path_follow_2d);
- path_follow_2d->set_offset(0);
+ path_follow_2d->set_progress(0);
CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 0)));
- path_follow_2d->set_offset(50);
+ path_follow_2d->set_progress(50);
CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 0)));
- path_follow_2d->set_offset(100);
+ path_follow_2d->set_progress(100);
CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 0)));
- path_follow_2d->set_offset(150);
+ path_follow_2d->set_progress(150);
CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 50)));
- path_follow_2d->set_offset(200);
+ path_follow_2d->set_progress(200);
CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 100)));
- path_follow_2d->set_offset(250);
+ path_follow_2d->set_progress(250);
CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 100)));
- path_follow_2d->set_offset(300);
+ path_follow_2d->set_progress(300);
CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 100)));
- path_follow_2d->set_offset(350);
+ path_follow_2d->set_progress(350);
CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 50)));
- path_follow_2d->set_offset(400);
+ path_follow_2d->set_progress(400);
CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(0, 0)));
memdelete(path);
@@ -131,7 +131,7 @@ TEST_CASE("[PathFollow2D] Removal of a point in curve") {
const PathFollow2D *path_follow_2d = memnew(PathFollow2D);
path->add_child(path_follow_2d);
- path_follow_2d->set_unit_offset(0.5);
+ path_follow_2d->set_progress_ratio(0.5);
CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(100, 0)));
curve->remove_point(1);
@@ -152,7 +152,7 @@ TEST_CASE("[PathFollow2D] Setting h_offset and v_offset") {
const PathFollow2D *path_follow_2d = memnew(PathFollow2D);
path->add_child(path_follow_2d);
- path_follow_2d->set_unit_offset(0.5);
+ path_follow_2d->set_progress_ratio(0.5);
CHECK(path_follow_2d->get_transform().get_origin().is_equal_approx(Vector2(50, 0)));
path_follow_2d->set_h_offset(25);
@@ -175,32 +175,32 @@ TEST_CASE("[PathFollow2D] Unit offset out of range") {
path_follow_2d->set_loop(true);
- path_follow_2d->set_unit_offset(-0.3);
+ path_follow_2d->set_progress_ratio(-0.3);
CHECK_MESSAGE(
- path_follow_2d->get_unit_offset() == 0.7,
- "Unit Offset should loop back from the end in the opposite direction");
+ path_follow_2d->get_progress_ratio() == 0.7,
+ "Progress Ratio should loop back from the end in the opposite direction");
- path_follow_2d->set_unit_offset(1.3);
+ path_follow_2d->set_progress_ratio(1.3);
CHECK_MESSAGE(
- path_follow_2d->get_unit_offset() == 0.3,
- "Unit Offset should loop back from the end in the opposite direction");
+ path_follow_2d->get_progress_ratio() == 0.3,
+ "Progress Ratio should loop back from the end in the opposite direction");
path_follow_2d->set_loop(false);
- path_follow_2d->set_unit_offset(-0.3);
+ path_follow_2d->set_progress_ratio(-0.3);
CHECK_MESSAGE(
- path_follow_2d->get_unit_offset() == 0,
- "Unit Offset should be clamped at 0");
+ path_follow_2d->get_progress_ratio() == 0,
+ "Progress Ratio should be clamped at 0");
- path_follow_2d->set_unit_offset(1.3);
+ path_follow_2d->set_progress_ratio(1.3);
CHECK_MESSAGE(
- path_follow_2d->get_unit_offset() == 1,
- "Unit Offset should be clamped at 1");
+ path_follow_2d->get_progress_ratio() == 1,
+ "Progress Ratio should be clamped at 1");
memdelete(path);
}
-TEST_CASE("[PathFollow2D] Offset out of range") {
+TEST_CASE("[PathFollow2D] Progress out of range") {
const Ref<Curve2D> &curve = memnew(Curve2D());
curve->add_point(Vector2(0, 0));
curve->add_point(Vector2(100, 0));
@@ -211,27 +211,27 @@ TEST_CASE("[PathFollow2D] Offset out of range") {
path_follow_2d->set_loop(true);
- path_follow_2d->set_offset(-50);
+ path_follow_2d->set_progress(-50);
CHECK_MESSAGE(
- path_follow_2d->get_offset() == 50,
- "Offset should loop back from the end in the opposite direction");
+ path_follow_2d->get_progress() == 50,
+ "Progress should loop back from the end in the opposite direction");
- path_follow_2d->set_offset(150);
+ path_follow_2d->set_progress(150);
CHECK_MESSAGE(
- path_follow_2d->get_offset() == 50,
- "Offset should loop back from the end in the opposite direction");
+ path_follow_2d->get_progress() == 50,
+ "Progress should loop back from the end in the opposite direction");
path_follow_2d->set_loop(false);
- path_follow_2d->set_offset(-50);
+ path_follow_2d->set_progress(-50);
CHECK_MESSAGE(
- path_follow_2d->get_offset() == 0,
- "Offset should be clamped at 0");
+ path_follow_2d->get_progress() == 0,
+ "Progress should be clamped at 0");
- path_follow_2d->set_offset(150);
+ path_follow_2d->set_progress(150);
CHECK_MESSAGE(
- path_follow_2d->get_offset() == 100,
- "Offset should be clamped at 1");
+ path_follow_2d->get_progress() == 100,
+ "Progress should be clamped at 1");
memdelete(path);
}
diff --git a/tests/scene/test_path_follow_3d.h b/tests/scene/test_path_follow_3d.h
index 9ffe49e3d6..6334fa56de 100644
--- a/tests/scene/test_path_follow_3d.h
+++ b/tests/scene/test_path_follow_3d.h
@@ -37,7 +37,7 @@
namespace TestPathFollow3D {
-TEST_CASE("[PathFollow3D] Sampling with unit offset") {
+TEST_CASE("[PathFollow3D] Sampling with progress ratio") {
const Ref<Curve3D> &curve = memnew(Curve3D());
curve->add_point(Vector3(0, 0, 0));
curve->add_point(Vector3(100, 0, 0));
@@ -49,37 +49,37 @@ TEST_CASE("[PathFollow3D] Sampling with unit offset") {
const PathFollow3D *path_follow_3d = memnew(PathFollow3D);
path->add_child(path_follow_3d);
- path_follow_3d->set_unit_offset(0);
+ path_follow_3d->set_progress_ratio(0);
CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(0, 0, 0));
- path_follow_3d->set_unit_offset(0.125);
+ path_follow_3d->set_progress_ratio(0.125);
CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(50, 0, 0));
- path_follow_3d->set_unit_offset(0.25);
+ path_follow_3d->set_progress_ratio(0.25);
CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 0, 0);
- path_follow_3d->set_unit_offset(0.375);
+ path_follow_3d->set_progress_ratio(0.375);
CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 50, 0)));
- path_follow_3d->set_unit_offset(0.5);
+ path_follow_3d->set_progress_ratio(0.5);
CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 0)));
- path_follow_3d->set_unit_offset(0.625);
+ path_follow_3d->set_progress_ratio(0.625);
CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 50)));
- path_follow_3d->set_unit_offset(0.75);
+ path_follow_3d->set_progress_ratio(0.75);
CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 100)));
- path_follow_3d->set_unit_offset(0.875);
+ path_follow_3d->set_progress_ratio(0.875);
CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 50, 100)));
- path_follow_3d->set_unit_offset(1);
+ path_follow_3d->set_progress_ratio(1);
CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 0, 100)));
memdelete(path);
}
-TEST_CASE("[PathFollow3D] Sampling with offset") {
+TEST_CASE("[PathFollow3D] Sampling with progress") {
const Ref<Curve3D> &curve = memnew(Curve3D());
curve->add_point(Vector3(0, 0, 0));
curve->add_point(Vector3(100, 0, 0));
@@ -91,31 +91,31 @@ TEST_CASE("[PathFollow3D] Sampling with offset") {
const PathFollow3D *path_follow_3d = memnew(PathFollow3D);
path->add_child(path_follow_3d);
- path_follow_3d->set_offset(0);
+ path_follow_3d->set_progress(0);
CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(0, 0, 0));
- path_follow_3d->set_offset(50);
+ path_follow_3d->set_progress(50);
CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(50, 0, 0));
- path_follow_3d->set_offset(100);
+ path_follow_3d->set_progress(100);
CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 0, 0);
- path_follow_3d->set_offset(150);
+ path_follow_3d->set_progress(150);
CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 50, 0)));
- path_follow_3d->set_offset(200);
+ path_follow_3d->set_progress(200);
CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 0)));
- path_follow_3d->set_offset(250);
+ path_follow_3d->set_progress(250);
CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 50)));
- path_follow_3d->set_offset(300);
+ path_follow_3d->set_progress(300);
CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 100, 100)));
- path_follow_3d->set_offset(350);
+ path_follow_3d->set_progress(350);
CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 50, 100)));
- path_follow_3d->set_offset(400);
+ path_follow_3d->set_progress(400);
CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector3(100, 0, 100)));
memdelete(path);
@@ -131,7 +131,7 @@ TEST_CASE("[PathFollow3D] Removal of a point in curve") {
const PathFollow3D *path_follow_3d = memnew(PathFollow3D);
path->add_child(path_follow_3d);
- path_follow_3d->set_unit_offset(0.5);
+ path_follow_3d->set_progress_ratio(0.5);
CHECK(path_follow_3d->get_transform().get_origin().is_equal_approx(Vector2(100, 0, 0)));
curve->remove_point(1);
@@ -143,7 +143,7 @@ TEST_CASE("[PathFollow3D] Removal of a point in curve") {
memdelete(path);
}
-TEST_CASE("[PathFollow3D] Unit offset out of range") {
+TEST_CASE("[PathFollow3D] Progress ratio out of range") {
const Ref<Curve3D> &curve = memnew(Curve3D());
curve->add_point(Vector3(0, 0, 0));
curve->add_point(Vector3(100, 0, 0));
@@ -154,32 +154,32 @@ TEST_CASE("[PathFollow3D] Unit offset out of range") {
path_follow_3d->set_loop(true);
- path_follow_3d->set_unit_offset(-0.3);
+ path_follow_3d->set_progress_ratio(-0.3);
CHECK_MESSAGE(
- path_follow_3d->get_unit_offset() == 0.7,
- "Unit Offset should loop back from the end in the opposite direction");
+ path_follow_3d->get_progress_ratio() == 0.7,
+ "Progress Ratio should loop back from the end in the opposite direction");
- path_follow_3d->set_unit_offset(1.3);
+ path_follow_3d->set_progress_ratio(1.3);
CHECK_MESSAGE(
- path_follow_3d->get_unit_offset() == 0.3,
- "Unit Offset should loop back from the end in the opposite direction");
+ path_follow_3d->get_progress_ratio() == 0.3,
+ "Progress Ratio should loop back from the end in the opposite direction");
path_follow_3d->set_loop(false);
- path_follow_3d->set_unit_offset(-0.3);
+ path_follow_3d->set_progress_ratio(-0.3);
CHECK_MESSAGE(
- path_follow_3d->get_unit_offset() == 0,
- "Unit Offset should be clamped at 0");
+ path_follow_3d->get_progress_ratio() == 0,
+ "Progress Ratio should be clamped at 0");
- path_follow_3d->set_unit_offset(1.3);
+ path_follow_3d->set_progress_ratio(1.3);
CHECK_MESSAGE(
- path_follow_3d->get_unit_offset() == 1,
- "Unit Offset should be clamped at 1");
+ path_follow_3d->get_progress_ratio() == 1,
+ "Progress Ratio should be clamped at 1");
memdelete(path);
}
-TEST_CASE("[PathFollow3D] Offset out of range") {
+TEST_CASE("[PathFollow3D] Progress out of range") {
const Ref<Curve3D> &curve = memnew(Curve3D());
curve->add_point(Vector3(0, 0, 0));
curve->add_point(Vector3(100, 0, 0));
@@ -190,27 +190,27 @@ TEST_CASE("[PathFollow3D] Offset out of range") {
path_follow_3d->set_loop(true);
- path_follow_3d->set_offset(-50);
+ path_follow_3d->set_progress(-50);
CHECK_MESSAGE(
- path_follow_3d->get_offset() == 50,
- "Offset should loop back from the end in the opposite direction");
+ path_follow_3d->get_progress() == 50,
+ "Progress should loop back from the end in the opposite direction");
- path_follow_3d->set_offset(150);
+ path_follow_3d->set_progress(150);
CHECK_MESSAGE(
- path_follow_3d->get_offset() == 50,
- "Offset should loop back from the end in the opposite direction");
+ path_follow_3d->get_progress() == 50,
+ "Progress should loop back from the end in the opposite direction");
path_follow_3d->set_loop(false);
- path_follow_3d->set_offset(-50);
+ path_follow_3d->set_progress(-50);
CHECK_MESSAGE(
- path_follow_3d->get_offset() == 0,
- "Offset should be clamped at 0");
+ path_follow_3d->get_progress() == 0,
+ "Progress should be clamped at 0");
- path_follow_3d->set_offset(150);
+ path_follow_3d->set_progress(150);
CHECK_MESSAGE(
- path_follow_3d->get_offset() == 100,
- "Offset should be clamped at max value of curve");
+ path_follow_3d->get_progress() == 100,
+ "Progress should be clamped at max value of curve");
memdelete(path);
}
diff --git a/tests/scene/test_sprite_frames.h b/tests/scene/test_sprite_frames.h
new file mode 100644
index 0000000000..61bbd16493
--- /dev/null
+++ b/tests/scene/test_sprite_frames.h
@@ -0,0 +1,247 @@
+/*************************************************************************/
+/* test_sprite_frames.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef TEST_SPRITE_FRAMES_H
+#define TEST_SPRITE_FRAMES_H
+
+#include "scene/resources/sprite_frames.h"
+
+#include "tests/test_macros.h"
+
+namespace TestSpriteFrames {
+const String test_animation_name = "GodotTest";
+
+TEST_CASE("[SpriteFrames] Constructor methods") {
+ const SpriteFrames frames;
+ CHECK_MESSAGE(
+ frames.get_animation_names().size() == 1,
+ "Should be initialized with 1 entry.");
+ CHECK_MESSAGE(
+ frames.get_animation_names().get(0) == "default",
+ "Should be initialized with default entry.");
+}
+
+TEST_CASE("[SpriteFrames] Animation addition, list getter, renaming, removal, and retrieval") {
+ SpriteFrames frames;
+ Vector<String> test_names = { "default", "2", "1", "3" };
+
+ // "default" is there already
+ frames.add_animation("2");
+ frames.add_animation("1");
+ frames.add_animation("3");
+
+ for (int i = 0; i < test_names.size(); i++) {
+ CHECK_MESSAGE(
+ frames.has_animation(test_names[i]),
+ "Add animation properly worked for each value");
+ }
+
+ CHECK_MESSAGE(
+ !frames.has_animation("999"),
+ "Return false when checking for animation that does not exist");
+
+ List<StringName> sname_list;
+ frames.get_animation_list(&sname_list);
+
+ CHECK_MESSAGE(
+ sname_list.size() == test_names.size(),
+ "StringName List getter returned list of expected size");
+
+ for (int i = 0; i < test_names.size(); i++) {
+ CHECK_MESSAGE(
+ sname_list[i] == StringName(test_names[i]),
+ "StringName List getter returned expected values");
+ }
+
+ // get_animation_names() sorts the results.
+ Vector<String> string_vector = frames.get_animation_names();
+ test_names.sort();
+
+ for (int i = 0; i < test_names.size(); i++) {
+ CHECK_MESSAGE(
+ string_vector[i] == test_names[i],
+ "String Vector getter returned expected values");
+ }
+
+ // These error handling cases should not crash.
+ ERR_PRINT_OFF;
+ frames.rename_animation("This does not exist", "0");
+ ERR_PRINT_ON;
+
+ CHECK_MESSAGE(
+ !frames.has_animation("0"),
+ "Correctly handles rename error when entry does not exist");
+
+ // These error handling cases should not crash.
+ ERR_PRINT_OFF;
+ frames.rename_animation("3", "1");
+ ERR_PRINT_ON;
+
+ CHECK_MESSAGE(
+ frames.has_animation("3"),
+ "Correctly handles rename error when entry exists, but new name already exists");
+
+ ERR_PRINT_OFF;
+ frames.add_animation("1");
+ ERR_PRINT_ON;
+
+ CHECK_MESSAGE(
+ frames.get_animation_names().size() == 4,
+ "Correctly does not add when entry already exists");
+
+ frames.rename_animation("3", "9");
+
+ CHECK_MESSAGE(
+ frames.has_animation("9"),
+ "Animation renamed correctly");
+
+ frames.remove_animation("9");
+
+ CHECK_MESSAGE(
+ !frames.has_animation("9"),
+ "Animation removed correctly");
+
+ frames.clear_all();
+
+ CHECK_MESSAGE(
+ frames.get_animation_names().size() == 1,
+ "Clear all removed all animations and re-added the default animation entry");
+}
+
+TEST_CASE("[SpriteFrames] Animation Speed getter and setter") {
+ SpriteFrames frames;
+
+ frames.add_animation(test_animation_name);
+
+ CHECK_MESSAGE(
+ frames.get_animation_speed(test_animation_name) == 5.0,
+ "Sets new animation to default speed");
+
+ frames.set_animation_speed(test_animation_name, 123.0004);
+
+ CHECK_MESSAGE(
+ frames.get_animation_speed(test_animation_name) == 123.0004,
+ "Sets animation to positive double");
+
+ // These error handling cases should not crash.
+ ERR_PRINT_OFF;
+ frames.get_animation_speed("This does not exist");
+ frames.set_animation_speed("This does not exist", 100);
+ frames.set_animation_speed(test_animation_name, -999.999);
+ ERR_PRINT_ON;
+
+ CHECK_MESSAGE(
+ frames.get_animation_speed(test_animation_name) == 123.0004,
+ "Prevents speed of animation being set to a negative value");
+
+ frames.set_animation_speed(test_animation_name, 0.0);
+
+ CHECK_MESSAGE(
+ frames.get_animation_speed(test_animation_name) == 0.0,
+ "Sets animation to zero");
+}
+
+TEST_CASE("[SpriteFrames] Animation Loop getter and setter") {
+ SpriteFrames frames;
+
+ frames.add_animation(test_animation_name);
+
+ CHECK_MESSAGE(
+ frames.get_animation_loop(test_animation_name),
+ "Sets new animation to default loop value.");
+
+ frames.set_animation_loop(test_animation_name, true);
+
+ CHECK_MESSAGE(
+ frames.get_animation_loop(test_animation_name),
+ "Sets animation loop to true");
+
+ frames.set_animation_loop(test_animation_name, false);
+
+ CHECK_MESSAGE(
+ !frames.get_animation_loop(test_animation_name),
+ "Sets animation loop to false");
+
+ // These error handling cases should not crash.
+ ERR_PRINT_OFF;
+ frames.get_animation_loop("This does not exist");
+ frames.set_animation_loop("This does not exist", false);
+ ERR_PRINT_ON;
+}
+
+// TODO
+TEST_CASE("[SpriteFrames] Frame addition, removal, and retrieval") {
+ Ref<Texture2D> dummy_frame1;
+ dummy_frame1.instantiate();
+
+ SpriteFrames frames;
+ frames.add_animation(test_animation_name);
+ frames.add_animation("1");
+ frames.add_animation("2");
+
+ CHECK_MESSAGE(
+ frames.get_frame_count(test_animation_name) == 0,
+ "Animation has a default frame count of 0");
+
+ frames.add_frame(test_animation_name, dummy_frame1, 0);
+ frames.add_frame(test_animation_name, dummy_frame1, 1);
+ frames.add_frame(test_animation_name, dummy_frame1, 2);
+
+ CHECK_MESSAGE(
+ frames.get_frame_count(test_animation_name) == 3,
+ "Adds multiple frames");
+
+ frames.remove_frame(test_animation_name, 1);
+ frames.remove_frame(test_animation_name, 0);
+
+ CHECK_MESSAGE(
+ frames.get_frame_count(test_animation_name) == 1,
+ "Removes multiple frames");
+
+ // These error handling cases should not crash.
+ ERR_PRINT_OFF;
+ frames.add_frame("does not exist", dummy_frame1, 0);
+ frames.remove_frame(test_animation_name, -99);
+ frames.remove_frame("does not exist", 0);
+ ERR_PRINT_ON;
+
+ CHECK_MESSAGE(
+ frames.get_frame_count(test_animation_name) == 1,
+ "Handles bad values when adding or removing frames.");
+
+ frames.clear(test_animation_name);
+
+ CHECK_MESSAGE(
+ frames.get_frame_count(test_animation_name) == 0,
+ "Clears frames.");
+}
+} // namespace TestSpriteFrames
+
+#endif // TEST_SPRITE_FRAMES_H
diff --git a/tests/scene/test_theme.h b/tests/scene/test_theme.h
index f7cfa0fd5b..f5b21eec32 100644
--- a/tests/scene/test_theme.h
+++ b/tests/scene/test_theme.h
@@ -101,18 +101,24 @@ TEST_CASE_FIXTURE(Fixture, "[Theme] Good theme type names") {
SUBCASE("set_type_variation") {
for (const StringName &name : names) {
+ if (name == StringName()) { // Skip empty here, not allowed.
+ continue;
+ }
Ref<Theme> theme = memnew(Theme);
ErrorDetector ed;
theme->set_type_variation(valid_type_name, name);
- CHECK(ed.has_error == (name == StringName()));
+ CHECK_FALSE(ed.has_error);
}
for (const StringName &name : names) {
+ if (name == StringName()) { // Skip empty here, not allowed.
+ continue;
+ }
Ref<Theme> theme = memnew(Theme);
ErrorDetector ed;
theme->set_type_variation(name, valid_type_name);
- CHECK(ed.has_error == (name == StringName()));
+ CHECK_FALSE(ed.has_error);
}
}
}
@@ -125,6 +131,8 @@ TEST_CASE_FIXTURE(Fixture, "[Theme] Bad theme type names") {
String::utf8("contains_汉字"),
};
+ ERR_PRINT_OFF; // All these rightfully print errors.
+
SUBCASE("add_type") {
for (const StringName &name : names) {
Ref<Theme> theme = memnew(Theme);
@@ -175,6 +183,8 @@ TEST_CASE_FIXTURE(Fixture, "[Theme] Bad theme type names") {
CHECK(ed.has_error);
}
}
+
+ ERR_PRINT_ON;
}
TEST_CASE_FIXTURE(Fixture, "[Theme] Good theme item names") {
@@ -223,6 +233,8 @@ TEST_CASE_FIXTURE(Fixture, "[Theme] Bad theme item names") {
String::utf8("contains_汉字"),
};
+ ERR_PRINT_OFF; // All these rightfully print errors.
+
SUBCASE("set_theme_item") {
for (const StringName &name : names) {
for (const DataEntry &entry : valid_data) {
@@ -250,6 +262,8 @@ TEST_CASE_FIXTURE(Fixture, "[Theme] Bad theme item names") {
}
}
}
+
+ ERR_PRINT_ON;
}
} // namespace TestTheme
diff --git a/tests/servers/test_text_server.h b/tests/servers/test_text_server.h
index 61207216fc..9ebd0f34b4 100644
--- a/tests/servers/test_text_server.h
+++ b/tests/servers/test_text_server.h
@@ -39,12 +39,12 @@
namespace TestTextServer {
-TEST_SUITE("[[TextServer]") {
+TEST_SUITE("[TextServer]") {
TEST_CASE("[TextServer] Init, font loading and shaping") {
SUBCASE("[TextServer] Loading fonts") {
for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i);
- TEST_FAIL_COND(ts.is_null(), "Invalid TS interface.");
+ CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface.");
if (!ts->has_feature(TextServer::FEATURE_FONT_DYNAMIC)) {
continue;
@@ -52,7 +52,7 @@ TEST_SUITE("[[TextServer]") {
RID font = ts->create_font();
ts->font_set_data_ptr(font, _font_NotoSans_Regular, _font_NotoSans_Regular_size);
- TEST_FAIL_COND(font == RID(), "Loading font failed.");
+ CHECK_FALSE_MESSAGE(font == RID(), "Loading font failed.");
ts->free_rid(font);
}
}
@@ -60,7 +60,7 @@ TEST_SUITE("[[TextServer]") {
SUBCASE("[TextServer] Text layout: Font fallback") {
for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i);
- TEST_FAIL_COND(ts.is_null(), "Invalid TS interface.");
+ CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface.");
if (!ts->has_feature(TextServer::FEATURE_FONT_DYNAMIC) || !ts->has_feature(TextServer::FEATURE_SIMPLE_LAYOUT)) {
continue;
@@ -79,26 +79,26 @@ TEST_SUITE("[[TextServer]") {
// 6^ 17^
RID ctx = ts->create_shaped_text();
- TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed.");
+ CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed.");
bool ok = ts->shaped_text_add_string(ctx, test, font, 16);
- TEST_FAIL_COND(!ok, "Adding text to the buffer failed.");
+ CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed.");
const Glyph *glyphs = ts->shaped_text_get_glyphs(ctx);
int gl_size = ts->shaped_text_get_glyph_count(ctx);
- TEST_FAIL_COND(gl_size == 0, "Shaping failed");
+ CHECK_FALSE_MESSAGE(gl_size == 0, "Shaping failed");
for (int j = 0; j < gl_size; j++) {
if (glyphs[j].start < 6) {
- TEST_FAIL_COND(glyphs[j].font_rid != font[1], "Incorrect font selected.");
+ CHECK_FALSE_MESSAGE(glyphs[j].font_rid != font[1], "Incorrect font selected.");
}
if ((glyphs[j].start > 6) && (glyphs[j].start < 16)) {
- TEST_FAIL_COND(glyphs[j].font_rid != font[0], "Incorrect font selected.");
+ CHECK_FALSE_MESSAGE(glyphs[j].font_rid != font[0], "Incorrect font selected.");
}
if (glyphs[j].start > 16) {
- TEST_FAIL_COND(glyphs[j].font_rid != RID(), "Incorrect font selected.");
- TEST_FAIL_COND(glyphs[j].index != test[glyphs[j].start], "Incorrect glyph index.");
+ CHECK_FALSE_MESSAGE(glyphs[j].font_rid != RID(), "Incorrect font selected.");
+ CHECK_FALSE_MESSAGE(glyphs[j].index != test[glyphs[j].start], "Incorrect glyph index.");
}
- TEST_FAIL_COND((glyphs[j].start < 0 || glyphs[j].end > test.length()), "Incorrect glyph range.");
- TEST_FAIL_COND(glyphs[j].font_size != 16, "Incorrect glyph font size.");
+ CHECK_FALSE_MESSAGE((glyphs[j].start < 0 || glyphs[j].end > test.length()), "Incorrect glyph range.");
+ CHECK_FALSE_MESSAGE(glyphs[j].font_size != 16, "Incorrect glyph font size.");
}
ts->free_rid(ctx);
@@ -113,7 +113,7 @@ TEST_SUITE("[[TextServer]") {
SUBCASE("[TextServer] Text layout: BiDi") {
for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i);
- TEST_FAIL_COND(ts.is_null(), "Invalid TS interface.");
+ CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface.");
if (!ts->has_feature(TextServer::FEATURE_FONT_DYNAMIC) || !ts->has_feature(TextServer::FEATURE_BIDI_LAYOUT)) {
continue;
@@ -132,23 +132,23 @@ TEST_SUITE("[[TextServer]") {
// 7^ 26^
RID ctx = ts->create_shaped_text();
- TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed.");
+ CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed.");
bool ok = ts->shaped_text_add_string(ctx, test, font, 16);
- TEST_FAIL_COND(!ok, "Adding text to the buffer failed.");
+ CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed.");
const Glyph *glyphs = ts->shaped_text_get_glyphs(ctx);
int gl_size = ts->shaped_text_get_glyph_count(ctx);
- TEST_FAIL_COND(gl_size == 0, "Shaping failed");
+ CHECK_FALSE_MESSAGE(gl_size == 0, "Shaping failed");
for (int j = 0; j < gl_size; j++) {
if (glyphs[j].count > 0) {
if (glyphs[j].start < 7) {
- TEST_FAIL_COND(((glyphs[j].flags & TextServer::GRAPHEME_IS_RTL) == TextServer::GRAPHEME_IS_RTL), "Incorrect direction.");
+ CHECK_FALSE_MESSAGE(((glyphs[j].flags & TextServer::GRAPHEME_IS_RTL) == TextServer::GRAPHEME_IS_RTL), "Incorrect direction.");
}
if ((glyphs[j].start > 8) && (glyphs[j].start < 23)) {
- TEST_FAIL_COND(((glyphs[j].flags & TextServer::GRAPHEME_IS_RTL) != TextServer::GRAPHEME_IS_RTL), "Incorrect direction.");
+ CHECK_FALSE_MESSAGE(((glyphs[j].flags & TextServer::GRAPHEME_IS_RTL) != TextServer::GRAPHEME_IS_RTL), "Incorrect direction.");
}
if (glyphs[j].start > 26) {
- TEST_FAIL_COND(((glyphs[j].flags & TextServer::GRAPHEME_IS_RTL) == TextServer::GRAPHEME_IS_RTL), "Incorrect direction.");
+ CHECK_FALSE_MESSAGE(((glyphs[j].flags & TextServer::GRAPHEME_IS_RTL) == TextServer::GRAPHEME_IS_RTL), "Incorrect direction.");
}
}
}
@@ -165,7 +165,7 @@ TEST_SUITE("[[TextServer]") {
SUBCASE("[TextServer] Text layout: Line break and align points") {
for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i);
- TEST_FAIL_COND(ts.is_null(), "Invalid TS interface.");
+ CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface.");
if (!ts->has_feature(TextServer::FEATURE_FONT_DYNAMIC) || !ts->has_feature(TextServer::FEATURE_SIMPLE_LAYOUT)) {
continue;
@@ -186,16 +186,16 @@ TEST_SUITE("[[TextServer]") {
{
String test = U"Test test long text long text\n";
RID ctx = ts->create_shaped_text();
- TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed.");
+ CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed.");
bool ok = ts->shaped_text_add_string(ctx, test, font, 16);
- TEST_FAIL_COND(!ok, "Adding text to the buffer failed.");
+ CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed.");
ts->shaped_text_update_breaks(ctx);
ts->shaped_text_update_justification_ops(ctx);
const Glyph *glyphs = ts->shaped_text_get_glyphs(ctx);
int gl_size = ts->shaped_text_get_glyph_count(ctx);
- TEST_FAIL_COND(gl_size != 30, "Invalid glyph count.");
+ CHECK_FALSE_MESSAGE(gl_size != 30, "Invalid glyph count.");
for (int j = 0; j < gl_size; j++) {
bool hard = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_HARD) == TextServer::GRAPHEME_IS_BREAK_HARD;
bool soft = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_SOFT) == TextServer::GRAPHEME_IS_BREAK_SOFT;
@@ -203,11 +203,11 @@ TEST_SUITE("[[TextServer]") {
bool virt = (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL;
bool elo = (glyphs[j].flags & TextServer::GRAPHEME_IS_ELONGATION) == TextServer::GRAPHEME_IS_ELONGATION;
if (j == 4 || j == 9 || j == 14 || j == 19 || j == 24) {
- TEST_FAIL_COND((!soft || !space || hard || virt || elo), "Invalid glyph flags.");
+ CHECK_FALSE_MESSAGE((!soft || !space || hard || virt || elo), "Invalid glyph flags.");
} else if (j == 29) {
- TEST_FAIL_COND((soft || !space || !hard || virt || elo), "Invalid glyph flags.");
+ CHECK_FALSE_MESSAGE((soft || !space || !hard || virt || elo), "Invalid glyph flags.");
} else {
- TEST_FAIL_COND((soft || space || hard || virt || elo), "Invalid glyph flags.");
+ CHECK_FALSE_MESSAGE((soft || space || hard || virt || elo), "Invalid glyph flags.");
}
}
ts->free_rid(ctx);
@@ -216,21 +216,63 @@ TEST_SUITE("[[TextServer]") {
{
String test = U"الحمـد";
RID ctx = ts->create_shaped_text();
- TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed.");
+ CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed.");
bool ok = ts->shaped_text_add_string(ctx, test, font, 16);
- TEST_FAIL_COND(!ok, "Adding text to the buffer failed.");
+ CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed.");
ts->shaped_text_update_breaks(ctx);
const Glyph *glyphs = ts->shaped_text_get_glyphs(ctx);
int gl_size = ts->shaped_text_get_glyph_count(ctx);
- TEST_FAIL_COND(gl_size != 6, "Invalid glyph count.");
+ CHECK_FALSE_MESSAGE(gl_size != 6, "Invalid glyph count.");
for (int j = 0; j < gl_size; j++) {
bool hard = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_HARD) == TextServer::GRAPHEME_IS_BREAK_HARD;
bool soft = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_SOFT) == TextServer::GRAPHEME_IS_BREAK_SOFT;
bool space = (glyphs[j].flags & TextServer::GRAPHEME_IS_SPACE) == TextServer::GRAPHEME_IS_SPACE;
bool virt = (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL;
bool elo = (glyphs[j].flags & TextServer::GRAPHEME_IS_ELONGATION) == TextServer::GRAPHEME_IS_ELONGATION;
- TEST_FAIL_COND((soft || space || hard || virt || elo), "Invalid glyph flags.");
+ CHECK_FALSE_MESSAGE((soft || space || hard || virt || elo), "Invalid glyph flags.");
+ }
+ if (ts->has_feature(TextServer::FEATURE_KASHIDA_JUSTIFICATION)) {
+ ts->shaped_text_update_justification_ops(ctx);
+
+ glyphs = ts->shaped_text_get_glyphs(ctx);
+ gl_size = ts->shaped_text_get_glyph_count(ctx);
+
+ CHECK_FALSE_MESSAGE(gl_size != 6, "Invalid glyph count.");
+ for (int j = 0; j < gl_size; j++) {
+ bool hard = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_HARD) == TextServer::GRAPHEME_IS_BREAK_HARD;
+ bool soft = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_SOFT) == TextServer::GRAPHEME_IS_BREAK_SOFT;
+ bool space = (glyphs[j].flags & TextServer::GRAPHEME_IS_SPACE) == TextServer::GRAPHEME_IS_SPACE;
+ bool virt = (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL;
+ bool elo = (glyphs[j].flags & TextServer::GRAPHEME_IS_ELONGATION) == TextServer::GRAPHEME_IS_ELONGATION;
+ if (j == 1) {
+ CHECK_FALSE_MESSAGE((soft || space || hard || virt || !elo), "Invalid glyph flags.");
+ } else {
+ CHECK_FALSE_MESSAGE((soft || space || hard || virt || elo), "Invalid glyph flags.");
+ }
+ }
+ }
+ ts->free_rid(ctx);
+ }
+
+ {
+ String test = U"الحمد";
+ RID ctx = ts->create_shaped_text();
+ CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed.");
+ bool ok = ts->shaped_text_add_string(ctx, test, font, 16);
+ CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed.");
+ ts->shaped_text_update_breaks(ctx);
+
+ const Glyph *glyphs = ts->shaped_text_get_glyphs(ctx);
+ int gl_size = ts->shaped_text_get_glyph_count(ctx);
+ CHECK_FALSE_MESSAGE(gl_size != 5, "Invalid glyph count.");
+ for (int j = 0; j < gl_size; j++) {
+ bool hard = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_HARD) == TextServer::GRAPHEME_IS_BREAK_HARD;
+ bool soft = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_SOFT) == TextServer::GRAPHEME_IS_BREAK_SOFT;
+ bool space = (glyphs[j].flags & TextServer::GRAPHEME_IS_SPACE) == TextServer::GRAPHEME_IS_SPACE;
+ bool virt = (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL;
+ bool elo = (glyphs[j].flags & TextServer::GRAPHEME_IS_ELONGATION) == TextServer::GRAPHEME_IS_ELONGATION;
+ CHECK_FALSE_MESSAGE((soft || space || hard || virt || elo), "Invalid glyph flags.");
}
if (ts->has_feature(TextServer::FEATURE_KASHIDA_JUSTIFICATION)) {
@@ -239,7 +281,7 @@ TEST_SUITE("[[TextServer]") {
glyphs = ts->shaped_text_get_glyphs(ctx);
gl_size = ts->shaped_text_get_glyph_count(ctx);
- TEST_FAIL_COND(gl_size != 6, "Invalid glyph count.");
+ CHECK_FALSE_MESSAGE(gl_size != 6, "Invalid glyph count.");
for (int j = 0; j < gl_size; j++) {
bool hard = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_HARD) == TextServer::GRAPHEME_IS_BREAK_HARD;
bool soft = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_SOFT) == TextServer::GRAPHEME_IS_BREAK_SOFT;
@@ -247,9 +289,9 @@ TEST_SUITE("[[TextServer]") {
bool virt = (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL;
bool elo = (glyphs[j].flags & TextServer::GRAPHEME_IS_ELONGATION) == TextServer::GRAPHEME_IS_ELONGATION;
if (j == 1) {
- TEST_FAIL_COND((soft || space || hard || virt || !elo), "Invalid glyph flags.");
+ CHECK_FALSE_MESSAGE((soft || space || hard || !virt || !elo), "Invalid glyph flags.");
} else {
- TEST_FAIL_COND((soft || space || hard || virt || elo), "Invalid glyph flags.");
+ CHECK_FALSE_MESSAGE((soft || space || hard || virt || elo), "Invalid glyph flags.");
}
}
}
@@ -259,15 +301,15 @@ TEST_SUITE("[[TextServer]") {
{
String test = U"الحمـد الرياضي العربي";
RID ctx = ts->create_shaped_text();
- TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed.");
+ CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed.");
bool ok = ts->shaped_text_add_string(ctx, test, font, 16);
- TEST_FAIL_COND(!ok, "Adding text to the buffer failed.");
+ CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed.");
ts->shaped_text_update_breaks(ctx);
const Glyph *glyphs = ts->shaped_text_get_glyphs(ctx);
int gl_size = ts->shaped_text_get_glyph_count(ctx);
- TEST_FAIL_COND(gl_size != 21, "Invalid glyph count.");
+ CHECK_FALSE_MESSAGE(gl_size != 21, "Invalid glyph count.");
for (int j = 0; j < gl_size; j++) {
bool hard = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_HARD) == TextServer::GRAPHEME_IS_BREAK_HARD;
bool soft = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_SOFT) == TextServer::GRAPHEME_IS_BREAK_SOFT;
@@ -275,9 +317,9 @@ TEST_SUITE("[[TextServer]") {
bool virt = (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL;
bool elo = (glyphs[j].flags & TextServer::GRAPHEME_IS_ELONGATION) == TextServer::GRAPHEME_IS_ELONGATION;
if (j == 6 || j == 14) {
- TEST_FAIL_COND((!soft || !space || hard || virt || elo), "Invalid glyph flags.");
+ CHECK_FALSE_MESSAGE((!soft || !space || hard || virt || elo), "Invalid glyph flags.");
} else {
- TEST_FAIL_COND((soft || space || hard || virt || elo), "Invalid glyph flags.");
+ CHECK_FALSE_MESSAGE((soft || space || hard || virt || elo), "Invalid glyph flags.");
}
}
@@ -287,7 +329,7 @@ TEST_SUITE("[[TextServer]") {
glyphs = ts->shaped_text_get_glyphs(ctx);
gl_size = ts->shaped_text_get_glyph_count(ctx);
- TEST_FAIL_COND(gl_size != 23, "Invalid glyph count.");
+ CHECK_FALSE_MESSAGE(gl_size != 23, "Invalid glyph count.");
for (int j = 0; j < gl_size; j++) {
bool hard = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_HARD) == TextServer::GRAPHEME_IS_BREAK_HARD;
bool soft = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_SOFT) == TextServer::GRAPHEME_IS_BREAK_SOFT;
@@ -295,13 +337,13 @@ TEST_SUITE("[[TextServer]") {
bool virt = (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL;
bool elo = (glyphs[j].flags & TextServer::GRAPHEME_IS_ELONGATION) == TextServer::GRAPHEME_IS_ELONGATION;
if (j == 7 || j == 16) {
- TEST_FAIL_COND((!soft || !space || hard || virt || elo), "Invalid glyph flags.");
+ CHECK_FALSE_MESSAGE((!soft || !space || hard || virt || elo), "Invalid glyph flags.");
} else if (j == 3 || j == 9) {
- TEST_FAIL_COND((soft || space || hard || !virt || !elo), "Invalid glyph flags.");
+ CHECK_FALSE_MESSAGE((soft || space || hard || !virt || !elo), "Invalid glyph flags.");
} else if (j == 18) {
- TEST_FAIL_COND((soft || space || hard || virt || !elo), "Invalid glyph flags.");
+ CHECK_FALSE_MESSAGE((soft || space || hard || virt || !elo), "Invalid glyph flags.");
} else {
- TEST_FAIL_COND((soft || space || hard || virt || elo), "Invalid glyph flags.");
+ CHECK_FALSE_MESSAGE((soft || space || hard || virt || elo), "Invalid glyph flags.");
}
}
}
@@ -312,16 +354,16 @@ TEST_SUITE("[[TextServer]") {
{
String test = U"เป็น ภาษา ราชà¸à¸²à¸£ à¹à¸¥à¸° ภาษา";
RID ctx = ts->create_shaped_text();
- TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed.");
+ CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed.");
bool ok = ts->shaped_text_add_string(ctx, test, font, 16);
- TEST_FAIL_COND(!ok, "Adding text to the buffer failed.");
+ CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed.");
ts->shaped_text_update_breaks(ctx);
ts->shaped_text_update_justification_ops(ctx);
const Glyph *glyphs = ts->shaped_text_get_glyphs(ctx);
int gl_size = ts->shaped_text_get_glyph_count(ctx);
- TEST_FAIL_COND(gl_size != 25, "Invalid glyph count.");
+ CHECK_FALSE_MESSAGE(gl_size != 25, "Invalid glyph count.");
for (int j = 0; j < gl_size; j++) {
bool hard = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_HARD) == TextServer::GRAPHEME_IS_BREAK_HARD;
bool soft = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_SOFT) == TextServer::GRAPHEME_IS_BREAK_SOFT;
@@ -329,9 +371,9 @@ TEST_SUITE("[[TextServer]") {
bool virt = (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL;
bool elo = (glyphs[j].flags & TextServer::GRAPHEME_IS_ELONGATION) == TextServer::GRAPHEME_IS_ELONGATION;
if (j == 4 || j == 9 || j == 16 || j == 20) {
- TEST_FAIL_COND((!soft || !space || hard || virt || elo), "Invalid glyph flags.");
+ CHECK_FALSE_MESSAGE((!soft || !space || hard || virt || elo), "Invalid glyph flags.");
} else {
- TEST_FAIL_COND((soft || space || hard || virt || elo), "Invalid glyph flags.");
+ CHECK_FALSE_MESSAGE((soft || space || hard || virt || elo), "Invalid glyph flags.");
}
}
ts->free_rid(ctx);
@@ -340,16 +382,16 @@ TEST_SUITE("[[TextServer]") {
if (ts->has_feature(TextServer::FEATURE_BREAK_ITERATORS)) {
String test = U"เป็นภาษาราชà¸à¸²à¸£à¹à¸¥à¸°à¸ à¸²à¸©à¸²";
RID ctx = ts->create_shaped_text();
- TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed.");
+ CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed.");
bool ok = ts->shaped_text_add_string(ctx, test, font, 16);
- TEST_FAIL_COND(!ok, "Adding text to the buffer failed.");
+ CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed.");
ts->shaped_text_update_breaks(ctx);
ts->shaped_text_update_justification_ops(ctx);
const Glyph *glyphs = ts->shaped_text_get_glyphs(ctx);
int gl_size = ts->shaped_text_get_glyph_count(ctx);
- TEST_FAIL_COND(gl_size != 25, "Invalid glyph count.");
+ CHECK_FALSE_MESSAGE(gl_size != 25, "Invalid glyph count.");
for (int j = 0; j < gl_size; j++) {
bool hard = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_HARD) == TextServer::GRAPHEME_IS_BREAK_HARD;
bool soft = (glyphs[j].flags & TextServer::GRAPHEME_IS_BREAK_SOFT) == TextServer::GRAPHEME_IS_BREAK_SOFT;
@@ -357,9 +399,9 @@ TEST_SUITE("[[TextServer]") {
bool virt = (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL;
bool elo = (glyphs[j].flags & TextServer::GRAPHEME_IS_ELONGATION) == TextServer::GRAPHEME_IS_ELONGATION;
if (j == 4 || j == 9 || j == 16 || j == 20) {
- TEST_FAIL_COND((!soft || !space || hard || !virt || elo), "Invalid glyph flags.");
+ CHECK_FALSE_MESSAGE((!soft || !space || hard || !virt || elo), "Invalid glyph flags.");
} else {
- TEST_FAIL_COND((soft || space || hard || virt || elo), "Invalid glyph flags.");
+ CHECK_FALSE_MESSAGE((soft || space || hard || virt || elo), "Invalid glyph flags.");
}
}
ts->free_rid(ctx);
@@ -375,7 +417,7 @@ TEST_SUITE("[[TextServer]") {
SUBCASE("[TextServer] Text layout: Line breaking") {
for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i);
- TEST_FAIL_COND(ts.is_null(), "Invalid TS interface.");
+ CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface.");
if (!ts->has_feature(TextServer::FEATURE_FONT_DYNAMIC) || !ts->has_feature(TextServer::FEATURE_SIMPLE_LAYOUT)) {
continue;
@@ -394,21 +436,21 @@ TEST_SUITE("[[TextServer]") {
font.push_back(font2);
RID ctx = ts->create_shaped_text();
- TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed.");
+ CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed.");
bool ok = ts->shaped_text_add_string(ctx, test_1, font, 16);
- TEST_FAIL_COND(!ok, "Adding text to the buffer failed.");
+ CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed.");
PackedInt32Array brks = ts->shaped_text_get_line_breaks(ctx, 1);
- TEST_FAIL_COND(brks.size() != 6, "Invalid line breaks number.");
+ CHECK_FALSE_MESSAGE(brks.size() != 6, "Invalid line breaks number.");
if (brks.size() == 6) {
- TEST_FAIL_COND(brks[0] != 0, "Invalid line break position.");
- TEST_FAIL_COND(brks[1] != 5, "Invalid line break position.");
+ CHECK_FALSE_MESSAGE(brks[0] != 0, "Invalid line break position.");
+ CHECK_FALSE_MESSAGE(brks[1] != 5, "Invalid line break position.");
- TEST_FAIL_COND(brks[2] != 5, "Invalid line break position.");
- TEST_FAIL_COND(brks[3] != 10, "Invalid line break position.");
+ CHECK_FALSE_MESSAGE(brks[2] != 5, "Invalid line break position.");
+ CHECK_FALSE_MESSAGE(brks[3] != 10, "Invalid line break position.");
- TEST_FAIL_COND(brks[4] != 10, "Invalid line break position.");
- TEST_FAIL_COND(brks[5] != 14, "Invalid line break position.");
+ CHECK_FALSE_MESSAGE(brks[4] != 10, "Invalid line break position.");
+ CHECK_FALSE_MESSAGE(brks[5] != 14, "Invalid line break position.");
}
ts->free_rid(ctx);
@@ -423,7 +465,7 @@ TEST_SUITE("[[TextServer]") {
SUBCASE("[TextServer] Text layout: Justification") {
for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i);
- TEST_FAIL_COND(ts.is_null(), "Invalid TS interface.");
+ CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface.");
if (!ts->has_feature(TextServer::FEATURE_FONT_DYNAMIC) || !ts->has_feature(TextServer::FEATURE_SIMPLE_LAYOUT)) {
continue;
@@ -448,40 +490,40 @@ TEST_SUITE("[[TextServer]") {
float width_old, width;
if (ts->has_feature(TextServer::FEATURE_KASHIDA_JUSTIFICATION)) {
ctx = ts->create_shaped_text();
- TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed.");
+ CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed.");
ok = ts->shaped_text_add_string(ctx, test_1, font, 16);
- TEST_FAIL_COND(!ok, "Adding text to the buffer failed.");
+ CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed.");
width_old = ts->shaped_text_get_width(ctx);
width = ts->shaped_text_fit_to_width(ctx, 100, TextServer::JUSTIFICATION_WORD_BOUND);
- TEST_FAIL_COND((width != width_old), "Invalid fill width.");
+ CHECK_FALSE_MESSAGE((width != width_old), "Invalid fill width.");
width = ts->shaped_text_fit_to_width(ctx, 100, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA);
- TEST_FAIL_COND((width <= width_old || width > 100), "Invalid fill width.");
+ CHECK_FALSE_MESSAGE((width <= width_old || width > 100), "Invalid fill width.");
ts->free_rid(ctx);
ctx = ts->create_shaped_text();
- TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed.");
+ CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed.");
ok = ts->shaped_text_add_string(ctx, test_2, font, 16);
- TEST_FAIL_COND(!ok, "Adding text to the buffer failed.");
+ CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed.");
width_old = ts->shaped_text_get_width(ctx);
width = ts->shaped_text_fit_to_width(ctx, 100, TextServer::JUSTIFICATION_WORD_BOUND);
- TEST_FAIL_COND((width <= width_old || width > 100), "Invalid fill width.");
+ CHECK_FALSE_MESSAGE((width <= width_old || width > 100), "Invalid fill width.");
width = ts->shaped_text_fit_to_width(ctx, 100, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA);
- TEST_FAIL_COND((width <= width_old || width > 100), "Invalid fill width.");
+ CHECK_FALSE_MESSAGE((width <= width_old || width > 100), "Invalid fill width.");
ts->free_rid(ctx);
}
ctx = ts->create_shaped_text();
- TEST_FAIL_COND(ctx == RID(), "Creating text buffer failed.");
+ CHECK_FALSE_MESSAGE(ctx == RID(), "Creating text buffer failed.");
ok = ts->shaped_text_add_string(ctx, test_3, font, 16);
- TEST_FAIL_COND(!ok, "Adding text to the buffer failed.");
+ CHECK_FALSE_MESSAGE(!ok, "Adding text to the buffer failed.");
width_old = ts->shaped_text_get_width(ctx);
width = ts->shaped_text_fit_to_width(ctx, 100, TextServer::JUSTIFICATION_WORD_BOUND);
- TEST_FAIL_COND((width <= width_old || width > 100), "Invalid fill width.");
+ CHECK_FALSE_MESSAGE((width <= width_old || width > 100), "Invalid fill width.");
ts->free_rid(ctx);
@@ -492,10 +534,31 @@ TEST_SUITE("[[TextServer]") {
}
}
+ SUBCASE("[TextServer] Unicode identifiers") {
+ for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
+ Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i);
+ CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface.");
+
+ static const char32_t *data[19] = { U"-30", U"100", U"10.1", U"10,1", U"1e2", U"1e-2", U"1e2e3", U"0xAB", U"AB", U"Test1", U"1Test", U"Test*1", U"test_testeT", U"test_tes teT", U"عَلَيْكÙمْ", U"عَلَيْكÙمْTest", U"Ó’Ó–ÓšÓœ", U"_test", U"ÂÃÄÅĀĂĄÇĆĈĊ" };
+ static bool isid[19] = { false, false, false, false, false, false, false, false, true, true, false, false, true, false, true, true, true, true, true };
+ for (int j = 0; j < 19; j++) {
+ String s = String(data[j]);
+ CHECK(ts->is_valid_identifier(s) == isid[j]);
+ }
+
+ if (ts->has_feature(TextServer::FEATURE_UNICODE_IDENTIFIERS)) {
+ // Test UAX 3.2 ZW(N)J usage.
+ CHECK(ts->is_valid_identifier(U"\u0646\u0627\u0645\u0647\u200C\u0627\u06CC"));
+ CHECK(ts->is_valid_identifier(U"\u0D26\u0D43\u0D15\u0D4D\u200C\u0D38\u0D3E\u0D15\u0D4D\u0D37\u0D3F"));
+ CHECK(ts->is_valid_identifier(U"\u0DC1\u0DCA\u200D\u0DBB\u0DD3"));
+ }
+ }
+ }
+
SUBCASE("[TextServer] Strip Diacritics") {
for (int i = 0; i < TextServerManager::get_singleton()->get_interface_count(); i++) {
Ref<TextServer> ts = TextServerManager::get_singleton()->get_interface(i);
- TEST_FAIL_COND(ts.is_null(), "Invalid TS interface.");
+ CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface.");
if (ts->has_feature(TextServer::FEATURE_SHAPING)) {
CHECK(ts->strip_diacritics(U"ٱلسَّلَام٠عَلَيْكÙمْ") == U"ٱلسلام عليكم");
@@ -523,7 +586,7 @@ TEST_SUITE("[[TextServer]") {
continue;
}
- TEST_FAIL_COND(ts.is_null(), "Invalid TS interface.");
+ CHECK_FALSE_MESSAGE(ts.is_null(), "Invalid TS interface.");
{
String text1 = U"linguistically similar and effectively form";
// 14^ 22^ 26^ 38^
diff --git a/tests/test_macros.h b/tests/test_macros.h
index eff09fb4b0..69ae0d3124 100644
--- a/tests/test_macros.h
+++ b/tests/test_macros.h
@@ -31,6 +31,7 @@
#ifndef TEST_MACROS_H
#define TEST_MACROS_H
+#include "core/core_globals.h"
#include "core/input/input_map.h"
#include "core/object/message_queue.h"
#include "core/variant/variant.h"
@@ -53,12 +54,12 @@
// Temporarily disable error prints to test failure paths.
// This allows to avoid polluting the test summary with error messages.
-// The `_print_error_enabled` boolean is defined in `core/print_string.cpp` and
+// The `print_error_enabled` boolean is defined in `core/core_globals.cpp` and
// works at global scope. It's used by various loggers in `should_log()` method,
// which are used by error macros which call into `OS::print_error`, effectively
// disabling any error messages to be printed from the engine side (not tests).
-#define ERR_PRINT_OFF _print_error_enabled = false;
-#define ERR_PRINT_ON _print_error_enabled = true;
+#define ERR_PRINT_OFF CoreGlobals::print_error_enabled = false;
+#define ERR_PRINT_ON CoreGlobals::print_error_enabled = true;
// Stringify all `Variant` compatible types for doctest output by default.
// https://github.com/onqtam/doctest/blob/master/doc/markdown/stringification.md
@@ -199,8 +200,8 @@ int register_test_command(String p_command, TestFunc p_function);
// We toggle _print_error_enabled to prevent display server not supported warnings.
#define SEND_GUI_MOUSE_MOTION_EVENT(m_object, m_local_pos, m_mask, m_modifers) \
{ \
- bool errors_enabled = _print_error_enabled; \
- _print_error_enabled = false; \
+ bool errors_enabled = CoreGlobals::print_error_enabled; \
+ CoreGlobals::print_error_enabled = false; \
Ref<InputEventMouseMotion> event; \
event.instantiate(); \
event->set_position(m_local_pos); \
@@ -209,7 +210,7 @@ int register_test_command(String p_command, TestFunc p_function);
_UPDATE_EVENT_MODIFERS(event, m_modifers); \
m_object->get_viewport()->push_input(event); \
MessageQueue::get_singleton()->flush(); \
- _print_error_enabled = errors_enabled; \
+ CoreGlobals::print_error_enabled = errors_enabled; \
}
// Utility class / macros for testing signals
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index 40fe562be1..a30d11342a 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -30,6 +30,8 @@
#include "test_main.h"
+#include "tests/core/input/test_input_event_key.h"
+#include "tests/core/input/test_shortcut.h"
#include "tests/core/io/test_config_file.h"
#include "tests/core/io/test_file_access.h"
#include "tests/core/io/test_image.h"
@@ -46,13 +48,18 @@
#include "tests/core/math/test_geometry_2d.h"
#include "tests/core/math/test_geometry_3d.h"
#include "tests/core/math/test_plane.h"
+#include "tests/core/math/test_quaternion.h"
#include "tests/core/math/test_random_number_generator.h"
#include "tests/core/math/test_rect2.h"
#include "tests/core/math/test_rect2i.h"
+#include "tests/core/math/test_transform_2d.h"
+#include "tests/core/math/test_transform_3d.h"
#include "tests/core/math/test_vector2.h"
#include "tests/core/math/test_vector2i.h"
#include "tests/core/math/test_vector3.h"
#include "tests/core/math/test_vector3i.h"
+#include "tests/core/math/test_vector4.h"
+#include "tests/core/math/test_vector4i.h"
#include "tests/core/object/test_class_db.h"
#include "tests/core/object/test_method_bind.h"
#include "tests/core/object/test_object.h"
@@ -67,6 +74,7 @@
#include "tests/core/templates/test_local_vector.h"
#include "tests/core/templates/test_lru.h"
#include "tests/core/templates/test_paged_array.h"
+#include "tests/core/templates/test_rid.h"
#include "tests/core/templates/test_vector.h"
#include "tests/core/test_crypto.h"
#include "tests/core/test_hashing_context.h"
@@ -76,10 +84,12 @@
#include "tests/core/variant/test_dictionary.h"
#include "tests/core/variant/test_variant.h"
#include "tests/scene/test_animation.h"
+#include "tests/scene/test_audio_stream_wav.h"
#include "tests/scene/test_code_edit.h"
#include "tests/scene/test_curve.h"
#include "tests/scene/test_gradient.h"
#include "tests/scene/test_path_3d.h"
+#include "tests/scene/test_sprite_frames.h"
#include "tests/scene/test_text_edit.h"
#include "tests/scene/test_theme.h"
#include "tests/servers/test_text_server.h"
@@ -89,7 +99,7 @@
#include "tests/test_macros.h"
-#include "scene/resources/default_theme/default_theme.h"
+#include "scene/theme/theme_db.h"
#include "servers/navigation_server_2d.h"
#include "servers/navigation_server_3d.h"
#include "servers/physics_server_2d.h"
@@ -105,7 +115,7 @@ int test_main(int argc, char *argv[]) {
for (int i = 0; i < argc; i++) {
args.push_back(String::utf8(argv[i]));
}
- OS::get_singleton()->set_cmdline("", args);
+ OS::get_singleton()->set_cmdline("", args, List<String>());
// Run custom test tools.
if (test_commands) {
@@ -169,6 +179,7 @@ struct GodotTestCaseListener : public doctest::IReporter {
PhysicsServer2D *physics_server_2d = nullptr;
NavigationServer3D *navigation_server_3d = nullptr;
NavigationServer2D *navigation_server_2d = nullptr;
+ ThemeDB *theme_db = nullptr;
void test_case_start(const doctest::TestCaseData &p_in) override {
SignalWatcher::get_singleton()->_clear_signals();
@@ -207,12 +218,22 @@ struct GodotTestCaseListener : public doctest::IReporter {
memnew(InputMap);
InputMap::get_singleton()->load_default();
- make_default_theme(1.0, Ref<Font>());
+ theme_db = memnew(ThemeDB);
+ theme_db->initialize_theme_noproject();
memnew(SceneTree);
SceneTree::get_singleton()->initialize();
return;
}
+
+ if (name.find("Audio") != -1) {
+ // The last driver index should always be the dummy driver.
+ int dummy_idx = AudioDriverManager::get_driver_count() - 1;
+ AudioDriverManager::initialize(dummy_idx);
+ AudioServer *audio_server = memnew(AudioServer);
+ audio_server->init();
+ return;
+ }
}
void test_case_end(const doctest::CurrentTestCaseStats &) override {
@@ -228,7 +249,10 @@ struct GodotTestCaseListener : public doctest::IReporter {
memdelete(SceneTree::get_singleton());
}
- clear_default_theme();
+ if (theme_db) {
+ memdelete(theme_db);
+ theme_db = nullptr;
+ }
if (navigation_server_3d) {
memdelete(navigation_server_3d);
@@ -275,6 +299,11 @@ struct GodotTestCaseListener : public doctest::IReporter {
MessageQueue::get_singleton()->flush();
memdelete(MessageQueue::get_singleton());
}
+
+ if (AudioServer::get_singleton()) {
+ AudioServer::get_singleton()->finish();
+ memdelete(AudioServer::get_singleton());
+ }
}
void test_run_start() override {
diff --git a/tests/test_utils.cpp b/tests/test_utils.cpp
index 11cb6398aa..ce12a30381 100644
--- a/tests/test_utils.cpp
+++ b/tests/test_utils.cpp
@@ -34,7 +34,7 @@
String TestUtils::get_data_path(const String &p_file) {
String data_path = "../tests/data";
- return get_executable_dir().plus_file(data_path.plus_file(p_file));
+ return get_executable_dir().path_join(data_path.path_join(p_file));
}
String TestUtils::get_executable_dir() {
diff --git a/tests/test_validate_testing.h b/tests/test_validate_testing.h
index 413a7e351d..1471a952cd 100644
--- a/tests/test_validate_testing.h
+++ b/tests/test_validate_testing.h
@@ -31,6 +31,7 @@
#ifndef TEST_VALIDATE_TESTING_H
#define TEST_VALIDATE_TESTING_H
+#include "core/core_globals.h"
#include "core/os/os.h"
#include "tests/test_macros.h"
@@ -49,10 +50,10 @@ TEST_SUITE("Validate tests") {
}
TEST_CASE("Muting Godot error messages") {
ERR_PRINT_OFF;
- CHECK_MESSAGE(!_print_error_enabled, "Error printing should be disabled.");
+ CHECK_MESSAGE(!CoreGlobals::print_error_enabled, "Error printing should be disabled.");
ERR_PRINT("Still waiting for Godot!"); // This should never get printed!
ERR_PRINT_ON;
- CHECK_MESSAGE(_print_error_enabled, "Error printing should be re-enabled.");
+ CHECK_MESSAGE(CoreGlobals::print_error_enabled, "Error printing should be re-enabled.");
}
TEST_CASE("Stringify Variant types") {
Variant var;
diff --git a/thirdparty/README.md b/thirdparty/README.md
index b06d9cec81..ffc8137819 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -44,7 +44,7 @@ Files extracted from upstream source:
## certs
- Upstream: Mozilla, via https://github.com/bagder/ca-bundle
-- Version: git (8b263a18fca98ea371e54227837321c5cdaa1ba7, 2021)
+- Version: git (7f33e7eb8472dbcf31fdcf50cd216c89a282825d, 2022)
- License: MPL 2.0
@@ -195,6 +195,7 @@ Files extracted from upstream source:
to `glslang/build_info.h`
- `LICENSE.txt`
- Unnecessary files like `CMakeLists.txt`, `*.m4` and `updateGrammar` removed.
+- Patch in `patches/unused_cleanup.diff` must be applied.
## graphite
@@ -213,7 +214,7 @@ Files extracted from upstream source:
## harfbuzz
- Upstream: https://github.com/harfbuzz/harfbuzz
-- Version: 5.0.1 (cbccadba8d1e51d6cc03a891b7c3a17f598e774c, 2022)
+- Version: 5.1.0 (f1f2be776bcd994fa9262622e1a7098a066e5cf7, 2022)
- License: MIT
Files extracted from upstream source:
@@ -231,6 +232,8 @@ Files extracted from upstream source:
Files extracted from upstream source:
- the `common` folder
+- `scriptset.*`, `ucln_in.*`, `uspoof.cpp"` and `uspoof_impl.cpp` from the `i18n` folder
+- `uspoof.h` from the `i18n/unicode` folder
- `LICENSE`
Files generated from upstream source:
@@ -317,12 +320,12 @@ Files extracted from upstream source:
## libwebp
- Upstream: https://chromium.googlesource.com/webm/libwebp/
-- Version: 1.2.2 (b0a860891dcd4c0c2d7c6149e5cccb6eb881cc21, 2022)
+- Version: 1.2.4 (0d1f12546bd803099a60c070517a552483f3790e, 2022)
- License: BSD-3-Clause
Files extracted from upstream source:
-- `src/*` except from: `.am`, `.rc` and `.in` files
+- `src/` and `sharpyuv/` except from: `.am`, `.rc` and `.in` files
- `AUTHORS`, `COPYING`, `PATENTS`
@@ -342,6 +345,9 @@ File extracted from upstream release tarball:
- Added 2 files `godot_core_mbedtls_platform.c` and `godot_core_mbedtls_config.h`
providing configuration for light bundling with core.
+Some changes have been made in order to fix Windows on ARM build errors.
+They are marked with `// -- GODOT start --` and `// -- GODOT end --`
+
## meshoptimizer
@@ -372,6 +378,9 @@ Files extracted from upstream repository:
- `minimp3_ex.h`
- `LICENSE`
+Some changes have been made in order to fix Windows on ARM build errors.
+They are marked with `// -- GODOT start --` and `// -- GODOT end --`
+
## miniupnpc
@@ -597,7 +606,7 @@ Godot. See the patch in the `patches` folder for details.
## spirv-reflect
- Upstream: https://github.com/KhronosGroup/SPIRV-Reflect
-- Version: git (1aceb6af56e74b92a00378842dda5c5a73f49a4b, 2022)
+- Version: git (1ef99b09fa7ce5aee2c5cf70c61a4f7458d27e09, 2022)
- License: Apache 2.0
Does not track Vulkan SDK releases closely, but try to package a commit newer
diff --git a/thirdparty/certs/ca-certificates.crt b/thirdparty/certs/ca-certificates.crt
index e218b024d0..036f630d5b 100644
--- a/thirdparty/certs/ca-certificates.crt
+++ b/thirdparty/certs/ca-certificates.crt
@@ -1,7 +1,7 @@
##
## Bundle of CA Root Certificates
##
-## Certificate data from Mozilla as of: Thu Mar 31 08:10:21 2022 GMT
+## Certificate data from Mozilla as of: Tue Jul 19 14:20:01 2022 GMT
##
## This is a bundle of X.509 certificates of public Certificate Authorities
## (CA). These were automatically extracted from Mozilla's root certificates
@@ -14,7 +14,7 @@
## Just configure this file as the SSLCACertificateFile.
##
## Conversion done with mk-ca-bundle.pl version 1.29.
-## SHA256: d59c5c83ce7a7635fa95521d8d245677949b86d5574bfcc6f855b6a48f2d5566
+## SHA256: 9bf3799611fb58197f61d45e71ce3dc19f30e7dd73731915872ce5108a7bb066
##
@@ -993,30 +993,6 @@ tnRGEmyR7jTV7JqR50S+kDFy1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29
mvVXIwAHIRc/SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03
-----END CERTIFICATE-----
-Hellenic Academic and Research Institutions RootCA 2011
-=======================================================
------BEGIN CERTIFICATE-----
-MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1IxRDBCBgNVBAoT
-O0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9y
-aXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z
-IFJvb3RDQSAyMDExMB4XDTExMTIwNjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYT
-AkdSMUQwQgYDVQQKEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25z
-IENlcnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNo
-IEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
-AKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPzdYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI
-1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJfel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa
-71HFK9+WXesyHgLacEnsbgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u
-8yBRQlqD75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSPFEDH
-3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNVHRMBAf8EBTADAQH/
-MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp5dgTBCPuQSUwRwYDVR0eBEAwPqA8
-MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQub3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQu
-b3JnMA0GCSqGSIb3DQEBBQUAA4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVt
-XdMiKahsog2p6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8
-TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7dIsXRSZMFpGD
-/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8AcysNnq/onN694/BtZqhFLKPM58N
-7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXIl7WdmplNsDz4SgCbZN2fOUvRJ9e4
------END CERTIFICATE-----
-
Actalis Authentication Root CA
==============================
-----BEGIN CERTIFICATE-----
@@ -3279,3 +3255,206 @@ PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/C
r8deVl5c1RxYIigL9zC2L7F8AjEA8GE8p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh
4rsUecrNIdSUtUlD
-----END CERTIFICATE-----
+
+Telia Root CA v2
+================
+-----BEGIN CERTIFICATE-----
+MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQxCzAJBgNVBAYT
+AkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2
+MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQK
+DBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZI
+hvcNAQEBBQADggIPADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ7
+6zBqAMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9vVYiQJ3q
+9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9lRdU2HhE8Qx3FZLgmEKn
+pNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTODn3WhUidhOPFZPY5Q4L15POdslv5e2QJl
+tI5c0BE0312/UqeBAMN/mUWZFdUXyApT7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW
+5olWK8jjfN7j/4nlNW4o6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNr
+RBH0pUPCTEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6WT0E
+BXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63RDolUK5X6wK0dmBR4
+M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZIpEYslOqodmJHixBTB0hXbOKSTbau
+BcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGjYzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7W
+xy+G2CQ5MB0GA1UdDgQWBBRyrOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYD
+VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ
+8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi0f6X+J8wfBj5
+tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMMA8iZGok1GTzTyVR8qPAs5m4H
+eW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBSSRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+C
+y748fdHif64W1lZYudogsYMVoe+KTTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygC
+QMez2P2ccGrGKMOF6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15
+h2Er3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMtTy3EHD70
+sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pTVmBds9hCG1xLEooc6+t9
+xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAWysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQ
+raVplI/owd8k+BsHMYeB2F326CjYSlKArBPuUBQemMc=
+-----END CERTIFICATE-----
+
+D-TRUST BR Root CA 1 2020
+=========================
+-----BEGIN CERTIFICATE-----
+MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE
+RTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEJSIFJvb3QgQ0EgMSAy
+MDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNV
+BAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAG
+ByqGSM49AgEGBSuBBAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7
+dPYSzuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0QVK5buXu
+QqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/VbNafAkl1bK6CKBrqx9t
+MA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu
+bmV0L2NybC9kLXRydXN0X2JyX3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj
+dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP
+PUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD
+AwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFWwKrY7RjEsK70Pvom
+AjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHVdWNbFJWcHwHP2NVypw87
+-----END CERTIFICATE-----
+
+D-TRUST EV Root CA 1 2020
+=========================
+-----BEGIN CERTIFICATE-----
+MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQswCQYDVQQGEwJE
+RTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRSVVNUIEVWIFJvb3QgQ0EgMSAy
+MDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNV
+BAoTDEQtVHJ1c3QgR21iSDEiMCAGA1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAG
+ByqGSM49AgEGBSuBBAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8
+ZRCC/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rDwpdhQntJ
+raOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3OqQo5FD4pPfsazK2/umL
+MA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6gPKA6hjhodHRwOi8vY3JsLmQtdHJ1c3Qu
+bmV0L2NybC9kLXRydXN0X2V2X3Jvb3RfY2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVj
+dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxP
+PUQtVHJ1c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjOPQQD
+AwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CAy/m0sRtW9XLS/BnR
+AjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJbgfM0agPnIjhQW+0ZT0MW
+-----END CERTIFICATE-----
+
+DigiCert TLS ECC P384 Root G5
+=============================
+-----BEGIN CERTIFICATE-----
+MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURpZ2lDZXJ0IFRMUyBFQ0MgUDM4
+NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMx
+FzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQg
+Um9vdCBHNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1Tzvd
+lHJS7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp0zVozptj
+n4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICISB4CIfBFqMA4GA1UdDwEB
+/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQCJao1H5+z8blUD2Wds
+Jk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQLgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIx
+AJSdYsiJvRmEFOml+wG4DXZDjC5Ty3zfDBeWUA==
+-----END CERTIFICATE-----
+
+DigiCert TLS RSA4096 Root G5
+============================
+-----BEGIN CERTIFICATE-----
+MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBNMQswCQYDVQQG
+EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0
+MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcNNDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2
+IFJvb3QgRzUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS8
+7IE+ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG02C+JFvuU
+AT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgpwgscONyfMXdcvyej/Ces
+tyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZMpG2T6T867jp8nVid9E6P/DsjyG244gXa
+zOvswzH016cpVIDPRFtMbzCe88zdH5RDnU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnV
+DdXifBBiqmvwPXbzP6PosMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9q
+TXeXAaDxZre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cdLvvy
+z6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvXKyY//SovcfXWJL5/
+MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNeXoVPzthwiHvOAbWWl9fNff2C+MIk
+wcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPLtgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4E
+FgQUUTMc7TZArxfTJc1paPKvTiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8w
+DQYJKoZIhvcNAQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw
+GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7HPNtQOa27PShN
+lnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLFO4uJ+DQtpBflF+aZfTCIITfN
+MBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQREtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/
+u4cnYiWB39yhL/btp/96j1EuMPikAdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9G
+OUrYU9DzLjtxpdRv/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh
+47a+p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilwMUc/dNAU
+FvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WFqUITVuwhd4GTWgzqltlJ
+yqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCKovfepEWFJqgejF0pW8hL2JpqA15w8oVP
+bEtoL8pU9ozaMv7Da4M/OMZ+
+-----END CERTIFICATE-----
+
+Certainly Root R1
+=================
+-----BEGIN CERTIFICATE-----
+MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAwPTELMAkGA1UE
+BhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2VydGFpbmx5IFJvb3QgUjEwHhcN
+MjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2Vy
+dGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
+ADCCAgoCggIBANA21B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O
+5MQTvqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbedaFySpvXl
+8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b01C7jcvk2xusVtyWMOvwl
+DbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGI
+XsXwClTNSaa/ApzSRKft43jvRl5tcdF5cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkN
+KPl6I7ENPT2a/Z2B7yyQwHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQ
+AjeZjOVJ6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA2Cnb
+rlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyHWyf5QBGenDPBt+U1
+VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMReiFPCyEQtkA6qyI6BJyLm4SGcprS
+p6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
+DgQWBBTgqj8ljZ9EXME66C6ud0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAsz
+HQNTVfSVcOQrPbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d
+8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi1wrykXprOQ4v
+MMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrdrRT90+7iIgXr0PK3aBLXWopB
+GsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9ditaY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+
+gjwN/KUD+nsa2UUeYNrEjvn8K8l7lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgH
+JBu6haEaBQmAupVjyTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7
+fpYnKx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLyyCwzk5Iw
+x06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5nwXARPbv0+Em34yaXOp/S
+X3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6OV+KmalBWQewLK8=
+-----END CERTIFICATE-----
+
+Certainly Root E1
+=================
+-----BEGIN CERTIFICATE-----
+MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQswCQYDVQQGEwJV
+UzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlubHkgUm9vdCBFMTAeFw0yMTA0
+MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJBgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlu
+bHkxGjAYBgNVBAMTEUNlcnRhaW5seSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4
+fxzf7flHh4axpMCK+IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9
+YBk2QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8EBAMCAQYw
+DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4hevIIgcwCgYIKoZIzj0E
+AwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozmut6Dacpps6kFtZaSF4fC0urQe87YQVt8
+rgIwRt7qy12a7DLCZRawTDBcMPPaTnOGBtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR
+-----END CERTIFICATE-----
+
+E-Tugra Global Root CA RSA v3
+=============================
+-----BEGIN CERTIFICATE-----
+MIIF8zCCA9ugAwIBAgIUDU3FzRYilZYIfrgLfxUGNPt5EDQwDQYJKoZIhvcNAQELBQAwgYAxCzAJ
+BgNVBAYTAlRSMQ8wDQYDVQQHEwZBbmthcmExGTAXBgNVBAoTEEUtVHVncmEgRUJHIEEuUy4xHTAb
+BgNVBAsTFEUtVHVncmEgVHJ1c3QgQ2VudGVyMSYwJAYDVQQDEx1FLVR1Z3JhIEdsb2JhbCBSb290
+IENBIFJTQSB2MzAeFw0yMDAzMTgwOTA3MTdaFw00NTAzMTIwOTA3MTdaMIGAMQswCQYDVQQGEwJU
+UjEPMA0GA1UEBxMGQW5rYXJhMRkwFwYDVQQKExBFLVR1Z3JhIEVCRyBBLlMuMR0wGwYDVQQLExRF
+LVR1Z3JhIFRydXN0IENlbnRlcjEmMCQGA1UEAxMdRS1UdWdyYSBHbG9iYWwgUm9vdCBDQSBSU0Eg
+djMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCiZvCJt3J77gnJY9LTQ91ew6aEOErx
+jYG7FL1H6EAX8z3DeEVypi6Q3po61CBxyryfHUuXCscxuj7X/iWpKo429NEvx7epXTPcMHD4QGxL
+sqYxYdE0PD0xesevxKenhOGXpOhL9hd87jwH7eKKV9y2+/hDJVDqJ4GohryPUkqWOmAalrv9c/SF
+/YP9f4RtNGx/ardLAQO/rWm31zLZ9Vdq6YaCPqVmMbMWPcLzJmAy01IesGykNz709a/r4d+ABs8q
+QedmCeFLl+d3vSFtKbZnwy1+7dZ5ZdHPOrbRsV5WYVB6Ws5OUDGAA5hH5+QYfERaxqSzO8bGwzrw
+bMOLyKSRBfP12baqBqG3q+Sx6iEUXIOk/P+2UNOMEiaZdnDpwA+mdPy70Bt4znKS4iicvObpCdg6
+04nmvi533wEKb5b25Y08TVJ2Glbhc34XrD2tbKNSEhhw5oBOM/J+JjKsBY04pOZ2PJ8QaQ5tndLB
+eSBrW88zjdGUdjXnXVXHt6woq0bM5zshtQoK5EpZ3IE1S0SVEgpnpaH/WwAH0sDM+T/8nzPyAPiM
+bIedBi3x7+PmBvrFZhNb/FAHnnGGstpvdDDPk1Po3CLW3iAfYY2jLqN4MpBs3KwytQXk9TwzDdbg
+h3cXTJ2w2AmoDVf3RIXwyAS+XF1a4xeOVGNpf0l0ZAWMowIDAQABo2MwYTAPBgNVHRMBAf8EBTAD
+AQH/MB8GA1UdIwQYMBaAFLK0ruYt9ybVqnUtdkvAG1Mh0EjvMB0GA1UdDgQWBBSytK7mLfcm1ap1
+LXZLwBtTIdBI7zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAImocn+M684uGMQQ
+gC0QDP/7FM0E4BQ8Tpr7nym/Ip5XuYJzEmMmtcyQ6dIqKe6cLcwsmb5FJ+Sxce3kOJUxQfJ9emN4
+38o2Fi+CiJ+8EUdPdk3ILY7r3y18Tjvarvbj2l0Upq7ohUSdBm6O++96SmotKygY/r+QLHUWnw/q
+ln0F7psTpURs+APQ3SPh/QMSEgj0GDSz4DcLdxEBSL9htLX4GdnLTeqjjO/98Aa1bZL0SmFQhO3s
+SdPkvmjmLuMxC1QLGpLWgti2omU8ZgT5Vdps+9u1FGZNlIM7zR6mK7L+d0CGq+ffCsn99t2HVhjY
+sCxVYJb6CH5SkPVLpi6HfMsg2wY+oF0Dd32iPBMbKaITVaA9FCKvb7jQmhty3QUBjYZgv6Rn7rWl
+DdF/5horYmbDB7rnoEgcOMPpRfunf/ztAmgayncSd6YAVSgU7NbHEqIbZULpkejLPoeJVF3Zr52X
+nGnnCv8PWniLYypMfUeUP95L6VPQMPHF9p5J3zugkaOj/s1YzOrfr28oO6Bpm4/srK4rVJ2bBLFH
+IK+WEj5jlB0E5y67hscMmoi/dkfv97ALl2bSRM9gUgfh1SxKOidhd8rXj+eHDjD/DLsE4mHDosiX
+YY60MGo8bcIHX0pzLz/5FooBZu+6kcpSV3uu1OYP3Qt6f4ueJiDPO++BcYNZ
+-----END CERTIFICATE-----
+
+E-Tugra Global Root CA ECC v3
+=============================
+-----BEGIN CERTIFICATE-----
+MIICpTCCAiqgAwIBAgIUJkYZdzHhT28oNt45UYbm1JeIIsEwCgYIKoZIzj0EAwMwgYAxCzAJBgNV
+BAYTAlRSMQ8wDQYDVQQHEwZBbmthcmExGTAXBgNVBAoTEEUtVHVncmEgRUJHIEEuUy4xHTAbBgNV
+BAsTFEUtVHVncmEgVHJ1c3QgQ2VudGVyMSYwJAYDVQQDEx1FLVR1Z3JhIEdsb2JhbCBSb290IENB
+IEVDQyB2MzAeFw0yMDAzMTgwOTQ2NThaFw00NTAzMTIwOTQ2NThaMIGAMQswCQYDVQQGEwJUUjEP
+MA0GA1UEBxMGQW5rYXJhMRkwFwYDVQQKExBFLVR1Z3JhIEVCRyBBLlMuMR0wGwYDVQQLExRFLVR1
+Z3JhIFRydXN0IENlbnRlcjEmMCQGA1UEAxMdRS1UdWdyYSBHbG9iYWwgUm9vdCBDQSBFQ0MgdjMw
+djAQBgcqhkjOPQIBBgUrgQQAIgNiAASOmCm/xxAeJ9urA8woLNheSBkQKczLWYHMjLiSF4mDKpL2
+w6QdTGLVn9agRtwcvHbB40fQWxPa56WzZkjnIZpKT4YKfWzqTTKACrJ6CZtpS5iB4i7sAnCWH/31
+Rs7K3IKjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU/4Ixcj75xGZsrTie0bBRiKWQ
+zPUwHQYDVR0OBBYEFP+CMXI++cRmbK04ntGwUYilkMz1MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjO
+PQQDAwNpADBmAjEA5gVYaWHlLcoNy/EZCL3W/VGSGn5jVASQkZo1kTmZ+gepZpO6yGjUij/67W4W
+Aie3AjEA3VoXK3YdZUKWpqxdinlW2Iob35reX8dQj7FbcQwm32pAAOwzkSFxvmjkI6TZraE3
+-----END CERTIFICATE-----
diff --git a/thirdparty/glslang/glslang/OSDependent/Unix/ossource.cpp b/thirdparty/glslang/glslang/OSDependent/Unix/ossource.cpp
index 81da99c2c4..1cbd616e98 100644
--- a/thirdparty/glslang/glslang/OSDependent/Unix/ossource.cpp
+++ b/thirdparty/glslang/glslang/OSDependent/Unix/ossource.cpp
@@ -66,43 +66,6 @@ static void DetachThreadLinux(void *)
}
//
-// Registers cleanup handler, sets cancel type and state, and executes the thread specific
-// cleanup handler. This function will be called in the Standalone.cpp for regression
-// testing. When OpenGL applications are run with the driver code, Linux OS does the
-// thread cleanup.
-//
-void OS_CleanupThreadData(void)
-{
-#if defined(__ANDROID__) || defined(__Fuchsia__)
- DetachThreadLinux(NULL);
-#else
- int old_cancel_state, old_cancel_type;
- void *cleanupArg = NULL;
-
- //
- // Set thread cancel state and push cleanup handler.
- //
- pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancel_state);
- pthread_cleanup_push(DetachThreadLinux, (void *) cleanupArg);
-
- //
- // Put the thread in deferred cancellation mode.
- //
- pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &old_cancel_type);
-
- //
- // Pop cleanup handler and execute it prior to unregistering the cleanup handler.
- //
- pthread_cleanup_pop(1);
-
- //
- // Restore the thread's previous cancellation mode.
- //
- pthread_setcanceltype(old_cancel_state, NULL);
-#endif
-}
-
-//
// Thread Local Storage Operations
//
inline OS_TLSIndex PthreadKeyToTLSIndex(pthread_key_t key)
diff --git a/thirdparty/glslang/glslang/OSDependent/osinclude.h b/thirdparty/glslang/glslang/OSDependent/osinclude.h
index 218abe4f23..fcfeff2cc4 100644
--- a/thirdparty/glslang/glslang/OSDependent/osinclude.h
+++ b/thirdparty/glslang/glslang/OSDependent/osinclude.h
@@ -54,8 +54,6 @@ void ReleaseGlobalLock();
typedef unsigned int (*TThreadEntrypoint)(void*);
-void OS_CleanupThreadData(void);
-
void OS_DumpMemoryCounters();
} // end namespace glslang
diff --git a/thirdparty/glslang/patches/unused_cleanup.diff b/thirdparty/glslang/patches/unused_cleanup.diff
new file mode 100644
index 0000000000..3e9a9c23f9
--- /dev/null
+++ b/thirdparty/glslang/patches/unused_cleanup.diff
@@ -0,0 +1,61 @@
+diff --git a/thirdparty/glslang/glslang/OSDependent/Unix/ossource.cpp b/thirdparty/glslang/glslang/OSDependent/Unix/ossource.cpp
+index 81da99c2c4..1cbd616e98 100644
+--- a/thirdparty/glslang/glslang/OSDependent/Unix/ossource.cpp
++++ b/thirdparty/glslang/glslang/OSDependent/Unix/ossource.cpp
+@@ -65,43 +65,6 @@ static void DetachThreadLinux(void *)
+ DetachThread();
+ }
+
+-//
+-// Registers cleanup handler, sets cancel type and state, and executes the thread specific
+-// cleanup handler. This function will be called in the Standalone.cpp for regression
+-// testing. When OpenGL applications are run with the driver code, Linux OS does the
+-// thread cleanup.
+-//
+-void OS_CleanupThreadData(void)
+-{
+-#if defined(__ANDROID__) || defined(__Fuchsia__)
+- DetachThreadLinux(NULL);
+-#else
+- int old_cancel_state, old_cancel_type;
+- void *cleanupArg = NULL;
+-
+- //
+- // Set thread cancel state and push cleanup handler.
+- //
+- pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancel_state);
+- pthread_cleanup_push(DetachThreadLinux, (void *) cleanupArg);
+-
+- //
+- // Put the thread in deferred cancellation mode.
+- //
+- pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &old_cancel_type);
+-
+- //
+- // Pop cleanup handler and execute it prior to unregistering the cleanup handler.
+- //
+- pthread_cleanup_pop(1);
+-
+- //
+- // Restore the thread's previous cancellation mode.
+- //
+- pthread_setcanceltype(old_cancel_state, NULL);
+-#endif
+-}
+-
+ //
+ // Thread Local Storage Operations
+ //
+diff --git a/thirdparty/glslang/glslang/OSDependent/osinclude.h b/thirdparty/glslang/glslang/OSDependent/osinclude.h
+index 218abe4f23..fcfeff2cc4 100644
+--- a/thirdparty/glslang/glslang/OSDependent/osinclude.h
++++ b/thirdparty/glslang/glslang/OSDependent/osinclude.h
+@@ -54,8 +54,6 @@ void ReleaseGlobalLock();
+
+ typedef unsigned int (*TThreadEntrypoint)(void*);
+
+-void OS_CleanupThreadData(void);
+-
+ void OS_DumpMemoryCounters();
+
+ } // end namespace glslang
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh
index 7c34bb3c93..7f58fac8b8 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh
@@ -140,6 +140,13 @@ struct CursivePosFormat1
unsigned int i = skippy_iter.idx;
unsigned int j = buffer->idx;
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "cursive attaching glyph at %d to glyph at %d",
+ i, j);
+ }
+
buffer->unsafe_to_break (i, j + 1);
float entry_x, entry_y, exit_x, exit_y;
(this+prev_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y);
@@ -231,6 +238,13 @@ struct CursivePosFormat1
pos[parent].x_offset = 0;
}
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "cursive attached glyph at %d to glyph at %d",
+ i, j);
+ }
+
buffer->idx++;
return_trace (true);
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh
index f8cddd1991..cb5e8b2689 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh
@@ -39,6 +39,13 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y);
glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "attaching mark glyph at %d to glyph at %d",
+ c->buffer->idx, glyph_pos);
+ }
+
hb_glyph_position_t &o = buffer->cur_pos();
o.x_offset = roundf (base_x - mark_x);
o.y_offset = roundf (base_y - mark_y);
@@ -46,6 +53,13 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "attached mark glyph at %d to glyph at %d",
+ c->buffer->idx, glyph_pos);
+ }
+
buffer->idx++;
return_trace (true);
}
@@ -83,10 +97,11 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Cove
}
};
-static void Markclass_closure_and_remap_indexes (const Coverage &mark_coverage,
- const MarkArray &mark_array,
- const hb_set_t &glyphset,
- hb_map_t* klass_mapping /* INOUT */)
+HB_INTERNAL inline
+void Markclass_closure_and_remap_indexes (const Coverage &mark_coverage,
+ const MarkArray &mark_array,
+ const hb_set_t &glyphset,
+ hb_map_t* klass_mapping /* INOUT */)
{
hb_set_t orig_classes;
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh
index f58bcb1b30..a80fe0c226 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh
@@ -217,10 +217,23 @@ struct PairPosFormat2_4
}
bail:
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "kerning glyphs at %d,%d",
+ c->buffer->idx, skippy_iter.idx);
+ }
applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos());
applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "kerned glyphs at %d,%d",
+ c->buffer->idx, skippy_iter.idx);
+ }
+
success:
if (applied_first || applied_second)
buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1);
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh
index 58ba4de6c1..4578fbd1d6 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh
@@ -109,12 +109,28 @@ struct PairSet
record_size);
if (record)
{
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "kerning glyphs at %d,%d",
+ c->buffer->idx, pos);
+ }
+
bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "kerned glyphs at %d,%d",
+ c->buffer->idx, pos);
+ }
+
if (applied_first || applied_second)
buffer->unsafe_to_break (buffer->idx, pos + 1);
if (len2)
pos++;
+
buffer->idx = pos;
return_trace (true);
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairValueRecord.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairValueRecord.hh
index 55de5abebf..bd95abde16 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairValueRecord.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/PairValueRecord.hh
@@ -1,6 +1,8 @@
#ifndef OT_LAYOUT_GPOS_PAIRVALUERECORD_HH
#define OT_LAYOUT_GPOS_PAIRVALUERECORD_HH
+#include "ValueFormat.hh"
+
namespace OT {
namespace Layout {
namespace GPOS_impl {
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh
index c0e7d29cea..7cbdf6dc6c 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh
@@ -39,12 +39,10 @@ struct SinglePosFormat1
{
if (!valueFormat.has_device ()) return;
- auto it =
- + hb_iter (this+coverage)
- | hb_filter (c->glyph_set)
- ;
+ hb_set_t intersection;
+ (this+coverage).intersect_set (*c->glyph_set, intersection);
+ if (!intersection) return;
- if (!it) return;
valueFormat.collect_variation_indices (c, this, values.as_array (valueFormat.get_len ()));
}
@@ -62,8 +60,22 @@ struct SinglePosFormat1
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "positioning glyph at %d",
+ c->buffer->idx);
+ }
+
valueFormat.apply_value (c, this, values, buffer->cur_pos());
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "positioned glyph at %d",
+ c->buffer->idx);
+ }
+
buffer->idx++;
return_trace (true);
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh
index 0d038b4422..518fa9dcb0 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh
@@ -70,10 +70,24 @@ struct SinglePosFormat2
if (likely (index >= valueCount)) return_trace (false);
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "positioning glyph at %d",
+ c->buffer->idx);
+ }
+
valueFormat.apply_value (c, this,
&values[index * valueFormat.get_len ()],
buffer->cur_pos());
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "positioned glyph at %d",
+ c->buffer->idx);
+ }
+
buffer->idx++;
return_trace (true);
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh
index a5dcb65359..4a9e9672eb 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh
@@ -57,8 +57,23 @@ struct AlternateSet
if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "replacing glyph at %d (alternate substitution)",
+ c->buffer->idx);
+ }
+
c->replace_glyph (alternates[alt_index - 1]);
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "replaced glyph at %d (alternate substitution)",
+ c->buffer->idx - 1);
+ }
+
return_trace (true);
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh
index 22ed65f858..f373d921b5 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh
@@ -64,7 +64,24 @@ struct Ligature
* as a "ligated" substitution. */
if (unlikely (count == 1))
{
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "replacing glyph at %d (ligature substitution)",
+ c->buffer->idx);
+ }
+
c->replace_glyph (ligGlyph);
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "replaced glyph at %d (ligature substitution)",
+ c->buffer->idx - 1);
+ }
+
return_trace (true);
}
@@ -85,6 +102,31 @@ struct Ligature
return_trace (false);
}
+ unsigned pos = 0;
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ unsigned delta = c->buffer->sync_so_far ();
+
+ pos = c->buffer->idx;
+
+ char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0};
+ char *p = buf;
+
+ match_end += delta;
+ for (unsigned i = 0; i < count; i++)
+ {
+ match_positions[i] += delta;
+ if (i)
+ *p++ = ',';
+ sprintf (p, "%u", match_positions[i]);
+ p += strlen(p);
+ }
+
+ c->buffer->message (c->font,
+ "ligating glyphs at %s",
+ buf);
+ }
+
ligate_input (c,
count,
match_positions,
@@ -92,6 +134,14 @@ struct Ligature
ligGlyph,
total_component_count);
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "ligated glyph at %d",
+ pos);
+ }
+
return_trace (true);
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
index 1d27df95dd..a23e92028e 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
@@ -131,7 +131,23 @@ struct ReverseChainSingleSubstFormat1
c->buffer->idx + 1, &end_index))
{
c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "replacing glyph at %d (reverse chaining substitution)",
+ c->buffer->idx);
+ }
+
c->replace_glyph_inplace (substitute[index]);
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "replaced glyph at %d (reverse chaining substitution)",
+ c->buffer->idx);
+ }
+
/* Note: We DON'T decrease buffer->idx. The main loop does it
* for us. This is useful for preventing surprises if someone
* calls us through a Context lookup. */
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh
index c5cd15bb23..3d84a5e6ea 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh
@@ -40,17 +40,58 @@ struct Sequence
* as a "multiplied" substitution. */
if (unlikely (count == 1))
{
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "replacing glyph at %d (multiple substitution)",
+ c->buffer->idx);
+ }
+
c->replace_glyph (substitute.arrayZ[0]);
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "replaced glyph at %d (multiple subtitution)",
+ c->buffer->idx - 1);
+ }
+
return_trace (true);
}
/* Spec disallows this, but Uniscribe allows it.
* https://github.com/harfbuzz/harfbuzz/issues/253 */
else if (unlikely (count == 0))
{
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "deleting glyph at %d (multiple substitution)",
+ c->buffer->idx);
+ }
+
c->buffer->delete_glyph ();
+
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "deleted glyph at %d (multiple substitution)",
+ c->buffer->idx);
+ }
+
return_trace (true);
}
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "multiplying glyph at %d",
+ c->buffer->idx);
+ }
+
unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur());
@@ -65,6 +106,26 @@ struct Sequence
}
c->buffer->skip_glyph ();
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->sync_so_far ();
+
+ char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0};
+ char *p = buf;
+
+ for (unsigned i = c->buffer->idx - count; i < c->buffer->idx; i++)
+ {
+ if (buf < p)
+ *p++ = ',';
+ sprintf (p, "%u", i);
+ p += strlen(p);
+ }
+
+ c->buffer->message (c->font,
+ "multiplied glyphs at %s",
+ buf);
+ }
+
return_trace (true);
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh
index dd44595741..4b17243d81 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh
@@ -45,6 +45,18 @@ struct SingleSubstFormat1_3
hb_set_t intersection;
(this+coverage).intersect_set (c->parent_active_glyphs (), intersection);
+ /* In degenerate fuzzer-found fonts, but not real fonts,
+ * this table can keep adding new glyphs in each round of closure.
+ * Refuse to close-over, if it maps glyph range to overlapping range. */
+ hb_codepoint_t min_before = intersection.get_min ();
+ hb_codepoint_t max_before = intersection.get_max ();
+ hb_codepoint_t min_after = (min_before + d) & mask;
+ hb_codepoint_t max_after = (max_before + d) & mask;
+ if ((this+coverage).get_population () >= max_before - min_before &&
+ ((min_before <= min_after && min_after <= max_before) ||
+ (min_before <= max_after && max_after <= max_before)))
+ return;
+
+ hb_iter (intersection)
| hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; })
| hb_sink (c->output)
@@ -82,8 +94,23 @@ struct SingleSubstFormat1_3
glyph_id = (glyph_id + d) & mask;
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "replacing glyph at %d (single substitution)",
+ c->buffer->idx);
+ }
+
c->replace_glyph (glyph_id);
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "replaced glyph at %d (single substitution)",
+ c->buffer->idx - 1);
+ }
+
return_trace (true);
}
diff --git a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh
index 386419a2a5..fb1e90d03e 100644
--- a/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh
+++ b/thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh
@@ -68,8 +68,23 @@ struct SingleSubstFormat2_4
if (unlikely (index >= substitute.len)) return_trace (false);
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "replacing glyph at %d (single substitution)",
+ c->buffer->idx);
+ }
+
c->replace_glyph (substitute[index]);
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ c->buffer->message (c->font,
+ "replaced glyph at %d (single substitution)",
+ c->buffer->idx - 1);
+ }
+
return_trace (true);
}
diff --git a/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh b/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh
index abe4c8330c..98c2ee4e73 100644
--- a/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh
+++ b/thirdparty/harfbuzz/src/OT/glyf/CompositeGlyph.hh
@@ -26,7 +26,9 @@ struct CompositeGlyphRecord
OVERLAP_COMPOUND = 0x0400,
SCALED_COMPONENT_OFFSET = 0x0800,
UNSCALED_COMPONENT_OFFSET = 0x1000,
+#ifndef HB_NO_BEYOND_64K
GID_IS_24BIT = 0x2000
+#endif
};
public:
@@ -34,7 +36,9 @@ struct CompositeGlyphRecord
{
unsigned int size = min_size;
/* glyphIndex is 24bit instead of 16bit */
+#ifndef HB_NO_BEYOND_64K
if (flags & GID_IS_24BIT) size += HBGlyphID24::static_size - HBGlyphID16::static_size;
+#endif
/* arg1 and 2 are int16 */
if (flags & ARG_1_AND_2_ARE_WORDS) size += 4;
/* arg1 and 2 are int8 */
@@ -64,9 +68,11 @@ struct CompositeGlyphRecord
void get_anchor_points (unsigned int &point1, unsigned int &point2) const
{
const auto *p = &StructAfter<const HBUINT8> (flags);
+#ifndef HB_NO_BEYOND_64K
if (flags & GID_IS_24BIT)
p += HBGlyphID24::static_size;
else
+#endif
p += HBGlyphID16::static_size;
if (flags & ARG_1_AND_2_ARE_WORDS)
{
@@ -109,9 +115,11 @@ struct CompositeGlyphRecord
matrix[1] = matrix[2] = 0.f;
const auto *p = &StructAfter<const HBINT8> (flags);
+#ifndef HB_NO_BEYOND_64K
if (flags & GID_IS_24BIT)
p += HBGlyphID24::static_size;
else
+#endif
p += HBGlyphID16::static_size;
int tx, ty;
if (flags & ARG_1_AND_2_ARE_WORDS)
@@ -158,16 +166,20 @@ struct CompositeGlyphRecord
public:
hb_codepoint_t get_gid () const
{
+#ifndef HB_NO_BEYOND_64K
if (flags & GID_IS_24BIT)
return StructAfter<const HBGlyphID24> (flags);
else
+#endif
return StructAfter<const HBGlyphID16> (flags);
}
void set_gid (hb_codepoint_t gid)
{
+#ifndef HB_NO_BEYOND_64K
if (flags & GID_IS_24BIT)
StructAfter<HBGlyphID24> (flags) = gid;
else
+#endif
/* TODO assert? */
StructAfter<HBGlyphID16> (flags) = gid;
}
diff --git a/thirdparty/harfbuzz/src/graph/coverage-graph.hh b/thirdparty/harfbuzz/src/graph/coverage-graph.hh
new file mode 100644
index 0000000000..1d9fd0eb5b
--- /dev/null
+++ b/thirdparty/harfbuzz/src/graph/coverage-graph.hh
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2022 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#include "graph.hh"
+#include "../OT/Layout/Common/Coverage.hh"
+
+#ifndef GRAPH_COVERAGE_GRAPH_HH
+#define GRAPH_COVERAGE_GRAPH_HH
+
+namespace graph {
+
+struct CoverageFormat1 : public OT::Layout::Common::CoverageFormat1_3<SmallTypes>
+{
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ constexpr unsigned min_size = OT::Layout::Common::CoverageFormat1_3<SmallTypes>::min_size;
+ if (vertex_len < min_size) return false;
+ return vertex_len >= min_size + glyphArray.get_size () - glyphArray.len.get_size ();
+ }
+};
+
+struct CoverageFormat2 : public OT::Layout::Common::CoverageFormat2_4<SmallTypes>
+{
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ constexpr unsigned min_size = OT::Layout::Common::CoverageFormat2_4<SmallTypes>::min_size;
+ if (vertex_len < min_size) return false;
+ return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size ();
+ }
+};
+
+struct Coverage : public OT::Layout::Common::Coverage
+{
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ if (vertex_len < OT::Layout::Common::Coverage::min_size) return false;
+ switch (u.format)
+ {
+ case 1: return ((CoverageFormat1*)this)->sanitize (vertex);
+ case 2: return ((CoverageFormat2*)this)->sanitize (vertex);
+#ifndef HB_NO_BORING_EXPANSION
+ // Not currently supported
+ case 3:
+ case 4:
+#endif
+ default: return false;
+ }
+ }
+};
+
+
+}
+
+#endif // GRAPH_COVERAGE_GRAPH_HH
diff --git a/thirdparty/harfbuzz/src/graph/graph.hh b/thirdparty/harfbuzz/src/graph/graph.hh
index 49638f34a7..b3aef558a2 100644
--- a/thirdparty/harfbuzz/src/graph/graph.hh
+++ b/thirdparty/harfbuzz/src/graph/graph.hh
@@ -24,6 +24,10 @@
* Google Author(s): Garret Rieger
*/
+#include "../hb-set.hh"
+#include "../hb-priority-queue.hh"
+#include "../hb-serialize.hh"
+
#ifndef GRAPH_GRAPH_HH
#define GRAPH_GRAPH_HH
@@ -76,6 +80,22 @@ struct graph_t
}
}
+ void remove_real_link (unsigned child_index, const void* offset)
+ {
+ for (unsigned i = 0; i < obj.real_links.length; i++)
+ {
+ auto& link = obj.real_links[i];
+ if (link.objidx != child_index)
+ continue;
+
+ if ((obj.head + link.position) != offset)
+ continue;
+
+ obj.real_links.remove (i);
+ return;
+ }
+ }
+
void remap_parents (const hb_vector_t<unsigned>& id_map)
{
for (unsigned i = 0; i < parents.length; i++)
@@ -107,6 +127,10 @@ struct graph_t
return priority >= 3;
}
+ size_t table_size () const {
+ return obj.tail - obj.head;
+ }
+
int64_t modified_distance (unsigned order) const
{
// TODO(garretrieger): once priority is high enough, should try
@@ -199,13 +223,24 @@ struct graph_t
return vertices_.length - 1;
}
- const hb_serialize_context_t::object_t& object(unsigned i) const
+ const hb_serialize_context_t::object_t& object (unsigned i) const
{
return vertices_[i].obj;
}
/*
* Generates a new topological sorting of graph ordered by the shortest
+ * distance to each node if positions are marked as invalid.
+ */
+ void sort_shortest_distance_if_needed ()
+ {
+ if (!positions_invalid) return;
+ sort_shortest_distance ();
+ }
+
+
+ /*
+ * Generates a new topological sorting of graph ordered by the shortest
* distance to each node.
*/
void sort_shortest_distance ()
@@ -256,12 +291,12 @@ struct graph_t
check_success (!queue.in_error ());
check_success (!sorted_graph.in_error ());
- if (!check_success (new_id == -1))
- print_orphaned_nodes ();
remap_all_obj_indices (id_map, &sorted_graph);
-
hb_swap (vertices_, sorted_graph);
+
+ if (!check_success (new_id == -1))
+ print_orphaned_nodes ();
}
/*
@@ -310,6 +345,22 @@ struct graph_t
}
}
+ unsigned index_for_offset(unsigned node_idx, const void* offset) const
+ {
+ const auto& node = object (node_idx);
+ if (offset < node.head || offset >= node.tail) return -1;
+
+ for (const auto& link : node.real_links)
+ {
+ if (offset != node.head + link.position)
+ continue;
+ return link.objidx;
+ }
+
+ return -1;
+ }
+
+
/*
* Assign unique space numbers to each connected subgraph of 24 bit and/or 32 bit offset(s).
* Currently, this is implemented specifically tailored to the structure of a GPOS/GSUB
@@ -317,6 +368,8 @@ struct graph_t
*/
bool assign_spaces ()
{
+ update_parents ();
+
hb_set_t visited;
hb_set_t roots;
find_space_roots (visited, roots);
@@ -458,6 +511,21 @@ struct graph_t
find_subgraph (link.objidx, subgraph);
}
+ size_t find_subgraph_size (unsigned node_idx, hb_set_t& subgraph, unsigned max_depth = -1)
+ {
+ if (subgraph.has (node_idx)) return 0;
+ subgraph.add (node_idx);
+
+ const auto& o = vertices_[node_idx].obj;
+ size_t size = o.tail - o.head;
+ if (max_depth == 0)
+ return size;
+
+ for (const auto& link : o.all_links ())
+ size += find_subgraph_size (link.objidx, subgraph, max_depth - 1);
+ return size;
+ }
+
/*
* Finds the topmost children of 32bit offsets in the subgraph starting
* at node_idx. Found indices are placed into 'found'.
@@ -475,6 +543,37 @@ struct graph_t
}
/*
+ * Moves the child of old_parent_idx pointed to by old_offset to a new
+ * vertex at the new_offset.
+ */
+ template<typename O>
+ void move_child (unsigned old_parent_idx,
+ const O* old_offset,
+ unsigned new_parent_idx,
+ const O* new_offset)
+ {
+ distance_invalid = true;
+ positions_invalid = true;
+
+ auto& old_v = vertices_[old_parent_idx];
+ auto& new_v = vertices_[new_parent_idx];
+
+ unsigned child_id = index_for_offset (old_parent_idx,
+ old_offset);
+
+ auto* new_link = new_v.obj.real_links.push ();
+ new_link->width = O::static_size;
+ new_link->objidx = child_id;
+ new_link->position = (const char*) new_offset - (const char*) new_v.obj.head;
+
+ auto& child = vertices_[child_id];
+ child.parents.push (new_parent_idx);
+
+ old_v.remove_real_link (child_id, old_offset);
+ child.remove_parent (old_parent_idx);
+ }
+
+ /*
* duplicates all nodes in the subgraph reachable from node_idx. Does not re-assign
* links. index_map is updated with mappings from old id to new id. If a duplication has already
* been performed for a given index, then it will be skipped.
@@ -581,6 +680,39 @@ struct graph_t
return true;
}
+
+ /*
+ * Adds a new node to the graph, not connected to anything.
+ */
+ unsigned new_node (char* head, char* tail)
+ {
+ positions_invalid = true;
+ distance_invalid = true;
+
+ auto* clone = vertices_.push ();
+ if (vertices_.in_error ()) {
+ return -1;
+ }
+
+ clone->obj.head = head;
+ clone->obj.tail = tail;
+ clone->distance = 0;
+ clone->space = 0;
+
+ unsigned clone_idx = vertices_.length - 2;
+
+ // The last object is the root of the graph, so swap back the root to the end.
+ // The root's obj idx does change, however since it's root nothing else refers to it.
+ // all other obj idx's will be unaffected.
+ hb_swap (vertices_[vertices_.length - 2], *clone);
+
+ // Since the root moved, update the parents arrays of all children on the root.
+ for (const auto& l : root ().obj.all_links ())
+ vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ());
+
+ return clone_idx;
+ }
+
/*
* Raises the sorting priority of all children.
*/
diff --git a/thirdparty/harfbuzz/src/graph/gsubgpos-context.cc b/thirdparty/harfbuzz/src/graph/gsubgpos-context.cc
new file mode 100644
index 0000000000..e0ff6ff85f
--- /dev/null
+++ b/thirdparty/harfbuzz/src/graph/gsubgpos-context.cc
@@ -0,0 +1,71 @@
+/*
+ * Copyright © 2022 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#include "gsubgpos-graph.hh"
+
+namespace graph {
+
+gsubgpos_graph_context_t::gsubgpos_graph_context_t (hb_tag_t table_tag_,
+ graph_t& graph_)
+ : table_tag (table_tag_),
+ graph (graph_),
+ lookup_list_index (0),
+ lookups (),
+ buffers ()
+{
+ if (table_tag_ != HB_OT_TAG_GPOS
+ && table_tag_ != HB_OT_TAG_GSUB)
+ return;
+
+ GSTAR* gstar = graph::GSTAR::graph_to_gstar (graph_);
+ if (gstar) {
+ gstar->find_lookups (graph, lookups);
+ lookup_list_index = gstar->get_lookup_list_index (graph_);
+ }
+}
+
+unsigned gsubgpos_graph_context_t::create_node (unsigned size)
+{
+ char* buffer = (char*) hb_calloc (1, size);
+ if (!buffer)
+ return -1;
+
+ buffers.push (buffer);
+
+ return graph.new_node (buffer, buffer + size);
+}
+
+unsigned gsubgpos_graph_context_t::num_non_ext_subtables () {
+ unsigned count = 0;
+ for (auto l : lookups.values ())
+ {
+ if (l->is_extension (table_tag)) continue;
+ count += l->number_of_subtables ();
+ }
+ return count;
+}
+
+}
diff --git a/thirdparty/harfbuzz/src/graph/gsubgpos-context.hh b/thirdparty/harfbuzz/src/graph/gsubgpos-context.hh
new file mode 100644
index 0000000000..49b24198ff
--- /dev/null
+++ b/thirdparty/harfbuzz/src/graph/gsubgpos-context.hh
@@ -0,0 +1,67 @@
+/*
+ * Copyright © 2022 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#include "graph.hh"
+#include "../hb-ot-layout-gsubgpos.hh"
+
+#ifndef GRAPH_GSUBGPOS_CONTEXT_HH
+#define GRAPH_GSUBGPOS_CONTEXT_HH
+
+namespace graph {
+
+struct Lookup;
+
+struct gsubgpos_graph_context_t
+{
+ hb_tag_t table_tag;
+ graph_t& graph;
+ unsigned lookup_list_index;
+ hb_hashmap_t<unsigned, graph::Lookup*> lookups;
+ hb_vector_t<char*> buffers;
+
+ HB_INTERNAL gsubgpos_graph_context_t (hb_tag_t table_tag_,
+ graph_t& graph_);
+
+ ~gsubgpos_graph_context_t ()
+ {
+ for (char* b : buffers)
+ hb_free (b);
+ }
+
+ HB_INTERNAL unsigned create_node (unsigned size);
+
+ void add_buffer (char* buffer)
+ {
+ buffers.push (buffer);
+ }
+
+ private:
+ HB_INTERNAL unsigned num_non_ext_subtables ();
+};
+
+}
+
+#endif // GRAPH_GSUBGPOS_CONTEXT
diff --git a/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh b/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh
new file mode 100644
index 0000000000..afa1152c44
--- /dev/null
+++ b/thirdparty/harfbuzz/src/graph/gsubgpos-graph.hh
@@ -0,0 +1,351 @@
+/*
+ * Copyright © 2022 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#include "graph.hh"
+#include "../hb-ot-layout-gsubgpos.hh"
+#include "../OT/Layout/GSUB/ExtensionSubst.hh"
+#include "gsubgpos-context.hh"
+#include "pairpos-graph.hh"
+
+#ifndef GRAPH_GSUBGPOS_GRAPH_HH
+#define GRAPH_GSUBGPOS_GRAPH_HH
+
+namespace graph {
+
+struct Lookup;
+
+template<typename T>
+struct ExtensionFormat1 : public OT::ExtensionFormat1<T>
+{
+ void reset(unsigned type)
+ {
+ this->format = 1;
+ this->extensionLookupType = type;
+ this->extensionOffset = 0;
+ }
+
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ return vertex_len >= OT::ExtensionFormat1<T>::static_size;
+ }
+
+ unsigned get_lookup_type () const
+ {
+ return this->extensionLookupType;
+ }
+
+ unsigned get_subtable_index (graph_t& graph, unsigned this_index) const
+ {
+ return graph.index_for_offset (this_index, &this->extensionOffset);
+ }
+};
+
+struct Lookup : public OT::Lookup
+{
+ unsigned number_of_subtables () const
+ {
+ return subTable.len;
+ }
+
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ if (vertex_len < OT::Lookup::min_size) return false;
+ return vertex_len >= this->get_size ();
+ }
+
+ bool is_extension (hb_tag_t table_tag) const
+ {
+ return lookupType == extension_type (table_tag);
+ }
+
+ bool make_extension (gsubgpos_graph_context_t& c,
+ unsigned this_index)
+ {
+ unsigned type = lookupType;
+ unsigned ext_type = extension_type (c.table_tag);
+ if (!ext_type || is_extension (c.table_tag))
+ {
+ // NOOP
+ return true;
+ }
+
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ "Promoting lookup type %u (obj %u) to extension.",
+ type,
+ this_index);
+
+ for (unsigned i = 0; i < subTable.len; i++)
+ {
+ unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]);
+ if (!make_subtable_extension (c,
+ this_index,
+ subtable_index))
+ return false;
+ }
+
+ lookupType = ext_type;
+ return true;
+ }
+
+ bool split_subtables_if_needed (gsubgpos_graph_context_t& c,
+ unsigned this_index)
+ {
+ unsigned type = lookupType;
+ bool is_ext = is_extension (c.table_tag);
+
+ if (c.table_tag != HB_OT_TAG_GPOS)
+ return true;
+
+ if (!is_ext && type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair)
+ return true;
+
+ hb_vector_t<unsigned> all_new_subtables;
+ for (unsigned i = 0; i < subTable.len; i++)
+ {
+ unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]);
+ if (is_ext) {
+ unsigned ext_subtable_index = subtable_index;
+ ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension =
+ (ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*)
+ c.graph.object (ext_subtable_index).head;
+ if (!extension->sanitize (c.graph.vertices_[ext_subtable_index]))
+ continue;
+
+ subtable_index = extension->get_subtable_index (c.graph, ext_subtable_index);
+ type = extension->get_lookup_type ();
+ if (type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair)
+ continue;
+ }
+
+ PairPos* pairPos = (PairPos*) c.graph.object (subtable_index).head;
+ if (!pairPos->sanitize (c.graph.vertices_[subtable_index])) continue;
+
+ hb_vector_t<unsigned> new_sub_tables = pairPos->split_subtables (c, subtable_index);
+ if (new_sub_tables.in_error ()) return false;
+ + new_sub_tables.iter() | hb_sink (all_new_subtables);
+ }
+
+ if (all_new_subtables)
+ add_sub_tables (c, this_index, type, all_new_subtables);
+
+ return true;
+ }
+
+ void add_sub_tables (gsubgpos_graph_context_t& c,
+ unsigned this_index,
+ unsigned type,
+ hb_vector_t<unsigned>& subtable_indices)
+ {
+ bool is_ext = is_extension (c.table_tag);
+ auto& v = c.graph.vertices_[this_index];
+
+ size_t new_size = v.table_size ()
+ + subtable_indices.length * OT::Offset16::static_size;
+ char* buffer = (char*) hb_calloc (1, new_size);
+ c.add_buffer (buffer);
+ memcpy (buffer, v.obj.head, v.table_size());
+
+ v.obj.head = buffer;
+ v.obj.tail = buffer + new_size;
+
+ Lookup* new_lookup = (Lookup*) buffer;
+
+ new_lookup->subTable.len = subTable.len + subtable_indices.length;
+ unsigned offset_index = subTable.len;
+ for (unsigned subtable_id : subtable_indices)
+ {
+ if (is_ext)
+ {
+ unsigned ext_id = create_extension_subtable (c, subtable_id, type);
+ c.graph.vertices_[subtable_id].parents.push (ext_id);
+ subtable_id = ext_id;
+ }
+
+ auto* link = v.obj.real_links.push ();
+ link->width = 2;
+ link->objidx = subtable_id;
+ link->position = (char*) &new_lookup->subTable[offset_index++] -
+ (char*) new_lookup;
+ c.graph.vertices_[subtable_id].parents.push (this_index);
+ }
+
+ // The head location of the lookup has changed, invalidating the lookups map entry
+ // in the context. Update the map.
+ c.lookups.set (this_index, new_lookup);
+ }
+
+ unsigned create_extension_subtable (gsubgpos_graph_context_t& c,
+ unsigned subtable_index,
+ unsigned type)
+ {
+ unsigned extension_size = OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::static_size;
+
+ unsigned ext_index = c.create_node (extension_size);
+ if (ext_index == (unsigned) -1)
+ return -1;
+
+ auto& ext_vertex = c.graph.vertices_[ext_index];
+ ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension =
+ (ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*) ext_vertex.obj.head;
+ extension->reset (type);
+
+ // Make extension point at the subtable.
+ auto* l = ext_vertex.obj.real_links.push ();
+
+ l->width = 4;
+ l->objidx = subtable_index;
+ l->position = 4;
+
+ return ext_index;
+ }
+
+ bool make_subtable_extension (gsubgpos_graph_context_t& c,
+ unsigned lookup_index,
+ unsigned subtable_index)
+ {
+ unsigned type = lookupType;
+
+ unsigned ext_index = create_extension_subtable(c, subtable_index, type);
+ if (ext_index == (unsigned) -1)
+ return false;
+
+ auto& lookup_vertex = c.graph.vertices_[lookup_index];
+ for (auto& l : lookup_vertex.obj.real_links.writer ())
+ {
+ if (l.objidx == subtable_index)
+ // Change lookup to point at the extension.
+ l.objidx = ext_index;
+ }
+
+ // Make extension point at the subtable.
+ auto& ext_vertex = c.graph.vertices_[ext_index];
+ auto& subtable_vertex = c.graph.vertices_[subtable_index];
+ ext_vertex.parents.push (lookup_index);
+ subtable_vertex.remap_parent (lookup_index, ext_index);
+
+ return true;
+ }
+
+ private:
+ unsigned extension_type (hb_tag_t table_tag) const
+ {
+ switch (table_tag)
+ {
+ case HB_OT_TAG_GPOS: return 9;
+ case HB_OT_TAG_GSUB: return 7;
+ default: return 0;
+ }
+ }
+};
+
+template <typename T>
+struct LookupList : public OT::LookupList<T>
+{
+ bool sanitize (const graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ if (vertex_len < OT::LookupList<T>::min_size) return false;
+ return vertex_len >= OT::LookupList<T>::item_size * this->len;
+ }
+};
+
+struct GSTAR : public OT::GSUBGPOS
+{
+ static GSTAR* graph_to_gstar (graph_t& graph)
+ {
+ const auto& r = graph.root ();
+
+ GSTAR* gstar = (GSTAR*) r.obj.head;
+ if (!gstar->sanitize (r))
+ return nullptr;
+
+ return gstar;
+ }
+
+ const void* get_lookup_list_field_offset () const
+ {
+ switch (u.version.major) {
+ case 1: return u.version1.get_lookup_list_offset ();
+#ifndef HB_NO_BORING_EXPANSION
+ case 2: return u.version2.get_lookup_list_offset ();
+#endif
+ default: return 0;
+ }
+ }
+
+ bool sanitize (const graph_t::vertex_t& vertex)
+ {
+ int64_t len = vertex.obj.tail - vertex.obj.head;
+ if (len < OT::GSUBGPOS::min_size) return false;
+ return len >= get_size ();
+ }
+
+ void find_lookups (graph_t& graph,
+ hb_hashmap_t<unsigned, Lookup*>& lookups /* OUT */)
+ {
+ switch (u.version.major) {
+ case 1: find_lookups<SmallTypes> (graph, lookups); break;
+#ifndef HB_NO_BORING_EXPANSION
+ case 2: find_lookups<MediumTypes> (graph, lookups); break;
+#endif
+ }
+ }
+
+ unsigned get_lookup_list_index (graph_t& graph)
+ {
+ return graph.index_for_offset (graph.root_idx (),
+ get_lookup_list_field_offset());
+ }
+
+ template<typename Types>
+ void find_lookups (graph_t& graph,
+ hb_hashmap_t<unsigned, Lookup*>& lookups /* OUT */)
+ {
+ unsigned lookup_list_idx = get_lookup_list_index (graph);
+
+ const LookupList<Types>* lookupList =
+ (const LookupList<Types>*) graph.object (lookup_list_idx).head;
+ if (!lookupList->sanitize (graph.vertices_[lookup_list_idx]))
+ return;
+
+ for (unsigned i = 0; i < lookupList->len; i++)
+ {
+ unsigned lookup_idx = graph.index_for_offset (lookup_list_idx, &(lookupList->arrayZ[i]));
+ Lookup* lookup = (Lookup*) graph.object (lookup_idx).head;
+ if (!lookup->sanitize (graph.vertices_[lookup_idx])) continue;
+ lookups.set (lookup_idx, lookup);
+ }
+ }
+};
+
+
+
+
+}
+
+#endif /* GRAPH_GSUBGPOS_GRAPH_HH */
diff --git a/thirdparty/harfbuzz/src/graph/pairpos-graph.hh b/thirdparty/harfbuzz/src/graph/pairpos-graph.hh
new file mode 100644
index 0000000000..3ca4fc701c
--- /dev/null
+++ b/thirdparty/harfbuzz/src/graph/pairpos-graph.hh
@@ -0,0 +1,299 @@
+/*
+ * Copyright © 2022 Google, Inc.
+ *
+ * This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#ifndef GRAPH_PAIRPOS_GRAPH_HH
+#define GRAPH_PAIRPOS_GRAPH_HH
+
+#include "coverage-graph.hh"
+#include "../OT/Layout/GPOS/PairPos.hh"
+#include "../OT/Layout/GPOS/PosLookupSubTable.hh"
+
+namespace graph {
+
+struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>
+{
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size;
+ if (vertex_len < min_size) return false;
+
+ return vertex_len >=
+ min_size + pairSet.get_size () - pairSet.len.get_size();
+ }
+
+ hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
+ {
+ hb_set_t visited;
+
+ const unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage);
+ const unsigned coverage_size = c.graph.vertices_[coverage_id].table_size ();
+ const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size
+ + coverage_size;
+
+ unsigned accumulated = base_size;
+ hb_vector_t<unsigned> split_points;
+ for (unsigned i = 0; i < pairSet.len; i++)
+ {
+ unsigned pair_set_index = pair_set_graph_index (c, this_index, i);
+ accumulated += c.graph.find_subgraph_size (pair_set_index, visited);
+ accumulated += SmallTypes::size; // for PairSet offset.
+
+ // TODO(garretrieger): don't count the size of the largest pairset against the limit, since
+ // it will be packed last in the order and does not contribute to
+ // the 64kb limit.
+
+ if (accumulated > (1 << 16))
+ {
+ split_points.push (i);
+ accumulated = base_size;
+ visited.clear (); // Pretend node sharing isn't allowed between splits.
+ }
+ }
+
+ return do_split (c, this_index, split_points);
+ }
+
+ private:
+
+ // Split this PairPos into two or more PairPos's. split_points defines
+ // the indices (first index to include in the new table) to split at.
+ // Returns the object id's of the newly created PairPos subtables.
+ hb_vector_t<unsigned> do_split (gsubgpos_graph_context_t& c,
+ unsigned this_index,
+ const hb_vector_t<unsigned> split_points)
+ {
+ hb_vector_t<unsigned> new_objects;
+ if (!split_points)
+ return new_objects;
+
+ for (unsigned i = 0; i < split_points.length; i++)
+ {
+ unsigned start = split_points[i];
+ unsigned end = (i < split_points.length - 1) ? split_points[i + 1] : pairSet.len;
+ unsigned id = clone_range (c, this_index, start, end);
+
+ if (id == (unsigned) -1)
+ {
+ new_objects.reset ();
+ new_objects.allocated = -1; // mark error
+ return new_objects;
+ }
+ new_objects.push (id);
+ }
+
+ if (!shrink (c, this_index, split_points[0]))
+ {
+ new_objects.reset ();
+ new_objects.allocated = -1; // mark error
+ }
+
+ return new_objects;
+ }
+
+ bool shrink (gsubgpos_graph_context_t& c,
+ unsigned this_index,
+ unsigned count)
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ " Shrinking PairPosFormat1 (%u) to [0, %u).",
+ this_index,
+ count);
+ unsigned old_count = pairSet.len;
+ if (count >= old_count)
+ return true;
+
+ pairSet.len = count;
+ c.graph.vertices_[this_index].obj.tail -= (old_count - count) * SmallTypes::size;
+
+ unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage);
+ unsigned coverage_size = c.graph.vertices_[coverage_id].table_size ();
+ auto& coverage_v = c.graph.vertices_[coverage_id];
+ Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
+ if (!coverage_table->sanitize (coverage_v))
+ return false;
+
+ auto new_coverage =
+ + hb_zip (coverage_table->iter (), hb_range ())
+ | hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) {
+ return p.second < count;
+ })
+ | hb_map_retains_sorting (hb_first)
+ ;
+
+ return make_coverage (c, new_coverage, coverage_id, coverage_size);
+ }
+
+ // Create a new PairPos including PairSet's from start (inclusive) to end (exclusive).
+ // Returns object id of the new object.
+ unsigned clone_range (gsubgpos_graph_context_t& c,
+ unsigned this_index,
+ unsigned start, unsigned end) const
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr,
+ " Cloning PairPosFormat1 (%u) range [%u, %u).", this_index, start, end);
+
+ unsigned num_pair_sets = end - start;
+ unsigned prime_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size
+ + num_pair_sets * SmallTypes::size;
+
+ unsigned pair_pos_prime_id = c.create_node (prime_size);
+ if (pair_pos_prime_id == (unsigned) -1) return -1;
+
+ PairPosFormat1* pair_pos_prime = (PairPosFormat1*) c.graph.object (pair_pos_prime_id).head;
+ pair_pos_prime->format = this->format;
+ pair_pos_prime->valueFormat[0] = this->valueFormat[0];
+ pair_pos_prime->valueFormat[1] = this->valueFormat[1];
+ pair_pos_prime->pairSet.len = num_pair_sets;
+
+ for (unsigned i = start; i < end; i++)
+ {
+ c.graph.move_child<> (this_index,
+ &pairSet[i],
+ pair_pos_prime_id,
+ &pair_pos_prime->pairSet[i - start]);
+ }
+
+ unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage);
+ unsigned coverage_size = c.graph.vertices_[coverage_id].table_size ();
+ auto& coverage_v = c.graph.vertices_[coverage_id];
+ Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
+ if (!coverage_table->sanitize (coverage_v))
+ return false;
+
+ auto new_coverage =
+ + hb_zip (coverage_table->iter (), hb_range ())
+ | hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) {
+ return p.second >= start && p.second < end;
+ })
+ | hb_map_retains_sorting (hb_first)
+ ;
+
+ unsigned coverage_prime_id = c.graph.new_node (nullptr, nullptr);
+ auto& coverage_prime_vertex = c.graph.vertices_[coverage_prime_id];
+ if (!make_coverage (c, new_coverage, coverage_prime_id, coverage_size))
+ return -1;
+
+ auto* coverage_link = c.graph.vertices_[pair_pos_prime_id].obj.real_links.push ();
+ coverage_link->width = SmallTypes::size;
+ coverage_link->objidx = coverage_prime_id;
+ coverage_link->position = 2;
+ coverage_prime_vertex.parents.push (pair_pos_prime_id);
+
+ return pair_pos_prime_id;
+ }
+
+ template<typename It>
+ bool make_coverage (gsubgpos_graph_context_t& c,
+ It glyphs,
+ unsigned dest_obj,
+ unsigned max_size) const
+ {
+ char* buffer = (char*) hb_calloc (1, max_size);
+ hb_serialize_context_t serializer (buffer, max_size);
+ Coverage_serialize (&serializer, glyphs);
+ serializer.end_serialize ();
+ if (serializer.in_error ())
+ {
+ hb_free (buffer);
+ return false;
+ }
+
+ hb_bytes_t coverage_copy = serializer.copy_bytes ();
+ c.add_buffer ((char *) coverage_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer.
+
+ auto& obj = c.graph.vertices_[dest_obj].obj;
+ obj.head = (char *) coverage_copy.arrayZ;
+ obj.tail = obj.head + coverage_copy.length;
+
+ hb_free (buffer);
+ return true;
+ }
+
+ unsigned pair_set_graph_index (gsubgpos_graph_context_t& c, unsigned this_index, unsigned i) const
+ {
+ return c.graph.index_for_offset (this_index, &pairSet[i]);
+ }
+};
+
+struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>
+{
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ // TODO(garretrieger): implement me!
+ return true;
+ }
+
+ hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
+ {
+ // TODO(garretrieger): implement me!
+ return hb_vector_t<unsigned> ();
+ }
+};
+
+struct PairPos : public OT::Layout::GPOS_impl::PairPos
+{
+ hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
+ {
+ switch (u.format) {
+ case 1:
+ return ((PairPosFormat1*)(&u.format1))->split_subtables (c, this_index);
+ case 2:
+ return ((PairPosFormat2*)(&u.format2))->split_subtables (c, this_index);
+#ifndef HB_NO_BORING_EXPANSION
+ case 3: HB_FALLTHROUGH;
+ case 4: HB_FALLTHROUGH;
+ // Don't split 24bit PairPos's.
+#endif
+ default:
+ return hb_vector_t<unsigned> ();
+ }
+ }
+
+ bool sanitize (graph_t::vertex_t& vertex) const
+ {
+ int64_t vertex_len = vertex.obj.tail - vertex.obj.head;
+ if (vertex_len < u.format.get_size ()) return false;
+
+ switch (u.format) {
+ case 1:
+ return ((PairPosFormat1*)(&u.format1))->sanitize (vertex);
+ case 2:
+ return ((PairPosFormat2*)(&u.format2))->sanitize (vertex);
+#ifndef HB_NO_BORING_EXPANSION
+ case 3: HB_FALLTHROUGH;
+ case 4: HB_FALLTHROUGH;
+#endif
+ default:
+ // We don't handle format 3 and 4 here.
+ return false;
+ }
+ }
+};
+
+}
+
+#endif // GRAPH_PAIRPOS_GRAPH_HH
diff --git a/thirdparty/harfbuzz/src/hb-blob.cc b/thirdparty/harfbuzz/src/hb-blob.cc
index 47062eab9a..9bc12ea3fa 100644
--- a/thirdparty/harfbuzz/src/hb-blob.cc
+++ b/thirdparty/harfbuzz/src/hb-blob.cc
@@ -303,7 +303,7 @@ hb_blob_set_user_data (hb_blob_t *blob,
* Since: 0.9.2
**/
void *
-hb_blob_get_user_data (hb_blob_t *blob,
+hb_blob_get_user_data (const hb_blob_t *blob,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (blob, key);
diff --git a/thirdparty/harfbuzz/src/hb-blob.h b/thirdparty/harfbuzz/src/hb-blob.h
index 203f9e19dd..4eb42314da 100644
--- a/thirdparty/harfbuzz/src/hb-blob.h
+++ b/thirdparty/harfbuzz/src/hb-blob.h
@@ -135,7 +135,7 @@ hb_blob_set_user_data (hb_blob_t *blob,
HB_EXTERN void *
-hb_blob_get_user_data (hb_blob_t *blob,
+hb_blob_get_user_data (const hb_blob_t *blob,
hb_user_data_key_t *key);
diff --git a/thirdparty/harfbuzz/src/hb-buffer.cc b/thirdparty/harfbuzz/src/hb-buffer.cc
index fddda23304..57a5ae03ed 100644
--- a/thirdparty/harfbuzz/src/hb-buffer.cc
+++ b/thirdparty/harfbuzz/src/hb-buffer.cc
@@ -387,9 +387,11 @@ hb_buffer_t::clear_positions ()
hb_memset (pos, 0, sizeof (pos[0]) * len);
}
-void
+bool
hb_buffer_t::sync ()
{
+ bool ret = false;
+
assert (have_output);
assert (idx <= len);
@@ -403,12 +405,39 @@ hb_buffer_t::sync ()
info = out_info;
}
len = out_len;
+ ret = true;
reset:
have_output = false;
out_len = 0;
out_info = info;
idx = 0;
+
+ return ret;
+}
+
+int
+hb_buffer_t::sync_so_far ()
+{
+ bool had_output = have_output;
+ unsigned out_i = out_len;
+ unsigned i = idx;
+ unsigned old_idx = idx;
+
+ if (sync ())
+ idx = out_i;
+ else
+ idx = i;
+
+ if (had_output)
+ {
+ have_output = true;
+ out_len = idx;
+ }
+
+ assert (idx <= len);
+
+ return idx - old_idx;
}
bool
@@ -802,7 +831,7 @@ hb_buffer_set_user_data (hb_buffer_t *buffer,
* Since: 0.9.2
**/
void *
-hb_buffer_get_user_data (hb_buffer_t *buffer,
+hb_buffer_get_user_data (const hb_buffer_t *buffer,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (buffer, key);
@@ -2090,8 +2119,16 @@ hb_buffer_set_message_func (hb_buffer_t *buffer,
bool
hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
{
+ assert (!have_output || (out_info == info && out_len == idx));
+
+ message_depth++;
+
char buf[100];
vsnprintf (buf, sizeof (buf), fmt, ap);
- return (bool) this->message_func (this, font, buf, this->message_data);
+ bool ret = (bool) this->message_func (this, font, buf, this->message_data);
+
+ message_depth--;
+
+ return ret;
}
#endif
diff --git a/thirdparty/harfbuzz/src/hb-buffer.h b/thirdparty/harfbuzz/src/hb-buffer.h
index e095c5344c..c6af759fb9 100644
--- a/thirdparty/harfbuzz/src/hb-buffer.h
+++ b/thirdparty/harfbuzz/src/hb-buffer.h
@@ -142,6 +142,15 @@ typedef struct hb_glyph_info_t {
* shaping, otherwise the buffer flag will not be
* reliably produced.
* Since: 4.0.0
+ * @HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL: In scripts that use elongation (Arabic,
+ Mongolian, Syriac, etc.), this flag signifies
+ that it is safe to insert a U+0640 TATWEEL
+ character *before* this cluster for elongation.
+ This flag does not determine the
+ script-specific elongation places, but only
+ when it is safe to do the elongation without
+ interrupting text shaping.
+ Since: 5.1.0
* @HB_GLYPH_FLAG_DEFINED: All the currently defined flags.
*
* Flags for #hb_glyph_info_t.
@@ -149,10 +158,11 @@ typedef struct hb_glyph_info_t {
* Since: 1.5.0
*/
typedef enum { /*< flags >*/
- HB_GLYPH_FLAG_UNSAFE_TO_BREAK = 0x00000001,
- HB_GLYPH_FLAG_UNSAFE_TO_CONCAT = 0x00000002,
+ HB_GLYPH_FLAG_UNSAFE_TO_BREAK = 0x00000001,
+ HB_GLYPH_FLAG_UNSAFE_TO_CONCAT = 0x00000002,
+ HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL = 0x00000004,
- HB_GLYPH_FLAG_DEFINED = 0x00000003 /* OR of all defined flags */
+ HB_GLYPH_FLAG_DEFINED = 0x00000007 /* OR of all defined flags */
} hb_glyph_flags_t;
HB_EXTERN hb_glyph_flags_t
@@ -266,7 +276,7 @@ hb_buffer_set_user_data (hb_buffer_t *buffer,
hb_bool_t replace);
HB_EXTERN void *
-hb_buffer_get_user_data (hb_buffer_t *buffer,
+hb_buffer_get_user_data (const hb_buffer_t *buffer,
hb_user_data_key_t *key);
@@ -373,6 +383,10 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
* flag indicating that the @HB_GLYPH_FLAG_UNSAFE_TO_CONCAT
* glyph-flag should be produced by the shaper. By default
* it will not be produced since it incurs a cost. Since: 4.0.0
+ * @HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL:
+ * flag indicating that the @HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL
+ * glyph-flag should be produced by the shaper. By default
+ * it will not be produced. Since: 5.1.0
* @HB_BUFFER_FLAG_DEFINED: All currently defined flags: Since: 4.4.0
*
* Flags for #hb_buffer_t.
@@ -388,8 +402,9 @@ typedef enum { /*< flags >*/
HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u,
HB_BUFFER_FLAG_VERIFY = 0x00000020u,
HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT = 0x00000040u,
+ HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL = 0x00000080u,
- HB_BUFFER_FLAG_DEFINED = 0x0000007Fu
+ HB_BUFFER_FLAG_DEFINED = 0x000000FFu
} hb_buffer_flags_t;
HB_EXTERN void
diff --git a/thirdparty/harfbuzz/src/hb-buffer.hh b/thirdparty/harfbuzz/src/hb-buffer.hh
index 6ca78f28d4..26c3f0fac8 100644
--- a/thirdparty/harfbuzz/src/hb-buffer.hh
+++ b/thirdparty/harfbuzz/src/hb-buffer.hh
@@ -288,7 +288,8 @@ struct hb_buffer_t
HB_INTERNAL void guess_segment_properties ();
- HB_INTERNAL void sync ();
+ HB_INTERNAL bool sync ();
+ HB_INTERNAL int sync_so_far ();
HB_INTERNAL void clear_output ();
HB_INTERNAL void clear_positions ();
@@ -461,6 +462,17 @@ struct hb_buffer_t
start, end,
true);
}
+ void safe_to_insert_tatweel (unsigned int start = 0, unsigned int end = -1)
+ {
+ if ((flags & HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL) == 0)
+ {
+ unsafe_to_break (start, end);
+ return;
+ }
+ _set_glyph_flags (HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL,
+ start, end,
+ true);
+ }
void unsafe_to_concat (unsigned int start = 0, unsigned int end = -1)
{
if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0))
@@ -555,15 +567,11 @@ struct hb_buffer_t
if (likely (!messaging ()))
return true;
- message_depth++;
-
va_list ap;
va_start (ap, fmt);
bool ret = message_impl (font, fmt, ap);
va_end (ap);
- message_depth--;
-
return ret;
#endif
}
diff --git a/thirdparty/harfbuzz/src/hb-cplusplus.hh b/thirdparty/harfbuzz/src/hb-cplusplus.hh
index f06a32d912..c4d9d29e23 100644
--- a/thirdparty/harfbuzz/src/hb-cplusplus.hh
+++ b/thirdparty/harfbuzz/src/hb-cplusplus.hh
@@ -130,7 +130,7 @@ template <typename T,
void *,
hb_destroy_func_t,
hb_bool_t),
- void * (*_get_user_data) (T *,
+ void * (*_get_user_data) (const T *,
hb_user_data_key_t *)>
struct vtable_t
{
@@ -164,6 +164,27 @@ HB_DEFINE_VTABLE (unicode_funcs);
#undef HB_DEFINE_VTABLE
+#ifdef HB_SUBSET_H
+
+#define HB_DEFINE_VTABLE(name) \
+ template<> \
+ struct vtable<hb_##name##_t> \
+ : vtable_t<hb_##name##_t, \
+ nullptr, \
+ &hb_##name##_reference, \
+ &hb_##name##_destroy, \
+ &hb_##name##_set_user_data, \
+ &hb_##name##_get_user_data> {}
+
+
+HB_DEFINE_VTABLE (subset_input);
+HB_DEFINE_VTABLE (subset_plan);
+
+#undef HB_DEFINE_VTABLE
+
+#endif
+
+
} // namespace hb
/* Workaround for GCC < 7, see:
diff --git a/thirdparty/harfbuzz/src/hb-debug.hh b/thirdparty/harfbuzz/src/hb-debug.hh
index 3ac7440e80..905a46a087 100644
--- a/thirdparty/harfbuzz/src/hb-debug.hh
+++ b/thirdparty/harfbuzz/src/hb-debug.hh
@@ -460,4 +460,9 @@ struct hb_no_trace_t {
#endif
+#ifndef HB_BUFFER_MESSAGE_MORE
+#define HB_BUFFER_MESSAGE_MORE (HB_DEBUG+1)
+#endif
+
+
#endif /* HB_DEBUG_HH */
diff --git a/thirdparty/harfbuzz/src/hb-face.cc b/thirdparty/harfbuzz/src/hb-face.cc
index 8f8b1a6d14..61adbdd503 100644
--- a/thirdparty/harfbuzz/src/hb-face.cc
+++ b/thirdparty/harfbuzz/src/hb-face.cc
@@ -342,7 +342,7 @@ hb_face_set_user_data (hb_face_t *face,
* Since: 0.9.2
**/
void *
-hb_face_get_user_data (hb_face_t *face,
+hb_face_get_user_data (const hb_face_t *face,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (face, key);
diff --git a/thirdparty/harfbuzz/src/hb-face.h b/thirdparty/harfbuzz/src/hb-face.h
index 3b7477a76c..6ef2f8b886 100644
--- a/thirdparty/harfbuzz/src/hb-face.h
+++ b/thirdparty/harfbuzz/src/hb-face.h
@@ -96,7 +96,7 @@ hb_face_set_user_data (hb_face_t *face,
hb_bool_t replace);
HB_EXTERN void *
-hb_face_get_user_data (hb_face_t *face,
+hb_face_get_user_data (const hb_face_t *face,
hb_user_data_key_t *key);
HB_EXTERN void
diff --git a/thirdparty/harfbuzz/src/hb-font.cc b/thirdparty/harfbuzz/src/hb-font.cc
index fd9073c33e..856bbdda32 100644
--- a/thirdparty/harfbuzz/src/hb-font.cc
+++ b/thirdparty/harfbuzz/src/hb-font.cc
@@ -781,8 +781,8 @@ hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs,
* Since: 0.9.2
**/
void *
-hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs,
- hb_user_data_key_t *key)
+hb_font_funcs_get_user_data (const hb_font_funcs_t *ffuncs,
+ hb_user_data_key_t *key)
{
return hb_object_get_user_data (ffuncs, key);
}
@@ -1897,7 +1897,7 @@ hb_font_set_user_data (hb_font_t *font,
* Since: 0.9.2
**/
void *
-hb_font_get_user_data (hb_font_t *font,
+hb_font_get_user_data (const hb_font_t *font,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (font, key);
diff --git a/thirdparty/harfbuzz/src/hb-font.h b/thirdparty/harfbuzz/src/hb-font.h
index 3f27bca288..e2c3df4a5a 100644
--- a/thirdparty/harfbuzz/src/hb-font.h
+++ b/thirdparty/harfbuzz/src/hb-font.h
@@ -86,8 +86,8 @@ hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs,
HB_EXTERN void *
-hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs,
- hb_user_data_key_t *key);
+hb_font_funcs_get_user_data (const hb_font_funcs_t *ffuncs,
+ hb_user_data_key_t *key);
HB_EXTERN void
@@ -993,7 +993,7 @@ hb_font_set_user_data (hb_font_t *font,
HB_EXTERN void *
-hb_font_get_user_data (hb_font_t *font,
+hb_font_get_user_data (const hb_font_t *font,
hb_user_data_key_t *key);
HB_EXTERN void
diff --git a/thirdparty/harfbuzz/src/hb-ft.cc b/thirdparty/harfbuzz/src/hb-ft.cc
index 5c88a7f3bd..ef073475cb 100644
--- a/thirdparty/harfbuzz/src/hb-ft.cc
+++ b/thirdparty/harfbuzz/src/hb-ft.cc
@@ -1086,7 +1086,8 @@ hb_ft_font_changed (hb_font_t *font)
}
#endif
- _hb_ft_hb_font_check_changed (font, ft_font);
+ ft_font->advance_cache.clear ();
+ ft_font->cached_serial = font->serial;
}
/**
diff --git a/thirdparty/harfbuzz/src/hb-map.cc b/thirdparty/harfbuzz/src/hb-map.cc
index a29fa1a313..5c5f5de59e 100644
--- a/thirdparty/harfbuzz/src/hb-map.cc
+++ b/thirdparty/harfbuzz/src/hb-map.cc
@@ -145,7 +145,7 @@ hb_map_set_user_data (hb_map_t *map,
* Since: 1.7.7
**/
void *
-hb_map_get_user_data (hb_map_t *map,
+hb_map_get_user_data (const hb_map_t *map,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (map, key);
diff --git a/thirdparty/harfbuzz/src/hb-map.h b/thirdparty/harfbuzz/src/hb-map.h
index 41d877d6a1..3a067c5c73 100644
--- a/thirdparty/harfbuzz/src/hb-map.h
+++ b/thirdparty/harfbuzz/src/hb-map.h
@@ -74,7 +74,7 @@ hb_map_set_user_data (hb_map_t *map,
hb_bool_t replace);
HB_EXTERN void *
-hb_map_get_user_data (hb_map_t *map,
+hb_map_get_user_data (const hb_map_t *map,
hb_user_data_key_t *key);
diff --git a/thirdparty/harfbuzz/src/hb-number-parser.hh b/thirdparty/harfbuzz/src/hb-number-parser.hh
index ec68c3a728..1a9dbba6dd 100644
--- a/thirdparty/harfbuzz/src/hb-number-parser.hh
+++ b/thirdparty/harfbuzz/src/hb-number-parser.hh
@@ -31,7 +31,7 @@
#include "hb.hh"
-#line 32 "hb-number-parser.hh"
+#line 35 "hb-number-parser.hh"
static const unsigned char _double_parser_trans_keys[] = {
0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u,
46u, 101u, 0
@@ -135,12 +135,12 @@ strtod_rl (const char *p, const char **end_ptr /* IN/OUT */)
int cs;
-#line 132 "hb-number-parser.hh"
+#line 139 "hb-number-parser.hh"
{
cs = double_parser_start;
}
-#line 135 "hb-number-parser.hh"
+#line 144 "hb-number-parser.hh"
{
int _slen;
int _trans;
@@ -198,7 +198,7 @@ _resume:
exp_overflow = true;
}
break;
-#line 187 "hb-number-parser.hh"
+#line 202 "hb-number-parser.hh"
}
_again:
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
index 9a4157b21f..0532039aad 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh
@@ -72,10 +72,6 @@ using OT::Layout::MediumTypes;
#define HB_MAX_LANGSYS_FEATURE_COUNT 50000
#endif
-#ifndef HB_MAX_FEATURES
-#define HB_MAX_FEATURES 750
-#endif
-
#ifndef HB_MAX_FEATURE_INDICES
#define HB_MAX_FEATURE_INDICES 1500
#endif
@@ -1337,7 +1333,7 @@ struct Lookup
return_trace (true);
}
- private:
+ protected:
HBUINT16 lookupType; /* Different enumerations for GSUB and GPOS */
HBUINT16 lookupFlag; /* Lookup qualifiers */
Array16Of<Offset16>
diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
index 5acd228b83..c77ec12fbe 100644
--- a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
@@ -1602,9 +1602,28 @@ static inline void apply_lookup (hb_ot_apply_context_t *c,
if (unlikely (buffer->max_ops <= 0))
break;
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ if (buffer->have_output)
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "recursing to lookup %u at %d",
+ (unsigned) lookupRecord[i].lookupListIndex,
+ buffer->idx);
+ }
+
if (!c->recurse (lookupRecord[i].lookupListIndex))
continue;
+ if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
+ {
+ if (buffer->have_output)
+ c->buffer->sync_so_far ();
+ c->buffer->message (c->font,
+ "recursed to lookup %u",
+ (unsigned) lookupRecord[i].lookupListIndex);
+ }
+
unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
int delta = new_len - orig_len;
@@ -4010,6 +4029,11 @@ struct GSUBGPOSVersion1_2
(version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
}
+ const typename Types::template OffsetTo<LookupList<Types>>* get_lookup_list_offset () const
+ {
+ return &lookupList;
+ }
+
template <typename TLookup>
bool sanitize (hb_sanitize_context_t *c) const
{
diff --git a/thirdparty/harfbuzz/src/hb-ot-shape.cc b/thirdparty/harfbuzz/src/hb-ot-shape.cc
index 2ada84b8a3..7f679cfd39 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shape.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shape.cc
@@ -1141,6 +1141,18 @@ hb_propagate_flags (hb_buffer_t *buffer)
if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS))
return;
+ /* If we are producing SAFE_TO_INSERT_TATWEEL, then do two things:
+ *
+ * - If the places that the Arabic shaper marked as SAFE_TO_INSERT_TATWEEL,
+ * are UNSAFE_TO_BREAK, then clear the SAFE_TO_INSERT_TATWEEL,
+ * - Any place that is SAFE_TO_INSERT_TATWEEL, is also now UNSAFE_TO_BREAK.
+ *
+ * We couldn't make this interaction earlier. It has to be done here.
+ */
+ bool flip_tatweel = buffer->flags & HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL;
+
+ bool clear_concat = (buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0;
+
hb_glyph_info_t *info = buffer->info;
foreach_cluster (buffer, start, end)
@@ -1148,9 +1160,20 @@ hb_propagate_flags (hb_buffer_t *buffer)
unsigned int mask = 0;
for (unsigned int i = start; i < end; i++)
mask |= info[i].mask & HB_GLYPH_FLAG_DEFINED;
- if (mask)
- for (unsigned int i = start; i < end; i++)
- info[i].mask |= mask;
+
+ if (flip_tatweel)
+ {
+ if (mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
+ mask &= ~HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL;
+ if (mask & HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL)
+ mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT;
+ }
+
+ if (clear_concat)
+ mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_CONCAT;
+
+ for (unsigned int i = start; i < end; i++)
+ info[i].mask = mask;
}
}
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-arabic.cc b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic.cc
index b331a048b6..ed2748b828 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-arabic.cc
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-arabic.cc
@@ -331,7 +331,7 @@ arabic_joining (hb_buffer_t *buffer)
if (entry->prev_action != NONE && prev != UINT_MAX)
{
info[prev].arabic_shaping_action() = entry->prev_action;
- buffer->unsafe_to_break (prev, i + 1);
+ buffer->safe_to_insert_tatweel (prev, i + 1);
}
else
{
@@ -365,7 +365,7 @@ arabic_joining (hb_buffer_t *buffer)
if (entry->prev_action != NONE && prev != UINT_MAX)
{
info[prev].arabic_shaping_action() = entry->prev_action;
- buffer->unsafe_to_break (prev, buffer->len);
+ buffer->safe_to_insert_tatweel (prev, buffer->len);
}
else if (2 <= state && state <= 5) /* States that have a possible prev_action. */
{
diff --git a/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh b/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh
index 4f09fa805e..e45ea30e60 100644
--- a/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ot-shaper-use-table.hh
@@ -90,263 +90,264 @@
#pragma GCC diagnostic pop
static const uint8_t
-hb_use_u8[1842] =
+hb_use_u8[3083] =
{
- 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 5,
- 6, 7, 3, 8, 3, 3, 9, 3, 10, 3, 3, 11, 3, 12, 13, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 14, 0, 0, 1, 1, 2, 1, 1, 3, 4, 5, 6, 7, 8, 9, 10,
- 1, 11, 12, 1, 1, 1, 1, 1, 1, 13, 14, 15, 16, 17, 18, 19,
- 1, 1, 20, 1, 1, 1, 1, 21, 1, 1, 1, 1, 1, 1, 1, 22,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 23, 24, 25, 26, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 27, 28, 1, 1, 1, 1, 1, 29, 1, 1, 1, 1, 30, 31, 1, 32,
- 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 1, 46, 47,
- 48, 1, 49, 49, 49, 49, 50, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 51, 52, 1, 1,
- 1, 53, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 49, 54, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 55, 1,
- 1, 1, 1, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 57, 58, 1, 1, 1, 1, 1, 1, 59, 1, 1, 1, 1,
- 1, 1, 60, 61, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
- 60, 60, O, O, O, O, O, GB, O, O, B, B, B, B, B, B,
- O, O, GB, O, O, O, O, WJ, O, O, O, O,FMPst,FMPst, O, O,
- O, GB, O, O, O, CGJ, B, O, O, O, O, O, B, B, B, B,
- B,VMAbv,VMAbv,VMAbv,VMAbv,VMAbv, O, O, B, O, O,VMAbv, O, O, B,CMBlw,
- CMBlw,CMBlw,VMAbv,VMAbv,VMAbv,VMPst, B, B, VAbv, VPst,CMBlw, B, VPst, VPre, VPst, VBlw,
- VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, VPst, VPst, VPst, VPst, H, VPre, VPst, O,VMAbv,
- VMBlw, O, O, VAbv, VBlw, VBlw, B, B, VBlw, VBlw, GB,VMAbv,VMPst,VMPst, O, B,
- B, B, B, O, O, B, B, O, B, B, B, O, B, O, VBlw, O,
- O, VPre, VPre, O, O, VPre, VPre, H, O, O, O, O, O, VPst, B, B,
- O, B, B, O,FMAbv, O, O,VMAbv,VMAbv,VMPst, B, B, B, O, O, O,
- O, B, O, B, B, O,CMBlw, O, VPst, VPre, VPst, VBlw, VBlw, O, O, O,
- O, VAbv, VAbv, O, O, VAbv, VAbv, H, O, O, O,VMBlw, O, O,VMAbv,CMAbv,
- GB, GB, O, MBlw, O, O, VBlw, VAbv, O, VAbv, VAbv, VAbv, O, VPst, VPst, H,
- O, O, O, B,VMAbv,VMAbv,VMAbv,CMAbv,CMAbv,CMAbv, O,VMAbv,VMPst,VMPst,CMBlw, B,
- VPst, VAbv, O, VAbv, VAbv, VAbv, O, B, O, O, O, O,VMAbv, O, O, O,
- VPst, VPst, VAbv, VPst, VPst, O, O, O, VPre, VPre, VPre, O, VPre, VPre,VMAbv,VMPst,
- VMPst,VMPst,VMAbv, B, B, B,CMBlw, B, VAbv, VAbv, VPst, O, VAbv, VAbv, VAbv, O,
- VAbv, VAbv, O, VAbv, VBlw, O, B,VMAbv,VMPst,VMPst, O, VPst, VPst, O, O, CS,
- CS, O,VMAbv,VMAbv,VMPst,VMPst, B, B, B, VAbv, VAbv, B, VPst, VPst, VPst, VPst,
- VPst, VBlw, VBlw, O, VPre, VPre, VPre, H, R, O, O, O, HVM, O, VPst, VPst,
- VAbv, VAbv, VBlw, O, VBlw, O, VPst, VPre, VPre, VPre, VPre, VPre, VPre, VPst, VBlw, VBlw,
- O, O, O, FBlw, O, FBlw, O,CMAbv, O, O, O, O, VPst, VPre, O,CMBlw,
- VBlw, VAbv, VAbv, VBlw, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw,VMAbv, O, VBlw, VAbv,
- VMAbv,VMAbv, VBlw, O,VMAbv,VMAbv, B, SUB, SUB, SUB, SUB, SUB, SUB, SUB, O, SUB,
- SUB, SUB, SUB, O, O, O, O, O, FBlw, O, B, B, B, VPst, VPst, VAbv,
- VAbv, VBlw, VBlw, VPre, VAbv, VAbv, VAbv, VAbv,VMAbv,VMBlw,VMPst, IS, VAbv, MPst, MPre, MBlw,
- MBlw, B, B, B, O, GB, O, O, GB, O, B, B, VPst, VPst, VBlw, VBlw,
- B, B, B, B, MBlw, MBlw, MBlw, B, VPst,VMPst,VMPst, B, B, VPst, VPst,VMPst,
- VMPst,VMPst,VMPst,VMPst, B, B, B, VAbv, VAbv, VAbv, VAbv, B, B, B, B, B,
- MBlw, VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMPst,VMPst,VMPst,VMPst,VMBlw, B,VMPst, B, B,
- VMPst,VMPst, VPst, VAbv, O, O, B, B, VAbv, VBlw, VBlw, VPst, O, O, VPst, O,
- O, O, B, O, VAbv, VBlw, CGJ, CGJ, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw,
- VPre, VPre, VPre, VPre, VPre, VPre, VPre, VPre,VMAbv,VMPst, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,
- FMAbv,VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, O, O, O, O, B, CGJ, CGJ, CGJ,
- WJ, CGJ, GB, GB, GB, GB, GB,CMAbv,CMAbv, B, B,CMBlw, B, O, GB, B,
- B, B, VAbv, VAbv, VBlw, VPst, VPst, VAbv, VAbv, VAbv, VAbv, SUB, SUB, SUB, FPst, FPst,
- VMBlw, FPst, FPst, FPst, FPst, FPst, FPst, FBlw,VMAbv,FMBlw,VMPst,VMPst, O, O, VAbv, VPre,
- VPst, VAbv, B, MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, SUB, SUB, SUB, O, Sk, VPst,
- VAbv, VPst, VAbv, VBlw, VBlw, VAbv, VBlw, VPst, VPre, VPre, VPre, VPre, VPre, VAbv,VMAbv,VMAbv,
- VAbv,VMAbv,VMAbv, O, O,VMBlw,VMAbv,VMAbv,VMAbv, FAbv,VMPst, B, B, B,CMAbv, VPst,
- VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VPre, VPre, VPre, VPre, VAbv, VAbv, H, B,
- B, B, O, O, O,SMAbv,SMBlw,SMAbv,SMAbv,SMAbv,SMAbv,SMAbv,SMAbv,SMAbv,VMAbv, FAbv,
- VMPst, B, VAbv, VBlw, VPre, VPst, VAbv, VAbv, VPst, IS, SUB, SUB, B, B, B, B,
- CMAbv, VPst, VAbv, VAbv, VPst, VPst, VPst, VAbv, VPst, VAbv, FAbv, FAbv,CMBlw,CMBlw, SUB, SUB,
- VPst, VPre, VPre, VPre, VPst, VPst, VBlw, FAbv, FAbv, FAbv, FAbv, FAbv, FAbv, FAbv,VMPre,VMPre,
- FMAbv,CMBlw,VMAbv,VMAbv,VMAbv, O,VMBlw,VMBlw,VMBlw,VMBlw,VMBlw,VMBlw,VMAbv,VMAbv,VMAbv,VMPst,
- VMBlw,VMBlw,VMBlw, O, O, O,VMAbv, CS, CS,VMPst,VMAbv,VMAbv, GB, O, O, O,
- O,FMAbv, O, O, O, WJ, ZWNJ, CGJ, WJ, WJ, O, O, WJ, WJ, WJ, WJ,
- WJ, O, WJ, WJ, WJ, WJ,FMPst, O, O, O,VMAbv, O, O, O, O, O,
- O, H, B, B, VAbv, B, B, B, H, B, VPst, VBlw, VAbv, VPst, VBlw, O,
- O, O, MPst, VPst, VPst, VPst, VPst, VPst, VPst, VPst, H,VMAbv, O, O,VMAbv,VMAbv,
- B, B, O, O, B, VAbv, B, B, VAbv, VAbv, VAbv, VAbv, VAbv,VMBlw,VMBlw,VMBlw,
- O, O, B, B, B, VBlw, VBlw, VBlw, VAbv, VBlw, VBlw, VBlw, VBlw, FAbv, FAbv, FAbv,
- FPst, VPst,VMAbv,VMAbv, FAbv,VMPst, B, B, B,CMAbv, VAbv, MBlw, MPst, MBlw, H, O,
- O, O, B, VAbv, O, B, B,VMAbv, VAbv, VAbv, VAbv, VBlw, VAbv, VPre, VPre, VAbv,
- VBlw, MPst, MPre, MAbv, MBlw, O, B, B, B, FAbv, FAbv, FPst, O, O, GB, GB,
- GB, O, O, O, B,VMPst,VMAbv,VMPst, B, B, VAbv, B, VAbv, VAbv, VBlw, B,
- B, VAbv, B, B, VAbv,VMAbv, B,VMAbv, B, O, B, B, B, VPre, VBlw, VAbv,
- VPre, VPst, O,VMPst, IS, O, VPst, VAbv, VPst, VPst, VBlw, VPst, VPst, O,VMPst, VBlw,
- O, O, CGJ, CGJ, CGJ, CGJ, WJ, O, O, O, B, VBlw, VBlw, VBlw, VPst,VMBlw,
- VMBlw,VMAbv,CMBlw,CMBlw,CMBlw, O, O, O, O, IS, B,CMBlw,CMBlw, O,VMAbv,VMAbv,
- VMAbv,CMAbv, B, B, O, VAbv, VAbv, O, O, O, B, B,VMBlw,VMBlw,VMBlw, B,
- B, B, B, B,CMBlw,CMBlw,CMBlw,CMBlw, O, O,VMPst,VMAbv,VMPst, CS, CS, B,
- B, B, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, H, O, O, O,
- N, N, N, N, N, N, N, N, B, B, VAbv, B, B, VAbv, VAbv, B,
- O, O, O, O, O, HN,VMAbv,VMAbv,VMPst, B, VPst, VPre, VPst, VBlw, VBlw, VAbv,
- VAbv, VPst, VPst, H,CMBlw, O, O, O, VBlw, O,VMAbv,VMAbv,VMAbv, B, VPre, VBlw,
- VAbv, VAbv, VBlw, VAbv, VAbv, IS,CMAbv, O, B, B, B, VPst, VPst, B, B, B,
- B,CMBlw, VPre, VPst, VBlw, VBlw, H, B, R, R, O,FMBlw,CMBlw, VAbv, VBlw, O,
- VPre,VMAbv,VMAbv, H,CMAbv,CMAbv, VAbv,CMBlw, VBlw, O, B, B, O,CMBlw,CMBlw, B,
- VPst, VPst, VPst, O, O, VPre, O, O,VMAbv,VMAbv, B, VPst, VPre, VPst, VPst, VPst,
- H,VMAbv,VMAbv,VMPst,CMBlw, B, O, O,FMAbv, B, CS, CS, O, O, VBlw, VPre,
- VAbv, VPre, VPre, VPst, VPre,VMAbv,VMAbv,VMAbv, H,CMBlw,VMAbv,VMAbv,VMPst, H,CMBlw, O,
- O, O, VPst,VMAbv,VMPst, H,VMPst, VAbv, VPre, VPst, VAbv, VAbv, H,CMBlw, O, MBlw,
- MPre, MAbv, VBlw, VBlw, VPre, VAbv, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv,VMAbv,VMPst, H,
- CMBlw, O, VPst, VPre, O, VPre, VPre, O, O,VMAbv,VMAbv, VPst, IS, R, MPst, R,
- MPst,CMBlw, O, O, VAbv, VAbv, VPst, VPst,VMPst,VMPst, H, B, O, O, VPre, O,
- O, O, B, VAbv, VBlw, VBlw, VAbv, VAbv, VBlw, B, B, B, B,FMBlw, VBlw,VMAbv,
- VMAbv,VMAbv,VMAbv,VMPst, R, MBlw, MBlw, MBlw, MBlw, GB, O, GB, O, IS, VAbv, VAbv,
- VAbv, VPst, R, R, R, R, R, R, FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, FBlw,
- VMAbv,VMPst,CMAbv, IS, O, O, VBlw, VBlw, VBlw, O, O, O, SUB, SUB, VBlw, VPre,
- VBlw, VAbv, VPst,VMAbv,VMAbv, O, VAbv, VAbv, VBlw, O, O, O, VAbv, O, VAbv, VAbv,
- O, VAbv,VMAbv,VMAbv,CMBlw, VAbv, VBlw, IS, R, MBlw, VPst, VPst, VPst, O, VPst,VMAbv,
- VMPst, IS, B, B, GB, VAbv, VBlw, VPre, VPst, O, H, H, H, H, H, H,
- H, B, O, O, O,CMBlw, O, VBlw, VBlw, VBlw, O, O, O,VMBlw,VMBlw,VMBlw,
- VMBlw, O, O,CMBlw,CMBlw, O, B, B,VMAbv, O,CMAbv,CMAbv,CMAbv,CMAbv,CMAbv,CMAbv,
- CMAbv, B,
+ 16, 50, 51, 51, 51, 52, 51, 83, 118, 131, 51, 57, 58, 179, 195, 61,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 14, 0, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 4, 2, 2,
+ 5, 6, 2, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 2, 2, 17,
+ 18, 19, 20, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 21,
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 2, 33, 2, 2, 2,
+ 2, 34, 35, 2, 2, 2, 2, 2, 2, 2, 2, 2, 36, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 37, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 38, 39, 40, 41, 42, 43, 2, 44, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 45, 46, 2,
+ 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 48, 49, 2, 2, 2,
+ 2, 2, 2, 2, 2, 50, 51, 2, 52, 2, 2, 53, 2, 2, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63, 2, 64, 65, 2, 66, 67, 68, 69,
+ 2, 70, 2, 71, 72, 73, 74, 2, 2, 75, 76, 77, 78, 2, 79, 2,
+ 2, 80, 80, 80, 80, 80, 80, 80, 80, 81, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 82, 83, 2, 2, 2, 2, 2, 2, 2, 84,
+ 85, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 80, 80, 80, 86, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 87, 88, 2, 2, 2, 2, 2,
+ 2, 2, 2, 89, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 90, 2, 2, 91, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 92, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 93, 93, 94, 95, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 0, 2, 2, 2, 2, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4,
+ 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 8, 9, 9, 9, 9, 0, 0, 0, 7, 10,
+ 0, 2, 2, 2, 2, 11, 12, 0, 0, 9, 13, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 14, 15, 16, 17, 18, 19, 20, 14, 21, 22,
+ 23, 10, 24, 25, 18, 2, 2, 2, 2, 2, 18, 0, 2, 2, 2, 2,
+ 2, 0, 2, 2, 2, 2, 2, 2, 2, 26, 27, 28, 2, 2, 2, 7,
+ 28, 7, 28, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 2, 2,
+ 2, 7, 7, 0, 2, 2, 0, 15, 16, 17, 18, 29, 30, 31, 30, 32,
+ 0, 0, 0, 0, 33, 0, 0, 2, 28, 2, 0, 0, 0, 0, 0, 7,
+ 34, 10, 13, 28, 2, 2, 7, 0, 28, 7, 2, 28, 7, 2, 0, 35,
+ 16, 17, 29, 0, 25, 36, 25, 37, 0, 38, 0, 0, 0, 28, 2, 7,
+ 7, 0, 0, 0, 2, 2, 2, 2, 2, 39, 40, 41, 0, 0, 0, 0,
+ 0, 10, 13, 28, 2, 2, 2, 2, 28, 2, 28, 2, 2, 2, 2, 2,
+ 2, 7, 2, 28, 2, 2, 0, 15, 16, 17, 18, 19, 25, 20, 33, 22,
+ 0, 0, 0, 0, 0, 28, 9, 39, 42, 10, 27, 28, 2, 2, 2, 7,
+ 28, 7, 2, 28, 2, 2, 0, 15, 43, 0, 0, 25, 20, 0, 0, 2,
+ 28, 28, 0, 0, 0, 0, 0, 0, 0, 0, 44, 28, 2, 2, 7, 0,
+ 2, 7, 2, 2, 0, 28, 7, 7, 2, 0, 28, 7, 0, 2, 7, 0,
+ 2, 2, 2, 2, 2, 2, 0, 0, 21, 14, 45, 0, 46, 31, 46, 32,
+ 0, 0, 0, 0, 33, 0, 0, 0, 0, 13, 27, 47, 2, 2, 2, 7,
+ 2, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 15,
+ 20, 14, 21, 45, 20, 36, 20, 37, 0, 0, 0, 25, 29, 2, 7, 0,
+ 0, 8, 27, 28, 2, 2, 2, 7, 2, 2, 2, 28, 2, 2, 0, 15,
+ 43, 0, 0, 33, 45, 0, 0, 0, 7, 48, 49, 0, 0, 0, 0, 0,
+ 0, 9, 27, 2, 2, 2, 2, 7, 2, 2, 2, 2, 2, 2, 50, 51,
+ 21, 21, 17, 29, 46, 31, 46, 32, 52, 0, 0, 0, 33, 0, 0, 0,
+ 28, 10, 27, 28, 2, 2, 2, 2, 2, 2, 2, 2, 7, 0, 2, 2,
+ 2, 2, 28, 2, 2, 2, 2, 28, 0, 2, 2, 2, 7, 0, 53, 0,
+ 33, 21, 20, 29, 29, 16, 46, 46, 23, 0, 21, 0, 0, 0, 0, 0,
+ 0, 2, 0, 2, 7, 0, 0, 0, 0, 0, 0, 0, 0, 18, 0, 0,
+ 0, 2, 2, 54, 54, 55, 0, 0, 16, 2, 2, 2, 2, 28, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 7, 0, 56, 19, 57, 20, 20, 18, 18,
+ 44, 19, 9, 29, 9, 2, 2, 58, 59, 59, 59, 59, 59, 60, 59, 59,
+ 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61,
+ 0, 0, 0, 0, 62, 0, 0, 0, 0, 2, 2, 2, 2, 2, 63, 43,
+ 57, 64, 20, 20, 65, 66, 67, 68, 69, 2, 2, 2, 2, 2, 1, 0,
+ 3, 2, 2, 2, 21, 18, 2, 2, 70, 69, 71, 72, 63, 71, 27, 27,
+ 2, 50, 20, 51, 2, 2, 2, 2, 2, 2, 73, 74, 75, 27, 27, 76,
+ 77, 2, 2, 2, 2, 2, 27, 43, 0, 2, 57, 78, 0, 0, 0, 0,
+ 28, 2, 57, 45, 0, 0, 0, 0, 0, 2, 57, 0, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 2, 7, 2, 7, 57, 0, 0, 0, 0, 0,
+ 0, 2, 2, 79, 43, 20, 57, 18, 46, 46, 46, 46, 13, 80, 81, 82,
+ 83, 84, 85, 0, 0, 0, 0, 86, 0, 7, 0, 0, 28, 0, 87, 79,
+ 88, 2, 2, 2, 2, 7, 0, 0, 0, 40, 40, 89, 90, 2, 2, 2,
+ 2, 2, 2, 2, 2, 11, 7, 0, 0, 91, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 7, 20, 78, 43, 20, 92, 59, 0,
+ 0, 93, 94, 93, 93, 95, 96, 0, 0, 2, 2, 2, 2, 2, 2, 2,
+ 0, 2, 2, 7, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0,
+ 0, 2, 2, 2, 2, 27, 0, 0, 0, 2, 2, 2, 2, 2, 7, 0,
+ 0, 2, 2, 2, 50, 97, 43, 0, 0, 2, 2, 98, 99, 100, 101, 59,
+ 61, 102, 14, 43, 20, 57, 19, 78, 46, 46, 74, 9, 9, 9, 103, 44,
+ 38, 9, 104, 72, 2, 2, 2, 2, 2, 2, 2, 105, 20, 18, 18, 20,
+ 46, 46, 20, 106, 2, 2, 2, 7, 0, 0, 0, 0, 0, 0, 107, 108,
+ 109, 109, 109, 0, 0, 0, 0, 0, 0, 104, 72, 2, 2, 2, 2, 2,
+ 2, 58, 59, 57, 23, 20, 110, 59, 2, 2, 2, 2, 105, 20, 21, 43,
+ 43, 100, 12, 0, 0, 0, 0, 0, 0, 2, 2, 59, 16, 46, 21, 111,
+ 100, 100, 100, 112, 113, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 28,
+ 2, 9, 44, 114, 114, 114, 9, 114, 114, 13, 114, 114, 114, 24, 0, 38,
+ 0, 0, 0, 115, 116, 9, 3, 0, 0, 0, 0, 0, 0, 0, 117, 0,
+ 0, 0, 0, 0, 0, 0, 4, 118, 119, 40, 40, 3, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 119, 119, 120, 119, 119, 119, 119, 119, 119, 119,
+ 119, 0, 0, 121, 0, 0, 0, 0, 0, 0, 5, 121, 0, 0, 0, 0,
+ 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7,
+ 0, 2, 2, 2, 2, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0,
+ 122, 2, 51, 2, 106, 2, 8, 2, 2, 2, 63, 17, 14, 0, 0, 29,
+ 0, 2, 2, 0, 0, 0, 0, 0, 0, 27, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 123, 21, 21, 21, 21, 21, 21, 21, 124, 0, 0, 0, 0,
+ 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 0,
+ 50, 2, 2, 2, 20, 20, 125, 114, 0, 2, 2, 2, 126, 18, 57, 18,
+ 111, 100, 127, 0, 0, 0, 0, 0, 0, 9, 128, 2, 2, 2, 2, 2,
+ 2, 2, 129, 21, 20, 18, 46, 130, 131, 132, 0, 0, 0, 0, 0, 0,
+ 0, 2, 2, 50, 28, 2, 2, 2, 2, 2, 2, 2, 2, 8, 20, 57,
+ 97, 74, 133, 134, 135, 0, 0, 0, 0, 2, 136, 2, 2, 2, 2, 137,
+ 0, 28, 2, 40, 3, 0, 77, 13, 2, 51, 20, 138, 50, 51, 2, 2,
+ 103, 8, 7, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 139, 19,
+ 23, 0, 0, 140, 141, 0, 0, 0, 0, 2, 63, 43, 21, 78, 45, 142,
+ 0, 79, 79, 79, 79, 79, 79, 79, 79, 0, 0, 0, 0, 0, 0, 0,
+ 4, 119, 119, 119, 119, 120, 0, 0, 0, 2, 2, 2, 2, 2, 7, 2,
+ 2, 2, 7, 2, 28, 2, 2, 2, 2, 2, 28, 2, 2, 2, 28, 7,
+ 0, 126, 18, 25, 29, 0, 0, 143, 144, 2, 2, 28, 2, 28, 2, 2,
+ 2, 2, 2, 2, 0, 12, 35, 0, 145, 2, 2, 11, 35, 0, 28, 2,
+ 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 2, 2,
+ 7, 2, 2, 9, 39, 0, 0, 0, 0, 2, 2, 2, 2, 2, 25, 36,
+ 0, 2, 2, 2, 114, 114, 114, 114, 114, 146, 2, 7, 0, 0, 0, 0,
+ 0, 2, 12, 12, 0, 0, 0, 0, 0, 7, 2, 2, 7, 2, 2, 2,
+ 2, 28, 2, 7, 0, 28, 2, 0, 0, 147, 148, 149, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 20, 20, 18, 18, 18, 20, 20, 132, 0, 0, 0,
+ 0, 0, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 2, 2, 2, 2,
+ 2, 51, 50, 51, 0, 0, 0, 0, 151, 9, 72, 2, 2, 2, 2, 2,
+ 2, 16, 17, 19, 14, 22, 35, 0, 0, 0, 29, 0, 0, 0, 0, 0,
+ 0, 9, 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 126, 18, 20, 152,
+ 20, 19, 153, 154, 2, 2, 2, 2, 2, 0, 0, 63, 155, 0, 0, 0,
+ 0, 2, 11, 0, 0, 0, 0, 0, 0, 2, 63, 23, 18, 18, 18, 20,
+ 20, 106, 156, 0, 0, 157, 158, 29, 159, 28, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 21, 17, 20, 20, 160, 42, 0, 0, 0,
+ 44, 2, 2, 2, 7, 7, 2, 2, 28, 2, 2, 2, 2, 2, 2, 2,
+ 28, 2, 2, 2, 2, 2, 2, 2, 8, 16, 17, 19, 20, 161, 29, 0,
+ 0, 9, 9, 28, 2, 2, 2, 7, 28, 7, 2, 28, 2, 2, 56, 15,
+ 21, 14, 21, 45, 30, 31, 30, 32, 0, 0, 0, 0, 33, 0, 0, 0,
+ 2, 2, 21, 0, 9, 9, 9, 44, 0, 9, 9, 44, 0, 0, 0, 0,
+ 0, 2, 2, 63, 23, 18, 18, 18, 20, 21, 124, 13, 15, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 0, 0, 162, 163, 0, 0, 0, 0, 0, 0,
+ 0, 16, 17, 18, 18, 64, 97, 23, 159, 9, 164, 7, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 2, 2, 63, 23, 18, 18, 0, 46, 46, 9,
+ 165, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 18,
+ 0, 21, 17, 18, 18, 19, 14, 80, 165, 36, 0, 0, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 8, 166, 23, 18, 20, 20, 164, 7, 0, 0,
+ 0, 2, 2, 2, 2, 2, 7, 41, 134, 21, 20, 18, 74, 19, 20, 0,
+ 0, 2, 2, 2, 7, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 16,
+ 17, 18, 19, 20, 103, 165, 35, 0, 0, 2, 2, 2, 7, 28, 0, 2,
+ 2, 2, 2, 28, 7, 2, 2, 2, 2, 21, 21, 16, 30, 31, 10, 167,
+ 168, 169, 170, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 2, 2,
+ 2, 63, 23, 18, 18, 0, 20, 21, 27, 106, 0, 31, 0, 0, 0, 0,
+ 0, 50, 18, 20, 20, 20, 138, 2, 2, 2, 171, 172, 9, 13, 173, 70,
+ 174, 0, 0, 1, 145, 0, 0, 0, 0, 50, 18, 20, 14, 17, 18, 2,
+ 2, 2, 2, 156, 156, 156, 175, 175, 175, 175, 175, 175, 13, 176, 0, 28,
+ 0, 20, 18, 18, 29, 20, 20, 9, 165, 0, 59, 59, 59, 59, 59, 59,
+ 59, 64, 19, 80, 44, 0, 0, 0, 0, 2, 2, 2, 7, 2, 28, 2,
+ 2, 50, 20, 20, 29, 0, 36, 20, 25, 9, 158, 177, 173, 0, 0, 0,
+ 0, 2, 2, 2, 28, 7, 2, 2, 2, 2, 2, 2, 2, 2, 21, 21,
+ 45, 20, 33, 80, 66, 0, 0, 0, 0, 2, 178, 64, 45, 0, 0, 0,
+ 0, 179, 179, 179, 106, 7, 0, 0, 0, 9, 9, 9, 44, 0, 0, 0,
+ 0, 2, 2, 2, 2, 2, 7, 0, 56, 180, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0,
+ 38, 114, 24, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0,
+ 0, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 56,
+ 35, 0, 4, 119, 119, 119, 120, 0, 0, 9, 9, 9, 47, 2, 2, 2,
+ 0, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
+ 44, 2, 2, 2, 2, 2, 2, 9, 9, 2, 2, 42, 42, 42, 90, 0,
+ 0, O, O, O, GB, B, B, GB, O, O, WJ,FMPst,FMPst, O, CGJ, B,
+ O, B,VMAbv,VMAbv,VMAbv, O,VMAbv, B,CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw,
+ B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VPst, VPst, VPst, H, VPre,
+ VPst,VMBlw, O, O, VAbv, GB,VMAbv,VMPst,VMPst, O, B, VBlw, O, O, VPre, VPre,
+ O, VPre, H, O, VPst,FMAbv, O,CMBlw, O, VAbv, O, VAbv, H, O,VMBlw,VMAbv,
+ CMAbv, GB, GB, O, MBlw,CMAbv,CMAbv, VPst, VAbv,VMAbv, O, VPst, O, VPre, VPre,VMAbv,
+ B, O, CS, CS, O, B, VAbv, VAbv, B, R, O, HVM, O, O, FBlw, O,
+ CMAbv, O,CMBlw, VAbv, VBlw, B, SUB, SUB, SUB, O, SUB, SUB, O, FBlw, O, B,
+ VPst, VBlw, VPre,VMAbv,VMBlw,VMPst, IS, VAbv, MPst, MPre, MBlw, MBlw, B, MBlw, MBlw, VPst,
+ VMPst,VMPst, B, MBlw, VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw, B,VMPst, VBlw, VPst, CGJ,
+ CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, B,
+ CGJ, WJ, CGJ, GB,CMAbv,CMAbv, B, GB, B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst,
+ FBlw,VMAbv,FMBlw, VAbv, VPre, B, MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,
+ VMAbv,VMAbv, FAbv,CMAbv, VPst, H, B, O,SMAbv,SMBlw,SMAbv,SMAbv,SMAbv, VPst, IS, VBlw,
+ FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv, CS, CS,VMPst, O,FMAbv, ZWNJ, CGJ, WJ,
+ WJ, WJ, O,FMPst, O, O, H, MPst, VPst, H,VMAbv, VAbv,VMBlw, B, VBlw, FPst,
+ VPst, FAbv,VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, H, O, VBlw, MPst, MPre, MAbv, MBlw,
+ O, B, FAbv, FAbv, FPst, VBlw, B, B, VPre, O,VMPst, IS, O,VMPst, VBlw, VPst,
+ VMBlw,VMBlw,VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst, CS, CS, B, N, N, O,
+ HN, VPre, VBlw, VAbv, IS,CMAbv, O, VPst, B, R, R, O,FMBlw,CMBlw, VAbv, VPre,
+ VMAbv,VMAbv, H, VAbv,CMBlw,FMAbv, B, CS, CS, H,CMBlw,VMPst, H,VMPst, VAbv,VMAbv,
+ VPst, IS, R, MPst, R, MPst,CMBlw, B,FMBlw, VBlw,VMAbv, R, MBlw, MBlw, GB, FBlw,
+ FBlw,CMAbv, IS, VBlw, IS, GB, VAbv, H, H, O, VBlw,
};
static const uint16_t
-hb_use_u16[2056] =
+hb_use_u16[768] =
{
0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 5, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11,
- 0, 0, 0, 0, 9, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 13, 9, 9, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 17, 25,
- 26, 20, 21, 27, 28, 29, 30, 31, 32, 33, 21, 34, 35, 0, 17, 36,
- 37, 20, 21, 38, 23, 39, 17, 40, 41, 42, 43, 44, 45, 46, 30, 0,
- 47, 48, 21, 49, 50, 51, 17, 0, 52, 48, 21, 53, 50, 54, 17, 55,
- 56, 48, 9, 57, 58, 59, 17, 0, 60, 61, 9, 62, 63, 64, 30, 65,
- 66, 67, 9, 68, 69, 9, 70, 71, 72, 73, 74, 75, 76, 0, 0, 0,
- 9, 9, 77, 78, 79, 80, 81, 82, 83, 84, 0, 0, 0, 0, 0, 0,
- 9, 85, 9, 86, 9, 87, 88, 89, 9, 9, 9, 90, 91, 92, 2, 0,
- 93, 0, 9, 9, 9, 9, 9, 94, 95, 9, 96, 0, 0, 0, 0, 0,
- 97, 98, 99,100, 30, 9,101,102, 9, 9,103, 9,104,105, 0, 0,
- 9,106, 9, 9, 9,107,108,109, 2, 2, 0, 0, 0, 0, 0, 0,
- 110, 9, 9,111,112, 2,113,114,115, 9,116, 9, 9, 9,117,118,
- 9, 9,119,120,121, 0, 0, 0, 0, 0, 0, 0, 0,122,123,124,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,125,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0,
+ 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 11,
+ 0, 0, 0, 0, 9, 12, 0, 0, 13, 9, 9, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 17, 25, 26, 20, 21, 27, 28, 29, 30, 31,
+ 32, 33, 21, 34, 35, 0, 17, 36, 37, 20, 21, 38, 23, 39, 17, 40,
+ 41, 42, 43, 44, 45, 46, 30, 0, 47, 48, 21, 49, 50, 51, 17, 0,
+ 52, 48, 21, 53, 50, 54, 17, 55, 56, 48, 9, 57, 58, 59, 17, 0,
+ 60, 61, 9, 62, 63, 64, 30, 65, 66, 67, 9, 68, 69, 9, 70, 71,
+ 72, 73, 74, 75, 76, 0, 0, 0, 9, 9, 77, 78, 79, 80, 81, 82,
+ 83, 84, 0, 0, 0, 0, 0, 0, 9, 85, 9, 86, 9, 87, 88, 89,
+ 9, 9, 9, 90, 91, 92, 2, 0, 93, 0, 9, 9, 9, 9, 9, 94,
+ 95, 9, 96, 0, 0, 0, 0, 0, 97, 98, 99,100, 30, 9,101,102,
+ 9, 9,103, 9,104,105, 0, 0, 9,106, 9, 9, 9,107,108,109,
+ 2, 2, 0, 0, 0, 0, 0, 0,110, 9, 9,111,112, 2,113,114,
+ 115, 9,116, 9, 9, 9,117,118, 9, 9,119,120,121, 0, 0, 0,
+ 0, 0, 0, 0, 0,122,123,124, 0, 0, 0, 0, 0, 0, 0,125,
126,127,128, 0, 0, 0,129,130,131, 0, 0, 0, 0, 0, 0,132,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,133, 0, 0, 0,
- 0, 0, 0, 9, 9, 9,134,135, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,133, 0, 0, 0, 0, 0, 0, 9, 9, 9,134,135,
136, 9,137, 0, 9, 9, 9,138,139, 9, 9,140,141, 2,142,143,
9, 9,144, 9,145,146, 0, 0,147, 9, 9,148,149, 2,150, 98,
9, 9,151,152,153, 2, 9,154, 9, 9, 9,155,156, 0,157,158,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9,159, 2,
- 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,161,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,162,
+ 0, 0, 0, 0, 9, 9,159, 2,160, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,161, 0, 0, 0, 0, 0, 0, 0,162,
0, 0, 0, 0, 0, 0, 0,163,163,164, 33,165, 0, 0, 0, 0,
166,167, 9,168, 94, 0, 0, 0, 0, 0, 0, 0, 69, 9,169, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 9,170,171, 0, 0, 0, 0, 0,
- 9, 9,172, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 9, 9,173,170, 0, 0, 0, 0,
- 0, 0, 0, 9,174,175, 0, 9,176, 0, 0,177,178, 0, 0, 0,
- 179, 9, 9,180,181,182,183,184,185, 9, 9,186,187, 0, 0, 0,
- 188, 9,189,190,191, 9, 9,192,185, 9, 9,193,194,105,195,102,
- 9, 33,196,197, 0, 0, 0, 0,198,199, 94, 9, 9,200,201, 2,
- 202, 20, 21,203,204,205,206,207, 0, 0, 0, 0, 0, 0, 0, 0,
+ 9,170,171, 0, 0, 0, 0, 0, 9, 9,172, 2, 0, 0, 0, 0,
+ 9, 9,173,170, 0, 0, 0, 0, 0, 0, 0, 9,174,175, 0, 9,
+ 176, 0, 0,177,178, 0, 0, 0,179, 9, 9,180,181,182,183,184,
+ 185, 9, 9,186,187, 0, 0, 0,188, 9,189,190,191, 9, 9,192,
+ 185, 9, 9,193,194,105,195,102, 9, 33,196,197, 0, 0, 0, 0,
+ 198,199, 94, 9, 9,200,201, 2,202, 20, 21,203,204,205,206,207,
9, 9, 9,208,209,210,211, 0,195, 9, 9,212,213, 2, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 9, 9,214,215,216,217, 0, 0,
- 9, 9, 9,218,219, 2, 0, 0, 9, 9,220,221, 2, 0, 0, 0,
- 9,222,223,103,224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 9, 9,225,226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 227,228, 9,229,230, 2, 0, 0, 0, 0,231, 9, 9,232,233, 0,
- 234, 9, 9,235,236,237, 9, 9,238,239, 0, 0, 0, 0, 0, 0,
- 21, 9,214,240, 7, 9, 70, 18, 9,241, 73,242, 0, 0, 0, 0,
- 243, 9, 9,244,245, 2,246, 9,247,248, 2, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,249,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 98,250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
- 9, 9, 9,251, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 9, 9,214,215,216,217, 0, 0, 9, 9, 9,218,219, 2, 0, 0,
+ 9, 9,220,221, 2, 0, 0, 0, 9,222,223,103,224, 0, 0, 0,
+ 9, 9,225,226, 0, 0, 0, 0,227,228, 9,229,230, 2, 0, 0,
+ 0, 0,231, 9, 9,232,233, 0,234, 9, 9,235,236,237, 9, 9,
+ 238,239, 0, 0, 0, 0, 0, 0, 21, 9,214,240, 7, 9, 70, 18,
+ 9,241, 73,242, 0, 0, 0, 0,243, 9, 9,244,245, 2,246, 9,
+ 247,248, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,249,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 98,250, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 0, 0, 0, 9, 9, 9,251, 0, 0, 0, 0,
9, 9, 9, 9,252,253,254,254,255,256, 0, 0, 0, 0,257, 0,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,258, 0, 0,
- 9, 9, 9, 9, 9, 9,105, 70, 94,259, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,260, 0, 0, 0, 0, 0, 0, 0, 0,
- 9, 9, 70,261,262, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,263, 0, 9, 9,264, 2,
- 9, 9, 9, 9,265, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,
+ 9, 9, 9, 9, 9,258, 0, 0, 9, 9, 9, 9, 9, 9,105, 70,
+ 94,259, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,260,
+ 9, 9, 70,261,262, 0, 0, 0, 0, 9,263, 0, 9, 9,264, 2,
+ 9, 9, 9, 9,265, 2, 0, 0,129,129,129,129,129,129,129,129,
160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,129,
- 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 0, 4, 0, 0, 5,
- 6, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0,
- 0, 0, 10, 2, 2, 2, 2, 2, 2, 2, 11, 12, 12, 0, 13, 14,
- 2, 2, 15, 0, 16, 2, 2, 2, 2, 2, 17, 18, 19, 20, 21, 22,
- 23, 24, 2, 2, 25, 10, 2, 2, 10, 2, 2, 2, 26, 27, 2, 28,
- 28, 2, 2, 2, 2, 2, 29, 2, 30, 10, 3, 18, 19, 31, 32, 33,
- 0, 34, 0, 35, 3, 0, 0, 36, 37, 27, 38, 39, 29, 40, 3, 41,
- 42, 43, 44, 45, 46, 0, 27, 30, 0, 10, 2, 2, 47, 48, 0, 0,
- 37, 27, 2, 35, 35, 2, 2, 2, 29, 27, 3, 18, 19, 49, 50, 51,
- 0, 0, 52, 53, 54, 27, 2, 28, 29, 27, 3, 55, 0, 56, 0, 35,
- 57, 0, 0, 0, 58, 27, 38, 10, 29, 3, 40, 29, 39, 9, 38, 10,
- 2, 2, 3, 59, 60, 61, 62, 33, 0, 34, 0, 0, 63, 64, 2, 29,
- 29, 2, 2, 2, 2, 2, 3, 65, 21, 66, 67, 45, 0, 68, 38, 0,
- 69, 27, 2, 29, 2, 27, 3, 55, 0, 70, 0, 13, 71, 0, 0, 0,
- 72, 2, 2, 29, 2, 2, 73, 74, 75, 76, 62, 77, 0, 34, 0, 39,
- 54, 27, 2, 2, 2, 38, 10, 2, 35, 2, 2, 57, 2, 38, 78, 34,
- 79, 80, 81, 82, 59, 0, 0, 0, 3, 38, 0, 0, 0, 0, 83, 0,
- 2, 84, 85, 86, 2, 2, 27, 2, 2, 2, 2, 9, 87, 88, 89, 90,
- 91, 92, 2, 93, 94, 94, 95, 94, 94, 94, 94, 94, 94, 94, 94, 96,
- 0, 97, 0, 0, 2, 2, 98, 99,100,101,102,103, 2, 2,104,105,
- 2,106,107,108,109,110,111,112,113,114, 2, 2,115,116,117,118,
- 2, 2,119,120,121,122, 0, 39,121,123, 0, 0,121, 0, 0, 0,
- 2, 2, 2, 29,124, 0, 0, 0, 2,125,126,127,128,129,130,131,
- 132, 0, 0,133, 9, 39,134,135, 2, 2, 9, 0,136,137, 2, 2,
- 2, 2,138, 0,139, 2, 2, 2, 2, 2, 2, 38,140,141,142, 0,
- 143,144,145, 0, 2, 2, 2, 3, 2, 9, 0, 0, 2, 2, 2, 0,
- 2, 2,146, 0, 2, 2, 38, 0, 2, 73,147, 0, 2,148,149,150,
- 151,141,152,153,154, 12,155,156,157,158, 2, 2, 2,159,160,161,
- 162,163, 2, 9, 0, 0,164,165,166, 0, 0, 0,167, 2, 2, 2,
- 93,168,169,170, 2,171,172,173,174, 0, 0, 0, 2,175,176,177,
- 178,179, 0, 0, 2, 2, 3, 27,180,181,182,181,183,181,184, 46,
- 0,185,186, 0, 0, 0,187, 0, 0, 0,188,189,136, 4, 0, 0,
- 0, 0,190,191,192,192,192,192, 0,193, 0, 0, 6,193, 0, 0,
- 194, 0, 0, 0, 0, 0, 0, 9, 2, 2, 0, 39, 0, 0, 0,195,
- 196,197, 11, 2, 98,198, 0,199, 2, 0, 0, 0,112, 2, 2, 2,
- 2,200,201,201,201,202, 0, 0, 12, 12, 12, 12,203, 0, 0,204,
- 2,205,206,207, 2,208,209,210,211, 0, 0, 0,212, 2, 2, 2,
- 213, 79,127,214,215, 0, 0, 0, 2,216, 2, 2, 2, 2,217,218,
- 219,220, 0, 0,221, 2, 2,222, 27,223,224,225,226,227,114,228,
- 229, 0, 0, 0, 2, 2,230,231, 0,232, 0, 0, 98,233,234,235,
- 236,236,236,236, 0, 0, 0,188,192,192,237, 0, 2, 2, 38, 2,
- 38, 35, 2, 2, 35, 2, 35, 9,238, 68, 0,239, 2, 27, 27, 2,
- 2, 3,240,241, 2,242, 39, 2, 3, 0, 0, 0, 0, 0, 27, 38,
- 2,243, 0, 0, 2, 2,244,245, 2,246,181,181,247, 9, 0, 0,
- 248,249, 0, 0, 29, 38, 2, 2, 27, 9, 27, 0,250,251, 2, 2,
- 2, 2,252,160,253,254, 0, 0,255,256,256,256,256,257, 2, 2,
- 258,259, 0,260,261, 2, 2, 2,262,263,264, 0,265, 0, 0, 0,
- 266, 2, 2, 2, 2,208,253,267,268,269, 2, 2, 0,270, 0, 0,
- 271, 0, 0, 0, 98,272,160,252,273, 0,274,275, 27, 2, 2, 2,
- 2, 2, 2, 75,252,276, 0, 58, 2, 38, 29, 35, 2, 2, 2, 35,
- 2, 2, 2, 11,262, 20,277, 0, 12, 27, 2, 28, 29, 27,278,279,
- 21,280, 32, 33, 0, 34, 0, 10,106,281, 12,194, 12,194, 0, 0,
- 2,282,160,253,283,284, 0, 0, 2, 2, 3,285,286, 0, 0, 0,
- 262,160,287,288,289, 9, 0, 0, 2, 2, 2, 98,272, 83,128,290,
- 291, 0, 0, 0, 0, 0, 2, 83, 75,160,263,292,245, 0, 0, 0,
- 2, 2, 11,293,253,294, 9, 0, 2, 2, 38,295, 79,296, 20, 0,
- 2, 38, 0, 0, 2, 2, 2,262,297,298,299, 0, 2, 38, 57, 2,
- 2, 40, 2, 2,201,300,301,302,303, 0, 0, 0, 2, 2, 10, 2,
- 282,160,304,305,306,307, 0, 0,308,252,309, 2,310,311,312,313,
- 0,314, 0, 0,308,315, 19, 2, 2,316,317,318,318,319,320, 57,
- 89,321,252,290,322, 94, 94, 94,323,324, 0, 0, 2, 38, 35, 2,
- 113,325,326,327,328,329, 0, 0, 2, 35, 29, 2, 2, 2,106,330,
- 50,331, 0, 0,332,333, 0, 0,334,335, 9, 0, 12,180, 0, 0,
- 2, 2, 38,336,337,160,160,160,160,160,160,160,160,160, 0,338,
- 339, 0, 0, 0, 0, 9, 0, 0, 2, 3, 0, 0, 2, 2, 3,340,
- 188,192,191, 0, 12,266, 2, 3, 2, 2, 3, 10, 2, 2, 2,341,
- 2, 2, 2, 12, 2,342,343, 0,
};
+static inline unsigned
+hb_use_b4 (const uint8_t* a, unsigned i)
+{
+ return (a[i>>1]>>((i&1u)<<2))&15u;
+}
static inline uint_fast8_t
hb_use_get_category (unsigned u)
{
- return u<921600u?hb_use_u8[466+(((hb_use_u16[992+(((hb_use_u16[((hb_use_u8[226+(((hb_use_u8[u>>2>>2>>4>>4])<<4)+((u>>2>>2>>4)&15u))])<<4)+((u>>2>>2)&15u)])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:O;
+ return u<921600u?hb_use_u8[2721+(((hb_use_u8[593+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
}
#undef B
@@ -392,5 +393,26 @@ hb_use_get_category (unsigned u)
#undef VMPre
+#ifdef HB_USE_TABLE_MAIN
+int main (int argc, char **argv)
+{
+ if (argc != 2)
+ {
+ for (unsigned u = 0; u < 0x10FFFFu; u++)
+ printf ("U+%04X %d\n", u, hb_use_get_category (u));
+ return 0;
+ }
+
+ hb_codepoint_t u;
+ sscanf (argv[1], "%x", &u);
+
+ printf ("%d\n", hb_use_get_category (u));
+
+ return 0;
+}
+
+#endif
+
+
#endif /* HB_OT_SHAPER_USE_TABLE_HH */
/* == End of generated table == */
diff --git a/thirdparty/harfbuzz/src/hb-repacker.hh b/thirdparty/harfbuzz/src/hb-repacker.hh
index 173fe4a2fb..61b142238e 100644
--- a/thirdparty/harfbuzz/src/hb-repacker.hh
+++ b/thirdparty/harfbuzz/src/hb-repacker.hh
@@ -29,10 +29,9 @@
#include "hb-open-type.hh"
#include "hb-map.hh"
-#include "hb-priority-queue.hh"
-#include "hb-serialize.hh"
#include "hb-vector.hh"
#include "graph/graph.hh"
+#include "graph/gsubgpos-graph.hh"
#include "graph/serialize.hh"
using graph::graph_t;
@@ -42,6 +41,143 @@ using graph::graph_t;
* docs/repacker.md
*/
+struct lookup_size_t
+{
+ unsigned lookup_index;
+ size_t size;
+ unsigned num_subtables;
+
+ static int cmp (const void* a, const void* b)
+ {
+ return cmp ((const lookup_size_t*) a,
+ (const lookup_size_t*) b);
+ }
+
+ static int cmp (const lookup_size_t* a, const lookup_size_t* b)
+ {
+ double subtables_per_byte_a = (double) a->num_subtables / (double) a->size;
+ double subtables_per_byte_b = (double) b->num_subtables / (double) b->size;
+ if (subtables_per_byte_a == subtables_per_byte_b) {
+ return b->lookup_index - a->lookup_index;
+ }
+
+ double cmp = subtables_per_byte_b - subtables_per_byte_a;
+ if (cmp < 0) return -1;
+ if (cmp > 0) return 1;
+ return 0;
+ }
+};
+
+static inline
+bool _presplit_subtables_if_needed (graph::gsubgpos_graph_context_t& ext_context)
+{
+ // For each lookup this will check the size of subtables and split them as needed
+ // so that no subtable is at risk of overflowing. (where we support splitting for
+ // that subtable type).
+ //
+ // TODO(grieger): de-dup newly added nodes as necessary. Probably just want a full de-dup
+ // pass after this processing is done. Not super necessary as splits are
+ // only done where overflow is likely, so de-dup probably will get undone
+ // later anyways.
+ for (unsigned lookup_index : ext_context.lookups.keys ())
+ {
+ graph::Lookup* lookup = ext_context.lookups.get(lookup_index);
+ if (!lookup->split_subtables_if_needed (ext_context, lookup_index))
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Analyze the lookups in a GSUB/GPOS table and decide if any should be promoted
+ * to extension lookups.
+ */
+static inline
+bool _promote_extensions_if_needed (graph::gsubgpos_graph_context_t& ext_context)
+{
+ // Simple Algorithm (v1, current):
+ // 1. Calculate how many bytes each non-extension lookup consumes.
+ // 2. Select up to 64k of those to remain as non-extension (greedy, highest subtables per byte first)
+ // 3. Promote the rest.
+ //
+ // Advanced Algorithm (v2, not implemented):
+ // 1. Perform connected component analysis using lookups as roots.
+ // 2. Compute size of each connected component.
+ // 3. Select up to 64k worth of connected components to remain as non-extensions.
+ // (greedy, highest subtables per byte first)
+ // 4. Promote the rest.
+
+ // TODO(garretrieger): support extension demotion, then consider all lookups. Requires advanced algo.
+ // TODO(garretrieger): also support extension promotion during iterative resolution phase, then
+ // we can use a less conservative threshold here.
+ // TODO(grieger): skip this for the 24 bit case.
+ if (!ext_context.lookups) return true;
+
+ hb_vector_t<lookup_size_t> lookup_sizes;
+ lookup_sizes.alloc (ext_context.lookups.get_population ());
+
+ for (unsigned lookup_index : ext_context.lookups.keys ())
+ {
+ const graph::Lookup* lookup = ext_context.lookups.get(lookup_index);
+ hb_set_t visited;
+ lookup_sizes.push (lookup_size_t {
+ lookup_index,
+ ext_context.graph.find_subgraph_size (lookup_index, visited),
+ lookup->number_of_subtables (),
+ });
+ }
+
+ lookup_sizes.qsort ();
+
+ size_t lookup_list_size = ext_context.graph.vertices_[ext_context.lookup_list_index].table_size ();
+ size_t l2_l3_size = lookup_list_size; // Lookup List + Lookups
+ size_t l3_l4_size = 0; // Lookups + SubTables
+ size_t l4_plus_size = 0; // SubTables + their descendants
+
+ // Start by assuming all lookups are using extension subtables, this size will be removed later
+ // if it's decided to not make a lookup extension.
+ for (auto p : lookup_sizes)
+ {
+ unsigned subtables_size = p.num_subtables * 8;
+ l3_l4_size += subtables_size;
+ l4_plus_size += subtables_size;
+ }
+
+ bool layers_full = false;
+ for (auto p : lookup_sizes)
+ {
+ const graph::Lookup* lookup = ext_context.lookups.get(p.lookup_index);
+ if (lookup->is_extension (ext_context.table_tag))
+ // already an extension so size is counted by the loop above.
+ continue;
+
+ if (!layers_full)
+ {
+ size_t lookup_size = ext_context.graph.vertices_[p.lookup_index].table_size ();
+ hb_set_t visited;
+ size_t subtables_size = ext_context.graph.find_subgraph_size (p.lookup_index, visited, 1) - lookup_size;
+ size_t remaining_size = p.size - subtables_size - lookup_size;
+
+ l2_l3_size += lookup_size;
+ l3_l4_size += lookup_size + subtables_size;
+ l3_l4_size -= p.num_subtables * 8;
+ l4_plus_size += subtables_size + remaining_size;
+
+ if (l2_l3_size < (1 << 16)
+ && l3_l4_size < (1 << 16)
+ && l4_plus_size < (1 << 16)) continue; // this lookup fits within all layers groups
+
+ layers_full = true;
+ }
+
+ if (!ext_context.lookups.get(p.lookup_index)->make_extension (ext_context, p.lookup_index))
+ return false;
+ }
+
+ return true;
+}
+
static inline
bool _try_isolating_subgraphs (const hb_vector_t<graph::overflow_record_t>& overflows,
graph_t& sorted_graph)
@@ -157,7 +293,8 @@ template<typename T>
inline hb_blob_t*
hb_resolve_overflows (const T& packed,
hb_tag_t table_tag,
- unsigned max_rounds = 20) {
+ unsigned max_rounds = 20,
+ bool recalculate_extensions = false) {
graph_t sorted_graph (packed);
sorted_graph.sort_shortest_distance ();
@@ -167,13 +304,31 @@ hb_resolve_overflows (const T& packed,
return graph::serialize (sorted_graph);
}
+ graph::gsubgpos_graph_context_t ext_context (table_tag, sorted_graph);
if ((table_tag == HB_OT_TAG_GPOS
|| table_tag == HB_OT_TAG_GSUB)
&& will_overflow)
{
+ if (recalculate_extensions)
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Splitting subtables if needed.");
+ if (!_presplit_subtables_if_needed (ext_context)) {
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Subtable splitting failed.");
+ return nullptr;
+ }
+
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Promoting lookups to extensions if needed.");
+ if (!_promote_extensions_if_needed (ext_context)) {
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Extensions promotion failed.");
+ return nullptr;
+ }
+ }
+
DEBUG_MSG (SUBSET_REPACK, nullptr, "Assigning spaces to 32 bit subgraphs.");
if (sorted_graph.assign_spaces ())
sorted_graph.sort_shortest_distance ();
+ else
+ sorted_graph.sort_shortest_distance_if_needed ();
}
unsigned round = 0;
diff --git a/thirdparty/harfbuzz/src/hb-set.cc b/thirdparty/harfbuzz/src/hb-set.cc
index 5bf9d7c8cd..0270b21998 100644
--- a/thirdparty/harfbuzz/src/hb-set.cc
+++ b/thirdparty/harfbuzz/src/hb-set.cc
@@ -145,7 +145,7 @@ hb_set_set_user_data (hb_set_t *set,
* Since: 0.9.2
**/
void *
-hb_set_get_user_data (hb_set_t *set,
+hb_set_get_user_data (const hb_set_t *set,
hb_user_data_key_t *key)
{
return hb_object_get_user_data (set, key);
diff --git a/thirdparty/harfbuzz/src/hb-set.h b/thirdparty/harfbuzz/src/hb-set.h
index 56902c267e..93636ab5d7 100644
--- a/thirdparty/harfbuzz/src/hb-set.h
+++ b/thirdparty/harfbuzz/src/hb-set.h
@@ -77,7 +77,7 @@ hb_set_set_user_data (hb_set_t *set,
hb_bool_t replace);
HB_EXTERN void *
-hb_set_get_user_data (hb_set_t *set,
+hb_set_get_user_data (const hb_set_t *set,
hb_user_data_key_t *key);
diff --git a/thirdparty/harfbuzz/src/hb-shape-plan.cc b/thirdparty/harfbuzz/src/hb-shape-plan.cc
index 8dbb661cd2..9e513c0458 100644
--- a/thirdparty/harfbuzz/src/hb-shape-plan.cc
+++ b/thirdparty/harfbuzz/src/hb-shape-plan.cc
@@ -358,8 +358,8 @@ hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan,
* Since: 0.9.7
**/
void *
-hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan,
- hb_user_data_key_t *key)
+hb_shape_plan_get_user_data (const hb_shape_plan_t *shape_plan,
+ hb_user_data_key_t *key)
{
return hb_object_get_user_data (shape_plan, key);
}
diff --git a/thirdparty/harfbuzz/src/hb-shape-plan.h b/thirdparty/harfbuzz/src/hb-shape-plan.h
index fc7c041899..aaf5cf9c45 100644
--- a/thirdparty/harfbuzz/src/hb-shape-plan.h
+++ b/thirdparty/harfbuzz/src/hb-shape-plan.h
@@ -102,8 +102,8 @@ hb_shape_plan_set_user_data (hb_shape_plan_t *shape_plan,
hb_bool_t replace);
HB_EXTERN void *
-hb_shape_plan_get_user_data (hb_shape_plan_t *shape_plan,
- hb_user_data_key_t *key);
+hb_shape_plan_get_user_data (const hb_shape_plan_t *shape_plan,
+ hb_user_data_key_t *key);
HB_EXTERN hb_bool_t
diff --git a/thirdparty/harfbuzz/src/hb-subset-repacker.cc b/thirdparty/harfbuzz/src/hb-subset-repacker.cc
index 03e3feb1f6..55ca48d709 100644
--- a/thirdparty/harfbuzz/src/hb-subset-repacker.cc
+++ b/thirdparty/harfbuzz/src/hb-subset-repacker.cc
@@ -25,18 +25,24 @@
#include "hb-repacker.hh"
#ifdef HB_EXPERIMENTAL_API
+
/**
* hb_subset_repack_or_fail:
+ * @table_tag: tag of the table being packed, needed to allow table specific optimizations.
* @hb_objects: raw array of struct hb_object_t, which provides
* object graph info
* @num_hb_objs: number of hb_object_t in the hb_objects array.
*
* Given the input object graph info, repack a table to eliminate
* offset overflows. A nullptr is returned if the repacking attempt fails.
+ * Table specific optimizations (eg. extension promotion in GSUB/GPOS) may be performed.
+ * Passing HB_TAG_NONE will disable table specific optimizations.
*
* Since: EXPERIMENTAL
**/
-hb_blob_t* hb_subset_repack_or_fail (hb_object_t* hb_objects, unsigned num_hb_objs)
+hb_blob_t* hb_subset_repack_or_fail (hb_tag_t table_tag,
+ hb_object_t* hb_objects,
+ unsigned num_hb_objs)
{
hb_vector_t<const hb_object_t *> packed;
packed.alloc (num_hb_objs + 1);
@@ -44,6 +50,9 @@ hb_blob_t* hb_subset_repack_or_fail (hb_object_t* hb_objects, unsigned num_hb_ob
for (unsigned i = 0 ; i < num_hb_objs ; i++)
packed.push (&(hb_objects[i]));
- return hb_resolve_overflows (packed, HB_OT_TAG_GSUB);
+ return hb_resolve_overflows (packed,
+ table_tag,
+ 20,
+ true);
}
#endif
diff --git a/thirdparty/harfbuzz/src/hb-subset-repacker.h b/thirdparty/harfbuzz/src/hb-subset-repacker.h
index e28f879362..245cf60765 100644
--- a/thirdparty/harfbuzz/src/hb-subset-repacker.h
+++ b/thirdparty/harfbuzz/src/hb-subset-repacker.h
@@ -70,7 +70,8 @@ struct hb_object_t
typedef struct hb_object_t hb_object_t;
HB_EXTERN hb_blob_t*
-hb_subset_repack_or_fail (hb_object_t* hb_objects,
+hb_subset_repack_or_fail (hb_tag_t table_tag,
+ hb_object_t* hb_objects,
unsigned num_hb_objs);
#endif
diff --git a/thirdparty/harfbuzz/src/hb-ucd-table.hh b/thirdparty/harfbuzz/src/hb-ucd-table.hh
index 9e76ca460b..14734c91ea 100644
--- a/thirdparty/harfbuzz/src/hb-ucd-table.hh
+++ b/thirdparty/harfbuzz/src/hb-ucd-table.hh
@@ -1068,2860 +1068,6 @@ _hb_ucd_dm2_u64_map[388] =
#ifndef HB_OPTIMIZE_SIZE
static const uint8_t
-_hb_ucd_u8[33120] =
-{
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 27, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 28, 26, 29, 30, 31, 32, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 33, 34, 34, 34, 34,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
- 26, 56, 57, 58, 58, 58, 58, 59, 26, 26, 60, 58, 58, 58, 58, 58,
- 58, 58, 26, 61, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 26, 62, 58, 63, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 64, 26, 26, 65, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 66, 67, 68, 58, 58, 58, 58, 69, 58,
- 58, 58, 58, 58, 58, 58, 58, 70, 71, 72, 73, 74, 75, 76, 58, 77,
- 78, 79, 58, 80, 81, 58, 82, 83, 84, 85, 75, 86, 87, 88, 58, 58,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 89, 26, 26, 26, 26, 26, 26, 26, 90, 91, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 92, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 93, 58, 58, 58, 58, 58, 58, 26, 94, 58, 58,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 95, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 96, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 97,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 98,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 29, 21, 21, 21, 23, 21, 21, 21, 22, 18, 21, 25, 21, 17, 21, 21,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 25, 25, 25, 21,
- 21, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 22, 21, 18, 24, 16,
- 24, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 22, 25, 18, 25, 0,
- 29, 21, 23, 23, 23, 23, 26, 21, 24, 26, 7, 20, 25, 1, 26, 24,
- 26, 25, 15, 15, 24, 5, 21, 21, 24, 15, 7, 19, 15, 15, 15, 21,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 25, 9, 9, 9, 9, 9, 9, 9, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 25, 5, 5, 5, 5, 5, 5, 5, 5,
- 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5,
- 9, 5, 9, 5, 9, 5, 9, 5, 5, 9, 5, 9, 5, 9, 5, 9,
- 5, 9, 5, 9, 5, 9, 5, 9, 5, 5, 9, 5, 9, 5, 9, 5,
- 9, 5, 9, 5, 9, 5, 9, 5, 9, 9, 5, 9, 5, 9, 5, 5,
- 5, 9, 9, 5, 9, 5, 9, 9, 5, 9, 9, 9, 5, 5, 9, 9,
- 9, 9, 5, 9, 9, 5, 9, 9, 9, 5, 5, 5, 9, 9, 5, 9,
- 9, 5, 9, 5, 9, 5, 9, 9, 5, 9, 5, 5, 9, 5, 9, 9,
- 5, 9, 9, 9, 5, 9, 5, 9, 9, 5, 5, 7, 9, 5, 5, 5,
- 7, 7, 7, 7, 9, 8, 5, 9, 8, 5, 9, 8, 5, 9, 5, 9,
- 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 5, 9, 5,
- 5, 9, 8, 5, 9, 5, 9, 9, 9, 5, 9, 5, 9, 5, 9, 5,
- 9, 5, 9, 5, 5, 5, 5, 5, 5, 5, 9, 9, 5, 9, 9, 5,
- 5, 9, 5, 9, 9, 9, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5,
- 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 24, 24, 24, 24, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 6, 6, 6, 6, 6, 24, 24, 24, 24, 24, 24, 24, 6, 24, 6, 24,
- 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 9, 5, 9, 5, 6, 24, 9, 5, 2, 2, 6, 5, 5, 5, 21, 9,
- 2, 2, 2, 2, 24, 24, 9, 21, 9, 9, 9, 2, 9, 2, 9, 9,
- 5, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 9,
- 5, 5, 9, 9, 9, 5, 5, 5, 9, 5, 9, 5, 9, 5, 9, 5,
- 5, 5, 5, 5, 9, 5, 25, 9, 5, 9, 9, 5, 5, 9, 9, 9,
- 9, 5, 26, 12, 12, 12, 12, 12, 11, 11, 9, 5, 9, 5, 9, 5,
- 9, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 5,
- 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 2, 2, 6, 21, 21, 21, 21, 21, 21,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 21, 17, 2, 2, 26, 26, 23,
- 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 12,
- 21, 12, 12, 21, 12, 12, 21, 12, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 7,
- 7, 7, 7, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 1, 1, 1, 1, 1, 1, 25, 25, 25, 21, 21, 23, 21, 21, 26, 26,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 1, 21, 21, 21,
- 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21, 7, 7,
- 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 21, 7, 12, 12, 12, 12, 12, 12, 12, 1, 26, 12,
- 12, 12, 12, 12, 12, 6, 6, 12, 12, 26, 12, 12, 12, 12, 7, 7,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 7, 7, 7, 26, 26, 7,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, 1,
- 7, 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 2, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 6, 6, 26, 21, 21, 21, 6, 2, 2, 12, 23, 23,
- 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 6, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 6, 12, 12, 12, 6, 12, 12, 12, 12, 12, 2, 2,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 2, 2, 21, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 24, 7, 7, 7, 7, 7, 7, 2,
- 1, 1, 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 12, 12, 12, 12,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 12, 12, 12, 12, 12, 12,
- 12, 12, 1, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 10, 12, 7, 10, 10,
- 10, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 10, 10, 12, 10, 10,
- 7, 12, 12, 12, 12, 12, 12, 12, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 12, 12, 21, 21, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 21, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 12, 10, 10, 2, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 7,
- 7, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7,
- 7, 2, 7, 2, 2, 2, 7, 7, 7, 7, 2, 2, 12, 7, 10, 10,
- 10, 12, 12, 12, 12, 2, 2, 10, 10, 2, 2, 10, 10, 12, 7, 2,
- 2, 2, 2, 2, 2, 2, 2, 10, 2, 2, 2, 2, 7, 7, 2, 7,
- 7, 7, 12, 12, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 7, 7, 23, 23, 15, 15, 15, 15, 15, 15, 26, 23, 7, 21, 12, 2,
- 2, 12, 12, 10, 2, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 7,
- 7, 2, 7, 7, 2, 7, 7, 2, 7, 7, 2, 2, 12, 2, 10, 10,
- 10, 12, 12, 2, 2, 2, 2, 12, 12, 2, 2, 12, 12, 12, 2, 2,
- 2, 12, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 2, 7, 2,
- 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 12, 12, 7, 7, 7, 12, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 12, 12, 10, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7,
- 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 2, 7, 7, 2, 7, 7, 7, 7, 7, 2, 2, 12, 7, 10, 10,
- 10, 12, 12, 12, 12, 12, 2, 12, 12, 10, 2, 10, 10, 12, 2, 2,
- 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 21, 23, 2, 2, 2, 2, 2, 2, 2, 7, 12, 12, 12, 12, 12, 12,
- 2, 12, 10, 10, 2, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 7,
- 7, 2, 7, 7, 2, 7, 7, 7, 7, 7, 2, 2, 12, 7, 10, 12,
- 10, 12, 12, 12, 12, 2, 2, 10, 10, 2, 2, 10, 10, 12, 2, 2,
- 2, 2, 2, 2, 2, 12, 12, 10, 2, 2, 2, 2, 7, 7, 2, 7,
- 26, 7, 15, 15, 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 12, 7, 2, 7, 7, 7, 7, 7, 7, 2, 2, 2, 7, 7,
- 7, 2, 7, 7, 7, 7, 2, 2, 2, 7, 7, 2, 7, 2, 7, 7,
- 2, 2, 2, 7, 7, 2, 2, 2, 7, 7, 7, 2, 2, 2, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 10, 10,
- 12, 10, 10, 2, 2, 2, 10, 10, 10, 2, 10, 10, 10, 12, 2, 2,
- 7, 2, 2, 2, 2, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2,
- 15, 15, 15, 26, 26, 26, 26, 26, 26, 23, 26, 2, 2, 2, 2, 2,
- 12, 10, 10, 10, 12, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7,
- 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 12, 7, 12, 12,
- 12, 10, 10, 10, 10, 2, 12, 12, 12, 2, 12, 12, 12, 12, 2, 2,
- 2, 2, 2, 2, 2, 12, 12, 2, 7, 7, 7, 2, 2, 7, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 21, 15, 15, 15, 15, 15, 15, 15, 26,
- 7, 12, 10, 10, 21, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7,
- 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 2, 2, 12, 7, 10, 12,
- 10, 10, 10, 10, 10, 2, 12, 10, 10, 2, 10, 10, 12, 12, 2, 2,
- 2, 2, 2, 2, 2, 10, 10, 2, 2, 2, 2, 2, 2, 7, 7, 2,
- 2, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 12, 12, 10, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 7, 10, 10,
- 10, 12, 12, 12, 12, 2, 10, 10, 10, 2, 10, 10, 10, 12, 7, 26,
- 2, 2, 2, 2, 7, 7, 7, 10, 15, 15, 15, 15, 15, 15, 15, 7,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 7, 7, 7, 7, 7, 7,
- 2, 12, 10, 10, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 7, 7, 7, 7, 7, 7,
- 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 12, 2, 2, 2, 2, 10,
- 10, 10, 12, 12, 12, 2, 12, 2, 10, 10, 10, 10, 10, 10, 10, 10,
- 2, 2, 10, 10, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 12, 7, 7, 12, 12, 12, 12, 12, 12, 12, 2, 2, 2, 2, 23,
- 7, 7, 7, 7, 7, 7, 6, 12, 12, 12, 12, 12, 12, 12, 12, 21,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 7, 7, 2, 7, 2, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7,
- 7, 7, 7, 7, 2, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 12, 7, 7, 12, 12, 12, 12, 12, 12, 12, 12, 12, 7, 2, 2,
- 7, 7, 7, 7, 7, 2, 6, 2, 12, 12, 12, 12, 12, 12, 2, 2,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 7, 7, 7, 7,
- 7, 26, 26, 26, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 26, 21, 26, 26, 26, 12, 12, 26, 26, 26, 26, 26, 26,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 26, 12, 26, 12, 26, 12, 22, 18, 22, 18, 10, 10,
- 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2,
- 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10,
- 12, 12, 12, 12, 12, 21, 12, 12, 7, 7, 7, 7, 7, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 2, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 26, 26,
- 26, 26, 26, 26, 26, 26, 12, 26, 26, 26, 26, 26, 26, 2, 26, 26,
- 21, 21, 21, 21, 21, 26, 26, 26, 26, 21, 21, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 10, 10, 12, 12, 12,
- 12, 10, 12, 12, 12, 12, 12, 12, 10, 12, 12, 10, 10, 12, 12, 7,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21, 21, 21,
- 7, 7, 7, 7, 7, 7, 10, 10, 12, 12, 7, 7, 7, 7, 12, 12,
- 12, 7, 10, 10, 10, 7, 7, 10, 10, 10, 10, 10, 10, 10, 7, 7,
- 7, 12, 12, 12, 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 12, 10, 10, 12, 12, 10, 10, 10, 10, 10, 10, 12, 7, 10,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 10, 10, 10, 12, 26, 26,
- 9, 9, 9, 9, 9, 9, 2, 9, 2, 2, 2, 2, 2, 9, 2, 2,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 21, 6, 5, 5, 5,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 2, 7, 2, 7, 7, 7, 7, 2, 2,
- 7, 2, 7, 7, 7, 7, 2, 2, 7, 7, 7, 7, 7, 7, 7, 2,
- 7, 2, 7, 7, 7, 7, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 12, 12, 12,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 2,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 2,
- 9, 9, 9, 9, 9, 9, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2,
- 17, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 26, 21, 7,
- 29, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 22, 18, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 21, 21, 21, 14, 14,
- 14, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 12, 12, 12, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7,
- 7, 7, 12, 12, 10, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7,
- 7, 2, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 12, 12, 10, 12, 12, 12, 12, 12, 12, 12, 10, 10,
- 10, 10, 10, 10, 10, 10, 12, 10, 10, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 21, 21, 21, 6, 21, 21, 21, 23, 7, 12, 2, 2,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 2, 2,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 2, 2, 2, 2,
- 21, 21, 21, 21, 21, 21, 17, 21, 21, 21, 21, 12, 12, 12, 1, 12,
- 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 12, 12, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 7, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2,
- 12, 12, 12, 10, 10, 10, 10, 12, 12, 10, 10, 10, 2, 2, 2, 2,
- 10, 10, 12, 10, 10, 10, 10, 10, 10, 12, 12, 12, 2, 2, 2, 2,
- 26, 2, 2, 2, 21, 21, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2,
- 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 2, 2, 2, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 7, 7, 7, 7, 7, 7, 7, 12, 12, 10, 10, 12, 2, 2, 21, 21,
- 7, 7, 7, 7, 7, 10, 12, 10, 12, 12, 12, 12, 12, 12, 12, 2,
- 12, 10, 12, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 10,
- 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 2, 12,
- 21, 21, 21, 21, 21, 21, 21, 6, 21, 21, 21, 21, 21, 21, 2, 2,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2,
- 12, 12, 12, 12, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 12, 10, 12, 12, 12, 12, 12, 10, 12, 10, 10, 10,
- 10, 10, 12, 10, 10, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2,
- 21, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 26, 26, 26, 26, 26, 26, 26, 26, 26, 21, 21, 2,
- 12, 12, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 10, 12, 12, 12, 12, 10, 10, 12, 12, 10, 12, 12, 12, 7, 7,
- 7, 7, 7, 7, 7, 7, 12, 10, 12, 12, 10, 10, 10, 12, 10, 12,
- 12, 12, 10, 10, 2, 2, 2, 2, 2, 2, 2, 2, 21, 21, 21, 21,
- 7, 7, 7, 7, 10, 10, 10, 10, 10, 10, 10, 10, 12, 12, 12, 12,
- 12, 12, 12, 12, 10, 10, 12, 12, 2, 2, 2, 21, 21, 21, 21, 21,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 21, 21,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 2, 9, 9, 9,
- 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2,
- 12, 12, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 10, 12, 12, 12, 12, 12, 12, 12, 7, 7, 7, 7, 12, 7, 7,
- 7, 7, 7, 7, 12, 7, 7, 10, 12, 12, 7, 2, 2, 2, 2, 2,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6,
- 9, 5, 9, 5, 9, 5, 5, 5, 5, 5, 5, 5, 5, 5, 9, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 9, 9, 9, 9, 9, 9, 9, 9,
- 5, 5, 5, 5, 5, 5, 2, 2, 9, 9, 9, 9, 9, 9, 2, 2,
- 5, 5, 5, 5, 5, 5, 5, 5, 2, 9, 2, 9, 2, 9, 2, 9,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2,
- 5, 5, 5, 5, 5, 5, 5, 5, 8, 8, 8, 8, 8, 8, 8, 8,
- 5, 5, 5, 5, 5, 2, 5, 5, 9, 9, 9, 9, 8, 24, 5, 24,
- 24, 24, 5, 5, 5, 2, 5, 5, 9, 9, 9, 9, 8, 24, 24, 24,
- 5, 5, 5, 5, 2, 2, 5, 5, 9, 9, 9, 9, 2, 24, 24, 24,
- 5, 5, 5, 5, 5, 5, 5, 5, 9, 9, 9, 9, 9, 24, 24, 24,
- 2, 2, 5, 5, 5, 2, 5, 5, 9, 9, 9, 9, 8, 24, 24, 2,
- 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 1, 1, 1, 1, 1,
- 17, 17, 17, 17, 17, 17, 21, 21, 20, 19, 22, 20, 20, 19, 22, 20,
- 21, 21, 21, 21, 21, 21, 21, 21, 27, 28, 1, 1, 1, 1, 1, 29,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 20, 19, 21, 21, 21, 21, 16,
- 16, 21, 21, 21, 25, 22, 18, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 25, 21, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 29,
- 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 15, 6, 2, 2, 15, 15, 15, 15, 15, 15, 25, 25, 25, 22, 18, 6,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 25, 25, 25, 22, 18, 2,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 2,
- 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
- 23, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11,
- 11, 12, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 26, 26, 9, 26, 26, 26, 26, 9, 26, 26, 5, 9, 9, 9, 5, 5,
- 9, 9, 9, 5, 26, 9, 26, 26, 25, 9, 9, 9, 9, 9, 26, 26,
- 26, 26, 26, 26, 9, 26, 9, 26, 9, 26, 9, 9, 9, 9, 26, 5,
- 9, 9, 9, 9, 5, 7, 7, 7, 7, 5, 26, 26, 5, 5, 9, 9,
- 25, 25, 25, 25, 25, 9, 5, 5, 5, 5, 26, 25, 26, 26, 5, 26,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 14, 9, 5, 14, 14, 14, 14, 15, 26, 26, 2, 2, 2, 2,
- 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 25, 25, 26, 26, 26, 26,
- 25, 26, 26, 25, 26, 26, 25, 26, 26, 26, 26, 26, 26, 26, 25, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 25,
- 26, 26, 25, 26, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 26, 26, 26, 26, 26, 26, 26, 26, 22, 18, 22, 18, 26, 26, 26, 26,
- 25, 25, 26, 26, 26, 26, 26, 26, 26, 22, 18, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 25, 25, 25,
- 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 15, 15, 15, 15, 15, 15,
- 26, 26, 26, 26, 26, 26, 26, 25, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 25, 25, 25, 25, 25, 25, 25, 25,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25,
- 26, 26, 26, 26, 26, 26, 26, 26, 22, 18, 22, 18, 22, 18, 22, 18,
- 22, 18, 22, 18, 22, 18, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 25, 25, 25, 25, 25, 22, 18, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18,
- 25, 25, 25, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 22,
- 18, 22, 18, 22, 18, 22, 18, 22, 18, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 22, 18, 22, 18, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 22, 18, 25, 25,
- 25, 25, 25, 25, 25, 26, 26, 25, 25, 25, 25, 25, 25, 26, 26, 26,
- 26, 26, 26, 26, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 9, 5, 9, 9, 9, 5, 5, 9, 5, 9, 5, 9, 5, 9, 9, 9,
- 9, 5, 9, 5, 5, 9, 5, 5, 5, 5, 5, 5, 6, 6, 9, 9,
- 9, 5, 9, 5, 5, 26, 26, 26, 26, 26, 26, 9, 5, 9, 5, 12,
- 12, 12, 9, 5, 2, 2, 2, 2, 2, 21, 21, 21, 21, 15, 21, 21,
- 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2, 2, 2, 5, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 6,
- 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12,
- 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 2,
- 21, 21, 20, 19, 20, 19, 21, 21, 21, 20, 19, 21, 20, 19, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 17, 21, 21, 17, 21, 20, 19, 21, 21,
- 20, 19, 22, 18, 22, 18, 22, 18, 22, 18, 21, 21, 21, 21, 21, 6,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 17, 17, 21, 21, 21, 21,
- 17, 21, 22, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 26, 26, 21, 21, 21, 22, 18, 22, 18, 22, 18, 22, 18, 17, 2, 2,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2,
- 29, 21, 21, 21, 26, 6, 7, 14, 22, 18, 22, 18, 22, 18, 22, 18,
- 22, 18, 26, 26, 22, 18, 22, 18, 22, 18, 22, 18, 17, 22, 18, 18,
- 26, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 12, 10, 10,
- 17, 6, 6, 6, 6, 6, 26, 26, 14, 14, 14, 6, 7, 21, 26, 26,
- 7, 7, 7, 7, 7, 7, 7, 2, 2, 12, 12, 24, 24, 6, 6, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 21, 6, 6, 6, 7,
- 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 26, 26, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 15, 15, 15, 15, 15, 15, 15, 15,
- 26, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 21, 21, 21,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 7, 7, 2, 2, 2, 2,
- 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 7, 12,
- 11, 11, 11, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 6,
- 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 6, 6, 12, 12,
- 7, 7, 7, 7, 7, 7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 12, 12, 21, 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2,
- 24, 24, 24, 24, 24, 24, 24, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 24, 24, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5,
- 5, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5,
- 6, 5, 5, 5, 5, 5, 5, 5, 5, 9, 5, 9, 5, 9, 9, 5,
- 9, 5, 9, 5, 9, 5, 9, 5, 6, 24, 24, 9, 5, 9, 5, 7,
- 9, 5, 9, 5, 5, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5,
- 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 9, 9, 9, 9, 5,
- 9, 9, 9, 9, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5,
- 9, 5, 9, 5, 9, 9, 9, 9, 5, 9, 5, 2, 2, 2, 2, 2,
- 9, 5, 2, 5, 2, 5, 9, 5, 9, 5, 2, 2, 2, 2, 2, 2,
- 2, 2, 6, 6, 6, 9, 5, 7, 6, 6, 5, 7, 7, 7, 7, 7,
- 7, 7, 12, 7, 7, 7, 12, 7, 7, 7, 7, 12, 7, 7, 7, 7,
- 7, 7, 7, 10, 10, 12, 12, 10, 26, 26, 26, 26, 12, 2, 2, 2,
- 15, 15, 15, 15, 15, 15, 26, 26, 23, 26, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2,
- 10, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 21, 21,
- 12, 12, 7, 7, 7, 7, 7, 7, 21, 21, 21, 7, 21, 7, 7, 12,
- 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21,
- 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 10, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 21,
- 7, 7, 7, 12, 10, 10, 12, 12, 12, 12, 10, 10, 12, 12, 10, 10,
- 10, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, 6,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 21, 21,
- 7, 7, 7, 7, 7, 12, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 7, 7, 7, 7, 7, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 10,
- 10, 12, 12, 10, 10, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 12, 7, 7, 7, 7, 7, 7, 7, 7, 12, 10, 2, 2,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 21, 21, 21, 21,
- 6, 7, 7, 7, 7, 7, 7, 26, 26, 26, 7, 10, 12, 10, 7, 7,
- 12, 7, 12, 12, 12, 7, 7, 12, 12, 7, 7, 7, 7, 7, 12, 12,
- 7, 12, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 6, 21, 21,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 10, 12, 12, 10, 10,
- 21, 21, 7, 6, 6, 10, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 7, 7, 7, 7, 7, 7, 2, 2, 7, 7, 7, 7, 7, 7, 2,
- 2, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 24, 6, 6, 6, 6,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 24, 24, 2, 2, 2, 2,
- 7, 7, 7, 10, 10, 12, 10, 10, 12, 10, 10, 21, 10, 12, 2, 2,
- 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 7, 7, 7, 7, 7,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 7, 12, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 25, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 2, 7, 2,
- 7, 7, 2, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 24, 24, 24, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 18, 22,
- 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 26,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 23, 26, 26, 26,
- 21, 21, 21, 21, 21, 21, 21, 22, 18, 21, 2, 2, 2, 2, 2, 2,
- 21, 17, 17, 16, 16, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 22,
- 18, 22, 18, 22, 18, 21, 21, 22, 18, 21, 21, 21, 21, 16, 16, 16,
- 21, 21, 21, 2, 21, 21, 21, 21, 17, 22, 18, 22, 18, 22, 18, 21,
- 21, 21, 25, 17, 25, 25, 25, 2, 21, 23, 21, 21, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 1,
- 2, 21, 21, 21, 23, 21, 21, 21, 22, 18, 21, 25, 21, 17, 21, 21,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 22, 25, 18, 25, 22,
- 18, 21, 22, 18, 21, 21, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6,
- 2, 2, 7, 7, 7, 7, 7, 7, 2, 2, 7, 7, 7, 7, 7, 7,
- 2, 2, 7, 7, 7, 7, 7, 7, 2, 2, 7, 7, 7, 2, 2, 2,
- 23, 23, 25, 24, 26, 23, 23, 2, 26, 25, 25, 25, 25, 26, 26, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 26, 26, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 2, 7,
- 21, 21, 21, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 14, 14, 14, 14, 14, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 15, 15, 26, 26, 26, 2,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2,
- 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 12, 2, 2,
- 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 2, 2,
- 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7,
- 7, 14, 7, 7, 7, 7, 7, 7, 7, 7, 14, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 21,
- 7, 7, 7, 7, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7,
- 21, 14, 14, 14, 14, 14, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 9, 9, 9, 9, 9, 9, 9, 9, 5, 5, 5, 5, 5, 5, 5, 5,
- 9, 9, 9, 9, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 21,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9,
- 9, 9, 9, 2, 9, 9, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 2, 5, 5, 2, 2, 2,
- 6, 6, 6, 6, 6, 6, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 2, 2, 7, 2, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 2, 7, 7, 2, 2, 2, 7, 2, 2, 7,
- 7, 7, 7, 7, 7, 7, 2, 21, 15, 15, 15, 15, 15, 15, 15, 15,
- 7, 7, 7, 7, 7, 7, 7, 26, 26, 15, 15, 15, 15, 15, 15, 15,
- 2, 2, 2, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 7, 7, 7, 2, 7, 7, 2, 2, 2, 2, 2, 15, 15, 15, 15, 15,
- 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 2, 2, 2, 21,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 21,
- 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 15, 15, 7, 7,
- 2, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 7, 12, 12, 12, 2, 12, 12, 2, 2, 2, 2, 2, 12, 12, 12, 12,
- 7, 7, 7, 7, 2, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 2, 2, 12, 12, 12, 2, 2, 2, 2, 12,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 15, 15, 21,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 15, 15, 15,
- 7, 7, 7, 7, 7, 7, 7, 7, 26, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 12, 12, 2, 2, 2, 2, 15, 15, 15, 15, 15,
- 21, 21, 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 2, 2, 2, 21, 21, 21, 21, 21, 21, 21,
- 7, 7, 7, 7, 7, 7, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15,
- 7, 7, 7, 2, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15,
- 7, 7, 2, 2, 2, 2, 2, 2, 2, 21, 21, 21, 21, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, 15,
- 9, 9, 9, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15,
- 7, 7, 7, 7, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 12, 12, 17, 2, 2,
- 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 15, 15, 15, 15, 15, 15, 15, 7, 2, 2, 2, 2, 2, 2, 2, 2,
- 12, 15, 15, 15, 15, 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2,
- 7, 7, 12, 12, 12, 12, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 2, 2, 2, 2,
- 10, 12, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 2, 2,
- 15, 15, 15, 15, 15, 15, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 12, 7, 7, 12, 12, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12,
- 10, 10, 10, 12, 12, 12, 12, 10, 10, 12, 12, 21, 21, 1, 21, 21,
- 21, 21, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2,
- 12, 12, 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 10, 12, 12, 12,
- 12, 12, 12, 12, 12, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 21, 21, 21, 21, 7, 10, 10, 7, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 12, 21, 21, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10,
- 10, 7, 7, 7, 7, 21, 21, 21, 21, 12, 12, 12, 12, 21, 10, 12,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 7, 21, 7, 21, 21, 21,
- 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 12,
- 12, 12, 10, 10, 12, 10, 12, 12, 21, 21, 21, 21, 21, 21, 12, 2,
- 7, 7, 7, 7, 7, 7, 7, 2, 7, 2, 7, 7, 7, 7, 2, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 21, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12,
- 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 2, 2, 2, 2, 2,
- 12, 12, 10, 10, 2, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 7,
- 7, 2, 7, 7, 2, 7, 7, 7, 7, 7, 2, 12, 12, 7, 10, 10,
- 12, 10, 10, 10, 10, 2, 2, 10, 10, 2, 2, 10, 10, 10, 2, 2,
- 7, 2, 2, 2, 2, 2, 2, 10, 2, 2, 2, 2, 2, 7, 7, 7,
- 7, 7, 10, 10, 2, 2, 12, 12, 12, 12, 12, 12, 12, 2, 2, 2,
- 12, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12,
- 10, 10, 12, 12, 12, 10, 12, 7, 7, 7, 7, 21, 21, 21, 21, 21,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 2, 21, 12, 7,
- 10, 10, 10, 12, 12, 12, 12, 12, 12, 10, 12, 10, 10, 10, 10, 12,
- 12, 10, 12, 12, 7, 7, 21, 7, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 10,
- 10, 10, 12, 12, 12, 12, 2, 2, 10, 10, 10, 10, 12, 12, 10, 12,
- 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 21, 7, 7, 7, 7, 12, 12, 2, 2,
- 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 12, 10, 12,
- 12, 21, 21, 21, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 10, 12, 10, 10,
- 12, 12, 12, 12, 12, 12, 10, 12, 7, 21, 2, 2, 2, 2, 2, 2,
- 10, 10, 12, 12, 12, 12, 10, 12, 12, 12, 12, 12, 2, 2, 2, 2,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 21, 21, 21, 26,
- 12, 12, 12, 12, 12, 12, 12, 12, 10, 12, 12, 21, 2, 2, 2, 2,
- 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7,
- 7, 7, 7, 7, 7, 7, 7, 2, 2, 7, 2, 2, 7, 7, 7, 7,
- 7, 7, 7, 7, 2, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7,
- 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 2, 12, 12, 10, 12, 7,
- 10, 7, 10, 12, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 7, 7, 7, 7, 7, 7,
- 7, 10, 10, 10, 12, 12, 12, 12, 2, 2, 12, 12, 10, 10, 10, 10,
- 12, 7, 21, 7, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 7, 7, 7, 7, 7,
- 7, 7, 7, 12, 12, 12, 12, 12, 12, 10, 7, 12, 12, 12, 12, 21,
- 21, 21, 21, 21, 21, 21, 21, 12, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 12, 12, 12, 12, 12, 12, 10, 10, 12, 12, 12, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 10, 12, 12, 21, 21, 21, 7, 21, 21,
- 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 12, 12, 12, 12, 12, 12, 12, 2, 12, 12, 12, 12, 12, 12, 10, 12,
- 7, 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 21, 21, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 2, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 2, 10, 12, 12, 12, 12, 12, 12,
- 12, 10, 12, 12, 10, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 2, 7, 7, 7, 7, 7,
- 7, 12, 12, 12, 12, 12, 12, 2, 2, 2, 12, 2, 12, 12, 2, 12,
- 12, 12, 12, 12, 12, 12, 7, 12, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 2, 7, 7, 2, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10, 2,
- 12, 12, 2, 10, 10, 12, 10, 12, 7, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 12, 12, 10, 10, 21, 21, 2, 2, 2, 2, 2, 2, 2,
- 15, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26, 26, 23, 23, 23,
- 23, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 21,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2,
- 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
- 12, 12, 12, 12, 12, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 26, 26, 26, 26,
- 6, 6, 6, 6, 21, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 15, 15, 15, 15, 15,
- 15, 15, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 7, 7, 7,
- 15, 15, 15, 15, 15, 15, 15, 21, 21, 21, 21, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 12,
- 7, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 12,
- 12, 12, 12, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 21, 6, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 10, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 6, 6, 6, 6, 2, 6, 6, 6, 6, 6, 6, 6, 2, 6, 6, 2,
- 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 26, 12, 12, 21,
- 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 2,
- 12, 12, 12, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 26, 26, 26, 26, 26, 26, 26, 2, 2, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 10, 10, 12, 12, 12, 26, 26, 26, 10, 10, 10,
- 10, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 12, 12, 12, 12, 12,
- 12, 12, 12, 26, 26, 12, 12, 12, 12, 12, 12, 12, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 12, 12, 12, 12, 26, 26,
- 26, 26, 12, 12, 12, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 5, 5,
- 5, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 9, 9, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 9, 2, 9, 9,
- 2, 2, 9, 2, 2, 9, 9, 2, 2, 9, 9, 9, 9, 2, 9, 9,
- 9, 9, 9, 9, 9, 9, 5, 5, 5, 5, 2, 5, 2, 5, 5, 5,
- 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 9, 9, 2, 9, 9, 9, 9, 2, 2, 9, 9, 9,
- 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, 2, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 9, 9, 2, 9, 9, 9, 9, 2,
- 9, 9, 9, 9, 9, 2, 9, 2, 2, 2, 9, 9, 9, 9, 9, 9,
- 9, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 2, 2, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 25, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 25, 5, 5, 5, 5,
- 5, 5, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 25, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 25, 5, 5, 5, 5, 5, 5, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 25, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 25,
- 5, 5, 5, 5, 5, 5, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 25,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 25, 5, 5, 5, 5, 5, 5,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 25, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 25, 5, 5, 5, 5, 5, 5, 9, 5, 2, 2, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 12, 12, 12, 12, 12, 12, 12, 26, 26, 26, 26, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 26, 26, 26,
- 26, 26, 26, 26, 26, 12, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 12, 26, 26, 21, 21, 21, 21, 21, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 12,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 7, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2,
- 12, 12, 12, 12, 12, 12, 12, 2, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 2, 12, 12, 12, 12, 12,
- 12, 12, 2, 12, 12, 2, 12, 12, 12, 12, 12, 2, 2, 2, 2, 2,
- 12, 12, 12, 12, 12, 12, 12, 6, 6, 6, 6, 6, 6, 6, 2, 2,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 7, 26,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 2, 23,
- 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 2, 7, 7, 2,
- 7, 7, 7, 7, 7, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 5, 5, 5, 5, 12, 12, 12, 12, 12, 12, 12, 6, 2, 2, 2, 2,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 15, 15, 15,
- 23, 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2,
- 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 2, 7, 7, 2, 7, 2, 2, 7, 2, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 2, 7, 7, 7, 7, 2, 7, 2, 7, 2, 2, 2, 2,
- 2, 2, 7, 2, 2, 2, 2, 7, 2, 7, 2, 7, 2, 7, 7, 7,
- 2, 7, 7, 2, 7, 2, 2, 7, 2, 7, 2, 7, 2, 7, 2, 7,
- 2, 7, 7, 2, 7, 2, 2, 7, 7, 7, 7, 2, 7, 7, 7, 7,
- 7, 7, 7, 2, 7, 7, 7, 7, 2, 7, 7, 7, 7, 2, 7, 2,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7,
- 2, 7, 7, 7, 2, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7,
- 25, 25, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2,
- 2, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 2, 2,
- 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 24, 24, 24, 24, 24,
- 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 2, 2, 2,
- 26, 26, 26, 26, 26, 2, 2, 2, 26, 26, 26, 26, 26, 2, 2, 2,
- 26, 26, 26, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 12, 12, 13, 14, 12, 15, 16, 17, 18, 19, 20,
- 21, 22, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 24, 25,
- 0, 26, 27, 0, 28, 29, 30, 31, 32, 33, 0, 34, 0, 0, 0, 0,
- 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 38, 0, 0, 0, 0,
- 39, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0,
- 43, 44, 45, 46, 0, 47, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 50, 0, 0, 0,
- 0, 0, 0, 51, 0, 52, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 54, 55, 0, 0, 0, 0, 56, 0, 0, 57, 58, 59,
- 60, 61, 62, 63, 64, 65, 66, 0, 67, 68, 0, 69, 70, 71, 72, 0,
- 61, 0, 73, 74, 75, 76, 0, 0, 70, 0, 77, 78, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 79, 80, 0, 0, 0, 0, 0, 0, 0, 0, 81,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 83, 84, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 86, 0, 80, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 88, 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
- 12, 1, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 14, 15, 16, 17, 18, 19, 20, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 21, 0, 0, 0, 0, 0, 22, 23, 24,
- 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 27,
- 28, 29, 0, 0, 0, 0, 30, 0, 0, 0, 31, 32, 33, 34, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 13, 35, 36, 0, 0, 26, 37, 38, 39, 0, 0, 0, 0, 0, 40,
- 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 42, 43, 1,
- 44, 45, 46, 47, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 50, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0,
- 0, 0, 0, 51, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 49, 52, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 0, 49, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 56, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 58, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 59, 0, 0, 60, 61, 0, 0, 0, 0,
- 0, 0, 62, 63, 64, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 67, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68,
- 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 70, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 71,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 74, 75, 0, 0, 0, 0, 0, 0, 0, 0,
- 76, 0, 68, 77, 0, 0, 0, 0, 0, 0, 78, 79, 80, 81, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 70, 0, 0, 0,
- 0, 82, 83, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0,
- 85, 0, 84, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 86, 87,
- 88, 89, 90, 91, 0, 0, 0, 0, 0, 0, 0, 0, 92, 93, 94, 1,
- 1, 1, 95, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 98,
- 99,100,101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 74, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 0, 0, 0, 0, 0,103, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 74,105,106, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 91, 0,107, 0, 0, 0, 0, 70, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 0, 0, 0,
- 1, 1, 91, 0, 0, 0, 0, 0, 0,108, 0, 0, 0, 0,109, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,110, 0, 76, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,111,112,113, 0, 0, 0,
- 0, 0,107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 49, 0, 0, 0, 0, 0,114, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,115,116, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 26,117, 0,118, 0, 0, 0, 0, 0,119, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 120, 0, 0, 0, 0, 0, 0, 0,105, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,121, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,122,123, 75, 0,
- 0, 0, 0, 0,124, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0, 0, 0,
- 0, 0, 76,102, 0, 0, 0, 0, 0, 0, 0,125, 0, 0, 0, 0,
- 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 53, 0, 0, 0, 0, 0,
- 0, 0,110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76,126, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,127, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0,129, 0, 49, 0, 0,
- 26,130,130, 0, 0, 0, 0, 0, 0, 0, 0, 0,131, 0, 0, 51,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,132, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,102,133, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,102, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,134, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,109, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,135,110, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 0,102, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,136, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,137, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,102, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,138, 0, 0, 0, 0, 0, 0, 0,139, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,140, 0, 0, 0, 0,141, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 142,143,144,145,146,147, 0, 0, 0,148, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,149, 0, 0, 0,
- 0, 0, 0, 0,139, 1, 1,150,151,117, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, 0,
- 0,105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,152, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105,153, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230,230,230,
- 230,230,230,230,230,230,230,230,230,232,220,220,220,220,232,216,
- 220,220,220,220,220,202,202,220,220,220,220,202,202,220,220,220,
- 220,220,220,220,220,220,220,220, 1, 1, 1, 1, 1,220,220,220,
- 220,230,230,230,230,230,230,230,230,240,230,220,220,220,230,230,
- 230,220,220, 0,230,230,230,220,220,220,220,230,232,220,220,230,
- 233,234,234,233,234,234,233,230,230,230,230,230, 0, 0, 0,230,
- 230,230,230,230, 0,220,230,230,230,230,220,230,230,230,222,220,
- 230,230,230,230,230,230,220,220,220,220,220,220,230,230,220,230,
- 230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20,
- 21, 22, 0, 23, 0, 24, 25, 0,230,220, 0, 18, 30, 31, 32, 0,
- 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34,230,
- 230,220,220,230,230,230,230,230,220,230,230,220, 35, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230,230,230,230,230,
- 230, 0, 0,230,230,230,230,220,230, 0, 0,230,230, 0,220,230,
- 230,220, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0,230,220,230,230,
- 220,230,230,220,220,220,230,220,220,230,220,230,230,230,220,230,
- 220,230,220,230,220,230,230, 0, 0, 0, 0, 0,230,230,220,230,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,220, 0, 0,230,230, 0,230,
- 230,230,230,230,230,230,230,230, 0,230,230,230, 0,230,230,230,
- 230,230, 0, 0, 0,220,220,220, 0, 0, 0, 0,230,220,220,220,
- 230,230,230,230, 0, 0,230,230,230,230,230,220,220,220,220,220,
- 230,230,230,230,230,230, 0,220,230,230,220,230,230,220,230,230,
- 230,220,220,220, 27, 28, 29,230,230,230,220,230,230,220,220,230,
- 230,230,230,230, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0,
- 0, 9, 0, 0, 0,230,220,230,230, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,230, 0, 0, 0, 0, 0, 0, 84, 91, 0, 0, 0, 0, 9,
- 9, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0,103,103, 9, 0,
- 0, 0, 0, 0,107,107,107,107, 0, 0, 0, 0,118,118, 9, 0,
- 0, 0, 0, 0,122,122,122,122, 0, 0, 0, 0,220,220, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,220, 0,220, 0,216, 0, 0,
- 0, 0, 0, 0, 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130,
- 130,130, 0, 0,130, 0,230,230, 9, 0,230,230, 0, 0, 0, 0,
- 0, 0,220, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 9, 9, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230,230, 0, 0, 0, 0,
- 9, 9, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0,
- 0,230, 0, 0, 0,228, 0, 0, 0, 0, 0, 0, 0,222,230,220,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,230,220, 0, 0, 0,
- 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0,230,230,230,230,
- 230, 0, 0,220,230,230,230,230,230,220,220,220,220,220,220,230,
- 230,220, 0,220,220,230,230,220,220,230,230,230,230,230,220,230,
- 230,230,230, 0, 0, 0, 0,230,220,230,230,230,230,230,230,230,
- 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 7, 0,230,230,230, 0, 1,220,220,220,220,220,230,230,
- 220,220,220,220,230, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
- 0,220, 0, 0, 0, 0, 0, 0,230, 0, 0, 0,230,230, 0, 0,
- 0, 0, 0, 0,230,230,220,230,230,230,230,230,230,230,220,230,
- 230,234,214,220,202,230,230,230,230,230,230,230,230,230,230,230,
- 230,230,232,228,228,220,218,230,233,220,230,220,230,230, 1, 1,
- 230,230,230,230, 1, 1, 1,230,230, 0, 0, 0, 0,230, 0, 0,
- 0, 1, 1,230,220,230, 1, 1,220,220,220,220,230, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0,218,228,
- 232,222,224,224, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 230,230,230,230,230,230,230,230,230,230, 0, 0, 0, 0, 0, 0,
- 0, 0, 9, 0, 0, 0, 0,220,220,220, 0, 0, 0, 0, 0, 9,
- 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0,230, 0,230,230,
- 220, 0, 0,230,230, 0, 0, 0, 0, 0,230,230, 0,230, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0,230,230,230,230,
- 230,230,230,220,220,220,220,220,220,220,230,230,230,230,230, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,220, 0,230,230, 1,220, 0,
- 0, 0, 0, 9, 0, 0, 0, 0, 0,230,220, 0, 0, 0, 0,230,
- 230, 0, 0, 0, 0, 0, 0, 0, 0, 0,220,220,230,230,230,220,
- 230,220,220,220, 0, 0,230,220,230,220, 0, 0, 0, 9, 7, 0,
- 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 9, 7, 0, 0, 7, 9, 0, 0, 0, 0, 0, 0, 0, 0, 7,
- 7, 0, 0, 0,230,230,230,230,230, 0, 0, 0, 0, 0, 9, 0,
- 0, 0, 7, 0, 0, 0, 9, 7, 0, 0, 0, 0, 7, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 7, 0, 0, 0, 0,
- 0, 9, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0,
- 9, 9, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,230,230,230,230,
- 230,230,230, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 0, 0, 0, 0, 0, 0,216,216, 1, 1, 1, 0, 0,
- 0,226,216,216,216,216,216, 0, 0, 0, 0, 0, 0, 0, 0,220,
- 220,220,220,220,220,220,220, 0, 0,230,230,230,230,230,220,220,
- 0, 0, 0, 0, 0, 0,230,230,230,230, 0, 0, 0, 0,230,230,
- 230, 0, 0, 0,230, 0, 0,230,230,230,230,230,230,230, 0,230,
- 230, 0,230,230,220,220,220,220,220,220,220, 0,230,230, 7, 0,
- 0, 0, 0, 0, 16, 17, 17, 17, 17, 17, 17, 33, 17, 17, 17, 19,
- 17, 17, 17, 17, 20,101, 17,113,129,169, 17, 27, 28, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17,237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
- 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0,
- 0, 0, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0,
- 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 7, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 10, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 11, 12, 0, 13, 0, 14, 15, 16, 0, 0,
- 0, 0, 0, 1, 17, 18, 0, 19, 7, 1, 0, 0, 0, 20, 20, 7,
- 20, 20, 20, 20, 20, 20, 20, 8, 21, 0, 22, 0, 7, 23, 24, 0,
- 20, 20, 25, 0, 0, 0, 26, 27, 1, 7, 20, 20, 20, 20, 20, 1,
- 28, 29, 30, 31, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 10, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20,
- 20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 8, 21, 32, 4, 0, 10, 0, 33, 7, 20, 20, 20,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 8, 34, 34, 35, 36, 34, 37, 0, 38, 1, 20, 20,
- 0, 0, 39, 0, 1, 1, 0, 8, 21, 1, 20, 0, 0, 0, 1, 0,
- 0, 40, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 21,
- 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
- 0, 0, 26, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 7, 20, 41,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 0, 42, 43, 44, 0, 45,
- 0, 8, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 46, 7, 1, 10, 1, 0, 0, 0, 1, 20, 20, 1, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 34, 9, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 20, 20, 1, 20, 20, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 21, 0, 1, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0,
- 0, 0, 3, 4, 0, 0, 0, 0, 0, 0, 3, 47, 48, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
- 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0,
- 0, 0, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
- 12, 13, 14, 15, 16, 17, 18, 17, 19, 20, 21, 22, 23, 24, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 27, 27, 28, 29, 30, 31, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
- 51, 52, 53, 54, 55, 56, 57, 34, 34, 34, 34, 58, 59, 59, 60, 34,
- 34, 34, 34, 34, 34, 34, 61, 62, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 63, 64, 34, 65, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 67, 66, 68, 69, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 70, 71, 72, 34, 34,
- 34, 34, 73, 34, 34, 34, 34, 34, 34, 34, 34, 74, 75, 76, 77, 78,
- 79, 80, 34, 81, 82, 83, 34, 84, 85, 34, 86, 87, 88, 89, 17, 90,
- 91, 92, 34, 34, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 93, 25, 25, 25, 25, 25, 25, 25, 94,
- 95, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 96, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 97, 34, 34, 34, 34, 34, 34,
- 25, 98, 34, 34, 25, 25, 25, 25, 25, 25, 25, 25, 25, 99, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34,100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 19, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0,
- 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0,
- 26, 26, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, 9, 9, 2, 2,
- 9, 9, 9, 9, 0, 9, 2, 2, 2, 2, 9, 0, 9, 0, 9, 9,
- 9, 2, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 55, 55, 55, 55, 55, 55, 55, 55,
- 55, 55, 55, 55, 55, 55, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 2, 2, 4, 4, 4, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 2,
- 2, 2, 2, 2, 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
- 14, 2, 2, 2, 2, 14, 14, 14, 14, 14, 14, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3,
- 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 0, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 0, 3, 3, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 2, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 2, 2, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38,
- 38, 38, 38, 38, 38, 38, 38, 38, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 2, 2, 64, 64, 64, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
- 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
- 90, 90, 90, 90, 2, 2, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
- 90, 90, 90, 90, 90, 2, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
- 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
- 95, 95, 2, 2, 95, 2, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
- 37, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5,
- 5, 5, 5, 2, 2, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2,
- 5, 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2, 5, 5, 5, 5,
- 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 5, 5, 2,
- 2, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2,
- 2, 2, 5, 5, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 2, 2, 11, 11, 11, 2, 11, 11, 11, 11, 11,
- 11, 2, 2, 2, 2, 11, 11, 2, 2, 11, 11, 11, 11, 11, 11, 11,
- 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2,
- 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, 11, 11, 2, 11, 11,
- 2, 2, 11, 2, 11, 11, 11, 11, 11, 2, 2, 2, 2, 11, 11, 2,
- 2, 11, 11, 11, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11,
- 11, 11, 11, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11,
- 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2,
- 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 10, 10, 10, 10, 10,
- 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10,
- 2, 10, 10, 10, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10,
- 10, 10, 10, 10, 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 10,
- 10, 10, 10, 10, 10, 10, 2, 21, 21, 21, 2, 21, 21, 21, 21, 21,
- 21, 21, 21, 2, 2, 21, 21, 2, 2, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2,
- 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 2, 21, 21, 21, 21, 21,
- 2, 2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2,
- 2, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 21, 21, 21, 2, 2,
- 2, 2, 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 22, 22, 2, 22, 22, 22, 22, 22,
- 22, 2, 2, 2, 22, 22, 22, 2, 22, 22, 22, 22, 2, 2, 2, 22,
- 22, 2, 22, 2, 22, 22, 2, 2, 2, 22, 22, 2, 2, 2, 22, 22,
- 22, 2, 2, 2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
- 2, 2, 2, 2, 22, 22, 22, 22, 22, 2, 2, 2, 22, 22, 22, 2,
- 22, 22, 22, 22, 2, 2, 22, 2, 2, 2, 2, 2, 2, 22, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22,
- 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
- 22, 2, 2, 2, 2, 2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
- 23, 23, 23, 2, 23, 23, 23, 2, 23, 23, 23, 23, 23, 23, 23, 23,
- 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 2,
- 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
- 2, 2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 2, 23, 23, 23, 2,
- 23, 23, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 23, 2, 23, 23,
- 23, 2, 2, 23, 2, 2, 23, 23, 23, 23, 2, 2, 23, 23, 23, 23,
- 23, 23, 23, 23, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 23, 23,
- 23, 23, 23, 23, 23, 23, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 2, 16, 16, 16, 2, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2,
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 16,
- 2, 2, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 2,
- 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 16, 16, 2, 2, 2,
- 2, 2, 2, 16, 16, 2, 16, 16, 16, 16, 2, 2, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 2, 16, 16, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
- 20, 20, 20, 2, 20, 20, 20, 2, 20, 20, 20, 20, 20, 20, 20, 20,
- 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
- 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 2, 20, 20, 20, 2,
- 20, 20, 20, 20, 20, 20, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20,
- 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 2, 2, 20, 20, 20, 20,
- 20, 20, 20, 20, 20, 20, 2, 36, 36, 36, 2, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2,
- 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 2, 36, 2, 2, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2,
- 36, 2, 2, 2, 2, 36, 36, 36, 36, 36, 36, 2, 36, 2, 36, 36,
- 36, 36, 36, 36, 36, 36, 2, 2, 2, 2, 2, 2, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 2, 2, 36, 36, 36, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 24, 2, 2, 2, 2, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
- 24, 24, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 18, 18, 2, 18, 2, 18, 18, 18, 18,
- 18, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18,
- 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 2, 2, 18, 18, 18, 18, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 2, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 2, 2, 2, 2, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
- 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 0, 0, 0, 0, 25,
- 25, 2, 2, 2, 2, 2, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
- 33, 33, 33, 33, 33, 33, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 2, 8, 2, 2,
- 2, 2, 2, 8, 2, 2, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 0, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 2,
- 30, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 2, 30, 2,
- 30, 30, 30, 30, 2, 2, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30,
- 30, 30, 30, 30, 30, 2, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 2, 30, 30,
- 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 2, 2, 2, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
- 2, 2, 2, 2, 2, 2, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
- 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 2, 2, 29, 29,
- 29, 29, 29, 29, 2, 2, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
- 28, 28, 28, 28, 28, 28, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 34, 2, 2, 2, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
- 35, 0, 0, 0, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 2,
- 2, 2, 2, 2, 2, 2, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
- 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 45, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
- 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43,
- 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
- 46, 46, 46, 2, 46, 46, 46, 2, 46, 46, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 31, 31, 31, 31, 2, 2, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
- 2, 2, 2, 2, 2, 2, 32, 32, 0, 0, 32, 0, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2,
- 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 2, 2, 2, 2, 2, 28, 28, 28, 28, 28, 28, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 2, 2, 2, 2, 48, 2, 2, 2, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
- 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52,
- 52, 52, 52, 52, 2, 2, 52, 52, 52, 52, 52, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 58, 2, 2, 2, 2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 2, 2, 2, 2, 2, 2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
- 58, 2, 2, 2, 58, 58, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
- 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
- 54, 54, 2, 2, 54, 54, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
- 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
- 91, 91, 91, 91, 91, 2, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
- 91, 91, 91, 2, 2, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
- 2, 2, 2, 2, 2, 2, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
- 91, 91, 91, 91, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 2, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
- 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
- 62, 62, 62, 2, 2, 2, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
- 62, 62, 62, 62, 62, 2, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76,
- 76, 76, 76, 76, 76, 76, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
- 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 2, 2, 2, 2, 2, 2,
- 2, 2, 93, 93, 93, 93, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 2, 2,
- 2, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
- 2, 2, 2, 70, 70, 70, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
- 73, 73, 73, 73, 73, 73, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2,
- 2, 2, 2, 2, 2, 2, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 2, 2, 8, 8, 8, 76, 76, 76, 76, 76, 76, 76, 76, 2, 2,
- 2, 2, 2, 2, 2, 2, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0,
- 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1,
- 0, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9,
- 9, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, 9, 9, 9, 9,
- 9, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 6, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 9, 9, 9, 9, 9, 9, 9, 2, 2, 9, 9,
- 9, 9, 9, 9, 2, 2, 9, 9, 9, 9, 9, 9, 9, 9, 2, 9,
- 2, 9, 2, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 2, 2, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 2, 9, 9, 9, 9,
- 9, 9, 2, 9, 9, 9, 2, 2, 9, 9, 9, 2, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 19, 2, 2, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 2, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0,
- 19, 19, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 19, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0,
- 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 2, 2, 2, 2, 2, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
- 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
- 56, 56, 56, 56, 56, 56, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
- 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 2, 2, 2, 2, 2, 55,
- 55, 55, 55, 55, 55, 55, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
- 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 2, 2,
- 2, 2, 2, 2, 2, 61, 61, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 61, 30, 30, 30, 30, 30, 30, 30, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 30, 30, 30, 30, 30, 30, 30, 2, 30, 30,
- 30, 30, 30, 30, 30, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 13, 0, 13, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 1, 1, 1, 1, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13,
- 13, 13, 0, 0, 0, 0, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 1,
- 1, 0, 0, 15, 15, 15, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 0, 0, 17, 17, 17, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
- 26, 26, 26, 26, 26, 26, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 0, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0,
- 0, 0, 0, 0, 0, 0, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
- 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39,
- 39, 39, 39, 2, 2, 2, 39, 39, 39, 39, 39, 39, 39, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
- 86, 86, 86, 86, 86, 86, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
- 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
- 77, 77, 2, 2, 2, 2, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79,
- 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0,
- 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 2, 2, 2, 2, 2, 19, 19, 2, 19, 2, 19, 19, 19, 19, 19,
- 2, 2, 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
- 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
- 60, 60, 60, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 2, 2, 2, 2, 2, 2, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
- 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 2, 2,
- 2, 2, 2, 2, 2, 2, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
- 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 2, 2, 2, 2,
- 2, 2, 2, 2, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
- 2, 2, 2, 2, 2, 2, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
- 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
- 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 74, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 2, 2, 2, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
- 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
- 84, 84, 84, 84, 2, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
- 2, 2, 2, 2, 84, 84, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
- 33, 33, 33, 33, 33, 2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 68, 68, 68, 68, 2, 2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
- 2, 2, 68, 68, 68, 68, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
- 92, 92, 92, 92, 92, 92, 92, 92, 92, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 92, 92, 92, 92, 92, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 30, 30, 30, 30, 30, 30, 2, 2, 30,
- 30, 30, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 19, 19, 19, 19,
- 0, 0, 2, 2, 2, 2, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 2, 2, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 12, 12, 12, 2, 2, 2,
- 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 2, 2,
- 2, 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 14, 14,
- 14, 14, 14, 2, 14, 2, 14, 14, 2, 14, 14, 2, 14, 14, 14, 14,
- 14, 14, 14, 14, 14, 14, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 0, 0, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2,
- 2, 2, 2, 2, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 6, 6, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0,
- 0, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 3, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 0, 0, 2, 2, 12, 12, 12, 12, 12, 12, 2, 2,
- 12, 12, 12, 12, 12, 12, 2, 2, 12, 12, 12, 12, 12, 12, 2, 2,
- 12, 12, 12, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0,
- 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0,
- 0, 0, 0, 0, 2, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 2, 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 2, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 2, 2, 2, 9, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 2, 2, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
- 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
- 71, 71, 71, 2, 2, 2, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67,
- 67, 67, 67, 67, 67, 67, 67, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
- 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 42, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
- 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
- 41, 2, 2, 2, 2, 2,118,118,118,118,118,118,118,118,118,118,
- 118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,
- 118, 2, 2, 2, 2, 2, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
- 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
- 53, 53, 53, 53, 2, 53, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
- 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 2, 2, 2, 2, 59, 59,
- 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
- 40, 40, 40, 40, 40, 40, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
- 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
- 50, 50, 50, 50, 2, 2, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
- 2, 2, 2, 2, 2, 2,135,135,135,135,135,135,135,135,135,135,
- 135,135,135,135,135,135,135,135,135,135, 2, 2, 2, 2,135,135,
- 135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,
- 135,135, 2, 2, 2, 2,106,106,106,106,106,106,106,106,106,106,
- 106,106,106,106,106,106,106,106,106,106,106,106,106,106, 2, 2,
- 2, 2, 2, 2, 2, 2,104,104,104,104,104,104,104,104,104,104,
- 104,104,104,104,104,104,104,104,104,104, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2,104,161,161,161,161,161,161,161,161,161,161,
- 161, 2,161,161,161,161,161,161,161, 2,161,161, 2,161,161,161,
- 161,161,161,161,161,161,161,161, 2,161,161,161,161,161,161,161,
- 161,161,161,161,161,161,161,161, 2,161,161,161,161,161,161,161,
- 2,161,161, 2, 2, 2,110,110,110,110,110,110,110,110,110,110,
- 110,110,110,110,110,110,110,110,110,110,110,110,110, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,110,110,110,110,110,110, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,110,110,110,110,110,110,110,110, 2, 2,
- 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 2, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 2, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 2, 2, 2, 2, 2, 47, 47, 47, 47, 47, 47, 2, 2, 47, 2,
- 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
- 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 2, 47, 47, 2,
- 2, 2, 47, 2, 2, 47, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
- 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 2, 81, 81, 81,
- 81, 81, 81, 81, 81, 81,120,120,120,120,120,120,120,120,120,120,
- 120,120,120,120,120,120,116,116,116,116,116,116,116,116,116,116,
- 116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,
- 116,116,116,116,116, 2, 2, 2, 2, 2, 2, 2, 2,116,116,116,
- 116,116,116,116,116,116,128,128,128,128,128,128,128,128,128,128,
- 128,128,128,128,128,128,128,128,128, 2,128,128, 2, 2, 2, 2,
- 2,128,128,128,128,128, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
- 66, 66, 2, 2, 2, 66, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
- 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
- 2, 2, 2, 2, 2, 72, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98,
- 98, 98, 98, 98, 98, 98, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,
- 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 2, 2,
- 2, 2, 97, 97, 97, 97, 2, 2, 97, 97, 97, 97, 97, 97, 97, 97,
- 97, 97, 97, 97, 97, 97, 57, 57, 57, 57, 2, 57, 57, 2, 2, 2,
- 2, 2, 57, 57, 57, 57, 57, 57, 57, 57, 2, 57, 57, 57, 2, 57,
- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
- 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 2, 2, 57, 57,
- 57, 2, 2, 2, 2, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 2,
- 2, 2, 2, 2, 2, 2, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88,
- 88, 88, 88, 88, 88, 88,117,117,117,117,117,117,117,117,117,117,
- 117,117,117,117,117,117,112,112,112,112,112,112,112,112,112,112,
- 112,112,112,112,112,112,112,112,112,112,112,112,112, 2, 2, 2,
- 2,112,112,112,112,112,112,112,112,112,112,112,112, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78,
- 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 2, 2, 2, 78,
- 78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83,
- 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 2, 2, 83, 83,
- 83, 83, 83, 83, 83, 83, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
- 82, 82, 82, 82, 82, 82, 82, 82, 82, 2, 2, 2, 2, 2, 82, 82,
- 82, 82, 82, 82, 82, 82,122,122,122,122,122,122,122,122,122,122,
- 122,122,122,122,122,122,122,122, 2, 2, 2, 2, 2, 2, 2,122,
- 122,122,122, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,122,
- 122,122,122,122,122,122, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89,
- 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 2,
- 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,130,130,130,130,
- 130,130,130,130,130,130,130,130,130, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,130,130,130, 2, 2, 2, 2, 2, 2, 2,
- 130,130,130,130,130,130,144,144,144,144,144,144,144,144,144,144,
- 144,144,144,144,144,144,144,144,144,144,144,144,144,144, 2, 2,
- 2, 2, 2, 2, 2, 2,144,144,144,144,144,144,144,144,144,144,
- 2, 2, 2, 2, 2, 2,156,156,156,156,156,156,156,156,156,156,
- 156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,
- 2,156,156,156, 2, 2,156,156, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,147,147,147,147,147,147,147,147,147,147,
- 147,147,147,147,147,147,147,147,147,147,147,147,147,147, 2, 2,
- 2, 2, 2, 2, 2, 2,148,148,148,148,148,148,148,148,148,148,
- 148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,
- 2, 2, 2, 2, 2, 2,158,158,158,158,158,158,158,158,158,158,
- 158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,
- 2, 2, 2, 2, 2, 2,153,153,153,153,153,153,153,153,153,153,
- 153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,
- 153,153, 2, 2, 2, 2,149,149,149,149,149,149,149,149,149,149,
- 149,149,149,149,149,149,149,149,149,149,149,149,149, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
- 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
- 94, 94, 94, 94, 2, 2, 2, 2, 94, 94, 94, 94, 94, 94, 94, 94,
- 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 94, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
- 85, 85, 85, 85, 85, 85, 85, 85, 85, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 85, 2, 2,101,101,101,101,101,101,101,101,101,101,
- 101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, 2,
- 2, 2, 2, 2, 2, 2,101,101,101,101,101,101,101,101,101,101,
- 2, 2, 2, 2, 2, 2, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 2, 96, 96, 96, 96,
- 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 2, 2,
- 2, 2, 2, 2, 2, 2,111,111,111,111,111,111,111,111,111,111,
- 111,111,111,111,111,111,111,111,111,111,111,111,111, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,100,100,100,100,100,100,100,100,100,100,
- 100,100,100,100,100,100, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36,
- 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,108,108,108,108,108,108,108,108,108,108,
- 108,108,108,108,108,108,108,108, 2,108,108,108,108,108,108,108,
- 108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,
- 108,108,108,108,108, 2,129,129,129,129,129,129,129, 2,129, 2,
- 129,129,129,129, 2,129,129,129,129,129,129,129,129,129,129,129,
- 129,129,129,129, 2,129,129,129,129,129,129,129,129,129,129,129,
- 2, 2, 2, 2, 2, 2,109,109,109,109,109,109,109,109,109,109,
- 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,
- 109, 2, 2, 2, 2, 2,109,109,109,109,109,109,109,109,109,109,
- 2, 2, 2, 2, 2, 2,107,107,107,107, 2,107,107,107,107,107,
- 107,107,107, 2, 2,107,107, 2, 2,107,107,107,107,107,107,107,
- 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107, 2,
- 107,107,107,107,107,107,107, 2,107,107, 2,107,107,107,107,107,
- 2, 1,107,107,107,107,107,107,107,107,107, 2, 2,107,107, 2,
- 2,107,107,107, 2, 2,107, 2, 2, 2, 2, 2, 2,107, 2, 2,
- 2, 2, 2,107,107,107,107,107,107,107, 2, 2,107,107,107,107,
- 107,107,107, 2, 2, 2,107,107,107,107,107, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,137,137,137,137,137,137,137,137,137,137,
- 137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,
- 137,137, 2,137,137,137,137,137, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,124,124,124,124,124,124,124,124,124,124,
- 124,124,124,124,124,124,124,124,124,124,124,124,124,124, 2, 2,
- 2, 2, 2, 2, 2, 2,124,124,124,124,124,124,124,124,124,124,
- 2, 2, 2, 2, 2, 2,123,123,123,123,123,123,123,123,123,123,
- 123,123,123,123,123,123,123,123,123,123,123,123, 2, 2,123,123,
- 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,
- 123,123,123,123, 2, 2,114,114,114,114,114,114,114,114,114,114,
- 114,114,114,114,114,114,114,114,114,114,114, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,114,114,114,114,114,114,114,114,114,114,
- 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 2, 2, 2,102,102,102,102,102,102,102,102,102,102,
- 102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,
- 2, 2, 2, 2, 2, 2,126,126,126,126,126,126,126,126,126,126,
- 126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,
- 126, 2, 2,126,126,126,126,126,126,126,126,126,126,126,126,126,
- 126,126, 2, 2, 2, 2,126,126,126,126,126,126,126, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,142,142,142,142,142,142,142,142,142,142,
- 142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,
- 142,142, 2, 2, 2, 2,125,125,125,125,125,125,125,125,125,125,
- 125,125,125,125,125,125,125,125,125, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2,125,154,154,154,154,154,154,154, 2, 2,154,
- 2, 2,154,154,154,154,154,154,154,154, 2,154,154, 2,154,154,
- 154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,
- 154,154,154,154,154,154,154,154,154,154,154,154, 2,154,154, 2,
- 2,154,154,154,154,154,154,154,154,154,154,154,154, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,154,154,154,154,154,154,154,154,154,154,
- 2, 2, 2, 2, 2, 2,150,150,150,150,150,150,150,150, 2, 2,
- 150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,
- 150,150,150,150,150,150,150,150,150,150,150, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,141,141,141,141,141,141,141,141,141,141,
- 141,141,141,141,141,141,141,141,141,141,141,141,141,141, 2, 2,
- 2, 2, 2, 2, 2, 2,140,140,140,140,140,140,140,140,140,140,
- 140,140,140,140,140,140,140,140,140, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,121,121,121,121,121,121,121,121,121,121,
- 121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, 2,
- 2, 2, 2, 2, 2, 2,133,133,133,133,133,133,133,133,133, 2,
- 133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,
- 133,133,133,133,133,133,133,133,133,133,133,133,133, 2,133,133,
- 133,133,133,133,133,133,133,133,133,133,133,133, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,133,133,133,133,133,133,133,133,133,133,
- 133,133,133, 2, 2, 2,134,134,134,134,134,134,134,134,134,134,
- 134,134,134,134,134,134, 2, 2,134,134,134,134,134,134,134,134,
- 134,134,134,134,134,134,134,134,134,134,134,134,134,134, 2,134,
- 134,134,134,134,134,134,134,134,134,134,134,134,134, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,138,138,138,138,138,138,138, 2,138,138,
- 2,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,
- 138,138,138,138,138,138,138,138,138,138,138,138,138, 2, 2, 2,
- 138, 2,138,138, 2,138,138,138,138,138,138,138,138,138, 2, 2,
- 2, 2, 2, 2, 2, 2,138,138,138,138,138,138,138,138,138,138,
- 2, 2, 2, 2, 2, 2,143,143,143,143,143,143, 2,143,143, 2,
- 143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
- 143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
- 143,143,143,143,143, 2,143,143, 2,143,143,143,143,143,143, 2,
- 2, 2, 2, 2, 2, 2,143,143,143,143,143,143,143,143,143,143,
- 2, 2, 2, 2, 2, 2,145,145,145,145,145,145,145,145,145,145,
- 145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, 2,
- 2, 2, 2, 2, 2, 2, 86, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
- 22, 22, 22, 22, 22, 22, 22, 22, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 22, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
- 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 2, 63, 63, 63, 63, 63, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,157,157,157,157,157,157,157,157,157,157,
- 157,157,157,157,157,157,157,157,157, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
- 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
- 80, 80, 80, 80, 80, 2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 2,
- 2, 2, 2, 2, 2, 2,127,127,127,127,127,127,127,127,127,127,
- 127,127,127,127,127,127,127,127,127,127,127,127,127, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2,
- 2, 2, 2, 2, 2, 2,115,115,115,115,115,115,115,115,115,115,
- 115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,
- 115,115,115,115,115, 2,115,115,115,115,115,115,115,115,115,115,
- 2, 2, 2, 2,115,115,159,159,159,159,159,159,159,159,159,159,
- 159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,
- 159,159,159,159,159, 2,159,159,159,159,159,159,159,159,159,159,
- 2, 2, 2, 2, 2, 2,103,103,103,103,103,103,103,103,103,103,
- 103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,
- 103,103,103,103, 2, 2,103,103,103,103,103,103, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,119,119,119,119,119,119,119,119,119,119,
- 119,119,119,119,119,119,119,119,119,119,119,119, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,119,119,119,119,119,119,119,119,119,119,
- 2,119,119,119,119,119,119,119, 2,119,119,119,119,119,119,119,
- 119,119,119,119,119,119,119,119,119,119,119,119,119,119, 2, 2,
- 2, 2, 2,119,119,119,146,146,146,146,146,146,146,146,146,146,
- 146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,
- 146, 2, 2, 2, 2, 2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 2, 2, 2, 2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 2, 2,
- 2, 2, 2, 2, 2, 99,136,139, 13, 13,155, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 13, 13, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,136,136,136,136,136,136,136,136,136,136,
- 136,136,136,136,136,136,136,136,136,136,136,136,136,136, 2, 2,
- 2, 2, 2, 2, 2, 2,155,155,155,155,155,155,155,155,155,155,
- 155,155,155,155,155,155,155,155,155,155,155,155, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,136,136,136,136,136,136,136,136,136, 2,
- 2, 2, 2, 2, 2, 2, 17, 17, 17, 17, 2, 17, 17, 17, 17, 17,
- 17, 17, 2, 17, 17, 2, 17, 15, 15, 15, 15, 15, 15, 15, 15, 15,
- 15, 15, 15, 15, 15, 15, 17, 17, 17, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 17, 17, 17, 17, 2, 2,
- 2, 2, 2, 2, 2, 2,139,139,139,139,139,139,139,139,139,139,
- 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,
- 139,139, 2, 2, 2, 2,105,105,105,105,105,105,105,105,105,105,
- 105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,
- 105, 2, 2, 2, 2, 2,105,105,105,105,105,105,105,105,105,105,
- 105,105,105, 2, 2, 2,105,105,105,105,105,105,105,105,105, 2,
- 2, 2, 2, 2, 2, 2,105,105,105,105,105,105,105,105,105,105,
- 2, 2,105,105,105,105, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1,
- 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 0, 0, 9, 9, 9, 9, 9, 9, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 2, 0, 0, 2, 2, 0, 2, 2, 0, 0, 2, 2, 0,
- 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
- 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0,
- 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 2, 2,
- 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 2, 2, 0, 0,131,131,131,131,131,131,131,131,131,131,
- 131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,
- 131,131, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2,131,131,131,131,131, 2,131,131,131,131,131,131,131,131,131,
- 131,131,131,131,131,131, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 2, 56, 56, 56, 56, 56, 56, 56, 2, 56, 56,
- 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 2,
- 2, 56, 56, 56, 56, 56, 56, 56, 2, 56, 56, 2, 56, 56, 56, 56,
- 56, 2, 2, 2, 2, 2,151,151,151,151,151,151,151,151,151,151,
- 151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,
- 151,151,151, 2, 2, 2,151,151,151,151,151,151,151,151,151,151,
- 151,151,151,151, 2, 2,151,151,151,151,151,151,151,151,151,151,
- 2, 2, 2, 2,151,151,160,160,160,160,160,160,160,160,160,160,
- 160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,
- 160,160,160,160,160, 2,152,152,152,152,152,152,152,152,152,152,
- 152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,
- 2, 2, 2, 2, 2,152, 30, 30, 30, 30, 30, 30, 30, 2, 30, 30,
- 30, 30, 2, 30, 30, 2, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
- 30, 30, 30, 30, 30, 2,113,113,113,113,113,113,113,113,113,113,
- 113,113,113,113,113,113,113,113,113,113,113, 2, 2,113,113,113,
- 113,113,113,113,113,113,113,113,113,113,113,113,113, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,132,132,132,132,132,132,132,132,132,132,
- 132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,
- 132,132, 2, 2, 2, 2,132,132,132,132,132,132,132,132,132,132,
- 2, 2, 2, 2,132,132, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3,
- 3, 3, 3, 3, 3, 3, 2, 3, 3, 2, 3, 2, 2, 3, 2, 3,
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 3,
- 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 3,
- 2, 3, 2, 3, 3, 3, 2, 3, 3, 2, 3, 2, 2, 3, 2, 3,
- 2, 3, 2, 3, 2, 3, 2, 3, 3, 2, 3, 2, 2, 3, 3, 3,
- 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 3,
- 3, 3, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 3, 3,
- 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 15, 0, 0, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2,
- 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0,
- 0, 0, 0, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2,
- 2, 2, 2, 2, 2, 2, 13, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 0, 0, 0, 1, 2, 3, 4, 5, 6, 0,
- 0, 0, 0, 7, 8, 9, 10, 11, 0, 12, 0, 0, 0, 0, 13, 0,
- 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 15, 16, 0, 17, 18, 19,
- 0, 0, 0, 20, 21, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 0,
- 0, 0, 0, 27, 28, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33,
- 34, 35, 36, 37, 38, 39, 40, 0, 0, 0, 41, 0, 42, 43, 44, 45,
- 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 50, 51, 52, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, 57, 58,
- 59, 60, 61, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 64, 0, 0, 0, 0, 0,
- 0, 0, 0, 65, 0, 0, 0, 0, 66, 0, 0, 0, 67, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 70, 71, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 72, 73, 74, 75, 76, 77, 78, 79, 80, 0,
-};
-static const uint16_t
-_hb_ucd_u16[11584] =
-{
- 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12,
- 13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23,
- 13, 13, 13, 24, 25, 11, 11, 11, 11, 26, 11, 27, 28, 29, 30, 31,
- 32, 32, 32, 32, 32, 32, 32, 33, 34, 35, 36, 11, 37, 38, 13, 39,
- 9, 9, 9, 11, 11, 11, 13, 13, 40, 13, 13, 13, 41, 13, 13, 13,
- 13, 13, 13, 42, 9, 43, 11, 11, 44, 45, 32, 46, 47, 48, 49, 50,
- 51, 52, 48, 48, 53, 32, 54, 55, 48, 48, 48, 48, 48, 56, 57, 58,
- 59, 60, 48, 32, 61, 48, 48, 48, 48, 48, 62, 63, 64, 48, 65, 66,
- 48, 67, 68, 69, 48, 70, 71, 48, 72, 73, 48, 48, 74, 32, 75, 32,
- 76, 48, 48, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
- 90, 83, 84, 91, 92, 93, 94, 95, 96, 97, 84, 98, 99, 100, 88, 101,
- 102, 83, 84, 103, 104, 105, 88, 106, 107, 108, 109, 110, 111, 112, 94, 113,
- 114, 115, 84, 116, 117, 118, 88, 119, 120, 115, 84, 121, 122, 123, 88, 124,
- 125, 115, 48, 126, 127, 128, 88, 129, 130, 131, 48, 132, 133, 134, 94, 135,
- 136, 48, 48, 137, 138, 139, 140, 140, 141, 48, 142, 143, 144, 145, 140, 140,
- 146, 147, 148, 149, 150, 48, 151, 152, 153, 154, 32, 155, 156, 157, 140, 140,
- 48, 48, 158, 159, 160, 161, 162, 163, 164, 165, 9, 9, 166, 11, 11, 167,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 168, 169, 48, 48, 168, 48, 48, 170, 171, 172, 48, 48,
- 48, 171, 48, 48, 48, 173, 174, 175, 48, 176, 9, 9, 9, 9, 9, 177,
- 178, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 179, 48, 180, 181, 48, 48, 48, 48, 182, 183,
- 48, 184, 48, 185, 48, 186, 187, 188, 48, 48, 48, 189, 190, 191, 192, 193,
- 194, 192, 48, 48, 195, 48, 48, 196, 197, 48, 198, 48, 48, 48, 48, 199,
- 48, 200, 201, 202, 203, 48, 204, 205, 48, 48, 206, 48, 207, 208, 209, 209,
- 48, 210, 48, 48, 48, 211, 212, 213, 192, 192, 214, 215, 216, 140, 140, 140,
- 217, 48, 48, 218, 219, 160, 220, 221, 222, 48, 223, 64, 48, 48, 224, 225,
- 48, 48, 226, 227, 228, 64, 48, 229, 230, 9, 9, 231, 232, 233, 234, 235,
- 11, 11, 236, 27, 27, 27, 237, 238, 11, 239, 27, 27, 32, 32, 32, 32,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 240, 13, 13, 13, 13, 13, 13,
- 241, 242, 241, 241, 242, 243, 241, 244, 245, 245, 245, 246, 247, 248, 249, 250,
- 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 261, 262, 263, 264, 265,
- 266, 267, 268, 269, 270, 271, 272, 272, 273, 274, 275, 209, 276, 277, 209, 278,
- 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279,
- 280, 209, 281, 209, 209, 209, 209, 282, 209, 283, 279, 284, 209, 285, 286, 209,
- 209, 209, 287, 140, 288, 140, 271, 271, 271, 289, 209, 209, 209, 209, 290, 271,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 291, 292, 209, 209, 293,
- 209, 209, 209, 209, 209, 209, 294, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 295, 296, 271, 297, 209, 209, 298, 279, 299, 279,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 279, 279, 279, 279, 279, 279, 279, 279, 300, 301, 279, 279, 279, 302, 279, 303,
- 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279,
- 209, 209, 209, 279, 304, 209, 209, 305, 209, 306, 209, 209, 209, 209, 209, 209,
- 9, 9, 9, 11, 11, 11, 307, 308, 13, 13, 13, 13, 13, 13, 309, 310,
- 11, 11, 311, 48, 48, 48, 312, 313, 48, 314, 315, 315, 315, 315, 32, 32,
- 316, 317, 318, 319, 320, 321, 140, 140, 209, 322, 209, 209, 209, 209, 209, 323,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 324, 140, 325,
- 326, 327, 328, 329, 136, 48, 48, 48, 48, 330, 178, 48, 48, 48, 48, 331,
- 332, 48, 48, 136, 48, 48, 48, 48, 200, 333, 48, 48, 209, 209, 323, 48,
- 209, 334, 335, 209, 336, 337, 209, 209, 335, 209, 209, 337, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 209, 209, 209, 209,
- 48, 338, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 151, 209, 209, 209, 287, 48, 48, 229,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 339, 48, 340, 140, 13, 13, 341, 342, 13, 343, 48, 48, 48, 48, 344, 345,
- 31, 346, 347, 348, 13, 13, 13, 349, 350, 351, 352, 353, 354, 355, 140, 356,
- 357, 48, 358, 359, 48, 48, 48, 360, 361, 48, 48, 362, 363, 192, 32, 364,
- 64, 48, 365, 48, 366, 367, 48, 151, 76, 48, 48, 368, 369, 370, 371, 372,
- 48, 48, 373, 374, 375, 376, 48, 377, 48, 48, 48, 378, 379, 380, 381, 382,
- 383, 384, 315, 11, 11, 385, 386, 11, 11, 11, 11, 11, 48, 48, 387, 192,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 388, 48, 389, 48, 48, 206,
- 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390,
- 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390,
- 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391,
- 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391,
- 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 204, 48, 48, 48, 48, 48, 48, 207, 140, 140,
- 392, 393, 394, 395, 396, 48, 48, 48, 48, 48, 48, 397, 398, 399, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 400, 209, 48, 48, 48, 48, 401, 48, 48, 402, 140, 140, 403,
- 32, 404, 32, 405, 406, 407, 408, 409, 48, 48, 48, 48, 48, 48, 48, 410,
- 411, 2, 3, 4, 5, 412, 413, 414, 48, 415, 48, 200, 416, 417, 418, 419,
- 420, 48, 172, 421, 204, 204, 140, 140, 48, 48, 48, 48, 48, 48, 48, 71,
- 422, 271, 271, 423, 272, 272, 272, 424, 425, 426, 427, 140, 140, 209, 209, 428,
- 140, 140, 140, 140, 140, 140, 140, 140, 48, 151, 48, 48, 48, 100, 429, 430,
- 48, 48, 431, 48, 432, 48, 48, 433, 48, 434, 48, 48, 435, 436, 140, 140,
- 9, 9, 437, 11, 11, 48, 48, 48, 48, 204, 192, 9, 9, 438, 11, 439,
- 48, 48, 440, 48, 48, 48, 441, 442, 442, 443, 444, 445, 140, 140, 140, 140,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 314, 48, 199, 440, 140, 446, 27, 27, 447, 140, 140, 140, 140,
- 448, 48, 48, 449, 48, 450, 48, 451, 48, 200, 452, 140, 140, 140, 48, 453,
- 48, 454, 48, 455, 140, 140, 140, 140, 48, 48, 48, 456, 271, 457, 271, 271,
- 458, 459, 48, 460, 461, 462, 48, 463, 48, 464, 140, 140, 465, 48, 466, 467,
- 48, 48, 48, 468, 48, 469, 48, 470, 48, 471, 472, 140, 140, 140, 140, 140,
- 48, 48, 48, 48, 196, 140, 140, 140, 9, 9, 9, 473, 11, 11, 11, 474,
- 48, 48, 475, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 271, 476, 48, 48, 477, 478, 140, 140, 140, 140,
- 48, 464, 479, 48, 62, 480, 140, 48, 481, 140, 140, 48, 482, 140, 48, 314,
- 483, 48, 48, 484, 485, 457, 486, 487, 222, 48, 48, 488, 489, 48, 196, 192,
- 490, 48, 491, 492, 493, 48, 48, 494, 222, 48, 48, 495, 496, 497, 498, 499,
- 48, 97, 500, 501, 140, 140, 140, 140, 502, 503, 504, 48, 48, 505, 506, 192,
- 507, 83, 84, 508, 509, 510, 511, 512, 140, 140, 140, 140, 140, 140, 140, 140,
- 48, 48, 48, 513, 514, 515, 478, 140, 48, 48, 48, 516, 517, 192, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 48, 48, 518, 519, 520, 521, 140, 140,
- 48, 48, 48, 522, 523, 192, 524, 140, 48, 48, 525, 526, 192, 140, 140, 140,
- 48, 173, 527, 528, 314, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 48, 48, 500, 529, 140, 140, 140, 140, 140, 140, 9, 9, 11, 11, 148, 530,
- 531, 532, 48, 533, 534, 192, 140, 140, 140, 140, 535, 48, 48, 536, 537, 140,
- 538, 48, 48, 539, 540, 541, 48, 48, 542, 543, 544, 48, 48, 48, 48, 196,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 84, 48, 518, 545, 546, 148, 175, 547, 48, 548, 549, 550, 140, 140, 140, 140,
- 551, 48, 48, 552, 553, 192, 554, 48, 555, 556, 192, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 557,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 100, 271, 558, 559, 560,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 207, 140, 140, 140, 140, 140, 140,
- 272, 272, 272, 272, 272, 272, 561, 562, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 388, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 563,
- 48, 48, 200, 564, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 48, 48, 48, 48, 314, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 48, 48, 48, 196, 48, 200, 370, 48, 48, 48, 48, 200, 192, 48, 204, 565,
- 48, 48, 48, 566, 567, 568, 569, 570, 48, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 9, 9, 11, 11, 271, 571, 140, 140, 140, 140, 140, 140,
- 48, 48, 48, 48, 572, 573, 574, 574, 575, 576, 140, 140, 140, 140, 577, 578,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 440,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 199, 140, 140,
- 196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 579,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 580, 140, 140, 580, 581, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 206,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 48, 48, 48, 48, 48, 48, 71, 151, 196, 582, 583, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 32, 32, 584, 32, 585, 209, 209, 209, 209, 209, 209, 209, 323, 140, 140, 140,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 324,
- 209, 209, 586, 209, 209, 209, 587, 588, 589, 209, 590, 209, 209, 209, 288, 140,
- 209, 209, 209, 209, 591, 140, 140, 140, 140, 140, 140, 140, 140, 140, 271, 592,
- 209, 209, 209, 209, 209, 287, 271, 461, 140, 140, 140, 140, 140, 140, 140, 140,
- 9, 593, 11, 594, 595, 596, 241, 9, 597, 598, 599, 600, 601, 9, 593, 11,
- 602, 603, 11, 604, 605, 606, 607, 9, 608, 11, 9, 593, 11, 594, 595, 11,
- 241, 9, 597, 607, 9, 608, 11, 9, 593, 11, 609, 9, 610, 611, 612, 613,
- 11, 614, 9, 615, 616, 617, 618, 11, 619, 9, 620, 11, 621, 622, 622, 622,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 32, 32, 32, 623, 32, 32, 624, 625, 626, 627, 45, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 628, 629, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 630, 631, 632, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 48, 48, 151, 633, 634, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 48, 635, 140, 48, 48, 636, 637,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 638, 200,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 639, 585, 140, 140,
- 9, 9, 597, 11, 640, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 498, 271, 271, 641, 642, 140, 140, 140, 140,
- 498, 271, 643, 644, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 645, 48, 646, 647, 648, 649, 650, 651, 652, 206, 653, 206, 140, 140, 140, 654,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 209, 209, 325, 209, 209, 209, 209, 209, 209, 323, 334, 655, 655, 655, 209, 324,
- 656, 209, 209, 209, 209, 209, 209, 209, 209, 209, 657, 140, 140, 140, 658, 209,
- 659, 209, 209, 325, 660, 661, 324, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 662,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 663, 426, 426,
- 209, 209, 209, 209, 209, 209, 209, 323, 209, 209, 209, 209, 209, 660, 325, 427,
- 325, 209, 209, 209, 664, 176, 209, 209, 664, 209, 657, 661, 140, 140, 140, 140,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
- 209, 209, 209, 209, 209, 323, 657, 665, 287, 209, 426, 288, 324, 176, 664, 287,
- 209, 209, 209, 209, 209, 209, 209, 209, 209, 666, 209, 209, 288, 140, 140, 192,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 140, 140,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 196, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 204, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 478, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 100, 140,
- 48, 204, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 71, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140,
- 667, 140, 668, 668, 668, 668, 668, 668, 140, 140, 140, 140, 140, 140, 140, 140,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 140,
- 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391,
- 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 669,
- 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391,
- 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 670,
- 0, 0, 0, 0, 1, 2, 1, 2, 0, 0, 3, 3, 4, 5, 4, 5,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 0, 0, 7, 0,
- 8, 8, 8, 8, 8, 8, 8, 9, 10, 11, 12, 11, 11, 11, 13, 11,
- 14, 14, 14, 14, 14, 14, 14, 14, 15, 14, 14, 14, 14, 14, 14, 14,
- 14, 14, 14, 16, 17, 18, 17, 17, 19, 20, 21, 21, 22, 21, 23, 24,
- 25, 26, 27, 27, 28, 29, 27, 30, 27, 27, 27, 27, 27, 31, 27, 27,
- 32, 33, 33, 33, 34, 27, 27, 27, 35, 35, 35, 36, 37, 37, 37, 38,
- 39, 39, 40, 41, 42, 43, 44, 27, 45, 46, 27, 27, 27, 27, 47, 27,
- 48, 48, 48, 48, 48, 49, 50, 48, 51, 52, 53, 54, 55, 56, 57, 58,
- 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
- 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
- 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106,
- 107, 108, 109, 109, 110, 111, 112, 109, 113, 114, 115, 116, 117, 118, 119, 120,
- 121, 122, 122, 123, 122, 124, 125, 125, 126, 127, 128, 129, 130, 131, 125, 125,
- 132, 132, 132, 132, 133, 132, 134, 135, 132, 133, 132, 136, 136, 137, 125, 125,
- 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 139, 139, 140, 139, 139, 141,
- 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
- 143, 143, 143, 143, 144, 145, 143, 143, 144, 143, 143, 146, 147, 148, 143, 143,
- 143, 147, 143, 143, 143, 149, 143, 150, 143, 151, 152, 152, 152, 152, 152, 153,
- 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
- 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
- 154, 154, 154, 154, 154, 154, 154, 154, 155, 156, 157, 157, 157, 157, 158, 159,
- 160, 161, 162, 163, 164, 165, 166, 167, 168, 168, 168, 168, 168, 169, 170, 170,
- 171, 172, 173, 173, 173, 173, 173, 174, 173, 173, 175, 154, 154, 154, 154, 176,
- 177, 178, 179, 179, 180, 181, 182, 183, 184, 184, 185, 184, 186, 187, 168, 168,
- 188, 189, 190, 190, 190, 191, 190, 192, 193, 193, 194, 8, 195, 125, 125, 125,
- 196, 196, 196, 196, 197, 196, 196, 198, 199, 199, 199, 199, 200, 200, 200, 201,
- 202, 202, 202, 203, 204, 205, 205, 205, 206, 139, 139, 207, 208, 209, 210, 211,
- 4, 4, 212, 4, 4, 213, 214, 215, 4, 4, 4, 216, 8, 8, 8, 8,
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 11, 217, 11, 11, 217, 218, 11, 219, 11, 11, 11, 220, 220, 221, 11, 222,
- 223, 0, 0, 0, 0, 0, 224, 225, 226, 227, 0, 0, 228, 8, 8, 229,
- 0, 0, 230, 231, 232, 0, 4, 4, 233, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 234, 125, 235, 125, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 237, 0, 238, 0, 0, 0, 0, 0, 0,
- 239, 239, 239, 239, 239, 239, 4, 4, 240, 240, 240, 240, 240, 240, 240, 241,
- 139, 139, 140, 242, 242, 242, 243, 244, 143, 245, 246, 246, 246, 246, 14, 14,
- 0, 0, 0, 0, 0, 247, 125, 125, 248, 249, 248, 248, 248, 248, 248, 250,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 251, 125, 252,
- 253, 0, 254, 255, 256, 257, 257, 257, 257, 258, 259, 260, 260, 260, 260, 261,
- 262, 263, 263, 264, 142, 142, 142, 142, 265, 0, 263, 263, 0, 0, 266, 260,
- 142, 265, 0, 0, 0, 0, 142, 267, 0, 0, 0, 0, 0, 260, 260, 268,
- 260, 260, 260, 260, 260, 269, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 0, 0, 0, 0,
- 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270,
- 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270,
- 270, 270, 270, 270, 270, 270, 270, 270, 271, 270, 270, 270, 272, 273, 273, 273,
- 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, 274,
- 274, 274, 275, 125, 14, 14, 14, 14, 14, 14, 276, 276, 276, 276, 276, 277,
- 0, 0, 278, 4, 4, 4, 4, 4, 279, 4, 4, 4, 280, 281, 125, 282,
- 283, 283, 284, 285, 286, 286, 286, 287, 288, 288, 288, 288, 289, 290, 48, 48,
- 291, 291, 292, 293, 293, 294, 142, 295, 296, 296, 296, 296, 297, 298, 138, 299,
- 300, 300, 300, 301, 302, 303, 138, 138, 304, 304, 304, 304, 305, 306, 307, 308,
- 309, 310, 246, 4, 4, 311, 312, 152, 152, 152, 152, 152, 307, 307, 313, 314,
- 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
- 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
- 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
- 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 315, 142, 316, 142, 142, 317,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 248, 318, 248, 248, 248, 248, 248, 248, 319, 125, 125,
- 320, 321, 21, 322, 323, 27, 27, 27, 27, 27, 27, 27, 324, 325, 27, 27,
- 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
- 27, 27, 27, 326, 27, 27, 27, 27, 27, 327, 27, 27, 328, 125, 125, 27,
- 8, 285, 329, 0, 0, 330, 331, 332, 27, 27, 27, 27, 27, 27, 27, 333,
- 334, 0, 1, 2, 1, 2, 335, 259, 260, 336, 142, 265, 337, 338, 339, 340,
- 341, 342, 343, 344, 345, 345, 125, 125, 342, 342, 342, 342, 342, 342, 342, 346,
- 347, 0, 0, 348, 11, 11, 11, 11, 349, 350, 351, 125, 125, 0, 0, 352,
- 125, 125, 125, 125, 125, 125, 125, 125, 353, 354, 355, 355, 355, 356, 357, 252,
- 358, 358, 359, 360, 361, 362, 362, 363, 364, 365, 366, 366, 367, 368, 125, 125,
- 369, 369, 369, 369, 369, 370, 370, 370, 371, 372, 373, 374, 374, 375, 374, 376,
- 377, 377, 378, 379, 379, 379, 380, 381, 381, 382, 383, 384, 125, 125, 125, 125,
- 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385, 385,
- 385, 385, 385, 386, 385, 387, 388, 125, 389, 4, 4, 390, 125, 125, 125, 125,
- 391, 392, 392, 393, 394, 395, 396, 396, 397, 398, 399, 125, 125, 125, 400, 401,
- 402, 403, 404, 405, 125, 125, 125, 125, 406, 406, 407, 408, 407, 409, 407, 407,
- 410, 411, 412, 413, 414, 414, 415, 415, 416, 416, 125, 125, 417, 417, 418, 419,
- 420, 420, 420, 421, 422, 423, 424, 425, 426, 427, 428, 125, 125, 125, 125, 125,
- 429, 429, 429, 429, 430, 125, 125, 125, 431, 431, 431, 432, 431, 431, 431, 433,
- 434, 434, 435, 436, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 27, 45, 437, 437, 438, 439, 125, 125, 125, 125,
- 440, 440, 441, 442, 442, 443, 125, 444, 445, 125, 125, 446, 447, 125, 448, 449,
- 450, 450, 450, 450, 451, 452, 450, 453, 454, 454, 454, 454, 455, 456, 457, 458,
- 459, 459, 459, 460, 461, 462, 462, 463, 464, 464, 464, 464, 464, 464, 465, 466,
- 467, 468, 467, 469, 125, 125, 125, 125, 470, 471, 472, 473, 473, 473, 474, 475,
- 476, 477, 478, 479, 480, 481, 482, 483, 125, 125, 125, 125, 125, 125, 125, 125,
- 484, 484, 484, 484, 484, 485, 486, 125, 487, 487, 487, 487, 488, 489, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 490, 490, 490, 491, 490, 492, 125, 125,
- 493, 493, 493, 493, 494, 495, 496, 125, 497, 497, 497, 498, 498, 125, 125, 125,
- 499, 500, 501, 499, 502, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 503, 503, 503, 504, 125, 125, 125, 125, 125, 125, 505, 505, 505, 505, 505, 506,
- 507, 508, 509, 510, 511, 512, 125, 125, 125, 125, 513, 514, 514, 513, 515, 125,
- 516, 516, 516, 516, 517, 518, 518, 518, 518, 518, 519, 154, 520, 520, 520, 521,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 522, 523, 523, 524, 525, 523, 526, 527, 527, 528, 529, 530, 125, 125, 125, 125,
- 531, 532, 532, 533, 534, 535, 536, 537, 538, 539, 540, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 541, 542,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 543, 544, 544, 544, 545,
- 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546,
- 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546,
- 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546,
- 546, 546, 546, 546, 546, 546, 546, 546, 546, 547, 125, 125, 125, 125, 125, 125,
- 546, 546, 546, 546, 546, 546, 548, 549, 546, 546, 546, 546, 546, 546, 546, 546,
- 546, 546, 546, 546, 550, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 551, 551, 551, 551, 551, 551, 552,
- 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553,
- 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553, 553,
- 553, 553, 554, 555, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556,
- 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556,
- 556, 556, 556, 556, 557, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
- 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
- 276, 276, 276, 558, 559, 560, 561, 562, 562, 562, 562, 563, 564, 565, 566, 567,
- 568, 568, 568, 568, 569, 570, 571, 572, 568, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 573, 573, 573, 573, 573, 574, 125, 125, 125, 125, 125, 125,
- 575, 575, 575, 575, 576, 575, 575, 575, 577, 575, 125, 125, 125, 125, 578, 579,
- 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580,
- 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580,
- 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580,
- 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 581,
- 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580, 580,
- 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582,
- 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 582, 583, 125, 125,
- 584, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 585,
- 586, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257, 257,
- 257, 257, 587, 125, 125, 588, 589, 590, 590, 590, 590, 590, 590, 590, 590, 590,
- 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 591,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 592, 592, 592, 592, 592, 592, 593, 594, 595, 596, 266, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 8, 8, 597, 8, 598, 0, 0, 0, 0, 0, 0, 0, 266, 125, 125, 125,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 599,
- 0, 0, 600, 0, 0, 0, 601, 602, 603, 0, 604, 0, 0, 0, 235, 125,
- 11, 11, 11, 11, 605, 125, 125, 125, 125, 125, 125, 125, 125, 125, 0, 266,
- 0, 0, 0, 0, 0, 234, 0, 606, 125, 125, 125, 125, 125, 125, 125, 125,
- 0, 0, 0, 0, 0, 224, 0, 0, 0, 607, 608, 609, 610, 0, 0, 0,
- 611, 612, 0, 613, 614, 615, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 616, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 617, 0, 0, 0,
- 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618,
- 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618, 618,
- 618, 618, 618, 618, 618, 618, 618, 618, 619, 620, 621, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 4, 622, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 623, 624, 625, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 626, 626, 627, 628, 629, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 630, 631, 125, 632, 632, 632, 633,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 634, 635,
- 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 636, 637, 638, 125, 125,
- 639, 639, 639, 639, 640, 641, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 334, 0, 0, 0, 642, 125, 125, 125, 125,
- 334, 0, 0, 247, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 643, 27, 644, 645, 646, 647, 648, 649, 650, 651, 652, 651, 125, 125, 125, 653,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 0, 0, 252, 0, 0, 0, 0, 0, 0, 266, 226, 334, 334, 334, 0, 599,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 247, 125, 125, 125, 654, 0,
- 655, 0, 0, 252, 606, 656, 599, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 657, 350, 350,
- 0, 0, 0, 0, 0, 0, 0, 266, 0, 0, 0, 0, 0, 606, 252, 228,
- 252, 0, 0, 0, 658, 285, 0, 0, 658, 0, 247, 656, 125, 125, 125, 125,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 266, 247, 659, 234, 0, 350, 235, 599, 285, 658, 234,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 330, 0, 0, 235, 125, 125, 285,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 125, 125,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 660, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 318, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 579, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 661, 125,
- 248, 318, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
- 248, 248, 248, 248, 662, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125,
- 663, 125, 0, 0, 0, 0, 0, 0, 125, 125, 125, 125, 125, 125, 125, 125,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003,1008,
- 0,1033,1040,1041,1042,1043,1047, 0, 0,1080,1081,1082,1086,1110, 0, 0,
- 1124,1125,1126,1127,1131,1133, 0,1147,1154,1155,1156,1161,1187,1188,1189,1193,
- 0,1219,1226,1227,1228,1229,1233, 0, 0,1267,1268,1269,1273,1298, 0,1303,
- 943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149,
- 0, 0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175,
- 991,1176, 993,1178, 994,1179, 0, 0,1004,1190,1005,1191,1006,1192,1014,1199,
- 1007, 0, 0, 0,1016,1201,1020,1206, 0,1022,1208,1025,1211,1023,1209, 0,
- 0, 0, 0,1032,1218,1037,1223,1035,1221, 0, 0, 0,1044,1230,1045,1231,
- 1049,1235, 0, 0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258,
- 1069,1255,1077,1264,1074,1261, 0, 0,1083,1270,1084,1271,1085,1272,1088,1275,
- 1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1053,1239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1093,
- 1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 949,1134,1010,
- 1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366, 0,1320,1347,
- 1418,1419,1323,1350, 0, 0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424,
- 1202, 0, 0, 0, 987,1172, 0, 0,1031,1217,1321,1348,1322,1349,1338,1365,
- 950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238,
- 1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263, 0, 0, 997,1182,
- 0, 0, 0, 0, 0, 0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232,
- 1422,1423,1113,1301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 8, 9, 0, 10,1425, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
- 0, 0, 0, 0, 0,1314,1427, 5,1434,1438,1443, 0,1450, 0,1455,1461,
- 1514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1446,1458,1468,1476,1480,1486,
- 1517, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1489,1503,1494,1500,1508, 0,
- 0, 0, 0,1520,1521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1526,1528, 0,1525, 0, 0, 0,1522, 0, 0, 0, 0,1536,1532,1539, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1534, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1556, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1548,1550, 0,1547, 0, 0, 0,1567, 0, 0, 0, 0,1558,1554,1561, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,1568,1569, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1529,1551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1523,1545,1524,1546, 0, 0,1527,1549, 0, 0,1570,1571,1530,1552,1531,1553,
- 0, 0,1533,1555,1535,1557,1537,1559, 0, 0,1572,1573,1544,1566,1538,1560,
- 1540,1562,1541,1563,1542,1564, 0, 0,1543,1565, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,1606,1607,1609,1608,1610, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1613, 0,1611, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1620, 0, 0, 0, 0, 0, 0,
- 0,1623, 0, 0,1624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1614,1615,1616,1617,1618,1619,1621,1622,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1628,1629, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1625,1626, 0,1627,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1634, 0, 0,1635, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1630,1631,1632, 0, 0,1633, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1639, 0, 0,1638,1640, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1636,1637, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1641, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1642,1644,1643, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1645, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1646, 0, 0, 0, 0, 0, 0,1648,1649, 0,1647,1650, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1651,1653,1652, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1654, 0,1655,1657,1656, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1659, 0, 0, 0, 0, 0, 0, 0, 0, 0,1660, 0, 0,
- 0, 0,1661, 0, 0, 0, 0,1662, 0, 0, 0, 0,1663, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1658, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1664, 0,1665,1673, 0,1674, 0, 0, 0, 0, 0, 0, 0,
- 0,1666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0,1668, 0, 0, 0, 0, 0, 0, 0, 0, 0,1669, 0, 0,
- 0, 0,1670, 0, 0, 0, 0,1671, 0, 0, 0, 0,1672, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0,1667, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,1675, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,1676, 0,1677, 0,1678, 0,1679, 0,1680, 0,
- 0, 0,1681, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1682, 0,1683, 0, 0,
- 1684,1685, 0,1686, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153,
- 966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171,
- 989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356,
- 1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214,
- 1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363,
- 1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251,
- 1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266,
- 1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287,
- 1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302,
- 1119,1308,1122,1311,1123,1312,1186,1260,1293,1305, 0,1394, 0, 0, 0, 0,
- 952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375,
- 1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353,
- 1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234,
- 1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403,
- 1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412,
- 1409,1414,1109,1297,1117,1306,1116,1304,1112,1300, 0, 0, 0, 0, 0, 0,
- 1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721,
- 1477,1478,1729,1731,1730,1732, 0, 0,1435,1436,1733,1735,1734,1736, 0, 0,
- 1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757,
- 1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776,
- 1495,1496,1777,1779,1778,1780, 0, 0,1451,1452,1781,1783,1782,1784, 0, 0,
- 1504,1505,1785,1788,1786,1789,1787,1790, 0,1459, 0,1791, 0,1792, 0,1793,
- 1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814,
- 1467, 21,1475, 22,1479, 23,1485, 24,1493, 27,1499, 28,1507, 29, 0, 0,
- 1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728,
- 1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764,
- 1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821,
- 1470,1469,1822,1474,1465, 0,1473,1825,1429,1428,1426, 12,1432, 0, 26, 0,
- 0,1315,1823,1484,1466, 0,1483,1829,1433, 13,1437, 14,1441,1826,1827,1828,
- 1488,1487,1513, 19, 0, 0,1492,1515,1445,1444,1442, 15, 0,1831,1832,1833,
- 1502,1501,1516, 25,1497,1498,1506,1518,1457,1456,1454, 17,1453,1313, 11, 3,
- 0, 0,1824,1512,1519, 0,1511,1830,1449, 16,1460, 18,1464, 4, 0, 0,
- 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 6, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1834,1835, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1836, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1837,1839,1838,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1840, 0, 0, 0, 0,1841, 0, 0,1842, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1843, 0,1844, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0,1845, 0, 0,1846, 0, 0,1847, 0,1848, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 937, 0,1850, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1849, 936, 938,
- 1851,1852, 0, 0,1853,1854, 0, 0,1855,1856, 0, 0, 0, 0, 0, 0,
- 1857,1858, 0, 0,1861,1862, 0, 0,1863,1864, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1867,1868,1869,1870,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1859,1860,1865,1866, 0, 0, 0, 0, 0, 0,1871,1872,1873,1874, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1875, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1877, 0,1878, 0,
- 1879, 0,1880, 0,1881, 0,1882, 0,1883, 0,1884, 0,1885, 0,1886, 0,
- 1887, 0,1888, 0, 0,1889, 0,1890, 0,1891, 0, 0, 0, 0, 0, 0,
- 1892,1893, 0,1894,1895, 0,1896,1897, 0,1898,1899, 0,1900,1901, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1876, 0, 0, 0, 0, 0, 0, 0, 0, 0,1902, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1904, 0,1905, 0,
- 1906, 0,1907, 0,1908, 0,1909, 0,1910, 0,1911, 0,1912, 0,1913, 0,
- 1914, 0,1915, 0, 0,1916, 0,1917, 0,1918, 0, 0, 0, 0, 0, 0,
- 1919,1920, 0,1921,1922, 0,1923,1924, 0,1925,1926, 0,1927,1928, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,1903, 0, 0,1929,1930,1931,1932, 0, 0, 0,1933, 0,
- 710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601,
- 663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662,
- 810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168,
- 368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758,
- 811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585,
- 594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259,
- 313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697,
- 424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170,
- 193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330,
- 337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473,
- 683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603,
- 608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411,
- 479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583,
- 791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269,
- 377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510,
- 659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156,
- 153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210, 0, 0,
- 227, 0, 379, 0, 0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604, 0,
- 661, 0, 703, 0, 0, 735, 743, 0, 0, 0, 793, 794, 795, 808, 741, 773,
- 118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329,
- 335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548,
- 549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651,
- 690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623, 0, 0,
- 102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243,
- 250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362,
- 370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490,
- 493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586,
- 591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706,
- 709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848,
- 847, 857, 55, 65, 66, 883, 892, 916, 822, 824, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1586, 0,1605,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1602,1603,1934,1935,1574,1575,
- 1576,1577,1579,1580,1581,1583,1584, 0,1585,1587,1588,1589,1591, 0,1592, 0,
- 1593,1594, 0,1595,1596, 0,1598,1599,1600,1601,1604,1582,1578,1590,1597, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1936, 0,1937, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1938, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1939,1940,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1941,1942, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1944,1943, 0,1945, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1946,1947, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,1948, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1949,1950,
- 1951,1952,1953,1954,1955, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1956,1957,1958,1960,1959,
- 1961, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125, 34, 830, 130, 131,
- 132, 137, 827, 35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152, 37,
- 157, 158, 159, 160, 38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179,
- 181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195,
- 197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216,
- 153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244,
- 836, 837, 247, 248, 249, 246, 251, 39, 40, 253, 255, 255, 838, 257, 258, 259,
- 261, 839, 262, 263, 301, 264, 41, 266, 270, 272, 271, 841, 274, 842, 277, 276,
- 278, 281, 282, 42, 283, 284, 285, 286, 43, 843, 44, 289, 290, 291, 293, 934,
- 298, 845, 845, 621, 300, 300, 45, 852, 894, 302, 304, 46, 306, 309, 310, 312,
- 316, 48, 47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334,
- 335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361,
- 358, 356, 49, 363, 365, 367, 364, 50, 369, 371, 851, 376, 386, 378, 53, 381,
- 52, 51, 140, 141, 387, 382, 614, 78, 388, 389, 390, 394, 392, 856, 54, 399,
- 396, 402, 404, 858, 405, 401, 407, 55, 408, 409, 410, 413, 859, 415, 56, 417,
- 860, 418, 57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433,
- 437, 441, 438, 439, 442, 443, 864, 436, 449, 450, 58, 454, 453, 865, 447, 460,
- 866, 867, 461, 466, 465, 464, 59, 467, 470, 469, 472, 828, 475, 868, 478, 870,
- 483, 485, 486, 871, 488, 489, 872, 873, 495, 497, 60, 498, 61, 61, 504, 505,
- 507, 508, 511, 62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878, 63, 64,
- 528, 880, 879, 881, 882, 530, 531, 531, 533, 66, 534, 67, 68, 884, 536, 538,
- 541, 69, 885, 549, 886, 887, 556, 559, 70, 561, 562, 563, 888, 889, 889, 567,
- 71, 890, 570, 571, 72, 891, 577, 73, 581, 579, 582, 893, 587, 74, 590, 592,
- 596, 75, 895, 896, 76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611,
- 853, 77, 615, 616, 79, 617, 252, 902, 903, 854, 855, 621, 622, 731, 80, 627,
- 626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651,
- 638, 643, 644, 645, 905, 907, 906, 81, 653, 654, 656, 911, 657, 908, 82, 83,
- 909, 910, 84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675, 85,
- 677, 678, 86, 681, 682, 912, 685, 686, 87, 689, 36, 913, 914, 88, 89, 696,
- 702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728,
- 918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762, 90,
- 764, 922, 91, 775, 279, 780, 923, 925, 92, 93, 785, 926, 94, 927, 787, 787,
- 789, 928, 792, 95, 796, 797, 798, 800, 96, 929, 802, 804, 806, 97, 98, 807,
- 930, 99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-};
-static const int16_t
-_hb_ucd_i16[196] =
-{
- 0, 0, 0, 0, 1, -1, 0, 0, 2, 0, -2, 0, 0, 0, 0, 2,
- 0, -2, 0, 0, 0, 0, 0, 16, 0, 0, 0, -16, 0, 0, 1, -1,
- 0, 0, 0, 1, -1, 0, 0, 0, 0, 1, -1, 0, 3, 3, 3, -3,
- -3, -3, 0, 0, 0, 2016, 0, 0, 0, 0, 0, 2527, 1923, 1914, 1918, 0,
- 2250, 0, 0, 0, 0, 0, 0, 138, 0, 7, 0, 0, -7, 0, 0, 0,
- 1, -1, 1, -1, -1, 1, -1, 0, 1824, 0, 0, 0, 0, 0, 2104, 0,
- 2108, 2106, 0, 2106, 1316, 0, 0, 0, 0, 1, -1, 1, -1, -138, 0, 0,
- 1, -1, 8, 8, 8, 0, 7, 7, 0, 0, -8, -8, -8, -7, -7, 0,
- 1, -1, 0, 2,-1316, 1, -1, 0, -1, 1, -1, 1, -1, 3, 1, -1,
- -3, 1, -1, 1, -1, 0, 0,-1914,-1918, 0, 0,-1923,-1824, 0, 0, 0,
- 0,-2016, 0, 0, 1, -1, 0, 1, 0, 0,-2104, 0, 0, 0, 0,-2106,
- -2108,-2106, 0, 0, 1, -1,-2250, 0, 0, 0,-2527, 0, 0, -2, 0, 1,
- -1, 0, 1, -1,
-};
-
-static inline uint_fast8_t
-_hb_ucd_gc (unsigned u)
-{
- return u<1114110u?_hb_ucd_u8[2176+(((_hb_ucd_u16[((_hb_ucd_u8[u>>4>>5])<<5)+((u>>4)&31u)])<<4)+((u)&15u))]:2;
-}
-static inline uint_fast8_t
-_hb_ucd_ccc (unsigned u)
-{
- return u<125259u?_hb_ucd_u8[15332+(((_hb_ucd_u8[13892+(((_hb_ucd_u8[12912+(u>>3>>4)])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:0;
-}
-static inline unsigned
-_hb_ucd_b4 (const uint8_t* a, unsigned i)
-{
- return (a[i>>1]>>((i&1u)<<2))&15u;
-}
-static inline int_fast16_t
-_hb_ucd_bmg (unsigned u)
-{
- return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[16692+(((_hb_ucd_b4(16564+_hb_ucd_u8,u>>2>>6))<<6)+((u>>2)&63u))])<<2)+((u)&3u)]:0;
-}
-static inline uint_fast8_t
-_hb_ucd_sc (unsigned u)
-{
- return u<918000u?_hb_ucd_u8[19446+(((_hb_ucd_u16[3168+(((_hb_ucd_u8[17652+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:2;
-}
-static inline uint_fast16_t
-_hb_ucd_dm (unsigned u)
-{
- return u<195102u?_hb_ucd_u16[6400+(((_hb_ucd_u8[30070+(u>>6)])<<6)+((u)&63u))]:0;
-}
-
-
-#elif !defined(HB_NO_UCD_UNASSIGNED)
-
-static const uint8_t
_hb_ucd_u8[17936] =
{
0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7,
@@ -5675,10 +2821,1743 @@ _hb_ucd_dm (unsigned u)
}
+#elif !defined(HB_NO_UCD_UNASSIGNED)
+
+static const uint8_t
+_hb_ucd_u8[17564] =
+{
+ 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 9, 10, 7, 7, 7, 7, 11, 12, 13, 13, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 22, 22, 22, 22, 24, 7, 7,
+ 25, 26, 22, 22, 22, 27, 28, 29, 22, 30, 31, 32, 33, 34, 35, 36,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 37, 7, 38, 39, 7, 40, 7, 7, 7, 41, 22, 42,
+ 7, 7, 43, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 44, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 45,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 46,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 34, 35, 36, 37, 38, 39, 34, 34, 34, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 64, 65, 66, 67, 68, 69, 70, 71, 69, 72, 73,
+ 69, 69, 64, 74, 64, 64, 75, 76, 77, 78, 79, 80, 81, 82, 69, 83,
+ 84, 85, 86, 87, 88, 89, 69, 69, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 90, 34, 34, 34, 34,
+ 91, 34, 34, 34, 34, 34, 34, 34, 34, 92, 34, 34, 93, 94, 95, 96,
+ 97, 98, 99,100,101,102,103,104, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,105,
+ 106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,
+ 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,
+ 107,107, 34, 34,108,109,110,111, 34, 34,112,113,114,115,116,117,
+ 118,119,120,121,122,123,124,125,126,127,128,129, 34, 34,130,131,
+ 132,133,134,135,136,137,138,139,140,141,142,122,143,144,145,146,
+ 147,148,149,150,151,152,153,122,154,155,122,156,157,158,159,122,
+ 160,161,162,163,164,165,122,122,166,167,168,169,122,170,122,171,
+ 34, 34, 34, 34, 34, 34, 34,172,173, 34,174,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,175,
+ 34, 34, 34, 34, 34, 34, 34, 34,176,122,122,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122, 34, 34, 34, 34,177,122,122,122,
+ 34, 34, 34, 34,178,179,180,181,122,122,122,122,182,183,184,185,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,186,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34,187,188,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,189,
+ 34, 34,190, 34, 34,191,122,122,122,122,122,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,192,193,122,122,122,122,122,122,
+ 122,122,122,122,122,122,122,122,122,122,122,122,122,122,194,195,
+ 69,196,197,198,199,200,201,122,202,203,204,205,206,207,208,209,
+ 69, 69, 69, 69,210,211,122,122,122,122,122,122,122,122,212,122,
+ 213,122,214,122,122,215,122,122,122,122,122,122,122,122,122,216,
+ 34,217,218,122,122,122,122,122,219,220,221,122,222,223,122,122,
+ 224,225,226,227,228,122, 69,229, 69, 69, 69, 69, 69,230,231,232,
+ 233,234, 69, 69,235,236, 69,237,122,122,122,122,122,122,122,122,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,238, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,239, 34,
+ 240, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,241, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34,242,122,122,122,122,122,122,122,122,
+ 34, 34, 34, 34,243,122,122,122,122,122,122,122,122,122,122,122,
+ 34, 34, 34, 34, 34, 34,244,122,122,122,122,122,122,122,122,122,
+ 245,122,246,247,122,122,122,122,122,122,122,122,122,122,122,122,
+ 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,248,
+ 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,249,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 2, 4, 5, 6, 2,
+ 7, 7, 7, 7, 7, 2, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 17, 18, 19, 1, 20, 20, 21, 22, 23, 24, 25,
+ 26, 27, 15, 2, 28, 29, 27, 30, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 31, 11, 11, 11, 32, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 33, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 34, 34, 34, 34, 34, 34, 34, 34, 16, 32, 32, 32,
+ 32, 32, 32, 32, 11, 34, 34, 16, 34, 32, 32, 11, 34, 11, 16, 11,
+ 11, 34, 32, 11, 32, 16, 11, 34, 32, 32, 32, 11, 34, 16, 32, 11,
+ 34, 11, 34, 34, 32, 35, 32, 16, 36, 36, 37, 34, 38, 37, 34, 34,
+ 34, 34, 34, 34, 34, 34, 16, 32, 34, 38, 32, 11, 32, 32, 32, 32,
+ 32, 32, 16, 16, 16, 11, 34, 32, 34, 34, 11, 32, 32, 32, 32, 32,
+ 16, 16, 39, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 41, 41, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41,
+ 40, 40, 42, 41, 41, 41, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41,
+ 43, 43, 43, 43, 43, 43, 43, 43, 32, 32, 42, 32, 44, 45, 16, 10,
+ 44, 44, 41, 46, 11, 47, 47, 11, 34, 11, 11, 11, 11, 11, 11, 11,
+ 11, 48, 11, 11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 34,
+ 16, 11, 32, 16, 32, 32, 32, 32, 16, 16, 32, 49, 34, 32, 34, 11,
+ 32, 50, 43, 43, 51, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16,
+ 48, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 47, 52, 2, 2, 2,
+ 16, 16, 16, 16, 53, 54, 55, 56, 57, 43, 43, 43, 43, 43, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 58, 59, 60, 43, 59, 44, 44, 44, 44,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 62,
+ 36, 63, 64, 44, 44, 44, 44, 44, 65, 65, 65, 8, 9, 66, 2, 67,
+ 43, 43, 43, 43, 43, 60, 68, 2, 69, 36, 36, 36, 36, 70, 43, 43,
+ 7, 7, 7, 7, 7, 2, 2, 36, 71, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 72, 43, 43, 43, 73, 50, 43, 43, 74, 75, 76, 43, 43, 36,
+ 7, 7, 7, 7, 7, 36, 77, 78, 2, 2, 2, 2, 2, 2, 2, 79,
+ 70, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 80, 62, 36,
+ 36, 36, 36, 43, 43, 43, 43, 43, 71, 44, 44, 44, 44, 44, 44, 44,
+ 7, 7, 7, 7, 7, 36, 36, 36, 36, 36, 36, 36, 36, 70, 43, 43,
+ 43, 43, 40, 21, 2, 81, 57, 20, 36, 36, 36, 43, 43, 75, 43, 43,
+ 43, 43, 75, 43, 75, 43, 43, 44, 2, 2, 2, 2, 2, 2, 2, 64,
+ 36, 36, 36, 36, 70, 43, 44, 64, 36, 36, 36, 36, 36, 61, 44, 44,
+ 36, 36, 36, 36, 82, 36, 36, 61, 65, 44, 44, 44, 43, 43, 43, 43,
+ 36, 36, 36, 36, 83, 43, 43, 43, 43, 84, 43, 43, 43, 43, 43, 43,
+ 43, 85, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 85, 71, 86,
+ 87, 43, 43, 43, 85, 86, 87, 86, 70, 43, 43, 43, 36, 36, 36, 36,
+ 36, 43, 2, 7, 7, 7, 7, 7, 88, 36, 36, 36, 36, 36, 36, 36,
+ 70, 86, 62, 36, 36, 36, 61, 62, 61, 62, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 61, 36, 36, 36, 61, 61, 44, 36, 36, 44, 71, 86,
+ 87, 43, 80, 89, 90, 89, 87, 61, 44, 44, 44, 89, 44, 44, 36, 62,
+ 36, 43, 44, 7, 7, 7, 7, 7, 36, 20, 27, 27, 27, 56, 63, 80,
+ 57, 85, 62, 36, 36, 61, 44, 62, 61, 36, 62, 61, 36, 44, 80, 86,
+ 87, 80, 44, 57, 80, 57, 43, 44, 57, 44, 44, 44, 62, 36, 61, 61,
+ 44, 44, 44, 7, 7, 7, 7, 7, 43, 36, 70, 64, 44, 44, 44, 44,
+ 57, 85, 62, 36, 36, 36, 36, 62, 36, 62, 36, 36, 36, 36, 36, 36,
+ 61, 36, 62, 36, 36, 44, 71, 86, 87, 43, 43, 57, 85, 89, 87, 44,
+ 61, 44, 44, 44, 44, 44, 44, 44, 66, 44, 44, 44, 62, 43, 43, 43,
+ 57, 86, 62, 36, 36, 36, 61, 62, 61, 36, 62, 36, 36, 44, 71, 87,
+ 87, 43, 80, 89, 90, 89, 87, 44, 44, 44, 57, 85, 44, 44, 36, 62,
+ 78, 27, 27, 27, 44, 44, 44, 44, 44, 71, 62, 36, 36, 61, 44, 36,
+ 61, 36, 36, 44, 62, 61, 61, 36, 44, 62, 61, 44, 36, 61, 44, 36,
+ 36, 36, 36, 36, 36, 44, 44, 86, 85, 90, 44, 86, 90, 86, 87, 44,
+ 61, 44, 44, 89, 44, 44, 44, 44, 27, 91, 67, 67, 56, 92, 44, 44,
+ 85, 86, 71, 36, 36, 36, 61, 36, 61, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 44, 71, 43, 85, 86, 90, 43, 80, 43, 43, 44,
+ 44, 44, 57, 80, 36, 61, 62, 44, 44, 44, 44, 93, 27, 27, 27, 91,
+ 70, 86, 72, 36, 36, 36, 61, 36, 36, 36, 62, 36, 36, 44, 71, 87,
+ 86, 86, 90, 85, 90, 86, 43, 44, 44, 44, 89, 90, 44, 44, 62, 61,
+ 62, 61, 44, 44, 44, 44, 44, 44, 43, 86, 36, 36, 36, 36, 61, 36,
+ 36, 36, 36, 36, 36, 70, 71, 86, 87, 43, 80, 86, 90, 86, 87, 77,
+ 44, 44, 36, 94, 27, 27, 27, 95, 27, 27, 27, 27, 91, 36, 36, 36,
+ 57, 86, 62, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 36, 36, 36,
+ 36, 62, 36, 36, 36, 36, 62, 44, 36, 36, 36, 61, 44, 80, 44, 89,
+ 86, 43, 80, 80, 86, 86, 86, 86, 44, 86, 64, 44, 44, 44, 44, 44,
+ 62, 36, 36, 36, 36, 36, 36, 36, 70, 36, 43, 43, 43, 80, 44, 96,
+ 36, 36, 36, 75, 43, 43, 43, 60, 7, 7, 7, 7, 7, 2, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 62, 61, 61, 36, 36, 61, 36, 36,
+ 36, 36, 62, 62, 36, 36, 36, 36, 70, 36, 43, 43, 43, 43, 71, 44,
+ 36, 36, 61, 81, 43, 43, 43, 44, 7, 7, 7, 7, 7, 44, 36, 36,
+ 77, 67, 2, 2, 2, 2, 2, 2, 2, 97, 97, 67, 43, 67, 67, 67,
+ 7, 7, 7, 7, 7, 27, 27, 27, 27, 27, 50, 50, 50, 4, 4, 86,
+ 36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44,
+ 57, 43, 43, 43, 43, 43, 43, 85, 43, 43, 60, 43, 36, 36, 70, 43,
+ 43, 43, 43, 43, 57, 43, 43, 43, 43, 43, 43, 43, 43, 43, 80, 67,
+ 67, 67, 67, 76, 67, 67, 92, 67, 2, 2, 97, 67, 21, 64, 44, 44,
+ 36, 36, 36, 36, 36, 94, 87, 43, 85, 43, 43, 43, 87, 85, 87, 71,
+ 7, 7, 7, 7, 7, 2, 2, 2, 36, 36, 36, 86, 43, 36, 36, 43,
+ 71, 86, 98, 94, 86, 86, 86, 36, 70, 43, 71, 36, 36, 36, 36, 36,
+ 36, 85, 87, 85, 86, 86, 87, 94, 7, 7, 7, 7, 7, 86, 87, 67,
+ 11, 11, 11, 48, 44, 44, 48, 44, 16, 16, 16, 16, 16, 53, 45, 16,
+ 36, 36, 36, 36, 61, 36, 36, 44, 36, 36, 36, 61, 61, 36, 36, 44,
+ 61, 36, 36, 44, 36, 36, 36, 61, 61, 36, 36, 44, 36, 36, 36, 36,
+ 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 57, 43,
+ 2, 2, 2, 2, 99, 27, 27, 27, 27, 27, 27, 27, 27, 27,100, 44,
+ 67, 67, 67, 67, 67, 44, 44, 44, 11, 11, 11, 44, 16, 16, 16, 44,
+ 101, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 77, 72,
+ 102, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,103,104, 44,
+ 36, 36, 36, 36, 36, 63, 2,105,106, 36, 36, 36, 61, 44, 44, 44,
+ 36, 43, 85, 44, 44, 44, 44, 62, 36, 43,107, 64, 44, 44, 44, 44,
+ 36, 43, 44, 44, 44, 44, 44, 44, 36, 36, 36, 36, 36, 36, 61, 36,
+ 61, 43, 44, 44, 44, 44, 44, 44, 36, 36, 43, 87, 43, 43, 43, 86,
+ 86, 86, 86, 85, 87, 43, 43, 43, 43, 43, 2, 88, 2, 66, 70, 44,
+ 7, 7, 7, 7, 7, 44, 44, 44, 27, 27, 27, 27, 27, 44, 44, 44,
+ 2, 2, 2,108, 2, 59, 43, 84, 36, 83, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 61, 44, 44, 44, 36, 36, 70, 71, 36, 36, 36, 36,
+ 36, 36, 36, 36, 70, 61, 44, 44, 36, 36, 36, 44, 44, 44, 44, 44,
+ 36, 36, 36, 36, 36, 36, 36, 61, 43, 85, 86, 87, 85, 86, 44, 44,
+ 86, 85, 86, 86, 87, 43, 44, 44, 92, 44, 2, 7, 7, 7, 7, 7,
+ 36, 36, 36, 36, 36, 36, 36, 44, 36, 36, 61, 44, 44, 44, 44, 44,
+ 36, 36, 36, 36, 36, 36, 44, 44, 36, 36, 36, 36, 36, 44, 44, 44,
+ 7, 7, 7, 7, 7,100, 44, 67, 67, 67, 67, 67, 67, 67, 67, 67,
+ 36, 36, 36, 70, 85, 87, 44, 2, 36, 36, 94, 85, 43, 43, 43, 80,
+ 85, 85, 87, 43, 43, 43, 85, 86, 86, 87, 43, 43, 43, 43, 80, 57,
+ 2, 2, 2, 88, 2, 2, 2, 44, 43, 43, 43, 43, 43, 43, 43,109,
+ 43, 43, 43, 43, 43, 43, 43, 80, 43, 43, 98, 36, 36, 36, 36, 36,
+ 36, 36, 85, 43, 43, 85, 85, 86, 86, 85, 98, 36, 36, 36, 61, 44,
+ 97, 67, 67, 67, 67, 50, 43, 43, 43, 43, 67, 67, 67, 67, 21, 64,
+ 43, 98, 36, 36, 36, 36, 36, 36, 94, 43, 43, 86, 43, 87, 43, 36,
+ 36, 36, 36, 85, 43, 86, 87, 87, 43, 86, 44, 44, 44, 44, 2, 2,
+ 36, 36, 86, 86, 86, 86, 43, 43, 43, 43, 86, 43, 44, 93, 2, 2,
+ 7, 7, 7, 7, 7, 44, 62, 36, 36, 36, 36, 36, 40, 40, 40, 2,
+ 16, 16, 16, 16,110, 44, 44, 44, 11, 11, 11, 11, 11, 47, 48, 11,
+ 2, 2, 2, 2, 44, 44, 44, 44, 43, 60, 43, 43, 43, 43, 43, 43,
+ 85, 43, 43, 43, 71, 36, 70, 36, 36, 36, 71, 94, 43, 61, 44, 44,
+ 16, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 45, 16, 16,
+ 16, 16, 16, 16, 45, 16, 16, 16, 16, 16, 16, 16, 16,111, 40, 40,
+ 32, 32, 32, 16, 16, 16, 16, 32, 16, 16, 16, 16, 11, 11, 11, 11,
+ 16, 16, 16, 44, 11, 11, 11, 44, 16, 16, 16, 16, 48, 48, 48, 48,
+ 16, 16, 16, 16, 16, 16, 16, 44, 16, 16, 16, 16,112,112,112,112,
+ 16, 16,110, 16, 11, 11,113,114, 41, 16,110, 16, 11, 11,113, 41,
+ 16, 16, 44, 16, 11, 11,115, 41, 16, 16, 16, 16, 11, 11,116, 41,
+ 44, 16,110, 16, 11, 11,113,117,118,118,118,118,118,119, 65, 65,
+ 120,120,120, 2,121,122,121,122, 2, 2, 2, 2,123, 65, 65,124,
+ 2, 2, 2, 2,125,126, 2,127,128, 2,129,130, 2, 2, 2, 2,
+ 2, 9,128, 2, 2, 2, 2,131, 65, 65,132, 65, 65, 65, 65, 65,
+ 133, 44, 27, 27, 27, 8,129,134, 27, 27, 27, 27, 27, 8,129,104,
+ 40, 40, 40, 40, 40, 40, 81, 44, 20, 20, 20, 20, 20, 20, 20, 20,
+ 135, 44, 44, 44, 44, 44, 44, 44, 43, 43, 43, 43, 43, 43,136, 51,
+ 109, 51,109, 43, 43, 43, 43, 43, 80, 44, 44, 44, 44, 44, 44, 44,
+ 67,137, 67,138, 67, 34, 11, 16, 11, 32,138, 67, 49, 11, 11, 67,
+ 67, 67,137,137,137, 11, 11,139, 11, 11, 35, 36, 39, 67, 16, 11,
+ 8, 8, 49, 16, 16, 26, 67,140, 27, 27, 27, 27, 27, 27, 27, 27,
+ 105,105,105,105,105,105,105,105,105,141,142,105,143, 67, 44, 44,
+ 8, 8,144, 67, 67, 8, 67, 67,144, 26, 67,144, 67, 67, 67,144,
+ 67, 67, 67, 67, 67, 67, 67, 8, 67,144,144, 67, 67, 67, 67, 67,
+ 67, 67, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 67, 67, 67, 67, 4, 4, 67, 67, 8, 67, 67, 67,145,146, 67, 67,
+ 67, 67, 67, 67, 67, 67,144, 67, 67, 67, 67, 67, 67, 26, 8, 8,
+ 8, 8, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 8, 8,
+ 8, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 92, 44, 44, 44, 44,
+ 67, 67, 67, 67, 67, 92, 44, 44, 27, 27, 27, 27, 27, 27, 67, 67,
+ 67, 67, 67, 67, 67, 27, 27, 27, 67, 67, 67, 26, 67, 67, 67, 67,
+ 26, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 8, 8, 8, 8,
+ 67, 67, 67, 67, 67, 67, 67, 26, 67, 67, 67, 67, 4, 4, 4, 4,
+ 4, 4, 4, 27, 27, 27, 27, 27, 27, 27, 67, 67, 67, 67, 67, 67,
+ 8, 8,129,147, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4,
+ 8,129,148,148,148,148,148,148,148,148,148,148,147, 8, 8, 8,
+ 8, 8, 8, 8, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 4, 8,
+ 8, 8,144, 26, 8, 8,144, 67, 67, 67, 44, 67, 67, 67, 67, 67,
+ 67, 67, 67, 55, 67, 67, 67, 67, 32, 11, 32, 34, 34, 34, 34, 11,
+ 32, 32, 34, 16, 16, 16, 40, 11, 32, 32,140, 67, 67,138, 34,149,
+ 43, 32, 44, 44, 93, 2, 99, 2, 16, 16, 16,150, 44, 44,150, 44,
+ 36, 36, 36, 36, 44, 44, 44, 52, 64, 44, 44, 44, 44, 44, 44, 57,
+ 36, 36, 36, 61, 44, 44, 44, 44, 36, 36, 36, 61, 36, 36, 36, 61,
+ 2,121,121, 2,125,126,121, 2, 2, 2, 2, 6, 2,108,121, 2,
+ 121, 4, 4, 4, 4, 2, 2, 88, 2, 2, 2, 2, 2,120, 2, 2,
+ 108,151, 2, 2, 2, 2, 2, 2, 67, 2,152,148,148,148,153, 44,
+ 67, 67, 67, 67, 67, 55, 67, 67, 67, 67, 44, 44, 44, 44, 44, 44,
+ 67, 67, 67, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 67, 44, 44,
+ 1, 2,154,155, 4, 4, 4, 4, 4, 67, 4, 4, 4, 4,156,157,
+ 158,105,105,105,105, 43, 43, 86,159, 40, 40, 67,105,160, 63, 67,
+ 36, 36, 36, 61, 57,161,162, 69, 36, 36, 36, 36, 36, 63, 40, 69,
+ 44, 44, 62, 36, 36, 36, 36, 36, 67, 27, 27, 67, 67, 67, 67, 67,
+ 67, 67, 67, 67, 67, 67, 67, 92, 27, 27, 27, 27, 27, 67, 67, 67,
+ 67, 67, 67, 67, 27, 27, 27, 27,163, 27, 27, 27, 27, 27, 27, 27,
+ 36, 36, 83, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,164, 2,
+ 7, 7, 7, 7, 7, 36, 44, 44, 32, 32, 32, 32, 32, 32, 32, 70,
+ 51,165, 43, 43, 43, 43, 43, 88, 32, 32, 32, 32, 32, 32, 40, 43,
+ 36, 36, 36,105,105,105,105,105, 43, 2, 2, 2, 44, 44, 44, 44,
+ 41, 41, 41,162, 40, 40, 40, 40, 41, 32, 32, 32, 32, 32, 32, 32,
+ 16, 32, 32, 32, 32, 32, 32, 32, 45, 16, 16, 16, 34, 34, 34, 32,
+ 32, 32, 32, 32, 42,166, 34, 35, 32, 32, 16, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 11, 11, 32, 11, 11, 32, 32, 32, 32, 32, 32,
+ 32, 32, 11, 11, 34,110, 44, 44, 32,150,150, 32, 32, 44, 44, 44,
+ 44, 40,167, 35, 40, 35, 36, 36, 36, 71, 36, 71, 36, 70, 36, 36,
+ 36, 94, 87, 85, 67, 67, 80, 44, 27, 27, 27, 67,168, 44, 44, 44,
+ 36, 36, 2, 2, 44, 44, 44, 44, 86, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 86, 86, 86, 86, 86, 86, 86, 86, 43, 44, 44, 44, 44, 2,
+ 43, 36, 36, 36, 2, 72, 72, 70, 36, 36, 36, 43, 43, 43, 43, 2,
+ 36, 36, 36, 70, 43, 43, 43, 43, 43, 86, 44, 44, 44, 44, 44, 93,
+ 36, 70, 86, 43, 43, 86, 43, 86,107, 2, 2, 2, 2, 2, 2, 52,
+ 7, 7, 7, 7, 7, 44, 44, 2, 36, 36, 70, 69, 36, 36, 36, 36,
+ 7, 7, 7, 7, 7, 36, 36, 61, 36, 36, 36, 36, 70, 43, 43, 85,
+ 87, 85, 87, 80, 44, 44, 44, 44, 36, 70, 36, 36, 36, 36, 85, 44,
+ 7, 7, 7, 7, 7, 44, 2, 2, 69, 36, 36, 77, 67, 94, 85, 36,
+ 71, 43, 71, 70, 71, 36, 36, 43, 70, 61, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 62, 83, 2, 36, 36, 36, 36, 36, 94, 43, 86,
+ 2, 83,169, 80, 44, 44, 44, 44, 62, 36, 36, 61, 62, 36, 36, 61,
+ 62, 36, 36, 61, 44, 44, 44, 44, 16, 16, 16, 16, 16,114, 40, 40,
+ 16, 16, 16, 16,111, 41, 44, 44, 36, 94, 87, 86, 85,107, 87, 44,
+ 36, 36, 44, 44, 44, 44, 44, 44, 36, 36, 36, 61, 44, 62, 36, 36,
+ 170,170,170,170,170,170,170,170,171,171,171,171,171,171,171,171,
+ 16, 16, 16,110, 44, 44, 44, 44, 44,150, 16, 16, 44, 44, 62, 71,
+ 36, 36, 36, 36,172, 36, 36, 36, 36, 36, 36, 61, 36, 36, 61, 61,
+ 36, 62, 61, 36, 36, 36, 36, 36, 36, 41, 41, 41, 41, 41, 41, 41,
+ 41,117, 44, 44, 44, 44, 44, 44, 44, 62, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36,148, 44, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 44, 44, 44, 55, 36, 36, 36, 36, 36, 36,168, 67,
+ 2, 2, 2,152,130, 44, 44, 44, 6,173,174,148,148,148,148,148,
+ 148,148,130,152,130, 2,127,175, 2, 64, 2, 2,156,148,148,130,
+ 2,176, 8,177, 66, 2, 44, 44, 36, 36, 61, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 61, 79, 93, 2, 3, 2, 4, 5, 6, 2,
+ 16, 16, 16, 16, 16, 17, 18,129,130, 4, 2, 36, 36, 36, 36, 36,
+ 69, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 40,
+ 44, 36, 36, 36, 44, 36, 36, 36, 44, 36, 36, 36, 44, 36, 61, 44,
+ 20,178, 56,135, 26, 8,144, 92, 44, 44, 44, 44, 79, 65, 67, 44,
+ 36, 36, 36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 61, 36, 62,
+ 2, 64, 44,179, 27, 27, 27, 27, 27, 27, 44, 55, 67, 67, 67, 67,
+ 105,105,143, 27, 91, 67, 67, 67, 67, 67, 67, 67, 67, 27, 67, 92,
+ 67, 67, 67, 67, 67, 67, 92, 44, 92, 44, 44, 44, 44, 44, 44, 44,
+ 67, 67, 67, 67, 67, 67, 50, 44,180, 27, 27, 27, 27, 27, 27, 27,
+ 27, 27, 27, 27, 27, 27, 44, 44, 27, 27, 44, 44, 44, 44, 62, 36,
+ 155, 36, 36, 36, 36,181, 44, 44, 36, 36, 36, 43, 43, 80, 44, 44,
+ 36, 36, 36, 36, 36, 36, 36, 93, 36, 36, 44, 44, 36, 36, 36, 36,
+ 182,105,105, 44, 44, 44, 44, 44, 11, 11, 11, 11, 16, 16, 16, 16,
+ 11, 11, 44, 44, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 44, 44,
+ 36, 36, 36, 36, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44, 44, 93,
+ 11, 11, 11, 11, 11, 47, 11, 11, 11, 47, 11,150, 16, 16, 16, 16,
+ 16,150, 16, 16, 16, 16, 16, 16, 16,150, 16, 16, 16,150,110, 44,
+ 40, 40, 40, 52, 40, 40, 40, 40, 81, 40, 40, 40, 40, 81, 44, 44,
+ 36, 36, 36, 44, 61, 36, 36, 36, 36, 36, 36, 62, 61, 44, 61, 62,
+ 36, 36, 36, 93, 27, 27, 27, 27, 36, 36, 36, 77,163, 27, 27, 27,
+ 44, 44, 44,179, 27, 27, 27, 27, 36, 61, 36, 44, 44,179, 27, 27,
+ 36, 36, 36, 27, 27, 27, 44, 93, 36, 36, 36, 36, 36, 44, 44, 93,
+ 36, 36, 36, 36, 44, 44, 27, 36, 44, 27, 27, 27, 27, 27, 27, 27,
+ 70, 43, 57, 80, 44, 44, 43, 43, 36, 36, 62, 36, 62, 36, 36, 36,
+ 36, 36, 36, 44, 43, 80, 44, 57, 27, 27, 27, 27,100, 44, 44, 44,
+ 2, 2, 2, 2, 64, 44, 44, 44, 36, 36, 36, 36, 36, 36,183, 30,
+ 36, 36, 36, 36, 36, 36,183, 27, 36, 36, 36, 36, 78, 36, 36, 36,
+ 36, 36, 70, 80, 44,179, 27, 27, 2, 2, 2, 64, 44, 44, 44, 44,
+ 36, 36, 36, 44, 93, 2, 2, 2, 36, 36, 36, 44, 27, 27, 27, 27,
+ 36, 61, 44, 44, 27, 27, 27, 27, 36, 44, 44, 44, 93, 2, 64, 44,
+ 44, 44, 44, 44,179, 27, 27, 27, 11, 47, 44, 44, 44, 44, 44, 44,
+ 16,110, 44, 44, 44, 27, 27, 27, 36, 36, 43, 43, 44, 44, 44, 44,
+ 27, 27, 27, 27, 27, 27, 27,100, 36, 36, 36, 36, 36, 57,184, 44,
+ 36, 44, 44, 44, 44, 44, 44, 44, 27, 27, 27, 95, 44, 44, 44, 44,
+ 180, 27, 30, 2, 2, 44, 44, 44, 36, 43, 43, 2, 2, 44, 44, 44,
+ 36, 36,183, 27, 27, 27, 44, 44, 87, 98, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 43, 60, 2, 2, 2, 44,
+ 27, 27, 27, 7, 7, 7, 7, 7, 71, 70, 71, 44, 44, 44, 44, 57,
+ 86, 87, 43, 85, 87, 60,185, 2, 2, 80, 44, 44, 44, 44, 79, 44,
+ 43, 71, 36, 36, 36, 36, 36, 36, 36, 36, 36, 70, 43, 43, 87, 43,
+ 43, 43, 80, 7, 7, 7, 7, 7, 2, 2, 94, 98, 44, 44, 44, 44,
+ 36, 70, 2, 61, 44, 44, 44, 44, 36, 94, 86, 43, 43, 43, 43, 85,
+ 98, 36, 63, 2, 59, 43, 60, 87, 7, 7, 7, 7, 7, 63, 63, 2,
+ 179, 27, 27, 27, 27, 27, 27, 27, 27, 27,100, 44, 44, 44, 44, 44,
+ 36, 36, 36, 36, 36, 36, 86, 87, 43, 86, 85, 43, 2, 2, 2, 80,
+ 36, 36, 36, 61, 61, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 62,
+ 36, 36, 36, 36, 63, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 70,
+ 86, 87, 43, 43, 43, 80, 44, 44, 43, 86, 62, 36, 36, 36, 61, 62,
+ 61, 36, 62, 36, 36, 57, 71, 86, 85, 86, 90, 89, 90, 89, 86, 44,
+ 61, 44, 44, 89, 44, 44, 62, 36, 36, 86, 44, 43, 43, 43, 80, 44,
+ 43, 43, 80, 44, 44, 44, 44, 44, 36, 36, 94, 86, 43, 43, 43, 43,
+ 86, 43, 85, 71, 36, 63, 2, 2, 7, 7, 7, 7, 7, 2, 93, 71,
+ 86, 87, 43, 43, 85, 85, 86, 87, 85, 43, 36, 72, 44, 44, 44, 44,
+ 36, 36, 36, 36, 36, 36, 36, 94, 86, 43, 43, 44, 86, 86, 43, 87,
+ 60, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 36, 36, 43, 44,
+ 86, 87, 43, 43, 43, 85, 87, 87, 60, 2, 61, 44, 44, 44, 44, 44,
+ 2, 2, 2, 2, 2, 2, 64, 44, 36, 36, 36, 36, 36, 70, 87, 86,
+ 43, 43, 43, 87, 63, 44, 44, 44, 86, 43, 43, 87, 43, 43, 44, 44,
+ 7, 7, 7, 7, 7, 27, 2, 97, 43, 43, 43, 43, 87, 60, 44, 44,
+ 27,100, 44, 44, 44, 44, 44, 62, 36, 36, 36, 61, 62, 44, 36, 36,
+ 36, 36, 62, 61, 36, 36, 36, 36, 86, 86, 86, 89, 90, 57, 85, 71,
+ 98, 87, 2, 64, 44, 44, 44, 44, 36, 36, 36, 36, 44, 36, 36, 36,
+ 94, 86, 43, 43, 44, 43, 86, 86, 71, 72, 90, 44, 44, 44, 44, 44,
+ 70, 43, 43, 43, 43, 71, 36, 36, 36, 70, 43, 43, 85, 70, 43, 60,
+ 2, 2, 2, 59, 44, 44, 44, 44, 70, 43, 43, 85, 87, 43, 36, 36,
+ 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 85, 43, 2, 72, 2,
+ 2, 64, 44, 44, 44, 44, 44, 44, 43, 43, 43, 80, 43, 43, 43, 87,
+ 63, 2, 2, 44, 44, 44, 44, 44, 2, 36, 36, 36, 36, 36, 36, 36,
+ 44, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 89, 43, 43, 43,
+ 85, 43, 87, 80, 44, 44, 44, 44, 36, 36, 36, 61, 36, 62, 36, 36,
+ 70, 43, 43, 80, 44, 80, 43, 57, 43, 43, 43, 70, 44, 44, 44, 44,
+ 36, 36, 36, 62, 61, 36, 36, 36, 36, 36, 36, 36, 36, 86, 86, 90,
+ 43, 89, 87, 87, 61, 44, 44, 44, 36, 70, 85,107, 64, 44, 44, 44,
+ 27, 27, 91, 67, 67, 67, 56, 20,168, 67, 67, 67, 67, 67, 67, 67,
+ 67, 44, 44, 44, 44, 44, 44, 93,105,105,105,105,105,105,105,181,
+ 2, 2, 64, 44, 44, 44, 44, 44, 63, 64, 44, 44, 44, 44, 44, 44,
+ 65, 65, 65, 65,132, 44, 44, 44, 43, 43, 60, 44, 44, 44, 44, 44,
+ 43, 43, 43, 60, 2, 2, 67, 67, 40, 40, 97, 44, 44, 44, 44, 44,
+ 7, 7, 7, 7, 7,179, 27, 27, 27, 62, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 44, 44, 62, 36, 27, 27, 27, 30, 2, 64, 44, 44,
+ 36, 36, 36, 36, 36, 61, 44, 57, 94, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 44, 44, 44, 57,
+ 43, 74, 40, 40, 40, 40, 40, 40, 40, 88, 80, 44, 44, 44, 44, 44,
+ 86, 44, 44, 44, 44, 44, 44, 44, 40, 40, 52, 40, 40, 40, 52, 81,
+ 36, 61, 44, 44, 44, 44, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44,
+ 36, 36, 36, 36, 36, 44, 50, 60, 65, 65, 44, 44, 44, 44, 44, 44,
+ 43, 43, 43, 43, 43, 43, 43, 44, 43, 43, 43, 80, 44, 44, 44, 44,
+ 67, 67, 67, 92, 55, 67, 67, 67, 67, 67,186, 87, 43, 67,186, 86,
+ 86,187, 65, 65, 65, 84, 43, 43, 43, 76, 50, 43, 43, 43, 67, 67,
+ 67, 67, 67, 67, 67, 43, 43, 67, 67, 43, 76, 44, 44, 44, 44, 44,
+ 27, 27, 44, 44, 44, 44, 44, 44, 11, 11, 11, 11, 11, 16, 16, 16,
+ 16, 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 16,
+ 16, 16,110, 16, 16, 16, 16, 16, 11, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 47, 11, 44, 47, 48, 47, 48, 11, 47, 11,
+ 11, 11, 11, 16, 16,150,150, 16, 16, 16,150, 16, 16, 16, 16, 16,
+ 16, 16, 11, 48, 11, 47, 48, 11, 11, 11, 47, 11, 11, 11, 47, 16,
+ 16, 16, 16, 16, 11, 48, 11, 47, 11, 11, 47, 47, 44, 11, 11, 11,
+ 47, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 11, 11,
+ 11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 44, 11, 11, 11, 11,
+ 31, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 33, 16, 16,
+ 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 31, 16, 16,
+ 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 31, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16,
+ 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, 32, 44, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 43, 43, 43, 76, 67, 50, 43, 43,
+ 43, 43, 43, 43, 43, 43, 76, 67, 67, 67, 50, 67, 67, 67, 67, 67,
+ 67, 67, 76, 21, 2, 2, 44, 44, 44, 44, 44, 44, 44, 57, 43, 43,
+ 16, 16, 16, 16, 16, 39, 16, 16, 16, 16, 16, 16, 16, 16, 16,110,
+ 43, 43, 43, 80, 43, 43, 43, 43, 43, 43, 43, 43, 80, 57, 43, 43,
+ 43, 57, 80, 43, 43, 80, 44, 44, 43, 43, 43, 74, 40, 40, 40, 44,
+ 7, 7, 7, 7, 7, 44, 44, 77, 36, 36, 36, 36, 36, 36, 36, 80,
+ 36, 36, 36, 36, 36, 36, 43, 43, 7, 7, 7, 7, 7, 44, 44, 96,
+ 36, 36, 36, 61, 36, 36, 62, 61, 36, 36, 61,179, 27, 27, 27, 27,
+ 16, 16, 43, 43, 43, 74, 44, 44, 27, 27, 27, 27, 27, 27,163, 27,
+ 188, 27,100, 44, 44, 44, 44, 44, 27, 27, 27, 27, 27, 27, 27,163,
+ 27, 27, 27, 27, 27, 27, 27, 44, 36, 36, 62, 36, 36, 36, 36, 36,
+ 62, 61, 61, 62, 62, 36, 36, 36, 36, 61, 36, 36, 62, 62, 44, 44,
+ 44, 61, 44, 62, 62, 62, 62, 36, 62, 61, 61, 62, 62, 62, 62, 62,
+ 62, 61, 61, 62, 36, 61, 36, 36, 36, 61, 36, 36, 62, 36, 61, 61,
+ 36, 36, 36, 36, 36, 62, 36, 36, 62, 36, 62, 36, 36, 62, 36, 36,
+ 8, 44, 44, 44, 44, 44, 44, 44, 55, 67, 67, 67, 67, 67, 67, 67,
+ 27, 27, 27, 27, 27, 27, 91, 67, 67, 67, 67, 67, 67, 67, 67, 44,
+ 44, 44, 44, 67, 67, 67, 67, 67, 67, 92, 44, 44, 44, 44, 44, 44,
+ 67, 67, 67, 67, 92, 44, 44, 44, 67, 44, 44, 44, 44, 44, 44, 44,
+ 67, 67, 67, 67, 67, 25, 41, 41, 67, 67, 67, 67, 44, 44, 55, 67,
+ 67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 92, 44, 67, 67, 92, 44,
+ 67, 92, 67, 67, 67, 67, 67, 67, 79, 44, 44, 44, 44, 44, 44, 44,
+ 65, 65, 65, 65, 65, 65, 65, 65,171,171,171,171,171,171,171, 44,
+ 171,171,171,171,171,171,171, 0, 0, 0, 29, 21, 21, 21, 23, 21,
+ 22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21, 9, 9, 9,
+ 9, 22, 21, 18, 24, 16, 24, 5, 5, 5, 5, 22, 25, 18, 25, 0,
+ 23, 23, 26, 21, 24, 26, 7, 20, 25, 1, 26, 24, 26, 25, 15, 15,
+ 24, 15, 7, 19, 15, 21, 9, 25, 9, 5, 5, 25, 5, 9, 5, 7,
+ 7, 7, 9, 8, 8, 5, 7, 5, 6, 6, 24, 24, 6, 24, 12, 12,
+ 2, 2, 6, 5, 9, 21, 9, 2, 2, 9, 25, 9, 26, 12, 11, 11,
+ 2, 6, 5, 21, 17, 2, 2, 26, 26, 23, 2, 12, 17, 12, 21, 12,
+ 12, 21, 7, 2, 2, 7, 7, 21, 21, 2, 1, 1, 21, 23, 26, 26,
+ 1, 21, 6, 7, 7, 12, 12, 7, 21, 7, 12, 1, 12, 6, 6, 12,
+ 12, 26, 7, 26, 26, 7, 2, 1, 12, 2, 6, 2, 24, 7, 7, 6,
+ 1, 12, 12, 10, 10, 10, 10, 12, 21, 6, 2, 10, 10, 2, 15, 26,
+ 26, 2, 2, 21, 7, 10, 15, 7, 2, 23, 21, 26, 10, 7, 21, 15,
+ 15, 2, 17, 7, 29, 7, 7, 22, 18, 2, 14, 14, 14, 7, 10, 21,
+ 17, 21, 11, 12, 5, 2, 5, 6, 8, 8, 8, 24, 5, 24, 2, 24,
+ 9, 24, 24, 2, 29, 29, 29, 1, 17, 17, 20, 19, 22, 20, 27, 28,
+ 1, 29, 21, 20, 19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29,
+ 1, 2, 15, 6, 18, 6, 23, 2, 12, 11, 9, 26, 26, 9, 26, 5,
+ 5, 26, 14, 9, 5, 14, 14, 15, 25, 26, 26, 22, 18, 26, 18, 25,
+ 18, 22, 5, 12, 2, 5, 22, 21, 21, 22, 18, 17, 26, 6, 7, 14,
+ 17, 22, 18, 18, 26, 14, 17, 6, 14, 6, 12, 24, 24, 6, 26, 15,
+ 6, 21, 11, 21, 24, 9, 6, 9, 23, 26, 6, 10, 4, 4, 3, 3,
+ 7, 25, 17, 16, 16, 22, 16, 16, 25, 17, 25, 2, 25, 24, 2, 15,
+ 12, 15, 14, 2, 21, 14, 7, 15, 12, 17, 21, 1, 26, 10, 10, 1,
+ 23, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12,
+ 13, 0, 14, 0, 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20,
+ 0, 21, 22, 23, 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 34, 0, 35, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0,
+ 0, 0, 39, 40, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 3, 0, 0, 0, 4, 5,
+ 6, 7, 0, 8, 9, 10, 0, 11, 12, 13, 14, 15, 16, 17, 16, 18,
+ 16, 19, 16, 19, 16, 19, 0, 19, 16, 20, 16, 19, 21, 19, 0, 22,
+ 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 32, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 34, 0, 0, 35,
+ 0, 0, 36, 0, 37, 0, 0, 0, 38, 39, 40, 41, 42, 43, 44, 45,
+ 46, 0, 0, 47, 0, 0, 0, 48, 0, 0, 0, 49, 0, 0, 0, 0,
+ 0, 0, 0, 50, 0, 51, 0, 52, 53, 0, 54, 0, 0, 0, 0, 0,
+ 0, 55, 56, 57, 0, 0, 0, 0, 58, 0, 0, 59, 60, 61, 62, 63,
+ 0, 0, 64, 65, 0, 0, 0, 66, 0, 0, 0, 0, 67, 0, 0, 0,
+ 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69,
+ 0, 0, 0, 70, 0, 71, 0, 0, 72, 0, 0, 73, 0, 0, 0, 0,
+ 0, 0, 0, 0, 74, 0, 0, 0, 0, 0, 75, 0, 0, 76, 77, 0,
+ 0, 78, 79, 0, 80, 62, 0, 81, 82, 0, 0, 83, 84, 85, 0, 0,
+ 0, 86, 0, 87, 0, 0, 51, 88, 51, 0, 89, 0, 90, 0, 0, 0,
+ 79, 0, 0, 0, 91, 92, 0, 93, 94, 95, 96, 0, 0, 0, 0, 0,
+ 51, 0, 0, 0, 0, 97, 98, 0, 0, 0, 0, 99,100, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,101, 0, 0,102, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,103,104, 0, 0,105, 0, 0, 0, 0, 0, 0,
+ 106, 0, 0, 0,100, 0, 0, 0, 0, 0,107,108, 0, 0, 0, 0,
+ 0, 0, 0,109, 0,110, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
+ 5, 6, 7, 0, 8, 0, 0, 0, 0, 9, 10, 11, 12, 0, 0, 0,
+ 0, 13, 0, 0, 14, 15, 0, 16, 0, 17, 18, 0, 0, 19, 0, 20,
+ 21, 0, 0, 0, 0, 0, 22, 23, 0, 24, 25, 0, 0, 26, 0, 0,
+ 0, 27, 0, 0, 28, 29, 30, 31, 0, 0, 0, 32, 33, 34, 0, 0,
+ 33, 0, 0, 35, 33, 0, 0, 0, 33, 36, 0, 0, 0, 0, 0, 37,
+ 38, 0, 0, 0, 0, 0, 0, 39, 40, 0, 0, 0, 0, 0, 0, 41,
+ 42, 0, 0, 0, 0, 43, 0, 44, 0, 0, 0, 45, 46, 0, 0, 0,
+ 47, 0, 0, 0, 0, 0, 0, 48, 49, 0, 0, 0, 0, 50, 0, 0,
+ 0, 51, 0, 52, 0, 53, 0, 0, 0, 0, 54, 0, 0, 0, 0, 55,
+ 0, 56, 0, 0, 0, 0, 57, 58, 0, 0, 0, 59, 60, 0, 0, 0,
+ 0, 0, 0, 61, 52, 0, 62, 63, 0, 0, 64, 0, 0, 0, 65, 66,
+ 0, 0, 0, 67, 0, 68, 69, 70, 71, 72, 1, 73, 0, 74, 75, 76,
+ 0, 0, 77, 78, 0, 0, 0, 79, 0, 0, 1, 1, 0, 0, 80, 0,
+ 0, 81, 0, 0, 0, 0, 77, 82, 0, 83, 0, 0, 0, 0, 0, 78,
+ 84, 0, 85, 0, 52, 0, 1, 78, 0, 0, 86, 0, 0, 87, 0, 0,
+ 0, 0, 0, 88, 57, 0, 0, 0, 0, 0, 0, 89, 90, 0, 0, 84,
+ 0, 0, 33, 0, 0, 91, 0, 0, 0, 0, 92, 0, 0, 0, 0, 49,
+ 0, 0, 93, 0, 0, 0, 0, 94, 95, 0, 0, 96, 0, 0, 97, 0,
+ 0, 0, 98, 0, 0, 0, 99, 0,100, 93, 0, 0,101, 0, 0, 0,
+ 84, 0, 0,102, 0, 0, 0,103,104, 0, 0,105,106, 0, 0, 0,
+ 0, 0, 0,107, 0, 0,108, 0, 0, 0, 0,109, 33, 0,110,111,
+ 112, 35, 0, 0,113, 0, 0, 0,114, 0, 0, 0, 0, 0, 0,115,
+ 0, 0,116, 0, 0, 0, 0,117, 88, 0, 0, 0, 0, 0, 57, 0,
+ 0, 0, 0, 52,118, 0, 0, 0, 0,119, 0, 0,120, 0, 0, 0,
+ 0,118, 0, 0, 0, 0, 0,121, 0, 0, 0,122, 0, 0, 0,123,
+ 0,124, 0, 0, 0, 0,125,126,127, 0,128, 0,129, 0, 0, 0,
+ 130,131,132, 0, 0, 0, 35, 0, 0, 0,133, 0, 0,134, 0, 0,
+ 135, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 4,
+ 5, 6, 7, 4, 4, 8, 9, 10, 1, 11, 12, 13, 14, 15, 16, 17,
+ 18, 1, 1, 1, 19, 1, 0, 0, 20, 21, 22, 1, 23, 4, 21, 24,
+ 25, 26, 27, 28, 29, 30, 0, 0, 1, 1, 31, 0, 0, 0, 32, 33,
+ 34, 35, 1, 36, 37, 0, 0, 0, 0, 38, 1, 39, 14, 39, 40, 41,
+ 42, 0, 0, 0, 43, 36, 44, 45, 21, 45, 46, 0, 0, 0, 19, 1,
+ 21, 0, 0, 47, 0, 38, 48, 1, 1, 49, 49, 50, 0, 0, 51, 0,
+ 0, 0, 52, 1, 0, 0, 38, 14, 4, 1, 1, 1, 53, 21, 43, 52,
+ 54, 21, 35, 1, 0, 0, 0, 55, 0, 0, 0, 56, 57, 58, 0, 0,
+ 0, 0, 0, 59, 0, 60, 0, 0, 0, 0, 61, 62, 0, 0, 63, 0,
+ 0, 0, 64, 0, 0, 0, 65, 0, 0, 0, 66, 0, 0, 0, 67, 0,
+ 0, 0, 68, 0, 0, 69, 70, 0, 71, 72, 73, 74, 75, 76, 0, 0,
+ 0, 77, 0, 0, 0, 78, 79, 0, 0, 0, 0, 47, 0, 0, 0, 49,
+ 0, 80, 0, 0, 0, 62, 0, 0, 63, 0, 0, 81, 0, 0, 82, 0,
+ 0, 0, 83, 0, 0, 19, 84, 0, 62, 0, 0, 0, 0, 49, 1, 85,
+ 1, 52, 15, 86, 36, 10, 21, 87, 0, 55, 0, 0, 0, 0, 19, 10,
+ 1, 0, 0, 0, 0, 0, 88, 0, 0, 89, 0, 0, 88, 0, 0, 0,
+ 0, 78, 0, 0, 87, 9, 12, 4, 90, 8, 91, 47, 0, 58, 50, 0,
+ 21, 1, 21, 92, 93, 1, 1, 1, 1, 94, 95, 96, 97, 1, 98, 58,
+ 81, 99,100, 4, 58, 0, 0, 0, 0, 0, 0, 19, 50, 0, 0, 0,
+ 0, 0, 0, 61, 0, 0,101,102, 0, 0,103, 0, 0, 1, 1, 50,
+ 0, 0, 0, 38, 0, 63, 0, 0, 0, 0, 0, 62, 0, 0,104, 68,
+ 61, 0, 0, 0, 78, 0, 0, 0,105,106, 58, 38, 81, 0, 0, 0,
+ 0, 0, 0,107, 1, 14, 4, 12, 84, 0, 0, 0, 0, 38, 87, 0,
+ 0, 0, 0,108, 0, 0,109, 61, 0,110, 0, 0, 0, 1, 0, 0,
+ 0, 0, 19, 58, 0,111, 14, 52,112, 41, 0, 0, 62, 0, 0, 61,
+ 0, 0,113, 0, 87, 0, 0, 0, 61, 62, 0, 0, 62, 0, 89, 0,
+ 0,113, 0, 0, 0, 0,114, 0, 0, 0, 78, 55, 0, 38, 1, 58,
+ 1, 58, 0, 0, 63, 89, 0, 0,115, 0, 0, 0, 55, 0, 0, 0,
+ 0,115, 0, 0, 0, 0, 61, 0, 0, 0, 0, 79, 0, 61, 0, 0,
+ 0, 0, 56, 0, 89, 80, 0, 0, 8, 91, 0, 0, 1, 87, 0, 0,
+ 116, 0, 0, 0, 0, 0, 0,117, 0,118,119,120,121, 0,104, 4,
+ 122, 49, 23, 0, 0, 0, 38, 50, 38, 58, 0, 0, 1, 87, 1, 1,
+ 1, 1, 39, 1, 48,105, 87, 0, 0, 0, 0, 1, 4,122, 0, 0,
+ 0, 1,123, 0, 0, 0, 0, 0,230,230,230,230,230,232,220,220,
+ 220,220,232,216,220,220,220,220,220,202,202,220,220,220,220,202,
+ 202,220,220,220, 1, 1, 1, 1, 1,220,220,220,220,230,230,230,
+ 230,240,230,220,220,220,230,230,230,220,220, 0,230,230,230,220,
+ 220,220,220,230,232,220,220,230,233,234,234,233,234,234,233,230,
+ 0, 0, 0,230, 0,220,230,230,230,230,220,230,230,230,222,220,
+ 230,230,220,220,230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 19, 20, 21, 22, 0, 23, 0, 24, 25, 0,230,220, 0, 18,
+ 30, 31, 32, 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34,230,
+ 230,220,220,230,220,230,230,220, 35, 0, 0, 0, 0, 0,230,230,
+ 230, 0, 0,230,230, 0,220,230,230,220, 0, 0, 0, 36, 0, 0,
+ 230,220,230,230,220,220,230,220,220,230,220,230,220,230,230, 0,
+ 0,220, 0, 0,230,230, 0,230, 0,230,230,230,230,230, 0, 0,
+ 0,220,220,220,230,220,220,220,230,230, 0,220, 27, 28, 29,230,
+ 7, 0, 0, 0, 0, 9, 0, 0, 0,230,220,230,230, 0, 0, 0,
+ 0, 0,230, 0, 0, 84, 91, 0, 0, 0, 0, 9, 9, 0, 0, 0,
+ 0, 0, 9, 0,103,103, 9, 0,107,107,107,107,118,118, 9, 0,
+ 122,122,122,122,220,220, 0, 0, 0,220, 0,220, 0,216, 0, 0,
+ 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130,130,130, 0, 0,
+ 130, 0,230,230, 9, 0,230,230, 0, 0,220, 0, 0, 0, 0, 7,
+ 0, 9, 9, 0, 9, 9, 0, 0, 0,230, 0, 0, 0,228, 0, 0,
+ 0,222,230,220,220, 0, 0, 0,230, 0, 0,220,230,220, 0,220,
+ 230,230,230, 0, 0, 0, 9, 9, 0, 0, 7, 0,230, 0, 1, 1,
+ 1, 0, 0, 0,230,234,214,220,202,230,230,230,230,230,232,228,
+ 228,220,218,230,233,220,230,220,230,230, 1, 1, 1, 1, 1,230,
+ 0, 1, 1,230,220,230, 1, 1, 0, 0,218,228,232,222,224,224,
+ 0, 8, 8, 0, 0, 0, 0,220,230, 0,230,230,220, 0, 0,230,
+ 0, 0, 26, 0, 0,220, 0,230,230, 1,220, 0, 0,230,220, 0,
+ 0, 0,220,220, 0, 0,230,220, 0, 9, 7, 0, 0, 7, 9, 0,
+ 0, 0, 9, 7, 6, 6, 0, 0, 0, 0, 1, 0, 0,216,216, 1,
+ 1, 1, 0, 0, 0,226,216,216,216,216,216, 0,220,220,220, 0,
+ 230,230, 7, 0, 16, 17, 17, 17, 17, 17, 17, 33, 17, 17, 17, 19,
+ 17, 17, 17, 17, 20,101, 17,113,129,169, 17, 27, 28, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17,237, 0, 1, 2, 2, 0, 3, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 5, 0, 0, 0, 0, 6, 7, 8, 9, 0, 0, 0, 10, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20,
+ 0, 0, 21, 22, 0, 0, 0, 0, 23, 24, 25, 26, 0, 27, 0, 28,
+ 29, 30, 31, 32, 0, 0, 0, 0, 0, 0, 0, 33, 34, 35, 36, 0,
+ 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 39,
+ 0, 0, 0, 0, 1, 2, 40, 41, 0, 1, 2, 2, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0,
+ 0, 0, 3, 4, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 0, 0,
+ 0, 0, 7, 1, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0,
+ 0, 0, 10, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 11, 12,
+ 0, 13, 0, 14, 15, 16, 0, 0, 0, 0, 0, 1, 17, 18, 0, 19,
+ 7, 1, 0, 0, 0, 20, 20, 7, 20, 20, 20, 20, 20, 20, 20, 8,
+ 21, 0, 22, 0, 7, 23, 24, 0, 20, 20, 25, 0, 0, 0, 26, 27,
+ 1, 7, 20, 20, 20, 20, 20, 1, 28, 29, 30, 31, 0, 0, 20, 0,
+ 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 20, 20,
+ 20, 1, 0, 0, 8, 21, 32, 4, 0, 10, 0, 33, 7, 20, 20, 20,
+ 0, 0, 0, 0, 8, 34, 34, 35, 36, 34, 37, 0, 38, 1, 20, 20,
+ 0, 0, 39, 0, 1, 1, 0, 8, 21, 1, 20, 0, 0, 0, 1, 0,
+ 0, 40, 1, 1, 0, 0, 8, 21, 0, 1, 0, 1, 0, 1, 0, 0,
+ 0, 0, 26, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 7, 20, 41,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 0, 42, 43, 44, 0, 45,
+ 0, 8, 21, 0, 0, 0, 0, 0, 0, 0, 0, 46, 7, 1, 10, 1,
+ 0, 0, 0, 1, 20, 20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 26, 34, 9, 0, 0, 20, 20, 1, 20, 20, 0, 0, 0, 0, 0,
+ 0, 0, 26, 21, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 3, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3,
+ 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 9, 10, 11, 11, 11, 11, 12, 13, 13, 13, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 13, 22, 13, 13, 13, 13, 23, 24, 24, 25, 26, 13, 13,
+ 13, 27, 28, 29, 13, 30, 31, 32, 33, 34, 35, 36, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 37, 7, 38, 39, 7, 40, 7, 7, 7, 41, 13, 42, 7, 7, 43, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 44, 0, 0, 1,
+ 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 32, 33, 34, 35, 36, 37, 37, 37, 37, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 2, 2, 53, 54, 55, 56,
+ 57, 58, 59, 59, 59, 59, 60, 59, 59, 59, 59, 59, 59, 59, 61, 61,
+ 59, 59, 59, 59, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
+ 74, 75, 76, 77, 78, 59, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 79, 70, 70, 70, 70, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 81, 82, 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 95, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 70, 70, 97, 98, 99,100,101,101,102,103,104,105,106,107,108,109,
+ 110,111, 96,112,113,114,115,116,117,118,119,119,120,121,122,123,
+ 124,125,126,127,128,129,130,131,132, 96,133,134,135,136,137,138,
+ 139,140,141,142,143, 96,144,145, 96,146,147,148,149, 96,150,151,
+ 152,153,154,155, 96, 96,156,157,158,159, 96,160, 96,161,162,162,
+ 162,162,162,162,162,163,164,162,165, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,166,167,167,
+ 167,167,167,167,167,167,168, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96,169,169,169,169,170, 96, 96, 96,171,171,
+ 171,171,172,173,174,175, 96, 96, 96, 96,176,177,178,179,180,180,
+ 180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,
+ 180,180,180,180,180,180,180,180,180,180,180,180,180,181,180,180,
+ 180,180,180,180,182,182,182,183,184, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,185,186,187,
+ 188,189,189,190, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96,191,192, 96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96,193,194, 59,195,
+ 196,197,198,199,200, 96,201,202,203, 59, 59,204, 59,205,206,206,
+ 206,206,206,207, 96, 96, 96, 96, 96, 96, 96, 96,208, 96,209, 96,
+ 210, 96, 96,211, 96, 96, 96, 96, 96, 96, 96, 96, 96,212,213,214,
+ 215, 96, 96, 96, 96, 96,216,217,218, 96,219,220, 96, 96,221,222,
+ 59,223,224, 96, 59, 59, 59, 59, 59, 59, 59,225,226,227,228,229,
+ 59, 59,230,231, 59,232, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,233, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,234, 70,235, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,236, 70, 70, 70, 70,
+ 70, 70, 70, 70, 70,237, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
+ 70, 70,238, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 70, 70,
+ 70, 70, 70, 70,239, 96, 96, 96, 96, 96, 96, 96, 96, 96,240, 96,
+ 241,242, 0, 1, 2, 2, 0, 1, 2, 2, 2, 3, 4, 5, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0,
+ 19, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 0, 19, 0,
+ 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0,
+ 26, 26, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9,
+ 9, 9, 0, 9, 9, 9, 2, 2, 9, 9, 9, 9, 0, 9, 2, 2,
+ 2, 2, 9, 0, 9, 0, 9, 9, 9, 2, 9, 2, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9,
+ 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 6, 2, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 2, 4, 4, 4, 2, 2, 4, 4, 4, 2, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 2,
+ 2, 2, 2, 2, 2, 2, 14, 14, 14, 2, 2, 2, 2, 14, 14, 14,
+ 14, 14, 14, 2, 2, 2, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3,
+ 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 0, 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 3,
+ 3, 3, 3, 3, 3, 3, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 2, 37, 37, 37, 37, 2, 2, 37, 37, 37, 38, 38,
+ 38, 38, 38, 38, 38, 38, 38, 38, 2, 2, 2, 2, 2, 2, 64, 64,
+ 64, 64, 64, 64, 64, 64, 64, 64, 64, 2, 2, 64, 64, 64, 90, 90,
+ 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 2, 2, 90, 90,
+ 90, 90, 90, 90, 90, 2, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+ 95, 95, 2, 2, 95, 2, 37, 37, 37, 2, 2, 2, 2, 2, 3, 3,
+ 3, 3, 3, 3, 3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3,
+ 0, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1,
+ 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7, 5, 5,
+ 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 5, 5, 2,
+ 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2,
+ 5, 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2, 5, 5, 5, 5,
+ 2, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 2, 2, 2,
+ 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 5, 5, 2, 5, 5, 5,
+ 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 11,
+ 11, 11, 2, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 11, 11, 2,
+ 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2,
+ 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, 11, 11, 2, 11, 11,
+ 2, 2, 11, 2, 11, 11, 11, 2, 2, 11, 11, 11, 2, 2, 2, 11,
+ 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, 2, 11, 2, 2, 2,
+ 2, 2, 2, 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 10,
+ 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10,
+ 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2,
+ 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 10, 10, 10, 10, 10,
+ 2, 2, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, 2, 2, 10, 2,
+ 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10,
+ 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 2, 21,
+ 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2,
+ 2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2,
+ 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 2, 21, 21, 21, 21, 21,
+ 2, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 2, 2, 2, 2,
+ 2, 2, 2, 21, 21, 21, 2, 2, 2, 2, 21, 21, 2, 21, 21, 21,
+ 21, 21, 2, 2, 21, 21, 2, 2, 22, 22, 2, 22, 22, 22, 22, 22,
+ 22, 2, 2, 2, 22, 22, 22, 2, 22, 22, 22, 22, 2, 2, 2, 22,
+ 22, 2, 22, 2, 22, 22, 2, 2, 2, 22, 22, 2, 2, 2, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 2, 2, 2, 2, 22, 22, 22, 2,
+ 2, 2, 2, 2, 2, 22, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22,
+ 22, 2, 2, 2, 2, 2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 2, 23, 23, 23, 2, 23, 23, 23, 23, 23, 23, 23, 23,
+ 2, 2, 23, 23, 23, 23, 23, 2, 23, 23, 23, 23, 2, 2, 2, 2,
+ 2, 2, 2, 23, 23, 2, 23, 23, 23, 2, 2, 23, 2, 2, 23, 23,
+ 23, 23, 2, 2, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 2,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 16,
+ 2, 2, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 2, 2, 2, 2,
+ 2, 2, 2, 16, 16, 2, 16, 16, 16, 16, 2, 2, 16, 16, 2, 16,
+ 16, 2, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 2, 20, 20, 20, 2, 20, 20, 20, 20, 20, 20, 2, 2,
+ 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 2, 2, 20, 20, 2, 36,
+ 36, 36, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 2, 2, 2, 36, 36, 36, 36, 36, 36, 36, 36,
+ 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2, 2,
+ 36, 2, 2, 2, 2, 36, 36, 36, 36, 36, 36, 2, 36, 2, 2, 2,
+ 2, 2, 2, 2, 36, 36, 2, 2, 36, 36, 36, 2, 2, 2, 2, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 2, 2, 2, 2, 0, 24, 24, 24, 24, 2, 2, 2, 2, 2, 18,
+ 18, 2, 18, 2, 18, 18, 18, 18, 18, 2, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, 18,
+ 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18,
+ 2, 2, 18, 18, 18, 18, 25, 25, 25, 25, 25, 25, 25, 25, 2, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 2, 2, 2, 25, 25,
+ 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 0, 0, 0, 0, 25,
+ 25, 2, 2, 2, 2, 2, 33, 33, 33, 33, 33, 33, 33, 33, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 2, 8, 2, 2,
+ 2, 2, 2, 8, 2, 2, 8, 8, 8, 0, 8, 8, 8, 8, 12, 12,
+ 12, 12, 12, 12, 12, 12, 30, 30, 30, 30, 30, 30, 30, 30, 30, 2,
+ 30, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 2, 30, 30,
+ 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 30, 2, 2, 2, 30, 30,
+ 2, 2, 2, 2, 2, 2, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+ 29, 29, 29, 29, 2, 2, 28, 28, 28, 28, 28, 28, 28, 28, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 2, 2, 2, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 0, 0, 0, 35, 35, 35, 2,
+ 2, 2, 2, 2, 2, 2, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 2, 2, 2, 2, 2, 2, 2, 2, 2, 45, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 2, 43, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 2, 2, 2, 2, 46, 46,
+ 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 2, 46, 46, 46, 2,
+ 46, 46, 2, 2, 2, 2, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 2, 2, 31, 31, 2, 2, 2, 2, 2, 2, 32, 32,
+ 0, 0, 32, 0, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, 2, 2, 2, 32, 32,
+ 32, 2, 2, 2, 2, 2, 28, 28, 28, 28, 28, 28, 2, 2, 48, 48,
+ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 2, 48, 48,
+ 48, 48, 2, 2, 2, 2, 48, 2, 2, 2, 48, 48, 48, 48, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 2, 2, 52, 52,
+ 52, 52, 52, 2, 2, 2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58,
+ 58, 58, 2, 2, 2, 2, 58, 58, 2, 2, 2, 2, 2, 2, 58, 58,
+ 58, 2, 2, 2, 58, 58, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,
+ 54, 54, 2, 2, 54, 54, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91,
+ 91, 91, 91, 91, 91, 2, 91, 91, 91, 91, 91, 2, 2, 91, 91, 91,
+ 2, 2, 2, 2, 2, 2, 91, 91, 91, 91, 91, 91, 2, 2, 1, 1,
+ 1, 1, 1, 1, 1, 2, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+ 62, 62, 62, 2, 2, 2, 62, 62, 62, 62, 62, 62, 62, 2, 76, 76,
+ 76, 76, 76, 76, 76, 76, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 2, 2, 2, 2, 2, 2, 2, 2, 93, 93, 93, 93, 70, 70,
+ 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 70, 70, 70, 70,
+ 2, 2, 2, 70, 70, 70, 73, 73, 73, 73, 73, 73, 73, 73, 6, 2,
+ 2, 2, 2, 2, 2, 2, 8, 8, 8, 2, 2, 8, 8, 8, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1,
+ 0, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9,
+ 9, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9, 9,
+ 19, 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, 19, 6, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 9, 9,
+ 9, 9, 9, 9, 2, 2, 2, 9, 2, 9, 2, 9, 2, 9, 9, 9,
+ 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 2, 2, 9, 9, 9, 9,
+ 9, 9, 2, 9, 9, 9, 2, 2, 9, 9, 9, 2, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 2, 0, 0, 0, 19, 2, 2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 2, 19, 19,
+ 19, 19, 19, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, 2,
+ 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0,
+ 19, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 19, 0,
+ 0, 0, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 27, 27,
+ 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0,
+ 0, 0, 0, 0, 2, 0, 56, 56, 56, 56, 56, 56, 56, 56, 55, 55,
+ 55, 55, 2, 2, 2, 2, 2, 55, 55, 55, 55, 55, 55, 55, 61, 61,
+ 61, 61, 61, 61, 61, 61, 2, 2, 2, 2, 2, 2, 2, 61, 61, 2,
+ 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 2, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 2, 2, 0, 0,
+ 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 13, 0, 13, 0, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, 13, 13,
+ 13, 13, 0, 0, 0, 0, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 1,
+ 1, 0, 0, 15, 15, 15, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 17, 17, 17, 2, 2,
+ 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 12, 12,
+ 12, 12, 12, 12, 12, 0, 17, 17, 17, 17, 17, 17, 17, 0, 39, 39,
+ 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 2, 2, 2, 39, 39,
+ 39, 39, 39, 39, 39, 2, 86, 86, 86, 86, 86, 86, 86, 86, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 2, 2, 2, 2, 79, 79,
+ 79, 79, 79, 79, 79, 79, 0, 0, 19, 19, 19, 19, 19, 19, 0, 0,
+ 0, 19, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2, 2, 2, 19, 19,
+ 2, 19, 2, 19, 19, 19, 19, 19, 2, 2, 2, 2, 2, 2, 2, 2,
+ 19, 19, 19, 19, 19, 19, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60,
+ 60, 60, 60, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 65, 65,
+ 65, 65, 65, 65, 65, 65, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75,
+ 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 2, 2, 75, 75, 75, 75,
+ 2, 2, 2, 2, 2, 2, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74,
+ 74, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 74, 12, 12,
+ 12, 12, 12, 2, 2, 2, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+ 84, 84, 84, 84, 2, 0, 84, 84, 2, 2, 2, 2, 84, 84, 33, 33,
+ 33, 33, 33, 33, 33, 2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 2, 68, 68, 68, 68, 68, 68, 2, 2, 68, 68,
+ 2, 2, 68, 68, 68, 68, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
+ 92, 2, 2, 2, 2, 2, 2, 2, 2, 92, 92, 92, 92, 92, 87, 87,
+ 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 2, 2, 30,
+ 30, 30, 30, 30, 30, 2, 19, 19, 19, 0, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 9, 19, 19, 19, 19, 0, 0, 2, 2, 2, 2, 87, 87,
+ 87, 87, 87, 87, 2, 2, 87, 87, 2, 2, 2, 2, 2, 2, 12, 12,
+ 12, 12, 2, 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 12, 13, 13,
+ 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2,
+ 2, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 2, 14, 14, 14, 14, 14, 2, 14, 2, 14, 14,
+ 2, 14, 14, 2, 14, 14, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2,
+ 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 2, 2,
+ 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 1, 1,
+ 1, 1, 1, 1, 6, 6, 0, 0, 0, 2, 0, 0, 0, 0, 3, 3,
+ 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 0, 2, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17,
+ 17, 17, 17, 17, 0, 0, 2, 2, 12, 12, 12, 12, 12, 12, 2, 2,
+ 12, 12, 12, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 49, 49,
+ 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49, 49, 49, 49,
+ 49, 49, 49, 49, 49, 2, 49, 49, 49, 2, 49, 49, 2, 49, 49, 49,
+ 49, 49, 49, 49, 2, 2, 49, 49, 49, 2, 2, 2, 2, 2, 0, 0,
+ 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0,
+ 0, 0, 0, 2, 2, 2, 9, 2, 2, 2, 2, 2, 2, 2, 0, 0,
+ 0, 0, 0, 1, 2, 2, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
+ 71, 71, 71, 2, 2, 2, 67, 67, 67, 67, 67, 67, 67, 67, 67, 2,
+ 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 42, 42,
+ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 42, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
+ 41, 2, 2, 2, 2, 2,118,118,118,118,118,118,118,118,118,118,
+ 118, 2, 2, 2, 2, 2, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53,
+ 53, 53, 53, 53, 2, 53, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59,
+ 59, 59, 2, 2, 2, 2, 59, 59, 59, 59, 59, 59, 2, 2, 40, 40,
+ 40, 40, 40, 40, 40, 40, 51, 51, 51, 51, 51, 51, 51, 51, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 2, 2, 50, 50,
+ 2, 2, 2, 2, 2, 2,135,135,135,135,135,135,135,135,135,135,
+ 135,135, 2, 2, 2, 2,106,106,106,106,106,106,106,106,104,104,
+ 104,104,104,104,104,104,104,104,104,104, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2,104,161,161,161,161,161,161,161,161,161,161,
+ 161, 2,161,161,161,161,161,161,161, 2,161,161, 2,161,161,161,
+ 2,161,161,161,161,161,161,161, 2,161,161, 2, 2, 2,110,110,
+ 110,110,110,110,110,110,110,110,110,110,110,110,110, 2,110,110,
+ 110,110,110,110, 2, 2, 19, 19, 19, 19, 19, 19, 2, 19, 19, 2,
+ 19, 19, 19, 19, 19, 19, 47, 47, 47, 47, 47, 47, 2, 2, 47, 2,
+ 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 2, 47, 47, 2, 2, 2, 47, 2, 2, 47, 81, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 2, 81,120,120,
+ 120,120,120,120,120,120,116,116,116,116,116,116,116,116,116,116,
+ 116,116,116,116,116, 2, 2, 2, 2, 2, 2, 2, 2,116,128,128,
+ 128,128,128,128,128,128,128,128,128, 2,128,128, 2, 2, 2, 2,
+ 2,128,128,128,128,128, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 2, 2, 2, 66, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+ 2, 2, 2, 2, 2, 72, 98, 98, 98, 98, 98, 98, 98, 98, 97, 97,
+ 97, 97, 97, 97, 97, 97, 2, 2, 2, 2, 97, 97, 97, 97, 2, 2,
+ 97, 97, 97, 97, 97, 97, 57, 57, 57, 57, 2, 57, 57, 2, 2, 2,
+ 2, 2, 57, 57, 57, 57, 57, 57, 57, 57, 2, 57, 57, 57, 2, 57,
+ 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+ 57, 57, 57, 57, 2, 2, 57, 57, 57, 2, 2, 2, 2, 57, 57, 2,
+ 2, 2, 2, 2, 2, 2, 88, 88, 88, 88, 88, 88, 88, 88,117,117,
+ 117,117,117,117,117,117,112,112,112,112,112,112,112,112,112,112,
+ 112,112,112,112,112, 2, 2, 2, 2,112,112,112,112,112, 78, 78,
+ 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 2, 2, 2, 78,
+ 78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83,
+ 83, 83, 83, 83, 2, 2, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
+ 82, 2, 2, 2, 2, 2,122,122,122,122,122,122,122,122,122,122,
+ 2, 2, 2, 2, 2, 2, 2,122,122,122,122, 2, 2, 2, 2,122,
+ 122,122,122,122,122,122, 89, 89, 89, 89, 89, 89, 89, 89, 89, 2,
+ 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,130,130,130,130,
+ 130, 2, 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,144,144,
+ 144,144,144,144,144,144,144,144, 2, 2, 2, 2, 2, 2,156,156,
+ 156,156,156,156,156,156,156,156, 2,156,156,156, 2, 2,156,156,
+ 2, 2, 2, 2, 2, 2,147,147,147,147,147,147,147,147,148,148,
+ 148,148,148,148,148,148,148,148, 2, 2, 2, 2, 2, 2,158,158,
+ 158,158,158,158,158,158,158,158, 2, 2, 2, 2, 2, 2,153,153,
+ 153,153,153,153,153,153,153,153,153,153, 2, 2, 2, 2,149,149,
+ 149,149,149,149,149,149,149,149,149,149,149,149,149, 2, 94, 94,
+ 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 2, 2, 2, 2,
+ 94, 94, 94, 94, 94, 94, 2, 2, 2, 2, 2, 2, 2, 94, 85, 85,
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 85, 2, 2,101,101,101,101,101,101,101,101,101, 2,
+ 2, 2, 2, 2, 2, 2,101,101, 2, 2, 2, 2, 2, 2, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 2, 96, 96,111,111,
+ 111,111,111,111,111,111,111,111,111,111,111,111,111, 2,100,100,
+ 100,100,100,100,100,100, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 2, 2, 2,108,108,108,108,108,108,108,108,108,108,
+ 2,108,108,108,108,108,108,108,108,108,108,108,108, 2,129,129,
+ 129,129,129,129,129, 2,129, 2,129,129,129,129, 2,129,129,129,
+ 129,129,129,129,129,129,129,129,129,129,129,129, 2,129,129,129,
+ 2, 2, 2, 2, 2, 2,109,109,109,109,109,109,109,109,109,109,
+ 109, 2, 2, 2, 2, 2,109,109, 2, 2, 2, 2, 2, 2,107,107,
+ 107,107, 2,107,107,107,107,107,107,107,107, 2, 2,107,107, 2,
+ 2,107,107,107,107,107,107,107,107,107,107,107,107,107,107, 2,
+ 107,107,107,107,107,107,107, 2,107,107, 2,107,107,107,107,107,
+ 2, 1,107,107,107,107,107, 2, 2,107,107,107, 2, 2,107, 2,
+ 2, 2, 2, 2, 2,107, 2, 2, 2, 2, 2,107,107,107,107,107,
+ 107,107, 2, 2,107,107,107,107,107,107,107, 2, 2, 2,137,137,
+ 137,137,137,137,137,137,137,137,137,137, 2,137,137,137,137,137,
+ 2, 2, 2, 2, 2, 2,124,124,124,124,124,124,124,124,124,124,
+ 2, 2, 2, 2, 2, 2,123,123,123,123,123,123,123,123,123,123,
+ 123,123,123,123, 2, 2,114,114,114,114,114,114,114,114,114,114,
+ 114,114,114, 2, 2, 2,114,114, 2, 2, 2, 2, 2, 2, 32, 32,
+ 32, 32, 32, 2, 2, 2,102,102,102,102,102,102,102,102,102,102,
+ 2, 2, 2, 2, 2, 2,126,126,126,126,126,126,126,126,126,126,
+ 126, 2, 2,126,126,126,126,126,126,126, 2, 2, 2, 2,126,126,
+ 126,126,126,126,126, 2,142,142,142,142,142,142,142,142,142,142,
+ 142,142, 2, 2, 2, 2,125,125,125,125,125,125,125,125,125,125,
+ 125, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,125,154,154,
+ 154,154,154,154,154, 2, 2,154, 2, 2,154,154,154,154,154,154,
+ 154,154, 2,154,154, 2,154,154,154,154,154,154,154,154,154,154,
+ 154,154,154,154, 2,154,154, 2, 2,154,154,154,154,154,154,154,
+ 2, 2, 2, 2, 2, 2,150,150,150,150,150,150,150,150, 2, 2,
+ 150,150,150,150,150,150,150,150,150,150,150, 2, 2, 2,141,141,
+ 141,141,141,141,141,141,140,140,140,140,140,140,140,140,140,140,
+ 140, 2, 2, 2, 2, 2,121,121,121,121,121,121,121,121,121, 2,
+ 2, 2, 2, 2, 2, 2,133,133,133,133,133,133,133,133,133, 2,
+ 133,133,133,133,133,133,133,133,133,133,133,133,133, 2,133,133,
+ 133,133,133,133, 2, 2,133,133,133,133,133, 2, 2, 2,134,134,
+ 134,134,134,134,134,134, 2, 2,134,134,134,134,134,134, 2,134,
+ 134,134,134,134,134,134,134,134,134,134,134,134,134, 2,138,138,
+ 138,138,138,138,138, 2,138,138, 2,138,138,138,138,138,138,138,
+ 138,138,138,138,138,138, 2, 2,138, 2,138,138, 2,138,138,138,
+ 2, 2, 2, 2, 2, 2,143,143,143,143,143,143, 2,143,143, 2,
+ 143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,
+ 143,143,143,143,143, 2,143,143, 2,143,143,143,143,143,143, 2,
+ 2, 2, 2, 2, 2, 2,143,143, 2, 2, 2, 2, 2, 2,145,145,
+ 145,145,145,145,145,145,145, 2, 2, 2, 2, 2, 2, 2, 86, 2,
+ 2, 2, 2, 2, 2, 2, 22, 22, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 22, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 63, 63, 63, 2, 63, 63,
+ 63, 63, 63, 2, 2, 2, 63, 63, 63, 63, 2, 2, 2, 2,157,157,
+ 157,157,157,157,157,157,157,157,157, 2, 2, 2, 2, 2, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 2, 80, 2,
+ 2, 2, 2, 2, 2, 2,127,127,127,127,127,127,127,127,127,127,
+ 127,127,127,127,127, 2, 79, 2, 2, 2, 2, 2, 2, 2,115,115,
+ 115,115,115,115,115,115,115,115,115,115,115,115,115, 2,115,115,
+ 2, 2, 2, 2,115,115,159,159,159,159,159,159,159,159,159,159,
+ 159,159,159,159,159, 2,159,159, 2, 2, 2, 2, 2, 2,103,103,
+ 103,103,103,103,103,103,103,103,103,103,103,103, 2, 2,119,119,
+ 119,119,119,119,119,119,119,119,119,119,119,119, 2, 2,119,119,
+ 2,119,119,119,119,119, 2, 2, 2, 2, 2,119,119,119,146,146,
+ 146,146,146,146,146,146,146,146,146, 2, 2, 2, 2, 2, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99, 99, 2, 2, 2, 2, 99, 2, 2,
+ 2, 2, 2, 2, 2, 99,136,139, 13, 13,155, 2, 2, 2,136,136,
+ 136,136,136,136,136,136,155,155,155,155,155,155,155,155,155,155,
+ 155,155,155,155, 2, 2,136, 2, 2, 2, 2, 2, 2, 2, 17, 17,
+ 17, 17, 2, 17, 17, 17, 17, 17, 17, 17, 2, 17, 17, 2, 17, 15,
+ 15, 15, 15, 15, 15, 15, 17, 17, 17, 2, 2, 2, 2, 2, 15, 15,
+ 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 17, 17, 17, 17,139,139,
+ 139,139,139,139,139,139,139,139,139,139, 2, 2, 2, 2,105,105,
+ 105,105,105,105,105,105,105,105,105, 2, 2, 2, 2, 2,105,105,
+ 105,105,105, 2, 2, 2,105, 2, 2, 2, 2, 2, 2, 2,105,105,
+ 2, 2,105,105,105,105, 1, 1, 1, 1, 1, 1, 2, 2, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1,
+ 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 2, 2,
+ 0, 2, 2, 0, 0, 2, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0,
+ 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,
+ 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0,
+ 0, 0, 0, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2,
+ 0, 0, 0, 0, 0, 0,131,131,131,131,131,131,131,131,131,131,
+ 131,131, 2, 2, 2, 2, 2, 2, 2,131,131,131,131,131, 2,131,
+ 131,131,131,131,131,131, 56, 56, 56, 56, 56, 56, 56, 2, 56, 2,
+ 2, 56, 56, 56, 56, 56, 56, 56, 2, 56, 56, 2, 56, 56, 56, 56,
+ 56, 2, 2, 2, 2, 2,151,151,151,151,151,151,151,151,151,151,
+ 151,151,151, 2, 2, 2,151,151,151,151,151,151, 2, 2,151,151,
+ 2, 2, 2, 2,151,151,160,160,160,160,160,160,160,160,160,160,
+ 160,160,160,160,160, 2,152,152,152,152,152,152,152,152,152,152,
+ 2, 2, 2, 2, 2,152, 30, 30, 30, 30, 2, 30, 30, 2,113,113,
+ 113,113,113,113,113,113,113,113,113,113,113, 2, 2,113,113,113,
+ 113,113,113,113,113, 2,132,132,132,132,132,132,132,132,132,132,
+ 132,132, 2, 2, 2, 2,132,132, 2, 2, 2, 2,132,132, 3, 3,
+ 3, 3, 2, 3, 3, 3, 2, 3, 3, 2, 3, 2, 2, 3, 2, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 3,
+ 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 3,
+ 2, 3, 2, 3, 3, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3,
+ 3, 3, 3, 2, 3, 2, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2,
+ 2, 2, 2, 2, 0, 0, 15, 0, 0, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 0, 0, 0, 13, 2, 2, 2, 2, 2, 2, 2, 13, 13,
+ 13, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 0, 1,
+ 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 10, 9, 11, 12, 13,
+ 9, 9, 9, 14, 9, 9, 15, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 16, 17, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 18, 19, 20, 9, 21, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 22, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 23, 24, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 23, 0, 0, 24, 25, 26, 27, 28, 29, 30, 0, 0, 31, 32, 0, 33,
+ 0, 34, 0, 35, 0, 0, 0, 0, 36, 37, 38, 39, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44,
+ 0, 45, 0, 0, 0, 0, 0, 0, 46, 47, 0, 0, 0, 0, 0, 48,
+ 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 50, 51, 0, 0, 0, 52, 0, 0, 53, 0, 0, 0, 0, 0, 0, 0,
+ 54, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0,
+ 56, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 58, 59, 60, 61, 62, 63, 64, 65, 0, 0, 0, 0, 0, 0, 66, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 68, 0, 69,
+ 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
+ 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,104, 0,
+ 0, 0, 0, 0, 0,105,106, 0,107, 0, 0, 0,108, 0,109, 0,
+ 110, 0,111,112,113, 0,114, 0, 0, 0,115, 0, 0, 0,116, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,117, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 118,119,120,121, 0,122,123,124,125,126, 0,127, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128,129,130,131,
+ 132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,
+ 148,149,150,151,152,153,154,155,156,157, 0, 0, 0,158,159,160,
+ 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,162,163, 0, 0, 0, 0, 0, 0, 0,164, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,167, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,168,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,169,170, 0, 0, 0, 0,171,172, 0, 0, 0,173,174,175,176,
+ 177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,
+ 193,194,195,196,197,198,199,200,201,202,203,204,205,206, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
+};
+static const uint16_t
+_hb_ucd_u16[9200] =
+{
+ 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12,
+ 13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23,
+ 13, 13, 13, 24, 25, 11, 11, 11, 11, 26, 11, 27, 28, 29, 30, 31,
+ 32, 32, 32, 32, 32, 32, 32, 33, 34, 35, 36, 11, 37, 38, 13, 39,
+ 9, 9, 9, 11, 11, 11, 13, 13, 40, 13, 13, 13, 41, 13, 13, 13,
+ 13, 13, 13, 42, 9, 43, 11, 11, 44, 45, 32, 46, 47, 48, 49, 50,
+ 51, 52, 48, 48, 53, 32, 54, 55, 48, 48, 48, 48, 48, 56, 57, 58,
+ 59, 60, 48, 32, 61, 48, 48, 48, 48, 48, 62, 63, 64, 48, 65, 66,
+ 48, 67, 68, 69, 48, 70, 71, 48, 72, 73, 48, 48, 74, 32, 75, 32,
+ 76, 48, 48, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
+ 90, 83, 84, 91, 92, 93, 94, 95, 96, 97, 84, 98, 99, 100, 88, 101,
+ 102, 83, 84, 103, 104, 105, 88, 106, 107, 108, 109, 110, 111, 112, 94, 113,
+ 114, 115, 84, 116, 117, 118, 88, 119, 120, 115, 84, 121, 122, 123, 88, 124,
+ 125, 115, 48, 126, 127, 128, 88, 129, 130, 131, 48, 132, 133, 134, 94, 135,
+ 136, 48, 48, 137, 138, 139, 140, 140, 141, 48, 142, 143, 144, 145, 140, 140,
+ 146, 147, 148, 149, 150, 48, 151, 152, 153, 154, 32, 155, 156, 157, 140, 140,
+ 48, 48, 158, 159, 160, 161, 162, 163, 164, 165, 9, 9, 166, 11, 11, 167,
+ 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 168, 169, 48, 48,
+ 168, 48, 48, 170, 171, 172, 48, 48, 48, 171, 48, 48, 48, 173, 174, 175,
+ 48, 176, 9, 9, 9, 9, 9, 177, 178, 48, 48, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 48, 179, 48, 180, 181, 48, 48, 48, 48, 182, 183,
+ 48, 184, 48, 185, 48, 186, 187, 188, 48, 48, 48, 189, 190, 191, 192, 193,
+ 194, 192, 48, 48, 195, 48, 48, 196, 197, 48, 198, 48, 48, 48, 48, 199,
+ 48, 200, 201, 202, 203, 48, 204, 205, 48, 48, 206, 48, 207, 208, 209, 209,
+ 48, 210, 48, 48, 48, 211, 212, 213, 192, 192, 214, 215, 216, 140, 140, 140,
+ 217, 48, 48, 218, 219, 160, 220, 221, 222, 48, 223, 64, 48, 48, 224, 225,
+ 48, 48, 226, 227, 228, 64, 48, 229, 230, 9, 9, 231, 232, 233, 234, 235,
+ 11, 11, 236, 27, 27, 27, 237, 238, 11, 239, 27, 27, 32, 32, 32, 32,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 240, 13, 13, 13, 13, 13, 13,
+ 241, 242, 241, 241, 242, 243, 241, 244, 245, 245, 245, 246, 247, 248, 249, 250,
+ 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 261, 262, 263, 264, 265,
+ 266, 267, 268, 269, 270, 271, 272, 272, 273, 274, 275, 209, 276, 277, 209, 278,
+ 279, 279, 279, 279, 279, 279, 279, 279, 280, 209, 281, 209, 209, 209, 209, 282,
+ 209, 283, 279, 284, 209, 285, 286, 209, 209, 209, 287, 140, 288, 140, 271, 271,
+ 271, 289, 209, 209, 209, 209, 290, 271, 209, 209, 209, 209, 209, 209, 209, 209,
+ 209, 209, 209, 291, 292, 209, 209, 293, 209, 209, 209, 209, 209, 209, 294, 209,
+ 209, 209, 209, 209, 209, 209, 295, 296, 271, 297, 209, 209, 298, 279, 299, 279,
+ 300, 301, 279, 279, 279, 302, 279, 303, 209, 209, 209, 279, 304, 209, 209, 305,
+ 209, 306, 209, 209, 209, 209, 209, 209, 9, 9, 9, 11, 11, 11, 307, 308,
+ 13, 13, 13, 13, 13, 13, 309, 310, 11, 11, 311, 48, 48, 48, 312, 313,
+ 48, 314, 315, 315, 315, 315, 32, 32, 316, 317, 318, 319, 320, 321, 140, 140,
+ 209, 322, 209, 209, 209, 209, 209, 323, 209, 209, 209, 209, 209, 324, 140, 325,
+ 326, 327, 328, 329, 136, 48, 48, 48, 48, 330, 178, 48, 48, 48, 48, 331,
+ 332, 48, 48, 136, 48, 48, 48, 48, 200, 333, 48, 48, 209, 209, 323, 48,
+ 209, 334, 335, 209, 336, 337, 209, 209, 335, 209, 209, 337, 209, 209, 209, 209,
+ 48, 48, 48, 48, 209, 209, 209, 209, 48, 338, 48, 48, 48, 48, 48, 48,
+ 151, 209, 209, 209, 287, 48, 48, 229, 339, 48, 340, 140, 13, 13, 341, 342,
+ 13, 343, 48, 48, 48, 48, 344, 345, 31, 346, 347, 348, 13, 13, 13, 349,
+ 350, 351, 352, 353, 354, 355, 140, 356, 357, 48, 358, 359, 48, 48, 48, 360,
+ 361, 48, 48, 362, 363, 192, 32, 364, 64, 48, 365, 48, 366, 367, 48, 151,
+ 76, 48, 48, 368, 369, 370, 371, 372, 48, 48, 373, 374, 375, 376, 48, 377,
+ 48, 48, 48, 378, 379, 380, 381, 382, 383, 384, 315, 11, 11, 385, 386, 11,
+ 11, 11, 11, 11, 48, 48, 387, 192, 48, 48, 388, 48, 389, 48, 48, 206,
+ 390, 390, 390, 390, 390, 390, 390, 390, 391, 391, 391, 391, 391, 391, 391, 391,
+ 48, 48, 48, 48, 48, 48, 204, 48, 48, 48, 48, 48, 48, 207, 140, 140,
+ 392, 393, 394, 395, 396, 48, 48, 48, 48, 48, 48, 397, 398, 399, 48, 48,
+ 48, 48, 48, 400, 209, 48, 48, 48, 48, 401, 48, 48, 402, 140, 140, 403,
+ 32, 404, 32, 405, 406, 407, 408, 409, 48, 48, 48, 48, 48, 48, 48, 410,
+ 411, 2, 3, 4, 5, 412, 413, 414, 48, 415, 48, 200, 416, 417, 418, 419,
+ 420, 48, 172, 421, 204, 204, 140, 140, 48, 48, 48, 48, 48, 48, 48, 71,
+ 422, 271, 271, 423, 272, 272, 272, 424, 425, 426, 427, 140, 140, 209, 209, 428,
+ 140, 140, 140, 140, 140, 140, 140, 140, 48, 151, 48, 48, 48, 100, 429, 430,
+ 48, 48, 431, 48, 432, 48, 48, 433, 48, 434, 48, 48, 435, 436, 140, 140,
+ 9, 9, 437, 11, 11, 48, 48, 48, 48, 204, 192, 9, 9, 438, 11, 439,
+ 48, 48, 440, 48, 48, 48, 441, 442, 442, 443, 444, 445, 140, 140, 140, 140,
+ 48, 48, 48, 314, 48, 199, 440, 140, 446, 27, 27, 447, 140, 140, 140, 140,
+ 448, 48, 48, 449, 48, 450, 48, 451, 48, 200, 452, 140, 140, 140, 48, 453,
+ 48, 454, 48, 455, 140, 140, 140, 140, 48, 48, 48, 456, 271, 457, 271, 271,
+ 458, 459, 48, 460, 461, 462, 48, 463, 48, 464, 140, 140, 465, 48, 466, 467,
+ 48, 48, 48, 468, 48, 469, 48, 470, 48, 471, 472, 140, 140, 140, 140, 140,
+ 48, 48, 48, 48, 196, 140, 140, 140, 9, 9, 9, 473, 11, 11, 11, 474,
+ 48, 48, 475, 192, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 271, 476,
+ 48, 48, 477, 478, 140, 140, 140, 140, 48, 464, 479, 48, 62, 480, 140, 48,
+ 481, 140, 140, 48, 482, 140, 48, 314, 483, 48, 48, 484, 485, 457, 486, 487,
+ 222, 48, 48, 488, 489, 48, 196, 192, 490, 48, 491, 492, 493, 48, 48, 494,
+ 222, 48, 48, 495, 496, 497, 498, 499, 48, 97, 500, 501, 140, 140, 140, 140,
+ 502, 503, 504, 48, 48, 505, 506, 192, 507, 83, 84, 508, 509, 510, 511, 512,
+ 48, 48, 48, 513, 514, 515, 478, 140, 48, 48, 48, 516, 517, 192, 140, 140,
+ 48, 48, 518, 519, 520, 521, 140, 140, 48, 48, 48, 522, 523, 192, 524, 140,
+ 48, 48, 525, 526, 192, 140, 140, 140, 48, 173, 527, 528, 314, 140, 140, 140,
+ 48, 48, 500, 529, 140, 140, 140, 140, 140, 140, 9, 9, 11, 11, 148, 530,
+ 531, 532, 48, 533, 534, 192, 140, 140, 140, 140, 535, 48, 48, 536, 537, 140,
+ 538, 48, 48, 539, 540, 541, 48, 48, 542, 543, 544, 48, 48, 48, 48, 196,
+ 84, 48, 518, 545, 546, 148, 175, 547, 48, 548, 549, 550, 140, 140, 140, 140,
+ 551, 48, 48, 552, 553, 192, 554, 48, 555, 556, 192, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 48, 557, 140, 140, 140, 100, 271, 558, 559, 560,
+ 48, 207, 140, 140, 140, 140, 140, 140, 272, 272, 272, 272, 272, 272, 561, 562,
+ 48, 48, 48, 48, 388, 140, 140, 140, 140, 48, 48, 48, 48, 48, 48, 563,
+ 48, 48, 200, 564, 140, 140, 140, 140, 48, 48, 48, 48, 314, 140, 140, 140,
+ 48, 48, 48, 196, 48, 200, 370, 48, 48, 48, 48, 200, 192, 48, 204, 565,
+ 48, 48, 48, 566, 567, 568, 569, 570, 48, 140, 140, 140, 140, 140, 140, 140,
+ 140, 140, 140, 140, 9, 9, 11, 11, 271, 571, 140, 140, 140, 140, 140, 140,
+ 48, 48, 48, 48, 572, 573, 574, 574, 575, 576, 140, 140, 140, 140, 577, 578,
+ 48, 48, 48, 48, 48, 48, 48, 440, 48, 48, 48, 48, 48, 199, 140, 140,
+ 196, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 579,
+ 48, 48, 580, 140, 140, 580, 581, 48, 48, 48, 48, 48, 48, 48, 48, 206,
+ 48, 48, 48, 48, 48, 48, 71, 151, 196, 582, 583, 140, 140, 140, 140, 140,
+ 32, 32, 584, 32, 585, 209, 209, 209, 209, 209, 209, 209, 323, 140, 140, 140,
+ 209, 209, 209, 209, 209, 209, 209, 324, 209, 209, 586, 209, 209, 209, 587, 588,
+ 589, 209, 590, 209, 209, 209, 288, 140, 209, 209, 209, 209, 591, 140, 140, 140,
+ 140, 140, 140, 140, 140, 140, 271, 592, 209, 209, 209, 209, 209, 287, 271, 461,
+ 9, 593, 11, 594, 595, 596, 241, 9, 597, 598, 599, 600, 601, 9, 593, 11,
+ 602, 603, 11, 604, 605, 606, 607, 9, 608, 11, 9, 593, 11, 594, 595, 11,
+ 241, 9, 597, 607, 9, 608, 11, 9, 593, 11, 609, 9, 610, 611, 612, 613,
+ 11, 614, 9, 615, 616, 617, 618, 11, 619, 9, 620, 11, 621, 622, 622, 622,
+ 32, 32, 32, 623, 32, 32, 624, 625, 626, 627, 45, 140, 140, 140, 140, 140,
+ 628, 629, 140, 140, 140, 140, 140, 140, 630, 631, 632, 140, 140, 140, 140, 140,
+ 48, 48, 151, 633, 634, 140, 140, 140, 140, 48, 635, 140, 48, 48, 636, 637,
+ 140, 140, 140, 140, 140, 140, 638, 200, 48, 48, 48, 48, 639, 585, 140, 140,
+ 9, 9, 597, 11, 640, 370, 140, 140, 140, 140, 140, 140, 140, 140, 140, 498,
+ 271, 271, 641, 642, 140, 140, 140, 140, 498, 271, 643, 644, 140, 140, 140, 140,
+ 645, 48, 646, 647, 648, 649, 650, 651, 652, 206, 653, 206, 140, 140, 140, 654,
+ 209, 209, 325, 209, 209, 209, 209, 209, 209, 323, 334, 655, 655, 655, 209, 324,
+ 656, 209, 209, 209, 209, 209, 209, 209, 209, 209, 657, 140, 140, 140, 658, 209,
+ 659, 209, 209, 325, 660, 661, 324, 140, 209, 209, 209, 209, 209, 209, 209, 662,
+ 209, 209, 209, 209, 209, 663, 426, 426, 209, 209, 209, 209, 209, 209, 209, 323,
+ 209, 209, 209, 209, 209, 660, 325, 427, 325, 209, 209, 209, 664, 176, 209, 209,
+ 664, 209, 657, 661, 140, 140, 140, 140, 209, 209, 209, 209, 209, 323, 657, 665,
+ 287, 209, 426, 288, 324, 176, 664, 287, 209, 666, 209, 209, 288, 140, 140, 192,
+ 48, 48, 48, 48, 48, 48, 140, 140, 48, 48, 48, 196, 48, 48, 48, 48,
+ 48, 204, 48, 48, 48, 48, 48, 48, 48, 48, 478, 48, 48, 48, 48, 48,
+ 48, 48, 48, 48, 48, 48, 100, 140, 48, 204, 140, 140, 140, 140, 140, 140,
+ 48, 48, 48, 48, 71, 140, 140, 140, 667, 140, 668, 668, 668, 668, 668, 668,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 140,
+ 391, 391, 391, 391, 391, 391, 391, 669, 391, 391, 391, 391, 391, 391, 391, 670,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 1, 2, 2, 3,
+ 0, 0, 0, 0, 0, 4, 0, 4, 2, 2, 5, 2, 2, 2, 5, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 6, 0, 0, 0, 0, 7, 8, 0, 0,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 11,
+ 12, 13, 14, 14, 15, 14, 14, 14, 14, 14, 14, 14, 16, 17, 14, 14,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 19, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 20, 21, 21, 21, 22, 20, 21, 21, 21, 21,
+ 21, 23, 24, 25, 25, 25, 25, 25, 25, 26, 25, 25, 25, 27, 28, 26,
+ 29, 30, 31, 32, 31, 31, 31, 31, 33, 34, 35, 31, 31, 31, 36, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 29, 31, 31, 31, 31,
+ 37, 38, 37, 37, 37, 37, 37, 37, 37, 39, 31, 31, 31, 31, 31, 31,
+ 40, 40, 40, 40, 40, 40, 41, 26, 42, 42, 42, 42, 42, 42, 42, 43,
+ 44, 44, 44, 44, 44, 45, 44, 46, 47, 47, 47, 48, 37, 49, 31, 31,
+ 31, 50, 51, 31, 31, 31, 31, 31, 31, 31, 31, 31, 52, 31, 31, 31,
+ 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 54, 53, 55, 53, 53, 53,
+ 56, 57, 58, 59, 59, 60, 61, 62, 57, 63, 64, 65, 66, 59, 59, 67,
+ 68, 69, 70, 71, 71, 72, 73, 74, 69, 75, 76, 77, 78, 71, 79, 26,
+ 80, 81, 82, 83, 83, 84, 85, 86, 81, 87, 88, 26, 89, 83, 90, 91,
+ 92, 93, 94, 95, 95, 96, 97, 98, 93, 99, 100, 101, 102, 95, 95, 26,
+ 103, 104, 105, 106, 107, 104, 108, 109, 104, 105, 110, 26, 111, 108, 108, 112,
+ 113, 114, 115, 113, 113, 115, 113, 116, 114, 117, 118, 119, 120, 113, 121, 113,
+ 122, 123, 124, 122, 122, 124, 125, 126, 123, 127, 128, 128, 129, 122, 130, 26,
+ 131, 132, 133, 131, 131, 131, 131, 131, 132, 133, 134, 131, 135, 131, 131, 131,
+ 136, 137, 138, 139, 137, 137, 140, 141, 138, 142, 143, 137, 144, 137, 145, 26,
+ 146, 147, 147, 147, 147, 147, 147, 148, 147, 147, 147, 149, 26, 26, 26, 26,
+ 150, 151, 152, 152, 153, 152, 152, 154, 155, 154, 152, 156, 26, 26, 26, 26,
+ 157, 157, 157, 157, 157, 157, 157, 157, 157, 158, 157, 157, 157, 159, 158, 157,
+ 157, 157, 157, 158, 157, 157, 157, 160, 157, 160, 161, 162, 26, 26, 26, 26,
+ 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163,
+ 163, 163, 163, 163, 164, 164, 164, 164, 165, 166, 164, 164, 164, 164, 164, 167,
+ 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168,
+ 169, 169, 169, 169, 169, 169, 169, 169, 169, 170, 171, 170, 169, 169, 169, 169,
+ 169, 170, 169, 169, 169, 169, 170, 171, 170, 169, 171, 169, 169, 169, 169, 169,
+ 169, 169, 170, 169, 169, 169, 169, 169, 169, 169, 169, 172, 169, 169, 169, 173,
+ 169, 169, 169, 174, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 176, 176,
+ 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 178, 178, 178, 179, 180, 180, 180, 180, 180, 180, 180, 180, 180, 181, 180, 182,
+ 183, 183, 184, 185, 186, 186, 187, 26, 188, 188, 189, 26, 190, 191, 192, 26,
+ 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 194, 193, 195, 193, 195,
+ 196, 197, 197, 198, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 199,
+ 197, 197, 197, 197, 197, 200, 177, 177, 177, 177, 177, 177, 177, 177, 201, 26,
+ 202, 202, 202, 203, 202, 204, 202, 204, 205, 202, 206, 206, 206, 207, 208, 26,
+ 209, 209, 209, 209, 209, 210, 209, 209, 209, 211, 209, 212, 193, 193, 193, 193,
+ 213, 213, 213, 214, 215, 215, 215, 215, 215, 215, 215, 216, 215, 215, 215, 217,
+ 215, 218, 215, 218, 215, 219, 9, 9, 9, 220, 26, 26, 26, 26, 26, 26,
+ 221, 221, 221, 221, 221, 221, 221, 221, 221, 222, 221, 221, 221, 221, 221, 223,
+ 224, 224, 224, 224, 224, 224, 224, 224, 225, 225, 225, 225, 225, 225, 226, 227,
+ 228, 228, 228, 228, 228, 228, 228, 229, 228, 230, 231, 231, 231, 231, 231, 231,
+ 18, 232, 164, 164, 164, 164, 164, 233, 224, 26, 234, 9, 235, 236, 237, 238,
+ 2, 2, 2, 2, 239, 240, 2, 2, 2, 2, 2, 241, 242, 243, 2, 244,
+ 2, 2, 2, 2, 2, 2, 2, 245, 9, 9, 9, 9, 9, 9, 9, 9,
+ 14, 14, 246, 246, 14, 14, 14, 14, 246, 246, 14, 247, 14, 14, 14, 246,
+ 14, 14, 14, 14, 14, 14, 248, 14, 248, 14, 249, 250, 14, 14, 251, 252,
+ 0, 253, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 0, 255, 256,
+ 0, 257, 2, 258, 0, 0, 0, 0, 259, 26, 9, 9, 9, 9, 260, 26,
+ 0, 0, 0, 0, 261, 262, 4, 0, 0, 263, 0, 0, 2, 2, 2, 2,
+ 2, 264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 257, 26, 26, 26, 0, 265, 26, 26, 0, 0, 0, 0,
+ 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 267, 0,
+ 0, 0, 268, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 269, 2, 2, 2, 2,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 270, 271,
+ 164, 164, 164, 164, 165, 166, 272, 272, 272, 272, 272, 272, 272, 273, 274, 273,
+ 169, 169, 171, 26, 171, 171, 171, 171, 171, 171, 171, 171, 18, 18, 18, 18,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 275, 26, 26, 26, 26,
+ 276, 276, 276, 277, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 278, 26,
+ 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
+ 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279, 26, 26, 26, 0, 280,
+ 281, 0, 0, 0, 282, 283, 0, 284, 285, 286, 286, 286, 286, 286, 286, 286,
+ 286, 286, 287, 288, 289, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 291,
+ 292, 293, 293, 293, 293, 293, 294, 168, 168, 168, 168, 168, 168, 168, 168, 168,
+ 168, 295, 0, 0, 293, 293, 293, 293, 0, 0, 0, 0, 280, 26, 290, 290,
+ 168, 168, 168, 295, 0, 0, 0, 0, 0, 0, 0, 0, 168, 168, 168, 296,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 290, 290, 290, 290, 290, 297,
+ 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 0, 0, 0, 0, 0,
+ 276, 276, 276, 276, 276, 276, 276, 276, 0, 0, 0, 0, 0, 0, 0, 0,
+ 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298, 298,
+ 298, 299, 298, 298, 298, 298, 298, 298, 300, 26, 301, 301, 301, 301, 301, 301,
+ 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302, 302,
+ 302, 302, 302, 302, 302, 303, 26, 26, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 26,
+ 0, 0, 0, 0, 305, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 306, 2, 2, 2, 2, 2, 2, 2, 307, 308, 309, 26, 26, 310, 2,
+ 311, 311, 311, 311, 311, 312, 0, 313, 314, 314, 314, 314, 314, 314, 314, 26,
+ 315, 315, 315, 315, 315, 315, 315, 315, 316, 317, 315, 318, 53, 53, 53, 53,
+ 319, 319, 319, 319, 319, 320, 321, 321, 321, 321, 322, 323, 168, 168, 168, 324,
+ 325, 325, 325, 325, 325, 325, 325, 325, 325, 326, 325, 327, 163, 163, 163, 328,
+ 329, 329, 329, 329, 329, 329, 330, 26, 329, 331, 329, 332, 163, 163, 163, 163,
+ 333, 333, 333, 333, 333, 333, 333, 333, 334, 26, 26, 335, 336, 336, 337, 26,
+ 338, 338, 338, 26, 171, 171, 2, 2, 2, 2, 2, 339, 340, 341, 175, 175,
+ 175, 175, 175, 175, 175, 175, 175, 175, 336, 336, 336, 336, 336, 342, 336, 343,
+ 168, 168, 168, 168, 344, 26, 168, 168, 295, 345, 168, 168, 168, 168, 168, 344,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 279, 276, 276,
+ 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 346, 26, 26, 26, 26,
+ 347, 26, 348, 349, 25, 25, 350, 351, 352, 25, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 353, 26, 354, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 355, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 356, 31, 31, 31, 31, 31, 31, 357, 26, 26, 26, 26, 31, 31,
+ 9, 9, 0, 313, 9, 358, 0, 0, 0, 0, 359, 0, 257, 280, 360, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 361,
+ 362, 0, 0, 0, 1, 2, 2, 3, 1, 2, 2, 3, 363, 290, 289, 290,
+ 290, 290, 290, 364, 168, 168, 168, 295, 365, 365, 365, 366, 257, 257, 26, 367,
+ 368, 369, 368, 368, 370, 368, 368, 371, 368, 372, 368, 372, 26, 26, 26, 26,
+ 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 368, 373,
+ 374, 0, 0, 0, 0, 0, 375, 0, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 252, 0, 376, 377, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 378,
+ 379, 379, 379, 380, 381, 381, 381, 381, 381, 381, 382, 26, 383, 0, 0, 280,
+ 384, 384, 384, 384, 385, 386, 387, 387, 387, 388, 389, 389, 389, 389, 389, 390,
+ 391, 391, 391, 392, 393, 393, 393, 393, 394, 393, 395, 26, 26, 26, 26, 26,
+ 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 397, 397, 397, 397, 397, 397,
+ 398, 398, 398, 399, 398, 400, 401, 401, 401, 401, 402, 401, 401, 401, 401, 402,
+ 403, 403, 403, 403, 403, 26, 404, 404, 404, 404, 404, 404, 405, 406, 407, 408,
+ 407, 408, 409, 407, 410, 407, 410, 411, 26, 26, 26, 26, 26, 26, 26, 26,
+ 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412, 412,
+ 412, 412, 412, 412, 412, 412, 413, 26, 412, 412, 414, 26, 412, 26, 26, 26,
+ 415, 2, 2, 2, 2, 2, 416, 307, 26, 26, 26, 26, 26, 26, 26, 26,
+ 417, 418, 419, 419, 419, 419, 420, 421, 422, 422, 423, 422, 424, 424, 424, 424,
+ 425, 425, 425, 426, 427, 425, 26, 26, 26, 26, 26, 26, 428, 428, 429, 430,
+ 431, 431, 431, 432, 433, 433, 433, 434, 26, 26, 26, 26, 26, 26, 26, 26,
+ 435, 435, 435, 435, 436, 436, 436, 437, 436, 436, 438, 436, 436, 436, 436, 436,
+ 439, 440, 441, 442, 443, 443, 444, 445, 443, 446, 443, 446, 447, 447, 447, 447,
+ 448, 448, 448, 448, 26, 26, 26, 26, 449, 449, 449, 449, 450, 451, 450, 26,
+ 452, 452, 452, 452, 452, 452, 453, 454, 455, 455, 456, 455, 457, 457, 458, 457,
+ 459, 459, 460, 461, 26, 462, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 463, 463, 463, 463, 463, 463, 463, 463, 463, 464, 26, 26, 26, 26, 26, 26,
+ 465, 465, 465, 465, 465, 465, 466, 26, 465, 465, 465, 465, 465, 465, 466, 467,
+ 468, 468, 468, 468, 468, 26, 468, 469, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 31, 31, 31, 50,
+ 470, 470, 470, 470, 470, 471, 472, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 473, 473, 473, 473, 473, 26, 474, 474, 474, 474, 474, 475, 26, 26, 476, 476,
+ 476, 477, 26, 26, 26, 26, 478, 478, 478, 479, 26, 26, 480, 480, 481, 26,
+ 482, 482, 482, 482, 482, 482, 482, 482, 482, 483, 484, 482, 482, 482, 483, 485,
+ 486, 486, 486, 486, 486, 486, 486, 486, 487, 488, 489, 489, 489, 490, 489, 491,
+ 492, 492, 492, 492, 492, 492, 493, 492, 492, 26, 494, 494, 494, 494, 495, 26,
+ 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 497, 137, 498, 26,
+ 499, 499, 500, 499, 499, 499, 499, 501, 26, 26, 26, 26, 26, 26, 26, 26,
+ 502, 503, 504, 505, 504, 506, 507, 507, 507, 507, 507, 507, 507, 508, 507, 509,
+ 510, 511, 512, 513, 513, 514, 515, 516, 511, 517, 518, 519, 520, 521, 521, 26,
+ 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 522, 523, 524, 26, 26, 26,
+ 525, 525, 525, 525, 525, 525, 525, 525, 525, 26, 525, 526, 26, 26, 26, 26,
+ 527, 527, 527, 527, 527, 527, 528, 527, 527, 527, 527, 528, 26, 26, 26, 26,
+ 529, 529, 529, 529, 529, 529, 529, 529, 530, 26, 529, 531, 197, 532, 26, 26,
+ 533, 533, 533, 533, 533, 533, 533, 534, 533, 534, 26, 26, 26, 26, 26, 26,
+ 535, 535, 535, 536, 535, 537, 535, 535, 538, 26, 26, 26, 26, 26, 26, 26,
+ 539, 539, 539, 539, 539, 539, 539, 540, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 542, 543,
+ 544, 545, 546, 547, 547, 547, 548, 549, 544, 26, 547, 550, 26, 26, 26, 26,
+ 26, 26, 26, 26, 551, 552, 551, 551, 551, 551, 551, 552, 553, 26, 26, 26,
+ 554, 554, 554, 554, 554, 554, 554, 554, 554, 26, 555, 555, 555, 555, 555, 555,
+ 555, 555, 555, 555, 556, 26, 177, 177, 557, 557, 557, 557, 557, 557, 557, 558,
+ 559, 560, 559, 559, 559, 559, 561, 559, 562, 26, 559, 559, 559, 563, 564, 564,
+ 564, 564, 565, 564, 564, 566, 567, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 568, 569, 570, 570, 570, 570, 568, 571, 570, 26, 570, 572, 573, 574, 575, 575,
+ 575, 576, 577, 578, 575, 579, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 580, 580, 580, 581,
+ 26, 26, 26, 26, 26, 26, 582, 26, 108, 108, 108, 108, 108, 108, 583, 584,
+ 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585,
+ 585, 585, 585, 586, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 587, 588, 26,
+ 585, 585, 585, 585, 585, 585, 585, 585, 589, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 591, 26,
+ 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592, 592,
+ 592, 592, 592, 592, 592, 593, 592, 594, 26, 26, 26, 26, 26, 26, 26, 26,
+ 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595, 595,
+ 595, 595, 595, 595, 595, 595, 595, 595, 596, 26, 26, 26, 26, 26, 26, 26,
+ 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304,
+ 304, 304, 304, 304, 304, 304, 304, 597, 598, 598, 598, 599, 598, 600, 601, 601,
+ 601, 601, 601, 601, 601, 601, 601, 602, 601, 603, 604, 604, 604, 605, 605, 26,
+ 606, 606, 606, 606, 606, 606, 606, 606, 607, 26, 606, 608, 608, 606, 606, 609,
+ 606, 606, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 610, 610, 610, 610, 610, 610, 610, 610,
+ 610, 610, 610, 611, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 612, 612, 612, 612, 612, 612, 612, 612, 612, 613, 612, 612, 612, 612, 612, 612,
+ 612, 614, 612, 612, 26, 26, 26, 26, 26, 26, 26, 26, 615, 26, 346, 26,
+ 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616,
+ 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 616, 26,
+ 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 617,
+ 617, 617, 617, 617, 617, 617, 617, 617, 617, 617, 618, 26, 26, 26, 26, 26,
+ 616, 619, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 620, 621,
+ 622, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
+ 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286, 286,
+ 286, 286, 286, 286, 623, 26, 26, 26, 26, 26, 624, 26, 625, 26, 626, 626,
+ 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626,
+ 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 626, 627,
+ 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 629, 628, 630,
+ 628, 631, 628, 632, 280, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 9, 9, 9, 9, 9, 633, 9, 9, 220, 26, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 280, 26, 26, 26, 26, 26, 26, 26,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 275, 26,
+ 0, 0, 0, 0, 257, 362, 0, 0, 0, 0, 0, 0, 634, 635, 0, 636,
+ 637, 638, 0, 0, 0, 639, 0, 0, 0, 0, 0, 0, 0, 265, 26, 26,
+ 14, 14, 14, 14, 14, 14, 14, 14, 246, 26, 26, 26, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 280, 26,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 257, 26, 0, 0, 0, 259,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 0, 0, 0, 0, 0,
+ 0, 0, 0, 254, 640, 641, 0, 642, 643, 0, 0, 0, 0, 0, 0, 0,
+ 268, 644, 254, 254, 0, 0, 0, 645, 646, 647, 648, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 275, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 267, 0, 0, 0, 0, 0, 0,
+ 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649, 649,
+ 649, 650, 26, 651, 652, 649, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 2, 2, 2, 347, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 653, 269, 269, 654, 655, 656, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 657, 657, 657, 657, 657, 658, 657, 659, 657, 660, 26, 26, 26, 26, 26, 26,
+ 26, 26, 661, 661, 661, 662, 26, 26, 663, 663, 663, 663, 663, 663, 663, 664,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 171, 665, 169, 171,
+ 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666, 666,
+ 666, 666, 666, 666, 666, 666, 666, 666, 667, 666, 668, 26, 26, 26, 26, 26,
+ 669, 669, 669, 669, 669, 669, 669, 669, 669, 670, 669, 671, 26, 26, 26, 26,
+ 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 362, 0,
+ 0, 0, 0, 0, 0, 0, 376, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 362, 0, 0, 0, 0, 0, 0, 275, 26, 26, 26, 26, 26, 26, 26, 26,
+ 672, 31, 31, 31, 673, 674, 675, 676, 677, 678, 673, 679, 673, 675, 675, 680,
+ 31, 681, 31, 682, 683, 681, 31, 682, 26, 26, 26, 26, 26, 26, 51, 26,
+ 0, 0, 0, 0, 0, 280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 280, 26, 0, 257, 362, 0, 362, 0, 362, 0, 0, 0, 275, 26,
+ 0, 0, 0, 0, 0, 275, 26, 26, 26, 26, 26, 26, 684, 0, 0, 0,
+ 685, 26, 0, 0, 0, 0, 0, 280, 0, 259, 313, 26, 275, 26, 26, 26,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 686, 0, 376, 0, 376,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 280, 26,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 259, 0, 280, 259, 26,
+ 0, 280, 0, 0, 0, 0, 0, 0, 0, 26, 0, 313, 0, 0, 0, 0,
+ 0, 26, 0, 0, 0, 275, 313, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 280, 26, 0, 275, 376, 376,
+ 257, 26, 0, 0, 0, 376, 0, 265, 275, 26, 0, 313, 0, 26, 257, 26,
+ 0, 0, 359, 0, 0, 0, 0, 0, 0, 265, 26, 26, 26, 26, 0, 313,
+ 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 26, 26, 26, 26,
+ 276, 276, 276, 276, 276, 276, 276, 687, 276, 276, 276, 276, 276, 276, 276, 276,
+ 276, 276, 276, 279, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
+ 276, 276, 276, 276, 346, 26, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
+ 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 687, 26, 26, 26,
+ 276, 276, 276, 279, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+ 276, 276, 276, 276, 276, 276, 276, 276, 276, 688, 26, 26, 26, 26, 26, 26,
+ 689, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003,1008,
+ 0,1033,1040,1041,1042,1043,1047, 0, 0,1080,1081,1082,1086,1110, 0, 0,
+ 1124,1125,1126,1127,1131,1133, 0,1147,1154,1155,1156,1161,1187,1188,1189,1193,
+ 0,1219,1226,1227,1228,1229,1233, 0, 0,1267,1268,1269,1273,1298, 0,1303,
+ 943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149,
+ 0, 0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175,
+ 991,1176, 993,1178, 994,1179, 0, 0,1004,1190,1005,1191,1006,1192,1014,1199,
+ 1007, 0, 0, 0,1016,1201,1020,1206, 0,1022,1208,1025,1211,1023,1209, 0,
+ 0, 0, 0,1032,1218,1037,1223,1035,1221, 0, 0, 0,1044,1230,1045,1231,
+ 1049,1235, 0, 0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258,
+ 1069,1255,1077,1264,1074,1261, 0, 0,1083,1270,1084,1271,1085,1272,1088,1275,
+ 1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310, 0,
+ 1053,1239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1093,
+ 1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 949,1134,1010,
+ 1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366, 0,1320,1347,
+ 1418,1419,1323,1350, 0, 0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424,
+ 1202, 0, 0, 0, 987,1172, 0, 0,1031,1217,1321,1348,1322,1349,1338,1365,
+ 950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238,
+ 1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263, 0, 0, 997,1182,
+ 0, 0, 0, 0, 0, 0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232,
+ 1422,1423,1113,1301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 8, 9, 0, 10,1425, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0,1314,1427, 5,1434,1438,1443, 0,1450, 0,1455,1461,
+ 1514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1446,1458,1468,1476,1480,1486,
+ 1517, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1489,1503,1494,1500,1508, 0,
+ 0, 0, 0,1520,1521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1526,1528, 0,1525, 0, 0, 0,1522, 0, 0, 0, 0,1536,1532,1539, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1534, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1556, 0, 0, 0, 0, 0, 0,
+ 1548,1550, 0,1547, 0, 0, 0,1567, 0, 0, 0, 0,1558,1554,1561, 0,
+ 0, 0, 0, 0, 0, 0,1568,1569, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1529,1551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1523,1545,1524,1546, 0, 0,1527,1549, 0, 0,1570,1571,1530,1552,1531,1553,
+ 0, 0,1533,1555,1535,1557,1537,1559, 0, 0,1572,1573,1544,1566,1538,1560,
+ 1540,1562,1541,1563,1542,1564, 0, 0,1543,1565, 0, 0, 0, 0, 0, 0,
+ 0, 0,1606,1607,1609,1608,1610, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1613, 0,1611, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1620, 0, 0, 0, 0, 0, 0,
+ 0,1623, 0, 0,1624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1614,1615,1616,1617,1618,1619,1621,1622,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1628,1629, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1625,1626, 0,1627,
+ 0, 0, 0,1634, 0, 0,1635, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1630,1631,1632, 0, 0,1633, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1639, 0, 0,1638,1640, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1636,1637, 0, 0,
+ 0, 0, 0, 0,1641, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1642,1644,1643, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1645, 0, 0, 0, 0, 0, 0, 0,
+ 1646, 0, 0, 0, 0, 0, 0,1648,1649, 0,1647,1650, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1651,1653,1652, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1654, 0,1655,1657,1656, 0,
+ 0, 0, 0,1659, 0, 0, 0, 0, 0, 0, 0, 0, 0,1660, 0, 0,
+ 0, 0,1661, 0, 0, 0, 0,1662, 0, 0, 0, 0,1663, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1658, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1664, 0,1665,1673, 0,1674, 0, 0, 0, 0, 0, 0, 0,
+ 0,1666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,1668, 0, 0, 0, 0, 0, 0, 0, 0, 0,1669, 0, 0,
+ 0, 0,1670, 0, 0, 0, 0,1671, 0, 0, 0, 0,1672, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,1667, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1675, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,1676, 0,1677, 0,1678, 0,1679, 0,1680, 0,
+ 0, 0,1681, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1682, 0,1683, 0, 0,
+ 1684,1685, 0,1686, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153,
+ 966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171,
+ 989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356,
+ 1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214,
+ 1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363,
+ 1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251,
+ 1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266,
+ 1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287,
+ 1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302,
+ 1119,1308,1122,1311,1123,1312,1186,1260,1293,1305, 0,1394, 0, 0, 0, 0,
+ 952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375,
+ 1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353,
+ 1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234,
+ 1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403,
+ 1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412,
+ 1409,1414,1109,1297,1117,1306,1116,1304,1112,1300, 0, 0, 0, 0, 0, 0,
+ 1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721,
+ 1477,1478,1729,1731,1730,1732, 0, 0,1435,1436,1733,1735,1734,1736, 0, 0,
+ 1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757,
+ 1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776,
+ 1495,1496,1777,1779,1778,1780, 0, 0,1451,1452,1781,1783,1782,1784, 0, 0,
+ 1504,1505,1785,1788,1786,1789,1787,1790, 0,1459, 0,1791, 0,1792, 0,1793,
+ 1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814,
+ 1467, 21,1475, 22,1479, 23,1485, 24,1493, 27,1499, 28,1507, 29, 0, 0,
+ 1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728,
+ 1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764,
+ 1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821,
+ 1470,1469,1822,1474,1465, 0,1473,1825,1429,1428,1426, 12,1432, 0, 26, 0,
+ 0,1315,1823,1484,1466, 0,1483,1829,1433, 13,1437, 14,1441,1826,1827,1828,
+ 1488,1487,1513, 19, 0, 0,1492,1515,1445,1444,1442, 15, 0,1831,1832,1833,
+ 1502,1501,1516, 25,1497,1498,1506,1518,1457,1456,1454, 17,1453,1313, 11, 3,
+ 0, 0,1824,1512,1519, 0,1511,1830,1449, 16,1460, 18,1464, 4, 0, 0,
+ 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 6, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1834,1835, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1836, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1837,1839,1838,
+ 0, 0, 0, 0,1840, 0, 0, 0, 0,1841, 0, 0,1842, 0, 0, 0,
+ 0, 0, 0, 0,1843, 0,1844, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,1845, 0, 0,1846, 0, 0,1847, 0,1848, 0, 0, 0, 0, 0, 0,
+ 937, 0,1850, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1849, 936, 938,
+ 1851,1852, 0, 0,1853,1854, 0, 0,1855,1856, 0, 0, 0, 0, 0, 0,
+ 1857,1858, 0, 0,1861,1862, 0, 0,1863,1864, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1867,1868,1869,1870,
+ 1859,1860,1865,1866, 0, 0, 0, 0, 0, 0,1871,1872,1873,1874, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1875, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1877, 0,1878, 0,
+ 1879, 0,1880, 0,1881, 0,1882, 0,1883, 0,1884, 0,1885, 0,1886, 0,
+ 1887, 0,1888, 0, 0,1889, 0,1890, 0,1891, 0, 0, 0, 0, 0, 0,
+ 1892,1893, 0,1894,1895, 0,1896,1897, 0,1898,1899, 0,1900,1901, 0, 0,
+ 0, 0, 0, 0,1876, 0, 0, 0, 0, 0, 0, 0, 0, 0,1902, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1904, 0,1905, 0,
+ 1906, 0,1907, 0,1908, 0,1909, 0,1910, 0,1911, 0,1912, 0,1913, 0,
+ 1914, 0,1915, 0, 0,1916, 0,1917, 0,1918, 0, 0, 0, 0, 0, 0,
+ 1919,1920, 0,1921,1922, 0,1923,1924, 0,1925,1926, 0,1927,1928, 0, 0,
+ 0, 0, 0, 0,1903, 0, 0,1929,1930,1931,1932, 0, 0, 0,1933, 0,
+ 710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601,
+ 663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662,
+ 810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168,
+ 368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758,
+ 811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585,
+ 594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259,
+ 313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697,
+ 424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170,
+ 193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330,
+ 337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473,
+ 683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603,
+ 608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411,
+ 479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583,
+ 791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269,
+ 377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510,
+ 659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156,
+ 153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210, 0, 0,
+ 227, 0, 379, 0, 0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604, 0,
+ 661, 0, 703, 0, 0, 735, 743, 0, 0, 0, 793, 794, 795, 808, 741, 773,
+ 118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329,
+ 335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548,
+ 549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651,
+ 690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623, 0, 0,
+ 102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243,
+ 250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362,
+ 370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490,
+ 493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586,
+ 591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706,
+ 709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848,
+ 847, 857, 55, 65, 66, 883, 892, 916, 822, 824, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1586, 0,1605,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1602,1603,1934,1935,1574,1575,
+ 1576,1577,1579,1580,1581,1583,1584, 0,1585,1587,1588,1589,1591, 0,1592, 0,
+ 1593,1594, 0,1595,1596, 0,1598,1599,1600,1601,1604,1582,1578,1590,1597, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1936, 0,1937, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1938, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1939,1940,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1941,1942, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1944,1943, 0,1945, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1946,1947, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,1948, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1949,1950,
+ 1951,1952,1953,1954,1955, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1956,1957,1958,1960,1959,
+ 1961, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125, 34, 830, 130, 131,
+ 132, 137, 827, 35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152, 37,
+ 157, 158, 159, 160, 38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179,
+ 181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195,
+ 197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216,
+ 153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244,
+ 836, 837, 247, 248, 249, 246, 251, 39, 40, 253, 255, 255, 838, 257, 258, 259,
+ 261, 839, 262, 263, 301, 264, 41, 266, 270, 272, 271, 841, 274, 842, 277, 276,
+ 278, 281, 282, 42, 283, 284, 285, 286, 43, 843, 44, 289, 290, 291, 293, 934,
+ 298, 845, 845, 621, 300, 300, 45, 852, 894, 302, 304, 46, 306, 309, 310, 312,
+ 316, 48, 47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334,
+ 335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361,
+ 358, 356, 49, 363, 365, 367, 364, 50, 369, 371, 851, 376, 386, 378, 53, 381,
+ 52, 51, 140, 141, 387, 382, 614, 78, 388, 389, 390, 394, 392, 856, 54, 399,
+ 396, 402, 404, 858, 405, 401, 407, 55, 408, 409, 410, 413, 859, 415, 56, 417,
+ 860, 418, 57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433,
+ 437, 441, 438, 439, 442, 443, 864, 436, 449, 450, 58, 454, 453, 865, 447, 460,
+ 866, 867, 461, 466, 465, 464, 59, 467, 470, 469, 472, 828, 475, 868, 478, 870,
+ 483, 485, 486, 871, 488, 489, 872, 873, 495, 497, 60, 498, 61, 61, 504, 505,
+ 507, 508, 511, 62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878, 63, 64,
+ 528, 880, 879, 881, 882, 530, 531, 531, 533, 66, 534, 67, 68, 884, 536, 538,
+ 541, 69, 885, 549, 886, 887, 556, 559, 70, 561, 562, 563, 888, 889, 889, 567,
+ 71, 890, 570, 571, 72, 891, 577, 73, 581, 579, 582, 893, 587, 74, 590, 592,
+ 596, 75, 895, 896, 76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611,
+ 853, 77, 615, 616, 79, 617, 252, 902, 903, 854, 855, 621, 622, 731, 80, 627,
+ 626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651,
+ 638, 643, 644, 645, 905, 907, 906, 81, 653, 654, 656, 911, 657, 908, 82, 83,
+ 909, 910, 84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675, 85,
+ 677, 678, 86, 681, 682, 912, 685, 686, 87, 689, 36, 913, 914, 88, 89, 696,
+ 702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728,
+ 918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762, 90,
+ 764, 922, 91, 775, 279, 780, 923, 925, 92, 93, 785, 926, 94, 927, 787, 787,
+ 789, 928, 792, 95, 796, 797, 798, 800, 96, 929, 802, 804, 806, 97, 98, 807,
+ 930, 99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935, 0, 0,
+};
+static const int16_t
+_hb_ucd_i16[196] =
+{
+ 0, 0, 0, 0, 1, -1, 0, 0, 2, 0, -2, 0, 0, 0, 0, 2,
+ 0, -2, 0, 0, 0, 0, 0, 16, 0, 0, 0, -16, 0, 0, 1, -1,
+ 0, 0, 0, 1, -1, 0, 0, 0, 0, 1, -1, 0, 3, 3, 3, -3,
+ -3, -3, 0, 0, 0, 2016, 0, 0, 0, 0, 0, 2527, 1923, 1914, 1918, 0,
+ 2250, 0, 0, 0, 0, 0, 0, 138, 0, 7, 0, 0, -7, 0, 0, 0,
+ 1, -1, 1, -1, -1, 1, -1, 0, 1824, 0, 0, 0, 0, 0, 2104, 0,
+ 2108, 2106, 0, 2106, 1316, 0, 0, 0, 0, 1, -1, 1, -1, -138, 0, 0,
+ 1, -1, 8, 8, 8, 0, 7, 7, 0, 0, -8, -8, -8, -7, -7, 0,
+ 1, -1, 0, 2,-1316, 1, -1, 0, -1, 1, -1, 1, -1, 3, 1, -1,
+ -3, 1, -1, 1, -1, 0, 0,-1914,-1918, 0, 0,-1923,-1824, 0, 0, 0,
+ 0,-2016, 0, 0, 1, -1, 0, 1, 0, 0,-2104, 0, 0, 0, 0,-2106,
+ -2108,-2106, 0, 0, 1, -1,-2250, 0, 0, 0,-2527, 0, 0, -2, 0, 1,
+ -1, 0, 1, -1,
+};
+
+static inline uint_fast8_t
+_hb_ucd_gc (unsigned u)
+{
+ return u<1114110u?_hb_ucd_u8[6664+(((_hb_ucd_u8[1296+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2;
+}
+static inline uint_fast8_t
+_hb_ucd_ccc (unsigned u)
+{
+ return u<125259u?_hb_ucd_u8[8612+(((_hb_ucd_u8[8068+(((_hb_ucd_u8[7624+(((_hb_ucd_u8[7288+(((_hb_ucd_u8[7042+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0;
+}
+static inline unsigned
+_hb_ucd_b4 (const uint8_t* a, unsigned i)
+{
+ return (a[i>>1]>>((i&1u)<<2))&15u;
+}
+static inline int_fast16_t
+_hb_ucd_bmg (unsigned u)
+{
+ return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9356+(((_hb_ucd_u8[9236+(((_hb_ucd_b4(9108+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0;
+}
+static inline uint_fast8_t
+_hb_ucd_sc (unsigned u)
+{
+ return u<918000u?_hb_ucd_u8[10862+(((_hb_ucd_u16[2000+(((_hb_ucd_u8[10142+(((_hb_ucd_u8[9692+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2;
+}
+static inline uint_fast16_t
+_hb_ucd_dm (unsigned u)
+{
+ return u<195102u?_hb_ucd_u16[5888+(((_hb_ucd_u8[16764+(((_hb_ucd_u8[16382+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
+}
+
+
#else
static const uint8_t
-_hb_ucd_u8[13602] =
+_hb_ucd_u8[13246] =
{
0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 9, 10, 7, 7, 7, 7, 7, 11, 12, 12, 12, 13,
@@ -6146,331 +5025,309 @@ _hb_ucd_u8[13602] =
220, 0, 0,230,220, 0, 0, 0,220,220, 0, 0,230,220, 0, 9,
7, 0, 0, 7, 9, 0, 0, 0, 9, 7, 6, 6, 0, 0, 0, 0,
1, 0, 0,216,216, 1, 1, 1, 0, 0, 0,226,216,216,216,216,
- 216, 0,220,220,220, 0,230,230, 7, 0, 16, 17, 17, 17, 17, 17,
- 17, 33, 17, 17, 17, 19, 17, 17, 17, 17, 20,101, 17,113,129,169,
- 17, 27, 28, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 216, 0,220,220,220, 0,230,230, 7, 0, 16, 17, 17, 33, 17, 49,
+ 17, 17, 84, 97,135,145, 26, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17,177, 0, 1, 2, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3,
+ 3, 3, 3, 3, 5, 3, 3, 3, 3, 3, 6, 7, 8, 3, 3, 3,
+ 3, 3, 9, 10, 11, 12, 13, 3, 3, 3, 3, 3, 3, 3, 3, 14,
+ 3, 15, 3, 3, 3, 3, 3, 3, 16, 17, 18, 19, 20, 21, 3, 3,
+ 3, 22, 23, 24, 3, 3, 3, 3, 3, 3, 25, 3, 3, 3, 3, 3,
+ 3, 3, 3, 26, 3, 3, 27, 28, 0, 1, 0, 0, 0, 0, 0, 1,
+ 0, 2, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4,
+ 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 6, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 8, 9, 0, 0, 0, 0, 0, 0, 9, 0, 9, 0, 0, 0, 0,
+ 0, 0, 0, 10, 11, 12, 13, 0, 0, 14, 15, 16, 6, 0, 17, 18,
+ 19, 19, 19, 20, 21, 22, 23, 24, 19, 25, 0, 26, 27, 19, 19, 28,
+ 29, 30, 0, 31, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 19,
+ 28, 0, 32, 33, 9, 34, 35, 19, 0, 0, 36, 37, 38, 39, 40, 19,
+ 0, 41, 42, 43, 44, 31, 0, 1, 45, 42, 0, 0, 0, 0, 0, 32,
+ 14, 14, 0, 0, 0, 0, 14, 0, 0, 46, 47, 47, 47, 47, 48, 49,
+ 47, 47, 47, 47, 50, 51, 52, 53, 43, 21, 0, 0, 0, 0, 0, 0,
+ 0, 54, 6, 55, 0, 14, 19, 1, 0, 0, 0, 0, 56, 57, 0, 0,
+ 0, 0, 0, 19, 58, 31, 0, 0, 0, 0, 0, 0, 0, 59, 14, 0,
+ 0, 0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 60, 61, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 3, 0, 4,
+ 5, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 1, 1, 0, 0, 8,
+ 9, 0, 8, 9, 0, 0, 0, 0, 8, 9, 10, 11, 12, 0, 0, 0,
+ 13, 0, 0, 0, 0, 14, 15, 16, 17, 0, 0, 0, 1, 0, 0, 18,
+ 19, 0, 0, 0, 20, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1,
+ 1, 1, 1, 1, 0, 8, 21, 9, 0, 0, 22, 0, 0, 0, 0, 1,
+ 0, 23, 24, 25, 0, 0, 26, 0, 0, 0, 8, 21, 27, 0, 1, 0,
+ 0, 1, 1, 1, 1, 0, 1, 28, 29, 30, 0, 31, 32, 20, 1, 1,
+ 0, 0, 0, 8, 21, 9, 1, 4, 5, 0, 0, 0, 33, 9, 0, 1,
+ 1, 1, 0, 8, 21, 21, 21, 21, 34, 1, 35, 21, 21, 21, 9, 36,
+ 0, 0, 37, 38, 1, 0, 39, 0, 0, 0, 1, 0, 1, 0, 0, 0,
+ 0, 8, 21, 9, 1, 0, 0, 0, 40, 0, 8, 21, 21, 21, 21, 21,
+ 21, 21, 21, 9, 0, 1, 1, 1, 1, 8, 21, 21, 21, 9, 0, 0,
+ 0, 41, 0, 42, 43, 0, 0, 0, 1, 44, 0, 0, 0, 45, 8, 9,
+ 1, 0, 0, 0, 8, 21, 21, 21, 9, 0, 1, 0, 1, 1, 8, 21,
+ 21, 9, 0, 4, 5, 8, 9, 1, 0, 0, 0, 1, 2, 3, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 3, 3, 3, 3, 3, 3,
+ 3, 15, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 17, 17, 17, 17, 17, 17,237, 0, 1, 2, 2, 0, 3,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 6, 7, 8, 9, 0,
- 0, 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 24,
- 25, 26, 0, 27, 0, 28, 29, 30, 31, 32, 0, 0, 0, 0, 0, 0,
- 0, 33, 34, 35, 36, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 38, 39, 0, 0, 0, 0, 1, 2, 40, 41, 0, 1,
- 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
- 0, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 5, 0, 0, 0,
- 6, 0, 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 0, 0,
- 8, 9, 0, 0, 0, 0, 0, 0, 10, 0, 0, 10, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0,
- 0, 0, 0, 0, 11, 12, 0, 13, 0, 14, 15, 16, 0, 0, 0, 0,
- 0, 1, 17, 18, 0, 19, 7, 1, 0, 0, 0, 20, 20, 7, 20, 20,
- 20, 20, 20, 20, 20, 8, 21, 0, 22, 0, 7, 23, 24, 0, 20, 20,
- 25, 0, 0, 0, 26, 27, 1, 7, 20, 20, 20, 20, 20, 1, 28, 29,
- 30, 31, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0,
- 0, 0, 0, 0, 20, 20, 20, 1, 0, 0, 8, 21, 32, 4, 0, 10,
- 0, 33, 7, 20, 20, 20, 0, 0, 0, 0, 8, 34, 34, 35, 36, 34,
- 37, 0, 38, 1, 20, 20, 0, 0, 39, 0, 1, 1, 0, 8, 21, 1,
- 20, 0, 0, 0, 1, 0, 0, 40, 1, 1, 0, 0, 8, 21, 0, 1,
- 0, 1, 0, 1, 0, 0, 0, 0, 26, 34, 34, 34, 34, 34, 34, 34,
- 34, 34, 21, 7, 20, 41, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21,
- 0, 42, 43, 44, 0, 45, 0, 8, 21, 0, 0, 0, 0, 0, 0, 0,
- 0, 46, 7, 1, 10, 1, 0, 0, 0, 1, 20, 20, 1, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 26, 34, 9, 0, 0, 20, 20, 1, 20,
- 20, 0, 0, 0, 0, 0, 0, 0, 26, 21, 0, 1, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 3, 47, 48, 0, 0, 0, 0, 0,
- 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 9, 10, 11, 11, 11, 11, 11, 12, 12, 12,
- 12, 13, 14, 15, 16, 17, 18, 19, 20, 12, 21, 12, 12, 12, 12, 22,
- 23, 23, 23, 24, 12, 12, 12, 25, 26, 27, 12, 28, 29, 30, 31, 32,
- 33, 34, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 35,
- 12, 36, 7, 7, 37, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
- 12, 12, 38, 0, 0, 1, 2, 2, 2, 3, 4, 5, 6, 7, 8, 9,
- 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
- 26, 27, 28, 29, 30, 31, 32, 32, 33, 33, 33, 34, 35, 35, 35, 35,
- 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
- 2, 2, 51, 51, 52, 53, 54, 55, 56, 56, 56, 56, 56, 56, 56, 56,
- 56, 56, 56, 56, 57, 57, 56, 56, 56, 56, 56, 56, 58, 59, 60, 61,
- 56, 62, 62, 63, 64, 65, 66, 67, 68, 69, 70, 56, 62, 62, 62, 62,
- 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
- 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 71,
- 62, 62, 62, 62, 72, 72, 72, 72, 72, 72, 72, 72, 72, 73, 74, 74,
- 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 32, 32, 32, 32,
- 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
- 32, 32, 32, 32, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 87, 87, 62, 62, 62, 62, 88, 89, 89, 89, 90, 89,
- 91, 92, 93, 94, 95, 95, 96, 97, 87, 98, 99,100,101,102,103,104,
- 105,105,105, 2,106,107,108,109,110,111,112,113,114,115,116, 87,
- 89,117,118,119,120,121,122,123,124,125,126, 87,127,128, 87,129,
- 130,131,132, 87,133,134,135,136,137,138, 87, 87,139,140,141,142,
- 87,143, 87,144,145,145,145,145,145,145,145,145,145,145,145, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87,146,147,147,147,147,147,147,147,147,147, 87, 87, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,148,148,148,148,
- 148, 87, 87, 87,149,149,149,149,150,151,152,152, 87, 87, 87, 87,
- 153,153,154,155,156,156,156,156,156,156,156,156,156,156,156,156,
- 156,156,156,156,156,156,156,156,156,156,157,157,157,157,156, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87,158,159,160,161,162,162,162, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,163,164, 87, 87,
- 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,
- 87, 87,165, 56, 56, 56,166,167, 51, 56, 56, 87, 56, 56, 56, 56,
- 56, 56, 56, 56,168,168,168,168,168,168, 87, 87, 87, 87, 87, 87,
- 87, 87, 2, 87,169, 87,170, 87, 87,171, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 33,172,172,173, 87, 87, 87, 87, 87, 56, 56, 56, 87,
- 89, 89, 87, 87, 56, 56, 56, 56,174, 87, 56, 56, 56, 56, 56, 56,
- 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 87, 87, 87, 87,
- 87, 87, 87, 87, 62, 62, 62, 62, 62, 62, 62, 62, 87, 87, 87, 87,
- 87, 87, 87, 87, 62, 62, 62, 62, 62, 87, 87, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 62, 62, 62, 62, 62, 62, 62, 87, 87, 87, 87, 87,
- 87, 87, 87, 87, 56, 87,175,175, 0, 1, 2, 2, 0, 1, 2, 2,
- 2, 3, 4, 5, 0, 0, 0, 0, 1, 2, 1, 2, 0, 0, 3, 3,
- 4, 5, 4, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6,
- 0, 0, 7, 0, 8, 8, 8, 8, 8, 8, 8, 9, 10, 11, 11, 11,
- 11, 11, 12, 11, 13, 13, 13, 13, 13, 13, 13, 13, 14, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 15, 16, 16, 16, 16, 16, 17, 18, 18,
- 18, 18, 18, 18, 19, 20, 21, 21, 22, 23, 21, 24, 21, 21, 21, 21,
- 21, 25, 21, 21, 26, 26, 26, 26, 26, 21, 21, 21, 27, 27, 27, 27,
- 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 26, 21, 21, 21, 21, 21,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 0, 0, 1, 2, 3,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 17, 17,
+ 18, 17, 19, 20, 21, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 24, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 25, 25, 26, 27,
+ 28, 29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 52, 53, 31,
+ 31, 31, 31, 54, 55, 55, 56, 31, 31, 31, 31, 31, 31, 31, 57, 58,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 59, 60, 31, 61, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
+ 62, 63, 64, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 65, 66, 67, 31, 31, 31, 31, 68, 31, 31, 31, 31, 31,
+ 31, 31, 31, 69, 70, 71, 17, 17, 72, 73, 31, 74, 75, 76, 31, 77,
+ 78, 31, 79, 80, 17, 81, 17, 17, 17, 17, 31, 31, 23, 23, 23, 23,
+ 23, 23, 31, 31, 31, 31, 31, 31, 23, 82, 31, 31, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 83, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 84, 0, 0, 1,
+ 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3,
+ 4, 4, 4, 4, 4, 4, 5, 6, 7, 8, 9, 10, 11, 11, 12, 11,
+ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 19, 27,
+ 28, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36, 36,
+ 37, 37, 38, 38, 39, 40, 41, 41, 42, 42, 42, 43, 44, 44, 45, 46,
+ 47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 49, 50, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 52, 53, 54, 55, 56, 56, 57, 58, 59, 51,
+ 60, 61, 62, 63, 64, 65, 66, 7, 67, 67, 68, 69, 70, 71, 72, 73,
+ 74, 75, 76, 7, 4, 4, 4, 4, 77, 77, 77, 77, 78, 79, 80, 81,
+ 82, 83, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 85, 85,
+ 0, 0, 0, 0, 86, 87, 88, 88, 89, 90, 48, 91, 0, 0, 92, 92,
+ 92, 92, 92, 93, 94, 95, 96, 97, 98, 47, 99,100,101,102, 0,103,
+ 104,105, 0, 0, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
+ 92, 92, 92, 0,106,106,106,106,106,106,106,106,106,106,106,107,
+ 108,108,108,108,108, 11,109,110,111, 4,112, 4,113,114,115,116,
+ 117,118,119,120,121,122,123,124,125,126, 50,127, 47, 47, 47, 47,
+ 47, 47, 47, 47,128,128,128,128,128,128,128,128,128,128,128,128,
+ 92, 92, 92, 92, 92, 92, 92, 92,129,130, 19, 19, 19, 19, 19, 19,
+ 131, 19, 19, 19,132,133, 19,134,135,136,137,101,138,138,138,138,
+ 0, 77,139,140,128,128,141,142,143,144,145,146,147,148,149,150,
+ 151,152,153,153,154,154,154,154,154,154, 4, 4,155,156,157,158,
+ 159,160,161,162,163,164,165,166,167,168,169,169,170,170,171,171,
+ 172,172,128,128, 19, 19,173,173,174,175,176,177,178,178,179,180,
+ 181,182,183,184,185,185,186,187,188,189,128,128,190,190,191,191,
+ 128,128,192,192,193,194,195,195,196,196,128,128,197,197,198,198,
+ 199,199,200,200,201,202,203,204,128,128,128,128,205,206,207,207,
+ 208,209,210,210,128,128,211,211,128,128,212, 34,213,213,213,213,
+ 213,213,213,213,213,213,213,213,213,213,128,128,128,128,128,128,
+ 128,128,214,214,215,215,215,215,215,215,215,215,215,215,128,128,
+ 128,128,128,128,216,216,216,216,216,216,216,216,216,216,128,128,
+ 128,128,128,128,110,110,110,110,110,110,110,110,110,217,218,219,
+ 220,220,220,220,221,221,221,221,222,222,222,223,224,224,224,224,
+ 224,224,224,224,224,224,224,224,225,225,225,225,225,225,225,225,
+ 224,224,128,128,128,128,128,128,128,128,104,104,226,227,227,227,
+ 228,229,230,230,230,230,230,230,128,128,128,128,231,231,232, 0,
+ 128,128,128,128,128,128,128,128, 7,233, 0, 0, 0, 0, 0, 0,
+ 0,234,235, 0, 77, 77, 0, 0, 0, 0,128,128,236,236,236,236,
+ 236,236,236,236,236,236,236,236,128,128,128,128,128,128,128,128,
+ 4, 4,128,128, 86, 86,128,128,237,237,128,128,128,128,238,239,
+ 128,128,128,128,128,128,128,128,128,128, 48, 48,240,240,240,240,
+ 241,241,128,128, 0, 0, 0, 0, 0, 0,128,128, 19, 19, 19, 19,
+ 128,128,128,128,242, 0,128,128, 0, 0, 0, 0, 92, 92,128,128,
+ 128,128,128,128, 92, 92, 92, 92, 92, 92,128,128, 0, 0,128,128,
+ 7, 7, 7, 7, 0, 0, 0, 0, 1, 2, 1, 2, 0, 0, 3, 3,
+ 4, 5, 4, 5, 4, 4, 4, 4, 4, 4, 4, 6, 0, 0, 7, 0,
+ 8, 8, 8, 8, 8, 8, 8, 9, 10, 11, 11, 11, 11, 11, 12, 11,
+ 13, 13, 13, 13, 14, 13, 13, 13, 13, 13, 13, 15, 16, 16, 16, 16,
+ 16, 17, 18, 18, 18, 18, 18, 18, 19, 20, 21, 21, 22, 23, 21, 24,
+ 21, 21, 21, 21, 21, 25, 21, 21, 26, 26, 26, 26, 26, 21, 21, 21,
+ 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 26, 21,
21, 21, 31, 21, 32, 32, 32, 32, 32, 33, 34, 32, 35, 35, 35, 35,
- 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 36, 36, 37, 37, 37, 37,
- 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39,
- 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41,
- 41, 41, 41, 41, 42, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43,
- 43, 43, 43, 43, 44, 44, 44, 45, 44, 44, 44, 44, 46, 46, 46, 46,
- 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47,
- 47, 48, 47, 47, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 50, 50,
- 50, 50, 50, 51, 52, 52, 52, 52, 52, 52, 52, 52, 53, 53, 53, 53,
- 53, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 54, 55, 55, 55, 55,
+ 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
+ 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
+ 44, 44, 44, 45, 44, 44, 44, 44, 46, 46, 46, 46, 47, 47, 47, 47,
+ 47, 48, 47, 47, 49, 49, 49, 49, 49, 49, 50, 50, 50, 50, 50, 51,
+ 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 54,
55, 55, 55, 55, 56, 56, 57, 57, 57, 57, 58, 57, 59, 59, 60, 61,
- 62, 62, 63, 63, 64, 64, 64, 64, 64, 64, 64, 64, 65, 66, 66, 66,
- 66, 66, 66, 66, 66, 66, 66, 55, 55, 55, 55, 55, 67, 67, 67, 67,
- 67, 68, 68, 68, 69, 69, 69, 69, 69, 69, 64, 64, 70, 70, 71, 71,
- 71, 71, 71, 71, 71, 71, 71, 8, 8, 8, 8, 8, 72, 72, 72, 72,
+ 62, 62, 63, 63, 64, 64, 64, 64, 65, 66, 66, 66, 66, 66, 66, 66,
+ 66, 66, 66, 55, 67, 67, 67, 67, 67, 68, 68, 68, 69, 69, 69, 69,
+ 69, 69, 64, 64, 70, 70, 71, 71, 71, 71, 71, 71, 71, 71, 71, 8,
72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75,
75, 76, 76, 76, 13, 50, 50, 50, 73, 77, 78, 79, 4, 4, 80, 4,
- 4, 81, 82, 83, 4, 4, 4, 84, 8, 8, 8, 8, 11, 11, 11, 11,
- 11, 11, 11, 11, 85, 0, 0, 0, 0, 0, 0, 86, 0, 4, 0, 0,
- 0, 8, 8, 8, 0, 0, 87, 88, 89, 0, 4, 4, 6, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 90, 90, 90,
- 90, 90, 90, 90, 91, 91, 91, 91, 91, 91, 4, 4, 92, 92, 92, 92,
- 92, 92, 92, 92, 50, 50, 50, 93, 93, 93, 93, 93, 53, 53, 53, 53,
- 53, 53, 13, 13, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
- 94, 94, 94, 0, 95, 0, 96, 97, 98, 99, 99, 99, 99,100,101,102,
- 102,102,102,103,104,104,104,105, 52, 52, 52, 52, 52, 0,104,104,
- 0, 0, 0,102, 52, 52, 0, 0, 0, 0, 52,106, 0, 0, 0, 0,
- 0,102,102,107,102,102,102,102,102,108, 0, 0, 94, 94, 94, 94,
- 0, 0, 0, 0,109,109,109,109,109,109,109,109,109,109,109,109,
- 109,110,110,110,111,111,111,111,111,111,111,111,111,111,111,111,
- 13, 13, 13, 13, 13, 13,112,112,112,112,112,112, 0, 0,113, 4,
- 4, 4, 4, 4,114, 4, 4, 4, 4, 4, 4, 4,115,115,115, 0,
- 116,116,116,116,117,117,117,117,117,117, 32, 32,118,118,119,120,
- 120,120, 52, 52,121,121,121,121,122,121, 49, 49,123,123,123,123,
- 123,123, 49, 49,124,124,124,124,124,124,125,125, 53, 53, 53, 4,
- 4,126,127, 54, 54, 54, 54, 54,125,125,125,125,128,128,128,128,
- 128,128,128,128, 4,129, 18, 18, 18, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21,130, 21, 21, 21, 21, 8, 0,131, 0,
- 0, 0, 0, 21, 21, 21, 21, 21, 21, 21, 21,132, 0, 0, 1, 2,
- 1, 2,133,101,102,134, 52, 52, 52, 52, 0, 0,135,135,135,135,
- 135,135,135,135, 0, 0, 0, 0, 11, 11, 11, 11, 11, 0, 11, 11,
- 11, 0, 0,136,137,137,138,138,138,138,139, 0,140,140,140,141,
- 141,142,142,142,143,143,144,144,144,144,144,144,145,145,145,145,
- 145,146,146,146,147,147,147,148,148,148,148,148,149,149,149,150,
- 150,150,150,151,151,151,151,151,151,151,151,151,152,152,152,152,
- 152,152,152,152,153,153,153,153,154,154,155,155,156,156,156,156,
- 156,156,157,157,158,158,159,159,159,159,159,159,160,160,161,161,
- 161,161,161,161,162,162,162,162,162,162,163,163,164,164,164,164,
- 165,165,165,165,166,166,166,166,167,167,168,168,169,169,169,169,
- 169,169,169,169,170,170,170,170,170,170,170,170,171,171,171,171,
- 171,171,171,171,172,172,172,172,172,172,172,172,173,173,173,173,
- 173,173,173,173,174,174,174,175,175,175,175,176,176,176,176,177,
- 177,177,178,178,179,179,179,179,179,179,179,179,180,180,180,180,
- 180,181,181,181,182,182,182,182,182,183,183,183,184,184,184,184,
- 184,184,185, 43,186,186,186,186,186,186,186,186,187,187,187,188,
+ 4, 81, 82, 83, 4, 4, 4, 84, 11, 11, 11, 11, 85, 0, 0, 0,
+ 0, 0, 0, 86, 0, 4, 0, 0, 0, 8, 8, 8, 0, 0, 87, 88,
+ 89, 0, 4, 4, 6, 0, 0, 0, 90, 90, 90, 90, 91, 91, 91, 91,
+ 91, 91, 4, 4, 92, 92, 92, 92, 50, 50, 50, 93, 93, 93, 93, 93,
+ 53, 53, 13, 13, 94, 94, 94, 94, 94, 94, 94, 0, 95, 0, 96, 97,
+ 98, 99, 99, 99, 99,100,101,102,102,102,102,103,104,104,104,105,
+ 52, 0,104,104, 0, 0, 0,102, 52, 52, 0, 0, 0, 0, 52,106,
+ 0,102,102,107,102,102,102,102,102,108, 0, 0,109,109,109,109,
+ 109,110,110,110,111,111,111,111, 13, 13,112,112,112,112,112,112,
+ 0, 0,113, 4,114, 4, 4, 4,115,115,115, 0,116,116,116,116,
+ 117,117,117,117,117,117, 32, 32,118,118,119,120,120,120, 52, 52,
+ 121,121,121,121,122,121, 49, 49,123,123,123,123,123,123, 49, 49,
+ 124,124,124,124,124,124,125,125, 53, 53, 53, 4, 4,126,127, 54,
+ 125,125,125,125,128,128,128,128, 4,129, 18, 18, 18, 21, 21, 21,
+ 21, 21, 21,130, 8, 0,131, 0, 0, 0, 0, 21, 21, 21, 21,132,
+ 0, 0, 1, 2, 1, 2,133,101,102,134, 52, 52,135,135,135,135,
+ 11, 0, 11, 11, 11, 0, 0,136,137,137,138,138,138,138,139, 0,
+ 140,140,140,141,141,142,142,142,143,143,144,144,144,144,144,144,
+ 145,145,145,145,145,146,146,146,147,147,147,148,148,148,148,148,
+ 149,149,149,150,150,150,150,151,151,151,151,151,152,152,152,152,
+ 153,153,153,153,154,154,155,155,156,156,156,156,156,156,157,157,
+ 158,158,159,159,159,159,159,159,160,160,161,161,161,161,161,161,
+ 162,162,162,162,162,162,163,163,164,164,164,164,165,165,165,165,
+ 166,166,166,166,167,167,168,168,169,169,169,169,170,170,170,170,
+ 171,171,171,171,172,172,172,172,173,173,173,173,174,174,174,175,
+ 175,175,175,176,176,176,176,177,177,177,178,178,179,179,179,179,
+ 180,180,180,180,180,181,181,181,182,182,182,182,182,183,183,183,
+ 184,184,184,184,184,184,185, 43,186,186,186,186,187,187,187,188,
188,188,188,188,189,189,189,190,189,189,189,189,191,191,191,191,
- 191,191,191,191,192,192,192,192,192,192,192,192,193,193,193,193,
- 193,193,193,193,194,194,194,194,194,194, 66, 66,195,195,195,195,
- 195,195,195,195,196,196,196,196,196,196,196,196,197,197,197,197,
- 197,197,197,197,198,198,198,198,198,198,198,198,199,199,199,199,
- 199,199,199,199,200,200,200,200,200,200,200,200,201,201,201,201,
- 201,202,202,202,202,202,202, 55,203,203,203,203,204,204,204,204,
- 204,204,204,205,205,205,205,205,205,205,205,205,206,206,206,206,
- 206,206,207,207,207,207,207,207,207,207,207,207,208,208,208,208,
- 208,208,208,208,110,110,110,110, 39, 39, 39, 39,209,209,209,209,
- 209,209,209,209,210,210,210,210,210,210,210,210,211,211,211,211,
- 211,211,211,211,212,212,212,212,212,212,212,212,112,112,112,112,
- 112,112,112,112,112,112,112,112,213,213,213,214,214,214,214,214,
- 214,215,215,215,216,216,216,216,216,216,216,216,217,217,217,217,
- 217,217,217,217,218,218,218,218,218,218,218,218,218,218,218,218,
- 218,218,219, 94,220,220,220,220,220,220,220,220,221,221,221,221,
- 221,221,221,221,102,102,102,102,102,102,102,102,222, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,102,102,
- 102, 99,223,224,224,224,224,224,224,224,224,224,225,225,225,225,
- 225,225,225,225,225,225, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8,
- 8, 0, 0, 0, 0, 0, 0, 0, 0, 0,226,227,228, 0,229, 0,
- 0, 0, 0, 0,230,230,230,230,230,230,230,230, 91, 91, 91, 91,
- 91, 91, 91, 91,231,231,231,231,231,231,231,231,232,232,232,232,
- 233,233,233,233,234,234,234,234,234,234,234,234,235,235,235,235,
- 235,235,235,235,236, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8,
- 8, 8, 8, 8, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 3, 0,
- 0, 0, 4, 0, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 5, 0,
- 2, 5, 6, 0, 7, 7, 7, 7, 8, 9, 8, 10, 8, 11, 8, 8,
- 8, 8, 8, 8, 12, 13, 13, 13, 14, 14, 14, 14, 14, 15, 14, 14,
- 16, 17, 17, 17, 17, 17, 17, 17, 18, 19, 19, 19, 19, 19, 19, 19,
- 20, 21, 20, 22, 20, 20, 23, 23, 20, 20, 20, 20, 22, 20, 24, 7,
- 7, 25, 20, 20, 26, 20, 20, 20, 20, 20, 20, 21, 27, 27, 27, 27,
- 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
- 32, 20, 20, 20, 33, 33, 33, 33, 34, 35, 33, 33, 33, 36, 33, 33,
- 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40,
- 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 44,
- 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 47, 48, 48, 48, 48,
- 49, 49, 49, 49, 49, 50, 51, 49, 52, 52, 52, 52, 53, 53, 53, 53,
- 53, 53, 54, 53, 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57,
- 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 61, 62,
- 63, 63, 63, 63, 64, 64, 64, 64, 64, 65, 0, 0, 66, 66, 66, 66,
- 67, 67, 67, 67, 68, 68, 68, 68, 69, 70, 71, 71, 71, 71, 71, 71,
- 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75,
- 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, 78, 78, 79, 79, 79, 79,
- 80, 80, 80, 80, 81, 81, 81, 81, 82, 7, 7, 7, 83, 7, 84, 85,
- 0, 84, 86, 0, 2, 87, 88, 2, 2, 2, 2, 89, 90, 87, 91, 2,
- 2, 2, 92, 2, 2, 2, 2, 93, 0, 0, 0, 86, 1, 0, 0, 94,
- 0, 95, 96, 0, 4, 0, 0, 0, 0, 0, 0, 4, 97, 97, 97, 97,
- 98, 98, 98, 98, 13, 13, 13, 13, 99, 99, 99, 99,100,100,100,100,
- 0,101, 0, 0,102,100,103,104, 0, 0,100, 0,105,106,106,106,
- 106,106,106,106,106,106,107,105,108,109,109,109,109,109,109,109,
- 109,109,110,108,111,111,111,111,112, 55, 55, 55, 55, 55, 55,113,
- 109,109,109,110,109,109, 0, 0,114,114,114,114,115,115,115,115,
- 116,116,116,116,117,117,117,117, 96, 2, 2, 2, 2, 2, 94, 2,
- 118,118,118,118,119,119,119,119,120,120,120,120,121,121,121,121,
- 121,121,121,122,123,123,123,123,124,124,124,124,124,124,124,125,
- 126,126,126,126,127,127,127,127,128,128,128,128, 2, 2, 3, 2,
- 2,129,130, 0,131,131,131,131,132, 17, 17, 18, 20, 20, 20,133,
- 7, 7, 7,134, 20, 20, 20, 23, 0,135,109,109,109,109,109,136,
- 137,137,137,137, 0, 0, 0,138,139,139,139,139,140,140,140,140,
- 84, 0, 0, 0,141,141,141,141,142,142,142,142,143,143,143,143,
- 144,144,144,144,145,145,145,145,146,146,146,146,147,147,147,147,
- 148,148,148,148,149,149,149,149,150,150,150,150,151,151,151,151,
- 152,152,152,152,153,153,153,153,154,154,154,154,155,155,155,155,
- 156,156,156,156,157,157,157,157,158,158,158,158,159,159,159,159,
- 160,160,160,160,161,161,161,161,162,162,162,162,163,163,163,163,
- 164,164,164,164,165,165,165,165,166,166,166,166,167,167,167,167,
- 168,168,168,168,169,169,169,169,170,170,170,170,171,171,171,171,
- 172,172,172,172,173,173,173,173,174,174,174,174,175,175,175,175,
- 176,176,176,176,177,177,177,177,178,178,178,178,179,179,179,179,
- 180,180,180,180,181,181,181,181,182,182,182,182,183,183,183,183,
- 184,184,184,184,185,185,185,185,186, 45, 45, 45,187,187,187,187,
- 188,188,188,188,189,189,189,189,190,190,190,190,190,190,191,190,
- 192,192,192,192,193,193,193,193,194,194,194,194,195,195,195,195,
- 196,196,196,196,197,197,197,197,198,198,198,198,199,199,199,199,
- 200,200,200,200,201,201,201,201,202,202,202,202,203,203,203,203,
- 204,204,204,204,205,205,205,205,206,206,206,206,207,207,207,207,
- 208,208,208,208,209,209,209,209,210,210,210,210,211,211,211,211,
- 212,212,212,212,213,213,213,213,214,214,214,214,215,215,215,215,
- 216,216,216,216,217,217,217,217,218,218,218,218,219,219,219,219,
- 220,221,221,221,222,222,222,222,221,221,221,221,223,106,106,106,
- 106,109,109,109,224,224,224,224,225,225,225,225, 0,226, 86, 0,
- 0, 0,226, 7, 82,138, 7, 0, 0, 0,227, 86,228,228,228,228,
- 229,229,229,229,230,230,230,230,231,231,231,231,232,232,232,232,
- 233,233,233,233,234, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 19, 0, 19, 0, 0, 0,
- 0, 0, 26, 26, 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, 9, 9,
- 9, 9, 0, 9, 9, 0, 9, 0, 9, 9, 55, 55, 55, 55, 55, 55,
- 6, 6, 6, 6, 6, 1, 1, 6, 6, 4, 4, 4, 4, 4, 4, 4,
- 4, 14, 14, 14, 14, 14, 14, 14, 3, 3, 3, 3, 3, 0, 3, 3,
- 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 1, 1, 1, 3, 3,
- 1, 3, 3, 3, 37, 37, 37, 37, 38, 38, 38, 38, 64, 64, 64, 64,
- 90, 90, 90, 90, 95, 95, 95, 95, 3, 3, 0, 3, 7, 7, 7, 7,
- 7, 1, 1, 1, 1, 7, 7, 7, 0, 0, 7, 7, 5, 5, 5, 5,
- 11, 11, 11, 11, 10, 10, 10, 10, 21, 21, 21, 21, 22, 22, 22, 22,
- 23, 23, 23, 23, 16, 16, 16, 16, 20, 20, 20, 20, 36, 36, 36, 36,
- 24, 24, 24, 24, 24, 24, 24, 0, 18, 18, 18, 18, 25, 25, 25, 25,
- 25, 0, 0, 0, 0, 25, 25, 25, 33, 33, 33, 33, 8, 8, 8, 8,
- 8, 8, 8, 0, 12, 12, 12, 12, 30, 30, 30, 30, 29, 29, 29, 29,
- 28, 28, 28, 28, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, 35, 0,
- 0, 0, 35, 35, 45, 45, 45, 45, 44, 44, 44, 44, 44, 0, 0, 0,
- 43, 43, 43, 43, 46, 46, 46, 46, 31, 31, 31, 31, 32, 32, 0, 0,
- 32, 0, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 52, 52, 52, 52,
- 58, 58, 58, 58, 54, 54, 54, 54, 91, 91, 91, 91, 62, 62, 62, 62,
- 76, 76, 76, 76, 93, 93, 93, 93, 70, 70, 70, 70, 73, 73, 73, 73,
- 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0,
- 1, 1, 0, 0, 19, 19, 9, 9, 9, 9, 9, 6, 19, 9, 9, 9,
- 9, 9, 19, 19, 9, 9, 9, 19, 6, 19, 19, 19, 19, 19, 19, 9,
- 0, 0, 0, 19, 0, 0, 9, 0, 0, 0, 19, 19, 27, 27, 27, 27,
- 56, 56, 56, 56, 61, 61, 61, 61, 13, 13, 13, 13, 0, 13, 0, 13,
- 0, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, 0, 15, 15, 15,
- 15, 15, 15, 15, 15, 1, 1, 0, 0, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17, 0, 26, 26, 26, 26, 26, 12, 12, 12, 12, 12, 12, 0,
- 39, 39, 39, 39, 86, 86, 86, 86, 77, 77, 77, 77, 79, 79, 79, 79,
- 60, 60, 60, 60, 65, 65, 65, 65, 75, 75, 75, 75, 69, 69, 69, 69,
- 69, 69, 0, 69, 74, 74, 74, 74, 84, 84, 84, 84, 84, 84, 84, 0,
- 68, 68, 68, 68, 92, 92, 92, 92, 87, 87, 87, 87, 19, 9, 19, 19,
- 19, 19, 0, 0, 2, 2, 2, 2, 19, 19, 19, 4, 3, 3, 0, 0,
- 1, 1, 6, 6, 0, 0, 17, 17, 17, 17, 0, 0, 49, 49, 49, 49,
- 0, 1, 1, 1, 71, 71, 71, 71, 67, 67, 67, 67, 42, 42, 42, 42,
- 41, 41, 41, 41,118,118,118,118, 53, 53, 53, 53, 59, 59, 59, 59,
- 40, 40, 40, 40, 51, 51, 51, 51, 50, 50, 50, 50,135,135,135,135,
- 106,106,106,106,104,104,104,104,161,161,161,161,110,110,110,110,
- 47, 47, 47, 47, 81, 81, 81, 81,120,120,120,120,116,116,116,116,
- 128,128,128,128, 66, 66, 66, 66, 72, 72, 72, 72, 98, 98, 98, 98,
- 97, 97, 97, 97, 57, 57, 57, 57, 88, 88, 88, 88,117,117,117,117,
- 112,112,112,112, 78, 78, 78, 78, 83, 83, 83, 83, 82, 82, 82, 82,
- 122,122,122,122, 89, 89, 89, 89,130,130,130,130,144,144,144,144,
- 156,156,156,156,147,147,147,147,148,148,148,148,158,158,158,158,
- 153,153,153,153,149,149,149,149, 94, 94, 94, 94, 85, 85, 85, 85,
- 101,101,101,101, 96, 96, 96, 96,111,111,111,111,100,100,100,100,
- 100, 36, 36, 36,108,108,108,108,129,129,129,129,109,109,109,109,
- 107,107,107,107,107,107,107, 1,137,137,137,137,124,124,124,124,
- 123,123,123,123,114,114,114,114,102,102,102,102,126,126,126,126,
- 142,142,142,142,125,125,125,125,154,154,154,154,150,150,150,150,
- 141,141,141,141,140,140,140,140,121,121,121,121,133,133,133,133,
- 134,134,134,134,138,138,138,138,143,143,143,143,145,145,145,145,
- 63, 63, 63, 63,157,157,157,157, 80, 80, 80, 80,127,127,127,127,
- 115,115,115,115,159,159,159,159,103,103,103,103,119,119,119,119,
- 146,146,146,146, 99, 99, 99, 99,136,139, 13, 13,155,155,155,155,
- 136,136,136,136, 17, 15, 15, 15,139,139,139,139,105,105,105,105,
- 0, 0, 0, 1, 0, 0, 1, 1,131,131,131,131,151,151,151,151,
- 160,160,160,160,152,152,152,152,113,113,113,113,132,132,132,132,
- 15, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9,
- 9, 10, 9, 11, 12, 13, 9, 9, 9, 14, 9, 9, 15, 9, 9, 9,
+ 192,192,192,192,193,193,193,193,194,194,194,194,194,194, 66, 66,
+ 195,195,195,195,196,196,196,196,197,197,197,197,198,198,198,198,
+ 199,199,199,199,200,200,200,200,201,201,201,201,201,202,202,202,
+ 202,202,202, 55,203,203,203,203,204,204,204,204,204,204,204,205,
+ 205,205,205,205,206,206,206,206,206,206,207,207,207,207,207,207,
+ 208,208,208,208,110,110,110,110,209,209,209,209,210,210,210,210,
+ 211,211,211,211,212,212,212,212,213,213,213,214,214,214,214,214,
+ 214,215,215,215,216,216,216,216,217,217,217,217,218,218,218,218,
+ 218,218,219, 94,220,220,220,220,221,221,221,221,222, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99,102,102,102, 99,223,224,224,224,224,224,
+ 225,225,225,225,225,225, 0, 0, 8, 0, 0, 0, 0, 0,226,227,
+ 228, 0,229, 0,230,230,230,230,231,231,231,231,232,232,232,232,
+ 233,233,233,233,234,234,234,234,235,235,235,235,236, 0, 0, 0,
+ 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 3, 0, 0, 0, 4, 0,
+ 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 5, 0, 2, 5, 6, 0,
+ 7, 7, 7, 7, 8, 9, 8, 10, 8, 11, 8, 8, 8, 8, 8, 8,
+ 12, 13, 13, 13, 14, 14, 14, 14, 14, 15, 14, 14, 16, 17, 17, 17,
+ 17, 17, 17, 17, 18, 19, 19, 19, 19, 19, 19, 19, 20, 21, 20, 22,
+ 20, 20, 23, 23, 20, 20, 20, 20, 22, 20, 24, 7, 7, 25, 20, 20,
+ 26, 20, 20, 20, 20, 20, 20, 21, 27, 27, 27, 27, 28, 28, 28, 28,
+ 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 32, 20, 20, 20,
+ 33, 33, 33, 33, 34, 35, 33, 33, 33, 36, 33, 33, 37, 37, 37, 37,
+ 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41,
+ 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45,
+ 46, 46, 46, 46, 46, 46, 46, 47, 48, 48, 48, 48, 49, 49, 49, 49,
+ 49, 50, 51, 49, 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 54, 53,
+ 55, 55, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58,
+ 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 61, 62, 63, 63, 63, 63,
+ 64, 64, 64, 64, 64, 65, 0, 0, 66, 66, 66, 66, 67, 67, 67, 67,
+ 68, 68, 68, 68, 69, 70, 71, 71, 71, 71, 71, 71, 72, 72, 72, 72,
+ 73, 73, 73, 73, 74, 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76,
+ 77, 77, 77, 77, 78, 78, 78, 78, 79, 79, 79, 79, 80, 80, 80, 80,
+ 81, 81, 81, 81, 82, 7, 7, 7, 83, 7, 84, 85, 0, 84, 86, 0,
+ 2, 87, 88, 2, 2, 2, 2, 89, 90, 87, 91, 2, 2, 2, 92, 2,
+ 2, 2, 2, 93, 0, 0, 0, 86, 1, 0, 0, 94, 0, 95, 96, 0,
+ 4, 0, 0, 0, 0, 0, 0, 4, 97, 97, 97, 97, 98, 98, 98, 98,
+ 13, 13, 13, 13, 99, 99, 99, 99,100,100,100,100, 0,101, 0, 0,
+ 102,100,103,104, 0, 0,100, 0,105,106,106,106,106,106,106,106,
+ 106,106,107,105,108,109,109,109,109,109,109,109,109,109,110,108,
+ 111,111,111,111,112, 55, 55, 55, 55, 55, 55,113,109,109,109,110,
+ 109,109, 0, 0,114,114,114,114,115,115,115,115,116,116,116,116,
+ 117,117,117,117, 96, 2, 2, 2, 2, 2, 94, 2,118,118,118,118,
+ 119,119,119,119,120,120,120,120,121,121,121,121,121,121,121,122,
+ 123,123,123,123,124,124,124,124,124,124,124,125,126,126,126,126,
+ 127,127,127,127,128,128,128,128, 2, 2, 3, 2, 2,129,130, 0,
+ 131,131,131,131,132, 17, 17, 18, 20, 20, 20,133, 7, 7, 7,134,
+ 20, 20, 20, 23, 0,135,109,109,109,109,109,136,137,137,137,137,
+ 0, 0, 0,138,139,139,139,139,140,140,140,140, 84, 0, 0, 0,
+ 141,141,141,141,142,142,142,142,143,143,143,143,144,144,144,144,
+ 145,145,145,145,146,146,146,146,147,147,147,147,148,148,148,148,
+ 149,149,149,149,150,150,150,150,151,151,151,151,152,152,152,152,
+ 153,153,153,153,154,154,154,154,155,155,155,155,156,156,156,156,
+ 157,157,157,157,158,158,158,158,159,159,159,159,160,160,160,160,
+ 161,161,161,161,162,162,162,162,163,163,163,163,164,164,164,164,
+ 165,165,165,165,166,166,166,166,167,167,167,167,168,168,168,168,
+ 169,169,169,169,170,170,170,170,171,171,171,171,172,172,172,172,
+ 173,173,173,173,174,174,174,174,175,175,175,175,176,176,176,176,
+ 177,177,177,177,178,178,178,178,179,179,179,179,180,180,180,180,
+ 181,181,181,181,182,182,182,182,183,183,183,183,184,184,184,184,
+ 185,185,185,185,186, 45, 45, 45,187,187,187,187,188,188,188,188,
+ 189,189,189,189,190,190,190,190,190,190,191,190,192,192,192,192,
+ 193,193,193,193,194,194,194,194,195,195,195,195,196,196,196,196,
+ 197,197,197,197,198,198,198,198,199,199,199,199,200,200,200,200,
+ 201,201,201,201,202,202,202,202,203,203,203,203,204,204,204,204,
+ 205,205,205,205,206,206,206,206,207,207,207,207,208,208,208,208,
+ 209,209,209,209,210,210,210,210,211,211,211,211,212,212,212,212,
+ 213,213,213,213,214,214,214,214,215,215,215,215,216,216,216,216,
+ 217,217,217,217,218,218,218,218,219,219,219,219,220,221,221,221,
+ 222,222,222,222,221,221,221,221,223,106,106,106,106,109,109,109,
+ 224,224,224,224,225,225,225,225, 0,226, 86, 0, 0, 0,226, 7,
+ 82,138, 7, 0, 0, 0,227, 86,228,228,228,228,229,229,229,229,
+ 230,230,230,230,231,231,231,231,232,232,232,232,233,233,233,233,
+ 234, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 0, 0, 0, 19, 0, 19, 0, 0, 0, 0, 0, 26, 26,
+ 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, 9, 9, 9, 9, 0, 9,
+ 9, 0, 9, 0, 9, 9, 55, 55, 55, 55, 55, 55, 6, 6, 6, 6,
+ 6, 1, 1, 6, 6, 4, 4, 4, 4, 4, 4, 4, 4, 14, 14, 14,
+ 14, 14, 14, 14, 3, 3, 3, 3, 3, 0, 3, 3, 0, 3, 3, 3,
+ 3, 3, 3, 0, 3, 3, 3, 1, 1, 1, 3, 3, 1, 3, 3, 3,
+ 37, 37, 37, 37, 38, 38, 38, 38, 64, 64, 64, 64, 90, 90, 90, 90,
+ 95, 95, 95, 95, 3, 3, 0, 3, 7, 7, 7, 7, 7, 1, 1, 1,
+ 1, 7, 7, 7, 0, 0, 7, 7, 5, 5, 5, 5, 11, 11, 11, 11,
+ 10, 10, 10, 10, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
+ 16, 16, 16, 16, 20, 20, 20, 20, 36, 36, 36, 36, 24, 24, 24, 24,
+ 24, 24, 24, 0, 18, 18, 18, 18, 25, 25, 25, 25, 25, 0, 0, 0,
+ 0, 25, 25, 25, 33, 33, 33, 33, 8, 8, 8, 8, 8, 8, 8, 0,
+ 12, 12, 12, 12, 30, 30, 30, 30, 29, 29, 29, 29, 28, 28, 28, 28,
+ 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, 35, 0, 0, 0, 35, 35,
+ 45, 45, 45, 45, 44, 44, 44, 44, 44, 0, 0, 0, 43, 43, 43, 43,
+ 46, 46, 46, 46, 31, 31, 31, 31, 32, 32, 0, 0, 32, 0, 32, 32,
+ 32, 32, 32, 32, 48, 48, 48, 48, 52, 52, 52, 52, 58, 58, 58, 58,
+ 54, 54, 54, 54, 91, 91, 91, 91, 62, 62, 62, 62, 76, 76, 76, 76,
+ 93, 93, 93, 93, 70, 70, 70, 70, 73, 73, 73, 73, 1, 1, 1, 0,
+ 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0,
+ 19, 19, 9, 9, 9, 9, 9, 6, 19, 9, 9, 9, 9, 9, 19, 19,
+ 9, 9, 9, 19, 6, 19, 19, 19, 19, 19, 19, 9, 0, 0, 0, 19,
+ 0, 0, 9, 0, 0, 0, 19, 19, 27, 27, 27, 27, 56, 56, 56, 56,
+ 61, 61, 61, 61, 13, 13, 13, 13, 0, 13, 0, 13, 0, 13, 13, 13,
+ 13, 13, 1, 1, 1, 1, 12, 12, 0, 15, 15, 15, 15, 15, 15, 15,
+ 15, 1, 1, 0, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 0,
+ 26, 26, 26, 26, 26, 12, 12, 12, 12, 12, 12, 0, 39, 39, 39, 39,
+ 86, 86, 86, 86, 77, 77, 77, 77, 79, 79, 79, 79, 60, 60, 60, 60,
+ 65, 65, 65, 65, 75, 75, 75, 75, 69, 69, 69, 69, 69, 69, 0, 69,
+ 74, 74, 74, 74, 84, 84, 84, 84, 84, 84, 84, 0, 68, 68, 68, 68,
+ 92, 92, 92, 92, 87, 87, 87, 87, 19, 9, 19, 19, 19, 19, 0, 0,
+ 2, 2, 2, 2, 19, 19, 19, 4, 3, 3, 0, 0, 1, 1, 6, 6,
+ 0, 0, 17, 17, 17, 17, 0, 0, 49, 49, 49, 49, 0, 1, 1, 1,
+ 71, 71, 71, 71, 67, 67, 67, 67, 42, 42, 42, 42, 41, 41, 41, 41,
+ 118,118,118,118, 53, 53, 53, 53, 59, 59, 59, 59, 40, 40, 40, 40,
+ 51, 51, 51, 51, 50, 50, 50, 50,135,135,135,135,106,106,106,106,
+ 104,104,104,104,161,161,161,161,110,110,110,110, 47, 47, 47, 47,
+ 81, 81, 81, 81,120,120,120,120,116,116,116,116,128,128,128,128,
+ 66, 66, 66, 66, 72, 72, 72, 72, 98, 98, 98, 98, 97, 97, 97, 97,
+ 57, 57, 57, 57, 88, 88, 88, 88,117,117,117,117,112,112,112,112,
+ 78, 78, 78, 78, 83, 83, 83, 83, 82, 82, 82, 82,122,122,122,122,
+ 89, 89, 89, 89,130,130,130,130,144,144,144,144,156,156,156,156,
+ 147,147,147,147,148,148,148,148,158,158,158,158,153,153,153,153,
+ 149,149,149,149, 94, 94, 94, 94, 85, 85, 85, 85,101,101,101,101,
+ 96, 96, 96, 96,111,111,111,111,100,100,100,100,100, 36, 36, 36,
+ 108,108,108,108,129,129,129,129,109,109,109,109,107,107,107,107,
+ 107,107,107, 1,137,137,137,137,124,124,124,124,123,123,123,123,
+ 114,114,114,114,102,102,102,102,126,126,126,126,142,142,142,142,
+ 125,125,125,125,154,154,154,154,150,150,150,150,141,141,141,141,
+ 140,140,140,140,121,121,121,121,133,133,133,133,134,134,134,134,
+ 138,138,138,138,143,143,143,143,145,145,145,145, 63, 63, 63, 63,
+ 157,157,157,157, 80, 80, 80, 80,127,127,127,127,115,115,115,115,
+ 159,159,159,159,103,103,103,103,119,119,119,119,146,146,146,146,
+ 99, 99, 99, 99,136,139, 13, 13,155,155,155,155,136,136,136,136,
+ 17, 15, 15, 15,139,139,139,139,105,105,105,105, 0, 0, 0, 1,
+ 0, 0, 1, 1,131,131,131,131,151,151,151,151,160,160,160,160,
+ 152,152,152,152,113,113,113,113,132,132,132,132, 15, 0, 0, 0,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 10, 9, 11,
+ 12, 13, 9, 9, 9, 14, 9, 9, 15, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 16, 17, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 18, 19, 20, 9, 21, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 16, 17, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 19, 20, 9,
- 21, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 22, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 22, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
@@ -6479,58 +5336,57 @@ _hb_ucd_u8[13602] =
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
- 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2,
- 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 13, 14, 15, 16,
- 17, 18, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 23, 0, 0, 24, 25, 26, 27, 28, 29, 30,
- 0, 0, 31, 32, 0, 33, 0, 34, 0, 35, 0, 0, 0, 0, 36, 37,
- 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 23, 24, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 0, 0, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 23, 0, 0, 24, 25, 26, 27, 28, 29, 30, 0, 0, 31, 32,
+ 0, 33, 0, 34, 0, 35, 0, 0, 0, 0, 36, 37, 38, 39, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, 46, 47, 0, 0, 0, 0,
+ 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 50, 51, 0, 0, 0, 52, 0, 0, 53, 0, 0, 0, 0, 0,
+ 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0,
+ 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, 46, 47,
- 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 50, 51, 0, 0, 0, 52, 0, 0, 53, 0,
- 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 55, 0,
- 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 57,
+ 0, 0, 58, 59, 60, 61, 62, 63, 64, 65, 0, 0, 0, 0, 0, 0,
+ 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 58, 59, 60, 61, 62, 63, 64, 65, 0, 0,
- 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 68,
+ 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71, 72,
+ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 104, 0, 0, 0, 0, 0, 0,105,106, 0,107, 0, 0, 0,108, 0,
+ 109, 0,110, 0,111,112,113, 0,114, 0, 0, 0,115, 0, 0, 0,
+ 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,117, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 67, 68, 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
- 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,
- 101,102,103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0,105,106, 0,107, 0,
- 0, 0,108, 0,109, 0,110, 0,111,112,113, 0,114, 0, 0, 0,
- 115, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,117,
+ 0, 0,118,119,120,121, 0,122,123,124,125,126, 0,127, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,118,119,120,121, 0,122,123,124,125,126,
- 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128,129,
+ 130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,
+ 146,147,148,149,150,151,152,153,154,155,156,157, 0, 0, 0,158,
+ 159,160,161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0,162,163, 0, 0, 0, 0, 0, 0, 0,
+ 164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0,128,129,130,131,132,133,134,135,136,137,138,139,140,141,
- 142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,
- 0, 0, 0,158,159,160,161, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,162,163, 0, 0, 0,
- 0, 0, 0, 0,164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0,165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0,167, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0,165, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,166, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,167, 0, 0,
+ 0,168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0,168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0,169,170, 0, 0, 0, 0,171,172, 0, 0, 0,173,174,
+ 175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,
+ 191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,169,170, 0, 0, 0, 0,171,172, 0,
- 0, 0,173,174,175,176,177,178,179,180,181,182,183,184,185,186,
- 187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,
- 203,204,205,206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2,
- 3, 4,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4,
};
static const uint16_t
_hb_ucd_u16[4888] =
@@ -6843,21 +5699,14 @@ _hb_ucd_u16[4888] =
817, 818, 819, 820, 821, 935, 0, 0,
};
static const int16_t
-_hb_ucd_i16[196] =
+_hb_ucd_i16[92] =
{
- 0, 0, 0, 0, 1, -1, 0, 0, 2, 0, -2, 0, 0, 0, 0, 2,
- 0, -2, 0, 0, 0, 0, 0, 16, 0, 0, 0, -16, 0, 0, 1, -1,
- 0, 0, 0, 1, -1, 0, 0, 0, 0, 1, -1, 0, 3, 3, 3, -3,
- -3, -3, 0, 0, 0, 2016, 0, 0, 0, 0, 0, 2527, 1923, 1914, 1918, 0,
- 2250, 0, 0, 0, 0, 0, 0, 138, 0, 7, 0, 0, -7, 0, 0, 0,
- 1, -1, 1, -1, -1, 1, -1, 0, 1824, 0, 0, 0, 0, 0, 2104, 0,
- 2108, 2106, 0, 2106, 1316, 0, 0, 0, 0, 1, -1, 1, -1, -138, 0, 0,
- 1, -1, 8, 8, 8, 0, 7, 7, 0, 0, -8, -8, -8, -7, -7, 0,
- 1, -1, 0, 2,-1316, 1, -1, 0, -1, 1, -1, 1, -1, 3, 1, -1,
- -3, 1, -1, 1, -1, 0, 0,-1914,-1918, 0, 0,-1923,-1824, 0, 0, 0,
- 0,-2016, 0, 0, 1, -1, 0, 1, 0, 0,-2104, 0, 0, 0, 0,-2106,
- -2108,-2106, 0, 0, 1, -1,-2250, 0, 0, 0,-2527, 0, 0, -2, 0, 1,
- -1, 0, 1, -1,
+ 0, 0, 1, -1, 2, 0, -2, 0, 0, 2, 0, -2, 0, 16, 0, -16,
+ 0, 1, -1, 0, 3, 3, 3, -3, -3, -3, 0, 2016, 0, 2527, 1923, 1914,
+ 1918, 0, 2250, 0, 0, 138, 0, 7, -7, 0, -1, 1, 1824, 0, 2104, 0,
+ 2108, 2106, 0, 2106, 1316, 0, -1, -138, 8, 8, 8, 0, 7, 7, -8, -8,
+ -8, -7,-1316, 1, -1, 3, -3, 1, 0,-1914,-1918, 0, 0,-1923,-1824, 0,
+ 0,-2016,-2104, 0, 0,-2106,-2108,-2106,-2250, 0,-2527, 0,
};
static inline uint_fast8_t
@@ -6878,17 +5727,17 @@ _hb_ucd_b4 (const uint8_t* a, unsigned i)
static inline int_fast16_t
_hb_ucd_bmg (unsigned u)
{
- return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[7714+(((_hb_ucd_u8[7594+(((_hb_ucd_b4(7466+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0;
+ return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[7858+(((_hb_ucd_u8[7626+(((_hb_ucd_u8[7530+(((_hb_ucd_b4(7466+_hb_ucd_u8,u>>1>>2>>3>>3))<<3)+((u>>1>>2>>3)&7u))])<<3)+((u>>1>>2)&7u))])<<2)+((u>>1)&3u))])<<1)+((u)&1u)]:0;
}
static inline uint_fast8_t
_hb_ucd_sc (unsigned u)
{
- return u<918016u?_hb_ucd_u8[11480+(((_hb_ucd_u8[10532+(((_hb_ucd_u8[9124+(((_hb_ucd_u8[8500+(((_hb_ucd_u8[8050+(u>>2>>2>>3>>4)])<<4)+((u>>2>>2>>3)&15u))])<<3)+((u>>2>>2)&7u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2;
+ return u<918016u?_hb_ucd_u8[11124+(((_hb_ucd_u8[10176+(((_hb_ucd_u8[9204+(((_hb_ucd_u8[8524+(((_hb_ucd_u8[8220+(((_hb_ucd_u8[8106+(u>>2>>2>>2>>3>>4)])<<4)+((u>>2>>2>>2>>3)&15u))])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2;
}
static inline uint_fast16_t
_hb_ucd_dm (unsigned u)
{
- return u<195102u?_hb_ucd_u16[1576+(((_hb_ucd_u8[12802+(((_hb_ucd_u8[12420+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
+ return u<195102u?_hb_ucd_u16[1576+(((_hb_ucd_u8[12446+(((_hb_ucd_u8[12064+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0;
}
#endif
diff --git a/thirdparty/harfbuzz/src/hb-unicode-emoji-table.hh b/thirdparty/harfbuzz/src/hb-unicode-emoji-table.hh
index c216379201..036c71a424 100644
--- a/thirdparty/harfbuzz/src/hb-unicode-emoji-table.hh
+++ b/thirdparty/harfbuzz/src/hb-unicode-emoji-table.hh
@@ -24,42 +24,37 @@
#include "hb-unicode.hh"
static const uint8_t
-_hb_emoji_u8[544] =
+_hb_emoji_u8[464] =
{
16, 17, 17, 17, 50, 20, 21, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,118,152,
- 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 2, 3, 0, 0, 4, 0, 5, 0, 0, 0, 0, 0, 6, 0, 7, 8,
- 0, 0, 0, 9, 0, 0, 10, 11, 12, 13, 14, 13, 15, 16, 17, 0,
- 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 19, 20, 0, 0,
- 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0,
- 13, 13, 13, 13, 23, 24, 25, 26, 27, 28, 13, 13, 13, 13, 13, 29,
- 13, 13, 13, 13, 30, 31, 13, 13, 13, 32, 13, 13, 0, 33, 0, 34,
- 35, 36, 37, 13, 38, 39, 13, 13, 13, 13, 13, 13, 0, 0, 0, 0,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 30,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 16, 0, 2, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 4, 0, 0, 2, 0, 0,240, 3, 0, 6, 0, 0,
- 0, 0, 0, 12, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
- 0,128, 0, 0, 0,254, 15, 7, 4, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 12, 64, 0, 1, 0, 0, 0, 0, 0, 0,120,
- 191,255,247,255,255,255,255,255,255,255,255,255,255,255,255,255,
- 63, 0,255,255,255,255,255,255, 63,255, 87, 32, 2, 1, 24, 0,
- 144, 80,184, 0,248, 0, 0, 0, 0, 0,224, 0, 2, 0, 1,128,
- 0, 0, 0, 0, 0, 0, 48, 0,224, 0, 0, 24, 0, 0, 0, 0,
- 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 32,
- 0, 0,128, 2, 0, 0, 0, 0, 0,224, 0, 0, 0,128, 0, 0,
- 0, 0, 0, 0, 0,240, 3,192, 0, 64,254, 7, 0,224,255,255,
- 255,255,255,255, 63, 0, 0, 0,254,255, 0, 4, 0,128,252,247,
- 0,254,255,255,255,255,255,255,255,255,255,255,255,255,255, 7,
- 255,255,255,255,255,255,255, 63,192,255,255,255,255,255,255,255,
- 255,255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,240,255,
- 0, 0,224,255,255,255,255,255, 0,240, 0, 0, 0, 0, 0, 0,
- 0,255, 0,252, 0, 0, 0, 0, 0,255, 0, 0, 0,192,255,255,
- 0,240,255,255,255,255,255,247,191,255,255,255,255,255,255,255,
+ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 2, 0, 3, 4, 0, 0, 5, 6, 0, 7, 0, 8, 9, 10, 11, 12,
+ 0, 0, 13, 0, 0, 0, 14, 0, 15, 0, 0, 0, 0, 16, 0, 0,
+ 17, 17, 18, 19, 20, 17, 17, 21, 17, 17, 22, 17, 23, 17, 24, 25,
+ 26, 27, 28, 17, 17, 17, 0, 0, 17, 17, 17, 17, 17, 17, 17, 29,
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 3, 0, 0, 4, 0, 0,
+ 5, 6, 0, 0, 7, 8, 0, 0, 8, 0, 9, 10, 0, 0, 11, 0,
+ 0, 12, 13, 14, 15, 16, 16, 16, 17, 16, 16, 16, 18, 19, 20, 21,
+ 22, 23, 0, 0, 0, 24, 0, 0, 25, 0, 26, 0, 0, 27, 0, 0,
+ 28, 0, 0, 0, 16, 16, 16, 16, 29, 9, 0, 30, 31, 32, 16, 33,
+ 34, 35, 36, 16, 16, 16, 16, 37, 16, 38, 39, 16, 16, 16, 40, 0,
+ 0, 0, 0, 41, 0, 0, 42, 16, 43, 0, 44, 0, 45, 46, 16, 16,
+ 47, 48, 49, 16, 16, 16, 16, 38, 0, 0, 0, 0, 0, 66, 0, 0,
+ 0, 0, 0, 16, 0, 2, 0, 0, 4, 0, 0, 2, 0, 0,240, 3,
+ 0, 6, 0, 0, 0, 0, 0, 12, 0, 1, 0, 0, 0,128, 0, 0,
+ 0,254, 15, 7, 4, 0, 0, 0, 0, 12, 64, 0, 1, 0, 0, 0,
+ 0, 0, 0,120,191,255,247,255,255,255,255,255, 63, 0,255,255,
+ 63,255, 87, 32, 2, 1, 24, 0,144, 80,184, 0,248, 0, 0, 0,
+ 0, 0,224, 0, 2, 0, 1,128, 0, 0, 48, 0,224, 0, 0, 24,
+ 0, 0, 33, 0, 0, 0, 1, 32, 0, 0,128, 2, 0,224, 0, 0,
+ 0,240, 3,192, 0, 64,254, 7, 0,224,255,255, 63, 0, 0, 0,
+ 254,255, 0, 4, 0,128,252,247, 0,254,255,255,255,255,255, 7,
+ 255,255,255, 63,192,255,255,255,255,255, 0, 0, 0, 0,240,255,
+ 0, 0,224,255, 0,240, 0, 0, 0,255, 0,252, 0,255, 0, 0,
+ 0,192,255,255, 0,240,255,255,255,255,255,247,191,255,255,255,
};
static inline unsigned
@@ -75,7 +70,7 @@ _hb_emoji_b1 (const uint8_t* a, unsigned i)
static inline uint_fast8_t
_hb_emoji_is_Extended_Pictographic (unsigned u)
{
- return u<131070u?_hb_emoji_b1(224+_hb_emoji_u8,((_hb_emoji_u8[64+(((_hb_emoji_b4(_hb_emoji_u8,u>>6>>4))<<4)+((u>>6)&15u))])<<6)+((u)&63u)):0;
+ return u<131070u?_hb_emoji_b1(264+_hb_emoji_u8,((_hb_emoji_u8[144+(((_hb_emoji_u8[64+(((_hb_emoji_b4(_hb_emoji_u8,u>>5>>2>>3))<<3)+((u>>5>>2)&7u))])<<2)+((u>>5)&3u))])<<5)+((u)&31u)):0;
}
diff --git a/thirdparty/harfbuzz/src/hb-unicode.cc b/thirdparty/harfbuzz/src/hb-unicode.cc
index 9899e01a41..c1795dc7f2 100644
--- a/thirdparty/harfbuzz/src/hb-unicode.cc
+++ b/thirdparty/harfbuzz/src/hb-unicode.cc
@@ -308,8 +308,8 @@ hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
* Since: 0.9.2
**/
void *
-hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
- hb_user_data_key_t *key)
+hb_unicode_funcs_get_user_data (const hb_unicode_funcs_t *ufuncs,
+ hb_user_data_key_t *key)
{
return hb_object_get_user_data (ufuncs, key);
}
diff --git a/thirdparty/harfbuzz/src/hb-unicode.h b/thirdparty/harfbuzz/src/hb-unicode.h
index a500384575..faa8d67924 100644
--- a/thirdparty/harfbuzz/src/hb-unicode.h
+++ b/thirdparty/harfbuzz/src/hb-unicode.h
@@ -317,8 +317,8 @@ hb_unicode_funcs_set_user_data (hb_unicode_funcs_t *ufuncs,
HB_EXTERN void *
-hb_unicode_funcs_get_user_data (hb_unicode_funcs_t *ufuncs,
- hb_user_data_key_t *key);
+hb_unicode_funcs_get_user_data (const hb_unicode_funcs_t *ufuncs,
+ hb_user_data_key_t *key);
HB_EXTERN void
diff --git a/thirdparty/harfbuzz/src/hb-version.h b/thirdparty/harfbuzz/src/hb-version.h
index 40ea3eb017..a1586a58b6 100644
--- a/thirdparty/harfbuzz/src/hb-version.h
+++ b/thirdparty/harfbuzz/src/hb-version.h
@@ -47,20 +47,20 @@ HB_BEGIN_DECLS
*
* The minor component of the library version available at compile-time.
*/
-#define HB_VERSION_MINOR 0
+#define HB_VERSION_MINOR 1
/**
* HB_VERSION_MICRO:
*
* The micro component of the library version available at compile-time.
*/
-#define HB_VERSION_MICRO 1
+#define HB_VERSION_MICRO 0
/**
* HB_VERSION_STRING:
*
* A string literal containing the library version available at compile-time.
*/
-#define HB_VERSION_STRING "5.0.1"
+#define HB_VERSION_STRING "5.1.0"
/**
* HB_VERSION_ATLEAST:
diff --git a/thirdparty/icu4c/godot_data.json b/thirdparty/icu4c/godot_data.json
index 3a9c28af4c..e36e2b078b 100644
--- a/thirdparty/icu4c/godot_data.json
+++ b/thirdparty/icu4c/godot_data.json
@@ -6,5 +6,6 @@
brkitr_tree: include
misc: include
normalization: include
+ confusables: include
}
-} \ No newline at end of file
+}
diff --git a/thirdparty/icu4c/i18n/scriptset.cpp b/thirdparty/icu4c/i18n/scriptset.cpp
new file mode 100644
index 0000000000..6a1db8c01c
--- /dev/null
+++ b/thirdparty/icu4c/i18n/scriptset.cpp
@@ -0,0 +1,313 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+**********************************************************************
+* Copyright (C) 2014, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+*
+* scriptset.cpp
+*
+* created on: 2013 Jan 7
+* created by: Andy Heninger
+*/
+
+#include "unicode/utypes.h"
+
+#include "unicode/uchar.h"
+#include "unicode/unistr.h"
+
+#include "scriptset.h"
+#include "uassert.h"
+#include "cmemory.h"
+
+U_NAMESPACE_BEGIN
+
+//----------------------------------------------------------------------------
+//
+// ScriptSet implementation
+//
+//----------------------------------------------------------------------------
+ScriptSet::ScriptSet() {
+ uprv_memset(bits, 0, sizeof(bits));
+}
+
+ScriptSet::~ScriptSet() {
+}
+
+ScriptSet::ScriptSet(const ScriptSet &other) {
+ *this = other;
+}
+
+ScriptSet & ScriptSet::operator =(const ScriptSet &other) {
+ uprv_memcpy(bits, other.bits, sizeof(bits));
+ return *this;
+}
+
+bool ScriptSet::operator == (const ScriptSet &other) const {
+ for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
+ if (bits[i] != other.bits[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+UBool ScriptSet::test(UScriptCode script, UErrorCode &status) const {
+ if (U_FAILURE(status)) {
+ return FALSE;
+ }
+ if (script < 0 || (int32_t)script >= SCRIPT_LIMIT) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return FALSE;
+ }
+ uint32_t index = script / 32;
+ uint32_t bit = 1 << (script & 31);
+ return ((bits[index] & bit) != 0);
+}
+
+
+ScriptSet &ScriptSet::set(UScriptCode script, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ if (script < 0 || (int32_t)script >= SCRIPT_LIMIT) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return *this;
+ }
+ uint32_t index = script / 32;
+ uint32_t bit = 1 << (script & 31);
+ bits[index] |= bit;
+ return *this;
+}
+
+ScriptSet &ScriptSet::reset(UScriptCode script, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ if (script < 0 || (int32_t)script >= SCRIPT_LIMIT) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return *this;
+ }
+ uint32_t index = script / 32;
+ uint32_t bit = 1 << (script & 31);
+ bits[index] &= ~bit;
+ return *this;
+}
+
+
+
+ScriptSet &ScriptSet::Union(const ScriptSet &other) {
+ for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
+ bits[i] |= other.bits[i];
+ }
+ return *this;
+}
+
+ScriptSet &ScriptSet::intersect(const ScriptSet &other) {
+ for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
+ bits[i] &= other.bits[i];
+ }
+ return *this;
+}
+
+ScriptSet &ScriptSet::intersect(UScriptCode script, UErrorCode &status) {
+ ScriptSet t;
+ t.set(script, status);
+ if (U_SUCCESS(status)) {
+ this->intersect(t);
+ }
+ return *this;
+}
+
+UBool ScriptSet::intersects(const ScriptSet &other) const {
+ for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
+ if ((bits[i] & other.bits[i]) != 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+UBool ScriptSet::contains(const ScriptSet &other) const {
+ ScriptSet t(*this);
+ t.intersect(other);
+ return (t == other);
+}
+
+
+ScriptSet &ScriptSet::setAll() {
+ for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
+ bits[i] = 0xffffffffu;
+ }
+ return *this;
+}
+
+
+ScriptSet &ScriptSet::resetAll() {
+ uprv_memset(bits, 0, sizeof(bits));
+ return *this;
+}
+
+int32_t ScriptSet::countMembers() const {
+ // This bit counter is good for sparse numbers of '1's, which is
+ // very much the case that we will usually have.
+ int32_t count = 0;
+ for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
+ uint32_t x = bits[i];
+ while (x > 0) {
+ count++;
+ x &= (x - 1); // and off the least significant one bit.
+ }
+ }
+ return count;
+}
+
+int32_t ScriptSet::hashCode() const {
+ int32_t hash = 0;
+ for (int32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
+ hash ^= bits[i];
+ }
+ return hash;
+}
+
+int32_t ScriptSet::nextSetBit(int32_t fromIndex) const {
+ // TODO: Wants a better implementation.
+ if (fromIndex < 0) {
+ return -1;
+ }
+ UErrorCode status = U_ZERO_ERROR;
+ for (int32_t scriptIndex = fromIndex; scriptIndex < SCRIPT_LIMIT; scriptIndex++) {
+ if (test((UScriptCode)scriptIndex, status)) {
+ return scriptIndex;
+ }
+ }
+ return -1;
+}
+
+UBool ScriptSet::isEmpty() const {
+ for (uint32_t i=0; i<UPRV_LENGTHOF(bits); i++) {
+ if (bits[i] != 0) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+UnicodeString &ScriptSet::displayScripts(UnicodeString &dest) const {
+ UBool firstTime = TRUE;
+ for (int32_t i = nextSetBit(0); i >= 0; i = nextSetBit(i + 1)) {
+ if (!firstTime) {
+ dest.append((UChar)0x20);
+ }
+ firstTime = FALSE;
+ const char *scriptName = uscript_getShortName((UScriptCode(i)));
+ dest.append(UnicodeString(scriptName, -1, US_INV));
+ }
+ return dest;
+}
+
+ScriptSet &ScriptSet::parseScripts(const UnicodeString &scriptString, UErrorCode &status) {
+ resetAll();
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ UnicodeString oneScriptName;
+ for (int32_t i=0; i<scriptString.length();) {
+ UChar32 c = scriptString.char32At(i);
+ i = scriptString.moveIndex32(i, 1);
+ if (!u_isUWhiteSpace(c)) {
+ oneScriptName.append(c);
+ if (i < scriptString.length()) {
+ continue;
+ }
+ }
+ if (oneScriptName.length() > 0) {
+ char buf[40];
+ oneScriptName.extract(0, oneScriptName.length(), buf, sizeof(buf)-1, US_INV);
+ buf[sizeof(buf)-1] = 0;
+ int32_t sc = u_getPropertyValueEnum(UCHAR_SCRIPT, buf);
+ if (sc == UCHAR_INVALID_CODE) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ } else {
+ this->set((UScriptCode)sc, status);
+ }
+ if (U_FAILURE(status)) {
+ return *this;
+ }
+ oneScriptName.remove();
+ }
+ }
+ return *this;
+}
+
+void ScriptSet::setScriptExtensions(UChar32 codePoint, UErrorCode& status) {
+ if (U_FAILURE(status)) { return; }
+ static const int32_t FIRST_GUESS_SCRIPT_CAPACITY = 20;
+ MaybeStackArray<UScriptCode,FIRST_GUESS_SCRIPT_CAPACITY> scripts;
+ UErrorCode internalStatus = U_ZERO_ERROR;
+ int32_t script_count = -1;
+
+ while (TRUE) {
+ script_count = uscript_getScriptExtensions(
+ codePoint, scripts.getAlias(), scripts.getCapacity(), &internalStatus);
+ if (internalStatus == U_BUFFER_OVERFLOW_ERROR) {
+ // Need to allocate more space
+ if (scripts.resize(script_count) == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ internalStatus = U_ZERO_ERROR;
+ } else {
+ break;
+ }
+ }
+
+ // Check if we failed for some reason other than buffer overflow
+ if (U_FAILURE(internalStatus)) {
+ status = internalStatus;
+ return;
+ }
+
+ // Load the scripts into the ScriptSet and return
+ for (int32_t i = 0; i < script_count; i++) {
+ this->set(scripts[i], status);
+ if (U_FAILURE(status)) { return; }
+ }
+}
+
+U_NAMESPACE_END
+
+U_CAPI UBool U_EXPORT2
+uhash_equalsScriptSet(const UElement key1, const UElement key2) {
+ icu::ScriptSet *s1 = static_cast<icu::ScriptSet *>(key1.pointer);
+ icu::ScriptSet *s2 = static_cast<icu::ScriptSet *>(key2.pointer);
+ return (*s1 == *s2);
+}
+
+U_CAPI int8_t U_EXPORT2
+uhash_compareScriptSet(UElement key0, UElement key1) {
+ icu::ScriptSet *s0 = static_cast<icu::ScriptSet *>(key0.pointer);
+ icu::ScriptSet *s1 = static_cast<icu::ScriptSet *>(key1.pointer);
+ int32_t diff = s0->countMembers() - s1->countMembers();
+ if (diff != 0) return static_cast<UBool>(diff);
+ int32_t i0 = s0->nextSetBit(0);
+ int32_t i1 = s1->nextSetBit(0);
+ while ((diff = i0-i1) == 0 && i0 > 0) {
+ i0 = s0->nextSetBit(i0+1);
+ i1 = s1->nextSetBit(i1+1);
+ }
+ return (int8_t)diff;
+}
+
+U_CAPI int32_t U_EXPORT2
+uhash_hashScriptSet(const UElement key) {
+ icu::ScriptSet *s = static_cast<icu::ScriptSet *>(key.pointer);
+ return s->hashCode();
+}
+
+U_CAPI void U_EXPORT2
+uhash_deleteScriptSet(void *obj) {
+ icu::ScriptSet *s = static_cast<icu::ScriptSet *>(obj);
+ delete s;
+}
diff --git a/thirdparty/icu4c/i18n/scriptset.h b/thirdparty/icu4c/i18n/scriptset.h
new file mode 100644
index 0000000000..51980ab7b3
--- /dev/null
+++ b/thirdparty/icu4c/i18n/scriptset.h
@@ -0,0 +1,86 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+**********************************************************************
+* Copyright (C) 2013, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+*
+* scriptset.h
+*
+* created on: 2013 Jan 7
+* created by: Andy Heninger
+*/
+
+#ifndef __SCRIPTSET_H__
+#define __SCRIPTSET_H__
+
+#include "unicode/utypes.h"
+#include "unicode/uobject.h"
+#include "unicode/uscript.h"
+
+#include "uelement.h"
+
+U_NAMESPACE_BEGIN
+
+//-------------------------------------------------------------------------------
+//
+// ScriptSet - A bit set representing a set of scripts.
+//
+// This class was originally used exclusively with script sets appearing
+// as part of the spoof check whole script confusable binary data. Its
+// use has since become more general, but the continued use to wrap
+// prebuilt binary data does constrain the design.
+//
+//-------------------------------------------------------------------------------
+class U_I18N_API ScriptSet: public UMemory {
+ public:
+ static constexpr int32_t SCRIPT_LIMIT = 224; // multiple of 32!
+
+ ScriptSet();
+ ScriptSet(const ScriptSet &other);
+ ~ScriptSet();
+
+ bool operator == (const ScriptSet &other) const;
+ bool operator != (const ScriptSet &other) const {return !(*this == other);}
+ ScriptSet & operator = (const ScriptSet &other);
+
+ UBool test(UScriptCode script, UErrorCode &status) const;
+ ScriptSet &Union(const ScriptSet &other);
+ ScriptSet &set(UScriptCode script, UErrorCode &status);
+ ScriptSet &reset(UScriptCode script, UErrorCode &status);
+ ScriptSet &intersect(const ScriptSet &other);
+ ScriptSet &intersect(UScriptCode script, UErrorCode &status);
+ UBool intersects(const ScriptSet &other) const; // Sets contain at least one script in common.
+ UBool contains(const ScriptSet &other) const; // All set bits in other are also set in this.
+
+ ScriptSet &setAll();
+ ScriptSet &resetAll();
+ int32_t countMembers() const;
+ int32_t hashCode() const;
+ int32_t nextSetBit(int32_t script) const;
+
+ UBool isEmpty() const;
+
+ UnicodeString &displayScripts(UnicodeString &dest) const; // append script names to dest string.
+ ScriptSet & parseScripts(const UnicodeString &scriptsString, UErrorCode &status); // Replaces ScriptSet contents.
+
+ // Wraps around UScript::getScriptExtensions() and adds the corresponding scripts to this instance.
+ void setScriptExtensions(UChar32 codePoint, UErrorCode& status);
+
+ private:
+ uint32_t bits[SCRIPT_LIMIT / 32];
+};
+
+U_NAMESPACE_END
+
+U_CAPI UBool U_EXPORT2
+uhash_compareScriptSet(const UElement key1, const UElement key2);
+
+U_CAPI int32_t U_EXPORT2
+uhash_hashScriptSet(const UElement key);
+
+U_CAPI void U_EXPORT2
+uhash_deleteScriptSet(void *obj);
+
+#endif // __SCRIPTSET_H__
diff --git a/thirdparty/icu4c/i18n/ucln_in.cpp b/thirdparty/icu4c/i18n/ucln_in.cpp
new file mode 100644
index 0000000000..f29cbe41dd
--- /dev/null
+++ b/thirdparty/icu4c/i18n/ucln_in.cpp
@@ -0,0 +1,65 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+******************************************************************************
+* *
+* Copyright (C) 2001-2014, International Business Machines *
+* Corporation and others. All Rights Reserved. *
+* *
+******************************************************************************
+* file name: ucln_in.cpp
+* encoding: UTF-8
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2001July05
+* created by: George Rhoten
+*/
+
+#include "ucln.h"
+#include "ucln_in.h"
+#include "mutex.h"
+#include "uassert.h"
+
+/** Auto-client for UCLN_I18N **/
+#define UCLN_TYPE UCLN_I18N
+#include "ucln_imp.h"
+
+/* Leave this copyright notice here! It needs to go somewhere in this library. */
+static const char copyright[] = U_COPYRIGHT_STRING;
+
+static cleanupFunc *gCleanupFunctions[UCLN_I18N_COUNT];
+
+static UBool U_CALLCONV i18n_cleanup(void)
+{
+ int32_t libType = UCLN_I18N_START;
+ (void)copyright; /* Suppress unused variable warning with clang. */
+
+ while (++libType<UCLN_I18N_COUNT) {
+ if (gCleanupFunctions[libType])
+ {
+ gCleanupFunctions[libType]();
+ gCleanupFunctions[libType] = NULL;
+ }
+ }
+#if !UCLN_NO_AUTO_CLEANUP && (defined(UCLN_AUTO_ATEXIT) || defined(UCLN_AUTO_LOCAL))
+ ucln_unRegisterAutomaticCleanup();
+#endif
+ return TRUE;
+}
+
+void ucln_i18n_registerCleanup(ECleanupI18NType type,
+ cleanupFunc *func) {
+ U_ASSERT(UCLN_I18N_START < type && type < UCLN_I18N_COUNT);
+ {
+ icu::Mutex m; // See ticket 10295 for discussion.
+ ucln_registerCleanup(UCLN_I18N, i18n_cleanup);
+ if (UCLN_I18N_START < type && type < UCLN_I18N_COUNT) {
+ gCleanupFunctions[type] = func;
+ }
+ }
+#if !UCLN_NO_AUTO_CLEANUP && (defined(UCLN_AUTO_ATEXIT) || defined(UCLN_AUTO_LOCAL))
+ ucln_registerAutomaticCleanup();
+#endif
+}
+
diff --git a/thirdparty/icu4c/i18n/ucln_in.h b/thirdparty/icu4c/i18n/ucln_in.h
new file mode 100644
index 0000000000..765cdd559f
--- /dev/null
+++ b/thirdparty/icu4c/i18n/ucln_in.h
@@ -0,0 +1,74 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+******************************************************************************
+* Copyright (C) 2001-2016, International Business Machines
+* Corporation and others. All Rights Reserved.
+******************************************************************************
+* file name: ucln_in.h
+* encoding: UTF-8
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2001July05
+* created by: George Rhoten
+*/
+
+#ifndef __UCLN_IN_H__
+#define __UCLN_IN_H__
+
+#include "unicode/utypes.h"
+#include "ucln.h"
+
+/*
+Please keep the order of enums declared in same order
+as the functions are suppose to be called.
+It's usually best to have child dependencies called first. */
+typedef enum ECleanupI18NType {
+ UCLN_I18N_START = -1,
+ UCLN_I18N_UNIT_EXTRAS,
+ UCLN_I18N_NUMBER_SKELETONS,
+ UCLN_I18N_CURRENCY_SPACING,
+ UCLN_I18N_SPOOF,
+ UCLN_I18N_SPOOFDATA,
+ UCLN_I18N_TRANSLITERATOR,
+ UCLN_I18N_REGEX,
+ UCLN_I18N_JAPANESE_CALENDAR,
+ UCLN_I18N_ISLAMIC_CALENDAR,
+ UCLN_I18N_CHINESE_CALENDAR,
+ UCLN_I18N_HEBREW_CALENDAR,
+ UCLN_I18N_ASTRO_CALENDAR,
+ UCLN_I18N_DANGI_CALENDAR,
+ UCLN_I18N_CALENDAR,
+ UCLN_I18N_TIMEZONEFORMAT,
+ UCLN_I18N_TZDBTIMEZONENAMES,
+ UCLN_I18N_TIMEZONEGENERICNAMES,
+ UCLN_I18N_TIMEZONENAMES,
+ UCLN_I18N_ZONEMETA,
+ UCLN_I18N_TIMEZONE,
+ UCLN_I18N_DIGITLIST,
+ UCLN_I18N_DECFMT,
+ UCLN_I18N_NUMFMT,
+ UCLN_I18N_ALLOWED_HOUR_FORMATS,
+ UCLN_I18N_DAYPERIODRULES,
+ UCLN_I18N_SMPDTFMT,
+ UCLN_I18N_USEARCH,
+ UCLN_I18N_COLLATOR,
+ UCLN_I18N_UCOL_RES,
+ UCLN_I18N_CSDET,
+ UCLN_I18N_COLLATION_ROOT,
+ UCLN_I18N_GENDERINFO,
+ UCLN_I18N_CDFINFO,
+ UCLN_I18N_REGION,
+ UCLN_I18N_LIST_FORMATTER,
+ UCLN_I18N_NUMSYS,
+ UCLN_I18N_COUNT /* This must be last */
+} ECleanupI18NType;
+
+/* Main library cleanup registration function. */
+/* See common/ucln.h for details on adding a cleanup function. */
+/* Note: the global mutex must not be held when calling this function. */
+U_CFUNC void U_EXPORT2 ucln_i18n_registerCleanup(ECleanupI18NType type,
+ cleanupFunc *func);
+
+#endif
diff --git a/thirdparty/icu4c/i18n/unicode/uspoof.h b/thirdparty/icu4c/i18n/unicode/uspoof.h
new file mode 100644
index 0000000000..b674c91b2c
--- /dev/null
+++ b/thirdparty/icu4c/i18n/unicode/uspoof.h
@@ -0,0 +1,1577 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+***************************************************************************
+* Copyright (C) 2008-2016, International Business Machines Corporation
+* and others. All Rights Reserved.
+***************************************************************************
+* file name: uspoof.h
+* encoding: UTF-8
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2008Feb13
+* created by: Andy Heninger
+*
+* Unicode Spoof Detection
+*/
+
+#ifndef USPOOF_H
+#define USPOOF_H
+
+#include "unicode/utypes.h"
+#include "unicode/uset.h"
+#include "unicode/parseerr.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+
+#if U_SHOW_CPLUSPLUS_API
+#include "unicode/localpointer.h"
+#include "unicode/unistr.h"
+#include "unicode/uniset.h"
+#endif
+
+
+/**
+ * \file
+ * \brief Unicode Security and Spoofing Detection, C API.
+ *
+ * <p>
+ * This class, based on <a href="http://unicode.org/reports/tr36">Unicode Technical Report #36</a> and
+ * <a href="http://unicode.org/reports/tr39">Unicode Technical Standard #39</a>, has two main functions:
+ *
+ * <ol>
+ * <li>Checking whether two strings are visually <em>confusable</em> with each other, such as "Harvest" and
+ * &quot;&Eta;arvest&quot;, where the second string starts with the Greek capital letter Eta.</li>
+ * <li>Checking whether an individual string is likely to be an attempt at confusing the reader (<em>spoof
+ * detection</em>), such as "paypal" with some Latin characters substituted with Cyrillic look-alikes.</li>
+ * </ol>
+ *
+ * <p>
+ * Although originally designed as a method for flagging suspicious identifier strings such as URLs,
+ * <code>USpoofChecker</code> has a number of other practical use cases, such as preventing attempts to evade bad-word
+ * content filters.
+ *
+ * <p>
+ * The functions of this class are exposed as C API, with a handful of syntactical conveniences for C++.
+ *
+ * <h2>Confusables</h2>
+ *
+ * <p>
+ * The following example shows how to use <code>USpoofChecker</code> to check for confusability between two strings:
+ *
+ * \code{.c}
+ * UErrorCode status = U_ZERO_ERROR;
+ * UChar* str1 = (UChar*) u"Harvest";
+ * UChar* str2 = (UChar*) u"\u0397arvest"; // with U+0397 GREEK CAPITAL LETTER ETA
+ *
+ * USpoofChecker* sc = uspoof_open(&status);
+ * uspoof_setChecks(sc, USPOOF_CONFUSABLE, &status);
+ *
+ * int32_t bitmask = uspoof_areConfusable(sc, str1, -1, str2, -1, &status);
+ * UBool result = bitmask != 0;
+ * // areConfusable: 1 (status: U_ZERO_ERROR)
+ * printf("areConfusable: %d (status: %s)\n", result, u_errorName(status));
+ * uspoof_close(sc);
+ * \endcode
+ *
+ * <p>
+ * The call to {@link uspoof_open} creates a <code>USpoofChecker</code> object; the call to {@link uspoof_setChecks}
+ * enables confusable checking and disables all other checks; the call to {@link uspoof_areConfusable} performs the
+ * confusability test; and the following line extracts the result out of the return value. For best performance,
+ * the instance should be created once (e.g., upon application startup), and the efficient
+ * {@link uspoof_areConfusable} method can be used at runtime.
+ *
+ * <p>
+ * The type {@link LocalUSpoofCheckerPointer} is exposed for C++ programmers. It will automatically call
+ * {@link uspoof_close} when the object goes out of scope:
+ *
+ * \code{.cpp}
+ * UErrorCode status = U_ZERO_ERROR;
+ * LocalUSpoofCheckerPointer sc(uspoof_open(&status));
+ * uspoof_setChecks(sc.getAlias(), USPOOF_CONFUSABLE, &status);
+ * // ...
+ * \endcode
+ *
+ * UTS 39 defines two strings to be <em>confusable</em> if they map to the same <em>skeleton string</em>. A skeleton can
+ * be thought of as a "hash code". {@link uspoof_getSkeleton} computes the skeleton for a particular string, so
+ * the following snippet is equivalent to the example above:
+ *
+ * \code{.c}
+ * UErrorCode status = U_ZERO_ERROR;
+ * UChar* str1 = (UChar*) u"Harvest";
+ * UChar* str2 = (UChar*) u"\u0397arvest"; // with U+0397 GREEK CAPITAL LETTER ETA
+ *
+ * USpoofChecker* sc = uspoof_open(&status);
+ * uspoof_setChecks(sc, USPOOF_CONFUSABLE, &status);
+ *
+ * // Get skeleton 1
+ * int32_t skel1Len = uspoof_getSkeleton(sc, 0, str1, -1, NULL, 0, &status);
+ * UChar* skel1 = (UChar*) malloc(++skel1Len * sizeof(UChar));
+ * status = U_ZERO_ERROR;
+ * uspoof_getSkeleton(sc, 0, str1, -1, skel1, skel1Len, &status);
+ *
+ * // Get skeleton 2
+ * int32_t skel2Len = uspoof_getSkeleton(sc, 0, str2, -1, NULL, 0, &status);
+ * UChar* skel2 = (UChar*) malloc(++skel2Len * sizeof(UChar));
+ * status = U_ZERO_ERROR;
+ * uspoof_getSkeleton(sc, 0, str2, -1, skel2, skel2Len, &status);
+ *
+ * // Are the skeletons the same?
+ * UBool result = u_strcmp(skel1, skel2) == 0;
+ * // areConfusable: 1 (status: U_ZERO_ERROR)
+ * printf("areConfusable: %d (status: %s)\n", result, u_errorName(status));
+ * uspoof_close(sc);
+ * free(skel1);
+ * free(skel2);
+ * \endcode
+ *
+ * If you need to check if a string is confusable with any string in a dictionary of many strings, rather than calling
+ * {@link uspoof_areConfusable} many times in a loop, {@link uspoof_getSkeleton} can be used instead, as shown below:
+ *
+ * \code{.c}
+ * UErrorCode status = U_ZERO_ERROR;
+ * #define DICTIONARY_LENGTH 2
+ * UChar* dictionary[DICTIONARY_LENGTH] = { (UChar*) u"lorem", (UChar*) u"ipsum" };
+ * UChar* skeletons[DICTIONARY_LENGTH];
+ * UChar* str = (UChar*) u"1orern";
+ *
+ * // Setup:
+ * USpoofChecker* sc = uspoof_open(&status);
+ * uspoof_setChecks(sc, USPOOF_CONFUSABLE, &status);
+ * for (size_t i=0; i<DICTIONARY_LENGTH; i++) {
+ * UChar* word = dictionary[i];
+ * int32_t len = uspoof_getSkeleton(sc, 0, word, -1, NULL, 0, &status);
+ * skeletons[i] = (UChar*) malloc(++len * sizeof(UChar));
+ * status = U_ZERO_ERROR;
+ * uspoof_getSkeleton(sc, 0, word, -1, skeletons[i], len, &status);
+ * }
+ *
+ * // Live Check:
+ * {
+ * int32_t len = uspoof_getSkeleton(sc, 0, str, -1, NULL, 0, &status);
+ * UChar* skel = (UChar*) malloc(++len * sizeof(UChar));
+ * status = U_ZERO_ERROR;
+ * uspoof_getSkeleton(sc, 0, str, -1, skel, len, &status);
+ * UBool result = false;
+ * for (size_t i=0; i<DICTIONARY_LENGTH; i++) {
+ * result = u_strcmp(skel, skeletons[i]) == 0;
+ * if (result == true) { break; }
+ * }
+ * // Has confusable in dictionary: 1 (status: U_ZERO_ERROR)
+ * printf("Has confusable in dictionary: %d (status: %s)\n", result, u_errorName(status));
+ * free(skel);
+ * }
+ *
+ * for (size_t i=0; i<DICTIONARY_LENGTH; i++) {
+ * free(skeletons[i]);
+ * }
+ * uspoof_close(sc);
+ * \endcode
+ *
+ * <b>Note:</b> Since the Unicode confusables mapping table is frequently updated, confusable skeletons are <em>not</em>
+ * guaranteed to be the same between ICU releases. We therefore recommend that you always compute confusable skeletons
+ * at runtime and do not rely on creating a permanent, or difficult to update, database of skeletons.
+ *
+ * <h2>Spoof Detection</h2>
+ *
+ * The following snippet shows a minimal example of using <code>USpoofChecker</code> to perform spoof detection on a
+ * string:
+ *
+ * \code{.c}
+ * UErrorCode status = U_ZERO_ERROR;
+ * UChar* str = (UChar*) u"p\u0430ypal"; // with U+0430 CYRILLIC SMALL LETTER A
+ *
+ * // Get the default set of allowable characters:
+ * USet* allowed = uset_openEmpty();
+ * uset_addAll(allowed, uspoof_getRecommendedSet(&status));
+ * uset_addAll(allowed, uspoof_getInclusionSet(&status));
+ *
+ * USpoofChecker* sc = uspoof_open(&status);
+ * uspoof_setAllowedChars(sc, allowed, &status);
+ * uspoof_setRestrictionLevel(sc, USPOOF_MODERATELY_RESTRICTIVE);
+ *
+ * int32_t bitmask = uspoof_check(sc, str, -1, NULL, &status);
+ * UBool result = bitmask != 0;
+ * // fails checks: 1 (status: U_ZERO_ERROR)
+ * printf("fails checks: %d (status: %s)\n", result, u_errorName(status));
+ * uspoof_close(sc);
+ * uset_close(allowed);
+ * \endcode
+ *
+ * As in the case for confusability checking, it is good practice to create one <code>USpoofChecker</code> instance at
+ * startup, and call the cheaper {@link uspoof_check} online. We specify the set of
+ * allowed characters to be those with type RECOMMENDED or INCLUSION, according to the recommendation in UTS 39.
+ *
+ * In addition to {@link uspoof_check}, the function {@link uspoof_checkUTF8} is exposed for UTF8-encoded char* strings,
+ * and {@link uspoof_checkUnicodeString} is exposed for C++ programmers.
+ *
+ * If the {@link USPOOF_AUX_INFO} check is enabled, a limited amount of information on why a string failed the checks
+ * is available in the returned bitmask. For complete information, use the {@link uspoof_check2} class of functions
+ * with a {@link USpoofCheckResult} parameter:
+ *
+ * \code{.c}
+ * UErrorCode status = U_ZERO_ERROR;
+ * UChar* str = (UChar*) u"p\u0430ypal"; // with U+0430 CYRILLIC SMALL LETTER A
+ *
+ * // Get the default set of allowable characters:
+ * USet* allowed = uset_openEmpty();
+ * uset_addAll(allowed, uspoof_getRecommendedSet(&status));
+ * uset_addAll(allowed, uspoof_getInclusionSet(&status));
+ *
+ * USpoofChecker* sc = uspoof_open(&status);
+ * uspoof_setAllowedChars(sc, allowed, &status);
+ * uspoof_setRestrictionLevel(sc, USPOOF_MODERATELY_RESTRICTIVE);
+ *
+ * USpoofCheckResult* checkResult = uspoof_openCheckResult(&status);
+ * int32_t bitmask = uspoof_check2(sc, str, -1, checkResult, &status);
+ *
+ * int32_t failures1 = bitmask;
+ * int32_t failures2 = uspoof_getCheckResultChecks(checkResult, &status);
+ * assert(failures1 == failures2);
+ * // checks that failed: 0x00000010 (status: U_ZERO_ERROR)
+ * printf("checks that failed: %#010x (status: %s)\n", failures1, u_errorName(status));
+ *
+ * // Cleanup:
+ * uspoof_close(sc);
+ * uset_close(allowed);
+ * uspoof_closeCheckResult(checkResult);
+ * \endcode
+ *
+ * C++ users can take advantage of a few syntactical conveniences. The following snippet is functionally
+ * equivalent to the one above:
+ *
+ * \code{.cpp}
+ * UErrorCode status = U_ZERO_ERROR;
+ * UnicodeString str((UChar*) u"p\u0430ypal"); // with U+0430 CYRILLIC SMALL LETTER A
+ *
+ * // Get the default set of allowable characters:
+ * UnicodeSet allowed;
+ * allowed.addAll(*uspoof_getRecommendedUnicodeSet(&status));
+ * allowed.addAll(*uspoof_getInclusionUnicodeSet(&status));
+ *
+ * LocalUSpoofCheckerPointer sc(uspoof_open(&status));
+ * uspoof_setAllowedChars(sc.getAlias(), allowed.toUSet(), &status);
+ * uspoof_setRestrictionLevel(sc.getAlias(), USPOOF_MODERATELY_RESTRICTIVE);
+ *
+ * LocalUSpoofCheckResultPointer checkResult(uspoof_openCheckResult(&status));
+ * int32_t bitmask = uspoof_check2UnicodeString(sc.getAlias(), str, checkResult.getAlias(), &status);
+ *
+ * int32_t failures1 = bitmask;
+ * int32_t failures2 = uspoof_getCheckResultChecks(checkResult.getAlias(), &status);
+ * assert(failures1 == failures2);
+ * // checks that failed: 0x00000010 (status: U_ZERO_ERROR)
+ * printf("checks that failed: %#010x (status: %s)\n", failures1, u_errorName(status));
+ *
+ * // Explicit cleanup not necessary.
+ * \endcode
+ *
+ * The return value is a bitmask of the checks that failed. In this case, there was one check that failed:
+ * {@link USPOOF_RESTRICTION_LEVEL}, corresponding to the fifth bit (16). The possible checks are:
+ *
+ * <ul>
+ * <li><code>RESTRICTION_LEVEL</code>: flags strings that violate the
+ * <a href="http://unicode.org/reports/tr39/#Restriction_Level_Detection">Restriction Level</a> test as specified in UTS
+ * 39; in most cases, this means flagging strings that contain characters from multiple different scripts.</li>
+ * <li><code>INVISIBLE</code>: flags strings that contain invisible characters, such as zero-width spaces, or character
+ * sequences that are likely not to display, such as multiple occurrences of the same non-spacing mark.</li>
+ * <li><code>CHAR_LIMIT</code>: flags strings that contain characters outside of a specified set of acceptable
+ * characters. See {@link uspoof_setAllowedChars} and {@link uspoof_setAllowedLocales}.</li>
+ * <li><code>MIXED_NUMBERS</code>: flags strings that contain digits from multiple different numbering systems.</li>
+ * </ul>
+ *
+ * <p>
+ * These checks can be enabled independently of each other. For example, if you were interested in checking for only the
+ * INVISIBLE and MIXED_NUMBERS conditions, you could do:
+ *
+ * \code{.c}
+ * UErrorCode status = U_ZERO_ERROR;
+ * UChar* str = (UChar*) u"8\u09EA"; // 8 mixed with U+09EA BENGALI DIGIT FOUR
+ *
+ * USpoofChecker* sc = uspoof_open(&status);
+ * uspoof_setChecks(sc, USPOOF_INVISIBLE | USPOOF_MIXED_NUMBERS, &status);
+ *
+ * int32_t bitmask = uspoof_check2(sc, str, -1, NULL, &status);
+ * UBool result = bitmask != 0;
+ * // fails checks: 1 (status: U_ZERO_ERROR)
+ * printf("fails checks: %d (status: %s)\n", result, u_errorName(status));
+ * uspoof_close(sc);
+ * \endcode
+ *
+ * Here is an example in C++ showing how to compute the restriction level of a string:
+ *
+ * \code{.cpp}
+ * UErrorCode status = U_ZERO_ERROR;
+ * UnicodeString str((UChar*) u"p\u0430ypal"); // with U+0430 CYRILLIC SMALL LETTER A
+ *
+ * // Get the default set of allowable characters:
+ * UnicodeSet allowed;
+ * allowed.addAll(*uspoof_getRecommendedUnicodeSet(&status));
+ * allowed.addAll(*uspoof_getInclusionUnicodeSet(&status));
+ *
+ * LocalUSpoofCheckerPointer sc(uspoof_open(&status));
+ * uspoof_setAllowedChars(sc.getAlias(), allowed.toUSet(), &status);
+ * uspoof_setRestrictionLevel(sc.getAlias(), USPOOF_MODERATELY_RESTRICTIVE);
+ * uspoof_setChecks(sc.getAlias(), USPOOF_RESTRICTION_LEVEL | USPOOF_AUX_INFO, &status);
+ *
+ * LocalUSpoofCheckResultPointer checkResult(uspoof_openCheckResult(&status));
+ * int32_t bitmask = uspoof_check2UnicodeString(sc.getAlias(), str, checkResult.getAlias(), &status);
+ *
+ * URestrictionLevel restrictionLevel = uspoof_getCheckResultRestrictionLevel(checkResult.getAlias(), &status);
+ * // Since USPOOF_AUX_INFO was enabled, the restriction level is also available in the upper bits of the bitmask:
+ * assert((restrictionLevel & bitmask) == restrictionLevel);
+ * // Restriction level: 0x50000000 (status: U_ZERO_ERROR)
+ * printf("Restriction level: %#010x (status: %s)\n", restrictionLevel, u_errorName(status));
+ * \endcode
+ *
+ * The code '0x50000000' corresponds to the restriction level USPOOF_MINIMALLY_RESTRICTIVE. Since
+ * USPOOF_MINIMALLY_RESTRICTIVE is weaker than USPOOF_MODERATELY_RESTRICTIVE, the string fails the check.
+ *
+ * <b>Note:</b> The Restriction Level is the most powerful of the checks. The full logic is documented in
+ * <a href="http://unicode.org/reports/tr39/#Restriction_Level_Detection">UTS 39</a>, but the basic idea is that strings
+ * are restricted to contain characters from only a single script, <em>except</em> that most scripts are allowed to have
+ * Latin characters interspersed. Although the default restriction level is <code>HIGHLY_RESTRICTIVE</code>, it is
+ * recommended that users set their restriction level to <code>MODERATELY_RESTRICTIVE</code>, which allows Latin mixed
+ * with all other scripts except Cyrillic, Greek, and Cherokee, with which it is often confusable. For more details on
+ * the levels, see UTS 39 or {@link URestrictionLevel}. The Restriction Level test is aware of the set of
+ * allowed characters set in {@link uspoof_setAllowedChars}. Note that characters which have script code
+ * COMMON or INHERITED, such as numbers and punctuation, are ignored when computing whether a string has multiple
+ * scripts.
+ *
+ * <h2>Additional Information</h2>
+ *
+ * A <code>USpoofChecker</code> instance may be used repeatedly to perform checks on any number of identifiers.
+ *
+ * <b>Thread Safety:</b> The test functions for checking a single identifier, or for testing whether
+ * two identifiers are possible confusable, are thread safe. They may called concurrently, from multiple threads,
+ * using the same USpoofChecker instance.
+ *
+ * More generally, the standard ICU thread safety rules apply: functions that take a const USpoofChecker parameter are
+ * thread safe. Those that take a non-const USpoofChecker are not thread safe..
+ *
+ * @stable ICU 4.6
+ */
+
+U_CDECL_BEGIN
+
+struct USpoofChecker;
+/**
+ * @stable ICU 4.2
+ */
+typedef struct USpoofChecker USpoofChecker; /**< typedef for C of USpoofChecker */
+
+struct USpoofCheckResult;
+/**
+ * @see uspoof_openCheckResult
+ * @stable ICU 58
+ */
+typedef struct USpoofCheckResult USpoofCheckResult;
+
+/**
+ * Enum for the kinds of checks that USpoofChecker can perform.
+ * These enum values are used both to select the set of checks that
+ * will be performed, and to report results from the check function.
+ *
+ * @stable ICU 4.2
+ */
+typedef enum USpoofChecks {
+ /**
+ * When performing the two-string {@link uspoof_areConfusable} test, this flag in the return value indicates
+ * that the two strings are visually confusable and that they are from the same script, according to UTS 39 section
+ * 4.
+ *
+ * @see uspoof_areConfusable
+ * @stable ICU 4.2
+ */
+ USPOOF_SINGLE_SCRIPT_CONFUSABLE = 1,
+
+ /**
+ * When performing the two-string {@link uspoof_areConfusable} test, this flag in the return value indicates
+ * that the two strings are visually confusable and that they are <b>not</b> from the same script, according to UTS
+ * 39 section 4.
+ *
+ * @see uspoof_areConfusable
+ * @stable ICU 4.2
+ */
+ USPOOF_MIXED_SCRIPT_CONFUSABLE = 2,
+
+ /**
+ * When performing the two-string {@link uspoof_areConfusable} test, this flag in the return value indicates
+ * that the two strings are visually confusable and that they are not from the same script but both of them are
+ * single-script strings, according to UTS 39 section 4.
+ *
+ * @see uspoof_areConfusable
+ * @stable ICU 4.2
+ */
+ USPOOF_WHOLE_SCRIPT_CONFUSABLE = 4,
+
+ /**
+ * Enable this flag in {@link uspoof_setChecks} to turn on all types of confusables. You may set
+ * the checks to some subset of SINGLE_SCRIPT_CONFUSABLE, MIXED_SCRIPT_CONFUSABLE, or WHOLE_SCRIPT_CONFUSABLE to
+ * make {@link uspoof_areConfusable} return only those types of confusables.
+ *
+ * @see uspoof_areConfusable
+ * @see uspoof_getSkeleton
+ * @stable ICU 58
+ */
+ USPOOF_CONFUSABLE = USPOOF_SINGLE_SCRIPT_CONFUSABLE | USPOOF_MIXED_SCRIPT_CONFUSABLE | USPOOF_WHOLE_SCRIPT_CONFUSABLE,
+
+#ifndef U_HIDE_DEPRECATED_API
+ /**
+ * This flag is deprecated and no longer affects the behavior of SpoofChecker.
+ *
+ * @deprecated ICU 58 Any case confusable mappings were removed from UTS 39; the corresponding ICU API was deprecated.
+ */
+ USPOOF_ANY_CASE = 8,
+#endif /* U_HIDE_DEPRECATED_API */
+
+ /**
+ * Check that an identifier is no looser than the specified RestrictionLevel.
+ * The default if {@link uspoof_setRestrictionLevel} is not called is HIGHLY_RESTRICTIVE.
+ *
+ * If USPOOF_AUX_INFO is enabled the actual restriction level of the
+ * identifier being tested will also be returned by uspoof_check().
+ *
+ * @see URestrictionLevel
+ * @see uspoof_setRestrictionLevel
+ * @see USPOOF_AUX_INFO
+ *
+ * @stable ICU 51
+ */
+ USPOOF_RESTRICTION_LEVEL = 16,
+
+#ifndef U_HIDE_DEPRECATED_API
+ /** Check that an identifier contains only characters from a
+ * single script (plus chars from the common and inherited scripts.)
+ * Applies to checks of a single identifier check only.
+ * @deprecated ICU 51 Use RESTRICTION_LEVEL instead.
+ */
+ USPOOF_SINGLE_SCRIPT = USPOOF_RESTRICTION_LEVEL,
+#endif /* U_HIDE_DEPRECATED_API */
+
+ /** Check an identifier for the presence of invisible characters,
+ * such as zero-width spaces, or character sequences that are
+ * likely not to display, such as multiple occurrences of the same
+ * non-spacing mark. This check does not test the input string as a whole
+ * for conformance to any particular syntax for identifiers.
+ */
+ USPOOF_INVISIBLE = 32,
+
+ /** Check that an identifier contains only characters from a specified set
+ * of acceptable characters. See {@link uspoof_setAllowedChars} and
+ * {@link uspoof_setAllowedLocales}. Note that a string that fails this check
+ * will also fail the {@link USPOOF_RESTRICTION_LEVEL} check.
+ */
+ USPOOF_CHAR_LIMIT = 64,
+
+ /**
+ * Check that an identifier does not mix numbers from different numbering systems.
+ * For more information, see UTS 39 section 5.3.
+ *
+ * @stable ICU 51
+ */
+ USPOOF_MIXED_NUMBERS = 128,
+
+ /**
+ * Check that an identifier does not have a combining character following a character in which that
+ * combining character would be hidden; for example 'i' followed by a U+0307 combining dot.
+ *
+ * More specifically, the following characters are forbidden from preceding a U+0307:
+ * <ul>
+ * <li>Those with the Soft_Dotted Unicode property (which includes 'i' and 'j')</li>
+ * <li>Latin lowercase letter 'l'</li>
+ * <li>Dotless 'i' and 'j' ('ı' and 'ȷ', U+0131 and U+0237)</li>
+ * <li>Any character whose confusable prototype ends with such a character
+ * (Soft_Dotted, 'l', 'ı', or 'ȷ')</li>
+ * </ul>
+ * In addition, combining characters are allowed between the above characters and U+0307 except those
+ * with combining class 0 or combining class "Above" (230, same class as U+0307).
+ *
+ * This list and the number of combing characters considered by this check may grow over time.
+ *
+ * @stable ICU 62
+ */
+ USPOOF_HIDDEN_OVERLAY = 256,
+
+ /**
+ * Enable all spoof checks.
+ *
+ * @stable ICU 4.6
+ */
+ USPOOF_ALL_CHECKS = 0xFFFF,
+
+ /**
+ * Enable the return of auxiliary (non-error) information in the
+ * upper bits of the check results value.
+ *
+ * If this "check" is not enabled, the results of {@link uspoof_check} will be
+ * zero when an identifier passes all of the enabled checks.
+ *
+ * If this "check" is enabled, (uspoof_check() & {@link USPOOF_ALL_CHECKS}) will
+ * be zero when an identifier passes all checks.
+ *
+ * @stable ICU 51
+ */
+ USPOOF_AUX_INFO = 0x40000000
+
+ } USpoofChecks;
+
+
+ /**
+ * Constants from UAX #39 for use in {@link uspoof_setRestrictionLevel}, and
+ * for returned identifier restriction levels in check results.
+ *
+ * @stable ICU 51
+ *
+ * @see uspoof_setRestrictionLevel
+ * @see uspoof_check
+ */
+ typedef enum URestrictionLevel {
+ /**
+ * All characters in the string are in the identifier profile and all characters in the string are in the
+ * ASCII range.
+ *
+ * @stable ICU 51
+ */
+ USPOOF_ASCII = 0x10000000,
+ /**
+ * The string classifies as ASCII-Only, or all characters in the string are in the identifier profile and
+ * the string is single-script, according to the definition in UTS 39 section 5.1.
+ *
+ * @stable ICU 53
+ */
+ USPOOF_SINGLE_SCRIPT_RESTRICTIVE = 0x20000000,
+ /**
+ * The string classifies as Single Script, or all characters in the string are in the identifier profile and
+ * the string is covered by any of the following sets of scripts, according to the definition in UTS 39
+ * section 5.1:
+ * <ul>
+ * <li>Latin + Han + Bopomofo (or equivalently: Latn + Hanb)</li>
+ * <li>Latin + Han + Hiragana + Katakana (or equivalently: Latn + Jpan)</li>
+ * <li>Latin + Han + Hangul (or equivalently: Latn +Kore)</li>
+ * </ul>
+ * This is the default restriction in ICU.
+ *
+ * @stable ICU 51
+ */
+ USPOOF_HIGHLY_RESTRICTIVE = 0x30000000,
+ /**
+ * The string classifies as Highly Restrictive, or all characters in the string are in the identifier profile
+ * and the string is covered by Latin and any one other Recommended or Aspirational script, except Cyrillic,
+ * Greek, and Cherokee.
+ *
+ * @stable ICU 51
+ */
+ USPOOF_MODERATELY_RESTRICTIVE = 0x40000000,
+ /**
+ * All characters in the string are in the identifier profile. Allow arbitrary mixtures of scripts.
+ *
+ * @stable ICU 51
+ */
+ USPOOF_MINIMALLY_RESTRICTIVE = 0x50000000,
+ /**
+ * Any valid identifiers, including characters outside of the Identifier Profile.
+ *
+ * @stable ICU 51
+ */
+ USPOOF_UNRESTRICTIVE = 0x60000000,
+ /**
+ * Mask for selecting the Restriction Level bits from the return value of {@link uspoof_check}.
+ *
+ * @stable ICU 53
+ */
+ USPOOF_RESTRICTION_LEVEL_MASK = 0x7F000000,
+#ifndef U_HIDE_INTERNAL_API
+ /**
+ * An undefined restriction level.
+ * @internal
+ */
+ USPOOF_UNDEFINED_RESTRICTIVE = -1
+#endif /* U_HIDE_INTERNAL_API */
+ } URestrictionLevel;
+
+/**
+ * Create a Unicode Spoof Checker, configured to perform all
+ * checks except for USPOOF_LOCALE_LIMIT and USPOOF_CHAR_LIMIT.
+ * Note that additional checks may be added in the future,
+ * resulting in the changes to the default checking behavior.
+ *
+ * @param status The error code, set if this function encounters a problem.
+ * @return the newly created Spoof Checker
+ * @stable ICU 4.2
+ */
+U_CAPI USpoofChecker * U_EXPORT2
+uspoof_open(UErrorCode *status);
+
+
+/**
+ * Open a Spoof checker from its serialized form, stored in 32-bit-aligned memory.
+ * Inverse of uspoof_serialize().
+ * The memory containing the serialized data must remain valid and unchanged
+ * as long as the spoof checker, or any cloned copies of the spoof checker,
+ * are in use. Ownership of the memory remains with the caller.
+ * The spoof checker (and any clones) must be closed prior to deleting the
+ * serialized data.
+ *
+ * @param data a pointer to 32-bit-aligned memory containing the serialized form of spoof data
+ * @param length the number of bytes available at data;
+ * can be more than necessary
+ * @param pActualLength receives the actual number of bytes at data taken up by the data;
+ * can be NULL
+ * @param pErrorCode ICU error code
+ * @return the spoof checker.
+ *
+ * @see uspoof_open
+ * @see uspoof_serialize
+ * @stable ICU 4.2
+ */
+U_CAPI USpoofChecker * U_EXPORT2
+uspoof_openFromSerialized(const void *data, int32_t length, int32_t *pActualLength,
+ UErrorCode *pErrorCode);
+
+/**
+ * Open a Spoof Checker from the source form of the spoof data.
+ * The input corresponds to the Unicode data file confusables.txt
+ * as described in Unicode UAX #39. The syntax of the source data
+ * is as described in UAX #39 for this file, and the content of
+ * this file is acceptable input.
+ *
+ * The character encoding of the (char *) input text is UTF-8.
+ *
+ * @param confusables a pointer to the confusable characters definitions,
+ * as found in file confusables.txt from unicode.org.
+ * @param confusablesLen The length of the confusables text, or -1 if the
+ * input string is zero terminated.
+ * @param confusablesWholeScript
+ * Deprecated in ICU 58. No longer used.
+ * @param confusablesWholeScriptLen
+ * Deprecated in ICU 58. No longer used.
+ * @param errType In the event of an error in the input, indicates
+ * which of the input files contains the error.
+ * The value is one of USPOOF_SINGLE_SCRIPT_CONFUSABLE or
+ * USPOOF_WHOLE_SCRIPT_CONFUSABLE, or
+ * zero if no errors are found.
+ * @param pe In the event of an error in the input, receives the position
+ * in the input text (line, offset) of the error.
+ * @param status an in/out ICU UErrorCode. Among the possible errors is
+ * U_PARSE_ERROR, which is used to report syntax errors
+ * in the input.
+ * @return A spoof checker that uses the rules from the input files.
+ * @stable ICU 4.2
+ */
+U_CAPI USpoofChecker * U_EXPORT2
+uspoof_openFromSource(const char *confusables, int32_t confusablesLen,
+ const char *confusablesWholeScript, int32_t confusablesWholeScriptLen,
+ int32_t *errType, UParseError *pe, UErrorCode *status);
+
+
+/**
+ * Close a Spoof Checker, freeing any memory that was being held by
+ * its implementation.
+ * @stable ICU 4.2
+ */
+U_CAPI void U_EXPORT2
+uspoof_close(USpoofChecker *sc);
+
+/**
+ * Clone a Spoof Checker. The clone will be set to perform the same checks
+ * as the original source.
+ *
+ * @param sc The source USpoofChecker
+ * @param status The error code, set if this function encounters a problem.
+ * @return
+ * @stable ICU 4.2
+ */
+U_CAPI USpoofChecker * U_EXPORT2
+uspoof_clone(const USpoofChecker *sc, UErrorCode *status);
+
+
+/**
+ * Specify the bitmask of checks that will be performed by {@link uspoof_check}. Calling this method
+ * overwrites any checks that may have already been enabled. By default, all checks are enabled.
+ *
+ * To enable specific checks and disable all others,
+ * OR together only the bit constants for the desired checks.
+ * For example, to fail strings containing characters outside of
+ * the set specified by {@link uspoof_setAllowedChars} and
+ * also strings that contain digits from mixed numbering systems:
+ *
+ * <pre>
+ * {@code
+ * uspoof_setChecks(USPOOF_CHAR_LIMIT | USPOOF_MIXED_NUMBERS);
+ * }
+ * </pre>
+ *
+ * To disable specific checks and enable all others,
+ * start with ALL_CHECKS and "AND away" the not-desired checks.
+ * For example, if you are not planning to use the {@link uspoof_areConfusable} functionality,
+ * it is good practice to disable the CONFUSABLE check:
+ *
+ * <pre>
+ * {@code
+ * uspoof_setChecks(USPOOF_ALL_CHECKS & ~USPOOF_CONFUSABLE);
+ * }
+ * </pre>
+ *
+ * Note that methods such as {@link uspoof_setAllowedChars}, {@link uspoof_setAllowedLocales}, and
+ * {@link uspoof_setRestrictionLevel} will enable certain checks when called. Those methods will OR the check they
+ * enable onto the existing bitmask specified by this method. For more details, see the documentation of those
+ * methods.
+ *
+ * @param sc The USpoofChecker
+ * @param checks The set of checks that this spoof checker will perform.
+ * The value is a bit set, obtained by OR-ing together
+ * values from enum USpoofChecks.
+ * @param status The error code, set if this function encounters a problem.
+ * @stable ICU 4.2
+ *
+ */
+U_CAPI void U_EXPORT2
+uspoof_setChecks(USpoofChecker *sc, int32_t checks, UErrorCode *status);
+
+/**
+ * Get the set of checks that this Spoof Checker has been configured to perform.
+ *
+ * @param sc The USpoofChecker
+ * @param status The error code, set if this function encounters a problem.
+ * @return The set of checks that this spoof checker will perform.
+ * The value is a bit set, obtained by OR-ing together
+ * values from enum USpoofChecks.
+ * @stable ICU 4.2
+ *
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_getChecks(const USpoofChecker *sc, UErrorCode *status);
+
+/**
+ * Set the loosest restriction level allowed for strings. The default if this is not called is
+ * {@link USPOOF_HIGHLY_RESTRICTIVE}. Calling this method enables the {@link USPOOF_RESTRICTION_LEVEL} and
+ * {@link USPOOF_MIXED_NUMBERS} checks, corresponding to Sections 5.1 and 5.2 of UTS 39. To customize which checks are
+ * to be performed by {@link uspoof_check}, see {@link uspoof_setChecks}.
+ *
+ * @param sc The USpoofChecker
+ * @param restrictionLevel The loosest restriction level allowed.
+ * @see URestrictionLevel
+ * @stable ICU 51
+ */
+U_CAPI void U_EXPORT2
+uspoof_setRestrictionLevel(USpoofChecker *sc, URestrictionLevel restrictionLevel);
+
+
+/**
+ * Get the Restriction Level that will be tested if the checks include {@link USPOOF_RESTRICTION_LEVEL}.
+ *
+ * @return The restriction level
+ * @see URestrictionLevel
+ * @stable ICU 51
+ */
+U_CAPI URestrictionLevel U_EXPORT2
+uspoof_getRestrictionLevel(const USpoofChecker *sc);
+
+/**
+ * Limit characters that are acceptable in identifiers being checked to those
+ * normally used with the languages associated with the specified locales.
+ * Any previously specified list of locales is replaced by the new settings.
+ *
+ * A set of languages is determined from the locale(s), and
+ * from those a set of acceptable Unicode scripts is determined.
+ * Characters from this set of scripts, along with characters from
+ * the "common" and "inherited" Unicode Script categories
+ * will be permitted.
+ *
+ * Supplying an empty string removes all restrictions;
+ * characters from any script will be allowed.
+ *
+ * The {@link USPOOF_CHAR_LIMIT} test is automatically enabled for this
+ * USpoofChecker when calling this function with a non-empty list
+ * of locales.
+ *
+ * The Unicode Set of characters that will be allowed is accessible
+ * via the uspoof_getAllowedChars() function. uspoof_setAllowedLocales()
+ * will <i>replace</i> any previously applied set of allowed characters.
+ *
+ * Adjustments, such as additions or deletions of certain classes of characters,
+ * can be made to the result of uspoof_setAllowedLocales() by
+ * fetching the resulting set with uspoof_getAllowedChars(),
+ * manipulating it with the Unicode Set API, then resetting the
+ * spoof detectors limits with uspoof_setAllowedChars().
+ *
+ * @param sc The USpoofChecker
+ * @param localesList A list list of locales, from which the language
+ * and associated script are extracted. The locales
+ * are comma-separated if there is more than one.
+ * White space may not appear within an individual locale,
+ * but is ignored otherwise.
+ * The locales are syntactically like those from the
+ * HTTP Accept-Language header.
+ * If the localesList is empty, no restrictions will be placed on
+ * the allowed characters.
+ *
+ * @param status The error code, set if this function encounters a problem.
+ * @stable ICU 4.2
+ */
+U_CAPI void U_EXPORT2
+uspoof_setAllowedLocales(USpoofChecker *sc, const char *localesList, UErrorCode *status);
+
+/**
+ * Get a list of locales for the scripts that are acceptable in strings
+ * to be checked. If no limitations on scripts have been specified,
+ * an empty string will be returned.
+ *
+ * uspoof_setAllowedChars() will reset the list of allowed to be empty.
+ *
+ * The format of the returned list is the same as that supplied to
+ * uspoof_setAllowedLocales(), but returned list may not be identical
+ * to the originally specified string; the string may be reformatted,
+ * and information other than languages from
+ * the originally specified locales may be omitted.
+ *
+ * @param sc The USpoofChecker
+ * @param status The error code, set if this function encounters a problem.
+ * @return A string containing a list of locales corresponding
+ * to the acceptable scripts, formatted like an
+ * HTTP Accept Language value.
+ *
+ * @stable ICU 4.2
+ */
+U_CAPI const char * U_EXPORT2
+uspoof_getAllowedLocales(USpoofChecker *sc, UErrorCode *status);
+
+
+/**
+ * Limit the acceptable characters to those specified by a Unicode Set.
+ * Any previously specified character limit is
+ * is replaced by the new settings. This includes limits on
+ * characters that were set with the uspoof_setAllowedLocales() function.
+ *
+ * The USPOOF_CHAR_LIMIT test is automatically enabled for this
+ * USpoofChecker by this function.
+ *
+ * @param sc The USpoofChecker
+ * @param chars A Unicode Set containing the list of
+ * characters that are permitted. Ownership of the set
+ * remains with the caller. The incoming set is cloned by
+ * this function, so there are no restrictions on modifying
+ * or deleting the USet after calling this function.
+ * @param status The error code, set if this function encounters a problem.
+ * @stable ICU 4.2
+ */
+U_CAPI void U_EXPORT2
+uspoof_setAllowedChars(USpoofChecker *sc, const USet *chars, UErrorCode *status);
+
+
+/**
+ * Get a USet for the characters permitted in an identifier.
+ * This corresponds to the limits imposed by the Set Allowed Characters
+ * functions. Limitations imposed by other checks will not be
+ * reflected in the set returned by this function.
+ *
+ * The returned set will be frozen, meaning that it cannot be modified
+ * by the caller.
+ *
+ * Ownership of the returned set remains with the Spoof Detector. The
+ * returned set will become invalid if the spoof detector is closed,
+ * or if a new set of allowed characters is specified.
+ *
+ *
+ * @param sc The USpoofChecker
+ * @param status The error code, set if this function encounters a problem.
+ * @return A USet containing the characters that are permitted by
+ * the USPOOF_CHAR_LIMIT test.
+ * @stable ICU 4.2
+ */
+U_CAPI const USet * U_EXPORT2
+uspoof_getAllowedChars(const USpoofChecker *sc, UErrorCode *status);
+
+
+/**
+ * Check the specified string for possible security issues.
+ * The text to be checked will typically be an identifier of some sort.
+ * The set of checks to be performed is specified with uspoof_setChecks().
+ *
+ * \note
+ * Consider using the newer API, {@link uspoof_check2}, instead.
+ * The newer API exposes additional information from the check procedure
+ * and is otherwise identical to this method.
+ *
+ * @param sc The USpoofChecker
+ * @param id The identifier to be checked for possible security issues,
+ * in UTF-16 format.
+ * @param length the length of the string to be checked, expressed in
+ * 16 bit UTF-16 code units, or -1 if the string is
+ * zero terminated.
+ * @param position Deprecated in ICU 51. Always returns zero.
+ * Originally, an out parameter for the index of the first
+ * string position that failed a check.
+ * This parameter may be NULL.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Spoofing or security issues detected with the input string are
+ * not reported here, but through the function's return value.
+ * @return An integer value with bits set for any potential security
+ * or spoofing issues detected. The bits are defined by
+ * enum USpoofChecks. (returned_value & USPOOF_ALL_CHECKS)
+ * will be zero if the input string passes all of the
+ * enabled checks.
+ * @see uspoof_check2
+ * @stable ICU 4.2
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_check(const USpoofChecker *sc,
+ const UChar *id, int32_t length,
+ int32_t *position,
+ UErrorCode *status);
+
+
+/**
+ * Check the specified string for possible security issues.
+ * The text to be checked will typically be an identifier of some sort.
+ * The set of checks to be performed is specified with uspoof_setChecks().
+ *
+ * \note
+ * Consider using the newer API, {@link uspoof_check2UTF8}, instead.
+ * The newer API exposes additional information from the check procedure
+ * and is otherwise identical to this method.
+ *
+ * @param sc The USpoofChecker
+ * @param id A identifier to be checked for possible security issues, in UTF8 format.
+ * @param length the length of the string to be checked, or -1 if the string is
+ * zero terminated.
+ * @param position Deprecated in ICU 51. Always returns zero.
+ * Originally, an out parameter for the index of the first
+ * string position that failed a check.
+ * This parameter may be NULL.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Spoofing or security issues detected with the input string are
+ * not reported here, but through the function's return value.
+ * If the input contains invalid UTF-8 sequences,
+ * a status of U_INVALID_CHAR_FOUND will be returned.
+ * @return An integer value with bits set for any potential security
+ * or spoofing issues detected. The bits are defined by
+ * enum USpoofChecks. (returned_value & USPOOF_ALL_CHECKS)
+ * will be zero if the input string passes all of the
+ * enabled checks.
+ * @see uspoof_check2UTF8
+ * @stable ICU 4.2
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_checkUTF8(const USpoofChecker *sc,
+ const char *id, int32_t length,
+ int32_t *position,
+ UErrorCode *status);
+
+
+/**
+ * Check the specified string for possible security issues.
+ * The text to be checked will typically be an identifier of some sort.
+ * The set of checks to be performed is specified with uspoof_setChecks().
+ *
+ * @param sc The USpoofChecker
+ * @param id The identifier to be checked for possible security issues,
+ * in UTF-16 format.
+ * @param length the length of the string to be checked, or -1 if the string is
+ * zero terminated.
+ * @param checkResult An instance of USpoofCheckResult to be filled with
+ * details about the identifier. Can be NULL.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Spoofing or security issues detected with the input string are
+ * not reported here, but through the function's return value.
+ * @return An integer value with bits set for any potential security
+ * or spoofing issues detected. The bits are defined by
+ * enum USpoofChecks. (returned_value & USPOOF_ALL_CHECKS)
+ * will be zero if the input string passes all of the
+ * enabled checks. Any information in this bitmask will be
+ * consistent with the information saved in the optional
+ * checkResult parameter.
+ * @see uspoof_openCheckResult
+ * @see uspoof_check2UTF8
+ * @see uspoof_check2UnicodeString
+ * @stable ICU 58
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_check2(const USpoofChecker *sc,
+ const UChar* id, int32_t length,
+ USpoofCheckResult* checkResult,
+ UErrorCode *status);
+
+/**
+ * Check the specified string for possible security issues.
+ * The text to be checked will typically be an identifier of some sort.
+ * The set of checks to be performed is specified with uspoof_setChecks().
+ *
+ * This version of {@link uspoof_check} accepts a USpoofCheckResult, which
+ * returns additional information about the identifier. For more
+ * information, see {@link uspoof_openCheckResult}.
+ *
+ * @param sc The USpoofChecker
+ * @param id A identifier to be checked for possible security issues, in UTF8 format.
+ * @param length the length of the string to be checked, or -1 if the string is
+ * zero terminated.
+ * @param checkResult An instance of USpoofCheckResult to be filled with
+ * details about the identifier. Can be NULL.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Spoofing or security issues detected with the input string are
+ * not reported here, but through the function's return value.
+ * @return An integer value with bits set for any potential security
+ * or spoofing issues detected. The bits are defined by
+ * enum USpoofChecks. (returned_value & USPOOF_ALL_CHECKS)
+ * will be zero if the input string passes all of the
+ * enabled checks. Any information in this bitmask will be
+ * consistent with the information saved in the optional
+ * checkResult parameter.
+ * @see uspoof_openCheckResult
+ * @see uspoof_check2
+ * @see uspoof_check2UnicodeString
+ * @stable ICU 58
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_check2UTF8(const USpoofChecker *sc,
+ const char *id, int32_t length,
+ USpoofCheckResult* checkResult,
+ UErrorCode *status);
+
+/**
+ * Create a USpoofCheckResult, used by the {@link uspoof_check2} class of functions to return
+ * information about the identifier. Information includes:
+ * <ul>
+ * <li>A bitmask of the checks that failed</li>
+ * <li>The identifier's restriction level (UTS 39 section 5.2)</li>
+ * <li>The set of numerics in the string (UTS 39 section 5.3)</li>
+ * </ul>
+ * The data held in a USpoofCheckResult is cleared whenever it is passed into a new call
+ * of {@link uspoof_check2}.
+ *
+ * @param status The error code, set if this function encounters a problem.
+ * @return the newly created USpoofCheckResult
+ * @see uspoof_check2
+ * @see uspoof_check2UTF8
+ * @see uspoof_check2UnicodeString
+ * @stable ICU 58
+ */
+U_CAPI USpoofCheckResult* U_EXPORT2
+uspoof_openCheckResult(UErrorCode *status);
+
+/**
+ * Close a USpoofCheckResult, freeing any memory that was being held by
+ * its implementation.
+ *
+ * @param checkResult The instance of USpoofCheckResult to close
+ * @stable ICU 58
+ */
+U_CAPI void U_EXPORT2
+uspoof_closeCheckResult(USpoofCheckResult *checkResult);
+
+/**
+ * Indicates which of the spoof check(s) have failed. The value is a bitwise OR of the constants for the tests
+ * in question: USPOOF_RESTRICTION_LEVEL, USPOOF_CHAR_LIMIT, and so on.
+ *
+ * @param checkResult The instance of USpoofCheckResult created by {@link uspoof_openCheckResult}
+ * @param status The error code, set if an error occurred.
+ * @return An integer value with bits set for any potential security
+ * or spoofing issues detected. The bits are defined by
+ * enum USpoofChecks. (returned_value & USPOOF_ALL_CHECKS)
+ * will be zero if the input string passes all of the
+ * enabled checks.
+ * @see uspoof_setChecks
+ * @stable ICU 58
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_getCheckResultChecks(const USpoofCheckResult *checkResult, UErrorCode *status);
+
+/**
+ * Gets the restriction level that the text meets, if the USPOOF_RESTRICTION_LEVEL check
+ * was enabled; otherwise, undefined.
+ *
+ * @param checkResult The instance of USpoofCheckResult created by {@link uspoof_openCheckResult}
+ * @param status The error code, set if an error occurred.
+ * @return The restriction level contained in the USpoofCheckResult
+ * @see uspoof_setRestrictionLevel
+ * @stable ICU 58
+ */
+U_CAPI URestrictionLevel U_EXPORT2
+uspoof_getCheckResultRestrictionLevel(const USpoofCheckResult *checkResult, UErrorCode *status);
+
+/**
+ * Gets the set of numerics found in the string, if the USPOOF_MIXED_NUMBERS check was enabled;
+ * otherwise, undefined. The set will contain the zero digit from each decimal number system found
+ * in the input string. Ownership of the returned USet remains with the USpoofCheckResult.
+ * The USet will be free'd when {@link uspoof_closeCheckResult} is called.
+ *
+ * @param checkResult The instance of USpoofCheckResult created by {@link uspoof_openCheckResult}
+ * @return The set of numerics contained in the USpoofCheckResult
+ * @param status The error code, set if an error occurred.
+ * @stable ICU 58
+ */
+U_CAPI const USet* U_EXPORT2
+uspoof_getCheckResultNumerics(const USpoofCheckResult *checkResult, UErrorCode *status);
+
+
+/**
+ * Check the whether two specified strings are visually confusable.
+ *
+ * If the strings are confusable, the return value will be nonzero, as long as
+ * {@link USPOOF_CONFUSABLE} was enabled in uspoof_setChecks().
+ *
+ * The bits in the return value correspond to flags for each of the classes of
+ * confusables applicable to the two input strings. According to UTS 39
+ * section 4, the possible flags are:
+ *
+ * <ul>
+ * <li>{@link USPOOF_SINGLE_SCRIPT_CONFUSABLE}</li>
+ * <li>{@link USPOOF_MIXED_SCRIPT_CONFUSABLE}</li>
+ * <li>{@link USPOOF_WHOLE_SCRIPT_CONFUSABLE}</li>
+ * </ul>
+ *
+ * If one or more of the above flags were not listed in uspoof_setChecks(), this
+ * function will never report that class of confusable. The check
+ * {@link USPOOF_CONFUSABLE} enables all three flags.
+ *
+ *
+ * @param sc The USpoofChecker
+ * @param id1 The first of the two identifiers to be compared for
+ * confusability. The strings are in UTF-16 format.
+ * @param length1 the length of the first identifier, expressed in
+ * 16 bit UTF-16 code units, or -1 if the string is
+ * nul terminated.
+ * @param id2 The second of the two identifiers to be compared for
+ * confusability. The identifiers are in UTF-16 format.
+ * @param length2 The length of the second identifiers, expressed in
+ * 16 bit UTF-16 code units, or -1 if the string is
+ * nul terminated.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Confusability of the identifiers is not reported here,
+ * but through this function's return value.
+ * @return An integer value with bit(s) set corresponding to
+ * the type of confusability found, as defined by
+ * enum USpoofChecks. Zero is returned if the identifiers
+ * are not confusable.
+ *
+ * @stable ICU 4.2
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_areConfusable(const USpoofChecker *sc,
+ const UChar *id1, int32_t length1,
+ const UChar *id2, int32_t length2,
+ UErrorCode *status);
+
+
+
+/**
+ * A version of {@link uspoof_areConfusable} accepting strings in UTF-8 format.
+ *
+ * @param sc The USpoofChecker
+ * @param id1 The first of the two identifiers to be compared for
+ * confusability. The strings are in UTF-8 format.
+ * @param length1 the length of the first identifiers, in bytes, or -1
+ * if the string is nul terminated.
+ * @param id2 The second of the two identifiers to be compared for
+ * confusability. The strings are in UTF-8 format.
+ * @param length2 The length of the second string in bytes, or -1
+ * if the string is nul terminated.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Confusability of the strings is not reported here,
+ * but through this function's return value.
+ * @return An integer value with bit(s) set corresponding to
+ * the type of confusability found, as defined by
+ * enum USpoofChecks. Zero is returned if the strings
+ * are not confusable.
+ *
+ * @stable ICU 4.2
+ *
+ * @see uspoof_areConfusable
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_areConfusableUTF8(const USpoofChecker *sc,
+ const char *id1, int32_t length1,
+ const char *id2, int32_t length2,
+ UErrorCode *status);
+
+
+
+
+/**
+ * Get the "skeleton" for an identifier.
+ * Skeletons are a transformation of the input identifier;
+ * Two identifiers are confusable if their skeletons are identical.
+ * See Unicode UAX #39 for additional information.
+ *
+ * Using skeletons directly makes it possible to quickly check
+ * whether an identifier is confusable with any of some large
+ * set of existing identifiers, by creating an efficiently
+ * searchable collection of the skeletons.
+ *
+ * @param sc The USpoofChecker
+ * @param type Deprecated in ICU 58. You may pass any number.
+ * Originally, controlled which of the Unicode confusable data
+ * tables to use.
+ * @param id The input identifier whose skeleton will be computed.
+ * @param length The length of the input identifier, expressed in 16 bit
+ * UTF-16 code units, or -1 if the string is zero terminated.
+ * @param dest The output buffer, to receive the skeleton string.
+ * @param destCapacity The length of the output buffer, in 16 bit units.
+ * The destCapacity may be zero, in which case the function will
+ * return the actual length of the skeleton.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * @return The length of the skeleton string. The returned length
+ * is always that of the complete skeleton, even when the
+ * supplied buffer is too small (or of zero length)
+ *
+ * @stable ICU 4.2
+ * @see uspoof_areConfusable
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_getSkeleton(const USpoofChecker *sc,
+ uint32_t type,
+ const UChar *id, int32_t length,
+ UChar *dest, int32_t destCapacity,
+ UErrorCode *status);
+
+/**
+ * Get the "skeleton" for an identifier.
+ * Skeletons are a transformation of the input identifier;
+ * Two identifiers are confusable if their skeletons are identical.
+ * See Unicode UAX #39 for additional information.
+ *
+ * Using skeletons directly makes it possible to quickly check
+ * whether an identifier is confusable with any of some large
+ * set of existing identifiers, by creating an efficiently
+ * searchable collection of the skeletons.
+ *
+ * @param sc The USpoofChecker
+ * @param type Deprecated in ICU 58. You may pass any number.
+ * Originally, controlled which of the Unicode confusable data
+ * tables to use.
+ * @param id The UTF-8 format identifier whose skeleton will be computed.
+ * @param length The length of the input string, in bytes,
+ * or -1 if the string is zero terminated.
+ * @param dest The output buffer, to receive the skeleton string.
+ * @param destCapacity The length of the output buffer, in bytes.
+ * The destCapacity may be zero, in which case the function will
+ * return the actual length of the skeleton.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check. Possible Errors include U_INVALID_CHAR_FOUND
+ * for invalid UTF-8 sequences, and
+ * U_BUFFER_OVERFLOW_ERROR if the destination buffer is too small
+ * to hold the complete skeleton.
+ * @return The length of the skeleton string, in bytes. The returned length
+ * is always that of the complete skeleton, even when the
+ * supplied buffer is too small (or of zero length)
+ *
+ * @stable ICU 4.2
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_getSkeletonUTF8(const USpoofChecker *sc,
+ uint32_t type,
+ const char *id, int32_t length,
+ char *dest, int32_t destCapacity,
+ UErrorCode *status);
+
+/**
+ * Get the set of Candidate Characters for Inclusion in Identifiers, as defined
+ * in http://unicode.org/Public/security/latest/xidmodifications.txt
+ * and documented in http://www.unicode.org/reports/tr39/, Unicode Security Mechanisms.
+ *
+ * The returned set is frozen. Ownership of the set remains with the ICU library; it must not
+ * be deleted by the caller.
+ *
+ * @param status The error code, set if a problem occurs while creating the set.
+ *
+ * @stable ICU 51
+ */
+U_CAPI const USet * U_EXPORT2
+uspoof_getInclusionSet(UErrorCode *status);
+
+/**
+ * Get the set of characters from Recommended Scripts for Inclusion in Identifiers, as defined
+ * in http://unicode.org/Public/security/latest/xidmodifications.txt
+ * and documented in http://www.unicode.org/reports/tr39/, Unicode Security Mechanisms.
+ *
+ * The returned set is frozen. Ownership of the set remains with the ICU library; it must not
+ * be deleted by the caller.
+ *
+ * @param status The error code, set if a problem occurs while creating the set.
+ *
+ * @stable ICU 51
+ */
+U_CAPI const USet * U_EXPORT2
+uspoof_getRecommendedSet(UErrorCode *status);
+
+/**
+ * Serialize the data for a spoof detector into a chunk of memory.
+ * The flattened spoof detection tables can later be used to efficiently
+ * instantiate a new Spoof Detector.
+ *
+ * The serialized spoof checker includes only the data compiled from the
+ * Unicode data tables by uspoof_openFromSource(); it does not include
+ * include any other state or configuration that may have been set.
+ *
+ * @param sc the Spoof Detector whose data is to be serialized.
+ * @param data a pointer to 32-bit-aligned memory to be filled with the data,
+ * can be NULL if capacity==0
+ * @param capacity the number of bytes available at data,
+ * or 0 for preflighting
+ * @param status an in/out ICU UErrorCode; possible errors include:
+ * - U_BUFFER_OVERFLOW_ERROR if the data storage block is too small for serialization
+ * - U_ILLEGAL_ARGUMENT_ERROR the data or capacity parameters are bad
+ * @return the number of bytes written or needed for the spoof data
+ *
+ * @see utrie2_openFromSerialized()
+ * @stable ICU 4.2
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_serialize(USpoofChecker *sc,
+ void *data, int32_t capacity,
+ UErrorCode *status);
+
+U_CDECL_END
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUSpoofCheckerPointer
+ * "Smart pointer" class, closes a USpoofChecker via uspoof_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 4.4
+ */
+/**
+ * \cond
+ * Note: Doxygen is giving a bogus warning on this U_DEFINE_LOCAL_OPEN_POINTER.
+ * For now, suppress with a Doxygen cond
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUSpoofCheckerPointer, USpoofChecker, uspoof_close);
+/** \endcond */
+
+/**
+ * \class LocalUSpoofCheckResultPointer
+ * "Smart pointer" class, closes a USpoofCheckResult via `uspoof_closeCheckResult()`.
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @stable ICU 58
+ */
+
+/**
+ * \cond
+ * Note: Doxygen is giving a bogus warning on this U_DEFINE_LOCAL_OPEN_POINTER.
+ * For now, suppress with a Doxygen cond
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUSpoofCheckResultPointer, USpoofCheckResult, uspoof_closeCheckResult);
+/** \endcond */
+
+U_NAMESPACE_END
+
+/**
+ * Limit the acceptable characters to those specified by a Unicode Set.
+ * Any previously specified character limit is
+ * is replaced by the new settings. This includes limits on
+ * characters that were set with the uspoof_setAllowedLocales() function.
+ *
+ * The USPOOF_CHAR_LIMIT test is automatically enabled for this
+ * USoofChecker by this function.
+ *
+ * @param sc The USpoofChecker
+ * @param chars A Unicode Set containing the list of
+ * characters that are permitted. Ownership of the set
+ * remains with the caller. The incoming set is cloned by
+ * this function, so there are no restrictions on modifying
+ * or deleting the UnicodeSet after calling this function.
+ * @param status The error code, set if this function encounters a problem.
+ * @stable ICU 4.2
+ */
+U_CAPI void U_EXPORT2
+uspoof_setAllowedUnicodeSet(USpoofChecker *sc, const icu::UnicodeSet *chars, UErrorCode *status);
+
+
+/**
+ * Get a UnicodeSet for the characters permitted in an identifier.
+ * This corresponds to the limits imposed by the Set Allowed Characters /
+ * UnicodeSet functions. Limitations imposed by other checks will not be
+ * reflected in the set returned by this function.
+ *
+ * The returned set will be frozen, meaning that it cannot be modified
+ * by the caller.
+ *
+ * Ownership of the returned set remains with the Spoof Detector. The
+ * returned set will become invalid if the spoof detector is closed,
+ * or if a new set of allowed characters is specified.
+ *
+ *
+ * @param sc The USpoofChecker
+ * @param status The error code, set if this function encounters a problem.
+ * @return A UnicodeSet containing the characters that are permitted by
+ * the USPOOF_CHAR_LIMIT test.
+ * @stable ICU 4.2
+ */
+U_CAPI const icu::UnicodeSet * U_EXPORT2
+uspoof_getAllowedUnicodeSet(const USpoofChecker *sc, UErrorCode *status);
+
+/**
+ * Check the specified string for possible security issues.
+ * The text to be checked will typically be an identifier of some sort.
+ * The set of checks to be performed is specified with uspoof_setChecks().
+ *
+ * \note
+ * Consider using the newer API, {@link uspoof_check2UnicodeString}, instead.
+ * The newer API exposes additional information from the check procedure
+ * and is otherwise identical to this method.
+ *
+ * @param sc The USpoofChecker
+ * @param id A identifier to be checked for possible security issues.
+ * @param position Deprecated in ICU 51. Always returns zero.
+ * Originally, an out parameter for the index of the first
+ * string position that failed a check.
+ * This parameter may be NULL.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Spoofing or security issues detected with the input string are
+ * not reported here, but through the function's return value.
+ * @return An integer value with bits set for any potential security
+ * or spoofing issues detected. The bits are defined by
+ * enum USpoofChecks. (returned_value & USPOOF_ALL_CHECKS)
+ * will be zero if the input string passes all of the
+ * enabled checks.
+ * @see uspoof_check2UnicodeString
+ * @stable ICU 4.2
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_checkUnicodeString(const USpoofChecker *sc,
+ const icu::UnicodeString &id,
+ int32_t *position,
+ UErrorCode *status);
+
+/**
+ * Check the specified string for possible security issues.
+ * The text to be checked will typically be an identifier of some sort.
+ * The set of checks to be performed is specified with uspoof_setChecks().
+ *
+ * @param sc The USpoofChecker
+ * @param id A identifier to be checked for possible security issues.
+ * @param checkResult An instance of USpoofCheckResult to be filled with
+ * details about the identifier. Can be NULL.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Spoofing or security issues detected with the input string are
+ * not reported here, but through the function's return value.
+ * @return An integer value with bits set for any potential security
+ * or spoofing issues detected. The bits are defined by
+ * enum USpoofChecks. (returned_value & USPOOF_ALL_CHECKS)
+ * will be zero if the input string passes all of the
+ * enabled checks. Any information in this bitmask will be
+ * consistent with the information saved in the optional
+ * checkResult parameter.
+ * @see uspoof_openCheckResult
+ * @see uspoof_check2
+ * @see uspoof_check2UTF8
+ * @stable ICU 58
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_check2UnicodeString(const USpoofChecker *sc,
+ const icu::UnicodeString &id,
+ USpoofCheckResult* checkResult,
+ UErrorCode *status);
+
+/**
+ * A version of {@link uspoof_areConfusable} accepting UnicodeStrings.
+ *
+ * @param sc The USpoofChecker
+ * @param s1 The first of the two identifiers to be compared for
+ * confusability. The strings are in UTF-8 format.
+ * @param s2 The second of the two identifiers to be compared for
+ * confusability. The strings are in UTF-8 format.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * Confusability of the identifiers is not reported here,
+ * but through this function's return value.
+ * @return An integer value with bit(s) set corresponding to
+ * the type of confusability found, as defined by
+ * enum USpoofChecks. Zero is returned if the identifiers
+ * are not confusable.
+ *
+ * @stable ICU 4.2
+ *
+ * @see uspoof_areConfusable
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_areConfusableUnicodeString(const USpoofChecker *sc,
+ const icu::UnicodeString &s1,
+ const icu::UnicodeString &s2,
+ UErrorCode *status);
+
+/**
+ * Get the "skeleton" for an identifier.
+ * Skeletons are a transformation of the input identifier;
+ * Two identifiers are confusable if their skeletons are identical.
+ * See Unicode UAX #39 for additional information.
+ *
+ * Using skeletons directly makes it possible to quickly check
+ * whether an identifier is confusable with any of some large
+ * set of existing identifiers, by creating an efficiently
+ * searchable collection of the skeletons.
+ *
+ * @param sc The USpoofChecker.
+ * @param type Deprecated in ICU 58. You may pass any number.
+ * Originally, controlled which of the Unicode confusable data
+ * tables to use.
+ * @param id The input identifier whose skeleton will be computed.
+ * @param dest The output identifier, to receive the skeleton string.
+ * @param status The error code, set if an error occurred while attempting to
+ * perform the check.
+ * @return A reference to the destination (skeleton) string.
+ *
+ * @stable ICU 4.2
+ */
+U_I18N_API icu::UnicodeString & U_EXPORT2
+uspoof_getSkeletonUnicodeString(const USpoofChecker *sc,
+ uint32_t type,
+ const icu::UnicodeString &id,
+ icu::UnicodeString &dest,
+ UErrorCode *status);
+
+/**
+ * Get the set of Candidate Characters for Inclusion in Identifiers, as defined
+ * in http://unicode.org/Public/security/latest/xidmodifications.txt
+ * and documented in http://www.unicode.org/reports/tr39/, Unicode Security Mechanisms.
+ *
+ * The returned set is frozen. Ownership of the set remains with the ICU library; it must not
+ * be deleted by the caller.
+ *
+ * @param status The error code, set if a problem occurs while creating the set.
+ *
+ * @stable ICU 51
+ */
+U_CAPI const icu::UnicodeSet * U_EXPORT2
+uspoof_getInclusionUnicodeSet(UErrorCode *status);
+
+/**
+ * Get the set of characters from Recommended Scripts for Inclusion in Identifiers, as defined
+ * in http://unicode.org/Public/security/latest/xidmodifications.txt
+ * and documented in http://www.unicode.org/reports/tr39/, Unicode Security Mechanisms.
+ *
+ * The returned set is frozen. Ownership of the set remains with the ICU library; it must not
+ * be deleted by the caller.
+ *
+ * @param status The error code, set if a problem occurs while creating the set.
+ *
+ * @stable ICU 51
+ */
+U_CAPI const icu::UnicodeSet * U_EXPORT2
+uspoof_getRecommendedUnicodeSet(UErrorCode *status);
+
+#endif /* U_SHOW_CPLUSPLUS_API */
+
+#endif /* UCONFIG_NO_NORMALIZATION */
+
+#endif /* USPOOF_H */
diff --git a/thirdparty/icu4c/i18n/uspoof.cpp b/thirdparty/icu4c/i18n/uspoof.cpp
new file mode 100644
index 0000000000..dd4618baa7
--- /dev/null
+++ b/thirdparty/icu4c/i18n/uspoof.cpp
@@ -0,0 +1,839 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+***************************************************************************
+* Copyright (C) 2008-2015, International Business Machines Corporation
+* and others. All Rights Reserved.
+***************************************************************************
+* file name: uspoof.cpp
+* encoding: UTF-8
+* tab size: 8 (not used)
+* indentation:4
+*
+* created on: 2008Feb13
+* created by: Andy Heninger
+*
+* Unicode Spoof Detection
+*/
+#include "unicode/utypes.h"
+#include "unicode/normalizer2.h"
+#include "unicode/uspoof.h"
+#include "unicode/ustring.h"
+#include "unicode/utf16.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "mutex.h"
+#include "scriptset.h"
+#include "uassert.h"
+#include "ucln_in.h"
+#include "uspoof_impl.h"
+#include "umutex.h"
+
+
+#if !UCONFIG_NO_NORMALIZATION
+
+U_NAMESPACE_USE
+
+
+//
+// Static Objects used by the spoof impl, their thread safe initialization and their cleanup.
+//
+static UnicodeSet *gInclusionSet = NULL;
+static UnicodeSet *gRecommendedSet = NULL;
+static const Normalizer2 *gNfdNormalizer = NULL;
+static UInitOnce gSpoofInitStaticsOnce = U_INITONCE_INITIALIZER;
+
+namespace {
+
+UBool U_CALLCONV
+uspoof_cleanup(void) {
+ delete gInclusionSet;
+ gInclusionSet = NULL;
+ delete gRecommendedSet;
+ gRecommendedSet = NULL;
+ gNfdNormalizer = NULL;
+ gSpoofInitStaticsOnce.reset();
+ return TRUE;
+}
+
+void U_CALLCONV initializeStatics(UErrorCode &status) {
+ static const char16_t *inclusionPat =
+ u"['\\-.\\:\\u00B7\\u0375\\u058A\\u05F3\\u05F4\\u06FD\\u06FE\\u0F0B\\u200C"
+ u"\\u200D\\u2010\\u2019\\u2027\\u30A0\\u30FB]";
+ gInclusionSet = new UnicodeSet(UnicodeString(inclusionPat), status);
+ if (gInclusionSet == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ gInclusionSet->freeze();
+
+ // Note: data from IdentifierStatus.txt & IdentifierType.txt
+ // There is tooling to generate this constant in the unicodetools project:
+ // org.unicode.text.tools.RecommendedSetGenerator
+ // It will print the Java and C++ code to the console for easy copy-paste into this file.
+ static const char16_t *recommendedPat =
+ u"[0-9A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u0131\\u0134-\\u013E"
+ u"\\u0141-\\u0148\\u014A-\\u017E\\u018F\\u01A0\\u01A1\\u01AF\\u01B0\\u01CD-"
+ u"\\u01DC\\u01DE-\\u01E3\\u01E6-\\u01F0\\u01F4\\u01F5\\u01F8-\\u021B\\u021E"
+ u"\\u021F\\u0226-\\u0233\\u0259\\u02BB\\u02BC\\u02EC\\u0300-\\u0304\\u0306-"
+ u"\\u030C\\u030F-\\u0311\\u0313\\u0314\\u031B\\u0323-\\u0328\\u032D\\u032E"
+ u"\\u0330\\u0331\\u0335\\u0338\\u0339\\u0342\\u0345\\u037B-\\u037D\\u0386"
+ u"\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03CE\\u03FC-\\u045F\\u048A-"
+ u"\\u04FF\\u0510-\\u0529\\u052E\\u052F\\u0531-\\u0556\\u0559\\u0561-\\u0586"
+ u"\\u05B4\\u05D0-\\u05EA\\u05EF-\\u05F2\\u0620-\\u063F\\u0641-\\u0655\\u0660-"
+ u"\\u0669\\u0670-\\u0672\\u0674\\u0679-\\u068D\\u068F-\\u06A0\\u06A2-\\u06D3"
+ u"\\u06D5\\u06E5\\u06E6\\u06EE-\\u06FC\\u06FF\\u0750-\\u07B1\\u0870-\\u0887"
+ u"\\u0889-\\u088E\\u08A0-\\u08AC\\u08B2\\u08B5-\\u08C9\\u0901-\\u094D\\u094F"
+ u"\\u0950\\u0956\\u0957\\u0960-\\u0963\\u0966-\\u096F\\u0971-\\u0977\\u0979-"
+ u"\\u097F\\u0981-\\u0983\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-"
+ u"\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BC-\\u09C4\\u09C7\\u09C8\\u09CB-\\u09CE"
+ u"\\u09D7\\u09E0-\\u09E3\\u09E6-\\u09F1\\u09FE\\u0A01-\\u0A03\\u0A05-\\u0A0A"
+ u"\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A35\\u0A38\\u0A39"
+ u"\\u0A3C\\u0A3E-\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A5C\\u0A66-\\u0A74"
+ u"\\u0A81-\\u0A83\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0"
+ u"\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABC-\\u0AC5\\u0AC7-\\u0AC9\\u0ACB-\\u0ACD"
+ u"\\u0AD0\\u0AE0-\\u0AE3\\u0AE6-\\u0AEF\\u0AFA-\\u0AFF\\u0B01-\\u0B03\\u0B05-"
+ u"\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-"
+ u"\\u0B39\\u0B3C-\\u0B43\\u0B47\\u0B48\\u0B4B-\\u0B4D\\u0B55-\\u0B57\\u0B5F-"
+ u"\\u0B61\\u0B66-\\u0B6F\\u0B71\\u0B82\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90"
+ u"\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-"
+ u"\\u0BAA\\u0BAE-\\u0BB9\\u0BBE-\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCD\\u0BD0"
+ u"\\u0BD7\\u0BE6-\\u0BEF\\u0C01-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-"
+ u"\\u0C33\\u0C35-\\u0C39\\u0C3C-\\u0C44\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55"
+ u"\\u0C56\\u0C5D\\u0C60\\u0C61\\u0C66-\\u0C6F\\u0C80\\u0C82\\u0C83\\u0C85-"
+ u"\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBC-"
+ u"\\u0CC4\\u0CC6-\\u0CC8\\u0CCA-\\u0CCD\\u0CD5\\u0CD6\\u0CDD\\u0CE0-\\u0CE3"
+ u"\\u0CE6-\\u0CEF\\u0CF1\\u0CF2\\u0D00\\u0D02\\u0D03\\u0D05-\\u0D0C\\u0D0E-"
+ u"\\u0D10\\u0D12-\\u0D3A\\u0D3D-\\u0D43\\u0D46-\\u0D48\\u0D4A-\\u0D4E\\u0D54-"
+ u"\\u0D57\\u0D60\\u0D61\\u0D66-\\u0D6F\\u0D7A-\\u0D7F\\u0D82\\u0D83\\u0D85-"
+ u"\\u0D8E\\u0D91-\\u0D96\\u0D9A-\\u0DA5\\u0DA7-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD"
+ u"\\u0DC0-\\u0DC6\\u0DCA\\u0DCF-\\u0DD4\\u0DD6\\u0DD8-\\u0DDE\\u0DF2\\u0E01-"
+ u"\\u0E32\\u0E34-\\u0E3A\\u0E40-\\u0E4E\\u0E50-\\u0E59\\u0E81\\u0E82\\u0E84"
+ u"\\u0E86-\\u0E8A\\u0E8C-\\u0EA3\\u0EA5\\u0EA7-\\u0EB2\\u0EB4-\\u0EBD\\u0EC0-"
+ u"\\u0EC4\\u0EC6\\u0EC8-\\u0ECD\\u0ED0-\\u0ED9\\u0EDE\\u0EDF\\u0F00\\u0F20-"
+ u"\\u0F29\\u0F35\\u0F37\\u0F3E-\\u0F42\\u0F44-\\u0F47\\u0F49-\\u0F4C\\u0F4E-"
+ u"\\u0F51\\u0F53-\\u0F56\\u0F58-\\u0F5B\\u0F5D-\\u0F68\\u0F6A-\\u0F6C\\u0F71"
+ u"\\u0F72\\u0F74\\u0F7A-\\u0F80\\u0F82-\\u0F84\\u0F86-\\u0F92\\u0F94-\\u0F97"
+ u"\\u0F99-\\u0F9C\\u0F9E-\\u0FA1\\u0FA3-\\u0FA6\\u0FA8-\\u0FAB\\u0FAD-\\u0FB8"
+ u"\\u0FBA-\\u0FBC\\u0FC6\\u1000-\\u1049\\u1050-\\u109D\\u10C7\\u10CD\\u10D0-"
+ u"\\u10F0\\u10F7-\\u10FA\\u10FD-\\u10FF\\u1200-\\u1248\\u124A-\\u124D\\u1250-"
+ u"\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0"
+ u"\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-"
+ u"\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u135D-\\u135F\\u1380-\\u138F\\u1780-"
+ u"\\u17A2\\u17A5-\\u17A7\\u17A9-\\u17B3\\u17B6-\\u17CD\\u17D0\\u17D2\\u17D7"
+ u"\\u17DC\\u17E0-\\u17E9\\u1C90-\\u1CBA\\u1CBD-\\u1CBF\\u1E00-\\u1E99\\u1E9E"
+ u"\\u1EA0-\\u1EF9\\u1F00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D"
+ u"\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F70\\u1F72\\u1F74\\u1F76"
+ u"\\u1F78\\u1F7A\\u1F7C\\u1F80-\\u1FB4\\u1FB6-\\u1FBA\\u1FBC\\u1FC2-\\u1FC4"
+ u"\\u1FC6-\\u1FC8\\u1FCA\\u1FCC\\u1FD0-\\u1FD2\\u1FD6-\\u1FDA\\u1FE0-\\u1FE2"
+ u"\\u1FE4-\\u1FEA\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FF8\\u1FFA\\u1FFC\\u2D27"
+ u"\\u2D2D\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-"
+ u"\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u3005-"
+ u"\\u3007\\u3041-\\u3096\\u3099\\u309A\\u309D\\u309E\\u30A1-\\u30FA\\u30FC-"
+ u"\\u30FE\\u3105-\\u312D\\u312F\\u31A0-\\u31BF\\u3400-\\u4DBF\\u4E00-\\u9FFF"
+ u"\\uA67F\\uA717-\\uA71F\\uA788\\uA78D\\uA792\\uA793\\uA7AA\\uA7AE\\uA7B8"
+ u"\\uA7B9\\uA7C0-\\uA7CA\\uA7D0\\uA7D1\\uA7D3\\uA7D5-\\uA7D9\\uA9E7-\\uA9FE"
+ u"\\uAA60-\\uAA76\\uAA7A-\\uAA7F\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16"
+ u"\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB66\\uAB67\\uAC00-\\uD7A3\\uFA0E\\uFA0F"
+ u"\\uFA11\\uFA13\\uFA14\\uFA1F\\uFA21\\uFA23\\uFA24\\uFA27-\\uFA29\\U00011301"
+ u"\\U00011303\\U0001133B\\U0001133C\\U00016FF0\\U00016FF1\\U0001B11F-"
+ u"\\U0001B122\\U0001B150-\\U0001B152\\U0001B164-\\U0001B167\\U0001DF00-"
+ u"\\U0001DF1E\\U0001E7E0-\\U0001E7E6\\U0001E7E8-\\U0001E7EB\\U0001E7ED"
+ u"\\U0001E7EE\\U0001E7F0-\\U0001E7FE\\U00020000-\\U0002A6DF\\U0002A700-"
+ u"\\U0002B738\\U0002B740-\\U0002B81D\\U0002B820-\\U0002CEA1\\U0002CEB0-"
+ u"\\U0002EBE0\\U00030000-\\U0003134A]";
+
+ gRecommendedSet = new UnicodeSet(UnicodeString(recommendedPat), status);
+ if (gRecommendedSet == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ delete gInclusionSet;
+ return;
+ }
+ gRecommendedSet->freeze();
+ gNfdNormalizer = Normalizer2::getNFDInstance(status);
+ ucln_i18n_registerCleanup(UCLN_I18N_SPOOF, uspoof_cleanup);
+}
+
+} // namespace
+
+U_CFUNC void uspoof_internalInitStatics(UErrorCode *status) {
+ umtx_initOnce(gSpoofInitStaticsOnce, &initializeStatics, *status);
+}
+
+U_CAPI USpoofChecker * U_EXPORT2
+uspoof_open(UErrorCode *status) {
+ umtx_initOnce(gSpoofInitStaticsOnce, &initializeStatics, *status);
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+ SpoofImpl *si = new SpoofImpl(*status);
+ if (si == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ if (U_FAILURE(*status)) {
+ delete si;
+ return NULL;
+ }
+ return si->asUSpoofChecker();
+}
+
+
+U_CAPI USpoofChecker * U_EXPORT2
+uspoof_openFromSerialized(const void *data, int32_t length, int32_t *pActualLength,
+ UErrorCode *status) {
+ if (U_FAILURE(*status)) {
+ return NULL;
+ }
+
+ if (data == NULL) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return NULL;
+ }
+
+ umtx_initOnce(gSpoofInitStaticsOnce, &initializeStatics, *status);
+ if (U_FAILURE(*status))
+ {
+ return NULL;
+ }
+
+ SpoofData *sd = new SpoofData(data, length, *status);
+ if (sd == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+
+ if (U_FAILURE(*status)) {
+ delete sd;
+ return NULL;
+ }
+
+ SpoofImpl *si = new SpoofImpl(sd, *status);
+ if (si == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ delete sd; // explicit delete as the destructor for si won't be called.
+ return NULL;
+ }
+
+ if (U_FAILURE(*status)) {
+ delete si; // no delete for sd, as the si destructor will delete it.
+ return NULL;
+ }
+
+ if (pActualLength != NULL) {
+ *pActualLength = sd->size();
+ }
+ return si->asUSpoofChecker();
+}
+
+
+U_CAPI USpoofChecker * U_EXPORT2
+uspoof_clone(const USpoofChecker *sc, UErrorCode *status) {
+ const SpoofImpl *src = SpoofImpl::validateThis(sc, *status);
+ if (src == NULL) {
+ return NULL;
+ }
+ SpoofImpl *result = new SpoofImpl(*src, *status); // copy constructor
+ if (result == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ if (U_FAILURE(*status)) {
+ delete result;
+ result = NULL;
+ }
+ return result->asUSpoofChecker();
+}
+
+
+U_CAPI void U_EXPORT2
+uspoof_close(USpoofChecker *sc) {
+ UErrorCode status = U_ZERO_ERROR;
+ SpoofImpl *This = SpoofImpl::validateThis(sc, status);
+ delete This;
+}
+
+
+U_CAPI void U_EXPORT2
+uspoof_setChecks(USpoofChecker *sc, int32_t checks, UErrorCode *status) {
+ SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return;
+ }
+
+ // Verify that the requested checks are all ones (bits) that
+ // are acceptable, known values.
+ if (checks & ~(USPOOF_ALL_CHECKS | USPOOF_AUX_INFO)) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+
+ This->fChecks = checks;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_getChecks(const USpoofChecker *sc, UErrorCode *status) {
+ const SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return 0;
+ }
+ return This->fChecks;
+}
+
+U_CAPI void U_EXPORT2
+uspoof_setRestrictionLevel(USpoofChecker *sc, URestrictionLevel restrictionLevel) {
+ UErrorCode status = U_ZERO_ERROR;
+ SpoofImpl *This = SpoofImpl::validateThis(sc, status);
+ if (This != NULL) {
+ This->fRestrictionLevel = restrictionLevel;
+ This->fChecks |= USPOOF_RESTRICTION_LEVEL;
+ }
+}
+
+U_CAPI URestrictionLevel U_EXPORT2
+uspoof_getRestrictionLevel(const USpoofChecker *sc) {
+ UErrorCode status = U_ZERO_ERROR;
+ const SpoofImpl *This = SpoofImpl::validateThis(sc, status);
+ if (This == NULL) {
+ return USPOOF_UNRESTRICTIVE;
+ }
+ return This->fRestrictionLevel;
+}
+
+U_CAPI void U_EXPORT2
+uspoof_setAllowedLocales(USpoofChecker *sc, const char *localesList, UErrorCode *status) {
+ SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return;
+ }
+ This->setAllowedLocales(localesList, *status);
+}
+
+U_CAPI const char * U_EXPORT2
+uspoof_getAllowedLocales(USpoofChecker *sc, UErrorCode *status) {
+ SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return NULL;
+ }
+ return This->getAllowedLocales(*status);
+}
+
+
+U_CAPI const USet * U_EXPORT2
+uspoof_getAllowedChars(const USpoofChecker *sc, UErrorCode *status) {
+ const UnicodeSet *result = uspoof_getAllowedUnicodeSet(sc, status);
+ return result->toUSet();
+}
+
+U_CAPI const UnicodeSet * U_EXPORT2
+uspoof_getAllowedUnicodeSet(const USpoofChecker *sc, UErrorCode *status) {
+ const SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return NULL;
+ }
+ return This->fAllowedCharsSet;
+}
+
+
+U_CAPI void U_EXPORT2
+uspoof_setAllowedChars(USpoofChecker *sc, const USet *chars, UErrorCode *status) {
+ const UnicodeSet *set = UnicodeSet::fromUSet(chars);
+ uspoof_setAllowedUnicodeSet(sc, set, status);
+}
+
+
+U_CAPI void U_EXPORT2
+uspoof_setAllowedUnicodeSet(USpoofChecker *sc, const UnicodeSet *chars, UErrorCode *status) {
+ SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return;
+ }
+ if (chars->isBogus()) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ UnicodeSet *clonedSet = chars->clone();
+ if (clonedSet == NULL || clonedSet->isBogus()) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ clonedSet->freeze();
+ delete This->fAllowedCharsSet;
+ This->fAllowedCharsSet = clonedSet;
+ This->fChecks |= USPOOF_CHAR_LIMIT;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_check(const USpoofChecker *sc,
+ const UChar *id, int32_t length,
+ int32_t *position,
+ UErrorCode *status) {
+
+ // Backwards compatibility:
+ if (position != NULL) {
+ *position = 0;
+ }
+
+ // Delegate to uspoof_check2
+ return uspoof_check2(sc, id, length, NULL, status);
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_check2(const USpoofChecker *sc,
+ const UChar* id, int32_t length,
+ USpoofCheckResult* checkResult,
+ UErrorCode *status) {
+
+ const SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return 0;
+ }
+ if (length < -1) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ UnicodeString idStr((length == -1), id, length); // Aliasing constructor.
+ int32_t result = uspoof_check2UnicodeString(sc, idStr, checkResult, status);
+ return result;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_checkUTF8(const USpoofChecker *sc,
+ const char *id, int32_t length,
+ int32_t *position,
+ UErrorCode *status) {
+
+ // Backwards compatibility:
+ if (position != NULL) {
+ *position = 0;
+ }
+
+ // Delegate to uspoof_check2
+ return uspoof_check2UTF8(sc, id, length, NULL, status);
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_check2UTF8(const USpoofChecker *sc,
+ const char *id, int32_t length,
+ USpoofCheckResult* checkResult,
+ UErrorCode *status) {
+
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ UnicodeString idStr = UnicodeString::fromUTF8(StringPiece(id, length>=0 ? length : static_cast<int32_t>(uprv_strlen(id))));
+ int32_t result = uspoof_check2UnicodeString(sc, idStr, checkResult, status);
+ return result;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_areConfusable(const USpoofChecker *sc,
+ const UChar *id1, int32_t length1,
+ const UChar *id2, int32_t length2,
+ UErrorCode *status) {
+ SpoofImpl::validateThis(sc, *status);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ if (length1 < -1 || length2 < -1) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ UnicodeString id1Str((length1==-1), id1, length1); // Aliasing constructor
+ UnicodeString id2Str((length2==-1), id2, length2); // Aliasing constructor
+ return uspoof_areConfusableUnicodeString(sc, id1Str, id2Str, status);
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_areConfusableUTF8(const USpoofChecker *sc,
+ const char *id1, int32_t length1,
+ const char *id2, int32_t length2,
+ UErrorCode *status) {
+ SpoofImpl::validateThis(sc, *status);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ if (length1 < -1 || length2 < -1) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+ UnicodeString id1Str = UnicodeString::fromUTF8(StringPiece(id1, length1>=0? length1 : static_cast<int32_t>(uprv_strlen(id1))));
+ UnicodeString id2Str = UnicodeString::fromUTF8(StringPiece(id2, length2>=0? length2 : static_cast<int32_t>(uprv_strlen(id2))));
+ int32_t results = uspoof_areConfusableUnicodeString(sc, id1Str, id2Str, status);
+ return results;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_areConfusableUnicodeString(const USpoofChecker *sc,
+ const icu::UnicodeString &id1,
+ const icu::UnicodeString &id2,
+ UErrorCode *status) {
+ const SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ //
+ // See section 4 of UAX 39 for the algorithm for checking whether two strings are confusable,
+ // and for definitions of the types (single, whole, mixed-script) of confusables.
+
+ // We only care about a few of the check flags. Ignore the others.
+ // If no tests relevant to this function have been specified, return an error.
+ // TODO: is this really the right thing to do? It's probably an error on the caller's part,
+ // but logically we would just return 0 (no error).
+ if ((This->fChecks & USPOOF_CONFUSABLE) == 0) {
+ *status = U_INVALID_STATE_ERROR;
+ return 0;
+ }
+
+ // Compute the skeletons and check for confusability.
+ UnicodeString id1Skeleton;
+ uspoof_getSkeletonUnicodeString(sc, 0 /* deprecated */, id1, id1Skeleton, status);
+ UnicodeString id2Skeleton;
+ uspoof_getSkeletonUnicodeString(sc, 0 /* deprecated */, id2, id2Skeleton, status);
+ if (U_FAILURE(*status)) { return 0; }
+ if (id1Skeleton != id2Skeleton) {
+ return 0;
+ }
+
+ // If we get here, the strings are confusable. Now we just need to set the flags for the appropriate classes
+ // of confusables according to UTS 39 section 4.
+ // Start by computing the resolved script sets of id1 and id2.
+ ScriptSet id1RSS;
+ This->getResolvedScriptSet(id1, id1RSS, *status);
+ ScriptSet id2RSS;
+ This->getResolvedScriptSet(id2, id2RSS, *status);
+
+ // Turn on all applicable flags
+ int32_t result = 0;
+ if (id1RSS.intersects(id2RSS)) {
+ result |= USPOOF_SINGLE_SCRIPT_CONFUSABLE;
+ } else {
+ result |= USPOOF_MIXED_SCRIPT_CONFUSABLE;
+ if (!id1RSS.isEmpty() && !id2RSS.isEmpty()) {
+ result |= USPOOF_WHOLE_SCRIPT_CONFUSABLE;
+ }
+ }
+
+ // Turn off flags that the user doesn't want
+ if ((This->fChecks & USPOOF_SINGLE_SCRIPT_CONFUSABLE) == 0) {
+ result &= ~USPOOF_SINGLE_SCRIPT_CONFUSABLE;
+ }
+ if ((This->fChecks & USPOOF_MIXED_SCRIPT_CONFUSABLE) == 0) {
+ result &= ~USPOOF_MIXED_SCRIPT_CONFUSABLE;
+ }
+ if ((This->fChecks & USPOOF_WHOLE_SCRIPT_CONFUSABLE) == 0) {
+ result &= ~USPOOF_WHOLE_SCRIPT_CONFUSABLE;
+ }
+
+ return result;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_checkUnicodeString(const USpoofChecker *sc,
+ const icu::UnicodeString &id,
+ int32_t *position,
+ UErrorCode *status) {
+
+ // Backwards compatibility:
+ if (position != NULL) {
+ *position = 0;
+ }
+
+ // Delegate to uspoof_check2
+ return uspoof_check2UnicodeString(sc, id, NULL, status);
+}
+
+namespace {
+
+int32_t checkImpl(const SpoofImpl* This, const UnicodeString& id, CheckResult* checkResult, UErrorCode* status) {
+ U_ASSERT(This != NULL);
+ U_ASSERT(checkResult != NULL);
+ checkResult->clear();
+ int32_t result = 0;
+
+ if (0 != (This->fChecks & USPOOF_RESTRICTION_LEVEL)) {
+ URestrictionLevel idRestrictionLevel = This->getRestrictionLevel(id, *status);
+ if (idRestrictionLevel > This->fRestrictionLevel) {
+ result |= USPOOF_RESTRICTION_LEVEL;
+ }
+ checkResult->fRestrictionLevel = idRestrictionLevel;
+ }
+
+ if (0 != (This->fChecks & USPOOF_MIXED_NUMBERS)) {
+ UnicodeSet numerics;
+ This->getNumerics(id, numerics, *status);
+ if (numerics.size() > 1) {
+ result |= USPOOF_MIXED_NUMBERS;
+ }
+ checkResult->fNumerics = numerics; // UnicodeSet::operator=
+ }
+
+ if (0 != (This->fChecks & USPOOF_HIDDEN_OVERLAY)) {
+ int32_t index = This->findHiddenOverlay(id, *status);
+ if (index != -1) {
+ result |= USPOOF_HIDDEN_OVERLAY;
+ }
+ }
+
+
+ if (0 != (This->fChecks & USPOOF_CHAR_LIMIT)) {
+ int32_t i;
+ UChar32 c;
+ int32_t length = id.length();
+ for (i=0; i<length ;) {
+ c = id.char32At(i);
+ i += U16_LENGTH(c);
+ if (!This->fAllowedCharsSet->contains(c)) {
+ result |= USPOOF_CHAR_LIMIT;
+ break;
+ }
+ }
+ }
+
+ if (0 != (This->fChecks & USPOOF_INVISIBLE)) {
+ // This check needs to be done on NFD input
+ UnicodeString nfdText;
+ gNfdNormalizer->normalize(id, nfdText, *status);
+ int32_t nfdLength = nfdText.length();
+
+ // scan for more than one occurrence of the same non-spacing mark
+ // in a sequence of non-spacing marks.
+ int32_t i;
+ UChar32 c;
+ UChar32 firstNonspacingMark = 0;
+ UBool haveMultipleMarks = FALSE;
+ UnicodeSet marksSeenSoFar; // Set of combining marks in a single combining sequence.
+
+ for (i=0; i<nfdLength ;) {
+ c = nfdText.char32At(i);
+ i += U16_LENGTH(c);
+ if (u_charType(c) != U_NON_SPACING_MARK) {
+ firstNonspacingMark = 0;
+ if (haveMultipleMarks) {
+ marksSeenSoFar.clear();
+ haveMultipleMarks = FALSE;
+ }
+ continue;
+ }
+ if (firstNonspacingMark == 0) {
+ firstNonspacingMark = c;
+ continue;
+ }
+ if (!haveMultipleMarks) {
+ marksSeenSoFar.add(firstNonspacingMark);
+ haveMultipleMarks = TRUE;
+ }
+ if (marksSeenSoFar.contains(c)) {
+ // report the error, and stop scanning.
+ // No need to find more than the first failure.
+ result |= USPOOF_INVISIBLE;
+ break;
+ }
+ marksSeenSoFar.add(c);
+ }
+ }
+
+ checkResult->fChecks = result;
+ return checkResult->toCombinedBitmask(This->fChecks);
+}
+
+} // namespace
+
+U_CAPI int32_t U_EXPORT2
+uspoof_check2UnicodeString(const USpoofChecker *sc,
+ const icu::UnicodeString &id,
+ USpoofCheckResult* checkResult,
+ UErrorCode *status) {
+ const SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ return FALSE;
+ }
+
+ if (checkResult != NULL) {
+ CheckResult* ThisCheckResult = CheckResult::validateThis(checkResult, *status);
+ if (ThisCheckResult == NULL) {
+ return FALSE;
+ }
+ return checkImpl(This, id, ThisCheckResult, status);
+ } else {
+ // Stack-allocate the checkResult since this method doesn't return it
+ CheckResult stackCheckResult;
+ return checkImpl(This, id, &stackCheckResult, status);
+ }
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_getSkeleton(const USpoofChecker *sc,
+ uint32_t type,
+ const UChar *id, int32_t length,
+ UChar *dest, int32_t destCapacity,
+ UErrorCode *status) {
+
+ SpoofImpl::validateThis(sc, *status);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ if (length<-1 || destCapacity<0 || (destCapacity==0 && dest!=NULL)) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ UnicodeString idStr((length==-1), id, length); // Aliasing constructor
+ UnicodeString destStr;
+ uspoof_getSkeletonUnicodeString(sc, type, idStr, destStr, status);
+ destStr.extract(dest, destCapacity, *status);
+ return destStr.length();
+}
+
+
+
+U_I18N_API UnicodeString & U_EXPORT2
+uspoof_getSkeletonUnicodeString(const USpoofChecker *sc,
+ uint32_t /*type*/,
+ const UnicodeString &id,
+ UnicodeString &dest,
+ UErrorCode *status) {
+ const SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (U_FAILURE(*status)) {
+ return dest;
+ }
+
+ UnicodeString nfdId;
+ gNfdNormalizer->normalize(id, nfdId, *status);
+
+ // Apply the skeleton mapping to the NFD normalized input string
+ // Accumulate the skeleton, possibly unnormalized, in a UnicodeString.
+ int32_t inputIndex = 0;
+ UnicodeString skelStr;
+ int32_t normalizedLen = nfdId.length();
+ for (inputIndex=0; inputIndex < normalizedLen; ) {
+ UChar32 c = nfdId.char32At(inputIndex);
+ inputIndex += U16_LENGTH(c);
+ This->fSpoofData->confusableLookup(c, skelStr);
+ }
+
+ gNfdNormalizer->normalize(skelStr, dest, *status);
+ return dest;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_getSkeletonUTF8(const USpoofChecker *sc,
+ uint32_t type,
+ const char *id, int32_t length,
+ char *dest, int32_t destCapacity,
+ UErrorCode *status) {
+ SpoofImpl::validateThis(sc, *status);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+ if (length<-1 || destCapacity<0 || (destCapacity==0 && dest!=NULL)) {
+ *status = U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ UnicodeString srcStr = UnicodeString::fromUTF8(StringPiece(id, length>=0 ? length : static_cast<int32_t>(uprv_strlen(id))));
+ UnicodeString destStr;
+ uspoof_getSkeletonUnicodeString(sc, type, srcStr, destStr, status);
+ if (U_FAILURE(*status)) {
+ return 0;
+ }
+
+ int32_t lengthInUTF8 = 0;
+ u_strToUTF8(dest, destCapacity, &lengthInUTF8,
+ destStr.getBuffer(), destStr.length(), status);
+ return lengthInUTF8;
+}
+
+
+U_CAPI int32_t U_EXPORT2
+uspoof_serialize(USpoofChecker *sc,void *buf, int32_t capacity, UErrorCode *status) {
+ SpoofImpl *This = SpoofImpl::validateThis(sc, *status);
+ if (This == NULL) {
+ U_ASSERT(U_FAILURE(*status));
+ return 0;
+ }
+
+ return This->fSpoofData->serialize(buf, capacity, *status);
+}
+
+U_CAPI const USet * U_EXPORT2
+uspoof_getInclusionSet(UErrorCode *status) {
+ umtx_initOnce(gSpoofInitStaticsOnce, &initializeStatics, *status);
+ return gInclusionSet->toUSet();
+}
+
+U_CAPI const USet * U_EXPORT2
+uspoof_getRecommendedSet(UErrorCode *status) {
+ umtx_initOnce(gSpoofInitStaticsOnce, &initializeStatics, *status);
+ return gRecommendedSet->toUSet();
+}
+
+U_I18N_API const UnicodeSet * U_EXPORT2
+uspoof_getInclusionUnicodeSet(UErrorCode *status) {
+ umtx_initOnce(gSpoofInitStaticsOnce, &initializeStatics, *status);
+ return gInclusionSet;
+}
+
+U_I18N_API const UnicodeSet * U_EXPORT2
+uspoof_getRecommendedUnicodeSet(UErrorCode *status) {
+ umtx_initOnce(gSpoofInitStaticsOnce, &initializeStatics, *status);
+ return gRecommendedSet;
+}
+
+//------------------
+// CheckResult APIs
+//------------------
+
+U_CAPI USpoofCheckResult* U_EXPORT2
+uspoof_openCheckResult(UErrorCode *status) {
+ CheckResult* checkResult = new CheckResult();
+ if (checkResult == NULL) {
+ *status = U_MEMORY_ALLOCATION_ERROR;
+ return NULL;
+ }
+ return checkResult->asUSpoofCheckResult();
+}
+
+U_CAPI void U_EXPORT2
+uspoof_closeCheckResult(USpoofCheckResult* checkResult) {
+ UErrorCode status = U_ZERO_ERROR;
+ CheckResult* This = CheckResult::validateThis(checkResult, status);
+ delete This;
+}
+
+U_CAPI int32_t U_EXPORT2
+uspoof_getCheckResultChecks(const USpoofCheckResult *checkResult, UErrorCode *status) {
+ const CheckResult* This = CheckResult::validateThis(checkResult, *status);
+ if (U_FAILURE(*status)) { return 0; }
+ return This->fChecks;
+}
+
+U_CAPI URestrictionLevel U_EXPORT2
+uspoof_getCheckResultRestrictionLevel(const USpoofCheckResult *checkResult, UErrorCode *status) {
+ const CheckResult* This = CheckResult::validateThis(checkResult, *status);
+ if (U_FAILURE(*status)) { return USPOOF_UNRESTRICTIVE; }
+ return This->fRestrictionLevel;
+}
+
+U_CAPI const USet* U_EXPORT2
+uspoof_getCheckResultNumerics(const USpoofCheckResult *checkResult, UErrorCode *status) {
+ const CheckResult* This = CheckResult::validateThis(checkResult, *status);
+ if (U_FAILURE(*status)) { return NULL; }
+ return This->fNumerics.toUSet();
+}
+
+
+
+#endif // !UCONFIG_NO_NORMALIZATION
diff --git a/thirdparty/icu4c/i18n/uspoof_impl.cpp b/thirdparty/icu4c/i18n/uspoof_impl.cpp
new file mode 100644
index 0000000000..b283d81321
--- /dev/null
+++ b/thirdparty/icu4c/i18n/uspoof_impl.cpp
@@ -0,0 +1,959 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+**********************************************************************
+* Copyright (C) 2008-2016, International Business Machines
+* Corporation and others. All Rights Reserved.
+**********************************************************************
+*/
+
+#include "unicode/utypes.h"
+#include "unicode/uspoof.h"
+#include "unicode/uchar.h"
+#include "unicode/uniset.h"
+#include "unicode/utf16.h"
+#include "utrie2.h"
+#include "cmemory.h"
+#include "cstring.h"
+#include "scriptset.h"
+#include "umutex.h"
+#include "udataswp.h"
+#include "uassert.h"
+#include "ucln_in.h"
+#include "uspoof_impl.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SpoofImpl)
+
+SpoofImpl::SpoofImpl(SpoofData *data, UErrorCode& status) {
+ construct(status);
+ fSpoofData = data;
+}
+
+SpoofImpl::SpoofImpl(UErrorCode& status) {
+ construct(status);
+
+ // TODO: Call this method where it is actually needed, instead of in the
+ // constructor, to allow for lazy data loading. See #12696.
+ fSpoofData = SpoofData::getDefault(status);
+}
+
+SpoofImpl::SpoofImpl() {
+ UErrorCode status = U_ZERO_ERROR;
+ construct(status);
+
+ // TODO: Call this method where it is actually needed, instead of in the
+ // constructor, to allow for lazy data loading. See #12696.
+ fSpoofData = SpoofData::getDefault(status);
+}
+
+void SpoofImpl::construct(UErrorCode& status) {
+ fChecks = USPOOF_ALL_CHECKS;
+ fSpoofData = NULL;
+ fAllowedCharsSet = NULL;
+ fAllowedLocales = NULL;
+ fRestrictionLevel = USPOOF_HIGHLY_RESTRICTIVE;
+
+ if (U_FAILURE(status)) { return; }
+
+ UnicodeSet *allowedCharsSet = new UnicodeSet(0, 0x10ffff);
+ fAllowedCharsSet = allowedCharsSet;
+ fAllowedLocales = uprv_strdup("");
+ if (fAllowedCharsSet == NULL || fAllowedLocales == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ allowedCharsSet->freeze();
+}
+
+
+// Copy Constructor, used by the user level clone() function.
+SpoofImpl::SpoofImpl(const SpoofImpl &src, UErrorCode &status) :
+ fChecks(USPOOF_ALL_CHECKS), fSpoofData(NULL), fAllowedCharsSet(NULL) ,
+ fAllowedLocales(NULL) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fChecks = src.fChecks;
+ if (src.fSpoofData != NULL) {
+ fSpoofData = src.fSpoofData->addReference();
+ }
+ fAllowedCharsSet = src.fAllowedCharsSet->clone();
+ fAllowedLocales = uprv_strdup(src.fAllowedLocales);
+ if (fAllowedCharsSet == NULL || fAllowedLocales == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ }
+ fRestrictionLevel = src.fRestrictionLevel;
+}
+
+SpoofImpl::~SpoofImpl() {
+ if (fSpoofData != NULL) {
+ fSpoofData->removeReference(); // Will delete if refCount goes to zero.
+ }
+ delete fAllowedCharsSet;
+ uprv_free((void *)fAllowedLocales);
+}
+
+// Cast this instance as a USpoofChecker for the C API.
+USpoofChecker *SpoofImpl::asUSpoofChecker() {
+ return exportForC();
+}
+
+//
+// Incoming parameter check on Status and the SpoofChecker object
+// received from the C API.
+//
+const SpoofImpl *SpoofImpl::validateThis(const USpoofChecker *sc, UErrorCode &status) {
+ auto* This = validate(sc, status);
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ if (This->fSpoofData != NULL && !This->fSpoofData->validateDataVersion(status)) {
+ return NULL;
+ }
+ return This;
+}
+
+SpoofImpl *SpoofImpl::validateThis(USpoofChecker *sc, UErrorCode &status) {
+ return const_cast<SpoofImpl *>
+ (SpoofImpl::validateThis(const_cast<const USpoofChecker *>(sc), status));
+}
+
+
+void SpoofImpl::setAllowedLocales(const char *localesList, UErrorCode &status) {
+ UnicodeSet allowedChars;
+ UnicodeSet *tmpSet = NULL;
+ const char *locStart = localesList;
+ const char *locEnd = NULL;
+ const char *localesListEnd = localesList + uprv_strlen(localesList);
+ int32_t localeListCount = 0; // Number of locales provided by caller.
+
+ // Loop runs once per locale from the localesList, a comma separated list of locales.
+ do {
+ locEnd = uprv_strchr(locStart, ',');
+ if (locEnd == NULL) {
+ locEnd = localesListEnd;
+ }
+ while (*locStart == ' ') {
+ locStart++;
+ }
+ const char *trimmedEnd = locEnd-1;
+ while (trimmedEnd > locStart && *trimmedEnd == ' ') {
+ trimmedEnd--;
+ }
+ if (trimmedEnd <= locStart) {
+ break;
+ }
+ const char *locale = uprv_strndup(locStart, (int32_t)(trimmedEnd + 1 - locStart));
+ localeListCount++;
+
+ // We have one locale from the locales list.
+ // Add the script chars for this locale to the accumulating set of allowed chars.
+ // If the locale is no good, we will be notified back via status.
+ addScriptChars(locale, &allowedChars, status);
+ uprv_free((void *)locale);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ locStart = locEnd + 1;
+ } while (locStart < localesListEnd);
+
+ // If our caller provided an empty list of locales, we disable the allowed characters checking
+ if (localeListCount == 0) {
+ uprv_free((void *)fAllowedLocales);
+ fAllowedLocales = uprv_strdup("");
+ tmpSet = new UnicodeSet(0, 0x10ffff);
+ if (fAllowedLocales == NULL || tmpSet == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ tmpSet->freeze();
+ delete fAllowedCharsSet;
+ fAllowedCharsSet = tmpSet;
+ fChecks &= ~USPOOF_CHAR_LIMIT;
+ return;
+ }
+
+
+ // Add all common and inherited characters to the set of allowed chars.
+ UnicodeSet tempSet;
+ tempSet.applyIntPropertyValue(UCHAR_SCRIPT, USCRIPT_COMMON, status);
+ allowedChars.addAll(tempSet);
+ tempSet.applyIntPropertyValue(UCHAR_SCRIPT, USCRIPT_INHERITED, status);
+ allowedChars.addAll(tempSet);
+
+ // If anything went wrong, we bail out without changing
+ // the state of the spoof checker.
+ if (U_FAILURE(status)) {
+ return;
+ }
+
+ // Store the updated spoof checker state.
+ tmpSet = allowedChars.clone();
+ const char *tmpLocalesList = uprv_strdup(localesList);
+ if (tmpSet == NULL || tmpLocalesList == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ uprv_free((void *)fAllowedLocales);
+ fAllowedLocales = tmpLocalesList;
+ tmpSet->freeze();
+ delete fAllowedCharsSet;
+ fAllowedCharsSet = tmpSet;
+ fChecks |= USPOOF_CHAR_LIMIT;
+}
+
+
+const char * SpoofImpl::getAllowedLocales(UErrorCode &/*status*/) {
+ return fAllowedLocales;
+}
+
+
+// Given a locale (a language), add all the characters from all of the scripts used with that language
+// to the allowedChars UnicodeSet
+
+void SpoofImpl::addScriptChars(const char *locale, UnicodeSet *allowedChars, UErrorCode &status) {
+ UScriptCode scripts[30];
+
+ int32_t numScripts = uscript_getCode(locale, scripts, UPRV_LENGTHOF(scripts), &status);
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (status == U_USING_DEFAULT_WARNING) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ UnicodeSet tmpSet;
+ int32_t i;
+ for (i=0; i<numScripts; i++) {
+ tmpSet.applyIntPropertyValue(UCHAR_SCRIPT, scripts[i], status);
+ allowedChars->addAll(tmpSet);
+ }
+}
+
+// Computes the augmented script set for a code point, according to UTS 39 section 5.1.
+void SpoofImpl::getAugmentedScriptSet(UChar32 codePoint, ScriptSet& result, UErrorCode& status) {
+ result.resetAll();
+ result.setScriptExtensions(codePoint, status);
+ if (U_FAILURE(status)) { return; }
+
+ // Section 5.1 step 1
+ if (result.test(USCRIPT_HAN, status)) {
+ result.set(USCRIPT_HAN_WITH_BOPOMOFO, status);
+ result.set(USCRIPT_JAPANESE, status);
+ result.set(USCRIPT_KOREAN, status);
+ }
+ if (result.test(USCRIPT_HIRAGANA, status)) {
+ result.set(USCRIPT_JAPANESE, status);
+ }
+ if (result.test(USCRIPT_KATAKANA, status)) {
+ result.set(USCRIPT_JAPANESE, status);
+ }
+ if (result.test(USCRIPT_HANGUL, status)) {
+ result.set(USCRIPT_KOREAN, status);
+ }
+ if (result.test(USCRIPT_BOPOMOFO, status)) {
+ result.set(USCRIPT_HAN_WITH_BOPOMOFO, status);
+ }
+
+ // Section 5.1 step 2
+ if (result.test(USCRIPT_COMMON, status) || result.test(USCRIPT_INHERITED, status)) {
+ result.setAll();
+ }
+}
+
+// Computes the resolved script set for a string, according to UTS 39 section 5.1.
+void SpoofImpl::getResolvedScriptSet(const UnicodeString& input, ScriptSet& result, UErrorCode& status) const {
+ getResolvedScriptSetWithout(input, USCRIPT_CODE_LIMIT, result, status);
+}
+
+// Computes the resolved script set for a string, omitting characters having the specified script.
+// If USCRIPT_CODE_LIMIT is passed as the second argument, all characters are included.
+void SpoofImpl::getResolvedScriptSetWithout(const UnicodeString& input, UScriptCode script, ScriptSet& result, UErrorCode& status) const {
+ result.setAll();
+
+ ScriptSet temp;
+ UChar32 codePoint;
+ for (int32_t i = 0; i < input.length(); i += U16_LENGTH(codePoint)) {
+ codePoint = input.char32At(i);
+
+ // Compute the augmented script set for the character
+ getAugmentedScriptSet(codePoint, temp, status);
+ if (U_FAILURE(status)) { return; }
+
+ // Intersect the augmented script set with the resolved script set, but only if the character doesn't
+ // have the script specified in the function call
+ if (script == USCRIPT_CODE_LIMIT || !temp.test(script, status)) {
+ result.intersect(temp);
+ }
+ }
+}
+
+// Computes the set of numerics for a string, according to UTS 39 section 5.3.
+void SpoofImpl::getNumerics(const UnicodeString& input, UnicodeSet& result, UErrorCode& /*status*/) const {
+ result.clear();
+
+ UChar32 codePoint;
+ for (int32_t i = 0; i < input.length(); i += U16_LENGTH(codePoint)) {
+ codePoint = input.char32At(i);
+
+ // Store a representative character for each kind of decimal digit
+ if (u_charType(codePoint) == U_DECIMAL_DIGIT_NUMBER) {
+ // Store the zero character as a representative for comparison.
+ // Unicode guarantees it is codePoint - value
+ result.add(codePoint - (UChar32)u_getNumericValue(codePoint));
+ }
+ }
+}
+
+// Computes the restriction level of a string, according to UTS 39 section 5.2.
+URestrictionLevel SpoofImpl::getRestrictionLevel(const UnicodeString& input, UErrorCode& status) const {
+ // Section 5.2 step 1:
+ if (!fAllowedCharsSet->containsAll(input)) {
+ return USPOOF_UNRESTRICTIVE;
+ }
+
+ // Section 5.2 step 2
+ // Java use a static UnicodeSet for this test. In C++, avoid the static variable
+ // and just do a simple for loop.
+ UBool allASCII = TRUE;
+ for (int32_t i=0, length=input.length(); i<length; i++) {
+ if (input.charAt(i) > 0x7f) {
+ allASCII = FALSE;
+ break;
+ }
+ }
+ if (allASCII) {
+ return USPOOF_ASCII;
+ }
+
+ // Section 5.2 steps 3:
+ ScriptSet resolvedScriptSet;
+ getResolvedScriptSet(input, resolvedScriptSet, status);
+ if (U_FAILURE(status)) { return USPOOF_UNRESTRICTIVE; }
+
+ // Section 5.2 step 4:
+ if (!resolvedScriptSet.isEmpty()) {
+ return USPOOF_SINGLE_SCRIPT_RESTRICTIVE;
+ }
+
+ // Section 5.2 step 5:
+ ScriptSet resolvedNoLatn;
+ getResolvedScriptSetWithout(input, USCRIPT_LATIN, resolvedNoLatn, status);
+ if (U_FAILURE(status)) { return USPOOF_UNRESTRICTIVE; }
+
+ // Section 5.2 step 6:
+ if (resolvedNoLatn.test(USCRIPT_HAN_WITH_BOPOMOFO, status)
+ || resolvedNoLatn.test(USCRIPT_JAPANESE, status)
+ || resolvedNoLatn.test(USCRIPT_KOREAN, status)) {
+ return USPOOF_HIGHLY_RESTRICTIVE;
+ }
+
+ // Section 5.2 step 7:
+ if (!resolvedNoLatn.isEmpty()
+ && !resolvedNoLatn.test(USCRIPT_CYRILLIC, status)
+ && !resolvedNoLatn.test(USCRIPT_GREEK, status)
+ && !resolvedNoLatn.test(USCRIPT_CHEROKEE, status)) {
+ return USPOOF_MODERATELY_RESTRICTIVE;
+ }
+
+ // Section 5.2 step 8:
+ return USPOOF_MINIMALLY_RESTRICTIVE;
+}
+
+int32_t SpoofImpl::findHiddenOverlay(const UnicodeString& input, UErrorCode&) const {
+ bool sawLeadCharacter = false;
+ for (int32_t i=0; i<input.length();) {
+ UChar32 cp = input.char32At(i);
+ if (sawLeadCharacter && cp == 0x0307) {
+ return i;
+ }
+ uint8_t combiningClass = u_getCombiningClass(cp);
+ // Skip over characters except for those with combining class 0 (non-combining characters) or with
+ // combining class 230 (same class as U+0307)
+ U_ASSERT(u_getCombiningClass(0x0307) == 230);
+ if (combiningClass == 0 || combiningClass == 230) {
+ sawLeadCharacter = isIllegalCombiningDotLeadCharacter(cp);
+ }
+ i += U16_LENGTH(cp);
+ }
+ return -1;
+}
+
+static inline bool isIllegalCombiningDotLeadCharacterNoLookup(UChar32 cp) {
+ return cp == u'i' || cp == u'j' || cp == u'ı' || cp == u'ȷ' || cp == u'l' ||
+ u_hasBinaryProperty(cp, UCHAR_SOFT_DOTTED);
+}
+
+bool SpoofImpl::isIllegalCombiningDotLeadCharacter(UChar32 cp) const {
+ if (isIllegalCombiningDotLeadCharacterNoLookup(cp)) {
+ return true;
+ }
+ UnicodeString skelStr;
+ fSpoofData->confusableLookup(cp, skelStr);
+ UChar32 finalCp = skelStr.char32At(skelStr.moveIndex32(skelStr.length(), -1));
+ if (finalCp != cp && isIllegalCombiningDotLeadCharacterNoLookup(finalCp)) {
+ return true;
+ }
+ return false;
+}
+
+
+
+// Convert a text format hex number. Utility function used by builder code. Static.
+// Input: UChar *string text. Output: a UChar32
+// Input has been pre-checked, and will have no non-hex chars.
+// The number must fall in the code point range of 0..0x10ffff
+// Static Function.
+UChar32 SpoofImpl::ScanHex(const UChar *s, int32_t start, int32_t limit, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+ U_ASSERT(limit-start > 0);
+ uint32_t val = 0;
+ int i;
+ for (i=start; i<limit; i++) {
+ int digitVal = s[i] - 0x30;
+ if (digitVal>9) {
+ digitVal = 0xa + (s[i] - 0x41); // Upper Case 'A'
+ }
+ if (digitVal>15) {
+ digitVal = 0xa + (s[i] - 0x61); // Lower Case 'a'
+ }
+ U_ASSERT(digitVal <= 0xf);
+ val <<= 4;
+ val += digitVal;
+ }
+ if (val > 0x10ffff) {
+ status = U_PARSE_ERROR;
+ val = 0;
+ }
+ return (UChar32)val;
+}
+
+
+//-----------------------------------------
+//
+// class CheckResult Implementation
+//
+//-----------------------------------------
+
+CheckResult::CheckResult() {
+ clear();
+}
+
+USpoofCheckResult* CheckResult::asUSpoofCheckResult() {
+ return exportForC();
+}
+
+//
+// Incoming parameter check on Status and the CheckResult object
+// received from the C API.
+//
+const CheckResult* CheckResult::validateThis(const USpoofCheckResult *ptr, UErrorCode &status) {
+ return validate(ptr, status);
+}
+
+CheckResult* CheckResult::validateThis(USpoofCheckResult *ptr, UErrorCode &status) {
+ return validate(ptr, status);
+}
+
+void CheckResult::clear() {
+ fChecks = 0;
+ fNumerics.clear();
+ fRestrictionLevel = USPOOF_UNDEFINED_RESTRICTIVE;
+}
+
+int32_t CheckResult::toCombinedBitmask(int32_t enabledChecks) {
+ if ((enabledChecks & USPOOF_AUX_INFO) != 0 && fRestrictionLevel != USPOOF_UNDEFINED_RESTRICTIVE) {
+ return fChecks | fRestrictionLevel;
+ } else {
+ return fChecks;
+ }
+}
+
+CheckResult::~CheckResult() {
+}
+
+//----------------------------------------------------------------------------------------------
+//
+// class SpoofData Implementation
+//
+//----------------------------------------------------------------------------------------------
+
+
+UBool SpoofData::validateDataVersion(UErrorCode &status) const {
+ if (U_FAILURE(status) ||
+ fRawData == NULL ||
+ fRawData->fMagic != USPOOF_MAGIC ||
+ fRawData->fFormatVersion[0] != USPOOF_CONFUSABLE_DATA_FORMAT_VERSION ||
+ fRawData->fFormatVersion[1] != 0 ||
+ fRawData->fFormatVersion[2] != 0 ||
+ fRawData->fFormatVersion[3] != 0) {
+ status = U_INVALID_FORMAT_ERROR;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static UBool U_CALLCONV
+spoofDataIsAcceptable(void *context,
+ const char * /* type */, const char * /*name*/,
+ const UDataInfo *pInfo) {
+ if(
+ pInfo->size >= 20 &&
+ pInfo->isBigEndian == U_IS_BIG_ENDIAN &&
+ pInfo->charsetFamily == U_CHARSET_FAMILY &&
+ pInfo->dataFormat[0] == 0x43 && // dataFormat="Cfu "
+ pInfo->dataFormat[1] == 0x66 &&
+ pInfo->dataFormat[2] == 0x75 &&
+ pInfo->dataFormat[3] == 0x20 &&
+ pInfo->formatVersion[0] == USPOOF_CONFUSABLE_DATA_FORMAT_VERSION
+ ) {
+ UVersionInfo *version = static_cast<UVersionInfo *>(context);
+ if(version != NULL) {
+ uprv_memcpy(version, pInfo->dataVersion, 4);
+ }
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+// Methods for the loading of the default confusables data file. The confusable
+// data is loaded only when it is needed.
+//
+// SpoofData::getDefault() - Return the default confusables data, and call the
+// initOnce() if it is not available. Adds a reference
+// to the SpoofData that the caller is responsible for
+// decrementing when they are done with the data.
+//
+// uspoof_loadDefaultData - Called once, from initOnce(). The resulting SpoofData
+// is shared by all spoof checkers using the default data.
+//
+// uspoof_cleanupDefaultData - Called during cleanup.
+//
+
+static UInitOnce gSpoofInitDefaultOnce = U_INITONCE_INITIALIZER;
+static SpoofData* gDefaultSpoofData;
+
+static UBool U_CALLCONV
+uspoof_cleanupDefaultData(void) {
+ if (gDefaultSpoofData) {
+ // Will delete, assuming all user-level spoof checkers were closed.
+ gDefaultSpoofData->removeReference();
+ gDefaultSpoofData = nullptr;
+ gSpoofInitDefaultOnce.reset();
+ }
+ return TRUE;
+}
+
+static void U_CALLCONV uspoof_loadDefaultData(UErrorCode& status) {
+ UDataMemory *udm = udata_openChoice(nullptr, "cfu", "confusables",
+ spoofDataIsAcceptable,
+ nullptr, // context, would receive dataVersion if supplied.
+ &status);
+ if (U_FAILURE(status)) { return; }
+ gDefaultSpoofData = new SpoofData(udm, status);
+ if (U_FAILURE(status)) {
+ delete gDefaultSpoofData;
+ gDefaultSpoofData = nullptr;
+ return;
+ }
+ if (gDefaultSpoofData == nullptr) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ ucln_i18n_registerCleanup(UCLN_I18N_SPOOFDATA, uspoof_cleanupDefaultData);
+}
+
+SpoofData* SpoofData::getDefault(UErrorCode& status) {
+ umtx_initOnce(gSpoofInitDefaultOnce, &uspoof_loadDefaultData, status);
+ if (U_FAILURE(status)) { return NULL; }
+ gDefaultSpoofData->addReference();
+ return gDefaultSpoofData;
+}
+
+
+
+SpoofData::SpoofData(UDataMemory *udm, UErrorCode &status)
+{
+ reset();
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fUDM = udm;
+ // fRawData is non-const because it may be constructed by the data builder.
+ fRawData = reinterpret_cast<SpoofDataHeader *>(
+ const_cast<void *>(udata_getMemory(udm)));
+ validateDataVersion(status);
+ initPtrs(status);
+}
+
+
+SpoofData::SpoofData(const void *data, int32_t length, UErrorCode &status)
+{
+ reset();
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if ((size_t)length < sizeof(SpoofDataHeader)) {
+ status = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+ if (data == NULL) {
+ status = U_ILLEGAL_ARGUMENT_ERROR;
+ return;
+ }
+ void *ncData = const_cast<void *>(data);
+ fRawData = static_cast<SpoofDataHeader *>(ncData);
+ if (length < fRawData->fLength) {
+ status = U_INVALID_FORMAT_ERROR;
+ return;
+ }
+ validateDataVersion(status);
+ initPtrs(status);
+}
+
+
+// Spoof Data constructor for use from data builder.
+// Initializes a new, empty data area that will be populated later.
+SpoofData::SpoofData(UErrorCode &status) {
+ reset();
+ if (U_FAILURE(status)) {
+ return;
+ }
+ fDataOwned = true;
+
+ // The spoof header should already be sized to be a multiple of 16 bytes.
+ // Just in case it's not, round it up.
+ uint32_t initialSize = (sizeof(SpoofDataHeader) + 15) & ~15;
+ U_ASSERT(initialSize == sizeof(SpoofDataHeader));
+
+ fRawData = static_cast<SpoofDataHeader *>(uprv_malloc(initialSize));
+ fMemLimit = initialSize;
+ if (fRawData == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+ uprv_memset(fRawData, 0, initialSize);
+
+ fRawData->fMagic = USPOOF_MAGIC;
+ fRawData->fFormatVersion[0] = USPOOF_CONFUSABLE_DATA_FORMAT_VERSION;
+ fRawData->fFormatVersion[1] = 0;
+ fRawData->fFormatVersion[2] = 0;
+ fRawData->fFormatVersion[3] = 0;
+ initPtrs(status);
+}
+
+// reset() - initialize all fields.
+// Should be updated if any new fields are added.
+// Called by constructors to put things in a known initial state.
+void SpoofData::reset() {
+ fRawData = NULL;
+ fDataOwned = FALSE;
+ fUDM = NULL;
+ fMemLimit = 0;
+ fRefCount = 1;
+ fCFUKeys = NULL;
+ fCFUValues = NULL;
+ fCFUStrings = NULL;
+}
+
+
+// SpoofData::initPtrs()
+// Initialize the pointers to the various sections of the raw data.
+//
+// This function is used both during the Trie building process (multiple
+// times, as the individual data sections are added), and
+// during the opening of a Spoof Checker from prebuilt data.
+//
+// The pointers for non-existent data sections (identified by an offset of 0)
+// are set to NULL.
+//
+// Note: During building the data, adding each new data section
+// reallocs the raw data area, which likely relocates it, which
+// in turn requires reinitializing all of the pointers into it, hence
+// multiple calls to this function during building.
+//
+void SpoofData::initPtrs(UErrorCode &status) {
+ fCFUKeys = NULL;
+ fCFUValues = NULL;
+ fCFUStrings = NULL;
+ if (U_FAILURE(status)) {
+ return;
+ }
+ if (fRawData->fCFUKeys != 0) {
+ fCFUKeys = (int32_t *)((char *)fRawData + fRawData->fCFUKeys);
+ }
+ if (fRawData->fCFUStringIndex != 0) {
+ fCFUValues = (uint16_t *)((char *)fRawData + fRawData->fCFUStringIndex);
+ }
+ if (fRawData->fCFUStringTable != 0) {
+ fCFUStrings = (UChar *)((char *)fRawData + fRawData->fCFUStringTable);
+ }
+}
+
+
+SpoofData::~SpoofData() {
+ if (fDataOwned) {
+ uprv_free(fRawData);
+ }
+ fRawData = NULL;
+ if (fUDM != NULL) {
+ udata_close(fUDM);
+ }
+ fUDM = NULL;
+}
+
+
+void SpoofData::removeReference() {
+ if (umtx_atomic_dec(&fRefCount) == 0) {
+ delete this;
+ }
+}
+
+
+SpoofData *SpoofData::addReference() {
+ umtx_atomic_inc(&fRefCount);
+ return this;
+}
+
+
+void *SpoofData::reserveSpace(int32_t numBytes, UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return NULL;
+ }
+ if (!fDataOwned) {
+ UPRV_UNREACHABLE_EXIT;
+ }
+
+ numBytes = (numBytes + 15) & ~15; // Round up to a multiple of 16
+ uint32_t returnOffset = fMemLimit;
+ fMemLimit += numBytes;
+ fRawData = static_cast<SpoofDataHeader *>(uprv_realloc(fRawData, fMemLimit));
+ fRawData->fLength = fMemLimit;
+ uprv_memset((char *)fRawData + returnOffset, 0, numBytes);
+ initPtrs(status);
+ return (char *)fRawData + returnOffset;
+}
+
+int32_t SpoofData::serialize(void *buf, int32_t capacity, UErrorCode &status) const {
+ int32_t dataSize = fRawData->fLength;
+ if (capacity < dataSize) {
+ status = U_BUFFER_OVERFLOW_ERROR;
+ return dataSize;
+ }
+ uprv_memcpy(buf, fRawData, dataSize);
+ return dataSize;
+}
+
+int32_t SpoofData::size() const {
+ return fRawData->fLength;
+}
+
+//-------------------------------
+//
+// Front-end APIs for SpoofData
+//
+//-------------------------------
+
+int32_t SpoofData::confusableLookup(UChar32 inChar, UnicodeString &dest) const {
+ // Perform a binary search.
+ // [lo, hi), i.e lo is inclusive, hi is exclusive.
+ // The result after the loop will be in lo.
+ int32_t lo = 0;
+ int32_t hi = length();
+ do {
+ int32_t mid = (lo + hi) / 2;
+ if (codePointAt(mid) > inChar) {
+ hi = mid;
+ } else if (codePointAt(mid) < inChar) {
+ lo = mid;
+ } else {
+ // Found result. Break early.
+ lo = mid;
+ break;
+ }
+ } while (hi - lo > 1);
+
+ // Did we find an entry? If not, the char maps to itself.
+ if (codePointAt(lo) != inChar) {
+ dest.append(inChar);
+ return 1;
+ }
+
+ // Add the element to the string builder and return.
+ return appendValueTo(lo, dest);
+}
+
+int32_t SpoofData::length() const {
+ return fRawData->fCFUKeysSize;
+}
+
+UChar32 SpoofData::codePointAt(int32_t index) const {
+ return ConfusableDataUtils::keyToCodePoint(fCFUKeys[index]);
+}
+
+int32_t SpoofData::appendValueTo(int32_t index, UnicodeString& dest) const {
+ int32_t stringLength = ConfusableDataUtils::keyToLength(fCFUKeys[index]);
+
+ // Value is either a char (for strings of length 1) or
+ // an index into the string table (for longer strings)
+ uint16_t value = fCFUValues[index];
+ if (stringLength == 1) {
+ dest.append((UChar)value);
+ } else {
+ dest.append(fCFUStrings + value, stringLength);
+ }
+
+ return stringLength;
+}
+
+
+U_NAMESPACE_END
+
+U_NAMESPACE_USE
+
+//-----------------------------------------------------------------------------
+//
+// uspoof_swap - byte swap and char encoding swap of spoof data
+//
+//-----------------------------------------------------------------------------
+U_CAPI int32_t U_EXPORT2
+uspoof_swap(const UDataSwapper *ds, const void *inData, int32_t length, void *outData,
+ UErrorCode *status) {
+
+ if (status == NULL || U_FAILURE(*status)) {
+ return 0;
+ }
+ if(ds==NULL || inData==NULL || length<-1 || (length>0 && outData==NULL)) {
+ *status=U_ILLEGAL_ARGUMENT_ERROR;
+ return 0;
+ }
+
+ //
+ // Check that the data header is for spoof data.
+ // (Header contents are defined in gencfu.cpp)
+ //
+ const UDataInfo *pInfo = (const UDataInfo *)((const char *)inData+4);
+ if(!( pInfo->dataFormat[0]==0x43 && /* dataFormat="Cfu " */
+ pInfo->dataFormat[1]==0x66 &&
+ pInfo->dataFormat[2]==0x75 &&
+ pInfo->dataFormat[3]==0x20 &&
+ pInfo->formatVersion[0]==USPOOF_CONFUSABLE_DATA_FORMAT_VERSION &&
+ pInfo->formatVersion[1]==0 &&
+ pInfo->formatVersion[2]==0 &&
+ pInfo->formatVersion[3]==0 )) {
+ udata_printError(ds, "uspoof_swap(): data format %02x.%02x.%02x.%02x "
+ "(format version %02x %02x %02x %02x) is not recognized\n",
+ pInfo->dataFormat[0], pInfo->dataFormat[1],
+ pInfo->dataFormat[2], pInfo->dataFormat[3],
+ pInfo->formatVersion[0], pInfo->formatVersion[1],
+ pInfo->formatVersion[2], pInfo->formatVersion[3]);
+ *status=U_UNSUPPORTED_ERROR;
+ return 0;
+ }
+
+ //
+ // Swap the data header. (This is the generic ICU Data Header, not the uspoof Specific
+ // header). This swap also conveniently gets us
+ // the size of the ICU d.h., which lets us locate the start
+ // of the uspoof specific data.
+ //
+ int32_t headerSize=udata_swapDataHeader(ds, inData, length, outData, status);
+
+
+ //
+ // Get the Spoof Data Header, and check that it appears to be OK.
+ //
+ //
+ const uint8_t *inBytes =(const uint8_t *)inData+headerSize;
+ SpoofDataHeader *spoofDH = (SpoofDataHeader *)inBytes;
+ if (ds->readUInt32(spoofDH->fMagic) != USPOOF_MAGIC ||
+ ds->readUInt32(spoofDH->fLength) < sizeof(SpoofDataHeader))
+ {
+ udata_printError(ds, "uspoof_swap(): Spoof Data header is invalid.\n");
+ *status=U_UNSUPPORTED_ERROR;
+ return 0;
+ }
+
+ //
+ // Prefight operation? Just return the size
+ //
+ int32_t spoofDataLength = ds->readUInt32(spoofDH->fLength);
+ int32_t totalSize = headerSize + spoofDataLength;
+ if (length < 0) {
+ return totalSize;
+ }
+
+ //
+ // Check that length passed in is consistent with length from Spoof data header.
+ //
+ if (length < totalSize) {
+ udata_printError(ds, "uspoof_swap(): too few bytes (%d after ICU Data header) for spoof data.\n",
+ spoofDataLength);
+ *status=U_INDEX_OUTOFBOUNDS_ERROR;
+ return 0;
+ }
+
+
+ //
+ // Swap the Data. Do the data itself first, then the Spoof Data Header, because
+ // we need to reference the header to locate the data, and an
+ // inplace swap of the header leaves it unusable.
+ //
+ uint8_t *outBytes = (uint8_t *)outData + headerSize;
+ SpoofDataHeader *outputDH = (SpoofDataHeader *)outBytes;
+
+ int32_t sectionStart;
+ int32_t sectionLength;
+
+ //
+ // If not swapping in place, zero out the output buffer before starting.
+ // Gaps may exist between the individual sections, and these must be zeroed in
+ // the output buffer. The simplest way to do that is to just zero the whole thing.
+ //
+ if (inBytes != outBytes) {
+ uprv_memset(outBytes, 0, spoofDataLength);
+ }
+
+ // Confusables Keys Section (fCFUKeys)
+ sectionStart = ds->readUInt32(spoofDH->fCFUKeys);
+ sectionLength = ds->readUInt32(spoofDH->fCFUKeysSize) * 4;
+ ds->swapArray32(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
+
+ // String Index Section
+ sectionStart = ds->readUInt32(spoofDH->fCFUStringIndex);
+ sectionLength = ds->readUInt32(spoofDH->fCFUStringIndexSize) * 2;
+ ds->swapArray16(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
+
+ // String Table Section
+ sectionStart = ds->readUInt32(spoofDH->fCFUStringTable);
+ sectionLength = ds->readUInt32(spoofDH->fCFUStringTableLen) * 2;
+ ds->swapArray16(ds, inBytes+sectionStart, sectionLength, outBytes+sectionStart, status);
+
+ // And, last, swap the header itself.
+ // int32_t fMagic // swap this
+ // uint8_t fFormatVersion[4] // Do not swap this, just copy
+ // int32_t fLength and all the rest // Swap the rest, all is 32 bit stuff.
+ //
+ uint32_t magic = ds->readUInt32(spoofDH->fMagic);
+ ds->writeUInt32((uint32_t *)&outputDH->fMagic, magic);
+
+ if (outputDH->fFormatVersion != spoofDH->fFormatVersion) {
+ uprv_memcpy(outputDH->fFormatVersion, spoofDH->fFormatVersion, sizeof(spoofDH->fFormatVersion));
+ }
+ // swap starting at fLength
+ ds->swapArray32(ds, &spoofDH->fLength, sizeof(SpoofDataHeader)-8 /* minus magic and fFormatVersion[4] */, &outputDH->fLength, status);
+
+ return totalSize;
+}
+
+#endif
+
+
diff --git a/thirdparty/icu4c/i18n/uspoof_impl.h b/thirdparty/icu4c/i18n/uspoof_impl.h
new file mode 100644
index 0000000000..e75ae262bd
--- /dev/null
+++ b/thirdparty/icu4c/i18n/uspoof_impl.h
@@ -0,0 +1,343 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+***************************************************************************
+* Copyright (C) 2008-2013, International Business Machines Corporation
+* and others. All Rights Reserved.
+***************************************************************************
+*
+* uspoof_impl.h
+*
+* Implementation header for spoof detection
+*
+*/
+
+#ifndef USPOOFIM_H
+#define USPOOFIM_H
+
+#include "uassert.h"
+#include "unicode/utypes.h"
+#include "unicode/uspoof.h"
+#include "unicode/uscript.h"
+#include "unicode/udata.h"
+#include "udataswp.h"
+#include "utrie2.h"
+
+#if !UCONFIG_NO_NORMALIZATION
+
+#ifdef __cplusplus
+
+#include "capi_helper.h"
+
+U_NAMESPACE_BEGIN
+
+// The maximum length (in UTF-16 UChars) of the skeleton replacement string resulting from
+// a single input code point. This is function of the unicode.org data.
+#define USPOOF_MAX_SKELETON_EXPANSION 20
+
+// The default stack buffer size for copies or conversions or normalizations
+// of input strings being checked. (Used in multiple places.)
+#define USPOOF_STACK_BUFFER_SIZE 100
+
+// Magic number for sanity checking spoof data.
+#define USPOOF_MAGIC 0x3845fdef
+
+// Magic number for sanity checking spoof checkers.
+#define USPOOF_CHECK_MAGIC 0x2734ecde
+
+class ScriptSet;
+class SpoofData;
+struct SpoofDataHeader;
+class ConfusableDataUtils;
+
+/**
+ * Class SpoofImpl corresponds directly to the plain C API opaque type
+ * USpoofChecker. One can be cast to the other.
+ */
+class SpoofImpl : public UObject,
+ public IcuCApiHelper<USpoofChecker, SpoofImpl, USPOOF_MAGIC> {
+public:
+ SpoofImpl(SpoofData *data, UErrorCode& status);
+ SpoofImpl(UErrorCode& status);
+ SpoofImpl();
+ void construct(UErrorCode& status);
+ virtual ~SpoofImpl();
+
+ /** Copy constructor, used by the user level uspoof_clone() function.
+ */
+ SpoofImpl(const SpoofImpl &src, UErrorCode &status);
+
+ USpoofChecker *asUSpoofChecker();
+ static SpoofImpl *validateThis(USpoofChecker *sc, UErrorCode &status);
+ static const SpoofImpl *validateThis(const USpoofChecker *sc, UErrorCode &status);
+
+ /** Set and Get AllowedLocales, implementations of the corresponding API */
+ void setAllowedLocales(const char *localesList, UErrorCode &status);
+ const char * getAllowedLocales(UErrorCode &status);
+
+ // Add (union) to the UnicodeSet all of the characters for the scripts used for
+ // the specified locale. Part of the implementation of setAllowedLocales.
+ void addScriptChars(const char *locale, UnicodeSet *allowedChars, UErrorCode &status);
+
+ // Functions implementing the features of UTS 39 section 5.
+ static void getAugmentedScriptSet(UChar32 codePoint, ScriptSet& result, UErrorCode& status);
+ void getResolvedScriptSet(const UnicodeString& input, ScriptSet& result, UErrorCode& status) const;
+ void getResolvedScriptSetWithout(const UnicodeString& input, UScriptCode script, ScriptSet& result, UErrorCode& status) const;
+ void getNumerics(const UnicodeString& input, UnicodeSet& result, UErrorCode& status) const;
+ URestrictionLevel getRestrictionLevel(const UnicodeString& input, UErrorCode& status) const;
+
+ int32_t findHiddenOverlay(const UnicodeString& input, UErrorCode& status) const;
+ bool isIllegalCombiningDotLeadCharacter(UChar32 cp) const;
+
+ /** parse a hex number. Untility used by the builders. */
+ static UChar32 ScanHex(const UChar *s, int32_t start, int32_t limit, UErrorCode &status);
+
+ static UClassID U_EXPORT2 getStaticClassID(void);
+ virtual UClassID getDynamicClassID(void) const override;
+
+ //
+ // Data Members
+ //
+
+ int32_t fChecks; // Bit vector of checks to perform.
+
+ SpoofData *fSpoofData;
+
+ const UnicodeSet *fAllowedCharsSet; // The UnicodeSet of allowed characters.
+ // for this Spoof Checker. Defaults to all chars.
+
+ const char *fAllowedLocales; // The list of allowed locales.
+ URestrictionLevel fRestrictionLevel; // The maximum restriction level for an acceptable identifier.
+};
+
+/**
+ * Class CheckResult corresponds directly to the plain C API opaque type
+ * USpoofCheckResult. One can be cast to the other.
+ */
+class CheckResult : public UObject,
+ public IcuCApiHelper<USpoofCheckResult, CheckResult, USPOOF_CHECK_MAGIC> {
+public:
+ CheckResult();
+ virtual ~CheckResult();
+
+ USpoofCheckResult *asUSpoofCheckResult();
+ static CheckResult *validateThis(USpoofCheckResult *ptr, UErrorCode &status);
+ static const CheckResult *validateThis(const USpoofCheckResult *ptr, UErrorCode &status);
+
+ void clear();
+
+ // Used to convert this CheckResult to the older int32_t return value API
+ int32_t toCombinedBitmask(int32_t expectedChecks);
+
+ // Data Members
+ int32_t fChecks; // Bit vector of checks that were failed.
+ UnicodeSet fNumerics; // Set of numerics found in the string.
+ URestrictionLevel fRestrictionLevel; // The restriction level of the string.
+};
+
+
+//
+// Confusable Mappings Data Structures, version 2.0
+//
+// For the confusable data, we are essentially implementing a map,
+// key: a code point
+// value: a string. Most commonly one char in length, but can be more.
+//
+// The keys are stored as a sorted array of 32 bit ints.
+// bits 0-23 a code point value
+// bits 24-31 length of value string, in UChars (between 1 and 256 UChars).
+// The key table is sorted in ascending code point order. (not on the
+// 32 bit int value, the flag bits do not participate in the sorting.)
+//
+// Lookup is done by means of a binary search in the key table.
+//
+// The corresponding values are kept in a parallel array of 16 bit ints.
+// If the value string is of length 1, it is literally in the value array.
+// For longer strings, the value array contains an index into the strings table.
+//
+// String Table:
+// The strings table contains all of the value strings (those of length two or greater)
+// concatenated together into one long UChar (UTF-16) array.
+//
+// There is no nul character or other mark between adjacent strings.
+//
+//----------------------------------------------------------------------------
+//
+// Changes from format version 1 to format version 2:
+// 1) Removal of the whole-script confusable data tables.
+// 2) Removal of the SL/SA/ML/MA and multi-table flags in the key bitmask.
+// 3) Expansion of string length value in the key bitmask from 2 bits to 8 bits.
+// 4) Removal of the string lengths table since 8 bits is sufficient for the
+// lengths of all entries in confusables.txt.
+
+
+
+// Internal functions for manipulating confusable data table keys
+#define USPOOF_CONFUSABLE_DATA_FORMAT_VERSION 2 // version for ICU 58
+class ConfusableDataUtils {
+public:
+ inline static UChar32 keyToCodePoint(int32_t key) {
+ return key & 0x00ffffff;
+ }
+ inline static int32_t keyToLength(int32_t key) {
+ return ((key & 0xff000000) >> 24) + 1;
+ }
+ inline static int32_t codePointAndLengthToKey(UChar32 codePoint, int32_t length) {
+ U_ASSERT((codePoint & 0x00ffffff) == codePoint);
+ U_ASSERT(length <= 256);
+ return codePoint | ((length - 1) << 24);
+ }
+};
+
+
+//-------------------------------------------------------------------------------------
+//
+// SpoofData
+//
+// A small class that wraps the raw (usually memory mapped) spoof data.
+// Serves two primary functions:
+// 1. Convenience. Contains real pointers to the data, to avoid dealing with
+// the offsets in the raw data.
+// 2. Reference counting. When a spoof checker is cloned, the raw data is shared
+// and must be retained until all checkers using the data are closed.
+// Nothing in this struct includes state that is specific to any particular
+// USpoofDetector object.
+//
+//---------------------------------------------------------------------------------------
+class SpoofData: public UMemory {
+ public:
+ static SpoofData* getDefault(UErrorCode &status); // Get standard ICU spoof data.
+ static void releaseDefault(); // Cleanup reference to default spoof data.
+
+ SpoofData(UErrorCode &status); // Create new spoof data wrapper.
+ // Only used when building new data from rules.
+
+ // Constructor for use when creating from prebuilt default data.
+ // A UDataMemory is what the ICU internal data loading functions provide.
+ // The udm is adopted by the SpoofData.
+ SpoofData(UDataMemory *udm, UErrorCode &status);
+
+ // Constructor for use when creating from serialized data.
+ //
+ SpoofData(const void *serializedData, int32_t length, UErrorCode &status);
+
+ // Check raw Spoof Data Version compatibility.
+ // Return true it looks good.
+ UBool validateDataVersion(UErrorCode &status) const;
+
+ ~SpoofData(); // Destructor not normally used.
+ // Use removeReference() instead.
+ // Reference Counting functions.
+ // Clone of a user-level spoof detector increments the ref count on the data.
+ // Close of a user-level spoof detector decrements the ref count.
+ // If the data is owned by us, it will be deleted when count goes to zero.
+ SpoofData *addReference();
+ void removeReference();
+
+ // Reset all fields to an initial state.
+ // Called from the top of all constructors.
+ void reset();
+
+ // Copy this instance's raw data buffer to the specified address.
+ int32_t serialize(void *buf, int32_t capacity, UErrorCode &status) const;
+
+ // Get the total number of bytes of data backed by this SpoofData.
+ // Not to be confused with length, which returns the number of confusable entries.
+ int32_t size() const;
+
+ // Get the confusable skeleton transform for a single code point.
+ // The result is a string with a length between 1 and 18 as of Unicode 9.
+ // This is the main public endpoint for this class.
+ // @return The length in UTF-16 code units of the substitution string.
+ int32_t confusableLookup(UChar32 inChar, UnicodeString &dest) const;
+
+ // Get the number of confusable entries in this SpoofData.
+ int32_t length() const;
+
+ // Get the code point (key) at the specified index.
+ UChar32 codePointAt(int32_t index) const;
+
+ // Get the confusable skeleton (value) at the specified index.
+ // Append it to the specified UnicodeString&.
+ // @return The length in UTF-16 code units of the skeleton string.
+ int32_t appendValueTo(int32_t index, UnicodeString& dest) const;
+
+ private:
+ // Reserve space in the raw data. For use by builder when putting together a
+ // new set of data. Init the new storage to zero, to prevent inconsistent
+ // results if it is not all otherwise set by the requester.
+ // Return:
+ // pointer to the new space that was added by this function.
+ void *reserveSpace(int32_t numBytes, UErrorCode &status);
+
+ // initialize the pointers from this object to the raw data.
+ void initPtrs(UErrorCode &status);
+
+ SpoofDataHeader *fRawData; // Ptr to the raw memory-mapped data
+ UBool fDataOwned; // True if the raw data is owned, and needs
+ // to be deleted when refcount goes to zero.
+ UDataMemory *fUDM; // If not NULL, our data came from a
+ // UDataMemory, which we must close when
+ // we are done.
+
+ uint32_t fMemLimit; // Limit of available raw data space
+ u_atomic_int32_t fRefCount;
+
+ // Confusable data
+ int32_t *fCFUKeys;
+ uint16_t *fCFUValues;
+ UChar *fCFUStrings;
+
+ friend class ConfusabledataBuilder;
+};
+
+//---------------------------------------------------------------------------------------
+//
+// Raw Binary Data Formats, as loaded from the ICU data file,
+// or as built by the builder.
+//
+//---------------------------------------------------------------------------------------
+struct SpoofDataHeader {
+ int32_t fMagic; // (0x3845fdef)
+ uint8_t fFormatVersion[4]; // Data Format. Same as the value in struct UDataInfo
+ // if there is one associated with this data.
+ int32_t fLength; // Total length in bytes of this spoof data,
+ // including all sections, not just the header.
+
+ // The following four sections refer to data representing the confusable data
+ // from the Unicode.org data from "confusables.txt"
+
+ int32_t fCFUKeys; // byte offset to Keys table (from SpoofDataHeader *)
+ int32_t fCFUKeysSize; // number of entries in keys table (32 bits each)
+
+ // TODO: change name to fCFUValues, for consistency.
+ int32_t fCFUStringIndex; // byte offset to String Indexes table
+ int32_t fCFUStringIndexSize; // number of entries in String Indexes table (16 bits each)
+ // (number of entries must be same as in Keys table
+
+ int32_t fCFUStringTable; // byte offset of String table
+ int32_t fCFUStringTableLen; // length of string table (in 16 bit UChars)
+
+ // The following sections are for data from xidmodifications.txt
+
+ int32_t unused[15]; // Padding, Room for Expansion
+};
+
+
+
+U_NAMESPACE_END
+#endif /* __cplusplus */
+
+/**
+ * Endianness swap function for binary spoof data.
+ * @internal
+ */
+U_CAPI int32_t U_EXPORT2
+uspoof_swap(const UDataSwapper *ds, const void *inData, int32_t length, void *outData,
+ UErrorCode *status);
+
+
+#endif
+
+#endif /* USPOOFIM_H */
+
diff --git a/thirdparty/icu4c/icudt71l.dat b/thirdparty/icu4c/icudt71l.dat
index 4c2c1c4d16..3fa3af9c23 100644
--- a/thirdparty/icu4c/icudt71l.dat
+++ b/thirdparty/icu4c/icudt71l.dat
Binary files differ
diff --git a/thirdparty/libwebp/AUTHORS b/thirdparty/libwebp/AUTHORS
index 8307c2099d..3efcbe25b6 100644
--- a/thirdparty/libwebp/AUTHORS
+++ b/thirdparty/libwebp/AUTHORS
@@ -1,12 +1,15 @@
Contributors:
- Aidan O'Loan (aidanol at gmail dot com)
- Alan Browning (browning at google dot com)
+- Alexandru Ardelean (ardeleanalex at gmail dot com)
+- Brian Ledger (brianpl at google dot com)
- Charles Munger (clm at google dot com)
- Cheng Yi (cyi at google dot com)
- Christian Duvivier (cduvivier at google dot com)
- Christopher Degawa (ccom at randomderp dot com)
- Clement Courbet (courbet at google dot com)
- Djordje Pesut (djordje dot pesut at imgtec dot com)
+- Frank Barchard (fbarchard at google dot com)
- Hui Su (huisu at google dot com)
- Ilya Kurdyukov (jpegqs at gmail dot com)
- Ingvar Stepanyan (rreverser at google dot com)
@@ -22,6 +25,7 @@ Contributors:
- Mans Rullgard (mans at mansr dot com)
- Marcin Kowalczyk (qrczak at google dot com)
- Martin Olsson (mnemo at minimum dot se)
+- Maryla Ustarroz-Calonge (maryla at google dot com)
- Mikołaj Zalewski (mikolajz at google dot com)
- Mislav Bradac (mislavm at google dot com)
- Nico Weber (thakis at chromium dot org)
diff --git a/thirdparty/libwebp/sharpyuv/sharpyuv.c b/thirdparty/libwebp/sharpyuv/sharpyuv.c
new file mode 100644
index 0000000000..8b3ab7216b
--- /dev/null
+++ b/thirdparty/libwebp/sharpyuv/sharpyuv.c
@@ -0,0 +1,498 @@
+// Copyright 2022 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Sharp RGB to YUV conversion.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "sharpyuv/sharpyuv.h"
+
+#include <assert.h>
+#include <limits.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "src/webp/types.h"
+#include "src/dsp/cpu.h"
+#include "sharpyuv/sharpyuv_dsp.h"
+#include "sharpyuv/sharpyuv_gamma.h"
+
+//------------------------------------------------------------------------------
+// Sharp RGB->YUV conversion
+
+static const int kNumIterations = 4;
+
+#define YUV_FIX 16 // fixed-point precision for RGB->YUV
+static const int kYuvHalf = 1 << (YUV_FIX - 1);
+
+// Max bit depth so that intermediate calculations fit in 16 bits.
+static const int kMaxBitDepth = 14;
+
+// Returns the precision shift to use based on the input rgb_bit_depth.
+static int GetPrecisionShift(int rgb_bit_depth) {
+ // Try to add 2 bits of precision if it fits in kMaxBitDepth. Otherwise remove
+ // bits if needed.
+ return ((rgb_bit_depth + 2) <= kMaxBitDepth) ? 2
+ : (kMaxBitDepth - rgb_bit_depth);
+}
+
+typedef int16_t fixed_t; // signed type with extra precision for UV
+typedef uint16_t fixed_y_t; // unsigned type with extra precision for W
+
+//------------------------------------------------------------------------------
+
+static uint8_t clip_8b(fixed_t v) {
+ return (!(v & ~0xff)) ? (uint8_t)v : (v < 0) ? 0u : 255u;
+}
+
+static uint16_t clip(fixed_t v, int max) {
+ return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v;
+}
+
+static fixed_y_t clip_bit_depth(int y, int bit_depth) {
+ const int max = (1 << bit_depth) - 1;
+ return (!(y & ~max)) ? (fixed_y_t)y : (y < 0) ? 0 : max;
+}
+
+//------------------------------------------------------------------------------
+
+static int RGBToGray(int64_t r, int64_t g, int64_t b) {
+ const int64_t luma = 13933 * r + 46871 * g + 4732 * b + kYuvHalf;
+ return (int)(luma >> YUV_FIX);
+}
+
+static uint32_t ScaleDown(uint16_t a, uint16_t b, uint16_t c, uint16_t d,
+ int rgb_bit_depth) {
+ const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
+ const uint32_t A = SharpYuvGammaToLinear(a, bit_depth);
+ const uint32_t B = SharpYuvGammaToLinear(b, bit_depth);
+ const uint32_t C = SharpYuvGammaToLinear(c, bit_depth);
+ const uint32_t D = SharpYuvGammaToLinear(d, bit_depth);
+ return SharpYuvLinearToGamma((A + B + C + D + 2) >> 2, bit_depth);
+}
+
+static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int w,
+ int rgb_bit_depth) {
+ const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
+ int i;
+ for (i = 0; i < w; ++i) {
+ const uint32_t R = SharpYuvGammaToLinear(src[0 * w + i], bit_depth);
+ const uint32_t G = SharpYuvGammaToLinear(src[1 * w + i], bit_depth);
+ const uint32_t B = SharpYuvGammaToLinear(src[2 * w + i], bit_depth);
+ const uint32_t Y = RGBToGray(R, G, B);
+ dst[i] = (fixed_y_t)SharpYuvLinearToGamma(Y, bit_depth);
+ }
+}
+
+static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2,
+ fixed_t* dst, int uv_w, int rgb_bit_depth) {
+ int i;
+ for (i = 0; i < uv_w; ++i) {
+ const int r =
+ ScaleDown(src1[0 * uv_w + 0], src1[0 * uv_w + 1], src2[0 * uv_w + 0],
+ src2[0 * uv_w + 1], rgb_bit_depth);
+ const int g =
+ ScaleDown(src1[2 * uv_w + 0], src1[2 * uv_w + 1], src2[2 * uv_w + 0],
+ src2[2 * uv_w + 1], rgb_bit_depth);
+ const int b =
+ ScaleDown(src1[4 * uv_w + 0], src1[4 * uv_w + 1], src2[4 * uv_w + 0],
+ src2[4 * uv_w + 1], rgb_bit_depth);
+ const int W = RGBToGray(r, g, b);
+ dst[0 * uv_w] = (fixed_t)(r - W);
+ dst[1 * uv_w] = (fixed_t)(g - W);
+ dst[2 * uv_w] = (fixed_t)(b - W);
+ dst += 1;
+ src1 += 2;
+ src2 += 2;
+ }
+}
+
+static void StoreGray(const fixed_y_t* rgb, fixed_y_t* y, int w) {
+ int i;
+ assert(w > 0);
+ for (i = 0; i < w; ++i) {
+ y[i] = RGBToGray(rgb[0 * w + i], rgb[1 * w + i], rgb[2 * w + i]);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+static WEBP_INLINE fixed_y_t Filter2(int A, int B, int W0, int bit_depth) {
+ const int v0 = (A * 3 + B + 2) >> 2;
+ return clip_bit_depth(v0 + W0, bit_depth);
+}
+
+//------------------------------------------------------------------------------
+
+static WEBP_INLINE int Shift(int v, int shift) {
+ return (shift >= 0) ? (v << shift) : (v >> -shift);
+}
+
+static void ImportOneRow(const uint8_t* const r_ptr,
+ const uint8_t* const g_ptr,
+ const uint8_t* const b_ptr,
+ int rgb_step,
+ int rgb_bit_depth,
+ int pic_width,
+ fixed_y_t* const dst) {
+ // Convert the rgb_step from a number of bytes to a number of uint8_t or
+ // uint16_t values depending the bit depth.
+ const int step = (rgb_bit_depth > 8) ? rgb_step / 2 : rgb_step;
+ int i;
+ const int w = (pic_width + 1) & ~1;
+ for (i = 0; i < pic_width; ++i) {
+ const int off = i * step;
+ const int shift = GetPrecisionShift(rgb_bit_depth);
+ if (rgb_bit_depth == 8) {
+ dst[i + 0 * w] = Shift(r_ptr[off], shift);
+ dst[i + 1 * w] = Shift(g_ptr[off], shift);
+ dst[i + 2 * w] = Shift(b_ptr[off], shift);
+ } else {
+ dst[i + 0 * w] = Shift(((uint16_t*)r_ptr)[off], shift);
+ dst[i + 1 * w] = Shift(((uint16_t*)g_ptr)[off], shift);
+ dst[i + 2 * w] = Shift(((uint16_t*)b_ptr)[off], shift);
+ }
+ }
+ if (pic_width & 1) { // replicate rightmost pixel
+ dst[pic_width + 0 * w] = dst[pic_width + 0 * w - 1];
+ dst[pic_width + 1 * w] = dst[pic_width + 1 * w - 1];
+ dst[pic_width + 2 * w] = dst[pic_width + 2 * w - 1];
+ }
+}
+
+static void InterpolateTwoRows(const fixed_y_t* const best_y,
+ const fixed_t* prev_uv,
+ const fixed_t* cur_uv,
+ const fixed_t* next_uv,
+ int w,
+ fixed_y_t* out1,
+ fixed_y_t* out2,
+ int rgb_bit_depth) {
+ const int uv_w = w >> 1;
+ const int len = (w - 1) >> 1; // length to filter
+ int k = 3;
+ const int bit_depth = rgb_bit_depth + GetPrecisionShift(rgb_bit_depth);
+ while (k-- > 0) { // process each R/G/B segments in turn
+ // special boundary case for i==0
+ out1[0] = Filter2(cur_uv[0], prev_uv[0], best_y[0], bit_depth);
+ out2[0] = Filter2(cur_uv[0], next_uv[0], best_y[w], bit_depth);
+
+ SharpYuvFilterRow(cur_uv, prev_uv, len, best_y + 0 + 1, out1 + 1,
+ bit_depth);
+ SharpYuvFilterRow(cur_uv, next_uv, len, best_y + w + 1, out2 + 1,
+ bit_depth);
+
+ // special boundary case for i == w - 1 when w is even
+ if (!(w & 1)) {
+ out1[w - 1] = Filter2(cur_uv[uv_w - 1], prev_uv[uv_w - 1],
+ best_y[w - 1 + 0], bit_depth);
+ out2[w - 1] = Filter2(cur_uv[uv_w - 1], next_uv[uv_w - 1],
+ best_y[w - 1 + w], bit_depth);
+ }
+ out1 += w;
+ out2 += w;
+ prev_uv += uv_w;
+ cur_uv += uv_w;
+ next_uv += uv_w;
+ }
+}
+
+static WEBP_INLINE int RGBToYUVComponent(int r, int g, int b,
+ const int coeffs[4], int sfix) {
+ const int srounder = 1 << (YUV_FIX + sfix - 1);
+ const int luma = coeffs[0] * r + coeffs[1] * g + coeffs[2] * b +
+ coeffs[3] + srounder;
+ return (luma >> (YUV_FIX + sfix));
+}
+
+static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv,
+ uint8_t* y_ptr, int y_stride, uint8_t* u_ptr,
+ int u_stride, uint8_t* v_ptr, int v_stride,
+ int rgb_bit_depth,
+ int yuv_bit_depth, int width, int height,
+ const SharpYuvConversionMatrix* yuv_matrix) {
+ int i, j;
+ const fixed_t* const best_uv_base = best_uv;
+ const int w = (width + 1) & ~1;
+ const int h = (height + 1) & ~1;
+ const int uv_w = w >> 1;
+ const int uv_h = h >> 1;
+ const int sfix = GetPrecisionShift(rgb_bit_depth);
+ const int yuv_max = (1 << yuv_bit_depth) - 1;
+
+ for (best_uv = best_uv_base, j = 0; j < height; ++j) {
+ for (i = 0; i < width; ++i) {
+ const int off = (i >> 1);
+ const int W = best_y[i];
+ const int r = best_uv[off + 0 * uv_w] + W;
+ const int g = best_uv[off + 1 * uv_w] + W;
+ const int b = best_uv[off + 2 * uv_w] + W;
+ const int y = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_y, sfix);
+ if (yuv_bit_depth <= 8) {
+ y_ptr[i] = clip_8b(y);
+ } else {
+ ((uint16_t*)y_ptr)[i] = clip(y, yuv_max);
+ }
+ }
+ best_y += w;
+ best_uv += (j & 1) * 3 * uv_w;
+ y_ptr += y_stride;
+ }
+ for (best_uv = best_uv_base, j = 0; j < uv_h; ++j) {
+ for (i = 0; i < uv_w; ++i) {
+ const int off = i;
+ // Note r, g and b values here are off by W, but a constant offset on all
+ // 3 components doesn't change the value of u and v with a YCbCr matrix.
+ const int r = best_uv[off + 0 * uv_w];
+ const int g = best_uv[off + 1 * uv_w];
+ const int b = best_uv[off + 2 * uv_w];
+ const int u = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_u, sfix);
+ const int v = RGBToYUVComponent(r, g, b, yuv_matrix->rgb_to_v, sfix);
+ if (yuv_bit_depth <= 8) {
+ u_ptr[i] = clip_8b(u);
+ v_ptr[i] = clip_8b(v);
+ } else {
+ ((uint16_t*)u_ptr)[i] = clip(u, yuv_max);
+ ((uint16_t*)v_ptr)[i] = clip(v, yuv_max);
+ }
+ }
+ best_uv += 3 * uv_w;
+ u_ptr += u_stride;
+ v_ptr += v_stride;
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// Main function
+
+static void* SafeMalloc(uint64_t nmemb, size_t size) {
+ const uint64_t total_size = nmemb * (uint64_t)size;
+ if (total_size != (size_t)total_size) return NULL;
+ return malloc((size_t)total_size);
+}
+
+#define SAFE_ALLOC(W, H, T) ((T*)SafeMalloc((W) * (H), sizeof(T)))
+
+static int DoSharpArgbToYuv(const uint8_t* r_ptr, const uint8_t* g_ptr,
+ const uint8_t* b_ptr, int rgb_step, int rgb_stride,
+ int rgb_bit_depth, uint8_t* y_ptr, int y_stride,
+ uint8_t* u_ptr, int u_stride, uint8_t* v_ptr,
+ int v_stride, int yuv_bit_depth, int width,
+ int height,
+ const SharpYuvConversionMatrix* yuv_matrix) {
+ // we expand the right/bottom border if needed
+ const int w = (width + 1) & ~1;
+ const int h = (height + 1) & ~1;
+ const int uv_w = w >> 1;
+ const int uv_h = h >> 1;
+ uint64_t prev_diff_y_sum = ~0;
+ int j, iter;
+
+ // TODO(skal): allocate one big memory chunk. But for now, it's easier
+ // for valgrind debugging to have several chunks.
+ fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t); // scratch
+ fixed_y_t* const best_y_base = SAFE_ALLOC(w, h, fixed_y_t);
+ fixed_y_t* const target_y_base = SAFE_ALLOC(w, h, fixed_y_t);
+ fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t);
+ fixed_t* const best_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
+ fixed_t* const target_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
+ fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t);
+ fixed_y_t* best_y = best_y_base;
+ fixed_y_t* target_y = target_y_base;
+ fixed_t* best_uv = best_uv_base;
+ fixed_t* target_uv = target_uv_base;
+ const uint64_t diff_y_threshold = (uint64_t)(3.0 * w * h);
+ int ok;
+ assert(w > 0);
+ assert(h > 0);
+
+ if (best_y_base == NULL || best_uv_base == NULL ||
+ target_y_base == NULL || target_uv_base == NULL ||
+ best_rgb_y == NULL || best_rgb_uv == NULL ||
+ tmp_buffer == NULL) {
+ ok = 0;
+ goto End;
+ }
+
+ // Import RGB samples to W/RGB representation.
+ for (j = 0; j < height; j += 2) {
+ const int is_last_row = (j == height - 1);
+ fixed_y_t* const src1 = tmp_buffer + 0 * w;
+ fixed_y_t* const src2 = tmp_buffer + 3 * w;
+
+ // prepare two rows of input
+ ImportOneRow(r_ptr, g_ptr, b_ptr, rgb_step, rgb_bit_depth, width,
+ src1);
+ if (!is_last_row) {
+ ImportOneRow(r_ptr + rgb_stride, g_ptr + rgb_stride, b_ptr + rgb_stride,
+ rgb_step, rgb_bit_depth, width, src2);
+ } else {
+ memcpy(src2, src1, 3 * w * sizeof(*src2));
+ }
+ StoreGray(src1, best_y + 0, w);
+ StoreGray(src2, best_y + w, w);
+
+ UpdateW(src1, target_y, w, rgb_bit_depth);
+ UpdateW(src2, target_y + w, w, rgb_bit_depth);
+ UpdateChroma(src1, src2, target_uv, uv_w, rgb_bit_depth);
+ memcpy(best_uv, target_uv, 3 * uv_w * sizeof(*best_uv));
+ best_y += 2 * w;
+ best_uv += 3 * uv_w;
+ target_y += 2 * w;
+ target_uv += 3 * uv_w;
+ r_ptr += 2 * rgb_stride;
+ g_ptr += 2 * rgb_stride;
+ b_ptr += 2 * rgb_stride;
+ }
+
+ // Iterate and resolve clipping conflicts.
+ for (iter = 0; iter < kNumIterations; ++iter) {
+ const fixed_t* cur_uv = best_uv_base;
+ const fixed_t* prev_uv = best_uv_base;
+ uint64_t diff_y_sum = 0;
+
+ best_y = best_y_base;
+ best_uv = best_uv_base;
+ target_y = target_y_base;
+ target_uv = target_uv_base;
+ for (j = 0; j < h; j += 2) {
+ fixed_y_t* const src1 = tmp_buffer + 0 * w;
+ fixed_y_t* const src2 = tmp_buffer + 3 * w;
+ {
+ const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0);
+ InterpolateTwoRows(best_y, prev_uv, cur_uv, next_uv, w,
+ src1, src2, rgb_bit_depth);
+ prev_uv = cur_uv;
+ cur_uv = next_uv;
+ }
+
+ UpdateW(src1, best_rgb_y + 0 * w, w, rgb_bit_depth);
+ UpdateW(src2, best_rgb_y + 1 * w, w, rgb_bit_depth);
+ UpdateChroma(src1, src2, best_rgb_uv, uv_w, rgb_bit_depth);
+
+ // update two rows of Y and one row of RGB
+ diff_y_sum +=
+ SharpYuvUpdateY(target_y, best_rgb_y, best_y, 2 * w,
+ rgb_bit_depth + GetPrecisionShift(rgb_bit_depth));
+ SharpYuvUpdateRGB(target_uv, best_rgb_uv, best_uv, 3 * uv_w);
+
+ best_y += 2 * w;
+ best_uv += 3 * uv_w;
+ target_y += 2 * w;
+ target_uv += 3 * uv_w;
+ }
+ // test exit condition
+ if (iter > 0) {
+ if (diff_y_sum < diff_y_threshold) break;
+ if (diff_y_sum > prev_diff_y_sum) break;
+ }
+ prev_diff_y_sum = diff_y_sum;
+ }
+
+ // final reconstruction
+ ok = ConvertWRGBToYUV(best_y_base, best_uv_base, y_ptr, y_stride, u_ptr,
+ u_stride, v_ptr, v_stride, rgb_bit_depth, yuv_bit_depth,
+ width, height, yuv_matrix);
+
+ End:
+ free(best_y_base);
+ free(best_uv_base);
+ free(target_y_base);
+ free(target_uv_base);
+ free(best_rgb_y);
+ free(best_rgb_uv);
+ free(tmp_buffer);
+ return ok;
+}
+#undef SAFE_ALLOC
+
+// Hidden exported init function.
+// By default SharpYuvConvert calls it with NULL. If needed, users can declare
+// it as extern and call it with a VP8CPUInfo function.
+extern void SharpYuvInit(VP8CPUInfo cpu_info_func);
+void SharpYuvInit(VP8CPUInfo cpu_info_func) {
+ static volatile VP8CPUInfo sharpyuv_last_cpuinfo_used =
+ (VP8CPUInfo)&sharpyuv_last_cpuinfo_used;
+ const int initialized =
+ (sharpyuv_last_cpuinfo_used != (VP8CPUInfo)&sharpyuv_last_cpuinfo_used);
+ if (cpu_info_func == NULL && initialized) return;
+ if (sharpyuv_last_cpuinfo_used == cpu_info_func) return;
+
+ SharpYuvInitDsp(cpu_info_func);
+ if (!initialized) {
+ SharpYuvInitGammaTables();
+ }
+
+ sharpyuv_last_cpuinfo_used = cpu_info_func;
+}
+
+int SharpYuvConvert(const void* r_ptr, const void* g_ptr,
+ const void* b_ptr, int rgb_step, int rgb_stride,
+ int rgb_bit_depth, void* y_ptr, int y_stride,
+ void* u_ptr, int u_stride, void* v_ptr,
+ int v_stride, int yuv_bit_depth, int width,
+ int height, const SharpYuvConversionMatrix* yuv_matrix) {
+ SharpYuvConversionMatrix scaled_matrix;
+ const int rgb_max = (1 << rgb_bit_depth) - 1;
+ const int rgb_round = 1 << (rgb_bit_depth - 1);
+ const int yuv_max = (1 << yuv_bit_depth) - 1;
+ const int sfix = GetPrecisionShift(rgb_bit_depth);
+
+ if (width < 1 || height < 1 || width == INT_MAX || height == INT_MAX ||
+ r_ptr == NULL || g_ptr == NULL || b_ptr == NULL || y_ptr == NULL ||
+ u_ptr == NULL || v_ptr == NULL) {
+ return 0;
+ }
+ if (rgb_bit_depth != 8 && rgb_bit_depth != 10 && rgb_bit_depth != 12 &&
+ rgb_bit_depth != 16) {
+ return 0;
+ }
+ if (yuv_bit_depth != 8 && yuv_bit_depth != 10 && yuv_bit_depth != 12) {
+ return 0;
+ }
+ if (rgb_bit_depth > 8 && (rgb_step % 2 != 0 || rgb_stride %2 != 0)) {
+ // Step/stride should be even for uint16_t buffers.
+ return 0;
+ }
+ if (yuv_bit_depth > 8 &&
+ (y_stride % 2 != 0 || u_stride % 2 != 0 || v_stride % 2 != 0)) {
+ // Stride should be even for uint16_t buffers.
+ return 0;
+ }
+ SharpYuvInit(NULL);
+
+ // Add scaling factor to go from rgb_bit_depth to yuv_bit_depth, to the
+ // rgb->yuv conversion matrix.
+ if (rgb_bit_depth == yuv_bit_depth) {
+ memcpy(&scaled_matrix, yuv_matrix, sizeof(scaled_matrix));
+ } else {
+ int i;
+ for (i = 0; i < 3; ++i) {
+ scaled_matrix.rgb_to_y[i] =
+ (yuv_matrix->rgb_to_y[i] * yuv_max + rgb_round) / rgb_max;
+ scaled_matrix.rgb_to_u[i] =
+ (yuv_matrix->rgb_to_u[i] * yuv_max + rgb_round) / rgb_max;
+ scaled_matrix.rgb_to_v[i] =
+ (yuv_matrix->rgb_to_v[i] * yuv_max + rgb_round) / rgb_max;
+ }
+ }
+ // Also incorporate precision change scaling.
+ scaled_matrix.rgb_to_y[3] = Shift(yuv_matrix->rgb_to_y[3], sfix);
+ scaled_matrix.rgb_to_u[3] = Shift(yuv_matrix->rgb_to_u[3], sfix);
+ scaled_matrix.rgb_to_v[3] = Shift(yuv_matrix->rgb_to_v[3], sfix);
+
+ return DoSharpArgbToYuv(r_ptr, g_ptr, b_ptr, rgb_step, rgb_stride,
+ rgb_bit_depth, y_ptr, y_stride, u_ptr, u_stride,
+ v_ptr, v_stride, yuv_bit_depth, width, height,
+ &scaled_matrix);
+}
+
+//------------------------------------------------------------------------------
diff --git a/thirdparty/libwebp/sharpyuv/sharpyuv.h b/thirdparty/libwebp/sharpyuv/sharpyuv.h
new file mode 100644
index 0000000000..9386ea2185
--- /dev/null
+++ b/thirdparty/libwebp/sharpyuv/sharpyuv.h
@@ -0,0 +1,81 @@
+// Copyright 2022 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Sharp RGB to YUV conversion.
+
+#ifndef WEBP_SHARPYUV_SHARPYUV_H_
+#define WEBP_SHARPYUV_SHARPYUV_H_
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// SharpYUV API version following the convention from semver.org
+#define SHARPYUV_VERSION_MAJOR 0
+#define SHARPYUV_VERSION_MINOR 1
+#define SHARPYUV_VERSION_PATCH 0
+// Version as a uint32_t. The major number is the high 8 bits.
+// The minor number is the middle 8 bits. The patch number is the low 16 bits.
+#define SHARPYUV_MAKE_VERSION(MAJOR, MINOR, PATCH) \
+ (((MAJOR) << 24) | ((MINOR) << 16) | (PATCH))
+#define SHARPYUV_VERSION \
+ SHARPYUV_MAKE_VERSION(SHARPYUV_VERSION_MAJOR, SHARPYUV_VERSION_MINOR, \
+ SHARPYUV_VERSION_PATCH)
+
+// RGB to YUV conversion matrix, in 16 bit fixed point.
+// y = rgb_to_y[0] * r + rgb_to_y[1] * g + rgb_to_y[2] * b + rgb_to_y[3]
+// u = rgb_to_u[0] * r + rgb_to_u[1] * g + rgb_to_u[2] * b + rgb_to_u[3]
+// v = rgb_to_v[0] * r + rgb_to_v[1] * g + rgb_to_v[2] * b + rgb_to_v[3]
+// Then y, u and v values are divided by 1<<16 and rounded.
+typedef struct {
+ int rgb_to_y[4];
+ int rgb_to_u[4];
+ int rgb_to_v[4];
+} SharpYuvConversionMatrix;
+
+// Converts RGB to YUV420 using a downsampling algorithm that minimizes
+// artefacts caused by chroma subsampling.
+// This is slower than standard downsampling (averaging of 4 UV values).
+// Assumes that the image will be upsampled using a bilinear filter. If nearest
+// neighbor is used instead, the upsampled image might look worse than with
+// standard downsampling.
+// r_ptr, g_ptr, b_ptr: pointers to the source r, g and b channels. Should point
+// to uint8_t buffers if rgb_bit_depth is 8, or uint16_t buffers otherwise.
+// rgb_step: distance in bytes between two horizontally adjacent pixels on the
+// r, g and b channels. If rgb_bit_depth is > 8, it should be a
+// multiple of 2.
+// rgb_stride: distance in bytes between two vertically adjacent pixels on the
+// r, g, and b channels. If rgb_bit_depth is > 8, it should be a
+// multiple of 2.
+// rgb_bit_depth: number of bits for each r/g/b value. One of: 8, 10, 12, 16.
+// Note: 16 bit input is truncated to 14 bits before conversion to yuv.
+// yuv_bit_depth: number of bits for each y/u/v value. One of: 8, 10, 12.
+// y_ptr, u_ptr, v_ptr: pointers to the destination y, u and v channels. Should
+// point to uint8_t buffers if yuv_bit_depth is 8, or uint16_t buffers
+// otherwise.
+// y_stride, u_stride, v_stride: distance in bytes between two vertically
+// adjacent pixels on the y, u and v channels. If yuv_bit_depth > 8, they
+// should be multiples of 2.
+// width, height: width and height of the image in pixels
+int SharpYuvConvert(const void* r_ptr, const void* g_ptr, const void* b_ptr,
+ int rgb_step, int rgb_stride, int rgb_bit_depth,
+ void* y_ptr, int y_stride, void* u_ptr, int u_stride,
+ void* v_ptr, int v_stride, int yuv_bit_depth, int width,
+ int height, const SharpYuvConversionMatrix* yuv_matrix);
+
+// TODO(b/194336375): Add YUV444 to YUV420 conversion. Maybe also add 422
+// support (it's rarely used in practice, especially for images).
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBP_SHARPYUV_SHARPYUV_H_
diff --git a/thirdparty/libwebp/sharpyuv/sharpyuv_csp.c b/thirdparty/libwebp/sharpyuv/sharpyuv_csp.c
new file mode 100644
index 0000000000..5334fa64fa
--- /dev/null
+++ b/thirdparty/libwebp/sharpyuv/sharpyuv_csp.c
@@ -0,0 +1,110 @@
+// Copyright 2022 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Colorspace utilities.
+
+#include "sharpyuv/sharpyuv_csp.h"
+
+#include <assert.h>
+#include <math.h>
+#include <string.h>
+
+static int ToFixed16(float f) { return (int)floor(f * (1 << 16) + 0.5f); }
+
+void SharpYuvComputeConversionMatrix(const SharpYuvColorSpace* yuv_color_space,
+ SharpYuvConversionMatrix* matrix) {
+ const float kr = yuv_color_space->kr;
+ const float kb = yuv_color_space->kb;
+ const float kg = 1.0f - kr - kb;
+ const float cr = 0.5f / (1.0f - kb);
+ const float cb = 0.5f / (1.0f - kr);
+
+ const int shift = yuv_color_space->bit_depth - 8;
+
+ const float denom = (float)((1 << yuv_color_space->bit_depth) - 1);
+ float scale_y = 1.0f;
+ float add_y = 0.0f;
+ float scale_u = cr;
+ float scale_v = cb;
+ float add_uv = (float)(128 << shift);
+ assert(yuv_color_space->bit_depth >= 8);
+
+ if (yuv_color_space->range == kSharpYuvRangeLimited) {
+ scale_y *= (219 << shift) / denom;
+ scale_u *= (224 << shift) / denom;
+ scale_v *= (224 << shift) / denom;
+ add_y = (float)(16 << shift);
+ }
+
+ matrix->rgb_to_y[0] = ToFixed16(kr * scale_y);
+ matrix->rgb_to_y[1] = ToFixed16(kg * scale_y);
+ matrix->rgb_to_y[2] = ToFixed16(kb * scale_y);
+ matrix->rgb_to_y[3] = ToFixed16(add_y);
+
+ matrix->rgb_to_u[0] = ToFixed16(-kr * scale_u);
+ matrix->rgb_to_u[1] = ToFixed16(-kg * scale_u);
+ matrix->rgb_to_u[2] = ToFixed16((1 - kb) * scale_u);
+ matrix->rgb_to_u[3] = ToFixed16(add_uv);
+
+ matrix->rgb_to_v[0] = ToFixed16((1 - kr) * scale_v);
+ matrix->rgb_to_v[1] = ToFixed16(-kg * scale_v);
+ matrix->rgb_to_v[2] = ToFixed16(-kb * scale_v);
+ matrix->rgb_to_v[3] = ToFixed16(add_uv);
+}
+
+// Matrices are in YUV_FIX fixed point precision.
+// WebP's matrix, similar but not identical to kRec601LimitedMatrix.
+static const SharpYuvConversionMatrix kWebpMatrix = {
+ {16839, 33059, 6420, 16 << 16},
+ {-9719, -19081, 28800, 128 << 16},
+ {28800, -24116, -4684, 128 << 16},
+};
+// Kr=0.2990f Kb=0.1140f bits=8 range=kSharpYuvRangeLimited
+static const SharpYuvConversionMatrix kRec601LimitedMatrix = {
+ {16829, 33039, 6416, 16 << 16},
+ {-9714, -19071, 28784, 128 << 16},
+ {28784, -24103, -4681, 128 << 16},
+};
+// Kr=0.2990f Kb=0.1140f bits=8 range=kSharpYuvRangeFull
+static const SharpYuvConversionMatrix kRec601FullMatrix = {
+ {19595, 38470, 7471, 0},
+ {-11058, -21710, 32768, 128 << 16},
+ {32768, -27439, -5329, 128 << 16},
+};
+// Kr=0.2126f Kb=0.0722f bits=8 range=kSharpYuvRangeLimited
+static const SharpYuvConversionMatrix kRec709LimitedMatrix = {
+ {11966, 40254, 4064, 16 << 16},
+ {-6596, -22189, 28784, 128 << 16},
+ {28784, -26145, -2639, 128 << 16},
+};
+// Kr=0.2126f Kb=0.0722f bits=8 range=kSharpYuvRangeFull
+static const SharpYuvConversionMatrix kRec709FullMatrix = {
+ {13933, 46871, 4732, 0},
+ {-7509, -25259, 32768, 128 << 16},
+ {32768, -29763, -3005, 128 << 16},
+};
+
+const SharpYuvConversionMatrix* SharpYuvGetConversionMatrix(
+ SharpYuvMatrixType matrix_type) {
+ switch (matrix_type) {
+ case kSharpYuvMatrixWebp:
+ return &kWebpMatrix;
+ case kSharpYuvMatrixRec601Limited:
+ return &kRec601LimitedMatrix;
+ case kSharpYuvMatrixRec601Full:
+ return &kRec601FullMatrix;
+ case kSharpYuvMatrixRec709Limited:
+ return &kRec709LimitedMatrix;
+ case kSharpYuvMatrixRec709Full:
+ return &kRec709FullMatrix;
+ case kSharpYuvMatrixNum:
+ return NULL;
+ }
+ return NULL;
+}
diff --git a/thirdparty/libwebp/sharpyuv/sharpyuv_csp.h b/thirdparty/libwebp/sharpyuv/sharpyuv_csp.h
new file mode 100644
index 0000000000..63c99ef5cd
--- /dev/null
+++ b/thirdparty/libwebp/sharpyuv/sharpyuv_csp.h
@@ -0,0 +1,59 @@
+// Copyright 2022 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Colorspace utilities.
+
+#ifndef WEBP_SHARPYUV_SHARPYUV_CSP_H_
+#define WEBP_SHARPYUV_SHARPYUV_CSP_H_
+
+#include "sharpyuv/sharpyuv.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Range of YUV values.
+typedef enum {
+ kSharpYuvRangeFull, // YUV values between [0;255] (for 8 bit)
+ kSharpYuvRangeLimited // Y in [16;235], YUV in [16;240] (for 8 bit)
+} SharpYuvRange;
+
+// Constants that define a YUV color space.
+typedef struct {
+ // Kr and Kb are defined such that:
+ // Y = Kr * r + Kg * g + Kb * b where Kg = 1 - Kr - Kb.
+ float kr;
+ float kb;
+ int bit_depth; // 8, 10 or 12
+ SharpYuvRange range;
+} SharpYuvColorSpace;
+
+// Fills in 'matrix' for the given YUVColorSpace.
+void SharpYuvComputeConversionMatrix(const SharpYuvColorSpace* yuv_color_space,
+ SharpYuvConversionMatrix* matrix);
+
+// Enums for precomputed conversion matrices.
+typedef enum {
+ kSharpYuvMatrixWebp = 0,
+ kSharpYuvMatrixRec601Limited,
+ kSharpYuvMatrixRec601Full,
+ kSharpYuvMatrixRec709Limited,
+ kSharpYuvMatrixRec709Full,
+ kSharpYuvMatrixNum
+} SharpYuvMatrixType;
+
+// Returns a pointer to a matrix for one of the predefined colorspaces.
+const SharpYuvConversionMatrix* SharpYuvGetConversionMatrix(
+ SharpYuvMatrixType matrix_type);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBP_SHARPYUV_SHARPYUV_CSP_H_
diff --git a/thirdparty/libwebp/sharpyuv/sharpyuv_dsp.c b/thirdparty/libwebp/sharpyuv/sharpyuv_dsp.c
new file mode 100644
index 0000000000..956fa7ce55
--- /dev/null
+++ b/thirdparty/libwebp/sharpyuv/sharpyuv_dsp.c
@@ -0,0 +1,102 @@
+// Copyright 2022 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Speed-critical functions for Sharp YUV.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "sharpyuv/sharpyuv_dsp.h"
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "src/dsp/cpu.h"
+
+//-----------------------------------------------------------------------------
+
+#if !WEBP_NEON_OMIT_C_CODE
+static uint16_t clip(int v, int max) {
+ return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v;
+}
+
+static uint64_t SharpYuvUpdateY_C(const uint16_t* ref, const uint16_t* src,
+ uint16_t* dst, int len, int bit_depth) {
+ uint64_t diff = 0;
+ int i;
+ const int max_y = (1 << bit_depth) - 1;
+ for (i = 0; i < len; ++i) {
+ const int diff_y = ref[i] - src[i];
+ const int new_y = (int)dst[i] + diff_y;
+ dst[i] = clip(new_y, max_y);
+ diff += (uint64_t)abs(diff_y);
+ }
+ return diff;
+}
+
+static void SharpYuvUpdateRGB_C(const int16_t* ref, const int16_t* src,
+ int16_t* dst, int len) {
+ int i;
+ for (i = 0; i < len; ++i) {
+ const int diff_uv = ref[i] - src[i];
+ dst[i] += diff_uv;
+ }
+}
+
+static void SharpYuvFilterRow_C(const int16_t* A, const int16_t* B, int len,
+ const uint16_t* best_y, uint16_t* out,
+ int bit_depth) {
+ int i;
+ const int max_y = (1 << bit_depth) - 1;
+ for (i = 0; i < len; ++i, ++A, ++B) {
+ const int v0 = (A[0] * 9 + A[1] * 3 + B[0] * 3 + B[1] + 8) >> 4;
+ const int v1 = (A[1] * 9 + A[0] * 3 + B[1] * 3 + B[0] + 8) >> 4;
+ out[2 * i + 0] = clip(best_y[2 * i + 0] + v0, max_y);
+ out[2 * i + 1] = clip(best_y[2 * i + 1] + v1, max_y);
+ }
+}
+#endif // !WEBP_NEON_OMIT_C_CODE
+
+//-----------------------------------------------------------------------------
+
+uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref,
+ uint16_t* dst, int len, int bit_depth);
+void (*SharpYuvUpdateRGB)(const int16_t* src, const int16_t* ref, int16_t* dst,
+ int len);
+void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len,
+ const uint16_t* best_y, uint16_t* out,
+ int bit_depth);
+
+extern void InitSharpYuvSSE2(void);
+extern void InitSharpYuvNEON(void);
+
+void SharpYuvInitDsp(VP8CPUInfo cpu_info_func) {
+ (void)cpu_info_func;
+
+#if !WEBP_NEON_OMIT_C_CODE
+ SharpYuvUpdateY = SharpYuvUpdateY_C;
+ SharpYuvUpdateRGB = SharpYuvUpdateRGB_C;
+ SharpYuvFilterRow = SharpYuvFilterRow_C;
+#endif
+
+#if defined(WEBP_HAVE_SSE2)
+ if (cpu_info_func == NULL || cpu_info_func(kSSE2)) {
+ InitSharpYuvSSE2();
+ }
+#endif // WEBP_HAVE_SSE2
+
+#if defined(WEBP_HAVE_NEON)
+ if (WEBP_NEON_OMIT_C_CODE || cpu_info_func == NULL || cpu_info_func(kNEON)) {
+ InitSharpYuvNEON();
+ }
+#endif // WEBP_HAVE_NEON
+
+ assert(SharpYuvUpdateY != NULL);
+ assert(SharpYuvUpdateRGB != NULL);
+ assert(SharpYuvFilterRow != NULL);
+}
diff --git a/thirdparty/libwebp/sharpyuv/sharpyuv_dsp.h b/thirdparty/libwebp/sharpyuv/sharpyuv_dsp.h
new file mode 100644
index 0000000000..e561d8d3d0
--- /dev/null
+++ b/thirdparty/libwebp/sharpyuv/sharpyuv_dsp.h
@@ -0,0 +1,29 @@
+// Copyright 2022 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Speed-critical functions for Sharp YUV.
+
+#ifndef WEBP_SHARPYUV_SHARPYUV_DSP_H_
+#define WEBP_SHARPYUV_SHARPYUV_DSP_H_
+
+#include <stdint.h>
+
+#include "src/dsp/cpu.h"
+
+extern uint64_t (*SharpYuvUpdateY)(const uint16_t* src, const uint16_t* ref,
+ uint16_t* dst, int len, int bit_depth);
+extern void (*SharpYuvUpdateRGB)(const int16_t* src, const int16_t* ref,
+ int16_t* dst, int len);
+extern void (*SharpYuvFilterRow)(const int16_t* A, const int16_t* B, int len,
+ const uint16_t* best_y, uint16_t* out,
+ int bit_depth);
+
+void SharpYuvInitDsp(VP8CPUInfo cpu_info_func);
+
+#endif // WEBP_SHARPYUV_SHARPYUV_DSP_H_
diff --git a/thirdparty/libwebp/sharpyuv/sharpyuv_gamma.c b/thirdparty/libwebp/sharpyuv/sharpyuv_gamma.c
new file mode 100644
index 0000000000..05b5436f83
--- /dev/null
+++ b/thirdparty/libwebp/sharpyuv/sharpyuv_gamma.c
@@ -0,0 +1,114 @@
+// Copyright 2022 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Gamma correction utilities.
+
+#include "sharpyuv/sharpyuv_gamma.h"
+
+#include <assert.h>
+#include <math.h>
+#include <stdint.h>
+
+#include "src/webp/types.h"
+
+// Gamma correction compensates loss of resolution during chroma subsampling.
+// Size of pre-computed table for converting from gamma to linear.
+#define GAMMA_TO_LINEAR_TAB_BITS 10
+#define GAMMA_TO_LINEAR_TAB_SIZE (1 << GAMMA_TO_LINEAR_TAB_BITS)
+static uint32_t kGammaToLinearTabS[GAMMA_TO_LINEAR_TAB_SIZE + 2];
+#define LINEAR_TO_GAMMA_TAB_BITS 9
+#define LINEAR_TO_GAMMA_TAB_SIZE (1 << LINEAR_TO_GAMMA_TAB_BITS)
+static uint32_t kLinearToGammaTabS[LINEAR_TO_GAMMA_TAB_SIZE + 2];
+
+static const double kGammaF = 1. / 0.45;
+#define GAMMA_TO_LINEAR_BITS 16
+
+static volatile int kGammaTablesSOk = 0;
+void SharpYuvInitGammaTables(void) {
+ assert(GAMMA_TO_LINEAR_BITS <= 16);
+ if (!kGammaTablesSOk) {
+ int v;
+ const double a = 0.09929682680944;
+ const double thresh = 0.018053968510807;
+ const double final_scale = 1 << GAMMA_TO_LINEAR_BITS;
+ // Precompute gamma to linear table.
+ {
+ const double norm = 1. / GAMMA_TO_LINEAR_TAB_SIZE;
+ const double a_rec = 1. / (1. + a);
+ for (v = 0; v <= GAMMA_TO_LINEAR_TAB_SIZE; ++v) {
+ const double g = norm * v;
+ double value;
+ if (g <= thresh * 4.5) {
+ value = g / 4.5;
+ } else {
+ value = pow(a_rec * (g + a), kGammaF);
+ }
+ kGammaToLinearTabS[v] = (uint32_t)(value * final_scale + .5);
+ }
+ // to prevent small rounding errors to cause read-overflow:
+ kGammaToLinearTabS[GAMMA_TO_LINEAR_TAB_SIZE + 1] =
+ kGammaToLinearTabS[GAMMA_TO_LINEAR_TAB_SIZE];
+ }
+ // Precompute linear to gamma table.
+ {
+ const double scale = 1. / LINEAR_TO_GAMMA_TAB_SIZE;
+ for (v = 0; v <= LINEAR_TO_GAMMA_TAB_SIZE; ++v) {
+ const double g = scale * v;
+ double value;
+ if (g <= thresh) {
+ value = 4.5 * g;
+ } else {
+ value = (1. + a) * pow(g, 1. / kGammaF) - a;
+ }
+ kLinearToGammaTabS[v] =
+ (uint32_t)(final_scale * value + 0.5);
+ }
+ // to prevent small rounding errors to cause read-overflow:
+ kLinearToGammaTabS[LINEAR_TO_GAMMA_TAB_SIZE + 1] =
+ kLinearToGammaTabS[LINEAR_TO_GAMMA_TAB_SIZE];
+ }
+ kGammaTablesSOk = 1;
+ }
+}
+
+static WEBP_INLINE int Shift(int v, int shift) {
+ return (shift >= 0) ? (v << shift) : (v >> -shift);
+}
+
+static WEBP_INLINE uint32_t FixedPointInterpolation(int v, uint32_t* tab,
+ int tab_pos_shift_right,
+ int tab_value_shift) {
+ const uint32_t tab_pos = Shift(v, -tab_pos_shift_right);
+ // fractional part, in 'tab_pos_shift' fixed-point precision
+ const uint32_t x = v - (tab_pos << tab_pos_shift_right); // fractional part
+ // v0 / v1 are in kGammaToLinearBits fixed-point precision (range [0..1])
+ const uint32_t v0 = Shift(tab[tab_pos + 0], tab_value_shift);
+ const uint32_t v1 = Shift(tab[tab_pos + 1], tab_value_shift);
+ // Final interpolation.
+ const uint32_t v2 = (v1 - v0) * x; // note: v1 >= v0.
+ const int half =
+ (tab_pos_shift_right > 0) ? 1 << (tab_pos_shift_right - 1) : 0;
+ const uint32_t result = v0 + ((v2 + half) >> tab_pos_shift_right);
+ return result;
+}
+
+uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth) {
+ const int shift = GAMMA_TO_LINEAR_TAB_BITS - bit_depth;
+ if (shift > 0) {
+ return kGammaToLinearTabS[v << shift];
+ }
+ return FixedPointInterpolation(v, kGammaToLinearTabS, -shift, 0);
+}
+
+uint16_t SharpYuvLinearToGamma(uint32_t value, int bit_depth) {
+ return FixedPointInterpolation(
+ value, kLinearToGammaTabS,
+ (GAMMA_TO_LINEAR_BITS - LINEAR_TO_GAMMA_TAB_BITS),
+ bit_depth - GAMMA_TO_LINEAR_BITS);
+}
diff --git a/thirdparty/libwebp/sharpyuv/sharpyuv_gamma.h b/thirdparty/libwebp/sharpyuv/sharpyuv_gamma.h
new file mode 100644
index 0000000000..2f1a3ff4a0
--- /dev/null
+++ b/thirdparty/libwebp/sharpyuv/sharpyuv_gamma.h
@@ -0,0 +1,35 @@
+// Copyright 2022 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Gamma correction utilities.
+
+#ifndef WEBP_SHARPYUV_SHARPYUV_GAMMA_H_
+#define WEBP_SHARPYUV_SHARPYUV_GAMMA_H_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Initializes precomputed tables. Must be called once before calling
+// SharpYuvGammaToLinear or SharpYuvLinearToGamma.
+void SharpYuvInitGammaTables(void);
+
+// Converts a gamma color value on 'bit_depth' bits to a 16 bit linear value.
+uint32_t SharpYuvGammaToLinear(uint16_t v, int bit_depth);
+
+// Converts a 16 bit linear color value to a gamma value on 'bit_depth' bits.
+uint16_t SharpYuvLinearToGamma(uint32_t value, int bit_depth);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBP_SHARPYUV_SHARPYUV_GAMMA_H_
diff --git a/thirdparty/libwebp/sharpyuv/sharpyuv_neon.c b/thirdparty/libwebp/sharpyuv/sharpyuv_neon.c
new file mode 100644
index 0000000000..5cf6aaffb0
--- /dev/null
+++ b/thirdparty/libwebp/sharpyuv/sharpyuv_neon.c
@@ -0,0 +1,182 @@
+// Copyright 2022 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Speed-critical functions for Sharp YUV.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "sharpyuv/sharpyuv_dsp.h"
+
+#if defined(WEBP_USE_NEON)
+#include <assert.h>
+#include <stdlib.h>
+#include <arm_neon.h>
+#endif
+
+extern void InitSharpYuvNEON(void);
+
+#if defined(WEBP_USE_NEON)
+
+static uint16_t clip_NEON(int v, int max) {
+ return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v;
+}
+
+static uint64_t SharpYuvUpdateY_NEON(const uint16_t* ref, const uint16_t* src,
+ uint16_t* dst, int len, int bit_depth) {
+ const int max_y = (1 << bit_depth) - 1;
+ int i;
+ const int16x8_t zero = vdupq_n_s16(0);
+ const int16x8_t max = vdupq_n_s16(max_y);
+ uint64x2_t sum = vdupq_n_u64(0);
+ uint64_t diff;
+
+ for (i = 0; i + 8 <= len; i += 8) {
+ const int16x8_t A = vreinterpretq_s16_u16(vld1q_u16(ref + i));
+ const int16x8_t B = vreinterpretq_s16_u16(vld1q_u16(src + i));
+ const int16x8_t C = vreinterpretq_s16_u16(vld1q_u16(dst + i));
+ const int16x8_t D = vsubq_s16(A, B); // diff_y
+ const int16x8_t F = vaddq_s16(C, D); // new_y
+ const uint16x8_t H =
+ vreinterpretq_u16_s16(vmaxq_s16(vminq_s16(F, max), zero));
+ const int16x8_t I = vabsq_s16(D); // abs(diff_y)
+ vst1q_u16(dst + i, H);
+ sum = vpadalq_u32(sum, vpaddlq_u16(vreinterpretq_u16_s16(I)));
+ }
+ diff = vgetq_lane_u64(sum, 0) + vgetq_lane_u64(sum, 1);
+ for (; i < len; ++i) {
+ const int diff_y = ref[i] - src[i];
+ const int new_y = (int)(dst[i]) + diff_y;
+ dst[i] = clip_NEON(new_y, max_y);
+ diff += (uint64_t)(abs(diff_y));
+ }
+ return diff;
+}
+
+static void SharpYuvUpdateRGB_NEON(const int16_t* ref, const int16_t* src,
+ int16_t* dst, int len) {
+ int i;
+ for (i = 0; i + 8 <= len; i += 8) {
+ const int16x8_t A = vld1q_s16(ref + i);
+ const int16x8_t B = vld1q_s16(src + i);
+ const int16x8_t C = vld1q_s16(dst + i);
+ const int16x8_t D = vsubq_s16(A, B); // diff_uv
+ const int16x8_t E = vaddq_s16(C, D); // new_uv
+ vst1q_s16(dst + i, E);
+ }
+ for (; i < len; ++i) {
+ const int diff_uv = ref[i] - src[i];
+ dst[i] += diff_uv;
+ }
+}
+
+static void SharpYuvFilterRow16_NEON(const int16_t* A, const int16_t* B,
+ int len, const uint16_t* best_y,
+ uint16_t* out, int bit_depth) {
+ const int max_y = (1 << bit_depth) - 1;
+ int i;
+ const int16x8_t max = vdupq_n_s16(max_y);
+ const int16x8_t zero = vdupq_n_s16(0);
+ for (i = 0; i + 8 <= len; i += 8) {
+ const int16x8_t a0 = vld1q_s16(A + i + 0);
+ const int16x8_t a1 = vld1q_s16(A + i + 1);
+ const int16x8_t b0 = vld1q_s16(B + i + 0);
+ const int16x8_t b1 = vld1q_s16(B + i + 1);
+ const int16x8_t a0b1 = vaddq_s16(a0, b1);
+ const int16x8_t a1b0 = vaddq_s16(a1, b0);
+ const int16x8_t a0a1b0b1 = vaddq_s16(a0b1, a1b0); // A0+A1+B0+B1
+ const int16x8_t a0b1_2 = vaddq_s16(a0b1, a0b1); // 2*(A0+B1)
+ const int16x8_t a1b0_2 = vaddq_s16(a1b0, a1b0); // 2*(A1+B0)
+ const int16x8_t c0 = vshrq_n_s16(vaddq_s16(a0b1_2, a0a1b0b1), 3);
+ const int16x8_t c1 = vshrq_n_s16(vaddq_s16(a1b0_2, a0a1b0b1), 3);
+ const int16x8_t e0 = vrhaddq_s16(c1, a0);
+ const int16x8_t e1 = vrhaddq_s16(c0, a1);
+ const int16x8x2_t f = vzipq_s16(e0, e1);
+ const int16x8_t g0 = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i + 0));
+ const int16x8_t g1 = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i + 8));
+ const int16x8_t h0 = vaddq_s16(g0, f.val[0]);
+ const int16x8_t h1 = vaddq_s16(g1, f.val[1]);
+ const int16x8_t i0 = vmaxq_s16(vminq_s16(h0, max), zero);
+ const int16x8_t i1 = vmaxq_s16(vminq_s16(h1, max), zero);
+ vst1q_u16(out + 2 * i + 0, vreinterpretq_u16_s16(i0));
+ vst1q_u16(out + 2 * i + 8, vreinterpretq_u16_s16(i1));
+ }
+ for (; i < len; ++i) {
+ const int a0b1 = A[i + 0] + B[i + 1];
+ const int a1b0 = A[i + 1] + B[i + 0];
+ const int a0a1b0b1 = a0b1 + a1b0 + 8;
+ const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4;
+ const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4;
+ out[2 * i + 0] = clip_NEON(best_y[2 * i + 0] + v0, max_y);
+ out[2 * i + 1] = clip_NEON(best_y[2 * i + 1] + v1, max_y);
+ }
+}
+
+static void SharpYuvFilterRow32_NEON(const int16_t* A, const int16_t* B,
+ int len, const uint16_t* best_y,
+ uint16_t* out, int bit_depth) {
+ const int max_y = (1 << bit_depth) - 1;
+ int i;
+ const uint16x8_t max = vdupq_n_u16(max_y);
+ for (i = 0; i + 4 <= len; i += 4) {
+ const int16x4_t a0 = vld1_s16(A + i + 0);
+ const int16x4_t a1 = vld1_s16(A + i + 1);
+ const int16x4_t b0 = vld1_s16(B + i + 0);
+ const int16x4_t b1 = vld1_s16(B + i + 1);
+ const int32x4_t a0b1 = vaddl_s16(a0, b1);
+ const int32x4_t a1b0 = vaddl_s16(a1, b0);
+ const int32x4_t a0a1b0b1 = vaddq_s32(a0b1, a1b0); // A0+A1+B0+B1
+ const int32x4_t a0b1_2 = vaddq_s32(a0b1, a0b1); // 2*(A0+B1)
+ const int32x4_t a1b0_2 = vaddq_s32(a1b0, a1b0); // 2*(A1+B0)
+ const int32x4_t c0 = vshrq_n_s32(vaddq_s32(a0b1_2, a0a1b0b1), 3);
+ const int32x4_t c1 = vshrq_n_s32(vaddq_s32(a1b0_2, a0a1b0b1), 3);
+ const int32x4_t e0 = vrhaddq_s32(c1, vmovl_s16(a0));
+ const int32x4_t e1 = vrhaddq_s32(c0, vmovl_s16(a1));
+ const int32x4x2_t f = vzipq_s32(e0, e1);
+
+ const int16x8_t g = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i));
+ const int32x4_t h0 = vaddw_s16(f.val[0], vget_low_s16(g));
+ const int32x4_t h1 = vaddw_s16(f.val[1], vget_high_s16(g));
+ const uint16x8_t i_16 = vcombine_u16(vqmovun_s32(h0), vqmovun_s32(h1));
+ const uint16x8_t i_clamped = vminq_u16(i_16, max);
+ vst1q_u16(out + 2 * i + 0, i_clamped);
+ }
+ for (; i < len; ++i) {
+ const int a0b1 = A[i + 0] + B[i + 1];
+ const int a1b0 = A[i + 1] + B[i + 0];
+ const int a0a1b0b1 = a0b1 + a1b0 + 8;
+ const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4;
+ const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4;
+ out[2 * i + 0] = clip_NEON(best_y[2 * i + 0] + v0, max_y);
+ out[2 * i + 1] = clip_NEON(best_y[2 * i + 1] + v1, max_y);
+ }
+}
+
+static void SharpYuvFilterRow_NEON(const int16_t* A, const int16_t* B, int len,
+ const uint16_t* best_y, uint16_t* out,
+ int bit_depth) {
+ if (bit_depth <= 10) {
+ SharpYuvFilterRow16_NEON(A, B, len, best_y, out, bit_depth);
+ } else {
+ SharpYuvFilterRow32_NEON(A, B, len, best_y, out, bit_depth);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+WEBP_TSAN_IGNORE_FUNCTION void InitSharpYuvNEON(void) {
+ SharpYuvUpdateY = SharpYuvUpdateY_NEON;
+ SharpYuvUpdateRGB = SharpYuvUpdateRGB_NEON;
+ SharpYuvFilterRow = SharpYuvFilterRow_NEON;
+}
+
+#else // !WEBP_USE_NEON
+
+void InitSharpYuvNEON(void) {}
+
+#endif // WEBP_USE_NEON
diff --git a/thirdparty/libwebp/sharpyuv/sharpyuv_sse2.c b/thirdparty/libwebp/sharpyuv/sharpyuv_sse2.c
new file mode 100644
index 0000000000..1943873748
--- /dev/null
+++ b/thirdparty/libwebp/sharpyuv/sharpyuv_sse2.c
@@ -0,0 +1,204 @@
+// Copyright 2022 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Speed-critical functions for Sharp YUV.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "sharpyuv/sharpyuv_dsp.h"
+
+#if defined(WEBP_USE_SSE2)
+#include <stdlib.h>
+#include <emmintrin.h>
+#endif
+
+extern void InitSharpYuvSSE2(void);
+
+#if defined(WEBP_USE_SSE2)
+
+static uint16_t clip_SSE2(int v, int max) {
+ return (v < 0) ? 0 : (v > max) ? max : (uint16_t)v;
+}
+
+static uint64_t SharpYuvUpdateY_SSE2(const uint16_t* ref, const uint16_t* src,
+ uint16_t* dst, int len, int bit_depth) {
+ const int max_y = (1 << bit_depth) - 1;
+ uint64_t diff = 0;
+ uint32_t tmp[4];
+ int i;
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i max = _mm_set1_epi16(max_y);
+ const __m128i one = _mm_set1_epi16(1);
+ __m128i sum = zero;
+
+ for (i = 0; i + 8 <= len; i += 8) {
+ const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i));
+ const __m128i B = _mm_loadu_si128((const __m128i*)(src + i));
+ const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i));
+ const __m128i D = _mm_sub_epi16(A, B); // diff_y
+ const __m128i E = _mm_cmpgt_epi16(zero, D); // sign (-1 or 0)
+ const __m128i F = _mm_add_epi16(C, D); // new_y
+ const __m128i G = _mm_or_si128(E, one); // -1 or 1
+ const __m128i H = _mm_max_epi16(_mm_min_epi16(F, max), zero);
+ const __m128i I = _mm_madd_epi16(D, G); // sum(abs(...))
+ _mm_storeu_si128((__m128i*)(dst + i), H);
+ sum = _mm_add_epi32(sum, I);
+ }
+ _mm_storeu_si128((__m128i*)tmp, sum);
+ diff = tmp[3] + tmp[2] + tmp[1] + tmp[0];
+ for (; i < len; ++i) {
+ const int diff_y = ref[i] - src[i];
+ const int new_y = (int)dst[i] + diff_y;
+ dst[i] = clip_SSE2(new_y, max_y);
+ diff += (uint64_t)abs(diff_y);
+ }
+ return diff;
+}
+
+static void SharpYuvUpdateRGB_SSE2(const int16_t* ref, const int16_t* src,
+ int16_t* dst, int len) {
+ int i = 0;
+ for (i = 0; i + 8 <= len; i += 8) {
+ const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i));
+ const __m128i B = _mm_loadu_si128((const __m128i*)(src + i));
+ const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i));
+ const __m128i D = _mm_sub_epi16(A, B); // diff_uv
+ const __m128i E = _mm_add_epi16(C, D); // new_uv
+ _mm_storeu_si128((__m128i*)(dst + i), E);
+ }
+ for (; i < len; ++i) {
+ const int diff_uv = ref[i] - src[i];
+ dst[i] += diff_uv;
+ }
+}
+
+static void SharpYuvFilterRow16_SSE2(const int16_t* A, const int16_t* B,
+ int len, const uint16_t* best_y,
+ uint16_t* out, int bit_depth) {
+ const int max_y = (1 << bit_depth) - 1;
+ int i;
+ const __m128i kCst8 = _mm_set1_epi16(8);
+ const __m128i max = _mm_set1_epi16(max_y);
+ const __m128i zero = _mm_setzero_si128();
+ for (i = 0; i + 8 <= len; i += 8) {
+ const __m128i a0 = _mm_loadu_si128((const __m128i*)(A + i + 0));
+ const __m128i a1 = _mm_loadu_si128((const __m128i*)(A + i + 1));
+ const __m128i b0 = _mm_loadu_si128((const __m128i*)(B + i + 0));
+ const __m128i b1 = _mm_loadu_si128((const __m128i*)(B + i + 1));
+ const __m128i a0b1 = _mm_add_epi16(a0, b1);
+ const __m128i a1b0 = _mm_add_epi16(a1, b0);
+ const __m128i a0a1b0b1 = _mm_add_epi16(a0b1, a1b0); // A0+A1+B0+B1
+ const __m128i a0a1b0b1_8 = _mm_add_epi16(a0a1b0b1, kCst8);
+ const __m128i a0b1_2 = _mm_add_epi16(a0b1, a0b1); // 2*(A0+B1)
+ const __m128i a1b0_2 = _mm_add_epi16(a1b0, a1b0); // 2*(A1+B0)
+ const __m128i c0 = _mm_srai_epi16(_mm_add_epi16(a0b1_2, a0a1b0b1_8), 3);
+ const __m128i c1 = _mm_srai_epi16(_mm_add_epi16(a1b0_2, a0a1b0b1_8), 3);
+ const __m128i d0 = _mm_add_epi16(c1, a0);
+ const __m128i d1 = _mm_add_epi16(c0, a1);
+ const __m128i e0 = _mm_srai_epi16(d0, 1);
+ const __m128i e1 = _mm_srai_epi16(d1, 1);
+ const __m128i f0 = _mm_unpacklo_epi16(e0, e1);
+ const __m128i f1 = _mm_unpackhi_epi16(e0, e1);
+ const __m128i g0 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 0));
+ const __m128i g1 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 8));
+ const __m128i h0 = _mm_add_epi16(g0, f0);
+ const __m128i h1 = _mm_add_epi16(g1, f1);
+ const __m128i i0 = _mm_max_epi16(_mm_min_epi16(h0, max), zero);
+ const __m128i i1 = _mm_max_epi16(_mm_min_epi16(h1, max), zero);
+ _mm_storeu_si128((__m128i*)(out + 2 * i + 0), i0);
+ _mm_storeu_si128((__m128i*)(out + 2 * i + 8), i1);
+ }
+ for (; i < len; ++i) {
+ // (9 * A0 + 3 * A1 + 3 * B0 + B1 + 8) >> 4 =
+ // = (8 * A0 + 2 * (A1 + B0) + (A0 + A1 + B0 + B1 + 8)) >> 4
+ // We reuse the common sub-expressions.
+ const int a0b1 = A[i + 0] + B[i + 1];
+ const int a1b0 = A[i + 1] + B[i + 0];
+ const int a0a1b0b1 = a0b1 + a1b0 + 8;
+ const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4;
+ const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4;
+ out[2 * i + 0] = clip_SSE2(best_y[2 * i + 0] + v0, max_y);
+ out[2 * i + 1] = clip_SSE2(best_y[2 * i + 1] + v1, max_y);
+ }
+}
+
+static WEBP_INLINE __m128i s16_to_s32(__m128i in) {
+ return _mm_srai_epi32(_mm_unpacklo_epi16(in, in), 16);
+}
+
+static void SharpYuvFilterRow32_SSE2(const int16_t* A, const int16_t* B,
+ int len, const uint16_t* best_y,
+ uint16_t* out, int bit_depth) {
+ const int max_y = (1 << bit_depth) - 1;
+ int i;
+ const __m128i kCst8 = _mm_set1_epi32(8);
+ const __m128i max = _mm_set1_epi16(max_y);
+ const __m128i zero = _mm_setzero_si128();
+ for (i = 0; i + 4 <= len; i += 4) {
+ const __m128i a0 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(A + i + 0)));
+ const __m128i a1 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(A + i + 1)));
+ const __m128i b0 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(B + i + 0)));
+ const __m128i b1 = s16_to_s32(_mm_loadl_epi64((const __m128i*)(B + i + 1)));
+ const __m128i a0b1 = _mm_add_epi32(a0, b1);
+ const __m128i a1b0 = _mm_add_epi32(a1, b0);
+ const __m128i a0a1b0b1 = _mm_add_epi32(a0b1, a1b0); // A0+A1+B0+B1
+ const __m128i a0a1b0b1_8 = _mm_add_epi32(a0a1b0b1, kCst8);
+ const __m128i a0b1_2 = _mm_add_epi32(a0b1, a0b1); // 2*(A0+B1)
+ const __m128i a1b0_2 = _mm_add_epi32(a1b0, a1b0); // 2*(A1+B0)
+ const __m128i c0 = _mm_srai_epi32(_mm_add_epi32(a0b1_2, a0a1b0b1_8), 3);
+ const __m128i c1 = _mm_srai_epi32(_mm_add_epi32(a1b0_2, a0a1b0b1_8), 3);
+ const __m128i d0 = _mm_add_epi32(c1, a0);
+ const __m128i d1 = _mm_add_epi32(c0, a1);
+ const __m128i e0 = _mm_srai_epi32(d0, 1);
+ const __m128i e1 = _mm_srai_epi32(d1, 1);
+ const __m128i f0 = _mm_unpacklo_epi32(e0, e1);
+ const __m128i f1 = _mm_unpackhi_epi32(e0, e1);
+ const __m128i g = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 0));
+ const __m128i h_16 = _mm_add_epi16(g, _mm_packs_epi32(f0, f1));
+ const __m128i final = _mm_max_epi16(_mm_min_epi16(h_16, max), zero);
+ _mm_storeu_si128((__m128i*)(out + 2 * i + 0), final);
+ }
+ for (; i < len; ++i) {
+ // (9 * A0 + 3 * A1 + 3 * B0 + B1 + 8) >> 4 =
+ // = (8 * A0 + 2 * (A1 + B0) + (A0 + A1 + B0 + B1 + 8)) >> 4
+ // We reuse the common sub-expressions.
+ const int a0b1 = A[i + 0] + B[i + 1];
+ const int a1b0 = A[i + 1] + B[i + 0];
+ const int a0a1b0b1 = a0b1 + a1b0 + 8;
+ const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4;
+ const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4;
+ out[2 * i + 0] = clip_SSE2(best_y[2 * i + 0] + v0, max_y);
+ out[2 * i + 1] = clip_SSE2(best_y[2 * i + 1] + v1, max_y);
+ }
+}
+
+static void SharpYuvFilterRow_SSE2(const int16_t* A, const int16_t* B, int len,
+ const uint16_t* best_y, uint16_t* out,
+ int bit_depth) {
+ if (bit_depth <= 10) {
+ SharpYuvFilterRow16_SSE2(A, B, len, best_y, out, bit_depth);
+ } else {
+ SharpYuvFilterRow32_SSE2(A, B, len, best_y, out, bit_depth);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+extern void InitSharpYuvSSE2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void InitSharpYuvSSE2(void) {
+ SharpYuvUpdateY = SharpYuvUpdateY_SSE2;
+ SharpYuvUpdateRGB = SharpYuvUpdateRGB_SSE2;
+ SharpYuvFilterRow = SharpYuvFilterRow_SSE2;
+}
+#else // !WEBP_USE_SSE2
+
+void InitSharpYuvSSE2(void) {}
+
+#endif // WEBP_USE_SSE2
diff --git a/thirdparty/libwebp/src/dec/vp8i_dec.h b/thirdparty/libwebp/src/dec/vp8i_dec.h
index 9af22f8cc6..30c1bd3ef9 100644
--- a/thirdparty/libwebp/src/dec/vp8i_dec.h
+++ b/thirdparty/libwebp/src/dec/vp8i_dec.h
@@ -32,7 +32,7 @@ extern "C" {
// version numbers
#define DEC_MAJ_VERSION 1
#define DEC_MIN_VERSION 2
-#define DEC_REV_VERSION 2
+#define DEC_REV_VERSION 4
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
// Constraints are: We need to store one 16x16 block of luma samples (y),
diff --git a/thirdparty/libwebp/src/dec/vp8l_dec.c b/thirdparty/libwebp/src/dec/vp8l_dec.c
index 78db014030..1348055128 100644
--- a/thirdparty/libwebp/src/dec/vp8l_dec.c
+++ b/thirdparty/libwebp/src/dec/vp8l_dec.c
@@ -178,7 +178,7 @@ static WEBP_INLINE int PlaneCodeToDistance(int xsize, int plane_code) {
//------------------------------------------------------------------------------
// Decodes the next Huffman code from bit-stream.
-// FillBitWindow(br) needs to be called at minimum every second call
+// VP8LFillBitWindow(br) needs to be called at minimum every second call
// to ReadSymbol, in order to pre-fetch enough bits.
static WEBP_INLINE int ReadSymbol(const HuffmanCode* table,
VP8LBitReader* const br) {
@@ -321,7 +321,7 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
// The first code is either 1 bit or 8 bit code.
int symbol = VP8LReadBits(br, (first_symbol_len_code == 0) ? 1 : 8);
code_lengths[symbol] = 1;
- // The second code (if present), is always 8 bit long.
+ // The second code (if present), is always 8 bits long.
if (num_symbols == 2) {
symbol = VP8LReadBits(br, 8);
code_lengths[symbol] = 1;
@@ -1281,7 +1281,7 @@ static int ExpandColorMap(int num_colors, VP8LTransform* const transform) {
uint8_t* const new_data = (uint8_t*)new_color_map;
new_color_map[0] = transform->data_[0];
for (i = 4; i < 4 * num_colors; ++i) {
- // Equivalent to AddPixelEq(), on a byte-basis.
+ // Equivalent to VP8LAddPixels(), on a byte-basis.
new_data[i] = (data[i] + new_data[i - 4]) & 0xff;
}
for (; i < 4 * final_num_colors; ++i) {
diff --git a/thirdparty/libwebp/src/demux/demux.c b/thirdparty/libwebp/src/demux/demux.c
index f04a2b8450..41387ec2d6 100644
--- a/thirdparty/libwebp/src/demux/demux.c
+++ b/thirdparty/libwebp/src/demux/demux.c
@@ -25,7 +25,7 @@
#define DMUX_MAJ_VERSION 1
#define DMUX_MIN_VERSION 2
-#define DMUX_REV_VERSION 2
+#define DMUX_REV_VERSION 4
typedef struct {
size_t start_; // start location of the data
@@ -614,7 +614,6 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
while (f != NULL) {
const int cur_frame_set = f->frame_num_;
- int frame_count = 0;
// Check frame properties.
for (; f != NULL && f->frame_num_ == cur_frame_set; f = f->next_) {
@@ -649,8 +648,6 @@ static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
dmux->canvas_width_, dmux->canvas_height_)) {
return 0;
}
-
- ++frame_count;
}
}
return 1;
diff --git a/thirdparty/libwebp/src/dsp/alpha_processing_neon.c b/thirdparty/libwebp/src/dsp/alpha_processing_neon.c
index 9e0ace9421..6716fb77f0 100644
--- a/thirdparty/libwebp/src/dsp/alpha_processing_neon.c
+++ b/thirdparty/libwebp/src/dsp/alpha_processing_neon.c
@@ -83,7 +83,7 @@ static void ApplyAlphaMultiply_NEON(uint8_t* rgba, int alpha_first,
static int DispatchAlpha_NEON(const uint8_t* WEBP_RESTRICT alpha,
int alpha_stride, int width, int height,
uint8_t* WEBP_RESTRICT dst, int dst_stride) {
- uint32_t alpha_mask = 0xffffffffu;
+ uint32_t alpha_mask = 0xffu;
uint8x8_t mask8 = vdup_n_u8(0xff);
uint32_t tmp[2];
int i, j;
@@ -107,6 +107,7 @@ static int DispatchAlpha_NEON(const uint8_t* WEBP_RESTRICT alpha,
dst += dst_stride;
}
vst1_u8((uint8_t*)tmp, mask8);
+ alpha_mask *= 0x01010101;
alpha_mask &= tmp[0];
alpha_mask &= tmp[1];
return (alpha_mask != 0xffffffffu);
@@ -135,7 +136,7 @@ static void DispatchAlphaToGreen_NEON(const uint8_t* WEBP_RESTRICT alpha,
static int ExtractAlpha_NEON(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
int width, int height,
uint8_t* WEBP_RESTRICT alpha, int alpha_stride) {
- uint32_t alpha_mask = 0xffffffffu;
+ uint32_t alpha_mask = 0xffu;
uint8x8_t mask8 = vdup_n_u8(0xff);
uint32_t tmp[2];
int i, j;
@@ -157,6 +158,7 @@ static int ExtractAlpha_NEON(const uint8_t* WEBP_RESTRICT argb, int argb_stride,
alpha += alpha_stride;
}
vst1_u8((uint8_t*)tmp, mask8);
+ alpha_mask *= 0x01010101;
alpha_mask &= tmp[0];
alpha_mask &= tmp[1];
return (alpha_mask == 0xffffffffu);
diff --git a/thirdparty/libwebp/src/dsp/cpu.c b/thirdparty/libwebp/src/dsp/cpu.c
index 3145e190a4..a4ba7f2cb7 100644
--- a/thirdparty/libwebp/src/dsp/cpu.c
+++ b/thirdparty/libwebp/src/dsp/cpu.c
@@ -11,7 +11,7 @@
//
// Author: Christian Duvivier (cduvivier@google.com)
-#include "src/dsp/dsp.h"
+#include "src/dsp/cpu.h"
#if defined(WEBP_HAVE_NEON_RTCD)
#include <stdio.h>
diff --git a/thirdparty/libwebp/src/dsp/cpu.h b/thirdparty/libwebp/src/dsp/cpu.h
new file mode 100644
index 0000000000..57a40d87d4
--- /dev/null
+++ b/thirdparty/libwebp/src/dsp/cpu.h
@@ -0,0 +1,254 @@
+// Copyright 2022 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// CPU detection functions and macros.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_DSP_CPU_H_
+#define WEBP_DSP_CPU_H_
+
+#ifdef HAVE_CONFIG_H
+#include "src/webp/config.h"
+#endif
+
+#include "src/webp/types.h"
+
+#if defined(__GNUC__)
+#define LOCAL_GCC_VERSION ((__GNUC__ << 8) | __GNUC_MINOR__)
+#define LOCAL_GCC_PREREQ(maj, min) (LOCAL_GCC_VERSION >= (((maj) << 8) | (min)))
+#else
+#define LOCAL_GCC_VERSION 0
+#define LOCAL_GCC_PREREQ(maj, min) 0
+#endif
+
+#if defined(__clang__)
+#define LOCAL_CLANG_VERSION ((__clang_major__ << 8) | __clang_minor__)
+#define LOCAL_CLANG_PREREQ(maj, min) \
+ (LOCAL_CLANG_VERSION >= (((maj) << 8) | (min)))
+#else
+#define LOCAL_CLANG_VERSION 0
+#define LOCAL_CLANG_PREREQ(maj, min) 0
+#endif
+
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
+
+#if !defined(HAVE_CONFIG_H)
+#if defined(_MSC_VER) && _MSC_VER > 1310 && \
+ (defined(_M_X64) || defined(_M_IX86))
+#define WEBP_MSC_SSE2 // Visual C++ SSE2 targets
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1500 && \
+ (defined(_M_X64) || defined(_M_IX86))
+#define WEBP_MSC_SSE41 // Visual C++ SSE4.1 targets
+#endif
+#endif
+
+// WEBP_HAVE_* are used to indicate the presence of the instruction set in dsp
+// files without intrinsics, allowing the corresponding Init() to be called.
+// Files containing intrinsics will need to be built targeting the instruction
+// set so should succeed on one of the earlier tests.
+#if (defined(__SSE2__) || defined(WEBP_MSC_SSE2)) && \
+ (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE2))
+#define WEBP_USE_SSE2
+#endif
+
+#if defined(WEBP_USE_SSE2) && !defined(WEBP_HAVE_SSE2)
+#define WEBP_HAVE_SSE2
+#endif
+
+#if (defined(__SSE4_1__) || defined(WEBP_MSC_SSE41)) && \
+ (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE41))
+#define WEBP_USE_SSE41
+#endif
+
+#if defined(WEBP_USE_SSE41) && !defined(WEBP_HAVE_SSE41)
+#define WEBP_HAVE_SSE41
+#endif
+
+#undef WEBP_MSC_SSE41
+#undef WEBP_MSC_SSE2
+
+// The intrinsics currently cause compiler errors with arm-nacl-gcc and the
+// inline assembly would need to be modified for use with Native Client.
+#if ((defined(__ARM_NEON__) || defined(__aarch64__)) && \
+ (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_NEON))) && \
+ !defined(__native_client__)
+#define WEBP_USE_NEON
+#endif
+
+#if !defined(WEBP_USE_NEON) && defined(__ANDROID__) && \
+ defined(__ARM_ARCH_7A__) && defined(HAVE_CPU_FEATURES_H)
+#define WEBP_ANDROID_NEON // Android targets that may have NEON
+#define WEBP_USE_NEON
+#endif
+
+// Note: ARM64 is supported in Visual Studio 2017, but requires the direct
+// inclusion of arm64_neon.h; Visual Studio 2019 includes this file in
+// arm_neon.h. Compile errors were seen with Visual Studio 2019 16.4 with
+// vtbl4_u8(); a fix was made in 16.6.
+#if defined(_MSC_VER) && ((_MSC_VER >= 1700 && defined(_M_ARM)) || \
+ (_MSC_VER >= 1926 && defined(_M_ARM64)))
+#define WEBP_USE_NEON
+#define WEBP_USE_INTRINSICS
+#endif
+
+#if defined(WEBP_USE_NEON) && !defined(WEBP_HAVE_NEON)
+#define WEBP_HAVE_NEON
+#endif
+
+#if defined(__mips__) && !defined(__mips64) && defined(__mips_isa_rev) && \
+ (__mips_isa_rev >= 1) && (__mips_isa_rev < 6)
+#define WEBP_USE_MIPS32
+#if (__mips_isa_rev >= 2)
+#define WEBP_USE_MIPS32_R2
+#if defined(__mips_dspr2) || (defined(__mips_dsp_rev) && __mips_dsp_rev >= 2)
+#define WEBP_USE_MIPS_DSP_R2
+#endif
+#endif
+#endif
+
+#if defined(__mips_msa) && defined(__mips_isa_rev) && (__mips_isa_rev >= 5)
+#define WEBP_USE_MSA
+#endif
+
+#ifndef WEBP_DSP_OMIT_C_CODE
+#define WEBP_DSP_OMIT_C_CODE 1
+#endif
+
+#if defined(WEBP_USE_NEON) && WEBP_DSP_OMIT_C_CODE
+#define WEBP_NEON_OMIT_C_CODE 1
+#else
+#define WEBP_NEON_OMIT_C_CODE 0
+#endif
+
+#if !(LOCAL_CLANG_PREREQ(3, 8) || LOCAL_GCC_PREREQ(4, 8) || \
+ defined(__aarch64__))
+#define WEBP_NEON_WORK_AROUND_GCC 1
+#else
+#define WEBP_NEON_WORK_AROUND_GCC 0
+#endif
+
+// This macro prevents thread_sanitizer from reporting known concurrent writes.
+#define WEBP_TSAN_IGNORE_FUNCTION
+#if defined(__has_feature)
+#if __has_feature(thread_sanitizer)
+#undef WEBP_TSAN_IGNORE_FUNCTION
+#define WEBP_TSAN_IGNORE_FUNCTION __attribute__((no_sanitize_thread))
+#endif
+#endif
+
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+#define WEBP_MSAN
+#endif
+#endif
+
+#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
+#include <pthread.h> // NOLINT
+
+#define WEBP_DSP_INIT(func) \
+ do { \
+ static volatile VP8CPUInfo func##_last_cpuinfo_used = \
+ (VP8CPUInfo)&func##_last_cpuinfo_used; \
+ static pthread_mutex_t func##_lock = PTHREAD_MUTEX_INITIALIZER; \
+ if (pthread_mutex_lock(&func##_lock)) break; \
+ if (func##_last_cpuinfo_used != VP8GetCPUInfo) func(); \
+ func##_last_cpuinfo_used = VP8GetCPUInfo; \
+ (void)pthread_mutex_unlock(&func##_lock); \
+ } while (0)
+#else // !(defined(WEBP_USE_THREAD) && !defined(_WIN32))
+#define WEBP_DSP_INIT(func) \
+ do { \
+ static volatile VP8CPUInfo func##_last_cpuinfo_used = \
+ (VP8CPUInfo)&func##_last_cpuinfo_used; \
+ if (func##_last_cpuinfo_used == VP8GetCPUInfo) break; \
+ func(); \
+ func##_last_cpuinfo_used = VP8GetCPUInfo; \
+ } while (0)
+#endif // defined(WEBP_USE_THREAD) && !defined(_WIN32)
+
+// Defines an Init + helper function that control multiple initialization of
+// function pointers / tables.
+/* Usage:
+ WEBP_DSP_INIT_FUNC(InitFunc) {
+ ...function body
+ }
+*/
+#define WEBP_DSP_INIT_FUNC(name) \
+ static WEBP_TSAN_IGNORE_FUNCTION void name##_body(void); \
+ WEBP_TSAN_IGNORE_FUNCTION void name(void) { WEBP_DSP_INIT(name##_body); } \
+ static WEBP_TSAN_IGNORE_FUNCTION void name##_body(void)
+
+#define WEBP_UBSAN_IGNORE_UNDEF
+#define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW
+#if defined(__clang__) && defined(__has_attribute)
+#if __has_attribute(no_sanitize)
+// This macro prevents the undefined behavior sanitizer from reporting
+// failures. This is only meant to silence unaligned loads on platforms that
+// are known to support them.
+#undef WEBP_UBSAN_IGNORE_UNDEF
+#define WEBP_UBSAN_IGNORE_UNDEF __attribute__((no_sanitize("undefined")))
+
+// This macro prevents the undefined behavior sanitizer from reporting
+// failures related to unsigned integer overflows. This is only meant to
+// silence cases where this well defined behavior is expected.
+#undef WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW
+#define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW \
+ __attribute__((no_sanitize("unsigned-integer-overflow")))
+#endif
+#endif
+
+// If 'ptr' is NULL, returns NULL. Otherwise returns 'ptr + off'.
+// Prevents undefined behavior sanitizer nullptr-with-nonzero-offset warning.
+#if !defined(WEBP_OFFSET_PTR)
+#define WEBP_OFFSET_PTR(ptr, off) (((ptr) == NULL) ? NULL : ((ptr) + (off)))
+#endif
+
+// Regularize the definition of WEBP_SWAP_16BIT_CSP (backward compatibility)
+#if !defined(WEBP_SWAP_16BIT_CSP)
+#define WEBP_SWAP_16BIT_CSP 0
+#endif
+
+// some endian fix (e.g.: mips-gcc doesn't define __BIG_ENDIAN__)
+#if !defined(WORDS_BIGENDIAN) && \
+ (defined(__BIG_ENDIAN__) || defined(_M_PPC) || \
+ (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)))
+#define WORDS_BIGENDIAN
+#endif
+
+typedef enum {
+ kSSE2,
+ kSSE3,
+ kSlowSSSE3, // special feature for slow SSSE3 architectures
+ kSSE4_1,
+ kAVX,
+ kAVX2,
+ kNEON,
+ kMIPS32,
+ kMIPSdspR2,
+ kMSA
+} CPUFeature;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// returns true if the CPU supports the feature.
+typedef int (*VP8CPUInfo)(CPUFeature feature);
+WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo;
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBP_DSP_CPU_H_
diff --git a/thirdparty/libwebp/src/dsp/dsp.h b/thirdparty/libwebp/src/dsp/dsp.h
index c4f57e4d5b..d2000b8efc 100644
--- a/thirdparty/libwebp/src/dsp/dsp.h
+++ b/thirdparty/libwebp/src/dsp/dsp.h
@@ -18,6 +18,7 @@
#include "src/webp/config.h"
#endif
+#include "src/dsp/cpu.h"
#include "src/webp/types.h"
#ifdef __cplusplus
@@ -43,225 +44,6 @@ extern "C" {
#define WEBP_RESTRICT
#endif
-//------------------------------------------------------------------------------
-// CPU detection
-
-#if defined(__GNUC__)
-# define LOCAL_GCC_VERSION ((__GNUC__ << 8) | __GNUC_MINOR__)
-# define LOCAL_GCC_PREREQ(maj, min) \
- (LOCAL_GCC_VERSION >= (((maj) << 8) | (min)))
-#else
-# define LOCAL_GCC_VERSION 0
-# define LOCAL_GCC_PREREQ(maj, min) 0
-#endif
-
-#if defined(__clang__)
-# define LOCAL_CLANG_VERSION ((__clang_major__ << 8) | __clang_minor__)
-# define LOCAL_CLANG_PREREQ(maj, min) \
- (LOCAL_CLANG_VERSION >= (((maj) << 8) | (min)))
-#else
-# define LOCAL_CLANG_VERSION 0
-# define LOCAL_CLANG_PREREQ(maj, min) 0
-#endif
-
-#ifndef __has_builtin
-# define __has_builtin(x) 0
-#endif
-
-#if !defined(HAVE_CONFIG_H)
-#if defined(_MSC_VER) && _MSC_VER > 1310 && \
- (defined(_M_X64) || defined(_M_IX86))
-#define WEBP_MSC_SSE2 // Visual C++ SSE2 targets
-#endif
-
-#if defined(_MSC_VER) && _MSC_VER >= 1500 && \
- (defined(_M_X64) || defined(_M_IX86))
-#define WEBP_MSC_SSE41 // Visual C++ SSE4.1 targets
-#endif
-#endif
-
-// WEBP_HAVE_* are used to indicate the presence of the instruction set in dsp
-// files without intrinsics, allowing the corresponding Init() to be called.
-// Files containing intrinsics will need to be built targeting the instruction
-// set so should succeed on one of the earlier tests.
-#if (defined(__SSE2__) || defined(WEBP_MSC_SSE2)) && \
- (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE2))
-#define WEBP_USE_SSE2
-#endif
-
-#if defined(WEBP_USE_SSE2) && !defined(WEBP_HAVE_SSE2)
-#define WEBP_HAVE_SSE2
-#endif
-
-#if (defined(__SSE4_1__) || defined(WEBP_MSC_SSE41)) && \
- (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_SSE41))
-#define WEBP_USE_SSE41
-#endif
-
-#if defined(WEBP_USE_SSE41) && !defined(WEBP_HAVE_SSE41)
-#define WEBP_HAVE_SSE41
-#endif
-
-#undef WEBP_MSC_SSE41
-#undef WEBP_MSC_SSE2
-
-// The intrinsics currently cause compiler errors with arm-nacl-gcc and the
-// inline assembly would need to be modified for use with Native Client.
-#if ((defined(__ARM_NEON__) || defined(__aarch64__)) && \
- (!defined(HAVE_CONFIG_H) || defined(WEBP_HAVE_NEON))) && \
- !defined(__native_client__)
-#define WEBP_USE_NEON
-#endif
-
-#if !defined(WEBP_USE_NEON) && defined(__ANDROID__) && \
- defined(__ARM_ARCH_7A__) && defined(HAVE_CPU_FEATURES_H)
-#define WEBP_ANDROID_NEON // Android targets that may have NEON
-#define WEBP_USE_NEON
-#endif
-
-// Note: ARM64 is supported in Visual Studio 2017, but requires the direct
-// inclusion of arm64_neon.h; Visual Studio 2019 includes this file in
-// arm_neon.h.
-#if defined(_MSC_VER) && \
- ((_MSC_VER >= 1700 && defined(_M_ARM)) || \
- (_MSC_VER >= 1920 && defined(_M_ARM64)))
-#define WEBP_USE_NEON
-#define WEBP_USE_INTRINSICS
-#endif
-
-#if defined(WEBP_USE_NEON) && !defined(WEBP_HAVE_NEON)
-#define WEBP_HAVE_NEON
-#endif
-
-#if defined(__mips__) && !defined(__mips64) && \
- defined(__mips_isa_rev) && (__mips_isa_rev >= 1) && (__mips_isa_rev < 6)
-#define WEBP_USE_MIPS32
-#if (__mips_isa_rev >= 2)
-#define WEBP_USE_MIPS32_R2
-#if defined(__mips_dspr2) || (defined(__mips_dsp_rev) && __mips_dsp_rev >= 2)
-#define WEBP_USE_MIPS_DSP_R2
-#endif
-#endif
-#endif
-
-#if defined(__mips_msa) && defined(__mips_isa_rev) && (__mips_isa_rev >= 5)
-#define WEBP_USE_MSA
-#endif
-
-#ifndef WEBP_DSP_OMIT_C_CODE
-#define WEBP_DSP_OMIT_C_CODE 1
-#endif
-
-#if defined(WEBP_USE_NEON) && WEBP_DSP_OMIT_C_CODE
-#define WEBP_NEON_OMIT_C_CODE 1
-#else
-#define WEBP_NEON_OMIT_C_CODE 0
-#endif
-
-#if !(LOCAL_CLANG_PREREQ(3,8) || LOCAL_GCC_PREREQ(4,8) || defined(__aarch64__))
-#define WEBP_NEON_WORK_AROUND_GCC 1
-#else
-#define WEBP_NEON_WORK_AROUND_GCC 0
-#endif
-
-// This macro prevents thread_sanitizer from reporting known concurrent writes.
-#define WEBP_TSAN_IGNORE_FUNCTION
-#if defined(__has_feature)
-#if __has_feature(thread_sanitizer)
-#undef WEBP_TSAN_IGNORE_FUNCTION
-#define WEBP_TSAN_IGNORE_FUNCTION __attribute__((no_sanitize_thread))
-#endif
-#endif
-
-#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
-#include <pthread.h> // NOLINT
-
-#define WEBP_DSP_INIT(func) do { \
- static volatile VP8CPUInfo func ## _last_cpuinfo_used = \
- (VP8CPUInfo)&func ## _last_cpuinfo_used; \
- static pthread_mutex_t func ## _lock = PTHREAD_MUTEX_INITIALIZER; \
- if (pthread_mutex_lock(&func ## _lock)) break; \
- if (func ## _last_cpuinfo_used != VP8GetCPUInfo) func(); \
- func ## _last_cpuinfo_used = VP8GetCPUInfo; \
- (void)pthread_mutex_unlock(&func ## _lock); \
-} while (0)
-#else // !(defined(WEBP_USE_THREAD) && !defined(_WIN32))
-#define WEBP_DSP_INIT(func) do { \
- static volatile VP8CPUInfo func ## _last_cpuinfo_used = \
- (VP8CPUInfo)&func ## _last_cpuinfo_used; \
- if (func ## _last_cpuinfo_used == VP8GetCPUInfo) break; \
- func(); \
- func ## _last_cpuinfo_used = VP8GetCPUInfo; \
-} while (0)
-#endif // defined(WEBP_USE_THREAD) && !defined(_WIN32)
-
-// Defines an Init + helper function that control multiple initialization of
-// function pointers / tables.
-/* Usage:
- WEBP_DSP_INIT_FUNC(InitFunc) {
- ...function body
- }
-*/
-#define WEBP_DSP_INIT_FUNC(name) \
- static WEBP_TSAN_IGNORE_FUNCTION void name ## _body(void); \
- WEBP_TSAN_IGNORE_FUNCTION void name(void) { \
- WEBP_DSP_INIT(name ## _body); \
- } \
- static WEBP_TSAN_IGNORE_FUNCTION void name ## _body(void)
-
-#define WEBP_UBSAN_IGNORE_UNDEF
-#define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW
-#if defined(__clang__) && defined(__has_attribute)
-#if __has_attribute(no_sanitize)
-// This macro prevents the undefined behavior sanitizer from reporting
-// failures. This is only meant to silence unaligned loads on platforms that
-// are known to support them.
-#undef WEBP_UBSAN_IGNORE_UNDEF
-#define WEBP_UBSAN_IGNORE_UNDEF \
- __attribute__((no_sanitize("undefined")))
-
-// This macro prevents the undefined behavior sanitizer from reporting
-// failures related to unsigned integer overflows. This is only meant to
-// silence cases where this well defined behavior is expected.
-#undef WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW
-#define WEBP_UBSAN_IGNORE_UNSIGNED_OVERFLOW \
- __attribute__((no_sanitize("unsigned-integer-overflow")))
-#endif
-#endif
-
-// If 'ptr' is NULL, returns NULL. Otherwise returns 'ptr + off'.
-// Prevents undefined behavior sanitizer nullptr-with-nonzero-offset warning.
-#if !defined(WEBP_OFFSET_PTR)
-#define WEBP_OFFSET_PTR(ptr, off) (((ptr) == NULL) ? NULL : ((ptr) + (off)))
-#endif
-
-// Regularize the definition of WEBP_SWAP_16BIT_CSP (backward compatibility)
-#if !defined(WEBP_SWAP_16BIT_CSP)
-#define WEBP_SWAP_16BIT_CSP 0
-#endif
-
-// some endian fix (e.g.: mips-gcc doesn't define __BIG_ENDIAN__)
-#if !defined(WORDS_BIGENDIAN) && \
- (defined(__BIG_ENDIAN__) || defined(_M_PPC) || \
- (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)))
-#define WORDS_BIGENDIAN
-#endif
-
-typedef enum {
- kSSE2,
- kSSE3,
- kSlowSSSE3, // special feature for slow SSSE3 architectures
- kSSE4_1,
- kAVX,
- kAVX2,
- kNEON,
- kMIPS32,
- kMIPSdspR2,
- kMSA
-} CPUFeature;
-// returns true if the CPU supports the feature.
-typedef int (*VP8CPUInfo)(CPUFeature feature);
-WEBP_EXTERN VP8CPUInfo VP8GetCPUInfo;
//------------------------------------------------------------------------------
// Init stub generator
@@ -550,15 +332,6 @@ extern void WebPConvertARGBToUV_C(const uint32_t* argb, uint8_t* u, uint8_t* v,
extern void WebPConvertRGBA32ToUV_C(const uint16_t* rgb,
uint8_t* u, uint8_t* v, int width);
-// utilities for accurate RGB->YUV conversion
-extern uint64_t (*WebPSharpYUVUpdateY)(const uint16_t* src, const uint16_t* ref,
- uint16_t* dst, int len);
-extern void (*WebPSharpYUVUpdateRGB)(const int16_t* src, const int16_t* ref,
- int16_t* dst, int len);
-extern void (*WebPSharpYUVFilterRow)(const int16_t* A, const int16_t* B,
- int len,
- const uint16_t* best_y, uint16_t* out);
-
// Must be called before using the above.
void WebPInitConvertARGBToYUV(void);
diff --git a/thirdparty/libwebp/src/dsp/lossless.h b/thirdparty/libwebp/src/dsp/lossless.h
index c26c6bca07..de60d95d0b 100644
--- a/thirdparty/libwebp/src/dsp/lossless.h
+++ b/thirdparty/libwebp/src/dsp/lossless.h
@@ -182,9 +182,9 @@ extern VP8LPredictorAddSubFunc VP8LPredictorsSub_C[16];
// -----------------------------------------------------------------------------
// Huffman-cost related functions.
-typedef double (*VP8LCostFunc)(const uint32_t* population, int length);
-typedef double (*VP8LCostCombinedFunc)(const uint32_t* X, const uint32_t* Y,
- int length);
+typedef float (*VP8LCostFunc)(const uint32_t* population, int length);
+typedef float (*VP8LCostCombinedFunc)(const uint32_t* X, const uint32_t* Y,
+ int length);
typedef float (*VP8LCombinedShannonEntropyFunc)(const int X[256],
const int Y[256]);
@@ -198,7 +198,7 @@ typedef struct { // small struct to hold counters
} VP8LStreaks;
typedef struct { // small struct to hold bit entropy results
- double entropy; // entropy
+ float entropy; // entropy
uint32_t sum; // sum of the population
int nonzeros; // number of non-zero elements in the population
uint32_t max_val; // maximum value in the population
diff --git a/thirdparty/libwebp/src/dsp/lossless_enc.c b/thirdparty/libwebp/src/dsp/lossless_enc.c
index 1580631e38..de6c4ace5f 100644
--- a/thirdparty/libwebp/src/dsp/lossless_enc.c
+++ b/thirdparty/libwebp/src/dsp/lossless_enc.c
@@ -402,7 +402,7 @@ static float FastLog2Slow_C(uint32_t v) {
// Compute the combined Shanon's entropy for distribution {X} and {X+Y}
static float CombinedShannonEntropy_C(const int X[256], const int Y[256]) {
int i;
- double retval = 0.;
+ float retval = 0.f;
int sumX = 0, sumXY = 0;
for (i = 0; i < 256; ++i) {
const int x = X[i];
@@ -418,7 +418,7 @@ static float CombinedShannonEntropy_C(const int X[256], const int Y[256]) {
}
}
retval += VP8LFastSLog2(sumX) + VP8LFastSLog2(sumXY);
- return (float)retval;
+ return retval;
}
void VP8LBitEntropyInit(VP8LBitEntropy* const entropy) {
@@ -636,17 +636,17 @@ void VP8LBundleColorMap_C(const uint8_t* const row, int width, int xbits,
//------------------------------------------------------------------------------
-static double ExtraCost_C(const uint32_t* population, int length) {
+static float ExtraCost_C(const uint32_t* population, int length) {
int i;
- double cost = 0.;
+ float cost = 0.f;
for (i = 2; i < length - 2; ++i) cost += (i >> 1) * population[i + 2];
return cost;
}
-static double ExtraCostCombined_C(const uint32_t* X, const uint32_t* Y,
+static float ExtraCostCombined_C(const uint32_t* X, const uint32_t* Y,
int length) {
int i;
- double cost = 0.;
+ float cost = 0.f;
for (i = 2; i < length - 2; ++i) {
const int xy = X[i + 2] + Y[i + 2];
cost += (i >> 1) * xy;
diff --git a/thirdparty/libwebp/src/dsp/lossless_enc_mips32.c b/thirdparty/libwebp/src/dsp/lossless_enc_mips32.c
index 0412a093cf..639f786631 100644
--- a/thirdparty/libwebp/src/dsp/lossless_enc_mips32.c
+++ b/thirdparty/libwebp/src/dsp/lossless_enc_mips32.c
@@ -103,8 +103,8 @@ static float FastLog2Slow_MIPS32(uint32_t v) {
// cost += i * *(pop + 1);
// pop += 2;
// }
-// return (double)cost;
-static double ExtraCost_MIPS32(const uint32_t* const population, int length) {
+// return (float)cost;
+static float ExtraCost_MIPS32(const uint32_t* const population, int length) {
int i, temp0, temp1;
const uint32_t* pop = &population[4];
const uint32_t* const LoopEnd = &population[length];
@@ -130,7 +130,7 @@ static double ExtraCost_MIPS32(const uint32_t* const population, int length) {
: "memory", "hi", "lo"
);
- return (double)((int64_t)temp0 << 32 | temp1);
+ return (float)((int64_t)temp0 << 32 | temp1);
}
// C version of this function:
@@ -148,9 +148,9 @@ static double ExtraCost_MIPS32(const uint32_t* const population, int length) {
// pX += 2;
// pY += 2;
// }
-// return (double)cost;
-static double ExtraCostCombined_MIPS32(const uint32_t* const X,
- const uint32_t* const Y, int length) {
+// return (float)cost;
+static float ExtraCostCombined_MIPS32(const uint32_t* const X,
+ const uint32_t* const Y, int length) {
int i, temp0, temp1, temp2, temp3;
const uint32_t* pX = &X[4];
const uint32_t* pY = &Y[4];
@@ -183,7 +183,7 @@ static double ExtraCostCombined_MIPS32(const uint32_t* const X,
: "memory", "hi", "lo"
);
- return (double)((int64_t)temp0 << 32 | temp1);
+ return (float)((int64_t)temp0 << 32 | temp1);
}
#define HUFFMAN_COST_PASS \
@@ -347,24 +347,24 @@ static void GetCombinedEntropyUnrefined_MIPS32(const uint32_t X[],
static void AddVector_MIPS32(const uint32_t* pa, const uint32_t* pb,
uint32_t* pout, int size) {
uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
- const uint32_t end = ((size) / 4) * 4;
+ const int end = ((size) / 4) * 4;
const uint32_t* const LoopEnd = pa + end;
int i;
ASM_START
ADD_TO_OUT(0, 4, 8, 12, 1, pa, pb, pout)
ASM_END_0
- for (i = end; i < size; ++i) pout[i] = pa[i] + pb[i];
+ for (i = 0; i < size - end; ++i) pout[i] = pa[i] + pb[i];
}
static void AddVectorEq_MIPS32(const uint32_t* pa, uint32_t* pout, int size) {
uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
- const uint32_t end = ((size) / 4) * 4;
+ const int end = ((size) / 4) * 4;
const uint32_t* const LoopEnd = pa + end;
int i;
ASM_START
ADD_TO_OUT(0, 4, 8, 12, 0, pa, pout, pout)
ASM_END_1
- for (i = end; i < size; ++i) pout[i] += pa[i];
+ for (i = 0; i < size - end; ++i) pout[i] += pa[i];
}
#undef ASM_END_1
diff --git a/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c b/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c
index b2f83b871c..948001a3d5 100644
--- a/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c
+++ b/thirdparty/libwebp/src/dsp/lossless_enc_sse2.c
@@ -239,7 +239,7 @@ static void AddVectorEq_SSE2(const uint32_t* a, uint32_t* out, int size) {
static float CombinedShannonEntropy_SSE2(const int X[256], const int Y[256]) {
int i;
- double retval = 0.;
+ float retval = 0.f;
int sumX = 0, sumXY = 0;
const __m128i zero = _mm_setzero_si128();
@@ -273,7 +273,7 @@ static float CombinedShannonEntropy_SSE2(const int X[256], const int Y[256]) {
}
}
retval += VP8LFastSLog2(sumX) + VP8LFastSLog2(sumXY);
- return (float)retval;
+ return retval;
}
#else
diff --git a/thirdparty/libwebp/src/dsp/yuv.c b/thirdparty/libwebp/src/dsp/yuv.c
index 48466f8b11..d16c13d3ca 100644
--- a/thirdparty/libwebp/src/dsp/yuv.c
+++ b/thirdparty/libwebp/src/dsp/yuv.c
@@ -194,50 +194,6 @@ void WebPConvertRGBA32ToUV_C(const uint16_t* rgb,
//-----------------------------------------------------------------------------
-#if !WEBP_NEON_OMIT_C_CODE
-#define MAX_Y ((1 << 10) - 1) // 10b precision over 16b-arithmetic
-static uint16_t clip_y(int v) {
- return (v < 0) ? 0 : (v > MAX_Y) ? MAX_Y : (uint16_t)v;
-}
-
-static uint64_t SharpYUVUpdateY_C(const uint16_t* ref, const uint16_t* src,
- uint16_t* dst, int len) {
- uint64_t diff = 0;
- int i;
- for (i = 0; i < len; ++i) {
- const int diff_y = ref[i] - src[i];
- const int new_y = (int)dst[i] + diff_y;
- dst[i] = clip_y(new_y);
- diff += (uint64_t)abs(diff_y);
- }
- return diff;
-}
-
-static void SharpYUVUpdateRGB_C(const int16_t* ref, const int16_t* src,
- int16_t* dst, int len) {
- int i;
- for (i = 0; i < len; ++i) {
- const int diff_uv = ref[i] - src[i];
- dst[i] += diff_uv;
- }
-}
-
-static void SharpYUVFilterRow_C(const int16_t* A, const int16_t* B, int len,
- const uint16_t* best_y, uint16_t* out) {
- int i;
- for (i = 0; i < len; ++i, ++A, ++B) {
- const int v0 = (A[0] * 9 + A[1] * 3 + B[0] * 3 + B[1] + 8) >> 4;
- const int v1 = (A[1] * 9 + A[0] * 3 + B[1] * 3 + B[0] + 8) >> 4;
- out[2 * i + 0] = clip_y(best_y[2 * i + 0] + v0);
- out[2 * i + 1] = clip_y(best_y[2 * i + 1] + v1);
- }
-}
-#endif // !WEBP_NEON_OMIT_C_CODE
-
-#undef MAX_Y
-
-//-----------------------------------------------------------------------------
-
void (*WebPConvertRGB24ToY)(const uint8_t* rgb, uint8_t* y, int width);
void (*WebPConvertBGR24ToY)(const uint8_t* bgr, uint8_t* y, int width);
void (*WebPConvertRGBA32ToUV)(const uint16_t* rgb,
@@ -247,18 +203,9 @@ void (*WebPConvertARGBToY)(const uint32_t* argb, uint8_t* y, int width);
void (*WebPConvertARGBToUV)(const uint32_t* argb, uint8_t* u, uint8_t* v,
int src_width, int do_store);
-uint64_t (*WebPSharpYUVUpdateY)(const uint16_t* ref, const uint16_t* src,
- uint16_t* dst, int len);
-void (*WebPSharpYUVUpdateRGB)(const int16_t* ref, const int16_t* src,
- int16_t* dst, int len);
-void (*WebPSharpYUVFilterRow)(const int16_t* A, const int16_t* B, int len,
- const uint16_t* best_y, uint16_t* out);
-
extern void WebPInitConvertARGBToYUVSSE2(void);
extern void WebPInitConvertARGBToYUVSSE41(void);
extern void WebPInitConvertARGBToYUVNEON(void);
-extern void WebPInitSharpYUVSSE2(void);
-extern void WebPInitSharpYUVNEON(void);
WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) {
WebPConvertARGBToY = ConvertARGBToY_C;
@@ -269,17 +216,10 @@ WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) {
WebPConvertRGBA32ToUV = WebPConvertRGBA32ToUV_C;
-#if !WEBP_NEON_OMIT_C_CODE
- WebPSharpYUVUpdateY = SharpYUVUpdateY_C;
- WebPSharpYUVUpdateRGB = SharpYUVUpdateRGB_C;
- WebPSharpYUVFilterRow = SharpYUVFilterRow_C;
-#endif
-
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_HAVE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
WebPInitConvertARGBToYUVSSE2();
- WebPInitSharpYUVSSE2();
}
#endif // WEBP_HAVE_SSE2
#if defined(WEBP_HAVE_SSE41)
@@ -293,7 +233,6 @@ WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) {
if (WEBP_NEON_OMIT_C_CODE ||
(VP8GetCPUInfo != NULL && VP8GetCPUInfo(kNEON))) {
WebPInitConvertARGBToYUVNEON();
- WebPInitSharpYUVNEON();
}
#endif // WEBP_HAVE_NEON
@@ -302,7 +241,4 @@ WEBP_DSP_INIT_FUNC(WebPInitConvertARGBToYUV) {
assert(WebPConvertRGB24ToY != NULL);
assert(WebPConvertBGR24ToY != NULL);
assert(WebPConvertRGBA32ToUV != NULL);
- assert(WebPSharpYUVUpdateY != NULL);
- assert(WebPSharpYUVUpdateRGB != NULL);
- assert(WebPSharpYUVFilterRow != NULL);
}
diff --git a/thirdparty/libwebp/src/dsp/yuv_neon.c b/thirdparty/libwebp/src/dsp/yuv_neon.c
index a34d60248f..ff77b00980 100644
--- a/thirdparty/libwebp/src/dsp/yuv_neon.c
+++ b/thirdparty/libwebp/src/dsp/yuv_neon.c
@@ -173,116 +173,8 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUVNEON(void) {
WebPConvertRGBA32ToUV = ConvertRGBA32ToUV_NEON;
}
-//------------------------------------------------------------------------------
-
-#define MAX_Y ((1 << 10) - 1) // 10b precision over 16b-arithmetic
-static uint16_t clip_y_NEON(int v) {
- return (v < 0) ? 0 : (v > MAX_Y) ? MAX_Y : (uint16_t)v;
-}
-
-static uint64_t SharpYUVUpdateY_NEON(const uint16_t* ref, const uint16_t* src,
- uint16_t* dst, int len) {
- int i;
- const int16x8_t zero = vdupq_n_s16(0);
- const int16x8_t max = vdupq_n_s16(MAX_Y);
- uint64x2_t sum = vdupq_n_u64(0);
- uint64_t diff;
-
- for (i = 0; i + 8 <= len; i += 8) {
- const int16x8_t A = vreinterpretq_s16_u16(vld1q_u16(ref + i));
- const int16x8_t B = vreinterpretq_s16_u16(vld1q_u16(src + i));
- const int16x8_t C = vreinterpretq_s16_u16(vld1q_u16(dst + i));
- const int16x8_t D = vsubq_s16(A, B); // diff_y
- const int16x8_t F = vaddq_s16(C, D); // new_y
- const uint16x8_t H =
- vreinterpretq_u16_s16(vmaxq_s16(vminq_s16(F, max), zero));
- const int16x8_t I = vabsq_s16(D); // abs(diff_y)
- vst1q_u16(dst + i, H);
- sum = vpadalq_u32(sum, vpaddlq_u16(vreinterpretq_u16_s16(I)));
- }
- diff = vgetq_lane_u64(sum, 0) + vgetq_lane_u64(sum, 1);
- for (; i < len; ++i) {
- const int diff_y = ref[i] - src[i];
- const int new_y = (int)(dst[i]) + diff_y;
- dst[i] = clip_y_NEON(new_y);
- diff += (uint64_t)(abs(diff_y));
- }
- return diff;
-}
-
-static void SharpYUVUpdateRGB_NEON(const int16_t* ref, const int16_t* src,
- int16_t* dst, int len) {
- int i;
- for (i = 0; i + 8 <= len; i += 8) {
- const int16x8_t A = vld1q_s16(ref + i);
- const int16x8_t B = vld1q_s16(src + i);
- const int16x8_t C = vld1q_s16(dst + i);
- const int16x8_t D = vsubq_s16(A, B); // diff_uv
- const int16x8_t E = vaddq_s16(C, D); // new_uv
- vst1q_s16(dst + i, E);
- }
- for (; i < len; ++i) {
- const int diff_uv = ref[i] - src[i];
- dst[i] += diff_uv;
- }
-}
-
-static void SharpYUVFilterRow_NEON(const int16_t* A, const int16_t* B, int len,
- const uint16_t* best_y, uint16_t* out) {
- int i;
- const int16x8_t max = vdupq_n_s16(MAX_Y);
- const int16x8_t zero = vdupq_n_s16(0);
- for (i = 0; i + 8 <= len; i += 8) {
- const int16x8_t a0 = vld1q_s16(A + i + 0);
- const int16x8_t a1 = vld1q_s16(A + i + 1);
- const int16x8_t b0 = vld1q_s16(B + i + 0);
- const int16x8_t b1 = vld1q_s16(B + i + 1);
- const int16x8_t a0b1 = vaddq_s16(a0, b1);
- const int16x8_t a1b0 = vaddq_s16(a1, b0);
- const int16x8_t a0a1b0b1 = vaddq_s16(a0b1, a1b0); // A0+A1+B0+B1
- const int16x8_t a0b1_2 = vaddq_s16(a0b1, a0b1); // 2*(A0+B1)
- const int16x8_t a1b0_2 = vaddq_s16(a1b0, a1b0); // 2*(A1+B0)
- const int16x8_t c0 = vshrq_n_s16(vaddq_s16(a0b1_2, a0a1b0b1), 3);
- const int16x8_t c1 = vshrq_n_s16(vaddq_s16(a1b0_2, a0a1b0b1), 3);
- const int16x8_t d0 = vaddq_s16(c1, a0);
- const int16x8_t d1 = vaddq_s16(c0, a1);
- const int16x8_t e0 = vrshrq_n_s16(d0, 1);
- const int16x8_t e1 = vrshrq_n_s16(d1, 1);
- const int16x8x2_t f = vzipq_s16(e0, e1);
- const int16x8_t g0 = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i + 0));
- const int16x8_t g1 = vreinterpretq_s16_u16(vld1q_u16(best_y + 2 * i + 8));
- const int16x8_t h0 = vaddq_s16(g0, f.val[0]);
- const int16x8_t h1 = vaddq_s16(g1, f.val[1]);
- const int16x8_t i0 = vmaxq_s16(vminq_s16(h0, max), zero);
- const int16x8_t i1 = vmaxq_s16(vminq_s16(h1, max), zero);
- vst1q_u16(out + 2 * i + 0, vreinterpretq_u16_s16(i0));
- vst1q_u16(out + 2 * i + 8, vreinterpretq_u16_s16(i1));
- }
- for (; i < len; ++i) {
- const int a0b1 = A[i + 0] + B[i + 1];
- const int a1b0 = A[i + 1] + B[i + 0];
- const int a0a1b0b1 = a0b1 + a1b0 + 8;
- const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4;
- const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4;
- out[2 * i + 0] = clip_y_NEON(best_y[2 * i + 0] + v0);
- out[2 * i + 1] = clip_y_NEON(best_y[2 * i + 1] + v1);
- }
-}
-#undef MAX_Y
-
-//------------------------------------------------------------------------------
-
-extern void WebPInitSharpYUVNEON(void);
-
-WEBP_TSAN_IGNORE_FUNCTION void WebPInitSharpYUVNEON(void) {
- WebPSharpYUVUpdateY = SharpYUVUpdateY_NEON;
- WebPSharpYUVUpdateRGB = SharpYUVUpdateRGB_NEON;
- WebPSharpYUVFilterRow = SharpYUVFilterRow_NEON;
-}
-
#else // !WEBP_USE_NEON
WEBP_DSP_INIT_STUB(WebPInitConvertARGBToYUVNEON)
-WEBP_DSP_INIT_STUB(WebPInitSharpYUVNEON)
#endif // WEBP_USE_NEON
diff --git a/thirdparty/libwebp/src/dsp/yuv_sse2.c b/thirdparty/libwebp/src/dsp/yuv_sse2.c
index baa48d5371..970bbb7884 100644
--- a/thirdparty/libwebp/src/dsp/yuv_sse2.c
+++ b/thirdparty/libwebp/src/dsp/yuv_sse2.c
@@ -747,128 +747,9 @@ WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUVSSE2(void) {
WebPConvertRGBA32ToUV = ConvertRGBA32ToUV_SSE2;
}
-//------------------------------------------------------------------------------
-
-#define MAX_Y ((1 << 10) - 1) // 10b precision over 16b-arithmetic
-static uint16_t clip_y(int v) {
- return (v < 0) ? 0 : (v > MAX_Y) ? MAX_Y : (uint16_t)v;
-}
-
-static uint64_t SharpYUVUpdateY_SSE2(const uint16_t* ref, const uint16_t* src,
- uint16_t* dst, int len) {
- uint64_t diff = 0;
- uint32_t tmp[4];
- int i;
- const __m128i zero = _mm_setzero_si128();
- const __m128i max = _mm_set1_epi16(MAX_Y);
- const __m128i one = _mm_set1_epi16(1);
- __m128i sum = zero;
-
- for (i = 0; i + 8 <= len; i += 8) {
- const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i));
- const __m128i B = _mm_loadu_si128((const __m128i*)(src + i));
- const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i));
- const __m128i D = _mm_sub_epi16(A, B); // diff_y
- const __m128i E = _mm_cmpgt_epi16(zero, D); // sign (-1 or 0)
- const __m128i F = _mm_add_epi16(C, D); // new_y
- const __m128i G = _mm_or_si128(E, one); // -1 or 1
- const __m128i H = _mm_max_epi16(_mm_min_epi16(F, max), zero);
- const __m128i I = _mm_madd_epi16(D, G); // sum(abs(...))
- _mm_storeu_si128((__m128i*)(dst + i), H);
- sum = _mm_add_epi32(sum, I);
- }
- _mm_storeu_si128((__m128i*)tmp, sum);
- diff = tmp[3] + tmp[2] + tmp[1] + tmp[0];
- for (; i < len; ++i) {
- const int diff_y = ref[i] - src[i];
- const int new_y = (int)dst[i] + diff_y;
- dst[i] = clip_y(new_y);
- diff += (uint64_t)abs(diff_y);
- }
- return diff;
-}
-
-static void SharpYUVUpdateRGB_SSE2(const int16_t* ref, const int16_t* src,
- int16_t* dst, int len) {
- int i = 0;
- for (i = 0; i + 8 <= len; i += 8) {
- const __m128i A = _mm_loadu_si128((const __m128i*)(ref + i));
- const __m128i B = _mm_loadu_si128((const __m128i*)(src + i));
- const __m128i C = _mm_loadu_si128((const __m128i*)(dst + i));
- const __m128i D = _mm_sub_epi16(A, B); // diff_uv
- const __m128i E = _mm_add_epi16(C, D); // new_uv
- _mm_storeu_si128((__m128i*)(dst + i), E);
- }
- for (; i < len; ++i) {
- const int diff_uv = ref[i] - src[i];
- dst[i] += diff_uv;
- }
-}
-
-static void SharpYUVFilterRow_SSE2(const int16_t* A, const int16_t* B, int len,
- const uint16_t* best_y, uint16_t* out) {
- int i;
- const __m128i kCst8 = _mm_set1_epi16(8);
- const __m128i max = _mm_set1_epi16(MAX_Y);
- const __m128i zero = _mm_setzero_si128();
- for (i = 0; i + 8 <= len; i += 8) {
- const __m128i a0 = _mm_loadu_si128((const __m128i*)(A + i + 0));
- const __m128i a1 = _mm_loadu_si128((const __m128i*)(A + i + 1));
- const __m128i b0 = _mm_loadu_si128((const __m128i*)(B + i + 0));
- const __m128i b1 = _mm_loadu_si128((const __m128i*)(B + i + 1));
- const __m128i a0b1 = _mm_add_epi16(a0, b1);
- const __m128i a1b0 = _mm_add_epi16(a1, b0);
- const __m128i a0a1b0b1 = _mm_add_epi16(a0b1, a1b0); // A0+A1+B0+B1
- const __m128i a0a1b0b1_8 = _mm_add_epi16(a0a1b0b1, kCst8);
- const __m128i a0b1_2 = _mm_add_epi16(a0b1, a0b1); // 2*(A0+B1)
- const __m128i a1b0_2 = _mm_add_epi16(a1b0, a1b0); // 2*(A1+B0)
- const __m128i c0 = _mm_srai_epi16(_mm_add_epi16(a0b1_2, a0a1b0b1_8), 3);
- const __m128i c1 = _mm_srai_epi16(_mm_add_epi16(a1b0_2, a0a1b0b1_8), 3);
- const __m128i d0 = _mm_add_epi16(c1, a0);
- const __m128i d1 = _mm_add_epi16(c0, a1);
- const __m128i e0 = _mm_srai_epi16(d0, 1);
- const __m128i e1 = _mm_srai_epi16(d1, 1);
- const __m128i f0 = _mm_unpacklo_epi16(e0, e1);
- const __m128i f1 = _mm_unpackhi_epi16(e0, e1);
- const __m128i g0 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 0));
- const __m128i g1 = _mm_loadu_si128((const __m128i*)(best_y + 2 * i + 8));
- const __m128i h0 = _mm_add_epi16(g0, f0);
- const __m128i h1 = _mm_add_epi16(g1, f1);
- const __m128i i0 = _mm_max_epi16(_mm_min_epi16(h0, max), zero);
- const __m128i i1 = _mm_max_epi16(_mm_min_epi16(h1, max), zero);
- _mm_storeu_si128((__m128i*)(out + 2 * i + 0), i0);
- _mm_storeu_si128((__m128i*)(out + 2 * i + 8), i1);
- }
- for (; i < len; ++i) {
- // (9 * A0 + 3 * A1 + 3 * B0 + B1 + 8) >> 4 =
- // = (8 * A0 + 2 * (A1 + B0) + (A0 + A1 + B0 + B1 + 8)) >> 4
- // We reuse the common sub-expressions.
- const int a0b1 = A[i + 0] + B[i + 1];
- const int a1b0 = A[i + 1] + B[i + 0];
- const int a0a1b0b1 = a0b1 + a1b0 + 8;
- const int v0 = (8 * A[i + 0] + 2 * a1b0 + a0a1b0b1) >> 4;
- const int v1 = (8 * A[i + 1] + 2 * a0b1 + a0a1b0b1) >> 4;
- out[2 * i + 0] = clip_y(best_y[2 * i + 0] + v0);
- out[2 * i + 1] = clip_y(best_y[2 * i + 1] + v1);
- }
-}
-
-#undef MAX_Y
-
-//------------------------------------------------------------------------------
-
-extern void WebPInitSharpYUVSSE2(void);
-
-WEBP_TSAN_IGNORE_FUNCTION void WebPInitSharpYUVSSE2(void) {
- WebPSharpYUVUpdateY = SharpYUVUpdateY_SSE2;
- WebPSharpYUVUpdateRGB = SharpYUVUpdateRGB_SSE2;
- WebPSharpYUVFilterRow = SharpYUVFilterRow_SSE2;
-}
-
#else // !WEBP_USE_SSE2
WEBP_DSP_INIT_STUB(WebPInitSamplersSSE2)
WEBP_DSP_INIT_STUB(WebPInitConvertARGBToYUVSSE2)
-WEBP_DSP_INIT_STUB(WebPInitSharpYUVSSE2)
#endif // WEBP_USE_SSE2
diff --git a/thirdparty/libwebp/src/enc/alpha_enc.c b/thirdparty/libwebp/src/enc/alpha_enc.c
index 0b54f3e6ec..f7c02690e3 100644
--- a/thirdparty/libwebp/src/enc/alpha_enc.c
+++ b/thirdparty/libwebp/src/enc/alpha_enc.c
@@ -86,7 +86,7 @@ static int EncodeLossless(const uint8_t* const data, int width, int height,
// a decoder bug related to alpha with color cache.
// See: https://code.google.com/p/webp/issues/detail?id=239
// Need to re-enable this later.
- ok = (VP8LEncodeStream(&config, &picture, bw, 0 /*use_cache*/) == VP8_ENC_OK);
+ ok = VP8LEncodeStream(&config, &picture, bw, /*use_cache=*/0);
WebPPictureFree(&picture);
ok = ok && !bw->error_;
if (!ok) {
diff --git a/thirdparty/libwebp/src/enc/backward_references_cost_enc.c b/thirdparty/libwebp/src/enc/backward_references_cost_enc.c
index 516abd73eb..6968ef3c9f 100644
--- a/thirdparty/libwebp/src/enc/backward_references_cost_enc.c
+++ b/thirdparty/libwebp/src/enc/backward_references_cost_enc.c
@@ -15,10 +15,11 @@
//
#include <assert.h>
+#include <float.h>
+#include "src/dsp/lossless_common.h"
#include "src/enc/backward_references_enc.h"
#include "src/enc/histogram_enc.h"
-#include "src/dsp/lossless_common.h"
#include "src/utils/color_cache_utils.h"
#include "src/utils/utils.h"
@@ -30,15 +31,15 @@ extern void VP8LBackwardRefsCursorAdd(VP8LBackwardRefs* const refs,
const PixOrCopy v);
typedef struct {
- double alpha_[VALUES_IN_BYTE];
- double red_[VALUES_IN_BYTE];
- double blue_[VALUES_IN_BYTE];
- double distance_[NUM_DISTANCE_CODES];
- double* literal_;
+ float alpha_[VALUES_IN_BYTE];
+ float red_[VALUES_IN_BYTE];
+ float blue_[VALUES_IN_BYTE];
+ float distance_[NUM_DISTANCE_CODES];
+ float* literal_;
} CostModel;
static void ConvertPopulationCountTableToBitEstimates(
- int num_symbols, const uint32_t population_counts[], double output[]) {
+ int num_symbols, const uint32_t population_counts[], float output[]) {
uint32_t sum = 0;
int nonzeros = 0;
int i;
@@ -51,7 +52,7 @@ static void ConvertPopulationCountTableToBitEstimates(
if (nonzeros <= 1) {
memset(output, 0, num_symbols * sizeof(*output));
} else {
- const double logsum = VP8LFastLog2(sum);
+ const float logsum = VP8LFastLog2(sum);
for (i = 0; i < num_symbols; ++i) {
output[i] = logsum - VP8LFastLog2(population_counts[i]);
}
@@ -75,8 +76,8 @@ static int CostModelBuild(CostModel* const m, int xsize, int cache_bits,
}
ConvertPopulationCountTableToBitEstimates(
- VP8LHistogramNumCodes(histo->palette_code_bits_),
- histo->literal_, m->literal_);
+ VP8LHistogramNumCodes(histo->palette_code_bits_), histo->literal_,
+ m->literal_);
ConvertPopulationCountTableToBitEstimates(
VALUES_IN_BYTE, histo->red_, m->red_);
ConvertPopulationCountTableToBitEstimates(
@@ -92,27 +93,27 @@ static int CostModelBuild(CostModel* const m, int xsize, int cache_bits,
return ok;
}
-static WEBP_INLINE double GetLiteralCost(const CostModel* const m, uint32_t v) {
+static WEBP_INLINE float GetLiteralCost(const CostModel* const m, uint32_t v) {
return m->alpha_[v >> 24] +
m->red_[(v >> 16) & 0xff] +
m->literal_[(v >> 8) & 0xff] +
m->blue_[v & 0xff];
}
-static WEBP_INLINE double GetCacheCost(const CostModel* const m, uint32_t idx) {
+static WEBP_INLINE float GetCacheCost(const CostModel* const m, uint32_t idx) {
const int literal_idx = VALUES_IN_BYTE + NUM_LENGTH_CODES + idx;
return m->literal_[literal_idx];
}
-static WEBP_INLINE double GetLengthCost(const CostModel* const m,
- uint32_t length) {
+static WEBP_INLINE float GetLengthCost(const CostModel* const m,
+ uint32_t length) {
int code, extra_bits;
VP8LPrefixEncodeBits(length, &code, &extra_bits);
return m->literal_[VALUES_IN_BYTE + code] + extra_bits;
}
-static WEBP_INLINE double GetDistanceCost(const CostModel* const m,
- uint32_t distance) {
+static WEBP_INLINE float GetDistanceCost(const CostModel* const m,
+ uint32_t distance) {
int code, extra_bits;
VP8LPrefixEncodeBits(distance, &code, &extra_bits);
return m->distance_[code] + extra_bits;
@@ -122,20 +123,20 @@ static WEBP_INLINE void AddSingleLiteralWithCostModel(
const uint32_t* const argb, VP8LColorCache* const hashers,
const CostModel* const cost_model, int idx, int use_color_cache,
float prev_cost, float* const cost, uint16_t* const dist_array) {
- double cost_val = prev_cost;
+ float cost_val = prev_cost;
const uint32_t color = argb[idx];
const int ix = use_color_cache ? VP8LColorCacheContains(hashers, color) : -1;
if (ix >= 0) {
// use_color_cache is true and hashers contains color
- const double mul0 = 0.68;
+ const float mul0 = 0.68f;
cost_val += GetCacheCost(cost_model, ix) * mul0;
} else {
- const double mul1 = 0.82;
+ const float mul1 = 0.82f;
if (use_color_cache) VP8LColorCacheInsert(hashers, color);
cost_val += GetLiteralCost(cost_model, color) * mul1;
}
if (cost[idx] > cost_val) {
- cost[idx] = (float)cost_val;
+ cost[idx] = cost_val;
dist_array[idx] = 1; // only one is inserted.
}
}
@@ -172,7 +173,7 @@ struct CostInterval {
// The GetLengthCost(cost_model, k) are cached in a CostCacheInterval.
typedef struct {
- double cost_;
+ float cost_;
int start_;
int end_; // Exclusive.
} CostCacheInterval;
@@ -187,7 +188,7 @@ typedef struct {
int count_; // The number of stored intervals.
CostCacheInterval* cache_intervals_;
size_t cache_intervals_size_;
- double cost_cache_[MAX_LENGTH]; // Contains the GetLengthCost(cost_model, k).
+ float cost_cache_[MAX_LENGTH]; // Contains the GetLengthCost(cost_model, k).
float* costs_;
uint16_t* dist_array_;
// Most of the time, we only need few intervals -> use a free-list, to avoid
@@ -262,10 +263,13 @@ static int CostManagerInit(CostManager* const manager,
CostManagerInitFreeList(manager);
// Fill in the cost_cache_.
+ // Has to be done in two passes due to a GCC bug on i686
+ // related to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323
+ for (i = 0; i < cost_cache_size; ++i) {
+ manager->cost_cache_[i] = GetLengthCost(cost_model, i);
+ }
manager->cache_intervals_size_ = 1;
- manager->cost_cache_[0] = GetLengthCost(cost_model, 0);
for (i = 1; i < cost_cache_size; ++i) {
- manager->cost_cache_[i] = GetLengthCost(cost_model, i);
// Get the number of bound intervals.
if (manager->cost_cache_[i] != manager->cost_cache_[i - 1]) {
++manager->cache_intervals_size_;
@@ -294,7 +298,7 @@ static int CostManagerInit(CostManager* const manager,
cur->end_ = 1;
cur->cost_ = manager->cost_cache_[0];
for (i = 1; i < cost_cache_size; ++i) {
- const double cost_val = manager->cost_cache_[i];
+ const float cost_val = manager->cost_cache_[i];
if (cost_val != cur->cost_) {
++cur;
// Initialize an interval.
@@ -303,6 +307,8 @@ static int CostManagerInit(CostManager* const manager,
}
cur->end_ = i + 1;
}
+ assert((size_t)(cur - manager->cache_intervals_) + 1 ==
+ manager->cache_intervals_size_);
}
manager->costs_ = (float*)WebPSafeMalloc(pix_count, sizeof(*manager->costs_));
@@ -311,7 +317,7 @@ static int CostManagerInit(CostManager* const manager,
return 0;
}
// Set the initial costs_ high for every pixel as we will keep the minimum.
- for (i = 0; i < pix_count; ++i) manager->costs_[i] = 1e38f;
+ for (i = 0; i < pix_count; ++i) manager->costs_[i] = FLT_MAX;
return 1;
}
@@ -457,7 +463,7 @@ static WEBP_INLINE void InsertInterval(CostManager* const manager,
// If handling the interval or one of its subintervals becomes to heavy, its
// contribution is added to the costs right away.
static WEBP_INLINE void PushInterval(CostManager* const manager,
- double distance_cost, int position,
+ float distance_cost, int position,
int len) {
size_t i;
CostInterval* interval = manager->head_;
@@ -474,7 +480,7 @@ static WEBP_INLINE void PushInterval(CostManager* const manager,
const int k = j - position;
float cost_tmp;
assert(k >= 0 && k < MAX_LENGTH);
- cost_tmp = (float)(distance_cost + manager->cost_cache_[k]);
+ cost_tmp = distance_cost + manager->cost_cache_[k];
if (manager->costs_[j] > cost_tmp) {
manager->costs_[j] = cost_tmp;
@@ -492,7 +498,7 @@ static WEBP_INLINE void PushInterval(CostManager* const manager,
const int end = position + (cost_cache_intervals[i].end_ > len
? len
: cost_cache_intervals[i].end_);
- const float cost = (float)(distance_cost + cost_cache_intervals[i].cost_);
+ const float cost = distance_cost + cost_cache_intervals[i].cost_;
for (; interval != NULL && interval->start_ < end;
interval = interval_next) {
@@ -570,22 +576,21 @@ static int BackwardReferencesHashChainDistanceOnly(
const int pix_count = xsize * ysize;
const int use_color_cache = (cache_bits > 0);
const size_t literal_array_size =
- sizeof(double) * (NUM_LITERAL_CODES + NUM_LENGTH_CODES +
- ((cache_bits > 0) ? (1 << cache_bits) : 0));
+ sizeof(float) * (VP8LHistogramNumCodes(cache_bits));
const size_t cost_model_size = sizeof(CostModel) + literal_array_size;
CostModel* const cost_model =
(CostModel*)WebPSafeCalloc(1ULL, cost_model_size);
VP8LColorCache hashers;
CostManager* cost_manager =
- (CostManager*)WebPSafeMalloc(1ULL, sizeof(*cost_manager));
+ (CostManager*)WebPSafeCalloc(1ULL, sizeof(*cost_manager));
int offset_prev = -1, len_prev = -1;
- double offset_cost = -1;
+ float offset_cost = -1.f;
int first_offset_is_constant = -1; // initialized with 'impossible' value
int reach = 0;
if (cost_model == NULL || cost_manager == NULL) goto Error;
- cost_model->literal_ = (double*)(cost_model + 1);
+ cost_model->literal_ = (float*)(cost_model + 1);
if (use_color_cache) {
cc_init = VP8LColorCacheInit(&hashers, cache_bits);
if (!cc_init) goto Error;
@@ -675,7 +680,7 @@ static int BackwardReferencesHashChainDistanceOnly(
}
ok = !refs->error_;
-Error:
+ Error:
if (cc_init) VP8LColorCacheClear(&hashers);
CostManagerClear(cost_manager);
WebPSafeFree(cost_model);
diff --git a/thirdparty/libwebp/src/enc/backward_references_enc.c b/thirdparty/libwebp/src/enc/backward_references_enc.c
index 519b36a091..49a0fac034 100644
--- a/thirdparty/libwebp/src/enc/backward_references_enc.c
+++ b/thirdparty/libwebp/src/enc/backward_references_enc.c
@@ -10,6 +10,8 @@
// Author: Jyrki Alakuijala (jyrki@google.com)
//
+#include "src/enc/backward_references_enc.h"
+
#include <assert.h>
#include <float.h>
#include <math.h>
@@ -17,10 +19,11 @@
#include "src/dsp/dsp.h"
#include "src/dsp/lossless.h"
#include "src/dsp/lossless_common.h"
-#include "src/enc/backward_references_enc.h"
#include "src/enc/histogram_enc.h"
+#include "src/enc/vp8i_enc.h"
#include "src/utils/color_cache_utils.h"
#include "src/utils/utils.h"
+#include "src/webp/encode.h"
#define MIN_BLOCK_SIZE 256 // minimum block size for backward references
@@ -255,10 +258,13 @@ static WEBP_INLINE int MaxFindCopyLength(int len) {
int VP8LHashChainFill(VP8LHashChain* const p, int quality,
const uint32_t* const argb, int xsize, int ysize,
- int low_effort) {
+ int low_effort, const WebPPicture* const pic,
+ int percent_range, int* const percent) {
const int size = xsize * ysize;
const int iter_max = GetMaxItersForQuality(quality);
const uint32_t window_size = GetWindowSizeForHashChain(quality, xsize);
+ int remaining_percent = percent_range;
+ int percent_start = *percent;
int pos;
int argb_comp;
uint32_t base_position;
@@ -276,7 +282,13 @@ int VP8LHashChainFill(VP8LHashChain* const p, int quality,
hash_to_first_index =
(int32_t*)WebPSafeMalloc(HASH_SIZE, sizeof(*hash_to_first_index));
- if (hash_to_first_index == NULL) return 0;
+ if (hash_to_first_index == NULL) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ return 0;
+ }
+
+ percent_range = remaining_percent / 2;
+ remaining_percent -= percent_range;
// Set the int32_t array to -1.
memset(hash_to_first_index, 0xff, HASH_SIZE * sizeof(*hash_to_first_index));
@@ -323,12 +335,22 @@ int VP8LHashChainFill(VP8LHashChain* const p, int quality,
hash_to_first_index[hash_code] = pos++;
argb_comp = argb_comp_next;
}
+
+ if (!WebPReportProgress(
+ pic, percent_start + percent_range * pos / (size - 2), percent)) {
+ WebPSafeFree(hash_to_first_index);
+ return 0;
+ }
}
// Process the penultimate pixel.
chain[pos] = hash_to_first_index[GetPixPairHash64(argb + pos)];
WebPSafeFree(hash_to_first_index);
+ percent_start += percent_range;
+ if (!WebPReportProgress(pic, percent_start, percent)) return 0;
+ percent_range = remaining_percent;
+
// Find the best match interval at each pixel, defined by an offset to the
// pixel and a length. The right-most pixel cannot match anything to the right
// (hence a best length of 0) and the left-most pixel nothing to the left
@@ -417,8 +439,17 @@ int VP8LHashChainFill(VP8LHashChain* const p, int quality,
max_base_position = base_position;
}
}
+
+ if (!WebPReportProgress(pic,
+ percent_start + percent_range *
+ (size - 2 - base_position) /
+ (size - 2),
+ percent)) {
+ return 0;
+ }
}
- return 1;
+
+ return WebPReportProgress(pic, percent_start + percent_range, percent);
}
static WEBP_INLINE void AddSingleLiteral(uint32_t pixel, int use_color_cache,
@@ -728,7 +759,7 @@ static int CalculateBestCacheSize(const uint32_t* argb, int quality,
int* const best_cache_bits) {
int i;
const int cache_bits_max = (quality <= 25) ? 0 : *best_cache_bits;
- double entropy_min = MAX_ENTROPY;
+ float entropy_min = MAX_ENTROPY;
int cc_init[MAX_COLOR_CACHE_BITS + 1] = { 0 };
VP8LColorCache hashers[MAX_COLOR_CACHE_BITS + 1];
VP8LRefsCursor c = VP8LRefsCursorInit(refs);
@@ -813,14 +844,14 @@ static int CalculateBestCacheSize(const uint32_t* argb, int quality,
}
for (i = 0; i <= cache_bits_max; ++i) {
- const double entropy = VP8LHistogramEstimateBits(histos[i]);
+ const float entropy = VP8LHistogramEstimateBits(histos[i]);
if (i == 0 || entropy < entropy_min) {
entropy_min = entropy;
*best_cache_bits = i;
}
}
ok = 1;
-Error:
+ Error:
for (i = 0; i <= cache_bits_max; ++i) {
if (cc_init[i]) VP8LColorCacheClear(&hashers[i]);
VP8LFreeHistogram(histos[i]);
@@ -890,7 +921,7 @@ static int GetBackwardReferences(int width, int height,
int i, lz77_type;
// Index 0 is for a color cache, index 1 for no cache (if needed).
int lz77_types_best[2] = {0, 0};
- double bit_costs_best[2] = {DBL_MAX, DBL_MAX};
+ float bit_costs_best[2] = {FLT_MAX, FLT_MAX};
VP8LHashChain hash_chain_box;
VP8LBackwardRefs* const refs_tmp = &refs[do_no_cache ? 2 : 1];
int status = 0;
@@ -902,7 +933,7 @@ static int GetBackwardReferences(int width, int height,
for (lz77_type = 1; lz77_types_to_try;
lz77_types_to_try &= ~lz77_type, lz77_type <<= 1) {
int res = 0;
- double bit_cost = 0.;
+ float bit_cost = 0.f;
if ((lz77_types_to_try & lz77_type) == 0) continue;
switch (lz77_type) {
case kLZ77RLE:
@@ -976,15 +1007,16 @@ static int GetBackwardReferences(int width, int height,
const VP8LHashChain* const hash_chain_tmp =
(lz77_types_best[i] == kLZ77Standard) ? hash_chain : &hash_chain_box;
const int cache_bits = (i == 1) ? 0 : *cache_bits_best;
- if (VP8LBackwardReferencesTraceBackwards(width, height, argb, cache_bits,
- hash_chain_tmp, &refs[i],
- refs_tmp)) {
- double bit_cost_trace;
- VP8LHistogramCreate(histo, refs_tmp, cache_bits);
- bit_cost_trace = VP8LHistogramEstimateBits(histo);
- if (bit_cost_trace < bit_costs_best[i]) {
- BackwardRefsSwap(refs_tmp, &refs[i]);
- }
+ float bit_cost_trace;
+ if (!VP8LBackwardReferencesTraceBackwards(width, height, argb, cache_bits,
+ hash_chain_tmp, &refs[i],
+ refs_tmp)) {
+ goto Error;
+ }
+ VP8LHistogramCreate(histo, refs_tmp, cache_bits);
+ bit_cost_trace = VP8LHistogramEstimateBits(histo);
+ if (bit_cost_trace < bit_costs_best[i]) {
+ BackwardRefsSwap(refs_tmp, &refs[i]);
}
}
@@ -1000,31 +1032,37 @@ static int GetBackwardReferences(int width, int height,
}
status = 1;
-Error:
+ Error:
VP8LHashChainClear(&hash_chain_box);
VP8LFreeHistogram(histo);
return status;
}
-WebPEncodingError VP8LGetBackwardReferences(
+int VP8LGetBackwardReferences(
int width, int height, const uint32_t* const argb, int quality,
int low_effort, int lz77_types_to_try, int cache_bits_max, int do_no_cache,
const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs,
- int* const cache_bits_best) {
+ int* const cache_bits_best, const WebPPicture* const pic, int percent_range,
+ int* const percent) {
if (low_effort) {
VP8LBackwardRefs* refs_best;
*cache_bits_best = cache_bits_max;
refs_best = GetBackwardReferencesLowEffort(
width, height, argb, cache_bits_best, hash_chain, refs);
- if (refs_best == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
+ if (refs_best == NULL) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ return 0;
+ }
// Set it in first position.
BackwardRefsSwap(refs_best, &refs[0]);
} else {
if (!GetBackwardReferences(width, height, argb, quality, lz77_types_to_try,
cache_bits_max, do_no_cache, hash_chain, refs,
cache_bits_best)) {
- return VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ return 0;
}
}
- return VP8_ENC_OK;
+
+ return WebPReportProgress(pic, *percent + percent_range, percent);
}
diff --git a/thirdparty/libwebp/src/enc/backward_references_enc.h b/thirdparty/libwebp/src/enc/backward_references_enc.h
index 4c0267b41e..4dff1c27b5 100644
--- a/thirdparty/libwebp/src/enc/backward_references_enc.h
+++ b/thirdparty/libwebp/src/enc/backward_references_enc.h
@@ -134,10 +134,11 @@ struct VP8LHashChain {
// Must be called first, to set size.
int VP8LHashChainInit(VP8LHashChain* const p, int size);
-// Pre-compute the best matches for argb.
+// Pre-compute the best matches for argb. pic and percent are for progress.
int VP8LHashChainFill(VP8LHashChain* const p, int quality,
const uint32_t* const argb, int xsize, int ysize,
- int low_effort);
+ int low_effort, const WebPPicture* const pic,
+ int percent_range, int* const percent);
void VP8LHashChainClear(VP8LHashChain* const p); // release memory
static WEBP_INLINE int VP8LHashChainFindOffset(const VP8LHashChain* const p,
@@ -227,11 +228,14 @@ enum VP8LLZ77Type {
// VP8LBackwardRefs is put in the first element, the best value with no-cache in
// the second element.
// In both cases, the last element is used as temporary internally.
-WebPEncodingError VP8LGetBackwardReferences(
+// pic and percent are for progress.
+// Returns false in case of error (stored in pic->error_code).
+int VP8LGetBackwardReferences(
int width, int height, const uint32_t* const argb, int quality,
int low_effort, int lz77_types_to_try, int cache_bits_max, int do_no_cache,
const VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs,
- int* const cache_bits_best);
+ int* const cache_bits_best, const WebPPicture* const pic, int percent_range,
+ int* const percent);
#ifdef __cplusplus
}
diff --git a/thirdparty/libwebp/src/enc/histogram_enc.c b/thirdparty/libwebp/src/enc/histogram_enc.c
index 38a0cebcab..8418def2e1 100644
--- a/thirdparty/libwebp/src/enc/histogram_enc.c
+++ b/thirdparty/libwebp/src/enc/histogram_enc.c
@@ -13,15 +13,17 @@
#include "src/webp/config.h"
#endif
+#include <float.h>
#include <math.h>
-#include "src/enc/backward_references_enc.h"
-#include "src/enc/histogram_enc.h"
#include "src/dsp/lossless.h"
#include "src/dsp/lossless_common.h"
+#include "src/enc/backward_references_enc.h"
+#include "src/enc/histogram_enc.h"
+#include "src/enc/vp8i_enc.h"
#include "src/utils/utils.h"
-#define MAX_COST 1.e38
+#define MAX_BIT_COST FLT_MAX
// Number of partitions for the three dominant (literal, red and blue) symbol
// costs.
@@ -228,8 +230,8 @@ void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
// -----------------------------------------------------------------------------
// Entropy-related functions.
-static WEBP_INLINE double BitsEntropyRefine(const VP8LBitEntropy* entropy) {
- double mix;
+static WEBP_INLINE float BitsEntropyRefine(const VP8LBitEntropy* entropy) {
+ float mix;
if (entropy->nonzeros < 5) {
if (entropy->nonzeros <= 1) {
return 0;
@@ -238,67 +240,67 @@ static WEBP_INLINE double BitsEntropyRefine(const VP8LBitEntropy* entropy) {
// Let's mix in a bit of entropy to favor good clustering when
// distributions of these are combined.
if (entropy->nonzeros == 2) {
- return 0.99 * entropy->sum + 0.01 * entropy->entropy;
+ return 0.99f * entropy->sum + 0.01f * entropy->entropy;
}
// No matter what the entropy says, we cannot be better than min_limit
// with Huffman coding. I am mixing a bit of entropy into the
// min_limit since it produces much better (~0.5 %) compression results
// perhaps because of better entropy clustering.
if (entropy->nonzeros == 3) {
- mix = 0.95;
+ mix = 0.95f;
} else {
- mix = 0.7; // nonzeros == 4.
+ mix = 0.7f; // nonzeros == 4.
}
} else {
- mix = 0.627;
+ mix = 0.627f;
}
{
- double min_limit = 2 * entropy->sum - entropy->max_val;
- min_limit = mix * min_limit + (1.0 - mix) * entropy->entropy;
+ float min_limit = 2.f * entropy->sum - entropy->max_val;
+ min_limit = mix * min_limit + (1.f - mix) * entropy->entropy;
return (entropy->entropy < min_limit) ? min_limit : entropy->entropy;
}
}
-double VP8LBitsEntropy(const uint32_t* const array, int n) {
+float VP8LBitsEntropy(const uint32_t* const array, int n) {
VP8LBitEntropy entropy;
VP8LBitsEntropyUnrefined(array, n, &entropy);
return BitsEntropyRefine(&entropy);
}
-static double InitialHuffmanCost(void) {
+static float InitialHuffmanCost(void) {
// Small bias because Huffman code length is typically not stored in
// full length.
static const int kHuffmanCodeOfHuffmanCodeSize = CODE_LENGTH_CODES * 3;
- static const double kSmallBias = 9.1;
+ static const float kSmallBias = 9.1f;
return kHuffmanCodeOfHuffmanCodeSize - kSmallBias;
}
// Finalize the Huffman cost based on streak numbers and length type (<3 or >=3)
-static double FinalHuffmanCost(const VP8LStreaks* const stats) {
+static float FinalHuffmanCost(const VP8LStreaks* const stats) {
// The constants in this function are experimental and got rounded from
// their original values in 1/8 when switched to 1/1024.
- double retval = InitialHuffmanCost();
+ float retval = InitialHuffmanCost();
// Second coefficient: Many zeros in the histogram are covered efficiently
// by a run-length encode. Originally 2/8.
- retval += stats->counts[0] * 1.5625 + 0.234375 * stats->streaks[0][1];
+ retval += stats->counts[0] * 1.5625f + 0.234375f * stats->streaks[0][1];
// Second coefficient: Constant values are encoded less efficiently, but still
// RLE'ed. Originally 6/8.
- retval += stats->counts[1] * 2.578125 + 0.703125 * stats->streaks[1][1];
+ retval += stats->counts[1] * 2.578125f + 0.703125f * stats->streaks[1][1];
// 0s are usually encoded more efficiently than non-0s.
// Originally 15/8.
- retval += 1.796875 * stats->streaks[0][0];
+ retval += 1.796875f * stats->streaks[0][0];
// Originally 26/8.
- retval += 3.28125 * stats->streaks[1][0];
+ retval += 3.28125f * stats->streaks[1][0];
return retval;
}
// Get the symbol entropy for the distribution 'population'.
// Set 'trivial_sym', if there's only one symbol present in the distribution.
-static double PopulationCost(const uint32_t* const population, int length,
- uint32_t* const trivial_sym,
- uint8_t* const is_used) {
+static float PopulationCost(const uint32_t* const population, int length,
+ uint32_t* const trivial_sym,
+ uint8_t* const is_used) {
VP8LBitEntropy bit_entropy;
VP8LStreaks stats;
VP8LGetEntropyUnrefined(population, length, &bit_entropy, &stats);
@@ -314,11 +316,10 @@ static double PopulationCost(const uint32_t* const population, int length,
// trivial_at_end is 1 if the two histograms only have one element that is
// non-zero: both the zero-th one, or both the last one.
-static WEBP_INLINE double GetCombinedEntropy(const uint32_t* const X,
- const uint32_t* const Y,
- int length, int is_X_used,
- int is_Y_used,
- int trivial_at_end) {
+static WEBP_INLINE float GetCombinedEntropy(const uint32_t* const X,
+ const uint32_t* const Y, int length,
+ int is_X_used, int is_Y_used,
+ int trivial_at_end) {
VP8LStreaks stats;
if (trivial_at_end) {
// This configuration is due to palettization that transforms an indexed
@@ -356,7 +357,7 @@ static WEBP_INLINE double GetCombinedEntropy(const uint32_t* const X,
}
// Estimates the Entropy + Huffman + other block overhead size cost.
-double VP8LHistogramEstimateBits(VP8LHistogram* const p) {
+float VP8LHistogramEstimateBits(VP8LHistogram* const p) {
return
PopulationCost(p->literal_, VP8LHistogramNumCodes(p->palette_code_bits_),
NULL, &p->is_used_[0])
@@ -373,8 +374,7 @@ double VP8LHistogramEstimateBits(VP8LHistogram* const p) {
static int GetCombinedHistogramEntropy(const VP8LHistogram* const a,
const VP8LHistogram* const b,
- double cost_threshold,
- double* cost) {
+ float cost_threshold, float* cost) {
const int palette_code_bits = a->palette_code_bits_;
int trivial_at_end = 0;
assert(a->palette_code_bits_ == b->palette_code_bits_);
@@ -439,12 +439,11 @@ static WEBP_INLINE void HistogramAdd(const VP8LHistogram* const a,
// Since the previous score passed is 'cost_threshold', we only need to compare
// the partial cost against 'cost_threshold + C(a) + C(b)' to possibly bail-out
// early.
-static double HistogramAddEval(const VP8LHistogram* const a,
- const VP8LHistogram* const b,
- VP8LHistogram* const out,
- double cost_threshold) {
- double cost = 0;
- const double sum_cost = a->bit_cost_ + b->bit_cost_;
+static float HistogramAddEval(const VP8LHistogram* const a,
+ const VP8LHistogram* const b,
+ VP8LHistogram* const out, float cost_threshold) {
+ float cost = 0;
+ const float sum_cost = a->bit_cost_ + b->bit_cost_;
cost_threshold += sum_cost;
if (GetCombinedHistogramEntropy(a, b, cost_threshold, &cost)) {
@@ -459,10 +458,10 @@ static double HistogramAddEval(const VP8LHistogram* const a,
// Same as HistogramAddEval(), except that the resulting histogram
// is not stored. Only the cost C(a+b) - C(a) is evaluated. We omit
// the term C(b) which is constant over all the evaluations.
-static double HistogramAddThresh(const VP8LHistogram* const a,
- const VP8LHistogram* const b,
- double cost_threshold) {
- double cost;
+static float HistogramAddThresh(const VP8LHistogram* const a,
+ const VP8LHistogram* const b,
+ float cost_threshold) {
+ float cost;
assert(a != NULL && b != NULL);
cost = -a->bit_cost_;
GetCombinedHistogramEntropy(a, b, cost_threshold, &cost);
@@ -473,24 +472,22 @@ static double HistogramAddThresh(const VP8LHistogram* const a,
// The structure to keep track of cost range for the three dominant entropy
// symbols.
-// TODO(skal): Evaluate if float can be used here instead of double for
-// representing the entropy costs.
typedef struct {
- double literal_max_;
- double literal_min_;
- double red_max_;
- double red_min_;
- double blue_max_;
- double blue_min_;
+ float literal_max_;
+ float literal_min_;
+ float red_max_;
+ float red_min_;
+ float blue_max_;
+ float blue_min_;
} DominantCostRange;
static void DominantCostRangeInit(DominantCostRange* const c) {
c->literal_max_ = 0.;
- c->literal_min_ = MAX_COST;
+ c->literal_min_ = MAX_BIT_COST;
c->red_max_ = 0.;
- c->red_min_ = MAX_COST;
+ c->red_min_ = MAX_BIT_COST;
c->blue_max_ = 0.;
- c->blue_min_ = MAX_COST;
+ c->blue_min_ = MAX_BIT_COST;
}
static void UpdateDominantCostRange(
@@ -505,10 +502,9 @@ static void UpdateDominantCostRange(
static void UpdateHistogramCost(VP8LHistogram* const h) {
uint32_t alpha_sym, red_sym, blue_sym;
- const double alpha_cost =
- PopulationCost(h->alpha_, NUM_LITERAL_CODES, &alpha_sym,
- &h->is_used_[3]);
- const double distance_cost =
+ const float alpha_cost =
+ PopulationCost(h->alpha_, NUM_LITERAL_CODES, &alpha_sym, &h->is_used_[3]);
+ const float distance_cost =
PopulationCost(h->distance_, NUM_DISTANCE_CODES, NULL, &h->is_used_[4]) +
VP8LExtraCost(h->distance_, NUM_DISTANCE_CODES);
const int num_codes = VP8LHistogramNumCodes(h->palette_code_bits_);
@@ -529,10 +525,10 @@ static void UpdateHistogramCost(VP8LHistogram* const h) {
}
}
-static int GetBinIdForEntropy(double min, double max, double val) {
- const double range = max - min;
+static int GetBinIdForEntropy(float min, float max, float val) {
+ const float range = max - min;
if (range > 0.) {
- const double delta = val - min;
+ const float delta = val - min;
return (int)((NUM_PARTITIONS - 1e-6) * delta / range);
} else {
return 0;
@@ -641,15 +637,11 @@ static void HistogramAnalyzeEntropyBin(VP8LHistogramSet* const image_histo,
// Merges some histograms with same bin_id together if it's advantageous.
// Sets the remaining histograms to NULL.
-static void HistogramCombineEntropyBin(VP8LHistogramSet* const image_histo,
- int* num_used,
- const uint16_t* const clusters,
- uint16_t* const cluster_mappings,
- VP8LHistogram* cur_combo,
- const uint16_t* const bin_map,
- int num_bins,
- double combine_cost_factor,
- int low_effort) {
+static void HistogramCombineEntropyBin(
+ VP8LHistogramSet* const image_histo, int* num_used,
+ const uint16_t* const clusters, uint16_t* const cluster_mappings,
+ VP8LHistogram* cur_combo, const uint16_t* const bin_map, int num_bins,
+ float combine_cost_factor, int low_effort) {
VP8LHistogram** const histograms = image_histo->histograms;
int idx;
struct {
@@ -679,11 +671,10 @@ static void HistogramCombineEntropyBin(VP8LHistogramSet* const image_histo,
cluster_mappings[clusters[idx]] = clusters[first];
} else {
// try to merge #idx into #first (both share the same bin_id)
- const double bit_cost = histograms[idx]->bit_cost_;
- const double bit_cost_thresh = -bit_cost * combine_cost_factor;
- const double curr_cost_diff =
- HistogramAddEval(histograms[first], histograms[idx],
- cur_combo, bit_cost_thresh);
+ const float bit_cost = histograms[idx]->bit_cost_;
+ const float bit_cost_thresh = -bit_cost * combine_cost_factor;
+ const float curr_cost_diff = HistogramAddEval(
+ histograms[first], histograms[idx], cur_combo, bit_cost_thresh);
if (curr_cost_diff < bit_cost_thresh) {
// Try to merge two histograms only if the combo is a trivial one or
// the two candidate histograms are already non-trivial.
@@ -731,8 +722,8 @@ static uint32_t MyRand(uint32_t* const seed) {
typedef struct {
int idx1;
int idx2;
- double cost_diff;
- double cost_combo;
+ float cost_diff;
+ float cost_combo;
} HistogramPair;
typedef struct {
@@ -787,10 +778,9 @@ static void HistoQueueUpdateHead(HistoQueue* const histo_queue,
// Update the cost diff and combo of a pair of histograms. This needs to be
// called when the the histograms have been merged with a third one.
static void HistoQueueUpdatePair(const VP8LHistogram* const h1,
- const VP8LHistogram* const h2,
- double threshold,
+ const VP8LHistogram* const h2, float threshold,
HistogramPair* const pair) {
- const double sum_cost = h1->bit_cost_ + h2->bit_cost_;
+ const float sum_cost = h1->bit_cost_ + h2->bit_cost_;
pair->cost_combo = 0.;
GetCombinedHistogramEntropy(h1, h2, sum_cost + threshold, &pair->cost_combo);
pair->cost_diff = pair->cost_combo - sum_cost;
@@ -799,9 +789,9 @@ static void HistoQueueUpdatePair(const VP8LHistogram* const h1,
// Create a pair from indices "idx1" and "idx2" provided its cost
// is inferior to "threshold", a negative entropy.
// It returns the cost of the pair, or 0. if it superior to threshold.
-static double HistoQueuePush(HistoQueue* const histo_queue,
- VP8LHistogram** const histograms, int idx1,
- int idx2, double threshold) {
+static float HistoQueuePush(HistoQueue* const histo_queue,
+ VP8LHistogram** const histograms, int idx1,
+ int idx2, float threshold) {
const VP8LHistogram* h1;
const VP8LHistogram* h2;
HistogramPair pair;
@@ -945,8 +935,8 @@ static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
++tries_with_no_success < num_tries_no_success;
++iter) {
int* mapping_index;
- double best_cost =
- (histo_queue.size == 0) ? 0. : histo_queue.queue[0].cost_diff;
+ float best_cost =
+ (histo_queue.size == 0) ? 0.f : histo_queue.queue[0].cost_diff;
int best_idx1 = -1, best_idx2 = 1;
const uint32_t rand_range = (*num_used - 1) * (*num_used);
// (*num_used) / 2 was chosen empirically. Less means faster but worse
@@ -955,7 +945,7 @@ static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
// Pick random samples.
for (j = 0; *num_used >= 2 && j < num_tries; ++j) {
- double curr_cost;
+ float curr_cost;
// Choose two different histograms at random and try to combine them.
const uint32_t tmp = MyRand(&seed) % rand_range;
uint32_t idx1 = tmp / (*num_used - 1);
@@ -1034,7 +1024,7 @@ static int HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
*do_greedy = (*num_used <= min_cluster_size);
ok = 1;
-End:
+ End:
HistoQueueClear(&histo_queue);
WebPSafeFree(mappings);
return ok;
@@ -1057,7 +1047,7 @@ static void HistogramRemap(const VP8LHistogramSet* const in,
if (out_size > 1) {
for (i = 0; i < in_size; ++i) {
int best_out = 0;
- double best_bits = MAX_COST;
+ float best_bits = MAX_BIT_COST;
int k;
if (in_histo[i] == NULL) {
// Arbitrarily set to the previous value if unused to help future LZ77.
@@ -1065,7 +1055,7 @@ static void HistogramRemap(const VP8LHistogramSet* const in,
continue;
}
for (k = 0; k < out_size; ++k) {
- double cur_bits;
+ float cur_bits;
cur_bits = HistogramAddThresh(out_histo[k], in_histo[i], best_bits);
if (k == 0 || cur_bits < best_bits) {
best_bits = cur_bits;
@@ -1093,13 +1083,13 @@ static void HistogramRemap(const VP8LHistogramSet* const in,
}
}
-static double GetCombineCostFactor(int histo_size, int quality) {
- double combine_cost_factor = 0.16;
+static float GetCombineCostFactor(int histo_size, int quality) {
+ float combine_cost_factor = 0.16f;
if (quality < 90) {
- if (histo_size > 256) combine_cost_factor /= 2.;
- if (histo_size > 512) combine_cost_factor /= 2.;
- if (histo_size > 1024) combine_cost_factor /= 2.;
- if (quality <= 50) combine_cost_factor /= 2.;
+ if (histo_size > 256) combine_cost_factor /= 2.f;
+ if (histo_size > 512) combine_cost_factor /= 2.f;
+ if (histo_size > 1024) combine_cost_factor /= 2.f;
+ if (quality <= 50) combine_cost_factor /= 2.f;
}
return combine_cost_factor;
}
@@ -1169,13 +1159,13 @@ static void RemoveEmptyHistograms(VP8LHistogramSet* const image_histo) {
}
int VP8LGetHistoImageSymbols(int xsize, int ysize,
- const VP8LBackwardRefs* const refs,
- int quality, int low_effort,
- int histogram_bits, int cache_bits,
+ const VP8LBackwardRefs* const refs, int quality,
+ int low_effort, int histogram_bits, int cache_bits,
VP8LHistogramSet* const image_histo,
VP8LHistogram* const tmp_histo,
- uint16_t* const histogram_symbols) {
- int ok = 0;
+ uint16_t* const histogram_symbols,
+ const WebPPicture* const pic, int percent_range,
+ int* const percent) {
const int histo_xsize =
histogram_bits ? VP8LSubSampleSize(xsize, histogram_bits) : 1;
const int histo_ysize =
@@ -1192,7 +1182,10 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
WebPSafeMalloc(2 * image_histo_raw_size, sizeof(map_tmp));
uint16_t* const cluster_mappings = map_tmp + image_histo_raw_size;
int num_used = image_histo_raw_size;
- if (orig_histo == NULL || map_tmp == NULL) goto Error;
+ if (orig_histo == NULL || map_tmp == NULL) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ goto Error;
+ }
// Construct the histograms from backward references.
HistogramBuild(xsize, histogram_bits, refs, orig_histo);
@@ -1206,16 +1199,15 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
if (entropy_combine) {
uint16_t* const bin_map = map_tmp;
- const double combine_cost_factor =
+ const float combine_cost_factor =
GetCombineCostFactor(image_histo_raw_size, quality);
const uint32_t num_clusters = num_used;
HistogramAnalyzeEntropyBin(image_histo, bin_map, low_effort);
// Collapse histograms with similar entropy.
- HistogramCombineEntropyBin(image_histo, &num_used, histogram_symbols,
- cluster_mappings, tmp_histo, bin_map,
- entropy_combine_num_bins, combine_cost_factor,
- low_effort);
+ HistogramCombineEntropyBin(
+ image_histo, &num_used, histogram_symbols, cluster_mappings, tmp_histo,
+ bin_map, entropy_combine_num_bins, combine_cost_factor, low_effort);
OptimizeHistogramSymbols(image_histo, cluster_mappings, num_clusters,
map_tmp, histogram_symbols);
}
@@ -1229,11 +1221,13 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
int do_greedy;
if (!HistogramCombineStochastic(image_histo, &num_used, threshold_size,
&do_greedy)) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
if (do_greedy) {
RemoveEmptyHistograms(image_histo);
if (!HistogramCombineGreedy(image_histo, &num_used)) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
}
@@ -1243,10 +1237,12 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
RemoveEmptyHistograms(image_histo);
HistogramRemap(orig_histo, image_histo, histogram_symbols);
- ok = 1;
+ if (!WebPReportProgress(pic, *percent + percent_range, percent)) {
+ goto Error;
+ }
Error:
VP8LFreeHistogramSet(orig_histo);
WebPSafeFree(map_tmp);
- return ok;
+ return (pic->error_code == VP8_ENC_OK);
}
diff --git a/thirdparty/libwebp/src/enc/histogram_enc.h b/thirdparty/libwebp/src/enc/histogram_enc.h
index c3428b5d55..4c0bb97464 100644
--- a/thirdparty/libwebp/src/enc/histogram_enc.h
+++ b/thirdparty/libwebp/src/enc/histogram_enc.h
@@ -40,10 +40,10 @@ typedef struct {
int palette_code_bits_;
uint32_t trivial_symbol_; // True, if histograms for Red, Blue & Alpha
// literal symbols are single valued.
- double bit_cost_; // cached value of bit cost.
- double literal_cost_; // Cached values of dominant entropy costs:
- double red_cost_; // literal, red & blue.
- double blue_cost_;
+ float bit_cost_; // cached value of bit cost.
+ float literal_cost_; // Cached values of dominant entropy costs:
+ float red_cost_; // literal, red & blue.
+ float blue_cost_;
uint8_t is_used_[5]; // 5 for literal, red, blue, alpha, distance
} VP8LHistogram;
@@ -105,21 +105,23 @@ static WEBP_INLINE int VP8LHistogramNumCodes(int palette_code_bits) {
((palette_code_bits > 0) ? (1 << palette_code_bits) : 0);
}
-// Builds the histogram image.
+// Builds the histogram image. pic and percent are for progress.
+// Returns false in case of error (stored in pic->error_code).
int VP8LGetHistoImageSymbols(int xsize, int ysize,
- const VP8LBackwardRefs* const refs,
- int quality, int low_effort,
- int histogram_bits, int cache_bits,
+ const VP8LBackwardRefs* const refs, int quality,
+ int low_effort, int histogram_bits, int cache_bits,
VP8LHistogramSet* const image_histo,
VP8LHistogram* const tmp_histo,
- uint16_t* const histogram_symbols);
+ uint16_t* const histogram_symbols,
+ const WebPPicture* const pic, int percent_range,
+ int* const percent);
// Returns the entropy for the symbols in the input array.
-double VP8LBitsEntropy(const uint32_t* const array, int n);
+float VP8LBitsEntropy(const uint32_t* const array, int n);
// Estimate how many bits the combined entropy of literals and distance
// approximately maps to.
-double VP8LHistogramEstimateBits(VP8LHistogram* const p);
+float VP8LHistogramEstimateBits(VP8LHistogram* const p);
#ifdef __cplusplus
}
diff --git a/thirdparty/libwebp/src/enc/picture_csp_enc.c b/thirdparty/libwebp/src/enc/picture_csp_enc.c
index 35eede9635..fabebcf202 100644
--- a/thirdparty/libwebp/src/enc/picture_csp_enc.c
+++ b/thirdparty/libwebp/src/enc/picture_csp_enc.c
@@ -15,12 +15,19 @@
#include <stdlib.h>
#include <math.h>
+#include "sharpyuv/sharpyuv.h"
+#include "sharpyuv/sharpyuv_csp.h"
#include "src/enc/vp8i_enc.h"
#include "src/utils/random_utils.h"
#include "src/utils/utils.h"
#include "src/dsp/dsp.h"
#include "src/dsp/lossless.h"
#include "src/dsp/yuv.h"
+#include "src/dsp/cpu.h"
+
+#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
+#include <pthread.h>
+#endif
// Uncomment to disable gamma-compression during RGB->U/V averaging
#define USE_GAMMA_COMPRESSION
@@ -76,16 +83,16 @@ int WebPPictureHasTransparency(const WebPPicture* picture) {
#if defined(USE_GAMMA_COMPRESSION)
-// gamma-compensates loss of resolution during chroma subsampling
-#define kGamma 0.80 // for now we use a different gamma value than kGammaF
-#define kGammaFix 12 // fixed-point precision for linear values
-#define kGammaScale ((1 << kGammaFix) - 1)
-#define kGammaTabFix 7 // fixed-point fractional bits precision
-#define kGammaTabScale (1 << kGammaTabFix)
-#define kGammaTabRounder (kGammaTabScale >> 1)
-#define kGammaTabSize (1 << (kGammaFix - kGammaTabFix))
+// Gamma correction compensates loss of resolution during chroma subsampling.
+#define GAMMA_FIX 12 // fixed-point precision for linear values
+#define GAMMA_TAB_FIX 7 // fixed-point fractional bits precision
+#define GAMMA_TAB_SIZE (1 << (GAMMA_FIX - GAMMA_TAB_FIX))
+static const double kGamma = 0.80;
+static const int kGammaScale = ((1 << GAMMA_FIX) - 1);
+static const int kGammaTabScale = (1 << GAMMA_TAB_FIX);
+static const int kGammaTabRounder = (1 << GAMMA_TAB_FIX >> 1);
-static int kLinearToGammaTab[kGammaTabSize + 1];
+static int kLinearToGammaTab[GAMMA_TAB_SIZE + 1];
static uint16_t kGammaToLinearTab[256];
static volatile int kGammaTablesOk = 0;
static void InitGammaTables(void);
@@ -93,13 +100,13 @@ static void InitGammaTables(void);
WEBP_DSP_INIT_FUNC(InitGammaTables) {
if (!kGammaTablesOk) {
int v;
- const double scale = (double)(1 << kGammaTabFix) / kGammaScale;
+ const double scale = (double)(1 << GAMMA_TAB_FIX) / kGammaScale;
const double norm = 1. / 255.;
for (v = 0; v <= 255; ++v) {
kGammaToLinearTab[v] =
(uint16_t)(pow(norm * v, kGamma) * kGammaScale + .5);
}
- for (v = 0; v <= kGammaTabSize; ++v) {
+ for (v = 0; v <= GAMMA_TAB_SIZE; ++v) {
kLinearToGammaTab[v] = (int)(255. * pow(scale * v, 1. / kGamma) + .5);
}
kGammaTablesOk = 1;
@@ -111,12 +118,12 @@ static WEBP_INLINE uint32_t GammaToLinear(uint8_t v) {
}
static WEBP_INLINE int Interpolate(int v) {
- const int tab_pos = v >> (kGammaTabFix + 2); // integer part
+ const int tab_pos = v >> (GAMMA_TAB_FIX + 2); // integer part
const int x = v & ((kGammaTabScale << 2) - 1); // fractional part
const int v0 = kLinearToGammaTab[tab_pos];
const int v1 = kLinearToGammaTab[tab_pos + 1];
const int y = v1 * x + v0 * ((kGammaTabScale << 2) - x); // interpolate
- assert(tab_pos + 1 < kGammaTabSize + 1);
+ assert(tab_pos + 1 < GAMMA_TAB_SIZE + 1);
return y;
}
@@ -124,7 +131,7 @@ static WEBP_INLINE int Interpolate(int v) {
// U/V value, suitable for RGBToU/V calls.
static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) {
const int y = Interpolate(base_value << shift); // final uplifted value
- return (y + kGammaTabRounder) >> kGammaTabFix; // descale
+ return (y + kGammaTabRounder) >> GAMMA_TAB_FIX; // descale
}
#else
@@ -158,415 +165,41 @@ static int RGBToV(int r, int g, int b, VP8Random* const rg) {
//------------------------------------------------------------------------------
// Sharp RGB->YUV conversion
-static const int kNumIterations = 4;
static const int kMinDimensionIterativeConversion = 4;
-// We could use SFIX=0 and only uint8_t for fixed_y_t, but it produces some
-// banding sometimes. Better use extra precision.
-#define SFIX 2 // fixed-point precision of RGB and Y/W
-typedef int16_t fixed_t; // signed type with extra SFIX precision for UV
-typedef uint16_t fixed_y_t; // unsigned type with extra SFIX precision for W
-
-#define SHALF (1 << SFIX >> 1)
-#define MAX_Y_T ((256 << SFIX) - 1)
-#define SROUNDER (1 << (YUV_FIX + SFIX - 1))
-
-#if defined(USE_GAMMA_COMPRESSION)
-
-// We use tables of different size and precision for the Rec709 / BT2020
-// transfer function.
-#define kGammaF (1./0.45)
-static uint32_t kLinearToGammaTabS[kGammaTabSize + 2];
-#define GAMMA_TO_LINEAR_BITS 14
-static uint32_t kGammaToLinearTabS[MAX_Y_T + 1]; // size scales with Y_FIX
-static volatile int kGammaTablesSOk = 0;
-static void InitGammaTablesS(void);
-
-WEBP_DSP_INIT_FUNC(InitGammaTablesS) {
- assert(2 * GAMMA_TO_LINEAR_BITS < 32); // we use uint32_t intermediate values
- if (!kGammaTablesSOk) {
- int v;
- const double norm = 1. / MAX_Y_T;
- const double scale = 1. / kGammaTabSize;
- const double a = 0.09929682680944;
- const double thresh = 0.018053968510807;
- const double final_scale = 1 << GAMMA_TO_LINEAR_BITS;
- for (v = 0; v <= MAX_Y_T; ++v) {
- const double g = norm * v;
- double value;
- if (g <= thresh * 4.5) {
- value = g / 4.5;
- } else {
- const double a_rec = 1. / (1. + a);
- value = pow(a_rec * (g + a), kGammaF);
- }
- kGammaToLinearTabS[v] = (uint32_t)(value * final_scale + .5);
- }
- for (v = 0; v <= kGammaTabSize; ++v) {
- const double g = scale * v;
- double value;
- if (g <= thresh) {
- value = 4.5 * g;
- } else {
- value = (1. + a) * pow(g, 1. / kGammaF) - a;
- }
- // we already incorporate the 1/2 rounding constant here
- kLinearToGammaTabS[v] =
- (uint32_t)(MAX_Y_T * value) + (1 << GAMMA_TO_LINEAR_BITS >> 1);
- }
- // to prevent small rounding errors to cause read-overflow:
- kLinearToGammaTabS[kGammaTabSize + 1] = kLinearToGammaTabS[kGammaTabSize];
- kGammaTablesSOk = 1;
- }
-}
-
-// return value has a fixed-point precision of GAMMA_TO_LINEAR_BITS
-static WEBP_INLINE uint32_t GammaToLinearS(int v) {
- return kGammaToLinearTabS[v];
-}
-
-static WEBP_INLINE uint32_t LinearToGammaS(uint32_t value) {
- // 'value' is in GAMMA_TO_LINEAR_BITS fractional precision
- const uint32_t v = value * kGammaTabSize;
- const uint32_t tab_pos = v >> GAMMA_TO_LINEAR_BITS;
- // fractional part, in GAMMA_TO_LINEAR_BITS fixed-point precision
- const uint32_t x = v - (tab_pos << GAMMA_TO_LINEAR_BITS); // fractional part
- // v0 / v1 are in GAMMA_TO_LINEAR_BITS fixed-point precision (range [0..1])
- const uint32_t v0 = kLinearToGammaTabS[tab_pos + 0];
- const uint32_t v1 = kLinearToGammaTabS[tab_pos + 1];
- // Final interpolation. Note that rounding is already included.
- const uint32_t v2 = (v1 - v0) * x; // note: v1 >= v0.
- const uint32_t result = v0 + (v2 >> GAMMA_TO_LINEAR_BITS);
- return result;
-}
-
-#else
-
-static void InitGammaTablesS(void) {}
-static WEBP_INLINE uint32_t GammaToLinearS(int v) {
- return (v << GAMMA_TO_LINEAR_BITS) / MAX_Y_T;
-}
-static WEBP_INLINE uint32_t LinearToGammaS(uint32_t value) {
- return (MAX_Y_T * value) >> GAMMA_TO_LINEAR_BITS;
-}
-
-#endif // USE_GAMMA_COMPRESSION
-
-//------------------------------------------------------------------------------
-
-static uint8_t clip_8b(fixed_t v) {
- return (!(v & ~0xff)) ? (uint8_t)v : (v < 0) ? 0u : 255u;
-}
-
-static fixed_y_t clip_y(int y) {
- return (!(y & ~MAX_Y_T)) ? (fixed_y_t)y : (y < 0) ? 0 : MAX_Y_T;
-}
-
-//------------------------------------------------------------------------------
-
-static int RGBToGray(int r, int g, int b) {
- const int luma = 13933 * r + 46871 * g + 4732 * b + YUV_HALF;
- return (luma >> YUV_FIX);
-}
-
-static uint32_t ScaleDown(int a, int b, int c, int d) {
- const uint32_t A = GammaToLinearS(a);
- const uint32_t B = GammaToLinearS(b);
- const uint32_t C = GammaToLinearS(c);
- const uint32_t D = GammaToLinearS(d);
- return LinearToGammaS((A + B + C + D + 2) >> 2);
-}
-
-static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int w) {
- int i;
- for (i = 0; i < w; ++i) {
- const uint32_t R = GammaToLinearS(src[0 * w + i]);
- const uint32_t G = GammaToLinearS(src[1 * w + i]);
- const uint32_t B = GammaToLinearS(src[2 * w + i]);
- const uint32_t Y = RGBToGray(R, G, B);
- dst[i] = (fixed_y_t)LinearToGammaS(Y);
- }
-}
-
-static void UpdateChroma(const fixed_y_t* src1, const fixed_y_t* src2,
- fixed_t* dst, int uv_w) {
- int i;
- for (i = 0; i < uv_w; ++i) {
- const int r = ScaleDown(src1[0 * uv_w + 0], src1[0 * uv_w + 1],
- src2[0 * uv_w + 0], src2[0 * uv_w + 1]);
- const int g = ScaleDown(src1[2 * uv_w + 0], src1[2 * uv_w + 1],
- src2[2 * uv_w + 0], src2[2 * uv_w + 1]);
- const int b = ScaleDown(src1[4 * uv_w + 0], src1[4 * uv_w + 1],
- src2[4 * uv_w + 0], src2[4 * uv_w + 1]);
- const int W = RGBToGray(r, g, b);
- dst[0 * uv_w] = (fixed_t)(r - W);
- dst[1 * uv_w] = (fixed_t)(g - W);
- dst[2 * uv_w] = (fixed_t)(b - W);
- dst += 1;
- src1 += 2;
- src2 += 2;
- }
-}
-
-static void StoreGray(const fixed_y_t* rgb, fixed_y_t* y, int w) {
- int i;
- for (i = 0; i < w; ++i) {
- y[i] = RGBToGray(rgb[0 * w + i], rgb[1 * w + i], rgb[2 * w + i]);
- }
-}
-
-//------------------------------------------------------------------------------
-
-static WEBP_INLINE fixed_y_t Filter2(int A, int B, int W0) {
- const int v0 = (A * 3 + B + 2) >> 2;
- return clip_y(v0 + W0);
-}
-
//------------------------------------------------------------------------------
+// Main function
-static WEBP_INLINE fixed_y_t UpLift(uint8_t a) { // 8bit -> SFIX
- return ((fixed_y_t)a << SFIX) | SHALF;
-}
-
-static void ImportOneRow(const uint8_t* const r_ptr,
- const uint8_t* const g_ptr,
- const uint8_t* const b_ptr,
- int step,
- int pic_width,
- fixed_y_t* const dst) {
- int i;
- const int w = (pic_width + 1) & ~1;
- for (i = 0; i < pic_width; ++i) {
- const int off = i * step;
- dst[i + 0 * w] = UpLift(r_ptr[off]);
- dst[i + 1 * w] = UpLift(g_ptr[off]);
- dst[i + 2 * w] = UpLift(b_ptr[off]);
- }
- if (pic_width & 1) { // replicate rightmost pixel
- dst[pic_width + 0 * w] = dst[pic_width + 0 * w - 1];
- dst[pic_width + 1 * w] = dst[pic_width + 1 * w - 1];
- dst[pic_width + 2 * w] = dst[pic_width + 2 * w - 1];
- }
-}
-
-static void InterpolateTwoRows(const fixed_y_t* const best_y,
- const fixed_t* prev_uv,
- const fixed_t* cur_uv,
- const fixed_t* next_uv,
- int w,
- fixed_y_t* out1,
- fixed_y_t* out2) {
- const int uv_w = w >> 1;
- const int len = (w - 1) >> 1; // length to filter
- int k = 3;
- while (k-- > 0) { // process each R/G/B segments in turn
- // special boundary case for i==0
- out1[0] = Filter2(cur_uv[0], prev_uv[0], best_y[0]);
- out2[0] = Filter2(cur_uv[0], next_uv[0], best_y[w]);
-
- WebPSharpYUVFilterRow(cur_uv, prev_uv, len, best_y + 0 + 1, out1 + 1);
- WebPSharpYUVFilterRow(cur_uv, next_uv, len, best_y + w + 1, out2 + 1);
-
- // special boundary case for i == w - 1 when w is even
- if (!(w & 1)) {
- out1[w - 1] = Filter2(cur_uv[uv_w - 1], prev_uv[uv_w - 1],
- best_y[w - 1 + 0]);
- out2[w - 1] = Filter2(cur_uv[uv_w - 1], next_uv[uv_w - 1],
- best_y[w - 1 + w]);
- }
- out1 += w;
- out2 += w;
- prev_uv += uv_w;
- cur_uv += uv_w;
- next_uv += uv_w;
- }
-}
-
-static WEBP_INLINE uint8_t ConvertRGBToY(int r, int g, int b) {
- const int luma = 16839 * r + 33059 * g + 6420 * b + SROUNDER;
- return clip_8b(16 + (luma >> (YUV_FIX + SFIX)));
-}
+extern void SharpYuvInit(VP8CPUInfo cpu_info_func);
-static WEBP_INLINE uint8_t ConvertRGBToU(int r, int g, int b) {
- const int u = -9719 * r - 19081 * g + 28800 * b + SROUNDER;
- return clip_8b(128 + (u >> (YUV_FIX + SFIX)));
-}
+static void SafeInitSharpYuv(void) {
+#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
+ static pthread_mutex_t initsharpyuv_lock = PTHREAD_MUTEX_INITIALIZER;
+ if (pthread_mutex_lock(&initsharpyuv_lock)) return;
+#endif
-static WEBP_INLINE uint8_t ConvertRGBToV(int r, int g, int b) {
- const int v = +28800 * r - 24116 * g - 4684 * b + SROUNDER;
- return clip_8b(128 + (v >> (YUV_FIX + SFIX)));
-}
+ SharpYuvInit(VP8GetCPUInfo);
-static int ConvertWRGBToYUV(const fixed_y_t* best_y, const fixed_t* best_uv,
- WebPPicture* const picture) {
- int i, j;
- uint8_t* dst_y = picture->y;
- uint8_t* dst_u = picture->u;
- uint8_t* dst_v = picture->v;
- const fixed_t* const best_uv_base = best_uv;
- const int w = (picture->width + 1) & ~1;
- const int h = (picture->height + 1) & ~1;
- const int uv_w = w >> 1;
- const int uv_h = h >> 1;
- for (best_uv = best_uv_base, j = 0; j < picture->height; ++j) {
- for (i = 0; i < picture->width; ++i) {
- const int off = (i >> 1);
- const int W = best_y[i];
- const int r = best_uv[off + 0 * uv_w] + W;
- const int g = best_uv[off + 1 * uv_w] + W;
- const int b = best_uv[off + 2 * uv_w] + W;
- dst_y[i] = ConvertRGBToY(r, g, b);
- }
- best_y += w;
- best_uv += (j & 1) * 3 * uv_w;
- dst_y += picture->y_stride;
- }
- for (best_uv = best_uv_base, j = 0; j < uv_h; ++j) {
- for (i = 0; i < uv_w; ++i) {
- const int off = i;
- const int r = best_uv[off + 0 * uv_w];
- const int g = best_uv[off + 1 * uv_w];
- const int b = best_uv[off + 2 * uv_w];
- dst_u[i] = ConvertRGBToU(r, g, b);
- dst_v[i] = ConvertRGBToV(r, g, b);
- }
- best_uv += 3 * uv_w;
- dst_u += picture->uv_stride;
- dst_v += picture->uv_stride;
- }
- return 1;
+#if defined(WEBP_USE_THREAD) && !defined(_WIN32)
+ (void)pthread_mutex_unlock(&initsharpyuv_lock);
+#endif
}
-//------------------------------------------------------------------------------
-// Main function
-
-#define SAFE_ALLOC(W, H, T) ((T*)WebPSafeMalloc((W) * (H), sizeof(T)))
-
static int PreprocessARGB(const uint8_t* r_ptr,
const uint8_t* g_ptr,
const uint8_t* b_ptr,
int step, int rgb_stride,
WebPPicture* const picture) {
- // we expand the right/bottom border if needed
- const int w = (picture->width + 1) & ~1;
- const int h = (picture->height + 1) & ~1;
- const int uv_w = w >> 1;
- const int uv_h = h >> 1;
- uint64_t prev_diff_y_sum = ~0;
- int j, iter;
-
- // TODO(skal): allocate one big memory chunk. But for now, it's easier
- // for valgrind debugging to have several chunks.
- fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t); // scratch
- fixed_y_t* const best_y_base = SAFE_ALLOC(w, h, fixed_y_t);
- fixed_y_t* const target_y_base = SAFE_ALLOC(w, h, fixed_y_t);
- fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t);
- fixed_t* const best_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
- fixed_t* const target_uv_base = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
- fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t);
- fixed_y_t* best_y = best_y_base;
- fixed_y_t* target_y = target_y_base;
- fixed_t* best_uv = best_uv_base;
- fixed_t* target_uv = target_uv_base;
- const uint64_t diff_y_threshold = (uint64_t)(3.0 * w * h);
- int ok;
-
- if (best_y_base == NULL || best_uv_base == NULL ||
- target_y_base == NULL || target_uv_base == NULL ||
- best_rgb_y == NULL || best_rgb_uv == NULL ||
- tmp_buffer == NULL) {
- ok = WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
- goto End;
- }
- assert(picture->width >= kMinDimensionIterativeConversion);
- assert(picture->height >= kMinDimensionIterativeConversion);
-
- WebPInitConvertARGBToYUV();
-
- // Import RGB samples to W/RGB representation.
- for (j = 0; j < picture->height; j += 2) {
- const int is_last_row = (j == picture->height - 1);
- fixed_y_t* const src1 = tmp_buffer + 0 * w;
- fixed_y_t* const src2 = tmp_buffer + 3 * w;
-
- // prepare two rows of input
- ImportOneRow(r_ptr, g_ptr, b_ptr, step, picture->width, src1);
- if (!is_last_row) {
- ImportOneRow(r_ptr + rgb_stride, g_ptr + rgb_stride, b_ptr + rgb_stride,
- step, picture->width, src2);
- } else {
- memcpy(src2, src1, 3 * w * sizeof(*src2));
- }
- StoreGray(src1, best_y + 0, w);
- StoreGray(src2, best_y + w, w);
-
- UpdateW(src1, target_y, w);
- UpdateW(src2, target_y + w, w);
- UpdateChroma(src1, src2, target_uv, uv_w);
- memcpy(best_uv, target_uv, 3 * uv_w * sizeof(*best_uv));
- best_y += 2 * w;
- best_uv += 3 * uv_w;
- target_y += 2 * w;
- target_uv += 3 * uv_w;
- r_ptr += 2 * rgb_stride;
- g_ptr += 2 * rgb_stride;
- b_ptr += 2 * rgb_stride;
- }
-
- // Iterate and resolve clipping conflicts.
- for (iter = 0; iter < kNumIterations; ++iter) {
- const fixed_t* cur_uv = best_uv_base;
- const fixed_t* prev_uv = best_uv_base;
- uint64_t diff_y_sum = 0;
-
- best_y = best_y_base;
- best_uv = best_uv_base;
- target_y = target_y_base;
- target_uv = target_uv_base;
- for (j = 0; j < h; j += 2) {
- fixed_y_t* const src1 = tmp_buffer + 0 * w;
- fixed_y_t* const src2 = tmp_buffer + 3 * w;
- {
- const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0);
- InterpolateTwoRows(best_y, prev_uv, cur_uv, next_uv, w, src1, src2);
- prev_uv = cur_uv;
- cur_uv = next_uv;
- }
-
- UpdateW(src1, best_rgb_y + 0 * w, w);
- UpdateW(src2, best_rgb_y + 1 * w, w);
- UpdateChroma(src1, src2, best_rgb_uv, uv_w);
-
- // update two rows of Y and one row of RGB
- diff_y_sum += WebPSharpYUVUpdateY(target_y, best_rgb_y, best_y, 2 * w);
- WebPSharpYUVUpdateRGB(target_uv, best_rgb_uv, best_uv, 3 * uv_w);
-
- best_y += 2 * w;
- best_uv += 3 * uv_w;
- target_y += 2 * w;
- target_uv += 3 * uv_w;
- }
- // test exit condition
- if (iter > 0) {
- if (diff_y_sum < diff_y_threshold) break;
- if (diff_y_sum > prev_diff_y_sum) break;
- }
- prev_diff_y_sum = diff_y_sum;
+ const int ok = SharpYuvConvert(
+ r_ptr, g_ptr, b_ptr, step, rgb_stride, /*rgb_bit_depth=*/8,
+ picture->y, picture->y_stride, picture->u, picture->uv_stride, picture->v,
+ picture->uv_stride, /*yuv_bit_depth=*/8, picture->width,
+ picture->height, SharpYuvGetConversionMatrix(kSharpYuvMatrixWebp));
+ if (!ok) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
- // final reconstruction
- ok = ConvertWRGBToYUV(best_y_base, best_uv_base, picture);
-
- End:
- WebPSafeFree(best_y_base);
- WebPSafeFree(best_uv_base);
- WebPSafeFree(target_y_base);
- WebPSafeFree(target_uv_base);
- WebPSafeFree(best_rgb_y);
- WebPSafeFree(best_rgb_uv);
- WebPSafeFree(tmp_buffer);
return ok;
}
-#undef SAFE_ALLOC
//------------------------------------------------------------------------------
// "Fast" regular RGB->YUV
@@ -591,8 +224,8 @@ static const int kAlphaFix = 19;
// and constant are adjusted very tightly to fit 32b arithmetic.
// In particular, they use the fact that the operands for 'v / a' are actually
// derived as v = (a0.p0 + a1.p1 + a2.p2 + a3.p3) and a = a0 + a1 + a2 + a3
-// with ai in [0..255] and pi in [0..1<<kGammaFix). The constraint to avoid
-// overflow is: kGammaFix + kAlphaFix <= 31.
+// with ai in [0..255] and pi in [0..1<<GAMMA_FIX). The constraint to avoid
+// overflow is: GAMMA_FIX + kAlphaFix <= 31.
static const uint32_t kInvAlpha[4 * 0xff + 1] = {
0, /* alpha = 0 */
524288, 262144, 174762, 131072, 104857, 87381, 74898, 65536,
@@ -818,11 +451,20 @@ static WEBP_INLINE void AccumulateRGB(const uint8_t* const r_ptr,
dst[0] = SUM4(r_ptr + j, step);
dst[1] = SUM4(g_ptr + j, step);
dst[2] = SUM4(b_ptr + j, step);
+ // MemorySanitizer may raise false positives with data that passes through
+ // RGBA32PackedToPlanar_16b_SSE41() due to incorrect modeling of shuffles.
+ // See https://crbug.com/webp/573.
+#ifdef WEBP_MSAN
+ dst[3] = 0;
+#endif
}
if (width & 1) {
dst[0] = SUM2(r_ptr + j);
dst[1] = SUM2(g_ptr + j);
dst[2] = SUM2(b_ptr + j);
+#ifdef WEBP_MSAN
+ dst[3] = 0;
+#endif
}
}
@@ -863,18 +505,18 @@ static int ImportYUVAFromRGBA(const uint8_t* r_ptr,
use_iterative_conversion = 0;
}
- if (!WebPPictureAllocYUVA(picture, width, height)) {
+ if (!WebPPictureAllocYUVA(picture)) {
return 0;
}
if (has_alpha) {
assert(step == 4);
#if defined(USE_GAMMA_COMPRESSION) && defined(USE_INVERSE_ALPHA_TABLE)
- assert(kAlphaFix + kGammaFix <= 31);
+ assert(kAlphaFix + GAMMA_FIX <= 31);
#endif
}
if (use_iterative_conversion) {
- InitGammaTablesS();
+ SafeInitSharpYuv();
if (!PreprocessARGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, picture)) {
return 0;
}
@@ -1044,7 +686,7 @@ int WebPPictureYUVAToARGB(WebPPicture* picture) {
return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
}
// Allocate a new argb buffer (discarding the previous one).
- if (!WebPPictureAllocARGB(picture, picture->width, picture->height)) return 0;
+ if (!WebPPictureAllocARGB(picture)) return 0;
picture->use_argb = 1;
// Convert
@@ -1106,6 +748,8 @@ static int Import(WebPPicture* const picture,
const int width = picture->width;
const int height = picture->height;
+ if (abs(rgb_stride) < (import_alpha ? 4 : 3) * width) return 0;
+
if (!picture->use_argb) {
const uint8_t* a_ptr = import_alpha ? rgb + 3 : NULL;
return ImportYUVAFromRGBA(r_ptr, g_ptr, b_ptr, a_ptr, step, rgb_stride,
@@ -1163,24 +807,24 @@ static int Import(WebPPicture* const picture,
#if !defined(WEBP_REDUCE_CSP)
int WebPPictureImportBGR(WebPPicture* picture,
- const uint8_t* rgb, int rgb_stride) {
- return (picture != NULL && rgb != NULL)
- ? Import(picture, rgb, rgb_stride, 3, 1, 0)
+ const uint8_t* bgr, int bgr_stride) {
+ return (picture != NULL && bgr != NULL)
+ ? Import(picture, bgr, bgr_stride, 3, 1, 0)
: 0;
}
int WebPPictureImportBGRA(WebPPicture* picture,
- const uint8_t* rgba, int rgba_stride) {
- return (picture != NULL && rgba != NULL)
- ? Import(picture, rgba, rgba_stride, 4, 1, 1)
+ const uint8_t* bgra, int bgra_stride) {
+ return (picture != NULL && bgra != NULL)
+ ? Import(picture, bgra, bgra_stride, 4, 1, 1)
: 0;
}
int WebPPictureImportBGRX(WebPPicture* picture,
- const uint8_t* rgba, int rgba_stride) {
- return (picture != NULL && rgba != NULL)
- ? Import(picture, rgba, rgba_stride, 4, 1, 0)
+ const uint8_t* bgrx, int bgrx_stride) {
+ return (picture != NULL && bgrx != NULL)
+ ? Import(picture, bgrx, bgrx_stride, 4, 1, 0)
: 0;
}
@@ -1201,9 +845,9 @@ int WebPPictureImportRGBA(WebPPicture* picture,
}
int WebPPictureImportRGBX(WebPPicture* picture,
- const uint8_t* rgba, int rgba_stride) {
- return (picture != NULL && rgba != NULL)
- ? Import(picture, rgba, rgba_stride, 4, 0, 0)
+ const uint8_t* rgbx, int rgbx_stride) {
+ return (picture != NULL && rgbx != NULL)
+ ? Import(picture, rgbx, rgbx_stride, 4, 0, 0)
: 0;
}
diff --git a/thirdparty/libwebp/src/enc/picture_enc.c b/thirdparty/libwebp/src/enc/picture_enc.c
index c691622d03..3af6383d38 100644
--- a/thirdparty/libwebp/src/enc/picture_enc.c
+++ b/thirdparty/libwebp/src/enc/picture_enc.c
@@ -45,6 +45,22 @@ int WebPPictureInitInternal(WebPPicture* picture, int version) {
//------------------------------------------------------------------------------
+int WebPValidatePicture(const WebPPicture* const picture) {
+ if (picture == NULL) return 0;
+ if (picture->width <= 0 || picture->height <= 0) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
+ }
+ if (picture->width <= 0 || picture->width / 4 > INT_MAX / 4 ||
+ picture->height <= 0 || picture->height / 4 > INT_MAX / 4) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
+ }
+ if (picture->colorspace != WEBP_YUV420 &&
+ picture->colorspace != WEBP_YUV420A) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
+ }
+ return 1;
+}
+
static void WebPPictureResetBufferARGB(WebPPicture* const picture) {
picture->memory_argb_ = NULL;
picture->argb = NULL;
@@ -63,18 +79,17 @@ void WebPPictureResetBuffers(WebPPicture* const picture) {
WebPPictureResetBufferYUVA(picture);
}
-int WebPPictureAllocARGB(WebPPicture* const picture, int width, int height) {
+int WebPPictureAllocARGB(WebPPicture* const picture) {
void* memory;
+ const int width = picture->width;
+ const int height = picture->height;
const uint64_t argb_size = (uint64_t)width * height;
- assert(picture != NULL);
+ if (!WebPValidatePicture(picture)) return 0;
WebPSafeFree(picture->memory_argb_);
WebPPictureResetBufferARGB(picture);
- if (width <= 0 || height <= 0) {
- return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
- }
// allocate a new buffer.
memory = WebPSafeMalloc(argb_size + WEBP_ALIGN_CST, sizeof(*picture->argb));
if (memory == NULL) {
@@ -86,10 +101,10 @@ int WebPPictureAllocARGB(WebPPicture* const picture, int width, int height) {
return 1;
}
-int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height) {
- const WebPEncCSP uv_csp =
- (WebPEncCSP)((int)picture->colorspace & WEBP_CSP_UV_MASK);
+int WebPPictureAllocYUVA(WebPPicture* const picture) {
const int has_alpha = (int)picture->colorspace & WEBP_CSP_ALPHA_BIT;
+ const int width = picture->width;
+ const int height = picture->height;
const int y_stride = width;
const int uv_width = (int)(((int64_t)width + 1) >> 1);
const int uv_height = (int)(((int64_t)height + 1) >> 1);
@@ -98,15 +113,11 @@ int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height) {
uint64_t y_size, uv_size, a_size, total_size;
uint8_t* mem;
- assert(picture != NULL);
+ if (!WebPValidatePicture(picture)) return 0;
WebPSafeFree(picture->memory_);
WebPPictureResetBufferYUVA(picture);
- if (uv_csp != WEBP_YUV420) {
- return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
- }
-
// alpha
a_width = has_alpha ? width : 0;
a_stride = a_width;
@@ -152,15 +163,12 @@ int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height) {
int WebPPictureAlloc(WebPPicture* picture) {
if (picture != NULL) {
- const int width = picture->width;
- const int height = picture->height;
-
WebPPictureFree(picture); // erase previous buffer
if (!picture->use_argb) {
- return WebPPictureAllocYUVA(picture, width, height);
+ return WebPPictureAllocYUVA(picture);
} else {
- return WebPPictureAllocARGB(picture, width, height);
+ return WebPPictureAllocARGB(picture);
}
}
return 1;
diff --git a/thirdparty/libwebp/src/enc/picture_rescale_enc.c b/thirdparty/libwebp/src/enc/picture_rescale_enc.c
index a75f5d9c06..839f91cacc 100644
--- a/thirdparty/libwebp/src/enc/picture_rescale_enc.c
+++ b/thirdparty/libwebp/src/enc/picture_rescale_enc.c
@@ -13,14 +13,15 @@
#include "src/webp/encode.h"
-#if !defined(WEBP_REDUCE_SIZE)
-
#include <assert.h>
#include <stdlib.h>
#include "src/enc/vp8i_enc.h"
+
+#if !defined(WEBP_REDUCE_SIZE)
#include "src/utils/rescaler_utils.h"
#include "src/utils/utils.h"
+#endif // !defined(WEBP_REDUCE_SIZE)
#define HALVE(x) (((x) + 1) >> 1)
@@ -56,6 +57,7 @@ static int AdjustAndCheckRectangle(const WebPPicture* const pic,
return 1;
}
+#if !defined(WEBP_REDUCE_SIZE)
int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) {
if (src == NULL || dst == NULL) return 0;
if (src == dst) return 1;
@@ -81,6 +83,7 @@ int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) {
}
return 1;
}
+#endif // !defined(WEBP_REDUCE_SIZE)
int WebPPictureIsView(const WebPPicture* picture) {
if (picture == NULL) return 0;
@@ -120,6 +123,7 @@ int WebPPictureView(const WebPPicture* src,
return 1;
}
+#if !defined(WEBP_REDUCE_SIZE)
//------------------------------------------------------------------------------
// Picture cropping
@@ -198,34 +202,34 @@ static void AlphaMultiplyY(WebPPicture* const pic, int inverse) {
}
}
-int WebPPictureRescale(WebPPicture* pic, int width, int height) {
+int WebPPictureRescale(WebPPicture* picture, int width, int height) {
WebPPicture tmp;
int prev_width, prev_height;
rescaler_t* work;
- if (pic == NULL) return 0;
- prev_width = pic->width;
- prev_height = pic->height;
+ if (picture == NULL) return 0;
+ prev_width = picture->width;
+ prev_height = picture->height;
if (!WebPRescalerGetScaledDimensions(
prev_width, prev_height, &width, &height)) {
return 0;
}
- PictureGrabSpecs(pic, &tmp);
+ PictureGrabSpecs(picture, &tmp);
tmp.width = width;
tmp.height = height;
if (!WebPPictureAlloc(&tmp)) return 0;
- if (!pic->use_argb) {
+ if (!picture->use_argb) {
work = (rescaler_t*)WebPSafeMalloc(2ULL * width, sizeof(*work));
if (work == NULL) {
WebPPictureFree(&tmp);
return 0;
}
// If present, we need to rescale alpha first (for AlphaMultiplyY).
- if (pic->a != NULL) {
+ if (picture->a != NULL) {
WebPInitAlphaProcessing();
- if (!RescalePlane(pic->a, prev_width, prev_height, pic->a_stride,
+ if (!RescalePlane(picture->a, prev_width, prev_height, picture->a_stride,
tmp.a, width, height, tmp.a_stride, work, 1)) {
return 0;
}
@@ -233,17 +237,15 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) {
// We take transparency into account on the luma plane only. That's not
// totally exact blending, but still is a good approximation.
- AlphaMultiplyY(pic, 0);
- if (!RescalePlane(pic->y, prev_width, prev_height, pic->y_stride,
+ AlphaMultiplyY(picture, 0);
+ if (!RescalePlane(picture->y, prev_width, prev_height, picture->y_stride,
tmp.y, width, height, tmp.y_stride, work, 1) ||
- !RescalePlane(pic->u,
- HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
- tmp.u,
- HALVE(width), HALVE(height), tmp.uv_stride, work, 1) ||
- !RescalePlane(pic->v,
- HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
- tmp.v,
- HALVE(width), HALVE(height), tmp.uv_stride, work, 1)) {
+ !RescalePlane(picture->u, HALVE(prev_width), HALVE(prev_height),
+ picture->uv_stride, tmp.u, HALVE(width), HALVE(height),
+ tmp.uv_stride, work, 1) ||
+ !RescalePlane(picture->v, HALVE(prev_width), HALVE(prev_height),
+ picture->uv_stride, tmp.v, HALVE(width), HALVE(height),
+ tmp.uv_stride, work, 1)) {
return 0;
}
AlphaMultiplyY(&tmp, 1);
@@ -257,18 +259,17 @@ int WebPPictureRescale(WebPPicture* pic, int width, int height) {
// weighting first (black-matting), scale the RGB values, and remove
// the premultiplication afterward (while preserving the alpha channel).
WebPInitAlphaProcessing();
- AlphaMultiplyARGB(pic, 0);
- if (!RescalePlane((const uint8_t*)pic->argb, prev_width, prev_height,
- pic->argb_stride * 4,
- (uint8_t*)tmp.argb, width, height,
- tmp.argb_stride * 4, work, 4)) {
+ AlphaMultiplyARGB(picture, 0);
+ if (!RescalePlane((const uint8_t*)picture->argb, prev_width, prev_height,
+ picture->argb_stride * 4, (uint8_t*)tmp.argb, width,
+ height, tmp.argb_stride * 4, work, 4)) {
return 0;
}
AlphaMultiplyARGB(&tmp, 1);
}
- WebPPictureFree(pic);
+ WebPPictureFree(picture);
WebPSafeFree(work);
- *pic = tmp;
+ *picture = tmp;
return 1;
}
@@ -280,23 +281,6 @@ int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) {
return 0;
}
-int WebPPictureIsView(const WebPPicture* picture) {
- (void)picture;
- return 0;
-}
-
-int WebPPictureView(const WebPPicture* src,
- int left, int top, int width, int height,
- WebPPicture* dst) {
- (void)src;
- (void)left;
- (void)top;
- (void)width;
- (void)height;
- (void)dst;
- return 0;
-}
-
int WebPPictureCrop(WebPPicture* pic,
int left, int top, int width, int height) {
(void)pic;
diff --git a/thirdparty/libwebp/src/enc/picture_tools_enc.c b/thirdparty/libwebp/src/enc/picture_tools_enc.c
index 38cb01534a..147cc18608 100644
--- a/thirdparty/libwebp/src/enc/picture_tools_enc.c
+++ b/thirdparty/libwebp/src/enc/picture_tools_enc.c
@@ -190,27 +190,28 @@ static WEBP_INLINE uint32_t MakeARGB32(int r, int g, int b) {
return (0xff000000u | (r << 16) | (g << 8) | b);
}
-void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb) {
+void WebPBlendAlpha(WebPPicture* picture, uint32_t background_rgb) {
const int red = (background_rgb >> 16) & 0xff;
const int green = (background_rgb >> 8) & 0xff;
const int blue = (background_rgb >> 0) & 0xff;
int x, y;
- if (pic == NULL) return;
- if (!pic->use_argb) {
- const int uv_width = (pic->width >> 1); // omit last pixel during u/v loop
+ if (picture == NULL) return;
+ if (!picture->use_argb) {
+ // omit last pixel during u/v loop
+ const int uv_width = (picture->width >> 1);
const int Y0 = VP8RGBToY(red, green, blue, YUV_HALF);
// VP8RGBToU/V expects the u/v values summed over four pixels
const int U0 = VP8RGBToU(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF);
const int V0 = VP8RGBToV(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF);
- const int has_alpha = pic->colorspace & WEBP_CSP_ALPHA_BIT;
- uint8_t* y_ptr = pic->y;
- uint8_t* u_ptr = pic->u;
- uint8_t* v_ptr = pic->v;
- uint8_t* a_ptr = pic->a;
+ const int has_alpha = picture->colorspace & WEBP_CSP_ALPHA_BIT;
+ uint8_t* y_ptr = picture->y;
+ uint8_t* u_ptr = picture->u;
+ uint8_t* v_ptr = picture->v;
+ uint8_t* a_ptr = picture->a;
if (!has_alpha || a_ptr == NULL) return; // nothing to do
- for (y = 0; y < pic->height; ++y) {
+ for (y = 0; y < picture->height; ++y) {
// Luma blending
- for (x = 0; x < pic->width; ++x) {
+ for (x = 0; x < picture->width; ++x) {
const uint8_t alpha = a_ptr[x];
if (alpha < 0xff) {
y_ptr[x] = BLEND(Y0, y_ptr[x], alpha);
@@ -219,7 +220,7 @@ void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb) {
// Chroma blending every even line
if ((y & 1) == 0) {
uint8_t* const a_ptr2 =
- (y + 1 == pic->height) ? a_ptr : a_ptr + pic->a_stride;
+ (y + 1 == picture->height) ? a_ptr : a_ptr + picture->a_stride;
for (x = 0; x < uv_width; ++x) {
// Average four alpha values into a single blending weight.
// TODO(skal): might lead to visible contouring. Can we do better?
@@ -229,24 +230,24 @@ void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb) {
u_ptr[x] = BLEND_10BIT(U0, u_ptr[x], alpha);
v_ptr[x] = BLEND_10BIT(V0, v_ptr[x], alpha);
}
- if (pic->width & 1) { // rightmost pixel
+ if (picture->width & 1) { // rightmost pixel
const uint32_t alpha = 2 * (a_ptr[2 * x + 0] + a_ptr2[2 * x + 0]);
u_ptr[x] = BLEND_10BIT(U0, u_ptr[x], alpha);
v_ptr[x] = BLEND_10BIT(V0, v_ptr[x], alpha);
}
} else {
- u_ptr += pic->uv_stride;
- v_ptr += pic->uv_stride;
+ u_ptr += picture->uv_stride;
+ v_ptr += picture->uv_stride;
}
- memset(a_ptr, 0xff, pic->width); // reset alpha value to opaque
- a_ptr += pic->a_stride;
- y_ptr += pic->y_stride;
+ memset(a_ptr, 0xff, picture->width); // reset alpha value to opaque
+ a_ptr += picture->a_stride;
+ y_ptr += picture->y_stride;
}
} else {
- uint32_t* argb = pic->argb;
+ uint32_t* argb = picture->argb;
const uint32_t background = MakeARGB32(red, green, blue);
- for (y = 0; y < pic->height; ++y) {
- for (x = 0; x < pic->width; ++x) {
+ for (y = 0; y < picture->height; ++y) {
+ for (x = 0; x < picture->width; ++x) {
const int alpha = (argb[x] >> 24) & 0xff;
if (alpha != 0xff) {
if (alpha > 0) {
@@ -262,7 +263,7 @@ void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb) {
}
}
}
- argb += pic->argb_stride;
+ argb += picture->argb_stride;
}
}
}
diff --git a/thirdparty/libwebp/src/enc/predictor_enc.c b/thirdparty/libwebp/src/enc/predictor_enc.c
index 2b5c767280..b3d44b59d5 100644
--- a/thirdparty/libwebp/src/enc/predictor_enc.c
+++ b/thirdparty/libwebp/src/enc/predictor_enc.c
@@ -16,6 +16,7 @@
#include "src/dsp/lossless.h"
#include "src/dsp/lossless_common.h"
+#include "src/enc/vp8i_enc.h"
#include "src/enc/vp8li_enc.h"
#define MAX_DIFF_COST (1e30f)
@@ -31,10 +32,10 @@ static WEBP_INLINE int GetMin(int a, int b) { return (a > b) ? b : a; }
// Methods to calculate Entropy (Shannon).
static float PredictionCostSpatial(const int counts[256], int weight_0,
- double exp_val) {
+ float exp_val) {
const int significant_symbols = 256 >> 4;
- const double exp_decay_factor = 0.6;
- double bits = weight_0 * counts[0];
+ const float exp_decay_factor = 0.6f;
+ float bits = (float)weight_0 * counts[0];
int i;
for (i = 1; i < significant_symbols; ++i) {
bits += exp_val * (counts[i] + counts[256 - i]);
@@ -46,9 +47,9 @@ static float PredictionCostSpatial(const int counts[256], int weight_0,
static float PredictionCostSpatialHistogram(const int accumulated[4][256],
const int tile[4][256]) {
int i;
- double retval = 0;
+ float retval = 0.f;
for (i = 0; i < 4; ++i) {
- const double kExpValue = 0.94;
+ const float kExpValue = 0.94f;
retval += PredictionCostSpatial(tile[i], 1, kExpValue);
retval += VP8LCombinedShannonEntropy(tile[i], accumulated[i]);
}
@@ -472,12 +473,15 @@ static void CopyImageWithPrediction(int width, int height,
// with respect to predictions. If near_lossless_quality < 100, applies
// near lossless processing, shaving off more bits of residuals for lower
// qualities.
-void VP8LResidualImage(int width, int height, int bits, int low_effort,
- uint32_t* const argb, uint32_t* const argb_scratch,
- uint32_t* const image, int near_lossless_quality,
- int exact, int used_subtract_green) {
+int VP8LResidualImage(int width, int height, int bits, int low_effort,
+ uint32_t* const argb, uint32_t* const argb_scratch,
+ uint32_t* const image, int near_lossless_quality,
+ int exact, int used_subtract_green,
+ const WebPPicture* const pic, int percent_range,
+ int* const percent) {
const int tiles_per_row = VP8LSubSampleSize(width, bits);
const int tiles_per_col = VP8LSubSampleSize(height, bits);
+ int percent_start = *percent;
int tile_y;
int histo[4][256];
const int max_quantization = 1 << VP8LNearLosslessBits(near_lossless_quality);
@@ -491,17 +495,24 @@ void VP8LResidualImage(int width, int height, int bits, int low_effort,
for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) {
int tile_x;
for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) {
- const int pred = GetBestPredictorForTile(width, height, tile_x, tile_y,
- bits, histo, argb_scratch, argb, max_quantization, exact,
- used_subtract_green, image);
+ const int pred = GetBestPredictorForTile(
+ width, height, tile_x, tile_y, bits, histo, argb_scratch, argb,
+ max_quantization, exact, used_subtract_green, image);
image[tile_y * tiles_per_row + tile_x] = ARGB_BLACK | (pred << 8);
}
+
+ if (!WebPReportProgress(
+ pic, percent_start + percent_range * tile_y / tiles_per_col,
+ percent)) {
+ return 0;
+ }
}
}
CopyImageWithPrediction(width, height, bits, image, argb_scratch, argb,
low_effort, max_quantization, exact,
used_subtract_green);
+ return WebPReportProgress(pic, percent_start + percent_range, percent);
}
//------------------------------------------------------------------------------
@@ -532,7 +543,7 @@ static float PredictionCostCrossColor(const int accumulated[256],
const int counts[256]) {
// Favor low entropy, locally and globally.
// Favor small absolute values for PredictionCostSpatial
- static const double kExpValue = 2.4;
+ static const float kExpValue = 2.4f;
return VP8LCombinedShannonEntropy(counts, accumulated) +
PredictionCostSpatial(counts, 3, kExpValue);
}
@@ -714,11 +725,14 @@ static void CopyTileWithColorTransform(int xsize, int ysize,
}
}
-void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
- uint32_t* const argb, uint32_t* image) {
+int VP8LColorSpaceTransform(int width, int height, int bits, int quality,
+ uint32_t* const argb, uint32_t* image,
+ const WebPPicture* const pic, int percent_range,
+ int* const percent) {
const int max_tile_size = 1 << bits;
const int tile_xsize = VP8LSubSampleSize(width, bits);
const int tile_ysize = VP8LSubSampleSize(height, bits);
+ int percent_start = *percent;
int accumulated_red_histo[256] = { 0 };
int accumulated_blue_histo[256] = { 0 };
int tile_x, tile_y;
@@ -768,5 +782,11 @@ void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
}
}
}
+ if (!WebPReportProgress(
+ pic, percent_start + percent_range * tile_y / tile_ysize,
+ percent)) {
+ return 0;
+ }
}
+ return 1;
}
diff --git a/thirdparty/libwebp/src/enc/quant_enc.c b/thirdparty/libwebp/src/enc/quant_enc.c
index 6cede28ab4..6d8202d277 100644
--- a/thirdparty/libwebp/src/enc/quant_enc.c
+++ b/thirdparty/libwebp/src/enc/quant_enc.c
@@ -533,7 +533,8 @@ static void InitScore(VP8ModeScore* const rd) {
rd->score = MAX_COST;
}
-static void CopyScore(VP8ModeScore* const dst, const VP8ModeScore* const src) {
+static void CopyScore(VP8ModeScore* WEBP_RESTRICT const dst,
+ const VP8ModeScore* WEBP_RESTRICT const src) {
dst->D = src->D;
dst->SD = src->SD;
dst->R = src->R;
@@ -542,7 +543,8 @@ static void CopyScore(VP8ModeScore* const dst, const VP8ModeScore* const src) {
dst->score = src->score;
}
-static void AddScore(VP8ModeScore* const dst, const VP8ModeScore* const src) {
+static void AddScore(VP8ModeScore* WEBP_RESTRICT const dst,
+ const VP8ModeScore* WEBP_RESTRICT const src) {
dst->D += src->D;
dst->SD += src->SD;
dst->R += src->R;
@@ -588,10 +590,10 @@ static WEBP_INLINE score_t RDScoreTrellis(int lambda, score_t rate,
// Coefficient type.
enum { TYPE_I16_AC = 0, TYPE_I16_DC = 1, TYPE_CHROMA_A = 2, TYPE_I4_AC = 3 };
-static int TrellisQuantizeBlock(const VP8Encoder* const enc,
+static int TrellisQuantizeBlock(const VP8Encoder* WEBP_RESTRICT const enc,
int16_t in[16], int16_t out[16],
int ctx0, int coeff_type,
- const VP8Matrix* const mtx,
+ const VP8Matrix* WEBP_RESTRICT const mtx,
int lambda) {
const ProbaArray* const probas = enc->proba_.coeffs_[coeff_type];
CostArrayPtr const costs =
@@ -767,9 +769,9 @@ static int TrellisQuantizeBlock(const VP8Encoder* const enc,
// all at once. Output is the reconstructed block in *yuv_out, and the
// quantized levels in *levels.
-static int ReconstructIntra16(VP8EncIterator* const it,
- VP8ModeScore* const rd,
- uint8_t* const yuv_out,
+static int ReconstructIntra16(VP8EncIterator* WEBP_RESTRICT const it,
+ VP8ModeScore* WEBP_RESTRICT const rd,
+ uint8_t* WEBP_RESTRICT const yuv_out,
int mode) {
const VP8Encoder* const enc = it->enc_;
const uint8_t* const ref = it->yuv_p_ + VP8I16ModeOffsets[mode];
@@ -819,10 +821,10 @@ static int ReconstructIntra16(VP8EncIterator* const it,
return nz;
}
-static int ReconstructIntra4(VP8EncIterator* const it,
+static int ReconstructIntra4(VP8EncIterator* WEBP_RESTRICT const it,
int16_t levels[16],
- const uint8_t* const src,
- uint8_t* const yuv_out,
+ const uint8_t* WEBP_RESTRICT const src,
+ uint8_t* WEBP_RESTRICT const yuv_out,
int mode) {
const VP8Encoder* const enc = it->enc_;
const uint8_t* const ref = it->yuv_p_ + VP8I4ModeOffsets[mode];
@@ -855,7 +857,8 @@ static int ReconstructIntra4(VP8EncIterator* const it,
// Quantize as usual, but also compute and return the quantization error.
// Error is already divided by DSHIFT.
-static int QuantizeSingle(int16_t* const v, const VP8Matrix* const mtx) {
+static int QuantizeSingle(int16_t* WEBP_RESTRICT const v,
+ const VP8Matrix* WEBP_RESTRICT const mtx) {
int V = *v;
const int sign = (V < 0);
if (sign) V = -V;
@@ -869,9 +872,10 @@ static int QuantizeSingle(int16_t* const v, const VP8Matrix* const mtx) {
return (sign ? -V : V) >> DSCALE;
}
-static void CorrectDCValues(const VP8EncIterator* const it,
- const VP8Matrix* const mtx,
- int16_t tmp[][16], VP8ModeScore* const rd) {
+static void CorrectDCValues(const VP8EncIterator* WEBP_RESTRICT const it,
+ const VP8Matrix* WEBP_RESTRICT const mtx,
+ int16_t tmp[][16],
+ VP8ModeScore* WEBP_RESTRICT const rd) {
// | top[0] | top[1]
// --------+--------+---------
// left[0] | tmp[0] tmp[1] <-> err0 err1
@@ -902,8 +906,8 @@ static void CorrectDCValues(const VP8EncIterator* const it,
}
}
-static void StoreDiffusionErrors(VP8EncIterator* const it,
- const VP8ModeScore* const rd) {
+static void StoreDiffusionErrors(VP8EncIterator* WEBP_RESTRICT const it,
+ const VP8ModeScore* WEBP_RESTRICT const rd) {
int ch;
for (ch = 0; ch <= 1; ++ch) {
int8_t* const top = it->top_derr_[it->x_][ch];
@@ -922,8 +926,9 @@ static void StoreDiffusionErrors(VP8EncIterator* const it,
//------------------------------------------------------------------------------
-static int ReconstructUV(VP8EncIterator* const it, VP8ModeScore* const rd,
- uint8_t* const yuv_out, int mode) {
+static int ReconstructUV(VP8EncIterator* WEBP_RESTRICT const it,
+ VP8ModeScore* WEBP_RESTRICT const rd,
+ uint8_t* WEBP_RESTRICT const yuv_out, int mode) {
const VP8Encoder* const enc = it->enc_;
const uint8_t* const ref = it->yuv_p_ + VP8UVModeOffsets[mode];
const uint8_t* const src = it->yuv_in_ + U_OFF_ENC;
@@ -994,7 +999,8 @@ static void SwapOut(VP8EncIterator* const it) {
SwapPtr(&it->yuv_out_, &it->yuv_out2_);
}
-static void PickBestIntra16(VP8EncIterator* const it, VP8ModeScore* rd) {
+static void PickBestIntra16(VP8EncIterator* WEBP_RESTRICT const it,
+ VP8ModeScore* WEBP_RESTRICT rd) {
const int kNumBlocks = 16;
VP8SegmentInfo* const dqm = &it->enc_->dqm_[it->mb_->segment_];
const int lambda = dqm->lambda_i16_;
@@ -1054,7 +1060,7 @@ static void PickBestIntra16(VP8EncIterator* const it, VP8ModeScore* rd) {
//------------------------------------------------------------------------------
// return the cost array corresponding to the surrounding prediction modes.
-static const uint16_t* GetCostModeI4(VP8EncIterator* const it,
+static const uint16_t* GetCostModeI4(VP8EncIterator* WEBP_RESTRICT const it,
const uint8_t modes[16]) {
const int preds_w = it->enc_->preds_w_;
const int x = (it->i4_ & 3), y = it->i4_ >> 2;
@@ -1063,7 +1069,8 @@ static const uint16_t* GetCostModeI4(VP8EncIterator* const it,
return VP8FixedCostsI4[top][left];
}
-static int PickBestIntra4(VP8EncIterator* const it, VP8ModeScore* const rd) {
+static int PickBestIntra4(VP8EncIterator* WEBP_RESTRICT const it,
+ VP8ModeScore* WEBP_RESTRICT const rd) {
const VP8Encoder* const enc = it->enc_;
const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_];
const int lambda = dqm->lambda_i4_;
@@ -1159,7 +1166,8 @@ static int PickBestIntra4(VP8EncIterator* const it, VP8ModeScore* const rd) {
//------------------------------------------------------------------------------
-static void PickBestUV(VP8EncIterator* const it, VP8ModeScore* const rd) {
+static void PickBestUV(VP8EncIterator* WEBP_RESTRICT const it,
+ VP8ModeScore* WEBP_RESTRICT const rd) {
const int kNumBlocks = 8;
const VP8SegmentInfo* const dqm = &it->enc_->dqm_[it->mb_->segment_];
const int lambda = dqm->lambda_uv_;
@@ -1211,7 +1219,8 @@ static void PickBestUV(VP8EncIterator* const it, VP8ModeScore* const rd) {
//------------------------------------------------------------------------------
// Final reconstruction and quantization.
-static void SimpleQuantize(VP8EncIterator* const it, VP8ModeScore* const rd) {
+static void SimpleQuantize(VP8EncIterator* WEBP_RESTRICT const it,
+ VP8ModeScore* WEBP_RESTRICT const rd) {
const VP8Encoder* const enc = it->enc_;
const int is_i16 = (it->mb_->type_ == 1);
int nz = 0;
@@ -1236,9 +1245,9 @@ static void SimpleQuantize(VP8EncIterator* const it, VP8ModeScore* const rd) {
}
// Refine intra16/intra4 sub-modes based on distortion only (not rate).
-static void RefineUsingDistortion(VP8EncIterator* const it,
+static void RefineUsingDistortion(VP8EncIterator* WEBP_RESTRICT const it,
int try_both_modes, int refine_uv_mode,
- VP8ModeScore* const rd) {
+ VP8ModeScore* WEBP_RESTRICT const rd) {
score_t best_score = MAX_COST;
int nz = 0;
int mode;
@@ -1352,7 +1361,8 @@ static void RefineUsingDistortion(VP8EncIterator* const it,
//------------------------------------------------------------------------------
// Entry point
-int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd,
+int VP8Decimate(VP8EncIterator* WEBP_RESTRICT const it,
+ VP8ModeScore* WEBP_RESTRICT const rd,
VP8RDLevel rd_opt) {
int is_skipped;
const int method = it->enc_->method_;
diff --git a/thirdparty/libwebp/src/enc/vp8i_enc.h b/thirdparty/libwebp/src/enc/vp8i_enc.h
index b4bba08f27..71f76702ae 100644
--- a/thirdparty/libwebp/src/enc/vp8i_enc.h
+++ b/thirdparty/libwebp/src/enc/vp8i_enc.h
@@ -32,7 +32,7 @@ extern "C" {
// version numbers
#define ENC_MAJ_VERSION 1
#define ENC_MIN_VERSION 2
-#define ENC_REV_VERSION 2
+#define ENC_REV_VERSION 4
enum { MAX_LF_LEVELS = 64, // Maximum loop filter level
MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost
@@ -470,7 +470,8 @@ int VP8EncAnalyze(VP8Encoder* const enc);
// Sets up segment's quantization values, base_quant_ and filter strengths.
void VP8SetSegmentParams(VP8Encoder* const enc, float quality);
// Pick best modes and fills the levels. Returns true if skipped.
-int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd,
+int VP8Decimate(VP8EncIterator* WEBP_RESTRICT const it,
+ VP8ModeScore* WEBP_RESTRICT const rd,
VP8RDLevel rd_opt);
// in alpha.c
@@ -490,19 +491,24 @@ int VP8FilterStrengthFromDelta(int sharpness, int delta);
// misc utils for picture_*.c:
+// Returns true if 'picture' is non-NULL and dimensions/colorspace are within
+// their valid ranges. If returning false, the 'error_code' in 'picture' is
+// updated.
+int WebPValidatePicture(const WebPPicture* const picture);
+
// Remove reference to the ARGB/YUVA buffer (doesn't free anything).
void WebPPictureResetBuffers(WebPPicture* const picture);
-// Allocates ARGB buffer of given dimension (previous one is always free'd).
-// Preserves the YUV(A) buffer. Returns false in case of error (invalid param,
-// out-of-memory).
-int WebPPictureAllocARGB(WebPPicture* const picture, int width, int height);
+// Allocates ARGB buffer according to set width/height (previous one is
+// always free'd). Preserves the YUV(A) buffer. Returns false in case of error
+// (invalid param, out-of-memory).
+int WebPPictureAllocARGB(WebPPicture* const picture);
-// Allocates YUVA buffer of given dimension (previous one is always free'd).
-// Uses picture->csp to determine whether an alpha buffer is needed.
+// Allocates YUVA buffer according to set width/height (previous one is always
+// free'd). Uses picture->csp to determine whether an alpha buffer is needed.
// Preserves the ARGB buffer.
// Returns false in case of error (invalid param, out-of-memory).
-int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height);
+int WebPPictureAllocYUVA(WebPPicture* const picture);
// Replace samples that are fully transparent by 'color' to help compressibility
// (no guarantee, though). Assumes pic->use_argb is true.
diff --git a/thirdparty/libwebp/src/enc/vp8l_enc.c b/thirdparty/libwebp/src/enc/vp8l_enc.c
index e330e716f1..2b345df610 100644
--- a/thirdparty/libwebp/src/enc/vp8l_enc.c
+++ b/thirdparty/libwebp/src/enc/vp8l_enc.c
@@ -15,15 +15,16 @@
#include <assert.h>
#include <stdlib.h>
+#include "src/dsp/lossless.h"
+#include "src/dsp/lossless_common.h"
#include "src/enc/backward_references_enc.h"
#include "src/enc/histogram_enc.h"
#include "src/enc/vp8i_enc.h"
#include "src/enc/vp8li_enc.h"
-#include "src/dsp/lossless.h"
-#include "src/dsp/lossless_common.h"
#include "src/utils/bit_writer_utils.h"
#include "src/utils/huffman_encode_utils.h"
#include "src/utils/utils.h"
+#include "src/webp/encode.h"
#include "src/webp/format_constants.h"
// Maximum number of histogram images (sub-blocks).
@@ -183,10 +184,9 @@ static void CoOccurrenceFindMax(const uint32_t* const cooccurrence,
}
// Builds the cooccurrence matrix
-static WebPEncodingError CoOccurrenceBuild(const WebPPicture* const pic,
- const uint32_t* const palette,
- uint32_t num_colors,
- uint32_t* cooccurrence) {
+static int CoOccurrenceBuild(const WebPPicture* const pic,
+ const uint32_t* const palette, uint32_t num_colors,
+ uint32_t* cooccurrence) {
uint32_t *lines, *line_top, *line_current, *line_tmp;
int x, y;
const uint32_t* src = pic->argb;
@@ -195,7 +195,10 @@ static WebPEncodingError CoOccurrenceBuild(const WebPPicture* const pic,
uint32_t idx_map[MAX_PALETTE_SIZE] = {0};
uint32_t palette_sorted[MAX_PALETTE_SIZE];
lines = (uint32_t*)WebPSafeMalloc(2 * pic->width, sizeof(*lines));
- if (lines == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
+ if (lines == NULL) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ return 0;
+ }
line_top = &lines[0];
line_current = &lines[pic->width];
PrepareMapToPalette(palette, num_colors, palette_sorted, idx_map);
@@ -226,7 +229,7 @@ static WebPEncodingError CoOccurrenceBuild(const WebPPicture* const pic,
src += pic->argb_stride;
}
WebPSafeFree(lines);
- return VP8_ENC_OK;
+ return 1;
}
struct Sum {
@@ -237,7 +240,7 @@ struct Sum {
// Implements the modified Zeng method from "A Survey on Palette Reordering
// Methods for Improving the Compression of Color-Indexed Images" by Armando J.
// Pinho and Antonio J. R. Neves.
-static WebPEncodingError PaletteSortModifiedZeng(
+static int PaletteSortModifiedZeng(
const WebPPicture* const pic, const uint32_t* const palette_sorted,
uint32_t num_colors, uint32_t* const palette) {
uint32_t i, j, ind;
@@ -247,15 +250,16 @@ static WebPEncodingError PaletteSortModifiedZeng(
uint32_t first, last;
uint32_t num_sums;
// TODO(vrabaud) check whether one color images should use palette or not.
- if (num_colors <= 1) return VP8_ENC_OK;
+ if (num_colors <= 1) return 1;
// Build the co-occurrence matrix.
cooccurrence =
(uint32_t*)WebPSafeCalloc(num_colors * num_colors, sizeof(*cooccurrence));
- if (cooccurrence == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
- if (CoOccurrenceBuild(pic, palette_sorted, num_colors, cooccurrence) !=
- VP8_ENC_OK) {
- WebPSafeFree(cooccurrence);
- return VP8_ENC_ERROR_OUT_OF_MEMORY;
+ if (cooccurrence == NULL) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ return 0;
+ }
+ if (!CoOccurrenceBuild(pic, palette_sorted, num_colors, cooccurrence)) {
+ return 0;
}
// Initialize the mapping list with the two best indices.
@@ -316,7 +320,7 @@ static WebPEncodingError PaletteSortModifiedZeng(
for (i = 0; i < num_colors; ++i) {
palette[i] = palette_sorted[remapping[(first + i) % num_colors]];
}
- return VP8_ENC_OK;
+ return 1;
}
// -----------------------------------------------------------------------------
@@ -434,8 +438,8 @@ static int AnalyzeEntropy(const uint32_t* argb,
curr_row += argb_stride;
}
{
- double entropy_comp[kHistoTotal];
- double entropy[kNumEntropyIx];
+ float entropy_comp[kHistoTotal];
+ float entropy[kNumEntropyIx];
int k;
int last_mode_to_analyze = use_palette ? kPalette : kSpatialSubGreen;
int j;
@@ -949,11 +953,11 @@ static WEBP_INLINE void WriteHuffmanCodeWithExtraBits(
VP8LPutBits(bw, (bits << depth) | symbol, depth + n_bits);
}
-static WebPEncodingError StoreImageToBitMask(
+static int StoreImageToBitMask(
VP8LBitWriter* const bw, int width, int histo_bits,
const VP8LBackwardRefs* const refs,
const uint16_t* histogram_symbols,
- const HuffmanTreeCode* const huffman_codes) {
+ const HuffmanTreeCode* const huffman_codes, const WebPPicture* const pic) {
const int histo_xsize = histo_bits ? VP8LSubSampleSize(width, histo_bits) : 1;
const int tile_mask = (histo_bits == 0) ? 0 : -(1 << histo_bits);
// x and y trace the position in the image.
@@ -1006,44 +1010,53 @@ static WebPEncodingError StoreImageToBitMask(
}
VP8LRefsCursorNext(&c);
}
- return bw->error_ ? VP8_ENC_ERROR_OUT_OF_MEMORY : VP8_ENC_OK;
+ if (bw->error_) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ return 0;
+ }
+ return 1;
}
-// Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31
-static WebPEncodingError EncodeImageNoHuffman(
- VP8LBitWriter* const bw, const uint32_t* const argb,
- VP8LHashChain* const hash_chain, VP8LBackwardRefs* const refs_array,
- int width, int height, int quality, int low_effort) {
+// Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31.
+// pic and percent are for progress.
+static int EncodeImageNoHuffman(VP8LBitWriter* const bw,
+ const uint32_t* const argb,
+ VP8LHashChain* const hash_chain,
+ VP8LBackwardRefs* const refs_array, int width,
+ int height, int quality, int low_effort,
+ const WebPPicture* const pic, int percent_range,
+ int* const percent) {
int i;
int max_tokens = 0;
- WebPEncodingError err = VP8_ENC_OK;
VP8LBackwardRefs* refs;
HuffmanTreeToken* tokens = NULL;
- HuffmanTreeCode huffman_codes[5] = { { 0, NULL, NULL } };
- const uint16_t histogram_symbols[1] = { 0 }; // only one tree, one symbol
+ HuffmanTreeCode huffman_codes[5] = {{0, NULL, NULL}};
+ const uint16_t histogram_symbols[1] = {0}; // only one tree, one symbol
int cache_bits = 0;
VP8LHistogramSet* histogram_image = NULL;
HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc(
- 3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree));
+ 3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree));
if (huff_tree == NULL) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
// Calculate backward references from ARGB image.
- if (!VP8LHashChainFill(hash_chain, quality, argb, width, height,
- low_effort)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ if (!VP8LHashChainFill(hash_chain, quality, argb, width, height, low_effort,
+ pic, percent_range / 2, percent)) {
+ goto Error;
+ }
+ if (!VP8LGetBackwardReferences(width, height, argb, quality, /*low_effort=*/0,
+ kLZ77Standard | kLZ77RLE, cache_bits,
+ /*do_no_cache=*/0, hash_chain, refs_array,
+ &cache_bits, pic,
+ percent_range - percent_range / 2, percent)) {
goto Error;
}
- err = VP8LGetBackwardReferences(
- width, height, argb, quality, /*low_effort=*/0, kLZ77Standard | kLZ77RLE,
- cache_bits, /*do_no_cache=*/0, hash_chain, refs_array, &cache_bits);
- if (err != VP8_ENC_OK) goto Error;
refs = &refs_array[0];
histogram_image = VP8LAllocateHistogramSet(1, cache_bits);
if (histogram_image == NULL) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
VP8LHistogramSetClear(histogram_image);
@@ -1054,7 +1067,7 @@ static WebPEncodingError EncodeImageNoHuffman(
// Create Huffman bit lengths and codes for each histogram image.
assert(histogram_image->size == 1);
if (!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
@@ -1071,7 +1084,7 @@ static WebPEncodingError EncodeImageNoHuffman(
tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens, sizeof(*tokens));
if (tokens == NULL) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
@@ -1083,27 +1096,32 @@ static WebPEncodingError EncodeImageNoHuffman(
}
// Store actual literals.
- err = StoreImageToBitMask(bw, width, 0, refs, histogram_symbols,
- huffman_codes);
+ if (!StoreImageToBitMask(bw, width, 0, refs, histogram_symbols, huffman_codes,
+ pic)) {
+ goto Error;
+ }
Error:
WebPSafeFree(tokens);
WebPSafeFree(huff_tree);
VP8LFreeHistogramSet(histogram_image);
WebPSafeFree(huffman_codes[0].codes);
- return err;
+ return (pic->error_code == VP8_ENC_OK);
}
-static WebPEncodingError EncodeImageInternal(
+// pic and percent are for progress.
+static int EncodeImageInternal(
VP8LBitWriter* const bw, const uint32_t* const argb,
VP8LHashChain* const hash_chain, VP8LBackwardRefs refs_array[4], int width,
int height, int quality, int low_effort, int use_cache,
const CrunchConfig* const config, int* cache_bits, int histogram_bits,
- size_t init_byte_position, int* const hdr_size, int* const data_size) {
- WebPEncodingError err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ size_t init_byte_position, int* const hdr_size, int* const data_size,
+ const WebPPicture* const pic, int percent_range, int* const percent) {
const uint32_t histogram_image_xysize =
VP8LSubSampleSize(width, histogram_bits) *
VP8LSubSampleSize(height, histogram_bits);
+ int remaining_percent = percent_range;
+ int percent_start = *percent;
VP8LHistogramSet* histogram_image = NULL;
VP8LHistogram* tmp_histo = NULL;
int histogram_image_size = 0;
@@ -1112,9 +1130,8 @@ static WebPEncodingError EncodeImageInternal(
3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree));
HuffmanTreeToken* tokens = NULL;
HuffmanTreeCode* huffman_codes = NULL;
- uint16_t* const histogram_symbols =
- (uint16_t*)WebPSafeMalloc(histogram_image_xysize,
- sizeof(*histogram_symbols));
+ uint16_t* const histogram_symbols = (uint16_t*)WebPSafeMalloc(
+ histogram_image_xysize, sizeof(*histogram_symbols));
int sub_configs_idx;
int cache_bits_init, write_histogram_image;
VP8LBitWriter bw_init = *bw, bw_best;
@@ -1126,14 +1143,27 @@ static WebPEncodingError EncodeImageInternal(
assert(hdr_size != NULL);
assert(data_size != NULL);
- // Make sure we can allocate the different objects.
memset(&hash_chain_histogram, 0, sizeof(hash_chain_histogram));
+ if (!VP8LBitWriterInit(&bw_best, 0)) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ goto Error;
+ }
+
+ // Make sure we can allocate the different objects.
if (huff_tree == NULL || histogram_symbols == NULL ||
- !VP8LHashChainInit(&hash_chain_histogram, histogram_image_xysize) ||
- !VP8LHashChainFill(hash_chain, quality, argb, width, height,
- low_effort)) {
+ !VP8LHashChainInit(&hash_chain_histogram, histogram_image_xysize)) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ goto Error;
+ }
+
+ percent_range = remaining_percent / 5;
+ if (!VP8LHashChainFill(hash_chain, quality, argb, width, height,
+ low_effort, pic, percent_range, percent)) {
goto Error;
}
+ percent_start += percent_range;
+ remaining_percent -= percent_range;
+
if (use_cache) {
// If the value is different from zero, it has been set during the
// palette analysis.
@@ -1142,22 +1172,27 @@ static WebPEncodingError EncodeImageInternal(
cache_bits_init = 0;
}
// If several iterations will happen, clone into bw_best.
- if (!VP8LBitWriterInit(&bw_best, 0) ||
- ((config->sub_configs_size_ > 1 ||
- config->sub_configs_[0].do_no_cache_) &&
- !VP8LBitWriterClone(bw, &bw_best))) {
+ if ((config->sub_configs_size_ > 1 || config->sub_configs_[0].do_no_cache_) &&
+ !VP8LBitWriterClone(bw, &bw_best)) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
+
for (sub_configs_idx = 0; sub_configs_idx < config->sub_configs_size_;
++sub_configs_idx) {
const CrunchSubConfig* const sub_config =
&config->sub_configs_[sub_configs_idx];
int cache_bits_best, i_cache;
- err = VP8LGetBackwardReferences(width, height, argb, quality, low_effort,
- sub_config->lz77_, cache_bits_init,
- sub_config->do_no_cache_, hash_chain,
- &refs_array[0], &cache_bits_best);
- if (err != VP8_ENC_OK) goto Error;
+ int i_remaining_percent = remaining_percent / config->sub_configs_size_;
+ int i_percent_range = i_remaining_percent / 4;
+ i_remaining_percent -= i_percent_range;
+
+ if (!VP8LGetBackwardReferences(
+ width, height, argb, quality, low_effort, sub_config->lz77_,
+ cache_bits_init, sub_config->do_no_cache_, hash_chain,
+ &refs_array[0], &cache_bits_best, pic, i_percent_range, percent)) {
+ goto Error;
+ }
for (i_cache = 0; i_cache < (sub_config->do_no_cache_ ? 2 : 1); ++i_cache) {
const int cache_bits_tmp = (i_cache == 0) ? cache_bits_best : 0;
@@ -1172,11 +1207,17 @@ static WebPEncodingError EncodeImageInternal(
histogram_image =
VP8LAllocateHistogramSet(histogram_image_xysize, cache_bits_tmp);
tmp_histo = VP8LAllocateHistogram(cache_bits_tmp);
- if (histogram_image == NULL || tmp_histo == NULL ||
- !VP8LGetHistoImageSymbols(width, height, &refs_array[i_cache],
- quality, low_effort, histogram_bits,
- cache_bits_tmp, histogram_image, tmp_histo,
- histogram_symbols)) {
+ if (histogram_image == NULL || tmp_histo == NULL) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ goto Error;
+ }
+
+ i_percent_range = i_remaining_percent / 3;
+ i_remaining_percent -= i_percent_range;
+ if (!VP8LGetHistoImageSymbols(
+ width, height, &refs_array[i_cache], quality, low_effort,
+ histogram_bits, cache_bits_tmp, histogram_image, tmp_histo,
+ histogram_symbols, pic, i_percent_range, percent)) {
goto Error;
}
// Create Huffman bit lengths and codes for each histogram image.
@@ -1189,6 +1230,7 @@ static WebPEncodingError EncodeImageInternal(
// GetHuffBitLengthsAndCodes().
if (huffman_codes == NULL ||
!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
// Free combined histograms.
@@ -1211,12 +1253,14 @@ static WebPEncodingError EncodeImageInternal(
write_histogram_image = (histogram_image_size > 1);
VP8LPutBits(bw, write_histogram_image, 1);
if (write_histogram_image) {
- uint32_t* const histogram_argb =
- (uint32_t*)WebPSafeMalloc(histogram_image_xysize,
- sizeof(*histogram_argb));
+ uint32_t* const histogram_argb = (uint32_t*)WebPSafeMalloc(
+ histogram_image_xysize, sizeof(*histogram_argb));
int max_index = 0;
uint32_t i;
- if (histogram_argb == NULL) goto Error;
+ if (histogram_argb == NULL) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ goto Error;
+ }
for (i = 0; i < histogram_image_xysize; ++i) {
const int symbol_index = histogram_symbols[i] & 0xffff;
histogram_argb[i] = (symbol_index << 8);
@@ -1227,12 +1271,17 @@ static WebPEncodingError EncodeImageInternal(
histogram_image_size = max_index;
VP8LPutBits(bw, histogram_bits - 2, 3);
- err = EncodeImageNoHuffman(
- bw, histogram_argb, &hash_chain_histogram, &refs_array[2],
- VP8LSubSampleSize(width, histogram_bits),
- VP8LSubSampleSize(height, histogram_bits), quality, low_effort);
+ i_percent_range = i_remaining_percent / 2;
+ i_remaining_percent -= i_percent_range;
+ if (!EncodeImageNoHuffman(
+ bw, histogram_argb, &hash_chain_histogram, &refs_array[2],
+ VP8LSubSampleSize(width, histogram_bits),
+ VP8LSubSampleSize(height, histogram_bits), quality, low_effort,
+ pic, i_percent_range, percent)) {
+ WebPSafeFree(histogram_argb);
+ goto Error;
+ }
WebPSafeFree(histogram_argb);
- if (err != VP8_ENC_OK) goto Error;
}
// Store Huffman codes.
@@ -1256,9 +1305,10 @@ static WebPEncodingError EncodeImageInternal(
}
// Store actual literals.
hdr_size_tmp = (int)(VP8LBitWriterNumBytes(bw) - init_byte_position);
- err = StoreImageToBitMask(bw, width, histogram_bits, &refs_array[i_cache],
- histogram_symbols, huffman_codes);
- if (err != VP8_ENC_OK) goto Error;
+ if (!StoreImageToBitMask(bw, width, histogram_bits, &refs_array[i_cache],
+ histogram_symbols, huffman_codes, pic)) {
+ goto Error;
+ }
// Keep track of the smallest image so far.
if (VP8LBitWriterNumBytes(bw) < bw_size_best) {
bw_size_best = VP8LBitWriterNumBytes(bw);
@@ -1278,7 +1328,10 @@ static WebPEncodingError EncodeImageInternal(
}
}
VP8LBitWriterSwap(bw, &bw_best);
- err = VP8_ENC_OK;
+
+ if (!WebPReportProgress(pic, percent_start + remaining_percent, percent)) {
+ goto Error;
+ }
Error:
WebPSafeFree(tokens);
@@ -1292,7 +1345,7 @@ static WebPEncodingError EncodeImageInternal(
}
WebPSafeFree(histogram_symbols);
VP8LBitWriterWipeOut(&bw_best);
- return err;
+ return (pic->error_code == VP8_ENC_OK);
}
// -----------------------------------------------------------------------------
@@ -1305,22 +1358,23 @@ static void ApplySubtractGreen(VP8LEncoder* const enc, int width, int height,
VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height);
}
-static WebPEncodingError ApplyPredictFilter(const VP8LEncoder* const enc,
- int width, int height,
- int quality, int low_effort,
- int used_subtract_green,
- VP8LBitWriter* const bw) {
+static int ApplyPredictFilter(const VP8LEncoder* const enc, int width,
+ int height, int quality, int low_effort,
+ int used_subtract_green, VP8LBitWriter* const bw,
+ int percent_range, int* const percent) {
const int pred_bits = enc->transform_bits_;
const int transform_width = VP8LSubSampleSize(width, pred_bits);
const int transform_height = VP8LSubSampleSize(height, pred_bits);
// we disable near-lossless quantization if palette is used.
- const int near_lossless_strength = enc->use_palette_ ? 100
- : enc->config_->near_lossless;
+ const int near_lossless_strength =
+ enc->use_palette_ ? 100 : enc->config_->near_lossless;
- VP8LResidualImage(width, height, pred_bits, low_effort, enc->argb_,
- enc->argb_scratch_, enc->transform_data_,
- near_lossless_strength, enc->config_->exact,
- used_subtract_green);
+ if (!VP8LResidualImage(
+ width, height, pred_bits, low_effort, enc->argb_, enc->argb_scratch_,
+ enc->transform_data_, near_lossless_strength, enc->config_->exact,
+ used_subtract_green, enc->pic_, percent_range / 2, percent)) {
+ return 0;
+ }
VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2);
assert(pred_bits >= 2);
@@ -1328,19 +1382,23 @@ static WebPEncodingError ApplyPredictFilter(const VP8LEncoder* const enc,
return EncodeImageNoHuffman(
bw, enc->transform_data_, (VP8LHashChain*)&enc->hash_chain_,
(VP8LBackwardRefs*)&enc->refs_[0], transform_width, transform_height,
- quality, low_effort);
+ quality, low_effort, enc->pic_, percent_range - percent_range / 2,
+ percent);
}
-static WebPEncodingError ApplyCrossColorFilter(const VP8LEncoder* const enc,
- int width, int height,
- int quality, int low_effort,
- VP8LBitWriter* const bw) {
+static int ApplyCrossColorFilter(const VP8LEncoder* const enc, int width,
+ int height, int quality, int low_effort,
+ VP8LBitWriter* const bw, int percent_range,
+ int* const percent) {
const int ccolor_transform_bits = enc->transform_bits_;
const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits);
const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits);
- VP8LColorSpaceTransform(width, height, ccolor_transform_bits, quality,
- enc->argb_, enc->transform_data_);
+ if (!VP8LColorSpaceTransform(width, height, ccolor_transform_bits, quality,
+ enc->argb_, enc->transform_data_, enc->pic_,
+ percent_range / 2, percent)) {
+ return 0;
+ }
VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
VP8LPutBits(bw, CROSS_COLOR_TRANSFORM, 2);
assert(ccolor_transform_bits >= 2);
@@ -1348,23 +1406,21 @@ static WebPEncodingError ApplyCrossColorFilter(const VP8LEncoder* const enc,
return EncodeImageNoHuffman(
bw, enc->transform_data_, (VP8LHashChain*)&enc->hash_chain_,
(VP8LBackwardRefs*)&enc->refs_[0], transform_width, transform_height,
- quality, low_effort);
+ quality, low_effort, enc->pic_, percent_range - percent_range / 2,
+ percent);
}
// -----------------------------------------------------------------------------
-static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic,
- size_t riff_size, size_t vp8l_size) {
+static int WriteRiffHeader(const WebPPicture* const pic, size_t riff_size,
+ size_t vp8l_size) {
uint8_t riff[RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8L_SIGNATURE_SIZE] = {
'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P',
'V', 'P', '8', 'L', 0, 0, 0, 0, VP8L_MAGIC_BYTE,
};
PutLE32(riff + TAG_SIZE, (uint32_t)riff_size);
PutLE32(riff + RIFF_HEADER_SIZE + TAG_SIZE, (uint32_t)vp8l_size);
- if (!pic->writer(riff, sizeof(riff), pic)) {
- return VP8_ENC_ERROR_BAD_WRITE;
- }
- return VP8_ENC_OK;
+ return pic->writer(riff, sizeof(riff), pic);
}
static int WriteImageSize(const WebPPicture* const pic,
@@ -1384,36 +1440,29 @@ static int WriteRealAlphaAndVersion(VP8LBitWriter* const bw, int has_alpha) {
return !bw->error_;
}
-static WebPEncodingError WriteImage(const WebPPicture* const pic,
- VP8LBitWriter* const bw,
- size_t* const coded_size) {
- WebPEncodingError err = VP8_ENC_OK;
+static int WriteImage(const WebPPicture* const pic, VP8LBitWriter* const bw,
+ size_t* const coded_size) {
const uint8_t* const webpll_data = VP8LBitWriterFinish(bw);
const size_t webpll_size = VP8LBitWriterNumBytes(bw);
const size_t vp8l_size = VP8L_SIGNATURE_SIZE + webpll_size;
const size_t pad = vp8l_size & 1;
const size_t riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8l_size + pad;
- err = WriteRiffHeader(pic, riff_size, vp8l_size);
- if (err != VP8_ENC_OK) goto Error;
-
- if (!pic->writer(webpll_data, webpll_size, pic)) {
- err = VP8_ENC_ERROR_BAD_WRITE;
- goto Error;
+ if (!WriteRiffHeader(pic, riff_size, vp8l_size) ||
+ !pic->writer(webpll_data, webpll_size, pic)) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE);
+ return 0;
}
if (pad) {
const uint8_t pad_byte[1] = { 0 };
if (!pic->writer(pad_byte, 1, pic)) {
- err = VP8_ENC_ERROR_BAD_WRITE;
- goto Error;
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_WRITE);
+ return 0;
}
}
*coded_size = CHUNK_HEADER_SIZE + riff_size;
- return VP8_ENC_OK;
-
- Error:
- return err;
+ return 1;
}
// -----------------------------------------------------------------------------
@@ -1429,18 +1478,16 @@ static void ClearTransformBuffer(VP8LEncoder* const enc) {
// Flags influencing the memory allocated:
// enc->transform_bits_
// enc->use_predict_, enc->use_cross_color_
-static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc,
- int width, int height) {
- WebPEncodingError err = VP8_ENC_OK;
+static int AllocateTransformBuffer(VP8LEncoder* const enc, int width,
+ int height) {
const uint64_t image_size = width * height;
// VP8LResidualImage needs room for 2 scanlines of uint32 pixels with an extra
// pixel in each, plus 2 regular scanlines of bytes.
// TODO(skal): Clean up by using arithmetic in bytes instead of words.
const uint64_t argb_scratch_size =
- enc->use_predict_
- ? (width + 1) * 2 +
- (width * 2 + sizeof(uint32_t) - 1) / sizeof(uint32_t)
- : 0;
+ enc->use_predict_ ? (width + 1) * 2 + (width * 2 + sizeof(uint32_t) - 1) /
+ sizeof(uint32_t)
+ : 0;
const uint64_t transform_data_size =
(enc->use_predict_ || enc->use_cross_color_)
? VP8LSubSampleSize(width, enc->transform_bits_) *
@@ -1448,17 +1495,16 @@ static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc,
: 0;
const uint64_t max_alignment_in_words =
(WEBP_ALIGN_CST + sizeof(uint32_t) - 1) / sizeof(uint32_t);
- const uint64_t mem_size =
- image_size + max_alignment_in_words +
- argb_scratch_size + max_alignment_in_words +
- transform_data_size;
+ const uint64_t mem_size = image_size + max_alignment_in_words +
+ argb_scratch_size + max_alignment_in_words +
+ transform_data_size;
uint32_t* mem = enc->transform_mem_;
if (mem == NULL || mem_size > enc->transform_mem_size_) {
ClearTransformBuffer(enc);
mem = (uint32_t*)WebPSafeMalloc(mem_size, sizeof(*mem));
if (mem == NULL) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
- goto Error;
+ WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ return 0;
}
enc->transform_mem_ = mem;
enc->transform_mem_size_ = (size_t)mem_size;
@@ -1471,19 +1517,16 @@ static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc,
enc->transform_data_ = mem;
enc->current_width_ = width;
- Error:
- return err;
+ return 1;
}
-static WebPEncodingError MakeInputImageCopy(VP8LEncoder* const enc) {
- WebPEncodingError err = VP8_ENC_OK;
+static int MakeInputImageCopy(VP8LEncoder* const enc) {
const WebPPicture* const picture = enc->pic_;
const int width = picture->width;
const int height = picture->height;
- err = AllocateTransformBuffer(enc, width, height);
- if (err != VP8_ENC_OK) return err;
- if (enc->argb_content_ == kEncoderARGB) return VP8_ENC_OK;
+ if (!AllocateTransformBuffer(enc, width, height)) return 0;
+ if (enc->argb_content_ == kEncoderARGB) return 1;
{
uint32_t* dst = enc->argb_;
@@ -1497,7 +1540,7 @@ static WebPEncodingError MakeInputImageCopy(VP8LEncoder* const enc) {
}
enc->argb_content_ = kEncoderARGB;
assert(enc->current_width_ == width);
- return VP8_ENC_OK;
+ return 1;
}
// -----------------------------------------------------------------------------
@@ -1559,16 +1602,19 @@ static WEBP_INLINE uint32_t ApplyPaletteHash2(uint32_t color) {
// using 'row' as a temporary buffer of size 'width'.
// We assume that all src[] values have a corresponding entry in the palette.
// Note: src[] can be the same as dst[]
-static WebPEncodingError ApplyPalette(const uint32_t* src, uint32_t src_stride,
- uint32_t* dst, uint32_t dst_stride,
- const uint32_t* palette, int palette_size,
- int width, int height, int xbits) {
+static int ApplyPalette(const uint32_t* src, uint32_t src_stride, uint32_t* dst,
+ uint32_t dst_stride, const uint32_t* palette,
+ int palette_size, int width, int height, int xbits,
+ const WebPPicture* const pic) {
// TODO(skal): this tmp buffer is not needed if VP8LBundleColorMap() can be
// made to work in-place.
uint8_t* const tmp_row = (uint8_t*)WebPSafeMalloc(width, sizeof(*tmp_row));
int x, y;
- if (tmp_row == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
+ if (tmp_row == NULL) {
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ return 0;
+ }
if (palette_size < APPLY_PALETTE_GREEDY_MAX) {
APPLY_PALETTE_FOR(SearchColorGreedy(palette, palette_size, pix));
@@ -1613,7 +1659,7 @@ static WebPEncodingError ApplyPalette(const uint32_t* src, uint32_t src_stride,
}
}
WebPSafeFree(tmp_row);
- return VP8_ENC_OK;
+ return 1;
}
#undef APPLY_PALETTE_FOR
#undef PALETTE_INV_SIZE_BITS
@@ -1621,9 +1667,7 @@ static WebPEncodingError ApplyPalette(const uint32_t* src, uint32_t src_stride,
#undef APPLY_PALETTE_GREEDY_MAX
// Note: Expects "enc->palette_" to be set properly.
-static WebPEncodingError MapImageFromPalette(VP8LEncoder* const enc,
- int in_place) {
- WebPEncodingError err = VP8_ENC_OK;
+static int MapImageFromPalette(VP8LEncoder* const enc, int in_place) {
const WebPPicture* const pic = enc->pic_;
const int width = pic->width;
const int height = pic->height;
@@ -1641,19 +1685,22 @@ static WebPEncodingError MapImageFromPalette(VP8LEncoder* const enc,
xbits = (palette_size <= 16) ? 1 : 0;
}
- err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height);
- if (err != VP8_ENC_OK) return err;
-
- err = ApplyPalette(src, src_stride,
+ if (!AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height)) {
+ return 0;
+ }
+ if (!ApplyPalette(src, src_stride,
enc->argb_, enc->current_width_,
- palette, palette_size, width, height, xbits);
+ palette, palette_size, width, height, xbits, pic)) {
+ return 0;
+ }
enc->argb_content_ = kEncoderPalette;
- return err;
+ return 1;
}
// Save palette_[] to bitstream.
static WebPEncodingError EncodePalette(VP8LBitWriter* const bw, int low_effort,
- VP8LEncoder* const enc) {
+ VP8LEncoder* const enc,
+ int percent_range, int* const percent) {
int i;
uint32_t tmp_palette[MAX_PALETTE_SIZE];
const int palette_size = enc->palette_size_;
@@ -1668,7 +1715,7 @@ static WebPEncodingError EncodePalette(VP8LBitWriter* const bw, int low_effort,
tmp_palette[0] = palette[0];
return EncodeImageNoHuffman(bw, tmp_palette, &enc->hash_chain_,
&enc->refs_[0], palette_size, 1, /*quality=*/20,
- low_effort);
+ low_effort, enc->pic_, percent_range, percent);
}
// -----------------------------------------------------------------------------
@@ -1712,7 +1759,6 @@ typedef struct {
CrunchConfig crunch_configs_[CRUNCH_CONFIGS_MAX];
int num_crunch_configs_;
int red_and_blue_always_zero_;
- WebPEncodingError err_;
WebPAuxStats* stats_;
} StreamEncodeContext;
@@ -1729,7 +1775,6 @@ static int EncodeStreamHook(void* input, void* data2) {
#if !defined(WEBP_DISABLE_STATS)
WebPAuxStats* const stats = params->stats_;
#endif
- WebPEncodingError err = VP8_ENC_OK;
const int quality = (int)config->quality;
const int low_effort = (config->method == 0);
#if (WEBP_NEAR_LOSSLESS == 1)
@@ -1737,6 +1782,7 @@ static int EncodeStreamHook(void* input, void* data2) {
#endif
const int height = picture->height;
const size_t byte_position = VP8LBitWriterNumBytes(bw);
+ int percent = 2; // for WebPProgressHook
#if (WEBP_NEAR_LOSSLESS == 1)
int use_near_lossless = 0;
#endif
@@ -1750,12 +1796,13 @@ static int EncodeStreamHook(void* input, void* data2) {
if (!VP8LBitWriterInit(&bw_best, 0) ||
(num_crunch_configs > 1 && !VP8LBitWriterClone(bw, &bw_best))) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
for (idx = 0; idx < num_crunch_configs; ++idx) {
const int entropy_idx = crunch_configs[idx].entropy_idx_;
+ int remaining_percent = 97 / num_crunch_configs, percent_range;
enc->use_palette_ =
(entropy_idx == kPalette) || (entropy_idx == kPaletteAndSpatial);
enc->use_subtract_green_ =
@@ -1779,11 +1826,10 @@ static int EncodeStreamHook(void* input, void* data2) {
use_near_lossless = (config->near_lossless < 100) && !enc->use_palette_ &&
!enc->use_predict_;
if (use_near_lossless) {
- err = AllocateTransformBuffer(enc, width, height);
- if (err != VP8_ENC_OK) goto Error;
+ if (!AllocateTransformBuffer(enc, width, height)) goto Error;
if ((enc->argb_content_ != kEncoderNearLossless) &&
!VP8ApplyNearLossless(picture, config->near_lossless, enc->argb_)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
enc->argb_content_ = kEncoderNearLossless;
@@ -1805,14 +1851,17 @@ static int EncodeStreamHook(void* input, void* data2) {
enc->palette_);
} else {
assert(crunch_configs[idx].palette_sorting_type_ == kModifiedZeng);
- err = PaletteSortModifiedZeng(enc->pic_, enc->palette_sorted_,
- enc->palette_size_, enc->palette_);
- if (err != VP8_ENC_OK) goto Error;
+ if (!PaletteSortModifiedZeng(enc->pic_, enc->palette_sorted_,
+ enc->palette_size_, enc->palette_)) {
+ goto Error;
+ }
}
- err = EncodePalette(bw, low_effort, enc);
- if (err != VP8_ENC_OK) goto Error;
- err = MapImageFromPalette(enc, use_delta_palette);
- if (err != VP8_ENC_OK) goto Error;
+ percent_range = remaining_percent / 4;
+ if (!EncodePalette(bw, low_effort, enc, percent_range, &percent)) {
+ goto Error;
+ }
+ remaining_percent -= percent_range;
+ if (!MapImageFromPalette(enc, use_delta_palette)) goto Error;
// If using a color cache, do not have it bigger than the number of
// colors.
if (use_cache && enc->palette_size_ < (1 << MAX_COLOR_CACHE_BITS)) {
@@ -1823,8 +1872,7 @@ static int EncodeStreamHook(void* input, void* data2) {
// In case image is not packed.
if (enc->argb_content_ != kEncoderNearLossless &&
enc->argb_content_ != kEncoderPalette) {
- err = MakeInputImageCopy(enc);
- if (err != VP8_ENC_OK) goto Error;
+ if (!MakeInputImageCopy(enc)) goto Error;
}
// -----------------------------------------------------------------------
@@ -1835,15 +1883,22 @@ static int EncodeStreamHook(void* input, void* data2) {
}
if (enc->use_predict_) {
- err = ApplyPredictFilter(enc, enc->current_width_, height, quality,
- low_effort, enc->use_subtract_green_, bw);
- if (err != VP8_ENC_OK) goto Error;
+ percent_range = remaining_percent / 3;
+ if (!ApplyPredictFilter(enc, enc->current_width_, height, quality,
+ low_effort, enc->use_subtract_green_, bw,
+ percent_range, &percent)) {
+ goto Error;
+ }
+ remaining_percent -= percent_range;
}
if (enc->use_cross_color_) {
- err = ApplyCrossColorFilter(enc, enc->current_width_, height, quality,
- low_effort, bw);
- if (err != VP8_ENC_OK) goto Error;
+ percent_range = remaining_percent / 2;
+ if (!ApplyCrossColorFilter(enc, enc->current_width_, height, quality,
+ low_effort, bw, percent_range, &percent)) {
+ goto Error;
+ }
+ remaining_percent -= percent_range;
}
}
@@ -1851,12 +1906,13 @@ static int EncodeStreamHook(void* input, void* data2) {
// -------------------------------------------------------------------------
// Encode and write the transformed image.
- err = EncodeImageInternal(bw, enc->argb_, &enc->hash_chain_, enc->refs_,
- enc->current_width_, height, quality, low_effort,
- use_cache, &crunch_configs[idx],
- &enc->cache_bits_, enc->histo_bits_,
- byte_position, &hdr_size, &data_size);
- if (err != VP8_ENC_OK) goto Error;
+ if (!EncodeImageInternal(
+ bw, enc->argb_, &enc->hash_chain_, enc->refs_, enc->current_width_,
+ height, quality, low_effort, use_cache, &crunch_configs[idx],
+ &enc->cache_bits_, enc->histo_bits_, byte_position, &hdr_size,
+ &data_size, picture, remaining_percent, &percent)) {
+ goto Error;
+ }
// If we are better than what we already have.
if (VP8LBitWriterNumBytes(bw) < best_size) {
@@ -1886,18 +1942,15 @@ static int EncodeStreamHook(void* input, void* data2) {
}
VP8LBitWriterSwap(&bw_best, bw);
-Error:
+ Error:
VP8LBitWriterWipeOut(&bw_best);
- params->err_ = err;
// The hook should return false in case of error.
- return (err == VP8_ENC_OK);
+ return (params->picture_->error_code == VP8_ENC_OK);
}
-WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
- const WebPPicture* const picture,
- VP8LBitWriter* const bw_main,
- int use_cache) {
- WebPEncodingError err = VP8_ENC_OK;
+int VP8LEncodeStream(const WebPConfig* const config,
+ const WebPPicture* const picture,
+ VP8LBitWriter* const bw_main, int use_cache) {
VP8LEncoder* const enc_main = VP8LEncoderNew(config, picture);
VP8LEncoder* enc_side = NULL;
CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX];
@@ -1909,15 +1962,24 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
// The main thread uses picture->stats, the side thread uses stats_side.
WebPAuxStats stats_side;
VP8LBitWriter bw_side;
+ WebPPicture picture_side;
const WebPWorkerInterface* const worker_interface = WebPGetWorkerInterface();
int ok_main;
+ if (enc_main == NULL || !VP8LBitWriterInit(&bw_side, 0)) {
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ VP8LEncoderDelete(enc_main);
+ return 0;
+ }
+
+ // Avoid "garbage value" error from Clang's static analysis tool.
+ WebPPictureInit(&picture_side);
+
// Analyze image (entropy, num_palettes etc)
- if (enc_main == NULL ||
- !EncoderAnalyze(enc_main, crunch_configs, &num_crunch_configs_main,
+ if (!EncoderAnalyze(enc_main, crunch_configs, &num_crunch_configs_main,
&red_and_blue_always_zero) ||
- !EncoderInit(enc_main) || !VP8LBitWriterInit(&bw_side, 0)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ !EncoderInit(enc_main)) {
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
@@ -1946,25 +2008,32 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
StreamEncodeContext* const param =
(idx == 0) ? &params_main : &params_side;
param->config_ = config;
- param->picture_ = picture;
param->use_cache_ = use_cache;
param->red_and_blue_always_zero_ = red_and_blue_always_zero;
if (idx == 0) {
+ param->picture_ = picture;
param->stats_ = picture->stats;
param->bw_ = bw_main;
param->enc_ = enc_main;
} else {
+ // Create a side picture (error_code is not thread-safe).
+ if (!WebPPictureView(picture, /*left=*/0, /*top=*/0, picture->width,
+ picture->height, &picture_side)) {
+ assert(0);
+ }
+ picture_side.progress_hook = NULL; // Progress hook is not thread-safe.
+ param->picture_ = &picture_side; // No need to free a view afterwards.
param->stats_ = (picture->stats == NULL) ? NULL : &stats_side;
// Create a side bit writer.
if (!VP8LBitWriterClone(bw_main, &bw_side)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
param->bw_ = &bw_side;
// Create a side encoder.
- enc_side = VP8LEncoderNew(config, picture);
+ enc_side = VP8LEncoderNew(config, &picture_side);
if (enc_side == NULL || !EncoderInit(enc_side)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
// Copy the values that were computed for the main encoder.
@@ -1988,7 +2057,7 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
// Start the second thread if needed.
if (num_crunch_configs_side != 0) {
if (!worker_interface->Reset(&worker_side)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
#if !defined(WEBP_DISABLE_STATS)
@@ -1998,8 +2067,6 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
memcpy(&stats_side, picture->stats, sizeof(stats_side));
}
#endif
- // This line is only useful to remove a Clang static analyzer warning.
- params_side.err_ = VP8_ENC_OK;
worker_interface->Launch(&worker_side);
}
// Execute the main thread.
@@ -2011,7 +2078,10 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
const int ok_side = worker_interface->Sync(&worker_side);
worker_interface->End(&worker_side);
if (!ok_main || !ok_side) {
- err = ok_main ? params_side.err_ : params_main.err_;
+ if (picture->error_code == VP8_ENC_OK) {
+ assert(picture_side.error_code != VP8_ENC_OK);
+ WebPEncodingSetError(picture, picture_side.error_code);
+ }
goto Error;
}
if (VP8LBitWriterNumBytes(&bw_side) < VP8LBitWriterNumBytes(bw_main)) {
@@ -2022,18 +2092,13 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
}
#endif
}
- } else {
- if (!ok_main) {
- err = params_main.err_;
- goto Error;
- }
}
-Error:
+ Error:
VP8LBitWriterWipeOut(&bw_side);
VP8LEncoderDelete(enc_main);
VP8LEncoderDelete(enc_side);
- return err;
+ return (picture->error_code == VP8_ENC_OK);
}
#undef CRUNCH_CONFIGS_MAX
@@ -2046,14 +2111,12 @@ int VP8LEncodeImage(const WebPConfig* const config,
size_t coded_size;
int percent = 0;
int initial_size;
- WebPEncodingError err = VP8_ENC_OK;
VP8LBitWriter bw;
if (picture == NULL) return 0;
if (config == NULL || picture->argb == NULL) {
- err = VP8_ENC_ERROR_NULL_PARAMETER;
- WebPEncodingSetError(picture, err);
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
return 0;
}
@@ -2064,13 +2127,13 @@ int VP8LEncodeImage(const WebPConfig* const config,
initial_size = (config->image_hint == WEBP_HINT_GRAPH) ?
width * height : width * height * 2;
if (!VP8LBitWriterInit(&bw, initial_size)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
if (!WebPReportProgress(picture, 1, &percent)) {
UserAbort:
- err = VP8_ENC_ERROR_USER_ABORT;
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_USER_ABORT);
goto Error;
}
// Reset stats (for pure lossless coding)
@@ -2086,28 +2149,26 @@ int VP8LEncodeImage(const WebPConfig* const config,
// Write image size.
if (!WriteImageSize(picture, &bw)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
has_alpha = WebPPictureHasTransparency(picture);
// Write the non-trivial Alpha flag and lossless version.
if (!WriteRealAlphaAndVersion(&bw, has_alpha)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
goto Error;
}
- if (!WebPReportProgress(picture, 5, &percent)) goto UserAbort;
+ if (!WebPReportProgress(picture, 2, &percent)) goto UserAbort;
// Encode main image stream.
- err = VP8LEncodeStream(config, picture, &bw, 1 /*use_cache*/);
- if (err != VP8_ENC_OK) goto Error;
+ if (!VP8LEncodeStream(config, picture, &bw, 1 /*use_cache*/)) goto Error;
- if (!WebPReportProgress(picture, 90, &percent)) goto UserAbort;
+ if (!WebPReportProgress(picture, 99, &percent)) goto UserAbort;
// Finish the RIFF chunk.
- err = WriteImage(picture, &bw, &coded_size);
- if (err != VP8_ENC_OK) goto Error;
+ if (!WriteImage(picture, &bw, &coded_size)) goto Error;
if (!WebPReportProgress(picture, 100, &percent)) goto UserAbort;
@@ -2126,13 +2187,11 @@ int VP8LEncodeImage(const WebPConfig* const config,
}
Error:
- if (bw.error_) err = VP8_ENC_ERROR_OUT_OF_MEMORY;
- VP8LBitWriterWipeOut(&bw);
- if (err != VP8_ENC_OK) {
- WebPEncodingSetError(picture, err);
- return 0;
+ if (bw.error_) {
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
- return 1;
+ VP8LBitWriterWipeOut(&bw);
+ return (picture->error_code == VP8_ENC_OK);
}
//------------------------------------------------------------------------------
diff --git a/thirdparty/libwebp/src/enc/vp8li_enc.h b/thirdparty/libwebp/src/enc/vp8li_enc.h
index 00de48946c..3d35e1612d 100644
--- a/thirdparty/libwebp/src/enc/vp8li_enc.h
+++ b/thirdparty/libwebp/src/enc/vp8li_enc.h
@@ -89,9 +89,10 @@ int VP8LEncodeImage(const WebPConfig* const config,
// Encodes the main image stream using the supplied bit writer.
// If 'use_cache' is false, disables the use of color cache.
-WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
- const WebPPicture* const picture,
- VP8LBitWriter* const bw, int use_cache);
+// Returns false in case of error (stored in picture->error_code).
+int VP8LEncodeStream(const WebPConfig* const config,
+ const WebPPicture* const picture, VP8LBitWriter* const bw,
+ int use_cache);
#if (WEBP_NEAR_LOSSLESS == 1)
// in near_lossless.c
@@ -103,13 +104,18 @@ int VP8ApplyNearLossless(const WebPPicture* const picture, int quality,
//------------------------------------------------------------------------------
// Image transforms in predictor.c.
-void VP8LResidualImage(int width, int height, int bits, int low_effort,
- uint32_t* const argb, uint32_t* const argb_scratch,
- uint32_t* const image, int near_lossless, int exact,
- int used_subtract_green);
-
-void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
- uint32_t* const argb, uint32_t* image);
+// pic and percent are for progress.
+// Returns false in case of error (stored in pic->error_code).
+int VP8LResidualImage(int width, int height, int bits, int low_effort,
+ uint32_t* const argb, uint32_t* const argb_scratch,
+ uint32_t* const image, int near_lossless, int exact,
+ int used_subtract_green, const WebPPicture* const pic,
+ int percent_range, int* const percent);
+
+int VP8LColorSpaceTransform(int width, int height, int bits, int quality,
+ uint32_t* const argb, uint32_t* image,
+ const WebPPicture* const pic, int percent_range,
+ int* const percent);
//------------------------------------------------------------------------------
diff --git a/thirdparty/libwebp/src/enc/webp_enc.c b/thirdparty/libwebp/src/enc/webp_enc.c
index ce2db2e94b..9620e05070 100644
--- a/thirdparty/libwebp/src/enc/webp_enc.c
+++ b/thirdparty/libwebp/src/enc/webp_enc.c
@@ -336,9 +336,7 @@ int WebPEncode(const WebPConfig* config, WebPPicture* pic) {
if (!WebPValidateConfig(config)) {
return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION);
}
- if (pic->width <= 0 || pic->height <= 0) {
- return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION);
- }
+ if (!WebPValidatePicture(pic)) return 0;
if (pic->width > WEBP_MAX_DIMENSION || pic->height > WEBP_MAX_DIMENSION) {
return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION);
}
diff --git a/thirdparty/libwebp/src/mux/muxedit.c b/thirdparty/libwebp/src/mux/muxedit.c
index 02c3edecd7..63e71a0aba 100644
--- a/thirdparty/libwebp/src/mux/muxedit.c
+++ b/thirdparty/libwebp/src/mux/muxedit.c
@@ -70,6 +70,7 @@ void WebPMuxDelete(WebPMux* mux) {
err = ChunkAssignData(&chunk, data, copy_data, tag); \
if (err == WEBP_MUX_OK) { \
err = ChunkSetHead(&chunk, (LIST)); \
+ if (err != WEBP_MUX_OK) ChunkRelease(&chunk); \
} \
return err; \
}
diff --git a/thirdparty/libwebp/src/mux/muxi.h b/thirdparty/libwebp/src/mux/muxi.h
index d9bf9b3770..0f4af1784d 100644
--- a/thirdparty/libwebp/src/mux/muxi.h
+++ b/thirdparty/libwebp/src/mux/muxi.h
@@ -29,7 +29,7 @@ extern "C" {
#define MUX_MAJ_VERSION 1
#define MUX_MIN_VERSION 2
-#define MUX_REV_VERSION 2
+#define MUX_REV_VERSION 4
// Chunk object.
typedef struct WebPChunk WebPChunk;
diff --git a/thirdparty/libwebp/src/mux/muxinternal.c b/thirdparty/libwebp/src/mux/muxinternal.c
index b9ee6717d3..75b6b416b9 100644
--- a/thirdparty/libwebp/src/mux/muxinternal.c
+++ b/thirdparty/libwebp/src/mux/muxinternal.c
@@ -155,17 +155,18 @@ WebPMuxError ChunkSetHead(WebPChunk* const chunk,
WebPMuxError ChunkAppend(WebPChunk* const chunk,
WebPChunk*** const chunk_list) {
+ WebPMuxError err;
assert(chunk_list != NULL && *chunk_list != NULL);
if (**chunk_list == NULL) {
- ChunkSetHead(chunk, *chunk_list);
+ err = ChunkSetHead(chunk, *chunk_list);
} else {
WebPChunk* last_chunk = **chunk_list;
while (last_chunk->next_ != NULL) last_chunk = last_chunk->next_;
- ChunkSetHead(chunk, &last_chunk->next_);
- *chunk_list = &last_chunk->next_;
+ err = ChunkSetHead(chunk, &last_chunk->next_);
+ if (err == WEBP_MUX_OK) *chunk_list = &last_chunk->next_;
}
- return WEBP_MUX_OK;
+ return err;
}
//------------------------------------------------------------------------------
diff --git a/thirdparty/libwebp/src/webp/encode.h b/thirdparty/libwebp/src/webp/encode.h
index b4c599df87..56b68e2f10 100644
--- a/thirdparty/libwebp/src/webp/encode.h
+++ b/thirdparty/libwebp/src/webp/encode.h
@@ -441,7 +441,7 @@ WEBP_EXTERN int WebPPictureCrop(WebPPicture* picture,
// the original dimension will be lost). Picture 'dst' need not be initialized
// with WebPPictureInit() if it is different from 'src', since its content will
// be overwritten.
-// Returns false in case of memory allocation error or invalid parameters.
+// Returns false in case of invalid parameters.
WEBP_EXTERN int WebPPictureView(const WebPPicture* src,
int left, int top, int width, int height,
WebPPicture* dst);
@@ -455,7 +455,7 @@ WEBP_EXTERN int WebPPictureIsView(const WebPPicture* picture);
// dimension will be calculated preserving the aspect ratio.
// No gamma correction is applied.
// Returns false in case of error (invalid parameter or insufficient memory).
-WEBP_EXTERN int WebPPictureRescale(WebPPicture* pic, int width, int height);
+WEBP_EXTERN int WebPPictureRescale(WebPPicture* picture, int width, int height);
// Colorspace conversion function to import RGB samples.
// Previous buffer will be free'd, if any.
@@ -526,7 +526,7 @@ WEBP_EXTERN int WebPPictureHasTransparency(const WebPPicture* picture);
// Remove the transparency information (if present) by blending the color with
// the background color 'background_rgb' (specified as 24bit RGB triplet).
// After this call, all alpha values are reset to 0xff.
-WEBP_EXTERN void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb);
+WEBP_EXTERN void WebPBlendAlpha(WebPPicture* picture, uint32_t background_rgb);
//------------------------------------------------------------------------------
// Main call
diff --git a/thirdparty/mbedtls/library/timing.c b/thirdparty/mbedtls/library/timing.c
index 57bc9bcc12..78bfa10cfb 100644
--- a/thirdparty/mbedtls/library/timing.c
+++ b/thirdparty/mbedtls/library/timing.c
@@ -195,8 +195,10 @@ unsigned long mbedtls_timing_hardclock( void )
#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM &&
__GNUC__ && __ia64__ */
-#if !defined(HAVE_HARDCLOCK) && defined(_MSC_VER) && \
+// -- GODOT start --
+#if !defined(HAVE_HARDCLOCK) && defined(_WIN32) && \
!defined(EFIX64) && !defined(EFI32)
+// -- GODOT end --
#define HAVE_HARDCLOCK
diff --git a/thirdparty/minimp3/minimp3.h b/thirdparty/minimp3/minimp3.h
index 3220ae1a85..2a9975cc86 100644
--- a/thirdparty/minimp3/minimp3.h
+++ b/thirdparty/minimp3/minimp3.h
@@ -1566,7 +1566,18 @@ static void mp3d_synth(float *xl, mp3d_sample_t *dstl, int nch, float *lins)
#else /* MINIMP3_FLOAT_OUTPUT */
+// -- GODOT start --
+#if defined(_MSC_VER) && (defined(_M_ARM64) || defined(_M_ARM64EC) || defined(_M_ARM))
+ static f4 g_scale;
+ g_scale = vsetq_lane_f32(1.0f/32768.0f, g_scale, 0);
+ g_scale = vsetq_lane_f32(1.0f/32768.0f, g_scale, 1);
+ g_scale = vsetq_lane_f32(1.0f/32768.0f, g_scale, 2);
+ g_scale = vsetq_lane_f32(1.0f/32768.0f, g_scale, 3);
+#else
static const f4 g_scale = { 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f };
+#endif
+// -- GODOT end --
+
a = VMUL(a, g_scale);
b = VMUL(b, g_scale);
#if HAVE_SSE
@@ -1813,7 +1824,19 @@ void mp3dec_f32_to_s16(const float *in, int16_t *out, int num_samples)
int aligned_count = num_samples & ~7;
for(; i < aligned_count; i += 8)
{
+
+// -- GODOT start --
+#if defined(_MSC_VER) && (defined(_M_ARM64) || defined(_M_ARM64EC) || defined(_M_ARM))
+ static f4 g_scale;
+ g_scale = vsetq_lane_f32(32768.0f, g_scale, 0);
+ g_scale = vsetq_lane_f32(32768.0f, g_scale, 1);
+ g_scale = vsetq_lane_f32(32768.0f, g_scale, 2);
+ g_scale = vsetq_lane_f32(32768.0f, g_scale, 3);
+#else
static const f4 g_scale = { 32768.0f, 32768.0f, 32768.0f, 32768.0f };
+#endif
+// -- GODOT end --
+
f4 a = VMUL(VLD(&in[i ]), g_scale);
f4 b = VMUL(VLD(&in[i+4]), g_scale);
#if HAVE_SSE
diff --git a/thirdparty/spirv-reflect/include/spirv/unified1/spirv.h b/thirdparty/spirv-reflect/include/spirv/unified1/spirv.h
index c15736e255..ae81f141c4 100644
--- a/thirdparty/spirv-reflect/include/spirv/unified1/spirv.h
+++ b/thirdparty/spirv-reflect/include/spirv/unified1/spirv.h
@@ -70,6 +70,7 @@ typedef enum SpvSourceLanguage_ {
SpvSourceLanguageOpenCL_CPP = 4,
SpvSourceLanguageHLSL = 5,
SpvSourceLanguageCPP_for_OpenCL = 6,
+ SpvSourceLanguageSYCL = 7,
SpvSourceLanguageMax = 0x7fffffff,
} SpvSourceLanguage;
@@ -184,6 +185,7 @@ typedef enum SpvExecutionMode_ {
SpvExecutionModeNoGlobalOffsetINTEL = 5895,
SpvExecutionModeNumSIMDWorkitemsINTEL = 5896,
SpvExecutionModeSchedulerTargetFmaxMhzINTEL = 5903,
+ SpvExecutionModeNamedBarrierCountINTEL = 6417,
SpvExecutionModeMax = 0x7fffffff,
} SpvExecutionMode;
@@ -546,6 +548,8 @@ typedef enum SpvDecoration_ {
SpvDecorationPrefetchINTEL = 5902,
SpvDecorationStallEnableINTEL = 5905,
SpvDecorationFuseLoopsInFunctionINTEL = 5907,
+ SpvDecorationAliasScopeINTEL = 5914,
+ SpvDecorationNoAliasINTEL = 5915,
SpvDecorationBufferLocationINTEL = 5921,
SpvDecorationIOPipeStorageINTEL = 5944,
SpvDecorationFunctionFloatingPointModeINTEL = 6080,
@@ -677,6 +681,7 @@ typedef enum SpvBuiltIn_ {
SpvBuiltInSMCountNV = 5375,
SpvBuiltInWarpIDNV = 5376,
SpvBuiltInSMIDNV = 5377,
+ SpvBuiltInCullMaskKHR = 6021,
SpvBuiltInMax = 0x7fffffff,
} SpvBuiltIn;
@@ -804,6 +809,8 @@ typedef enum SpvMemoryAccessShift_ {
SpvMemoryAccessMakePointerVisibleKHRShift = 4,
SpvMemoryAccessNonPrivatePointerShift = 5,
SpvMemoryAccessNonPrivatePointerKHRShift = 5,
+ SpvMemoryAccessAliasScopeINTELMaskShift = 16,
+ SpvMemoryAccessNoAliasINTELMaskShift = 17,
SpvMemoryAccessMax = 0x7fffffff,
} SpvMemoryAccessShift;
@@ -818,6 +825,8 @@ typedef enum SpvMemoryAccessMask_ {
SpvMemoryAccessMakePointerVisibleKHRMask = 0x00000010,
SpvMemoryAccessNonPrivatePointerMask = 0x00000020,
SpvMemoryAccessNonPrivatePointerKHRMask = 0x00000020,
+ SpvMemoryAccessAliasScopeINTELMaskMask = 0x00010000,
+ SpvMemoryAccessNoAliasINTELMaskMask = 0x00020000,
} SpvMemoryAccessMask;
typedef enum SpvScope_ {
@@ -1059,6 +1068,7 @@ typedef enum SpvCapability_ {
SpvCapabilityFPGAMemoryAccessesINTEL = 5898,
SpvCapabilityFPGAClusterAttributesINTEL = 5904,
SpvCapabilityLoopFuseINTEL = 5906,
+ SpvCapabilityMemoryAccessAliasingINTEL = 5910,
SpvCapabilityFPGABufferLocationINTEL = 5920,
SpvCapabilityArbitraryPrecisionFixedPointINTEL = 5922,
SpvCapabilityUSMStorageClassesINTEL = 5935,
@@ -1073,13 +1083,17 @@ typedef enum SpvCapability_ {
SpvCapabilityDotProductInput4x8BitPackedKHR = 6018,
SpvCapabilityDotProduct = 6019,
SpvCapabilityDotProductKHR = 6019,
+ SpvCapabilityRayCullMaskKHR = 6020,
SpvCapabilityBitInstructions = 6025,
+ SpvCapabilityGroupNonUniformRotateKHR = 6026,
SpvCapabilityAtomicFloat32AddEXT = 6033,
SpvCapabilityAtomicFloat64AddEXT = 6034,
SpvCapabilityLongConstantCompositeINTEL = 6089,
SpvCapabilityOptNoneINTEL = 6094,
SpvCapabilityAtomicFloat16AddEXT = 6095,
SpvCapabilityDebugInfoModuleINTEL = 6114,
+ SpvCapabilitySplitBarrierINTEL = 6141,
+ SpvCapabilityGroupUniformArithmeticKHR = 6400,
SpvCapabilityMax = 0x7fffffff,
} SpvCapability;
@@ -1535,6 +1549,7 @@ typedef enum SpvOp_ {
SpvOpSubgroupAllKHR = 4428,
SpvOpSubgroupAnyKHR = 4429,
SpvOpSubgroupAllEqualKHR = 4430,
+ SpvOpGroupNonUniformRotateKHR = 4431,
SpvOpSubgroupReadInvocationKHR = 4432,
SpvOpTraceRayKHR = 4445,
SpvOpExecuteCallableKHR = 4446,
@@ -1801,6 +1816,9 @@ typedef enum SpvOp_ {
SpvOpArbitraryFloatPowRINTEL = 5881,
SpvOpArbitraryFloatPowNINTEL = 5882,
SpvOpLoopControlINTEL = 5887,
+ SpvOpAliasDomainDeclINTEL = 5911,
+ SpvOpAliasScopeDeclINTEL = 5912,
+ SpvOpAliasScopeListDeclINTEL = 5913,
SpvOpFixedSqrtINTEL = 5923,
SpvOpFixedRecipINTEL = 5924,
SpvOpFixedRsqrtINTEL = 5925,
@@ -1839,10 +1857,23 @@ typedef enum SpvOp_ {
SpvOpTypeStructContinuedINTEL = 6090,
SpvOpConstantCompositeContinuedINTEL = 6091,
SpvOpSpecConstantCompositeContinuedINTEL = 6092,
+ SpvOpControlBarrierArriveINTEL = 6142,
+ SpvOpControlBarrierWaitINTEL = 6143,
+ SpvOpGroupIMulKHR = 6401,
+ SpvOpGroupFMulKHR = 6402,
+ SpvOpGroupBitwiseAndKHR = 6403,
+ SpvOpGroupBitwiseOrKHR = 6404,
+ SpvOpGroupBitwiseXorKHR = 6405,
+ SpvOpGroupLogicalAndKHR = 6406,
+ SpvOpGroupLogicalOrKHR = 6407,
+ SpvOpGroupLogicalXorKHR = 6408,
SpvOpMax = 0x7fffffff,
} SpvOp;
#ifdef SPV_ENABLE_UTILITY_CODE
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultType) {
*hasResult = *hasResultType = false;
switch (opcode) {
@@ -2197,6 +2228,7 @@ inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultTy
case SpvOpSubgroupAllKHR: *hasResult = true; *hasResultType = true; break;
case SpvOpSubgroupAnyKHR: *hasResult = true; *hasResultType = true; break;
case SpvOpSubgroupAllEqualKHR: *hasResult = true; *hasResultType = true; break;
+ case SpvOpGroupNonUniformRotateKHR: *hasResult = true; *hasResultType = true; break;
case SpvOpSubgroupReadInvocationKHR: *hasResult = true; *hasResultType = true; break;
case SpvOpTraceRayKHR: *hasResult = false; *hasResultType = false; break;
case SpvOpExecuteCallableKHR: *hasResult = false; *hasResultType = false; break;
@@ -2452,6 +2484,9 @@ inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultTy
case SpvOpArbitraryFloatPowRINTEL: *hasResult = true; *hasResultType = true; break;
case SpvOpArbitraryFloatPowNINTEL: *hasResult = true; *hasResultType = true; break;
case SpvOpLoopControlINTEL: *hasResult = false; *hasResultType = false; break;
+ case SpvOpAliasDomainDeclINTEL: *hasResult = true; *hasResultType = false; break;
+ case SpvOpAliasScopeDeclINTEL: *hasResult = true; *hasResultType = false; break;
+ case SpvOpAliasScopeListDeclINTEL: *hasResult = true; *hasResultType = false; break;
case SpvOpFixedSqrtINTEL: *hasResult = true; *hasResultType = true; break;
case SpvOpFixedRecipINTEL: *hasResult = true; *hasResultType = true; break;
case SpvOpFixedRsqrtINTEL: *hasResult = true; *hasResultType = true; break;
@@ -2490,9 +2525,18 @@ inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultTy
case SpvOpTypeStructContinuedINTEL: *hasResult = false; *hasResultType = false; break;
case SpvOpConstantCompositeContinuedINTEL: *hasResult = false; *hasResultType = false; break;
case SpvOpSpecConstantCompositeContinuedINTEL: *hasResult = false; *hasResultType = false; break;
+ case SpvOpControlBarrierArriveINTEL: *hasResult = false; *hasResultType = false; break;
+ case SpvOpControlBarrierWaitINTEL: *hasResult = false; *hasResultType = false; break;
+ case SpvOpGroupIMulKHR: *hasResult = true; *hasResultType = true; break;
+ case SpvOpGroupFMulKHR: *hasResult = true; *hasResultType = true; break;
+ case SpvOpGroupBitwiseAndKHR: *hasResult = true; *hasResultType = true; break;
+ case SpvOpGroupBitwiseOrKHR: *hasResult = true; *hasResultType = true; break;
+ case SpvOpGroupBitwiseXorKHR: *hasResult = true; *hasResultType = true; break;
+ case SpvOpGroupLogicalAndKHR: *hasResult = true; *hasResultType = true; break;
+ case SpvOpGroupLogicalOrKHR: *hasResult = true; *hasResultType = true; break;
+ case SpvOpGroupLogicalXorKHR: *hasResult = true; *hasResultType = true; break;
}
}
#endif /* SPV_ENABLE_UTILITY_CODE */
#endif
-
diff --git a/thirdparty/spirv-reflect/patches/specialization-constants.patch b/thirdparty/spirv-reflect/patches/specialization-constants.patch
index 9bb5f97cd3..99815c9162 100644
--- a/thirdparty/spirv-reflect/patches/specialization-constants.patch
+++ b/thirdparty/spirv-reflect/patches/specialization-constants.patch
@@ -1,8 +1,8 @@
diff --git a/thirdparty/spirv-reflect/spirv_reflect.c b/thirdparty/spirv-reflect/spirv_reflect.c
-index e9b11bf495..f181df5fa2 100644
+index cdcf3ca663..c174ae1900 100644
--- a/thirdparty/spirv-reflect/spirv_reflect.c
+++ b/thirdparty/spirv-reflect/spirv_reflect.c
-@@ -125,6 +125,9 @@ typedef struct SpvReflectPrvDecorations {
+@@ -126,6 +126,9 @@ typedef struct SpvReflectPrvDecorations {
SpvReflectPrvNumberDecoration location;
SpvReflectPrvNumberDecoration offset;
SpvReflectPrvNumberDecoration uav_counter_buffer;
@@ -12,7 +12,7 @@ index e9b11bf495..f181df5fa2 100644
SpvReflectPrvStringDecoration semantic;
uint32_t array_stride;
uint32_t matrix_stride;
-@@ -631,6 +634,9 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser)
+@@ -639,6 +642,9 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser)
p_parser->nodes[i].decorations.offset.value = (uint32_t)INVALID_VALUE;
p_parser->nodes[i].decorations.uav_counter_buffer.value = (uint32_t)INVALID_VALUE;
p_parser->nodes[i].decorations.built_in = (SpvBuiltIn)INVALID_VALUE;
@@ -22,7 +22,7 @@ index e9b11bf495..f181df5fa2 100644
}
// Mark source file id node
p_parser->source_file_id = (uint32_t)INVALID_VALUE;
-@@ -821,10 +827,16 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser)
+@@ -829,10 +835,16 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser)
CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id);
}
break;
@@ -41,7 +41,7 @@ index e9b11bf495..f181df5fa2 100644
case SpvOpSpecConstantComposite:
case SpvOpSpecConstantOp: {
CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id);
-@@ -856,7 +868,7 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser)
+@@ -864,7 +876,7 @@ static SpvReflectResult ParseNodes(SpvReflectPrvParser* p_parser)
CHECKED_READU32(p_parser, p_node->word_offset + 3, p_access_chain->base_id);
//
// SPIRV_ACCESS_CHAIN_INDEX_OFFSET (4) is the number of words up until the first index:
@@ -50,7 +50,7 @@ index e9b11bf495..f181df5fa2 100644
//
p_access_chain->index_count = (node_word_count - SPIRV_ACCESS_CHAIN_INDEX_OFFSET);
if (p_access_chain->index_count > 0) {
-@@ -1338,6 +1350,9 @@ static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser)
+@@ -1346,6 +1358,9 @@ static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser)
skip = true;
}
break;
@@ -60,7 +60,7 @@ index e9b11bf495..f181df5fa2 100644
case SpvDecorationRelaxedPrecision:
case SpvDecorationBlock:
case SpvDecorationBufferBlock:
-@@ -1481,7 +1496,14 @@ static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser)
+@@ -1495,7 +1510,14 @@ static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser)
p_target_decorations->input_attachment_index.word_offset = word_offset;
}
break;
@@ -76,7 +76,7 @@ index e9b11bf495..f181df5fa2 100644
case SpvReflectDecorationHlslCounterBufferGOOGLE: {
uint32_t word_offset = p_node->word_offset + member_offset+ 3;
CHECKED_READU32(p_parser, word_offset, p_target_decorations->uav_counter_buffer.value);
-@@ -1789,6 +1811,13 @@ static SpvReflectResult ParseType(
+@@ -1803,6 +1825,13 @@ static SpvReflectResult ParseType(
p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_ACCELERATION_STRUCTURE;
}
break;
@@ -90,7 +90,7 @@ index e9b11bf495..f181df5fa2 100644
}
if (result == SPV_REFLECT_RESULT_SUCCESS) {
-@@ -3269,6 +3298,69 @@ static SpvReflectResult ParseExecutionModes(
+@@ -3332,6 +3361,69 @@ static SpvReflectResult ParseExecutionModes(
return SPV_REFLECT_RESULT_SUCCESS;
}
@@ -160,7 +160,7 @@ index e9b11bf495..f181df5fa2 100644
static SpvReflectResult ParsePushConstantBlocks(
SpvReflectPrvParser* p_parser,
SpvReflectShaderModule* p_module)
-@@ -3650,6 +3742,12 @@ static SpvReflectResult CreateShaderModule(
+@@ -3717,6 +3809,12 @@ static SpvReflectResult CreateShaderModule(
result = ParsePushConstantBlocks(&parser, p_module);
SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
}
@@ -173,8 +173,8 @@ index e9b11bf495..f181df5fa2 100644
if (result == SPV_REFLECT_RESULT_SUCCESS) {
result = ParseEntryPoints(&parser, p_module);
SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS);
-@@ -3807,6 +3905,9 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module)
- SafeFree(p_entry->used_push_constants);
+@@ -3875,6 +3973,9 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module)
+ SafeFree(p_entry->execution_modes);
}
SafeFree(p_module->entry_points);
+// -- GODOT begin --
@@ -183,7 +183,7 @@ index e9b11bf495..f181df5fa2 100644
// Push constants
for (size_t i = 0; i < p_module->push_constant_block_count; ++i) {
-@@ -4077,6 +4178,38 @@ SpvReflectResult spvReflectEnumerateEntryPointInterfaceVariables(
+@@ -4145,6 +4246,38 @@ SpvReflectResult spvReflectEnumerateEntryPointInterfaceVariables(
return SPV_REFLECT_RESULT_SUCCESS;
}
@@ -223,10 +223,10 @@ index e9b11bf495..f181df5fa2 100644
const SpvReflectShaderModule* p_module,
uint32_t* p_count,
diff --git a/thirdparty/spirv-reflect/spirv_reflect.h b/thirdparty/spirv-reflect/spirv_reflect.h
-index e9e4c40755..948533d3c0 100644
+index 02b81613a1..02850f8811 100644
--- a/thirdparty/spirv-reflect/spirv_reflect.h
+++ b/thirdparty/spirv-reflect/spirv_reflect.h
-@@ -323,6 +323,28 @@ typedef struct SpvReflectTypeDescription {
+@@ -329,6 +329,28 @@ typedef struct SpvReflectTypeDescription {
struct SpvReflectTypeDescription* members;
} SpvReflectTypeDescription;
@@ -255,7 +255,7 @@ index e9e4c40755..948533d3c0 100644
/*! @struct SpvReflectInterfaceVariable
-@@ -472,6 +494,10 @@ typedef struct SpvReflectShaderModule {
+@@ -483,6 +505,10 @@ typedef struct SpvReflectShaderModule {
SpvReflectInterfaceVariable* interface_variables; // Uses value(s) from first entry point
uint32_t push_constant_block_count; // Uses value(s) from first entry point
SpvReflectBlockVariable* push_constant_blocks; // Uses value(s) from first entry point
@@ -266,7 +266,7 @@ index e9e4c40755..948533d3c0 100644
struct Internal {
SpvReflectModuleFlags module_flags;
-@@ -744,6 +770,33 @@ SpvReflectResult spvReflectEnumerateInputVariables(
+@@ -755,6 +781,33 @@ SpvReflectResult spvReflectEnumerateInputVariables(
SpvReflectInterfaceVariable** pp_variables
);
diff --git a/thirdparty/spirv-reflect/patches/zero-calloc.patch b/thirdparty/spirv-reflect/patches/zero-calloc.patch
new file mode 100644
index 0000000000..796fe1266a
--- /dev/null
+++ b/thirdparty/spirv-reflect/patches/zero-calloc.patch
@@ -0,0 +1,28 @@
+diff --git a/thirdparty/spirv-reflect/spirv_reflect.c b/thirdparty/spirv-reflect/spirv_reflect.c
+index c174ae1900..11ccbdee3a 100644
+--- a/thirdparty/spirv-reflect/spirv_reflect.c
++++ b/thirdparty/spirv-reflect/spirv_reflect.c
+@@ -3322,12 +3322,18 @@ static SpvReflectResult ParseExecutionModes(
+ }
+ for (size_t entry_point_idx = 0; entry_point_idx < p_module->entry_point_count; ++entry_point_idx) {
+ SpvReflectEntryPoint* p_entry_point = &p_module->entry_points[entry_point_idx];
+- p_entry_point->execution_modes =
+- (SpvExecutionMode*)calloc(p_entry_point->execution_mode_count, sizeof(*p_entry_point->execution_modes));
+- if (IsNull(p_entry_point->execution_modes)) {
+- SafeFree(indices);
+- return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
++// -- GODOT begin --
++ if (p_entry_point->execution_mode_count > 0) {
++// -- GODOT end --
++ p_entry_point->execution_modes =
++ (SpvExecutionMode*)calloc(p_entry_point->execution_mode_count, sizeof(*p_entry_point->execution_modes));
++ if (IsNull(p_entry_point->execution_modes)) {
++ SafeFree(indices);
++ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
++ }
++// -- GODOT begin --
+ }
++// -- GODOT end --
+ }
+
+ for (size_t node_idx = 0; node_idx < p_parser->node_count; ++node_idx) {
diff --git a/thirdparty/spirv-reflect/spirv_reflect.c b/thirdparty/spirv-reflect/spirv_reflect.c
index f181df5fa2..11ccbdee3a 100644
--- a/thirdparty/spirv-reflect/spirv_reflect.c
+++ b/thirdparty/spirv-reflect/spirv_reflect.c
@@ -119,6 +119,7 @@ typedef struct SpvReflectPrvDecorations {
bool is_noperspective;
bool is_flat;
bool is_non_writable;
+ bool is_non_readable;
SpvReflectPrvNumberDecoration set;
SpvReflectPrvNumberDecoration binding;
SpvReflectPrvNumberDecoration input_attachment_index;
@@ -306,7 +307,12 @@ static SpvReflectResult IntersectSortedUint32(
size_t* res_size
)
{
+ *pp_res = NULL;
*res_size = 0;
+ if (IsNull(p_arr0) || IsNull(p_arr1)) {
+ return SPV_REFLECT_RESULT_SUCCESS;
+ }
+
const uint32_t* arr0_end = p_arr0 + arr0_size;
const uint32_t* arr1_end = p_arr1 + arr1_size;
@@ -324,7 +330,6 @@ static SpvReflectResult IntersectSortedUint32(
}
}
- *pp_res = NULL;
if (*res_size > 0) {
*pp_res = (uint32_t*)calloc(*res_size, sizeof(**pp_res));
if (IsNull(*pp_res)) {
@@ -488,6 +493,9 @@ static SpvReflectDecorationFlags ApplyDecorations(const SpvReflectPrvDecorations
if (p_decoration_fields->is_non_writable) {
decorations |= SPV_REFLECT_DECORATION_NON_WRITABLE;
}
+ if (p_decoration_fields->is_non_readable) {
+ decorations |= SPV_REFLECT_DECORATION_NON_READABLE;
+ }
return decorations;
}
@@ -1364,6 +1372,7 @@ static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser)
case SpvDecorationNoPerspective:
case SpvDecorationFlat:
case SpvDecorationNonWritable:
+ case SpvDecorationNonReadable:
case SpvDecorationLocation:
case SpvDecorationBinding:
case SpvDecorationDescriptorSet:
@@ -1462,6 +1471,11 @@ static SpvReflectResult ParseDecorations(SpvReflectPrvParser* p_parser)
}
break;
+ case SpvDecorationNonReadable: {
+ p_target_decorations->is_non_readable = true;
+ }
+ break;
+
case SpvDecorationLocation: {
uint32_t word_offset = p_node->word_offset + member_offset + 3;
CHECKED_READU32(p_parser, word_offset, p_target_decorations->location.value);
@@ -1970,6 +1984,7 @@ static SpvReflectResult ParseDescriptorBindings(
p_descriptor->count = 1;
p_descriptor->uav_counter_id = p_node->decorations.uav_counter_buffer.value;
p_descriptor->type_description = p_type;
+ p_descriptor->decoration_flags = ApplyDecorations(&p_node->decorations);
// If this is in the StorageBuffer storage class, it's for sure a storage
// buffer descriptor. We need to handle this case earlier because in SPIR-V
@@ -3208,8 +3223,8 @@ static SpvReflectResult ParseExecutionModes(
// Read entry point id
uint32_t entry_point_id = 0;
CHECKED_READU32(p_parser, p_node->word_offset + 1, entry_point_id);
-
- // Find entry point
+
+ // Find entry point
SpvReflectEntryPoint* p_entry_point = NULL;
for (size_t entry_point_idx = 0; entry_point_idx < p_module->entry_point_count; ++entry_point_idx) {
if (p_module->entry_points[entry_point_idx].id == entry_point_id) {
@@ -3221,7 +3236,7 @@ static SpvReflectResult ParseExecutionModes(
if (IsNull(p_entry_point)) {
return SPV_REFLECT_RESULT_ERROR_SPIRV_INVALID_ENTRY_POINT;
}
-
+
// Read execution mode
uint32_t execution_mode = (uint32_t)INVALID_VALUE;
CHECKED_READU32(p_parser, p_node->word_offset + 2, execution_mode);
@@ -3288,12 +3303,66 @@ static SpvReflectResult ParseExecutionModes(
case SpvExecutionModeLocalSizeId:
case SpvExecutionModeLocalSizeHintId:
case SpvExecutionModePostDepthCoverage:
+ case SpvExecutionModeDenormPreserve:
+ case SpvExecutionModeDenormFlushToZero:
+ case SpvExecutionModeSignedZeroInfNanPreserve:
+ case SpvExecutionModeRoundingModeRTE:
+ case SpvExecutionModeRoundingModeRTZ:
case SpvExecutionModeStencilRefReplacingEXT:
+ case SpvExecutionModeOutputLinesNV:
case SpvExecutionModeOutputPrimitivesNV:
case SpvExecutionModeOutputTrianglesNV:
break;
}
+ p_entry_point->execution_mode_count++;
+ }
+ uint32_t* indices = (uint32_t*)calloc(p_module->entry_point_count, sizeof(indices));
+ if (IsNull(indices)) {
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+ for (size_t entry_point_idx = 0; entry_point_idx < p_module->entry_point_count; ++entry_point_idx) {
+ SpvReflectEntryPoint* p_entry_point = &p_module->entry_points[entry_point_idx];
+// -- GODOT begin --
+ if (p_entry_point->execution_mode_count > 0) {
+// -- GODOT end --
+ p_entry_point->execution_modes =
+ (SpvExecutionMode*)calloc(p_entry_point->execution_mode_count, sizeof(*p_entry_point->execution_modes));
+ if (IsNull(p_entry_point->execution_modes)) {
+ SafeFree(indices);
+ return SPV_REFLECT_RESULT_ERROR_ALLOC_FAILED;
+ }
+// -- GODOT begin --
+ }
+// -- GODOT end --
+ }
+
+ for (size_t node_idx = 0; node_idx < p_parser->node_count; ++node_idx) {
+ SpvReflectPrvNode* p_node = &(p_parser->nodes[node_idx]);
+ if (p_node->op != SpvOpExecutionMode) {
+ continue;
+ }
+
+ // Read entry point id
+ uint32_t entry_point_id = 0;
+ CHECKED_READU32(p_parser, p_node->word_offset + 1, entry_point_id);
+
+ // Find entry point
+ SpvReflectEntryPoint* p_entry_point = NULL;
+ uint32_t* idx = NULL;
+ for (size_t entry_point_idx = 0; entry_point_idx < p_module->entry_point_count; ++entry_point_idx) {
+ if (p_module->entry_points[entry_point_idx].id == entry_point_id) {
+ p_entry_point = &p_module->entry_points[entry_point_idx];
+ idx = &indices[entry_point_idx];
+ break;
+ }
+ }
+
+ // Read execution mode
+ uint32_t execution_mode = (uint32_t)INVALID_VALUE;
+ CHECKED_READU32(p_parser, p_node->word_offset + 2, execution_mode);
+ p_entry_point->execution_modes[(*idx)++] = (SpvExecutionMode)execution_mode;
}
+ SafeFree(indices);
}
return SPV_REFLECT_RESULT_SUCCESS;
}
@@ -3649,7 +3718,11 @@ static SpvReflectResult CreateShaderModule(
if (flags & SPV_REFLECT_MODULE_FLAG_NO_COPY) {
// Set internal size and pointer to args passed in
p_module->_internal->spirv_size = size;
+#if defined(__cplusplus)
+ p_module->_internal->spirv_code = const_cast<uint32_t*>(static_cast<const uint32_t*>(p_code)); // cast that const away
+#else
p_module->_internal->spirv_code = (void*)p_code; // cast that const away
+#endif
p_module->_internal->spirv_word_count = (uint32_t)(size / SPIRV_WORD_SIZE);
}
else {
@@ -3903,6 +3976,7 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module)
SafeFree(p_entry->interface_variables);
SafeFree(p_entry->used_uniforms);
SafeFree(p_entry->used_push_constants);
+ SafeFree(p_entry->execution_modes);
}
SafeFree(p_module->entry_points);
// -- GODOT begin --
@@ -5093,6 +5167,7 @@ const char* spvReflectSourceLanguage(SpvSourceLanguage source_lang)
case SpvSourceLanguageOpenCL_CPP : return "OpenCL_CPP";
case SpvSourceLanguageHLSL : return "HLSL";
case SpvSourceLanguageCPP_for_OpenCL : return "CPP_for_OpenCL";
+ case SpvSourceLanguageSYCL : return "SYCL";
case SpvSourceLanguageMax:
break;
}
diff --git a/thirdparty/spirv-reflect/spirv_reflect.h b/thirdparty/spirv-reflect/spirv_reflect.h
index 948533d3c0..02850f8811 100644
--- a/thirdparty/spirv-reflect/spirv_reflect.h
+++ b/thirdparty/spirv-reflect/spirv_reflect.h
@@ -30,7 +30,12 @@ VERSION HISTORY
#ifndef SPIRV_REFLECT_H
#define SPIRV_REFLECT_H
+#if defined(SPIRV_REFLECT_USE_SYSTEM_SPIRV_H)
+#include <spirv/unified1/spirv.h>
+#else
#include "./include/spirv/unified1/spirv.h"
+#endif
+
#include <stdint.h>
#include <string.h>
@@ -139,6 +144,7 @@ typedef enum SpvReflectDecorationFlagBits {
SPV_REFLECT_DECORATION_FLAT = 0x00000040,
SPV_REFLECT_DECORATION_NON_WRITABLE = 0x00000080,
SPV_REFLECT_DECORATION_RELAXED_PRECISION = 0x00000100,
+ SPV_REFLECT_DECORATION_NON_READABLE = 0x00000200,
} SpvReflectDecorationFlagBits;
typedef uint32_t SpvReflectDecorationFlags;
@@ -422,6 +428,8 @@ typedef struct SpvReflectDescriptorBinding {
uint32_t binding;
uint32_t set;
} word_offset;
+
+ SpvReflectDecorationFlags decoration_flags;
} SpvReflectDescriptorBinding;
/*! @struct SpvReflectDescriptorSet
@@ -458,6 +466,9 @@ typedef struct SpvReflectEntryPoint {
uint32_t used_push_constant_count;
uint32_t* used_push_constants;
+ uint32_t execution_mode_count;
+ SpvExecutionMode* execution_modes;
+
struct LocalSize {
uint32_t x;
uint32_t y;